diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000000000..00a1c4c3093dc --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,84 @@ +[alias] +vdev = "run --quiet --package vdev --" + +[env] +# Build with large pages so that Vector runs on systems with 64k pages or less (e.g. 4k) to support +# CentOS 7, 8, and a few other Linux distributions. +JEMALLOC_SYS_WITH_LG_PAGE = "16" + +[target.'cfg(all())'] +rustflags = [ + "-Dclippy::print_stdout", + "-Dclippy::print_stderr", + "-Dclippy::dbg_macro", +] + +# We need to bring in `libstdc++` for things that build against C++ (librdkafka, etc) which comes along in the +# `cross` base image but _isn't_ in a path searched by the linker normally. Additionally, our custom Docker image that +# we base on the `cross` image moves `libstdc++` into this custom-looking directory to avoid some _other_ libraries +# included in the `cross` base image from having a higher precedence than some of the "self-contained" libraries that +# Rust will bundle/use for specific targets like MUSL. +[target.x86_64-unknown-linux-musl] +rustflags = "-Lnative=/lib/native-libs" + +[target.aarch64-unknown-linux-musl] +rustflags = "-Lnative=/lib/native-libs" + +[target.armv7-unknown-linux-musleabihf] +rustflags = "-Lnative=/lib/native-libs" + +[target.x86_64-unknown-linux-gnu] +rustflags = ["-C", "link-args=-rdynamic"] + +[target.aarch64-unknown-linux-gnu] +rustflags = ["-C", "link-args=-rdynamic"] + +[target.x86_64-pc-windows-msvc] +# https://github.com/dtolnay/inventory/issues/58 +rustflags = ["-C", "codegen-units=1"] + +[source.crates-io] +replace-with = "vendored-sources" + +[source."git+https://github.com/GreptimeTeam/greptime-proto.git?tag=v0.4.1"] +git = "https://github.com/GreptimeTeam/greptime-proto.git" +tag = "v0.4.1" +replace-with = "vendored-sources" + +[source."git+https://github.com/GreptimeTeam/greptimedb-ingester-rust.git?rev=d21dbcff680139ed2065b62100bac3123da7c789"] +git = "https://github.com/GreptimeTeam/greptimedb-ingester-rust.git" +rev = "d21dbcff680139ed2065b62100bac3123da7c789" +replace-with = "vendored-sources" + +[source."git+https://github.com/MSxDOS/ntapi.git?rev=24fc1e47677fc9f6e38e5f154e6011dc9b270da6"] +git = "https://github.com/MSxDOS/ntapi.git" +rev = "24fc1e47677fc9f6e38e5f154e6011dc9b270da6" +replace-with = "vendored-sources" + +[source."git+https://github.com/tokio-rs/tracing?rev=e0642d949891546a3bb7e47080365ee7274f05cd"] +git = "https://github.com/tokio-rs/tracing" +rev = "e0642d949891546a3bb7e47080365ee7274f05cd" +replace-with = "vendored-sources" + +[source."git+https://github.com/vectordotdev/aws-sdk-rust?rev=3d6aefb7fcfced5fc2a7e761a87e4ddbda1ee670"] +git = "https://github.com/vectordotdev/aws-sdk-rust" +rev = "3d6aefb7fcfced5fc2a7e761a87e4ddbda1ee670" +replace-with = "vendored-sources" + +[source."git+https://github.com/vectordotdev/heim.git?branch=update-nix"] +git = "https://github.com/vectordotdev/heim.git" +branch = "update-nix" +replace-with = "vendored-sources" + +[source."git+https://github.com/vectordotdev/nix.git?branch=memfd/gnu/musl"] +git = "https://github.com/vectordotdev/nix.git" +branch = "memfd/gnu/musl" +replace-with = "vendored-sources" + +[source."git+https://github.com/vectordotdev/tokio?branch=tokio-util-0.7.8-framed-read-continue-on-error"] +git = "https://github.com/vectordotdev/tokio" +branch = "tokio-util-0.7.8-framed-read-continue-on-error" +replace-with = "vendored-sources" + +[source.vendored-sources] +directory = "vendor" diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 964923cc6c37b..743eb16c52620 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -185,9 +185,9 @@ concating concats condrestart conffiles +configkey configmap confl -confluentinc confy consigliere CONTEUDO @@ -863,7 +863,6 @@ protoc protofbuf protosizer Prt -psl psv publickey purgecss @@ -1142,6 +1141,7 @@ trivy Troutwine trustarc truste +TRUSTSTORE TSDB Tsvg turbofish @@ -1232,7 +1232,6 @@ wktpointer wmem woooooow woothee -wor wordlist workdir workstreams @@ -1244,6 +1243,7 @@ wtcache wtime wtimeouts wtr +wurstmeister xact xcatsy Xcg diff --git a/.github/workflows/build_preview_sites.yml b/.github/workflows/build_preview_sites.yml deleted file mode 100644 index e3478ee2711d2..0000000000000 --- a/.github/workflows/build_preview_sites.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Deploy Vector Preview Sites - -on: - workflow_run: - workflows: ["Call Build Preview"] - types: - - completed - -jobs: - deploy_vector_preview_site: - uses: ./.github/workflows/create_preview_sites.yml - with: - APP_ID: "d1a7j77663uxsc" - APP_NAME: "vector.dev" - secrets: - REQUEST_TOKEN: ${{ secrets.REQUEST_TOKEN }} - REQUEST_MESSAGE: ${{ secrets.REQUEST_MESSAGE }} - ENDPOINT: ${{ secrets.BUILDER_ENDPOINT }} - - deploy_rust_doc_preview_site: - uses: ./.github/workflows/create_preview_sites.yml - with: - APP_ID: "d1hoyoksbulg25" - APP_NAME: "Rust Doc" - secrets: - REQUEST_TOKEN: ${{ secrets.REQUEST_TOKEN }} - REQUEST_MESSAGE: ${{ secrets.REQUEST_MESSAGE }} - ENDPOINT: ${{ secrets.BUILDER_ENDPOINT }} - - deploy_vrl_playground_preview_site: - uses: ./.github/workflows/create_preview_sites.yml - with: - APP_ID: "d2lr4eds605rpz" - APP_NAME: "VRL Playground" - secrets: - REQUEST_TOKEN: ${{ secrets.REQUEST_TOKEN }} - REQUEST_MESSAGE: ${{ secrets.REQUEST_MESSAGE }} - ENDPOINT: ${{ secrets.BUILDER_ENDPOINT }} - diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml deleted file mode 100644 index 8ad6077d265c3..0000000000000 --- a/.github/workflows/changelog.yaml +++ /dev/null @@ -1,89 +0,0 @@ -# Changelog -# -# Validates that a changelog entry was added. -# Runs on PRs when: -# - opened/re-opened -# - new commits pushed -# - label is added or removed -# Runs on merge queues, but just passes, because it is a required check. - -name: Changelog - -on: - pull_request: - types: [opened, synchronize, reopened, labeled, unlabeled] - # Due to merge queue requiring same status checks as PRs, must pass by default - merge_group: - types: [checks_requested] - -jobs: - validate-changelog: - runs-on: ubuntu-latest - if: github.event_name == 'pull_request' - env: - PR_HAS_LABEL: ${{ contains( github.event.pull_request.labels.*.name, 'no-changelog') }} - steps: - # checkout full depth because in the check_changelog_fragments script, we need to specify a - # merge base. If we only shallow clone the repo, git may not have enough history to determine - # the base. - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Generate authentication token - # don't run this step if the PR is from a fork or dependabot since the secrets won't exist - if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' }} - id: generate_token - uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a - with: - app_id: ${{ secrets.GH_APP_DATADOG_VECTOR_CI_APP_ID }} - private_key: ${{ secrets.GH_APP_DATADOG_VECTOR_CI_APP_PRIVATE_KEY }} - - - name: Get PR comment author - # don't run this step if the PR is from a fork or dependabot since the secrets won't exist - if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' }} - id: author - uses: tspascoal/get-user-teams-membership@v3 - with: - username: ${{ github.actor }} - team: 'Vector' - GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} - - - env: - # if the prior step did not run, this var will be '' - AUTHOR_IS_TEAM_MEMBER: ${{ steps.author.outputs.isTeamMember }} - run: | - if [[ $PR_HAS_LABEL == 'true' ]] ; then - echo "'no-changelog' label detected." - exit 0 - fi - - # helper script needs to reference the master branch to compare against - git fetch origin master:refs/remotes/origin/master - - # If the PR author is an external contributor, validate that the - # changelog fragments added contain the author line for website rendering. - args="" - if [[ $AUTHOR_IS_TEAM_MEMBER != 'true' ]] ; then - echo "PR author detected to be an external contributor." - args="--authors" - fi - - ./scripts/check_changelog_fragments.sh ${args} - - check-changelog: - name: Changelog - runs-on: ubuntu-latest - needs: validate-changelog - if: always() - env: - FAILED: ${{ contains(needs.*.result, 'failure') }} - steps: - - name: exit - run: | - echo "failed=${{ env.FAILED }}" - if [[ "$FAILED" == "true" ]] ; then - exit 1 - else - exit 0 - fi diff --git a/.github/workflows/create_preview_sites.yml b/.github/workflows/create_preview_sites.yml deleted file mode 100644 index aaef5d5f8b234..0000000000000 --- a/.github/workflows/create_preview_sites.yml +++ /dev/null @@ -1,106 +0,0 @@ -name: Create Preview Sites - -on: - workflow_call: - inputs: - APP_ID: - description: "App ID for the associated website" - required: true - type: string - APP_NAME: - description: "Application name for the comment" - required: true - type: string - secrets: - REQUEST_TOKEN: - description: "Token for the request" - required: true - REQUEST_MESSAGE: - description: "Message for the request" - required: true - ENDPOINT: - description: "Request endpoint" - required: true - -jobs: - create_preview_site: - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - # Get the artifacts with the PR number and branch name - - name: Download artifact - uses: actions/github-script@v7.0.1 - with: - script: | - const fs = require('fs'); - const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: ${{ github.event.workflow_run.id }}, - }); - const matchArtifact = artifacts.data.artifacts.filter(artifact => artifact.name == "pr")[0]; - const download = await github.rest.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: matchArtifact.id, - archive_format: 'zip', - }); - fs.writeFileSync('${{ github.workspace }}/pr.zip', Buffer.from(download.data)); - - # Extract the info from the artifact and set variables - - name: Extract PR info from artifact - run: | - unzip pr.zip -d pr - BRANCH_NAME=$(cat ./pr/branch) - SANITIZED_BRANCH_NAME=$(echo "$BRANCH_NAME" | sed 's/[\/\.]/-/g') - echo "SANITIZED_BRANCH_NAME=$SANITIZED_BRANCH_NAME" >> $GITHUB_ENV - echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV - - # Kick off the job in amplify - - name: Deploy Site - env: - APP_ID: ${{ inputs.APP_ID }} - APP_NAME: ${{ inputs.APP_NAME }} - REQUEST_TOKEN: ${{ secrets.REQUEST_TOKEN }} - REQUEST_MESSAGE: ${{ secrets.REQUEST_MESSAGE }} - ENDPOINT: ${{ secrets.ENDPOINT }} - run: | - sleep 20 - HMAC_KEY=$(echo -n $REQUEST_MESSAGE | openssl dgst -sha256 -hmac "$REQUEST_TOKEN" | cut -d" " -f2) - SIGNATURE="sha256=$HMAC_KEY" - RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ - -H "Content-Type: application/json" \ - -H "X-Hub-Signature: $SIGNATURE" \ - -d "{\"app_id\": \"$APP_ID\", \"branch_name\": \"$BRANCH_NAME\"}" \ - "$ENDPOINT") - - # check the response code and fail if not 200 - if [ "$RESPONSE_CODE" != "200" ]; then - echo "Request failed with response code $RESPONSE_CODE" - exit 1 - fi - - # Add preview link to comment if all 3 sites successfully start - - name: Comment Preview Link - if: success() - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - APP_ID: ${{ inputs.APP_ID }} - APP_NAME: ${{ inputs.APP_NAME }} - uses: actions/github-script@v7.0.1 - with: - script: | - const fs = require('fs'); - const prNumber = fs.readFileSync('./pr/number', 'utf8'); - const issueNumber = parseInt(prNumber); - const { APP_ID, APP_NAME, SANITIZED_BRANCH_NAME } = process.env - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issueNumber, - body: `Your preview site for the **${APP_NAME}** will be ready in a few minutes, please allow time for it to build. \n \n Heres your preview link: \n [${APP_NAME} preview](https://${SANITIZED_BRANCH_NAME}.${APP_ID}.amplifyapp.com)` - }); - - diff --git a/.github/workflows/deny.yml b/.github/workflows/deny.yml deleted file mode 100644 index d3cbc15304e20..0000000000000 --- a/.github/workflows/deny.yml +++ /dev/null @@ -1,75 +0,0 @@ -# Deny - Linux -# -# Checks for security vulnerabilities or license incompatibilities -# -# Runs on: -# - scheduled UTC midnight -# - on PR comment (see comment-trigger.yml) -# - on demand from github actions UI - -name: Deny - Linux - -on: - workflow_call: - workflow_dispatch: - schedule: - # At midnight UTC - - cron: '0 0 * * *' - -jobs: - test-deny: - runs-on: ubuntu-latest - timeout-minutes: 15 - env: - CARGO_INCREMENTAL: 0 - steps: - - name: (PR comment) Get PR branch - if: ${{ github.event_name == 'issue_comment' }} - uses: xt0rted/pull-request-comment-branch@v2 - id: comment-branch - - - name: (PR comment) Set latest commit status as pending - if: ${{ github.event_name == 'issue_comment' }} - uses: myrotvorets/set-commit-status-action@v2.0.1 - with: - sha: ${{ steps.comment-branch.outputs.head_sha }} - token: ${{ secrets.GITHUB_TOKEN }} - context: Deny - Linux - status: pending - - - name: (PR comment) Checkout PR branch - if: ${{ github.event_name == 'issue_comment' }} - uses: actions/checkout@v3 - with: - ref: ${{ steps.comment-branch.outputs.head_ref }} - - - name: Checkout branch - if: ${{ github.event_name != 'issue_comment' }} - uses: actions/checkout@v3 - - - uses: actions/cache@v4 - name: Cache Cargo registry + index - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo- - - - run: sudo -E bash scripts/environment/bootstrap-ubuntu-20.04.sh - - run: bash scripts/environment/prepare.sh - - run: echo "::add-matcher::.github/matchers/rust.json" - - name: Check cargo deny advisories/licenses - run: make check-deny - - - name: (PR comment) Set latest commit status as ${{ job.status }} - uses: myrotvorets/set-commit-status-action@v2.0.1 - if: always() && github.event_name == 'issue_comment' - with: - sha: ${{ steps.comment-branch.outputs.head_sha }} - token: ${{ secrets.GITHUB_TOKEN }} - context: Deny - Linux - status: ${{ job.status }} diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml deleted file mode 100644 index 3a6524f156c1b..0000000000000 --- a/.github/workflows/e2e.yml +++ /dev/null @@ -1,116 +0,0 @@ -# End to End Suite -# -# Runs on: -# - PRs if there are code changes to the source files that are noted in `vdev e2e ci_paths` -# - MQ (always pass) -# - Scheduled: at midnight UTC Tues-Sat - -name: E2E Test Suite - -on: - pull_request: - # Needs to pass by default in MQ - merge_group: - types: [checks_requested] - schedule: - # At midnight UTC Tue-Sat - - cron: '0 0 * * 2-6' - -concurrency: - # `github.event.number` exists for pull requests, otherwise fall back to SHA for merge queue - group: ${{ github.workflow }}-${{ github.event.number || github.event.merge_group.head_sha }} - cancel-in-progress: true - -env: - CONTAINER_TOOL: "docker" - DD_ENV: "ci" - DD_API_KEY: ${{ secrets.DD_API_KEY }} - TEST_DATADOG_API_KEY: ${{ secrets.CI_TEST_DATADOG_API_KEY }} - RUST_BACKTRACE: full - TEST_LOG: vector=debug - VERBOSE: true - CI: true - PROFILE: debug - # observing issues fetching boringssl via HTTPS in the OSX build, seeing if this helps - # can be removed when we switch back to the upstream openssl-sys crate - CARGO_NET_GIT_FETCH_WITH_CLI: true - -jobs: - - changes: - if: github.event_name == 'pull_request' - uses: ./.github/workflows/changes.yml - with: - base_ref: ${{ github.event.pull_request.base.ref }} - head_ref: ${{ github.event.pull_request.head.ref }} - source: false - e2e_tests: true - secrets: inherit - - e2e-tests: - name: E2E Tests - runs-on: ubuntu-20.04-8core - timeout-minutes: 45 - needs: changes - if: always() && ( - github.event_name == 'schedule' || ( - needs.changes.outputs.all-e2e == 'true' - || needs.changes.outputs.e2e-datadog-logs == 'true' - || needs.changes.outputs.e2e-datadog-metrics == 'true' - ) - ) - steps: - - uses: actions/checkout@v3 - with: - submodules: "recursive" - - - run: sudo npm -g install @datadog/datadog-ci - - - run: docker image prune -af ; docker container prune -f - - - name: Determine if secrets are defined (PR author is team member). - if: github.event_name == 'pull_request' - env: - GH_APP_DATADOG_VECTOR_CI_APP_ID: ${{ secrets.GH_APP_DATADOG_VECTOR_CI_APP_ID }} - run: | - if [[ "$GH_APP_DATADOG_VECTOR_CI_APP_ID" != "" ]] ; then - echo "PR_HAS_ACCESS_TO_SECRETS=true" >> "$GITHUB_ENV" - else - echo "PR_HAS_ACCESS_TO_SECRETS=false" >> "$GITHUB_ENV" - fi - - - if: (github.event_name == 'schedule' || needs.changes.outputs.all-e2e == 'true' || needs.changes.outputs.e2e-datadog-logs == 'true') && - (github.event_name != 'pull_request' || env.PR_HAS_ACCESS_TO_SECRETS == 'true') - name: e2e-datadog-logs - uses: nick-fields/retry@v3 - with: - timeout_minutes: 35 - max_attempts: 3 - command: bash scripts/ci-int-e2e-test.sh e2e datadog-logs - - - if: (github.event_name == 'schedule' || needs.changes.outputs.all-e2e == 'true' || needs.changes.outputs.e2e-datadog-metrics == 'true') && - (github.event_name != 'pull_request' || env.PR_HAS_ACCESS_TO_SECRETS == 'true') - name: e2e-datadog-metrics - uses: nick-fields/retry@v3 - with: - timeout_minutes: 35 - max_attempts: 3 - command: bash scripts/ci-int-e2e-test.sh e2e datadog-metrics - - - e2e-test-suite: - name: E2E Test Suite - runs-on: ubuntu-latest - timeout-minutes: 5 - if: always() - needs: e2e-tests - env: - FAILED: ${{ contains(needs.*.result, 'failure') }} - steps: - - run: | - echo "failed=${{ env.FAILED }}" - if [[ "$FAILED" == "true" ]] ; then - exit 1 - else - exit 0 - fi diff --git a/.github/workflows/preview_site_trigger.yml b/.github/workflows/preview_site_trigger.yml deleted file mode 100644 index 7c2a960e1f88d..0000000000000 --- a/.github/workflows/preview_site_trigger.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Call Build Preview - -on: - pull_request: - types: [opened, reopened] - -jobs: - approval_check: - runs-on: ubuntu-latest - timeout-minutes: 5 - if: ${{ contains(github.head_ref, 'website') }} - steps: - - name: Echo approval - run: | - echo "Workflow has been allowed to run for PR ${{ github.event.number }}. Setting artifacts and then continuing workflow runs" - - # Save the PR number and branch name to an artifact for use in subsequent jobs - - name: Save PR number and Branch name - run: | - mkdir -p ./pr - echo "${{ github.event.number }}" > ./pr/number - echo "${{ github.head_ref }}" >> ./pr/branch - - # Upload the artifact - - name: Upload PR information artifact - uses: actions/upload-artifact@v3 - with: - name: pr - path: pr/ diff --git a/deny.toml b/deny.toml index 5fd31b7b73c2e..6801310076119 100644 --- a/deny.toml +++ b/deny.toml @@ -38,7 +38,7 @@ license-files = [ ] [advisories] -ignore = [ +ignore = [ # Vulnerability in `rsa` crate: https://rustsec.org/advisories/RUSTSEC-2023-0071.html # There is not fix available yet. # https://github.com/vectordotdev/vector/issues/19262 diff --git a/patch/openssl/.cargo-checksum.json b/patch/openssl/.cargo-checksum.json new file mode 100644 index 0000000000000..89ee4f23fa3eb --- /dev/null +++ b/patch/openssl/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"17f14a499bdfaef855f51755d4b97c9a84f547658c74f0885645163f2395f3d4","Cargo.lock":"8c49d30aedb81f5388622a0062a29c664b07d6d877c46063da60964e31126aff","Cargo.toml":"5783964d3053c0559f8b040edcc79f84ae8cda3985c7477ba670f355be1bef28","LICENSE":"f3d4287b4a21c5176fea2f9bd4ae800696004e2fb8e05cbc818be513f188a941","README.md":"c5ddde25c2756a1115daaa671fb4297cdc83bf23009c8356ba65b5311d0dd30d","build.rs":"3c92eb5e68da6943dabc614fd1b1a2c77c7a9c65ea7fe27624f11700d4a7c0f0","examples/mk_certs.rs":"012569fc734c314c5d3c1c9dc8ae64a32db4cfa917e8fbc363c1eef118600d0a","src/aes.rs":"a428f06147e4b48219a789da0af12371d967d2eefcc55536df4d1547001dda8b","src/asn1.rs":"d250233df5913879a6dc205e16f2404bd7512e29a2b8dab2b9ea83c670ee85be","src/base64.rs":"8be8ad4fe10055cdd55d0147d569e7669d3ac82927569bb917a76e447dfe90d1","src/bio.rs":"c19b865b79bb7ea3460083046f50757800f6c93fe9ec9f3dbb438980fe127aa4","src/bn.rs":"966356af877c59fbbf3d43d03ac643f6021933cbccab330b143e00fea7bfea5e","src/cipher.rs":"3bf4595773be7c5f292b671c9272979d2b300b0e2961e14d3aa0d1c03a24b83d","src/cipher_ctx.rs":"01ffd0005693695c41e5dd1d86b448bca4808e43d5778c5b9f707c1e867a75bb","src/cms.rs":"0dfa2f1134b84de1c7c9a8ad78ad2b8cd773cea75c9b80cf57bcf181f7ed4573","src/conf.rs":"c374003c606c331fedbe9075abfaf41eba38bfbbbefe9c9f2d2a1d445e4b1606","src/derive.rs":"963694c3cf7b0b70802b5b2b3f93f857ed7b320d5db331b57c2ff11bcb0891ad","src/dh.rs":"e9fc6d5910241a6cba0b7c6ce4139ba8cbd04be7de5c92a479406ddc79a581cd","src/dsa.rs":"10b6aca140fe332cb35c78cb3b0e9f1aa7cf18971059ac93a9a458481de26f85","src/ec.rs":"43142ab898dd4dc25efd7cd5c081be4f1a65c39d48e715fa3a208c7a2c5cb534","src/ecdsa.rs":"b5bbfd49fafc9f08bd309a0046eca20016990cd266d442973498c6f2951aed37","src/encrypt.rs":"d1c6de4f5998f06d33de66005a1926eab895f0ecff01396b46dc697dc1593b26","src/envelope.rs":"773551074ece307aff215686e6a43471edf0ef6f74c520e4611e70f96e928652","src/error.rs":"ede27beebf1594a9165f16aa8732816f28501a8454d3125b6eb5ce98756e0255","src/ex_data.rs":"0a58a3a274a4ef2251dadb64cbcd44b43710d252201b137ecfb91cf14373c04f","src/fips.rs":"761cd7cdfbc16af88fbfefd38e54cb77b4ba8e2f49221607e145bc541f089d7e","src/hash.rs":"ee695fa92f63807c8689e8375e2616fd8798bbe655e7162f2fa1349d0b3ad8aa","src/lib.rs":"c845f485a5772705f25a0bfa4033604b9586d6174288f1ff712b82ccff91994e","src/lib_ctx.rs":"ec6431adad53f3a9621b011506678104bd4f62bdea38ef9d1b731334507ab068","src/macros.rs":"648054f2ee89a22314b942a882878d47121b97b47d9b1146e323b8c6c255a52c","src/md.rs":"038fb8c568634590d5beeb81e47d8bffa201b3ec0297b7b83a06af7abc3bf780","src/md_ctx.rs":"a00fbe465477fd1209fffd7b83eebb1e86af2bfd3acf2c1ca691f19da1a5b35f","src/memcmp.rs":"f48e0e29f372db2d0eb2239290abec8819300eb3e01e3bb1030783d6f6a8b2c9","src/nid.rs":"8ed819d454abb0e531d5dd359bc6ca8c16c7c48ec8cf07dd52e59a7bebd1d77a","src/ocsp.rs":"bfb378fa87945eee583521e350f427406888bbb8a804a90aeb06bdbf1b656ddf","src/pkcs12.rs":"b4171fa4423eaf8e1b060cf68f9b85fe0bc84d6c5fe23dabf3ddb0fed9a8cb23","src/pkcs5.rs":"b73bdd59ec857830a4fcc1e2e9b954e69f18df5302c5cc3366f11a877b0e655f","src/pkcs7.rs":"24431303749047c08aad278f53ea47d6e47130318d368dd5213194e27bd58620","src/pkey.rs":"e8a509baf35b2477253c024f06c45da7b6804580673d7b1f84b021ea80a29d71","src/pkey_ctx.rs":"0da4de8cc6cd814133a96a941ace5dbc76ea8b19f145ae71a150f32e2397aa8a","src/provider.rs":"5ab0b25e8866ecea327ad764d44594912f1dc09eb73c3ed5db134714e9f4b73e","src/rand.rs":"d409044aeabc86314b5b3dd9511f2341042582bab2ed9862ffeb87b031d73872","src/rsa.rs":"48e1d8c0100f87a69123daae20350c61e4ad6a256a535612c297bcb855aeada0","src/sha.rs":"c34f2f9df5fb52b578022568e195e011d0967f9f5ff57b559d7d2a235951a5b9","src/sign.rs":"9af5544b9c5d81c494ba055c247c8d152e5853a26efa60ff7c1788b569225fd9","src/srtp.rs":"3defe1815cfc790e2407ff935f8ca7b0e8d504242886e8841715279e0d85f721","src/ssl/bio.rs":"f6c20da805b711d69f527e9df8897061f9d6f3ef22d2d0a8f9fd87f96dc3947e","src/ssl/callbacks.rs":"07bacf44efc4977a7ad327bb026786585c78ebd991a0983c15669429f8d5d99b","src/ssl/connector.rs":"32afe0925584b349b3595aaabd0dadbf6ab383b5879c49c68ad2d0fddf0b0e4a","src/ssl/error.rs":"f39ac3e1037a35ae5cccbf5cf5976044614a6368c9ffe3f1b96bead63c0c4231","src/ssl/mod.rs":"070a0e7b2b48c44817a3a4247e238d7f014245bae7625d65bd88b9b35d9d9325","src/ssl/test/mod.rs":"0bf87ab47287ce40f1317016beeb54602a9a5836d00e0424072e67bedafa9c35","src/ssl/test/server.rs":"4276ba970a0fac5c9cae21d7df7af36389c377472f3546ce597678ffc6ad5b38","src/stack.rs":"29aa6e467153b951cbf56ab62ac806941b4eb0e1dd22f22d4b1ab562cc037d55","src/string.rs":"8276d719b35cd74ee0efbecce9e58e754d50d8cc96111f2febd3c0d8849847a8","src/symm.rs":"3da30db9c0c67dff2e68a36b1497f542f08ee20f6fe1ca6bc0986bd7c88575ba","src/util.rs":"e6794bf0643d0c29e96325653f2bb4a00221de55bb5b3c6c96d5dbae3debe238","src/version.rs":"e3acbb0db2095ab616870055c7c7a902fb7b1439520574fd20b7c1164b1178b7","src/x509/extension.rs":"26a265248eb0e54c3b106708f8fce7d5fb5b91b7195f17a97e1b8b1d3b6fa119","src/x509/mod.rs":"a51fc221c4bd75cada6d90b669f02d85bd519c1b37c190fe0f6a8cf7eb0594a8","src/x509/store.rs":"e42823f931ce2b6e4bac5f7314f3790c70dd12002398da03a2ebecd96f248c98","src/x509/tests.rs":"0d2dffcd49b013ad4daba22458f2ea543e8387e0523b1002904d3fb12e6bfb0c","src/x509/verify.rs":"9db665ffccecfd8a29874f8f4b0b3c09d195899daaa927dffdf57d6e9d32403e","test/aia_test_cert.pem":"9eaf52b5d0023f3be7911938d937ed16fc75d43d14dbe41557a800b0a82f4b1b","test/alt_name_cert.pem":"f3cc0a1d21657164918dffab0dac8f1c499fc1cf5717805420a0134b3aee128c","test/authority_key_identifier.pem":"4644b83bbcd36a6e1917d1f7bd3b8ff913bf86cc74917c07dd78b6731b4d5bec","test/ca.crt":"70bcf52acc79191409801e72371db3a0cd8a27c0fc24eacb3fb8f8ab3e558f67","test/cert.pem":"53c8b338be254490c71a6b13da90dc5a59ba596587c548be5673657e04824afb","test/certs.pem":"106d5d22c86e26c3db619b9525567f22333d22de82e4d2850ed379150c638008","test/certv3.pem":"c230b76b6efb973816d0e3096ae95cdcf4941ec928c01c31b6537d01743fcd8a","test/certv3_extfile":"610fdc10edac2da398a582895e53d288d3e47a9d4f3868c2c7f7662c212b60bd","test/cms.p12":"d33fc5edd6b9caa672e7570b869135235bb2583580a273f6e88c6a6c68fd5a8a","test/cms_pubkey.der":"03682a732e1fd861f5fa687915a8e6f5c935d10273b0f6f73f3db52a8d71fc6d","test/crl-ca.crt":"911360ccdf700fd7d6091bd78c4138da0e9f027ca211f7ed80b394e570eb897c","test/csr.pem":"24423008144c43cf33f56ebcc245931b2d61bcd4eee17b476d7adb6f7416e24d","test/dhparams.pem":"14d9461949d9ae8ca50a393b008ee2168254f14342b0e17b56c0a62d2905b963","test/dsa.pem":"826d513234205fd3dee0bbbf844f0b6fea501145bdf05ea3b14e14df98cbe090","test/dsa.pem.pub":"721677bebf9ab28b8650f98a0cd27658de0c1acd867a4b6e985fe1df95a8bd37","test/dsaparam.pem":"94a1284bdd7d7566151cfde0c7f245e84f7b99ba840f202e3f27ea0160f82988","test/entry_extensions.crl":"bee73d33a326bde92d3c38f275b3f94943e46cf778d7043e1176e84413dc22e9","test/identity.p12":"aceeb3e5516471bd5af9a44bbeffc9559c4f228f67c677d29f36a4b368e2779f","test/intermediate-ca.key":"a5f3d331af87c1305843e235841e494a0669a95d3824a6c766d09371f62c3bab","test/intermediate-ca.pem":"5ff8055325d0cbb60586f4e20bd2df7718e4d94f5261f2ee05ba52a8fb9223f0","test/key.der":"e8842cd6674b5c77a83e0283cd876a91de404561dfc86d79ce525f6e55b28197","test/key.der.pub":"e559d56bb6ec57ad743dbf972bbcaf263a9fa7d320433baa71b04f849d987060","test/key.pem":"12d9105a92bf39b615ccb4820c5c1e38c61905483cd30be13f9ab99b98af64ed","test/key.pem.pub":"f5d030df843ddbaba5bf316ae18f1434de5a63a955be66442429dd4f16f161ef","test/keystore-empty-chain.p12":"bbea280f6fe10556d7470df7072ef0e4ee3997e2c0b3666197f423430c0e6b61","test/leaf.pem":"4f2c3fd02f73b3f49a1e05cf0622669ed014ba019876d89d3f21c788457c1e01","test/nid_test_cert.pem":"7047e8d317e284c6b698eee4a0f1a629d50cd4615ad7da85fe90a2ffb6c21611","test/nid_uid_test_cert.pem":"a735211f3b40edbde7084337138fb0aea06aea6c78369c52015253e4b7a17d83","test/pkcs1.pem.pub":"4d446864b63c4178ec2c7dc8df9b7121d9271851c1f4701231fccb8b07c94918","test/pkcs8-nocrypt.der":"5590d03cc0d037c6c27d78fafc937f48defb226e9a52cde84d54df68086d0575","test/pkcs8.der":"8719fc002d59313fb97e46e068ae40db4d9acc0e2debd308ac9eb46329bea487","test/root-ca.key":"b37cf88614980c38e43c4329cdf7162bae48cc8af1fafd54db2fe0d17e458e1d","test/root-ca.pem":"59b9200c35e818bf21be4aaa97ba87bb6a18fd780527a9f9c51cc74212c631a0","test/rsa-encrypted.pem":"ea41b0f1816056672de6abbab43d0e8089da047c329ceed14aace5a5bde713f1","test/rsa.pem":"f866a5506ea9a37ed2f73f62f503e1aff32f7e4145be62b023535f4da1c24416","test/rsa.pem.pub":"2c5eeea39708e90396f9f09d920f2af8b7e9f84ace963c1319072224dd3d302b","test/subca.crt":"70bcf52acc79191409801e72371db3a0cd8a27c0fc24eacb3fb8f8ab3e558f67","test/test.crl":"ac8443257214f9e82543871c3df48694ea39f2b16bd6c4ef5998a161edbb8fba"},"package":"95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"} \ No newline at end of file diff --git a/vdev/Cargo.toml b/vdev/Cargo.toml index 30237186c7af2..b4fa716b8e9dc 100644 --- a/vdev/Cargo.toml +++ b/vdev/Cargo.toml @@ -6,7 +6,6 @@ authors = ["Vector Contributors "] license = "MPL-2.0" readme = "README.md" publish = false -rust-version = "1.71.1" [dependencies] anyhow = "1.0.86" diff --git a/vendor/addr2line/bench.plot.r b/vendor/addr2line/bench.plot.r new file mode 100644 index 0000000000000..ecbf2489351e9 --- /dev/null +++ b/vendor/addr2line/bench.plot.r @@ -0,0 +1,23 @@ +v <- read.table(file("stdin")) +t <- data.frame(prog=v[,1], funcs=(v[,2]=="func"), time=v[,3], mem=v[,4], stringsAsFactors=FALSE) + +t$prog <- as.character(t$prog) +t$prog[t$prog == "master"] <- "gimli-rs/addr2line" +t$funcs[t$funcs == TRUE] <- "With functions" +t$funcs[t$funcs == FALSE] <- "File/line only" +t$mem = t$mem / 1024.0 + +library(ggplot2) +p <- ggplot(data=t, aes(x=prog, y=time, fill=prog)) +p <- p + geom_bar(stat = "identity") +p <- p + facet_wrap(~ funcs) +p <- p + theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank()) +p <- p + ylab("time (s)") + ggtitle("addr2line runtime") +ggsave('time.png',plot=p,width=10,height=6) + +p <- ggplot(data=t, aes(x=prog, y=mem, fill=prog)) +p <- p + geom_bar(stat = "identity") +p <- p + facet_wrap(~ funcs) +p <- p + theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank()) +p <- p + ylab("memory (kB)") + ggtitle("addr2line memory usage") +ggsave('memory.png',plot=p,width=10,height=6) diff --git a/vendor/addr2line/benchmark.sh b/vendor/addr2line/benchmark.sh new file mode 100755 index 0000000000000..ca4c4f6ece58e --- /dev/null +++ b/vendor/addr2line/benchmark.sh @@ -0,0 +1,112 @@ +#!/bin/bash +if [[ $# -le 1 ]]; then + echo "Usage: $0 [] REFS..." + exit 1 +fi +target="$1" +shift + +addresses="" +if [[ -e "$1" ]]; then + addresses="$1" + shift +fi + +# path to "us" +# readlink -f, but more portable: +dirname=$(perl -e 'use Cwd "abs_path";print abs_path(shift)' "$(dirname "$0")") + +# https://stackoverflow.com/a/2358432/472927 +{ + # compile all refs + pushd "$dirname" > /dev/null + # if the user has some local changes, preserve them + nstashed=$(git stash list | wc -l) + echo "==> Stashing any local modifications" + git stash --keep-index > /dev/null + popstash() { + # https://stackoverflow.com/q/24520791/472927 + if [[ "$(git stash list | wc -l)" -ne "$nstashed" ]]; then + echo "==> Restoring stashed state" + git stash pop > /dev/null + fi + } + # if the user has added stuff to the index, abort + if ! git diff-index --quiet HEAD --; then + echo "Refusing to overwrite outstanding git changes" + popstash + exit 2 + fi + current=$(git symbolic-ref --short HEAD) + for ref in "$@"; do + echo "==> Compiling $ref" + git checkout -q "$ref" + commit=$(git rev-parse HEAD) + fn="target/release/addr2line-$commit" + if [[ ! -e "$fn" ]]; then + cargo build --release --example addr2line + cp target/release/examples/addr2line "$fn" + fi + if [[ "$ref" != "$commit" ]]; then + ln -sfn "addr2line-$commit" target/release/addr2line-"$ref" + fi + done + git checkout -q "$current" + popstash + popd > /dev/null + + # get us some addresses to look up + if [[ -z "$addresses" ]]; then + echo "==> Looking for benchmarking addresses (this may take a while)" + addresses=$(mktemp tmp.XXXXXXXXXX) + objdump -C -x --disassemble -l "$target" \ + | grep -P '0[048]:' \ + | awk '{print $1}' \ + | sed 's/:$//' \ + > "$addresses" + echo " -> Addresses stored in $addresses; you should re-use it next time" + fi + + run() { + func="$1" + name="$2" + cmd="$3" + args="$4" + printf "%s\t%s\t" "$name" "$func" + if [[ "$cmd" =~ llvm-symbolizer ]]; then + /usr/bin/time -f '%e\t%M' "$cmd" $args -obj="$target" < "$addresses" 2>&1 >/dev/null + else + /usr/bin/time -f '%e\t%M' "$cmd" $args -e "$target" < "$addresses" 2>&1 >/dev/null + fi + } + + # run without functions + log1=$(mktemp tmp.XXXXXXXXXX) + echo "==> Benchmarking" + run nofunc binutils addr2line >> "$log1" + #run nofunc elfutils eu-addr2line >> "$log1" + run nofunc llvm-sym llvm-symbolizer -functions=none >> "$log1" + for ref in "$@"; do + run nofunc "$ref" "$dirname/target/release/addr2line-$ref" >> "$log1" + done + cat "$log1" | column -t + + # run with functions + log2=$(mktemp tmp.XXXXXXXXXX) + echo "==> Benchmarking with -f" + run func binutils addr2line "-f -i" >> "$log2" + #run func elfutils eu-addr2line "-f -i" >> "$log2" + run func llvm-sym llvm-symbolizer "-functions=linkage -demangle=0" >> "$log2" + for ref in "$@"; do + run func "$ref" "$dirname/target/release/addr2line-$ref" "-f -i" >> "$log2" + done + cat "$log2" | column -t + cat "$log2" >> "$log1"; rm "$log2" + + echo "==> Plotting" + Rscript --no-readline --no-restore --no-save "$dirname/bench.plot.r" < "$log1" + + echo "==> Cleaning up" + rm "$log1" + exit 0 +} diff --git a/vendor/addr2line/coverage.sh b/vendor/addr2line/coverage.sh new file mode 100644 index 0000000000000..892c0b7faa6e8 --- /dev/null +++ b/vendor/addr2line/coverage.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# Run tarpaulin and pycobertura to generate coverage.html. + +cargo tarpaulin --skip-clean --out Xml +pycobertura show --format html --output coverage.html cobertura.xml diff --git a/vendor/ahash-0.7.7/.cargo-checksum.json b/vendor/ahash-0.7.7/.cargo-checksum.json new file mode 100644 index 0000000000000..7a7410090e773 --- /dev/null +++ b/vendor/ahash-0.7.7/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"16acf9b0dd6cbe5e377d740eb1a080ed1a84e75035c031c091d9f51e864a2949","FAQ.md":"9eb41898523ee209a0a937f9bcb78afe45ad55ca0556f8a4d4063558098f6d1e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"72185284f100e149998fe5301f70489e617cc4415b51cc77e967c63c6e970a67","build.rs":"123b322034273b5aa1b4934d84c277fef279afd533ecfb44831a3715e9887fcd","rustfmt.toml":"e090969e99df9360705680cc0097cfaddae10c22dc2e01470592cf3b9787fd36","src/aes_hash.rs":"0b11ce066931396222d2bed7eff678fdd7c8351819485efb721f62a30551866b","src/convert.rs":"f0e78840046493d0679a9ec077c8164cf57cf30d5e852b11bfadfdd996d29bd1","src/fallback_hash.rs":"ec00691bd555c69f7446afe893b6631cb84207cb7b512260dec8ef488e1905f3","src/hash_map.rs":"ed0c79c41c2218ad9591a585670a2b9b983807c9725880b780138a44c126cbfd","src/hash_quality_test.rs":"61695e5cac46ea25021a9d04199fb00c513e0c0c9c0f67aca0c647b9d2f7dd5a","src/hash_set.rs":"dc3d33e290aad62457ab1f5e64d3e33eb79e28c9468bfc8686339f0bbd8b19aa","src/lib.rs":"9fec7d1d412e414231c9b929081b1daa7c3b788a9f91eedd79a55efdf5d0d291","src/operations.rs":"10772e65b8b7106f195428c5eb8dbf6cbd49dd5a2165ac750e54af5995210f88","src/random_state.rs":"ce9689147659efa975887debe1481daddca09386ea8e1d5b4ee90ebeda6c8745","src/specialize.rs":"38d3b56ef4f264d564f48dbcb8ac137928babf90635090c9771c1a62140d1f30","tests/bench.rs":"0851dffebaffd7a437f6f9946ed5e03a957e9a6eb0da7911451af58778c411ec","tests/map_tests.rs":"e0f155f964dd965740b072ee1da110a8c6ef34491c95219f7c89064112c7840f","tests/nopanic.rs":"3363675c4c1a197b86604a0aebbe958fb5ec7c01a414fbfd70e9eb8a29707400"},"package":"5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd"} \ No newline at end of file diff --git a/vendor/ahash-0.7.7/Cargo.toml b/vendor/ahash-0.7.7/Cargo.toml new file mode 100644 index 0000000000000..32dd5e00a3903 --- /dev/null +++ b/vendor/ahash-0.7.7/Cargo.toml @@ -0,0 +1,149 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "ahash" +version = "0.7.7" +authors = ["Tom Kaitchuck "] +build = "./build.rs" +exclude = [ + "/smhasher", + "/benchmark_tools", +] +description = "A non-cryptographic hash function using AES-NI for high performance" +documentation = "https://docs.rs/ahash" +readme = "README.md" +keywords = [ + "hash", + "hasher", + "hashmap", + "aes", + "no-std", +] +categories = [ + "algorithms", + "data-structures", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/tkaitchuck/ahash" + +[package.metadata.docs.rs] +features = ["std"] +rustc-args = [ + "-C", + "target-feature=+aes", +] +rustdoc-args = [ + "-C", + "target-feature=+aes", +] + +[profile.bench] +opt-level = 3 +lto = "fat" +codegen-units = 1 +debug = 0 +debug-assertions = false + +[profile.release] +opt-level = 3 +lto = "fat" +codegen-units = 1 +debug = 0 +debug-assertions = false + +[profile.test] +opt-level = 2 +lto = "fat" + +[lib] +name = "ahash" +path = "src/lib.rs" +test = true +doctest = true +bench = true +doc = true + +[[bench]] +name = "ahash" +path = "tests/bench.rs" +harness = false + +[[bench]] +name = "map" +path = "tests/map_tests.rs" +harness = false + +[dev-dependencies.criterion] +version = "0.3.2" + +[dev-dependencies.fnv] +version = "1.0.5" + +[dev-dependencies.fxhash] +version = "0.2.1" + +[dev-dependencies.hex] +version = "0.4.2" + +[dev-dependencies.no-panic] +version = "0.1.10" + +[dev-dependencies.rand] +version = "0.7.3" + +[dev-dependencies.seahash] +version = "4.0" + +[dev-dependencies.serde_json] +version = "1.0.59" + +[build-dependencies.version_check] +version = "0.9" + +[features] +atomic-polyfill = [ + "dep:atomic-polyfill", + "once_cell/atomic-polyfill", +] +compile-time-rng = ["const-random"] +default = ["std"] +std = [] + +[target."cfg(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\"))".dependencies.const-random] +version = "0.1.12" +optional = true + +[target."cfg(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\"))".dependencies.getrandom] +version = "0.2.3" + +[target."cfg(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\"))".dependencies.serde] +version = "1.0.117" +optional = true + +[target."cfg(not(all(target_arch = \"arm\", target_os = \"none\")))".dependencies.once_cell] +version = "1.13.1" +features = ["alloc"] +default-features = false + +[target."cfg(not(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\")))".dependencies.atomic-polyfill] +version = "1.0.1" +optional = true + +[target."cfg(not(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\")))".dependencies.const-random] +version = "0.1.12" +optional = true + +[target."cfg(not(any(target_os = \"linux\", target_os = \"android\", target_os = \"windows\", target_os = \"macos\", target_os = \"ios\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"dragonfly\", target_os = \"solaris\", target_os = \"illumos\", target_os = \"fuchsia\", target_os = \"redox\", target_os = \"cloudabi\", target_os = \"haiku\", target_os = \"vxworks\", target_os = \"emscripten\", target_os = \"wasi\")))".dependencies.serde] +version = "1.0.117" +optional = true diff --git a/vendor/ahash-0.7.7/FAQ.md b/vendor/ahash-0.7.7/FAQ.md new file mode 100644 index 0000000000000..26c4a688e3b5b --- /dev/null +++ b/vendor/ahash-0.7.7/FAQ.md @@ -0,0 +1,118 @@ +## How does aHash prevent DOS attacks + +AHash is designed to [prevent an adversary that does not know the key from being able to create hash collisions or partial collisions.](https://github.com/tkaitchuck/aHash/wiki/How-aHash-is-resists-DOS-attacks) + +If you are a cryptographer and would like to help review aHash's algorithm, please post a comment [here](https://github.com/tkaitchuck/aHash/issues/11). + +In short, this is achieved by ensuring that: + +* aHash is designed to [resist differential crypto analysis](https://github.com/tkaitchuck/aHash/wiki/How-aHash-is-resists-DOS-attacks#differential-analysis). Meaning it should not be possible to devise a scheme to "cancel" out a modification of the internal state from a block of input via some corresponding change in a subsequent block of input. + * This is achieved by not performing any "premixing" - This reversible mixing gave previous hashes such as murmurhash confidence in their quality, but could be undone by a deliberate attack. + * Before it is used each chunk of input is "masked" such as by xoring it with an unpredictable value. +* aHash obeys the '[strict avalanche criterion](https://en.wikipedia.org/wiki/Avalanche_effect#Strict_avalanche_criterion)': +Each bit of input has the potential to flip every bit of the output. +* Similarly, each bit in the key can affect every bit in the output. +* Input bits never effect just one, or a very few, bits in intermediate state. This is specifically designed to prevent the sort of +[differential attacks launched by the sipHash authors](https://emboss.github.io/blog/2012/12/14/breaking-murmur-hash-flooding-dos-reloaded/) which cancel previous inputs. +* The `finish` call at the end of the hash is designed to not expose individual bits of the internal state. + * For example in the main algorithm 256bits of state and 256bits of keys are reduced to 64 total bits using 3 rounds of AES encryption. +Reversing this is more than non-trivial. Most of the information is by definition gone, and any given bit of the internal state is fully diffused across the output. +* In both aHash and its fallback the internal state is divided into two halves which are updated by two unrelated techniques using the same input. - This means that if there is a way to attack one of them it likely won't be able to attack both of them at the same time. +* It is deliberately difficult to 'chain' collisions. (This has been the major technique used to weaponize attacks on other hash functions) + +More details are available on [the wiki](https://github.com/tkaitchuck/aHash/wiki/How-aHash-is-resists-DOS-attacks). + +## Why not use a cryptographic hash in a hashmap. + +Cryptographic hashes are designed to make is nearly impossible to find two items that collide when the attacker has full control +over the input. This has several implications: + +* They are very difficult to construct, and have to go to a lot of effort to ensure that collisions are not possible. +* They have no notion of a 'key'. Rather, they are fully deterministic and provide exactly one hash for a given input. + +For a HashMap the requirements are different. + +* Speed is very important, especially for short inputs. Often the key for a HashMap is a single `u32` or similar, and to be effective +the bucket that it should be hashed to needs to be computed in just a few CPU cycles. +* A hashmap does not need to provide a hard and fast guarantee that no two inputs will ever collide. Hence, hashCodes are not 256bits +but are just 64 or 32 bits in length. Often the first thing done with the hashcode is to truncate it further to compute which among a few buckets should be used for a key. + * Here collisions are expected, and a cheap to deal with provided there is no systematic way to generated huge numbers of values that all +go to the same bucket. + * This also means that unlike a cryptographic hash partial collisions matter. It doesn't do a hashmap any good to produce a unique 256bit hash if +the lower 12 bits are all the same. This means that even a provably irreversible hash would not offer protection from a DOS attack in a hashmap +because an attacker can easily just brute force the bottom N bits. + +From a cryptography point of view, a hashmap needs something closer to a block cypher. +Where the input can be quickly mixed in a way that cannot be reversed without knowing a key. + +## Why isn't aHash cryptographically secure + +It is not designed to be. +Attempting to use aHash as a secure hash will likely fail to hold up for several reasons: + +1. aHash relies on random keys which are assumed to not be observable by an attacker. For a cryptographic hash all inputs can be seen and controlled by the attacker. +2. aHash has not yet gone through peer review, which is a pre-requisite for security critical algorithms. +3. Because aHash uses reduced rounds of AES as opposed to the standard of 10. Things like the SQUARE attack apply to part of the internal state. +(These are mitigated by other means to prevent producing collections, but would be a problem in other contexts). +4. Like any cypher based hash, it will show certain statistical deviations from truly random output when comparing a (VERY) large number of hashes. +(By definition cyphers have fewer collisions than truly random data.) + +There are efforts to build a secure hash function that uses AES-NI for acceleration, but aHash is not one of them. + +## How is aHash so fast + +AHash uses a number of tricks. + +One trick is taking advantage of specialization. If aHash is compiled on nightly it will take +advantage of specialized hash implementations for strings, slices, and primitives. + +Another is taking advantage of hardware instructions. +When it is available aHash uses AES rounds using the AES-NI instruction. AES-NI is very fast (on an intel i7-6700 it +is as fast as a 64 bit multiplication.) and handles 16 bytes of input at a time, while being a very strong permutation. + +This is obviously much faster than most standard approaches to hashing, and does a better job of scrambling data than most non-secure hashes. + +On an intel i7-6700 compiled on nightly Rust with flags `-C opt-level=3 -C target-cpu=native -C codegen-units=1`: + +| Input | SipHash 1-3 time | FnvHash time|FxHash time| aHash time| aHash Fallback* | +|----------------|-----------|-----------|-----------|-----------|---------------| +| u8 | 9.3271 ns | 0.808 ns | **0.594 ns** | 0.7704 ns | 0.7664 ns | +| u16 | 9.5139 ns | 0.803 ns | **0.594 ns** | 0.7653 ns | 0.7704 ns | +| u32 | 9.1196 ns | 1.4424 ns | **0.594 ns** | 0.7637 ns | 0.7712 ns | +| u64 | 10.854 ns | 3.0484 ns | **0.628 ns** | 0.7788 ns | 0.7888 ns | +| u128 | 12.465 ns | 7.0728 ns | 0.799 ns | **0.6174 ns** | 0.6250 ns | +| 1 byte string | 11.745 ns | 2.4743 ns | 2.4000 ns | **1.4921 ns** | 1.5861 ns | +| 3 byte string | 12.066 ns | 3.5221 ns | 2.9253 ns | **1.4745 ns** | 1.8518 ns | +| 4 byte string | 11.634 ns | 4.0770 ns | 1.8818 ns | **1.5206 ns** | 1.8924 ns | +| 7 byte string | 14.762 ns | 5.9780 ns | 3.2282 ns | **1.5207 ns** | 1.8933 ns | +| 8 byte string | 13.442 ns | 4.0535 ns | 2.9422 ns | **1.6262 ns** | 1.8929 ns | +| 15 byte string | 16.880 ns | 8.3434 ns | 4.6070 ns | **1.6265 ns** | 1.7965 ns | +| 16 byte string | 15.155 ns | 7.5796 ns | 3.2619 ns | **1.6262 ns** | 1.8011 ns | +| 24 byte string | 16.521 ns | 12.492 ns | 3.5424 ns | **1.6266 ns** | 2.8311 ns | +| 68 byte string | 24.598 ns | 50.715 ns | 5.8312 ns | **4.8282 ns** | 5.4824 ns | +| 132 byte string| 39.224 ns | 119.96 ns | 11.777 ns | **6.5087 ns** | 9.1459 ns | +|1024 byte string| 254.00 ns | 1087.3 ns | 156.41 ns | **25.402 ns** | 54.566 ns | + +* Fallback refers to the algorithm aHash would use if AES instructions are unavailable. +For reference a hash that does nothing (not even reads the input data takes) **0.520 ns**. So that represents the fastest +possible time. + +As you can see above aHash like `FxHash` provides a large speedup over `SipHash-1-3` which is already nearly twice as fast as `SipHash-2-4`. + +Rust's HashMap by default uses `SipHash-1-3` because faster hash functions such as `FxHash` are predictable and vulnerable to denial of +service attacks. While `aHash` has both very strong scrambling and very high performance. + +AHash performs well when dealing with large inputs because aHash reads 8 or 16 bytes at a time. (depending on availability of AES-NI) + +Because of this, and its optimized logic, `aHash` is able to outperform `FxHash` with strings. +It also provides especially good performance dealing with unaligned input. +(Notice the big performance gaps between 3 vs 4, 7 vs 8 and 15 vs 16 in `FxHash` above) + +### Which CPUs can use the hardware acceleration + +Hardware AES instructions are built into Intel processors built after 2010 and AMD processors after 2012. +It is also available on [many other CPUs](https://en.wikipedia.org/wiki/AES_instruction_set) should in eventually +be able to get aHash to work. However, only X86 and X86-64 are the only supported architectures at the moment, as currently +they are the only architectures for which Rust provides an intrinsic. + +aHash also uses `sse2` and `sse3` instructions. X86 processors that have `aesni` also have these instruction sets. diff --git a/vendor/ahash-0.7.7/LICENSE-APACHE b/vendor/ahash-0.7.7/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/vendor/ahash-0.7.7/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/ahash-0.7.7/LICENSE-MIT b/vendor/ahash-0.7.7/LICENSE-MIT new file mode 100644 index 0000000000000..5afc2a7b0acab --- /dev/null +++ b/vendor/ahash-0.7.7/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Amanieu d'Antras + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/ahash-0.7.7/README.md b/vendor/ahash-0.7.7/README.md new file mode 100644 index 0000000000000..be365a79f1a1b --- /dev/null +++ b/vendor/ahash-0.7.7/README.md @@ -0,0 +1,110 @@ +# aHash ![Build Status](https://img.shields.io/github/workflow/status/tkaitchuck/ahash/Rust) ![Licence](https://img.shields.io/crates/l/ahash) ![Downloads](https://img.shields.io/crates/d/ahash) + +AHash is the [fastest](https://github.com/tkaitchuck/aHash/blob/master/compare/readme.md#Speed), +[DOS resistant hash](https://github.com/tkaitchuck/aHash/wiki/How-aHash-is-resists-DOS-attacks) currently available in Rust. +AHash is intended *exclusively* for use in in-memory hashmaps. + +AHash's output is of [high quality](https://github.com/tkaitchuck/aHash/blob/master/compare/readme.md#Quality) but aHash is **not** a cryptographically secure hash. + +## Design + +Because AHash is a keyed hash, each map will produce completely different hashes, which cannot be predicted without knowing the keys. +[This prevents DOS attacks where an attacker sends a large number of items whose hashes collide that get used as keys in a hashmap.](https://github.com/tkaitchuck/aHash/wiki/How-aHash-is-resists-DOS-attacks) + +This also avoids [accidentally quadratic behavior by reading from one map and writing to another.](https://accidentallyquadratic.tumblr.com/post/153545455987/rust-hash-iteration-reinsertion) + +## Goals and Non-Goals + +AHash does *not* have a fixed standard for its output. This allows it to improve over time. For example, +if any faster algorithm is found, aHash will be updated to incorporate the technique. +Similarly, should any flaw in aHash's DOS resistance be found, aHash will be changed to correct the flaw. + +Because it does not have a fixed standard, different computers or computers on different versions of the code will observe different hash values. +As such, aHash is not recommended for use other than in-memory maps. Specifically, aHash is not intended for network use or in applications which persist hashed values. +(In these cases `HighwayHash` would be a better choice) + +Additionally, aHash is not intended to be cryptographically secure and should not be used as a MAC, or anywhere which requires a cryptographically secure hash. +(In these cases `SHA-3` would be a better choice) + +## Usage + +AHash is a drop in replacement for the default implementation of the `Hasher` trait. To construct a `HashMap` using aHash +as its hasher do the following: + +```rust +use ahash::{AHasher, RandomState}; +use std::collections::HashMap; + +let mut map: HashMap = HashMap::default(); +map.insert(12, 34); +``` +For convenience, wrappers called `AHashMap` and `AHashSet` are also provided. +These do the same thing with slightly less typing. +```rust +use ahash::AHashMap; + +let mut map: AHashMap = AHashMap::new(); +map.insert(12, 34); +map.insert(56, 78); +``` + +## Flags + +The aHash package has the following flags: +* `std`: This enables features which require the standard library. (On by default) This includes providing the utility classes `AHashMap` and `AHashSet`. +* `serde`: Enables `serde` support for the utility classes `AHashMap` and `AHashSet`. +* `compile-time-rng`: Whenever possible aHash will seed hashers with random numbers using the [getrandom](https://github.com/rust-random/getrandom) crate. +This is possible for OS targets which provide a source of randomness. (see the [full list](https://docs.rs/getrandom/0.2.0/getrandom/#supported-targets).) +For OS targets without access to a random number generator, `compile-time-rng` provides an alternative. +If `getrandom` is unavailable and `compile-time-rng` is enabled, aHash will generate random numbers at compile time and embed them in the binary. +This allows for DOS resistance even if there is no random number generator available at runtime (assuming the compiled binary is not public). +This makes the binary non-deterministic, unless `getrandom` is available for the target in which case the flag does nothing. +(If non-determinism is a problem see [constrandom's documentation](https://github.com/tkaitchuck/constrandom#deterministic-builds)) + +**NOTE:** If `getrandom` is unavailable and `compile-time-rng` is disabled aHash will fall back on using the numeric +value of memory addresses as a source of randomness. This is somewhat strong if ALSR is turned on (it is by default) +but for embedded platforms this will result in weak keys. As a result, it is recommended to use `compile-time-rng` anytime +random numbers will not be available at runtime. + +## Comparison with other hashers + +A full comparison with other hashing algorithms can be found [here](https://github.com/tkaitchuck/aHash/blob/master/compare/readme.md) + +![Hasher performance](https://docs.google.com/spreadsheets/d/e/2PACX-1vSK7Li2nS-Bur9arAYF9IfT37MP-ohAe1v19lZu5fd9MajI1fSveLAQZyEie4Ea9k5-SWHTff7nL2DW/pubchart?oid=1323618938&format=image) + +For a more representative performance comparison which includes the overhead of using a HashMap, see [HashBrown's benchmarks](https://github.com/rust-lang/hashbrown#performance) +as HashBrown now uses aHash as its hasher by default. + +## Hash quality + +AHash passes the full [SMHasher test suite](https://github.com/rurban/smhasher). + +The code to reproduce the result, and the full output [are checked into the repo](https://github.com/tkaitchuck/aHash/tree/master/smhasher). + +## Additional FAQ + +A separate FAQ document is maintained [here](https://github.com/tkaitchuck/aHash/blob/master/FAQ.md). +If you have questions not covered there, open an issue [here](https://github.com/tkaitchuck/aHash/issues). + +## License + +Licensed under either of: + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +## Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. + + + + + + + + diff --git a/vendor/ahash-0.7.7/build.rs b/vendor/ahash-0.7.7/build.rs new file mode 100644 index 0000000000000..8be4964e520e0 --- /dev/null +++ b/vendor/ahash-0.7.7/build.rs @@ -0,0 +1,45 @@ +#![deny(warnings)] + +use std::env; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + if let Some(channel) = version_check::Channel::read() { + if channel.supports_features() { + println!("cargo:rustc-cfg=feature=\"specialize\""); + println!("cargo:rustc-cfg=feature=\"stdsimd\""); + } + } + let os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set"); + if os.eq_ignore_ascii_case("linux") + || os.eq_ignore_ascii_case("android") + || os.eq_ignore_ascii_case("windows") + || os.eq_ignore_ascii_case("macos") + || os.eq_ignore_ascii_case("ios") + || os.eq_ignore_ascii_case("freebsd") + || os.eq_ignore_ascii_case("openbsd") + || os.eq_ignore_ascii_case("dragonfly") + || os.eq_ignore_ascii_case("solaris") + || os.eq_ignore_ascii_case("illumos") + || os.eq_ignore_ascii_case("fuchsia") + || os.eq_ignore_ascii_case("redox") + || os.eq_ignore_ascii_case("cloudabi") + || os.eq_ignore_ascii_case("haiku") + || os.eq_ignore_ascii_case("vxworks") + || os.eq_ignore_ascii_case("emscripten") + || os.eq_ignore_ascii_case("wasi") + { + println!("cargo:rustc-cfg=feature=\"runtime-rng\""); + } + let arch = env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH was not set"); + if arch.eq_ignore_ascii_case("x86_64") + || arch.eq_ignore_ascii_case("aarch64") + || arch.eq_ignore_ascii_case("mips64") + || arch.eq_ignore_ascii_case("powerpc64") + || arch.eq_ignore_ascii_case("riscv64gc") + || arch.eq_ignore_ascii_case("s390x") + { + println!("cargo:rustc-cfg=feature=\"folded_multiply\""); + } + +} diff --git a/vendor/ahash-0.7.7/rustfmt.toml b/vendor/ahash-0.7.7/rustfmt.toml new file mode 100644 index 0000000000000..75306517965a5 --- /dev/null +++ b/vendor/ahash-0.7.7/rustfmt.toml @@ -0,0 +1 @@ +max_width = 120 diff --git a/vendor/ahash-0.7.7/src/aes_hash.rs b/vendor/ahash-0.7.7/src/aes_hash.rs new file mode 100644 index 0000000000000..7e619b520b9c9 --- /dev/null +++ b/vendor/ahash-0.7.7/src/aes_hash.rs @@ -0,0 +1,440 @@ +use crate::convert::*; +#[cfg(feature = "specialize")] +use crate::fallback_hash::MULTIPLE; +use crate::operations::*; +use crate::RandomState; +use core::hash::Hasher; +use crate::random_state::PI; + +/// A `Hasher` for hashing an arbitrary stream of bytes. +/// +/// Instances of [`AHasher`] represent state that is updated while hashing data. +/// +/// Each method updates the internal state based on the new data provided. Once +/// all of the data has been provided, the resulting hash can be obtained by calling +/// `finish()` +/// +/// [Clone] is also provided in case you wish to calculate hashes for two different items that +/// start with the same data. +/// +#[derive(Debug, Clone)] +pub struct AHasher { + enc: u128, + sum: u128, + key: u128, +} + +impl AHasher { + /// Creates a new hasher keyed to the provided keys. + /// + /// Normally hashers are created via `AHasher::default()` for fixed keys or `RandomState::new()` for randomly + /// generated keys and `RandomState::with_seeds(a,b)` for seeds that are set and can be reused. All of these work at + /// map creation time (and hence don't have any overhead on a per-item bais). + /// + /// This method directly creates the hasher instance and performs no transformation on the provided seeds. This may + /// be useful where a HashBuilder is not desired, such as for testing purposes. + /// + /// # Example + /// + /// ``` + /// use std::hash::Hasher; + /// use ahash::AHasher; + /// + /// let mut hasher = AHasher::new_with_keys(1234, 5678); + /// + /// hasher.write_u32(1989); + /// hasher.write_u8(11); + /// hasher.write_u8(9); + /// hasher.write(b"Huh?"); + /// + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` + #[inline] + pub fn new_with_keys(key1: u128, key2: u128) -> Self { + let pi: [u128; 2] = PI.convert(); + let key1 = key1 ^ pi[0]; + let key2 = key2 ^ pi[1]; + Self { + enc: key1, + sum: key2, + key: key1 ^ key2, + } + } + + #[allow(unused)] // False positive + pub(crate) fn test_with_keys(key1: u128, key2: u128) -> Self { + Self { + enc: key1, + sum: key2, + key: key1 ^ key2, + } + } + + + #[inline] + pub(crate) fn from_random_state(rand_state: &RandomState) -> Self { + let key1 = [rand_state.k0, rand_state.k1].convert(); + let key2 = [rand_state.k2, rand_state.k3].convert(); + Self { + enc: key1, + sum: key2, + key: key1 ^ key2, + } + } + + #[inline(always)] + fn add_in_length(&mut self, length: u64) { + //This will be scrambled by the next AES round. + let mut enc: [u64; 2] = self.enc.convert(); + enc[0] = enc[0].wrapping_add(length); + self.enc = enc.convert(); + } + + #[inline(always)] + fn hash_in(&mut self, new_value: u128) { + self.enc = aesenc(self.enc, new_value); + self.sum = shuffle_and_add(self.sum, new_value); + } + + #[inline(always)] + fn hash_in_2(&mut self, v1: u128, v2: u128) { + self.enc = aesenc(self.enc, v1); + self.sum = shuffle_and_add(self.sum, v1); + self.enc = aesenc(self.enc, v2); + self.sum = shuffle_and_add(self.sum, v2); + } + + #[inline] + #[cfg(feature = "specialize")] + fn short_finish(&self) -> u64 { + let combined = aesdec(self.sum, self.enc); + let result: [u64; 2] = aesenc(combined, combined).convert(); + result[0] + } +} + +/// Provides [Hasher] methods to hash all of the primitive types. +/// +/// [Hasher]: core::hash::Hasher +impl Hasher for AHasher { + #[inline] + fn write_u8(&mut self, i: u8) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u16(&mut self, i: u16) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u128(&mut self, i: u128) { + self.hash_in(i); + } + + #[inline] + #[cfg(any(target_pointer_width = "64", target_pointer_width = "32", target_pointer_width = "16"))] + fn write_usize(&mut self, i: usize) { + self.write_u64(i as u64); + } + + #[inline] + #[cfg(target_pointer_width = "128")] + fn write_usize(&mut self, i: usize) { + self.write_u128(i as u128); + } + + #[inline] + fn write_u64(&mut self, i: u64) { + self.write_u128(i as u128); + } + + #[inline] + #[allow(clippy::collapsible_if)] + fn write(&mut self, input: &[u8]) { + let mut data = input; + let length = data.len(); + self.add_in_length(length as u64); + //A 'binary search' on sizes reduces the number of comparisons. + if data.len() <= 8 { + let value = read_small(data); + self.hash_in(value.convert()); + } else { + if data.len() > 32 { + if data.len() > 64 { + let tail = data.read_last_u128x4(); + let mut current: [u128; 4] = [self.key; 4]; + current[0] = aesenc(current[0], tail[0]); + current[1] = aesdec(current[1], tail[1]); + current[2] = aesenc(current[2], tail[2]); + current[3] = aesdec(current[3], tail[3]); + let mut sum: [u128; 2] = [self.key, !self.key]; + sum[0] = add_by_64s(sum[0].convert(), tail[0].convert()).convert(); + sum[1] = add_by_64s(sum[1].convert(), tail[1].convert()).convert(); + sum[0] = shuffle_and_add(sum[0], tail[2]); + sum[1] = shuffle_and_add(sum[1], tail[3]); + while data.len() > 64 { + let (blocks, rest) = data.read_u128x4(); + current[0] = aesenc(current[0], blocks[0]); + current[1] = aesenc(current[1], blocks[1]); + current[2] = aesenc(current[2], blocks[2]); + current[3] = aesenc(current[3], blocks[3]); + sum[0] = shuffle_and_add(sum[0], blocks[0]); + sum[1] = shuffle_and_add(sum[1], blocks[1]); + sum[0] = shuffle_and_add(sum[0], blocks[2]); + sum[1] = shuffle_and_add(sum[1], blocks[3]); + data = rest; + } + self.hash_in_2(current[0], current[1]); + self.hash_in_2(current[2], current[3]); + self.hash_in_2(sum[0], sum[1]); + } else { + //len 33-64 + let (head, _) = data.read_u128x2(); + let tail = data.read_last_u128x2(); + self.hash_in_2(head[0], head[1]); + self.hash_in_2(tail[0], tail[1]); + } + } else { + if data.len() > 16 { + //len 17-32 + self.hash_in_2(data.read_u128().0, data.read_last_u128()); + } else { + //len 9-16 + let value: [u64; 2] = [data.read_u64().0, data.read_last_u64()]; + self.hash_in(value.convert()); + } + } + } + } + #[inline] + fn finish(&self) -> u64 { + let combined = aesdec(self.sum, self.enc); + let result: [u64; 2] = aesenc(aesenc(combined, self.key), combined).convert(); + result[1] + } +} + +#[cfg(feature = "specialize")] +pub(crate) struct AHasherU64 { + pub(crate) buffer: u64, + pub(crate) pad: u64, +} + +/// A specialized hasher for only primitives under 64 bits. +#[cfg(feature = "specialize")] +impl Hasher for AHasherU64 { + #[inline] + fn finish(&self) -> u64 { + let rot = (self.pad & 63) as u32; + self.buffer.rotate_left(rot) + } + + #[inline] + fn write(&mut self, _bytes: &[u8]) { + unreachable!("Specialized hasher was called with a different type of object") + } + + #[inline] + fn write_u8(&mut self, i: u8) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u16(&mut self, i: u16) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u64(&mut self, i: u64) { + self.buffer = folded_multiply(i ^ self.buffer, MULTIPLE); + } + + #[inline] + fn write_u128(&mut self, _i: u128) { + unreachable!("Specialized hasher was called with a different type of object") + } + + #[inline] + fn write_usize(&mut self, _i: usize) { + unreachable!("Specialized hasher was called with a different type of object") + } +} + +#[cfg(feature = "specialize")] +pub(crate) struct AHasherFixed(pub AHasher); + +/// A specialized hasher for fixed size primitives larger than 64 bits. +#[cfg(feature = "specialize")] +impl Hasher for AHasherFixed { + #[inline] + fn finish(&self) -> u64 { + self.0.short_finish() + } + + #[inline] + fn write(&mut self, bytes: &[u8]) { + self.0.write(bytes) + } + + #[inline] + fn write_u8(&mut self, i: u8) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u16(&mut self, i: u16) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u64(&mut self, i: u64) { + self.0.write_u64(i); + } + + #[inline] + fn write_u128(&mut self, i: u128) { + self.0.write_u128(i); + } + + #[inline] + fn write_usize(&mut self, i: usize) { + self.0.write_usize(i); + } +} + +#[cfg(feature = "specialize")] +pub(crate) struct AHasherStr(pub AHasher); + +/// A specialized hasher for strings +/// Note that the other types don't panic because the hash impl for String tacks on an unneeded call. (As does vec) +#[cfg(feature = "specialize")] +impl Hasher for AHasherStr { + #[inline] + fn finish(&self) -> u64 { + let result : [u64; 2] = self.0.enc.convert(); + result[0] + } + + #[inline] + fn write(&mut self, bytes: &[u8]) { + if bytes.len() > 8 { + self.0.write(bytes); + self.0.enc = aesdec(self.0.sum, self.0.enc); + self.0.enc = aesenc(aesenc(self.0.enc, self.0.key), self.0.enc); + } else { + self.0.add_in_length(bytes.len() as u64); + let value = read_small(bytes).convert(); + self.0.sum = shuffle_and_add(self.0.sum, value); + self.0.enc = aesdec(self.0.sum, self.0.enc); + self.0.enc = aesenc(aesenc(self.0.enc, self.0.key), self.0.enc); + } + } + + #[inline] + fn write_u8(&mut self, _i: u8) {} + + #[inline] + fn write_u16(&mut self, _i: u16) {} + + #[inline] + fn write_u32(&mut self, _i: u32) {} + + #[inline] + fn write_u64(&mut self, _i: u64) {} + + #[inline] + fn write_u128(&mut self, _i: u128) {} + + #[inline] + fn write_usize(&mut self, _i: usize) {} +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::convert::Convert; + use crate::operations::aesenc; + use crate::RandomState; + use std::hash::{BuildHasher, Hasher}; + #[test] + fn test_sanity() { + let mut hasher = RandomState::with_seeds(1, 2, 3, 4).build_hasher(); + hasher.write_u64(0); + let h1 = hasher.finish(); + hasher.write(&[1, 0, 0, 0, 0, 0, 0, 0]); + let h2 = hasher.finish(); + assert_ne!(h1, h2); + } + + #[cfg(feature = "compile-time-rng")] + #[test] + fn test_builder() { + use std::collections::HashMap; + use std::hash::BuildHasherDefault; + + let mut map = HashMap::>::default(); + map.insert(1, 3); + } + + #[cfg(feature = "compile-time-rng")] + #[test] + fn test_default() { + let hasher_a = AHasher::default(); + let a_enc: [u64; 2] = hasher_a.enc.convert(); + let a_sum: [u64; 2] = hasher_a.sum.convert(); + assert_ne!(0, a_enc[0]); + assert_ne!(0, a_enc[1]); + assert_ne!(0, a_sum[0]); + assert_ne!(0, a_sum[1]); + assert_ne!(a_enc[0], a_enc[1]); + assert_ne!(a_sum[0], a_sum[1]); + assert_ne!(a_enc[0], a_sum[0]); + assert_ne!(a_enc[1], a_sum[1]); + let hasher_b = AHasher::default(); + let b_enc: [u64; 2] = hasher_b.enc.convert(); + let b_sum: [u64; 2] = hasher_b.sum.convert(); + assert_eq!(a_enc[0], b_enc[0]); + assert_eq!(a_enc[1], b_enc[1]); + assert_eq!(a_sum[0], b_sum[0]); + assert_eq!(a_sum[1], b_sum[1]); + } + + #[test] + fn test_hash() { + let mut result: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d]; + let value: [u64; 2] = [1 << 32, 0xFEDCBA9876543210]; + result = aesenc(value.convert(), result.convert()).convert(); + result = aesenc(result.convert(), result.convert()).convert(); + let mut result2: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d]; + let value2: [u64; 2] = [1, 0xFEDCBA9876543210]; + result2 = aesenc(value2.convert(), result2.convert()).convert(); + result2 = aesenc(result2.convert(), result.convert()).convert(); + let result: [u8; 16] = result.convert(); + let result2: [u8; 16] = result2.convert(); + assert_ne!(hex::encode(result), hex::encode(result2)); + } + + #[test] + fn test_conversion() { + let input: &[u8] = "dddddddd".as_bytes(); + let bytes: u64 = as_array!(input, 8).convert(); + assert_eq!(bytes, 0x6464646464646464); + } +} + diff --git a/vendor/ahash-0.7.7/src/convert.rs b/vendor/ahash-0.7.7/src/convert.rs new file mode 100644 index 0000000000000..4c0a00eb7c56f --- /dev/null +++ b/vendor/ahash-0.7.7/src/convert.rs @@ -0,0 +1,167 @@ +pub(crate) trait Convert { + fn convert(self) -> To; +} + +macro_rules! convert { + ($a:ty, $b:ty) => { + impl Convert<$b> for $a { + #[inline(always)] + fn convert(self) -> $b { + unsafe { + core::mem::transmute::<$a, $b>(self) + } + } + } + impl Convert<$a> for $b { + #[inline(always)] + fn convert(self) -> $a { + unsafe { + core::mem::transmute::<$b, $a>(self) + } + } + } + }; +} + +convert!([u128; 4], [u64; 8]); +convert!([u128; 4], [u32; 16]); +convert!([u128; 4], [u16; 32]); +convert!([u128; 4], [u8; 64]); +convert!([u128; 2], [u64; 4]); +convert!([u128; 2], [u32; 8]); +convert!([u128; 2], [u16; 16]); +convert!([u128; 2], [u8; 32]); +convert!(u128, [u64; 2]); +convert!(u128, [u32; 4]); +convert!(u128, [u16; 8]); +convert!(u128, [u8; 16]); +convert!([u64; 8], [u32; 16]); +convert!([u64; 8], [u16; 32]); +convert!([u64; 8], [u8; 64]); +convert!([u64; 4], [u32; 8]); +convert!([u64; 4], [u16; 16]); +convert!([u64; 4], [u8; 32]); +convert!([u64; 2], [u32; 4]); +convert!([u64; 2], [u16; 8]); +convert!([u64; 2], [u8; 16]); +convert!([u32; 4], [u16; 8]); +convert!([u32; 4], [u8; 16]); +convert!([u16; 8], [u8; 16]); +convert!(u64, [u32; 2]); +convert!(u64, [u16; 4]); +convert!(u64, [u8; 8]); +convert!([u32; 2], [u16; 4]); +convert!([u32; 2], [u8; 8]); +convert!(u32, [u16; 2]); +convert!(u32, [u8; 4]); +convert!([u16; 2], [u8; 4]); +convert!(u16, [u8; 2]); +convert!([[u64; 4]; 2], [u8; 64]); + +convert!([f64; 2], [u8; 16]); +convert!([f32; 4], [u8; 16]); +convert!(f64, [u8; 8]); +convert!([f32; 2], [u8; 8]); +convert!(f32, [u8; 4]); + +macro_rules! as_array { + ($input:expr, $len:expr) => {{ + { + #[inline(always)] + fn as_array(slice: &[T]) -> &[T; $len] { + assert_eq!(slice.len(), $len); + unsafe { &*(slice.as_ptr() as *const [_; $len]) } + } + as_array($input) + } + }}; +} + +pub(crate) trait ReadFromSlice { + fn read_u16(&self) -> (u16, &[u8]); + fn read_u32(&self) -> (u32, &[u8]); + fn read_u64(&self) -> (u64, &[u8]); + fn read_u128(&self) -> (u128, &[u8]); + fn read_u128x2(&self) -> ([u128; 2], &[u8]); + fn read_u128x4(&self) -> ([u128; 4], &[u8]); + fn read_last_u16(&self) -> u16; + fn read_last_u32(&self) -> u32; + fn read_last_u64(&self) -> u64; + fn read_last_u128(&self) -> u128; + fn read_last_u128x2(&self) -> [u128; 2]; + fn read_last_u128x4(&self) -> [u128; 4]; +} + +impl ReadFromSlice for [u8] { + #[inline(always)] + fn read_u16(&self) -> (u16, &[u8]) { + let (value, rest) = self.split_at(2); + (as_array!(value, 2).convert(), rest) + } + + #[inline(always)] + fn read_u32(&self) -> (u32, &[u8]) { + let (value, rest) = self.split_at(4); + (as_array!(value, 4).convert(), rest) + } + + #[inline(always)] + fn read_u64(&self) -> (u64, &[u8]) { + let (value, rest) = self.split_at(8); + (as_array!(value, 8).convert(), rest) + } + + #[inline(always)] + fn read_u128(&self) -> (u128, &[u8]) { + let (value, rest) = self.split_at(16); + (as_array!(value, 16).convert(), rest) + } + + #[inline(always)] + fn read_u128x2(&self) -> ([u128; 2], &[u8]) { + let (value, rest) = self.split_at(32); + (as_array!(value, 32).convert(), rest) + } + + #[inline(always)] + fn read_u128x4(&self) -> ([u128; 4], &[u8]) { + let (value, rest) = self.split_at(64); + (as_array!(value, 64).convert(), rest) + } + + #[inline(always)] + fn read_last_u16(&self) -> u16 { + let (_, value) = self.split_at(self.len() - 2); + as_array!(value, 2).convert() + } + + #[inline(always)] + fn read_last_u32(&self) -> u32 { + let (_, value) = self.split_at(self.len() - 4); + as_array!(value, 4).convert() + } + + #[inline(always)] + fn read_last_u64(&self) -> u64 { + let (_, value) = self.split_at(self.len() - 8); + as_array!(value, 8).convert() + } + + #[inline(always)] + fn read_last_u128(&self) -> u128 { + let (_, value) = self.split_at(self.len() - 16); + as_array!(value, 16).convert() + } + + #[inline(always)] + fn read_last_u128x2(&self) -> [u128; 2] { + let (_, value) = self.split_at(self.len() - 32); + as_array!(value, 32).convert() + } + + #[inline(always)] + fn read_last_u128x4(&self) -> [u128; 4] { + let (_, value) = self.split_at(self.len() - 64); + as_array!(value, 64).convert() + } +} diff --git a/vendor/ahash-0.7.7/src/fallback_hash.rs b/vendor/ahash-0.7.7/src/fallback_hash.rs new file mode 100644 index 0000000000000..aad9efc859c5c --- /dev/null +++ b/vendor/ahash-0.7.7/src/fallback_hash.rs @@ -0,0 +1,392 @@ +use crate::convert::*; +use crate::operations::folded_multiply; +use crate::operations::read_small; +use crate::random_state::PI; +use crate::RandomState; +use core::hash::Hasher; + +///This constant come from Kunth's prng (Empirically it works better than those from splitmix32). +pub(crate) const MULTIPLE: u64 = 6364136223846793005; +const ROT: u32 = 23; //17 + +/// A `Hasher` for hashing an arbitrary stream of bytes. +/// +/// Instances of [`AHasher`] represent state that is updated while hashing data. +/// +/// Each method updates the internal state based on the new data provided. Once +/// all of the data has been provided, the resulting hash can be obtained by calling +/// `finish()` +/// +/// [Clone] is also provided in case you wish to calculate hashes for two different items that +/// start with the same data. +/// +#[derive(Debug, Clone)] +pub struct AHasher { + buffer: u64, + pad: u64, + extra_keys: [u64; 2], +} + +impl AHasher { + /// Creates a new hasher keyed to the provided key. + #[inline] + #[allow(dead_code)] // Is not called if non-fallback hash is used. + pub fn new_with_keys(key1: u128, key2: u128) -> AHasher { + let pi: [u128; 2] = PI.convert(); + let key1: [u64; 2] = (key1 ^ pi[0]).convert(); + let key2: [u64; 2] = (key2 ^ pi[1]).convert(); + AHasher { + buffer: key1[0], + pad: key1[1], + extra_keys: key2, + } + } + + #[allow(unused)] // False positive + pub(crate) fn test_with_keys(key1: u128, key2: u128) -> Self { + let key1: [u64; 2] = key1.convert(); + let key2: [u64; 2] = key2.convert(); + Self { + buffer: key1[0], + pad: key1[1], + extra_keys: key2, + } + } + + #[inline] + #[allow(dead_code)] // Is not called if non-fallback hash is used. + pub(crate) fn from_random_state(rand_state: &RandomState) -> AHasher { + AHasher { + buffer: rand_state.k0, + pad: rand_state.k1, + extra_keys: [rand_state.k2, rand_state.k3], + } + } + + /// This update function has the goal of updating the buffer with a single multiply + /// FxHash does this but is vulnerable to attack. To avoid this input needs to be masked to with an + /// unpredictable value. Other hashes such as murmurhash have taken this approach but were found vulnerable + /// to attack. The attack was based on the idea of reversing the pre-mixing (Which is necessarily + /// reversible otherwise bits would be lost) then placing a difference in the highest bit before the + /// multiply used to mix the data. Because a multiply can never affect the bits to the right of it, a + /// subsequent update that also differed in this bit could result in a predictable collision. + /// + /// This version avoids this vulnerability while still only using a single multiply. It takes advantage + /// of the fact that when a 64 bit multiply is performed the upper 64 bits are usually computed and thrown + /// away. Instead it creates two 128 bit values where the upper 64 bits are zeros and multiplies them. + /// (The compiler is smart enough to turn this into a 64 bit multiplication in the assembly) + /// Then the upper bits are xored with the lower bits to produce a single 64 bit result. + /// + /// To understand why this is a good scrambling function it helps to understand multiply-with-carry PRNGs: + /// https://en.wikipedia.org/wiki/Multiply-with-carry_pseudorandom_number_generator + /// If the multiple is chosen well, this creates a long period, decent quality PRNG. + /// Notice that this function is equivalent to this except the `buffer`/`state` is being xored with each + /// new block of data. In the event that data is all zeros, it is exactly equivalent to a MWC PRNG. + /// + /// This is impervious to attack because every bit buffer at the end is dependent on every bit in + /// `new_data ^ buffer`. For example suppose two inputs differed in only the 5th bit. Then when the + /// multiplication is performed the `result` will differ in bits 5-69. More specifically it will differ by + /// 2^5 * MULTIPLE. However in the next step bits 65-128 are turned into a separate 64 bit value. So the + /// differing bits will be in the lower 6 bits of this value. The two intermediate values that differ in + /// bits 5-63 and in bits 0-5 respectively get added together. Producing an output that differs in every + /// bit. The addition carries in the multiplication and at the end additionally mean that the even if an + /// attacker somehow knew part of (but not all) the contents of the buffer before hand, + /// they would not be able to predict any of the bits in the buffer at the end. + #[inline(always)] + #[cfg(feature = "folded_multiply")] + fn update(&mut self, new_data: u64) { + self.buffer = folded_multiply(new_data ^ self.buffer, MULTIPLE); + } + + #[inline(always)] + #[cfg(not(feature = "folded_multiply"))] + fn update(&mut self, new_data: u64) { + let d1 = (new_data ^ self.buffer).wrapping_mul(MULTIPLE); + self.pad = (self.pad ^ d1).rotate_left(8).wrapping_mul(MULTIPLE); + self.buffer = (self.buffer ^ self.pad).rotate_left(24); + } + + /// Similar to the above this function performs an update using a "folded multiply". + /// However it takes in 128 bits of data instead of 64. Both halves must be masked. + /// + /// This makes it impossible for an attacker to place a single bit difference between + /// two blocks so as to cancel each other. + /// + /// However this is not sufficient. to prevent (a,b) from hashing the same as (b,a) the buffer itself must + /// be updated between calls in a way that does not commute. To achieve this XOR and Rotate are used. + /// Add followed by xor is not the same as xor followed by add, and rotate ensures that the same out bits + /// can't be changed by the same set of input bits. To cancel this sequence with subsequent input would require + /// knowing the keys. + #[inline(always)] + #[cfg(feature = "folded_multiply")] + fn large_update(&mut self, new_data: u128) { + let block: [u64; 2] = new_data.convert(); + let combined = folded_multiply(block[0] ^ self.extra_keys[0], block[1] ^ self.extra_keys[1]); + self.buffer = (self.buffer.wrapping_add(self.pad) ^ combined).rotate_left(ROT); + } + + #[inline(always)] + #[cfg(not(feature = "folded_multiply"))] + fn large_update(&mut self, new_data: u128) { + let block: [u64; 2] = new_data.convert(); + self.update(block[0] ^ self.extra_keys[0]); + self.update(block[1] ^ self.extra_keys[1]); + } + + #[inline] + #[cfg(feature = "specialize")] + fn short_finish(&self) -> u64 { + self.buffer.wrapping_add(self.pad) + } +} + +/// Provides [Hasher] methods to hash all of the primitive types. +/// +/// [Hasher]: core::hash::Hasher +impl Hasher for AHasher { + #[inline] + fn write_u8(&mut self, i: u8) { + self.update(i as u64); + } + + #[inline] + fn write_u16(&mut self, i: u16) { + self.update(i as u64); + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.update(i as u64); + } + + #[inline] + fn write_u64(&mut self, i: u64) { + self.update(i as u64); + } + + #[inline] + fn write_u128(&mut self, i: u128) { + self.large_update(i); + } + + #[inline] + #[cfg(any(target_pointer_width = "64", target_pointer_width = "32", target_pointer_width = "16"))] + fn write_usize(&mut self, i: usize) { + self.write_u64(i as u64); + } + + #[inline] + #[cfg(target_pointer_width = "128")] + fn write_usize(&mut self, i: usize) { + self.write_u128(i as u128); + } + + #[inline] + #[allow(clippy::collapsible_if)] + fn write(&mut self, input: &[u8]) { + let mut data = input; + let length = data.len() as u64; + //Needs to be an add rather than an xor because otherwise it could be canceled with carefully formed input. + self.buffer = self.buffer.wrapping_add(length).wrapping_mul(MULTIPLE); + //A 'binary search' on sizes reduces the number of comparisons. + if data.len() > 8 { + if data.len() > 16 { + let tail = data.read_last_u128(); + self.large_update(tail); + while data.len() > 16 { + let (block, rest) = data.read_u128(); + self.large_update(block); + data = rest; + } + } else { + self.large_update([data.read_u64().0, data.read_last_u64()].convert()); + } + } else { + let value = read_small(data); + self.large_update(value.convert()); + } + } + + #[inline] + #[cfg(feature = "folded_multiply")] + fn finish(&self) -> u64 { + let rot = (self.buffer & 63) as u32; + folded_multiply(self.buffer, self.pad).rotate_left(rot) + } + + #[inline] + #[cfg(not(feature = "folded_multiply"))] + fn finish(&self) -> u64 { + let rot = (self.buffer & 63) as u32; + (self.buffer.wrapping_mul(MULTIPLE) ^ self.pad).rotate_left(rot) + } +} + +#[cfg(feature = "specialize")] +pub(crate) struct AHasherU64 { + pub(crate) buffer: u64, + pub(crate) pad: u64, +} + +/// A specialized hasher for only primitives under 64 bits. +#[cfg(feature = "specialize")] +impl Hasher for AHasherU64 { + #[inline] + fn finish(&self) -> u64 { + let rot = (self.pad & 63) as u32; + self.buffer.rotate_left(rot) + } + + #[inline] + fn write(&mut self, _bytes: &[u8]) { + unreachable!("Specialized hasher was called with a different type of object") + } + + #[inline] + fn write_u8(&mut self, i: u8) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u16(&mut self, i: u16) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u64(&mut self, i: u64) { + self.buffer = folded_multiply(i ^ self.buffer, MULTIPLE); + } + + #[inline] + fn write_u128(&mut self, _i: u128) { + unreachable!("Specialized hasher was called with a different type of object") + } + + #[inline] + fn write_usize(&mut self, _i: usize) { + unreachable!("Specialized hasher was called with a different type of object") + } +} + +#[cfg(feature = "specialize")] +pub(crate) struct AHasherFixed(pub AHasher); + +/// A specialized hasher for fixed size primitives larger than 64 bits. +#[cfg(feature = "specialize")] +impl Hasher for AHasherFixed { + #[inline] + fn finish(&self) -> u64 { + self.0.short_finish() + } + + #[inline] + fn write(&mut self, bytes: &[u8]) { + self.0.write(bytes) + } + + #[inline] + fn write_u8(&mut self, i: u8) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u16(&mut self, i: u16) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.write_u64(i as u64); + } + + #[inline] + fn write_u64(&mut self, i: u64) { + self.0.write_u64(i); + } + + #[inline] + fn write_u128(&mut self, i: u128) { + self.0.write_u128(i); + } + + #[inline] + fn write_usize(&mut self, i: usize) { + self.0.write_usize(i); + } +} + +#[cfg(feature = "specialize")] +pub(crate) struct AHasherStr(pub AHasher); + +/// A specialized hasher for a single string +/// Note that the other types don't panic because the hash impl for String tacks on an unneeded call. (As does vec) +#[cfg(feature = "specialize")] +impl Hasher for AHasherStr { + #[inline] + fn finish(&self) -> u64 { + self.0.finish() + } + + #[inline] + fn write(&mut self, bytes: &[u8]) { + if bytes.len() > 8 { + self.0.write(bytes) + } else { + let value = read_small(bytes); + self.0.buffer = folded_multiply(value[0] ^ self.0.buffer, + value[1] ^ self.0.extra_keys[1]); + self.0.pad = self.0.pad.wrapping_add(bytes.len() as u64); + } + } + + #[inline] + fn write_u8(&mut self, _i: u8) {} + + #[inline] + fn write_u16(&mut self, _i: u16) {} + + #[inline] + fn write_u32(&mut self, _i: u32) {} + + #[inline] + fn write_u64(&mut self, _i: u64) {} + + #[inline] + fn write_u128(&mut self, _i: u128) {} + + #[inline] + fn write_usize(&mut self, _i: usize) {} +} + +#[cfg(test)] +mod tests { + use crate::convert::Convert; + use crate::fallback_hash::*; + + #[test] + fn test_hash() { + let mut hasher = AHasher::new_with_keys(0, 0); + let value: u64 = 1 << 32; + hasher.update(value); + let result = hasher.buffer; + let mut hasher = AHasher::new_with_keys(0, 0); + let value2: u64 = 1; + hasher.update(value2); + let result2 = hasher.buffer; + let result: [u8; 8] = result.convert(); + let result2: [u8; 8] = result2.convert(); + assert_ne!(hex::encode(result), hex::encode(result2)); + } + + #[test] + fn test_conversion() { + let input: &[u8] = "dddddddd".as_bytes(); + let bytes: u64 = as_array!(input, 8).convert(); + assert_eq!(bytes, 0x6464646464646464); + } +} diff --git a/vendor/ahash-0.7.7/src/hash_map.rs b/vendor/ahash-0.7.7/src/hash_map.rs new file mode 100644 index 0000000000000..ec8fa433bbe51 --- /dev/null +++ b/vendor/ahash-0.7.7/src/hash_map.rs @@ -0,0 +1,371 @@ +use std::borrow::Borrow; +use std::collections::{hash_map, HashMap}; +use std::fmt::{self, Debug}; +use std::hash::{BuildHasher, Hash}; +use std::iter::FromIterator; +use std::ops::{Deref, DerefMut, Index}; +use std::panic::UnwindSafe; + +#[cfg(feature = "serde")] +use serde::{ + de::{Deserialize, Deserializer}, + ser::{Serialize, Serializer}, +}; + +use crate::RandomState; + +/// A [`HashMap`](std::collections::HashMap) using [`RandomState`](crate::RandomState) to hash the items. +/// (Requires the `std` feature to be enabled.) +#[derive(Clone)] +pub struct AHashMap(HashMap); + +impl From> for AHashMap { + fn from(item: HashMap) -> Self { + AHashMap(item) + } +} + +impl Into> for AHashMap { + fn into(self) -> HashMap { + self.0 + } +} + +impl AHashMap { + pub fn new() -> Self { + AHashMap(HashMap::with_hasher(RandomState::default())) + } + + pub fn with_capacity(capacity: usize) -> Self { + AHashMap(HashMap::with_capacity_and_hasher(capacity, RandomState::default())) + } +} + +impl AHashMap +where + S: BuildHasher, +{ + pub fn with_hasher(hash_builder: S) -> Self { + AHashMap(HashMap::with_hasher(hash_builder)) + } + + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { + AHashMap(HashMap::with_capacity_and_hasher(capacity, hash_builder)) + } +} + +impl AHashMap +where + K: Hash + Eq, + S: BuildHasher, +{ + /// Returns a reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get(&1), Some(&"a")); + /// assert_eq!(map.get(&2), None); + /// ``` + #[inline] + pub fn get(&self, k: &Q) -> Option<&V> + where + K: Borrow, + Q: Hash + Eq, + { + self.0.get(k) + } + + /// Returns the key-value pair corresponding to the supplied key. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); + /// assert_eq!(map.get_key_value(&2), None); + /// ``` + #[inline] + pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + where + K: Borrow, + Q: Hash + Eq, + { + self.0.get_key_value(k) + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// if let Some(x) = map.get_mut(&1) { + /// *x = "b"; + /// } + /// assert_eq!(map[&1], "b"); + /// ``` + #[inline] + pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: Borrow, + Q: Hash + Eq, + { + self.0.get_mut(k) + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, [`None`] is returned. + /// + /// If the map did have this key present, the value is updated, and the old + /// value is returned. The key is not updated, though; this matters for + /// types that can be `==` without being identical. See the [module-level + /// documentation] for more. + /// + /// [module-level documentation]: crate::collections#insert-and-complex-keys + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.insert(37, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.insert(37, "c"), Some("b")); + /// assert_eq!(map[&37], "c"); + /// ``` + #[inline] + pub fn insert(&mut self, k: K, v: V) -> Option { + self.0.insert(k, v) + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.remove(&1), Some("a")); + /// assert_eq!(map.remove(&1), None); + /// ``` + #[inline] + pub fn remove(&mut self, k: &Q) -> Option + where + K: Borrow, + Q: Hash + Eq, + { + self.0.remove(k) + } +} + +impl Deref for AHashMap { + type Target = HashMap; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for AHashMap { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl UnwindSafe for AHashMap +where + K: UnwindSafe, + V: UnwindSafe, +{ +} + +impl PartialEq for AHashMap +where + K: Eq + Hash, + V: PartialEq, + S: BuildHasher, +{ + fn eq(&self, other: &AHashMap) -> bool { + self.0.eq(&other.0) + } +} + +impl Eq for AHashMap +where + K: Eq + Hash, + V: Eq, + S: BuildHasher, +{ +} + +impl Index<&Q> for AHashMap +where + K: Eq + Hash + Borrow, + Q: Eq + Hash, + S: BuildHasher, +{ + type Output = V; + + /// Returns a reference to the value corresponding to the supplied key. + /// + /// # Panics + /// + /// Panics if the key is not present in the `HashMap`. + #[inline] + fn index(&self, key: &Q) -> &V { + self.0.index(key) + } +} + +impl Debug for AHashMap +where + K: Debug, + V: Debug, + S: BuildHasher, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(fmt) + } +} + +impl FromIterator<(K, V)> for AHashMap +where + K: Eq + Hash, + S: BuildHasher + Default, +{ + fn from_iter>(iter: T) -> Self { + AHashMap(HashMap::from_iter(iter)) + } +} + +impl<'a, K, V, S> IntoIterator for &'a AHashMap { + type Item = (&'a K, &'a V); + type IntoIter = hash_map::Iter<'a, K, V>; + fn into_iter(self) -> Self::IntoIter { + (&self.0).iter() + } +} + +impl<'a, K, V, S> IntoIterator for &'a mut AHashMap { + type Item = (&'a K, &'a mut V); + type IntoIter = hash_map::IterMut<'a, K, V>; + fn into_iter(self) -> Self::IntoIter { + (&mut self.0).iter_mut() + } +} + +impl IntoIterator for AHashMap { + type Item = (K, V); + type IntoIter = hash_map::IntoIter; + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl Extend<(K, V)> for AHashMap +where + K: Eq + Hash, + S: BuildHasher, +{ + #[inline] + fn extend>(&mut self, iter: T) { + self.0.extend(iter) + } +} + +impl<'a, K, V, S> Extend<(&'a K, &'a V)> for AHashMap +where + K: Eq + Hash + Copy + 'a, + V: Copy + 'a, + S: BuildHasher, +{ + #[inline] + fn extend>(&mut self, iter: T) { + self.0.extend(iter) + } +} + +impl Default for AHashMap { + #[inline] + fn default() -> AHashMap { + AHashMap::new() + } +} + +#[cfg(feature = "serde")] +impl Serialize for AHashMap +where + K: Serialize + Eq + Hash, + V: Serialize, +{ + fn serialize(&self, serializer: S) -> Result { + self.deref().serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, K, V> Deserialize<'de> for AHashMap +where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, +{ + fn deserialize>(deserializer: D) -> Result { + let hash_map = HashMap::deserialize(deserializer); + hash_map.map(|hash_map| Self(hash_map)) + } +} + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn test_borrow() { + let mut map: AHashMap = AHashMap::new(); + map.insert("foo".to_string(), "Bar".to_string()); + map.insert("Bar".to_string(), map.get("foo").unwrap().to_owned()); + } + + #[cfg(feature = "serde")] + #[test] + fn test_serde() { + let mut map = AHashMap::new(); + map.insert("for".to_string(), 0); + map.insert("bar".to_string(), 1); + let serialization = serde_json::to_string(&map).unwrap(); + let deserialization: AHashMap = serde_json::from_str(&serialization).unwrap(); + assert_eq!(deserialization, map); + } +} diff --git a/vendor/ahash-0.7.7/src/hash_quality_test.rs b/vendor/ahash-0.7.7/src/hash_quality_test.rs new file mode 100644 index 0000000000000..17228d4716545 --- /dev/null +++ b/vendor/ahash-0.7.7/src/hash_quality_test.rs @@ -0,0 +1,517 @@ +use core::hash::{Hash, Hasher}; +use std::collections::{HashMap}; + +fn assert_sufficiently_different(a: u64, b: u64, tolerance: i32) { + let (same_byte_count, same_nibble_count) = count_same_bytes_and_nibbles(a, b); + assert!(same_byte_count <= tolerance, "{:x} vs {:x}: {:}", a, b, same_byte_count); + assert!( + same_nibble_count <= tolerance * 3, + "{:x} vs {:x}: {:}", + a, + b, + same_nibble_count + ); + let flipped_bits = (a ^ b).count_ones(); + assert!( + flipped_bits > 12 && flipped_bits < 52, + "{:x} and {:x}: {:}", + a, + b, + flipped_bits + ); + for rotate in 0..64 { + let flipped_bits2 = (a ^ (b.rotate_left(rotate))).count_ones(); + assert!( + flipped_bits2 > 10 && flipped_bits2 < 54, + "{:x} and {:x}: {:}", + a, + b.rotate_left(rotate), + flipped_bits2 + ); + } +} + +fn count_same_bytes_and_nibbles(a: u64, b: u64) -> (i32, i32) { + let mut same_byte_count = 0; + let mut same_nibble_count = 0; + for byte in 0..8 { + let ba = (a >> (8 * byte)) as u8; + let bb = (b >> (8 * byte)) as u8; + if ba == bb { + same_byte_count += 1; + } + if ba & 0xF0u8 == bb & 0xF0u8 { + same_nibble_count += 1; + } + if ba & 0x0Fu8 == bb & 0x0Fu8 { + same_nibble_count += 1; + } + } + (same_byte_count, same_nibble_count) +} + +fn gen_combinations(options: &[u32; 8], depth: u32, so_far: Vec, combinations: &mut Vec>) { + if depth == 0 { + return; + } + for option in options { + let mut next = so_far.clone(); + next.push(*option); + combinations.push(next.clone()); + gen_combinations(options, depth - 1, next, combinations); + } +} + +fn test_no_full_collisions(gen_hash: impl Fn() -> T) { + let options: [u32; 8] = [ + 0x00000000, 0x20000000, 0x40000000, 0x60000000, 0x80000000, 0xA0000000, 0xC0000000, 0xE0000000, + ]; + let mut combinations = Vec::new(); + gen_combinations(&options, 7, Vec::new(), &mut combinations); + let mut map: HashMap> = HashMap::new(); + for combination in combinations { + let array = unsafe { + let (begin, middle, end) = combination.align_to::(); + assert_eq!(0, begin.len()); + assert_eq!(0, end.len()); + middle.to_vec() + }; + let mut hasher = gen_hash(); + hasher.write(&array); + let hash = hasher.finish(); + if let Some(value) = map.get(&hash) { + assert_eq!( + value, &array, + "Found a collision between {:x?} and {:x?}. Hash: {:x?}", + value, &array, &hash + ); + } else { + map.insert(hash, array); + } + } + assert_eq!(2396744, map.len()); +} + +fn test_keys_change_output(constructor: impl Fn(u128, u128) -> T) { + let mut a = constructor(1, 1); + let mut b = constructor(1, 2); + let mut c = constructor(2, 1); + let mut d = constructor(2, 2); + "test".hash(&mut a); + "test".hash(&mut b); + "test".hash(&mut c); + "test".hash(&mut d); + assert_sufficiently_different(a.finish(), b.finish(), 1); + assert_sufficiently_different(a.finish(), c.finish(), 1); + assert_sufficiently_different(a.finish(), d.finish(), 1); + assert_sufficiently_different(b.finish(), c.finish(), 1); + assert_sufficiently_different(b.finish(), d.finish(), 1); + assert_sufficiently_different(c.finish(), d.finish(), 1); +} + +fn test_input_affect_every_byte(constructor: impl Fn(u128, u128) -> T) { + let base = hash_with(&0, constructor(0, 0)); + for shift in 0..16 { + let mut alternitives = vec![]; + for v in 0..256 { + let input = (v as u128) << (shift * 8); + let hasher = constructor(0, 0); + alternitives.push(hash_with(&input, hasher)); + } + assert_each_byte_differs(shift, base, alternitives); + } +} + +///Ensures that for every bit in the output there is some value for each byte in the key that flips it. +fn test_keys_affect_every_byte(item: H, constructor: impl Fn(u128, u128) -> T) { + let base = hash_with(&item, constructor(0, 0)); + for shift in 0..16 { + let mut alternitives1 = vec![]; + let mut alternitives2 = vec![]; + for v in 0..256 { + let input = (v as u128) << (shift * 8); + let hasher1 = constructor(input, 0); + let hasher2 = constructor(0, input); + let h1 = hash_with(&item, hasher1); + let h2 = hash_with(&item, hasher2); + alternitives1.push(h1); + alternitives2.push(h2); + } + assert_each_byte_differs(shift, base, alternitives1); + assert_each_byte_differs(shift, base, alternitives2); + } +} + +fn assert_each_byte_differs(num: u64, base: u64, alternitives: Vec) { + let mut changed_bits = 0_u64; + for alternitive in alternitives { + changed_bits |= base ^ alternitive + } + assert_eq!(core::u64::MAX, changed_bits, "Bits changed: {:x} on num: {:?}", changed_bits, num); +} + +fn test_finish_is_consistent(constructor: impl Fn(u128, u128) -> T) { + let mut hasher = constructor(1, 2); + "Foo".hash(&mut hasher); + let a = hasher.finish(); + let b = hasher.finish(); + assert_eq!(a, b); +} + +fn test_single_key_bit_flip(constructor: impl Fn(u128, u128) -> T) { + for bit in 0..128 { + let mut a = constructor(0, 0); + let mut b = constructor(0, 1 << bit); + let mut c = constructor(1 << bit, 0); + "1234".hash(&mut a); + "1234".hash(&mut b); + "1234".hash(&mut c); + assert_sufficiently_different(a.finish(), b.finish(), 2); + assert_sufficiently_different(a.finish(), c.finish(), 2); + assert_sufficiently_different(b.finish(), c.finish(), 2); + let mut a = constructor(0, 0); + let mut b = constructor(0, 1 << bit); + let mut c = constructor(1 << bit, 0); + "12345678".hash(&mut a); + "12345678".hash(&mut b); + "12345678".hash(&mut c); + assert_sufficiently_different(a.finish(), b.finish(), 2); + assert_sufficiently_different(a.finish(), c.finish(), 2); + assert_sufficiently_different(b.finish(), c.finish(), 2); + let mut a = constructor(0, 0); + let mut b = constructor(0, 1 << bit); + let mut c = constructor(1 << bit, 0); + "1234567812345678".hash(&mut a); + "1234567812345678".hash(&mut b); + "1234567812345678".hash(&mut c); + assert_sufficiently_different(a.finish(), b.finish(), 2); + assert_sufficiently_different(a.finish(), c.finish(), 2); + assert_sufficiently_different(b.finish(), c.finish(), 2); + } +} + +fn test_all_bytes_matter(hasher: impl Fn() -> T) { + let mut item = vec![0; 256]; + let base_hash = hash(&item, &hasher); + for pos in 0..256 { + item[pos] = 255; + let hash = hash(&item, &hasher); + assert_ne!(base_hash, hash, "Position {} did not affect output", pos); + item[pos] = 0; + } +} + +fn test_no_pair_collisions(hasher: impl Fn() -> T) { + let base = [0_u64, 0_u64]; + let base_hash = hash(&base, &hasher); + for bitpos1 in 0..64 { + let a = 1_u64 << bitpos1; + for bitpos2 in 0..bitpos1 { + let b = 1_u64 << bitpos2; + let aa = hash(&[a, a], &hasher); + let ab = hash(&[a, b], &hasher); + let ba = hash(&[b, a], &hasher); + let bb = hash(&[b, b], &hasher); + assert_sufficiently_different(base_hash, aa, 3); + assert_sufficiently_different(base_hash, ab, 3); + assert_sufficiently_different(base_hash, ba, 3); + assert_sufficiently_different(base_hash, bb, 3); + assert_sufficiently_different(aa, ab, 3); + assert_sufficiently_different(ab, ba, 3); + assert_sufficiently_different(ba, bb, 3); + assert_sufficiently_different(aa, ba, 3); + assert_sufficiently_different(ab, bb, 3); + assert_sufficiently_different(aa, bb, 3); + } + } +} + +fn hash(b: &H, hash_builder: &dyn Fn() -> T) -> u64 { + let mut hasher = hash_builder(); + b.hash(&mut hasher); + hasher.finish() +} + +fn hash_with(b: &H, mut hasher: T) -> u64 { + b.hash(&mut hasher); + hasher.finish() +} + +fn test_single_bit_flip(hasher: impl Fn() -> T) { + let size = 32; + let compare_value = hash(&0u32, &hasher); + for pos in 0..size { + let test_value = hash(&(1u32 << pos), &hasher); + assert_sufficiently_different(compare_value, test_value, 2); + } + let size = 64; + let compare_value = hash(&0u64, &hasher); + for pos in 0..size { + let test_value = hash(&(1u64 << pos), &hasher); + assert_sufficiently_different(compare_value, test_value, 2); + } + let size = 128; + let compare_value = hash(&0u128, &hasher); + for pos in 0..size { + let test_value = hash(&(1u128 << pos), &hasher); + dbg!(compare_value, test_value); + assert_sufficiently_different(compare_value, test_value, 2); + } +} + +fn test_padding_doesnot_collide(hasher: impl Fn() -> T) { + for c in 0..128u8 { + for string in ["", "\0", "\x01", "1234", "12345678", "1234567812345678"].iter() { + let mut short = hasher(); + string.hash(&mut short); + let value = short.finish(); + let mut padded = string.to_string(); + for num in 1..=128 { + let mut long = hasher(); + padded.push(c as char); + padded.hash(&mut long); + let (same_bytes, same_nibbles) = count_same_bytes_and_nibbles(value, long.finish()); + assert!( + same_bytes <= 3, + "{} bytes of {} -> {:x} vs {:x}", num, c, value, long.finish() + ); + assert!( + same_nibbles <= 8, + "{} bytes of {} -> {:x} vs {:x}", num, c, value, long.finish() + ); + let flipped_bits = (value ^ long.finish()).count_ones(); + assert!(flipped_bits > 10); + } + if string.len() > 0 { + let mut padded = string[1..].to_string(); + padded.push(c as char); + for num in 2..=128 { + let mut long = hasher(); + padded.push(c as char); + padded.hash(&mut long); + let (same_bytes, same_nibbles) = count_same_bytes_and_nibbles(value, long.finish()); + assert!( + same_bytes <= 3, + "string {:?} + {} bytes of {} -> {:x} vs {:x}", + string, + num, + c, + value, + long.finish() + ); + assert!( + same_nibbles <= 8, + "string {:?} + {} bytes of {} -> {:x} vs {:x}", + string, + num, + c, + value, + long.finish() + ); + let flipped_bits = (value ^ long.finish()).count_ones(); + assert!(flipped_bits > 10); + } + } + } + } +} + +fn test_length_extension(hasher: impl Fn(u128, u128) -> T) { + for key in 0..256 { + let h1 = hasher(key, key); + let v1 = hash_with(&[0_u8, 0, 0, 0, 0, 0, 0, 0], h1); + let h2 = hasher(key, key); + let v2 = hash_with(&[1_u8, 0, 0, 0, 0, 0, 0, 0, 0], h2); + assert_ne!(v1, v2); + } +} + +fn test_sparse(hasher: impl Fn() -> T) { + let mut buf = [0u8; 256]; + let mut hashes = HashMap::new(); + for idx_1 in 0..256 { + for idx_2 in idx_1+1..256 { + for value_1 in [1, 2, 4, 8, 16, 32, 64, 128] { + for value_2 in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 16, 17, 18, 20, 24, 31, 32, 33, 48, 64, 96, 127, 128, 129, 192, 254, 255] { + buf[idx_1] = value_1; + buf[idx_2] = value_2; + let hash_value = hash_with(&buf, &mut hasher()); + let keys = hashes.entry(hash_value).or_insert(Vec::new()); + keys.push((idx_1, value_1, idx_2, value_2)); + buf[idx_1] = 0; + buf[idx_2] = 0; + } + } + } + } + hashes.retain(|_key, value| value.len() != 1); + assert_eq!(0, hashes.len(), "Collision with: {:?}", hashes); +} + +#[cfg(test)] +mod fallback_tests { + use crate::fallback_hash::*; + use crate::hash_quality_test::*; + + #[test] + fn fallback_single_bit_flip() { + test_single_bit_flip(|| AHasher::new_with_keys(0, 0)) + } + + #[test] + fn fallback_single_key_bit_flip() { + test_single_key_bit_flip(AHasher::new_with_keys) + } + + #[test] + fn fallback_all_bytes_matter() { + test_all_bytes_matter(|| AHasher::new_with_keys(0, 0)); + } + + #[test] + fn fallback_test_no_pair_collisions() { + test_no_pair_collisions(|| AHasher::new_with_keys(0, 0)); + } + + #[test] + fn fallback_test_no_full_collisions() { + test_no_full_collisions(|| AHasher::new_with_keys(0, 0)); + } + + #[test] + fn fallback_keys_change_output() { + test_keys_change_output(AHasher::new_with_keys); + } + + #[test] + fn fallback_input_affect_every_byte() { + test_input_affect_every_byte(AHasher::new_with_keys); + } + + #[test] + fn fallback_keys_affect_every_byte() { + //For fallback second key is not used in every hash. + #[cfg(all(not(feature = "specialize"), feature = "folded_multiply"))] + test_keys_affect_every_byte(0, |a, b| AHasher::new_with_keys(a ^ b, a)); + test_keys_affect_every_byte("", |a, b| AHasher::new_with_keys(a ^ b, a)); + test_keys_affect_every_byte((0, 0), |a, b| AHasher::new_with_keys(a ^ b, a)); + } + + #[test] + fn fallback_finish_is_consistant() { + test_finish_is_consistent(AHasher::test_with_keys) + } + + #[test] + fn fallback_padding_doesnot_collide() { + test_padding_doesnot_collide(|| AHasher::new_with_keys(0, 0)); + test_padding_doesnot_collide(|| AHasher::new_with_keys(0, 2)); + test_padding_doesnot_collide(|| AHasher::new_with_keys(2, 0)); + test_padding_doesnot_collide(|| AHasher::new_with_keys(2, 2)); + } + + #[test] + fn fallback_length_extension() { + test_length_extension(|a, b| AHasher::new_with_keys(a, b)); + } + + #[test] + fn test_no_sparse_collisions() { + test_sparse(|| AHasher::new_with_keys(0, 0)); + test_sparse(|| AHasher::new_with_keys(1, 2)); + } +} + +///Basic sanity tests of the cypto properties of aHash. +#[cfg(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") +))] +#[cfg(test)] +mod aes_tests { + use crate::aes_hash::*; + use crate::hash_quality_test::*; + use std::hash::{Hash, Hasher}; + + //This encrypts to 0. + const BAD_KEY2: u128 = 0x6363_6363_6363_6363_6363_6363_6363_6363; + //This decrypts to 0. + const BAD_KEY: u128 = 0x5252_5252_5252_5252_5252_5252_5252_5252; + + #[test] + fn test_single_bit_in_byte() { + let mut hasher1 = AHasher::test_with_keys(0, 0); + 8_u32.hash(&mut hasher1); + let mut hasher2 = AHasher::test_with_keys(0, 0); + 0_u32.hash(&mut hasher2); + assert_sufficiently_different(hasher1.finish(), hasher2.finish(), 1); + } + + #[test] + fn aes_single_bit_flip() { + test_single_bit_flip(|| AHasher::test_with_keys(BAD_KEY, BAD_KEY)); + test_single_bit_flip(|| AHasher::test_with_keys(BAD_KEY2, BAD_KEY2)); + } + + #[test] + fn aes_single_key_bit_flip() { + test_single_key_bit_flip(AHasher::test_with_keys) + } + + #[test] + fn aes_all_bytes_matter() { + test_all_bytes_matter(|| AHasher::test_with_keys(BAD_KEY, BAD_KEY)); + test_all_bytes_matter(|| AHasher::test_with_keys(BAD_KEY2, BAD_KEY2)); + } + + #[test] + fn aes_test_no_pair_collisions() { + test_no_pair_collisions(|| AHasher::test_with_keys(BAD_KEY, BAD_KEY)); + test_no_pair_collisions(|| AHasher::test_with_keys(BAD_KEY2, BAD_KEY2)); + } + + #[test] + fn ase_test_no_full_collisions() { + test_no_full_collisions(|| AHasher::test_with_keys(12345, 67890)); + } + + #[test] + fn aes_keys_change_output() { + test_keys_change_output(AHasher::test_with_keys); + } + + #[test] + fn aes_input_affect_every_byte() { + test_input_affect_every_byte(AHasher::test_with_keys); + } + + #[test] + fn aes_keys_affect_every_byte() { + #[cfg(not(feature = "specialize"))] + test_keys_affect_every_byte(0, AHasher::test_with_keys); + test_keys_affect_every_byte("", AHasher::test_with_keys); + test_keys_affect_every_byte((0, 0), AHasher::test_with_keys); + } + + #[test] + fn aes_finish_is_consistant() { + test_finish_is_consistent(AHasher::test_with_keys) + } + + #[test] + fn aes_padding_doesnot_collide() { + test_padding_doesnot_collide(|| AHasher::test_with_keys(BAD_KEY, BAD_KEY)); + test_padding_doesnot_collide(|| AHasher::test_with_keys(BAD_KEY2, BAD_KEY2)); + } + + #[test] + fn aes_length_extension() { + test_length_extension(|a, b| AHasher::test_with_keys(a, b)); + } + + #[test] + fn aes_no_sparse_collisions() { + test_sparse(|| AHasher::test_with_keys(0, 0)); + test_sparse(|| AHasher::test_with_keys(1, 2)); + } +} diff --git a/vendor/ahash-0.7.7/src/hash_set.rs b/vendor/ahash-0.7.7/src/hash_set.rs new file mode 100644 index 0000000000000..9766b676ffa53 --- /dev/null +++ b/vendor/ahash-0.7.7/src/hash_set.rs @@ -0,0 +1,313 @@ +use crate::RandomState; +use std::collections::{hash_set, HashSet}; +use std::fmt::{self, Debug}; +use std::hash::{BuildHasher, Hash}; +use std::iter::FromIterator; +use std::ops::{BitAnd, BitOr, BitXor, Deref, DerefMut, Sub}; + +#[cfg(feature = "serde")] +use serde::{ + de::{Deserialize, Deserializer}, + ser::{Serialize, Serializer}, +}; + +/// A [`HashSet`](std::collections::HashSet) using [`RandomState`](crate::RandomState) to hash the items. +/// (Requires the `std` feature to be enabled.) +#[derive(Clone)] +pub struct AHashSet(HashSet); + +impl From> for AHashSet { + fn from(item: HashSet) -> Self { + AHashSet(item) + } +} + +impl Into> for AHashSet { + fn into(self) -> HashSet { + self.0 + } +} + +impl AHashSet { + pub fn new() -> Self { + AHashSet(HashSet::with_hasher(RandomState::default())) + } + + pub fn with_capacity(capacity: usize) -> Self { + AHashSet(HashSet::with_capacity_and_hasher(capacity, RandomState::default())) + } +} + +impl AHashSet +where + S: BuildHasher, +{ + pub fn with_hasher(hash_builder: S) -> Self { + AHashSet(HashSet::with_hasher(hash_builder)) + } + + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { + AHashSet(HashSet::with_capacity_and_hasher(capacity, hash_builder)) + } +} + +impl Deref for AHashSet { + type Target = HashSet; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for AHashSet { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl PartialEq for AHashSet +where + T: Eq + Hash, + S: BuildHasher, +{ + fn eq(&self, other: &AHashSet) -> bool { + self.0.eq(&other.0) + } +} + +impl Eq for AHashSet +where + T: Eq + Hash, + S: BuildHasher, +{ +} + +impl BitOr<&AHashSet> for &AHashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = AHashSet; + + /// Returns the union of `self` and `rhs` as a new `AHashSet`. + /// + /// # Examples + /// + /// ``` + /// use ahash::AHashSet; + /// + /// let a: AHashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: AHashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a | &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 3, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitor(self, rhs: &AHashSet) -> AHashSet { + AHashSet(self.0.bitor(&rhs.0)) + } +} + +impl BitAnd<&AHashSet> for &AHashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = AHashSet; + + /// Returns the intersection of `self` and `rhs` as a new `AHashSet`. + /// + /// # Examples + /// + /// ``` + /// use ahash::AHashSet; + /// + /// let a: AHashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: AHashSet<_> = vec![2, 3, 4].into_iter().collect(); + /// + /// let set = &a & &b; + /// + /// let mut i = 0; + /// let expected = [2, 3]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitand(self, rhs: &AHashSet) -> AHashSet { + AHashSet(self.0.bitand(&rhs.0)) + } +} + +impl BitXor<&AHashSet> for &AHashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = AHashSet; + + /// Returns the symmetric difference of `self` and `rhs` as a new `AHashSet`. + /// + /// # Examples + /// + /// ``` + /// use ahash::AHashSet; + /// + /// let a: AHashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: AHashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a ^ &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitxor(self, rhs: &AHashSet) -> AHashSet { + AHashSet(self.0.bitxor(&rhs.0)) + } +} + +impl Sub<&AHashSet> for &AHashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = AHashSet; + + /// Returns the difference of `self` and `rhs` as a new `AHashSet`. + /// + /// # Examples + /// + /// ``` + /// use ahash::AHashSet; + /// + /// let a: AHashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: AHashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a - &b; + /// + /// let mut i = 0; + /// let expected = [1, 2]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn sub(self, rhs: &AHashSet) -> AHashSet { + AHashSet(self.0.sub(&rhs.0)) + } +} + +impl Debug for AHashSet +where + T: Debug, + S: BuildHasher, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(fmt) + } +} + +impl FromIterator for AHashSet +where + T: Eq + Hash, + S: BuildHasher + Default, +{ + #[inline] + fn from_iter>(iter: I) -> AHashSet { + AHashSet(HashSet::from_iter(iter)) + } +} + +impl<'a, T, S> IntoIterator for &'a AHashSet { + type Item = &'a T; + type IntoIter = hash_set::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + (&self.0).iter() + } +} + +impl IntoIterator for AHashSet { + type Item = T; + type IntoIter = hash_set::IntoIter; + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl Extend for AHashSet +where + T: Eq + Hash, + S: BuildHasher, +{ + #[inline] + fn extend>(&mut self, iter: I) { + self.0.extend(iter) + } +} + +impl<'a, T, S> Extend<&'a T> for AHashSet +where + T: 'a + Eq + Hash + Copy, + S: BuildHasher, +{ + #[inline] + fn extend>(&mut self, iter: I) { + self.0.extend(iter) + } +} + +impl Default for AHashSet { + /// Creates an empty `AHashSet` with the `Default` value for the hasher. + #[inline] + fn default() -> AHashSet { + AHashSet(HashSet::default()) + } +} + +#[cfg(feature = "serde")] +impl Serialize for AHashSet +where + T: Serialize + Eq + Hash, +{ + fn serialize(&self, serializer: S) -> Result { + self.deref().serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, T> Deserialize<'de> for AHashSet +where + T: Deserialize<'de> + Eq + Hash, +{ + fn deserialize>(deserializer: D) -> Result { + let hash_set = HashSet::deserialize(deserializer); + hash_set.map(|hash_set| Self(hash_set)) + } +} + +#[cfg(all(test, feature = "serde"))] +mod test { + use super::*; + + #[test] + fn test_serde() { + let mut set = AHashSet::new(); + set.insert("for".to_string()); + set.insert("bar".to_string()); + let serialization = serde_json::to_string(&set).unwrap(); + let deserialization: AHashSet = serde_json::from_str(&serialization).unwrap(); + assert_eq!(deserialization, set); + } +} diff --git a/vendor/ahash-0.7.7/src/lib.rs b/vendor/ahash-0.7.7/src/lib.rs new file mode 100644 index 0000000000000..9964a7c47b408 --- /dev/null +++ b/vendor/ahash-0.7.7/src/lib.rs @@ -0,0 +1,263 @@ +//! AHash is a hashing algorithm is intended to be a high performance, (hardware specific), keyed hash function. +//! This can be seen as a DOS resistant alternative to `FxHash`, or a fast equivalent to `SipHash`. +//! It provides a high speed hash algorithm, but where the result is not predictable without knowing a Key. +//! This allows it to be used in a `HashMap` without allowing for the possibility that an malicious user can +//! induce a collision. +//! +//! # How aHash works +//! +//! aHash uses the hardware AES instruction on x86 processors to provide a keyed hash function. +//! aHash is not a cryptographically secure hash. +//! +//! # Example +//! ``` +//! use ahash::{AHasher, RandomState}; +//! use std::collections::HashMap; +//! +//! let mut map: HashMap = HashMap::default(); +//! map.insert(12, 34); +//! ``` +//! For convinence wrappers called `AHashMap` and `AHashSet` are also provided. +//! These to the same thing with slightly less typing. +//! ```ignore +//! use ahash::AHashMap; +//! +//! let mut map: AHashMap = AHashMap::with_capacity(4); +//! map.insert(12, 34); +//! map.insert(56, 78); +//! ``` +#![deny(clippy::correctness, clippy::complexity, clippy::perf)] +#![allow(clippy::pedantic, clippy::cast_lossless, clippy::unreadable_literal)] +#![cfg_attr(all(not(test), not(feature = "std")), no_std)] +#![cfg_attr(feature = "specialize", feature(min_specialization))] +#![cfg_attr(feature = "stdsimd", feature(stdsimd))] + +#[macro_use] +mod convert; + +#[cfg(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") +))] +mod aes_hash; +mod fallback_hash; +#[cfg(test)] +mod hash_quality_test; + +#[cfg(feature = "std")] +mod hash_map; +#[cfg(feature = "std")] +mod hash_set; +mod operations; +mod random_state; +mod specialize; + +#[cfg(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") +))] +pub use crate::aes_hash::AHasher; + +#[cfg(not(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") +)))] +pub use crate::fallback_hash::AHasher; +pub use crate::random_state::RandomState; + +pub use crate::specialize::CallHasher; + +#[cfg(feature = "std")] +pub use crate::hash_map::AHashMap; +#[cfg(feature = "std")] +pub use crate::hash_set::AHashSet; +use core::hash::BuildHasher; +use core::hash::Hash; +use core::hash::Hasher; + +/// Provides a default [Hasher] with fixed keys. +/// This is typically used in conjunction with [BuildHasherDefault] to create +/// [AHasher]s in order to hash the keys of the map. +/// +/// Generally it is preferable to use [RandomState] instead, so that different +/// hashmaps will have different keys. However if fixed keys are desireable this +/// may be used instead. +/// +/// # Example +/// ``` +/// use std::hash::BuildHasherDefault; +/// use ahash::{AHasher, RandomState}; +/// use std::collections::HashMap; +/// +/// let mut map: HashMap> = HashMap::default(); +/// map.insert(12, 34); +/// ``` +/// +/// [BuildHasherDefault]: std::hash::BuildHasherDefault +/// [Hasher]: std::hash::Hasher +/// [HashMap]: std::collections::HashMap +impl Default for AHasher { + /// Constructs a new [AHasher] with fixed keys. + /// If `std` is enabled these will be generated upon first invocation. + /// Otherwise if the `compile-time-rng`feature is enabled these will be generated at compile time. + /// If neither of these features are available, hardcoded constants will be used. + /// + /// Because the values are fixed, different hashers will all hash elements the same way. + /// This could make hash values predictable, if DOS attacks are a concern. If this behaviour is + /// not required, it may be preferable to use [RandomState] instead. + /// + /// # Examples + /// + /// ``` + /// use ahash::AHasher; + /// use std::hash::Hasher; + /// + /// let mut hasher_1 = AHasher::default(); + /// let mut hasher_2 = AHasher::default(); + /// + /// hasher_1.write_u32(1234); + /// hasher_2.write_u32(1234); + /// + /// assert_eq!(hasher_1.finish(), hasher_2.finish()); + /// ``` + #[inline] + fn default() -> AHasher { + RandomState::with_fixed_keys().build_hasher() + } +} + +/// Used for specialization. (Sealed) +pub(crate) trait BuildHasherExt: BuildHasher { + #[doc(hidden)] + fn hash_as_u64(&self, value: &T) -> u64; + + #[doc(hidden)] + fn hash_as_fixed_length(&self, value: &T) -> u64; + + #[doc(hidden)] + fn hash_as_str(&self, value: &T) -> u64; +} + +impl BuildHasherExt for B { + #[inline] + #[cfg(feature = "specialize")] + default fn hash_as_u64(&self, value: &T) -> u64 { + let mut hasher = self.build_hasher(); + value.hash(&mut hasher); + hasher.finish() + } + #[inline] + #[cfg(not(feature = "specialize"))] + fn hash_as_u64(&self, value: &T) -> u64 { + let mut hasher = self.build_hasher(); + value.hash(&mut hasher); + hasher.finish() + } + #[inline] + #[cfg(feature = "specialize")] + default fn hash_as_fixed_length(&self, value: &T) -> u64 { + let mut hasher = self.build_hasher(); + value.hash(&mut hasher); + hasher.finish() + } + #[inline] + #[cfg(not(feature = "specialize"))] + fn hash_as_fixed_length(&self, value: &T) -> u64 { + let mut hasher = self.build_hasher(); + value.hash(&mut hasher); + hasher.finish() + } + #[inline] + #[cfg(feature = "specialize")] + default fn hash_as_str(&self, value: &T) -> u64 { + let mut hasher = self.build_hasher(); + value.hash(&mut hasher); + hasher.finish() + } + #[inline] + #[cfg(not(feature = "specialize"))] + fn hash_as_str(&self, value: &T) -> u64 { + let mut hasher = self.build_hasher(); + value.hash(&mut hasher); + hasher.finish() + } +} + +// #[inline(never)] +// #[doc(hidden)] +// pub fn hash_test(input: &[u8]) -> u64 { +// let a = RandomState::with_seeds(11, 22, 33, 44); +// <[u8]>::get_hash(input, &a) +// } + +#[cfg(feature = "std")] +#[cfg(test)] +mod test { + use crate::convert::Convert; + use crate::*; + use std::collections::HashMap; + use std::hash::Hash; + + #[test] + fn test_default_builder() { + use core::hash::BuildHasherDefault; + + let mut map = HashMap::>::default(); + map.insert(1, 3); + } + + #[test] + fn test_builder() { + let mut map = HashMap::::default(); + map.insert(1, 3); + } + + #[test] + fn test_conversion() { + let input: &[u8] = b"dddddddd"; + let bytes: u64 = as_array!(input, 8).convert(); + assert_eq!(bytes, 0x6464646464646464); + } + + + #[test] + fn test_non_zero() { + let mut hasher1 = AHasher::new_with_keys(0, 0); + let mut hasher2 = AHasher::new_with_keys(0, 0); + "foo".hash(&mut hasher1); + "bar".hash(&mut hasher2); + assert_ne!(hasher1.finish(), 0); + assert_ne!(hasher2.finish(), 0); + assert_ne!(hasher1.finish(), hasher2.finish()); + + let mut hasher1 = AHasher::new_with_keys(0, 0); + let mut hasher2 = AHasher::new_with_keys(0, 0); + 3_u64.hash(&mut hasher1); + 4_u64.hash(&mut hasher2); + assert_ne!(hasher1.finish(), 0); + assert_ne!(hasher2.finish(), 0); + assert_ne!(hasher1.finish(), hasher2.finish()); + } + + #[test] + fn test_non_zero_specialized() { + let hasher_build = RandomState::with_seeds(0,0,0,0); + + let h1 = str::get_hash("foo", &hasher_build); + let h2 = str::get_hash("bar", &hasher_build); + assert_ne!(h1, 0); + assert_ne!(h2, 0); + assert_ne!(h1, h2); + + let h1 = u64::get_hash(&3_u64, &hasher_build); + let h2 = u64::get_hash(&4_u64, &hasher_build); + assert_ne!(h1, 0); + assert_ne!(h2, 0); + assert_ne!(h1, h2); + } + + #[test] + fn test_ahasher_construction() { + let _ = AHasher::new_with_keys(1234, 5678); + } +} diff --git a/vendor/ahash-0.7.7/src/operations.rs b/vendor/ahash-0.7.7/src/operations.rs new file mode 100644 index 0000000000000..b71fd5a743393 --- /dev/null +++ b/vendor/ahash-0.7.7/src/operations.rs @@ -0,0 +1,330 @@ +use crate::convert::*; + +/// This is a constant with a lot of special properties found by automated search. +/// See the unit tests below. (Below are alternative values) +#[cfg(all(target_feature = "ssse3", not(miri)))] +const SHUFFLE_MASK: u128 = 0x020a0700_0c01030e_050f0d08_06090b04_u128; +//const SHUFFLE_MASK: u128 = 0x000d0702_0a040301_05080f0c_0e0b0609_u128; +//const SHUFFLE_MASK: u128 = 0x040A0700_030E0106_0D050F08_020B0C09_u128; + +#[inline(always)] +pub(crate) const fn folded_multiply(s: u64, by: u64) -> u64 { + let result = (s as u128).wrapping_mul(by as u128); + ((result & 0xffff_ffff_ffff_ffff) as u64) ^ ((result >> 64) as u64) +} + + +/// Given a small (less than 8 byte slice) returns the same data stored in two u32s. +/// (order of and non-duplication of bytes is NOT guaranteed) +#[inline(always)] +pub(crate) fn read_small(data: &[u8]) -> [u64; 2] { + debug_assert!(data.len() <= 8); + if data.len() >= 2 { + if data.len() >= 4 { + //len 4-8 + [data.read_u32().0 as u64, data.read_last_u32() as u64] + } else { + //len 2-3 + [data.read_u16().0 as u64, data[data.len() - 1] as u64] + } + } else { + if data.len() > 0 { + [data[0] as u64, data[0] as u64] + } else { + [0, 0] + } + } +} + +#[inline(always)] +pub(crate) fn shuffle(a: u128) -> u128 { + #[cfg(all(target_feature = "ssse3", not(miri)))] + { + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + use core::mem::transmute; + unsafe { transmute(_mm_shuffle_epi8(transmute(a), transmute(SHUFFLE_MASK))) } + } + #[cfg(not(all(target_feature = "ssse3", not(miri))))] + { + a.swap_bytes() + } +} + +#[allow(unused)] //not used by fallback +#[inline(always)] +pub(crate) fn add_and_shuffle(a: u128, b: u128) -> u128 { + let sum = add_by_64s(a.convert(), b.convert()); + shuffle(sum.convert()) +} + +#[allow(unused)] //not used by fallbac +#[inline(always)] +pub(crate) fn shuffle_and_add(base: u128, to_add: u128) -> u128 { + let shuffled: [u64; 2] = shuffle(base).convert(); + add_by_64s(shuffled, to_add.convert()).convert() +} + +#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2", not(miri)))] +#[inline(always)] +pub(crate) fn add_by_64s(a: [u64; 2], b: [u64; 2]) -> [u64; 2] { + use core::mem::transmute; + unsafe { + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + transmute(_mm_add_epi64(transmute(a), transmute(b))) + } +} + +#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2", not(miri))))] +#[inline(always)] +pub(crate) fn add_by_64s(a: [u64; 2], b: [u64; 2]) -> [u64; 2] { + [a[0].wrapping_add(b[0]), a[1].wrapping_add(b[1])] +} + +#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))] +#[allow(unused)] +#[inline(always)] +pub(crate) fn aesenc(value: u128, xor: u128) -> u128 { + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + use core::mem::transmute; + unsafe { + let value = transmute(value); + transmute(_mm_aesenc_si128(value, transmute(xor))) + } +} + +#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd"))] +#[allow(unused)] +#[inline(always)] +pub(crate) fn aesenc(value: u128, xor: u128) -> u128 { + #[cfg(target_arch = "arm")] + use core::arch::arm::*; + #[cfg(target_arch = "aarch64")] + use core::arch::aarch64::*; + use core::mem::transmute; + unsafe { + let value = transmute(value); + transmute(vaesmcq_u8(vaeseq_u8(value, transmute(xor)))) + } +} + +#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))] +#[allow(unused)] +#[inline(always)] +pub(crate) fn aesdec(value: u128, xor: u128) -> u128 { + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + use core::mem::transmute; + unsafe { + let value = transmute(value); + transmute(_mm_aesdec_si128(value, transmute(xor))) + } +} + +#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd"))] +#[allow(unused)] +#[inline(always)] +pub(crate) fn aesdec(value: u128, xor: u128) -> u128 { + #[cfg(target_arch = "arm")] + use core::arch::arm::*; + #[cfg(target_arch = "aarch64")] + use core::arch::aarch64::*; + use core::mem::transmute; + unsafe { + let value = transmute(value); + transmute(vaesimcq_u8(vaesdq_u8(value, transmute(xor)))) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::convert::Convert; + + // This is code to search for the shuffle constant + // + //thread_local! { static MASK: Cell = Cell::new(0); } + // + // fn shuffle(a: u128) -> u128 { + // use std::intrinsics::transmute; + // #[cfg(target_arch = "x86")] + // use core::arch::x86::*; + // #[cfg(target_arch = "x86_64")] + // use core::arch::x86_64::*; + // MASK.with(|mask| { + // unsafe { transmute(_mm_shuffle_epi8(transmute(a), transmute(mask.get()))) } + // }) + // } + // + // #[test] + // fn find_shuffle() { + // use rand::prelude::*; + // use SliceRandom; + // use std::panic; + // use std::io::Write; + // + // let mut value: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ,13, 14, 15]; + // let mut rand = thread_rng(); + // let mut successful_list = HashMap::new(); + // for _attempt in 0..10000000 { + // rand.shuffle(&mut value); + // let test_val = value.convert(); + // MASK.with(|mask| { + // mask.set(test_val); + // }); + // if let Ok(successful) = panic::catch_unwind(|| { + // test_shuffle_does_not_collide_with_aes(); + // test_shuffle_moves_high_bits(); + // test_shuffle_moves_every_value(); + // //test_shuffle_does_not_loop(); + // value + // }) { + // let successful: u128 = successful.convert(); + // successful_list.insert(successful, iters_before_loop()); + // } + // } + // let write_file = File::create("/tmp/output").unwrap(); + // let mut writer = BufWriter::new(&write_file); + // + // for success in successful_list { + // writeln!(writer, "Found successful: {:x?} - {:?}", success.0, success.1); + // } + // } + // + // fn iters_before_loop() -> u32 { + // let numbered = 0x00112233_44556677_8899AABB_CCDDEEFF; + // let mut shuffled = shuffle(numbered); + // let mut count = 0; + // loop { + // // println!("{:>16x}", shuffled); + // if numbered == shuffled { + // break; + // } + // count += 1; + // shuffled = shuffle(shuffled); + // } + // count + // } + + #[cfg(all( + any(target_arch = "x86", target_arch = "x86_64"), + target_feature = "ssse3", + target_feature = "aes", + not(miri) + ))] + #[test] + fn test_shuffle_does_not_collide_with_aes() { + let mut value: [u8; 16] = [0; 16]; + let zero_mask_enc = aesenc(0, 0); + let zero_mask_dec = aesdec(0, 0); + for index in 0..16 { + value[index] = 1; + let excluded_positions_enc: [u8; 16] = aesenc(value.convert(), zero_mask_enc).convert(); + let excluded_positions_dec: [u8; 16] = aesdec(value.convert(), zero_mask_dec).convert(); + let actual_location: [u8; 16] = shuffle(value.convert()).convert(); + for pos in 0..16 { + if actual_location[pos] != 0 { + assert_eq!( + 0, excluded_positions_enc[pos], + "Forward Overlap between {:?} and {:?} at {}", + excluded_positions_enc, actual_location, index + ); + assert_eq!( + 0, excluded_positions_dec[pos], + "Reverse Overlap between {:?} and {:?} at {}", + excluded_positions_dec, actual_location, index + ); + } + } + value[index] = 0; + } + } + + #[test] + fn test_shuffle_contains_each_value() { + let value: [u8; 16] = 0x00010203_04050607_08090A0B_0C0D0E0F_u128.convert(); + let shuffled: [u8; 16] = shuffle(value.convert()).convert(); + for index in 0..16_u8 { + assert!(shuffled.contains(&index), "Value is missing {}", index); + } + } + + #[test] + fn test_shuffle_moves_every_value() { + let mut value: [u8; 16] = [0; 16]; + for index in 0..16 { + value[index] = 1; + let shuffled: [u8; 16] = shuffle(value.convert()).convert(); + assert_eq!(0, shuffled[index], "Value is not moved {}", index); + value[index] = 0; + } + } + + #[test] + fn test_shuffle_moves_high_bits() { + assert!( + shuffle(1) > (1_u128 << 80), + "Low bits must be moved to other half {:?} -> {:?}", + 0, + shuffle(1) + ); + + assert!( + shuffle(1_u128 << 58) >= (1_u128 << 64), + "High bits must be moved to other half {:?} -> {:?}", + 7, + shuffle(1_u128 << 58) + ); + assert!( + shuffle(1_u128 << 58) < (1_u128 << 112), + "High bits must not remain high {:?} -> {:?}", + 7, + shuffle(1_u128 << 58) + ); + assert!( + shuffle(1_u128 << 64) < (1_u128 << 64), + "Low bits must be moved to other half {:?} -> {:?}", + 8, + shuffle(1_u128 << 64) + ); + assert!( + shuffle(1_u128 << 64) >= (1_u128 << 16), + "Low bits must not remain low {:?} -> {:?}", + 8, + shuffle(1_u128 << 64) + ); + + assert!( + shuffle(1_u128 << 120) < (1_u128 << 50), + "High bits must be moved to low half {:?} -> {:?}", + 15, + shuffle(1_u128 << 120) + ); + } + + #[cfg(all( + any(target_arch = "x86", target_arch = "x86_64"), + target_feature = "ssse3", + not(miri) + ))] + #[test] + fn test_shuffle_does_not_loop() { + let numbered = 0x00112233_44556677_8899AABB_CCDDEEFF; + let mut shuffled = shuffle(numbered); + for count in 0..100 { + // println!("{:>16x}", shuffled); + assert_ne!(numbered, shuffled, "Equal after {} vs {:x}", count, shuffled); + shuffled = shuffle(shuffled); + } + } +} diff --git a/vendor/ahash-0.7.7/src/random_state.rs b/vendor/ahash-0.7.7/src/random_state.rs new file mode 100644 index 0000000000000..9ac2f3ec432fc --- /dev/null +++ b/vendor/ahash-0.7.7/src/random_state.rs @@ -0,0 +1,363 @@ +#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))] +use crate::convert::Convert; +#[cfg(feature = "specialize")] +use crate::BuildHasherExt; + +#[cfg(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") +))] +pub use crate::aes_hash::*; + +#[cfg(not(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") +)))] +pub use crate::fallback_hash::*; + +#[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))] +use const_random::const_random; +use core::any::{Any, TypeId}; +use core::fmt; +use core::hash::BuildHasher; +#[cfg(feature = "specialize")] +use core::hash::Hash; +use core::hash::Hasher; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std as alloc; + +#[cfg(feature = "atomic-polyfill")] +use atomic_polyfill as atomic; +#[cfg(not(feature = "atomic-polyfill"))] +use core::sync::atomic; + +use alloc::boxed::Box; +use atomic::{AtomicUsize, Ordering}; +#[cfg(not(all(target_arch = "arm", target_os = "none")))] +use once_cell::race::OnceBox; + +#[cfg(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") +))] +use crate::aes_hash::*; +#[cfg(not(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") +)))] +use crate::fallback_hash::*; + +#[cfg(not(all(target_arch = "arm", target_os = "none")))] +static RAND_SOURCE: OnceBox> = OnceBox::new(); + +/// A supplier of Randomness used for different hashers. +/// See [RandomState.set_random_source]. +pub trait RandomSource { + + fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2]; + + fn gen_hasher_seed(&self) -> usize; + +} + +pub(crate) const PI: [u64; 4] = [ + 0x243f_6a88_85a3_08d3, + 0x1319_8a2e_0370_7344, + 0xa409_3822_299f_31d0, + 0x082e_fa98_ec4e_6c89, +]; + +pub(crate) const PI2: [u64; 4] = [ + 0x4528_21e6_38d0_1377, + 0xbe54_66cf_34e9_0c6c, + 0xc0ac_29b7_c97c_50dd, + 0x3f84_d5b5_b547_0917, +]; + +struct DefaultRandomSource { + counter: AtomicUsize, +} + +impl DefaultRandomSource { + fn new() -> DefaultRandomSource { + DefaultRandomSource { + counter: AtomicUsize::new(&PI as *const _ as usize), + } + } + + const fn default() -> DefaultRandomSource { + DefaultRandomSource { + counter: AtomicUsize::new(PI[3] as usize), + } + } +} + +impl RandomSource for DefaultRandomSource { + + #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))] + fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2] { + static SEEDS: OnceBox<[[u64; 4]; 2]> = OnceBox::new(); + + SEEDS.get_or_init(|| { + let mut result: [u8; 64] = [0; 64]; + getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed."); + Box::new(result.convert()) + }) + } + + #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))] + fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2] { + const RAND: [[u64; 4]; 2] = [ + [ + const_random!(u64), + const_random!(u64), + const_random!(u64), + const_random!(u64), + ], [ + const_random!(u64), + const_random!(u64), + const_random!(u64), + const_random!(u64), + ] + ]; + &RAND + } + + #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))] + fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2] { + &[PI, PI2] + } + + #[cfg(not(all(target_arch = "arm", target_os = "none")))] + fn gen_hasher_seed(&self) -> usize { + let stack = self as *const _ as usize; + self.counter.fetch_add(stack, Ordering::Relaxed) + } + + #[cfg(all(target_arch = "arm", target_os = "none"))] + fn gen_hasher_seed(&self) -> usize { + let stack = self as *const _ as usize; + let previous = self.counter.load(Ordering::Relaxed); + let new = previous.wrapping_add(stack); + self.counter.store(new, Ordering::Relaxed); + new + } +} + +/// Provides a [Hasher] factory. This is typically used (e.g. by [HashMap]) to create +/// [AHasher]s in order to hash the keys of the map. See `build_hasher` below. +/// +/// [build_hasher]: ahash:: +/// [Hasher]: std::hash::Hasher +/// [BuildHasher]: std::hash::BuildHasher +/// [HashMap]: std::collections::HashMap +#[derive(Clone)] +pub struct RandomState { + pub(crate) k0: u64, + pub(crate) k1: u64, + pub(crate) k2: u64, + pub(crate) k3: u64, +} + +impl fmt::Debug for RandomState { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("RandomState { .. }") + } +} + +impl RandomState { + + /// Provides an optional way to manually supply a source of randomness for Hasher keys. + /// + /// The provided [RandomSource] will be used to be used as a source of randomness by [RandomState] to generate new states. + /// If this method is not invoked the standard source of randomness is used as described in the Readme. + /// + /// The source of randomness can only be set once, and must be set before the first RandomState is created. + /// If the source has already been specified `Err` is returned with a `bool` indicating if the set failed because + /// method was previously invoked (true) or if the default source is already being used (false). + #[cfg(not(all(target_arch = "arm", target_os = "none")))] + pub fn set_random_source(source: impl RandomSource + Send + Sync + 'static) -> Result<(), bool> { + RAND_SOURCE.set(Box::new(Box::new(source))).map_err(|s| s.as_ref().type_id() != TypeId::of::<&DefaultRandomSource>()) + } + + #[inline] + #[cfg(not(all(target_arch = "arm", target_os = "none")))] + fn get_src() -> &'static dyn RandomSource { + RAND_SOURCE.get_or_init(|| Box::new(Box::new(DefaultRandomSource::new()))).as_ref() + } + + #[inline] + #[cfg(all(target_arch = "arm", target_os = "none"))] + fn get_src() -> &'static dyn RandomSource { + static RAND_SOURCE: DefaultRandomSource = DefaultRandomSource::default(); + &RAND_SOURCE + } + + /// Use randomly generated keys + #[inline] + pub fn new() -> RandomState { + let src = Self::get_src(); + let fixed = src.get_fixed_seeds(); + Self::from_keys(&fixed[0], &fixed[1], src.gen_hasher_seed()) + } + + /// Allows for supplying seeds, but each time it is called the resulting state will be different. + /// This is done using a static counter, so it can safely be used with a fixed keys. + #[inline] + pub fn generate_with(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState { + let src = Self::get_src(); + let fixed = src.get_fixed_seeds(); + RandomState::from_keys(&fixed[0], &[k0, k1, k2, k3], src.gen_hasher_seed()) + } + + fn from_keys(a: &[u64; 4], b: &[u64; 4], c: usize) -> RandomState { + let &[k0, k1, k2, k3] = a; + let mut hasher = AHasher::from_random_state(&RandomState { k0, k1, k2, k3 }); + hasher.write_usize(c); + let mix = |k: u64| { + let mut h = hasher.clone(); + h.write_u64(k); + h.finish() + }; + RandomState { + k0: mix(b[0]), + k1: mix(b[1]), + k2: mix(b[2]), + k3: mix(b[3]), + } + } + + /// Internal. Used by Default. + #[inline] + pub(crate) fn with_fixed_keys() -> RandomState { + let [k0, k1, k2, k3] = Self::get_src().get_fixed_seeds()[0]; + RandomState { k0, k1, k2, k3 } + } + + /// Allows for explicitly setting a seed to used. + /// + /// Note: This method does not require the provided seed to be strong. + #[inline] + pub fn with_seed(key: usize) -> RandomState { + let fixed = Self::get_src().get_fixed_seeds(); + RandomState::from_keys(&fixed[0], &fixed[1], key) + } + + /// Allows for explicitly setting the seeds to used. + /// + /// Note: This method is robust against 0s being passed for one or more of the parameters + /// or the same value being passed for more than one parameter. + #[inline] + pub const fn with_seeds(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState { + RandomState { k0: k0 ^ PI2[0], k1: k1 ^ PI2[1], k2: k2 ^ PI2[2], k3: k3 ^ PI2[3] } + } +} + +impl Default for RandomState { + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl BuildHasher for RandomState { + type Hasher = AHasher; + + /// Constructs a new [AHasher] with keys based on this [RandomState] object. + /// This means that two different [RandomState]s will will generate + /// [AHasher]s that will return different hashcodes, but [Hasher]s created from the same [BuildHasher] + /// will generate the same hashes for the same input data. + /// + /// # Examples + /// + /// ``` + /// use ahash::{AHasher, RandomState}; + /// use std::hash::{Hasher, BuildHasher}; + /// + /// let build_hasher = RandomState::new(); + /// let mut hasher_1 = build_hasher.build_hasher(); + /// let mut hasher_2 = build_hasher.build_hasher(); + /// + /// hasher_1.write_u32(1234); + /// hasher_2.write_u32(1234); + /// + /// assert_eq!(hasher_1.finish(), hasher_2.finish()); + /// + /// let other_build_hasher = RandomState::new(); + /// let mut different_hasher = other_build_hasher.build_hasher(); + /// different_hasher.write_u32(1234); + /// assert_ne!(different_hasher.finish(), hasher_1.finish()); + /// ``` + /// [Hasher]: std::hash::Hasher + /// [BuildHasher]: std::hash::BuildHasher + /// [HashMap]: std::collections::HashMap + #[inline] + fn build_hasher(&self) -> AHasher { + AHasher::from_random_state(self) + } +} + +#[cfg(feature = "specialize")] +impl BuildHasherExt for RandomState { + #[inline] + fn hash_as_u64(&self, value: &T) -> u64 { + let mut hasher = AHasherU64 { + buffer: self.k0, + pad: self.k1, + }; + value.hash(&mut hasher); + hasher.finish() + } + + #[inline] + fn hash_as_fixed_length(&self, value: &T) -> u64 { + let mut hasher = AHasherFixed(self.build_hasher()); + value.hash(&mut hasher); + hasher.finish() + } + + #[inline] + fn hash_as_str(&self, value: &T) -> u64 { + let mut hasher = AHasherStr(self.build_hasher()); + value.hash(&mut hasher); + hasher.finish() + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_unique() { + let a = RandomState::new(); + let b = RandomState::new(); + assert_ne!(a.build_hasher().finish(), b.build_hasher().finish()); + } + + #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))] + #[test] + fn test_not_pi() { + assert_ne!(PI, RandomState::get_src().get_fixed_seeds()[0]); + } + + #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))] + #[test] + fn test_not_pi_const() { + assert_ne!(PI, RandomState::get_src().get_fixed_seeds()[0]); + } + + #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))] + #[test] + fn test_pi() { + assert_eq!(PI, RandomState::get_src().get_fixed_seeds()[0]); + } + + #[test] + fn test_with_seeds_const() { + const _CONST_RANDOM_STATE: RandomState = RandomState::with_seeds(17, 19, 21, 23); + } +} diff --git a/vendor/ahash-0.7.7/src/specialize.rs b/vendor/ahash-0.7.7/src/specialize.rs new file mode 100644 index 0000000000000..d94a4eed0d0ac --- /dev/null +++ b/vendor/ahash-0.7.7/src/specialize.rs @@ -0,0 +1,239 @@ +use core::hash::BuildHasher; +use core::hash::Hash; +use core::hash::Hasher; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std as alloc; + +#[cfg(feature = "specialize")] +use crate::BuildHasherExt; +#[cfg(feature = "specialize")] +use alloc::string::String; +#[cfg(feature = "specialize")] +use alloc::vec::Vec; + +/// Provides a way to get an optimized hasher for a given data type. +/// Rather than using a Hasher generically which can hash any value, this provides a way to get a specialized hash +/// for a specific type. So this may be faster for primitive types. +/// # Example +/// ``` +/// use std::hash::BuildHasher; +/// use ahash::RandomState; +/// use ahash::CallHasher; +/// +/// let hash_builder = RandomState::new(); +/// //... +/// let value: u32 = 17; +/// let hash = u32::get_hash(&value, &hash_builder); +/// ``` +/// Note that the type used to invoke `get_hash` must be the same a the type of value passed. +/// For example get a hasher specialized on `[u8]` can invoke: +/// ``` +/// /// use std::hash::BuildHasher; +/// # use ahash::RandomState; +/// # use ahash::CallHasher; +/// # let hash_builder = RandomState::new(); +/// let bytes: [u8; 4] = [1, 2, 3, 4]; +/// let hash = <[u8]>::get_hash(&bytes, &hash_builder); +/// ``` +pub trait CallHasher { + fn get_hash(value: &H, build_hasher: &B) -> u64; +} + +#[cfg(not(feature = "specialize"))] +impl CallHasher for T +where + T: Hash + ?Sized, +{ + #[inline] + fn get_hash(value: &H, build_hasher: &B) -> u64 { + let mut hasher = build_hasher.build_hasher(); + value.hash(&mut hasher); + hasher.finish() + } +} + +#[cfg(feature = "specialize")] +impl CallHasher for T +where + T: Hash + ?Sized, +{ + #[inline] + default fn get_hash(value: &H, build_hasher: &B) -> u64 { + let mut hasher = build_hasher.build_hasher(); + value.hash(&mut hasher); + hasher.finish() + } +} + +macro_rules! call_hasher_impl { + ($typ:ty) => { + #[cfg(feature = "specialize")] + impl CallHasher for $typ { + #[inline] + fn get_hash(value: &H, build_hasher: &B) -> u64 { + build_hasher.hash_as_u64(value) + } + } + }; +} +call_hasher_impl!(u8); +call_hasher_impl!(u16); +call_hasher_impl!(u32); +call_hasher_impl!(u64); +call_hasher_impl!(i8); +call_hasher_impl!(i16); +call_hasher_impl!(i32); +call_hasher_impl!(i64); + +#[cfg(feature = "specialize")] +impl CallHasher for u128 { + #[inline] + fn get_hash(value: &H, build_hasher: &B) -> u64 { + build_hasher.hash_as_fixed_length(value) + } +} + +#[cfg(feature = "specialize")] +impl CallHasher for i128 { + #[inline] + fn get_hash(value: &H, build_hasher: &B) -> u64 { + build_hasher.hash_as_fixed_length(value) + } +} + +#[cfg(feature = "specialize")] +impl CallHasher for usize { + #[inline] + fn get_hash(value: &H, build_hasher: &B) -> u64 { + build_hasher.hash_as_fixed_length(value) + } +} + +#[cfg(feature = "specialize")] +impl CallHasher for isize { + #[inline] + fn get_hash(value: &H, build_hasher: &B) -> u64 { + build_hasher.hash_as_fixed_length(value) + } +} + +#[cfg(feature = "specialize")] +impl CallHasher for [u8] { + #[inline] + fn get_hash(value: &H, build_hasher: &B) -> u64 { + build_hasher.hash_as_str(value) + } +} + +#[cfg(feature = "specialize")] +impl CallHasher for Vec { + #[inline] + fn get_hash(value: &H, build_hasher: &B) -> u64 { + build_hasher.hash_as_str(value) + } +} + +#[cfg(feature = "specialize")] +impl CallHasher for str { + #[inline] + fn get_hash(value: &H, build_hasher: &B) -> u64 { + build_hasher.hash_as_str(value) + } +} + +#[cfg(all(feature = "specialize"))] +impl CallHasher for String { + #[inline] + fn get_hash(value: &H, build_hasher: &B) -> u64 { + build_hasher.hash_as_str(value) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::*; + + #[test] + #[cfg(feature = "specialize")] + pub fn test_specialized_invoked() { + let build_hasher = RandomState::with_seeds(1, 2, 3, 4); + let shortened = u64::get_hash(&0, &build_hasher); + let mut hasher = AHasher::new_with_keys(1, 2); + 0_u64.hash(&mut hasher); + assert_ne!(hasher.finish(), shortened); + } + + /// Tests that some non-trivial transformation takes place. + #[test] + pub fn test_input_processed() { + let build_hasher = RandomState::with_seeds(2, 2, 2, 2); + assert_ne!(0, u64::get_hash(&0, &build_hasher)); + assert_ne!(1, u64::get_hash(&0, &build_hasher)); + assert_ne!(2, u64::get_hash(&0, &build_hasher)); + assert_ne!(3, u64::get_hash(&0, &build_hasher)); + assert_ne!(4, u64::get_hash(&0, &build_hasher)); + assert_ne!(5, u64::get_hash(&0, &build_hasher)); + + assert_ne!(0, u64::get_hash(&1, &build_hasher)); + assert_ne!(1, u64::get_hash(&1, &build_hasher)); + assert_ne!(2, u64::get_hash(&1, &build_hasher)); + assert_ne!(3, u64::get_hash(&1, &build_hasher)); + assert_ne!(4, u64::get_hash(&1, &build_hasher)); + assert_ne!(5, u64::get_hash(&1, &build_hasher)); + + let xored = u64::get_hash(&0, &build_hasher) ^ u64::get_hash(&1, &build_hasher); + assert_ne!(0, xored); + assert_ne!(1, xored); + assert_ne!(2, xored); + assert_ne!(3, xored); + assert_ne!(4, xored); + assert_ne!(5, xored); + } + + #[test] + pub fn test_ref_independent() { + let build_hasher = RandomState::with_seeds(1, 2, 3, 4); + assert_eq!(u8::get_hash(&&1, &build_hasher), u8::get_hash(&1, &build_hasher)); + assert_eq!(u16::get_hash(&&2, &build_hasher), u16::get_hash(&2, &build_hasher)); + assert_eq!(u32::get_hash(&&3, &build_hasher), u32::get_hash(&3, &build_hasher)); + assert_eq!(u64::get_hash(&&4, &build_hasher), u64::get_hash(&4, &build_hasher)); + assert_eq!(u128::get_hash(&&5, &build_hasher), u128::get_hash(&5, &build_hasher)); + assert_eq!( + str::get_hash(&"test", &build_hasher), + str::get_hash("test", &build_hasher) + ); + assert_eq!( + str::get_hash(&"test", &build_hasher), + String::get_hash(&"test".to_string(), &build_hasher) + ); + #[cfg(feature = "specialize")] + assert_eq!( + str::get_hash(&"test", &build_hasher), + <[u8]>::get_hash("test".as_bytes(), &build_hasher) + ); + + let build_hasher = RandomState::with_seeds(10, 20, 30, 40); + assert_eq!(u8::get_hash(&&&1, &build_hasher), u8::get_hash(&1, &build_hasher)); + assert_eq!(u16::get_hash(&&&2, &build_hasher), u16::get_hash(&2, &build_hasher)); + assert_eq!(u32::get_hash(&&&3, &build_hasher), u32::get_hash(&3, &build_hasher)); + assert_eq!(u64::get_hash(&&&4, &build_hasher), u64::get_hash(&4, &build_hasher)); + assert_eq!(u128::get_hash(&&&5, &build_hasher), u128::get_hash(&5, &build_hasher)); + assert_eq!( + str::get_hash(&&"test", &build_hasher), + str::get_hash("test", &build_hasher) + ); + assert_eq!( + str::get_hash(&&"test", &build_hasher), + String::get_hash(&"test".to_string(), &build_hasher) + ); + #[cfg(feature = "specialize")] + assert_eq!( + str::get_hash(&&"test", &build_hasher), + <[u8]>::get_hash(&"test".to_string().into_bytes(), &build_hasher) + ); + } +} diff --git a/vendor/ahash-0.7.7/tests/bench.rs b/vendor/ahash-0.7.7/tests/bench.rs new file mode 100644 index 0000000000000..9e6dccc481e6e --- /dev/null +++ b/vendor/ahash-0.7.7/tests/bench.rs @@ -0,0 +1,154 @@ +use ahash::{CallHasher, RandomState}; +use criterion::*; +use fxhash::FxHasher; +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; + +#[cfg(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") +))] +fn aeshash(b: &H) -> u64 { + let build_hasher = RandomState::with_seeds(1, 2, 3, 4); + H::get_hash(b, &build_hasher) +} +#[cfg(not(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") +)))] +fn aeshash(_b: &H) -> u64 { + panic!("aes must be enabled") +} + +#[cfg(not(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") +)))] +fn fallbackhash(b: &H) -> u64 { + let build_hasher = RandomState::with_seeds(1, 2, 3, 4); + H::get_hash(b, &build_hasher) +} +#[cfg(any( + all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), + all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd") +))] +fn fallbackhash(_b: &H) -> u64 { + panic!("aes must be disabled") +} + +fn fnvhash(b: &H) -> u64 { + let mut hasher = fnv::FnvHasher::default(); + b.hash(&mut hasher); + hasher.finish() +} + +fn siphash(b: &H) -> u64 { + let mut hasher = DefaultHasher::default(); + b.hash(&mut hasher); + hasher.finish() +} + +fn fxhash(b: &H) -> u64 { + let mut hasher = FxHasher::default(); + b.hash(&mut hasher); + hasher.finish() +} + +fn seahash(b: &H) -> u64 { + let mut hasher = seahash::SeaHasher::default(); + b.hash(&mut hasher); + hasher.finish() +} + +const STRING_LENGTHS: [u32; 12] = [1, 3, 4, 7, 8, 15, 16, 24, 33, 68, 132, 1024]; + +fn gen_strings() -> Vec { + STRING_LENGTHS + .iter() + .map(|len| { + let mut string = String::default(); + for pos in 1..=*len { + let c = (48 + (pos % 10) as u8) as char; + string.push(c); + } + string + }) + .collect() +} + +const U8_VALUE: u8 = 123; +const U16_VALUE: u16 = 1234; +const U32_VALUE: u32 = 12345678; +const U64_VALUE: u64 = 1234567890123456; +const U128_VALUE: u128 = 12345678901234567890123456789012; + +fn bench_ahash(c: &mut Criterion) { + let mut group = c.benchmark_group("aeshash"); + group.bench_with_input("u8", &U8_VALUE, |b, s| b.iter(|| black_box(aeshash(s)))); + group.bench_with_input("u16", &U16_VALUE, |b, s| b.iter(|| black_box(aeshash(s)))); + group.bench_with_input("u32", &U32_VALUE, |b, s| b.iter(|| black_box(aeshash(s)))); + group.bench_with_input("u64", &U64_VALUE, |b, s| b.iter(|| black_box(aeshash(s)))); + group.bench_with_input("u128", &U128_VALUE, |b, s| b.iter(|| black_box(aeshash(s)))); + group.bench_with_input("string", &gen_strings(), |b, s| b.iter(|| black_box(aeshash(s)))); +} + +fn bench_fallback(c: &mut Criterion) { + let mut group = c.benchmark_group("fallback"); + group.bench_with_input("u8", &U8_VALUE, |b, s| b.iter(|| black_box(fallbackhash(s)))); + group.bench_with_input("u16", &U16_VALUE, |b, s| b.iter(|| black_box(fallbackhash(s)))); + group.bench_with_input("u32", &U32_VALUE, |b, s| b.iter(|| black_box(fallbackhash(s)))); + group.bench_with_input("u64", &U64_VALUE, |b, s| b.iter(|| black_box(fallbackhash(s)))); + group.bench_with_input("u128", &U128_VALUE, |b, s| b.iter(|| black_box(fallbackhash(s)))); + group.bench_with_input("string", &gen_strings(), |b, s| b.iter(|| black_box(fallbackhash(s)))); +} + +fn bench_fx(c: &mut Criterion) { + let mut group = c.benchmark_group("fx"); + group.bench_with_input("u8", &U8_VALUE, |b, s| b.iter(|| black_box(fxhash(s)))); + group.bench_with_input("u16", &U16_VALUE, |b, s| b.iter(|| black_box(fxhash(s)))); + group.bench_with_input("u32", &U32_VALUE, |b, s| b.iter(|| black_box(fxhash(s)))); + group.bench_with_input("u64", &U64_VALUE, |b, s| b.iter(|| black_box(fxhash(s)))); + group.bench_with_input("u128", &U128_VALUE, |b, s| b.iter(|| black_box(fxhash(s)))); + group.bench_with_input("string", &gen_strings(), |b, s| b.iter(|| black_box(fxhash(s)))); +} + +fn bench_fnv(c: &mut Criterion) { + let mut group = c.benchmark_group("fnv"); + group.bench_with_input("u8", &U8_VALUE, |b, s| b.iter(|| black_box(fnvhash(s)))); + group.bench_with_input("u16", &U16_VALUE, |b, s| b.iter(|| black_box(fnvhash(s)))); + group.bench_with_input("u32", &U32_VALUE, |b, s| b.iter(|| black_box(fnvhash(s)))); + group.bench_with_input("u64", &U64_VALUE, |b, s| b.iter(|| black_box(fnvhash(s)))); + group.bench_with_input("u128", &U128_VALUE, |b, s| b.iter(|| black_box(fnvhash(s)))); + group.bench_with_input("string", &gen_strings(), |b, s| b.iter(|| black_box(fnvhash(s)))); +} + +fn bench_sea(c: &mut Criterion) { + let mut group = c.benchmark_group("sea"); + group.bench_with_input("u8", &U8_VALUE, |b, s| b.iter(|| black_box(seahash(s)))); + group.bench_with_input("u16", &U16_VALUE, |b, s| b.iter(|| black_box(seahash(s)))); + group.bench_with_input("u32", &U32_VALUE, |b, s| b.iter(|| black_box(seahash(s)))); + group.bench_with_input("u64", &U64_VALUE, |b, s| b.iter(|| black_box(seahash(s)))); + group.bench_with_input("u128", &U128_VALUE, |b, s| b.iter(|| black_box(seahash(s)))); + group.bench_with_input("string", &gen_strings(), |b, s| b.iter(|| black_box(seahash(s)))); +} + +fn bench_sip(c: &mut Criterion) { + let mut group = c.benchmark_group("sip"); + group.bench_with_input("u8", &U8_VALUE, |b, s| b.iter(|| black_box(siphash(s)))); + group.bench_with_input("u16", &U16_VALUE, |b, s| b.iter(|| black_box(siphash(s)))); + group.bench_with_input("u32", &U32_VALUE, |b, s| b.iter(|| black_box(siphash(s)))); + group.bench_with_input("u64", &U64_VALUE, |b, s| b.iter(|| black_box(siphash(s)))); + group.bench_with_input("u128", &U128_VALUE, |b, s| b.iter(|| black_box(siphash(s)))); + group.bench_with_input("string", &gen_strings(), |b, s| b.iter(|| black_box(siphash(s)))); +} + +criterion_main!(benches); +criterion_group!( + benches, + bench_ahash, + bench_fallback, + bench_fx, + bench_fnv, + bench_sea, + bench_sip +); diff --git a/vendor/ahash-0.7.7/tests/map_tests.rs b/vendor/ahash-0.7.7/tests/map_tests.rs new file mode 100644 index 0000000000000..be617a2e7290f --- /dev/null +++ b/vendor/ahash-0.7.7/tests/map_tests.rs @@ -0,0 +1,203 @@ +use std::hash::{BuildHasher, Hash, Hasher}; + +use criterion::*; +use fxhash::FxHasher; + +use ahash::{AHasher, CallHasher, RandomState}; + +fn gen_word_pairs() -> Vec { + let words: Vec<_> = r#" +a, ability, able, about, above, accept, according, account, across, act, action, +activity, actually, add, address, administration, admit, adult, affect, after, +again, against, age, agency, agent, ago, agree, agreement, ahead, air, all, +allow, almost, alone, along, already, also, although, always, American, among, +amount, analysis, and, animal, another, answer, any, anyone, anything, appear, +apply, approach, area, argue, arm, around, arrive, art, article, artist, as, +ask, assume, at, attack, attention, attorney, audience, author, authority, +available, avoid, away, baby, back, bad, bag, ball, bank, bar, base, be, beat, +beautiful, because, become, bed, before, begin, behavior, behind, believe, +benefit, best, better, between, beyond, big, bill, billion, bit, black, blood, +blue, board, body, book, born, both, box, boy, break, bring, brother, budget, +build, building, business, but, buy, by, call, camera, campaign, can, cancer, +candidate, capital, car, card, care, career, carry, case, catch, cause, cell, +center, central, century, certain, certainly, chair, challenge, chance, change, +character, charge, check, child, choice, choose, church, citizen, city, civil, +claim, class, clear, clearly, close, coach, cold, collection, college, color, +come, commercial, common, community, company, compare, computer, concern, +condition, conference, Congress, consider, consumer, contain, continue, control, +cost, could, country, couple, course, court, cover, create, crime, cultural, +culture, cup, current, customer, cut, dark, data, daughter, day, dead, deal, +death, debate, decade, decide, decision, deep, defense, degree, Democrat, +democratic, describe, design, despite, detail, determine, develop, development, +die, difference, different, difficult, dinner, direction, director, discover, +discuss, discussion, disease, do, doctor, dog, door, down, draw, dream, drive, +drop, drug, during, each, early, east, easy, eat, economic, economy, edge, +education, effect, effort, eight, either, election, else, employee, end, energy, +enjoy, enough, enter, entire, environment, environmental, especially, establish, +even, evening, event, ever, every, everybody, everyone, everything, evidence, +exactly, example, executive, exist, expect, experience, expert, explain, eye, +face, fact, factor, fail, fall, family, far, fast, father, fear, federal, feel, +feeling, few, field, fight, figure, fill, film, final, finally, financial, find, +fine, finger, finish, fire, firm, first, fish, five, floor, fly, focus, follow, +food, foot, for, force, foreign, forget, form, former, forward, four, free, +friend, from, front, full, fund, future, game, garden, gas, general, generation, +get, girl, give, glass, go, goal, good, government, great, green, ground, group, +grow, growth, guess, gun, guy, hair, half, hand, hang, happen, happy, hard, +have, he, head, health, hear, heart, heat, heavy, help, her, here, herself, +high, him, himself, his, history, hit, hold, home, hope, hospital, hot, hotel, +hour, house, how, however, huge, human, hundred, husband, I, idea, identify, if, +image, imagine, impact, important, improve, in, include, including, increase, +indeed, indicate, individual, industry, information, inside, instead, +institution, interest, interesting, international, interview, into, investment, +involve, issue, it, item, its, itself, job, join, just, keep, key, kid, kill, +kind, kitchen, know, knowledge, land, language, large, last, late, later, laugh, +law, lawyer, lay, lead, leader, learn, least, leave, left, leg, legal, less, +let, letter, level, lie, life, light, like, likely, line, list, listen, little, +live, local, long, look, lose, loss, lot, love, low, machine, magazine, main, +maintain, major, majority, make, man, manage, management, manager, many, market, +marriage, material, matter, may, maybe, me, mean, measure, media, medical, meet, +meeting, member, memory, mention, message, method, middle, might, military, +million, mind, minute, miss, mission, model, modern, moment, money, month, more, +morning, most, mother, mouth, move, movement, movie, Mr, Mrs, much, music, must, +my, myself, name, nation, national, natural, nature, near, nearly, necessary, +need, network, never, new, news, newspaper, next, nice, night, no, none, nor, +north, not, note, nothing, notice, now, n't, number, occur, of, off, offer, +office, officer, official, often, oh, oil, ok, old, on, once, one, only, onto, +open, operation, opportunity, option, or, order, organization, other, others, +our, out, outside, over, own, owner, page, pain, painting, paper, parent, part, +participant, particular, particularly, partner, party, pass, past, patient, +pattern, pay, peace, people, per, perform, performance, perhaps, period, person, +personal, phone, physical, pick, picture, piece, place, plan, plant, play, +player, PM, point, police, policy, political, politics, poor, popular, +population, position, positive, possible, power, practice, prepare, present, +president, pressure, pretty, prevent, price, private, probably, problem, +process, produce, product, production, professional, professor, program, +project, property, protect, prove, provide, public, pull, purpose, push, put, +quality, question, quickly, quite, race, radio, raise, range, rate, rather, +reach, read, ready, real, reality, realize, really, reason, receive, recent, +recently, recognize, record, red, reduce, reflect, region, relate, relationship, +religious, remain, remember, remove, report, represent, Republican, require, +research, resource, respond, response, responsibility, rest, result, return, +reveal, rich, right, rise, risk, road, rock, role, room, rule, run, safe, same, +save, say, scene, school, science, scientist, score, sea, season, seat, second, +section, security, see, seek, seem, sell, send, senior, sense, series, serious, +serve, service, set, seven, several, sex, sexual, shake, share, she, shoot, +short, shot, should, shoulder, show, side, sign, significant, similar, simple, +simply, since, sing, single, sister, sit, site, situation, six, size, skill, +skin, small, smile, so, social, society, soldier, some, somebody, someone, +something, sometimes, son, song, soon, sort, sound, source, south, southern, +space, speak, special, specific, speech, spend, sport, spring, staff, stage, +stand, standard, star, start, state, statement, station, stay, step, still, +stock, stop, store, story, strategy, street, strong, structure, student, study, +stuff, style, subject, success, successful, such, suddenly, suffer, suggest, +summer, support, sure, surface, system, table, take, talk, task, tax, teach, +teacher, team, technology, television, tell, ten, tend, term, test, than, thank, +that, the, their, them, themselves, then, theory, there, these, they, thing, +think, third, this, those, though, thought, thousand, threat, three, through, +throughout, throw, thus, time, to, today, together, tonight, too, top, total, +tough, toward, town, trade, traditional, training, travel, treat, treatment, +tree, trial, trip, trouble, true, truth, try, turn, TV, two, type, under, +understand, unit, until, up, upon, us, use, usually, value, various, very, +victim, view, violence, visit, voice, vote, wait, walk, wall, want, war, watch, +water, way, we, weapon, wear, week, weight, well, west, western, what, whatever, +when, where, whether, which, while, white, who, whole, whom, whose, why, wide, +wife, will, win, wind, window, wish, with, within, without, woman, wonder, word, +work, worker, world, worry, would, write, writer, wrong, yard, yeah, year, yes, +yet, you, young, your, yourself"# + .split(',') + .map(|word| word.trim()) + .collect(); + + let mut word_pairs: Vec<_> = Vec::new(); + for word in &words { + for other_word in &words { + word_pairs.push(word.to_string() + " " + other_word); + } + } + assert_eq!(1_000_000, word_pairs.len()); + word_pairs +} + +#[allow(unused)] // False positive +fn test_hash_common_words(build_hasher: &B) { + let word_pairs: Vec<_> = gen_word_pairs(); + check_for_collisions(build_hasher, &word_pairs, 32); +} + +#[allow(unused)] // False positive +fn check_for_collisions(build_hasher: &B, items: &[H], bucket_count: usize) { + let mut buckets = vec![0; bucket_count]; + for item in items { + let value = hash(item, build_hasher) as usize; + buckets[value % bucket_count] += 1; + } + let mean = items.len() / bucket_count; + let max = *buckets.iter().max().unwrap(); + let min = *buckets.iter().min().unwrap(); + assert!( + (min as f64) > (mean as f64) * 0.95, + "min: {}, max:{}, {:?}", + min, + max, + buckets + ); + assert!( + (max as f64) < (mean as f64) * 1.05, + "min: {}, max:{}, {:?}", + min, + max, + buckets + ); +} + +#[allow(unused)] // False positive +fn hash(b: &H, build_hasher: &B) -> u64 { + H::get_hash(b, build_hasher) +} + +#[test] +fn test_bucket_distribution() { + let build_hasher = RandomState::with_seeds(1, 2, 3, 4); + test_hash_common_words(&build_hasher); + let sequence: Vec<_> = (0..320000).collect(); + check_for_collisions(&build_hasher, &sequence, 32); + let sequence: Vec<_> = (0..2560000).collect(); + check_for_collisions(&build_hasher, &sequence, 256); + let sequence: Vec<_> = (0..320000).map(|i| i * 1024).collect(); + check_for_collisions(&build_hasher, &sequence, 32); + let sequence: Vec<_> = (0..2560000_u64).map(|i| i * 1024).collect(); + check_for_collisions(&build_hasher, &sequence, 256); +} + +fn ahash_vec(b: &Vec) -> u64 { + let mut total: u64 = 0; + for item in b { + let mut hasher = AHasher::new_with_keys(1234, 5678); + item.hash(&mut hasher); + total = total.wrapping_add(hasher.finish()); + } + total +} + +fn fxhash_vec(b: &Vec) -> u64 { + let mut total: u64 = 0; + for item in b { + let mut hasher = FxHasher::default(); + item.hash(&mut hasher); + total = total.wrapping_add(hasher.finish()); + } + total +} + +fn bench_ahash_words(c: &mut Criterion) { + let words = gen_word_pairs(); + c.bench_function("aes_words", |b| b.iter(|| black_box(ahash_vec(&words)))); +} + +fn bench_fx_words(c: &mut Criterion) { + let words = gen_word_pairs(); + c.bench_function("fx_words", |b| b.iter(|| black_box(fxhash_vec(&words)))); +} + +criterion_main!(benches); +criterion_group!(benches, bench_ahash_words, bench_fx_words,); diff --git a/vendor/ahash-0.7.7/tests/nopanic.rs b/vendor/ahash-0.7.7/tests/nopanic.rs new file mode 100644 index 0000000000000..d48ff559d204c --- /dev/null +++ b/vendor/ahash-0.7.7/tests/nopanic.rs @@ -0,0 +1,72 @@ +use ahash::{AHasher, CallHasher, RandomState}; +use std::hash::BuildHasher; + +#[macro_use] +extern crate no_panic; + +#[inline(never)] +#[no_panic] +fn hash_test_final(num: i32, string: &str) -> (u64, u64) { + use core::hash::Hasher; + let mut hasher1 = AHasher::new_with_keys(1, 2); + let mut hasher2 = AHasher::new_with_keys(3, 4); + hasher1.write_i32(num); + hasher2.write(string.as_bytes()); + (hasher1.finish(), hasher2.finish()) +} + +#[inline(never)] +fn hash_test_final_wrapper(num: i32, string: &str) { + hash_test_final(num, string); +} + +struct SimpleBuildHasher { + hasher: AHasher, +} + +impl BuildHasher for SimpleBuildHasher { + type Hasher = AHasher; + + fn build_hasher(&self) -> Self::Hasher { + self.hasher.clone() + } +} + +#[inline(never)] +#[no_panic] +fn hash_test_specialize(num: i32, string: &str) -> (u64, u64) { + let hasher1 = AHasher::new_with_keys(1, 2); + let hasher2 = AHasher::new_with_keys(1, 2); + ( + i32::get_hash(&num, &SimpleBuildHasher { hasher: hasher1 }), + <[u8]>::get_hash(string.as_bytes(), &SimpleBuildHasher { hasher: hasher2 }), + ) +} + +#[inline(never)] +fn hash_test_random_wrapper(num: i32, string: &str) { + hash_test_specialize(num, string); +} + +#[inline(never)] +#[no_panic] +fn hash_test_random(num: i32, string: &str) -> (u64, u64) { + let build_hasher1 = RandomState::with_seeds(1, 2, 3, 4); + let build_hasher2 = RandomState::with_seeds(1, 2, 3, 4); + ( + i32::get_hash(&num, &build_hasher1), + <[u8]>::get_hash(string.as_bytes(), &build_hasher2), + ) +} + +#[inline(never)] +fn hash_test_specialize_wrapper(num: i32, string: &str) { + hash_test_specialize(num, string); +} + +#[test] +fn test_no_panic() { + hash_test_final_wrapper(2, "Foo"); + hash_test_specialize_wrapper(2, "Bar"); + hash_test_random_wrapper(2, "Baz"); +} diff --git a/vendor/allocator-api2/COPYING b/vendor/allocator-api2/COPYING new file mode 100644 index 0000000000000..4d3f91283013e --- /dev/null +++ b/vendor/allocator-api2/COPYING @@ -0,0 +1,6 @@ +Copyright 2023 The allocator-api2 Project Developers + +Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +copied, modified, or distributed except according to those terms. diff --git a/vendor/allocator-api2/license/APACHE b/vendor/allocator-api2/license/APACHE new file mode 100644 index 0000000000000..83b33707fc468 --- /dev/null +++ b/vendor/allocator-api2/license/APACHE @@ -0,0 +1,13 @@ +Copyright 2023 The allocator-api2 project developers + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/vendor/allocator-api2/license/MIT b/vendor/allocator-api2/license/MIT new file mode 100644 index 0000000000000..e8658e9b021fa --- /dev/null +++ b/vendor/allocator-api2/license/MIT @@ -0,0 +1,25 @@ +Copyright (c) 2023 The allocator-api2 project developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/anstyle-query/examples/report.rs b/vendor/anstyle-query/examples/report.rs new file mode 100644 index 0000000000000..322811471ffb2 --- /dev/null +++ b/vendor/anstyle-query/examples/report.rs @@ -0,0 +1,19 @@ +fn main() { + println!("clicolor: {:?}", anstyle_query::clicolor()); + println!("clicolor_force: {}", anstyle_query::clicolor_force()); + println!("no_color: {}", anstyle_query::no_color()); + println!( + "term_supports_ansi_color: {}", + anstyle_query::term_supports_ansi_color() + ); + println!( + "term_supports_color: {}", + anstyle_query::term_supports_color() + ); + println!("truecolor: {}", anstyle_query::truecolor()); + println!( + "enable_ansi_colors: {:?}", + anstyle_query::windows::enable_ansi_colors() + ); + println!("is_ci: {:?}", anstyle_query::is_ci()); +} diff --git a/vendor/anstyle-wincon/examples/dump.rs b/vendor/anstyle-wincon/examples/dump.rs new file mode 100644 index 0000000000000..bb80bf42ed51f --- /dev/null +++ b/vendor/anstyle-wincon/examples/dump.rs @@ -0,0 +1,139 @@ +use anstyle_wincon::WinconStream as _; + +fn main() -> Result<(), lexopt::Error> { + let args = Args::parse()?; + let stdout = std::io::stdout(); + let mut stdout = stdout.lock(); + + for fixed in 0..16 { + let style = style(fixed, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + if fixed == 7 || fixed == 15 { + let _ = stdout.write_colored(None, None, &b"\n"[..]); + } + } + + for r in 0..6 { + let _ = stdout.write_colored(None, None, &b"\n"[..]); + for g in 0..6 { + for b in 0..6 { + let fixed = r * 36 + g * 6 + b + 16; + let style = style(fixed, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + } + let _ = stdout.write_colored(None, None, &b"\n"[..]); + } + } + + for c in 0..24 { + if 0 == c % 8 { + let _ = stdout.write_colored(None, None, &b"\n"[..]); + } + let fixed = 232 + c; + let style = style(fixed, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + } + + Ok(()) +} + +fn style(fixed: u8, layer: Layer, effects: anstyle::Effects) -> anstyle::Style { + let color = anstyle::Ansi256Color(fixed).into(); + (match layer { + Layer::Fg => anstyle::Style::new().fg_color(Some(color)), + Layer::Bg => anstyle::Style::new().bg_color(Some(color)), + Layer::Underline => anstyle::Style::new().underline_color(Some(color)), + }) | effects +} + +fn print_number( + stdout: &mut std::io::StdoutLock<'static>, + fixed: u8, + style: anstyle::Style, +) -> std::io::Result<()> { + let fg = style.get_fg_color().and_then(|c| match c { + anstyle::Color::Ansi(c) => Some(c), + anstyle::Color::Ansi256(c) => c.into_ansi(), + anstyle::Color::Rgb(_) => None, + }); + let bg = style.get_bg_color().and_then(|c| match c { + anstyle::Color::Ansi(c) => Some(c), + anstyle::Color::Ansi256(c) => c.into_ansi(), + anstyle::Color::Rgb(_) => None, + }); + + stdout + .write_colored(fg, bg, format!("{:>4}", fixed).as_bytes()) + .map(|_| ()) +} + +#[derive(Default)] +struct Args { + effects: anstyle::Effects, + layer: Layer, +} + +#[derive(Copy, Clone, Default)] +enum Layer { + #[default] + Fg, + Bg, + Underline, +} + +impl Args { + fn parse() -> Result { + use lexopt::prelude::*; + + let mut res = Args::default(); + + let mut args = lexopt::Parser::from_env(); + while let Some(arg) = args.next()? { + match arg { + Long("layer") => { + res.layer = args.value()?.parse_with(|s| match s { + "fg" => Ok(Layer::Fg), + "bg" => Ok(Layer::Bg), + "underline" => Ok(Layer::Underline), + _ => Err("expected values fg, bg, underline"), + })?; + } + Long("effect") => { + const EFFECTS: [(&str, anstyle::Effects); 12] = [ + ("bold", anstyle::Effects::BOLD), + ("dimmed", anstyle::Effects::DIMMED), + ("italic", anstyle::Effects::ITALIC), + ("underline", anstyle::Effects::UNDERLINE), + ("double_underline", anstyle::Effects::UNDERLINE), + ("curly_underline", anstyle::Effects::CURLY_UNDERLINE), + ("dotted_underline", anstyle::Effects::DOTTED_UNDERLINE), + ("dashed_underline", anstyle::Effects::DASHED_UNDERLINE), + ("blink", anstyle::Effects::BLINK), + ("invert", anstyle::Effects::INVERT), + ("hidden", anstyle::Effects::HIDDEN), + ("strikethrough", anstyle::Effects::STRIKETHROUGH), + ]; + let effect = args.value()?.parse_with(|s| { + EFFECTS + .into_iter() + .find(|(name, _)| *name == s) + .map(|(_, effect)| effect) + .ok_or_else(|| { + format!( + "expected one of {}", + EFFECTS + .into_iter() + .map(|(n, _)| n) + .collect::>() + .join(", ") + ) + }) + })?; + res.effects = res.effects.insert(effect); + } + _ => return Err(arg.unexpected()), + } + } + Ok(res) + } +} diff --git a/vendor/anstyle-wincon/examples/set.rs b/vendor/anstyle-wincon/examples/set.rs new file mode 100644 index 0000000000000..6febb0ae50dd9 --- /dev/null +++ b/vendor/anstyle-wincon/examples/set.rs @@ -0,0 +1,58 @@ +#![cfg_attr(not(windows), allow(dead_code))] + +#[cfg(not(windows))] +fn main() { + panic!("unsupported"); +} + +#[cfg(windows)] +fn main() -> Result<(), lexopt::Error> { + use anstyle_wincon::WinconStream as _; + + let args = Args::parse()?; + let stdout = std::io::stdout(); + let mut stdout = stdout.lock(); + + let fg = args.fg.and_then(|c| c.into_ansi()); + let bg = args.bg.and_then(|c| c.into_ansi()); + + let _ = stdout.write_colored(fg, bg, "".as_bytes()); + + std::mem::forget(stdout); + + Ok(()) +} + +#[derive(Default)] +struct Args { + fg: Option, + bg: Option, +} + +impl Args { + fn parse() -> Result { + use lexopt::prelude::*; + + let mut res = Args::default(); + + let mut args = lexopt::Parser::from_env(); + while let Some(arg) = args.next()? { + match arg { + Long("fg") => { + res.fg = Some( + args.value()? + .parse_with(|s| s.parse::().map(anstyle::Ansi256Color))?, + ); + } + Long("bg") => { + res.fg = Some( + args.value()? + .parse_with(|s| s.parse::().map(anstyle::Ansi256Color))?, + ); + } + _ => return Err(arg.unexpected()), + } + } + Ok(res) + } +} diff --git a/vendor/anstyle/examples/dump.rs b/vendor/anstyle/examples/dump.rs new file mode 100644 index 0000000000000..1221cd6c7907c --- /dev/null +++ b/vendor/anstyle/examples/dump.rs @@ -0,0 +1,132 @@ +use std::io::Write; + +fn main() -> Result<(), lexopt::Error> { + let args = Args::parse()?; + let stdout = std::io::stdout(); + let mut stdout = stdout.lock(); + + for fixed in 0..16 { + let style = style(fixed, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + if fixed == 7 || fixed == 15 { + let _ = writeln!(&mut stdout); + } + } + + for r in 0..6 { + let _ = writeln!(stdout); + for g in 0..6 { + for b in 0..6 { + let fixed = r * 36 + g * 6 + b + 16; + let style = style(fixed, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + } + let _ = writeln!(stdout); + } + } + + for c in 0..24 { + if 0 == c % 8 { + let _ = writeln!(stdout); + } + let fixed = 232 + c; + let style = style(fixed, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + } + + Ok(()) +} + +fn style(fixed: u8, layer: Layer, effects: anstyle::Effects) -> anstyle::Style { + let color = anstyle::Ansi256Color(fixed).into(); + (match layer { + Layer::Fg => anstyle::Style::new().fg_color(Some(color)), + Layer::Bg => anstyle::Style::new().bg_color(Some(color)), + Layer::Underline => anstyle::Style::new().underline_color(Some(color)), + }) | effects +} + +fn print_number( + stdout: &mut std::io::StdoutLock<'_>, + fixed: u8, + style: anstyle::Style, +) -> std::io::Result<()> { + write!( + stdout, + "{}{:>4}{}", + style.render(), + fixed, + anstyle::Reset.render() + ) +} + +#[derive(Default)] +struct Args { + effects: anstyle::Effects, + layer: Layer, +} + +#[derive(Copy, Clone, Default)] +enum Layer { + #[default] + Fg, + Bg, + Underline, +} + +impl Args { + fn parse() -> Result { + use lexopt::prelude::*; + + let mut res = Args::default(); + + let mut args = lexopt::Parser::from_env(); + while let Some(arg) = args.next()? { + match arg { + Long("layer") => { + res.layer = args.value()?.parse_with(|s| match s { + "fg" => Ok(Layer::Fg), + "bg" => Ok(Layer::Bg), + "underline" => Ok(Layer::Underline), + _ => Err("expected values fg, bg, underline"), + })?; + } + Long("effect") => { + const EFFECTS: [(&str, anstyle::Effects); 12] = [ + ("bold", anstyle::Effects::BOLD), + ("dimmed", anstyle::Effects::DIMMED), + ("italic", anstyle::Effects::ITALIC), + ("underline", anstyle::Effects::UNDERLINE), + ("double_underline", anstyle::Effects::DOUBLE_UNDERLINE), + ("curly_underline", anstyle::Effects::CURLY_UNDERLINE), + ("dotted_underline", anstyle::Effects::DOTTED_UNDERLINE), + ("dashed_underline", anstyle::Effects::DASHED_UNDERLINE), + ("blink", anstyle::Effects::BLINK), + ("invert", anstyle::Effects::INVERT), + ("hidden", anstyle::Effects::HIDDEN), + ("strikethrough", anstyle::Effects::STRIKETHROUGH), + ]; + let effect = args.value()?.parse_with(|s| { + EFFECTS + .into_iter() + .find(|(name, _)| *name == s) + .map(|(_, effect)| effect) + .ok_or_else(|| { + format!( + "expected one of {}", + EFFECTS + .into_iter() + .map(|(n, _)| n) + .collect::>() + .join(", ") + ) + }) + })?; + res.effects = res.effects.insert(effect); + } + _ => return Err(arg.unexpected()), + } + } + Ok(res) + } +} diff --git a/vendor/async-trait/build.rs b/vendor/async-trait/build.rs new file mode 100644 index 0000000000000..db7c5f0eb3853 --- /dev/null +++ b/vendor/async-trait/build.rs @@ -0,0 +1,31 @@ +use std::env; +use std::process::Command; +use std::str; + +fn main() { + println!("cargo:rerun-if-env-changed=DOCS_RS"); + + let compiler = match rustc_minor_version() { + Some(compiler) => compiler, + None => return, + }; + + if compiler < 45 { + println!("cargo:rustc-cfg=no_span_mixed_site"); + } + + if compiler < 47 { + println!("cargo:rustc-cfg=self_span_hack"); + } +} + +fn rustc_minor_version() -> Option { + let rustc = env::var_os("RUSTC")?; + let output = Command::new(rustc).arg("--version").output().ok()?; + let version = str::from_utf8(&output.stdout).ok()?; + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + pieces.next()?.parse().ok() +} diff --git a/vendor/atomic/.cargo-checksum.json b/vendor/atomic/.cargo-checksum.json new file mode 100644 index 0000000000000..2da8be9c6f6a3 --- /dev/null +++ b/vendor/atomic/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"6ab9c72fb767e69a66cbfbac124b327c28421431342dd75a604fca26a23d59f1","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","README.md":"42102d75b38b25a8f527d32bf446d5566fb7034862b936dd027d34a14eb65554","src/fallback.rs":"46fc90b087020f3b0db2e0df98db9e2b66162c00fd148c36245634e4507dcbe7","src/lib.rs":"9b7f6a4e700faac06da4cb284e42ba395c093ad838fc663ba38a273ed023aa77","src/ops.rs":"c458b473c2d2d3895d170865fd09ef283df61824ff4249b12944ce25c92d4c61"},"package":"c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba"} \ No newline at end of file diff --git a/vendor/atomic/Cargo.toml b/vendor/atomic/Cargo.toml new file mode 100644 index 0000000000000..5152aabc4f758 --- /dev/null +++ b/vendor/atomic/Cargo.toml @@ -0,0 +1,31 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "atomic" +version = "0.5.3" +authors = ["Amanieu d'Antras "] +description = "Generic Atomic wrapper type" +documentation = "https://amanieu.github.io/atomic-rs/atomic/index.html" +readme = "README.md" +keywords = [ + "atomic", + "no_std", +] +license = "Apache-2.0/MIT" +repository = "https://github.com/Amanieu/atomic-rs" + +[features] +default = ["fallback"] +fallback = [] +nightly = [] +std = [] diff --git a/vendor/atomic/LICENSE-APACHE b/vendor/atomic/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/vendor/atomic/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/atomic/LICENSE-MIT b/vendor/atomic/LICENSE-MIT new file mode 100644 index 0000000000000..40b8817a47beb --- /dev/null +++ b/vendor/atomic/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/atomic/README.md b/vendor/atomic/README.md new file mode 100644 index 0000000000000..ea2c0cb7cc9ed --- /dev/null +++ b/vendor/atomic/README.md @@ -0,0 +1,42 @@ +Generic `Atomic` for Rust +============================ + +[![Build Status](https://travis-ci.org/Amanieu/atomic-rs.svg?branch=master)](https://travis-ci.org/Amanieu/atomic-rs) [![Crates.io](https://img.shields.io/crates/v/atomic.svg)](https://crates.io/crates/atomic) + +A Rust library which provides a generic `Atomic` type for all `T: Copy` types, unlike the standard library which only provides a few fixed atomic types (`AtomicBool`, `AtomicIsize`, `AtomicUsize`, `AtomicPtr`). + +This library will use native atomic instructions if possible, and will otherwise fall back to a lock-based mechanism. You can use the `Atomic::::is_lock_free()` function to check whether native atomic operations are supported for a given type. Note that a type must have a power-of-2 size and alignment in order to be used by native atomic instructions. + +This crate uses `#![no_std]` and only depends on libcore. + +[Documentation](https://amanieu.github.io/atomic-rs/atomic/index.html) + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +atomic = "0.5" +``` + +and this to your crate root: + +```rust +extern crate atomic; +``` + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/vendor/atomic/src/fallback.rs b/vendor/atomic/src/fallback.rs new file mode 100644 index 0000000000000..2f9f7fda42513 --- /dev/null +++ b/vendor/atomic/src/fallback.rs @@ -0,0 +1,197 @@ +// Copyright 2016 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use core::cmp; +use core::hint; +use core::mem; +use core::num::Wrapping; +use core::ops; +use core::ptr; +use core::slice; +use core::sync::atomic::{AtomicUsize, Ordering}; + +// We use an AtomicUsize instead of an AtomicBool because it performs better +// on architectures that don't have byte-sized atomics. +// +// We give each spinlock its own cache line to avoid false sharing. +#[repr(align(64))] +struct SpinLock(AtomicUsize); + +impl SpinLock { + fn lock(&self) { + while self + .0 + .compare_exchange_weak(0, 1, Ordering::Acquire, Ordering::Relaxed) + .is_err() + { + while self.0.load(Ordering::Relaxed) != 0 { + hint::spin_loop(); + } + } + } + + fn unlock(&self) { + self.0.store(0, Ordering::Release); + } +} + +// A big array of spinlocks which we use to guard atomic accesses. A spinlock is +// chosen based on a hash of the address of the atomic object, which helps to +// reduce contention compared to a single global lock. +macro_rules! array { + (@accum (0, $($_es:expr),*) -> ($($body:tt)*)) + => {array!(@as_expr [$($body)*])}; + (@accum (1, $($es:expr),*) -> ($($body:tt)*)) + => {array!(@accum (0, $($es),*) -> ($($body)* $($es,)*))}; + (@accum (2, $($es:expr),*) -> ($($body:tt)*)) + => {array!(@accum (0, $($es),*) -> ($($body)* $($es,)* $($es,)*))}; + (@accum (4, $($es:expr),*) -> ($($body:tt)*)) + => {array!(@accum (2, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (8, $($es:expr),*) -> ($($body:tt)*)) + => {array!(@accum (4, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (16, $($es:expr),*) -> ($($body:tt)*)) + => {array!(@accum (8, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (32, $($es:expr),*) -> ($($body:tt)*)) + => {array!(@accum (16, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (64, $($es:expr),*) -> ($($body:tt)*)) + => {array!(@accum (32, $($es,)* $($es),*) -> ($($body)*))}; + + (@as_expr $e:expr) => {$e}; + + [$e:expr; $n:tt] => { array!(@accum ($n, $e) -> ()) }; +} +static SPINLOCKS: [SpinLock; 64] = array![SpinLock(AtomicUsize::new(0)); 64]; + +// Spinlock pointer hashing function from compiler-rt +#[inline] +fn lock_for_addr(addr: usize) -> &'static SpinLock { + // Disregard the lowest 4 bits. We want all values that may be part of the + // same memory operation to hash to the same value and therefore use the same + // lock. + let mut hash = addr >> 4; + // Use the next bits as the basis for the hash + let low = hash & (SPINLOCKS.len() - 1); + // Now use the high(er) set of bits to perturb the hash, so that we don't + // get collisions from atomic fields in a single object + hash >>= 16; + hash ^= low; + // Return a pointer to the lock to use + &SPINLOCKS[hash & (SPINLOCKS.len() - 1)] +} + +#[inline] +fn lock(addr: usize) -> LockGuard { + let lock = lock_for_addr(addr); + lock.lock(); + LockGuard(lock) +} + +struct LockGuard(&'static SpinLock); +impl Drop for LockGuard { + #[inline] + fn drop(&mut self) { + self.0.unlock(); + } +} + +#[inline] +pub unsafe fn atomic_load(dst: *mut T) -> T { + let _l = lock(dst as usize); + ptr::read(dst) +} + +#[inline] +pub unsafe fn atomic_store(dst: *mut T, val: T) { + let _l = lock(dst as usize); + ptr::write(dst, val); +} + +#[inline] +pub unsafe fn atomic_swap(dst: *mut T, val: T) -> T { + let _l = lock(dst as usize); + ptr::replace(dst, val) +} + +#[inline] +pub unsafe fn atomic_compare_exchange(dst: *mut T, current: T, new: T) -> Result { + let _l = lock(dst as usize); + let result = ptr::read(dst); + // compare_exchange compares with memcmp instead of Eq + let a = slice::from_raw_parts(&result as *const _ as *const u8, mem::size_of_val(&result)); + let b = slice::from_raw_parts( + ¤t as *const _ as *const u8, + mem::size_of_val(¤t), + ); + if a == b { + ptr::write(dst, new); + Ok(result) + } else { + Err(result) + } +} + +#[inline] +pub unsafe fn atomic_add(dst: *mut T, val: T) -> T +where + Wrapping: ops::Add>, +{ + let _l = lock(dst as usize); + let result = ptr::read(dst); + ptr::write(dst, (Wrapping(result) + Wrapping(val)).0); + result +} + +#[inline] +pub unsafe fn atomic_sub(dst: *mut T, val: T) -> T +where + Wrapping: ops::Sub>, +{ + let _l = lock(dst as usize); + let result = ptr::read(dst); + ptr::write(dst, (Wrapping(result) - Wrapping(val)).0); + result +} + +#[inline] +pub unsafe fn atomic_and>(dst: *mut T, val: T) -> T { + let _l = lock(dst as usize); + let result = ptr::read(dst); + ptr::write(dst, result & val); + result +} + +#[inline] +pub unsafe fn atomic_or>(dst: *mut T, val: T) -> T { + let _l = lock(dst as usize); + let result = ptr::read(dst); + ptr::write(dst, result | val); + result +} + +#[inline] +pub unsafe fn atomic_xor>(dst: *mut T, val: T) -> T { + let _l = lock(dst as usize); + let result = ptr::read(dst); + ptr::write(dst, result ^ val); + result +} + +#[inline] +pub unsafe fn atomic_min(dst: *mut T, val: T) -> T { + let _l = lock(dst as usize); + let result = ptr::read(dst); + ptr::write(dst, cmp::min(result, val)); + result +} + +#[inline] +pub unsafe fn atomic_max(dst: *mut T, val: T) -> T { + let _l = lock(dst as usize); + let result = ptr::read(dst); + ptr::write(dst, cmp::max(result, val)); + result +} diff --git a/vendor/atomic/src/lib.rs b/vendor/atomic/src/lib.rs new file mode 100644 index 0000000000000..1f89ca62ae383 --- /dev/null +++ b/vendor/atomic/src/lib.rs @@ -0,0 +1,745 @@ +// Copyright 2016 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +//! Generic `Atomic` wrapper type +//! +//! Atomic types provide primitive shared-memory communication between +//! threads, and are the building blocks of other concurrent types. +//! +//! This library defines a generic atomic wrapper type `Atomic` for all +//! `T: Copy` types. +//! Atomic types present operations that, when used correctly, synchronize +//! updates between threads. +//! +//! Each method takes an `Ordering` which represents the strength of +//! the memory barrier for that operation. These orderings are the +//! same as [LLVM atomic orderings][1]. +//! +//! [1]: http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations +//! +//! Atomic variables are safe to share between threads (they implement `Sync`) +//! but they do not themselves provide the mechanism for sharing. The most +//! common way to share an atomic variable is to put it into an `Arc` (an +//! atomically-reference-counted shared pointer). +//! +//! Most atomic types may be stored in static variables, initialized using +//! the `const fn` constructors. Atomic statics are often used for lazy global +//! initialization. + +#![warn(missing_docs)] +#![warn(rust_2018_idioms)] +#![no_std] +#![cfg_attr(feature = "nightly", feature(integer_atomics))] + +#[cfg(any(test, feature = "std"))] +#[macro_use] +extern crate std; + +use core::mem::MaybeUninit; +// Re-export some useful definitions from libcore +pub use core::sync::atomic::{fence, Ordering}; + +use core::cell::UnsafeCell; +use core::fmt; + +#[cfg(feature = "std")] +use std::panic::RefUnwindSafe; + +#[cfg(feature = "fallback")] +mod fallback; +mod ops; + +/// A generic atomic wrapper type which allows an object to be safely shared +/// between threads. +#[repr(transparent)] +pub struct Atomic { + // The MaybeUninit is here to work around rust-lang/rust#87341. + v: UnsafeCell>, +} + +// Atomic is only Sync if T is Send +unsafe impl Sync for Atomic {} + +// Given that atomicity is guaranteed, Atomic is RefUnwindSafe if T is +// +// This is trivially correct for native lock-free atomic types. For those whose +// atomicity is emulated using a spinlock, it is still correct because the +// `Atomic` API does not allow doing any panic-inducing operation after writing +// to the target object. +#[cfg(feature = "std")] +impl RefUnwindSafe for Atomic {} + +impl Default for Atomic { + #[inline] + fn default() -> Self { + Self::new(Default::default()) + } +} + +impl fmt::Debug for Atomic { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Atomic") + .field(&self.load(Ordering::SeqCst)) + .finish() + } +} + +impl Atomic { + /// Creates a new `Atomic`. + #[inline] + pub const fn new(v: T) -> Atomic { + Atomic { + v: UnsafeCell::new(MaybeUninit::new(v)), + } + } + + /// Checks if `Atomic` objects of this type are lock-free. + /// + /// If an `Atomic` is not lock-free then it may be implemented using locks + /// internally, which makes it unsuitable for some situations (such as + /// communicating with a signal handler). + #[inline] + pub const fn is_lock_free() -> bool { + ops::atomic_is_lock_free::() + } +} + +impl Atomic { + #[inline] + fn inner_ptr(&self) -> *mut T { + self.v.get() as *mut T + } + + /// Returns a mutable reference to the underlying type. + /// + /// This is safe because the mutable reference guarantees that no other threads are + /// concurrently accessing the atomic data. + #[inline] + pub fn get_mut(&mut self) -> &mut T { + unsafe { &mut *self.inner_ptr() } + } + + /// Consumes the atomic and returns the contained value. + /// + /// This is safe because passing `self` by value guarantees that no other threads are + /// concurrently accessing the atomic data. + #[inline] + pub fn into_inner(self) -> T { + unsafe { self.v.into_inner().assume_init() } + } + + /// Loads a value from the `Atomic`. + /// + /// `load` takes an `Ordering` argument which describes the memory ordering + /// of this operation. + /// + /// # Panics + /// + /// Panics if `order` is `Release` or `AcqRel`. + #[inline] + pub fn load(&self, order: Ordering) -> T { + unsafe { ops::atomic_load(self.inner_ptr(), order) } + } + + /// Stores a value into the `Atomic`. + /// + /// `store` takes an `Ordering` argument which describes the memory ordering + /// of this operation. + /// + /// # Panics + /// + /// Panics if `order` is `Acquire` or `AcqRel`. + #[inline] + pub fn store(&self, val: T, order: Ordering) { + unsafe { + ops::atomic_store(self.inner_ptr(), val, order); + } + } + + /// Stores a value into the `Atomic`, returning the old value. + /// + /// `swap` takes an `Ordering` argument which describes the memory ordering + /// of this operation. + #[inline] + pub fn swap(&self, val: T, order: Ordering) -> T { + unsafe { ops::atomic_swap(self.inner_ptr(), val, order) } + } + + /// Stores a value into the `Atomic` if the current value is the same as the + /// `current` value. + /// + /// The return value is a result indicating whether the new value was + /// written and containing the previous value. On success this value is + /// guaranteed to be equal to `new`. + /// + /// `compare_exchange` takes two `Ordering` arguments to describe the memory + /// ordering of this operation. The first describes the required ordering if + /// the operation succeeds while the second describes the required ordering + /// when the operation fails. The failure ordering can't be `Release` or + /// `AcqRel` and must be equivalent or weaker than the success ordering. + #[inline] + pub fn compare_exchange( + &self, + current: T, + new: T, + success: Ordering, + failure: Ordering, + ) -> Result { + unsafe { ops::atomic_compare_exchange(self.inner_ptr(), current, new, success, failure) } + } + + /// Stores a value into the `Atomic` if the current value is the same as the + /// `current` value. + /// + /// Unlike `compare_exchange`, this function is allowed to spuriously fail + /// even when the comparison succeeds, which can result in more efficient + /// code on some platforms. The return value is a result indicating whether + /// the new value was written and containing the previous value. + /// + /// `compare_exchange` takes two `Ordering` arguments to describe the memory + /// ordering of this operation. The first describes the required ordering if + /// the operation succeeds while the second describes the required ordering + /// when the operation fails. The failure ordering can't be `Release` or + /// `AcqRel` and must be equivalent or weaker than the success ordering. + /// success ordering. + #[inline] + pub fn compare_exchange_weak( + &self, + current: T, + new: T, + success: Ordering, + failure: Ordering, + ) -> Result { + unsafe { + ops::atomic_compare_exchange_weak(self.inner_ptr(), current, new, success, failure) + } + } + + /// Fetches the value, and applies a function to it that returns an optional + /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else + /// `Err(previous_value)`. + /// + /// Note: This may call the function multiple times if the value has been changed from other threads in + /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied + /// only once to the stored value. + /// + /// `fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation. + /// The first describes the required ordering for when the operation finally succeeds while the second + /// describes the required ordering for loads. These correspond to the success and failure orderings of + /// [`compare_exchange`] respectively. + /// + /// Using [`Acquire`] as success ordering makes the store part + /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load + /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] + /// and must be equivalent to or weaker than the success ordering. + /// + /// [`compare_exchange`]: #method.compare_exchange + /// [`Ordering`]: enum.Ordering.html + /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed + /// [`Release`]: enum.Ordering.html#variant.Release + /// [`Acquire`]: enum.Ordering.html#variant.Acquire + /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst + /// + /// # Examples + /// + /// ```rust + /// use atomic::{Atomic, Ordering}; + /// + /// let x = Atomic::new(7); + /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7)); + /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7)); + /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8)); + /// assert_eq!(x.load(Ordering::SeqCst), 9); + /// ``` + #[inline] + pub fn fetch_update( + &self, + set_order: Ordering, + fetch_order: Ordering, + mut f: F, + ) -> Result + where + F: FnMut(T) -> Option, + { + let mut prev = self.load(fetch_order); + while let Some(next) = f(prev) { + match self.compare_exchange_weak(prev, next, set_order, fetch_order) { + x @ Ok(_) => return x, + Err(next_prev) => prev = next_prev, + } + } + Err(prev) + } +} + +impl Atomic { + /// Logical "and" with a boolean value. + /// + /// Performs a logical "and" operation on the current value and the argument + /// `val`, and sets the new value to the result. + /// + /// Returns the previous value. + #[inline] + pub fn fetch_and(&self, val: bool, order: Ordering) -> bool { + unsafe { ops::atomic_and(self.inner_ptr(), val, order) } + } + + /// Logical "or" with a boolean value. + /// + /// Performs a logical "or" operation on the current value and the argument + /// `val`, and sets the new value to the result. + /// + /// Returns the previous value. + #[inline] + pub fn fetch_or(&self, val: bool, order: Ordering) -> bool { + unsafe { ops::atomic_or(self.inner_ptr(), val, order) } + } + + /// Logical "xor" with a boolean value. + /// + /// Performs a logical "xor" operation on the current value and the argument + /// `val`, and sets the new value to the result. + /// + /// Returns the previous value. + #[inline] + pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool { + unsafe { ops::atomic_xor(self.inner_ptr(), val, order) } + } +} + +macro_rules! atomic_ops_common { + ($($t:ty)*) => ($( + impl Atomic<$t> { + /// Add to the current value, returning the previous value. + #[inline] + pub fn fetch_add(&self, val: $t, order: Ordering) -> $t { + unsafe { ops::atomic_add(self.inner_ptr(), val, order) } + } + + /// Subtract from the current value, returning the previous value. + #[inline] + pub fn fetch_sub(&self, val: $t, order: Ordering) -> $t { + unsafe { ops::atomic_sub(self.inner_ptr(), val, order) } + } + + /// Bitwise and with the current value, returning the previous value. + #[inline] + pub fn fetch_and(&self, val: $t, order: Ordering) -> $t { + unsafe { ops::atomic_and(self.inner_ptr(), val, order) } + } + + /// Bitwise or with the current value, returning the previous value. + #[inline] + pub fn fetch_or(&self, val: $t, order: Ordering) -> $t { + unsafe { ops::atomic_or(self.inner_ptr(), val, order) } + } + + /// Bitwise xor with the current value, returning the previous value. + #[inline] + pub fn fetch_xor(&self, val: $t, order: Ordering) -> $t { + unsafe { ops::atomic_xor(self.inner_ptr(), val, order) } + } + } + )*); +} +macro_rules! atomic_ops_signed { + ($($t:ty)*) => ( + atomic_ops_common!{ $($t)* } + $( + impl Atomic<$t> { + /// Minimum with the current value. + #[inline] + pub fn fetch_min(&self, val: $t, order: Ordering) -> $t { + unsafe { ops::atomic_min(self.inner_ptr(), val, order) } + } + + /// Maximum with the current value. + #[inline] + pub fn fetch_max(&self, val: $t, order: Ordering) -> $t { + unsafe { ops::atomic_max(self.inner_ptr(), val, order) } + } + } + )* + ); +} +macro_rules! atomic_ops_unsigned { + ($($t:ty)*) => ( + atomic_ops_common!{ $($t)* } + $( + impl Atomic<$t> { + /// Minimum with the current value. + #[inline] + pub fn fetch_min(&self, val: $t, order: Ordering) -> $t { + unsafe { ops::atomic_umin(self.inner_ptr(), val, order) } + } + + /// Maximum with the current value. + #[inline] + pub fn fetch_max(&self, val: $t, order: Ordering) -> $t { + unsafe { ops::atomic_umax(self.inner_ptr(), val, order) } + } + } + )* + ); +} +atomic_ops_signed! { i8 i16 i32 i64 isize i128 } +atomic_ops_unsigned! { u8 u16 u32 u64 usize u128 } + +#[cfg(test)] +mod tests { + use super::{Atomic, Ordering::*}; + use core::mem; + + #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)] + struct Foo(u8, u8); + #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)] + struct Bar(u64, u64); + #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)] + struct Quux(u32); + + #[test] + fn atomic_bool() { + let a = Atomic::new(false); + assert_eq!( + Atomic::::is_lock_free(), + cfg!(target_has_atomic = "8"), + ); + assert_eq!(format!("{:?}", a), "Atomic(false)"); + assert_eq!(a.load(SeqCst), false); + a.store(true, SeqCst); + assert_eq!(a.swap(false, SeqCst), true); + assert_eq!(a.compare_exchange(true, false, SeqCst, SeqCst), Err(false)); + assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false)); + assert_eq!(a.fetch_and(false, SeqCst), true); + assert_eq!(a.fetch_or(true, SeqCst), false); + assert_eq!(a.fetch_xor(false, SeqCst), true); + assert_eq!(a.load(SeqCst), true); + } + + #[test] + fn atomic_i8() { + let a = Atomic::new(0i8); + assert_eq!(Atomic::::is_lock_free(), cfg!(target_has_atomic = "8")); + assert_eq!(format!("{:?}", a), "Atomic(0)"); + assert_eq!(a.load(SeqCst), 0); + a.store(1, SeqCst); + assert_eq!(a.swap(2, SeqCst), 1); + assert_eq!(a.compare_exchange(5, 45, SeqCst, SeqCst), Err(2)); + assert_eq!(a.compare_exchange(2, 3, SeqCst, SeqCst), Ok(2)); + assert_eq!(a.fetch_add(123, SeqCst), 3); + // Make sure overflows are handled correctly + assert_eq!(a.fetch_sub(-56, SeqCst), 126); + assert_eq!(a.fetch_and(7, SeqCst), -74); + assert_eq!(a.fetch_or(64, SeqCst), 6); + assert_eq!(a.fetch_xor(1, SeqCst), 70); + assert_eq!(a.fetch_min(30, SeqCst), 71); + assert_eq!(a.fetch_max(-25, SeqCst), 30); + assert_eq!(a.load(SeqCst), 30); + } + + #[test] + fn atomic_i16() { + let a = Atomic::new(0i16); + assert_eq!( + Atomic::::is_lock_free(), + cfg!(target_has_atomic = "16") + ); + assert_eq!(format!("{:?}", a), "Atomic(0)"); + assert_eq!(a.load(SeqCst), 0); + a.store(1, SeqCst); + assert_eq!(a.swap(2, SeqCst), 1); + assert_eq!(a.compare_exchange(5, 45, SeqCst, SeqCst), Err(2)); + assert_eq!(a.compare_exchange(2, 3, SeqCst, SeqCst), Ok(2)); + assert_eq!(a.fetch_add(123, SeqCst), 3); + assert_eq!(a.fetch_sub(-56, SeqCst), 126); + assert_eq!(a.fetch_and(7, SeqCst), 182); + assert_eq!(a.fetch_or(64, SeqCst), 6); + assert_eq!(a.fetch_xor(1, SeqCst), 70); + assert_eq!(a.fetch_min(30, SeqCst), 71); + assert_eq!(a.fetch_max(-25, SeqCst), 30); + assert_eq!(a.load(SeqCst), 30); + } + + #[test] + fn atomic_i32() { + let a = Atomic::new(0i32); + assert_eq!( + Atomic::::is_lock_free(), + cfg!(target_has_atomic = "32") + ); + assert_eq!(format!("{:?}", a), "Atomic(0)"); + assert_eq!(a.load(SeqCst), 0); + a.store(1, SeqCst); + assert_eq!(a.swap(2, SeqCst), 1); + assert_eq!(a.compare_exchange(5, 45, SeqCst, SeqCst), Err(2)); + assert_eq!(a.compare_exchange(2, 3, SeqCst, SeqCst), Ok(2)); + assert_eq!(a.fetch_add(123, SeqCst), 3); + assert_eq!(a.fetch_sub(-56, SeqCst), 126); + assert_eq!(a.fetch_and(7, SeqCst), 182); + assert_eq!(a.fetch_or(64, SeqCst), 6); + assert_eq!(a.fetch_xor(1, SeqCst), 70); + assert_eq!(a.fetch_min(30, SeqCst), 71); + assert_eq!(a.fetch_max(-25, SeqCst), 30); + assert_eq!(a.load(SeqCst), 30); + } + + #[test] + fn atomic_i64() { + let a = Atomic::new(0i64); + assert_eq!( + Atomic::::is_lock_free(), + cfg!(target_has_atomic = "64") && mem::align_of::() == 8 + ); + assert_eq!(format!("{:?}", a), "Atomic(0)"); + assert_eq!(a.load(SeqCst), 0); + a.store(1, SeqCst); + assert_eq!(a.swap(2, SeqCst), 1); + assert_eq!(a.compare_exchange(5, 45, SeqCst, SeqCst), Err(2)); + assert_eq!(a.compare_exchange(2, 3, SeqCst, SeqCst), Ok(2)); + assert_eq!(a.fetch_add(123, SeqCst), 3); + assert_eq!(a.fetch_sub(-56, SeqCst), 126); + assert_eq!(a.fetch_and(7, SeqCst), 182); + assert_eq!(a.fetch_or(64, SeqCst), 6); + assert_eq!(a.fetch_xor(1, SeqCst), 70); + assert_eq!(a.fetch_min(30, SeqCst), 71); + assert_eq!(a.fetch_max(-25, SeqCst), 30); + assert_eq!(a.load(SeqCst), 30); + } + + #[test] + fn atomic_i128() { + let a = Atomic::new(0i128); + assert_eq!( + Atomic::::is_lock_free(), + cfg!(feature = "nightly") & cfg!(target_has_atomic = "128") + ); + assert_eq!(format!("{:?}", a), "Atomic(0)"); + assert_eq!(a.load(SeqCst), 0); + a.store(1, SeqCst); + assert_eq!(a.swap(2, SeqCst), 1); + assert_eq!(a.compare_exchange(5, 45, SeqCst, SeqCst), Err(2)); + assert_eq!(a.compare_exchange(2, 3, SeqCst, SeqCst), Ok(2)); + assert_eq!(a.fetch_add(123, SeqCst), 3); + assert_eq!(a.fetch_sub(-56, SeqCst), 126); + assert_eq!(a.fetch_and(7, SeqCst), 182); + assert_eq!(a.fetch_or(64, SeqCst), 6); + assert_eq!(a.fetch_xor(1, SeqCst), 70); + assert_eq!(a.fetch_min(30, SeqCst), 71); + assert_eq!(a.fetch_max(-25, SeqCst), 30); + assert_eq!(a.load(SeqCst), 30); + } + + #[test] + fn atomic_isize() { + let a = Atomic::new(0isize); + assert_eq!(format!("{:?}", a), "Atomic(0)"); + assert_eq!(a.load(SeqCst), 0); + a.store(1, SeqCst); + assert_eq!(a.swap(2, SeqCst), 1); + assert_eq!(a.compare_exchange(5, 45, SeqCst, SeqCst), Err(2)); + assert_eq!(a.compare_exchange(2, 3, SeqCst, SeqCst), Ok(2)); + assert_eq!(a.fetch_add(123, SeqCst), 3); + assert_eq!(a.fetch_sub(-56, SeqCst), 126); + assert_eq!(a.fetch_and(7, SeqCst), 182); + assert_eq!(a.fetch_or(64, SeqCst), 6); + assert_eq!(a.fetch_xor(1, SeqCst), 70); + assert_eq!(a.fetch_min(30, SeqCst), 71); + assert_eq!(a.fetch_max(-25, SeqCst), 30); + assert_eq!(a.load(SeqCst), 30); + } + + #[test] + fn atomic_u8() { + let a = Atomic::new(0u8); + assert_eq!(Atomic::::is_lock_free(), cfg!(target_has_atomic = "8")); + assert_eq!(format!("{:?}", a), "Atomic(0)"); + assert_eq!(a.load(SeqCst), 0); + a.store(1, SeqCst); + assert_eq!(a.swap(2, SeqCst), 1); + assert_eq!(a.compare_exchange(5, 45, SeqCst, SeqCst), Err(2)); + assert_eq!(a.compare_exchange(2, 3, SeqCst, SeqCst), Ok(2)); + assert_eq!(a.fetch_add(123, SeqCst), 3); + assert_eq!(a.fetch_sub(56, SeqCst), 126); + assert_eq!(a.fetch_and(7, SeqCst), 70); + assert_eq!(a.fetch_or(64, SeqCst), 6); + assert_eq!(a.fetch_xor(1, SeqCst), 70); + assert_eq!(a.fetch_min(30, SeqCst), 71); + assert_eq!(a.fetch_max(25, SeqCst), 30); + assert_eq!(a.load(SeqCst), 30); + } + + #[test] + fn atomic_u16() { + let a = Atomic::new(0u16); + assert_eq!( + Atomic::::is_lock_free(), + cfg!(target_has_atomic = "16") + ); + assert_eq!(format!("{:?}", a), "Atomic(0)"); + assert_eq!(a.load(SeqCst), 0); + a.store(1, SeqCst); + assert_eq!(a.swap(2, SeqCst), 1); + assert_eq!(a.compare_exchange(5, 45, SeqCst, SeqCst), Err(2)); + assert_eq!(a.compare_exchange(2, 3, SeqCst, SeqCst), Ok(2)); + assert_eq!(a.fetch_add(123, SeqCst), 3); + assert_eq!(a.fetch_sub(56, SeqCst), 126); + assert_eq!(a.fetch_and(7, SeqCst), 70); + assert_eq!(a.fetch_or(64, SeqCst), 6); + assert_eq!(a.fetch_xor(1, SeqCst), 70); + assert_eq!(a.fetch_min(30, SeqCst), 71); + assert_eq!(a.fetch_max(25, SeqCst), 30); + assert_eq!(a.load(SeqCst), 30); + } + + #[test] + fn atomic_u32() { + let a = Atomic::new(0u32); + assert_eq!( + Atomic::::is_lock_free(), + cfg!(target_has_atomic = "32") + ); + assert_eq!(format!("{:?}", a), "Atomic(0)"); + assert_eq!(a.load(SeqCst), 0); + a.store(1, SeqCst); + assert_eq!(a.swap(2, SeqCst), 1); + assert_eq!(a.compare_exchange(5, 45, SeqCst, SeqCst), Err(2)); + assert_eq!(a.compare_exchange(2, 3, SeqCst, SeqCst), Ok(2)); + assert_eq!(a.fetch_add(123, SeqCst), 3); + assert_eq!(a.fetch_sub(56, SeqCst), 126); + assert_eq!(a.fetch_and(7, SeqCst), 70); + assert_eq!(a.fetch_or(64, SeqCst), 6); + assert_eq!(a.fetch_xor(1, SeqCst), 70); + assert_eq!(a.fetch_min(30, SeqCst), 71); + assert_eq!(a.fetch_max(25, SeqCst), 30); + assert_eq!(a.load(SeqCst), 30); + } + + #[test] + fn atomic_u64() { + let a = Atomic::new(0u64); + assert_eq!( + Atomic::::is_lock_free(), + cfg!(target_has_atomic = "64") && mem::align_of::() == 8 + ); + assert_eq!(format!("{:?}", a), "Atomic(0)"); + assert_eq!(a.load(SeqCst), 0); + a.store(1, SeqCst); + assert_eq!(a.swap(2, SeqCst), 1); + assert_eq!(a.compare_exchange(5, 45, SeqCst, SeqCst), Err(2)); + assert_eq!(a.compare_exchange(2, 3, SeqCst, SeqCst), Ok(2)); + assert_eq!(a.fetch_add(123, SeqCst), 3); + assert_eq!(a.fetch_sub(56, SeqCst), 126); + assert_eq!(a.fetch_and(7, SeqCst), 70); + assert_eq!(a.fetch_or(64, SeqCst), 6); + assert_eq!(a.fetch_xor(1, SeqCst), 70); + assert_eq!(a.fetch_min(30, SeqCst), 71); + assert_eq!(a.fetch_max(25, SeqCst), 30); + assert_eq!(a.load(SeqCst), 30); + } + + #[test] + fn atomic_u128() { + let a = Atomic::new(0u128); + assert_eq!( + Atomic::::is_lock_free(), + cfg!(feature = "nightly") & cfg!(target_has_atomic = "128") + ); + assert_eq!(format!("{:?}", a), "Atomic(0)"); + assert_eq!(a.load(SeqCst), 0); + a.store(1, SeqCst); + assert_eq!(a.swap(2, SeqCst), 1); + assert_eq!(a.compare_exchange(5, 45, SeqCst, SeqCst), Err(2)); + assert_eq!(a.compare_exchange(2, 3, SeqCst, SeqCst), Ok(2)); + assert_eq!(a.fetch_add(123, SeqCst), 3); + assert_eq!(a.fetch_sub(56, SeqCst), 126); + assert_eq!(a.fetch_and(7, SeqCst), 70); + assert_eq!(a.fetch_or(64, SeqCst), 6); + assert_eq!(a.fetch_xor(1, SeqCst), 70); + assert_eq!(a.fetch_min(30, SeqCst), 71); + assert_eq!(a.fetch_max(25, SeqCst), 30); + assert_eq!(a.load(SeqCst), 30); + } + + #[test] + fn atomic_usize() { + let a = Atomic::new(0usize); + assert_eq!(format!("{:?}", a), "Atomic(0)"); + assert_eq!(a.load(SeqCst), 0); + a.store(1, SeqCst); + assert_eq!(a.swap(2, SeqCst), 1); + assert_eq!(a.compare_exchange(5, 45, SeqCst, SeqCst), Err(2)); + assert_eq!(a.compare_exchange(2, 3, SeqCst, SeqCst), Ok(2)); + assert_eq!(a.fetch_add(123, SeqCst), 3); + assert_eq!(a.fetch_sub(56, SeqCst), 126); + assert_eq!(a.fetch_and(7, SeqCst), 70); + assert_eq!(a.fetch_or(64, SeqCst), 6); + assert_eq!(a.fetch_xor(1, SeqCst), 70); + assert_eq!(a.fetch_min(30, SeqCst), 71); + assert_eq!(a.fetch_max(25, SeqCst), 30); + assert_eq!(a.load(SeqCst), 30); + } + + #[test] + fn atomic_foo() { + let a = Atomic::default(); + assert_eq!(Atomic::::is_lock_free(), false); + assert_eq!(format!("{:?}", a), "Atomic(Foo(0, 0))"); + assert_eq!(a.load(SeqCst), Foo(0, 0)); + a.store(Foo(1, 1), SeqCst); + assert_eq!(a.swap(Foo(2, 2), SeqCst), Foo(1, 1)); + assert_eq!( + a.compare_exchange(Foo(5, 5), Foo(45, 45), SeqCst, SeqCst), + Err(Foo(2, 2)) + ); + assert_eq!( + a.compare_exchange(Foo(2, 2), Foo(3, 3), SeqCst, SeqCst), + Ok(Foo(2, 2)) + ); + assert_eq!(a.load(SeqCst), Foo(3, 3)); + } + + #[test] + fn atomic_bar() { + let a = Atomic::default(); + assert_eq!(Atomic::::is_lock_free(), false); + assert_eq!(format!("{:?}", a), "Atomic(Bar(0, 0))"); + assert_eq!(a.load(SeqCst), Bar(0, 0)); + a.store(Bar(1, 1), SeqCst); + assert_eq!(a.swap(Bar(2, 2), SeqCst), Bar(1, 1)); + assert_eq!( + a.compare_exchange(Bar(5, 5), Bar(45, 45), SeqCst, SeqCst), + Err(Bar(2, 2)) + ); + assert_eq!( + a.compare_exchange(Bar(2, 2), Bar(3, 3), SeqCst, SeqCst), + Ok(Bar(2, 2)) + ); + assert_eq!(a.load(SeqCst), Bar(3, 3)); + } + + #[test] + fn atomic_quxx() { + let a = Atomic::default(); + assert_eq!( + Atomic::::is_lock_free(), + cfg!(target_has_atomic = "32") + ); + assert_eq!(format!("{:?}", a), "Atomic(Quux(0))"); + assert_eq!(a.load(SeqCst), Quux(0)); + a.store(Quux(1), SeqCst); + assert_eq!(a.swap(Quux(2), SeqCst), Quux(1)); + assert_eq!( + a.compare_exchange(Quux(5), Quux(45), SeqCst, SeqCst), + Err(Quux(2)) + ); + assert_eq!( + a.compare_exchange(Quux(2), Quux(3), SeqCst, SeqCst), + Ok(Quux(2)) + ); + assert_eq!(a.load(SeqCst), Quux(3)); + } +} diff --git a/vendor/atomic/src/ops.rs b/vendor/atomic/src/ops.rs new file mode 100644 index 0000000000000..5deb710009b8f --- /dev/null +++ b/vendor/atomic/src/ops.rs @@ -0,0 +1,299 @@ +// Copyright 2016 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +#[cfg(feature = "fallback")] +use crate::fallback; +use core::cmp; +use core::mem; +use core::num::Wrapping; +use core::ops; +use core::sync::atomic::Ordering; + +macro_rules! match_atomic { + ($type:ident, $atomic:ident, $impl:expr, $fallback_impl:expr) => { + match mem::size_of::<$type>() { + #[cfg(target_has_atomic = "8")] + 1 if mem::align_of::<$type>() >= 1 => { + type $atomic = core::sync::atomic::AtomicU8; + + $impl + } + #[cfg(target_has_atomic = "16")] + 2 if mem::align_of::<$type>() >= 2 => { + type $atomic = core::sync::atomic::AtomicU16; + + $impl + } + #[cfg(target_has_atomic = "32")] + 4 if mem::align_of::<$type>() >= 4 => { + type $atomic = core::sync::atomic::AtomicU32; + + $impl + } + #[cfg(target_has_atomic = "64")] + 8 if mem::align_of::<$type>() >= 8 => { + type $atomic = core::sync::atomic::AtomicU64; + + $impl + } + #[cfg(all(feature = "nightly", target_has_atomic = "128"))] + 16 if mem::align_of::<$type>() >= 16 => { + type $atomic = core::sync::atomic::AtomicU128; + + $impl + } + #[cfg(feature = "fallback")] + _ => $fallback_impl, + #[cfg(not(feature = "fallback"))] + _ => panic!("Atomic operations for type `{}` are not available as the `fallback` feature of the `atomic` crate is disabled.", core::any::type_name::<$type>()), + } + }; +} + +macro_rules! match_signed_atomic { + ($type:ident, $atomic:ident, $impl:expr, $fallback_impl:expr) => { + match mem::size_of::<$type>() { + #[cfg(target_has_atomic = "8")] + 1 if mem::align_of::<$type>() >= 1 => { + type $atomic = core::sync::atomic::AtomicI8; + + $impl + } + #[cfg(target_has_atomic = "16")] + 2 if mem::align_of::<$type>() >= 2 => { + type $atomic = core::sync::atomic::AtomicI16; + + $impl + } + #[cfg(target_has_atomic = "32")] + 4 if mem::align_of::<$type>() >= 4 => { + type $atomic = core::sync::atomic::AtomicI32; + + $impl + } + #[cfg(target_has_atomic = "64")] + 8 if mem::align_of::<$type>() >= 8 => { + type $atomic = core::sync::atomic::AtomicI64; + + $impl + } + #[cfg(all(feature = "nightly", target_has_atomic = "128"))] + 16 if mem::align_of::<$type>() >= 16 => { + type $atomic = core::sync::atomic::AtomicI128; + + $impl + } + #[cfg(feature = "fallback")] + _ => $fallback_impl, + #[cfg(not(feature = "fallback"))] + _ => panic!("Atomic operations for type `{}` are not available as the `fallback` feature of the `atomic` crate is disabled.", core::any::type_name::<$type>()), + } + }; +} + +#[inline] +pub const fn atomic_is_lock_free() -> bool { + let size = mem::size_of::(); + let align = mem::align_of::(); + + (cfg!(target_has_atomic = "8") & (size == 1) & (align >= 1)) + | (cfg!(target_has_atomic = "16") & (size == 2) & (align >= 2)) + | (cfg!(target_has_atomic = "32") & (size == 4) & (align >= 4)) + | (cfg!(target_has_atomic = "64") & (size == 8) & (align >= 8)) + | (cfg!(feature = "nightly") + & cfg!(target_has_atomic = "128") + & (size == 16) + & (align >= 16)) +} + +#[inline] +pub unsafe fn atomic_load(dst: *mut T, order: Ordering) -> T { + match_atomic!( + T, + A, + mem::transmute_copy(&(*(dst as *const A)).load(order)), + fallback::atomic_load(dst) + ) +} + +#[inline] +pub unsafe fn atomic_store(dst: *mut T, val: T, order: Ordering) { + match_atomic!( + T, + A, + (*(dst as *const A)).store(mem::transmute_copy(&val), order), + fallback::atomic_store(dst, val) + ) +} + +#[inline] +pub unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { + match_atomic!( + T, + A, + mem::transmute_copy(&(*(dst as *const A)).swap(mem::transmute_copy(&val), order)), + fallback::atomic_swap(dst, val) + ) +} + +#[inline] +unsafe fn map_result(r: Result) -> Result { + match r { + Ok(x) => Ok(mem::transmute_copy(&x)), + Err(x) => Err(mem::transmute_copy(&x)), + } +} + +#[inline] +pub unsafe fn atomic_compare_exchange( + dst: *mut T, + current: T, + new: T, + success: Ordering, + failure: Ordering, +) -> Result { + match_atomic!( + T, + A, + map_result((*(dst as *const A)).compare_exchange( + mem::transmute_copy(¤t), + mem::transmute_copy(&new), + success, + failure, + )), + fallback::atomic_compare_exchange(dst, current, new) + ) +} + +#[inline] +pub unsafe fn atomic_compare_exchange_weak( + dst: *mut T, + current: T, + new: T, + success: Ordering, + failure: Ordering, +) -> Result { + match_atomic!( + T, + A, + map_result((*(dst as *const A)).compare_exchange_weak( + mem::transmute_copy(¤t), + mem::transmute_copy(&new), + success, + failure, + )), + fallback::atomic_compare_exchange(dst, current, new) + ) +} + +#[inline] +pub unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T +where + Wrapping: ops::Add>, +{ + match_atomic!( + T, + A, + mem::transmute_copy(&(*(dst as *const A)).fetch_add(mem::transmute_copy(&val), order),), + fallback::atomic_add(dst, val) + ) +} + +#[inline] +pub unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T +where + Wrapping: ops::Sub>, +{ + match_atomic!( + T, + A, + mem::transmute_copy(&(*(dst as *const A)).fetch_sub(mem::transmute_copy(&val), order),), + fallback::atomic_sub(dst, val) + ) +} + +#[inline] +pub unsafe fn atomic_and>( + dst: *mut T, + val: T, + order: Ordering, +) -> T { + match_atomic!( + T, + A, + mem::transmute_copy(&(*(dst as *const A)).fetch_and(mem::transmute_copy(&val), order),), + fallback::atomic_and(dst, val) + ) +} + +#[inline] +pub unsafe fn atomic_or>( + dst: *mut T, + val: T, + order: Ordering, +) -> T { + match_atomic!( + T, + A, + mem::transmute_copy(&(*(dst as *const A)).fetch_or(mem::transmute_copy(&val), order),), + fallback::atomic_or(dst, val) + ) +} + +#[inline] +pub unsafe fn atomic_xor>( + dst: *mut T, + val: T, + order: Ordering, +) -> T { + match_atomic!( + T, + A, + mem::transmute_copy(&(*(dst as *const A)).fetch_xor(mem::transmute_copy(&val), order),), + fallback::atomic_xor(dst, val) + ) +} + +#[inline] +pub unsafe fn atomic_min(dst: *mut T, val: T, order: Ordering) -> T { + match_signed_atomic!( + T, + A, + mem::transmute_copy(&(*(dst as *const A)).fetch_min(mem::transmute_copy(&val), order),), + fallback::atomic_min(dst, val) + ) +} + +#[inline] +pub unsafe fn atomic_max(dst: *mut T, val: T, order: Ordering) -> T { + match_signed_atomic!( + T, + A, + mem::transmute_copy(&(*(dst as *const A)).fetch_max(mem::transmute_copy(&val), order),), + fallback::atomic_max(dst, val) + ) +} + +#[inline] +pub unsafe fn atomic_umin(dst: *mut T, val: T, order: Ordering) -> T { + match_atomic!( + T, + A, + mem::transmute_copy(&(*(dst as *const A)).fetch_min(mem::transmute_copy(&val), order),), + fallback::atomic_min(dst, val) + ) +} + +#[inline] +pub unsafe fn atomic_umax(dst: *mut T, val: T, order: Ordering) -> T { + match_atomic!( + T, + A, + mem::transmute_copy(&(*(dst as *const A)).fetch_max(mem::transmute_copy(&val), order),), + fallback::atomic_max(dst, val) + ) +} diff --git a/vendor/atty/.cargo-checksum.json b/vendor/atty/.cargo-checksum.json new file mode 100644 index 0000000000000..a68b85b16d395 --- /dev/null +++ b/vendor/atty/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"70db121262d72acc472ad1a90b78c42de570820e65b566c6b9339b62e636d572","Cargo.lock":"6868f02a96413bcba37a06f01c6bf87e6331dea9461681a47a561cec6acd2546","Cargo.toml":"3af88a07af6a4adb84373fc3cd4920884b0b12b338cdb55ef598fd512ee1a790","LICENSE":"99fa95ba4e4cdaf71c27d73260ea069fc4515b3d02fde3020c5b562280006cbc","README.md":"e559a69c0b2bd20bffcede64fd548df6c671b0d1504613c5e3e5d884d759caea","examples/atty.rs":"1551387a71474d9ac1b5153231f884e9e05213badcfaa3494ad2cb7ea958374a","rustfmt.toml":"8e6ea1bcb79c505490034020c98e9b472f4ac4113f245bae90f5e1217b1ec65a","src/lib.rs":"d5abf6a54e8c496c486572bdc91eef10480f6ad126c4287f039df5feff7a9bbb"},"package":"d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"} \ No newline at end of file diff --git a/vendor/atty/CHANGELOG.md b/vendor/atty/CHANGELOG.md new file mode 100644 index 0000000000000..4e9673f0de20b --- /dev/null +++ b/vendor/atty/CHANGELOG.md @@ -0,0 +1,73 @@ +# 0.2.14 + +* add support for [RustyHermit](https://github.com/hermitcore/libhermit-rs), a Rust-based unikernel [#41](https://github.com/softprops/atty/pull/41) + +# 0.2.13 + +* support older versions of rust that do now support 2018 edition + +# 0.2.12 + +* Redox is now in the unix family so redox cfg is no longer needed [#35](https://github.com/softprops/atty/pull/35) + +# 0.2.11 + +* fix msys detection with `winapi@0.3.5` [#28](https://github.com/softprops/atty/pull/28) + +# 0.2.10 + +* fix wasm regression [#27](https://github.com/softprops/atty/pull/27) + +# 0.2.9 + +* Fix fix pty detection [#25](https://github.com/softprops/atty/pull/25) + +# 0.2.8 + +* Fix an inverted condition on MinGW [#22](https://github.com/softprops/atty/pull/22) + +# 0.2.7 + +* Change `||` to `&&` for whether MSYS is a tty [#24](https://github.com/softprops/atty/pull/24/) + +# 0.2.6 + +* updated winapi dependency to [0.3](https://retep998.github.io/blog/winapi-0.3/) [#18](https://github.com/softprops/atty/pull/18) + +# 0.2.5 + +* added support for Wasm compile targets [#17](https://github.com/softprops/atty/pull/17) + +# 0.2.4 + +* added support for Wasm compile targets [#17](https://github.com/softprops/atty/pull/17) + +# 0.2.3 + +* added support for Redox OS [#14](https://github.com/softprops/atty/pull/14) + +# 0.2.2 + +* use target specific dependencies [#11](https://github.com/softprops/atty/pull/11) +* Add tty detection for MSYS terminals [#12](https://github.com/softprops/atty/pull/12) + +# 0.2.1 + +* fix windows bug + +# 0.2.0 + +* support for various stream types + +# 0.1.2 + +* windows support (with automated testing) +* automated code coverage + +# 0.1.1 + +* bumped libc dep from `0.1` to `0.2` + +# 0.1.0 + +* initial release diff --git a/vendor/atty/Cargo.lock b/vendor/atty/Cargo.lock new file mode 100644 index 0000000000000..8dc13c81cfa43 --- /dev/null +++ b/vendor/atty/Cargo.lock @@ -0,0 +1,49 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "atty" +version = "0.2.14" +dependencies = [ + "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/atty/Cargo.toml b/vendor/atty/Cargo.toml new file mode 100644 index 0000000000000..d6bf2d03b36ee --- /dev/null +++ b/vendor/atty/Cargo.toml @@ -0,0 +1,34 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "atty" +version = "0.2.14" +authors = ["softprops "] +exclude = ["/.travis.yml", "/appveyor.yml"] +description = "A simple interface for querying atty" +homepage = "https://github.com/softprops/atty" +documentation = "http://softprops.github.io/atty" +readme = "README.md" +keywords = ["terminal", "tty", "isatty"] +license = "MIT" +repository = "https://github.com/softprops/atty" +[target."cfg(target_os = \"hermit\")".dependencies.hermit-abi] +version = "0.1.6" +[target."cfg(unix)".dependencies.libc] +version = "0.2" +default-features = false +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["consoleapi", "processenv", "minwinbase", "minwindef", "winbase"] +[badges.travis-ci] +repository = "softprops/atty" diff --git a/vendor/atty/LICENSE b/vendor/atty/LICENSE new file mode 100644 index 0000000000000..b9da76b73525c --- /dev/null +++ b/vendor/atty/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2015-2019 Doug Tangren + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/atty/README.md b/vendor/atty/README.md new file mode 100644 index 0000000000000..cd85593d6e0cd --- /dev/null +++ b/vendor/atty/README.md @@ -0,0 +1,74 @@ +# atty + +[![Build Status](https://travis-ci.org/softprops/atty.svg?branch=master)](https://travis-ci.org/softprops/atty) [![Build status](https://ci.appveyor.com/api/projects/status/geggrsnsjsuse8cv?svg=true)](https://ci.appveyor.com/project/softprops/atty) [![Coverage Status](https://coveralls.io/repos/softprops/atty/badge.svg?branch=master&service=github)](https://coveralls.io/github/softprops/atty?branch=master) [![crates.io](https://img.shields.io/crates/v/atty.svg)](https://crates.io/crates/atty) [![Released API docs](https://docs.rs/atty/badge.svg)](http://docs.rs/atty) [![Master API docs](https://img.shields.io/badge/docs-master-green.svg)](https://softprops.github.io/atty) + +> are you or are you not a tty? + + +## install + +Add the following to your `Cargo.toml` + +```toml +[dependencies] +atty = "0.2" +``` + +## usage + +```rust +use atty::Stream; + +fn main() { + if atty::is(Stream::Stdout) { + println!("I'm a terminal"); + } else { + println!("I'm not"); + } +} +``` + +## testing + +This library has been unit tested on both unix and windows platforms (via appveyor). + + +A simple example program is provided in this repo to test various tty's. By default. + +It prints + +```bash +$ cargo run --example atty +stdout? true +stderr? true +stdin? true +``` + +To test std in, pipe some text to the program + +```bash +$ echo "test" | cargo run --example atty +stdout? true +stderr? true +stdin? false +``` + +To test std out, pipe the program to something + +```bash +$ cargo run --example atty | grep std +stdout? false +stderr? true +stdin? true +``` + +To test std err, pipe the program to something redirecting std err + +```bash +$ cargo run --example atty 2>&1 | grep std +stdout? false +stderr? false +stdin? true +``` + +Doug Tangren (softprops) 2015-2019 diff --git a/vendor/atty/examples/atty.rs b/vendor/atty/examples/atty.rs new file mode 100644 index 0000000000000..3b3635e59cbd1 --- /dev/null +++ b/vendor/atty/examples/atty.rs @@ -0,0 +1,9 @@ +extern crate atty; + +use atty::{is, Stream}; + +fn main() { + println!("stdout? {}", is(Stream::Stdout)); + println!("stderr? {}", is(Stream::Stderr)); + println!("stdin? {}", is(Stream::Stdin)); +} diff --git a/vendor/atty/rustfmt.toml b/vendor/atty/rustfmt.toml new file mode 100644 index 0000000000000..899a094cd5977 --- /dev/null +++ b/vendor/atty/rustfmt.toml @@ -0,0 +1,4 @@ +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#fn_args_layout +fn_args_layout = "Vertical" +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#merge_imports +merge_imports = true \ No newline at end of file diff --git a/vendor/atty/src/lib.rs b/vendor/atty/src/lib.rs new file mode 100644 index 0000000000000..501cad69484a7 --- /dev/null +++ b/vendor/atty/src/lib.rs @@ -0,0 +1,210 @@ +//! atty is a simple utility that answers one question +//! > is this a tty? +//! +//! usage is just as simple +//! +//! ``` +//! if atty::is(atty::Stream::Stdout) { +//! println!("i'm a tty") +//! } +//! ``` +//! +//! ``` +//! if atty::isnt(atty::Stream::Stdout) { +//! println!("i'm not a tty") +//! } +//! ``` + +#![cfg_attr(unix, no_std)] + +#[cfg(unix)] +extern crate libc; +#[cfg(windows)] +extern crate winapi; + +#[cfg(windows)] +use winapi::shared::minwindef::DWORD; +#[cfg(windows)] +use winapi::shared::ntdef::WCHAR; + +/// possible stream sources +#[derive(Clone, Copy, Debug)] +pub enum Stream { + Stdout, + Stderr, + Stdin, +} + +/// returns true if this is a tty +#[cfg(all(unix, not(target_arch = "wasm32")))] +pub fn is(stream: Stream) -> bool { + extern crate libc; + + let fd = match stream { + Stream::Stdout => libc::STDOUT_FILENO, + Stream::Stderr => libc::STDERR_FILENO, + Stream::Stdin => libc::STDIN_FILENO, + }; + unsafe { libc::isatty(fd) != 0 } +} + +/// returns true if this is a tty +#[cfg(target_os = "hermit")] +pub fn is(stream: Stream) -> bool { + extern crate hermit_abi; + + let fd = match stream { + Stream::Stdout => hermit_abi::STDOUT_FILENO, + Stream::Stderr => hermit_abi::STDERR_FILENO, + Stream::Stdin => hermit_abi::STDIN_FILENO, + }; + hermit_abi::isatty(fd) +} + +/// returns true if this is a tty +#[cfg(windows)] +pub fn is(stream: Stream) -> bool { + use winapi::um::winbase::{ + STD_ERROR_HANDLE as STD_ERROR, STD_INPUT_HANDLE as STD_INPUT, + STD_OUTPUT_HANDLE as STD_OUTPUT, + }; + + let (fd, others) = match stream { + Stream::Stdin => (STD_INPUT, [STD_ERROR, STD_OUTPUT]), + Stream::Stderr => (STD_ERROR, [STD_INPUT, STD_OUTPUT]), + Stream::Stdout => (STD_OUTPUT, [STD_INPUT, STD_ERROR]), + }; + if unsafe { console_on_any(&[fd]) } { + // False positives aren't possible. If we got a console then + // we definitely have a tty on stdin. + return true; + } + + // At this point, we *could* have a false negative. We can determine that + // this is true negative if we can detect the presence of a console on + // any of the other streams. If another stream has a console, then we know + // we're in a Windows console and can therefore trust the negative. + if unsafe { console_on_any(&others) } { + return false; + } + + // Otherwise, we fall back to a very strange msys hack to see if we can + // sneakily detect the presence of a tty. + unsafe { msys_tty_on(fd) } +} + +/// returns true if this is _not_ a tty +pub fn isnt(stream: Stream) -> bool { + !is(stream) +} + +/// Returns true if any of the given fds are on a console. +#[cfg(windows)] +unsafe fn console_on_any(fds: &[DWORD]) -> bool { + use winapi::um::{consoleapi::GetConsoleMode, processenv::GetStdHandle}; + + for &fd in fds { + let mut out = 0; + let handle = GetStdHandle(fd); + if GetConsoleMode(handle, &mut out) != 0 { + return true; + } + } + false +} + +/// Returns true if there is an MSYS tty on the given handle. +#[cfg(windows)] +unsafe fn msys_tty_on(fd: DWORD) -> bool { + use std::{mem, slice}; + + use winapi::{ + ctypes::c_void, + shared::minwindef::MAX_PATH, + um::{ + fileapi::FILE_NAME_INFO, minwinbase::FileNameInfo, processenv::GetStdHandle, + winbase::GetFileInformationByHandleEx, + }, + }; + + let size = mem::size_of::(); + let mut name_info_bytes = vec![0u8; size + MAX_PATH * mem::size_of::()]; + let res = GetFileInformationByHandleEx( + GetStdHandle(fd), + FileNameInfo, + &mut *name_info_bytes as *mut _ as *mut c_void, + name_info_bytes.len() as u32, + ); + if res == 0 { + return false; + } + let name_info: &FILE_NAME_INFO = &*(name_info_bytes.as_ptr() as *const FILE_NAME_INFO); + let s = slice::from_raw_parts( + name_info.FileName.as_ptr(), + name_info.FileNameLength as usize / 2, + ); + let name = String::from_utf16_lossy(s); + // This checks whether 'pty' exists in the file name, which indicates that + // a pseudo-terminal is attached. To mitigate against false positives + // (e.g., an actual file name that contains 'pty'), we also require that + // either the strings 'msys-' or 'cygwin-' are in the file name as well.) + let is_msys = name.contains("msys-") || name.contains("cygwin-"); + let is_pty = name.contains("-pty"); + is_msys && is_pty +} + +/// returns true if this is a tty +#[cfg(target_arch = "wasm32")] +pub fn is(_stream: Stream) -> bool { + false +} + +#[cfg(test)] +mod tests { + use super::{is, Stream}; + + #[test] + #[cfg(windows)] + fn is_err() { + // appveyor pipes its output + assert!(!is(Stream::Stderr)) + } + + #[test] + #[cfg(windows)] + fn is_out() { + // appveyor pipes its output + assert!(!is(Stream::Stdout)) + } + + #[test] + #[cfg(windows)] + fn is_in() { + assert!(is(Stream::Stdin)) + } + + #[test] + #[cfg(unix)] + fn is_err() { + assert!(is(Stream::Stderr)) + } + + #[test] + #[cfg(unix)] + fn is_out() { + assert!(is(Stream::Stdout)) + } + + #[test] + #[cfg(target_os = "macos")] + fn is_in() { + // macos on travis seems to pipe its input + assert!(is(Stream::Stdin)) + } + + #[test] + #[cfg(all(not(target_os = "macos"), unix))] + fn is_in() { + assert!(is(Stream::Stdin)) + } +} diff --git a/vendor/aws-config/src/fs_util.rs b/vendor/aws-config/src/fs_util.rs new file mode 100644 index 0000000000000..89af426d89cf1 --- /dev/null +++ b/vendor/aws-config/src/fs_util.rs @@ -0,0 +1,62 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use aws_types::os_shim_internal; + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub(crate) enum Os { + Windows, + NotWindows, +} + +impl Os { + pub(crate) fn real() -> Self { + match std::env::consts::OS { + "windows" => Os::Windows, + _ => Os::NotWindows, + } + } +} + +/// Resolve a home directory given a set of environment variables +pub(crate) fn home_dir(env_var: &os_shim_internal::Env, os: Os) -> Option { + if let Ok(home) = env_var.get("HOME") { + tracing::debug!(src = "HOME", "loaded home directory"); + return Some(home); + } + + if os == Os::Windows { + if let Ok(home) = env_var.get("USERPROFILE") { + tracing::debug!(src = "USERPROFILE", "loaded home directory"); + return Some(home); + } + + let home_drive = env_var.get("HOMEDRIVE"); + let home_path = env_var.get("HOMEPATH"); + tracing::debug!(src = "HOMEDRIVE/HOMEPATH", "loaded home directory"); + if let (Ok(mut drive), Ok(path)) = (home_drive, home_path) { + drive.push_str(&path); + return Some(drive); + } + } + None +} + +#[cfg(test)] +mod test { + use super::*; + use aws_types::os_shim_internal::Env; + + #[test] + fn homedir_profile_only_windows() { + // windows specific variables should only be considered when the platform is windows + let env = Env::from_slice(&[("USERPROFILE", "C:\\Users\\name")]); + assert_eq!( + home_dir(&env, Os::Windows), + Some("C:\\Users\\name".to_string()) + ); + assert_eq!(home_dir(&env, Os::NotWindows), None); + } +} diff --git a/vendor/aws-config/src/profile/mod.rs b/vendor/aws-config/src/profile/mod.rs new file mode 100644 index 0000000000000..56490f333523b --- /dev/null +++ b/vendor/aws-config/src/profile/mod.rs @@ -0,0 +1,28 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Load configuration from AWS Profiles +//! +//! AWS profiles are typically stored in `~/.aws/config` and `~/.aws/credentials`. For more details +//! see the [`load`](parser::load) function. + +mod parser; + +// This can't be included in the other `pub use` statement until +// https://github.com/rust-lang/rust/pull/87487 is fixed by upgrading +// to Rust 1.60 +#[doc(inline)] +pub use parser::ProfileParseError; +#[doc(inline)] +pub use parser::{load, Profile, ProfileFileLoadError, ProfileSet, Property}; + +pub mod credentials; +pub mod profile_file; +pub mod region; + +#[doc(inline)] +pub use credentials::ProfileFileCredentialsProvider; +#[doc(inline)] +pub use region::ProfileFileRegionProvider; diff --git a/vendor/aws-config/src/profile/parser/normalize.rs b/vendor/aws-config/src/profile/parser/normalize.rs new file mode 100644 index 0000000000000..5b3b5c1ea8cfb --- /dev/null +++ b/vendor/aws-config/src/profile/parser/normalize.rs @@ -0,0 +1,244 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::profile::parser::parse::{RawProfileSet, WHITESPACE}; +use crate::profile::profile_file::ProfileFileKind; +use crate::profile::{Profile, ProfileSet, Property}; +use std::borrow::Cow; +use std::collections::HashMap; + +const DEFAULT: &str = "default"; +const PROFILE_PREFIX: &str = "profile"; + +#[derive(Eq, PartialEq, Hash, Debug)] +struct ProfileName<'a> { + name: &'a str, + has_profile_prefix: bool, +} + +impl ProfileName<'_> { + fn parse(input: &str) -> ProfileName<'_> { + let input = input.trim_matches(WHITESPACE); + let (name, has_profile_prefix) = match input.strip_prefix(PROFILE_PREFIX) { + // profilefoo isn't considered as having the profile prefix + Some(stripped) if stripped.starts_with(WHITESPACE) => (stripped.trim(), true), + _ => (input, false), + }; + ProfileName { + name, + has_profile_prefix, + } + } + + /// Validate a ProfileName for a given file key + /// + /// 1. `name` must ALWAYS be a valid identifier + /// 2. For Config files, the profile must either be `default` or it must have a profile prefix + /// 3. For credentials files, the profile name MUST NOT have a profile prefix + fn valid_for(self, kind: ProfileFileKind) -> Result { + if validate_identifier(self.name).is_err() { + return Err(format!( + "profile `{}` ignored because `{}` was not a valid identifier", + &self.name, &self.name + )); + } + match (self.name, kind, self.has_profile_prefix) { + (_, ProfileFileKind::Config, true) => Ok(self), + (DEFAULT, ProfileFileKind::Config, false) => Ok(self), + (_not_default, ProfileFileKind::Config, false) => Err(format!( + "profile `{}` ignored because config profiles must be of the form `[profile ]`", + self.name + )), + (_, ProfileFileKind::Credentials, true) => Err(format!( + "profile `{}` ignored because credential profiles must NOT begin with `profile`", + self.name + )), + (_, ProfileFileKind::Credentials, false) => Ok(self), + } + } +} + +/// Normalize a raw profile into a `MergedProfile` +/// +/// This function follows the following rules, codified in the tests & the reference Java implementation +/// - When the profile is a config file, strip `profile` and trim whitespace (`profile foo` => `foo`) +/// - Profile names are validated (see `validate_profile_name`) +/// - A profile named `profile default` takes priority over a profile named `default`. +/// - Profiles with identical names are merged +pub(super) fn merge_in( + base: &mut ProfileSet, + raw_profile_set: RawProfileSet<'_>, + kind: ProfileFileKind, +) { + // parse / validate profile names + let validated_profiles = raw_profile_set + .into_iter() + .map(|(name, profile)| (ProfileName::parse(name).valid_for(kind), profile)); + + // remove invalid profiles & emit warning + // valid_profiles contains only valid profiles but it may contain `[profile default]` and `[default]` + // which must be filtered later + let valid_profiles = validated_profiles + .filter_map(|(name, profile)| match name { + Ok(profile_name) => Some((profile_name, profile)), + Err(err_str) => { + tracing::warn!("{}", err_str); + None + } + }) + .collect::>(); + // if a `[profile default]` exists then we should ignore `[default]` + let ignore_unprefixed_default = valid_profiles + .iter() + .any(|(profile, _)| profile.name == DEFAULT && profile.has_profile_prefix); + + for (profile_name, raw_profile) in valid_profiles { + // When normalizing profiles, profiles should be merged. However, `[profile default]` and + // `[default]` are considered two separate profiles. Furthermore, `[profile default]` fully + // replaces any contents of `[default]`! + if ignore_unprefixed_default + && profile_name.name == DEFAULT + && !profile_name.has_profile_prefix + { + tracing::warn!("profile `default` ignored because `[profile default]` was found which takes priority"); + continue; + } + let profile = base + .profiles + .entry(profile_name.name.to_string()) + .or_insert_with(|| Profile::new(profile_name.name.to_string(), Default::default())); + merge_into_base(profile, raw_profile) + } +} + +fn merge_into_base(target: &mut Profile, profile: HashMap<&str, Cow<'_, str>>) { + for (k, v) in profile { + match validate_identifier(k) { + Ok(k) => { + target + .properties + .insert(k.to_owned(), Property::new(k.to_owned(), v.into())); + } + Err(_) => { + tracing::warn!(profile = %&target.name, key = ?k, "key ignored because `{}` was not a valid identifier", k); + } + } + } +} + +/// Validate that a string is a valid identifier +/// +/// Identifiers must match `[A-Za-z0-9_\-/.%@:\+]+` +fn validate_identifier(input: &str) -> Result<&str, ()> { + input + .chars() + .all(|ch| { + ch.is_ascii_alphanumeric() + || ['_', '-', '/', '.', '%', '@', ':', '+'] + .iter() + .any(|c| *c == ch) + }) + .then_some(input) + .ok_or(()) +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use tracing_test::traced_test; + + use crate::profile::parser::parse::RawProfileSet; + use crate::profile::ProfileSet; + + use super::{merge_in, ProfileName}; + use crate::profile::parser::normalize::validate_identifier; + use crate::profile::profile_file::ProfileFileKind; + + #[test] + fn profile_name_parsing() { + assert_eq!( + ProfileName::parse("profile name"), + ProfileName { + name: "name", + has_profile_prefix: true + } + ); + assert_eq!( + ProfileName::parse("name"), + ProfileName { + name: "name", + has_profile_prefix: false + } + ); + assert_eq!( + ProfileName::parse("profile\tname"), + ProfileName { + name: "name", + has_profile_prefix: true + } + ); + assert_eq!( + ProfileName::parse("profile name "), + ProfileName { + name: "name", + has_profile_prefix: true + } + ); + assert_eq!( + ProfileName::parse("profilename"), + ProfileName { + name: "profilename", + has_profile_prefix: false + } + ); + assert_eq!( + ProfileName::parse(" whitespace "), + ProfileName { + name: "whitespace", + has_profile_prefix: false + } + ); + } + + #[test] + fn test_validate_identifier() { + assert_eq!( + Ok("some-thing:long/the_one%only.foo@bar+"), + validate_identifier("some-thing:long/the_one%only.foo@bar+") + ); + assert_eq!(Err(()), validate_identifier("foo!bar")); + } + + #[test] + #[traced_test] + fn ignored_key_generates_warning() { + let mut profile: RawProfileSet<'_> = HashMap::new(); + profile.insert("default", { + let mut out = HashMap::new(); + out.insert("invalid key", "value".into()); + out + }); + let mut base = ProfileSet::empty(); + merge_in(&mut base, profile, ProfileFileKind::Config); + assert!(base + .get_profile("default") + .expect("contains default profile") + .properties + .is_empty()); + assert!(logs_contain( + "key ignored because `invalid key` was not a valid identifier" + )); + } + + #[test] + #[traced_test] + fn invalid_profile_generates_warning() { + let mut profile: RawProfileSet<'_> = HashMap::new(); + profile.insert("foo", HashMap::new()); + merge_in(&mut ProfileSet::empty(), profile, ProfileFileKind::Config); + assert!(logs_contain("profile `foo` ignored")); + } +} diff --git a/vendor/aws-config/src/profile/parser/parse.rs b/vendor/aws-config/src/profile/parser/parse.rs new file mode 100644 index 0000000000000..1d3c3acb05763 --- /dev/null +++ b/vendor/aws-config/src/profile/parser/parse.rs @@ -0,0 +1,348 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Profile file parsing +//! +//! This file implements profile file parsing at a very literal level. Prior to actually being used, +//! profiles must be normalized into a canonical form. Constructions that will eventually be +//! deemed invalid are accepted during parsing such as: +//! - keys that are invalid identifiers: `a b = c` +//! - profiles with invalid names +//! - profile name normalization (`profile foo` => `foo`) + +use crate::profile::parser::source::File; +use std::borrow::Cow; +use std::collections::HashMap; +use std::error::Error; +use std::fmt::{self, Display, Formatter}; + +/// A set of profiles that still carries a reference to the underlying data +pub(super) type RawProfileSet<'a> = HashMap<&'a str, HashMap<&'a str, Cow<'a, str>>>; + +/// Characters considered to be whitespace by the spec +/// +/// Profile parsing is actually quite strict about what is and is not whitespace, so use this instead +/// of `.is_whitespace()` / `.trim()` +pub(super) const WHITESPACE: &[char] = &[' ', '\t']; +const COMMENT: &[char] = &['#', ';']; + +/// Location for use during error reporting +#[derive(Clone, Debug, Eq, PartialEq)] +struct Location { + line_number: usize, + path: String, +} + +/// An error encountered while parsing a profile +#[derive(Debug, Clone)] +pub struct ProfileParseError { + /// Location where this error occurred + location: Location, + + /// Error message + message: String, +} + +impl Display for ProfileParseError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "error parsing {} on line {}:\n {}", + self.location.path, self.location.line_number, self.message + ) + } +} + +impl Error for ProfileParseError {} + +/// Validate that a line represents a valid subproperty +/// +/// - Subproperties looks like regular properties (`k=v`) that are nested within an existing property. +/// - Subproperties must be validated for compatibility with other SDKs, but they are not actually +/// parsed into structured data. +fn validate_subproperty(value: &str, location: Location) -> Result<(), ProfileParseError> { + if value.trim_matches(WHITESPACE).is_empty() { + Ok(()) + } else { + parse_property_line(value) + .map_err(|err| err.into_error("sub-property", location)) + .map(|_| ()) + } +} + +fn is_empty_line(line: &str) -> bool { + line.trim_matches(WHITESPACE).is_empty() +} + +fn is_comment_line(line: &str) -> bool { + line.starts_with(COMMENT) +} + +/// Parser for profile files +struct Parser<'a> { + /// In-progress profile representation + data: RawProfileSet<'a>, + + /// Parser state + state: State<'a>, + + /// Parser source location + /// + /// Location is tracked to facilitate error reporting + location: Location, +} + +enum State<'a> { + Starting, + ReadingProfile { + profile: &'a str, + property: Option<&'a str>, + is_subproperty: bool, + }, +} + +/// Parse `file` into a `RawProfileSet` +pub(super) fn parse_profile_file(file: &File) -> Result, ProfileParseError> { + let mut parser = Parser { + data: HashMap::new(), + state: State::Starting, + location: Location { + line_number: 0, + path: file.path.clone().unwrap_or_default(), + }, + }; + parser.parse_profile(&file.contents)?; + Ok(parser.data) +} + +impl<'a> Parser<'a> { + /// Parse `file` containing profile data into `self.data`. + fn parse_profile(&mut self, file: &'a str) -> Result<(), ProfileParseError> { + for (line_number, line) in file.lines().enumerate() { + self.location.line_number = line_number + 1; // store a 1-indexed line number + if is_empty_line(line) || is_comment_line(line) { + continue; + } + if line.starts_with('[') { + self.read_profile_line(line)?; + } else if line.starts_with(WHITESPACE) { + self.read_property_continuation(line)?; + } else { + self.read_property_line(line)?; + } + } + Ok(()) + } + + /// Parse a property line like `a = b` + /// + /// A property line is only valid when we're within a profile definition, `[profile foo]` + fn read_property_line(&mut self, line: &'a str) -> Result<(), ProfileParseError> { + let location = &self.location; + let (current_profile, name) = match &self.state { + State::Starting => return Err(self.make_error("Expected a profile definition")), + State::ReadingProfile { profile, .. } => ( + self.data.get_mut(*profile).expect("profile must exist"), + profile, + ), + }; + let (k, v) = parse_property_line(line) + .map_err(|err| err.into_error("property", location.clone()))?; + self.state = State::ReadingProfile { + profile: name, + property: Some(k), + is_subproperty: v.is_empty(), + }; + current_profile.insert(k, v.into()); + Ok(()) + } + + /// Create a location-tagged error message + fn make_error(&self, message: &str) -> ProfileParseError { + ProfileParseError { + location: self.location.clone(), + message: message.into(), + } + } + + /// Parse the lines of a property after the first line. + /// + /// This is triggered by lines that start with whitespace. + fn read_property_continuation(&mut self, line: &'a str) -> Result<(), ProfileParseError> { + let current_property = match &self.state { + State::Starting => return Err(self.make_error("Expected a profile definition")), + State::ReadingProfile { + profile, + property: Some(property), + is_subproperty, + } => { + if *is_subproperty { + validate_subproperty(line, self.location.clone())?; + } + self.data + .get_mut(*profile) + .expect("profile must exist") + .get_mut(*property) + .expect("property must exist") + } + State::ReadingProfile { + profile: _, + property: None, + .. + } => return Err(self.make_error("Expected a property definition, found continuation")), + }; + let line = line.trim_matches(WHITESPACE); + let current_property = current_property.to_mut(); + current_property.push('\n'); + current_property.push_str(line); + Ok(()) + } + + fn read_profile_line(&mut self, line: &'a str) -> Result<(), ProfileParseError> { + let line = prepare_line(line, false); + let profile_name = line + .strip_prefix('[') + .ok_or_else(|| self.make_error("Profile definition must start with ]"))? + .strip_suffix(']') + .ok_or_else(|| self.make_error("Profile definition must end with ']'"))?; + if !self.data.contains_key(profile_name) { + self.data.insert(profile_name, Default::default()); + } + self.state = State::ReadingProfile { + profile: profile_name, + property: None, + is_subproperty: false, + }; + Ok(()) + } +} + +/// Error encountered while parsing a property +#[derive(Debug, Eq, PartialEq)] +enum PropertyError { + NoEquals, + NoName, +} + +impl PropertyError { + fn into_error(self, ctx: &str, location: Location) -> ProfileParseError { + let mut ctx = ctx.to_string(); + match self { + PropertyError::NoName => { + ctx.get_mut(0..1).unwrap().make_ascii_uppercase(); + ProfileParseError { + location, + message: format!("{} did not have a name", ctx), + } + } + PropertyError::NoEquals => ProfileParseError { + location, + message: format!("Expected an '=' sign defining a {}", ctx), + }, + } + } +} + +/// Parse a property line into a key-value pair +fn parse_property_line(line: &str) -> Result<(&str, &str), PropertyError> { + let line = prepare_line(line, true); + let (k, v) = line.split_once('=').ok_or(PropertyError::NoEquals)?; + let k = k.trim_matches(WHITESPACE); + let v = v.trim_matches(WHITESPACE); + if k.is_empty() { + return Err(PropertyError::NoName); + } + Ok((k, v)) +} + +/// Prepare a line for parsing +/// +/// Because leading whitespace is significant, this method should only be called after determining +/// whether a line represents a property (no whitespace) or a sub-property (whitespace). +/// This function preprocesses a line to simplify parsing: +/// 1. Strip leading and trailing whitespace +/// 2. Remove trailing comments +/// +/// Depending on context, comment characters may need to be preceded by whitespace to be considered +/// comments. +fn prepare_line(line: &str, comments_need_whitespace: bool) -> &str { + let line = line.trim_matches(WHITESPACE); + let mut prev_char_whitespace = false; + let mut comment_idx = None; + for (idx, chr) in line.char_indices() { + if (COMMENT.contains(&chr)) && (prev_char_whitespace || !comments_need_whitespace) { + comment_idx = Some(idx); + break; + } + prev_char_whitespace = chr.is_whitespace(); + } + comment_idx + .map(|idx| &line[..idx]) + .unwrap_or(line) + // trimming the comment might result in more whitespace that needs to be handled + .trim_matches(WHITESPACE) +} + +#[cfg(test)] +mod test { + use super::{parse_profile_file, prepare_line, Location}; + use crate::profile::parser::parse::{parse_property_line, PropertyError}; + use crate::profile::parser::source::File; + use crate::profile::profile_file::ProfileFileKind; + + // most test cases covered by the JSON test suite + + #[test] + fn property_parsing() { + assert_eq!(parse_property_line("a = b"), Ok(("a", "b"))); + assert_eq!(parse_property_line("a=b"), Ok(("a", "b"))); + assert_eq!(parse_property_line("a = b "), Ok(("a", "b"))); + assert_eq!(parse_property_line(" a = b "), Ok(("a", "b"))); + assert_eq!(parse_property_line(" a = b 🱠"), Ok(("a", "b ðŸ±"))); + assert_eq!(parse_property_line("a b"), Err(PropertyError::NoEquals)); + assert_eq!(parse_property_line("= b"), Err(PropertyError::NoName)); + assert_eq!(parse_property_line("a = "), Ok(("a", ""))); + assert_eq!( + parse_property_line("something_base64=aGVsbG8gZW50aHVzaWFzdGljIHJlYWRlcg=="), + Ok(("something_base64", "aGVsbG8gZW50aHVzaWFzdGljIHJlYWRlcg==")) + ); + } + + #[test] + fn prepare_line_strips_comments() { + assert_eq!( + prepare_line("name = value # Comment with # sign", true), + "name = value" + ); + + assert_eq!( + prepare_line("name = value#Comment # sign", true), + "name = value#Comment" + ); + + assert_eq!( + prepare_line("name = value#Comment # sign", false), + "name = value" + ); + } + + #[test] + fn error_line_numbers() { + let file = File { + kind: ProfileFileKind::Config, + path: Some("~/.aws/config".into()), + contents: "[default\nk=v".into(), + }; + let err = parse_profile_file(&file).expect_err("parsing should fail"); + assert_eq!(err.message, "Profile definition must end with ']'"); + assert_eq!( + err.location, + Location { + path: "~/.aws/config".into(), + line_number: 1 + } + ) + } +} diff --git a/vendor/aws-config/src/profile/parser/source.rs b/vendor/aws-config/src/profile/parser/source.rs new file mode 100644 index 0000000000000..1b859fcee90b8 --- /dev/null +++ b/vendor/aws-config/src/profile/parser/source.rs @@ -0,0 +1,486 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::fs_util::{home_dir, Os}; + +use crate::profile::parser::{CouldNotReadProfileFile, ProfileFileLoadError}; +use crate::profile::profile_file::{ProfileFile, ProfileFileKind, ProfileFiles}; + +use aws_smithy_types::error::display::DisplayErrorContext; +use aws_types::os_shim_internal; +use std::borrow::Cow; +use std::io::ErrorKind; +use std::path::{Component, Path, PathBuf}; +use std::sync::Arc; +use tracing::{warn, Instrument}; + +const HOME_EXPANSION_FAILURE_WARNING: &str = + "home directory expansion was requested (via `~` character) for the profile \ + config file path, but no home directory could be determined"; + +/// In-memory source of profile data +pub(super) struct Source { + /// Profile file sources + pub(super) files: Vec, + + /// Profile to use + /// + /// Overridden via `$AWS_PROFILE`, defaults to `default` + pub(super) profile: Cow<'static, str>, +} + +/// In-memory configuration file +pub(super) struct File { + pub(super) kind: ProfileFileKind, + pub(super) path: Option, + pub(super) contents: String, +} + +/// Load a [Source](Source) from a given environment and filesystem. +pub(super) async fn load( + proc_env: &os_shim_internal::Env, + fs: &os_shim_internal::Fs, + profile_files: &ProfileFiles, +) -> Result { + let home = home_dir(proc_env, Os::real()); + + let mut files = Vec::new(); + for file in &profile_files.files { + let file = load_config_file(file, &home, fs, proc_env) + .instrument(tracing::debug_span!("load_config_file", file = ?file)) + .await?; + files.push(file); + } + + Ok(Source { + files, + profile: proc_env + .get("AWS_PROFILE") + .map(Cow::Owned) + .unwrap_or(Cow::Borrowed("default")), + }) +} + +fn file_contents_to_string(path: &Path, contents: Vec) -> String { + // if the file is not valid utf-8, log a warning and use an empty file instead + match String::from_utf8(contents) { + Ok(contents) => contents, + Err(e) => { + tracing::warn!(path = ?path, error = %DisplayErrorContext(&e), "config file did not contain utf-8 encoded data"); + Default::default() + } + } +} + +/// Loads an AWS Config file +/// +/// Both the default & the overriding patterns may contain `~/` which MUST be expanded to the users +/// home directory in a platform-aware way (see [`expand_home`](expand_home)) +/// +/// Arguments: +/// * `kind`: The type of config file to load +/// * `home_directory`: Home directory to use during home directory expansion +/// * `fs`: Filesystem abstraction +/// * `environment`: Process environment abstraction +async fn load_config_file( + source: &ProfileFile, + home_directory: &Option, + fs: &os_shim_internal::Fs, + environment: &os_shim_internal::Env, +) -> Result { + let (path, kind, contents) = match source { + ProfileFile::Default(kind) => { + let (path_is_default, path) = environment + .get(kind.override_environment_variable()) + .map(|p| (false, Cow::Owned(p))) + .ok() + .unwrap_or_else(|| (true, kind.default_path().into())); + let expanded = expand_home(path.as_ref(), path_is_default, home_directory); + if path != expanded.to_string_lossy() { + tracing::debug!(before = ?path, after = ?expanded, "home directory expanded"); + } + // read the data at the specified path + // if the path does not exist, log a warning but pretend it was actually an empty file + let data = match fs.read_to_end(&expanded).await { + Ok(data) => data, + Err(e) => { + // Important: The default config/credentials files MUST NOT return an error + match e.kind() { + ErrorKind::NotFound if path == kind.default_path() => { + tracing::debug!(path = %path, "config file not found") + } + ErrorKind::NotFound if path != kind.default_path() => { + // in the case where the user overrode the path with an environment variable, + // log more loudly than the case where the default path was missing + tracing::warn!(path = %path, env = %kind.override_environment_variable(), "config file overridden via environment variable not found") + } + _other => { + tracing::warn!(path = %path, error = %DisplayErrorContext(&e), "failed to read config file") + } + }; + Default::default() + } + }; + let contents = file_contents_to_string(&expanded, data); + (Some(Cow::Owned(expanded)), kind, contents) + } + ProfileFile::FilePath { kind, path } => { + let data = match fs.read_to_end(&path).await { + Ok(data) => data, + Err(e) => { + return Err(ProfileFileLoadError::CouldNotReadFile( + CouldNotReadProfileFile { + path: path.clone(), + cause: Arc::new(e), + }, + )) + } + }; + ( + Some(Cow::Borrowed(path)), + kind, + file_contents_to_string(path, data), + ) + } + ProfileFile::FileContents { kind, contents } => (None, kind, contents.clone()), + }; + tracing::debug!(path = ?path, size = ?contents.len(), "config file loaded"); + Ok(File { + kind: *kind, + // lossy is OK here, the name of this file is just for debugging purposes + path: path.map(|p| p.to_string_lossy().into()), + contents, + }) +} + +fn expand_home( + path: impl AsRef, + path_is_default: bool, + home_dir: &Option, +) -> PathBuf { + let path = path.as_ref(); + let mut components = path.components(); + let start = components.next(); + match start { + None => path.into(), // empty path, + Some(Component::Normal(s)) if s == "~" => { + // do homedir replacement + let path = match home_dir { + Some(dir) => { + tracing::debug!(home = ?dir, path = ?path, "performing home directory substitution"); + dir.clone() + } + None => { + // Only log a warning if the path was explicitly set by the customer. + if !path_is_default { + warn!(HOME_EXPANSION_FAILURE_WARNING); + } + // if we can't determine the home directory, just leave it as `~` + "~".into() + } + }; + let mut path: PathBuf = path.into(); + // rewrite the path using system-specific path separators + for component in components { + path.push(component); + } + path + } + // Finally, handle the case where it doesn't begin with some version of `~/`: + // NOTE: in this case we aren't performing path rewriting. This is correct because + // this path comes from an environment variable on the target + // platform, so in that case, the separators should already be correct. + _other => path.into(), + } +} + +#[cfg(test)] +mod tests { + use crate::profile::parser::source::{ + expand_home, load, load_config_file, HOME_EXPANSION_FAILURE_WARNING, + }; + use crate::profile::parser::ProfileFileLoadError; + use crate::profile::profile_file::{ProfileFile, ProfileFileKind, ProfileFiles}; + use aws_types::os_shim_internal::{Env, Fs}; + use futures_util::FutureExt; + use serde::Deserialize; + use std::collections::HashMap; + use std::error::Error; + use std::fs; + use tracing_test::traced_test; + + #[test] + fn only_expand_home_prefix() { + // ~ is only expanded as a single component (currently) + let path = "~aws/config"; + assert_eq!( + expand_home(path, false, &None).to_str().unwrap(), + "~aws/config" + ); + } + + #[derive(Deserialize, Debug)] + #[serde(rename_all = "camelCase")] + struct SourceTests { + tests: Vec, + } + + #[derive(Deserialize, Debug)] + #[serde(rename_all = "camelCase")] + struct TestCase { + name: String, + environment: HashMap, + platform: String, + profile: Option, + config_location: String, + credentials_location: String, + } + + /// Run all tests from file-location-tests.json + #[test] + fn run_tests() -> Result<(), Box> { + let tests = fs::read_to_string("test-data/file-location-tests.json")?; + let tests: SourceTests = serde_json::from_str(&tests)?; + for (i, test) in tests.tests.into_iter().enumerate() { + eprintln!("test: {}", i); + check(test) + .now_or_never() + .expect("these futures should never poll"); + } + Ok(()) + } + + #[traced_test] + #[test] + fn logs_produced_default() { + let env = Env::from_slice(&[("HOME", "/user/name")]); + let mut fs = HashMap::new(); + fs.insert( + "/user/name/.aws/config".to_string(), + "[default]\nregion = us-east-1", + ); + + let fs = Fs::from_map(fs); + + let _src = load(&env, &fs, &Default::default()).now_or_never(); + assert!(logs_contain("config file loaded")); + assert!(logs_contain("performing home directory substitution")); + } + + #[traced_test] + #[test] + fn load_config_file_should_not_emit_warning_when_path_not_explicitly_set() { + let env = Env::from_slice(&[]); + let fs = Fs::from_slice(&[]); + + let _src = load_config_file( + &ProfileFile::Default(ProfileFileKind::Config), + &None, + &fs, + &env, + ) + .now_or_never(); + assert!(!logs_contain(HOME_EXPANSION_FAILURE_WARNING)); + } + + #[traced_test] + #[test] + fn load_config_file_should_emit_warning_when_path_explicitly_set() { + let env = Env::from_slice(&[("AWS_CONFIG_FILE", "~/some/path")]); + let fs = Fs::from_slice(&[]); + + let _src = load_config_file( + &ProfileFile::Default(ProfileFileKind::Config), + &None, + &fs, + &env, + ) + .now_or_never(); + assert!(logs_contain(HOME_EXPANSION_FAILURE_WARNING)); + } + + async fn check(test_case: TestCase) { + let fs = Fs::real(); + let env = Env::from(test_case.environment); + let platform_matches = (cfg!(windows) && test_case.platform == "windows") + || (!cfg!(windows) && test_case.platform != "windows"); + if platform_matches { + let source = load(&env, &fs, &Default::default()).await.unwrap(); + if let Some(expected_profile) = test_case.profile { + assert_eq!(source.profile, expected_profile, "{}", &test_case.name); + } + assert_eq!( + source.files[0].path, + Some(test_case.config_location), + "{}", + &test_case.name + ); + assert_eq!( + source.files[1].path, + Some(test_case.credentials_location), + "{}", + &test_case.name + ) + } else { + println!( + "NOTE: ignoring test case for {} which does not apply to our platform: \n {}", + &test_case.platform, &test_case.name + ) + } + } + + #[test] + #[cfg_attr(windows, ignore)] + fn test_expand_home() { + let path = "~/.aws/config"; + assert_eq!( + expand_home(path, false, &Some("/user/foo".to_string())) + .to_str() + .unwrap(), + "/user/foo/.aws/config" + ); + } + + #[test] + fn expand_home_no_home() { + // there is an edge case around expansion when no home directory exists + // if no home directory can be determined, leave the path as is + if !cfg!(windows) { + assert_eq!( + expand_home("~/config", false, &None).to_str().unwrap(), + "~/config" + ) + } else { + assert_eq!( + expand_home("~/config", false, &None).to_str().unwrap(), + "~\\config" + ) + } + } + + /// Test that a linux oriented path expands on windows + #[test] + #[cfg_attr(not(windows), ignore)] + fn test_expand_home_windows() { + let path = "~/.aws/config"; + assert_eq!( + expand_home(path, true, &Some("C:\\Users\\name".to_string()),) + .to_str() + .unwrap(), + "C:\\Users\\name\\.aws\\config" + ); + } + + #[tokio::test] + async fn programmatically_set_credentials_file_contents() { + let contents = "[default]\n\ + aws_access_key_id = AKIAFAKE\n\ + aws_secret_access_key = FAKE\n\ + "; + let env = Env::from_slice(&[]); + let fs = Fs::from_slice(&[]); + let profile_files = ProfileFiles::builder() + .with_contents(ProfileFileKind::Credentials, contents) + .build(); + let source = load(&env, &fs, &profile_files).await.unwrap(); + assert_eq!(1, source.files.len()); + assert_eq!("default", source.profile); + assert_eq!(contents, source.files[0].contents); + } + + #[tokio::test] + async fn programmatically_set_credentials_file_path() { + let contents = "[default]\n\ + aws_access_key_id = AKIAFAKE\n\ + aws_secret_access_key = FAKE\n\ + "; + let mut fs = HashMap::new(); + fs.insert( + "/custom/path/to/credentials".to_string(), + contents.to_string(), + ); + + let fs = Fs::from_map(fs); + let env = Env::from_slice(&[]); + let profile_files = ProfileFiles::builder() + .with_file(ProfileFileKind::Credentials, "/custom/path/to/credentials") + .build(); + let source = load(&env, &fs, &profile_files).await.unwrap(); + assert_eq!(1, source.files.len()); + assert_eq!("default", source.profile); + assert_eq!(contents, source.files[0].contents); + } + + #[tokio::test] + async fn programmatically_include_default_files() { + let config_contents = "[default]\nregion = us-east-1"; + let credentials_contents = "[default]\n\ + aws_access_key_id = AKIAFAKE\n\ + aws_secret_access_key = FAKE\n\ + "; + let custom_contents = "[profile some-profile]\n\ + aws_access_key_id = AKIAFAKEOTHER\n\ + aws_secret_access_key = FAKEOTHER\n\ + "; + let mut fs = HashMap::new(); + fs.insert( + "/user/name/.aws/config".to_string(), + config_contents.to_string(), + ); + fs.insert( + "/user/name/.aws/credentials".to_string(), + credentials_contents.to_string(), + ); + + let fs = Fs::from_map(fs); + let env = Env::from_slice(&[("HOME", "/user/name")]); + let profile_files = ProfileFiles::builder() + .with_contents(ProfileFileKind::Config, custom_contents) + .include_default_credentials_file(true) + .include_default_config_file(true) + .build(); + let source = load(&env, &fs, &profile_files).await.unwrap(); + assert_eq!(3, source.files.len()); + assert_eq!("default", source.profile); + assert_eq!(config_contents, source.files[0].contents); + assert_eq!(credentials_contents, source.files[1].contents); + assert_eq!(custom_contents, source.files[2].contents); + } + + #[tokio::test] + async fn default_files_must_not_error() { + let custom_contents = "[profile some-profile]\n\ + aws_access_key_id = AKIAFAKEOTHER\n\ + aws_secret_access_key = FAKEOTHER\n\ + "; + + let fs = Fs::from_slice(&[]); + let env = Env::from_slice(&[("HOME", "/user/name")]); + let profile_files = ProfileFiles::builder() + .with_contents(ProfileFileKind::Config, custom_contents) + .include_default_credentials_file(true) + .include_default_config_file(true) + .build(); + let source = load(&env, &fs, &profile_files).await.unwrap(); + assert_eq!(3, source.files.len()); + assert_eq!("default", source.profile); + assert_eq!("", source.files[0].contents); + assert_eq!("", source.files[1].contents); + assert_eq!(custom_contents, source.files[2].contents); + } + + #[tokio::test] + async fn misconfigured_programmatic_custom_profile_path_must_error() { + let fs = Fs::from_slice(&[]); + let env = Env::from_slice(&[]); + let profile_files = ProfileFiles::builder() + .with_file(ProfileFileKind::Config, "definitely-doesnt-exist") + .build(); + assert!(matches!( + load(&env, &fs, &profile_files).await, + Err(ProfileFileLoadError::CouldNotReadFile(_)) + )); + } +} diff --git a/vendor/aws-config/src/standard_property.rs b/vendor/aws-config/src/standard_property.rs new file mode 100644 index 0000000000000..ec2ef2b9bc3a5 --- /dev/null +++ b/vendor/aws-config/src/standard_property.rs @@ -0,0 +1,121 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::provider_config::ProviderConfig; +use std::borrow::Cow; +use std::error::Error; +use std::fmt::{Display, Formatter}; + +#[derive(Debug)] +pub(crate) enum PropertySource<'a> { + Environment { name: &'a str }, + Profile { name: &'a str, key: &'a str }, +} + +impl Display for PropertySource<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + PropertySource::Environment { name } => write!(f, "environment variable `{}`", name), + PropertySource::Profile { name, key } => { + write!(f, "profile `{}`, key: `{}`", name, key) + } + } + } +} + +#[derive(Debug)] +pub(crate) struct PropertyResolutionError> { + property_source: String, + pub(crate) err: E, +} + +impl Display for PropertyResolutionError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}. source: {}", self.err, self.property_source) + } +} + +impl Error for PropertyResolutionError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + self.err.source() + } +} + +/// Standard properties simplify code that reads properties from the environment and AWS Profile +/// +/// `StandardProperty` will first look in the environment, then the AWS profile. They track the +/// provenance of properties so that unified validation errors can be created. +/// +/// For a usage example, see [`crate::default_provider::retry_config`] +#[derive(Default)] +pub(crate) struct StandardProperty { + environment_variable: Option>, + profile_key: Option>, +} + +impl StandardProperty { + pub(crate) fn new() -> Self { + Self::default() + } + + /// Set the environment variable to read + pub(crate) fn env(mut self, key: &'static str) -> Self { + self.environment_variable = Some(Cow::Borrowed(key)); + self + } + + /// Set the profile key to read + pub(crate) fn profile(mut self, key: &'static str) -> Self { + self.profile_key = Some(Cow::Borrowed(key)); + self + } + + /// Load the value from `provider_config`, validating with `validator` + pub(crate) async fn validate( + self, + provider_config: &ProviderConfig, + validator: impl Fn(&str) -> Result, + ) -> Result, PropertyResolutionError> { + let value = self.load(provider_config).await; + value + .map(|(v, ctx)| { + validator(v.as_ref()).map_err(|err| PropertyResolutionError { + property_source: format!("{}", ctx), + err, + }) + }) + .transpose() + } + + /// Load the value from `provider_config` + pub(crate) async fn load<'a>( + &'a self, + provider_config: &'a ProviderConfig, + ) -> Option<(Cow<'a, str>, PropertySource<'a>)> { + if let Some(env_var) = self.environment_variable.as_ref() { + if let Ok(value) = provider_config.env().get(env_var) { + return Some(( + Cow::Owned(value), + PropertySource::Environment { name: env_var }, + )); + } + } + if let Some(profile_key) = self.profile_key.as_ref() { + let profile = provider_config.profile().await?; + + if let Some(value) = profile.get(profile_key) { + return Some(( + Cow::Borrowed(value), + PropertySource::Profile { + name: profile.selected_profile(), + key: profile_key, + }, + )); + } + } + + None + } +} diff --git a/vendor/aws-http/.cargo-checksum.json b/vendor/aws-http/.cargo-checksum.json new file mode 100644 index 0000000000000..408e395ba2462 --- /dev/null +++ b/vendor/aws-http/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"cd07b1c9ff82c0e6b854025b41cd599dac7d9fd4d88ef7928692893ff30a1d1d","LICENSE":"09e8a9bcec8067104652c168685ab0931e7868f9c8284b66f5ae6edae5f1130b","README.md":"ef9760995b82d2061226ae922e2d5f37e0d8da3e1d2edf9c3bd09c55d79ad7e8","external-types.toml":"75923255e9438bfeca7e78555ff758194835f106bf74e0660513c0aa7c6650db","src/content_encoding.rs":"692fb09210dcf1932894cdfef07e3506504cb0cccb0b2539ebcce7c89c040eb9","src/lib.rs":"52ea48e676abd0d70ea4091581eb30773c05a8d4f6a2a516a830fc5f63bf91e2","src/user_agent.rs":"5b3383dc7b5622995e629b3cfbf00fda03884eac52195cc89f2ecf4ceca6a84d","test-data/recursion-detection.json":"af8b2e8186809ebf20e9250ea29755efb3f4222dc78c91ba62285a8008c2ed04"},"package":"361c4310fdce94328cc2d1ca0c8a48c13f43009c61d3367585685a50ca8c66b6"} \ No newline at end of file diff --git a/vendor/aws-http/Cargo.toml b/vendor/aws-http/Cargo.toml new file mode 100644 index 0000000000000..d7d4957ba8dec --- /dev/null +++ b/vendor/aws-http/Cargo.toml @@ -0,0 +1,69 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "aws-http" +version = "0.60.0" +authors = [ + "AWS Rust SDK Team ", + "Russell Cohen ", +] +description = "HTTP specific AWS SDK behaviors." +readme = "README.md" +license = "Apache-2.0" +repository = "https://github.com/smithy-lang/smithy-rs" +resolver = "1" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies.aws-smithy-runtime-api] +version = "1.0.0" +features = ["client"] + +[dependencies.aws-smithy-types] +version = "1.0.0" +features = ["http-body-0-4-x"] + +[dependencies.aws-types] +version = "1.0.0" + +[dependencies.bytes] +version = "1.1" + +[dependencies.http] +version = "0.2.3" + +[dependencies.http-body] +version = "0.4.5" + +[dependencies.pin-project-lite] +version = "0.2.9" + +[dependencies.tracing] +version = "0.1" + +[dev-dependencies.bytes-utils] +version = "0.1.2" + +[dev-dependencies.tokio] +version = "1.23.1" +features = [ + "macros", + "rt", + "time", +] diff --git a/vendor/aws-http/LICENSE b/vendor/aws-http/LICENSE new file mode 100644 index 0000000000000..67db8588217f2 --- /dev/null +++ b/vendor/aws-http/LICENSE @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/vendor/aws-http/README.md b/vendor/aws-http/README.md new file mode 100644 index 0000000000000..b4d264c8230c5 --- /dev/null +++ b/vendor/aws-http/README.md @@ -0,0 +1,10 @@ +# aws-http + +This crate provides middleware for AWS SDKs using HTTP including: +* Generalized retry policy +* Middleware for setting `User-Agent` headers based on runtime configuration +* Credential loading async middleware + + +This crate is part of the [AWS SDK for Rust](https://awslabs.github.io/aws-sdk-rust/) and the [smithy-rs](https://github.com/smithy-lang/smithy-rs) code generator. In most cases, it should not be used directly. + diff --git a/vendor/aws-http/external-types.toml b/vendor/aws-http/external-types.toml new file mode 100644 index 0000000000000..429bf1a909805 --- /dev/null +++ b/vendor/aws-http/external-types.toml @@ -0,0 +1,11 @@ +allowed_external_types = [ + "aws_smithy_runtime_api::http::headers::Headers", + "aws_smithy_types::body::Error", + "aws_smithy_types::config_bag::storable::Storable", + "aws_smithy_types::config_bag::storable::StoreReplace", + "aws_smithy_types::error::metadata::Builder", + "aws_types::app_name::AppName", + "aws_types::os_shim_internal::Env", + "bytes::bytes::Bytes", + "http_body::Body", +] diff --git a/vendor/aws-http/src/content_encoding.rs b/vendor/aws-http/src/content_encoding.rs new file mode 100644 index 0000000000000..dc9c62a1c7a4f --- /dev/null +++ b/vendor/aws-http/src/content_encoding.rs @@ -0,0 +1,613 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use bytes::{Bytes, BytesMut}; +use http::{HeaderMap, HeaderValue}; +use http_body::{Body, SizeHint}; +use pin_project_lite::pin_project; + +use std::pin::Pin; +use std::task::{Context, Poll}; + +const CRLF: &str = "\r\n"; +const CHUNK_TERMINATOR: &str = "0\r\n"; +const TRAILER_SEPARATOR: &[u8] = b":"; + +/// Content encoding header value constants +pub mod header_value { + /// Header value denoting "aws-chunked" encoding + pub const AWS_CHUNKED: &str = "aws-chunked"; +} + +/// Options used when constructing an [`AwsChunkedBody`][AwsChunkedBody]. +#[derive(Debug, Default)] +#[non_exhaustive] +pub struct AwsChunkedBodyOptions { + /// The total size of the stream. Because we only support unsigned encoding + /// this implies that there will only be a single chunk containing the + /// underlying payload. + stream_length: u64, + /// The length of each trailer sent within an `AwsChunkedBody`. Necessary in + /// order to correctly calculate the total size of the body accurately. + trailer_lengths: Vec, +} + +impl AwsChunkedBodyOptions { + /// Create a new [`AwsChunkedBodyOptions`][AwsChunkedBodyOptions] + pub fn new(stream_length: u64, trailer_lengths: Vec) -> Self { + Self { + stream_length, + trailer_lengths, + } + } + + fn total_trailer_length(&self) -> u64 { + self.trailer_lengths.iter().sum::() + // We need to account for a CRLF after each trailer name/value pair + + (self.trailer_lengths.len() * CRLF.len()) as u64 + } + + /// Set a trailer len + pub fn with_trailer_len(mut self, trailer_len: u64) -> Self { + self.trailer_lengths.push(trailer_len); + self + } +} + +#[derive(Debug, PartialEq, Eq)] +enum AwsChunkedBodyState { + /// Write out the size of the chunk that will follow. Then, transition into the + /// `WritingChunk` state. + WritingChunkSize, + /// Write out the next chunk of data. Multiple polls of the inner body may need to occur before + /// all data is written out. Once there is no more data to write, transition into the + /// `WritingTrailers` state. + WritingChunk, + /// Write out all trailers associated with this `AwsChunkedBody` and then transition into the + /// `Closed` state. + WritingTrailers, + /// This is the final state. Write out the body terminator and then remain in this state. + Closed, +} + +pin_project! { + /// A request body compatible with `Content-Encoding: aws-chunked`. This implementation is only + /// capable of writing a single chunk and does not support signed chunks. + /// + /// Chunked-Body grammar is defined in [ABNF] as: + /// + /// ```txt + /// Chunked-Body = *chunk + /// last-chunk + /// chunked-trailer + /// CRLF + /// + /// chunk = chunk-size CRLF chunk-data CRLF + /// chunk-size = 1*HEXDIG + /// last-chunk = 1*("0") CRLF + /// chunked-trailer = *( entity-header CRLF ) + /// entity-header = field-name ":" OWS field-value OWS + /// ``` + /// For more info on what the abbreviations mean, see https://datatracker.ietf.org/doc/html/rfc7230#section-1.2 + /// + /// [ABNF]:https://en.wikipedia.org/wiki/Augmented_Backus%E2%80%93Naur_form + #[derive(Debug)] + pub struct AwsChunkedBody { + #[pin] + inner: InnerBody, + #[pin] + state: AwsChunkedBodyState, + options: AwsChunkedBodyOptions, + inner_body_bytes_read_so_far: usize, + } +} + +impl AwsChunkedBody { + /// Wrap the given body in an outer body compatible with `Content-Encoding: aws-chunked` + pub fn new(body: Inner, options: AwsChunkedBodyOptions) -> Self { + Self { + inner: body, + state: AwsChunkedBodyState::WritingChunkSize, + options, + inner_body_bytes_read_so_far: 0, + } + } + + fn encoded_length(&self) -> u64 { + let mut length = 0; + if self.options.stream_length != 0 { + length += get_unsigned_chunk_bytes_length(self.options.stream_length); + } + + // End chunk + length += CHUNK_TERMINATOR.len() as u64; + + // Trailers + for len in self.options.trailer_lengths.iter() { + length += len + CRLF.len() as u64; + } + + // Encoding terminator + length += CRLF.len() as u64; + + length + } +} + +fn get_unsigned_chunk_bytes_length(payload_length: u64) -> u64 { + let hex_repr_len = int_log16(payload_length); + hex_repr_len + CRLF.len() as u64 + payload_length + CRLF.len() as u64 +} + +/// Writes trailers out into a `string` and then converts that `String` to a `Bytes` before +/// returning. +/// +/// - Trailer names are separated by a single colon only, no space. +/// - Trailer names with multiple values will be written out one line per value, with the name +/// appearing on each line. +fn trailers_as_aws_chunked_bytes( + trailer_map: Option, + estimated_length: u64, +) -> BytesMut { + if let Some(trailer_map) = trailer_map { + let mut current_header_name = None; + let mut trailers = BytesMut::with_capacity(estimated_length.try_into().unwrap_or_default()); + + for (header_name, header_value) in trailer_map.into_iter() { + // When a header has multiple values, the name only comes up in iteration the first time + // we see it. Therefore, we need to keep track of the last name we saw and fall back to + // it when `header_name == None`. + current_header_name = header_name.or(current_header_name); + + // In practice, this will always exist, but `if let` is nicer than unwrap + if let Some(header_name) = current_header_name.as_ref() { + trailers.extend_from_slice(header_name.as_ref()); + trailers.extend_from_slice(TRAILER_SEPARATOR); + trailers.extend_from_slice(header_value.as_bytes()); + trailers.extend_from_slice(CRLF.as_bytes()); + } + } + + trailers + } else { + BytesMut::new() + } +} + +/// Given an optional `HeaderMap`, calculate the total number of bytes required to represent the +/// `HeaderMap`. If no `HeaderMap` is given as input, return 0. +/// +/// - Trailer names are separated by a single colon only, no space. +/// - Trailer names with multiple values will be written out one line per value, with the name +/// appearing on each line. +fn total_rendered_length_of_trailers(trailer_map: Option<&HeaderMap>) -> u64 { + match trailer_map { + Some(trailer_map) => trailer_map + .iter() + .map(|(trailer_name, trailer_value)| { + trailer_name.as_str().len() + + TRAILER_SEPARATOR.len() + + trailer_value.len() + + CRLF.len() + }) + .sum::() as u64, + None => 0, + } +} + +impl Body for AwsChunkedBody +where + Inner: Body, +{ + type Data = Bytes; + type Error = aws_smithy_types::body::Error; + + fn poll_data( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll>> { + tracing::trace!(state = ?self.state, "polling AwsChunkedBody"); + let mut this = self.project(); + + match *this.state { + AwsChunkedBodyState::WritingChunkSize => { + if this.options.stream_length == 0 { + // If the stream is empty, we skip to writing trailers after writing the CHUNK_TERMINATOR. + *this.state = AwsChunkedBodyState::WritingTrailers; + tracing::trace!("stream is empty, writing chunk terminator"); + Poll::Ready(Some(Ok(Bytes::from([CHUNK_TERMINATOR].concat())))) + } else { + *this.state = AwsChunkedBodyState::WritingChunk; + // A chunk must be prefixed by chunk size in hexadecimal + let chunk_size = format!("{:X?}{CRLF}", this.options.stream_length); + tracing::trace!(%chunk_size, "writing chunk size"); + let chunk_size = Bytes::from(chunk_size); + Poll::Ready(Some(Ok(chunk_size))) + } + } + AwsChunkedBodyState::WritingChunk => match this.inner.poll_data(cx) { + Poll::Ready(Some(Ok(data))) => { + tracing::trace!(len = data.len(), "writing chunk data"); + *this.inner_body_bytes_read_so_far += data.len(); + Poll::Ready(Some(Ok(data))) + } + Poll::Ready(None) => { + let actual_stream_length = *this.inner_body_bytes_read_so_far as u64; + let expected_stream_length = this.options.stream_length; + if actual_stream_length != expected_stream_length { + let err = Box::new(AwsChunkedBodyError::StreamLengthMismatch { + actual: actual_stream_length, + expected: expected_stream_length, + }); + return Poll::Ready(Some(Err(err))); + }; + + tracing::trace!("no more chunk data, writing CRLF and chunk terminator"); + *this.state = AwsChunkedBodyState::WritingTrailers; + // Since we wrote chunk data, we end it with a CRLF and since we only write + // a single chunk, we write the CHUNK_TERMINATOR immediately after + Poll::Ready(Some(Ok(Bytes::from([CRLF, CHUNK_TERMINATOR].concat())))) + } + Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))), + Poll::Pending => Poll::Pending, + }, + AwsChunkedBodyState::WritingTrailers => { + return match this.inner.poll_trailers(cx) { + Poll::Ready(Ok(trailers)) => { + *this.state = AwsChunkedBodyState::Closed; + let expected_length = total_rendered_length_of_trailers(trailers.as_ref()); + let actual_length = this.options.total_trailer_length(); + + if expected_length != actual_length { + let err = + Box::new(AwsChunkedBodyError::ReportedTrailerLengthMismatch { + actual: actual_length, + expected: expected_length, + }); + return Poll::Ready(Some(Err(err))); + } + + let mut trailers = + trailers_as_aws_chunked_bytes(trailers, actual_length + 1); + // Insert the final CRLF to close the body + trailers.extend_from_slice(CRLF.as_bytes()); + + Poll::Ready(Some(Ok(trailers.into()))) + } + Poll::Pending => Poll::Pending, + Poll::Ready(Err(e)) => Poll::Ready(Some(Err(e))), + }; + } + AwsChunkedBodyState::Closed => Poll::Ready(None), + } + } + + fn poll_trailers( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll>, Self::Error>> { + // Trailers were already appended to the body because of the content encoding scheme + Poll::Ready(Ok(None)) + } + + fn is_end_stream(&self) -> bool { + self.state == AwsChunkedBodyState::Closed + } + + fn size_hint(&self) -> SizeHint { + SizeHint::with_exact(self.encoded_length()) + } +} + +/// Errors related to `AwsChunkedBody` +#[derive(Debug)] +enum AwsChunkedBodyError { + /// Error that occurs when the sum of `trailer_lengths` set when creating an `AwsChunkedBody` is + /// not equal to the actual length of the trailers returned by the inner `http_body::Body` + /// implementor. These trailer lengths are necessary in order to correctly calculate the total + /// size of the body for setting the content length header. + ReportedTrailerLengthMismatch { actual: u64, expected: u64 }, + /// Error that occurs when the `stream_length` set when creating an `AwsChunkedBody` is not + /// equal to the actual length of the body returned by the inner `http_body::Body` implementor. + /// `stream_length` must be correct in order to set an accurate content length header. + StreamLengthMismatch { actual: u64, expected: u64 }, +} + +impl std::fmt::Display for AwsChunkedBodyError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::ReportedTrailerLengthMismatch { actual, expected } => { + write!(f, "When creating this AwsChunkedBody, length of trailers was reported as {expected}. However, when double checking during trailer encoding, length was found to be {actual} instead.") + } + Self::StreamLengthMismatch { actual, expected } => { + write!(f, "When creating this AwsChunkedBody, stream length was reported as {expected}. However, when double checking during body encoding, length was found to be {actual} instead.") + } + } + } +} + +impl std::error::Error for AwsChunkedBodyError {} + +// Used for finding how many hexadecimal digits it takes to represent a base 10 integer +fn int_log16(mut i: T) -> u64 +where + T: std::ops::DivAssign + PartialOrd + From + Copy, +{ + let mut len = 0; + let zero = T::from(0); + let sixteen = T::from(16); + + while i > zero { + i /= sixteen; + len += 1; + } + + len +} + +#[cfg(test)] +mod tests { + use super::{ + total_rendered_length_of_trailers, trailers_as_aws_chunked_bytes, AwsChunkedBody, + AwsChunkedBodyOptions, CHUNK_TERMINATOR, CRLF, + }; + + use aws_smithy_types::body::SdkBody; + use bytes::{Buf, Bytes}; + use bytes_utils::SegmentedBuf; + use http::{HeaderMap, HeaderValue}; + use http_body::{Body, SizeHint}; + use pin_project_lite::pin_project; + + use std::io::Read; + use std::pin::Pin; + use std::task::{Context, Poll}; + use std::time::Duration; + + pin_project! { + struct SputteringBody { + parts: Vec>, + cursor: usize, + delay_in_millis: u64, + } + } + + impl SputteringBody { + fn len(&self) -> usize { + self.parts.iter().flatten().map(|b| b.len()).sum() + } + } + + impl Body for SputteringBody { + type Data = Bytes; + type Error = aws_smithy_types::body::Error; + + fn poll_data( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll>> { + if self.cursor == self.parts.len() { + return Poll::Ready(None); + } + + let this = self.project(); + let delay_in_millis = *this.delay_in_millis; + let next_part = this.parts.get_mut(*this.cursor).unwrap().take(); + + match next_part { + None => { + *this.cursor += 1; + let waker = cx.waker().clone(); + tokio::spawn(async move { + tokio::time::sleep(Duration::from_millis(delay_in_millis)).await; + waker.wake(); + }); + Poll::Pending + } + Some(data) => { + *this.cursor += 1; + Poll::Ready(Some(Ok(data))) + } + } + } + + fn poll_trailers( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll>, Self::Error>> { + Poll::Ready(Ok(None)) + } + + fn is_end_stream(&self) -> bool { + false + } + + fn size_hint(&self) -> SizeHint { + SizeHint::new() + } + } + + #[tokio::test] + async fn test_aws_chunked_encoding() { + let test_fut = async { + let input_str = "Hello world"; + let opts = AwsChunkedBodyOptions::new(input_str.len() as u64, Vec::new()); + let mut body = AwsChunkedBody::new(SdkBody::from(input_str), opts); + + let mut output = SegmentedBuf::new(); + while let Some(buf) = body.data().await { + output.push(buf.unwrap()); + } + + let mut actual_output = String::new(); + output + .reader() + .read_to_string(&mut actual_output) + .expect("Doesn't cause IO errors"); + + let expected_output = "B\r\nHello world\r\n0\r\n\r\n"; + + assert_eq!(expected_output, actual_output); + assert!( + body.trailers() + .await + .expect("no errors occurred during trailer polling") + .is_none(), + "aws-chunked encoded bodies don't have normal HTTP trailers" + ); + + // You can insert a `tokio::time::sleep` here to verify the timeout works as intended + }; + + let timeout_duration = Duration::from_secs(3); + if tokio::time::timeout(timeout_duration, test_fut) + .await + .is_err() + { + panic!("test_aws_chunked_encoding timed out after {timeout_duration:?}"); + } + } + + #[tokio::test] + async fn test_aws_chunked_encoding_sputtering_body() { + let test_fut = async { + let input = SputteringBody { + parts: vec![ + Some(Bytes::from_static(b"chunk 1, ")), + None, + Some(Bytes::from_static(b"chunk 2, ")), + Some(Bytes::from_static(b"chunk 3, ")), + None, + None, + Some(Bytes::from_static(b"chunk 4, ")), + Some(Bytes::from_static(b"chunk 5, ")), + Some(Bytes::from_static(b"chunk 6")), + ], + cursor: 0, + delay_in_millis: 500, + }; + let opts = AwsChunkedBodyOptions::new(input.len() as u64, Vec::new()); + let mut body = AwsChunkedBody::new(input, opts); + + let mut output = SegmentedBuf::new(); + while let Some(buf) = body.data().await { + output.push(buf.unwrap()); + } + + let mut actual_output = String::new(); + output + .reader() + .read_to_string(&mut actual_output) + .expect("Doesn't cause IO errors"); + + let expected_output = + "34\r\nchunk 1, chunk 2, chunk 3, chunk 4, chunk 5, chunk 6\r\n0\r\n\r\n"; + + assert_eq!(expected_output, actual_output); + assert!( + body.trailers() + .await + .expect("no errors occurred during trailer polling") + .is_none(), + "aws-chunked encoded bodies don't have normal HTTP trailers" + ); + }; + + let timeout_duration = Duration::from_secs(3); + if tokio::time::timeout(timeout_duration, test_fut) + .await + .is_err() + { + panic!( + "test_aws_chunked_encoding_sputtering_body timed out after {timeout_duration:?}" + ); + } + } + + #[tokio::test] + #[should_panic = "called `Result::unwrap()` on an `Err` value: ReportedTrailerLengthMismatch { actual: 44, expected: 0 }"] + async fn test_aws_chunked_encoding_incorrect_trailer_length_panic() { + let input_str = "Hello world"; + // Test body has no trailers, so this length is incorrect and will trigger an assert panic + // When the panic occurs, it will actually expect a length of 44. This is because, when using + // aws-chunked encoding, each trailer will end with a CRLF which is 2 bytes long. + let wrong_trailer_len = 42; + let opts = AwsChunkedBodyOptions::new(input_str.len() as u64, vec![wrong_trailer_len]); + let mut body = AwsChunkedBody::new(SdkBody::from(input_str), opts); + + // We don't care about the body contents but we have to read it all before checking for trailers + while let Some(buf) = body.data().await { + drop(buf.unwrap()); + } + + assert!( + body.trailers() + .await + .expect("no errors occurred during trailer polling") + .is_none(), + "aws-chunked encoded bodies don't have normal HTTP trailers" + ); + } + + #[tokio::test] + async fn test_aws_chunked_encoding_empty_body() { + let input_str = ""; + let opts = AwsChunkedBodyOptions::new(input_str.len() as u64, Vec::new()); + let mut body = AwsChunkedBody::new(SdkBody::from(input_str), opts); + + let mut output = SegmentedBuf::new(); + while let Some(buf) = body.data().await { + output.push(buf.unwrap()); + } + + let mut actual_output = String::new(); + output + .reader() + .read_to_string(&mut actual_output) + .expect("Doesn't cause IO errors"); + + let expected_output = [CHUNK_TERMINATOR, CRLF].concat(); + + assert_eq!(expected_output, actual_output); + assert!( + body.trailers() + .await + .expect("no errors occurred during trailer polling") + .is_none(), + "aws-chunked encoded bodies don't have normal HTTP trailers" + ); + } + + #[tokio::test] + async fn test_total_rendered_length_of_trailers() { + let mut trailers = HeaderMap::new(); + + trailers.insert("empty_value", HeaderValue::from_static("")); + + trailers.insert("single_value", HeaderValue::from_static("value 1")); + + trailers.insert("two_values", HeaderValue::from_static("value 1")); + trailers.append("two_values", HeaderValue::from_static("value 2")); + + trailers.insert("three_values", HeaderValue::from_static("value 1")); + trailers.append("three_values", HeaderValue::from_static("value 2")); + trailers.append("three_values", HeaderValue::from_static("value 3")); + + let trailers = Some(trailers); + let actual_length = total_rendered_length_of_trailers(trailers.as_ref()); + let expected_length = (trailers_as_aws_chunked_bytes(trailers, actual_length).len()) as u64; + + assert_eq!(expected_length, actual_length); + } + + #[tokio::test] + async fn test_total_rendered_length_of_empty_trailers() { + let trailers = Some(HeaderMap::new()); + let actual_length = total_rendered_length_of_trailers(trailers.as_ref()); + let expected_length = (trailers_as_aws_chunked_bytes(trailers, actual_length).len()) as u64; + + assert_eq!(expected_length, actual_length); + } +} diff --git a/vendor/aws-http/src/lib.rs b/vendor/aws-http/src/lib.rs new file mode 100644 index 0000000000000..a5a670988c434 --- /dev/null +++ b/vendor/aws-http/src/lib.rs @@ -0,0 +1,21 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! AWS-specific middleware implementations and HTTP-related features. + +#![allow(clippy::derive_partial_eq_without_eq)] +#![warn( + missing_docs, + rustdoc::missing_crate_level_docs, + missing_debug_implementations, + rust_2018_idioms, + unreachable_pub +)] + +/// User agent middleware +pub mod user_agent; + +/// AWS-specific content-encoding tools +pub mod content_encoding; diff --git a/vendor/aws-http/src/user_agent.rs b/vendor/aws-http/src/user_agent.rs new file mode 100644 index 0000000000000..1e26da4d4e68b --- /dev/null +++ b/vendor/aws-http/src/user_agent.rs @@ -0,0 +1,711 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use aws_smithy_types::config_bag::{Storable, StoreReplace}; +use aws_types::app_name::AppName; +use aws_types::build_metadata::{OsFamily, BUILD_METADATA}; +use aws_types::os_shim_internal::Env; +use std::borrow::Cow; +use std::error::Error; +use std::fmt; + +/// AWS User Agent +/// +/// Ths struct should be inserted into the [`ConfigBag`](aws_smithy_types::config_bag::ConfigBag) +/// during operation construction. The `UserAgentInterceptor` reads `AwsUserAgent` +/// from the config bag and sets the `User-Agent` and `x-amz-user-agent` headers. +#[derive(Clone, Debug)] +pub struct AwsUserAgent { + sdk_metadata: SdkMetadata, + api_metadata: ApiMetadata, + os_metadata: OsMetadata, + language_metadata: LanguageMetadata, + exec_env_metadata: Option, + feature_metadata: Vec, + config_metadata: Vec, + framework_metadata: Vec, + app_name: Option, +} + +impl AwsUserAgent { + /// Load a User Agent configuration from the environment + /// + /// This utilizes [`BUILD_METADATA`](const@aws_types::build_metadata::BUILD_METADATA) from `aws_types` + /// to capture the Rust version & target platform. `ApiMetadata` provides + /// the version & name of the specific service. + pub fn new_from_environment(env: Env, api_metadata: ApiMetadata) -> Self { + let build_metadata = &BUILD_METADATA; + let sdk_metadata = SdkMetadata { + name: "rust", + version: build_metadata.core_pkg_version, + }; + let os_metadata = OsMetadata { + os_family: &build_metadata.os_family, + version: None, + }; + let exec_env_metadata = env + .get("AWS_EXECUTION_ENV") + .ok() + .map(|name| ExecEnvMetadata { name }); + AwsUserAgent { + sdk_metadata, + api_metadata, + os_metadata, + language_metadata: LanguageMetadata { + lang: "rust", + version: BUILD_METADATA.rust_version, + extras: Default::default(), + }, + exec_env_metadata, + feature_metadata: Default::default(), + config_metadata: Default::default(), + framework_metadata: Default::default(), + app_name: Default::default(), + } + } + + /// For test purposes, construct an environment-independent User Agent + /// + /// Without this, running CI on a different platform would produce different user agent strings + pub fn for_tests() -> Self { + Self { + sdk_metadata: SdkMetadata { + name: "rust", + version: "0.123.test", + }, + api_metadata: ApiMetadata { + service_id: "test-service".into(), + version: "0.123", + }, + os_metadata: OsMetadata { + os_family: &OsFamily::Windows, + version: Some("XPSP3".to_string()), + }, + language_metadata: LanguageMetadata { + lang: "rust", + version: "1.50.0", + extras: Default::default(), + }, + exec_env_metadata: None, + feature_metadata: Vec::new(), + config_metadata: Vec::new(), + framework_metadata: Vec::new(), + app_name: None, + } + } + + #[doc(hidden)] + /// Adds feature metadata to the user agent. + pub fn with_feature_metadata(mut self, metadata: FeatureMetadata) -> Self { + self.feature_metadata.push(metadata); + self + } + + #[doc(hidden)] + /// Adds feature metadata to the user agent. + pub fn add_feature_metadata(&mut self, metadata: FeatureMetadata) -> &mut Self { + self.feature_metadata.push(metadata); + self + } + + #[doc(hidden)] + /// Adds config metadata to the user agent. + pub fn with_config_metadata(mut self, metadata: ConfigMetadata) -> Self { + self.config_metadata.push(metadata); + self + } + + #[doc(hidden)] + /// Adds config metadata to the user agent. + pub fn add_config_metadata(&mut self, metadata: ConfigMetadata) -> &mut Self { + self.config_metadata.push(metadata); + self + } + + #[doc(hidden)] + /// Adds framework metadata to the user agent. + pub fn with_framework_metadata(mut self, metadata: FrameworkMetadata) -> Self { + self.framework_metadata.push(metadata); + self + } + + #[doc(hidden)] + /// Adds framework metadata to the user agent. + pub fn add_framework_metadata(&mut self, metadata: FrameworkMetadata) -> &mut Self { + self.framework_metadata.push(metadata); + self + } + + /// Sets the app name for the user agent. + pub fn with_app_name(mut self, app_name: AppName) -> Self { + self.app_name = Some(app_name); + self + } + + /// Sets the app name for the user agent. + pub fn set_app_name(&mut self, app_name: AppName) -> &mut Self { + self.app_name = Some(app_name); + self + } + + /// Generate a new-style user agent style header + /// + /// This header should be set at `x-amz-user-agent` + pub fn aws_ua_header(&self) -> String { + /* + ABNF for the user agent (see the bottom of the file for complete ABNF): + ua-string = sdk-metadata RWS + [api-metadata RWS] + os-metadata RWS + language-metadata RWS + [env-metadata RWS] + *(feat-metadata RWS) + *(config-metadata RWS) + *(framework-metadata RWS) + [appId] + */ + let mut ua_value = String::new(); + use std::fmt::Write; + // unwrap calls should never fail because string formatting will always succeed. + write!(ua_value, "{} ", &self.sdk_metadata).unwrap(); + write!(ua_value, "{} ", &self.api_metadata).unwrap(); + write!(ua_value, "{} ", &self.os_metadata).unwrap(); + write!(ua_value, "{} ", &self.language_metadata).unwrap(); + if let Some(ref env_meta) = self.exec_env_metadata { + write!(ua_value, "{} ", env_meta).unwrap(); + } + for feature in &self.feature_metadata { + write!(ua_value, "{} ", feature).unwrap(); + } + for config in &self.config_metadata { + write!(ua_value, "{} ", config).unwrap(); + } + for framework in &self.framework_metadata { + write!(ua_value, "{} ", framework).unwrap(); + } + if let Some(app_name) = &self.app_name { + write!(ua_value, "app/{}", app_name).unwrap(); + } + if ua_value.ends_with(' ') { + ua_value.truncate(ua_value.len() - 1); + } + ua_value + } + + /// Generate an old-style User-Agent header for backward compatibility + /// + /// This header is intended to be set at `User-Agent` + pub fn ua_header(&self) -> String { + let mut ua_value = String::new(); + use std::fmt::Write; + write!(ua_value, "{} ", &self.sdk_metadata).unwrap(); + write!(ua_value, "{} ", &self.os_metadata).unwrap(); + write!(ua_value, "{}", &self.language_metadata).unwrap(); + ua_value + } +} + +impl Storable for AwsUserAgent { + type Storer = StoreReplace; +} + +#[derive(Clone, Copy, Debug)] +struct SdkMetadata { + name: &'static str, + version: &'static str, +} + +impl fmt::Display for SdkMetadata { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "aws-sdk-{}/{}", self.name, self.version) + } +} + +/// Metadata about the client that's making the call. +#[derive(Clone, Debug)] +pub struct ApiMetadata { + service_id: Cow<'static, str>, + version: &'static str, +} + +impl ApiMetadata { + /// Creates new `ApiMetadata`. + pub const fn new(service_id: &'static str, version: &'static str) -> Self { + Self { + service_id: Cow::Borrowed(service_id), + version, + } + } +} + +impl fmt::Display for ApiMetadata { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "api/{}/{}", self.service_id, self.version) + } +} + +impl Storable for ApiMetadata { + type Storer = StoreReplace; +} + +/// Error for when an user agent metadata doesn't meet character requirements. +/// +/// Metadata may only have alphanumeric characters and any of these characters: +/// ```text +/// !#$%&'*+-.^_`|~ +/// ``` +/// Spaces are not allowed. +#[derive(Debug)] +#[non_exhaustive] +pub struct InvalidMetadataValue; + +impl Error for InvalidMetadataValue {} + +impl fmt::Display for InvalidMetadataValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "User agent metadata can only have alphanumeric characters, or any of \ + '!' | '#' | '$' | '%' | '&' | '\\'' | '*' | '+' | '-' | \ + '.' | '^' | '_' | '`' | '|' | '~'" + ) + } +} + +fn validate_metadata(value: Cow<'static, str>) -> Result, InvalidMetadataValue> { + fn valid_character(c: char) -> bool { + match c { + _ if c.is_ascii_alphanumeric() => true, + '!' | '#' | '$' | '%' | '&' | '\'' | '*' | '+' | '-' | '.' | '^' | '_' | '`' | '|' + | '~' => true, + _ => false, + } + } + if !value.chars().all(valid_character) { + return Err(InvalidMetadataValue); + } + Ok(value) +} + +#[doc(hidden)] +/// Additional metadata that can be bundled with framework or feature metadata. +#[derive(Clone, Debug)] +#[non_exhaustive] +pub struct AdditionalMetadata { + value: Cow<'static, str>, +} + +impl AdditionalMetadata { + /// Creates `AdditionalMetadata`. + /// + /// This will result in `InvalidMetadataValue` if the given value isn't alphanumeric or + /// has characters other than the following: + /// ```text + /// !#$%&'*+-.^_`|~ + /// ``` + pub fn new(value: impl Into>) -> Result { + Ok(Self { + value: validate_metadata(value.into())?, + }) + } +} + +impl fmt::Display for AdditionalMetadata { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // additional-metadata = "md/" ua-pair + write!(f, "md/{}", self.value) + } +} + +#[derive(Clone, Debug, Default)] +struct AdditionalMetadataList(Vec); + +impl AdditionalMetadataList { + fn push(&mut self, metadata: AdditionalMetadata) { + self.0.push(metadata); + } +} + +impl fmt::Display for AdditionalMetadataList { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for metadata in &self.0 { + write!(f, " {}", metadata)?; + } + Ok(()) + } +} + +#[doc(hidden)] +/// Metadata about a feature that is being used in the SDK. +#[derive(Clone, Debug)] +#[non_exhaustive] +pub struct FeatureMetadata { + name: Cow<'static, str>, + version: Option>, + additional: AdditionalMetadataList, +} + +impl FeatureMetadata { + /// Creates `FeatureMetadata`. + /// + /// This will result in `InvalidMetadataValue` if the given value isn't alphanumeric or + /// has characters other than the following: + /// ```text + /// !#$%&'*+-.^_`|~ + /// ``` + pub fn new( + name: impl Into>, + version: Option>, + ) -> Result { + Ok(Self { + name: validate_metadata(name.into())?, + version: version.map(validate_metadata).transpose()?, + additional: Default::default(), + }) + } + + /// Bundles additional arbitrary metadata with this feature metadata. + pub fn with_additional(mut self, metadata: AdditionalMetadata) -> Self { + self.additional.push(metadata); + self + } +} + +impl fmt::Display for FeatureMetadata { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // feat-metadata = "ft/" name ["/" version] *(RWS additional-metadata) + if let Some(version) = &self.version { + write!(f, "ft/{}/{}{}", self.name, version, self.additional) + } else { + write!(f, "ft/{}{}", self.name, self.additional) + } + } +} + +#[doc(hidden)] +/// Metadata about a config value that is being used in the SDK. +#[derive(Clone, Debug)] +#[non_exhaustive] +pub struct ConfigMetadata { + config: Cow<'static, str>, + value: Option>, +} + +impl ConfigMetadata { + /// Creates `ConfigMetadata`. + /// + /// This will result in `InvalidMetadataValue` if the given value isn't alphanumeric or + /// has characters other than the following: + /// ```text + /// !#$%&'*+-.^_`|~ + /// ``` + pub fn new( + config: impl Into>, + value: Option>, + ) -> Result { + Ok(Self { + config: validate_metadata(config.into())?, + value: value.map(validate_metadata).transpose()?, + }) + } +} + +impl fmt::Display for ConfigMetadata { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // config-metadata = "cfg/" config ["/" value] + if let Some(value) = &self.value { + write!(f, "cfg/{}/{}", self.config, value) + } else { + write!(f, "cfg/{}", self.config) + } + } +} + +#[doc(hidden)] +/// Metadata about a software framework that is being used with the SDK. +#[derive(Clone, Debug)] +#[non_exhaustive] +pub struct FrameworkMetadata { + name: Cow<'static, str>, + version: Option>, + additional: AdditionalMetadataList, +} + +impl FrameworkMetadata { + /// Creates `FrameworkMetadata`. + /// + /// This will result in `InvalidMetadataValue` if the given value isn't alphanumeric or + /// has characters other than the following: + /// ```text + /// !#$%&'*+-.^_`|~ + /// ``` + pub fn new( + name: impl Into>, + version: Option>, + ) -> Result { + Ok(Self { + name: validate_metadata(name.into())?, + version: version.map(validate_metadata).transpose()?, + additional: Default::default(), + }) + } + + /// Bundles additional arbitrary metadata with this framework metadata. + pub fn with_additional(mut self, metadata: AdditionalMetadata) -> Self { + self.additional.push(metadata); + self + } +} + +impl fmt::Display for FrameworkMetadata { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // framework-metadata = "lib/" name ["/" version] *(RWS additional-metadata) + if let Some(version) = &self.version { + write!(f, "lib/{}/{}{}", self.name, version, self.additional) + } else { + write!(f, "lib/{}{}", self.name, self.additional) + } + } +} + +#[derive(Clone, Debug)] +struct OsMetadata { + os_family: &'static OsFamily, + version: Option, +} + +impl fmt::Display for OsMetadata { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let os_family = match self.os_family { + OsFamily::Windows => "windows", + OsFamily::Linux => "linux", + OsFamily::Macos => "macos", + OsFamily::Android => "android", + OsFamily::Ios => "ios", + OsFamily::Other => "other", + }; + write!(f, "os/{}", os_family)?; + if let Some(ref version) = self.version { + write!(f, "/{}", version)?; + } + Ok(()) + } +} + +#[derive(Clone, Debug)] +struct LanguageMetadata { + lang: &'static str, + version: &'static str, + extras: AdditionalMetadataList, +} +impl fmt::Display for LanguageMetadata { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // language-metadata = "lang/" language "/" version *(RWS additional-metadata) + write!(f, "lang/{}/{}{}", self.lang, self.version, self.extras) + } +} + +#[derive(Clone, Debug)] +struct ExecEnvMetadata { + name: String, +} +impl fmt::Display for ExecEnvMetadata { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "exec-env/{}", &self.name) + } +} + +#[cfg(test)] +mod test { + use super::*; + use aws_types::app_name::AppName; + use aws_types::build_metadata::OsFamily; + use aws_types::os_shim_internal::Env; + use std::borrow::Cow; + + fn make_deterministic(ua: &mut AwsUserAgent) { + // hard code some variable things for a deterministic test + ua.sdk_metadata.version = "0.1"; + ua.language_metadata.version = "1.50.0"; + ua.os_metadata.os_family = &OsFamily::Macos; + ua.os_metadata.version = Some("1.15".to_string()); + } + + #[test] + fn generate_a_valid_ua() { + let api_metadata = ApiMetadata { + service_id: "dynamodb".into(), + version: "123", + }; + let mut ua = AwsUserAgent::new_from_environment(Env::from_slice(&[]), api_metadata); + make_deterministic(&mut ua); + assert_eq!( + ua.aws_ua_header(), + "aws-sdk-rust/0.1 api/dynamodb/123 os/macos/1.15 lang/rust/1.50.0" + ); + assert_eq!( + ua.ua_header(), + "aws-sdk-rust/0.1 os/macos/1.15 lang/rust/1.50.0" + ); + } + + #[test] + fn generate_a_valid_ua_with_execution_env() { + let api_metadata = ApiMetadata { + service_id: "dynamodb".into(), + version: "123", + }; + let mut ua = AwsUserAgent::new_from_environment( + Env::from_slice(&[("AWS_EXECUTION_ENV", "lambda")]), + api_metadata, + ); + make_deterministic(&mut ua); + assert_eq!( + ua.aws_ua_header(), + "aws-sdk-rust/0.1 api/dynamodb/123 os/macos/1.15 lang/rust/1.50.0 exec-env/lambda" + ); + assert_eq!( + ua.ua_header(), + "aws-sdk-rust/0.1 os/macos/1.15 lang/rust/1.50.0" + ); + } + + #[test] + fn generate_a_valid_ua_with_features() { + let api_metadata = ApiMetadata { + service_id: "dynamodb".into(), + version: "123", + }; + let mut ua = AwsUserAgent::new_from_environment(Env::from_slice(&[]), api_metadata) + .with_feature_metadata( + FeatureMetadata::new("test-feature", Some(Cow::Borrowed("1.0"))).unwrap(), + ) + .with_feature_metadata( + FeatureMetadata::new("other-feature", None) + .unwrap() + .with_additional(AdditionalMetadata::new("asdf").unwrap()), + ); + make_deterministic(&mut ua); + assert_eq!( + ua.aws_ua_header(), + "aws-sdk-rust/0.1 api/dynamodb/123 os/macos/1.15 lang/rust/1.50.0 ft/test-feature/1.0 ft/other-feature md/asdf" + ); + assert_eq!( + ua.ua_header(), + "aws-sdk-rust/0.1 os/macos/1.15 lang/rust/1.50.0" + ); + } + + #[test] + fn generate_a_valid_ua_with_config() { + let api_metadata = ApiMetadata { + service_id: "dynamodb".into(), + version: "123", + }; + let mut ua = AwsUserAgent::new_from_environment(Env::from_slice(&[]), api_metadata) + .with_config_metadata( + ConfigMetadata::new("some-config", Some(Cow::Borrowed("5"))).unwrap(), + ) + .with_config_metadata(ConfigMetadata::new("other-config", None).unwrap()); + make_deterministic(&mut ua); + assert_eq!( + ua.aws_ua_header(), + "aws-sdk-rust/0.1 api/dynamodb/123 os/macos/1.15 lang/rust/1.50.0 cfg/some-config/5 cfg/other-config" + ); + assert_eq!( + ua.ua_header(), + "aws-sdk-rust/0.1 os/macos/1.15 lang/rust/1.50.0" + ); + } + + #[test] + fn generate_a_valid_ua_with_frameworks() { + let api_metadata = ApiMetadata { + service_id: "dynamodb".into(), + version: "123", + }; + let mut ua = AwsUserAgent::new_from_environment(Env::from_slice(&[]), api_metadata) + .with_framework_metadata( + FrameworkMetadata::new("some-framework", Some(Cow::Borrowed("1.3"))) + .unwrap() + .with_additional(AdditionalMetadata::new("something").unwrap()), + ) + .with_framework_metadata(FrameworkMetadata::new("other", None).unwrap()); + make_deterministic(&mut ua); + assert_eq!( + ua.aws_ua_header(), + "aws-sdk-rust/0.1 api/dynamodb/123 os/macos/1.15 lang/rust/1.50.0 lib/some-framework/1.3 md/something lib/other" + ); + assert_eq!( + ua.ua_header(), + "aws-sdk-rust/0.1 os/macos/1.15 lang/rust/1.50.0" + ); + } + + #[test] + fn generate_a_valid_ua_with_app_name() { + let api_metadata = ApiMetadata { + service_id: "dynamodb".into(), + version: "123", + }; + let mut ua = AwsUserAgent::new_from_environment(Env::from_slice(&[]), api_metadata) + .with_app_name(AppName::new("my_app").unwrap()); + make_deterministic(&mut ua); + assert_eq!( + ua.aws_ua_header(), + "aws-sdk-rust/0.1 api/dynamodb/123 os/macos/1.15 lang/rust/1.50.0 app/my_app" + ); + assert_eq!( + ua.ua_header(), + "aws-sdk-rust/0.1 os/macos/1.15 lang/rust/1.50.0" + ); + } +} + +/* +Appendix: User Agent ABNF +sdk-ua-header = "x-amz-user-agent:" OWS ua-string OWS +ua-pair = ua-name ["/" ua-value] +ua-name = token +ua-value = token +version = token +name = token +service-id = token +sdk-name = java / ruby / php / dotnet / python / cli / kotlin / rust / js / cpp / go / go-v2 +os-family = windows / linux / macos / android / ios / other +config = retry-mode +additional-metadata = "md/" ua-pair +sdk-metadata = "aws-sdk-" sdk-name "/" version +api-metadata = "api/" service-id "/" version +os-metadata = "os/" os-family ["/" version] +language-metadata = "lang/" language "/" version *(RWS additional-metadata) +env-metadata = "exec-env/" name +feat-metadata = "ft/" name ["/" version] *(RWS additional-metadata) +config-metadata = "cfg/" config ["/" value] +framework-metadata = "lib/" name ["/" version] *(RWS additional-metadata) +appId = "app/" name +ua-string = sdk-metadata RWS + [api-metadata RWS] + os-metadata RWS + language-metadata RWS + [env-metadata RWS] + *(feat-metadata RWS) + *(config-metadata RWS) + *(framework-metadata RWS) + [appId] + +# New metadata field might be added in the future and they must follow this format +prefix = token +metadata = prefix "/" ua-pair + +# token, RWS and OWS are defined in [RFC 7230](https://tools.ietf.org/html/rfc7230) +OWS = *( SP / HTAB ) + ; optional whitespace +RWS = 1*( SP / HTAB ) + ; required whitespace +token = 1*tchar +tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / + "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA +*/ diff --git a/vendor/aws-http/test-data/recursion-detection.json b/vendor/aws-http/test-data/recursion-detection.json new file mode 100644 index 0000000000000..59a44307f7b1e --- /dev/null +++ b/vendor/aws-http/test-data/recursion-detection.json @@ -0,0 +1,71 @@ +[ + { + "env": {}, + "requestHeadersBefore": [], + "requestHeadersAfter": [], + "description": [ + "The AWS_LAMBDA_FUNCTION_NAME and _X_AMZN_TRACE_ID environment variables are not set.", + "There should be no X-Amzn-Trace-Id header sent." + ] + }, + { + "env": { + "AWS_LAMBDA_FUNCTION_NAME": "some-function", + "_X_AMZN_TRACE_ID": "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1;lineage=a87bd80c:0,68fd508a:5,c512fbe3:2" + }, + "requestHeadersBefore": [], + "requestHeadersAfter": [ + "X-Amzn-Trace-Id: Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1;lineage=a87bd80c:0,68fd508a:5,c512fbe3:2" + ], + "description": [ + "AWS_LAMBDA_FUNCTION_NAME is set, and", + "_X_AMZN_TRACE_ID is set to \"Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1;lineage=a87bd80c:0,68fd508a:5,c512fbe3:2\".", + "The X-Amzn-Trace-Id header should be sent with that value." + ] + }, + { + "env": { + "_X_AMZN_TRACE_ID": "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1;lineage=a87bd80c:0,68fd508a:5,c512fbe3:2" + }, + "requestHeadersBefore": [], + "requestHeadersAfter": [], + "description": [ + "AWS_LAMBDA_FUNCTION_NAME is NOT set, and", + "_X_AMZN_TRACE_ID is set to \"Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1;lineage=a87bd80c:0,68fd508a:5,c512fbe3:2\".", + "The X-Amzn-Trace-Id header should NOT be sent with that value." + ] + }, + { + "env": { + "AWS_LAMBDA_FUNCTION_NAME": "some-function", + "_X_AMZN_TRACE_ID": "EnvValue" + }, + "requestHeadersBefore": [ + "X-Amzn-Trace-Id: OriginalValue" + ], + "requestHeadersAfter": [ + "X-Amzn-Trace-Id: OriginalValue" + ], + "desciption": [ + "AWS_LAMBDA_FUNCTION_NAME is set, and", + "_X_AMZN_TRACE_ID is set to \"EnvValue\",", + "but the X-Amzn-Trace-Id header is already set on the request.", + "The X-Amzn-Trace-Id header should keep its original value." + ] + }, + { + "env": { + "AWS_LAMBDA_FUNCTION_NAME": "some-function", + "_X_AMZN_TRACE_ID": "first\nsecond¼\t" + }, + "requestHeadersBefore": [], + "requestHeadersAfter": [ + "X-Amzn-Trace-Id: first%0Asecond%C2%BC%09" + ], + "description": [ + "AWS_LAMBDA_FUNCTION_NAME is set, and", + "_X_AMZN_TRACE_ID has ASCII control characters in it.", + "The X-Amzn-Trace-Id header is added with the control characters percent encoded." + ] + } +] diff --git a/vendor/aws-sdk-s3/tests/user-agent-app-name.rs b/vendor/aws-sdk-s3/tests/user-agent-app-name.rs new file mode 100644 index 0000000000000..c9cb041bbdc62 --- /dev/null +++ b/vendor/aws-sdk-s3/tests/user-agent-app-name.rs @@ -0,0 +1,39 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use aws_config::SdkConfig; +use aws_credential_types::provider::SharedCredentialsProvider; +use aws_sdk_s3::config::{AppName, Credentials, Region}; +use aws_sdk_s3::Client; +use aws_smithy_runtime::client::http::test_util::capture_request; + +#[tokio::test] +async fn user_agent_app_name() { + let (http_client, rcvr) = capture_request(None); + let sdk_config = SdkConfig::builder() + .credentials_provider(SharedCredentialsProvider::new(Credentials::for_tests())) + .region(Region::new("us-east-1")) + .http_client(http_client.clone()) + .app_name(AppName::new("test-app-name").expect("valid app name")) // set app name in config + .build(); + let client = Client::new(&sdk_config); + let _ = client.list_objects_v2().bucket("test-bucket").send().await; + + // verify app name made it to the user agent + let request = rcvr.expect_request(); + let formatted = std::str::from_utf8( + request + .headers() + .get("x-amz-user-agent") + .unwrap() + .as_bytes(), + ) + .unwrap(); + assert!( + formatted.ends_with(" app/test-app-name"), + "'{}' didn't end with the app name", + formatted + ); +} diff --git a/vendor/backtrace/src/android-api.c b/vendor/backtrace/src/android-api.c new file mode 100644 index 0000000000000..1bfeadf5b6343 --- /dev/null +++ b/vendor/backtrace/src/android-api.c @@ -0,0 +1,4 @@ +// Used from the build script to detect the value of the `__ANDROID_API__` +// builtin #define + +APIVERSION __ANDROID_API__ diff --git a/vendor/backtrace/src/backtrace/dbghelp.rs b/vendor/backtrace/src/backtrace/dbghelp.rs new file mode 100644 index 0000000000000..ba0f05f3b25d6 --- /dev/null +++ b/vendor/backtrace/src/backtrace/dbghelp.rs @@ -0,0 +1,257 @@ +//! Backtrace strategy for MSVC platforms. +//! +//! This module contains the ability to generate a backtrace on MSVC using one +//! of two possible methods. The `StackWalkEx` function is primarily used if +//! possible, but not all systems have that. Failing that the `StackWalk64` +//! function is used instead. Note that `StackWalkEx` is favored because it +//! handles debuginfo internally and returns inline frame information. +//! +//! Note that all dbghelp support is loaded dynamically, see `src/dbghelp.rs` +//! for more information about that. + +#![allow(bad_style)] + +use super::super::{dbghelp, windows::*}; +use core::ffi::c_void; +use core::mem; + +#[derive(Clone, Copy)] +pub enum StackFrame { + New(STACKFRAME_EX), + Old(STACKFRAME64), +} + +#[derive(Clone, Copy)] +pub struct Frame { + pub(crate) stack_frame: StackFrame, + base_address: *mut c_void, +} + +// we're just sending around raw pointers and reading them, never interpreting +// them so this should be safe to both send and share across threads. +unsafe impl Send for Frame {} +unsafe impl Sync for Frame {} + +impl Frame { + pub fn ip(&self) -> *mut c_void { + self.addr_pc().Offset as *mut _ + } + + pub fn sp(&self) -> *mut c_void { + self.addr_stack().Offset as *mut _ + } + + pub fn symbol_address(&self) -> *mut c_void { + self.ip() + } + + pub fn module_base_address(&self) -> Option<*mut c_void> { + Some(self.base_address) + } + + fn addr_pc(&self) -> &ADDRESS64 { + match self.stack_frame { + StackFrame::New(ref new) => &new.AddrPC, + StackFrame::Old(ref old) => &old.AddrPC, + } + } + + fn addr_pc_mut(&mut self) -> &mut ADDRESS64 { + match self.stack_frame { + StackFrame::New(ref mut new) => &mut new.AddrPC, + StackFrame::Old(ref mut old) => &mut old.AddrPC, + } + } + + fn addr_frame_mut(&mut self) -> &mut ADDRESS64 { + match self.stack_frame { + StackFrame::New(ref mut new) => &mut new.AddrFrame, + StackFrame::Old(ref mut old) => &mut old.AddrFrame, + } + } + + fn addr_stack(&self) -> &ADDRESS64 { + match self.stack_frame { + StackFrame::New(ref new) => &new.AddrStack, + StackFrame::Old(ref old) => &old.AddrStack, + } + } + + fn addr_stack_mut(&mut self) -> &mut ADDRESS64 { + match self.stack_frame { + StackFrame::New(ref mut new) => &mut new.AddrStack, + StackFrame::Old(ref mut old) => &mut old.AddrStack, + } + } +} + +#[repr(C, align(16))] // required by `CONTEXT`, is a FIXME in winapi right now +struct MyContext(CONTEXT); + +#[inline(always)] +pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) { + // Allocate necessary structures for doing the stack walk + let process = GetCurrentProcess(); + let thread = GetCurrentThread(); + + let mut context = mem::zeroed::(); + RtlCaptureContext(&mut context.0); + + // Ensure this process's symbols are initialized + let dbghelp = match dbghelp::init() { + Ok(dbghelp) => dbghelp, + Err(()) => return, // oh well... + }; + + // On x86_64 and ARM64 we opt to not use the default `Sym*` functions from + // dbghelp for getting the function table and module base. Instead we use + // the `RtlLookupFunctionEntry` function in kernel32 which will account for + // JIT compiler frames as well. These should be equivalent, but using + // `Rtl*` allows us to backtrace through JIT frames. + // + // Note that `RtlLookupFunctionEntry` only works for in-process backtraces, + // but that's all we support anyway, so it all lines up well. + cfg_if::cfg_if! { + if #[cfg(target_pointer_width = "64")] { + use core::ptr; + + unsafe extern "system" fn function_table_access(_process: HANDLE, addr: DWORD64) -> PVOID { + let mut base = 0; + RtlLookupFunctionEntry(addr, &mut base, ptr::null_mut()).cast() + } + + unsafe extern "system" fn get_module_base(_process: HANDLE, addr: DWORD64) -> DWORD64 { + let mut base = 0; + RtlLookupFunctionEntry(addr, &mut base, ptr::null_mut()); + base + } + } else { + let function_table_access = dbghelp.SymFunctionTableAccess64(); + let get_module_base = dbghelp.SymGetModuleBase64(); + } + } + + let process_handle = GetCurrentProcess(); + + // Attempt to use `StackWalkEx` if we can, but fall back to `StackWalk64` + // since it's in theory supported on more systems. + match (*dbghelp.dbghelp()).StackWalkEx() { + Some(StackWalkEx) => { + let mut inner: STACKFRAME_EX = mem::zeroed(); + inner.StackFrameSize = mem::size_of::() as DWORD; + let mut frame = super::Frame { + inner: Frame { + stack_frame: StackFrame::New(inner), + base_address: 0 as _, + }, + }; + let image = init_frame(&mut frame.inner, &context.0); + let frame_ptr = match &mut frame.inner.stack_frame { + StackFrame::New(ptr) => ptr as *mut STACKFRAME_EX, + _ => unreachable!(), + }; + + while StackWalkEx( + image as DWORD, + process, + thread, + frame_ptr, + &mut context.0 as *mut CONTEXT as *mut _, + None, + Some(function_table_access), + Some(get_module_base), + None, + 0, + ) == TRUE + { + frame.inner.base_address = get_module_base(process_handle, frame.ip() as _) as _; + + if !cb(&frame) { + break; + } + } + } + None => { + let mut frame = super::Frame { + inner: Frame { + stack_frame: StackFrame::Old(mem::zeroed()), + base_address: 0 as _, + }, + }; + let image = init_frame(&mut frame.inner, &context.0); + let frame_ptr = match &mut frame.inner.stack_frame { + StackFrame::Old(ptr) => ptr as *mut STACKFRAME64, + _ => unreachable!(), + }; + + while dbghelp.StackWalk64()( + image as DWORD, + process, + thread, + frame_ptr, + &mut context.0 as *mut CONTEXT as *mut _, + None, + Some(function_table_access), + Some(get_module_base), + None, + ) == TRUE + { + frame.inner.base_address = get_module_base(process_handle, frame.ip() as _) as _; + + if !cb(&frame) { + break; + } + } + } + } +} + +#[cfg(target_arch = "x86_64")] +fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD { + frame.addr_pc_mut().Offset = ctx.Rip as u64; + frame.addr_pc_mut().Mode = AddrModeFlat; + frame.addr_stack_mut().Offset = ctx.Rsp as u64; + frame.addr_stack_mut().Mode = AddrModeFlat; + frame.addr_frame_mut().Offset = ctx.Rbp as u64; + frame.addr_frame_mut().Mode = AddrModeFlat; + + IMAGE_FILE_MACHINE_AMD64 +} + +#[cfg(target_arch = "x86")] +fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD { + frame.addr_pc_mut().Offset = ctx.Eip as u64; + frame.addr_pc_mut().Mode = AddrModeFlat; + frame.addr_stack_mut().Offset = ctx.Esp as u64; + frame.addr_stack_mut().Mode = AddrModeFlat; + frame.addr_frame_mut().Offset = ctx.Ebp as u64; + frame.addr_frame_mut().Mode = AddrModeFlat; + + IMAGE_FILE_MACHINE_I386 +} + +#[cfg(target_arch = "aarch64")] +fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD { + frame.addr_pc_mut().Offset = ctx.Pc as u64; + frame.addr_pc_mut().Mode = AddrModeFlat; + frame.addr_stack_mut().Offset = ctx.Sp as u64; + frame.addr_stack_mut().Mode = AddrModeFlat; + unsafe { + frame.addr_frame_mut().Offset = ctx.u.s().Fp as u64; + } + frame.addr_frame_mut().Mode = AddrModeFlat; + IMAGE_FILE_MACHINE_ARM64 +} + +#[cfg(target_arch = "arm")] +fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD { + frame.addr_pc_mut().Offset = ctx.Pc as u64; + frame.addr_pc_mut().Mode = AddrModeFlat; + frame.addr_stack_mut().Offset = ctx.Sp as u64; + frame.addr_stack_mut().Mode = AddrModeFlat; + unsafe { + frame.addr_frame_mut().Offset = ctx.R11 as u64; + } + frame.addr_frame_mut().Mode = AddrModeFlat; + IMAGE_FILE_MACHINE_ARMNT +} diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing1-2.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing1-2.snap new file mode 100644 index 0000000000000..3c539b1999cad --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing1-2.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(attrs.deserialize) +--- +K : Hash + Ord +V : Eq + Ord + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing1.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing1.snap new file mode 100644 index 0000000000000..19c757409d16c --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing1.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(attrs.serialize.clone()) +--- +K : Hash + Eq + Ord +V : Ord + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing2-2.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing2-2.snap new file mode 100644 index 0000000000000..0ece71242a540 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing2-2.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(attrs.deserialize) +--- +K : Hash + Eq + borsh :: de :: BorshDeserialize +V : borsh :: de :: BorshDeserialize + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing2.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing2.snap new file mode 100644 index 0000000000000..01f78296948f7 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing2.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(attrs.serialize.clone()) +--- +K : Hash + Eq + borsh :: ser :: BorshSerialize +V : borsh :: ser :: BorshSerialize + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing3.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing3.snap new file mode 100644 index 0000000000000..0ece71242a540 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing3.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(attrs.deserialize) +--- +K : Hash + Eq + borsh :: de :: BorshDeserialize +V : borsh :: de :: BorshDeserialize + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing4.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing4.snap new file mode 100644 index 0000000000000..8a9b05f30951f --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing4.snap @@ -0,0 +1,6 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(attrs.deserialize) +--- +K : Hash + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing_error.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing_error.snap new file mode 100644 index 0000000000000..db0a6e9a8a883 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing_error.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: err +--- +Error( + "malformed bound attribute, expected `bound(deserialize = ..., serialize = ...)`", +) diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing_error2.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing_error2.snap new file mode 100644 index 0000000000000..fc006afe24ae8 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing_error2.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: err +--- +Error( + "expected `:`", +) diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing_error3.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing_error3.snap new file mode 100644 index 0000000000000..9c23f5698db4d --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/bounds_parsing_error3.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: err +--- +Error( + "expected borsh bound attribute to be a string: `deserialize = \"...\"`", +) diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/reject_multiple_borsh_attrs.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/reject_multiple_borsh_attrs.snap new file mode 100644 index 0000000000000..0494fbf30b9bf --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/reject_multiple_borsh_attrs.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: err +--- +Error( + "multiple `borsh` attributes not allowed", +) diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_params_combined-2.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_params_combined-2.snap new file mode 100644 index 0000000000000..c805b5f3f94c0 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_params_combined-2.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(schema.params.clone()) +--- +T => < T as TraitName > :: Associated +V => Vec < V > + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_params_combined-3.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_params_combined-3.snap new file mode 100644 index 0000000000000..4a6ed4cf42324 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_params_combined-3.snap @@ -0,0 +1,6 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_tokenizable(attrs.serialize_with) +--- +third_party_impl :: serialize_third_party + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_params_combined.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_params_combined.snap new file mode 100644 index 0000000000000..5e5017be81fa6 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_params_combined.snap @@ -0,0 +1,6 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(bounds.deserialize) +--- +K : Hash + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_wrong_key_combined.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_wrong_key_combined.snap new file mode 100644 index 0000000000000..110f4f29f9517 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_wrong_key_combined.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: err +--- +Error( + "malformed borsh attribute, expected `borsh(bound(...), deserialize_with = ..., schema(...), serialize_with = ..., skip)`", +) diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_error.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_error.snap new file mode 100644 index 0000000000000..110f4f29f9517 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/root_error.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: err +--- +Error( + "malformed borsh attribute, expected `borsh(bound(...), deserialize_with = ..., schema(...), serialize_with = ..., skip)`", +) diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_params_parsing1.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_params_parsing1.snap new file mode 100644 index 0000000000000..a5a116002d021 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_params_parsing1.snap @@ -0,0 +1,6 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(schema_attrs.unwrap().params) +--- +T => < T as TraitName > :: Associated + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_params_parsing2.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_params_parsing2.snap new file mode 100644 index 0000000000000..9627133e955cd --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_params_parsing2.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(schema_attrs.unwrap().params) +--- +T => < T as TraitName > :: Associated +V => Vec < V > + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_params_parsing_error.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_params_parsing_error.snap new file mode 100644 index 0000000000000..492f3127b5433 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_params_parsing_error.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: err +--- +Error( + "expected `>`", +) diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_params_parsing_error2.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_params_parsing_error2.snap new file mode 100644 index 0000000000000..8eed50d3c59ef --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_params_parsing_error2.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: err +--- +Error( + "malformed schema attribute, expected `schema(params = ..., with_funcs(...))`", +) diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_with_funcs_parsing-2.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_with_funcs_parsing-2.snap new file mode 100644 index 0000000000000..49d8fb91fa53e --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_with_funcs_parsing-2.snap @@ -0,0 +1,6 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_tokenizable(with_funcs.definitions) +--- +third_party_impl :: add_definitions_recursively :: < K , V > + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_with_funcs_parsing.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_with_funcs_parsing.snap new file mode 100644 index 0000000000000..836792a76f0f5 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_with_funcs_parsing.snap @@ -0,0 +1,6 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_tokenizable(with_funcs.declaration.clone()) +--- +third_party_impl :: declaration :: < K , V > + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_with_funcs_parsing_error.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_with_funcs_parsing_error.snap new file mode 100644 index 0000000000000..82f887b732418 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/schema_with_funcs_parsing_error.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: err +--- +Error( + "both `declaration = ...` and `definitions = ...` have to be specified at the same time", +) diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/ser_de_with_parsing1-2.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/ser_de_with_parsing1-2.snap new file mode 100644 index 0000000000000..85a4d0b8d8b82 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/ser_de_with_parsing1-2.snap @@ -0,0 +1,6 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_tokenizable(attrs.deserialize_with) +--- +third_party_impl :: deserialize_third_party + diff --git a/vendor/borsh-derive/src/internals/attributes/field/snapshots/ser_de_with_parsing1.snap b/vendor/borsh-derive/src/internals/attributes/field/snapshots/ser_de_with_parsing1.snap new file mode 100644 index 0000000000000..b03de7f03f991 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/field/snapshots/ser_de_with_parsing1.snap @@ -0,0 +1,6 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_tokenizable(attrs.serialize_with.as_ref()) +--- +third_party_impl :: serialize_third_party + diff --git a/vendor/borsh-derive/src/internals/attributes/item/snapshots/check_attrs_borsh_invalid_on_whole_item.snap b/vendor/borsh-derive/src/internals/attributes/item/snapshots/check_attrs_borsh_invalid_on_whole_item.snap new file mode 100644 index 0000000000000..f2a856a52907f --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/item/snapshots/check_attrs_borsh_invalid_on_whole_item.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/item/mod.rs +expression: actual.unwrap_err() +--- +Error( + "`crate`, `use_discriminant` or `init` are the only supported attributes for `borsh`", +) diff --git a/vendor/borsh-derive/src/internals/attributes/item/snapshots/check_attrs_borsh_skip_on_whole_item.snap b/vendor/borsh-derive/src/internals/attributes/item/snapshots/check_attrs_borsh_skip_on_whole_item.snap new file mode 100644 index 0000000000000..f2a856a52907f --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/item/snapshots/check_attrs_borsh_skip_on_whole_item.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/item/mod.rs +expression: actual.unwrap_err() +--- +Error( + "`crate`, `use_discriminant` or `init` are the only supported attributes for `borsh`", +) diff --git a/vendor/borsh-derive/src/internals/attributes/item/snapshots/check_attrs_init_function_wrong_format.snap b/vendor/borsh-derive/src/internals/attributes/item/snapshots/check_attrs_init_function_wrong_format.snap new file mode 100644 index 0000000000000..f2a856a52907f --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/item/snapshots/check_attrs_init_function_wrong_format.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/item/mod.rs +expression: actual.unwrap_err() +--- +Error( + "`crate`, `use_discriminant` or `init` are the only supported attributes for `borsh`", +) diff --git a/vendor/borsh-derive/src/internals/attributes/item/snapshots/check_attrs_use_discriminant_on_struct.snap b/vendor/borsh-derive/src/internals/attributes/item/snapshots/check_attrs_use_discriminant_on_struct.snap new file mode 100644 index 0000000000000..ed09a1830e9d7 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/item/snapshots/check_attrs_use_discriminant_on_struct.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/item/mod.rs +expression: actual.unwrap_err() +--- +Error( + "borsh(use_discriminant=) does not support structs", +) diff --git a/vendor/borsh-derive/src/internals/attributes/item/snapshots/init_function_parsing_error.snap b/vendor/borsh-derive/src/internals/attributes/item/snapshots/init_function_parsing_error.snap new file mode 100644 index 0000000000000..b5ff442a67bd0 --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/item/snapshots/init_function_parsing_error.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/item/mod.rs +expression: err +--- +Error( + "expected identifier", +) diff --git a/vendor/borsh-derive/src/internals/attributes/item/snapshots/reject_multiple_borsh_attrs.snap b/vendor/borsh-derive/src/internals/attributes/item/snapshots/reject_multiple_borsh_attrs.snap new file mode 100644 index 0000000000000..eb7600a70ca7b --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/item/snapshots/reject_multiple_borsh_attrs.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/item/mod.rs +expression: actual.unwrap_err() +--- +Error( + "multiple `borsh` attributes not allowed", +) diff --git a/vendor/borsh-derive/src/internals/attributes/item/snapshots/use_discriminant_wrong_value.snap b/vendor/borsh-derive/src/internals/attributes/item/snapshots/use_discriminant_wrong_value.snap new file mode 100644 index 0000000000000..81b53a54b167b --- /dev/null +++ b/vendor/borsh-derive/src/internals/attributes/item/snapshots/use_discriminant_wrong_value.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/item/mod.rs +expression: err +--- +Error( + "`use_discriminant` accepts only `true` or `false`", +) diff --git a/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_false.snap b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_false.snap new file mode 100644 index 0000000000000..0230f7747c58e --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_false.snap @@ -0,0 +1,43 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for X { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for X { + fn deserialize_variant( + reader: &mut R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0u8 { + X::A + } else if variant_tag == 1u8 { + X::B + } else if variant_tag == 2u8 { + X::C + } else if variant_tag == 3u8 { + X::D + } else if variant_tag == 4u8 { + X::E + } else if variant_tag == 5u8 { + X::F + } else { + return Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_true.snap b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_true.snap new file mode 100644 index 0000000000000..541a1df848b10 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_true.snap @@ -0,0 +1,43 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for X { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for X { + fn deserialize_variant( + reader: &mut R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0 { + X::A + } else if variant_tag == 20 { + X::B + } else if variant_tag == 20 + 1 { + X::C + } else if variant_tag == 20 + 1 + 1 { + X::D + } else if variant_tag == 10 { + X::E + } else if variant_tag == 10 + 1 { + X::F + } else { + return Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_init_func.snap b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_init_func.snap new file mode 100644 index 0000000000000..d5e070dd6a889 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_init_func.snap @@ -0,0 +1,44 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for A { + fn deserialize_variant( + reader: &mut R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0u8 { + A::A + } else if variant_tag == 1u8 { + A::B + } else if variant_tag == 2u8 { + A::C + } else if variant_tag == 3u8 { + A::D + } else if variant_tag == 4u8 { + A::E + } else if variant_tag == 5u8 { + A::F + } else { + return Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + return_value.initialization_method(); + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_struct_variant_field.snap b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_struct_variant_field.snap new file mode 100644 index 0000000000000..7c325c295c7c6 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_struct_variant_field.snap @@ -0,0 +1,40 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for AA { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for AA { + fn deserialize_variant( + reader: &mut R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0u8 { + AA::B { + c: core::default::Default::default(), + d: borsh::BorshDeserialize::deserialize_reader(reader)?, + } + } else if variant_tag == 1u8 { + AA::NegatedVariant { + beta: borsh::BorshDeserialize::deserialize_reader(reader)?, + } + } else { + return Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_tuple_variant_field.snap b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_tuple_variant_field.snap new file mode 100644 index 0000000000000..6062e702d5b0e --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_tuple_variant_field.snap @@ -0,0 +1,40 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for AAT { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for AAT { + fn deserialize_variant( + reader: &mut R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0u8 { + AAT::B( + core::default::Default::default(), + borsh::BorshDeserialize::deserialize_reader(reader)?, + ) + } else if variant_tag == 1u8 { + AAT::NegatedVariant { + beta: borsh::BorshDeserialize::deserialize_reader(reader)?, + } + } else { + return Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/bound_generics.snap b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/bound_generics.snap new file mode 100644 index 0000000000000..87c803f3fc21f --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/bound_generics.snap @@ -0,0 +1,53 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A +where + V: Value, + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, + U: borsh::de::BorshDeserialize, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for A +where + V: Value, + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, + U: borsh::de::BorshDeserialize, +{ + fn deserialize_variant( + reader: &mut R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0u8 { + A::B { + x: borsh::BorshDeserialize::deserialize_reader(reader)?, + y: borsh::BorshDeserialize::deserialize_reader(reader)?, + } + } else if variant_tag == 1u8 { + A::C( + borsh::BorshDeserialize::deserialize_reader(reader)?, + borsh::BorshDeserialize::deserialize_reader(reader)?, + ) + } else { + return Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_attr.snap b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_attr.snap new file mode 100644 index 0000000000000..2d74a476c81ee --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_attr.snap @@ -0,0 +1,49 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for C +where + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for C +where + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, +{ + fn deserialize_variant( + reader: &mut R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0u8 { + C::C3( + borsh::BorshDeserialize::deserialize_reader(reader)?, + borsh::BorshDeserialize::deserialize_reader(reader)?, + ) + } else if variant_tag == 1u8 { + C::C4 { + x: borsh::BorshDeserialize::deserialize_reader(reader)?, + y: third_party_impl::deserialize_third_party(reader)?, + } + } else { + return Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_struct_field.snap b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_struct_field.snap new file mode 100644 index 0000000000000..88606d92339b1 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_struct_field.snap @@ -0,0 +1,55 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A +where + V: Value, + K: borsh::de::BorshDeserialize, + U: borsh::de::BorshDeserialize, + K: core::default::Default, + V: core::default::Default, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for A +where + V: Value, + K: borsh::de::BorshDeserialize, + U: borsh::de::BorshDeserialize, + K: core::default::Default, + V: core::default::Default, +{ + fn deserialize_variant( + reader: &mut R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0u8 { + A::B { + x: core::default::Default::default(), + y: borsh::BorshDeserialize::deserialize_reader(reader)?, + } + } else if variant_tag == 1u8 { + A::C( + borsh::BorshDeserialize::deserialize_reader(reader)?, + borsh::BorshDeserialize::deserialize_reader(reader)?, + ) + } else { + return Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_tuple_field.snap b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_tuple_field.snap new file mode 100644 index 0000000000000..0188577282bf2 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_tuple_field.snap @@ -0,0 +1,53 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A +where + V: Value, + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, + U: core::default::Default, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for A +where + V: Value, + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, + U: core::default::Default, +{ + fn deserialize_variant( + reader: &mut R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0u8 { + A::B { + x: borsh::BorshDeserialize::deserialize_reader(reader)?, + y: borsh::BorshDeserialize::deserialize_reader(reader)?, + } + } else if variant_tag == 1u8 { + A::C( + borsh::BorshDeserialize::deserialize_reader(reader)?, + core::default::Default::default(), + ) + } else { + return Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_bound.snap b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_bound.snap new file mode 100644 index 0000000000000..486b3e42f90f5 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_bound.snap @@ -0,0 +1,49 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A +where + T: PartialOrd + Hash + Eq + borsh::de::BorshDeserialize, + U: borsh::de::BorshDeserialize, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for A +where + T: PartialOrd + Hash + Eq + borsh::de::BorshDeserialize, + U: borsh::de::BorshDeserialize, +{ + fn deserialize_variant( + reader: &mut R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0u8 { + A::C { + a: borsh::BorshDeserialize::deserialize_reader(reader)?, + b: borsh::BorshDeserialize::deserialize_reader(reader)?, + } + } else if variant_tag == 1u8 { + A::D( + borsh::BorshDeserialize::deserialize_reader(reader)?, + borsh::BorshDeserialize::deserialize_reader(reader)?, + ) + } else { + return Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/recursive_enum.snap b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/recursive_enum.snap new file mode 100644 index 0000000000000..76473c24ba9ed --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/recursive_enum.snap @@ -0,0 +1,51 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A +where + V: Value, + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for A +where + V: Value, + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, +{ + fn deserialize_variant( + reader: &mut R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0u8 { + A::B { + x: borsh::BorshDeserialize::deserialize_reader(reader)?, + y: borsh::BorshDeserialize::deserialize_reader(reader)?, + } + } else if variant_tag == 1u8 { + A::C( + borsh::BorshDeserialize::deserialize_reader(reader)?, + borsh::BorshDeserialize::deserialize_reader(reader)?, + ) + } else { + return Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/simple_enum_with_custom_crate.snap b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/simple_enum_with_custom_crate.snap new file mode 100644 index 0000000000000..a1395c9dbc414 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/simple_enum_with_custom_crate.snap @@ -0,0 +1,43 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl reexporter::borsh::de::BorshDeserialize for A { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader( + reader, + )?; + ::deserialize_variant(reader, tag) + } +} +impl reexporter::borsh::de::EnumExt for A { + fn deserialize_variant( + reader: &mut R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0u8 { + A::B { + x: reexporter::borsh::BorshDeserialize::deserialize_reader(reader)?, + y: reexporter::borsh::BorshDeserialize::deserialize_reader(reader)?, + } + } else if variant_tag == 1u8 { + A::C( + reexporter::borsh::BorshDeserialize::deserialize_reader(reader)?, + reexporter::borsh::BorshDeserialize::deserialize_reader(reader)?, + ) + } else { + return Err( + reexporter::borsh::io::Error::new( + reexporter::borsh::io::ErrorKind::InvalidData, + reexporter::borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/simple_generics.snap b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/simple_generics.snap new file mode 100644 index 0000000000000..7dc6b1f0816d0 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/enums/snapshots/simple_generics.snap @@ -0,0 +1,51 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A +where + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, + U: borsh::de::BorshDeserialize, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for A +where + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, + U: borsh::de::BorshDeserialize, +{ + fn deserialize_variant( + reader: &mut R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0u8 { + A::B { + x: borsh::BorshDeserialize::deserialize_reader(reader)?, + y: borsh::BorshDeserialize::deserialize_reader(reader)?, + } + } else if variant_tag == 1u8 { + A::C( + borsh::BorshDeserialize::deserialize_reader(reader)?, + borsh::BorshDeserialize::deserialize_reader(reader)?, + ) + } else { + return Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/borsh_init_func.snap b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/borsh_init_func.snap new file mode 100644 index 0000000000000..417d0e1d9a100 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/borsh_init_func.snap @@ -0,0 +1,17 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + let mut return_value = Self { + x: borsh::BorshDeserialize::deserialize_reader(reader)?, + y: borsh::BorshDeserialize::deserialize_reader(reader)?, + }; + return_value.initialization_method(); + Ok(return_value) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/bound_generics.snap b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/bound_generics.snap new file mode 100644 index 0000000000000..9799faca0027e --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/bound_generics.snap @@ -0,0 +1,20 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A +where + V: Value, + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + x: borsh::BorshDeserialize::deserialize_reader(reader)?, + y: borsh::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_attr.snap b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_attr.snap new file mode 100644 index 0000000000000..22798639e1a56 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_attr.snap @@ -0,0 +1,19 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A +where + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + x: third_party_impl::deserialize_third_party(reader)?, + y: borsh::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_bound.snap b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_bound.snap new file mode 100644 index 0000000000000..a17b005c0d760 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_bound.snap @@ -0,0 +1,19 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for C +where + T: PartialOrd + Hash + Eq + borsh::de::BorshDeserialize, + U: borsh::de::BorshDeserialize, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + a: borsh::BorshDeserialize::deserialize_reader(reader)?, + b: borsh::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap new file mode 100644 index 0000000000000..eebe6a1e8f7d2 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap @@ -0,0 +1,20 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for G +where + U: borsh::de::BorshDeserialize, + K: core::default::Default, + V: core::default::Default, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + x: core::default::Default::default(), + y: borsh::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap new file mode 100644 index 0000000000000..53fd0f8bbe039 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap @@ -0,0 +1,22 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for G +where + U: borsh::de::BorshDeserialize, + K: core::default::Default, + V: core::default::Default, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok( + Self( + core::default::Default::default(), + borsh::BorshDeserialize::deserialize_reader(reader)?, + ), + ) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap new file mode 100644 index 0000000000000..e6e142567de90 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap @@ -0,0 +1,22 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for G +where + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, + U: core::default::Default, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok( + Self( + borsh::BorshDeserialize::deserialize_reader(reader)?, + core::default::Default::default(), + ), + ) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait.snap b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait.snap new file mode 100644 index 0000000000000..3d450380cb2be --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait.snap @@ -0,0 +1,20 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for G1 +where + U: borsh::de::BorshDeserialize, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok( + Self( + core::default::Default::default(), + borsh::BorshDeserialize::deserialize_reader(reader)?, + ), + ) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/recursive_struct.snap b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/recursive_struct.snap new file mode 100644 index 0000000000000..4f9738096966c --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/recursive_struct.snap @@ -0,0 +1,15 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for CRecC { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + a: borsh::BorshDeserialize::deserialize_reader(reader)?, + b: borsh::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generic_tuple_struct.snap b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generic_tuple_struct.snap new file mode 100644 index 0000000000000..4c7f939b1625d --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generic_tuple_struct.snap @@ -0,0 +1,20 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for TupleA +where + T: borsh::de::BorshDeserialize, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok( + Self( + borsh::BorshDeserialize::deserialize_reader(reader)?, + borsh::BorshDeserialize::deserialize_reader(reader)?, + ), + ) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generics.snap b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generics.snap new file mode 100644 index 0000000000000..e33d4e9d679d2 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generics.snap @@ -0,0 +1,19 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A +where + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, +{ + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + x: borsh::BorshDeserialize::deserialize_reader(reader)?, + y: borsh::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct.snap b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct.snap new file mode 100644 index 0000000000000..39b182a7d3c12 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct.snap @@ -0,0 +1,15 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + x: borsh::BorshDeserialize::deserialize_reader(reader)?, + y: borsh::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} + diff --git a/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct_with_custom_crate.snap b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct_with_custom_crate.snap new file mode 100644 index 0000000000000..b5bb0b89c2a66 --- /dev/null +++ b/vendor/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct_with_custom_crate.snap @@ -0,0 +1,15 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl reexporter::borsh::de::BorshDeserialize for A { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + x: reexporter::borsh::BorshDeserialize::deserialize_reader(reader)?, + y: reexporter::borsh::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/borsh_discriminant_false.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/borsh_discriminant_false.snap new file mode 100644 index 0000000000000..4fa592109c98c --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/borsh_discriminant_false.snap @@ -0,0 +1,65 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for X { + fn declaration() -> borsh::schema::Declaration { + "X".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XA; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XB; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XC; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XD; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XE; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XF; + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "A".into(), < XA as borsh::BorshSchema > + ::declaration()), (u8::from(1u8) as i64, "B".into(), < XB as + borsh::BorshSchema > ::declaration()), (u8::from(2u8) as i64, "C".into(), + < XC as borsh::BorshSchema > ::declaration()), (u8::from(3u8) as i64, "D" + .into(), < XD as borsh::BorshSchema > ::declaration()), (u8::from(4u8) as + i64, "E".into(), < XE as borsh::BorshSchema > ::declaration()), + (u8::from(5u8) as i64, "F".into(), < XF as borsh::BorshSchema > + ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/borsh_discriminant_true.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/borsh_discriminant_true.snap new file mode 100644 index 0000000000000..1b234f1dfaee4 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/borsh_discriminant_true.snap @@ -0,0 +1,65 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for X { + fn declaration() -> borsh::schema::Declaration { + "X".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XA; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XB; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XC; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XD; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XE; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XF; + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0) as i64, "A".into(), < XA as borsh::BorshSchema > + ::declaration()), (u8::from(20) as i64, "B".into(), < XB as + borsh::BorshSchema > ::declaration()), (u8::from(20 + 1) as i64, "C" + .into(), < XC as borsh::BorshSchema > ::declaration()), (u8::from(20 + 1 + + 1) as i64, "D".into(), < XD as borsh::BorshSchema > ::declaration()), + (u8::from(10) as i64, "E".into(), < XE as borsh::BorshSchema > + ::declaration()), (u8::from(10 + 1) as i64, "F".into(), < XF as + borsh::BorshSchema > ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/check_with_funcs_skip_conflict.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/check_with_funcs_skip_conflict.snap new file mode 100644 index 0000000000000..ee88202fd85ab --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/check_with_funcs_skip_conflict.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: actual.unwrap_err() +--- +Error( + "`skip` cannot be used at the same time as `schema(with_funcs(...))`", +) diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/complex_enum.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/complex_enum.snap new file mode 100644 index 0000000000000..60006941b357e --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/complex_enum.snap @@ -0,0 +1,56 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A { + fn declaration() -> borsh::schema::Declaration { + "A".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ABacon; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct AEggs; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ASalad(Tomatoes, Cucumber, Oil); + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ASausage { + wrapper: Wrapper, + filling: Filling, + } + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "Bacon".into(), < ABacon as borsh::BorshSchema > + ::declaration()), (u8::from(1u8) as i64, "Eggs".into(), < AEggs as + borsh::BorshSchema > ::declaration()), (u8::from(2u8) as i64, "Salad" + .into(), < ASalad as borsh::BorshSchema > ::declaration()), + (u8::from(3u8) as i64, "Sausage".into(), < ASausage as borsh::BorshSchema + > ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/complex_enum_generics.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/complex_enum_generics.snap new file mode 100644 index 0000000000000..46c0ca1028533 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/complex_enum_generics.snap @@ -0,0 +1,64 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A +where + C: borsh::BorshSchema, + W: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < C as borsh::BorshSchema > ::declaration(), < W as borsh::BorshSchema > + ::declaration() + ]; + format!(r#"{}<{}>"#, "A", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ABacon; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct AEggs; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ASalad(Tomatoes, C, Oil); + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ASausage { + wrapper: W, + filling: Filling, + } + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + as borsh::BorshSchema>::add_definitions_recursively(definitions); + as borsh::BorshSchema>::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "Bacon".into(), < ABacon as borsh::BorshSchema > + ::declaration()), (u8::from(1u8) as i64, "Eggs".into(), < AEggs as + borsh::BorshSchema > ::declaration()), (u8::from(2u8) as i64, "Salad" + .into(), < ASalad < C > as borsh::BorshSchema > ::declaration()), + (u8::from(3u8) as i64, "Sausage".into(), < ASausage < W > as + borsh::BorshSchema > ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/complex_enum_generics_borsh_skip_named_field.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/complex_enum_generics_borsh_skip_named_field.snap new file mode 100644 index 0000000000000..c73bb784db71e --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/complex_enum_generics_borsh_skip_named_field.snap @@ -0,0 +1,66 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A +where + U: borsh::BorshSchema, + C: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < U as borsh::BorshSchema > ::declaration(), < C as borsh::BorshSchema > + ::declaration() + ]; + format!(r#"{}<{}>"#, "A", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ABacon; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct AEggs; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ASalad(Tomatoes, C, Oil); + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ASausage { + #[borsh(skip)] + wrapper: W, + filling: Filling, + unexpected: U, + } + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + as borsh::BorshSchema>::add_definitions_recursively(definitions); + as borsh::BorshSchema>::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "Bacon".into(), < ABacon as borsh::BorshSchema > + ::declaration()), (u8::from(1u8) as i64, "Eggs".into(), < AEggs as + borsh::BorshSchema > ::declaration()), (u8::from(2u8) as i64, "Salad" + .into(), < ASalad < C > as borsh::BorshSchema > ::declaration()), + (u8::from(3u8) as i64, "Sausage".into(), < ASausage < W, U > as + borsh::BorshSchema > ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/complex_enum_generics_borsh_skip_tuple_field.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/complex_enum_generics_borsh_skip_tuple_field.snap new file mode 100644 index 0000000000000..a531044c87bbd --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/complex_enum_generics_borsh_skip_tuple_field.snap @@ -0,0 +1,66 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A +where + W: Hash, + W: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < W as borsh::BorshSchema > ::declaration() + ]; + format!(r#"{}<{}>"#, "A", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ABacon; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct AEggs; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ASalad(Tomatoes, #[borsh(skip)] C, Oil); + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ASausage + where + W: Hash, + { + wrapper: W, + filling: Filling, + } + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + as borsh::BorshSchema>::add_definitions_recursively(definitions); + as borsh::BorshSchema>::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "Bacon".into(), < ABacon as borsh::BorshSchema > + ::declaration()), (u8::from(1u8) as i64, "Eggs".into(), < AEggs as + borsh::BorshSchema > ::declaration()), (u8::from(2u8) as i64, "Salad" + .into(), < ASalad < C > as borsh::BorshSchema > ::declaration()), + (u8::from(3u8) as i64, "Sausage".into(), < ASausage < W > as + borsh::BorshSchema > ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/filter_foreign_attrs.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/filter_foreign_attrs.snap new file mode 100644 index 0000000000000..3eaab191eafe9 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/filter_foreign_attrs.snap @@ -0,0 +1,47 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A { + fn declaration() -> borsh::schema::Declaration { + "A".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct AB { + c: i32, + #[borsh(skip)] + d: u32, + l: u64, + } + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ANegative { + beta: String, + } + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "B".into(), < AB as borsh::BorshSchema > + ::declaration()), (u8::from(1u8) as i64, "Negative".into(), < ANegative + as borsh::BorshSchema > ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/generic_associated_type.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/generic_associated_type.snap new file mode 100644 index 0000000000000..c87de892b4100 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/generic_associated_type.snap @@ -0,0 +1,74 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for EnumParametrized +where + K: TraitName, + K: core::cmp::Ord, + V: core::cmp::Ord, + T: Eq + Hash, + T: borsh::BorshSchema, + K: borsh::BorshSchema, + K::Associated: borsh::BorshSchema, + V: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < T as borsh::BorshSchema > ::declaration(), < K as borsh::BorshSchema > + ::declaration(), < K::Associated as borsh::BorshSchema > ::declaration(), < V + as borsh::BorshSchema > ::declaration() + ]; + format!(r#"{}<{}>"#, "EnumParametrized", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct EnumParametrizedB + where + K: TraitName, + K: core::cmp::Ord, + V: core::cmp::Ord, + { + x: BTreeMap, + y: String, + z: K::Associated, + } + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct EnumParametrizedC( + T, + u16, + ) + where + T: Eq + Hash; + as borsh::BorshSchema>::add_definitions_recursively(definitions); + as borsh::BorshSchema>::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "B".into(), < EnumParametrizedB < K, V > as + borsh::BorshSchema > ::declaration()), (u8::from(1u8) as i64, "C".into(), + < EnumParametrizedC < T > as borsh::BorshSchema > ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/generic_associated_type_param_override.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/generic_associated_type_param_override.snap new file mode 100644 index 0000000000000..9389a848d3dba --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/generic_associated_type_param_override.snap @@ -0,0 +1,75 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for EnumParametrized +where + K: TraitName, + K: core::cmp::Ord, + V: core::cmp::Ord, + T: Eq + Hash, + T: borsh::BorshSchema, + K: borsh::BorshSchema, + ::Associated: borsh::BorshSchema, + V: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < T as borsh::BorshSchema > ::declaration(), < K as borsh::BorshSchema > + ::declaration(), < < K as TraitName > ::Associated as borsh::BorshSchema > + ::declaration(), < V as borsh::BorshSchema > ::declaration() + ]; + format!(r#"{}<{}>"#, "EnumParametrized", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct EnumParametrizedB + where + K: TraitName, + K: core::cmp::Ord, + V: core::cmp::Ord, + { + x: BTreeMap, + y: String, + #[borsh(schema(params = "K => ::Associated"))] + z: ::Associated, + } + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct EnumParametrizedC( + T, + u16, + ) + where + T: Eq + Hash; + as borsh::BorshSchema>::add_definitions_recursively(definitions); + as borsh::BorshSchema>::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "B".into(), < EnumParametrizedB < K, V > as + borsh::BorshSchema > ::declaration()), (u8::from(1u8) as i64, "C".into(), + < EnumParametrizedC < T > as borsh::BorshSchema > ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/generic_associated_type_param_override_conflict.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/generic_associated_type_param_override_conflict.snap new file mode 100644 index 0000000000000..e53e1f57f6d9d --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/generic_associated_type_param_override_conflict.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: actual.unwrap_err() +--- +Error( + "`skip` cannot be used at the same time as `schema(params = ...)`", +) diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/recursive_enum.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/recursive_enum.snap new file mode 100644 index 0000000000000..856f9f630947e --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/recursive_enum.snap @@ -0,0 +1,55 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A +where + V: Value, + K: borsh::BorshSchema, + V: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < K as borsh::BorshSchema > ::declaration(), < V as borsh::BorshSchema > + ::declaration() + ]; + format!(r#"{}<{}>"#, "A", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct AB + where + V: Value, + { + x: HashMap, + y: String, + } + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct AC(K, Vec); + as borsh::BorshSchema>::add_definitions_recursively(definitions); + as borsh::BorshSchema>::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "B".into(), < AB < K, V > as borsh::BorshSchema > + ::declaration()), (u8::from(1u8) as i64, "C".into(), < AC < K > as + borsh::BorshSchema > ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/simple_enum.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/simple_enum.snap new file mode 100644 index 0000000000000..cbadbaf7f4bd2 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/simple_enum.snap @@ -0,0 +1,40 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A { + fn declaration() -> borsh::schema::Declaration { + "A".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ABacon; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct AEggs; + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "Bacon".into(), < ABacon as borsh::BorshSchema > + ::declaration()), (u8::from(1u8) as i64, "Eggs".into(), < AEggs as + borsh::BorshSchema > ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/simple_enum_with_custom_crate.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/simple_enum_with_custom_crate.snap new file mode 100644 index 0000000000000..368a39d92c25f --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/simple_enum_with_custom_crate.snap @@ -0,0 +1,45 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl reexporter::borsh::BorshSchema for A { + fn declaration() -> reexporter::borsh::schema::Declaration { + "A".to_string() + } + fn add_definitions_recursively( + definitions: &mut reexporter::borsh::__private::maybestd::collections::BTreeMap< + reexporter::borsh::schema::Declaration, + reexporter::borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(reexporter::borsh::BorshSchema)] + #[borsh(crate = "reexporter :: borsh")] + struct ABacon; + #[allow(dead_code)] + #[derive(reexporter::borsh::BorshSchema)] + #[borsh(crate = "reexporter :: borsh")] + struct AEggs; + ::add_definitions_recursively( + definitions, + ); + ::add_definitions_recursively( + definitions, + ); + let definition = reexporter::borsh::schema::Definition::Enum { + tag_width: 1, + variants: reexporter::borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "Bacon".into(), < ABacon as + reexporter::borsh::BorshSchema > ::declaration()), (u8::from(1u8) as i64, + "Eggs".into(), < AEggs as reexporter::borsh::BorshSchema > + ::declaration()) + ], + }; + reexporter::borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/single_field_enum.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/single_field_enum.snap new file mode 100644 index 0000000000000..f3a886f9bfb12 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/single_field_enum.snap @@ -0,0 +1,34 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A { + fn declaration() -> borsh::schema::Declaration { + "A".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct ABacon; + ::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "Bacon".into(), < ABacon as borsh::BorshSchema > + ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/trailing_comma_generics.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/trailing_comma_generics.snap new file mode 100644 index 0000000000000..d6dfffc9a2e4c --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/trailing_comma_generics.snap @@ -0,0 +1,58 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for Side +where + A: Display + Debug, + B: Display + Debug, + B: borsh::BorshSchema, + A: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < B as borsh::BorshSchema > ::declaration(), < A as borsh::BorshSchema > + ::declaration() + ]; + format!(r#"{}<{}>"#, "Side", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct SideLeft( + A, + ) + where + A: Display + Debug; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct SideRight( + B, + ) + where + B: Display + Debug; + as borsh::BorshSchema>::add_definitions_recursively(definitions); + as borsh::BorshSchema>::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "Left".into(), < SideLeft < A > as + borsh::BorshSchema > ::declaration()), (u8::from(1u8) as i64, "Right" + .into(), < SideRight < B > as borsh::BorshSchema > ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/enums/snapshots/with_funcs_attr.snap b/vendor/borsh-derive/src/internals/schema/enums/snapshots/with_funcs_attr.snap new file mode 100644 index 0000000000000..17f16077c6538 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/enums/snapshots/with_funcs_attr.snap @@ -0,0 +1,59 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for C +where + K: borsh::BorshSchema, + V: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < K as borsh::BorshSchema > ::declaration(), < V as borsh::BorshSchema > + ::declaration() + ]; + format!(r#"{}<{}>"#, "C", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct CC3(u64, u64); + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct CC4( + u64, + #[borsh( + schema( + with_funcs( + declaration = "third_party_impl::declaration::", + definitions = "third_party_impl::add_definitions_recursively::" + ) + ) + )] + ThirdParty, + ); + ::add_definitions_recursively(definitions); + as borsh::BorshSchema>::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (u8::from(0u8) as i64, "C3".into(), < CC3 as borsh::BorshSchema > + ::declaration()), (u8::from(1u8) as i64, "C4".into(), < CC4 < K, V > as + borsh::BorshSchema > ::declaration()) + ], + }; + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/check_with_funcs_skip_conflict.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/check_with_funcs_skip_conflict.snap new file mode 100644 index 0000000000000..12a1f234aab89 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/check_with_funcs_skip_conflict.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: actual.unwrap_err() +--- +Error( + "`skip` cannot be used at the same time as `schema(with_funcs(...))`", +) diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_associated_type.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_associated_type.snap new file mode 100644 index 0000000000000..baeb6e635e68d --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_associated_type.snap @@ -0,0 +1,50 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for Parametrized +where + T: TraitName, + V: borsh::BorshSchema, + T::Associated: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < V as borsh::BorshSchema > ::declaration(), < T::Associated as + borsh::BorshSchema > ::declaration() + ]; + format!(r#"{}<{}>"#, "Parametrized", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::NamedFields( + borsh::__private::maybestd::vec![ + ("field".to_string(), < T::Associated as borsh::BorshSchema > + ::declaration()), ("another".to_string(), < V as borsh::BorshSchema > + ::declaration()) + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + ::add_definitions_recursively( + definitions, + ); + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_associated_type_param_override.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_associated_type_param_override.snap new file mode 100644 index 0000000000000..718014e6bc5b5 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_associated_type_param_override.snap @@ -0,0 +1,50 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for Parametrized +where + T: TraitName, + V: borsh::BorshSchema, + ::Associated: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < V as borsh::BorshSchema > ::declaration(), < < T as TraitName > + ::Associated as borsh::BorshSchema > ::declaration() + ]; + format!(r#"{}<{}>"#, "Parametrized", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::NamedFields( + borsh::__private::maybestd::vec![ + ("field".to_string(), < < T as TraitName > ::Associated as + borsh::BorshSchema > ::declaration()), ("another".to_string(), < V as + borsh::BorshSchema > ::declaration()) + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + <::Associated as borsh::BorshSchema>::add_definitions_recursively( + definitions, + ); + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_associated_type_param_override2.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_associated_type_param_override2.snap new file mode 100644 index 0000000000000..0316161385b79 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_associated_type_param_override2.snap @@ -0,0 +1,53 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for Parametrized +where + T: TraitName, + V: borsh::BorshSchema, + T: borsh::BorshSchema, + ::Associated: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < V as borsh::BorshSchema > ::declaration(), < T as borsh::BorshSchema > + ::declaration(), < < T as TraitName > ::Associated as borsh::BorshSchema > + ::declaration() + ]; + format!(r#"{}<{}>"#, "Parametrized", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::NamedFields( + borsh::__private::maybestd::vec![ + ("field".to_string(), < (< T as TraitName > ::Associated, T) as + borsh::BorshSchema > ::declaration()), ("another".to_string(), < V as + borsh::BorshSchema > ::declaration()) + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + <( + ::Associated, + T, + ) as borsh::BorshSchema>::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_associated_type_param_override_conflict.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_associated_type_param_override_conflict.snap new file mode 100644 index 0000000000000..eede94af8577f --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_associated_type_param_override_conflict.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: actual.unwrap_err() +--- +Error( + "`skip` cannot be used at the same time as `schema(params = ...)`", +) diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_named_fields_struct_borsh_skip.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_named_fields_struct_borsh_skip.snap new file mode 100644 index 0000000000000..6d310d61507d5 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_named_fields_struct_borsh_skip.snap @@ -0,0 +1,42 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for G +where + U: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < U as borsh::BorshSchema > ::declaration() + ]; + format!(r#"{}<{}>"#, "G", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::NamedFields( + borsh::__private::maybestd::vec![ + ("y".to_string(), < U as borsh::BorshSchema > ::declaration()) + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_tuple_struct_borsh_skip1.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_tuple_struct_borsh_skip1.snap new file mode 100644 index 0000000000000..5f3967f2aab75 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_tuple_struct_borsh_skip1.snap @@ -0,0 +1,40 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for G +where + U: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < U as borsh::BorshSchema > ::declaration() + ]; + format!(r#"{}<{}>"#, "G", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::UnnamedFields( + borsh::__private::maybestd::vec![< U as borsh::BorshSchema > ::declaration()], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_tuple_struct_borsh_skip2.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_tuple_struct_borsh_skip2.snap new file mode 100644 index 0000000000000..c3b075b10f80d --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_tuple_struct_borsh_skip2.snap @@ -0,0 +1,47 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for G +where + K: borsh::BorshSchema, + V: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < K as borsh::BorshSchema > ::declaration(), < V as borsh::BorshSchema > + ::declaration() + ]; + format!(r#"{}<{}>"#, "G", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::UnnamedFields( + borsh::__private::maybestd::vec![ + < HashMap < K, V > as borsh::BorshSchema > ::declaration() + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + as borsh::BorshSchema>::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_tuple_struct_borsh_skip3.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_tuple_struct_borsh_skip3.snap new file mode 100644 index 0000000000000..bd4906729d182 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_tuple_struct_borsh_skip3.snap @@ -0,0 +1,46 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for G +where + U: borsh::BorshSchema, + K: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < U as borsh::BorshSchema > ::declaration(), < K as borsh::BorshSchema > + ::declaration() + ]; + format!(r#"{}<{}>"#, "G", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::UnnamedFields( + borsh::__private::maybestd::vec![ + < U as borsh::BorshSchema > ::declaration(), < K as borsh::BorshSchema > + ::declaration() + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_tuple_struct_borsh_skip4.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_tuple_struct_borsh_skip4.snap new file mode 100644 index 0000000000000..351abf0280345 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/generic_tuple_struct_borsh_skip4.snap @@ -0,0 +1,38 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for ASalad { + fn declaration() -> borsh::schema::Declaration { + "ASalad".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::UnnamedFields( + borsh::__private::maybestd::vec![ + < Tomatoes as borsh::BorshSchema > ::declaration(), < Oil as + borsh::BorshSchema > ::declaration() + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/recursive_struct.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/recursive_struct.snap new file mode 100644 index 0000000000000..b301714211c6a --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/recursive_struct.snap @@ -0,0 +1,42 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for CRecC { + fn declaration() -> borsh::schema::Declaration { + "CRecC".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::NamedFields( + borsh::__private::maybestd::vec![ + ("a".to_string(), < String as borsh::BorshSchema > ::declaration()), ("b" + .to_string(), < HashMap < String, CRecC > as borsh::BorshSchema > + ::declaration()) + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + ::add_definitions_recursively(definitions); + as borsh::BorshSchema>::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/schema_param_override3.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/schema_param_override3.snap new file mode 100644 index 0000000000000..27908d04c4243 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/schema_param_override3.snap @@ -0,0 +1,48 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A +where + V: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < V as borsh::BorshSchema > ::declaration() + ]; + format!(r#"{}<{}>"#, "A", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::NamedFields( + borsh::__private::maybestd::vec![ + ("x".to_string(), < PrimaryMap < K, V > as borsh::BorshSchema > + ::declaration()), ("y".to_string(), < String as borsh::BorshSchema > + ::declaration()) + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + as borsh::BorshSchema>::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/simple_generics.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/simple_generics.snap new file mode 100644 index 0000000000000..e2db10ea024f8 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/simple_generics.snap @@ -0,0 +1,50 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A +where + K: borsh::BorshSchema, + V: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < K as borsh::BorshSchema > ::declaration(), < V as borsh::BorshSchema > + ::declaration() + ]; + format!(r#"{}<{}>"#, "A", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::NamedFields( + borsh::__private::maybestd::vec![ + ("x".to_string(), < HashMap < K, V > as borsh::BorshSchema > + ::declaration()), ("y".to_string(), < String as borsh::BorshSchema > + ::declaration()) + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + as borsh::BorshSchema>::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/simple_struct.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/simple_struct.snap new file mode 100644 index 0000000000000..e600d44012597 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/simple_struct.snap @@ -0,0 +1,38 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A { + fn declaration() -> borsh::schema::Declaration { + "A".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::NamedFields( + borsh::__private::maybestd::vec![ + ("x".to_string(), < u64 as borsh::BorshSchema > ::declaration()), ("y" + .to_string(), < String as borsh::BorshSchema > ::declaration()) + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/simple_struct_with_custom_crate.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/simple_struct_with_custom_crate.snap new file mode 100644 index 0000000000000..49fd05b555942 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/simple_struct_with_custom_crate.snap @@ -0,0 +1,43 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl reexporter::borsh::BorshSchema for A { + fn declaration() -> reexporter::borsh::schema::Declaration { + "A".to_string() + } + fn add_definitions_recursively( + definitions: &mut reexporter::borsh::__private::maybestd::collections::BTreeMap< + reexporter::borsh::schema::Declaration, + reexporter::borsh::schema::Definition, + >, + ) { + let fields = reexporter::borsh::schema::Fields::NamedFields( + reexporter::borsh::__private::maybestd::vec![ + ("x".to_string(), < u64 as reexporter::borsh::BorshSchema > + ::declaration()), ("y".to_string(), < String as + reexporter::borsh::BorshSchema > ::declaration()) + ], + ); + let definition = reexporter::borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + reexporter::borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + ::add_definitions_recursively( + definitions, + ); + ::add_definitions_recursively( + definitions, + ); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/trailing_comma_generics.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/trailing_comma_generics.snap new file mode 100644 index 0000000000000..5cc65afde708a --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/trailing_comma_generics.snap @@ -0,0 +1,51 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A +where + K: Display + Debug, + K: borsh::BorshSchema, + V: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < K as borsh::BorshSchema > ::declaration(), < V as borsh::BorshSchema > + ::declaration() + ]; + format!(r#"{}<{}>"#, "A", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::NamedFields( + borsh::__private::maybestd::vec![ + ("x".to_string(), < HashMap < K, V > as borsh::BorshSchema > + ::declaration()), ("y".to_string(), < String as borsh::BorshSchema > + ::declaration()) + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + as borsh::BorshSchema>::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/tuple_struct.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/tuple_struct.snap new file mode 100644 index 0000000000000..7c8ec231a4477 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/tuple_struct.snap @@ -0,0 +1,38 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A { + fn declaration() -> borsh::schema::Declaration { + "A".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::UnnamedFields( + borsh::__private::maybestd::vec![ + < u64 as borsh::BorshSchema > ::declaration(), < String as + borsh::BorshSchema > ::declaration() + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/tuple_struct_params.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/tuple_struct_params.snap new file mode 100644 index 0000000000000..45f10abe035c7 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/tuple_struct_params.snap @@ -0,0 +1,46 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A +where + K: borsh::BorshSchema, + V: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < K as borsh::BorshSchema > ::declaration(), < V as borsh::BorshSchema > + ::declaration() + ]; + format!(r#"{}<{}>"#, "A", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::UnnamedFields( + borsh::__private::maybestd::vec![ + < K as borsh::BorshSchema > ::declaration(), < V as borsh::BorshSchema > + ::declaration() + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/tuple_struct_partial_skip.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/tuple_struct_partial_skip.snap new file mode 100644 index 0000000000000..2d72dfaff05fe --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/tuple_struct_partial_skip.snap @@ -0,0 +1,36 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A { + fn declaration() -> borsh::schema::Declaration { + "A".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::UnnamedFields( + borsh::__private::maybestd::vec![ + < String as borsh::BorshSchema > ::declaration() + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/tuple_struct_whole_skip.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/tuple_struct_whole_skip.snap new file mode 100644 index 0000000000000..ef562500583e5 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/tuple_struct_whole_skip.snap @@ -0,0 +1,30 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A { + fn declaration() -> borsh::schema::Declaration { + "A".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::Empty; + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag {} + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/unit_struct.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/unit_struct.snap new file mode 100644 index 0000000000000..ef562500583e5 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/unit_struct.snap @@ -0,0 +1,30 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A { + fn declaration() -> borsh::schema::Declaration { + "A".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::Empty; + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag {} + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/with_funcs_attr.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/with_funcs_attr.snap new file mode 100644 index 0000000000000..ea8b2332d45f1 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/with_funcs_attr.snap @@ -0,0 +1,46 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A +where + K: borsh::BorshSchema, + V: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < K as borsh::BorshSchema > ::declaration(), < V as borsh::BorshSchema > + ::declaration() + ]; + format!(r#"{}<{}>"#, "A", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::NamedFields( + borsh::__private::maybestd::vec![ + ("x".to_string(), third_party_impl::declaration:: < K, V > ()), ("y" + .to_string(), < u64 as borsh::BorshSchema > ::declaration()) + ], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + third_party_impl::add_definitions_recursively::(definitions); + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/schema/structs/snapshots/wrapper_struct.snap b/vendor/borsh-derive/src/internals/schema/structs/snapshots/wrapper_struct.snap new file mode 100644 index 0000000000000..0c674c9697c65 --- /dev/null +++ b/vendor/borsh-derive/src/internals/schema/structs/snapshots/wrapper_struct.snap @@ -0,0 +1,40 @@ +--- +source: borsh-derive/src/internals/schema/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for A +where + T: borsh::BorshSchema, +{ + fn declaration() -> borsh::schema::Declaration { + let params = borsh::__private::maybestd::vec![ + < T as borsh::BorshSchema > ::declaration() + ]; + format!(r#"{}<{}>"#, "A", params.join(", ")) + } + fn add_definitions_recursively( + definitions: &mut borsh::__private::maybestd::collections::BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::UnnamedFields( + borsh::__private::maybestd::vec![< T as borsh::BorshSchema > ::declaration()], + ); + let definition = borsh::schema::Definition::Struct { + fields, + }; + let no_recursion_flag = definitions + .get(&::declaration()) + .is_none(); + borsh::schema::add_definition( + ::declaration(), + definition, + definitions, + ); + if no_recursion_flag { + ::add_definitions_recursively(definitions); + } + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_false.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_false.snap new file mode 100644 index 0000000000000..f2d9971f7ce82 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_false.snap @@ -0,0 +1,30 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for X { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + X::A => 0u8, + X::B => 1u8, + X::C => 2u8, + X::D => 3u8, + X::E => 4u8, + X::F => 5u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + X::A => {} + X::B => {} + X::C => {} + X::D => {} + X::E => {} + X::F => {} + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_true.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_true.snap new file mode 100644 index 0000000000000..7191ea5bbf1db --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_true.snap @@ -0,0 +1,30 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for X { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + X::A => 0, + X::B => 20, + X::C => 20 + 1, + X::D => 20 + 1 + 1, + X::E => 10, + X::F => 10 + 1, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + X::A => {} + X::B => {} + X::C => {} + X::D => {} + X::E => {} + X::F => {} + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_all_fields.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_all_fields.snap new file mode 100644 index 0000000000000..27f0fc94574c4 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_all_fields.snap @@ -0,0 +1,24 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for AAB { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + AAB::B { .. } => 0u8, + AAB::NegatedVariant { .. } => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + AAB::B { .. } => {} + AAB::NegatedVariant { beta, .. } => { + borsh::BorshSerialize::serialize(beta, writer)?; + } + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_field.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_field.snap new file mode 100644 index 0000000000000..737f0a4787a2d --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_field.snap @@ -0,0 +1,26 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for AB { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + AB::B { .. } => 0u8, + AB::NegatedVariant { .. } => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + AB::B { d, .. } => { + borsh::BorshSerialize::serialize(d, writer)?; + } + AB::NegatedVariant { beta, .. } => { + borsh::BorshSerialize::serialize(beta, writer)?; + } + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_tuple_variant_field.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_tuple_variant_field.snap new file mode 100644 index 0000000000000..17d050126c343 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_tuple_variant_field.snap @@ -0,0 +1,24 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for AATTB { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + AATTB::B(..) => 0u8, + AATTB::NegatedVariant { .. } => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + AATTB::B(_id0, _id1) => {} + AATTB::NegatedVariant { beta, .. } => { + borsh::BorshSerialize::serialize(beta, writer)?; + } + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/bound_generics.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/bound_generics.snap new file mode 100644 index 0000000000000..5c4129d6824f0 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/bound_generics.snap @@ -0,0 +1,34 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for A +where + V: Value, + K: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, + U: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::B { .. } => 0u8, + A::C(..) => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + A::B { x, y, .. } => { + borsh::BorshSerialize::serialize(x, writer)?; + borsh::BorshSerialize::serialize(y, writer)?; + } + A::C(id0, id1) => { + borsh::BorshSerialize::serialize(id0, writer)?; + borsh::BorshSerialize::serialize(id1, writer)?; + } + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_attr.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_attr.snap new file mode 100644 index 0000000000000..33d2795beb8b2 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_attr.snap @@ -0,0 +1,32 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for C +where + K: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + C::C3(..) => 0u8, + C::C4 { .. } => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + C::C3(id0, id1) => { + borsh::BorshSerialize::serialize(id0, writer)?; + borsh::BorshSerialize::serialize(id1, writer)?; + } + C::C4 { x, y, .. } => { + borsh::BorshSerialize::serialize(x, writer)?; + third_party_impl::serialize_third_party(y, writer)?; + } + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_struct_field.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_struct_field.snap new file mode 100644 index 0000000000000..495a19a499c1b --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_struct_field.snap @@ -0,0 +1,32 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for A +where + V: Value, + K: borsh::ser::BorshSerialize, + U: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::B { .. } => 0u8, + A::C(..) => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + A::B { y, .. } => { + borsh::BorshSerialize::serialize(y, writer)?; + } + A::C(id0, id1) => { + borsh::BorshSerialize::serialize(id0, writer)?; + borsh::BorshSerialize::serialize(id1, writer)?; + } + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_tuple_field.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_tuple_field.snap new file mode 100644 index 0000000000000..75a2829367624 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_tuple_field.snap @@ -0,0 +1,32 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for A +where + V: Value, + K: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::B { .. } => 0u8, + A::C(..) => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + A::B { x, y, .. } => { + borsh::BorshSerialize::serialize(x, writer)?; + borsh::BorshSerialize::serialize(y, writer)?; + } + A::C(id0, _id1) => { + borsh::BorshSerialize::serialize(id0, writer)?; + } + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_bound.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_bound.snap new file mode 100644 index 0000000000000..687b35590b8f5 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_bound.snap @@ -0,0 +1,32 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for A +where + T: borsh::ser::BorshSerialize + PartialOrd, + U: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::C { .. } => 0u8, + A::D(..) => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + A::C { a, b, .. } => { + borsh::BorshSerialize::serialize(a, writer)?; + borsh::BorshSerialize::serialize(b, writer)?; + } + A::D(id0, id1) => { + borsh::BorshSerialize::serialize(id0, writer)?; + borsh::BorshSerialize::serialize(id1, writer)?; + } + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/recursive_enum.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/recursive_enum.snap new file mode 100644 index 0000000000000..2387e0c830a03 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/recursive_enum.snap @@ -0,0 +1,33 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for A +where + V: Value, + K: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::B { .. } => 0u8, + A::C(..) => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + A::B { x, y, .. } => { + borsh::BorshSerialize::serialize(x, writer)?; + borsh::BorshSerialize::serialize(y, writer)?; + } + A::C(id0, id1) => { + borsh::BorshSerialize::serialize(id0, writer)?; + borsh::BorshSerialize::serialize(id1, writer)?; + } + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/simple_enum_with_custom_crate.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/simple_enum_with_custom_crate.snap new file mode 100644 index 0000000000000..09de52a723c35 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/simple_enum_with_custom_crate.snap @@ -0,0 +1,27 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl reexporter::borsh::ser::BorshSerialize for AB { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), reexporter::borsh::io::Error> { + let variant_idx: u8 = match self { + AB::B { .. } => 0u8, + AB::NegatedVariant { .. } => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + AB::B { c, d, .. } => { + reexporter::borsh::BorshSerialize::serialize(c, writer)?; + reexporter::borsh::BorshSerialize::serialize(d, writer)?; + } + AB::NegatedVariant { beta, .. } => { + reexporter::borsh::BorshSerialize::serialize(beta, writer)?; + } + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/simple_generics.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/simple_generics.snap new file mode 100644 index 0000000000000..c6d201d8434c9 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/simple_generics.snap @@ -0,0 +1,33 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for A +where + K: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, + U: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::B { .. } => 0u8, + A::C(..) => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + A::B { x, y, .. } => { + borsh::BorshSerialize::serialize(x, writer)?; + borsh::BorshSerialize::serialize(y, writer)?; + } + A::C(id0, id1) => { + borsh::BorshSerialize::serialize(id0, writer)?; + borsh::BorshSerialize::serialize(id1, writer)?; + } + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/enums/snapshots/struct_variant_field.snap b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/struct_variant_field.snap new file mode 100644 index 0000000000000..508ee24e42952 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/enums/snapshots/struct_variant_field.snap @@ -0,0 +1,27 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for AB { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + AB::B { .. } => 0u8, + AB::NegatedVariant { .. } => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + AB::B { c, d, .. } => { + borsh::BorshSerialize::serialize(c, writer)?; + borsh::BorshSerialize::serialize(d, writer)?; + } + AB::NegatedVariant { beta, .. } => { + borsh::BorshSerialize::serialize(beta, writer)?; + } + } + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/bound_generics.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/bound_generics.snap new file mode 100644 index 0000000000000..c85a000f1e5c9 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/bound_generics.snap @@ -0,0 +1,20 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for A +where + V: Value, + K: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&self.x, writer)?; + borsh::BorshSerialize::serialize(&self.y, writer)?; + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_attr.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_attr.snap new file mode 100644 index 0000000000000..963dfcee6b440 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_attr.snap @@ -0,0 +1,19 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for A +where + K: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + third_party_impl::serialize_third_party(&self.x, writer)?; + borsh::BorshSerialize::serialize(&self.y, writer)?; + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_skip_conflict.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_skip_conflict.snap new file mode 100644 index 0000000000000..0334d44bb7b3f --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_skip_conflict.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: err +--- +Error( + "`skip` cannot be used at the same time as `serialize_with` or `deserialize_with`", +) diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_associated_type.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_associated_type.snap new file mode 100644 index 0000000000000..b35b0ee3c8e2e --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_associated_type.snap @@ -0,0 +1,20 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for Parametrized +where + T: TraitName, + T::Associated: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&self.field, writer)?; + borsh::BorshSerialize::serialize(&self.another, writer)?; + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap new file mode 100644 index 0000000000000..8a95e2685146f --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap @@ -0,0 +1,17 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for G +where + U: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&self.y, writer)?; + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_bound.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_bound.snap new file mode 100644 index 0000000000000..8b46520f1f3fa --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_bound.snap @@ -0,0 +1,19 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for C +where + T: borsh::ser::BorshSerialize + PartialOrd, + U: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&self.a, writer)?; + borsh::BorshSerialize::serialize(&self.b, writer)?; + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap new file mode 100644 index 0000000000000..ad07ce8469382 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap @@ -0,0 +1,17 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for G +where + U: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&self.1, writer)?; + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap new file mode 100644 index 0000000000000..0931db5bfd453 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap @@ -0,0 +1,18 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for G +where + K: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&self.0, writer)?; + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/override_generic_associated_type_wrong_derive.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/override_generic_associated_type_wrong_derive.snap new file mode 100644 index 0000000000000..42c701c9e66bc --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/override_generic_associated_type_wrong_derive.snap @@ -0,0 +1,20 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for Parametrized +where + T: TraitName, + V: borsh::ser::BorshSerialize, + ::Associated: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&self.field, writer)?; + borsh::BorshSerialize::serialize(&self.another, writer)?; + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/recursive_struct.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/recursive_struct.snap new file mode 100644 index 0000000000000..c97e45a5b8711 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/recursive_struct.snap @@ -0,0 +1,15 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for CRecC { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&self.a, writer)?; + borsh::BorshSerialize::serialize(&self.b, writer)?; + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/simple_generic_tuple_struct.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/simple_generic_tuple_struct.snap new file mode 100644 index 0000000000000..e7939c1ed0508 --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/simple_generic_tuple_struct.snap @@ -0,0 +1,18 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for TupleA +where + T: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&self.0, writer)?; + borsh::BorshSerialize::serialize(&self.1, writer)?; + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/simple_generics.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/simple_generics.snap new file mode 100644 index 0000000000000..bca9544e53b1d --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/simple_generics.snap @@ -0,0 +1,19 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for A +where + K: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, +{ + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&self.x, writer)?; + borsh::BorshSerialize::serialize(&self.y, writer)?; + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct.snap new file mode 100644 index 0000000000000..557d9ded2ee2e --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct.snap @@ -0,0 +1,15 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::ser::BorshSerialize for A { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&self.x, writer)?; + borsh::BorshSerialize::serialize(&self.y, writer)?; + Ok(()) + } +} + diff --git a/vendor/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct_with_custom_crate.snap b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct_with_custom_crate.snap new file mode 100644 index 0000000000000..c06c46f8cb84a --- /dev/null +++ b/vendor/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct_with_custom_crate.snap @@ -0,0 +1,15 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl reexporter::borsh::ser::BorshSerialize for A { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), reexporter::borsh::io::Error> { + reexporter::borsh::BorshSerialize::serialize(&self.x, writer)?; + reexporter::borsh::BorshSerialize::serialize(&self.y, writer)?; + Ok(()) + } +} + diff --git a/vendor/borsh/tests/test_arrays.rs b/vendor/borsh/tests/test_arrays.rs new file mode 100644 index 0000000000000..7defd8132086e --- /dev/null +++ b/vendor/borsh/tests/test_arrays.rs @@ -0,0 +1,81 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![allow(clippy::float_cmp)] + +use borsh::{from_slice, to_vec}; +#[cfg(feature = "derive")] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::string::{String, ToString}; + +macro_rules! test_array { + ($v: expr, $t: ty, $len: expr) => { + let buf = borsh::to_vec(&$v).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(buf); + let actual_v: [$t; $len] = from_slice(&buf).expect("failed to deserialize"); + assert_eq!($v.len(), actual_v.len()); + #[allow(clippy::reversed_empty_ranges)] + for i in 0..$len { + assert_eq!($v[i], actual_v[i]); + } + }; +} + +macro_rules! test_arrays { + ($test_name: ident, $el: expr, $t: ty) => { + #[test] + fn $test_name() { + test_array!([$el; 0], $t, 0); + test_array!([$el; 1], $t, 1); + test_array!([$el; 2], $t, 2); + test_array!([$el; 3], $t, 3); + test_array!([$el; 4], $t, 4); + test_array!([$el; 8], $t, 8); + test_array!([$el; 16], $t, 16); + test_array!([$el; 32], $t, 32); + test_array!([$el; 64], $t, 64); + test_array!([$el; 65], $t, 65); + } + }; +} + +test_arrays!(test_array_u8, 100u8, u8); +test_arrays!(test_array_i8, 100i8, i8); +test_arrays!(test_array_u32, 1000000000u32, u32); +test_arrays!(test_array_u64, 1000000000000000000u64, u64); +test_arrays!( + test_array_u128, + 1000000000000000000000000000000000000u128, + u128 +); +test_arrays!(test_array_f32, 1000000000.0f32, f32); +test_arrays!(test_array_array_u8, [100u8; 32], [u8; 32]); +test_arrays!(test_array_zst, (), ()); + +#[cfg(feature = "derive")] +#[derive(BorshDeserialize, BorshSerialize, PartialEq, Debug)] +struct CustomStruct(u8); + +#[cfg(feature = "derive")] +#[test] +fn test_custom_struct_array() { + let arr = [CustomStruct(0), CustomStruct(1), CustomStruct(2)]; + let serialized = to_vec(&arr).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(serialized); + let deserialized: [CustomStruct; 3] = from_slice(&serialized).unwrap(); + assert_eq!(arr, deserialized); +} + +#[test] +fn test_string_array() { + let arr = ["0".to_string(), "1".to_string(), "2".to_string()]; + let serialized = to_vec(&arr).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(serialized); + let deserialized: [String; 3] = from_slice(&serialized).unwrap(); + assert_eq!(arr, deserialized); +} diff --git a/vendor/borsh/tests/test_ascii_strings.rs b/vendor/borsh/tests/test_ascii_strings.rs new file mode 100644 index 0000000000000..ea8774c17bebe --- /dev/null +++ b/vendor/borsh/tests/test_ascii_strings.rs @@ -0,0 +1,134 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "ascii")] + +use borsh::{from_slice, to_vec}; + +extern crate alloc; +use alloc::string::String; + +/// Verifies serialisation and deserialisation of an ASCII string `value`. +fn check_ascii(value: &str) -> alloc::vec::Vec { + // Caller promises value is ASCII. + let ascii_str = ascii::AsciiStr::from_ascii(&value).unwrap(); + let buf = to_vec(ascii_str).unwrap(); + // AsciiStr and AsciiString serialise the same way String does. + assert_eq!(buf, to_vec(&ascii::AsciiString::from(ascii_str)).unwrap()); + // Check round trip. + let got = from_slice::(&buf).unwrap(); + assert_eq!(ascii_str, got); + buf +} + +macro_rules! test_ascii_string { + ($test_name: ident, $str: expr, $snap:expr) => { + #[test] + fn $test_name() { + let value = String::from($str); + let _buf = check_ascii(&value); + #[cfg(feature = "std")] + if $snap { + insta::assert_debug_snapshot!(_buf); + } + } + }; +} + +test_ascii_string!(test_empty_string, "", true); +test_ascii_string!(test_a, "a", true); +test_ascii_string!(test_hello_world, "hello world", true); +test_ascii_string!(test_x_1024, "x".repeat(1024), true); +test_ascii_string!(test_x_4096, "x".repeat(4096), false); +test_ascii_string!(test_x_65535, "x".repeat(65535), false); +test_ascii_string!(test_hello_10, "hello world!".repeat(30), true); +test_ascii_string!(test_hello_1000, "hello Achilles!".repeat(1000), false); + +#[test] +fn test_ascii_char() { + use ascii::AsciiChar; + + let buf = to_vec(&AsciiChar::Dot).unwrap(); + assert_eq!(".".as_bytes(), buf); + assert_eq!(AsciiChar::Dot, from_slice::(&buf).unwrap()); + + from_slice::(&[b'\x80']).unwrap_err(); +} + +mod de_errors { + use alloc::string::ToString; + use borsh::from_slice; + + #[test] + fn test_non_ascii() { + let buf = borsh::to_vec(&[0xbf, 0xf3, 0xb3, 0x77][..]).unwrap(); + assert_eq!( + from_slice::(&buf) + .unwrap_err() + .to_string(), + "the byte at index 0 is not ASCII" + ); + + let buf = borsh::to_vec("żółw").unwrap(); + assert_eq!( + from_slice::(&buf) + .unwrap_err() + .to_string(), + "the byte at index 0 is not ASCII" + ); + + assert_eq!( + from_slice::(&[0xbf]) + .unwrap_err() + .to_string(), + "not an ASCII character" + ); + } +} + +#[cfg(feature = "unstable__schema")] +mod schema { + use alloc::{collections::BTreeMap, string::ToString}; + use borsh::schema::{BorshSchema, Definition}; + macro_rules! map( + () => { BTreeMap::new() }; + { $($key:expr => $value:expr),+ } => { + { + let mut m = BTreeMap::new(); + $( + m.insert($key.to_string(), $value); + )+ + m + } + }; + ); + + #[test] + fn test_ascii_strings() { + assert_eq!("AsciiString", ascii::AsciiStr::declaration()); + assert_eq!("AsciiString", ascii::AsciiString::declaration()); + assert_eq!("AsciiChar", ascii::AsciiChar::declaration()); + + let want_char = map! { + "AsciiChar" => Definition::Primitive(1) + }; + let mut actual_defs = map!(); + ascii::AsciiChar::add_definitions_recursively(&mut actual_defs); + assert_eq!(want_char, actual_defs); + + let want = map! { + "AsciiString" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "AsciiChar".to_string() + }, + "AsciiChar" => Definition::Primitive(1) + }; + + let mut actual_defs = map!(); + ascii::AsciiStr::add_definitions_recursively(&mut actual_defs); + assert_eq!(want, actual_defs); + + let mut actual_defs = map!(); + ascii::AsciiString::add_definitions_recursively(&mut actual_defs); + assert_eq!(want, actual_defs); + } +} diff --git a/vendor/borsh/tests/test_bson_object_ids.rs b/vendor/borsh/tests/test_bson_object_ids.rs new file mode 100644 index 0000000000000..af4e5ebf97146 --- /dev/null +++ b/vendor/borsh/tests/test_bson_object_ids.rs @@ -0,0 +1,23 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![allow(clippy::float_cmp)] +#![cfg(feature = "derive")] + +use borsh::{from_slice, to_vec, BorshDeserialize, BorshSerialize}; +use bson::oid::ObjectId; + +#[derive(BorshDeserialize, BorshSerialize, PartialEq, Debug)] +struct StructWithObjectId(i32, ObjectId, u8); + +#[test] +fn test_object_id() { + let obj = StructWithObjectId( + 123, + ObjectId::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), + 33, + ); + let serialized = to_vec(&obj).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(serialized); + let deserialized: StructWithObjectId = from_slice(&serialized).unwrap(); + assert_eq!(obj, deserialized); +} diff --git a/vendor/borsh/tests/test_btree_map.rs b/vendor/borsh/tests/test_btree_map.rs new file mode 100644 index 0000000000000..e85754a5046cc --- /dev/null +++ b/vendor/borsh/tests/test_btree_map.rs @@ -0,0 +1,104 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "std")] +use std::collections::{BTreeMap, BTreeSet}; +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{ + collections::{BTreeMap, BTreeSet}, + string::{String, ToString}, + vec, + vec::Vec, +}; + +use borsh::{from_slice, BorshSerialize}; + +#[macro_use] +mod common_macro; + +macro_rules! btreeset_test_template [ + [$test_name: ident, $($key: expr),* ] => [ + #[allow(unused_mut)] + #[allow(redundant_semicolons)] + #[test] + fn $test_name() { + let mut set = BTreeSet::new(); + + set_insert_deser_assert_macro!(set, data, $($key),*); + + let actual_set = from_slice::>(&data).unwrap(); + assert_eq!(set, actual_set); + + } + + ] + +]; + +macro_rules! btreemap_test_template [ + [$test_name: ident, $($key: expr => $value: expr),* ] => [ + #[allow(unused_mut)] + #[allow(redundant_semicolons)] + #[test] + fn $test_name() { + let mut map = BTreeMap::new(); + + map_insert_deser_assert_macro!(map, data, $($key => $value),*); + + let actual_map = from_slice::>(&data).unwrap(); + assert_eq!(map, actual_map); + + } + + ] + +]; + +btreeset_test_template!(test_empty_btreeset,); + +btreeset_test_template!(test_1_element_btreeset, "one".to_string()); + +btreeset_test_template!( + test_2_element_btreeset, + "one".to_string(), + "different".to_string() +); + +btreeset_test_template!( + test_default_btreeset, + "foo".to_string(), + "many".to_string(), + "various".to_string(), + "different".to_string(), + "keys".to_string(), + "one".to_string() +); + +btreemap_test_template!(test_default_btreemap, + "foo".to_string() => "bar".to_string(), + "one".to_string() => "two".to_string() +); + +btreemap_test_template!(test_empty_btreemap,); +btreemap_test_template!(test_1_element_btreemap, + "one".to_string() => "element".to_string() +); + +btreemap_test_template!(test_8_element_btreemap, + "one".to_string() => "element".to_string(), + "key".to_string() => "powers".to_string(), + "more".to_string() => "of".to_string(), + "various".to_string() => "two".to_string(), + "different".to_string() => "are".to_string(), + "keys".to_string() => "always".to_string(), + "where".to_string() => "unpredictable".to_string(), + "nowhere".to_string() => "pile".to_string() +); + +#[cfg(feature = "de_strict_order")] +const ERROR_WRONG_ORDER_OF_KEYS: &str = "keys were not serialized in ascending order"; + +set_wrong_order_test!(test_btreeset_deser_err_wrong_order, BTreeSet); + +map_wrong_order_test!(test_btreemap_deser_err_wrong_order, BTreeMap); diff --git a/vendor/borsh/tests/test_custom_reader.rs b/vendor/borsh/tests/test_custom_reader.rs new file mode 100644 index 0000000000000..57773ca01d560 --- /dev/null +++ b/vendor/borsh/tests/test_custom_reader.rs @@ -0,0 +1,148 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "derive")] +use borsh::{from_reader, to_vec, BorshDeserialize, BorshSerialize}; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{ + string::{String, ToString}, + vec::Vec, +}; + +const ERROR_NOT_ALL_BYTES_READ: &str = "Not all bytes read"; +const ERROR_UNEXPECTED_LENGTH_OF_INPUT: &str = "Unexpected length of input"; + +#[derive(BorshSerialize, BorshDeserialize, Debug)] +struct Serializable { + item1: i32, + item2: String, + item3: f64, +} + +#[test] +fn test_custom_reader() { + let s = Serializable { + item1: 100, + item2: "foo".into(), + item3: 1.2345, + }; + let bytes = to_vec(&s).unwrap(); + let mut reader = CustomReader { + data: bytes, + read_index: 0, + }; + let de: Serializable = BorshDeserialize::deserialize_reader(&mut reader).unwrap(); + assert_eq!(de.item1, s.item1); + assert_eq!(de.item2, s.item2); + assert_eq!(de.item3, s.item3); +} + +#[test] +fn test_custom_reader_with_insufficient_data() { + let s = Serializable { + item1: 100, + item2: "foo".into(), + item3: 1.2345, + }; + let mut bytes = to_vec(&s).unwrap(); + bytes.pop().unwrap(); + let mut reader = CustomReader { + data: bytes, + read_index: 0, + }; + assert_eq!( + ::deserialize_reader(&mut reader) + .unwrap_err() + .to_string(), + ERROR_UNEXPECTED_LENGTH_OF_INPUT + ); +} + +#[test] +fn test_custom_reader_with_too_much_data() { + let s = Serializable { + item1: 100, + item2: "foo".into(), + item3: 1.2345, + }; + let mut bytes = to_vec(&s).unwrap(); + bytes.push(1); + let mut reader = CustomReader { + data: bytes, + read_index: 0, + }; + assert_eq!( + from_reader::(&mut reader) + .unwrap_err() + .to_string(), + ERROR_NOT_ALL_BYTES_READ + ); +} + +struct CustomReader { + data: Vec, + read_index: usize, +} + +impl borsh::io::Read for CustomReader { + fn read(&mut self, buf: &mut [u8]) -> borsh::io::Result { + let len = buf.len().min(self.data.len() - self.read_index); + buf[0..len].copy_from_slice(&self.data[self.read_index..self.read_index + len]); + self.read_index += len; + Ok(len) + } +} + +#[test] +fn test_custom_reader_that_doesnt_fill_slices() { + let s = Serializable { + item1: 100, + item2: "foo".into(), + item3: 1.2345, + }; + let bytes = to_vec(&s).unwrap(); + let mut reader = CustomReaderThatDoesntFillSlices { + data: bytes, + read_index: 0, + }; + let de: Serializable = BorshDeserialize::deserialize_reader(&mut reader).unwrap(); + assert_eq!(de.item1, s.item1); + assert_eq!(de.item2, s.item2); + assert_eq!(de.item3, s.item3); +} + +struct CustomReaderThatDoesntFillSlices { + data: Vec, + read_index: usize, +} + +impl borsh::io::Read for CustomReaderThatDoesntFillSlices { + fn read(&mut self, buf: &mut [u8]) -> borsh::io::Result { + let len = buf.len().min(self.data.len() - self.read_index); + let len = if len <= 1 { len } else { len / 2 }; + buf[0..len].copy_from_slice(&self.data[self.read_index..self.read_index + len]); + self.read_index += len; + Ok(len) + } +} + +#[test] +fn test_custom_reader_that_fails_preserves_error_information() { + let mut reader = CustomReaderThatFails; + + let err = from_reader::(&mut reader).unwrap_err(); + assert_eq!(err.to_string(), "I don't like to run"); + assert_eq!(err.kind(), borsh::io::ErrorKind::ConnectionAborted); +} + +struct CustomReaderThatFails; + +impl borsh::io::Read for CustomReaderThatFails { + fn read(&mut self, _buf: &mut [u8]) -> borsh::io::Result { + Err(borsh::io::Error::new( + borsh::io::ErrorKind::ConnectionAborted, + "I don't like to run", + )) + } +} diff --git a/vendor/borsh/tests/test_de_errors.rs b/vendor/borsh/tests/test_de_errors.rs new file mode 100644 index 0000000000000..88253823b96e2 --- /dev/null +++ b/vendor/borsh/tests/test_de_errors.rs @@ -0,0 +1,237 @@ +#![cfg_attr(not(feature = "std"), no_std)] +use borsh::from_slice; + +#[cfg(feature = "derive")] +use borsh::BorshDeserialize; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{ + format, + string::{String, ToString}, + vec, + vec::Vec, +}; + +#[cfg(feature = "derive")] +#[derive(BorshDeserialize, Debug)] +#[borsh(use_discriminant = true)] +enum A { + X, + Y, +} + +#[cfg(feature = "derive")] +#[derive(BorshDeserialize, Debug)] +#[borsh(use_discriminant = false)] +enum AWithUseDiscriminantFalse { + X, + Y, +} + +#[cfg(feature = "derive")] +#[derive(BorshDeserialize, Debug)] +struct B { + #[allow(unused)] + x: u64, + #[allow(unused)] + y: u32, +} + +const ERROR_UNEXPECTED_LENGTH_OF_INPUT: &str = "Unexpected length of input"; +const ERROR_INVALID_ZERO_VALUE: &str = "Expected a non-zero value"; + +#[cfg(feature = "derive")] +#[test] +fn test_missing_bytes() { + let bytes = vec![1, 0]; + assert_eq!( + from_slice::(&bytes).unwrap_err().to_string(), + ERROR_UNEXPECTED_LENGTH_OF_INPUT + ); +} + +#[cfg(feature = "derive")] +#[test] +fn test_invalid_enum_variant() { + let bytes = vec![123]; + assert_eq!( + from_slice::(&bytes).unwrap_err().to_string(), + "Unexpected variant tag: 123" + ); +} + +#[cfg(feature = "derive")] +#[test] +fn test_invalid_enum_variant_old() { + let bytes = vec![123]; + assert_eq!( + from_slice::(&bytes) + .unwrap_err() + .to_string(), + "Unexpected variant tag: 123" + ); +} + +#[test] +fn test_extra_bytes() { + let bytes = vec![1, 0, 0, 0, 32, 32]; + assert_eq!( + from_slice::>(&bytes).unwrap_err().to_string(), + "Not all bytes read" + ); +} + +#[test] +fn test_invalid_bool() { + for i in 2u8..=255 { + let bytes = [i]; + assert_eq!( + from_slice::(&bytes).unwrap_err().to_string(), + format!("Invalid bool representation: {}", i) + ); + } +} + +#[test] +fn test_invalid_option() { + for i in 2u8..=255 { + let bytes = [i, 32]; + assert_eq!( + from_slice::>(&bytes).unwrap_err().to_string(), + format!( + "Invalid Option representation: {}. The first byte must be 0 or 1", + i + ) + ); + } +} + +#[test] +fn test_invalid_result() { + for i in 2u8..=255 { + let bytes = [i, 0]; + assert_eq!( + from_slice::>(&bytes) + .unwrap_err() + .to_string(), + format!( + "Invalid Result representation: {}. The first byte must be 0 or 1", + i + ) + ); + } +} + +#[test] +fn test_invalid_length() { + let bytes = vec![255u8; 4]; + assert_eq!( + from_slice::>(&bytes).unwrap_err().to_string(), + ERROR_UNEXPECTED_LENGTH_OF_INPUT + ); +} + +#[test] +fn test_invalid_length_string() { + let bytes = vec![255u8; 4]; + assert_eq!( + from_slice::(&bytes).unwrap_err().to_string(), + ERROR_UNEXPECTED_LENGTH_OF_INPUT + ); +} + +#[test] +fn test_non_utf_string() { + let bytes = vec![1, 0, 0, 0, 0xC0]; + assert_eq!( + from_slice::(&bytes).unwrap_err().to_string(), + "invalid utf-8 sequence of 1 bytes from index 0" + ); +} + +#[test] +fn test_nan_float() { + let bytes = vec![0, 0, 192, 127]; + assert_eq!( + from_slice::(&bytes).unwrap_err().to_string(), + "For portability reasons we do not allow to deserialize NaNs." + ); +} + +#[test] +fn test_evil_bytes_vec_with_extra() { + // Should fail to allocate given length + // test takes a really long time if read() is used instead of read_exact() + let bytes = vec![255, 255, 255, 255, 32, 32]; + assert_eq!( + from_slice::>(&bytes).unwrap_err().to_string(), + ERROR_UNEXPECTED_LENGTH_OF_INPUT + ); +} + +#[test] +fn test_evil_bytes_string_extra() { + // Might fail if reading too much + let bytes = vec![255, 255, 255, 255, 32, 32]; + assert_eq!( + from_slice::(&bytes).unwrap_err().to_string(), + ERROR_UNEXPECTED_LENGTH_OF_INPUT + ); +} + +#[test] +fn test_zero_on_nonzero_integer_u8() { + let bytes = &[0]; + assert_eq!( + from_slice::(bytes) + .unwrap_err() + .to_string(), + ERROR_INVALID_ZERO_VALUE + ); +} + +#[test] +fn test_zero_on_nonzero_integer_u32() { + let bytes = &[0; 4]; + assert_eq!( + from_slice::(bytes) + .unwrap_err() + .to_string(), + ERROR_INVALID_ZERO_VALUE + ); +} + +#[test] +fn test_zero_on_nonzero_integer_i64() { + let bytes = &[0; 8]; + assert_eq!( + from_slice::(bytes) + .unwrap_err() + .to_string(), + ERROR_INVALID_ZERO_VALUE + ); +} + +#[test] +fn test_zero_on_nonzero_integer_usize() { + let bytes = &[0; 8]; + assert_eq!( + from_slice::(bytes) + .unwrap_err() + .to_string(), + ERROR_INVALID_ZERO_VALUE + ); +} + +#[test] +fn test_zero_on_nonzero_integer_missing_byte() { + let bytes = &[0; 7]; + assert_eq!( + from_slice::(bytes) + .unwrap_err() + .to_string(), + ERROR_UNEXPECTED_LENGTH_OF_INPUT + ); +} diff --git a/vendor/borsh/tests/test_enum_discriminants.rs b/vendor/borsh/tests/test_enum_discriminants.rs new file mode 100644 index 0000000000000..2fd9473cb3e6b --- /dev/null +++ b/vendor/borsh/tests/test_enum_discriminants.rs @@ -0,0 +1,314 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "derive")] + +#[cfg(not(feature = "std"))] +extern crate alloc; + +#[cfg(not(feature = "std"))] +use alloc::vec; + +use borsh::{from_slice, to_vec, BorshDeserialize, BorshSerialize}; + +// sequence, no unit enums +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Copy, Debug)] +#[borsh(use_discriminant = true)] +#[repr(u16)] +enum XY { + A, + B = 20, + C, + D(u32, u32), + E = 10, + F(u64), +} + +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Copy, Debug)] +#[borsh(use_discriminant = false)] +#[repr(u16)] +enum XYNoDiscriminant { + A, + B = 20, + C, + D(u32, u32), + E = 10, + F(u64), +} + +#[test] +fn test_discriminant_serde_no_unit_type() { + let values = vec![XY::A, XY::B, XY::C, XY::E, XY::D(12, 14), XY::F(35325423)]; + let expected_discriminants = [0u8, 20, 21, 10, 22, 11]; + + for (ind, value) in values.iter().enumerate() { + let data = to_vec(value).unwrap(); + assert_eq!(data[0], expected_discriminants[ind]); + assert_eq!(from_slice::(&data).unwrap(), values[ind]); + } +} + +#[test] +fn test_discriminant_serde_no_unit_type_no_use_discriminant() { + let values = vec![ + XYNoDiscriminant::A, + XYNoDiscriminant::B, + XYNoDiscriminant::C, + XYNoDiscriminant::D(12, 14), + XYNoDiscriminant::E, + XYNoDiscriminant::F(35325423), + ]; + let expected_discriminants = [0u8, 1, 2, 3, 4, 5]; + + for (ind, value) in values.iter().enumerate() { + let data = to_vec(value).unwrap(); + assert_eq!(data[0], expected_discriminants[ind]); + assert_eq!(from_slice::(&data).unwrap(), values[ind]); + } +} + +// minimal +#[derive(BorshSerialize)] +#[borsh(use_discriminant = true)] +enum MyDiscriminantEnum { + A = 20, +} + +#[derive(BorshSerialize)] +#[borsh(use_discriminant = false)] +enum MyDiscriminantEnumFalse { + A = 20, +} + +#[derive(BorshSerialize)] +enum MyEnumNoDiscriminant { + A, +} +#[test] +fn test_discriminant_minimal_true() { + assert_eq!(MyDiscriminantEnum::A as u8, 20); + assert_eq!(to_vec(&MyDiscriminantEnum::A).unwrap(), vec![20]); +} + +#[test] +fn test_discriminant_minimal_false() { + assert_eq!(MyDiscriminantEnumFalse::A as u8, 20); + assert_eq!( + to_vec(&MyEnumNoDiscriminant::A).unwrap(), + to_vec(&MyDiscriminantEnumFalse::A).unwrap(), + ); + assert_eq!(to_vec(&MyDiscriminantEnumFalse::A).unwrap(), vec![0]); +} + +// sequence +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Copy, Debug)] +#[borsh(use_discriminant = false)] +enum XNoDiscriminant { + A, + B = 20, + C, + D, + E = 10, + F, +} + +#[test] +fn test_discriminant_serde_no_use_discriminant() { + let values = vec![ + XNoDiscriminant::A, + XNoDiscriminant::B, + XNoDiscriminant::C, + XNoDiscriminant::D, + XNoDiscriminant::E, + XNoDiscriminant::F, + ]; + let expected_discriminants = [0u8, 1, 2, 3, 4, 5]; + for (index, value) in values.iter().enumerate() { + let data = to_vec(value).unwrap(); + assert_eq!(data[0], expected_discriminants[index]); + assert_eq!(from_slice::(&data).unwrap(), values[index]); + } +} +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] +struct D { + x: u64, +} + +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] +enum C { + C1, + C2(u64), + C3(u64, u64), + C4 { x: u64, y: u64 }, + C5(D), +} + +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Copy, Debug)] +#[borsh(use_discriminant = true)] +enum X { + A, + B = 20, + C, + D, + E = 10, + F, +} + +#[test] +fn test_discriminant_serialization() { + let values = vec![X::A, X::B, X::C, X::D, X::E, X::F]; + for value in values { + assert_eq!(to_vec(&value).unwrap(), [value as u8]); + } +} + +#[test] +fn test_discriminant_deserialization() { + let values = vec![X::A, X::B, X::C, X::D, X::E, X::F]; + for value in values { + assert_eq!(from_slice::(&[value as u8]).unwrap(), value,); + } +} + +#[test] +#[should_panic = "Unexpected variant tag: 2"] +fn test_deserialize_invalid_discriminant() { + from_slice::(&[2]).unwrap(); +} + +#[test] +fn test_discriminant_serde() { + let values = vec![X::A, X::B, X::C, X::D, X::E, X::F]; + let expected_discriminants = [0u8, 20, 21, 22, 10, 11]; + for (index, value) in values.iter().enumerate() { + let data = to_vec(value).unwrap(); + assert_eq!(data[0], expected_discriminants[index]); + assert_eq!(from_slice::(&data).unwrap(), values[index]); + } +} + +#[cfg(feature = "unstable__schema")] +mod schema { + #[cfg(not(feature = "std"))] + use alloc::{collections::BTreeMap, string::ToString, vec}; + + #[cfg(feature = "std")] + use std::collections::BTreeMap; + + macro_rules! map( + () => { BTreeMap::new() }; + { $($key:expr => $value:expr),+ } => { + { + let mut m = BTreeMap::new(); + $( + m.insert($key.to_string(), $value); + )+ + m + } + }; + ); + + use borsh::{ + schema::{Definition, Fields}, + BorshSchema, + }; + + #[allow(unused)] + #[derive(BorshSchema)] + #[borsh(use_discriminant = true)] + #[repr(i16)] + enum XY { + A, + B = 20, + C, + D(u32, u32), + E = 10, + F(u64), + } + + #[test] + fn test_schema_discriminant_no_unit_type() { + assert_eq!("XY".to_string(), XY::declaration()); + let mut defs = Default::default(); + XY::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "XY" => Definition::Enum { + tag_width: 1, + variants: vec![ + (0, "A".to_string(), "XYA".to_string()), + (20, "B".to_string(), "XYB".to_string()), + (21, "C".to_string(), "XYC".to_string()), + (22, "D".to_string(), "XYD".to_string()), + (10, "E".to_string(), "XYE".to_string()), + (11, "F".to_string(), "XYF".to_string()) + ] + }, + "XYA" => Definition::Struct{ fields: Fields::Empty }, + "XYB" => Definition::Struct{ fields: Fields::Empty }, + "XYC" => Definition::Struct{ fields: Fields::Empty }, + "XYD" => Definition::Struct{ fields: Fields::UnnamedFields( + vec!["u32".to_string(), "u32".to_string()] + )}, + "XYE" => Definition::Struct{ fields: Fields::Empty }, + "XYF" => Definition::Struct{ fields: Fields::UnnamedFields( + vec!["u64".to_string()] + + )}, + "u32" => Definition::Primitive(4), + "u64" => Definition::Primitive(8) + }, + defs + ); + } + + #[allow(unused)] + #[derive(BorshSchema)] + #[borsh(use_discriminant = false)] + #[repr(i16)] + enum XYNoDiscriminant { + A, + B = 20, + C, + D(u32, u32), + E = 10, + F(u64), + } + + #[test] + fn test_schema_discriminant_no_unit_type_no_use_discriminant() { + assert_eq!( + "XYNoDiscriminant".to_string(), + XYNoDiscriminant::declaration() + ); + let mut defs = Default::default(); + XYNoDiscriminant::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "XYNoDiscriminant" => Definition::Enum { + tag_width: 1, + variants: vec![ + (0, "A".to_string(), "XYNoDiscriminantA".to_string()), + (1, "B".to_string(), "XYNoDiscriminantB".to_string()), + (2, "C".to_string(), "XYNoDiscriminantC".to_string()), + (3, "D".to_string(), "XYNoDiscriminantD".to_string()), + (4, "E".to_string(), "XYNoDiscriminantE".to_string()), + (5, "F".to_string(), "XYNoDiscriminantF".to_string()) + ] + }, + "XYNoDiscriminantA" => Definition::Struct{ fields: Fields::Empty }, + "XYNoDiscriminantB" => Definition::Struct{ fields: Fields::Empty }, + "XYNoDiscriminantC" => Definition::Struct{ fields: Fields::Empty }, + "XYNoDiscriminantD" => Definition::Struct{ fields: Fields::UnnamedFields( + vec!["u32".to_string(), "u32".to_string()] + )}, + "XYNoDiscriminantE" => Definition::Struct{ fields: Fields::Empty }, + "XYNoDiscriminantF" => Definition::Struct{ fields: Fields::UnnamedFields( + vec!["u64".to_string()] + + )}, + "u32" => Definition::Primitive(4), + "u64" => Definition::Primitive(8) + }, + defs + ); + } +} diff --git a/vendor/borsh/tests/test_generic_struct.rs b/vendor/borsh/tests/test_generic_struct.rs new file mode 100644 index 0000000000000..d96d1ce4f28a3 --- /dev/null +++ b/vendor/borsh/tests/test_generic_struct.rs @@ -0,0 +1,238 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "derive")] +use core::marker::PhantomData; + +#[cfg(feature = "hashbrown")] +use hashbrown::HashMap; + +#[cfg(hash_collections)] +use core::{cmp::Eq, hash::Hash}; + +#[cfg(feature = "std")] +use std::collections::{BTreeMap, HashMap}; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{ + collections::BTreeMap, + string::{String, ToString}, + vec, + vec::Vec, +}; +#[cfg(not(feature = "std"))] +use core::result::Result; + +use borsh::{from_slice, to_vec, BorshDeserialize, BorshSerialize}; + +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] +struct A { + x: Vec, + y: String, + b: B, + pd: PhantomData, + c: Result, + d: [u64; 5], +} + +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] +enum B { + X { f: Vec }, + Y(G), +} + +#[derive(BorshSerialize, BorshDeserialize, Debug)] +struct TupleA(T, u32); + +#[derive(BorshSerialize, BorshDeserialize, Debug)] +struct NamedA { + a: T, + b: u32, +} + +/// `T: PartialOrd` bound is required for `BorshSerialize` derive to be successful +/// `T: Hash + Eq` bound is required for `BorshDeserialize` derive to be successful +#[cfg(hash_collections)] +#[derive(BorshSerialize, BorshDeserialize)] +struct C { + a: String, + b: HashMap, +} + +/// `T: PartialOrd` is injected here via field bound to avoid having this restriction on +/// the struct itself +#[cfg(hash_collections)] +#[derive(BorshSerialize)] +struct C1 { + a: String, + #[borsh(bound(serialize = "T: borsh::ser::BorshSerialize + Ord, + U: borsh::ser::BorshSerialize"))] + b: HashMap, +} + +/// `T: PartialOrd + Hash + Eq` is injected here via field bound to avoid having this restriction on +/// the struct itself +#[allow(unused)] +#[cfg(hash_collections)] +#[derive(BorshDeserialize)] +struct C2 { + a: String, + #[borsh(bound(deserialize = "T: Ord + Hash + Eq + borsh::de::BorshDeserialize, + U: borsh::de::BorshDeserialize"))] + b: HashMap, +} + +/// `T: Ord` bound is required for `BorshDeserialize` derive to be successful +#[derive(BorshSerialize, BorshDeserialize)] +struct D { + a: String, + b: BTreeMap, +} + +#[cfg(hash_collections)] +#[derive(BorshSerialize)] +struct G(#[borsh(skip)] HashMap, U); + +#[cfg(hash_collections)] +#[derive(BorshDeserialize)] +struct G1(#[borsh(skip)] HashMap, U); + +#[cfg(hash_collections)] +#[derive(BorshDeserialize)] +struct G2(HashMap, #[borsh(skip)] U); + +/// implicit derived `core::default::Default` bounds on `K` and `V` are dropped by empty bound +/// specified, as `HashMap` hash its own `Default` implementation +#[cfg(hash_collections)] +#[derive(BorshDeserialize)] +struct G3(#[borsh(skip, bound(deserialize = ""))] HashMap, U); + +#[cfg(hash_collections)] +#[derive(BorshSerialize, BorshDeserialize)] +struct H { + x: BTreeMap, + #[allow(unused)] + #[borsh(skip)] + y: U, +} + +/// `T: Ord` bound is required for `BorshDeserialize` derive to be successful +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] +enum E { + X { f: BTreeMap }, + Y(G), +} + +#[cfg(hash_collections)] +#[derive(BorshSerialize, BorshDeserialize, Debug)] +enum I1 { + B { + #[allow(unused)] + #[borsh(skip)] + x: HashMap, + y: String, + }, + C(K, Vec), +} + +#[cfg(hash_collections)] +#[derive(BorshSerialize, BorshDeserialize, Debug)] +enum I2 { + B { x: HashMap, y: String }, + C(K, #[borsh(skip)] U), +} + +trait TraitName { + type Associated; + fn method(&self); +} + +impl TraitName for u32 { + type Associated = String; + fn method(&self) {} +} + +#[allow(unused)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] +struct Parametrized +where + T: TraitName, +{ + field: T::Associated, + another: V, +} + +#[allow(unused)] +#[derive(BorshSerialize)] +struct ParametrizedWronDerive +where + T: TraitName, +{ + #[borsh(bound(serialize = "::Associated: borsh::ser::BorshSerialize"))] + field: ::Associated, + another: V, +} + +#[test] +fn test_generic_struct() { + let a = A:: { + x: vec!["foo".to_string(), "bar".to_string()], + pd: Default::default(), + y: "world".to_string(), + b: B::X { f: vec![1, 2] }, + c: Err("error".to_string()), + d: [0, 1, 2, 3, 4], + }; + let data = to_vec(&a).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(data); + let actual_a = from_slice::>(&data).unwrap(); + assert_eq!(a, actual_a); +} + +#[test] +fn test_generic_associated_type_field() { + let a = Parametrized:: { + field: "value".to_string(), + another: "field".to_string(), + }; + let data = to_vec(&a).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(data); + let actual_a = from_slice::>(&data).unwrap(); + assert_eq!(a, actual_a); +} + +#[cfg(hash_collections)] +#[test] +fn test_generic_struct_hashmap() { + let mut hashmap = HashMap::new(); + hashmap.insert(34, "another".to_string()); + hashmap.insert(14, "value".to_string()); + let a = C:: { + a: "field".to_string(), + b: hashmap, + }; + let data = to_vec(&a).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(data); + let actual_a = from_slice::>(&data).unwrap(); + assert_eq!(actual_a.b.get(&14), Some("value".to_string()).as_ref()); + assert_eq!(actual_a.b.get(&34), Some("another".to_string()).as_ref()); +} + +#[test] +fn test_generic_enum() { + let b: B = B::X { + f: vec!["one".to_string(), "two".to_string(), "three".to_string()], + }; + let c: B = B::Y(656556u64); + + let list = vec![b, c]; + let data = to_vec(&list).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(data); + let actual_list = from_slice::>>(&data).unwrap(); + + assert_eq!(list, actual_list); +} diff --git a/vendor/borsh/tests/test_hash_map.rs b/vendor/borsh/tests/test_hash_map.rs new file mode 100644 index 0000000000000..6c470fba20568 --- /dev/null +++ b/vendor/borsh/tests/test_hash_map.rs @@ -0,0 +1,222 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(hash_collections)] + +#[cfg(feature = "std")] +use core::hash::BuildHasher; + +#[cfg(feature = "hashbrown")] +use hashbrown::{HashMap, HashSet}; +#[cfg(feature = "std")] +use std::collections::{ + hash_map::{DefaultHasher, RandomState}, + HashMap, HashSet, +}; + +#[cfg(not(feature = "std"))] +use core::iter::IntoIterator; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{ + string::{String, ToString}, + vec, + vec::Vec, +}; + +use borsh::{from_slice, BorshSerialize}; + +#[macro_use] +mod common_macro; + +macro_rules! hashset_test_template [ + [$test_name: ident, $($key: expr),* ] => [ + #[allow(unused_mut)] + #[allow(redundant_semicolons)] + #[test] + fn $test_name() { + let mut set = HashSet::new(); + + set_insert_deser_assert_macro!(set, data, $($key),*); + + let actual_set = from_slice::>(&data).unwrap(); + assert_eq!(set, actual_set); + + } + + ] + +]; + +macro_rules! hashmap_test_template [ + [$test_name: ident, $($key: expr => $value: expr),* ] => [ + #[allow(unused_mut)] + #[allow(redundant_semicolons)] + #[test] + fn $test_name() { + let mut map = HashMap::new(); + + map_insert_deser_assert_macro!(map, data, $($key => $value),*); + + let actual_map = from_slice::>(&data).unwrap(); + assert_eq!(map, actual_map); + + } + + ] + +]; + +#[derive(Default)] +#[cfg(feature = "std")] +struct NewHasher(RandomState); + +#[cfg(feature = "std")] +impl BuildHasher for NewHasher { + type Hasher = DefaultHasher; + fn build_hasher(&self) -> DefaultHasher { + self.0.build_hasher() + } +} + +#[cfg(feature = "std")] +macro_rules! generic_hashset_test_template [ + [$test_name: ident, $($key: expr),* ] => [ + #[allow(unused_mut)] + #[allow(redundant_semicolons)] + #[test] + fn $test_name() { + let mut set = HashSet::with_hasher(NewHasher::default()); + + set_insert_deser_assert_macro!(set, data, $($key),*); + + let actual_set = from_slice::>(&data).unwrap(); + assert_eq!(set, actual_set); + + } + + ] + +]; + +#[cfg(feature = "std")] +macro_rules! generic_hashmap_test_template [ + [$test_name: ident, $($key: expr => $value: expr),* ] => [ + #[allow(unused_mut)] + #[allow(redundant_semicolons)] + #[test] + fn $test_name() { + let mut map = HashMap::with_hasher(NewHasher::default()); + + map_insert_deser_assert_macro!(map, data, $($key => $value),*); + + let actual_map = from_slice::>(&data).unwrap(); + assert_eq!(map, actual_map); + + } + + ] + +]; + +hashset_test_template!(test_empty_hashset,); + +hashset_test_template!(test_1_element_hashset, "one".to_string()); + +hashset_test_template!( + test_2_element_hashset, + "one".to_string(), + "different".to_string() +); + +hashset_test_template!( + test_default_hashset, + "foo".to_string(), + "many".to_string(), + "various".to_string(), + "different".to_string(), + "keys".to_string(), + "one".to_string() +); + +#[cfg(feature = "std")] +generic_hashset_test_template!(test_empty_generic_hashset,); + +#[cfg(feature = "std")] +generic_hashset_test_template!(test_1_element_generic_hashset, "one".to_string()); + +#[cfg(feature = "std")] +generic_hashset_test_template!( + test_2_element_generic_hashset, + "one".to_string(), + "different".to_string() +); + +#[cfg(feature = "std")] +generic_hashset_test_template!( + test_generic_hashset, + "foo".to_string(), + "many".to_string(), + "various".to_string(), + "different".to_string(), + "keys".to_string(), + "one".to_string() +); + +hashmap_test_template!(test_default_hashmap, + "foo".to_string() => "bar".to_string(), + "one".to_string() => "two".to_string() +); + +hashmap_test_template!(test_empty_hashmap,); +hashmap_test_template!(test_1_element_hashmap, + "one".to_string() => "element".to_string() +); + +hashmap_test_template!(test_8_element_hashmap, + "one".to_string() => "element".to_string(), + "key".to_string() => "powers".to_string(), + "more".to_string() => "of".to_string(), + "various".to_string() => "two".to_string(), + "different".to_string() => "are".to_string(), + "keys".to_string() => "always".to_string(), + "where".to_string() => "unpredictable".to_string(), + "nowhere".to_string() => "pile".to_string() +); + +#[cfg(feature = "std")] +generic_hashmap_test_template!(test_generic_hash_hashmap, + "foo".to_string() => "bar".to_string(), + "one".to_string() => "two".to_string() +); + +#[cfg(feature = "std")] +generic_hashmap_test_template!(test_empty_generic_hashmap,); +#[cfg(feature = "std")] +generic_hashmap_test_template!(test_1_element_generic_hashmap, + "one".to_string() => "element".to_string() +); + +#[cfg(feature = "std")] +generic_hashmap_test_template!(test_8_element_generic_hashmap, + "one".to_string() => "element".to_string(), + "key".to_string() => "powers".to_string(), + "more".to_string() => "of".to_string(), + "various".to_string() => "two".to_string(), + "different".to_string() => "are".to_string(), + "keys".to_string() => "always".to_string(), + "where".to_string() => "unpredictable".to_string(), + "nowhere".to_string() => "pile".to_string() +); + +#[cfg(feature = "de_strict_order")] +const ERROR_WRONG_ORDER_OF_KEYS: &str = "keys were not serialized in ascending order"; + +set_wrong_order_test!(test_hashset_deser_err_wrong_order, HashSet); +#[cfg(feature = "std")] +set_wrong_order_test!(test_generic_hashset_deser_err_wrong_order, HashSet); + +map_wrong_order_test!(test_hashmap_deser_err_wrong_order, HashMap); + +#[cfg(feature = "std")] +map_wrong_order_test!(test_generic_hashmap_deser_err_wrong_order, HashMap); diff --git a/vendor/borsh/tests/test_init_in_deserialize.rs b/vendor/borsh/tests/test_init_in_deserialize.rs new file mode 100644 index 0000000000000..f081aaccaa20a --- /dev/null +++ b/vendor/borsh/tests/test_init_in_deserialize.rs @@ -0,0 +1,56 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "derive")] + +use borsh::{from_slice, to_vec, BorshDeserialize, BorshSerialize}; +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] +#[borsh(init=init)] +struct A { + lazy: Option, +} + +impl A { + pub fn init(&mut self) { + if let Some(v) = self.lazy.as_mut() { + *v *= 10; + } + } +} +#[test] +fn test_simple_struct() { + let a = A { lazy: Some(5) }; + + let encoded_a = to_vec(&a).unwrap(); + + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(encoded_a); + + let decoded_a = from_slice::(&encoded_a).unwrap(); + let expected_a = A { lazy: Some(50) }; + assert_eq!(expected_a, decoded_a); +} + +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] +#[borsh(init=initialization_method)] +enum AEnum { + A, + B, + C, +} + +impl AEnum { + pub fn initialization_method(&mut self) { + *self = AEnum::C; + } +} + +#[test] +fn test_simple_enum() { + let a = AEnum::B; + let encoded_a = to_vec(&a).unwrap(); + + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(encoded_a); + + let decoded_a = from_slice::(&encoded_a).unwrap(); + assert_eq!(AEnum::C, decoded_a); +} diff --git a/vendor/borsh/tests/test_macro_namespace_collisions.rs b/vendor/borsh/tests/test_macro_namespace_collisions.rs new file mode 100644 index 0000000000000..83cf0435da1c2 --- /dev/null +++ b/vendor/borsh/tests/test_macro_namespace_collisions.rs @@ -0,0 +1,15 @@ +#![cfg_attr(not(feature = "std"), no_std)] +// Borsh macros should not collide with the local modules: +// https://github.com/near/borsh-rs/issues/11 +#![cfg(feature = "derive")] +mod std {} +mod core {} + +#[derive(borsh::BorshSerialize, borsh::BorshDeserialize)] +struct A; + +#[derive(borsh::BorshSerialize, borsh::BorshDeserialize)] +enum B { + C, + D, +} diff --git a/vendor/borsh/tests/test_nonzero_integers.rs b/vendor/borsh/tests/test_nonzero_integers.rs new file mode 100644 index 0000000000000..d41879097b956 --- /dev/null +++ b/vendor/borsh/tests/test_nonzero_integers.rs @@ -0,0 +1,33 @@ +#![cfg_attr(not(feature = "std"), no_std)] +use borsh::from_slice; +use core::num::*; + +#[test] +fn test_nonzero_integer_u8() { + let bytes = &[1]; + assert_eq!(from_slice::(bytes).unwrap().get(), 1); +} + +#[test] +fn test_nonzero_integer_u32() { + let bytes = &[255, 0, 0, 0]; + assert_eq!(from_slice::(bytes).unwrap().get(), 255); +} + +#[test] +fn test_nonzero_integer_usize() { + let bytes = &[1, 1, 0, 0, 0, 0, 0, 0]; + assert_eq!(from_slice::(bytes).unwrap().get(), 257); +} + +#[test] +fn test_nonzero_integer_i64() { + let bytes = &[255; 8]; + assert_eq!(from_slice::(bytes).unwrap().get(), -1); +} + +#[test] +fn test_nonzero_integer_i16b() { + let bytes = &[0, 0b1000_0000]; + assert_eq!(from_slice::(bytes).unwrap().get(), i16::MIN); +} diff --git a/vendor/borsh/tests/test_primitives.rs b/vendor/borsh/tests/test_primitives.rs new file mode 100644 index 0000000000000..aa74db385740e --- /dev/null +++ b/vendor/borsh/tests/test_primitives.rs @@ -0,0 +1,26 @@ +#![cfg_attr(not(feature = "std"), no_std)] +use borsh::{from_slice, to_vec}; + +macro_rules! test_primitive { + ($test_name: ident, $v: expr, $t: ty) => { + #[test] + fn $test_name() { + let expected: $t = $v; + + let buf = to_vec(&expected).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(buf); + let actual = from_slice::<$t>(&buf).expect("failed to deserialize"); + assert_eq!(actual, expected); + } + }; +} + +test_primitive!(test_isize_neg, -100isize, isize); +test_primitive!(test_isize_pos, 100isize, isize); +test_primitive!(test_isize_min, isize::min_value(), isize); +test_primitive!(test_isize_max, isize::max_value(), isize); + +test_primitive!(test_usize, 100usize, usize); +test_primitive!(test_usize_min, usize::min_value(), usize); +test_primitive!(test_usize_max, usize::max_value(), usize); diff --git a/vendor/borsh/tests/test_range.rs b/vendor/borsh/tests/test_range.rs new file mode 100644 index 0000000000000..5c9de9b8d2bc6 --- /dev/null +++ b/vendor/borsh/tests/test_range.rs @@ -0,0 +1,13 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +#[test] +fn test_ranges() { + let want = (1..2, 3..=4, 5.., ..6, ..=7, ..); + + let encoded = borsh::to_vec(&want).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(encoded); + + let got = borsh::from_slice(&encoded).unwrap(); + assert_eq!(want, got); +} diff --git a/vendor/borsh/tests/test_rc.rs b/vendor/borsh/tests/test_rc.rs new file mode 100644 index 0000000000000..ba1e3f9f1d84c --- /dev/null +++ b/vendor/borsh/tests/test_rc.rs @@ -0,0 +1,46 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "rc")] + +#[cfg(feature = "std")] +pub use std::{rc, sync}; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +pub use alloc::{rc, sync}; + +use borsh::{from_slice, to_vec}; + +#[test] +fn test_rc_roundtrip() { + let value = rc::Rc::new(8u8); + let serialized = to_vec(&value).unwrap(); + let deserialized = from_slice::>(&serialized).unwrap(); + assert_eq!(value, deserialized); +} + +#[test] +fn test_slice_rc() { + let original: &[i32] = &[1, 2, 3, 4, 6, 9, 10]; + let shared: rc::Rc<[i32]> = rc::Rc::from(original); + let serialized = to_vec(&shared).unwrap(); + let deserialized = from_slice::>(&serialized).unwrap(); + assert_eq!(original, &*deserialized); +} + +#[test] +fn test_arc_roundtrip() { + let value = sync::Arc::new(8u8); + let serialized = to_vec(&value).unwrap(); + let deserialized = from_slice::>(&serialized).unwrap(); + assert_eq!(value, deserialized); +} + +#[test] +fn test_slice_arc() { + let original: &[i32] = &[1, 2, 3, 4, 6, 9, 10]; + let shared: sync::Arc<[i32]> = sync::Arc::from(original); + let serialized = to_vec(&shared).unwrap(); + let deserialized = from_slice::>(&serialized).unwrap(); + assert_eq!(original, &*deserialized); +} diff --git a/vendor/borsh/tests/test_recursive_structs.rs b/vendor/borsh/tests/test_recursive_structs.rs new file mode 100644 index 0000000000000..dfbaf054fdb78 --- /dev/null +++ b/vendor/borsh/tests/test_recursive_structs.rs @@ -0,0 +1,89 @@ +#![cfg(feature = "derive")] +use borsh::{from_slice, to_vec, BorshDeserialize, BorshSerialize}; + +#[cfg(feature = "hashbrown")] +use hashbrown::HashMap; + +#[cfg(feature = "std")] +use std::collections::HashMap; + +#[cfg(hash_collections)] +use core::{cmp::Eq, hash::Hash}; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{boxed::Box, string::String, vec::Vec}; + +#[cfg(hash_collections)] +#[derive(BorshSerialize, BorshDeserialize)] +struct CRec { + a: String, + b: HashMap>, +} + +// `impl BorshDeserialize for Box` pulls in => `ToOwned` +// => pulls in at least `Clone` +#[derive(Clone, BorshSerialize, BorshDeserialize)] +struct CRecA { + a: String, + b: Box, +} + +#[derive(Debug, BorshSerialize, BorshDeserialize, PartialEq, Eq)] +struct CRecB { + a: String, + b: Vec, +} + +#[cfg(hash_collections)] +#[derive(BorshSerialize, BorshDeserialize)] +struct CRecC { + a: String, + b: HashMap, +} + +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] +enum ERecD { + B { x: String, y: i32 }, + C(u8, Vec), +} + +#[test] +fn test_recursive_struct() { + let one = CRecB { + a: "one".to_string(), + b: vec![], + }; + let two = CRecB { + a: "two".to_string(), + b: vec![], + }; + + let three = CRecB { + a: "three".to_string(), + b: vec![one, two], + }; + + let data = to_vec(&three).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(data); + let actual_three = from_slice::(&data).unwrap(); + assert_eq!(three, actual_three); +} + +#[test] +fn test_recursive_enum() { + let one = ERecD::B { + x: "one".to_string(), + y: 3213123, + }; + let two = ERecD::C(10, vec![]); + + let three = ERecD::C(11, vec![one, two]); + let data = to_vec(&three).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(data); + let actual_three = from_slice::(&data).unwrap(); + assert_eq!(three, actual_three); +} diff --git a/vendor/borsh/tests/test_schema_conflict.rs b/vendor/borsh/tests/test_schema_conflict.rs new file mode 100644 index 0000000000000..6d516091de09f --- /dev/null +++ b/vendor/borsh/tests/test_schema_conflict.rs @@ -0,0 +1,177 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "unstable__schema")] + +#[cfg(feature = "std")] +use std::collections::{BTreeMap, BTreeSet}; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{ + collections::{BTreeMap, BTreeSet}, + format, + string::ToString, + vec::Vec, +}; + +use borsh::schema::{add_definition, Declaration, Definition, Fields}; +use borsh::BorshSchema; + +struct ConflictingSchema; + +impl BorshSchema for ConflictingSchema { + #[inline] + fn add_definitions_recursively(definitions: &mut BTreeMap) { + let fields = Fields::Empty; + let def = Definition::Struct { fields }; + add_definition(Self::declaration(), def, definitions); + } + #[inline] + fn declaration() -> Declaration { + "i64".into() + } +} + +#[test] +#[should_panic(expected = "Redefining type schema for i64")] +fn test_conflict() { + let mut defs = Default::default(); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); + + ::add_definitions_recursively(&mut defs); +} + +#[test] +#[should_panic(expected = "Redefining type schema for i64")] +fn test_implicit_conflict_vec() { + let mut defs = Default::default(); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); +} + +#[test] +#[should_panic(expected = "Redefining type schema for i64")] +fn test_implicit_conflict_range() { + let mut defs = Default::default(); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); + as borsh::BorshSchema>::add_definitions_recursively( + &mut defs, + ); +} + +#[test] +#[should_panic(expected = "Redefining type schema for i64")] +fn test_implicit_conflict_slice() { + let mut defs = Default::default(); + <[i64] as borsh::BorshSchema>::add_definitions_recursively(&mut defs); + <[ConflictingSchema] as borsh::BorshSchema>::add_definitions_recursively(&mut defs); +} + +#[test] +#[should_panic(expected = "Redefining type schema for i64")] +fn test_implicit_conflict_array() { + let mut defs = Default::default(); + <[i64; 10] as borsh::BorshSchema>::add_definitions_recursively(&mut defs); + <[ConflictingSchema; 10] as borsh::BorshSchema>::add_definitions_recursively(&mut defs); +} + +#[test] +#[should_panic(expected = "Redefining type schema for i64")] +fn test_implicit_conflict_option() { + let mut defs = Default::default(); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); +} + +#[allow(unused)] +#[derive(borsh::BorshSchema)] +struct GenericStruct { + field: T, +} + +#[test] +fn test_implicit_conflict_struct() { + let mut defs = Default::default(); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); + as borsh::BorshSchema>::add_definitions_recursively( + &mut defs, + ); + // NOTE: the contents of `defs` depend on the order of 2 above lines + // this loophole is needed to enable derives for recursive structs/enums +} + +#[allow(unused)] +#[derive(borsh::BorshSchema)] +struct SelfConflictingStruct { + field_1: i64, + field_2: ConflictingSchema, +} + +#[test] +#[should_panic(expected = "Redefining type schema for i64")] +fn test_implicit_conflict_self_conflicting_struct() { + let mut defs = Default::default(); + ::add_definitions_recursively(&mut defs); +} + +#[allow(unused)] +#[derive(borsh::BorshSchema)] +enum GenericEnum { + A { field: T }, + B(u64), +} + +#[test] +fn test_implicit_conflict_enum() { + let mut defs = Default::default(); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); + // NOTE: the contents of `defs` depend on the order of 2 above lines + // this loophole is needed to enable derives for recursive structs/enums +} + +#[allow(unused)] +#[derive(borsh::BorshSchema)] +enum SelfConflictingEnum { + A { field: i64 }, + B { field: ConflictingSchema }, +} + +#[test] +#[should_panic(expected = "Redefining type schema for i64")] +fn test_implicit_conflict_self_conflicting_enum() { + let mut defs = Default::default(); + ::add_definitions_recursively(&mut defs); +} + +#[test] +#[should_panic(expected = "Redefining type schema for i64")] +fn test_implicit_conflict_result() { + let mut defs = Default::default(); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); +} + +#[test] +#[should_panic(expected = "Redefining type schema for i64")] +fn test_implicit_conflict_btreemap() { + let mut defs = Default::default(); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); +} + +#[test] +#[should_panic(expected = "Redefining type schema for i64")] +fn test_implicit_conflict_btreeset() { + let mut defs = Default::default(); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); + as borsh::BorshSchema>::add_definitions_recursively(&mut defs); +} + +#[test] +#[should_panic(expected = "Redefining type schema for i64")] +fn test_implicit_conflict_tuple() { + let mut defs = Default::default(); + <(i64, u8) as borsh::BorshSchema>::add_definitions_recursively(&mut defs); + <(ConflictingSchema, u8) as borsh::BorshSchema>::add_definitions_recursively(&mut defs); +} diff --git a/vendor/borsh/tests/test_schema_enums.rs b/vendor/borsh/tests/test_schema_enums.rs new file mode 100644 index 0000000000000..cb2cde7254616 --- /dev/null +++ b/vendor/borsh/tests/test_schema_enums.rs @@ -0,0 +1,387 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![allow(dead_code)] // Local structures do not have their fields used. +#![cfg(feature = "unstable__schema")] + +use core::fmt::{Debug, Display}; +#[cfg(feature = "std")] +use std::collections::BTreeMap; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{ + collections::BTreeMap, + format, + string::{String, ToString}, + vec, +}; + +use borsh::schema::*; +use borsh::{try_from_slice_with_schema, try_to_vec_with_schema}; + +macro_rules! map( + () => { BTreeMap::new() }; + { $($key:expr => $value:expr),+ } => { + { + let mut m = BTreeMap::new(); + $( + m.insert($key.to_string(), $value); + )+ + m + } + }; +); + +#[test] +pub fn simple_enum() { + #[derive(borsh::BorshSchema)] + enum A { + Bacon, + Eggs, + } + // https://github.com/near/borsh-rs/issues/112 + #[allow(unused)] + impl A { + pub fn declaration() -> usize { + 42 + } + } + assert_eq!("A".to_string(), ::declaration()); + let mut defs = Default::default(); + A::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "ABacon" => Definition::Struct{ fields: Fields::Empty }, + "AEggs" => Definition::Struct{ fields: Fields::Empty }, + "A" => Definition::Enum { + tag_width: 1, + variants: vec![(0, "Bacon".to_string(), "ABacon".to_string()), (1, "Eggs".to_string(), "AEggs".to_string())] + } + }, + defs + ); +} + +#[test] +pub fn single_field_enum() { + #[derive(borsh::BorshSchema)] + enum A { + Bacon, + } + assert_eq!("A".to_string(), A::declaration()); + let mut defs = Default::default(); + A::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "ABacon" => Definition::Struct {fields: Fields::Empty}, + "A" => Definition::Enum { + tag_width: 1, + variants: vec![(0, "Bacon".to_string(), "ABacon".to_string())] + } + }, + defs + ); +} + +/// test: Sausage wasn't populated with param Sausage +#[derive(borsh::BorshSchema, Debug)] +enum AWithSkip { + Bacon, + Eggs, + Salad(u32, C, u32), + Sausage { + #[borsh(skip)] + wrapper: W, + filling: u32, + }, +} + +/// test: inner structs in BorshSchema derive don't need any bounds, unrelated to BorshSchema +// #[derive(borsh::BorshSchema)] +// struct SideLeft( +// A, +// ) +// where +// A: Display + Debug, +// B: Display + Debug; +#[derive(borsh::BorshSchema)] +enum Side +where + A: Display + Debug, + B: Display + Debug, +{ + Left(A), + Right(B), +} + +#[test] +pub fn complex_enum_with_schema() { + #[derive( + borsh::BorshSchema, + Default, + borsh::BorshSerialize, + borsh::BorshDeserialize, + PartialEq, + Debug, + )] + struct Tomatoes; + #[derive( + borsh::BorshSchema, + Default, + borsh::BorshSerialize, + borsh::BorshDeserialize, + PartialEq, + Debug, + )] + struct Cucumber; + #[derive( + borsh::BorshSchema, + Default, + borsh::BorshSerialize, + borsh::BorshDeserialize, + PartialEq, + Debug, + )] + struct Oil; + #[derive( + borsh::BorshSchema, + Default, + borsh::BorshSerialize, + borsh::BorshDeserialize, + PartialEq, + Debug, + )] + struct Wrapper; + #[derive( + borsh::BorshSchema, + Default, + borsh::BorshSerialize, + borsh::BorshDeserialize, + PartialEq, + Debug, + )] + struct Filling; + #[derive( + borsh::BorshSchema, borsh::BorshSerialize, borsh::BorshDeserialize, PartialEq, Debug, + )] + enum A { + Bacon, + Eggs, + Salad(Tomatoes, Cucumber, Oil), + Sausage { wrapper: Wrapper, filling: Filling }, + } + + impl Default for A { + fn default() -> Self { + A::Sausage { + wrapper: Default::default(), + filling: Default::default(), + } + } + } + // First check schema. + assert_eq!("A".to_string(), A::declaration()); + let mut defs = Default::default(); + A::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "Cucumber" => Definition::Struct {fields: Fields::Empty}, + "ASalad" => Definition::Struct{ fields: Fields::UnnamedFields(vec!["Tomatoes".to_string(), "Cucumber".to_string(), "Oil".to_string()])}, + "ABacon" => Definition::Struct {fields: Fields::Empty}, + "Oil" => Definition::Struct {fields: Fields::Empty}, + "A" => Definition::Enum { + tag_width: 1, + variants: vec![ + (0, "Bacon".to_string(), "ABacon".to_string()), + (1, "Eggs".to_string(), "AEggs".to_string()), + (2, "Salad".to_string(), "ASalad".to_string()), + (3, "Sausage".to_string(), "ASausage".to_string()) + ] + }, + "Wrapper" => Definition::Struct {fields: Fields::Empty}, + "Tomatoes" => Definition::Struct {fields: Fields::Empty}, + "ASausage" => Definition::Struct { fields: Fields::NamedFields(vec![ + ("wrapper".to_string(), "Wrapper".to_string()), + ("filling".to_string(), "Filling".to_string()) + ])}, + "AEggs" => Definition::Struct {fields: Fields::Empty}, + "Filling" => Definition::Struct {fields: Fields::Empty} + }, + defs + ); + // Then check that we serialize and deserialize with schema. + let obj = A::default(); + let data = try_to_vec_with_schema(&obj).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(data); + let obj2: A = try_from_slice_with_schema(&data).unwrap(); + assert_eq!(obj, obj2); +} + +#[test] +pub fn complex_enum_generics() { + #[derive(borsh::BorshSchema)] + struct Tomatoes; + #[derive(borsh::BorshSchema)] + struct Cucumber; + #[derive(borsh::BorshSchema)] + struct Oil; + #[derive(borsh::BorshSchema)] + struct Wrapper; + #[derive(borsh::BorshSchema)] + struct Filling; + #[derive(borsh::BorshSchema)] + enum A { + Bacon, + Eggs, + Salad(Tomatoes, C, Oil), + Sausage { wrapper: W, filling: Filling }, + } + assert_eq!( + "A".to_string(), + >::declaration() + ); + let mut defs = Default::default(); + >::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "Cucumber" => Definition::Struct {fields: Fields::Empty}, + "ASalad" => Definition::Struct{ + fields: Fields::UnnamedFields(vec!["Tomatoes".to_string(), "Cucumber".to_string(), "Oil".to_string()]) + }, + "ABacon" => Definition::Struct {fields: Fields::Empty}, + "Oil" => Definition::Struct {fields: Fields::Empty}, + "A" => Definition::Enum { + tag_width: 1, + variants: vec![ + (0, "Bacon".to_string(), "ABacon".to_string()), + (1, "Eggs".to_string(), "AEggs".to_string()), + (2, "Salad".to_string(), "ASalad".to_string()), + (3, "Sausage".to_string(), "ASausage".to_string()) + ] + }, + "Wrapper" => Definition::Struct {fields: Fields::Empty}, + "Tomatoes" => Definition::Struct {fields: Fields::Empty}, + "ASausage" => Definition::Struct { + fields: Fields::NamedFields(vec![ + ("wrapper".to_string(), "Wrapper".to_string()), + ("filling".to_string(), "Filling".to_string()) + ]) + }, + "AEggs" => Definition::Struct {fields: Fields::Empty}, + "Filling" => Definition::Struct {fields: Fields::Empty} + }, + defs + ); +} + +fn common_map() -> BTreeMap { + map! { + "EnumParametrized" => Definition::Enum { + tag_width: 1, + variants: vec![ + (0, "B".to_string(), "EnumParametrizedB".to_string()), + (1, "C".to_string(), "EnumParametrizedC".to_string()) + ] + }, + "EnumParametrizedB" => Definition::Struct { fields: Fields::NamedFields(vec![ + ("x".to_string(), "BTreeMap".to_string()), + ("y".to_string(), "String".to_string()), + ("z".to_string(), "i8".to_string()) + ])}, + "EnumParametrizedC" => Definition::Struct{ fields: Fields::UnnamedFields(vec!["String".to_string(), "u16".to_string()])}, + "BTreeMap" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "(u32, u16)".to_string(), + }, + "(u32, u16)" => Definition::Tuple { elements: vec!["u32".to_string(), "u16".to_string()]}, + "u32" => Definition::Primitive(4), + "i8" => Definition::Primitive(1), + "u16" => Definition::Primitive(2), + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + }, + "u8" => Definition::Primitive(1) + } +} + +#[test] +pub fn generic_associated_item1() { + trait TraitName { + type Associated; + fn method(&self); + } + + impl TraitName for u32 { + type Associated = i8; + fn method(&self) {} + } + + #[allow(unused)] + #[derive(borsh::BorshSchema)] + enum EnumParametrized + where + K: TraitName, + K: core::cmp::Ord, + V: core::cmp::Ord, + { + B { + x: BTreeMap, + y: String, + z: K::Associated, + }, + C(T, u16), + } + + assert_eq!( + "EnumParametrized".to_string(), + >::declaration() + ); + + let mut defs = Default::default(); + >::add_definitions_recursively(&mut defs); + assert_eq!(common_map(), defs); +} + +#[test] +pub fn generic_associated_item2() { + trait TraitName { + type Associated; + fn method(&self); + } + + impl TraitName for u32 { + type Associated = i8; + fn method(&self) {} + } + + #[allow(unused)] + #[derive(borsh::BorshSchema)] + enum EnumParametrized + where + K: TraitName, + K: core::cmp::Ord, + V: core::cmp::Ord, + { + B { + x: BTreeMap, + y: String, + #[borsh(schema(params = "K => ::Associated"))] + z: ::Associated, + }, + C(T, u16), + } + + assert_eq!( + "EnumParametrized".to_string(), + >::declaration() + ); + + let mut defs = Default::default(); + >::add_definitions_recursively(&mut defs); + + assert_eq!(common_map(), defs); +} diff --git a/vendor/borsh/tests/test_schema_nested.rs b/vendor/borsh/tests/test_schema_nested.rs new file mode 100644 index 0000000000000..735a74230b0f5 --- /dev/null +++ b/vendor/borsh/tests/test_schema_nested.rs @@ -0,0 +1,131 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(hash_collections)] +#![allow(dead_code)] // Local structures do not have their fields used. +#![cfg(feature = "unstable__schema")] + +use borsh::schema::*; +#[cfg(feature = "hashbrown")] +use hashbrown::HashMap; +#[cfg(feature = "std")] +use std::collections::{BTreeMap, HashMap}; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{ + boxed::Box, + collections::BTreeMap, + format, + string::{String, ToString}, + vec, +}; + +macro_rules! map( + () => { BTreeMap::new() }; + { $($key:expr => $value:expr),+ } => { + { + let mut m = BTreeMap::new(); + $( + m.insert($key.to_string(), $value); + )+ + m + } + }; +); + +// Checks that recursive definitions work. Also checks that re-instantiations of templated types work. +#[cfg(hash_collections)] +#[test] +pub fn duplicated_instantiations() { + #[derive(borsh::BorshSchema)] + struct Tomatoes; + #[derive(borsh::BorshSchema)] + struct Cucumber; + #[derive(borsh::BorshSchema)] + struct Oil { + seeds: HashMap, + liquid: Option, + } + #[derive(borsh::BorshSchema)] + struct Wrapper { + foo: Option, + bar: Box>, + } + #[derive(borsh::BorshSchema)] + struct Filling; + #[derive(borsh::BorshSchema)] + enum A { + Bacon, + Eggs, + Salad(Tomatoes, C, Oil), + Sausage { wrapper: W, filling: Filling }, + } + assert_eq!( + "A>".to_string(), + >>::declaration() + ); + let mut defs = Default::default(); + >>::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "A>" => Definition::Enum { + tag_width: 1, + variants: vec![ + (0, "Bacon".to_string(), "ABacon".to_string()), + (1, "Eggs".to_string(), "AEggs".to_string()), + (2, "Salad".to_string(), "ASalad".to_string()), + (3, "Sausage".to_string(), "ASausage>".to_string()) + ] + }, + "A" => Definition::Enum { + tag_width: 1, + variants: vec![ + (0, "Bacon".to_string(), "ABacon".to_string()), + (1, "Eggs".to_string(), "AEggs".to_string()), + (2, "Salad".to_string(), "ASalad".to_string()), + (3, "Sausage".to_string(), "ASausage".to_string()) + ] + }, + "ABacon" => Definition::Struct {fields: Fields::Empty}, + "AEggs" => Definition::Struct {fields: Fields::Empty}, + "ASalad" => Definition::Struct {fields: Fields::UnnamedFields(vec!["Tomatoes".to_string(), "Cucumber".to_string(), "Oil".to_string()])}, + "ASalad" => Definition::Struct { fields: Fields::UnnamedFields( vec!["Tomatoes".to_string(), "String".to_string(), "Oil".to_string() ])}, + "ASausage>" => Definition::Struct {fields: Fields::NamedFields(vec![("wrapper".to_string(), "Wrapper".to_string()), ("filling".to_string(), "Filling".to_string())])}, + "ASausage" => Definition::Struct{ fields: Fields::NamedFields(vec![("wrapper".to_string(), "String".to_string()), ("filling".to_string(), "Filling".to_string())])}, + "Cucumber" => Definition::Struct {fields: Fields::Empty}, + "Filling" => Definition::Struct {fields: Fields::Empty}, + "HashMap" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "(u64, String)".to_string(), + }, + "Oil" => Definition::Struct { fields: Fields::NamedFields(vec![("seeds".to_string(), "HashMap".to_string()), ("liquid".to_string(), "Option".to_string())])}, + "Option" => Definition::Enum { + tag_width: 1, + variants: vec![ + (0, "None".to_string(), "()".to_string()), + (1, "Some".to_string(), "String".to_string()) + ] + }, + "Option" => Definition::Enum { + tag_width: 1, + variants: vec![ + (0, "None".to_string(), "()".to_string()), + (1, "Some".to_string(), "u64".to_string()) + ] + }, + "Tomatoes" => Definition::Struct {fields: Fields::Empty}, + "(u64, String)" => Definition::Tuple {elements: vec!["u64".to_string(), "String".to_string()]}, + "Wrapper" => Definition::Struct{ fields: Fields::NamedFields(vec![("foo".to_string(), "Option".to_string()), ("bar".to_string(), "A".to_string())])}, + "u64" => Definition::Primitive(8), + "()" => Definition::Primitive(0), + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + }, + "u8" => Definition::Primitive(1) + }, + defs + ); +} diff --git a/vendor/borsh/tests/test_schema_primitives.rs b/vendor/borsh/tests/test_schema_primitives.rs new file mode 100644 index 0000000000000..473e2bd6a2279 --- /dev/null +++ b/vendor/borsh/tests/test_schema_primitives.rs @@ -0,0 +1,58 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(hash_collections)] +#![cfg(feature = "unstable__schema")] + +#[cfg(feature = "std")] +use std::collections::BTreeMap; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{collections::BTreeMap, string::ToString}; + +use borsh::{schema::*, schema_container_of}; + +macro_rules! map( + () => { BTreeMap::new() }; + { $($key:expr => $value:expr),+ } => { + { + let mut m = BTreeMap::new(); + $( + m.insert($key.to_string(), $value); + )+ + m + } + }; +); + +#[test] +fn isize_schema() { + let schema = schema_container_of::(); + + assert_eq!( + schema, + BorshSchemaContainer::new( + "i64".to_string(), + map! { + "i64" => Definition::Primitive(8) + + } + ) + ) +} + +#[test] +fn usize_schema() { + let schema = schema_container_of::(); + + assert_eq!( + schema, + BorshSchemaContainer::new( + "u64".to_string(), + map! { + "u64" => Definition::Primitive(8) + + } + ) + ) +} diff --git a/vendor/borsh/tests/test_schema_recursive.rs b/vendor/borsh/tests/test_schema_recursive.rs new file mode 100644 index 0000000000000..63cd2171c84a1 --- /dev/null +++ b/vendor/borsh/tests/test_schema_recursive.rs @@ -0,0 +1,121 @@ +#![cfg(feature = "unstable__schema")] + +#[cfg(feature = "std")] +use std::collections::BTreeMap; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{collections::BTreeMap, string::ToString, vec}; + +use borsh::schema::*; + +#[allow(unused)] +#[derive(borsh::BorshSchema)] +struct CRecC { + a: String, + b: BTreeMap, +} + +#[allow(unused)] +#[derive(borsh::BorshSchema)] +enum ERecD { + B { x: String, y: i32 }, + C(u8, Vec), +} + +macro_rules! map( + () => { BTreeMap::new() }; + { $($key:expr => $value:expr),+ } => { + { + let mut m = BTreeMap::new(); + $( + m.insert($key.to_string(), $value); + )+ + m + } + }; +); + +#[test] +pub fn recursive_struct_schema() { + let mut defs = Default::default(); + CRecC::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "CRecC" => Definition::Struct { + fields: Fields::NamedFields( + vec![ + ( + "a".to_string(), + "String".to_string(), + ), + ( + "b".to_string(), + "BTreeMap".to_string(), + ), + ] + + ) + + }, + "BTreeMap" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "(String, CRecC)".to_string(), + }, + "(String, CRecC)" => Definition::Tuple {elements: vec!["String".to_string(), "CRecC".to_string()]}, + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + }, + "u8" => Definition::Primitive(1) + }, + defs + ); +} + +#[test] +pub fn recursive_enum_schema() { + let mut defs = Default::default(); + ERecD::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "ERecD" => Definition::Enum { + tag_width: 1, + variants: vec![ + (0, "B".to_string(), "ERecDB".to_string()), + (1, "C".to_string(), "ERecDC".to_string()), + ] + }, + "ERecDB" => Definition::Struct { + fields: Fields::NamedFields ( + vec![ + ("x".to_string(), "String".to_string()), + ("y".to_string(), "i32".to_string()), + ] + ) + }, + "ERecDC" => Definition::Struct { + fields: Fields::UnnamedFields( vec![ + "u8".to_string(), + "Vec".to_string(), + ]) + }, + "Vec" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "ERecD".to_string(), + }, + "i32" => Definition::Primitive(4), + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + }, + "u8" => Definition::Primitive(1) + }, + defs + ); +} diff --git a/vendor/borsh/tests/test_schema_structs.rs b/vendor/borsh/tests/test_schema_structs.rs new file mode 100644 index 0000000000000..4a4b6d5e8d244 --- /dev/null +++ b/vendor/borsh/tests/test_schema_structs.rs @@ -0,0 +1,402 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "unstable__schema")] + +use borsh::schema::*; + +#[cfg(feature = "hashbrown")] +use hashbrown::HashMap; + +use core::marker::PhantomData; +#[cfg(feature = "std")] +use std::collections::{BTreeMap, HashMap}; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{ + boxed::Box, + collections::BTreeMap, + format, + string::{String, ToString}, + vec, +}; + +macro_rules! map( + () => { BTreeMap::new() }; + { $($key:expr => $value:expr),+ } => { + { + let mut m = BTreeMap::new(); + $( + m.insert($key.to_string(), $value); + )+ + m + } + }; +); + +#[test] +pub fn unit_struct() { + #[derive(borsh::BorshSchema)] + struct A; + + // https://github.com/near/borsh-rs/issues/112 + #[allow(unused)] + impl A { + pub fn declaration() -> usize { + 42 + } + } + assert_eq!("A".to_string(), ::declaration()); + let mut defs = Default::default(); + A::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "A" => Definition::Struct {fields: Fields::Empty} + }, + defs + ); +} + +#[test] +pub fn simple_struct() { + #[derive(borsh::BorshSchema)] + struct A { + _f1: u64, + _f2: String, + } + assert_eq!("A".to_string(), A::declaration()); + let mut defs = Default::default(); + A::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "A" => Definition::Struct{ fields: Fields::NamedFields(vec![ + ("_f1".to_string(), "u64".to_string()), + ("_f2".to_string(), "String".to_string()) + ])}, + "u64" => Definition::Primitive(8), + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + }, + "u8" => Definition::Primitive(1) + }, + defs + ); +} + +#[test] +pub fn boxed() { + #[derive(borsh::BorshSchema)] + struct A { + _f1: Box, + _f2: Box, + _f3: Box<[u8]>, + } + assert_eq!("A".to_string(), A::declaration()); + let mut defs = Default::default(); + A::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "Vec" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string(), + }, + "A" => Definition::Struct{ fields: Fields::NamedFields(vec![ + ("_f1".to_string(), "u64".to_string()), + ("_f2".to_string(), "String".to_string()), + ("_f3".to_string(), "Vec".to_string()) + ])}, + "u64" => Definition::Primitive(8), + "u8" => Definition::Primitive(1), + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + } + }, + defs + ); +} + +#[test] +pub fn wrapper_struct() { + #[derive(borsh::BorshSchema)] + struct A(T); + assert_eq!("A".to_string(), >::declaration()); + let mut defs = Default::default(); + >::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "A" => Definition::Struct {fields: Fields::UnnamedFields(vec!["u64".to_string()])}, + "u64" => Definition::Primitive(8) + }, + defs + ); +} + +#[test] +pub fn tuple_struct() { + #[derive(borsh::BorshSchema)] + struct A(u64, String); + assert_eq!("A".to_string(), A::declaration()); + let mut defs = Default::default(); + A::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "A" => Definition::Struct {fields: Fields::UnnamedFields(vec![ + "u64".to_string(), "String".to_string() + ])}, + "u64" => Definition::Primitive(8), + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + }, + "u8" => Definition::Primitive(1) + }, + defs + ); +} + +#[test] +pub fn tuple_struct_params() { + #[derive(borsh::BorshSchema)] + struct A(K, V); + assert_eq!( + "A".to_string(), + >::declaration() + ); + let mut defs = Default::default(); + >::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "A" => Definition::Struct { fields: Fields::UnnamedFields(vec![ + "u64".to_string(), "String".to_string() + ])}, + "u64" => Definition::Primitive(8), + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + }, + "u8" => Definition::Primitive(1) + }, + defs + ); +} + +#[cfg(hash_collections)] +#[test] +pub fn simple_generics() { + #[derive(borsh::BorshSchema)] + struct A { + _f1: HashMap, + _f2: String, + } + assert_eq!( + "A".to_string(), + >::declaration() + ); + let mut defs = Default::default(); + >::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "A" => Definition::Struct { + fields: Fields::NamedFields(vec![ + ("_f1".to_string(), "HashMap".to_string()), + ("_f2".to_string(), "String".to_string()) + ]) + }, + "HashMap" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "(u64, String)".to_string(), + }, + "(u64, String)" => Definition::Tuple{elements: vec!["u64".to_string(), "String".to_string()]}, + "u64" => Definition::Primitive(8), + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + }, + "u8" => Definition::Primitive(1) + }, + defs + ); +} + +fn common_map() -> BTreeMap { + map! { + + "Parametrized" => Definition::Struct { + fields: Fields::NamedFields(vec![ + ("field".to_string(), "i8".to_string()), + ("another".to_string(), "String".to_string()) + ]) + }, + "i8" => Definition::Primitive(1), + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + }, + "u8" => Definition::Primitive(1) + } +} + +#[test] +pub fn generic_associated_item() { + trait TraitName { + type Associated; + fn method(&self); + } + + impl TraitName for u32 { + type Associated = i8; + fn method(&self) {} + } + + #[allow(unused)] + #[derive(borsh::BorshSchema)] + struct Parametrized + where + T: TraitName, + { + field: T::Associated, + another: V, + } + + assert_eq!( + "Parametrized".to_string(), + >::declaration() + ); + + let mut defs = Default::default(); + >::add_definitions_recursively(&mut defs); + assert_eq!(common_map(), defs); +} + +#[test] +pub fn generic_associated_item2() { + trait TraitName { + type Associated; + fn method(&self); + } + + impl TraitName for u32 { + type Associated = i8; + fn method(&self) {} + } + + #[allow(unused)] + #[derive(borsh::BorshSchema)] + struct Parametrized + where + T: TraitName, + { + #[borsh(schema(params = "T => ::Associated"))] + field: ::Associated, + another: V, + } + + assert_eq!( + "Parametrized".to_string(), + >::declaration() + ); + + let mut defs = Default::default(); + >::add_definitions_recursively(&mut defs); + assert_eq!(common_map(), defs); +} + +#[test] +pub fn generic_associated_item3() { + trait TraitName { + type Associated; + fn method(&self); + } + + impl TraitName for u32 { + type Associated = i8; + fn method(&self) {} + } + + #[allow(unused)] + #[derive(borsh::BorshSchema)] + struct Parametrized + where + T: TraitName, + { + #[borsh(schema(params = "T => T, T => ::Associated"))] + field: (::Associated, T), + another: V, + } + + assert_eq!( + "Parametrized".to_string(), + >::declaration() + ); + + let mut defs = Default::default(); + >::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "Parametrized" => Definition::Struct { + fields: Fields::NamedFields(vec![ + ("field".to_string(), "(i8, u32)".to_string()), + ("another".to_string(), "String".to_string()) + ]) + }, + "(i8, u32)" => Definition::Tuple { + elements: vec!["i8".to_string(), "u32".to_string()] + }, + "i8" => Definition::Primitive(1), + "u32" => Definition::Primitive(4), + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + }, + "u8" => Definition::Primitive(1) + }, + defs + ); +} + +#[test] +pub fn with_phantom_data() { + #[allow(unused)] + #[derive(borsh::BorshSchema)] + struct Parametrized { + field: K, + another: PhantomData, + } + + assert_eq!( + "Parametrized".to_string(), + >::declaration() + ); + + let mut defs = Default::default(); + >::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "Parametrized" => Definition::Struct { + fields: Fields::NamedFields(vec![ + ("field".to_string(), "String".to_string()), + ("another".to_string(), "()".to_string()) + ]) + }, + "()" => Definition::Primitive(0), + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + }, + "u8" => Definition::Primitive(1) + }, + defs + ); +} diff --git a/vendor/borsh/tests/test_schema_tuple.rs b/vendor/borsh/tests/test_schema_tuple.rs new file mode 100644 index 0000000000000..c3892d048ed6c --- /dev/null +++ b/vendor/borsh/tests/test_schema_tuple.rs @@ -0,0 +1,39 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "unstable__schema")] + +#[cfg(feature = "std")] +use std::collections::BTreeMap; + +use borsh::schema::*; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{collections::BTreeMap, string::ToString, vec}; + +macro_rules! map( + () => { BTreeMap::new() }; + { $($key:expr => $value:expr),+ } => { + { + let mut m = BTreeMap::new(); + $( + m.insert($key.to_string(), $value); + )+ + m + } + }; +); + +#[test] +fn test_unary_tuple_schema() { + assert_eq!("(bool,)", <(bool,)>::declaration()); + let mut defs = Default::default(); + <(bool,)>::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "(bool,)" => Definition::Tuple { elements: vec!["bool".to_string()] }, + "bool" => Definition::Primitive(1) + }, + defs + ); +} diff --git a/vendor/borsh/tests/test_schema_validate.rs b/vendor/borsh/tests/test_schema_validate.rs new file mode 100644 index 0000000000000..fe82a146bf48a --- /dev/null +++ b/vendor/borsh/tests/test_schema_validate.rs @@ -0,0 +1,99 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "unstable__schema")] + +#[cfg(feature = "std")] +use std::collections::BTreeMap; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{boxed::Box, collections::BTreeMap, format, string::ToString, vec::Vec}; + +use borsh::schema::*; +use borsh::BorshSchema; + +#[track_caller] +fn test_ok() { + let schema = BorshSchemaContainer::for_type::(); + assert_eq!(Ok(()), schema.validate()); +} + +#[track_caller] +fn test_err(err: SchemaContainerValidateError) { + let schema = BorshSchemaContainer::for_type::(); + assert_eq!(Err(err), schema.validate()); +} + +#[test] +fn validate_for_derived_types() { + #[derive(BorshSchema)] + pub struct Empty; + + #[derive(BorshSchema)] + pub struct Named { + _foo: usize, + _bar: [u8; 15], + } + + #[derive(BorshSchema)] + pub struct Unnamed(usize, [u8; 15]); + + #[derive(BorshSchema)] + struct Recursive(Option>); + + #[derive(BorshSchema)] + struct RecursiveSequence(Vec); + + // thankfully, this one cannot be constructed + #[derive(BorshSchema)] + struct RecursiveArray(Box<[RecursiveArray; 3]>); + + test_ok::(); + test_ok::(); + test_ok::(); + test_ok::(); + test_ok::(); + test_ok::(); + test_ok::(); + + test_ok::<[(); 300]>(); +} + +#[test] +fn validate_for_zst_sequences() { + test_err::>>(SchemaContainerValidateError::ZSTSequence( + "Vec<()>".to_string(), + )); + test_err::>(SchemaContainerValidateError::ZSTSequence( + "Vec".to_string(), + )); +} + +#[test] +fn max_serialized_size_bound_vec() { + #[allow(dead_code)] + struct BoundVec; + + impl BorshSchema for BoundVec { + fn declaration() -> Declaration { + format!("BoundVec<{}, {}>", W, N) + } + fn add_definitions_recursively(definitions: &mut BTreeMap) { + let definition = Definition::Sequence { + length_width: W, + length_range: 0..=N, + elements: "u8".to_string(), + }; + add_definition(Self::declaration(), definition, definitions); + u8::add_definitions_recursively(definitions); + } + } + + test_ok::>(); + test_err::>(SchemaContainerValidateError::TagTooNarrow( + "BoundVec<1, 65535>".to_string(), + )); + + test_ok::>(); + test_ok::>(); +} diff --git a/vendor/borsh/tests/test_schema_vec.rs b/vendor/borsh/tests/test_schema_vec.rs new file mode 100644 index 0000000000000..7ff3932ca978a --- /dev/null +++ b/vendor/borsh/tests/test_schema_vec.rs @@ -0,0 +1,68 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(hash_collections)] +#![cfg(feature = "unstable__schema")] + +#[cfg(feature = "std")] +use std::collections::BTreeMap; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{collections::BTreeMap, string::ToString}; + +use borsh::{schema::*, schema_container_of}; + +macro_rules! map( + () => { BTreeMap::new() }; + { $($key:expr => $value:expr),+ } => { + { + let mut m = BTreeMap::new(); + $( + m.insert($key.to_string(), $value); + )+ + m + } + }; +); + +#[test] +fn slice_schema_container() { + let schema = schema_container_of::<[i64]>(); + + assert_eq!( + schema, + BorshSchemaContainer::new( + "Vec".to_string(), + map! { + "Vec" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "i64".to_string(), + }, + "i64" => Definition::Primitive(8) + + } + ) + ) +} + +#[test] +fn vec_schema_container() { + let schema = schema_container_of::>(); + + assert_eq!( + schema, + BorshSchemaContainer::new( + "Vec".to_string(), + map! { + "Vec" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "i64".to_string(), + }, + "i64" => Definition::Primitive(8) + + } + ) + ) +} diff --git a/vendor/borsh/tests/test_schema_with.rs b/vendor/borsh/tests/test_schema_with.rs new file mode 100644 index 0000000000000..b337ab51e9cd9 --- /dev/null +++ b/vendor/borsh/tests/test_schema_with.rs @@ -0,0 +1,174 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "unstable__schema")] + +#[cfg(feature = "std")] +use std::collections::BTreeMap; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{ + collections::BTreeMap, + format, + string::{String, ToString}, + vec, +}; + +use borsh::schema::*; +use borsh::BorshSchema; + +macro_rules! map( + () => { BTreeMap::new() }; + { $($key:expr => $value:expr),+ } => { + { + let mut m = BTreeMap::new(); + $( + m.insert($key.to_string(), $value); + )+ + m + } + }; +); + +#[allow(unused)] +struct ThirdParty(BTreeMap); +#[allow(unused)] +mod third_party_impl { + + #[cfg(feature = "std")] + use std::collections::BTreeMap; + + #[cfg(not(feature = "std"))] + use alloc::{ + borrow, + boxed::Box, + collections::BTreeMap, + format, + string::{String, ToString}, + vec, + vec::Vec, + }; + use borsh::BorshSchema; + + pub(super) fn declaration( + ) -> borsh::schema::Declaration { + let params = vec![::declaration(), ::declaration()]; + format!(r#"{}<{}>"#, "ThirdParty", params.join(", ")) + } + + pub(super) fn add_definitions_recursively( + definitions: &mut BTreeMap, + ) { + let fields = borsh::schema::Fields::UnnamedFields(vec![ + as borsh::BorshSchema>::declaration(), + ]); + let definition = borsh::schema::Definition::Struct { fields }; + let no_recursion_flag = definitions.get(&declaration::()).is_none(); + borsh::schema::add_definition(declaration::(), definition, definitions); + if no_recursion_flag { + as borsh::BorshSchema>::add_definitions_recursively(definitions); + } + } +} + +#[allow(unused)] +#[derive(BorshSchema)] +struct A { + #[borsh(schema(with_funcs( + declaration = "third_party_impl::declaration::", + definitions = "third_party_impl::add_definitions_recursively::" + )))] + x: ThirdParty, + y: u64, +} + +#[allow(unused)] +#[derive(BorshSchema)] +enum C { + C3(u64, u64), + C4( + u64, + #[borsh(schema(with_funcs( + declaration = "third_party_impl::declaration::", + definitions = "third_party_impl::add_definitions_recursively::" + )))] + ThirdParty, + ), +} + +#[test] +pub fn struct_overriden() { + assert_eq!( + "A".to_string(), + >::declaration() + ); + let mut defs = Default::default(); + >::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "A" => Definition::Struct { fields: Fields::NamedFields(vec![ + ("x".to_string(), "ThirdParty".to_string()), + ("y".to_string(), "u64".to_string())] + )}, + "ThirdParty" => Definition::Struct { fields: Fields::UnnamedFields(vec![ + "BTreeMap".to_string(), + ]) }, + "BTreeMap"=> Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "(u64, String)".to_string(), + }, + "(u64, String)" => Definition::Tuple { elements: vec!["u64".to_string(), "String".to_string()]}, + "u64" => Definition::Primitive(8), + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + }, + "u8" => Definition::Primitive(1) + }, + defs + ); +} + +#[test] +pub fn enum_overriden() { + assert_eq!( + "C".to_string(), + >::declaration() + ); + let mut defs = Default::default(); + >::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "C" => Definition::Enum { + tag_width: 1, + variants: vec![ + (0, "C3".to_string(), "CC3".to_string()), + (1, "C4".to_string(), "CC4".to_string()) + ] + }, + "CC3" => Definition::Struct { fields: Fields::UnnamedFields(vec!["u64".to_string(), "u64".to_string()]) }, + "CC4" => Definition::Struct { fields: Fields::UnnamedFields(vec![ + "u64".to_string(), "ThirdParty".to_string() + ]) }, + "ThirdParty" => Definition::Struct { fields: Fields::UnnamedFields(vec![ + "BTreeMap".to_string(), + ]) }, + "BTreeMap"=> Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "(u64, String)".to_string(), + }, + "(u64, String)" => Definition::Tuple { elements: vec!["u64".to_string(), "String".to_string()]}, + "u64" => Definition::Primitive(8), + "String" => Definition::Sequence { + length_width: Definition::DEFAULT_LENGTH_WIDTH, + length_range: Definition::DEFAULT_LENGTH_RANGE, + elements: "u8".to_string() + }, + "u8" => Definition::Primitive(1) + }, + defs + ); +} diff --git a/vendor/borsh/tests/test_ser_de_with.rs b/vendor/borsh/tests/test_ser_de_with.rs new file mode 100644 index 0000000000000..cb8e769bbf7ee --- /dev/null +++ b/vendor/borsh/tests/test_ser_de_with.rs @@ -0,0 +1,107 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "derive")] + +#[cfg(feature = "std")] +use std::collections::BTreeMap; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{ + collections::BTreeMap, + string::{String, ToString}, +}; +use borsh::{from_slice, to_vec, BorshDeserialize, BorshSerialize}; + +#[derive(Debug, PartialEq, Eq)] +struct ThirdParty(pub BTreeMap); + +mod third_party_impl { + use super::ThirdParty; + + pub(super) fn serialize_third_party< + K: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, + W: borsh::io::Write, + >( + obj: &ThirdParty, + writer: &mut W, + ) -> ::core::result::Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&obj.0, writer)?; + Ok(()) + } + + pub(super) fn deserialize_third_party< + R: borsh::io::Read, + K: borsh::de::BorshDeserialize + Ord, + V: borsh::de::BorshDeserialize, + >( + reader: &mut R, + ) -> ::core::result::Result, borsh::io::Error> { + Ok(ThirdParty(borsh::BorshDeserialize::deserialize_reader( + reader, + )?)) + } +} + +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug)] +struct A { + #[borsh( + deserialize_with = "third_party_impl::deserialize_third_party", + serialize_with = "third_party_impl::serialize_third_party", + bound( + deserialize = "K: borsh::de::BorshDeserialize + Ord, V: borsh::de::BorshDeserialize", + ) + )] + x: ThirdParty, + y: u64, +} + +#[allow(unused)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug)] +enum C { + C3(u64, u64), + C4( + u64, + #[borsh( + deserialize_with = "third_party_impl::deserialize_third_party", + serialize_with = "third_party_impl::serialize_third_party", + bound( + deserialize = "K: borsh::de::BorshDeserialize + Ord, V: borsh::de::BorshDeserialize", + ) + )] + ThirdParty, + ), +} + +#[test] +fn test_overriden_struct() { + let mut m = BTreeMap::::new(); + m.insert(0, "0th element".to_string()); + m.insert(1, "1st element".to_string()); + let th_p = ThirdParty(m); + let a = A { x: th_p, y: 42 }; + + let data = to_vec(&a).unwrap(); + + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(data); + let actual_a = from_slice::>(&data).unwrap(); + assert_eq!(a, actual_a); +} + +#[test] +fn test_overriden_enum() { + let mut m = BTreeMap::::new(); + m.insert(0, "0th element".to_string()); + m.insert(1, "1st element".to_string()); + let th_p = ThirdParty(m); + let c = C::C4(42, th_p); + + let data = to_vec(&c).unwrap(); + + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(data); + let actual_c = from_slice::>(&data).unwrap(); + assert_eq!(c, actual_c); +} diff --git a/vendor/borsh/tests/test_simple_structs.rs b/vendor/borsh/tests/test_simple_structs.rs new file mode 100644 index 0000000000000..647bf3fe3acfb --- /dev/null +++ b/vendor/borsh/tests/test_simple_structs.rs @@ -0,0 +1,225 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "derive")] + +#[cfg(feature = "std")] +use std::{ + borrow, + collections::{BTreeMap, BTreeSet, LinkedList, VecDeque}, + ops, +}; + +#[cfg(not(feature = "std"))] +use core::{ops, result::Result}; + +#[cfg(not(feature = "std"))] +extern crate alloc; + +#[cfg(not(feature = "std"))] +use alloc::{ + borrow, + boxed::Box, + collections::{BTreeMap, BTreeSet, LinkedList, VecDeque}, + string::{String, ToString}, + vec, + vec::Vec, +}; + +use bytes::{Bytes, BytesMut}; + +use borsh::{from_slice, to_vec, BorshDeserialize, BorshSerialize}; + +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] +struct A<'a> { + x: u64, + b: B, + y: f32, + z: String, + t: (String, u64), + btree_map_string: BTreeMap, + btree_set_u64: BTreeSet, + linked_list_string: LinkedList, + vec_deque_u64: VecDeque, + bytes: Bytes, + bytes_mut: BytesMut, + v: Vec, + w: Box<[u8]>, + box_str: Box, + i: [u8; 32], + u: Result, + lazy: Option, + c: borrow::Cow<'a, str>, + cow_arr: borrow::Cow<'a, [borrow::Cow<'a, str>]>, + range_u32: ops::Range, + #[borsh(skip)] + skipped: Option, +} + +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] +struct B { + x: u64, + y: i32, + c: C, +} + +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] +enum C { + C1, + C2(u64), + C3(u64, u64), + C4 { x: u64, y: u64 }, + C5(D), +} + +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] +struct D { + x: u64, +} + +#[derive(BorshSerialize)] +struct E<'a, 'b> { + a: &'a A<'b>, +} + +#[derive(BorshSerialize)] +struct F1<'a, 'b> { + aa: &'a [&'a A<'b>], +} + +#[derive(BorshDeserialize)] +struct F2<'b> { + aa: Vec>, +} + +#[test] +fn test_ultimate_combined_all_features() { + let mut map: BTreeMap = BTreeMap::new(); + map.insert("test".into(), "test".into()); + let mut set: BTreeSet = BTreeSet::new(); + set.insert(u64::MAX); + let cow_arr = [ + borrow::Cow::Borrowed("Hello1"), + borrow::Cow::Owned("Hello2".to_string()), + ]; + let a = A { + x: 1, + b: B { + x: 2, + y: 3, + c: C::C5(D { x: 1 }), + }, + y: 4.0, + z: "123".to_string(), + t: ("Hello".to_string(), 10), + btree_map_string: map.clone(), + btree_set_u64: set.clone(), + linked_list_string: vec!["a".to_string(), "b".to_string()].into_iter().collect(), + vec_deque_u64: vec![1, 2, 3].into_iter().collect(), + bytes: vec![5, 4, 3, 2, 1].into(), + bytes_mut: BytesMut::from(&[1, 2, 3, 4, 5][..]), + v: vec!["qwe".to_string(), "zxc".to_string()], + w: vec![0].into_boxed_slice(), + box_str: Box::from("asd"), + i: [4u8; 32], + u: Ok("Hello".to_string()), + lazy: Some(5), + c: borrow::Cow::Borrowed("Hello"), + cow_arr: borrow::Cow::Borrowed(&cow_arr), + range_u32: 12..71, + skipped: Some(6), + }; + let encoded_a = to_vec(&a).unwrap(); + let e = E { a: &a }; + let encoded_ref_a = to_vec(&e).unwrap(); + assert_eq!(encoded_ref_a, encoded_a); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(encoded_a); + + let decoded_a = from_slice::(&encoded_a).unwrap(); + let expected_a = A { + x: 1, + b: B { + x: 2, + y: 3, + c: C::C5(D { x: 1 }), + }, + y: 4.0, + z: a.z.clone(), + t: ("Hello".to_string(), 10), + btree_map_string: map, + btree_set_u64: set, + linked_list_string: vec!["a".to_string(), "b".to_string()].into_iter().collect(), + vec_deque_u64: vec![1, 2, 3].into_iter().collect(), + bytes: vec![5, 4, 3, 2, 1].into(), + bytes_mut: BytesMut::from(&[1, 2, 3, 4, 5][..]), + v: a.v.clone(), + w: a.w.clone(), + box_str: Box::from("asd"), + i: a.i, + u: Ok("Hello".to_string()), + lazy: Some(5), + c: borrow::Cow::Owned("Hello".to_string()), + cow_arr: borrow::Cow::Owned(vec![ + borrow::Cow::Borrowed("Hello1"), + borrow::Cow::Owned("Hello2".to_string()), + ]), + range_u32: 12..71, + skipped: None, + }; + + assert_eq!(expected_a, decoded_a); + + let f1 = F1 { aa: &[&a, &a] }; + let encoded_f1 = to_vec(&f1).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(encoded_f1); + let decoded_f2 = from_slice::(&encoded_f1).unwrap(); + assert_eq!(decoded_f2.aa.len(), 2); + assert!(decoded_f2.aa.iter().all(|f2_a| f2_a == &expected_a)); +} + +#[test] +fn test_object_length() { + let mut map: BTreeMap = BTreeMap::new(); + map.insert("test".into(), "test".into()); + let mut set: BTreeSet = BTreeSet::new(); + set.insert(u64::MAX); + set.insert(100); + set.insert(103); + set.insert(109); + let cow_arr = [ + borrow::Cow::Borrowed("Hello1"), + borrow::Cow::Owned("Hello2".to_string()), + ]; + let a = A { + x: 1, + b: B { + x: 2, + y: 3, + c: C::C5(D { x: 1 }), + }, + y: 4.0, + z: "123".to_string(), + t: ("Hello".to_string(), 10), + btree_map_string: map.clone(), + btree_set_u64: set.clone(), + linked_list_string: vec!["a".to_string(), "b".to_string()].into_iter().collect(), + vec_deque_u64: vec![1, 2, 3].into_iter().collect(), + bytes: vec![5, 4, 3, 2, 1].into(), + bytes_mut: BytesMut::from(&[1, 2, 3, 4, 5][..]), + v: vec!["qwe".to_string(), "zxc".to_string()], + w: vec![0].into_boxed_slice(), + box_str: Box::from("asd"), + i: [4u8; 32], + u: Ok("Hello".to_string()), + lazy: Some(5), + c: borrow::Cow::Borrowed("Hello"), + cow_arr: borrow::Cow::Borrowed(&cow_arr), + range_u32: 12..71, + skipped: Some(6), + }; + let encoded_a_len = to_vec(&a).unwrap().len(); + + let len_helper_result = borsh::object_length(&a).unwrap(); + + assert_eq!(encoded_a_len, len_helper_result); +} diff --git a/vendor/borsh/tests/test_strings.rs b/vendor/borsh/tests/test_strings.rs new file mode 100644 index 0000000000000..e3bbe79bfd0f6 --- /dev/null +++ b/vendor/borsh/tests/test_strings.rs @@ -0,0 +1,44 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +use alloc::string::String; +use borsh::{from_slice, to_vec}; + +/// Verifies serialisation and deserialisation of the given string. +/// +/// Returns serialised representation of the string. +fn check_string(value: &str) -> alloc::vec::Vec { + // Encoding is the same as Vec with UTF-8 encoded string. + let buf = to_vec(value.as_bytes()).unwrap(); + assert_eq!(buf, to_vec(value).unwrap()); + assert_eq!(buf, to_vec(&String::from(value)).unwrap()); + // Check round trip. + assert_eq!(value, from_slice::(&buf).unwrap()); + buf +} + +macro_rules! test_string { + ($test_name: ident, $str: expr, $snap:expr) => { + #[test] + fn $test_name() { + let value = String::from($str); + let _buf = check_string(&value); + #[cfg(feature = "std")] + if $snap { + insta::assert_debug_snapshot!(_buf); + } + } + }; +} + +test_string!(test_empty_string, "", true); +test_string!(test_a, "a", true); +test_string!(test_hello_world, "hello world", true); +test_string!(test_x_1024, "x".repeat(1024), true); +test_string!(test_x_4096, "x".repeat(4096), false); +test_string!(test_x_65535, "x".repeat(65535), false); +test_string!(test_hello_10, "hello world!".repeat(30), true); +test_string!(test_hello_1000, "hello world!".repeat(1000), false); + +test_string!(test_non_ascii, "💩", true); diff --git a/vendor/borsh/tests/test_tuple.rs b/vendor/borsh/tests/test_tuple.rs new file mode 100644 index 0000000000000..92e98e1496475 --- /dev/null +++ b/vendor/borsh/tests/test_tuple.rs @@ -0,0 +1,12 @@ +#![cfg_attr(not(feature = "std"), no_std)] +use borsh::{from_slice, to_vec}; + +#[test] +fn test_unary_tuple() { + let expected = (true,); + let buf = to_vec(&expected).unwrap(); + #[cfg(feature = "std")] + insta::assert_debug_snapshot!(buf); + let actual = from_slice::<(bool,)>(&buf).expect("failed to deserialize"); + assert_eq!(actual, expected); +} diff --git a/vendor/borsh/tests/test_vecs.rs b/vendor/borsh/tests/test_vecs.rs new file mode 100644 index 0000000000000..e55babc736fb6 --- /dev/null +++ b/vendor/borsh/tests/test_vecs.rs @@ -0,0 +1,45 @@ +#![cfg_attr(not(feature = "std"), no_std)] +use borsh::{from_slice, to_vec}; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{ + string::{String, ToString}, + vec, + vec::Vec, +}; + +macro_rules! test_vec { + ($v: expr, $t: ty, $snap: expr) => { + let buf = to_vec(&$v).unwrap(); + #[cfg(feature = "std")] + if $snap { + insta::assert_debug_snapshot!(buf); + } + let actual_v: Vec<$t> = from_slice(&buf).expect("failed to deserialize"); + assert_eq!(actual_v, $v); + }; +} + +macro_rules! test_vecs { + ($test_name: ident, $el: expr, $t: ty) => { + #[test] + fn $test_name() { + test_vec!(Vec::<$t>::new(), $t, true); + test_vec!(vec![$el], $t, true); + test_vec!(vec![$el; 10], $t, true); + test_vec!(vec![$el; 100], $t, true); + test_vec!(vec![$el; 1000], $t, false); // one assumes that the concept has been proved + test_vec!(vec![$el; 10000], $t, false); + } + }; +} + +test_vecs!(test_vec_u8, 100u8, u8); +test_vecs!(test_vec_i8, 100i8, i8); +test_vecs!(test_vec_u32, 1000000000u32, u32); +test_vecs!(test_vec_f32, 1000000000.0f32, f32); +test_vecs!(test_vec_string, "a".to_string(), String); +test_vecs!(test_vec_vec_u8, vec![100u8; 10], Vec); +test_vecs!(test_vec_vec_u32, vec![100u32; 10], Vec); diff --git a/vendor/borsh/tests/test_zero_sized_types.rs b/vendor/borsh/tests/test_zero_sized_types.rs new file mode 100644 index 0000000000000..ce4a877eb39c8 --- /dev/null +++ b/vendor/borsh/tests/test_zero_sized_types.rs @@ -0,0 +1,156 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "derive")] + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{string::ToString, vec, vec::Vec}; + +#[cfg(feature = "std")] +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, LinkedList, VecDeque}; + +#[cfg(not(feature = "std"))] +use alloc::collections::{BTreeMap, BTreeSet, LinkedList, VecDeque}; +#[cfg(feature = "hashbrown")] +use hashbrown::{HashMap, HashSet}; + +use borsh::from_slice; +use borsh::to_vec; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +use borsh::error::ERROR_ZST_FORBIDDEN; +#[derive(BorshDeserialize, BorshSerialize, PartialEq, Debug, Eq, PartialOrd, Ord, Hash)] +struct A(); + +#[test] +fn test_deserialize_vec_of_zst() { + let v = [0u8, 0u8, 0u8, 64u8]; + let res = from_slice::>(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[test] +fn test_serialize_vec_of_zst() { + let v = vec![A()]; + let res = to_vec(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[test] +fn test_serialize_vec_of_unit_type() { + let v = vec![(), (), ()]; + let res = to_vec(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[test] +fn test_serialize_vec_of_vec_of_unit_type() { + let v: Vec> = vec![vec![(), (), ()]]; + let res = to_vec(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[test] +fn test_deserialize_vec_deque_of_zst() { + let v = [0u8, 0u8, 0u8, 64u8]; + let res = from_slice::>(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[test] +fn test_serialize_vec_deque_of_zst() { + let v: VecDeque = vec![A()].into(); + let res = to_vec(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[test] +fn test_deserialize_linked_list_of_zst() { + let v = [0u8, 0u8, 0u8, 64u8]; + let res = from_slice::>(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[test] +fn test_serialize_linked_list_of_zst() { + let v: LinkedList = vec![A()].into_iter().collect(); + let res = to_vec(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[test] +fn test_deserialize_btreeset_of_zst() { + let v = [0u8, 0u8, 0u8, 64u8]; + let res = from_slice::>(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[test] +fn test_serialize_btreeset_of_zst() { + let v: BTreeSet = vec![A()].into_iter().collect(); + let res = to_vec(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[cfg(hash_collections)] +#[test] +fn test_deserialize_hashset_of_zst() { + let v = [0u8, 0u8, 0u8, 64u8]; + let res = from_slice::>(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[cfg(hash_collections)] +#[test] +fn test_serialize_hashset_of_zst() { + let v: HashSet = vec![A()].into_iter().collect(); + let res = to_vec(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[test] +fn test_deserialize_btreemap_of_zst() { + let v = [0u8, 0u8, 0u8, 64u8]; + let res = from_slice::>(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[test] +fn test_serialize_btreemap_of_zst() { + let v: BTreeMap = vec![(A(), 42u64)].into_iter().collect(); + let res = to_vec(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[cfg(hash_collections)] +#[test] +fn test_deserialize_hashmap_of_zst() { + let v = [0u8, 0u8, 0u8, 64u8]; + let res = from_slice::>(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[cfg(hash_collections)] +#[test] +fn test_serialize_hashmap_of_zst() { + let v: HashMap = vec![(A(), 42u64)].into_iter().collect(); + let res = to_vec(&v); + assert_eq!(res.unwrap_err().to_string(), ERROR_ZST_FORBIDDEN); +} + +#[derive(BorshDeserialize, BorshSerialize, PartialEq, Debug)] +struct B(u32); +#[test] +fn test_deserialize_non_zst() { + let v = [1, 0, 0, 0, 64, 0, 0, 0]; + let res = Vec::::try_from_slice(&v); + assert!(res.is_ok()); +} + +#[test] +fn test_serialize_non_zst() { + let v = vec![B(1)]; + let res = to_vec(&v); + assert!(res.is_ok()); +} diff --git a/vendor/bstr-0.2.17/.cargo-checksum.json b/vendor/bstr-0.2.17/.cargo-checksum.json new file mode 100644 index 0000000000000..a38a78f37eb0d --- /dev/null +++ b/vendor/bstr-0.2.17/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"COPYING":"13361f93b3db60ddb43f8fdc97ba469461019bbf7589f6bde833eb3d995d2497","Cargo.lock":"0098420b2c41749835875ecc77cf074781b2448945fe5e7518fdb928ae560b3d","Cargo.toml":"c6c4148fcfd276773164c1966a5d5c9bd45818f00ffc1b7173e61703461e41b6","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6b7374c39a57e57fc2c38eb529c4c88340152b10f51dd5ae2d819dfa67f61715","README.md":"2edf49d9a95fae4fcf1ec37c25c56e1493928daafeb83dc90e486c925d5ae74d","examples/graphemes-std.rs":"100264f623ff973be76831fb1d4519e6f371b21972d6577bb49bf7bbff4d0d5e","examples/graphemes.rs":"401c5fac813f78e4029ece9c98bccb3128637c507d8667b73e069bfbc9d7f2f4","examples/lines-std.rs":"094a48bfd483ec01f80f9c937ddfe6f0bdbf09f960ba822215ec8ed9862624df","examples/lines.rs":"65ae4edbdb0ccff8ff40cdc70b4e7a70824f5028daff2e1b2a3247f884589db8","examples/uppercase-std.rs":"33aed88e38483aa303625757304a974594476a3a659d8bdd4877aceb90ff8be3","examples/uppercase.rs":"2cdf7f173cb6a5d4c16a967e3f733bc40331f5167da519c5194ceee187ff814f","examples/words-std.rs":"ffde2fccd361890fab0e0b051915a749d5d51e95b9be700b76fada231d002f00","examples/words.rs":"aa805faa5012714428ef895596947c333417c2b16a7e0155d4a128be7428fc17","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","scripts/generate-unicode-data":"75d68617b5acf564cc681ddfbf77a6097eaa9a9f8f54af4e16905dda3dc6df77","scripts/regex/grapheme.sh":"d796bca73278f6ab04d65f285b2dc72efcad76874f98f4bfa22bf38f2eaeece7","scripts/regex/sentence.sh":"7892e07ac9e450967bd79279558cbef2f0fc0b0aefab24217910937ed6330f06","scripts/regex/word.sh":"b3f53e2331e9e50a1a7232b7d278aaecace6a42ef6c16dd0b8d0ec59fd2aaf4f","src/ascii.rs":"19bdd85083467382c5bcc31345aa7ce731cc0dbfad3db21cbf09ee86a4ef8327","src/bstr.rs":"10e8af4cf7f39226da45bfb4836bd9da3694edf963d20f34b19574efc9bdbd58","src/bstring.rs":"00dabd0b94dca1b21324a0d6c7caf5a18b0231d4126a617d272c0c12ea30995d","src/byteset/mod.rs":"2ac3f6685fa396fc0fb59ea279d36c59556afea0a7df4d8f0c5855312b24b331","src/byteset/scalar.rs":"81aed13fbbe24274b22794a14767026e3f31d63d6e8f0eaf48f88b3c4d6ee94e","src/ext_slice.rs":"f2e1e4c9b67df88751005bdc186187a49341920ef013196450b125cfddf34b38","src/ext_vec.rs":"02ae97c421f8dabfb5402652ec0de99d8560fb949c105f856253cdb85b1a9187","src/impls.rs":"0da8b528009878b48a5925a0fcdc7b7fe639a66161ac34a8af20bd75d73981d7","src/io.rs":"b9e6718605b24057af0016d969c52b82b0ce19e740b167b600b6a0f0cfa6961b","src/lib.rs":"eace27e8708288fc71450b4ab0e553443412fe6102b2730f0eb53b211f4ffff3","src/tests.rs":"9e50757473b50273ae3a8aeaed924282ffab82ded7134c15745f3b798b16e574","src/unicode/data/GraphemeBreakTest.txt":"95bd55cf803b93eb0b4990cf0e1d70ede263b36412d9c6921fd6f15cef058961","src/unicode/data/LICENSE-UNICODE":"8b9babb256418ec15761d635a49f973424939affba7a0a88de2fc2690e454a23","src/unicode/data/SentenceBreakTest.txt":"7d6c909af97d0ab545a132d412f6e4e65c7eb5158514a7feb9bf00bcd05875f9","src/unicode/data/WordBreakTest.txt":"3e3320bbbe775de7f1a0b9a30021eb949116a9b05cb461c90596c5ecf1743831","src/unicode/fsm/grapheme_break_fwd.bigendian.dfa":"6daed7530f9e0798b51fbd758ea4626ce53d889bdc7d64dd7d2124b3d0c065db","src/unicode/fsm/grapheme_break_fwd.littleendian.dfa":"f24e7d3fd1fe702811e315611fbe5be24746f7f30e5fd30cf578ade55ae2ac15","src/unicode/fsm/grapheme_break_fwd.rs":"68239e41a0702c2e4a4f207b14f0c7b55f26309d02c6e4402bf723d5e100975b","src/unicode/fsm/grapheme_break_rev.bigendian.dfa":"58544096b5209e438d65000d481ad8bdab4c1ee21f1af70247fafd2a0638b712","src/unicode/fsm/grapheme_break_rev.littleendian.dfa":"9895471633472d48ad3280f436c63b5ae08989c1816cd511428c0dc01d32e7f2","src/unicode/fsm/grapheme_break_rev.rs":"5852dd8064828c050a99a95b3ca958e489de752dbcb60aec9f337a9f631ff7b0","src/unicode/fsm/mod.rs":"50b8baa692e83f909a0fe62eced9666b712a68b6c7bf42976c8cc37e49dd9b64","src/unicode/fsm/regional_indicator_rev.bigendian.dfa":"db9db4c86bced5f4aaf68d5e475e13e5d4976c237deec13c192111a399aa5858","src/unicode/fsm/regional_indicator_rev.littleendian.dfa":"0905f70acddd423c1b53bfbeb73299009f724400029d7f9a987d63c32d36e36c","src/unicode/fsm/regional_indicator_rev.rs":"6241065da1a2dcea4416a4915a3e4e8c40b700ebc55f6f983cee2cd213d1af25","src/unicode/fsm/sentence_break_fwd.bigendian.dfa":"3c1966fb1edd143264dc98e59b5c907b383dc20a957ae3e3982c38fbfac7d5a2","src/unicode/fsm/sentence_break_fwd.littleendian.dfa":"855249a618cb57d3403a449883a925e6d6cd4dfc5d316f473038f258ea890b3f","src/unicode/fsm/sentence_break_fwd.rs":"b0bf5dfb9d29d1529034242c4f2a7954b3be2410598b9ace7f170d24703b313f","src/unicode/fsm/simple_word_fwd.bigendian.dfa":"8092da9a59d903bdee43fd73a95f32bb61e611e46528c676aeb42b3810bce085","src/unicode/fsm/simple_word_fwd.littleendian.dfa":"c79d90294aa00f4915295d13d13eb3743cb202066088c9407a6a3690f4b172d4","src/unicode/fsm/simple_word_fwd.rs":"7c2c1d37390c970e9d8b33d3be45cc4fff92d719324737e8a1abfb715942dd81","src/unicode/fsm/whitespace_anchored_fwd.bigendian.dfa":"593c8ad059ab0bee60a2ea25f4c1fc89c105cb19a9bda3fa98d1464b8e87cfc0","src/unicode/fsm/whitespace_anchored_fwd.littleendian.dfa":"a04ed70d5dbd969c0af0e12bec5033ca910161c486f741dd0a792d2e5b0cc6f6","src/unicode/fsm/whitespace_anchored_fwd.rs":"09d402fad14ffc81d88318808a10c763f356edd42ed6ec1f80df09e5f02700a3","src/unicode/fsm/whitespace_anchored_rev.bigendian.dfa":"9ab09359ce73058d22e5bfa857e040831d49f4a53dd25da804136e9db9e7f5fb","src/unicode/fsm/whitespace_anchored_rev.littleendian.dfa":"cb5804786bd98bfe0726f3f7733d72bc1d69130c8a8b026465c03c78f8c8ac79","src/unicode/fsm/whitespace_anchored_rev.rs":"680cc4e81c94aab5f017bb43efff03221cc3ebcae7bd1fd9284e0c4fc86ebd9e","src/unicode/fsm/word_break_fwd.bigendian.dfa":"5ec979ebe17f0d0b85805625c5b9206476a518d89c707c869dcbe24f422367c8","src/unicode/fsm/word_break_fwd.littleendian.dfa":"28e1b3e13a4ff4b0c7660b611f9e5dd0a087bb3b9a9b63b27cd2eb69a8412a31","src/unicode/fsm/word_break_fwd.rs":"a2581e5e298cd6b748071bc3b637a2a9d3b503c027c3c47b25f47dfd05e8b6db","src/unicode/grapheme.rs":"e0e65949fda3d41dfbf34a03dda3f403c3e8e5e95112b982a358392a37c51b50","src/unicode/mod.rs":"93340dcadca5a4f01a0a993d40e283e98015065098a7b1d076ab966ee591736d","src/unicode/sentence.rs":"ab09a096ab8474bbafb832a8e9905ebb1491a08d11848d9d73587b8361bf6297","src/unicode/whitespace.rs":"0188d053d1aa283d63d1583497d62502ff8c6c7af9f99d42cc9ac800b1438a9c","src/unicode/word.rs":"ce5791b0dc34a2033b99d48bbceb335806cee684913327578f35bac9bf918f06","src/utf8.rs":"6c94ac997924d54cf8f1866e6e62723c780d63b3302adc5285a100c7968b94a9"},"package":"ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"} \ No newline at end of file diff --git a/vendor/bstr-0.2.17/COPYING b/vendor/bstr-0.2.17/COPYING new file mode 100644 index 0000000000000..d5a7d7ec8942e --- /dev/null +++ b/vendor/bstr-0.2.17/COPYING @@ -0,0 +1,8 @@ +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. diff --git a/vendor/bstr-0.2.17/Cargo.lock b/vendor/bstr-0.2.17/Cargo.lock new file mode 100644 index 0000000000000..b99837c6785a1 --- /dev/null +++ b/vendor/bstr-0.2.17/Cargo.lock @@ -0,0 +1,136 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bstr" +version = "0.2.17" +dependencies = [ + "lazy_static", + "memchr", + "quickcheck", + "regex-automata", + "serde", + "ucd-parse", + "unicode-segmentation", +] + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "quickcheck" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +dependencies = [ + "rand", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "regex" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8963b85b8ce3074fecffde43b4b0dded83ce2f367dc8d363afc56679f3ee820b" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" +dependencies = [ + "byteorder", +] + +[[package]] +name = "regex-syntax" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cab7a364d15cde1e505267766a2d3c4e22a843e1a601f0fa7564c0f82ced11c" + +[[package]] +name = "serde" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" + +[[package]] +name = "ucd-parse" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5269f8d35df6b8b60758343a6d742ecf09e4bca13faee32af5503aebd1e11b7c" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" diff --git a/vendor/bstr-0.2.17/Cargo.toml b/vendor/bstr-0.2.17/Cargo.toml new file mode 100644 index 0000000000000..0f206ba5a81f7 --- /dev/null +++ b/vendor/bstr-0.2.17/Cargo.toml @@ -0,0 +1,63 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "bstr" +version = "0.2.17" +authors = ["Andrew Gallant "] +exclude = ["/.github"] +description = "A string type that is not required to be valid UTF-8." +homepage = "https://github.com/BurntSushi/bstr" +documentation = "https://docs.rs/bstr" +readme = "README.md" +keywords = ["string", "str", "byte", "bytes", "text"] +categories = ["text-processing", "encoding"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/BurntSushi/bstr" +[profile.release] +debug = true + +[lib] +bench = false +[dependencies.lazy_static] +version = "1.2.0" +optional = true + +[dependencies.memchr] +version = "2.4.0" +default-features = false + +[dependencies.regex-automata] +version = "0.1.5" +optional = true +default-features = false + +[dependencies.serde] +version = "1.0.85" +optional = true +default-features = false +[dev-dependencies.quickcheck] +version = "1" +default-features = false + +[dev-dependencies.ucd-parse] +version = "0.1.3" + +[dev-dependencies.unicode-segmentation] +version = "1.2.1" + +[features] +default = ["std", "unicode"] +serde1 = ["std", "serde1-nostd", "serde/std"] +serde1-nostd = ["serde"] +std = ["memchr/std"] +unicode = ["lazy_static", "regex-automata"] diff --git a/vendor/bstr-0.2.17/LICENSE-APACHE b/vendor/bstr-0.2.17/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/vendor/bstr-0.2.17/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/bstr-0.2.17/LICENSE-MIT b/vendor/bstr-0.2.17/LICENSE-MIT new file mode 100644 index 0000000000000..17d687378cc54 --- /dev/null +++ b/vendor/bstr-0.2.17/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018-2019 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/bstr-0.2.17/README.md b/vendor/bstr-0.2.17/README.md new file mode 100644 index 0000000000000..13bf0fc71eb2a --- /dev/null +++ b/vendor/bstr-0.2.17/README.md @@ -0,0 +1,251 @@ +bstr +==== +This crate provides extension traits for `&[u8]` and `Vec` that enable +their use as byte strings, where byte strings are _conventionally_ UTF-8. This +differs from the standard library's `String` and `str` types in that they are +not required to be valid UTF-8, but may be fully or partially valid UTF-8. + +[![Build status](https://github.com/BurntSushi/bstr/workflows/ci/badge.svg)](https://github.com/BurntSushi/bstr/actions) +[![](https://meritbadge.herokuapp.com/bstr)](https://crates.io/crates/bstr) + + +### Documentation + +https://docs.rs/bstr + + +### When should I use byte strings? + +See this part of the documentation for more details: +https://docs.rs/bstr/0.2.*/bstr/#when-should-i-use-byte-strings. + +The short story is that byte strings are useful when it is inconvenient or +incorrect to require valid UTF-8. + + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +bstr = "0.2" +``` + + +### Examples + +The following two examples exhibit both the API features of byte strings and +the I/O convenience functions provided for reading line-by-line quickly. + +This first example simply shows how to efficiently iterate over lines in +stdin, and print out lines containing a particular substring: + +```rust +use std::error::Error; +use std::io::{self, Write}; + +use bstr::{ByteSlice, io::BufReadExt}; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdout = io::BufWriter::new(io::stdout()); + + stdin.lock().for_byte_line_with_terminator(|line| { + if line.contains_str("Dimension") { + stdout.write_all(line)?; + } + Ok(true) + })?; + Ok(()) +} +``` + +This example shows how to count all of the words (Unicode-aware) in stdin, +line-by-line: + +```rust +use std::error::Error; +use std::io; + +use bstr::{ByteSlice, io::BufReadExt}; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut words = 0; + stdin.lock().for_byte_line_with_terminator(|line| { + words += line.words().count(); + Ok(true) + })?; + println!("{}", words); + Ok(()) +} +``` + +This example shows how to convert a stream on stdin to uppercase without +performing UTF-8 validation _and_ amortizing allocation. On standard ASCII +text, this is quite a bit faster than what you can (easily) do with standard +library APIs. (N.B. Any invalid UTF-8 bytes are passed through unchanged.) + +```rust +use std::error::Error; +use std::io::{self, Write}; + +use bstr::{ByteSlice, io::BufReadExt}; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdout = io::BufWriter::new(io::stdout()); + + let mut upper = vec![]; + stdin.lock().for_byte_line_with_terminator(|line| { + upper.clear(); + line.to_uppercase_into(&mut upper); + stdout.write_all(&upper)?; + Ok(true) + })?; + Ok(()) +} +``` + +This example shows how to extract the first 10 visual characters (as grapheme +clusters) from each line, where invalid UTF-8 sequences are generally treated +as a single character and are passed through correctly: + +```rust +use std::error::Error; +use std::io::{self, Write}; + +use bstr::{ByteSlice, io::BufReadExt}; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdout = io::BufWriter::new(io::stdout()); + + stdin.lock().for_byte_line_with_terminator(|line| { + let end = line + .grapheme_indices() + .map(|(_, end, _)| end) + .take(10) + .last() + .unwrap_or(line.len()); + stdout.write_all(line[..end].trim_end())?; + stdout.write_all(b"\n")?; + Ok(true) + })?; + Ok(()) +} +``` + + +### Cargo features + +This crates comes with a few features that control standard library, serde +and Unicode support. + +* `std` - **Enabled** by default. This provides APIs that require the standard + library, such as `Vec`. +* `unicode` - **Enabled** by default. This provides APIs that require sizable + Unicode data compiled into the binary. This includes, but is not limited to, + grapheme/word/sentence segmenters. When this is disabled, basic support such + as UTF-8 decoding is still included. +* `serde1` - **Disabled** by default. Enables implementations of serde traits + for the `BStr` and `BString` types. +* `serde1-nostd` - **Disabled** by default. Enables implementations of serde + traits for the `BStr` type only, intended for use without the standard + library. Generally, you either want `serde1` or `serde1-nostd`, not both. + + +### Minimum Rust version policy + +This crate's minimum supported `rustc` version (MSRV) is `1.41.1`. + +In general, this crate will be conservative with respect to the minimum +supported version of Rust. MSRV may be bumped in minor version releases. + + +### Future work + +Since this is meant to be a core crate, getting a `1.0` release is a priority. +My hope is to move to `1.0` within the next year and commit to its API so that +`bstr` can be used as a public dependency. + +A large part of the API surface area was taken from the standard library, so +from an API design perspective, a good portion of this crate should be on solid +ground already. The main differences from the standard library are in how the +various substring search routines work. The standard library provides generic +infrastructure for supporting different types of searches with a single method, +where as this library prefers to define new methods for each type of search and +drop the generic infrastructure. + +Some _probable_ future considerations for APIs include, but are not limited to: + +* A convenience layer on top of the `aho-corasick` crate. +* Unicode normalization. +* More sophisticated support for dealing with Unicode case, perhaps by + combining the use cases supported by [`caseless`](https://docs.rs/caseless) + and [`unicase`](https://docs.rs/unicase). +* Add facilities for dealing with OS strings and file paths, probably via + simple conversion routines. + +Here are some examples that are _probably_ out of scope for this crate: + +* Regular expressions. +* Unicode collation. + +The exact scope isn't quite clear, but I expect we can iterate on it. + +In general, as stated below, this crate brings lots of related APIs together +into a single crate while simultaneously attempting to keep the total number of +dependencies low. Indeed, every dependency of `bstr`, except for `memchr`, is +optional. + + +### High level motivation + +Strictly speaking, the `bstr` crate provides very little that can't already be +achieved with the standard library `Vec`/`&[u8]` APIs and the ecosystem of +library crates. For example: + +* The standard library's + [`Utf8Error`](https://doc.rust-lang.org/std/str/struct.Utf8Error.html) + can be used for incremental lossy decoding of `&[u8]`. +* The + [`unicode-segmentation`](https://unicode-rs.github.io/unicode-segmentation/unicode_segmentation/index.html) + crate can be used for iterating over graphemes (or words), but is only + implemented for `&str` types. One could use `Utf8Error` above to implement + grapheme iteration with the same semantics as what `bstr` provides (automatic + Unicode replacement codepoint substitution). +* The [`twoway`](https://docs.rs/twoway) crate can be used for + fast substring searching on `&[u8]`. + +So why create `bstr`? Part of the point of the `bstr` crate is to provide a +uniform API of coupled components instead of relying on users to piece together +loosely coupled components from the crate ecosystem. For example, if you wanted +to perform a search and replace in a `Vec`, then writing the code to do +that with the `twoway` crate is not that difficult, but it's still additional +glue code you have to write. This work adds up depending on what you're doing. +Consider, for example, trimming and splitting, along with their different +variants. + +In other words, `bstr` is partially a way of pushing back against the +micro-crate ecosystem that appears to be evolving. Namely, it is a goal of +`bstr` to keep its dependency list lightweight. For example, `serde` is an +optional dependency because there is no feasible alternative. In service of +this philosophy, currently, the only required dependency of `bstr` is `memchr`. + + +### License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + https://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + https://opensource.org/licenses/MIT) + +at your option. + +The data in `src/unicode/data/` is licensed under the Unicode License Agreement +([LICENSE-UNICODE](https://www.unicode.org/copyright.html#License)), although +this data is only used in tests. diff --git a/vendor/bstr-0.2.17/examples/graphemes-std.rs b/vendor/bstr-0.2.17/examples/graphemes-std.rs new file mode 100644 index 0000000000000..647739d4a0643 --- /dev/null +++ b/vendor/bstr-0.2.17/examples/graphemes-std.rs @@ -0,0 +1,25 @@ +use std::error::Error; +use std::io::{self, BufRead, Write}; + +use unicode_segmentation::UnicodeSegmentation; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdin = stdin.lock(); + let mut stdout = io::BufWriter::new(io::stdout()); + + let mut line = String::new(); + while stdin.read_line(&mut line)? > 0 { + let end = line + .grapheme_indices(true) + .map(|(start, g)| start + g.len()) + .take(10) + .last() + .unwrap_or(line.len()); + stdout.write_all(line[..end].trim_end().as_bytes())?; + stdout.write_all(b"\n")?; + + line.clear(); + } + Ok(()) +} diff --git a/vendor/bstr-0.2.17/examples/graphemes.rs b/vendor/bstr-0.2.17/examples/graphemes.rs new file mode 100644 index 0000000000000..6adc7019d16a4 --- /dev/null +++ b/vendor/bstr-0.2.17/examples/graphemes.rs @@ -0,0 +1,22 @@ +use std::error::Error; +use std::io::{self, Write}; + +use bstr::{io::BufReadExt, ByteSlice}; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdout = io::BufWriter::new(io::stdout()); + + stdin.lock().for_byte_line_with_terminator(|line| { + let end = line + .grapheme_indices() + .map(|(_, end, _)| end) + .take(10) + .last() + .unwrap_or(line.len()); + stdout.write_all(line[..end].trim_end())?; + stdout.write_all(b"\n")?; + Ok(true) + })?; + Ok(()) +} diff --git a/vendor/bstr-0.2.17/examples/lines-std.rs b/vendor/bstr-0.2.17/examples/lines-std.rs new file mode 100644 index 0000000000000..69fc6a586c717 --- /dev/null +++ b/vendor/bstr-0.2.17/examples/lines-std.rs @@ -0,0 +1,17 @@ +use std::error::Error; +use std::io::{self, BufRead, Write}; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdin = stdin.lock(); + let mut stdout = io::BufWriter::new(io::stdout()); + + let mut line = String::new(); + while stdin.read_line(&mut line)? > 0 { + if line.contains("Dimension") { + stdout.write_all(line.as_bytes())?; + } + line.clear(); + } + Ok(()) +} diff --git a/vendor/bstr-0.2.17/examples/lines.rs b/vendor/bstr-0.2.17/examples/lines.rs new file mode 100644 index 0000000000000..c392a2229cf81 --- /dev/null +++ b/vendor/bstr-0.2.17/examples/lines.rs @@ -0,0 +1,17 @@ +use std::error::Error; +use std::io::{self, Write}; + +use bstr::{io::BufReadExt, ByteSlice}; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdout = io::BufWriter::new(io::stdout()); + + stdin.lock().for_byte_line_with_terminator(|line| { + if line.contains_str("Dimension") { + stdout.write_all(line)?; + } + Ok(true) + })?; + Ok(()) +} diff --git a/vendor/bstr-0.2.17/examples/uppercase-std.rs b/vendor/bstr-0.2.17/examples/uppercase-std.rs new file mode 100644 index 0000000000000..672bd717124d4 --- /dev/null +++ b/vendor/bstr-0.2.17/examples/uppercase-std.rs @@ -0,0 +1,15 @@ +use std::error::Error; +use std::io::{self, BufRead, Write}; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdin = stdin.lock(); + let mut stdout = io::BufWriter::new(io::stdout()); + + let mut line = String::new(); + while stdin.read_line(&mut line)? > 0 { + stdout.write_all(line.to_uppercase().as_bytes())?; + line.clear(); + } + Ok(()) +} diff --git a/vendor/bstr-0.2.17/examples/uppercase.rs b/vendor/bstr-0.2.17/examples/uppercase.rs new file mode 100644 index 0000000000000..1eb798a34c905 --- /dev/null +++ b/vendor/bstr-0.2.17/examples/uppercase.rs @@ -0,0 +1,18 @@ +use std::error::Error; +use std::io::{self, Write}; + +use bstr::{io::BufReadExt, ByteSlice}; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdout = io::BufWriter::new(io::stdout()); + + let mut upper = vec![]; + stdin.lock().for_byte_line_with_terminator(|line| { + upper.clear(); + line.to_uppercase_into(&mut upper); + stdout.write_all(&upper)?; + Ok(true) + })?; + Ok(()) +} diff --git a/vendor/bstr-0.2.17/examples/words-std.rs b/vendor/bstr-0.2.17/examples/words-std.rs new file mode 100644 index 0000000000000..aeeeb26ff36f8 --- /dev/null +++ b/vendor/bstr-0.2.17/examples/words-std.rs @@ -0,0 +1,18 @@ +use std::error::Error; +use std::io::{self, BufRead}; + +use unicode_segmentation::UnicodeSegmentation; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdin = stdin.lock(); + + let mut words = 0; + let mut line = String::new(); + while stdin.read_line(&mut line)? > 0 { + words += line.unicode_words().count(); + line.clear(); + } + println!("{}", words); + Ok(()) +} diff --git a/vendor/bstr-0.2.17/examples/words.rs b/vendor/bstr-0.2.17/examples/words.rs new file mode 100644 index 0000000000000..db305da0dbd4e --- /dev/null +++ b/vendor/bstr-0.2.17/examples/words.rs @@ -0,0 +1,15 @@ +use std::error::Error; +use std::io; + +use bstr::{io::BufReadExt, ByteSlice}; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut words = 0; + stdin.lock().for_byte_line_with_terminator(|line| { + words += line.words().count(); + Ok(true) + })?; + println!("{}", words); + Ok(()) +} diff --git a/vendor/bstr-0.2.17/rustfmt.toml b/vendor/bstr-0.2.17/rustfmt.toml new file mode 100644 index 0000000000000..aa37a218b97e5 --- /dev/null +++ b/vendor/bstr-0.2.17/rustfmt.toml @@ -0,0 +1,2 @@ +max_width = 79 +use_small_heuristics = "max" diff --git a/vendor/bstr-0.2.17/scripts/generate-unicode-data b/vendor/bstr-0.2.17/scripts/generate-unicode-data new file mode 100755 index 0000000000000..b8341c5a64f25 --- /dev/null +++ b/vendor/bstr-0.2.17/scripts/generate-unicode-data @@ -0,0 +1,149 @@ +#!/bin/sh + +set -e +D="$(dirname "$0")" + +# Convenience function for checking that a command exists. +requires() { + cmd="$1" + if ! command -v "$cmd" > /dev/null 2>&1; then + echo "DEPENDENCY MISSING: $cmd must be installed" >&2 + exit 1 + fi +} + +# Test if an array ($2) contains a particular element ($1). +array_exists() { + needle="$1" + shift + + for el in "$@"; do + if [ "$el" = "$needle" ]; then + return 0 + fi + done + return 1 +} + +graphemes() { + regex="$(sh "$D/regex/grapheme.sh")" + + echo "generating forward grapheme DFA" + ucd-generate dfa \ + --name GRAPHEME_BREAK_FWD \ + --sparse --minimize --anchored --state-size 2 \ + src/unicode/fsm/ \ + "$regex" + + echo "generating reverse grapheme DFA" + ucd-generate dfa \ + --name GRAPHEME_BREAK_REV \ + --reverse --longest \ + --sparse --minimize --anchored --state-size 2 \ + src/unicode/fsm/ \ + "$regex" +} + +words() { + regex="$(sh "$D/regex/word.sh")" + + echo "generating forward word DFA (this can take a while)" + ucd-generate dfa \ + --name WORD_BREAK_FWD \ + --sparse --minimize --anchored --state-size 4 \ + src/unicode/fsm/ \ + "$regex" +} + +sentences() { + regex="$(sh "$D/regex/sentence.sh")" + + echo "generating forward sentence DFA (this can take a while)" + ucd-generate dfa \ + --name SENTENCE_BREAK_FWD \ + --minimize \ + --sparse --anchored --state-size 4 \ + src/unicode/fsm/ \ + "$regex" +} + +regional_indicator() { + # For finding all occurrences of region indicators. This is used to handle + # regional indicators as a special case for the reverse grapheme iterator + # and the reverse word iterator. + echo "generating regional indicator DFA" + ucd-generate dfa \ + --name REGIONAL_INDICATOR_REV \ + --reverse \ + --classes --minimize --anchored --premultiply --state-size 1 \ + src/unicode/fsm/ \ + "\p{gcb=Regional_Indicator}" +} + +simple_word() { + echo "generating forward simple word DFA" + ucd-generate dfa \ + --name SIMPLE_WORD_FWD \ + --sparse --minimize --state-size 2 \ + src/unicode/fsm/ \ + "\w" +} + +whitespace() { + echo "generating forward whitespace DFA" + ucd-generate dfa \ + --name WHITESPACE_ANCHORED_FWD \ + --anchored --classes --premultiply --minimize --state-size 1 \ + src/unicode/fsm/ \ + "\s+" + + echo "generating reverse whitespace DFA" + ucd-generate dfa \ + --name WHITESPACE_ANCHORED_REV \ + --reverse \ + --anchored --classes --premultiply --minimize --state-size 2 \ + src/unicode/fsm/ \ + "\s+" +} + +main() { + if array_exists "-h" "$@" || array_exists "--help" "$@"; then + echo "Usage: $(basename "$0") [--list-commands] [] ..." >&2 + exit + fi + + commands=" + graphemes + sentences + words + regional-indicator + simple-word + whitespace + " + if array_exists "--list-commands" "$@"; then + for cmd in $commands; do + echo "$cmd" + done + exit + fi + + # ucd-generate is used to compile regexes into DFAs. + requires ucd-generate + + mkdir -p src/unicode/fsm/ + + cmds=$* + if [ $# -eq 0 ] || array_exists "all" "$@"; then + cmds=$commands + fi + for cmd in $cmds; do + if array_exists "$cmd" $commands; then + fun="$(echo "$cmd" | sed 's/-/_/g')" + eval "$fun" + else + echo "unrecognized command: $cmd" >&2 + fi + done +} + +main "$@" diff --git a/vendor/bstr-0.2.17/scripts/regex/grapheme.sh b/vendor/bstr-0.2.17/scripts/regex/grapheme.sh new file mode 100644 index 0000000000000..0b2b54daa2585 --- /dev/null +++ b/vendor/bstr-0.2.17/scripts/regex/grapheme.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +# vim: indentexpr= nosmartindent autoindent +# vim: tabstop=2 shiftwidth=2 softtabstop=2 + +# This regex was manually written, derived from the rules in UAX #29. +# Particularly, from Table 1c, which lays out a regex for grapheme clusters. + +CR="\p{gcb=CR}" +LF="\p{gcb=LF}" +Control="\p{gcb=Control}" +Prepend="\p{gcb=Prepend}" +L="\p{gcb=L}" +V="\p{gcb=V}" +LV="\p{gcb=LV}" +LVT="\p{gcb=LVT}" +T="\p{gcb=T}" +RI="\p{gcb=RI}" +Extend="\p{gcb=Extend}" +ZWJ="\p{gcb=ZWJ}" +SpacingMark="\p{gcb=SpacingMark}" + +Any="\p{any}" +ExtendPict="\p{Extended_Pictographic}" + +echo "(?x) +$CR $LF +| +$Control +| +$Prepend* +( + ( + ($L* ($V+ | $LV $V* | $LVT) $T*) + | + $L+ + | + $T+ + ) + | + $RI $RI + | + $ExtendPict ($Extend* $ZWJ $ExtendPict)* + | + [^$Control $CR $LF] +) +[$Extend $ZWJ $SpacingMark]* +| +$Any +" diff --git a/vendor/bstr-0.2.17/scripts/regex/sentence.sh b/vendor/bstr-0.2.17/scripts/regex/sentence.sh new file mode 100644 index 0000000000000..689d1849fd9c1 --- /dev/null +++ b/vendor/bstr-0.2.17/scripts/regex/sentence.sh @@ -0,0 +1,176 @@ +#!/bin/sh + +# vim: indentexpr= nosmartindent autoindent +# vim: tabstop=2 shiftwidth=2 softtabstop=2 + +# This is a regex that I reverse engineered from the sentence boundary chain +# rules in UAX #29. Unlike the grapheme regex, which is essentially provided +# for us in UAX #29, no such sentence regex exists. +# +# I looked into how ICU achieves this, since UAX #29 hints that producing +# finite state machines for grapheme/sentence/word/line breaking is possible, +# but only easy to do for graphemes. ICU does this by implementing their own +# DSL for describing the break algorithms in terms of the chaining rules +# directly. You can see an example for sentences in +# icu4c/source/data/brkitr/rules/sent.txt. ICU then builds a finite state +# machine from those rules in a mostly standard way, but implements the +# "chaining" aspect of the rules by connecting overlapping end and start +# states. For example, given SB7: +# +# (Upper | Lower) ATerm x Upper +# +# Then the naive way to convert this into a regex would be something like +# +# [\p{sb=Upper}\p{sb=Lower}]\p{sb=ATerm}\p{sb=Upper} +# +# Unfortunately, this is incorrect. Why? Well, consider an example like so: +# +# U.S.A. +# +# A correct implementation of the sentence breaking algorithm should not insert +# any breaks here, exactly in accordance with repeatedly applying rule SB7 as +# given above. Our regex fails to do this because it will first match `U.S` +# without breaking them---which is correct---but will then start looking for +# its next rule beginning with a full stop (in ATerm) and followed by an +# uppercase letter (A). This will wind up triggering rule SB11 (without +# matching `A`), which inserts a break. +# +# The reason why this happens is because our initial application of rule SB7 +# "consumes" the next uppercase letter (S), which we want to reuse as a prefix +# in the next rule application. A natural way to express this would be with +# look-around, although it's not clear that works in every case since you +# ultimately might want to consume that ending uppercase letter. In any case, +# we can't use look-around in our truly regular regexes, so we must fix this. +# The approach we take is to explicitly repeat rules when a suffix of a rule +# is a prefix of another rule. In the case of SB7, the end of the rule, an +# uppercase letter, also happens to match the beginning of the rule. This can +# in turn be repeated indefinitely. Thus, our actual translation to a regex is: +# +# [\p{sb=Upper}\p{sb=Lower}]\p{sb=ATerm}\p{sb=Upper}(\p{sb=ATerm}\p{sb=Upper}* +# +# It turns out that this is exactly what ICU does, but in their case, they do +# it automatically. In our case, we connect the chaining rules manually. It's +# tedious. With that said, we do no implement Unicode line breaking with this +# approach, which is a far scarier beast. In that case, it would probably be +# worth writing the code to do what ICU does. +# +# In the case of sentence breaks, there aren't *too* many overlaps of this +# nature. We list them out exhaustively to make this clear, because it's +# essentially impossible to easily observe this in the regex. (It took me a +# full day to figure all of this out.) Rules marked with N/A mean that they +# specify a break, and this strategy only really applies to stringing together +# non-breaks. +# +# SB1 - N/A +# SB2 - N/A +# SB3 - None +# SB4 - N/A +# SB5 - None +# SB6 - None +# SB7 - End overlaps with beginning of SB7 +# SB8 - End overlaps with beginning of SB7 +# SB8a - End overlaps with beginning of SB6, SB8, SB8a, SB9, SB10, SB11 +# SB9 - None +# SB10 - None +# SB11 - None +# SB998 - N/A +# +# SB8a is in particular quite tricky to get right without look-ahead, since it +# allows ping-ponging between match rules SB8a and SB9-11, where SB9-11 +# otherwise indicate that a break has been found. In the regex below, we tackle +# this by only permitting part of SB8a to match inside our core non-breaking +# repetition. In particular, we only allow the parts of SB8a to match that +# permit the non-breaking components to continue. If a part of SB8a matches +# that guarantees a pop out to SB9-11, (like `STerm STerm`), then we let it +# happen. This still isn't correct because an SContinue might be seen which +# would allow moving back into SB998 and thus the non-breaking repetition, so +# we handle that case as well. +# +# Finally, the last complication here is the sprinkling of $Ex* everywhere. +# This essentially corresponds to the implementation of SB5 by following +# UAX #29's recommendation in S6.2. Essentially, we use it avoid ever breaking +# in the middle of a grapheme cluster. + +CR="\p{sb=CR}" +LF="\p{sb=LF}" +Sep="\p{sb=Sep}" +Close="\p{sb=Close}" +Sp="\p{sb=Sp}" +STerm="\p{sb=STerm}" +ATerm="\p{sb=ATerm}" +SContinue="\p{sb=SContinue}" +Numeric="\p{sb=Numeric}" +Upper="\p{sb=Upper}" +Lower="\p{sb=Lower}" +OLetter="\p{sb=OLetter}" + +Ex="[\p{sb=Extend}\p{sb=Format}]" +ParaSep="[$Sep $CR $LF]" +SATerm="[$STerm $ATerm]" + +LetterSepTerm="[$OLetter $Upper $Lower $ParaSep $SATerm]" + +echo "(?x) +( + # SB6 + $ATerm $Ex* + $Numeric + | + # SB7 + [$Upper $Lower] $Ex* $ATerm $Ex* + $Upper $Ex* + # overlap with SB7 + ($ATerm $Ex* $Upper $Ex*)* + | + # SB8 + $ATerm $Ex* $Close* $Ex* $Sp* $Ex* + ([^$LetterSepTerm] $Ex*)* $Lower $Ex* + # overlap with SB7 + ($ATerm $Ex* $Upper $Ex*)* + | + # SB8a + $SATerm $Ex* $Close* $Ex* $Sp* $Ex* + ( + $SContinue + | + $ATerm $Ex* + # Permit repetition of SB8a + (($Close $Ex*)* ($Sp $Ex*)* $SATerm)* + # In order to continue non-breaking matching, we now must observe + # a match with a rule that keeps us in SB6-8a. Otherwise, we've entered + # one of SB9-11 and know that a break must follow. + ( + # overlap with SB6 + $Numeric + | + # overlap with SB8 + ($Close $Ex*)* ($Sp $Ex*)* + ([^$LetterSepTerm] $Ex*)* $Lower $Ex* + # overlap with SB7 + ($ATerm $Ex* $Upper $Ex*)* + | + # overlap with SB8a + ($Close $Ex*)* ($Sp $Ex*)* $SContinue + ) + | + $STerm $Ex* + # Permit repetition of SB8a + (($Close $Ex*)* ($Sp $Ex*)* $SATerm)* + # As with ATerm above, in order to continue non-breaking matching, we + # must now observe a match with a rule that keeps us out of SB9-11. + # For STerm, the only such possibility is to see an SContinue. Anything + # else will result in a break. + ($Close $Ex*)* ($Sp $Ex*)* $SContinue + ) + | + # SB998 + # The logic behind this catch-all is that if we get to this point and + # see a Sep, CR, LF, STerm or ATerm, then it has to fall into one of + # SB9, SB10 or SB11. In the cases of SB9-11, we always find a break since + # SB11 acts as a catch-all to induce a break following a SATerm that isn't + # handled by rules SB6-SB8a. + [^$ParaSep $SATerm] +)* +# The following collapses rules SB3, SB4, part of SB8a, SB9, SB10 and SB11. +($SATerm $Ex* ($Close $Ex*)* ($Sp $Ex*)*)* ($CR $LF | $ParaSep)? +" diff --git a/vendor/bstr-0.2.17/scripts/regex/word.sh b/vendor/bstr-0.2.17/scripts/regex/word.sh new file mode 100644 index 0000000000000..78c7a05cf326b --- /dev/null +++ b/vendor/bstr-0.2.17/scripts/regex/word.sh @@ -0,0 +1,111 @@ +#!/bin/sh + +# vim: indentexpr= nosmartindent autoindent +# vim: tabstop=2 shiftwidth=2 softtabstop=2 + +# See the comments in regex/sentence.sh for the general approach to how this +# regex was written. +# +# Writing the regex for this was *hard*. It took me two days of hacking to get +# this far, and that was after I had finished the sentence regex, so my brain +# was fully cached on this. Unlike the sentence regex, the rules in the regex +# below don't correspond as nicely to the rules in UAX #29. In particular, the +# UAX #29 rules have a ton of overlap with each other, which requires crazy +# stuff in the regex. I'm not even sure the regex below is 100% correct or even +# minimal, however, I did compare this with the ICU word segmenter on a few +# different corpora, and it produces identical results. (In addition to of +# course passing the UCD tests.) +# +# In general, I consider this approach to be a failure. Firstly, this is +# clearly a write-only regex. Secondly, building the minimized DFA for this is +# incredibly slow. Thirdly, the DFA is itself very large (~240KB). Fourthly, +# reversing this regex (for reverse word iteration) results in a >19MB DFA. +# Yes. That's MB. Wat. And it took 5 minutes to build. +# +# I think we might consider changing our approach to this problem. The normal +# path I've seen, I think, is to decode codepoints one at a time, and then +# thread them through a state machine in the code itself. We could take this +# approach, or possibly combine it with a DFA that tells us which Word_Break +# value a codepoint has. I'd prefer the latter approach, but it requires adding +# RegexSet support to regex-automata. Something that should definitely be done, +# but is a fair amount of work. +# +# Gah. + +CR="\p{wb=CR}" +LF="\p{wb=LF}" +Newline="\p{wb=Newline}" +ZWJ="\p{wb=ZWJ}" +RI="\p{wb=Regional_Indicator}" +Katakana="\p{wb=Katakana}" +HebrewLet="\p{wb=HebrewLetter}" +ALetter="\p{wb=ALetter}" +SingleQuote="\p{wb=SingleQuote}" +DoubleQuote="\p{wb=DoubleQuote}" +MidNumLet="\p{wb=MidNumLet}" +MidLetter="\p{wb=MidLetter}" +MidNum="\p{wb=MidNum}" +Numeric="\p{wb=Numeric}" +ExtendNumLet="\p{wb=ExtendNumLet}" +WSegSpace="\p{wb=WSegSpace}" + +Any="\p{any}" +Ex="[\p{wb=Extend} \p{wb=Format} $ZWJ]" +ExtendPict="\p{Extended_Pictographic}" +AHLetter="[$ALetter $HebrewLet]" +MidNumLetQ="[$MidNumLet $SingleQuote]" + +AHLetterRepeat="$AHLetter $Ex* ([$MidLetter $MidNumLetQ] $Ex* $AHLetter $Ex*)*" +NumericRepeat="$Numeric $Ex* ([$MidNum $MidNumLetQ] $Ex* $Numeric $Ex*)*" + +echo "(?x) +$CR $LF +| +[$Newline $CR $LF] +| +$WSegSpace $WSegSpace+ +| +( + ([^$Newline $CR $LF]? $Ex* $ZWJ $ExtendPict $Ex*)+ + | + ($ExtendNumLet $Ex*)* $AHLetter $Ex* + ( + ( + ($NumericRepeat | $ExtendNumLet $Ex*)* + | + [$MidLetter $MidNumLetQ] $Ex* + ) + $AHLetter $Ex* + )+ + ($NumericRepeat | $ExtendNumLet $Ex*)* + | + ($ExtendNumLet $Ex*)* $AHLetter $Ex* ($NumericRepeat | $ExtendNumLet $Ex*)+ + | + ($ExtendNumLet $Ex*)* $Numeric $Ex* + ( + ( + ($AHLetterRepeat | $ExtendNumLet $Ex*)* + | + [$MidNum $MidNumLetQ] $Ex* + ) + $Numeric $Ex* + )+ + ($AHLetterRepeat | $ExtendNumLet $Ex*)* + | + ($ExtendNumLet $Ex*)* $Numeric $Ex* ($AHLetterRepeat | $ExtendNumLet $Ex*)+ + | + $Katakana $Ex* + (($Katakana | $ExtendNumLet) $Ex*)+ + | + $ExtendNumLet $Ex* + (($ExtendNumLet | $AHLetter | $Numeric | $Katakana) $Ex*)+ +)+ +| +$HebrewLet $Ex* $SingleQuote $Ex* +| +($HebrewLet $Ex* $DoubleQuote $Ex*)+ $HebrewLet $Ex* +| +$RI $Ex* $RI $Ex* +| +$Any $Ex* +" diff --git a/vendor/bstr-0.2.17/src/ascii.rs b/vendor/bstr-0.2.17/src/ascii.rs new file mode 100644 index 0000000000000..bb2b67949ed92 --- /dev/null +++ b/vendor/bstr-0.2.17/src/ascii.rs @@ -0,0 +1,336 @@ +use core::mem; + +// The following ~400 lines of code exists for exactly one purpose, which is +// to optimize this code: +// +// byte_slice.iter().position(|&b| b > 0x7F).unwrap_or(byte_slice.len()) +// +// Yes... Overengineered is a word that comes to mind, but this is effectively +// a very similar problem to memchr, and virtually nobody has been able to +// resist optimizing the crap out of that (except for perhaps the BSD and MUSL +// folks). In particular, this routine makes a very common case (ASCII) very +// fast, which seems worth it. We do stop short of adding AVX variants of the +// code below in order to retain our sanity and also to avoid needing to deal +// with runtime target feature detection. RESIST! +// +// In order to understand the SIMD version below, it would be good to read this +// comment describing how my memchr routine works: +// https://github.com/BurntSushi/rust-memchr/blob/b0a29f267f4a7fad8ffcc8fe8377a06498202883/src/x86/sse2.rs#L19-L106 +// +// The primary difference with memchr is that for ASCII, we can do a bit less +// work. In particular, we don't need to detect the presence of a specific +// byte, but rather, whether any byte has its most significant bit set. That +// means we can effectively skip the _mm_cmpeq_epi8 step and jump straight to +// _mm_movemask_epi8. + +#[cfg(any(test, not(target_arch = "x86_64")))] +const USIZE_BYTES: usize = mem::size_of::(); +#[cfg(any(test, not(target_arch = "x86_64")))] +const FALLBACK_LOOP_SIZE: usize = 2 * USIZE_BYTES; + +// This is a mask where the most significant bit of each byte in the usize +// is set. We test this bit to determine whether a character is ASCII or not. +// Namely, a single byte is regarded as an ASCII codepoint if and only if it's +// most significant bit is not set. +#[cfg(any(test, not(target_arch = "x86_64")))] +const ASCII_MASK_U64: u64 = 0x8080808080808080; +#[cfg(any(test, not(target_arch = "x86_64")))] +const ASCII_MASK: usize = ASCII_MASK_U64 as usize; + +/// Returns the index of the first non ASCII byte in the given slice. +/// +/// If slice only contains ASCII bytes, then the length of the slice is +/// returned. +pub fn first_non_ascii_byte(slice: &[u8]) -> usize { + #[cfg(not(target_arch = "x86_64"))] + { + first_non_ascii_byte_fallback(slice) + } + + #[cfg(target_arch = "x86_64")] + { + first_non_ascii_byte_sse2(slice) + } +} + +#[cfg(any(test, not(target_arch = "x86_64")))] +fn first_non_ascii_byte_fallback(slice: &[u8]) -> usize { + let align = USIZE_BYTES - 1; + let start_ptr = slice.as_ptr(); + let end_ptr = slice[slice.len()..].as_ptr(); + let mut ptr = start_ptr; + + unsafe { + if slice.len() < USIZE_BYTES { + return first_non_ascii_byte_slow(start_ptr, end_ptr, ptr); + } + + let chunk = read_unaligned_usize(ptr); + let mask = chunk & ASCII_MASK; + if mask != 0 { + return first_non_ascii_byte_mask(mask); + } + + ptr = ptr_add(ptr, USIZE_BYTES - (start_ptr as usize & align)); + debug_assert!(ptr > start_ptr); + debug_assert!(ptr_sub(end_ptr, USIZE_BYTES) >= start_ptr); + if slice.len() >= FALLBACK_LOOP_SIZE { + while ptr <= ptr_sub(end_ptr, FALLBACK_LOOP_SIZE) { + debug_assert_eq!(0, (ptr as usize) % USIZE_BYTES); + + let a = *(ptr as *const usize); + let b = *(ptr_add(ptr, USIZE_BYTES) as *const usize); + if (a | b) & ASCII_MASK != 0 { + // What a kludge. We wrap the position finding code into + // a non-inlineable function, which makes the codegen in + // the tight loop above a bit better by avoiding a + // couple extra movs. We pay for it by two additional + // stores, but only in the case of finding a non-ASCII + // byte. + #[inline(never)] + unsafe fn findpos( + start_ptr: *const u8, + ptr: *const u8, + ) -> usize { + let a = *(ptr as *const usize); + let b = *(ptr_add(ptr, USIZE_BYTES) as *const usize); + + let mut at = sub(ptr, start_ptr); + let maska = a & ASCII_MASK; + if maska != 0 { + return at + first_non_ascii_byte_mask(maska); + } + + at += USIZE_BYTES; + let maskb = b & ASCII_MASK; + debug_assert!(maskb != 0); + return at + first_non_ascii_byte_mask(maskb); + } + return findpos(start_ptr, ptr); + } + ptr = ptr_add(ptr, FALLBACK_LOOP_SIZE); + } + } + first_non_ascii_byte_slow(start_ptr, end_ptr, ptr) + } +} + +#[cfg(target_arch = "x86_64")] +fn first_non_ascii_byte_sse2(slice: &[u8]) -> usize { + use core::arch::x86_64::*; + + const VECTOR_SIZE: usize = mem::size_of::<__m128i>(); + const VECTOR_ALIGN: usize = VECTOR_SIZE - 1; + const VECTOR_LOOP_SIZE: usize = 4 * VECTOR_SIZE; + + let start_ptr = slice.as_ptr(); + let end_ptr = slice[slice.len()..].as_ptr(); + let mut ptr = start_ptr; + + unsafe { + if slice.len() < VECTOR_SIZE { + return first_non_ascii_byte_slow(start_ptr, end_ptr, ptr); + } + + let chunk = _mm_loadu_si128(ptr as *const __m128i); + let mask = _mm_movemask_epi8(chunk); + if mask != 0 { + return mask.trailing_zeros() as usize; + } + + ptr = ptr.add(VECTOR_SIZE - (start_ptr as usize & VECTOR_ALIGN)); + debug_assert!(ptr > start_ptr); + debug_assert!(end_ptr.sub(VECTOR_SIZE) >= start_ptr); + if slice.len() >= VECTOR_LOOP_SIZE { + while ptr <= ptr_sub(end_ptr, VECTOR_LOOP_SIZE) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + let a = _mm_load_si128(ptr as *const __m128i); + let b = _mm_load_si128(ptr.add(VECTOR_SIZE) as *const __m128i); + let c = + _mm_load_si128(ptr.add(2 * VECTOR_SIZE) as *const __m128i); + let d = + _mm_load_si128(ptr.add(3 * VECTOR_SIZE) as *const __m128i); + + let or1 = _mm_or_si128(a, b); + let or2 = _mm_or_si128(c, d); + let or3 = _mm_or_si128(or1, or2); + if _mm_movemask_epi8(or3) != 0 { + let mut at = sub(ptr, start_ptr); + let mask = _mm_movemask_epi8(a); + if mask != 0 { + return at + mask.trailing_zeros() as usize; + } + + at += VECTOR_SIZE; + let mask = _mm_movemask_epi8(b); + if mask != 0 { + return at + mask.trailing_zeros() as usize; + } + + at += VECTOR_SIZE; + let mask = _mm_movemask_epi8(c); + if mask != 0 { + return at + mask.trailing_zeros() as usize; + } + + at += VECTOR_SIZE; + let mask = _mm_movemask_epi8(d); + debug_assert!(mask != 0); + return at + mask.trailing_zeros() as usize; + } + ptr = ptr_add(ptr, VECTOR_LOOP_SIZE); + } + } + while ptr <= end_ptr.sub(VECTOR_SIZE) { + debug_assert!(sub(end_ptr, ptr) >= VECTOR_SIZE); + + let chunk = _mm_loadu_si128(ptr as *const __m128i); + let mask = _mm_movemask_epi8(chunk); + if mask != 0 { + return sub(ptr, start_ptr) + mask.trailing_zeros() as usize; + } + ptr = ptr.add(VECTOR_SIZE); + } + first_non_ascii_byte_slow(start_ptr, end_ptr, ptr) + } +} + +#[inline(always)] +unsafe fn first_non_ascii_byte_slow( + start_ptr: *const u8, + end_ptr: *const u8, + mut ptr: *const u8, +) -> usize { + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr); + + while ptr < end_ptr { + if *ptr > 0x7F { + return sub(ptr, start_ptr); + } + ptr = ptr.offset(1); + } + sub(end_ptr, start_ptr) +} + +/// Compute the position of the first ASCII byte in the given mask. +/// +/// The mask should be computed by `chunk & ASCII_MASK`, where `chunk` is +/// 8 contiguous bytes of the slice being checked where *at least* one of those +/// bytes is not an ASCII byte. +/// +/// The position returned is always in the inclusive range [0, 7]. +#[cfg(any(test, not(target_arch = "x86_64")))] +fn first_non_ascii_byte_mask(mask: usize) -> usize { + #[cfg(target_endian = "little")] + { + mask.trailing_zeros() as usize / 8 + } + #[cfg(target_endian = "big")] + { + mask.leading_zeros() as usize / 8 + } +} + +/// Increment the given pointer by the given amount. +unsafe fn ptr_add(ptr: *const u8, amt: usize) -> *const u8 { + debug_assert!(amt < ::core::isize::MAX as usize); + ptr.offset(amt as isize) +} + +/// Decrement the given pointer by the given amount. +unsafe fn ptr_sub(ptr: *const u8, amt: usize) -> *const u8 { + debug_assert!(amt < ::core::isize::MAX as usize); + ptr.offset((amt as isize).wrapping_neg()) +} + +#[cfg(any(test, not(target_arch = "x86_64")))] +unsafe fn read_unaligned_usize(ptr: *const u8) -> usize { + use core::ptr; + + let mut n: usize = 0; + ptr::copy_nonoverlapping(ptr, &mut n as *mut _ as *mut u8, USIZE_BYTES); + n +} + +/// Subtract `b` from `a` and return the difference. `a` should be greater than +/// or equal to `b`. +fn sub(a: *const u8, b: *const u8) -> usize { + debug_assert!(a >= b); + (a as usize) - (b as usize) +} + +#[cfg(test)] +mod tests { + use super::*; + + // Our testing approach here is to try and exhaustively test every case. + // This includes the position at which a non-ASCII byte occurs in addition + // to the alignment of the slice that we're searching. + + #[test] + fn positive_fallback_forward() { + for i in 0..517 { + let s = "a".repeat(i); + assert_eq!( + i, + first_non_ascii_byte_fallback(s.as_bytes()), + "i: {:?}, len: {:?}, s: {:?}", + i, + s.len(), + s + ); + } + } + + #[test] + #[cfg(target_arch = "x86_64")] + fn positive_sse2_forward() { + for i in 0..517 { + let b = "a".repeat(i).into_bytes(); + assert_eq!(b.len(), first_non_ascii_byte_sse2(&b)); + } + } + + #[test] + fn negative_fallback_forward() { + for i in 0..517 { + for align in 0..65 { + let mut s = "a".repeat(i); + s.push_str("☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃"); + let s = s.get(align..).unwrap_or(""); + assert_eq!( + i.saturating_sub(align), + first_non_ascii_byte_fallback(s.as_bytes()), + "i: {:?}, align: {:?}, len: {:?}, s: {:?}", + i, + align, + s.len(), + s + ); + } + } + } + + #[test] + #[cfg(target_arch = "x86_64")] + fn negative_sse2_forward() { + for i in 0..517 { + for align in 0..65 { + let mut s = "a".repeat(i); + s.push_str("☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃"); + let s = s.get(align..).unwrap_or(""); + assert_eq!( + i.saturating_sub(align), + first_non_ascii_byte_sse2(s.as_bytes()), + "i: {:?}, align: {:?}, len: {:?}, s: {:?}", + i, + align, + s.len(), + s + ); + } + } + } +} diff --git a/vendor/bstr-0.2.17/src/bstr.rs b/vendor/bstr-0.2.17/src/bstr.rs new file mode 100644 index 0000000000000..1e3c91b9a0f05 --- /dev/null +++ b/vendor/bstr-0.2.17/src/bstr.rs @@ -0,0 +1,74 @@ +use core::mem; + +/// A wrapper for `&[u8]` that provides convenient string oriented trait impls. +/// +/// If you need ownership or a growable byte string buffer, then use +/// [`BString`](struct.BString.html). +/// +/// Using a `&BStr` is just like using a `&[u8]`, since `BStr` +/// implements `Deref` to `[u8]`. So all methods available on `[u8]` +/// are also available on `BStr`. +/// +/// # Representation +/// +/// A `&BStr` has the same representation as a `&str`. That is, a `&BStr` is +/// a fat pointer which consists of a pointer to some bytes and a length. +/// +/// # Trait implementations +/// +/// The `BStr` type has a number of trait implementations, and in particular, +/// defines equality and ordinal comparisons between `&BStr`, `&str` and +/// `&[u8]` for convenience. +/// +/// The `Debug` implementation for `BStr` shows its bytes as a normal string. +/// For invalid UTF-8, hex escape sequences are used. +/// +/// The `Display` implementation behaves as if `BStr` were first lossily +/// converted to a `str`. Invalid UTF-8 bytes are substituted with the Unicode +/// replacement codepoint, which looks like this: �. +#[derive(Hash)] +#[repr(transparent)] +pub struct BStr { + pub(crate) bytes: [u8], +} + +impl BStr { + #[inline] + pub(crate) fn new>(bytes: &B) -> &BStr { + BStr::from_bytes(bytes.as_ref()) + } + + #[inline] + pub(crate) fn new_mut>( + bytes: &mut B, + ) -> &mut BStr { + BStr::from_bytes_mut(bytes.as_mut()) + } + + #[inline] + pub(crate) fn from_bytes(slice: &[u8]) -> &BStr { + unsafe { mem::transmute(slice) } + } + + #[inline] + pub(crate) fn from_bytes_mut(slice: &mut [u8]) -> &mut BStr { + unsafe { mem::transmute(slice) } + } + + #[inline] + #[cfg(feature = "std")] + pub(crate) fn from_boxed_bytes(slice: Box<[u8]>) -> Box { + unsafe { Box::from_raw(Box::into_raw(slice) as _) } + } + + #[inline] + #[cfg(feature = "std")] + pub(crate) fn into_boxed_bytes(slice: Box) -> Box<[u8]> { + unsafe { Box::from_raw(Box::into_raw(slice) as _) } + } + + #[inline] + pub(crate) fn as_bytes(&self) -> &[u8] { + &self.bytes + } +} diff --git a/vendor/bstr-0.2.17/src/bstring.rs b/vendor/bstr-0.2.17/src/bstring.rs new file mode 100644 index 0000000000000..30093ba64e0d3 --- /dev/null +++ b/vendor/bstr-0.2.17/src/bstring.rs @@ -0,0 +1,59 @@ +use crate::bstr::BStr; + +/// A wrapper for `Vec` that provides convenient string oriented trait +/// impls. +/// +/// A `BString` has ownership over its contents and corresponds to +/// a growable or shrinkable buffer. Its borrowed counterpart is a +/// [`BStr`](struct.BStr.html), called a byte string slice. +/// +/// Using a `BString` is just like using a `Vec`, since `BString` +/// implements `Deref` to `Vec`. So all methods available on `Vec` +/// are also available on `BString`. +/// +/// # Examples +/// +/// You can create a new `BString` from a `Vec` via a `From` impl: +/// +/// ``` +/// use bstr::BString; +/// +/// let s = BString::from("Hello, world!"); +/// ``` +/// +/// # Deref +/// +/// The `BString` type implements `Deref` and `DerefMut`, where the target +/// types are `&Vec` and `&mut Vec`, respectively. `Deref` permits all of the +/// methods defined on `Vec` to be implicitly callable on any `BString`. +/// +/// For more information about how deref works, see the documentation for the +/// [`std::ops::Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) +/// trait. +/// +/// # Representation +/// +/// A `BString` has the same representation as a `Vec` and a `String`. +/// That is, it is made up of three word sized components: a pointer to a +/// region of memory containing the bytes, a length and a capacity. +#[derive(Clone, Hash)] +pub struct BString { + pub(crate) bytes: Vec, +} + +impl BString { + #[inline] + pub(crate) fn as_bytes(&self) -> &[u8] { + &self.bytes + } + + #[inline] + pub(crate) fn as_bstr(&self) -> &BStr { + BStr::new(&self.bytes) + } + + #[inline] + pub(crate) fn as_mut_bstr(&mut self) -> &mut BStr { + BStr::new_mut(&mut self.bytes) + } +} diff --git a/vendor/bstr-0.2.17/src/byteset/mod.rs b/vendor/bstr-0.2.17/src/byteset/mod.rs new file mode 100644 index 0000000000000..043d309868226 --- /dev/null +++ b/vendor/bstr-0.2.17/src/byteset/mod.rs @@ -0,0 +1,114 @@ +use memchr::{memchr, memchr2, memchr3, memrchr, memrchr2, memrchr3}; +mod scalar; + +#[inline] +fn build_table(byteset: &[u8]) -> [u8; 256] { + let mut table = [0u8; 256]; + for &b in byteset { + table[b as usize] = 1; + } + table +} + +#[inline] +pub(crate) fn find(haystack: &[u8], byteset: &[u8]) -> Option { + match byteset.len() { + 0 => return None, + 1 => memchr(byteset[0], haystack), + 2 => memchr2(byteset[0], byteset[1], haystack), + 3 => memchr3(byteset[0], byteset[1], byteset[2], haystack), + _ => { + let table = build_table(byteset); + scalar::forward_search_bytes(haystack, |b| table[b as usize] != 0) + } + } +} + +#[inline] +pub(crate) fn rfind(haystack: &[u8], byteset: &[u8]) -> Option { + match byteset.len() { + 0 => return None, + 1 => memrchr(byteset[0], haystack), + 2 => memrchr2(byteset[0], byteset[1], haystack), + 3 => memrchr3(byteset[0], byteset[1], byteset[2], haystack), + _ => { + let table = build_table(byteset); + scalar::reverse_search_bytes(haystack, |b| table[b as usize] != 0) + } + } +} + +#[inline] +pub(crate) fn find_not(haystack: &[u8], byteset: &[u8]) -> Option { + if haystack.is_empty() { + return None; + } + match byteset.len() { + 0 => return Some(0), + 1 => scalar::inv_memchr(byteset[0], haystack), + 2 => scalar::forward_search_bytes(haystack, |b| { + b != byteset[0] && b != byteset[1] + }), + 3 => scalar::forward_search_bytes(haystack, |b| { + b != byteset[0] && b != byteset[1] && b != byteset[2] + }), + _ => { + let table = build_table(byteset); + scalar::forward_search_bytes(haystack, |b| table[b as usize] == 0) + } + } +} +#[inline] +pub(crate) fn rfind_not(haystack: &[u8], byteset: &[u8]) -> Option { + if haystack.is_empty() { + return None; + } + match byteset.len() { + 0 => return Some(haystack.len() - 1), + 1 => scalar::inv_memrchr(byteset[0], haystack), + 2 => scalar::reverse_search_bytes(haystack, |b| { + b != byteset[0] && b != byteset[1] + }), + 3 => scalar::reverse_search_bytes(haystack, |b| { + b != byteset[0] && b != byteset[1] && b != byteset[2] + }), + _ => { + let table = build_table(byteset); + scalar::reverse_search_bytes(haystack, |b| table[b as usize] == 0) + } + } +} + +#[cfg(test)] +mod tests { + quickcheck::quickcheck! { + fn qc_byteset_forward_matches_naive( + haystack: Vec, + needles: Vec + ) -> bool { + super::find(&haystack, &needles) + == haystack.iter().position(|b| needles.contains(b)) + } + fn qc_byteset_backwards_matches_naive( + haystack: Vec, + needles: Vec + ) -> bool { + super::rfind(&haystack, &needles) + == haystack.iter().rposition(|b| needles.contains(b)) + } + fn qc_byteset_forward_not_matches_naive( + haystack: Vec, + needles: Vec + ) -> bool { + super::find_not(&haystack, &needles) + == haystack.iter().position(|b| !needles.contains(b)) + } + fn qc_byteset_backwards_not_matches_naive( + haystack: Vec, + needles: Vec + ) -> bool { + super::rfind_not(&haystack, &needles) + == haystack.iter().rposition(|b| !needles.contains(b)) + } + } +} diff --git a/vendor/bstr-0.2.17/src/byteset/scalar.rs b/vendor/bstr-0.2.17/src/byteset/scalar.rs new file mode 100644 index 0000000000000..9bd34a8f94661 --- /dev/null +++ b/vendor/bstr-0.2.17/src/byteset/scalar.rs @@ -0,0 +1,295 @@ +// This is adapted from `fallback.rs` from rust-memchr. It's modified to return +// the 'inverse' query of memchr, e.g. finding the first byte not in the provided +// set. This is simple for the 1-byte case. + +use core::cmp; +use core::usize; + +#[cfg(target_pointer_width = "32")] +const USIZE_BYTES: usize = 4; + +#[cfg(target_pointer_width = "64")] +const USIZE_BYTES: usize = 8; + +// The number of bytes to loop at in one iteration of memchr/memrchr. +const LOOP_SIZE: usize = 2 * USIZE_BYTES; + +/// Repeat the given byte into a word size number. That is, every 8 bits +/// is equivalent to the given byte. For example, if `b` is `\x4E` or +/// `01001110` in binary, then the returned value on a 32-bit system would be: +/// `01001110_01001110_01001110_01001110`. +#[inline(always)] +fn repeat_byte(b: u8) -> usize { + (b as usize) * (usize::MAX / 255) +} + +pub fn inv_memchr(n1: u8, haystack: &[u8]) -> Option { + let vn1 = repeat_byte(n1); + let confirm = |byte| byte != n1; + let loop_size = cmp::min(LOOP_SIZE, haystack.len()); + let align = USIZE_BYTES - 1; + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = start_ptr; + + unsafe { + if haystack.len() < USIZE_BYTES { + return forward_search(start_ptr, end_ptr, ptr, confirm); + } + + let chunk = read_unaligned_usize(ptr); + if (chunk ^ vn1) != 0 { + return forward_search(start_ptr, end_ptr, ptr, confirm); + } + + ptr = ptr.add(USIZE_BYTES - (start_ptr as usize & align)); + debug_assert!(ptr > start_ptr); + debug_assert!(end_ptr.sub(USIZE_BYTES) >= start_ptr); + while loop_size == LOOP_SIZE && ptr <= end_ptr.sub(loop_size) { + debug_assert_eq!(0, (ptr as usize) % USIZE_BYTES); + + let a = *(ptr as *const usize); + let b = *(ptr.add(USIZE_BYTES) as *const usize); + let eqa = (a ^ vn1) != 0; + let eqb = (b ^ vn1) != 0; + if eqa || eqb { + break; + } + ptr = ptr.add(LOOP_SIZE); + } + forward_search(start_ptr, end_ptr, ptr, confirm) + } +} + +/// Return the last index not matching the byte `x` in `text`. +pub fn inv_memrchr(n1: u8, haystack: &[u8]) -> Option { + let vn1 = repeat_byte(n1); + let confirm = |byte| byte != n1; + let loop_size = cmp::min(LOOP_SIZE, haystack.len()); + let align = USIZE_BYTES - 1; + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = end_ptr; + + unsafe { + if haystack.len() < USIZE_BYTES { + return reverse_search(start_ptr, end_ptr, ptr, confirm); + } + + let chunk = read_unaligned_usize(ptr.sub(USIZE_BYTES)); + if (chunk ^ vn1) != 0 { + return reverse_search(start_ptr, end_ptr, ptr, confirm); + } + + ptr = (end_ptr as usize & !align) as *const u8; + debug_assert!(start_ptr <= ptr && ptr <= end_ptr); + while loop_size == LOOP_SIZE && ptr >= start_ptr.add(loop_size) { + debug_assert_eq!(0, (ptr as usize) % USIZE_BYTES); + + let a = *(ptr.sub(2 * USIZE_BYTES) as *const usize); + let b = *(ptr.sub(1 * USIZE_BYTES) as *const usize); + let eqa = (a ^ vn1) != 0; + let eqb = (b ^ vn1) != 0; + if eqa || eqb { + break; + } + ptr = ptr.sub(loop_size); + } + reverse_search(start_ptr, end_ptr, ptr, confirm) + } +} + +#[inline(always)] +unsafe fn forward_search bool>( + start_ptr: *const u8, + end_ptr: *const u8, + mut ptr: *const u8, + confirm: F, +) -> Option { + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr); + + while ptr < end_ptr { + if confirm(*ptr) { + return Some(sub(ptr, start_ptr)); + } + ptr = ptr.offset(1); + } + None +} + +#[inline(always)] +unsafe fn reverse_search bool>( + start_ptr: *const u8, + end_ptr: *const u8, + mut ptr: *const u8, + confirm: F, +) -> Option { + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr); + + while ptr > start_ptr { + ptr = ptr.offset(-1); + if confirm(*ptr) { + return Some(sub(ptr, start_ptr)); + } + } + None +} + +unsafe fn read_unaligned_usize(ptr: *const u8) -> usize { + (ptr as *const usize).read_unaligned() +} + +/// Subtract `b` from `a` and return the difference. `a` should be greater than +/// or equal to `b`. +fn sub(a: *const u8, b: *const u8) -> usize { + debug_assert!(a >= b); + (a as usize) - (b as usize) +} + +/// Safe wrapper around `forward_search` +#[inline] +pub(crate) fn forward_search_bytes bool>( + s: &[u8], + confirm: F, +) -> Option { + unsafe { + let start = s.as_ptr(); + let end = start.add(s.len()); + forward_search(start, end, start, confirm) + } +} + +/// Safe wrapper around `reverse_search` +#[inline] +pub(crate) fn reverse_search_bytes bool>( + s: &[u8], + confirm: F, +) -> Option { + unsafe { + let start = s.as_ptr(); + let end = start.add(s.len()); + reverse_search(start, end, end, confirm) + } +} + +#[cfg(test)] +mod tests { + use super::{inv_memchr, inv_memrchr}; + // search string, search byte, inv_memchr result, inv_memrchr result. + // these are expanded into a much larger set of tests in build_tests + const TESTS: &[(&[u8], u8, usize, usize)] = &[ + (b"z", b'a', 0, 0), + (b"zz", b'a', 0, 1), + (b"aza", b'a', 1, 1), + (b"zaz", b'a', 0, 2), + (b"zza", b'a', 0, 1), + (b"zaa", b'a', 0, 0), + (b"zzz", b'a', 0, 2), + ]; + + type TestCase = (Vec, u8, Option<(usize, usize)>); + + fn build_tests() -> Vec { + let mut result = vec![]; + for &(search, byte, fwd_pos, rev_pos) in TESTS { + result.push((search.to_vec(), byte, Some((fwd_pos, rev_pos)))); + for i in 1..515 { + // add a bunch of copies of the search byte to the end. + let mut suffixed: Vec = search.into(); + suffixed.extend(std::iter::repeat(byte).take(i)); + result.push((suffixed, byte, Some((fwd_pos, rev_pos)))); + + // add a bunch of copies of the search byte to the start. + let mut prefixed: Vec = + std::iter::repeat(byte).take(i).collect(); + prefixed.extend(search); + result.push(( + prefixed, + byte, + Some((fwd_pos + i, rev_pos + i)), + )); + + // add a bunch of copies of the search byte to both ends. + let mut surrounded: Vec = + std::iter::repeat(byte).take(i).collect(); + surrounded.extend(search); + surrounded.extend(std::iter::repeat(byte).take(i)); + result.push(( + surrounded, + byte, + Some((fwd_pos + i, rev_pos + i)), + )); + } + } + + // build non-matching tests for several sizes + for i in 0..515 { + result.push(( + std::iter::repeat(b'\0').take(i).collect(), + b'\0', + None, + )); + } + + result + } + + #[test] + fn test_inv_memchr() { + use crate::{ByteSlice, B}; + for (search, byte, matching) in build_tests() { + assert_eq!( + inv_memchr(byte, &search), + matching.map(|m| m.0), + "inv_memchr when searching for {:?} in {:?}", + byte as char, + // better printing + B(&search).as_bstr(), + ); + assert_eq!( + inv_memrchr(byte, &search), + matching.map(|m| m.1), + "inv_memrchr when searching for {:?} in {:?}", + byte as char, + // better printing + B(&search).as_bstr(), + ); + // Test a rather large number off offsets for potential alignment issues + for offset in 1..130 { + if offset >= search.len() { + break; + } + // If this would cause us to shift the results off the end, skip + // it so that we don't have to recompute them. + if let Some((f, r)) = matching { + if offset > f || offset > r { + break; + } + } + let realigned = &search[offset..]; + + let forward_pos = matching.map(|m| m.0 - offset); + let reverse_pos = matching.map(|m| m.1 - offset); + + assert_eq!( + inv_memchr(byte, &realigned), + forward_pos, + "inv_memchr when searching (realigned by {}) for {:?} in {:?}", + offset, + byte as char, + realigned.as_bstr(), + ); + assert_eq!( + inv_memrchr(byte, &realigned), + reverse_pos, + "inv_memrchr when searching (realigned by {}) for {:?} in {:?}", + offset, + byte as char, + realigned.as_bstr(), + ); + } + } + } +} diff --git a/vendor/bstr-0.2.17/src/ext_slice.rs b/vendor/bstr-0.2.17/src/ext_slice.rs new file mode 100644 index 0000000000000..0cc73affcf71a --- /dev/null +++ b/vendor/bstr-0.2.17/src/ext_slice.rs @@ -0,0 +1,3655 @@ +#[cfg(feature = "std")] +use std::borrow::Cow; +#[cfg(feature = "std")] +use std::ffi::OsStr; +#[cfg(feature = "std")] +use std::path::Path; + +use core::{iter, ops, ptr, slice, str}; +use memchr::{memchr, memmem, memrchr}; + +use crate::ascii; +use crate::bstr::BStr; +use crate::byteset; +#[cfg(feature = "std")] +use crate::ext_vec::ByteVec; +#[cfg(feature = "unicode")] +use crate::unicode::{ + whitespace_len_fwd, whitespace_len_rev, GraphemeIndices, Graphemes, + SentenceIndices, Sentences, WordIndices, Words, WordsWithBreakIndices, + WordsWithBreaks, +}; +use crate::utf8::{self, CharIndices, Chars, Utf8Chunks, Utf8Error}; + +/// A short-hand constructor for building a `&[u8]`. +/// +/// This idiosyncratic constructor is useful for concisely building byte string +/// slices. Its primary utility is in conveniently writing byte string literals +/// in a uniform way. For example, consider this code that does not compile: +/// +/// ```ignore +/// let strs = vec![b"a", b"xy"]; +/// ``` +/// +/// The above code doesn't compile because the type of the byte string literal +/// `b"a"` is `&'static [u8; 1]`, and the type of `b"xy"` is +/// `&'static [u8; 2]`. Since their types aren't the same, they can't be stored +/// in the same `Vec`. (This is dissimilar from normal Unicode string slices, +/// where both `"a"` and `"xy"` have the same type of `&'static str`.) +/// +/// One way of getting the above code to compile is to convert byte strings to +/// slices. You might try this: +/// +/// ```ignore +/// let strs = vec![&b"a", &b"xy"]; +/// ``` +/// +/// But this just creates values with type `& &'static [u8; 1]` and +/// `& &'static [u8; 2]`. Instead, you need to force the issue like so: +/// +/// ``` +/// let strs = vec![&b"a"[..], &b"xy"[..]]; +/// // or +/// let strs = vec![b"a".as_ref(), b"xy".as_ref()]; +/// ``` +/// +/// But neither of these are particularly convenient to type, especially when +/// it's something as common as a string literal. Thus, this constructor +/// permits writing the following instead: +/// +/// ``` +/// use bstr::B; +/// +/// let strs = vec![B("a"), B(b"xy")]; +/// ``` +/// +/// Notice that this also lets you mix and match both string literals and byte +/// string literals. This can be quite convenient! +#[allow(non_snake_case)] +#[inline] +pub fn B<'a, B: ?Sized + AsRef<[u8]>>(bytes: &'a B) -> &'a [u8] { + bytes.as_ref() +} + +impl ByteSlice for [u8] { + #[inline] + fn as_bytes(&self) -> &[u8] { + self + } + + #[inline] + fn as_bytes_mut(&mut self) -> &mut [u8] { + self + } +} + +/// Ensure that callers cannot implement `ByteSlice` by making an +/// umplementable trait its super trait. +pub trait Sealed {} +impl Sealed for [u8] {} + +/// A trait that extends `&[u8]` with string oriented methods. +pub trait ByteSlice: Sealed { + /// A method for accessing the raw bytes of this type. This is always a + /// no-op and callers shouldn't care about it. This only exists for making + /// the extension trait work. + #[doc(hidden)] + fn as_bytes(&self) -> &[u8]; + + /// A method for accessing the raw bytes of this type, mutably. This is + /// always a no-op and callers shouldn't care about it. This only exists + /// for making the extension trait work. + #[doc(hidden)] + fn as_bytes_mut(&mut self) -> &mut [u8]; + + /// Return this byte slice as a `&BStr`. + /// + /// Use `&BStr` is useful because of its `fmt::Debug` representation + /// and various other trait implementations (such as `PartialEq` and + /// `PartialOrd`). In particular, the `Debug` implementation for `BStr` + /// shows its bytes as a normal string. For invalid UTF-8, hex escape + /// sequences are used. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// println!("{:?}", b"foo\xFFbar".as_bstr()); + /// ``` + #[inline] + fn as_bstr(&self) -> &BStr { + BStr::new(self.as_bytes()) + } + + /// Return this byte slice as a `&mut BStr`. + /// + /// Use `&mut BStr` is useful because of its `fmt::Debug` representation + /// and various other trait implementations (such as `PartialEq` and + /// `PartialOrd`). In particular, the `Debug` implementation for `BStr` + /// shows its bytes as a normal string. For invalid UTF-8, hex escape + /// sequences are used. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut bytes = *b"foo\xFFbar"; + /// println!("{:?}", &mut bytes.as_bstr_mut()); + /// ``` + #[inline] + fn as_bstr_mut(&mut self) -> &mut BStr { + BStr::new_mut(self.as_bytes_mut()) + } + + /// Create an immutable byte string from an OS string slice. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns `None` if the given OS string is not valid UTF-8. (For + /// example, on Windows, file paths are allowed to be a sequence of + /// arbitrary 16-bit integers. Not all such sequences can be transcoded to + /// valid UTF-8.) + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// use bstr::{B, ByteSlice}; + /// + /// let os_str = OsStr::new("foo"); + /// let bs = <[u8]>::from_os_str(os_str).expect("should be valid UTF-8"); + /// assert_eq!(bs, B("foo")); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn from_os_str(os_str: &OsStr) -> Option<&[u8]> { + #[cfg(unix)] + #[inline] + fn imp(os_str: &OsStr) -> Option<&[u8]> { + use std::os::unix::ffi::OsStrExt; + + Some(os_str.as_bytes()) + } + + #[cfg(not(unix))] + #[inline] + fn imp(os_str: &OsStr) -> Option<&[u8]> { + os_str.to_str().map(|s| s.as_bytes()) + } + + imp(os_str) + } + + /// Create an immutable byte string from a file path. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns `None` if the given path is not valid UTF-8. (For example, + /// on Windows, file paths are allowed to be a sequence of arbitrary 16-bit + /// integers. Not all such sequences can be transcoded to valid UTF-8.) + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::path::Path; + /// + /// use bstr::{B, ByteSlice}; + /// + /// let path = Path::new("foo"); + /// let bs = <[u8]>::from_path(path).expect("should be valid UTF-8"); + /// assert_eq!(bs, B("foo")); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn from_path(path: &Path) -> Option<&[u8]> { + Self::from_os_str(path.as_os_str()) + } + + /// Safely convert this byte string into a `&str` if it's valid UTF-8. + /// + /// If this byte string is not valid UTF-8, then an error is returned. The + /// error returned indicates the first invalid byte found and the length + /// of the error. + /// + /// In cases where a lossy conversion to `&str` is acceptable, then use one + /// of the [`to_str_lossy`](trait.ByteSlice.html#method.to_str_lossy) or + /// [`to_str_lossy_into`](trait.ByteSlice.html#method.to_str_lossy_into) + /// methods. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice, ByteVec}; + /// + /// # fn example() -> Result<(), bstr::Utf8Error> { + /// let s = B("☃βツ").to_str()?; + /// assert_eq!("☃βツ", s); + /// + /// let mut bstring = >::from("☃βツ"); + /// bstring.push(b'\xFF'); + /// let err = bstring.to_str().unwrap_err(); + /// assert_eq!(8, err.valid_up_to()); + /// # Ok(()) }; example().unwrap() + /// ``` + #[inline] + fn to_str(&self) -> Result<&str, Utf8Error> { + utf8::validate(self.as_bytes()).map(|_| { + // SAFETY: This is safe because of the guarantees provided by + // utf8::validate. + unsafe { str::from_utf8_unchecked(self.as_bytes()) } + }) + } + + /// Unsafely convert this byte string into a `&str`, without checking for + /// valid UTF-8. + /// + /// # Safety + /// + /// Callers *must* ensure that this byte string is valid UTF-8 before + /// calling this method. Converting a byte string into a `&str` that is + /// not valid UTF-8 is considered undefined behavior. + /// + /// This routine is useful in performance sensitive contexts where the + /// UTF-8 validity of the byte string is already known and it is + /// undesirable to pay the cost of an additional UTF-8 validation check + /// that [`to_str`](trait.ByteSlice.html#method.to_str) performs. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// // SAFETY: This is safe because string literals are guaranteed to be + /// // valid UTF-8 by the Rust compiler. + /// let s = unsafe { B("☃βツ").to_str_unchecked() }; + /// assert_eq!("☃βツ", s); + /// ``` + #[inline] + unsafe fn to_str_unchecked(&self) -> &str { + str::from_utf8_unchecked(self.as_bytes()) + } + + /// Convert this byte string to a valid UTF-8 string by replacing invalid + /// UTF-8 bytes with the Unicode replacement codepoint (`U+FFFD`). + /// + /// If the byte string is already valid UTF-8, then no copying or + /// allocation is performed and a borrrowed string slice is returned. If + /// the byte string is not valid UTF-8, then an owned string buffer is + /// returned with invalid bytes replaced by the replacement codepoint. + /// + /// This method uses the "substitution of maximal subparts" (Unicode + /// Standard, Chapter 3, Section 9) strategy for inserting the replacement + /// codepoint. Specifically, a replacement codepoint is inserted whenever a + /// byte is found that cannot possibly lead to a valid code unit sequence. + /// If there were previous bytes that represented a prefix of a well-formed + /// code unit sequence, then all of those bytes are substituted with a + /// single replacement codepoint. The "substitution of maximal subparts" + /// strategy is the same strategy used by + /// [W3C's Encoding standard](https://www.w3.org/TR/encoding/). + /// For a more precise description of the maximal subpart strategy, see + /// the Unicode Standard, Chapter 3, Section 9. See also + /// [Public Review Issue #121](http://www.unicode.org/review/pr-121.html). + /// + /// N.B. Rust's standard library also appears to use the same strategy, + /// but it does not appear to be an API guarantee. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::borrow::Cow; + /// + /// use bstr::ByteSlice; + /// + /// let mut bstring = >::from("☃βツ"); + /// assert_eq!(Cow::Borrowed("☃βツ"), bstring.to_str_lossy()); + /// + /// // Add a byte that makes the sequence invalid. + /// bstring.push(b'\xFF'); + /// assert_eq!(Cow::Borrowed("☃βツ\u{FFFD}"), bstring.to_str_lossy()); + /// ``` + /// + /// This demonstrates the "maximal subpart" substitution logic. + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// // \x61 is the ASCII codepoint for 'a'. + /// // \xF1\x80\x80 is a valid 3-byte code unit prefix. + /// // \xE1\x80 is a valid 2-byte code unit prefix. + /// // \xC2 is a valid 1-byte code unit prefix. + /// // \x62 is the ASCII codepoint for 'b'. + /// // + /// // In sum, each of the prefixes is replaced by a single replacement + /// // codepoint since none of the prefixes are properly completed. This + /// // is in contrast to other strategies that might insert a replacement + /// // codepoint for every single byte. + /// let bs = B(b"\x61\xF1\x80\x80\xE1\x80\xC2\x62"); + /// assert_eq!("a\u{FFFD}\u{FFFD}\u{FFFD}b", bs.to_str_lossy()); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn to_str_lossy(&self) -> Cow<'_, str> { + match utf8::validate(self.as_bytes()) { + Ok(()) => { + // SAFETY: This is safe because of the guarantees provided by + // utf8::validate. + unsafe { + Cow::Borrowed(str::from_utf8_unchecked(self.as_bytes())) + } + } + Err(err) => { + let mut lossy = String::with_capacity(self.as_bytes().len()); + let (valid, after) = + self.as_bytes().split_at(err.valid_up_to()); + // SAFETY: This is safe because utf8::validate guarantees + // that all of `valid` is valid UTF-8. + lossy.push_str(unsafe { str::from_utf8_unchecked(valid) }); + lossy.push_str("\u{FFFD}"); + if let Some(len) = err.error_len() { + after[len..].to_str_lossy_into(&mut lossy); + } + Cow::Owned(lossy) + } + } + } + + /// Copy the contents of this byte string into the given owned string + /// buffer, while replacing invalid UTF-8 code unit sequences with the + /// Unicode replacement codepoint (`U+FFFD`). + /// + /// This method uses the same "substitution of maximal subparts" strategy + /// for inserting the replacement codepoint as the + /// [`to_str_lossy`](trait.ByteSlice.html#method.to_str_lossy) method. + /// + /// This routine is useful for amortizing allocation. However, unlike + /// `to_str_lossy`, this routine will _always_ copy the contents of this + /// byte string into the destination buffer, even if this byte string is + /// valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::borrow::Cow; + /// + /// use bstr::ByteSlice; + /// + /// let mut bstring = >::from("☃βツ"); + /// // Add a byte that makes the sequence invalid. + /// bstring.push(b'\xFF'); + /// + /// let mut dest = String::new(); + /// bstring.to_str_lossy_into(&mut dest); + /// assert_eq!("☃βツ\u{FFFD}", dest); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn to_str_lossy_into(&self, dest: &mut String) { + let mut bytes = self.as_bytes(); + dest.reserve(bytes.len()); + loop { + match utf8::validate(bytes) { + Ok(()) => { + // SAFETY: This is safe because utf8::validate guarantees + // that all of `bytes` is valid UTF-8. + dest.push_str(unsafe { str::from_utf8_unchecked(bytes) }); + break; + } + Err(err) => { + let (valid, after) = bytes.split_at(err.valid_up_to()); + // SAFETY: This is safe because utf8::validate guarantees + // that all of `valid` is valid UTF-8. + dest.push_str(unsafe { str::from_utf8_unchecked(valid) }); + dest.push_str("\u{FFFD}"); + match err.error_len() { + None => break, + Some(len) => bytes = &after[len..], + } + } + } + } + } + + /// Create an OS string slice from this byte string. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns a UTF-8 decoding error if this byte string is not valid + /// UTF-8. (For example, on Windows, file paths are allowed to be a + /// sequence of arbitrary 16-bit integers. There is no obvious mapping from + /// an arbitrary sequence of 8-bit integers to an arbitrary sequence of + /// 16-bit integers.) + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let os_str = b"foo".to_os_str().expect("should be valid UTF-8"); + /// assert_eq!(os_str, "foo"); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn to_os_str(&self) -> Result<&OsStr, Utf8Error> { + #[cfg(unix)] + #[inline] + fn imp(bytes: &[u8]) -> Result<&OsStr, Utf8Error> { + use std::os::unix::ffi::OsStrExt; + + Ok(OsStr::from_bytes(bytes)) + } + + #[cfg(not(unix))] + #[inline] + fn imp(bytes: &[u8]) -> Result<&OsStr, Utf8Error> { + bytes.to_str().map(OsStr::new) + } + + imp(self.as_bytes()) + } + + /// Lossily create an OS string slice from this byte string. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this will perform a UTF-8 check and lossily convert this byte string + /// into valid UTF-8 using the Unicode replacement codepoint. + /// + /// Note that this can prevent the correct roundtripping of file paths on + /// non-Unix systems such as Windows, where file paths are an arbitrary + /// sequence of 16-bit integers. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let os_str = b"foo\xFFbar".to_os_str_lossy(); + /// assert_eq!(os_str.to_string_lossy(), "foo\u{FFFD}bar"); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn to_os_str_lossy(&self) -> Cow<'_, OsStr> { + #[cfg(unix)] + #[inline] + fn imp(bytes: &[u8]) -> Cow<'_, OsStr> { + use std::os::unix::ffi::OsStrExt; + + Cow::Borrowed(OsStr::from_bytes(bytes)) + } + + #[cfg(not(unix))] + #[inline] + fn imp(bytes: &[u8]) -> Cow { + use std::ffi::OsString; + + match bytes.to_str_lossy() { + Cow::Borrowed(x) => Cow::Borrowed(OsStr::new(x)), + Cow::Owned(x) => Cow::Owned(OsString::from(x)), + } + } + + imp(self.as_bytes()) + } + + /// Create a path slice from this byte string. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns a UTF-8 decoding error if this byte string is not valid + /// UTF-8. (For example, on Windows, file paths are allowed to be a + /// sequence of arbitrary 16-bit integers. There is no obvious mapping from + /// an arbitrary sequence of 8-bit integers to an arbitrary sequence of + /// 16-bit integers.) + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let path = b"foo".to_path().expect("should be valid UTF-8"); + /// assert_eq!(path.as_os_str(), "foo"); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn to_path(&self) -> Result<&Path, Utf8Error> { + self.to_os_str().map(Path::new) + } + + /// Lossily create a path slice from this byte string. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this will perform a UTF-8 check and lossily convert this byte string + /// into valid UTF-8 using the Unicode replacement codepoint. + /// + /// Note that this can prevent the correct roundtripping of file paths on + /// non-Unix systems such as Windows, where file paths are an arbitrary + /// sequence of 16-bit integers. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = b"foo\xFFbar"; + /// let path = bs.to_path_lossy(); + /// assert_eq!(path.to_string_lossy(), "foo\u{FFFD}bar"); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn to_path_lossy(&self) -> Cow<'_, Path> { + use std::path::PathBuf; + + match self.to_os_str_lossy() { + Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), + Cow::Owned(x) => Cow::Owned(PathBuf::from(x)), + } + } + + /// Create a new byte string by repeating this byte string `n` times. + /// + /// # Panics + /// + /// This function panics if the capacity of the new byte string would + /// overflow. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// assert_eq!(b"foo".repeatn(4), B("foofoofoofoo")); + /// assert_eq!(b"foo".repeatn(0), B("")); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn repeatn(&self, n: usize) -> Vec { + let bs = self.as_bytes(); + let mut dst = vec![0; bs.len() * n]; + for i in 0..n { + dst[i * bs.len()..(i + 1) * bs.len()].copy_from_slice(bs); + } + dst + } + + /// Returns true if and only if this byte string contains the given needle. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// assert!(b"foo bar".contains_str("foo")); + /// assert!(b"foo bar".contains_str("bar")); + /// assert!(!b"foo".contains_str("foobar")); + /// ``` + #[inline] + fn contains_str>(&self, needle: B) -> bool { + self.find(needle).is_some() + } + + /// Returns true if and only if this byte string has the given prefix. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// assert!(b"foo bar".starts_with_str("foo")); + /// assert!(!b"foo bar".starts_with_str("bar")); + /// assert!(!b"foo".starts_with_str("foobar")); + /// ``` + #[inline] + fn starts_with_str>(&self, prefix: B) -> bool { + self.as_bytes().starts_with(prefix.as_ref()) + } + + /// Returns true if and only if this byte string has the given suffix. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// assert!(b"foo bar".ends_with_str("bar")); + /// assert!(!b"foo bar".ends_with_str("foo")); + /// assert!(!b"bar".ends_with_str("foobar")); + /// ``` + #[inline] + fn ends_with_str>(&self, suffix: B) -> bool { + self.as_bytes().ends_with(suffix.as_ref()) + } + + /// Returns the index of the first occurrence of the given needle. + /// + /// The needle may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`. + /// + /// Note that if you're are searching for the same needle in many + /// different small haystacks, it may be faster to initialize a + /// [`Finder`](struct.Finder.html) once, and reuse it for each search. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"foo bar baz"; + /// assert_eq!(Some(0), s.find("foo")); + /// assert_eq!(Some(4), s.find("bar")); + /// assert_eq!(None, s.find("quux")); + /// ``` + #[inline] + fn find>(&self, needle: B) -> Option { + Finder::new(needle.as_ref()).find(self.as_bytes()) + } + + /// Returns the index of the last occurrence of the given needle. + /// + /// The needle may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`. + /// + /// Note that if you're are searching for the same needle in many + /// different small haystacks, it may be faster to initialize a + /// [`FinderReverse`](struct.FinderReverse.html) once, and reuse it for + /// each search. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"foo bar baz"; + /// assert_eq!(Some(0), s.rfind("foo")); + /// assert_eq!(Some(4), s.rfind("bar")); + /// assert_eq!(Some(8), s.rfind("ba")); + /// assert_eq!(None, s.rfind("quux")); + /// ``` + #[inline] + fn rfind>(&self, needle: B) -> Option { + FinderReverse::new(needle.as_ref()).rfind(self.as_bytes()) + } + + /// Returns an iterator of the non-overlapping occurrences of the given + /// needle. The iterator yields byte offset positions indicating the start + /// of each match. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"foo bar foo foo quux foo"; + /// let matches: Vec = s.find_iter("foo").collect(); + /// assert_eq!(matches, vec![0, 8, 12, 21]); + /// ``` + /// + /// An empty string matches at every position, including the position + /// immediately following the last byte: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let matches: Vec = b"foo".find_iter("").collect(); + /// assert_eq!(matches, vec![0, 1, 2, 3]); + /// + /// let matches: Vec = b"".find_iter("").collect(); + /// assert_eq!(matches, vec![0]); + /// ``` + #[inline] + fn find_iter<'a, B: ?Sized + AsRef<[u8]>>( + &'a self, + needle: &'a B, + ) -> Find<'a> { + Find::new(self.as_bytes(), needle.as_ref()) + } + + /// Returns an iterator of the non-overlapping occurrences of the given + /// needle in reverse. The iterator yields byte offset positions indicating + /// the start of each match. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"foo bar foo foo quux foo"; + /// let matches: Vec = s.rfind_iter("foo").collect(); + /// assert_eq!(matches, vec![21, 12, 8, 0]); + /// ``` + /// + /// An empty string matches at every position, including the position + /// immediately following the last byte: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let matches: Vec = b"foo".rfind_iter("").collect(); + /// assert_eq!(matches, vec![3, 2, 1, 0]); + /// + /// let matches: Vec = b"".rfind_iter("").collect(); + /// assert_eq!(matches, vec![0]); + /// ``` + #[inline] + fn rfind_iter<'a, B: ?Sized + AsRef<[u8]>>( + &'a self, + needle: &'a B, + ) -> FindReverse<'a> { + FindReverse::new(self.as_bytes(), needle.as_ref()) + } + + /// Returns the index of the first occurrence of the given byte. If the + /// byte does not occur in this byte string, then `None` is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// assert_eq!(Some(10), b"foo bar baz".find_byte(b'z')); + /// assert_eq!(None, b"foo bar baz".find_byte(b'y')); + /// ``` + #[inline] + fn find_byte(&self, byte: u8) -> Option { + memchr(byte, self.as_bytes()) + } + + /// Returns the index of the last occurrence of the given byte. If the + /// byte does not occur in this byte string, then `None` is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// assert_eq!(Some(10), b"foo bar baz".rfind_byte(b'z')); + /// assert_eq!(None, b"foo bar baz".rfind_byte(b'y')); + /// ``` + #[inline] + fn rfind_byte(&self, byte: u8) -> Option { + memrchr(byte, self.as_bytes()) + } + + /// Returns the index of the first occurrence of the given codepoint. + /// If the codepoint does not occur in this byte string, then `None` is + /// returned. + /// + /// Note that if one searches for the replacement codepoint, `\u{FFFD}`, + /// then only explicit occurrences of that encoding will be found. Invalid + /// UTF-8 sequences will not be matched. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// assert_eq!(Some(10), b"foo bar baz".find_char('z')); + /// assert_eq!(Some(4), B("αβγγδ").find_char('γ')); + /// assert_eq!(None, b"foo bar baz".find_char('y')); + /// ``` + #[inline] + fn find_char(&self, ch: char) -> Option { + self.find(ch.encode_utf8(&mut [0; 4])) + } + + /// Returns the index of the last occurrence of the given codepoint. + /// If the codepoint does not occur in this byte string, then `None` is + /// returned. + /// + /// Note that if one searches for the replacement codepoint, `\u{FFFD}`, + /// then only explicit occurrences of that encoding will be found. Invalid + /// UTF-8 sequences will not be matched. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// assert_eq!(Some(10), b"foo bar baz".rfind_char('z')); + /// assert_eq!(Some(6), B("αβγγδ").rfind_char('γ')); + /// assert_eq!(None, b"foo bar baz".rfind_char('y')); + /// ``` + #[inline] + fn rfind_char(&self, ch: char) -> Option { + self.rfind(ch.encode_utf8(&mut [0; 4])) + } + + /// Returns the index of the first occurrence of any of the bytes in the + /// provided set. + /// + /// The `byteset` may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`, but + /// note that passing a `&str` which contains multibyte characters may not + /// behave as you expect: each byte in the `&str` is treated as an + /// individual member of the byte set. + /// + /// Note that order is irrelevant for the `byteset` parameter, and + /// duplicate bytes present in its body are ignored. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the set of bytes and the haystack. That is, this + /// runs in `O(byteset.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// assert_eq!(b"foo bar baz".find_byteset(b"zr"), Some(6)); + /// assert_eq!(b"foo baz bar".find_byteset(b"bzr"), Some(4)); + /// assert_eq!(None, b"foo baz bar".find_byteset(b"\t\n")); + /// ``` + #[inline] + fn find_byteset>(&self, byteset: B) -> Option { + byteset::find(self.as_bytes(), byteset.as_ref()) + } + + /// Returns the index of the first occurrence of a byte that is not a member + /// of the provided set. + /// + /// The `byteset` may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`, but + /// note that passing a `&str` which contains multibyte characters may not + /// behave as you expect: each byte in the `&str` is treated as an + /// individual member of the byte set. + /// + /// Note that order is irrelevant for the `byteset` parameter, and + /// duplicate bytes present in its body are ignored. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the set of bytes and the haystack. That is, this + /// runs in `O(byteset.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// assert_eq!(b"foo bar baz".find_not_byteset(b"fo "), Some(4)); + /// assert_eq!(b"\t\tbaz bar".find_not_byteset(b" \t\r\n"), Some(2)); + /// assert_eq!(b"foo\nbaz\tbar".find_not_byteset(b"\t\n"), Some(0)); + /// ``` + #[inline] + fn find_not_byteset>(&self, byteset: B) -> Option { + byteset::find_not(self.as_bytes(), byteset.as_ref()) + } + + /// Returns the index of the last occurrence of any of the bytes in the + /// provided set. + /// + /// The `byteset` may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`, but + /// note that passing a `&str` which contains multibyte characters may not + /// behave as you expect: each byte in the `&str` is treated as an + /// individual member of the byte set. + /// + /// Note that order is irrelevant for the `byteset` parameter, and duplicate + /// bytes present in its body are ignored. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the set of bytes and the haystack. That is, this + /// runs in `O(byteset.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// assert_eq!(b"foo bar baz".rfind_byteset(b"agb"), Some(9)); + /// assert_eq!(b"foo baz bar".rfind_byteset(b"rabz "), Some(10)); + /// assert_eq!(b"foo baz bar".rfind_byteset(b"\n123"), None); + /// ``` + #[inline] + fn rfind_byteset>(&self, byteset: B) -> Option { + byteset::rfind(self.as_bytes(), byteset.as_ref()) + } + + /// Returns the index of the last occurrence of a byte that is not a member + /// of the provided set. + /// + /// The `byteset` may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`, but + /// note that passing a `&str` which contains multibyte characters may not + /// behave as you expect: each byte in the `&str` is treated as an + /// individual member of the byte set. + /// + /// Note that order is irrelevant for the `byteset` parameter, and + /// duplicate bytes present in its body are ignored. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the set of bytes and the haystack. That is, this + /// runs in `O(byteset.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// assert_eq!(b"foo bar baz,\t".rfind_not_byteset(b",\t"), Some(10)); + /// assert_eq!(b"foo baz bar".rfind_not_byteset(b"rabz "), Some(2)); + /// assert_eq!(None, b"foo baz bar".rfind_not_byteset(b"barfoz ")); + /// ``` + #[inline] + fn rfind_not_byteset>(&self, byteset: B) -> Option { + byteset::rfind_not(self.as_bytes(), byteset.as_ref()) + } + + /// Returns an iterator over the fields in a byte string, separated by + /// contiguous whitespace. + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B(" foo\tbar\t\u{2003}\nquux \n"); + /// let fields: Vec<&[u8]> = s.fields().collect(); + /// assert_eq!(fields, vec![B("foo"), B("bar"), B("quux")]); + /// ``` + /// + /// A byte string consisting of just whitespace yields no elements: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// assert_eq!(0, B(" \n\t\u{2003}\n \t").fields().count()); + /// ``` + #[inline] + fn fields(&self) -> Fields<'_> { + Fields::new(self.as_bytes()) + } + + /// Returns an iterator over the fields in a byte string, separated by + /// contiguous codepoints satisfying the given predicate. + /// + /// If this byte string is not valid UTF-8, then the given closure will + /// be called with a Unicode replacement codepoint when invalid UTF-8 + /// bytes are seen. + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = b"123foo999999bar1quux123456"; + /// let fields: Vec<&[u8]> = s.fields_with(|c| c.is_numeric()).collect(); + /// assert_eq!(fields, vec![B("foo"), B("bar"), B("quux")]); + /// ``` + /// + /// A byte string consisting of all codepoints satisfying the predicate + /// yields no elements: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// assert_eq!(0, b"1911354563".fields_with(|c| c.is_numeric()).count()); + /// ``` + #[inline] + fn fields_with bool>(&self, f: F) -> FieldsWith<'_, F> { + FieldsWith::new(self.as_bytes(), f) + } + + /// Returns an iterator over substrings of this byte string, separated + /// by the given byte string. Each element yielded is guaranteed not to + /// include the splitter substring. + /// + /// The splitter may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let x: Vec<&[u8]> = b"Mary had a little lamb".split_str(" ").collect(); + /// assert_eq!(x, vec![ + /// B("Mary"), B("had"), B("a"), B("little"), B("lamb"), + /// ]); + /// + /// let x: Vec<&[u8]> = b"".split_str("X").collect(); + /// assert_eq!(x, vec![b""]); + /// + /// let x: Vec<&[u8]> = b"lionXXtigerXleopard".split_str("X").collect(); + /// assert_eq!(x, vec![B("lion"), B(""), B("tiger"), B("leopard")]); + /// + /// let x: Vec<&[u8]> = b"lion::tiger::leopard".split_str("::").collect(); + /// assert_eq!(x, vec![B("lion"), B("tiger"), B("leopard")]); + /// ``` + /// + /// If a string contains multiple contiguous separators, you will end up + /// with empty strings yielded by the iterator: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let x: Vec<&[u8]> = b"||||a||b|c".split_str("|").collect(); + /// assert_eq!(x, vec![ + /// B(""), B(""), B(""), B(""), B("a"), B(""), B("b"), B("c"), + /// ]); + /// + /// let x: Vec<&[u8]> = b"(///)".split_str("/").collect(); + /// assert_eq!(x, vec![B("("), B(""), B(""), B(")")]); + /// ``` + /// + /// Separators at the start or end of a string are neighbored by empty + /// strings. + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let x: Vec<&[u8]> = b"010".split_str("0").collect(); + /// assert_eq!(x, vec![B(""), B("1"), B("")]); + /// ``` + /// + /// When the empty string is used as a separator, it splits every **byte** + /// in the byte string, along with the beginning and end of the byte + /// string. + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let x: Vec<&[u8]> = b"rust".split_str("").collect(); + /// assert_eq!(x, vec![ + /// B(""), B("r"), B("u"), B("s"), B("t"), B(""), + /// ]); + /// + /// // Splitting by an empty string is not UTF-8 aware. Elements yielded + /// // may not be valid UTF-8! + /// let x: Vec<&[u8]> = B("☃").split_str("").collect(); + /// assert_eq!(x, vec![ + /// B(""), B(b"\xE2"), B(b"\x98"), B(b"\x83"), B(""), + /// ]); + /// ``` + /// + /// Contiguous separators, especially whitespace, can lead to possibly + /// surprising behavior. For example, this code is correct: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let x: Vec<&[u8]> = b" a b c".split_str(" ").collect(); + /// assert_eq!(x, vec![ + /// B(""), B(""), B(""), B(""), B("a"), B(""), B("b"), B("c"), + /// ]); + /// ``` + /// + /// It does *not* give you `["a", "b", "c"]`. For that behavior, use + /// [`fields`](#method.fields) instead. + #[inline] + fn split_str<'a, B: ?Sized + AsRef<[u8]>>( + &'a self, + splitter: &'a B, + ) -> Split<'a> { + Split::new(self.as_bytes(), splitter.as_ref()) + } + + /// Returns an iterator over substrings of this byte string, separated by + /// the given byte string, in reverse. Each element yielded is guaranteed + /// not to include the splitter substring. + /// + /// The splitter may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let x: Vec<&[u8]> = + /// b"Mary had a little lamb".rsplit_str(" ").collect(); + /// assert_eq!(x, vec![ + /// B("lamb"), B("little"), B("a"), B("had"), B("Mary"), + /// ]); + /// + /// let x: Vec<&[u8]> = b"".rsplit_str("X").collect(); + /// assert_eq!(x, vec![b""]); + /// + /// let x: Vec<&[u8]> = b"lionXXtigerXleopard".rsplit_str("X").collect(); + /// assert_eq!(x, vec![B("leopard"), B("tiger"), B(""), B("lion")]); + /// + /// let x: Vec<&[u8]> = b"lion::tiger::leopard".rsplit_str("::").collect(); + /// assert_eq!(x, vec![B("leopard"), B("tiger"), B("lion")]); + /// ``` + /// + /// If a string contains multiple contiguous separators, you will end up + /// with empty strings yielded by the iterator: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let x: Vec<&[u8]> = b"||||a||b|c".rsplit_str("|").collect(); + /// assert_eq!(x, vec![ + /// B("c"), B("b"), B(""), B("a"), B(""), B(""), B(""), B(""), + /// ]); + /// + /// let x: Vec<&[u8]> = b"(///)".rsplit_str("/").collect(); + /// assert_eq!(x, vec![B(")"), B(""), B(""), B("(")]); + /// ``` + /// + /// Separators at the start or end of a string are neighbored by empty + /// strings. + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let x: Vec<&[u8]> = b"010".rsplit_str("0").collect(); + /// assert_eq!(x, vec![B(""), B("1"), B("")]); + /// ``` + /// + /// When the empty string is used as a separator, it splits every **byte** + /// in the byte string, along with the beginning and end of the byte + /// string. + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let x: Vec<&[u8]> = b"rust".rsplit_str("").collect(); + /// assert_eq!(x, vec![ + /// B(""), B("t"), B("s"), B("u"), B("r"), B(""), + /// ]); + /// + /// // Splitting by an empty string is not UTF-8 aware. Elements yielded + /// // may not be valid UTF-8! + /// let x: Vec<&[u8]> = B("☃").rsplit_str("").collect(); + /// assert_eq!(x, vec![B(""), B(b"\x83"), B(b"\x98"), B(b"\xE2"), B("")]); + /// ``` + /// + /// Contiguous separators, especially whitespace, can lead to possibly + /// surprising behavior. For example, this code is correct: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let x: Vec<&[u8]> = b" a b c".rsplit_str(" ").collect(); + /// assert_eq!(x, vec![ + /// B("c"), B("b"), B(""), B("a"), B(""), B(""), B(""), B(""), + /// ]); + /// ``` + /// + /// It does *not* give you `["a", "b", "c"]`. + #[inline] + fn rsplit_str<'a, B: ?Sized + AsRef<[u8]>>( + &'a self, + splitter: &'a B, + ) -> SplitReverse<'a> { + SplitReverse::new(self.as_bytes(), splitter.as_ref()) + } + + /// Returns an iterator of at most `limit` substrings of this byte string, + /// separated by the given byte string. If `limit` substrings are yielded, + /// then the last substring will contain the remainder of this byte string. + /// + /// The needle may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let x: Vec<_> = b"Mary had a little lamb".splitn_str(3, " ").collect(); + /// assert_eq!(x, vec![B("Mary"), B("had"), B("a little lamb")]); + /// + /// let x: Vec<_> = b"".splitn_str(3, "X").collect(); + /// assert_eq!(x, vec![b""]); + /// + /// let x: Vec<_> = b"lionXXtigerXleopard".splitn_str(3, "X").collect(); + /// assert_eq!(x, vec![B("lion"), B(""), B("tigerXleopard")]); + /// + /// let x: Vec<_> = b"lion::tiger::leopard".splitn_str(2, "::").collect(); + /// assert_eq!(x, vec![B("lion"), B("tiger::leopard")]); + /// + /// let x: Vec<_> = b"abcXdef".splitn_str(1, "X").collect(); + /// assert_eq!(x, vec![B("abcXdef")]); + /// + /// let x: Vec<_> = b"abcdef".splitn_str(2, "X").collect(); + /// assert_eq!(x, vec![B("abcdef")]); + /// + /// let x: Vec<_> = b"abcXdef".splitn_str(0, "X").collect(); + /// assert!(x.is_empty()); + /// ``` + #[inline] + fn splitn_str<'a, B: ?Sized + AsRef<[u8]>>( + &'a self, + limit: usize, + splitter: &'a B, + ) -> SplitN<'a> { + SplitN::new(self.as_bytes(), splitter.as_ref(), limit) + } + + /// Returns an iterator of at most `limit` substrings of this byte string, + /// separated by the given byte string, in reverse. If `limit` substrings + /// are yielded, then the last substring will contain the remainder of this + /// byte string. + /// + /// The needle may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let x: Vec<_> = + /// b"Mary had a little lamb".rsplitn_str(3, " ").collect(); + /// assert_eq!(x, vec![B("lamb"), B("little"), B("Mary had a")]); + /// + /// let x: Vec<_> = b"".rsplitn_str(3, "X").collect(); + /// assert_eq!(x, vec![b""]); + /// + /// let x: Vec<_> = b"lionXXtigerXleopard".rsplitn_str(3, "X").collect(); + /// assert_eq!(x, vec![B("leopard"), B("tiger"), B("lionX")]); + /// + /// let x: Vec<_> = b"lion::tiger::leopard".rsplitn_str(2, "::").collect(); + /// assert_eq!(x, vec![B("leopard"), B("lion::tiger")]); + /// + /// let x: Vec<_> = b"abcXdef".rsplitn_str(1, "X").collect(); + /// assert_eq!(x, vec![B("abcXdef")]); + /// + /// let x: Vec<_> = b"abcdef".rsplitn_str(2, "X").collect(); + /// assert_eq!(x, vec![B("abcdef")]); + /// + /// let x: Vec<_> = b"abcXdef".rsplitn_str(0, "X").collect(); + /// assert!(x.is_empty()); + /// ``` + #[inline] + fn rsplitn_str<'a, B: ?Sized + AsRef<[u8]>>( + &'a self, + limit: usize, + splitter: &'a B, + ) -> SplitNReverse<'a> { + SplitNReverse::new(self.as_bytes(), splitter.as_ref(), limit) + } + + /// Replace all matches of the given needle with the given replacement, and + /// the result as a new `Vec`. + /// + /// This routine is useful as a convenience. If you need to reuse an + /// allocation, use [`replace_into`](#method.replace_into) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"this is old".replace("old", "new"); + /// assert_eq!(s, "this is new".as_bytes()); + /// ``` + /// + /// When the pattern doesn't match: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"this is old".replace("nada nada", "limonada"); + /// assert_eq!(s, "this is old".as_bytes()); + /// ``` + /// + /// When the needle is an empty string: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"foo".replace("", "Z"); + /// assert_eq!(s, "ZfZoZoZ".as_bytes()); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn replace, R: AsRef<[u8]>>( + &self, + needle: N, + replacement: R, + ) -> Vec { + let mut dest = Vec::with_capacity(self.as_bytes().len()); + self.replace_into(needle, replacement, &mut dest); + dest + } + + /// Replace up to `limit` matches of the given needle with the given + /// replacement, and the result as a new `Vec`. + /// + /// This routine is useful as a convenience. If you need to reuse an + /// allocation, use [`replacen_into`](#method.replacen_into) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"foofoo".replacen("o", "z", 2); + /// assert_eq!(s, "fzzfoo".as_bytes()); + /// ``` + /// + /// When the pattern doesn't match: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"foofoo".replacen("a", "z", 2); + /// assert_eq!(s, "foofoo".as_bytes()); + /// ``` + /// + /// When the needle is an empty string: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"foo".replacen("", "Z", 2); + /// assert_eq!(s, "ZfZoo".as_bytes()); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn replacen, R: AsRef<[u8]>>( + &self, + needle: N, + replacement: R, + limit: usize, + ) -> Vec { + let mut dest = Vec::with_capacity(self.as_bytes().len()); + self.replacen_into(needle, replacement, limit, &mut dest); + dest + } + + /// Replace all matches of the given needle with the given replacement, + /// and write the result into the provided `Vec`. + /// + /// This does **not** clear `dest` before writing to it. + /// + /// This routine is useful for reusing allocation. For a more convenient + /// API, use [`replace`](#method.replace) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"this is old"; + /// + /// let mut dest = vec![]; + /// s.replace_into("old", "new", &mut dest); + /// assert_eq!(dest, "this is new".as_bytes()); + /// ``` + /// + /// When the pattern doesn't match: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"this is old"; + /// + /// let mut dest = vec![]; + /// s.replace_into("nada nada", "limonada", &mut dest); + /// assert_eq!(dest, "this is old".as_bytes()); + /// ``` + /// + /// When the needle is an empty string: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"foo"; + /// + /// let mut dest = vec![]; + /// s.replace_into("", "Z", &mut dest); + /// assert_eq!(dest, "ZfZoZoZ".as_bytes()); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn replace_into, R: AsRef<[u8]>>( + &self, + needle: N, + replacement: R, + dest: &mut Vec, + ) { + let (needle, replacement) = (needle.as_ref(), replacement.as_ref()); + + let mut last = 0; + for start in self.find_iter(needle) { + dest.push_str(&self.as_bytes()[last..start]); + dest.push_str(replacement); + last = start + needle.len(); + } + dest.push_str(&self.as_bytes()[last..]); + } + + /// Replace up to `limit` matches of the given needle with the given + /// replacement, and write the result into the provided `Vec`. + /// + /// This does **not** clear `dest` before writing to it. + /// + /// This routine is useful for reusing allocation. For a more convenient + /// API, use [`replacen`](#method.replacen) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"foofoo"; + /// + /// let mut dest = vec![]; + /// s.replacen_into("o", "z", 2, &mut dest); + /// assert_eq!(dest, "fzzfoo".as_bytes()); + /// ``` + /// + /// When the pattern doesn't match: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"foofoo"; + /// + /// let mut dest = vec![]; + /// s.replacen_into("a", "z", 2, &mut dest); + /// assert_eq!(dest, "foofoo".as_bytes()); + /// ``` + /// + /// When the needle is an empty string: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"foo"; + /// + /// let mut dest = vec![]; + /// s.replacen_into("", "Z", 2, &mut dest); + /// assert_eq!(dest, "ZfZoo".as_bytes()); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn replacen_into, R: AsRef<[u8]>>( + &self, + needle: N, + replacement: R, + limit: usize, + dest: &mut Vec, + ) { + let (needle, replacement) = (needle.as_ref(), replacement.as_ref()); + + let mut last = 0; + for start in self.find_iter(needle).take(limit) { + dest.push_str(&self.as_bytes()[last..start]); + dest.push_str(replacement); + last = start + needle.len(); + } + dest.push_str(&self.as_bytes()[last..]); + } + + /// Returns an iterator over the bytes in this byte string. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = b"foobar"; + /// let bytes: Vec = bs.bytes().collect(); + /// assert_eq!(bytes, bs); + /// ``` + #[inline] + fn bytes(&self) -> Bytes<'_> { + Bytes { it: self.as_bytes().iter() } + } + + /// Returns an iterator over the Unicode scalar values in this byte string. + /// If invalid UTF-8 is encountered, then the Unicode replacement codepoint + /// is yielded instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"; + /// let chars: Vec = bs.chars().collect(); + /// assert_eq!(vec!['☃', '\u{FFFD}', 'ðžƒ', '\u{FFFD}', 'a'], chars); + /// ``` + /// + /// Codepoints can also be iterated over in reverse: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"; + /// let chars: Vec = bs.chars().rev().collect(); + /// assert_eq!(vec!['a', '\u{FFFD}', 'ðžƒ', '\u{FFFD}', '☃'], chars); + /// ``` + #[inline] + fn chars(&self) -> Chars<'_> { + Chars::new(self.as_bytes()) + } + + /// Returns an iterator over the Unicode scalar values in this byte string + /// along with their starting and ending byte index positions. If invalid + /// UTF-8 is encountered, then the Unicode replacement codepoint is yielded + /// instead. + /// + /// Note that this is slightly different from the `CharIndices` iterator + /// provided by the standard library. Aside from working on possibly + /// invalid UTF-8, this iterator provides both the corresponding starting + /// and ending byte indices of each codepoint yielded. The ending position + /// is necessary to slice the original byte string when invalid UTF-8 bytes + /// are converted into a Unicode replacement codepoint, since a single + /// replacement codepoint can substitute anywhere from 1 to 3 invalid bytes + /// (inclusive). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"; + /// let chars: Vec<(usize, usize, char)> = bs.char_indices().collect(); + /// assert_eq!(chars, vec![ + /// (0, 3, '☃'), + /// (3, 4, '\u{FFFD}'), + /// (4, 8, 'ðžƒ'), + /// (8, 10, '\u{FFFD}'), + /// (10, 11, 'a'), + /// ]); + /// ``` + /// + /// Codepoints can also be iterated over in reverse: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"; + /// let chars: Vec<(usize, usize, char)> = bs + /// .char_indices() + /// .rev() + /// .collect(); + /// assert_eq!(chars, vec![ + /// (10, 11, 'a'), + /// (8, 10, '\u{FFFD}'), + /// (4, 8, 'ðžƒ'), + /// (3, 4, '\u{FFFD}'), + /// (0, 3, '☃'), + /// ]); + /// ``` + #[inline] + fn char_indices(&self) -> CharIndices<'_> { + CharIndices::new(self.as_bytes()) + } + + /// Iterate over chunks of valid UTF-8. + /// + /// The iterator returned yields chunks of valid UTF-8 separated by invalid + /// UTF-8 bytes, if they exist. Invalid UTF-8 bytes are always 1-3 bytes, + /// which are determined via the "substitution of maximal subparts" + /// strategy described in the docs for the + /// [`ByteSlice::to_str_lossy`](trait.ByteSlice.html#method.to_str_lossy) + /// method. + /// + /// # Examples + /// + /// This example shows how to gather all valid and invalid chunks from a + /// byte slice: + /// + /// ``` + /// use bstr::{ByteSlice, Utf8Chunk}; + /// + /// let bytes = b"foo\xFD\xFEbar\xFF"; + /// + /// let (mut valid_chunks, mut invalid_chunks) = (vec![], vec![]); + /// for chunk in bytes.utf8_chunks() { + /// if !chunk.valid().is_empty() { + /// valid_chunks.push(chunk.valid()); + /// } + /// if !chunk.invalid().is_empty() { + /// invalid_chunks.push(chunk.invalid()); + /// } + /// } + /// + /// assert_eq!(valid_chunks, vec!["foo", "bar"]); + /// assert_eq!(invalid_chunks, vec![b"\xFD", b"\xFE", b"\xFF"]); + /// ``` + #[inline] + fn utf8_chunks(&self) -> Utf8Chunks<'_> { + Utf8Chunks { bytes: self.as_bytes() } + } + + /// Returns an iterator over the grapheme clusters in this byte string. + /// If invalid UTF-8 is encountered, then the Unicode replacement codepoint + /// is yielded instead. + /// + /// # Examples + /// + /// This example shows how multiple codepoints can combine to form a + /// single grapheme cluster: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = "a\u{0300}\u{0316}\u{1F1FA}\u{1F1F8}".as_bytes(); + /// let graphemes: Vec<&str> = bs.graphemes().collect(); + /// assert_eq!(vec!["à̖", "🇺🇸"], graphemes); + /// ``` + /// + /// This shows that graphemes can be iterated over in reverse: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = "a\u{0300}\u{0316}\u{1F1FA}\u{1F1F8}".as_bytes(); + /// let graphemes: Vec<&str> = bs.graphemes().rev().collect(); + /// assert_eq!(vec!["🇺🇸", "à̖"], graphemes); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + fn graphemes(&self) -> Graphemes<'_> { + Graphemes::new(self.as_bytes()) + } + + /// Returns an iterator over the grapheme clusters in this byte string + /// along with their starting and ending byte index positions. If invalid + /// UTF-8 is encountered, then the Unicode replacement codepoint is yielded + /// instead. + /// + /// # Examples + /// + /// This example shows how to get the byte offsets of each individual + /// grapheme cluster: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = "a\u{0300}\u{0316}\u{1F1FA}\u{1F1F8}".as_bytes(); + /// let graphemes: Vec<(usize, usize, &str)> = + /// bs.grapheme_indices().collect(); + /// assert_eq!(vec![(0, 5, "à̖"), (5, 13, "🇺🇸")], graphemes); + /// ``` + /// + /// This example shows what happens when invalid UTF-8 is enountered. Note + /// that the offsets are valid indices into the original string, and do + /// not necessarily correspond to the length of the `&str` returned! + /// + /// ``` + /// use bstr::{ByteSlice, ByteVec}; + /// + /// let mut bytes = vec![]; + /// bytes.push_str("a\u{0300}\u{0316}"); + /// bytes.push(b'\xFF'); + /// bytes.push_str("\u{1F1FA}\u{1F1F8}"); + /// + /// let graphemes: Vec<(usize, usize, &str)> = + /// bytes.grapheme_indices().collect(); + /// assert_eq!( + /// graphemes, + /// vec![(0, 5, "à̖"), (5, 6, "\u{FFFD}"), (6, 14, "🇺🇸")] + /// ); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + fn grapheme_indices(&self) -> GraphemeIndices<'_> { + GraphemeIndices::new(self.as_bytes()) + } + + /// Returns an iterator over the words in this byte string. If invalid + /// UTF-8 is encountered, then the Unicode replacement codepoint is yielded + /// instead. + /// + /// This is similar to + /// [`words_with_breaks`](trait.ByteSlice.html#method.words_with_breaks), + /// except it only returns elements that contain a "word" character. A word + /// character is defined by UTS #18 (Annex C) to be the combination of the + /// `Alphabetic` and `Join_Control` properties, along with the + /// `Decimal_Number`, `Mark` and `Connector_Punctuation` general + /// categories. + /// + /// Since words are made up of one or more codepoints, this iterator + /// yields `&str` elements. When invalid UTF-8 is encountered, replacement + /// codepoints are [substituted](index.html#handling-of-invalid-utf-8). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = br#"The quick ("brown") fox can't jump 32.3 feet, right?"#; + /// let words: Vec<&str> = bs.words().collect(); + /// assert_eq!(words, vec![ + /// "The", "quick", "brown", "fox", "can't", + /// "jump", "32.3", "feet", "right", + /// ]); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + fn words(&self) -> Words<'_> { + Words::new(self.as_bytes()) + } + + /// Returns an iterator over the words in this byte string along with + /// their starting and ending byte index positions. + /// + /// This is similar to + /// [`words_with_break_indices`](trait.ByteSlice.html#method.words_with_break_indices), + /// except it only returns elements that contain a "word" character. A word + /// character is defined by UTS #18 (Annex C) to be the combination of the + /// `Alphabetic` and `Join_Control` properties, along with the + /// `Decimal_Number`, `Mark` and `Connector_Punctuation` general + /// categories. + /// + /// Since words are made up of one or more codepoints, this iterator + /// yields `&str` elements. When invalid UTF-8 is encountered, replacement + /// codepoints are [substituted](index.html#handling-of-invalid-utf-8). + /// + /// # Examples + /// + /// This example shows how to get the byte offsets of each individual + /// word: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = b"can't jump 32.3 feet"; + /// let words: Vec<(usize, usize, &str)> = bs.word_indices().collect(); + /// assert_eq!(words, vec![ + /// (0, 5, "can't"), + /// (6, 10, "jump"), + /// (11, 15, "32.3"), + /// (16, 20, "feet"), + /// ]); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + fn word_indices(&self) -> WordIndices<'_> { + WordIndices::new(self.as_bytes()) + } + + /// Returns an iterator over the words in this byte string, along with + /// all breaks between the words. Concatenating all elements yielded by + /// the iterator results in the original string (modulo Unicode replacement + /// codepoint substitutions if invalid UTF-8 is encountered). + /// + /// Since words are made up of one or more codepoints, this iterator + /// yields `&str` elements. When invalid UTF-8 is encountered, replacement + /// codepoints are [substituted](index.html#handling-of-invalid-utf-8). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = br#"The quick ("brown") fox can't jump 32.3 feet, right?"#; + /// let words: Vec<&str> = bs.words_with_breaks().collect(); + /// assert_eq!(words, vec![ + /// "The", " ", "quick", " ", "(", "\"", "brown", "\"", ")", + /// " ", "fox", " ", "can't", " ", "jump", " ", "32.3", " ", "feet", + /// ",", " ", "right", "?", + /// ]); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + fn words_with_breaks(&self) -> WordsWithBreaks<'_> { + WordsWithBreaks::new(self.as_bytes()) + } + + /// Returns an iterator over the words and their byte offsets in this + /// byte string, along with all breaks between the words. Concatenating + /// all elements yielded by the iterator results in the original string + /// (modulo Unicode replacement codepoint substitutions if invalid UTF-8 is + /// encountered). + /// + /// Since words are made up of one or more codepoints, this iterator + /// yields `&str` elements. When invalid UTF-8 is encountered, replacement + /// codepoints are [substituted](index.html#handling-of-invalid-utf-8). + /// + /// # Examples + /// + /// This example shows how to get the byte offsets of each individual + /// word: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = b"can't jump 32.3 feet"; + /// let words: Vec<(usize, usize, &str)> = + /// bs.words_with_break_indices().collect(); + /// assert_eq!(words, vec![ + /// (0, 5, "can't"), + /// (5, 6, " "), + /// (6, 10, "jump"), + /// (10, 11, " "), + /// (11, 15, "32.3"), + /// (15, 16, " "), + /// (16, 20, "feet"), + /// ]); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + fn words_with_break_indices(&self) -> WordsWithBreakIndices<'_> { + WordsWithBreakIndices::new(self.as_bytes()) + } + + /// Returns an iterator over the sentences in this byte string. + /// + /// Typically, a sentence will include its trailing punctuation and + /// whitespace. Concatenating all elements yielded by the iterator + /// results in the original string (modulo Unicode replacement codepoint + /// substitutions if invalid UTF-8 is encountered). + /// + /// Since sentences are made up of one or more codepoints, this iterator + /// yields `&str` elements. When invalid UTF-8 is encountered, replacement + /// codepoints are [substituted](index.html#handling-of-invalid-utf-8). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = b"I want this. Not that. Right now."; + /// let sentences: Vec<&str> = bs.sentences().collect(); + /// assert_eq!(sentences, vec![ + /// "I want this. ", + /// "Not that. ", + /// "Right now.", + /// ]); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + fn sentences(&self) -> Sentences<'_> { + Sentences::new(self.as_bytes()) + } + + /// Returns an iterator over the sentences in this byte string along with + /// their starting and ending byte index positions. + /// + /// Typically, a sentence will include its trailing punctuation and + /// whitespace. Concatenating all elements yielded by the iterator + /// results in the original string (modulo Unicode replacement codepoint + /// substitutions if invalid UTF-8 is encountered). + /// + /// Since sentences are made up of one or more codepoints, this iterator + /// yields `&str` elements. When invalid UTF-8 is encountered, replacement + /// codepoints are [substituted](index.html#handling-of-invalid-utf-8). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let bs = b"I want this. Not that. Right now."; + /// let sentences: Vec<(usize, usize, &str)> = + /// bs.sentence_indices().collect(); + /// assert_eq!(sentences, vec![ + /// (0, 13, "I want this. "), + /// (13, 23, "Not that. "), + /// (23, 33, "Right now."), + /// ]); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + fn sentence_indices(&self) -> SentenceIndices<'_> { + SentenceIndices::new(self.as_bytes()) + } + + /// An iterator over all lines in a byte string, without their + /// terminators. + /// + /// For this iterator, the only line terminators recognized are `\r\n` and + /// `\n`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = b"\ + /// foo + /// + /// bar\r + /// baz + /// + /// + /// quux"; + /// let lines: Vec<&[u8]> = s.lines().collect(); + /// assert_eq!(lines, vec![ + /// B("foo"), B(""), B("bar"), B("baz"), B(""), B(""), B("quux"), + /// ]); + /// ``` + #[inline] + fn lines(&self) -> Lines<'_> { + Lines::new(self.as_bytes()) + } + + /// An iterator over all lines in a byte string, including their + /// terminators. + /// + /// For this iterator, the only line terminator recognized is `\n`. (Since + /// line terminators are included, this also handles `\r\n` line endings.) + /// + /// Line terminators are only included if they are present in the original + /// byte string. For example, the last line in a byte string may not end + /// with a line terminator. + /// + /// Concatenating all elements yielded by this iterator is guaranteed to + /// yield the original byte string. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = b"\ + /// foo + /// + /// bar\r + /// baz + /// + /// + /// quux"; + /// let lines: Vec<&[u8]> = s.lines_with_terminator().collect(); + /// assert_eq!(lines, vec![ + /// B("foo\n"), + /// B("\n"), + /// B("bar\r\n"), + /// B("baz\n"), + /// B("\n"), + /// B("\n"), + /// B("quux"), + /// ]); + /// ``` + #[inline] + fn lines_with_terminator(&self) -> LinesWithTerminator<'_> { + LinesWithTerminator::new(self.as_bytes()) + } + + /// Return a byte string slice with leading and trailing whitespace + /// removed. + /// + /// Whitespace is defined according to the terms of the `White_Space` + /// Unicode property. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B(" foo\tbar\t\u{2003}\n"); + /// assert_eq!(s.trim(), B("foo\tbar")); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + fn trim(&self) -> &[u8] { + self.trim_start().trim_end() + } + + /// Return a byte string slice with leading whitespace removed. + /// + /// Whitespace is defined according to the terms of the `White_Space` + /// Unicode property. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B(" foo\tbar\t\u{2003}\n"); + /// assert_eq!(s.trim_start(), B("foo\tbar\t\u{2003}\n")); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + fn trim_start(&self) -> &[u8] { + let start = whitespace_len_fwd(self.as_bytes()); + &self.as_bytes()[start..] + } + + /// Return a byte string slice with trailing whitespace removed. + /// + /// Whitespace is defined according to the terms of the `White_Space` + /// Unicode property. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B(" foo\tbar\t\u{2003}\n"); + /// assert_eq!(s.trim_end(), B(" foo\tbar")); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + fn trim_end(&self) -> &[u8] { + let end = whitespace_len_rev(self.as_bytes()); + &self.as_bytes()[..end] + } + + /// Return a byte string slice with leading and trailing characters + /// satisfying the given predicate removed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = b"123foo5bar789"; + /// assert_eq!(s.trim_with(|c| c.is_numeric()), B("foo5bar")); + /// ``` + #[inline] + fn trim_with bool>(&self, mut trim: F) -> &[u8] { + self.trim_start_with(&mut trim).trim_end_with(&mut trim) + } + + /// Return a byte string slice with leading characters satisfying the given + /// predicate removed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = b"123foo5bar789"; + /// assert_eq!(s.trim_start_with(|c| c.is_numeric()), B("foo5bar789")); + /// ``` + #[inline] + fn trim_start_with bool>(&self, mut trim: F) -> &[u8] { + for (s, _, ch) in self.char_indices() { + if !trim(ch) { + return &self.as_bytes()[s..]; + } + } + b"" + } + + /// Return a byte string slice with trailing characters satisfying the + /// given predicate removed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = b"123foo5bar789"; + /// assert_eq!(s.trim_end_with(|c| c.is_numeric()), B("123foo5bar")); + /// ``` + #[inline] + fn trim_end_with bool>(&self, mut trim: F) -> &[u8] { + for (_, e, ch) in self.char_indices().rev() { + if !trim(ch) { + return &self.as_bytes()[..e]; + } + } + b"" + } + + /// Returns a new `Vec` containing the lowercase equivalent of this + /// byte string. + /// + /// In this case, lowercase is defined according to the `Lowercase` Unicode + /// property. + /// + /// If invalid UTF-8 is seen, or if a character has no lowercase variant, + /// then it is written to the given buffer unchanged. + /// + /// Note that some characters in this byte string may expand into multiple + /// characters when changing the case, so the number of bytes written to + /// the given byte string may not be equivalent to the number of bytes in + /// this byte string. + /// + /// If you'd like to reuse an allocation for performance reasons, then use + /// [`to_lowercase_into`](#method.to_lowercase_into) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B("HELLO Î’"); + /// assert_eq!("hello β".as_bytes(), s.to_lowercase().as_bytes()); + /// ``` + /// + /// Scripts without case are not changed: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B("农历新年"); + /// assert_eq!("农历新年".as_bytes(), s.to_lowercase().as_bytes()); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B(b"FOO\xFFBAR\xE2\x98BAZ"); + /// assert_eq!(B(b"foo\xFFbar\xE2\x98baz"), s.to_lowercase().as_bytes()); + /// ``` + #[cfg(all(feature = "std", feature = "unicode"))] + #[inline] + fn to_lowercase(&self) -> Vec { + let mut buf = vec![]; + self.to_lowercase_into(&mut buf); + buf + } + + /// Writes the lowercase equivalent of this byte string into the given + /// buffer. The buffer is not cleared before written to. + /// + /// In this case, lowercase is defined according to the `Lowercase` + /// Unicode property. + /// + /// If invalid UTF-8 is seen, or if a character has no lowercase variant, + /// then it is written to the given buffer unchanged. + /// + /// Note that some characters in this byte string may expand into multiple + /// characters when changing the case, so the number of bytes written to + /// the given byte string may not be equivalent to the number of bytes in + /// this byte string. + /// + /// If you don't need to amortize allocation and instead prefer + /// convenience, then use [`to_lowercase`](#method.to_lowercase) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B("HELLO Î’"); + /// + /// let mut buf = vec![]; + /// s.to_lowercase_into(&mut buf); + /// assert_eq!("hello β".as_bytes(), buf.as_bytes()); + /// ``` + /// + /// Scripts without case are not changed: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B("农历新年"); + /// + /// let mut buf = vec![]; + /// s.to_lowercase_into(&mut buf); + /// assert_eq!("农历新年".as_bytes(), buf.as_bytes()); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B(b"FOO\xFFBAR\xE2\x98BAZ"); + /// + /// let mut buf = vec![]; + /// s.to_lowercase_into(&mut buf); + /// assert_eq!(B(b"foo\xFFbar\xE2\x98baz"), buf.as_bytes()); + /// ``` + #[cfg(all(feature = "std", feature = "unicode"))] + #[inline] + fn to_lowercase_into(&self, buf: &mut Vec) { + // TODO: This is the best we can do given what std exposes I think. + // If we roll our own case handling, then we might be able to do this + // a bit faster. We shouldn't roll our own case handling unless we + // need to, e.g., for doing caseless matching or case folding. + + // TODO(BUG): This doesn't handle any special casing rules. + + buf.reserve(self.as_bytes().len()); + for (s, e, ch) in self.char_indices() { + if ch == '\u{FFFD}' { + buf.push_str(&self.as_bytes()[s..e]); + } else if ch.is_ascii() { + buf.push_char(ch.to_ascii_lowercase()); + } else { + for upper in ch.to_lowercase() { + buf.push_char(upper); + } + } + } + } + + /// Returns a new `Vec` containing the ASCII lowercase equivalent of + /// this byte string. + /// + /// In this case, lowercase is only defined in ASCII letters. Namely, the + /// letters `A-Z` are converted to `a-z`. All other bytes remain unchanged. + /// In particular, the length of the byte string returned is always + /// equivalent to the length of this byte string. + /// + /// If you'd like to reuse an allocation for performance reasons, then use + /// [`make_ascii_lowercase`](#method.make_ascii_lowercase) to perform + /// the conversion in place. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B("HELLO Î’"); + /// assert_eq!("hello Î’".as_bytes(), s.to_ascii_lowercase().as_bytes()); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B(b"FOO\xFFBAR\xE2\x98BAZ"); + /// assert_eq!(s.to_ascii_lowercase(), B(b"foo\xFFbar\xE2\x98baz")); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn to_ascii_lowercase(&self) -> Vec { + self.as_bytes().to_ascii_lowercase() + } + + /// Convert this byte string to its lowercase ASCII equivalent in place. + /// + /// In this case, lowercase is only defined in ASCII letters. Namely, the + /// letters `A-Z` are converted to `a-z`. All other bytes remain unchanged. + /// + /// If you don't need to do the conversion in + /// place and instead prefer convenience, then use + /// [`to_ascii_lowercase`](#method.to_ascii_lowercase) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut s = >::from("HELLO Î’"); + /// s.make_ascii_lowercase(); + /// assert_eq!(s, "hello Î’".as_bytes()); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, ByteSlice, ByteVec}; + /// + /// let mut s = >::from_slice(b"FOO\xFFBAR\xE2\x98BAZ"); + /// s.make_ascii_lowercase(); + /// assert_eq!(s, B(b"foo\xFFbar\xE2\x98baz")); + /// ``` + #[inline] + fn make_ascii_lowercase(&mut self) { + self.as_bytes_mut().make_ascii_lowercase(); + } + + /// Returns a new `Vec` containing the uppercase equivalent of this + /// byte string. + /// + /// In this case, uppercase is defined according to the `Uppercase` + /// Unicode property. + /// + /// If invalid UTF-8 is seen, or if a character has no uppercase variant, + /// then it is written to the given buffer unchanged. + /// + /// Note that some characters in this byte string may expand into multiple + /// characters when changing the case, so the number of bytes written to + /// the given byte string may not be equivalent to the number of bytes in + /// this byte string. + /// + /// If you'd like to reuse an allocation for performance reasons, then use + /// [`to_uppercase_into`](#method.to_uppercase_into) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B("hello β"); + /// assert_eq!(s.to_uppercase(), B("HELLO Î’")); + /// ``` + /// + /// Scripts without case are not changed: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B("农历新年"); + /// assert_eq!(s.to_uppercase(), B("农历新年")); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B(b"foo\xFFbar\xE2\x98baz"); + /// assert_eq!(s.to_uppercase(), B(b"FOO\xFFBAR\xE2\x98BAZ")); + /// ``` + #[cfg(all(feature = "std", feature = "unicode"))] + #[inline] + fn to_uppercase(&self) -> Vec { + let mut buf = vec![]; + self.to_uppercase_into(&mut buf); + buf + } + + /// Writes the uppercase equivalent of this byte string into the given + /// buffer. The buffer is not cleared before written to. + /// + /// In this case, uppercase is defined according to the `Uppercase` + /// Unicode property. + /// + /// If invalid UTF-8 is seen, or if a character has no uppercase variant, + /// then it is written to the given buffer unchanged. + /// + /// Note that some characters in this byte string may expand into multiple + /// characters when changing the case, so the number of bytes written to + /// the given byte string may not be equivalent to the number of bytes in + /// this byte string. + /// + /// If you don't need to amortize allocation and instead prefer + /// convenience, then use [`to_uppercase`](#method.to_uppercase) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B("hello β"); + /// + /// let mut buf = vec![]; + /// s.to_uppercase_into(&mut buf); + /// assert_eq!(buf, B("HELLO Î’")); + /// ``` + /// + /// Scripts without case are not changed: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B("农历新年"); + /// + /// let mut buf = vec![]; + /// s.to_uppercase_into(&mut buf); + /// assert_eq!(buf, B("农历新年")); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B(b"foo\xFFbar\xE2\x98baz"); + /// + /// let mut buf = vec![]; + /// s.to_uppercase_into(&mut buf); + /// assert_eq!(buf, B(b"FOO\xFFBAR\xE2\x98BAZ")); + /// ``` + #[cfg(all(feature = "std", feature = "unicode"))] + #[inline] + fn to_uppercase_into(&self, buf: &mut Vec) { + // TODO: This is the best we can do given what std exposes I think. + // If we roll our own case handling, then we might be able to do this + // a bit faster. We shouldn't roll our own case handling unless we + // need to, e.g., for doing caseless matching or case folding. + buf.reserve(self.as_bytes().len()); + for (s, e, ch) in self.char_indices() { + if ch == '\u{FFFD}' { + buf.push_str(&self.as_bytes()[s..e]); + } else if ch.is_ascii() { + buf.push_char(ch.to_ascii_uppercase()); + } else { + for upper in ch.to_uppercase() { + buf.push_char(upper); + } + } + } + } + + /// Returns a new `Vec` containing the ASCII uppercase equivalent of + /// this byte string. + /// + /// In this case, uppercase is only defined in ASCII letters. Namely, the + /// letters `a-z` are converted to `A-Z`. All other bytes remain unchanged. + /// In particular, the length of the byte string returned is always + /// equivalent to the length of this byte string. + /// + /// If you'd like to reuse an allocation for performance reasons, then use + /// [`make_ascii_uppercase`](#method.make_ascii_uppercase) to perform + /// the conversion in place. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B("hello β"); + /// assert_eq!(s.to_ascii_uppercase(), B("HELLO β")); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let s = B(b"foo\xFFbar\xE2\x98baz"); + /// assert_eq!(s.to_ascii_uppercase(), B(b"FOO\xFFBAR\xE2\x98BAZ")); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn to_ascii_uppercase(&self) -> Vec { + self.as_bytes().to_ascii_uppercase() + } + + /// Convert this byte string to its uppercase ASCII equivalent in place. + /// + /// In this case, uppercase is only defined in ASCII letters. Namely, the + /// letters `a-z` are converted to `A-Z`. All other bytes remain unchanged. + /// + /// If you don't need to do the conversion in + /// place and instead prefer convenience, then use + /// [`to_ascii_uppercase`](#method.to_ascii_uppercase) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let mut s = >::from("hello β"); + /// s.make_ascii_uppercase(); + /// assert_eq!(s, B("HELLO β")); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, ByteSlice, ByteVec}; + /// + /// let mut s = >::from_slice(b"foo\xFFbar\xE2\x98baz"); + /// s.make_ascii_uppercase(); + /// assert_eq!(s, B(b"FOO\xFFBAR\xE2\x98BAZ")); + /// ``` + #[inline] + fn make_ascii_uppercase(&mut self) { + self.as_bytes_mut().make_ascii_uppercase(); + } + + /// Reverse the bytes in this string, in place. + /// + /// This is not necessarily a well formed operation! For example, if this + /// byte string contains valid UTF-8 that isn't ASCII, then reversing the + /// string will likely result in invalid UTF-8 and otherwise non-sensical + /// content. + /// + /// Note that this is equivalent to the generic `[u8]::reverse` method. + /// This method is provided to permit callers to explicitly differentiate + /// between reversing bytes, codepoints and graphemes. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut s = >::from("hello"); + /// s.reverse_bytes(); + /// assert_eq!(s, "olleh".as_bytes()); + /// ``` + #[inline] + fn reverse_bytes(&mut self) { + self.as_bytes_mut().reverse(); + } + + /// Reverse the codepoints in this string, in place. + /// + /// If this byte string is valid UTF-8, then its reversal by codepoint + /// is also guaranteed to be valid UTF-8. + /// + /// This operation is equivalent to the following, but without allocating: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut s = >::from("foo☃bar"); + /// + /// let mut chars: Vec = s.chars().collect(); + /// chars.reverse(); + /// + /// let reversed: String = chars.into_iter().collect(); + /// assert_eq!(reversed, "rab☃oof"); + /// ``` + /// + /// Note that this is not necessarily a well formed operation. For example, + /// if this byte string contains grapheme clusters with more than one + /// codepoint, then those grapheme clusters will not necessarily be + /// preserved. If you'd like to preserve grapheme clusters, then use + /// [`reverse_graphemes`](#method.reverse_graphemes) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut s = >::from("foo☃bar"); + /// s.reverse_chars(); + /// assert_eq!(s, "rab☃oof".as_bytes()); + /// ``` + /// + /// This example shows that not all reversals lead to a well formed string. + /// For example, in this case, combining marks are used to put accents over + /// some letters, and those accent marks must appear after the codepoints + /// they modify. + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let mut s = >::from("reÌsumeÌ"); + /// s.reverse_chars(); + /// assert_eq!(s, B(b"\xCC\x81emus\xCC\x81er")); + /// ``` + /// + /// A word of warning: the above example relies on the fact that + /// `reÌsumeÌ` is in decomposed normal form, which means there are separate + /// codepoints for the accents above `e`. If it is instead in composed + /// normal form, then the example works: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let mut s = >::from("résumé"); + /// s.reverse_chars(); + /// assert_eq!(s, B("émusér")); + /// ``` + /// + /// The point here is to be cautious and not assume that just because + /// `reverse_chars` works in one case, that it therefore works in all + /// cases. + #[inline] + fn reverse_chars(&mut self) { + let mut i = 0; + loop { + let (_, size) = utf8::decode(&self.as_bytes()[i..]); + if size == 0 { + break; + } + if size > 1 { + self.as_bytes_mut()[i..i + size].reverse_bytes(); + } + i += size; + } + self.reverse_bytes(); + } + + /// Reverse the graphemes in this string, in place. + /// + /// If this byte string is valid UTF-8, then its reversal by grapheme + /// is also guaranteed to be valid UTF-8. + /// + /// This operation is equivalent to the following, but without allocating: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut s = >::from("foo☃bar"); + /// + /// let mut graphemes: Vec<&str> = s.graphemes().collect(); + /// graphemes.reverse(); + /// + /// let reversed = graphemes.concat(); + /// assert_eq!(reversed, "rab☃oof"); + /// ``` + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut s = >::from("foo☃bar"); + /// s.reverse_graphemes(); + /// assert_eq!(s, "rab☃oof".as_bytes()); + /// ``` + /// + /// This example shows how this correctly handles grapheme clusters, + /// unlike `reverse_chars`. + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut s = >::from("résumé"); + /// s.reverse_graphemes(); + /// assert_eq!(s, "émusér".as_bytes()); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + fn reverse_graphemes(&mut self) { + use crate::unicode::decode_grapheme; + + let mut i = 0; + loop { + let (_, size) = decode_grapheme(&self.as_bytes()[i..]); + if size == 0 { + break; + } + if size > 1 { + self.as_bytes_mut()[i..i + size].reverse_bytes(); + } + i += size; + } + self.reverse_bytes(); + } + + /// Returns true if and only if every byte in this byte string is ASCII. + /// + /// ASCII is an encoding that defines 128 codepoints. A byte corresponds to + /// an ASCII codepoint if and only if it is in the inclusive range + /// `[0, 127]`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// assert!(B("abc").is_ascii()); + /// assert!(!B("☃βツ").is_ascii()); + /// assert!(!B(b"\xFF").is_ascii()); + /// ``` + #[inline] + fn is_ascii(&self) -> bool { + ascii::first_non_ascii_byte(self.as_bytes()) == self.as_bytes().len() + } + + /// Returns true if and only if the entire byte string is valid UTF-8. + /// + /// If you need location information about where a byte string's first + /// invalid UTF-8 byte is, then use the [`to_str`](#method.to_str) method. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// assert!(B("abc").is_utf8()); + /// assert!(B("☃βツ").is_utf8()); + /// // invalid bytes + /// assert!(!B(b"abc\xFF").is_utf8()); + /// // surrogate encoding + /// assert!(!B(b"\xED\xA0\x80").is_utf8()); + /// // incomplete sequence + /// assert!(!B(b"\xF0\x9D\x9Ca").is_utf8()); + /// // overlong sequence + /// assert!(!B(b"\xF0\x82\x82\xAC").is_utf8()); + /// ``` + #[inline] + fn is_utf8(&self) -> bool { + utf8::validate(self.as_bytes()).is_ok() + } + + /// Returns the last byte in this byte string, if it's non-empty. If this + /// byte string is empty, this returns `None`. + /// + /// Note that this is like the generic `[u8]::last`, except this returns + /// the byte by value instead of a reference to the byte. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// assert_eq!(Some(b'z'), b"baz".last_byte()); + /// assert_eq!(None, b"".last_byte()); + /// ``` + #[inline] + fn last_byte(&self) -> Option { + let bytes = self.as_bytes(); + bytes.get(bytes.len().saturating_sub(1)).map(|&b| b) + } + + /// Returns the index of the first non-ASCII byte in this byte string (if + /// any such indices exist). Specifically, it returns the index of the + /// first byte with a value greater than or equal to `0x80`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{ByteSlice, B}; + /// + /// assert_eq!(Some(3), b"abc\xff".find_non_ascii_byte()); + /// assert_eq!(None, b"abcde".find_non_ascii_byte()); + /// assert_eq!(Some(0), B("😀").find_non_ascii_byte()); + /// ``` + #[inline] + fn find_non_ascii_byte(&self) -> Option { + let index = ascii::first_non_ascii_byte(self.as_bytes()); + if index == self.as_bytes().len() { + None + } else { + Some(index) + } + } + + /// Copies elements from one part of the slice to another part of itself, + /// where the parts may be overlapping. + /// + /// `src` is the range within this byte string to copy from, while `dest` + /// is the starting index of the range within this byte string to copy to. + /// The length indicated by `src` must be less than or equal to the number + /// of bytes from `dest` to the end of the byte string. + /// + /// # Panics + /// + /// Panics if either range is out of bounds, or if `src` is too big to fit + /// into `dest`, or if the end of `src` is before the start. + /// + /// # Examples + /// + /// Copying four bytes within a byte string: + /// + /// ``` + /// use bstr::{B, ByteSlice}; + /// + /// let mut buf = *b"Hello, World!"; + /// let s = &mut buf; + /// s.copy_within_str(1..5, 8); + /// assert_eq!(s, B("Hello, Wello!")); + /// ``` + #[inline] + fn copy_within_str(&mut self, src: R, dest: usize) + where + R: ops::RangeBounds, + { + // TODO: Deprecate this once slice::copy_within stabilizes. + let src_start = match src.start_bound() { + ops::Bound::Included(&n) => n, + ops::Bound::Excluded(&n) => { + n.checked_add(1).expect("attempted to index slice beyond max") + } + ops::Bound::Unbounded => 0, + }; + let src_end = match src.end_bound() { + ops::Bound::Included(&n) => { + n.checked_add(1).expect("attempted to index slice beyond max") + } + ops::Bound::Excluded(&n) => n, + ops::Bound::Unbounded => self.as_bytes().len(), + }; + assert!(src_start <= src_end, "src end is before src start"); + assert!(src_end <= self.as_bytes().len(), "src is out of bounds"); + let count = src_end - src_start; + assert!( + dest <= self.as_bytes().len() - count, + "dest is out of bounds", + ); + + // SAFETY: This is safe because we use ptr::copy to handle overlapping + // copies, and is also safe because we've checked all the bounds above. + // Finally, we are only dealing with u8 data, which is Copy, which + // means we can copy without worrying about ownership/destructors. + unsafe { + ptr::copy( + self.as_bytes().get_unchecked(src_start), + self.as_bytes_mut().get_unchecked_mut(dest), + count, + ); + } + } +} + +/// A single substring searcher fixed to a particular needle. +/// +/// The purpose of this type is to permit callers to construct a substring +/// searcher that can be used to search haystacks without the overhead of +/// constructing the searcher in the first place. This is a somewhat niche +/// concern when it's necessary to re-use the same needle to search multiple +/// different haystacks with as little overhead as possible. In general, using +/// [`ByteSlice::find`](trait.ByteSlice.html#method.find) +/// or +/// [`ByteSlice::find_iter`](trait.ByteSlice.html#method.find_iter) +/// is good enough, but `Finder` is useful when you can meaningfully observe +/// searcher construction time in a profile. +/// +/// When the `std` feature is enabled, then this type has an `into_owned` +/// version which permits building a `Finder` that is not connected to the +/// lifetime of its needle. +#[derive(Clone, Debug)] +pub struct Finder<'a>(memmem::Finder<'a>); + +impl<'a> Finder<'a> { + /// Create a new finder for the given needle. + #[inline] + pub fn new>(needle: &'a B) -> Finder<'a> { + Finder(memmem::Finder::new(needle.as_ref())) + } + + /// Convert this finder into its owned variant, such that it no longer + /// borrows the needle. + /// + /// If this is already an owned finder, then this is a no-op. Otherwise, + /// this copies the needle. + /// + /// This is only available when the `std` feature is enabled. + #[cfg(feature = "std")] + #[inline] + pub fn into_owned(self) -> Finder<'static> { + Finder(self.0.into_owned()) + } + + /// Returns the needle that this finder searches for. + /// + /// Note that the lifetime of the needle returned is tied to the lifetime + /// of the finder, and may be shorter than the `'a` lifetime. Namely, a + /// finder's needle can be either borrowed or owned, so the lifetime of the + /// needle returned must necessarily be the shorter of the two. + #[inline] + pub fn needle(&self) -> &[u8] { + self.0.needle() + } + + /// Returns the index of the first occurrence of this needle in the given + /// haystack. + /// + /// The haystack may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::Finder; + /// + /// let haystack = "foo bar baz"; + /// assert_eq!(Some(0), Finder::new("foo").find(haystack)); + /// assert_eq!(Some(4), Finder::new("bar").find(haystack)); + /// assert_eq!(None, Finder::new("quux").find(haystack)); + /// ``` + #[inline] + pub fn find>(&self, haystack: B) -> Option { + self.0.find(haystack.as_ref()) + } +} + +/// A single substring reverse searcher fixed to a particular needle. +/// +/// The purpose of this type is to permit callers to construct a substring +/// searcher that can be used to search haystacks without the overhead of +/// constructing the searcher in the first place. This is a somewhat niche +/// concern when it's necessary to re-use the same needle to search multiple +/// different haystacks with as little overhead as possible. In general, using +/// [`ByteSlice::rfind`](trait.ByteSlice.html#method.rfind) +/// or +/// [`ByteSlice::rfind_iter`](trait.ByteSlice.html#method.rfind_iter) +/// is good enough, but `FinderReverse` is useful when you can meaningfully +/// observe searcher construction time in a profile. +/// +/// When the `std` feature is enabled, then this type has an `into_owned` +/// version which permits building a `FinderReverse` that is not connected to +/// the lifetime of its needle. +#[derive(Clone, Debug)] +pub struct FinderReverse<'a>(memmem::FinderRev<'a>); + +impl<'a> FinderReverse<'a> { + /// Create a new reverse finder for the given needle. + #[inline] + pub fn new>(needle: &'a B) -> FinderReverse<'a> { + FinderReverse(memmem::FinderRev::new(needle.as_ref())) + } + + /// Convert this finder into its owned variant, such that it no longer + /// borrows the needle. + /// + /// If this is already an owned finder, then this is a no-op. Otherwise, + /// this copies the needle. + /// + /// This is only available when the `std` feature is enabled. + #[cfg(feature = "std")] + #[inline] + pub fn into_owned(self) -> FinderReverse<'static> { + FinderReverse(self.0.into_owned()) + } + + /// Returns the needle that this finder searches for. + /// + /// Note that the lifetime of the needle returned is tied to the lifetime + /// of this finder, and may be shorter than the `'a` lifetime. Namely, + /// a finder's needle can be either borrowed or owned, so the lifetime of + /// the needle returned must necessarily be the shorter of the two. + #[inline] + pub fn needle(&self) -> &[u8] { + self.0.needle() + } + + /// Returns the index of the last occurrence of this needle in the given + /// haystack. + /// + /// The haystack may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::FinderReverse; + /// + /// let haystack = "foo bar baz"; + /// assert_eq!(Some(0), FinderReverse::new("foo").rfind(haystack)); + /// assert_eq!(Some(4), FinderReverse::new("bar").rfind(haystack)); + /// assert_eq!(None, FinderReverse::new("quux").rfind(haystack)); + /// ``` + #[inline] + pub fn rfind>(&self, haystack: B) -> Option { + self.0.rfind(haystack.as_ref()) + } +} + +/// An iterator over non-overlapping substring matches. +/// +/// Matches are reported by the byte offset at which they begin. +/// +/// `'a` is the shorter of two lifetimes: the byte string being searched or the +/// byte string being looked for. +#[derive(Debug)] +pub struct Find<'a> { + it: memmem::FindIter<'a, 'a>, + haystack: &'a [u8], + needle: &'a [u8], +} + +impl<'a> Find<'a> { + fn new(haystack: &'a [u8], needle: &'a [u8]) -> Find<'a> { + Find { it: memmem::find_iter(haystack, needle), haystack, needle } + } +} + +impl<'a> Iterator for Find<'a> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + self.it.next() + } +} + +/// An iterator over non-overlapping substring matches in reverse. +/// +/// Matches are reported by the byte offset at which they begin. +/// +/// `'a` is the shorter of two lifetimes: the byte string being searched or the +/// byte string being looked for. +#[derive(Debug)] +pub struct FindReverse<'a> { + it: memmem::FindRevIter<'a, 'a>, + haystack: &'a [u8], + needle: &'a [u8], +} + +impl<'a> FindReverse<'a> { + fn new(haystack: &'a [u8], needle: &'a [u8]) -> FindReverse<'a> { + FindReverse { + it: memmem::rfind_iter(haystack, needle), + haystack, + needle, + } + } + + fn haystack(&self) -> &'a [u8] { + self.haystack + } + + fn needle(&self) -> &[u8] { + self.needle + } +} + +impl<'a> Iterator for FindReverse<'a> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + self.it.next() + } +} + +/// An iterator over the bytes in a byte string. +/// +/// `'a` is the lifetime of the byte string being traversed. +#[derive(Clone, Debug)] +pub struct Bytes<'a> { + it: slice::Iter<'a, u8>, +} + +impl<'a> Bytes<'a> { + /// Views the remaining underlying data as a subslice of the original data. + /// This has the same lifetime as the original slice, + /// and so the iterator can continue to be used while this exists. + #[inline] + pub fn as_slice(&self) -> &'a [u8] { + self.it.as_slice() + } +} + +impl<'a> Iterator for Bytes<'a> { + type Item = u8; + + #[inline] + fn next(&mut self) -> Option { + self.it.next().map(|&b| b) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a> DoubleEndedIterator for Bytes<'a> { + #[inline] + fn next_back(&mut self) -> Option { + self.it.next_back().map(|&b| b) + } +} + +impl<'a> ExactSizeIterator for Bytes<'a> { + #[inline] + fn len(&self) -> usize { + self.it.len() + } +} + +impl<'a> iter::FusedIterator for Bytes<'a> {} + +/// An iterator over the fields in a byte string, separated by whitespace. +/// +/// This iterator splits on contiguous runs of whitespace, such that the fields +/// in `foo\t\t\n \nbar` are `foo` and `bar`. +/// +/// `'a` is the lifetime of the byte string being split. +#[derive(Debug)] +pub struct Fields<'a> { + it: FieldsWith<'a, fn(char) -> bool>, +} + +impl<'a> Fields<'a> { + fn new(bytes: &'a [u8]) -> Fields<'a> { + Fields { it: bytes.fields_with(|ch| ch.is_whitespace()) } + } +} + +impl<'a> Iterator for Fields<'a> { + type Item = &'a [u8]; + + #[inline] + fn next(&mut self) -> Option<&'a [u8]> { + self.it.next() + } +} + +/// An iterator over fields in the byte string, separated by a predicate over +/// codepoints. +/// +/// This iterator splits a byte string based on its predicate function such +/// that the elements returned are separated by contiguous runs of codepoints +/// for which the predicate returns true. +/// +/// `'a` is the lifetime of the byte string being split, while `F` is the type +/// of the predicate, i.e., `FnMut(char) -> bool`. +#[derive(Debug)] +pub struct FieldsWith<'a, F> { + f: F, + bytes: &'a [u8], + chars: CharIndices<'a>, +} + +impl<'a, F: FnMut(char) -> bool> FieldsWith<'a, F> { + fn new(bytes: &'a [u8], f: F) -> FieldsWith<'a, F> { + FieldsWith { f, bytes, chars: bytes.char_indices() } + } +} + +impl<'a, F: FnMut(char) -> bool> Iterator for FieldsWith<'a, F> { + type Item = &'a [u8]; + + #[inline] + fn next(&mut self) -> Option<&'a [u8]> { + let (start, mut end); + loop { + match self.chars.next() { + None => return None, + Some((s, e, ch)) => { + if !(self.f)(ch) { + start = s; + end = e; + break; + } + } + } + } + while let Some((_, e, ch)) = self.chars.next() { + if (self.f)(ch) { + break; + } + end = e; + } + Some(&self.bytes[start..end]) + } +} + +/// An iterator over substrings in a byte string, split by a separator. +/// +/// `'a` is the lifetime of the byte string being split. +#[derive(Debug)] +pub struct Split<'a> { + finder: Find<'a>, + /// The end position of the previous match of our splitter. The element + /// we yield corresponds to the substring starting at `last` up to the + /// beginning of the next match of the splitter. + last: usize, + /// Only set when iteration is complete. A corner case here is when a + /// splitter is matched at the end of the haystack. At that point, we still + /// need to yield an empty string following it. + done: bool, +} + +impl<'a> Split<'a> { + fn new(haystack: &'a [u8], splitter: &'a [u8]) -> Split<'a> { + let finder = haystack.find_iter(splitter); + Split { finder, last: 0, done: false } + } +} + +impl<'a> Iterator for Split<'a> { + type Item = &'a [u8]; + + #[inline] + fn next(&mut self) -> Option<&'a [u8]> { + let haystack = self.finder.haystack; + match self.finder.next() { + Some(start) => { + let next = &haystack[self.last..start]; + self.last = start + self.finder.needle.len(); + Some(next) + } + None => { + if self.last >= haystack.len() { + if !self.done { + self.done = true; + Some(b"") + } else { + None + } + } else { + let s = &haystack[self.last..]; + self.last = haystack.len(); + self.done = true; + Some(s) + } + } + } + } +} + +/// An iterator over substrings in a byte string, split by a separator, in +/// reverse. +/// +/// `'a` is the lifetime of the byte string being split, while `F` is the type +/// of the predicate, i.e., `FnMut(char) -> bool`. +#[derive(Debug)] +pub struct SplitReverse<'a> { + finder: FindReverse<'a>, + /// The end position of the previous match of our splitter. The element + /// we yield corresponds to the substring starting at `last` up to the + /// beginning of the next match of the splitter. + last: usize, + /// Only set when iteration is complete. A corner case here is when a + /// splitter is matched at the end of the haystack. At that point, we still + /// need to yield an empty string following it. + done: bool, +} + +impl<'a> SplitReverse<'a> { + fn new(haystack: &'a [u8], splitter: &'a [u8]) -> SplitReverse<'a> { + let finder = haystack.rfind_iter(splitter); + SplitReverse { finder, last: haystack.len(), done: false } + } +} + +impl<'a> Iterator for SplitReverse<'a> { + type Item = &'a [u8]; + + #[inline] + fn next(&mut self) -> Option<&'a [u8]> { + let haystack = self.finder.haystack(); + match self.finder.next() { + Some(start) => { + let nlen = self.finder.needle().len(); + let next = &haystack[start + nlen..self.last]; + self.last = start; + Some(next) + } + None => { + if self.last == 0 { + if !self.done { + self.done = true; + Some(b"") + } else { + None + } + } else { + let s = &haystack[..self.last]; + self.last = 0; + self.done = true; + Some(s) + } + } + } + } +} + +/// An iterator over at most `n` substrings in a byte string, split by a +/// separator. +/// +/// `'a` is the lifetime of the byte string being split, while `F` is the type +/// of the predicate, i.e., `FnMut(char) -> bool`. +#[derive(Debug)] +pub struct SplitN<'a> { + split: Split<'a>, + limit: usize, + count: usize, +} + +impl<'a> SplitN<'a> { + fn new( + haystack: &'a [u8], + splitter: &'a [u8], + limit: usize, + ) -> SplitN<'a> { + let split = haystack.split_str(splitter); + SplitN { split, limit, count: 0 } + } +} + +impl<'a> Iterator for SplitN<'a> { + type Item = &'a [u8]; + + #[inline] + fn next(&mut self) -> Option<&'a [u8]> { + self.count += 1; + if self.count > self.limit || self.split.done { + None + } else if self.count == self.limit { + Some(&self.split.finder.haystack[self.split.last..]) + } else { + self.split.next() + } + } +} + +/// An iterator over at most `n` substrings in a byte string, split by a +/// separator, in reverse. +/// +/// `'a` is the lifetime of the byte string being split, while `F` is the type +/// of the predicate, i.e., `FnMut(char) -> bool`. +#[derive(Debug)] +pub struct SplitNReverse<'a> { + split: SplitReverse<'a>, + limit: usize, + count: usize, +} + +impl<'a> SplitNReverse<'a> { + fn new( + haystack: &'a [u8], + splitter: &'a [u8], + limit: usize, + ) -> SplitNReverse<'a> { + let split = haystack.rsplit_str(splitter); + SplitNReverse { split, limit, count: 0 } + } +} + +impl<'a> Iterator for SplitNReverse<'a> { + type Item = &'a [u8]; + + #[inline] + fn next(&mut self) -> Option<&'a [u8]> { + self.count += 1; + if self.count > self.limit || self.split.done { + None + } else if self.count == self.limit { + Some(&self.split.finder.haystack()[..self.split.last]) + } else { + self.split.next() + } + } +} + +/// An iterator over all lines in a byte string, without their terminators. +/// +/// For this iterator, the only line terminators recognized are `\r\n` and +/// `\n`. +/// +/// `'a` is the lifetime of the byte string being iterated over. +pub struct Lines<'a> { + it: LinesWithTerminator<'a>, +} + +impl<'a> Lines<'a> { + fn new(bytes: &'a [u8]) -> Lines<'a> { + Lines { it: LinesWithTerminator::new(bytes) } + } +} + +impl<'a> Iterator for Lines<'a> { + type Item = &'a [u8]; + + #[inline] + fn next(&mut self) -> Option<&'a [u8]> { + let mut line = self.it.next()?; + if line.last_byte() == Some(b'\n') { + line = &line[..line.len() - 1]; + if line.last_byte() == Some(b'\r') { + line = &line[..line.len() - 1]; + } + } + Some(line) + } +} + +/// An iterator over all lines in a byte string, including their terminators. +/// +/// For this iterator, the only line terminator recognized is `\n`. (Since +/// line terminators are included, this also handles `\r\n` line endings.) +/// +/// Line terminators are only included if they are present in the original +/// byte string. For example, the last line in a byte string may not end with +/// a line terminator. +/// +/// Concatenating all elements yielded by this iterator is guaranteed to yield +/// the original byte string. +/// +/// `'a` is the lifetime of the byte string being iterated over. +pub struct LinesWithTerminator<'a> { + bytes: &'a [u8], +} + +impl<'a> LinesWithTerminator<'a> { + fn new(bytes: &'a [u8]) -> LinesWithTerminator<'a> { + LinesWithTerminator { bytes } + } +} + +impl<'a> Iterator for LinesWithTerminator<'a> { + type Item = &'a [u8]; + + #[inline] + fn next(&mut self) -> Option<&'a [u8]> { + match self.bytes.find_byte(b'\n') { + None if self.bytes.is_empty() => None, + None => { + let line = self.bytes; + self.bytes = b""; + Some(line) + } + Some(end) => { + let line = &self.bytes[..end + 1]; + self.bytes = &self.bytes[end + 1..]; + Some(line) + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::ext_slice::{ByteSlice, B}; + use crate::tests::LOSSY_TESTS; + + #[test] + fn to_str_lossy() { + for (i, &(expected, input)) in LOSSY_TESTS.iter().enumerate() { + let got = B(input).to_str_lossy(); + assert_eq!( + expected.as_bytes(), + got.as_bytes(), + "to_str_lossy(ith: {:?}, given: {:?})", + i, + input, + ); + + let mut got = String::new(); + B(input).to_str_lossy_into(&mut got); + assert_eq!( + expected.as_bytes(), + got.as_bytes(), + "to_str_lossy_into", + ); + + let got = String::from_utf8_lossy(input); + assert_eq!(expected.as_bytes(), got.as_bytes(), "std"); + } + } + + #[test] + #[should_panic] + fn copy_within_fail1() { + let mut buf = *b"foobar"; + let s = &mut buf; + s.copy_within_str(0..2, 5); + } + + #[test] + #[should_panic] + fn copy_within_fail2() { + let mut buf = *b"foobar"; + let s = &mut buf; + s.copy_within_str(3..2, 0); + } + + #[test] + #[should_panic] + fn copy_within_fail3() { + let mut buf = *b"foobar"; + let s = &mut buf; + s.copy_within_str(5..7, 0); + } + + #[test] + #[should_panic] + fn copy_within_fail4() { + let mut buf = *b"foobar"; + let s = &mut buf; + s.copy_within_str(0..1, 6); + } +} diff --git a/vendor/bstr-0.2.17/src/ext_vec.rs b/vendor/bstr-0.2.17/src/ext_vec.rs new file mode 100644 index 0000000000000..5beb0e16ae926 --- /dev/null +++ b/vendor/bstr-0.2.17/src/ext_vec.rs @@ -0,0 +1,1105 @@ +use std::borrow::Cow; +use std::error; +use std::ffi::{OsStr, OsString}; +use std::fmt; +use std::iter; +use std::ops; +use std::path::{Path, PathBuf}; +use std::ptr; +use std::str; +use std::vec; + +use crate::ext_slice::ByteSlice; +use crate::utf8::{self, Utf8Error}; + +/// Concatenate the elements given by the iterator together into a single +/// `Vec`. +/// +/// The elements may be any type that can be cheaply converted into an `&[u8]`. +/// This includes, but is not limited to, `&str`, `&BStr` and `&[u8]` itself. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bstr; +/// +/// let s = bstr::concat(&["foo", "bar", "baz"]); +/// assert_eq!(s, "foobarbaz".as_bytes()); +/// ``` +#[inline] +pub fn concat(elements: I) -> Vec +where + T: AsRef<[u8]>, + I: IntoIterator, +{ + let mut dest = vec![]; + for element in elements { + dest.push_str(element); + } + dest +} + +/// Join the elements given by the iterator with the given separator into a +/// single `Vec`. +/// +/// Both the separator and the elements may be any type that can be cheaply +/// converted into an `&[u8]`. This includes, but is not limited to, +/// `&str`, `&BStr` and `&[u8]` itself. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bstr; +/// +/// let s = bstr::join(",", &["foo", "bar", "baz"]); +/// assert_eq!(s, "foo,bar,baz".as_bytes()); +/// ``` +#[inline] +pub fn join(separator: B, elements: I) -> Vec +where + B: AsRef<[u8]>, + T: AsRef<[u8]>, + I: IntoIterator, +{ + let mut it = elements.into_iter(); + let mut dest = vec![]; + match it.next() { + None => return dest, + Some(first) => { + dest.push_str(first); + } + } + for element in it { + dest.push_str(&separator); + dest.push_str(element); + } + dest +} + +impl ByteVec for Vec { + #[inline] + fn as_vec(&self) -> &Vec { + self + } + + #[inline] + fn as_vec_mut(&mut self) -> &mut Vec { + self + } + + #[inline] + fn into_vec(self) -> Vec { + self + } +} + +/// Ensure that callers cannot implement `ByteSlice` by making an +/// umplementable trait its super trait. +pub trait Sealed {} +impl Sealed for Vec {} + +/// A trait that extends `Vec` with string oriented methods. +/// +/// Note that when using the constructor methods, such as +/// `ByteVec::from_slice`, one should actually call them using the concrete +/// type. For example: +/// +/// ``` +/// use bstr::{B, ByteVec}; +/// +/// let s = Vec::from_slice(b"abc"); // NOT ByteVec::from_slice("...") +/// assert_eq!(s, B("abc")); +/// ``` +pub trait ByteVec: Sealed { + /// A method for accessing the raw vector bytes of this type. This is + /// always a no-op and callers shouldn't care about it. This only exists + /// for making the extension trait work. + #[doc(hidden)] + fn as_vec(&self) -> &Vec; + + /// A method for accessing the raw vector bytes of this type, mutably. This + /// is always a no-op and callers shouldn't care about it. This only exists + /// for making the extension trait work. + #[doc(hidden)] + fn as_vec_mut(&mut self) -> &mut Vec; + + /// A method for consuming ownership of this vector. This is always a no-op + /// and callers shouldn't care about it. This only exists for making the + /// extension trait work. + #[doc(hidden)] + fn into_vec(self) -> Vec + where + Self: Sized; + + /// Create a new owned byte string from the given byte slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteVec}; + /// + /// let s = Vec::from_slice(b"abc"); + /// assert_eq!(s, B("abc")); + /// ``` + #[inline] + fn from_slice>(bytes: B) -> Vec { + bytes.as_ref().to_vec() + } + + /// Create a new byte string from an owned OS string. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns the original OS string if it is not valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::ffi::OsString; + /// + /// use bstr::{B, ByteVec}; + /// + /// let os_str = OsString::from("foo"); + /// let bs = Vec::from_os_string(os_str).expect("valid UTF-8"); + /// assert_eq!(bs, B("foo")); + /// ``` + #[inline] + fn from_os_string(os_str: OsString) -> Result, OsString> { + #[cfg(unix)] + #[inline] + fn imp(os_str: OsString) -> Result, OsString> { + use std::os::unix::ffi::OsStringExt; + + Ok(Vec::from(os_str.into_vec())) + } + + #[cfg(not(unix))] + #[inline] + fn imp(os_str: OsString) -> Result, OsString> { + os_str.into_string().map(Vec::from) + } + + imp(os_str) + } + + /// Lossily create a new byte string from an OS string slice. + /// + /// On Unix, this always succeeds, is zero cost and always returns a slice. + /// On non-Unix systems, this does a UTF-8 check. If the given OS string + /// slice is not valid UTF-8, then it is lossily decoded into valid UTF-8 + /// (with invalid bytes replaced by the Unicode replacement codepoint). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// use bstr::{B, ByteVec}; + /// + /// let os_str = OsStr::new("foo"); + /// let bs = Vec::from_os_str_lossy(os_str); + /// assert_eq!(bs, B("foo")); + /// ``` + #[inline] + fn from_os_str_lossy<'a>(os_str: &'a OsStr) -> Cow<'a, [u8]> { + #[cfg(unix)] + #[inline] + fn imp<'a>(os_str: &'a OsStr) -> Cow<'a, [u8]> { + use std::os::unix::ffi::OsStrExt; + + Cow::Borrowed(os_str.as_bytes()) + } + + #[cfg(not(unix))] + #[inline] + fn imp<'a>(os_str: &'a OsStr) -> Cow<'a, [u8]> { + match os_str.to_string_lossy() { + Cow::Borrowed(x) => Cow::Borrowed(x.as_bytes()), + Cow::Owned(x) => Cow::Owned(Vec::from(x)), + } + } + + imp(os_str) + } + + /// Create a new byte string from an owned file path. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns the original path if it is not valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::path::PathBuf; + /// + /// use bstr::{B, ByteVec}; + /// + /// let path = PathBuf::from("foo"); + /// let bs = Vec::from_path_buf(path).expect("must be valid UTF-8"); + /// assert_eq!(bs, B("foo")); + /// ``` + #[inline] + fn from_path_buf(path: PathBuf) -> Result, PathBuf> { + Vec::from_os_string(path.into_os_string()).map_err(PathBuf::from) + } + + /// Lossily create a new byte string from a file path. + /// + /// On Unix, this always succeeds, is zero cost and always returns a slice. + /// On non-Unix systems, this does a UTF-8 check. If the given path is not + /// valid UTF-8, then it is lossily decoded into valid UTF-8 (with invalid + /// bytes replaced by the Unicode replacement codepoint). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::path::Path; + /// + /// use bstr::{B, ByteVec}; + /// + /// let path = Path::new("foo"); + /// let bs = Vec::from_path_lossy(path); + /// assert_eq!(bs, B("foo")); + /// ``` + #[inline] + fn from_path_lossy<'a>(path: &'a Path) -> Cow<'a, [u8]> { + Vec::from_os_str_lossy(path.as_os_str()) + } + + /// Appends the given byte to the end of this byte string. + /// + /// Note that this is equivalent to the generic `Vec::push` method. This + /// method is provided to permit callers to explicitly differentiate + /// between pushing bytes, codepoints and strings. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let mut s = >::from("abc"); + /// s.push_byte(b'\xE2'); + /// s.push_byte(b'\x98'); + /// s.push_byte(b'\x83'); + /// assert_eq!(s, "abc☃".as_bytes()); + /// ``` + #[inline] + fn push_byte(&mut self, byte: u8) { + self.as_vec_mut().push(byte); + } + + /// Appends the given `char` to the end of this byte string. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let mut s = >::from("abc"); + /// s.push_char('1'); + /// s.push_char('2'); + /// s.push_char('3'); + /// assert_eq!(s, "abc123".as_bytes()); + /// ``` + #[inline] + fn push_char(&mut self, ch: char) { + if ch.len_utf8() == 1 { + self.push_byte(ch as u8); + return; + } + self.as_vec_mut() + .extend_from_slice(ch.encode_utf8(&mut [0; 4]).as_bytes()); + } + + /// Appends the given slice to the end of this byte string. This accepts + /// any type that be converted to a `&[u8]`. This includes, but is not + /// limited to, `&str`, `&BStr`, and of course, `&[u8]` itself. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let mut s = >::from("abc"); + /// s.push_str(b"123"); + /// assert_eq!(s, "abc123".as_bytes()); + /// ``` + #[inline] + fn push_str>(&mut self, bytes: B) { + self.as_vec_mut().extend_from_slice(bytes.as_ref()); + } + + /// Converts a `Vec` into a `String` if and only if this byte string is + /// valid UTF-8. + /// + /// If it is not valid UTF-8, then a + /// [`FromUtf8Error`](struct.FromUtf8Error.html) + /// is returned. (This error can be used to examine why UTF-8 validation + /// failed, or to regain the original byte string.) + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// # fn example() -> Result<(), Box> { + /// let bytes = Vec::from("hello"); + /// let string = bytes.into_string()?; + /// + /// assert_eq!("hello", string); + /// # Ok(()) }; example().unwrap() + /// ``` + /// + /// If this byte string is not valid UTF-8, then an error will be returned. + /// That error can then be used to inspect the location at which invalid + /// UTF-8 was found, or to regain the original byte string: + /// + /// ``` + /// use bstr::{B, ByteVec}; + /// + /// let bytes = Vec::from_slice(b"foo\xFFbar"); + /// let err = bytes.into_string().unwrap_err(); + /// + /// assert_eq!(err.utf8_error().valid_up_to(), 3); + /// assert_eq!(err.utf8_error().error_len(), Some(1)); + /// + /// // At no point in this example is an allocation performed. + /// let bytes = Vec::from(err.into_vec()); + /// assert_eq!(bytes, B(b"foo\xFFbar")); + /// ``` + #[inline] + fn into_string(self) -> Result + where + Self: Sized, + { + match utf8::validate(self.as_vec()) { + Err(err) => Err(FromUtf8Error { original: self.into_vec(), err }), + Ok(()) => { + // SAFETY: This is safe because of the guarantees provided by + // utf8::validate. + unsafe { Ok(self.into_string_unchecked()) } + } + } + } + + /// Lossily converts a `Vec` into a `String`. If this byte string + /// contains invalid UTF-8, then the invalid bytes are replaced with the + /// Unicode replacement codepoint. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let bytes = Vec::from_slice(b"foo\xFFbar"); + /// let string = bytes.into_string_lossy(); + /// assert_eq!(string, "foo\u{FFFD}bar"); + /// ``` + #[inline] + fn into_string_lossy(self) -> String + where + Self: Sized, + { + match self.as_vec().to_str_lossy() { + Cow::Borrowed(_) => { + // SAFETY: to_str_lossy() returning a Cow::Borrowed guarantees + // the entire string is valid utf8. + unsafe { self.into_string_unchecked() } + } + Cow::Owned(s) => s, + } + } + + /// Unsafely convert this byte string into a `String`, without checking for + /// valid UTF-8. + /// + /// # Safety + /// + /// Callers *must* ensure that this byte string is valid UTF-8 before + /// calling this method. Converting a byte string into a `String` that is + /// not valid UTF-8 is considered undefined behavior. + /// + /// This routine is useful in performance sensitive contexts where the + /// UTF-8 validity of the byte string is already known and it is + /// undesirable to pay the cost of an additional UTF-8 validation check + /// that [`into_string`](#method.into_string) performs. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// // SAFETY: This is safe because string literals are guaranteed to be + /// // valid UTF-8 by the Rust compiler. + /// let s = unsafe { Vec::from("☃βツ").into_string_unchecked() }; + /// assert_eq!("☃βツ", s); + /// ``` + #[inline] + unsafe fn into_string_unchecked(self) -> String + where + Self: Sized, + { + String::from_utf8_unchecked(self.into_vec()) + } + + /// Converts this byte string into an OS string, in place. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns the original byte string if it is not valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// use bstr::ByteVec; + /// + /// let bs = Vec::from("foo"); + /// let os_str = bs.into_os_string().expect("should be valid UTF-8"); + /// assert_eq!(os_str, OsStr::new("foo")); + /// ``` + #[inline] + fn into_os_string(self) -> Result> + where + Self: Sized, + { + #[cfg(unix)] + #[inline] + fn imp(v: Vec) -> Result> { + use std::os::unix::ffi::OsStringExt; + + Ok(OsString::from_vec(v)) + } + + #[cfg(not(unix))] + #[inline] + fn imp(v: Vec) -> Result> { + match v.into_string() { + Ok(s) => Ok(OsString::from(s)), + Err(err) => Err(err.into_vec()), + } + } + + imp(self.into_vec()) + } + + /// Lossily converts this byte string into an OS string, in place. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this will perform a UTF-8 check and lossily convert this byte string + /// into valid UTF-8 using the Unicode replacement codepoint. + /// + /// Note that this can prevent the correct roundtripping of file paths on + /// non-Unix systems such as Windows, where file paths are an arbitrary + /// sequence of 16-bit integers. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let bs = Vec::from_slice(b"foo\xFFbar"); + /// let os_str = bs.into_os_string_lossy(); + /// assert_eq!(os_str.to_string_lossy(), "foo\u{FFFD}bar"); + /// ``` + #[inline] + fn into_os_string_lossy(self) -> OsString + where + Self: Sized, + { + #[cfg(unix)] + #[inline] + fn imp(v: Vec) -> OsString { + use std::os::unix::ffi::OsStringExt; + + OsString::from_vec(v) + } + + #[cfg(not(unix))] + #[inline] + fn imp(v: Vec) -> OsString { + OsString::from(v.into_string_lossy()) + } + + imp(self.into_vec()) + } + + /// Converts this byte string into an owned file path, in place. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns the original byte string if it is not valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let bs = Vec::from("foo"); + /// let path = bs.into_path_buf().expect("should be valid UTF-8"); + /// assert_eq!(path.as_os_str(), "foo"); + /// ``` + #[inline] + fn into_path_buf(self) -> Result> + where + Self: Sized, + { + self.into_os_string().map(PathBuf::from) + } + + /// Lossily converts this byte string into an owned file path, in place. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this will perform a UTF-8 check and lossily convert this byte string + /// into valid UTF-8 using the Unicode replacement codepoint. + /// + /// Note that this can prevent the correct roundtripping of file paths on + /// non-Unix systems such as Windows, where file paths are an arbitrary + /// sequence of 16-bit integers. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let bs = Vec::from_slice(b"foo\xFFbar"); + /// let path = bs.into_path_buf_lossy(); + /// assert_eq!(path.to_string_lossy(), "foo\u{FFFD}bar"); + /// ``` + #[inline] + fn into_path_buf_lossy(self) -> PathBuf + where + Self: Sized, + { + PathBuf::from(self.into_os_string_lossy()) + } + + /// Removes the last byte from this `Vec` and returns it. + /// + /// If this byte string is empty, then `None` is returned. + /// + /// If the last codepoint in this byte string is not ASCII, then removing + /// the last byte could make this byte string contain invalid UTF-8. + /// + /// Note that this is equivalent to the generic `Vec::pop` method. This + /// method is provided to permit callers to explicitly differentiate + /// between popping bytes and codepoints. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let mut s = Vec::from("foo"); + /// assert_eq!(s.pop_byte(), Some(b'o')); + /// assert_eq!(s.pop_byte(), Some(b'o')); + /// assert_eq!(s.pop_byte(), Some(b'f')); + /// assert_eq!(s.pop_byte(), None); + /// ``` + #[inline] + fn pop_byte(&mut self) -> Option { + self.as_vec_mut().pop() + } + + /// Removes the last codepoint from this `Vec` and returns it. + /// + /// If this byte string is empty, then `None` is returned. If the last + /// bytes of this byte string do not correspond to a valid UTF-8 code unit + /// sequence, then the Unicode replacement codepoint is yielded instead in + /// accordance with the + /// [replacement codepoint substitution policy](index.html#handling-of-invalid-utf8-8). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let mut s = Vec::from("foo"); + /// assert_eq!(s.pop_char(), Some('o')); + /// assert_eq!(s.pop_char(), Some('o')); + /// assert_eq!(s.pop_char(), Some('f')); + /// assert_eq!(s.pop_char(), None); + /// ``` + /// + /// This shows the replacement codepoint substitution policy. Note that + /// the first pop yields a replacement codepoint but actually removes two + /// bytes. This is in contrast with subsequent pops when encountering + /// `\xFF` since `\xFF` is never a valid prefix for any valid UTF-8 + /// code unit sequence. + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let mut s = Vec::from_slice(b"f\xFF\xFF\xFFoo\xE2\x98"); + /// assert_eq!(s.pop_char(), Some('\u{FFFD}')); + /// assert_eq!(s.pop_char(), Some('o')); + /// assert_eq!(s.pop_char(), Some('o')); + /// assert_eq!(s.pop_char(), Some('\u{FFFD}')); + /// assert_eq!(s.pop_char(), Some('\u{FFFD}')); + /// assert_eq!(s.pop_char(), Some('\u{FFFD}')); + /// assert_eq!(s.pop_char(), Some('f')); + /// assert_eq!(s.pop_char(), None); + /// ``` + #[inline] + fn pop_char(&mut self) -> Option { + let (ch, size) = utf8::decode_last_lossy(self.as_vec()); + if size == 0 { + return None; + } + let new_len = self.as_vec().len() - size; + self.as_vec_mut().truncate(new_len); + Some(ch) + } + + /// Removes a `char` from this `Vec` at the given byte position and + /// returns it. + /// + /// If the bytes at the given position do not lead to a valid UTF-8 code + /// unit sequence, then a + /// [replacement codepoint is returned instead](index.html#handling-of-invalid-utf8-8). + /// + /// # Panics + /// + /// Panics if `at` is larger than or equal to this byte string's length. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let mut s = Vec::from("foo☃bar"); + /// assert_eq!(s.remove_char(3), '☃'); + /// assert_eq!(s, b"foobar"); + /// ``` + /// + /// This example shows how the Unicode replacement codepoint policy is + /// used: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let mut s = Vec::from_slice(b"foo\xFFbar"); + /// assert_eq!(s.remove_char(3), '\u{FFFD}'); + /// assert_eq!(s, b"foobar"); + /// ``` + #[inline] + fn remove_char(&mut self, at: usize) -> char { + let (ch, size) = utf8::decode_lossy(&self.as_vec()[at..]); + assert!( + size > 0, + "expected {} to be less than {}", + at, + self.as_vec().len(), + ); + self.as_vec_mut().drain(at..at + size); + ch + } + + /// Inserts the given codepoint into this `Vec` at a particular byte + /// position. + /// + /// This is an `O(n)` operation as it may copy a number of elements in this + /// byte string proportional to its length. + /// + /// # Panics + /// + /// Panics if `at` is larger than the byte string's length. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let mut s = Vec::from("foobar"); + /// s.insert_char(3, '☃'); + /// assert_eq!(s, "foo☃bar".as_bytes()); + /// ``` + #[inline] + fn insert_char(&mut self, at: usize, ch: char) { + self.insert_str(at, ch.encode_utf8(&mut [0; 4]).as_bytes()); + } + + /// Inserts the given byte string into this byte string at a particular + /// byte position. + /// + /// This is an `O(n)` operation as it may copy a number of elements in this + /// byte string proportional to its length. + /// + /// The given byte string may be any type that can be cheaply converted + /// into a `&[u8]`. This includes, but is not limited to, `&str` and + /// `&[u8]`. + /// + /// # Panics + /// + /// Panics if `at` is larger than the byte string's length. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let mut s = Vec::from("foobar"); + /// s.insert_str(3, "☃☃☃"); + /// assert_eq!(s, "foo☃☃☃bar".as_bytes()); + /// ``` + #[inline] + fn insert_str>(&mut self, at: usize, bytes: B) { + let bytes = bytes.as_ref(); + let len = self.as_vec().len(); + assert!(at <= len, "expected {} to be <= {}", at, len); + + // SAFETY: We'd like to efficiently splice in the given bytes into + // this byte string. Since we are only working with `u8` elements here, + // we only need to consider whether our bounds are correct and whether + // our byte string has enough space. + self.as_vec_mut().reserve(bytes.len()); + unsafe { + // Shift bytes after `at` over by the length of `bytes` to make + // room for it. This requires referencing two regions of memory + // that may overlap, so we use ptr::copy. + ptr::copy( + self.as_vec().as_ptr().add(at), + self.as_vec_mut().as_mut_ptr().add(at + bytes.len()), + len - at, + ); + // Now copy the bytes given into the room we made above. In this + // case, we know that the given bytes cannot possibly overlap + // with this byte string since we have a mutable borrow of the + // latter. Thus, we can use a nonoverlapping copy. + ptr::copy_nonoverlapping( + bytes.as_ptr(), + self.as_vec_mut().as_mut_ptr().add(at), + bytes.len(), + ); + self.as_vec_mut().set_len(len + bytes.len()); + } + } + + /// Removes the specified range in this byte string and replaces it with + /// the given bytes. The given bytes do not need to have the same length + /// as the range provided. + /// + /// # Panics + /// + /// Panics if the given range is invalid. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let mut s = Vec::from("foobar"); + /// s.replace_range(2..4, "xxxxx"); + /// assert_eq!(s, "foxxxxxar".as_bytes()); + /// ``` + #[inline] + fn replace_range(&mut self, range: R, replace_with: B) + where + R: ops::RangeBounds, + B: AsRef<[u8]>, + { + self.as_vec_mut().splice(range, replace_with.as_ref().iter().cloned()); + } + + /// Creates a draining iterator that removes the specified range in this + /// `Vec` and yields each of the removed bytes. + /// + /// Note that the elements specified by the given range are removed + /// regardless of whether the returned iterator is fully exhausted. + /// + /// Also note that is is unspecified how many bytes are removed from the + /// `Vec` if the `DrainBytes` iterator is leaked. + /// + /// # Panics + /// + /// Panics if the given range is not valid. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::ByteVec; + /// + /// let mut s = Vec::from("foobar"); + /// { + /// let mut drainer = s.drain_bytes(2..4); + /// assert_eq!(drainer.next(), Some(b'o')); + /// assert_eq!(drainer.next(), Some(b'b')); + /// assert_eq!(drainer.next(), None); + /// } + /// assert_eq!(s, "foar".as_bytes()); + /// ``` + #[inline] + fn drain_bytes(&mut self, range: R) -> DrainBytes<'_> + where + R: ops::RangeBounds, + { + DrainBytes { it: self.as_vec_mut().drain(range) } + } +} + +/// A draining byte oriented iterator for `Vec`. +/// +/// This iterator is created by +/// [`ByteVec::drain_bytes`](trait.ByteVec.html#method.drain_bytes). +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bstr::ByteVec; +/// +/// let mut s = Vec::from("foobar"); +/// { +/// let mut drainer = s.drain_bytes(2..4); +/// assert_eq!(drainer.next(), Some(b'o')); +/// assert_eq!(drainer.next(), Some(b'b')); +/// assert_eq!(drainer.next(), None); +/// } +/// assert_eq!(s, "foar".as_bytes()); +/// ``` +#[derive(Debug)] +pub struct DrainBytes<'a> { + it: vec::Drain<'a, u8>, +} + +impl<'a> iter::FusedIterator for DrainBytes<'a> {} + +impl<'a> Iterator for DrainBytes<'a> { + type Item = u8; + + #[inline] + fn next(&mut self) -> Option { + self.it.next() + } +} + +impl<'a> DoubleEndedIterator for DrainBytes<'a> { + #[inline] + fn next_back(&mut self) -> Option { + self.it.next_back() + } +} + +impl<'a> ExactSizeIterator for DrainBytes<'a> { + #[inline] + fn len(&self) -> usize { + self.it.len() + } +} + +/// An error that may occur when converting a `Vec` to a `String`. +/// +/// This error includes the original `Vec` that failed to convert to a +/// `String`. This permits callers to recover the allocation used even if it +/// it not valid UTF-8. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bstr::{B, ByteVec}; +/// +/// let bytes = Vec::from_slice(b"foo\xFFbar"); +/// let err = bytes.into_string().unwrap_err(); +/// +/// assert_eq!(err.utf8_error().valid_up_to(), 3); +/// assert_eq!(err.utf8_error().error_len(), Some(1)); +/// +/// // At no point in this example is an allocation performed. +/// let bytes = Vec::from(err.into_vec()); +/// assert_eq!(bytes, B(b"foo\xFFbar")); +/// ``` +#[derive(Debug, Eq, PartialEq)] +pub struct FromUtf8Error { + original: Vec, + err: Utf8Error, +} + +impl FromUtf8Error { + /// Return the original bytes as a slice that failed to convert to a + /// `String`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteVec}; + /// + /// let bytes = Vec::from_slice(b"foo\xFFbar"); + /// let err = bytes.into_string().unwrap_err(); + /// + /// // At no point in this example is an allocation performed. + /// assert_eq!(err.as_bytes(), B(b"foo\xFFbar")); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.original + } + + /// Consume this error and return the original byte string that failed to + /// convert to a `String`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteVec}; + /// + /// let bytes = Vec::from_slice(b"foo\xFFbar"); + /// let err = bytes.into_string().unwrap_err(); + /// let original = err.into_vec(); + /// + /// // At no point in this example is an allocation performed. + /// assert_eq!(original, B(b"foo\xFFbar")); + /// ``` + #[inline] + pub fn into_vec(self) -> Vec { + self.original + } + + /// Return the underlying UTF-8 error that occurred. This error provides + /// information on the nature and location of the invalid UTF-8 detected. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, ByteVec}; + /// + /// let bytes = Vec::from_slice(b"foo\xFFbar"); + /// let err = bytes.into_string().unwrap_err(); + /// + /// assert_eq!(err.utf8_error().valid_up_to(), 3); + /// assert_eq!(err.utf8_error().error_len(), Some(1)); + /// ``` + #[inline] + pub fn utf8_error(&self) -> &Utf8Error { + &self.err + } +} + +impl error::Error for FromUtf8Error { + #[inline] + fn description(&self) -> &str { + "invalid UTF-8 vector" + } +} + +impl fmt::Display for FromUtf8Error { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.err) + } +} + +#[cfg(test)] +mod tests { + use crate::ext_vec::ByteVec; + + #[test] + fn insert() { + let mut s = vec![]; + s.insert_str(0, "foo"); + assert_eq!(s, "foo".as_bytes()); + + let mut s = Vec::from("a"); + s.insert_str(0, "foo"); + assert_eq!(s, "fooa".as_bytes()); + + let mut s = Vec::from("a"); + s.insert_str(1, "foo"); + assert_eq!(s, "afoo".as_bytes()); + + let mut s = Vec::from("foobar"); + s.insert_str(3, "quux"); + assert_eq!(s, "fooquuxbar".as_bytes()); + + let mut s = Vec::from("foobar"); + s.insert_str(3, "x"); + assert_eq!(s, "fooxbar".as_bytes()); + + let mut s = Vec::from("foobar"); + s.insert_str(0, "x"); + assert_eq!(s, "xfoobar".as_bytes()); + + let mut s = Vec::from("foobar"); + s.insert_str(6, "x"); + assert_eq!(s, "foobarx".as_bytes()); + + let mut s = Vec::from("foobar"); + s.insert_str(3, "quuxbazquux"); + assert_eq!(s, "fooquuxbazquuxbar".as_bytes()); + } + + #[test] + #[should_panic] + fn insert_fail1() { + let mut s = vec![]; + s.insert_str(1, "foo"); + } + + #[test] + #[should_panic] + fn insert_fail2() { + let mut s = Vec::from("a"); + s.insert_str(2, "foo"); + } + + #[test] + #[should_panic] + fn insert_fail3() { + let mut s = Vec::from("foobar"); + s.insert_str(7, "foo"); + } +} diff --git a/vendor/bstr-0.2.17/src/impls.rs b/vendor/bstr-0.2.17/src/impls.rs new file mode 100644 index 0000000000000..85a27ba778672 --- /dev/null +++ b/vendor/bstr-0.2.17/src/impls.rs @@ -0,0 +1,987 @@ +macro_rules! impl_partial_eq { + ($lhs:ty, $rhs:ty) => { + impl<'a, 'b> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let other: &[u8] = other.as_ref(); + PartialEq::eq(self.as_bytes(), other) + } + } + + impl<'a, 'b> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + let this: &[u8] = self.as_ref(); + PartialEq::eq(this, other.as_bytes()) + } + } + }; +} + +#[cfg(feature = "std")] +macro_rules! impl_partial_eq_cow { + ($lhs:ty, $rhs:ty) => { + impl<'a, 'b> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let other: &[u8] = (&**other).as_ref(); + PartialEq::eq(self.as_bytes(), other) + } + } + + impl<'a, 'b> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + let this: &[u8] = (&**other).as_ref(); + PartialEq::eq(this, self.as_bytes()) + } + } + }; +} + +macro_rules! impl_partial_ord { + ($lhs:ty, $rhs:ty) => { + impl<'a, 'b> PartialOrd<$rhs> for $lhs { + #[inline] + fn partial_cmp(&self, other: &$rhs) -> Option { + let other: &[u8] = other.as_ref(); + PartialOrd::partial_cmp(self.as_bytes(), other) + } + } + + impl<'a, 'b> PartialOrd<$lhs> for $rhs { + #[inline] + fn partial_cmp(&self, other: &$lhs) -> Option { + let this: &[u8] = self.as_ref(); + PartialOrd::partial_cmp(this, other.as_bytes()) + } + } + }; +} + +#[cfg(feature = "std")] +mod bstring { + use std::borrow::{Borrow, Cow, ToOwned}; + use std::cmp::Ordering; + use std::fmt; + use std::iter::FromIterator; + use std::ops; + + use crate::bstr::BStr; + use crate::bstring::BString; + use crate::ext_vec::ByteVec; + + impl fmt::Display for BString { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_bstr(), f) + } + } + + impl fmt::Debug for BString { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_bstr(), f) + } + } + + impl ops::Deref for BString { + type Target = Vec; + + #[inline] + fn deref(&self) -> &Vec { + &self.bytes + } + } + + impl ops::DerefMut for BString { + #[inline] + fn deref_mut(&mut self) -> &mut Vec { + &mut self.bytes + } + } + + impl AsRef<[u8]> for BString { + #[inline] + fn as_ref(&self) -> &[u8] { + &self.bytes + } + } + + impl AsRef for BString { + #[inline] + fn as_ref(&self) -> &BStr { + self.as_bstr() + } + } + + impl AsMut<[u8]> for BString { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + &mut self.bytes + } + } + + impl AsMut for BString { + #[inline] + fn as_mut(&mut self) -> &mut BStr { + self.as_mut_bstr() + } + } + + impl Borrow for BString { + #[inline] + fn borrow(&self) -> &BStr { + self.as_bstr() + } + } + + impl ToOwned for BStr { + type Owned = BString; + + #[inline] + fn to_owned(&self) -> BString { + BString::from(self) + } + } + + impl Default for BString { + fn default() -> BString { + BString::from(vec![]) + } + } + + impl<'a> From<&'a [u8]> for BString { + #[inline] + fn from(s: &'a [u8]) -> BString { + BString::from(s.to_vec()) + } + } + + impl From> for BString { + #[inline] + fn from(s: Vec) -> BString { + BString { bytes: s } + } + } + + impl From for Vec { + #[inline] + fn from(s: BString) -> Vec { + s.bytes + } + } + + impl<'a> From<&'a str> for BString { + #[inline] + fn from(s: &'a str) -> BString { + BString::from(s.as_bytes().to_vec()) + } + } + + impl From for BString { + #[inline] + fn from(s: String) -> BString { + BString::from(s.into_bytes()) + } + } + + impl<'a> From<&'a BStr> for BString { + #[inline] + fn from(s: &'a BStr) -> BString { + BString::from(s.bytes.to_vec()) + } + } + + impl<'a> From for Cow<'a, BStr> { + #[inline] + fn from(s: BString) -> Cow<'a, BStr> { + Cow::Owned(s) + } + } + + impl FromIterator for BString { + #[inline] + fn from_iter>(iter: T) -> BString { + BString::from(iter.into_iter().collect::()) + } + } + + impl FromIterator for BString { + #[inline] + fn from_iter>(iter: T) -> BString { + BString::from(iter.into_iter().collect::>()) + } + } + + impl<'a> FromIterator<&'a str> for BString { + #[inline] + fn from_iter>(iter: T) -> BString { + let mut buf = vec![]; + for b in iter { + buf.push_str(b); + } + BString::from(buf) + } + } + + impl<'a> FromIterator<&'a [u8]> for BString { + #[inline] + fn from_iter>(iter: T) -> BString { + let mut buf = vec![]; + for b in iter { + buf.push_str(b); + } + BString::from(buf) + } + } + + impl<'a> FromIterator<&'a BStr> for BString { + #[inline] + fn from_iter>(iter: T) -> BString { + let mut buf = vec![]; + for b in iter { + buf.push_str(b); + } + BString::from(buf) + } + } + + impl FromIterator for BString { + #[inline] + fn from_iter>(iter: T) -> BString { + let mut buf = vec![]; + for b in iter { + buf.push_str(b); + } + BString::from(buf) + } + } + + impl Eq for BString {} + + impl PartialEq for BString { + #[inline] + fn eq(&self, other: &BString) -> bool { + &self[..] == &other[..] + } + } + + impl_partial_eq!(BString, Vec); + impl_partial_eq!(BString, [u8]); + impl_partial_eq!(BString, &'a [u8]); + impl_partial_eq!(BString, String); + impl_partial_eq!(BString, str); + impl_partial_eq!(BString, &'a str); + impl_partial_eq!(BString, BStr); + impl_partial_eq!(BString, &'a BStr); + + impl PartialOrd for BString { + #[inline] + fn partial_cmp(&self, other: &BString) -> Option { + PartialOrd::partial_cmp(&self.bytes, &other.bytes) + } + } + + impl Ord for BString { + #[inline] + fn cmp(&self, other: &BString) -> Ordering { + self.partial_cmp(other).unwrap() + } + } + + impl_partial_ord!(BString, Vec); + impl_partial_ord!(BString, [u8]); + impl_partial_ord!(BString, &'a [u8]); + impl_partial_ord!(BString, String); + impl_partial_ord!(BString, str); + impl_partial_ord!(BString, &'a str); + impl_partial_ord!(BString, BStr); + impl_partial_ord!(BString, &'a BStr); +} + +mod bstr { + #[cfg(feature = "std")] + use std::borrow::Cow; + + use core::cmp::Ordering; + use core::fmt; + use core::ops; + + use crate::bstr::BStr; + use crate::ext_slice::ByteSlice; + + impl fmt::Display for BStr { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// Write the given bstr (lossily) to the given formatter. + fn write_bstr( + f: &mut fmt::Formatter<'_>, + bstr: &BStr, + ) -> Result<(), fmt::Error> { + for chunk in bstr.utf8_chunks() { + f.write_str(chunk.valid())?; + if !chunk.invalid().is_empty() { + f.write_str("\u{FFFD}")?; + } + } + Ok(()) + } + + /// Write 'num' fill characters to the given formatter. + fn write_pads( + f: &mut fmt::Formatter<'_>, + num: usize, + ) -> fmt::Result { + let fill = f.fill(); + for _ in 0..num { + f.write_fmt(format_args!("{}", fill))?; + } + Ok(()) + } + + if let Some(align) = f.align() { + let width = f.width().unwrap_or(0); + let nchars = self.chars().count(); + let remaining_pads = width.saturating_sub(nchars); + match align { + fmt::Alignment::Left => { + write_bstr(f, self)?; + write_pads(f, remaining_pads)?; + } + fmt::Alignment::Right => { + write_pads(f, remaining_pads)?; + write_bstr(f, self)?; + } + fmt::Alignment::Center => { + let half = remaining_pads / 2; + let second_half = if remaining_pads % 2 == 0 { + half + } else { + half + 1 + }; + write_pads(f, half)?; + write_bstr(f, self)?; + write_pads(f, second_half)?; + } + } + Ok(()) + } else { + write_bstr(f, self)?; + Ok(()) + } + } + } + + impl fmt::Debug for BStr { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "\"")?; + for (s, e, ch) in self.char_indices() { + match ch { + '\0' => write!(f, "\\0")?, + '\u{FFFD}' => { + let bytes = self[s..e].as_bytes(); + if bytes == b"\xEF\xBF\xBD" { + write!(f, "{}", ch.escape_debug())?; + } else { + for &b in self[s..e].as_bytes() { + write!(f, r"\x{:02X}", b)?; + } + } + } + // ASCII control characters except \0, \n, \r, \t + '\x01'..='\x08' + | '\x0b' + | '\x0c' + | '\x0e'..='\x19' + | '\x7f' => { + write!(f, "\\x{:02x}", ch as u32)?; + } + '\n' | '\r' | '\t' | _ => { + write!(f, "{}", ch.escape_debug())?; + } + } + } + write!(f, "\"")?; + Ok(()) + } + } + + impl ops::Deref for BStr { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + &self.bytes + } + } + + impl ops::DerefMut for BStr { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + &mut self.bytes + } + } + + impl ops::Index for BStr { + type Output = u8; + + #[inline] + fn index(&self, idx: usize) -> &u8 { + &self.as_bytes()[idx] + } + } + + impl ops::Index for BStr { + type Output = BStr; + + #[inline] + fn index(&self, _: ops::RangeFull) -> &BStr { + self + } + } + + impl ops::Index> for BStr { + type Output = BStr; + + #[inline] + fn index(&self, r: ops::Range) -> &BStr { + BStr::new(&self.as_bytes()[r.start..r.end]) + } + } + + impl ops::Index> for BStr { + type Output = BStr; + + #[inline] + fn index(&self, r: ops::RangeInclusive) -> &BStr { + BStr::new(&self.as_bytes()[*r.start()..=*r.end()]) + } + } + + impl ops::Index> for BStr { + type Output = BStr; + + #[inline] + fn index(&self, r: ops::RangeFrom) -> &BStr { + BStr::new(&self.as_bytes()[r.start..]) + } + } + + impl ops::Index> for BStr { + type Output = BStr; + + #[inline] + fn index(&self, r: ops::RangeTo) -> &BStr { + BStr::new(&self.as_bytes()[..r.end]) + } + } + + impl ops::Index> for BStr { + type Output = BStr; + + #[inline] + fn index(&self, r: ops::RangeToInclusive) -> &BStr { + BStr::new(&self.as_bytes()[..=r.end]) + } + } + + impl ops::IndexMut for BStr { + #[inline] + fn index_mut(&mut self, idx: usize) -> &mut u8 { + &mut self.bytes[idx] + } + } + + impl ops::IndexMut for BStr { + #[inline] + fn index_mut(&mut self, _: ops::RangeFull) -> &mut BStr { + self + } + } + + impl ops::IndexMut> for BStr { + #[inline] + fn index_mut(&mut self, r: ops::Range) -> &mut BStr { + BStr::from_bytes_mut(&mut self.bytes[r.start..r.end]) + } + } + + impl ops::IndexMut> for BStr { + #[inline] + fn index_mut(&mut self, r: ops::RangeInclusive) -> &mut BStr { + BStr::from_bytes_mut(&mut self.bytes[*r.start()..=*r.end()]) + } + } + + impl ops::IndexMut> for BStr { + #[inline] + fn index_mut(&mut self, r: ops::RangeFrom) -> &mut BStr { + BStr::from_bytes_mut(&mut self.bytes[r.start..]) + } + } + + impl ops::IndexMut> for BStr { + #[inline] + fn index_mut(&mut self, r: ops::RangeTo) -> &mut BStr { + BStr::from_bytes_mut(&mut self.bytes[..r.end]) + } + } + + impl ops::IndexMut> for BStr { + #[inline] + fn index_mut(&mut self, r: ops::RangeToInclusive) -> &mut BStr { + BStr::from_bytes_mut(&mut self.bytes[..=r.end]) + } + } + + impl AsRef<[u8]> for BStr { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } + } + + impl AsRef for [u8] { + #[inline] + fn as_ref(&self) -> &BStr { + BStr::new(self) + } + } + + impl AsRef for str { + #[inline] + fn as_ref(&self) -> &BStr { + BStr::new(self) + } + } + + impl AsMut<[u8]> for BStr { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + &mut self.bytes + } + } + + impl AsMut for [u8] { + #[inline] + fn as_mut(&mut self) -> &mut BStr { + BStr::new_mut(self) + } + } + + impl<'a> Default for &'a BStr { + fn default() -> &'a BStr { + BStr::from_bytes(b"") + } + } + + impl<'a> Default for &'a mut BStr { + fn default() -> &'a mut BStr { + BStr::from_bytes_mut(&mut []) + } + } + + impl<'a> From<&'a [u8]> for &'a BStr { + #[inline] + fn from(s: &'a [u8]) -> &'a BStr { + BStr::from_bytes(s) + } + } + + impl<'a> From<&'a str> for &'a BStr { + #[inline] + fn from(s: &'a str) -> &'a BStr { + BStr::from_bytes(s.as_bytes()) + } + } + + #[cfg(feature = "std")] + impl<'a> From<&'a BStr> for Cow<'a, BStr> { + #[inline] + fn from(s: &'a BStr) -> Cow<'a, BStr> { + Cow::Borrowed(s) + } + } + + #[cfg(feature = "std")] + impl From> for Box { + #[inline] + fn from(s: Box<[u8]>) -> Box { + BStr::from_boxed_bytes(s) + } + } + + #[cfg(feature = "std")] + impl From> for Box<[u8]> { + #[inline] + fn from(s: Box) -> Box<[u8]> { + BStr::into_boxed_bytes(s) + } + } + + impl Eq for BStr {} + + impl PartialEq for BStr { + #[inline] + fn eq(&self, other: &BStr) -> bool { + self.as_bytes() == other.as_bytes() + } + } + + impl_partial_eq!(BStr, [u8]); + impl_partial_eq!(BStr, &'a [u8]); + impl_partial_eq!(BStr, str); + impl_partial_eq!(BStr, &'a str); + + #[cfg(feature = "std")] + impl_partial_eq!(BStr, Vec); + #[cfg(feature = "std")] + impl_partial_eq!(&'a BStr, Vec); + #[cfg(feature = "std")] + impl_partial_eq!(BStr, String); + #[cfg(feature = "std")] + impl_partial_eq!(&'a BStr, String); + #[cfg(feature = "std")] + impl_partial_eq_cow!(&'a BStr, Cow<'a, BStr>); + #[cfg(feature = "std")] + impl_partial_eq_cow!(&'a BStr, Cow<'a, str>); + #[cfg(feature = "std")] + impl_partial_eq_cow!(&'a BStr, Cow<'a, [u8]>); + + impl PartialOrd for BStr { + #[inline] + fn partial_cmp(&self, other: &BStr) -> Option { + PartialOrd::partial_cmp(self.as_bytes(), other.as_bytes()) + } + } + + impl Ord for BStr { + #[inline] + fn cmp(&self, other: &BStr) -> Ordering { + self.partial_cmp(other).unwrap() + } + } + + impl_partial_ord!(BStr, [u8]); + impl_partial_ord!(BStr, &'a [u8]); + impl_partial_ord!(BStr, str); + impl_partial_ord!(BStr, &'a str); + + #[cfg(feature = "std")] + impl_partial_ord!(BStr, Vec); + #[cfg(feature = "std")] + impl_partial_ord!(&'a BStr, Vec); + #[cfg(feature = "std")] + impl_partial_ord!(BStr, String); + #[cfg(feature = "std")] + impl_partial_ord!(&'a BStr, String); +} + +#[cfg(feature = "serde1-nostd")] +mod bstr_serde { + use core::fmt; + + use serde::{ + de::Error, de::Visitor, Deserialize, Deserializer, Serialize, + Serializer, + }; + + use crate::bstr::BStr; + + impl Serialize for BStr { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_bytes(self.as_bytes()) + } + } + + impl<'a, 'de: 'a> Deserialize<'de> for &'a BStr { + #[inline] + fn deserialize(deserializer: D) -> Result<&'a BStr, D::Error> + where + D: Deserializer<'de>, + { + struct BStrVisitor; + + impl<'de> Visitor<'de> for BStrVisitor { + type Value = &'de BStr; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("a borrowed byte string") + } + + #[inline] + fn visit_borrowed_bytes( + self, + value: &'de [u8], + ) -> Result<&'de BStr, E> { + Ok(BStr::new(value)) + } + + #[inline] + fn visit_borrowed_str( + self, + value: &'de str, + ) -> Result<&'de BStr, E> { + Ok(BStr::new(value)) + } + } + + deserializer.deserialize_bytes(BStrVisitor) + } + } +} + +#[cfg(feature = "serde1")] +mod bstring_serde { + use std::cmp; + use std::fmt; + + use serde::{ + de::Error, de::SeqAccess, de::Visitor, Deserialize, Deserializer, + Serialize, Serializer, + }; + + use crate::bstring::BString; + + impl Serialize for BString { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_bytes(self.as_bytes()) + } + } + + impl<'de> Deserialize<'de> for BString { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct BStringVisitor; + + impl<'de> Visitor<'de> for BStringVisitor { + type Value = BString; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("a byte string") + } + + #[inline] + fn visit_seq>( + self, + mut visitor: V, + ) -> Result { + let len = cmp::min(visitor.size_hint().unwrap_or(0), 256); + let mut bytes = Vec::with_capacity(len); + while let Some(v) = visitor.next_element()? { + bytes.push(v); + } + Ok(BString::from(bytes)) + } + + #[inline] + fn visit_bytes( + self, + value: &[u8], + ) -> Result { + Ok(BString::from(value)) + } + + #[inline] + fn visit_byte_buf( + self, + value: Vec, + ) -> Result { + Ok(BString::from(value)) + } + + #[inline] + fn visit_str( + self, + value: &str, + ) -> Result { + Ok(BString::from(value)) + } + + #[inline] + fn visit_string( + self, + value: String, + ) -> Result { + Ok(BString::from(value)) + } + } + + deserializer.deserialize_byte_buf(BStringVisitor) + } + } +} + +#[cfg(test)] +mod display { + use crate::bstring::BString; + use crate::ByteSlice; + + #[test] + fn clean() { + assert_eq!(&format!("{}", &b"abc".as_bstr()), "abc"); + assert_eq!(&format!("{}", &b"\xf0\x28\x8c\xbc".as_bstr()), "�(��"); + } + + #[test] + fn width_bigger_than_bstr() { + assert_eq!(&format!("{:<7}!", &b"abc".as_bstr()), "abc !"); + assert_eq!(&format!("{:>7}!", &b"abc".as_bstr()), " abc!"); + assert_eq!(&format!("{:^7}!", &b"abc".as_bstr()), " abc !"); + assert_eq!(&format!("{:^6}!", &b"abc".as_bstr()), " abc !"); + assert_eq!(&format!("{:-<7}!", &b"abc".as_bstr()), "abc----!"); + assert_eq!(&format!("{:->7}!", &b"abc".as_bstr()), "----abc!"); + assert_eq!(&format!("{:-^7}!", &b"abc".as_bstr()), "--abc--!"); + assert_eq!(&format!("{:-^6}!", &b"abc".as_bstr()), "-abc--!"); + + assert_eq!( + &format!("{:<7}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + "�(�� !" + ); + assert_eq!( + &format!("{:>7}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + " �(��!" + ); + assert_eq!( + &format!("{:^7}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + " �(�� !" + ); + assert_eq!( + &format!("{:^6}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + " �(�� !" + ); + + assert_eq!( + &format!("{:-<7}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + "�(��---!" + ); + assert_eq!( + &format!("{:->7}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + "---�(��!" + ); + assert_eq!( + &format!("{:-^7}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + "-�(��--!" + ); + assert_eq!( + &format!("{:-^6}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + "-�(��-!" + ); + } + + #[test] + fn width_lesser_than_bstr() { + assert_eq!(&format!("{:<2}!", &b"abc".as_bstr()), "abc!"); + assert_eq!(&format!("{:>2}!", &b"abc".as_bstr()), "abc!"); + assert_eq!(&format!("{:^2}!", &b"abc".as_bstr()), "abc!"); + assert_eq!(&format!("{:-<2}!", &b"abc".as_bstr()), "abc!"); + assert_eq!(&format!("{:->2}!", &b"abc".as_bstr()), "abc!"); + assert_eq!(&format!("{:-^2}!", &b"abc".as_bstr()), "abc!"); + + assert_eq!( + &format!("{:<3}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + "�(��!" + ); + assert_eq!( + &format!("{:>3}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + "�(��!" + ); + assert_eq!( + &format!("{:^3}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + "�(��!" + ); + assert_eq!( + &format!("{:^2}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + "�(��!" + ); + + assert_eq!( + &format!("{:-<3}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + "�(��!" + ); + assert_eq!( + &format!("{:->3}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + "�(��!" + ); + assert_eq!( + &format!("{:-^3}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + "�(��!" + ); + assert_eq!( + &format!("{:-^2}!", &b"\xf0\x28\x8c\xbc".as_bstr()), + "�(��!" + ); + } + + quickcheck::quickcheck! { + fn total_length(bstr: BString) -> bool { + let size = bstr.chars().count(); + format!("{:<1$}", bstr.as_bstr(), size).chars().count() >= size + } + } +} + +#[cfg(test)] +mod bstring_arbitrary { + use crate::bstring::BString; + + use quickcheck::{Arbitrary, Gen}; + + impl Arbitrary for BString { + fn arbitrary(g: &mut Gen) -> BString { + BString::from(Vec::::arbitrary(g)) + } + + fn shrink(&self) -> Box> { + Box::new(self.bytes.shrink().map(BString::from)) + } + } +} + +#[test] +fn test_debug() { + use crate::{ByteSlice, B}; + + assert_eq!( + r#""\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp""#, + format!("{:?}", b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp".as_bstr()), + ); + + // Tests that if the underlying bytes contain the UTF-8 encoding of the + // replacement codepoint, then we emit the codepoint just like other + // non-printable Unicode characters. + assert_eq!( + b"\"\\xFF\xEF\xBF\xBD\\xFF\"".as_bstr(), + // Before fixing #72, the output here would be: + // \\xFF\\xEF\\xBF\\xBD\\xFF + B(&format!("{:?}", b"\xFF\xEF\xBF\xBD\xFF".as_bstr())).as_bstr(), + ); +} + +// See: https://github.com/BurntSushi/bstr/issues/82 +#[test] +fn test_cows_regression() { + use crate::ByteSlice; + use std::borrow::Cow; + + let c1 = Cow::from(b"hello bstr".as_bstr()); + let c2 = b"goodbye bstr".as_bstr(); + assert_ne!(c1, c2); + + let c3 = Cow::from("hello str"); + let c4 = "goodbye str"; + assert_ne!(c3, c4); +} diff --git a/vendor/bstr-0.2.17/src/io.rs b/vendor/bstr-0.2.17/src/io.rs new file mode 100644 index 0000000000000..ad6f3c1bb930a --- /dev/null +++ b/vendor/bstr-0.2.17/src/io.rs @@ -0,0 +1,514 @@ +/*! +Utilities for working with I/O using byte strings. + +This module currently only exports a single trait, `BufReadExt`, which provides +facilities for conveniently and efficiently working with lines as byte strings. + +More APIs may be added in the future. +*/ + +use std::io; + +use crate::ext_slice::ByteSlice; +use crate::ext_vec::ByteVec; + +/// An extention trait for +/// [`std::io::BufRead`](https://doc.rust-lang.org/std/io/trait.BufRead.html) +/// which provides convenience APIs for dealing with byte strings. +pub trait BufReadExt: io::BufRead { + /// Returns an iterator over the lines of this reader, where each line + /// is represented as a byte string. + /// + /// Each item yielded by this iterator is a `io::Result>`, where + /// an error is yielded if there was a problem reading from the underlying + /// reader. + /// + /// On success, the next line in the iterator is returned. The line does + /// *not* contain a trailing `\n` or `\r\n`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::io; + /// + /// use bstr::io::BufReadExt; + /// + /// # fn example() -> Result<(), io::Error> { + /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor"); + /// + /// let mut lines = vec![]; + /// for result in cursor.byte_lines() { + /// let line = result?; + /// lines.push(line); + /// } + /// assert_eq!(lines.len(), 3); + /// assert_eq!(lines[0], "lorem".as_bytes()); + /// assert_eq!(lines[1], "ipsum".as_bytes()); + /// assert_eq!(lines[2], "dolor".as_bytes()); + /// # Ok(()) }; example().unwrap() + /// ``` + fn byte_lines(self) -> ByteLines + where + Self: Sized, + { + ByteLines { buf: self } + } + + /// Returns an iterator over byte-terminated records of this reader, where + /// each record is represented as a byte string. + /// + /// Each item yielded by this iterator is a `io::Result>`, where + /// an error is yielded if there was a problem reading from the underlying + /// reader. + /// + /// On success, the next record in the iterator is returned. The record + /// does *not* contain its trailing terminator. + /// + /// Note that calling `byte_records(b'\n')` differs from `byte_lines()` in + /// that it has no special handling for `\r`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::io; + /// + /// use bstr::io::BufReadExt; + /// + /// # fn example() -> Result<(), io::Error> { + /// let cursor = io::Cursor::new(b"lorem\x00ipsum\x00dolor"); + /// + /// let mut records = vec![]; + /// for result in cursor.byte_records(b'\x00') { + /// let record = result?; + /// records.push(record); + /// } + /// assert_eq!(records.len(), 3); + /// assert_eq!(records[0], "lorem".as_bytes()); + /// assert_eq!(records[1], "ipsum".as_bytes()); + /// assert_eq!(records[2], "dolor".as_bytes()); + /// # Ok(()) }; example().unwrap() + /// ``` + fn byte_records(self, terminator: u8) -> ByteRecords + where + Self: Sized, + { + ByteRecords { terminator, buf: self } + } + + /// Executes the given closure on each line in the underlying reader. + /// + /// If the closure returns an error (or if the underlying reader returns an + /// error), then iteration is stopped and the error is returned. If false + /// is returned, then iteration is stopped and no error is returned. + /// + /// The closure given is called on exactly the same values as yielded by + /// the [`byte_lines`](trait.BufReadExt.html#method.byte_lines) + /// iterator. Namely, lines do _not_ contain trailing `\n` or `\r\n` bytes. + /// + /// This routine is useful for iterating over lines as quickly as + /// possible. Namely, a single allocation is reused for each line. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::io; + /// + /// use bstr::io::BufReadExt; + /// + /// # fn example() -> Result<(), io::Error> { + /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor"); + /// + /// let mut lines = vec![]; + /// cursor.for_byte_line(|line| { + /// lines.push(line.to_vec()); + /// Ok(true) + /// })?; + /// assert_eq!(lines.len(), 3); + /// assert_eq!(lines[0], "lorem".as_bytes()); + /// assert_eq!(lines[1], "ipsum".as_bytes()); + /// assert_eq!(lines[2], "dolor".as_bytes()); + /// # Ok(()) }; example().unwrap() + /// ``` + fn for_byte_line(self, mut for_each_line: F) -> io::Result<()> + where + Self: Sized, + F: FnMut(&[u8]) -> io::Result, + { + self.for_byte_line_with_terminator(|line| { + for_each_line(&trim_line_slice(&line)) + }) + } + + /// Executes the given closure on each byte-terminated record in the + /// underlying reader. + /// + /// If the closure returns an error (or if the underlying reader returns an + /// error), then iteration is stopped and the error is returned. If false + /// is returned, then iteration is stopped and no error is returned. + /// + /// The closure given is called on exactly the same values as yielded by + /// the [`byte_records`](trait.BufReadExt.html#method.byte_records) + /// iterator. Namely, records do _not_ contain a trailing terminator byte. + /// + /// This routine is useful for iterating over records as quickly as + /// possible. Namely, a single allocation is reused for each record. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::io; + /// + /// use bstr::io::BufReadExt; + /// + /// # fn example() -> Result<(), io::Error> { + /// let cursor = io::Cursor::new(b"lorem\x00ipsum\x00dolor"); + /// + /// let mut records = vec![]; + /// cursor.for_byte_record(b'\x00', |record| { + /// records.push(record.to_vec()); + /// Ok(true) + /// })?; + /// assert_eq!(records.len(), 3); + /// assert_eq!(records[0], "lorem".as_bytes()); + /// assert_eq!(records[1], "ipsum".as_bytes()); + /// assert_eq!(records[2], "dolor".as_bytes()); + /// # Ok(()) }; example().unwrap() + /// ``` + fn for_byte_record( + self, + terminator: u8, + mut for_each_record: F, + ) -> io::Result<()> + where + Self: Sized, + F: FnMut(&[u8]) -> io::Result, + { + self.for_byte_record_with_terminator(terminator, |chunk| { + for_each_record(&trim_record_slice(&chunk, terminator)) + }) + } + + /// Executes the given closure on each line in the underlying reader. + /// + /// If the closure returns an error (or if the underlying reader returns an + /// error), then iteration is stopped and the error is returned. If false + /// is returned, then iteration is stopped and no error is returned. + /// + /// Unlike + /// [`for_byte_line`](trait.BufReadExt.html#method.for_byte_line), + /// the lines given to the closure *do* include the line terminator, if one + /// exists. + /// + /// This routine is useful for iterating over lines as quickly as + /// possible. Namely, a single allocation is reused for each line. + /// + /// This is identical to `for_byte_record_with_terminator` with a + /// terminator of `\n`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::io; + /// + /// use bstr::io::BufReadExt; + /// + /// # fn example() -> Result<(), io::Error> { + /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor"); + /// + /// let mut lines = vec![]; + /// cursor.for_byte_line_with_terminator(|line| { + /// lines.push(line.to_vec()); + /// Ok(true) + /// })?; + /// assert_eq!(lines.len(), 3); + /// assert_eq!(lines[0], "lorem\n".as_bytes()); + /// assert_eq!(lines[1], "ipsum\r\n".as_bytes()); + /// assert_eq!(lines[2], "dolor".as_bytes()); + /// # Ok(()) }; example().unwrap() + /// ``` + fn for_byte_line_with_terminator( + self, + for_each_line: F, + ) -> io::Result<()> + where + Self: Sized, + F: FnMut(&[u8]) -> io::Result, + { + self.for_byte_record_with_terminator(b'\n', for_each_line) + } + + /// Executes the given closure on each byte-terminated record in the + /// underlying reader. + /// + /// If the closure returns an error (or if the underlying reader returns an + /// error), then iteration is stopped and the error is returned. If false + /// is returned, then iteration is stopped and no error is returned. + /// + /// Unlike + /// [`for_byte_record`](trait.BufReadExt.html#method.for_byte_record), + /// the lines given to the closure *do* include the record terminator, if + /// one exists. + /// + /// This routine is useful for iterating over records as quickly as + /// possible. Namely, a single allocation is reused for each record. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::io; + /// + /// use bstr::B; + /// use bstr::io::BufReadExt; + /// + /// # fn example() -> Result<(), io::Error> { + /// let cursor = io::Cursor::new(b"lorem\x00ipsum\x00dolor"); + /// + /// let mut records = vec![]; + /// cursor.for_byte_record_with_terminator(b'\x00', |record| { + /// records.push(record.to_vec()); + /// Ok(true) + /// })?; + /// assert_eq!(records.len(), 3); + /// assert_eq!(records[0], B(b"lorem\x00")); + /// assert_eq!(records[1], B("ipsum\x00")); + /// assert_eq!(records[2], B("dolor")); + /// # Ok(()) }; example().unwrap() + /// ``` + fn for_byte_record_with_terminator( + mut self, + terminator: u8, + mut for_each_record: F, + ) -> io::Result<()> + where + Self: Sized, + F: FnMut(&[u8]) -> io::Result, + { + let mut bytes = vec![]; + let mut res = Ok(()); + let mut consumed = 0; + 'outer: loop { + // Lend out complete record slices from our buffer + { + let mut buf = self.fill_buf()?; + while let Some(index) = buf.find_byte(terminator) { + let (record, rest) = buf.split_at(index + 1); + buf = rest; + consumed += record.len(); + match for_each_record(&record) { + Ok(false) => break 'outer, + Err(err) => { + res = Err(err); + break 'outer; + } + _ => (), + } + } + + // Copy the final record fragment to our local buffer. This + // saves read_until() from re-scanning a buffer we know + // contains no remaining terminators. + bytes.extend_from_slice(&buf); + consumed += buf.len(); + } + + self.consume(consumed); + consumed = 0; + + // N.B. read_until uses a different version of memchr that may + // be slower than the memchr crate that bstr uses. However, this + // should only run for a fairly small number of records, assuming a + // decent buffer size. + self.read_until(terminator, &mut bytes)?; + if bytes.is_empty() || !for_each_record(&bytes)? { + break; + } + bytes.clear(); + } + self.consume(consumed); + res + } +} + +impl BufReadExt for B {} + +/// An iterator over lines from an instance of +/// [`std::io::BufRead`](https://doc.rust-lang.org/std/io/trait.BufRead.html). +/// +/// This iterator is generally created by calling the +/// [`byte_lines`](trait.BufReadExt.html#method.byte_lines) +/// method on the +/// [`BufReadExt`](trait.BufReadExt.html) +/// trait. +#[derive(Debug)] +pub struct ByteLines { + buf: B, +} + +/// An iterator over records from an instance of +/// [`std::io::BufRead`](https://doc.rust-lang.org/std/io/trait.BufRead.html). +/// +/// A byte record is any sequence of bytes terminated by a particular byte +/// chosen by the caller. For example, NUL separated byte strings are said to +/// be NUL-terminated byte records. +/// +/// This iterator is generally created by calling the +/// [`byte_records`](trait.BufReadExt.html#method.byte_records) +/// method on the +/// [`BufReadExt`](trait.BufReadExt.html) +/// trait. +#[derive(Debug)] +pub struct ByteRecords { + buf: B, + terminator: u8, +} + +impl Iterator for ByteLines { + type Item = io::Result>; + + fn next(&mut self) -> Option>> { + let mut bytes = vec![]; + match self.buf.read_until(b'\n', &mut bytes) { + Err(e) => Some(Err(e)), + Ok(0) => None, + Ok(_) => { + trim_line(&mut bytes); + Some(Ok(bytes)) + } + } + } +} + +impl Iterator for ByteRecords { + type Item = io::Result>; + + fn next(&mut self) -> Option>> { + let mut bytes = vec![]; + match self.buf.read_until(self.terminator, &mut bytes) { + Err(e) => Some(Err(e)), + Ok(0) => None, + Ok(_) => { + trim_record(&mut bytes, self.terminator); + Some(Ok(bytes)) + } + } + } +} + +fn trim_line(line: &mut Vec) { + if line.last_byte() == Some(b'\n') { + line.pop_byte(); + if line.last_byte() == Some(b'\r') { + line.pop_byte(); + } + } +} + +fn trim_line_slice(mut line: &[u8]) -> &[u8] { + if line.last_byte() == Some(b'\n') { + line = &line[..line.len() - 1]; + if line.last_byte() == Some(b'\r') { + line = &line[..line.len() - 1]; + } + } + line +} + +fn trim_record(record: &mut Vec, terminator: u8) { + if record.last_byte() == Some(terminator) { + record.pop_byte(); + } +} + +fn trim_record_slice(mut record: &[u8], terminator: u8) -> &[u8] { + if record.last_byte() == Some(terminator) { + record = &record[..record.len() - 1]; + } + record +} + +#[cfg(test)] +mod tests { + use super::BufReadExt; + use crate::bstring::BString; + + fn collect_lines>(slice: B) -> Vec { + let mut lines = vec![]; + slice + .as_ref() + .for_byte_line(|line| { + lines.push(BString::from(line.to_vec())); + Ok(true) + }) + .unwrap(); + lines + } + + fn collect_lines_term>(slice: B) -> Vec { + let mut lines = vec![]; + slice + .as_ref() + .for_byte_line_with_terminator(|line| { + lines.push(BString::from(line.to_vec())); + Ok(true) + }) + .unwrap(); + lines + } + + #[test] + fn lines_without_terminator() { + assert_eq!(collect_lines(""), Vec::::new()); + + assert_eq!(collect_lines("\n"), vec![""]); + assert_eq!(collect_lines("\n\n"), vec!["", ""]); + assert_eq!(collect_lines("a\nb\n"), vec!["a", "b"]); + assert_eq!(collect_lines("a\nb"), vec!["a", "b"]); + assert_eq!(collect_lines("abc\nxyz\n"), vec!["abc", "xyz"]); + assert_eq!(collect_lines("abc\nxyz"), vec!["abc", "xyz"]); + + assert_eq!(collect_lines("\r\n"), vec![""]); + assert_eq!(collect_lines("\r\n\r\n"), vec!["", ""]); + assert_eq!(collect_lines("a\r\nb\r\n"), vec!["a", "b"]); + assert_eq!(collect_lines("a\r\nb"), vec!["a", "b"]); + assert_eq!(collect_lines("abc\r\nxyz\r\n"), vec!["abc", "xyz"]); + assert_eq!(collect_lines("abc\r\nxyz"), vec!["abc", "xyz"]); + + assert_eq!(collect_lines("abc\rxyz"), vec!["abc\rxyz"]); + } + + #[test] + fn lines_with_terminator() { + assert_eq!(collect_lines_term(""), Vec::::new()); + + assert_eq!(collect_lines_term("\n"), vec!["\n"]); + assert_eq!(collect_lines_term("\n\n"), vec!["\n", "\n"]); + assert_eq!(collect_lines_term("a\nb\n"), vec!["a\n", "b\n"]); + assert_eq!(collect_lines_term("a\nb"), vec!["a\n", "b"]); + assert_eq!(collect_lines_term("abc\nxyz\n"), vec!["abc\n", "xyz\n"]); + assert_eq!(collect_lines_term("abc\nxyz"), vec!["abc\n", "xyz"]); + + assert_eq!(collect_lines_term("\r\n"), vec!["\r\n"]); + assert_eq!(collect_lines_term("\r\n\r\n"), vec!["\r\n", "\r\n"]); + assert_eq!(collect_lines_term("a\r\nb\r\n"), vec!["a\r\n", "b\r\n"]); + assert_eq!(collect_lines_term("a\r\nb"), vec!["a\r\n", "b"]); + assert_eq!( + collect_lines_term("abc\r\nxyz\r\n"), + vec!["abc\r\n", "xyz\r\n"] + ); + assert_eq!(collect_lines_term("abc\r\nxyz"), vec!["abc\r\n", "xyz"]); + + assert_eq!(collect_lines_term("abc\rxyz"), vec!["abc\rxyz"]); + } +} diff --git a/vendor/bstr-0.2.17/src/lib.rs b/vendor/bstr-0.2.17/src/lib.rs new file mode 100644 index 0000000000000..41142c9c2fc55 --- /dev/null +++ b/vendor/bstr-0.2.17/src/lib.rs @@ -0,0 +1,437 @@ +/*! +A byte string library. + +Byte strings are just like standard Unicode strings with one very important +difference: byte strings are only *conventionally* UTF-8 while Rust's standard +Unicode strings are *guaranteed* to be valid UTF-8. The primary motivation for +byte strings is for handling arbitrary bytes that are mostly UTF-8. + +# Overview + +This crate provides two important traits that provide string oriented methods +on `&[u8]` and `Vec` types: + +* [`ByteSlice`](trait.ByteSlice.html) extends the `[u8]` type with additional + string oriented methods. +* [`ByteVec`](trait.ByteVec.html) extends the `Vec` type with additional + string oriented methods. + +Additionally, this crate provides two concrete byte string types that deref to +`[u8]` and `Vec`. These are useful for storing byte string types, and come +with convenient `std::fmt::Debug` implementations: + +* [`BStr`](struct.BStr.html) is a byte string slice, analogous to `str`. +* [`BString`](struct.BString.html) is an owned growable byte string buffer, + analogous to `String`. + +Additionally, the free function [`B`](fn.B.html) serves as a convenient short +hand for writing byte string literals. + +# Quick examples + +Byte strings build on the existing APIs for `Vec` and `&[u8]`, with +additional string oriented methods. Operations such as iterating over +graphemes, searching for substrings, replacing substrings, trimming and case +conversion are examples of things not provided on the standard library `&[u8]` +APIs but are provided by this crate. For example, this code iterates over all +of occurrences of a subtring: + +``` +use bstr::ByteSlice; + +let s = b"foo bar foo foo quux foo"; + +let mut matches = vec![]; +for start in s.find_iter("foo") { + matches.push(start); +} +assert_eq!(matches, [0, 8, 12, 21]); +``` + +Here's another example showing how to do a search and replace (and also showing +use of the `B` function): + +``` +use bstr::{B, ByteSlice}; + +let old = B("foo ☃☃☃ foo foo quux foo"); +let new = old.replace("foo", "hello"); +assert_eq!(new, B("hello ☃☃☃ hello hello quux hello")); +``` + +And here's an example that shows case conversion, even in the presence of +invalid UTF-8: + +``` +use bstr::{ByteSlice, ByteVec}; + +let mut lower = Vec::from("hello β"); +lower[0] = b'\xFF'; +// lowercase β is uppercased to Î’ +assert_eq!(lower.to_uppercase(), b"\xFFELLO \xCE\x92"); +``` + +# Convenient debug representation + +When working with byte strings, it is often useful to be able to print them +as if they were byte strings and not sequences of integers. While this crate +cannot affect the `std::fmt::Debug` implementations for `[u8]` and `Vec`, +this crate does provide the `BStr` and `BString` types which have convenient +`std::fmt::Debug` implementations. + +For example, this + +``` +use bstr::ByteSlice; + +let mut bytes = Vec::from("hello β"); +bytes[0] = b'\xFF'; + +println!("{:?}", bytes.as_bstr()); +``` + +will output `"\xFFello β"`. + +This example works because the +[`ByteSlice::as_bstr`](trait.ByteSlice.html#method.as_bstr) +method converts any `&[u8]` to a `&BStr`. + +# When should I use byte strings? + +This library reflects my hypothesis that UTF-8 by convention is a better trade +off in some circumstances than guaranteed UTF-8. It's possible, perhaps even +likely, that this is a niche concern for folks working closely with core text +primitives. + +The first time this idea hit me was in the implementation of Rust's regex +engine. In particular, very little of the internal implementation cares at all +about searching valid UTF-8 encoded strings. Indeed, internally, the +implementation converts `&str` from the API to `&[u8]` fairly quickly and +just deals with raw bytes. UTF-8 match boundaries are then guaranteed by the +finite state machine itself rather than any specific string type. This makes it +possible to not only run regexes on `&str` values, but also on `&[u8]` values. + +Why would you ever want to run a regex on a `&[u8]` though? Well, `&[u8]` is +the fundamental way at which one reads data from all sorts of streams, via the +standard library's [`Read`](https://doc.rust-lang.org/std/io/trait.Read.html) +trait. In particular, there is no platform independent way to determine whether +what you're reading from is some binary file or a human readable text file. +Therefore, if you're writing a program to search files, you probably need to +deal with `&[u8]` directly unless you're okay with first converting it to a +`&str` and dropping any bytes that aren't valid UTF-8. (Or otherwise determine +the encoding---which is often impractical---and perform a transcoding step.) +Often, the simplest and most robust way to approach this is to simply treat the +contents of a file as if it were mostly valid UTF-8 and pass through invalid +UTF-8 untouched. This may not be the most correct approach though! + +One case in particular exacerbates these issues, and that's memory mapping +a file. When you memory map a file, that file may be gigabytes big, but all +you get is a `&[u8]`. Converting that to a `&str` all in one go is generally +not a good idea because of the costs associated with doing so, and also +because it generally causes one to do two passes over the data instead of +one, which is quite undesirable. It is of course usually possible to do it an +incremental way by only parsing chunks at a time, but this is often complex to +do or impractical. For example, many regex engines only accept one contiguous +sequence of bytes at a time with no way to perform incremental matching. + +In summary, conventional UTF-8 byte strings provided by this library are +definitely useful in some limited circumstances, but how useful they are more +broadly isn't clear yet. + +# `bstr` in public APIs + +Since this library is not yet `1.0`, you should not use it in the public API of +your crates until it hits `1.0` (unless you're OK with with tracking breaking +releases of `bstr`). It is expected that `bstr 1.0` will be released before +2022. + +In general, it should be possible to avoid putting anything in this crate into +your public APIs. Namely, you should never need to use the `ByteSlice` or +`ByteVec` traits as bounds on public APIs, since their only purpose is to +extend the methods on the concrete types `[u8]` and `Vec`, respectively. +Similarly, it should not be necessary to put either the `BStr` or `BString` +types into public APIs. If you want to use them internally, then they can +be converted to/from `[u8]`/`Vec` as needed. + +# Differences with standard strings + +The primary difference between `[u8]` and `str` is that the former is +conventionally UTF-8 while the latter is guaranteed to be UTF-8. The phrase +"conventionally UTF-8" means that a `[u8]` may contain bytes that do not form +a valid UTF-8 sequence, but operations defined on the type in this crate are +generally most useful on valid UTF-8 sequences. For example, iterating over +Unicode codepoints or grapheme clusters is an operation that is only defined +on valid UTF-8. Therefore, when invalid UTF-8 is encountered, the Unicode +replacement codepoint is substituted. Thus, a byte string that is not UTF-8 at +all is of limited utility when using these crate. + +However, not all operations on byte strings are specifically Unicode aware. For +example, substring search has no specific Unicode semantics ascribed to it. It +works just as well for byte strings that are completely valid UTF-8 as for byte +strings that contain no valid UTF-8 at all. Similarly for replacements and +various other operations that do not need any Unicode specific tailoring. + +Aside from the difference in how UTF-8 is handled, the APIs between `[u8]` and +`str` (and `Vec` and `String`) are intentionally very similar, including +maintaining the same behavior for corner cases in things like substring +splitting. There are, however, some differences: + +* Substring search is not done with `matches`, but instead, `find_iter`. + In general, this crate does not define any generic + [`Pattern`](https://doc.rust-lang.org/std/str/pattern/trait.Pattern.html) + infrastructure, and instead prefers adding new methods for different + argument types. For example, `matches` can search by a `char` or a `&str`, + where as `find_iter` can only search by a byte string. `find_char` can be + used for searching by a `char`. +* Since `SliceConcatExt` in the standard library is unstable, it is not + possible to reuse that to implement `join` and `concat` methods. Instead, + [`join`](fn.join.html) and [`concat`](fn.concat.html) are provided as free + functions that perform a similar task. +* This library bundles in a few more Unicode operations, such as grapheme, + word and sentence iterators. More operations, such as normalization and + case folding, may be provided in the future. +* Some `String`/`str` APIs will panic if a particular index was not on a valid + UTF-8 code unit sequence boundary. Conversely, no such checking is performed + in this crate, as is consistent with treating byte strings as a sequence of + bytes. This means callers are responsible for maintaining a UTF-8 invariant + if that's important. +* Some routines provided by this crate, such as `starts_with_str`, have a + `_str` suffix to differentiate them from similar routines already defined + on the `[u8]` type. The difference is that `starts_with` requires its + parameter to be a `&[u8]`, where as `starts_with_str` permits its parameter + to by anything that implements `AsRef<[u8]>`, which is more flexible. This + means you can write `bytes.starts_with_str("☃")` instead of + `bytes.starts_with("☃".as_bytes())`. + +Otherwise, you should find most of the APIs between this crate and the standard +library string APIs to be very similar, if not identical. + +# Handling of invalid UTF-8 + +Since byte strings are only *conventionally* UTF-8, there is no guarantee +that byte strings contain valid UTF-8. Indeed, it is perfectly legal for a +byte string to contain arbitrary bytes. However, since this library defines +a *string* type, it provides many operations specified by Unicode. These +operations are typically only defined over codepoints, and thus have no real +meaning on bytes that are invalid UTF-8 because they do not map to a particular +codepoint. + +For this reason, whenever operations defined only on codepoints are used, this +library will automatically convert invalid UTF-8 to the Unicode replacement +codepoint, `U+FFFD`, which looks like this: `�`. For example, an +[iterator over codepoints](struct.Chars.html) will yield a Unicode +replacement codepoint whenever it comes across bytes that are not valid UTF-8: + +``` +use bstr::ByteSlice; + +let bs = b"a\xFF\xFFz"; +let chars: Vec = bs.chars().collect(); +assert_eq!(vec!['a', '\u{FFFD}', '\u{FFFD}', 'z'], chars); +``` + +There are a few ways in which invalid bytes can be substituted with a Unicode +replacement codepoint. One way, not used by this crate, is to replace every +individual invalid byte with a single replacement codepoint. In contrast, the +approach this crate uses is called the "substitution of maximal subparts," as +specified by the Unicode Standard (Chapter 3, Section 9). (This approach is +also used by [W3C's Encoding Standard](https://www.w3.org/TR/encoding/).) In +this strategy, a replacement codepoint is inserted whenever a byte is found +that cannot possibly lead to a valid UTF-8 code unit sequence. If there were +previous bytes that represented a *prefix* of a well-formed UTF-8 code unit +sequence, then all of those bytes (up to 3) are substituted with a single +replacement codepoint. For example: + +``` +use bstr::ByteSlice; + +let bs = b"a\xF0\x9F\x87z"; +let chars: Vec = bs.chars().collect(); +// The bytes \xF0\x9F\x87 could lead to a valid UTF-8 sequence, but 3 of them +// on their own are invalid. Only one replacement codepoint is substituted, +// which demonstrates the "substitution of maximal subparts" strategy. +assert_eq!(vec!['a', '\u{FFFD}', 'z'], chars); +``` + +If you do need to access the raw bytes for some reason in an iterator like +`Chars`, then you should use the iterator's "indices" variant, which gives +the byte offsets containing the invalid UTF-8 bytes that were substituted with +the replacement codepoint. For example: + +``` +use bstr::{B, ByteSlice}; + +let bs = b"a\xE2\x98z"; +let chars: Vec<(usize, usize, char)> = bs.char_indices().collect(); +// Even though the replacement codepoint is encoded as 3 bytes itself, the +// byte range given here is only two bytes, corresponding to the original +// raw bytes. +assert_eq!(vec![(0, 1, 'a'), (1, 3, '\u{FFFD}'), (3, 4, 'z')], chars); + +// Thus, getting the original raw bytes is as simple as slicing the original +// byte string: +let chars: Vec<&[u8]> = bs.char_indices().map(|(s, e, _)| &bs[s..e]).collect(); +assert_eq!(vec![B("a"), B(b"\xE2\x98"), B("z")], chars); +``` + +# File paths and OS strings + +One of the premiere features of Rust's standard library is how it handles file +paths. In particular, it makes it very hard to write incorrect code while +simultaneously providing a correct cross platform abstraction for manipulating +file paths. The key challenge that one faces with file paths across platforms +is derived from the following observations: + +* On most Unix-like systems, file paths are an arbitrary sequence of bytes. +* On Windows, file paths are an arbitrary sequence of 16-bit integers. + +(In both cases, certain sequences aren't allowed. For example a `NUL` byte is +not allowed in either case. But we can ignore this for the purposes of this +section.) + +Byte strings, like the ones provided in this crate, line up really well with +file paths on Unix like systems, which are themselves just arbitrary sequences +of bytes. It turns out that if you treat them as "mostly UTF-8," then things +work out pretty well. On the contrary, byte strings _don't_ really work +that well on Windows because it's not possible to correctly roundtrip file +paths between 16-bit integers and something that looks like UTF-8 _without_ +explicitly defining an encoding to do this for you, which is anathema to byte +strings, which are just bytes. + +Rust's standard library elegantly solves this problem by specifying an +internal encoding for file paths that's only used on Windows called +[WTF-8](https://simonsapin.github.io/wtf-8/). Its key properties are that they +permit losslessly roundtripping file paths on Windows by extending UTF-8 to +support an encoding of surrogate codepoints, while simultaneously supporting +zero-cost conversion from Rust's Unicode strings to file paths. (Since UTF-8 is +a proper subset of WTF-8.) + +The fundamental point at which the above strategy fails is when you want to +treat file paths as things that look like strings in a zero cost way. In most +cases, this is actually the wrong thing to do, but some cases call for it, +for example, glob or regex matching on file paths. This is because WTF-8 is +treated as an internal implementation detail, and there is no way to access +those bytes via a public API. Therefore, such consumers are limited in what +they can do: + +1. One could re-implement WTF-8 and re-encode file paths on Windows to WTF-8 + by accessing their underlying 16-bit integer representation. Unfortunately, + this isn't zero cost (it introduces a second WTF-8 decoding step) and it's + not clear this is a good thing to do, since WTF-8 should ideally remain an + internal implementation detail. +2. One could instead declare that they will not handle paths on Windows that + are not valid UTF-16, and return an error when one is encountered. +3. Like (2), but instead of returning an error, lossily decode the file path + on Windows that isn't valid UTF-16 into UTF-16 by replacing invalid bytes + with the Unicode replacement codepoint. + +While this library may provide facilities for (1) in the future, currently, +this library only provides facilities for (2) and (3). In particular, a suite +of conversion functions are provided that permit converting between byte +strings, OS strings and file paths. For owned byte strings, they are: + +* [`ByteVec::from_os_string`](trait.ByteVec.html#method.from_os_string) +* [`ByteVec::from_os_str_lossy`](trait.ByteVec.html#method.from_os_str_lossy) +* [`ByteVec::from_path_buf`](trait.ByteVec.html#method.from_path_buf) +* [`ByteVec::from_path_lossy`](trait.ByteVec.html#method.from_path_lossy) +* [`ByteVec::into_os_string`](trait.ByteVec.html#method.into_os_string) +* [`ByteVec::into_os_string_lossy`](trait.ByteVec.html#method.into_os_string_lossy) +* [`ByteVec::into_path_buf`](trait.ByteVec.html#method.into_path_buf) +* [`ByteVec::into_path_buf_lossy`](trait.ByteVec.html#method.into_path_buf_lossy) + +For byte string slices, they are: + +* [`ByteSlice::from_os_str`](trait.ByteSlice.html#method.from_os_str) +* [`ByteSlice::from_path`](trait.ByteSlice.html#method.from_path) +* [`ByteSlice::to_os_str`](trait.ByteSlice.html#method.to_os_str) +* [`ByteSlice::to_os_str_lossy`](trait.ByteSlice.html#method.to_os_str_lossy) +* [`ByteSlice::to_path`](trait.ByteSlice.html#method.to_path) +* [`ByteSlice::to_path_lossy`](trait.ByteSlice.html#method.to_path_lossy) + +On Unix, all of these conversions are rigorously zero cost, which gives one +a way to ergonomically deal with raw file paths exactly as they are using +normal string-related functions. On Windows, these conversion routines perform +a UTF-8 check and either return an error or lossily decode the file path +into valid UTF-8, depending on which function you use. This means that you +cannot roundtrip all file paths on Windows correctly using these conversion +routines. However, this may be an acceptable downside since such file paths +are exceptionally rare. Moreover, roundtripping isn't always necessary, for +example, if all you're doing is filtering based on file paths. + +The reason why using byte strings for this is potentially superior than the +standard library's approach is that a lot of Rust code is already lossily +converting file paths to Rust's Unicode strings, which are required to be valid +UTF-8, and thus contain latent bugs on Unix where paths with invalid UTF-8 are +not terribly uncommon. If you instead use byte strings, then you're guaranteed +to write correct code for Unix, at the cost of getting a corner case wrong on +Windows. +*/ + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use crate::bstr::BStr; +#[cfg(feature = "std")] +pub use crate::bstring::BString; +pub use crate::ext_slice::{ + ByteSlice, Bytes, Fields, FieldsWith, Find, FindReverse, Finder, + FinderReverse, Lines, LinesWithTerminator, Split, SplitN, SplitNReverse, + SplitReverse, B, +}; +#[cfg(feature = "std")] +pub use crate::ext_vec::{concat, join, ByteVec, DrainBytes, FromUtf8Error}; +#[cfg(feature = "unicode")] +pub use crate::unicode::{ + GraphemeIndices, Graphemes, SentenceIndices, Sentences, WordIndices, + Words, WordsWithBreakIndices, WordsWithBreaks, +}; +pub use crate::utf8::{ + decode as decode_utf8, decode_last as decode_last_utf8, CharIndices, + Chars, Utf8Chunk, Utf8Chunks, Utf8Error, +}; + +mod ascii; +mod bstr; +#[cfg(feature = "std")] +mod bstring; +mod byteset; +mod ext_slice; +#[cfg(feature = "std")] +mod ext_vec; +mod impls; +#[cfg(feature = "std")] +pub mod io; +#[cfg(test)] +mod tests; +#[cfg(feature = "unicode")] +mod unicode; +mod utf8; + +#[cfg(test)] +mod apitests { + use crate::bstr::BStr; + use crate::bstring::BString; + use crate::ext_slice::{Finder, FinderReverse}; + + #[test] + fn oibits() { + use std::panic::{RefUnwindSafe, UnwindSafe}; + + fn assert_send() {} + fn assert_sync() {} + fn assert_unwind_safe() {} + + assert_send::<&BStr>(); + assert_sync::<&BStr>(); + assert_unwind_safe::<&BStr>(); + assert_send::(); + assert_sync::(); + assert_unwind_safe::(); + + assert_send::>(); + assert_sync::>(); + assert_unwind_safe::>(); + assert_send::>(); + assert_sync::>(); + assert_unwind_safe::>(); + } +} diff --git a/vendor/bstr-0.2.17/src/tests.rs b/vendor/bstr-0.2.17/src/tests.rs new file mode 100644 index 0000000000000..f4179fd1d1385 --- /dev/null +++ b/vendor/bstr-0.2.17/src/tests.rs @@ -0,0 +1,32 @@ +/// A sequence of tests for checking whether lossy decoding uses the maximal +/// subpart strategy correctly. Namely, if a sequence of otherwise invalid +/// UTF-8 bytes is a valid prefix of a valid UTF-8 sequence, then the entire +/// prefix is replaced by a single replacement codepoint. In all other cases, +/// each invalid byte is replaced by a single replacement codepoint. +/// +/// The first element in each tuple is the expected result of lossy decoding, +/// while the second element is the input given. +pub const LOSSY_TESTS: &[(&str, &[u8])] = &[ + ("a", b"a"), + ("\u{FFFD}", b"\xFF"), + ("\u{FFFD}\u{FFFD}", b"\xFF\xFF"), + ("β\u{FFFD}", b"\xCE\xB2\xFF"), + ("☃\u{FFFD}", b"\xE2\x98\x83\xFF"), + ("ð±\u{FFFD}", b"\xF0\x9D\x9D\xB1\xFF"), + ("\u{FFFD}\u{FFFD}", b"\xCE\xF0"), + ("\u{FFFD}\u{FFFD}", b"\xCE\xFF"), + ("\u{FFFD}\u{FFFD}", b"\xE2\x98\xF0"), + ("\u{FFFD}\u{FFFD}", b"\xE2\x98\xFF"), + ("\u{FFFD}", b"\xF0\x9D\x9D"), + ("\u{FFFD}\u{FFFD}", b"\xF0\x9D\x9D\xF0"), + ("\u{FFFD}\u{FFFD}", b"\xF0\x9D\x9D\xFF"), + ("\u{FFFD}", b"\xCE"), + ("a\u{FFFD}", b"a\xCE"), + ("\u{FFFD}", b"\xE2\x98"), + ("a\u{FFFD}", b"a\xE2\x98"), + ("\u{FFFD}", b"\xF0\x9D\x9C"), + ("a\u{FFFD}", b"a\xF0\x9D\x9C"), + ("a\u{FFFD}\u{FFFD}\u{FFFD}z", b"a\xED\xA0\x80z"), + ("☃βツ\u{FFFD}", b"\xe2\x98\x83\xce\xb2\xe3\x83\x84\xFF"), + ("a\u{FFFD}\u{FFFD}\u{FFFD}b", b"\x61\xF1\x80\x80\xE1\x80\xC2\x62"), +]; diff --git a/vendor/bstr-0.2.17/src/unicode/data/GraphemeBreakTest.txt b/vendor/bstr-0.2.17/src/unicode/data/GraphemeBreakTest.txt new file mode 100644 index 0000000000000..fb4fec9fff029 --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/data/GraphemeBreakTest.txt @@ -0,0 +1,630 @@ +# GraphemeBreakTest-12.1.0.txt +# Date: 2019-03-10, 10:53:12 GMT +# © 2019 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ +# +# Default Grapheme_Cluster_Break Test +# +# Format: +# (# )? +# contains hex Unicode code points, with +# ÷ wherever there is a break opportunity, and +# × wherever there is not. +# the format can change, but currently it shows: +# - the sample character name +# - (x) the Grapheme_Cluster_Break property value for the sample character +# - [x] the rule that determines whether there is a break or not, +# as listed in the Rules section of GraphemeBreakTest.html +# +# These samples may be extended or changed in the future. +# +÷ 0020 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0020 × 0308 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0020 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (CR) ÷ [0.3] +÷ 0020 × 0308 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0020 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (LF) ÷ [0.3] +÷ 0020 × 0308 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0020 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (Control) ÷ [0.3] +÷ 0020 × 0308 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0020 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0020 × 0308 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0020 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0020 × 0308 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0020 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0020 × 0308 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0020 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0020 × 0308 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0020 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0020 × 0308 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0020 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0020 × 0308 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0020 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0020 × 0308 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0020 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0020 × 0308 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0020 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0020 × 0308 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0020 × 0308 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0020 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] (Other) ÷ [0.3] +÷ 0020 × 0308 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 000D ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [4.0] SPACE (Other) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 000D ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [4.0] (CR) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 000D × 000A ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 000D ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Control) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 000D ÷ 034F ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 000D ÷ 0308 × 034F ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000D ÷ 0600 ÷ # ÷ [0.2] (CR) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 000D ÷ 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 000D ÷ 0308 × 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 000D ÷ 1100 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 000D ÷ 1160 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 000D ÷ 11A8 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 000D ÷ AC00 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 000D ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 000D ÷ AC01 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 000D ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 000D ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [4.0] WATCH (ExtPict) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 000D ÷ 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 000D ÷ 200D ÷ # ÷ [0.2] (CR) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 000D ÷ 0308 × 200D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 000D ÷ 0378 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Other) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 000A ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [4.0] SPACE (Other) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 000A ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [4.0] (CR) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 000A ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] (LF) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 000A ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Control) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 000A ÷ 034F ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 000A ÷ 0308 × 034F ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000A ÷ 0600 ÷ # ÷ [0.2] (LF) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 000A ÷ 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 000A ÷ 0308 × 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 000A ÷ 1100 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 000A ÷ 1160 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 000A ÷ 11A8 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 000A ÷ AC00 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 000A ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 000A ÷ AC01 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 000A ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 000A ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [4.0] WATCH (ExtPict) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 000A ÷ 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 000A ÷ 200D ÷ # ÷ [0.2] (LF) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 000A ÷ 0308 × 200D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 000A ÷ 0378 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Other) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0001 ÷ 0020 ÷ # ÷ [0.2] (Control) ÷ [4.0] SPACE (Other) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0001 ÷ 000D ÷ # ÷ [0.2] (Control) ÷ [4.0] (CR) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0001 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] (LF) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0001 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Control) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0001 ÷ 034F ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0001 ÷ 0308 × 034F ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0001 ÷ 0600 ÷ # ÷ [0.2] (Control) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0001 ÷ 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0001 ÷ 0308 × 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0001 ÷ 1100 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0001 ÷ 1160 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0001 ÷ 11A8 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0001 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0001 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0001 ÷ 231A ÷ # ÷ [0.2] (Control) ÷ [4.0] WATCH (ExtPict) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0001 ÷ 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0001 ÷ 0308 × 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0001 ÷ 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0001 ÷ 0308 × 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0001 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Other) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 034F ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 034F × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 034F ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (CR) ÷ [0.3] +÷ 034F × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 034F ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (LF) ÷ [0.3] +÷ 034F × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 034F ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (Control) ÷ [0.3] +÷ 034F × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 034F × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 034F × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 034F ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 034F × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 034F ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 034F × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 034F × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 034F × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 034F ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 034F × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 034F ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 034F × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 034F ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 034F × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 034F ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 034F × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 034F ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 034F × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 034F ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 034F × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 034F × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 034F × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 034F × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 034F × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 034F ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] (Other) ÷ [0.3] +÷ 034F × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (CR) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (LF) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (Control) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 1F1E6 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1F1E6 × 0308 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F1E6 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1F1E6 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1F1E6 × 0308 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1F1E6 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F1E6 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1F1E6 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1F1E6 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1F1E6 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1F1E6 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 1F1E6 × 0308 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 1F1E6 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] (Other) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0600 × 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] SPACE (Other) ÷ [0.3] +÷ 0600 × 0308 ÷ 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0600 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (CR) ÷ [0.3] +÷ 0600 × 0308 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0600 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (LF) ÷ [0.3] +÷ 0600 × 0308 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0600 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (Control) ÷ [0.3] +÷ 0600 × 0308 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0600 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0600 × 0308 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0600 × 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0600 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0600 × 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0600 × 0308 ÷ 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0600 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0600 × 0308 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0600 × 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0600 × 0308 ÷ 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0600 × 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0600 × 0308 ÷ 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0600 × 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0600 × 0308 ÷ 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0600 × AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0600 × 0308 ÷ AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0600 × AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0600 × 0308 ÷ AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0600 × 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] WATCH (ExtPict) ÷ [0.3] +÷ 0600 × 0308 ÷ 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0600 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0600 × 0308 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0600 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0600 × 0308 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0600 × 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] (Other) ÷ [0.3] +÷ 0600 × 0308 ÷ 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0903 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0903 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0903 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] (CR) ÷ [0.3] +÷ 0903 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0903 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] (LF) ÷ [0.3] +÷ 0903 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0903 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] (Control) ÷ [0.3] +÷ 0903 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0903 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0903 × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0903 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0903 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0903 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0903 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0903 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0903 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0903 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0903 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0903 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0903 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0903 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0903 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0903 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0903 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0903 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0903 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0903 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0903 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0903 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0903 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0903 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0903 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0903 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] (Other) ÷ [0.3] +÷ 0903 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 1100 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1100 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1100 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (CR) ÷ [0.3] +÷ 1100 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 1100 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (LF) ÷ [0.3] +÷ 1100 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 1100 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (Control) ÷ [0.3] +÷ 1100 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 1100 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1100 × 0308 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1100 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1100 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1100 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1100 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1100 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1100 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1100 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1100 × 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1100 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1100 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1100 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1100 × AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1100 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1100 × AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1100 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1100 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1100 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1100 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 1100 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 1100 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 1100 × 0308 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 1100 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] (Other) ÷ [0.3] +÷ 1100 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 1160 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1160 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1160 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (CR) ÷ [0.3] +÷ 1160 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 1160 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (LF) ÷ [0.3] +÷ 1160 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 1160 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (Control) ÷ [0.3] +÷ 1160 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 1160 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1160 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1160 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1160 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1160 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1160 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1160 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1160 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1160 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1160 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1160 × 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [7.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1160 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1160 × 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1160 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1160 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1160 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1160 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1160 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1160 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1160 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1160 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 1160 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 1160 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 1160 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 1160 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] (Other) ÷ [0.3] +÷ 1160 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 11A8 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 11A8 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 11A8 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (CR) ÷ [0.3] +÷ 11A8 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 11A8 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (LF) ÷ [0.3] +÷ 11A8 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 11A8 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (Control) ÷ [0.3] +÷ 11A8 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 11A8 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 11A8 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 11A8 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 11A8 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 11A8 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 11A8 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 11A8 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 11A8 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 11A8 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 11A8 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 11A8 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 11A8 × 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 11A8 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 11A8 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 11A8 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 11A8 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 11A8 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 11A8 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 11A8 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 11A8 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 11A8 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 11A8 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 11A8 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 11A8 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] (Other) ÷ [0.3] +÷ 11A8 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ AC00 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ AC00 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ AC00 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (CR) ÷ [0.3] +÷ AC00 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ AC00 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (LF) ÷ [0.3] +÷ AC00 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ AC00 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (Control) ÷ [0.3] +÷ AC00 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ AC00 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ AC00 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ AC00 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC00 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC00 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ AC00 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ AC00 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ AC00 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ AC00 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC00 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC00 × 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ AC00 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ AC00 × 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ AC00 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ AC00 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ AC00 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ AC00 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ AC00 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ AC00 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ AC00 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ AC00 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ AC00 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ AC00 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ AC00 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ AC00 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] (Other) ÷ [0.3] +÷ AC00 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ AC01 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ AC01 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ AC01 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (CR) ÷ [0.3] +÷ AC01 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ AC01 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (LF) ÷ [0.3] +÷ AC01 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ AC01 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (Control) ÷ [0.3] +÷ AC01 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ AC01 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ AC01 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ AC01 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC01 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC01 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ AC01 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ AC01 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ AC01 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ AC01 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC01 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC01 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ AC01 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ AC01 × 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ AC01 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ AC01 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ AC01 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ AC01 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ AC01 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ AC01 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ AC01 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ AC01 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ AC01 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ AC01 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ AC01 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ AC01 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] (Other) ÷ [0.3] +÷ AC01 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 231A ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 231A × 0308 ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 231A ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (CR) ÷ [0.3] +÷ 231A × 0308 ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 231A ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (LF) ÷ [0.3] +÷ 231A × 0308 ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 231A ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (Control) ÷ [0.3] +÷ 231A × 0308 ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 231A × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 231A × 0308 × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 231A ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 231A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 231A ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 231A × 0308 ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 231A × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 231A × 0308 × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 231A ÷ 1100 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 231A × 0308 ÷ 1100 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 231A ÷ 1160 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 231A × 0308 ÷ 1160 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 231A ÷ 11A8 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 231A × 0308 ÷ 11A8 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 231A ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 231A × 0308 ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 231A ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 231A × 0308 ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 231A ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 231A × 0308 ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 231A × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 231A × 0308 × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 231A × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 231A × 0308 × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 231A ÷ 0378 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] (Other) ÷ [0.3] +÷ 231A × 0308 ÷ 0378 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0300 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0300 × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0300 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0300 × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0300 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0300 × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0300 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0300 × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0300 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0300 × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0300 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0300 × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0300 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0300 × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0300 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0300 × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0300 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0300 × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0300 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0300 × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0300 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0300 × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0300 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0300 × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0300 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0300 × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0300 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0300 × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 200D ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 200D × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 200D ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 200D × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 200D ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 200D × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 200D × 0308 × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 200D × 0308 ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 200D × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200D × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200D ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200D × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200D ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200D × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200D ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200D × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200D ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200D × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200D ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200D × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200D ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 200D × 0308 ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 200D × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 200D ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 200D × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0378 ÷ 0020 ÷ # ÷ [0.2] (Other) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0378 × 0308 ÷ 0020 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0378 ÷ 000D ÷ # ÷ [0.2] (Other) ÷ [5.0] (CR) ÷ [0.3] +÷ 0378 × 0308 ÷ 000D ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0378 ÷ 000A ÷ # ÷ [0.2] (Other) ÷ [5.0] (LF) ÷ [0.3] +÷ 0378 × 0308 ÷ 000A ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0378 ÷ 0001 ÷ # ÷ [0.2] (Other) ÷ [5.0] (Control) ÷ [0.3] +÷ 0378 × 0308 ÷ 0001 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0378 × 034F ÷ # ÷ [0.2] (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0378 × 0308 × 034F ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0378 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0378 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0378 ÷ 0600 ÷ # ÷ [0.2] (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0378 × 0308 ÷ 0600 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0378 × 0903 ÷ # ÷ [0.2] (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0378 × 0308 × 0903 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0378 ÷ 1100 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0378 × 0308 ÷ 1100 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0378 ÷ 1160 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0378 × 0308 ÷ 1160 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0378 ÷ 11A8 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0378 × 0308 ÷ 11A8 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0378 ÷ AC00 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0378 × 0308 ÷ AC00 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0378 ÷ AC01 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0378 × 0308 ÷ AC01 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0378 ÷ 231A ÷ # ÷ [0.2] (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0378 × 0308 ÷ 231A ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0378 × 0300 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0378 × 0308 × 0300 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0378 × 200D ÷ # ÷ [0.2] (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0378 × 0308 × 200D ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0378 ÷ 0378 ÷ # ÷ [0.2] (Other) ÷ [999.0] (Other) ÷ [0.3] +÷ 0378 × 0308 ÷ 0378 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 000D × 000A ÷ 0061 ÷ 000A ÷ 0308 ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [4.0] LATIN SMALL LETTER A (Other) ÷ [5.0] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [0.3] +÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [0.3] +÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC LETTER NOON (Other) ÷ [0.3] +÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC00 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC01 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 200D ÷ 1F1E7 × 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 × 1F1E9 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER D (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0061 × 0308 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 × 0903 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 0600 × 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) × [9.2] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 1F476 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3] +÷ 0061 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3] +÷ 0061 × 1F3FF ÷ 1F476 × 200D × 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 1F476 × 1F3FF × 0308 × 200D × 1F476 × 1F3FF ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [0.3] +÷ 1F6D1 × 200D × 1F6D1 ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 0061 × 200D ÷ 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 2701 × 200D × 2701 ÷ # ÷ [0.2] UPPER BLADE SCISSORS (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] UPPER BLADE SCISSORS (Other) ÷ [0.3] +÷ 0061 × 200D ÷ 2701 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] UPPER BLADE SCISSORS (Other) ÷ [0.3] +# +# Lines: 602 +# +# EOF diff --git a/vendor/bstr-0.2.17/src/unicode/data/LICENSE-UNICODE b/vendor/bstr-0.2.17/src/unicode/data/LICENSE-UNICODE new file mode 100644 index 0000000000000..ad06935770acb --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/data/LICENSE-UNICODE @@ -0,0 +1,45 @@ +UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE +See Terms of Use for definitions of Unicode Inc.'s +Data Files and Software. + +NOTICE TO USER: Carefully read the following legal agreement. +BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. +IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +THE DATA FILES OR SOFTWARE. + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2019 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in https://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. diff --git a/vendor/bstr-0.2.17/src/unicode/data/SentenceBreakTest.txt b/vendor/bstr-0.2.17/src/unicode/data/SentenceBreakTest.txt new file mode 100644 index 0000000000000..7c1c34afbd08e --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/data/SentenceBreakTest.txt @@ -0,0 +1,530 @@ +# SentenceBreakTest-12.1.0.txt +# Date: 2019-03-10, 10:53:28 GMT +# © 2019 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ +# +# Default Sentence_Break Test +# +# Format: +# (# )? +# contains hex Unicode code points, with +# ÷ wherever there is a break opportunity, and +# × wherever there is not. +# the format can change, but currently it shows: +# - the sample character name +# - (x) the Sentence_Break property value for the sample character +# - [x] the rule that determines whether there is a break or not, +# as listed in the Rules section of SentenceBreakTest.html +# +# These samples may be extended or changed in the future. +# +÷ 0001 × 0001 ÷ # ÷ [0.2] (Other) × [998.0] (Other) ÷ [0.3] +÷ 0001 × 0308 × 0001 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0001 × 000D ÷ # ÷ [0.2] (Other) × [998.0] (CR) ÷ [0.3] +÷ 0001 × 0308 × 000D ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0001 × 000A ÷ # ÷ [0.2] (Other) × [998.0] (LF) ÷ [0.3] +÷ 0001 × 0308 × 000A ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0001 × 0085 ÷ # ÷ [0.2] (Other) × [998.0] (Sep) ÷ [0.3] +÷ 0001 × 0308 × 0085 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0001 × 0009 ÷ # ÷ [0.2] (Other) × [998.0] (Sp) ÷ [0.3] +÷ 0001 × 0308 × 0009 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0001 × 0061 ÷ # ÷ [0.2] (Other) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0001 × 0308 × 0061 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0001 × 0041 ÷ # ÷ [0.2] (Other) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0001 × 0308 × 0041 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0001 × 01BB ÷ # ÷ [0.2] (Other) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0001 × 0308 × 01BB ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0001 × 0030 ÷ # ÷ [0.2] (Other) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0001 × 0308 × 0030 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0001 × 002E ÷ # ÷ [0.2] (Other) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0001 × 0308 × 002E ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0001 × 0021 ÷ # ÷ [0.2] (Other) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0001 × 0308 × 0021 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0001 × 0022 ÷ # ÷ [0.2] (Other) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0001 × 0308 × 0022 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0001 × 002C ÷ # ÷ [0.2] (Other) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0001 × 0308 × 002C ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0001 × 00AD ÷ # ÷ [0.2] (Other) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0001 × 0308 × 00AD ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0001 × 0300 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0001 × 0308 × 0300 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000D ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Other) ÷ [0.3] +÷ 000D ÷ 0308 × 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 000D ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [4.0] (CR) ÷ [0.3] +÷ 000D ÷ 0308 × 000D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 000D × 000A ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [0.3] +÷ 000D ÷ 0308 × 000A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 000D ÷ 0085 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Sep) ÷ [0.3] +÷ 000D ÷ 0308 × 0085 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 000D ÷ 0009 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Sp) ÷ [0.3] +÷ 000D ÷ 0308 × 0009 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 000D ÷ 0061 ÷ # ÷ [0.2] (CR) ÷ [4.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 000D ÷ 0308 × 0061 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 000D ÷ 0041 ÷ # ÷ [0.2] (CR) ÷ [4.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 000D ÷ 0308 × 0041 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 000D ÷ 01BB ÷ # ÷ [0.2] (CR) ÷ [4.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 000D ÷ 0308 × 01BB ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 000D ÷ 0030 ÷ # ÷ [0.2] (CR) ÷ [4.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000D ÷ 0308 × 0030 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000D ÷ 002E ÷ # ÷ [0.2] (CR) ÷ [4.0] FULL STOP (ATerm) ÷ [0.3] +÷ 000D ÷ 0308 × 002E ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 000D ÷ 0021 ÷ # ÷ [0.2] (CR) ÷ [4.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 000D ÷ 0308 × 0021 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 000D ÷ 0022 ÷ # ÷ [0.2] (CR) ÷ [4.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 000D ÷ 0308 × 0022 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 000D ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [4.0] COMMA (SContinue) ÷ [0.3] +÷ 000D ÷ 0308 × 002C ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 000D ÷ 00AD ÷ # ÷ [0.2] (CR) ÷ [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000D ÷ 0308 × 00AD ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000D ÷ 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000A ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Other) ÷ [0.3] +÷ 000A ÷ 0308 × 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 000A ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [4.0] (CR) ÷ [0.3] +÷ 000A ÷ 0308 × 000D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 000A ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] (LF) ÷ [0.3] +÷ 000A ÷ 0308 × 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 000A ÷ 0085 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Sep) ÷ [0.3] +÷ 000A ÷ 0308 × 0085 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 000A ÷ 0009 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Sp) ÷ [0.3] +÷ 000A ÷ 0308 × 0009 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 000A ÷ 0061 ÷ # ÷ [0.2] (LF) ÷ [4.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 000A ÷ 0308 × 0061 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 000A ÷ 0041 ÷ # ÷ [0.2] (LF) ÷ [4.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 000A ÷ 0308 × 0041 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 000A ÷ 01BB ÷ # ÷ [0.2] (LF) ÷ [4.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 000A ÷ 0308 × 01BB ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 000A ÷ 0030 ÷ # ÷ [0.2] (LF) ÷ [4.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000A ÷ 0308 × 0030 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000A ÷ 002E ÷ # ÷ [0.2] (LF) ÷ [4.0] FULL STOP (ATerm) ÷ [0.3] +÷ 000A ÷ 0308 × 002E ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 000A ÷ 0021 ÷ # ÷ [0.2] (LF) ÷ [4.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 000A ÷ 0308 × 0021 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 000A ÷ 0022 ÷ # ÷ [0.2] (LF) ÷ [4.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 000A ÷ 0308 × 0022 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 000A ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [4.0] COMMA (SContinue) ÷ [0.3] +÷ 000A ÷ 0308 × 002C ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 000A ÷ 00AD ÷ # ÷ [0.2] (LF) ÷ [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000A ÷ 0308 × 00AD ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000A ÷ 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0085 ÷ 0001 ÷ # ÷ [0.2] (Sep) ÷ [4.0] (Other) ÷ [0.3] +÷ 0085 ÷ 0308 × 0001 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0085 ÷ 000D ÷ # ÷ [0.2] (Sep) ÷ [4.0] (CR) ÷ [0.3] +÷ 0085 ÷ 0308 × 000D ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0085 ÷ 000A ÷ # ÷ [0.2] (Sep) ÷ [4.0] (LF) ÷ [0.3] +÷ 0085 ÷ 0308 × 000A ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0085 ÷ 0085 ÷ # ÷ [0.2] (Sep) ÷ [4.0] (Sep) ÷ [0.3] +÷ 0085 ÷ 0308 × 0085 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0085 ÷ 0009 ÷ # ÷ [0.2] (Sep) ÷ [4.0] (Sp) ÷ [0.3] +÷ 0085 ÷ 0308 × 0009 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0085 ÷ 0061 ÷ # ÷ [0.2] (Sep) ÷ [4.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0085 ÷ 0308 × 0061 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0085 ÷ 0041 ÷ # ÷ [0.2] (Sep) ÷ [4.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0085 ÷ 0308 × 0041 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0085 ÷ 01BB ÷ # ÷ [0.2] (Sep) ÷ [4.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0085 ÷ 0308 × 01BB ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0085 ÷ 0030 ÷ # ÷ [0.2] (Sep) ÷ [4.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0085 ÷ 0308 × 0030 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0085 ÷ 002E ÷ # ÷ [0.2] (Sep) ÷ [4.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0085 ÷ 0308 × 002E ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0085 ÷ 0021 ÷ # ÷ [0.2] (Sep) ÷ [4.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0085 ÷ 0308 × 0021 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0085 ÷ 0022 ÷ # ÷ [0.2] (Sep) ÷ [4.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0085 ÷ 0308 × 0022 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0085 ÷ 002C ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMMA (SContinue) ÷ [0.3] +÷ 0085 ÷ 0308 × 002C ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0085 ÷ 00AD ÷ # ÷ [0.2] (Sep) ÷ [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0085 ÷ 0308 × 00AD ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0085 ÷ 0300 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0085 ÷ 0308 × 0300 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0009 × 0001 ÷ # ÷ [0.2] (Sp) × [998.0] (Other) ÷ [0.3] +÷ 0009 × 0308 × 0001 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0009 × 000D ÷ # ÷ [0.2] (Sp) × [998.0] (CR) ÷ [0.3] +÷ 0009 × 0308 × 000D ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0009 × 000A ÷ # ÷ [0.2] (Sp) × [998.0] (LF) ÷ [0.3] +÷ 0009 × 0308 × 000A ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0009 × 0085 ÷ # ÷ [0.2] (Sp) × [998.0] (Sep) ÷ [0.3] +÷ 0009 × 0308 × 0085 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0009 × 0009 ÷ # ÷ [0.2] (Sp) × [998.0] (Sp) ÷ [0.3] +÷ 0009 × 0308 × 0009 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0009 × 0061 ÷ # ÷ [0.2] (Sp) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0009 × 0308 × 0061 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0009 × 0041 ÷ # ÷ [0.2] (Sp) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0009 × 0308 × 0041 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0009 × 01BB ÷ # ÷ [0.2] (Sp) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0009 × 0308 × 01BB ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0009 × 0030 ÷ # ÷ [0.2] (Sp) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0009 × 0308 × 0030 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0009 × 002E ÷ # ÷ [0.2] (Sp) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0009 × 0308 × 002E ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0009 × 0021 ÷ # ÷ [0.2] (Sp) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0009 × 0308 × 0021 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0009 × 0022 ÷ # ÷ [0.2] (Sp) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0009 × 0308 × 0022 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0009 × 002C ÷ # ÷ [0.2] (Sp) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0009 × 0308 × 002C ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0009 × 00AD ÷ # ÷ [0.2] (Sp) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0009 × 0308 × 00AD ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0009 × 0300 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0009 × 0308 × 0300 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 × 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] (Other) ÷ [0.3] +÷ 0061 × 0308 × 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0061 × 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] (CR) ÷ [0.3] +÷ 0061 × 0308 × 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0061 × 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] (LF) ÷ [0.3] +÷ 0061 × 0308 × 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0061 × 0085 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] (Sep) ÷ [0.3] +÷ 0061 × 0308 × 0085 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0061 × 0009 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] (Sp) ÷ [0.3] +÷ 0061 × 0308 × 0009 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0061 × 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0061 × 0308 × 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0061 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0061 × 0308 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0061 × 01BB ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0061 × 0308 × 01BB ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0061 × 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 × 0308 × 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 × 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0061 × 0308 × 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0061 × 0021 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0061 × 0308 × 0021 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0061 × 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0061 × 0308 × 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0061 × 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0061 × 0308 × 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0061 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0041 × 0001 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] (Other) ÷ [0.3] +÷ 0041 × 0308 × 0001 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0041 × 000D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] (CR) ÷ [0.3] +÷ 0041 × 0308 × 000D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0041 × 000A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] (LF) ÷ [0.3] +÷ 0041 × 0308 × 000A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0041 × 0085 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] (Sep) ÷ [0.3] +÷ 0041 × 0308 × 0085 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0041 × 0009 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] (Sp) ÷ [0.3] +÷ 0041 × 0308 × 0009 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0041 × 0061 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0041 × 0308 × 0061 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0041 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0041 × 0308 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0041 × 01BB ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0041 × 0308 × 01BB ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0041 × 0030 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0041 × 0308 × 0030 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0041 × 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0041 × 0308 × 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0041 × 0021 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0041 × 0308 × 0021 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0041 × 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0041 × 0308 × 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0041 × 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0041 × 0308 × 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0041 × 00AD ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0041 × 0308 × 00AD ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0041 × 0300 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0041 × 0308 × 0300 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 01BB × 0001 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] (Other) ÷ [0.3] +÷ 01BB × 0308 × 0001 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 01BB × 000D ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] (CR) ÷ [0.3] +÷ 01BB × 0308 × 000D ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 01BB × 000A ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] (LF) ÷ [0.3] +÷ 01BB × 0308 × 000A ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 01BB × 0085 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] (Sep) ÷ [0.3] +÷ 01BB × 0308 × 0085 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 01BB × 0009 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] (Sp) ÷ [0.3] +÷ 01BB × 0308 × 0009 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 01BB × 0061 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 01BB × 0308 × 0061 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 01BB × 0041 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 01BB × 0308 × 0041 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 01BB × 01BB ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 01BB × 0308 × 01BB ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 01BB × 0030 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 01BB × 0308 × 0030 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 01BB × 002E ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 01BB × 0308 × 002E ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 01BB × 0021 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 01BB × 0308 × 0021 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 01BB × 0022 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 01BB × 0308 × 0022 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 01BB × 002C ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 01BB × 0308 × 002C ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 01BB × 00AD ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 01BB × 0308 × 00AD ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 01BB × 0300 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 01BB × 0308 × 0300 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0030 × 0001 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] (Other) ÷ [0.3] +÷ 0030 × 0308 × 0001 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0030 × 000D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] (CR) ÷ [0.3] +÷ 0030 × 0308 × 000D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0030 × 000A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] (LF) ÷ [0.3] +÷ 0030 × 0308 × 000A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0030 × 0085 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] (Sep) ÷ [0.3] +÷ 0030 × 0308 × 0085 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0030 × 0009 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] (Sp) ÷ [0.3] +÷ 0030 × 0308 × 0009 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0030 × 0061 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0030 × 0308 × 0061 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0030 × 0041 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0030 × 0308 × 0041 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0030 × 01BB ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0030 × 0308 × 01BB ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0030 × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0030 × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0030 × 002E ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0030 × 0308 × 002E ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0030 × 0021 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0030 × 0308 × 0021 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0030 × 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0030 × 0308 × 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0030 × 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0030 × 0308 × 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0030 × 00AD ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0030 × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0030 × 0300 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0030 × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002E ÷ 0001 ÷ # ÷ [0.2] FULL STOP (ATerm) ÷ [11.0] (Other) ÷ [0.3] +÷ 002E × 0308 ÷ 0001 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] (Other) ÷ [0.3] +÷ 002E × 000D ÷ # ÷ [0.2] FULL STOP (ATerm) × [9.0] (CR) ÷ [0.3] +÷ 002E × 0308 × 000D ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (CR) ÷ [0.3] +÷ 002E × 000A ÷ # ÷ [0.2] FULL STOP (ATerm) × [9.0] (LF) ÷ [0.3] +÷ 002E × 0308 × 000A ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (LF) ÷ [0.3] +÷ 002E × 0085 ÷ # ÷ [0.2] FULL STOP (ATerm) × [9.0] (Sep) ÷ [0.3] +÷ 002E × 0308 × 0085 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (Sep) ÷ [0.3] +÷ 002E × 0009 ÷ # ÷ [0.2] FULL STOP (ATerm) × [9.0] (Sp) ÷ [0.3] +÷ 002E × 0308 × 0009 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (Sp) ÷ [0.3] +÷ 002E × 0061 ÷ # ÷ [0.2] FULL STOP (ATerm) × [8.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 002E × 0308 × 0061 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 002E ÷ 0041 ÷ # ÷ [0.2] FULL STOP (ATerm) ÷ [11.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 002E × 0308 ÷ 0041 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 002E ÷ 01BB ÷ # ÷ [0.2] FULL STOP (ATerm) ÷ [11.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 002E × 0308 ÷ 01BB ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 002E × 0030 ÷ # ÷ [0.2] FULL STOP (ATerm) × [6.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002E × 0308 × 0030 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [6.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002E × 002E ÷ # ÷ [0.2] FULL STOP (ATerm) × [8.1] FULL STOP (ATerm) ÷ [0.3] +÷ 002E × 0308 × 002E ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.1] FULL STOP (ATerm) ÷ [0.3] +÷ 002E × 0021 ÷ # ÷ [0.2] FULL STOP (ATerm) × [8.1] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 002E × 0308 × 0021 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.1] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 002E × 0022 ÷ # ÷ [0.2] FULL STOP (ATerm) × [9.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 002E × 0308 × 0022 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 002E × 002C ÷ # ÷ [0.2] FULL STOP (ATerm) × [8.1] COMMA (SContinue) ÷ [0.3] +÷ 002E × 0308 × 002C ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.1] COMMA (SContinue) ÷ [0.3] +÷ 002E × 00AD ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002E × 0308 × 00AD ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002E × 0300 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002E × 0308 × 0300 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0021 ÷ 0001 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) ÷ [11.0] (Other) ÷ [0.3] +÷ 0021 × 0308 ÷ 0001 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] (Other) ÷ [0.3] +÷ 0021 × 000D ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [9.0] (CR) ÷ [0.3] +÷ 0021 × 0308 × 000D ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (CR) ÷ [0.3] +÷ 0021 × 000A ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [9.0] (LF) ÷ [0.3] +÷ 0021 × 0308 × 000A ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (LF) ÷ [0.3] +÷ 0021 × 0085 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [9.0] (Sep) ÷ [0.3] +÷ 0021 × 0308 × 0085 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (Sep) ÷ [0.3] +÷ 0021 × 0009 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [9.0] (Sp) ÷ [0.3] +÷ 0021 × 0308 × 0009 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (Sp) ÷ [0.3] +÷ 0021 ÷ 0061 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) ÷ [11.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0021 × 0308 ÷ 0061 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0021 ÷ 0041 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) ÷ [11.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0021 × 0308 ÷ 0041 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0021 ÷ 01BB ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) ÷ [11.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0021 × 0308 ÷ 01BB ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0021 ÷ 0030 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) ÷ [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0021 × 0308 ÷ 0030 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0021 × 002E ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [8.1] FULL STOP (ATerm) ÷ [0.3] +÷ 0021 × 0308 × 002E ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.1] FULL STOP (ATerm) ÷ [0.3] +÷ 0021 × 0021 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [8.1] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0021 × 0308 × 0021 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.1] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0021 × 0022 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [9.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0021 × 0308 × 0022 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0021 × 002C ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [8.1] COMMA (SContinue) ÷ [0.3] +÷ 0021 × 0308 × 002C ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.1] COMMA (SContinue) ÷ [0.3] +÷ 0021 × 00AD ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0021 × 0308 × 00AD ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0021 × 0300 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0021 × 0308 × 0300 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0022 × 0001 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] (Other) ÷ [0.3] +÷ 0022 × 0308 × 0001 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0022 × 000D ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] (CR) ÷ [0.3] +÷ 0022 × 0308 × 000D ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0022 × 000A ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] (LF) ÷ [0.3] +÷ 0022 × 0308 × 000A ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0022 × 0085 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] (Sep) ÷ [0.3] +÷ 0022 × 0308 × 0085 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0022 × 0009 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] (Sp) ÷ [0.3] +÷ 0022 × 0308 × 0009 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0022 × 0061 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0022 × 0308 × 0061 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0022 × 0041 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0022 × 0308 × 0041 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0022 × 01BB ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0022 × 0308 × 01BB ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0022 × 0030 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0022 × 0308 × 0030 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0022 × 002E ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0022 × 0308 × 002E ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0022 × 0021 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0022 × 0308 × 0021 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0022 × 0022 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0022 × 0308 × 0022 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0022 × 002C ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0022 × 0308 × 002C ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0022 × 00AD ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0022 × 0308 × 00AD ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0022 × 0300 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0022 × 0308 × 0300 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002C × 0001 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] (Other) ÷ [0.3] +÷ 002C × 0308 × 0001 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 002C × 000D ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] (CR) ÷ [0.3] +÷ 002C × 0308 × 000D ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 002C × 000A ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] (LF) ÷ [0.3] +÷ 002C × 0308 × 000A ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 002C × 0085 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] (Sep) ÷ [0.3] +÷ 002C × 0308 × 0085 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 002C × 0009 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] (Sp) ÷ [0.3] +÷ 002C × 0308 × 0009 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 002C × 0061 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 002C × 0308 × 0061 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 002C × 0041 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 002C × 0308 × 0041 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 002C × 01BB ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 002C × 0308 × 01BB ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 002C × 0030 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002C × 0308 × 0030 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002C × 002E ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 002C × 0308 × 002E ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 002C × 0021 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 002C × 0308 × 0021 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 002C × 0022 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 002C × 0308 × 0022 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 002C × 002C ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 002C × 0308 × 002C ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 002C × 00AD ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002C × 0308 × 00AD ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002C × 0300 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002C × 0308 × 0300 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 00AD × 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] (Other) ÷ [0.3] +÷ 00AD × 0308 × 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 00AD × 000D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] (CR) ÷ [0.3] +÷ 00AD × 0308 × 000D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 00AD × 000A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] (LF) ÷ [0.3] +÷ 00AD × 0308 × 000A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 00AD × 0085 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] (Sep) ÷ [0.3] +÷ 00AD × 0308 × 0085 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 00AD × 0009 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] (Sp) ÷ [0.3] +÷ 00AD × 0308 × 0009 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 00AD × 0061 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 00AD × 0308 × 0061 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 00AD × 0041 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 00AD × 0308 × 0041 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 00AD × 01BB ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 00AD × 0308 × 01BB ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 00AD × 0030 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 00AD × 0308 × 0030 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 00AD × 002E ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 00AD × 0308 × 002E ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 00AD × 0021 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 00AD × 0308 × 0021 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 00AD × 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 00AD × 0308 × 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 00AD × 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 00AD × 0308 × 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 00AD × 00AD ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 00AD × 0308 × 00AD ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 00AD × 0300 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 00AD × 0308 × 0300 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0300 × 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0300 × 0308 × 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0300 × 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0300 × 0308 × 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0300 × 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0300 × 0308 × 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0300 × 0085 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0300 × 0308 × 0085 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0300 × 0009 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0300 × 0308 × 0009 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0300 × 0061 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0300 × 0308 × 0061 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0300 × 0041 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0300 × 0308 × 0041 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0300 × 01BB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0300 × 0308 × 01BB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0300 × 0030 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0300 × 0308 × 0030 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0300 × 002E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0300 × 0308 × 002E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0300 × 0021 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0300 × 0308 × 0021 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0300 × 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0300 × 0308 × 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0300 × 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0300 × 0308 × 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0300 × 00AD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0300 × 0308 × 00AD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000D × 000A ÷ 0061 × 000A ÷ 0308 ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [4.0] LATIN SMALL LETTER A (Lower) × [998.0] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [0.3] +÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [0.3] +÷ 0020 × 200D × 0646 ÷ # ÷ [0.2] SPACE (Sp) × [5.0] ZERO WIDTH JOINER (Extend_FE) × [998.0] ARABIC LETTER NOON (OLetter) ÷ [0.3] +÷ 0646 × 200D × 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (OLetter) × [5.0] ZERO WIDTH JOINER (Extend_FE) × [998.0] SPACE (Sp) ÷ [0.3] +÷ 0028 × 0022 × 0047 × 006F × 002E × 0022 × 0029 × 0020 ÷ 0028 × 0048 × 0065 × 0020 × 0064 × 0069 × 0064 × 002E × 0029 ÷ # ÷ [0.2] LEFT PARENTHESIS (Close) × [998.0] QUOTATION MARK (Close) × [998.0] LATIN CAPITAL LETTER G (Upper) × [998.0] LATIN SMALL LETTER O (Lower) × [998.0] FULL STOP (ATerm) × [9.0] QUOTATION MARK (Close) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] SPACE (Sp) ÷ [11.0] LEFT PARENTHESIS (Close) × [998.0] LATIN CAPITAL LETTER H (Upper) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] SPACE (Sp) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] LATIN SMALL LETTER I (Lower) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) ÷ [0.3] +÷ 0028 × 201C × 0047 × 006F × 003F × 201D × 0029 × 0020 ÷ 0028 × 0048 × 0065 × 0020 × 0064 × 0069 × 0064 × 002E × 0029 ÷ # ÷ [0.2] LEFT PARENTHESIS (Close) × [998.0] LEFT DOUBLE QUOTATION MARK (Close) × [998.0] LATIN CAPITAL LETTER G (Upper) × [998.0] LATIN SMALL LETTER O (Lower) × [998.0] QUESTION MARK (STerm) × [9.0] RIGHT DOUBLE QUOTATION MARK (Close) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] SPACE (Sp) ÷ [11.0] LEFT PARENTHESIS (Close) × [998.0] LATIN CAPITAL LETTER H (Upper) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] SPACE (Sp) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] LATIN SMALL LETTER I (Lower) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) ÷ [0.3] +÷ 0055 × 002E × 0053 × 002E × 0041 × 0300 × 002E × 0020 × 0069 × 0073 ÷ # ÷ [0.2] LATIN CAPITAL LETTER U (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER S (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) × [8.0] SPACE (Sp) × [8.0] LATIN SMALL LETTER I (Lower) × [998.0] LATIN SMALL LETTER S (Lower) ÷ [0.3] +÷ 0055 × 002E × 0053 × 002E × 0041 × 0300 × 003F × 0020 ÷ 0048 × 0065 ÷ # ÷ [0.2] LATIN CAPITAL LETTER U (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER S (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] QUESTION MARK (STerm) × [9.0] SPACE (Sp) ÷ [11.0] LATIN CAPITAL LETTER H (Upper) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0055 × 002E × 0053 × 002E × 0041 × 0300 × 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER U (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER S (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0033 × 002E × 0034 ÷ # ÷ [0.2] DIGIT THREE (Numeric) × [998.0] FULL STOP (ATerm) × [6.0] DIGIT FOUR (Numeric) ÷ [0.3] +÷ 0063 × 002E × 0064 ÷ # ÷ [0.2] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.0] LATIN SMALL LETTER D (Lower) ÷ [0.3] +÷ 0043 × 002E × 0064 ÷ # ÷ [0.2] LATIN CAPITAL LETTER C (Upper) × [998.0] FULL STOP (ATerm) × [8.0] LATIN SMALL LETTER D (Lower) ÷ [0.3] +÷ 0063 × 002E × 0044 ÷ # ÷ [0.2] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER D (Upper) ÷ [0.3] +÷ 0043 × 002E × 0044 ÷ # ÷ [0.2] LATIN CAPITAL LETTER C (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER D (Upper) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 0074 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.0] RIGHT PARENTHESIS (Close) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [8.0] NO-BREAK SPACE (Sp) × [8.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 ÷ 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [9.0] NO-BREAK SPACE (Sp) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 2018 × 0028 × 0074 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.0] RIGHT PARENTHESIS (Close) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [8.0] NO-BREAK SPACE (Sp) × [8.0] LEFT SINGLE QUOTATION MARK (Close) × [998.0] LEFT PARENTHESIS (Close) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 ÷ 2018 × 0028 × 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [9.0] NO-BREAK SPACE (Sp) ÷ [11.0] LEFT SINGLE QUOTATION MARK (Close) × [998.0] LEFT PARENTHESIS (Close) × [998.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 0308 × 0074 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.0] RIGHT PARENTHESIS (Close) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [8.0] NO-BREAK SPACE (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 0308 ÷ 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [9.0] NO-BREAK SPACE (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 0308 ÷ 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 000A ÷ 0308 × 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0074 × 0068 × 0065 × 0020 × 0072 × 0065 × 0073 × 0070 × 002E × 0020 × 006C × 0065 × 0061 × 0064 × 0065 × 0072 × 0073 × 0020 × 0061 × 0072 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] SPACE (Sp) × [998.0] LATIN SMALL LETTER R (Lower) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER S (Lower) × [998.0] LATIN SMALL LETTER P (Lower) × [998.0] FULL STOP (ATerm) × [8.0] SPACE (Sp) × [8.0] LATIN SMALL LETTER L (Lower) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER A (Lower) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER R (Lower) × [998.0] LATIN SMALL LETTER S (Lower) × [998.0] SPACE (Sp) × [998.0] LATIN SMALL LETTER A (Lower) × [998.0] LATIN SMALL LETTER R (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 5B57 × 002E ÷ 5B57 ÷ # ÷ [0.2] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [998.0] FULL STOP (ATerm) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E ÷ 5B83 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 3002 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.1] IDEOGRAPHIC FULL STOP (STerm) ÷ [0.3] +÷ 5B57 × 3002 ÷ 5B83 ÷ # ÷ [0.2] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [998.0] IDEOGRAPHIC FULL STOP (STerm) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) ÷ [0.3] +÷ 0021 × 0020 × 0020 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [9.0] SPACE (Sp) × [10.0] SPACE (Sp) ÷ [0.3] +÷ 2060 × 0028 × 2060 × 0022 × 2060 × 0047 × 2060 × 006F × 2060 × 002E × 2060 × 0022 × 2060 × 0029 × 2060 × 0020 × 2060 ÷ 0028 × 2060 × 0048 × 2060 × 0065 × 2060 × 0020 × 2060 × 0064 × 2060 × 0069 × 2060 × 0064 × 2060 × 002E × 2060 × 0029 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER G (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER O (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER H (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER I (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0028 × 2060 × 201C × 2060 × 0047 × 2060 × 006F × 2060 × 003F × 2060 × 201D × 2060 × 0029 × 2060 × 0020 × 2060 ÷ 0028 × 2060 × 0048 × 2060 × 0065 × 2060 × 0020 × 2060 × 0064 × 2060 × 0069 × 2060 × 0064 × 2060 × 002E × 2060 × 0029 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LEFT DOUBLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER G (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER O (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] QUESTION MARK (STerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT DOUBLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER H (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER I (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0055 × 2060 × 002E × 2060 × 0053 × 2060 × 002E × 2060 × 0041 × 2060 × 0300 × 002E × 2060 × 0020 × 2060 × 0069 × 2060 × 0073 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER U (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER S (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER I (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER S (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0055 × 2060 × 002E × 2060 × 0053 × 2060 × 002E × 2060 × 0041 × 2060 × 0300 × 003F × 2060 × 0020 × 2060 ÷ 0048 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER U (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER S (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] QUESTION MARK (STerm) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LATIN CAPITAL LETTER H (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0055 × 2060 × 002E × 2060 × 0053 × 2060 × 002E × 2060 × 0041 × 2060 × 0300 × 002E × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER U (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER S (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0033 × 2060 × 002E × 2060 × 0034 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] DIGIT THREE (Numeric) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [6.0] DIGIT FOUR (Numeric) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0063 × 2060 × 002E × 2060 × 0064 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0043 × 2060 × 002E × 2060 × 0064 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER C (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0063 × 2060 × 002E × 2060 × 0044 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER D (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0043 × 2060 × 002E × 2060 × 0044 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER C (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER D (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 ÷ 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 2018 × 2060 × 0028 × 2060 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LEFT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 ÷ 2018 × 2060 × 0028 × 2060 × 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LEFT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 0308 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 0308 ÷ 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 0308 ÷ 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 000A ÷ 2060 × 0308 × 2060 × 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] (LF) ÷ [4.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 0020 × 2060 × 0072 × 2060 × 0065 × 2060 × 0073 × 2060 × 0070 × 2060 × 002E × 2060 × 0020 × 2060 × 006C × 2060 × 0065 × 2060 × 0061 × 2060 × 0064 × 2060 × 0065 × 2060 × 0072 × 2060 × 0073 × 2060 × 0020 × 2060 × 0061 × 2060 × 0072 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER R (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER S (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER P (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER L (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER A (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER R (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER S (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER A (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER R (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 5B57 × 2060 × 002E × 2060 ÷ 5B57 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 ÷ 5B83 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 3002 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.1] IDEOGRAPHIC FULL STOP (STerm) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 5B57 × 2060 × 3002 × 2060 ÷ 5B83 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [5.0] WORD JOINER (Format_FE) × [998.0] IDEOGRAPHIC FULL STOP (STerm) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0021 × 2060 × 0020 × 2060 × 0020 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] EXCLAMATION MARK (STerm) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [10.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +# +# Lines: 502 +# +# EOF diff --git a/vendor/bstr-0.2.17/src/unicode/data/WordBreakTest.txt b/vendor/bstr-0.2.17/src/unicode/data/WordBreakTest.txt new file mode 100644 index 0000000000000..facd8920ea856 --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/data/WordBreakTest.txt @@ -0,0 +1,1851 @@ +# WordBreakTest-12.1.0.txt +# Date: 2019-03-10, 10:53:29 GMT +# © 2019 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ +# +# Default Word_Break Test +# +# Format: +# (# )? +# contains hex Unicode code points, with +# ÷ wherever there is a break opportunity, and +# × wherever there is not. +# the format can change, but currently it shows: +# - the sample character name +# - (x) the Word_Break property value for the sample character +# - [x] the rule that determines whether there is a break or not, +# as listed in the Rules section of WordBreakTest.html +# +# These samples may be extended or changed in the future. +# +÷ 0001 ÷ 0001 ÷ # ÷ [0.2] (Other) ÷ [999.0] (Other) ÷ [0.3] +÷ 0001 × 0308 ÷ 0001 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0001 ÷ 000D ÷ # ÷ [0.2] (Other) ÷ [3.2] (CR) ÷ [0.3] +÷ 0001 × 0308 ÷ 000D ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0001 ÷ 000A ÷ # ÷ [0.2] (Other) ÷ [3.2] (LF) ÷ [0.3] +÷ 0001 × 0308 ÷ 000A ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0001 ÷ 000B ÷ # ÷ [0.2] (Other) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0001 × 0308 ÷ 000B ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0001 ÷ 3031 ÷ # ÷ [0.2] (Other) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0001 × 0308 ÷ 3031 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0001 ÷ 0041 ÷ # ÷ [0.2] (Other) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0001 × 0308 ÷ 0041 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0001 ÷ 003A ÷ # ÷ [0.2] (Other) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0001 × 0308 ÷ 003A ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0001 ÷ 002C ÷ # ÷ [0.2] (Other) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0001 × 0308 ÷ 002C ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0001 ÷ 002E ÷ # ÷ [0.2] (Other) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0001 × 0308 ÷ 002E ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0001 ÷ 0030 ÷ # ÷ [0.2] (Other) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0001 × 0308 ÷ 0030 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0001 ÷ 005F ÷ # ÷ [0.2] (Other) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0001 × 0308 ÷ 005F ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0001 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0001 ÷ 05D0 ÷ # ÷ [0.2] (Other) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0001 × 0308 ÷ 05D0 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0001 ÷ 0022 ÷ # ÷ [0.2] (Other) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0001 × 0308 ÷ 0022 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0001 ÷ 0027 ÷ # ÷ [0.2] (Other) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0001 × 0308 ÷ 0027 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0001 ÷ 231A ÷ # ÷ [0.2] (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0001 × 0308 ÷ 231A ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0001 ÷ 0020 ÷ # ÷ [0.2] (Other) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0001 × 0308 ÷ 0020 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0001 × 00AD ÷ # ÷ [0.2] (Other) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0001 × 0308 × 00AD ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0001 × 0300 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0001 × 0308 × 0300 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0001 × 200D ÷ # ÷ [0.2] (Other) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0001 × 0308 × 200D ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0001 ÷ 0061 × 2060 ÷ # ÷ [0.2] (Other) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0001 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0001 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (Other) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0001 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0001 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (Other) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0001 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0001 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (Other) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0001 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0001 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (Other) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0001 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0001 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (Other) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0001 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0001 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (Other) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0001 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0001 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (Other) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0001 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0001 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (Other) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0001 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [3.1] (Other) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 000D ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [3.1] (CR) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 000D × 000A ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 000D ÷ 000B ÷ # ÷ [0.2] (CR) ÷ [3.1] (Newline) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 000B ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 000D ÷ 3031 ÷ # ÷ [0.2] (CR) ÷ [3.1] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 3031 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 000D ÷ 0041 ÷ # ÷ [0.2] (CR) ÷ [3.1] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0041 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 000D ÷ 003A ÷ # ÷ [0.2] (CR) ÷ [3.1] COLON (MidLetter) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 003A ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000D ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [3.1] COMMA (MidNum) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000D ÷ 002E ÷ # ÷ [0.2] (CR) ÷ [3.1] FULL STOP (MidNumLet) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 002E ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 000D ÷ 0030 ÷ # ÷ [0.2] (CR) ÷ [3.1] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0030 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000D ÷ 005F ÷ # ÷ [0.2] (CR) ÷ [3.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 005F ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [3.1] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000D ÷ 05D0 ÷ # ÷ [0.2] (CR) ÷ [3.1] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 05D0 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 000D ÷ 0022 ÷ # ÷ [0.2] (CR) ÷ [3.1] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0022 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 000D ÷ 0027 ÷ # ÷ [0.2] (CR) ÷ [3.1] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0027 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000D ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [3.1] WATCH (ExtPict) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 000D ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [3.1] SPACE (WSegSpace) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 000D ÷ 00AD ÷ # ÷ [0.2] (CR) ÷ [3.1] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000D ÷ 0308 × 00AD ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000D ÷ 0300 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000D ÷ 200D ÷ # ÷ [0.2] (CR) ÷ [3.1] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000D ÷ 0308 × 200D ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000D ÷ 0061 × 2060 ÷ # ÷ [0.2] (CR) ÷ [3.1] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (CR) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000D ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (CR) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000D ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (CR) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000D ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (CR) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000D ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (CR) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000D ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000D ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (CR) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000A ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [3.1] (Other) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 000A ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [3.1] (CR) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 000A ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [3.1] (LF) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 000A ÷ 000B ÷ # ÷ [0.2] (LF) ÷ [3.1] (Newline) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 000B ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 000A ÷ 3031 ÷ # ÷ [0.2] (LF) ÷ [3.1] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 3031 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 000A ÷ 0041 ÷ # ÷ [0.2] (LF) ÷ [3.1] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0041 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 000A ÷ 003A ÷ # ÷ [0.2] (LF) ÷ [3.1] COLON (MidLetter) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 003A ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000A ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [3.1] COMMA (MidNum) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000A ÷ 002E ÷ # ÷ [0.2] (LF) ÷ [3.1] FULL STOP (MidNumLet) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 002E ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 000A ÷ 0030 ÷ # ÷ [0.2] (LF) ÷ [3.1] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0030 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000A ÷ 005F ÷ # ÷ [0.2] (LF) ÷ [3.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 005F ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [3.1] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000A ÷ 05D0 ÷ # ÷ [0.2] (LF) ÷ [3.1] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 05D0 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 000A ÷ 0022 ÷ # ÷ [0.2] (LF) ÷ [3.1] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0022 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 000A ÷ 0027 ÷ # ÷ [0.2] (LF) ÷ [3.1] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0027 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000A ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [3.1] WATCH (ExtPict) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 000A ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [3.1] SPACE (WSegSpace) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 000A ÷ 00AD ÷ # ÷ [0.2] (LF) ÷ [3.1] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000A ÷ 0308 × 00AD ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000A ÷ 0300 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000A ÷ 200D ÷ # ÷ [0.2] (LF) ÷ [3.1] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000A ÷ 0308 × 200D ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000A ÷ 0061 × 2060 ÷ # ÷ [0.2] (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000A ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000A ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000A ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000A ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000A ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (LF) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000A ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (LF) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000A ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000A ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (LF) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000B ÷ 0001 ÷ # ÷ [0.2] (Newline) ÷ [3.1] (Other) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 000B ÷ 000D ÷ # ÷ [0.2] (Newline) ÷ [3.1] (CR) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 000B ÷ 000A ÷ # ÷ [0.2] (Newline) ÷ [3.1] (LF) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 000B ÷ 000B ÷ # ÷ [0.2] (Newline) ÷ [3.1] (Newline) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 000B ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 000B ÷ 3031 ÷ # ÷ [0.2] (Newline) ÷ [3.1] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 3031 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 000B ÷ 0041 ÷ # ÷ [0.2] (Newline) ÷ [3.1] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0041 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 000B ÷ 003A ÷ # ÷ [0.2] (Newline) ÷ [3.1] COLON (MidLetter) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 003A ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000B ÷ 002C ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMMA (MidNum) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 002C ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000B ÷ 002E ÷ # ÷ [0.2] (Newline) ÷ [3.1] FULL STOP (MidNumLet) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 002E ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 000B ÷ 0030 ÷ # ÷ [0.2] (Newline) ÷ [3.1] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0030 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000B ÷ 005F ÷ # ÷ [0.2] (Newline) ÷ [3.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 005F ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 000B ÷ 1F1E6 ÷ # ÷ [0.2] (Newline) ÷ [3.1] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000B ÷ 05D0 ÷ # ÷ [0.2] (Newline) ÷ [3.1] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 05D0 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 000B ÷ 0022 ÷ # ÷ [0.2] (Newline) ÷ [3.1] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0022 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 000B ÷ 0027 ÷ # ÷ [0.2] (Newline) ÷ [3.1] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0027 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000B ÷ 231A ÷ # ÷ [0.2] (Newline) ÷ [3.1] WATCH (ExtPict) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 000B ÷ 0020 ÷ # ÷ [0.2] (Newline) ÷ [3.1] SPACE (WSegSpace) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 000B ÷ 00AD ÷ # ÷ [0.2] (Newline) ÷ [3.1] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000B ÷ 0308 × 00AD ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000B ÷ 0300 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000B ÷ 0308 × 0300 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000B ÷ 200D ÷ # ÷ [0.2] (Newline) ÷ [3.1] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000B ÷ 0308 × 200D ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000B ÷ 0061 × 2060 ÷ # ÷ [0.2] (Newline) ÷ [3.1] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000B ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (Newline) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000B ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (Newline) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000B ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (Newline) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000B ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (Newline) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000B ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (Newline) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000B ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (Newline) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000B ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (Newline) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000B ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (Newline) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 3031 ÷ 0001 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] (Other) ÷ [0.3] +÷ 3031 × 0308 ÷ 0001 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 3031 ÷ 000D ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [3.2] (CR) ÷ [0.3] +÷ 3031 × 0308 ÷ 000D ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 3031 ÷ 000A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [3.2] (LF) ÷ [0.3] +÷ 3031 × 0308 ÷ 000A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 3031 ÷ 000B ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [3.2] (Newline) ÷ [0.3] +÷ 3031 × 0308 ÷ 000B ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 3031 × 3031 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [13.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 3031 × 0308 × 3031 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 3031 ÷ 0041 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 3031 × 0308 ÷ 0041 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 3031 ÷ 003A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 3031 × 0308 ÷ 003A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 3031 ÷ 002C ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 3031 × 0308 ÷ 002C ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 3031 ÷ 002E ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 3031 × 0308 ÷ 002E ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 3031 ÷ 0030 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 3031 × 0308 ÷ 0030 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 3031 × 005F ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 3031 × 0308 × 005F ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 3031 ÷ 1F1E6 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 3031 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 3031 ÷ 05D0 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 3031 × 0308 ÷ 05D0 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 3031 ÷ 0022 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 3031 × 0308 ÷ 0022 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 3031 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 3031 × 0308 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 3031 ÷ 231A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 3031 × 0308 ÷ 231A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 3031 ÷ 0020 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 3031 × 0308 ÷ 0020 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 3031 × 00AD ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 3031 × 0308 × 00AD ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 3031 × 0300 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 3031 × 0308 × 0300 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 3031 × 200D ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 3031 × 0308 × 200D ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 3031 ÷ 0061 × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 3031 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 3031 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 3031 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 3031 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 3031 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 3031 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 3031 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 3031 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 3031 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 3031 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 3031 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 3031 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 3031 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 3031 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 3031 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 3031 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 3031 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0041 ÷ 0001 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] (Other) ÷ [0.3] +÷ 0041 × 0308 ÷ 0001 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0041 ÷ 000D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [3.2] (CR) ÷ [0.3] +÷ 0041 × 0308 ÷ 000D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0041 ÷ 000A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [3.2] (LF) ÷ [0.3] +÷ 0041 × 0308 ÷ 000A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0041 ÷ 000B ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0041 × 0308 ÷ 000B ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0041 ÷ 3031 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0041 × 0308 ÷ 3031 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0041 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0041 × 0308 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0041 ÷ 003A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0041 × 0308 ÷ 003A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0041 ÷ 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0041 × 0308 ÷ 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0041 ÷ 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0041 × 0308 ÷ 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0041 × 0030 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0041 × 0308 × 0030 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0041 × 005F ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0041 × 0308 × 005F ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0041 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0041 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0041 × 05D0 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0041 × 0308 × 05D0 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0041 ÷ 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0041 × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0041 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0041 × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0041 ÷ 231A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0041 × 0308 ÷ 231A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0041 ÷ 0020 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0041 × 0308 ÷ 0020 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0041 × 00AD ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0041 × 0308 × 00AD ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0041 × 0300 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0041 × 0308 × 0300 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0041 × 200D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0041 × 0308 × 200D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0041 × 0061 × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0041 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0041 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0041 × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0041 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0041 × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0041 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0041 × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0041 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0041 × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0041 × 0031 ÷ 003A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0041 × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0041 × 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0041 × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0041 × 0031 ÷ 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0041 × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0041 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0041 × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 003A ÷ 0001 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] (Other) ÷ [0.3] +÷ 003A × 0308 ÷ 0001 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 003A ÷ 000D ÷ # ÷ [0.2] COLON (MidLetter) ÷ [3.2] (CR) ÷ [0.3] +÷ 003A × 0308 ÷ 000D ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 003A ÷ 000A ÷ # ÷ [0.2] COLON (MidLetter) ÷ [3.2] (LF) ÷ [0.3] +÷ 003A × 0308 ÷ 000A ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 003A ÷ 000B ÷ # ÷ [0.2] COLON (MidLetter) ÷ [3.2] (Newline) ÷ [0.3] +÷ 003A × 0308 ÷ 000B ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 003A ÷ 3031 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 003A × 0308 ÷ 3031 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 003A ÷ 0041 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 003A × 0308 ÷ 0041 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 003A ÷ 003A ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 003A × 0308 ÷ 003A ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 003A ÷ 002C ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 003A × 0308 ÷ 002C ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 003A ÷ 002E ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 003A × 0308 ÷ 002E ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 003A ÷ 0030 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 003A × 0308 ÷ 0030 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 003A ÷ 005F ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 003A × 0308 ÷ 005F ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 003A ÷ 1F1E6 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 003A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 003A ÷ 05D0 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 003A × 0308 ÷ 05D0 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 003A ÷ 0022 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 003A × 0308 ÷ 0022 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 003A ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 003A × 0308 ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 003A ÷ 231A ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 003A × 0308 ÷ 231A ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 003A ÷ 0020 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 003A × 0308 ÷ 0020 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 003A × 00AD ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 003A × 0308 × 00AD ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 003A × 0300 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 003A × 0308 × 0300 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 003A × 200D ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 003A × 0308 × 200D ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 003A ÷ 0061 × 2060 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 003A × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 003A ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 003A × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 003A ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 003A × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 003A ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 003A × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 003A ÷ 0061 ÷ 002C ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 003A × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 003A ÷ 0031 ÷ 003A ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 003A × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 003A ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 003A × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 003A ÷ 0031 ÷ 002C ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 003A × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 003A ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 003A × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002C ÷ 0001 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] (Other) ÷ [0.3] +÷ 002C × 0308 ÷ 0001 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 002C ÷ 000D ÷ # ÷ [0.2] COMMA (MidNum) ÷ [3.2] (CR) ÷ [0.3] +÷ 002C × 0308 ÷ 000D ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 002C ÷ 000A ÷ # ÷ [0.2] COMMA (MidNum) ÷ [3.2] (LF) ÷ [0.3] +÷ 002C × 0308 ÷ 000A ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 002C ÷ 000B ÷ # ÷ [0.2] COMMA (MidNum) ÷ [3.2] (Newline) ÷ [0.3] +÷ 002C × 0308 ÷ 000B ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 002C ÷ 3031 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 002C × 0308 ÷ 3031 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 002C ÷ 0041 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 002C × 0308 ÷ 0041 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 002C ÷ 003A ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002C × 0308 ÷ 003A ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002C ÷ 002C ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002C × 0308 ÷ 002C ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002C ÷ 002E ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 002C × 0308 ÷ 002E ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 002C ÷ 0030 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002C × 0308 ÷ 0030 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002C ÷ 005F ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 002C × 0308 ÷ 005F ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 002C ÷ 1F1E6 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 002C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 002C ÷ 05D0 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 002C × 0308 ÷ 05D0 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 002C ÷ 0022 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 002C × 0308 ÷ 0022 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 002C ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002C × 0308 ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002C ÷ 231A ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 002C × 0308 ÷ 231A ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 002C ÷ 0020 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 002C × 0308 ÷ 0020 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 002C × 00AD ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002C × 0308 × 00AD ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002C × 0300 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002C × 0308 × 0300 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002C × 200D ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 002C × 0308 × 200D ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 002C ÷ 0061 × 2060 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002C × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002C ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002C × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002C ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002C × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002C ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002C × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002C ÷ 0061 ÷ 002C ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002C × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002C ÷ 0031 ÷ 003A ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002C × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002C ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002C × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002C ÷ 0031 ÷ 002C ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002C × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002C ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002C × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002E ÷ 0001 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] (Other) ÷ [0.3] +÷ 002E × 0308 ÷ 0001 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 002E ÷ 000D ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [3.2] (CR) ÷ [0.3] +÷ 002E × 0308 ÷ 000D ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 002E ÷ 000A ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [3.2] (LF) ÷ [0.3] +÷ 002E × 0308 ÷ 000A ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 002E ÷ 000B ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [3.2] (Newline) ÷ [0.3] +÷ 002E × 0308 ÷ 000B ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 002E ÷ 3031 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 002E × 0308 ÷ 3031 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 002E ÷ 0041 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 002E × 0308 ÷ 0041 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 002E ÷ 003A ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002E × 0308 ÷ 003A ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002E ÷ 002C ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002E × 0308 ÷ 002C ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002E ÷ 002E ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 002E × 0308 ÷ 002E ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 002E ÷ 0030 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002E × 0308 ÷ 0030 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002E ÷ 005F ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 002E × 0308 ÷ 005F ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 002E ÷ 1F1E6 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 002E × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 002E ÷ 05D0 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 002E × 0308 ÷ 05D0 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 002E ÷ 0022 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 002E × 0308 ÷ 0022 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 002E ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002E × 0308 ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002E ÷ 231A ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 002E × 0308 ÷ 231A ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 002E ÷ 0020 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 002E × 0308 ÷ 0020 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 002E × 00AD ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002E × 0308 × 00AD ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002E × 0300 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002E × 0308 × 0300 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002E × 200D ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 002E × 0308 × 200D ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 002E ÷ 0061 × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002E × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002E ÷ 0061 ÷ 003A ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002E × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002E ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002E × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002E ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002E × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002E ÷ 0061 ÷ 002C ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002E × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002E ÷ 0031 ÷ 003A ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002E × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002E ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002E × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002E ÷ 0031 ÷ 002C ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002E × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002E ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002E × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0030 ÷ 0001 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] (Other) ÷ [0.3] +÷ 0030 × 0308 ÷ 0001 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0030 ÷ 000D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [3.2] (CR) ÷ [0.3] +÷ 0030 × 0308 ÷ 000D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0030 ÷ 000A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [3.2] (LF) ÷ [0.3] +÷ 0030 × 0308 ÷ 000A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0030 ÷ 000B ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0030 × 0308 ÷ 000B ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0030 ÷ 3031 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0030 × 0308 ÷ 3031 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0030 × 0041 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0030 × 0308 × 0041 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0030 ÷ 003A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0030 × 0308 ÷ 003A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0030 ÷ 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0030 × 0308 ÷ 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0030 ÷ 002E ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0030 × 0308 ÷ 002E ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0030 × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [8.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0030 × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [8.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0030 × 005F ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0030 × 0308 × 005F ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0030 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0030 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0030 × 05D0 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0030 × 0308 × 05D0 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0030 ÷ 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0030 × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0030 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0030 × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0030 ÷ 231A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0030 × 0308 ÷ 231A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0030 ÷ 0020 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0030 × 0308 ÷ 0020 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0030 × 00AD ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0030 × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0030 × 0300 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0030 × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0030 × 200D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0030 × 0308 × 200D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0030 × 0061 × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0030 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0030 × 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0030 × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0030 × 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0030 × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0030 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0030 × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0030 × 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0030 × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0030 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0030 × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0030 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0030 × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0030 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0030 × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0030 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0030 × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 005F ÷ 0001 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] (Other) ÷ [0.3] +÷ 005F × 0308 ÷ 0001 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 005F ÷ 000D ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [3.2] (CR) ÷ [0.3] +÷ 005F × 0308 ÷ 000D ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 005F ÷ 000A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [3.2] (LF) ÷ [0.3] +÷ 005F × 0308 ÷ 000A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 005F ÷ 000B ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [3.2] (Newline) ÷ [0.3] +÷ 005F × 0308 ÷ 000B ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 005F × 3031 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 005F × 0308 × 3031 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 005F × 0041 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 005F × 0308 × 0041 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 005F ÷ 003A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 005F × 0308 ÷ 003A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 005F ÷ 002C ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 005F × 0308 ÷ 002C ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 005F ÷ 002E ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 005F × 0308 ÷ 002E ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 005F × 0030 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 005F × 0308 × 0030 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 005F × 005F ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 005F × 0308 × 005F ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 005F ÷ 1F1E6 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 005F × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 005F × 05D0 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 005F × 0308 × 05D0 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 005F ÷ 0022 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 005F × 0308 ÷ 0022 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 005F ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 005F × 0308 ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 005F ÷ 231A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 005F × 0308 ÷ 231A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 005F ÷ 0020 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 005F × 0308 ÷ 0020 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 005F × 00AD ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 005F × 0308 × 00AD ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 005F × 0300 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 005F × 0308 × 0300 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 005F × 200D ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 005F × 0308 × 200D ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 005F × 0061 × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 005F × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 005F × 0061 ÷ 003A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 005F × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 005F × 0061 ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 005F × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 005F × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 005F × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 005F × 0061 ÷ 002C ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 005F × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 005F × 0031 ÷ 003A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 005F × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 005F × 0031 ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 005F × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 005F × 0031 ÷ 002C ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 005F × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 005F × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 005F × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] (Other) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [3.2] (CR) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [3.2] (LF) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 1F1E6 ÷ 000B ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [3.2] (Newline) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000B ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 1F1E6 ÷ 3031 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 3031 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 1F1E6 ÷ 0041 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0041 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 1F1E6 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 ÷ 002E ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 002E ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 1F1E6 ÷ 0030 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0030 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 1F1E6 ÷ 005F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 005F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [15.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F1E6 × 0308 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) × [15.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F1E6 ÷ 05D0 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 05D0 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 1F1E6 ÷ 0022 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0022 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 1F1E6 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 1F1E6 × 00AD ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0308 × 00AD ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 1F1E6 × 0308 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 1F1E6 ÷ 0061 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 05D0 ÷ 0001 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] (Other) ÷ [0.3] +÷ 05D0 × 0308 ÷ 0001 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 05D0 ÷ 000D ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [3.2] (CR) ÷ [0.3] +÷ 05D0 × 0308 ÷ 000D ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 05D0 ÷ 000A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [3.2] (LF) ÷ [0.3] +÷ 05D0 × 0308 ÷ 000A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 05D0 ÷ 000B ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [3.2] (Newline) ÷ [0.3] +÷ 05D0 × 0308 ÷ 000B ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 05D0 ÷ 3031 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 05D0 × 0308 ÷ 3031 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 05D0 × 0041 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 05D0 × 0308 × 0041 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 05D0 ÷ 003A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 05D0 × 0308 ÷ 003A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 05D0 ÷ 002C ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 05D0 × 0308 ÷ 002C ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 05D0 ÷ 002E ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 05D0 × 0308 ÷ 002E ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 05D0 × 0030 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 05D0 × 0308 × 0030 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 05D0 × 005F ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 05D0 × 0308 × 005F ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 05D0 ÷ 1F1E6 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 05D0 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 05D0 × 05D0 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 05D0 × 0308 × 05D0 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 05D0 ÷ 0022 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 05D0 × 0308 ÷ 0022 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 05D0 × 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [7.1] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 × 0308 × 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.1] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 ÷ 231A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 05D0 × 0308 ÷ 231A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 05D0 ÷ 0020 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 05D0 × 0308 ÷ 0020 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 05D0 × 00AD ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 05D0 × 0308 × 00AD ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 05D0 × 0300 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 05D0 × 0308 × 0300 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 05D0 × 200D ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 05D0 × 0308 × 200D ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 05D0 × 0061 × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 05D0 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 05D0 × 0061 ÷ 003A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 05D0 × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 05D0 × 0061 ÷ 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 05D0 × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 05D0 × 0061 ÷ 002C ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 05D0 × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 05D0 × 0031 ÷ 003A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 05D0 × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 05D0 × 0031 ÷ 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 × 0031 ÷ 002C ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 05D0 × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 05D0 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 05D0 × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0022 ÷ 0001 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] (Other) ÷ [0.3] +÷ 0022 × 0308 ÷ 0001 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0022 ÷ 000D ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [3.2] (CR) ÷ [0.3] +÷ 0022 × 0308 ÷ 000D ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0022 ÷ 000A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [3.2] (LF) ÷ [0.3] +÷ 0022 × 0308 ÷ 000A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0022 ÷ 000B ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0022 × 0308 ÷ 000B ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0022 ÷ 3031 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0022 × 0308 ÷ 3031 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0022 ÷ 0041 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0022 × 0308 ÷ 0041 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0022 ÷ 003A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0022 × 0308 ÷ 003A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0022 ÷ 002C ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0022 × 0308 ÷ 002C ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0022 ÷ 002E ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0022 × 0308 ÷ 002E ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0022 ÷ 0030 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0022 × 0308 ÷ 0030 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0022 ÷ 005F ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0022 × 0308 ÷ 005F ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0022 ÷ 1F1E6 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0022 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0022 ÷ 05D0 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0022 × 0308 ÷ 05D0 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0022 ÷ 0022 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0022 × 0308 ÷ 0022 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0022 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0022 × 0308 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0022 ÷ 231A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0022 × 0308 ÷ 231A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0022 ÷ 0020 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0022 × 0308 ÷ 0020 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0022 × 00AD ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0022 × 0308 × 00AD ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0022 × 0300 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0022 × 0308 × 0300 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0022 × 200D ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0022 × 0308 × 200D ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0022 ÷ 0061 × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0022 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0022 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0022 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0022 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0022 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0022 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0022 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0022 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0022 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0022 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0022 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0022 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0022 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0022 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0022 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0022 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0022 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0027 ÷ 0001 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] (Other) ÷ [0.3] +÷ 0027 × 0308 ÷ 0001 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0027 ÷ 000D ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [3.2] (CR) ÷ [0.3] +÷ 0027 × 0308 ÷ 000D ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0027 ÷ 000A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [3.2] (LF) ÷ [0.3] +÷ 0027 × 0308 ÷ 000A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0027 ÷ 000B ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0027 × 0308 ÷ 000B ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0027 ÷ 3031 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0027 × 0308 ÷ 3031 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0027 ÷ 0041 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0027 × 0308 ÷ 0041 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0027 ÷ 003A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0027 × 0308 ÷ 003A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0027 ÷ 002C ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0027 × 0308 ÷ 002C ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0027 ÷ 002E ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0027 × 0308 ÷ 002E ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0027 ÷ 0030 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0027 × 0308 ÷ 0030 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0027 ÷ 005F ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0027 × 0308 ÷ 005F ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0027 ÷ 1F1E6 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0027 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0027 ÷ 05D0 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0027 × 0308 ÷ 05D0 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0027 ÷ 0022 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0027 × 0308 ÷ 0022 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0027 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0027 × 0308 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0027 ÷ 231A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0027 × 0308 ÷ 231A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0027 ÷ 0020 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0027 × 0308 ÷ 0020 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0027 × 00AD ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0027 × 0308 × 00AD ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0027 × 0300 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0027 × 0308 × 0300 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0027 × 200D ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0027 × 0308 × 200D ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0027 ÷ 0061 × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0027 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0027 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0027 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0027 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0027 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0027 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0027 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0027 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0027 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0027 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0027 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0027 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0027 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0027 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0027 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0027 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0027 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 231A ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] (Other) ÷ [0.3] +÷ 231A × 0308 ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 231A ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [3.2] (CR) ÷ [0.3] +÷ 231A × 0308 ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 231A ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [3.2] (LF) ÷ [0.3] +÷ 231A × 0308 ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 231A ÷ 000B ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [3.2] (Newline) ÷ [0.3] +÷ 231A × 0308 ÷ 000B ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 231A ÷ 3031 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 231A × 0308 ÷ 3031 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 231A ÷ 0041 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 231A × 0308 ÷ 0041 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 231A ÷ 003A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 231A × 0308 ÷ 003A ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 231A ÷ 002C ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 231A × 0308 ÷ 002C ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 231A ÷ 002E ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 231A × 0308 ÷ 002E ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 231A ÷ 0030 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 231A × 0308 ÷ 0030 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 231A ÷ 005F ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 231A × 0308 ÷ 005F ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 231A ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 231A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 231A ÷ 05D0 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 231A × 0308 ÷ 05D0 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 231A ÷ 0022 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 231A × 0308 ÷ 0022 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 231A ÷ 0027 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 231A × 0308 ÷ 0027 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 231A ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 231A × 0308 ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 231A ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 231A × 0308 ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 231A × 00AD ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 231A × 0308 × 00AD ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 231A × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 231A × 0308 × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 231A × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 231A × 0308 × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 231A ÷ 0061 × 2060 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 231A × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 231A ÷ 0061 ÷ 003A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 231A × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 231A ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 231A × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 231A ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 231A × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 231A ÷ 0061 ÷ 002C ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 231A × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 231A ÷ 0031 ÷ 003A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 231A × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 231A ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 231A × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 231A ÷ 0031 ÷ 002C ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 231A × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 231A ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 231A × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0020 ÷ 0001 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] (Other) ÷ [0.3] +÷ 0020 × 0308 ÷ 0001 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0020 ÷ 000D ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [3.2] (CR) ÷ [0.3] +÷ 0020 × 0308 ÷ 000D ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0020 ÷ 000A ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [3.2] (LF) ÷ [0.3] +÷ 0020 × 0308 ÷ 000A ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0020 ÷ 000B ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0020 × 0308 ÷ 000B ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0020 ÷ 3031 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0020 × 0308 ÷ 3031 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0020 ÷ 0041 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0020 × 0308 ÷ 0041 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0020 ÷ 003A ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0020 × 0308 ÷ 003A ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0020 ÷ 002C ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0020 × 0308 ÷ 002C ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0020 ÷ 002E ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0020 × 0308 ÷ 002E ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0020 ÷ 0030 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0020 × 0308 ÷ 0030 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0020 ÷ 005F ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0020 × 0308 ÷ 005F ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0020 ÷ 05D0 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0020 × 0308 ÷ 05D0 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0020 ÷ 0022 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0020 × 0308 ÷ 0022 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0020 ÷ 0027 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0020 × 0308 ÷ 0027 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0020 ÷ 231A ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0020 × 0308 ÷ 231A ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0020 × 0020 ÷ # ÷ [0.2] SPACE (WSegSpace) × [3.4] SPACE (WSegSpace) ÷ [0.3] +÷ 0020 × 0308 ÷ 0020 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0020 × 00AD ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0020 × 0308 × 00AD ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0020 × 0308 × 200D ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0020 ÷ 0061 × 2060 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0020 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0020 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0020 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0020 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0020 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0020 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0020 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0020 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0020 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0020 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0020 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0020 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0020 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0020 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0020 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0020 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0020 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 00AD ÷ 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 00AD × 0308 ÷ 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 00AD ÷ 000D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 00AD × 0308 ÷ 000D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 00AD ÷ 000A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 00AD × 0308 ÷ 000A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 00AD ÷ 000B ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 00AD × 0308 ÷ 000B ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 00AD ÷ 3031 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 00AD × 0308 ÷ 3031 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 00AD ÷ 0041 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 00AD × 0308 ÷ 0041 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 00AD ÷ 003A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 00AD × 0308 ÷ 003A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 00AD ÷ 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 00AD × 0308 ÷ 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 00AD ÷ 002E ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 00AD × 0308 ÷ 002E ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 00AD ÷ 0030 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 00AD × 0308 ÷ 0030 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 00AD ÷ 005F ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 00AD × 0308 ÷ 005F ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 00AD ÷ 1F1E6 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 00AD × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 00AD ÷ 05D0 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 00AD × 0308 ÷ 05D0 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 00AD ÷ 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 00AD × 0308 ÷ 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 00AD ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 00AD × 0308 ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 00AD ÷ 231A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 00AD × 0308 ÷ 231A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 00AD ÷ 0020 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 00AD × 0308 ÷ 0020 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 00AD × 00AD ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 00AD × 0308 × 00AD ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 00AD × 0300 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 00AD × 0308 × 0300 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 00AD × 200D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 00AD × 0308 × 200D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 00AD ÷ 0061 × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 00AD × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 00AD ÷ 0061 ÷ 003A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 00AD × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 00AD ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 00AD × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 00AD ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 00AD × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 00AD ÷ 0061 ÷ 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 00AD × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 00AD ÷ 0031 ÷ 003A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 00AD × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 00AD ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 00AD × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 00AD ÷ 0031 ÷ 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 00AD × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 00AD ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 00AD × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0300 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0300 × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0300 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0300 × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0300 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0300 × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0300 ÷ 000B ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0300 × 0308 ÷ 000B ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0300 ÷ 3031 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0300 × 0308 ÷ 3031 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0300 ÷ 0041 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0300 × 0308 ÷ 0041 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0300 ÷ 003A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0300 × 0308 ÷ 003A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0300 ÷ 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0300 × 0308 ÷ 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0300 ÷ 002E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0300 × 0308 ÷ 002E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0300 ÷ 0030 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0300 × 0308 ÷ 0030 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0300 ÷ 005F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0300 × 0308 ÷ 005F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0300 ÷ 05D0 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0300 × 0308 ÷ 05D0 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0300 ÷ 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0300 × 0308 ÷ 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0300 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0300 × 0308 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0300 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0300 × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0300 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0300 × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0300 × 00AD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0300 × 0308 × 00AD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0300 ÷ 0061 × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0300 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0300 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0300 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0300 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0300 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0300 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0300 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0300 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0300 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0300 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0300 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0300 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0300 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0300 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0300 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0300 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0300 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 200D ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 200D × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 200D ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 200D ÷ 000B ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 200D × 0308 ÷ 000B ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 200D ÷ 3031 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 200D × 0308 ÷ 3031 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 200D ÷ 0041 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 200D × 0308 ÷ 0041 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 200D ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D × 0308 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D × 0308 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D ÷ 002E ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 200D × 0308 ÷ 002E ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 200D ÷ 0030 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 200D × 0308 ÷ 0030 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 200D ÷ 005F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 200D × 0308 ÷ 005F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D ÷ 05D0 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 200D × 0308 ÷ 05D0 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 200D ÷ 0022 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 200D × 0308 ÷ 0022 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 200D ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D × 0308 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D × 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] WATCH (ExtPict) ÷ [0.3] +÷ 200D × 0308 ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 200D ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 200D × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 200D × 00AD ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 200D × 0308 × 00AD ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 200D × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 200D ÷ 0061 × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D ÷ 0061 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D ÷ 0061 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D ÷ 0031 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D ÷ 0031 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 2060 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 × 2060 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 × 2060 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 × 2060 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 × 2060 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 × 2060 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 2060 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 2060 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 2060 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 × 2060 × 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 × 2060 × 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 × 2060 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 × 2060 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 × 2060 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 × 2060 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 2060 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 × 2060 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 × 2060 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 × 2060 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 × 2060 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 2060 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 2060 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 2060 × 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 2060 × 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 2060 × 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 2060 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 × 003A × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 003A × 0308 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 × 003A × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 × 003A × 0308 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 003A × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 × 003A × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 003A × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 003A × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 003A × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 003A × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 003A × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 003A × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 003A × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 003A × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 003A × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 × 0027 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 × 0027 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 0027 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 × 0027 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 0027 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 0027 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 002C × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 003A × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 × 0027 × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 × 0027 × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 0027 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 0027 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 × 0027 × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 × 0027 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 × 0027 × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 × 0027 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 0027 × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 0027 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 × 0027 × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 × 002C × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 × 002C × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 002C × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 002C × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 × 002C × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 × 002C × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 × 002C × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 × 002C × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 002C × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 002C × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 × 002C × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D × 000A ÷ 0061 ÷ 000A ÷ 0308 ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [3.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [0.3] +÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [0.3] +÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] ARABIC LETTER NOON (ALetter) ÷ [0.3] +÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (ALetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0041 × 0041 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0041 × 003A × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0041 ÷ 003A ÷ 003A ÷ 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 05D0 × 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [7.1] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 × 0022 × 05D0 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [7.2] QUOTATION MARK (Double_Quote) × [7.3] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0041 × 0030 × 0030 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [9.0] DIGIT ZERO (Numeric) × [8.0] DIGIT ZERO (Numeric) × [10.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0030 × 002C × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0030 ÷ 002C ÷ 002C ÷ 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 3031 × 3031 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [13.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0041 × 005F × 0030 × 005F × 3031 × 005F ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ZERO (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] VERTICAL KANA REPEAT MARK (Katakana) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0041 × 005F × 005F × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [15.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [16.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [16.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 200D × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [16.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 × 1F1E9 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [16.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) × [16.0] REGIONAL INDICATOR SYMBOL LETTER D (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 1F476 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] BABY (ExtPict) × [4.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_FE) ÷ [999.0] BABY (ExtPict) ÷ [0.3] +÷ 1F6D1 × 200D × 1F6D1 ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 0061 × 200D × 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 2701 × 200D × 2701 ÷ # ÷ [0.2] UPPER BLADE SCISSORS (Other) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] UPPER BLADE SCISSORS (Other) ÷ [0.3] +÷ 0061 × 200D × 2701 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] UPPER BLADE SCISSORS (Other) ÷ [0.3] +÷ 1F476 × 1F3FF × 0308 × 200D × 1F476 × 1F3FF ÷ # ÷ [0.2] BABY (ExtPict) × [4.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] BABY (ExtPict) × [4.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_FE) ÷ [0.3] +÷ 1F6D1 × 1F3FF ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) × [4.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_FE) ÷ [0.3] +÷ 200D × 1F6D1 × 1F3FF ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] OCTAGONAL SIGN (ExtPict) × [4.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_FE) ÷ [0.3] +÷ 200D × 1F6D1 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 200D × 1F6D1 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 1F6D1 ÷ 1F6D1 ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) ÷ [999.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 0061 × 0308 × 200D × 0308 × 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 0020 × 0020 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] SPACE (WSegSpace) × [3.4] SPACE (WSegSpace) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 003A ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 003A ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 003A ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 003A ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 003A ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 003A ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 003A ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 003A ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 003A ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 003A ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002E ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002E ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002E ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 002E ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002E ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002E ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002E ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002E ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002E ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 002E ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002E ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002E ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002E ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002E ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002E ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 002E ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002E ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002E ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002C ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002C ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002C ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002C ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002C ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002C ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002C ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002C ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002C ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002C ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 003A ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 003A ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 003A ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 003A ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 003A ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 003A ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 003A ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 003A ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 003A ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 003A ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002E ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002E ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002E ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 002E ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002E ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002E ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002E ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002E ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002E ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 002E ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002E ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002E ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002E ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002E ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002E ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 002E ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002E ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002E ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002C ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002C ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002C ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002C ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002C ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002C ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002C ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002C ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002C ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002C ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +# +# Lines: 1823 +# +# EOF diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_fwd.bigendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_fwd.bigendian.dfa new file mode 100644 index 0000000000000..0efaaf290fa3e Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_fwd.bigendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_fwd.littleendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_fwd.littleendian.dfa new file mode 100644 index 0000000000000..eb240256c3d59 Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_fwd.littleendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_fwd.rs b/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_fwd.rs new file mode 100644 index 0000000000000..b53b1d7d958b8 --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_fwd.rs @@ -0,0 +1,45 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate dfa --name GRAPHEME_BREAK_FWD --sparse --minimize --anchored --state-size 2 src/unicode/fsm/ [snip (arg too long)] +// +// ucd-generate 0.2.9 is available on crates.io. + +#[cfg(target_endian = "big")] +lazy_static::lazy_static! { + pub static ref GRAPHEME_BREAK_FWD: ::regex_automata::SparseDFA<&'static [u8], u16> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("grapheme_break_fwd.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static::lazy_static! { + pub static ref GRAPHEME_BREAK_FWD: ::regex_automata::SparseDFA<&'static [u8], u16> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("grapheme_break_fwd.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_rev.bigendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_rev.bigendian.dfa new file mode 100644 index 0000000000000..d42cd3652733d Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_rev.bigendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_rev.littleendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_rev.littleendian.dfa new file mode 100644 index 0000000000000..c75ea5fd62caa Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_rev.littleendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_rev.rs b/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_rev.rs new file mode 100644 index 0000000000000..93e888c64a9df --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/fsm/grapheme_break_rev.rs @@ -0,0 +1,45 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate dfa --name GRAPHEME_BREAK_REV --reverse --longest --sparse --minimize --anchored --state-size 2 src/unicode/fsm/ [snip (arg too long)] +// +// ucd-generate 0.2.9 is available on crates.io. + +#[cfg(target_endian = "big")] +lazy_static::lazy_static! { + pub static ref GRAPHEME_BREAK_REV: ::regex_automata::SparseDFA<&'static [u8], u16> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("grapheme_break_rev.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static::lazy_static! { + pub static ref GRAPHEME_BREAK_REV: ::regex_automata::SparseDFA<&'static [u8], u16> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("grapheme_break_rev.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/mod.rs b/vendor/bstr-0.2.17/src/unicode/fsm/mod.rs new file mode 100644 index 0000000000000..ae6c499fc3ff7 --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/fsm/mod.rs @@ -0,0 +1,8 @@ +pub mod grapheme_break_fwd; +pub mod grapheme_break_rev; +pub mod regional_indicator_rev; +pub mod sentence_break_fwd; +pub mod simple_word_fwd; +pub mod whitespace_anchored_fwd; +pub mod whitespace_anchored_rev; +pub mod word_break_fwd; diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/regional_indicator_rev.bigendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/regional_indicator_rev.bigendian.dfa new file mode 100644 index 0000000000000..1a3357f714d45 Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/regional_indicator_rev.bigendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/regional_indicator_rev.littleendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/regional_indicator_rev.littleendian.dfa new file mode 100644 index 0000000000000..e437aae3ad775 Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/regional_indicator_rev.littleendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/regional_indicator_rev.rs b/vendor/bstr-0.2.17/src/unicode/fsm/regional_indicator_rev.rs new file mode 100644 index 0000000000000..2bf7e4c91884e --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/fsm/regional_indicator_rev.rs @@ -0,0 +1,45 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate dfa --name REGIONAL_INDICATOR_REV --reverse --classes --minimize --anchored --premultiply --state-size 1 src/unicode/fsm/ \p{gcb=Regional_Indicator} +// +// ucd-generate 0.2.9 is available on crates.io. + +#[cfg(target_endian = "big")] +lazy_static::lazy_static! { + pub static ref REGIONAL_INDICATOR_REV: ::regex_automata::DenseDFA<&'static [u8], u8> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("regional_indicator_rev.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::DenseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static::lazy_static! { + pub static ref REGIONAL_INDICATOR_REV: ::regex_automata::DenseDFA<&'static [u8], u8> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("regional_indicator_rev.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::DenseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/sentence_break_fwd.bigendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/sentence_break_fwd.bigendian.dfa new file mode 100644 index 0000000000000..a1813d7c8eb16 Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/sentence_break_fwd.bigendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/sentence_break_fwd.littleendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/sentence_break_fwd.littleendian.dfa new file mode 100644 index 0000000000000..2763583be9f39 Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/sentence_break_fwd.littleendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/sentence_break_fwd.rs b/vendor/bstr-0.2.17/src/unicode/fsm/sentence_break_fwd.rs new file mode 100644 index 0000000000000..cc937a4ba6bae --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/fsm/sentence_break_fwd.rs @@ -0,0 +1,45 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate dfa --name SENTENCE_BREAK_FWD --minimize --sparse --anchored --state-size 4 src/unicode/fsm/ [snip (arg too long)] +// +// ucd-generate 0.2.9 is available on crates.io. + +#[cfg(target_endian = "big")] +lazy_static::lazy_static! { + pub static ref SENTENCE_BREAK_FWD: ::regex_automata::SparseDFA<&'static [u8], u32> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("sentence_break_fwd.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static::lazy_static! { + pub static ref SENTENCE_BREAK_FWD: ::regex_automata::SparseDFA<&'static [u8], u32> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("sentence_break_fwd.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/simple_word_fwd.bigendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/simple_word_fwd.bigendian.dfa new file mode 100644 index 0000000000000..adc64c1924752 Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/simple_word_fwd.bigendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/simple_word_fwd.littleendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/simple_word_fwd.littleendian.dfa new file mode 100644 index 0000000000000..dd48386194737 Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/simple_word_fwd.littleendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/simple_word_fwd.rs b/vendor/bstr-0.2.17/src/unicode/fsm/simple_word_fwd.rs new file mode 100644 index 0000000000000..f1f3da5f8de9f --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/fsm/simple_word_fwd.rs @@ -0,0 +1,45 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate dfa --name SIMPLE_WORD_FWD --sparse --minimize --state-size 2 src/unicode/fsm/ \w +// +// ucd-generate 0.2.9 is available on crates.io. + +#[cfg(target_endian = "big")] +lazy_static::lazy_static! { + pub static ref SIMPLE_WORD_FWD: ::regex_automata::SparseDFA<&'static [u8], u16> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("simple_word_fwd.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static::lazy_static! { + pub static ref SIMPLE_WORD_FWD: ::regex_automata::SparseDFA<&'static [u8], u16> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("simple_word_fwd.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_fwd.bigendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_fwd.bigendian.dfa new file mode 100644 index 0000000000000..bcfc4e9a15d37 Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_fwd.bigendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_fwd.littleendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_fwd.littleendian.dfa new file mode 100644 index 0000000000000..d534a464a5065 Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_fwd.littleendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_fwd.rs b/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_fwd.rs new file mode 100644 index 0000000000000..419b5d4f68a91 --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_fwd.rs @@ -0,0 +1,45 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate dfa --name WHITESPACE_ANCHORED_FWD --anchored --classes --premultiply --minimize --state-size 1 src/unicode/fsm/ \s+ +// +// ucd-generate 0.2.9 is available on crates.io. + +#[cfg(target_endian = "big")] +lazy_static::lazy_static! { + pub static ref WHITESPACE_ANCHORED_FWD: ::regex_automata::DenseDFA<&'static [u8], u8> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("whitespace_anchored_fwd.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::DenseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static::lazy_static! { + pub static ref WHITESPACE_ANCHORED_FWD: ::regex_automata::DenseDFA<&'static [u8], u8> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("whitespace_anchored_fwd.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::DenseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_rev.bigendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_rev.bigendian.dfa new file mode 100644 index 0000000000000..427d3a9227fd5 Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_rev.bigendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_rev.littleendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_rev.littleendian.dfa new file mode 100644 index 0000000000000..7cc3a0a995f4d Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_rev.littleendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_rev.rs b/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_rev.rs new file mode 100644 index 0000000000000..301b03cd9e0e5 --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/fsm/whitespace_anchored_rev.rs @@ -0,0 +1,45 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate dfa --name WHITESPACE_ANCHORED_REV --reverse --anchored --classes --premultiply --minimize --state-size 2 src/unicode/fsm/ \s+ +// +// ucd-generate 0.2.9 is available on crates.io. + +#[cfg(target_endian = "big")] +lazy_static::lazy_static! { + pub static ref WHITESPACE_ANCHORED_REV: ::regex_automata::DenseDFA<&'static [u16], u16> = { + #[repr(C)] + struct Aligned { + _align: [u16; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("whitespace_anchored_rev.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::DenseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static::lazy_static! { + pub static ref WHITESPACE_ANCHORED_REV: ::regex_automata::DenseDFA<&'static [u16], u16> = { + #[repr(C)] + struct Aligned { + _align: [u16; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("whitespace_anchored_rev.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::DenseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/word_break_fwd.bigendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/word_break_fwd.bigendian.dfa new file mode 100644 index 0000000000000..1e75db68a4e27 Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/word_break_fwd.bigendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/word_break_fwd.littleendian.dfa b/vendor/bstr-0.2.17/src/unicode/fsm/word_break_fwd.littleendian.dfa new file mode 100644 index 0000000000000..e3093a3f0c850 Binary files /dev/null and b/vendor/bstr-0.2.17/src/unicode/fsm/word_break_fwd.littleendian.dfa differ diff --git a/vendor/bstr-0.2.17/src/unicode/fsm/word_break_fwd.rs b/vendor/bstr-0.2.17/src/unicode/fsm/word_break_fwd.rs new file mode 100644 index 0000000000000..fb041b7a3c633 --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/fsm/word_break_fwd.rs @@ -0,0 +1,45 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate dfa --name WORD_BREAK_FWD --sparse --minimize --anchored --state-size 4 src/unicode/fsm/ [snip (arg too long)] +// +// ucd-generate 0.2.9 is available on crates.io. + +#[cfg(target_endian = "big")] +lazy_static::lazy_static! { + pub static ref WORD_BREAK_FWD: ::regex_automata::SparseDFA<&'static [u8], u32> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("word_break_fwd.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static::lazy_static! { + pub static ref WORD_BREAK_FWD: ::regex_automata::SparseDFA<&'static [u8], u32> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("word_break_fwd.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/vendor/bstr-0.2.17/src/unicode/grapheme.rs b/vendor/bstr-0.2.17/src/unicode/grapheme.rs new file mode 100644 index 0000000000000..ad31cf158ef2e --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/grapheme.rs @@ -0,0 +1,355 @@ +use regex_automata::DFA; + +use crate::ext_slice::ByteSlice; +use crate::unicode::fsm::grapheme_break_fwd::GRAPHEME_BREAK_FWD; +use crate::unicode::fsm::grapheme_break_rev::GRAPHEME_BREAK_REV; +use crate::unicode::fsm::regional_indicator_rev::REGIONAL_INDICATOR_REV; +use crate::utf8; + +/// An iterator over grapheme clusters in a byte string. +/// +/// This iterator is typically constructed by +/// [`ByteSlice::graphemes`](trait.ByteSlice.html#method.graphemes). +/// +/// Unicode defines a grapheme cluster as an *approximation* to a single user +/// visible character. A grapheme cluster, or just "grapheme," is made up of +/// one or more codepoints. For end user oriented tasks, one should generally +/// prefer using graphemes instead of [`Chars`](struct.Chars.html), which +/// always yields one codepoint at a time. +/// +/// Since graphemes are made up of one or more codepoints, this iterator yields +/// `&str` elements. When invalid UTF-8 is encountered, replacement codepoints +/// are [substituted](index.html#handling-of-invalid-utf-8). +/// +/// This iterator can be used in reverse. When reversed, exactly the same +/// set of grapheme clusters are yielded, but in reverse order. +/// +/// This iterator only yields *extended* grapheme clusters, in accordance with +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Grapheme_Cluster_Boundaries). +#[derive(Clone, Debug)] +pub struct Graphemes<'a> { + bs: &'a [u8], +} + +impl<'a> Graphemes<'a> { + pub(crate) fn new(bs: &'a [u8]) -> Graphemes<'a> { + Graphemes { bs } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut it = b"abc".graphemes(); + /// + /// assert_eq!(b"abc", it.as_bytes()); + /// it.next(); + /// assert_eq!(b"bc", it.as_bytes()); + /// it.next(); + /// it.next(); + /// assert_eq!(b"", it.as_bytes()); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &'a [u8] { + self.bs + } +} + +impl<'a> Iterator for Graphemes<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + let (grapheme, size) = decode_grapheme(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + Some(grapheme) + } +} + +impl<'a> DoubleEndedIterator for Graphemes<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + let (grapheme, size) = decode_last_grapheme(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[..self.bs.len() - size]; + Some(grapheme) + } +} + +/// An iterator over grapheme clusters in a byte string and their byte index +/// positions. +/// +/// This iterator is typically constructed by +/// [`ByteSlice::grapheme_indices`](trait.ByteSlice.html#method.grapheme_indices). +/// +/// Unicode defines a grapheme cluster as an *approximation* to a single user +/// visible character. A grapheme cluster, or just "grapheme," is made up of +/// one or more codepoints. For end user oriented tasks, one should generally +/// prefer using graphemes instead of [`Chars`](struct.Chars.html), which +/// always yields one codepoint at a time. +/// +/// Since graphemes are made up of one or more codepoints, this iterator +/// yields `&str` elements (along with their start and end byte offsets). +/// When invalid UTF-8 is encountered, replacement codepoints are +/// [substituted](index.html#handling-of-invalid-utf-8). Because of this, the +/// indices yielded by this iterator may not correspond to the length of the +/// grapheme cluster yielded with those indices. For example, when this +/// iterator encounters `\xFF` in the byte string, then it will yield a pair +/// of indices ranging over a single byte, but will provide an `&str` +/// equivalent to `"\u{FFFD}"`, which is three bytes in length. However, when +/// given only valid UTF-8, then all indices are in exact correspondence with +/// their paired grapheme cluster. +/// +/// This iterator can be used in reverse. When reversed, exactly the same +/// set of grapheme clusters are yielded, but in reverse order. +/// +/// This iterator only yields *extended* grapheme clusters, in accordance with +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Grapheme_Cluster_Boundaries). +#[derive(Clone, Debug)] +pub struct GraphemeIndices<'a> { + bs: &'a [u8], + forward_index: usize, + reverse_index: usize, +} + +impl<'a> GraphemeIndices<'a> { + pub(crate) fn new(bs: &'a [u8]) -> GraphemeIndices<'a> { + GraphemeIndices { bs: bs, forward_index: 0, reverse_index: bs.len() } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut it = b"abc".grapheme_indices(); + /// + /// assert_eq!(b"abc", it.as_bytes()); + /// it.next(); + /// assert_eq!(b"bc", it.as_bytes()); + /// it.next(); + /// it.next(); + /// assert_eq!(b"", it.as_bytes()); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &'a [u8] { + self.bs + } +} + +impl<'a> Iterator for GraphemeIndices<'a> { + type Item = (usize, usize, &'a str); + + #[inline] + fn next(&mut self) -> Option<(usize, usize, &'a str)> { + let index = self.forward_index; + let (grapheme, size) = decode_grapheme(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + self.forward_index += size; + Some((index, index + size, grapheme)) + } +} + +impl<'a> DoubleEndedIterator for GraphemeIndices<'a> { + #[inline] + fn next_back(&mut self) -> Option<(usize, usize, &'a str)> { + let (grapheme, size) = decode_last_grapheme(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[..self.bs.len() - size]; + self.reverse_index -= size; + Some((self.reverse_index, self.reverse_index + size, grapheme)) + } +} + +/// Decode a grapheme from the given byte string. +/// +/// This returns the resulting grapheme (which may be a Unicode replacement +/// codepoint if invalid UTF-8 was found), along with the number of bytes +/// decoded in the byte string. The number of bytes decoded may not be the +/// same as the length of grapheme in the case where invalid UTF-8 is found. +pub fn decode_grapheme(bs: &[u8]) -> (&str, usize) { + if bs.is_empty() { + ("", 0) + } else if let Some(end) = GRAPHEME_BREAK_FWD.find(bs) { + // Safe because a match can only occur for valid UTF-8. + let grapheme = unsafe { bs[..end].to_str_unchecked() }; + (grapheme, grapheme.len()) + } else { + const INVALID: &'static str = "\u{FFFD}"; + // No match on non-empty bytes implies we found invalid UTF-8. + let (_, size) = utf8::decode_lossy(bs); + (INVALID, size) + } +} + +fn decode_last_grapheme(bs: &[u8]) -> (&str, usize) { + if bs.is_empty() { + ("", 0) + } else if let Some(mut start) = GRAPHEME_BREAK_REV.rfind(bs) { + start = adjust_rev_for_regional_indicator(bs, start); + // Safe because a match can only occur for valid UTF-8. + let grapheme = unsafe { bs[start..].to_str_unchecked() }; + (grapheme, grapheme.len()) + } else { + const INVALID: &'static str = "\u{FFFD}"; + // No match on non-empty bytes implies we found invalid UTF-8. + let (_, size) = utf8::decode_last_lossy(bs); + (INVALID, size) + } +} + +/// Return the correct offset for the next grapheme decoded at the end of the +/// given byte string, where `i` is the initial guess. In particular, +/// `&bs[i..]` represents the candidate grapheme. +/// +/// `i` is returned by this function in all cases except when `&bs[i..]` is +/// a pair of regional indicator codepoints. In that case, if an odd number of +/// additional regional indicator codepoints precedes `i`, then `i` is +/// adjusted such that it points to only a single regional indicator. +/// +/// This "fixing" is necessary to handle the requirement that a break cannot +/// occur between regional indicators where it would cause an odd number of +/// regional indicators to exist before the break from the *start* of the +/// string. A reverse regex cannot detect this case easily without look-around. +fn adjust_rev_for_regional_indicator(mut bs: &[u8], i: usize) -> usize { + // All regional indicators use a 4 byte encoding, and we only care about + // the case where we found a pair of regional indicators. + if bs.len() - i != 8 { + return i; + } + // Count all contiguous occurrences of regional indicators. If there's an + // even number of them, then we can accept the pair we found. Otherwise, + // we can only take one of them. + // + // FIXME: This is quadratic in the worst case, e.g., a string of just + // regional indicator codepoints. A fix probably requires refactoring this + // code a bit such that we don't rescan regional indicators. + let mut count = 0; + while let Some(start) = REGIONAL_INDICATOR_REV.rfind(bs) { + bs = &bs[..start]; + count += 1; + } + if count % 2 == 0 { + i + } else { + i + 4 + } +} + +#[cfg(test)] +mod tests { + use ucd_parse::GraphemeClusterBreakTest; + + use super::*; + use crate::ext_slice::ByteSlice; + use crate::tests::LOSSY_TESTS; + + #[test] + fn forward_ucd() { + for (i, test) in ucdtests().into_iter().enumerate() { + let given = test.grapheme_clusters.concat(); + let got: Vec = Graphemes::new(given.as_bytes()) + .map(|cluster| cluster.to_string()) + .collect(); + assert_eq!( + test.grapheme_clusters, + got, + "\ngrapheme forward break test {} failed:\n\ + given: {:?}\n\ + expected: {:?}\n\ + got: {:?}\n", + i, + uniescape(&given), + uniescape_vec(&test.grapheme_clusters), + uniescape_vec(&got), + ); + } + } + + #[test] + fn reverse_ucd() { + for (i, test) in ucdtests().into_iter().enumerate() { + let given = test.grapheme_clusters.concat(); + let mut got: Vec = Graphemes::new(given.as_bytes()) + .rev() + .map(|cluster| cluster.to_string()) + .collect(); + got.reverse(); + assert_eq!( + test.grapheme_clusters, + got, + "\n\ngrapheme reverse break test {} failed:\n\ + given: {:?}\n\ + expected: {:?}\n\ + got: {:?}\n", + i, + uniescape(&given), + uniescape_vec(&test.grapheme_clusters), + uniescape_vec(&got), + ); + } + } + + #[test] + fn forward_lossy() { + for &(expected, input) in LOSSY_TESTS { + let got = Graphemes::new(input.as_bytes()).collect::(); + assert_eq!(expected, got); + } + } + + #[test] + fn reverse_lossy() { + for &(expected, input) in LOSSY_TESTS { + let expected: String = expected.chars().rev().collect(); + let got = + Graphemes::new(input.as_bytes()).rev().collect::(); + assert_eq!(expected, got); + } + } + + fn uniescape(s: &str) -> String { + s.chars().flat_map(|c| c.escape_unicode()).collect::() + } + + fn uniescape_vec(strs: &[String]) -> Vec { + strs.iter().map(|s| uniescape(s)).collect() + } + + /// Return all of the UCD for grapheme breaks. + fn ucdtests() -> Vec { + const TESTDATA: &'static str = + include_str!("data/GraphemeBreakTest.txt"); + + let mut tests = vec![]; + for mut line in TESTDATA.lines() { + line = line.trim(); + if line.starts_with("#") || line.contains("surrogate") { + continue; + } + tests.push(line.parse().unwrap()); + } + tests + } +} diff --git a/vendor/bstr-0.2.17/src/unicode/mod.rs b/vendor/bstr-0.2.17/src/unicode/mod.rs new file mode 100644 index 0000000000000..60318f437eb8f --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/mod.rs @@ -0,0 +1,12 @@ +pub use self::grapheme::{decode_grapheme, GraphemeIndices, Graphemes}; +pub use self::sentence::{SentenceIndices, Sentences}; +pub use self::whitespace::{whitespace_len_fwd, whitespace_len_rev}; +pub use self::word::{ + WordIndices, Words, WordsWithBreakIndices, WordsWithBreaks, +}; + +mod fsm; +mod grapheme; +mod sentence; +mod whitespace; +mod word; diff --git a/vendor/bstr-0.2.17/src/unicode/sentence.rs b/vendor/bstr-0.2.17/src/unicode/sentence.rs new file mode 100644 index 0000000000000..063f342e26e03 --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/sentence.rs @@ -0,0 +1,220 @@ +use regex_automata::DFA; + +use crate::ext_slice::ByteSlice; +use crate::unicode::fsm::sentence_break_fwd::SENTENCE_BREAK_FWD; +use crate::utf8; + +/// An iterator over sentences in a byte string. +/// +/// This iterator is typically constructed by +/// [`ByteSlice::sentences`](trait.ByteSlice.html#method.sentences). +/// +/// Sentences typically include their trailing punctuation and whitespace. +/// +/// Since sentences are made up of one or more codepoints, this iterator yields +/// `&str` elements. When invalid UTF-8 is encountered, replacement codepoints +/// are [substituted](index.html#handling-of-invalid-utf-8). +/// +/// This iterator yields words in accordance with the default sentence boundary +/// rules specified in +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Sentence_Boundaries). +#[derive(Clone, Debug)] +pub struct Sentences<'a> { + bs: &'a [u8], +} + +impl<'a> Sentences<'a> { + pub(crate) fn new(bs: &'a [u8]) -> Sentences<'a> { + Sentences { bs } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut it = b"I want this. Not that. Right now.".sentences(); + /// + /// assert_eq!(&b"I want this. Not that. Right now."[..], it.as_bytes()); + /// it.next(); + /// assert_eq!(b"Not that. Right now.", it.as_bytes()); + /// it.next(); + /// it.next(); + /// assert_eq!(b"", it.as_bytes()); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &'a [u8] { + self.bs + } +} + +impl<'a> Iterator for Sentences<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + let (sentence, size) = decode_sentence(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + Some(sentence) + } +} + +/// An iterator over sentences in a byte string, along with their byte offsets. +/// +/// This iterator is typically constructed by +/// [`ByteSlice::sentence_indices`](trait.ByteSlice.html#method.sentence_indices). +/// +/// Sentences typically include their trailing punctuation and whitespace. +/// +/// Since sentences are made up of one or more codepoints, this iterator +/// yields `&str` elements (along with their start and end byte offsets). +/// When invalid UTF-8 is encountered, replacement codepoints are +/// [substituted](index.html#handling-of-invalid-utf-8). Because of this, the +/// indices yielded by this iterator may not correspond to the length of the +/// sentence yielded with those indices. For example, when this iterator +/// encounters `\xFF` in the byte string, then it will yield a pair of indices +/// ranging over a single byte, but will provide an `&str` equivalent to +/// `"\u{FFFD}"`, which is three bytes in length. However, when given only +/// valid UTF-8, then all indices are in exact correspondence with their paired +/// word. +/// +/// This iterator yields words in accordance with the default sentence boundary +/// rules specified in +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Sentence_Boundaries). +#[derive(Clone, Debug)] +pub struct SentenceIndices<'a> { + bs: &'a [u8], + forward_index: usize, +} + +impl<'a> SentenceIndices<'a> { + pub(crate) fn new(bs: &'a [u8]) -> SentenceIndices<'a> { + SentenceIndices { bs: bs, forward_index: 0 } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut it = b"I want this. Not that. Right now.".sentence_indices(); + /// + /// assert_eq!(&b"I want this. Not that. Right now."[..], it.as_bytes()); + /// it.next(); + /// assert_eq!(b"Not that. Right now.", it.as_bytes()); + /// it.next(); + /// it.next(); + /// assert_eq!(b"", it.as_bytes()); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &'a [u8] { + self.bs + } +} + +impl<'a> Iterator for SentenceIndices<'a> { + type Item = (usize, usize, &'a str); + + #[inline] + fn next(&mut self) -> Option<(usize, usize, &'a str)> { + let index = self.forward_index; + let (word, size) = decode_sentence(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + self.forward_index += size; + Some((index, index + size, word)) + } +} + +fn decode_sentence(bs: &[u8]) -> (&str, usize) { + if bs.is_empty() { + ("", 0) + } else if let Some(end) = SENTENCE_BREAK_FWD.find(bs) { + // Safe because a match can only occur for valid UTF-8. + let sentence = unsafe { bs[..end].to_str_unchecked() }; + (sentence, sentence.len()) + } else { + const INVALID: &'static str = "\u{FFFD}"; + // No match on non-empty bytes implies we found invalid UTF-8. + let (_, size) = utf8::decode_lossy(bs); + (INVALID, size) + } +} + +#[cfg(test)] +mod tests { + use ucd_parse::SentenceBreakTest; + + use crate::ext_slice::ByteSlice; + + #[test] + fn forward_ucd() { + for (i, test) in ucdtests().into_iter().enumerate() { + let given = test.sentences.concat(); + let got = sentences(given.as_bytes()); + assert_eq!( + test.sentences, + got, + "\n\nsentence forward break test {} failed:\n\ + given: {:?}\n\ + expected: {:?}\n\ + got: {:?}\n", + i, + given, + strs_to_bstrs(&test.sentences), + strs_to_bstrs(&got), + ); + } + } + + // Some additional tests that don't seem to be covered by the UCD tests. + #[test] + fn forward_additional() { + assert_eq!(vec!["a.. ", "A"], sentences(b"a.. A")); + assert_eq!(vec!["a.. a"], sentences(b"a.. a")); + + assert_eq!(vec!["a... ", "A"], sentences(b"a... A")); + assert_eq!(vec!["a... a"], sentences(b"a... a")); + + assert_eq!(vec!["a...,..., a"], sentences(b"a...,..., a")); + } + + fn sentences(bytes: &[u8]) -> Vec<&str> { + bytes.sentences().collect() + } + + fn strs_to_bstrs>(strs: &[S]) -> Vec<&[u8]> { + strs.iter().map(|s| s.as_ref().as_bytes()).collect() + } + + /// Return all of the UCD for sentence breaks. + fn ucdtests() -> Vec { + const TESTDATA: &'static str = + include_str!("data/SentenceBreakTest.txt"); + + let mut tests = vec![]; + for mut line in TESTDATA.lines() { + line = line.trim(); + if line.starts_with("#") || line.contains("surrogate") { + continue; + } + tests.push(line.parse().unwrap()); + } + tests + } +} diff --git a/vendor/bstr-0.2.17/src/unicode/whitespace.rs b/vendor/bstr-0.2.17/src/unicode/whitespace.rs new file mode 100644 index 0000000000000..949a83fafdfe4 --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/whitespace.rs @@ -0,0 +1,14 @@ +use regex_automata::DFA; + +use crate::unicode::fsm::whitespace_anchored_fwd::WHITESPACE_ANCHORED_FWD; +use crate::unicode::fsm::whitespace_anchored_rev::WHITESPACE_ANCHORED_REV; + +/// Return the first position of a non-whitespace character. +pub fn whitespace_len_fwd(slice: &[u8]) -> usize { + WHITESPACE_ANCHORED_FWD.find(slice).unwrap_or(0) +} + +/// Return the last position of a non-whitespace character. +pub fn whitespace_len_rev(slice: &[u8]) -> usize { + WHITESPACE_ANCHORED_REV.rfind(slice).unwrap_or(slice.len()) +} diff --git a/vendor/bstr-0.2.17/src/unicode/word.rs b/vendor/bstr-0.2.17/src/unicode/word.rs new file mode 100644 index 0000000000000..e0a5701446c71 --- /dev/null +++ b/vendor/bstr-0.2.17/src/unicode/word.rs @@ -0,0 +1,406 @@ +use regex_automata::DFA; + +use crate::ext_slice::ByteSlice; +use crate::unicode::fsm::simple_word_fwd::SIMPLE_WORD_FWD; +use crate::unicode::fsm::word_break_fwd::WORD_BREAK_FWD; +use crate::utf8; + +/// An iterator over words in a byte string. +/// +/// This iterator is typically constructed by +/// [`ByteSlice::words`](trait.ByteSlice.html#method.words). +/// +/// This is similar to the [`WordsWithBreaks`](struct.WordsWithBreaks.html) +/// iterator, except it only returns elements that contain a "word" character. +/// A word character is defined by UTS #18 (Annex C) to be the combination +/// of the `Alphabetic` and `Join_Control` properties, along with the +/// `Decimal_Number`, `Mark` and `Connector_Punctuation` general categories. +/// +/// Since words are made up of one or more codepoints, this iterator yields +/// `&str` elements. When invalid UTF-8 is encountered, replacement codepoints +/// are [substituted](index.html#handling-of-invalid-utf-8). +/// +/// This iterator yields words in accordance with the default word boundary +/// rules specified in +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Word_Boundaries). +/// In particular, this may not be suitable for Japanese and Chinese scripts +/// that do not use spaces between words. +#[derive(Clone, Debug)] +pub struct Words<'a>(WordsWithBreaks<'a>); + +impl<'a> Words<'a> { + pub(crate) fn new(bs: &'a [u8]) -> Words<'a> { + Words(WordsWithBreaks::new(bs)) + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut it = b"foo bar baz".words(); + /// + /// assert_eq!(b"foo bar baz", it.as_bytes()); + /// it.next(); + /// it.next(); + /// assert_eq!(b" baz", it.as_bytes()); + /// it.next(); + /// assert_eq!(b"", it.as_bytes()); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &'a [u8] { + self.0.as_bytes() + } +} + +impl<'a> Iterator for Words<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + while let Some(word) = self.0.next() { + if SIMPLE_WORD_FWD.is_match(word.as_bytes()) { + return Some(word); + } + } + None + } +} + +/// An iterator over words in a byte string and their byte index positions. +/// +/// This iterator is typically constructed by +/// [`ByteSlice::word_indices`](trait.ByteSlice.html#method.word_indices). +/// +/// This is similar to the +/// [`WordsWithBreakIndices`](struct.WordsWithBreakIndices.html) iterator, +/// except it only returns elements that contain a "word" character. A +/// word character is defined by UTS #18 (Annex C) to be the combination +/// of the `Alphabetic` and `Join_Control` properties, along with the +/// `Decimal_Number`, `Mark` and `Connector_Punctuation` general categories. +/// +/// Since words are made up of one or more codepoints, this iterator +/// yields `&str` elements (along with their start and end byte offsets). +/// When invalid UTF-8 is encountered, replacement codepoints are +/// [substituted](index.html#handling-of-invalid-utf-8). Because of this, the +/// indices yielded by this iterator may not correspond to the length of the +/// word yielded with those indices. For example, when this iterator encounters +/// `\xFF` in the byte string, then it will yield a pair of indices ranging +/// over a single byte, but will provide an `&str` equivalent to `"\u{FFFD}"`, +/// which is three bytes in length. However, when given only valid UTF-8, then +/// all indices are in exact correspondence with their paired word. +/// +/// This iterator yields words in accordance with the default word boundary +/// rules specified in +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Word_Boundaries). +/// In particular, this may not be suitable for Japanese and Chinese scripts +/// that do not use spaces between words. +#[derive(Clone, Debug)] +pub struct WordIndices<'a>(WordsWithBreakIndices<'a>); + +impl<'a> WordIndices<'a> { + pub(crate) fn new(bs: &'a [u8]) -> WordIndices<'a> { + WordIndices(WordsWithBreakIndices::new(bs)) + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut it = b"foo bar baz".word_indices(); + /// + /// assert_eq!(b"foo bar baz", it.as_bytes()); + /// it.next(); + /// it.next(); + /// assert_eq!(b" baz", it.as_bytes()); + /// it.next(); + /// it.next(); + /// assert_eq!(b"", it.as_bytes()); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &'a [u8] { + self.0.as_bytes() + } +} + +impl<'a> Iterator for WordIndices<'a> { + type Item = (usize, usize, &'a str); + + #[inline] + fn next(&mut self) -> Option<(usize, usize, &'a str)> { + while let Some((start, end, word)) = self.0.next() { + if SIMPLE_WORD_FWD.is_match(word.as_bytes()) { + return Some((start, end, word)); + } + } + None + } +} + +/// An iterator over all word breaks in a byte string. +/// +/// This iterator is typically constructed by +/// [`ByteSlice::words_with_breaks`](trait.ByteSlice.html#method.words_with_breaks). +/// +/// This iterator yields not only all words, but the content that comes between +/// words. In particular, if all elements yielded by this iterator are +/// concatenated, then the result is the original string (subject to Unicode +/// replacement codepoint substitutions). +/// +/// Since words are made up of one or more codepoints, this iterator yields +/// `&str` elements. When invalid UTF-8 is encountered, replacement codepoints +/// are [substituted](index.html#handling-of-invalid-utf-8). +/// +/// This iterator yields words in accordance with the default word boundary +/// rules specified in +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Word_Boundaries). +/// In particular, this may not be suitable for Japanese and Chinese scripts +/// that do not use spaces between words. +#[derive(Clone, Debug)] +pub struct WordsWithBreaks<'a> { + bs: &'a [u8], +} + +impl<'a> WordsWithBreaks<'a> { + pub(crate) fn new(bs: &'a [u8]) -> WordsWithBreaks<'a> { + WordsWithBreaks { bs } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut it = b"foo bar baz".words_with_breaks(); + /// + /// assert_eq!(b"foo bar baz", it.as_bytes()); + /// it.next(); + /// assert_eq!(b" bar baz", it.as_bytes()); + /// it.next(); + /// it.next(); + /// assert_eq!(b" baz", it.as_bytes()); + /// it.next(); + /// it.next(); + /// assert_eq!(b"", it.as_bytes()); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &'a [u8] { + self.bs + } +} + +impl<'a> Iterator for WordsWithBreaks<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + let (word, size) = decode_word(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + Some(word) + } +} + +/// An iterator over all word breaks in a byte string, along with their byte +/// index positions. +/// +/// This iterator is typically constructed by +/// [`ByteSlice::words_with_break_indices`](trait.ByteSlice.html#method.words_with_break_indices). +/// +/// This iterator yields not only all words, but the content that comes between +/// words. In particular, if all elements yielded by this iterator are +/// concatenated, then the result is the original string (subject to Unicode +/// replacement codepoint substitutions). +/// +/// Since words are made up of one or more codepoints, this iterator +/// yields `&str` elements (along with their start and end byte offsets). +/// When invalid UTF-8 is encountered, replacement codepoints are +/// [substituted](index.html#handling-of-invalid-utf-8). Because of this, the +/// indices yielded by this iterator may not correspond to the length of the +/// word yielded with those indices. For example, when this iterator encounters +/// `\xFF` in the byte string, then it will yield a pair of indices ranging +/// over a single byte, but will provide an `&str` equivalent to `"\u{FFFD}"`, +/// which is three bytes in length. However, when given only valid UTF-8, then +/// all indices are in exact correspondence with their paired word. +/// +/// This iterator yields words in accordance with the default word boundary +/// rules specified in +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Word_Boundaries). +/// In particular, this may not be suitable for Japanese and Chinese scripts +/// that do not use spaces between words. +#[derive(Clone, Debug)] +pub struct WordsWithBreakIndices<'a> { + bs: &'a [u8], + forward_index: usize, +} + +impl<'a> WordsWithBreakIndices<'a> { + pub(crate) fn new(bs: &'a [u8]) -> WordsWithBreakIndices<'a> { + WordsWithBreakIndices { bs: bs, forward_index: 0 } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut it = b"foo bar baz".words_with_break_indices(); + /// + /// assert_eq!(b"foo bar baz", it.as_bytes()); + /// it.next(); + /// assert_eq!(b" bar baz", it.as_bytes()); + /// it.next(); + /// it.next(); + /// assert_eq!(b" baz", it.as_bytes()); + /// it.next(); + /// it.next(); + /// assert_eq!(b"", it.as_bytes()); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &'a [u8] { + self.bs + } +} + +impl<'a> Iterator for WordsWithBreakIndices<'a> { + type Item = (usize, usize, &'a str); + + #[inline] + fn next(&mut self) -> Option<(usize, usize, &'a str)> { + let index = self.forward_index; + let (word, size) = decode_word(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + self.forward_index += size; + Some((index, index + size, word)) + } +} + +fn decode_word(bs: &[u8]) -> (&str, usize) { + if bs.is_empty() { + ("", 0) + } else if let Some(end) = WORD_BREAK_FWD.find(bs) { + // Safe because a match can only occur for valid UTF-8. + let word = unsafe { bs[..end].to_str_unchecked() }; + (word, word.len()) + } else { + const INVALID: &'static str = "\u{FFFD}"; + // No match on non-empty bytes implies we found invalid UTF-8. + let (_, size) = utf8::decode_lossy(bs); + (INVALID, size) + } +} + +#[cfg(test)] +mod tests { + use ucd_parse::WordBreakTest; + + use crate::ext_slice::ByteSlice; + + #[test] + fn forward_ucd() { + for (i, test) in ucdtests().into_iter().enumerate() { + let given = test.words.concat(); + let got = words(given.as_bytes()); + assert_eq!( + test.words, + got, + "\n\nword forward break test {} failed:\n\ + given: {:?}\n\ + expected: {:?}\n\ + got: {:?}\n", + i, + given, + strs_to_bstrs(&test.words), + strs_to_bstrs(&got), + ); + } + } + + // Some additional tests that don't seem to be covered by the UCD tests. + // + // It's pretty amazing that the UCD tests miss these cases. I only found + // them by running this crate's segmenter and ICU's segmenter on the same + // text and comparing the output. + #[test] + fn forward_additional() { + assert_eq!(vec!["a", ".", " ", "Y"], words(b"a. Y")); + assert_eq!(vec!["r", ".", " ", "Yo"], words(b"r. Yo")); + assert_eq!( + vec!["whatsoever", ".", " ", "You", " ", "may"], + words(b"whatsoever. You may") + ); + assert_eq!( + vec!["21stcentury'syesterday"], + words(b"21stcentury'syesterday") + ); + + assert_eq!(vec!["Bonta_", "'", "s"], words(b"Bonta_'s")); + assert_eq!(vec!["_vhat's"], words(b"_vhat's")); + assert_eq!(vec!["__on'anima"], words(b"__on'anima")); + assert_eq!(vec!["123_", "'", "4"], words(b"123_'4")); + assert_eq!(vec!["_123'4"], words(b"_123'4")); + assert_eq!(vec!["__12'345"], words(b"__12'345")); + + assert_eq!( + vec!["tomorrowat4", ":", "00", ","], + words(b"tomorrowat4:00,") + ); + assert_eq!(vec!["RS1", "'", "s"], words(b"RS1's")); + assert_eq!(vec!["X38"], words(b"X38")); + + assert_eq!(vec!["4abc", ":", "00", ","], words(b"4abc:00,")); + assert_eq!(vec!["12S", "'", "1"], words(b"12S'1")); + assert_eq!(vec!["1XY"], words(b"1XY")); + + assert_eq!(vec!["\u{FEFF}", "Ты"], words("\u{FEFF}Ты".as_bytes())); + } + + fn words(bytes: &[u8]) -> Vec<&str> { + bytes.words_with_breaks().collect() + } + + fn strs_to_bstrs>(strs: &[S]) -> Vec<&[u8]> { + strs.iter().map(|s| s.as_ref().as_bytes()).collect() + } + + /// Return all of the UCD for word breaks. + fn ucdtests() -> Vec { + const TESTDATA: &'static str = include_str!("data/WordBreakTest.txt"); + + let mut tests = vec![]; + for mut line in TESTDATA.lines() { + line = line.trim(); + if line.starts_with("#") || line.contains("surrogate") { + continue; + } + tests.push(line.parse().unwrap()); + } + tests + } +} diff --git a/vendor/bstr-0.2.17/src/utf8.rs b/vendor/bstr-0.2.17/src/utf8.rs new file mode 100644 index 0000000000000..5c7de363dc630 --- /dev/null +++ b/vendor/bstr-0.2.17/src/utf8.rs @@ -0,0 +1,1370 @@ +use core::char; +use core::cmp; +use core::fmt; +use core::str; +#[cfg(feature = "std")] +use std::error; + +use crate::ascii; +use crate::bstr::BStr; +use crate::ext_slice::ByteSlice; + +// The UTF-8 decoder provided here is based on the one presented here: +// https://bjoern.hoehrmann.de/utf-8/decoder/dfa/ +// +// We *could* have done UTF-8 decoding by using a DFA generated by `\p{any}` +// using regex-automata that is roughly the same size. The real benefit of +// Hoehrmann's formulation is that the byte class mapping below is manually +// tailored such that each byte's class doubles as a shift to mask out the +// bits necessary for constructing the leading bits of each codepoint value +// from the initial byte. +// +// There are some minor differences between this implementation and Hoehrmann's +// formulation. +// +// Firstly, we make REJECT have state ID 0, since it makes the state table +// itself a little easier to read and is consistent with the notion that 0 +// means "false" or "bad." +// +// Secondly, when doing bulk decoding, we add a SIMD accelerated ASCII fast +// path. +// +// Thirdly, we pre-multiply the state IDs to avoid a multiplication instruction +// in the core decoding loop. (Which is what regex-automata would do by +// default.) +// +// Fourthly, we split the byte class mapping and transition table into two +// arrays because it's clearer. +// +// It is unlikely that this is the fastest way to do UTF-8 decoding, however, +// it is fairly simple. + +const ACCEPT: usize = 12; +const REJECT: usize = 0; + +/// SAFETY: The decode below function relies on the correctness of these +/// equivalence classes. +#[cfg_attr(rustfmt, rustfmt::skip)] +const CLASSES: [u8; 256] = [ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, +]; + +/// SAFETY: The decode below function relies on the correctness of this state +/// machine. +#[cfg_attr(rustfmt, rustfmt::skip)] +const STATES_FORWARD: &'static [u8] = &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 24, 36, 60, 96, 84, 0, 0, 0, 48, 72, + 0, 12, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, + 0, 24, 0, 0, 0, 0, 0, 24, 0, 24, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, + 0, 24, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 36, 0, 36, 0, 0, + 0, 36, 0, 0, 0, 0, 0, 36, 0, 36, 0, 0, + 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +/// An iterator over Unicode scalar values in a byte string. +/// +/// When invalid UTF-8 byte sequences are found, they are substituted with the +/// Unicode replacement codepoint (`U+FFFD`) using the +/// ["maximal subpart" strategy](http://www.unicode.org/review/pr-121.html). +/// +/// This iterator is created by the +/// [`chars`](trait.ByteSlice.html#method.chars) method provided by the +/// [`ByteSlice`](trait.ByteSlice.html) extension trait for `&[u8]`. +#[derive(Clone, Debug)] +pub struct Chars<'a> { + bs: &'a [u8], +} + +impl<'a> Chars<'a> { + pub(crate) fn new(bs: &'a [u8]) -> Chars<'a> { + Chars { bs } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut chars = b"abc".chars(); + /// + /// assert_eq!(b"abc", chars.as_bytes()); + /// chars.next(); + /// assert_eq!(b"bc", chars.as_bytes()); + /// chars.next(); + /// chars.next(); + /// assert_eq!(b"", chars.as_bytes()); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &'a [u8] { + self.bs + } +} + +impl<'a> Iterator for Chars<'a> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { + let (ch, size) = decode_lossy(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + Some(ch) + } +} + +impl<'a> DoubleEndedIterator for Chars<'a> { + #[inline] + fn next_back(&mut self) -> Option { + let (ch, size) = decode_last_lossy(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[..self.bs.len() - size]; + Some(ch) + } +} + +/// An iterator over Unicode scalar values in a byte string and their +/// byte index positions. +/// +/// When invalid UTF-8 byte sequences are found, they are substituted with the +/// Unicode replacement codepoint (`U+FFFD`) using the +/// ["maximal subpart" strategy](http://www.unicode.org/review/pr-121.html). +/// +/// Note that this is slightly different from the `CharIndices` iterator +/// provided by the standard library. Aside from working on possibly invalid +/// UTF-8, this iterator provides both the corresponding starting and ending +/// byte indices of each codepoint yielded. The ending position is necessary to +/// slice the original byte string when invalid UTF-8 bytes are converted into +/// a Unicode replacement codepoint, since a single replacement codepoint can +/// substitute anywhere from 1 to 3 invalid bytes (inclusive). +/// +/// This iterator is created by the +/// [`char_indices`](trait.ByteSlice.html#method.char_indices) method provided +/// by the [`ByteSlice`](trait.ByteSlice.html) extension trait for `&[u8]`. +#[derive(Clone, Debug)] +pub struct CharIndices<'a> { + bs: &'a [u8], + forward_index: usize, + reverse_index: usize, +} + +impl<'a> CharIndices<'a> { + pub(crate) fn new(bs: &'a [u8]) -> CharIndices<'a> { + CharIndices { bs: bs, forward_index: 0, reverse_index: bs.len() } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let mut it = b"abc".char_indices(); + /// + /// assert_eq!(b"abc", it.as_bytes()); + /// it.next(); + /// assert_eq!(b"bc", it.as_bytes()); + /// it.next(); + /// it.next(); + /// assert_eq!(b"", it.as_bytes()); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &'a [u8] { + self.bs + } +} + +impl<'a> Iterator for CharIndices<'a> { + type Item = (usize, usize, char); + + #[inline] + fn next(&mut self) -> Option<(usize, usize, char)> { + let index = self.forward_index; + let (ch, size) = decode_lossy(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + self.forward_index += size; + Some((index, index + size, ch)) + } +} + +impl<'a> DoubleEndedIterator for CharIndices<'a> { + #[inline] + fn next_back(&mut self) -> Option<(usize, usize, char)> { + let (ch, size) = decode_last_lossy(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[..self.bs.len() - size]; + self.reverse_index -= size; + Some((self.reverse_index, self.reverse_index + size, ch)) + } +} + +impl<'a> ::core::iter::FusedIterator for CharIndices<'a> {} + +/// An iterator over chunks of valid UTF-8 in a byte slice. +/// +/// See [`utf8_chunks`](trait.ByteSlice.html#method.utf8_chunks). +#[derive(Clone, Debug)] +pub struct Utf8Chunks<'a> { + pub(super) bytes: &'a [u8], +} + +/// A chunk of valid UTF-8, possibly followed by invalid UTF-8 bytes. +/// +/// This is yielded by the +/// [`Utf8Chunks`](struct.Utf8Chunks.html) +/// iterator, which can be created via the +/// [`ByteSlice::utf8_chunks`](trait.ByteSlice.html#method.utf8_chunks) +/// method. +/// +/// The `'a` lifetime parameter corresponds to the lifetime of the bytes that +/// are being iterated over. +#[cfg_attr(test, derive(Debug, PartialEq))] +pub struct Utf8Chunk<'a> { + /// A valid UTF-8 piece, at the start, end, or between invalid UTF-8 bytes. + /// + /// This is empty between adjacent invalid UTF-8 byte sequences. + valid: &'a str, + /// A sequence of invalid UTF-8 bytes. + /// + /// Can only be empty in the last chunk. + /// + /// Should be replaced by a single unicode replacement character, if not + /// empty. + invalid: &'a BStr, + /// Indicates whether the invalid sequence could've been valid if there + /// were more bytes. + /// + /// Can only be true in the last chunk. + incomplete: bool, +} + +impl<'a> Utf8Chunk<'a> { + /// Returns the (possibly empty) valid UTF-8 bytes in this chunk. + /// + /// This may be empty if there are consecutive sequences of invalid UTF-8 + /// bytes. + #[inline] + pub fn valid(&self) -> &'a str { + self.valid + } + + /// Returns the (possibly empty) invalid UTF-8 bytes in this chunk that + /// immediately follow the valid UTF-8 bytes in this chunk. + /// + /// This is only empty when this chunk corresponds to the last chunk in + /// the original bytes. + /// + /// The maximum length of this slice is 3. That is, invalid UTF-8 byte + /// sequences greater than 1 always correspond to a valid _prefix_ of + /// a valid UTF-8 encoded codepoint. This corresponds to the "substitution + /// of maximal subparts" strategy that is described in more detail in the + /// docs for the + /// [`ByteSlice::to_str_lossy`](trait.ByteSlice.html#method.to_str_lossy) + /// method. + #[inline] + pub fn invalid(&self) -> &'a [u8] { + self.invalid.as_bytes() + } + + /// Returns whether the invalid sequence might still become valid if more + /// bytes are added. + /// + /// Returns true if the end of the input was reached unexpectedly, + /// without encountering an unexpected byte. + /// + /// This can only be the case for the last chunk. + #[inline] + pub fn incomplete(&self) -> bool { + self.incomplete + } +} + +impl<'a> Iterator for Utf8Chunks<'a> { + type Item = Utf8Chunk<'a>; + + #[inline] + fn next(&mut self) -> Option> { + if self.bytes.is_empty() { + return None; + } + match validate(self.bytes) { + Ok(()) => { + let valid = self.bytes; + self.bytes = &[]; + Some(Utf8Chunk { + // SAFETY: This is safe because of the guarantees provided + // by utf8::validate. + valid: unsafe { str::from_utf8_unchecked(valid) }, + invalid: [].as_bstr(), + incomplete: false, + }) + } + Err(e) => { + let (valid, rest) = self.bytes.split_at(e.valid_up_to()); + // SAFETY: This is safe because of the guarantees provided by + // utf8::validate. + let valid = unsafe { str::from_utf8_unchecked(valid) }; + let (invalid_len, incomplete) = match e.error_len() { + Some(n) => (n, false), + None => (rest.len(), true), + }; + let (invalid, rest) = rest.split_at(invalid_len); + self.bytes = rest; + Some(Utf8Chunk { + valid, + invalid: invalid.as_bstr(), + incomplete, + }) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.bytes.is_empty() { + (0, Some(0)) + } else { + (1, Some(self.bytes.len())) + } + } +} + +impl<'a> ::core::iter::FusedIterator for Utf8Chunks<'a> {} + +/// An error that occurs when UTF-8 decoding fails. +/// +/// This error occurs when attempting to convert a non-UTF-8 byte +/// string to a Rust string that must be valid UTF-8. For example, +/// [`to_str`](trait.ByteSlice.html#method.to_str) is one such method. +/// +/// # Example +/// +/// This example shows what happens when a given byte sequence is invalid, +/// but ends with a sequence that is a possible prefix of valid UTF-8. +/// +/// ``` +/// use bstr::{B, ByteSlice}; +/// +/// let s = B(b"foobar\xF1\x80\x80"); +/// let err = s.to_str().unwrap_err(); +/// assert_eq!(err.valid_up_to(), 6); +/// assert_eq!(err.error_len(), None); +/// ``` +/// +/// This example shows what happens when a given byte sequence contains +/// invalid UTF-8. +/// +/// ``` +/// use bstr::ByteSlice; +/// +/// let s = b"foobar\xF1\x80\x80quux"; +/// let err = s.to_str().unwrap_err(); +/// assert_eq!(err.valid_up_to(), 6); +/// // The error length reports the maximum number of bytes that correspond to +/// // a valid prefix of a UTF-8 encoded codepoint. +/// assert_eq!(err.error_len(), Some(3)); +/// +/// // In contrast to the above which contains a single invalid prefix, +/// // consider the case of multiple individal bytes that are never valid +/// // prefixes. Note how the value of error_len changes! +/// let s = b"foobar\xFF\xFFquux"; +/// let err = s.to_str().unwrap_err(); +/// assert_eq!(err.valid_up_to(), 6); +/// assert_eq!(err.error_len(), Some(1)); +/// +/// // The fact that it's an invalid prefix does not change error_len even +/// // when it immediately precedes the end of the string. +/// let s = b"foobar\xFF"; +/// let err = s.to_str().unwrap_err(); +/// assert_eq!(err.valid_up_to(), 6); +/// assert_eq!(err.error_len(), Some(1)); +/// ``` +#[derive(Debug, Eq, PartialEq)] +pub struct Utf8Error { + valid_up_to: usize, + error_len: Option, +} + +impl Utf8Error { + /// Returns the byte index of the position immediately following the last + /// valid UTF-8 byte. + /// + /// # Example + /// + /// This examples shows how `valid_up_to` can be used to retrieve a + /// possibly empty prefix that is guaranteed to be valid UTF-8: + /// + /// ``` + /// use bstr::ByteSlice; + /// + /// let s = b"foobar\xF1\x80\x80quux"; + /// let err = s.to_str().unwrap_err(); + /// + /// // This is guaranteed to never panic. + /// let string = s[..err.valid_up_to()].to_str().unwrap(); + /// assert_eq!(string, "foobar"); + /// ``` + #[inline] + pub fn valid_up_to(&self) -> usize { + self.valid_up_to + } + + /// Returns the total number of invalid UTF-8 bytes immediately following + /// the position returned by `valid_up_to`. This value is always at least + /// `1`, but can be up to `3` if bytes form a valid prefix of some UTF-8 + /// encoded codepoint. + /// + /// If the end of the original input was found before a valid UTF-8 encoded + /// codepoint could be completed, then this returns `None`. This is useful + /// when processing streams, where a `None` value signals that more input + /// might be needed. + #[inline] + pub fn error_len(&self) -> Option { + self.error_len + } +} + +#[cfg(feature = "std")] +impl error::Error for Utf8Error { + fn description(&self) -> &str { + "invalid UTF-8" + } +} + +impl fmt::Display for Utf8Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "invalid UTF-8 found at byte offset {}", self.valid_up_to) + } +} + +/// Returns OK if and only if the given slice is completely valid UTF-8. +/// +/// If the slice isn't valid UTF-8, then an error is returned that explains +/// the first location at which invalid UTF-8 was detected. +pub fn validate(slice: &[u8]) -> Result<(), Utf8Error> { + // The fast path for validating UTF-8. It steps through a UTF-8 automaton + // and uses a SIMD accelerated ASCII fast path on x86_64. If an error is + // detected, it backs up and runs the slower version of the UTF-8 automaton + // to determine correct error information. + fn fast(slice: &[u8]) -> Result<(), Utf8Error> { + let mut state = ACCEPT; + let mut i = 0; + + while i < slice.len() { + let b = slice[i]; + + // ASCII fast path. If we see two consecutive ASCII bytes, then try + // to validate as much ASCII as possible very quickly. + if state == ACCEPT + && b <= 0x7F + && slice.get(i + 1).map_or(false, |&b| b <= 0x7F) + { + i += ascii::first_non_ascii_byte(&slice[i..]); + continue; + } + + state = step(state, b); + if state == REJECT { + return Err(find_valid_up_to(slice, i)); + } + i += 1; + } + if state != ACCEPT { + Err(find_valid_up_to(slice, slice.len())) + } else { + Ok(()) + } + } + + // Given the first position at which a UTF-8 sequence was determined to be + // invalid, return an error that correctly reports the position at which + // the last complete UTF-8 sequence ends. + #[inline(never)] + fn find_valid_up_to(slice: &[u8], rejected_at: usize) -> Utf8Error { + // In order to find the last valid byte, we need to back up an amount + // that guarantees every preceding byte is part of a valid UTF-8 + // code unit sequence. To do this, we simply locate the last leading + // byte that occurs before rejected_at. + let mut backup = rejected_at.saturating_sub(1); + while backup > 0 && !is_leading_or_invalid_utf8_byte(slice[backup]) { + backup -= 1; + } + let upto = cmp::min(slice.len(), rejected_at.saturating_add(1)); + let mut err = slow(&slice[backup..upto]).unwrap_err(); + err.valid_up_to += backup; + err + } + + // Like top-level UTF-8 decoding, except it correctly reports a UTF-8 error + // when an invalid sequence is found. This is split out from validate so + // that the fast path doesn't need to keep track of the position of the + // last valid UTF-8 byte. In particular, tracking this requires checking + // for an ACCEPT state on each byte, which degrades throughput pretty + // badly. + fn slow(slice: &[u8]) -> Result<(), Utf8Error> { + let mut state = ACCEPT; + let mut valid_up_to = 0; + for (i, &b) in slice.iter().enumerate() { + state = step(state, b); + if state == ACCEPT { + valid_up_to = i + 1; + } else if state == REJECT { + // Our error length must always be at least 1. + let error_len = Some(cmp::max(1, i - valid_up_to)); + return Err(Utf8Error { valid_up_to, error_len }); + } + } + if state != ACCEPT { + Err(Utf8Error { valid_up_to, error_len: None }) + } else { + Ok(()) + } + } + + // Advance to the next state given the current state and current byte. + fn step(state: usize, b: u8) -> usize { + let class = CLASSES[b as usize]; + // SAFETY: This is safe because 'class' is always <=11 and 'state' is + // always <=96. Therefore, the maximal index is 96+11 = 107, where + // STATES_FORWARD.len() = 108 such that every index is guaranteed to be + // valid by construction of the state machine and the byte equivalence + // classes. + unsafe { + *STATES_FORWARD.get_unchecked(state + class as usize) as usize + } + } + + fast(slice) +} + +/// UTF-8 decode a single Unicode scalar value from the beginning of a slice. +/// +/// When successful, the corresponding Unicode scalar value is returned along +/// with the number of bytes it was encoded with. The number of bytes consumed +/// for a successful decode is always between 1 and 4, inclusive. +/// +/// When unsuccessful, `None` is returned along with the number of bytes that +/// make up a maximal prefix of a valid UTF-8 code unit sequence. In this case, +/// the number of bytes consumed is always between 0 and 3, inclusive, where +/// 0 is only returned when `slice` is empty. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bstr::decode_utf8; +/// +/// // Decoding a valid codepoint. +/// let (ch, size) = decode_utf8(b"\xE2\x98\x83"); +/// assert_eq!(Some('☃'), ch); +/// assert_eq!(3, size); +/// +/// // Decoding an incomplete codepoint. +/// let (ch, size) = decode_utf8(b"\xE2\x98"); +/// assert_eq!(None, ch); +/// assert_eq!(2, size); +/// ``` +/// +/// This example shows how to iterate over all codepoints in UTF-8 encoded +/// bytes, while replacing invalid UTF-8 sequences with the replacement +/// codepoint: +/// +/// ``` +/// use bstr::{B, decode_utf8}; +/// +/// let mut bytes = B(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"); +/// let mut chars = vec![]; +/// while !bytes.is_empty() { +/// let (ch, size) = decode_utf8(bytes); +/// bytes = &bytes[size..]; +/// chars.push(ch.unwrap_or('\u{FFFD}')); +/// } +/// assert_eq!(vec!['☃', '\u{FFFD}', 'ðžƒ', '\u{FFFD}', 'a'], chars); +/// ``` +#[inline] +pub fn decode>(slice: B) -> (Option, usize) { + let slice = slice.as_ref(); + match slice.get(0) { + None => return (None, 0), + Some(&b) if b <= 0x7F => return (Some(b as char), 1), + _ => {} + } + + let (mut state, mut cp, mut i) = (ACCEPT, 0, 0); + while i < slice.len() { + decode_step(&mut state, &mut cp, slice[i]); + i += 1; + + if state == ACCEPT { + // SAFETY: This is safe because `decode_step` guarantees that + // `cp` is a valid Unicode scalar value in an ACCEPT state. + let ch = unsafe { char::from_u32_unchecked(cp) }; + return (Some(ch), i); + } else if state == REJECT { + // At this point, we always want to advance at least one byte. + return (None, cmp::max(1, i.saturating_sub(1))); + } + } + (None, i) +} + +/// Lossily UTF-8 decode a single Unicode scalar value from the beginning of a +/// slice. +/// +/// When successful, the corresponding Unicode scalar value is returned along +/// with the number of bytes it was encoded with. The number of bytes consumed +/// for a successful decode is always between 1 and 4, inclusive. +/// +/// When unsuccessful, the Unicode replacement codepoint (`U+FFFD`) is returned +/// along with the number of bytes that make up a maximal prefix of a valid +/// UTF-8 code unit sequence. In this case, the number of bytes consumed is +/// always between 0 and 3, inclusive, where 0 is only returned when `slice` is +/// empty. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ```ignore +/// use bstr::decode_utf8_lossy; +/// +/// // Decoding a valid codepoint. +/// let (ch, size) = decode_utf8_lossy(b"\xE2\x98\x83"); +/// assert_eq!('☃', ch); +/// assert_eq!(3, size); +/// +/// // Decoding an incomplete codepoint. +/// let (ch, size) = decode_utf8_lossy(b"\xE2\x98"); +/// assert_eq!('\u{FFFD}', ch); +/// assert_eq!(2, size); +/// ``` +/// +/// This example shows how to iterate over all codepoints in UTF-8 encoded +/// bytes, while replacing invalid UTF-8 sequences with the replacement +/// codepoint: +/// +/// ```ignore +/// use bstr::{B, decode_utf8_lossy}; +/// +/// let mut bytes = B(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"); +/// let mut chars = vec![]; +/// while !bytes.is_empty() { +/// let (ch, size) = decode_utf8_lossy(bytes); +/// bytes = &bytes[size..]; +/// chars.push(ch); +/// } +/// assert_eq!(vec!['☃', '\u{FFFD}', 'ðžƒ', '\u{FFFD}', 'a'], chars); +/// ``` +#[inline] +pub fn decode_lossy>(slice: B) -> (char, usize) { + match decode(slice) { + (Some(ch), size) => (ch, size), + (None, size) => ('\u{FFFD}', size), + } +} + +/// UTF-8 decode a single Unicode scalar value from the end of a slice. +/// +/// When successful, the corresponding Unicode scalar value is returned along +/// with the number of bytes it was encoded with. The number of bytes consumed +/// for a successful decode is always between 1 and 4, inclusive. +/// +/// When unsuccessful, `None` is returned along with the number of bytes that +/// make up a maximal prefix of a valid UTF-8 code unit sequence. In this case, +/// the number of bytes consumed is always between 0 and 3, inclusive, where +/// 0 is only returned when `slice` is empty. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bstr::decode_last_utf8; +/// +/// // Decoding a valid codepoint. +/// let (ch, size) = decode_last_utf8(b"\xE2\x98\x83"); +/// assert_eq!(Some('☃'), ch); +/// assert_eq!(3, size); +/// +/// // Decoding an incomplete codepoint. +/// let (ch, size) = decode_last_utf8(b"\xE2\x98"); +/// assert_eq!(None, ch); +/// assert_eq!(2, size); +/// ``` +/// +/// This example shows how to iterate over all codepoints in UTF-8 encoded +/// bytes in reverse, while replacing invalid UTF-8 sequences with the +/// replacement codepoint: +/// +/// ``` +/// use bstr::{B, decode_last_utf8}; +/// +/// let mut bytes = B(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"); +/// let mut chars = vec![]; +/// while !bytes.is_empty() { +/// let (ch, size) = decode_last_utf8(bytes); +/// bytes = &bytes[..bytes.len()-size]; +/// chars.push(ch.unwrap_or('\u{FFFD}')); +/// } +/// assert_eq!(vec!['a', '\u{FFFD}', 'ðžƒ', '\u{FFFD}', '☃'], chars); +/// ``` +#[inline] +pub fn decode_last>(slice: B) -> (Option, usize) { + // TODO: We could implement this by reversing the UTF-8 automaton, but for + // now, we do it the slow way by using the forward automaton. + + let slice = slice.as_ref(); + if slice.is_empty() { + return (None, 0); + } + let mut start = slice.len() - 1; + let limit = slice.len().saturating_sub(4); + while start > limit && !is_leading_or_invalid_utf8_byte(slice[start]) { + start -= 1; + } + let (ch, size) = decode(&slice[start..]); + // If we didn't consume all of the bytes, then that means there's at least + // one stray byte that never occurs in a valid code unit prefix, so we can + // advance by one byte. + if start + size != slice.len() { + (None, 1) + } else { + (ch, size) + } +} + +/// Lossily UTF-8 decode a single Unicode scalar value from the end of a slice. +/// +/// When successful, the corresponding Unicode scalar value is returned along +/// with the number of bytes it was encoded with. The number of bytes consumed +/// for a successful decode is always between 1 and 4, inclusive. +/// +/// When unsuccessful, the Unicode replacement codepoint (`U+FFFD`) is returned +/// along with the number of bytes that make up a maximal prefix of a valid +/// UTF-8 code unit sequence. In this case, the number of bytes consumed is +/// always between 0 and 3, inclusive, where 0 is only returned when `slice` is +/// empty. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ```ignore +/// use bstr::decode_last_utf8_lossy; +/// +/// // Decoding a valid codepoint. +/// let (ch, size) = decode_last_utf8_lossy(b"\xE2\x98\x83"); +/// assert_eq!('☃', ch); +/// assert_eq!(3, size); +/// +/// // Decoding an incomplete codepoint. +/// let (ch, size) = decode_last_utf8_lossy(b"\xE2\x98"); +/// assert_eq!('\u{FFFD}', ch); +/// assert_eq!(2, size); +/// ``` +/// +/// This example shows how to iterate over all codepoints in UTF-8 encoded +/// bytes in reverse, while replacing invalid UTF-8 sequences with the +/// replacement codepoint: +/// +/// ```ignore +/// use bstr::decode_last_utf8_lossy; +/// +/// let mut bytes = B(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"); +/// let mut chars = vec![]; +/// while !bytes.is_empty() { +/// let (ch, size) = decode_last_utf8_lossy(bytes); +/// bytes = &bytes[..bytes.len()-size]; +/// chars.push(ch); +/// } +/// assert_eq!(vec!['a', '\u{FFFD}', 'ðžƒ', '\u{FFFD}', '☃'], chars); +/// ``` +#[inline] +pub fn decode_last_lossy>(slice: B) -> (char, usize) { + match decode_last(slice) { + (Some(ch), size) => (ch, size), + (None, size) => ('\u{FFFD}', size), + } +} + +/// SAFETY: The decode function relies on state being equal to ACCEPT only if +/// cp is a valid Unicode scalar value. +#[inline] +pub fn decode_step(state: &mut usize, cp: &mut u32, b: u8) { + let class = CLASSES[b as usize]; + if *state == ACCEPT { + *cp = (0xFF >> class) & (b as u32); + } else { + *cp = (b as u32 & 0b111111) | (*cp << 6); + } + *state = STATES_FORWARD[*state + class as usize] as usize; +} + +/// Returns true if and only if the given byte is either a valid leading UTF-8 +/// byte, or is otherwise an invalid byte that can never appear anywhere in a +/// valid UTF-8 sequence. +fn is_leading_or_invalid_utf8_byte(b: u8) -> bool { + // In the ASCII case, the most significant bit is never set. The leading + // byte of a 2/3/4-byte sequence always has the top two most significant + // bits set. For bytes that can never appear anywhere in valid UTF-8, this + // also returns true, since every such byte has its two most significant + // bits set: + // + // \xC0 :: 11000000 + // \xC1 :: 11000001 + // \xF5 :: 11110101 + // \xF6 :: 11110110 + // \xF7 :: 11110111 + // \xF8 :: 11111000 + // \xF9 :: 11111001 + // \xFA :: 11111010 + // \xFB :: 11111011 + // \xFC :: 11111100 + // \xFD :: 11111101 + // \xFE :: 11111110 + // \xFF :: 11111111 + (b & 0b1100_0000) != 0b1000_0000 +} + +#[cfg(test)] +mod tests { + use std::char; + + use crate::ext_slice::{ByteSlice, B}; + use crate::tests::LOSSY_TESTS; + use crate::utf8::{self, Utf8Error}; + + fn utf8e(valid_up_to: usize) -> Utf8Error { + Utf8Error { valid_up_to, error_len: None } + } + + fn utf8e2(valid_up_to: usize, error_len: usize) -> Utf8Error { + Utf8Error { valid_up_to, error_len: Some(error_len) } + } + + #[test] + fn validate_all_codepoints() { + for i in 0..(0x10FFFF + 1) { + let cp = match char::from_u32(i) { + None => continue, + Some(cp) => cp, + }; + let mut buf = [0; 4]; + let s = cp.encode_utf8(&mut buf); + assert_eq!(Ok(()), utf8::validate(s.as_bytes())); + } + } + + #[test] + fn validate_multiple_codepoints() { + assert_eq!(Ok(()), utf8::validate(b"abc")); + assert_eq!(Ok(()), utf8::validate(b"a\xE2\x98\x83a")); + assert_eq!(Ok(()), utf8::validate(b"a\xF0\x9D\x9C\xB7a")); + assert_eq!(Ok(()), utf8::validate(b"\xE2\x98\x83\xF0\x9D\x9C\xB7",)); + assert_eq!( + Ok(()), + utf8::validate(b"a\xE2\x98\x83a\xF0\x9D\x9C\xB7a",) + ); + assert_eq!( + Ok(()), + utf8::validate(b"\xEF\xBF\xBD\xE2\x98\x83\xEF\xBF\xBD",) + ); + } + + #[test] + fn validate_errors() { + // single invalid byte + assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xFF")); + // single invalid byte after ASCII + assert_eq!(Err(utf8e2(1, 1)), utf8::validate(b"a\xFF")); + // single invalid byte after 2 byte sequence + assert_eq!(Err(utf8e2(2, 1)), utf8::validate(b"\xCE\xB2\xFF")); + // single invalid byte after 3 byte sequence + assert_eq!(Err(utf8e2(3, 1)), utf8::validate(b"\xE2\x98\x83\xFF")); + // single invalid byte after 4 byte sequence + assert_eq!(Err(utf8e2(4, 1)), utf8::validate(b"\xF0\x9D\x9D\xB1\xFF")); + + // An invalid 2-byte sequence with a valid 1-byte prefix. + assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xCE\xF0")); + // An invalid 3-byte sequence with a valid 2-byte prefix. + assert_eq!(Err(utf8e2(0, 2)), utf8::validate(b"\xE2\x98\xF0")); + // An invalid 4-byte sequence with a valid 3-byte prefix. + assert_eq!(Err(utf8e2(0, 3)), utf8::validate(b"\xF0\x9D\x9D\xF0")); + + // An overlong sequence. Should be \xE2\x82\xAC, but we encode the + // same codepoint value in 4 bytes. This not only tests that we reject + // overlong sequences, but that we get valid_up_to correct. + assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xF0\x82\x82\xAC")); + assert_eq!(Err(utf8e2(1, 1)), utf8::validate(b"a\xF0\x82\x82\xAC")); + assert_eq!( + Err(utf8e2(3, 1)), + utf8::validate(b"\xE2\x98\x83\xF0\x82\x82\xAC",) + ); + + // Check that encoding a surrogate codepoint using the UTF-8 scheme + // fails validation. + assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xED\xA0\x80")); + assert_eq!(Err(utf8e2(1, 1)), utf8::validate(b"a\xED\xA0\x80")); + assert_eq!( + Err(utf8e2(3, 1)), + utf8::validate(b"\xE2\x98\x83\xED\xA0\x80",) + ); + + // Check that an incomplete 2-byte sequence fails. + assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xCEa")); + assert_eq!(Err(utf8e2(1, 1)), utf8::validate(b"a\xCEa")); + assert_eq!( + Err(utf8e2(3, 1)), + utf8::validate(b"\xE2\x98\x83\xCE\xE2\x98\x83",) + ); + // Check that an incomplete 3-byte sequence fails. + assert_eq!(Err(utf8e2(0, 2)), utf8::validate(b"\xE2\x98a")); + assert_eq!(Err(utf8e2(1, 2)), utf8::validate(b"a\xE2\x98a")); + assert_eq!( + Err(utf8e2(3, 2)), + utf8::validate(b"\xE2\x98\x83\xE2\x98\xE2\x98\x83",) + ); + // Check that an incomplete 4-byte sequence fails. + assert_eq!(Err(utf8e2(0, 3)), utf8::validate(b"\xF0\x9D\x9Ca")); + assert_eq!(Err(utf8e2(1, 3)), utf8::validate(b"a\xF0\x9D\x9Ca")); + assert_eq!( + Err(utf8e2(4, 3)), + utf8::validate(b"\xF0\x9D\x9C\xB1\xF0\x9D\x9C\xE2\x98\x83",) + ); + assert_eq!( + Err(utf8e2(6, 3)), + utf8::validate(b"foobar\xF1\x80\x80quux",) + ); + + // Check that an incomplete (EOF) 2-byte sequence fails. + assert_eq!(Err(utf8e(0)), utf8::validate(b"\xCE")); + assert_eq!(Err(utf8e(1)), utf8::validate(b"a\xCE")); + assert_eq!(Err(utf8e(3)), utf8::validate(b"\xE2\x98\x83\xCE")); + // Check that an incomplete (EOF) 3-byte sequence fails. + assert_eq!(Err(utf8e(0)), utf8::validate(b"\xE2\x98")); + assert_eq!(Err(utf8e(1)), utf8::validate(b"a\xE2\x98")); + assert_eq!(Err(utf8e(3)), utf8::validate(b"\xE2\x98\x83\xE2\x98")); + // Check that an incomplete (EOF) 4-byte sequence fails. + assert_eq!(Err(utf8e(0)), utf8::validate(b"\xF0\x9D\x9C")); + assert_eq!(Err(utf8e(1)), utf8::validate(b"a\xF0\x9D\x9C")); + assert_eq!( + Err(utf8e(4)), + utf8::validate(b"\xF0\x9D\x9C\xB1\xF0\x9D\x9C",) + ); + + // Test that we errors correct even after long valid sequences. This + // checks that our "backup" logic for detecting errors is correct. + assert_eq!( + Err(utf8e2(8, 1)), + utf8::validate(b"\xe2\x98\x83\xce\xb2\xe3\x83\x84\xFF",) + ); + } + + #[test] + fn decode_valid() { + fn d(mut s: &str) -> Vec { + let mut chars = vec![]; + while !s.is_empty() { + let (ch, size) = utf8::decode(s.as_bytes()); + s = &s[size..]; + chars.push(ch.unwrap()); + } + chars + } + + assert_eq!(vec!['☃'], d("☃")); + assert_eq!(vec!['☃', '☃'], d("☃☃")); + assert_eq!(vec!['α', 'β', 'γ', 'δ', 'ε'], d("αβγδε")); + assert_eq!(vec!['☃', '⛄', '⛇'], d("☃⛄⛇")); + assert_eq!(vec!['ð—®', 'ð—¯', 'ð—°', 'ð—±', 'ð—²'], d("ð—®ð—¯ð—°ð—±ð—²")); + } + + #[test] + fn decode_invalid() { + let (ch, size) = utf8::decode(b""); + assert_eq!(None, ch); + assert_eq!(0, size); + + let (ch, size) = utf8::decode(b"\xFF"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode(b"\xCE\xF0"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode(b"\xE2\x98\xF0"); + assert_eq!(None, ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode(b"\xF0\x9D\x9D"); + assert_eq!(None, ch); + assert_eq!(3, size); + + let (ch, size) = utf8::decode(b"\xF0\x9D\x9D\xF0"); + assert_eq!(None, ch); + assert_eq!(3, size); + + let (ch, size) = utf8::decode(b"\xF0\x82\x82\xAC"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode(b"\xED\xA0\x80"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode(b"\xCEa"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode(b"\xE2\x98a"); + assert_eq!(None, ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode(b"\xF0\x9D\x9Ca"); + assert_eq!(None, ch); + assert_eq!(3, size); + } + + #[test] + fn decode_lossy() { + let (ch, size) = utf8::decode_lossy(b""); + assert_eq!('\u{FFFD}', ch); + assert_eq!(0, size); + + let (ch, size) = utf8::decode_lossy(b"\xFF"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_lossy(b"\xCE\xF0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_lossy(b"\xE2\x98\xF0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode_lossy(b"\xF0\x9D\x9D\xF0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(3, size); + + let (ch, size) = utf8::decode_lossy(b"\xF0\x82\x82\xAC"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_lossy(b"\xED\xA0\x80"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_lossy(b"\xCEa"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_lossy(b"\xE2\x98a"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode_lossy(b"\xF0\x9D\x9Ca"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(3, size); + } + + #[test] + fn decode_last_valid() { + fn d(mut s: &str) -> Vec { + let mut chars = vec![]; + while !s.is_empty() { + let (ch, size) = utf8::decode_last(s.as_bytes()); + s = &s[..s.len() - size]; + chars.push(ch.unwrap()); + } + chars + } + + assert_eq!(vec!['☃'], d("☃")); + assert_eq!(vec!['☃', '☃'], d("☃☃")); + assert_eq!(vec!['ε', 'δ', 'γ', 'β', 'α'], d("αβγδε")); + assert_eq!(vec!['⛇', '⛄', '☃'], d("☃⛄⛇")); + assert_eq!(vec!['ð—²', 'ð—±', 'ð—°', 'ð—¯', 'ð—®'], d("ð—®ð—¯ð—°ð—±ð—²")); + } + + #[test] + fn decode_last_invalid() { + let (ch, size) = utf8::decode_last(b""); + assert_eq!(None, ch); + assert_eq!(0, size); + + let (ch, size) = utf8::decode_last(b"\xFF"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xCE\xF0"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xCE"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xE2\x98\xF0"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xE2\x98"); + assert_eq!(None, ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode_last(b"\xF0\x9D\x9D\xF0"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xF0\x9D\x9D"); + assert_eq!(None, ch); + assert_eq!(3, size); + + let (ch, size) = utf8::decode_last(b"\xF0\x82\x82\xAC"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xED\xA0\x80"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xED\xA0"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xED"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"a\xCE"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"a\xE2\x98"); + assert_eq!(None, ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode_last(b"a\xF0\x9D\x9C"); + assert_eq!(None, ch); + assert_eq!(3, size); + } + + #[test] + fn decode_last_lossy() { + let (ch, size) = utf8::decode_last_lossy(b""); + assert_eq!('\u{FFFD}', ch); + assert_eq!(0, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xFF"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xCE\xF0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xCE"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xE2\x98\xF0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xE2\x98"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xF0\x9D\x9D\xF0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xF0\x9D\x9D"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(3, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xF0\x82\x82\xAC"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xED\xA0\x80"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xED\xA0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xED"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"a\xCE"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"a\xE2\x98"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode_last_lossy(b"a\xF0\x9D\x9C"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(3, size); + } + + #[test] + fn chars() { + for (i, &(expected, input)) in LOSSY_TESTS.iter().enumerate() { + let got: String = B(input).chars().collect(); + assert_eq!( + expected, got, + "chars(ith: {:?}, given: {:?})", + i, input, + ); + let got: String = + B(input).char_indices().map(|(_, _, ch)| ch).collect(); + assert_eq!( + expected, got, + "char_indices(ith: {:?}, given: {:?})", + i, input, + ); + + let expected: String = expected.chars().rev().collect(); + + let got: String = B(input).chars().rev().collect(); + assert_eq!( + expected, got, + "chars.rev(ith: {:?}, given: {:?})", + i, input, + ); + let got: String = + B(input).char_indices().rev().map(|(_, _, ch)| ch).collect(); + assert_eq!( + expected, got, + "char_indices.rev(ith: {:?}, given: {:?})", + i, input, + ); + } + } + + #[test] + fn utf8_chunks() { + let mut c = utf8::Utf8Chunks { bytes: b"123\xC0" }; + assert_eq!( + (c.next(), c.next()), + ( + Some(utf8::Utf8Chunk { + valid: "123", + invalid: b"\xC0".as_bstr(), + incomplete: false, + }), + None, + ) + ); + + let mut c = utf8::Utf8Chunks { bytes: b"123\xFF\xFF" }; + assert_eq!( + (c.next(), c.next(), c.next()), + ( + Some(utf8::Utf8Chunk { + valid: "123", + invalid: b"\xFF".as_bstr(), + incomplete: false, + }), + Some(utf8::Utf8Chunk { + valid: "", + invalid: b"\xFF".as_bstr(), + incomplete: false, + }), + None, + ) + ); + + let mut c = utf8::Utf8Chunks { bytes: b"123\xD0" }; + assert_eq!( + (c.next(), c.next()), + ( + Some(utf8::Utf8Chunk { + valid: "123", + invalid: b"\xD0".as_bstr(), + incomplete: true, + }), + None, + ) + ); + + let mut c = utf8::Utf8Chunks { bytes: b"123\xD0456" }; + assert_eq!( + (c.next(), c.next(), c.next()), + ( + Some(utf8::Utf8Chunk { + valid: "123", + invalid: b"\xD0".as_bstr(), + incomplete: false, + }), + Some(utf8::Utf8Chunk { + valid: "456", + invalid: b"".as_bstr(), + incomplete: false, + }), + None, + ) + ); + + let mut c = utf8::Utf8Chunks { bytes: b"123\xE2\x98" }; + assert_eq!( + (c.next(), c.next()), + ( + Some(utf8::Utf8Chunk { + valid: "123", + invalid: b"\xE2\x98".as_bstr(), + incomplete: true, + }), + None, + ) + ); + + let mut c = utf8::Utf8Chunks { bytes: b"123\xF4\x8F\xBF" }; + assert_eq!( + (c.next(), c.next()), + ( + Some(utf8::Utf8Chunk { + valid: "123", + invalid: b"\xF4\x8F\xBF".as_bstr(), + incomplete: true, + }), + None, + ) + ); + } +} diff --git a/vendor/cached/.cargo-checksum.json b/vendor/cached/.cargo-checksum.json new file mode 100644 index 0000000000000..4499f6e9f8218 --- /dev/null +++ b/vendor/cached/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"e6fc97d9fb35d6d59f3c3872c31a91c9ceff67610bb86115e04a83a1f4659492","CONTRIBUTING.md":"a2585a7e002afc1b2ea853b6d7167c8d20a8f7b56ea0029d76ddd71498c1b085","COPYRIGHT":"8cef07d222d9332eabdb748e2284945320c5f9cb320acbe8a3b31fb3161ed2bd","Cargo.lock":"d23016c031757344403075c36dc334cc2c691c608d93bd7574bd9e005f8d211e","Cargo.toml":"a67da427ec256505d314eab97610d110259612c1f40116116d7e5ed2ef8c7383","LICENSE":"8e65cf73127700ffe243f50963547dd6c297190945033677e29eecdde69d666f","Makefile":"0363a3e724c629e8c4c3f217f01b5142d4bc335955a38872cc17ee81b8578f09","README.md":"3531fe65ff3653673acb15938840ac13556d2555cfe36dca751546d2fa3ed778","bin/readme.rs":"f9571edab43e0b38d36e017db782648e7bd45663a8a708c47995d6b09cbaf909","examples/async_std.rs":"9366f26a8b887efa6160f1c93c7a8d1b84a5f7cd6f8dd5ea8f3b4cabd05404b5","examples/basic.rs":"5d4e7c8a50d23097c8c41f3b155578eab83574ac07ac7ba74e1550abb1e9bef4","examples/basic_proc_macro.rs":"1ba76387482c7a35620fb4100c3659441956826e593b2dce0df4617e966b1f88","examples/disk.rs":"a65634afc0668c00e3cca37edcc906961bd2572ea1b5b72ef9302f037e25230a","examples/kitchen_sink.rs":"1a16b0a2abc2abb958c1671e50ccc1be1069d644cedb5c506b12d45890a6a720","examples/kitchen_sink_proc_macro.rs":"16100f836b996f2b72f0b2c7baa64e70ff9f4213dfe7e958c373dc6ec931e590","examples/redis-async.rs":"8bceea2cbc8c334d6166b4404bbe75c650bdf9aab539c85a85468ac91ef9b688","examples/redis.rs":"80f1de6b34a6bdbbf8d838207c514241dbefadd5fd33c4f4f50838582d2e50ff","examples/tokio.rs":"41c095ae51d3d77ad19a8b6bff8d81f3833dc84cc94543eda9548aa098526c7c","src/lib.rs":"274089228159b70a333c647dc16bec6c5e260173d4a75b5c7a987508e9f8527e","src/lru_list.rs":"6cf7052b7a2becc5783e81047fbe4658008f868ff04970862bc0b6365df61b89","src/macros.rs":"603e4a1b0b510afeaa5b5930ab54480bc551b585bc8d93969151a7df9aa535b6","src/proc_macro.rs":"add6787b024cc8c207b3e81d3b8593228d2ad37dbababc435b9644a5a011bb40","src/stores/disk.rs":"66e945a4eab78324ee73f997b7a508047f137b9bccd8d67c8c433e3b8c077c32","src/stores/expiring_value_cache.rs":"012a0b0ad1e14be351fa69ff5e0203e623f776d329878f771c2f350ae5dda5b6","src/stores/mod.rs":"a17db855c19de002fa0a698dc4c1724a6f2f7422657e5f5ebff4bc95bd244562","src/stores/redis.rs":"80726a92c0952ef3b9dc0d2390e2bd7cdfbf12d4da025766c1cfbf8d2cfedefb","src/stores/sized.rs":"0c206688029472036f2a88f7100c91b155b50f964e15108b902f257eb98f9b97","src/stores/timed.rs":"8278d54331227c4f5bd3110565253570d4530999a6f62ea868c7ada03582ae6d","src/stores/timed_sized.rs":"59badb88b973acb0dc07767ac207c25e876460b02c984b73af57229a22156e1b","src/stores/unbound.rs":"38a7a9e4f1c6405ac91b27e2a9af69c4f7d43b81ab3b59343677a92a0c8666c3","tests/cached.rs":"10d7bf9d98b6ee52766cce75eb7ae84f9a5481b49fe66d0546cefbe1fa98a10b"},"package":"f251fd1e72720ca07bf5d8e310f54a193fd053479a1f6342c6663ee4fa01cf96"} \ No newline at end of file diff --git a/vendor/cached/CHANGELOG.md b/vendor/cached/CHANGELOG.md new file mode 100644 index 0000000000000..0232cfc038ef8 --- /dev/null +++ b/vendor/cached/CHANGELOG.md @@ -0,0 +1,507 @@ +# Changelog + +## [Unreleased] +## Added +## Changed +## Removed + +## [0.49.2] +## Added +## Changed +- While handling cache refreshes in `DiskCache::cache_get`, treat deserialization failures as non-existent values +## Removed + +## [0.49.1] +## Added +## Changed +- Fix `DiskCache::remove_expired_entries` signature +## Removed + +## [0.49.0 / [cached_proc_macro[0.20.0]] ] +## Added +- Add DiskCache store +- Add `disk=true` (and company) flags to `#[io_cached]` +## Changed +## Removed + +## [0.48.1 / [cached_proc_macro[0.19.1]] / [cached_proc_macro_types[0.1.1]]] +## Added +- Include LICENSE file in `cached_proc_macro` and `cached_proc_macro_types` +## Changed +## Removed + +## [0.48.0 / [cached_proc_macro[0.19.0]]] +## Added +- Add `CloneCached` trait with additional methods when the cache value type implements `Clone` +- Add `result_fallback` option to `cached` proc_macro to support re-using expired cache values + when utilizing an expiring cache store and a fallible function. +## Changed +## Removed + +## [0.47.0] +## Added +## Changed +- Update redis `0.23.0` -> `0.24.0` +## Removed + +## [0.46.1 / [cached_proc_macro[0.18.1]] +## Added +## Changed +- Fix #once sync_writes bug causing a deadlock after ttl expiry, https://github.com/jaemk/cached/issues/174 +## Removed + +## [0.46.0] +## Added +- Add `ahash` feature to use the faster [ahash](https://github.com/tkaitchuck/aHash) algorithm. +- Set `ahash` as a default feature. +- Update hashbrown `0.13.0` -> `0.14.0` +## Changed +## Removed + +## [0.45.1] / [cached_proc_macro[0.18.0]] +## Added +## Changed +- Release `*_no_cache` changes from `0.45.0`. The change is in the proc macro crate which + I forgot to release a new version of. +## Removed + +## [0.45.0] +## Added +- Generate `*_no_cache` function for every cached function to allow calling the original function + without caching. **This is backwards incompatible if you have a function with the same name**. +## Changed +- `tokio` dependency has been removed from `proc_macro` feature (originally unecessarily included). +- `async` feature has been removed from the `default` feature. **This is a backwards incompatible change.** + If you want to use `async` features, you need to enable `async` explicitly. +- remove accidental `#[doc(hidden)]` on the `stores` module +## Removed + +## [0.44.0] / [cached_proc_macro[0.17.0]] +## Added +- Option to enable redis multiplex-connection manager on `AsyncRedisCache` +## Changed +- Show proc-macro documentation on docs.rs +- Document needed feature flags +- Hide implementation details in documentation +- Relax `Cached` trait's `cache_get`, `cache_get_mut` and `cache_remove` key parameter. Allow `K: Borrow` + like `std::collections::HashMap` and friends. Avoids copies particularly on `Cached` where now + you can do `cache.cache_get("key")` and before you had to `cache.cache_get("key".to_string())`. + + Note: This is a minor breaking change for anyone manually implementing the `Cached` trait. + The signatures of `cache_get`, `cache_get_mut`, and `cache_remove` must be updated to include the + additional trait bound on the `key` type: + ```rust + fn cache_get(&mut self, key: &Q) -> Option<&V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + ``` +## Removed +- Dependency to `lazy_static` and `async_once` are removed. + +## [0.43.0] +## Added +## Changed +- Update redis `0.22.0` -> `0.23.0` +- Update serial_test `0.10.0` -> `2.0.0` +## Removed + +## [0.42.0] / [cached_proc_macro[0.16.0]] +## Added +## Changed +- Better code generation for `#[cached]` when the `sync_writes` flag is true. +## Removed + +## [0.41.0] +## Added +## Changed +- Fix "sized" cache types (`SizedCache`, `TimedSizedCache`) to check capacity and evict members after insertion. +- Fixes bug where continuously inserting a key present in the cache would incorrectly evict the oldest cache member + even though the cache size was not increasing. +## Removed + +## [0.40.0] +## Added +- Add optional feature flag `redis_ahash` to enable `redis`'s optional `ahash` feature +## Changed +- Update `redis` to `0.22.0` +- Move `tokio`'s `rt-multi-thread` feature from being a default to being optionally enabled by `async_tokio_rt_multi_thread` +- Fix makefile's doc target to match documentation, changed from `make sync` to `make docs` +## Removed + +## [0.39.0] +## Added +- Add flush method to ExpiringValueCache +## Changed +## Removed + +## [0.38.0] / [cached_proc_macro[0.15.0]] +## Added +## Changed +- Fix proc macro argument documentation +- Disable futures `default-features` +- Add cache-remove to redis example +## Removed + +## [0.37.0] / [cached_proc_macro[0.14.0]] +## Added +## Changed +- Mark the auto-generated "priming" functions with `#[allow(dead_code)]` +- Fix documentation typos +- Replace dev/build scripts with a Makefile +## Removed + +## [0.36.0] / [cached_proc_macro[0.13.0]] +## Added +- wasm support for non-io macros and stores +## Changed +- Use `instant` crate for wasm compatible time +## Removed + +## [0.35.0] +## Added +- Added `ExpiringValueCache` for caching values that can themselves expire. +- Added COPYRIGHT file +## Changed +## Removed + +## [0.34.1] +## Added +- Make sure `AsyncRedisCacheBuilder`, `RedisCacheBuilder`, and `RedisCacheBuildError` publicly visible +## Changed +## Removed + +## [0.34.0] / [cached_proc_macro[0.12.0]] +## Added +## Changed +- Replace `async-mutex` and `async-rwlock` used by proc-macros with `tokio::sync` versions +- Add optional `version` field to `CachedRedisValue` struct +- Cleanup feature flags so async redis features include `redis_store` and `async` features automatically +## Removed + +## [0.33.0] +## Added +- Allow specifying the namespace added to cache keys generated by redis stores +## Changed +- Bump hashbrown 0.11.2 -> 0.12: https://github.com/rust-lang/hashbrown/blob/master/CHANGELOG.md#v0120---2022-01-17 +- Bump smartstring 0.2 -> 1: https://github.com/bodil/smartstring/blob/master/CHANGELOG.md#100---2022-02-24 +## Removed + +## [0.32.1] +## Added +## Changed +- Fix redis features so `redis/aio` is only included when async redis + features (`redis_tokio` / `redis_async_std`) are enabled +## Removed + +## [0.32.0] / [cached_proc_macro[0.11.0]] +## Added +- Fix how doc strings are handled by proc-macros. Capture all documentation on the + cached function definitions and add them to the function definitions generated + by the proc-macros. Add doc strings to generated static caches. Link to relevant static + caches in generated function definitions. Add documentation to the generated + cache-priming function. +## Changed +## Removed + +## [0.31.0] / [cached_proc_macro[0.10.0]] +## Added +- `IOCached` and `IOCachedAsync` traits +- `RedisCache` and `AsyncRedisCache` store types +- Add `#[io_cached]` proc macro for defining cached functions backed + by stores that implement `IOCached`/`IOCachedAsync` +## Changed +- Convert from travis-ci to github actions +- Update build status badge to link to github actions +## Removed + +## [0.30.0] +## Added +- Add flush method to TimedSize and TimedSized caches +## Changed +- Fix timed/timed-sized cache-get/insert/remove to remove and not + return expired values +## Removed + +## [0.29.0] / [cached_proc_macro[0.9.0]] +## Added +- proc-macro: support arguments of the wrapped function being prefixed with `mut` +## Changed +## Removed + +## [0.28.0] +## Added +- Add failable TimedSize and SizeCached constructors +## Changed +## Removed + +## [0.27.0] / [cached_proc_macro[0.8.0]] +## Added +- Add `time_refresh` option to `#[cached]` to refresh TTLs on cache hits +- Generate `*_prime_cache` functions for every `#[cached]` and `#[once]` function + to allow priming caches. +## Changed +## Removed + +## [0.26.1] / [cached_proc_macro[0.7.1]] +## Added +- Add `sync_writes` option to `#[cached]` macro to synchronize + concurrent function calls of duplicate arguments. For ex, if + a long running `#[cached(sync_writes = true)]` function is called + several times concurrently, the actual function is only executed + once while all other calls block and return the newly cached value. +## Changed +## Removed + +## [0.26.0] / [cached_proc_macro[0.7.0]] +## Added +- Add `#[once]` macro for create a `RwLock` cache wrapping a single value +- For all caches, add a function to get an immutable reference to their + contents. This makes it possible to manually dump a cache, so its contents + can be saved and restored later. +## Changed +## Removed + +## [0.25.1] +## Added +## Changed +- Update deps hashbrown and darling, remove async-mutex from cached-proc-macro crate +## Removed + +## [0.25.0] +## Added +- Add option to "timed" caches to refresh the ttl of entries on cache hits +## Changed +## Removed + +## [0.24.1] / [cached_proc_macro[0.6.1]] +## Added +- Add docs strings to the items generated by the `#cached` proc macro +## Changed +## Removed + +## [0.24.0] +## Added +- `cache_reset_metrics` trait method to reset hits/misses +## Changed +## Removed + +## [0.23.0] +## Added +## Changed +- Refactor cache store types to separate modules +## Removed + +## cached[0.22.0] / cached_proc_macro[0.6.0] / cached_proc_macro_types[0.1.0] +## Added +- Add support for returning a `cached::Return` wrapper type that + indicates whether the result came from the function's cache. +## Changed +## Removed + +## [0.21.1] / [0.5.0] +## Added +- Support mutual `size` & `time` args in the cached proc macro. + Added when TimedSizedCache was added, but forgot to release + the cached_proc_macro crate update. +## Changed +## Removed + +## [0.21.0] +## Added +- Add a TimedSizedCache combining LRU and timed/ttl logic +## Changed +## Removed + +## [0.20.0] +## Added +- Add new CachedAsync trait. Only present with async feature. Adds two async function in the entry API style of HashMap +## Changed +## Removed + +## [0.19.0] / [0.4.0] +## Added +## Changed +- Add type hint `_result!` macros +- remove unnecessary transmute in cache reset +- remove unnecessary clones in proc macro +## Removed + +## [0.18.0] / [0.3.0] +## Added +## Changed +- use `async-mutex` instead of full `async-std` +## Removed + +## [0.17.0] +## Added +## Changed +- Store inner values when `result=true` or `option=true`. The `Error` type in the +`Result` now no longer needs to implement `Clone`. +## Removed + +## [0.16.0] +## Added +- add `cache_set_lifespan` to change the cache lifespace, old value returned. +## Changed +## Removed + +## [0.15.1] +## Added +## Changed +- fix proc macro when result=true, regression from changing `cache_set` to return the previous value +## Removed + +## [0.15.0] +## Added +- add `Cached` implementation for std `HashMap` +## Changed +- trait `Cached` has a new method `cache_get_or_set_with` +- `cache_set` now returns the previous value if any +## Removed + +## [0.14.0] +## Added +- add Clone, Debug trait derives on pub types + +## Changed + +## Removed + +## [0.13.1] +## Added + +## Changed +- fix proc macro documentation + +## Removed + +## [0.13.0] +## Added +- proc macro version +- async support when using the new proc macro version + +## Changed + +## Removed + +## [0.12.0] +## Added +- Add `cache_get_mut` to `Cached` trait, to allow mutable access for values in the cache. +- Change the type of `hits` and `misses` to be `u64`. + +## Changed + +## Removed + +## [0.11.0] +## Added +- Add `value_order` method to SizedCache, similar to `key_order` + +## Changed + +## Removed + +## [0.10.0] +## Added +- add `cache_reset` trait method for resetting cache collections to + their initial state + +## Changed +- Update `once_cell` to 1.x + +## Removed + +## [0.9.0] +## Added + +## Changed +- Replace SizedCache implementation to avoid O(n) lookup on cache-get +- Update to Rust-2018 edition +- cargo fmt everything + +## Removed + + +## [0.8.1] +## Added + +## Changed +- Replace inner cache when "clearing" unbounded cache + +## Removed + + +## [0.8.0] +## Added + +## Changed +- Switch to `once_cell`. Library users no longer need to import `lazy_static` + +## Removed + +## [0.7.0] +## Added +- Add `cache_clear` and `cache_result` to `Cached` trait + - Allows for defeating cache entries if desired + +## Changed + +## Removed + +## [0.6.2] +## Added + +## Changed +- Update documentation + - Note the in-memory nature of cache stores + - Note the behavior of memoized functions under concurrent access + +## Removed + +## [0.6.1] +## Added + +## Changed +- Fixed duplicate key eviction in `SizedCache::cache_set`. This would manifest when + `cached` functions called with duplicate keys would race set an uncached key, + or if `SizedCache` was used directly. + +## Removed + +## [0.6.0] +## Added +- Add `cached_result` and `cached_key_result` to allow the caching of success for a function that returns `Result`. +- Add `cached_control` macro to allow specifying functionality + at key points of the macro + +## [0.5.0] +## Added +- Add `cached_key` macro to allow defining the caching key + +## Changed +- Tweak `cached` macro syntax +- Update readme + +## Removed + + +## [0.4.4] +## Added + +## Changed +- Update trait docs + +## Removed + + +## [0.4.3] +## Added + +## Changed +- Update readme +- Update examples +- Update crate documentation and examples + +## Removed diff --git a/vendor/cached/CONTRIBUTING.md b/vendor/cached/CONTRIBUTING.md new file mode 100644 index 0000000000000..b42adc5e1dc63 --- /dev/null +++ b/vendor/cached/CONTRIBUTING.md @@ -0,0 +1,54 @@ +# Contributing + +Thanks for contributing! + +## Getting Started + +### Required software + +- [Rust toolchain](https://www.rust-lang.org/en-US/install.html) +- [`cargo-readme`](https://github.com/livioribeiro/cargo-readme) (`cargo install + cargo-readme`) +- [GNU Make](https://www.gnu.org/software/make/) +- [Docker](https://www.docker.com/) or another Docker-compatible container + engine + - The docker command used by the Makefile can be specified with `DOCKER_COMMAND`, e.g. + ``` + make DOCKER_COMMAND=containerd docker/redis + ``` + +## Making Changes + +- Before committing changes, make sure to run `make fmt` to format the changes +- Add an entry to the `CHANGELOG.md` file +- The `README.md` is generated using `cargo-readme` from the crate level + documentation in `src/lib.rs`. This means the `README.md` should never be + modified by hand. To sync changes made to `src/lib.rs`, run `make docs` +- The CI system will run all tests using `make ci`. Make sure to run all tests + before submitting your pull request + +## Make goals overview + +```bash +# The goal used by the CI system +make ci +# Runs all examples +make examples +# Runs all tests +make tests +# Syncs all docs +make sync +# Formats the source code +make fmt +# Performs multiple checks (formatting, clippy and documentation sync) +make check +# Removes all generated artifacts, including docker containers +make clean +``` + +## Submitting Changes + +Pull Requests should be made against master. +Travis CI will run the test suite on all PRs. +Remember to update the changelog! + diff --git a/vendor/cached/COPYRIGHT b/vendor/cached/COPYRIGHT new file mode 100644 index 0000000000000..528d43d082988 --- /dev/null +++ b/vendor/cached/COPYRIGHT @@ -0,0 +1,6 @@ +Copyrights in the "cached" project are retained by their contributors. No +copyright assignment is required to contribute to the "cached" project. + +Copyright attributions may be noted at the top of individual files. +For full authorship information, see the version control history. +https://github.com/jaemk/cached/graphs/contributors diff --git a/vendor/cached/Cargo.lock b/vendor/cached/Cargo.lock new file mode 100644 index 0000000000000..6c2fc2383b91f --- /dev/null +++ b/vendor/cached/Cargo.lock @@ -0,0 +1,1705 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "arc-swap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" + +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn 1.0.98", +] + +[[package]] +name = "async-channel" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5262ed948da60dd8956c6c5aca4d4163593dddb7b32d73267c93dab7b2e98940" +dependencies = [ + "async-channel", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "num_cpus", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5e18f61464ae81cde0a23e713ae8fd299580c54d697a35820cfd0625b8b0e07" +dependencies = [ + "concurrent-queue", + "futures-lite", + "libc", + "log", + "once_cell", + "parking", + "polling", + "slab", + "socket2", + "waker-fn", + "winapi", +] + +[[package]] +name = "async-lock" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-native-tls" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d57d4cec3c647232e1094dc013546c0b33ce785d8aeb251e1f20dfaf8a9a13fe" +dependencies = [ + "futures-util", + "native-tls", + "thiserror", + "url", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-attributes", + "async-channel", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" + +[[package]] +name = "async-trait" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.98", +] + +[[package]] +name = "atomic-waker" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "blocking" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc" +dependencies = [ + "async-channel", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "once_cell", +] + +[[package]] +name = "bumpalo" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cache-padded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" + +[[package]] +name = "cached" +version = "0.49.2" +dependencies = [ + "ahash", + "async-std", + "async-trait", + "cached_proc_macro", + "cached_proc_macro_types", + "directories", + "futures", + "hashbrown 0.14.3", + "instant", + "once_cell", + "r2d2", + "redis", + "rmp-serde", + "serde", + "serde_json", + "serial_test", + "sled", + "smartstring", + "thiserror", + "tokio", +] + +[[package]] +name = "cached_proc_macro" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9f16c0d84de31a2ab7fdf5f7783c14631f7075cf464eb3bb43119f61c9cb2a" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.98", +] + +[[package]] +name = "cached_proc_macro_types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "combine" +version = "4.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" +dependencies = [ + "bytes", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "concurrent-queue" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +dependencies = [ + "cache-padded", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "ctor" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" +dependencies = [ + "quote", + "syn 1.0.98", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.98", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.98", +] + +[[package]] +name = "dashmap" +version = "5.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f" +dependencies = [ + "cfg-if", + "hashbrown 0.12.1", + "lock_api", + "parking_lot_core 0.9.3", +] + +[[package]] +name = "directories" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "event-listener" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "futures" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-executor" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.98", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gloo-timers" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "js-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", + "value-bag", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "native-tls" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "openssl" +version = "0.10.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb81a6430ac911acb25fe5ac8f1d2af1b4ea8a4fdfda0f1ee4292af2e2d8eb0e" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.98", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.3", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.13", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.13", + "smallvec", + "windows-sys", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78203e83c48cffbe01e4a2d35d566ca4de445d79a85372fc64e378bfc812a260" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.98", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "polling" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" +dependencies = [ + "cfg-if", + "libc", + "log", + "wepoll-ffi", + "winapi", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot 0.12.1", + "scheduled-thread-pool", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redis" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c580d9cbbe1d1b479e8d67cf9daf6a62c957e6846048408b80b43ac3f6af84cd" +dependencies = [ + "ahash", + "arc-swap", + "async-native-tls", + "async-std", + "async-trait", + "bytes", + "combine", + "futures", + "futures-util", + "itoa", + "native-tls", + "percent-encoding", + "pin-project-lite", + "r2d2", + "ryu", + "sha1_smol", + "socket2", + "tokio", + "tokio-native-tls", + "tokio-retry", + "tokio-util", + "url", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rmp" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys", +] + +[[package]] +name = "scheduled-thread-pool" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf" +dependencies = [ + "parking_lot 0.12.1", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.98", +] + +[[package]] +name = "serde_json" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serial_test" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" +dependencies = [ + "dashmap", + "futures", + "lazy_static", + "log", + "parking_lot 0.12.1", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.46", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "sled" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935" +dependencies = [ + "crc32fast", + "crossbeam-epoch", + "crossbeam-utils", + "fs2", + "fxhash", + "libc", + "log", + "parking_lot 0.11.2", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "smartstring" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" +dependencies = [ + "autocfg", + "static_assertions", + "version_check", +] + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall 0.2.13", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.98", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot 0.12.1", + "pin-project-lite", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.98", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-retry" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" +dependencies = [ + "pin-project", + "rand", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +dependencies = [ + "once_cell", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "unicode-normalization" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "value-bag" +version = "1.0.0-alpha.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" +dependencies = [ + "ctor", + "version_check", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn 1.0.98", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.98", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" + +[[package]] +name = "web-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wepoll-ffi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +dependencies = [ + "cc", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.46", +] diff --git a/vendor/cached/Cargo.toml b/vendor/cached/Cargo.toml new file mode 100644 index 0000000000000..08d33ad6f13e7 --- /dev/null +++ b/vendor/cached/Cargo.toml @@ -0,0 +1,216 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "cached" +version = "0.49.2" +authors = ["James Kominick "] +description = "Generic cache implementations and simplified function memoization" +documentation = "https://docs.rs/cached" +readme = "README.md" +keywords = [ + "cache", + "memoize", + "lru", + "redis", + "disk", +] +categories = [ + "caching", + "data-structures", +] +license = "MIT" +repository = "https://github.com/jaemk/cached" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[[example]] +name = "redis" +required-features = [ + "redis_store", + "proc_macro", +] + +[[example]] +name = "redis-async" +required-features = [ + "async", + "proc_macro", +] + +[[example]] +name = "tokio" +required-features = [ + "async", + "proc_macro", +] + +[[example]] +name = "async_std" +required-features = [ + "async", + "proc_macro", +] + +[dependencies.ahash] +version = "0.8" +optional = true +default-features = false + +[dependencies.async-trait] +version = "0.1" +optional = true + +[dependencies.cached_proc_macro] +version = "0.20.0" +optional = true + +[dependencies.cached_proc_macro_types] +version = "0.1.1" +optional = true + +[dependencies.directories] +version = "4.0" +optional = true + +[dependencies.futures] +version = "0.3" +optional = true +default-features = false + +[dependencies.hashbrown] +version = "0.14" +features = [ + "raw", + "inline-more", +] +default-features = false + +[dependencies.instant] +version = "0.1" + +[dependencies.once_cell] +version = "1" + +[dependencies.r2d2] +version = "0.8" +optional = true + +[dependencies.redis] +version = "0.24" +features = ["r2d2"] +optional = true + +[dependencies.rmp-serde] +version = "1.1" +optional = true + +[dependencies.serde] +version = "1.0" +features = ["derive"] +optional = true + +[dependencies.serde_json] +version = "1.0" +optional = true + +[dependencies.sled] +version = "0.34" +optional = true + +[dependencies.thiserror] +version = "1" + +[dependencies.tokio] +version = "1" +features = [ + "macros", + "time", + "sync", + "parking_lot", +] +optional = true + +[dev-dependencies.async-std] +version = "1.6" +features = ["attributes"] + +[dev-dependencies.serial_test] +version = "2" + +[dev-dependencies.smartstring] +version = "1" + +[features] +ahash = [ + "dep:ahash", + "hashbrown/default", +] +async = [ + "futures", + "tokio", + "async-trait", +] +async_tokio_rt_multi_thread = [ + "async", + "tokio/rt-multi-thread", +] +default = [ + "proc_macro", + "ahash", +] +disk_store = [ + "sled", + "serde", + "rmp-serde", + "directories", +] +proc_macro = [ + "cached_proc_macro", + "cached_proc_macro_types", +] +redis_ahash = [ + "redis_store", + "redis/ahash", +] +redis_async_std = [ + "redis_store", + "async", + "redis/aio", + "redis/async-std-comp", + "redis/tls", + "redis/async-std-tls-comp", +] +redis_connection_manager = [ + "redis_store", + "redis/connection-manager", +] +redis_store = [ + "redis", + "r2d2", + "serde", + "serde_json", +] +redis_tokio = [ + "redis_store", + "async", + "redis/aio", + "redis/tokio-comp", + "redis/tls", + "redis/tokio-native-tls-comp", +] +wasm = ["instant/wasm-bindgen"] diff --git a/vendor/cached/LICENSE b/vendor/cached/LICENSE new file mode 100644 index 0000000000000..3b332da1eb1c3 --- /dev/null +++ b/vendor/cached/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 James Kominick + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/cached/Makefile b/vendor/cached/Makefile new file mode 100644 index 0000000000000..abd4050fce2e5 --- /dev/null +++ b/vendor/cached/Makefile @@ -0,0 +1,164 @@ +################################################################################ +# Author: Altair Bueno +# Date: 22/06/2022 +# Source: https://github.com/jaemk/cached +# Copyright: MIT License (see LICENSE) +# Description: GNU Makefile for `cached` +################################################################################ +# Configuration variables + +# List with all basic examples. An example is considered basic if it can be +# run using `cargo run --example=$EXAMPLE` and run standalone. All features are +# **enabled** +CACHED_BASIC_EXAMPLES = async_std \ + basic \ + basic_proc_macro \ + kitchen_sink \ + kitchen_sink_proc_macro \ + tokio +# Same as `CACHED_BASIC_EXAMPLES`, but these examples require the `docker/redis` +# goal +CACHED_REDIS_EXAMPLES = redis \ + redis-async +# Custom commands. NOTE: You'll need to specify the goal manually. See +# `examples/cargo/wasm` for an example +CACHED_CARGO_EXAMPLES = wasm + +# Cargo command used to run `run`, `build`, `test`... Useful if you keep +# multiple cargo versions installed on your machine +CARGO_COMMAND = cargo + +# Compiler program and flags used to generate README.md +README_CC = $(CARGO_COMMAND) readme +README_CCFLAGS = --no-indent-headings + +# Compiler program and flags used to generate format the crate +FMT_CC = $(CARGO_COMMAND) fmt +FMT_CCFLAGS = + +# Docker configuration. Set DOCKER_COMMAND on your shell to override the +# container engine used +# +# ```sh +# # Using containerd to run `docker/redis` +# make DOCKER_COMMAND=containerd docker/redis +# ``` +DOCKER_COMMAND = docker +DOCKER_REDIS_CONTAINER_NAME = cached-tests +DOCKER_REDIS_CONTAINER_LOCAL_PORT = 6399 + +################################################################################ +# Exported variables +export CACHED_REDIS_CONNECTION_STRING = redis://127.0.0.1:$(DOCKER_REDIS_CONTAINER_LOCAL_PORT) +export RUST_BACKTRACE = 1 + +################################################################################ +# GitHub Actions goal. Run this to test your changes before summiting your final +# pull request +ci: check tests examples + +################################################################################ +# Runs all examples +examples: examples/basic examples/cargo examples/redis +# Runs all basic examples +examples/basic: $(addprefix examples/basic/, $(CACHED_BASIC_EXAMPLES)) +# Runs all the project based examples +examples/cargo: $(addprefix examples/cargo/, $(CACHED_CARGO_EXAMPLES)) +# Runs `redis` related examples. NOTE: depends on `docker/redis` +examples/redis: $(addprefix examples/redis/, $(CACHED_REDIS_EXAMPLES)) + +examples/basic/%: + @echo [$@]: Running example $*... + $(CARGO_COMMAND) run --example $* --all-features + +# Only builds the `wasm` example. Running this example requires a browser +examples/cargo/wasm: + @echo [$@]: Building example $*... + cd examples/wasm ; $(CARGO_COMMAND) build --target=wasm32-unknown-unknown + +examples/redis/%: docker/redis + @echo [$@]: Running example $*... + $(CARGO_COMMAND) run --example $* --all-features + +################################################################################ +# Runs `cached` tests. NOTE: Depends on `docker/redis` +tests: docker/redis + @echo [$@]: Running tests... + $(CARGO_COMMAND) test --all-features -- --nocapture + +################################################################################ +# Starts a Redis server using `DOCKER_COMMAND` +docker/redis: docker/status + @echo [$@]: Starting Redis container... + -$(DOCKER_COMMAND) run --rm --name $(DOCKER_REDIS_CONTAINER_NAME) \ + -p $(DOCKER_REDIS_CONTAINER_LOCAL_PORT):6379 -d redis + +docker/status: + @echo [$@]: Checking the Docker engine + @docker info > /dev/null || (>&2 echo 'Is the Docker engine running?' && exit 42) + +################################################################################ +# Syncs all docs +docs: docs/readme + +# Updates README.md using `README_CC` +docs/readme: README.md + +README.md: src/lib.rs + @echo [$@]: Updating $@... + $(README_CC) $(README_CCFLAGS) > $@ + +################################################################################ +# Formats `cached` crate +fmt: + @echo [$@]: Formatting code... + $(FMT_CC) $(FMT_CCFLAGS) + +################################################################################ +# Runs all checks +check: check/fmt check/readme check/clippy + +# Checks if `cached` crate is well formatted +check/fmt: FMT_CCFLAGS += --check +check/fmt: + @echo [$@]: Checking code format... + $(FMT_CC) $(FMT_CCFLAGS) + +# Checks if the README.md file is up-to-date +check/readme: + @echo [$@]: Checking README.md... + $(README_CC) $(README_CCFLAGS) | cmp README.md + +# Runs clippy linter on `cached` crate +check/clippy: + @echo [$@]: Running clippy... + $(CARGO_COMMAND) clippy --all-features --all-targets --examples --tests + +################################################################################ +# Cleans all generated artifacts and deletes all docker containers +clean: clean/docker clean/cargo + +# Runs `cargo clean` +clean/cargo: + @echo [$@]: Removing cargo artifacts... + $(CARGO_COMMAND) clean + +# Removes all docker containers +clean/docker: clean/docker/$(DOCKER_REDIS_CONTAINER_NAME) + +# Removes a docker container with the given name +clean/docker/%: + @echo [$@]: Removing container called $*... + $(DOCKER_COMMAND) rm -f $* + +################################################################################ +# Special targets. + +.PHONY: ci \ + $(filter examples%, $(MAKECMDGOALS)) \ + $(filter tests%, $(MAKECMDGOALS)) \ + $(filter docker%, $(MAKECMDGOALS)) \ + $(filter docs%, $(MAKECMDGOALS)) \ + $(filter fmt%, $(MAKECMDGOALS)) \ + $(filter check%, $(MAKECMDGOALS)) \ + $(filter clean%, $(MAKECMDGOALS)) diff --git a/vendor/cached/README.md b/vendor/cached/README.md new file mode 100644 index 0000000000000..3081539e2dca1 --- /dev/null +++ b/vendor/cached/README.md @@ -0,0 +1,199 @@ +# cached + +[![Build Status](https://github.com/jaemk/cached/actions/workflows/build.yml/badge.svg)](https://github.com/jaemk/cached/actions/workflows/build.yml) +[![crates.io](https://img.shields.io/crates/v/cached.svg)](https://crates.io/crates/cached) +[![docs](https://docs.rs/cached/badge.svg)](https://docs.rs/cached) + +> Caching structures and simplified function memoization + +`cached` provides implementations of several caching structures as well as a handy macros +for defining memoized functions. + +Memoized functions defined using [`#[cached]`](proc_macro::cached)/[`#[once]`](proc_macro::once)/[`#[io_cached]`](proc_macro::io_cached)/[`cached!`](crate::macros) macros are thread-safe with the backing +function-cache wrapped in a mutex/rwlock, or externally synchronized in the case of `#[io_cached]`. +By default, the function-cache is **not** locked for the duration of the function's execution, so initial (on an empty cache) +concurrent calls of long-running functions with the same arguments will each execute fully and each overwrite +the memoized value as they complete. This mirrors the behavior of Python's `functools.lru_cache`. To synchronize the execution and caching +of un-cached arguments, specify `#[cached(sync_writes = true)]` / `#[once(sync_writes = true)]` (not supported by `#[io_cached]`. + +- See [`cached::stores` docs](https://docs.rs/cached/latest/cached/stores/index.html) cache stores available. +- See [`proc_macro`](https://docs.rs/cached/latest/cached/proc_macro/index.html) for more procedural macro examples. +- See [`macros`](https://docs.rs/cached/latest/cached/macros/index.html) for more declarative macro examples. + +**Features** + +- `default`: Include `proc_macro` and `ahash` features +- `proc_macro`: Include proc macros +- `ahash`: Enable the optional `ahash` hasher as default hashing algorithm. +- `async`: Include support for async functions and async cache stores +- `async_tokio_rt_multi_thread`: Enable `tokio`'s optional `rt-multi-thread` feature. +- `redis_store`: Include Redis cache store +- `redis_async_std`: Include async Redis support using `async-std` and `async-std` tls support, implies `redis_store` and `async` +- `redis_tokio`: Include async Redis support using `tokio` and `tokio` tls support, implies `redis_store` and `async` +- `redis_connection_manager`: Enable the optional `connection-manager` feature of `redis`. Any async redis caches created + will use a connection manager instead of a `MultiplexedConnection` +- `redis_ahash`: Enable the optional `ahash` feature of `redis` +- `disk_store`: Include disk cache store +- `wasm`: Enable WASM support. Note that this feature is incompatible with `tokio`'s multi-thread + runtime (`async_tokio_rt_multi_thread`) and all Redis features (`redis_store`, `redis_async_std`, `redis_tokio`, `redis_ahash`) + +The procedural macros (`#[cached]`, `#[once]`, `#[io_cached]`) offer more features, including async support. +See the [`proc_macro`](crate::proc_macro) and [`macros`](crate::macros) modules for more samples, and the +[`examples`](https://github.com/jaemk/cached/tree/master/examples) directory for runnable snippets. + +Any custom cache that implements `cached::Cached`/`cached::CachedAsync` can be used with the `#[cached]`/`#[once]`/`cached!` macros in place of the built-ins. +Any custom cache that implements `cached::IOCached`/`cached::IOCachedAsync` can be used with the `#[io_cached]` macro. + +---- + +The basic usage looks like: + +```rust +use cached::proc_macro::cached; + +/// Defines a function named `fib` that uses a cache implicitly named `FIB`. +/// By default, the cache will be the function's name in all caps. +/// The following line is equivalent to #[cached(name = "FIB", unbound)] +#[cached] +fn fib(n: u64) -> u64 { + if n == 0 || n == 1 { return n } + fib(n-1) + fib(n-2) +} +``` + +---- + +```rust +use std::thread::sleep; +use std::time::Duration; +use cached::proc_macro::cached; +use cached::SizedCache; + +/// Use an explicit cache-type with a custom creation block and custom cache-key generating block +#[cached( + type = "SizedCache", + create = "{ SizedCache::with_size(100) }", + convert = r#"{ format!("{}{}", a, b) }"# +)] +fn keyed(a: &str, b: &str) -> usize { + let size = a.len() + b.len(); + sleep(Duration::new(size as u64, 0)); + size +} +``` + +---- + +```rust +use cached::proc_macro::once; + +/// Only cache the initial function call. +/// Function will be re-executed after the cache +/// expires (according to `time` seconds). +/// When no (or expired) cache, concurrent calls +/// will synchronize (`sync_writes`) so the function +/// is only executed once. +#[once(time=10, option = true, sync_writes = true)] +fn keyed(a: String) -> Option { + if a == "a" { + Some(a.len()) + } else { + None + } +} +``` + +---- + +```rust,no_run,ignore +use cached::proc_macro::io_cached; +use cached::AsyncRedisCache; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq, Clone)] +enum ExampleError { + #[error("error with redis cache `{0}`")] + RedisError(String), +} + +/// Cache the results of an async function in redis. Cache +/// keys will be prefixed with `cache_redis_prefix`. +/// A `map_error` closure must be specified to convert any +/// redis cache errors into the same type of error returned +/// by your function. All `io_cached` functions must return `Result`s. +#[io_cached( + map_error = r##"|e| ExampleError::RedisError(format!("{:?}", e))"##, + type = "AsyncRedisCache", + create = r##" { + AsyncRedisCache::new("cached_redis_prefix", 1) + .set_refresh(true) + .build() + .await + .expect("error building example redis cache") + } "## +)] +async fn async_cached_sleep_secs(secs: u64) -> Result { + std::thread::sleep(std::time::Duration::from_secs(secs)); + Ok(secs.to_string()) +} +``` + +---- + +```rust,no_run,ignore +use cached::proc_macro::io_cached; +use cached::DiskCache; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq, Clone)] +enum ExampleError { + #[error("error with disk cache `{0}`")] + DiskError(String), +} + +/// Cache the results of a function on disk. +/// Cache files will be stored under the system cache dir +/// unless otherwise specified with `disk_dir` or the `create` argument. +/// A `map_error` closure must be specified to convert any +/// disk cache errors into the same type of error returned +/// by your function. All `io_cached` functions must return `Result`s. +#[io_cached( + map_error = r##"|e| ExampleError::DiskError(format!("{:?}", e))"##, + disk = true +)] +fn cached_sleep_secs(secs: u64) -> Result { + std::thread::sleep(std::time::Duration::from_secs(secs)); + Ok(secs.to_string()) +} +``` + + +Functions defined via macros will have their results cached using the +function's arguments as a key, a `convert` expression specified on a procedural macros, +or a `Key` block specified on a `cached_key!` declarative macro. + +When a macro-defined function is called, the function's cache is first checked for an already +computed (and still valid) value before evaluating the function body. + +Due to the requirements of storing arguments and return values in a global cache: + +- Function return types: + - For all store types, except Redis, must be owned and implement `Clone` + - For the Redis store type, must be owned and implement `serde::Serialize + serde::DeserializeOwned` +- Function arguments: + - For all store types, except Redis, must either be owned and implement `Hash + Eq + Clone`, + the `cached_key!` macro is used with a `Key` block specifying key construction, or + a `convert` expression is specified on a procedural macro to specify how to construct a key + of a `Hash + Eq + Clone` type. + - For the Redis store type, must either be owned and implement `Display`, or the `cached_key!` & `Key` + or procedural macro & `convert` expression used to specify how to construct a key of a `Display` type. +- Arguments and return values will be `cloned` in the process of insertion and retrieval. Except for Redis + where arguments are formatted into `Strings` and values are de/serialized. +- Macro-defined functions should not be used to produce side-effectual results! +- Macro-defined functions cannot live directly under `impl` blocks since macros expand to a + `once_cell` initialization and one or more function definitions. +- Macro-defined functions cannot accept `Self` types as a parameter. + + + +License: MIT diff --git a/vendor/cached/bin/readme.rs b/vendor/cached/bin/readme.rs new file mode 100644 index 0000000000000..95851481855d9 --- /dev/null +++ b/vendor/cached/bin/readme.rs @@ -0,0 +1,16 @@ +// cargo-deps: sha2="0.9" + +use std::io::Read; +use sha2::Digest; + +fn main() { + let args = std::env::args().collect::>(); + let mut file = std::fs::File::open("README.md").expect("no file"); + let mut contents = String::new(); + file.read_to_string(&mut contents).expect("read error"); + + let mut hasher = sha2::Sha256::new(); + hasher.update(contents.as_bytes()); + let result = hasher.finalize(); + println!("{:?}", result); +} \ No newline at end of file diff --git a/vendor/cached/examples/async_std.rs b/vendor/cached/examples/async_std.rs new file mode 100644 index 0000000000000..a61999330e833 --- /dev/null +++ b/vendor/cached/examples/async_std.rs @@ -0,0 +1,191 @@ +use async_std::task::sleep; +use cached::proc_macro::cached; +use cached::proc_macro::once; +use std::time::Duration; + +async fn sleep_secs(secs: u64) { + sleep(Duration::from_secs(secs)).await; +} + +/// should only sleep the first time it's called +#[cached] +async fn cached_sleep_secs(secs: u64) { + sleep(Duration::from_secs(secs)).await; +} + +/// should only cache the result for a second, and only when +/// the result is `Ok` +#[cached(time = 1, key = "bool", convert = r#"{ true }"#, result = true)] +async fn only_cached_a_second( + s: String, +) -> std::result::Result, &'static dyn std::error::Error> { + Ok(vec![s]) +} + +/// should only cache the _first_ `Ok` returned. +/// all arguments are ignored for subsequent calls. +#[once(result = true)] +async fn only_cached_result_once(s: String, error: bool) -> std::result::Result, u32> { + if error { + Err(1) + } else { + Ok(vec![s]) + } +} + +/// should only cache the _first_ `Ok` returned for 1 second. +/// all arguments are ignored for subsequent calls until the +/// cache expires after a second. +#[once(result = true, time = 1)] +async fn only_cached_result_once_per_second( + s: String, + error: bool, +) -> std::result::Result, u32> { + if error { + Err(1) + } else { + Ok(vec![s]) + } +} + +/// should only cache the _first_ `Some` returned . +/// all arguments are ignored for subsequent calls +#[once(option = true)] +async fn only_cached_option_once(s: String, none: bool) -> Option> { + if none { + None + } else { + Some(vec![s]) + } +} + +/// should only cache the _first_ `Some` returned for 1 second. +/// all arguments are ignored for subsequent calls until the +/// cache expires after a second. +#[once(option = true, time = 1)] +async fn only_cached_option_once_per_second(s: String, none: bool) -> Option> { + if none { + None + } else { + Some(vec![s]) + } +} + +/// should only cache the _first_ value returned for 1 second. +/// all arguments are ignored for subsequent calls until the +/// cache expires after a second. +#[once(time = 1)] +async fn only_cached_once_per_second(s: String) -> Vec { + vec![s] +} + +/// should only cache the _first_ value returned for 2 seconds. +/// all arguments are ignored for subsequent calls until the +/// cache expires after a second. +/// when multiple un-cached tasks are running concurrently, only +/// _one_ call will be "executed" and all others will be synchronized +/// to return the cached result of the one call instead of all +/// concurrently un-cached tasks executing and writing concurrently. +#[once(time = 2, sync_writes = true)] +async fn only_cached_once_per_second_sync_writes(s: String) -> Vec { + vec![s] +} + +#[async_std::main] +async fn main() { + let a = only_cached_a_second("a".to_string()).await.unwrap(); + let b = only_cached_a_second("b".to_string()).await.unwrap(); + assert_eq!(a, b); + sleep_secs(1).await; + let b = only_cached_a_second("b".to_string()).await.unwrap(); + assert_ne!(a, b); + + println!("cached sleeping for 1 seconds"); + cached_sleep_secs(1).await; + println!("cached sleeping for 1 seconds"); + cached_sleep_secs(1).await; + + println!("cached result once"); + assert!(only_cached_result_once("z".to_string(), true) + .await + .is_err()); + let a = only_cached_result_once("a".to_string(), false) + .await + .unwrap(); + let b = only_cached_result_once("b".to_string(), false) + .await + .unwrap(); + assert_eq!(a, b); + sleep_secs(1).await; + let b = only_cached_result_once("b".to_string(), false) + .await + .unwrap(); + assert_eq!(a, b); + + println!("cached result once per second"); + assert!(only_cached_result_once_per_second("z".to_string(), true) + .await + .is_err()); + let a = only_cached_result_once_per_second("a".to_string(), false) + .await + .unwrap(); + let b = only_cached_result_once_per_second("b".to_string(), false) + .await + .unwrap(); + assert_eq!(a, b); + sleep_secs(1).await; + let b = only_cached_result_once_per_second("b".to_string(), false) + .await + .unwrap(); + assert_eq!(vec!["b".to_string()], b); + + println!("cached option once"); + assert!(only_cached_option_once("z".to_string(), true) + .await + .is_none()); + let a = only_cached_option_once("a".to_string(), false) + .await + .unwrap(); + let b = only_cached_option_once("b".to_string(), false) + .await + .unwrap(); + assert_eq!(a, b); + sleep_secs(1).await; + let b = only_cached_option_once("b".to_string(), false) + .await + .unwrap(); + assert_eq!(a, b); + + println!("cached option once per second"); + assert!(only_cached_option_once_per_second("z".to_string(), true) + .await + .is_none()); + let a = only_cached_option_once_per_second("a".to_string(), false) + .await + .unwrap(); + let b = only_cached_option_once_per_second("b".to_string(), false) + .await + .unwrap(); + assert_eq!(a, b); + sleep_secs(1).await; + let b = only_cached_option_once_per_second("b".to_string(), false) + .await + .unwrap(); + assert_eq!(vec!["b".to_string()], b); + + println!("cached once per second"); + let a = only_cached_once_per_second("a".to_string()).await; + let b = only_cached_once_per_second("b".to_string()).await; + assert_eq!(a, b); + sleep_secs(1).await; + let b = only_cached_once_per_second("b".to_string()).await; + assert_eq!(vec!["b".to_string()], b); + + println!("cached once per second synchronized writes"); + let a = async_std::task::spawn(only_cached_once_per_second_sync_writes("a".to_string())); + sleep_secs(1).await; + let b = async_std::task::spawn(only_cached_once_per_second_sync_writes("b".to_string())); + assert_eq!(a.await, b.await); + + println!("done!"); +} diff --git a/vendor/cached/examples/basic.rs b/vendor/cached/examples/basic.rs new file mode 100644 index 0000000000000..6ae8f16b1144a --- /dev/null +++ b/vendor/cached/examples/basic.rs @@ -0,0 +1,43 @@ +#[macro_use] +extern crate cached; + +use std::thread::sleep; +use std::time::{Duration, Instant}; + +use cached::SizedCache; + +cached! { + SLOW_FN: SizedCache = SizedCache::with_size(50); + fn slow_fn(n: u32) -> String = { + if n == 0 { return "done".to_string(); } + sleep(Duration::new(1, 0)); + slow_fn(n-1) + } +} + +pub fn main() { + println!("Initial run..."); + let now = Instant::now(); + let _ = slow_fn(10); + println!("Elapsed: {}\n", now.elapsed().as_secs()); + + println!("Cached run..."); + let now = Instant::now(); + let _ = slow_fn(10); + println!("Elapsed: {}\n", now.elapsed().as_secs()); + + // Inspect the cache + { + use cached::Cached; // must be in scope to access cache + + println!(" ** Cache info **"); + let cache = SLOW_FN.lock().unwrap(); + assert_eq!(cache.cache_hits().unwrap(), 1); + println!("hits=1 -> {:?}", cache.cache_hits().unwrap() == 1); + assert_eq!(cache.cache_misses().unwrap(), 11); + println!("misses=11 -> {:?}", cache.cache_misses().unwrap() == 11); + // make sure the cache-lock is dropped + } + + println!("done!"); +} diff --git a/vendor/cached/examples/basic_proc_macro.rs b/vendor/cached/examples/basic_proc_macro.rs new file mode 100644 index 0000000000000..9696f1f67a9ad --- /dev/null +++ b/vendor/cached/examples/basic_proc_macro.rs @@ -0,0 +1,59 @@ +use cached::proc_macro::cached; +use cached::proc_macro::once; +use std::thread::sleep; +use std::time::{Duration, Instant}; + +#[cached(size = 50)] +fn slow_fn(n: u32) -> String { + if n == 0 { + return "done".to_string(); + } + sleep(Duration::new(1, 0)); + slow_fn(n - 1) +} + +#[once(time = 1)] +fn once_slow_fn(n: u32) -> String { + sleep(Duration::new(1, 0)); + format!("{n}") +} + +pub fn main() { + println!("[cached] Initial run..."); + let now = Instant::now(); + let _ = slow_fn(10); + println!("[cached] Elapsed: {}\n", now.elapsed().as_secs()); + + println!("[cached] Cached run..."); + let now = Instant::now(); + let _ = slow_fn(10); + println!("[cached] Elapsed: {}\n", now.elapsed().as_secs()); + + // Inspect the cache + { + use cached::Cached; // must be in scope to access cache + + println!("[cached] ** Cache info **"); + let cache = SLOW_FN.lock().unwrap(); + assert_eq!(cache.cache_hits().unwrap(), 1); + println!("[cached] hits=1 -> {:?}", cache.cache_hits().unwrap() == 1); + assert_eq!(cache.cache_misses().unwrap(), 11); + println!( + "[cached] misses=11 -> {:?}", + cache.cache_misses().unwrap() == 11 + ); + // make sure the cache-lock is dropped + } + + println!("[once] Initial run..."); + let now = Instant::now(); + let _ = once_slow_fn(10); + println!("[once] Elapsed: {}\n", now.elapsed().as_secs()); + + println!("[once] Cached run..."); + let now = Instant::now(); + let _ = once_slow_fn(10); + println!("[once] Elapsed: {}\n", now.elapsed().as_secs()); + + println!("done!"); +} diff --git a/vendor/cached/examples/disk.rs b/vendor/cached/examples/disk.rs new file mode 100644 index 0000000000000..83bbe5bbff6f2 --- /dev/null +++ b/vendor/cached/examples/disk.rs @@ -0,0 +1,46 @@ +/* +run with required features: + cargo run --example disk --features "disk_store" + */ + +use cached::proc_macro::io_cached; +use std::io; +use std::io::Write; +use std::time::Duration; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq, Clone)] +enum ExampleError { + #[error("error with redis cache `{0}`")] + DiskError(String), +} + +// When the macro constructs your DiskCache instance, the default +// cache files will be stored under $system_cache_dir/cached_disk_cache/ +#[io_cached( + disk = true, + time = 30, + map_error = r##"|e| ExampleError::DiskError(format!("{:?}", e))"## +)] +fn cached_sleep_secs(secs: u64) -> Result<(), ExampleError> { + std::thread::sleep(Duration::from_secs(secs)); + Ok(()) +} + +fn main() { + print!("1. first sync call with a 2 seconds sleep..."); + io::stdout().flush().unwrap(); + cached_sleep_secs(2).unwrap(); + println!("done"); + print!("second sync call with a 2 seconds sleep (it should be fast)..."); + io::stdout().flush().unwrap(); + cached_sleep_secs(2).unwrap(); + println!("done"); + + use cached::IOCached; + CACHED_SLEEP_SECS.cache_remove(&2).unwrap(); + print!("third sync call with a 2 seconds sleep (slow, after cache-remove)..."); + io::stdout().flush().unwrap(); + cached_sleep_secs(2).unwrap(); + println!("done"); +} diff --git a/vendor/cached/examples/kitchen_sink.rs b/vendor/cached/examples/kitchen_sink.rs new file mode 100644 index 0000000000000..3dffb48aad605 --- /dev/null +++ b/vendor/cached/examples/kitchen_sink.rs @@ -0,0 +1,163 @@ +#[macro_use] +extern crate cached; + +use std::cmp::Eq; +use std::collections::HashMap; +use std::hash::Hash; + +use std::thread::sleep; +use std::time::Duration; + +use cached::{Cached, SizedCache, UnboundCache}; + +// cached shorthand, uses the default unbounded cache. +// Equivalent to specifying `FIB: UnboundCache<(u32), u32> = UnboundCache::new();` +cached! { + FIB; + fn fib(n: u32) -> u32 = { + if n == 0 || n == 1 { return n; } + fib(n-1) + fib(n-2) + } +} + +// Same as above, but preallocates some space. +// Note that the cache key type is a tuple of function argument types. +cached! { + FIB_SPECIFIC: UnboundCache = UnboundCache::with_capacity(50); + fn fib_specific(n: u32) -> u32 = { + if n == 0 || n == 1 { return n; } + fib_specific(n-1) + fib_specific(n-2) + } +} + +// Specify a specific cache type +// Note that the cache key type is a tuple of function argument types. +cached! { + SLOW: SizedCache<(u32, u32), u32> = SizedCache::with_size(100); + fn slow(a: u32, b: u32) -> u32 = { + sleep(Duration::new(2, 0)); + a * b + } +} + +// Specify a specific cache type and an explicit key expression +// Note that the cache key type is a `String` created from the borrow arguments +cached_key! { + KEYED: SizedCache = SizedCache::with_size(100); + Key = { format!("{a}{b}") }; + fn keyed(a: &str, b: &str) -> usize = { + let size = a.len() + b.len(); + sleep(Duration::new(size as u64, 0)); + size + } +} + +// Implement our own cache type +struct MyCache { + store: HashMap, + capacity: usize, +} +impl MyCache { + pub fn with_capacity(size: usize) -> MyCache { + MyCache { + store: HashMap::with_capacity(size), + capacity: size, + } + } +} +impl Cached for MyCache { + fn cache_get(&mut self, k: &Q) -> Option<&V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.store.get(k) + } + fn cache_get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.store.get_mut(k) + } + fn cache_get_or_set_with V>(&mut self, k: K, f: F) -> &mut V { + self.store.entry(k).or_insert_with(f) + } + fn cache_set(&mut self, k: K, v: V) -> Option { + self.store.insert(k, v) + } + fn cache_remove(&mut self, k: &Q) -> Option + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.store.remove(k) + } + fn cache_clear(&mut self) { + self.store.clear(); + } + fn cache_reset(&mut self) { + self.store = HashMap::with_capacity(self.capacity); + } + fn cache_size(&self) -> usize { + self.store.len() + } +} + +// Specify our custom cache and supply an instance to use +cached! { + CUSTOM: MyCache = MyCache::with_capacity(50); + fn custom(n: u32) -> () = { + if n == 0 { return; } + custom(n-1); + } +} + +pub fn main() { + println!("\n ** default cache **"); + fib(3); + fib(3); + { + let cache = FIB.lock().unwrap(); + println!("hits: {:?}", cache.cache_hits()); + println!("misses: {:?}", cache.cache_misses()); + // make sure lock is dropped + } + fib(10); + fib(10); + + println!("\n ** specific cache **"); + fib_specific(20); + fib_specific(20); + { + let cache = FIB_SPECIFIC.lock().unwrap(); + println!("hits: {:?}", cache.cache_hits()); + println!("misses: {:?}", cache.cache_misses()); + // make sure lock is dropped + } + fib_specific(20); + fib_specific(20); + + println!("\n ** custom cache **"); + custom(25); + { + let cache = CUSTOM.lock().unwrap(); + println!("hits: {:?}", cache.cache_hits()); + println!("misses: {:?}", cache.cache_misses()); + // make sure lock is dropped + } + + println!("\n ** slow func **"); + println!(" - first run `slow(10)`"); + slow(10, 10); + println!(" - second run `slow(10)`"); + slow(10, 10); + { + let cache = SLOW.lock().unwrap(); + println!("hits: {:?}", cache.cache_hits()); + println!("misses: {:?}", cache.cache_misses()); + // make sure the cache-lock is dropped + } + + println!("done!"); +} diff --git a/vendor/cached/examples/kitchen_sink_proc_macro.rs b/vendor/cached/examples/kitchen_sink_proc_macro.rs new file mode 100644 index 0000000000000..46ab3c3f08053 --- /dev/null +++ b/vendor/cached/examples/kitchen_sink_proc_macro.rs @@ -0,0 +1,369 @@ +use cached::proc_macro::cached; +use cached::Return; +use cached::{Cached, SizedCache, UnboundCache}; +use std::cmp::Eq; +use std::collections::HashMap; +use std::hash::Hash; +use std::thread::{sleep, spawn}; +use std::time::Duration; + +// cached shorthand, uses the default unbounded cache. +// Equivalent to specifying `type = "UnboundCache<(u32), u32>", create= "{ UnboundCache::new() }"` +#[cached] +fn fib(n: u32) -> u32 { + if n == 0 || n == 1 { + return n; + } + fib(n - 1) + fib(n - 2) +} + +#[cached(name = "FLIB")] +fn fib_2(n: u32) -> u32 { + if n == 0 || n == 1 { + return n; + } + fib(n - 1) + fib(n - 2) +} + +// Same as above, but preallocates some space. +#[cached( + type = "UnboundCache", + create = "{ UnboundCache::with_capacity(50) }" +)] +fn fib_specific(n: u32) -> u32 { + if n == 0 || n == 1 { + return n; + } + fib_specific(n - 1) + fib_specific(n - 2) +} + +// Specify a specific cache type +// Note that the cache key type is a tuple of function argument types. +#[cached( + type = "SizedCache<(u32, u32), u32>", + create = "{ SizedCache::with_size(100) }" +)] +fn slow(a: u32, b: u32) -> u32 { + sleep(Duration::new(2, 0)); + a * b +} + +// Specify a specific cache type and an explicit key expression +// Note that the cache key type is a `String` created from the borrow arguments +// Note that key is not used, convert requires either key or type to be set. +#[cached( + type = "SizedCache", + create = "{ SizedCache::with_size(100) }", + convert = r#"{ format!("{}{}", a, b) }"# +)] +fn keyed(a: &str, b: &str) -> usize { + let size = a.len() + b.len(); + sleep(Duration::new(size as u64, 0)); + size +} + +#[cached(key = "String", convert = r#"{ format!("{}{}", a, b) }"#)] +fn keyed_key(a: &str, b: &str) -> usize { + let size = a.len() + b.len(); + sleep(Duration::new(size as u64, 0)); + size +} + +// Implement our own cache type +struct MyCache { + store: HashMap, + capacity: usize, +} +impl MyCache { + pub fn with_capacity(size: usize) -> MyCache { + MyCache { + store: HashMap::with_capacity(size), + capacity: size, + } + } +} +impl Cached for MyCache { + fn cache_get(&mut self, k: &Q) -> Option<&V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.store.get(k) + } + fn cache_get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.store.get_mut(k) + } + fn cache_get_or_set_with V>(&mut self, k: K, f: F) -> &mut V { + self.store.entry(k).or_insert_with(f) + } + fn cache_set(&mut self, k: K, v: V) -> Option { + self.store.insert(k, v) + } + fn cache_remove(&mut self, k: &Q) -> Option + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.store.remove(k) + } + fn cache_clear(&mut self) { + self.store.clear(); + } + fn cache_reset(&mut self) { + self.store = HashMap::with_capacity(self.capacity); + } + fn cache_size(&self) -> usize { + self.store.len() + } +} + +// Specify our custom cache and supply an instance to use +#[cached(type = "MyCache", create = "{ MyCache::with_capacity(50) }")] +fn custom(n: u32) { + if n == 0 { + return; + } + custom(n - 1); +} + +// handle results, don't cache errors +#[cached(result = true)] +fn slow_result(a: u32, b: u32) -> Result { + sleep(Duration::new(2, 0)); + Ok(a * b) +} + +// return a flag indicated whether the result was cached +#[cached(with_cached_flag = true)] +fn with_cached_flag(a: String) -> Return { + sleep(Duration::new(1, 0)); + Return::new(a) +} + +// return a flag indicated whether the result was cached, with a result type +#[cached(result = true, with_cached_flag = true)] +fn with_cached_flag_result(a: String) -> Result, ()> { + sleep(Duration::new(1, 0)); + Ok(Return::new(a)) +} + +// return a flag indicated whether the result was cached, with an option type +#[cached(option = true, with_cached_flag = true)] +fn with_cached_flag_option(a: String) -> Option> { + sleep(Duration::new(1, 0)); + Some(Return::new(a)) +} + +// A simple cache that expires after a second. We'll keep the +// value fresh by priming it in a separate thread. +#[cached(time = 1)] +fn expires_for_priming(a: i32) -> i32 { + a +} + +// NOTE: +// The following fails with compilation error +// ``` +// error: +// When specifying `with_cached_flag = true`, the return type must be wrapped in `cached::Return`. +// The following return types are supported: +// | `cached::Return` +// | `std::result::Result, E>` +// | `std::option::Option>` +// Found type: std::result::Result. +// ``` +// +// #[cached(with_cached_flag = true)] +// fn with_cached_flag_requires_return_type(a: u32) -> std::result::Result { +// Ok(1) +// } + +pub fn main() { + println!("\n ** default cache with default name **"); + fib(3); + fib(3); + { + let cache = FIB.lock().unwrap(); + println!("hits: {:?}", cache.cache_hits()); + assert_eq!(cache.cache_hits().unwrap(), 2); + println!("misses: {:?}", cache.cache_misses()); + assert_eq!(cache.cache_misses(), Some(4)); + // make sure lock is dropped + } + fib(10); + fib(10); + + println!("\n ** default cache with explicit name **"); + fib_2(3); + fib_2(3); + { + let cache = FLIB.lock().unwrap(); + println!("hits: {:?}", cache.cache_hits()); + assert_eq!(cache.cache_hits().unwrap(), 1); + println!("misses: {:?}", cache.cache_misses()); + assert_eq!(cache.cache_misses(), Some(1)); + // make sure lock is dropped + } + + println!("\n ** specific cache **"); + fib_specific(20); + fib_specific(20); + { + let cache = FIB_SPECIFIC.lock().unwrap(); + println!("hits: {:?}", cache.cache_hits()); + assert_eq!(cache.cache_hits().unwrap(), 19); + println!("misses: {:?}", cache.cache_misses()); + assert_eq!(cache.cache_misses(), Some(21)); + // make sure lock is dropped + } + fib_specific(20); + fib_specific(20); + + println!("\n ** custom cache **"); + custom(25); + { + let cache = CUSTOM.lock().unwrap(); + println!("hits: {:?}", cache.cache_hits()); + assert_eq!(cache.cache_hits(), None); + println!("misses: {:?}", cache.cache_misses()); + assert_eq!(cache.cache_misses(), None); + //custom cache doesn't implement these so they're None + // make sure lock is dropped + } + + println!("\n ** slow func **"); + println!(" - first run `slow(10)`"); + slow(10, 10); + println!(" - second run `slow(10)`"); + slow(10, 10); + { + let cache = SLOW.lock().unwrap(); + println!("hits: {:?}", cache.cache_hits()); + assert_eq!(cache.cache_hits().unwrap(), 1); + println!("misses: {:?}", cache.cache_misses()); + assert_eq!(cache.cache_misses().unwrap(), 1); + // make sure the cache-lock is dropped + } + + println!("\n ** slow result func **"); + println!(" - first run `slow_result(10)`"); + let _ = slow_result(10, 10); + println!(" - second run `slow_result(10)`"); + let _ = slow_result(10, 10); + { + let cache = SLOW_RESULT.lock().unwrap(); + println!("hits: {:?}", cache.cache_hits()); + assert_eq!(cache.cache_hits().unwrap(), 1); + println!("misses: {:?}", cache.cache_misses()); + assert_eq!(cache.cache_misses(), Some(1)); + // make sure the cache-lock is dropped + } + + println!("\n ** with cached flag func **"); + println!(" - first run `with_cached_flag(\"a\")`"); + let r = with_cached_flag("a".to_string()); + println!("was cached: {}", r.was_cached); + println!(" - second run `with_cached_flag(\"a\")`"); + let r = with_cached_flag("a".to_string()); + println!("was cached: {}", r.was_cached); + println!("derefs to inner, *r == \"a\" : {}", *r == "a"); + println!( + "derefs to inner, r.as_str() == \"a\" : {}", + r.as_str() == "a" + ); + { + let cache = WITH_CACHED_FLAG.lock().unwrap(); + println!("hits: {:?}", cache.cache_hits()); + assert_eq!(cache.cache_hits().unwrap(), 1); + println!("misses: {:?}", cache.cache_misses()); + assert_eq!(cache.cache_misses(), Some(1)); + // make sure the cache-lock is dropped + } + + println!("\n ** with cached flag result func **"); + println!(" - first run `with_cached_flag_result(\"a\")`"); + let r = with_cached_flag_result("a".to_string()).expect("with_cached_flag_result failed"); + println!("was cached: {}", r.was_cached); + println!(" - second run `with_cached_flag_result(\"a\")`"); + let r = with_cached_flag_result("a".to_string()).expect("with_cached_flag_result failed"); + println!("was cached: {}", r.was_cached); + println!("derefs to inner, *r : {:?}", *r); + println!("derefs to inner, *r == \"a\" : {}", *r == "a"); + println!( + "derefs to inner, r.as_str() == \"a\" : {}", + r.as_str() == "a" + ); + { + let cache = WITH_CACHED_FLAG_RESULT.lock().unwrap(); + println!("hits: {:?}", cache.cache_hits()); + assert_eq!(cache.cache_hits().unwrap(), 1); + println!("misses: {:?}", cache.cache_misses()); + assert_eq!(cache.cache_misses(), Some(1)); + // make sure the cache-lock is dropped + } + + println!("\n ** with cached flag option func **"); + println!(" - first run `with_cached_flag_option(\"a\")`"); + let r = with_cached_flag_option("a".to_string()).expect("with_cached_flag_result failed"); + println!("was cached: {}", r.was_cached); + println!(" - second run `with_cached_flag_option(\"a\")`"); + let r = with_cached_flag_option("a".to_string()).expect("with_cached_flag_result failed"); + println!("was cached: {}", r.was_cached); + println!("derefs to inner, *r : {:?}", *r); + println!("derefs to inner, *r == \"a\" : {}", *r == "a"); + println!( + "derefs to inner, r.as_str() == \"a\" : {}", + r.as_str() == "a" + ); + { + let cache = WITH_CACHED_FLAG_OPTION.lock().unwrap(); + println!("hits: {:?}", cache.cache_hits()); + assert_eq!(cache.cache_hits().unwrap(), 1); + println!("misses: {:?}", cache.cache_misses()); + assert_eq!(cache.cache_misses(), Some(1)); + // make sure the cache-lock is dropped + } + + println!("\n ** refresh by priming **"); + let h = spawn(|| { + for _ in 1..6 { + expires_for_priming_prime_cache(1); + sleep(Duration::from_millis(500)); + } + }); + sleep(Duration::from_millis(200)); + for n in 1..6 { + assert_eq!(1, expires_for_priming(1)); + { + let c = EXPIRES_FOR_PRIMING.lock().unwrap(); + assert_eq!(n, c.cache_hits().unwrap()); + assert_eq!(0, c.cache_misses().unwrap()); + println!( + "primed cache hits: {}, misses: {}", + c.cache_hits().unwrap(), + c.cache_misses().unwrap() + ); + } + sleep(Duration::from_millis(500)); + } + h.join().unwrap(); + println!("now wait for expiration"); + sleep(Duration::from_millis(1000)); + assert_eq!(1, expires_for_priming(1)); + { + let c = EXPIRES_FOR_PRIMING.lock().unwrap(); + assert_eq!(5, c.cache_hits().unwrap()); + assert_eq!(1, c.cache_misses().unwrap()); + println!( + "primed cache hits: {}, misses: {}", + c.cache_hits().unwrap(), + c.cache_misses().unwrap() + ); + } + + println!("\ndone!"); +} diff --git a/vendor/cached/examples/redis-async.rs b/vendor/cached/examples/redis-async.rs new file mode 100644 index 0000000000000..ffd6d8cf44e2e --- /dev/null +++ b/vendor/cached/examples/redis-async.rs @@ -0,0 +1,112 @@ +/* +Start a redis docker image if you don't already have it running locally: + docker run --rm --name async-cached-redis-example -p 6379:6379 -d redis +Set the required env variable and run this example and run with required features: + CACHED_REDIS_CONNECTION_STRING=redis://127.0.0.1:6379 cargo run --example redis-async --features "async redis_store redis_tokio" +Cleanup the redis docker container: + docker rm -f async-cached-redis-example + */ + +use cached::proc_macro::io_cached; +use cached::AsyncRedisCache; +use once_cell::sync::Lazy; +use std::io; +use std::io::Write; +use std::time::Duration; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq, Clone)] +enum ExampleError { + #[error("error with redis cache `{0}`")] + RedisError(String), +} + +// When the macro constructs your RedisCache instance, the connection string +// will be pulled from the env var: `CACHED_REDIS_CONNECTION_STRING`; +#[io_cached( + redis = true, + time = 30, + cache_prefix_block = r##"{ "cache-redis-example-1" }"##, + map_error = r##"|e| ExampleError::RedisError(format!("{:?}", e))"## +)] +async fn cached_sleep_secs(secs: u64) -> Result<(), ExampleError> { + std::thread::sleep(Duration::from_secs(secs)); + Ok(()) +} + +#[io_cached( + map_error = r##"|e| ExampleError::RedisError(format!("{:?}", e))"##, + type = "cached::AsyncRedisCache", + create = r##" { + AsyncRedisCache::new("cache_redis_example_cached_sleep_secs", 1) + .set_refresh(true) + .build() + .await + .expect("error building example redis cache") + } "## +)] +async fn async_cached_sleep_secs(secs: u64) -> Result { + std::thread::sleep(Duration::from_secs(secs)); + Ok(secs.to_string()) +} + +struct Config { + conn_str: String, +} +impl Config { + fn load() -> Self { + Self { + conn_str: std::env::var("CACHED_REDIS_CONNECTION_STRING").unwrap(), + } + } +} + +static CONFIG: Lazy = Lazy::new(Config::load); + +#[io_cached( + map_error = r##"|e| ExampleError::RedisError(format!("{:?}", e))"##, + type = "cached::AsyncRedisCache", + create = r##" { + AsyncRedisCache::new("cache_redis_example_cached_sleep_secs_config", 1) + .set_refresh(true) + .set_connection_string(&CONFIG.conn_str) + .build() + .await + .expect("error building example redis cache") + } "## +)] +async fn async_cached_sleep_secs_config(secs: u64) -> Result { + std::thread::sleep(Duration::from_secs(secs)); + Ok(secs.to_string()) +} + +#[tokio::main] +async fn main() { + print!("1. first sync call with a 2 seconds sleep..."); + io::stdout().flush().unwrap(); + cached_sleep_secs(2).await.unwrap(); + println!("done"); + print!("second sync call with a 2 seconds sleep (it should be fast)..."); + io::stdout().flush().unwrap(); + cached_sleep_secs(2).await.unwrap(); + println!("done"); + + print!("2. first async call with a 2 seconds sleep..."); + io::stdout().flush().unwrap(); + async_cached_sleep_secs(2).await.unwrap(); + println!("done"); + print!("second async call with a 2 seconds sleep (it should be fast)..."); + io::stdout().flush().unwrap(); + async_cached_sleep_secs(2).await.unwrap(); + println!("done"); + + async_cached_sleep_secs_config_prime_cache(2).await.unwrap(); + print!("3. first primed async call with a 2 seconds sleep (should be fast)..."); + io::stdout().flush().unwrap(); + async_cached_sleep_secs_config(2).await.unwrap(); + println!("done"); + print!("second async call with a 2 seconds sleep (it should be fast)..."); + io::stdout().flush().unwrap(); + async_cached_sleep_secs_config(2).await.unwrap(); + println!("done"); +} diff --git a/vendor/cached/examples/redis.rs b/vendor/cached/examples/redis.rs new file mode 100644 index 0000000000000..278366e83efda --- /dev/null +++ b/vendor/cached/examples/redis.rs @@ -0,0 +1,114 @@ +/* +Start a redis docker image if you don't already have it running locally: + docker run --rm --name cached-redis-example -p 6379:6379 -d redis +Set the required env variable and run this example and run with required features: + CACHED_REDIS_CONNECTION_STRING=redis://127.0.0.1:6379 cargo run --example redis --features "redis_store" +Cleanup the redis docker container: + docker rm -f cached-redis-example + */ + +use cached::proc_macro::io_cached; +use cached::RedisCache; +use once_cell::sync::Lazy; +use std::io; +use std::io::Write; +use std::time::Duration; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq, Clone)] +enum ExampleError { + #[error("error with redis cache `{0}`")] + RedisError(String), +} + +// When the macro constructs your RedisCache instance, the connection string +// will be pulled from the env var: `CACHED_REDIS_CONNECTION_STRING`; +#[io_cached( + redis = true, + time = 30, + cache_prefix_block = r##"{ "cache-redis-example-1" }"##, + map_error = r##"|e| ExampleError::RedisError(format!("{:?}", e))"## +)] +fn cached_sleep_secs(secs: u64) -> Result<(), ExampleError> { + std::thread::sleep(Duration::from_secs(secs)); + Ok(()) +} + +// If not `cache_prefix_block` is specified, then the function name +// is used to create a prefix for cache keys used by this function +#[io_cached( + redis = true, + time = 30, + map_error = r##"|e| ExampleError::RedisError(format!("{:?}", e))"## +)] +fn cached_sleep_secs_example_2(secs: u64) -> Result<(), ExampleError> { + std::thread::sleep(Duration::from_secs(secs)); + Ok(()) +} + +struct Config { + conn_str: String, +} +impl Config { + fn load() -> Self { + Self { + conn_str: std::env::var("CACHED_REDIS_CONNECTION_STRING").unwrap(), + } + } +} + +static CONFIG: Lazy = Lazy::new(Config::load); + +#[io_cached( + map_error = r##"|e| ExampleError::RedisError(format!("{:?}", e))"##, + type = "cached::RedisCache", + create = r##" { + RedisCache::new("cache_redis_example_cached_sleep_secs_config", 1) + .set_refresh(true) + .set_connection_string(&CONFIG.conn_str) + .build() + .expect("error building example redis cache") + } "## +)] +fn cached_sleep_secs_config(secs: u64) -> Result { + std::thread::sleep(Duration::from_secs(secs)); + Ok(secs.to_string()) +} + +#[tokio::main] +async fn main() { + print!("1. first sync call with a 2 seconds sleep..."); + io::stdout().flush().unwrap(); + cached_sleep_secs(2).unwrap(); + println!("done"); + print!("second sync call with a 2 seconds sleep (it should be fast)..."); + io::stdout().flush().unwrap(); + cached_sleep_secs(2).unwrap(); + println!("done"); + + use cached::IOCached; + CACHED_SLEEP_SECS.cache_remove(&2).unwrap(); + print!("third sync call with a 2 seconds sleep (slow, after cache-remove)..."); + io::stdout().flush().unwrap(); + cached_sleep_secs(2).unwrap(); + println!("done"); + + print!("2. first sync call with a 2 seconds sleep..."); + io::stdout().flush().unwrap(); + cached_sleep_secs_example_2(2).unwrap(); + println!("done"); + print!("second sync call with a 2 seconds sleep (it should be fast)..."); + io::stdout().flush().unwrap(); + cached_sleep_secs_example_2(2).unwrap(); + println!("done"); + + cached_sleep_secs_config_prime_cache(2).unwrap(); + print!("3. first primed async call with a 2 seconds sleep (should be fast)..."); + io::stdout().flush().unwrap(); + cached_sleep_secs_config(2).unwrap(); + println!("done"); + print!("second async call with a 2 seconds sleep (it should be fast)..."); + io::stdout().flush().unwrap(); + cached_sleep_secs_config(2).unwrap(); + println!("done"); +} diff --git a/vendor/cached/examples/tokio.rs b/vendor/cached/examples/tokio.rs new file mode 100644 index 0000000000000..73cedb88f82bf --- /dev/null +++ b/vendor/cached/examples/tokio.rs @@ -0,0 +1,37 @@ +use cached::proc_macro::cached; +use std::time::Duration; +use tokio::time::sleep; + +async fn sleep_secs(secs: u64) { + sleep(Duration::from_secs(secs)).await; +} + +#[cached] +async fn cached_sleep_secs(secs: u64) { + sleep(Duration::from_secs(secs)).await; +} + +#[cached(result = true, with_cached_flag = true)] +async fn cached_was_cached(count: u32) -> Result, ()> { + Ok(cached::Return::new( + (0..count).map(|_| "a").collect::>().join(""), + )) +} + +#[tokio::main] +async fn main() { + println!("sleeping for 4 seconds"); + sleep_secs(4).await; + println!("first cached sleeping for 4 seconds"); + cached_sleep_secs(4).await; + println!("second cached sleeping for 4 seconds"); + cached_sleep_secs(4).await; + + let a = cached_was_cached(4).await.unwrap(); + assert_eq!(a.to_uppercase(), "AAAA"); + assert!(!a.was_cached); + let a = cached_was_cached(4).await.unwrap(); + assert!(a.was_cached); + + println!("done!"); +} diff --git a/vendor/cached/src/lib.rs b/vendor/cached/src/lib.rs new file mode 100644 index 0000000000000..fa49324e375f6 --- /dev/null +++ b/vendor/cached/src/lib.rs @@ -0,0 +1,451 @@ +/*! +[![Build Status](https://github.com/jaemk/cached/actions/workflows/build.yml/badge.svg)](https://github.com/jaemk/cached/actions/workflows/build.yml) +[![crates.io](https://img.shields.io/crates/v/cached.svg)](https://crates.io/crates/cached) +[![docs](https://docs.rs/cached/badge.svg)](https://docs.rs/cached) + +> Caching structures and simplified function memoization + +`cached` provides implementations of several caching structures as well as a handy macros +for defining memoized functions. + +Memoized functions defined using [`#[cached]`](proc_macro::cached)/[`#[once]`](proc_macro::once)/[`#[io_cached]`](proc_macro::io_cached)/[`cached!`](crate::macros) macros are thread-safe with the backing +function-cache wrapped in a mutex/rwlock, or externally synchronized in the case of `#[io_cached]`. +By default, the function-cache is **not** locked for the duration of the function's execution, so initial (on an empty cache) +concurrent calls of long-running functions with the same arguments will each execute fully and each overwrite +the memoized value as they complete. This mirrors the behavior of Python's `functools.lru_cache`. To synchronize the execution and caching +of un-cached arguments, specify `#[cached(sync_writes = true)]` / `#[once(sync_writes = true)]` (not supported by `#[io_cached]`. + +- See [`cached::stores` docs](https://docs.rs/cached/latest/cached/stores/index.html) cache stores available. +- See [`proc_macro`](https://docs.rs/cached/latest/cached/proc_macro/index.html) for more procedural macro examples. +- See [`macros`](https://docs.rs/cached/latest/cached/macros/index.html) for more declarative macro examples. + +**Features** + +- `default`: Include `proc_macro` and `ahash` features +- `proc_macro`: Include proc macros +- `ahash`: Enable the optional `ahash` hasher as default hashing algorithm. +- `async`: Include support for async functions and async cache stores +- `async_tokio_rt_multi_thread`: Enable `tokio`'s optional `rt-multi-thread` feature. +- `redis_store`: Include Redis cache store +- `redis_async_std`: Include async Redis support using `async-std` and `async-std` tls support, implies `redis_store` and `async` +- `redis_tokio`: Include async Redis support using `tokio` and `tokio` tls support, implies `redis_store` and `async` +- `redis_connection_manager`: Enable the optional `connection-manager` feature of `redis`. Any async redis caches created + will use a connection manager instead of a `MultiplexedConnection` +- `redis_ahash`: Enable the optional `ahash` feature of `redis` +- `disk_store`: Include disk cache store +- `wasm`: Enable WASM support. Note that this feature is incompatible with `tokio`'s multi-thread + runtime (`async_tokio_rt_multi_thread`) and all Redis features (`redis_store`, `redis_async_std`, `redis_tokio`, `redis_ahash`) + +The procedural macros (`#[cached]`, `#[once]`, `#[io_cached]`) offer more features, including async support. +See the [`proc_macro`](crate::proc_macro) and [`macros`](crate::macros) modules for more samples, and the +[`examples`](https://github.com/jaemk/cached/tree/master/examples) directory for runnable snippets. + +Any custom cache that implements `cached::Cached`/`cached::CachedAsync` can be used with the `#[cached]`/`#[once]`/`cached!` macros in place of the built-ins. +Any custom cache that implements `cached::IOCached`/`cached::IOCachedAsync` can be used with the `#[io_cached]` macro. + +---- + +The basic usage looks like: + +```rust,no_run +use cached::proc_macro::cached; + +/// Defines a function named `fib` that uses a cache implicitly named `FIB`. +/// By default, the cache will be the function's name in all caps. +/// The following line is equivalent to #[cached(name = "FIB", unbound)] +#[cached] +fn fib(n: u64) -> u64 { + if n == 0 || n == 1 { return n } + fib(n-1) + fib(n-2) +} +# pub fn main() { } +``` + +---- + +```rust,no_run +use std::thread::sleep; +use std::time::Duration; +use cached::proc_macro::cached; +use cached::SizedCache; + +/// Use an explicit cache-type with a custom creation block and custom cache-key generating block +#[cached( + type = "SizedCache", + create = "{ SizedCache::with_size(100) }", + convert = r#"{ format!("{}{}", a, b) }"# +)] +fn keyed(a: &str, b: &str) -> usize { + let size = a.len() + b.len(); + sleep(Duration::new(size as u64, 0)); + size +} +# pub fn main() { } +``` + +---- + +```rust,no_run +use cached::proc_macro::once; + +/// Only cache the initial function call. +/// Function will be re-executed after the cache +/// expires (according to `time` seconds). +/// When no (or expired) cache, concurrent calls +/// will synchronize (`sync_writes`) so the function +/// is only executed once. +#[once(time=10, option = true, sync_writes = true)] +fn keyed(a: String) -> Option { + if a == "a" { + Some(a.len()) + } else { + None + } +} +# pub fn main() { } +``` + +---- + +```rust,no_run,ignore +use cached::proc_macro::io_cached; +use cached::AsyncRedisCache; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq, Clone)] +enum ExampleError { + #[error("error with redis cache `{0}`")] + RedisError(String), +} + +/// Cache the results of an async function in redis. Cache +/// keys will be prefixed with `cache_redis_prefix`. +/// A `map_error` closure must be specified to convert any +/// redis cache errors into the same type of error returned +/// by your function. All `io_cached` functions must return `Result`s. +#[io_cached( + map_error = r##"|e| ExampleError::RedisError(format!("{:?}", e))"##, + type = "AsyncRedisCache", + create = r##" { + AsyncRedisCache::new("cached_redis_prefix", 1) + .set_refresh(true) + .build() + .await + .expect("error building example redis cache") + } "## +)] +async fn async_cached_sleep_secs(secs: u64) -> Result { + std::thread::sleep(std::time::Duration::from_secs(secs)); + Ok(secs.to_string()) +} +``` + +---- + +```rust,no_run,ignore +use cached::proc_macro::io_cached; +use cached::DiskCache; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq, Clone)] +enum ExampleError { + #[error("error with disk cache `{0}`")] + DiskError(String), +} + +/// Cache the results of a function on disk. +/// Cache files will be stored under the system cache dir +/// unless otherwise specified with `disk_dir` or the `create` argument. +/// A `map_error` closure must be specified to convert any +/// disk cache errors into the same type of error returned +/// by your function. All `io_cached` functions must return `Result`s. +#[io_cached( + map_error = r##"|e| ExampleError::DiskError(format!("{:?}", e))"##, + disk = true +)] +fn cached_sleep_secs(secs: u64) -> Result { + std::thread::sleep(std::time::Duration::from_secs(secs)); + Ok(secs.to_string()) +} +``` + + +Functions defined via macros will have their results cached using the +function's arguments as a key, a `convert` expression specified on a procedural macros, +or a `Key` block specified on a `cached_key!` declarative macro. + +When a macro-defined function is called, the function's cache is first checked for an already +computed (and still valid) value before evaluating the function body. + +Due to the requirements of storing arguments and return values in a global cache: + +- Function return types: + - For all store types, except Redis, must be owned and implement `Clone` + - For the Redis store type, must be owned and implement `serde::Serialize + serde::DeserializeOwned` +- Function arguments: + - For all store types, except Redis, must either be owned and implement `Hash + Eq + Clone`, + the `cached_key!` macro is used with a `Key` block specifying key construction, or + a `convert` expression is specified on a procedural macro to specify how to construct a key + of a `Hash + Eq + Clone` type. + - For the Redis store type, must either be owned and implement `Display`, or the `cached_key!` & `Key` + or procedural macro & `convert` expression used to specify how to construct a key of a `Display` type. +- Arguments and return values will be `cloned` in the process of insertion and retrieval. Except for Redis + where arguments are formatted into `Strings` and values are de/serialized. +- Macro-defined functions should not be used to produce side-effectual results! +- Macro-defined functions cannot live directly under `impl` blocks since macros expand to a + `once_cell` initialization and one or more function definitions. +- Macro-defined functions cannot accept `Self` types as a parameter. + + +*/ + +#![cfg_attr(docsrs, feature(doc_cfg))] + +#[doc(hidden)] +pub extern crate once_cell; + +#[cfg(feature = "proc_macro")] +#[cfg_attr(docsrs, doc(cfg(feature = "proc_macro")))] +pub use proc_macro::Return; +#[cfg(any(feature = "redis_async_std", feature = "redis_tokio"))] +#[cfg_attr( + docsrs, + doc(cfg(any(feature = "redis_async_std", feature = "redis_tokio"))) +)] +pub use stores::AsyncRedisCache; +pub use stores::{ + CanExpire, ExpiringValueCache, SizedCache, TimedCache, TimedSizedCache, UnboundCache, +}; +#[cfg(feature = "disk_store")] +#[cfg_attr(docsrs, doc(cfg(feature = "disk_store")))] +pub use stores::{DiskCache, DiskCacheError}; +#[cfg(feature = "redis_store")] +#[cfg_attr(docsrs, doc(cfg(feature = "redis_store")))] +pub use stores::{RedisCache, RedisCacheError}; +#[cfg(feature = "async")] +#[cfg_attr(docsrs, doc(cfg(feature = "async")))] +use {async_trait::async_trait, futures::Future}; + +mod lru_list; +pub mod macros; +#[cfg(feature = "proc_macro")] +pub mod proc_macro; +pub mod stores; +#[doc(hidden)] +pub use instant; + +#[cfg(feature = "async")] +#[doc(hidden)] +pub mod async_sync { + pub use tokio::sync::Mutex; + pub use tokio::sync::OnceCell; + pub use tokio::sync::RwLock; +} + +/// Cache operations +/// +/// ```rust +/// use cached::{Cached, UnboundCache}; +/// +/// let mut cache: UnboundCache = UnboundCache::new(); +/// +/// // When writing, keys and values are owned: +/// cache.cache_set("key".to_string(), "owned value".to_string()); +/// +/// // When reading, keys are only borrowed for lookup: +/// let borrowed_cache_value = cache.cache_get("key"); +/// +/// assert_eq!(borrowed_cache_value, Some(&"owned value".to_string())) +/// ``` +pub trait Cached { + /// Attempt to retrieve a cached value + /// + /// ```rust + /// # use cached::{Cached, UnboundCache}; + /// # let mut cache: UnboundCache = UnboundCache::new(); + /// # cache.cache_set("key".to_string(), "owned value".to_string()); + /// // You can use borrowed data, or the data's borrowed type: + /// let borrow_lookup_1 = cache.cache_get("key") + /// .map(String::clone); + /// let borrow_lookup_2 = cache.cache_get(&"key".to_string()) + /// .map(String::clone); // copy the values for test asserts + /// + /// # assert_eq!(borrow_lookup_1, borrow_lookup_2); + /// ``` + fn cache_get(&mut self, k: &Q) -> Option<&V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized; + + /// Attempt to retrieve a cached value with mutable access + /// + /// ```rust + /// # use cached::{Cached, UnboundCache}; + /// # let mut cache: UnboundCache = UnboundCache::new(); + /// # cache.cache_set("key".to_string(), "owned value".to_string()); + /// // You can use borrowed data, or the data's borrowed type: + /// let borrow_lookup_1 = cache.cache_get_mut("key") + /// .map(|value| value.clone()); + /// let borrow_lookup_2 = cache.cache_get_mut(&"key".to_string()) + /// .map(|value| value.clone()); // copy the values for test asserts + /// + /// # assert_eq!(borrow_lookup_1, borrow_lookup_2); + /// ``` + fn cache_get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized; + + /// Insert a key, value pair and return the previous value + fn cache_set(&mut self, k: K, v: V) -> Option; + + /// Get or insert a key, value pair + fn cache_get_or_set_with V>(&mut self, k: K, f: F) -> &mut V; + + /// Remove a cached value + /// + /// ```rust + /// # use cached::{Cached, UnboundCache}; + /// # let mut cache: UnboundCache = UnboundCache::new(); + /// # cache.cache_set("key1".to_string(), "owned value 1".to_string()); + /// # cache.cache_set("key2".to_string(), "owned value 2".to_string()); + /// // You can use borrowed data, or the data's borrowed type: + /// let remove_1 = cache.cache_remove("key1"); + /// let remove_2 = cache.cache_remove(&"key2".to_string()); + /// + /// # assert_eq!(remove_1, Some("owned value 1".to_string())); + /// # assert_eq!(remove_2, Some("owned value 2".to_string())); + /// ``` + fn cache_remove(&mut self, k: &Q) -> Option + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized; + + /// Remove all cached values. Keeps the allocated memory for reuse. + fn cache_clear(&mut self); + + /// Remove all cached values. Free memory and return to initial state + fn cache_reset(&mut self); + + /// Reset misses/hits counters + fn cache_reset_metrics(&mut self) {} + + /// Return the current cache size (number of elements) + fn cache_size(&self) -> usize; + + /// Return the number of times a cached value was successfully retrieved + fn cache_hits(&self) -> Option { + None + } + + /// Return the number of times a cached value was unable to be retrieved + fn cache_misses(&self) -> Option { + None + } + + /// Return the cache capacity + fn cache_capacity(&self) -> Option { + None + } + + /// Return the lifespan of cached values (time to eviction) + fn cache_lifespan(&self) -> Option { + None + } + + /// Set the lifespan of cached values, returns the old value + fn cache_set_lifespan(&mut self, _seconds: u64) -> Option { + None + } +} + +/// Extra cache operations for types that implement `Clone` +pub trait CloneCached { + /// Attempt to retrieve a cached value and indicate whether that value was evicted. + fn cache_get_expired(&mut self, _key: &Q) -> (Option, bool) + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized; +} + +#[cfg(feature = "async")] +#[cfg_attr(docsrs, doc(cfg(feature = "async")))] +#[async_trait] +pub trait CachedAsync { + async fn get_or_set_with(&mut self, k: K, f: F) -> &mut V + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future + Send; + + async fn try_get_or_set_with(&mut self, k: K, f: F) -> Result<&mut V, E> + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future> + Send; +} + +/// Cache operations on an io-connected store +pub trait IOCached { + type Error; + + /// Attempt to retrieve a cached value + /// + /// # Errors + /// + /// Should return `Self::Error` if the operation fails + fn cache_get(&self, k: &K) -> Result, Self::Error>; + + /// Insert a key, value pair and return the previous value + /// + /// # Errors + /// + /// Should return `Self::Error` if the operation fails + fn cache_set(&self, k: K, v: V) -> Result, Self::Error>; + + /// Remove a cached value + /// + /// # Errors + /// + /// Should return `Self::Error` if the operation fails + fn cache_remove(&self, k: &K) -> Result, Self::Error>; + + /// Set the flag to control whether cache hits refresh the ttl of cached values, returns the old flag value + fn cache_set_refresh(&mut self, refresh: bool) -> bool; + + /// Return the lifespan of cached values (time to eviction) + fn cache_lifespan(&self) -> Option { + None + } + + /// Set the lifespan of cached values, returns the old value + fn cache_set_lifespan(&mut self, _seconds: u64) -> Option { + None + } +} + +#[cfg(feature = "async")] +#[cfg_attr(docsrs, doc(cfg(feature = "async")))] +#[async_trait] +pub trait IOCachedAsync { + type Error; + async fn cache_get(&self, k: &K) -> Result, Self::Error>; + + async fn cache_set(&self, k: K, v: V) -> Result, Self::Error>; + + /// Remove a cached value + async fn cache_remove(&self, k: &K) -> Result, Self::Error>; + + /// Set the flag to control whether cache hits refresh the ttl of cached values, returns the old flag value + fn cache_set_refresh(&mut self, refresh: bool) -> bool; + + /// Return the lifespan of cached values (time to eviction) + fn cache_lifespan(&self) -> Option { + None + } + + /// Set the lifespan of cached values, returns the old value + fn cache_set_lifespan(&mut self, _seconds: u64) -> Option { + None + } +} diff --git a/vendor/cached/src/lru_list.rs b/vendor/cached/src/lru_list.rs new file mode 100644 index 0000000000000..13fd1105f2d53 --- /dev/null +++ b/vendor/cached/src/lru_list.rs @@ -0,0 +1,136 @@ +/// Limited functionality doubly linked list using Vec as storage. +#[derive(Clone, Debug)] + +pub struct LRUList { + values: Vec>, +} + +#[derive(Clone, Debug)] +struct ListEntry { + value: Option, + next: usize, + prev: usize, +} + +/// Free and occupied cells are each linked into a cyclic list with one auxiliary cell. +/// Cell #0 is on the list of free cells, element #1 is on the list of occupied cells. +/// +impl LRUList { + const FREE: usize = 0; + const OCCUPIED: usize = 1; + + pub(crate) fn with_capacity(capacity: usize) -> LRUList { + let mut values = Vec::with_capacity(capacity + 2); + values.push(ListEntry:: { + value: None, + next: 0, + prev: 0, + }); + values.push(ListEntry:: { + value: None, + next: 1, + prev: 1, + }); + LRUList { values } + } + + pub(crate) fn unlink(&mut self, index: usize) { + let prev = self.values[index].prev; + let next = self.values[index].next; + self.values[prev].next = next; + self.values[next].prev = prev; + } + + pub(crate) fn link_after(&mut self, index: usize, prev: usize) { + let next = self.values[prev].next; + self.values[index].prev = prev; + self.values[index].next = next; + self.values[prev].next = index; + self.values[next].prev = index; + } + + pub(crate) fn move_to_front(&mut self, index: usize) { + self.unlink(index); + self.link_after(index, Self::OCCUPIED); + } + + pub(crate) fn push_front(&mut self, value: T) -> usize { + if self.values[Self::FREE].next == Self::FREE { + self.values.push(ListEntry:: { + value: None, + next: Self::FREE, + prev: Self::FREE, + }); + self.values[Self::FREE].next = self.values.len() - 1; + } + let index = self.values[Self::FREE].next; + self.values[index].value = Some(value); + self.unlink(index); + self.link_after(index, Self::OCCUPIED); + index + } + + pub(crate) fn remove(&mut self, index: usize) -> T { + self.unlink(index); + self.link_after(index, Self::FREE); + self.values[index].value.take().expect("invalid index") + } + + pub(crate) fn back(&self) -> usize { + self.values[Self::OCCUPIED].prev + } + + pub(crate) fn get(&self, index: usize) -> &T { + self.values[index].value.as_ref().expect("invalid index") + } + + pub(crate) fn get_mut(&mut self, index: usize) -> &mut T { + self.values[index].value.as_mut().expect("invalid index") + } + + pub(crate) fn set(&mut self, index: usize, value: T) -> Option { + self.values[index].value.replace(value) + } + + pub(crate) fn clear(&mut self) { + self.values.clear(); + self.values.push(ListEntry:: { + value: None, + next: 0, + prev: 0, + }); + self.values.push(ListEntry:: { + value: None, + next: 1, + prev: 1, + }); + } + + pub fn iter(&self) -> LRUListIterator { + LRUListIterator:: { + list: self, + index: Self::OCCUPIED, + } + } +} + +#[derive(Debug)] +pub struct LRUListIterator<'a, T> { + list: &'a LRUList, + index: usize, +} + +impl<'a, T> Iterator for LRUListIterator<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + let next = self.list.values[self.index].next; + if next == LRUList::::OCCUPIED { + None + } else { + let value = self.list.values[next].value.as_ref(); + self.index = next; + value + } + } +} diff --git a/vendor/cached/src/macros.rs b/vendor/cached/src/macros.rs new file mode 100644 index 0000000000000..d0ff75817c2c1 --- /dev/null +++ b/vendor/cached/src/macros.rs @@ -0,0 +1,497 @@ +/*! +Declarative macros for defining functions that wrap a static-ref cache object. + +### `cached!` and `cached_key!` Usage & Options: + +There are several options depending on how explicit you want to be. See below for a full syntax breakdown. + + +1.) Using the shorthand will use an unbounded cache. + + +```rust,no_run +#[macro_use] extern crate cached; + +/// Defines a function named `fib` that uses a cache named `FIB` +cached!{ + FIB; + fn fib(n: u64) -> u64 = { + if n == 0 || n == 1 { return n } + fib(n-1) + fib(n-2) + } +} +# pub fn main() { } +``` + + +2.) Using the full syntax requires specifying the full cache type and providing + an instance of the cache to use. Note that the cache's key-type is a tuple + of the function argument types. If you would like fine grained control over + the key, you can use the `cached_key!` macro. + The following example uses a `SizedCache` (LRU): + +```rust,no_run +#[macro_use] extern crate cached; + +use std::thread::sleep; +use std::time::Duration; +use cached::SizedCache; + +/// Defines a function `compute` that uses an LRU cache named `COMPUTE` which has a +/// size limit of 50 items. The `cached!` macro will implicitly combine +/// the function arguments into a tuple to be used as the cache key. +cached!{ + COMPUTE: SizedCache<(u64, u64), u64> = SizedCache::with_size(50); + fn compute(a: u64, b: u64) -> u64 = { + sleep(Duration::new(2, 0)); + return a * b; + } +} +# pub fn main() { } +``` + + +3.) The `cached_key` macro functions identically, but allows you to define the + cache key as an expression. + +```rust,no_run +#[macro_use] extern crate cached; + +use std::thread::sleep; +use std::time::Duration; +use cached::SizedCache; + +/// Defines a function named `length` that uses an LRU cache named `LENGTH`. +/// The `Key = ` expression is used to explicitly define the value that +/// should be used as the cache key. Here the borrowed arguments are converted +/// to an owned string that can be stored in the global function cache. +cached_key!{ + LENGTH: SizedCache = SizedCache::with_size(50); + Key = { format!("{}{}", a, b) }; + fn length(a: &str, b: &str) -> usize = { + let size = a.len() + b.len(); + sleep(Duration::new(size as u64, 0)); + size + } +} +# pub fn main() { } +``` + +4.) The `cached_result` and `cached_key_result` macros function similarly to `cached` + and `cached_key` respectively but the cached function needs to return `Result` + (or some type alias like `io::Result`). If the function returns `Ok(val)` then `val` + is cached, but errors are not. Note that only the success type needs to implement + `Clone`, _not_ the error type. When using `cached_result` and `cached_key_result`, + the cache type cannot be derived and must always be explicitly specified. + +```rust,no_run +#[macro_use] extern crate cached; + +use cached::UnboundCache; + +/// Cache the successes of a function. +/// To use `cached_key_result` add a key function as in `cached_key`. +cached_result!{ + MULT: UnboundCache<(u64, u64), u64> = UnboundCache::new(); // Type must always be specified + fn mult(a: u64, b: u64) -> Result = { + if a == 0 || b == 0 { + return Err(()); + } else { + return Ok(a * b); + } + } +} +# pub fn main() { } +``` + +---- + +```rust,ignore +#[macro_use] extern crate cached; +use std::thread::sleep; +use std::time::Duration; +use cached::RedisCache; + +cached! { + UNBOUND_REDIS: RedisCache = RedisCache::new(); + fn cached_redis(n: u32) -> u32 = { + sleep(Duration::new(3, 0)); + n + } +} + +cached! { + TIMED_REDIS: RedisCache = RedisCache::with_lifespan(2); + fn cached_timed_redis(n: u32) -> u32 = { + sleep(Duration::new(3, 0)); + n + } +} +# pub fn main() { } +``` + + +---- + +## Syntax + +The common macro syntax is: + + +```rust,ignore +cached_key!{ + CACHE_NAME: CacheType = CacheInstance; + Key = KeyExpression; + fn func_name(arg1: arg_type, arg2: arg_type) -> return_type = { + // do stuff like normal + return_type + } +} +``` + +Where: + +- `CACHE_NAME` is the unique name used to hold a `static ref` to the cache +- `CacheType` is the full type of the cache +- `CacheInstance` is any expression that yields an instance of `CacheType` to be used + as the cache-store, followed by `;` +- When using the `cached_key!` macro, the "Key" line must be specified. This line must start with + the literal tokens `Key = `, followed by an expression that evaluates to the key, followed by `;` +- `fn func_name(arg1: arg_type) -> return_type` is the same form as a regular function signature, with the exception + that functions with no return value must be explicitly stated (e.g. `fn func_name(arg: arg_type) -> ()`) +- The expression following `=` is the function body assigned to `func_name`. Note, the function + body can make recursive calls to its cached-self (`func_name`). + + +# Fine grained control using `cached_control!` + +The `cached_control!` macro allows you to provide expressions that get plugged into key areas +of the memoized function. While the `cached` and `cached_result` variants are adequate for most +scenarios, it can be useful to have the ability to customize the macro's functionality. + +```rust,no_run +#[macro_use] extern crate cached; + +use cached::UnboundCache; + +/// The following usage plugs in expressions to make the macro behave like +/// the `cached_result!` macro. +cached_control!{ + CACHE: UnboundCache = UnboundCache::new(); + + // Use an owned copy of the argument `input` as the cache key + Key = { input.to_owned() }; + + // If a cached value exists, it will bind to `cached_val` and + // a `Result` will be returned containing a copy of the cached + // evaluated body. This will return before the function body + // is executed. + PostGet(cached_val) = { return Ok(cached_val.clone()) }; + + // The result of executing the function body will be bound to + // `body_result`. In this case, the function body returns a `Result`. + // We match on the `Result`, returning an early `Err` if the function errored. + // Otherwise, we pass on the function's result to be cached. + PostExec(body_result) = { + match body_result { + Ok(v) => v, + Err(e) => return Err(e), + } + }; + + // When inserting the value into the cache we bind + // the to-be-set-value to `set_value` and give back a copy + // of it to be inserted into the cache + Set(set_value) = { set_value.clone() }; + + // Before returning, print the value that will be returned + Return(return_value) = { + println!("{}", return_value); + Ok(return_value) + }; + + fn can_fail(input: &str) -> Result = { + let len = input.len(); + if len < 3 { Ok(format!("{}-{}", input, len)) } + else { Err("too big".to_string()) } + } +} +# pub fn main() {} +``` + + + */ + +#[macro_export] +macro_rules! cached { + // Use default cached::Cache + ($cachename:ident; + fn $name:ident ($($arg:ident : $argtype:ty),*) -> $ret:ty = $body:expr) => { + cached!( + $cachename : $crate::UnboundCache<($($argtype),*), $ret> = $crate::UnboundCache::new(); + fn $name($($arg : $argtype),*) -> $ret = $body + ); + }; + + // Use a specified cache-type and an explicitly created cache-instance + ($cachename:ident : $cachetype:ty = $cacheinstance:expr ; + fn $name:ident ($($arg:ident : $argtype:ty),*) -> $ret:ty = $body:expr) => { + static $cachename: $crate::once_cell::sync::Lazy<::std::sync::Mutex<$cachetype>> + = $crate::once_cell::sync::Lazy::new(|| ::std::sync::Mutex::new($cacheinstance)); + + #[allow(unused_parens)] + pub fn $name($($arg: $argtype),*) -> $ret { + let key = ($($arg.clone()),*); + { + let mut cache = $cachename.lock().unwrap(); + let res = $crate::Cached::cache_get(&mut *cache, &key); + if let Some(res) = res { return res.clone(); } + } + let val = (||$body)(); + let mut cache = $cachename.lock().unwrap(); + $crate::Cached::cache_set(&mut *cache, key, val.clone()); + val + } + }; + + ($cachename:ident : $cachetype:ty = $cacheinstance:expr ; + async fn $name:ident ($($arg:ident : $argtype:ty),*) -> $ret:ty = $body:block) => { + static $cachename: $crate::once_cell::sync::Lazy<::std::sync::Mutex<$cachetype>> + = $crate::once_cell::sync::Lazy::new(|| ::std::sync::Mutex::new($cacheinstance)); + + #[allow(unused_parens)] + pub async fn $name($($arg: $argtype),*) -> $ret { + let key = ($($arg.clone()),*); + { + let mut cache = $cachename.lock().unwrap(); + let res = $crate::Cached::cache_get(&mut *cache, &key); + if let Some(res) = res { return res.clone(); } + } + // run the function and cache the result + async fn inner($($arg: $argtype),*) -> $ret $body + let val = inner($($arg),*).await; + + let mut cache = $cachename.lock().unwrap(); + $crate::Cached::cache_set(&mut *cache, key, val.clone()); + val + } + }; +} + +#[macro_export] +macro_rules! cached_key { + // Use a specified cache-type and an explicitly created cache-instance + ($cachename:ident : $cachetype:ty = $cacheinstance:expr ; + Key = $key:expr; + fn $name:ident ($($arg:ident : $argtype:ty),*) -> $ret:ty = $body:expr) => { + static $cachename: $crate::once_cell::sync::Lazy<::std::sync::Mutex<$cachetype>> + = $crate::once_cell::sync::Lazy::new(|| ::std::sync::Mutex::new($cacheinstance)); + + #[allow(unused_parens)] + pub fn $name($($arg: $argtype),*) -> $ret { + let key = $key; + { + let mut cache = $cachename.lock().unwrap(); + let res = $crate::Cached::cache_get(&mut *cache, &key); + if let Some(res) = res { return res.clone(); } + } + let val = (||$body)(); + let mut cache = $cachename.lock().unwrap(); + $crate::Cached::cache_set(&mut *cache, key, val.clone()); + val + } + }; + + ($cachename:ident : $cachetype:ty = $cacheinstance:expr ; + Key = $key:expr; + async fn $name:ident ($($arg:ident : $argtype:ty),*) -> $ret:ty = $body:expr) => { + static $cachename: $crate::once_cell::sync::Lazy<::std::sync::Mutex<$cachetype>> + = $crate::once_cell::sync::Lazy::new(|| ::std::sync::Mutex::new($cacheinstance)); + + #[allow(unused_parens)] + pub async fn $name($($arg: $argtype),*) -> $ret { + let key = $key; + { + let mut cache = $cachename.lock().unwrap(); + let res = $crate::Cached::cache_get(&mut *cache, &key); + if let Some(res) = res { return res.clone(); } + } + // run the function and cache the result + async fn inner($($arg: $argtype),*) -> $ret $body + let val = inner($($arg),*).await; + let mut cache = $cachename.lock().unwrap(); + $crate::Cached::cache_set(&mut *cache, key, val.clone()); + val + } + }; +} + +#[macro_export] +macro_rules! cached_result { + // Unfortunately it's impossible to infer the cache type because it's not the function return type + ($cachename:ident : $cachetype:ty = $cacheinstance:expr ; + fn $name:ident ($($arg:ident : $argtype:ty),*) -> $ret:ty = $body:expr) => { + static $cachename: $crate::once_cell::sync::Lazy<::std::sync::Mutex<$cachetype>> + = $crate::once_cell::sync::Lazy::new(|| ::std::sync::Mutex::new($cacheinstance)); + + #[allow(unused_parens)] + pub fn $name($($arg: $argtype),*) -> $ret { + let key = ($($arg.clone()),*); + { + let mut cache = $cachename.lock().unwrap(); + let res = $crate::Cached::cache_get(&mut *cache, &key); + if let Some(res) = res { return Ok(res.clone()); } + } + + // Store return in temporary typed variable in case type cannot be inferred + let ret : $ret = (||$body)(); + let val = ret?; + + let mut cache = $cachename.lock().unwrap(); + $crate::Cached::cache_set(&mut *cache, key, val.clone()); + Ok(val) + } + }; + + ($cachename:ident : $cachetype:ty = $cacheinstance:expr ; + async fn $name:ident ($($arg:ident : $argtype:ty),*) -> $ret:ty = $body:expr) => { + static $cachename: $crate::once_cell::sync::Lazy<::std::sync::Mutex<$cachetype>> + = $crate::once_cell::sync::Lazy::new(|| ::std::sync::Mutex::new($cacheinstance)); + + #[allow(unused_parens)] + pub async fn $name($($arg: $argtype),*) -> $ret { + let key = ($($arg.clone()),*); + { + let mut cache = $cachename.lock().unwrap(); + let res = $crate::Cached::cache_get(&mut *cache, &key); + if let Some(res) = res { return Ok(res.clone()); } + } + + // run the function and cache the result + async fn inner($($arg: $argtype),*) -> $ret $body + let val = inner($($arg),*).await?; + + let mut cache = $cachename.lock().unwrap(); + $crate::Cached::cache_set(&mut *cache, key, val.clone()); + Ok(val) + } + }; +} + +#[macro_export] +macro_rules! cached_key_result { + // Use a specified cache-type and an explicitly created cache-instance + ($cachename:ident : $cachetype:ty = $cacheinstance:expr ; + Key = $key:expr; + fn $name:ident ($($arg:ident : $argtype:ty),*) -> $ret:ty = $body:expr) => { + static $cachename: $crate::once_cell::sync::Lazy<::std::sync::Mutex<$cachetype>> + = $crate::once_cell::sync::Lazy::new(|| ::std::sync::Mutex::new($cacheinstance)); + + #[allow(unused_parens)] + pub fn $name($($arg: $argtype),*) -> $ret { + let key = $key; + { + let mut cache = $cachename.lock().unwrap(); + let res = $crate::Cached::cache_get(&mut *cache, &key); + if let Some(res) = res { return Ok(res.clone()); } + } + + // Store return in temporary typed variable in case type cannot be inferred + let ret : $ret = (||$body)(); + let val = ret?; + + let mut cache = $cachename.lock().unwrap(); + $crate::Cached::cache_set(&mut *cache, key, val.clone()); + Ok(val) + } + }; + + ($cachename:ident : $cachetype:ty = $cacheinstance:expr ; + Key = $key:expr; + async fn $name:ident ($($arg:ident : $argtype:ty),*) -> $ret:ty = $body:expr) => { + static $cachename: $crate::once_cell::sync::Lazy<::std::sync::Mutex<$cachetype>> + = $crate::once_cell::sync::Lazy::new(|| ::std::sync::Mutex::new($cacheinstance)); + + #[allow(unused_parens)] + pub async fn $name($($arg: $argtype),*) -> $ret { + let key = $key; + { + let mut cache = $cachename.lock().unwrap(); + let res = $crate::Cached::cache_get(&mut *cache, &key); + if let Some(res) = res { return Ok(res.clone()); } + } + + // run the function and cache the result + async fn inner($($arg: $argtype),*) -> $ret $body + let val = inner($($arg),*).await?; + + let mut cache = $cachename.lock().unwrap(); + $crate::Cached::cache_set(&mut *cache, key, val.clone()); + Ok(val) + } + }; +} + +#[macro_export] +macro_rules! cached_control { + // Use a specified cache-type and an explicitly created cache-instance + ($cachename:ident : $cachetype:ty = $cacheinstance:expr ; + Key = $key:expr; + PostGet($cached_value:ident) = $post_get:expr; + PostExec($body_value:ident) = $post_exec:expr; + Set($set_value:ident) = $pre_set:expr; + Return($ret_value:ident) = $return:expr; + fn $name:ident ($($arg:ident : $argtype:ty),*) -> $ret:ty = $body:expr) => { + static $cachename: $crate::once_cell::sync::Lazy<::std::sync::Mutex<$cachetype>> + = $crate::once_cell::sync::Lazy::new(|| ::std::sync::Mutex::new($cacheinstance)); + + #[allow(unused_parens)] + pub fn $name($($arg: $argtype),*) -> $ret { + let key = $key; + { + let mut cache = $cachename.lock().unwrap(); + let res = $crate::Cached::cache_get(&mut *cache, &key); + if let Some($cached_value) = res { + $post_get + } + } + let $body_value = (||$body)(); + let $set_value = $post_exec; + let mut cache = $cachename.lock().unwrap(); + $crate::Cached::cache_set(&mut *cache, key, $pre_set); + let $ret_value = $set_value; + $return + } + }; + + ($cachename:ident : $cachetype:ty = $cacheinstance:expr ; + Key = $key:expr; + PostGet($cached_value:ident) = $post_get:expr; + PostExec($body_value:ident) = $post_exec:expr; + Set($set_value:ident) = $pre_set:expr; + Return($ret_value:ident) = $return:expr; + async fn $name:ident ($($arg:ident : $argtype:ty),*) -> $ret:ty = $body:expr) => { + static $cachename: $crate::once_cell::sync::Lazy<::std::sync::Mutex<$cachetype>> + = $crate::once_cell::sync::Lazy::new(|| ::std::sync::Mutex::new($cacheinstance)); + + #[allow(unused_parens)] + pub async fn $name($($arg: $argtype),*) -> $ret { + let key = $key; + { + let mut cache = $cachename.lock().unwrap(); + let res = $crate::Cached::cache_get(&mut *cache, &key); + if let Some($cached_value) = res { + $post_get + } + } + // run the function and cache the result + async fn inner($($arg: $argtype),*) -> $ret $body + let $body_value = inner($($arg),*).await?; + let $set_value = $post_exec; + let mut cache = $cachename.lock().unwrap(); + $crate::Cached::cache_set(&mut *cache, key, $pre_set); + let $ret_value = $set_value; + $return + } + }; +} diff --git a/vendor/cached/src/proc_macro.rs b/vendor/cached/src/proc_macro.rs new file mode 100644 index 0000000000000..1926d83738da8 --- /dev/null +++ b/vendor/cached/src/proc_macro.rs @@ -0,0 +1,333 @@ +#![cfg_attr(docsrs, doc(cfg(feature = "proc_macro")))] + +/*! +Procedural macros for defining functions that wrap a static-ref cache object. + +```rust,no_run +use std::thread::sleep; +use std::time::Duration; +use cached::proc_macro::cached; + +/// Use an lru cache with size 100 and a `(String, String)` cache key +#[cached(size=100)] +fn keyed(a: String, b: String) -> usize { + let size = a.len() + b.len(); + sleep(Duration::new(size as u64, 0)); + size +} +# pub fn main() { } +``` + +---- + +```rust,no_run +use std::thread::sleep; +use std::time::Duration; +use cached::proc_macro::cached; + +/// Use a timed-lru cache with size 1, a TTL of 60s, +/// and a `(usize, usize)` cache key +#[cached(size=1, time=60)] +fn keyed(a: usize, b: usize) -> usize { + let total = a + b; + sleep(Duration::new(total as u64, 0)); + total +} +pub fn main() { + keyed(1, 2); // Not cached, will sleep (1+2)s + + keyed(1, 2); // Cached, no sleep + + sleep(Duration::new(60, 0)); // Sleep for the TTL + + keyed(1, 2); // 60s TTL has passed so the cached + // value has expired, will sleep (1+2)s + + keyed(1, 2); // Cached, no sleep + + keyed(2, 1); // New args, not cached, will sleep (2+1)s + + keyed(1, 2); // Was evicted because of lru size of 1, + // will sleep (1+2)s +} +``` + +---- + +```rust,no_run +use std::thread::sleep; +use std::time::Duration; +use cached::proc_macro::cached; + +/// Use a timed cache with a TTL of 60s +/// that refreshes the entry TTL on cache hit, +/// and a `(String, String)` cache key +#[cached(time=60, time_refresh=true)] +fn keyed(a: String, b: String) -> usize { + let size = a.len() + b.len(); + sleep(Duration::new(size as u64, 0)); + size +} +# pub fn main() { } +``` + +---- + +```rust,no_run +use cached::proc_macro::cached; + +# fn do_something_fallible() -> std::result::Result<(), ()> { +# Ok(()) +# } + +/// Cache a fallible function. Only `Ok` results are cached. +#[cached(size=1, result = true)] +fn keyed(a: String) -> Result { + do_something_fallible()?; + Ok(a.len()) +} +# pub fn main() { } +``` + +---- + +```rust,no_run +use cached::proc_macro::cached; + +/// Cache an optional function. Only `Some` results are cached. +#[cached(size=1, option = true)] +fn keyed(a: String) -> Option { + if a == "a" { + Some(a.len()) + } else { + None + } +} +# pub fn main() { } +``` + +---- + +```rust,no_run +use cached::proc_macro::cached; + +/// Cache an optional function. Only `Some` results are cached. +/// When called concurrently, duplicate argument-calls will be +/// synchronized so as to only run once - the remaining concurrent +/// calls return a cached value. +#[cached(size=1, option = true, sync_writes = true)] +fn keyed(a: String) -> Option { + if a == "a" { + Some(a.len()) + } else { + None + } +} +# pub fn main() { } +``` + +---- + +```rust,no_run +use cached::proc_macro::cached; +use cached::Return; + +/// Get a `cached::Return` value that indicates +/// whether the value returned came from the cache: +/// `cached::Return.was_cached`. +/// Use an LRU cache and a `String` cache key. +#[cached(size=1, with_cached_flag = true)] +fn calculate(a: String) -> Return { + Return::new(a) +} +pub fn main() { + let r = calculate("a".to_string()); + assert!(!r.was_cached); + let r = calculate("a".to_string()); + assert!(r.was_cached); + // Return derefs to String + assert_eq!(r.to_uppercase(), "A"); +} +``` + +---- + +```rust,no_run +use cached::proc_macro::cached; +use cached::Return; + +# fn do_something_fallible() -> std::result::Result<(), ()> { +# Ok(()) +# } + +/// Same as the previous, but returning a Result +#[cached(size=1, result = true, with_cached_flag = true)] +fn calculate(a: String) -> Result, ()> { + do_something_fallible()?; + Ok(Return::new(a.len())) +} +pub fn main() { + match calculate("a".to_string()) { + Err(e) => eprintln!("error: {:?}", e), + Ok(r) => { + println!("value: {:?}, was cached: {}", *r, r.was_cached); + // value: "a", was cached: true + } + } +} +``` + +---- + +```rust,no_run +use cached::proc_macro::cached; +use cached::Return; + +/// Same as the previous, but returning an Option +#[cached(size=1, option = true, with_cached_flag = true)] +fn calculate(a: String) -> Option> { + if a == "a" { + Some(Return::new(a.len())) + } else { + None + } +} +pub fn main() { + if let Some(a) = calculate("a".to_string()) { + println!("value: {:?}, was cached: {}", *a, a.was_cached); + // value: "a", was cached: true + } +} +``` + +---- + +```rust,no_run +use std::thread::sleep; +use std::time::Duration; +use cached::proc_macro::cached; +use cached::SizedCache; + +/// Use an explicit cache-type with a custom creation block and custom cache-key generating block +#[cached( + type = "SizedCache", + create = "{ SizedCache::with_size(100) }", + convert = r#"{ format!("{}{}", a, b) }"# +)] +fn keyed(a: &str, b: &str) -> usize { + let size = a.len() + b.len(); + sleep(Duration::new(size as u64, 0)); + size +} +# pub fn main() { } +``` + +---- + +```rust,no_run +use cached::proc_macro::once; + +/// Only cache the initial function call. +/// Function will be re-executed after the cache +/// expires (according to `time` seconds). +/// When no (or expired) cache, concurrent calls +/// will synchronize (`sync_writes`) so the function +/// is only executed once. +#[once(time=10, option = true, sync_writes = true)] +fn keyed(a: String) -> Option { + if a == "a" { + Some(a.len()) + } else { + None + } +} +# pub fn main() { } +``` + +---- + +```rust +use std::thread::sleep; +use std::time::Duration; +use cached::proc_macro::cached; + +/// Use a timed cache with a TTL of 60s. +/// Run a background thread to continuously refresh a specific key. +#[cached(time = 60, key = "String", convert = r#"{ String::from(a) }"#)] +fn keyed(a: &str) -> usize { + a.len() +} +pub fn main() { + let _handler = std::thread::spawn(|| { + loop { + sleep(Duration::from_secs(50)); + // this method is generated by the `cached` macro + keyed_prime_cache("a"); + } + }); + // handler.join().unwrap(); +} +``` + +---- + +```rust +use std::thread::sleep; +use std::time::Duration; +use cached::proc_macro::once; + +/// Run a background thread to continuously refresh a singleton. +#[once] +fn keyed() -> String { + // do some long http request + "some data".to_string() +} +pub fn main() { + let _handler = std::thread::spawn(|| { + loop { + sleep(Duration::from_secs(60)); + // this method is generated by the `cached` macro + keyed_prime_cache(); + } + }); + // handler.join().unwrap(); +} +``` + +---- + +```rust +use std::thread::sleep; +use std::time::Duration; +use cached::proc_macro::cached; + +/// Run a background thread to continuously refresh every key of a cache +#[cached(key = "String", convert = r#"{ String::from(a) }"#)] +fn keyed(a: &str) -> usize { + a.len() +} +pub fn main() { + let _handler = std::thread::spawn(|| { + loop { + sleep(Duration::from_secs(60)); + let keys: Vec = { + // note the cache keys are a tuple of all function arguments, unless it's one value + KEYED.lock().unwrap().get_store().keys().map(|k| k.clone()).collect() + }; + for k in &keys { + // this method is generated by the `cached` macro + keyed_prime_cache(k); + } + } + }); + // handler.join().unwrap(); +} +``` + + +*/ + +#[doc(inline)] +pub use cached_proc_macro::{cached, io_cached, once}; +#[doc(inline)] +pub use cached_proc_macro_types::Return; diff --git a/vendor/cached/src/stores/disk.rs b/vendor/cached/src/stores/disk.rs new file mode 100644 index 0000000000000..33a85e7670839 --- /dev/null +++ b/vendor/cached/src/stores/disk.rs @@ -0,0 +1,396 @@ +use crate::IOCached; +use directories::BaseDirs; +use instant::Duration; +use serde::de::DeserializeOwned; +use serde::Serialize; +use sled::Db; +use std::marker::PhantomData; +use std::path::Path; +use std::{fmt::Display, path::PathBuf, time::SystemTime}; + +pub struct DiskCacheBuilder { + seconds: Option, + refresh: bool, + disk_dir: Option, + cache_name: String, + _phantom: PhantomData<(K, V)>, +} + +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum DiskCacheBuildError { + #[error("Storage connection error")] + ConnectionError(#[from] sled::Error), + #[error("Connection string not specified or invalid in env var {env_key:?}: {error:?}")] + MissingDiskPath { + env_key: String, + error: std::env::VarError, + }, +} + +static DISK_FILE_PREFIX: &str = "cached_disk_cache"; +const DISK_FILE_VERSION: u64 = 1; + +impl DiskCacheBuilder +where + K: Display, + V: Serialize + DeserializeOwned, +{ + /// Initialize a `DiskCacheBuilder` + pub fn new>(cache_name: S) -> DiskCacheBuilder { + Self { + seconds: None, + refresh: false, + disk_dir: None, + cache_name: cache_name.as_ref().to_string(), + _phantom: Default::default(), + } + } + + /// Specify the cache TTL/lifespan in seconds + pub fn set_lifespan(mut self, seconds: u64) -> Self { + self.seconds = Some(seconds); + self + } + + /// Specify whether cache hits refresh the TTL + pub fn set_refresh(mut self, refresh: bool) -> Self { + self.refresh = refresh; + self + } + + /// Set the disk path for where the data will be stored + pub fn set_disk_directory>(mut self, dir: P) -> Self { + self.disk_dir = Some(dir.as_ref().into()); + self + } + + fn default_disk_dir() -> PathBuf { + BaseDirs::new() + .map(|base_dirs| { + let exe_name = std::env::current_exe() + .ok() + .and_then(|path| { + path.file_name() + .and_then(|os_str| os_str.to_str().map(|s| format!("{}_", s))) + }) + .unwrap_or_default(); + let dir_prefix = format!("{}{}", exe_name, DISK_FILE_PREFIX); + base_dirs.cache_dir().join(dir_prefix) + }) + .unwrap_or_else(|| { + std::env::current_dir().expect("disk cache unable to determine current directory") + }) + } + + pub fn build(self) -> Result, DiskCacheBuildError> { + let disk_dir = self.disk_dir.unwrap_or_else(|| Self::default_disk_dir()); + let disk_path = disk_dir.join(format!("{}_v{}", self.cache_name, DISK_FILE_VERSION)); + let connection = sled::open(disk_path.clone())?; + + Ok(DiskCache { + seconds: self.seconds, + refresh: self.refresh, + version: DISK_FILE_VERSION, + disk_path, + connection, + _phantom: self._phantom, + }) + } +} + +/// Cache store backed by disk +pub struct DiskCache { + pub(super) seconds: Option, + pub(super) refresh: bool, + #[allow(unused)] + version: u64, + #[allow(unused)] + disk_path: PathBuf, + connection: Db, + _phantom: PhantomData<(K, V)>, +} + +impl DiskCache +where + K: Display, + V: Serialize + DeserializeOwned, +{ + #[allow(clippy::new_ret_no_self)] + /// Initialize a `DiskCacheBuilder` + pub fn new(cache_name: &str) -> DiskCacheBuilder { + DiskCacheBuilder::new(cache_name) + } + + pub fn remove_expired_entries(&self) { + let now = SystemTime::now(); + + for (key, value) in self.connection.iter().flatten() { + if let Ok(cached) = rmp_serde::from_slice::>(&value) { + if let Some(lifetime_seconds) = self.seconds { + if now + .duration_since(cached.created_at) + .unwrap_or(Duration::from_secs(0)) + < Duration::from_secs(lifetime_seconds) + { + let _ = self.connection.remove(key); + } + } + } + } + } +} + +#[derive(Error, Debug)] +pub enum DiskCacheError { + #[error("Storage error")] + StorageError(#[from] sled::Error), + #[error("Error deserializing cached value")] + CacheDeserializtionError(#[from] rmp_serde::decode::Error), + #[error("Error serializing cached value")] + CacheSerializtionError(#[from] rmp_serde::encode::Error), +} + +#[derive(serde::Serialize, serde::Deserialize)] +struct CachedDiskValue { + pub(crate) value: V, + pub(crate) created_at: SystemTime, + pub(crate) version: u64, +} + +impl CachedDiskValue { + fn new(value: V) -> Self { + Self { + value, + created_at: SystemTime::now(), + version: 1, + } + } + + fn refresh_created_at(&mut self) { + self.created_at = SystemTime::now(); + } +} + +impl IOCached for DiskCache +where + K: Display, + V: Serialize + DeserializeOwned, +{ + type Error = DiskCacheError; + + fn cache_get(&self, key: &K) -> Result, DiskCacheError> { + let key = key.to_string(); + let seconds = self.seconds; + let refresh = self.refresh; + let update = |old: Option<&[u8]>| -> Option> { + let old = old?; + if seconds.is_none() { + return Some(old.to_vec()); + } + let seconds = seconds.unwrap(); + let mut cached = match rmp_serde::from_slice::>(old) { + Ok(cached) => cached, + Err(_) => { + // unable to deserialize, treat it as not existing + return None; + } + }; + if SystemTime::now() + .duration_since(cached.created_at) + .unwrap_or(Duration::from_secs(0)) + < Duration::from_secs(seconds) + { + if refresh { + cached.refresh_created_at(); + } + let cache_val = + rmp_serde::to_vec(&cached).expect("error serializing cached disk value"); + Some(cache_val) + } else { + None + } + }; + + if let Some(data) = self.connection.update_and_fetch(key, update)? { + let cached = rmp_serde::from_slice::>(&data)?; + Ok(Some(cached.value)) + } else { + Ok(None) + } + } + + fn cache_set(&self, key: K, value: V) -> Result, DiskCacheError> { + let key = key.to_string(); + let value = rmp_serde::to_vec(&CachedDiskValue::new(value))?; + + if let Some(data) = self.connection.insert(key, value)? { + let cached = rmp_serde::from_slice::>(&data)?; + + if let Some(lifetime_seconds) = self.seconds { + if SystemTime::now() + .duration_since(cached.created_at) + .unwrap_or(Duration::from_secs(0)) + < Duration::from_secs(lifetime_seconds) + { + Ok(Some(cached.value)) + } else { + Ok(None) + } + } else { + Ok(Some(cached.value)) + } + } else { + Ok(None) + } + } + + fn cache_remove(&self, key: &K) -> Result, DiskCacheError> { + let key = key.to_string(); + if let Some(data) = self.connection.remove(key)? { + let cached = rmp_serde::from_slice::>(&data)?; + + if let Some(lifetime_seconds) = self.seconds { + if SystemTime::now() + .duration_since(cached.created_at) + .unwrap_or(Duration::from_secs(0)) + < Duration::from_secs(lifetime_seconds) + { + Ok(Some(cached.value)) + } else { + Ok(None) + } + } else { + Ok(Some(cached.value)) + } + } else { + Ok(None) + } + } + + fn cache_lifespan(&self) -> Option { + self.seconds + } + + fn cache_set_lifespan(&mut self, seconds: u64) -> Option { + let old = self.seconds; + self.seconds = Some(seconds); + old + } + + fn cache_set_refresh(&mut self, refresh: bool) -> bool { + let old = self.refresh; + self.refresh = refresh; + old + } +} + +#[cfg(test)] +/// Cache store tests +mod tests { + use std::thread::sleep; + use std::time::Duration; + + use super::*; + + fn now_millis() -> u128 { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_millis() + } + + #[test] + fn disk_set_get_remove() { + let cache: DiskCache = + DiskCache::new(&format!("{}:disk-cache-test-sgr", now_millis())) + .set_disk_directory(std::env::temp_dir().join("cachedtest-sgr")) + .build() + .unwrap(); + + let cached = cache.cache_get(&6).unwrap(); + assert!(cached.is_none()); + + let cached = cache.cache_set(6, 4444).unwrap(); + assert_eq!(cached, None); + + let cached = cache.cache_set(6, 5555).unwrap(); + assert_eq!(cached, Some(4444)); + + let cached = cache.cache_get(&6).unwrap(); + assert_eq!(cached, Some(5555)); + + let cached = cache.cache_remove(&6).unwrap(); + assert_eq!(cached, Some(5555)); + + let cached = cache.cache_get(&6).unwrap(); + assert!(cached.is_none()); + + drop(cache); + } + + #[test] + fn disk_expire() { + let mut c: DiskCache = + DiskCache::new(&format!("{}:disk-cache-test", now_millis())) + .set_lifespan(2) + .build() + .unwrap(); + + assert!(c.cache_get(&1).unwrap().is_none()); + + assert!(c.cache_set(1, 100).unwrap().is_none()); + assert!(c.cache_get(&1).unwrap().is_some()); + + sleep(Duration::new(2, 500000)); + assert!(c.cache_get(&1).unwrap().is_none()); + + let old = c.cache_set_lifespan(1).unwrap(); + assert_eq!(2, old); + assert!(c.cache_set(1, 100).unwrap().is_none()); + assert!(c.cache_get(&1).unwrap().is_some()); + + sleep(Duration::new(1, 600000)); + assert!(c.cache_get(&1).unwrap().is_none()); + + c.cache_set_lifespan(10).unwrap(); + assert!(c.cache_set(1, 100).unwrap().is_none()); + assert!(c.cache_set(2, 100).unwrap().is_none()); + assert_eq!(c.cache_get(&1).unwrap().unwrap(), 100); + assert_eq!(c.cache_get(&1).unwrap().unwrap(), 100); + } + + #[test] + fn disk_remove() { + let cache: DiskCache = + DiskCache::new(&format!("{}:disk-cache-test-remove", now_millis())) + .set_disk_directory(std::env::temp_dir().join("cachedtest-remove")) + .build() + .unwrap(); + + assert!(cache.cache_set(1, 100).unwrap().is_none()); + assert!(cache.cache_set(2, 200).unwrap().is_none()); + assert!(cache.cache_set(3, 300).unwrap().is_none()); + + assert_eq!(100, cache.cache_remove(&1).unwrap().unwrap()); + + drop(cache); + } + + #[test] + fn disk_default_cache_dir() { + let cache: DiskCache = + DiskCache::new(&format!("{}:disk-cache-test-default-dir", now_millis())) + .build() + .unwrap(); + + assert!(cache.cache_set(1, 100).unwrap().is_none()); + assert!(cache.cache_set(2, 200).unwrap().is_none()); + assert!(cache.cache_set(3, 300).unwrap().is_none()); + + assert_eq!(100, cache.cache_remove(&1).unwrap().unwrap()); + + drop(cache); + } +} diff --git a/vendor/cached/src/stores/expiring_value_cache.rs b/vendor/cached/src/stores/expiring_value_cache.rs new file mode 100644 index 0000000000000..34b550cbf5eba --- /dev/null +++ b/vendor/cached/src/stores/expiring_value_cache.rs @@ -0,0 +1,295 @@ +use super::{Cached, SizedCache}; +use crate::{stores::timed::Status, CloneCached}; +use std::hash::Hash; + +/// The `CanExpire` trait defines a function for implementations to determine if +/// the value has expired. +pub trait CanExpire { + /// `is_expired` returns whether the value has expired. + fn is_expired(&self) -> bool; +} + +/// Expiring Value Cache +/// +/// Stores values that implement the `CanExpire` trait so that expiration +/// is determined by the values themselves. This is useful for caching +/// values which themselves contain an expiry timestamp. +/// +/// Note: This cache is in-memory only. +#[derive(Clone, Debug)] +pub struct ExpiringValueCache { + pub(super) store: SizedCache, + pub(super) hits: u64, + pub(super) misses: u64, +} + +impl ExpiringValueCache { + /// Creates a new `ExpiringValueCache` with a given size limit and + /// pre-allocated backing data. + #[must_use] + pub fn with_size(size: usize) -> ExpiringValueCache { + ExpiringValueCache { + store: SizedCache::with_size(size), + hits: 0, + misses: 0, + } + } + + fn status(&mut self, k: &Q) -> Status + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + let v = self.store.cache_get(k); + match v { + Some(v) => { + if v.is_expired() { + Status::Expired + } else { + Status::Found + } + } + None => Status::NotFound, + } + } + + /// Remove any expired values from the cache + pub fn flush(&mut self) { + self.store.retain(|_, v| !v.is_expired()); + } +} + +// https://docs.rs/cached/latest/cached/trait.Cached.html +impl Cached for ExpiringValueCache { + fn cache_get(&mut self, k: &Q) -> Option<&V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + match self.status(k) { + Status::NotFound => { + self.misses += 1; + None + } + Status::Found => { + self.hits += 1; + self.store.cache_get(k) + } + Status::Expired => { + self.misses += 1; + self.store.cache_remove(k); + None + } + } + } + + fn cache_get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + match self.status(k) { + Status::NotFound => { + self.misses += 1; + None + } + Status::Found => { + self.hits += 1; + self.store.cache_get_mut(k) + } + Status::Expired => { + self.misses += 1; + self.store.cache_remove(k); + None + } + } + } + + fn cache_get_or_set_with V>(&mut self, k: K, f: F) -> &mut V { + // get_or_set_with_if will set the value in the cache if an existing + // value is not valid, which, in our case, is if the value has expired. + let (was_present, was_valid, v) = self.store.get_or_set_with_if(k, f, |v| !v.is_expired()); + if was_present && was_valid { + self.hits += 1; + } else { + self.misses += 1; + } + v + } + fn cache_set(&mut self, k: K, v: V) -> Option { + self.store.cache_set(k, v) + } + fn cache_remove(&mut self, k: &Q) -> Option + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.store.cache_remove(k) + } + fn cache_clear(&mut self) { + self.store.cache_clear(); + } + fn cache_reset(&mut self) { + self.store.cache_reset(); + } + fn cache_size(&self) -> usize { + self.store.cache_size() + } + fn cache_hits(&self) -> Option { + Some(self.hits) + } + fn cache_misses(&self) -> Option { + Some(self.misses) + } + fn cache_reset_metrics(&mut self) { + self.hits = 0; + self.misses = 0; + } +} + +impl CloneCached for ExpiringValueCache { + fn cache_get_expired(&mut self, k: &Q) -> (Option, bool) + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + match self.status(k) { + Status::NotFound => { + self.misses += 1; + (None, false) + } + Status::Found => { + self.hits += 1; + (self.store.cache_get(k).cloned(), false) + } + Status::Expired => { + self.misses += 1; + (self.store.cache_remove(k), true) + } + } + } +} + +#[cfg(test)] +/// Expiring Value Cache tests +mod tests { + use super::*; + + type ExpiredU8 = u8; + + impl CanExpire for ExpiredU8 { + fn is_expired(&self) -> bool { + *self > 10 + } + } + + #[test] + fn expiring_value_cache_get_miss() { + let mut c: ExpiringValueCache = ExpiringValueCache::with_size(3); + + // Getting a non-existent cache key. + assert!(c.cache_get(&1).is_none()); + assert_eq!(c.cache_hits(), Some(0)); + assert_eq!(c.cache_misses(), Some(1)); + } + + #[test] + fn expiring_value_cache_get_hit() { + let mut c: ExpiringValueCache = ExpiringValueCache::with_size(3); + + // Getting a cached value. + assert!(c.cache_set(1, 2).is_none()); + assert_eq!(c.cache_get(&1), Some(&2)); + assert_eq!(c.cache_hits(), Some(1)); + assert_eq!(c.cache_misses(), Some(0)); + } + + #[test] + fn expiring_value_cache_get_expired() { + let mut c: ExpiringValueCache = ExpiringValueCache::with_size(3); + + assert!(c.cache_set(2, 12).is_none()); + + assert!(c.cache_get(&2).is_none()); + assert_eq!(c.cache_hits(), Some(0)); + assert_eq!(c.cache_misses(), Some(1)); + } + + #[test] + fn expiring_value_cache_get_mut_miss() { + let mut c: ExpiringValueCache = ExpiringValueCache::with_size(3); + + // Getting a non-existent cache key. + assert!(c.cache_get_mut(&1).is_none()); + assert_eq!(c.cache_hits(), Some(0)); + assert_eq!(c.cache_misses(), Some(1)); + } + + #[test] + fn expiring_value_cache_get_mut_hit() { + let mut c: ExpiringValueCache = ExpiringValueCache::with_size(3); + + // Getting a cached value. + assert!(c.cache_set(1, 2).is_none()); + assert_eq!(c.cache_get_mut(&1), Some(&mut 2)); + assert_eq!(c.cache_hits(), Some(1)); + assert_eq!(c.cache_misses(), Some(0)); + } + + #[test] + fn expiring_value_cache_get_mut_expired() { + let mut c: ExpiringValueCache = ExpiringValueCache::with_size(3); + + assert!(c.cache_set(2, 12).is_none()); + + assert!(c.cache_get(&2).is_none()); + assert_eq!(c.cache_hits(), Some(0)); + assert_eq!(c.cache_misses(), Some(1)); + } + + #[test] + fn expiring_value_cache_get_or_set_with_missing() { + let mut c: ExpiringValueCache = ExpiringValueCache::with_size(3); + + assert_eq!(c.cache_get_or_set_with(1, || 1), &1); + assert_eq!(c.cache_hits(), Some(0)); + assert_eq!(c.cache_misses(), Some(1)); + } + + #[test] + fn expiring_value_cache_get_or_set_with_present() { + let mut c: ExpiringValueCache = ExpiringValueCache::with_size(3); + assert!(c.cache_set(1, 5).is_none()); + + // Existing value is returned rather than setting new value. + assert_eq!(c.cache_get_or_set_with(1, || 1), &5); + assert_eq!(c.cache_hits(), Some(1)); + assert_eq!(c.cache_misses(), Some(0)); + } + + #[test] + fn expiring_value_cache_get_or_set_with_expired() { + let mut c: ExpiringValueCache = ExpiringValueCache::with_size(3); + assert!(c.cache_set(1, 11).is_none()); + + // New value is returned as existing had expired. + assert_eq!(c.cache_get_or_set_with(1, || 1), &1); + assert_eq!(c.cache_hits(), Some(0)); + assert_eq!(c.cache_misses(), Some(1)); + } + + #[test] + fn flush_expired() { + let mut c: ExpiringValueCache = ExpiringValueCache::with_size(3); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(1, 200), Some(100)); + assert_eq!(c.cache_set(2, 1), None); + assert_eq!(c.cache_size(), 2); + + // It should only flush n > 10 + assert_eq!(2, c.cache_size()); + c.flush(); + assert_eq!(1, c.cache_size()); + } +} diff --git a/vendor/cached/src/stores/mod.rs b/vendor/cached/src/stores/mod.rs new file mode 100644 index 0000000000000..3aef8c47881ce --- /dev/null +++ b/vendor/cached/src/stores/mod.rs @@ -0,0 +1,142 @@ +use crate::Cached; +use std::cmp::Eq; +#[cfg(feature = "async")] +use std::collections::hash_map::Entry; +use std::collections::HashMap; +use std::hash::Hash; + +#[cfg(feature = "async")] +use {super::CachedAsync, async_trait::async_trait, futures::Future}; + +#[cfg(feature = "disk_store")] +mod disk; +mod expiring_value_cache; +#[cfg(feature = "redis_store")] +mod redis; +mod sized; +mod timed; +mod timed_sized; +mod unbound; + +#[cfg(feature = "disk_store")] +pub use crate::stores::disk::{DiskCache, DiskCacheBuildError, DiskCacheBuilder, DiskCacheError}; +#[cfg(feature = "redis_store")] +#[cfg_attr(docsrs, doc(cfg(feature = "redis_store")))] +pub use crate::stores::redis::{ + RedisCache, RedisCacheBuildError, RedisCacheBuilder, RedisCacheError, +}; +pub use expiring_value_cache::{CanExpire, ExpiringValueCache}; +pub use sized::SizedCache; +pub use timed::TimedCache; +pub use timed_sized::TimedSizedCache; +pub use unbound::UnboundCache; + +#[cfg(all( + feature = "async", + feature = "redis_store", + any(feature = "redis_async_std", feature = "redis_tokio") +))] +#[cfg_attr( + docsrs, + doc(cfg(all( + feature = "async", + feature = "redis_store", + any(feature = "redis_async_std", feature = "redis_tokio") + ))) +)] +pub use crate::stores::redis::{AsyncRedisCache, AsyncRedisCacheBuilder}; + +impl Cached for HashMap +where + K: Hash + Eq, + S: std::hash::BuildHasher + Default, +{ + fn cache_get(&mut self, k: &Q) -> Option<&V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.get(k) + } + fn cache_get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.get_mut(k) + } + fn cache_set(&mut self, k: K, v: V) -> Option { + self.insert(k, v) + } + fn cache_get_or_set_with V>(&mut self, key: K, f: F) -> &mut V { + self.entry(key).or_insert_with(f) + } + fn cache_remove(&mut self, k: &Q) -> Option + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.remove(k) + } + fn cache_clear(&mut self) { + self.clear(); + } + fn cache_reset(&mut self) { + *self = HashMap::default(); + } + fn cache_size(&self) -> usize { + self.len() + } +} + +#[cfg(feature = "async")] +#[async_trait] +impl CachedAsync for HashMap +where + K: Hash + Eq + Clone + Send, + S: std::hash::BuildHasher + Send, +{ + async fn get_or_set_with(&mut self, k: K, f: F) -> &mut V + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future + Send, + { + match self.entry(k) { + Entry::Occupied(o) => o.into_mut(), + Entry::Vacant(v) => v.insert(f().await), + } + } + + async fn try_get_or_set_with(&mut self, k: K, f: F) -> Result<&mut V, E> + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future> + Send, + { + let v = match self.entry(k) { + Entry::Occupied(o) => o.into_mut(), + Entry::Vacant(v) => v.insert(f().await?), + }; + + Ok(v) + } +} + +#[cfg(test)] +/// Cache store tests +mod tests { + use super::*; + + #[test] + fn hashmap() { + let mut c = std::collections::HashMap::new(); + assert!(c.cache_get(&1).is_none()); + assert_eq!(c.cache_misses(), None); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_get(&1), Some(&100)); + assert_eq!(c.cache_hits(), None); + assert_eq!(c.cache_misses(), None); + } +} diff --git a/vendor/cached/src/stores/redis.rs b/vendor/cached/src/stores/redis.rs new file mode 100644 index 0000000000000..8e95dc78636b2 --- /dev/null +++ b/vendor/cached/src/stores/redis.rs @@ -0,0 +1,767 @@ +use crate::IOCached; +use serde::de::DeserializeOwned; +use serde::Serialize; +use std::fmt::Display; +use std::marker::PhantomData; + +pub struct RedisCacheBuilder { + seconds: u64, + refresh: bool, + namespace: String, + prefix: String, + connection_string: Option, + pool_max_size: Option, + pool_min_idle: Option, + pool_max_lifetime: Option, + pool_idle_timeout: Option, + _phantom: PhantomData<(K, V)>, +} + +const ENV_KEY: &str = "CACHED_REDIS_CONNECTION_STRING"; +const DEFAULT_NAMESPACE: &str = "cached-redis-store:"; + +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum RedisCacheBuildError { + #[error("redis connection error")] + Connection(#[from] redis::RedisError), + #[error("redis pool error")] + Pool(#[from] r2d2::Error), + #[error("Connection string not specified or invalid in env var {env_key:?}: {error:?}")] + MissingConnectionString { + env_key: String, + error: std::env::VarError, + }, +} + +impl RedisCacheBuilder +where + K: Display, + V: Serialize + DeserializeOwned, +{ + /// Initialize a `RedisCacheBuilder` + pub fn new>(prefix: S, seconds: u64) -> RedisCacheBuilder { + Self { + seconds, + refresh: false, + namespace: DEFAULT_NAMESPACE.to_string(), + prefix: prefix.as_ref().to_string(), + connection_string: None, + pool_max_size: None, + pool_min_idle: None, + pool_max_lifetime: None, + pool_idle_timeout: None, + _phantom: PhantomData, + } + } + + /// Specify the cache TTL/lifespan in seconds + #[must_use] + pub fn set_lifespan(mut self, seconds: u64) -> Self { + self.seconds = seconds; + self + } + + /// Specify whether cache hits refresh the TTL + #[must_use] + pub fn set_refresh(mut self, refresh: bool) -> Self { + self.refresh = refresh; + self + } + + /// Set the namespace for cache keys. Defaults to `cached-redis-store:`. + /// Used to generate keys formatted as: `{namespace}{prefix}{key}` + /// Note that no delimiters are implicitly added so you may pass + /// an empty string if you want there to be no namespace on keys. + #[must_use] + pub fn set_namespace>(mut self, namespace: S) -> Self { + self.namespace = namespace.as_ref().to_string(); + self + } + + /// Set the prefix for cache keys. + /// Used to generate keys formatted as: `{namespace}{prefix}{key}` + /// Note that no delimiters are implicitly added so you may pass + /// an empty string if you want there to be no prefix on keys. + #[must_use] + pub fn set_prefix>(mut self, prefix: S) -> Self { + self.prefix = prefix.as_ref().to_string(); + self + } + + /// Set the connection string for redis + #[must_use] + pub fn set_connection_string(mut self, cs: &str) -> Self { + self.connection_string = Some(cs.to_string()); + self + } + + /// Set the max size of the underlying redis connection pool + #[must_use] + pub fn set_connection_pool_max_size(mut self, max_size: u32) -> Self { + self.pool_max_size = Some(max_size); + self + } + + /// Set the minimum number of idle redis connections that should be maintained by the + /// underlying redis connection pool + #[must_use] + pub fn set_connection_pool_min_idle(mut self, min_idle: u32) -> Self { + self.pool_min_idle = Some(min_idle); + self + } + + /// Set the max lifetime of connections used by the underlying redis connection pool + #[must_use] + pub fn set_connection_pool_max_lifetime(mut self, max_lifetime: std::time::Duration) -> Self { + self.pool_max_lifetime = Some(max_lifetime); + self + } + + /// Set the max lifetime of idle connections maintained by the underlying redis connection pool + #[must_use] + pub fn set_connection_pool_idle_timeout(mut self, idle_timeout: std::time::Duration) -> Self { + self.pool_idle_timeout = Some(idle_timeout); + self + } + + /// Return the current connection string or load from the env var: `CACHED_REDIS_CONNECTION_STRING` + /// + /// # Errors + /// + /// Will return `RedisCacheBuildError::MissingConnectionString` if connection string is not set + pub fn connection_string(&self) -> Result { + match self.connection_string { + Some(ref s) => Ok(s.to_string()), + None => { + std::env::var(ENV_KEY).map_err(|e| RedisCacheBuildError::MissingConnectionString { + env_key: ENV_KEY.to_string(), + error: e, + }) + } + } + } + + fn create_pool(&self) -> Result, RedisCacheBuildError> { + let s = self.connection_string()?; + let client: redis::Client = redis::Client::open(s)?; + // some pool-builder defaults are set when the builder is initialized + // so we can't overwrite any values with Nones... + let pool_builder = r2d2::Pool::builder(); + let pool_builder = if let Some(max_size) = self.pool_max_size { + pool_builder.max_size(max_size) + } else { + pool_builder + }; + let pool_builder = if let Some(min_idle) = self.pool_min_idle { + pool_builder.min_idle(Some(min_idle)) + } else { + pool_builder + }; + let pool_builder = if let Some(max_lifetime) = self.pool_max_lifetime { + pool_builder.max_lifetime(Some(max_lifetime)) + } else { + pool_builder + }; + let pool_builder = if let Some(idle_timeout) = self.pool_idle_timeout { + pool_builder.idle_timeout(Some(idle_timeout)) + } else { + pool_builder + }; + + let pool: r2d2::Pool = pool_builder.build(client)?; + Ok(pool) + } + + /// The last step in building a `RedisCache` is to call `build()` + /// + /// # Errors + /// + /// Will return a `RedisCacheBuildError`, depending on the error + pub fn build(self) -> Result, RedisCacheBuildError> { + Ok(RedisCache { + seconds: self.seconds, + refresh: self.refresh, + connection_string: self.connection_string()?, + pool: self.create_pool()?, + namespace: self.namespace, + prefix: self.prefix, + _phantom: PhantomData, + }) + } +} + +/// Cache store backed by redis +/// +/// Values have a ttl applied and enforced by redis. +/// Uses an r2d2 connection pool under the hood. +pub struct RedisCache { + pub(super) seconds: u64, + pub(super) refresh: bool, + pub(super) namespace: String, + pub(super) prefix: String, + connection_string: String, + pool: r2d2::Pool, + _phantom: PhantomData<(K, V)>, +} + +impl RedisCache +where + K: Display, + V: Serialize + DeserializeOwned, +{ + #[allow(clippy::new_ret_no_self)] + /// Initialize a `RedisCacheBuilder` + pub fn new>(prefix: S, seconds: u64) -> RedisCacheBuilder { + RedisCacheBuilder::new(prefix, seconds) + } + + fn generate_key(&self, key: &K) -> String { + format!("{}{}{}", self.namespace, self.prefix, key) + } + + /// Return the redis connection string used + #[must_use] + pub fn connection_string(&self) -> String { + self.connection_string.clone() + } +} + +#[derive(Error, Debug)] +pub enum RedisCacheError { + #[error("redis error")] + RedisCacheError(#[from] redis::RedisError), + #[error("redis pool error")] + PoolError(#[from] r2d2::Error), + #[error("Error deserializing cached value {cached_value:?}: {error:?}")] + CacheDeserializationError { + cached_value: String, + error: serde_json::Error, + }, + #[error("Error serializing cached value: {error:?}")] + CacheSerializationError { error: serde_json::Error }, +} + +#[derive(serde::Serialize, serde::Deserialize)] +struct CachedRedisValue { + pub(crate) value: V, + pub(crate) version: Option, +} +impl CachedRedisValue { + fn new(value: V) -> Self { + Self { + value, + version: Some(1), + } + } +} + +impl IOCached for RedisCache +where + K: Display, + V: Serialize + DeserializeOwned, +{ + type Error = RedisCacheError; + + fn cache_get(&self, key: &K) -> Result, RedisCacheError> { + let mut conn = self.pool.get()?; + let mut pipe = redis::pipe(); + let key = self.generate_key(key); + + pipe.get(key.clone()); + if self.refresh { + pipe.expire(key, self.seconds as i64).ignore(); + } + // ugh: https://github.com/mitsuhiko/redis-rs/pull/388#issuecomment-910919137 + let res: (Option,) = pipe.query(&mut *conn)?; + match res.0 { + None => Ok(None), + Some(s) => { + let v: CachedRedisValue = serde_json::from_str(&s).map_err(|e| { + RedisCacheError::CacheDeserializationError { + cached_value: s, + error: e, + } + })?; + Ok(Some(v.value)) + } + } + } + + fn cache_set(&self, key: K, val: V) -> Result, RedisCacheError> { + let mut conn = self.pool.get()?; + let mut pipe = redis::pipe(); + let key = self.generate_key(&key); + + let val = CachedRedisValue::new(val); + pipe.get(key.clone()); + pipe.set_ex::( + key, + serde_json::to_string(&val) + .map_err(|e| RedisCacheError::CacheSerializationError { error: e })?, + self.seconds, + ) + .ignore(); + + let res: (Option,) = pipe.query(&mut *conn)?; + match res.0 { + None => Ok(None), + Some(s) => { + let v: CachedRedisValue = serde_json::from_str(&s).map_err(|e| { + RedisCacheError::CacheDeserializationError { + cached_value: s, + error: e, + } + })?; + Ok(Some(v.value)) + } + } + } + + fn cache_remove(&self, key: &K) -> Result, RedisCacheError> { + let mut conn = self.pool.get()?; + let mut pipe = redis::pipe(); + let key = self.generate_key(key); + + pipe.get(key.clone()); + pipe.del::(key).ignore(); + let res: (Option,) = pipe.query(&mut *conn)?; + match res.0 { + None => Ok(None), + Some(s) => { + let v: CachedRedisValue = serde_json::from_str(&s).map_err(|e| { + RedisCacheError::CacheDeserializationError { + cached_value: s, + error: e, + } + })?; + Ok(Some(v.value)) + } + } + } + + fn cache_lifespan(&self) -> Option { + Some(self.seconds) + } + + fn cache_set_lifespan(&mut self, seconds: u64) -> Option { + let old = self.seconds; + self.seconds = seconds; + Some(old) + } + + fn cache_set_refresh(&mut self, refresh: bool) -> bool { + let old = self.refresh; + self.refresh = refresh; + old + } +} + +#[cfg(all( + feature = "async", + any(feature = "redis_async_std", feature = "redis_tokio") +))] +mod async_redis { + use super::{ + CachedRedisValue, DeserializeOwned, Display, PhantomData, RedisCacheBuildError, + RedisCacheError, Serialize, DEFAULT_NAMESPACE, ENV_KEY, + }; + use {crate::IOCachedAsync, async_trait::async_trait}; + + pub struct AsyncRedisCacheBuilder { + seconds: u64, + refresh: bool, + namespace: String, + prefix: String, + connection_string: Option, + _phantom: PhantomData<(K, V)>, + } + + impl AsyncRedisCacheBuilder + where + K: Display, + V: Serialize + DeserializeOwned, + { + /// Initialize a `RedisCacheBuilder` + pub fn new>(prefix: S, seconds: u64) -> AsyncRedisCacheBuilder { + Self { + seconds, + refresh: false, + namespace: DEFAULT_NAMESPACE.to_string(), + prefix: prefix.as_ref().to_string(), + connection_string: None, + _phantom: PhantomData, + } + } + + /// Specify the cache TTL/lifespan in seconds + #[must_use] + pub fn set_lifespan(mut self, seconds: u64) -> Self { + self.seconds = seconds; + self + } + + /// Specify whether cache hits refresh the TTL + #[must_use] + pub fn set_refresh(mut self, refresh: bool) -> Self { + self.refresh = refresh; + self + } + + /// Set the namespace for cache keys. Defaults to `cached-redis-store:`. + /// Used to generate keys formatted as: `{namespace}{prefix}{key}` + /// Note that no delimiters are implicitly added so you may pass + /// an empty string if you want there to be no namespace on keys. + #[must_use] + pub fn set_namespace>(mut self, namespace: S) -> Self { + self.namespace = namespace.as_ref().to_string(); + self + } + + /// Set the prefix for cache keys + /// Used to generate keys formatted as: `{namespace}{prefix}{key}` + /// Note that no delimiters are implicitly added so you may pass + /// an empty string if you want there to be no prefix on keys. + #[must_use] + pub fn set_prefix>(mut self, prefix: S) -> Self { + self.prefix = prefix.as_ref().to_string(); + self + } + + /// Set the connection string for redis + #[must_use] + pub fn set_connection_string(mut self, cs: &str) -> Self { + self.connection_string = Some(cs.to_string()); + self + } + + /// Return the current connection string or load from the env var: `CACHED_REDIS_CONNECTION_STRING` + /// + /// # Errors + /// + /// Will return `RedisCacheBuildError::MissingConnectionString` if connection string is not set + pub fn connection_string(&self) -> Result { + match self.connection_string { + Some(ref s) => Ok(s.to_string()), + None => std::env::var(ENV_KEY).map_err(|e| { + RedisCacheBuildError::MissingConnectionString { + env_key: ENV_KEY.to_string(), + error: e, + } + }), + } + } + + /// Create a multiplexed redis connection. This is a single connection that can + /// be used asynchronously by multiple futures. + #[cfg(not(feature = "redis_connection_manager"))] + async fn create_multiplexed_connection( + &self, + ) -> Result { + let s = self.connection_string()?; + let client = redis::Client::open(s)?; + let conn = client.get_multiplexed_async_connection().await?; + Ok(conn) + } + + /// Create a multiplexed connection wrapped in a manager. The manager provides access + /// to a multiplexed connection and will automatically reconnect to the server when + /// necessary. + #[cfg(feature = "redis_connection_manager")] + async fn create_connection_manager( + &self, + ) -> Result { + let s = self.connection_string()?; + let client = redis::Client::open(s)?; + let conn = redis::aio::ConnectionManager::new(client).await?; + Ok(conn) + } + + /// The last step in building a `RedisCache` is to call `build()` + /// + /// # Errors + /// + /// Will return a `RedisCacheBuildError`, depending on the error + pub async fn build(self) -> Result, RedisCacheBuildError> { + Ok(AsyncRedisCache { + seconds: self.seconds, + refresh: self.refresh, + connection_string: self.connection_string()?, + #[cfg(not(feature = "redis_connection_manager"))] + connection: self.create_multiplexed_connection().await?, + #[cfg(feature = "redis_connection_manager")] + connection: self.create_connection_manager().await?, + namespace: self.namespace, + prefix: self.prefix, + _phantom: PhantomData, + }) + } + } + + /// Cache store backed by redis + /// + /// Values have a ttl applied and enforced by redis. + /// Uses a `redis::aio::MultiplexedConnection` or `redis::aio::ConnectionManager` + /// under the hood depending if feature `redis_connection_manager` is used or not. + pub struct AsyncRedisCache { + pub(super) seconds: u64, + pub(super) refresh: bool, + pub(super) namespace: String, + pub(super) prefix: String, + connection_string: String, + #[cfg(not(feature = "redis_connection_manager"))] + connection: redis::aio::MultiplexedConnection, + #[cfg(feature = "redis_connection_manager")] + connection: redis::aio::ConnectionManager, + _phantom: PhantomData<(K, V)>, + } + + impl AsyncRedisCache + where + K: Display + Send + Sync, + V: Serialize + DeserializeOwned + Send + Sync, + { + #[allow(clippy::new_ret_no_self)] + /// Initialize an `AsyncRedisCacheBuilder` + pub fn new>(prefix: S, seconds: u64) -> AsyncRedisCacheBuilder { + AsyncRedisCacheBuilder::new(prefix, seconds) + } + + fn generate_key(&self, key: &K) -> String { + format!("{}{}{}", self.namespace, self.prefix, key) + } + + /// Return the redis connection string used + #[must_use] + pub fn connection_string(&self) -> String { + self.connection_string.clone() + } + } + + #[async_trait] + impl IOCachedAsync for AsyncRedisCache + where + K: Display + Send + Sync, + V: Serialize + DeserializeOwned + Send + Sync, + { + type Error = RedisCacheError; + + /// Get a cached value + async fn cache_get(&self, key: &K) -> Result, Self::Error> { + let mut conn = self.connection.clone(); + let mut pipe = redis::pipe(); + let key = self.generate_key(key); + + pipe.get(key.clone()); + if self.refresh { + pipe.expire(key, self.seconds as i64).ignore(); + } + let res: (Option,) = pipe.query_async(&mut conn).await?; + match res.0 { + None => Ok(None), + Some(s) => { + let v: CachedRedisValue = serde_json::from_str(&s).map_err(|e| { + RedisCacheError::CacheDeserializationError { + cached_value: s, + error: e, + } + })?; + Ok(Some(v.value)) + } + } + } + + /// Set a cached value + async fn cache_set(&self, key: K, val: V) -> Result, Self::Error> { + let mut conn = self.connection.clone(); + let mut pipe = redis::pipe(); + let key = self.generate_key(&key); + + let val = CachedRedisValue::new(val); + pipe.get(key.clone()); + pipe.set_ex::( + key, + serde_json::to_string(&val) + .map_err(|e| RedisCacheError::CacheSerializationError { error: e })?, + self.seconds, + ) + .ignore(); + + let res: (Option,) = pipe.query_async(&mut conn).await?; + match res.0 { + None => Ok(None), + Some(s) => { + let v: CachedRedisValue = serde_json::from_str(&s).map_err(|e| { + RedisCacheError::CacheDeserializationError { + cached_value: s, + error: e, + } + })?; + Ok(Some(v.value)) + } + } + } + + /// Remove a cached value + async fn cache_remove(&self, key: &K) -> Result, Self::Error> { + let mut conn = self.connection.clone(); + let mut pipe = redis::pipe(); + let key = self.generate_key(key); + + pipe.get(key.clone()); + pipe.del::(key).ignore(); + let res: (Option,) = pipe.query_async(&mut conn).await?; + match res.0 { + None => Ok(None), + Some(s) => { + let v: CachedRedisValue = serde_json::from_str(&s).map_err(|e| { + RedisCacheError::CacheDeserializationError { + cached_value: s, + error: e, + } + })?; + Ok(Some(v.value)) + } + } + } + + /// Set the flag to control whether cache hits refresh the ttl of cached values, returns the old flag value + fn cache_set_refresh(&mut self, refresh: bool) -> bool { + let old = self.refresh; + self.refresh = refresh; + old + } + + /// Return the lifespan of cached values (time to eviction) + fn cache_lifespan(&self) -> Option { + Some(self.seconds) + } + + /// Set the lifespan of cached values, returns the old value + fn cache_set_lifespan(&mut self, seconds: u64) -> Option { + let old = self.seconds; + self.seconds = seconds; + Some(old) + } + } + + #[cfg(test)] + mod tests { + use super::*; + use std::thread::sleep; + use std::time::Duration; + + fn now_millis() -> u128 { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_millis() + } + + #[tokio::test] + async fn test_async_redis_cache() { + let mut c: AsyncRedisCache = + AsyncRedisCache::new(format!("{}:async-redis-cache-test", now_millis()), 2) + .build() + .await + .unwrap(); + + assert!(c.cache_get(&1).await.unwrap().is_none()); + + assert!(c.cache_set(1, 100).await.unwrap().is_none()); + assert!(c.cache_get(&1).await.unwrap().is_some()); + + sleep(Duration::new(2, 500_000)); + assert!(c.cache_get(&1).await.unwrap().is_none()); + + let old = c.cache_set_lifespan(1).unwrap(); + assert_eq!(2, old); + assert!(c.cache_set(1, 100).await.unwrap().is_none()); + assert!(c.cache_get(&1).await.unwrap().is_some()); + + sleep(Duration::new(1, 600_000)); + assert!(c.cache_get(&1).await.unwrap().is_none()); + + c.cache_set_lifespan(10).unwrap(); + assert!(c.cache_set(1, 100).await.unwrap().is_none()); + assert!(c.cache_set(2, 100).await.unwrap().is_none()); + assert_eq!(c.cache_get(&1).await.unwrap().unwrap(), 100); + assert_eq!(c.cache_get(&1).await.unwrap().unwrap(), 100); + } + } +} + +#[cfg(all( + feature = "async", + any(feature = "redis_async_std", feature = "redis_tokio") +))] +#[cfg_attr( + docsrs, + doc(cfg(all( + feature = "async", + any(feature = "redis_async_std", feature = "redis_tokio") + ))) +)] +pub use async_redis::{AsyncRedisCache, AsyncRedisCacheBuilder}; + +#[cfg(test)] +/// Cache store tests +mod tests { + use std::thread::sleep; + use std::time::Duration; + + use super::*; + + fn now_millis() -> u128 { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_millis() + } + + #[test] + fn redis_cache() { + let mut c: RedisCache = + RedisCache::new(format!("{}:redis-cache-test", now_millis()), 2) + .set_namespace("in-tests:") + .build() + .unwrap(); + + assert!(c.cache_get(&1).unwrap().is_none()); + + assert!(c.cache_set(1, 100).unwrap().is_none()); + assert!(c.cache_get(&1).unwrap().is_some()); + + sleep(Duration::new(2, 500_000)); + assert!(c.cache_get(&1).unwrap().is_none()); + + let old = c.cache_set_lifespan(1).unwrap(); + assert_eq!(2, old); + assert!(c.cache_set(1, 100).unwrap().is_none()); + assert!(c.cache_get(&1).unwrap().is_some()); + + sleep(Duration::new(1, 600_000)); + assert!(c.cache_get(&1).unwrap().is_none()); + + c.cache_set_lifespan(10).unwrap(); + assert!(c.cache_set(1, 100).unwrap().is_none()); + assert!(c.cache_set(2, 100).unwrap().is_none()); + assert_eq!(c.cache_get(&1).unwrap().unwrap(), 100); + assert_eq!(c.cache_get(&1).unwrap().unwrap(), 100); + } + + #[test] + fn remove() { + let c: RedisCache = + RedisCache::new(format!("{}:redis-cache-test-remove", now_millis()), 3600) + .build() + .unwrap(); + + assert!(c.cache_set(1, 100).unwrap().is_none()); + assert!(c.cache_set(2, 200).unwrap().is_none()); + assert!(c.cache_set(3, 300).unwrap().is_none()); + + assert_eq!(100, c.cache_remove(&1).unwrap().unwrap()); + } +} diff --git a/vendor/cached/src/stores/sized.rs b/vendor/cached/src/stores/sized.rs new file mode 100644 index 0000000000000..d536bc79ab517 --- /dev/null +++ b/vendor/cached/src/stores/sized.rs @@ -0,0 +1,832 @@ +use super::Cached; +use crate::lru_list::LRUList; +use hashbrown::raw::RawTable; +use std::cmp::Eq; +use std::fmt; +use std::hash::{BuildHasher, Hash, Hasher}; + +#[cfg(feature = "ahash")] +use ahash::RandomState; + +#[cfg(not(feature = "ahash"))] +use std::collections::hash_map::RandomState; + +#[cfg(feature = "async")] +use {super::CachedAsync, async_trait::async_trait, futures::Future}; + +/// Least Recently Used / `Sized` Cache +/// +/// Stores up to a specified size before beginning +/// to evict the least recently used keys +/// +/// Note: This cache is in-memory only +#[derive(Clone)] +pub struct SizedCache { + // `store` contains a hash of K -> index of (K, V) tuple in `order` + pub(super) store: RawTable, + pub(super) hash_builder: RandomState, + pub(super) order: LRUList<(K, V)>, + pub(super) capacity: usize, + pub(super) hits: u64, + pub(super) misses: u64, +} + +impl fmt::Debug for SizedCache +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SizedCache") + .field("order", &self.order) + .field("capacity", &self.capacity) + .field("hits", &self.hits) + .field("misses", &self.misses) + .finish() + } +} + +impl PartialEq for SizedCache +where + K: Eq + Hash + Clone, + V: PartialEq, +{ + fn eq(&self, other: &SizedCache) -> bool { + self.store.len() == other.store.len() && { + self.order + .iter() + .all(|(key, value)| match other.get_index(other.hash(key), key) { + Some(i) => value == &other.order.get(i).1, + None => false, + }) + } + } +} + +impl Eq for SizedCache +where + K: Eq + Hash + Clone, + V: PartialEq, +{ +} + +impl SizedCache { + #[deprecated(since = "0.5.1", note = "method renamed to `with_size`")] + #[must_use] + pub fn with_capacity(size: usize) -> SizedCache { + Self::with_size(size) + } + + /// Creates a new `SizedCache` with a given size limit and pre-allocated backing data + /// + /// # Panics + /// + /// Will panic if size is 0 + #[must_use] + pub fn with_size(size: usize) -> SizedCache { + if size == 0 { + panic!("`size` of `SizedCache` must be greater than zero."); + } + SizedCache { + store: RawTable::with_capacity(size), + hash_builder: RandomState::new(), + order: LRUList::<(K, V)>::with_capacity(size), + capacity: size, + hits: 0, + misses: 0, + } + } + + /// Creates a new `SizedCache` with a given size limit and pre-allocated backing data + /// + /// # Errors + /// + /// Will return a `std::io::Error`, depending on the error + pub fn try_with_size(size: usize) -> std::io::Result> { + if size == 0 { + // EINVAL + return Err(std::io::Error::from_raw_os_error(22)); + } + + let store = match RawTable::try_with_capacity(size) { + Ok(store) => store, + Err(e) => { + let errcode = match e { + // ENOMEM + hashbrown::TryReserveError::AllocError { .. } => 12, + // EINVAL + hashbrown::TryReserveError::CapacityOverflow => 22, + }; + return Err(std::io::Error::from_raw_os_error(errcode)); + } + }; + + Ok(SizedCache { + store, + hash_builder: RandomState::new(), + order: LRUList::<(K, V)>::with_capacity(size), + capacity: size, + hits: 0, + misses: 0, + }) + } + + pub(super) fn iter_order(&self) -> impl Iterator { + self.order.iter() + } + + /// Return an iterator of keys in the current order from most + /// to least recently used. + pub fn key_order(&self) -> impl Iterator { + self.order.iter().map(|(k, _v)| k) + } + + /// Return an iterator of values in the current order from most + /// to least recently used. + pub fn value_order(&self) -> impl Iterator { + self.order.iter().map(|(_k, v)| v) + } + + fn hash(&self, key: &Q) -> u64 + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + let hasher = &mut self.hash_builder.build_hasher(); + key.hash(hasher); + hasher.finish() + } + + fn insert_index(&mut self, hash: u64, index: usize) { + let Self { + ref mut store, + ref order, + ref hash_builder, + .. + } = *self; + // insert the value `index` at `hash`, the closure provided + // is used to rehash values if a resize is necessary. + store.insert(hash, index, move |&i| { + // rehash the "key" value stored at index `i` - requires looking + // up the original "key" value in the `order` list. + let hasher = &mut hash_builder.build_hasher(); + order.get(i).0.hash(hasher); + hasher.finish() + }); + } + + fn get_index(&self, hash: u64, key: &Q) -> Option + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + let Self { store, order, .. } = self; + // Get the `order` index store under `hash`, the closure provided + // is used to compare against matching hashes - we lookup the original + // `key` value from the `order` list. + // This pattern is repeated in other lookup situations. + store + .get(hash, |&i| key == order.get(i).0.borrow()) + .copied() + } + + fn remove_index(&mut self, hash: u64, key: &Q) -> Option + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + let Self { store, order, .. } = self; + store.remove_entry(hash, |&i| key == order.get(i).0.borrow()) + } + + fn check_capacity(&mut self) { + let Self { + ref mut store, + ref mut order, + ref hash_builder, + capacity, + .. + } = *self; + let len = store.len(); + if len > capacity { + // store has reached capacity, evict the oldest item. + // store capacity cannot be zero, so there must be content in `self.order`. + let index = order.back(); + let key = &order.get(index).0; + let hasher = &mut hash_builder.build_hasher(); + key.hash(hasher); + let hash = hasher.finish(); + + let order_ = ℴ + let erased = store.erase_entry(hash, |&i| *key == order_.get(i).0); + assert!(erased, "SizedCache::cache_set failed evicting cache key"); + store.remove_entry(hash, |&i| *key == order_.get(i).0); + order.remove(index); + } + } + + pub(super) fn get_if bool, Q>(&mut self, key: &Q, is_valid: F) -> Option<&V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + if let Some(index) = self.get_index(self.hash(key), key) { + if is_valid(&self.order.get(index).1) { + self.order.move_to_front(index); + self.hits += 1; + return Some(&self.order.get(index).1); + } + } + self.misses += 1; + None + } + + pub(super) fn get_mut_if bool, Q>( + &mut self, + key: &Q, + is_valid: F, + ) -> Option<&mut V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + if let Some(index) = self.get_index(self.hash(key), key) { + if is_valid(&self.order.get(index).1) { + self.order.move_to_front(index); + self.hits += 1; + return Some(&mut self.order.get_mut(index).1); + } + } + self.misses += 1; + None + } + + /// Get the cached value, or set it using `f` if the value + /// is either not-set or if `is_valid` returns `false` for + /// the set value. + /// + /// Returns (`was_present`, `was_valid`, mut ref to set value) + /// `was_valid` will be false when `was_present` is false + pub(super) fn get_or_set_with_if V, FC: FnOnce(&V) -> bool>( + &mut self, + key: K, + f: F, + is_valid: FC, + ) -> (bool, bool, &mut V) { + let hash = self.hash(&key); + let index = self.get_index(hash, &key); + if let Some(index) = index { + self.hits += 1; + let replace_existing = { + let v = &self.order.get(index).1; + !is_valid(v) + }; + if replace_existing { + self.order.set(index, (key, f())); + } + self.order.move_to_front(index); + (true, !replace_existing, &mut self.order.get_mut(index).1) + } else { + self.misses += 1; + let index = self.order.push_front((key, f())); + self.insert_index(hash, index); + self.check_capacity(); + (false, false, &mut self.order.get_mut(index).1) + } + } + + #[allow(dead_code)] + fn try_get_or_set_with_if Result, FC: FnOnce(&V) -> bool>( + &mut self, + key: K, + f: F, + is_valid: FC, + ) -> Result<(bool, bool, &mut V), E> { + let hash = self.hash(&key); + let index = self.get_index(hash, &key); + if let Some(index) = index { + self.hits += 1; + let replace_existing = { + let v = &self.order.get(index).1; + !is_valid(v) + }; + if replace_existing { + self.order.set(index, (key, f()?)); + } + self.order.move_to_front(index); + Ok((true, !replace_existing, &mut self.order.get_mut(index).1)) + } else { + self.misses += 1; + let index = self.order.push_front((key, f()?)); + self.insert_index(hash, index); + self.check_capacity(); + Ok((false, false, &mut self.order.get_mut(index).1)) + } + } + + /// Returns a reference to the cache's `order` + #[must_use] + pub fn get_order(&self) -> &LRUList<(K, V)> { + &self.order + } + + pub fn retain bool>(&mut self, keep: F) { + let remove_keys = self + .iter_order() + .filter_map(|(k, v)| if keep(k, v) { None } else { Some(k.clone()) }) + .collect::>(); + for k in remove_keys { + self.cache_remove(&k); + } + } +} + +#[cfg(feature = "async")] +impl SizedCache +where + K: Hash + Eq + Clone + Send, +{ + /// Get the cached value, or set it using `f` if the value + /// is either not-set or if `is_valid` returns `false` for + /// the set value. + /// + /// Returns (`was_present`, `was_valid`, mut ref to set value) + /// `was_valid` will be false when `was_present` is false + pub(super) async fn get_or_set_with_if_async( + &mut self, + key: K, + f: F, + is_valid: FC, + ) -> (bool, bool, &mut V) + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future + Send, + FC: FnOnce(&V) -> bool, + { + let hash = self.hash(&key); + let index = self.get_index(hash, &key); + if let Some(index) = index { + self.hits += 1; + let replace_existing = { + let v = &self.order.get(index).1; + !is_valid(v) + }; + if replace_existing { + self.order.set(index, (key, f().await)); + } + self.order.move_to_front(index); + (true, !replace_existing, &mut self.order.get_mut(index).1) + } else { + self.misses += 1; + let index = self.order.push_front((key, f().await)); + self.insert_index(hash, index); + self.check_capacity(); + (false, false, &mut self.order.get_mut(index).1) + } + } + + pub(super) async fn try_get_or_set_with_if_async( + &mut self, + key: K, + f: F, + is_valid: FC, + ) -> Result<(bool, bool, &mut V), E> + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future> + Send, + FC: FnOnce(&V) -> bool, + { + let hash = self.hash(&key); + let index = self.get_index(hash, &key); + if let Some(index) = index { + self.hits += 1; + let replace_existing = { + let v = &self.order.get(index).1; + !is_valid(v) + }; + if replace_existing { + self.order.set(index, (key, f().await?)); + } + self.order.move_to_front(index); + Ok((true, !replace_existing, &mut self.order.get_mut(index).1)) + } else { + self.misses += 1; + let index = self.order.push_front((key, f().await?)); + self.insert_index(hash, index); + self.check_capacity(); + Ok((false, false, &mut self.order.get_mut(index).1)) + } + } +} + +impl Cached for SizedCache { + fn cache_get(&mut self, key: &Q) -> Option<&V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.get_if(key, |_| true) + } + + fn cache_get_mut(&mut self, key: &Q) -> std::option::Option<&mut V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.get_mut_if(key, |_| true) + } + + fn cache_set(&mut self, key: K, val: V) -> Option { + let hash = self.hash(&key); + let v = if let Some(index) = self.get_index(hash, &key) { + self.order.set(index, (key, val)).map(|(_, v)| v) + } else { + let index = self.order.push_front((key, val)); + self.insert_index(hash, index); + None + }; + self.check_capacity(); + v + } + + fn cache_get_or_set_with V>(&mut self, key: K, f: F) -> &mut V { + let (_, _, v) = self.get_or_set_with_if(key, f, |_| true); + v + } + + fn cache_remove(&mut self, k: &Q) -> Option + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + // try and remove item from mapping, and then from order list if it was in mapping + let hash = self.hash(k); + if let Some(index) = self.remove_index(hash, k) { + // need to remove the key in the order list + let (_key, value) = self.order.remove(index); + Some(value) + } else { + None + } + } + fn cache_clear(&mut self) { + // clear both the store and the order list + self.store.clear(); + self.order.clear(); + } + fn cache_reset(&mut self) { + // SizedCache uses cache_clear because capacity is fixed. + self.cache_clear(); + } + fn cache_reset_metrics(&mut self) { + self.misses = 0; + self.hits = 0; + } + fn cache_size(&self) -> usize { + self.store.len() + } + fn cache_hits(&self) -> Option { + Some(self.hits) + } + fn cache_misses(&self) -> Option { + Some(self.misses) + } + fn cache_capacity(&self) -> Option { + Some(self.capacity) + } +} + +#[cfg(feature = "async")] +#[async_trait] +impl CachedAsync for SizedCache +where + K: Hash + Eq + Clone + Send, +{ + async fn get_or_set_with(&mut self, k: K, f: F) -> &mut V + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future + Send, + { + let (_, _, v) = self.get_or_set_with_if_async(k, f, |_| true).await; + v + } + + async fn try_get_or_set_with(&mut self, k: K, f: F) -> Result<&mut V, E> + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future> + Send, + { + let (_, _, v) = self.try_get_or_set_with_if_async(k, f, |_| true).await?; + Ok(v) + } +} + +#[cfg(test)] +/// Cache store tests +mod tests { + use super::*; + + #[test] + fn sized_cache() { + let mut c = SizedCache::with_size(5); + assert!(c.cache_get(&1).is_none()); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, misses); + + assert_eq!(c.cache_set(1, 100), None); + assert!(c.cache_get(&1).is_some()); + let hits = c.cache_hits().unwrap(); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, hits); + assert_eq!(1, misses); + + assert_eq!(c.cache_set(2, 100), None); + assert_eq!(c.cache_set(3, 100), None); + assert_eq!(c.cache_set(4, 100), None); + assert_eq!(c.cache_set(5, 100), None); + + assert_eq!(c.key_order().copied().collect::>(), [5, 4, 3, 2, 1]); + + assert_eq!(c.cache_set(6, 100), None); + assert_eq!(c.cache_set(7, 100), None); + + assert_eq!(c.key_order().copied().collect::>(), [7, 6, 5, 4, 3]); + + assert!(c.cache_get(&2).is_none()); + assert!(c.cache_get(&3).is_some()); + + assert_eq!(c.key_order().copied().collect::>(), [3, 7, 6, 5, 4]); + + assert_eq!(2, c.cache_misses().unwrap()); + let size = c.cache_size(); + assert_eq!(5, size); + + c.cache_reset_metrics(); + let hits = c.cache_hits().unwrap(); + let misses = c.cache_misses().unwrap(); + let size = c.cache_size(); + assert_eq!(0, hits); + assert_eq!(0, misses); + assert_eq!(5, size); + + assert_eq!(c.cache_set(7, 200), Some(100)); + + #[derive(Hash, Clone, Eq, PartialEq)] + struct MyKey { + v: String, + } + let mut c = SizedCache::with_size(5); + assert_eq!( + c.cache_set( + MyKey { + v: String::from("s") + }, + String::from("a") + ), + None + ); + assert_eq!( + c.cache_set( + MyKey { + v: String::from("s") + }, + String::from("a") + ), + Some(String::from("a")) + ); + assert_eq!( + c.cache_set( + MyKey { + v: String::from("s2") + }, + String::from("b") + ), + None + ); + assert_eq!( + c.cache_set( + MyKey { + v: String::from("s2") + }, + String::from("b") + ), + Some(String::from("b")) + ); + } + + #[test] + fn try_new() { + let c: std::io::Result> = SizedCache::try_with_size(0); + assert_eq!(c.unwrap_err().raw_os_error(), Some(22)); + } + + #[test] + /// This is a regression test to confirm that racing cache sets on a `SizedCache` + /// do not cause duplicates to exist in the internal `order`. See issue #7 + fn size_cache_racing_keys_eviction_regression() { + let mut c = SizedCache::with_size(2); + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(1, 100), Some(100)); + // size would be 1, but internal ordered would be [1, 1] + assert_eq!(c.cache_set(2, 100), None); + assert_eq!(c.cache_set(3, 100), None); + // this next set would fail because a duplicate key would be evicted + assert_eq!(c.cache_set(4, 100), None); + } + + #[test] + fn clear() { + let mut c = SizedCache::with_size(3); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + c.cache_clear(); + + assert_eq!(0, c.cache_size()); + } + + #[test] + fn reset() { + let init_capacity = 1; + let mut c = SizedCache::with_size(init_capacity); + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + assert!(init_capacity <= c.store.capacity()); + + c.cache_reset(); + + assert!(init_capacity <= c.store.capacity()); + } + + #[test] + fn remove() { + let mut c = SizedCache::with_size(3); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + + assert_eq!(Some(100), c.cache_remove(&1)); + assert_eq!(2, c.cache_size()); + + assert_eq!(Some(200), c.cache_remove(&2)); + assert_eq!(1, c.cache_size()); + + assert_eq!(None, c.cache_remove(&2)); + assert_eq!(1, c.cache_size()); + + assert_eq!(Some(300), c.cache_remove(&3)); + assert_eq!(0, c.cache_size()); + } + + #[test] + fn sized_cache_get_mut() { + let mut c = SizedCache::with_size(5); + assert!(c.cache_get_mut(&1).is_none()); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, misses); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(*c.cache_get_mut(&1).unwrap(), 100); + let hits = c.cache_hits().unwrap(); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, hits); + assert_eq!(1, misses); + + let value = c.cache_get_mut(&1).unwrap(); + *value = 10; + + let hits = c.cache_hits().unwrap(); + let misses = c.cache_misses().unwrap(); + assert_eq!(2, hits); + assert_eq!(1, misses); + assert_eq!(*c.cache_get_mut(&1).unwrap(), 10); + } + + #[test] + fn sized_cache_eviction_fix() { + let mut cache = SizedCache::::with_size(3); + + cache.cache_set(1, ()); + cache.cache_set(2, ()); + cache.cache_set(3, ()); + + assert!(cache.cache_get(&1).is_some()); + assert!(cache.cache_get(&2).is_some()); + assert!(cache.cache_get(&3).is_some()); + assert!(cache.cache_get(&4).is_none()); + + // previous bug: inserting the same key multiple times would continue + // to evict the oldest cache member + cache.cache_set(4, ()); + assert_eq!(cache.cache_size(), 3); + cache.cache_set(4, ()); + assert_eq!(cache.cache_size(), 3); // previously failed, returning 2 + + assert!(cache.cache_get(&1).is_none()); // 1 is evicted by first "4" insert + assert!(cache.cache_get(&2).is_some()); // previously failed, 2 would be evicted by second "4" insert + assert!(cache.cache_get(&3).is_some()); + assert!(cache.cache_get(&4).is_some()); + } + + #[test] + fn get_or_set_with() { + let mut c = SizedCache::with_size(5); + + assert_eq!(c.cache_get_or_set_with(0, || 0), &0); + assert_eq!(c.cache_get_or_set_with(1, || 1), &1); + assert_eq!(c.cache_get_or_set_with(2, || 2), &2); + assert_eq!(c.cache_get_or_set_with(3, || 3), &3); + assert_eq!(c.cache_get_or_set_with(4, || 4), &4); + assert_eq!(c.cache_get_or_set_with(5, || 5), &5); + + assert_eq!(c.cache_misses(), Some(6)); + + assert_eq!(c.cache_get_or_set_with(0, || 0), &0); + + assert_eq!(c.cache_misses(), Some(7)); + + assert_eq!(c.cache_get_or_set_with(0, || 42), &0); + + assert_eq!(c.cache_misses(), Some(7)); + + assert_eq!(c.cache_get_or_set_with(1, || 1), &1); + + assert_eq!(c.cache_misses(), Some(8)); + } + + #[cfg(feature = "async")] + #[tokio::test] + async fn test_async_trait() { + use crate::CachedAsync; + let mut c = SizedCache::with_size(5); + + async fn _get(n: usize) -> usize { + n + } + + assert_eq!(c.get_or_set_with(0, || async { _get(0).await }).await, &0); + assert_eq!(c.get_or_set_with(1, || async { _get(1).await }).await, &1); + assert_eq!(c.get_or_set_with(2, || async { _get(2).await }).await, &2); + assert_eq!(c.get_or_set_with(3, || async { _get(3).await }).await, &3); + + assert_eq!(c.get_or_set_with(0, || async { _get(3).await }).await, &0); + assert_eq!(c.get_or_set_with(1, || async { _get(3).await }).await, &1); + assert_eq!(c.get_or_set_with(2, || async { _get(3).await }).await, &2); + assert_eq!(c.get_or_set_with(3, || async { _get(1).await }).await, &3); + + c.cache_reset(); + async fn _try_get(n: usize) -> Result { + if n < 10 { + Ok(n) + } else { + Err("dead".to_string()) + } + } + + assert_eq!( + c.try_get_or_set_with(0, || async { + match _try_get(0).await { + Ok(n) => Ok(n), + Err(_) => Err("err".to_string()), + } + }) + .await + .unwrap(), + &0 + ); + assert_eq!( + c.try_get_or_set_with(0, || async { + match _try_get(5).await { + Ok(n) => Ok(n), + Err(_) => Err("err".to_string()), + } + }) + .await + .unwrap(), + &0 + ); + + c.cache_reset(); + let res: Result<&mut usize, String> = c + .try_get_or_set_with(0, || async { _try_get(10).await }) + .await; + assert!(res.is_err()); + assert!(c.key_order().next().is_none()); + + let res: Result<&mut usize, String> = c + .try_get_or_set_with(0, || async { _try_get(1).await }) + .await; + assert_eq!(res.unwrap(), &1); + let res: Result<&mut usize, String> = c + .try_get_or_set_with(0, || async { _try_get(5).await }) + .await; + assert_eq!(res.unwrap(), &1); + } +} diff --git a/vendor/cached/src/stores/timed.rs b/vendor/cached/src/stores/timed.rs new file mode 100644 index 0000000000000..f7ffe47de6417 --- /dev/null +++ b/vendor/cached/src/stores/timed.rs @@ -0,0 +1,543 @@ +use instant::Instant; +use std::cmp::Eq; +use std::hash::Hash; + +#[cfg(feature = "ahash")] +use hashbrown::{hash_map::Entry, HashMap}; + +#[cfg(not(feature = "ahash"))] +use std::collections::{hash_map::Entry, HashMap}; + +#[cfg(feature = "async")] +use {super::CachedAsync, async_trait::async_trait, futures::Future}; + +use crate::CloneCached; + +use super::Cached; + +/// Enum used for defining the status of time-cached values +#[derive(Debug)] +pub(super) enum Status { + NotFound, + Found, + Expired, +} + +/// Cache store bound by time +/// +/// Values are timestamped when inserted and are +/// evicted if expired at time of retrieval. +/// +/// Note: This cache is in-memory only +#[derive(Clone, Debug)] +pub struct TimedCache { + pub(super) store: HashMap, + pub(super) seconds: u64, + pub(super) hits: u64, + pub(super) misses: u64, + pub(super) initial_capacity: Option, + pub(super) refresh: bool, +} + +impl TimedCache { + /// Creates a new `TimedCache` with a specified lifespan + #[must_use] + pub fn with_lifespan(seconds: u64) -> TimedCache { + Self::with_lifespan_and_refresh(seconds, false) + } + + /// Creates a new `TimedCache` with a specified lifespan and + /// cache-store with the specified pre-allocated capacity + #[must_use] + pub fn with_lifespan_and_capacity(seconds: u64, size: usize) -> TimedCache { + TimedCache { + store: Self::new_store(Some(size)), + seconds, + hits: 0, + misses: 0, + initial_capacity: Some(size), + refresh: false, + } + } + + /// Creates a new `TimedCache` with a specified lifespan which + /// refreshes the ttl when the entry is retrieved + #[must_use] + pub fn with_lifespan_and_refresh(seconds: u64, refresh: bool) -> TimedCache { + TimedCache { + store: Self::new_store(None), + seconds, + hits: 0, + misses: 0, + initial_capacity: None, + refresh, + } + } + + /// Returns if the lifetime is refreshed when the value is retrieved + #[must_use] + pub fn refresh(&self) -> bool { + self.refresh + } + + /// Sets if the lifetime is refreshed when the value is retrieved + pub fn set_refresh(&mut self, refresh: bool) { + self.refresh = refresh; + } + + fn new_store(capacity: Option) -> HashMap { + capacity.map_or_else(HashMap::new, HashMap::with_capacity) + } + + /// Returns a reference to the cache's `store` + #[must_use] + pub fn get_store(&self) -> &HashMap { + &self.store + } + + /// Remove any expired values from the cache + pub fn flush(&mut self) { + let seconds = self.seconds; + self.store + .retain(|_, (instant, _)| instant.elapsed().as_secs() < seconds); + } + + fn status(&mut self, key: &Q) -> Status + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + let mut val = self.store.get_mut(key); + if let Some(&mut (instant, _)) = val.as_mut() { + if instant.elapsed().as_secs() < self.seconds { + if self.refresh { + *instant = Instant::now(); + } + Status::Found + } else { + Status::Expired + } + } else { + Status::NotFound + } + } +} + +impl Cached for TimedCache { + fn cache_get(&mut self, key: &Q) -> Option<&V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + match self.status(key) { + Status::NotFound => { + self.misses += 1; + None + } + Status::Found => { + self.hits += 1; + self.store.get(key).map(|stamped| &stamped.1) + } + Status::Expired => { + self.misses += 1; + self.store.remove(key).unwrap(); + None + } + } + } + + fn cache_get_mut(&mut self, key: &Q) -> Option<&mut V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + match self.status(key) { + Status::NotFound => { + self.misses += 1; + None + } + Status::Found => { + self.hits += 1; + self.store.get_mut(key).map(|stamped| &mut stamped.1) + } + Status::Expired => { + self.misses += 1; + self.store.remove(key).unwrap(); + None + } + } + } + + fn cache_get_or_set_with V>(&mut self, key: K, f: F) -> &mut V { + match self.store.entry(key) { + Entry::Occupied(mut occupied) => { + if occupied.get().0.elapsed().as_secs() < self.seconds { + if self.refresh { + occupied.get_mut().0 = Instant::now(); + } + self.hits += 1; + } else { + self.misses += 1; + let val = f(); + occupied.insert((Instant::now(), val)); + } + &mut occupied.into_mut().1 + } + Entry::Vacant(vacant) => { + self.misses += 1; + let val = f(); + &mut vacant.insert((Instant::now(), val)).1 + } + } + } + + fn cache_set(&mut self, key: K, val: V) -> Option { + let stamped = (Instant::now(), val); + self.store.insert(key, stamped).and_then(|(instant, v)| { + if instant.elapsed().as_secs() < self.seconds { + Some(v) + } else { + None + } + }) + } + fn cache_remove(&mut self, k: &Q) -> Option + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.store.remove(k).and_then(|(instant, v)| { + if instant.elapsed().as_secs() < self.seconds { + Some(v) + } else { + None + } + }) + } + fn cache_clear(&mut self) { + self.store.clear(); + } + fn cache_reset_metrics(&mut self) { + self.misses = 0; + self.hits = 0; + } + fn cache_reset(&mut self) { + self.store = Self::new_store(self.initial_capacity); + } + fn cache_size(&self) -> usize { + self.store.len() + } + fn cache_hits(&self) -> Option { + Some(self.hits) + } + fn cache_misses(&self) -> Option { + Some(self.misses) + } + fn cache_lifespan(&self) -> Option { + Some(self.seconds) + } + + fn cache_set_lifespan(&mut self, seconds: u64) -> Option { + let old = self.seconds; + self.seconds = seconds; + Some(old) + } +} + +impl CloneCached for TimedCache { + fn cache_get_expired(&mut self, k: &Q) -> (Option, bool) + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + match self.status(k) { + Status::NotFound => { + self.misses += 1; + (None, false) + } + Status::Found => { + self.hits += 1; + (self.store.get(k).map(|stamped| &stamped.1).cloned(), false) + } + Status::Expired => { + self.misses += 1; + (self.store.remove(k).map(|stamped| stamped.1), true) + } + } + } +} + +#[cfg(feature = "async")] +#[async_trait] +impl CachedAsync for TimedCache +where + K: Hash + Eq + Clone + Send, +{ + async fn get_or_set_with(&mut self, k: K, f: F) -> &mut V + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future + Send, + { + match self.store.entry(k) { + Entry::Occupied(mut occupied) => { + if occupied.get().0.elapsed().as_secs() < self.seconds { + if self.refresh { + occupied.get_mut().0 = Instant::now(); + } + self.hits += 1; + } else { + self.misses += 1; + occupied.insert((Instant::now(), f().await)); + } + &mut occupied.into_mut().1 + } + Entry::Vacant(vacant) => { + self.misses += 1; + &mut vacant.insert((Instant::now(), f().await)).1 + } + } + } + + async fn try_get_or_set_with(&mut self, k: K, f: F) -> Result<&mut V, E> + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future> + Send, + { + let v = match self.store.entry(k) { + Entry::Occupied(mut occupied) => { + if occupied.get().0.elapsed().as_secs() < self.seconds { + if self.refresh { + occupied.get_mut().0 = Instant::now(); + } + self.hits += 1; + } else { + self.misses += 1; + occupied.insert((Instant::now(), f().await?)); + } + &mut occupied.into_mut().1 + } + Entry::Vacant(vacant) => { + self.misses += 1; + &mut vacant.insert((Instant::now(), f().await?)).1 + } + }; + + Ok(v) + } +} + +#[cfg(test)] +/// Cache store tests +mod tests { + use std::{thread::sleep, time::Duration}; + + use super::*; + + #[test] + fn timed_cache() { + let mut c = TimedCache::with_lifespan(2); + assert!(c.cache_get(&1).is_none()); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, misses); + + assert_eq!(c.cache_set(1, 100), None); + assert!(c.cache_get(&1).is_some()); + let hits = c.cache_hits().unwrap(); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, hits); + assert_eq!(1, misses); + + sleep(Duration::new(2, 0)); + assert!(c.cache_get(&1).is_none()); + let misses = c.cache_misses().unwrap(); + assert_eq!(2, misses); + + let old = c.cache_set_lifespan(1).unwrap(); + assert_eq!(2, old); + assert_eq!(c.cache_set(1, 100), None); + assert!(c.cache_get(&1).is_some()); + let hits = c.cache_hits().unwrap(); + let misses = c.cache_misses().unwrap(); + assert_eq!(2, hits); + assert_eq!(2, misses); + + sleep(Duration::new(1, 0)); + assert!(c.cache_get(&1).is_none()); + let misses = c.cache_misses().unwrap(); + assert_eq!(3, misses); + } + + #[test] + fn timed_cache_refresh() { + let mut c = TimedCache::with_lifespan_and_refresh(2, true); + assert!(c.refresh()); + assert_eq!(c.cache_get(&1), None); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, misses); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_get(&1), Some(&100)); + let hits = c.cache_hits().unwrap(); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, hits); + assert_eq!(1, misses); + + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_get(&2), Some(&200)); + sleep(Duration::new(1, 0)); + assert_eq!(c.cache_get(&1), Some(&100)); + sleep(Duration::new(1, 0)); + assert_eq!(c.cache_get(&1), Some(&100)); + assert_eq!(c.cache_get(&2), None); + } + + #[test] + fn clear() { + let mut c = TimedCache::with_lifespan(3600); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + c.cache_clear(); + + assert_eq!(0, c.cache_size()); + } + + #[test] + fn reset() { + let mut c = TimedCache::with_lifespan(100); + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + assert!(3 <= c.store.capacity()); + + c.cache_reset(); + + assert_eq!(0, c.store.capacity()); + + let init_capacity = 1; + let mut c = TimedCache::with_lifespan_and_capacity(100, init_capacity); + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + assert!(3 <= c.store.capacity()); + + c.cache_reset(); + + assert!(init_capacity <= c.store.capacity()); + } + + #[test] + fn remove() { + let mut c = TimedCache::with_lifespan(3600); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + + assert_eq!(Some(100), c.cache_remove(&1)); + assert_eq!(2, c.cache_size()); + } + + #[test] + fn remove_expired() { + let mut c = TimedCache::with_lifespan(1); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(1, 200), Some(100)); + assert_eq!(c.cache_size(), 1); + + std::thread::sleep(std::time::Duration::from_secs(1)); + assert_eq!(None, c.cache_remove(&1)); + assert_eq!(0, c.cache_size()); + } + + #[test] + fn insert_expired() { + let mut c = TimedCache::with_lifespan(1); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(1, 200), Some(100)); + assert_eq!(c.cache_size(), 1); + + std::thread::sleep(std::time::Duration::from_secs(1)); + assert_eq!(1, c.cache_size()); + assert_eq!(None, c.cache_set(1, 300)); + assert_eq!(1, c.cache_size()); + } + + #[test] + fn get_expired() { + let mut c = TimedCache::with_lifespan(1); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(1, 200), Some(100)); + assert_eq!(c.cache_size(), 1); + + std::thread::sleep(std::time::Duration::from_secs(1)); + // still around until we try to get + assert_eq!(1, c.cache_size()); + assert_eq!(None, c.cache_get(&1)); + assert_eq!(0, c.cache_size()); + } + + #[test] + fn get_mut_expired() { + let mut c = TimedCache::with_lifespan(1); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(1, 200), Some(100)); + assert_eq!(c.cache_size(), 1); + + std::thread::sleep(std::time::Duration::from_secs(1)); + // still around until we try to get + assert_eq!(1, c.cache_size()); + assert_eq!(None, c.cache_get_mut(&1)); + assert_eq!(0, c.cache_size()); + } + + #[test] + fn flush_expired() { + let mut c = TimedCache::with_lifespan(1); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(1, 200), Some(100)); + assert_eq!(c.cache_size(), 1); + + std::thread::sleep(std::time::Duration::from_secs(1)); + // still around until we flush + assert_eq!(1, c.cache_size()); + c.flush(); + assert_eq!(0, c.cache_size()); + } + + #[test] + fn get_or_set_with() { + let mut c = TimedCache::with_lifespan(2); + + assert_eq!(c.cache_get_or_set_with(0, || 0), &0); + assert_eq!(c.cache_get_or_set_with(1, || 1), &1); + assert_eq!(c.cache_get_or_set_with(2, || 2), &2); + assert_eq!(c.cache_get_or_set_with(3, || 3), &3); + assert_eq!(c.cache_get_or_set_with(4, || 4), &4); + assert_eq!(c.cache_get_or_set_with(5, || 5), &5); + + assert_eq!(c.cache_misses(), Some(6)); + + assert_eq!(c.cache_get_or_set_with(0, || 0), &0); + + assert_eq!(c.cache_misses(), Some(6)); + + assert_eq!(c.cache_get_or_set_with(0, || 42), &0); + + assert_eq!(c.cache_misses(), Some(6)); + + sleep(Duration::new(2, 0)); + + assert_eq!(c.cache_get_or_set_with(1, || 42), &42); + + assert_eq!(c.cache_misses(), Some(7)); + } +} diff --git a/vendor/cached/src/stores/timed_sized.rs b/vendor/cached/src/stores/timed_sized.rs new file mode 100644 index 0000000000000..5f0e24828aaa0 --- /dev/null +++ b/vendor/cached/src/stores/timed_sized.rs @@ -0,0 +1,716 @@ +use std::cmp::Eq; +use std::hash::Hash; + +use instant::Instant; + +#[cfg(feature = "async")] +use {super::CachedAsync, async_trait::async_trait, futures::Future}; + +use crate::{stores::timed::Status, CloneCached}; + +use super::{Cached, SizedCache}; + +/// Timed LRU Cache +/// +/// Stores a limited number of values, +/// evicting expired and least-used entries. +/// Time expiration is determined based on entry insertion time.. +/// The TTL of an entry is not updated when retrieved. +/// +/// Note: This cache is in-memory only +#[derive(Clone, Debug)] +pub struct TimedSizedCache { + pub(super) store: SizedCache, + pub(super) size: usize, + pub(super) seconds: u64, + pub(super) hits: u64, + pub(super) misses: u64, + pub(super) refresh: bool, +} + +impl TimedSizedCache { + /// Creates a new `SizedCache` with a given size limit and pre-allocated backing data + #[must_use] + pub fn with_size_and_lifespan(size: usize, seconds: u64) -> TimedSizedCache { + Self::with_size_and_lifespan_and_refresh(size, seconds, false) + } + + /// Creates a new `SizedCache` with a given size limit and pre-allocated backing data. + /// Also set if the ttl should be refreshed on retrieving + /// + /// # Panics + /// + /// Will panic if size is 0 + #[must_use] + pub fn with_size_and_lifespan_and_refresh( + size: usize, + seconds: u64, + refresh: bool, + ) -> TimedSizedCache { + if size == 0 { + panic!("`size` of `TimedSizedCache` must be greater than zero."); + } + TimedSizedCache { + store: SizedCache::with_size(size), + size, + seconds, + hits: 0, + misses: 0, + refresh, + } + } + + /// Creates a new `TimedSizedCache` with a specified lifespan and a given size limit and pre-allocated backing data + /// + /// # Errors + /// + /// Will return a `std::io::Error`, depending on the error + pub fn try_with_size_and_lifespan( + size: usize, + seconds: u64, + ) -> std::io::Result> { + if size == 0 { + // EINVAL + return Err(std::io::Error::from_raw_os_error(22)); + } + Ok(TimedSizedCache { + store: SizedCache::try_with_size(size)?, + size, + seconds, + hits: 0, + misses: 0, + refresh: false, + }) + } + + fn iter_order(&self) -> impl Iterator { + let max_seconds = self.seconds; + self.store + .iter_order() + .filter(move |(_k, stamped)| stamped.0.elapsed().as_secs() < max_seconds) + } + + /// Return an iterator of keys in the current order from most + /// to least recently used. + /// Items passed their expiration seconds will be excluded. + pub fn key_order(&self) -> impl Iterator { + self.iter_order().map(|(k, _v)| k) + } + + /// Return an iterator of timestamped values in the current order + /// from most to least recently used. + /// Items passed their expiration seconds will be excluded. + pub fn value_order(&self) -> impl Iterator { + self.iter_order().map(|(_k, v)| v) + } + + /// Returns if the lifetime is refreshed when the value is retrieved + #[must_use] + pub fn refresh(&self) -> bool { + self.refresh + } + + /// Sets if the lifetime is refreshed when the value is retrieved + pub fn set_refresh(&mut self, refresh: bool) { + self.refresh = refresh; + } + + /// Returns a reference to the cache's `store` + #[must_use] + pub fn get_store(&self) -> &SizedCache { + &self.store + } + + /// Remove any expired values from the cache + pub fn flush(&mut self) { + let seconds = self.seconds; + self.store + .retain(|_, (instant, _)| instant.elapsed().as_secs() < seconds); + } + + fn status(&mut self, key: &Q) -> Status + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + let mut val = self.store.get_mut_if(key, |_| true); + if let Some(&mut (instant, _)) = val.as_mut() { + if instant.elapsed().as_secs() < self.seconds { + if self.refresh { + *instant = Instant::now(); + } + Status::Found + } else { + Status::Expired + } + } else { + Status::NotFound + } + } +} + +impl Cached for TimedSizedCache { + fn cache_get(&mut self, key: &Q) -> Option<&V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + match self.status(key) { + Status::NotFound => { + self.misses += 1; + None + } + Status::Found => { + self.hits += 1; + self.store.cache_get(key).map(|stamped| &stamped.1) + } + Status::Expired => { + self.misses += 1; + self.store.cache_remove(key); + None + } + } + } + + fn cache_get_mut(&mut self, key: &Q) -> std::option::Option<&mut V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + match self.status(key) { + Status::NotFound => { + self.misses += 1; + None + } + Status::Found => { + self.hits += 1; + self.store.cache_get_mut(key).map(|stamped| &mut stamped.1) + } + Status::Expired => { + self.misses += 1; + self.store.cache_remove(key); + None + } + } + } + + fn cache_get_or_set_with V>(&mut self, key: K, f: F) -> &mut V { + let setter = || (Instant::now(), f()); + let max_seconds = self.seconds; + let (was_present, was_valid, stamped) = + self.store.get_or_set_with_if(key, setter, |stamped| { + stamped.0.elapsed().as_secs() < max_seconds + }); + if was_present && was_valid { + if self.refresh { + stamped.0 = Instant::now(); + } + self.hits += 1; + } else { + self.misses += 1; + } + &mut stamped.1 + } + + fn cache_set(&mut self, key: K, val: V) -> Option { + let stamped = self.store.cache_set(key, (Instant::now(), val)); + stamped.and_then(|(instant, v)| { + if instant.elapsed().as_secs() < self.seconds { + Some(v) + } else { + None + } + }) + } + + fn cache_remove(&mut self, k: &Q) -> Option + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + let stamped = self.store.cache_remove(k); + stamped.and_then(|(instant, v)| { + if instant.elapsed().as_secs() < self.seconds { + Some(v) + } else { + None + } + }) + } + fn cache_clear(&mut self) { + self.store.cache_clear(); + } + fn cache_reset(&mut self) { + self.cache_clear(); + } + fn cache_reset_metrics(&mut self) { + self.misses = 0; + self.hits = 0; + } + fn cache_size(&self) -> usize { + self.store.cache_size() + } + fn cache_hits(&self) -> Option { + Some(self.hits) + } + fn cache_misses(&self) -> Option { + Some(self.misses) + } + fn cache_capacity(&self) -> Option { + Some(self.size) + } + fn cache_lifespan(&self) -> Option { + Some(self.seconds) + } + fn cache_set_lifespan(&mut self, seconds: u64) -> Option { + let old = self.seconds; + self.seconds = seconds; + Some(old) + } +} + +impl CloneCached for TimedSizedCache { + fn cache_get_expired(&mut self, k: &Q) -> (Option, bool) + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + match self.status(k) { + Status::NotFound => { + self.misses += 1; + (None, false) + } + Status::Found => { + self.hits += 1; + ( + self.store.cache_get(k).map(|stamped| stamped.1.clone()), + false, + ) + } + Status::Expired => { + self.misses += 1; + (self.store.cache_remove(k).map(|stamped| stamped.1), true) + } + } + } +} + +#[cfg(feature = "async")] +#[async_trait] +impl CachedAsync for TimedSizedCache +where + K: Hash + Eq + Clone + Send, +{ + async fn get_or_set_with(&mut self, key: K, f: F) -> &mut V + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future + Send, + { + let setter = || async { (Instant::now(), f().await) }; + let max_seconds = self.seconds; + let (was_present, was_valid, stamped) = self + .store + .get_or_set_with_if_async(key, setter, |stamped| { + stamped.0.elapsed().as_secs() < max_seconds + }) + .await; + if was_present && was_valid { + if self.refresh { + stamped.0 = Instant::now(); + } + self.hits += 1; + } else { + self.misses += 1; + } + &mut stamped.1 + } + + async fn try_get_or_set_with(&mut self, key: K, f: F) -> Result<&mut V, E> + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future> + Send, + { + let setter = || async { + let new_val = f().await?; + Ok((Instant::now(), new_val)) + }; + let max_seconds = self.seconds; + let (was_present, was_valid, stamped) = self + .store + .try_get_or_set_with_if_async(key, setter, |stamped| { + stamped.0.elapsed().as_secs() < max_seconds + }) + .await?; + if was_present && was_valid { + if self.refresh { + stamped.0 = Instant::now(); + } + self.hits += 1; + } else { + self.misses += 1; + } + Ok(&mut stamped.1) + } +} + +#[cfg(test)] +/// Cache store tests +mod tests { + use std::{thread::sleep, time::Duration}; + + use super::*; + + #[test] + fn timed_sized_cache() { + let mut c = TimedSizedCache::with_size_and_lifespan(5, 2); + assert!(c.cache_get(&1).is_none()); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, misses); + + assert_eq!(c.cache_set(1, 100), None); + assert!(c.cache_get(&1).is_some()); + let hits = c.cache_hits().unwrap(); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, hits); + assert_eq!(1, misses); + + assert_eq!(c.cache_set(2, 100), None); + assert_eq!(c.cache_set(3, 100), None); + assert_eq!(c.cache_set(4, 100), None); + assert_eq!(c.cache_set(5, 100), None); + + assert_eq!(c.key_order().copied().collect::>(), [5, 4, 3, 2, 1]); + + sleep(Duration::new(1, 0)); + + assert_eq!(c.cache_set(6, 100), None); + assert_eq!(c.cache_set(7, 100), None); + + assert_eq!(c.key_order().copied().collect::>(), [7, 6, 5, 4, 3]); + + assert!(c.cache_get(&2).is_none()); + assert!(c.cache_get(&3).is_some()); + + assert_eq!(c.key_order().copied().collect::>(), [3, 7, 6, 5, 4]); + + assert_eq!(2, c.cache_misses().unwrap()); + assert_eq!(5, c.cache_size()); + + sleep(Duration::new(1, 0)); + + assert!(c.cache_get(&1).is_none()); + assert!(c.cache_get(&2).is_none()); + assert!(c.cache_get(&3).is_none()); + assert!(c.cache_get(&4).is_none()); + assert!(c.cache_get(&5).is_none()); + assert!(c.cache_get(&6).is_some()); + assert!(c.cache_get(&7).is_some()); + + assert_eq!(7, c.cache_misses().unwrap()); + + assert!(c.cache_set(1, 100).is_none()); + assert!(c.cache_set(2, 100).is_none()); + assert!(c.cache_set(3, 100).is_none()); + assert_eq!(c.key_order().copied().collect::>(), [3, 2, 1, 7, 6]); + + sleep(Duration::new(1, 0)); + + assert!(c.cache_get(&1).is_some()); + assert!(c.cache_get(&2).is_some()); + assert!(c.cache_get(&3).is_some()); + assert!(c.cache_get(&4).is_none()); + assert!(c.cache_get(&5).is_none()); + assert!(c.cache_get(&6).is_none()); + assert!(c.cache_get(&7).is_none()); + + assert_eq!(11, c.cache_misses().unwrap()); + + let mut c = TimedSizedCache::with_size_and_lifespan(5, 0); + let mut ticker = 0; + let setter = || { + let v = ticker; + ticker += 1; + v + }; + assert_eq!(c.cache_get_or_set_with(1, setter), &0); + let setter = || { + let v = ticker; + ticker += 1; + v + }; + assert_eq!(c.cache_get_or_set_with(1, setter), &1); + } + + #[test] + fn timed_cache_refresh() { + let mut c = TimedSizedCache::with_size_and_lifespan_and_refresh(2, 2, true); + assert!(c.refresh()); + assert_eq!(c.cache_get(&1), None); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, misses); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_get(&1), Some(&100)); + let hits = c.cache_hits().unwrap(); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, hits); + assert_eq!(1, misses); + + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_get(&2), Some(&200)); + sleep(Duration::new(1, 0)); + assert_eq!(c.cache_get(&1), Some(&100)); + sleep(Duration::new(1, 0)); + assert_eq!(c.cache_get(&1), Some(&100)); + assert_eq!(c.cache_get(&2), None); + } + + #[test] + fn try_new() { + let c: std::io::Result> = + TimedSizedCache::try_with_size_and_lifespan(0, 2); + assert_eq!(c.unwrap_err().raw_os_error(), Some(22)); + } + + #[test] + fn clear() { + let mut c = TimedSizedCache::with_size_and_lifespan(3, 3600); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + c.cache_clear(); + + assert_eq!(0, c.cache_size()); + } + + #[test] + fn reset() { + let init_capacity = 1; + let mut c = TimedSizedCache::with_size_and_lifespan(init_capacity, 100); + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + assert!(init_capacity <= c.store.capacity); + + c.cache_reset(); + assert!(init_capacity <= c.store.capacity); + } + + #[test] + fn remove() { + let mut c = TimedSizedCache::with_size_and_lifespan(3, 3600); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + + assert_eq!(Some(100), c.cache_remove(&1)); + assert_eq!(2, c.cache_size()); + + assert_eq!(Some(200), c.cache_remove(&2)); + assert_eq!(1, c.cache_size()); + + assert_eq!(None, c.cache_remove(&2)); + assert_eq!(1, c.cache_size()); + + assert_eq!(Some(300), c.cache_remove(&3)); + assert_eq!(0, c.cache_size()); + } + + #[test] + fn remove_expired() { + let mut c = TimedSizedCache::with_size_and_lifespan(3, 1); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(1, 200), Some(100)); + assert_eq!(c.cache_size(), 1); + + std::thread::sleep(std::time::Duration::from_secs(1)); + assert_eq!(None, c.cache_remove(&1)); + assert_eq!(0, c.cache_size()); + } + + #[test] + fn insert_expired() { + let mut c = TimedSizedCache::with_size_and_lifespan(3, 1); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(1, 200), Some(100)); + assert_eq!(c.cache_size(), 1); + + std::thread::sleep(std::time::Duration::from_secs(1)); + assert_eq!(1, c.cache_size()); + assert_eq!(None, c.cache_set(1, 300)); + assert_eq!(1, c.cache_size()); + } + + #[test] + fn get_expired() { + let mut c = TimedSizedCache::with_size_and_lifespan(3, 1); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(1, 200), Some(100)); + assert_eq!(c.cache_size(), 1); + + std::thread::sleep(std::time::Duration::from_secs(1)); + // still around until we try to get + assert_eq!(1, c.cache_size()); + assert_eq!(None, c.cache_get(&1)); + assert_eq!(0, c.cache_size()); + } + + #[test] + fn get_mut_expired() { + let mut c = TimedSizedCache::with_size_and_lifespan(3, 1); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(1, 200), Some(100)); + assert_eq!(c.cache_size(), 1); + + std::thread::sleep(std::time::Duration::from_secs(1)); + // still around until we try to get + assert_eq!(1, c.cache_size()); + assert_eq!(None, c.cache_get_mut(&1)); + assert_eq!(0, c.cache_size()); + } + + #[test] + fn flush_expired() { + let mut c = TimedSizedCache::with_size_and_lifespan(3, 1); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(1, 200), Some(100)); + assert_eq!(c.cache_size(), 1); + + std::thread::sleep(std::time::Duration::from_secs(2)); + // still around until we flush + assert_eq!(1, c.cache_size()); + c.flush(); + assert_eq!(0, c.cache_size()); + } + + #[test] + fn get_or_set_with() { + let mut c = TimedSizedCache::with_size_and_lifespan(5, 2); + + assert_eq!(c.cache_get_or_set_with(0, || 0), &0); + assert_eq!(c.cache_get_or_set_with(1, || 1), &1); + assert_eq!(c.cache_get_or_set_with(2, || 2), &2); + assert_eq!(c.cache_get_or_set_with(3, || 3), &3); + assert_eq!(c.cache_get_or_set_with(4, || 4), &4); + assert_eq!(c.cache_get_or_set_with(5, || 5), &5); + + assert_eq!(c.cache_misses(), Some(6)); + + assert_eq!(c.cache_get_or_set_with(0, || 0), &0); + + assert_eq!(c.cache_misses(), Some(7)); + + assert_eq!(c.cache_get_or_set_with(0, || 42), &0); + + sleep(Duration::new(1, 0)); + + assert_eq!(c.cache_get_or_set_with(0, || 42), &0); + + assert_eq!(c.cache_get_or_set_with(1, || 1), &1); + + assert_eq!(c.cache_get_or_set_with(4, || 42), &4); + + assert_eq!(c.cache_get_or_set_with(5, || 42), &5); + + assert_eq!(c.cache_get_or_set_with(6, || 6), &6); + + assert_eq!(c.cache_misses(), Some(9)); + + sleep(Duration::new(1, 0)); + + assert_eq!(c.cache_get_or_set_with(4, || 42), &42); + + assert_eq!(c.cache_get_or_set_with(5, || 42), &42); + + assert_eq!(c.cache_get_or_set_with(6, || 42), &6); + + assert_eq!(c.cache_misses(), Some(11)); + } + + #[cfg(feature = "async")] + #[tokio::test] + async fn test_async_trait_timed_sized() { + use crate::CachedAsync; + let mut c = TimedSizedCache::with_size_and_lifespan(5, 1); + + async fn _get(n: usize) -> usize { + n + } + + assert_eq!(c.get_or_set_with(0, || async { _get(0).await }).await, &0); + assert_eq!(c.get_or_set_with(1, || async { _get(1).await }).await, &1); + assert_eq!(c.get_or_set_with(2, || async { _get(2).await }).await, &2); + assert_eq!(c.get_or_set_with(3, || async { _get(3).await }).await, &3); + + assert_eq!(c.get_or_set_with(0, || async { _get(3).await }).await, &0); + assert_eq!(c.get_or_set_with(1, || async { _get(3).await }).await, &1); + assert_eq!(c.get_or_set_with(2, || async { _get(3).await }).await, &2); + assert_eq!(c.get_or_set_with(3, || async { _get(1).await }).await, &3); + + sleep(Duration::new(1, 0)); + // after sleeping, the original val should have expired + assert_eq!(c.get_or_set_with(0, || async { _get(3).await }).await, &3); + + c.cache_reset(); + async fn _try_get(n: usize) -> Result { + if n < 10 { + Ok(n) + } else { + Err("dead".to_string()) + } + } + + assert_eq!( + c.try_get_or_set_with(0, || async { + match _try_get(0).await { + Ok(n) => Ok(n), + Err(_) => Err("err".to_string()), + } + }) + .await + .unwrap(), + &0 + ); + assert_eq!( + c.try_get_or_set_with(0, || async { + match _try_get(5).await { + Ok(n) => Ok(n), + Err(_) => Err("err".to_string()), + } + }) + .await + .unwrap(), + &0 + ); + + c.cache_reset(); + let res: Result<&mut usize, String> = c + .try_get_or_set_with(0, || async { _try_get(10).await }) + .await; + assert!(res.is_err()); + assert!(c.key_order().next().is_none()); + + let res: Result<&mut usize, String> = c + .try_get_or_set_with(0, || async { _try_get(1).await }) + .await; + assert_eq!(res.unwrap(), &1); + let res: Result<&mut usize, String> = c + .try_get_or_set_with(0, || async { _try_get(5).await }) + .await; + assert_eq!(res.unwrap(), &1); + sleep(Duration::new(1, 0)); + let res: Result<&mut usize, String> = c + .try_get_or_set_with(0, || async { _try_get(5).await }) + .await; + assert_eq!(res.unwrap(), &5); + } +} diff --git a/vendor/cached/src/stores/unbound.rs b/vendor/cached/src/stores/unbound.rs new file mode 100644 index 0000000000000..766b1d8c2f832 --- /dev/null +++ b/vendor/cached/src/stores/unbound.rs @@ -0,0 +1,349 @@ +use super::Cached; + +use std::cmp::Eq; +use std::hash::Hash; + +#[cfg(feature = "ahash")] +use hashbrown::{hash_map::Entry, HashMap}; + +#[cfg(not(feature = "ahash"))] +use std::collections::{hash_map::Entry, HashMap}; + +#[cfg(feature = "async")] +use {super::CachedAsync, async_trait::async_trait, futures::Future}; + +/// Default unbounded cache +/// +/// This cache has no size limit or eviction policy. +/// +/// Note: This cache is in-memory only +#[derive(Clone, Debug)] +pub struct UnboundCache { + pub(super) store: HashMap, + pub(super) hits: u64, + pub(super) misses: u64, + pub(super) initial_capacity: Option, +} + +impl PartialEq for UnboundCache +where + K: Eq + Hash, + V: PartialEq, +{ + fn eq(&self, other: &UnboundCache) -> bool { + self.store.eq(&other.store) + } +} + +impl Eq for UnboundCache +where + K: Eq + Hash, + V: PartialEq, +{ +} + +impl UnboundCache { + /// Creates an empty `UnboundCache` + #[allow(clippy::new_without_default)] + #[must_use] + pub fn new() -> UnboundCache { + UnboundCache { + store: Self::new_store(None), + hits: 0, + misses: 0, + initial_capacity: None, + } + } + + /// Creates an empty `UnboundCache` with a given pre-allocated capacity + #[must_use] + pub fn with_capacity(size: usize) -> UnboundCache { + UnboundCache { + store: Self::new_store(Some(size)), + hits: 0, + misses: 0, + initial_capacity: Some(size), + } + } + + fn new_store(capacity: Option) -> HashMap { + capacity.map_or_else(HashMap::new, HashMap::with_capacity) + } + + /// Returns a reference to the cache's `store` + #[must_use] + pub fn get_store(&self) -> &HashMap { + &self.store + } +} + +impl Cached for UnboundCache { + fn cache_get(&mut self, key: &Q) -> Option<&V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + if let Some(v) = self.store.get(key) { + self.hits += 1; + Some(v) + } else { + self.misses += 1; + None + } + } + fn cache_get_mut(&mut self, key: &Q) -> std::option::Option<&mut V> + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + if let Some(v) = self.store.get_mut(key) { + self.hits += 1; + Some(v) + } else { + self.misses += 1; + None + } + } + fn cache_set(&mut self, key: K, val: V) -> Option { + self.store.insert(key, val) + } + fn cache_get_or_set_with V>(&mut self, key: K, f: F) -> &mut V { + match self.store.entry(key) { + Entry::Occupied(occupied) => { + self.hits += 1; + occupied.into_mut() + } + + Entry::Vacant(vacant) => { + self.misses += 1; + vacant.insert(f()) + } + } + } + fn cache_remove(&mut self, k: &Q) -> Option + where + K: std::borrow::Borrow, + Q: std::hash::Hash + Eq + ?Sized, + { + self.store.remove(k) + } + fn cache_clear(&mut self) { + self.store.clear(); + } + fn cache_reset(&mut self) { + self.store = Self::new_store(self.initial_capacity); + } + fn cache_reset_metrics(&mut self) { + self.misses = 0; + self.hits = 0; + } + fn cache_size(&self) -> usize { + self.store.len() + } + fn cache_hits(&self) -> Option { + Some(self.hits) + } + fn cache_misses(&self) -> Option { + Some(self.misses) + } +} + +#[cfg(feature = "async")] +#[async_trait] +impl CachedAsync for UnboundCache +where + K: Hash + Eq + Clone + Send, +{ + async fn get_or_set_with(&mut self, key: K, f: F) -> &mut V + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future + Send, + { + match self.store.entry(key) { + Entry::Occupied(occupied) => { + self.hits += 1; + occupied.into_mut() + } + + Entry::Vacant(vacant) => { + self.misses += 1; + vacant.insert(f().await) + } + } + } + + async fn try_get_or_set_with(&mut self, key: K, f: F) -> Result<&mut V, E> + where + V: Send, + F: FnOnce() -> Fut + Send, + Fut: Future> + Send, + { + let v = match self.store.entry(key) { + Entry::Occupied(occupied) => { + self.hits += 1; + occupied.into_mut() + } + + Entry::Vacant(vacant) => { + self.misses += 1; + vacant.insert(f().await?) + } + }; + Ok(v) + } +} + +#[cfg(test)] +/// Cache store tests +mod tests { + use super::*; + + #[test] + fn basic_cache() { + let mut c = UnboundCache::new(); + assert!(c.cache_get(&1).is_none()); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, misses); + + assert_eq!(c.cache_set(1, 100), None); + assert!(c.cache_get(&1).is_some()); + let hits = c.cache_hits().unwrap(); + let misses = c.cache_misses().unwrap(); + assert_eq!(1, hits); + assert_eq!(1, misses); + } + + #[test] + fn clear() { + let mut c = UnboundCache::new(); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + + // register some hits and misses + c.cache_get(&1); + c.cache_get(&2); + c.cache_get(&3); + c.cache_get(&10); + c.cache_get(&20); + c.cache_get(&30); + + assert_eq!(3, c.cache_size()); + assert_eq!(3, c.cache_hits().unwrap()); + assert_eq!(3, c.cache_misses().unwrap()); + assert!(3 <= c.store.capacity()); + + // clear the cache, should have no more elements + // hits and misses will still be kept + c.cache_clear(); + + assert_eq!(0, c.cache_size()); + assert_eq!(3, c.cache_hits().unwrap()); + assert_eq!(3, c.cache_misses().unwrap()); + assert!(3 <= c.store.capacity()); // Keeps the allocated memory for reuse. + + let capacity = 1; + let mut c = UnboundCache::with_capacity(capacity); + assert!(capacity <= c.store.capacity()); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + + assert!(3 <= c.store.capacity()); + + c.cache_clear(); + + assert!(3 <= c.store.capacity()); // Keeps the allocated memory for reuse. + } + + #[test] + fn reset() { + let mut c = UnboundCache::new(); + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + assert!(3 <= c.store.capacity()); + + c.cache_reset(); + + assert_eq!(0, c.store.capacity()); + + let init_capacity = 1; + let mut c = UnboundCache::with_capacity(init_capacity); + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + assert!(3 <= c.store.capacity()); + + c.cache_reset(); + + assert!(init_capacity <= c.store.capacity()); + } + + #[test] + fn remove() { + let mut c = UnboundCache::new(); + + assert_eq!(c.cache_set(1, 100), None); + assert_eq!(c.cache_set(2, 200), None); + assert_eq!(c.cache_set(3, 300), None); + + // register some hits and misses + c.cache_get(&1); + c.cache_get(&2); + c.cache_get(&3); + c.cache_get(&10); + c.cache_get(&20); + c.cache_get(&30); + + assert_eq!(3, c.cache_size()); + assert_eq!(3, c.cache_hits().unwrap()); + assert_eq!(3, c.cache_misses().unwrap()); + + // remove some items from cache + // hits and misses will still be kept + assert_eq!(Some(100), c.cache_remove(&1)); + + assert_eq!(2, c.cache_size()); + assert_eq!(3, c.cache_hits().unwrap()); + assert_eq!(3, c.cache_misses().unwrap()); + + assert_eq!(Some(200), c.cache_remove(&2)); + + assert_eq!(1, c.cache_size()); + + // removing extra is ok + assert_eq!(None, c.cache_remove(&2)); + + assert_eq!(1, c.cache_size()); + } + + #[test] + fn get_or_set_with() { + let mut c = UnboundCache::new(); + + assert_eq!(c.cache_get_or_set_with(0, || 0), &0); + assert_eq!(c.cache_get_or_set_with(1, || 1), &1); + assert_eq!(c.cache_get_or_set_with(2, || 2), &2); + assert_eq!(c.cache_get_or_set_with(3, || 3), &3); + assert_eq!(c.cache_get_or_set_with(4, || 4), &4); + assert_eq!(c.cache_get_or_set_with(5, || 5), &5); + + assert_eq!(c.cache_misses(), Some(6)); + + assert_eq!(c.cache_get_or_set_with(0, || 0), &0); + + assert_eq!(c.cache_misses(), Some(6)); + + assert_eq!(c.cache_get_or_set_with(0, || 42), &0); + + assert_eq!(c.cache_misses(), Some(6)); + + assert_eq!(c.cache_get_or_set_with(1, || 1), &1); + + assert_eq!(c.cache_misses(), Some(6)); + } +} diff --git a/vendor/cached/tests/cached.rs b/vendor/cached/tests/cached.rs new file mode 100644 index 0000000000000..97fd7af56e125 --- /dev/null +++ b/vendor/cached/tests/cached.rs @@ -0,0 +1,1613 @@ +/*! +Full tests of macro-defined functions +*/ +#[macro_use] +extern crate cached; + +use cached::{ + proc_macro::cached, proc_macro::once, Cached, CanExpire, ExpiringValueCache, SizedCache, + TimedCache, TimedSizedCache, UnboundCache, +}; +use serial_test::serial; +use std::thread::{self, sleep}; +use std::time::Duration; + +cached! { + UNBOUND_FIB; + fn fib0(n: u32) -> u32 = { + if n == 0 || n == 1 { return n } + fib0(n-1) + fib0(n-2) + } +} + +#[test] +fn test_unbound_cache() { + fib0(20); + { + let cache = UNBOUND_FIB.lock().unwrap(); + assert_eq!(21, cache.cache_size()); + } +} + +cached! { + SIZED_FIB: SizedCache = SizedCache::with_size(3); + fn fib1(n: u32) -> u32 = { + if n == 0 || n == 1 { return n } + fib1(n-1) + fib1(n-2) + } +} + +#[test] +fn test_sized_cache() { + let last = fib1(20); + { + let cache = SIZED_FIB.lock().unwrap(); + assert_eq!(3, cache.cache_size()); + let items = cache.get_order().iter().collect::>(); + assert_eq!(3, items.len()); + // (arg, result) + assert_eq!(&(20, last), items[0]); + } +} + +cached! { + TIMED: TimedCache = TimedCache::with_lifespan_and_capacity(2, 5); + fn timed(n: u32) -> u32 = { + sleep(Duration::new(3, 0)); + n + } +} + +#[test] +fn test_timed_cache() { + timed(1); + timed(1); + { + let cache = TIMED.lock().unwrap(); + assert_eq!(1, cache.cache_misses().unwrap()); + assert_eq!(1, cache.cache_hits().unwrap()); + } + sleep(Duration::new(3, 0)); + timed(1); + { + let cache = TIMED.lock().unwrap(); + assert_eq!(2, cache.cache_misses().unwrap()); + assert_eq!(1, cache.cache_hits().unwrap()); + } + { + let mut cache = TIMED.lock().unwrap(); + assert_eq!(2, cache.cache_set_lifespan(1).unwrap()); + } + timed(1); + sleep(Duration::new(1, 0)); + timed(1); + { + let cache = TIMED.lock().unwrap(); + assert_eq!(3, cache.cache_misses().unwrap()); + assert_eq!(2, cache.cache_hits().unwrap()); + } +} + +cached! { + TIMED_SIZED: TimedSizedCache = TimedSizedCache::with_size_and_lifespan(3, 2); + fn timefac(n: u32) -> u32 = { + sleep(Duration::new(1, 0)); + if n > 1 { + n * timefac(n - 1) + } else { + n + } + } +} + +#[test] +fn test_timed_sized_cache() { + timefac(1); + timefac(1); + { + let cache = TIMED_SIZED.lock().unwrap(); + assert_eq!(1, cache.cache_misses().unwrap()); + assert_eq!(1, cache.cache_hits().unwrap()); + } + sleep(Duration::new(3, 0)); + timefac(1); + { + let cache = TIMED_SIZED.lock().unwrap(); + assert_eq!(2, cache.cache_misses().unwrap()); + assert_eq!(1, cache.cache_hits().unwrap()); + } + { + let mut cache = TIMED_SIZED.lock().unwrap(); + assert_eq!(2, cache.cache_set_lifespan(1).unwrap()); + } + timefac(1); + sleep(Duration::new(1, 0)); + timefac(1); + { + let cache = TIMED_SIZED.lock().unwrap(); + assert_eq!(3, cache.cache_misses().unwrap()); + assert_eq!(2, cache.cache_hits().unwrap()); + } + { + let mut cache = TIMED_SIZED.lock().unwrap(); + assert_eq!(1, cache.cache_set_lifespan(6).unwrap()); + } + timefac(2); + { + let cache = TIMED_SIZED.lock().unwrap(); + assert_eq!(4, cache.cache_misses().unwrap()); + assert_eq!(3, cache.cache_hits().unwrap()); + } + timefac(3); + { + let cache = TIMED_SIZED.lock().unwrap(); + assert_eq!(5, cache.cache_misses().unwrap()); + assert_eq!(4, cache.cache_hits().unwrap()); + } + timefac(3); + timefac(2); + timefac(1); + { + let cache = TIMED_SIZED.lock().unwrap(); + assert_eq!(5, cache.cache_misses().unwrap()); + assert_eq!(7, cache.cache_hits().unwrap()); + } + timefac(4); + { + let cache = TIMED_SIZED.lock().unwrap(); + assert_eq!(6, cache.cache_misses().unwrap()); + assert_eq!(8, cache.cache_hits().unwrap()); + } + timefac(6); + { + let cache = TIMED_SIZED.lock().unwrap(); + assert_eq!(8, cache.cache_misses().unwrap()); + assert_eq!(9, cache.cache_hits().unwrap()); + } + timefac(1); + { + let cache = TIMED_SIZED.lock().unwrap(); + assert_eq!(9, cache.cache_misses().unwrap()); + assert_eq!(9, cache.cache_hits().unwrap()); + assert_eq!(3, cache.cache_size()); + } +} + +cached! { + STRING_CACHE_EXPLICIT: SizedCache<(String, String), String> = SizedCache::with_size(1); + fn string_1(a: String, b: String) -> String = { + a + b.as_ref() + } +} + +#[test] +fn test_string_cache() { + string_1("a".into(), "b".into()); + { + let cache = STRING_CACHE_EXPLICIT.lock().unwrap(); + assert_eq!(1, cache.cache_size()); + } +} + +cached_key! { + TIMED_CACHE: TimedCache = TimedCache::with_lifespan_and_capacity(2, 5); + Key = { n }; + fn timed_2(n: u32) -> u32 = { + sleep(Duration::new(3, 0)); + n + } +} + +#[test] +fn test_timed_cache_key() { + timed_2(1); + timed_2(1); + { + let cache = TIMED_CACHE.lock().unwrap(); + assert_eq!(1, cache.cache_misses().unwrap()); + assert_eq!(1, cache.cache_hits().unwrap()); + } + sleep(Duration::new(3, 0)); + timed_2(1); + { + let cache = TIMED_CACHE.lock().unwrap(); + assert_eq!(2, cache.cache_misses().unwrap()); + assert_eq!(1, cache.cache_hits().unwrap()); + } +} + +cached_key! { + SIZED_CACHE: SizedCache = SizedCache::with_size(2); + Key = { format!("{a}{b}") }; + fn sized_key(a: &str, b: &str) -> usize = { + let size = a.len() + b.len(); + sleep(Duration::new(size as u64, 0)); + size + } +} + +#[test] +fn test_sized_cache_key() { + sized_key("a", "1"); + sized_key("a", "1"); + { + let cache = SIZED_CACHE.lock().unwrap(); + assert_eq!(1, cache.cache_misses().unwrap()); + assert_eq!(1, cache.cache_hits().unwrap()); + assert_eq!(1, cache.cache_size()); + } + sized_key("a", "1"); + { + let cache = SIZED_CACHE.lock().unwrap(); + assert_eq!(1, cache.cache_misses().unwrap()); + assert_eq!(2, cache.cache_hits().unwrap()); + assert_eq!(1, cache.cache_size()); + } + sized_key("a", "2"); + { + let cache = SIZED_CACHE.lock().unwrap(); + assert_eq!(2, cache.cache_hits().unwrap()); + assert_eq!(2, cache.cache_size()); + assert_eq!(vec!["a2", "a1"], cache.key_order().collect::>()); + assert_eq!(vec![&2, &2], cache.value_order().collect::>()); + } + sized_key("a", "3"); + { + let cache = SIZED_CACHE.lock().unwrap(); + assert_eq!(2, cache.cache_size()); + assert_eq!(vec!["a3", "a2"], cache.key_order().collect::>()); + assert_eq!(vec![&2, &2], cache.value_order().collect::>()); + } + sized_key("a", "4"); + sized_key("a", "5"); + { + let cache = SIZED_CACHE.lock().unwrap(); + assert_eq!(2, cache.cache_size()); + assert_eq!(vec!["a5", "a4"], cache.key_order().collect::>()); + assert_eq!(vec![&2, &2], cache.value_order().collect::>()); + } + sized_key("a", "67"); + sized_key("a", "8"); + { + let cache = SIZED_CACHE.lock().unwrap(); + assert_eq!(2, cache.cache_size()); + assert_eq!(vec!["a8", "a67"], cache.key_order().collect::>()); + assert_eq!(vec![&2, &3], cache.value_order().collect::>()); + } +} + +cached_key_result! { + RESULT_CACHE_KEY: UnboundCache = UnboundCache::new(); + Key = { n }; + fn test_result_key(n: u32) -> Result = { + if n < 5 { Ok(n) } else { Err(()) } + } +} + +#[test] +fn cache_result_key() { + assert!(test_result_key(2).is_ok()); + assert!(test_result_key(4).is_ok()); + assert!(test_result_key(6).is_err()); + assert!(test_result_key(6).is_err()); + assert!(test_result_key(2).is_ok()); + assert!(test_result_key(4).is_ok()); + { + let cache = RESULT_CACHE_KEY.lock().unwrap(); + assert_eq!(2, cache.cache_size()); + assert_eq!(2, cache.cache_hits().unwrap()); + assert_eq!(4, cache.cache_misses().unwrap()); + } +} + +cached_result! { + RESULT_CACHE: UnboundCache = UnboundCache::new(); + fn test_result_no_default(n: u32) -> Result = { + if n < 5 { Ok(n) } else { Err(()) } + } +} + +#[test] +fn cache_result_no_default() { + assert!(test_result_no_default(2).is_ok()); + assert!(test_result_no_default(4).is_ok()); + assert!(test_result_no_default(6).is_err()); + assert!(test_result_no_default(6).is_err()); + assert!(test_result_no_default(2).is_ok()); + assert!(test_result_no_default(4).is_ok()); + { + let cache = RESULT_CACHE.lock().unwrap(); + assert_eq!(2, cache.cache_size()); + assert_eq!(2, cache.cache_hits().unwrap()); + assert_eq!(4, cache.cache_misses().unwrap()); + } +} + +cached_control! { + CONTROL_CACHE: UnboundCache = UnboundCache::new(); + Key = { input.to_owned() }; + PostGet(cached_val) = return Ok(cached_val.clone()); + PostExec(body_result) = { + match body_result { + Ok(v) => v, + Err(e) => return Err(e), + } + }; + Set(set_value) = set_value.clone(); + Return(return_value) = { + println!("{return_value}"); + Ok(return_value) + }; + fn can_fail(input: &str) -> Result = { + let len = input.len(); + if len < 3 { Ok(format!("{input}-{len}")) } + else { Err("too big".to_string()) } + } +} + +#[test] +fn test_can_fail() { + assert_eq!(can_fail("ab"), Ok("ab-2".to_string())); + assert_eq!(can_fail("abc"), Err("too big".to_string())); + { + let cache = CONTROL_CACHE.lock().unwrap(); + assert_eq!(2, cache.cache_misses().unwrap()); + } + assert_eq!(can_fail("ab"), Ok("ab-2".to_string())); + { + let cache = CONTROL_CACHE.lock().unwrap(); + assert_eq!(1, cache.cache_hits().unwrap()); + } +} + +cached_key! { + SIZED_KEY_RESULT_CACHE: SizedCache = SizedCache::with_size(2); + Key = { format!("{a}/{b}") }; + fn slow_small_cache(a: &str, b: &str) -> String = { + sleep(Duration::new(1, 0)); + format!("{a}:{b}") + } +} + +#[test] +/// This is a regression test to confirm that racing cache sets on a `SizedCache` +/// do not cause duplicates to exist in the internal `order`. See issue #7 +fn test_racing_duplicate_keys_do_not_duplicate_sized_cache_ordering() { + let a = thread::spawn(|| slow_small_cache("a", "b")); + sleep(Duration::new(0, 500_000)); + let b = thread::spawn(|| slow_small_cache("a", "b")); + a.join().unwrap(); + b.join().unwrap(); + // at this point, the cache should have a size of one since the keys are the same + // and the internal `order` list should also have one item. + // Since the method's cache has a capacity of 2, caching two more unique keys should + // force the full eviction of the original values. + slow_small_cache("c", "d"); + slow_small_cache("e", "f"); + slow_small_cache("g", "h"); +} + +// NoClone is not cloneable. So this also tests that the Result type +// itself does not have to be cloneable, just the type for the Ok +// value. +// Vec has Clone, but not Copy, to make sure Copy isn't required. +struct NoClone {} + +#[cached(result = true)] +fn proc_cached_result(n: u32) -> Result, NoClone> { + if n < 5 { + Ok(vec![n]) + } else { + Err(NoClone {}) + } +} + +#[test] +fn test_proc_cached_result() { + assert!(proc_cached_result(2).is_ok()); + assert!(proc_cached_result(4).is_ok()); + assert!(proc_cached_result(6).is_err()); + assert!(proc_cached_result(6).is_err()); + assert!(proc_cached_result(2).is_ok()); + assert!(proc_cached_result(4).is_ok()); + { + let cache = PROC_CACHED_RESULT.lock().unwrap(); + assert_eq!(2, cache.cache_size()); + assert_eq!(2, cache.cache_hits().unwrap()); + assert_eq!(4, cache.cache_misses().unwrap()); + } +} + +#[cached(option = true)] +fn proc_cached_option(n: u32) -> Option> { + if n < 5 { + Some(vec![n]) + } else { + None + } +} + +#[test] +fn test_proc_cached_option() { + assert!(proc_cached_option(2).is_some()); + assert!(proc_cached_option(4).is_some()); + assert!(proc_cached_option(1).is_some()); + assert!(proc_cached_option(6).is_none()); + assert!(proc_cached_option(6).is_none()); + assert!(proc_cached_option(2).is_some()); + assert!(proc_cached_option(1).is_some()); + assert!(proc_cached_option(4).is_some()); + { + let cache = PROC_CACHED_OPTION.lock().unwrap(); + assert_eq!(3, cache.cache_size()); + assert_eq!(3, cache.cache_hits().unwrap()); + assert_eq!(5, cache.cache_misses().unwrap()); + } +} + +cached_result! { + RESULT_CACHE_RETARM: UnboundCache = UnboundCache::new(); + fn test_result_missing_result_arm(n: u32) -> Result = { + Ok(n) + } +} + +cached_key_result! { + RESULT_CACHE_KEY_RETARM: UnboundCache = UnboundCache::new(); + Key = { n }; + fn test_result_key_missing_result_arm(n: u32) -> Result = { + Ok(n) + } +} + +#[cached(size = 1, time = 1)] +fn proc_timed_sized_sleeper(n: u64) -> u64 { + sleep(Duration::new(1, 0)); + n +} + +#[test] +fn test_proc_timed_sized_cache() { + proc_timed_sized_sleeper(1); + proc_timed_sized_sleeper(1); + { + let cache = PROC_TIMED_SIZED_SLEEPER.lock().unwrap(); + assert_eq!(1, cache.cache_misses().unwrap()); + assert_eq!(1, cache.cache_hits().unwrap()); + } + // sleep to expire the one entry + sleep(Duration::new(1, 0)); + proc_timed_sized_sleeper(1); + { + let cache = PROC_TIMED_SIZED_SLEEPER.lock().unwrap(); + assert_eq!(2, cache.cache_misses().unwrap()); + assert_eq!(1, cache.cache_hits().unwrap()); + assert_eq!(cache.key_order().collect::>(), vec![&1]); + } + // sleep to expire the one entry + sleep(Duration::new(1, 0)); + { + let cache = PROC_TIMED_SIZED_SLEEPER.lock().unwrap(); + assert!(cache.key_order().next().is_none()); + } + proc_timed_sized_sleeper(1); + proc_timed_sized_sleeper(1); + { + let cache = PROC_TIMED_SIZED_SLEEPER.lock().unwrap(); + assert_eq!(3, cache.cache_misses().unwrap()); + assert_eq!(2, cache.cache_hits().unwrap()); + assert_eq!(cache.key_order().collect::>(), vec![&1]); + } + // lru size is 1, so this new thing evicts the existing key + proc_timed_sized_sleeper(2); + { + let cache = PROC_TIMED_SIZED_SLEEPER.lock().unwrap(); + assert_eq!(4, cache.cache_misses().unwrap()); + assert_eq!(2, cache.cache_hits().unwrap()); + assert_eq!(cache.key_order().collect::>(), vec![&2]); + } +} + +#[cached(with_cached_flag = true)] +fn cached_return_flag(n: i32) -> cached::Return { + cached::Return::new(n) +} + +#[test] +fn test_cached_return_flag() { + let r = cached_return_flag(1); + assert!(!r.was_cached); + assert_eq!(*r, 1); + let r = cached_return_flag(1); + assert!(r.was_cached); + // derefs to inner + assert_eq!(*r, 1); + assert!(r.is_positive()); + { + let cache = CACHED_RETURN_FLAG.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(1)); + } +} + +#[cached(result = true, with_cached_flag = true)] +fn cached_return_flag_result(n: i32) -> Result, ()> { + if n == 10 { + return Err(()); + } + Ok(cached::Return::new(n)) +} + +#[test] +fn test_cached_return_flag_result() { + let r = cached_return_flag_result(1).unwrap(); + assert!(!r.was_cached); + assert_eq!(*r, 1); + let r = cached_return_flag_result(1).unwrap(); + assert!(r.was_cached); + // derefs to inner + assert_eq!(*r, 1); + assert!(r.is_positive()); + + let r = cached_return_flag_result(10); + assert!(r.is_err()); + { + let cache = CACHED_RETURN_FLAG_RESULT.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(2)); + } +} + +#[cached(option = true, with_cached_flag = true)] +fn cached_return_flag_option(n: i32) -> Option> { + if n == 10 { + return None; + } + Some(cached::Return::new(n)) +} + +#[test] +fn test_cached_return_flag_option() { + let r = cached_return_flag_option(1).unwrap(); + assert!(!r.was_cached); + assert_eq!(*r, 1); + let r = cached_return_flag_option(1).unwrap(); + assert!(r.was_cached); + // derefs to inner + assert_eq!(*r, 1); + assert!(r.is_positive()); + + let r = cached_return_flag_option(10); + assert!(r.is_none()); + { + let cache = CACHED_RETURN_FLAG_OPTION.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(2)); + } +} + +/// should only cache the _first_ value returned for 1 second. +/// all arguments are ignored for subsequent calls until the +/// cache expires after a second. +#[once(time = 1)] +fn only_cached_once_per_second(s: String) -> Vec { + vec![s] +} + +#[test] +fn test_only_cached_once_per_second() { + let a = only_cached_once_per_second("a".to_string()); + let b = only_cached_once_per_second("b".to_string()); + assert_eq!(a, b); + sleep(Duration::new(1, 0)); + let b = only_cached_once_per_second("b".to_string()); + assert_eq!(vec!["b".to_string()], b); +} + +#[cfg(feature = "async")] +#[once(time = 1)] +async fn only_cached_once_per_second_a(s: String) -> Vec { + vec![s] +} + +#[cfg(feature = "async")] +#[tokio::test] +async fn test_only_cached_once_per_second_a() { + let a = only_cached_once_per_second_a("a".to_string()).await; + let b = only_cached_once_per_second_a("b".to_string()).await; + assert_eq!(a, b); + sleep(Duration::new(1, 0)); + let b = only_cached_once_per_second_a("b".to_string()).await; + assert_eq!(vec!["b".to_string()], b); +} + +/// should only cache the _first_ `Ok` returned. +/// all arguments are ignored for subsequent calls. +#[once(result = true)] +fn only_cached_result_once(s: String, error: bool) -> std::result::Result, u32> { + if error { + Err(1) + } else { + Ok(vec![s]) + } +} + +#[test] +fn test_only_cached_result_once() { + assert!(only_cached_result_once("z".to_string(), true).is_err()); + let a = only_cached_result_once("a".to_string(), false).unwrap(); + let b = only_cached_result_once("b".to_string(), false).unwrap(); + assert_eq!(a, b); + sleep(Duration::new(1, 0)); + let b = only_cached_result_once("b".to_string(), false).unwrap(); + assert_eq!(a, b); +} + +#[cfg(feature = "async")] +#[once(result = true)] +async fn only_cached_result_once_a( + s: String, + error: bool, +) -> std::result::Result, u32> { + if error { + Err(1) + } else { + Ok(vec![s]) + } +} + +#[cfg(feature = "async")] +#[tokio::test] +async fn test_only_cached_result_once_a() { + assert!(only_cached_result_once_a("z".to_string(), true) + .await + .is_err()); + let a = only_cached_result_once_a("a".to_string(), false) + .await + .unwrap(); + let b = only_cached_result_once_a("b".to_string(), false) + .await + .unwrap(); + assert_eq!(a, b); + sleep(Duration::new(1, 0)); + let b = only_cached_result_once_a("b".to_string(), false) + .await + .unwrap(); + assert_eq!(a, b); +} + +/// should only cache the _first_ `Ok` returned for 1 second. +/// all arguments are ignored for subsequent calls until the +/// cache expires after a second. +#[once(result = true, time = 1)] +fn only_cached_result_once_per_second( + s: String, + error: bool, +) -> std::result::Result, u32> { + if error { + Err(1) + } else { + Ok(vec![s]) + } +} + +#[test] +fn test_only_cached_result_once_per_second() { + assert!(only_cached_result_once_per_second("z".to_string(), true).is_err()); + let a = only_cached_result_once_per_second("a".to_string(), false).unwrap(); + let b = only_cached_result_once_per_second("b".to_string(), false).unwrap(); + assert_eq!(a, b); + sleep(Duration::new(1, 0)); + let b = only_cached_result_once_per_second("b".to_string(), false).unwrap(); + assert_eq!(vec!["b".to_string()], b); +} + +#[cfg(feature = "async")] +#[once(result = true, time = 1)] +async fn only_cached_result_once_per_second_a( + s: String, + error: bool, +) -> std::result::Result, u32> { + if error { + Err(1) + } else { + Ok(vec![s]) + } +} + +#[cfg(feature = "async")] +#[tokio::test] +async fn test_only_cached_result_once_per_second_a() { + assert!(only_cached_result_once_per_second_a("z".to_string(), true) + .await + .is_err()); + let a = only_cached_result_once_per_second_a("a".to_string(), false) + .await + .unwrap(); + let b = only_cached_result_once_per_second_a("b".to_string(), false) + .await + .unwrap(); + assert_eq!(a, b); + sleep(Duration::new(1, 0)); + let b = only_cached_result_once_per_second_a("b".to_string(), false) + .await + .unwrap(); + assert_eq!(vec!["b".to_string()], b); +} + +/// should only cache the _first_ `Some` returned . +/// all arguments are ignored for subsequent calls +#[once(option = true)] +fn only_cached_option_once(s: String, none: bool) -> Option> { + if none { + None + } else { + Some(vec![s]) + } +} + +#[test] +fn test_only_cached_option_once() { + assert!(only_cached_option_once("z".to_string(), true).is_none()); + let a = only_cached_option_once("a".to_string(), false).unwrap(); + let b = only_cached_option_once("b".to_string(), false).unwrap(); + assert_eq!(a, b); + sleep(Duration::new(1, 0)); + let b = only_cached_option_once("b".to_string(), false).unwrap(); + assert_eq!(a, b); +} + +#[cfg(feature = "async")] +#[once(option = true)] +async fn only_cached_option_once_a(s: String, none: bool) -> Option> { + if none { + None + } else { + Some(vec![s]) + } +} + +#[cfg(feature = "async")] +#[tokio::test] +async fn test_only_cached_option_once_a() { + assert!(only_cached_option_once_a("z".to_string(), true) + .await + .is_none()); + let a = only_cached_option_once_a("a".to_string(), false) + .await + .unwrap(); + let b = only_cached_option_once_a("b".to_string(), false) + .await + .unwrap(); + assert_eq!(a, b); + sleep(Duration::new(1, 0)); + let b = only_cached_option_once_a("b".to_string(), false) + .await + .unwrap(); + assert_eq!(a, b); +} + +/// should only cache the _first_ `Some` returned for 1 second. +/// all arguments are ignored for subsequent calls until the +/// cache expires after a second. +#[once(option = true, time = 1)] +fn only_cached_option_once_per_second(s: String, none: bool) -> Option> { + if none { + None + } else { + Some(vec![s]) + } +} + +#[test] +fn test_only_cached_option_once_per_second() { + assert!(only_cached_option_once_per_second("z".to_string(), true).is_none()); + let a = only_cached_option_once_per_second("a".to_string(), false).unwrap(); + let b = only_cached_option_once_per_second("b".to_string(), false).unwrap(); + assert_eq!(a, b); + sleep(Duration::new(1, 0)); + let b = only_cached_option_once_per_second("b".to_string(), false).unwrap(); + assert_eq!(vec!["b".to_string()], b); +} + +#[cfg(feature = "async")] +#[once(option = true, time = 1)] +async fn only_cached_option_once_per_second_a(s: String, none: bool) -> Option> { + if none { + None + } else { + Some(vec![s]) + } +} + +#[cfg(feature = "async")] +#[tokio::test] +async fn test_only_cached_option_once_per_second_a() { + assert!(only_cached_option_once_per_second_a("z".to_string(), true) + .await + .is_none()); + let a = only_cached_option_once_per_second_a("a".to_string(), false) + .await + .unwrap(); + let b = only_cached_option_once_per_second_a("b".to_string(), false) + .await + .unwrap(); + assert_eq!(a, b); + sleep(Duration::new(1, 0)); + let b = only_cached_option_once_per_second_a("b".to_string(), false) + .await + .unwrap(); + assert_eq!(vec!["b".to_string()], b); +} + +/// should only cache the _first_ value returned for 2 seconds. +/// all arguments are ignored for subsequent calls until the +/// cache expires after a second. +/// when multiple un-cached tasks are running concurrently, only +/// _one_ call will be "executed" and all others will be synchronized +/// to return the cached result of the one call instead of all +/// concurrently un-cached tasks executing and writing concurrently. +#[cfg(feature = "async")] +#[once(time = 2, sync_writes = true)] +async fn only_cached_once_per_second_sync_writes(s: String) -> Vec { + vec![s] +} + +#[cfg(feature = "async")] +#[tokio::test] +async fn test_only_cached_once_per_second_sync_writes() { + let a = tokio::spawn(only_cached_once_per_second_sync_writes("a".to_string())); + tokio::time::sleep(Duration::new(1, 0)).await; + let b = tokio::spawn(only_cached_once_per_second_sync_writes("b".to_string())); + assert_eq!(a.await.unwrap(), b.await.unwrap()); +} + +#[cached(time = 2, sync_writes = true, key = "u32", convert = "{ 1 }")] +fn cached_sync_writes(s: String) -> Vec { + vec![s] +} + +#[test] +fn test_cached_sync_writes() { + let a = std::thread::spawn(|| cached_sync_writes("a".to_string())); + sleep(Duration::new(1, 0)); + let b = std::thread::spawn(|| cached_sync_writes("b".to_string())); + let c = std::thread::spawn(|| cached_sync_writes("c".to_string())); + let a = a.join().unwrap(); + let b = b.join().unwrap(); + let c = c.join().unwrap(); + assert_eq!(a, b); + assert_eq!(a, c); +} + +#[cfg(feature = "async")] +#[cached(time = 2, sync_writes = true, key = "u32", convert = "{ 1 }")] +async fn cached_sync_writes_a(s: String) -> Vec { + vec![s] +} + +#[cfg(feature = "async")] +#[tokio::test] +async fn test_cached_sync_writes_a() { + let a = tokio::spawn(cached_sync_writes_a("a".to_string())); + tokio::time::sleep(Duration::new(1, 0)).await; + let b = tokio::spawn(cached_sync_writes_a("b".to_string())); + let c = tokio::spawn(cached_sync_writes_a("c".to_string())); + let a = a.await.unwrap(); + assert_eq!(a, b.await.unwrap()); + assert_eq!(a, c.await.unwrap()); +} + +#[cfg(feature = "async")] +#[once(sync_writes = true)] +async fn once_sync_writes_a(s: &tokio::sync::Mutex) -> String { + let mut guard = s.lock().await; + let results: String = (*guard).clone().to_string(); + *guard = "consumed".to_string(); + results.to_string() +} + +#[cfg(feature = "async")] +#[tokio::test] +async fn test_once_sync_writes_a() { + let a_mutex = tokio::sync::Mutex::new("a".to_string()); + let b_mutex = tokio::sync::Mutex::new("b".to_string()); + let fut_a = once_sync_writes_a(&a_mutex); + let fut_b = once_sync_writes_a(&b_mutex); + let a = fut_a.await; + let b = fut_b.await; + assert_eq!(a, b); + assert_eq!("a", a); + + //check if cache function is executed for a + assert_eq!("consumed", a_mutex.lock().await.to_string()); + //check if cache inner is not executed for b (not executed second time) + assert_eq!("b", b_mutex.lock().await.to_string()); +} + +#[cached(size = 2)] +fn cached_smartstring(s: smartstring::alias::String) -> smartstring::alias::String { + if s == "very stringy" { + smartstring::alias::String::from("equal") + } else { + smartstring::alias::String::from("not equal") + } +} + +#[test] +fn test_cached_smartstring() { + let mut string = smartstring::alias::String::new(); + string.push_str("very stringy"); + assert_eq!("equal", cached_smartstring(string.clone())); + { + let cache = CACHED_SMARTSTRING.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(0)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + assert_eq!("equal", cached_smartstring(string.clone())); + { + let cache = CACHED_SMARTSTRING.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + let string = smartstring::alias::String::from("also stringy"); + assert_eq!("not equal", cached_smartstring(string)); + { + let cache = CACHED_SMARTSTRING.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(2)); + } +} + +#[cached( + size = 2, + key = "smartstring::alias::String", + convert = r#"{ smartstring::alias::String::from(s) }"# +)] +fn cached_smartstring_from_str(s: &str) -> bool { + s == "true" +} + +#[test] +fn test_cached_smartstring_from_str() { + assert!(cached_smartstring_from_str("true")); + { + let cache = CACHED_SMARTSTRING_FROM_STR.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(0)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + assert!(cached_smartstring_from_str("true")); + { + let cache = CACHED_SMARTSTRING_FROM_STR.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + assert!(!cached_smartstring_from_str("false")); + { + let cache = CACHED_SMARTSTRING_FROM_STR.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(2)); + } +} + +#[cached( + time = 1, + time_refresh = true, + key = "String", + convert = r#"{ String::from(s) }"# +)] +fn cached_timed_refresh(s: &str) -> bool { + s == "true" +} + +#[test] +fn test_cached_timed_refresh() { + assert!(cached_timed_refresh("true")); + { + let cache = CACHED_TIMED_REFRESH.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(0)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + assert!(cached_timed_refresh("true")); + { + let cache = CACHED_TIMED_REFRESH.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + std::thread::sleep(std::time::Duration::from_millis(500)); + assert!(cached_timed_refresh("true")); + std::thread::sleep(std::time::Duration::from_millis(500)); + assert!(cached_timed_refresh("true")); + std::thread::sleep(std::time::Duration::from_millis(500)); + assert!(cached_timed_refresh("true")); + { + let cache = CACHED_TIMED_REFRESH.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(4)); + assert_eq!(cache.cache_misses(), Some(1)); + } +} + +#[cached( + size = 2, + time = 1, + time_refresh = true, + key = "String", + convert = r#"{ String::from(s) }"# +)] +fn cached_timed_sized_refresh(s: &str) -> bool { + s == "true" +} + +#[test] +fn test_cached_timed_sized_refresh() { + assert!(cached_timed_sized_refresh("true")); + { + let cache = CACHED_TIMED_SIZED_REFRESH.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(0)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + assert!(cached_timed_sized_refresh("true")); + { + let cache = CACHED_TIMED_SIZED_REFRESH.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + std::thread::sleep(std::time::Duration::from_millis(500)); + assert!(cached_timed_sized_refresh("true")); + std::thread::sleep(std::time::Duration::from_millis(500)); + assert!(cached_timed_sized_refresh("true")); + std::thread::sleep(std::time::Duration::from_millis(500)); + assert!(cached_timed_sized_refresh("true")); + { + let cache = CACHED_TIMED_SIZED_REFRESH.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(4)); + assert_eq!(cache.cache_misses(), Some(1)); + } +} + +#[cached( + size = 2, + time = 1, + time_refresh = true, + key = "String", + convert = r#"{ String::from(s) }"# +)] +fn cached_timed_sized_refresh_prime(s: &str) -> bool { + s == "true" +} + +#[test] +fn test_cached_timed_sized_refresh_prime() { + assert!(cached_timed_sized_refresh_prime("true")); + { + let cache = CACHED_TIMED_SIZED_REFRESH_PRIME.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(0)); + assert_eq!(cache.cache_misses(), Some(1)); + } + assert!(cached_timed_sized_refresh_prime("true")); + { + let cache = CACHED_TIMED_SIZED_REFRESH_PRIME.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + std::thread::sleep(std::time::Duration::from_millis(500)); + assert!(cached_timed_sized_refresh_prime_prime_cache("true")); + std::thread::sleep(std::time::Duration::from_millis(500)); + assert!(cached_timed_sized_refresh_prime_prime_cache("true")); + std::thread::sleep(std::time::Duration::from_millis(500)); + assert!(cached_timed_sized_refresh_prime_prime_cache("true")); + + // stats unchanged (other than this new hit) since we kept priming + assert!(cached_timed_sized_refresh_prime("true")); + { + let cache = CACHED_TIMED_SIZED_REFRESH_PRIME.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(2)); + assert_eq!(cache.cache_misses(), Some(1)); + } +} + +#[cached(size = 2, time = 1, key = "String", convert = r#"{ String::from(s) }"#)] +fn cached_timed_sized_prime(s: &str) -> bool { + s == "true" +} + +#[test] +fn test_cached_timed_sized_prime() { + assert!(cached_timed_sized_prime("true")); + { + let cache = CACHED_TIMED_SIZED_PRIME.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(0)); + assert_eq!(cache.cache_misses(), Some(1)); + } + assert!(cached_timed_sized_prime("true")); + { + let cache = CACHED_TIMED_SIZED_PRIME.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + std::thread::sleep(std::time::Duration::from_millis(500)); + assert!(cached_timed_sized_prime_prime_cache("true")); + std::thread::sleep(std::time::Duration::from_millis(500)); + assert!(cached_timed_sized_prime_prime_cache("true")); + std::thread::sleep(std::time::Duration::from_millis(500)); + assert!(cached_timed_sized_prime_prime_cache("true")); + + // stats unchanged (other than this new hit) since we kept priming + assert!(cached_timed_sized_prime("true")); + { + let mut cache = CACHED_TIMED_SIZED_PRIME.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(2)); + assert_eq!(cache.cache_misses(), Some(1)); + assert!(cache.cache_size() > 0); + std::thread::sleep(std::time::Duration::from_millis(1000)); + cache.flush(); + assert_eq!(cache.cache_size(), 0); + } +} + +#[once] +fn once_for_priming() -> bool { + true +} + +#[test] +fn test_once_for_priming() { + assert!(once_for_priming_prime_cache()); + { + let cache = ONCE_FOR_PRIMING.read().unwrap(); + assert!(cache.is_some()); + } +} + +#[cached] +fn mutable_args(mut a: i32, mut b: i32) -> (i32, i32) { + a += 1; + b += 1; + (a, b) +} + +#[test] +fn test_mutable_args() { + assert_eq!((2, 2), mutable_args(1, 1)); + assert_eq!((2, 2), mutable_args(1, 1)); +} + +#[cached] +fn mutable_args_str(mut a: String) -> String { + a.push_str("-ok"); + a +} + +#[test] +fn test_mutable_args_str() { + assert_eq!("a-ok", mutable_args_str(String::from("a"))); + assert_eq!("a-ok", mutable_args_str(String::from("a"))); +} + +#[once] +fn mutable_args_once(mut a: i32, mut b: i32) -> (i32, i32) { + a += 1; + b += 1; + (a, b) +} + +#[test] +fn test_mutable_args_once() { + assert_eq!((2, 2), mutable_args_once(1, 1)); + assert_eq!((2, 2), mutable_args_once(1, 1)); + assert_eq!((2, 2), mutable_args_once(5, 6)); +} + +#[cfg(feature = "disk_store")] +mod disk_tests { + use super::*; + use cached::proc_macro::io_cached; + use cached::DiskCache; + use thiserror::Error; + + #[derive(Error, Debug, PartialEq, Clone)] + enum TestError { + #[error("error with disk cache `{0}`")] + DiskError(String), + #[error("count `{0}`")] + Count(u32), + } + + #[io_cached( + disk = true, + time = 1, + map_error = r##"|e| TestError::DiskError(format!("{:?}", e))"## + )] + fn cached_disk(n: u32) -> Result { + if n < 5 { + Ok(n) + } else { + Err(TestError::Count(n)) + } + } + + #[test] + fn test_cached_disk() { + assert_eq!(cached_disk(1), Ok(1)); + assert_eq!(cached_disk(1), Ok(1)); + assert_eq!(cached_disk(5), Err(TestError::Count(5))); + assert_eq!(cached_disk(6), Err(TestError::Count(6))); + } + + #[io_cached( + disk = true, + time = 1, + with_cached_flag = true, + map_error = r##"|e| TestError::DiskError(format!("{:?}", e))"## + )] + fn cached_disk_cached_flag(n: u32) -> Result, TestError> { + if n < 5 { + Ok(cached::Return::new(n)) + } else { + Err(TestError::Count(n)) + } + } + + #[test] + fn test_cached_disk_cached_flag() { + assert!(!cached_disk_cached_flag(1).unwrap().was_cached); + assert!(cached_disk_cached_flag(1).unwrap().was_cached); + assert!(cached_disk_cached_flag(5).is_err()); + assert!(cached_disk_cached_flag(6).is_err()); + } + + #[io_cached( + map_error = r##"|e| TestError::DiskError(format!("{:?}", e))"##, + type = "cached::DiskCache", + create = r##" { DiskCache::new("cached_disk_cache_create").set_lifespan(1).set_refresh(true).build().expect("error building disk cache") } "## + )] + fn cached_disk_cache_create(n: u32) -> Result { + if n < 5 { + Ok(n) + } else { + Err(TestError::Count(n)) + } + } + + #[test] + fn test_cached_disk_cache_create() { + assert_eq!(cached_disk_cache_create(1), Ok(1)); + assert_eq!(cached_disk_cache_create(1), Ok(1)); + assert_eq!(cached_disk_cache_create(5), Err(TestError::Count(5))); + assert_eq!(cached_disk_cache_create(6), Err(TestError::Count(6))); + } + + #[cfg(feature = "async")] + mod async_test { + use super::*; + + #[io_cached( + disk = true, + map_error = r##"|e| TestError::DiskError(format!("{:?}", e))"## + )] + async fn async_cached_disk(n: u32) -> Result { + if n < 5 { + Ok(n) + } else { + Err(TestError::Count(n)) + } + } + + #[tokio::test] + async fn test_async_cached_disk() { + assert_eq!(async_cached_disk(1).await, Ok(1)); + assert_eq!(async_cached_disk(1).await, Ok(1)); + assert_eq!(async_cached_disk(5).await, Err(TestError::Count(5))); + assert_eq!(async_cached_disk(6).await, Err(TestError::Count(6))); + } + } +} + +#[cfg(feature = "redis_store")] +mod redis_tests { + use super::*; + use cached::proc_macro::io_cached; + use cached::RedisCache; + use thiserror::Error; + + #[derive(Error, Debug, PartialEq, Clone)] + enum TestError { + #[error("error with redis cache `{0}`")] + RedisError(String), + #[error("count `{0}`")] + Count(u32), + } + + #[io_cached( + redis = true, + time = 1, + cache_prefix_block = "{ \"__cached_redis_proc_macro_test_fn_cached_redis\" }", + map_error = r##"|e| TestError::RedisError(format!("{:?}", e))"## + )] + fn cached_redis(n: u32) -> Result { + if n < 5 { + Ok(n) + } else { + Err(TestError::Count(n)) + } + } + + #[test] + fn test_cached_redis() { + assert_eq!(cached_redis(1), Ok(1)); + assert_eq!(cached_redis(1), Ok(1)); + assert_eq!(cached_redis(5), Err(TestError::Count(5))); + assert_eq!(cached_redis(6), Err(TestError::Count(6))); + } + + #[io_cached( + redis = true, + time = 1, + with_cached_flag = true, + map_error = r##"|e| TestError::RedisError(format!("{:?}", e))"## + )] + fn cached_redis_cached_flag(n: u32) -> Result, TestError> { + if n < 5 { + Ok(cached::Return::new(n)) + } else { + Err(TestError::Count(n)) + } + } + + #[test] + fn test_cached_redis_cached_flag() { + assert!(!cached_redis_cached_flag(1).unwrap().was_cached); + assert!(cached_redis_cached_flag(1).unwrap().was_cached); + assert!(cached_redis_cached_flag(5).is_err()); + assert!(cached_redis_cached_flag(6).is_err()); + } + + #[io_cached( + map_error = r##"|e| TestError::RedisError(format!("{:?}", e))"##, + type = "cached::RedisCache", + create = r##" { RedisCache::new("cache_redis_test_cache_create", 1).set_refresh(true).build().expect("error building redis cache") } "## + )] + fn cached_redis_cache_create(n: u32) -> Result { + if n < 5 { + Ok(n) + } else { + Err(TestError::Count(n)) + } + } + + #[test] + fn test_cached_redis_cache_create() { + assert_eq!(cached_redis_cache_create(1), Ok(1)); + assert_eq!(cached_redis_cache_create(1), Ok(1)); + assert_eq!(cached_redis_cache_create(5), Err(TestError::Count(5))); + assert_eq!(cached_redis_cache_create(6), Err(TestError::Count(6))); + } + + #[cfg(any(feature = "redis_async_std", feature = "redis_tokio"))] + mod async_redis_tests { + use super::*; + + #[io_cached( + redis = true, + time = 1, + cache_prefix_block = "{ \"__cached_redis_proc_macro_test_fn_async_cached_redis\" }", + map_error = r##"|e| TestError::RedisError(format!("{:?}", e))"## + )] + async fn async_cached_redis(n: u32) -> Result { + if n < 5 { + Ok(n) + } else { + Err(TestError::Count(n)) + } + } + + #[tokio::test] + async fn test_async_cached_redis() { + assert_eq!(async_cached_redis(1).await, Ok(1)); + assert_eq!(async_cached_redis(1).await, Ok(1)); + assert_eq!(async_cached_redis(5).await, Err(TestError::Count(5))); + assert_eq!(async_cached_redis(6).await, Err(TestError::Count(6))); + } + + #[io_cached( + redis = true, + time = 1, + with_cached_flag = true, + map_error = r##"|e| TestError::RedisError(format!("{:?}", e))"## + )] + async fn async_cached_redis_cached_flag(n: u32) -> Result, TestError> { + if n < 5 { + Ok(cached::Return::new(n)) + } else { + Err(TestError::Count(n)) + } + } + + #[tokio::test] + async fn test_async_cached_redis_cached_flag() { + assert!(!async_cached_redis_cached_flag(1).await.unwrap().was_cached); + assert!(async_cached_redis_cached_flag(1).await.unwrap().was_cached,); + assert!(async_cached_redis_cached_flag(5).await.is_err()); + assert!(async_cached_redis_cached_flag(6).await.is_err()); + } + + use cached::AsyncRedisCache; + #[io_cached( + map_error = r##"|e| TestError::RedisError(format!("{:?}", e))"##, + type = "cached::AsyncRedisCache", + create = r##" { AsyncRedisCache::new("async_cached_redis_test_cache_create", 1).set_refresh(true).build().await.expect("error building async redis cache") } "## + )] + async fn async_cached_redis_cache_create(n: u32) -> Result { + if n < 5 { + Ok(n) + } else { + Err(TestError::Count(n)) + } + } + + #[tokio::test] + async fn test_async_cached_redis_cache_create() { + assert_eq!(async_cached_redis_cache_create(1).await, Ok(1)); + assert_eq!(async_cached_redis_cache_create(1).await, Ok(1)); + assert_eq!( + async_cached_redis_cache_create(5).await, + Err(TestError::Count(5)) + ); + assert_eq!( + async_cached_redis_cache_create(6).await, + Err(TestError::Count(6)) + ); + } + } +} + +#[derive(Clone)] +pub struct NewsArticle { + slug: String, + is_expired: bool, +} + +impl CanExpire for NewsArticle { + fn is_expired(&self) -> bool { + self.is_expired + } +} + +const EXPIRED_SLUG: &str = "expired_slug"; +const UNEXPIRED_SLUG: &str = "unexpired_slug"; + +#[cached( + type = "ExpiringValueCache", + create = "{ ExpiringValueCache::with_size(3) }", + result = true +)] +fn fetch_article(slug: String) -> Result { + match slug.as_str() { + EXPIRED_SLUG => Ok(NewsArticle { + slug: String::from(EXPIRED_SLUG), + is_expired: true, + }), + UNEXPIRED_SLUG => Ok(NewsArticle { + slug: String::from(UNEXPIRED_SLUG), + is_expired: false, + }), + _ => Err(()), + } +} + +#[test] +#[serial(ExpiringCacheTest)] +fn test_expiring_value_expired_article_returned_with_miss() { + { + let mut cache = FETCH_ARTICLE.lock().unwrap(); + cache.cache_reset(); + cache.cache_reset_metrics(); + } + let expired_article = fetch_article(EXPIRED_SLUG.to_string()); + + assert!(expired_article.is_ok()); + assert_eq!(EXPIRED_SLUG, expired_article.unwrap().slug.as_str()); + + // The article was fetched due to a cache miss and the result cached. + { + let cache = FETCH_ARTICLE.lock().unwrap(); + assert_eq!(1, cache.cache_size()); + assert_eq!(cache.cache_hits(), Some(0)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + let _ = fetch_article(EXPIRED_SLUG.to_string()); + + // The article was fetched again as it had expired. + { + let cache = FETCH_ARTICLE.lock().unwrap(); + assert_eq!(1, cache.cache_size()); + assert_eq!(cache.cache_hits(), Some(0)); + assert_eq!(cache.cache_misses(), Some(2)); + } +} + +#[test] +#[serial(ExpiringCacheTest)] +fn test_expiring_value_unexpired_article_returned_with_hit() { + { + let mut cache = FETCH_ARTICLE.lock().unwrap(); + cache.cache_reset(); + cache.cache_reset_metrics(); + } + let unexpired_article = fetch_article(UNEXPIRED_SLUG.to_string()); + + assert!(unexpired_article.is_ok()); + assert_eq!(UNEXPIRED_SLUG, unexpired_article.unwrap().slug.as_str()); + + // The article was fetched due to a cache miss and the result cached. + { + let cache = FETCH_ARTICLE.lock().unwrap(); + assert_eq!(1, cache.cache_size()); + assert_eq!(cache.cache_hits(), Some(0)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + let cached_article = fetch_article(UNEXPIRED_SLUG.to_string()); + assert!(cached_article.is_ok()); + assert_eq!(UNEXPIRED_SLUG, cached_article.unwrap().slug.as_str()); + + // The article was not fetched but returned as a hit from the cache. + { + let cache = FETCH_ARTICLE.lock().unwrap(); + assert_eq!(1, cache.cache_size()); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(1)); + } +} + +#[cached::proc_macro::cached(result = true, time = 1, result_fallback = true)] +fn always_failing() -> Result { + Err(()) +} + +#[test] +fn test_result_fallback() { + assert!(always_failing().is_err()); + { + let cache = ALWAYS_FAILING.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(0)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + // Pretend it succeeded once + ALWAYS_FAILING.lock().unwrap().cache_set((), 1); + assert_eq!(always_failing(), Ok(1)); + { + let cache = ALWAYS_FAILING.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(1)); + } + + std::thread::sleep(std::time::Duration::from_millis(2000)); + + // Even though the cache should've expired, the `result_fallback` flag means it refreshes the cache with the last valid result + assert_eq!(always_failing(), Ok(1)); + { + let cache = ALWAYS_FAILING.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(1)); + assert_eq!(cache.cache_misses(), Some(2)); + } + + assert_eq!(always_failing(), Ok(1)); + { + let cache = ALWAYS_FAILING.lock().unwrap(); + assert_eq!(cache.cache_hits(), Some(2)); + assert_eq!(cache.cache_misses(), Some(2)); + } +} diff --git a/vendor/cached_proc_macro/.cargo-checksum.json b/vendor/cached_proc_macro/.cargo-checksum.json new file mode 100644 index 0000000000000..32fc6b99d7838 --- /dev/null +++ b/vendor/cached_proc_macro/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"aa52376fbfc2c0cbc77458987bc6749ad18c4837a7af62ed62c1f1f790225989","LICENSE":"8e65cf73127700ffe243f50963547dd6c297190945033677e29eecdde69d666f","README.md":"ed2d5d03ab40366ac05d662c055df3219fdad2aeabcdc7c68619f2758b1aa128","src/cached.rs":"82bffaf24db0bef27f9782a65cba043728aa6146fc4f9ef986c8b8ed5310ca6c","src/helpers.rs":"e06fa0d2ec7577e62523aca11ef61f76cd90137662d05bae9ed631adbe0399d1","src/io_cached.rs":"25622e14239c5d95ae5cfd5bc2fbcae7023b0cbdfdf27050ed78f4c156d2c8bc","src/lib.rs":"963ff22affc672b73d6a54f261bb13facc139cfef047834cd57cbd3b1153812f","src/once.rs":"d00a7f27f682551706e7fd302a9eee8c04da1298c0540957582eb112e42946be"},"package":"ad9f16c0d84de31a2ab7fdf5f7783c14631f7075cf464eb3bb43119f61c9cb2a"} \ No newline at end of file diff --git a/vendor/cached_proc_macro/Cargo.toml b/vendor/cached_proc_macro/Cargo.toml new file mode 100644 index 0000000000000..dacad07959e4c --- /dev/null +++ b/vendor/cached_proc_macro/Cargo.toml @@ -0,0 +1,47 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "cached_proc_macro" +version = "0.20.0" +authors = [ + "csos95 ", + "James Kominick ", +] +description = "Generic cache implementations and simplified function memoization" +documentation = "https://docs.rs/cached" +readme = "README.md" +keywords = [ + "caching", + "cache", + "memoize", + "lru", +] +categories = ["caching"] +license = "MIT" +repository = "https://github.com/jaemk/cached" + +[lib] +proc-macro = true + +[dependencies.darling] +version = "0.14.2" + +[dependencies.proc-macro2] +version = "1.0.49" + +[dependencies.quote] +version = "1.0.6" + +[dependencies.syn] +version = "1.0.27" +features = ["full"] diff --git a/vendor/cached_proc_macro/LICENSE b/vendor/cached_proc_macro/LICENSE new file mode 100644 index 0000000000000..3b332da1eb1c3 --- /dev/null +++ b/vendor/cached_proc_macro/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 James Kominick + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/cached_proc_macro/README.md b/vendor/cached_proc_macro/README.md new file mode 100644 index 0000000000000..1fe12c3ed9a28 --- /dev/null +++ b/vendor/cached_proc_macro/README.md @@ -0,0 +1 @@ +See https://crates.io/crates/cached diff --git a/vendor/cached_proc_macro/src/cached.rs b/vendor/cached_proc_macro/src/cached.rs new file mode 100644 index 0000000000000..21534ddc82880 --- /dev/null +++ b/vendor/cached_proc_macro/src/cached.rs @@ -0,0 +1,332 @@ +use crate::helpers::*; +use darling::FromMeta; +use proc_macro::TokenStream; +use quote::quote; +use syn::spanned::Spanned; +use syn::{parse_macro_input, parse_str, AttributeArgs, Block, Ident, ItemFn, ReturnType, Type}; + +#[derive(FromMeta)] +struct MacroArgs { + #[darling(default)] + name: Option, + #[darling(default)] + unbound: bool, + #[darling(default)] + size: Option, + #[darling(default)] + time: Option, + #[darling(default)] + time_refresh: bool, + #[darling(default)] + key: Option, + #[darling(default)] + convert: Option, + #[darling(default)] + result: bool, + #[darling(default)] + option: bool, + #[darling(default)] + sync_writes: bool, + #[darling(default)] + with_cached_flag: bool, + #[darling(default, rename = "type")] + cache_type: Option, + #[darling(default, rename = "create")] + cache_create: Option, + #[darling(default)] + result_fallback: bool, +} + +pub fn cached(args: TokenStream, input: TokenStream) -> TokenStream { + let attr_args = parse_macro_input!(args as AttributeArgs); + let args = match MacroArgs::from_list(&attr_args) { + Ok(v) => v, + Err(e) => { + return TokenStream::from(e.write_errors()); + } + }; + let input = parse_macro_input!(input as ItemFn); + + // pull out the parts of the input + let mut attributes = input.attrs; + let visibility = input.vis; + let signature = input.sig; + let body = input.block; + + // pull out the parts of the function signature + let fn_ident = signature.ident.clone(); + let inputs = signature.inputs.clone(); + let output = signature.output.clone(); + let asyncness = signature.asyncness; + + let input_tys = get_input_types(&inputs); + let input_names = get_input_names(&inputs); + + // pull out the output type + let output_ty = match &output { + ReturnType::Default => quote! {()}, + ReturnType::Type(_, ty) => quote! {#ty}, + }; + + let output_span = output_ty.span(); + let output_ts = TokenStream::from(output_ty.clone()); + let output_parts = get_output_parts(&output_ts); + let output_string = output_parts.join("::"); + let output_type_display = output_ts.to_string().replace(' ', ""); + + if check_with_cache_flag(args.with_cached_flag, output_string) { + return with_cache_flag_error(output_span, output_type_display); + } + + let cache_value_ty = find_value_type(args.result, args.option, &output, output_ty); + + // make the cache identifier + let cache_ident = match args.name { + Some(ref name) => Ident::new(name, fn_ident.span()), + None => Ident::new(&fn_ident.to_string().to_uppercase(), fn_ident.span()), + }; + + let (cache_key_ty, key_convert_block) = make_cache_key_type( + &args.key, + &args.convert, + &args.cache_type, + input_tys, + &input_names, + ); + + // make the cache type and create statement + let (cache_ty, cache_create) = match ( + &args.unbound, + &args.size, + &args.time, + &args.cache_type, + &args.cache_create, + &args.time_refresh, + ) { + (true, None, None, None, None, _) => { + let cache_ty = quote! {cached::UnboundCache<#cache_key_ty, #cache_value_ty>}; + let cache_create = quote! {cached::UnboundCache::new()}; + (cache_ty, cache_create) + } + (false, Some(size), None, None, None, _) => { + let cache_ty = quote! {cached::SizedCache<#cache_key_ty, #cache_value_ty>}; + let cache_create = quote! {cached::SizedCache::with_size(#size)}; + (cache_ty, cache_create) + } + (false, None, Some(time), None, None, time_refresh) => { + let cache_ty = quote! {cached::TimedCache<#cache_key_ty, #cache_value_ty>}; + let cache_create = + quote! {cached::TimedCache::with_lifespan_and_refresh(#time, #time_refresh)}; + (cache_ty, cache_create) + } + (false, Some(size), Some(time), None, None, time_refresh) => { + let cache_ty = quote! {cached::TimedSizedCache<#cache_key_ty, #cache_value_ty>}; + let cache_create = quote! {cached::TimedSizedCache::with_size_and_lifespan_and_refresh(#size, #time, #time_refresh)}; + (cache_ty, cache_create) + } + (false, None, None, None, None, _) => { + let cache_ty = quote! {cached::UnboundCache<#cache_key_ty, #cache_value_ty>}; + let cache_create = quote! {cached::UnboundCache::new()}; + (cache_ty, cache_create) + } + (false, None, None, Some(type_str), Some(create_str), _) => { + let cache_type = parse_str::(type_str).expect("unable to parse cache type"); + + let cache_create = + parse_str::(create_str).expect("unable to parse cache create block"); + + (quote! { #cache_type }, quote! { #cache_create }) + } + (false, None, None, Some(_), None, _) => { + panic!("type requires create to also be set") + } + (false, None, None, None, Some(_), _) => { + panic!("create requires type to also be set") + } + _ => panic!( + "cache types (unbound, size and/or time, or type and create) are mutually exclusive" + ), + }; + + // make the set cache and return cache blocks + let (set_cache_block, return_cache_block) = match (&args.result, &args.option) { + (false, false) => { + let set_cache_block = quote! { cache.cache_set(key, result.clone()); }; + let return_cache_block = if args.with_cached_flag { + quote! { let mut r = result.clone(); r.was_cached = true; return r } + } else { + quote! { return result.clone() } + }; + (set_cache_block, return_cache_block) + } + (true, false) => { + let set_cache_block = quote! { + if let Ok(result) = &result { + cache.cache_set(key, result.clone()); + } + }; + let return_cache_block = if args.with_cached_flag { + quote! { let mut r = result.clone(); r.was_cached = true; return Ok(r) } + } else { + quote! { return Ok(result.clone()) } + }; + (set_cache_block, return_cache_block) + } + (false, true) => { + let set_cache_block = quote! { + if let Some(result) = &result { + cache.cache_set(key, result.clone()); + } + }; + let return_cache_block = if args.with_cached_flag { + quote! { let mut r = result.clone(); r.was_cached = true; return Some(r) } + } else { + quote! { return Some(result.clone()) } + }; + (set_cache_block, return_cache_block) + } + _ => panic!("the result and option attributes are mutually exclusive"), + }; + + let set_cache_and_return = quote! { + #set_cache_block + result + }; + + let no_cache_fn_ident = Ident::new(&format!("{}_no_cache", &fn_ident), fn_ident.span()); + + let lock; + let function_no_cache; + let function_call; + let cache_type; + if asyncness.is_some() { + lock = quote! { + let mut cache = #cache_ident.lock().await; + }; + + function_no_cache = quote! { + async fn #no_cache_fn_ident(#inputs) #output #body + }; + + function_call = quote! { + let result = #no_cache_fn_ident(#(#input_names),*).await; + }; + + cache_type = quote! { + #visibility static #cache_ident: ::cached::once_cell::sync::Lazy<::cached::async_sync::Mutex<#cache_ty>> = ::cached::once_cell::sync::Lazy::new(|| ::cached::async_sync::Mutex::new(#cache_create)); + }; + } else { + lock = quote! { + let mut cache = #cache_ident.lock().unwrap(); + }; + + function_no_cache = quote! { + fn #no_cache_fn_ident(#inputs) #output #body + }; + + function_call = quote! { + let result = #no_cache_fn_ident(#(#input_names),*); + }; + + cache_type = quote! { + #visibility static #cache_ident: ::cached::once_cell::sync::Lazy> = ::cached::once_cell::sync::Lazy::new(|| std::sync::Mutex::new(#cache_create)); + }; + } + + let prime_do_set_return_block = quote! { + // try to get a lock first + #lock + // run the function and cache the result + #function_call + #set_cache_and_return + }; + + let do_set_return_block = if args.sync_writes { + quote! { + #lock + if let Some(result) = cache.cache_get(&key) { + #return_cache_block + } + #function_call + #set_cache_and_return + } + } else if args.result_fallback { + quote! { + let old_val = { + #lock + let (result, has_expired) = cache.cache_get_expired(&key); + if let (Some(result), false) = (result, has_expired) { + #return_cache_block + } + result + }; + #function_call + #lock + let result = match (result.is_err(), old_val) { + (true, Some(old_val)) => { + Ok(old_val) + } + _ => result + }; + #set_cache_and_return + } + } else { + quote! { + { + #lock + if let Some(result) = cache.cache_get(&key) { + #return_cache_block + } + } + #function_call + #lock + #set_cache_and_return + } + }; + + let signature_no_muts = get_mut_signature(signature); + + // create a signature for the cache-priming function + let prime_fn_ident = Ident::new(&format!("{}_prime_cache", &fn_ident), fn_ident.span()); + let mut prime_sig = signature_no_muts.clone(); + prime_sig.ident = prime_fn_ident; + + // make cached static, cached function and prime cached function doc comments + let cache_ident_doc = format!("Cached static for the [`{}`] function.", fn_ident); + let no_cache_fn_indent_doc = format!("Origin of the cached function [`{}`].", fn_ident); + let prime_fn_indent_doc = format!("Primes the cached function [`{}`].", fn_ident); + let cache_fn_doc_extra = format!( + "This is a cached function that uses the [`{}`] cached static.", + cache_ident + ); + fill_in_attributes(&mut attributes, cache_fn_doc_extra); + + // put it all together + let expanded = quote! { + // Cached static + #[doc = #cache_ident_doc] + #cache_type + // No cache function (origin of the cached function) + #[doc = #no_cache_fn_indent_doc] + #visibility #function_no_cache + // Cached function + #(#attributes)* + #visibility #signature_no_muts { + use cached::Cached; + use cached::CloneCached; + let key = #key_convert_block; + #do_set_return_block + } + // Prime cached function + #[doc = #prime_fn_indent_doc] + #[allow(dead_code)] + #(#attributes)* + #visibility #prime_sig { + use cached::Cached; + let key = #key_convert_block; + #prime_do_set_return_block + } + }; + + expanded.into() +} diff --git a/vendor/cached_proc_macro/src/helpers.rs b/vendor/cached_proc_macro/src/helpers.rs new file mode 100644 index 0000000000000..f75eae84e0e6c --- /dev/null +++ b/vendor/cached_proc_macro/src/helpers.rs @@ -0,0 +1,220 @@ +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; +use quote::__private::Span; +use quote::quote; +use std::ops::Deref; +use syn::punctuated::Punctuated; +use syn::token::Comma; +use syn::{ + parse_quote, parse_str, Attribute, Block, FnArg, Pat, PatType, PathArguments, ReturnType, + Signature, Type, +}; + +// if you define arguments as mutable, e.g. +// #[cached] +// fn mutable_args(mut a: i32, mut b: i32) -> (i32, i32) { +// a += 1; +// b += 1; +// (a, b) +// } +// then we want the `mut` keywords present on the "inner" function +// that wraps your actual block of code. +// If the `mut`s are also on the outer method, then you'll +// get compiler warnings about your arguments not needing to be `mut` +// when they really do need to be. +pub(super) fn get_mut_signature(signature: Signature) -> Signature { + let mut signature_no_muts = signature; + let mut sig_inputs = Punctuated::new(); + for inp in &signature_no_muts.inputs { + let item = match inp { + FnArg::Receiver(_) => inp.clone(), + FnArg::Typed(pat_type) => { + let mut pt = pat_type.clone(); + let pat = match_pattern_type(&pat_type); + pt.pat = pat; + FnArg::Typed(pt) + } + }; + sig_inputs.push(item); + } + signature_no_muts.inputs = sig_inputs; + signature_no_muts +} + +pub(super) fn match_pattern_type(pat_type: &&PatType) -> Box { + match &pat_type.pat.deref() { + Pat::Ident(pat_ident) => { + if pat_ident.mutability.is_some() { + let mut p = pat_ident.clone(); + p.mutability = None; + Box::new(Pat::Ident(p)) + } else { + Box::new(Pat::Ident(pat_ident.clone())) + } + } + _ => pat_type.pat.clone(), + } +} + +// Find the type of the value to store. +// Normally it's the same as the return type of the functions, but +// for Options and Results it's the (first) inner type. So for +// Option, store u32, for Result, store i32, etc. +pub(super) fn find_value_type( + result: bool, + option: bool, + output: &ReturnType, + output_ty: TokenStream2, +) -> TokenStream2 { + match (result, option) { + (false, false) => output_ty, + (true, true) => panic!("the result and option attributes are mutually exclusive"), + _ => match output.clone() { + ReturnType::Default => { + panic!("function must return something for result or option attributes") + } + ReturnType::Type(_, ty) => { + if let Type::Path(typepath) = *ty { + let segments = typepath.path.segments; + if let PathArguments::AngleBracketed(brackets) = + &segments.last().unwrap().arguments + { + let inner_ty = brackets.args.first().unwrap(); + quote! {#inner_ty} + } else { + panic!("function return type has no inner type") + } + } else { + panic!("function return type too complex") + } + } + }, + } +} + +// make the cache key type and block that converts the inputs into the key type +pub(super) fn make_cache_key_type( + key: &Option, + convert: &Option, + cache_type: &Option, + input_tys: Vec, + input_names: &Vec, +) -> (TokenStream2, TokenStream2) { + match (key, convert, cache_type) { + (Some(key_str), Some(convert_str), _) => { + let cache_key_ty = parse_str::(key_str).expect("unable to parse cache key type"); + + let key_convert_block = + parse_str::(convert_str).expect("unable to parse key convert block"); + + (quote! {#cache_key_ty}, quote! {#key_convert_block}) + } + (None, Some(convert_str), Some(_)) => { + let key_convert_block = + parse_str::(convert_str).expect("unable to parse key convert block"); + + (quote! {}, quote! {#key_convert_block}) + } + (None, None, _) => ( + quote! {(#(#input_tys),*)}, + quote! {(#(#input_names.clone()),*)}, + ), + (Some(_), None, _) => panic!("key requires convert to be set"), + (None, Some(_), None) => panic!("convert requires key or type to be set"), + } +} + +// if you define arguments as mutable, e.g. +// #[once] +// fn mutable_args(mut a: i32, mut b: i32) -> (i32, i32) { +// a += 1; +// b += 1; +// (a, b) +// } +// then we need to strip off the `mut` keyword from the +// variable identifiers, so we can refer to arguments `a` and `b` +// instead of `mut a` and `mut b` +pub(super) fn get_input_names(inputs: &Punctuated) -> Vec { + inputs + .iter() + .map(|input| match input { + FnArg::Receiver(_) => panic!("methods (functions taking 'self') are not supported"), + FnArg::Typed(pat_type) => *match_pattern_type(&pat_type), + }) + .collect() +} + +pub(super) fn fill_in_attributes(attributes: &mut Vec, cache_fn_doc_extra: String) { + if attributes.iter().any(|attr| attr.path.is_ident("doc")) { + attributes.push(parse_quote! { #[doc = ""] }); + attributes.push(parse_quote! { #[doc = "# Caching"] }); + attributes.push(parse_quote! { #[doc = #cache_fn_doc_extra] }); + } else { + attributes.push(parse_quote! { #[doc = #cache_fn_doc_extra] }); + } +} + +// pull out the names and types of the function inputs +pub(super) fn get_input_types(inputs: &Punctuated) -> Vec { + inputs + .iter() + .map(|input| match input { + FnArg::Receiver(_) => panic!("methods (functions taking 'self') are not supported"), + FnArg::Typed(pat_type) => *pat_type.ty.clone(), + }) + .collect() +} + +pub(super) fn get_output_parts(output_ts: &TokenStream) -> Vec { + output_ts + .clone() + .into_iter() + .filter_map(|tt| match tt { + proc_macro::TokenTree::Ident(ident) => Some(ident.to_string()), + _ => None, + }) + .collect() +} + +pub(super) fn with_cache_flag_error(output_span: Span, output_type_display: String) -> TokenStream { + syn::Error::new( + output_span, + format!( + "\nWhen specifying `with_cached_flag = true`, \ + the return type must be wrapped in `cached::Return`. \n\ + The following return types are supported: \n\ + | `cached::Return`\n\ + | `std::result::Result, E>`\n\ + | `std::option::Option>`\n\ + Found type: {t}.", + t = output_type_display + ), + ) + .to_compile_error() + .into() +} + +pub(super) fn gen_return_cache_block( + time: Option, + return_cache_block: TokenStream2, +) -> TokenStream2 { + if let Some(time) = &time { + quote! { + let (created_sec, result) = result; + if now.duration_since(*created_sec).as_secs() < #time { + #return_cache_block + } + } + } else { + quote! { #return_cache_block } + } +} + +// if `with_cached_flag = true`, then enforce that the return type +// is something wrapped in `Return`. Either `Return` or the +// fully qualified `cached::Return` +pub(super) fn check_with_cache_flag(with_cached_flag: bool, output_string: String) -> bool { + with_cached_flag + && !output_string.contains("Return") + && !output_string.contains("cached::Return") +} diff --git a/vendor/cached_proc_macro/src/io_cached.rs b/vendor/cached_proc_macro/src/io_cached.rs new file mode 100644 index 0000000000000..4c38843124e7f --- /dev/null +++ b/vendor/cached_proc_macro/src/io_cached.rs @@ -0,0 +1,491 @@ +use crate::helpers::*; +use darling::FromMeta; +use proc_macro::TokenStream; +use quote::quote; +use syn::spanned::Spanned; +use syn::{ + parse_macro_input, parse_str, AttributeArgs, Block, ExprClosure, GenericArgument, Ident, + ItemFn, PathArguments, ReturnType, Type, +}; + +#[derive(FromMeta)] +struct IOMacroArgs { + map_error: String, + #[darling(default)] + disk: bool, + #[darling(default)] + disk_dir: Option, + #[darling(default)] + redis: bool, + #[darling(default)] + cache_prefix_block: Option, + #[darling(default)] + name: Option, + #[darling(default)] + time: Option, + #[darling(default)] + time_refresh: Option, + #[darling(default)] + key: Option, + #[darling(default)] + convert: Option, + #[darling(default)] + with_cached_flag: bool, + #[darling(default, rename = "type")] + cache_type: Option, + #[darling(default, rename = "create")] + cache_create: Option, +} + +pub fn io_cached(args: TokenStream, input: TokenStream) -> TokenStream { + let attr_args = parse_macro_input!(args as AttributeArgs); + let args = match IOMacroArgs::from_list(&attr_args) { + Ok(v) => v, + Err(e) => { + return TokenStream::from(e.write_errors()); + } + }; + let input = parse_macro_input!(input as ItemFn); + + // pull out the parts of the input + let mut attributes = input.attrs; + let visibility = input.vis; + let signature = input.sig; + let body = input.block; + + // pull out the parts of the function signature + let fn_ident = signature.ident.clone(); + let inputs = signature.inputs.clone(); + let output = signature.output.clone(); + let asyncness = signature.asyncness; + + let input_tys = get_input_types(&inputs); + + let input_names = get_input_names(&inputs); + + // pull out the output type + let output_ty = match &output { + ReturnType::Default => quote! {()}, + ReturnType::Type(_, ty) => quote! {#ty}, + }; + + let output_span = output_ty.span(); + let output_ts = TokenStream::from(output_ty); + let output_parts = get_output_parts(&output_ts); + let output_string = output_parts.join("::"); + let output_type_display = output_ts.to_string().replace(' ', ""); + + // if `with_cached_flag = true`, then enforce that the return type + // is something wrapped in `Return`. Either `Return` or the + // fully qualified `cached::Return` + if args.with_cached_flag + && !output_string.contains("Return") + && !output_string.contains("cached::Return") + { + return syn::Error::new( + output_span, + format!( + "\nWhen specifying `with_cached_flag = true`, \ + the return type must be wrapped in `cached::Return`. \n\ + The following return types are supported: \n\ + | `Result, E>`\n\ + Found type: {t}.", + t = output_type_display + ), + ) + .to_compile_error() + .into(); + } + + // Find the type of the value to store. + // Return type always needs to be a result, so we want the (first) inner type. + // For Result, store i32, etc. + let cache_value_ty = match output.clone() { + ReturnType::Default => { + panic!( + "#[io_cached] functions must return `Result`s, found {:?}", + output_type_display + ); + } + ReturnType::Type(_, ty) => { + if let Type::Path(typepath) = *ty { + let segments = typepath.path.segments; + if let PathArguments::AngleBracketed(brackets) = &segments.last().unwrap().arguments + { + let inner_ty = brackets.args.first().unwrap(); + if output_string.contains("Return") || output_string.contains("cached::Return") + { + if let GenericArgument::Type(Type::Path(typepath)) = inner_ty { + let segments = &typepath.path.segments; + if let PathArguments::AngleBracketed(brackets) = + &segments.last().unwrap().arguments + { + let inner_ty = brackets.args.first().unwrap(); + quote! {#inner_ty} + } else { + panic!( + "#[io_cached] unable to determine cache value type, found {:?}", + output_type_display + ); + } + } else { + panic!( + "#[io_cached] unable to determine cache value type, found {:?}", + output_type_display + ); + } + } else { + quote! {#inner_ty} + } + } else { + panic!("#[io_cached] functions must return `Result`s") + } + } else { + panic!( + "function return type too complex, #[io_cached] functions must return `Result`s" + ) + } + } + }; + + // make the cache identifier + let cache_ident = match args.name { + Some(ref name) => Ident::new(name, fn_ident.span()), + None => Ident::new(&fn_ident.to_string().to_uppercase(), fn_ident.span()), + }; + let cache_name = cache_ident.to_string(); + + let (cache_key_ty, key_convert_block) = make_cache_key_type( + &args.key, + &args.convert, + &args.cache_type, + input_tys, + &input_names, + ); + + // make the cache type and create statement + let (cache_ty, cache_create) = match ( + &args.redis, + &args.disk, + &args.time, + &args.time_refresh, + &args.cache_prefix_block, + &args.cache_type, + &args.cache_create, + ) { + // redis + (true, false, time, time_refresh, cache_prefix, cache_type, cache_create) => { + let cache_ty = match cache_type { + Some(cache_type) => { + let cache_type = + parse_str::(cache_type).expect("unable to parse cache type"); + quote! { #cache_type } + } + None => { + if asyncness.is_some() { + quote! { cached::AsyncRedisCache<#cache_key_ty, #cache_value_ty> } + } else { + quote! { cached::RedisCache<#cache_key_ty, #cache_value_ty> } + } + } + }; + let cache_create = match cache_create { + Some(cache_create) => { + if time.is_some() || time_refresh.is_some() || cache_prefix.is_some() { + panic!("cannot specify `time`, `time_refresh`, or `cache_prefix` when passing `create block"); + } else { + let cache_create = parse_str::(cache_create.as_ref()) + .expect("unable to parse cache create block"); + quote! { #cache_create } + } + } + None => { + if time.is_none() { + if asyncness.is_some() { + panic!("AsyncRedisCache requires a `time` when `create` block is not specified") + } else { + panic!( + "RedisCache requires a `time` when `create` block is not specified" + ) + }; + } else { + let cache_prefix = if let Some(cp) = cache_prefix { + cp.to_string() + } else { + format!(" {{ \"cached::proc_macro::io_cached::{}\" }}", cache_ident) + }; + let cache_prefix = parse_str::(cache_prefix.as_ref()) + .expect("unable to parse cache_prefix_block"); + match time_refresh { + Some(time_refresh) => { + if asyncness.is_some() { + quote! { cached::AsyncRedisCache::new(#cache_prefix, #time).set_refresh(#time_refresh).build().await.expect("error constructing AsyncRedisCache in #[io_cached] macro") } + } else { + quote! { + cached::RedisCache::new(#cache_prefix, #time).set_refresh(#time_refresh).build().expect("error constructing RedisCache in #[io_cached] macro") + } + } + } + None => { + if asyncness.is_some() { + quote! { cached::AsyncRedisCache::new(#cache_prefix, #time).build().await.expect("error constructing AsyncRedisCache in #[io_cached] macro") } + } else { + quote! { + cached::RedisCache::new(#cache_prefix, #time).build().expect("error constructing RedisCache in #[io_cached] macro") + } + } + } + } + } + } + }; + (cache_ty, cache_create) + } + // disk + (false, true, time, time_refresh, _, cache_type, cache_create) => { + let cache_ty = match cache_type { + Some(cache_type) => { + let cache_type = + parse_str::(cache_type).expect("unable to parse cache type"); + quote! { #cache_type } + } + None => { + // https://github.com/spacejam/sled?tab=readme-ov-file#interaction-with-async + quote! { cached::DiskCache<#cache_key_ty, #cache_value_ty> } + } + }; + let cache_create = match cache_create { + Some(cache_create) => { + if time.is_some() || time_refresh.is_some() { + panic!( + "cannot specify `time` or `time_refresh` when passing `create block" + ); + } else { + let cache_create = parse_str::(cache_create.as_ref()) + .expect("unable to parse cache create block"); + quote! { #cache_create } + } + } + None => { + let create = quote! { + cached::DiskCache::new(#cache_name) + }; + let create = match time { + None => create, + Some(time) => { + quote! { + (#create).set_lifespan(#time) + } + } + }; + let create = match time_refresh { + None => create, + Some(time_refresh) => { + quote! { + (#create).set_refresh(#time_refresh) + } + } + }; + let create = match args.disk_dir { + None => create, + Some(disk_dir) => { + quote! { (#create).set_disk_directory(#disk_dir) } + } + }; + quote! { (#create).build().expect("error constructing DiskCache in #[io_cached] macro") } + } + }; + (cache_ty, cache_create) + } + (_, _, time, time_refresh, cache_prefix, cache_type, cache_create) => { + let cache_ty = match cache_type { + Some(cache_type) => { + let cache_type = + parse_str::(cache_type).expect("unable to parse cache type"); + quote! { #cache_type } + } + None => panic!("#[io_cached] cache `type` must be specified"), + }; + let cache_create = match cache_create { + Some(cache_create) => { + if time.is_some() || time_refresh.is_some() || cache_prefix.is_some() { + panic!("cannot specify `time`, `time_refresh`, or `cache_prefix` when passing `create block"); + } else { + let cache_create = parse_str::(cache_create.as_ref()) + .expect("unable to parse cache create block"); + quote! { #cache_create } + } + } + None => { + panic!("#[io_cached] cache `create` block must be specified"); + } + }; + (cache_ty, cache_create) + } + #[allow(unreachable_patterns)] + _ => panic!("#[io_cached] cache types cache type could not be determined"), + }; + + let map_error = &args.map_error; + let map_error = parse_str::(map_error).expect("unable to parse map_error block"); + + // make the set cache and return cache blocks + let (set_cache_block, return_cache_block) = { + let (set_cache_block, return_cache_block) = if args.with_cached_flag { + ( + if asyncness.is_some() && !args.disk { + quote! { + if let Ok(result) = &result { + cache.cache_set(key, result.value.clone()).await.map_err(#map_error)?; + } + } + } else { + quote! { + if let Ok(result) = &result { + cache.cache_set(key, result.value.clone()).map_err(#map_error)?; + } + } + }, + quote! { let mut r = ::cached::Return::new(result.clone()); r.was_cached = true; return Ok(r) }, + ) + } else { + ( + if asyncness.is_some() && !args.disk { + quote! { + if let Ok(result) = &result { + cache.cache_set(key, result.clone()).await.map_err(#map_error)?; + } + } + } else { + quote! { + if let Ok(result) = &result { + cache.cache_set(key, result.clone()).map_err(#map_error)?; + } + } + }, + quote! { return Ok(result.clone()) }, + ) + }; + (set_cache_block, return_cache_block) + }; + + let do_set_return_block = if asyncness.is_some() { + quote! { + // run the function and cache the result + async fn inner(#inputs) #output #body; + let result = inner(#(#input_names),*).await; + let cache = &#cache_ident.get_or_init(init).await; + #set_cache_block + result + } + } else { + quote! { + // run the function and cache the result + fn inner(#inputs) #output #body; + let result = inner(#(#input_names),*); + let cache = &#cache_ident; + #set_cache_block + result + } + }; + + let signature_no_muts = get_mut_signature(signature); + + // create a signature for the cache-priming function + let prime_fn_ident = Ident::new(&format!("{}_prime_cache", &fn_ident), fn_ident.span()); + let mut prime_sig = signature_no_muts.clone(); + prime_sig.ident = prime_fn_ident; + + // make cached static, cached function and prime cached function doc comments + let cache_ident_doc = format!("Cached static for the [`{}`] function.", fn_ident); + let prime_fn_indent_doc = format!("Primes the cached function [`{}`].", fn_ident); + let cache_fn_doc_extra = format!( + "This is a cached function that uses the [`{}`] cached static.", + cache_ident + ); + fill_in_attributes(&mut attributes, cache_fn_doc_extra); + + let async_trait = if asyncness.is_some() && !args.disk { + quote! { + use cached::IOCachedAsync; + } + } else { + quote! { + use cached::IOCached; + } + }; + + let async_cache_get_return = if asyncness.is_some() && !args.disk { + quote! { + if let Some(result) = cache.cache_get(&key).await.map_err(#map_error)? { + #return_cache_block + } + } + } else { + quote! { + if let Some(result) = cache.cache_get(&key).map_err(#map_error)? { + #return_cache_block + } + } + }; + // put it all together + let expanded = if asyncness.is_some() { + quote! { + // Cached static + #[doc = #cache_ident_doc] + #visibility static #cache_ident: ::cached::async_sync::OnceCell<#cache_ty> = ::cached::async_sync::OnceCell::const_new(); + // Cached function + #(#attributes)* + #visibility #signature_no_muts { + let init = || async { #cache_create }; + #async_trait + let key = #key_convert_block; + { + // check if the result is cached + let cache = &#cache_ident.get_or_init(init).await; + #async_cache_get_return + } + #do_set_return_block + } + // Prime cached function + #[doc = #prime_fn_indent_doc] + #[allow(dead_code)] + #visibility #prime_sig { + #async_trait + let init = || async { #cache_create }; + let key = #key_convert_block; + #do_set_return_block + } + } + } else { + quote! { + // Cached static + #[doc = #cache_ident_doc] + #visibility static #cache_ident: ::cached::once_cell::sync::Lazy<#cache_ty> = ::cached::once_cell::sync::Lazy::new(|| #cache_create); + // Cached function + #(#attributes)* + #visibility #signature_no_muts { + use cached::IOCached; + let key = #key_convert_block; + { + // check if the result is cached + let cache = &#cache_ident; + if let Some(result) = cache.cache_get(&key).map_err(#map_error)? { + #return_cache_block + } + } + #do_set_return_block + } + // Prime cached function + #[doc = #prime_fn_indent_doc] + #[allow(dead_code)] + #visibility #prime_sig { + use cached::IOCached; + let key = #key_convert_block; + #do_set_return_block + } + } + }; + + expanded.into() +} diff --git a/vendor/cached_proc_macro/src/lib.rs b/vendor/cached_proc_macro/src/lib.rs new file mode 100644 index 0000000000000..6a4a99836cce4 --- /dev/null +++ b/vendor/cached_proc_macro/src/lib.rs @@ -0,0 +1,96 @@ +mod cached; +mod helpers; +mod io_cached; +mod once; + +use proc_macro::TokenStream; + +/// Define a memoized function using a cache store that implements `cached::Cached` (and +/// `cached::CachedAsync` for async functions) +/// +/// # Attributes +/// - `name`: (optional, string) specify the name for the generated cache, defaults to the function name uppercase. +/// - `size`: (optional, usize) specify an LRU max size, implies the cache type is a `SizedCache` or `TimedSizedCache`. +/// - `time`: (optional, u64) specify a cache TTL in seconds, implies the cache type is a `TimedCache` or `TimedSizedCache`. +/// - `time_refresh`: (optional, bool) specify whether to refresh the TTL on cache hits. +/// - `sync_writes`: (optional, bool) specify whether to synchronize the execution of writing of uncached values. +/// - `type`: (optional, string type) The cache store type to use. Defaults to `UnboundCache`. When `unbound` is +/// specified, defaults to `UnboundCache`. When `size` is specified, defaults to `SizedCache`. +/// When `time` is specified, defaults to `TimedCached`. +/// When `size` and `time` are specified, defaults to `TimedSizedCache`. When `type` is +/// specified, `create` must also be specified. +/// - `create`: (optional, string expr) specify an expression used to create a new cache store, e.g. `create = r##"{ CacheType::new() }"##`. +/// - `key`: (optional, string type) specify what type to use for the cache key, e.g. `key = "u32"`. +/// When `key` is specified, `convert` must also be specified. +/// - `convert`: (optional, string expr) specify an expression used to convert function arguments to a cache +/// key, e.g. `convert = r##"{ format!("{}:{}", arg1, arg2) }"##`. When `convert` is specified, +/// `key` or `type` must also be set. +/// - `result`: (optional, bool) If your function returns a `Result`, only cache `Ok` values returned by the function. +/// - `option`: (optional, bool) If your function returns an `Option`, only cache `Some` values returned by the function. +/// - `with_cached_flag`: (optional, bool) If your function returns a `cached::Return` or `Result`, +/// the `cached::Return.was_cached` flag will be updated when a cached value is returned. +/// - `result_fallback`: (optional, bool) If your function returns a `Result` and it fails, the cache will instead refresh the recently expired `Ok` value. +/// In other words, refreshes are best-effort - returning `Ok` refreshes as usual but `Err` falls back to the last `Ok`. +/// This is useful, for example, for keeping the last successful result of a network operation even during network disconnects. +/// *Note*, this option requires the cache type implements `CloneCached`. +/// +/// ## Note +/// The `type`, `create`, `key`, and `convert` attributes must be in a `String` +/// This is because darling, which is used for parsing the attributes, does not support directly parsing +/// attributes into `Type`s or `Block`s. +#[proc_macro_attribute] +pub fn cached(args: TokenStream, input: TokenStream) -> TokenStream { + cached::cached(args, input) +} + +/// Define a memoized function using a cache store that implements `cached::Cached` (and +/// `cached::CachedAsync` for async functions). Function arguments are not used to identify +/// a cached value, only one value is cached unless a `time` expiry is specified. +/// +/// # Attributes +/// - `name`: (optional, string) specify the name for the generated cache, defaults to the function name uppercase. +/// - `time`: (optional, u64) specify a cache TTL in seconds, implies the cache type is a `TimedCached` or `TimedSizedCache`. +/// - `sync_writes`: (optional, bool) specify whether to synchronize the execution of writing of uncached values. +/// - `result`: (optional, bool) If your function returns a `Result`, only cache `Ok` values returned by the function. +/// - `option`: (optional, bool) If your function returns an `Option`, only cache `Some` values returned by the function. +/// - `with_cached_flag`: (optional, bool) If your function returns a `cached::Return` or `Result`, +/// the `cached::Return.was_cached` flag will be updated when a cached value is returned. +#[proc_macro_attribute] +pub fn once(args: TokenStream, input: TokenStream) -> TokenStream { + once::once(args, input) +} + +/// Define a memoized function using a cache store that implements `cached::IOCached` (and +/// `cached::IOCachedAsync` for async functions) +/// +/// # Attributes +/// - `map_error`: (string, expr closure) specify a closure used to map any IO-store errors into +/// the error type returned by your function. +/// - `name`: (optional, string) specify the name for the generated cache, defaults to the function name uppercase. +/// - `redis`: (optional, bool) default to a `RedisCache` or `AsyncRedisCache` +/// - `disk`: (optional, bool) use a `DiskCache`, this must be set to true even if `type` and `create` are specified. +/// - `time`: (optional, u64) specify a cache TTL in seconds, implies the cache type is a `TimedCached` or `TimedSizedCache`. +/// - `time_refresh`: (optional, bool) specify whether to refresh the TTL on cache hits. +/// - `type`: (optional, string type) explicitly specify the cache store type to use. +/// - `cache_prefix_block`: (optional, string expr) specify an expression used to create the string used as a +/// prefix for all cache keys of this function, e.g. `cache_prefix_block = r##"{ "my_prefix" }"##`. +/// When not specified, the cache prefix will be constructed from the name of the function. This +/// could result in unexpected conflicts between io_cached-functions of the same name, so it's +/// recommended that you specify a prefix you're sure will be unique. +/// - `create`: (optional, string expr) specify an expression used to create a new cache store, e.g. `create = r##"{ CacheType::new() }"##`. +/// - `key`: (optional, string type) specify what type to use for the cache key, e.g. `type = "TimedCached"`. +/// When `key` is specified, `convert` must also be specified. +/// - `convert`: (optional, string expr) specify an expression used to convert function arguments to a cache +/// key, e.g. `convert = r##"{ format!("{}:{}", arg1, arg2) }"##`. When `convert` is specified, +/// `key` or `type` must also be set. +/// - `with_cached_flag`: (optional, bool) If your function returns a `cached::Return` or `Result`, +/// the `cached::Return.was_cached` flag will be updated when a cached value is returned. +/// +/// ## Note +/// The `type`, `create`, `key`, and `convert` attributes must be in a `String` +/// This is because darling, which is used for parsing the attributes, does not support directly parsing +/// attributes into `Type`s or `Block`s. +#[proc_macro_attribute] +pub fn io_cached(args: TokenStream, input: TokenStream) -> TokenStream { + io_cached::io_cached(args, input) +} diff --git a/vendor/cached_proc_macro/src/once.rs b/vendor/cached_proc_macro/src/once.rs new file mode 100644 index 0000000000000..cbcd0d0c8aa5c --- /dev/null +++ b/vendor/cached_proc_macro/src/once.rs @@ -0,0 +1,272 @@ +use crate::helpers::*; +use darling::FromMeta; +use proc_macro::TokenStream; +use quote::quote; +use syn::spanned::Spanned; +use syn::{parse_macro_input, AttributeArgs, Ident, ItemFn, ReturnType}; + +#[derive(FromMeta)] +struct OnceMacroArgs { + #[darling(default)] + name: Option, + #[darling(default)] + time: Option, + #[darling(default)] + sync_writes: bool, + #[darling(default)] + result: bool, + #[darling(default)] + option: bool, + #[darling(default)] + with_cached_flag: bool, +} + +pub fn once(args: TokenStream, input: TokenStream) -> TokenStream { + let attr_args = parse_macro_input!(args as AttributeArgs); + let args = match OnceMacroArgs::from_list(&attr_args) { + Ok(v) => v, + Err(e) => { + return TokenStream::from(e.write_errors()); + } + }; + let input = parse_macro_input!(input as ItemFn); + + // pull out the parts of the input + let mut attributes = input.attrs; + let visibility = input.vis; + let signature = input.sig; + let body = input.block; + + // pull out the parts of the function signature + let fn_ident = signature.ident.clone(); + let inputs = signature.inputs.clone(); + let output = signature.output.clone(); + let asyncness = signature.asyncness; + + // pull out the names and types of the function inputs + let input_names = get_input_names(&inputs); + + // pull out the output type + let output_ty = match &output { + ReturnType::Default => quote! {()}, + ReturnType::Type(_, ty) => quote! {#ty}, + }; + + let output_span = output_ty.span(); + let output_ts = TokenStream::from(output_ty.clone()); + let output_parts = get_output_parts(&output_ts); + let output_string = output_parts.join("::"); + let output_type_display = output_ts.to_string().replace(' ', ""); + + if check_with_cache_flag(args.with_cached_flag, output_string) { + return with_cache_flag_error(output_span, output_type_display); + } + + let cache_value_ty = find_value_type(args.result, args.option, &output, output_ty); + + // make the cache identifier + let cache_ident = match args.name { + Some(name) => Ident::new(&name, fn_ident.span()), + None => Ident::new(&fn_ident.to_string().to_uppercase(), fn_ident.span()), + }; + + // make the cache type and create statement + let (cache_ty, cache_create) = match &args.time { + None => (quote! { Option<#cache_value_ty> }, quote! { None }), + Some(_) => ( + quote! { Option<(::cached::instant::Instant, #cache_value_ty)> }, + quote! { None }, + ), + }; + + // make the set cache and return cache blocks + let (set_cache_block, return_cache_block) = match (&args.result, &args.option) { + (false, false) => { + let set_cache_block = if args.time.is_some() { + quote! { + *cached = Some((now, result.clone())); + } + } else { + quote! { + *cached = Some(result.clone()); + } + }; + + let return_cache_block = if args.with_cached_flag { + quote! { let mut r = result.clone(); r.was_cached = true; return r } + } else { + quote! { return result.clone() } + }; + let return_cache_block = gen_return_cache_block(args.time, return_cache_block); + (set_cache_block, return_cache_block) + } + (true, false) => { + let set_cache_block = if args.time.is_some() { + quote! { + if let Ok(result) = &result { + *cached = Some((now, result.clone())); + } + } + } else { + quote! { + if let Ok(result) = &result { + *cached = Some(result.clone()); + } + } + }; + + let return_cache_block = if args.with_cached_flag { + quote! { let mut r = result.clone(); r.was_cached = true; return Ok(r) } + } else { + quote! { return Ok(result.clone()) } + }; + let return_cache_block = gen_return_cache_block(args.time, return_cache_block); + (set_cache_block, return_cache_block) + } + (false, true) => { + let set_cache_block = if args.time.is_some() { + quote! { + if let Some(result) = &result { + *cached = Some((now, result.clone())); + } + } + } else { + quote! { + if let Some(result) = &result { + *cached = Some(result.clone()); + } + } + }; + + let return_cache_block = if args.with_cached_flag { + quote! { let mut r = result.clone(); r.was_cached = true; return Some(r) } + } else { + quote! { return Some(result.clone()) } + }; + let return_cache_block = gen_return_cache_block(args.time, return_cache_block); + (set_cache_block, return_cache_block) + } + _ => panic!("the result and option attributes are mutually exclusive"), + }; + + let set_cache_and_return = quote! { + #set_cache_block + result + }; + let r_lock; + let w_lock; + let function_call; + let cache_type; + if asyncness.is_some() { + w_lock = quote! { + // try to get a write lock + let mut cached = #cache_ident.write().await; + }; + + r_lock = quote! { + // try to get a read lock + let mut cached = #cache_ident.read().await; + }; + + function_call = quote! { + // run the function and cache the result + async fn inner(#inputs) #output #body; + let result = inner(#(#input_names),*).await; + }; + + cache_type = quote! { + #visibility static #cache_ident: ::cached::once_cell::sync::Lazy<::cached::async_sync::RwLock<#cache_ty>> = ::cached::once_cell::sync::Lazy::new(|| ::cached::async_sync::RwLock::new(#cache_create)); + }; + } else { + w_lock = quote! { + // try to get a lock first + let mut cached = #cache_ident.write().unwrap(); + }; + + r_lock = quote! { + // try to get a read lock + let mut cached = #cache_ident.read().unwrap(); + }; + + function_call = quote! { + // run the function and cache the result + fn inner(#inputs) #output #body; + let result = inner(#(#input_names),*); + }; + + cache_type = quote! { + #visibility static #cache_ident: ::cached::once_cell::sync::Lazy> = ::cached::once_cell::sync::Lazy::new(|| std::sync::RwLock::new(#cache_create)); + }; + } + + let prime_do_set_return_block = quote! { + #w_lock + #function_call + #set_cache_and_return + }; + + let r_lock_return_cache_block = quote! { + { + #r_lock + if let Some(result) = &*cached { + #return_cache_block + } + } + }; + + let do_set_return_block = if args.sync_writes { + quote! { + #r_lock_return_cache_block + #w_lock + if let Some(result) = &*cached { + #return_cache_block + } + #function_call + #set_cache_and_return + } + } else { + quote! { + #r_lock_return_cache_block + #function_call + #w_lock + #set_cache_and_return + } + }; + + let signature_no_muts = get_mut_signature(signature); + + let prime_fn_ident = Ident::new(&format!("{}_prime_cache", &fn_ident), fn_ident.span()); + let mut prime_sig = signature_no_muts.clone(); + prime_sig.ident = prime_fn_ident; + + // make cached static, cached function and prime cached function doc comments + let cache_ident_doc = format!("Cached static for the [`{}`] function.", fn_ident); + let prime_fn_indent_doc = format!("Primes the cached function [`{}`].", fn_ident); + let cache_fn_doc_extra = format!( + "This is a cached function that uses the [`{}`] cached static.", + cache_ident + ); + fill_in_attributes(&mut attributes, cache_fn_doc_extra); + + // put it all together + let expanded = quote! { + // Cached static + #[doc = #cache_ident_doc] + #cache_type + // Cached function + #(#attributes)* + #visibility #signature_no_muts { + let now = ::cached::instant::Instant::now(); + #do_set_return_block + } + // Prime cached function + #[doc = #prime_fn_indent_doc] + #[allow(dead_code)] + #visibility #prime_sig { + let now = ::cached::instant::Instant::now(); + #prime_do_set_return_block + } + }; + + expanded.into() +} diff --git a/vendor/cached_proc_macro_types/.cargo-checksum.json b/vendor/cached_proc_macro_types/.cargo-checksum.json new file mode 100644 index 0000000000000..bc007ca67cfdc --- /dev/null +++ b/vendor/cached_proc_macro_types/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"f53d3843c9f169c3a1596534de7b955b52271ec00bde4318ae6c5df02c502e68","LICENSE":"8e65cf73127700ffe243f50963547dd6c297190945033677e29eecdde69d666f","README.md":"ed2d5d03ab40366ac05d662c055df3219fdad2aeabcdc7c68619f2758b1aa128","src/lib.rs":"1a03d6a67f18b5db3fa882706ef2b1e61af115edde048a3ba30056508cb3a54f"},"package":"ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"} \ No newline at end of file diff --git a/vendor/cached_proc_macro_types/Cargo.toml b/vendor/cached_proc_macro_types/Cargo.toml new file mode 100644 index 0000000000000..abb08ea3fd556 --- /dev/null +++ b/vendor/cached_proc_macro_types/Cargo.toml @@ -0,0 +1,30 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "cached_proc_macro_types" +version = "0.1.1" +authors = ["James Kominick "] +description = "Generic cache implementations and simplified function memoization" +documentation = "https://docs.rs/cached" +readme = "README.md" +keywords = [ + "caching", + "cache", + "memoize", + "lru", +] +categories = ["caching"] +license = "MIT" +repository = "https://github.com/jaemk/cached" + +[dependencies] diff --git a/vendor/cached_proc_macro_types/LICENSE b/vendor/cached_proc_macro_types/LICENSE new file mode 100644 index 0000000000000..3b332da1eb1c3 --- /dev/null +++ b/vendor/cached_proc_macro_types/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 James Kominick + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/cached_proc_macro_types/README.md b/vendor/cached_proc_macro_types/README.md new file mode 100644 index 0000000000000..1fe12c3ed9a28 --- /dev/null +++ b/vendor/cached_proc_macro_types/README.md @@ -0,0 +1 @@ +See https://crates.io/crates/cached diff --git a/vendor/cached_proc_macro_types/src/lib.rs b/vendor/cached_proc_macro_types/src/lib.rs new file mode 100644 index 0000000000000..71f76e276d1f5 --- /dev/null +++ b/vendor/cached_proc_macro_types/src/lib.rs @@ -0,0 +1,29 @@ +/// Used to wrap a function result so callers can see whether the result was cached. +#[derive(Clone)] +pub struct Return { + pub was_cached: bool, + pub value: T, +} + +impl Return { + pub fn new(value: T) -> Self { + Self { + was_cached: false, + value, + } + } +} + +impl std::ops::Deref for Return { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +impl std::ops::DerefMut for Return { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.value + } +} diff --git a/vendor/cc/Cargo.lock b/vendor/cc/Cargo.lock new file mode 100644 index 0000000000000..0c9b73e292ed7 --- /dev/null +++ b/vendor/cc/Cargo.lock @@ -0,0 +1,111 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.83" +dependencies = [ + "jobserver", + "libc", + "tempfile", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "jobserver" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.134" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/cc/src/bin/gcc-shim.rs b/vendor/cc/src/bin/gcc-shim.rs new file mode 100644 index 0000000000000..e5b537258514a --- /dev/null +++ b/vendor/cc/src/bin/gcc-shim.rs @@ -0,0 +1,70 @@ +#![cfg_attr(test, allow(dead_code))] + +use std::env; +use std::fs::File; +use std::io::{self, prelude::*}; +use std::path::PathBuf; + +fn main() { + let mut args = env::args(); + let program = args.next().expect("Unexpected empty args"); + + let out_dir = PathBuf::from( + env::var_os("GCCTEST_OUT_DIR") + .unwrap_or_else(|| panic!("{}: GCCTEST_OUT_DIR not found", program)), + ); + + // Find the first nonexistent candidate file to which the program's args can be written. + let candidate = (0..).find_map(|i| { + let candidate = out_dir.join(format!("out{}", i)); + + if candidate.exists() { + // If the file exists, commands have already run. Try again. + None + } else { + Some(candidate) + } + }).unwrap_or_else(|| panic!("Cannot find the first nonexistent candidate file to which the program's args can be written under out_dir '{}'", out_dir.display())); + + // Create a file and record the args passed to the command. + let f = File::create(&candidate).unwrap_or_else(|e| { + panic!( + "{}: can't create candidate: {}, error: {}", + program, + candidate.display(), + e + ) + }); + let mut f = io::BufWriter::new(f); + + (|| { + for arg in args { + writeln!(f, "{}", arg)?; + } + + f.flush()?; + + let mut f = f.into_inner()?; + f.flush()?; + f.sync_all() + })() + .unwrap_or_else(|e| { + panic!( + "{}: can't write to candidate: {}, error: {}", + program, + candidate.display(), + e + ) + }); + + // Create a file used by some tests. + let path = &out_dir.join("libfoo.a"); + File::create(path).unwrap_or_else(|e| { + panic!( + "{}: can't create libfoo.a: {}, error: {}", + program, + path.display(), + e + ) + }); +} diff --git a/vendor/cc/src/com.rs b/vendor/cc/src/com.rs new file mode 100644 index 0000000000000..cd2284427257b --- /dev/null +++ b/vendor/cc/src/com.rs @@ -0,0 +1,156 @@ +// Copyright © 2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused)] + +use crate::{ + winapi::{IUnknown, Interface}, + windows_sys::{ + CoInitializeEx, SysFreeString, SysStringLen, BSTR, COINIT_MULTITHREADED, HRESULT, S_FALSE, + S_OK, + }, +}; +use std::{ + ffi::{OsStr, OsString}, + mem::ManuallyDrop, + ops::Deref, + os::windows::ffi::{OsStrExt, OsStringExt}, + ptr::{null, null_mut}, + slice::from_raw_parts, +}; + +pub fn initialize() -> Result<(), HRESULT> { + let err = unsafe { CoInitializeEx(null(), COINIT_MULTITHREADED) }; + if err != S_OK && err != S_FALSE { + // S_FALSE just means COM is already initialized + Err(err) + } else { + Ok(()) + } +} + +pub struct ComPtr(*mut T) +where + T: Interface; +impl ComPtr +where + T: Interface, +{ + /// Creates a `ComPtr` to wrap a raw pointer. + /// It takes ownership over the pointer which means it does __not__ call `AddRef`. + /// `T` __must__ be a COM interface that inherits from `IUnknown`. + pub unsafe fn from_raw(ptr: *mut T) -> ComPtr { + assert!(!ptr.is_null()); + ComPtr(ptr) + } + /// Casts up the inheritance chain + pub fn up(self) -> ComPtr + where + T: Deref, + U: Interface, + { + ComPtr(self.into_raw() as *mut U) + } + /// Extracts the raw pointer. + /// You are now responsible for releasing it yourself. + pub fn into_raw(self) -> *mut T { + ManuallyDrop::new(self).0 + } + /// For internal use only. + fn as_unknown(&self) -> &IUnknown { + unsafe { &*(self.0 as *mut IUnknown) } + } + /// Performs QueryInterface fun. + pub fn cast(&self) -> Result, i32> + where + U: Interface, + { + let mut obj = null_mut(); + let err = unsafe { self.as_unknown().QueryInterface(&U::uuidof(), &mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { ComPtr::from_raw(obj as *mut U) }) + } +} +impl Deref for ComPtr +where + T: Interface, +{ + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.0 } + } +} +impl Clone for ComPtr +where + T: Interface, +{ + fn clone(&self) -> Self { + unsafe { + self.as_unknown().AddRef(); + ComPtr::from_raw(self.0) + } + } +} +impl Drop for ComPtr +where + T: Interface, +{ + fn drop(&mut self) { + unsafe { + self.as_unknown().Release(); + } + } +} +pub struct BStr(BSTR); +impl BStr { + pub unsafe fn from_raw(s: BSTR) -> BStr { + BStr(s) + } + pub fn to_osstring(&self) -> OsString { + let len = unsafe { SysStringLen(self.0) }; + let slice = unsafe { from_raw_parts(self.0, len as usize) }; + OsStringExt::from_wide(slice) + } +} +impl Drop for BStr { + fn drop(&mut self) { + unsafe { SysFreeString(self.0) }; + } +} + +pub trait ToWide { + fn to_wide(&self) -> Vec; + fn to_wide_null(&self) -> Vec; +} +impl ToWide for T +where + T: AsRef, +{ + fn to_wide(&self) -> Vec { + self.as_ref().encode_wide().collect() + } + fn to_wide_null(&self) -> Vec { + self.as_ref().encode_wide().chain(Some(0)).collect() + } +} +pub trait FromWide +where + Self: Sized, +{ + fn from_wide(wide: &[u16]) -> Self; + fn from_wide_null(wide: &[u16]) -> Self { + let len = wide.iter().take_while(|&&c| c != 0).count(); + Self::from_wide(&wide[..len]) + } +} +impl FromWide for OsString { + fn from_wide(wide: &[u16]) -> OsString { + OsStringExt::from_wide(wide) + } +} diff --git a/vendor/cc/src/os_pipe.rs b/vendor/cc/src/os_pipe.rs new file mode 100644 index 0000000000000..218c9bc9fbf23 --- /dev/null +++ b/vendor/cc/src/os_pipe.rs @@ -0,0 +1,28 @@ +//! Adapted from: +//! - https://doc.rust-lang.org/src/std/sys/unix/pipe.rs.html +//! - https://doc.rust-lang.org/src/std/sys/unix/fd.rs.html#385 +//! - https://github.com/rust-lang/rust/blob/master/library/std/src/sys/mod.rs#L57 +//! - https://github.com/oconnor663/os_pipe.rs +use std::fs::File; + +/// Open a new pipe and return a pair of [`File`] objects for the reader and writer. +/// +/// This corresponds to the `pipe2` library call on Posix and the +/// `CreatePipe` library call on Windows (though these implementation +/// details might change). These pipes are non-inheritable, so new child +/// processes won't receive a copy of them unless they're explicitly +/// passed as stdin/stdout/stderr. +pub fn pipe() -> std::io::Result<(File, File)> { + sys::pipe() +} + +#[cfg(unix)] +#[path = "os_pipe/unix.rs"] +mod sys; + +#[cfg(windows)] +#[path = "os_pipe/windows.rs"] +mod sys; + +#[cfg(all(not(unix), not(windows)))] +compile_error!("Only unix and windows support os_pipe!"); diff --git a/vendor/cc/src/os_pipe/unix.rs b/vendor/cc/src/os_pipe/unix.rs new file mode 100644 index 0000000000000..ec4e547f06857 --- /dev/null +++ b/vendor/cc/src/os_pipe/unix.rs @@ -0,0 +1,121 @@ +use std::{ + fs::File, + io, + os::{raw::c_int, unix::io::FromRawFd}, +}; + +pub(super) fn pipe() -> io::Result<(File, File)> { + let mut fds = [0; 2]; + + // The only known way right now to create atomically set the CLOEXEC flag is + // to use the `pipe2` syscall. This was added to Linux in 2.6.27, glibc 2.9 + // and musl 0.9.3, and some other targets also have it. + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox" + ))] + { + unsafe { + cvt(libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC))?; + } + } + + #[cfg(not(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox" + )))] + { + unsafe { + cvt(libc::pipe(fds.as_mut_ptr()))?; + } + + cloexec::set_cloexec(fds[0])?; + cloexec::set_cloexec(fds[1])?; + } + + unsafe { Ok((File::from_raw_fd(fds[0]), File::from_raw_fd(fds[1]))) } +} + +fn cvt(t: c_int) -> io::Result { + if t == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} + +#[cfg(not(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox" +)))] +mod cloexec { + use super::{c_int, cvt, io}; + + #[cfg(not(any( + target_env = "newlib", + target_os = "solaris", + target_os = "illumos", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "l4re", + target_os = "linux", + target_os = "haiku", + target_os = "redox", + target_os = "vxworks", + target_os = "nto", + )))] + pub(super) fn set_cloexec(fd: c_int) -> io::Result<()> { + unsafe { + cvt(libc::ioctl(fd, libc::FIOCLEX))?; + } + + Ok(()) + } + + #[cfg(any( + all( + target_env = "newlib", + not(any(target_os = "espidf", target_os = "horizon")) + ), + target_os = "solaris", + target_os = "illumos", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "l4re", + target_os = "linux", + target_os = "haiku", + target_os = "redox", + target_os = "vxworks", + target_os = "nto", + ))] + pub(super) fn set_cloexec(fd: c_int) -> io::Result<()> { + unsafe { + let previous = cvt(libc::fcntl(fd, libc::F_GETFD))?; + let new = previous | libc::FD_CLOEXEC; + if new != previous { + cvt(libc::fcntl(fd, libc::F_SETFD, new))?; + } + } + + Ok(()) + } + + // FD_CLOEXEC is not supported in ESP-IDF and Horizon OS but there's no need to, + // because neither supports spawning processes. + #[cfg(any(target_os = "espidf", target_os = "horizon"))] + pub(super) fn set_cloexec(_fd: c_int) -> io::Result<()> { + Ok(()) + } +} diff --git a/vendor/cc/src/os_pipe/windows.rs b/vendor/cc/src/os_pipe/windows.rs new file mode 100644 index 0000000000000..212632e43b0e0 --- /dev/null +++ b/vendor/cc/src/os_pipe/windows.rs @@ -0,0 +1,24 @@ +use crate::windows_sys::{CreatePipe, INVALID_HANDLE_VALUE}; +use std::{fs::File, io, os::windows::prelude::*, ptr}; + +/// NOTE: These pipes do not support IOCP. +/// +/// If IOCP is needed, then you might want to emulate +/// anonymous pipes with CreateNamedPipe, as Rust's stdlib does. +pub(super) fn pipe() -> io::Result<(File, File)> { + let mut read_pipe = INVALID_HANDLE_VALUE; + let mut write_pipe = INVALID_HANDLE_VALUE; + + let ret = unsafe { CreatePipe(&mut read_pipe, &mut write_pipe, ptr::null_mut(), 0) }; + + if ret == 0 { + Err(io::Error::last_os_error()) + } else { + unsafe { + Ok(( + File::from_raw_handle(read_pipe as RawHandle), + File::from_raw_handle(write_pipe as RawHandle), + )) + } + } +} diff --git a/vendor/cc/src/registry.rs b/vendor/cc/src/registry.rs new file mode 100644 index 0000000000000..7c1c2dd79d472 --- /dev/null +++ b/vendor/cc/src/registry.rs @@ -0,0 +1,190 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::windows_sys::{ + RegCloseKey, RegEnumKeyExW, RegOpenKeyExW, RegQueryValueExW, ERROR_NO_MORE_ITEMS, + ERROR_SUCCESS, HKEY, HKEY_LOCAL_MACHINE, KEY_READ, KEY_WOW64_32KEY, REG_SZ, +}; +use std::{ + ffi::{OsStr, OsString}, + io, + ops::RangeFrom, + os::windows::prelude::*, + ptr::null_mut, +}; + +/// Must never be `HKEY_PERFORMANCE_DATA`. +pub(crate) struct RegistryKey(Repr); + +type DWORD = u32; + +struct OwnedKey(HKEY); + +/// Note: must not encode `HKEY_PERFORMANCE_DATA` or one of its subkeys. +enum Repr { + /// `HKEY_LOCAL_MACHINE`. + LocalMachine, + /// A subkey of `HKEY_LOCAL_MACHINE`. + Owned(OwnedKey), +} + +pub struct Iter<'a> { + idx: RangeFrom, + key: &'a RegistryKey, +} + +unsafe impl Sync for Repr {} +unsafe impl Send for Repr {} + +pub(crate) const LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::LocalMachine); + +impl RegistryKey { + fn raw(&self) -> HKEY { + match self.0 { + Repr::LocalMachine => HKEY_LOCAL_MACHINE, + Repr::Owned(ref val) => val.0, + } + } + + /// Open a sub-key of `self`. + pub fn open(&self, key: &OsStr) -> io::Result { + let key = key.encode_wide().chain(Some(0)).collect::>(); + let mut ret = null_mut(); + let err = unsafe { + RegOpenKeyExW( + self.raw(), + key.as_ptr(), + 0, + KEY_READ | KEY_WOW64_32KEY, + &mut ret, + ) + }; + if err == ERROR_SUCCESS { + Ok(RegistryKey(Repr::Owned(OwnedKey(ret)))) + } else { + Err(io::Error::from_raw_os_error(err as i32)) + } + } + + pub fn iter(&self) -> Iter { + Iter { + idx: 0.., + key: self, + } + } + + pub fn query_str(&self, name: &str) -> io::Result { + let name: &OsStr = name.as_ref(); + let name = name.encode_wide().chain(Some(0)).collect::>(); + let mut len = 0; + let mut kind = 0; + unsafe { + let err = RegQueryValueExW( + self.raw(), + name.as_ptr(), + null_mut(), + &mut kind, + null_mut(), + &mut len, + ); + if err != ERROR_SUCCESS { + return Err(io::Error::from_raw_os_error(err as i32)); + } + if kind != REG_SZ { + return Err(io::Error::new( + io::ErrorKind::Other, + "registry key wasn't a string", + )); + } + + // The length here is the length in bytes, but we're using wide + // characters so we need to be sure to halve it for the length + // passed in. + assert!(len % 2 == 0, "impossible wide string size: {} bytes", len); + let vlen = len as usize / 2; + // Defensively initialized, see comment about + // `HKEY_PERFORMANCE_DATA` below. + let mut v = vec![0u16; vlen]; + let err = RegQueryValueExW( + self.raw(), + name.as_ptr(), + null_mut(), + null_mut(), + v.as_mut_ptr() as *mut _, + &mut len, + ); + // We don't check for `ERROR_MORE_DATA` (which would if the value + // grew between the first and second call to `RegQueryValueExW`), + // both because it's extremely unlikely, and this is a bit more + // defensive more defensive against weird types of registry keys. + if err != ERROR_SUCCESS { + return Err(io::Error::from_raw_os_error(err as i32)); + } + // The length is allowed to change, but should still be even, as + // well as smaller. + assert!(len % 2 == 0, "impossible wide string size: {} bytes", len); + // If the length grew but returned a success code, it *probably* + // indicates we're `HKEY_PERFORMANCE_DATA` or a subkey(?). We + // consider this UB, since those keys write "undefined" or + // "unpredictable" values to len, and need to use a completely + // different loop structure. This should be impossible (and enforce + // it in the API to the best of our ability), but to mitigate the + // damage we do some smoke-checks on the len, and ensure `v` has + // been fully initialized (rather than trusting the result of + // `RegQueryValueExW`). + let actual_len = len as usize / 2; + assert!(actual_len <= v.len()); + v.truncate(actual_len); + // Some registry keys may have a terminating nul character, but + // we're not interested in that, so chop it off if it's there. + if !v.is_empty() && v[v.len() - 1] == 0 { + v.pop(); + } + return Ok(OsString::from_wide(&v)); + } + } +} + +impl Drop for OwnedKey { + fn drop(&mut self) { + unsafe { + RegCloseKey(self.0); + } + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + self.idx.next().and_then(|i| unsafe { + let mut v = Vec::with_capacity(256); + let mut len = v.capacity() as DWORD; + let ret = RegEnumKeyExW( + self.key.raw(), + i, + v.as_mut_ptr(), + &mut len, + null_mut(), + null_mut(), + null_mut(), + null_mut(), + ); + if ret == ERROR_NO_MORE_ITEMS { + None + } else if ret != ERROR_SUCCESS { + Some(Err(io::Error::from_raw_os_error(ret as i32))) + } else { + v.set_len(len as usize); + Some(Ok(OsString::from_wide(&v))) + } + }) + } +} diff --git a/vendor/cc/src/setup_config.rs b/vendor/cc/src/setup_config.rs new file mode 100644 index 0000000000000..fe2c0309638bc --- /dev/null +++ b/vendor/cc/src/setup_config.rs @@ -0,0 +1,283 @@ +// Copyright © 2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] +#![allow(unused)] + +use crate::{ + com::{BStr, ComPtr}, + winapi::{ + IUnknown, IUnknownVtbl, Interface, LCID, LPCOLESTR, LPCWSTR, LPFILETIME, LPSAFEARRAY, + PULONGLONG, ULONG, + }, + windows_sys::{CoCreateInstance, BSTR, CLSCTX_ALL, HRESULT, S_FALSE}, +}; + +use std::{ + ffi::OsString, + ptr::{null, null_mut}, +}; + +// Bindings to the Setup.Configuration stuff +pub type InstanceState = u32; + +pub const eNone: InstanceState = 0; +pub const eLocal: InstanceState = 1; +pub const eRegistered: InstanceState = 2; +pub const eNoRebootRequired: InstanceState = 4; +pub const eComplete: InstanceState = -1i32 as u32; + +RIDL! {#[uuid(0xb41463c3, 0x8866, 0x43b5, 0xbc, 0x33, 0x2b, 0x06, 0x76, 0xf7, 0xf4, 0x2e)] +interface ISetupInstance(ISetupInstanceVtbl): IUnknown(IUnknownVtbl) { + fn GetInstanceId( + pbstrInstanceId: *mut BSTR, + ) -> HRESULT, + fn GetInstallDate( + pInstallDate: LPFILETIME, + ) -> HRESULT, + fn GetInstallationName( + pbstrInstallationName: *mut BSTR, + ) -> HRESULT, + fn GetInstallationPath( + pbstrInstallationPath: *mut BSTR, + ) -> HRESULT, + fn GetInstallationVersion( + pbstrInstallationVersion: *mut BSTR, + ) -> HRESULT, + fn GetDisplayName( + lcid: LCID, + pbstrDisplayName: *mut BSTR, + ) -> HRESULT, + fn GetDescription( + lcid: LCID, + pbstrDescription: *mut BSTR, + ) -> HRESULT, + fn ResolvePath( + pwszRelativePath: LPCOLESTR, + pbstrAbsolutePath: *mut BSTR, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x89143c9a, 0x05af, 0x49b0, 0xb7, 0x17, 0x72, 0xe2, 0x18, 0xa2, 0x18, 0x5c)] +interface ISetupInstance2(ISetupInstance2Vtbl): ISetupInstance(ISetupInstanceVtbl) { + fn GetState( + pState: *mut InstanceState, + ) -> HRESULT, + fn GetPackages( + ppsaPackages: *mut LPSAFEARRAY, + ) -> HRESULT, + fn GetProduct( + ppPackage: *mut *mut ISetupPackageReference, + ) -> HRESULT, + fn GetProductPath( + pbstrProductPath: *mut BSTR, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x6380bcff, 0x41d3, 0x4b2e, 0x8b, 0x2e, 0xbf, 0x8a, 0x68, 0x10, 0xc8, 0x48)] +interface IEnumSetupInstances(IEnumSetupInstancesVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut *mut ISetupInstance, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumSetupInstances, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x42843719, 0xdb4c, 0x46c2, 0x8e, 0x7c, 0x64, 0xf1, 0x81, 0x6e, 0xfd, 0x5b)] +interface ISetupConfiguration(ISetupConfigurationVtbl): IUnknown(IUnknownVtbl) { + fn EnumInstances( + ppEnumInstances: *mut *mut IEnumSetupInstances, + ) -> HRESULT, + fn GetInstanceForCurrentProcess( + ppInstance: *mut *mut ISetupInstance, + ) -> HRESULT, + fn GetInstanceForPath( + wzPath: LPCWSTR, + ppInstance: *mut *mut ISetupInstance, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x26aab78c, 0x4a60, 0x49d6, 0xaf, 0x3b, 0x3c, 0x35, 0xbc, 0x93, 0x36, 0x5d)] +interface ISetupConfiguration2(ISetupConfiguration2Vtbl): + ISetupConfiguration(ISetupConfigurationVtbl) { + fn EnumAllInstances( + ppEnumInstances: *mut *mut IEnumSetupInstances, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0xda8d8a16, 0xb2b6, 0x4487, 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5)] +interface ISetupPackageReference(ISetupPackageReferenceVtbl): IUnknown(IUnknownVtbl) { + fn GetId( + pbstrId: *mut BSTR, + ) -> HRESULT, + fn GetVersion( + pbstrVersion: *mut BSTR, + ) -> HRESULT, + fn GetChip( + pbstrChip: *mut BSTR, + ) -> HRESULT, + fn GetLanguage( + pbstrLanguage: *mut BSTR, + ) -> HRESULT, + fn GetBranch( + pbstrBranch: *mut BSTR, + ) -> HRESULT, + fn GetType( + pbstrType: *mut BSTR, + ) -> HRESULT, + fn GetUniqueId( + pbstrUniqueId: *mut BSTR, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x42b21b78, 0x6192, 0x463e, 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c)] +interface ISetupHelper(ISetupHelperVtbl): IUnknown(IUnknownVtbl) { + fn ParseVersion( + pwszVersion: LPCOLESTR, + pullVersion: PULONGLONG, + ) -> HRESULT, + fn ParseVersionRange( + pwszVersionRange: LPCOLESTR, + pullMinVersion: PULONGLONG, + pullMaxVersion: PULONGLONG, + ) -> HRESULT, +}} + +DEFINE_GUID! {CLSID_SetupConfiguration, +0x177f0c4a, 0x1cd3, 0x4de7, 0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d} + +// Safe wrapper around the COM interfaces +pub struct SetupConfiguration(ComPtr); + +impl SetupConfiguration { + pub fn new() -> Result { + let mut obj = null_mut(); + let err = unsafe { + CoCreateInstance( + &CLSID_SetupConfiguration, + null_mut(), + CLSCTX_ALL, + &ISetupConfiguration::uuidof(), + &mut obj, + ) + }; + if err < 0 { + return Err(err); + } + let obj = unsafe { ComPtr::from_raw(obj as *mut ISetupConfiguration) }; + Ok(SetupConfiguration(obj)) + } + pub fn get_instance_for_current_process(&self) -> Result { + let mut obj = null_mut(); + let err = unsafe { self.0.GetInstanceForCurrentProcess(&mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { SetupInstance::from_raw(obj) }) + } + pub fn enum_instances(&self) -> Result { + let mut obj = null_mut(); + let err = unsafe { self.0.EnumInstances(&mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { EnumSetupInstances::from_raw(obj) }) + } + pub fn enum_all_instances(&self) -> Result { + let mut obj = null_mut(); + let this = self.0.cast::()?; + let err = unsafe { this.EnumAllInstances(&mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { EnumSetupInstances::from_raw(obj) }) + } +} + +pub struct SetupInstance(ComPtr); + +impl SetupInstance { + pub unsafe fn from_raw(obj: *mut ISetupInstance) -> SetupInstance { + SetupInstance(ComPtr::from_raw(obj)) + } + pub fn instance_id(&self) -> Result { + let mut s = null(); + let err = unsafe { self.0.GetInstanceId(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn installation_name(&self) -> Result { + let mut s = null(); + let err = unsafe { self.0.GetInstallationName(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn installation_path(&self) -> Result { + let mut s = null(); + let err = unsafe { self.0.GetInstallationPath(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn installation_version(&self) -> Result { + let mut s = null(); + let err = unsafe { self.0.GetInstallationVersion(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn product_path(&self) -> Result { + let mut s = null(); + let this = self.0.cast::()?; + let err = unsafe { this.GetProductPath(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } +} + +pub struct EnumSetupInstances(ComPtr); + +impl EnumSetupInstances { + pub unsafe fn from_raw(obj: *mut IEnumSetupInstances) -> EnumSetupInstances { + EnumSetupInstances(ComPtr::from_raw(obj)) + } +} + +impl Iterator for EnumSetupInstances { + type Item = Result; + fn next(&mut self) -> Option> { + let mut obj = null_mut(); + let err = unsafe { self.0.Next(1, &mut obj, null_mut()) }; + if err < 0 { + return Some(Err(err)); + } + if err == S_FALSE { + return None; + } + Some(Ok(unsafe { SetupInstance::from_raw(obj) })) + } +} diff --git a/vendor/cc/src/vs_instances.rs b/vendor/cc/src/vs_instances.rs new file mode 100644 index 0000000000000..31d3dd1470fa9 --- /dev/null +++ b/vendor/cc/src/vs_instances.rs @@ -0,0 +1,199 @@ +use std::borrow::Cow; +use std::collections::HashMap; +use std::convert::TryFrom; +use std::io::BufRead; +use std::path::PathBuf; + +use crate::setup_config::{EnumSetupInstances, SetupInstance}; + +pub enum VsInstance { + Com(SetupInstance), + Vswhere(VswhereInstance), +} + +impl VsInstance { + pub fn installation_name(&self) -> Option> { + match self { + VsInstance::Com(s) => s + .installation_name() + .ok() + .and_then(|s| s.into_string().ok()) + .map(Cow::from), + VsInstance::Vswhere(v) => v.map.get("installationName").map(Cow::from), + } + } + + pub fn installation_path(&self) -> Option { + match self { + VsInstance::Com(s) => s.installation_path().ok().map(PathBuf::from), + VsInstance::Vswhere(v) => v.map.get("installationPath").map(PathBuf::from), + } + } + + pub fn installation_version(&self) -> Option> { + match self { + VsInstance::Com(s) => s + .installation_version() + .ok() + .and_then(|s| s.into_string().ok()) + .map(Cow::from), + VsInstance::Vswhere(v) => v.map.get("installationVersion").map(Cow::from), + } + } +} + +pub enum VsInstances { + ComBased(EnumSetupInstances), + VswhereBased(VswhereInstance), +} + +impl IntoIterator for VsInstances { + type Item = VsInstance; + #[allow(bare_trait_objects)] + type IntoIter = Box>; + + fn into_iter(self) -> Self::IntoIter { + match self { + VsInstances::ComBased(e) => { + Box::new(e.into_iter().filter_map(Result::ok).map(VsInstance::Com)) + } + VsInstances::VswhereBased(v) => Box::new(std::iter::once(VsInstance::Vswhere(v))), + } + } +} + +#[derive(Debug)] +pub struct VswhereInstance { + map: HashMap, +} + +impl TryFrom<&Vec> for VswhereInstance { + type Error = &'static str; + + fn try_from(output: &Vec) -> Result { + let map: HashMap<_, _> = output + .lines() + .filter_map(Result::ok) + .filter_map(|s| { + let mut splitn = s.splitn(2, ": "); + Some((splitn.next()?.to_owned(), splitn.next()?.to_owned())) + }) + .collect(); + + if !map.contains_key("installationName") + || !map.contains_key("installationPath") + || !map.contains_key("installationVersion") + { + return Err("required properties not found"); + } + + Ok(Self { map }) + } +} + +#[cfg(test)] +mod tests_ { + use std::borrow::Cow; + use std::convert::TryFrom; + use std::path::PathBuf; + + #[test] + fn it_parses_vswhere_output_correctly() { + let output = br"instanceId: 58104422 +installDate: 21/02/2021 21:50:33 +installationName: VisualStudio/16.9.2+31112.23 +installationPath: C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools +installationVersion: 16.9.31112.23 +productId: Microsoft.VisualStudio.Product.BuildTools +productPath: C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\Common7\Tools\LaunchDevCmd.bat +state: 4294967295 +isComplete: 1 +isLaunchable: 1 +isPrerelease: 0 +isRebootRequired: 0 +displayName: Visual Studio Build Tools 2019 +description: The Visual Studio Build Tools allows you to build native and managed MSBuild-based applications without requiring the Visual Studio IDE. There are options to install the Visual C++ compilers and libraries, MFC, ATL, and C++/CLI support. +channelId: VisualStudio.16.Release +channelUri: https://aka.ms/vs/16/release/channel +enginePath: C:\Program Files (x86)\Microsoft Visual Studio\Installer\resources\app\ServiceHub\Services\Microsoft.VisualStudio.Setup.Service +releaseNotes: https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes-v16.9#16.9.2 +thirdPartyNotices: https://go.microsoft.com/fwlink/?LinkId=660909 +updateDate: 2021-03-17T21:16:46.5963702Z +catalog_buildBranch: d16.9 +catalog_buildVersion: 16.9.31112.23 +catalog_id: VisualStudio/16.9.2+31112.23 +catalog_localBuild: build-lab +catalog_manifestName: VisualStudio +catalog_manifestType: installer +catalog_productDisplayVersion: 16.9.2 +catalog_productLine: Dev16 +catalog_productLineVersion: 2019 +catalog_productMilestone: RTW +catalog_productMilestoneIsPreRelease: False +catalog_productName: Visual Studio +catalog_productPatchVersion: 2 +catalog_productPreReleaseMilestoneSuffix: 1.0 +catalog_productSemanticVersion: 16.9.2+31112.23 +catalog_requiredEngineVersion: 2.9.3365.38425 +properties_campaignId: 156063665.1613940062 +properties_channelManifestId: VisualStudio.16.Release/16.9.2+31112.23 +properties_nickname: +properties_setupEngineFilePath: C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installershell.exe +" + .to_vec(); + + let vswhere_instance = super::VswhereInstance::try_from(&output); + assert!(vswhere_instance.is_ok()); + + let vs_instance = super::VsInstance::Vswhere(vswhere_instance.unwrap()); + assert_eq!( + vs_instance.installation_name(), + Some(Cow::from("VisualStudio/16.9.2+31112.23")) + ); + assert_eq!( + vs_instance.installation_path(), + Some(PathBuf::from( + r"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools" + )) + ); + assert_eq!( + vs_instance.installation_version(), + Some(Cow::from("16.9.31112.23")) + ); + } + + #[test] + fn it_returns_an_error_for_empty_output() { + let output = b"".to_vec(); + + let vswhere_instance = super::VswhereInstance::try_from(&output); + + assert!(vswhere_instance.is_err()); + } + + #[test] + fn it_returns_an_error_for_output_consisting_of_empty_lines() { + let output = br" + +" + .to_vec(); + + let vswhere_instance = super::VswhereInstance::try_from(&output); + + assert!(vswhere_instance.is_err()); + } + + #[test] + fn it_returns_an_error_for_output_without_required_properties() { + let output = br"instanceId: 58104422 +installDate: 21/02/2021 21:50:33 +productId: Microsoft.VisualStudio.Product.BuildTools +productPath: C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\Common7\Tools\LaunchDevCmd.bat +" + .to_vec(); + + let vswhere_instance = super::VswhereInstance::try_from(&output); + + assert!(vswhere_instance.is_err()); + } +} diff --git a/vendor/cc/src/winapi.rs b/vendor/cc/src/winapi.rs new file mode 100644 index 0000000000000..223599f622cb2 --- /dev/null +++ b/vendor/cc/src/winapi.rs @@ -0,0 +1,146 @@ +// Copyright © 2015-2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] + +use std::os::raw; + +pub type wchar_t = u16; + +pub use crate::windows_sys::{FILETIME, GUID, HRESULT, SAFEARRAY, SAFEARRAYBOUND}; + +pub type REFIID = *const IID; +pub type IID = GUID; +pub type ULONG = raw::c_ulong; +pub type DWORD = u32; +pub type LPFILETIME = *mut FILETIME; +pub type OLECHAR = WCHAR; +pub type WCHAR = wchar_t; +pub type LPCOLESTR = *const OLECHAR; +pub type LCID = DWORD; +pub type LPCWSTR = *const WCHAR; +pub type PULONGLONG = *mut ULONGLONG; +pub type ULONGLONG = u64; + +pub trait Interface { + fn uuidof() -> GUID; +} + +pub type LPSAFEARRAY = *mut SAFEARRAY; + +macro_rules! DEFINE_GUID { + ( + $name:ident, $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr + ) => { + pub const $name: $crate::winapi::GUID = $crate::winapi::GUID { + data1: $l, + data2: $w1, + data3: $w2, + data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + }; + }; +} + +macro_rules! RIDL { + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + #[repr(C)] + pub struct $vtbl { + $(pub $method: unsafe extern "system" fn( + This: *mut $interface, + $($p: $t),* + ) -> $rtr,)+ + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}} + RIDL!{@uuid $interface $($uuid),+} + ); + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) { + }) => ( + #[repr(C)] + pub struct $vtbl { + pub parent: $pvtbl, + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@deref $interface $pinterface} + RIDL!{@uuid $interface $($uuid),+} + ); + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + #[repr(C)] + pub struct $vtbl { + pub parent: $pvtbl, + $(pub $method: unsafe extern "system" fn( + This: *mut $interface, + $($p: $t,)* + ) -> $rtr,)+ + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}} + RIDL!{@deref $interface $pinterface} + RIDL!{@uuid $interface $($uuid),+} + ); + (@deref $interface:ident $pinterface:ident) => ( + impl ::std::ops::Deref for $interface { + type Target = $pinterface; + #[inline] + fn deref(&self) -> &$pinterface { + unsafe { &*(self as *const $interface as *const $pinterface) } + } + } + ); + (@impl $interface:ident {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + impl $interface { + $(#[inline] pub unsafe fn $method(&self, $($p: $t,)*) -> $rtr { + ((*self.lpVtbl).$method)(self as *const _ as *mut _, $($p,)*) + })+ + } + ); + (@uuid $interface:ident + $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr + ) => ( + impl $crate::winapi::Interface for $interface { + #[inline] + fn uuidof() -> $crate::winapi::GUID { + $crate::winapi::GUID { + data1: $l, + data2: $w1, + data3: $w2, + data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + } + } + } + ); +} + +RIDL! {#[uuid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IUnknown(IUnknownVtbl) { + fn QueryInterface( + riid: REFIID, + ppvObject: *mut *mut raw::c_void, + ) -> HRESULT, + fn AddRef() -> ULONG, + fn Release() -> ULONG, +}} diff --git a/vendor/cc/src/windows_registry.rs b/vendor/cc/src/windows_registry.rs new file mode 100644 index 0000000000000..07a9c4db6cdb8 --- /dev/null +++ b/vendor/cc/src/windows_registry.rs @@ -0,0 +1,896 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A helper module to probe the Windows Registry when looking for +//! windows-specific tools. + +use std::process::Command; + +use crate::Tool; +#[cfg(windows)] +use crate::ToolFamily; + +#[cfg(windows)] +const MSVC_FAMILY: ToolFamily = ToolFamily::Msvc { clang_cl: false }; + +/// Attempts to find a tool within an MSVC installation using the Windows +/// registry as a point to search from. +/// +/// The `target` argument is the target that the tool should work for (e.g. +/// compile or link for) and the `tool` argument is the tool to find (e.g. +/// `cl.exe` or `link.exe`). +/// +/// This function will return `None` if the tool could not be found, or it will +/// return `Some(cmd)` which represents a command that's ready to execute the +/// tool with the appropriate environment variables set. +/// +/// Note that this function always returns `None` for non-MSVC targets. +pub fn find(target: &str, tool: &str) -> Option { + find_tool(target, tool).map(|c| c.to_command()) +} + +/// Similar to the `find` function above, this function will attempt the same +/// operation (finding a MSVC tool in a local install) but instead returns a +/// `Tool` which may be introspected. +#[cfg(not(windows))] +pub fn find_tool(_target: &str, _tool: &str) -> Option { + None +} + +/// Documented above. +#[cfg(windows)] +pub fn find_tool(target: &str, tool: &str) -> Option { + // This logic is all tailored for MSVC, if we're not that then bail out + // early. + if !target.contains("msvc") { + return None; + } + + // Looks like msbuild isn't located in the same location as other tools like + // cl.exe and lib.exe. To handle this we probe for it manually with + // dedicated registry keys. + if tool.contains("msbuild") { + return impl_::find_msbuild(target); + } + + if tool.contains("devenv") { + return impl_::find_devenv(target); + } + + // Ok, if we're here, now comes the fun part of the probing. Default shells + // or shells like MSYS aren't really configured to execute `cl.exe` and the + // various compiler tools shipped as part of Visual Studio. Here we try to + // first find the relevant tool, then we also have to be sure to fill in + // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that + // the tool is actually usable. + + return impl_::find_msvc_environment(tool, target) + .or_else(|| impl_::find_msvc_15plus(tool, target)) + .or_else(|| impl_::find_msvc_14(tool, target)) + .or_else(|| impl_::find_msvc_12(tool, target)) + .or_else(|| impl_::find_msvc_11(tool, target)); +} + +/// A version of Visual Studio +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[non_exhaustive] +pub enum VsVers { + /// Visual Studio 12 (2013) + Vs12, + /// Visual Studio 14 (2015) + Vs14, + /// Visual Studio 15 (2017) + Vs15, + /// Visual Studio 16 (2019) + Vs16, + /// Visual Studio 17 (2022) + Vs17, +} + +/// Find the most recent installed version of Visual Studio +/// +/// This is used by the cmake crate to figure out the correct +/// generator. +#[cfg(not(windows))] +pub fn find_vs_version() -> Result { + Err("not windows".to_string()) +} + +/// Documented above +#[cfg(windows)] +pub fn find_vs_version() -> Result { + use std::env; + + match env::var("VisualStudioVersion") { + Ok(version) => match &version[..] { + "17.0" => Ok(VsVers::Vs17), + "16.0" => Ok(VsVers::Vs16), + "15.0" => Ok(VsVers::Vs15), + "14.0" => Ok(VsVers::Vs14), + "12.0" => Ok(VsVers::Vs12), + vers => Err(format!( + "\n\n\ + unsupported or unknown VisualStudio version: {}\n\ + if another version is installed consider running \ + the appropriate vcvars script before building this \ + crate\n\ + ", + vers + )), + }, + _ => { + // Check for the presence of a specific registry key + // that indicates visual studio is installed. + if impl_::has_msbuild_version("17.0") { + Ok(VsVers::Vs17) + } else if impl_::has_msbuild_version("16.0") { + Ok(VsVers::Vs16) + } else if impl_::has_msbuild_version("15.0") { + Ok(VsVers::Vs15) + } else if impl_::has_msbuild_version("14.0") { + Ok(VsVers::Vs14) + } else if impl_::has_msbuild_version("12.0") { + Ok(VsVers::Vs12) + } else { + Err(format!( + "\n\n\ + couldn't determine visual studio generator\n\ + if VisualStudio is installed, however, consider \ + running the appropriate vcvars script before building \ + this crate\n\ + " + )) + } + } + } +} + +#[cfg(windows)] +mod impl_ { + use crate::com; + use crate::registry::{RegistryKey, LOCAL_MACHINE}; + use crate::setup_config::SetupConfiguration; + use crate::vs_instances::{VsInstances, VswhereInstance}; + use std::convert::TryFrom; + use std::env; + use std::ffi::OsString; + use std::fs::File; + use std::io::Read; + use std::iter; + use std::mem; + use std::path::{Path, PathBuf}; + use std::process::Command; + use std::str::FromStr; + + use super::MSVC_FAMILY; + use crate::Tool; + + struct MsvcTool { + tool: PathBuf, + libs: Vec, + path: Vec, + include: Vec, + } + + impl MsvcTool { + fn new(tool: PathBuf) -> MsvcTool { + MsvcTool { + tool: tool, + libs: Vec::new(), + path: Vec::new(), + include: Vec::new(), + } + } + + fn into_tool(self) -> Tool { + let MsvcTool { + tool, + libs, + path, + include, + } = self; + let mut tool = Tool::with_family(tool.into(), MSVC_FAMILY); + add_env(&mut tool, "LIB", libs); + add_env(&mut tool, "PATH", path); + add_env(&mut tool, "INCLUDE", include); + tool + } + } + + /// Checks to see if the `VSCMD_ARG_TGT_ARCH` environment variable matches the + /// given target's arch. Returns `None` if the variable does not exist. + #[cfg(windows)] + fn is_vscmd_target(target: &str) -> Option { + let vscmd_arch = env::var("VSCMD_ARG_TGT_ARCH").ok()?; + // Convert the Rust target arch to its VS arch equivalent. + let arch = match target.split("-").next() { + Some("x86_64") => "x64", + Some("aarch64") => "arm64", + Some("i686") | Some("i586") => "x86", + Some("thumbv7a") => "arm", + // An unrecognized arch. + _ => return Some(false), + }; + Some(vscmd_arch == arch) + } + + /// Attempt to find the tool using environment variables set by vcvars. + pub fn find_msvc_environment(tool: &str, target: &str) -> Option { + // Early return if the environment doesn't contain a VC install. + if env::var_os("VCINSTALLDIR").is_none() { + return None; + } + let vs_install_dir = env::var_os("VSINSTALLDIR")?.into(); + + // If the vscmd target differs from the requested target then + // attempt to get the tool using the VS install directory. + if is_vscmd_target(target) == Some(false) { + // We will only get here with versions 15+. + tool_from_vs15plus_instance(tool, target, &vs_install_dir) + } else { + // Fallback to simply using the current environment. + env::var_os("PATH") + .and_then(|path| { + env::split_paths(&path) + .map(|p| p.join(tool)) + .find(|p| p.exists()) + }) + .map(|path| Tool::with_family(path.into(), MSVC_FAMILY)) + } + } + + fn find_msbuild_vs17(target: &str) -> Option { + find_tool_in_vs16plus_path(r"MSBuild\Current\Bin\MSBuild.exe", target, "17") + } + + #[allow(bare_trait_objects)] + fn vs16plus_instances(target: &str, version: &'static str) -> Box> { + let instances = if let Some(instances) = vs15plus_instances(target) { + instances + } else { + return Box::new(iter::empty()); + }; + Box::new(instances.into_iter().filter_map(move |instance| { + let installation_name = instance.installation_name()?; + if installation_name.starts_with(&format!("VisualStudio/{}.", version)) { + Some(instance.installation_path()?) + } else if installation_name.starts_with(&format!("VisualStudioPreview/{}.", version)) { + Some(instance.installation_path()?) + } else { + None + } + })) + } + + fn find_tool_in_vs16plus_path(tool: &str, target: &str, version: &'static str) -> Option { + vs16plus_instances(target, version) + .filter_map(|path| { + let path = path.join(tool); + if !path.is_file() { + return None; + } + let mut tool = Tool::with_family(path, MSVC_FAMILY); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + if target.contains("aarch64") { + tool.env.push(("Platform".into(), "ARM64".into())); + } + Some(tool) + }) + .next() + } + + fn find_msbuild_vs16(target: &str) -> Option { + find_tool_in_vs16plus_path(r"MSBuild\Current\Bin\MSBuild.exe", target, "16") + } + + // In MSVC 15 (2017) MS once again changed the scheme for locating + // the tooling. Now we must go through some COM interfaces, which + // is super fun for Rust. + // + // Note that much of this logic can be found [online] wrt paths, COM, etc. + // + // [online]: https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/ + // + // Returns MSVC 15+ instances (15, 16 right now), the order should be consider undefined. + // + // However, on ARM64 this method doesn't work because VS Installer fails to register COM component on ARM64. + // Hence, as the last resort we try to use vswhere.exe to list available instances. + fn vs15plus_instances(target: &str) -> Option { + vs15plus_instances_using_com().or_else(|| vs15plus_instances_using_vswhere(target)) + } + + fn vs15plus_instances_using_com() -> Option { + com::initialize().ok()?; + + let config = SetupConfiguration::new().ok()?; + let enum_setup_instances = config.enum_all_instances().ok()?; + + Some(VsInstances::ComBased(enum_setup_instances)) + } + + fn vs15plus_instances_using_vswhere(target: &str) -> Option { + let program_files_path: PathBuf = env::var("ProgramFiles(x86)") + .or_else(|_| env::var("ProgramFiles")) + .ok()? + .into(); + + let vswhere_path = + program_files_path.join(r"Microsoft Visual Studio\Installer\vswhere.exe"); + + if !vswhere_path.exists() { + return None; + } + + let arch = target.split('-').next().unwrap(); + let tools_arch = match arch { + "i586" | "i686" | "x86_64" => Some("x86.x64"), + "arm" | "thumbv7a" => Some("ARM"), + "aarch64" => Some("ARM64"), + _ => None, + }; + + let vswhere_output = Command::new(vswhere_path) + .args(&[ + "-latest", + "-products", + "*", + "-requires", + &format!("Microsoft.VisualStudio.Component.VC.Tools.{}", tools_arch?), + "-format", + "text", + "-nologo", + ]) + .stderr(std::process::Stdio::inherit()) + .output() + .ok()?; + + let vs_instances = + VsInstances::VswhereBased(VswhereInstance::try_from(&vswhere_output.stdout).ok()?); + + Some(vs_instances) + } + + // Inspired from official microsoft/vswhere ParseVersionString + // i.e. at most four u16 numbers separated by '.' + fn parse_version(version: &str) -> Option> { + version + .split('.') + .map(|chunk| u16::from_str(chunk).ok()) + .collect() + } + + pub fn find_msvc_15plus(tool: &str, target: &str) -> Option { + let iter = vs15plus_instances(target)?; + iter.into_iter() + .filter_map(|instance| { + let version = parse_version(&instance.installation_version()?)?; + let instance_path = instance.installation_path()?; + let tool = tool_from_vs15plus_instance(tool, target, &instance_path)?; + Some((version, tool)) + }) + .max_by(|(a_version, _), (b_version, _)| a_version.cmp(b_version)) + .map(|(_version, tool)| tool) + } + + // While the paths to Visual Studio 2017's devenv and MSBuild could + // potentially be retrieved from the registry, finding them via + // SetupConfiguration has shown to be [more reliable], and is preferred + // according to Microsoft. To help head off potential regressions though, + // we keep the registry method as a fallback option. + // + // [more reliable]: https://github.com/rust-lang/cc-rs/pull/331 + fn find_tool_in_vs15_path(tool: &str, target: &str) -> Option { + let mut path = match vs15plus_instances(target) { + Some(instances) => instances + .into_iter() + .filter_map(|instance| instance.installation_path()) + .map(|path| path.join(tool)) + .find(|ref path| path.is_file()), + None => None, + }; + + if path.is_none() { + let key = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7"; + path = LOCAL_MACHINE + .open(key.as_ref()) + .ok() + .and_then(|key| key.query_str("15.0").ok()) + .map(|path| PathBuf::from(path).join(tool)) + .and_then(|path| if path.is_file() { Some(path) } else { None }); + } + + path.map(|path| { + let mut tool = Tool::with_family(path, MSVC_FAMILY); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + if target.contains("aarch64") { + tool.env.push(("Platform".into(), "ARM64".into())); + } + tool + }) + } + + fn tool_from_vs15plus_instance( + tool: &str, + target: &str, + instance_path: &PathBuf, + ) -> Option { + let (root_path, bin_path, host_dylib_path, lib_path, include_path) = + vs15plus_vc_paths(target, instance_path)?; + let tool_path = bin_path.join(tool); + if !tool_path.exists() { + return None; + }; + + let mut tool = MsvcTool::new(tool_path); + tool.path.push(bin_path.clone()); + tool.path.push(host_dylib_path); + tool.libs.push(lib_path); + tool.include.push(include_path); + + if let Some((atl_lib_path, atl_include_path)) = atl_paths(target, &root_path) { + tool.libs.push(atl_lib_path); + tool.include.push(atl_include_path); + } + + add_sdks(&mut tool, target)?; + + Some(tool.into_tool()) + } + + fn vs15plus_vc_paths( + target: &str, + instance_path: &PathBuf, + ) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf, PathBuf)> { + let version_path = + instance_path.join(r"VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt"); + let mut version_file = File::open(version_path).ok()?; + let mut version = String::new(); + version_file.read_to_string(&mut version).ok()?; + let version = version.trim(); + let host = match host_arch() { + X86 => "X86", + X86_64 => "X64", + // There is no natively hosted compiler on ARM64. + // Instead, use the x86 toolchain under emulation (there is no x64 emulation). + AARCH64 => "X86", + _ => return None, + }; + let target = lib_subdir(target)?; + // The directory layout here is MSVC/bin/Host$host/$target/ + let path = instance_path.join(r"VC\Tools\MSVC").join(version); + // This is the path to the toolchain for a particular target, running + // on a given host + let bin_path = path + .join("bin") + .join(&format!("Host{}", host)) + .join(&target); + // But! we also need PATH to contain the target directory for the host + // architecture, because it contains dlls like mspdb140.dll compiled for + // the host architecture. + let host_dylib_path = path + .join("bin") + .join(&format!("Host{}", host)) + .join(&host.to_lowercase()); + let lib_path = path.join("lib").join(&target); + let include_path = path.join("include"); + Some((path, bin_path, host_dylib_path, lib_path, include_path)) + } + + fn atl_paths(target: &str, path: &Path) -> Option<(PathBuf, PathBuf)> { + let atl_path = path.join("atlmfc"); + let sub = lib_subdir(target)?; + if atl_path.exists() { + Some((atl_path.join("lib").join(sub), atl_path.join("include"))) + } else { + None + } + } + + // For MSVC 14 we need to find the Universal CRT as well as either + // the Windows 10 SDK or Windows 8.1 SDK. + pub fn find_msvc_14(tool: &str, target: &str) -> Option { + let vcdir = get_vc_dir("14.0")?; + let mut tool = get_tool(tool, &vcdir, target)?; + add_sdks(&mut tool, target)?; + Some(tool.into_tool()) + } + + fn add_sdks(tool: &mut MsvcTool, target: &str) -> Option<()> { + let sub = lib_subdir(target)?; + let (ucrt, ucrt_version) = get_ucrt_dir()?; + + let host = match host_arch() { + X86 => "x86", + X86_64 => "x64", + AARCH64 => "arm64", + _ => return None, + }; + + tool.path + .push(ucrt.join("bin").join(&ucrt_version).join(host)); + + let ucrt_include = ucrt.join("include").join(&ucrt_version); + tool.include.push(ucrt_include.join("ucrt")); + + let ucrt_lib = ucrt.join("lib").join(&ucrt_version); + tool.libs.push(ucrt_lib.join("ucrt").join(sub)); + + if let Some((sdk, version)) = get_sdk10_dir() { + tool.path.push(sdk.join("bin").join(host)); + let sdk_lib = sdk.join("lib").join(&version); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk.join("include").join(&version); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("cppwinrt")); + tool.include.push(sdk_include.join("winrt")); + tool.include.push(sdk_include.join("shared")); + } else if let Some(sdk) = get_sdk81_dir() { + tool.path.push(sdk.join("bin").join(host)); + let sdk_lib = sdk.join("lib").join("winv6.3"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk.join("include"); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + tool.include.push(sdk_include.join("shared")); + } + + Some(()) + } + + // For MSVC 12 we need to find the Windows 8.1 SDK. + pub fn find_msvc_12(tool: &str, target: &str) -> Option { + let vcdir = get_vc_dir("12.0")?; + let mut tool = get_tool(tool, &vcdir, target)?; + let sub = lib_subdir(target)?; + let sdk81 = get_sdk81_dir()?; + tool.path.push(sdk81.join("bin").join(sub)); + let sdk_lib = sdk81.join("lib").join("winv6.3"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk81.join("include"); + tool.include.push(sdk_include.join("shared")); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + Some(tool.into_tool()) + } + + // For MSVC 11 we need to find the Windows 8 SDK. + pub fn find_msvc_11(tool: &str, target: &str) -> Option { + let vcdir = get_vc_dir("11.0")?; + let mut tool = get_tool(tool, &vcdir, target)?; + let sub = lib_subdir(target)?; + let sdk8 = get_sdk8_dir()?; + tool.path.push(sdk8.join("bin").join(sub)); + let sdk_lib = sdk8.join("lib").join("win8"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk8.join("include"); + tool.include.push(sdk_include.join("shared")); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + Some(tool.into_tool()) + } + + fn add_env(tool: &mut Tool, env: &str, paths: Vec) { + let prev = env::var_os(env).unwrap_or(OsString::new()); + let prev = env::split_paths(&prev); + let new = paths.into_iter().chain(prev); + tool.env + .push((env.to_string().into(), env::join_paths(new).unwrap())); + } + + // Given a possible MSVC installation directory, we look for the linker and + // then add the MSVC library path. + fn get_tool(tool: &str, path: &Path, target: &str) -> Option { + bin_subdir(target) + .into_iter() + .map(|(sub, host)| { + ( + path.join("bin").join(sub).join(tool), + path.join("bin").join(host), + ) + }) + .filter(|&(ref path, _)| path.is_file()) + .map(|(path, host)| { + let mut tool = MsvcTool::new(path); + tool.path.push(host); + tool + }) + .filter_map(|mut tool| { + let sub = vc_lib_subdir(target)?; + tool.libs.push(path.join("lib").join(sub)); + tool.include.push(path.join("include")); + let atlmfc_path = path.join("atlmfc"); + if atlmfc_path.exists() { + tool.libs.push(atlmfc_path.join("lib").join(sub)); + tool.include.push(atlmfc_path.join("include")); + } + Some(tool) + }) + .next() + } + + // To find MSVC we look in a specific registry key for the version we are + // trying to find. + fn get_vc_dir(ver: &str) -> Option { + let key = r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let path = key.query_str(ver).ok()?; + Some(path.into()) + } + + // To find the Universal CRT we look in a specific registry key for where + // all the Universal CRTs are located and then sort them asciibetically to + // find the newest version. While this sort of sorting isn't ideal, it is + // what vcvars does so that's good enough for us. + // + // Returns a pair of (root, version) for the ucrt dir if found + fn get_ucrt_dir() -> Option<(PathBuf, String)> { + let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let root = key.query_str("KitsRoot10").ok()?; + let readdir = Path::new(&root).join("lib").read_dir().ok()?; + let max_libdir = readdir + .filter_map(|dir| dir.ok()) + .map(|dir| dir.path()) + .filter(|dir| { + dir.components() + .last() + .and_then(|c| c.as_os_str().to_str()) + .map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir()) + .unwrap_or(false) + }) + .max()?; + let version = max_libdir.components().last().unwrap(); + let version = version.as_os_str().to_str().unwrap().to_string(); + Some((root.into(), version)) + } + + // Vcvars finds the correct version of the Windows 10 SDK by looking + // for the include `um\Windows.h` because sometimes a given version will + // only have UCRT bits without the rest of the SDK. Since we only care about + // libraries and not includes, we instead look for `um\x64\kernel32.lib`. + // Since the 32-bit and 64-bit libraries are always installed together we + // only need to bother checking x64, making this code a tiny bit simpler. + // Like we do for the Universal CRT, we sort the possibilities + // asciibetically to find the newest one as that is what vcvars does. + // Before doing that, we check the "WindowsSdkDir" and "WindowsSDKVersion" + // environment variables set by vcvars to use the environment sdk version + // if one is already configured. + fn get_sdk10_dir() -> Option<(PathBuf, String)> { + if let (Ok(root), Ok(version)) = (env::var("WindowsSdkDir"), env::var("WindowsSDKVersion")) + { + return Some((root.into(), version.trim_end_matches('\\').to_string())); + } + + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let root = key.query_str("InstallationFolder").ok()?; + let readdir = Path::new(&root).join("lib").read_dir().ok()?; + let mut dirs = readdir + .filter_map(|dir| dir.ok()) + .map(|dir| dir.path()) + .collect::>(); + dirs.sort(); + let dir = dirs + .into_iter() + .rev() + .filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file()) + .next()?; + let version = dir.components().last().unwrap(); + let version = version.as_os_str().to_str().unwrap().to_string(); + Some((root.into(), version)) + } + + // Interestingly there are several subdirectories, `win7` `win8` and + // `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same + // applies to us. Note that if we were targeting kernel mode drivers + // instead of user mode applications, we would care. + fn get_sdk81_dir() -> Option { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let root = key.query_str("InstallationFolder").ok()?; + Some(root.into()) + } + + fn get_sdk8_dir() -> Option { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let root = key.query_str("InstallationFolder").ok()?; + Some(root.into()) + } + + const PROCESSOR_ARCHITECTURE_INTEL: u16 = 0; + const PROCESSOR_ARCHITECTURE_AMD64: u16 = 9; + const PROCESSOR_ARCHITECTURE_ARM64: u16 = 12; + const X86: u16 = PROCESSOR_ARCHITECTURE_INTEL; + const X86_64: u16 = PROCESSOR_ARCHITECTURE_AMD64; + const AARCH64: u16 = PROCESSOR_ARCHITECTURE_ARM64; + + // When choosing the tool to use, we have to choose the one which matches + // the target architecture. Otherwise we end up in situations where someone + // on 32-bit Windows is trying to cross compile to 64-bit and it tries to + // invoke the native 64-bit compiler which won't work. + // + // For the return value of this function, the first member of the tuple is + // the folder of the tool we will be invoking, while the second member is + // the folder of the host toolchain for that tool which is essential when + // using a cross linker. We return a Vec since on x64 there are often two + // linkers that can target the architecture we desire. The 64-bit host + // linker is preferred, and hence first, due to 64-bit allowing it more + // address space to work with and potentially being faster. + fn bin_subdir(target: &str) -> Vec<(&'static str, &'static str)> { + let arch = target.split('-').next().unwrap(); + match (arch, host_arch()) { + ("i586", X86) | ("i686", X86) => vec![("", "")], + ("i586", X86_64) | ("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")], + ("x86_64", X86) => vec![("x86_amd64", "")], + ("x86_64", X86_64) => vec![("amd64", "amd64"), ("x86_amd64", "")], + ("arm", X86) | ("thumbv7a", X86) => vec![("x86_arm", "")], + ("arm", X86_64) | ("thumbv7a", X86_64) => vec![("amd64_arm", "amd64"), ("x86_arm", "")], + _ => vec![], + } + } + + fn lib_subdir(target: &str) -> Option<&'static str> { + let arch = target.split('-').next().unwrap(); + match arch { + "i586" | "i686" => Some("x86"), + "x86_64" => Some("x64"), + "arm" | "thumbv7a" => Some("arm"), + "aarch64" => Some("arm64"), + _ => None, + } + } + + // MSVC's x86 libraries are not in a subfolder + fn vc_lib_subdir(target: &str) -> Option<&'static str> { + let arch = target.split('-').next().unwrap(); + match arch { + "i586" | "i686" => Some(""), + "x86_64" => Some("amd64"), + "arm" | "thumbv7a" => Some("arm"), + "aarch64" => Some("arm64"), + _ => None, + } + } + + #[allow(bad_style)] + fn host_arch() -> u16 { + type DWORD = u32; + type WORD = u16; + type LPVOID = *mut u8; + type DWORD_PTR = usize; + + #[repr(C)] + struct SYSTEM_INFO { + wProcessorArchitecture: WORD, + _wReserved: WORD, + _dwPageSize: DWORD, + _lpMinimumApplicationAddress: LPVOID, + _lpMaximumApplicationAddress: LPVOID, + _dwActiveProcessorMask: DWORD_PTR, + _dwNumberOfProcessors: DWORD, + _dwProcessorType: DWORD, + _dwAllocationGranularity: DWORD, + _wProcessorLevel: WORD, + _wProcessorRevision: WORD, + } + + extern "system" { + fn GetNativeSystemInfo(lpSystemInfo: *mut SYSTEM_INFO); + } + + unsafe { + let mut info = mem::zeroed(); + GetNativeSystemInfo(&mut info); + info.wProcessorArchitecture + } + } + + // Given a registry key, look at all the sub keys and find the one which has + // the maximal numeric value. + // + // Returns the name of the maximal key as well as the opened maximal key. + fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> { + let mut max_vers = 0; + let mut max_key = None; + for subkey in key.iter().filter_map(|k| k.ok()) { + let val = subkey + .to_str() + .and_then(|s| s.trim_left_matches("v").replace(".", "").parse().ok()); + let val = match val { + Some(s) => s, + None => continue, + }; + if val > max_vers { + if let Ok(k) = key.open(&subkey) { + max_vers = val; + max_key = Some((subkey, k)); + } + } + } + max_key + } + + pub fn has_msbuild_version(version: &str) -> bool { + match version { + "17.0" => { + find_msbuild_vs17("x86_64-pc-windows-msvc").is_some() + || find_msbuild_vs17("i686-pc-windows-msvc").is_some() + || find_msbuild_vs17("aarch64-pc-windows-msvc").is_some() + } + "16.0" => { + find_msbuild_vs16("x86_64-pc-windows-msvc").is_some() + || find_msbuild_vs16("i686-pc-windows-msvc").is_some() + || find_msbuild_vs16("aarch64-pc-windows-msvc").is_some() + } + "15.0" => { + find_msbuild_vs15("x86_64-pc-windows-msvc").is_some() + || find_msbuild_vs15("i686-pc-windows-msvc").is_some() + || find_msbuild_vs15("aarch64-pc-windows-msvc").is_some() + } + "12.0" | "14.0" => LOCAL_MACHINE + .open(&OsString::from(format!( + "SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\{}", + version + ))) + .is_ok(), + _ => false, + } + } + + pub fn find_devenv(target: &str) -> Option { + find_devenv_vs15(&target) + } + + fn find_devenv_vs15(target: &str) -> Option { + find_tool_in_vs15_path(r"Common7\IDE\devenv.exe", target) + } + + // see http://stackoverflow.com/questions/328017/path-to-msbuild + pub fn find_msbuild(target: &str) -> Option { + // VS 15 (2017) changed how to locate msbuild + if let Some(r) = find_msbuild_vs17(target) { + return Some(r); + } else if let Some(r) = find_msbuild_vs16(target) { + return Some(r); + } else if let Some(r) = find_msbuild_vs15(target) { + return Some(r); + } else { + find_old_msbuild(target) + } + } + + fn find_msbuild_vs15(target: &str) -> Option { + find_tool_in_vs15_path(r"MSBuild\15.0\Bin\MSBuild.exe", target) + } + + fn find_old_msbuild(target: &str) -> Option { + let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions"; + LOCAL_MACHINE + .open(key.as_ref()) + .ok() + .and_then(|key| { + max_version(&key).and_then(|(_vers, key)| key.query_str("MSBuildToolsPath").ok()) + }) + .map(|path| { + let mut path = PathBuf::from(path); + path.push("MSBuild.exe"); + let mut tool = Tool::with_family(path, MSVC_FAMILY); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + tool + }) + } +} diff --git a/vendor/cc/src/windows_sys.rs b/vendor/cc/src/windows_sys.rs new file mode 100644 index 0000000000000..ee4704d254dc5 --- /dev/null +++ b/vendor/cc/src/windows_sys.rs @@ -0,0 +1,198 @@ +// This file is autogenerated. +// +// To add bindings, edit windows_sys.lst then run: +// +// ``` +// cd generate-windows-sys/ +// cargo run +// ``` +// Bindings generated by `windows-bindgen` 0.49.0 + +#![allow( + non_snake_case, + non_upper_case_globals, + non_camel_case_types, + dead_code, + clippy::all +)] +#[link(name = "advapi32")] +extern "system" { + pub fn RegCloseKey(hkey: HKEY) -> WIN32_ERROR; +} +#[link(name = "advapi32")] +extern "system" { + pub fn RegEnumKeyExW( + hkey: HKEY, + dwindex: u32, + lpname: PWSTR, + lpcchname: *mut u32, + lpreserved: *const u32, + lpclass: PWSTR, + lpcchclass: *mut u32, + lpftlastwritetime: *mut FILETIME, + ) -> WIN32_ERROR; +} +#[link(name = "advapi32")] +extern "system" { + pub fn RegOpenKeyExW( + hkey: HKEY, + lpsubkey: PCWSTR, + uloptions: u32, + samdesired: REG_SAM_FLAGS, + phkresult: *mut HKEY, + ) -> WIN32_ERROR; +} +#[link(name = "advapi32")] +extern "system" { + pub fn RegQueryValueExW( + hkey: HKEY, + lpvaluename: PCWSTR, + lpreserved: *const u32, + lptype: *mut REG_VALUE_TYPE, + lpdata: *mut u8, + lpcbdata: *mut u32, + ) -> WIN32_ERROR; +} +#[link(name = "kernel32")] +extern "system" { + pub fn CreatePipe( + hreadpipe: *mut HANDLE, + hwritepipe: *mut HANDLE, + lppipeattributes: *const SECURITY_ATTRIBUTES, + nsize: u32, + ) -> BOOL; +} +#[link(name = "ole32")] +extern "system" { + pub fn CoCreateInstance( + rclsid: *const GUID, + punkouter: IUnknown, + dwclscontext: CLSCTX, + riid: *const GUID, + ppv: *mut *mut ::core::ffi::c_void, + ) -> HRESULT; +} +#[link(name = "ole32")] +extern "system" { + pub fn CoInitializeEx(pvreserved: *const ::core::ffi::c_void, dwcoinit: COINIT) -> HRESULT; +} +#[link(name = "oleaut32")] +extern "system" { + pub fn SysFreeString(bstrstring: BSTR) -> (); +} +#[link(name = "oleaut32")] +extern "system" { + pub fn SysStringLen(pbstr: BSTR) -> u32; +} +pub type ADVANCED_FEATURE_FLAGS = u16; +pub type BOOL = i32; +pub type BSTR = *const u16; +pub type CLSCTX = u32; +pub const CLSCTX_ALL: CLSCTX = 23u32; +pub type COINIT = i32; +pub const COINIT_MULTITHREADED: COINIT = 0i32; +pub const ERROR_NO_MORE_ITEMS: WIN32_ERROR = 259u32; +pub const ERROR_SUCCESS: WIN32_ERROR = 0u32; +#[repr(C)] +pub struct FILETIME { + pub dwLowDateTime: u32, + pub dwHighDateTime: u32, +} +impl ::core::marker::Copy for FILETIME {} +impl ::core::clone::Clone for FILETIME { + fn clone(&self) -> Self { + *self + } +} +#[repr(C)] +pub struct GUID { + pub data1: u32, + pub data2: u16, + pub data3: u16, + pub data4: [u8; 8], +} +impl GUID { + pub const fn from_u128(uuid: u128) -> Self { + Self { + data1: (uuid >> 96) as u32, + data2: (uuid >> 80 & 0xffff) as u16, + data3: (uuid >> 64 & 0xffff) as u16, + data4: (uuid as u64).to_be_bytes(), + } + } +} +impl ::core::marker::Copy for GUID {} +impl ::core::clone::Clone for GUID { + fn clone(&self) -> Self { + *self + } +} +pub type HANDLE = *mut ::core::ffi::c_void; +pub type HKEY = *mut ::core::ffi::c_void; +pub const HKEY_LOCAL_MACHINE: HKEY = invalid_mut(-2147483646i32 as _); +pub type HRESULT = i32; +pub const INVALID_HANDLE_VALUE: HANDLE = invalid_mut(-1i32 as _); +pub type IUnknown = *mut ::core::ffi::c_void; +pub const KEY_READ: REG_SAM_FLAGS = 131097u32; +pub const KEY_WOW64_32KEY: REG_SAM_FLAGS = 512u32; +pub type PCWSTR = *const u16; +pub type PWSTR = *mut u16; +pub type REG_SAM_FLAGS = u32; +pub const REG_SZ: REG_VALUE_TYPE = 1u32; +pub type REG_VALUE_TYPE = u32; +#[repr(C)] +pub struct SAFEARRAY { + pub cDims: u16, + pub fFeatures: ADVANCED_FEATURE_FLAGS, + pub cbElements: u32, + pub cLocks: u32, + pub pvData: *mut ::core::ffi::c_void, + pub rgsabound: [SAFEARRAYBOUND; 1], +} +impl ::core::marker::Copy for SAFEARRAY {} +impl ::core::clone::Clone for SAFEARRAY { + fn clone(&self) -> Self { + *self + } +} +#[repr(C)] +pub struct SAFEARRAYBOUND { + pub cElements: u32, + pub lLbound: i32, +} +impl ::core::marker::Copy for SAFEARRAYBOUND {} +impl ::core::clone::Clone for SAFEARRAYBOUND { + fn clone(&self) -> Self { + *self + } +} +#[repr(C)] +pub struct SECURITY_ATTRIBUTES { + pub nLength: u32, + pub lpSecurityDescriptor: *mut ::core::ffi::c_void, + pub bInheritHandle: BOOL, +} +impl ::core::marker::Copy for SECURITY_ATTRIBUTES {} +impl ::core::clone::Clone for SECURITY_ATTRIBUTES { + fn clone(&self) -> Self { + *self + } +} +pub const S_FALSE: HRESULT = 1i32; +pub const S_OK: HRESULT = 0i32; +pub type WIN32_ERROR = u32; + +/// Adapted from +/// [`core::ptr::invalid_mut()`](https://doc.rust-lang.org/src/core/ptr/mod.rs.html#600-607). +/// +/// This function should actually use `core::mem::transmute` but due to msrv +/// we use `as` casting instead. +/// +/// Once msrv is bumped to 1.56, replace this with `core::mem::transmute` since +/// it is const stablised in 1.56 +/// +/// NOTE that once supports `strict_provenance` we would also have to update +/// this. +const fn invalid_mut(addr: usize) -> *mut T { + addr as *mut T +} diff --git a/vendor/cc/tests/cc_env.rs b/vendor/cc/tests/cc_env.rs new file mode 100644 index 0000000000000..43eb689f0fbfa --- /dev/null +++ b/vendor/cc/tests/cc_env.rs @@ -0,0 +1,118 @@ +use std::env; +use std::ffi::OsString; +use std::path::Path; + +mod support; +use crate::support::Test; + +#[test] +fn main() { + ccache(); + distcc(); + ccache_spaces(); + ccache_env_flags(); + leading_spaces(); + extra_flags(); + path_to_ccache(); + more_spaces(); +} + +fn ccache() { + let test = Test::gnu(); + + env::set_var("CC", "ccache cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn ccache_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn distcc() { + let test = Test::gnu(); + test.shim("distcc"); + + env::set_var("CC", "distcc cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn ccache_env_flags() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache lol-this-is-not-a-compiler"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("lol-this-is-not-a-compiler")); + assert_eq!( + compiler.cc_env(), + OsString::from("ccache lol-this-is-not-a-compiler") + ); + assert!( + compiler + .cflags_env() + .into_string() + .unwrap() + .contains("ccache") + == false + ); + assert!( + compiler + .cflags_env() + .into_string() + .unwrap() + .contains(" lol-this-is-not-a-compiler") + == false + ); + + env::set_var("CC", ""); +} + +fn leading_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", " test "); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("test")); + + env::set_var("CC", ""); +} + +fn extra_flags() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache cc -m32"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn path_to_ccache() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "/path/to/ccache.exe cc -m32"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); + assert_eq!( + compiler.cc_env(), + OsString::from("/path/to/ccache.exe cc -m32"), + ); +} + +fn more_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "cc -m32"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} diff --git a/vendor/cc/tests/cflags.rs b/vendor/cc/tests/cflags.rs new file mode 100644 index 0000000000000..caec6ea4ed4cd --- /dev/null +++ b/vendor/cc/tests/cflags.rs @@ -0,0 +1,15 @@ +mod support; + +use crate::support::Test; +use std::env; + +/// This test is in its own module because it modifies the environment and would affect other tests +/// when run in parallel with them. +#[test] +fn gnu_no_warnings_if_cflags() { + env::set_var("CFLAGS", "-arbitrary"); + let test = Test::gnu(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra"); +} diff --git a/vendor/cc/tests/cxxflags.rs b/vendor/cc/tests/cxxflags.rs new file mode 100644 index 0000000000000..c524c7da4e9f0 --- /dev/null +++ b/vendor/cc/tests/cxxflags.rs @@ -0,0 +1,15 @@ +mod support; + +use crate::support::Test; +use std::env; + +/// This test is in its own module because it modifies the environment and would affect other tests +/// when run in parallel with them. +#[test] +fn gnu_no_warnings_if_cxxflags() { + env::set_var("CXXFLAGS", "-arbitrary"); + let test = Test::gnu(); + test.gcc().file("foo.cpp").cpp(true).compile("foo"); + + test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra"); +} diff --git a/vendor/cc/tests/support/mod.rs b/vendor/cc/tests/support/mod.rs new file mode 100644 index 0000000000000..f3c04405a3f76 --- /dev/null +++ b/vendor/cc/tests/support/mod.rs @@ -0,0 +1,172 @@ +#![allow(dead_code)] + +use std::env; +use std::ffi::{OsStr, OsString}; +use std::fs::{self, File}; +use std::io; +use std::io::prelude::*; +use std::path::{Path, PathBuf}; + +use cc; +use tempfile::{Builder, TempDir}; + +pub struct Test { + pub td: TempDir, + pub gcc: PathBuf, + pub msvc: bool, +} + +pub struct Execution { + args: Vec, +} + +impl Test { + pub fn new() -> Test { + // This is ugly: `sccache` needs to introspect the compiler it is + // executing, as it adjusts its behavior depending on the + // language/compiler. This crate's test driver uses mock compilers that + // are obviously not supported by sccache, so the tests fail if + // RUSTC_WRAPPER is set. rust doesn't build test dependencies with + // the `test` feature enabled, so we can't conditionally disable the + // usage of `sccache` if running in a test environment, at least not + // without setting an environment variable here and testing for it + // there. Explicitly deasserting RUSTC_WRAPPER here seems to be the + // lesser of the two evils. + env::remove_var("RUSTC_WRAPPER"); + + let mut gcc = PathBuf::from(env::current_exe().unwrap()); + gcc.pop(); + if gcc.ends_with("deps") { + gcc.pop(); + } + let td = Builder::new().prefix("gcc-test").tempdir_in(&gcc).unwrap(); + gcc.push(format!("gcc-shim{}", env::consts::EXE_SUFFIX)); + Test { + td: td, + gcc: gcc, + msvc: false, + } + } + + pub fn gnu() -> Test { + let t = Test::new(); + t.shim("cc").shim("c++").shim("ar"); + t + } + + pub fn msvc() -> Test { + let mut t = Test::new(); + t.shim("cl").shim("lib.exe"); + t.msvc = true; + t + } + + pub fn shim(&self, name: &str) -> &Test { + let name = if name.ends_with(env::consts::EXE_SUFFIX) { + name.to_string() + } else { + format!("{}{}", name, env::consts::EXE_SUFFIX) + }; + link_or_copy(&self.gcc, self.td.path().join(name)).unwrap(); + self + } + + pub fn gcc(&self) -> cc::Build { + let mut cfg = cc::Build::new(); + let target = if self.msvc { + "x86_64-pc-windows-msvc" + } else { + "x86_64-unknown-linux-gnu" + }; + + cfg.target(target) + .host(target) + .opt_level(2) + .debug(false) + .out_dir(self.td.path()) + .__set_env("PATH", self.path()) + .__set_env("GCCTEST_OUT_DIR", self.td.path()); + if self.msvc { + cfg.compiler(self.td.path().join("cl")); + cfg.archiver(self.td.path().join("lib.exe")); + } + cfg + } + + fn path(&self) -> OsString { + let mut path = env::split_paths(&env::var_os("PATH").unwrap()).collect::>(); + path.insert(0, self.td.path().to_owned()); + env::join_paths(path).unwrap() + } + + pub fn cmd(&self, i: u32) -> Execution { + let mut s = String::new(); + File::open(self.td.path().join(format!("out{}", i))) + .unwrap() + .read_to_string(&mut s) + .unwrap(); + Execution { + args: s.lines().map(|s| s.to_string()).collect(), + } + } +} + +impl Execution { + pub fn must_have>(&self, p: P) -> &Execution { + if !self.has(p.as_ref()) { + panic!("didn't find {:?} in {:?}", p.as_ref(), self.args); + } else { + self + } + } + + pub fn must_not_have>(&self, p: P) -> &Execution { + if self.has(p.as_ref()) { + panic!("found {:?}", p.as_ref()); + } else { + self + } + } + + pub fn has(&self, p: &OsStr) -> bool { + self.args.iter().any(|arg| OsStr::new(arg) == p) + } + + pub fn must_have_in_order(&self, before: &str, after: &str) -> &Execution { + let before_position = self + .args + .iter() + .rposition(|x| OsStr::new(x) == OsStr::new(before)); + let after_position = self + .args + .iter() + .rposition(|x| OsStr::new(x) == OsStr::new(after)); + match (before_position, after_position) { + (Some(b), Some(a)) if b < a => {} + (b, a) => panic!( + "{:?} (last position: {:?}) did not appear before {:?} (last position: {:?})", + before, b, after, a + ), + }; + self + } +} + +/// Hard link an executable or copy it if that fails. +/// +/// We first try to hard link an executable to save space. If that fails (as on Windows with +/// different mount points, issue #60), we copy. +#[cfg(not(target_os = "macos"))] +fn link_or_copy, Q: AsRef>(from: P, to: Q) -> io::Result<()> { + let from = from.as_ref(); + let to = to.as_ref(); + fs::hard_link(from, to).or_else(|_| fs::copy(from, to).map(|_| ())) +} + +/// Copy an executable. +/// +/// On macOS, hard linking the executable leads to strange failures (issue #419), so we just copy. +#[cfg(target_os = "macos")] +fn link_or_copy, Q: AsRef>(from: P, to: Q) -> io::Result<()> { + fs::copy(from, to).map(|_| ()) +} diff --git a/vendor/cc/tests/test.rs b/vendor/cc/tests/test.rs new file mode 100644 index 0000000000000..7f1ddb2181213 --- /dev/null +++ b/vendor/cc/tests/test.rs @@ -0,0 +1,477 @@ +use crate::support::Test; + +mod support; + +// Some tests check that a flag is *not* present. These tests might fail if the flag is set in the +// CFLAGS or CXXFLAGS environment variables. This function clears the CFLAGS and CXXFLAGS +// variables to make sure that the tests can run correctly. +fn reset_env() { + std::env::set_var("CFLAGS", ""); + std::env::set_var("CXXFLAGS", ""); +} + +#[test] +fn gnu_smoke() { + reset_env(); + + let test = Test::gnu(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0) + .must_have("-O2") + .must_have("foo.c") + .must_not_have("-gdwarf-4") + .must_have("-c") + .must_have("-ffunction-sections") + .must_have("-fdata-sections"); + test.cmd(1).must_have(test.td.path().join("foo.o")); +} + +#[test] +fn gnu_opt_level_1() { + reset_env(); + + let test = Test::gnu(); + test.gcc().opt_level(1).file("foo.c").compile("foo"); + + test.cmd(0).must_have("-O1").must_not_have("-O2"); +} + +#[test] +fn gnu_opt_level_s() { + reset_env(); + + let test = Test::gnu(); + test.gcc().opt_level_str("s").file("foo.c").compile("foo"); + + test.cmd(0) + .must_have("-Os") + .must_not_have("-O1") + .must_not_have("-O2") + .must_not_have("-O3") + .must_not_have("-Oz"); +} + +#[test] +fn gnu_debug() { + let test = Test::gnu(); + test.gcc().debug(true).file("foo.c").compile("foo"); + test.cmd(0).must_have("-gdwarf-4"); + + let test = Test::gnu(); + test.gcc() + .target("x86_64-apple-darwin") + .debug(true) + .file("foo.c") + .compile("foo"); + test.cmd(0).must_have("-gdwarf-2"); +} + +#[test] +fn gnu_debug_fp_auto() { + let test = Test::gnu(); + test.gcc().debug(true).file("foo.c").compile("foo"); + test.cmd(0).must_have("-gdwarf-4"); + test.cmd(0).must_have("-fno-omit-frame-pointer"); +} + +#[test] +fn gnu_debug_fp() { + let test = Test::gnu(); + test.gcc().debug(true).file("foo.c").compile("foo"); + test.cmd(0).must_have("-gdwarf-4"); + test.cmd(0).must_have("-fno-omit-frame-pointer"); +} + +#[test] +fn gnu_debug_nofp() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .debug(true) + .force_frame_pointer(false) + .file("foo.c") + .compile("foo"); + test.cmd(0).must_have("-gdwarf-4"); + test.cmd(0).must_not_have("-fno-omit-frame-pointer"); + + let test = Test::gnu(); + test.gcc() + .force_frame_pointer(false) + .debug(true) + .file("foo.c") + .compile("foo"); + test.cmd(0).must_have("-gdwarf-4"); + test.cmd(0).must_not_have("-fno-omit-frame-pointer"); +} + +#[test] +fn gnu_warnings_into_errors() { + let test = Test::gnu(); + test.gcc() + .warnings_into_errors(true) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Werror"); +} + +#[test] +fn gnu_warnings() { + let test = Test::gnu(); + test.gcc() + .warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Wall").must_have("-Wextra"); +} + +#[test] +fn gnu_extra_warnings0() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .warnings(true) + .extra_warnings(false) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Wall").must_not_have("-Wextra"); +} + +#[test] +fn gnu_extra_warnings1() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .warnings(false) + .extra_warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-Wall").must_have("-Wextra"); +} + +#[test] +fn gnu_warnings_overridable() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0) + .must_have_in_order("-Wall", "-Wno-missing-field-initializers"); +} + +#[test] +fn gnu_x86_64() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("x86_64-{}", vendor); + let test = Test::gnu(); + test.gcc() + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-fPIC").must_have("-m64"); + } +} + +#[test] +fn gnu_x86_64_no_pic() { + reset_env(); + + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("x86_64-{}", vendor); + let test = Test::gnu(); + test.gcc() + .pic(false) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-fPIC"); + } +} + +#[test] +fn gnu_i686() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("i686-{}", vendor); + let test = Test::gnu(); + test.gcc() + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-m32"); + } +} + +#[test] +fn gnu_i686_pic() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("i686-{}", vendor); + let test = Test::gnu(); + test.gcc() + .pic(true) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-fPIC"); + } +} + +#[test] +fn gnu_x86_64_no_plt() { + let target = "x86_64-unknown-linux-gnu"; + let test = Test::gnu(); + test.gcc() + .pic(true) + .use_plt(false) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + test.cmd(0).must_have("-fno-plt"); +} + +#[test] +fn gnu_set_stdlib() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .cpp_set_stdlib(Some("foo")) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-stdlib=foo"); +} + +#[test] +fn gnu_include() { + let test = Test::gnu(); + test.gcc().include("foo/bar").file("foo.c").compile("foo"); + + test.cmd(0).must_have("-I").must_have("foo/bar"); +} + +#[test] +fn gnu_define() { + let test = Test::gnu(); + test.gcc() + .define("FOO", "bar") + .define("BAR", None) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR"); +} + +#[test] +fn gnu_compile_assembly() { + let test = Test::gnu(); + test.gcc().file("foo.S").compile("foo"); + test.cmd(0).must_have("foo.S"); +} + +#[test] +fn gnu_shared() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .shared_flag(true) + .static_flag(false) + .compile("foo"); + + test.cmd(0).must_have("-shared").must_not_have("-static"); +} + +#[test] +fn gnu_flag_if_supported() { + reset_env(); + + if cfg!(windows) { + return; + } + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .flag("-v") + .flag_if_supported("-Wall") + .flag_if_supported("-Wflag-does-not-exist") + .flag_if_supported("-std=c++11") + .compile("foo"); + + test.cmd(0) + .must_have("-v") + .must_have("-Wall") + .must_not_have("-Wflag-does-not-exist") + .must_not_have("-std=c++11"); +} + +#[test] +fn gnu_flag_if_supported_cpp() { + if cfg!(windows) { + return; + } + let test = Test::gnu(); + test.gcc() + .cpp(true) + .file("foo.cpp") + .flag_if_supported("-std=c++11") + .compile("foo"); + + test.cmd(0).must_have("-std=c++11"); +} + +#[test] +fn gnu_static() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .shared_flag(false) + .static_flag(true) + .compile("foo"); + + test.cmd(0).must_have("-static").must_not_have("-shared"); +} + +#[test] +fn gnu_no_dash_dash() { + let test = Test::gnu(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0).must_not_have("--"); +} + +#[test] +fn gnu_std_c() { + let test = Test::gnu(); + test.gcc().file("foo.c").std("c11").compile("foo"); + + test.cmd(0).must_have("-std=c11"); +} + +#[test] +fn msvc_smoke() { + reset_env(); + + let test = Test::msvc(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0) + .must_have("-O2") + .must_have("foo.c") + .must_not_have("-Z7") + .must_have("-c") + .must_have("-MD"); + test.cmd(1).must_have(test.td.path().join("foo.o")); +} + +#[test] +fn msvc_opt_level_0() { + reset_env(); + + let test = Test::msvc(); + test.gcc().opt_level(0).file("foo.c").compile("foo"); + + test.cmd(0).must_not_have("-O2"); +} + +#[test] +fn msvc_debug() { + let test = Test::msvc(); + test.gcc().debug(true).file("foo.c").compile("foo"); + test.cmd(0).must_have("-Z7"); +} + +#[test] +fn msvc_include() { + let test = Test::msvc(); + test.gcc().include("foo/bar").file("foo.c").compile("foo"); + + test.cmd(0).must_have("-I").must_have("foo/bar"); +} + +#[test] +fn msvc_define() { + let test = Test::msvc(); + test.gcc() + .define("FOO", "bar") + .define("BAR", None) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR"); +} + +#[test] +fn msvc_static_crt() { + let test = Test::msvc(); + test.gcc().static_crt(true).file("foo.c").compile("foo"); + + test.cmd(0).must_have("-MT"); +} + +#[test] +fn msvc_no_static_crt() { + let test = Test::msvc(); + test.gcc().static_crt(false).file("foo.c").compile("foo"); + + test.cmd(0).must_have("-MD"); +} + +#[test] +fn msvc_no_dash_dash() { + let test = Test::msvc(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0).must_not_have("--"); +} + +#[test] +fn msvc_std_c() { + let test = Test::msvc(); + test.gcc().file("foo.c").std("c11").compile("foo"); + + test.cmd(0).must_have("-std:c11"); +} + +// Disable this test with the parallel feature because the execution +// order is not deterministic. +#[cfg(not(feature = "parallel"))] +#[test] +fn asm_flags() { + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .file("x86_64.asm") + .file("x86_64.S") + .asm_flag("--abc") + .compile("foo"); + test.cmd(0).must_not_have("--abc"); + test.cmd(1).must_have("--abc"); + test.cmd(2).must_have("--abc"); +} diff --git a/vendor/chrono-tz/README.md b/vendor/chrono-tz/README.md new file mode 100644 index 0000000000000..02e2d42158f43 --- /dev/null +++ b/vendor/chrono-tz/README.md @@ -0,0 +1,183 @@ +# Chrono-TZ + +`Chrono-TZ` is a library that provides implementors of the +[`TimeZone`][timezone] trait for [`rust-chrono`][chrono]. The +impls are generated by a build script using the [`IANA database`][iana] +and [`parse-zoneinfo`][parse_zoneinfo]. + +[chrono]: https://github.com/lifthrasiir/rust-chrono +[timezone]: https://lifthrasiir.github.io/rust-chrono/chrono/offset/trait.TimeZone.html +[iana]: http://www.iana.org/time-zones +[parse_zoneinfo]: https://github.com/djzin/parse-zoneinfo + +## Documentation + +Documentation is hosted on [docs.rs][docsrs] + +[docsrs]: https://docs.rs/chrono-tz + +## Examples + +Create a time in one timezone and convert it to UTC + +```rust +use chrono::{TimeZone, Utc}; +use chrono_tz::US::Pacific; + +let pacific_time = Pacific.ymd(1990, 5, 6).and_hms(12, 30, 45); +let utc_time = pacific_time.with_timezone(&Utc); +assert_eq!(utc_time, Utc.ymd(1990, 5, 6).and_hms(19, 30, 45)); +``` + +Create a naive datetime and convert it to a timezone-aware datetime + +```rust +use chrono::{TimeZone, NaiveDate}; +use chrono_tz::Africa::Johannesburg; + +let naive_dt = NaiveDate::from_ymd(2038, 1, 19).and_hms(3, 14, 08); +let tz_aware = Johannesburg.from_local_datetime(&naive_dt).unwrap(); +assert_eq!(tz_aware.to_string(), "2038-01-19 03:14:08 SAST"); +``` + +London and New York change their clocks on different days in March +so only have a 4-hour difference on certain days. + +```rust +use chrono::TimeZone; +use chrono_tz::Europe::London; +use chrono_tz::America::New_York; + +let london_time = London.ymd(2016, 3, 18).and_hms(3, 0, 0); +let ny_time = london_time.with_timezone(&New_York); +assert_eq!(ny_time, New_York.ymd(2016, 3, 17).and_hms(23, 0, 0)); +``` + +You can get the raw offsets as well if you want to see the standard +UTC offset as well as any special offsets in effect (such as DST) +at a given time. Note that you need to import the `OffsetComponents` +trait. + +```rust +use chrono::{Duration, TimeZone}; +use chrono_tz::Europe::London; +use chrono_tz::OffsetComponents; + +let london_time = London.ymd(2016, 5, 10).and_hms(12, 0, 0); + +// London typically has zero offset from UTC, but has a 1h adjustment forward +// when summer time is in effect. +assert_eq!(london_time.offset().base_utc_offset(), Duration::hours(0)); +assert_eq!(london_time.offset().dst_offset(), Duration::hours(1)); +``` + +Adding 24 hours across a daylight savings change causes a change +in local time + +```rust +use chrono::{TimeZone, Duration}; +use chrono_tz::Europe::London; + +let dt = London.ymd(2016, 10, 29).and_hms(12, 0, 0); +let later = dt + Duration::hours(24); +assert_eq!(later, London.ymd(2016, 10, 30).and_hms(11, 0, 0)); +``` + +And of course you can always convert a local time to a unix timestamp + +```rust +use chrono::TimeZone; +use chrono_tz::Asia::Kolkata; + +let dt = Kolkata.ymd(2000, 1, 1).and_hms(0, 0, 0); +let timestamp = dt.timestamp(); +assert_eq!(timestamp, 946665000); +``` + +Pretty-printing a string will use the correct abbreviation for the timezone + +```rust +use chrono::TimeZone; +use chrono_tz::Europe::London; + +let dt = London.ymd(2016, 5, 10).and_hms(12, 0, 0); +assert_eq!(dt.to_string(), "2016-05-10 12:00:00 BST"); +assert_eq!(dt.to_rfc3339(), "2016-05-10T12:00:00+01:00"); +``` + +You can convert a timezone string to a timezone using the FromStr trait + +```rust +use chrono::TimeZone; +use chrono_tz::Tz; +use chrono_tz::UTC; + +let tz: Tz = "Antarctica/South_Pole".parse().unwrap(); +let dt = tz.ymd(2016, 10, 22).and_hms(12, 0, 0); +let utc = dt.with_timezone(&UTC); +assert_eq!(utc.to_string(), "2016-10-21 23:00:00 UTC"); +``` + +## `no_std` Support + +To use this library without depending on the Rust standard library, put this +in your `Cargo.toml`: + +```toml +[dependencies] +chrono = { version = "0.4", default-features = false } +chrono-tz = { version = "0.5", default-features = false } +``` + +If you are using this library in an environment with limited program +space, such as a microcontroller, take note that you will also likely +need to enable optimizations and Link Time Optimization: +```toml +[profile.dev] +opt-level = 2 +lto = true + +[profile.release] +lto = true +``` + +Otherwise, the additional binary size added by this library may overflow +available program space and trigger a linker error. + +## Limiting the Timezone Table to Zones of Interest + +`Chrono-tz` by default generates timezones for all entries in the [IANA database][]. If you are +interested in only a few timezones you can use enable the `filter-by-regex` feature and set an +environment variable to select them. The environment variable is called +`CHRONO_TZ_TIMEZONE_FILTER` and is a regular expression. It should be specified in your top-level +build: + +```toml +[dependencies] +chrono-tz = { version = "0.6", features = [ "filter-by-regex" ] } +``` + +```sh +CHRONO_TZ_TIMEZONE_FILTER="(Europe/London|US/.*)" cargo build +``` + +This can significantly reduce the size of the generated database, depending on how many timezones +you are interested in. Wikipedia has an [article listing the timezone names][wiki-list]. + +The filtering applied is liberal; if you use a pattern such as "US/.*" then `chrono-tz` will +include all the zones that are linked, such as "America/Denver", not just "US/Mountain". + +[IANA database]: http://www.iana.org/time-zones +[wiki-list]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + +## Developing + +`chrono-tz` uses git submodules, so in order to build locally you will need to +run `git submodule init` and `git submodule update`. + +## Future Improvements + +- Handle leap seconds +- Handle Julian to Gregorian calendar transitions +- Load tzdata always from latest version +- Dynamic tzdata loading diff --git a/vendor/chrono-tz/src/directory.rs.example b/vendor/chrono-tz/src/directory.rs.example new file mode 100644 index 0000000000000..35612217e42e7 --- /dev/null +++ b/vendor/chrono-tz/src/directory.rs.example @@ -0,0 +1,14 @@ +pub mod America { + use timezones::Tz; + + pub const New_York : Tz = Tz::America__New_York; + pub const Toronto : Tz = Tz::America__Toronto; +} + +pub mod Europe { + use timezones::Tz; + + pub const London : Tz = Tz::Europe__London; + pub const Moscow : Tz = Tz::Europe__Moscow; + pub const Rome : Tz = Tz::Europe__Rome; +} diff --git a/vendor/chrono-tz/src/timezones.rs.example b/vendor/chrono-tz/src/timezones.rs.example new file mode 100644 index 0000000000000..110412400aa06 --- /dev/null +++ b/vendor/chrono-tz/src/timezones.rs.example @@ -0,0 +1,122 @@ +use ::timezone_impl::{TimeSpans, FixedTimespanSet, FixedTimespan}; +use std::fmt::{Debug, Formatter, Error}; + +use std::str::FromStr; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum Tz { + America__New_York, + America__Toronto, + Europe__London, + Europe__Moscow, + Europe__Rome, +} + +// Perfect hash table of timezone string -> Tz +static TIMEZONES: phf::Map<&'static str, Tz> = /* ... */ + +impl FromStr for Tz { + type Err = String; + fn from_str(s: &str) -> Result { + TIMEZONES.get(s).cloned().ok_or(s.to_string()) + } +} + +impl Debug for Tz { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + match *self { + Tz::America__New_York => write!(f, "America/New_York"), + Tz::America__Toronto => write!(f, "America/Toronto"), + Tz::Europe__London => write!(f, "Europe/London"), + Tz::Europe__Moscow => write!(f, "Europe/Moscow"), + Tz::Europe__Rome => write!(f, "Europe/Rome"), + } + } +} + +impl TimeSpans for Tz { + fn timespans(&self) -> FixedTimespanSet { + match *self { + Tz::America__New_York => { + const REST: &'static [(i64, FixedTimespan)] = &[ + (-2717650800, FixedTimespan { utc_offset: -18000, dst_offset: 0, name: "EST" }), + (-1633280400, FixedTimespan { utc_offset: -18000, dst_offset: 3600, name: "EDT" }), + (-1615140000, FixedTimespan { utc_offset: -18000, dst_offset: 0, name: "EST" }), + ]; + FixedTimespanSet { + first: FixedTimespan { + utc_offset: -17762, + dst_offset: 0, + name: "LMT", + }, + rest: REST + } + }, + + Tz::America__Toronto => { + const REST: &'static [(i64, FixedTimespan)] = &[ + (-2366736148, FixedTimespan { utc_offset: -18000, dst_offset: 0, name: "EST" }), + (-1632070800, FixedTimespan { utc_offset: -18000, dst_offset: 3600, name: "EDT" }), + (-1615140000, FixedTimespan { utc_offset: -18000, dst_offset: 0, name: "EST" }), + ]; + FixedTimespanSet { + first: FixedTimespan { + utc_offset: -19052, + dst_offset: 0, + name: "LMT", + }, + rest: REST + } + }, + + Tz::Europe__London => { + const REST: &'static [(i64, FixedTimespan)] = &[ + (-3852662325, FixedTimespan { utc_offset: 0, dst_offset: 0, name: "GMT" }), + (-1691964000, FixedTimespan { utc_offset: 0, dst_offset: 3600, name: "BST" }), + (-1680472800, FixedTimespan { utc_offset: 0, dst_offset: 0, name: "GMT" }), + ]; + FixedTimespanSet { + first: FixedTimespan { + utc_offset: -75, + dst_offset: 0, + name: "LMT", + }, + rest: REST + } + }, + + Tz::Europe__Moscow => { + const REST: &'static [(i64, FixedTimespan)] = &[ + (-2840149817, FixedTimespan { utc_offset: 9017, dst_offset: 0, name: "MMT" }), + (-1688265017, FixedTimespan { utc_offset: 9079, dst_offset: 0, name: "MMT" }), + (-1656819079, FixedTimespan { utc_offset: 9079, dst_offset: 3600, name: "MST" }), + ]; + FixedTimespanSet { + first: FixedTimespan { + utc_offset: 9017, + dst_offset: 0, + name: "LMT", + }, + rest: REST + } + }, + + Tz::Europe__Rome => { + const REST: &'static [(i64, FixedTimespan)] = &[ + (-3259097396, FixedTimespan { utc_offset: 2996, dst_offset: 0, name: "RMT" }), + (-2403564596, FixedTimespan { utc_offset: 3600, dst_offset: 0, name: "CET" }), + (-1690851600, FixedTimespan { utc_offset: 3600, dst_offset: 3600, name: "CEST" }), + ]; + FixedTimespanSet { + first: FixedTimespan { + utc_offset: 2996, + dst_offset: 0, + name: "LMT", + }, + rest: REST + } + }, + + } + } +} diff --git a/vendor/chrono-tz/tz/CONTRIBUTING b/vendor/chrono-tz/tz/CONTRIBUTING new file mode 100644 index 0000000000000..6d800e4c03a34 --- /dev/null +++ b/vendor/chrono-tz/tz/CONTRIBUTING @@ -0,0 +1,97 @@ +# Contributing to the tz code and data + +Please do not create issues or pull requests on GitHub, as the +proper procedure for proposing and distributing patches is via +email as described below. + +The time zone database is by no means authoritative: governments +change timekeeping rules erratically and sometimes with little +warning, the data entries do not cover all of civil time before +1970, and undoubtedly errors remain in the code and data. Feel +free to fill gaps or fix mistakes, and please email improvements +to for use in the future. In your email, please give +reliable sources that reviewers can check. + +## Contributing technical changes + +To email small changes, please run a POSIX shell command like +'diff -u old/europe new/europe >myfix.patch', and attach +'myfix.patch' to the email. + +For more-elaborate or possibly controversial changes, +such as renaming, adding or removing zones, please read +"Theory and pragmatics of the tz code and data" +. +It is also good to browse the mailing list archives + for examples of patches that tend +to work well. Additions to data should contain commentary citing +reliable sources as justification. Citations should use "https:" URLs +if available. + +For changes that fix sensitive security-related bugs, please see the +distribution's 'SECURITY' file. + +Please submit changes against either the latest release + or the main branch of the development +repository. The latter is preferred. + +## Sample Git workflow for developing contributions + +If you use Git the following workflow may be helpful: + + * Copy the development repository. + + git clone https://github.com/eggert/tz.git + cd tz + + * Get current with the main branch. + + git checkout main + git pull + + * Switch to a new branch for the changes. Choose a different + branch name for each change set. + + git checkout -b mybranch + + * Sleuth by using 'git blame'. For example, when fixing data for + Africa/Sao_Tome, if the command 'git blame africa' outputs a line + '2951fa3b (Paul Eggert 2018-01-08 09:03:13 -0800 1068) Zone + Africa/Sao_Tome 0:26:56 - LMT 1884', commit 2951fa3b should + provide some justification for the 'Zone Africa/Sao_Tome' line. + + * Edit source files. Include commentary that justifies the + changes by citing reliable sources. + + * Debug the changes, e.g.: + + make check + make install + ./zdump -v America/Los_Angeles + + * For each separable change, commit it in the new branch, e.g.: + + git add northamerica + git commit + + See recent 'git log' output for the commit-message style. + + * Create patch files 0001-..., 0002-..., ... + + git format-patch main + + * After reviewing the patch files, send the patches to + for others to review. + + git send-email main + + For an archived example of such an email, see + "[PROPOSED] Fix off-by-1 error for Jamaica and T&C before 1913" + . + + * Start anew by getting current with the main branch again + (the second step above). + +----- + +This file is in the public domain. diff --git a/vendor/chrono-tz/tz/Makefile b/vendor/chrono-tz/tz/Makefile new file mode 100644 index 0000000000000..d48354c72df46 --- /dev/null +++ b/vendor/chrono-tz/tz/Makefile @@ -0,0 +1,1361 @@ +# Make and install tzdb code and data. +# This file is in the public domain, so clarified as of +# 2009-05-17 by Arthur David Olson. +# Request POSIX conformance; this must be the first non-comment line. +.POSIX: +# On older platforms you may need to scrounge for a POSIX-conforming 'make'. +# For example, on Solaris 10 (2005), use /usr/sfw/bin/gmake or +# /usr/xpg4/bin/make, not /usr/ccs/bin/make. + +# To affect how this Makefile works, you can run a shell script like this: +# +# #!/bin/sh +# make CC='gcc -std=gnu11' "$@" +# +# This example script is appropriate for a pre-2017 GNU/Linux system +# where a non-default setting is needed to support this package's use of C99. +# +# Alternatively, you can simply edit this Makefile to tailor the following +# macro definitions. + +############################################################################### +# Start of macros that one plausibly might want to tailor. + +# Package name for the code distribution. +PACKAGE= tzcode + +# Version number for the distribution, overridden in the 'tarballs' rule below. +VERSION= unknown + +# Email address for bug reports. +BUGEMAIL= tz@iana.org + +# DATAFORM selects the data format. +# Available formats represent essentially the same data, albeit +# possibly with minor discrepancies that users are not likely to notice. +# To get new features and the best data right away, use: +# DATAFORM= vanguard +# To wait a while before using new features, to give downstream users +# time to upgrade zic (the default), use: +# DATAFORM= main +# To wait even longer for new features, use: +# DATAFORM= rearguard +# Rearguard users might also want "ZFLAGS = -b fat"; see below. +DATAFORM= main + +# Change the line below for your timezone (after finding the one you want in +# one of the $(TDATA) source files, or adding it to a source file). +# Alternatively, if you discover you've got the wrong timezone, you can just +# 'zic -l -' to remove it, or 'zic -l rightzone' to change it. +# Use the command +# make zonenames +# to get a list of the values you can use for LOCALTIME. + +LOCALTIME= Factory + +# The POSIXRULES macro controls interpretation of POSIX-2017.1-like TZ +# settings like TZ='EET-2EEST' that lack DST transition rules. +# If POSIXRULES is '-', no template is installed; this is the default. +# Any other value for POSIXRULES is obsolete and should not be relied on, as: +# * It does not work correctly in popular implementations such as GNU/Linux. +# * It does not work even in tzcode, except for historical timestamps +# that precede the last explicit transition in the POSIXRULES file. +# Hence it typically does not work for current and future timestamps. +# If, despite the above, you want a template for handling these settings, +# you can change the line below (after finding the timezone you want in the +# one of the $(TDATA) source files, or adding it to a source file). +# Alternatively, if you discover you've got the wrong timezone, you can just +# 'zic -p -' to remove it, or 'zic -p rightzone' to change it. +# Use the command +# make zonenames +# to get a list of the values you can use for POSIXRULES. + +POSIXRULES= - + +# Also see TZDEFRULESTRING below, which takes effect only +# if POSIXRULES is '-' or if the template file cannot be accessed. + + +# Installation locations. +# +# The defaults are suitable for Debian, except that if REDO is +# posix_right or right_posix then files that Debian puts under +# /usr/share/zoneinfo/posix and /usr/share/zoneinfo/right are instead +# put under /usr/share/zoneinfo-posix and /usr/share/zoneinfo-leaps, +# respectively. Problems with the Debian approach are discussed in +# the commentary for the right_posix rule (below). + +# Destination directory, which can be used for staging. +# 'make DESTDIR=/stage install' installs under /stage (e.g., to +# /stage/etc/localtime instead of to /etc/localtime). Files under +# /stage are not intended to work as-is, but can be copied by hand to +# the root directory later. If DESTDIR is empty, 'make install' does +# not stage, but installs directly into production locations. +DESTDIR = + +# Everything is installed into subdirectories of TOPDIR, and used there. +# TOPDIR should be empty (meaning the root directory), +# or a directory name that does not end in "/". +# TOPDIR should be empty or an absolute name unless you're just testing. +TOPDIR = + +# The default local timezone is taken from the file TZDEFAULT. +TZDEFAULT = $(TOPDIR)/etc/localtime + +# The subdirectory containing installed program and data files, and +# likewise for installed files that can be shared among architectures. +# These should be relative file names. +USRDIR = usr +USRSHAREDIR = $(USRDIR)/share + +# "Compiled" timezone information is placed in the "TZDIR" directory +# (and subdirectories). +# TZDIR_BASENAME should not contain "/" and should not be ".", ".." or empty. +TZDIR_BASENAME= zoneinfo +TZDIR = $(TOPDIR)/$(USRSHAREDIR)/$(TZDIR_BASENAME) + +# The "tzselect" and (if you do "make INSTALL") "date" commands go in: +BINDIR = $(TOPDIR)/$(USRDIR)/bin + +# The "zdump" command goes in: +ZDUMPDIR = $(BINDIR) + +# The "zic" command goes in: +ZICDIR = $(TOPDIR)/$(USRDIR)/sbin + +# Manual pages go in subdirectories of. . . +MANDIR = $(TOPDIR)/$(USRSHAREDIR)/man + +# Library functions are put in an archive in LIBDIR. +LIBDIR = $(TOPDIR)/$(USRDIR)/lib + + +# Types to try, as an alternative to time_t. +TIME_T_ALTERNATIVES = $(TIME_T_ALTERNATIVES_HEAD) $(TIME_T_ALTERNATIVES_TAIL) +TIME_T_ALTERNATIVES_HEAD = int_least64_t +TIME_T_ALTERNATIVES_TAIL = int_least32_t uint_least32_t uint_least64_t + +# What kind of TZif data files to generate. (TZif is the binary time +# zone data format that zic generates; see Internet RFC 8536.) +# If you want only POSIX time, with time values interpreted as +# seconds since the epoch (not counting leap seconds), use +# REDO= posix_only +# below. If you want only "right" time, with values interpreted +# as seconds since the epoch (counting leap seconds), use +# REDO= right_only +# below. If you want both sets of data available, with leap seconds not +# counted normally, use +# REDO= posix_right +# below. If you want both sets of data available, with leap seconds counted +# normally, use +# REDO= right_posix +# below. POSIX mandates that leap seconds not be counted; for compatibility +# with it, use "posix_only" or "posix_right". Use POSIX time on systems with +# leap smearing; this can work better than unsmeared "right" time with +# applications that are not leap second aware, and is closer to unsmeared +# "right" time than unsmeared POSIX time is (e.g., 0.5 vs 1.0 s max error). + +REDO= posix_right + +# Whether to put an "Expires" line in the leapseconds file. +# Use EXPIRES_LINE=1 to put the line in, 0 to omit it. +# The EXPIRES_LINE value matters only if REDO's value contains "right". +# If you change EXPIRES_LINE, remove the leapseconds file before running "make". +# zic's support for the Expires line was introduced in tzdb 2020a, +# and was modified in tzdb 2021b to generate version 4 TZif files. +# EXPIRES_LINE defaults to 0 for now so that the leapseconds file +# can be given to pre-2020a zic implementations and so that TZif files +# built by newer zic implementations can be read by pre-2021b libraries. +EXPIRES_LINE= 0 + +# To install data in text form that has all the information of the TZif data, +# (optionally incorporating leap second information), use +# TZDATA_TEXT= tzdata.zi leapseconds +# To install text data without leap second information (e.g., because +# REDO='posix_only'), use +# TZDATA_TEXT= tzdata.zi +# To avoid installing text data, use +# TZDATA_TEXT= + +TZDATA_TEXT= leapseconds tzdata.zi + +# For backward-compatibility links for old zone names, use +# BACKWARD= backward +# To omit these links, use +# BACKWARD= + +BACKWARD= backward + +# If you want out-of-scope and often-wrong data from the file 'backzone', +# but only for entries listed in the backward-compatibility file zone.tab, use +# PACKRATDATA= backzone +# PACKRATLIST= zone.tab +# If you want all the 'backzone' data, use +# PACKRATDATA= backzone +# PACKRATLIST= +# To omit this data, use +# PACKRATDATA= +# PACKRATLIST= + +PACKRATDATA= +PACKRATLIST= + +# The name of a locale using the UTF-8 encoding, used during self-tests. +# The tests are skipped if the name does not appear to work on this system. + +UTF8_LOCALE= en_US.utf8 + +# Non-default libraries needed to link. +# On some hosts, this should have -lintl unless CFLAGS has -DHAVE_GETTEXT=0. +LDLIBS= + +# Add the following to an uncommented "CFLAGS=" line as needed +# to override defaults specified in the source code or by the system. +# "-DFOO" is equivalent to "-DFOO=1". +# -DDEPRECATE_TWO_DIGIT_YEARS for optional runtime warnings about strftime +# formats that generate only the last two digits of year numbers +# -DEPOCH_LOCAL if the 'time' function returns local time not UT +# -DEPOCH_OFFSET=N if the 'time' function returns a value N greater +# than what POSIX specifies, assuming local time is UT. +# For example, N is 252460800 on AmigaOS. +# -DHAVE_DECL_ASCTIME_R=0 if does not declare asctime_r +# -DHAVE_DECL_ENVIRON if declares 'environ' +# -DHAVE_DECL_TIMEGM=0 if does not declare timegm +# -DHAVE_DIRECT_H if mkdir needs (MS-Windows) +# -DHAVE__GENERIC=0 if _Generic does not work* +# -DHAVE_GETRANDOM if getrandom works (e.g., GNU/Linux), +# -DHAVE_GETRANDOM=0 to avoid using getrandom +# -DHAVE_GETTEXT if gettext works (e.g., GNU/Linux, FreeBSD, Solaris), +# where LDLIBS also needs to contain -lintl on some hosts; +# -DHAVE_GETTEXT=0 to avoid using gettext +# -DHAVE_INCOMPATIBLE_CTIME_R if your system's time.h declares +# ctime_r and asctime_r incompatibly with the POSIX standard +# (Solaris when _POSIX_PTHREAD_SEMANTICS is not defined). +# -DHAVE_INTTYPES_H=0 if does not work*+ +# -DHAVE_LINK=0 if your system lacks a link function +# -DHAVE_LOCALTIME_R=0 if your system lacks a localtime_r function +# -DHAVE_LOCALTIME_RZ=0 if you do not want zdump to use localtime_rz +# localtime_rz can make zdump significantly faster, but is nonstandard. +# -DHAVE_MALLOC_ERRNO=0 if malloc etc. do not set errno on failure. +# -DHAVE_POSIX_DECLS=0 if your system's include files do not declare +# functions like 'link' or variables like 'tzname' required by POSIX +# -DHAVE_SETENV=0 if your system lacks the setenv function +# -DHAVE_SNPRINTF=0 if your system lacks the snprintf function+ +# -DHAVE_STDCKDINT_H=0 if neither nor substitutes like +# __builtin_add_overflow work* +# -DHAVE_STDINT_H=0 if does not work*+ +# -DHAVE_STRFTIME_L if declares locale_t and strftime_l +# -DHAVE_STRDUP=0 if your system lacks the strdup function +# -DHAVE_STRTOLL=0 if your system lacks the strtoll function+ +# -DHAVE_SYMLINK=0 if your system lacks the symlink function +# -DHAVE_SYS_STAT_H=0 if does not work* +# -DHAVE_TZSET=0 if your system lacks a tzset function +# -DHAVE_UNISTD_H=0 if does not work* +# -DHAVE_UTMPX_H=0 if does not work* +# -Dlocale_t=XXX if your system uses XXX instead of locale_t +# -DPORT_TO_C89 if tzcode should also run on mostly-C89 platforms+ +# Typically it is better to use a later standard. For example, +# with GCC 4.9.4 (2016), prefer '-std=gnu11' to '-DPORT_TO_C89'. +# Even with -DPORT_TO_C89, the code needs at least one C99 +# feature (integers at least 64 bits wide) and maybe more. +# -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers +# with external linkage, e.g., applications cannot define 'localtime'. +# -Dssize_t=long on hosts like MS-Windows that lack ssize_t +# -DSUPPORT_C89 if the tzcode library should support C89 callers+ +# However, this might trigger latent bugs in C99-or-later callers. +# -DSUPPRESS_TZDIR to not prepend TZDIR to file names; this has +# security implications and is not recommended for general use +# -DTHREAD_SAFE to make localtime.c thread-safe, as POSIX requires; +# not needed by the main-program tz code, which is single-threaded. +# Append other compiler flags as needed, e.g., -pthread on GNU/Linux. +# -Dtime_tz=\"T\" to use T as the time_t type, rather than the system time_t +# This is intended for internal use only; it mangles external names. +# -DTZ_DOMAIN=\"foo\" to use "foo" for gettext domain name; default is "tz" +# -DTZ_DOMAINDIR=\"/path\" to use "/path" for gettext directory; +# the default is system-supplied, typically "/usr/lib/locale" +# -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified +# DST transitions for POSIX.1-2017-style TZ strings lacking them, +# in the usual case where POSIXRULES is '-'. If not specified, +# TZDEFRULESTRING defaults to US rules for future DST transitions. +# This mishandles some past timestamps, as US DST rules have changed. +# It also mishandles settings like TZ='EET-2EEST' for eastern Europe, +# as Europe and US DST rules differ. +# -DTZNAME_MAXIMUM=N to limit time zone abbreviations to N bytes (default 255) +# -DUNINIT_TRAP if reading uninitialized storage can cause problems +# other than simply getting garbage data +# -DUSE_LTZ=0 to build zdump with the system time zone library +# Also set TZDOBJS=zdump.o and CHECK_TIME_T_ALTERNATIVES= below. +# -DZIC_BLOAT_DEFAULT=\"fat\" to default zic's -b option to "fat", and +# similarly for "slim". Fat TZif files work around incompatibilities +# and bugs in some TZif readers, notably older ones that +# ignore or otherwise mishandle 64-bit data in TZif files; +# however, fat TZif files may trigger bugs in newer TZif readers. +# Slim TZif files are more efficient, and are the default. +# -DZIC_MAX_ABBR_LEN_WO_WARN=3 +# (or some other number) to set the maximum time zone abbreviation length +# that zic will accept without a warning (the default is 6) +# -g to generate symbolic debugging info +# -Idir to include from directory 'dir' +# -O0 to disable optimization; other -O options to enable more optimization +# -Uname to remove any definition of the macro 'name' +# $(GCC_DEBUG_FLAGS) if you are using recent GCC and want lots of checking +# +# * Options marked "*" can be omitted if your compiler is C23 compatible. +# * Options marked "+" are obsolescent and are planned to be removed +# once the code assumes C99 or later, say in the year 2029. +# +# Select instrumentation via "make GCC_INSTRUMENT='whatever'". +GCC_INSTRUMENT = \ + -fsanitize=undefined -fsanitize-address-use-after-scope \ + -fsanitize-undefined-trap-on-error -fstack-protector +# Omit -fanalyzer from GCC_DEBUG_FLAGS, as it makes GCC too slow. +GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \ + $(GCC_INSTRUMENT) \ + -Wall -Wextra \ + -Walloc-size-larger-than=100000 -Warray-bounds=2 \ + -Wbad-function-cast -Wbidi-chars=any,ucn -Wcast-align=strict -Wdate-time \ + -Wdeclaration-after-statement -Wdouble-promotion \ + -Wduplicated-branches -Wduplicated-cond \ + -Wformat=2 -Wformat-overflow=2 -Wformat-signedness -Wformat-truncation \ + -Wimplicit-fallthrough=5 -Winit-self -Wlogical-op \ + -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ + -Wnull-dereference \ + -Wold-style-definition -Woverlength-strings -Wpointer-arith \ + -Wshadow -Wshift-overflow=2 -Wstrict-overflow \ + -Wstrict-prototypes -Wstringop-overflow=4 \ + -Wstringop-truncation -Wsuggest-attribute=cold \ + -Wsuggest-attribute=const -Wsuggest-attribute=format \ + -Wsuggest-attribute=malloc \ + -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure \ + -Wtrampolines -Wundef -Wuninitialized -Wunused-macros -Wuse-after-free=3 \ + -Wvariadic-macros -Wvla -Wwrite-strings \ + -Wno-address -Wno-format-nonliteral -Wno-sign-compare \ + -Wno-type-limits +# +# If your system has a "GMT offset" field in its "struct tm"s +# (or if you decide to add such a field in your system's "time.h" file), +# add the name to a define such as +# -DTM_GMTOFF=tm_gmtoff +# to the end of the "CFLAGS=" line. If not defined, the code attempts to +# guess TM_GMTOFF from other macros; define NO_TM_GMTOFF to suppress this. +# Similarly, if your system has a "zone abbreviation" field, define +# -DTM_ZONE=tm_zone +# and define NO_TM_ZONE to suppress any guessing. +# Although these two fields are not required by POSIX.1-2017, +# POSIX 202x/D4 requires them and they are widely available +# on GNU/Linux and BSD systems. +# +# The next batch of options control support for external variables +# exported by tzcode. In practice these variables are less useful +# than TM_GMTOFF and TM_ZONE. However, most of them are standardized. +# # +# # To omit or support the external variable "tzname", add one of: +# # -DHAVE_TZNAME=0 # do not support "tzname" +# # -DHAVE_TZNAME=1 # support "tzname", which is defined by system library +# # -DHAVE_TZNAME=2 # support and define "tzname" +# # to the "CFLAGS=" line. "tzname" is required by POSIX.1-1988 and later. +# # If not defined, the code attempts to guess HAVE_TZNAME from other macros. +# # Warning: unless time_tz is also defined, HAVE_TZNAME=1 can cause +# # crashes when combined with some platforms' standard libraries, +# # presumably due to memory allocation issues. +# # +# # To omit or support the external variables "timezone" and "daylight", add +# # -DUSG_COMPAT=0 # do not support +# # -DUSG_COMPAT=1 # support, and variables are defined by system library +# # -DUSG_COMPAT=2 # support and define variables +# # to the "CFLAGS=" line; "timezone" and "daylight" are inspired by Unix +# # Systems Group code and are required by POSIX.1-2008 and later (with XSI). +# # If not defined, the code attempts to guess USG_COMPAT from other macros. +# # +# # To support the external variable "altzone", add +# # -DALTZONE=0 # do not support +# # -DALTZONE=1 # support "altzone", which is defined by system library +# # -DALTZONE=2 # support and define "altzone" +# # to the end of the "CFLAGS=" line; although "altzone" appeared in +# # System V Release 3.1 it has not been standardized. +# # If not defined, the code attempts to guess ALTZONE from other macros. +# +# If you want functions that were inspired by early versions of X3J11's work, +# add +# -DSTD_INSPIRED +# to the end of the "CFLAGS=" line. This arranges for the following +# functions to be added to the time conversion library. +# "offtime" is like "gmtime" except that it accepts a second (long) argument +# that gives an offset to add to the time_t when converting it. +# I.e., "offtime" is like calling "localtime_rz" with a fixed-offset zone. +# "timelocal" is nearly equivalent to "mktime". +# "timeoff" is like "timegm" except that it accepts a second (long) argument +# that gives an offset to use when converting to a time_t. +# I.e., "timeoff" is like calling "mktime_z" with a fixed-offset zone. +# "posix2time" and "time2posix" are described in an included manual page. +# X3J11's work does not describe any of these functions. +# These functions may well disappear in future releases of the time +# conversion package. +# +# If you don't want functions that were inspired by NetBSD, add +# -DNETBSD_INSPIRED=0 +# to the end of the "CFLAGS=" line. Otherwise, the functions +# "localtime_rz", "mktime_z", "tzalloc", and "tzfree" are added to the +# time library, and if STD_INSPIRED is also defined to nonzero the functions +# "posix2time_z" and "time2posix_z" are added as well. +# The functions ending in "_z" (or "_rz") are like their unsuffixed +# (or suffixed-by-"_r") counterparts, except with an extra first +# argument of opaque type timezone_t that specifies the timezone. +# "tzalloc" allocates a timezone_t value, and "tzfree" frees it. +# +# If you want to allocate state structures in localtime, add +# -DALL_STATE +# to the end of the "CFLAGS=" line. Storage is obtained by calling malloc. +# +# NIST-PCTS:151-2, Version 1.4, (1993-12-03) is a test suite put +# out by the National Institute of Standards and Technology +# which claims to test C and POSIX conformance. If you want to pass PCTS, add +# -DPCTS +# to the end of the "CFLAGS=" line. +# +# If you want strict compliance with XPG4 as of 1994-04-09, add +# -DXPG4_1994_04_09 +# to the end of the "CFLAGS=" line. This causes "strftime" to always return +# 53 as a week number (rather than 52 or 53) for January days before +# January's first Monday when a "%V" format is used and January 1 +# falls on a Friday, Saturday, or Sunday. +# +# POSIX says CFLAGS defaults to "-O 1". +# Uncomment the following line and edit its contents as needed. + +#CFLAGS= -O 1 + + +# The name of a POSIX-like library archiver, its flags, C compiler, +# linker flags, and 'make' utility. Ordinarily the defaults suffice. +# The commented-out values are the defaults specified by POSIX.1-202x/D4. +#AR = ar +#ARFLAGS = -rv +#CC = c17 +#LDFLAGS = +#MAKE = make + +# For leap seconds, this Makefile uses LEAPSECONDS='-L leapseconds' in +# submake command lines. The default is no leap seconds. + +LEAPSECONDS= + +# Where to fetch leap-seconds.list from. +leaplist_URI = \ + https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list +# The file is generated by the IERS Earth Orientation Centre, in Paris. +leaplist_TZ = Europe/Paris + +# The zic command and its arguments. + +zic= ./zic +ZIC= $(zic) $(ZFLAGS) + +# To shrink the size of installed TZif files, +# append "-r @N" to omit data before N-seconds-after-the-Epoch. +# To grow the files and work around bugs in older applications, +# possibly at the expense of introducing bugs in newer ones, +# append "-b fat"; see ZIC_BLOAT_DEFAULT above. +# See the zic man page for more about -b and -r. +ZFLAGS= + +# How to use zic to install TZif files. + +ZIC_INSTALL= $(ZIC) -d '$(DESTDIR)$(TZDIR)' $(LEAPSECONDS) + +# The name of a POSIX-compliant 'awk' on your system. +# mawk 1.3.3 and Solaris 10 /usr/bin/awk do not work. +# Also, it is better (though not essential) if 'awk' supports UTF-8, +# and unfortunately mawk and busybox awk do not support UTF-8. +# Try AWK=gawk or AWK=nawk if your awk has the abovementioned problems. +AWK= awk + +# The full path name of a POSIX-compliant shell, preferably one that supports +# the Korn shell's 'select' statement as an extension. +# These days, Bash is the most popular. +# It should be OK to set this to /bin/sh, on platforms where /bin/sh +# lacks 'select' or doesn't completely conform to POSIX, but /bin/bash +# is typically nicer if it works. +KSHELL= /bin/bash + +# Name of curl , used for HTML validation +# and to fetch leap-seconds.list from upstream. +CURL= curl + +# Name of GNU Privacy Guard , used to sign distributions. +GPG= gpg + +# This expensive test requires USE_LTZ. +# To suppress it, define this macro to be empty. +CHECK_TIME_T_ALTERNATIVES = check_time_t_alternatives + +# SAFE_CHAR is a regular expression that matches a safe character. +# Some parts of this distribution are limited to safe characters; +# others can use any UTF-8 character. +# For now, the safe characters are a safe subset of ASCII. +# The caller must set the shell variable 'sharp' to the character '#', +# since Makefile macros cannot contain '#'. +# TAB_CHAR is a single tab character, in single quotes. +TAB_CHAR= ' ' +SAFE_CHARSET1= $(TAB_CHAR)' !\"'$$sharp'$$%&'\''()*+,./0123456789:;<=>?@' +SAFE_CHARSET2= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\^_`' +SAFE_CHARSET3= 'abcdefghijklmnopqrstuvwxyz{|}~' +SAFE_CHARSET= $(SAFE_CHARSET1)$(SAFE_CHARSET2)$(SAFE_CHARSET3) +SAFE_CHAR= '[]'$(SAFE_CHARSET)'-]' + +# These non-alphabetic, non-ASCII printable characters are Latin-1, +# and so are likely displayable even in editors like XEmacs 21 +# that have limited display capabilities. +UNUSUAL_OK_LATIN_1 = ¡¢£¤¥¦§¨©«¬®¯°±²³´¶·¸¹»¼½¾¿×÷ +# Non-ASCII non-letters that OK_CHAR allows, as these characters are +# useful in commentary. +UNUSUAL_OK_CHARSET= $(UNUSUAL_OK_LATIN_1) + +# Put this in a bracket expression to match spaces. +s = [:space:] + +# OK_CHAR matches any character allowed in the distributed files. +# This is the same as SAFE_CHAR, except that UNUSUAL_OK_CHARSET and +# multibyte letters are also allowed so that commentary can contain a +# few safe symbols and people's names and can quote non-English sources. +# Other non-letters are limited to ASCII renderings for the +# convenience of maintainers using XEmacs 21.5.34, which by default +# mishandles Unicode characters U+0100 and greater. +OK_CHAR= '[][:alpha:]$(UNUSUAL_OK_CHARSET)'$(SAFE_CHARSET)'-]' + +# SAFE_LINE matches a line of safe characters. +# SAFE_SHARP_LINE is similar, except any OK character can follow '#'; +# this is so that comments can contain non-ASCII characters. +# OK_LINE matches a line of OK characters. +SAFE_LINE= '^'$(SAFE_CHAR)'*$$' +SAFE_SHARP_LINE='^'$(SAFE_CHAR)'*('$$sharp$(OK_CHAR)'*)?$$' +OK_LINE= '^'$(OK_CHAR)'*$$' + +# Flags to give 'tar' when making a distribution. +# Try to use flags appropriate for GNU tar. +GNUTARFLAGS= --format=pax --pax-option='delete=atime,delete=ctime' \ + --numeric-owner --owner=0 --group=0 \ + --mode=go+u,go-w --sort=name +TARFLAGS= `if tar $(GNUTARFLAGS) --version >/dev/null 2>&1; \ + then echo $(GNUTARFLAGS); \ + else :; \ + fi` + +# Flags to give 'gzip' when making a distribution. +GZIPFLAGS= -9n + +# When comparing .tzs files, use GNU diff's -F'^TZ=' option if supported. +# This makes it easier to see which Zone has been affected. +DIFF_TZS= diff -u$$(! diff -u -F'^TZ=' - - <>/dev/null >&0 2>&1 \ + || echo ' -F^TZ=') + +# ':' on typical hosts; 'ranlib' on the ancient hosts that still need ranlib. +RANLIB= : + +# POSIX prohibits defining or using SHELL. However, csh users on systems +# that use the user shell for Makefile commands may need to define SHELL. +#SHELL= /bin/sh + +# End of macros that one plausibly might want to tailor. +############################################################################### + + +TZCOBJS= zic.o +TZDOBJS= zdump.o localtime.o asctime.o strftime.o +DATEOBJS= date.o localtime.o strftime.o asctime.o +LIBSRCS= localtime.c asctime.c difftime.c strftime.c +LIBOBJS= localtime.o asctime.o difftime.o strftime.o +HEADERS= tzfile.h private.h +NONLIBSRCS= zic.c zdump.c +NEWUCBSRCS= date.c +SOURCES= $(HEADERS) $(LIBSRCS) $(NONLIBSRCS) $(NEWUCBSRCS) \ + tzselect.ksh workman.sh +MANS= newctime.3 newstrftime.3 newtzset.3 time2posix.3 \ + tzfile.5 tzselect.8 zic.8 zdump.8 +MANTXTS= newctime.3.txt newstrftime.3.txt newtzset.3.txt \ + time2posix.3.txt \ + tzfile.5.txt tzselect.8.txt zic.8.txt zdump.8.txt \ + date.1.txt +COMMON= calendars CONTRIBUTING LICENSE Makefile \ + NEWS README SECURITY theory.html version +WEB_PAGES= tz-art.html tz-how-to.html tz-link.html +CHECK_WEB_PAGES=check_theory.html check_tz-art.html \ + check_tz-how-to.html check_tz-link.html +DOCS= $(MANS) date.1 $(MANTXTS) $(WEB_PAGES) +PRIMARY_YDATA= africa antarctica asia australasia \ + europe northamerica southamerica +YDATA= $(PRIMARY_YDATA) etcetera +NDATA= factory +TDATA_TO_CHECK= $(YDATA) $(NDATA) backward +TDATA= $(YDATA) $(NDATA) $(BACKWARD) +ZONETABLES= zone.tab zone1970.tab zonenow.tab +TABDATA= iso3166.tab $(TZDATA_TEXT) $(ZONETABLES) +LEAP_DEPS= leapseconds.awk leap-seconds.list +TZDATA_ZI_DEPS= ziguard.awk zishrink.awk version $(TDATA) \ + $(PACKRATDATA) $(PACKRATLIST) +DSTDATA_ZI_DEPS= ziguard.awk $(TDATA) $(PACKRATDATA) $(PACKRATLIST) +DATA= $(TDATA_TO_CHECK) backzone iso3166.tab leap-seconds.list \ + leapseconds $(ZONETABLES) +AWK_SCRIPTS= checklinks.awk checknow.awk checktab.awk leapseconds.awk \ + ziguard.awk zishrink.awk +MISC= $(AWK_SCRIPTS) +TZS_YEAR= 2050 +TZS_CUTOFF_FLAG= -c $(TZS_YEAR) +TZS= to$(TZS_YEAR).tzs +TZS_NEW= to$(TZS_YEAR)new.tzs +TZS_DEPS= $(YDATA) asctime.c localtime.c \ + private.h tzfile.h zdump.c zic.c +TZDATA_DIST = $(COMMON) $(DATA) $(MISC) +# EIGHT_YARDS is just a yard short of the whole ENCHILADA. +EIGHT_YARDS = $(TZDATA_DIST) $(DOCS) $(SOURCES) tzdata.zi +ENCHILADA = $(EIGHT_YARDS) $(TZS) + +# Consult these files when deciding whether to rebuild the 'version' file. +# This list is not the same as the output of 'git ls-files', since +# .gitignore is not distributed. +VERSION_DEPS= \ + calendars CONTRIBUTING LICENSE Makefile NEWS README SECURITY \ + africa antarctica asctime.c asia australasia \ + backward backzone \ + checklinks.awk checknow.awk checktab.awk \ + date.1 date.c difftime.c \ + etcetera europe factory iso3166.tab \ + leap-seconds.list leapseconds.awk localtime.c \ + newctime.3 newstrftime.3 newtzset.3 northamerica \ + private.h southamerica strftime.c theory.html \ + time2posix.3 tz-art.html tz-how-to.html tz-link.html \ + tzfile.5 tzfile.h tzselect.8 tzselect.ksh \ + workman.sh zdump.8 zdump.c zic.8 zic.c \ + ziguard.awk zishrink.awk \ + zone.tab zone1970.tab zonenow.tab + +all: tzselect zic zdump libtz.a $(TABDATA) \ + vanguard.zi main.zi rearguard.zi + +ALL: all date $(ENCHILADA) + +install: all $(DATA) $(REDO) $(MANS) + mkdir -p '$(DESTDIR)$(BINDIR)' \ + '$(DESTDIR)$(ZDUMPDIR)' '$(DESTDIR)$(ZICDIR)' \ + '$(DESTDIR)$(LIBDIR)' \ + '$(DESTDIR)$(MANDIR)/man3' '$(DESTDIR)$(MANDIR)/man5' \ + '$(DESTDIR)$(MANDIR)/man8' + $(ZIC_INSTALL) -l $(LOCALTIME) \ + `case '$(POSIXRULES)' in ?*) echo '-p';; esac \ + ` $(POSIXRULES) \ + -t '$(DESTDIR)$(TZDEFAULT)' + cp -f $(TABDATA) '$(DESTDIR)$(TZDIR)/.' + cp tzselect '$(DESTDIR)$(BINDIR)/.' + cp zdump '$(DESTDIR)$(ZDUMPDIR)/.' + cp zic '$(DESTDIR)$(ZICDIR)/.' + cp libtz.a '$(DESTDIR)$(LIBDIR)/.' + $(RANLIB) '$(DESTDIR)$(LIBDIR)/libtz.a' + cp -f newctime.3 newtzset.3 '$(DESTDIR)$(MANDIR)/man3/.' + cp -f tzfile.5 '$(DESTDIR)$(MANDIR)/man5/.' + cp -f tzselect.8 zdump.8 zic.8 '$(DESTDIR)$(MANDIR)/man8/.' + +INSTALL: ALL install date.1 + mkdir -p '$(DESTDIR)$(BINDIR)' '$(DESTDIR)$(MANDIR)/man1' + cp date '$(DESTDIR)$(BINDIR)/.' + cp -f date.1 '$(DESTDIR)$(MANDIR)/man1/.' + +# Calculate version number from git, if available. +# Otherwise, use $(VERSION) unless it is "unknown" and there is already +# a 'version' file, in which case reuse the existing 'version' contents +# and append "-dirty" if the contents do not already end in "-dirty". +version: $(VERSION_DEPS) + { (type git) >/dev/null 2>&1 && \ + V=`git describe --match '[0-9][0-9][0-9][0-9][a-z]*' \ + --abbrev=7 --dirty` || \ + if test '$(VERSION)' = unknown && V=`cat $@`; then \ + case $$V in *-dirty);; *) V=$$V-dirty;; esac; \ + else \ + V='$(VERSION)'; \ + fi; } && \ + printf '%s\n' "$$V" >$@.out + mv $@.out $@ + +# These files can be tailored by setting BACKWARD, PACKRATDATA, PACKRATLIST. +vanguard.zi main.zi rearguard.zi: $(DSTDATA_ZI_DEPS) + $(AWK) \ + -v DATAFORM=`expr $@ : '\(.*\).zi'` \ + -v PACKRATDATA='$(PACKRATDATA)' \ + -v PACKRATLIST='$(PACKRATLIST)' \ + -f ziguard.awk \ + $(TDATA) $(PACKRATDATA) >$@.out + mv $@.out $@ +# This file has a version comment that attempts to capture any tailoring +# via BACKWARD, DATAFORM, PACKRATDATA, PACKRATLIST, and REDO. +tzdata.zi: $(DATAFORM).zi version zishrink.awk + version=`sed 1q version` && \ + LC_ALL=C $(AWK) \ + -v dataform='$(DATAFORM)' \ + -v deps='$(DSTDATA_ZI_DEPS) zishrink.awk' \ + -v redo='$(REDO)' \ + -v version="$$version" \ + -f zishrink.awk \ + $(DATAFORM).zi >$@.out + mv $@.out $@ + +tzdir.h: + printf '%s\n' >$@.out \ + '#ifndef TZDEFAULT' \ + '# define TZDEFAULT "$(TZDEFAULT)" /* default zone */' \ + '#endif' \ + '#ifndef TZDIR' \ + '# define TZDIR "$(TZDIR)" /* TZif directory */' \ + '#endif' + mv $@.out $@ + +version.h: version + VERSION=`cat version` && printf '%s\n' \ + 'static char const PKGVERSION[]="($(PACKAGE)) ";' \ + "static char const TZVERSION[]=\"$$VERSION\";" \ + 'static char const REPORT_BUGS_TO[]="$(BUGEMAIL)";' \ + >$@.out + mv $@.out $@ + +zdump: $(TZDOBJS) + $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(TZDOBJS) $(LDLIBS) + +zic: $(TZCOBJS) + $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(TZCOBJS) $(LDLIBS) + +leapseconds: $(LEAP_DEPS) + $(AWK) -v EXPIRES_LINE=$(EXPIRES_LINE) \ + -f leapseconds.awk leap-seconds.list >$@.out + mv $@.out $@ + +# Awk script to extract a Git-style author from leap-seconds.list comments. +EXTRACT_AUTHOR = \ + author_line { sub(/^.[[:space:]]*/, ""); \ + sub(/:[[:space:]]*/, " <"); \ + printf "%s>\n", $$0; \ + success = 1; \ + exit \ + } \ + /Questions or comments to:/ { author_line = 1 } \ + END { exit !success } + +# Fetch leap-seconds.list from upstream. +fetch-leap-seconds.list: + $(CURL) -OR $(leaplist_URI) + +# Fetch leap-seconds.list from upstream and commit it to the local repository. +commit-leap-seconds.list: fetch-leap-seconds.list + author=$$($(AWK) '$(EXTRACT_AUTHOR)' leap-seconds.list) && \ + date=$$(TZ=$(leaplist_TZ) stat -c%y leap-seconds.list) && \ + git commit --author="$$author" --date="$$date" -m'make $@' \ + leap-seconds.list + +# Arguments to pass to submakes of install_data. +# They can be overridden by later submake arguments. +INSTALLARGS = \ + BACKWARD='$(BACKWARD)' \ + DESTDIR='$(DESTDIR)' \ + LEAPSECONDS='$(LEAPSECONDS)' \ + PACKRATDATA='$(PACKRATDATA)' \ + PACKRATLIST='$(PACKRATLIST)' \ + TZDEFAULT='$(TZDEFAULT)' \ + TZDIR='$(TZDIR)' \ + ZIC='$(ZIC)' + +INSTALL_DATA_DEPS = zic leapseconds tzdata.zi + +# 'make install_data' installs one set of TZif files. +install_data: $(INSTALL_DATA_DEPS) + $(ZIC_INSTALL) tzdata.zi + +posix_only: $(INSTALL_DATA_DEPS) + $(MAKE) $(INSTALLARGS) LEAPSECONDS= install_data + +right_only: $(INSTALL_DATA_DEPS) + $(MAKE) $(INSTALLARGS) LEAPSECONDS='-L leapseconds' \ + install_data + +# In earlier versions of this makefile, the other two directories were +# subdirectories of $(TZDIR). However, this led to configuration errors. +# For example, with posix_right under the earlier scheme, +# TZ='right/Australia/Adelaide' got you localtime with leap seconds, +# but gmtime without leap seconds, which led to problems with applications +# like sendmail that subtract gmtime from localtime. +# Therefore, the other two directories are now siblings of $(TZDIR). +# You must replace all of $(TZDIR) to switch from not using leap seconds +# to using them, or vice versa. +right_posix: right_only + rm -fr '$(DESTDIR)$(TZDIR)-leaps' + ln -s '$(TZDIR_BASENAME)' '$(DESTDIR)$(TZDIR)-leaps' || \ + $(MAKE) $(INSTALLARGS) TZDIR='$(TZDIR)-leaps' right_only + $(MAKE) $(INSTALLARGS) TZDIR='$(TZDIR)-posix' posix_only + +posix_right: posix_only + rm -fr '$(DESTDIR)$(TZDIR)-posix' + ln -s '$(TZDIR_BASENAME)' '$(DESTDIR)$(TZDIR)-posix' || \ + $(MAKE) $(INSTALLARGS) TZDIR='$(TZDIR)-posix' posix_only + $(MAKE) $(INSTALLARGS) TZDIR='$(TZDIR)-leaps' right_only + +zones: $(REDO) + +# dummy.zd is not a real file; it is mentioned here only so that the +# top-level 'make' does not have a syntax error. +ZDS = dummy.zd +# Rule used only by submakes invoked by the $(TZS_NEW) rule. +# It is separate so that GNU 'make -j' can run instances in parallel. +$(ZDS): zdump + ./zdump -i $(TZS_CUTOFF_FLAG) '$(wd)/'$$(expr $@ : '\(.*\).zd') \ + >$@ + +TZS_NEW_DEPS = tzdata.zi zdump zic +$(TZS_NEW): $(TZS_NEW_DEPS) + rm -fr tzs$(TZS_YEAR).dir + mkdir tzs$(TZS_YEAR).dir + $(zic) -d tzs$(TZS_YEAR).dir tzdata.zi + $(AWK) '/^L/{print "Link\t" $$2 "\t" $$3}' \ + tzdata.zi | LC_ALL=C sort >$@.out + wd=`pwd` && \ + x=`$(AWK) '/^Z/{print "tzs$(TZS_YEAR).dir/" $$2 ".zd"}' \ + tzdata.zi \ + | LC_ALL=C sort -t . -k 2,2` && \ + set x $$x && \ + shift && \ + ZDS=$$* && \ + $(MAKE) wd="$$wd" TZS_CUTOFF_FLAG="$(TZS_CUTOFF_FLAG)" \ + ZDS="$$ZDS" $$ZDS && \ + sed 's,^TZ=".*\.dir/,TZ=",' $$ZDS >>$@.out + rm -fr tzs$(TZS_YEAR).dir + mv $@.out $@ + +# If $(TZS) exists but 'make check_tzs' fails, a maintainer should inspect the +# failed output and fix the inconsistency, perhaps by running 'make force_tzs'. +$(TZS): + touch $@ + +force_tzs: $(TZS_NEW) + cp $(TZS_NEW) $(TZS) + +libtz.a: $(LIBOBJS) + rm -f $@ + $(AR) $(ARFLAGS) $@ $(LIBOBJS) + $(RANLIB) $@ + +date: $(DATEOBJS) + $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(DATEOBJS) $(LDLIBS) + +tzselect: tzselect.ksh version + VERSION=`cat version` && sed \ + -e "s'#!/bin/bash'#!"'$(KSHELL)'\' \ + -e s\''\(AWK\)=[^}]*'\''\1=\'\''$(AWK)\'\'\' \ + -e s\''\(PKGVERSION\)=.*'\''\1=\'\''($(PACKAGE)) \'\'\' \ + -e s\''\(REPORT_BUGS_TO\)=.*'\''\1=\'\''$(BUGEMAIL)\'\'\' \ + -e s\''\(TZDIR\)=[^}]*'\''\1=\'\''$(TZDIR)\'\'\' \ + -e s\''\(TZVERSION\)=.*'\''\1=\'"'$$VERSION\\''" \ + <$@.ksh >$@.out + chmod +x $@.out + mv $@.out $@ + +check: check_back check_mild +check_mild: check_character_set check_white_space check_links \ + check_name_lengths check_now \ + check_slashed_abbrs check_sorted \ + check_tables check_web check_ziguard check_zishrink check_tzs + +# True if UTF8_LOCALE does not work; +# otherwise, false but with LC_ALL set to $(UTF8_LOCALE). +UTF8_LOCALE_MISSING = \ + { test ! '$(UTF8_LOCALE)' \ + || ! printf 'A\304\200B\n' \ + | LC_ALL='$(UTF8_LOCALE)' grep -q '^A.B$$' >/dev/null 2>&1 \ + || { LC_ALL='$(UTF8_LOCALE)'; export LC_ALL; false; }; } + +check_character_set: $(ENCHILADA) + $(UTF8_LOCALE_MISSING) || { \ + sharp='#' && \ + ! grep -Env $(SAFE_LINE) $(MANS) date.1 $(MANTXTS) \ + $(MISC) $(SOURCES) $(WEB_PAGES) \ + CONTRIBUTING LICENSE README SECURITY \ + version tzdata.zi && \ + ! grep -Env $(SAFE_LINE)'|^UNUSUAL_OK_'$(OK_CHAR)'*$$' \ + Makefile && \ + ! grep -Env $(SAFE_SHARP_LINE) $(TDATA_TO_CHECK) backzone \ + leapseconds zone.tab && \ + ! grep -Env $(OK_LINE) $(ENCHILADA); \ + } + touch $@ + +check_white_space: $(ENCHILADA) + $(UTF8_LOCALE_MISSING) || { \ + patfmt=' \t|[\f\r\v]' && pat=`printf "$$patfmt\\n"` && \ + ! grep -En "$$pat|[$s]\$$" \ + $$(ls $(ENCHILADA) | grep -Fvx leap-seconds.list); \ + } + touch $@ + +PRECEDES_FILE_NAME = ^(Zone|Link[$s]+[^$s]+)[$s]+ +FILE_NAME_COMPONENT_TOO_LONG = $(PRECEDES_FILE_NAME)[^$s]*[^/$s]{15} + +check_name_lengths: $(TDATA_TO_CHECK) backzone + ! grep -En '$(FILE_NAME_COMPONENT_TOO_LONG)' \ + $(TDATA_TO_CHECK) backzone + touch $@ + +PRECEDES_STDOFF = ^(Zone[$s]+[^$s]+)?[$s]+ +STDOFF = [-+]?[0-9:.]+ +RULELESS_SAVE = (-|$(STDOFF)[sd]?) +RULELESS_SLASHED_ABBRS = \ + $(PRECEDES_STDOFF)$(STDOFF)[$s]+$(RULELESS_SAVE)[$s]+[^$s]*/ + +check_slashed_abbrs: $(TDATA_TO_CHECK) + ! grep -En '$(RULELESS_SLASHED_ABBRS)' $(TDATA_TO_CHECK) + touch $@ + +CHECK_CC_LIST = { n = split($$1,a,/,/); for (i=2; i<=n; i++) print a[1], a[i]; } + +check_sorted: backward backzone + $(AWK) '/^Link/ {printf "%.5d %s\n", g, $$3} !/./ {g++}' \ + backward | LC_ALL=C sort -cu + $(AWK) '/^Zone/ {print $$2}' backzone | LC_ALL=C sort -cu + touch $@ + +check_back: checklinks.awk $(TDATA_TO_CHECK) + $(AWK) \ + -v DATAFORM=$(DATAFORM) \ + -v backcheck=backward \ + -f checklinks.awk $(TDATA_TO_CHECK) + touch $@ + +check_links: checklinks.awk tzdata.zi + $(AWK) \ + -v DATAFORM=$(DATAFORM) \ + -f checklinks.awk tzdata.zi + touch $@ + +# Check timestamps from now through 28 years from now, to make sure +# that zonenow.tab contains all sequences of planned timestamps, +# without any duplicate sequences. In theory this might require +# 2800 years but that would take a long time to check. +CHECK_NOW_TIMESTAMP = `./date +%s` +CHECK_NOW_FUTURE_YEARS = 28 +CHECK_NOW_FUTURE_SECS = $(CHECK_NOW_FUTURE_YEARS) '*' 366 '*' 24 '*' 60 '*' 60 +check_now: checknow.awk date tzdata.zi zdump zic zone1970.tab zonenow.tab + rm -fr $@.dir + mkdir $@.dir + ./zic -d $@.dir tzdata.zi + now=$(CHECK_NOW_TIMESTAMP) && \ + future=`expr $(CHECK_NOW_FUTURE_SECS) + $$now` && \ + ./zdump -i -t $$now,$$future \ + $$(find $$PWD/$@.dir/????*/ -type f) \ + >$@.dir/zdump.tab + $(AWK) \ + -v zdump_table=$@.dir/zdump.tab \ + -f checknow.awk zonenow.tab + rm -fr $@.dir + touch $@ + +check_tables: checktab.awk $(YDATA) backward zone.tab zone1970.tab + for tab in $(ZONETABLES); do \ + test "$$tab" = zone.tab && links='$(BACKWARD)' || links=''; \ + $(AWK) -f checktab.awk -v zone_table=$$tab $(YDATA) $$links \ + || exit; \ + done + touch $@ + +check_tzs: $(TZS) $(TZS_NEW) + if test -s $(TZS); then \ + $(DIFF_TZS) $(TZS) $(TZS_NEW); \ + else \ + cp $(TZS_NEW) $(TZS); \ + fi + touch $@ + +check_web: $(CHECK_WEB_PAGES) +check_theory.html: theory.html +check_tz-art.html: tz-art.html +check_tz-how-to.html: tz-how-to.html +check_tz-link.html: tz-link.html +check_theory.html check_tz-art.html check_tz-how-to.html check_tz-link.html: + $(CURL) -sS --url https://validator.w3.org/nu/ -F out=gnu \ + -F file=@$$(expr $@ : 'check_\(.*\)') -o $@.out && \ + test ! -s $@.out || { cat $@.out; exit 1; } + mv $@.out $@ + +check_ziguard: rearguard.zi vanguard.zi ziguard.awk + $(AWK) -v DATAFORM=rearguard -f ziguard.awk vanguard.zi | \ + diff -u rearguard.zi - + $(AWK) -v DATAFORM=vanguard -f ziguard.awk rearguard.zi | \ + diff -u vanguard.zi - + touch $@ + +# Check that zishrink.awk does not alter the data, and that ziguard.awk +# preserves main-format data. +check_zishrink: check_zishrink_posix check_zishrink_right +check_zishrink_posix check_zishrink_right: \ + zic leapseconds $(PACKRATDATA) $(PACKRATLIST) \ + $(TDATA) $(DATAFORM).zi tzdata.zi + rm -fr $@.dir $@-t.dir $@-shrunk.dir + mkdir $@.dir $@-t.dir $@-shrunk.dir + case $@ in \ + *_right) leap='-L leapseconds';; \ + *) leap=;; \ + esac && \ + $(ZIC) $$leap -d $@.dir $(DATAFORM).zi && \ + $(ZIC) $$leap -d $@-shrunk.dir tzdata.zi && \ + case $(DATAFORM),$(PACKRATLIST) in \ + main,) \ + $(ZIC) $$leap -d $@-t.dir $(TDATA) && \ + $(AWK) '/^Rule/' $(TDATA) | \ + $(ZIC) $$leap -d $@-t.dir - $(PACKRATDATA) && \ + diff -r $@.dir $@-t.dir;; \ + esac + diff -r $@.dir $@-shrunk.dir + rm -fr $@.dir $@-t.dir $@-shrunk.dir + touch $@ + +clean_misc: + rm -fr check_*.dir typecheck_*.dir + rm -f *.o *.out $(TIME_T_ALTERNATIVES) \ + check_* core typecheck_* \ + date tzdir.h tzselect version.h zdump zic libtz.a +clean: clean_misc + rm -fr *.dir tzdb-*/ + rm -f *.zi $(TZS_NEW) + +maintainer-clean: clean + @echo 'This command is intended for maintainers to use; it' + @echo 'deletes files that may need special tools to rebuild.' + rm -f leapseconds version $(MANTXTS) $(TZS) *.asc *.tar.* + +names: + @echo $(ENCHILADA) + +public: check check_public $(CHECK_TIME_T_ALTERNATIVES) \ + tarballs signatures + +date.1.txt: date.1 +newctime.3.txt: newctime.3 +newstrftime.3.txt: newstrftime.3 +newtzset.3.txt: newtzset.3 +time2posix.3.txt: time2posix.3 +tzfile.5.txt: tzfile.5 +tzselect.8.txt: tzselect.8 +zdump.8.txt: zdump.8 +zic.8.txt: zic.8 + +$(MANTXTS): workman.sh + LC_ALL=C sh workman.sh `expr $@ : '\(.*\)\.txt$$'` >$@.out + mv $@.out $@ + +# Set file timestamps deterministically if possible, +# so that tarballs containing the timestamps are reproducible. +# +# '$(SET_TIMESTAMP_N) N DEST A B C ...' sets the timestamp of the +# file DEST to the maximum of the timestamps of the files A B C ..., +# plus N if GNU ls and touch are available. +SET_TIMESTAMP_N = sh -c '\ + n=$$0 dest=$$1; shift; \ + <"$$dest" && \ + if test $$n != 0 && \ + lsout=`ls -nt --time-style="+%s" "$$@" 2>/dev/null`; then \ + set x $$lsout && \ + timestamp=`expr $$7 + $$n` && \ + echo "+ touch -md @$$timestamp $$dest" && \ + touch -md @$$timestamp "$$dest"; \ + else \ + newest=`ls -t "$$@" | sed 1q` && \ + echo "+ touch -mr $$newest $$dest" && \ + touch -mr "$$newest" "$$dest"; \ + fi' +# If DEST depends on A B C ... in this Makefile, callers should use +# $(SET_TIMESTAMP_DEP) DEST A B C ..., for the benefit of any +# downstream 'make' that considers equal timestamps to be out of date. +# POSIX allows this 'make' behavior, and HP-UX 'make' does it. +# If all that matters is that the timestamp be reproducible +# and plausible, use $(SET_TIMESTAMP). +SET_TIMESTAMP = $(SET_TIMESTAMP_N) 0 +SET_TIMESTAMP_DEP = $(SET_TIMESTAMP_N) 1 + +# Set the timestamps to those of the git repository, if available, +# and if the files have not changed since then. +# This uses GNU 'ls --time-style=+%s', which outputs the seconds count, +# and GNU 'touch -d@N FILE', where N is the number of seconds since 1970. +# If git or GNU is absent, don't bother to sync with git timestamps. +# Also, set the timestamp of each prebuilt file like 'leapseconds' +# to be the maximum of the files it depends on. +set-timestamps.out: $(EIGHT_YARDS) + rm -f $@ + if (type git) >/dev/null 2>&1 && \ + files=`git ls-files $(EIGHT_YARDS)` && \ + touch -md @1 test.out; then \ + rm -f test.out && \ + for file in $$files; do \ + if git diff --quiet $$file; then \ + time=`TZ=UTC0 git log -1 \ + --format='tformat:%cd' \ + --date='format:%Y-%m-%dT%H:%M:%SZ' \ + $$file` && \ + echo "+ touch -md $$time $$file" && \ + touch -md $$time $$file; \ + else \ + echo >&2 "$$file: warning: does not match repository"; \ + fi || exit; \ + done; \ + fi + $(SET_TIMESTAMP_DEP) leapseconds $(LEAP_DEPS) + for file in `ls $(MANTXTS) | sed 's/\.txt$$//'`; do \ + $(SET_TIMESTAMP_DEP) $$file.txt $$file workman.sh || \ + exit; \ + done + $(SET_TIMESTAMP_DEP) version $(VERSION_DEPS) + $(SET_TIMESTAMP_DEP) tzdata.zi $(TZDATA_ZI_DEPS) + touch $@ +set-tzs-timestamp.out: $(TZS) + $(SET_TIMESTAMP_DEP) $(TZS) $(TZS_DEPS) + touch $@ + +# The zics below ensure that each data file can stand on its own. +# We also do an all-files run to catch links to links. + +check_public: $(VERSION_DEPS) + rm -fr public.dir + mkdir public.dir + ln $(VERSION_DEPS) public.dir + cd public.dir \ + && $(MAKE) CFLAGS='$(GCC_DEBUG_FLAGS)' TZDIR='$(TZDIR)' ALL + for i in $(TDATA_TO_CHECK) public.dir/tzdata.zi \ + public.dir/vanguard.zi public.dir/main.zi \ + public.dir/rearguard.zi; \ + do \ + public.dir/zic -v -d public.dir/zoneinfo $$i 2>&1 || exit; \ + done + public.dir/zic -v -d public.dir/zoneinfo-all $(TDATA_TO_CHECK) + : + : Also check 'backzone' syntax. + rm public.dir/main.zi + cd public.dir && $(MAKE) PACKRATDATA=backzone main.zi + public.dir/zic -d public.dir/zoneinfo main.zi + rm public.dir/main.zi + cd public.dir && \ + $(MAKE) PACKRATDATA=backzone PACKRATLIST=zone.tab main.zi + public.dir/zic -d public.dir/zoneinfo main.zi + : + rm -fr public.dir + touch $@ + +# Check that the code works under various alternative +# implementations of time_t. +check_time_t_alternatives: $(TIME_T_ALTERNATIVES) +$(TIME_T_ALTERNATIVES_TAIL): $(TIME_T_ALTERNATIVES_HEAD) +$(TIME_T_ALTERNATIVES): $(VERSION_DEPS) + rm -fr $@.dir + mkdir $@.dir + ln $(VERSION_DEPS) $@.dir + case $@ in \ + int*32_t) range=-2147483648,2147483648;; \ + u*) range=0,4294967296;; \ + *) range=-4294967296,4294967296;; \ + esac && \ + wd=`pwd` && \ + zones=`$(AWK) '/^[^#]/ { print $$3 }' /dev/null; then \ + quiet_option='-q'; \ + else \ + quiet_option=''; \ + fi && \ + diff $$quiet_option -r $(TIME_T_ALTERNATIVES_HEAD).dir/etc \ + $@.dir/etc && \ + diff $$quiet_option -r \ + $(TIME_T_ALTERNATIVES_HEAD).dir/usr/share \ + $@.dir/usr/share; \ + } + touch $@ + +TRADITIONAL_ASC = \ + tzcode$(VERSION).tar.gz.asc \ + tzdata$(VERSION).tar.gz.asc +REARGUARD_ASC = \ + tzdata$(VERSION)-rearguard.tar.gz.asc +ALL_ASC = $(TRADITIONAL_ASC) $(REARGUARD_ASC) \ + tzdb-$(VERSION).tar.lz.asc + +tarballs rearguard_tarballs tailored_tarballs traditional_tarballs \ +signatures rearguard_signatures traditional_signatures: \ + version set-timestamps.out rearguard.zi vanguard.zi + VERSION=`cat version` && \ + $(MAKE) AWK='$(AWK)' VERSION="$$VERSION" $@_version + +# These *_version rules are intended for use if VERSION is set by some +# other means. Ordinarily these rules are used only by the above +# non-_version rules, which set VERSION on the 'make' command line. +tarballs_version: traditional_tarballs_version rearguard_tarballs_version \ + tzdb-$(VERSION).tar.lz +rearguard_tarballs_version: \ + tzdata$(VERSION)-rearguard.tar.gz +traditional_tarballs_version: \ + tzcode$(VERSION).tar.gz tzdata$(VERSION).tar.gz +tailored_tarballs_version: \ + tzdata$(VERSION)-tailored.tar.gz +signatures_version: $(ALL_ASC) +rearguard_signatures_version: $(REARGUARD_ASC) +traditional_signatures_version: $(TRADITIONAL_ASC) + +tzcode$(VERSION).tar.gz: set-timestamps.out + LC_ALL=C && export LC_ALL && \ + tar $(TARFLAGS) -cf - \ + $(COMMON) $(DOCS) $(SOURCES) | \ + gzip $(GZIPFLAGS) >$@.out + mv $@.out $@ + +tzdata$(VERSION).tar.gz: set-timestamps.out + LC_ALL=C && export LC_ALL && \ + tar $(TARFLAGS) -cf - $(TZDATA_DIST) | \ + gzip $(GZIPFLAGS) >$@.out + mv $@.out $@ + +# Create empty files with a reproducible timestamp. +CREATE_EMPTY = TZ=UTC0 touch -mt 202010122253.00 + +# The obsolescent *rearguard* targets and related macros are present +# for backwards compatibility with tz releases 2018e through 2022a. +# They should go away eventually. To build rearguard tarballs you +# can instead use 'make DATAFORM=rearguard tailored_tarballs'. +tzdata$(VERSION)-rearguard.tar.gz: rearguard.zi set-timestamps.out + rm -fr $@.dir + mkdir $@.dir + ln $(TZDATA_DIST) $@.dir + cd $@.dir && rm -f $(TDATA) $(PACKRATDATA) version + for f in $(TDATA) $(PACKRATDATA); do \ + rearf=$@.dir/$$f; \ + $(AWK) -v DATAFORM=rearguard -f ziguard.awk $$f >$$rearf && \ + $(SET_TIMESTAMP_DEP) $$rearf ziguard.awk $$f || exit; \ + done + sed '1s/$$/-rearguard/' $@.dir/version + : The dummy pacificnew pacifies TZUpdater 2.3.1 and earlier. + $(CREATE_EMPTY) $@.dir/pacificnew + touch -mr version $@.dir/version + LC_ALL=C && export LC_ALL && \ + (cd $@.dir && \ + tar $(TARFLAGS) -cf - \ + $(TZDATA_DIST) pacificnew | \ + gzip $(GZIPFLAGS)) >$@.out + mv $@.out $@ + +# Create a tailored tarball suitable for TZUpdater and compatible tools. +# For example, 'make DATAFORM=vanguard tailored_tarballs' makes a tarball +# useful for testing whether TZUpdater supports vanguard form. +# The generated tarball is not byte-for-byte equivalent to a hand-tailored +# traditional tarball, as data entries are put into 'etcetera' even if they +# came from some other source file. However, the effect should be the same +# for ordinary use, which reads all the source files. +tzdata$(VERSION)-tailored.tar.gz: set-timestamps.out + rm -fr $@.dir + mkdir $@.dir + : The dummy pacificnew pacifies TZUpdater 2.3.1 and earlier. + cd $@.dir && \ + $(CREATE_EMPTY) $(PRIMARY_YDATA) $(NDATA) backward \ + `test $(DATAFORM) = vanguard || echo pacificnew` + (grep '^#' tzdata.zi && echo && cat $(DATAFORM).zi) \ + >$@.dir/etcetera + touch -mr tzdata.zi $@.dir/etcetera + sed -n \ + -e '/^# *version *\(.*\)/h' \ + -e '/^# *ddeps */H' \ + -e '$$!d' \ + -e 'g' \ + -e 's/^# *version *//' \ + -e 's/\n# *ddeps */-/' \ + -e 's/ /-/g' \ + -e 'p' \ + $@.dir/version + touch -mr version $@.dir/version + links= && \ + for file in $(TZDATA_DIST); do \ + test -f $@.dir/$$file || links="$$links $$file"; \ + done && \ + ln $$links $@.dir + LC_ALL=C && export LC_ALL && \ + (cd $@.dir && \ + tar $(TARFLAGS) -cf - * | gzip $(GZIPFLAGS)) >$@.out + mv $@.out $@ + +tzdb-$(VERSION).tar.lz: set-timestamps.out set-tzs-timestamp.out + rm -fr tzdb-$(VERSION) + mkdir tzdb-$(VERSION) + ln $(ENCHILADA) tzdb-$(VERSION) + $(SET_TIMESTAMP) tzdb-$(VERSION) tzdb-$(VERSION)/* + LC_ALL=C && export LC_ALL && \ + tar $(TARFLAGS) -cf - tzdb-$(VERSION) | lzip -9 >$@.out + mv $@.out $@ + +tzcode$(VERSION).tar.gz.asc: tzcode$(VERSION).tar.gz +tzdata$(VERSION).tar.gz.asc: tzdata$(VERSION).tar.gz +tzdata$(VERSION)-rearguard.tar.gz.asc: tzdata$(VERSION)-rearguard.tar.gz +tzdb-$(VERSION).tar.lz.asc: tzdb-$(VERSION).tar.lz +$(ALL_ASC): + $(GPG) --armor --detach-sign $? + +TYPECHECK_CFLAGS = $(CFLAGS) -DTYPECHECK -D__time_t_defined -D_TIME_T +typecheck: typecheck_long_long typecheck_unsigned +typecheck_long_long typecheck_unsigned: $(VERSION_DEPS) + rm -fr $@.dir + mkdir $@.dir + ln $(VERSION_DEPS) $@.dir + cd $@.dir && \ + case $@ in \ + *_long_long) i="long long";; \ + *_unsigned ) i="unsigned" ;; \ + esac && \ + typecheck_cflags='' && \ + $(MAKE) \ + CFLAGS="$(TYPECHECK_CFLAGS) \"-Dtime_t=$$i\"" \ + TOPDIR="`pwd`" \ + install + $@.dir/zdump -i -c 1970,1971 Europe/Rome + touch $@ + +zonenames: tzdata.zi + @$(AWK) '/^Z/ { print $$2 } /^L/ { print $$3 }' tzdata.zi + +asctime.o: private.h tzfile.h +date.o: private.h +difftime.o: private.h +localtime.o: private.h tzfile.h tzdir.h +strftime.o: private.h tzfile.h +zdump.o: version.h +zic.o: private.h tzfile.h tzdir.h version.h + +.PHONY: ALL INSTALL all +.PHONY: check check_mild check_time_t_alternatives +.PHONY: check_web check_zishrink +.PHONY: clean clean_misc commit-leap-seconds.list dummy.zd +.PHONY: fetch-leap-seconds.list force_tzs +.PHONY: install install_data maintainer-clean names +.PHONY: posix_only posix_right public +.PHONY: rearguard_signatures rearguard_signatures_version +.PHONY: rearguard_tarballs rearguard_tarballs_version +.PHONY: right_only right_posix signatures signatures_version +.PHONY: tarballs tarballs_version +.PHONY: traditional_signatures traditional_signatures_version +.PHONY: traditional_tarballs traditional_tarballs_version +.PHONY: tailored_tarballs tailored_tarballs_version +.PHONY: typecheck +.PHONY: zonenames zones +.PHONY: $(ZDS) diff --git a/vendor/chrono-tz/tz/README b/vendor/chrono-tz/tz/README new file mode 100644 index 0000000000000..edabd2e0690f8 --- /dev/null +++ b/vendor/chrono-tz/tz/README @@ -0,0 +1,55 @@ +README for the tz distribution + +"Where do I set the hands of the clock?" -- Les Tremayne as The King +"Oh that--you can set them any place you want." -- Frank Baxter as The Scientist + (from the Bell System film "About Time") + +The Time Zone Database (called tz, tzdb or zoneinfo) contains code and +data that represent the history of local time for many representative +locations around the globe. It is updated periodically to reflect +changes made by political bodies to time zone boundaries, UTC offsets, +and daylight-saving rules. + +See or the +file tz-link.html for how to acquire the code and data. + +Once acquired, read the leading comments in the file "Makefile" +and make any changes needed to make things right for your system, +especially when using a platform other than current GNU/Linux. + +Then run the following commands, substituting your desired +installation directory for "$HOME/tzdir": + + make TOPDIR="$HOME/tzdir" install + "$HOME/tzdir/usr/bin/zdump" -v America/Los_Angeles + +See the file tz-how-to.html for examples of how to read the data files. + +This database of historical local time information has several goals: + + * Provide a compendium of data about the history of civil time that + is useful even if not 100% accurate. + + * Give an idea of the variety of local time rules that have existed + in the past and thus may be expected in the future. + + * Test the generality of the local time rule description system. + +The information in the time zone data files is by no means authoritative; +fixes and enhancements are welcome. Please see the file CONTRIBUTING +for details. + +Thanks to these Time Zone Caballeros who've made major contributions to the +time conversion package: Keith Bostic; Bob Devine; Paul Eggert; Robert Elz; +Guy Harris; Mark Horton; John Mackin; and Bradley White. Thanks also to +Michael Bloom, Art Neilson, Stephen Prince, John Sovereign, and Frank Wales +for testing work, and to Gwillim Law for checking local mean time data. +Thanks in particular to Arthur David Olson, the project's founder and first +maintainer, to whom the time zone community owes the greatest debt of all. +None of them are responsible for remaining errors. + +----- + +This file is in the public domain, so clarified as of 2009-05-17 by +Arthur David Olson. The other files in this distribution are either +public domain or BSD licensed; see the file LICENSE for details. diff --git a/vendor/chrono-tz/tz/SECURITY b/vendor/chrono-tz/tz/SECURITY new file mode 100644 index 0000000000000..40128bc86dd2a --- /dev/null +++ b/vendor/chrono-tz/tz/SECURITY @@ -0,0 +1,15 @@ +Please report any sensitive security-related bugs via email to the +tzdb designated coordinators, currently Paul Eggert + and Tim Parenti . +Put "tzdb security" at the start of your email's subject line. +We prefer communications to be in English. + +You should receive a response within a week. If not, please follow up +via email to make sure we received your original message. + +If we confirm the bug, we plan to notify affected third-party services +or software that we know about, prepare an advisory, commit fixes to +the main development branch as quickly as is practical, and finally +publish the advisory on tz@iana.org. As with all tzdb contributions, +we give credit to security contributors unless they wish to remain +anonymous. diff --git a/vendor/chrono-tz/tz/asctime.c b/vendor/chrono-tz/tz/asctime.c new file mode 100644 index 0000000000000..a40661f289763 --- /dev/null +++ b/vendor/chrono-tz/tz/asctime.c @@ -0,0 +1,131 @@ +/* asctime and asctime_r a la POSIX and ISO C, except pad years before 1000. */ + +/* +** This file is in the public domain, so clarified as of +** 1996-06-05 by Arthur David Olson. +*/ + +/* +** Avoid the temptation to punt entirely to strftime; +** the output of strftime is supposed to be locale specific +** whereas the output of asctime is supposed to be constant. +*/ + +/*LINTLIBRARY*/ + +#include "private.h" +#include + +/* +** All years associated with 32-bit time_t values are exactly four digits long; +** some years associated with 64-bit time_t values are not. +** Vintage programs are coded for years that are always four digits long +** and may assume that the newline always lands in the same place. +** For years that are less than four digits, we pad the output with +** leading zeroes to get the newline in the traditional place. +** The -4 ensures that we get four characters of output even if +** we call a strftime variant that produces fewer characters for some years. +** The ISO C and POSIX standards prohibit padding the year, +** but many implementations pad anyway; most likely the standards are buggy. +*/ +static char const ASCTIME_FMT[] = "%s %s%3d %.2d:%.2d:%.2d %-4s\n"; +/* +** For years that are more than four digits we put extra spaces before the year +** so that code trying to overwrite the newline won't end up overwriting +** a digit within a year and truncating the year (operating on the assumption +** that no output is better than wrong output). +*/ +static char const ASCTIME_FMT_B[] = "%s %s%3d %.2d:%.2d:%.2d %s\n"; + +enum { STD_ASCTIME_BUF_SIZE = 26 }; +/* +** Big enough for something such as +** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n +** (two three-character abbreviations, five strings denoting integers, +** seven explicit spaces, two explicit colons, a newline, +** and a trailing NUL byte). +** The values above are for systems where an int is 32 bits and are provided +** as an example; the size expression below is a bound for the system at +** hand. +*/ +static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1]; + +/* A similar buffer for ctime. + C89 requires that they be the same buffer. + This requirement was removed in C99, so support it only if requested, + as support is more likely to lead to bugs in badly written programs. */ +#if SUPPORT_C89 +# define buf_ctime buf_asctime +#else +static char buf_ctime[sizeof buf_asctime]; +#endif + +char * +asctime_r(struct tm const *restrict timeptr, char *restrict buf) +{ + static const char wday_name[][4] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static const char mon_name[][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + register const char * wn; + register const char * mn; + char year[INT_STRLEN_MAXIMUM(int) + 2]; + char result[sizeof buf_asctime]; + + if (timeptr == NULL) { + errno = EINVAL; + return strcpy(buf, "??? ??? ?? ??:??:?? ????\n"); + } + if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK) + wn = "???"; + else wn = wday_name[timeptr->tm_wday]; + if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR) + mn = "???"; + else mn = mon_name[timeptr->tm_mon]; + /* + ** Use strftime's %Y to generate the year, to avoid overflow problems + ** when computing timeptr->tm_year + TM_YEAR_BASE. + ** Assume that strftime is unaffected by other out-of-range members + ** (e.g., timeptr->tm_mday) when processing "%Y". + */ + strftime(year, sizeof year, "%Y", timeptr); + /* + ** We avoid using snprintf since it's not available on all systems. + */ + sprintf(result, + ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B), + wn, mn, + timeptr->tm_mday, timeptr->tm_hour, + timeptr->tm_min, timeptr->tm_sec, + year); + if (strlen(result) < STD_ASCTIME_BUF_SIZE + || buf == buf_ctime || buf == buf_asctime) + return strcpy(buf, result); + else { + errno = EOVERFLOW; + return NULL; + } +} + +char * +asctime(register const struct tm *timeptr) +{ + return asctime_r(timeptr, buf_asctime); +} + +char * +ctime_r(const time_t *timep, char *buf) +{ + struct tm mytm; + struct tm *tmp = localtime_r(timep, &mytm); + return tmp ? asctime_r(tmp, buf) : NULL; +} + +char * +ctime(const time_t *timep) +{ + return ctime_r(timep, buf_ctime); +} diff --git a/vendor/chrono-tz/tz/backzone b/vendor/chrono-tz/tz/backzone new file mode 100644 index 0000000000000..f45250340493b --- /dev/null +++ b/vendor/chrono-tz/tz/backzone @@ -0,0 +1,1834 @@ +# Zones that go back beyond the scope of the tz database + +# This file is in the public domain. + +# This file is by no means authoritative; if you think you know +# better, go ahead and edit it (and please send any changes to +# tz@iana.org for general use in the future). For more, please see +# the file CONTRIBUTING in the tz distribution. + +# When proposing changes to this file, please use 'git format-patch' +# format, either by attaching the resulting .patch file to your email, +# or by using 'git send-email'. This will help maintainers save time. + + +# From Paul Eggert (2014-10-31): + +# This file contains data outside the normal scope of the tz database, +# in that its zones do not differ from normal tz zones after 1970. +# Links in this file point to zones in this file, superseding links in +# the file 'backward'. + +# Although zones in this file may be of some use for analyzing +# pre-1970 timestamps, they are less reliable, cover only a tiny +# sliver of the pre-1970 era, and cannot feasibly be improved to cover +# most of the era. Because the zones are out of normal scope for the +# database, less effort is put into maintaining this file. Many of +# the zones were formerly in other source files, but were removed or +# replaced by links as their data entries were questionable and/or they +# differed from other zones only in pre-1970 timestamps. + +# Unless otherwise specified, the source for data through 1990 is: +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition), +# San Diego: ACS Publications, Inc. (2003). +# Unfortunately this book contains many errors and cites no sources. + +# This file is not intended to be compiled standalone, as it +# assumes rules from other files. In the tz distribution, use +# 'make PACKRATDATA=backzone zones' to compile and install this file. + + +# From Paul Eggert (2020-04-15): +# The following remarks should be incorporated into this table sometime. +# Patches in 'git format-patch' format would be welcome. +# +# From Phake Nick (2020-04-15): +# ... the historical timezone data for those China zones seems to be +# incorrect. The transition to GMT+8 date given there for these zones +# were 1980 which also contradict the file description that they do +# not disagree with normal zone after 1970. According to sources that +# have also been cited in the asia file, except Xinjiang and Tibet, +# they should have adopted the Beijing Time from around 1949/1950 +# depends on exactly when each of those cities were taken over by the +# communist army. And they should also follow the DST setting of +# Asia/Shanghai after that point of time. In addition, +# http://gaz.ncl.edu.tw/detail.jsp?sysid=E1091792 the document from +# Chongqing Nationalist government say in year 1945 all of China +# should adopt summer time due to the war (not sure whether it +# continued after WWII ends)(Probably only enforced in area under +# their rule at the time?) The Asia/Harbin's 1932 and 1940 entry +# should also be incorrect. As per sources recorded at +# https://wiki.suikawiki.org/n/%E6%BA%80%E5%B7%9E%E5%9B%BD%E3%81%AE%E6%A8%99%E6%BA%96%E6%99%82 +# , in 1932 Harbin should have adopted UTC+8:00 instead of data +# currently listed in the tz database according to official +# announcement from Manchuko. And they should have adopted GMT+9 in +# 1937 January 1st according to official announcement at the time +# being cited on the webpage. + + +# Zones are sorted by zone name. Each zone is preceded by the +# name of the country that the zone is in, along with any other +# commentary and rules associated with the entry. +# If the zone overrides links in the main data, it +# is followed by the corresponding Link lines. +# If the zone overrides main-data links only when building with +# PACKRATLIST=zone.tab, it is followed by a commented-out Link line +# that starts with "#PACKRATLIST zone.tab". +# +# As explained in the zic man page, the zone columns are: +# Zone NAME STDOFF RULES FORMAT [UNTIL] +# and the rule columns are: +# Rule NAME FROM TO - IN ON AT SAVE LETTER/S + + +# Ghana + +# From P Chan (2020-11-20): +# Interpretation Amendment Ordinance, 1915 (No.24 of 1915) [1915-11-02] +# Ordinances of the Gold Coast, Ashanti, Northern Territories 1915, p 69-71 +# https://books.google.com/books?id=ErA-AQAAIAAJ&pg=PA70 +# This Ordinance added "'Time' shall mean Greenwich Mean Time" to the +# Interpretation Ordinance, 1876. +# +# Determination of the Time Ordinance, 1919 (No. 18 of 1919) [1919-11-24] +# Ordinances of the Gold Coast, Ashanti, Northern Territories 1919, p 75-76 +# https://books.google.com/books?id=MbA-AQAAIAAJ&pg=PA75 +# This Ordinance removed the previous definition of time and introduced DST. +# +# Time Determination Ordinance (Cap. 214) +# The Laws of the Gold Coast (including Togoland Under British Mandate) +# Vol. II (1937), p 2328 +# https://books.google.com/books?id=Z7M-AQAAIAAJ&pg=PA2328 +# Revised edition of the 1919 Ordinance. +# +# Time Determination (Amendment) Ordinance, 1940 (No. 9 of 1940) [1940-04-06] +# Annual Volume of the Laws of the Gold Coast: +# Containing All Legislation Enacted During Year 1940, p 22 +# https://books.google.com/books?id=1ao-AQAAIAAJ&pg=PA22 +# This Ordinance changed the forward transition from September to May. +# +# Defence (Time Determination Ordinance Amendment) Regulations, 1942 +# (Regulations No. 6 of 1942) [1942-01-31, commenced on 1942-02-08] +# Annual Volume of the Laws of the Gold Coast: +# Containing All Legislation Enacted During Year 1942, p 48 +# https://books.google.com/books?id=Das-AQAAIAAJ&pg=PA48 +# These regulations advanced the [standard] time by thirty minutes. +# +# Defence (Time Determination Ordinance Amendment (No.2)) Regulations, +# 1942 (Regulations No. 28 of 1942) [1942-04-25] +# Annual Volume of the Laws of the Gold Coast: +# Containing All Legislation Enacted During Year 1942, p 87 +# https://books.google.com/books?id=Das-AQAAIAAJ&pg=PA87 +# These regulations abolished DST and changed the time to GMT+0:30. +# +# Defence (Revocation) (No.4) Regulations, 1945 (Regulations No. 45 of +# 1945) [1945-10-24, commenced on 1946-01-06] +# Annual Volume of the Laws of the Gold Coast: +# Containing All Legislation Enacted During Year 1945, p 256 +# https://books.google.com/books?id=9as-AQAAIAAJ&pg=PA256 +# These regulations revoked the previous two sets of Regulations. +# +# Time Determination (Amendment) Ordinance, 1945 (No. 18 of 1945) [1946-01-06] +# Annual Volume of the Laws of the Gold Coast: +# Containing All Legislation Enacted During Year 1945, p 69 +# https://books.google.com/books?id=9as-AQAAIAAJ&pg=PA69 +# This Ordinance abolished DST. +# +# Time Determination (Amendment) Ordinance, 1950 (No. 26 of 1950) [1950-07-22] +# Annual Volume of the Laws of the Gold Coast: +# Containing All Legislation Enacted During Year 1950, p 35 +# https://books.google.com/books?id=e60-AQAAIAAJ&pg=PA35 +# This Ordinance restored DST but with thirty minutes offset. +# +# Time Determination Ordinance (Cap. 264) +# The Laws of the Gold Coast, Vol. V (1954), p 380 +# https://books.google.com/books?id=Mqc-AQAAIAAJ&pg=PA380 +# Revised edition of the Time Determination Ordinance. +# +# Time Determination (Amendment) Ordinance, 1956 (No. 21 of 1956) [1956-08-29] +# Annual Volume of the Ordinances of the Gold Coast Enacted During the +# Year 1956, p 83 +# https://books.google.com/books?id=VLE-AQAAIAAJ&pg=PA83 +# This Ordinance abolished DST. + +Rule Ghana 1919 only - Nov 24 0:00 0:20 +0020 +Rule Ghana 1920 1942 - Jan 1 2:00 0 GMT +Rule Ghana 1920 1939 - Sep 1 2:00 0:20 +0020 +Rule Ghana 1940 1941 - May 1 2:00 0:20 +0020 +Rule Ghana 1950 1955 - Sep 1 2:00 0:30 +0030 +Rule Ghana 1951 1956 - Jan 1 2:00 0 GMT + +Zone Africa/Accra -0:00:52 - LMT 1915 Nov 2 + 0:00 Ghana %s 1942 Feb 8 + 0:30 - +0030 1946 Jan 6 + 0:00 Ghana %s + +# Ethiopia +# From Paul Eggert (2014-07-31): +# Like the Swahili of Kenya and Tanzania, many Ethiopians keep a +# 12-hour clock starting at our 06:00, so their "8 o'clock" is our +# 02:00 or 14:00. Keep this in mind when you ask the time in Amharic. +# +# Shanks & Pottenger write that Ethiopia had six narrowly spaced time +# zones between 1870 and 1890, that they merged to 38E50 (2:35:20) in +# 1890, and that they switched to 3:00 on 1936-05-05. Perhaps 38E50 +# was for Adis Dera. Quite likely the Shanks data entries are wrong +# anyway. +Zone Africa/Addis_Ababa 2:34:48 - LMT 1870 + 2:35:20 - ADMT 1936 May 5 # Adis Dera MT + 3:00 - EAT + +# Eritrea +Zone Africa/Asmara 2:35:32 - LMT 1870 + 2:35:32 - AMT 1890 # Asmara Mean Time + 2:35:20 - ADMT 1936 May 5 # Adis Dera MT + 3:00 - EAT +Link Africa/Asmara Africa/Asmera + +# Mali (southern) +Zone Africa/Bamako -0:32:00 - LMT 1912 + 0:00 - GMT 1934 Feb 26 + -1:00 - -01 1960 Jun 20 + 0:00 - GMT +#PACKRATLIST zone.tab Link Africa/Bamako Africa/Timbuktu + +# Central African Republic +Zone Africa/Bangui 1:14:20 - LMT 1912 + 1:00 - WAT + +# The Gambia +# From P Chan (2020-12-09): +# Standard time of GMT-1 was adopted on 1933-04-01. On 1942-02-01, GMT was +# adopted as a war time measure. This was made permanent in 1946. +# +# Interpretation Ordinance, 1914 (No. 12 of 1914) [1914-09-29] +# Interpretation Ordinance, 1933 (No. 10 of 1933) [1933-03-31] +# Notice No. 5 of 1942, Colony of the Gambia Government Gazette, Vol. LIX, +# No.2, 1942-01-15, p 2 +# Interpretation (Amendment) Ordinance, 1946 (No. 3 of 1946) [1946-07-15] +Zone Africa/Banjul -1:06:36 - LMT 1912 + -1:06:36 - BMT 1933 Apr 1 # Banjul Mean Time + -1:00 - -01 1942 Feb 1 0:00 + 0:00 - GMT + +# Malawi +# From P Chan (2020-12-09): +# In 1911, Zomba mean time was adopted as the legal time of Nyasaland. In +# 1914, Zomba mean time switched from GMT+2:21:10 to GMT+2:21. On 1925-07-01, +# GMT+2 was adopted. +# +# Interpretation and General Clauses Ordinance, 1911 (No. 12 of 1911) +# [1911-07-24] +# Notice No. 124 of 1914, 1914-06-30, The Nyasaland Government Gazette, Vol. +# XXI, No. 8, 1914-06-30, p 122 +# Interpretation and General Clauses (Amendment) Ordinance, 1925 (No. 3 of +# 1925) [1925-04-02] +Zone Africa/Blantyre 2:20:00 - LMT 1911 Jul 24 + 2:21:10 - ZMT 1914 Jun 30 # Zomba Mean Time + 2:21 - ZMT 1925 Jul 1 + 2:00 - CAT + +# Republic of the Congo +Zone Africa/Brazzaville 1:01:08 - LMT 1912 + 1:00 - WAT + +# Burundi +Zone Africa/Bujumbura 1:57:28 - LMT 1890 + 2:00 - CAT + +# Guinea +Zone Africa/Conakry -0:54:52 - LMT 1912 + 0:00 - GMT 1934 Feb 26 + -1:00 - -01 1960 + 0:00 - GMT + +# Senegal +Zone Africa/Dakar -1:09:44 - LMT 1912 + -1:00 - -01 1941 Jun + 0:00 - GMT + +# Tanzania +Zone Africa/Dar_es_Salaam 2:37:08 - LMT 1931 + 3:00 - EAT 1948 + 2:45 - +0245 1961 + 3:00 - EAT + +# Djibouti +Zone Africa/Djibouti 2:52:36 - LMT 1911 Jul + 3:00 - EAT + +# Cameroon +# Whitman says they switched to 1:00 in 1920; go with Shanks & Pottenger. +Zone Africa/Douala 0:38:48 - LMT 1912 + 1:00 - WAT +# Sierra Leone +# From P Chan (2020-12-09): +# Standard time of GMT-1 was adopted on 1913-07-01. Twenty minutes of DST was +# introduce[d] in 1932 and was suspended in 1939. In 1941, GMT was adopted by +# Defence Regulations. This was made permanent in 1946. +# +# Government Notice No. 121 of 1913, 1913-06-06, Sierra Leone Royal Gazette, +# Vol. XLIV, No. 1384, 1913-06-14, p 347 +# Alteration of Time Ordinance, 1932 (No. 34 of 1932) [1932-12-01] +# Alteration of Time (Amendment) Ordinance, 1938 (No. 25 of 1938) [1938-11-24] +# Defence Regulations (No. 9), 1939 (Regulations No. 9 of 1939), 1939-09-05 +# Defence Regulations (No. 11), 1939 (Regulations No. 11 of 1939), 1939-09-27 +# Defence (Amendment) (No. 17) Regulations, 1941 (Public Notice No. 157 of +# 1941), 1914-12-04 +# Alteration of Time (Amendment) Ordinance, 1946 (No. 2 of 1946) [1946-02-07] + +# From Tim Parenti (2021-03-02), per P Chan (2021-02-25): +# For Sierra Leone in 1957-1962, the standard time was defined in the +# Alteration of Time Ordinance, 1932 (as amended in 1946, renamed to Local Time +# Ordinance in 1960 and Local Time Act in 1961). It was unamended throughout +# that period. See references to "Time" in the Alphabetical Index of the +# Legislation in force on the 31st day of December, +# 1957: https://books.google.com/books?id=lvQ-AQAAIAAJ&pg=RA2-PA49 +# 1958: https://books.google.com/books?id=4fQ-AQAAIAAJ&pg=RA2-PA50 +# 1959: https://books.google.com/books?id=p_U-AQAAIAAJ&pg=RA2-PA55 +# 1960: https://books.google.com/books?id=JPY-AQAAIAAJ&pg=RA3-PA37 +# 1961: https://books.google.com/books?id=7vY-AQAAIAAJ&pg=RA3-PA41 +# 1962: https://books.google.com/books?id=W_c-AQAAIAAJ&pg=RA3-PA44 +# 1963: https://books.google.com/books?id=9vk-AQAAIAAJ&pg=RA1-PA47 +# +# Although Shanks & Pottenger had DST from Jun 1 00:00 to Sep 1 00:00 in this +# period, many contemporaneous almanacs agree that it wasn't used: +# https://mm.icann.org/pipermail/tz/2021-February/029866.html +# Go with the above. + +Rule SL 1932 only - Dec 1 0:00 0:20 -0040 +Rule SL 1933 1938 - Mar 31 24:00 0 -01 +Rule SL 1933 1939 - Aug 31 24:00 0:20 -0040 +Rule SL 1939 only - May 31 24:00 0 -01 + +Zone Africa/Freetown -0:53:00 - LMT 1882 + -0:53:00 - FMT 1913 Jul 1 # Freetown MT + -1:00 SL %s 1939 Sep 5 + -1:00 - -01 1941 Dec 6 24:00 + 0:00 - GMT + +# Botswana +# From Paul Eggert (2013-02-21): +# Milne says they were regulated by the Cape Town Signal in 1899; +# assume they switched to 2:00 when Cape Town did. +Zone Africa/Gaborone 1:43:40 - LMT 1885 + 1:30 - SAST 1903 Mar + 2:00 - CAT 1943 Sep 19 2:00 + 2:00 1:00 CAST 1944 Mar 19 2:00 + 2:00 - CAT + +# Zimbabwe +Zone Africa/Harare 2:04:12 - LMT 1903 Mar + 2:00 - CAT + +# Uganda +Zone Africa/Kampala 2:09:40 - LMT 1928 Jul + 3:00 - EAT 1930 + 2:30 - +0230 1948 + 2:45 - +0245 1957 + 3:00 - EAT + +# Rwanda +Zone Africa/Kigali 2:00:16 - LMT 1935 Jun + 2:00 - CAT + +# Democratic Republic of the Congo (west) +Zone Africa/Kinshasa 1:01:12 - LMT 1897 Nov 9 + 1:00 - WAT + +# Gabon +Zone Africa/Libreville 0:37:48 - LMT 1912 + 1:00 - WAT + +# Togo +Zone Africa/Lome 0:04:52 - LMT 1893 + 0:00 - GMT + +# Angola +# +# From Paul Eggert (2018-02-16): +# Shanks gives 1911-05-26 for the transition to WAT, +# evidently confusing the date of the Portuguese decree +# (see Europe/Lisbon) with the date that it took effect. +# +Zone Africa/Luanda 0:52:56 - LMT 1892 + 0:52:04 - LMT 1911 Dec 31 23:00u # Luanda MT? + 1:00 - WAT + +# Democratic Republic of the Congo (east) +# +# From Alois Treindl (2022-02-28): +# My main source for its time zone history is +# Henri le Corre, Régimes horaires pour l'Europe et l'Afrique. +# Shanks follows le Corre. As does Françoise Schneider-Gauquelin in her book +# Problèmes de l'heure résolus pour le monde entier. +# +Zone Africa/Lubumbashi 1:49:52 - LMT 1897 Nov 9 + 1:00 - WAT 1920 Apr 25 + 2:00 - CAT + +# Zambia +Zone Africa/Lusaka 1:53:08 - LMT 1903 Mar + 2:00 - CAT + +# Equatorial Guinea +# +# Although Shanks says that Malabo switched from UT +00 to +01 on 1963-12-15, +# a Google Books search says that London Calling, Issues 432-465 (1948), p 19, +# says that Spanish Guinea was at +01 back then. The Shanks data entries +# are most likely wrong, but we have nothing better; use them here for now. +# +Zone Africa/Malabo 0:35:08 - LMT 1912 + 0:00 - GMT 1963 Dec 15 + 1:00 - WAT + +# Lesotho +Zone Africa/Maseru 1:50:00 - LMT 1903 Mar + 2:00 - SAST 1943 Sep 19 2:00 + 2:00 1:00 SAST 1944 Mar 19 2:00 + 2:00 - SAST + +# Eswatini (formerly Swaziland) +Zone Africa/Mbabane 2:04:24 - LMT 1903 Mar + 2:00 - SAST + +# Somalia +Zone Africa/Mogadishu 3:01:28 - LMT 1893 Nov + 3:00 - EAT 1931 + 2:30 - +0230 1957 + 3:00 - EAT + +# Niger +Zone Africa/Niamey 0:08:28 - LMT 1912 + -1:00 - -01 1934 Feb 26 + 0:00 - GMT 1960 + 1:00 - WAT + +# Mauritania +Zone Africa/Nouakchott -1:03:48 - LMT 1912 + 0:00 - GMT 1934 Feb 26 + -1:00 - -01 1960 Nov 28 + 0:00 - GMT + +# Burkina Faso +Zone Africa/Ouagadougou -0:06:04 - LMT 1912 + 0:00 - GMT + +# Benin +# Whitman says they switched to 1:00 in 1946, not 1934; +# go with Shanks & Pottenger. +Zone Africa/Porto-Novo 0:10:28 - LMT 1912 Jan 1 + 0:00 - GMT 1934 Feb 26 + 1:00 - WAT + +# Mali (northern) +Zone Africa/Timbuktu -0:12:04 - LMT 1912 + 0:00 - GMT + +# Anguilla +Zone America/Anguilla -4:12:16 - LMT 1912 Mar 2 + -4:00 - AST + +# Antigua and Barbuda +Zone America/Antigua -4:07:12 - LMT 1912 Mar 2 + -5:00 - EST 1951 + -4:00 - AST + +# Chubut, Argentina +# The name "Comodoro Rivadavia" exceeds the 14-byte POSIX limit. +Zone America/Argentina/ComodRivadavia -4:30:00 - LMT 1894 Oct 31 + -4:16:48 - CMT 1920 May + -4:00 - -04 1930 Dec + -4:00 Arg -04/-03 1969 Oct 5 + -3:00 Arg -03/-02 1991 Mar 3 + -4:00 - -04 1991 Oct 20 + -3:00 Arg -03/-02 1999 Oct 3 + -4:00 Arg -04/-03 2000 Mar 3 + -3:00 - -03 2004 Jun 1 + -4:00 - -04 2004 Jun 20 + -3:00 - -03 + +# Aruba +Zone America/Aruba -4:40:24 - LMT 1912 Feb 12 # Oranjestad + -4:30 - -0430 1965 + -4:00 - AST + +# Atikokan, Ontario + +# From Paul Eggert (1997-10-17): +# Mark Brader writes that an article in the 1997-10-14 Toronto Star +# says that Atikokan, Ontario currently does not observe DST, +# but will vote on 11-10 whether to use EST/EDT. +# He also writes that the Ontario Time Act (1990, Chapter T.9) +# http://www.gov.on.ca/MBS/english/publications/statregs/conttext.html +# says that Ontario east of 90W uses EST/EDT, and west of 90W uses CST/CDT. +# Officially Atikokan is therefore on CST/CDT, and most likely this report +# concerns a non-official time observed as a matter of local practice. +# +# From Paul Eggert (2000-10-02): +# Matthews and Vincent (1998) write that Atikokan, Pickle Lake, and +# New Osnaburgh observe CST all year, that Big Trout Lake observes +# CST/CDT, and that Upsala and Shebandowan observe EST/EDT, all in +# violation of the official Ontario rules. +# +# From Paul Eggert (2006-07-09): +# Chris Walton (2006-07-06) mentioned an article by Stephanie MacLellan in the +# 2005-07-21 Chronicle-Journal, which said: +# +# The clocks in Atikokan stay set on standard time year-round. +# This means they spend about half the time on central time and +# the other half on eastern time. +# +# For the most part, the system works, Mayor Dennis Brown said. +# +# "The majority of businesses in Atikokan deal more with Eastern +# Canada, but there are some that deal with Western Canada," he +# said. "I don't see any changes happening here." +# +# Walton also writes "Supposedly Pickle Lake and Mishkeegogamang +# [New Osnaburgh] follow the same practice." + +# From Garry McKinnon (2006-07-14) via Chris Walton: +# I chatted with a member of my board who has an outstanding memory +# and a long history in Atikokan (and in the telecom industry) and he +# can say for certain that Atikokan has been practicing the current +# time keeping since 1952, at least. + +# From Paul Eggert (2006-07-17): +# Shanks & Pottenger say that Atikokan has agreed with Rainy River +# ever since standard time was introduced, but the information from +# McKinnon sounds more authoritative. For now, assume that Atikokan +# switched to EST immediately after WWII era daylight saving time +# ended. This matches the old (less populous) America/Coral_Harbour +# entry since our cutoff date of 1970, so we can move +# America/Coral_Harbour to the 'backward' file. + +Zone America/Atikokan -6:06:28 - LMT 1895 + -6:00 Canada C%sT 1940 Sep 29 + -6:00 1:00 CDT 1942 Feb 9 2:00s + -6:00 Canada C%sT 1945 Sep 30 2:00 + -5:00 - EST +#PACKRATLIST zone.tab Link America/Atikokan America/Coral_Harbour + +# Quebec east of Natashquan + +# From Paul Eggert (2021-05-09): +# H. David Matthews and Mary Vincent's map +# "It's about TIME", _Canadian Geographic_ (September-October 1998) +# http://www.canadiangeographic.ca/Magazine/SO98/alacarte.asp +# says that Quebec east of the -63 meridian is supposed to observe +# AST, but residents as far east as Natashquan use EST/EDT, and +# residents east of Natashquan use AST. +# The Quebec department of justice writes in +# "The situation in Minganie and Basse-Côte-Nord" +# https://www.justice.gouv.qc.ca/en/department/ministre/functions-and-responsabilities/legal-time-in-quebec/the-situation-in-minganie-and-basse-cote-nord/ +# that the coastal strip from just east of Natashquan to Blanc-Sablon +# observes Atlantic standard time all year round. +# This common practice was codified into law as of 2007; see Legal Time Act, +# CQLR c T-5.1 . +# For lack of better info, guess this practice began around 1970, contra to +# Shanks & Pottenger who have this region observing AST/ADT. + +Zone America/Blanc-Sablon -3:48:28 - LMT 1884 + -4:00 Canada A%sT 1970 + -4:00 - AST + +# Cayman Is +Zone America/Cayman -5:25:32 - LMT 1890 # Georgetown + -5:07:10 - KMT 1912 Feb # Kingston Mean Time + -5:00 - EST + +# United States +# +# From Paul Eggert (2018-03-18): +# America/Chillicothe would be tricky, as it was a city of two-timers: +# "To prevent a constant mixup at Chillicothe, caused by the courthouse +# clock running on central time and the city running on 'daylight saving' +# time, a third hand was added to the dial of the courthouse clock." +# -- Ohio news in brief. The Cedarville Herald. 1920-05-21;43(21):1 (col. 5) +# https://digitalcommons.cedarville.edu/cedarville_herald/794 + +# Canada +Zone America/Coral_Harbour -5:32:40 - LMT 1884 + -5:00 NT_YK E%sT 1946 + -5:00 - EST + +# From Chris Walton (2011-12-01): +# There are two areas within the Canadian province of British Columbia +# that do not currently observe daylight saving: +# a) The Creston Valley (includes the town of Creston and surrounding area) +# b) The eastern half of the Peace River Regional District +# (includes the cities of Dawson Creek and Fort St. John) + +# Earlier this year I stumbled across a detailed article about the time +# keeping history of Creston; it was written by Tammy Hardwick who is the +# manager of the Creston & District Museum. The article was written in May 2009. +# http://www.ilovecreston.com/?p=articles&t=spec&ar=260 +# According to the article, Creston has not changed its clocks since June 1918. +# i.e. Creston has been stuck on UT-7 for 93 years. +# Dawson Creek, on the other hand, changed its clocks as recently as April 1972. + +# Unfortunately the exact date for the time change in June 1918 remains +# unknown and will be difficult to ascertain. I e-mailed Tammy a few months +# ago to ask if Sunday June 2 was a reasonable guess. She said it was just +# as plausible as any other date (in June). She also said that after writing +# the article she had discovered another time change in 1916; this is the +# subject of another article which she wrote in October 2010. +# http://www.creston.museum.bc.ca/index.php?module=comments&uop=view_comment&cm+id=56 + +# Here is a summary of the three clock change events in Creston's history: +# 1. 1884 or 1885: adoption of Mountain Standard Time (GMT-7) +# Exact date unknown +# 2. Oct 1916: switch to Pacific Standard Time (GMT-8) +# Exact date in October unknown; Sunday October 1 is a reasonable guess. +# 3. June 1918: switch to Pacific Daylight Time (GMT-7) +# Exact date in June unknown; Sunday June 2 is a reasonable guess. +# note 1: +# On Oct 27/1918 when daylight saving ended in the rest of Canada, +# Creston did not change its clocks. +# note 2: +# During WWII when the Federal Government legislated a mandatory clock change, +# Creston did not oblige. +# note 3: +# There is no guarantee that Creston will remain on Mountain Standard Time +# (UTC-7) forever. +# The subject was debated at least once this year by the town Council. +# http://www.bclocalnews.com/kootenay_rockies/crestonvalleyadvance/news/116760809.html + +# During a period WWII, summer time (Daylight saying) was mandatory in Canada. +# In Creston, that was handled by shifting the area to PST (-8:00) then applying +# summer time to cause the offset to be -7:00, the same as it had been before +# the change. It can be argued that the timezone abbreviation during this +# period should be PDT rather than MST, but that doesn't seem important enough +# (to anyone) to further complicate the rules. + +# The transition dates (and times) are guesses. + +Zone America/Creston -7:46:04 - LMT 1884 + -7:00 - MST 1916 Oct 1 + -8:00 - PST 1918 Jun 2 + -7:00 - MST + +# Curaçao +# Milne gives 4:35:46.9 for Curaçao mean time; round to nearest. +# +# From Paul Eggert (2006-03-22): +# Shanks & Pottenger say that The Bottom and Philipsburg have been at +# -4:00 since standard time was introduced on 1912-03-02; and that +# Kralendijk and Rincon used Kralendijk Mean Time (-4:33:08) from +# 1912-02-02 to 1965-01-01. The former is dubious, since S&P also say +# Saba Island has been like Curaçao. +# This all predates our 1970 cutoff, though. +# +# By July 2007 Curaçao and St Maarten are planned to become +# associated states within the Netherlands, much like Aruba; +# Bonaire, Saba and St Eustatius would become directly part of the +# Netherlands as Kingdom Islands. This won't affect their time zones +# though, as far as we know. +# +Zone America/Curacao -4:35:47 - LMT 1912 Feb 12 # Willemstad + -4:30 - -0430 1965 + -4:00 - AST +Link America/Curacao America/Kralendijk +Link America/Curacao America/Lower_Princes + +# Dominica +Zone America/Dominica -4:05:36 - LMT 1911 Jul 1 0:01 # Roseau + -4:00 - AST + +# Baja California +# See 'northamerica' for why this entry is here rather than there. +Zone America/Ensenada -7:46:28 - LMT 1922 Jan 1 0:13:32 + -8:00 - PST 1927 Jun 10 23:00 + -7:00 - MST 1930 Nov 16 + -8:00 - PST 1942 Apr + -7:00 - MST 1949 Jan 14 + -8:00 - PST 1996 + -8:00 Mexico P%sT + +# Grenada +Zone America/Grenada -4:07:00 - LMT 1911 Jul # St George's + -4:00 - AST + +# Guadeloupe +Zone America/Guadeloupe -4:06:08 - LMT 1911 Jun 8 # Pointe-à-Pitre + -4:00 - AST + + +# Canada +# +# From Paul Eggert (2015-03-24): +# Since 1970 most of Quebec has been like Toronto; see +# America/Toronto. However, earlier versions of the tz database +# mistakenly relied on data from Shanks & Pottenger saying that Quebec +# differed from Ontario after 1970, and the following rules and zone +# were created for most of Quebec from the incorrect Shanks & +# Pottenger data. The post-1970 entries have been corrected, but the +# pre-1970 entries are unchecked and probably have errors. +# +Rule Mont 1917 only - Mar 25 2:00 1:00 D +Rule Mont 1917 only - Apr 24 0:00 0 S +Rule Mont 1919 only - Mar 31 2:30 1:00 D +Rule Mont 1919 only - Oct 25 2:30 0 S +Rule Mont 1920 only - May 2 2:30 1:00 D +Rule Mont 1920 1922 - Oct Sun>=1 2:30 0 S +Rule Mont 1921 only - May 1 2:00 1:00 D +Rule Mont 1922 only - Apr 30 2:00 1:00 D +Rule Mont 1924 only - May 17 2:00 1:00 D +Rule Mont 1924 1926 - Sep lastSun 2:30 0 S +Rule Mont 1925 1926 - May Sun>=1 2:00 1:00 D +Rule Mont 1927 1937 - Apr lastSat 24:00 1:00 D +Rule Mont 1927 1937 - Sep lastSat 24:00 0 S +Rule Mont 1938 1940 - Apr lastSun 0:00 1:00 D +Rule Mont 1938 1939 - Sep lastSun 0:00 0 S +Rule Mont 1946 1973 - Apr lastSun 2:00 1:00 D +Rule Mont 1945 1948 - Sep lastSun 2:00 0 S +Rule Mont 1949 1950 - Oct lastSun 2:00 0 S +Rule Mont 1951 1956 - Sep lastSun 2:00 0 S +Rule Mont 1957 1973 - Oct lastSun 2:00 0 S +Zone America/Montreal -4:54:16 - LMT 1884 + -5:00 Mont E%sT 1918 + -5:00 Canada E%sT 1919 + -5:00 Mont E%sT 1942 Feb 9 2:00s + -5:00 Canada E%sT 1946 + -5:00 Mont E%sT 1974 + -5:00 Canada E%sT + +# Montserrat +# From Paul Eggert (2006-03-22): +# In 1995 volcanic eruptions forced evacuation of Plymouth, the capital. +# world.gazetteer.com says Cork Hill is the most populous location now. +Zone America/Montserrat -4:08:52 - LMT 1911 Jul 1 0:01 # Cork Hill + -4:00 - AST + +# The Bahamas +# +# For 1899 Milne gives -5:09:29.5; round that. +# +# From P Chan (2020-11-27, corrected on 2020-12-02): +# There were two periods of DST observed in 1942-1945: 1942-05-01 +# midnight to 1944-12-31 midnight and 1945-02-01 to 1945-10-17 midnight. +# "midnight" should mean 24:00 from the context. +# +# War Time Order 1942 [1942-05-01] and War Time (No. 2) Order 1942 [1942-09-29] +# Appendix to the Statutes of 7 George VI. and the Year 1942. p 34, 43 +# https://books.google.com/books?id=5rlNAQAAIAAJ&pg=RA3-PA34 +# https://books.google.com/books?id=5rlNAQAAIAAJ&pg=RA3-PA43 +# +# War Time Order 1943 [1943-03-31] and War Time Order 1944 [1943-12-29] +# Appendix to the Statutes of 8 George VI. and the Year 1943. p 9-10, 28-29 +# https://books.google.com/books?id=5rlNAQAAIAAJ&pg=RA4-PA9 +# https://books.google.com/books?id=5rlNAQAAIAAJ&pg=RA4-PA28 +# +# War Time Order 1945 [1945-01-31] and the Order which revoke War Time Order +# 1945 [1945-10-16] Appendix to the Statutes of 9 George VI. and the Year +# 1945. p 160, 247-248 +# https://books.google.com/books?id=5rlNAQAAIAAJ&pg=RA6-PA160 +# https://books.google.com/books?id=5rlNAQAAIAAJ&pg=RA6-PA247 +# +# From Sue Williams (2006-12-07): +# The Bahamas announced about a month ago that they plan to change their DST +# rules to sync with the U.S. starting in 2007.... +# http://www.jonesbahamas.com/?c=45&a=10412 + +Rule Bahamas 1942 only - May 1 24:00 1:00 W +Rule Bahamas 1944 only - Dec 31 24:00 0 S +Rule Bahamas 1945 only - Feb 1 0:00 1:00 W +Rule Bahamas 1945 only - Aug 14 23:00u 1:00 P # Peace +Rule Bahamas 1945 only - Oct 17 24:00 0 S +Rule Bahamas 1964 1975 - Oct lastSun 2:00 0 S +Rule Bahamas 1964 1975 - Apr lastSun 2:00 1:00 D + +Zone America/Nassau -5:09:30 - LMT 1912 Mar 2 + -5:00 Bahamas E%sT 1976 + -5:00 US E%sT + +# Canada +# From Chris Walton (2022-10-15): +# I would also like to see America/Nipigon and America/Rainy_River converted +# into link entries because I have zero faith in the current Shanks based data. +# From Paul Eggert (2022-10-15): +# These are now links in the primary data. Also see America/Thunder_Bay. +Zone America/Nipigon -5:53:04 - LMT 1895 + -5:00 Canada E%sT 1940 Sep 29 + -5:00 1:00 EDT 1942 Feb 9 2:00s + -5:00 Canada E%sT + +# From Rives McDow (1999-11-08): +# On October 31, when the rest of Nunavut went to Central time, +# Pangnirtung wobbled. Here is the result of their wobble: +# +# The following businesses and organizations in Pangnirtung use Central Time: +# +# First Air, Power Corp, Nunavut Construction, Health Center, RCMP, +# Eastern Arctic National Parks, A & D Specialist +# +# The following businesses and organizations in Pangnirtung use Eastern Time: +# +# Hamlet office, All other businesses, Both schools, Airport operator +# +# This has made for an interesting situation there, which warranted the news. +# No one there that I spoke with seems concerned, or has plans to +# change the local methods of keeping time, as it evidently does not +# really interfere with any activities or make things difficult locally. +# They plan to celebrate New Year's turn-over twice, one hour apart, +# so it appears that the situation will last at least that long. +# The Nunavut Intergovernmental Affairs hopes that they will "come to +# their senses", but the locals evidently don't see any problem with +# the current state of affairs. + +# From Michaela Rodrigue, writing in the +# Nunatsiaq News (1999-11-19): +# http://www.nunatsiaqonline.ca/archives/nunavut991130/nvt91119_17.html +# Clyde River, Pangnirtung and Sanikiluaq now operate with two time zones, +# central - or Nunavut time - for government offices, and eastern time +# for municipal offices and schools.... Igloolik [was similar but then] +# made the switch to central time on Saturday, Nov. 6. + +# From Chris Walton (2022-11-06): +# The implication is that Pangnirtung and Qikiqtarjuaq have observed Eastern +# Time as far back as 1984 (and likely even further back than that). +# It is possible that these communities never actually observed Atlantic +# Time, but that would be difficult to prove. +# From Paul Eggert (2022-11-06): +# This is in 'backzone' as we have no good evidence that Pangnirtung differs +# from America/Iqaluit since 1970. A Google Books snippet view of +# volume 2, page 186 of "Pilot of Arctic Canada", published 1959 by +# the Canadian Hydrographic Service, suggests (though does not state) +# that Pangnirtung observed EST then. +# +# aka Panniqtuuq +Zone America/Pangnirtung 0 - -00 1921 # trading post est. + -5:00 NT_YK E%sT 1999 Oct 31 2:00 + -6:00 Canada C%sT 2000 Oct 29 2:00 + -5:00 Canada E%sT + +# United States +# +# From Paul Eggert (2018-03-18): +# America/Palm_Springs would be tricky, as it kept two sets of clocks +# in 1946/7. See the following notes. +# +# From Steve Allen (2018-01-19): +# The shadow of Mt. San Jacinto brings darkness very early in the winter +# months. In 1946 the chamber of commerce decided to put the clocks of Palm +# Springs forward by an hour in the winter. +# https://www.desertsun.com/story/life/2017/12/27/palm-springs-struggle-daylight-savings-time-and-idea-sun-time/984416001/ +# Desert Sun, Number 18, 1 November 1946 +# https://cdnc.ucr.edu/cgi-bin/cdnc?a=d&d=DS19461101 +# has proposal for meeting on front page and page 21. +# Desert Sun, Number 19, 5 November 1946 +# https://cdnc.ucr.edu/cgi-bin/cdnc?a=d&d=DS19461105 +# reports that Sun Time won at the meeting on front page and page 5. +# Desert Sun, Number 37, 7 January 1947 +# https://cdnc.ucr.edu/cgi-bin/cdnc?a=d&d=DS19470107.2.12 +# front page reports request to abandon Sun Time and page 7 notes a "class war". +# Desert Sun, Number 38, 10 January 1947 +# https://cdnc.ucr.edu/cgi-bin/cdnc?a=d&d=DS19470110 +# front page reports on end. + +# Trinidad and Tobago +Zone America/Port_of_Spain -4:06:04 - LMT 1912 Mar 2 + -4:00 - AST +Link America/Port_of_Spain America/Marigot +Link America/Port_of_Spain America/St_Barthelemy + +# Canada +# From Chris Walton (2022-10-15): +# I would also like to see America/Nipigon and America/Rainy_River converted +# into link entries because I have zero faith in the current Shanks based data. +# From Paul Eggert (2022-10-15): +# These are now links in the primary data. Also see America/Thunder_Bay. +Zone America/Rainy_River -6:18:16 - LMT 1895 + -6:00 Canada C%sT 1940 Sep 29 + -6:00 1:00 CDT 1942 Feb 9 2:00s + -6:00 Canada C%sT + +# Argentina +# This entry was intended for the following areas, but has been superseded by +# more detailed zones. +# Santa Fe (SF), Entre Ríos (ER), Corrientes (CN), Misiones (MN), Chaco (CC), +# Formosa (FM), La Pampa (LP), Chubut (CH) +Zone America/Rosario -4:02:40 - LMT 1894 Nov + -4:16:44 - CMT 1920 May + -4:00 - -04 1930 Dec + -4:00 Arg -04/-03 1969 Oct 5 + -3:00 Arg -03/-02 1991 Jul + -3:00 - -03 1999 Oct 3 0:00 + -4:00 Arg -04/-03 2000 Mar 3 0:00 + -3:00 - -03 + +# St Kitts-Nevis +Zone America/St_Kitts -4:10:52 - LMT 1912 Mar 2 # Basseterre + -4:00 - AST + +# St Lucia +Zone America/St_Lucia -4:04:00 - LMT 1890 # Castries + -4:04:00 - CMT 1912 # Castries Mean Time + -4:00 - AST + +# US Virgin Is +Zone America/St_Thomas -4:19:44 - LMT 1911 Jul # Charlotte Amalie + -4:00 - AST +Link America/St_Thomas America/Virgin + +# St Vincent and the Grenadines +Zone America/St_Vincent -4:04:56 - LMT 1890 # Kingstown + -4:04:56 - KMT 1912 # Kingstown Mean Time + -4:00 - AST + +# Canada +# +# From Paul Eggert (2003-07-27): +# Willett (1914-03) writes (p. 17) "In the Cities of Fort William, and +# Port Arthur, Ontario, the principle of the Bill has been in +# operation for the past three years, and in the City of Moose Jaw, +# Saskatchewan, for one year." +# +# From David Bryan via Tory Tronrud, Director/Curator, +# Thunder Bay Museum (2003-11-12): +# There is some suggestion, however, that, by-law or not, daylight +# savings time was being practiced in Fort William and Port Arthur +# before 1909.... [I]n 1910, the line between the Eastern and Central +# Time Zones was permanently moved about two hundred miles west to +# include the Thunder Bay area.... When Canada adopted daylight +# savings time in 1916, Fort William and Port Arthur, having done so +# already, did not change their clocks.... During the Second World +# War,... [t]he cities agreed to implement DST during the summer +# months for the remainder of the war years. +# +# From Jeffery Nichols (2020-02-06): +# According to the [Shanks] atlas, those western Ontario zones are huge, +# covering most of Ontario northwest of Sault Ste Marie and Timmins. +# The zones seem to include towns bigger than the ones they're named after, +# like Dryden in America/Rainy_River and Wawa (and maybe Attawapiskat) in +# America/Nipigon. I assume it's too much trouble to change the name of the +# zone (like when you found out that America/Glace_Bay includes Sydney, Nova +# Scotia).... +# +# From Chris Walton (2022-10-15): +# The TZ database currently shows that Thunder Bay has observed daylight +# saving every year from 1970 onwards with the exception of 1973. +# Back in July I raised some doubts on this mailing list about the 1973 data. +# I now have more proof that it is wrong. +# [attached Chronicle-Journal front pages, 1973-04-28 and 1973-10-27] +# +# From Paul Eggert (2022-10-15): +# This is now a link in the primary data. The following entry is +# from Shanks & Pottenger, with corrections as noted above. +# +Zone America/Thunder_Bay -5:57:00 - LMT 1895 + -6:00 - CST 1910 + -5:00 - EST 1942 + -5:00 Canada E%sT 1970 + -5:00 Toronto E%sT 1974 + -5:00 Canada E%sT + +# British Virgin Is +Zone America/Tortola -4:18:28 - LMT 1911 Jul # Road Town + -4:00 - AST + +# Yellowknife, Northwest Territories +Zone America/Yellowknife 0 - -00 1935 # Yellowknife founded? + -7:00 NT_YK M%sT 1980 + -7:00 Canada M%sT + +# Dumont d'Urville, ÃŽle des Pétrels, -6640+14001, since 1956-11 +# (2005-12-05) +# +# Another base at Port-Martin, 50km east, began operation in 1947. +# It was destroyed by fire on 1952-01-14. +# +Zone Antarctica/DumontDUrville 0 - -00 1947 + 10:00 - +10 1952 Jan 14 + 0 - -00 1956 Nov + 10:00 - +10 + +# McMurdo, Ross Island, since 1955-12 +Zone Antarctica/McMurdo 0 - -00 1956 + 12:00 NZ NZ%sT +Link Antarctica/McMurdo Antarctica/South_Pole + +# Syowa, Antarctica +# +# From Hideyuki Suzuki (1999-02-06): +# In all Japanese stations, +0300 is used as the standard time. +# +# Syowa station, which is the first antarctic station of Japan, +# was established on 1957-01-29. Since Syowa station is still the main +# station of Japan, it's appropriate for the principal location. +# See: +# NIPR Antarctic Research Activities (1999-08-17) +# http://www.nipr.ac.jp/english/ara01.html +Zone Antarctica/Syowa 0 - -00 1957 Jan 29 + 3:00 - +03 + +# Yemen +# Milne says 2:59:54 was the meridian of the saluting battery at Aden, +# and that Yemen was at 1:55:56, the meridian of the Hagia Sophia. +Zone Asia/Aden 2:59:54 - LMT 1950 + 3:00 - +03 + +# Bahrain +# +# From Paul Eggert (2020-07-23): +# Most of this data comes from: +# Stewart A. Why Gulf Standard Time is far from standard: the fascinating story +# behind the time zone's invention. The National (Abu Dhabi). 2020-07-22. +# https://www.thenational.ae/arts-culture/why-gulf-standard-time-is-far-from-standard-the-fascinating-story-behind-the-time-zone-s-invention-1.1052589 +# Stewart writes that before 1941 some companies in Bahrain were at +0330 and +# others at +0323. Reginald George Alban, a British political agent based in +# Manama, worked to standardize this, and from 1941-07-20 Bahrain was at +# +0330. However, BOAC asked that clocks be moved to gain more light at day's +# end, so Bahrain switched to +04 on 1944-01-01. +# +# Re the 1941 transition, Stewart privately sent me this citation: +# "File 16/53 Enquiries Re: Calculation of Local Time", British Library: India +# Office Records and Private Papers, IOR/R/15/2/1564, in Qatar Digital Library +# https://www.qdl.qa/archive/81055/vdc_100000000282.0x00012b +# It says there was no real standard in Bahrain before 1941-07-20. +# +0330 was used by steamers of the British India Co, by Petroleum Concessions +# and by Cable & Wireless; +0323 was used by the Eastern Bank Ltd, BOAC, and +# Bahrein Petroleum (Bapco), and California Arabian Standard Oil Co (Casoc) +# adopted DST effective 1941-05-24. Alban suggested adopting DST, R.B. Coomb +# of C&W countersuggested +0330, and although C.A. Rodstrom of Casoc (formerly +# of Bapco) stated that Bahrain had formerly used +0330 before Bapco arrived +# but Bapco switched to +0323 because of "constant confusion", the consensus +# was +0330. The government adopted +0330 in 1941-07-20 and companies seem to +# have switched by 08-01. No time of day was given for the 1940s transitions. +Zone Asia/Bahrain 3:22:20 - LMT 1941 Jul 20 # Manamah + 3:30 - +0330 1944 Jan 1 + 4:00 - +04 1972 Jun + 3:00 - +03 + +# Brunei +Zone Asia/Brunei 7:39:40 - LMT 1926 Mar # Bandar Seri Begawan + 7:30 - +0730 1933 + 8:00 - +08 + +# India +# +# From Paul Eggert (2014-09-06): +# The 1876 Report of the Secretary of the [US] Navy, p 305 says that Madras +# civil time was 5:20:57.3. +# +# From Paul Eggert (2014-08-21): +# In tomorrow's The Hindu, Nitya Menon reports that India had two civil time +# zones starting in 1884, one in Bombay and one in Calcutta, and that railways +# used a third time zone based on Madras time (80° 18' 30" E). Also, +# in 1881 Bombay briefly switched to Madras time, but switched back. See: +# http://www.thehindu.com/news/cities/chennai/madras-375-when-madras-clocked-the-time/article6339393.ece +#Zone Asia/Chennai [not enough info to complete] + +# China +# Long-shu Time (probably due to Long and Shu being two names of that area) +# Guangxi, Guizhou, Hainan, Ningxia, Sichuan, Shaanxi, and Yunnan; +# most of Gansu; west Inner Mongolia; west Qinghai; and the Guangdong +# counties Deqing, Enping, Kaiping, Luoding, Taishan, Xinxing, +# Yangchun, Yangjiang, Yu'nan, and Yunfu. +Zone Asia/Chongqing 7:06:20 - LMT 1928 # or Chungking + 7:00 - +07 1980 May + 8:00 PRC C%sT +Link Asia/Chongqing Asia/Chungking + +# Vietnam +# From Paul Eggert (2014-10-13): +# See Asia/Ho_Chi_Minh for the source for this data. +# Trần's book says the 1954-55 transition to 07:00 in Hanoi was in +# October 1954, with exact date and time unspecified. +Zone Asia/Hanoi 7:03:24 - LMT 1906 Jul 1 + 7:06:30 - PLMT 1911 May 1 + 7:00 - +07 1942 Dec 31 23:00 + 8:00 - +08 1945 Mar 14 23:00 + 9:00 - +09 1945 Sep 2 + 7:00 - +07 1947 Apr 1 + 8:00 - +08 1954 Oct + 7:00 - +07 + +# China +# Changbai Time ("Long-white Time", Long-white = Heilongjiang area) +# Heilongjiang (except Mohe county), Jilin +Zone Asia/Harbin 8:26:44 - LMT 1928 # or Haerbin + 8:30 - +0830 1932 Mar + 8:00 - CST 1940 + 9:00 - +09 1966 May + 8:30 - +0830 1980 May + 8:00 PRC C%sT + +# far west China +Zone Asia/Kashgar 5:03:56 - LMT 1928 # or Kashi or Kaxgar + 5:30 - +0530 1940 + 5:00 - +05 1980 May + 8:00 PRC C%sT + +# peninsular Malaysia +# taken from Mok Ly Yng (2003-10-30) +# https://web.archive.org/web/20190822231045/http://www.math.nus.edu.sg/~mathelmr/teaching/timezone.html +# This agrees with Singapore since 1905-06-01. +Zone Asia/Kuala_Lumpur 6:46:46 - LMT 1901 Jan 1 + 6:55:25 - SMT 1905 Jun 1 # Singapore M.T. + 7:00 - +07 1933 Jan 1 + 7:00 0:20 +0720 1936 Jan 1 + 7:20 - +0720 1941 Sep 1 + 7:30 - +0730 1942 Feb 16 + 9:00 - +09 1945 Sep 12 + 7:30 - +0730 1981 Dec 31 16:00u + 8:00 - +08 + +# Kuwait +Zone Asia/Kuwait 3:11:56 - LMT 1950 + 3:00 - +03 + + +# Oman +# Milne says 3:54:24 was the meridian of the Muscat Tidal Observatory. +Zone Asia/Muscat 3:54:24 - LMT 1920 + 4:00 - +04 + +# India +# From Paul Eggert (2014-08-11), after a heads-up from Stephen Colebourne: +# According to a Portuguese decree (1911-05-26) +# https://dre.pt/pdf1sdip/1911/05/12500/23132313.pdf +# Portuguese India switched to UT +05 on 1912-01-01. +#Zone Asia/Panaji [not enough info to complete] + +# Cambodia + +# From an adoptive daughter of the late Cambodian ruler Prince Sihanouk, +# via Alois Treindl (2019-08-08): +# +# King Sihanouk said that, during the Japanese occupation, starting with +# what historians refer to as "le coup de force du 9 mars 1945", Cambodia, +# like the entire French Indochina, used Tokyo time zone. After Japan +# surrendered, 2 September 1945, Cambodia fell under French rule again and +# adopted Hanoi time zone again. +# +# However, on 7 January 1946, Sihanouk and Tioulong managed to obtain a +# status of "internal autonomy" from the government of Charles de Gaulle. +# Although many fields remained under the administration of the French +# (customs, taxes, justice, defence, foreign affairs, etc.), the Cambodian +# administration was responsible for religious matters and traditional +# celebrations, which included our calendar and time. The time zone was GMT +# + 7 and _no_ DST was applied. +# +# After Sihanouk and Tioulong achieved full independence, on 9 November 1953, +# GMT + 7 was maintained. + +# From Paul Eggert (2019-08-26): +# See Asia/Ho_Chi_Minh for the source for most of rest of this data. + +Zone Asia/Phnom_Penh 6:59:40 - LMT 1906 Jul 1 + 7:06:30 - PLMT 1911 May 1 + 7:00 - +07 1942 Dec 31 23:00 + 8:00 - +08 1945 Mar 14 23:00 + 9:00 - +09 1945 Sep 2 + 7:00 - +07 + +# Israel +Zone Asia/Tel_Aviv 2:19:04 - LMT 1880 + 2:21 - JMT 1918 + 2:00 Zion I%sT + +# Laos +# From Paul Eggert (2014-10-11): +# See Asia/Ho_Chi_Minh for the source for most of this data. +# Trần's book says that Laos reverted to UT +07 on 1955-04-15. +# Also, guess that Laos reverted to +07 on 1945-09-02, when Vietnam did; +# this is probably wrong but it's better than guessing no transition. +Zone Asia/Vientiane 6:50:24 - LMT 1906 Jul 1 + 7:06:30 - PLMT 1911 May 1 + 7:00 - +07 1942 Dec 31 23:00 + 8:00 - +08 1945 Mar 14 23:00 + 9:00 - +09 1945 Sep 2 + 7:00 - +07 1947 Apr 1 + 8:00 - +08 1955 Apr 15 + 7:00 - +07 + +# Jan Mayen +# From Whitman: +Zone Atlantic/Jan_Mayen -1:00 - -01 + +# Iceland +# +# From Adam David (1993-11-06): +# The name of the timezone in Iceland for system / mail / news purposes is GMT. +# +# (1993-12-05): +# This material is paraphrased from the 1988 edition of the University of +# Iceland Almanak. +# +# From January 1st, 1908 the whole of Iceland was standardised at 1 hour +# behind GMT. Previously, local mean solar time was used in different parts +# of Iceland, the almanak had been based on Reykjavík mean solar time which +# was 1 hour and 28 minutes behind GMT. +# +# "first day of winter" referred to [below] means the first day of the 26 weeks +# of winter, according to the old icelandic calendar that dates back to the +# time the norsemen first settled Iceland. The first day of winter is always +# Saturday, but is not dependent on the Julian or Gregorian calendars. +# +# (1993-12-10): +# I have a reference from the Oxford Icelandic-English dictionary for the +# beginning of winter, which ties it to the ecclesiastical calendar (and thus +# to the julian/gregorian calendar) over the period in question. +# the winter begins on the Saturday next before St. Luke's day +# (old style), or on St. Luke's day, if a Saturday. +# St. Luke's day ought to be traceable from ecclesiastical sources. "old style" +# might be a reference to the Julian calendar as opposed to Gregorian, or it +# might mean something else (???). +# +# From Paul Eggert (2014-11-22): +# The information below is taken from the 1988 Almanak; see +# http://www.almanak.hi.is/klukkan.html +# +Rule Iceland 1917 1919 - Feb 19 23:00 1:00 - +Rule Iceland 1917 only - Oct 21 1:00 0 - +Rule Iceland 1918 1919 - Nov 16 1:00 0 - +Rule Iceland 1921 only - Mar 19 23:00 1:00 - +Rule Iceland 1921 only - Jun 23 1:00 0 - +Rule Iceland 1939 only - Apr 29 23:00 1:00 - +Rule Iceland 1939 only - Oct 29 2:00 0 - +Rule Iceland 1940 only - Feb 25 2:00 1:00 - +Rule Iceland 1940 1941 - Nov Sun>=2 1:00s 0 - +Rule Iceland 1941 1942 - Mar Sun>=2 1:00s 1:00 - +# 1943-1946 - first Sunday in March until first Sunday in winter +Rule Iceland 1943 1946 - Mar Sun>=1 1:00s 1:00 - +Rule Iceland 1942 1948 - Oct Sun>=22 1:00s 0 - +# 1947-1967 - first Sunday in April until first Sunday in winter +Rule Iceland 1947 1967 - Apr Sun>=1 1:00s 1:00 - +# 1949 and 1967 Oct transitions delayed by 1 week +Rule Iceland 1949 only - Oct 30 1:00s 0 - +Rule Iceland 1950 1966 - Oct Sun>=22 1:00s 0 - +Rule Iceland 1967 only - Oct 29 1:00s 0 - + +Zone Atlantic/Reykjavik -1:28 - LMT 1908 + -1:00 Iceland -01/+00 1968 Apr 7 1:00s + 0:00 - GMT +Link Atlantic/Reykjavik Iceland + +# St Helena +Zone Atlantic/St_Helena -0:22:48 - LMT 1890 # Jamestown + -0:22:48 - JMT 1951 # Jamestown Mean Time + 0:00 - GMT + +# King Island +Zone Australia/Currie 9:35:28 - LMT 1895 Sep + 10:00 AT AE%sT 1919 Oct 24 + 10:00 Aus AE%sT 1968 Oct 15 + 10:00 AT AE%sT + + +# Netherlands + +# Howse writes that the Netherlands' railways used GMT between 1892 and 1940, +# but for other purposes the Netherlands used Amsterdam mean time. + +# However, Robert H. van Gent writes (2001-04-01): +# Howse's statement is only correct up to 1909. From 1909-05-01 (00:00:00 +# Amsterdam mean time) onwards, the whole of the Netherlands (including +# the Dutch railways) was required by law to observe Amsterdam mean time +# (19 minutes 32.13 seconds ahead of GMT). This had already been the +# common practice (except for the railways) for many decades but it was +# not until 1909 when the Dutch government finally defined this by law. +# On 1937-07-01 this was changed to 20 minutes (exactly) ahead of GMT and +# was generally known as Dutch Time ("Nederlandse Tijd"). +# +# (2001-04-08): +# 1892-05-01 was the date when the Dutch railways were by law required to +# observe GMT while the remainder of the Netherlands adhered to the common +# practice of following Amsterdam mean time. +# +# (2001-04-09): +# In 1835 the authorities of the province of North Holland requested the +# municipal authorities of the towns and cities in the province to observe +# Amsterdam mean time but I do not know in how many cases this request was +# actually followed. +# +# From 1852 onwards the Dutch telegraph offices were by law required to +# observe Amsterdam mean time. As the time signals from the observatory of +# Leiden were also distributed by the telegraph system, I assume that most +# places linked up with the telegraph (and railway) system automatically +# adopted Amsterdam mean time. +# +# Although the early Dutch railway companies initially observed a variety +# of times, most of them had adopted Amsterdam mean time by 1858 but it +# was not until 1866 when they were all required by law to observe +# Amsterdam mean time. + +# The data entries before 1945 are taken from +# https://www.staff.science.uu.nl/~gent0113/wettijd/wettijd.htm + +# From Paul Eggert (2021-05-09): +# I invented the abbreviations AMT for Amsterdam Mean Time and NST for +# Netherlands Summer Time, used in the Netherlands from 1835 to 1937. + +Rule Neth 1916 only - May 1 0:00 1:00 NST # Netherlands Summer Time +Rule Neth 1916 only - Oct 1 0:00 0 AMT # Amsterdam Mean Time +Rule Neth 1917 only - Apr 16 2:00s 1:00 NST +Rule Neth 1917 only - Sep 17 2:00s 0 AMT +Rule Neth 1918 1921 - Apr Mon>=1 2:00s 1:00 NST +Rule Neth 1918 1921 - Sep lastMon 2:00s 0 AMT +Rule Neth 1922 only - Mar lastSun 2:00s 1:00 NST +Rule Neth 1922 1936 - Oct Sun>=2 2:00s 0 AMT +Rule Neth 1923 only - Jun Fri>=1 2:00s 1:00 NST +Rule Neth 1924 only - Mar lastSun 2:00s 1:00 NST +Rule Neth 1925 only - Jun Fri>=1 2:00s 1:00 NST +# From 1926 through 1939 DST began 05-15, except that it was delayed by a week +# in years when 05-15 fell in the Pentecost weekend. +Rule Neth 1926 1931 - May 15 2:00s 1:00 NST +Rule Neth 1932 only - May 22 2:00s 1:00 NST +Rule Neth 1933 1936 - May 15 2:00s 1:00 NST +Rule Neth 1937 only - May 22 2:00s 1:00 NST +Rule Neth 1937 only - Jul 1 0:00 1:00 S +Rule Neth 1937 1939 - Oct Sun>=2 2:00s 0 - +Rule Neth 1938 1939 - May 15 2:00s 1:00 S +Rule Neth 1945 only - Apr 2 2:00s 1:00 S +Rule Neth 1945 only - Sep 16 2:00s 0 - + #STDOFF 0:19:32.13 +Zone Europe/Amsterdam 0:19:32 - LMT 1835 + 0:19:32 Neth %s 1937 Jul 1 + 0:20 Neth +0020/+0120 1940 May 16 0:00 + 1:00 C-Eur CE%sT 1945 Apr 2 2:00 + 1:00 Neth CE%sT 1977 + 1:00 EU CE%sT + + +# Northern Ireland +Zone Europe/Belfast -0:23:40 - LMT 1880 Aug 2 + -0:25:21 - DMT 1916 May 21 2:00 + # DMT = Dublin/Dunsink MT + -0:25:21 1:00 IST 1916 Oct 1 2:00s + # IST = Irish Summer Time + 0:00 GB-Eire %s 1968 Oct 27 + 1:00 - BST 1971 Oct 31 2:00u + 0:00 GB-Eire %s 1996 + 0:00 EU GMT/BST + + +# Denmark + +# From Jesper Nørgaard Welen (2005-04-26): +# the law [introducing standard time] was in effect from 1894-01-01.... +# The page https://www.retsinformation.dk/eli/lta/1893/83 +# confirms this, and states that the law was put forth 1893-03-29. +# +# The EU [actually, EEC and Euratom] treaty with effect from 1973: +# https://www.retsinformation.dk/eli/lta/1972/21100 +# +# This provoked a new law from 1974 to make possible summer time changes +# in subsequent decrees with the law +# https://www.retsinformation.dk/eli/lta/1974/223 +# +# It seems however that no decree was set forward until 1980. I have +# not found any decree, but in another related law, the effecting DST +# changes are stated explicitly to be from 1980-04-06 at 02:00 to +# 1980-09-28 at 02:00. If this is true, this differs slightly from +# the EU rule in that DST runs to 02:00, not 03:00. We don't know +# when Denmark began using the EU rule correctly, but we have only +# confirmation of the 1980-time, so I presume it was correct in 1981: +# The law is about the management of the extra hour, concerning +# working hours reported and effect on obligatory-rest rules (which +# was suspended on that night): +# https://web.archive.org/web/20140104053304/https://www.retsinformation.dk/Forms/R0710.aspx?id=60267 + +# From Jesper Nørgaard Welen (2005-06-11): +# The Herning Folkeblad (1980-09-26) reported that the night between +# Saturday and Sunday the clock is set back from three to two. + +# From Paul Eggert (2005-06-11): +# Hence the "02:00" of the 1980 law refers to standard time, not +# wall-clock time, and so the EU rules were in effect in 1980. + +Rule Denmark 1916 only - May 14 23:00 1:00 S +Rule Denmark 1916 only - Sep 30 23:00 0 - +Rule Denmark 1940 only - May 15 0:00 1:00 S +Rule Denmark 1945 only - Apr 2 2:00s 1:00 S +Rule Denmark 1945 only - Aug 15 2:00s 0 - +Rule Denmark 1946 only - May 1 2:00s 1:00 S +Rule Denmark 1946 only - Sep 1 2:00s 0 - +Rule Denmark 1947 only - May 4 2:00s 1:00 S +Rule Denmark 1947 only - Aug 10 2:00s 0 - +Rule Denmark 1948 only - May 9 2:00s 1:00 S +Rule Denmark 1948 only - Aug 8 2:00s 0 - +# +Zone Europe/Copenhagen 0:50:20 - LMT 1890 + 0:50:20 - CMT 1894 Jan 1 # Copenhagen MT + 1:00 Denmark CE%sT 1942 Nov 2 2:00s + 1:00 C-Eur CE%sT 1945 Apr 2 2:00 + 1:00 Denmark CE%sT 1980 + 1:00 EU CE%sT + +# Guernsey +# Data from Joseph S. Myers +# https://mm.icann.org/pipermail/tz/2013-September/019883.html +# References to be added +# LMT is for Town Church, St. Peter Port, 49° 27' 17" N, 2° 32' 10" W. +Zone Europe/Guernsey -0:10:09 - LMT 1913 Jun 18 + 0:00 GB-Eire %s 1940 Jul 2 + 1:00 C-Eur CE%sT 1945 May 8 + 0:00 GB-Eire %s 1968 Oct 27 + 1:00 - BST 1971 Oct 31 2:00u + 0:00 GB-Eire %s 1996 + 0:00 EU GMT/BST + +# Isle of Man +# +# From Lester Caine (2013-09-04): +# The Isle of Man legislation is now on-line at +# , starting with the original Statutory +# Time Act in 1883 and including additional confirmation of some of +# the dates of the 'Summer Time' orders originating at +# Westminster. There is a little uncertainty as to the starting date +# of the first summer time in 1916 which may have been announced a +# couple of days late. There is still a substantial number of +# documents to work through, but it is thought that every GB change +# was also implemented on the island. +# +# AT4 of 1883 - The Statutory Time et cetera Act 1883 - +# LMT Location - 54.1508N -4.4814E - Tynwald Hill ( Manx parliament ) +Zone Europe/Isle_of_Man -0:17:55 - LMT 1883 Mar 30 0:00s + 0:00 GB-Eire %s 1968 Oct 27 + 1:00 - BST 1971 Oct 31 2:00u + 0:00 GB-Eire %s 1996 + 0:00 EU GMT/BST + +# Jersey +# Data from Joseph S. Myers +# https://mm.icann.org/pipermail/tz/2013-September/019883.html +# References to be added +# LMT is for Parish Church, St. Helier, 49° 11' 0.57" N, 2° 6' 24.33" W. +Zone Europe/Jersey -0:08:26 - LMT 1898 Jun 11 16:00u + 0:00 GB-Eire %s 1940 Jul 2 + 1:00 C-Eur CE%sT 1945 May 8 + 0:00 GB-Eire %s 1968 Oct 27 + 1:00 - BST 1971 Oct 31 2:00u + 0:00 GB-Eire %s 1996 + 0:00 EU GMT/BST + +# Slovenia +Zone Europe/Ljubljana 0:58:04 - LMT 1884 + 1:00 - CET 1941 Apr 18 23:00 + 1:00 C-Eur CE%sT 1945 May 8 2:00s + 1:00 1:00 CEST 1945 Sep 16 2:00s + 1:00 - CET 1982 Nov 27 + 1:00 EU CE%sT + + +# Luxembourg + +# Whitman disagrees with most of these dates in minor ways; +# go with Shanks & Pottenger. +Rule Lux 1916 only - May 14 23:00 1:00 S +Rule Lux 1916 only - Oct 1 1:00 0 - +Rule Lux 1917 only - Apr 28 23:00 1:00 S +Rule Lux 1917 only - Sep 17 1:00 0 - +Rule Lux 1918 only - Apr Mon>=15 2:00s 1:00 S +Rule Lux 1918 only - Sep Mon>=15 2:00s 0 - +Rule Lux 1919 only - Mar 1 23:00 1:00 S +Rule Lux 1919 only - Oct 5 3:00 0 - +Rule Lux 1920 only - Feb 14 23:00 1:00 S +Rule Lux 1920 only - Oct 24 2:00 0 - +Rule Lux 1921 only - Mar 14 23:00 1:00 S +Rule Lux 1921 only - Oct 26 2:00 0 - +Rule Lux 1922 only - Mar 25 23:00 1:00 S +Rule Lux 1922 only - Oct Sun>=2 1:00 0 - +Rule Lux 1923 only - Apr 21 23:00 1:00 S +Rule Lux 1923 only - Oct Sun>=2 2:00 0 - +Rule Lux 1924 only - Mar 29 23:00 1:00 S +Rule Lux 1924 1928 - Oct Sun>=2 1:00 0 - +Rule Lux 1925 only - Apr 5 23:00 1:00 S +Rule Lux 1926 only - Apr 17 23:00 1:00 S +Rule Lux 1927 only - Apr 9 23:00 1:00 S +Rule Lux 1928 only - Apr 14 23:00 1:00 S +Rule Lux 1929 only - Apr 20 23:00 1:00 S + +Zone Europe/Luxembourg 0:24:36 - LMT 1904 Jun + 1:00 Lux CE%sT 1918 Nov 25 + 0:00 Lux WE%sT 1929 Oct 6 2:00s + 0:00 Belgium WE%sT 1940 May 14 3:00 + 1:00 C-Eur WE%sT 1944 Sep 18 3:00 + 1:00 Belgium CE%sT 1977 + 1:00 EU CE%sT + +# Monaco +# +# From Michael Deckers (2020-06-12): +# In the "Journal de Monaco" of 1892-05-24, online at +# https://journaldemonaco.gouv.mc/var/jdm/storage/original/application/b1c67c12c5af11b41ea888fb048e4fe8.pdf +# we read: ... +# [In virtue of a Sovereign Ordinance of the May 13 of the current [year], +# legal time in the Principality will be set to, from the date of June 1, +# 1892 onwards, to the meridian of Paris, as in France.] +# In the "Journal de Monaco" of 1911-03-28, online at +# https://journaldemonaco.gouv.mc/var/jdm/storage/original/application/de74ffb7db53d4f599059fe8f0ed482a.pdf +# we read an ordinance of 1911-03-16: ... +# [Legal time in the Principality will be set, from the date of promulgation +# of the present ordinance, to legal time in France.... Consequently, legal +# time will be retarded by 9 minutes and 21 seconds.] +# +Zone Europe/Monaco 0:29:32 - LMT 1892 Jun 1 + 0:09:21 - PMT 1911 Mar 29 # Paris Mean Time + 0:00 France WE%sT 1945 Sep 16 3:00 + 1:00 France CE%sT 1977 + 1:00 EU CE%sT + + +# Norway + +# http://met.no/met/met_lex/q_u/sommertid.html (2004-01) agrees with Shanks & +# Pottenger. +Rule Norway 1916 only - May 22 1:00 1:00 S +Rule Norway 1916 only - Sep 30 0:00 0 - +Rule Norway 1945 only - Apr 2 2:00s 1:00 S +Rule Norway 1945 only - Oct 1 2:00s 0 - +Rule Norway 1959 1964 - Mar Sun>=15 2:00s 1:00 S +Rule Norway 1959 1965 - Sep Sun>=15 2:00s 0 - +Rule Norway 1965 only - Apr 25 2:00s 1:00 S + +Zone Europe/Oslo 0:43:00 - LMT 1895 Jan 1 + 1:00 Norway CE%sT 1940 Aug 10 23:00 + 1:00 C-Eur CE%sT 1945 Apr 2 2:00 + 1:00 Norway CE%sT 1980 + 1:00 EU CE%sT +Link Europe/Oslo Arctic/Longyearbyen +#PACKRATLIST zone.tab Link Europe/Oslo Atlantic/Jan_Mayen + +# Bosnia and Herzegovina +Zone Europe/Sarajevo 1:13:40 - LMT 1884 + 1:00 - CET 1941 Apr 18 23:00 + 1:00 C-Eur CE%sT 1945 May 8 2:00s + 1:00 1:00 CEST 1945 Sep 16 2:00s + 1:00 - CET 1982 Nov 27 + 1:00 EU CE%sT + +# North Macedonia +Zone Europe/Skopje 1:25:44 - LMT 1884 + 1:00 - CET 1941 Apr 18 23:00 + 1:00 C-Eur CE%sT 1945 May 8 2:00s + 1:00 1:00 CEST 1945 Sep 16 2:00s + 1:00 - CET 1982 Nov 27 + 1:00 EU CE%sT + + +# Sweden + +# From Ivan Nilsson (2001-04-13), superseding Shanks & Pottenger: +# +# The law "Svensk författningssamling 1878, no 14" about standard time in 1879: +# From the beginning of 1879 (that is 01-01 00:00) the time for all +# places in the country is "the mean solar time for the meridian at +# three degrees, or twelve minutes of time, to the west of the +# meridian of the Observatory of Stockholm". The law is dated 1878-05-31. +# +# The observatory at that time had the meridian 18° 03' 30" +# eastern longitude = 01:12:14 in time. Less 12 minutes gives the +# national standard time as 01:00:14 ahead of GMT.... +# +# About the beginning of CET in Sweden. The lawtext ("Svensk +# författningssamling 1899, no 44") states, that "from the beginning +# of 1900... ... the same as the mean solar time for the meridian at +# the distance of one hour of time from the meridian of the English +# observatory at Greenwich, or at 12 minutes 14 seconds to the west +# from the meridian of the Observatory of Stockholm". The law is dated +# 1899-06-16. In short: At 1900-01-01 00:00:00 the new standard time +# in Sweden is 01:00:00 ahead of GMT. +# +# 1916: The lawtext ("Svensk författningssamling 1916, no 124") states +# that "1916-05-15 is considered to begin one hour earlier". It is +# pretty obvious that at 05-14 23:00 the clocks are set to 05-15 00:00.... +# Further the law says, that "1916-09-30 is considered to end one hour later". +# +# The laws regulating [DST] are available on the site of the Swedish +# Parliament beginning with 1985 - the laws regulating 1980/1984 are +# not available on the site (to my knowledge they are only available +# in Swedish): (type +# "sommartid" without the quotes in the field "Fritext" and then click +# the Sök-button). +# +# (2001-05-13): +# +# I have now found a newspaper stating that at 1916-10-01 01:00 +# summertime the church-clocks etc were set back one hour to show +# 1916-10-01 00:00 standard time. The article also reports that some +# people thought the switch to standard time would take place already +# at 1916-10-01 00:00 summer time, but they had to wait for another +# hour before the event took place. +# +# Source: The newspaper "Dagens Nyheter", 1916-10-01, page 7 upper left. + +# An extra-special abbreviation style is SET for Swedish Time (svensk +# normaltid) 1879-1899, 3° west of the Stockholm Observatory. + +Zone Europe/Stockholm 1:12:12 - LMT 1879 Jan 1 + 1:00:14 - SET 1900 Jan 1 # Swedish Time + 1:00 - CET 1916 May 14 23:00 + 1:00 1:00 CEST 1916 Oct 1 1:00 + 1:00 - CET 1980 + 1:00 EU CE%sT + + +# Moldova / Transnistria +Zone Europe/Tiraspol 1:58:32 - LMT 1880 + 1:55 - CMT 1918 Feb 15 # Chisinau MT + 1:44:24 - BMT 1931 Jul 24 # Bucharest MT + 2:00 Romania EE%sT 1940 Aug 15 + 2:00 1:00 EEST 1941 Jul 17 + 1:00 C-Eur CE%sT 1944 Aug 24 + 3:00 Russia MSK/MSD 1991 Mar 31 2:00 + 2:00 Russia EE%sT 1992 Jan 19 2:00 + 3:00 Russia MSK/MSD + +# Ukraine +# +# Although Shanks & Pottenger say Transcarpathia used CET 1990/1991, +# this unreliable source contradicts contemporaneous government resolutions +# (see the commentary for Ukraine in the 'europe' file) +# so for now this dubious zone is in 'backzone'. +# "Uzhhorod" is the transliteration of the Ukrainian spelling, but +# "Uzhgorod" was a common English spelling when this dubious zone was +# added to TZDB in 1999. +Zone Europe/Uzhgorod 1:29:12 - LMT 1890 Oct + 1:00 - CET 1940 + 1:00 C-Eur CE%sT 1944 Oct + 1:00 1:00 CEST 1944 Oct 26 + 1:00 - CET 1945 Jun 29 + 3:00 Russia MSK/MSD 1990 + 3:00 - MSK 1990 Jul 1 2:00 + 1:00 - CET 1991 Mar 31 3:00 + 2:00 - EET 1992 Mar 20 + 2:00 C-Eur EE%sT 1996 May 13 + 2:00 EU EE%sT + +# Liechtenstein + +# From Paul Eggert (2022-07-21): +# Shanks & Pottenger say Vaduz is like Zurich starting June 1894. + +# From Alois Treindl (2019-07-04): +# I was able to access the online archive of the Vaduz paper Vaterland ... +# I could confirm from the paper that Liechtenstein did in fact follow +# the same DST in 1941 and 1942 as Switzerland did. + +Zone Europe/Vaduz 0:38:04 - LMT 1894 Jun + 1:00 Swiss CE%sT 1981 + 1:00 EU CE%sT + +# Croatia +Zone Europe/Zagreb 1:03:52 - LMT 1884 + 1:00 - CET 1941 Apr 18 23:00 + 1:00 C-Eur CE%sT 1945 May 8 2:00s + 1:00 1:00 CEST 1945 Sep 16 2:00s + 1:00 - CET 1982 Nov 27 + 1:00 EU CE%sT + +# Ukraine + +# Although Shanks & Pottenger say Zaporizhzhia and eastern Lugansk +# observed DST 1990/1991, this unreliable source contradicts contemporaneous +# government resolutions (see the commentary for Ukraine in the 'europe' file) +# so for now this dubious zone is in 'backzone'. +# "Zaporizhzhia" is the transliteration of the Ukrainian name, but +# "Zaporozhye" was a common English spelling when this dubious zone was +# added to TZDB in 1999. +Zone Europe/Zaporozhye 2:20:40 - LMT 1880 + 2:20 - +0220 1924 May 2 + 2:00 - EET 1930 Jun 21 + 3:00 - MSK 1941 Aug 25 + 1:00 C-Eur CE%sT 1943 Oct 25 + 3:00 Russia MSK/MSD 1991 Mar 31 2:00 + 2:00 E-Eur EE%sT 1992 Mar 20 + 2:00 C-Eur EE%sT 1996 May 13 + 2:00 EU EE%sT + +# Madagascar +Zone Indian/Antananarivo 3:10:04 - LMT 1911 Jul + 3:00 - EAT 1954 Feb 27 23:00s + 3:00 1:00 EAST 1954 May 29 23:00s + 3:00 - EAT + +# Christmas +Zone Indian/Christmas 7:02:52 - LMT 1895 Feb + 7:00 - +07 + +# Cocos (Keeling) Is +# These islands were ruled by the Ross family from about 1830 to 1978. +# We don't know when standard time was introduced; for now, we guess 1900. +Zone Indian/Cocos 6:27:40 - LMT 1900 + 6:30 - +0630 + +# Comoros +Zone Indian/Comoro 2:53:04 - LMT 1911 Jul # Moroni, Gran Comoro + 3:00 - EAT + +# Kerguelen +Zone Indian/Kerguelen 0 - -00 1950 # Port-aux-Français + 5:00 - +05 + +# Seychelles +# +# From P Chan (2020-11-27): +# Standard Time was adopted on 1907-01-01. +# +# Standard Time Ordinance (Chapter 237) +# The Laws of Seychelles in Force on the 31st December, 1971, Vol. 6, p 571 +# https://books.google.com/books?id=efE-AQAAIAAJ&pg=PA571 +# +# From Tim Parenti (2020-12-05): +# A footnote on https://books.google.com/books?id=DYdDAQAAMAAJ&pg=PA1689 +# confirms that Ordinance No. 9 of 1906 "was brought into force on the 1st +# January, 1907." + +Zone Indian/Mahe 3:41:48 - LMT 1907 Jan 1 # Victoria + 4:00 - +04 +# From Paul Eggert (2001-05-30): +# Aldabra, Farquhar, and Desroches, originally dependencies of the +# Seychelles, were transferred to the British Indian Ocean Territory +# in 1965 and returned to Seychelles control in 1976. We don't know +# whether this affected their time zone, so omit this for now. +# Possibly the islands were uninhabited. + + +# Mayotte +Zone Indian/Mayotte 3:00:56 - LMT 1911 Jul # Mamoutzou + 3:00 - EAT + +# Réunion +Zone Indian/Reunion 3:41:52 - LMT 1911 Jun # Saint-Denis + 4:00 - +04 +# +# Scattered Islands (Îles Éparses) administered from Réunion are as follows. +# The following information about them is taken from +# Îles Éparses (, 1997-07-22, +# in French; no longer available as of 1999-08-17). +# We have no info about their time zone histories. +# +# Bassas da India - uninhabited +# Europa Island - inhabited from 1905 to 1910 by two families +# Glorioso Is - inhabited until at least 1958 +# Juan de Nova - uninhabited +# Tromelin - inhabited until at least 1958 + +# Micronesia +# Also see Pacific/Pohnpei and commentary for Micronesia in 'australasia'. +# +# From Paul Eggert (2018-11-18): +# Alan Eugene Davis writes (1996-03-16), +# "I am certain, having lived there for the past decade, that 'Truk' +# (now properly known as Chuuk) ... is in the time zone GMT+10." +# Shanks & Pottenger write that Truk switched from UT +10 to +11 +# on 1978-10-01; ignore this for now. +Zone Pacific/Chuuk -13:52:52 - LMT 1844 Dec 31 + 10:07:08 - LMT 1901 + 10:00 - +10 1914 Oct + 9:00 - +09 1919 Feb 1 + 10:00 - +10 1941 Apr 1 + 9:00 - +09 1945 Aug + 10:00 - +10 +Link Pacific/Chuuk Pacific/Truk +Link Pacific/Chuuk Pacific/Yap + +# Phoenix Islands, Kiribati +# From Paul Eggert (2021-05-27): +# Enderbury was inhabited 1860/1880s to mine guano, and 1938-03-06/1942-02-09 +# for aviation (ostensibly commercial, but military uses foreseen). +# The 19th-century dates are approximate. See Pacific/Kanton for +# the currently inhabited representative for this timezone. +Zone Pacific/Enderbury 0 - -00 1860 + -11:24:20 - LMT 1885 + 0 - -00 1938 Mar 6 + -12:00 - -12 1942 Feb 9 + 0 - -00 + +# Tuvalu +Zone Pacific/Funafuti 11:56:52 - LMT 1901 + 12:00 - +12 + +# Johnston +Zone Pacific/Johnston -10:00 - HST + +# Marshall Is +Zone Pacific/Majuro 11:24:48 - LMT 1901 + 11:00 - +11 1914 Oct + 9:00 - +09 1919 Feb 1 + 11:00 - +11 1937 + 10:00 - +10 1941 Apr 1 + 9:00 - +09 1944 Jan 30 + 11:00 - +11 1969 Oct + 12:00 - +12 + +# Midway +# +# From Mark Brader (2005-01-23): +# [Fallacies and Fantasies of Air Transport History, by R.E.G. Davies, +# published 1994 by Paladwr Press, McLean, VA, USA; ISBN 0-9626483-5-3] +# reproduced a Pan American Airways timetable from 1936, for their weekly +# "Orient Express" flights between San Francisco and Manila, and connecting +# flights to Chicago and the US East Coast. As it uses some time zone +# designations that I've never seen before:.... +# Fri. 6:30A Lv. HONOLOLU (Pearl Harbor), H.I. H.L.T. Ar. 5:30P Sun. +# " 3:00P Ar. MIDWAY ISLAND . . . . . . . . . M.L.T. Lv. 6:00A " +# +Zone Pacific/Midway -11:49:28 - LMT 1901 + -11:00 - -11 1956 Jun 3 + -11:00 1:00 -10 1956 Sep 2 + -11:00 - SST # S=Samoa + +# Micronesia +# Also see Pacific/Chuuk and commentary for Micronesia in 'australasia'. +Zone Pacific/Pohnpei -13:27:08 - LMT 1844 Dec 31 # Kolonia + 10:32:52 - LMT 1901 + 11:00 - +11 1914 Oct + 9:00 - +09 1919 Feb 1 + 11:00 - +11 1937 + 10:00 - +10 1941 Apr 1 + 9:00 - +09 1945 Aug + 11:00 - +11 +Link Pacific/Pohnpei Pacific/Ponape + +# N Mariana Is +# +# From Paul Eggert (2022-08-16): +# Although Shanks & Pottenger say Saipan used +09 and then switched +# to Guam time in October 1969, this is surely wrong. +# Saipan used Guam time in the late 1950s; see page 4 of the minutes on the +# conference of the 12th Saipan Legislature and the Select Committee on +# Saipan Mission, 5th Guam Legislature (1959-09-11): +# http://www.nmhcouncil.org/nmhc_archives/U.S.%20Navy%20Civil%20Affairs%20Files%201944-1962/1959/1959%2009%2017%20letter,%20minutes%20of%20conference,%20Borja.pdf +# For now, assume Saipan switched to Guam time after the Battle of Saipan. +# +Zone Pacific/Saipan -14:17:00 - LMT 1844 Dec 31 + 9:43:00 - LMT 1901 + 9:00 - +09 1944 Jul 9 + 10:00 Guam G%sT 2000 Dec 23 + 10:00 - ChST # Chamorro Standard Time + + +# Wake + +# From Vernice Anderson, Personal Secretary to Philip Jessup, +# US Ambassador At Large (oral history interview, 1971-02-02): +# +# Saturday, the 14th [of October, 1950] - ... The time was all the +# more confusing at that point, because we had crossed the +# International Date Line, thus getting two Sundays. Furthermore, we +# discovered that Wake Island had two hours of daylight saving time +# making calculation of time in Washington difficult if not almost +# impossible. +# +# https://www.trumanlibrary.org/oralhist/andrsonv.htm + +# From Paul Eggert (2003-03-23): +# We have no other report of DST in Wake Island, so omit this info for now. + +# Also see commentary for Micronesia in 'australasia'. +Zone Pacific/Wake 11:06:28 - LMT 1901 + 12:00 - +12 + + +# Wallis and Futuna +Zone Pacific/Wallis 12:15:20 - LMT 1901 + 12:00 - +12 + +# Local Variables: +# coding: utf-8 +# End: diff --git a/vendor/chrono-tz/tz/calendars b/vendor/chrono-tz/tz/calendars new file mode 100644 index 0000000000000..f4ed9e434e500 --- /dev/null +++ b/vendor/chrono-tz/tz/calendars @@ -0,0 +1,173 @@ +----- Calendrical issues ----- + +As mentioned in Theory.html, although calendrical issues are out of +scope for tzdb, they indicate the sort of problems that we would run +into if we extended tzdb further into the past. The following +information and sources go beyond Theory.html's brief discussion. +They sometimes disagree. + + +France + +Gregorian calendar adopted 1582-12-20. +French Revolutionary calendar used 1793-11-24 through 1805-12-31, +and (in Paris only) 1871-05-06 through 1871-05-23. + + +Russia + +From Chris Carrier (1996-12-02): +On 1929-10-01 the Soviet Union instituted an "Eternal Calendar" +with 30-day months plus 5 holidays, with a 5-day week. +On 1931-12-01 it changed to a 6-day week; in 1934 it reverted to the +Gregorian calendar while retaining the 6-day week; on 1940-06-27 it +reverted to the 7-day week. With the 6-day week the usual days +off were the 6th, 12th, 18th, 24th and 30th of the month. +(Source: Evitiar Zerubavel, _The Seven Day Circle_) + + +Mark Brader reported a similar story in "The Book of Calendars", edited +by Frank Parise (1982, Facts on File, ISBN 0-8719-6467-8), page 377. But: + +From: Petteri Sulonen (via Usenet) +Date: 14 Jan 1999 00:00:00 GMT +... + +If your source is correct, how come documents between 1929 and 1940 were +still dated using the conventional, Gregorian calendar? + +I can post a scan of a document dated December 1, 1934, signed by +Yenukidze, the secretary, on behalf of Kalinin, the President of the +Executive Committee of the Supreme Soviet, if you like. + + + +Sweden (and Finland) + +From: Mark Brader +Subject: Re: Gregorian reform - a part of locale? + +Date: 1996-07-06 + +In 1700, Denmark made the transition from Julian to Gregorian. Sweden +decided to *start* a transition in 1700 as well, but rather than have one of +those unsightly calendar gaps :-), they simply decreed that the next leap +year after 1696 would be in 1744 - putting the whole country on a calendar +different from both Julian and Gregorian for a period of 40 years. + +However, in 1704 something went wrong and the plan was not carried through; +they did, after all, have a leap year that year. And one in 1708. In 1712 +they gave it up and went back to Julian, putting 30 days in February that +year!... + +Then in 1753, Sweden made the transition to Gregorian in the usual manner, +getting there only 13 years behind the original schedule. + +(A previous posting of this story was challenged, and Swedish readers +produced the following references to support it: "Tideräkning och historia" +by Natanael Beckman (1924) and "Tid, en bok om tideräkning och +kalenderväsen" by Lars-Olof Lodén (1968). + + +Grotefend's data + +From: "Michael Palmer" [with two obvious typos fixed] +Subject: Re: Gregorian Calendar (was Re: Another FHC related question +Newsgroups: soc.genealogy.german +Date: Tue, 9 Feb 1999 02:32:48 -800 +... + +The following is a(n incomplete) listing, arranged chronologically, of +European states, with the date they converted from the Julian to the +Gregorian calendar: + +04/15 Oct 1582 - Italy (with exceptions), Spain, Portugal, Poland (Roman + Catholics and Danzig only) +09/20 Dec 1582 - France, Lorraine + +21 Dec 1582/ + 01 Jan 1583 - Holland, Brabant, Flanders, Hennegau +10/21 Feb 1583 - bishopric of Liege (Lüttich) +13/24 Feb 1583 - bishopric of Augsburg +04/15 Oct 1583 - electorate of Trier +05/16 Oct 1583 - Bavaria, bishoprics of Freising, Eichstedt, Regensburg, + Salzburg, Brixen +13/24 Oct 1583 - Austrian Oberelsaß and Breisgau +20/31 Oct 1583 - bishopric of Basel +02/13 Nov 1583 - duchy of Jülich-Berg +02/13 Nov 1583 - electorate and city of Köln +04/15 Nov 1583 - bishopric of Würzburg +11/22 Nov 1583 - electorate of Mainz +16/27 Nov 1583 - bishopric of Strassburg and the margraviate of Baden +17/28 Nov 1583 - bishopric of Münster and duchy of Cleve +14/25 Dec 1583 - Steiermark + +06/17 Jan 1584 - Austria and Bohemia +11/22 Jan 1584 - Lucerne, Uri, Schwyz, Zug, Freiburg, Solothurn +12/23 Jan 1584 - Silesia and the Lausitz +22 Jan/ + 02 Feb 1584 - Hungary (legally on 21 Oct 1587) + Jun 1584 - Unterwalden +01/12 Jul 1584 - duchy of Westfalen + +16/27 Jun 1585 - bishopric of Paderborn + +14/25 Dec 1590 - Transylvania + +22 Aug/ + 02 Sep 1612 - duchy of Prussia + +13/24 Dec 1614 - Pfalz-Neuburg + + 1617 - duchy of Kurland (reverted to the Julian calendar in + 1796) + + 1624 - bishopric of Osnabrück + + 1630 - bishopric of Minden + +15/26 Mar 1631 - bishopric of Hildesheim + + 1655 - Kanton Wallis + +05/16 Feb 1682 - city of Strassburg + +18 Feb/ + 01 Mar 1700 - Protestant Germany (including Swedish possessions in + Germany), Denmark, Norway +30 Jun/ + 12 Jul 1700 - Gelderland, Zutphen +10 Nov/ + 12 Dec 1700 - Utrecht, Overijssel + +31 Dec 1700/ + 12 Jan 1701 - Friesland, Groningen, Zürich, Bern, Basel, Geneva, + Thurgau, and Schaffhausen + + 1724 - Glarus, Appenzell, and the city of St. Gallen + +01 Jan 1750 - Pisa and Florence + +02/14 Sep 1752 - Great Britain + +17 Feb/ + 01 Mar 1753 - Sweden + +1760-1812 - Graubünden + +The Russian empire (including Finland and the Baltic states) did not +convert to the Gregorian calendar until the Soviet revolution of 1917. + +Source: H. Grotefend, _Taschenbuch der Zeitrechnung des deutschen +Mittelalters und der Neuzeit_, herausgegeben von Dr. O. Grotefend +(Hannover: Hahnsche Buchhandlung, 1941), pp. 26-28. + +----- + +This file is in the public domain, so clarified as of 2009-05-17 by +Arthur David Olson. + +----- +Local Variables: +coding: utf-8 +End: diff --git a/vendor/chrono-tz/tz/checklinks.awk b/vendor/chrono-tz/tz/checklinks.awk new file mode 100644 index 0000000000000..82a5feab8399b --- /dev/null +++ b/vendor/chrono-tz/tz/checklinks.awk @@ -0,0 +1,70 @@ +# Check links in tz tables. + +# Contributed by Paul Eggert. This file is in the public domain. + +BEGIN { + # Special marker indicating that the name is defined as a Zone. + # It is a newline so that it cannot match a valid name. + # It is not null so that its slot does not appear unset. + Zone = "\n" +} + +/^Z/ { + if (defined[$2]) { + if (defined[$2] == Zone) { + printf "%s: Zone has duplicate definition\n", $2 + } else { + printf "%s: Link with same name as Zone\n", $2 + } + status = 1 + } + defined[$2] = Zone +} + +/^L/ { + if (defined[$3]) { + if (defined[$3] == Zone) { + printf "%s: Link with same name as Zone\n", $3 + } else if (defined[$3] == $2) { + printf "%s: Link has duplicate definition\n", $3 + } else { + printf "%s: Link to both %s and %s\n", $3, defined[$3], $2 + } + status = 1 + } + if (backcheck && FILENAME != backcheck && $3 != "GMT") { + printf "%s: Link should be in '%s'\n", $3, backcheck + status = 1 + } + if ($4 == "#=") { + shortcut[$5] = $3 + } + used[$2] = 1 + defined[$3] = $2 +} + +END { + for (tz in used) { + if (defined[tz] != Zone) { + if (!defined[tz]) { + printf "%s: Link to nowhere\n", tz + status = 1 + } else if (DATAFORM != "vanguard") { + printf "%s: Link to link\n", tz + status = 1 + } + } + } + for (tz in shortcut) { + if (defined[shortcut[tz]] != defined[tz]) { + target = (!defined[tz] ? "absence" \ + : defined[tz] == "\n" ? "zone" \ + : defined[tz]) + printf "%s: target %s disagrees with %s's target %s\n", \ + tz, target, shortcut[tz], defined[shortcut[tz]] + status = 1 + } + } + + exit status +} diff --git a/vendor/chrono-tz/tz/checknow.awk b/vendor/chrono-tz/tz/checknow.awk new file mode 100644 index 0000000000000..57ff3c02e7893 --- /dev/null +++ b/vendor/chrono-tz/tz/checknow.awk @@ -0,0 +1,54 @@ +# Check zonenow.tab for consistency with primary data. + +# Contributed by Paul Eggert. This file is in the public domain. + +function record_zone(zone, data) { + if (zone) { + zone_data[zone] = data + zones[data] = zones[data] " " zone + } +} + +BEGIN { + while (getline >"/dev/stderr" + status = 1 + } + cc = $1 + name = $2 + if (cc !~ /^[A-Z][A-Z]$/) { + printf "%s:%d: invalid country code '%s'\n", \ + iso_table, iso_NR, cc >>"/dev/stderr" + status = 1 + } + if (cc <= cc0) { + if (cc == cc0) { + s = "duplicate"; + } else { + s = "out of order"; + } + + printf "%s:%d: country code '%s' is %s\n", \ + iso_table, iso_NR, cc, s \ + >>"/dev/stderr" + status = 1 + } + cc0 = cc + if (name2cc[name]) { + printf "%s:%d: '%s' and '%s' have the same name\n", \ + iso_table, iso_NR, name2cc[name], cc \ + >>"/dev/stderr" + status = 1 + } + name2cc[name] = cc + cc2name[cc] = name + cc2NR[cc] = iso_NR + } + + cc0 = "" + + while (getline >"/dev/stderr" + status = 1 + } + ccs = input_ccs[zone_NR] = $1 + coordinates = $2 + tz = $3 + comments = input_comments[zone_NR] = $4 + split(ccs, cca, /,/) + cc = cca[1] + + # Don't complain about a special case for Crimea in zone.tab. + # FIXME: zone.tab should be removed, since it is obsolete. + # Or at least put just "XX" in its country-code column. + if (cc < cc0 \ + && !(zone_table == "zone.tab" \ + && tz0 == "Europe/Simferopol")) { + printf "%s:%d: country code '%s' is out of order\n", \ + zone_table, zone_NR, cc >>"/dev/stderr" + status = 1 + } + cc0 = cc + tz0 = tz + tztab[tz] = 1 + tz2NR[tz] = zone_NR + for (i in cca) { + cc = cca[i] + if (cc2name[cc]) { + cc_used[cc]++ + } else if (! (cc == "XX" && zone_table == "zonenow.tab")) { + printf "%s:%d: %s: unknown country code\n", \ + zone_table, zone_NR, cc >>"/dev/stderr" + status = 1 + } + } + if (coordinates !~ /^[-+][0-9][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9]$/ \ + && coordinates !~ /^[-+][0-9][0-9][0-5][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9][0-5][0-9]$/) { + printf "%s:%d: %s: invalid coordinates\n", \ + zone_table, zone_NR, coordinates >>"/dev/stderr" + status = 1 + } + } + + for (i = 1; i <= zone_NR; i++) { + ccs = input_ccs[i] + if (!ccs) continue + comments = input_comments[i] + split(ccs, cca, /,/) + used_max = 0 + for (j in cca) { + cc = cca[j] + if (used_max < cc_used[cc]) { + used_max = cc_used[cc] + used_max_cc = cc + } + } + if (used_max <= 1 && comments && zone_table != "zonenow.tab") { + printf "%s:%d: unnecessary comment '%s'\n", \ + zone_table, i, comments \ + >>"/dev/stderr" + status = 1 + } else if (1 < used_max && !comments) { + printf "%s:%d: missing comment for %s\n", \ + zone_table, i, used_max_cc \ + >>"/dev/stderr" + status = 1 + } + } + FS = " " +} + +$1 ~ /^#/ { next } + +{ + tz = rules = "" + if ($1 == "Zone") { + tz = $2 + ruleUsed[$4] = 1 + if ($5 ~ /%/) rulePercentUsed[$4] = 1 + } else if ($1 == "Link" && zone_table == "zone.tab") { + # Ignore Link commands if source and destination basenames + # are identical, e.g. Europe/Istanbul versus Asia/Istanbul. + src = $2 + dst = $3 + while ((i = index(src, "/"))) src = substr(src, i+1) + while ((i = index(dst, "/"))) dst = substr(dst, i+1) + if (src != dst) tz = $3 + } else if ($1 == "Rule") { + ruleDefined[$2] = 1 + if ($10 != "-") ruleLetters[$2] = 1 + } else { + ruleUsed[$2] = 1 + if ($3 ~ /%/) rulePercentUsed[$2] = 1 + } + if (tz && tz ~ /\// && tz !~ /^Etc\//) { + if (!tztab[tz] && FILENAME != "backward" \ + && zone_table != "zonenow.tab") { + printf "%s: no data for '%s'\n", zone_table, tz \ + >>"/dev/stderr" + status = 1 + } + zoneSeen[tz] = 1 + } +} + +END { + for (tz in ruleDefined) { + if (!ruleUsed[tz]) { + printf "%s: Rule never used\n", tz + status = 1 + } + } + for (tz in ruleLetters) { + if (!rulePercentUsed[tz]) { + printf "%s: Rule contains letters never used\n", tz + status = 1 + } + } + for (tz in tztab) { + if (!zoneSeen[tz] && tz !~ /^Etc\//) { + printf "%s:%d: no Zone table for '%s'\n", \ + zone_table, tz2NR[tz], tz >>"/dev/stderr" + status = 1 + } + } + if (0 < want_warnings) { + for (cc in cc2name) { + if (!cc_used[cc]) { + printf "%s:%d: warning: " \ + "no Zone entries for %s (%s)\n", \ + iso_table, cc2NR[cc], cc, cc2name[cc] + } + } + } + + exit status +} diff --git a/vendor/chrono-tz/tz/date.1 b/vendor/chrono-tz/tz/date.1 new file mode 100644 index 0000000000000..01907bc76e2ce --- /dev/null +++ b/vendor/chrono-tz/tz/date.1 @@ -0,0 +1,164 @@ +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. +.TH date 1 "" "Time Zone Database" +.SH NAME +date \- show and set date and time +.SH SYNOPSIS +.if n .nh +.if n .na +.ie \n(.g .ds - \f(CR-\fP +.el .ds - \- +.B date +[ +.B \*-u +] [ +.B \*-c +] [ +.B \*-r +.I seconds +] [ +.BI + format +] [ +\fR[\fIyyyy\fR]\fImmddhhmm\fR[\fIyy\fR][\fB.\fIss\fR] +] +.SH DESCRIPTION +.ie '\(lq'' .ds lq \&"\" +.el .ds lq \(lq\" +.ie '\(rq'' .ds rq \&"\" +.el .ds rq \(rq\" +.de q +\\$3\*(lq\\$1\*(rq\\$2 +.. +The +.B date +command +without arguments writes the date and time to the standard output in +the form +.ce 1 +Wed Mar 8 14:54:40 EST 1989 +.br +with +.B EST +replaced by the local time zone's abbreviation +(or by the abbreviation for the time zone specified in the +.B TZ +environment variable if set). +The exact output format depends on the locale. +.PP +If a command-line argument starts with a plus sign (\c +.q "\fB+\fP" ), +the rest of the argument is used as a +.I format +that controls what appears in the output. +In the format, when a percent sign (\c +.q "\fB%\fP" +appears, +it and the character after it are not output, +but rather identify part of the date or time +to be output in a particular way +(or identify a special character to output): +.nf +.sp +.if t .in +.5i +.if n .in +2 +.ta \w'%M\0\0'u +\w'Wed Mar 8 14:54:40 EST 1989\0\0'u + Sample output Explanation +%a Wed Abbreviated weekday name* +%A Wednesday Full weekday name* +%b Mar Abbreviated month name* +%B March Full month name* +%c Wed Mar 08 14:54:40 1989 Date and time* +%C 19 Century +%d 08 Day of month (always two digits) +%D 03/08/89 Month/day/year (eight characters) +%e 8 Day of month (leading zero blanked) +%h Mar Abbreviated month name* +%H 14 24-hour-clock hour (two digits) +%I 02 12-hour-clock hour (two digits) +%j 067 Julian day number (three digits) +%k 2 12-hour-clock hour (leading zero blanked) +%l 14 24-hour-clock hour (leading zero blanked) +%m 03 Month number (two digits) +%M 54 Minute (two digits) +%n \\n newline character +%p PM AM/PM designation +%r 02:54:40 PM Hour:minute:second AM/PM designation +%R 14:54 Hour:minute +%S 40 Second (two digits) +%t \\t tab character +%T 14:54:40 Hour:minute:second +%U 10 Sunday-based week number (two digits) +%w 3 Day number (one digit, Sunday is 0) +%W 10 Monday-based week number (two digits) +%x 03/08/89 Date* +%X 14:54:40 Time* +%y 89 Last two digits of year +%Y 1989 Year in full +%z -0500 Numeric time zone +%Z EST Time zone abbreviation +%+ Wed Mar 8 14:54:40 EST 1989 Default output format* +.if t .in -.5i +.if n .in -2 +* The exact output depends on the locale. +.sp +.fi +If a character other than one of those shown above appears after +a percent sign in the format, +that following character is output. +All other characters in the format are copied unchanged to the output; +a newline character is always added at the end of the output. +.PP +In Sunday-based week numbering, +the first Sunday of the year begins week 1; +days preceding it are part of +.q "week 0" . +In Monday-based week numbering, +the first Monday of the year begins week 1. +.PP +To set the date, use a command line argument with one of the following forms: +.nf +.if t .in +.5i +.if n .in +2 +.ta \w'198903081454\0'u +1454 24-hour-clock hours (first two digits) and minutes +081454 Month day (first two digits), hours, and minutes +03081454 Month (two digits, January is 01), month day, hours, minutes +8903081454 Year, month, month day, hours, minutes +0308145489 Month, month day, hours, minutes, year + (on System V-compatible systems) +030814541989 Month, month day, hours, minutes, four-digit year +198903081454 Four-digit year, month, month day, hours, minutes +.if t .in -.5i +.if n .in -2 +.fi +If the century, year, month, or month day is not given, +the current value is used. +Any of the above forms may be followed by a period and two digits that give +the seconds part of the new time; if no seconds are given, zero is assumed. +.PP +These options are available: +.TP +.BR \*-u " or " \*-c +Use Universal Time when setting and showing the date and time. +.TP +.BI "\*-r " seconds +Output the date that corresponds to +.I seconds +past the epoch of 1970-01-01 00:00:00 UTC, where +.I seconds +should be an integer, either decimal, octal (leading 0), or +hexadecimal (leading 0x), preceded by an optional sign. +.SH FILES +.ta \w'/usr/share/zoneinfo/posixrules\0\0'u +/etc/localtime local timezone file +.br +/usr/lib/locale/\f2L\fP/LC_TIME description of time locale \f2L\fP +.br +/usr/share/zoneinfo timezone directory +.br +/usr/share/zoneinfo/posixrules default DST rules (obsolete) +.br +/usr/share/zoneinfo/GMT for UTC leap seconds +.PP +If /usr/share/zoneinfo/GMT is absent, +UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present. diff --git a/vendor/chrono-tz/tz/date.c b/vendor/chrono-tz/tz/date.c new file mode 100644 index 0000000000000..b62f04d768bc0 --- /dev/null +++ b/vendor/chrono-tz/tz/date.c @@ -0,0 +1,217 @@ +/* Display or set the current time and date. */ + +/* Copyright 1985, 1987, 1988 The Regents of the University of California. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. */ + +#include "private.h" +#include +#include + +#if !HAVE_POSIX_DECLS +extern char * optarg; +extern int optind; +#endif + +static int retval = EXIT_SUCCESS; + +static void display(const char *, time_t); +static void dogmt(void); +static void errensure(void); +static void timeout(FILE *, const char *, const struct tm *); +ATTRIBUTE_NORETURN static void usage(void); + +int +main(const int argc, char *argv[]) +{ + register const char * format = "+%+"; + register int ch; + register bool rflag = false; + time_t t; + intmax_t secs; + char * endarg; + +#ifdef LC_ALL + setlocale(LC_ALL, ""); +#endif /* defined(LC_ALL) */ +#if HAVE_GETTEXT +# ifdef TZ_DOMAINDIR + bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); +# endif /* defined(TEXTDOMAINDIR) */ + textdomain(TZ_DOMAIN); +#endif /* HAVE_GETTEXT */ + t = time(NULL); + while ((ch = getopt(argc, argv, "ucr:")) != EOF && ch != -1) { + switch (ch) { + default: + usage(); + case 'u': /* do it in UT */ + case 'c': + dogmt(); + break; + case 'r': /* seconds since 1970 */ + if (rflag) { + fprintf(stderr, + _("date: error: multiple -r's used")); + usage(); + } + rflag = true; + errno = 0; + secs = strtoimax(optarg, &endarg, 0); + if (*endarg || optarg == endarg) + errno = EINVAL; + else if (! (TIME_T_MIN <= secs && secs <= TIME_T_MAX)) + errno = ERANGE; + if (errno) { + char const *e = strerror(errno); + fprintf(stderr, _("date: %s: %s\n"), + optarg, e); + errensure(); + exit(retval); + } + t = secs; + break; + } + } + if (optind < argc) { + if (argc - optind != 1) { + fprintf(stderr, + _("date: error: multiple operands in command line\n")); + usage(); + } + format = argv[optind]; + if (*format != '+') { + fprintf(stderr, _("date: unknown operand: %s\n"), format); + usage(); + } + } + + display(format, t); + return retval; +} + +static void +dogmt(void) +{ + static char ** fakeenv; + + if (fakeenv == NULL) { + static char tzeutc0[] = "TZ=UTC0"; + ptrdiff_t from, to, n; + + for (n = 0; environ[n] != NULL; ++n) + continue; +#if defined ckd_add && defined ckd_mul + if (!ckd_add(&n, n, 2) && !ckd_mul(&n, n, sizeof *fakeenv) + && n <= INDEX_MAX) + fakeenv = malloc(n); +#else + if (n <= INDEX_MAX / sizeof *fakeenv - 2) + fakeenv = malloc((n + 2) * sizeof *fakeenv); +#endif + if (fakeenv == NULL) { + fprintf(stderr, _("date: Memory exhausted\n")); + errensure(); + exit(retval); + } + to = 0; + fakeenv[to++] = tzeutc0; + for (from = 1; environ[from] != NULL; ++from) + if (strncmp(environ[from], "TZ=", 3) != 0) + fakeenv[to++] = environ[from]; + fakeenv[to] = NULL; + environ = fakeenv; + } +} + +static void +errensure(void) +{ + if (retval == EXIT_SUCCESS) + retval = EXIT_FAILURE; +} + +static void +usage(void) +{ + fprintf(stderr, + _("date: usage: date [-u] [-c] [-r seconds]" + " [+format]\n")); + errensure(); + exit(retval); +} + +static void +display(char const *format, time_t now) +{ + struct tm *tmp; + + tmp = localtime(&now); + if (!tmp) { + fprintf(stderr, + _("date: error: time out of range\n")); + errensure(); + return; + } + timeout(stdout, format, tmp); + putchar('\n'); + fflush(stdout); + fflush(stderr); + if (ferror(stdout) || ferror(stderr)) { + fprintf(stderr, + _("date: error: couldn't write results\n")); + errensure(); + } +} + +static void +timeout(FILE *fp, char const *format, struct tm const *tmp) +{ + char *cp = NULL; + ptrdiff_t result; + ptrdiff_t size = 1024 / 2; + + for ( ; ; ) { +#ifdef ckd_mul + bool bigger = !ckd_mul(&size, size, 2) && size <= INDEX_MAX; +#else + bool bigger = size <= INDEX_MAX / 2 && (size *= 2, true); +#endif + char *newcp = bigger ? realloc(cp, size) : NULL; + if (!newcp) { + fprintf(stderr, + _("date: error: can't get memory\n")); + errensure(); + exit(retval); + } + cp = newcp; + result = strftime(cp, size, format, tmp); + if (result != 0) + break; + } + fwrite(cp + 1, 1, result - 1, fp); + free(cp); +} diff --git a/vendor/chrono-tz/tz/difftime.c b/vendor/chrono-tz/tz/difftime.c new file mode 100644 index 0000000000000..ff78f03c5705e --- /dev/null +++ b/vendor/chrono-tz/tz/difftime.c @@ -0,0 +1,60 @@ +/* Return the difference between two timestamps. */ + +/* +** This file is in the public domain, so clarified as of +** 1996-06-05 by Arthur David Olson. +*/ + +/*LINTLIBRARY*/ + +#include "private.h" /* for time_t and TYPE_SIGNED */ + +/* Return -X as a double. Using this avoids casting to 'double'. */ +static double +dminus(double x) +{ + return -x; +} + +double +difftime(time_t time1, time_t time0) +{ + /* + ** If double is large enough, simply convert and subtract + ** (assuming that the larger type has more precision). + */ + if (sizeof(time_t) < sizeof(double)) { + double t1 = time1, t0 = time0; + return t1 - t0; + } + + /* + ** The difference of two unsigned values can't overflow + ** if the minuend is greater than or equal to the subtrahend. + */ + if (!TYPE_SIGNED(time_t)) + return time0 <= time1 ? time1 - time0 : dminus(time0 - time1); + + /* Use uintmax_t if wide enough. */ + if (sizeof(time_t) <= sizeof(uintmax_t)) { + uintmax_t t1 = time1, t0 = time0; + return time0 <= time1 ? t1 - t0 : dminus(t0 - t1); + } + + /* + ** Handle cases where both time1 and time0 have the same sign + ** (meaning that their difference cannot overflow). + */ + if ((time1 < 0) == (time0 < 0)) + return time1 - time0; + + /* + ** The values have opposite signs and uintmax_t is too narrow. + ** This suffers from double rounding; attempt to lessen that + ** by using long double temporaries. + */ + { + long double t1 = time1, t0 = time0; + return t1 - t0; + } +} diff --git a/vendor/chrono-tz/tz/factory b/vendor/chrono-tz/tz/factory new file mode 100644 index 0000000000000..9f5fc33023a30 --- /dev/null +++ b/vendor/chrono-tz/tz/factory @@ -0,0 +1,12 @@ +# tzdb data for noncommittal factory settings + +# This file is in the public domain, so clarified as of +# 2009-05-17 by Arthur David Olson. + +# For distributors who don't want to specify a timezone in their +# installation procedures. Users who run 'date' will get the +# time zone abbreviation "-00", indicating that the actual time zone +# is unknown. + +# Zone NAME STDOFF RULES FORMAT +Zone Factory 0 - -00 diff --git a/vendor/chrono-tz/tz/iso3166.tab b/vendor/chrono-tz/tz/iso3166.tab new file mode 100644 index 0000000000000..402c015ec6b10 --- /dev/null +++ b/vendor/chrono-tz/tz/iso3166.tab @@ -0,0 +1,279 @@ +# ISO 3166 alpha-2 country codes +# +# This file is in the public domain, so clarified as of +# 2009-05-17 by Arthur David Olson. +# +# From Paul Eggert (2023-09-06): +# This file contains a table of two-letter country codes. Columns are +# separated by a single tab. Lines beginning with '#' are comments. +# All text uses UTF-8 encoding. The columns of the table are as follows: +# +# 1. ISO 3166-1 alpha-2 country code, current as of +# ISO/TC 46 N1108 (2023-04-05). See: ISO/TC 46 Documents +# https://www.iso.org/committee/48750.html?view=documents +# 2. The usual English name for the coded region. This sometimes +# departs from ISO-listed names, sometimes so that sorted subsets +# of names are useful (e.g., "Samoa (American)" and "Samoa +# (western)" rather than "American Samoa" and "Samoa"), +# sometimes to avoid confusion among non-experts (e.g., +# "Czech Republic" and "Turkey" rather than "Czechia" and "Türkiye"), +# and sometimes to omit needless detail or churn (e.g., "Netherlands" +# rather than "Netherlands (the)" or "Netherlands (Kingdom of the)"). +# +# The table is sorted by country code. +# +# This table is intended as an aid for users, to help them select time +# zone data appropriate for their practical needs. It is not intended +# to take or endorse any position on legal or territorial claims. +# +#country- +#code name of country, territory, area, or subdivision +AD Andorra +AE United Arab Emirates +AF Afghanistan +AG Antigua & Barbuda +AI Anguilla +AL Albania +AM Armenia +AO Angola +AQ Antarctica +AR Argentina +AS Samoa (American) +AT Austria +AU Australia +AW Aruba +AX Åland Islands +AZ Azerbaijan +BA Bosnia & Herzegovina +BB Barbados +BD Bangladesh +BE Belgium +BF Burkina Faso +BG Bulgaria +BH Bahrain +BI Burundi +BJ Benin +BL St Barthelemy +BM Bermuda +BN Brunei +BO Bolivia +BQ Caribbean NL +BR Brazil +BS Bahamas +BT Bhutan +BV Bouvet Island +BW Botswana +BY Belarus +BZ Belize +CA Canada +CC Cocos (Keeling) Islands +CD Congo (Dem. Rep.) +CF Central African Rep. +CG Congo (Rep.) +CH Switzerland +CI Côte d'Ivoire +CK Cook Islands +CL Chile +CM Cameroon +CN China +CO Colombia +CR Costa Rica +CU Cuba +CV Cape Verde +CW Curaçao +CX Christmas Island +CY Cyprus +CZ Czech Republic +DE Germany +DJ Djibouti +DK Denmark +DM Dominica +DO Dominican Republic +DZ Algeria +EC Ecuador +EE Estonia +EG Egypt +EH Western Sahara +ER Eritrea +ES Spain +ET Ethiopia +FI Finland +FJ Fiji +FK Falkland Islands +FM Micronesia +FO Faroe Islands +FR France +GA Gabon +GB Britain (UK) +GD Grenada +GE Georgia +GF French Guiana +GG Guernsey +GH Ghana +GI Gibraltar +GL Greenland +GM Gambia +GN Guinea +GP Guadeloupe +GQ Equatorial Guinea +GR Greece +GS South Georgia & the South Sandwich Islands +GT Guatemala +GU Guam +GW Guinea-Bissau +GY Guyana +HK Hong Kong +HM Heard Island & McDonald Islands +HN Honduras +HR Croatia +HT Haiti +HU Hungary +ID Indonesia +IE Ireland +IL Israel +IM Isle of Man +IN India +IO British Indian Ocean Territory +IQ Iraq +IR Iran +IS Iceland +IT Italy +JE Jersey +JM Jamaica +JO Jordan +JP Japan +KE Kenya +KG Kyrgyzstan +KH Cambodia +KI Kiribati +KM Comoros +KN St Kitts & Nevis +KP Korea (North) +KR Korea (South) +KW Kuwait +KY Cayman Islands +KZ Kazakhstan +LA Laos +LB Lebanon +LC St Lucia +LI Liechtenstein +LK Sri Lanka +LR Liberia +LS Lesotho +LT Lithuania +LU Luxembourg +LV Latvia +LY Libya +MA Morocco +MC Monaco +MD Moldova +ME Montenegro +MF St Martin (French) +MG Madagascar +MH Marshall Islands +MK North Macedonia +ML Mali +MM Myanmar (Burma) +MN Mongolia +MO Macau +MP Northern Mariana Islands +MQ Martinique +MR Mauritania +MS Montserrat +MT Malta +MU Mauritius +MV Maldives +MW Malawi +MX Mexico +MY Malaysia +MZ Mozambique +NA Namibia +NC New Caledonia +NE Niger +NF Norfolk Island +NG Nigeria +NI Nicaragua +NL Netherlands +NO Norway +NP Nepal +NR Nauru +NU Niue +NZ New Zealand +OM Oman +PA Panama +PE Peru +PF French Polynesia +PG Papua New Guinea +PH Philippines +PK Pakistan +PL Poland +PM St Pierre & Miquelon +PN Pitcairn +PR Puerto Rico +PS Palestine +PT Portugal +PW Palau +PY Paraguay +QA Qatar +RE Réunion +RO Romania +RS Serbia +RU Russia +RW Rwanda +SA Saudi Arabia +SB Solomon Islands +SC Seychelles +SD Sudan +SE Sweden +SG Singapore +SH St Helena +SI Slovenia +SJ Svalbard & Jan Mayen +SK Slovakia +SL Sierra Leone +SM San Marino +SN Senegal +SO Somalia +SR Suriname +SS South Sudan +ST Sao Tome & Principe +SV El Salvador +SX St Maarten (Dutch) +SY Syria +SZ Eswatini (Swaziland) +TC Turks & Caicos Is +TD Chad +TF French S. Terr. +TG Togo +TH Thailand +TJ Tajikistan +TK Tokelau +TL East Timor +TM Turkmenistan +TN Tunisia +TO Tonga +TR Turkey +TT Trinidad & Tobago +TV Tuvalu +TW Taiwan +TZ Tanzania +UA Ukraine +UG Uganda +UM US minor outlying islands +US United States +UY Uruguay +UZ Uzbekistan +VA Vatican City +VC St Vincent +VE Venezuela +VG Virgin Islands (UK) +VI Virgin Islands (US) +VN Vietnam +VU Vanuatu +WF Wallis & Futuna +WS Samoa (western) +YE Yemen +YT Mayotte +ZA South Africa +ZM Zambia +ZW Zimbabwe diff --git a/vendor/chrono-tz/tz/leap-seconds.list b/vendor/chrono-tz/tz/leap-seconds.list new file mode 100644 index 0000000000000..e52effc257b27 --- /dev/null +++ b/vendor/chrono-tz/tz/leap-seconds.list @@ -0,0 +1,120 @@ +# ATOMIC TIME. +# The Coordinated Universal Time (UTC) is the reference time scale derived +# from The "Temps Atomique International" (TAI) calculated by the Bureau +# International des Poids et Mesures (BIPM) using a worldwide network of atomic +# clocks. UTC differs from TAI by an integer number of seconds; it is the basis +# of all activities in the world. +# +# +# ASTRONOMICAL TIME (UT1) is the time scale based on the rate of rotation of the earth. +# It is now mainly derived from Very Long Baseline Interferometry (VLBI). The various +# irregular fluctuations progressively detected in the rotation rate of the Earth lead +# in 1972 to the replacement of UT1 by UTC as the reference time scale. +# +# +# LEAP SECOND +# Atomic clocks are more stable than the rate of the earth rotation since the latter +# undergoes a full range of geophysical perturbations at various time scales: lunisolar +# and core-mantle torques, atmospheric and oceanic effetcs, etc. +# Leap seconds are needed to keep the two time scales in agreement, i.e. UT1-UTC smaller +# than 0.9 second. Therefore, when necessary a "leap second" is applied to UTC. +# Since the adoption of this system in 1972 it has been necessary to add a number of seconds to UTC, +# firstly due to the initial choice of the value of the second (1/86400 mean solar day of +# the year 1820) and secondly to the general slowing down of the Earth's rotation. It is +# theorically possible to have a negative leap second (a second removed from UTC), but so far, +# all leap seconds have been positive (a second has been added to UTC). Based on what we know about +# the earth's rotation, it is unlikely that we will ever have a negative leap second. +# +# +# HISTORY +# The first leap second was added on June 30, 1972. Until yhe year 2000, it was necessary in average to add a +# leap second at a rate of 1 to 2 years. Since the year 2000 leap seconds are introduced with an +# average interval of 3 to 4 years due to the acceleration of the Earth rotation speed. +# +# +# RESPONSABILITY OF THE DECISION TO INTRODUCE A LEAP SECOND IN UTC +# The decision to introduce a leap second in UTC is the responsibility of the Earth Orientation Center of +# the International Earth Rotation and reference System Service (IERS). This center is located at Paris +# Observatory. According to international agreements, leap seconds should only be scheduled for certain dates: +# first preference is given to the end of December and June, and second preference at the end of March +# and September. Since the introduction of leap seconds in 1972, only dates in June and December were used. +# +# Questions or comments to: +# Christian Bizouard: christian.bizouard@obspm.fr +# Earth orientation Center of the IERS +# Paris Observatory, France +# +# +# +# COPYRIGHT STATUS OF THIS FILE +# This file is in the public domain. +# +# +# VALIDITY OF THE FILE +# It is important to express the validity of the file. These next two dates are +# given in units of seconds since 1900.0. +# +# 1) Last update of the file. +# +# Updated through IERS Bulletin C (https://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat) +# +# The following line shows the last update of this file in NTP timestamp: +# +#$ 3913697179 +# +# 2) Expiration date of the file given on a semi-annual basis: last June or last December +# +# File expires on 28 December 2024 +# +# Expire date in NTP timestamp: +# +#@ 3944332800 +# +# +# LIST OF LEAP SECONDS +# NTP timestamp (X parameter) is the number of seconds since 1900.0 +# +# MJD: The Modified Julian Day number. MJD = X/86400 + 15020 +# +# DTAI: The difference DTAI= TAI-UTC in units of seconds +# It is the quantity to add to UTC to get the time in TAI +# +# Day Month Year : epoch in clear +# +#NTP Time DTAI Day Month Year +# +2272060800 10 # 1 Jan 1972 +2287785600 11 # 1 Jul 1972 +2303683200 12 # 1 Jan 1973 +2335219200 13 # 1 Jan 1974 +2366755200 14 # 1 Jan 1975 +2398291200 15 # 1 Jan 1976 +2429913600 16 # 1 Jan 1977 +2461449600 17 # 1 Jan 1978 +2492985600 18 # 1 Jan 1979 +2524521600 19 # 1 Jan 1980 +2571782400 20 # 1 Jul 1981 +2603318400 21 # 1 Jul 1982 +2634854400 22 # 1 Jul 1983 +2698012800 23 # 1 Jul 1985 +2776982400 24 # 1 Jan 1988 +2840140800 25 # 1 Jan 1990 +2871676800 26 # 1 Jan 1991 +2918937600 27 # 1 Jul 1992 +2950473600 28 # 1 Jul 1993 +2982009600 29 # 1 Jul 1994 +3029443200 30 # 1 Jan 1996 +3076704000 31 # 1 Jul 1997 +3124137600 32 # 1 Jan 1999 +3345062400 33 # 1 Jan 2006 +3439756800 34 # 1 Jan 2009 +3550089600 35 # 1 Jul 2012 +3644697600 36 # 1 Jul 2015 +3692217600 37 # 1 Jan 2017 +# +# A hash code has been generated to be able to verify the integrity +# of this file. For more information about using this hash code, +# please see the readme file in the 'source' directory : +# https://hpiers.obspm.fr/iers/bul/bulc/ntp/sources/README +# +#h 9dac5845 8acd32c0 2947d462 daf4a943 f58d9391 diff --git a/vendor/chrono-tz/tz/leapseconds.awk b/vendor/chrono-tz/tz/leapseconds.awk new file mode 100644 index 0000000000000..15e85012bf95b --- /dev/null +++ b/vendor/chrono-tz/tz/leapseconds.awk @@ -0,0 +1,249 @@ +# Generate zic format 'leapseconds' from NIST/IERS format 'leap-seconds.list'. + +# This file is in the public domain. + +# This program uses awk arithmetic. POSIX requires awk to support +# exact integer arithmetic only through 10**10, which means for NTP +# timestamps this program works only to the year 2216, which is the +# year 1900 plus 10**10 seconds. However, in practice +# POSIX-conforming awk implementations invariably use IEEE-754 double +# and so support exact integers through 2**53. By the year 2216, +# POSIX will almost surely require at least 2**53 for awk, so for NTP +# timestamps this program should be good until the year 285,428,681 +# (the year 1900 plus 2**53 seconds). By then leap seconds will be +# long obsolete, as the Earth will likely slow down so much that +# there will be more than 25 hours per day and so some other scheme +# will be needed. + +BEGIN { + print "# Allowance for leap seconds added to each time zone file." + print "" + print "# This file is in the public domain." + print "" + print "# This file is generated automatically from the data in the public-domain" + print "# NIST/IERS format leap-seconds.list file, which can be copied from" + print "# " + print "# or, in a variant with different comments, from" + print "# ." + print "# For more about leap-seconds.list, please see" + print "# The NTP Timescale and Leap Seconds" + print "# ." + print "" + print "# The rules for leap seconds are specified in Annex 1 (Time scales) of:" + print "# Standard-frequency and time-signal emissions." + print "# International Telecommunication Union - Radiocommunication Sector" + print "# (ITU-R) Recommendation TF.460-6 (02/2002)" + print "# ." + print "# The International Earth Rotation and Reference Systems Service (IERS)" + print "# periodically uses leap seconds to keep UTC to within 0.9 s of UT1" + print "# (a proxy for Earth's angle in space as measured by astronomers)" + print "# and publishes leap second data in a copyrighted file" + print "# ." + print "# See: Levine J. Coordinated Universal Time and the leap second." + print "# URSI Radio Sci Bull. 2016;89(4):30-6. doi:10.23919/URSIRSB.2016.7909995" + print "# ." + print "" + print "# There were no leap seconds before 1972, as no official mechanism" + print "# accounted for the discrepancy between atomic time (TAI) and the earth's" + print "# rotation. The first (\"1 Jan 1972\") data line in leap-seconds.list" + print "# does not denote a leap second; it denotes the start of the current definition" + print "# of UTC." + print "" + print "# All leap-seconds are Stationary (S) at the given UTC time." + print "# The correction (+ or -) is made at the given time, so in the unlikely" + print "# event of a negative leap second, a line would look like this:" + print "# Leap YEAR MON DAY 23:59:59 - S" + print "# Typical lines look like this:" + print "# Leap YEAR MON DAY 23:59:60 + S" + + monthabbr[ 1] = "Jan" + monthabbr[ 2] = "Feb" + monthabbr[ 3] = "Mar" + monthabbr[ 4] = "Apr" + monthabbr[ 5] = "May" + monthabbr[ 6] = "Jun" + monthabbr[ 7] = "Jul" + monthabbr[ 8] = "Aug" + monthabbr[ 9] = "Sep" + monthabbr[10] = "Oct" + monthabbr[11] = "Nov" + monthabbr[12] = "Dec" + + sstamp_init() +} + +# In case the input has CRLF form a la NIST. +{ sub(/\r$/, "") } + +/^#[ \t]*[Uu]pdated through/ || /^#[ \t]*[Ff]ile expires on/ { + last_lines = last_lines $0 "\n" +} + +/^#[$][ \t]/ { updated = $2 } +/^#[@][ \t]/ { expires = $2 } + +/^[ \t]*#/ { next } + +{ + NTP_timestamp = $1 + TAI_minus_UTC = $2 + if (old_TAI_minus_UTC) { + if (old_TAI_minus_UTC < TAI_minus_UTC) { + sign = "23:59:60\t+" + } else { + sign = "23:59:59\t-" + } + sstamp_to_ymdhMs(NTP_timestamp - 1, ss_NTP) + printf "Leap\t%d\t%s\t%d\t%s\tS\n", \ + ss_year, monthabbr[ss_month], ss_mday, sign + } + old_TAI_minus_UTC = TAI_minus_UTC +} + +END { + print "" + + if (expires) { + sstamp_to_ymdhMs(expires, ss_NTP) + + print "# UTC timestamp when this leap second list expires." + print "# Any additional leap seconds will come after this." + if (! EXPIRES_LINE) { + print "# This Expires line is commented out for now," + print "# so that pre-2020a zic implementations do not reject this file." + } + printf "%sExpires %.4d\t%s\t%.2d\t%.2d:%.2d:%.2d\n", \ + EXPIRES_LINE ? "" : "#", \ + ss_year, monthabbr[ss_month], ss_mday, ss_hour, ss_min, ss_sec + } else { + print "# (No Expires line, since the expires time is unknown.)" + } + + # The difference between the NTP and POSIX epochs is 70 years + # (including 17 leap days), each 24 hours of 60 minutes of 60 + # seconds each. + epoch_minus_NTP = ((1970 - 1900) * 365 + 17) * 24 * 60 * 60 + + print "" + print "# POSIX timestamps for the data in this file:" + if (updated) { + sstamp_to_ymdhMs(updated, ss_NTP) + printf "#updated %d (%.4d-%.2d-%.2d %.2d:%.2d:%.2d UTC)\n", \ + updated - epoch_minus_NTP, \ + ss_year, ss_month, ss_mday, ss_hour, ss_min, ss_sec + } else { + print "#(updated time unknown)" + } + if (expires) { + sstamp_to_ymdhMs(expires, ss_NTP) + printf "#expires %d (%.4d-%.2d-%.2d %.2d:%.2d:%.2d UTC)\n", \ + expires - epoch_minus_NTP, \ + ss_year, ss_month, ss_mday, ss_hour, ss_min, ss_sec + } else { + print "#(expires time unknown)" + } + printf "\n%s", last_lines +} + +# sstamp_to_ymdhMs - convert seconds timestamp to date and time +# +# Call as: +# +# sstamp_to_ymdhMs(sstamp, epoch_days) +# +# where: +# +# sstamp - is the seconds timestamp. +# epoch_days - is the timestamp epoch in Gregorian days since 1600-03-01. +# ss_NTP is appropriate for an NTP sstamp. +# +# Both arguments should be nonnegative integers. +# On return, the following variables are set based on sstamp: +# +# ss_year - Gregorian calendar year +# ss_month - month of the year (1-January to 12-December) +# ss_mday - day of the month (1-31) +# ss_hour - hour (0-23) +# ss_min - minute (0-59) +# ss_sec - second (0-59) +# ss_wday - day of week (0-Sunday to 6-Saturday) +# +# The function sstamp_init should be called prior to using sstamp_to_ymdhMs. + +function sstamp_init() +{ + # Days in month N, where March is month 0 and January month 10. + ss_mon_days[ 0] = 31 + ss_mon_days[ 1] = 30 + ss_mon_days[ 2] = 31 + ss_mon_days[ 3] = 30 + ss_mon_days[ 4] = 31 + ss_mon_days[ 5] = 31 + ss_mon_days[ 6] = 30 + ss_mon_days[ 7] = 31 + ss_mon_days[ 8] = 30 + ss_mon_days[ 9] = 31 + ss_mon_days[10] = 31 + + # Counts of days in a Gregorian year, quad-year, century, and quad-century. + ss_year_days = 365 + ss_quadyear_days = ss_year_days * 4 + 1 + ss_century_days = ss_quadyear_days * 25 - 1 + ss_quadcentury_days = ss_century_days * 4 + 1 + + # Standard day epochs, suitable for epoch_days. + # ss_MJD = 94493 + # ss_POSIX = 135080 + ss_NTP = 109513 +} + +function sstamp_to_ymdhMs(sstamp, epoch_days, \ + quadcentury, century, quadyear, year, month, day) +{ + ss_hour = int(sstamp / 3600) % 24 + ss_min = int(sstamp / 60) % 60 + ss_sec = sstamp % 60 + + # Start with a count of days since 1600-03-01 Gregorian. + day = epoch_days + int(sstamp / (24 * 60 * 60)) + + # Compute a year-month-day date with days of the month numbered + # 0-30, months (March-February) numbered 0-11, and years that start + # start March 1 and end after the last day of February. A quad-year + # starts on March 1 of a year evenly divisible by 4 and ends after + # the last day of February 4 years later. A century starts on and + # ends before March 1 in years evenly divisible by 100. + # A quad-century starts on and ends before March 1 in years divisible + # by 400. While the number of days in a quad-century is a constant, + # the number of days in each other time period can vary by 1. + # Any variation is in the last day of the time period (there might + # or might not be a February 29) where it is easy to deal with. + + quadcentury = int(day / ss_quadcentury_days) + day -= quadcentury * ss_quadcentury_days + ss_wday = (day + 3) % 7 + century = int(day / ss_century_days) + century -= century == 4 + day -= century * ss_century_days + quadyear = int(day / ss_quadyear_days) + day -= quadyear * ss_quadyear_days + year = int(day / ss_year_days) + year -= year == 4 + day -= year * ss_year_days + for (month = 0; month < 11; month++) { + if (day < ss_mon_days[month]) + break + day -= ss_mon_days[month] + } + + # Convert the date to a conventional day of month (1-31), + # month (1-12, January-December) and Gregorian year. + ss_mday = day + 1 + if (month <= 9) { + ss_month = month + 3 + } else { + ss_month = month - 9 + year++ + } + ss_year = 1600 + quadcentury * 400 + century * 100 + quadyear * 4 + year +} diff --git a/vendor/chrono-tz/tz/localtime.c b/vendor/chrono-tz/tz/localtime.c new file mode 100644 index 0000000000000..940a04fd09aba --- /dev/null +++ b/vendor/chrono-tz/tz/localtime.c @@ -0,0 +1,2474 @@ +/* Convert timestamp from time_t to struct tm. */ + +/* +** This file is in the public domain, so clarified as of +** 1996-06-05 by Arthur David Olson. +*/ + +/* +** Leap second handling from Bradley White. +** POSIX.1-1988 style TZ environment variable handling from Guy Harris. +*/ + +/*LINTLIBRARY*/ + +#define LOCALTIME_IMPLEMENTATION +#include "private.h" + +#include "tzdir.h" +#include "tzfile.h" +#include + +#if defined THREAD_SAFE && THREAD_SAFE +# include +static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER; +static int lock(void) { return pthread_mutex_lock(&locallock); } +static void unlock(void) { pthread_mutex_unlock(&locallock); } +#else +static int lock(void) { return 0; } +static void unlock(void) { } +#endif + +#ifndef TZ_ABBR_CHAR_SET +# define TZ_ABBR_CHAR_SET \ + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" +#endif /* !defined TZ_ABBR_CHAR_SET */ + +#ifndef TZ_ABBR_ERR_CHAR +# define TZ_ABBR_ERR_CHAR '_' +#endif /* !defined TZ_ABBR_ERR_CHAR */ + +/* +** Support non-POSIX platforms that distinguish between text and binary files. +*/ + +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +#ifndef WILDABBR +/* +** Someone might make incorrect use of a time zone abbreviation: +** 1. They might reference tzname[0] before calling tzset (explicitly +** or implicitly). +** 2. They might reference tzname[1] before calling tzset (explicitly +** or implicitly). +** 3. They might reference tzname[1] after setting to a time zone +** in which Daylight Saving Time is never observed. +** 4. They might reference tzname[0] after setting to a time zone +** in which Standard Time is never observed. +** 5. They might reference tm.TM_ZONE after calling offtime. +** What's best to do in the above cases is open to debate; +** for now, we just set things up so that in any of the five cases +** WILDABBR is used. Another possibility: initialize tzname[0] to the +** string "tzname[0] used before set", and similarly for the other cases. +** And another: initialize tzname[0] to "ERA", with an explanation in the +** manual page of what this "time zone abbreviation" means (doing this so +** that tzname[0] has the "normal" length of three characters). +*/ +# define WILDABBR " " +#endif /* !defined WILDABBR */ + +static const char wildabbr[] = WILDABBR; + +static char const etc_utc[] = "Etc/UTC"; +static char const *utc = etc_utc + sizeof "Etc/" - 1; + +/* +** The DST rules to use if TZ has no rules and we can't load TZDEFRULES. +** Default to US rules as of 2017-05-07. +** POSIX does not specify the default DST rules; +** for historical reasons, US rules are a common default. +*/ +#ifndef TZDEFRULESTRING +# define TZDEFRULESTRING ",M3.2.0,M11.1.0" +#endif + +struct ttinfo { /* time type information */ + int_fast32_t tt_utoff; /* UT offset in seconds */ + bool tt_isdst; /* used to set tm_isdst */ + int tt_desigidx; /* abbreviation list index */ + bool tt_ttisstd; /* transition is std time */ + bool tt_ttisut; /* transition is UT */ +}; + +struct lsinfo { /* leap second information */ + time_t ls_trans; /* transition time */ + int_fast32_t ls_corr; /* correction to apply */ +}; + +/* This abbreviation means local time is unspecified. */ +static char const UNSPEC[] = "-00"; + +/* How many extra bytes are needed at the end of struct state's chars array. + This needs to be at least 1 for null termination in case the input + data isn't properly terminated, and it also needs to be big enough + for ttunspecified to work without crashing. */ +enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 }; + +/* Limit to time zone abbreviation length in POSIX.1-2017-style TZ strings. + This is distinct from TZ_MAX_CHARS, which limits TZif file contents. */ +#ifndef TZNAME_MAXIMUM +# define TZNAME_MAXIMUM 255 +#endif + +/* A representation of the contents of a TZif file. Ideally this + would have no size limits; the following sizes should suffice for + practical use. This struct should not be too large, as instances + are put on the stack and stacks are relatively small on some platforms. + See tzfile.h for more about the sizes. */ +struct state { + int leapcnt; + int timecnt; + int typecnt; + int charcnt; + bool goback; + bool goahead; + time_t ats[TZ_MAX_TIMES]; + unsigned char types[TZ_MAX_TIMES]; + struct ttinfo ttis[TZ_MAX_TYPES]; + char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"), + 2 * (TZNAME_MAXIMUM + 1))]; + struct lsinfo lsis[TZ_MAX_LEAPS]; + + /* The time type to use for early times or if no transitions. + It is always zero for recent tzdb releases. + It might be nonzero for data from tzdb 2018e or earlier. */ + int defaulttype; +}; + +enum r_type { + JULIAN_DAY, /* Jn = Julian day */ + DAY_OF_YEAR, /* n = day of year */ + MONTH_NTH_DAY_OF_WEEK /* Mm.n.d = month, week, day of week */ +}; + +struct rule { + enum r_type r_type; /* type of rule */ + int r_day; /* day number of rule */ + int r_week; /* week number of rule */ + int r_mon; /* month number of rule */ + int_fast32_t r_time; /* transition time of rule */ +}; + +static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t, + struct tm *); +static bool increment_overflow(int *, int); +static bool increment_overflow_time(time_t *, int_fast32_t); +static int_fast32_t leapcorr(struct state const *, time_t); +static bool normalize_overflow32(int_fast32_t *, int *, int); +static struct tm *timesub(time_t const *, int_fast32_t, struct state const *, + struct tm *); +static bool tzparse(char const *, struct state *, struct state const *); + +#ifdef ALL_STATE +static struct state * lclptr; +static struct state * gmtptr; +#endif /* defined ALL_STATE */ + +#ifndef ALL_STATE +static struct state lclmem; +static struct state gmtmem; +static struct state *const lclptr = &lclmem; +static struct state *const gmtptr = &gmtmem; +#endif /* State Farm */ + +#ifndef TZ_STRLEN_MAX +# define TZ_STRLEN_MAX 255 +#endif /* !defined TZ_STRLEN_MAX */ + +static char lcl_TZname[TZ_STRLEN_MAX + 1]; +static int lcl_is_set; + +/* +** Section 4.12.3 of X3.159-1989 requires that +** Except for the strftime function, these functions [asctime, +** ctime, gmtime, localtime] return values in one of two static +** objects: a broken-down time structure and an array of char. +** Thanks to Paul Eggert for noting this. +** +** This requirement was removed in C99, so support it only if requested, +** as support is more likely to lead to bugs in badly written programs. +*/ + +#if SUPPORT_C89 +static struct tm tm; +#endif + +#if 2 <= HAVE_TZNAME + TZ_TIME_T +char * tzname[2] = { + (char *) wildabbr, + (char *) wildabbr +}; +#endif +#if 2 <= USG_COMPAT + TZ_TIME_T +long timezone; +int daylight; +#endif +#if 2 <= ALTZONE + TZ_TIME_T +long altzone; +#endif + +/* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX. */ +static void +init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx) +{ + s->tt_utoff = utoff; + s->tt_isdst = isdst; + s->tt_desigidx = desigidx; + s->tt_ttisstd = false; + s->tt_ttisut = false; +} + +/* Return true if SP's time type I does not specify local time. */ +static bool +ttunspecified(struct state const *sp, int i) +{ + char const *abbr = &sp->chars[sp->ttis[i].tt_desigidx]; + /* memcmp is likely faster than strcmp, and is safe due to CHARS_EXTRA. */ + return memcmp(abbr, UNSPEC, sizeof UNSPEC) == 0; +} + +static int_fast32_t +detzcode(const char *const codep) +{ + register int_fast32_t result; + register int i; + int_fast32_t one = 1; + int_fast32_t halfmaxval = one << (32 - 2); + int_fast32_t maxval = halfmaxval - 1 + halfmaxval; + int_fast32_t minval = -1 - maxval; + + result = codep[0] & 0x7f; + for (i = 1; i < 4; ++i) + result = (result << 8) | (codep[i] & 0xff); + + if (codep[0] & 0x80) { + /* Do two's-complement negation even on non-two's-complement machines. + If the result would be minval - 1, return minval. */ + result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0; + result += minval; + } + return result; +} + +static int_fast64_t +detzcode64(const char *const codep) +{ + register int_fast64_t result; + register int i; + int_fast64_t one = 1; + int_fast64_t halfmaxval = one << (64 - 2); + int_fast64_t maxval = halfmaxval - 1 + halfmaxval; + int_fast64_t minval = -TWOS_COMPLEMENT(int_fast64_t) - maxval; + + result = codep[0] & 0x7f; + for (i = 1; i < 8; ++i) + result = (result << 8) | (codep[i] & 0xff); + + if (codep[0] & 0x80) { + /* Do two's-complement negation even on non-two's-complement machines. + If the result would be minval - 1, return minval. */ + result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0; + result += minval; + } + return result; +} + +static void +update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp) +{ +#if HAVE_TZNAME + tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_desigidx]; +#endif +#if USG_COMPAT + if (!ttisp->tt_isdst) + timezone = - ttisp->tt_utoff; +#endif +#if ALTZONE + if (ttisp->tt_isdst) + altzone = - ttisp->tt_utoff; +#endif +} + +/* If STDDST_MASK indicates that SP's TYPE provides useful info, + update tzname, timezone, and/or altzone and return STDDST_MASK, + diminished by the provided info if it is a specified local time. + Otherwise, return STDDST_MASK. See settzname for STDDST_MASK. */ +static int +may_update_tzname_etc(int stddst_mask, struct state *sp, int type) +{ + struct ttinfo *ttisp = &sp->ttis[type]; + int this_bit = 1 << ttisp->tt_isdst; + if (stddst_mask & this_bit) { + update_tzname_etc(sp, ttisp); + if (!ttunspecified(sp, type)) + return stddst_mask & ~this_bit; + } + return stddst_mask; +} + +static void +settzname(void) +{ + register struct state * const sp = lclptr; + register int i; + + /* If STDDST_MASK & 1 we need info about a standard time. + If STDDST_MASK & 2 we need info about a daylight saving time. + When STDDST_MASK becomes zero we can stop looking. */ + int stddst_mask = 0; + +#if HAVE_TZNAME + tzname[0] = tzname[1] = (char *) (sp ? wildabbr : utc); + stddst_mask = 3; +#endif +#if USG_COMPAT + timezone = 0; + stddst_mask = 3; +#endif +#if ALTZONE + altzone = 0; + stddst_mask |= 2; +#endif + /* + ** And to get the latest time zone abbreviations into tzname. . . + */ + if (sp) { + for (i = sp->timecnt - 1; stddst_mask && 0 <= i; i--) + stddst_mask = may_update_tzname_etc(stddst_mask, sp, sp->types[i]); + for (i = sp->typecnt - 1; stddst_mask && 0 <= i; i--) + stddst_mask = may_update_tzname_etc(stddst_mask, sp, i); + } +#if USG_COMPAT + daylight = stddst_mask >> 1 ^ 1; +#endif +} + +/* Replace bogus characters in time zone abbreviations. + Return 0 on success, an errno value if a time zone abbreviation is + too long. */ +static int +scrub_abbrs(struct state *sp) +{ + int i; + + /* Reject overlong abbreviations. */ + for (i = 0; i < sp->charcnt - (TZNAME_MAXIMUM + 1); ) { + int len = strlen(&sp->chars[i]); + if (TZNAME_MAXIMUM < len) + return EOVERFLOW; + i += len + 1; + } + + /* Replace bogus characters. */ + for (i = 0; i < sp->charcnt; ++i) + if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL) + sp->chars[i] = TZ_ABBR_ERR_CHAR; + + return 0; +} + +/* Input buffer for data read from a compiled tz file. */ +union input_buffer { + /* The first part of the buffer, interpreted as a header. */ + struct tzhead tzhead; + + /* The entire buffer. Ideally this would have no size limits; + the following should suffice for practical use. */ + char buf[2 * sizeof(struct tzhead) + 2 * sizeof(struct state) + + 4 * TZ_MAX_TIMES]; +}; + +/* TZDIR with a trailing '/' rather than a trailing '\0'. */ +static char const tzdirslash[sizeof TZDIR] = TZDIR "/"; + +/* Local storage needed for 'tzloadbody'. */ +union local_storage { + /* The results of analyzing the file's contents after it is opened. */ + struct file_analysis { + /* The input buffer. */ + union input_buffer u; + + /* A temporary state used for parsing a TZ string in the file. */ + struct state st; + } u; + + /* The name of the file to be opened. Ideally this would have no + size limits, to support arbitrarily long Zone names. + Limiting Zone names to 1024 bytes should suffice for practical use. + However, there is no need for this to be smaller than struct + file_analysis as that struct is allocated anyway, as the other + union member. */ + char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)]; +}; + +/* Load tz data from the file named NAME into *SP. Read extended + format if DOEXTEND. Use *LSP for temporary storage. Return 0 on + success, an errno value on failure. */ +static int +tzloadbody(char const *name, struct state *sp, bool doextend, + union local_storage *lsp) +{ + register int i; + register int fid; + register int stored; + register ssize_t nread; + register bool doaccess; + register union input_buffer *up = &lsp->u.u; + register int tzheadsize = sizeof(struct tzhead); + + sp->goback = sp->goahead = false; + + if (! name) { + name = TZDEFAULT; + if (! name) + return EINVAL; + } + + if (name[0] == ':') + ++name; +#ifdef SUPPRESS_TZDIR + /* Do not prepend TZDIR. This is intended for specialized + applications only, due to its security implications. */ + doaccess = true; +#else + doaccess = name[0] == '/'; +#endif + if (!doaccess) { + char const *dot; + if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name)) + return ENAMETOOLONG; + + /* Create a string "TZDIR/NAME". Using sprintf here + would pull in stdio (and would fail if the + resulting string length exceeded INT_MAX!). */ + memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash); + strcpy(lsp->fullname + sizeof tzdirslash, name); + + /* Set doaccess if NAME contains a ".." file name + component, as such a name could read a file outside + the TZDIR virtual subtree. */ + for (dot = name; (dot = strchr(dot, '.')); dot++) + if ((dot == name || dot[-1] == '/') && dot[1] == '.' + && (dot[2] == '/' || !dot[2])) { + doaccess = true; + break; + } + + name = lsp->fullname; + } + if (doaccess && access(name, R_OK) != 0) + return errno; + fid = open(name, O_RDONLY | O_BINARY); + if (fid < 0) + return errno; + + nread = read(fid, up->buf, sizeof up->buf); + if (nread < tzheadsize) { + int err = nread < 0 ? errno : EINVAL; + close(fid); + return err; + } + if (close(fid) < 0) + return errno; + for (stored = 4; stored <= 8; stored *= 2) { + char version = up->tzhead.tzh_version[0]; + bool skip_datablock = stored == 4 && version; + int_fast32_t datablock_size; + int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt); + int_fast32_t ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt); + int_fast64_t prevtr = -1; + int_fast32_t prevcorr; + int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt); + int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt); + int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt); + int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt); + char const *p = up->buf + tzheadsize; + /* Although tzfile(5) currently requires typecnt to be nonzero, + support future formats that may allow zero typecnt + in files that have a TZ string and no transitions. */ + if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS + && 0 <= typecnt && typecnt < TZ_MAX_TYPES + && 0 <= timecnt && timecnt < TZ_MAX_TIMES + && 0 <= charcnt && charcnt < TZ_MAX_CHARS + && 0 <= ttisstdcnt && ttisstdcnt < TZ_MAX_TYPES + && 0 <= ttisutcnt && ttisutcnt < TZ_MAX_TYPES)) + return EINVAL; + datablock_size + = (timecnt * stored /* ats */ + + timecnt /* types */ + + typecnt * 6 /* ttinfos */ + + charcnt /* chars */ + + leapcnt * (stored + 4) /* lsinfos */ + + ttisstdcnt /* ttisstds */ + + ttisutcnt); /* ttisuts */ + if (nread < tzheadsize + datablock_size) + return EINVAL; + if (skip_datablock) + p += datablock_size; + else { + if (! ((ttisstdcnt == typecnt || ttisstdcnt == 0) + && (ttisutcnt == typecnt || ttisutcnt == 0))) + return EINVAL; + + sp->leapcnt = leapcnt; + sp->timecnt = timecnt; + sp->typecnt = typecnt; + sp->charcnt = charcnt; + + /* Read transitions, discarding those out of time_t range. + But pretend the last transition before TIME_T_MIN + occurred at TIME_T_MIN. */ + timecnt = 0; + for (i = 0; i < sp->timecnt; ++i) { + int_fast64_t at + = stored == 4 ? detzcode(p) : detzcode64(p); + sp->types[i] = at <= TIME_T_MAX; + if (sp->types[i]) { + time_t attime + = ((TYPE_SIGNED(time_t) ? at < TIME_T_MIN : at < 0) + ? TIME_T_MIN : at); + if (timecnt && attime <= sp->ats[timecnt - 1]) { + if (attime < sp->ats[timecnt - 1]) + return EINVAL; + sp->types[i - 1] = 0; + timecnt--; + } + sp->ats[timecnt++] = attime; + } + p += stored; + } + + timecnt = 0; + for (i = 0; i < sp->timecnt; ++i) { + unsigned char typ = *p++; + if (sp->typecnt <= typ) + return EINVAL; + if (sp->types[i]) + sp->types[timecnt++] = typ; + } + sp->timecnt = timecnt; + for (i = 0; i < sp->typecnt; ++i) { + register struct ttinfo * ttisp; + unsigned char isdst, desigidx; + + ttisp = &sp->ttis[i]; + ttisp->tt_utoff = detzcode(p); + p += 4; + isdst = *p++; + if (! (isdst < 2)) + return EINVAL; + ttisp->tt_isdst = isdst; + desigidx = *p++; + if (! (desigidx < sp->charcnt)) + return EINVAL; + ttisp->tt_desigidx = desigidx; + } + for (i = 0; i < sp->charcnt; ++i) + sp->chars[i] = *p++; + /* Ensure '\0'-terminated, and make it safe to call + ttunspecified later. */ + memset(&sp->chars[i], 0, CHARS_EXTRA); + + /* Read leap seconds, discarding those out of time_t range. */ + leapcnt = 0; + for (i = 0; i < sp->leapcnt; ++i) { + int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p); + int_fast32_t corr = detzcode(p + stored); + p += stored + 4; + + /* Leap seconds cannot occur before the Epoch, + or out of order. */ + if (tr <= prevtr) + return EINVAL; + + /* To avoid other botches in this code, each leap second's + correction must differ from the previous one's by 1 + second or less, except that the first correction can be + any value; these requirements are more generous than + RFC 8536, to allow future RFC extensions. */ + if (! (i == 0 + || (prevcorr < corr + ? corr == prevcorr + 1 + : (corr == prevcorr + || corr == prevcorr - 1)))) + return EINVAL; + prevtr = tr; + prevcorr = corr; + + if (tr <= TIME_T_MAX) { + sp->lsis[leapcnt].ls_trans = tr; + sp->lsis[leapcnt].ls_corr = corr; + leapcnt++; + } + } + sp->leapcnt = leapcnt; + + for (i = 0; i < sp->typecnt; ++i) { + register struct ttinfo * ttisp; + + ttisp = &sp->ttis[i]; + if (ttisstdcnt == 0) + ttisp->tt_ttisstd = false; + else { + if (*p != true && *p != false) + return EINVAL; + ttisp->tt_ttisstd = *p++; + } + } + for (i = 0; i < sp->typecnt; ++i) { + register struct ttinfo * ttisp; + + ttisp = &sp->ttis[i]; + if (ttisutcnt == 0) + ttisp->tt_ttisut = false; + else { + if (*p != true && *p != false) + return EINVAL; + ttisp->tt_ttisut = *p++; + } + } + } + + nread -= p - up->buf; + memmove(up->buf, p, nread); + + /* If this is an old file, we're done. */ + if (!version) + break; + } + if (doextend && nread > 2 && + up->buf[0] == '\n' && up->buf[nread - 1] == '\n' && + sp->typecnt + 2 <= TZ_MAX_TYPES) { + struct state *ts = &lsp->u.st; + + up->buf[nread - 1] = '\0'; + if (tzparse(&up->buf[1], ts, sp)) { + + /* Attempt to reuse existing abbreviations. + Without this, America/Anchorage would be right on + the edge after 2037 when TZ_MAX_CHARS is 50, as + sp->charcnt equals 40 (for LMT AST AWT APT AHST + AHDT YST AKDT AKST) and ts->charcnt equals 10 + (for AKST AKDT). Reusing means sp->charcnt can + stay 40 in this example. */ + int gotabbr = 0; + int charcnt = sp->charcnt; + for (i = 0; i < ts->typecnt; i++) { + char *tsabbr = ts->chars + ts->ttis[i].tt_desigidx; + int j; + for (j = 0; j < charcnt; j++) + if (strcmp(sp->chars + j, tsabbr) == 0) { + ts->ttis[i].tt_desigidx = j; + gotabbr++; + break; + } + if (! (j < charcnt)) { + int tsabbrlen = strlen(tsabbr); + if (j + tsabbrlen < TZ_MAX_CHARS) { + strcpy(sp->chars + j, tsabbr); + charcnt = j + tsabbrlen + 1; + ts->ttis[i].tt_desigidx = j; + gotabbr++; + } + } + } + if (gotabbr == ts->typecnt) { + sp->charcnt = charcnt; + + /* Ignore any trailing, no-op transitions generated + by zic as they don't help here and can run afoul + of bugs in zic 2016j or earlier. */ + while (1 < sp->timecnt + && (sp->types[sp->timecnt - 1] + == sp->types[sp->timecnt - 2])) + sp->timecnt--; + + sp->goahead = ts->goahead; + + for (i = 0; i < ts->timecnt; i++) { + time_t t = ts->ats[i]; + if (increment_overflow_time(&t, leapcorr(sp, t)) + || (0 < sp->timecnt + && t <= sp->ats[sp->timecnt - 1])) + continue; + if (TZ_MAX_TIMES <= sp->timecnt) { + sp->goahead = false; + break; + } + sp->ats[sp->timecnt] = t; + sp->types[sp->timecnt] = (sp->typecnt + + ts->types[i]); + sp->timecnt++; + } + for (i = 0; i < ts->typecnt; i++) + sp->ttis[sp->typecnt++] = ts->ttis[i]; + } + } + } + if (sp->typecnt == 0) + return EINVAL; + + /* Infer sp->defaulttype from the data. Although this default + type is always zero for data from recent tzdb releases, + things are trickier for data from tzdb 2018e or earlier. + + The first set of heuristics work around bugs in 32-bit data + generated by tzdb 2013c or earlier. The workaround is for + zones like Australia/Macquarie where timestamps before the + first transition have a time type that is not the earliest + standard-time type. See: + https://mm.icann.org/pipermail/tz/2013-May/019368.html */ + /* + ** If type 0 does not specify local time, or is unused in transitions, + ** it's the type to use for early times. + */ + for (i = 0; i < sp->timecnt; ++i) + if (sp->types[i] == 0) + break; + i = i < sp->timecnt && ! ttunspecified(sp, 0) ? -1 : 0; + /* + ** Absent the above, + ** if there are transition times + ** and the first transition is to a daylight time + ** find the standard type less than and closest to + ** the type of the first transition. + */ + if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) { + i = sp->types[0]; + while (--i >= 0) + if (!sp->ttis[i].tt_isdst) + break; + } + /* The next heuristics are for data generated by tzdb 2018e or + earlier, for zones like EST5EDT where the first transition + is to DST. */ + /* + ** If no result yet, find the first standard type. + ** If there is none, punt to type zero. + */ + if (i < 0) { + i = 0; + while (sp->ttis[i].tt_isdst) + if (++i >= sp->typecnt) { + i = 0; + break; + } + } + /* A simple 'sp->defaulttype = 0;' would suffice here if we + didn't have to worry about 2018e-or-earlier data. Even + simpler would be to remove the defaulttype member and just + use 0 in its place. */ + sp->defaulttype = i; + + return 0; +} + +/* Load tz data from the file named NAME into *SP. Read extended + format if DOEXTEND. Return 0 on success, an errno value on failure. */ +static int +tzload(char const *name, struct state *sp, bool doextend) +{ +#ifdef ALL_STATE + union local_storage *lsp = malloc(sizeof *lsp); + if (!lsp) { + return HAVE_MALLOC_ERRNO ? errno : ENOMEM; + } else { + int err = tzloadbody(name, sp, doextend, lsp); + free(lsp); + return err; + } +#else + union local_storage ls; + return tzloadbody(name, sp, doextend, &ls); +#endif +} + +static const int mon_lengths[2][MONSPERYEAR] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +static const int year_lengths[2] = { + DAYSPERNYEAR, DAYSPERLYEAR +}; + +/* Is C an ASCII digit? */ +static bool +is_digit(char c) +{ + return '0' <= c && c <= '9'; +} + +/* +** Given a pointer into a timezone string, scan until a character that is not +** a valid character in a time zone abbreviation is found. +** Return a pointer to that character. +*/ + +ATTRIBUTE_REPRODUCIBLE static const char * +getzname(register const char *strp) +{ + register char c; + + while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && + c != '+') + ++strp; + return strp; +} + +/* +** Given a pointer into an extended timezone string, scan until the ending +** delimiter of the time zone abbreviation is located. +** Return a pointer to the delimiter. +** +** As with getzname above, the legal character set is actually quite +** restricted, with other characters producing undefined results. +** We don't do any checking here; checking is done later in common-case code. +*/ + +ATTRIBUTE_REPRODUCIBLE static const char * +getqzname(register const char *strp, const int delim) +{ + register int c; + + while ((c = *strp) != '\0' && c != delim) + ++strp; + return strp; +} + +/* +** Given a pointer into a timezone string, extract a number from that string. +** Check that the number is within a specified range; if it is not, return +** NULL. +** Otherwise, return a pointer to the first character not part of the number. +*/ + +static const char * +getnum(register const char *strp, int *const nump, const int min, const int max) +{ + register char c; + register int num; + + if (strp == NULL || !is_digit(c = *strp)) + return NULL; + num = 0; + do { + num = num * 10 + (c - '0'); + if (num > max) + return NULL; /* illegal value */ + c = *++strp; + } while (is_digit(c)); + if (num < min) + return NULL; /* illegal value */ + *nump = num; + return strp; +} + +/* +** Given a pointer into a timezone string, extract a number of seconds, +** in hh[:mm[:ss]] form, from the string. +** If any error occurs, return NULL. +** Otherwise, return a pointer to the first character not part of the number +** of seconds. +*/ + +static const char * +getsecs(register const char *strp, int_fast32_t *const secsp) +{ + int num; + int_fast32_t secsperhour = SECSPERHOUR; + + /* + ** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-POSIX rules like + ** "M10.4.6/26", which does not conform to POSIX, + ** but which specifies the equivalent of + ** "02:00 on the first Sunday on or after 23 Oct". + */ + strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); + if (strp == NULL) + return NULL; + *secsp = num * secsperhour; + if (*strp == ':') { + ++strp; + strp = getnum(strp, &num, 0, MINSPERHOUR - 1); + if (strp == NULL) + return NULL; + *secsp += num * SECSPERMIN; + if (*strp == ':') { + ++strp; + /* 'SECSPERMIN' allows for leap seconds. */ + strp = getnum(strp, &num, 0, SECSPERMIN); + if (strp == NULL) + return NULL; + *secsp += num; + } + } + return strp; +} + +/* +** Given a pointer into a timezone string, extract an offset, in +** [+-]hh[:mm[:ss]] form, from the string. +** If any error occurs, return NULL. +** Otherwise, return a pointer to the first character not part of the time. +*/ + +static const char * +getoffset(register const char *strp, int_fast32_t *const offsetp) +{ + register bool neg = false; + + if (*strp == '-') { + neg = true; + ++strp; + } else if (*strp == '+') + ++strp; + strp = getsecs(strp, offsetp); + if (strp == NULL) + return NULL; /* illegal time */ + if (neg) + *offsetp = -*offsetp; + return strp; +} + +/* +** Given a pointer into a timezone string, extract a rule in the form +** date[/time]. See POSIX Base Definitions section 8.3 variable TZ +** for the format of "date" and "time". +** If a valid rule is not found, return NULL. +** Otherwise, return a pointer to the first character not part of the rule. +*/ + +static const char * +getrule(const char *strp, register struct rule *const rulep) +{ + if (*strp == 'J') { + /* + ** Julian day. + */ + rulep->r_type = JULIAN_DAY; + ++strp; + strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); + } else if (*strp == 'M') { + /* + ** Month, week, day. + */ + rulep->r_type = MONTH_NTH_DAY_OF_WEEK; + ++strp; + strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); + if (strp == NULL) + return NULL; + if (*strp++ != '.') + return NULL; + strp = getnum(strp, &rulep->r_week, 1, 5); + if (strp == NULL) + return NULL; + if (*strp++ != '.') + return NULL; + strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); + } else if (is_digit(*strp)) { + /* + ** Day of year. + */ + rulep->r_type = DAY_OF_YEAR; + strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); + } else return NULL; /* invalid format */ + if (strp == NULL) + return NULL; + if (*strp == '/') { + /* + ** Time specified. + */ + ++strp; + strp = getoffset(strp, &rulep->r_time); + } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ + return strp; +} + +/* +** Given a year, a rule, and the offset from UT at the time that rule takes +** effect, calculate the year-relative time that rule takes effect. +*/ + +static int_fast32_t +transtime(const int year, register const struct rule *const rulep, + const int_fast32_t offset) +{ + register bool leapyear; + register int_fast32_t value; + register int i; + int d, m1, yy0, yy1, yy2, dow; + + leapyear = isleap(year); + switch (rulep->r_type) { + + case JULIAN_DAY: + /* + ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap + ** years. + ** In non-leap years, or if the day number is 59 or less, just + ** add SECSPERDAY times the day number-1 to the time of + ** January 1, midnight, to get the day. + */ + value = (rulep->r_day - 1) * SECSPERDAY; + if (leapyear && rulep->r_day >= 60) + value += SECSPERDAY; + break; + + case DAY_OF_YEAR: + /* + ** n - day of year. + ** Just add SECSPERDAY times the day number to the time of + ** January 1, midnight, to get the day. + */ + value = rulep->r_day * SECSPERDAY; + break; + + case MONTH_NTH_DAY_OF_WEEK: + /* + ** Mm.n.d - nth "dth day" of month m. + */ + + /* + ** Use Zeller's Congruence to get day-of-week of first day of + ** month. + */ + m1 = (rulep->r_mon + 9) % 12 + 1; + yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; + yy1 = yy0 / 100; + yy2 = yy0 % 100; + dow = ((26 * m1 - 2) / 10 + + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; + if (dow < 0) + dow += DAYSPERWEEK; + + /* + ** "dow" is the day-of-week of the first day of the month. Get + ** the day-of-month (zero-origin) of the first "dow" day of the + ** month. + */ + d = rulep->r_day - dow; + if (d < 0) + d += DAYSPERWEEK; + for (i = 1; i < rulep->r_week; ++i) { + if (d + DAYSPERWEEK >= + mon_lengths[leapyear][rulep->r_mon - 1]) + break; + d += DAYSPERWEEK; + } + + /* + ** "d" is the day-of-month (zero-origin) of the day we want. + */ + value = d * SECSPERDAY; + for (i = 0; i < rulep->r_mon - 1; ++i) + value += mon_lengths[leapyear][i] * SECSPERDAY; + break; + + default: unreachable(); + } + + /* + ** "value" is the year-relative time of 00:00:00 UT on the day in + ** question. To get the year-relative time of the specified local + ** time on that day, add the transition time and the current offset + ** from UT. + */ + return value + rulep->r_time + offset; +} + +/* +** Given a POSIX.1-2017-style TZ string, fill in the rule tables as +** appropriate. +*/ + +static bool +tzparse(const char *name, struct state *sp, struct state const *basep) +{ + const char * stdname; + const char * dstname; + int_fast32_t stdoffset; + int_fast32_t dstoffset; + register char * cp; + register bool load_ok; + ptrdiff_t stdlen, dstlen, charcnt; + time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN; + + stdname = name; + if (*name == '<') { + name++; + stdname = name; + name = getqzname(name, '>'); + if (*name != '>') + return false; + stdlen = name - stdname; + name++; + } else { + name = getzname(name); + stdlen = name - stdname; + } + if (! (0 < stdlen && stdlen <= TZNAME_MAXIMUM)) + return false; + name = getoffset(name, &stdoffset); + if (name == NULL) + return false; + charcnt = stdlen + 1; + if (basep) { + if (0 < basep->timecnt) + atlo = basep->ats[basep->timecnt - 1]; + load_ok = false; + sp->leapcnt = basep->leapcnt; + memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof *sp->lsis); + } else { + load_ok = tzload(TZDEFRULES, sp, false) == 0; + if (!load_ok) + sp->leapcnt = 0; /* So, we're off a little. */ + } + if (0 < sp->leapcnt) + leaplo = sp->lsis[sp->leapcnt - 1].ls_trans; + sp->goback = sp->goahead = false; + if (*name != '\0') { + if (*name == '<') { + dstname = ++name; + name = getqzname(name, '>'); + if (*name != '>') + return false; + dstlen = name - dstname; + name++; + } else { + dstname = name; + name = getzname(name); + dstlen = name - dstname; /* length of DST abbr. */ + } + if (! (0 < dstlen && dstlen <= TZNAME_MAXIMUM)) + return false; + charcnt += dstlen + 1; + if (*name != '\0' && *name != ',' && *name != ';') { + name = getoffset(name, &dstoffset); + if (name == NULL) + return false; + } else dstoffset = stdoffset - SECSPERHOUR; + if (*name == '\0' && !load_ok) + name = TZDEFRULESTRING; + if (*name == ',' || *name == ';') { + struct rule start; + struct rule end; + register int year; + register int timecnt; + time_t janfirst; + int_fast32_t janoffset = 0; + int yearbeg, yearlim; + + ++name; + if ((name = getrule(name, &start)) == NULL) + return false; + if (*name++ != ',') + return false; + if ((name = getrule(name, &end)) == NULL) + return false; + if (*name != '\0') + return false; + sp->typecnt = 2; /* standard time and DST */ + /* + ** Two transitions per year, from EPOCH_YEAR forward. + */ + init_ttinfo(&sp->ttis[0], -stdoffset, false, 0); + init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1); + timecnt = 0; + janfirst = 0; + yearbeg = EPOCH_YEAR; + + do { + int_fast32_t yearsecs + = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY; + yearbeg--; + if (increment_overflow_time(&janfirst, -yearsecs)) { + janoffset = -yearsecs; + break; + } + } while (atlo < janfirst + && EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg); + + while (true) { + int_fast32_t yearsecs + = year_lengths[isleap(yearbeg)] * SECSPERDAY; + int yearbeg1 = yearbeg; + time_t janfirst1 = janfirst; + if (increment_overflow_time(&janfirst1, yearsecs) + || increment_overflow(&yearbeg1, 1) + || atlo <= janfirst1) + break; + yearbeg = yearbeg1; + janfirst = janfirst1; + } + + yearlim = yearbeg; + if (increment_overflow(&yearlim, years_of_observations)) + yearlim = INT_MAX; + for (year = yearbeg; year < yearlim; year++) { + int_fast32_t + starttime = transtime(year, &start, stdoffset), + endtime = transtime(year, &end, dstoffset); + int_fast32_t + yearsecs = (year_lengths[isleap(year)] + * SECSPERDAY); + bool reversed = endtime < starttime; + if (reversed) { + int_fast32_t swap = starttime; + starttime = endtime; + endtime = swap; + } + if (reversed + || (starttime < endtime + && endtime - starttime < yearsecs)) { + if (TZ_MAX_TIMES - 2 < timecnt) + break; + sp->ats[timecnt] = janfirst; + if (! increment_overflow_time + (&sp->ats[timecnt], + janoffset + starttime) + && atlo <= sp->ats[timecnt]) + sp->types[timecnt++] = !reversed; + sp->ats[timecnt] = janfirst; + if (! increment_overflow_time + (&sp->ats[timecnt], + janoffset + endtime) + && atlo <= sp->ats[timecnt]) { + sp->types[timecnt++] = reversed; + } + } + if (endtime < leaplo) { + yearlim = year; + if (increment_overflow(&yearlim, + years_of_observations)) + yearlim = INT_MAX; + } + if (increment_overflow_time + (&janfirst, janoffset + yearsecs)) + break; + janoffset = 0; + } + sp->timecnt = timecnt; + if (! timecnt) { + sp->ttis[0] = sp->ttis[1]; + sp->typecnt = 1; /* Perpetual DST. */ + } else if (years_of_observations <= year - yearbeg) + sp->goback = sp->goahead = true; + } else { + register int_fast32_t theirstdoffset; + register int_fast32_t theirdstoffset; + register int_fast32_t theiroffset; + register bool isdst; + register int i; + register int j; + + if (*name != '\0') + return false; + /* + ** Initial values of theirstdoffset and theirdstoffset. + */ + theirstdoffset = 0; + for (i = 0; i < sp->timecnt; ++i) { + j = sp->types[i]; + if (!sp->ttis[j].tt_isdst) { + theirstdoffset = + - sp->ttis[j].tt_utoff; + break; + } + } + theirdstoffset = 0; + for (i = 0; i < sp->timecnt; ++i) { + j = sp->types[i]; + if (sp->ttis[j].tt_isdst) { + theirdstoffset = + - sp->ttis[j].tt_utoff; + break; + } + } + /* + ** Initially we're assumed to be in standard time. + */ + isdst = false; + /* + ** Now juggle transition times and types + ** tracking offsets as you do. + */ + for (i = 0; i < sp->timecnt; ++i) { + j = sp->types[i]; + sp->types[i] = sp->ttis[j].tt_isdst; + if (sp->ttis[j].tt_ttisut) { + /* No adjustment to transition time */ + } else { + /* + ** If daylight saving time is in + ** effect, and the transition time was + ** not specified as standard time, add + ** the daylight saving time offset to + ** the transition time; otherwise, add + ** the standard time offset to the + ** transition time. + */ + /* + ** Transitions from DST to DDST + ** will effectively disappear since + ** POSIX.1-2017 provides for only one + ** DST offset. + */ + if (isdst && !sp->ttis[j].tt_ttisstd) { + sp->ats[i] += dstoffset - + theirdstoffset; + } else { + sp->ats[i] += stdoffset - + theirstdoffset; + } + } + theiroffset = -sp->ttis[j].tt_utoff; + if (sp->ttis[j].tt_isdst) + theirdstoffset = theiroffset; + else theirstdoffset = theiroffset; + } + /* + ** Finally, fill in ttis. + */ + init_ttinfo(&sp->ttis[0], -stdoffset, false, 0); + init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1); + sp->typecnt = 2; + } + } else { + dstlen = 0; + sp->typecnt = 1; /* only standard time */ + sp->timecnt = 0; + init_ttinfo(&sp->ttis[0], -stdoffset, false, 0); + } + sp->defaulttype = 0; + sp->charcnt = charcnt; + cp = sp->chars; + memcpy(cp, stdname, stdlen); + cp += stdlen; + *cp++ = '\0'; + if (dstlen != 0) { + memcpy(cp, dstname, dstlen); + *(cp + dstlen) = '\0'; + } + return true; +} + +static void +gmtload(struct state *const sp) +{ + if (tzload(etc_utc, sp, true) != 0) + tzparse("UTC0", sp, NULL); +} + +/* Initialize *SP to a value appropriate for the TZ setting NAME. + Return 0 on success, an errno value on failure. */ +static int +zoneinit(struct state *sp, char const *name) +{ + if (name && ! name[0]) { + /* + ** User wants it fast rather than right. + */ + sp->leapcnt = 0; /* so, we're off a little */ + sp->timecnt = 0; + sp->typecnt = 0; + sp->charcnt = 0; + sp->goback = sp->goahead = false; + init_ttinfo(&sp->ttis[0], 0, false, 0); + strcpy(sp->chars, utc); + sp->defaulttype = 0; + return 0; + } else { + int err = tzload(name, sp, true); + if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL)) + err = 0; + if (err == 0) + err = scrub_abbrs(sp); + return err; + } +} + +static void +tzset_unlocked(void) +{ + char const *name = getenv("TZ"); + struct state *sp = lclptr; + int lcl = name ? strlen(name) < sizeof lcl_TZname : -1; + if (lcl < 0 + ? lcl_is_set < 0 + : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0) + return; +#ifdef ALL_STATE + if (! sp) + lclptr = sp = malloc(sizeof *lclptr); +#endif /* defined ALL_STATE */ + if (sp) { + if (zoneinit(sp, name) != 0) + zoneinit(sp, ""); + if (0 < lcl) + strcpy(lcl_TZname, name); + } + settzname(); + lcl_is_set = lcl; +} + +void +tzset(void) +{ + if (lock() != 0) + return; + tzset_unlocked(); + unlock(); +} + +static void +gmtcheck(void) +{ + static bool gmt_is_set; + if (lock() != 0) + return; + if (! gmt_is_set) { +#ifdef ALL_STATE + gmtptr = malloc(sizeof *gmtptr); +#endif + if (gmtptr) + gmtload(gmtptr); + gmt_is_set = true; + } + unlock(); +} + +#if NETBSD_INSPIRED + +timezone_t +tzalloc(char const *name) +{ + timezone_t sp = malloc(sizeof *sp); + if (sp) { + int err = zoneinit(sp, name); + if (err != 0) { + free(sp); + errno = err; + return NULL; + } + } else if (!HAVE_MALLOC_ERRNO) + errno = ENOMEM; + return sp; +} + +void +tzfree(timezone_t sp) +{ + free(sp); +} + +/* +** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and +** ctime_r are obsolescent and have potential security problems that +** ctime_rz would share. Callers can instead use localtime_rz + strftime. +** +** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work +** in zones with three or more time zone abbreviations. +** Callers can instead use localtime_rz + strftime. +*/ + +#endif + +/* +** The easy way to behave "as if no library function calls" localtime +** is to not call it, so we drop its guts into "localsub", which can be +** freely called. (And no, the PANS doesn't require the above behavior, +** but it *is* desirable.) +** +** If successful and SETNAME is nonzero, +** set the applicable parts of tzname, timezone and altzone; +** however, it's OK to omit this step +** if the timezone is compatible with POSIX.1-2017 +** since in that case tzset should have already done this step correctly. +** SETNAME's type is int_fast32_t for compatibility with gmtsub, +** but it is actually a boolean and its value should be 0 or 1. +*/ + +/*ARGSUSED*/ +static struct tm * +localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, + struct tm *const tmp) +{ + register const struct ttinfo * ttisp; + register int i; + register struct tm * result; + const time_t t = *timep; + + if (sp == NULL) { + /* Don't bother to set tzname etc.; tzset has already done it. */ + return gmtsub(gmtptr, timep, 0, tmp); + } + if ((sp->goback && t < sp->ats[0]) || + (sp->goahead && t > sp->ats[sp->timecnt - 1])) { + time_t newt; + register time_t seconds; + register time_t years; + + if (t < sp->ats[0]) + seconds = sp->ats[0] - t; + else seconds = t - sp->ats[sp->timecnt - 1]; + --seconds; + + /* Beware integer overflow, as SECONDS might + be close to the maximum time_t. */ + years = seconds / SECSPERREPEAT * YEARSPERREPEAT; + seconds = years * AVGSECSPERYEAR; + years += YEARSPERREPEAT; + if (t < sp->ats[0]) + newt = t + seconds + SECSPERREPEAT; + else + newt = t - seconds - SECSPERREPEAT; + + if (newt < sp->ats[0] || + newt > sp->ats[sp->timecnt - 1]) + return NULL; /* "cannot happen" */ + result = localsub(sp, &newt, setname, tmp); + if (result) { +#if defined ckd_add && defined ckd_sub + if (t < sp->ats[0] + ? ckd_sub(&result->tm_year, + result->tm_year, years) + : ckd_add(&result->tm_year, + result->tm_year, years)) + return NULL; +#else + register int_fast64_t newy; + + newy = result->tm_year; + if (t < sp->ats[0]) + newy -= years; + else newy += years; + if (! (INT_MIN <= newy && newy <= INT_MAX)) + return NULL; + result->tm_year = newy; +#endif + } + return result; + } + if (sp->timecnt == 0 || t < sp->ats[0]) { + i = sp->defaulttype; + } else { + register int lo = 1; + register int hi = sp->timecnt; + + while (lo < hi) { + register int mid = (lo + hi) >> 1; + + if (t < sp->ats[mid]) + hi = mid; + else lo = mid + 1; + } + i = sp->types[lo - 1]; + } + ttisp = &sp->ttis[i]; + /* + ** To get (wrong) behavior that's compatible with System V Release 2.0 + ** you'd replace the statement below with + ** t += ttisp->tt_utoff; + ** timesub(&t, 0L, sp, tmp); + */ + result = timesub(&t, ttisp->tt_utoff, sp, tmp); + if (result) { + result->tm_isdst = ttisp->tt_isdst; +#ifdef TM_ZONE + result->TM_ZONE = (char *) &sp->chars[ttisp->tt_desigidx]; +#endif /* defined TM_ZONE */ + if (setname) + update_tzname_etc(sp, ttisp); + } + return result; +} + +#if NETBSD_INSPIRED + +struct tm * +localtime_rz(struct state *restrict sp, time_t const *restrict timep, + struct tm *restrict tmp) +{ + return localsub(sp, timep, 0, tmp); +} + +#endif + +static struct tm * +localtime_tzset(time_t const *timep, struct tm *tmp, bool setname) +{ + int err = lock(); + if (err) { + errno = err; + return NULL; + } + if (setname || !lcl_is_set) + tzset_unlocked(); + tmp = localsub(lclptr, timep, setname, tmp); + unlock(); + return tmp; +} + +struct tm * +localtime(const time_t *timep) +{ +#if !SUPPORT_C89 + static struct tm tm; +#endif + return localtime_tzset(timep, &tm, true); +} + +struct tm * +localtime_r(const time_t *restrict timep, struct tm *restrict tmp) +{ + return localtime_tzset(timep, tmp, false); +} + +/* +** gmtsub is to gmtime as localsub is to localtime. +*/ + +static struct tm * +gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep, + int_fast32_t offset, struct tm *tmp) +{ + register struct tm * result; + + result = timesub(timep, offset, gmtptr, tmp); +#ifdef TM_ZONE + /* + ** Could get fancy here and deliver something such as + ** "+xx" or "-xx" if offset is non-zero, + ** but this is no time for a treasure hunt. + */ + tmp->TM_ZONE = ((char *) + (offset ? wildabbr : gmtptr ? gmtptr->chars : utc)); +#endif /* defined TM_ZONE */ + return result; +} + +/* +* Re-entrant version of gmtime. +*/ + +struct tm * +gmtime_r(time_t const *restrict timep, struct tm *restrict tmp) +{ + gmtcheck(); + return gmtsub(gmtptr, timep, 0, tmp); +} + +struct tm * +gmtime(const time_t *timep) +{ +#if !SUPPORT_C89 + static struct tm tm; +#endif + return gmtime_r(timep, &tm); +} + +#if STD_INSPIRED + +/* This function is obsolescent and may disappear in future releases. + Callers can instead use localtime_rz with a fixed-offset zone. */ + +struct tm * +offtime(const time_t *timep, long offset) +{ + gmtcheck(); + +#if !SUPPORT_C89 + static struct tm tm; +#endif + return gmtsub(gmtptr, timep, offset, &tm); +} + +#endif + +/* +** Return the number of leap years through the end of the given year +** where, to make the math easy, the answer for year zero is defined as zero. +*/ + +static time_t +leaps_thru_end_of_nonneg(time_t y) +{ + return y / 4 - y / 100 + y / 400; +} + +static time_t +leaps_thru_end_of(time_t y) +{ + return (y < 0 + ? -1 - leaps_thru_end_of_nonneg(-1 - y) + : leaps_thru_end_of_nonneg(y)); +} + +static struct tm * +timesub(const time_t *timep, int_fast32_t offset, + const struct state *sp, struct tm *tmp) +{ + register const struct lsinfo * lp; + register time_t tdays; + register const int * ip; + register int_fast32_t corr; + register int i; + int_fast32_t idays, rem, dayoff, dayrem; + time_t y; + + /* If less than SECSPERMIN, the number of seconds since the + most recent positive leap second; otherwise, do not add 1 + to localtime tm_sec because of leap seconds. */ + time_t secs_since_posleap = SECSPERMIN; + + corr = 0; + i = (sp == NULL) ? 0 : sp->leapcnt; + while (--i >= 0) { + lp = &sp->lsis[i]; + if (*timep >= lp->ls_trans) { + corr = lp->ls_corr; + if ((i == 0 ? 0 : lp[-1].ls_corr) < corr) + secs_since_posleap = *timep - lp->ls_trans; + break; + } + } + + /* Calculate the year, avoiding integer overflow even if + time_t is unsigned. */ + tdays = *timep / SECSPERDAY; + rem = *timep % SECSPERDAY; + rem += offset % SECSPERDAY - corr % SECSPERDAY + 3 * SECSPERDAY; + dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3; + rem %= SECSPERDAY; + /* y = (EPOCH_YEAR + + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT), + sans overflow. But calculate against 1570 (EPOCH_YEAR - + YEARSPERREPEAT) instead of against 1970 so that things work + for localtime values before 1970 when time_t is unsigned. */ + dayrem = tdays % DAYSPERREPEAT; + dayrem += dayoff % DAYSPERREPEAT; + y = (EPOCH_YEAR - YEARSPERREPEAT + + ((1 + dayoff / DAYSPERREPEAT + dayrem / DAYSPERREPEAT + - ((dayrem % DAYSPERREPEAT) < 0) + + tdays / DAYSPERREPEAT) + * YEARSPERREPEAT)); + /* idays = (tdays + dayoff) mod DAYSPERREPEAT, sans overflow. */ + idays = tdays % DAYSPERREPEAT; + idays += dayoff % DAYSPERREPEAT + 2 * DAYSPERREPEAT; + idays %= DAYSPERREPEAT; + /* Increase Y and decrease IDAYS until IDAYS is in range for Y. */ + while (year_lengths[isleap(y)] <= idays) { + int tdelta = idays / DAYSPERLYEAR; + int_fast32_t ydelta = tdelta + !tdelta; + time_t newy = y + ydelta; + register int leapdays; + leapdays = leaps_thru_end_of(newy - 1) - + leaps_thru_end_of(y - 1); + idays -= ydelta * DAYSPERNYEAR; + idays -= leapdays; + y = newy; + } + +#ifdef ckd_add + if (ckd_add(&tmp->tm_year, y, -TM_YEAR_BASE)) { + errno = EOVERFLOW; + return NULL; + } +#else + if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) { + int signed_y = y; + tmp->tm_year = signed_y - TM_YEAR_BASE; + } else if ((!TYPE_SIGNED(time_t) || INT_MIN + TM_YEAR_BASE <= y) + && y - TM_YEAR_BASE <= INT_MAX) + tmp->tm_year = y - TM_YEAR_BASE; + else { + errno = EOVERFLOW; + return NULL; + } +#endif + tmp->tm_yday = idays; + /* + ** The "extra" mods below avoid overflow problems. + */ + tmp->tm_wday = (TM_WDAY_BASE + + ((tmp->tm_year % DAYSPERWEEK) + * (DAYSPERNYEAR % DAYSPERWEEK)) + + leaps_thru_end_of(y - 1) + - leaps_thru_end_of(TM_YEAR_BASE - 1) + + idays); + tmp->tm_wday %= DAYSPERWEEK; + if (tmp->tm_wday < 0) + tmp->tm_wday += DAYSPERWEEK; + tmp->tm_hour = rem / SECSPERHOUR; + rem %= SECSPERHOUR; + tmp->tm_min = rem / SECSPERMIN; + tmp->tm_sec = rem % SECSPERMIN; + + /* Use "... ??:??:60" at the end of the localtime minute containing + the second just before the positive leap second. */ + tmp->tm_sec += secs_since_posleap <= tmp->tm_sec; + + ip = mon_lengths[isleap(y)]; + for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon)) + idays -= ip[tmp->tm_mon]; + tmp->tm_mday = idays + 1; + tmp->tm_isdst = 0; +#ifdef TM_GMTOFF + tmp->TM_GMTOFF = offset; +#endif /* defined TM_GMTOFF */ + return tmp; +} + +/* +** Adapted from code provided by Robert Elz, who writes: +** The "best" way to do mktime I think is based on an idea of Bob +** Kridle's (so its said...) from a long time ago. +** It does a binary search of the time_t space. Since time_t's are +** just 32 bits, its a max of 32 iterations (even at 64 bits it +** would still be very reasonable). +*/ + +#ifndef WRONG +# define WRONG (-1) +#endif /* !defined WRONG */ + +/* +** Normalize logic courtesy Paul Eggert. +*/ + +static bool +increment_overflow(int *ip, int j) +{ +#ifdef ckd_add + return ckd_add(ip, *ip, j); +#else + register int const i = *ip; + + /* + ** If i >= 0 there can only be overflow if i + j > INT_MAX + ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow. + ** If i < 0 there can only be overflow if i + j < INT_MIN + ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow. + */ + if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i)) + return true; + *ip += j; + return false; +#endif +} + +static bool +increment_overflow32(int_fast32_t *const lp, int const m) +{ +#ifdef ckd_add + return ckd_add(lp, *lp, m); +#else + register int_fast32_t const l = *lp; + + if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l)) + return true; + *lp += m; + return false; +#endif +} + +static bool +increment_overflow_time(time_t *tp, int_fast32_t j) +{ +#ifdef ckd_add + return ckd_add(tp, *tp, j); +#else + /* + ** This is like + ** 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...', + ** except that it does the right thing even if *tp + j would overflow. + */ + if (! (j < 0 + ? (TYPE_SIGNED(time_t) ? TIME_T_MIN - j <= *tp : -1 - j < *tp) + : *tp <= TIME_T_MAX - j)) + return true; + *tp += j; + return false; +#endif +} + +static bool +normalize_overflow(int *const tensptr, int *const unitsptr, const int base) +{ + register int tensdelta; + + tensdelta = (*unitsptr >= 0) ? + (*unitsptr / base) : + (-1 - (-1 - *unitsptr) / base); + *unitsptr -= tensdelta * base; + return increment_overflow(tensptr, tensdelta); +} + +static bool +normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base) +{ + register int tensdelta; + + tensdelta = (*unitsptr >= 0) ? + (*unitsptr / base) : + (-1 - (-1 - *unitsptr) / base); + *unitsptr -= tensdelta * base; + return increment_overflow32(tensptr, tensdelta); +} + +static int +tmcomp(register const struct tm *const atmp, + register const struct tm *const btmp) +{ + register int result; + + if (atmp->tm_year != btmp->tm_year) + return atmp->tm_year < btmp->tm_year ? -1 : 1; + if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 && + (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && + (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && + (result = (atmp->tm_min - btmp->tm_min)) == 0) + result = atmp->tm_sec - btmp->tm_sec; + return result; +} + +/* Copy to *DEST from *SRC. Copy only the members needed for mktime, + as other members might not be initialized. */ +static void +mktmcpy(struct tm *dest, struct tm const *src) +{ + dest->tm_sec = src->tm_sec; + dest->tm_min = src->tm_min; + dest->tm_hour = src->tm_hour; + dest->tm_mday = src->tm_mday; + dest->tm_mon = src->tm_mon; + dest->tm_year = src->tm_year; + dest->tm_isdst = src->tm_isdst; +#if defined TM_GMTOFF && ! UNINIT_TRAP + dest->TM_GMTOFF = src->TM_GMTOFF; +#endif +} + +static time_t +time2sub(struct tm *const tmp, + struct tm *(*funcp)(struct state const *, time_t const *, + int_fast32_t, struct tm *), + struct state const *sp, + const int_fast32_t offset, + bool *okayp, + bool do_norm_secs) +{ + register int dir; + register int i, j; + register int saved_seconds; + register int_fast32_t li; + register time_t lo; + register time_t hi; + int_fast32_t y; + time_t newt; + time_t t; + struct tm yourtm, mytm; + + *okayp = false; + mktmcpy(&yourtm, tmp); + + if (do_norm_secs) { + if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, + SECSPERMIN)) + return WRONG; + } + if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) + return WRONG; + if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) + return WRONG; + y = yourtm.tm_year; + if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR)) + return WRONG; + /* + ** Turn y into an actual year number for now. + ** It is converted back to an offset from TM_YEAR_BASE later. + */ + if (increment_overflow32(&y, TM_YEAR_BASE)) + return WRONG; + while (yourtm.tm_mday <= 0) { + if (increment_overflow32(&y, -1)) + return WRONG; + li = y + (1 < yourtm.tm_mon); + yourtm.tm_mday += year_lengths[isleap(li)]; + } + while (yourtm.tm_mday > DAYSPERLYEAR) { + li = y + (1 < yourtm.tm_mon); + yourtm.tm_mday -= year_lengths[isleap(li)]; + if (increment_overflow32(&y, 1)) + return WRONG; + } + for ( ; ; ) { + i = mon_lengths[isleap(y)][yourtm.tm_mon]; + if (yourtm.tm_mday <= i) + break; + yourtm.tm_mday -= i; + if (++yourtm.tm_mon >= MONSPERYEAR) { + yourtm.tm_mon = 0; + if (increment_overflow32(&y, 1)) + return WRONG; + } + } +#ifdef ckd_add + if (ckd_add(&yourtm.tm_year, y, -TM_YEAR_BASE)) + return WRONG; +#else + if (increment_overflow32(&y, -TM_YEAR_BASE)) + return WRONG; + if (! (INT_MIN <= y && y <= INT_MAX)) + return WRONG; + yourtm.tm_year = y; +#endif + if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) + saved_seconds = 0; + else if (yourtm.tm_year < EPOCH_YEAR - TM_YEAR_BASE) { + /* + ** We can't set tm_sec to 0, because that might push the + ** time below the minimum representable time. + ** Set tm_sec to 59 instead. + ** This assumes that the minimum representable time is + ** not in the same minute that a leap second was deleted from, + ** which is a safer assumption than using 58 would be. + */ + if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) + return WRONG; + saved_seconds = yourtm.tm_sec; + yourtm.tm_sec = SECSPERMIN - 1; + } else { + saved_seconds = yourtm.tm_sec; + yourtm.tm_sec = 0; + } + /* + ** Do a binary search (this works whatever time_t's type is). + */ + lo = TIME_T_MIN; + hi = TIME_T_MAX; + for ( ; ; ) { + t = lo / 2 + hi / 2; + if (t < lo) + t = lo; + else if (t > hi) + t = hi; + if (! funcp(sp, &t, offset, &mytm)) { + /* + ** Assume that t is too extreme to be represented in + ** a struct tm; arrange things so that it is less + ** extreme on the next pass. + */ + dir = (t > 0) ? 1 : -1; + } else dir = tmcomp(&mytm, &yourtm); + if (dir != 0) { + if (t == lo) { + if (t == TIME_T_MAX) + return WRONG; + ++t; + ++lo; + } else if (t == hi) { + if (t == TIME_T_MIN) + return WRONG; + --t; + --hi; + } + if (lo > hi) + return WRONG; + if (dir > 0) + hi = t; + else lo = t; + continue; + } +#if defined TM_GMTOFF && ! UNINIT_TRAP + if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF + && (yourtm.TM_GMTOFF < 0 + ? (-SECSPERDAY <= yourtm.TM_GMTOFF + && (mytm.TM_GMTOFF <= + (min(INT_FAST32_MAX, LONG_MAX) + + yourtm.TM_GMTOFF))) + : (yourtm.TM_GMTOFF <= SECSPERDAY + && ((max(INT_FAST32_MIN, LONG_MIN) + + yourtm.TM_GMTOFF) + <= mytm.TM_GMTOFF)))) { + /* MYTM matches YOURTM except with the wrong UT offset. + YOURTM.TM_GMTOFF is plausible, so try it instead. + It's OK if YOURTM.TM_GMTOFF contains uninitialized data, + since the guess gets checked. */ + time_t altt = t; + int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF; + if (!increment_overflow_time(&altt, diff)) { + struct tm alttm; + if (funcp(sp, &altt, offset, &alttm) + && alttm.tm_isdst == mytm.tm_isdst + && alttm.TM_GMTOFF == yourtm.TM_GMTOFF + && tmcomp(&alttm, &yourtm) == 0) { + t = altt; + mytm = alttm; + } + } + } +#endif + if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) + break; + /* + ** Right time, wrong type. + ** Hunt for right time, right type. + ** It's okay to guess wrong since the guess + ** gets checked. + */ + if (sp == NULL) + return WRONG; + for (i = sp->typecnt - 1; i >= 0; --i) { + if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) + continue; + for (j = sp->typecnt - 1; j >= 0; --j) { + if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) + continue; + if (ttunspecified(sp, j)) + continue; + newt = (t + sp->ttis[j].tt_utoff + - sp->ttis[i].tt_utoff); + if (! funcp(sp, &newt, offset, &mytm)) + continue; + if (tmcomp(&mytm, &yourtm) != 0) + continue; + if (mytm.tm_isdst != yourtm.tm_isdst) + continue; + /* + ** We have a match. + */ + t = newt; + goto label; + } + } + return WRONG; + } +label: + newt = t + saved_seconds; + if ((newt < t) != (saved_seconds < 0)) + return WRONG; + t = newt; + if (funcp(sp, &t, offset, tmp)) + *okayp = true; + return t; +} + +static time_t +time2(struct tm * const tmp, + struct tm *(*funcp)(struct state const *, time_t const *, + int_fast32_t, struct tm *), + struct state const *sp, + const int_fast32_t offset, + bool *okayp) +{ + time_t t; + + /* + ** First try without normalization of seconds + ** (in case tm_sec contains a value associated with a leap second). + ** If that fails, try with normalization of seconds. + */ + t = time2sub(tmp, funcp, sp, offset, okayp, false); + return *okayp ? t : time2sub(tmp, funcp, sp, offset, okayp, true); +} + +static time_t +time1(struct tm *const tmp, + struct tm *(*funcp)(struct state const *, time_t const *, + int_fast32_t, struct tm *), + struct state const *sp, + const int_fast32_t offset) +{ + register time_t t; + register int samei, otheri; + register int sameind, otherind; + register int i; + register int nseen; + char seen[TZ_MAX_TYPES]; + unsigned char types[TZ_MAX_TYPES]; + bool okay; + + if (tmp == NULL) { + errno = EINVAL; + return WRONG; + } + if (tmp->tm_isdst > 1) + tmp->tm_isdst = 1; + t = time2(tmp, funcp, sp, offset, &okay); + if (okay) + return t; + if (tmp->tm_isdst < 0) +#ifdef PCTS + /* + ** POSIX Conformance Test Suite code courtesy Grant Sullivan. + */ + tmp->tm_isdst = 0; /* reset to std and try again */ +#else + return t; +#endif /* !defined PCTS */ + /* + ** We're supposed to assume that somebody took a time of one type + ** and did some math on it that yielded a "struct tm" that's bad. + ** We try to divine the type they started from and adjust to the + ** type they need. + */ + if (sp == NULL) + return WRONG; + for (i = 0; i < sp->typecnt; ++i) + seen[i] = false; + nseen = 0; + for (i = sp->timecnt - 1; i >= 0; --i) + if (!seen[sp->types[i]] && !ttunspecified(sp, sp->types[i])) { + seen[sp->types[i]] = true; + types[nseen++] = sp->types[i]; + } + for (sameind = 0; sameind < nseen; ++sameind) { + samei = types[sameind]; + if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) + continue; + for (otherind = 0; otherind < nseen; ++otherind) { + otheri = types[otherind]; + if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) + continue; + tmp->tm_sec += (sp->ttis[otheri].tt_utoff + - sp->ttis[samei].tt_utoff); + tmp->tm_isdst = !tmp->tm_isdst; + t = time2(tmp, funcp, sp, offset, &okay); + if (okay) + return t; + tmp->tm_sec -= (sp->ttis[otheri].tt_utoff + - sp->ttis[samei].tt_utoff); + tmp->tm_isdst = !tmp->tm_isdst; + } + } + return WRONG; +} + +static time_t +mktime_tzname(struct state *sp, struct tm *tmp, bool setname) +{ + if (sp) + return time1(tmp, localsub, sp, setname); + else { + gmtcheck(); + return time1(tmp, gmtsub, gmtptr, 0); + } +} + +#if NETBSD_INSPIRED + +time_t +mktime_z(struct state *restrict sp, struct tm *restrict tmp) +{ + return mktime_tzname(sp, tmp, false); +} + +#endif + +time_t +mktime(struct tm *tmp) +{ + time_t t; + int err = lock(); + if (err) { + errno = err; + return -1; + } + tzset_unlocked(); + t = mktime_tzname(lclptr, tmp, true); + unlock(); + return t; +} + +#if STD_INSPIRED +/* This function is obsolescent and may disapper in future releases. + Callers can instead use mktime. */ +time_t +timelocal(struct tm *tmp) +{ + if (tmp != NULL) + tmp->tm_isdst = -1; /* in case it wasn't initialized */ + return mktime(tmp); +} +#endif + +#ifndef EXTERN_TIMEOFF +# ifndef timeoff +# define timeoff my_timeoff /* Don't collide with OpenBSD 7.4 . */ +# endif +# define EXTERN_TIMEOFF static +#endif + +/* This function is obsolescent and may disapper in future releases. + Callers can instead use mktime_z with a fixed-offset zone. */ +EXTERN_TIMEOFF time_t +timeoff(struct tm *tmp, long offset) +{ + if (tmp) + tmp->tm_isdst = 0; + gmtcheck(); + return time1(tmp, gmtsub, gmtptr, offset); +} + +time_t +timegm(struct tm *tmp) +{ + time_t t; + struct tm tmcpy; + mktmcpy(&tmcpy, tmp); + tmcpy.tm_wday = -1; + t = timeoff(&tmcpy, 0); + if (0 <= tmcpy.tm_wday) + *tmp = tmcpy; + return t; +} + +static int_fast32_t +leapcorr(struct state const *sp, time_t t) +{ + register struct lsinfo const * lp; + register int i; + + i = sp->leapcnt; + while (--i >= 0) { + lp = &sp->lsis[i]; + if (t >= lp->ls_trans) + return lp->ls_corr; + } + return 0; +} + +/* +** XXX--is the below the right way to conditionalize?? +*/ + +#if STD_INSPIRED + +/* NETBSD_INSPIRED_EXTERN functions are exported to callers if + NETBSD_INSPIRED is defined, and are private otherwise. */ +# if NETBSD_INSPIRED +# define NETBSD_INSPIRED_EXTERN +# else +# define NETBSD_INSPIRED_EXTERN static +# endif + +/* +** IEEE Std 1003.1 (POSIX) says that 536457599 +** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which +** is not the case if we are accounting for leap seconds. +** So, we provide the following conversion routines for use +** when exchanging timestamps with POSIX conforming systems. +*/ + +NETBSD_INSPIRED_EXTERN time_t +time2posix_z(struct state *sp, time_t t) +{ + return t - leapcorr(sp, t); +} + +time_t +time2posix(time_t t) +{ + int err = lock(); + if (err) { + errno = err; + return -1; + } + if (!lcl_is_set) + tzset_unlocked(); + if (lclptr) + t = time2posix_z(lclptr, t); + unlock(); + return t; +} + +NETBSD_INSPIRED_EXTERN time_t +posix2time_z(struct state *sp, time_t t) +{ + time_t x; + time_t y; + /* + ** For a positive leap second hit, the result + ** is not unique. For a negative leap second + ** hit, the corresponding time doesn't exist, + ** so we return an adjacent second. + */ + x = t + leapcorr(sp, t); + y = x - leapcorr(sp, x); + if (y < t) { + do { + x++; + y = x - leapcorr(sp, x); + } while (y < t); + x -= y != t; + } else if (y > t) { + do { + --x; + y = x - leapcorr(sp, x); + } while (y > t); + x += y != t; + } + return x; +} + +time_t +posix2time(time_t t) +{ + int err = lock(); + if (err) { + errno = err; + return -1; + } + if (!lcl_is_set) + tzset_unlocked(); + if (lclptr) + t = posix2time_z(lclptr, t); + unlock(); + return t; +} + +#endif /* STD_INSPIRED */ + +#if TZ_TIME_T + +# if !USG_COMPAT +# define daylight 0 +# define timezone 0 +# endif +# if !ALTZONE +# define altzone 0 +# endif + +/* Convert from the underlying system's time_t to the ersatz time_tz, + which is called 'time_t' in this file. Typically, this merely + converts the time's integer width. On some platforms, the system + time is local time not UT, or uses some epoch other than the POSIX + epoch. + + Although this code appears to define a function named 'time' that + returns time_t, the macros in private.h cause this code to actually + define a function named 'tz_time' that returns tz_time_t. The call + to sys_time invokes the underlying system's 'time' function. */ + +time_t +time(time_t *p) +{ + time_t r = sys_time(0); + if (r != (time_t) -1) { + int_fast32_t offset = EPOCH_LOCAL ? (daylight ? timezone : altzone) : 0; + if (increment_overflow32(&offset, -EPOCH_OFFSET) + || increment_overflow_time(&r, offset)) { + errno = EOVERFLOW; + r = -1; + } + } + if (p) + *p = r; + return r; +} + +#endif diff --git a/vendor/chrono-tz/tz/newctime.3 b/vendor/chrono-tz/tz/newctime.3 new file mode 100644 index 0000000000000..3b54d4ad6ad24 --- /dev/null +++ b/vendor/chrono-tz/tz/newctime.3 @@ -0,0 +1,354 @@ +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. +.TH newctime 3 "" "Time Zone Database" +.SH NAME +asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time +.SH SYNOPSIS +.nf +.ie \n(.g .ds - \f(CR-\fP +.el .ds - \- +.B #include +.PP +.BR "extern char *tzname[];" " /\(** (optional) \(**/" +.PP +.B [[deprecated]] char *ctime(time_t const *clock); +.PP +.B char *ctime_r(time_t const *clock, char *buf); +.PP +.B double difftime(time_t time1, time_t time0); +.PP +.B [[deprecated]] char *asctime(struct tm const *tm); +.PP +.B "char *asctime_r(struct tm const *restrict tm," +.B " char *restrict result);" +.PP +.B struct tm *localtime(time_t const *clock); +.PP +.B "struct tm *localtime_r(time_t const *restrict clock," +.B " struct tm *restrict result);" +.PP +.B "struct tm *localtime_rz(timezone_t restrict zone," +.B " time_t const *restrict clock," +.B " struct tm *restrict result);" +.PP +.B struct tm *gmtime(time_t const *clock); +.PP +.B "struct tm *gmtime_r(time_t const *restrict clock," +.B " struct tm *restrict result);" +.PP +.B time_t mktime(struct tm *tm); +.PP +.B "time_t mktime_z(timezone_t restrict zone," +.B " struct tm *restrict tm);" +.PP +.B cc ... \*-ltz +.fi +.SH DESCRIPTION +.ie '\(en'' .ds en \- +.el .ds en \(en +.ie '\(lq'' .ds lq \&"\" +.el .ds lq \(lq\" +.ie '\(rq'' .ds rq \&"\" +.el .ds rq \(rq\" +.de q +\\$3\*(lq\\$1\*(rq\\$2 +.. +The +.B ctime +function +converts a long integer, pointed to by +.IR clock , +and returns a pointer to a +string of the form +.br +.ce +.eo +Thu Nov 24 18:22:48 1986\n\0 +.br +.ec +Years requiring fewer than four characters are padded with leading zeroes. +For years longer than four characters, the string is of the form +.br +.ce +.eo +Thu Nov 24 18:22:48 81986\n\0 +.ec +.br +with five spaces before the year. +These unusual formats are designed to make it less likely that older +software that expects exactly 26 bytes of output will mistakenly output +misleading values for out-of-range years. +.PP +The +.BI * clock +timestamp represents the time in seconds since 1970-01-01 00:00:00 +Coordinated Universal Time (UTC). +The POSIX standard says that timestamps must be nonnegative +and must ignore leap seconds. +Many implementations extend POSIX by allowing negative timestamps, +and can therefore represent timestamps that predate the +introduction of UTC and are some other flavor of Universal Time (UT). +Some implementations support leap seconds, in contradiction to POSIX. +.PP +The +.B ctime +function is deprecated starting in C23. +Callers can use +.B localtime_r +and +.B strftime +instead. +.PP +The +.B localtime +and +.B gmtime +functions +return pointers to +.q "tm" +structures, described below. +The +.B localtime +function +corrects for the time zone and any time zone adjustments +(such as Daylight Saving Time in the United States). +After filling in the +.q "tm" +structure, +.B localtime +sets the +.BR tm_isdst 'th +element of +.B tzname +to a pointer to a string that's the time zone abbreviation to be used with +.BR localtime 's +return value. +.PP +The +.B gmtime +function +converts to Coordinated Universal Time. +.PP +The +.B asctime +function +converts a time value contained in a +.q "tm" +structure to a string, +as shown in the above example, +and returns a pointer to the string. +This function is deprecated starting in C23. +Callers can use +.B strftime +instead. +.PP +The +.B mktime +function +converts the broken-down time, +expressed as local time, +in the structure pointed to by +.I tm +into a calendar time value with the same encoding as that of the values +returned by the +.B time +function. +The original values of the +.B tm_wday +and +.B tm_yday +components of the structure are ignored, +and the original values of the other components are not restricted +to their normal ranges. +(A positive or zero value for +.B tm_isdst +causes +.B mktime +to presume initially that daylight saving time +respectively, +is or is not in effect for the specified time. +A negative value for +.B tm_isdst +causes the +.B mktime +function to attempt to divine whether daylight saving time is in effect +for the specified time; in this case it does not use a consistent +rule and may give a different answer when later +presented with the same argument.) +On successful completion, the values of the +.B tm_wday +and +.B tm_yday +components of the structure are set appropriately, +and the other components are set to represent the specified calendar time, +but with their values forced to their normal ranges; the final value of +.B tm_mday +is not set until +.B tm_mon +and +.B tm_year +are determined. +The +.B mktime +function +returns the specified calendar time; +If the calendar time cannot be represented, +it returns \-1. +.PP +The +.B difftime +function +returns the difference between two calendar times, +.RI ( time1 +\- +.IR time0 ), +expressed in seconds. +.PP +The +.BR ctime_r , +.BR localtime_r , +.BR gmtime_r , +and +.B asctime_r +functions +are like their unsuffixed counterparts, except that they accept an +additional argument specifying where to store the result if successful. +.PP +The +.B localtime_rz +and +.B mktime_z +functions +are like their unsuffixed counterparts, except that they accept an +extra initial +.B zone +argument specifying the timezone to be used for conversion. +If +.B zone +is null, UT is used; otherwise, +.B zone +should be have been allocated by +.B tzalloc +and should not be freed until after all uses (e.g., by calls to +.BR strftime ) +of the filled-in +.B tm_zone +fields. +.PP +Declarations of all the functions and externals, and the +.q "tm" +structure, +are in the +.B +header file. +The structure (of type) +.B struct tm +includes the following fields: +.RS +.PP +.nf +.ta 2n +\w'long tm_gmtoff;nn'u + int tm_sec; /\(** seconds (0\*(en60) \(**/ + int tm_min; /\(** minutes (0\*(en59) \(**/ + int tm_hour; /\(** hours (0\*(en23) \(**/ + int tm_mday; /\(** day of month (1\*(en31) \(**/ + int tm_mon; /\(** month of year (0\*(en11) \(**/ + int tm_year; /\(** year \- 1900 \(**/ + int tm_wday; /\(** day of week (Sunday = 0) \(**/ + int tm_yday; /\(** day of year (0\*(en365) \(**/ + int tm_isdst; /\(** is daylight saving time in effect? \(**/ + char \(**tm_zone; /\(** time zone abbreviation (optional) \(**/ + long tm_gmtoff; /\(** offset from UT in seconds (optional) \(**/ +.fi +.RE +.PP +The +.B tm_isdst +field +is non-zero if daylight saving time is in effect. +.PP +The +.B tm_gmtoff +field +is the offset (in seconds) of the time represented +from UT, with positive values indicating east +of the Prime Meridian. +The field's name is derived from Greenwich Mean Time, a precursor of UT. +.PP +In +.B "struct tm" +the +.B tm_zone +and +.B tm_gmtoff +fields exist, and are filled in, only if arrangements to do +so were made when the library containing these functions was +created. +Similarly, the +.B tzname +variable is optional; also, there is no guarantee that +.B tzname +will +continue to exist in this form in future releases of this code. +.SH FILES +.ta \w'/usr/share/zoneinfo/posixrules\0\0'u +/etc/localtime local timezone file +.br +/usr/share/zoneinfo timezone directory +.br +/usr/share/zoneinfo/posixrules default DST rules (obsolete) +.br +/usr/share/zoneinfo/GMT for UTC leap seconds +.PP +If /usr/share/zoneinfo/GMT is absent, +UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present. +.SH SEE ALSO +getenv(3), +newstrftime(3), +newtzset(3), +time(2), +tzfile(5) +.SH NOTES +The return values of +.BR asctime , +.BR ctime , +.BR gmtime , +and +.B localtime +point to static data +overwritten by each call. +The +.B tzname +variable (once set) and the +.B tm_zone +field of a returned +.B "struct tm" +both point to an array of characters that +can be freed or overwritten by later calls to the functions +.BR localtime , +.BR tzfree , +and +.BR tzset , +if these functions affect the timezone information that specifies the +abbreviation in question. +The remaining functions and data are thread-safe. +.PP +The +.BR asctime , +.BR asctime_r , +.BR ctime , +and +.B ctime_r +functions +behave strangely for years before 1000 or after 9999. +The 1989 and 1999 editions of the C Standard say +that years from \-99 through 999 are converted without +extra spaces, but this conflicts with longstanding +tradition and with this implementation. +The 2011 edition says that the behavior +is undefined if the year is before 1000 or after 9999. +Traditional implementations of these two functions are +restricted to years in the range 1900 through 2099. +To avoid this portability mess, new programs should use +.B strftime +instead. diff --git a/vendor/chrono-tz/tz/newstrftime.3 b/vendor/chrono-tz/tz/newstrftime.3 new file mode 100644 index 0000000000000..704318ea26933 --- /dev/null +++ b/vendor/chrono-tz/tz/newstrftime.3 @@ -0,0 +1,438 @@ +.\" strftime man page +.\" +.\" Based on the UCB file whose corrected copyright information appears below. +.\" Copyright 1989, 1991 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" from: @(#)strftime.3 5.12 (Berkeley) 6/29/91 +.\" $Id: strftime.3,v 1.4 1993/12/15 20:33:00 jtc Exp $ +.\" +.TH newstrftime 3 "" "Time Zone Database" +.SH NAME +strftime \- format date and time +.SH SYNOPSIS +.nf +.ie \n(.g .ds - \f(CR-\fP +.el .ds - \- +.B #include +.PP +.B "size_t strftime(char *restrict buf, size_t maxsize," +.B " char const *restrict format, struct tm const *restrict timeptr);" +.PP +.B cc ... \-ltz +.fi +.SH DESCRIPTION +.ie '\(lq'' .ds lq \&"\" +.el .ds lq \(lq\" +.ie '\(rq'' .ds rq \&"\" +.el .ds rq \(rq\" +.de c +.ie \n(.g \f(CR\\$1\fP\\$2 +.el \\$1\\$2 +.. +.de q +\\$3\*(lq\\$1\*(rq\\$2 +.. +The +.B strftime +function formats the information from +.BI * timeptr +into the array pointed to by +.I buf +according to the string pointed to by +.IR format . +.PP +The +.I format +string consists of zero or more conversion specifications and +ordinary characters. +All ordinary characters are copied directly into the array. +A conversion specification consists of a percent sign +.Ql % +and one other character. +.PP +No more than +.I maxsize +bytes are placed into the array. +.PP +Each conversion specification is replaced by the characters as +follows which are then copied into the array. +The characters depend on the values of zero or more members of +.BI * timeptr +as specified by brackets in the description. +If a bracketed member name is followed by +.q + , +.B strftime +can use the named member even though POSIX.1-2017 does not list it; +if the name is followed by +.q \*- , +.B strftime +ignores the member even though POSIX.1-2017 lists it +which means portable code should set it. +For portability, +.BI * timeptr +should be initialized as if by a successful call to +.BR gmtime , +.BR localtime , +.BR mktime , +.BR timegm , +or similar functions. +.TP +%A +is replaced by the locale's full weekday name. +.RI [ tm_wday ] +.TP +%a +is replaced by the locale's abbreviated weekday name. +.RI [ tm_wday ] +.TP +%B +is replaced by the locale's full month name. +.RI [ tm_mon ] +.TP +%b or %h +is replaced by the locale's abbreviated month name. +.RI [ tm_mon ] +.TP +%C +is replaced by the century (a year divided by 100 and truncated to an integer) +as a decimal number, with at least two digits by default. +.RI [ tm_year ] +.TP +%c +is replaced by the locale's appropriate date and time representation. +.RI [ tm_year , +.IR tm_yday , +.IR tm_mon , +.IR tm_mday , +.IR tm_wday , +.IR tm_hour , +.IR tm_min , +.IR tm_sec , +.IR tm_gmtoff +, +.IR tm_zone +, +.IR tm_isdst \*-]. +.TP +%D +is equivalent to +.c %m/%d/%y . +.RI [ tm_year , +.IR tm_mon , +.IR tm_mday ] +.TP +%d +is replaced by the day of the month as a decimal number [01,31]. +.RI [ tm_mday ] +.TP +%e +is replaced by the day of month as a decimal number [1,31]; +single digits are preceded by a blank. +.RI [ tm_mday ] +.TP +%F +is equivalent to +.c %Y-%m-%d +(the ISO 8601 date format). +.RI [ tm_year , +.IR tm_mon , +.IR tm_mday ] +.TP +%G +is replaced by the ISO 8601 year with century as a decimal number. +See also the +.c %V +conversion specification. +.RI [ tm_year , +.IR tm_yday , +.IR tm_wday ] +.TP +%g +is replaced by the ISO 8601 year without century as a decimal number [00,99]. +This is the year that includes the greater part of the week. +(Monday as the first day of a week). +See also the +.c %V +conversion specification. +.RI [ tm_year , +.IR tm_yday , +.IR tm_wday ] +.TP +%H +is replaced by the hour (24-hour clock) as a decimal number [00,23]. +.RI [ tm_hour ] +.TP +%I +is replaced by the hour (12-hour clock) as a decimal number [01,12]. +.RI [ tm_hour ] +.TP +%j +is replaced by the day of the year as a decimal number [001,366]. +.RI [ tm_yday ] +.TP +%k +is replaced by the hour (24-hour clock) as a decimal number [0,23]; +single digits are preceded by a blank. +.RI [ tm_hour ] +.TP +%l +is replaced by the hour (12-hour clock) as a decimal number [1,12]; +single digits are preceded by a blank. +.RI [ tm_hour ] +.TP +%M +is replaced by the minute as a decimal number [00,59]. +.RI [ tm_min ] +.TP +%m +is replaced by the month as a decimal number [01,12]. +.RI [ tm_mon ] +.TP +%n +is replaced by a newline. +.TP +%p +is replaced by the locale's equivalent of either +.q AM +or +.q PM . +.RI [ tm_hour ] +.TP +%R +is replaced by the time in the format +.c %H:%M . +.RI [ tm_hour , +.IR tm_min ] +.TP +%r +is replaced by the locale's representation of 12-hour clock time +using AM/PM notation. +.RI [ tm_hour , +.IR tm_min , +.IR tm_sec ] +.TP +%S +is replaced by the second as a decimal number [00,60]. +The range of +seconds is [00,60] instead of [00,59] to allow for the periodic occurrence +of leap seconds. +.RI [ tm_sec ] +.TP +%s +is replaced by the number of seconds since the Epoch (see +.BR ctime (3)). +Although %s is reliable in this implementation, +it can have glitches on other platforms (notably platforms lacking +.IR tm_gmtoff ), +so portable code should format a +.B time_t +value directly via something like +.B sprintf +instead of via +.B localtime +followed by +.B strftime +with "%s". +.RI [ tm_year , +.IR tm_mon , +.IR tm_mday , +.IR tm_hour , +.IR tm_min , +.IR tm_sec , +.IR tm_gmtoff +, +.IR tm_isdst \*-]. +.TP +%T +is replaced by the time in the format +.c %H:%M:%S . +.RI [ tm_hour , +.IR tm_min , +.IR tm_sec ] +.TP +%t +is replaced by a tab. +.TP +%U +is replaced by the week number of the year (Sunday as the first day of +the week) as a decimal number [00,53]. +.RI [ tm_wday , +.IR tm_yday , +.IR tm_year \*-] +.TP +%u +is replaced by the weekday (Monday as the first day of the week) +as a decimal number [1,7]. +.RI [ tm_wday ] +.TP +%V +is replaced by the week number of the year (Monday as the first day of +the week) as a decimal number [01,53]. If the week containing January +1 has four or more days in the new year, then it is week 1; otherwise +it is week 53 of the previous year, and the next week is week 1. +The year is given by the +.c %G +conversion specification. +.RI [ tm_year , +.IR tm_yday , +.IR tm_wday ] +.TP +%W +is replaced by the week number of the year (Monday as the first day of +the week) as a decimal number [00,53]. +.RI [ tm_yday , +.IR tm_wday ] +.TP +%w +is replaced by the weekday (Sunday as the first day of the week) +as a decimal number [0,6]. +.RI [ tm_year , +.IR tm_yday , +.IR tm_wday ] +.TP +%X +is replaced by the locale's appropriate time representation. +.RI [ tm_year \*-, +.IR tm_yday \*-, +.IR tm_mon \*-, +.IR tm_mday \*-, +.IR tm_wday \*-, +.IR tm_hour , +.IR tm_min , +.IR tm_sec , +.IR tm_gmtoff +, +.IR tm_zone +, +.IR tm_isdst \*-]. +.TP +%x +is replaced by the locale's appropriate date representation. +.RI [ tm_year , +.IR tm_yday , +.IR tm_mon , +.IR tm_mday , +.IR tm_wday , +.IR tm_hour \*-, +.IR tm_min \*-, +.IR tm_sec \*-, +.IR tm_gmtoff \*-, +.IR tm_zone \*-, +.IR tm_isdst \*-]. +.TP +%Y +is replaced by the year with century as a decimal number. +.RI [ tm_year ] +.TP +%y +is replaced by the year without century as a decimal number [00,99]. +.RI [ tm_year ] +.TP +%Z +is replaced by the time zone abbreviation, +or by the empty string if this is not determinable. +.RI [ tm_zone +, +.IR tm_isdst \*-] +.TP +%z +is replaced by the offset from the Prime Meridian +in the format +HHMM or \*-HHMM (ISO 8601) as appropriate, +with positive values representing locations east of Greenwich, +or by the empty string if this is not determinable. +The numeric time zone abbreviation \*-0000 is used when the time is +Universal Time +but local time is indeterminate; by convention this is used for +locations while uninhabited, and corresponds to a zero offset when the +time zone abbreviation begins with +.q "\*-" . +.RI [ tm_gmtoff +, +.IR tm_zone +, +.IR tm_isdst \*-] +.TP +%% +is replaced by a single %. +.TP +%+ +is replaced by the locale's date and time in +.BR date (1) +format. +.RI [ tm_year , +.IR tm_yday , +.IR tm_mon , +.IR tm_mday , +.IR tm_wday , +.IR tm_hour , +.IR tm_min , +.IR tm_sec , +.IR tm_gmtoff , +.IR tm_zone ] +.PP +As a side effect, +.B strftime +also behaves as if +.B tzset +were called. +This is for compatibility with older platforms, as required by POSIX; +it is not needed for +.BR tzset 's +own use. +.SH "RETURN VALUE" +If the conversion is successful, +.B strftime +returns the number of bytes placed into the array, not counting the +terminating NUL; +.B errno +is unchanged if the returned value is zero. +Otherwise, +.B errno +is set to indicate the error, zero is returned, +and the array contents are unspecified. +.SH ERRORS +This function fails if: +.TP +[ERANGE] +The total number of resulting bytes, including the terminating +NUL character, is more than +.IR maxsize . +.PP +This function may fail if: +.TP +[EOVERFLOW] +The format includes an +.c %s +conversion and the number of seconds since the Epoch cannot be represented +in a +.c time_t . +.SH SEE ALSO +date(1), +getenv(3), +newctime(3), +newtzset(3), +time(2), +tzfile(5) +.SH BUGS +There is no conversion specification for the phase of the moon. diff --git a/vendor/chrono-tz/tz/newtzset.3 b/vendor/chrono-tz/tz/newtzset.3 new file mode 100644 index 0000000000000..b1384f32df0ba --- /dev/null +++ b/vendor/chrono-tz/tz/newtzset.3 @@ -0,0 +1,391 @@ +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. +.TH newtzset 3 "" "Time Zone Database" +.SH NAME +tzset \- initialize time conversion information +.SH SYNOPSIS +.nf +.ie \n(.g .ds - \f(CR-\fP +.el .ds - \- +.B #include +.PP +.BI "timezone_t tzalloc(char const *" TZ ); +.PP +.BI "void tzfree(timezone_t " tz ); +.PP +.B void tzset(void); +.PP +.B cc ... \*-ltz +.fi +.SH DESCRIPTION +.ie '\(en'' .ds en \- +.el .ds en \(en +.ie '\(lq'' .ds lq \&"\" +.el .ds lq \(lq\" +.ie '\(rq'' .ds rq \&"\" +.el .ds rq \(rq\" +.de q +\\$3\*(lq\\$1\*(rq\\$2 +.. +The +.B tzalloc +function +allocates and returns a timezone object described by +.IR TZ . +.PP +If +.I TZ +is a null pointer, +.B tzalloc +uses the best available approximation to local (wall +clock) time, as specified by the +.BR tzfile (5)-format +file +.B localtime +in the system time conversion information directory. +.PP +If +.I TZ +is the empty string, +.B tzalloc +uses Universal Time (UT), with the abbreviation "UTC" +and without leap second correction; please see +.BR newctime (3) +for more about UT, UTC, and leap seconds. +.PP +If +.I TZ +is nonnull and nonempty: +.IP +if the value begins with a colon, it is used as a pathname of a file +from which to read the time conversion information; +.IP +if the value does not begin with a colon, it is first used as the +pathname of a file from which to read the time conversion information, +and, if that file cannot be read, is used directly as a specification of +the time conversion information. +.PP +When +.I TZ +contents are used as a pathname, a pathname beginning with +.q "/" +is used as-is; otherwise +the pathname is relative to a system time conversion information +directory. +The file must be in the format specified in +.BR tzfile (5). +.PP +When +.I TZ +is used directly as a specification of the time conversion information, +it must have the following syntax: +.IP +\fIstd\|offset\fR[\fIdst\fR[\fIoffset\fR][\fB,\fIrule\fR]] +.PP +Where: +.RS +.TP +.IR std " and " dst +Three or more bytes that are the designation for the standard +.RI ( std ) +or the alternative +.RI ( dst , +such as daylight saving time) +time zone. Only +.I std +is required; if +.I dst +is missing, then daylight saving time does not apply in this locale. +Upper- and lowercase letters are explicitly allowed. Any characters +except a leading colon +.RB ( : ), +digits, comma +.RB ( , ), +ASCII minus +.RB ( \*- ), +ASCII plus +.RB ( + ), +and NUL bytes are allowed. +Alternatively, a designation can be surrounded by angle brackets +.B < +and +.BR > ; +in this case, the designation can contain any characters other than +.B > +and NUL. +.TP +.I offset +Indicates the value one must add to the local time to arrive at +Coordinated Universal Time. The +.I offset +has the form: +.RS +.IP +\fIhh\fR[\fB:\fImm\fR[\fB:\fIss\fR]] +.RE +.IP +The minutes +.RI ( mm ) +and seconds +.RI ( ss ) +are optional. The hour +.RI ( hh ) +is required and may be a single digit. The +.I offset +following +.I std +is required. If no +.I offset +follows +.IR dst , +daylight saving time is assumed to be one hour ahead of standard time. One or +more digits may be used; the value is always interpreted as a decimal +number. The hour must be between zero and 24, and the minutes (and +seconds) \*(en if present \*(en between zero and 59. If preceded by a +.q "\*-" , +the time zone shall be east of the Prime Meridian; otherwise it shall be +west (which may be indicated by an optional preceding +.q "+" . +.TP +.I rule +Indicates when to change to and back from daylight saving time. The +.I rule +has the form: +.RS +.IP +\fIdate\fB/\fItime\fB,\fIdate\fB/\fItime\fR +.RE +.IP +where the first +.I date +describes when the change from standard to daylight saving time occurs and the +second +.I date +describes when the change back happens. Each +.I time +field describes when, in current local time, the change to the other +time is made. +As an extension to POSIX.1-2017, daylight saving is assumed to be in effect +all year if it begins January 1 at 00:00 and ends December 31 at +24:00 plus the difference between daylight saving and standard time, +leaving no room for standard time in the calendar. +.IP +The format of +.I date +is one of the following: +.RS +.TP +.BI J n +The Julian day +.I n +.RI "(1\ \(<=" "\ n\ " "\(<=\ 365). +Leap days are not counted; that is, in all years \*(en including leap +years \*(en February 28 is day 59 and March 1 is day 60. It is +impossible to explicitly refer to the occasional February 29. +.TP +.I n +The zero-based Julian day +.RI "(0\ \(<=" "\ n\ " "\(<=\ 365). +Leap days are counted, and it is possible to refer to February 29. +.TP +.BI M m . n . d +The +.IR d' th +day +.RI "(0\ \(<=" "\ d\ " "\(<=\ 6) +of week +.I n +of month +.I m +of the year +.RI "(1\ \(<=" "\ n\ " "\(<=\ 5, +.RI "1\ \(<=" "\ m\ " "\(<=\ 12, +where week 5 means +.q "the last \fId\fP day in month \fIm\fP" +which may occur in either the fourth or the fifth week). Week 1 is the +first week in which the +.IR d' th +day occurs. Day zero is Sunday. +.RE +.IP +The +.I time +has the same format as +.I offset +except that POSIX.1-2017 does not allow a leading sign (\c +.q "\*-" +or +.q "+" ). +As an extension to POSIX.1-2017, the hours part of +.I time +can range from \-167 through 167; this allows for unusual rules such +as +.q "the Saturday before the first Sunday of March" . +The default, if +.I time +is not given, is +.BR 02:00:00 . +.RE +.LP +Here are some examples of +.I TZ +values that directly specify the timezone; they use some of the +extensions to POSIX.1-2017. +.TP +.B EST5 +stands for US Eastern Standard +Time (EST), 5 hours behind UT, without daylight saving. +.TP +.B <+12>\*-12<+13>,M11.1.0,M1.2.1/147 +stands for Fiji time, 12 hours ahead +of UT, springing forward on November's first Sunday at 02:00, and +falling back on January's second Monday at 147:00 (i.e., 03:00 on the +first Sunday on or after January 14). The abbreviations for standard +and daylight saving time are +.q "+12" +and +.q "+13". +.TP +.B IST\*-2IDT,M3.4.4/26,M10.5.0 +stands for Israel Standard Time (IST) and Israel Daylight Time (IDT), +2 hours ahead of UT, springing forward on March's fourth +Thursday at 26:00 (i.e., 02:00 on the first Friday on or after March +23), and falling back on October's last Sunday at 02:00. +.TP +.B <\*-04>4<\*-03>,J1/0,J365/25 +stands for permanent daylight saving time, 3 hours behind UT with +abbreviation +.q "\*-03". +There is a dummy fall-back transition on December 31 at 25:00 daylight +saving time (i.e., 24:00 standard time, equivalent to January 1 at +00:00 standard time), and a simultaneous spring-forward transition on +January 1 at 00:00 standard time, so daylight saving time is in effect +all year and the initial +.B <\*-04> +is a placeholder. +.TP +.B <\*-03>3<\*-02>,M3.5.0/\*-2,M10.5.0/\*-1 +stands for time in western Greenland, 3 hours behind UT, where clocks +follow the EU rules of +springing forward on March's last Sunday at 01:00 UT (\-02:00 local +time, i.e., 22:00 the previous day) and falling back on October's last +Sunday at 01:00 UT (\-01:00 local time, i.e., 23:00 the previous day). +The abbreviations for standard and daylight saving time are +.q "\*-03" +and +.q "\*-02". +.PP +If +.I TZ +specifies daylight saving time but does not specify a +.IR rule , +and the optional +.BR tzfile (5)-format +file +.B posixrules +is present in the system time conversion information directory, the +rules in +.B posixrules +are used, with the +.B posixrules +standard and daylight saving time offsets from UT +replaced by those specified by the +.I offset +values in +.IR TZ . +However, the +.B posixrules +file is obsolete: if it is present it is only for backward compatibility, +and it does not work reliably. +Therefore, if a +.I TZ +string directly specifies a timezone with daylight saving time, +it should specify the daylight saving rules explicitly. +.PP +For compatibility with System V Release 3.1, a semicolon +.RB ( ; ) +may be used to separate the +.I rule +from the rest of the specification; +this is an extension to POSIX. +.PP +The +.B tzfree +function +frees a timezone object +.IR tz , +which should have been successfully allocated by +.BR tzalloc . +This invalidates any +.B tm_zone +pointers that +.I tz +was used to set. +.PP +The +.B tzset +function +acts like +.BR tzalloc(getenv("TZ")) , +except it saves any resulting timezone object into internal +storage that is accessed by +.BR localtime , +.BR localtime_r , +and +.BR mktime . +The anonymous shared timezone object is freed by the next call to +.BR tzset . +If the implied call to +.B getenv +fails, +.B tzset +acts like +.BR tzalloc(nullptr) ; +if the implied call to +.B tzalloc +fails, +.B tzset +falls back on UT. +.SH "RETURN VALUE" +If successful, the +.B tzalloc +function returns a nonnull pointer to the newly allocated object. +Otherwise, it returns a null pointer and sets +.IR errno . +.SH ERRORS +.TP +.B EOVERFLOW +.I TZ +directly specifies time conversion information, +and contains an integer out of machine range +or a time zone abbreviation that is too long for this platform. +.PP +The +.B tzalloc +function may also fail and set +.I errno +for any of the errors specified for the routines +.BR access (2), +.BR close (2), +.BR malloc (3), +.BR open (2), +and +.BR read (2). +.SH FILES +.ta \w'/usr/share/zoneinfo/posixrules\0\0'u +/etc/localtime local timezone file +.br +/usr/share/zoneinfo timezone directory +.br +/usr/share/zoneinfo/posixrules default DST rules (obsolete) +.br +/usr/share/zoneinfo/GMT for UTC leap seconds +.PP +If /usr/share/zoneinfo/GMT is absent, +UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present. +.SH SEE ALSO +getenv(3), +newctime(3), +newstrftime(3), +time(2), +tzfile(5) diff --git a/vendor/chrono-tz/tz/private.h b/vendor/chrono-tz/tz/private.h new file mode 100644 index 0000000000000..0dac6af4e3cbf --- /dev/null +++ b/vendor/chrono-tz/tz/private.h @@ -0,0 +1,1034 @@ +/* Private header for tzdb code. */ + +#ifndef PRIVATE_H + +#define PRIVATE_H + +/* +** This file is in the public domain, so clarified as of +** 1996-06-05 by Arthur David Olson. +*/ + +/* +** This header is for use ONLY with the time conversion code. +** There is no guarantee that it will remain unchanged, +** or that it will remain at all. +** Do NOT copy it to any system include directory. +** Thank you! +*/ + +/* PORT_TO_C89 means the code should work even if the underlying + compiler and library support only C89 plus C99's 'long long' + and perhaps a few other extensions to C89. SUPPORT_C89 means the + tzcode library should support C89 callers in addition to the usual + support for C99-and-later callers; however, C89 support can trigger + latent bugs in C99-and-later callers. These macros are obsolescent, + and the plan is to remove them along with any code needed only when + they are nonzero. A good time to do that might be in the year 2029 + because RHEL 7 (whose GCC defaults to C89) extended life cycle + support (ELS) is scheduled to end on 2028-06-30. */ +#ifndef PORT_TO_C89 +# define PORT_TO_C89 0 +#endif +#ifndef SUPPORT_C89 +# define SUPPORT_C89 0 +#endif + +#ifndef __STDC_VERSION__ +# define __STDC_VERSION__ 0 +#endif + +/* Define true, false and bool if they don't work out of the box. */ +#if PORT_TO_C89 && __STDC_VERSION__ < 199901 +# define true 1 +# define false 0 +# define bool int +#elif __STDC_VERSION__ < 202311 +# include +#endif + +#if __STDC_VERSION__ < 202311 +# define static_assert(cond) extern int static_assert_check[(cond) ? 1 : -1] +#endif + +/* +** zdump has been made independent of the rest of the time +** conversion package to increase confidence in the verification it provides. +** You can use zdump to help in verifying other implementations. +** To do this, compile with -DUSE_LTZ=0 and link without the tz library. +*/ +#ifndef USE_LTZ +# define USE_LTZ 1 +#endif + +/* This string was in the Factory zone through version 2016f. */ +#define GRANDPARENTED "Local time zone must be set--see zic manual page" + +/* +** Defaults for preprocessor symbols. +** You can override these in your C compiler options, e.g. '-DHAVE_GETTEXT=1'. +*/ + +#ifndef HAVE_DECL_ASCTIME_R +# define HAVE_DECL_ASCTIME_R 1 +#endif + +#if !defined HAVE__GENERIC && defined __has_extension +# if !__has_extension(c_generic_selections) +# define HAVE__GENERIC 0 +# endif +#endif +/* _Generic is buggy in pre-4.9 GCC. */ +#if !defined HAVE__GENERIC && defined __GNUC__ && !defined __STRICT_ANSI__ +# define HAVE__GENERIC (4 < __GNUC__ + (9 <= __GNUC_MINOR__)) +#endif +#ifndef HAVE__GENERIC +# define HAVE__GENERIC (201112 <= __STDC_VERSION__) +#endif + +#if !defined HAVE_GETTEXT && defined __has_include +# if __has_include() +# define HAVE_GETTEXT true +# endif +#endif +#ifndef HAVE_GETTEXT +# define HAVE_GETTEXT false +#endif + +#ifndef HAVE_INCOMPATIBLE_CTIME_R +# define HAVE_INCOMPATIBLE_CTIME_R 0 +#endif + +#ifndef HAVE_LINK +# define HAVE_LINK 1 +#endif /* !defined HAVE_LINK */ + +#ifndef HAVE_MALLOC_ERRNO +# define HAVE_MALLOC_ERRNO 1 +#endif + +#ifndef HAVE_POSIX_DECLS +# define HAVE_POSIX_DECLS 1 +#endif + +#ifndef HAVE_SETENV +# define HAVE_SETENV 1 +#endif + +#ifndef HAVE_STRDUP +# define HAVE_STRDUP 1 +#endif + +#ifndef HAVE_SYMLINK +# define HAVE_SYMLINK 1 +#endif /* !defined HAVE_SYMLINK */ + +#if !defined HAVE_SYS_STAT_H && defined __has_include +# if !__has_include() +# define HAVE_SYS_STAT_H false +# endif +#endif +#ifndef HAVE_SYS_STAT_H +# define HAVE_SYS_STAT_H true +#endif + +#if !defined HAVE_UNISTD_H && defined __has_include +# if !__has_include() +# define HAVE_UNISTD_H false +# endif +#endif +#ifndef HAVE_UNISTD_H +# define HAVE_UNISTD_H true +#endif + +#ifndef NETBSD_INSPIRED +# define NETBSD_INSPIRED 1 +#endif + +#if HAVE_INCOMPATIBLE_CTIME_R +# define asctime_r _incompatible_asctime_r +# define ctime_r _incompatible_ctime_r +#endif /* HAVE_INCOMPATIBLE_CTIME_R */ + +/* Enable tm_gmtoff, tm_zone, and environ on GNUish systems. */ +#define _GNU_SOURCE 1 +/* Fix asctime_r on Solaris 11. */ +#define _POSIX_PTHREAD_SEMANTICS 1 +/* Enable strtoimax on pre-C99 Solaris 11. */ +#define __EXTENSIONS__ 1 + +/* On GNUish systems where time_t might be 32 or 64 bits, use 64. + On these platforms _FILE_OFFSET_BITS must also be 64; otherwise + setting _TIME_BITS to 64 does not work. The code does not + otherwise rely on _FILE_OFFSET_BITS being 64, since it does not + use off_t or functions like 'stat' that depend on off_t. */ +#ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +#endif +#if !defined _TIME_BITS && _FILE_OFFSET_BITS == 64 +# define _TIME_BITS 64 +#endif + +/* +** Nested includes +*/ + +/* Avoid clashes with NetBSD by renaming NetBSD's declarations. + If defining the 'timezone' variable, avoid a clash with FreeBSD's + 'timezone' function by renaming its declaration. */ +#define localtime_rz sys_localtime_rz +#define mktime_z sys_mktime_z +#define posix2time_z sys_posix2time_z +#define time2posix_z sys_time2posix_z +#if defined USG_COMPAT && USG_COMPAT == 2 +# define timezone sys_timezone +#endif +#define timezone_t sys_timezone_t +#define tzalloc sys_tzalloc +#define tzfree sys_tzfree +#include +#undef localtime_rz +#undef mktime_z +#undef posix2time_z +#undef time2posix_z +#if defined USG_COMPAT && USG_COMPAT == 2 +# undef timezone +#endif +#undef timezone_t +#undef tzalloc +#undef tzfree + +#include +#include +#if !PORT_TO_C89 +# include +#endif +#include /* for CHAR_BIT et al. */ +#include + +#include + +#ifndef EINVAL +# define EINVAL ERANGE +#endif + +#ifndef ELOOP +# define ELOOP EINVAL +#endif +#ifndef ENAMETOOLONG +# define ENAMETOOLONG EINVAL +#endif +#ifndef ENOMEM +# define ENOMEM EINVAL +#endif +#ifndef ENOTSUP +# define ENOTSUP EINVAL +#endif +#ifndef EOVERFLOW +# define EOVERFLOW EINVAL +#endif + +#if HAVE_GETTEXT +# include +#endif /* HAVE_GETTEXT */ + +#if HAVE_UNISTD_H +# include /* for R_OK, and other POSIX goodness */ +#endif /* HAVE_UNISTD_H */ + +#ifndef HAVE_STRFTIME_L +# if _POSIX_VERSION < 200809 +# define HAVE_STRFTIME_L 0 +# else +# define HAVE_STRFTIME_L 1 +# endif +#endif + +#ifndef USG_COMPAT +# ifndef _XOPEN_VERSION +# define USG_COMPAT 0 +# else +# define USG_COMPAT 1 +# endif +#endif + +#ifndef HAVE_TZNAME +# if _POSIX_VERSION < 198808 && !USG_COMPAT +# define HAVE_TZNAME 0 +# else +# define HAVE_TZNAME 1 +# endif +#endif + +#ifndef ALTZONE +# if defined __sun || defined _M_XENIX +# define ALTZONE 1 +# else +# define ALTZONE 0 +# endif +#endif + +#ifndef R_OK +# define R_OK 4 +#endif /* !defined R_OK */ + +#if PORT_TO_C89 + +/* +** Define HAVE_STDINT_H's default value here, rather than at the +** start, since __GLIBC__ and INTMAX_MAX's values depend on +** previously included files. glibc 2.1 and Solaris 10 and later have +** stdint.h, even with pre-C99 compilers. +*/ +#if !defined HAVE_STDINT_H && defined __has_include +# define HAVE_STDINT_H true /* C23 __has_include implies C99 stdint.h. */ +#endif +#ifndef HAVE_STDINT_H +# define HAVE_STDINT_H \ + (199901 <= __STDC_VERSION__ \ + || 2 < __GLIBC__ + (1 <= __GLIBC_MINOR__) \ + || __CYGWIN__ || INTMAX_MAX) +#endif /* !defined HAVE_STDINT_H */ + +#if HAVE_STDINT_H +# include +#endif /* !HAVE_STDINT_H */ + +#ifndef HAVE_INTTYPES_H +# define HAVE_INTTYPES_H HAVE_STDINT_H +#endif +#if HAVE_INTTYPES_H +# include +#endif + +/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */ +#if defined __LONG_LONG_MAX__ && !defined __STRICT_ANSI__ +# ifndef LLONG_MAX +# define LLONG_MAX __LONG_LONG_MAX__ +# endif +# ifndef LLONG_MIN +# define LLONG_MIN (-1 - LLONG_MAX) +# endif +# ifndef ULLONG_MAX +# define ULLONG_MAX (LLONG_MAX * 2ull + 1) +# endif +#endif + +#ifndef INT_FAST64_MAX +# if 1 <= LONG_MAX >> 31 >> 31 +typedef long int_fast64_t; +# define INT_FAST64_MIN LONG_MIN +# define INT_FAST64_MAX LONG_MAX +# else +/* If this fails, compile with -DHAVE_STDINT_H or with a better compiler. */ +typedef long long int_fast64_t; +# define INT_FAST64_MIN LLONG_MIN +# define INT_FAST64_MAX LLONG_MAX +# endif +#endif + +#ifndef PRIdFAST64 +# if INT_FAST64_MAX == LONG_MAX +# define PRIdFAST64 "ld" +# else +# define PRIdFAST64 "lld" +# endif +#endif + +#ifndef SCNdFAST64 +# define SCNdFAST64 PRIdFAST64 +#endif + +#ifndef INT_FAST32_MAX +# if INT_MAX >> 31 == 0 +typedef long int_fast32_t; +# define INT_FAST32_MAX LONG_MAX +# define INT_FAST32_MIN LONG_MIN +# else +typedef int int_fast32_t; +# define INT_FAST32_MAX INT_MAX +# define INT_FAST32_MIN INT_MIN +# endif +#endif + +#ifndef INTMAX_MAX +# ifdef LLONG_MAX +typedef long long intmax_t; +# ifndef HAVE_STRTOLL +# define HAVE_STRTOLL true +# endif +# if HAVE_STRTOLL +# define strtoimax strtoll +# endif +# define INTMAX_MAX LLONG_MAX +# define INTMAX_MIN LLONG_MIN +# else +typedef long intmax_t; +# define INTMAX_MAX LONG_MAX +# define INTMAX_MIN LONG_MIN +# endif +# ifndef strtoimax +# define strtoimax strtol +# endif +#endif + +#ifndef PRIdMAX +# if INTMAX_MAX == LLONG_MAX +# define PRIdMAX "lld" +# else +# define PRIdMAX "ld" +# endif +#endif + +#ifndef PTRDIFF_MAX +# define PTRDIFF_MAX MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t)) +#endif + +#ifndef UINT_FAST32_MAX +typedef unsigned long uint_fast32_t; +#endif + +#ifndef UINT_FAST64_MAX +# if 3 <= ULONG_MAX >> 31 >> 31 +typedef unsigned long uint_fast64_t; +# define UINT_FAST64_MAX ULONG_MAX +# else +/* If this fails, compile with -DHAVE_STDINT_H or with a better compiler. */ +typedef unsigned long long uint_fast64_t; +# define UINT_FAST64_MAX ULLONG_MAX +# endif +#endif + +#ifndef UINTMAX_MAX +# ifdef ULLONG_MAX +typedef unsigned long long uintmax_t; +# define UINTMAX_MAX ULLONG_MAX +# else +typedef unsigned long uintmax_t; +# define UINTMAX_MAX ULONG_MAX +# endif +#endif + +#ifndef PRIuMAX +# ifdef ULLONG_MAX +# define PRIuMAX "llu" +# else +# define PRIuMAX "lu" +# endif +#endif + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +#endif /* PORT_TO_C89 */ + +/* The maximum size of any created object, as a signed integer. + Although the C standard does not outright prohibit larger objects, + behavior is undefined if the result of pointer subtraction does not + fit into ptrdiff_t, and the code assumes in several places that + pointer subtraction works. As a practical matter it's OK to not + support objects larger than this. */ +#define INDEX_MAX ((ptrdiff_t) min(PTRDIFF_MAX, SIZE_MAX)) + +/* Support ckd_add, ckd_sub, ckd_mul on C23 or recent-enough GCC-like + hosts, unless compiled with -DHAVE_STDCKDINT_H=0 or with pre-C23 EDG. */ +#if !defined HAVE_STDCKDINT_H && defined __has_include +# if __has_include() +# define HAVE_STDCKDINT_H true +# endif +#endif +#ifdef HAVE_STDCKDINT_H +# if HAVE_STDCKDINT_H +# include +# endif +#elif defined __EDG__ +/* Do nothing, to work around EDG bug . */ +#elif defined __has_builtin +# if __has_builtin(__builtin_add_overflow) +# define ckd_add(r, a, b) __builtin_add_overflow(a, b, r) +# endif +# if __has_builtin(__builtin_sub_overflow) +# define ckd_sub(r, a, b) __builtin_sub_overflow(a, b, r) +# endif +# if __has_builtin(__builtin_mul_overflow) +# define ckd_mul(r, a, b) __builtin_mul_overflow(a, b, r) +# endif +#elif 7 <= __GNUC__ +# define ckd_add(r, a, b) __builtin_add_overflow(a, b, r) +# define ckd_sub(r, a, b) __builtin_sub_overflow(a, b, r) +# define ckd_mul(r, a, b) __builtin_mul_overflow(a, b, r) +#endif + +#if 3 <= __GNUC__ +# define ATTRIBUTE_MALLOC __attribute__((malloc)) +# define ATTRIBUTE_FORMAT(spec) __attribute__((format spec)) +#else +# define ATTRIBUTE_MALLOC /* empty */ +# define ATTRIBUTE_FORMAT(spec) /* empty */ +#endif + +#if (defined __has_c_attribute \ + && (202311 <= __STDC_VERSION__ || !defined __STRICT_ANSI__)) +# define HAVE___HAS_C_ATTRIBUTE true +#else +# define HAVE___HAS_C_ATTRIBUTE false +#endif + +#if HAVE___HAS_C_ATTRIBUTE +# if __has_c_attribute(deprecated) +# define ATTRIBUTE_DEPRECATED [[deprecated]] +# endif +#endif +#ifndef ATTRIBUTE_DEPRECATED +# if 3 < __GNUC__ + (2 <= __GNUC_MINOR__) +# define ATTRIBUTE_DEPRECATED __attribute__((deprecated)) +# else +# define ATTRIBUTE_DEPRECATED /* empty */ +# endif +#endif + +#if HAVE___HAS_C_ATTRIBUTE +# if __has_c_attribute(fallthrough) +# define ATTRIBUTE_FALLTHROUGH [[fallthrough]] +# endif +#endif +#ifndef ATTRIBUTE_FALLTHROUGH +# if 7 <= __GNUC__ +# define ATTRIBUTE_FALLTHROUGH __attribute__((fallthrough)) +# else +# define ATTRIBUTE_FALLTHROUGH ((void) 0) +# endif +#endif + +#if HAVE___HAS_C_ATTRIBUTE +# if __has_c_attribute(maybe_unused) +# define ATTRIBUTE_MAYBE_UNUSED [[maybe_unused]] +# endif +#endif +#ifndef ATTRIBUTE_MAYBE_UNUSED +# if 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define ATTRIBUTE_MAYBE_UNUSED __attribute__((unused)) +# else +# define ATTRIBUTE_MAYBE_UNUSED /* empty */ +# endif +#endif + +#if HAVE___HAS_C_ATTRIBUTE +# if __has_c_attribute(noreturn) +# define ATTRIBUTE_NORETURN [[noreturn]] +# endif +#endif +#ifndef ATTRIBUTE_NORETURN +# if 201112 <= __STDC_VERSION__ +# define ATTRIBUTE_NORETURN _Noreturn +# elif 2 < __GNUC__ + (8 <= __GNUC_MINOR__) +# define ATTRIBUTE_NORETURN __attribute__((noreturn)) +# else +# define ATTRIBUTE_NORETURN /* empty */ +# endif +#endif + +#if HAVE___HAS_C_ATTRIBUTE +# if __has_c_attribute(reproducible) +# define ATTRIBUTE_REPRODUCIBLE [[reproducible]] +# endif +#endif +#ifndef ATTRIBUTE_REPRODUCIBLE +# if 3 <= __GNUC__ +# define ATTRIBUTE_REPRODUCIBLE __attribute__((pure)) +# else +# define ATTRIBUTE_REPRODUCIBLE /* empty */ +# endif +#endif + +#if HAVE___HAS_C_ATTRIBUTE +# if __has_c_attribute(unsequenced) +# define ATTRIBUTE_UNSEQUENCED [[unsequenced]] +# endif +#endif +#ifndef ATTRIBUTE_UNSEQUENCED +# if 3 <= __GNUC__ +# define ATTRIBUTE_UNSEQUENCED __attribute__((const)) +# else +# define ATTRIBUTE_UNSEQUENCED /* empty */ +# endif +#endif + +#if (__STDC_VERSION__ < 199901 && !defined restrict \ + && (PORT_TO_C89 || defined _MSC_VER)) +# define restrict /* empty */ +#endif + +/* +** Workarounds for compilers/systems. +*/ + +#ifndef EPOCH_LOCAL +# define EPOCH_LOCAL 0 +#endif +#ifndef EPOCH_OFFSET +# define EPOCH_OFFSET 0 +#endif +#ifndef RESERVE_STD_EXT_IDS +# define RESERVE_STD_EXT_IDS 0 +#endif + +/* If standard C identifiers with external linkage (e.g., localtime) + are reserved and are not already being renamed anyway, rename them + as if compiling with '-Dtime_tz=time_t'. */ +#if !defined time_tz && RESERVE_STD_EXT_IDS && USE_LTZ +# define time_tz time_t +#endif + +/* +** Compile with -Dtime_tz=T to build the tz package with a private +** time_t type equivalent to T rather than the system-supplied time_t. +** This debugging feature can test unusual design decisions +** (e.g., time_t wider than 'long', or unsigned time_t) even on +** typical platforms. +*/ +#if defined time_tz || EPOCH_LOCAL || EPOCH_OFFSET != 0 +# define TZ_TIME_T 1 +#else +# define TZ_TIME_T 0 +#endif + +#if defined LOCALTIME_IMPLEMENTATION && TZ_TIME_T +static time_t sys_time(time_t *x) { return time(x); } +#endif + +#if TZ_TIME_T + +typedef time_tz tz_time_t; + +# undef asctime +# define asctime tz_asctime +# undef asctime_r +# define asctime_r tz_asctime_r +# undef ctime +# define ctime tz_ctime +# undef ctime_r +# define ctime_r tz_ctime_r +# undef difftime +# define difftime tz_difftime +# undef gmtime +# define gmtime tz_gmtime +# undef gmtime_r +# define gmtime_r tz_gmtime_r +# undef localtime +# define localtime tz_localtime +# undef localtime_r +# define localtime_r tz_localtime_r +# undef localtime_rz +# define localtime_rz tz_localtime_rz +# undef mktime +# define mktime tz_mktime +# undef mktime_z +# define mktime_z tz_mktime_z +# undef offtime +# define offtime tz_offtime +# undef posix2time +# define posix2time tz_posix2time +# undef posix2time_z +# define posix2time_z tz_posix2time_z +# undef strftime +# define strftime tz_strftime +# undef time +# define time tz_time +# undef time2posix +# define time2posix tz_time2posix +# undef time2posix_z +# define time2posix_z tz_time2posix_z +# undef time_t +# define time_t tz_time_t +# undef timegm +# define timegm tz_timegm +# undef timelocal +# define timelocal tz_timelocal +# undef timeoff +# define timeoff tz_timeoff +# undef tzalloc +# define tzalloc tz_tzalloc +# undef tzfree +# define tzfree tz_tzfree +# undef tzset +# define tzset tz_tzset +# if HAVE_STRFTIME_L +# undef strftime_l +# define strftime_l tz_strftime_l +# endif +# if HAVE_TZNAME +# undef tzname +# define tzname tz_tzname +# endif +# if USG_COMPAT +# undef daylight +# define daylight tz_daylight +# undef timezone +# define timezone tz_timezone +# endif +# if ALTZONE +# undef altzone +# define altzone tz_altzone +# endif + +# if __STDC_VERSION__ < 202311 +# define DEPRECATED_IN_C23 /* empty */ +# else +# define DEPRECATED_IN_C23 ATTRIBUTE_DEPRECATED +# endif +DEPRECATED_IN_C23 char *asctime(struct tm const *); +char *asctime_r(struct tm const *restrict, char *restrict); +DEPRECATED_IN_C23 char *ctime(time_t const *); +char *ctime_r(time_t const *, char *); +ATTRIBUTE_UNSEQUENCED double difftime(time_t, time_t); +size_t strftime(char *restrict, size_t, char const *restrict, + struct tm const *restrict); +# if HAVE_STRFTIME_L +size_t strftime_l(char *restrict, size_t, char const *restrict, + struct tm const *restrict, locale_t); +# endif +struct tm *gmtime(time_t const *); +struct tm *gmtime_r(time_t const *restrict, struct tm *restrict); +struct tm *localtime(time_t const *); +struct tm *localtime_r(time_t const *restrict, struct tm *restrict); +time_t mktime(struct tm *); +time_t time(time_t *); +time_t timegm(struct tm *); +void tzset(void); +#endif + +#ifndef HAVE_DECL_TIMEGM +# if (202311 <= __STDC_VERSION__ \ + || defined __GLIBC__ || defined __tm_zone /* musl */ \ + || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \ + || (defined __APPLE__ && defined __MACH__)) +# define HAVE_DECL_TIMEGM true +# else +# define HAVE_DECL_TIMEGM false +# endif +#endif +#if !HAVE_DECL_TIMEGM && !defined timegm +time_t timegm(struct tm *); +#endif + +#if !HAVE_DECL_ASCTIME_R && !defined asctime_r +extern char *asctime_r(struct tm const *restrict, char *restrict); +#endif + +#ifndef HAVE_DECL_ENVIRON +# if defined environ || defined __USE_GNU +# define HAVE_DECL_ENVIRON 1 +# else +# define HAVE_DECL_ENVIRON 0 +# endif +#endif + +#if !HAVE_DECL_ENVIRON +extern char **environ; +#endif + +#if 2 <= HAVE_TZNAME + (TZ_TIME_T || !HAVE_POSIX_DECLS) +extern char *tzname[]; +#endif +#if 2 <= USG_COMPAT + (TZ_TIME_T || !HAVE_POSIX_DECLS) +extern long timezone; +extern int daylight; +#endif +#if 2 <= ALTZONE + (TZ_TIME_T || !HAVE_POSIX_DECLS) +extern long altzone; +#endif + +/* +** The STD_INSPIRED functions are similar, but most also need +** declarations if time_tz is defined. +*/ + +#ifndef STD_INSPIRED +# define STD_INSPIRED 0 +#endif +#if STD_INSPIRED +# if TZ_TIME_T || !defined offtime +struct tm *offtime(time_t const *, long); +# endif +# if TZ_TIME_T || !defined timelocal +time_t timelocal(struct tm *); +# endif +# if TZ_TIME_T || !defined timeoff +# define EXTERN_TIMEOFF +# endif +# if TZ_TIME_T || !defined time2posix +time_t time2posix(time_t); +# endif +# if TZ_TIME_T || !defined posix2time +time_t posix2time(time_t); +# endif +#endif + +/* Infer TM_ZONE on systems where this information is known, but suppress + guessing if NO_TM_ZONE is defined. Similarly for TM_GMTOFF. */ +#if (200809 < _POSIX_VERSION \ + || defined __GLIBC__ \ + || defined __tm_zone /* musl */ \ + || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \ + || (defined __APPLE__ && defined __MACH__)) +# if !defined TM_GMTOFF && !defined NO_TM_GMTOFF +# define TM_GMTOFF tm_gmtoff +# endif +# if !defined TM_ZONE && !defined NO_TM_ZONE +# define TM_ZONE tm_zone +# endif +#endif + +/* +** Define functions that are ABI compatible with NetBSD but have +** better prototypes. NetBSD 6.1.4 defines a pointer type timezone_t +** and labors under the misconception that 'const timezone_t' is a +** pointer to a constant. This use of 'const' is ineffective, so it +** is not done here. What we call 'struct state' NetBSD calls +** 'struct __state', but this is a private name so it doesn't matter. +*/ +#if NETBSD_INSPIRED +typedef struct state *timezone_t; +struct tm *localtime_rz(timezone_t restrict, time_t const *restrict, + struct tm *restrict); +time_t mktime_z(timezone_t restrict, struct tm *restrict); +timezone_t tzalloc(char const *); +void tzfree(timezone_t); +# if STD_INSPIRED +# if TZ_TIME_T || !defined posix2time_z +ATTRIBUTE_REPRODUCIBLE time_t posix2time_z(timezone_t, time_t); +# endif +# if TZ_TIME_T || !defined time2posix_z +ATTRIBUTE_REPRODUCIBLE time_t time2posix_z(timezone_t, time_t); +# endif +# endif +#endif + +/* +** Finally, some convenience items. +*/ + +#define TYPE_BIT(type) (CHAR_BIT * (ptrdiff_t) sizeof(type)) +#define TYPE_SIGNED(type) (((type) -1) < 0) +#define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0) + +/* Minimum and maximum of two values. Use lower case to avoid + naming clashes with standard include files. */ +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) + +/* Max and min values of the integer type T, of which only the bottom + B bits are used, and where the highest-order used bit is considered + to be a sign bit if T is signed. */ +#define MAXVAL(t, b) \ + ((t) (((t) 1 << ((b) - 1 - TYPE_SIGNED(t))) \ + - 1 + ((t) 1 << ((b) - 1 - TYPE_SIGNED(t))))) +#define MINVAL(t, b) \ + ((t) (TYPE_SIGNED(t) ? - TWOS_COMPLEMENT(t) - MAXVAL(t, b) : 0)) + +/* The extreme time values, assuming no padding. */ +#define TIME_T_MIN_NO_PADDING MINVAL(time_t, TYPE_BIT(time_t)) +#define TIME_T_MAX_NO_PADDING MAXVAL(time_t, TYPE_BIT(time_t)) + +/* The extreme time values. These are macros, not constants, so that + any portability problems occur only when compiling .c files that use + the macros, which is safer for applications that need only zdump and zic. + This implementation assumes no padding if time_t is signed and + either the compiler lacks support for _Generic or time_t is not one + of the standard signed integer types. */ +#if HAVE__GENERIC +# define TIME_T_MIN \ + _Generic((time_t) 0, \ + signed char: SCHAR_MIN, short: SHRT_MIN, \ + int: INT_MIN, long: LONG_MIN, long long: LLONG_MIN, \ + default: TIME_T_MIN_NO_PADDING) +# define TIME_T_MAX \ + (TYPE_SIGNED(time_t) \ + ? _Generic((time_t) 0, \ + signed char: SCHAR_MAX, short: SHRT_MAX, \ + int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX, \ + default: TIME_T_MAX_NO_PADDING) \ + : (time_t) -1) +enum { SIGNED_PADDING_CHECK_NEEDED + = _Generic((time_t) 0, + signed char: false, short: false, + int: false, long: false, long long: false, + default: true) }; +#else +# define TIME_T_MIN TIME_T_MIN_NO_PADDING +# define TIME_T_MAX TIME_T_MAX_NO_PADDING +enum { SIGNED_PADDING_CHECK_NEEDED = true }; +#endif +/* Try to check the padding assumptions. Although TIME_T_MAX and the + following check can both have undefined behavior on oddball + platforms due to shifts exceeding widths of signed integers, these + platforms' compilers are likely to diagnose these issues in integer + constant expressions, so it shouldn't hurt to check statically. */ +static_assert(! TYPE_SIGNED(time_t) || ! SIGNED_PADDING_CHECK_NEEDED + || TIME_T_MAX >> (TYPE_BIT(time_t) - 2) == 1); + +/* +** 302 / 1000 is log10(2.0) rounded up. +** Subtract one for the sign bit if the type is signed; +** add one for integer division truncation; +** add one more for a minus sign if the type is signed. +*/ +#define INT_STRLEN_MAXIMUM(type) \ + ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \ + 1 + TYPE_SIGNED(type)) + +/* +** INITIALIZE(x) +*/ + +#ifdef GCC_LINT +# define INITIALIZE(x) ((x) = 0) +#else +# define INITIALIZE(x) +#endif + +/* Whether memory access must strictly follow the C standard. + If 0, it's OK to read uninitialized storage so long as the value is + not relied upon. Defining it to 0 lets mktime access parts of + struct tm that might be uninitialized, as a heuristic when the + standard doesn't say what to return and when tm_gmtoff can help + mktime likely infer a better value. */ +#ifndef UNINIT_TRAP +# define UNINIT_TRAP 0 +#endif + +/* localtime.c sometimes needs access to timeoff if it is not already public. + tz_private_timeoff should be used only by localtime.c. */ +#if (!defined EXTERN_TIMEOFF \ + && defined TM_GMTOFF && (200809 < _POSIX_VERSION || ! UNINIT_TRAP)) +# ifndef timeoff +# define timeoff tz_private_timeoff +# endif +# define EXTERN_TIMEOFF +#endif +#ifdef EXTERN_TIMEOFF +time_t timeoff(struct tm *, long); +#endif + +#ifdef DEBUG +# undef unreachable +# define unreachable() abort() +#elif !defined unreachable +# ifdef __has_builtin +# if __has_builtin(__builtin_unreachable) +# define unreachable() __builtin_unreachable() +# endif +# elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__) +# define unreachable() __builtin_unreachable() +# endif +# ifndef unreachable +# define unreachable() ((void) 0) +# endif +#endif + +/* +** For the benefit of GNU folk... +** '_(MSGID)' uses the current locale's message library string for MSGID. +** The default is to use gettext if available, and use MSGID otherwise. +*/ + +#if HAVE_GETTEXT +#define _(msgid) gettext(msgid) +#else /* !HAVE_GETTEXT */ +#define _(msgid) msgid +#endif /* !HAVE_GETTEXT */ + +#if !defined TZ_DOMAIN && defined HAVE_GETTEXT +# define TZ_DOMAIN "tz" +#endif + +#if HAVE_INCOMPATIBLE_CTIME_R +#undef asctime_r +#undef ctime_r +char *asctime_r(struct tm const *restrict, char *restrict); +char *ctime_r(time_t const *, char *); +#endif /* HAVE_INCOMPATIBLE_CTIME_R */ + +/* Handy macros that are independent of tzfile implementation. */ + +enum { + SECSPERMIN = 60, + MINSPERHOUR = 60, + SECSPERHOUR = SECSPERMIN * MINSPERHOUR, + HOURSPERDAY = 24, + DAYSPERWEEK = 7, + DAYSPERNYEAR = 365, + DAYSPERLYEAR = DAYSPERNYEAR + 1, + MONSPERYEAR = 12, + YEARSPERREPEAT = 400 /* years before a Gregorian repeat */ +}; + +#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY) + +#define DAYSPERREPEAT ((int_fast32_t) 400 * 365 + 100 - 4 + 1) +#define SECSPERREPEAT ((int_fast64_t) DAYSPERREPEAT * SECSPERDAY) +#define AVGSECSPERYEAR (SECSPERREPEAT / YEARSPERREPEAT) + +/* How many years to generate (in zic.c) or search through (in localtime.c). + This is two years larger than the obvious 400, to avoid edge cases. + E.g., suppose a non-POSIX.1-2017 rule applies from 2012 on with transitions + in March and September, plus one-off transitions in November 2013. + If zic looked only at the last 400 years, it would set max_year=2413, + with the intent that the 400 years 2014 through 2413 will be repeated. + The last transition listed in the tzfile would be in 2413-09, + less than 400 years after the last one-off transition in 2013-11. + Two years is not overkill for localtime.c, as a one-year bump + would mishandle 2023d's America/Ciudad_Juarez for November 2422. */ +enum { years_of_observations = YEARSPERREPEAT + 2 }; + +enum { + TM_SUNDAY, + TM_MONDAY, + TM_TUESDAY, + TM_WEDNESDAY, + TM_THURSDAY, + TM_FRIDAY, + TM_SATURDAY +}; + +enum { + TM_JANUARY, + TM_FEBRUARY, + TM_MARCH, + TM_APRIL, + TM_MAY, + TM_JUNE, + TM_JULY, + TM_AUGUST, + TM_SEPTEMBER, + TM_OCTOBER, + TM_NOVEMBER, + TM_DECEMBER +}; + +enum { + TM_YEAR_BASE = 1900, + TM_WDAY_BASE = TM_MONDAY, + EPOCH_YEAR = 1970, + EPOCH_WDAY = TM_THURSDAY +}; + +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + +/* +** Since everything in isleap is modulo 400 (or a factor of 400), we know that +** isleap(y) == isleap(y % 400) +** and so +** isleap(a + b) == isleap((a + b) % 400) +** or +** isleap(a + b) == isleap(a % 400 + b % 400) +** This is true even if % means modulo rather than Fortran remainder +** (which is allowed by C89 but not by C99 or later). +** We use this to avoid addition overflow problems. +*/ + +#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) + +#endif /* !defined PRIVATE_H */ diff --git a/vendor/chrono-tz/tz/strftime.c b/vendor/chrono-tz/tz/strftime.c new file mode 100644 index 0000000000000..755d341fa6d97 --- /dev/null +++ b/vendor/chrono-tz/tz/strftime.c @@ -0,0 +1,660 @@ +/* Convert a broken-down timestamp to a string. */ + +/* Copyright 1989 The Regents of the University of California. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. */ + +/* +** Based on the UCB version with the copyright notice appearing above. +** +** This is ANSIish only when "multibyte character == plain character". +*/ + +#include "private.h" + +#include +#include +#include + +#ifndef DEPRECATE_TWO_DIGIT_YEARS +# define DEPRECATE_TWO_DIGIT_YEARS false +#endif + +struct lc_time_T { + const char * mon[MONSPERYEAR]; + const char * month[MONSPERYEAR]; + const char * wday[DAYSPERWEEK]; + const char * weekday[DAYSPERWEEK]; + const char * X_fmt; + const char * x_fmt; + const char * c_fmt; + const char * am; + const char * pm; + const char * date_fmt; +}; + +static const struct lc_time_T C_time_locale = { + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }, { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + }, { + "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat" + }, { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" + }, + + /* X_fmt */ + "%H:%M:%S", + + /* + ** x_fmt + ** C99 and later require this format. + ** Using just numbers (as here) makes Quakers happier; + ** it's also compatible with SVR4. + */ + "%m/%d/%y", + + /* + ** c_fmt + ** C99 and later require this format. + ** Previously this code used "%D %X", but we now conform to C99. + ** Note that + ** "%a %b %d %H:%M:%S %Y" + ** is used by Solaris 2.3. + */ + "%a %b %e %T %Y", + + /* am */ + "AM", + + /* pm */ + "PM", + + /* date_fmt */ + "%a %b %e %H:%M:%S %Z %Y" +}; + +enum warn { IN_NONE, IN_SOME, IN_THIS, IN_ALL }; + +static char * _add(const char *, char *, const char *); +static char * _conv(int, const char *, char *, const char *); +static char * _fmt(const char *, const struct tm *, char *, const char *, + enum warn *); +static char * _yconv(int, int, bool, bool, char *, char const *); + +#ifndef YEAR_2000_NAME +# define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS" +#endif /* !defined YEAR_2000_NAME */ + +#if HAVE_STRFTIME_L +size_t +strftime_l(char *restrict s, size_t maxsize, char const *restrict format, + struct tm const *restrict t, + ATTRIBUTE_MAYBE_UNUSED locale_t locale) +{ + /* Just call strftime, as only the C locale is supported. */ + return strftime(s, maxsize, format, t); +} +#endif + +size_t +strftime(char *restrict s, size_t maxsize, char const *restrict format, + struct tm const *restrict t) +{ + char * p; + int saved_errno = errno; + enum warn warn = IN_NONE; + + tzset(); + p = _fmt(format, t, s, s + maxsize, &warn); + if (!p) { + errno = EOVERFLOW; + return 0; + } + if (DEPRECATE_TWO_DIGIT_YEARS + && warn != IN_NONE && getenv(YEAR_2000_NAME)) { + fprintf(stderr, "\n"); + fprintf(stderr, "strftime format \"%s\" ", format); + fprintf(stderr, "yields only two digits of years in "); + if (warn == IN_SOME) + fprintf(stderr, "some locales"); + else if (warn == IN_THIS) + fprintf(stderr, "the current locale"); + else fprintf(stderr, "all locales"); + fprintf(stderr, "\n"); + } + if (p == s + maxsize) { + errno = ERANGE; + return 0; + } + *p = '\0'; + errno = saved_errno; + return p - s; +} + +static char * +_fmt(const char *format, const struct tm *t, char *pt, + const char *ptlim, enum warn *warnp) +{ + struct lc_time_T const *Locale = &C_time_locale; + + for ( ; *format; ++format) { + if (*format == '%') { +label: + switch (*++format) { + case '\0': + --format; + break; + case 'A': + pt = _add((t->tm_wday < 0 || + t->tm_wday >= DAYSPERWEEK) ? + "?" : Locale->weekday[t->tm_wday], + pt, ptlim); + continue; + case 'a': + pt = _add((t->tm_wday < 0 || + t->tm_wday >= DAYSPERWEEK) ? + "?" : Locale->wday[t->tm_wday], + pt, ptlim); + continue; + case 'B': + pt = _add((t->tm_mon < 0 || + t->tm_mon >= MONSPERYEAR) ? + "?" : Locale->month[t->tm_mon], + pt, ptlim); + continue; + case 'b': + case 'h': + pt = _add((t->tm_mon < 0 || + t->tm_mon >= MONSPERYEAR) ? + "?" : Locale->mon[t->tm_mon], + pt, ptlim); + continue; + case 'C': + /* + ** %C used to do a... + ** _fmt("%a %b %e %X %Y", t); + ** ...whereas now POSIX 1003.2 calls for + ** something completely different. + ** (ado, 1993-05-24) + */ + pt = _yconv(t->tm_year, TM_YEAR_BASE, + true, false, pt, ptlim); + continue; + case 'c': + { + enum warn warn2 = IN_SOME; + + pt = _fmt(Locale->c_fmt, t, pt, ptlim, &warn2); + if (warn2 == IN_ALL) + warn2 = IN_THIS; + if (warn2 > *warnp) + *warnp = warn2; + } + continue; + case 'D': + pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp); + continue; + case 'd': + pt = _conv(t->tm_mday, "%02d", pt, ptlim); + continue; + case 'E': + case 'O': + /* + ** Locale modifiers of C99 and later. + ** The sequences + ** %Ec %EC %Ex %EX %Ey %EY + ** %Od %oe %OH %OI %Om %OM + ** %OS %Ou %OU %OV %Ow %OW %Oy + ** are supposed to provide alternative + ** representations. + */ + goto label; + case 'e': + pt = _conv(t->tm_mday, "%2d", pt, ptlim); + continue; + case 'F': + pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp); + continue; + case 'H': + pt = _conv(t->tm_hour, "%02d", pt, ptlim); + continue; + case 'I': + pt = _conv((t->tm_hour % 12) ? + (t->tm_hour % 12) : 12, + "%02d", pt, ptlim); + continue; + case 'j': + pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim); + continue; + case 'k': + /* + ** This used to be... + ** _conv(t->tm_hour % 12 ? + ** t->tm_hour % 12 : 12, 2, ' '); + ** ...and has been changed to the below to + ** match SunOS 4.1.1 and Arnold Robbins' + ** strftime version 3.0. That is, "%k" and + ** "%l" have been swapped. + ** (ado, 1993-05-24) + */ + pt = _conv(t->tm_hour, "%2d", pt, ptlim); + continue; +#ifdef KITCHEN_SINK + case 'K': + /* + ** After all this time, still unclaimed! + */ + pt = _add("kitchen sink", pt, ptlim); + continue; +#endif /* defined KITCHEN_SINK */ + case 'l': + /* + ** This used to be... + ** _conv(t->tm_hour, 2, ' '); + ** ...and has been changed to the below to + ** match SunOS 4.1.1 and Arnold Robbin's + ** strftime version 3.0. That is, "%k" and + ** "%l" have been swapped. + ** (ado, 1993-05-24) + */ + pt = _conv((t->tm_hour % 12) ? + (t->tm_hour % 12) : 12, + "%2d", pt, ptlim); + continue; + case 'M': + pt = _conv(t->tm_min, "%02d", pt, ptlim); + continue; + case 'm': + pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim); + continue; + case 'n': + pt = _add("\n", pt, ptlim); + continue; + case 'p': + pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ? + Locale->pm : + Locale->am, + pt, ptlim); + continue; + case 'R': + pt = _fmt("%H:%M", t, pt, ptlim, warnp); + continue; + case 'r': + pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp); + continue; + case 'S': + pt = _conv(t->tm_sec, "%02d", pt, ptlim); + continue; + case 's': + { + struct tm tm; + char buf[INT_STRLEN_MAXIMUM( + time_t) + 1]; + time_t mkt; + + tm.tm_sec = t->tm_sec; + tm.tm_min = t->tm_min; + tm.tm_hour = t->tm_hour; + tm.tm_mday = t->tm_mday; + tm.tm_mon = t->tm_mon; + tm.tm_year = t->tm_year; +#ifdef TM_GMTOFF + mkt = timeoff(&tm, t->TM_GMTOFF); +#else + tm.tm_isdst = t->tm_isdst; + mkt = mktime(&tm); +#endif + /* If mktime fails, %s expands to the + value of (time_t) -1 as a failure + marker; this is better in practice + than strftime failing. */ + if (TYPE_SIGNED(time_t)) { + intmax_t n = mkt; + sprintf(buf, "%"PRIdMAX, n); + } else { + uintmax_t n = mkt; + sprintf(buf, "%"PRIuMAX, n); + } + pt = _add(buf, pt, ptlim); + } + continue; + case 'T': + pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp); + continue; + case 't': + pt = _add("\t", pt, ptlim); + continue; + case 'U': + pt = _conv((t->tm_yday + DAYSPERWEEK - + t->tm_wday) / DAYSPERWEEK, + "%02d", pt, ptlim); + continue; + case 'u': + /* + ** From Arnold Robbins' strftime version 3.0: + ** "ISO 8601: Weekday as a decimal number + ** [1 (Monday) - 7]" + ** (ado, 1993-05-24) + */ + pt = _conv((t->tm_wday == 0) ? + DAYSPERWEEK : t->tm_wday, + "%d", pt, ptlim); + continue; + case 'V': /* ISO 8601 week number */ + case 'G': /* ISO 8601 year (four digits) */ + case 'g': /* ISO 8601 year (two digits) */ +/* +** From Arnold Robbins' strftime version 3.0: "the week number of the +** year (the first Monday as the first day of week 1) as a decimal number +** (01-53)." +** (ado, 1993-05-24) +** +** From by Markus Kuhn: +** "Week 01 of a year is per definition the first week which has the +** Thursday in this year, which is equivalent to the week which contains +** the fourth day of January. In other words, the first week of a new year +** is the week which has the majority of its days in the new year. Week 01 +** might also contain days from the previous year and the week before week +** 01 of a year is the last week (52 or 53) of the previous year even if +** it contains days from the new year. A week starts with Monday (day 1) +** and ends with Sunday (day 7). For example, the first week of the year +** 1997 lasts from 1996-12-30 to 1997-01-05..." +** (ado, 1996-01-02) +*/ + { + int year; + int base; + int yday; + int wday; + int w; + + year = t->tm_year; + base = TM_YEAR_BASE; + yday = t->tm_yday; + wday = t->tm_wday; + for ( ; ; ) { + int len; + int bot; + int top; + + len = isleap_sum(year, base) ? + DAYSPERLYEAR : + DAYSPERNYEAR; + /* + ** What yday (-3 ... 3) does + ** the ISO year begin on? + */ + bot = ((yday + 11 - wday) % + DAYSPERWEEK) - 3; + /* + ** What yday does the NEXT + ** ISO year begin on? + */ + top = bot - + (len % DAYSPERWEEK); + if (top < -3) + top += DAYSPERWEEK; + top += len; + if (yday >= top) { + ++base; + w = 1; + break; + } + if (yday >= bot) { + w = 1 + ((yday - bot) / + DAYSPERWEEK); + break; + } + --base; + yday += isleap_sum(year, base) ? + DAYSPERLYEAR : + DAYSPERNYEAR; + } +#ifdef XPG4_1994_04_09 + if ((w == 52 && + t->tm_mon == TM_JANUARY) || + (w == 1 && + t->tm_mon == TM_DECEMBER)) + w = 53; +#endif /* defined XPG4_1994_04_09 */ + if (*format == 'V') + pt = _conv(w, "%02d", + pt, ptlim); + else if (*format == 'g') { + *warnp = IN_ALL; + pt = _yconv(year, base, + false, true, + pt, ptlim); + } else pt = _yconv(year, base, + true, true, + pt, ptlim); + } + continue; + case 'v': + /* + ** From Arnold Robbins' strftime version 3.0: + ** "date as dd-bbb-YYYY" + ** (ado, 1993-05-24) + */ + pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp); + continue; + case 'W': + pt = _conv((t->tm_yday + DAYSPERWEEK - + (t->tm_wday ? + (t->tm_wday - 1) : + (DAYSPERWEEK - 1))) / DAYSPERWEEK, + "%02d", pt, ptlim); + continue; + case 'w': + pt = _conv(t->tm_wday, "%d", pt, ptlim); + continue; + case 'X': + pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp); + continue; + case 'x': + { + enum warn warn2 = IN_SOME; + + pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2); + if (warn2 == IN_ALL) + warn2 = IN_THIS; + if (warn2 > *warnp) + *warnp = warn2; + } + continue; + case 'y': + *warnp = IN_ALL; + pt = _yconv(t->tm_year, TM_YEAR_BASE, + false, true, + pt, ptlim); + continue; + case 'Y': + pt = _yconv(t->tm_year, TM_YEAR_BASE, + true, true, + pt, ptlim); + continue; + case 'Z': +#ifdef TM_ZONE + pt = _add(t->TM_ZONE, pt, ptlim); +#elif HAVE_TZNAME + if (t->tm_isdst >= 0) + pt = _add(tzname[t->tm_isdst != 0], + pt, ptlim); +#endif + /* + ** C99 and later say that %Z must be + ** replaced by the empty string if the + ** time zone abbreviation is not + ** determinable. + */ + continue; + case 'z': +#if defined TM_GMTOFF || USG_COMPAT || ALTZONE + { + long diff; + char const * sign; + bool negative; + +# ifdef TM_GMTOFF + diff = t->TM_GMTOFF; +# else + /* + ** C99 and later say that the UT offset must + ** be computed by looking only at + ** tm_isdst. This requirement is + ** incorrect, since it means the code + ** must rely on magic (in this case + ** altzone and timezone), and the + ** magic might not have the correct + ** offset. Doing things correctly is + ** tricky and requires disobeying the standard; + ** see GNU C strftime for details. + ** For now, punt and conform to the + ** standard, even though it's incorrect. + ** + ** C99 and later say that %z must be replaced by + ** the empty string if the time zone is not + ** determinable, so output nothing if the + ** appropriate variables are not available. + */ + if (t->tm_isdst < 0) + continue; + if (t->tm_isdst == 0) +# if USG_COMPAT + diff = -timezone; +# else + continue; +# endif + else +# if ALTZONE + diff = -altzone; +# else + continue; +# endif +# endif + negative = diff < 0; + if (diff == 0) { +# ifdef TM_ZONE + negative = t->TM_ZONE[0] == '-'; +# else + negative = t->tm_isdst < 0; +# if HAVE_TZNAME + if (tzname[t->tm_isdst != 0][0] == '-') + negative = true; +# endif +# endif + } + if (negative) { + sign = "-"; + diff = -diff; + } else sign = "+"; + pt = _add(sign, pt, ptlim); + diff /= SECSPERMIN; + diff = (diff / MINSPERHOUR) * 100 + + (diff % MINSPERHOUR); + pt = _conv(diff, "%04d", pt, ptlim); + } +#endif + continue; + case '+': + pt = _fmt(Locale->date_fmt, t, pt, ptlim, + warnp); + continue; + case '%': + /* + ** X311J/88-090 (4.12.3.5): if conversion char is + ** undefined, behavior is undefined. Print out the + ** character itself as printf(3) also does. + */ + default: + break; + } + } + if (pt == ptlim) + break; + *pt++ = *format; + } + return pt; +} + +static char * +_conv(int n, const char *format, char *pt, const char *ptlim) +{ + char buf[INT_STRLEN_MAXIMUM(int) + 1]; + + sprintf(buf, format, n); + return _add(buf, pt, ptlim); +} + +static char * +_add(const char *str, char *pt, const char *ptlim) +{ + while (pt < ptlim && (*pt = *str++) != '\0') + ++pt; + return pt; +} + +/* +** POSIX and the C Standard are unclear or inconsistent about +** what %C and %y do if the year is negative or exceeds 9999. +** Use the convention that %C concatenated with %y yields the +** same output as %Y, and that %Y contains at least 4 bytes, +** with more only if necessary. +*/ + +static char * +_yconv(int a, int b, bool convert_top, bool convert_yy, + char *pt, const char *ptlim) +{ + register int lead; + register int trail; + + int DIVISOR = 100; + trail = a % DIVISOR + b % DIVISOR; + lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR; + trail %= DIVISOR; + if (trail < 0 && lead > 0) { + trail += DIVISOR; + --lead; + } else if (lead < 0 && trail > 0) { + trail -= DIVISOR; + ++lead; + } + if (convert_top) { + if (lead == 0 && trail < 0) + pt = _add("-0", pt, ptlim); + else pt = _conv(lead, "%02d", pt, ptlim); + } + if (convert_yy) + pt = _conv(((trail < 0) ? -trail : trail), "%02d", pt, ptlim); + return pt; +} diff --git a/vendor/chrono-tz/tz/theory.html b/vendor/chrono-tz/tz/theory.html new file mode 100644 index 0000000000000..516d2a525111f --- /dev/null +++ b/vendor/chrono-tz/tz/theory.html @@ -0,0 +1,1506 @@ + + + + Theory and pragmatics of the tz code and data + + + + + +

Theory and pragmatics of the tz code and data

+

Outline

+
+ +
+

Scope of the tz database

+

+The tz +database attempts to record the history and predicted future of +civil time scales. +It organizes time zone and daylight saving time +data by partitioning the world into timezones +whose clocks all agree about timestamps that occur after the POSIX Epoch +(1970-01-01 00:00:00 UTC). +Although 1970 is a somewhat-arbitrary cutoff, there are significant +challenges to moving the cutoff earlier even by a decade or two, due +to the wide variety of local practices before computer timekeeping +became prevalent. +Most timezones correspond to a notable location and the database +records all known clock transitions for that location; +some timezones correspond instead to a fixed UTC offset. +

+ +

+Each timezone typically corresponds to a geographical region that is +smaller than a traditional time zone, because clocks in a timezone +all agree after 1970 whereas a traditional time zone merely +specifies current standard time. For example, applications that deal +with current and future timestamps in the traditional North +American mountain time zone can choose from the timezones +America/Denver which observes US-style daylight saving +time (DST), +and America/Phoenix which does not observe DST. +Applications that also deal with past timestamps in the mountain time +zone can choose from over a dozen timezones, such as +America/Boise, America/Edmonton, and +America/Hermosillo, each of which currently uses mountain +time but differs from other timezones for some timestamps after 1970. +

+ +

+Clock transitions before 1970 are recorded for location-based timezones, +because most systems support timestamps before 1970 and could +misbehave if data entries were omitted for pre-1970 transitions. +However, the database is not designed for and does not suffice for +applications requiring accurate handling of all past times everywhere, +as it would take far too much effort and guesswork to record all +details of pre-1970 civil timekeeping. +Although some information outside the scope of the database is +collected in a file backzone that is distributed along +with the database proper, this file is less reliable and does not +necessarily follow database guidelines. +

+ +

+As described below, reference source code for using the +tz database is also available. +The tz code is upwards compatible with POSIX, an international +standard for UNIX-like systems. +As of this writing, the current edition of POSIX is: The Open +Group Base Specifications Issue 7, IEEE Std 1003.1-2017, 2018 +Edition. +Because the database's scope encompasses real-world changes to civil +timekeeping, its model for describing time is more complex than the +standard and daylight saving times supported by POSIX.1-2017. +A tz timezone corresponds to a ruleset that can +have more than two changes per year, these changes need not merely +flip back and forth between two alternatives, and the rules themselves +can change at times. +Whether and when a timezone changes its clock, +and even the timezone's notional base offset from UTC, +are variable. +It does not always make sense to talk about a timezone's +"base offset", which is not necessarily a single number. +

+ +
+ +
+

Timezone identifiers

+

+Each timezone has a name that uniquely identifies the timezone. +Inexperienced users are not expected to select these names unaided. +Distributors should provide documentation and/or a simple selection +interface that explains each name via a map or via descriptive text like +"Czech Republic" instead of the timezone name "Europe/Prague". +If geolocation information is available, a selection interface can +locate the user on a timezone map or prioritize names that are +geographically close. For an example selection interface, see the +tzselect program in the tz code. +The Unicode Common Locale Data +Repository contains data that may be useful for other selection +interfaces; it maps timezone names like Europe/Prague to +locale-dependent strings like "Prague", "Praha", "Прага", and "布拉格". +

+ +

+The naming conventions attempt to strike a balance +among the following goals: +

+ +
    +
  • + Uniquely identify every timezone where clocks have agreed since 1970. + This is essential for the intended use: static clocks keeping local + civil time. +
  • +
  • + Indicate to experts where the timezone's clocks typically are. +
  • +
  • + Be robust in the presence of political changes. + For example, names are typically not tied to countries, to avoid + incompatibilities when countries change their name (e.g., + Swaziland→Eswatini) or when locations change countries (e.g., Hong + Kong from UK colony to China). + There is no requirement that every country or national + capital must have a timezone name. +
  • +
  • + Be portable to a wide variety of implementations. +
  • +
  • + Use a consistent naming conventions over the entire world. +
  • +
+ +

+Names normally have the form +AREA/LOCATION, where +AREA is a continent or ocean, and +LOCATION is a specific location within the area. +North and South America share the same area, 'America'. +Typical names are 'Africa/Cairo', +'America/New_York', and 'Pacific/Honolulu'. +Some names are further qualified to help avoid confusion; for example, +'America/Indiana/Petersburg' distinguishes Petersburg, +Indiana from other Petersburgs in America. +

+ +

+Here are the general guidelines used for +choosing timezone names, +in decreasing order of importance: +

+ +
    +
  • + Use only valid POSIX file name components (i.e., the parts of + names other than '/'). + Do not use the file name components '.' and + '..'. + Within a file name component, use only ASCII letters, + '.', '-' and '_'. + Do not use digits, as that might create an ambiguity with POSIX.1-2017 + TZ strings. + A file name component must not exceed 14 characters or start with + '-'. + E.g., prefer America/Noronha to + America/Fernando_de_Noronha. + Exceptions: see the discussion of legacy names below. +
  • +
  • + A name must not be empty, or contain '//', or + start or end with '/'. +
  • +
  • + Do not use names that differ only in case. + Although the reference implementation is case-sensitive, some + other implementations are not, and they would mishandle names + differing only in case. +
  • +
  • + If one name A is an initial prefix of another + name AB (ignoring case), then B must not + start with '/', as a regular file cannot have the + same name as a directory in POSIX. + For example, America/New_York precludes + America/New_York/Bronx. +
  • +
  • + Uninhabited regions like the North Pole and Bouvet Island + do not need locations, since local time is not defined there. +
  • +
  • + If all the clocks in a timezone have agreed since 1970, + do not bother to include more than one timezone + even if some of the clocks disagreed before 1970. + Otherwise these tables would become annoyingly large. +
  • +
  • + If boundaries between regions are fluid, such as during a war or + insurrection, do not bother to create a new timezone merely + because of yet another boundary change. This helps prevent table + bloat and simplifies maintenance. +
  • +
  • + If a name is ambiguous, use a less ambiguous alternative; + e.g., many cities are named San José and Georgetown, so + prefer America/Costa_Rica to + America/San_Jose and America/Guyana + to America/Georgetown. +
  • +
  • + Keep locations compact. + Use cities or small islands, not countries or regions, so that any + future changes do not split individual locations into different + timezones. + E.g., prefer Europe/Paris to Europe/France, + since + France + has had multiple time zones. +
  • +
  • + Use mainstream English spelling, e.g., prefer + Europe/Rome to Europa/Roma, and + prefer Europe/Athens to the Greek + ΕυÏώπη/Αθήνα or the Romanized + Evrópi/Athína. + The POSIX file name restrictions encourage this guideline. +
  • +
  • + Use the most populous among locations in a region, + e.g., prefer Asia/Shanghai to + Asia/Beijing. + Among locations with similar populations, pick the best-known + location, e.g., prefer Europe/Rome to + Europe/Milan. +
  • +
  • + Use the singular form, e.g., prefer Atlantic/Canary to + Atlantic/Canaries. +
  • +
  • + Omit common suffixes like '_Islands' and + '_City', unless that would lead to ambiguity. + E.g., prefer America/Cayman to + America/Cayman_Islands and + America/Guatemala to + America/Guatemala_City, but prefer + America/Mexico_City to + America/Mexico + because the + country of Mexico has several time zones. +
  • +
  • + Use '_' to represent a space. +
  • +
  • + Omit '.' from abbreviations in names. + E.g., prefer Atlantic/St_Helena to + Atlantic/St._Helena. +
  • +
  • + Do not change established names if they only marginally violate + the above guidelines. + For example, do not change the existing name Europe/Rome to + Europe/Milan merely because Milan's population has grown + to be somewhat greater than Rome's. +
  • +
  • + If a name is changed, put its old spelling in the + 'backward' file as a link to the new spelling. + This means old spellings will continue to work. + Ordinarily a name change should occur only in the rare case when + a location's consensus English-language spelling changes; for example, + in 2008 Asia/Calcutta was renamed to Asia/Kolkata + due to long-time widespread use of the new city name instead of the old. +
  • +
+ +

+Guidelines have evolved with time, and names following old versions of +these guidelines might not follow the current version. When guidelines +have changed, old names continue to be supported. Guideline changes +have included the following: +

+ +
    +
  • +Older versions of this package used a different naming scheme. +See the file 'backward' for most of these older names +(e.g., 'US/Eastern' instead of 'America/New_York'). +The other old-fashioned names still supported are +'WET', 'CET', 'MET', and +'EET' (see the file 'europe'). +
  • + +
  • +Older versions of this package defined legacy names that are +incompatible with the first guideline of location names, but which are +still supported. +These legacy names are mostly defined in the file +'etcetera'. +Also, the file 'backward' defines the legacy names +'Etc/GMT0', 'Etc/GMT-0', 'Etc/GMT+0', +'GMT0', 'GMT-0' and 'GMT+0', +and the file 'northamerica' defines the legacy names +'EST5EDT', 'CST6CDT', +'MST7MDT', and 'PST8PDT'. +
  • + +
  • +Older versions of these guidelines said that +there should typically be at least one name for each ISO +3166-1 officially assigned two-letter code for an inhabited +country or territory. +This old guideline has been dropped, as it was not needed to handle +timestamps correctly and it increased maintenance burden. +
  • +
+ +

+The file zone1970.tab lists geographical locations used +to name timezones. +It is intended to be an exhaustive list of names for geographic +regions as described above; this is a subset of the timezones in the data. +Although a zone1970.tab location's +longitude +corresponds to +its local mean +time (LMT) offset with one hour for every 15° +east longitude, this relationship is not exact. +The backward-compatibility file zone.tab is similar +but conforms to the older-version guidelines related to ISO 3166-1; +it lists only one country code per entry and unlike zone1970.tab +it can list names defined in backward. +Applications that process only timestamps from now on can instead use the file +zonenow.tab, which partitions the world more coarsely, +into regions where clocks agree now and in the predicted future; +this file is smaller and simpler than zone1970.tab +and zone.tab. +

+ +

+The database defines each timezone name to be a zone, or a link to a zone. +The source file backward defines links for backward +compatibility; it does not define zones. +Although backward was originally designed to be optional, +nowadays distributions typically use it +and no great weight should be attached to whether a link +is defined in backward or in some other file. +The source file etcetera defines names that may be useful +on platforms that do not support POSIX.1-2017-style TZ strings; +no other source file other than backward +contains links to its zones. +One of etcetera's names is Etc/UTC, +used by functions like gmtime to obtain leap +second information on platforms that support leap seconds. +Another etcetera name, GMT, +is used by older code releases. +

+
+ +
+

Time zone abbreviations

+

+When this package is installed, it generates time zone abbreviations +like 'EST' to be compatible with human tradition and POSIX. +Here are the general guidelines used for choosing time zone abbreviations, +in decreasing order of importance: +

+ +
    +
  • + Use three to six characters that are ASCII alphanumerics or + '+' or '-'. + Previous editions of this database also used characters like + space and '?', but these characters have a + special meaning to the + UNIX shell + and cause commands like + 'set + `date`' + to have unexpected effects. + Previous editions of this guideline required upper-case letters, but the + Congressman who introduced + Chamorro + Standard Time preferred "ChST", so lower-case letters are now + allowed. + Also, POSIX from 2001 on relaxed the rule to allow '-', + '+', and alphanumeric characters from the portable + character set in the current locale. + In practice ASCII alphanumerics and '+' and + '-' are safe in all locales. + +

    + In other words, in the C locale the POSIX extended regular + expression [-+[:alnum:]]{3,6} should match the + abbreviation. + This guarantees that all abbreviations could have been specified by a + POSIX.1-2017 TZ string. +

    +
  • +
  • + Use abbreviations that are in common use among English-speakers, + e.g., 'EST' for Eastern Standard Time in North America. + We assume that applications translate them to other languages + as part of the normal localization process; for example, + a French application might translate 'EST' to 'HNE'. + +

    + These abbreviations (for standard/daylight/etc. time) are: + ACST/ACDT Australian Central, + AST/ADT/APT/AWT/ADDT Atlantic, + AEST/AEDT Australian Eastern, + AHST/AHDT Alaska-Hawaii, + AKST/AKDT Alaska, + AWST/AWDT Australian Western, + BST/BDT Bering, + CAT/CAST Central Africa, + CET/CEST/CEMT Central European, + ChST Chamorro, + CST/CDT/CWT/CPT Central [North America], + CST/CDT China, + GMT/BST/IST/BDST Greenwich, + EAT East Africa, + EST/EDT/EWT/EPT Eastern [North America], + EET/EEST Eastern European, + GST/GDT Guam, + HST/HDT/HWT/HPT Hawaii, + HKT/HKST/HKWT Hong Kong, + IST India, + IST/GMT Irish, + IST/IDT/IDDT Israel, + JST/JDT Japan, + KST/KDT Korea, + MET/MEST Middle European (a backward-compatibility alias for + Central European), + MSK/MSD Moscow, + MST/MDT/MWT/MPT Mountain, + NST/NDT/NWT/NPT/NDDT Newfoundland, + NST/NDT/NWT/NPT Nome, + NZMT/NZST New Zealand through 1945, + NZST/NZDT New Zealand 1946–present, + PKT/PKST Pakistan, + PST/PDT/PWT/PPT Pacific, + PST/PDT Philippine, + SAST South Africa, + SST Samoa, + UTC Universal, + WAT/WAST West Africa, + WET/WEST/WEMT Western European, + WIB Waktu Indonesia Barat, + WIT Waktu Indonesia Timur, + WITA Waktu Indonesia Tengah, + YST/YDT/YWT/YPT/YDDT Yukon. +

    +
  • +
  • +

    + For times taken from a city's longitude, use the + traditional xMT notation. + The only abbreviation like this in current use is 'GMT'. + The others are for timestamps before 1960, + except that Monrovia Mean Time persisted until 1972. + Typically, numeric abbreviations (e.g., '-004430' for + MMT) would cause trouble here, as the numeric strings would exceed + the POSIX length limit. +

    + +

    + These abbreviations are: + AMT Asunción, Athens; + BMT Baghdad, Bangkok, Batavia, Bermuda, Bern, Bogotá, + Brussels, Bucharest; + CMT Calamarca, Caracas, Chisinau, Colón, Córdoba; + DMT Dublin/Dunsink; + EMT Easter; + FFMT Fort-de-France; + FMT Funchal; + GMT Greenwich; + HMT Havana, Helsinki, Horta, Howrah; + IMT Irkutsk, Istanbul; + JMT Jerusalem; + KMT Kaunas, Kyiv, Kingston; + LMT Lima, Lisbon, local; + MMT Macassar, Madras, Malé, Managua, Minsk, Monrovia, Montevideo, + Moratuwa, Moscow; + PLMT Phù Liễn; + PMT Paramaribo, Paris, Perm, Pontianak, Prague; + PMMT Port Moresby; + PPMT Port-au-Prince; + QMT Quito; + RMT Rangoon, Riga, Rome; + SDMT Santo Domingo; + SJMT San José; + SMT Santiago, Simferopol, Singapore, Stanley; + TBMT Tbilisi; + TMT Tallinn, Tehran; + WMT Warsaw. +

    + +

    + A few abbreviations also follow the pattern that + GMT/BST established for time in the UK. + They are: + BMT/BST for Bermuda 1890–1930, + CMT/BST for Calamarca Mean Time and Bolivian Summer Time + 1890–1932, + DMT/IST for Dublin/Dunsink Mean Time and Irish Summer Time + 1880–1916, + MMT/MST/MDST for Moscow 1880–1919, and + RMT/LST for Riga Mean Time and Latvian Summer time 1880–1926. + +

    +
  • +
  • + Use 'LMT' for local mean time of locations before the + introduction of standard time; see "Scope of the + tz database". +
  • +
  • + If there is no common English abbreviation, use numeric offsets like + -05 and +0530 that are generated + by zic's %z notation. +
  • +
  • + Use current abbreviations for older timestamps to avoid confusion. + For example, in 1910 a common English abbreviation for time + in central Europe was 'MEZ' (short for both "Middle European + Zone" and for "Mitteleuropäische Zeit" in German). + Nowadays 'CET' ("Central European Time") is more common in + English, and the database uses 'CET' even for circa-1910 + timestamps as this is less confusing for modern users and avoids + the need for determining when 'CET' supplanted 'MEZ' in common + usage. +
  • +
  • + Use a consistent style in a timezone's history. + For example, if a history tends to use numeric + abbreviations and a particular entry could go either way, use a + numeric abbreviation. +
  • +
  • + Use + Universal Time + (UT) (with time zone abbreviation '-00') for + locations while uninhabited. + The leading '-' is a flag that the UT offset is in + some sense undefined; this notation is derived + from Internet + RFC 3339. +
  • +
+ +

+Application writers should note that these abbreviations are ambiguous +in practice: e.g., 'CST' means one thing in China and something else +in North America, and 'IST' can refer to time in India, Ireland or +Israel. +To avoid ambiguity, use numeric UT offsets like +'-0600' instead of time zone abbreviations like 'CST'. +

+
+ +
+

Accuracy of the tz database

+

+The tz database is not authoritative, and it +surely has errors. +Corrections are welcome and encouraged; see the file CONTRIBUTING. +Users requiring authoritative data should consult national standards +bodies and the references cited in the database's comments. +

+ +

+Errors in the tz database arise from many sources: +

+ +
    +
  • + The tz database predicts future + timestamps, and current predictions + will be incorrect after future governments change the rules. + For example, if today someone schedules a meeting for 13:00 next + October 1, Casablanca time, and tomorrow Morocco changes its + daylight saving rules, software can mess up after the rule change + if it blithely relies on conversions made before the change. +
  • +
  • + The pre-1970 entries in this database cover only a tiny sliver of how + clocks actually behaved; the vast majority of the necessary + information was lost or never recorded. + Thousands more timezones would be needed if + the tz database's scope were extended to + cover even just the known or guessed history of standard time; for + example, the current single entry for France would need to split + into dozens of entries, perhaps hundreds. + And in most of the world even this approach would be misleading + due to widespread disagreement or indifference about what times + should be observed. + In her 2015 book + The + Global Transformation of Time, 1870–1950, + Vanessa Ogle writes + "Outside of Europe and North America there was no system of time + zones at all, often not even a stable landscape of mean times, + prior to the middle decades of the twentieth century". + See: Timothy Shenk, Booked: + A Global History of Time. Dissent 2015-12-17. +
  • +
  • + Most of the pre-1970 data entries come from unreliable sources, often + astrology books that lack citations and whose compilers evidently + invented entries when the true facts were unknown, without + reporting which entries were known and which were invented. + These books often contradict each other or give implausible entries, + and on the rare occasions when they are checked they are + typically found to be incorrect. +
  • +
  • + For the UK the tz database relies on + years of first-class work done by + Joseph Myers and others; see + "History of + legal time in Britain". + Other countries are not done nearly as well. +
  • +
  • + Sometimes, different people in the same city maintain clocks + that differ significantly. + Historically, railway time was used by railroad companies (which + did not always + agree with each other), church-clock time was used for birth + certificates, etc. + More recently, competing political groups might disagree about + clock settings. Often this is merely common practice, but + sometimes it is set by law. + For example, from 1891 to 1911 the UT offset in France + was legally UT +00:09:21 outside train stations and + UT +00:04:21 inside. Other examples include + Chillicothe in 1920, Palm Springs in 1946/7, and Jerusalem and + Ãœrümqi to this day. +
  • +
  • + Although a named location in the tz + database stands for the containing region, its pre-1970 data + entries are often accurate for only a small subset of that region. + For example, Europe/London stands for the United + Kingdom, but its pre-1847 times are valid only for locations that + have London's exact meridian, and its 1847 transition + to GMT is known to be valid only for the L&NW and + the Caledonian railways. +
  • +
  • + The tz database does not record the + earliest time for which a timezone's + data entries are thereafter valid for every location in the region. + For example, Europe/London is valid for all locations + in its region after GMT was made the standard time, + but the date of standardization (1880-08-02) is not in the + tz database, other than in commentary. + For many timezones the earliest time of + validity is unknown. +
  • +
  • + The tz database does not record a + region's boundaries, and in many cases the boundaries are not known. + For example, the timezone + America/Kentucky/Louisville represents a region + around the city of Louisville, the boundaries of which are + unclear. +
  • +
  • + Changes that are modeled as instantaneous transitions in the + tz + database were often spread out over hours, days, or even decades. +
  • +
  • + Even if the time is specified by law, locations sometimes + deliberately flout the law. +
  • +
  • + Early timekeeping practices, even assuming perfect clocks, were + often not specified to the accuracy that the + tz database requires. +
  • +
  • + The tz database cannot represent stopped clocks. + However, on 1911-03-11 at 00:00, some public-facing French clocks + were changed by stopping them for a few minutes to effect a transition. + The tz database models this via a + backward transition; the relevant French legislation does not + specify exactly how the transition was to occur. +
  • +
  • + Sometimes historical timekeeping was specified more precisely + than what the tz code can handle. + For example, from 1880 to 1916 clocks in Ireland observed Dublin Mean + Time (estimated to be UT + −00:25:21.1); although the tz + source data can represent the .1 second, TZif files and the code cannot. + In practice these old specifications were rarely if ever + implemented to subsecond precision. +
  • +
  • + Even when all the timestamp transitions recorded by the + tz database are correct, the + tz rules that generate them may not + faithfully reflect the historical rules. + For example, from 1922 until World War II the UK moved clocks + forward the day following the third Saturday in April unless that + was Easter, in which case it moved clocks forward the previous + Sunday. + Because the tz database has no + way to specify Easter, these exceptional years are entered as + separate tz Rule lines, even though the + legal rules did not change. + When transitions are known but the historical rules behind them are not, + the database contains Zone and Rule + entries that are intended to represent only the generated + transitions, not any underlying historical rules; however, this + intent is recorded at best only in commentary. +
  • +
  • + The tz database models time + using the proleptic + Gregorian calendar with days containing 24 equal-length hours + numbered 00 through 23, except when clock transitions occur. + Pre-standard time is modeled as local mean time. + However, historically many people used other calendars and other timescales. + For example, the Roman Empire used + the Julian + calendar, + and Roman + timekeeping had twelve varying-length daytime hours with a + non-hour-based system at night. + And even today, some local practices diverge from the Gregorian + calendar with 24-hour days. These divergences range from + relatively minor, such as Japanese bars giving times like "24:30" for the + wee hours of the morning, to more-significant differences such as the + east African practice of starting the day at dawn, renumbering + the Western 06:00 to be 12:00. These practices are largely outside + the scope of the tz code and data, which + provide only limited support for date and time localization + such as that required by POSIX.1-2017. + If DST is not used a different time zone + can often do the trick; for example, in Kenya a TZ setting + like <-03>3 or America/Cayenne starts + the day six hours later than Africa/Nairobi does. +
  • +
  • + Early clocks were less reliable, and data entries do not represent + clock error. +
  • +
  • + The tz database assumes Universal Time + (UT) as an origin, even though UT is not + standardized for older timestamps. + In the tz database commentary, + UT denotes a family of time standards that includes + Coordinated Universal Time (UTC) along with other + variants such as UT1 and GMT, + with days starting at midnight. + Although UT equals UTC for modern + timestamps, UTC was not defined until 1960, so + commentary uses the more general abbreviation UT for + timestamps that might predate 1960. + Since UT, UT1, etc. disagree slightly, + and since pre-1972 UTC seconds varied in length, + interpretation of older timestamps can be problematic when + subsecond accuracy is needed. +
  • +
  • + Civil time was not based on atomic time before 1972, and we do not + know the history of + earth's + rotation accurately enough to map SI seconds to + historical solar time + to more than about one-hour accuracy. + See: Stephenson FR, Morrison LV, Hohenkerk CY. + Measurement of + the Earth's rotation: 720 BC to AD 2015. + Proc Royal Soc A. 2016;472:20160404. + Also see: Espenak F. Uncertainty + in Delta T (ΔT). +
  • +
  • + The relationship between POSIX time (that is, UTC but + ignoring leap + seconds) and UTC is not agreed upon. + This affects time stamps during the leap second era (1972–2035). + Although the POSIX + clock officially stops during an inserted leap second, at least one + proposed standard has it jumping back a second instead; and in + practice POSIX clocks more typically either progress glacially during + a leap second, or are slightly slowed while near a leap second. +
  • +
  • + The tz database does not represent how + uncertain its information is. + Ideally it would contain information about when data entries are + incomplete or dicey. + Partial temporal knowledge is a field of active research, though, + and it is not clear how to apply it here. +
  • +
+ +

+In short, many, perhaps most, of the tz +database's pre-1970 and future timestamps are either wrong or +misleading. +Any attempt to pass the +tz database off as the definition of time +should be unacceptable to anybody who cares about the facts. +In particular, the tz database's +LMT offsets should not be considered meaningful, and +should not prompt creation of timezones +merely because two locations +differ in LMT or transitioned to standard time at +different dates. +

+
+ +
+

Time and date functions

+

+The tz code contains time and date functions +that are upwards compatible with those of POSIX. +Code compatible with this package is already +part of many platforms, where the +primary use of this package is to update obsolete time-related files. +To do this, you may need to compile the time zone compiler +'zic' supplied with this package instead of using the +system 'zic', since the format of zic's +input is occasionally extended, and a platform may still be shipping +an older zic. +

+ +

POSIX.1-2017 properties and limitations

+
    +
  • +

    + In POSIX.1-2017, time display in a process is controlled by the + environment variable TZ. + Unfortunately, the POSIX.1-2017 + TZ string takes a form that is hard to describe and + is error-prone in practice. + Also, POSIX.1-2017 TZ strings cannot deal with daylight + saving time rules not based on the Gregorian calendar (as in + Morocco), or with situations where more than two time zone + abbreviations or UT offsets are used in an area. +

    + +

    + The POSIX.1-2017 TZ string takes the following form: +

    + +

    + stdoffset[dst[offset][,date[/time],date[/time]]] +

    + +

    + where: +

    + +
    +
    std and dst
    + are 3 or more characters specifying the standard + and daylight saving time (DST) zone abbreviations. + Starting with POSIX.1-2001, std and dst + may also be in a quoted form like '<+09>'; + this allows "+" and "-" in the names. +
    +
    offset
    + is of the form + '[±]hh:[mm[:ss]]' + and specifies the offset west of UT. + 'hh' may be a single digit; + 0≤hh≤24. + The default DST offset is one hour ahead of + standard time. +
    +
    date[/time],date[/time]
    + specifies the beginning and end of DST. + If this is absent, the system supplies its own ruleset + for DST, typically current US + DST rules. +
    +
    time
    + takes the form + 'hh:[mm[:ss]]' + and defaults to 02:00. + This is the same format as the offset, except that a + leading '+' or '-' is not allowed. +
    +
    date
    + takes one of the following forms: +
    +
    Jn (1≤n≤365)
    + origin-1 day number not counting February 29 +
    +
    n (0≤n≤365)
    + origin-0 day number counting February 29 if present +
    +
    Mm.n.d + (0[Sunday]≤d≤6[Saturday], 1≤n≤5, + 1≤m≤12)
    + for the dth day of week n of + month m of the year, where week 1 is the first + week in which day d appears, and + '5' stands for the last week in which + day d appears (which may be either the 4th or + 5th week). + Typically, this is the only useful form; the n + and Jn forms are rarely used. +
    +
    +
    +
    + +

    + Here is an example POSIX.1-2017 TZ string for New + Zealand after 2007. + It says that standard time (NZST) is 12 hours ahead + of UT, and that daylight saving time + (NZDT) is observed from September's last Sunday at + 02:00 until April's first Sunday at 03:00: +

    + +
    TZ='NZST-12NZDT,M9.5.0,M4.1.0/3'
    + +

    + This POSIX.1-2017 TZ string is hard to remember, and + mishandles some timestamps before 2008. + With this package you can use this instead: +

    + +
    TZ='Pacific/Auckland'
    +
  • +
  • + POSIX does not define the DST transitions + for TZ values like + "EST5EDT". + Traditionally the current US DST rules + were used to interpret such values, but this meant that the + US DST rules were compiled into each + time conversion package, and when + US time conversion rules changed (as in the United + States in 1987 and again in 2007), all packages that + interpreted TZ values had to be updated + to ensure proper results. +
  • +
  • + The TZ environment variable is process-global, which + makes it hard to write efficient, thread-safe applications that + need access to multiple timezones. +
  • +
  • + In POSIX, there is no tamper-proof way for a process to learn the + system's best idea of local (wall clock) time. + This is important for applications that an administrator wants + used only at certain times – without regard to whether the + user has fiddled the + TZ environment variable. + While an administrator can "do everything in UT" to + get around the problem, doing so is inconvenient and precludes + handling daylight saving time shifts – as might be required to + limit phone calls to off-peak hours. +
  • +
  • + POSIX.1-2017 provides no convenient and efficient way to determine + the UT offset and time zone abbreviation of arbitrary + timestamps, particularly for timezones + that do not fit into the POSIX model. +
  • +
  • + POSIX requires that time_t clock counts exclude leap + seconds. +
  • +
  • + The tz code attempts to support all the + time_t implementations allowed by POSIX. + The time_t type represents a nonnegative count of seconds + since 1970-01-01 00:00:00 UTC, ignoring leap seconds. + In practice, time_t is usually a signed 64- or 32-bit + integer; 32-bit signed time_t values stop working after + 2038-01-19 03:14:07 UTC, so new implementations these + days typically use a signed 64-bit integer. + Unsigned 32-bit integers are used on one or two platforms, and 36-bit + and 40-bit integers are also used occasionally. + Although earlier POSIX versions allowed time_t to be a + floating-point type, this was not supported by any practical system, + and POSIX.1-2013 and the tz code both + require time_t to be an integer type. +
  • +
+ +

Extensions to POSIX.1-2017 in the +tz code

+
    +
  • +

    + The TZ environment variable is used in generating + the name of a file from which time-related information is read + (or is interpreted à la POSIX.1-2017); TZ is no longer + constrained to be a string containing abbreviations + and numeric data as described above. + The file's format is TZif, + a timezone information format that contains binary data; see + Internet + RFC 8536. + The daylight saving time rules to be used for a + particular timezone are encoded in the + TZif file; the format of the file allows US, + Australian, and other rules to be encoded, and + allows for situations where more than two time zone + abbreviations are used. +

    +

    + It was recognized that allowing the TZ environment + variable to take on values such as 'America/New_York' + might cause "old" programs (that expect TZ to have a + certain form) to operate incorrectly; consideration was given to using + some other environment variable (for example, TIMEZONE) + to hold the string used to generate the TZif file's name. + In the end, however, it was decided to continue using + TZ: it is widely used for time zone purposes; + separately maintaining both TZ + and TIMEZONE seemed a nuisance; and systems where + "new" forms of TZ might cause problems can simply + use legacy TZ values such as "EST5EDT" which + can be used by "new" programs as well as by "old" programs that + assume pre-POSIX TZ values. +

    +
  • +
  • + The code supports platforms with a UT offset member + in struct tm, e.g., tm_gmtoff, + or with a time zone abbreviation member in + struct tm, e.g., tm_zone. As noted + in Austin + Group defect 1533, a future version of POSIX is planned to + require tm_gmtoff and tm_zone. +
  • +
  • + Functions tzalloc, tzfree, + localtime_rz, and mktime_z for + more-efficient thread-safe applications that need to use multiple + timezones. + The tzalloc and tzfree functions + allocate and free objects of type timezone_t, + and localtime_rz and mktime_z are + like localtime_r and mktime with an + extra timezone_t argument. + The functions were inspired by NetBSD. +
  • +
  • + Negative time_t values are supported, on systems + where time_t is signed. +
  • +
  • + These functions can account for leap seconds; + see Leap seconds below. +
  • +
+ +

POSIX features no longer needed

+

+POSIX and ISO C +define some APIs that are vestigial: +they are not needed, and are relics of a too-simple model that does +not suffice to handle many real-world timestamps. +Although the tz code supports these +vestigial APIs for backwards compatibility, they should +be avoided in portable applications. +The vestigial APIs are: +

+
    +
  • + The POSIX tzname variable does not suffice and is no + longer needed. + To get a timestamp's time zone abbreviation, consult + the tm_zone member if available; otherwise, + use strftime's "%Z" conversion + specification. +
  • +
  • + The POSIX daylight and timezone + variables do not suffice and are no longer needed. + To get a timestamp's UT offset, consult + the tm_gmtoff member if available; otherwise, + subtract values returned by localtime + and gmtime using the rules of the Gregorian calendar, + or use strftime's "%z" conversion + specification if a string like "+0900" suffices. +
  • +
  • + The tm_isdst member is almost never needed and most of + its uses should be discouraged in favor of the abovementioned + APIs. + Although it can still be used in arguments to + mktime to disambiguate timestamps near + a DST transition when the clock jumps back on + platforms lacking tm_gmtoff, this + disambiguation does not work when standard time itself jumps back, + which can occur when a location changes to a time zone with a + lesser UT offset. +
  • +
+ +

Other portability notes

+
    +
  • + The 7th Edition + UNIX timezone function is not present in this + package; it is impossible to reliably map timezone's + arguments (a "minutes west of GMT" value and a + "daylight saving time in effect" flag) to a time zone + abbreviation, and we refuse to guess. + Programs that in the past used the timezone function + may now examine localtime(&clock)->tm_zone + (if TM_ZONE is defined) or + tzname[localtime(&clock)->tm_isdst] + (if HAVE_TZNAME is nonzero) to learn the correct time + zone abbreviation to use. +
  • +
  • + The 4.2BSD + gettimeofday function is not + used in this package. + This formerly let users obtain the current UTC offset + and DST flag, but this functionality was removed in + later versions of BSD. +
  • +
  • + In SVR2, time conversion fails for near-minimum or + near-maximum time_t values when doing conversions + for places that do not use UT. + This package takes care to do these conversions correctly. + A comment in the source code tells how to get compatibly wrong + results. +
  • +
  • + The functions that are conditionally compiled + if STD_INSPIRED is nonzero should, at this point, be + looked on primarily as food for thought. + They are not in any sense "standard compatible" – some are + not, in fact, specified in any standard. + They do, however, represent responses of various authors to + standardization proposals. +
  • +
  • + Other time conversion proposals, in particular those supported by the + Time Zone + Database Parser, offer a wider selection of functions + that provide capabilities beyond those provided here. + The absence of such functions from this package is not meant to + discourage the development, standardization, or use of such + functions. + Rather, their absence reflects the decision to make this package + contain valid extensions to POSIX, to ensure its broad + acceptability. + If more powerful time conversion functions can be standardized, so + much the better. +
  • +
+
+ +
+

Interface stability

+

+The tz code and data supply the following interfaces: +

+ +
    +
  • + A set of timezone names as per + "Timezone identifiers" above. +
  • +
  • + Library functions described in "Time and date + functions" above. +
  • +
  • + The programs tzselect, zdump, + and zic, documented in their man pages. +
  • +
  • + The format of zic input files, documented in + the zic man page. +
  • +
  • + The format of zic output files, documented in + the tzfile man page. +
  • +
  • + The format of zone table files, documented in zone1970.tab. +
  • +
  • + The format of the country code file, documented in iso3166.tab. +
  • +
  • + The version number of the code and data, as the first line of + the text file 'version' in each release. +
  • +
+ +

+Interface changes in a release attempt to preserve compatibility with +recent releases. +For example, tz data files typically do not +rely on recently added zic features, so that users can +run older zic versions to process newer data files. +Downloading +the tz database describes how releases +are tagged and distributed. +

+ +

+Interfaces not listed above are less stable. +For example, users should not rely on particular UT +offsets or abbreviations for timestamps, as data entries are often +based on guesswork and these guesses may be corrected or improved. +

+ +

+Timezone boundaries are not part of the stable interface. +For example, even though the Asia/Bangkok timezone +currently includes Chang Mai, Hanoi, and Phnom Penh, this is not part +of the stable interface and the timezone can split at any time. +If a calendar application records a future event in some location other +than Bangkok by putting "Asia/Bangkok" in the event's record, +the application should be robust in the presence of timezone splits +between now and the future time. +

+
+ +
+

Leap seconds

+

+Leap seconds were introduced in 1972 to accommodate the +difference between atomic time and the less regular rotation of the earth. +Unfortunately they caused so many problems with civil +timekeeping that they +are planned +to be discontinued by 2035, with some as-yet-undetermined +mechanism replacing them, perhaps after the year 2135. +Despite their impending obsolescence, a record of leap seconds is still +needed to resolve timestamps from 1972 through 2035. +

+ +

+The tz code and data can account for leap seconds, +thanks to code contributed by Bradley White. +However, the leap second support of this package is rarely used directly +because POSIX requires leap seconds to be excluded and many +software packages would mishandle leap seconds if they were present. +Instead, leap seconds are more commonly handled by occasionally adjusting +the operating system kernel clock as described in +Precision timekeeping, +and this package by default installs a leapseconds file +commonly used by +NTP +software that adjusts the kernel clock. +However, kernel-clock twiddling approximates UTC only roughly, +and systems needing more precise UTC can use this package's leap +second support directly. +

+ +

+The directly supported mechanism assumes that time_t +counts of seconds since the POSIX epoch normally include leap seconds, +as opposed to POSIX time_t counts which exclude leap seconds. +This modified timescale is converted to UTC +at the same point that time zone and DST +adjustments are applied – +namely, at calls to localtime and analogous functions – +and the process is driven by leap second information +stored in alternate versions of the TZif files. +Because a leap second adjustment may be needed even +if no time zone correction is desired, +calls to gmtime-like functions +also need to consult a TZif file, +conventionally named Etc/UTC +(GMT in previous versions), +to see whether leap second corrections are needed. +To convert an application's time_t timestamps to or from +POSIX time_t timestamps (for use when, say, +embedding or interpreting timestamps in portable +tar +files), +the application can call the utility functions +time2posix and posix2time +included with this package. +

+ +

+If the POSIX-compatible TZif file set is installed +in a directory whose basename is zoneinfo, the +leap-second-aware file set is by default installed in a separate +directory zoneinfo-leaps. +Although each process can have its own time zone by setting +its TZ environment variable, there is no support for some +processes being leap-second aware while other processes are +POSIX-compatible; the leap-second choice is system-wide. +So if you configure your kernel to count leap seconds, you should also +discard zoneinfo and rename zoneinfo-leaps +to zoneinfo. +Alternatively, you can install just one set of TZif files +in the first place; see the REDO variable in this package's +makefile. +

+
+ +
+

Calendrical issues

+

+Calendrical issues are a bit out of scope for a time zone database, +but they indicate the sort of problems that we would run into if we +extended the time zone database further into the past. +An excellent resource in this area is Edward M. Reingold +and Nachum Dershowitz, Calendrical +Calculations: The Ultimate Edition, Cambridge University Press (2018). +Other information and sources are given in the file 'calendars' +in the tz distribution. +They sometimes disagree. +

+
+ +
+

Time and time zones off Earth

+

+The European Space Agency is considering +the establishment of a reference timescale for the Moon, which has +days roughly equivalent to 29.5 Earth days, and where relativistic +effects cause clocks to tick slightly faster than on Earth. +

+ +

+Some people's work schedules have used +Mars time. +Jet Propulsion Laboratory (JPL) coordinators kept Mars time on +and off during the +Mars +Pathfinder mission (1997). +Some of their family members also adapted to Mars time. +Dozens of special Mars watches were built for JPL workers who kept +Mars time during the +Mars +Exploration Rovers (MER) mission (2004–2018). +These timepieces looked like normal Seikos and Citizens but were adjusted +to use Mars seconds rather than terrestrial seconds, although +unfortunately the adjusted watches were unreliable and appear to have +had only limited use. +

+ +

+A Mars solar day is called a "sol" and has a mean period equal to +about 24 hours 39 minutes 35.244 seconds in terrestrial time. +It is divided into a conventional 24-hour clock, so each Mars second +equals about 1.02749125 terrestrial seconds. +(One MER worker noted, "If I am working Mars hours, and Mars hours are +2.5% more than Earth hours, shouldn't I get an extra 2.5% pay raise?") +

+ +

+The prime +meridian of Mars goes through the center of the crater +Airy-0, named in +honor of the British astronomer who built the Greenwich telescope that +defines Earth's prime meridian. +Mean solar time on the Mars prime meridian is +called Mars Coordinated Time (MTC). +

+ +

+Each landed mission on Mars has adopted a different reference for +solar timekeeping, so there is no real standard for Mars time zones. +For example, the MER mission defined two time zones "Local +Solar Time A" and "Local Solar Time B" for its two missions, each zone +designed so that its time equals local true solar time at +approximately the middle of the nominal mission. +The A and B zones differ enough so that an MER worker assigned to +the A zone might suffer "Mars lag" when switching to work in the B zone. +Such a "time zone" is not particularly suited for any application +other than the mission itself. +

+ +

+Many calendars have been proposed for Mars, but none have achieved +wide acceptance. +Astronomers often use Mars Sol Date (MSD) which is a +sequential count of Mars solar days elapsed since about 1873-12-29 +12:00 GMT. +

+ +

+In our solar system, Mars is the planet with time and calendar most +like Earth's. +On other planets, Sun-based time and calendars would work quite +differently. +For example, although Mercury's +sidereal +rotation period is 58.646 Earth days, Mercury revolves around the +Sun so rapidly that an observer on Mercury's equator would see a +sunrise only every 175.97 Earth days, i.e., a Mercury year is 0.5 of a +Mercury day. +Venus is more complicated, partly because its rotation is slightly +retrograde: +its year is 1.92 of its days. +Gas giants like Jupiter are trickier still, as their polar and +equatorial regions rotate at different rates, so that the length of a +day depends on latitude. +This effect is most pronounced on Neptune, where the day is about 12 +hours at the poles and 18 hours at the equator. +

+ +

+Although the tz database does not support +time on other planets, it is documented here in the hopes that support +will be added eventually. +

+ +

+Sources for time on other planets: +

+ + +
+ +
+
+ This file is in the public domain, so clarified as of 2009-05-17 by + Arthur David Olson. +
+ + diff --git a/vendor/chrono-tz/tz/time2posix.3 b/vendor/chrono-tz/tz/time2posix.3 new file mode 100644 index 0000000000000..6644060ad76da --- /dev/null +++ b/vendor/chrono-tz/tz/time2posix.3 @@ -0,0 +1,133 @@ +.\" This file is in the public domain, so clarified as of +.\" 1996-06-05 by Arthur David Olson. +.TH time2posix 3 "" "Time Zone Database" +.SH NAME +time2posix, posix2time \- convert seconds since the Epoch +.SH SYNOPSIS +.nf +.ie \n(.g .ds - \f(CR-\fP +.el .ds - \- +.B #include +.PP +.B time_t time2posix(time_t t); +.PP +.B time_t posix2time(time_t t); +.PP +.B cc ... \*-ltz +.fi +.SH DESCRIPTION +.ie '\(en'' .ds en \- +.el .ds en \(en +.ie '\(lq'' .ds lq \&"\" +.el .ds lq \(lq\" +.ie '\(rq'' .ds rq \&"\" +.el .ds rq \(rq\" +.de q +\\$3\*(lq\\$1\*(rq\\$2 +.. +IEEE Standard 1003.1 +(POSIX) +requires the time_t value 536457599 to stand for 1986-12-31 23:59:59 UTC. +This effectively implies that POSIX time_t values cannot include leap +seconds and, +therefore, +that the system time must be adjusted as each leap occurs. +.PP +If the time package is configured with leap-second support +enabled, +however, +no such adjustment is needed and +time_t values continue to increase over leap events +(as a true +.q "seconds since...\&" +value). +This means that these values will differ from those required by POSIX +by the net number of leap seconds inserted since the Epoch. +.PP +Typically this is not a problem as the type time_t is intended +to be +(mostly) +opaque \*(en time_t values should only be obtained-from and +passed-to functions such as +.BR time(2) , +.BR localtime(3) , +.BR mktime(3) , +and +.BR difftime(3) . +However, +POSIX gives an arithmetic +expression for directly computing a time_t value from a given date/time, +and the same relationship is assumed by some +(usually older) +applications. +Any programs creating/dissecting time_t values +using such a relationship will typically not handle intervals +over leap seconds correctly. +.PP +The +.B time2posix +and +.B posix2time +functions are provided to address this time_t mismatch by converting +between local time_t values and their POSIX equivalents. +This is done by accounting for the number of time-base changes that +would have taken place on a POSIX system as leap seconds were inserted +or deleted. +These converted values can then be used in lieu of correcting the older +applications, +or when communicating with POSIX-compliant systems. +.PP +The +.B time2posix +function +is single-valued. +That is, +every local time_t +corresponds to a single POSIX time_t. +The +.B posix2time +function +is less well-behaved: +for a positive leap second hit the result is not unique, +and for a negative leap second hit the corresponding +POSIX time_t doesn't exist so an adjacent value is returned. +Both of these are good indicators of the inferiority of the +POSIX representation. +.PP +The following table summarizes the relationship between a time +T and its conversion to, +and back from, +the POSIX representation over the leap second inserted at the end of June, +1993. +.nf +.ta \w'93/06/30\0'u +\w'23:59:59\0'u +\w'A+0\0'u +\w'X=time2posix(T)\0'u +DATE TIME T X=time2posix(T) posix2time(X) +93/06/30 23:59:59 A+0 B+0 A+0 +93/06/30 23:59:60 A+1 B+1 A+1 or A+2 +93/07/01 00:00:00 A+2 B+1 A+1 or A+2 +93/07/01 00:00:01 A+3 B+2 A+3 + +A leap second deletion would look like... + +DATE TIME T X=time2posix(T) posix2time(X) +??/06/30 23:59:58 A+0 B+0 A+0 +??/07/01 00:00:00 A+1 B+2 A+1 +??/07/01 00:00:01 A+2 B+3 A+2 +.sp +.ce + [Note: posix2time(B+1) => A+0 or A+1] +.fi +.PP +If leap-second support is not enabled, +local time_t and +POSIX time_t values are equivalent, +and both +.B time2posix +and +.B posix2time +degenerate to the identity function. +.SH SEE ALSO +difftime(3), +localtime(3), +mktime(3), +time(2) diff --git a/vendor/chrono-tz/tz/tz-art.html b/vendor/chrono-tz/tz/tz-art.html new file mode 100644 index 0000000000000..3ee1eb2447314 --- /dev/null +++ b/vendor/chrono-tz/tz/tz-art.html @@ -0,0 +1,600 @@ + + + + +Time and the Arts + + +

Time and the Arts

+

Documentaries

+ +

Movies

+
    +
  • +In the 1946 movie A Matter of Life and Death +(U.S. title Stairway to Heaven) +there is a reference to British Double Summer Time. +The time does not play a large part in the plot; +it's just a passing reference to the time when one of the +characters was supposed to have died (but didn't). +(IMDb entry.) +(Dave Cantor) +
  • +The 1953 railway comedy movie The Titfield Thunderbolt includes a +play on words on British Double Summer Time. Valentine's wife wants +him to leave the pub and asks him, "Do you know what time it is?" +And he, happy where he is, replies: "Yes, my love. Summer double time." +(IMDb entry.) +(Mark Brader, 2009-10-02) +
  • +
  • +The premise of the 1999 caper movie Entrapment involves computers +in an international banking network being shut down briefly at +midnight in each time zone to avoid any problems at the transition +from the year 1999 to 2000 in that zone. (Hmmmm.) If this shutdown +is extended by 10 seconds, it will create a one-time opportunity for +a gigantic computerized theft. To achieve this, at one location the +crooks interfere with the microwave system supplying time signals to +the computer, advancing the time by 0.1 second each minute over the +last hour of 1999. (So this movie teaches us that 0.1 × 60 = 10.) +(IMDb entry.) +(Mark Brader, 2009-10-02) +
  • +
  • +One mustn't forget the +trailer +(2014; 2:23) for the movie Daylight Saving. +
  • +
+

TV episodes

+
    +
  • +An episode of The Adventures of Superman entitled "The Mysterious +Cube," first aired 1958-02-24, had Superman convincing the controllers +of the Arlington Time Signal to broadcast ahead of actual time; +doing so got a crook trying to be declared dead to +emerge a bit too early from the titular enclosure. +(IMDb entry.) +
  • +
  • +"The Chimes +of Big Ben", The Prisoner, episode 2, ITC, 1967-10-06. +Our protagonist tumbles to +the fraudulent nature of a Poland-to-England escape upon hearing "Big +Ben" chiming on Polish local time. +(IMDb entry.) +
  • +
  • +"The Susie", Seinfeld, season 8, episode 15, NBC, 1997-02-13. +Kramer decides that daylight saving time +isn't coming fast enough, so he sets his watch ahead an hour. +
  • +
  • +"20 Hours in America", The West Wing, season 4, episodes 1–2, +2002-09-25, contained a scene that +saw White House staffers stranded in Indiana; they thought they had time to +catch Air Force One but were done in by intra-Indiana local time changes. +
  • +
  • +"In what time zone would you find New York City?" was a $200 question on +the 1999-11-13 United States airing of Who Wants to Be a Millionaire?, +and "In 1883, what industry led the movement to divide the U.S. into four time +zones?" was a $32,000 question on the 2001-05-23 United States airing of +the same show. At this rate, the million-dollar time-zone +question should have been asked 2002-06-04. +
  • +
  • +A private jet's mid-flight change of time zones distorts Alison Dubois' +premonition in the "We Had a Dream" episode of Medium +(originally aired 2007-02-28). +
  • +
  • +A criminal's failure to account for the start of daylight saving is pivotal +in "Mr. Monk +and the Rapper" (first aired 2007-07-20). +
  • +
  • +In the 30 Rock episode "Anna Howard Shaw Day" +(first broadcast 2010-02-11), +Jack Donaghy's date realizes that a Geneva-to-New-York business phone call +received in the evening must be fake given the difference in local times. +
  • +
  • +In the "Run by the Monkeys" episode of Da Vinci's Inquest +(first broadcast 2002-11-17), +a witness in a five-year-old fire case realizes they may not have set +their clock back when daylight saving ended on the day of the fire, +introducing the possibility of an hour when arson might have occurred. +
  • +
  • +In "The Todd Couple" episode of Outsourced (first aired 2011-02-10), +Manmeet sets up Valentine's Day teledates for 6:00 and 9:00pm; +since one is with a New Yorker and the other with a San Franciscan, +hilarity ensues. +(Never mind that this should be 7:30am in Mumbai, yet for some reason the show +proceeds as though it's also mid-evening there.) +
  • +
  • +In the "14 Days to Go"/"T Minus..." episode of +You, Me and the Apocalypse +(first aired 2015-11-11 in the UK, 2016-03-10 in the US), +the success of a mission to deal with a comet +hinges on whether or not Russia observes daylight saving time. +(In the US, +the episode first aired in the week before the switch to DST.) +
  • +
  • +"The Lost Hour", Eerie, Indiana, episode 10, NBC, 1991-12-01. +Despite Indiana's then-lack of DST, +Marshall changes his clock with unusual consequences. +See "Eerie, +Indiana was a few dimensions ahead of its time". +
  • +
  • +"Time Tunnel", The Adventures of Pete & Pete, season 2, episode 5, +Nickelodeon, 1994-10-23. +The two Petes travel back in time an hour +on the day that DST ends. +
  • +
  • +"King-Size Homer", The Simpsons, episode 135, Fox, 1995-11-05. +Homer, working from home, remarks "8:58, first +time I've ever been early for work. Except for all those daylight +savings days. Lousy farmers." +
  • +
  • +Last Week Tonight with John Oliver, season 2, episode 5, 2015-03-08, +asked, "Daylight Saving +Time – How Is This Still A Thing?" +
  • +
  • +"Tracks", The Good Wife, season 7, episode 12, +CBS, 2016-01-17. +The applicability of a contract hinges on the +time zone associated with a video timestamp. +
  • +
  • +"Justice", Veep, season 6, episode 4, HBO, 2017-05-07. +Jonah's inability to understand DST ends up impressing a wealthy +backer who sets him up for a 2020 presidential run. +
  • +
+

Books, plays, and magazines

+
    +
  • +Jules Verne, Around the World in Eighty Days +(Le tour du monde en quatre-vingts jours), 1873. +Wall-clock time plays a central role in the plot. +European readers of the 1870s clearly held the U.S. press in +deep contempt; the protagonists cross the U.S. without once +reading a paper. +Available versions include +an English +translation, and +the original French +"with illustrations from the original 1873 French-language edition". +
  • +
  • +Nick Enright, Daylight Saving, 1989. +A fast-paced comedy about love and loneliness as the clocks turn back. +
  • +
  • +Umberto Eco, +The +Island of the Day Before +(L'isola del giorno prima), 1994. +"...the story of a 17th century Italian nobleman trapped near an island +on the International Date Line. Time and time zones play an integral +part in the novel." (Paul Eggert, 2006-04-22) +
  • +
  • +John Dunning, Two +O'Clock, Eastern Wartime, 2001. +Mystery, history, daylight saving time, and old-time radio. +
  • +
  • +Surrealist artist Guy Billout's work "Date Line" appeared on page 103 +of the 1999-11 Atlantic Monthly. +
  • +
  • +"Gloom, Gloom, Go Away" by Walter Kirn appeared on page 106 of Time +magazine's 2002-11-11 issue; among other things, it proposed +year-round DST as a way of lessening wintertime despair. +
  • +
+

Music

+
    +
  • +Recordings of "Save That Time," Russ Long, Serrob Publishing, BMI: +
      +
    • +Karrin Allyson, I Didn't Know About You (1993), track 11, 3:44. +Concord Jazz CCD-4543. +Karrin Allyson, vocal; +Russ Long, piano; +Gerald Spaits, bass; +Todd Strait, drums. +CD notes "additional lyric by Karrin Allyson; +arranged by Russ Long and Karrin Allyson". +ADO ★, +AMG +★★★★, Penguin ★★★⯪. +
    • +
    • +Kevin Mahogany, Double Rainbow (1993), track 3, 6:27. Enja ENJ-7097 2. +Kevin Mahogany, vocal; +Kenny Barron, piano; +Ray Drummond, bass; +Ralph Moore, tenor saxophone; +Lewis Nash, drums. +ADO ★⯪, +AMG +★★★, Penguin ★★★. +
    • +
    • +Joe Williams, Here's to Life (1994), track 7, 3:58. +Telarc Jazz CD-83357. +Joe Williams, vocal; The Robert Farnon [39 piece] Orchestra. +Also in a 3-CD package "Triple Play", Telarc CD-83461. +ADO •, +AMG +★★, Penguin ★★★. +
    • +
    • +Charles Fambrough, Keeper of the Spirit (1995), track 7, 7:07. +AudioQuest AQ-CD1033. +Charles Fambrough, bass; +Joel Levine, tenor recorder; +Edward Simon, piano; +Lenny White, drums; +Marion Simon, percussion. +ADO ★, +AMG +unrated, Penguin ★★★. +
    +
  • +
  • +Holly Cole Trio, Blame It On My Youth (1992). Manhattan CDP 7 97349 2, 37:45. +Holly Cole, voice; +Aaron Davis, piano; +David Piltch, string bass. +Lyrical reference to "Eastern Standard Time" in +Tom Waits's "Purple Avenue". +ADO ★★⯪, +AMG +★★★, Penguin unrated. +
  • +
  • +Milt Hinton, +Old +Man Time (1990). +Chiaroscuro CR(D) 310, 149:38 (two CDs). +Milt Hinton, bass; +Doc Cheatham, Dizzy Gillespie, Clark Terry, trumpet; +Al Grey, trombone; +Eddie Barefield, Joe Camel (Flip Phillips), Buddy Tate, +clarinet and saxophone; +John Bunch, Red Richards, Norman Simmons, Derek Smith, +Ralph Sutton, piano; +Danny Barker, Al Casey, guitar; +Gus Johnson, Gerryck King, Bob Rosengarden, Jackie Williams, +drums; +Lionel Hampton, vibraphone; +Cab Calloway, Joe Williams, vocal; +Buck Clayton, arrangements. +Tunes include "Old Man Time", "Time After Time", +"Sometimes I'm Happy", +"A Hot Time in the Old Town Tonight", +"Four or Five Times", "Now's the Time", +"Time on My Hands", "This Time It's Us", +and "Good Time Charlie". +ADO ★★★, +AMG +★★★★⯪, Penguin ★★★. +
  • +
  • +Alan Broadbent, Pacific Standard Time (1995). +Concord Jazz CCD-4664, 62:42. +Alan Broadbent, piano; +Putter Smith, Bass; +Frank Gibson, Jr., drums. +The CD cover features an analemma for equation-of-time fans. +ADO ★, +AMG +★★★★, Penguin ★★★⯪. +
  • +
  • +Anthony Braxton/Richard Teitelbaum, Silence/Time Zones (1996). +Black Lion BLCD 760221, 72:58. +Anthony Braxton, sopranino and alto saxophones, +contrebasse clarinet, miscellaneous instruments; +Leo Smith, trumpet and miscellaneous instruments; +Leroy Jenkins, violin and miscellaneous instruments; +Richard Teitelbaum, modular moog and micromoog synthesizer. +ADO •, +AMG +★★★★. +
  • +
  • +Charles Gayle, Time Zones (2006). Tompkins Square TSQ2839, 49:06. +Charles Gayle, piano. +ADO ★, +AMG +★★★★⯪. +
  • +
  • +The Get Up Kids, Eudora (2001). Vagrant 357, 65:12. +Includes the song "Central Standard Time." +Thanks to Colin Bowern for this information. +AMG +★★⯪. +
  • +
  • +Coldplay, "Clocks" (2003). +Capitol 52608, 4:13. +Won the 2004 Record of the Year honor at the +Grammy Awards. Co-written and performed by Chris Martin, +great-great-grandson of DST inventor William Willett. +The song's first line is "Lights go out and I can't be saved". +
  • +
  • +Jaime Guevara, "Qué +hora es" (1993), 3:04. +The song protested "Sixto Hour" in Ecuador +(1992–3). Its lyrics include "Amanecía en mitad de la noche, los +guaguas iban a clase sin sol" ("It was dawning in the middle of the +night, the buses went to class without sun"). +
  • +
  • +Irving Kahal and Harry Richman, +"There Ought to be a Moonlight Saving Time" (1931). +This musical standard was a No. 1 hit for Guy Lombardo +in 1931, and was also performed by Maurice Chevalier, Blossom Dearie +and many others. The phrase "Moonlight saving time" also appears in +the 1995 country song "Not Enough Hours in the Night" written by Aaron +Barker, Kim Williams and Rob Harbin and performed by Doug +Supernaw. +
  • +
  • +The Microscopic Septet, Lobster Leaps In (2008). +Cuneiform 272, 73:05. +Includes the song "Twilight Time Zone." +ADO ★★, +AMG +★★★⯪. +
  • +
  • +Bob Dylan, The Times They Are a-Changin' (1964). +Columbia CK-8905, 45:36. +ADO ★⯪, +AMG +★★★★⯪. +The title song is also available on "Bob Dylan's Greatest Hits" and "The Essential Bob Dylan." +
  • +
  • +Luciana Souza, Tide (2009). Universal Jazz France B0012688-02, 42:31. +ADO ★★⯪, +AMG +★★★⯪. +Includes the song "Fire and Wood" with the lyric +"The clocks were turned back you remember/Think it's still November." +
  • +
  • +Ken Nordine, You're Getting Better: The Word Jazz Dot Masters (2005). +Geffen B0005171-02, 156:22. +ADO ★, +AMG +★★★★⯪. +Includes the piece "What Time Is It" +("He knew what time it was everywhere...that counted"). +
  • +
  • +Chicago, Chicago Transit Authority (1969). Columbia 64409, 1:16:20. +AMG ★★★★. +Includes the song "Does Anybody Really Know What Time It Is?". +
  • +
  • +Emanuele Arciuli, +The Time Curve Preludes (2023). +Neuma 174, 44:46. +The title piece, composed by +William +Duckworth, is the first work of postminimal music. +Unlike minimalism, it does not assume that the listener has plenty of time. +
  • +
+

Comics

+ +

Jokes

+
    +
  • +The idea behind daylight saving time was first proposed as a joke by +Benjamin Franklin. To enforce it, he suggested, "Every +morning, as soon as the sun rises, let all the bells in every church +be set ringing; and if that is not sufficient, let cannon be fired in +every street, to wake the sluggards effectually, and make them open +their eyes to see their true interest. All the difficulty will be in +the first two or three days: after which the reformation will be as +natural and easy as the present irregularity; for, ce n'est que le +premier pas qui coûte." +Franklin's +joke was first published on 1784-04-26 by the +Journal de Paris as an +anonymous letter translated into French. +
  • +
  • +"We've been using the five-cent nickel in this country since 1492. +Now that's pretty near 100 years, daylight saving." +(Groucho Marx as Captain Spaulding in Animal Crackers, 1930, +as noted by Will Fitzgerald) +
  • +
  • +BRADY. ...[Bishop Usher] determined that the Lord began the Creation +on the 23rd of October in the Year 4,004 B.C. at – uh, 9 A.M.! +
    +DRUMMOND. That Eastern Standard Time? (Laughter.) Or Rocky Mountain +Time? (More laughter.) It wasn't daylight-saving time, was it? Because +the Lord didn't make the sun until the fourth day! +
    +(From the play Inherit the Wind by Jerome Lawrence and Robert E. Lee, +filmed in 1960 with Spencer Tracy as Drummond and Fredric March as +Brady, and several other times. Thanks to Mark Brader.) +
  • +
  • +"Good news." +"What did they do? Extend Daylight Saving Time year round?" +(Professional tanner George Hamilton, in dialog from a +May, 1999 episode of the syndicated television series Baywatch) +
  • +
  • +"A fundamental belief held by Americans is that if you are on land, you +cannot be killed by a fish...So most Americans remain on land, believing +they're safe. Unfortunately, this belief – like so many myths, such as that +there's a reason for 'Daylight Saving Time' – is false." +(Dave Barry column, 2000-07-02) +
  • +
  • +"I once had sex for an hour and five minutes, but that was on the day +when you turn the clocks ahead." +(Garry Shandling, 52nd Annual Emmys, 2000-09-10) +
  • +
  • +"Would it impress you if I told you I invented Daylight Savings Time?" +("Sahjhan" to "Lilah" in dialog from the "Loyalty" episode of Angel, +originally aired 2002-02-25) +
  • +
  • +"I thought you said Tulsa was a three-hour flight." +"Well, you're forgetting about the time difference." +("Joey" and "Chandler" in dialog from the episode of Friends +entitled "The One With Rachel's Phone Number," originally aired 2002-12-05) +
  • +
  • +"Is that a pertinent fact, +or are you just trying to dazzle me with your command of time zones?" +(Kelsey Grammer as "Frasier Crane" to "Roz" from the episode of Frasier +entitled "The Kid," originally aired 1997-11-04) +
  • +
  • +"I put myself and my staff through this crazy, huge ordeal, all because +I refused to go on at midnight, okay? And so I work, you know, and +then I get this job at eleven, supposed to be a big deal. Then +yesterday daylight [saving] time ended. Right now it's basically +midnight." (Conan O'Brien on the 2010-11-08 premiere of Conan) +
  • +
  • +"The best method, I told folks, was to hang a large clock high on a +barn wall where all the cows could see it. If you have Holsteins, you +will need to use an analog clock." (Jerry Nelson, How +to adjust dairy cows to daylight saving time", Successful Farming, +2017-10-09) +
  • +
  • +"And now, driving to California, I find that I must enter a password +in order to change the time zone on my laptop clock. Evidently, +someone is out to mess up my schedule and my clock must be secured." +(Garrison Keillor, +"We've +never been here before", 2017-08-22) +
  • +
  • +"Well, in my time zone that's all the time I have, +but maybe in your time zone I haven't finished yet. So stay tuned!" +(Goldie Hawn, Rowan & Martin's Laugh-In No. 65, 1970-03-09) +
  • +
+

See also

+ +
+
+This web page is in the public domain, so clarified as of +2009-05-17 by Arthur David Olson. +
+Please send corrections to this web page to the +time zone mailing list. +
+ + diff --git a/vendor/chrono-tz/tz/tz-how-to.html b/vendor/chrono-tz/tz/tz-how-to.html new file mode 100644 index 0000000000000..9e438f93092a6 --- /dev/null +++ b/vendor/chrono-tz/tz/tz-how-to.html @@ -0,0 +1,719 @@ + + + +How to Read the tz Database + + + + +

How to Read the tz +Database Source Files

+

by Bill Seymour

+

This guide uses the America/Chicago and +Pacific/Honolulu zones as examples of how to infer +times of day from the tz database +source files. It might be helpful, but not absolutely necessary, +for the reader to have already downloaded the +latest release of the database and become familiar with the basic layout +of the data files. The format is explained in the “man +page” for the zic compiler, zic.8.txt, in +the code subdirectory. +Although this guide covers many of the common cases, it is not a +complete summary of what zic accepts; the man page is the +authoritative reference.

+ +

We’ll begin by talking about the rules for changing between standard +and daylight saving time since we’ll need that information when we talk +about the zones.

+ +

First, let’s consider the special daylight saving time rules +for Chicago (from the northamerica file in +the data subdirectory):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
From the Source File
+ +
+
+#Rule NAME    FROM TO    -   IN  ON      AT   SAVE LETTER
+Rule  Chicago 1920 only  -   Jun 13      2:00 1:00 D
+Rule  Chicago 1920 1921  -   Oct lastSun 2:00 0    S
+Rule  Chicago 1921 only  -   Mar lastSun 2:00 1:00 D
+Rule  Chicago 1922 1966  -   Apr lastSun 2:00 1:00 D
+Rule  Chicago 1922 1954  -   Sep lastSun 2:00 0    S
+Rule  Chicago 1955 1966  -   Oct lastSun 2:00 0    S
+
+
Reformatted a Bit
FromToOnAtAction
1920 onlyJune 13th02:00 localgo to daylight saving time
19201921last Sundayin Octoberreturn to standard time
1921 onlyin Marchgo to daylight saving time
19221966in April
1954in Septemberreturn to standard time
19551966in October
+ +

The FROM and TO columns, respectively, specify the +first and last calendar years defining a contiguous range over which a specific +Rule line is to apply. The keyword only can be used in the +TO field to repeat the value of the FROM field in the +event that a rule should only apply to a single year. Often, the keyword +max is used to extend a rule’s application into the +indefinite future; it is a platform-agnostic stand-in for the largest +representable year. + +

The next column, -, is reserved; for compatibility with earlier +releases, it always contains a hyphen, which acts as a kind of null value. +Prior to the 2020b release, it was called the TYPE field, though +it had not been used in the main data since the 2000e release. +An obsolescent supplementary file used the +field as a proof-of-concept to allow zic to apply a given Rule +line only to certain “types” of years within the specified range as +dictated by the output of a separate script, such as: only years which would +have a US presidential election, or only years which wouldn’t. + +

The SAVE column contains the local (wall clock) offset from +local standard time. +This is usually either zero for standard time or one hour for daylight +saving time; but there’s no reason, in principle, why it can’t +take on other values. + +

The LETTER (sometimes called LETTER/S) +column can contain a variable +part of the usual abbreviation of the time zone’s name, or it can just +be a hyphen if there’s no variable part. For example, the abbreviation +used in the central time zone will be either “CST” or +“CDT”. The variable part is ‘S’ or ‘D’; +and, sure enough, that’s just what we find in +the LETTER column +in the Chicago rules. More about this when we talk about +“Zone” lines. + +

One important thing to notice is that “Rule” lines +want at once to be both transitions and steady states: +

    +
  • On the one hand, they represent transitions between standard and +daylight saving time; and any number of Rule lines can be in effect +during a given period (which will always be a non-empty set of +contiguous calendar years).
  • +
  • On the other hand, the SAVE and LETTER +columns contain state that exists between transitions. More about this +when we talk about the US rules.
  • +
+ +

In the example above, the transition to daylight saving time +happened on the 13th of June in 1920, and on +the last Sunday in March in 1921; but the return to standard time +happened on the last Sunday in October in both of those +years. Similarly, the rule for changing to daylight saving time was +the same from 1922 to 1966; but the rule for returning to standard +time changed in 1955. Got it?

+ +

OK, now for the somewhat more interesting “US” rules:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
From the Source File
+ +
+
+#Rule NAME FROM TO    -   IN  ON        AT   SAVE LETTER/S
+Rule  US   1918 1919  -   Mar lastSun  2:00  1:00 D
+Rule  US   1918 1919  -   Oct lastSun  2:00  0    S
+Rule  US   1942 only  -   Feb 9        2:00  1:00 W # War
+Rule  US   1945 only  -   Aug 14      23:00u 1:00 P # Peace
+Rule  US   1945 only  -   Sep 30       2:00  0    S
+Rule  US   1967 2006  -   Oct lastSun  2:00  0    S
+Rule  US   1967 1973  -   Apr lastSun  2:00  1:00 D
+Rule  US   1974 only  -   Jan 6        2:00  1:00 D
+Rule  US   1975 only  -   Feb 23       2:00  1:00 D
+Rule  US   1976 1986  -   Apr lastSun  2:00  1:00 D
+Rule  US   1987 2006  -   Apr Sun>=1   2:00  1:00 D
+Rule  US   2007 max   -   Mar Sun>=8   2:00  1:00 D
+Rule  US   2007 max   -   Nov Sun>=1   2:00  0    S
+
+
Reformatted a Bit
FromToOnAtAction
19181919last Sundayin March02:00 localgo to daylight saving time
in Octoberreturn to standard time
1942 onlyFebruary 9thgo to “war time”
1945 onlyAugust 14th23:00 UT + rename “war time” to “peace
time;” + clocks don’t change +
September 30th02:00 localreturn to standard time
19672006last Sundayin October
1973in Aprilgo to daylight saving time
1974 onlyJanuary 6th
1975 onlyFebruary 23rd
19761986last Sundayin April
19872006first Sunday
2007presentsecond Sunday in March
first Sunday in Novemberreturn to standard time
+ +

There are two interesting things to note here.

+ +

First, the time that something happens (in the AT +column) is not necessarily the local (wall clock) time. The time can be +suffixed with ‘s’ (for “standard”) to mean +local standard time, different from local (wall clock) time when observing +daylight saving time; or it can be suffixed with ‘g’, +‘u’, or ‘z’, all three of which mean the +standard time at the +prime meridian. +‘g’ stands for “GMT”; +‘u’ stands for “UT” or “UTC” +(whichever was official at the time); ‘z’ stands for the +nautical time zone +Z (a.k.a. “Zulu” which, in turn, stands for ‘Z’). +The time can also be suffixed with ‘w’ meaning local (wall +clock) time; but it usually isn’t because that’s the +default.

+ +

Second, the day in the ON column, in addition to +“lastSun” or a particular day of the month, +can have the form, “Sun>=x” or +“Sun<=x,” where x is a day +of the month. For example, “Sun>=8” means +“the first Sunday on or after the eighth of the month,” in +other words, the second Sunday of the month. Furthermore, although +there are no examples above, the weekday needn’t be +“Sun” in either form, but can be the usual +three-character English abbreviation for any day of the week.

+ +

And the US rules give us more examples of a couple of things +already mentioned:

+ +
    +
  • The rules for changing to and from daylight saving time are +actually different sets of rules; and the two sets can change +independently. Consider, for example, that the rule for the return to +standard time stayed the same from 1967 to 2006; but the rule for the +transition to daylight saving time changed several times in the same +period. There can also be periods, 1946 to 1966 for example, when no +rule from this group is in effect, and so either no transition +happened in those years, or some other rule is in effect (perhaps a +state or other more local rule).
  • + +
  • The SAVE and LETTER columns +contain steady state, not transitions. Consider, for example, +the transition from “war time” to “peace time” +that happened on August 14, 1945. The “1:00” in +the SAVE column is not an instruction to advance +the clock an hour. It means that clocks should be one hour +ahead of standard time, which they already are because of the previous +rule, so there should be no change.
  • + +
+ +

OK, now let’s look at a Zone record:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
From the Source File
+ +
+
+#Zone       NAME      STDOFF   RULES FORMAT [UNTIL]
+Zone  America/Chicago -5:50:36 -       LMT  1883 Nov 18 12:09:24
+                      -6:00    US      C%sT 1920
+                      -6:00    Chicago C%sT 1936 Mar  1  2:00
+                      -5:00    -       EST  1936 Nov 15  2:00
+                      -6:00    Chicago C%sT 1942
+                      -6:00    US      C%sT 1946
+                      -6:00    Chicago C%sT 1967
+                      -6:00    US      C%sT
+
+
Columns Renamed
Standard Offset
+ from Prime + Meridian
Daylight
Saving Time
Abbreviation(s)Ending at Local Time
DateTime
−5:50:36not observedLMT1883-11-1812:09:24
−6:00:00US rulesCST or CDT1920-01-0100:00:00
Chicago rules1936-03-0102:00:00
−5:00:00not observedEST1936-11-15
−6:00:00Chicago rulesCST or CDT1942-01-0100:00:00
US rulesCST, CWT or CPT1946-01-01
Chicago rulesCST or CDT1967-01-01
US rules
+ +

There are a couple of interesting differences between Zones and Rules.

+ +

First, and somewhat trivially, whereas Rules are considered to +contain one or more records, a Zone is considered to be a single +record with zero or more continuation lines. Thus, the keyword, +“Zone,” and the zone name are not +repeated. The last line is the one without anything in +the [UNTIL] column.

+ +

Second, and more fundamentally, each line of a Zone represents a +steady state, not a transition between states. The state exists from +the date and time in the previous line’s [UNTIL] +column up to the date and time in the current +line’s [UNTIL] column. In other words, the date and +time in the [UNTIL] column is the instant that separates +this state from the next. Where that would be ambiguous because +we’re setting our clocks back, the [UNTIL] column +specifies the first occurrence of the instant. The state specified by +the last line, the one without anything in the [UNTIL] +column, continues to the present.

+ +

The first line typically specifies the mean solar time observed +before the introduction of standard time. Since there’s no line before +that, it has no beginning. 8-) For some places near the International +Date Line, the first two lines will show solar times +differing by 24 hours; this corresponds to a movement of the Date +Line. For example:

+ +
+#Zone NAME          STDOFF   RULES FORMAT [UNTIL]
+Zone America/Juneau 15:02:19 -     LMT    1867 Oct 18
+                    -8:57:41 -     LMT    ...
+
+ +

When Alaska was purchased from Russia in 1867, the Date Line moved +from the Alaska/Canada border to the Bering Strait; and the time in +Alaska was then 24 hours earlier than it had +been. <aside>(6 October in the Julian calendar, +which Russia was still using then for religious reasons, was followed +by a second instance of the same day with a different name, 18 +October in the Gregorian calendar. Isn’t civil time +wonderful? 8-))</aside>

+ +

The abbreviation, “LMT” stands for “local mean +time”, which is an invention of +the tz +database and was probably never actually used during the +period. Furthermore, the value is almost certainly wrong except in the +archetypal place after which the zone is named. (The tz database +usually doesn’t provide a separate Zone record for places where +nothing significant happened after 1970.)

+ +

The RULES column tells us whether daylight saving time is being observed: +

    +
  • A hyphen, a kind of null value, means that we have not set our +clocks ahead of standard time.
  • + +
  • An amount of time (usually but not necessarily “1:00” +meaning one hour) means that we have set our clocks ahead by that +amount.
  • + +
  • Some alphabetic string means that we might have set our +clocks ahead; and we need to check the rule the name of which is the +given alphabetic string.
  • +
+ +

An example of a specific amount of time is:

+
+#Zone NAME            STDOFF RULES FORMAT [UNTIL]
+Zone Pacific/Honolulu ...                 1933 Apr 30  2:00
+                      -10:30 1:00  HDT    1933 May 21 12:00
+                      ...
+
+ +

Hawaii tried daylight saving time for three weeks in 1933 and +decided they didn’t like it. 8-) Note that +the STDOFF column always contains the standard time +offset, so the local (wall clock) time during this period was GMT − +10:30 + 1:00 = GMT − 9:30.

+ +

The FORMAT column specifies the usual abbreviation of +the time zone name. It should have one of four forms:

+
    + +
  • a time zone abbreviation that is a string of three or more +characters that are either ASCII alphanumerics, +“+”, or “-
  • + +
  • the string “%z”, in which case the +“%z” will be replaced by a numeric time zone +abbreviation
  • + +
  • a pair of time zone abbreviations separated by a slash +(‘/’), in which case the first string is the +abbreviation for the standard time name and the second string is the +abbreviation for the daylight saving time name
  • + +
  • a string containing “%s”, in which case +the “%s” will be replaced by the text in the +appropriate Rule’s LETTER column, and the resulting +string should be a time zone abbreviation
  • +
+ +

The last two make sense only if there’s a named rule in effect.

+ +

An example of a slash is:

+
+#Zone NAME          STDOFF RULES FORMAT  [UNTIL]
+Zone  Europe/London ...                  1996
+                    0:00   EU    GMT/BST
+
+ +

The current time in the UK is called either Greenwich mean time or +British summer time.

+ +

One wrinkle, not fully explained in zic.8.txt, is what +happens when switching to a named rule. To what values should +the SAVE and LETTER data be initialized?

+ +
    +
  • If at least one transition has happened, use +the SAVE and LETTER data from the most +recent.
  • + +
  • If switching to a named rule before any transition has happened, +assume standard time (SAVE zero), and use +the LETTER data from the earliest transition with +a SAVE of zero. + +
+ +

And three last things about the FORMAT column:

+
    + +
  • The tz +database gives abbreviations for time zones +in popular English-language usage. For +example, the last line in +Zone Pacific/Honolulu (shown below) gives +“HST” for “Hawaii standard time” even though the +legal +name for that time zone is “Hawaii-Aleutian standard time.” +This author has read that there are also some places in Australia where +popular time zone names differ from the legal ones. + +
  • No attempt is made to localize +the abbreviations. They are intended to be the values returned through the +"%Z" format specifier to +C’s +strftime +function in the +“C” locale. + +
  • If there is no generally accepted abbreviation for a time zone, +a numeric offset is used instead, e.g., +07 for 7 hours +ahead of Greenwich. By convention, -00 is used in a +zone while uninhabited, where the offset is zero but in some sense +the true offset is undefined. +
+ +

As a final example, here’s the complete history for Hawaii:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Relevant Excerpts from the US Rules
+ +
+
+#Rule NAME FROM TO   -    IN  ON      AT     SAVE LETTER/S
+Rule  US   1918 1919 -    Oct lastSun  2:00  0    S
+Rule  US   1942 only -    Feb  9       2:00  1:00 W # War
+Rule  US   1945 only -    Aug 14      23:00u 1:00 P # Peace
+Rule  US   1945 only -    Sep lastSun  2:00  0    S
+
+
The Zone Record
+ +
+
+#Zone NAME            STDOFF    RULES FORMAT [UNTIL]
+Zone Pacific/Honolulu -10:31:26 -     LMT    1896 Jan 13 12:00
+                      -10:30    -     HST    1933 Apr 30  2:00
+                      -10:30    1:00  HDT    1933 May 21  2:00
+                      -10:30    US    H%sT   1947 Jun  8  2:00
+                      -10:00    -     HST
+
+
What We Infer
Wall-Clock
Offset from
Prime Meridian
Adjust
Clocks
Time ZoneEnding at Local Time
Abbrv.NameDateTime
−10:31:26LMTlocal mean time1896-01-1312:00
−10:30+0:01:26HSTHawaii standard time1933-04-3002:00
−9:30+1:00HDTHawaii daylight time1933-05-2112:00
−10:30¹−1:00¹HST¹Hawaii standard time1942-02-0902:00
−9:30+1:00HWTHawaii war time1945-08-1413:30²
0HPTHawaii peace time1945-09-3002:00
−10:30−1:00HSTHawaii standard time1947-06-08
−10:00³+0:30³
+ ¹Switching to US rules…most recent transition (in 1919) was to standard time +
+ ²23:00 UT + + (−9:30) = 13:30 local +
+ ³Since 1947–06–08T12:30Z, + the civil time in Hawaii has been + UT/UTC + − 10:00 year-round. +
+ +

There will be a short quiz later. 8-)

+ +
+
+This web page is in the public domain, so clarified as of +2015-10-20 by Bill Seymour. +
+All suggestions and corrections will be welcome; all flames will be amusing. +Mail to was at pobox dot com. +
+ + diff --git a/vendor/chrono-tz/tz/tz-link.html b/vendor/chrono-tz/tz/tz-link.html new file mode 100644 index 0000000000000..9fb57c9058a93 --- /dev/null +++ b/vendor/chrono-tz/tz/tz-link.html @@ -0,0 +1,1212 @@ + + + +Time zone and daylight saving time data + + + + +

Time zone and daylight saving time data

+

+Time zone and +daylight-saving +rules are controlled by individual +governments. They are sometimes changed with little notice, and their +histories and planned futures are often recorded only fitfully. Here +is a summary of attempts to organize and record relevant data in this +area. +

+

Outline

+ + +
+

The tz database

+

+The public-domain +time zone database contains code and data +that represent the history of local time +for many representative locations around the globe. +It is updated periodically to reflect changes made by political bodies +to time zone boundaries and daylight saving rules. +This database (known as tz, +tzdb, or zoneinfo) +is used by several implementations, +including +the +GNU +C Library (used in +GNU/Linux), +Android, +FreeBSD, +NetBSD, +OpenBSD, +Chromium OS, +Cygwin, +MariaDB, +MINIX, +MySQL, +webOS, +AIX, +iOS, +macOS, +Microsoft Windows, +OpenVMS, +Oracle Database, and +Oracle Solaris.

+

+Each main entry in the database represents a timezone +for a set of civil-time clocks that have all agreed since 1970. +Timezones are typically identified by continent or ocean and then by the +name of the largest city within the region containing the clocks. +For example, America/New_York +represents most of the US eastern time zone; +America/Phoenix represents most of Arizona, which +uses mountain time without daylight saving time (DST); +America/Detroit represents most of Michigan, which uses +eastern time but with different DST rules in 1975; +and other entries represent smaller regions like Starke County, +Indiana, which switched from central to eastern time in 1991 +and switched back in 2006. +To use the database on an extended POSIX.1-2017 +implementation set the TZ +environment variable to the location's full name, +e.g., TZ="America/New_York".

+

+Associated with each timezone is a history of offsets from +Universal +Time (UT), which is Greenwich Mean +Time (GMT) with days beginning at midnight; +for timestamps after 1960 this is more precisely Coordinated +Universal Time (UTC). +The database also records when daylight saving time was in use, +along with some time zone abbreviations such as EST +for Eastern Standard Time in the US.

+
+ +
+

Downloading the tz database

+

+The following shell commands download +the latest release's two +tarballs +to a GNU/Linux or similar host.

+
mkdir tzdb
+cd tzdb
+wget https://www.iana.org/time-zones/repository/tzcode-latest.tar.gz
+wget https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz
+gzip -dc tzcode-latest.tar.gz | tar -xf -
+gzip -dc tzdata-latest.tar.gz | tar -xf -
+
+

Alternatively, the following shell commands download the same +release in a single-tarball format containing extra data +useful for regression testing:

+
wget https://www.iana.org/time-zones/repository/tzdb-latest.tar.lz
+lzip -dc tzdb-latest.tar.lz | tar -xf -
+
+

These commands use convenience links to the latest release +of the tz database hosted by the +Time Zone Database website +of the Internet Assigned Numbers +Authority (IANA). +Older releases are in files named +tzcodeV.tar.gz, +tzdataV.tar.gz, and +tzdb-V.tar.lz, +where V is the version. +Since 1996, each version has been a four-digit year followed by +lower-case letter (a through z, +then za through zz, then zza +through zzz, and so on). +Since version 2022a, each release has been distributed in +POSIX +ustar interchange format, compressed as described above; +older releases use a nearly compatible format. +Since version 2016h, each release has contained a text file named +"version" whose first (and currently only) line is the version. +Older releases are archived, +and are also available in an +FTP directory via a +less secure protocol.

+

Alternatively, a development repository of code and data can be +retrieved from GitHub via the shell +command:

+
git clone https://github.com/eggert/tz
+
+

+Since version 2012e, each release has been tagged in development repositories. +Untagged commits are less well tested and probably contain +more errors.

+

+After obtaining the code and data files, see the +README file for what to do next. +The code lets you compile the tz source files into +machine-readable binary files, one for each location. The binary files +are in a special timezone information format (TZif) +specified by Internet +RFC 8536. +The code also lets +you read a TZif file and interpret timestamps for that +location.

+
+ +
+

Changes to the tz database

+

+The tz code and data +are by no means authoritative. If you find errors, please +send changes to tz@iana.org, +the time zone mailing list. You can also subscribe to it +and browse the archive of old +messages. +Metadata for mailing list +discussions and corresponding data changes can be +generated automatically. +

+

+Changes to the tz code and data are often +propagated to clients via operating system updates, so +client tz data can often be corrected by +applying these updates. With GNU/Linux and similar systems, if your +maintenance provider has not yet adopted the +latest tz data, you can often short-circuit +the process by tailoring the generic instructions in +the tz README file and installing the latest +data yourself. System-specific instructions for installing the +latest tz data have also been published +for AIX, +Android, +ICU, +IBM +JDK, +Joda-Time, MySQL, +Noda Time, and OpenJDK/Oracle JDK. +

+

Since version 2013a, +sources for the tz database have been +UTF-8 +text files +with lines terminated by LF, +which can be modified by common text editors such +as GNU Emacs, +gedit, and +vim. +Specialized source-file editing can be done via the +Sublime +zoneinfo package for Sublime Text and the VSCode +zoneinfo extension for Visual +Studio Code. +

+

+For further information about updates, please see +Procedures for +Maintaining the Time Zone Database (Internet RFC 6557). More detail can be +found in Theory and pragmatics of the +tz code and data. +A0 TimeZone Migration +displays changes between recent tzdb versions. +

+
+ +
+

Coordinating with governments and distributors

+

+As discussed in +"How +Time Zones Are Coordinated", the time zone database relies on +collaboration among governments, the time zone database volunteer +community, and data distributors downstream. +

+If your government plans to change its time zone boundaries or +daylight saving rules, please send email to tz@iana.org well in advance, +as this will lessen confusion and will coordinate updates to many cell phones, +computers, and other devices around the world. +In your email, please cite the legislation or regulation that specifies +the change, so that it can be checked for details such as the exact times +when clock transitions occur. +It is OK if a rule change is planned to affect clocks +far into the future, as a long-planned change can easily be reverted +or otherwise altered with a year's notice before the change would have +affected clocks.

+

+There is no fixed schedule for tzdb releases. +However, typically a release occurs every few months. +Many downstream timezone data distributors wait for +a tzdb release before they produce an update +to time zone behavior in consumer devices and software products. +After a release, various parties must integrate, test, +and roll out an update before end users see changes. +These updates can be expensive, for both the quality +assurance process and the overall cost of shipping and installing +updates to each device's copy of tzdb. +Updates may be batched with other updates and may take substantial +time to reach end users after a release. +Older devices may no longer be supported and thus may never be updated, +which means they will continue to use out-of-date rules.

+

+For these reasons any rule change should be promulgated at least a +year before it affects how clocks operate; otherwise, there is a good +chance that many clocks will be wrong due to delays in propagating updates, +and that residents will be confused or even actively resist the change. +The shorter the notice, the more likely clock problems will arise; see "On +the Timing of Time Zone Changes" for examples. +

+
+ +
+

Commentary on the tz database

+ +
+ +
+

Web sites using recent versions of the +tz database

+

+These are listed roughly in ascending order of complexity and fanciness. +

+ +
+ +
+

Network protocols for tz data

+ +
+ +
+

Other tz compilers

+

Although some of these do not fully support +tz data, in recent tzdb +distributions you can generally work around compatibility problems by +running the command make rearguard_tarballs and compiling +from the resulting tarballs instead.

+ +
+ +
+

Other TZif readers

+
    +
  • The GNU C +Library +has an independent, thread-safe implementation of +a TZif file reader. +This library is freely available under the LGPL +and is widely used in GNU/Linux systems.
  • +
  • GNOME's +GLib has +a TZif file reader written in C that +creates a GTimeZone object representing sets +of UT offsets. +It is freely available under the LGPL.
  • +
  • The +BDE Standard Library's +baltzo::TimeZoneUtil component contains a C++ +implementation of a TZif file reader. It is freely available under +the Apache License.
  • +
  • CCTZ is a simple C++ +library that translates between UT and civil time and +can read TZif files. It is freely available under the Apache +License.
  • +
  • The +posix_tz_db +package contains Python code +to generate CSV and JSON tables that map +tz settings to POSIX.1-2017-like approximations. +For example, it maps "Africa/Cairo" +to "EET-2EEST,M4.5.5/0,M10.5.4/24", +an approximation valid for Cairo timestamps from 2023 on. +This can help porting to platforms that support only POSIX.1-2017. +The package is freely available under the MIT license.
  • +
  • Timelib is a C +library that reads TZif files and converts +timestamps from one time zone or format to another. +It is used by PHP, +HHVM, +and MongoDB. +It is freely available under the MIT license.
  • +
  • Tcl, mentioned above, also contains a +TZif file reader.
  • +
  • +DateTime::TimeZone::Tzfile +is a TZif file reader written in Perl. +It is freely available under the same terms as Perl +(dual GPL and Artistic license).
  • +
  • Python has a zoneinfo.ZoneInfo +class that reads TZif data and creates objects +that represent tzdb timezones. +Python is freely available under the +Python Software Foundation +License. +A companion PyPI module +tzdata +supplies TZif data if the underlying system data cannot be found; +it is freely available under the Apache License.
  • +
  • The +public-domain tz.js +library contains a Python tool that +converts TZif data into +JSON-format data suitable for use +in its JavaScript library for time zone conversion. Dates before 1970 +are not supported.
  • +
  • The timezone-olson +package contains Haskell code that +parses and uses TZif data. It is freely +available under a BSD-style license.
  • +
+
+ +
+

Other tz-based time zone software

+ +
+ +
+

Other time zone databases

+ +
+ +
+

Maps

+ +
+ +
+

Time zone boundaries

+

Geographical boundaries between timezones are available +from several Internet +geolocation +services and other sources.

+ +
+ +
+

Civil time concepts and history

+ +
+ +
+

National histories of legal time

+
+
Australia
+
The Parliamentary Library commissioned a research +paper on daylight saving time in Australia. +The Bureau of Meteorology publishes a list of Implementation +Dates of Daylight Savings Time within Australia.
+
Belgium
+
The Royal Observatory of Belgium maintains a table of time in +Belgium (in +Dutch and French).
+
Brazil
+
The Time Service Department of the National Observatory +records Brazil's daylight saving time decrees (in +Portuguese).
+
Canada
+
National Research Council Canada publishes current +and some older information about time +zones and daylight saving time.
+
Chile
+
The Hydrographic and Oceanographic Service of the Chilean Navy publishes a +history of +Chile's official time (in Spanish).
+
China
+
The Hong Kong Observatory maintains a +history of + summer time in Hong Kong, +and Macau's Meteorological and Geophysical Bureau maintains a similar +history for Macau. +Unfortunately the latter is incomplete and has errors.
+
Czech Republic
+
When daylight saving time starts and ends (in Czech) +summarizes and cites historical DST regulations.
+
Germany
+
The National Institute for Science and Technology maintains the Realisation +of Legal Time in Germany.
+
Israel
+
The Interior Ministry periodically issues announcements (in Hebrew).
+
Malaysia
+
See Singapore below.
+
Mexico
+
The Investigation and Analysis Service of the Mexican Library of +Congress has published a history of Mexican local time (in Spanish).
+
Netherlands
+
Legal time in the Netherlands (in Dutch) +covers the history of local time in the Netherlands from ancient times.
+
New Zealand
+
The Department of Internal Affairs maintains a brief History of +Daylight Saving.
+
Palestine
+
The Ministry of Telecom and IT publishes a history of clock changes (in Arabic).
+
Portugal
+
The Lisbon Astronomical Observatory publishes a +history of +legal time (in Portuguese).
+
Singapore
+
Why +is Singapore in the "Wrong" Time Zone? details the +history of legal time in Singapore and Malaysia.
+
United Kingdom
+
History of +legal time in Britain discusses in detail the country +with perhaps the best-documented history of clock adjustments.
+
United States
+
The Department of Transportation's Recent +Time Zone Proceedings lists changes to time zone boundaries.
+
Uruguay
+
The Oceanography, Hydrography, and Meteorology Service of the Uruguayan +Navy (SOHMA) publishes an annual almanac +(in Spanish).
+
+
+ +
+

Costs and benefits of time shifts

+

Various sources argue for and against daylight saving time and time +zone shifts, and many scientific studies have been conducted. This +section summarizes reviews and position statements based on +scientific literature in the area.

+ +
+ +
+

Precision timekeeping

+
    +
  • The +Science of Timekeeping is a thorough introduction +to the theory and practice of precision timekeeping.
  • +
  • The Science of +Time 2016 contains several freely readable papers.
  • +
  • NTP: The Network +Time Protocol (Internet RFC 5905) +discusses how to synchronize clocks of +Internet hosts.
  • +
  • The Huygens +family of software algorithms can achieve accuracy to a few tens of +nanoseconds in scalable server farms without special hardware.
  • +
  • The Precision +Time Protocol (IEEE 1588) +can achieve submicrosecond clock accuracy on a local area network +with special-purpose hardware.
  • +
  • Timezone +Options for DHCP +(Internet RFC 4833) +specifies a DHCP +option for a server to configure +a client's time zone and daylight saving settings automatically.
  • +
  • Time +Scales describes astronomical time scales like +TDT, +TCG, and +TDB. +
  • The IAU's SOFA +collection contains C and Fortran +code for converting among time scales like +TAI, +TDB, TDT and +UTC. It is freely available under the +SOFA license.
  • +
  • Mars24 Sunclock +– Time on Mars describes Airy Mean Time (AMT) and the +diverse local time +scales used by each landed mission on Mars.
  • +
  • LeapSecond.com is +dedicated not only to leap seconds but to precise time and frequency +in general. It covers the state of the art in amateur timekeeping, and +how the art has progressed over the past few decades.
  • +
  • The rules for leap seconds are specified in Annex 1 (Time scales) of Standard-frequency +and time-signal emissions, International Telecommunication Union – +Radiocommunication Sector (ITU-R) Recommendation TF.460-6 (02/2002).
  • +
  • IERS +Bulletins contains official publications of the International +Earth Rotation and Reference Systems Service, which decides when leap +seconds occur. The tz code and data support leap seconds +via an optional "right" configuration where a computer's internal +time_t integer clock counts every TAI second, +as opposed to the default "posix" configuration +where the internal clock ignores leap seconds. +The two configurations agree for timestamps starting with 1972-01-01 00:00:00 +UTC (time_t 63 072 000) and diverge for +timestamps starting with time_t 78 796 800, +which corresponds to the first leap second +1972-06-30 23:59:60 UTC in the "right" configuration, +and to +1972-07-01 00:00:00 UTC in the "posix" configuration. +In practice the two configurations also agree for timestamps before +1972 even though the historical situation is messy, partly because +neither UTC nor TAI +is well-defined for sufficiently old timestamps.
  • +
  • Leap Smear +discusses how to gradually adjust POSIX clocks near a +leap second so that they disagree with UTC by at most a +half second, even though every POSIX minute has exactly +sixty seconds. This approach works with the default tz +"posix" configuration, is supported by +the NTP reference implementation, supports conversion between +UTC and smeared POSIX timestamps, and is used by major +cloud service providers. However, according to +§3.7.1 of +Network Time Protocol Best Current Practices +(Internet RFC 8633), leap smearing is not suitable for +applications requiring accurate UTC or civil time, +and is intended for use only in single, well-controlled environments.
  • +
  • The Leap +Second Discussion List covers McCarthy +and Klepczynski's 1999 proposal to discontinue leap seconds, +discussed further in +The +leap second: its history and possible future. +UTC +might be redefined +without Leap Seconds gives pointers on this +contentious issue. +The General Conference on Weights and Measures +decided in 2022 +to discontinue the use of leap seconds by 2035, replacing them with an +as-yet-undetermined scheme some time after the year 2135. +The World Radiocommunication Conference resolved +in 2023 to cooperate with this process. +
  • +
+
+ +
+

Time notation

+
    +
  • The Unicode Common Locale Data +Repository (CLDR) Project has localizations for time +zone names, abbreviations, identifiers, and formats. For example, it +contains French translations for "Eastern European Summer Time", +"EEST", and +"Bucharest". Its +by-type +charts show these values for many locales. Data values are available in +both LDML +(an XML format) and JSON. +
  • +A summary of +the international standard date and time notation covers +ISO +8601-1:2019 – Date and time – Representations for information +interchange – Part 1: Basic rules.
  • +
  • +XML +Schema: Datatypes – dateTime specifies a format inspired by +ISO 8601 that is in common use in XML data.
  • +
  • §3.3 of +Internet Message Format (Internet RFC 5322) +specifies the time notation used in email and HTTP +headers.
  • +
  • +Date and Time +on the Internet: Timestamps (Internet RFC 3339) +specifies an ISO 8601 +profile for use in new Internet +protocols.
  • +
  • +Date & Time +Formats on the Web surveys web- and Internet-oriented date and time +formats.
  • +
  • Alphabetic time zone abbreviations should not be used as unique +identifiers for UT offsets as they are ambiguous in +practice. For example, in English-speaking North America +"CST" denotes 6 hours behind UT, +but in China it denotes 8 hours ahead of UT, +and French-speaking North Americans prefer +"HNC" to +"CST". The tz +database contains English abbreviations for many timestamps; +unfortunately some of these abbreviations were merely the database maintainers' +inventions, and these have been removed when possible.
  • +
  • Numeric time zone abbreviations typically count hours east of +UT, e.g., +09 for Japan and +−10 for Hawaii. However, the POSIX +TZ environment variable uses the opposite convention. +For example, one might use TZ="JST-9" and +TZ="HST10" +for Japan and Hawaii, respectively. If the +tz database is available, it is usually better to use +settings like TZ="Asia/Tokyo" and +TZ="Pacific/Honolulu" instead, as this should avoid +confusion, handle old timestamps better, and insulate you better from +any future changes to the rules. One should never set +POSIX TZ to a value like +"GMT-9", though, since this would incorrectly imply that +local time is nine hours ahead of UT and the time zone +is called "GMT".
  • +
+
+ +
+

See also

+ +
+ +
+
+This web page is in the public domain, so clarified as of +2009-05-17 by Arthur David Olson. +
+Please send corrections to this web page to the +time zone mailing list. +
+ + diff --git a/vendor/chrono-tz/tz/tzfile.5 b/vendor/chrono-tz/tz/tzfile.5 new file mode 100644 index 0000000000000..867348d6726d2 --- /dev/null +++ b/vendor/chrono-tz/tz/tzfile.5 @@ -0,0 +1,508 @@ +.\" This file is in the public domain, so clarified as of +.\" 1996-06-05 by Arthur David Olson. +.TH tzfile 5 "" "Time Zone Database" +.SH NAME +tzfile \- timezone information +.SH DESCRIPTION +.ie '\(lq'' .ds lq \&"\" +.el .ds lq \(lq\" +.ie '\(rq'' .ds rq \&"\" +.el .ds rq \(rq\" +.de q +\\$3\*(lq\\$1\*(rq\\$2 +.. +.ie \n(.g .ds - \f(CR-\fP +.el .ds - \- +The timezone information files used by +.BR tzset (3) +are typically found under a directory with a name like +.IR /usr/share/zoneinfo . +These files use the format described in Internet RFC 8536. +Each file is a sequence of 8-bit bytes. +In a file, a binary integer is represented by a sequence of one or +more bytes in network order (bigendian, or high-order byte first), +with all bits significant, +a signed binary integer is represented using two's complement, +and a boolean is represented by a one-byte binary integer that is +either 0 (false) or 1 (true). +The format begins with a 44-byte header containing the following fields: +.RS "\w' 'u" +.IP \(bu "\w'\(bu 'u" +The magic four-byte ASCII sequence +.q "TZif" +identifies the file as a timezone information file. +.IP \(bu +A byte identifying the version of the file's format +(as of 2021, either an ASCII NUL, +.q "2", +.q "3", +or +.q "4" ). +.IP \(bu +Fifteen bytes containing zeros reserved for future use. +.IP \(bu +Six four-byte integer values, in the following order: +.RS "\w' \(bu 'u" +.TP "\w' 'u" +.B tzh_ttisutcnt +The number of UT/local indicators stored in the file. +(UT is Universal Time.) +.TP +.B tzh_ttisstdcnt +The number of standard/wall indicators stored in the file. +.TP +.B tzh_leapcnt +The number of leap seconds for which data entries are stored in the file. +.TP +.B tzh_timecnt +The number of transition times for which data entries are stored +in the file. +.TP +.B tzh_typecnt +The number of local time types for which data entries are stored +in the file (must not be zero). +.TP +.B tzh_charcnt +The number of bytes of time zone abbreviation strings +stored in the file. +.RE +.PP +The above header is followed by the following fields, whose lengths +depend on the contents of the header: +.RS "\w' 'u" +.IP \(bu "\w'\(bu 'u" +.B tzh_timecnt +four-byte signed integer values sorted in ascending order. +These values are written in network byte order. +Each is used as a transition time (as returned by +.BR time (2)) +at which the rules for computing local time change. +.IP \(bu +.B tzh_timecnt +one-byte unsigned integer values; +each one but the last tells which of the different types of local time types +described in the file is associated with the time period +starting with the same-indexed transition time +and continuing up to but not including the next transition time. +(The last time type is present only for consistency checking with the +POSIX.1-2017-style TZ string described below.) +These values serve as indices into the next field. +.IP \(bu +.B tzh_typecnt +.B ttinfo +entries, each defined as follows: +.in +2 +.sp +.nf +.ta \w'\0\0\0\0'u +\w'unsigned char\0'u +struct ttinfo { + int32_t tt_utoff; + unsigned char tt_isdst; + unsigned char tt_desigidx; +}; +.in +.fi +.sp +Each structure is written as a four-byte signed integer value for +.BR tt_utoff , +in network byte order, followed by a one-byte boolean for +.B tt_isdst +and a one-byte value for +.BR tt_desigidx . +In each structure, +.B tt_utoff +gives the number of seconds to be added to UT, +.B tt_isdst +tells whether +.B tm_isdst +should be set by +.BR localtime (3) +and +.B tt_desigidx +serves as an index into the array of time zone abbreviation bytes +that follow the +.B ttinfo +entries in the file; if the designated string is "\*-00", the +.B ttinfo +entry is a placeholder indicating that local time is unspecified. +The +.B tt_utoff +value is never equal to \-2**31, to let 32-bit clients negate it without +overflow. +Also, in realistic applications +.B tt_utoff +is in the range [\-89999, 93599] (i.e., more than \-25 hours and less +than 26 hours); this allows easy support by implementations that +already support the POSIX-required range [\-24:59:59, 25:59:59]. +.RS "\w' 'u" +.IP \(bu "\w'\(bu 'u" +.B tzh_charcnt +bytes that represent time zone designations, +which are null-terminated byte strings, each indexed by the +.B tt_desigidx +values mentioned above. +The byte strings can overlap if one is a suffix of the other. +The encoding of these strings is not specified. +.IP \(bu +.B tzh_leapcnt +pairs of four-byte values, written in network byte order; +the first value of each pair gives the nonnegative time +(as returned by +.BR time (2)) +at which a leap second occurs or at which the leap second table expires; +the second is a signed integer specifying the correction, which is the +.I total +number of leap seconds to be applied during the time period +starting at the given time. +The pairs of values are sorted in strictly ascending order by time. +Each pair denotes one leap second, either positive or negative, +except that if the last pair has the same correction as the previous one, +the last pair denotes the leap second table's expiration time. +Each leap second is at the end of a UTC calendar month. +The first leap second has a nonnegative occurrence time, +and is a positive leap second if and only if its correction is positive; +the correction for each leap second after the first differs +from the previous leap second by either 1 for a positive leap second, +or \-1 for a negative leap second. +If the leap second table is empty, the leap-second correction is zero +for all timestamps; +otherwise, for timestamps before the first occurrence time, +the leap-second correction is zero if the first pair's correction is 1 or \-1, +and is unspecified otherwise (which can happen only in files +truncated at the start). +.IP \(bu +.B tzh_ttisstdcnt +standard/wall indicators, each stored as a one-byte boolean; +they tell whether the transition times associated with local time types +were specified as standard time or local (wall clock) time. +.IP \(bu +.B tzh_ttisutcnt +UT/local indicators, each stored as a one-byte boolean; +they tell whether the transition times associated with local time types +were specified as UT or local time. +If a UT/local indicator is set, the corresponding standard/wall indicator +must also be set. +.RE +.PP +The standard/wall and UT/local indicators were designed for +transforming a TZif file's transition times into transitions appropriate +for another time zone specified via +a POSIX.1-2017-style TZ string that lacks rules. +For example, when TZ="EET\*-2EEST" and there is no TZif file "EET\*-2EEST", +the idea was to adapt the transition times from a TZif file with the +well-known name "posixrules" that is present only for this purpose and +is a copy of the file "Europe/Brussels", a file with a different UT offset. +POSIX does not specify this obsolete transformational behavior, +the default rules are installation-dependent, and no implementation +is known to support this feature for timestamps past 2037, +so users desiring (say) Greek time should instead specify +TZ="Europe/Athens" for better historical coverage, falling back on +TZ="EET\*-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required +and older timestamps need not be handled accurately. +.PP +The +.BR localtime (3) +function +normally uses the first +.B ttinfo +structure in the file +if either +.B tzh_timecnt +is zero or the time argument is less than the first transition time recorded +in the file. +.SS Version 2 format +For version-2-format timezone files, +the above header and data are followed by a second header and data, +identical in format except that +eight bytes are used for each transition time or leap second time. +(Leap second counts remain four bytes.) +After the second header and data comes a newline-enclosed string +in the style of the contents of a POSIX.1-2017 TZ environment variable, +for use in handling instants +after the last transition time stored in the file +or for all instants if the file has no transitions. +The TZ string is empty (i.e., nothing between the newlines) +if there is no POSIX.1-2017-style representation for such instants. +If nonempty, the TZ string must agree with the local time +type after the last transition time if present in the eight-byte data; +for example, given the string +.q "WET0WEST,M3.5.0/1,M10.5.0" +then if a last transition time is in July, the transition's local time +type must specify a daylight-saving time abbreviated +.q "WEST" +that is one hour east of UT. +Also, if there is at least one transition, time type 0 is associated +with the time period from the indefinite past up to but not including +the earliest transition time. +.SS Version 3 format +For version-3-format timezone files, the TZ string may +use two minor extensions to the POSIX.1-2017 TZ format, as described in +.BR newtzset (3). +First, the hours part of its transition times may be signed and range from +\-167 through 167 instead of the POSIX-required unsigned values +from 0 through 24. +Second, DST is in effect all year if it starts +January 1 at 00:00 and ends December 31 at 24:00 plus the difference +between daylight saving and standard time. +.SS Version 4 format +For version-4-format TZif files, +the first leap second record can have a correction that is neither ++1 nor \-1, to represent truncation of the TZif file at the start. +Also, if two or more leap second transitions are present and the last +entry's correction equals the previous one, the last entry +denotes the expiration of the leap second table instead of a leap second; +timestamps after this expiration are unreliable in that future +releases will likely add leap second entries after the expiration, and +the added leap seconds will change how post-expiration timestamps are treated. +.SS Interoperability considerations +Future changes to the format may append more data. +.PP +Version 1 files are considered a legacy format and +should not be generated, as they do not support transition +times after the year 2038. +Readers that understand only Version 1 must ignore +any data that extends beyond the calculated end of the version +1 data block. +.PP +Other than version 1, writers should generate +the lowest version number needed by a file's data. +For example, a writer should generate a version 4 file +only if its leap second table either expires or is truncated at the start. +Likewise, a writer not generating a version 4 file +should generate a version 3 file only if +TZ string extensions are necessary to accurately +model transition times. +.PP +The sequence of time changes defined by the version 1 +header and data block should be a contiguous sub-sequence +of the time changes defined by the version 2+ header and data +block, and by the footer. +This guideline helps obsolescent version 1 readers +agree with current readers about timestamps within the +contiguous sub-sequence. It also lets writers not +supporting obsolescent readers use a +.B tzh_timecnt +of zero +in the version 1 data block to save space. +.PP +When a TZif file contains a leap second table expiration +time, TZif readers should either refuse to process +post-expiration timestamps, or process them as if the expiration +time did not exist (possibly with an error indication). +.PP +Time zone designations should consist of at least three (3) +and no more than six (6) ASCII characters from the set of +alphanumerics, +.q "\*-", +and +.q "+". +This is for compatibility with POSIX requirements for +time zone abbreviations. +.PP +When reading a version 2 or higher file, readers +should ignore the version 1 header and data block except for +the purpose of skipping over them. +.PP +Readers should calculate the total lengths of the +headers and data blocks and check that they all fit within +the actual file size, as part of a validity check for the file. +.PP +When a positive leap second occurs, readers should append an extra +second to the local minute containing the second just before the leap +second. If this occurs when the UTC offset is not a multiple of 60 +seconds, the leap second occurs earlier than the last second of the +local minute and the minute's remaining local seconds are numbered +through 60 instead of the usual 59; the UTC offset is unaffected. +.SS Common interoperability issues +This section documents common problems in reading or writing TZif files. +Most of these are problems in generating TZif files for use by +older readers. +The goals of this section are: +.RS "\w' 'u" +.IP \(bu "\w'\(bu 'u" +to help TZif writers output files that avoid common +pitfalls in older or buggy TZif readers, +.IP \(bu +to help TZif readers avoid common pitfalls when reading +files generated by future TZif writers, and +.IP \(bu +to help any future specification authors see what sort of +problems arise when the TZif format is changed. +.RE +.PP +When new versions of the TZif format have been defined, a +design goal has been that a reader can successfully use a TZif +file even if the file is of a later TZif version than what the +reader was designed for. +When complete compatibility was not achieved, an attempt was +made to limit glitches to rarely used timestamps and allow +simple partial workarounds in writers designed to generate +new-version data useful even for older-version readers. +This section attempts to document these compatibility issues and +workarounds, as well as to document other common bugs in +readers. +.PP +Interoperability problems with TZif include the following: +.RS "\w' 'u" +.IP \(bu "\w'\(bu 'u" +Some readers examine only version 1 data. +As a partial workaround, a writer can output as much version 1 +data as possible. +However, a reader should ignore version 1 data, and should use +version 2+ data even if the reader's native timestamps have only +32 bits. +.IP \(bu +Some readers designed for version 2 might mishandle +timestamps after a version 3 or higher file's last transition, because +they cannot parse extensions to POSIX.1-2017 in the TZ-like string. +As a partial workaround, a writer can output more transitions +than necessary, so that only far-future timestamps are +mishandled by version 2 readers. +.IP \(bu +Some readers designed for version 2 do not support +permanent daylight saving time with transitions after 24:00 +\(en e.g., a TZ string +.q "EST5EDT,0/0,J365/25" +denoting permanent Eastern Daylight Time +(\-04). +As a workaround, a writer can substitute standard time +for two time zones east, e.g., +.q "XXX3EDT4,0/0,J365/23" +for a time zone with a never-used standard time (XXX, \-03) +and negative daylight saving time (EDT, \-04) all year. +Alternatively, +as a partial workaround a writer can substitute standard time +for the next time zone east \(en e.g., +.q "AST4" +for permanent +Atlantic Standard Time (\-04). +.IP \(bu +Some readers designed for version 2 or 3, and that require strict +conformance to RFC 8536, reject version 4 files whose leap second +tables are truncated at the start or that end in expiration times. +.IP \(bu +Some readers ignore the footer, and instead predict future +timestamps from the time type of the last transition. +As a partial workaround, a writer can output more transitions +than necessary. +.IP \(bu +Some readers do not use time type 0 for timestamps before +the first transition, in that they infer a time type using a +heuristic that does not always select time type 0. +As a partial workaround, a writer can output a dummy (no-op) +first transition at an early time. +.IP \(bu +Some readers mishandle timestamps before the first +transition that has a timestamp not less than \-2**31. +Readers that support only 32-bit timestamps are likely to be +more prone to this problem, for example, when they process +64-bit transitions only some of which are representable in 32 +bits. +As a partial workaround, a writer can output a dummy +transition at timestamp \-2**31. +.IP \(bu +Some readers mishandle a transition if its timestamp has +the minimum possible signed 64-bit value. +Timestamps less than \-2**59 are not recommended. +.IP \(bu +Some readers mishandle TZ strings that +contain +.q "<" +or +.q ">". +As a partial workaround, a writer can avoid using +.q "<" +or +.q ">" +for time zone abbreviations containing only alphabetic +characters. +.IP \(bu +Many readers mishandle time zone abbreviations that contain +non-ASCII characters. +These characters are not recommended. +.IP \(bu +Some readers may mishandle time zone abbreviations that +contain fewer than 3 or more than 6 characters, or that +contain ASCII characters other than alphanumerics, +.q "\*-", +and +.q "+". +These abbreviations are not recommended. +.IP \(bu +Some readers mishandle TZif files that specify +daylight-saving time UT offsets that are less than the UT +offsets for the corresponding standard time. +These readers do not support locations like Ireland, which +uses the equivalent of the TZ string +.q "IST\*-1GMT0,M10.5.0,M3.5.0/1", +observing standard time +(IST, +01) in summer and daylight saving time (GMT, +00) in winter. +As a partial workaround, a writer can output data for the +equivalent of the TZ string +.q "GMT0IST,M3.5.0/1,M10.5.0", +thus swapping standard and daylight saving time. +Although this workaround misidentifies which part of the year +uses daylight saving time, it records UT offsets and time zone +abbreviations correctly. +.IP \(bu +Some readers generate ambiguous timestamps for positive leap seconds +that occur when the UTC offset is not a multiple of 60 seconds. +For example, in a timezone with UTC offset +01:23:45 and with +a positive leap second 78796801 (1972-06-30 23:59:60 UTC), some readers will +map both 78796800 and 78796801 to 01:23:45 local time the next day +instead of mapping the latter to 01:23:46, and they will map 78796815 to +01:23:59 instead of to 01:23:60. +This has not yet been a practical problem, since no civil authority +has observed such UTC offsets since leap seconds were +introduced in 1972. +.RE +.PP +Some interoperability problems are reader bugs that +are listed here mostly as warnings to developers of readers. +.RS "\w' 'u" +.IP \(bu "\w'\(bu 'u" +Some readers do not support negative timestamps. +Developers of distributed applications should keep this +in mind if they need to deal with pre-1970 data. +.IP \(bu +Some readers mishandle timestamps before the first +transition that has a nonnegative timestamp. +Readers that do not support negative timestamps are likely to +be more prone to this problem. +.IP \(bu +Some readers mishandle time zone abbreviations like +.q "\*-08" +that contain +.q "+", +.q "\*-", +or digits. +.IP \(bu +Some readers mishandle UT offsets that are out of the +traditional range of \-12 through +12 hours, and so do not +support locations like Kiritimati that are outside this +range. +.IP \(bu +Some readers mishandle UT offsets in the range [\-3599, \-1] +seconds from UT, because they integer-divide the offset by +3600 to get 0 and then display the hour part as +.q "+00". +.IP \(bu +Some readers mishandle UT offsets that are not a multiple +of one hour, or of 15 minutes, or of 1 minute. +.RE +.SH SEE ALSO +.BR time (2), +.BR localtime (3), +.BR tzset (3), +.BR tzselect (8), +.BR zdump (8), +.BR zic (8). +.PP +Olson A, Eggert P, Murchison K. The Time Zone Information Format (TZif). +2019 Feb. +.UR https://\:datatracker.ietf.org/\:doc/\:html/\:rfc8536 +Internet RFC 8536 +.UE +.UR https://\:doi.org/\:10.17487/\:RFC8536 +doi:10.17487/RFC8536 +.UE . diff --git a/vendor/chrono-tz/tz/tzfile.h b/vendor/chrono-tz/tz/tzfile.h new file mode 100644 index 0000000000000..3155010ed17f8 --- /dev/null +++ b/vendor/chrono-tz/tz/tzfile.h @@ -0,0 +1,119 @@ +/* Layout and location of TZif files. */ + +#ifndef TZFILE_H + +#define TZFILE_H + +/* +** This file is in the public domain, so clarified as of +** 1996-06-05 by Arthur David Olson. +*/ + +/* +** This header is for use ONLY with the time conversion code. +** There is no guarantee that it will remain unchanged, +** or that it will remain at all. +** Do NOT copy it to any system include directory. +** Thank you! +*/ + +/* +** Information about time zone files. +*/ + +#ifndef TZDEFRULES +# define TZDEFRULES "posixrules" +#endif /* !defined TZDEFRULES */ + + +/* See Internet RFC 8536 for more details about the following format. */ + +/* +** Each file begins with. . . +*/ + +#define TZ_MAGIC "TZif" + +struct tzhead { + char tzh_magic[4]; /* TZ_MAGIC */ + char tzh_version[1]; /* '\0' or '2'-'4' as of 2021 */ + char tzh_reserved[15]; /* reserved; must be zero */ + char tzh_ttisutcnt[4]; /* coded number of trans. time flags */ + char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ + char tzh_leapcnt[4]; /* coded number of leap seconds */ + char tzh_timecnt[4]; /* coded number of transition times */ + char tzh_typecnt[4]; /* coded number of local time types */ + char tzh_charcnt[4]; /* coded number of abbr. chars */ +}; + +/* +** . . .followed by. . . +** +** tzh_timecnt (char [4])s coded transition times a la time(2) +** tzh_timecnt (unsigned char)s types of local time starting at above +** tzh_typecnt repetitions of +** one (char [4]) coded UT offset in seconds +** one (unsigned char) used to set tm_isdst +** one (unsigned char) that's an abbreviation list index +** tzh_charcnt (char)s '\0'-terminated zone abbreviations +** tzh_leapcnt repetitions of +** one (char [4]) coded leap second transition times +** one (char [4]) total correction after above +** tzh_ttisstdcnt (char)s indexed by type; if 1, transition +** time is standard time, if 0, +** transition time is local (wall clock) +** time; if absent, transition times are +** assumed to be local time +** tzh_ttisutcnt (char)s indexed by type; if 1, transition +** time is UT, if 0, transition time is +** local time; if absent, transition +** times are assumed to be local time. +** When this is 1, the corresponding +** std/wall indicator must also be 1. +*/ + +/* +** If tzh_version is '2' or greater, the above is followed by a second instance +** of tzhead and a second instance of the data in which each coded transition +** time uses 8 rather than 4 chars, +** then a POSIX-TZ-environment-variable-style string for use in handling +** instants after the last transition time stored in the file +** (with nothing between the newlines if there is no POSIX.1-2017 +** representation for such instants). +** +** If tz_version is '3' or greater, the above is extended as follows. +** First, the TZ string's hour offset may range from -167 +** through 167 as compared to the POSIX-required 0 through 24. +** Second, its DST start time may be January 1 at 00:00 and its stop +** time December 31 at 24:00 plus the difference between DST and +** standard time, indicating DST all year. +*/ + +/* +** In the current implementation, "tzset()" refuses to deal with files that +** exceed any of the limits below. +*/ + +#ifndef TZ_MAX_TIMES +/* This must be at least 242 for Europe/London with 'zic -b fat'. */ +# define TZ_MAX_TIMES 2000 +#endif /* !defined TZ_MAX_TIMES */ + +#ifndef TZ_MAX_TYPES +/* This must be at least 18 for Europe/Vilnius with 'zic -b fat'. */ +# define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ +#endif /* !defined TZ_MAX_TYPES */ + +#ifndef TZ_MAX_CHARS +/* This must be at least 40 for America/Anchorage. */ +# define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ + /* (limited by what unsigned chars can hold) */ +#endif /* !defined TZ_MAX_CHARS */ + +#ifndef TZ_MAX_LEAPS +/* This must be at least 27 for leap seconds from 1972 through mid-2023. + There's a plan to discontinue leap seconds by 2035. */ +# define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ +#endif /* !defined TZ_MAX_LEAPS */ + +#endif /* !defined TZFILE_H */ diff --git a/vendor/chrono-tz/tz/tzselect.8 b/vendor/chrono-tz/tz/tzselect.8 new file mode 100644 index 0000000000000..ee031614f3ed8 --- /dev/null +++ b/vendor/chrono-tz/tz/tzselect.8 @@ -0,0 +1,125 @@ +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. +.TH tzselect 8 "" "Time Zone Database" +.SH NAME +tzselect \- select a timezone +.SH SYNOPSIS +.ie \n(.g .ds - \f(CR-\fP +.el .ds - \- +.ds d " degrees +.ds m " minutes +.ds s " seconds +.ds _ " \& +.if t \{\ +. if \n(.g .if c \(de .if c \(fm .if c \(sd \{\ +. ds d \(de +. ds m \(fm +. ds s \(sd +. ds _ \| +. \} +.\} +.B tzselect +[ +.B \*-c +.I coord +] [ +.B \*-n +.I limit +] [ +.B \*-\*-help +] [ +.B \*-\*-version +] +.SH DESCRIPTION +The +.B tzselect +program asks the user for information about the current location, +and outputs the resulting timezone to standard output. +The output is suitable as a value for the TZ environment variable. +.PP +All interaction with the user is done via standard input and standard error. +.SH OPTIONS +.TP +.BI "\*-c " coord +Instead of asking for continent and then country and then city, +ask for selection from time zones whose largest cities +are closest to the location with geographical coordinates +.I coord. +Use ISO 6709 notation for +.I coord, +that is, a latitude immediately followed by a longitude. The latitude +and longitude should be signed integers followed by an optional +decimal point and fraction: positive numbers represent north and east, +negative south and west. Latitudes with two and longitudes with three +integer digits are treated as degrees; latitudes with four or six and +longitudes with five or seven integer digits are treated as +.I "DDMM, DDDMM, DDMMSS," +or +.I DDDMMSS +representing +.I DD +or +.I DDD +degrees, +.I MM +minutes, +and zero or +.I SS +seconds, with any trailing fractions represent fractional minutes or +(if +.I SS +is present) seconds. The decimal point is that of the current locale. +For example, in the (default) C locale, +.B "\*-c\ +40.689\*-074.045" +specifies 40.689\*d\*_N, 74.045\*d\*_W, +.B "\*-c\ +4041.4\*-07402.7" +specifies 40\*d\*_41.4\*m\*_N, 74\*d\*_2.7\*m\*_W, and +.B "\*-c\ +404121\*-0740240" +specifies 40\*d\*_41\*m\*_21\*s\*_N, 74\*d\*_2\*m\*_40\*s\*_W. +If +.I coord +is not one of the documented forms, the resulting behavior is unspecified. +.TP +.BI "\*-n " limit +When +.B \*-c +is used, display the closest +.I limit +locations (default 10). +.TP +.B "\*-\*-help" +Output help information and exit. +.TP +.B "\*-\*-version" +Output version information and exit. +.SH "ENVIRONMENT VARIABLES" +.TP +\f3AWK\fP +Name of a POSIX-compliant +.B awk +program (default: +.BR awk ). +.TP +\f3TZDIR\fP +Name of the directory containing timezone data files (default: +.BR /usr/share/zoneinfo ). +.SH FILES +.TP +\f2TZDIR\fP\f3/iso3166.tab\fP +Table of ISO 3166 2-letter country codes and country names. +.TP +\f2TZDIR\fP\f3/zone1970.tab\fP +Table of country codes, latitude and longitude, timezones, and +descriptive comments. +.TP +\f2TZDIR\fP\f3/\fP\f2TZ\fP +Timezone data file for timezone \f2TZ\fP. +.SH "EXIT STATUS" +The exit status is zero if a timezone was successfully obtained from the user, +nonzero otherwise. +.SH "SEE ALSO" +newctime(3), tzfile(5), zdump(8), zic(8) +.SH NOTES +Applications should not assume that +.BR tzselect 's +output matches the user's political preferences. diff --git a/vendor/chrono-tz/tz/tzselect.ksh b/vendor/chrono-tz/tz/tzselect.ksh new file mode 100644 index 0000000000000..38941bbc55e7a --- /dev/null +++ b/vendor/chrono-tz/tz/tzselect.ksh @@ -0,0 +1,815 @@ +#!/bin/bash +# Ask the user about the time zone, and output the resulting TZ value to stdout. +# Interact with the user via stderr and stdin. + +PKGVERSION='(tzcode) ' +TZVERSION=see_Makefile +REPORT_BUGS_TO=tz@iana.org + +# Contributed by Paul Eggert. This file is in the public domain. + +# Porting notes: +# +# This script requires a POSIX-like shell and prefers the extension of a +# 'select' statement. The 'select' statement was introduced in the +# Korn shell and is available in Bash and other shell implementations. +# If your host lacks both Bash and the Korn shell, you can get their +# source from one of these locations: +# +# Bash +# Korn Shell +# MirBSD Korn Shell +# +# For portability to Solaris 10 /bin/sh (supported by Oracle through +# January 2027) this script avoids some POSIX features and common +# extensions, such as $(...), $((...)), ! CMD, unquoted ^, ${#ID}, +# ${ID##PAT}, ${ID%%PAT}, and $10. Although some of these constructs +# work sometimes, it's simpler to avoid them entirely. +# +# This script also uses several features of POSIX awk. +# If your host lacks awk, or has an old awk that does not conform to POSIX, +# you can use any of the following free programs instead: +# +# Gawk (GNU awk) +# mawk +# nawk +# +# Because 'awk "VAR=VALUE" ...' and 'awk -v "VAR=VALUE" ...' are not portable +# if VALUE contains \, ", or newline, awk scripts in this file use: +# awk 'BEGIN { VAR = substr(ARGV[1], 2); ARGV[1] = "" } ...' ="VALUE" +# The substr avoids problems when VALUE is of the form X=Y and would be +# misinterpreted as an assignment. + +# This script does not want path expansion. +set -f + +# Specify default values for environment variables if they are unset. +: ${AWK=awk} +: ${PWD=`pwd`} +: ${TZDIR=$PWD} + +# Output one argument as-is to standard output, with trailing newline. +# Safer than 'echo', which can mishandle '\' or leading '-'. +say() { + printf '%s\n' "$1" +} + +# Check for awk POSIX compliance. +($AWK -v x=y 'BEGIN { exit 123 }') <>/dev/null >&0 2>&0 +[ $? = 123 ] || { + say >&2 "$0: Sorry, your '$AWK' program is not POSIX compatible." + exit 1 +} + +coord= +location_limit=10 +zonetabtype=zone1970 + +usage="Usage: tzselect [--version] [--help] [-c COORD] [-n LIMIT] +Select a timezone interactively. + +Options: + + -c COORD + Instead of asking for continent and then country and then city, + ask for selection from time zones whose largest cities + are closest to the location with geographical coordinates COORD. + COORD should use ISO 6709 notation, for example, '-c +4852+00220' + for Paris (in degrees and minutes, North and East), or + '-c -35-058' for Buenos Aires (in degrees, South and West). + + -n LIMIT + Display at most LIMIT locations when -c is used (default $location_limit). + + --version + Output version information. + + --help + Output this help. + +Report bugs to $REPORT_BUGS_TO." + +# Ask the user to select from the function's arguments, +# and assign the selected argument to the variable 'select_result'. +# Exit on EOF or I/O error. Use the shell's nicer 'select' builtin if +# available, falling back on a portable substitute otherwise. +if + case $BASH_VERSION in + ?*) :;; + '') + # '; exit' should be redundant, but Dash doesn't properly fail without it. + (eval 'set --; select x; do break; done; exit') <>/dev/null 2>&0 + esac +then + # Do this inside 'eval', as otherwise the shell might exit when parsing it + # even though it is never executed. + eval ' + doselect() { + select select_result + do + case $select_result in + "") echo >&2 "Please enter a number in range.";; + ?*) break + esac + done || exit + } + ' +else + doselect() { + # Field width of the prompt numbers. + print_nargs_length="BEGIN {print length(\"$#\");}" + select_width=`$AWK "$print_nargs_length"` + + select_i= + + while : + do + case $select_i in + '') + select_i=0 + for select_word + do + select_i=`$AWK "BEGIN { print $select_i + 1 }"` + printf >&2 "%${select_width}d) %s\\n" $select_i "$select_word" + done;; + *[!0-9]*) + echo >&2 'Please enter a number in range.';; + *) + if test 1 -le $select_i && test $select_i -le $#; then + shift `$AWK "BEGIN { print $select_i - 1 }"` + select_result=$1 + break + fi + echo >&2 'Please enter a number in range.' + esac + + # Prompt and read input. + printf >&2 %s "${PS3-#? }" + read select_i || exit + done + } +fi + +while getopts c:n:t:-: opt +do + case $opt$OPTARG in + c*) + coord=$OPTARG;; + n*) + location_limit=$OPTARG;; + t*) # Undocumented option, used for developer testing. + zonetabtype=$OPTARG;; + -help) + exec echo "$usage";; + -version) + exec echo "tzselect $PKGVERSION$TZVERSION";; + -*) + say >&2 "$0: -$opt$OPTARG: unknown option; try '$0 --help'"; exit 1;; + *) + say >&2 "$0: try '$0 --help'"; exit 1 + esac +done + +shift `$AWK "BEGIN { print $OPTIND - 1 }"` +case $# in +0) ;; +*) say >&2 "$0: $1: unknown argument"; exit 1 +esac + +# translit=true to try transliteration. +# This is false if U+12345 CUNEIFORM SIGN URU TIMES KI has length 1 +# which means awk (and presumably the shell) do not need transliteration. +if $AWK 'BEGIN { u12345 = "\360\222\215\205"; exit length(u12345) == 1 }'; then + translit=true +else + translit=false +fi + +# Read into shell variable $1 the contents of file $2. +# Convert to the current locale's encoding if possible, +# as the shell aligns columns better that way. +# If GNU iconv's //TRANSLIT does not work, fall back on POSIXish iconv; +# if that does not work, fall back on 'cat'. +read_file() { + { $translit && { + eval "$1=\`(iconv -f UTF-8 -t //TRANSLIT) 2>/dev/null <\"\$2\"\`" || + eval "$1=\`(iconv -f UTF-8) 2>/dev/null <\"\$2\"\`" + }; } || + eval "$1=\`cat <\"\$2\"\`" || { + say >&2 "$0: time zone files are not set up correctly" + exit 1 + } +} +read_file TZ_COUNTRY_TABLE "$TZDIR/iso3166.tab" +read_file TZ_ZONETABTYPE_TABLE "$TZDIR/$zonetabtype.tab" +TZ_ZONENOW_TABLE= + +newline=' +' +IFS=$newline + +# Awk script to output a country list. +output_country_list=' + BEGIN { + continent_re = substr(ARGV[1], 2) + TZ_COUNTRY_TABLE = substr(ARGV[2], 2) + TZ_ZONE_TABLE = substr(ARGV[3], 2) + ARGV[1] = ARGV[2] = ARGV[3] = "" + FS = "\t" + nlines = split(TZ_ZONE_TABLE, line, /\n/) + for (iline = 1; iline <= nlines; iline++) { + $0 = line[iline] + commentary = $0 ~ /^#@/ + if (commentary) { + if ($0 !~ /^#@/) + continue + col1ccs = substr($1, 3) + conts = $2 + } else { + col1ccs = $1 + conts = $3 + } + ncc = split(col1ccs, cc, /,/) + ncont = split(conts, cont, /,/) + for (i = 1; i <= ncc; i++) { + elsewhere = commentary + for (ci = 1; ci <= ncont; ci++) { + if (cont[ci] ~ continent_re) { + if (!cc_seen[cc[i]]++) + cc_list[++ccs] = cc[i] + elsewhere = 0 + } + } + if (elsewhere) + for (i = 1; i <= ncc; i++) + cc_elsewhere[cc[i]] = 1 + } + } + nlines = split(TZ_COUNTRY_TABLE, line, /\n/) + for (i = 1; i <= nlines; i++) { + $0 = line[i] + if ($0 !~ /^#/) + cc_name[$1] = $2 + } + for (i = 1; i <= ccs; i++) { + country = cc_list[i] + if (cc_elsewhere[country]) + continue + if (cc_name[country]) + country = cc_name[country] + print country + } + } +' + +# Awk script to process a time zone table and output the same table, +# with each row preceded by its distance from 'here'. +# If output_times is set, each row is instead preceded by its local time +# and any apostrophes are escaped for the shell. +output_distances_or_times=' + BEGIN { + coord = substr(ARGV[1], 2) + TZ_COUNTRY_TABLE = substr(ARGV[2], 2) + TZ_ZONE_TABLE = substr(ARGV[3], 2) + ARGV[1] = ARGV[2] = ARGV[3] = "" + FS = "\t" + if (!output_times) { + nlines = split(TZ_COUNTRY_TABLE, line, /\n/) + for (i = 1; i <= nlines; i++) { + $0 = line[i] + if ($0 ~ /^#/) + continue + country[$1] = $2 + } + country["US"] = "US" # Otherwise the strings get too long. + } + } + function abs(x) { + return x < 0 ? -x : x; + } + function min(x, y) { + return x < y ? x : y; + } + function convert_coord(coord, deg, minute, ilen, sign, sec) { + if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9][0-9][0-9]([^0-9]|$)/) { + degminsec = coord + intdeg = degminsec < 0 ? -int(-degminsec / 10000) : int(degminsec / 10000) + minsec = degminsec - intdeg * 10000 + intmin = minsec < 0 ? -int(-minsec / 100) : int(minsec / 100) + sec = minsec - intmin * 100 + deg = (intdeg * 3600 + intmin * 60 + sec) / 3600 + } else if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9]([^0-9]|$)/) { + degmin = coord + intdeg = degmin < 0 ? -int(-degmin / 100) : int(degmin / 100) + minute = degmin - intdeg * 100 + deg = (intdeg * 60 + minute) / 60 + } else + deg = coord + return deg * 0.017453292519943296 + } + function convert_latitude(coord) { + match(coord, /..*[-+]/) + return convert_coord(substr(coord, 1, RLENGTH - 1)) + } + function convert_longitude(coord) { + match(coord, /..*[-+]/) + return convert_coord(substr(coord, RLENGTH)) + } + # Great-circle distance between points with given latitude and longitude. + # Inputs and output are in radians. This uses the great-circle special + # case of the Vicenty formula for distances on ellipsoids. + function gcdist(lat1, long1, lat2, long2, dlong, x, y, num, denom) { + dlong = long2 - long1 + x = cos(lat2) * sin(dlong) + y = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dlong) + num = sqrt(x * x + y * y) + denom = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(dlong) + return atan2(num, denom) + } + # Parallel distance between points with given latitude and longitude. + # This is the product of the longitude difference and the cosine + # of the latitude of the point that is further from the equator. + # I.e., it considers longitudes to be further apart if they are + # nearer the equator. + function pardist(lat1, long1, lat2, long2) { + return abs(long1 - long2) * min(cos(lat1), cos(lat2)) + } + # The distance function is the sum of the great-circle distance and + # the parallel distance. It could be weighted. + function dist(lat1, long1, lat2, long2) { + return gcdist(lat1, long1, lat2, long2) + pardist(lat1, long1, lat2, long2) + } + BEGIN { + coord_lat = convert_latitude(coord) + coord_long = convert_longitude(coord) + nlines = split(TZ_ZONE_TABLE, line, /\n/) + for (h = 1; h <= nlines; h++) { + $0 = line[h] + if ($0 ~ /^#/) + continue + inline[inlines++] = $0 + ncc = split($1, cc, /,/) + for (i = 1; i <= ncc; i++) + cc_used[cc[i]]++ + } + for (h = 0; h < inlines; h++) { + $0 = inline[h] + outline = $1 "\t" $2 "\t" $3 + sep = "\t" + ncc = split($1, cc, /,/) + split("", item_seen) + item_seen[""] = 1 + for (i = 1; i <= ncc; i++) { + item = cc_used[cc[i]] <= 1 ? country[cc[i]] : $4 + if (item_seen[item]++) + continue + outline = outline sep item + sep = "; " + } + if (output_times) { + fmt = "TZ='\''%s'\'' date +'\''%d %%Y %%m %%d %%H:%%M %%a %%b\t%s'\''\n" + gsub(/'\''/, "&\\\\&&", outline) + printf fmt, $3, h, outline + } else { + here_lat = convert_latitude($2) + here_long = convert_longitude($2) + printf "%g\t%s\n", dist(coord_lat, coord_long, here_lat, here_long), \ + outline + } + } + } +' + +# Begin the main loop. We come back here if the user wants to retry. +while + + echo >&2 'Please identify a location' \ + 'so that time zone rules can be set correctly.' + + continent= + country= + country_result= + region= + time= + TZ_ZONE_TABLE=$TZ_ZONETABTYPE_TABLE + + case $coord in + ?*) + continent=coord;; + '') + + # Ask the user for continent or ocean. + + echo >&2 \ + 'Please select a continent, ocean, "coord", "TZ", "time", or "now".' + + quoted_continents=` + $AWK ' + function handle_entry(entry) { + entry = substr(entry, 1, index(entry, "/") - 1) + if (entry == "America") + entry = entry "s" + if (entry ~ /^(Arctic|Atlantic|Indian|Pacific)$/) + entry = entry " Ocean" + printf "'\''%s'\''\n", entry + } + BEGIN { + TZ_ZONETABTYPE_TABLE = substr(ARGV[1], 2) + ARGV[1] = "" + FS = "\t" + nlines = split(TZ_ZONETABTYPE_TABLE, line, /\n/) + for (i = 1; i <= nlines; i++) { + $0 = line[i] + if ($0 ~ /^[^#]/) + handle_entry($3) + else if ($0 ~ /^#@/) { + ncont = split($2, cont, /,/) + for (ci = 1; ci <= ncont; ci++) + handle_entry(cont[ci]) + } + } + } + ' ="$TZ_ZONETABTYPE_TABLE" | + sort -u | + tr '\n' ' ' + echo '' + ` + + eval ' + doselect '"$quoted_continents"' \ + "coord - I want to use geographical coordinates." \ + "TZ - I want to specify the timezone using a POSIX.1-2017 TZ string." \ + "time - I know local time already." \ + "now - Like \"time\", but configure only for timestamps from now on." + continent=$select_result + case $continent in + Americas) continent=America;; + *) + # Get the first word of $continent. Path expansion is disabled + # so this works even with "*", which should not happen. + IFS=" " + for continent in $continent ""; do break; done + IFS=$newline;; + esac + case $zonetabtype,$continent in + zonenow,*) ;; + *,now) + ${TZ_ZONENOW_TABLE:+:} read_file TZ_ZONENOW_TABLE "$TZDIR/zonenow.tab" + TZ_ZONE_TABLE=$TZ_ZONENOW_TABLE + esac + ' + esac + + case $continent in + TZ) + # Ask the user for a POSIX.1-2017 TZ string. Check that it conforms. + check_POSIX_TZ_string=' + BEGIN { + tz = substr(ARGV[1], 2) + ARGV[1] = "" + tzname = ("(<[[:alnum:]+-][[:alnum:]+-][[:alnum:]+-]+>" \ + "|[[:alpha:]][[:alpha:]][[:alpha:]]+)") + time = ("(2[0-4]|[0-1]?[0-9])" \ + "(:[0-5][0-9](:[0-5][0-9])?)?") + offset = "[-+]?" time + mdate = "M([1-9]|1[0-2])\\.[1-5]\\.[0-6]" + jdate = ("((J[1-9]|[0-9]|J?[1-9][0-9]" \ + "|J?[1-2][0-9][0-9])|J?3[0-5][0-9]|J?36[0-5])") + datetime = ",(" mdate "|" jdate ")(/" time ")?" + tzpattern = ("^(:.*|" tzname offset "(" tzname \ + "(" offset ")?(" datetime datetime ")?)?)$") + exit tz ~ tzpattern + } + ' + + while + echo >&2 'Please enter the desired value' \ + 'of the TZ environment variable.' + echo >&2 'For example, AEST-10 is abbreviated' \ + 'AEST and is 10 hours' + echo >&2 'ahead (east) of Greenwich,' \ + 'with no daylight saving time.' + read tz + $AWK "$check_POSIX_TZ_string" ="$tz" + do + say >&2 "'$tz' is not a conforming POSIX.1-2017 timezone string." + done + TZ_for_date=$tz;; + *) + case $continent in + coord) + case $coord in + '') + echo >&2 'Please enter coordinates' \ + 'in ISO 6709 notation.' + echo >&2 'For example, +4042-07403 stands for' + echo >&2 '40 degrees 42 minutes north,' \ + '74 degrees 3 minutes west.' + read coord + esac + distance_table=` + $AWK \ + "$output_distances_or_times" \ + ="$coord" ="$TZ_COUNTRY_TABLE" ="$TZ_ZONE_TABLE" | + sort -n | + $AWK "{print} NR == $location_limit { exit }" + ` + regions=` + $AWK ' + BEGIN { + distance_table = substr(ARGV[1], 2) + ARGV[1] = "" + nlines = split(distance_table, line, /\n/) + for (nr = 1; nr <= nlines; nr++) { + nf = split(line[nr], f, /\t/) + print f[nf] + } + } + ' ="$distance_table" + ` + echo >&2 'Please select one of the following timezones,' + echo >&2 'listed roughly in increasing order' \ + "of distance from $coord". + doselect $regions + region=$select_result + tz=` + $AWK ' + BEGIN { + distance_table = substr(ARGV[1], 2) + region = substr(ARGV[2], 2) + ARGV[1] = ARGV[2] = "" + nlines = split(distance_table, line, /\n/) + for (nr = 1; nr <= nlines; nr++) { + nf = split(line[nr], f, /\t/) + if (f[nf] == region) + print f[4] + } + } + ' ="$distance_table" ="$region" + `;; + *) + case $continent in + now|time) + minute_format='%a %b %d %H:%M' + old_minute=`TZ=UTC0 date +"$minute_format"` + for i in 1 2 3 + do + time_table_command=` + $AWK \ + -v output_times=1 \ + "$output_distances_or_times" \ + = = ="$TZ_ZONE_TABLE" + ` + time_table=`eval "$time_table_command"` + new_minute=`TZ=UTC0 date +"$minute_format"` + case $old_minute in + "$new_minute") break + esac + old_minute=$new_minute + done + echo >&2 "The system says Universal Time is $new_minute." + echo >&2 "Assuming that's correct, what is the local time?" + sorted_table=`say "$time_table" | sort -k2n -k2,5 -k1n` || { + say >&2 "$0: cannot sort time table" + exit 1 + } + eval doselect ` + $AWK ' + BEGIN { + sorted_table = substr(ARGV[1], 2) + ARGV[1] = "" + nlines = split(sorted_table, line, /\n/) + for (i = 1; i <= nlines; i++) { + $0 = line[i] + outline = $6 " " $7 " " $4 " " $5 + if (outline == oldline) + continue + oldline = outline + gsub(/'\''/, "&\\\\&&", outline) + printf "'\''%s'\''\n", outline + } + } + ' ="$sorted_table" + ` + time=$select_result + continent_re='^' + zone_table=` + $AWK ' + BEGIN { + time = substr(ARGV[1], 2) + time_table = substr(ARGV[2], 2) + ARGV[1] = ARGV[2] = "" + nlines = split(time_table, line, /\n/) + for (i = 1; i <= nlines; i++) { + $0 = line[i] + if ($6 " " $7 " " $4 " " $5 == time) { + sub(/[^\t]*\t/, "") + print + } + } + } + ' ="$time" ="$time_table" + ` + countries=` + $AWK \ + "$output_country_list" \ + ="$continent_re" ="$TZ_COUNTRY_TABLE" ="$zone_table" | + sort -f + ` + ;; + *) + continent_re="^$continent/" + zone_table=$TZ_ZONE_TABLE + esac + + # Get list of names of countries in the continent or ocean. + countries=` + $AWK \ + "$output_country_list" \ + ="$continent_re" ="$TZ_COUNTRY_TABLE" ="$zone_table" | + sort -f + ` + # If all zone table entries have comments, and there are + # at most 22 entries, asked based on those comments. + # This fits the prompt onto old-fashioned 24-line screens. + regions=` + $AWK ' + BEGIN { + TZ_ZONE_TABLE = substr(ARGV[1], 2) + ARGV[1] = "" + FS = "\t" + nlines = split(TZ_ZONE_TABLE, line, /\n/) + for (i = 1; i <= nlines; i++) { + $0 = line[i] + if ($0 ~ /^[^#]/ && !missing_comment) { + if ($4) + comment[++inlines] = $4 + else + missing_comment = 1 + } + } + if (!missing_comment && inlines <= 22) + for (i = 1; i <= inlines; i++) + print comment[i] + } + ' ="$zone_table" + ` + + # If there's more than one country, ask the user which one. + case $countries in + *"$newline"*) + echo >&2 'Please select a country' \ + 'whose clocks agree with yours.' + doselect $countries + country_result=$select_result + country=$select_result;; + *) + country=$countries + esac + + + # Get list of timezones in the country. + regions=` + $AWK ' + BEGIN { + country = substr(ARGV[1], 2) + TZ_COUNTRY_TABLE = substr(ARGV[2], 2) + TZ_ZONE_TABLE = substr(ARGV[3], 2) + ARGV[1] = ARGV[2] = ARGV[3] = "" + FS = "\t" + cc = country + nlines = split(TZ_COUNTRY_TABLE, line, /\n/) + for (i = 1; i <= nlines; i++) { + $0 = line[i] + if ($0 !~ /^#/ && country == $2) { + cc = $1 + break + } + } + nlines = split(TZ_ZONE_TABLE, line, /\n/) + for (i = 1; i <= nlines; i++) { + $0 = line[i] + if ($0 ~ /^#/) + continue + if ($1 ~ cc) + print $4 + } + } + ' ="$country" ="$TZ_COUNTRY_TABLE" ="$zone_table" + ` + + # If there's more than one region, ask the user which one. + case $regions in + *"$newline"*) + echo >&2 'Please select one of the following timezones.' + doselect $regions + region=$select_result + esac + + # Determine tz from country and region. + tz=` + $AWK ' + BEGIN { + country = substr(ARGV[1], 2) + region = substr(ARGV[2], 2) + TZ_COUNTRY_TABLE = substr(ARGV[3], 2) + TZ_ZONE_TABLE = substr(ARGV[4], 2) + ARGV[1] = ARGV[2] = ARGV[3] = ARGV[4] = "" + FS = "\t" + cc = country + nlines = split(TZ_COUNTRY_TABLE, line, /\n/) + for (i = 1; i <= nlines; i++) { + $0 = line[i] + if ($0 !~ /^#/ && country == $2) { + cc = $1 + break + } + } + nlines = split(TZ_ZONE_TABLE, line, /\n/) + for (i = 1; i <= nlines; i++) { + $0 = line[i] + if ($0 ~ /^#/) + continue + if ($1 ~ cc && ($4 == region || !region)) + print $3 + } + } + ' ="$country" ="$region" ="$TZ_COUNTRY_TABLE" ="$zone_table" + ` + esac + + # Make sure the corresponding zoneinfo file exists. + TZ_for_date=$TZDIR/$tz + <"$TZ_for_date" || { + say >&2 "$0: time zone files are not set up correctly" + exit 1 + } + esac + + + # Use the proposed TZ to output the current date relative to UTC. + # Loop until they agree in seconds. + # Give up after 8 unsuccessful tries. + + extra_info= + for i in 1 2 3 4 5 6 7 8 + do + TZdate=`LANG=C TZ="$TZ_for_date" date` + UTdate=`LANG=C TZ=UTC0 date` + if $AWK ' + function getsecs(d) { + return match(d, /.*:[0-5][0-9]/) ? substr(d, RLENGTH - 1, 2) : "" + } + BEGIN { exit getsecs(ARGV[1]) != getsecs(ARGV[2]) } + ' ="$TZdate" ="$UTdate" + then + extra_info=" +Selected time is now: $TZdate. +Universal Time is now: $UTdate." + break + fi + done + + + # Output TZ info and ask the user to confirm. + + echo >&2 "" + echo >&2 "Based on the following information:" + echo >&2 "" + case $time%$country_result%$region%$coord in + ?*%?*%?*%) + say >&2 " $time$newline $country_result$newline $region";; + ?*%?*%%|?*%%?*%) say >&2 " $time$newline $country_result$region";; + ?*%%%) say >&2 " $time";; + %?*%?*%) say >&2 " $country_result$newline $region";; + %?*%%) say >&2 " $country_result";; + %%?*%?*) say >&2 " coord $coord$newline $region";; + %%%?*) say >&2 " coord $coord";; + *) say >&2 " TZ='$tz'" + esac + say >&2 "" + say >&2 "TZ='$tz' will be used.$extra_info" + say >&2 "Is the above information OK?" + + doselect Yes No + ok=$select_result + case $ok in + Yes) break + esac +do coord= +done + +case $SHELL in +*csh) file=.login line="setenv TZ '$tz'";; +*) file=.profile line="TZ='$tz'; export TZ" +esac + +test -t 1 && say >&2 " +You can make this change permanent for yourself by appending the line + $line +to the file '$file' in your home directory; then log out and log in again. + +Here is that TZ value again, this time on standard output so that you +can use the $0 command in shell scripts:" + +say "$tz" diff --git a/vendor/chrono-tz/tz/workman.sh b/vendor/chrono-tz/tz/workman.sh new file mode 100644 index 0000000000000..6e2da3a80c8d9 --- /dev/null +++ b/vendor/chrono-tz/tz/workman.sh @@ -0,0 +1,41 @@ +#! /bin/sh +# Convert manual page troff stdin to formatted .txt stdout. + +# This file is in the public domain, so clarified as of +# 2009-05-17 by Arthur David Olson. + +if (type nroff && type perl) >/dev/null 2>&1; then + + # Tell groff not to emit SGR escape sequences (ANSI color escapes). + GROFF_NO_SGR=1 + export GROFF_NO_SGR + + echo ".am TH +.hy 0 +.na +.. +.rm }H +.rm }F" | nroff -man - ${1+"$@"} | perl -ne ' + binmode STDIN, '\'':encoding(utf8)'\''; + binmode STDOUT, '\'':encoding(utf8)'\''; + chomp; + s/.\010//g; + s/\s*$//; + if (/^$/) { + $sawblank = 1; + next; + } else { + if ($sawblank && $didprint) { + print "\n"; + $sawblank = 0; + } + print "$_\n"; + $didprint = 1; + } + ' +elif (type mandoc && type col) >/dev/null 2>&1; then + mandoc -man -T ascii "$@" | col -bx +else + echo >&2 "$0: please install nroff and perl, or mandoc and col" + exit 1 +fi diff --git a/vendor/chrono-tz/tz/zdump.8 b/vendor/chrono-tz/tz/zdump.8 new file mode 100644 index 0000000000000..c3f0bba60ba81 --- /dev/null +++ b/vendor/chrono-tz/tz/zdump.8 @@ -0,0 +1,230 @@ +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. +.TH zdump 8 "" "Time Zone Database" +.SH NAME +zdump \- timezone dumper +.SH SYNOPSIS +.B zdump +[ +.I option +\&... ] [ +.I timezone +\&... ] +.SH DESCRIPTION +.ie '\(lq'' .ds lq \&"\" +.el .ds lq \(lq\" +.ie '\(rq'' .ds rq \&"\" +.el .ds rq \(rq\" +.de q +\\$3\*(lq\\$1\*(rq\\$2 +.. +.ie \n(.g .ds - \f(CR-\fP +.el .ds - \- +The +.B zdump +program prints the current time in each +.I timezone +named on the command line. +.SH OPTIONS +.TP +.B \*-\*-version +Output version information and exit. +.TP +.B \*-\*-help +Output short usage message and exit. +.TP +.B \*-i +Output a description of time intervals. For each +.I timezone +on the command line, output an interval-format description of the +timezone. See +.q "INTERVAL FORMAT" +below. +.TP +.B \*-v +Output a verbose description of time intervals. +For each +.I timezone +on the command line, +print the times at the two extreme time values, +the times (if present) at and just beyond the boundaries of years that +.BR localtime (3) +and +.BR gmtime (3) +can represent, and +the times both one second before and exactly at +each detected time discontinuity. +Each line is followed by +.BI isdst= D +where +.I D +is positive, zero, or negative depending on whether +the given time is daylight saving time, standard time, +or an unknown time type, respectively. +Each line is also followed by +.BI gmtoff= N +if the given local time is known to be +.I N +seconds east of Greenwich. +.TP +.B \*-V +Like +.BR \*-v , +except omit output concerning extreme time and year values. +This generates output that is easier to compare to that of +implementations with different time representations. +.TP +.BI "\*-c " \fR[\fIloyear , \fR]\fIhiyear +Cut off interval output at the given year(s). +Cutoff times are computed using the proleptic Gregorian calendar with year 0 +and with Universal Time (UT) ignoring leap seconds. +Cutoffs are at the start of each year, where the lower-bound +timestamp is inclusive and the upper is exclusive; for example, +.B "\*-c 1970,2070" +selects transitions on or after 1970-01-01 00:00:00 UTC +and before 2070-01-01 00:00:00 UTC. +The default cutoff is +.BR \*-500,2500 . +.TP +.BI "\*-t " \fR[\fIlotime , \fR]\fIhitime +Cut off interval output at the given time(s), +given in decimal seconds since 1970-01-01 00:00:00 +Coordinated Universal Time (UTC). +The +.I timezone +determines whether the count includes leap seconds. +As with +.BR \*-c , +the cutoff's lower bound is inclusive and its upper bound is exclusive. +.SH "INTERVAL FORMAT" +The interval format is a compact text representation that is intended +to be both human- and machine-readable. It consists of an empty line, +then a line +.q "TZ=\fIstring\fP" +where +.I string +is a double-quoted string giving the timezone, a second line +.q "\*- \*- \fIinterval\fP" +describing the time interval before the first transition if any, and +zero or more following lines +.q "\fIdate time interval\fP", +one line for each transition time and following interval. Fields are +separated by single tabs. +.PP +Dates are in +.IR yyyy - mm - dd +format and times are in 24-hour +.IR hh : mm : ss +format where +.IR hh <24. +Times are in local time immediately after the transition. A +time interval description consists of a UT offset in signed +.RI \(+- hhmmss +format, a time zone abbreviation, and an isdst flag. An abbreviation +that equals the UT offset is omitted; other abbreviations are +double-quoted strings unless they consist of one or more alphabetic +characters. An isdst flag is omitted for standard time, and otherwise +is a decimal integer that is unsigned and positive (typically 1) for +daylight saving time and negative for unknown. +.PP +In times and in UT offsets with absolute value less than 100 hours, +the seconds are omitted if they are zero, and +the minutes are also omitted if they are also zero. Positive UT +offsets are east of Greenwich. The UT offset \*-00 denotes a UT +placeholder in areas where the actual offset is unspecified; by +convention, this occurs when the UT offset is zero and the time zone +abbreviation begins with +.q "\*-" +or is +.q "zzz". +.PP +In double-quoted strings, escape sequences represent unusual +characters. The escape sequences are \es for space, and \e", \e\e, +\ef, \en, \er, \et, and \ev with their usual meaning in the C +programming language. E.g., the double-quoted string +\*(lq"CET\es\e"\e\e"\*(rq represents the character sequence \*(lqCET +"\e\*(rq.\"" +.PP +.ne 9 +Here is an example of the output, with the leading empty line omitted. +(This example is shown with tab stops set far enough apart so that the +tabbed columns line up.) +.nf +.sp +.if \n(.g .ft CR +.in +2 +.nr w \w'1896-01-13 'u+\n(.i +.ta \w'1896-01-13\0\0'u +\w'12:01:26\0\0'u +\w'-103126\0\0'u +\w'HWT\0\0'u +TZ="Pacific/Honolulu" +- - -103126 LMT +1896-01-13 12:01:26 -1030 HST +1933-04-30 03 -0930 HDT 1 +1933-05-21 11 -1030 HST +1942-02-09 03 -0930 HWT 1 +1945-08-14 13:30 -0930 HPT 1 +1945-09-30 01 -1030 HST +1947-06-08 02:30 -10 HST +.in +.if \n(.g .ft +.sp +.fi +Here, local time begins 10 hours, 31 minutes and 26 seconds west of +UT, and is a standard time abbreviated LMT. Immediately after the +first transition, the date is 1896-01-13 and the time is 12:01:26, and +the following time interval is 10.5 hours west of UT, a standard time +abbreviated HST. Immediately after the second transition, the date is +1933-04-30 and the time is 03:00:00 and the following time interval is +9.5 hours west of UT, is abbreviated HDT, and is daylight saving time. +Immediately after the last transition the date is 1947-06-08 and the +time is 02:30:00, and the following time interval is 10 hours west of +UT, a standard time abbreviated HST. +.PP +.ne 10 +Here are excerpts from another example: +.nf +.sp +.if \n(.g .ft CR +.if t .in +.5i +.if n .in +2 +TZ="Europe/Astrakhan" +- - +031212 LMT +1924-04-30 23:47:48 +03 +1930-06-21 01 +04 +1981-04-01 01 +05 1 +1981-09-30 23 +04 +\&... +2014-10-26 01 +03 +2016-03-27 03 +04 +.in +.if \n(.g .ft +.sp +.fi +This time zone is east of UT, so its UT offsets are positive. Also, +many of its time zone abbreviations are omitted since they duplicate +the text of the UT offset. +.SH LIMITATIONS +Time discontinuities are found by sampling the results returned by +.BR localtime (3) +at twelve-hour intervals. +This works in all real-world cases; +one can construct artificial time zones for which this fails. +.PP +In the +.B \*-v +and +.B \*-V +output, +.q "UT" +denotes the value returned by +.BR gmtime (3), +which uses UTC for modern timestamps and some other UT flavor for +timestamps that predate the introduction of UTC. +No attempt is currently made to have the output use +.q "UTC" +for newer and +.q "UT" +for older timestamps, partly because the exact date of the +introduction of UTC is problematic. +.SH SEE ALSO +.BR tzfile (5), +.BR zic (8) diff --git a/vendor/chrono-tz/tz/zdump.c b/vendor/chrono-tz/tz/zdump.c new file mode 100644 index 0000000000000..7d99cc74bd30d --- /dev/null +++ b/vendor/chrono-tz/tz/zdump.c @@ -0,0 +1,1267 @@ +/* Dump time zone data in a textual format. */ + +/* +** This file is in the public domain, so clarified as of +** 2009-05-17 by Arthur David Olson. +*/ + +#include "version.h" + +#ifndef NETBSD_INSPIRED +# define NETBSD_INSPIRED 1 +#endif + +#include "private.h" +#include + +#ifndef HAVE_SNPRINTF +# define HAVE_SNPRINTF (!PORT_TO_C89 || 199901 <= __STDC_VERSION__) +#endif + +#ifndef HAVE_LOCALTIME_R +# define HAVE_LOCALTIME_R 1 +#endif + +#ifndef HAVE_LOCALTIME_RZ +# ifdef TM_ZONE +# define HAVE_LOCALTIME_RZ (NETBSD_INSPIRED && USE_LTZ) +# else +# define HAVE_LOCALTIME_RZ 0 +# endif +#endif + +#ifndef HAVE_TZSET +# define HAVE_TZSET 1 +#endif + +#ifndef ZDUMP_LO_YEAR +# define ZDUMP_LO_YEAR (-500) +#endif /* !defined ZDUMP_LO_YEAR */ + +#ifndef ZDUMP_HI_YEAR +# define ZDUMP_HI_YEAR 2500 +#endif /* !defined ZDUMP_HI_YEAR */ + +#define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR) +#define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY) +#define SECSPER400YEARS (SECSPERNYEAR * (intmax_t) (300 + 3) \ + + SECSPERLYEAR * (intmax_t) (100 - 3)) + +/* +** True if SECSPER400YEARS is known to be representable as an +** intmax_t. It's OK that SECSPER400YEARS_FITS can in theory be false +** even if SECSPER400YEARS is representable, because when that happens +** the code merely runs a bit more slowly, and this slowness doesn't +** occur on any practical platform. +*/ +enum { SECSPER400YEARS_FITS = SECSPERLYEAR <= INTMAX_MAX / 400 }; + +#if HAVE_GETTEXT +# include /* for setlocale */ +#endif /* HAVE_GETTEXT */ + +#if ! HAVE_LOCALTIME_RZ +# undef timezone_t +# define timezone_t char ** +#endif + +#if !HAVE_POSIX_DECLS +extern int getopt(int argc, char * const argv[], + const char * options); +extern char * optarg; +extern int optind; +#endif + +/* The minimum and maximum finite time values. */ +enum { atime_shift = CHAR_BIT * sizeof(time_t) - 2 }; +static time_t const absolute_min_time = + ((time_t) -1 < 0 + ? (- ((time_t) ~ (time_t) 0 < 0) + - (((time_t) 1 << atime_shift) - 1 + ((time_t) 1 << atime_shift))) + : 0); +static time_t const absolute_max_time = + ((time_t) -1 < 0 + ? (((time_t) 1 << atime_shift) - 1 + ((time_t) 1 << atime_shift)) + : -1); +static int longest; +static char const *progname; +static bool warned; +static bool errout; + +static char const *abbr(struct tm const *); +ATTRIBUTE_REPRODUCIBLE static intmax_t delta(struct tm *, struct tm *); +static void dumptime(struct tm const *); +static time_t hunt(timezone_t, time_t, time_t, bool); +static void show(timezone_t, char *, time_t, bool); +static void showextrema(timezone_t, char *, time_t, struct tm *, time_t); +static void showtrans(char const *, struct tm const *, time_t, char const *, + char const *); +static const char *tformat(void); +ATTRIBUTE_REPRODUCIBLE static time_t yeartot(intmax_t); + +/* Is C an ASCII digit? */ +static bool +is_digit(char c) +{ + return '0' <= c && c <= '9'; +} + +/* Is A an alphabetic character in the C locale? */ +static bool +is_alpha(char a) +{ + switch (a) { + default: + return false; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': + case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': + case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': + case 'V': case 'W': case 'X': case 'Y': case 'Z': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': + case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': + case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': + case 'v': case 'w': case 'x': case 'y': case 'z': + return true; + } +} + +ATTRIBUTE_NORETURN static void +size_overflow(void) +{ + fprintf(stderr, _("%s: size overflow\n"), progname); + exit(EXIT_FAILURE); +} + +/* Return A + B, exiting if the result would overflow either ptrdiff_t + or size_t. A and B are both nonnegative. */ +ATTRIBUTE_REPRODUCIBLE static ptrdiff_t +sumsize(ptrdiff_t a, ptrdiff_t b) +{ +#ifdef ckd_add + ptrdiff_t sum; + if (!ckd_add(&sum, a, b) && sum <= INDEX_MAX) + return sum; +#else + if (a <= INDEX_MAX && b <= INDEX_MAX - a) + return a + b; +#endif + size_overflow(); +} + +/* Return the size of of the string STR, including its trailing NUL. + Report an error and exit if this would exceed INDEX_MAX which means + pointer subtraction wouldn't work. */ +static ptrdiff_t +xstrsize(char const *str) +{ + size_t len = strlen(str); + if (len < INDEX_MAX) + return len + 1; + size_overflow(); +} + +/* Return a pointer to a newly allocated buffer of size SIZE, exiting + on failure. SIZE should be positive. */ +ATTRIBUTE_MALLOC static void * +xmalloc(ptrdiff_t size) +{ + void *p = malloc(size); + if (!p) { + fprintf(stderr, _("%s: Memory exhausted\n"), progname); + exit(EXIT_FAILURE); + } + return p; +} + +#if ! HAVE_TZSET +# undef tzset +# define tzset zdump_tzset +static void tzset(void) { } +#endif + +/* Assume gmtime_r works if localtime_r does. + A replacement localtime_r is defined below if needed. */ +#if ! HAVE_LOCALTIME_R + +# undef gmtime_r +# define gmtime_r zdump_gmtime_r + +static struct tm * +gmtime_r(time_t *tp, struct tm *tmp) +{ + struct tm *r = gmtime(tp); + if (r) { + *tmp = *r; + r = tmp; + } + return r; +} + +#endif + +/* Platforms with TM_ZONE don't need tzname, so they can use the + faster localtime_rz or localtime_r if available. */ + +#if defined TM_ZONE && HAVE_LOCALTIME_RZ +# define USE_LOCALTIME_RZ true +#else +# define USE_LOCALTIME_RZ false +#endif + +#if ! USE_LOCALTIME_RZ + +# if !defined TM_ZONE || ! HAVE_LOCALTIME_R || ! HAVE_TZSET +# undef localtime_r +# define localtime_r zdump_localtime_r +static struct tm * +localtime_r(time_t *tp, struct tm *tmp) +{ + struct tm *r = localtime(tp); + if (r) { + *tmp = *r; + r = tmp; + } + return r; +} +# endif + +# undef localtime_rz +# define localtime_rz zdump_localtime_rz +static struct tm * +localtime_rz(ATTRIBUTE_MAYBE_UNUSED timezone_t rz, time_t *tp, struct tm *tmp) +{ + return localtime_r(tp, tmp); +} + +# ifdef TYPECHECK +# undef mktime_z +# define mktime_z zdump_mktime_z +static time_t +mktime_z(timezone_t tz, struct tm *tmp) +{ + return mktime(tmp); +} +# endif + +# undef tzalloc +# undef tzfree +# define tzalloc zdump_tzalloc +# define tzfree zdump_tzfree + +static timezone_t +tzalloc(char const *val) +{ +# if HAVE_SETENV + if (setenv("TZ", val, 1) != 0) { + char const *e = strerror(errno); + fprintf(stderr, _("%s: setenv: %s\n"), progname, e); + exit(EXIT_FAILURE); + } + tzset(); + return &optarg; /* Any valid non-null char ** will do. */ +# else + enum { TZeqlen = 3 }; + static char const TZeq[TZeqlen] = "TZ="; + static char **fakeenv; + static ptrdiff_t fakeenv0size; + void *freeable = NULL; + char **env = fakeenv, **initial_environ; + ptrdiff_t valsize = xstrsize(val); + if (fakeenv0size < valsize) { + char **e = environ, **to; + ptrdiff_t initial_nenvptrs = 1; /* Counting the trailing NULL pointer. */ + + while (*e++) { +# ifdef ckd_add + if (ckd_add(&initial_nenvptrs, initial_nenvptrs, 1) + || INDEX_MAX < initial_nenvptrs) + size_overflow(); +# else + if (initial_nenvptrs == INDEX_MAX / sizeof *environ) + size_overflow(); + initial_nenvptrs++; +# endif + } + fakeenv0size = sumsize(valsize, valsize); + fakeenv0size = max(fakeenv0size, 64); + freeable = env; + fakeenv = env = + xmalloc(sumsize(sumsize(sizeof *environ, + initial_nenvptrs * sizeof *environ), + sumsize(TZeqlen, fakeenv0size))); + to = env + 1; + for (e = environ; (*to = *e); e++) + to += strncmp(*e, TZeq, TZeqlen) != 0; + env[0] = memcpy(to + 1, TZeq, TZeqlen); + } + memcpy(env[0] + TZeqlen, val, valsize); + initial_environ = environ; + environ = env; + tzset(); + free(freeable); + return initial_environ; +# endif +} + +static void +tzfree(ATTRIBUTE_MAYBE_UNUSED timezone_t initial_environ) +{ +# if !HAVE_SETENV + environ = initial_environ; + tzset(); +# endif +} +#endif /* ! USE_LOCALTIME_RZ */ + +/* A UT time zone, and its initializer. */ +static timezone_t gmtz; +static void +gmtzinit(void) +{ + if (USE_LOCALTIME_RZ) { + /* Try "GMT" first to find out whether this is one of the rare + platforms where time_t counts leap seconds; this works due to + the "Zone GMT 0 - GMT" line in the "etcetera" file. If "GMT" + fails, fall back on "GMT0" which might be similar due to the + "Link GMT GMT0" line in the "backward" file, and which + should work on all POSIX platforms. The rest of zdump does not + use the "GMT" abbreviation that comes from this setting, so it + is OK to use "GMT" here rather than the modern "UTC" which + would not work on platforms that omit the "backward" file. */ + gmtz = tzalloc("GMT"); + if (!gmtz) { + static char const gmt0[] = "GMT0"; + gmtz = tzalloc(gmt0); + if (!gmtz) { + char const *e = strerror(errno); + fprintf(stderr, _("%s: unknown timezone '%s': %s\n"), + progname, gmt0, e); + exit(EXIT_FAILURE); + } + } + } +} + +/* Convert *TP to UT, storing the broken-down time into *TMP. + Return TMP if successful, NULL otherwise. This is like gmtime_r(TP, TMP), + except typically faster if USE_LOCALTIME_RZ. */ +static struct tm * +my_gmtime_r(time_t *tp, struct tm *tmp) +{ + return USE_LOCALTIME_RZ ? localtime_rz(gmtz, tp, tmp) : gmtime_r(tp, tmp); +} + +#ifndef TYPECHECK +# define my_localtime_rz localtime_rz +#else /* !defined TYPECHECK */ + +static struct tm * +my_localtime_rz(timezone_t tz, time_t *tp, struct tm *tmp) +{ + tmp = localtime_rz(tz, tp, tmp); + if (tmp) { + struct tm tm; + register time_t t; + + tm = *tmp; + t = mktime_z(tz, &tm); + if (t != *tp) { + fflush(stdout); + fprintf(stderr, "\n%s: ", progname); + fprintf(stderr, tformat(), *tp); + fprintf(stderr, " ->"); + fprintf(stderr, " year=%d", tmp->tm_year); + fprintf(stderr, " mon=%d", tmp->tm_mon); + fprintf(stderr, " mday=%d", tmp->tm_mday); + fprintf(stderr, " hour=%d", tmp->tm_hour); + fprintf(stderr, " min=%d", tmp->tm_min); + fprintf(stderr, " sec=%d", tmp->tm_sec); + fprintf(stderr, " isdst=%d", tmp->tm_isdst); + fprintf(stderr, " -> "); + fprintf(stderr, tformat(), t); + fprintf(stderr, "\n"); + errout = true; + } + } + return tmp; +} +#endif /* !defined TYPECHECK */ + +static void +abbrok(const char *const abbrp, const char *const zone) +{ + register const char * cp; + register const char * wp; + + if (warned) + return; + cp = abbrp; + while (is_alpha(*cp) || is_digit(*cp) || *cp == '-' || *cp == '+') + ++cp; + if (*cp) + wp = _("has characters other than ASCII alphanumerics, '-' or '+'"); + else if (cp - abbrp < 3) + wp = _("has fewer than 3 characters"); + else if (cp - abbrp > 6) + wp = _("has more than 6 characters"); + else + return; + fflush(stdout); + fprintf(stderr, + _("%s: warning: zone \"%s\" abbreviation \"%s\" %s\n"), + progname, zone, abbrp, wp); + warned = errout = true; +} + +/* Return a time zone abbreviation. If the abbreviation needs to be + saved, use *BUF (of size *BUFALLOC) to save it, and return the + abbreviation in the possibly reallocated *BUF. Otherwise, just + return the abbreviation. Get the abbreviation from TMP. + Exit on memory allocation failure. */ +static char const * +saveabbr(char **buf, ptrdiff_t *bufalloc, struct tm const *tmp) +{ + char const *ab = abbr(tmp); + if (HAVE_LOCALTIME_RZ) + return ab; + else { + ptrdiff_t absize = xstrsize(ab); + if (*bufalloc < absize) { + free(*buf); + + /* Make the new buffer at least twice as long as the old, + to avoid O(N**2) behavior on repeated calls. */ + *bufalloc = sumsize(*bufalloc, absize); + + *buf = xmalloc(*bufalloc); + } + return strcpy(*buf, ab); + } +} + +static void +close_file(FILE *stream) +{ + char const *e = (ferror(stream) ? _("I/O error") + : fclose(stream) != 0 ? strerror(errno) : NULL); + if (e) { + fprintf(stderr, "%s: %s\n", progname, e); + exit(EXIT_FAILURE); + } +} + +static void +usage(FILE * const stream, const int status) +{ + fprintf(stream, +_("%s: usage: %s OPTIONS TIMEZONE ...\n" + "Options include:\n" + " -c [L,]U Start at year L (default -500), end before year U (default 2500)\n" + " -t [L,]U Start at time L, end before time U (in seconds since 1970)\n" + " -i List transitions briefly (format is experimental)\n" \ + " -v List transitions verbosely\n" + " -V List transitions a bit less verbosely\n" + " --help Output this help\n" + " --version Output version info\n" + "\n" + "Report bugs to %s.\n"), + progname, progname, REPORT_BUGS_TO); + if (status == EXIT_SUCCESS) + close_file(stream); + exit(status); +} + +int +main(int argc, char *argv[]) +{ + /* These are static so that they're initially zero. */ + static char * abbrev; + static ptrdiff_t abbrevsize; + + register int i; + register bool vflag; + register bool Vflag; + register char * cutarg; + register char * cuttimes; + register time_t cutlotime; + register time_t cuthitime; + time_t now; + bool iflag = false; + + cutlotime = absolute_min_time; + cuthitime = absolute_max_time; +#if HAVE_GETTEXT + setlocale(LC_ALL, ""); +# ifdef TZ_DOMAINDIR + bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); +# endif /* defined TEXTDOMAINDIR */ + textdomain(TZ_DOMAIN); +#endif /* HAVE_GETTEXT */ + progname = argv[0] ? argv[0] : "zdump"; + for (i = 1; i < argc; ++i) + if (strcmp(argv[i], "--version") == 0) { + printf("zdump %s%s\n", PKGVERSION, TZVERSION); + return EXIT_SUCCESS; + } else if (strcmp(argv[i], "--help") == 0) { + usage(stdout, EXIT_SUCCESS); + } + vflag = Vflag = false; + cutarg = cuttimes = NULL; + for (;;) + switch (getopt(argc, argv, "c:it:vV")) { + case 'c': cutarg = optarg; break; + case 't': cuttimes = optarg; break; + case 'i': iflag = true; break; + case 'v': vflag = true; break; + case 'V': Vflag = true; break; + case -1: + if (! (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) + goto arg_processing_done; + ATTRIBUTE_FALLTHROUGH; + default: + usage(stderr, EXIT_FAILURE); + } + arg_processing_done:; + + if (iflag | vflag | Vflag) { + intmax_t lo; + intmax_t hi; + char *loend, *hiend; + register intmax_t cutloyear = ZDUMP_LO_YEAR; + register intmax_t cuthiyear = ZDUMP_HI_YEAR; + if (cutarg != NULL) { + lo = strtoimax(cutarg, &loend, 10); + if (cutarg != loend && !*loend) { + hi = lo; + cuthiyear = hi; + } else if (cutarg != loend && *loend == ',' + && (hi = strtoimax(loend + 1, &hiend, 10), + loend + 1 != hiend && !*hiend)) { + cutloyear = lo; + cuthiyear = hi; + } else { + fprintf(stderr, _("%s: wild -c argument %s\n"), + progname, cutarg); + return EXIT_FAILURE; + } + } + if (cutarg != NULL || cuttimes == NULL) { + cutlotime = yeartot(cutloyear); + cuthitime = yeartot(cuthiyear); + } + if (cuttimes != NULL) { + lo = strtoimax(cuttimes, &loend, 10); + if (cuttimes != loend && !*loend) { + hi = lo; + if (hi < cuthitime) { + if (hi < absolute_min_time + 1) + hi = absolute_min_time + 1; + cuthitime = hi; + } + } else if (cuttimes != loend && *loend == ',' + && (hi = strtoimax(loend + 1, &hiend, 10), + loend + 1 != hiend && !*hiend)) { + if (cutlotime < lo) { + if (absolute_max_time < lo) + lo = absolute_max_time; + cutlotime = lo; + } + if (hi < cuthitime) { + if (hi < absolute_min_time + 1) + hi = absolute_min_time + 1; + cuthitime = hi; + } + } else { + fprintf(stderr, + _("%s: wild -t argument %s\n"), + progname, cuttimes); + return EXIT_FAILURE; + } + } + } + gmtzinit(); + if (iflag | vflag | Vflag) + now = 0; + else { + now = time(NULL); + now |= !now; + } + longest = 0; + for (i = optind; i < argc; i++) { + size_t arglen = strlen(argv[i]); + if (longest < arglen) + longest = min(arglen, INT_MAX); + } + + for (i = optind; i < argc; ++i) { + timezone_t tz = tzalloc(argv[i]); + char const *ab; + time_t t; + struct tm tm, newtm; + bool tm_ok; + if (!tz) { + char const *e = strerror(errno); + fprintf(stderr, _("%s: unknown timezone '%s': %s\n"), + progname, argv[i], e); + return EXIT_FAILURE; + } + if (now) { + show(tz, argv[i], now, false); + tzfree(tz); + continue; + } + warned = false; + t = absolute_min_time; + if (! (iflag | Vflag)) { + show(tz, argv[i], t, true); + if (my_localtime_rz(tz, &t, &tm) == NULL + && t < cutlotime) { + time_t newt = cutlotime; + if (my_localtime_rz(tz, &newt, &newtm) != NULL) + showextrema(tz, argv[i], t, NULL, newt); + } + } + if (t + 1 < cutlotime) + t = cutlotime - 1; + tm_ok = my_localtime_rz(tz, &t, &tm) != NULL; + if (tm_ok) { + ab = saveabbr(&abbrev, &abbrevsize, &tm); + if (iflag) { + showtrans("\nTZ=%f", &tm, t, ab, argv[i]); + showtrans("-\t-\t%Q", &tm, t, ab, argv[i]); + } + } else + ab = NULL; + while (t < cuthitime - 1) { + time_t newt = ((t < absolute_max_time - SECSPERDAY / 2 + && t + SECSPERDAY / 2 < cuthitime - 1) + ? t + SECSPERDAY / 2 + : cuthitime - 1); + struct tm *newtmp = localtime_rz(tz, &newt, &newtm); + bool newtm_ok = newtmp != NULL; + if (tm_ok != newtm_ok + || (ab && (delta(&newtm, &tm) != newt - t + || newtm.tm_isdst != tm.tm_isdst + || strcmp(abbr(&newtm), ab) != 0))) { + newt = hunt(tz, t, newt, false); + newtmp = localtime_rz(tz, &newt, &newtm); + newtm_ok = newtmp != NULL; + if (iflag) + showtrans("%Y-%m-%d\t%L\t%Q", newtmp, newt, + newtm_ok ? abbr(&newtm) : NULL, argv[i]); + else { + show(tz, argv[i], newt - 1, true); + show(tz, argv[i], newt, true); + } + } + t = newt; + tm_ok = newtm_ok; + if (newtm_ok) { + ab = saveabbr(&abbrev, &abbrevsize, &newtm); + tm = newtm; + } + } + if (! (iflag | Vflag)) { + time_t newt = absolute_max_time; + t = cuthitime; + if (t < newt) { + struct tm *tmp = my_localtime_rz(tz, &t, &tm); + if (tmp != NULL + && my_localtime_rz(tz, &newt, &newtm) == NULL) + showextrema(tz, argv[i], t, tmp, newt); + } + show(tz, argv[i], absolute_max_time, true); + } + tzfree(tz); + } + close_file(stdout); + if (errout && (ferror(stderr) || fclose(stderr) != 0)) + return EXIT_FAILURE; + return EXIT_SUCCESS; +} + +static time_t +yeartot(intmax_t y) +{ + register intmax_t myy, seconds, years; + register time_t t; + + myy = EPOCH_YEAR; + t = 0; + while (myy < y) { + if (SECSPER400YEARS_FITS && 400 <= y - myy) { + intmax_t diff400 = (y - myy) / 400; + if (INTMAX_MAX / SECSPER400YEARS < diff400) + return absolute_max_time; + seconds = diff400 * SECSPER400YEARS; + years = diff400 * 400; + } else { + seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; + years = 1; + } + myy += years; + if (t > absolute_max_time - seconds) + return absolute_max_time; + t += seconds; + } + while (y < myy) { + if (SECSPER400YEARS_FITS && y + 400 <= myy && myy < 0) { + intmax_t diff400 = (myy - y) / 400; + if (INTMAX_MAX / SECSPER400YEARS < diff400) + return absolute_min_time; + seconds = diff400 * SECSPER400YEARS; + years = diff400 * 400; + } else { + seconds = isleap(myy - 1) ? SECSPERLYEAR : SECSPERNYEAR; + years = 1; + } + myy -= years; + if (t < absolute_min_time + seconds) + return absolute_min_time; + t -= seconds; + } + return t; +} + +/* Search for a discontinuity in timezone TZ, in the + timestamps ranging from LOT through HIT. LOT and HIT disagree + about some aspect of timezone. If ONLY_OK, search only for + definedness changes, i.e., localtime succeeds on one side of the + transition but fails on the other side. Return the timestamp just + before the transition from LOT's settings. */ + +static time_t +hunt(timezone_t tz, time_t lot, time_t hit, bool only_ok) +{ + static char * loab; + static ptrdiff_t loabsize; + struct tm lotm; + struct tm tm; + + /* Convert LOT into a broken-down time here, even though our + caller already did that. On platforms without TM_ZONE, + tzname may have been altered since our caller broke down + LOT, and tzname needs to be changed back. */ + bool lotm_ok = my_localtime_rz(tz, &lot, &lotm) != NULL; + bool tm_ok; + char const *ab = lotm_ok ? saveabbr(&loab, &loabsize, &lotm) : NULL; + + for ( ; ; ) { + /* T = average of LOT and HIT, rounding down. + Avoid overflow. */ + int rem_sum = lot % 2 + hit % 2; + time_t t = (rem_sum == 2) - (rem_sum < 0) + lot / 2 + hit / 2; + if (t == lot) + break; + tm_ok = my_localtime_rz(tz, &t, &tm) != NULL; + if (lotm_ok == tm_ok + && (only_ok + || (ab && tm.tm_isdst == lotm.tm_isdst + && delta(&tm, &lotm) == t - lot + && strcmp(abbr(&tm), ab) == 0))) { + lot = t; + if (tm_ok) + lotm = tm; + } else hit = t; + } + return hit; +} + +/* +** Thanks to Paul Eggert for logic used in delta_nonneg. +*/ + +static intmax_t +delta_nonneg(struct tm *newp, struct tm *oldp) +{ + intmax_t oldy = oldp->tm_year; + int cycles = (newp->tm_year - oldy) / YEARSPERREPEAT; + intmax_t sec = SECSPERREPEAT, result = cycles * sec; + int tmy = oldp->tm_year + cycles * YEARSPERREPEAT; + for ( ; tmy < newp->tm_year; ++tmy) + result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE); + result += newp->tm_yday - oldp->tm_yday; + result *= HOURSPERDAY; + result += newp->tm_hour - oldp->tm_hour; + result *= MINSPERHOUR; + result += newp->tm_min - oldp->tm_min; + result *= SECSPERMIN; + result += newp->tm_sec - oldp->tm_sec; + return result; +} + +static intmax_t +delta(struct tm *newp, struct tm *oldp) +{ + return (newp->tm_year < oldp->tm_year + ? -delta_nonneg(oldp, newp) + : delta_nonneg(newp, oldp)); +} + +#ifndef TM_GMTOFF +/* Return A->tm_yday, adjusted to compare it fairly to B->tm_yday. + Assume A and B differ by at most one year. */ +static int +adjusted_yday(struct tm const *a, struct tm const *b) +{ + int yday = a->tm_yday; + if (b->tm_year < a->tm_year) + yday += 365 + isleap_sum(b->tm_year, TM_YEAR_BASE); + return yday; +} +#endif + +/* If A is the broken-down local time and B the broken-down UT for + the same instant, return A's UT offset in seconds, where positive + offsets are east of Greenwich. On failure, return LONG_MIN. + + If T is nonnull, *T is the timestamp that corresponds to A; call + my_gmtime_r and use its result instead of B. Otherwise, B is the + possibly nonnull result of an earlier call to my_gmtime_r. */ +static long +gmtoff(struct tm const *a, ATTRIBUTE_MAYBE_UNUSED time_t *t, + ATTRIBUTE_MAYBE_UNUSED struct tm const *b) +{ +#ifdef TM_GMTOFF + return a->TM_GMTOFF; +#else + struct tm tm; + if (t) + b = my_gmtime_r(t, &tm); + if (! b) + return LONG_MIN; + else { + int ayday = adjusted_yday(a, b); + int byday = adjusted_yday(b, a); + int days = ayday - byday; + long hours = a->tm_hour - b->tm_hour + 24 * days; + long minutes = a->tm_min - b->tm_min + 60 * hours; + long seconds = a->tm_sec - b->tm_sec + 60 * minutes; + return seconds; + } +#endif +} + +static void +show(timezone_t tz, char *zone, time_t t, bool v) +{ + register struct tm * tmp; + register struct tm * gmtmp; + struct tm tm, gmtm; + + printf("%-*s ", longest, zone); + if (v) { + gmtmp = my_gmtime_r(&t, &gmtm); + if (gmtmp == NULL) { + printf(tformat(), t); + printf(_(" (gmtime failed)")); + } else { + dumptime(gmtmp); + printf(" UT"); + } + printf(" = "); + } + tmp = my_localtime_rz(tz, &t, &tm); + if (tmp == NULL) { + printf(tformat(), t); + printf(_(" (localtime failed)")); + } else { + dumptime(tmp); + if (*abbr(tmp) != '\0') + printf(" %s", abbr(tmp)); + if (v) { + long off = gmtoff(tmp, NULL, gmtmp); + printf(" isdst=%d", tmp->tm_isdst); + if (off != LONG_MIN) + printf(" gmtoff=%ld", off); + } + } + printf("\n"); + if (tmp != NULL && *abbr(tmp) != '\0') + abbrok(abbr(tmp), zone); +} + +/* Show timestamps just before and just after a transition between + defined and undefined (or vice versa) in either localtime or + gmtime. These transitions are for timezone TZ with name ZONE, in + the range from LO (with broken-down time LOTMP if that is nonnull) + through HI. LO and HI disagree on definedness. */ + +static void +showextrema(timezone_t tz, char *zone, time_t lo, struct tm *lotmp, time_t hi) +{ + struct tm localtm[2], gmtm[2]; + time_t t, boundary = hunt(tz, lo, hi, true); + bool old = false; + hi = (SECSPERDAY < hi - boundary + ? boundary + SECSPERDAY + : hi + (hi < TIME_T_MAX)); + if (SECSPERDAY < boundary - lo) { + lo = boundary - SECSPERDAY; + lotmp = my_localtime_rz(tz, &lo, &localtm[old]); + } + if (lotmp) + localtm[old] = *lotmp; + else + localtm[old].tm_sec = -1; + if (! my_gmtime_r(&lo, &gmtm[old])) + gmtm[old].tm_sec = -1; + + /* Search sequentially for definedness transitions. Although this + could be sped up by refining 'hunt' to search for either + localtime or gmtime definedness transitions, it hardly seems + worth the trouble. */ + for (t = lo + 1; t < hi; t++) { + bool new = !old; + if (! my_localtime_rz(tz, &t, &localtm[new])) + localtm[new].tm_sec = -1; + if (! my_gmtime_r(&t, &gmtm[new])) + gmtm[new].tm_sec = -1; + if (((localtm[old].tm_sec < 0) != (localtm[new].tm_sec < 0)) + | ((gmtm[old].tm_sec < 0) != (gmtm[new].tm_sec < 0))) { + show(tz, zone, t - 1, true); + show(tz, zone, t, true); + } + old = new; + } +} + +#if HAVE_SNPRINTF +# define my_snprintf snprintf +#else +# include + +/* A substitute for snprintf that is good enough for zdump. */ +ATTRIBUTE_FORMAT((printf, 3, 4)) static int +my_snprintf(char *s, size_t size, char const *format, ...) +{ + int n; + va_list args; + char const *arg; + size_t arglen, slen; + char buf[1024]; + va_start(args, format); + if (strcmp(format, "%s") == 0) { + arg = va_arg(args, char const *); + arglen = strlen(arg); + } else { + n = vsprintf(buf, format, args); + if (n < 0) { + va_end(args); + return n; + } + arg = buf; + arglen = n; + } + slen = arglen < size ? arglen : size - 1; + memcpy(s, arg, slen); + s[slen] = '\0'; + n = arglen <= INT_MAX ? arglen : -1; + va_end(args); + return n; +} +#endif + +/* Store into BUF, of size SIZE, a formatted local time taken from *TM. + Use ISO 8601 format +HH:MM:SS. Omit :SS if SS is zero, and omit + :MM too if MM is also zero. + + Return the length of the resulting string. If the string does not + fit, return the length that the string would have been if it had + fit; do not overrun the output buffer. */ +static int +format_local_time(char *buf, ptrdiff_t size, struct tm const *tm) +{ + int ss = tm->tm_sec, mm = tm->tm_min, hh = tm->tm_hour; + return (ss + ? my_snprintf(buf, size, "%02d:%02d:%02d", hh, mm, ss) + : mm + ? my_snprintf(buf, size, "%02d:%02d", hh, mm) + : my_snprintf(buf, size, "%02d", hh)); +} + +/* Store into BUF, of size SIZE, a formatted UT offset for the + localtime *TM corresponding to time T. Use ISO 8601 format + +HHMMSS, or -HHMMSS for timestamps west of Greenwich; use the + format -00 for unknown UT offsets. If the hour needs more than + two digits to represent, extend the length of HH as needed. + Otherwise, omit SS if SS is zero, and omit MM too if MM is also + zero. + + Return the length of the resulting string, or -1 if the result is + not representable as a string. If the string does not fit, return + the length that the string would have been if it had fit; do not + overrun the output buffer. */ +static int +format_utc_offset(char *buf, ptrdiff_t size, struct tm const *tm, time_t t) +{ + long off = gmtoff(tm, &t, NULL); + char sign = ((off < 0 + || (off == 0 + && (*abbr(tm) == '-' || strcmp(abbr(tm), "zzz") == 0))) + ? '-' : '+'); + long hh; + int mm, ss; + if (off < 0) + { + if (off == LONG_MIN) + return -1; + off = -off; + } + ss = off % 60; + mm = off / 60 % 60; + hh = off / 60 / 60; + return (ss || 100 <= hh + ? my_snprintf(buf, size, "%c%02ld%02d%02d", sign, hh, mm, ss) + : mm + ? my_snprintf(buf, size, "%c%02ld%02d", sign, hh, mm) + : my_snprintf(buf, size, "%c%02ld", sign, hh)); +} + +/* Store into BUF (of size SIZE) a quoted string representation of P. + If the representation's length is less than SIZE, return the + length; the representation is not null terminated. Otherwise + return SIZE, to indicate that BUF is too small. */ +static ptrdiff_t +format_quoted_string(char *buf, ptrdiff_t size, char const *p) +{ + char *b = buf; + ptrdiff_t s = size; + if (!s) + return size; + *b++ = '"', s--; + for (;;) { + char c = *p++; + if (s <= 1) + return size; + switch (c) { + default: *b++ = c, s--; continue; + case '\0': *b++ = '"', s--; return size - s; + case '"': case '\\': break; + case ' ': c = 's'; break; + case '\f': c = 'f'; break; + case '\n': c = 'n'; break; + case '\r': c = 'r'; break; + case '\t': c = 't'; break; + case '\v': c = 'v'; break; + } + *b++ = '\\', *b++ = c, s -= 2; + } +} + +/* Store into BUF (of size SIZE) a timestamp formatted by TIME_FMT. + TM is the broken-down time, T the seconds count, AB the time zone + abbreviation, and ZONE_NAME the zone name. Return true if + successful, false if the output would require more than SIZE bytes. + TIME_FMT uses the same format that strftime uses, with these + additions: + + %f zone name + %L local time as per format_local_time + %Q like "U\t%Z\tD" where U is the UT offset as for format_utc_offset + and D is the isdst flag; except omit D if it is zero, omit %Z if + it equals U, quote and escape %Z if it contains nonalphabetics, + and omit any trailing tabs. */ + +static bool +istrftime(char *buf, ptrdiff_t size, char const *time_fmt, + struct tm const *tm, time_t t, char const *ab, char const *zone_name) +{ + char *b = buf; + ptrdiff_t s = size; + char const *f = time_fmt, *p; + + for (p = f; ; p++) + if (*p == '%' && p[1] == '%') + p++; + else if (!*p + || (*p == '%' + && (p[1] == 'f' || p[1] == 'L' || p[1] == 'Q'))) { + ptrdiff_t formatted_len; + ptrdiff_t f_prefix_len = p - f; + ptrdiff_t f_prefix_copy_size = sumsize(f_prefix_len, 2); + char fbuf[100]; + bool oversized = sizeof fbuf <= f_prefix_copy_size; + char *f_prefix_copy = oversized ? xmalloc(f_prefix_copy_size) : fbuf; + memcpy(f_prefix_copy, f, f_prefix_len); + strcpy(f_prefix_copy + f_prefix_len, "X"); + formatted_len = strftime(b, s, f_prefix_copy, tm); + if (oversized) + free(f_prefix_copy); + if (formatted_len == 0) + return false; + formatted_len--; + b += formatted_len, s -= formatted_len; + if (!*p++) + break; + switch (*p) { + case 'f': + formatted_len = format_quoted_string(b, s, zone_name); + break; + case 'L': + formatted_len = format_local_time(b, s, tm); + break; + case 'Q': + { + bool show_abbr; + int offlen = format_utc_offset(b, s, tm, t); + if (! (0 <= offlen && offlen < s)) + return false; + show_abbr = strcmp(b, ab) != 0; + b += offlen, s -= offlen; + if (show_abbr) { + char const *abp; + ptrdiff_t len; + if (s <= 1) + return false; + *b++ = '\t', s--; + for (abp = ab; is_alpha(*abp); abp++) + continue; + len = (!*abp && *ab + ? my_snprintf(b, s, "%s", ab) + : format_quoted_string(b, s, ab)); + if (s <= len) + return false; + b += len, s -= len; + } + formatted_len + = (tm->tm_isdst + ? my_snprintf(b, s, &"\t\t%d"[show_abbr], tm->tm_isdst) + : 0); + } + break; + } + if (s <= formatted_len) + return false; + b += formatted_len, s -= formatted_len; + f = p + 1; + } + *b = '\0'; + return true; +} + +/* Show a time transition. */ +static void +showtrans(char const *time_fmt, struct tm const *tm, time_t t, char const *ab, + char const *zone_name) +{ + if (!tm) { + printf(tformat(), t); + putchar('\n'); + } else { + char stackbuf[1000]; + ptrdiff_t size = sizeof stackbuf; + char *buf = stackbuf; + char *bufalloc = NULL; + while (! istrftime(buf, size, time_fmt, tm, t, ab, zone_name)) { + size = sumsize(size, size); + free(bufalloc); + buf = bufalloc = xmalloc(size); + } + puts(buf); + free(bufalloc); + } +} + +static char const * +abbr(struct tm const *tmp) +{ +#ifdef TM_ZONE + return tmp->TM_ZONE; +#else +# if HAVE_TZNAME + if (0 <= tmp->tm_isdst && tzname[0 < tmp->tm_isdst]) + return tzname[0 < tmp->tm_isdst]; +# endif + return ""; +#endif +} + +/* +** The code below can fail on certain theoretical systems; +** it works on all known real-world systems as of 2022-01-25. +*/ + +static const char * +tformat(void) +{ +#if HAVE__GENERIC + /* C11-style _Generic is more likely to return the correct + format when distinct types have the same size. */ + char const *fmt = + _Generic(+ (time_t) 0, + int: "%d", long: "%ld", long long: "%lld", + unsigned: "%u", unsigned long: "%lu", + unsigned long long: "%llu", + default: NULL); + if (fmt) + return fmt; + fmt = _Generic((time_t) 0, + intmax_t: "%"PRIdMAX, uintmax_t: "%"PRIuMAX, + default: NULL); + if (fmt) + return fmt; +#endif + if (0 > (time_t) -1) { /* signed */ + if (sizeof(time_t) == sizeof(intmax_t)) + return "%"PRIdMAX; + if (sizeof(time_t) > sizeof(long)) + return "%lld"; + if (sizeof(time_t) > sizeof(int)) + return "%ld"; + return "%d"; + } +#ifdef PRIuMAX + if (sizeof(time_t) == sizeof(uintmax_t)) + return "%"PRIuMAX; +#endif + if (sizeof(time_t) > sizeof(unsigned long)) + return "%llu"; + if (sizeof(time_t) > sizeof(unsigned int)) + return "%lu"; + return "%u"; +} + +static void +dumptime(register const struct tm *timeptr) +{ + static const char wday_name[][4] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static const char mon_name[][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + register int lead; + register int trail; + int DIVISOR = 10; + + /* + ** The packaged localtime_rz and gmtime_r never put out-of-range + ** values in tm_wday or tm_mon, but since this code might be compiled + ** with other (perhaps experimental) versions, paranoia is in order. + */ + printf("%s %s%3d %.2d:%.2d:%.2d ", + ((0 <= timeptr->tm_wday + && timeptr->tm_wday < sizeof wday_name / sizeof wday_name[0]) + ? wday_name[timeptr->tm_wday] : "???"), + ((0 <= timeptr->tm_mon + && timeptr->tm_mon < sizeof mon_name / sizeof mon_name[0]) + ? mon_name[timeptr->tm_mon] : "???"), + timeptr->tm_mday, timeptr->tm_hour, + timeptr->tm_min, timeptr->tm_sec); + trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR; + lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR + + trail / DIVISOR; + trail %= DIVISOR; + if (trail < 0 && lead > 0) { + trail += DIVISOR; + --lead; + } else if (lead < 0 && trail > 0) { + trail -= DIVISOR; + ++lead; + } + if (lead == 0) + printf("%d", trail); + else printf("%d%d", lead, ((trail < 0) ? -trail : trail)); +} diff --git a/vendor/chrono-tz/tz/zic.8 b/vendor/chrono-tz/tz/zic.8 new file mode 100644 index 0000000000000..0ad373a2dd17c --- /dev/null +++ b/vendor/chrono-tz/tz/zic.8 @@ -0,0 +1,894 @@ +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. +.TH zic 8 "" "Time Zone Database" +.SH NAME +zic \- timezone compiler +.SH SYNOPSIS +.B zic +[ +.I option +\&... ] [ +.I filename +\&... ] +.SH DESCRIPTION +.ie '\(lq'' .ds lq \&"\" +.el .ds lq \(lq\" +.ie '\(rq'' .ds rq \&"\" +.el .ds rq \(rq\" +.de q +\\$3\*(lq\\$1\*(rq\\$2 +.. +.ie '\(la'' .ds < < +.el .ds < \(la +.ie '\(ra'' .ds > > +.el .ds > \(ra +.ie \n(.g \{\ +. ds : \: +. ds - \f(CR-\fP +.\} +.el \{\ +. ds : +. ds - \- +.\} +.ds d " degrees +.ds m " minutes +.ds s " seconds +.ds _ " \& +.if t \{\ +. if \n(.g .if c \(de .if c \(fm .if c \(sd \{\ +. ds d \(de +. ds m \(fm +. ds s \(sd +. ds _ \| +. \} +.\} +The +.B zic +program reads text from the file(s) named on the command line +and creates the timezone information format (TZif) files +specified in this input. +If a +.I filename +is +.q "\*-" , +standard input is read. +.SH OPTIONS +.TP +.B "\*-\*-version" +Output version information and exit. +.TP +.B \*-\*-help +Output short usage message and exit. +.TP +.BI "\*-b " bloat +Output backward-compatibility data as specified by +.IR bloat . +If +.I bloat +is +.BR fat , +generate additional data entries that work around potential bugs or +incompatibilities in older software, such as software that mishandles +the 64-bit generated data. +If +.I bloat +is +.BR slim , +keep the output files small; this can help check for the bugs +and incompatibilities. +The default is +.BR slim , +as software that mishandles 64-bit data typically +mishandles timestamps after the year 2038 anyway. +Also see the +.B \*-r +option for another way to alter output size. +.TP +.BI "\*-d " directory +Create time conversion information files in the named directory rather than +in the standard directory named below. +.TP +.BI "\*-l " timezone +Use +.I timezone +as local time. +.B zic +will act as if the input contained a link line of the form +.sp +.ti +2 +.ta \w'Link\0\0'u +\w'\fItimezone\fP\0\0'u +Link \fItimezone\fP localtime +.sp +If +.I timezone +is +.BR \*- , +any already-existing link is removed. +.TP +.BI "\*-L " leapsecondfilename +Read leap second information from the file with the given name. +If this option is not used, +no leap second information appears in output files. +.TP +.BI "\*-p " timezone +Use +.IR timezone 's +rules when handling nonstandard +TZ strings like "EET\*-2EEST" that lack transition rules. +.B zic +will act as if the input contained a link line of the form +.sp +.ti +2 +Link \fItimezone\fP posixrules +.sp +If +.I timezone +is +.q "\*-" +(the default), any already-existing link is removed. +.sp +Unless +.I timezone is +.q "\*-" , +this option is obsolete and poorly supported. +Among other things it should not be used for timestamps after the year 2037, +and it should not be combined with +.B "\*-b slim" +if +.IR timezone 's +transitions are at standard time or Universal Time (UT) instead of local time. +.TP +.BR "\*-r " "[\fB@\fP\fIlo\fP][\fB/@\fP\fIhi\fP]" +Limit the applicability of output files +to timestamps in the range from +.I lo +(inclusive) to +.I hi +(exclusive), where +.I lo +and +.I hi +are possibly signed decimal counts of seconds since the Epoch +(1970-01-01 00:00:00 UTC). +Omitted counts default to extreme values. +The output files use UT offset 0 and abbreviation +.q "\*-00" +in place of the omitted timestamp data. +For example, +.q "zic \*-r @0" +omits data intended for negative timestamps (i.e., before the Epoch), and +.q "zic \*-r @0/@2147483648" +outputs data intended only for nonnegative timestamps that fit into +31-bit signed integers. +On platforms with GNU +.BR date , +.q "zic \*-r @$(date +%s)" +omits data intended for past timestamps. +Although this option typically reduces the output file's size, +the size can increase due to the need to represent the timestamp range +boundaries, particularly if +.I hi +causes a TZif file to contain explicit entries for +.RI pre- hi +transitions rather than concisely representing them +with an extended POSIX.1-2017 TZ string. +Also see the +.B "\*-b slim" +option for another way to shrink output size. +.TP +.BI "\*-R @" hi +Generate redundant trailing explicit transitions for timestamps +that occur less than +.I hi +seconds since the Epoch, even though the transitions could be +more concisely represented via the extended POSIX.1-2017 TZ string. +This option does not affect the represented timestamps. +Although it accommodates nonstandard TZif readers +that ignore the extended POSIX.1-2017 TZ string, +it increases the size of the altered output files. +.TP +.BI "\*-t " file +When creating local time information, put the configuration link in +the named file rather than in the standard location. +.TP +.B \*-v +Be more verbose, and complain about the following situations: +.RS +.PP +The input specifies a link to a link, +something not supported by some older parsers, including +.B zic +itself through release 2022e. +.PP +A year that appears in a data file is outside the range +of representable years. +.PP +A time of 24:00 or more appears in the input. +Pre-1998 versions of +.B zic +prohibit 24:00, and pre-2007 versions prohibit times greater than 24:00. +.PP +A rule goes past the start or end of the month. +Pre-2004 versions of +.B zic +prohibit this. +.PP +A time zone abbreviation uses a +.B %z +format. +Pre-2015 versions of +.B zic +do not support this. +.PP +A timestamp contains fractional seconds. +Pre-2018 versions of +.B zic +do not support this. +.PP +The input contains abbreviations that are mishandled by pre-2018 versions of +.B zic +due to a longstanding coding bug. +These abbreviations include +.q L +for +.q Link , +.q mi +for +.q min , +.q Sa +for +.q Sat , +and +.q Su +for +.q Sun . +.PP +The output file does not contain all the information about the +long-term future of a timezone, because the future cannot be summarized as +an extended POSIX.1-2017 TZ string. For example, as of 2023 this problem +occurs for Morocco's daylight-saving rules, as these rules are based +on predictions for when Ramadan will be observed, something that +an extended POSIX.1-2017 TZ string cannot represent. +.PP +The output contains data that may not be handled properly by client +code designed for older +.B zic +output formats. These compatibility issues affect only timestamps +before 1970 or after the start of 2038. +.PP +The output contains a truncated leap second table, +which can cause some older TZif readers to misbehave. +This can occur if the +.B "\*-L" +option is used, and either an Expires line is present or +the +.B "\*-r" +option is also used. +.PP +The output file contains more than 1200 transitions, +which may be mishandled by some clients. +The current reference client supports at most 2000 transitions; +pre-2014 versions of the reference client support at most 1200 +transitions. +.PP +A time zone abbreviation has fewer than 3 or more than 6 characters. +POSIX requires at least 3, and requires implementations to support +at least 6. +.PP +An output file name contains a byte that is not an ASCII letter, +.q "\*-" , +.q "/" , +or +.q "_" ; +or it contains a file name component that contains more than 14 bytes +or that starts with +.q "\*-" . +.RE +.SH FILES +Input files use the format described in this section; output files use +.BR tzfile (5) +format. +.PP +Input files should be text files, that is, they should be a series of +zero or more lines, each ending in a newline byte and containing at +most 2048 bytes counting the newline, and without any NUL bytes. +The input text's encoding +is typically UTF-8 or ASCII; it should have a unibyte representation +for the POSIX Portable Character Set (PPCS) +\* +and the encoding's non-unibyte characters should consist entirely of +non-PPCS bytes. Non-PPCS characters typically occur only in comments: +although output file names and time zone abbreviations can contain +nearly any character, other software will work better if these are +limited to the restricted syntax described under the +.B \*-v +option. +.PP +Input lines are made up of fields. +Fields are separated from one another by one or more white space characters. +The white space characters are space, form feed, carriage return, newline, +tab, and vertical tab. +Leading and trailing white space on input lines is ignored. +An unquoted sharp character (#) in the input introduces a comment which extends +to the end of the line the sharp character appears on. +White space characters and sharp characters may be enclosed in double quotes +(") if they're to be used as part of a field. +Any line that is blank (after comment stripping) is ignored. +Nonblank lines are expected to be of one of three types: +rule lines, zone lines, and link lines. +.PP +Names must be in English and are case insensitive. +They appear in several contexts, and include month and weekday names +and keywords such as +.BR "maximum" , +.BR "only" , +.BR "Rolling" , +and +.BR "Zone" . +A name can be abbreviated by omitting all but an initial prefix; any +abbreviation must be unambiguous in context. +.PP +A rule line has the form +.nf +.ti +2 +.ta \w'Rule\0\0'u +\w'NAME\0\0'u +\w'FROM\0\0'u +\w'1973\0\0'u +\w'\*-\0\0'u +\w'Apr\0\0'u +\w'lastSun\0\0'u +\w'2:00w\0\0'u +\w'1:00d\0\0'u +.sp +Rule NAME FROM TO \*- IN ON AT SAVE LETTER/S +.sp +For example: +.ti +2 +.sp +Rule US 1967 1973 \*- Apr lastSun 2:00w 1:00d D +.sp +.fi +The fields that make up a rule line are: +.TP +.B NAME +Gives the name of the rule set that contains this line. +The name must start with a character that is neither +an ASCII digit nor +.q \*- +nor +.q + . +To allow for future extensions, +an unquoted name should not contain characters from the set +.ie \n(.g .q \f(CR!$%&\(aq()*,/:;<=>?@[\e]\(ha\(ga{|}\(ti\fP . +.el .ie t .q \f(CW!$%&'()*,/:;<=>?@[\e]^\(ga{|}~\fP . +.el .q !$%&'()*,/:;<=>?@[\e]^`{|}~ . +.TP +.B FROM +Gives the first year in which the rule applies. +Any signed integer year can be supplied; the proleptic Gregorian calendar +is assumed, with year 0 preceding year 1. +Rules can describe times that are not representable as time values, +with the unrepresentable times ignored; this allows rules to be portable +among hosts with differing time value types. +.TP +.B TO +Gives the final year in which the rule applies. +The word +.B maximum +(or an abbreviation) means the indefinite future, and the word +.B only +(or an abbreviation) +may be used to repeat the value of the +.B FROM +field. +.TP +.B \*- +Is a reserved field and should always contain +.q \*- +for compatibility with older versions of +.BR zic . +It was previously known as the +.B TYPE +field, which could contain values to allow a +separate script to further restrict in which +.q types +of years the rule would apply. +.TP +.B IN +Names the month in which the rule takes effect. +Month names may be abbreviated. +.TP +.B ON +Gives the day on which the rule takes effect. +Recognized forms include: +.nf +.in +2 +.sp +.ta \w'Sun<=25\0\0'u +5 the fifth of the month +lastSun the last Sunday in the month +lastMon the last Monday in the month +Sun>=8 first Sunday on or after the eighth +Sun<=25 last Sunday on or before the 25th +.fi +.in +.sp +A weekday name (e.g., +.BR "Sunday" ) +or a weekday name preceded by +.q "last" +(e.g., +.BR "lastSunday" ) +may be abbreviated or spelled out in full. +There must be no white space characters within the +.B ON +field. +The +.q <= +and +.q >= +constructs can result in a day in the neighboring month; +for example, the IN-ON combination +.q "Oct Sun>=31" +stands for the first Sunday on or after October 31, +even if that Sunday occurs in November. +.TP +.B AT +Gives the time of day at which the rule takes effect, +relative to 00:00, the start of a calendar day. +Recognized forms include: +.nf +.in +2 +.sp +.ta \w'00:19:32.13\0\0'u +2 time in hours +2:00 time in hours and minutes +01:28:14 time in hours, minutes, and seconds +00:19:32.13 time with fractional seconds +12:00 midday, 12 hours after 00:00 +15:00 3 PM, 15 hours after 00:00 +24:00 end of day, 24 hours after 00:00 +260:00 260 hours after 00:00 +\*-2:30 2.5 hours before 00:00 +\*- equivalent to 0 +.fi +.in +.sp +Although +.B zic +rounds times to the nearest integer second +(breaking ties to the even integer), the fractions may be useful +to other applications requiring greater precision. +The source format does not specify any maximum precision. +Any of these forms may be followed by the letter +.B w +if the given time is local or +.q "wall clock" +time, +.B s +if the given time is standard time without any adjustment for daylight saving, +or +.B u +(or +.B g +or +.BR z ) +if the given time is universal time; +in the absence of an indicator, +local (wall clock) time is assumed. +These forms ignore leap seconds; for example, +if a leap second occurs at 00:59:60 local time, +.q "1:00" +stands for 3601 seconds after local midnight instead of the usual 3600 seconds. +The intent is that a rule line describes the instants when a +clock/calendar set to the type of time specified in the +.B AT +field would show the specified date and time of day. +.TP +.B SAVE +Gives the amount of time to be added to local standard time when the rule is in +effect, and whether the resulting time is standard or daylight saving. +This field has the same format as the +.B AT +field +except with a different set of suffix letters: +.B s +for standard time and +.B d +for daylight saving time. +The suffix letter is typically omitted, and defaults to +.B s +if the offset is zero and to +.B d +otherwise. +Negative offsets are allowed; in Ireland, for example, daylight saving +time is observed in winter and has a negative offset relative to +Irish Standard Time. +The offset is merely added to standard time; for example, +.B zic +does not distinguish a 10:30 standard time plus an 0:30 +.B SAVE +from a 10:00 standard time plus a 1:00 +.BR SAVE . +.TP +.B LETTER/S +Gives the +.q "variable part" +(for example, the +.q "S" +or +.q "D" +in +.q "EST" +or +.q "EDT" ) +of time zone abbreviations to be used when this rule is in effect. +If this field is +.q \*- , +the variable part is null. +.PP +A zone line has the form +.sp +.nf +.ti +2 +.ta \w'Zone\0\0'u +\w'Asia/Amman\0\0'u +\w'STDOFF\0\0'u +\w'Jordan\0\0'u +\w'FORMAT\0\0'u +Zone NAME STDOFF RULES FORMAT [UNTIL] +.sp +For example: +.sp +.ti +2 +Zone Asia/Amman 2:00 Jordan EE%sT 2017 Oct 27 01:00 +.sp +.fi +The fields that make up a zone line are: +.TP +.B NAME +The name of the timezone. +This is the name used in creating the time conversion information file for the +timezone. +It should not contain a file name component +.q ".\&" +or +.q ".." ; +a file name component is a maximal substring that does not contain +.q "/" . +.TP +.B STDOFF +The amount of time to add to UT to get standard time, +without any adjustment for daylight saving. +This field has the same format as the +.B AT +and +.B SAVE +fields of rule lines, except without suffix letters; +begin the field with a minus sign if time must be subtracted from UT. +.TP +.B RULES +The name of the rules that apply in the timezone or, +alternatively, a field in the same format as a rule-line SAVE column, +giving the amount of time to be added to local standard time +and whether the resulting time is standard or daylight saving. +If this field is +.B \*- +then standard time always applies. +When an amount of time is given, only the sum of standard time and +this amount matters. +.TP +.B FORMAT +The format for time zone abbreviations. +The pair of characters +.B %s +is used to show where the +.q "variable part" +of the time zone abbreviation goes. +Alternatively, a format can use the pair of characters +.B %z +to stand for the UT offset in the form +.RI \(+- hh , +.RI \(+- hhmm , +or +.RI \(+- hhmmss , +using the shortest form that does not lose information, where +.IR hh , +.IR mm , +and +.I ss +are the hours, minutes, and seconds east (+) or west (\-) of UT. +Alternatively, +a slash (/) +separates standard and daylight abbreviations. +To conform to POSIX, a time zone abbreviation should contain only +alphanumeric ASCII characters, +.q "+" +and +.q "\*-". +By convention, the time zone abbreviation +.q "\*-00" +is a placeholder that means local time is unspecified. +.TP +.B UNTIL +The time at which the UT offset or the rule(s) change for a location. +It takes the form of one to four fields YEAR [MONTH [DAY [TIME]]]. +If this is specified, +the time zone information is generated from the given UT offset +and rule change until the time specified, which is interpreted using +the rules in effect just before the transition. +The month, day, and time of day have the same format as the IN, ON, and AT +fields of a rule; trailing fields can be omitted, and default to the +earliest possible value for the missing fields. +.IP +The next line must be a +.q "continuation" +line; this has the same form as a zone line except that the +string +.q "Zone" +and the name are omitted, as the continuation line will +place information starting at the time specified as the +.q "until" +information in the previous line in the file used by the previous line. +Continuation lines may contain +.q "until" +information, just as zone lines do, indicating that the next line is a further +continuation. +.PP +If a zone changes at the same instant that a rule would otherwise take +effect in the earlier zone or continuation line, the rule is ignored. +A zone or continuation line +.I L +with a named rule set starts with standard time by default: +that is, any of +.IR L 's +timestamps preceding +.IR L 's +earliest rule use the rule in effect after +.IR L 's +first transition into standard time. +In a single zone it is an error if two rules take effect at the same +instant, or if two zone changes take effect at the same instant. +.PP +If a continuation line subtracts +.I N +seconds from the UT offset after a transition that would be +interpreted to be later if using the continuation line's UT offset and +rules, the +.q "until" +time of the previous zone or continuation line is interpreted +according to the continuation line's UT offset and rules, and any rule +that would otherwise take effect in the next +.I N +seconds is instead assumed to take effect simultaneously. +For example: +.br +.ne 7 +.nf +.in +2 +.ta \w'# Rule\0\0'u +\w'NAME\0\0'u +\w'FROM\0\0'u +\w'2006\0\0'u +\w'\*-\0\0'u +\w'Oct\0\0'u +\w'lastSun\0\0'u +\w'2:00\0\0'u +\w'SAVE\0\0'u +.sp +# Rule NAME FROM TO \*- IN ON AT SAVE LETTER/S +Rule US 1967 2006 - Oct lastSun 2:00 0 S +Rule US 1967 1973 - Apr lastSun 2:00 1:00 D +.ta \w'# Zone\0\0'u +\w'America/Menominee\0\0'u +\w'STDOFF\0\0'u +\w'RULES\0\0'u +\w'FORMAT\0\0'u +# Zone NAME STDOFF RULES FORMAT [UNTIL] +Zone America/Menominee \*-5:00 \*- EST 1973 Apr 29 2:00 + \*-6:00 US C%sT +.sp +.in +.fi +Here, an incorrect reading would be there were two clock changes on 1973-04-29, +the first from 02:00 EST (\*-05) to 01:00 CST (\*-06), +and the second an hour later from 02:00 CST (\*-06) to 03:00 CDT (\*-05). +However, +.B zic +interprets this more sensibly as a single transition from 02:00 CST (\*-05) to +02:00 CDT (\*-05). +.PP +A link line has the form +.sp +.nf +.ti +2 +.ta \w'Link\0\0'u +\w'Europe/Istanbul\0\0'u +Link TARGET LINK-NAME +.sp +For example: +.sp +.ti +2 +Link Europe/Istanbul Asia/Istanbul +.sp +.fi +The +.B TARGET +field should appear as the +.B NAME +field in some zone line or as the +.B LINK-NAME +field in some link line. +The +.B LINK-NAME +field is used as an alternative name for that zone; +it has the same syntax as a zone line's +.B NAME +field. +Links can chain together, although the behavior is unspecified if a +chain of one or more links does not terminate in a Zone name. +A link line can appear before the line that defines the link target. +For example: +.sp +.ne 3 +.nf +.in +2 +.ta \w'Zone\0\0'u +\w'Greenwich\0\0'u +Link Greenwich G_M_T +Link Etc/GMT Greenwich +Zone Etc/GMT\0\00\0\0\*-\0\0GMT +.sp +.in +.fi +The two links are chained together, and G_M_T, Greenwich, and Etc/GMT +all name the same zone. +.PP +Except for continuation lines, +lines may appear in any order in the input. +However, the behavior is unspecified if multiple zone or link lines +define the same name. +.PP +The file that describes leap seconds can have leap lines and an +expiration line. +Leap lines have the following form: +.nf +.ti +2 +.ta \w'Leap\0\0'u +\w'YEAR\0\0'u +\w'MONTH\0\0'u +\w'DAY\0\0'u +\w'HH:MM:SS\0\0'u +\w'CORR\0\0'u +.sp +Leap YEAR MONTH DAY HH:MM:SS CORR R/S +.sp +For example: +.ti +2 +.sp +Leap 2016 Dec 31 23:59:60 + S +.sp +.fi +The +.BR YEAR , +.BR MONTH , +.BR DAY , +and +.B HH:MM:SS +fields tell when the leap second happened. +The +.B CORR +field +should be +.q "+" +if a second was added +or +.q "\*-" +if a second was skipped. +The +.B R/S +field +should be (an abbreviation of) +.q "Stationary" +if the leap second time given by the other fields should be interpreted as UTC +or +(an abbreviation of) +.q "Rolling" +if the leap second time given by the other fields should be interpreted as +local (wall clock) time. +.PP +Rolling leap seconds were implemented back when it was not +clear whether common practice was rolling or stationary, +with concerns that one would see +Times Square ball drops where there'd be a +.q "3... 2... 1... leap... Happy New Year" +countdown, placing the leap second at +midnight New York time rather than midnight UTC. +However, this countdown style does not seem to have caught on, +which means rolling leap seconds are not used in practice; +also, they are not supported if the +.B \*-r +option is used. +.PP +The expiration line, if present, has the form: +.nf +.ti +2 +.ta \w'Expires\0\0'u +\w'YEAR\0\0'u +\w'MONTH\0\0'u +\w'DAY\0\0'u +.sp +Expires YEAR MONTH DAY HH:MM:SS +.sp +For example: +.ti +2 +.sp +Expires 2020 Dec 28 00:00:00 +.sp +.fi +The +.BR YEAR , +.BR MONTH , +.BR DAY , +and +.B HH:MM:SS +fields give the expiration timestamp in UTC for the leap second table. +.br +.ne 22 +.SH "EXTENDED EXAMPLE" +Here is an extended example of +.B zic +input, intended to illustrate many of its features. +.nf +.in +2 +.ta \w'# Rule\0\0'u +\w'NAME\0\0'u +\w'FROM\0\0'u +\w'1973\0\0'u +\w'\*-\0\0'u +\w'Apr\0\0'u +\w'lastSun\0\0'u +\w'2:00\0\0'u +\w'SAVE\0\0'u +.sp +# Rule NAME FROM TO \*- IN ON AT SAVE LETTER/S +Rule Swiss 1941 1942 \*- May Mon>=1 1:00 1:00 S +Rule Swiss 1941 1942 \*- Oct Mon>=1 2:00 0 \*- +.sp .5 +Rule EU 1977 1980 \*- Apr Sun>=1 1:00u 1:00 S +Rule EU 1977 only \*- Sep lastSun 1:00u 0 \*- +Rule EU 1978 only \*- Oct 1 1:00u 0 \*- +Rule EU 1979 1995 \*- Sep lastSun 1:00u 0 \*- +Rule EU 1981 max \*- Mar lastSun 1:00u 1:00 S +Rule EU 1996 max \*- Oct lastSun 1:00u 0 \*- +.sp +.ta \w'# Zone\0\0'u +\w'Europe/Zurich\0\0'u +\w'0:29:45.50\0\0'u +\w'RULES\0\0'u +\w'FORMAT\0\0'u +# Zone NAME STDOFF RULES FORMAT [UNTIL] +Zone Europe/Zurich 0:34:08 \*- LMT 1853 Jul 16 + 0:29:45.50 \*- BMT 1894 Jun + 1:00 Swiss CE%sT 1981 + 1:00 EU CE%sT +.sp +Link Europe/Zurich Europe/Vaduz +.sp +.in +.fi +In this example, the EU rules are for the European Union +and for its predecessor organization, the European Communities. +The timezone is named Europe/Zurich and it has the alias Europe/Vaduz. +This example says that Zurich was 34 minutes and 8 +seconds east of UT until 1853-07-16 at 00:00, when the legal offset +was changed to +7\*d\*_26\*m\*_22.50\*s, +which works out to 0:29:45.50; +.B zic +treats this by rounding it to 0:29:46. +After 1894-06-01 at 00:00 the UT offset became one hour +and Swiss daylight saving rules (defined with lines beginning with +.q "Rule Swiss") +apply. From 1981 to the present, EU daylight saving rules have +applied, and the UTC offset has remained at one hour. +.PP +In 1941 and 1942, daylight saving time applied from the first Monday +in May at 01:00 to the first Monday in October at 02:00. +The pre-1981 EU daylight-saving rules have no effect +here, but are included for completeness. Since 1981, daylight +saving has begun on the last Sunday in March at 01:00 UTC. +Until 1995 it ended the last Sunday in September at 01:00 UTC, +but this changed to the last Sunday in October starting in 1996. +.PP +For purposes of display, +.q "LMT" +and +.q "BMT" +were initially used, respectively. Since +Swiss rules and later EU rules were applied, the time zone abbreviation +has been CET for standard time and CEST for daylight saving +time. +.SH FILES +.TP +.I /etc/localtime +Default local timezone file. +.TP +.I /usr/share/zoneinfo +Default timezone information directory. +.SH NOTES +For areas with more than two types of local time, +you may need to use local standard time in the +.B AT +field of the earliest transition time's rule to ensure that +the earliest transition time recorded in the compiled file is correct. +.PP +If, +for a particular timezone, +a clock advance caused by the start of daylight saving +coincides with and is equal to +a clock retreat caused by a change in UT offset, +.B zic +produces a single transition to daylight saving at the new UT offset +without any change in local (wall clock) time. +To get separate transitions +use multiple zone continuation lines +specifying transition instants using universal time. +.SH SEE ALSO +.BR tzfile (5), +.BR zdump (8) diff --git a/vendor/chrono-tz/tz/zic.c b/vendor/chrono-tz/tz/zic.c new file mode 100644 index 0000000000000..00f00e307a30f --- /dev/null +++ b/vendor/chrono-tz/tz/zic.c @@ -0,0 +1,3962 @@ +/* Compile .zi time zone data into TZif binary files. */ + +/* +** This file is in the public domain, so clarified as of +** 2006-07-17 by Arthur David Olson. +*/ + +/* Use the system 'time' function, instead of any private replacement. + This avoids creating an unnecessary dependency on localtime.c. */ +#undef EPOCH_LOCAL +#undef EPOCH_OFFSET +#undef RESERVE_STD_EXT_IDS +#undef time_tz + +#include "version.h" +#include "private.h" +#include "tzdir.h" +#include "tzfile.h" + +#include +#include +#include +#include +#include + +typedef int_fast64_t zic_t; +static zic_t const + ZIC_MIN = INT_FAST64_MIN, + ZIC_MAX = INT_FAST64_MAX, + ZIC32_MIN = -1 - (zic_t) 0x7fffffff, + ZIC32_MAX = 0x7fffffff; +#define SCNdZIC SCNdFAST64 + +#ifndef ZIC_MAX_ABBR_LEN_WO_WARN +# define ZIC_MAX_ABBR_LEN_WO_WARN 6 +#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */ + +/* Minimum and maximum years, assuming signed 32-bit time_t. */ +enum { YEAR_32BIT_MIN = 1901, YEAR_32BIT_MAX = 2038 }; + +/* An upper bound on how much a format might grow due to concatenation. */ +enum { FORMAT_LEN_GROWTH_BOUND = 5 }; + +#ifdef HAVE_DIRECT_H +# include +# include +# undef mkdir +# define mkdir(name, mode) _mkdir(name) +#endif + +#ifndef HAVE_GETRANDOM +# ifdef __has_include +# if __has_include() +# include +# endif +# elif 2 < __GLIBC__ + (25 <= __GLIBC_MINOR__) +# include +# endif +# define HAVE_GETRANDOM GRND_RANDOM +#elif HAVE_GETRANDOM +# include +#endif + +#if HAVE_SYS_STAT_H +# include +#endif +#ifdef S_IRUSR +# define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) +#else +# define MKDIR_UMASK 0755 +#endif + +/* The minimum alignment of a type, for pre-C23 platforms. + The __SUNPRO_C test is because Oracle Developer Studio 12.6 lacks + even though __STDC_VERSION__ == 201112. */ +#if __STDC_VERSION__ < 201112 || defined __SUNPRO_C +# define alignof(type) offsetof(struct { char a; type b; }, b) +#elif __STDC_VERSION__ < 202311 +# include +#endif + +/* The maximum length of a text line, including the trailing newline. */ +#ifndef _POSIX2_LINE_MAX +# define _POSIX2_LINE_MAX 2048 +#endif + +/* The type for line numbers. Use PRIdMAX to format them; formerly + there was also "#define PRIdLINENO PRIdMAX" and formats used + PRIdLINENO, but xgettext cannot grok that. */ +typedef intmax_t lineno; + +struct rule { + int r_filenum; + lineno r_linenum; + const char * r_name; + + zic_t r_loyear; /* for example, 1986 */ + zic_t r_hiyear; /* for example, 1986 */ + bool r_hiwasnum; + + int r_month; /* 0..11 */ + + int r_dycode; /* see below */ + int r_dayofmonth; + int r_wday; + + zic_t r_tod; /* time from midnight */ + bool r_todisstd; /* is r_tod standard time? */ + bool r_todisut; /* is r_tod UT? */ + bool r_isdst; /* is this daylight saving time? */ + zic_t r_save; /* offset from standard time */ + const char * r_abbrvar; /* variable part of abbreviation */ + + bool r_todo; /* a rule to do (used in outzone) */ + zic_t r_temp; /* used in outzone */ +}; + +/* +** r_dycode r_dayofmonth r_wday +*/ +enum { + DC_DOM, /* 1..31 */ /* unused */ + DC_DOWGEQ, /* 1..31 */ /* 0..6 (Sun..Sat) */ + DC_DOWLEQ /* 1..31 */ /* 0..6 (Sun..Sat) */ +}; + +struct zone { + int z_filenum; + lineno z_linenum; + + const char * z_name; + zic_t z_stdoff; + char * z_rule; + const char * z_format; + char z_format_specifier; + + bool z_isdst; + zic_t z_save; + + struct rule * z_rules; + ptrdiff_t z_nrules; + + struct rule z_untilrule; + zic_t z_untiltime; +}; + +#if !HAVE_POSIX_DECLS +extern int getopt(int argc, char * const argv[], + const char * options); +extern int link(const char * target, const char * linkname); +extern char * optarg; +extern int optind; +#endif + +#if ! HAVE_SYMLINK +static ssize_t +readlink(char const *restrict file, char *restrict buf, size_t size) +{ + errno = ENOTSUP; + return -1; +} +static int +symlink(char const *target, char const *linkname) +{ + errno = ENOTSUP; + return -1; +} +#endif +#ifndef AT_SYMLINK_FOLLOW +# define linkat(targetdir, target, linknamedir, linkname, flag) \ + (errno = ENOTSUP, -1) +#endif + +static void addtt(zic_t starttime, int type); +static int addtype(zic_t, char const *, bool, bool, bool); +static void leapadd(zic_t, int, int); +static void adjleap(void); +static void associate(void); +static void dolink(const char *, const char *, bool); +static int getfields(char *, char **, int); +static zic_t gethms(const char * string, const char * errstring); +static zic_t getsave(char *, bool *); +static void inexpires(char **, int); +static void infile(int, char const *); +static void inleap(char ** fields, int nfields); +static void inlink(char ** fields, int nfields); +static void inrule(char ** fields, int nfields); +static bool inzcont(char ** fields, int nfields); +static bool inzone(char ** fields, int nfields); +static bool inzsub(char **, int, bool); +static int itssymlink(char const *, int *); +static bool is_alpha(char a); +static char lowerit(char); +static void mkdirs(char const *, bool); +static void newabbr(const char * abbr); +static zic_t oadd(zic_t t1, zic_t t2); +static void outzone(const struct zone * zp, ptrdiff_t ntzones); +static zic_t rpytime(const struct rule * rp, zic_t wantedy); +static bool rulesub(struct rule * rp, + const char * loyearp, const char * hiyearp, + const char * typep, const char * monthp, + const char * dayp, const char * timep); +static zic_t tadd(zic_t t1, zic_t t2); + +/* Bound on length of what %z can expand to. */ +enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 }; + +static int charcnt; +static bool errors; +static bool warnings; +static int filenum; +static int leapcnt; +static bool leapseen; +static zic_t leapminyear; +static zic_t leapmaxyear; +static lineno linenum; +static int max_abbrvar_len = PERCENT_Z_LEN_BOUND; +static int max_format_len; +static zic_t max_year; +static zic_t min_year; +static bool noise; +static int rfilenum; +static lineno rlinenum; +static const char * progname; +static char const * leapsec; +static char *const * main_argv; +static ptrdiff_t timecnt; +static ptrdiff_t timecnt_alloc; +static int typecnt; +static int unspecifiedtype; + +/* +** Line codes. +*/ + +enum { + LC_RULE, + LC_ZONE, + LC_LINK, + LC_LEAP, + LC_EXPIRES +}; + +/* +** Which fields are which on a Zone line. +*/ + +enum { + ZF_NAME = 1, + ZF_STDOFF, + ZF_RULE, + ZF_FORMAT, + ZF_TILYEAR, + ZF_TILMONTH, + ZF_TILDAY, + ZF_TILTIME, + ZONE_MAXFIELDS, + ZONE_MINFIELDS = ZF_TILYEAR +}; + +/* +** Which fields are which on a Zone continuation line. +*/ + +enum { + ZFC_STDOFF, + ZFC_RULE, + ZFC_FORMAT, + ZFC_TILYEAR, + ZFC_TILMONTH, + ZFC_TILDAY, + ZFC_TILTIME, + ZONEC_MAXFIELDS, + ZONEC_MINFIELDS = ZFC_TILYEAR +}; + +/* +** Which files are which on a Rule line. +*/ + +enum { + RF_NAME = 1, + RF_LOYEAR, + RF_HIYEAR, + RF_COMMAND, + RF_MONTH, + RF_DAY, + RF_TOD, + RF_SAVE, + RF_ABBRVAR, + RULE_FIELDS +}; + +/* +** Which fields are which on a Link line. +*/ + +enum { + LF_TARGET = 1, + LF_LINKNAME, + LINK_FIELDS +}; + +/* +** Which fields are which on a Leap line. +*/ + +enum { + LP_YEAR = 1, + LP_MONTH, + LP_DAY, + LP_TIME, + LP_CORR, + LP_ROLL, + LEAP_FIELDS, + + /* Expires lines are like Leap lines, except without CORR and ROLL fields. */ + EXPIRES_FIELDS = LP_TIME + 1 +}; + +/* The maximum number of fields on any of the above lines. + (The "+"s pacify gcc -Wenum-compare.) */ +enum { + MAX_FIELDS = max(max(+RULE_FIELDS, +LINK_FIELDS), + max(+LEAP_FIELDS, +EXPIRES_FIELDS)) +}; + +/* +** Year synonyms. +*/ + +enum { + YR_MINIMUM, /* "minimum" is for backward compatibility only */ + YR_MAXIMUM, + YR_ONLY +}; + +static struct rule * rules; +static ptrdiff_t nrules; /* number of rules */ +static ptrdiff_t nrules_alloc; + +static struct zone * zones; +static ptrdiff_t nzones; /* number of zones */ +static ptrdiff_t nzones_alloc; + +struct link { + int l_filenum; + lineno l_linenum; + const char * l_target; + const char * l_linkname; +}; + +static struct link * links; +static ptrdiff_t nlinks; +static ptrdiff_t nlinks_alloc; + +struct lookup { + const char * l_word; + const int l_value; +}; + +static struct lookup const * byword(const char * string, + const struct lookup * lp); + +static struct lookup const zi_line_codes[] = { + { "Rule", LC_RULE }, + { "Zone", LC_ZONE }, + { "Link", LC_LINK }, + { NULL, 0 } +}; +static struct lookup const leap_line_codes[] = { + { "Leap", LC_LEAP }, + { "Expires", LC_EXPIRES }, + { NULL, 0} +}; + +static struct lookup const mon_names[] = { + { "January", TM_JANUARY }, + { "February", TM_FEBRUARY }, + { "March", TM_MARCH }, + { "April", TM_APRIL }, + { "May", TM_MAY }, + { "June", TM_JUNE }, + { "July", TM_JULY }, + { "August", TM_AUGUST }, + { "September", TM_SEPTEMBER }, + { "October", TM_OCTOBER }, + { "November", TM_NOVEMBER }, + { "December", TM_DECEMBER }, + { NULL, 0 } +}; + +static struct lookup const wday_names[] = { + { "Sunday", TM_SUNDAY }, + { "Monday", TM_MONDAY }, + { "Tuesday", TM_TUESDAY }, + { "Wednesday", TM_WEDNESDAY }, + { "Thursday", TM_THURSDAY }, + { "Friday", TM_FRIDAY }, + { "Saturday", TM_SATURDAY }, + { NULL, 0 } +}; + +static struct lookup const lasts[] = { + { "last-Sunday", TM_SUNDAY }, + { "last-Monday", TM_MONDAY }, + { "last-Tuesday", TM_TUESDAY }, + { "last-Wednesday", TM_WEDNESDAY }, + { "last-Thursday", TM_THURSDAY }, + { "last-Friday", TM_FRIDAY }, + { "last-Saturday", TM_SATURDAY }, + { NULL, 0 } +}; + +static struct lookup const begin_years[] = { + { "minimum", YR_MINIMUM }, + { NULL, 0 } +}; + +static struct lookup const end_years[] = { + { "maximum", YR_MAXIMUM }, + { "only", YR_ONLY }, + { NULL, 0 } +}; + +static struct lookup const leap_types[] = { + { "Rolling", true }, + { "Stationary", false }, + { NULL, 0 } +}; + +static const int len_months[2][MONSPERYEAR] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +static const int len_years[2] = { + DAYSPERNYEAR, DAYSPERLYEAR +}; + +static struct attype { + zic_t at; + bool dontmerge; + unsigned char type; +} * attypes; +static zic_t utoffs[TZ_MAX_TYPES]; +static char isdsts[TZ_MAX_TYPES]; +static unsigned char desigidx[TZ_MAX_TYPES]; +static bool ttisstds[TZ_MAX_TYPES]; +static bool ttisuts[TZ_MAX_TYPES]; +static char chars[TZ_MAX_CHARS]; +static zic_t trans[TZ_MAX_LEAPS]; +static zic_t corr[TZ_MAX_LEAPS]; +static char roll[TZ_MAX_LEAPS]; + +/* +** Memory allocation. +*/ + +ATTRIBUTE_NORETURN static void +memory_exhausted(const char *msg) +{ + fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg); + exit(EXIT_FAILURE); +} + +ATTRIBUTE_NORETURN static void +size_overflow(void) +{ + memory_exhausted(_("size overflow")); +} + +ATTRIBUTE_REPRODUCIBLE static ptrdiff_t +size_sum(size_t a, size_t b) +{ +#ifdef ckd_add + ptrdiff_t sum; + if (!ckd_add(&sum, a, b) && sum <= INDEX_MAX) + return sum; +#else + if (a <= INDEX_MAX && b <= INDEX_MAX - a) + return a + b; +#endif + size_overflow(); +} + +ATTRIBUTE_REPRODUCIBLE static ptrdiff_t +size_product(ptrdiff_t nitems, ptrdiff_t itemsize) +{ +#ifdef ckd_mul + ptrdiff_t product; + if (!ckd_mul(&product, nitems, itemsize) && product <= INDEX_MAX) + return product; +#else + ptrdiff_t nitems_max = INDEX_MAX / itemsize; + if (nitems <= nitems_max) + return nitems * itemsize; +#endif + size_overflow(); +} + +ATTRIBUTE_REPRODUCIBLE static ptrdiff_t +align_to(ptrdiff_t size, ptrdiff_t alignment) +{ + ptrdiff_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits); + return sum & ~lo_bits; +} + +#if !HAVE_STRDUP +static char * +strdup(char const *str) +{ + char *result = malloc(strlen(str) + 1); + return result ? strcpy(result, str) : result; +} +#endif + +static void * +memcheck(void *ptr) +{ + if (ptr == NULL) + memory_exhausted(strerror(HAVE_MALLOC_ERRNO ? errno : ENOMEM)); + return ptr; +} + +ATTRIBUTE_MALLOC static void * +emalloc(size_t size) +{ + return memcheck(malloc(size)); +} + +static void * +erealloc(void *ptr, size_t size) +{ + return memcheck(realloc(ptr, size)); +} + +ATTRIBUTE_MALLOC static char * +estrdup(char const *str) +{ + return memcheck(strdup(str)); +} + +static ptrdiff_t +grow_nitems_alloc(ptrdiff_t *nitems_alloc, ptrdiff_t itemsize) +{ + ptrdiff_t addend = (*nitems_alloc >> 1) + 1; +#if defined ckd_add && defined ckd_mul + ptrdiff_t product; + if (!ckd_add(nitems_alloc, *nitems_alloc, addend) + && !ckd_mul(&product, *nitems_alloc, itemsize) && product <= INDEX_MAX) + return product; +#else + if (*nitems_alloc <= ((INDEX_MAX - 1) / 3 * 2) / itemsize) { + *nitems_alloc += addend; + return *nitems_alloc * itemsize; + } +#endif + memory_exhausted(_("integer overflow")); +} + +static void * +growalloc(void *ptr, ptrdiff_t itemsize, ptrdiff_t nitems, + ptrdiff_t *nitems_alloc) +{ + return (nitems < *nitems_alloc + ? ptr + : erealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize))); +} + +/* +** Error handling. +*/ + +/* In most of the code, an input file name is represented by its index + into the main argument vector, except that LEAPSEC_FILENUM stands + for leapsec and COMMAND_LINE_FILENUM stands for the command line. */ +enum { LEAPSEC_FILENUM = -2, COMMAND_LINE_FILENUM = -1 }; + +/* Return the name of the Ith input file, for diagnostics. */ +static char const * +filename(int i) +{ + if (i == COMMAND_LINE_FILENUM) + return _("command line"); + else { + char const *fname = i == LEAPSEC_FILENUM ? leapsec : main_argv[i]; + return strcmp(fname, "-") == 0 ? _("standard input") : fname; + } +} + +static void +eats(int fnum, lineno num, int rfnum, lineno rnum) +{ + filenum = fnum; + linenum = num; + rfilenum = rfnum; + rlinenum = rnum; +} + +static void +eat(int fnum, lineno num) +{ + eats(fnum, num, 0, -1); +} + +ATTRIBUTE_FORMAT((printf, 1, 0)) static void +verror(const char *const string, va_list args) +{ + /* + ** Match the format of "cc" to allow sh users to + ** zic ... 2>&1 | error -t "*" -v + ** on BSD systems. + */ + if (filenum) + fprintf(stderr, _("\"%s\", line %"PRIdMAX": "), + filename(filenum), linenum); + vfprintf(stderr, string, args); + if (rfilenum) + fprintf(stderr, _(" (rule from \"%s\", line %"PRIdMAX")"), + filename(rfilenum), rlinenum); + fprintf(stderr, "\n"); +} + +ATTRIBUTE_FORMAT((printf, 1, 2)) static void +error(const char *const string, ...) +{ + va_list args; + va_start(args, string); + verror(string, args); + va_end(args); + errors = true; +} + +ATTRIBUTE_FORMAT((printf, 1, 2)) static void +warning(const char *const string, ...) +{ + va_list args; + fprintf(stderr, _("warning: ")); + va_start(args, string); + verror(string, args); + va_end(args); + warnings = true; +} + +/* Close STREAM. If it had an I/O error, report it against DIR/NAME, + remove TEMPNAME if nonnull, and then exit. */ +static void +close_file(FILE *stream, char const *dir, char const *name, + char const *tempname) +{ + char const *e = (ferror(stream) ? _("I/O error") + : fclose(stream) != 0 ? strerror(errno) : NULL); + if (e) { + fprintf(stderr, "%s: %s%s%s%s%s\n", progname, + dir ? dir : "", dir ? "/" : "", + name ? name : "", name ? ": " : "", + e); + if (tempname) + remove(tempname); + exit(EXIT_FAILURE); + } +} + +ATTRIBUTE_NORETURN static void +usage(FILE *stream, int status) +{ + fprintf(stream, + _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n" + "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]" + " [ -L leapseconds ] \\\n" + "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R '@hi' ] \\\n" + "\t[ -t localtime-link ] \\\n" + "\t[ filename ... ]\n\n" + "Report bugs to %s.\n"), + progname, progname, REPORT_BUGS_TO); + if (status == EXIT_SUCCESS) + close_file(stream, NULL, NULL, NULL); + exit(status); +} + +/* Change the working directory to DIR, possibly creating DIR and its + ancestors. After this is done, all files are accessed with names + relative to DIR. */ +static void +change_directory(char const *dir) +{ + if (chdir(dir) != 0) { + int chdir_errno = errno; + if (chdir_errno == ENOENT) { + mkdirs(dir, false); + chdir_errno = chdir(dir) == 0 ? 0 : errno; + } + if (chdir_errno != 0) { + fprintf(stderr, _("%s: Can't chdir to %s: %s\n"), + progname, dir, strerror(chdir_errno)); + exit(EXIT_FAILURE); + } + } +} + +/* Compare the two links A and B, for a stable sort by link name. */ +static int +qsort_linkcmp(void const *a, void const *b) +{ + struct link const *l = a; + struct link const *m = b; + int cmp = strcmp(l->l_linkname, m->l_linkname); + if (cmp) + return cmp; + + /* The link names are the same. Make the sort stable by comparing + file numbers (where subtraction cannot overflow) and possibly + line numbers (where it can). */ + cmp = l->l_filenum - m->l_filenum; + if (cmp) + return cmp; + return (l->l_linenum > m->l_linenum) - (l->l_linenum < m->l_linenum); +} + +/* Compare the string KEY to the link B, for bsearch. */ +static int +bsearch_linkcmp(void const *key, void const *b) +{ + struct link const *m = b; + return strcmp(key, m->l_linkname); +} + +/* Make the links specified by the Link lines. */ +static void +make_links(void) +{ + ptrdiff_t i, j, nalinks, pass_size; + if (1 < nlinks) + qsort(links, nlinks, sizeof *links, qsort_linkcmp); + + /* Ignore each link superseded by a later link with the same name. */ + j = 0; + for (i = 0; i < nlinks; i++) { + while (i + 1 < nlinks + && strcmp(links[i].l_linkname, links[i + 1].l_linkname) == 0) + i++; + links[j++] = links[i]; + } + nlinks = pass_size = j; + + /* Walk through the link array making links. However, + if a link's target has not been made yet, append a copy to the + end of the array. The end of the array will gradually fill + up with a small sorted subsequence of not-yet-made links. + nalinks counts all the links in the array, including copies. + When we reach the copied subsequence, it may still contain + a link to a not-yet-made link, so the process repeats. + At any given point in time, the link array consists of the + following subregions, where 0 <= i <= j <= nalinks and + 0 <= nlinks <= nalinks: + + 0 .. (i - 1): + links that either have been made, or have been copied to a + later point point in the array (this later point can be in + any of the three subregions) + i .. (j - 1): + not-yet-made links for this pass + j .. (nalinks - 1): + not-yet-made links that this pass has skipped because + they were links to not-yet-made links + + The first subregion might not be sorted if nlinks < i; + the other two subregions are sorted. This algorithm does + not alter entries 0 .. (nlinks - 1), which remain sorted. + + If there are L links, this algorithm is O(C*L*log(L)) where + C is the length of the longest link chain. Usually C is + short (e.g., 3) though its worst-case value is L. */ + + j = nalinks = nlinks; + + for (i = 0; i < nalinks; i++) { + struct link *l; + + eat(links[i].l_filenum, links[i].l_linenum); + + /* If this pass examined all its links, start the next pass. */ + if (i == j) { + if (nalinks - i == pass_size) { + error(_("\"Link %s %s\" is part of a link cycle"), + links[i].l_target, links[i].l_linkname); + break; + } + j = nalinks; + pass_size = nalinks - i; + } + + /* Diagnose self links, which the cycle detection algorithm would not + otherwise catch. */ + if (strcmp(links[i].l_target, links[i].l_linkname) == 0) { + error(_("link %s targets itself"), links[i].l_target); + continue; + } + + /* Make this link unless its target has not been made yet. */ + l = bsearch(links[i].l_target, &links[i + 1], j - (i + 1), + sizeof *links, bsearch_linkcmp); + if (!l) + l = bsearch(links[i].l_target, &links[j], nalinks - j, + sizeof *links, bsearch_linkcmp); + if (!l) + dolink(links[i].l_target, links[i].l_linkname, false); + else { + /* The link target has not been made yet; copy the link to the end. */ + links = growalloc(links, sizeof *links, nalinks, &nlinks_alloc); + links[nalinks++] = links[i]; + } + + if (noise && i < nlinks) { + if (l) + warning(_("link %s targeting link %s mishandled by pre-2023 zic"), + links[i].l_linkname, links[i].l_target); + else if (bsearch(links[i].l_target, links, nlinks, sizeof *links, + bsearch_linkcmp)) + warning(_("link %s targeting link %s"), + links[i].l_linkname, links[i].l_target); + } + } +} + +/* Simple signal handling: just set a flag that is checked + periodically outside critical sections. To set up the handler, + prefer sigaction if available to close a signal race. */ + +static sig_atomic_t got_signal; + +static void +signal_handler(int sig) +{ +#ifndef SA_SIGINFO + signal(sig, signal_handler); +#endif + got_signal = sig; +} + +/* Arrange for SIGINT etc. to be caught by the handler. */ +static void +catch_signals(void) +{ + static int const signals[] = { +#ifdef SIGHUP + SIGHUP, +#endif + SIGINT, +#ifdef SIGPIPE + SIGPIPE, +#endif + SIGTERM + }; + int i; + for (i = 0; i < sizeof signals / sizeof signals[0]; i++) { +#ifdef SA_SIGINFO + struct sigaction act0, act; + act.sa_handler = signal_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(signals[i], &act, &act0) == 0 + && ! (act0.sa_flags & SA_SIGINFO) && act0.sa_handler == SIG_IGN) { + sigaction(signals[i], &act0, NULL); + got_signal = 0; + } +#else + if (signal(signals[i], signal_handler) == SIG_IGN) { + signal(signals[i], SIG_IGN); + got_signal = 0; + } +#endif + } +} + +/* If a signal has arrived, terminate zic with appropriate status. */ +static void +check_for_signal(void) +{ + int sig = got_signal; + if (sig) { + signal(sig, SIG_DFL); + raise(sig); + abort(); /* A bug in 'raise'. */ + } +} + +enum { TIME_T_BITS_IN_FILE = 64 }; + +/* The minimum and maximum values representable in a TZif file. */ +static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE); +static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE); + +/* The minimum, and one less than the maximum, values specified by + the -r option. These default to MIN_TIME and MAX_TIME. */ +static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE); +static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE); + +/* The time specified by the -R option, defaulting to MIN_TIME; + or lo_time, whichever is greater. */ +static zic_t redundant_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE); + +/* The time specified by an Expires line, or negative if no such line. */ +static zic_t leapexpires = -1; + +/* Set the time range of the output to TIMERANGE. + Return true if successful. */ +static bool +timerange_option(char *timerange) +{ + intmax_t lo = min_time, hi = max_time; + char *lo_end = timerange, *hi_end; + if (*timerange == '@') { + errno = 0; + lo = strtoimax(timerange + 1, &lo_end, 10); + if (lo_end == timerange + 1 || (lo == INTMAX_MAX && errno == ERANGE)) + return false; + } + hi_end = lo_end; + if (lo_end[0] == '/' && lo_end[1] == '@') { + errno = 0; + hi = strtoimax(lo_end + 2, &hi_end, 10); + if (hi_end == lo_end + 2 || hi == INTMAX_MIN) + return false; + hi -= ! (hi == INTMAX_MAX && errno == ERANGE); + } + if (*hi_end || hi < lo || max_time < lo || hi < min_time) + return false; + lo_time = max(lo, min_time); + hi_time = min(hi, max_time); + return true; +} + +/* Generate redundant time stamps up to OPT. Return true if successful. */ +static bool +redundant_time_option(char *opt) +{ + if (*opt == '@') { + intmax_t redundant; + char *opt_end; + redundant = strtoimax(opt + 1, &opt_end, 10); + if (opt_end != opt + 1 && !*opt_end) { + redundant_time = max(redundant_time, redundant); + return true; + } + } + return false; +} + +static const char * psxrules; +static const char * lcltime; +static const char * directory; +static const char * tzdefault; + +/* -1 if the TZif output file should be slim, 0 if default, 1 if the + output should be fat for backward compatibility. ZIC_BLOAT_DEFAULT + determines the default. */ +static int bloat; + +static bool +want_bloat(void) +{ + return 0 <= bloat; +} + +#ifndef ZIC_BLOAT_DEFAULT +# define ZIC_BLOAT_DEFAULT "slim" +#endif + +int +main(int argc, char **argv) +{ + register int c, k; + register ptrdiff_t i, j; + bool timerange_given = false; + +#ifdef S_IWGRP + umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); +#endif +#if HAVE_GETTEXT + setlocale(LC_ALL, ""); +# ifdef TZ_DOMAINDIR + bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); +# endif /* defined TEXTDOMAINDIR */ + textdomain(TZ_DOMAIN); +#endif /* HAVE_GETTEXT */ + main_argv = argv; + progname = argv[0] ? argv[0] : "zic"; + if (TYPE_BIT(zic_t) < 64) { + fprintf(stderr, "%s: %s\n", progname, + _("wild compilation-time specification of zic_t")); + return EXIT_FAILURE; + } + for (k = 1; k < argc; k++) + if (strcmp(argv[k], "--version") == 0) { + printf("zic %s%s\n", PKGVERSION, TZVERSION); + close_file(stdout, NULL, NULL, NULL); + return EXIT_SUCCESS; + } else if (strcmp(argv[k], "--help") == 0) { + usage(stdout, EXIT_SUCCESS); + } + while ((c = getopt(argc, argv, "b:d:l:L:p:r:R:st:vy:")) != EOF + && c != -1) + switch (c) { + default: + usage(stderr, EXIT_FAILURE); + case 'b': + if (strcmp(optarg, "slim") == 0) { + if (0 < bloat) + error(_("incompatible -b options")); + bloat = -1; + } else if (strcmp(optarg, "fat") == 0) { + if (bloat < 0) + error(_("incompatible -b options")); + bloat = 1; + } else + error(_("invalid option: -b '%s'"), optarg); + break; + case 'd': + if (directory == NULL) + directory = optarg; + else { + fprintf(stderr, + _("%s: More than one -d option" + " specified\n"), + progname); + return EXIT_FAILURE; + } + break; + case 'l': + if (lcltime == NULL) + lcltime = optarg; + else { + fprintf(stderr, + _("%s: More than one -l option" + " specified\n"), + progname); + return EXIT_FAILURE; + } + break; + case 'p': + if (psxrules == NULL) + psxrules = optarg; + else { + fprintf(stderr, + _("%s: More than one -p option" + " specified\n"), + progname); + return EXIT_FAILURE; + } + break; + case 't': + if (tzdefault != NULL) { + fprintf(stderr, + _("%s: More than one -t option" + " specified\n"), + progname); + return EXIT_FAILURE; + } + tzdefault = optarg; + break; + case 'y': + warning(_("-y ignored")); + break; + case 'L': + if (leapsec == NULL) + leapsec = optarg; + else { + fprintf(stderr, + _("%s: More than one -L option" + " specified\n"), + progname); + return EXIT_FAILURE; + } + break; + case 'v': + noise = true; + break; + case 'r': + if (timerange_given) { + fprintf(stderr, + _("%s: More than one -r option" + " specified\n"), + progname); + return EXIT_FAILURE; + } + if (! timerange_option(optarg)) { + fprintf(stderr, + _("%s: invalid time range: %s\n"), + progname, optarg); + return EXIT_FAILURE; + } + timerange_given = true; + break; + case 'R': + if (! redundant_time_option(optarg)) { + fprintf(stderr, _("%s: invalid time: %s\n"), + progname, optarg); + return EXIT_FAILURE; + } + break; + case 's': + warning(_("-s ignored")); + break; + } + if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) + usage(stderr, EXIT_FAILURE); /* usage message by request */ + if (hi_time + (hi_time < ZIC_MAX) < redundant_time) { + fprintf(stderr, _("%s: -R time exceeds -r cutoff\n"), progname); + return EXIT_FAILURE; + } + if (redundant_time < lo_time) + redundant_time = lo_time; + if (bloat == 0) { + static char const bloat_default[] = ZIC_BLOAT_DEFAULT; + if (strcmp(bloat_default, "slim") == 0) + bloat = -1; + else if (strcmp(bloat_default, "fat") == 0) + bloat = 1; + else + abort(); /* Configuration error. */ + } + if (directory == NULL) + directory = TZDIR; + if (tzdefault == NULL) + tzdefault = TZDEFAULT; + + if (optind < argc && leapsec != NULL) { + infile(LEAPSEC_FILENUM, leapsec); + adjleap(); + } + + for (k = optind; k < argc; k++) + infile(k, argv[k]); + if (errors) + return EXIT_FAILURE; + associate(); + change_directory(directory); + catch_signals(); + for (i = 0; i < nzones; i = j) { + /* + ** Find the next non-continuation zone entry. + */ + for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) + continue; + outzone(&zones[i], j - i); + } + make_links(); + if (lcltime != NULL) { + eat(COMMAND_LINE_FILENUM, 1); + dolink(lcltime, tzdefault, true); + } + if (psxrules != NULL) { + eat(COMMAND_LINE_FILENUM, 1); + dolink(psxrules, TZDEFRULES, true); + } + if (warnings && (ferror(stderr) || fclose(stderr) != 0)) + return EXIT_FAILURE; + return errors ? EXIT_FAILURE : EXIT_SUCCESS; +} + +static bool +componentcheck(char const *name, char const *component, + char const *component_end) +{ + enum { component_len_max = 14 }; + ptrdiff_t component_len = component_end - component; + if (component_len == 0) { + if (!*name) + error(_("empty file name")); + else + error(_(component == name + ? "file name '%s' begins with '/'" + : *component_end + ? "file name '%s' contains '//'" + : "file name '%s' ends with '/'"), + name); + return false; + } + if (0 < component_len && component_len <= 2 + && component[0] == '.' && component_end[-1] == '.') { + int len = component_len; + error(_("file name '%s' contains '%.*s' component"), + name, len, component); + return false; + } + if (noise) { + if (0 < component_len && component[0] == '-') + warning(_("file name '%s' component contains leading '-'"), + name); + if (component_len_max < component_len) + warning(_("file name '%s' contains overlength component" + " '%.*s...'"), + name, component_len_max, component); + } + return true; +} + +static bool +namecheck(const char *name) +{ + register char const *cp; + + /* Benign characters in a portable file name. */ + static char const benign[] = + "-/_" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + /* Non-control chars in the POSIX portable character set, + excluding the benign characters. */ + static char const printable_and_not_benign[] = + " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~"; + + register char const *component = name; + for (cp = name; *cp; cp++) { + unsigned char c = *cp; + if (noise && !strchr(benign, c)) { + warning((strchr(printable_and_not_benign, c) + ? _("file name '%s' contains byte '%c'") + : _("file name '%s' contains byte '\\%o'")), + name, c); + } + if (c == '/') { + if (!componentcheck(name, component, cp)) + return false; + component = cp + 1; + } + } + return componentcheck(name, component, cp); +} + +/* Return a random uint_fast64_t. */ +static uint_fast64_t +get_rand_u64(void) +{ +#if HAVE_GETRANDOM + static uint_fast64_t entropy_buffer[max(1, 256 / sizeof(uint_fast64_t))]; + static int nwords; + if (!nwords) { + ssize_t s; + do + s = getrandom(entropy_buffer, sizeof entropy_buffer, 0); + while (s < 0 && errno == EINTR); + + nwords = s < 0 ? -1 : s / sizeof *entropy_buffer; + } + if (0 < nwords) + return entropy_buffer[--nwords]; +#endif + + /* getrandom didn't work, so fall back on portable code that is + not the best because the seed isn't cryptographically random and + 'rand' might not be cryptographically secure. */ + { + static bool initialized; + if (!initialized) { + srand(time(NULL)); + initialized = true; + } + } + + /* Return a random number if rand() yields a random number and in + the typical case where RAND_MAX is one less than a power of two. + In other cases this code yields a sort-of-random number. */ + { + uint_fast64_t rand_max = RAND_MAX, + nrand = rand_max < UINT_FAST64_MAX ? rand_max + 1 : 0, + rmod = INT_MAX < UINT_FAST64_MAX ? 0 : UINT_FAST64_MAX / nrand + 1, + r = 0, rmax = 0; + + do { + uint_fast64_t rmax1 = rmax; + if (rmod) { + /* Avoid signed integer overflow on theoretical platforms + where uint_fast64_t promotes to int. */ + rmax1 %= rmod; + r %= rmod; + } + rmax1 = nrand * rmax1 + rand_max; + r = nrand * r + rand(); + rmax = rmax < rmax1 ? rmax1 : UINT_FAST64_MAX; + } while (rmax < UINT_FAST64_MAX); + + return r; + } +} + +/* Generate a randomish name in the same directory as *NAME. If + *NAMEALLOC, put the name into *NAMEALLOC which is assumed to be + that returned by a previous call and is thus already almost set up + and equal to *NAME; otherwise, allocate a new name and put its + address into both *NAMEALLOC and *NAME. */ +static void +random_dirent(char const **name, char **namealloc) +{ + char const *src = *name; + char *dst = *namealloc; + static char const prefix[] = ".zic"; + static char const alphabet[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; + enum { prefixlen = sizeof prefix - 1, alphabetlen = sizeof alphabet - 1 }; + int suffixlen = 6; + char const *lastslash = strrchr(src, '/'); + ptrdiff_t dirlen = lastslash ? lastslash + 1 - src : 0; + int i; + uint_fast64_t r; + uint_fast64_t base = alphabetlen; + + /* BASE**6 */ + uint_fast64_t base__6 = base * base * base * base * base * base; + + /* The largest uintmax_t that is a multiple of BASE**6. Any random + uintmax_t value that is this value or greater, yields a biased + remainder when divided by BASE**6. UNFAIR_MIN equals the + mathematical value of ((UINTMAX_MAX + 1) - (UINTMAX_MAX + 1) % BASE**6) + computed without overflow. */ + uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6); + + if (!dst) { + dst = emalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); + memcpy(dst, src, dirlen); + memcpy(dst + dirlen, prefix, prefixlen); + dst[dirlen + prefixlen + suffixlen] = '\0'; + *name = *namealloc = dst; + } + + do + r = get_rand_u64(); + while (unfair_min <= r); + + for (i = 0; i < suffixlen; i++) { + dst[dirlen + prefixlen + i] = alphabet[r % alphabetlen]; + r /= alphabetlen; + } +} + +/* Prepare to write to the file *OUTNAME, using *TEMPNAME to store the + name of the temporary file that will eventually be renamed to + *OUTNAME. Assign the temporary file's name to both *OUTNAME and + *TEMPNAME. If *TEMPNAME is null, allocate the name of any such + temporary file; otherwise, reuse *TEMPNAME's storage, which is + already set up and only needs its trailing suffix updated. */ +static FILE * +open_outfile(char const **outname, char **tempname) +{ +#if __STDC_VERSION__ < 201112 + static char const fopen_mode[] = "wb"; +#else + static char const fopen_mode[] = "wbx"; +#endif + + FILE *fp; + bool dirs_made = false; + if (!*tempname) + random_dirent(outname, tempname); + + while (! (fp = fopen(*outname, fopen_mode))) { + int fopen_errno = errno; + if (fopen_errno == ENOENT && !dirs_made) { + mkdirs(*outname, true); + dirs_made = true; + } else if (fopen_errno == EEXIST) + random_dirent(outname, tempname); + else { + fprintf(stderr, _("%s: Can't create %s/%s: %s\n"), + progname, directory, *outname, strerror(fopen_errno)); + exit(EXIT_FAILURE); + } + } + + return fp; +} + +/* If TEMPNAME, the result is in the temporary file TEMPNAME even + though the user wanted it in NAME, so rename TEMPNAME to NAME. + Report an error and exit if there is trouble. Also, free TEMPNAME. */ +static void +rename_dest(char *tempname, char const *name) +{ + if (tempname) { + if (rename(tempname, name) != 0) { + int rename_errno = errno; + remove(tempname); + fprintf(stderr, _("%s: rename to %s/%s: %s\n"), + progname, directory, name, strerror(rename_errno)); + exit(EXIT_FAILURE); + } + free(tempname); + } +} + +/* Create symlink contents suitable for symlinking TARGET to LINKNAME, as a + freshly allocated string. TARGET should be a relative file name, and + is relative to the global variable DIRECTORY. LINKNAME can be either + relative or absolute. */ +static char * +relname(char const *target, char const *linkname) +{ + size_t i, taillen, dir_len = 0, dotdots = 0; + ptrdiff_t dotdotetcsize, linksize = INDEX_MAX; + char const *f = target; + char *result = NULL; + if (*linkname == '/') { + /* Make F absolute too. */ + size_t len = strlen(directory); + size_t lenslash = len + (len && directory[len - 1] != '/'); + size_t targetsize = strlen(target) + 1; + linksize = size_sum(lenslash, targetsize); + f = result = emalloc(linksize); + memcpy(result, directory, len); + result[len] = '/'; + memcpy(result + lenslash, target, targetsize); + } + for (i = 0; f[i] && f[i] == linkname[i]; i++) + if (f[i] == '/') + dir_len = i + 1; + for (; linkname[i]; i++) + dotdots += linkname[i] == '/' && linkname[i - 1] != '/'; + taillen = strlen(f + dir_len); + dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1); + if (dotdotetcsize <= linksize) { + if (!result) + result = emalloc(dotdotetcsize); + for (i = 0; i < dotdots; i++) + memcpy(result + 3 * i, "../", 3); + memmove(result + 3 * dotdots, f + dir_len, taillen + 1); + } + return result; +} + +/* Return true if A and B must have the same parent dir if A and B exist. + Return false if this is not necessarily true (though it might be true). + Keep it simple, and do not inspect the file system. */ +static bool +same_parent_dirs(char const *a, char const *b) +{ + for (; *a == *b; a++, b++) + if (!*a) + return true; + return ! (strchr(a, '/') || strchr(b, '/')); +} + +static void +dolink(char const *target, char const *linkname, bool staysymlink) +{ + bool linkdirs_made = false; + int link_errno; + char *tempname = NULL; + char const *outname = linkname; + int targetissym = -2, linknameissym = -2; + + check_for_signal(); + + if (strcmp(target, "-") == 0) { + if (remove(linkname) == 0 || errno == ENOENT || errno == ENOTDIR) + return; + else { + char const *e = strerror(errno); + fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), + progname, directory, linkname, e); + exit(EXIT_FAILURE); + } + } + + while (true) { + if (linkat(AT_FDCWD, target, AT_FDCWD, outname, AT_SYMLINK_FOLLOW) + == 0) { + link_errno = 0; + break; + } + link_errno = errno; + /* Linux 2.6.16 and 2.6.17 mishandle AT_SYMLINK_FOLLOW. */ + if (link_errno == EINVAL) + link_errno = ENOTSUP; +#if HAVE_LINK + /* If linkat is not supported, fall back on link(A, B). + However, skip this if A is a relative symlink + and A and B might not have the same parent directory. + On some platforms link(A, B) does not follow a symlink A, + and if A is relative it might misbehave elsewhere. */ + if (link_errno == ENOTSUP + && (same_parent_dirs(target, outname) + || 0 <= itssymlink(target, &targetissym))) { + if (link(target, outname) == 0) { + link_errno = 0; + break; + } + link_errno = errno; + } +#endif + if (link_errno == EXDEV || link_errno == ENOTSUP) + break; + + if (link_errno == EEXIST) { + staysymlink &= !tempname; + random_dirent(&outname, &tempname); + if (staysymlink && itssymlink(linkname, &linknameissym)) + break; + } else if (link_errno == ENOENT && !linkdirs_made) { + mkdirs(linkname, true); + linkdirs_made = true; + } else { + fprintf(stderr, _("%s: Can't link %s/%s to %s/%s: %s\n"), + progname, directory, target, directory, outname, + strerror(link_errno)); + exit(EXIT_FAILURE); + } + } + if (link_errno != 0) { + bool absolute = *target == '/'; + char *linkalloc = absolute ? NULL : relname(target, linkname); + char const *contents = absolute ? target : linkalloc; + int symlink_errno; + + while (true) { + if (symlink(contents, outname) == 0) { + symlink_errno = 0; + break; + } + symlink_errno = errno; + if (symlink_errno == EEXIST) + random_dirent(&outname, &tempname); + else if (symlink_errno == ENOENT && !linkdirs_made) { + mkdirs(linkname, true); + linkdirs_made = true; + } else + break; + } + free(linkalloc); + if (symlink_errno == 0) { + if (link_errno != ENOTSUP && link_errno != EEXIST) + warning(_("symbolic link used because hard link failed: %s"), + strerror(link_errno)); + } else { + FILE *fp, *tp; + int c; + fp = fopen(target, "rb"); + if (!fp) { + char const *e = strerror(errno); + fprintf(stderr, _("%s: Can't read %s/%s: %s\n"), + progname, directory, target, e); + exit(EXIT_FAILURE); + } + tp = open_outfile(&outname, &tempname); + while ((c = getc(fp)) != EOF) + putc(c, tp); + close_file(tp, directory, linkname, tempname); + close_file(fp, directory, target, NULL); + if (link_errno != ENOTSUP) + warning(_("copy used because hard link failed: %s"), + strerror(link_errno)); + else if (symlink_errno != ENOTSUP) + warning(_("copy used because symbolic link failed: %s"), + strerror(symlink_errno)); + } + } + rename_dest(tempname, linkname); +} + +/* Return 1 if NAME is an absolute symbolic link, -1 if it is relative, + 0 if it is not a symbolic link. If *CACHE is not -2, it is the + cached result of a previous call to this function with the same NAME. */ +static int +itssymlink(char const *name, int *cache) +{ + if (*cache == -2) { + char c = '\0'; + *cache = readlink(name, &c, 1) < 0 ? 0 : c == '/' ? 1 : -1; + } + return *cache; +} + +/* +** Associate sets of rules with zones. +*/ + +/* +** Sort by rule name. +*/ + +static int +rcomp(const void *cp1, const void *cp2) +{ + struct rule const *r1 = cp1, *r2 = cp2; + return strcmp(r1->r_name, r2->r_name); +} + +static void +associate(void) +{ + register struct zone * zp; + register struct rule * rp; + register ptrdiff_t i, j, base, out; + + if (1 < nrules) { + qsort(rules, nrules, sizeof *rules, rcomp); + for (i = 0; i < nrules - 1; ++i) { + if (strcmp(rules[i].r_name, + rules[i + 1].r_name) != 0) + continue; + if (rules[i].r_filenum == rules[i + 1].r_filenum) + continue; + eat(rules[i].r_filenum, rules[i].r_linenum); + warning(_("same rule name in multiple files")); + eat(rules[i + 1].r_filenum, rules[i + 1].r_linenum); + warning(_("same rule name in multiple files")); + for (j = i + 2; j < nrules; ++j) { + if (strcmp(rules[i].r_name, + rules[j].r_name) != 0) + break; + if (rules[i].r_filenum == rules[j].r_filenum) + continue; + if (rules[i + 1].r_filenum + == rules[j].r_filenum) + continue; + break; + } + i = j - 1; + } + } + for (i = 0; i < nzones; ++i) { + zp = &zones[i]; + zp->z_rules = NULL; + zp->z_nrules = 0; + } + for (base = 0; base < nrules; base = out) { + rp = &rules[base]; + for (out = base + 1; out < nrules; ++out) + if (strcmp(rp->r_name, rules[out].r_name) != 0) + break; + for (i = 0; i < nzones; ++i) { + zp = &zones[i]; + if (strcmp(zp->z_rule, rp->r_name) != 0) + continue; + zp->z_rules = rp; + zp->z_nrules = out - base; + } + } + for (i = 0; i < nzones; ++i) { + zp = &zones[i]; + if (zp->z_nrules == 0) { + /* + ** Maybe we have a local standard time offset. + */ + eat(zp->z_filenum, zp->z_linenum); + zp->z_save = getsave(zp->z_rule, &zp->z_isdst); + /* + ** Note, though, that if there's no rule, + ** a '%s' in the format is a bad thing. + */ + if (zp->z_format_specifier == 's') + error("%s", _("%s in ruleless zone")); + } + } + if (errors) + exit(EXIT_FAILURE); +} + +/* Read a text line from FP into BUF, which is of size BUFSIZE. + Terminate it with a NUL byte instead of a newline. + Return true if successful, false if EOF. + On error, report the error and exit. */ +static bool +inputline(FILE *fp, char *buf, ptrdiff_t bufsize) +{ + ptrdiff_t linelen = 0, ch; + while ((ch = getc(fp)) != '\n') { + if (ch < 0) { + if (ferror(fp)) { + error(_("input error")); + exit(EXIT_FAILURE); + } + if (linelen == 0) + return false; + error(_("unterminated line")); + exit(EXIT_FAILURE); + } + if (!ch) { + error(_("NUL input byte")); + exit(EXIT_FAILURE); + } + buf[linelen++] = ch; + if (linelen == bufsize) { + error(_("line too long")); + exit(EXIT_FAILURE); + } + } + buf[linelen] = '\0'; + return true; +} + +static void +infile(int fnum, char const *name) +{ + register FILE * fp; + register const struct lookup * lp; + register bool wantcont; + register lineno num; + + if (strcmp(name, "-") == 0) { + fp = stdin; + } else if ((fp = fopen(name, "r")) == NULL) { + const char *e = strerror(errno); + + fprintf(stderr, _("%s: Can't open %s: %s\n"), + progname, name, e); + exit(EXIT_FAILURE); + } + wantcont = false; + for (num = 1; ; ++num) { + enum { bufsize_bound + = (min(INT_MAX, INDEX_MAX) / FORMAT_LEN_GROWTH_BOUND) }; + char buf[min(_POSIX2_LINE_MAX, bufsize_bound)]; + int nfields; + char *fields[MAX_FIELDS]; + eat(fnum, num); + if (!inputline(fp, buf, sizeof buf)) + break; + nfields = getfields(buf, fields, + sizeof fields / sizeof *fields); + if (nfields == 0) { + /* nothing to do */ + } else if (wantcont) { + wantcont = inzcont(fields, nfields); + } else { + struct lookup const *line_codes + = fnum < 0 ? leap_line_codes : zi_line_codes; + lp = byword(fields[0], line_codes); + if (lp == NULL) + error(_("input line of unknown type")); + else switch (lp->l_value) { + case LC_RULE: + inrule(fields, nfields); + wantcont = false; + break; + case LC_ZONE: + wantcont = inzone(fields, nfields); + break; + case LC_LINK: + inlink(fields, nfields); + wantcont = false; + break; + case LC_LEAP: + inleap(fields, nfields); + wantcont = false; + break; + case LC_EXPIRES: + inexpires(fields, nfields); + wantcont = false; + break; + default: unreachable(); + } + } + } + close_file(fp, NULL, filename(fnum), NULL); + if (wantcont) + error(_("expected continuation line not found")); +} + +/* +** Convert a string of one of the forms +** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss +** into a number of seconds. +** A null string maps to zero. +** Call error with errstring and return zero on errors. +*/ + +static zic_t +gethms(char const *string, char const *errstring) +{ + zic_t hh; + int sign, mm = 0, ss = 0; + char hhx, mmx, ssx, xr = '0', xs; + int tenths = 0; + bool ok = true; + + if (string == NULL || *string == '\0') + return 0; + if (*string == '-') { + sign = -1; + ++string; + } else sign = 1; + switch (sscanf(string, + "%"SCNdZIC"%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c", + &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs)) { + default: ok = false; break; + case 8: + ok = '0' <= xr && xr <= '9'; + ATTRIBUTE_FALLTHROUGH; + case 7: + ok &= ssx == '.'; + if (ok && noise) + warning(_("fractional seconds rejected by" + " pre-2018 versions of zic")); + ATTRIBUTE_FALLTHROUGH; + case 5: ok &= mmx == ':'; ATTRIBUTE_FALLTHROUGH; + case 3: ok &= hhx == ':'; ATTRIBUTE_FALLTHROUGH; + case 1: break; + } + if (!ok) { + error("%s", errstring); + return 0; + } + if (hh < 0 || + mm < 0 || mm >= MINSPERHOUR || + ss < 0 || ss > SECSPERMIN) { + error("%s", errstring); + return 0; + } + if (ZIC_MAX / SECSPERHOUR < hh) { + error(_("time overflow")); + return 0; + } + ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even. */ + if (noise && (hh > HOURSPERDAY || + (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) +warning(_("values over 24 hours not handled by pre-2007 versions of zic")); + return oadd(sign * hh * SECSPERHOUR, + sign * (mm * SECSPERMIN + ss)); +} + +static zic_t +getsave(char *field, bool *isdst) +{ + int dst = -1; + zic_t save; + ptrdiff_t fieldlen = strlen(field); + if (fieldlen != 0) { + char *ep = field + fieldlen - 1; + switch (*ep) { + case 'd': dst = 1; *ep = '\0'; break; + case 's': dst = 0; *ep = '\0'; break; + } + } + save = gethms(field, _("invalid saved time")); + *isdst = dst < 0 ? save != 0 : dst; + return save; +} + +static void +inrule(char **fields, int nfields) +{ + struct rule r; + + if (nfields != RULE_FIELDS) { + error(_("wrong number of fields on Rule line")); + return; + } + switch (*fields[RF_NAME]) { + case '\0': + case ' ': case '\f': case '\n': case '\r': case '\t': case '\v': + case '+': case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + error(_("Invalid rule name \"%s\""), fields[RF_NAME]); + return; + } + r.r_filenum = filenum; + r.r_linenum = linenum; + r.r_save = getsave(fields[RF_SAVE], &r.r_isdst); + if (!rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], + fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY], + fields[RF_TOD])) + return; + r.r_name = estrdup(fields[RF_NAME]); + r.r_abbrvar = estrdup(fields[RF_ABBRVAR]); + if (max_abbrvar_len < strlen(r.r_abbrvar)) + max_abbrvar_len = strlen(r.r_abbrvar); + rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc); + rules[nrules++] = r; +} + +static bool +inzone(char **fields, int nfields) +{ + register ptrdiff_t i; + + if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { + error(_("wrong number of fields on Zone line")); + return false; + } + if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0) { + error(_("\"Zone %s\" line and -l option are mutually exclusive"), + tzdefault); + return false; + } + if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { + error(_("\"Zone %s\" line and -p option are mutually exclusive"), + TZDEFRULES); + return false; + } + for (i = 0; i < nzones; ++i) + if (zones[i].z_name != NULL && + strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { + error(_("duplicate zone name %s" + " (file \"%s\", line %"PRIdMAX")"), + fields[ZF_NAME], + filename(zones[i].z_filenum), + zones[i].z_linenum); + return false; + } + return inzsub(fields, nfields, false); +} + +static bool +inzcont(char **fields, int nfields) +{ + if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { + error(_("wrong number of fields on Zone continuation line")); + return false; + } + return inzsub(fields, nfields, true); +} + +static bool +inzsub(char **fields, int nfields, bool iscont) +{ + register char * cp; + char * cp1; + struct zone z; + int format_len; + register int i_stdoff, i_rule, i_format; + register int i_untilyear, i_untilmonth; + register int i_untilday, i_untiltime; + register bool hasuntil; + + if (iscont) { + i_stdoff = ZFC_STDOFF; + i_rule = ZFC_RULE; + i_format = ZFC_FORMAT; + i_untilyear = ZFC_TILYEAR; + i_untilmonth = ZFC_TILMONTH; + i_untilday = ZFC_TILDAY; + i_untiltime = ZFC_TILTIME; + } else if (!namecheck(fields[ZF_NAME])) + return false; + else { + i_stdoff = ZF_STDOFF; + i_rule = ZF_RULE; + i_format = ZF_FORMAT; + i_untilyear = ZF_TILYEAR; + i_untilmonth = ZF_TILMONTH; + i_untilday = ZF_TILDAY; + i_untiltime = ZF_TILTIME; + } + z.z_filenum = filenum; + z.z_linenum = linenum; + z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset")); + if ((cp = strchr(fields[i_format], '%')) != 0) { + if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%') + || strchr(fields[i_format], '/')) { + error(_("invalid abbreviation format")); + return false; + } + } + z.z_format_specifier = cp ? *cp : '\0'; + format_len = strlen(fields[i_format]); + if (max_format_len < format_len) + max_format_len = format_len; + hasuntil = nfields > i_untilyear; + if (hasuntil) { + z.z_untilrule.r_filenum = filenum; + z.z_untilrule.r_linenum = linenum; + if (!rulesub( + &z.z_untilrule, + fields[i_untilyear], + "only", + "", + (nfields > i_untilmonth) ? + fields[i_untilmonth] : "Jan", + (nfields > i_untilday) ? fields[i_untilday] : "1", + (nfields > i_untiltime) ? fields[i_untiltime] : "0")) + return false; + z.z_untiltime = rpytime(&z.z_untilrule, + z.z_untilrule.r_loyear); + if (iscont && nzones > 0 && + z.z_untiltime > min_time && + z.z_untiltime < max_time && + zones[nzones - 1].z_untiltime > min_time && + zones[nzones - 1].z_untiltime < max_time && + zones[nzones - 1].z_untiltime >= z.z_untiltime) { + error(_("Zone continuation line end time is" + " not after end time of previous line")); + return false; + } + } + z.z_name = iscont ? NULL : estrdup(fields[ZF_NAME]); + z.z_rule = estrdup(fields[i_rule]); + z.z_format = cp1 = estrdup(fields[i_format]); + if (z.z_format_specifier == 'z') { + cp1[cp - fields[i_format]] = 's'; + if (noise) + warning(_("format '%s' not handled by pre-2015 versions of zic"), + fields[i_format]); + } + zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc); + zones[nzones++] = z; + /* + ** If there was an UNTIL field on this line, + ** there's more information about the zone on the next line. + */ + return hasuntil; +} + +static zic_t +getleapdatetime(char **fields, bool expire_line) +{ + register const char * cp; + register const struct lookup * lp; + register zic_t i, j; + zic_t year; + int month, day; + zic_t dayoff, tod; + zic_t t; + char xs; + + dayoff = 0; + cp = fields[LP_YEAR]; + if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) { + /* + ** Leapin' Lizards! + */ + error(_("invalid leaping year")); + return -1; + } + if (!expire_line) { + if (!leapseen || leapmaxyear < year) + leapmaxyear = year; + if (!leapseen || leapminyear > year) + leapminyear = year; + leapseen = true; + } + j = EPOCH_YEAR; + while (j != year) { + if (year > j) { + i = len_years[isleap(j)]; + ++j; + } else { + --j; + i = -len_years[isleap(j)]; + } + dayoff = oadd(dayoff, i); + } + if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { + error(_("invalid month name")); + return -1; + } + month = lp->l_value; + j = TM_JANUARY; + while (j != month) { + i = len_months[isleap(year)][j]; + dayoff = oadd(dayoff, i); + ++j; + } + cp = fields[LP_DAY]; + if (sscanf(cp, "%d%c", &day, &xs) != 1 || + day <= 0 || day > len_months[isleap(year)][month]) { + error(_("invalid day of month")); + return -1; + } + dayoff = oadd(dayoff, day - 1); + if (dayoff < min_time / SECSPERDAY) { + error(_("time too small")); + return -1; + } + if (dayoff > max_time / SECSPERDAY) { + error(_("time too large")); + return -1; + } + t = dayoff * SECSPERDAY; + tod = gethms(fields[LP_TIME], _("invalid time of day")); + t = tadd(t, tod); + if (t < 0) + error(_("leap second precedes Epoch")); + return t; +} + +static void +inleap(char **fields, int nfields) +{ + if (nfields != LEAP_FIELDS) + error(_("wrong number of fields on Leap line")); + else { + zic_t t = getleapdatetime(fields, false); + if (0 <= t) { + struct lookup const *lp = byword(fields[LP_ROLL], leap_types); + if (!lp) + error(_("invalid Rolling/Stationary field on Leap line")); + else { + int correction = 0; + if (!fields[LP_CORR][0]) /* infile() turns "-" into "". */ + correction = -1; + else if (strcmp(fields[LP_CORR], "+") == 0) + correction = 1; + else + error(_("invalid CORRECTION field on Leap line")); + if (correction) + leapadd(t, correction, lp->l_value); + } + } + } +} + +static void +inexpires(char **fields, int nfields) +{ + if (nfields != EXPIRES_FIELDS) + error(_("wrong number of fields on Expires line")); + else if (0 <= leapexpires) + error(_("multiple Expires lines")); + else + leapexpires = getleapdatetime(fields, true); +} + +static void +inlink(char **fields, int nfields) +{ + struct link l; + + if (nfields != LINK_FIELDS) { + error(_("wrong number of fields on Link line")); + return; + } + if (*fields[LF_TARGET] == '\0') { + error(_("blank TARGET field on Link line")); + return; + } + if (! namecheck(fields[LF_LINKNAME])) + return; + l.l_filenum = filenum; + l.l_linenum = linenum; + l.l_target = estrdup(fields[LF_TARGET]); + l.l_linkname = estrdup(fields[LF_LINKNAME]); + links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc); + links[nlinks++] = l; +} + +static bool +rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, + const char *typep, const char *monthp, const char *dayp, + const char *timep) +{ + register const struct lookup * lp; + register const char * cp; + register char * dp; + register char * ep; + char xs; + + if ((lp = byword(monthp, mon_names)) == NULL) { + error(_("invalid month name")); + return false; + } + rp->r_month = lp->l_value; + rp->r_todisstd = false; + rp->r_todisut = false; + dp = estrdup(timep); + if (*dp != '\0') { + ep = dp + strlen(dp) - 1; + switch (lowerit(*ep)) { + case 's': /* Standard */ + rp->r_todisstd = true; + rp->r_todisut = false; + *ep = '\0'; + break; + case 'w': /* Wall */ + rp->r_todisstd = false; + rp->r_todisut = false; + *ep = '\0'; + break; + case 'g': /* Greenwich */ + case 'u': /* Universal */ + case 'z': /* Zulu */ + rp->r_todisstd = true; + rp->r_todisut = true; + *ep = '\0'; + break; + } + } + rp->r_tod = gethms(dp, _("invalid time of day")); + free(dp); + /* + ** Year work. + */ + cp = loyearp; + lp = byword(cp, begin_years); + if (lp) switch (lp->l_value) { + case YR_MINIMUM: + warning(_("FROM year \"%s\" is obsolete;" + " treated as %d"), + cp, YEAR_32BIT_MIN - 1); + rp->r_loyear = YEAR_32BIT_MIN - 1; + break; + default: unreachable(); + } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) { + error(_("invalid starting year")); + return false; + } + cp = hiyearp; + lp = byword(cp, end_years); + rp->r_hiwasnum = lp == NULL; + if (!rp->r_hiwasnum) switch (lp->l_value) { + case YR_MAXIMUM: + rp->r_hiyear = ZIC_MAX; + break; + case YR_ONLY: + rp->r_hiyear = rp->r_loyear; + break; + default: unreachable(); + } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) { + error(_("invalid ending year")); + return false; + } + if (rp->r_loyear > rp->r_hiyear) { + error(_("starting year greater than ending year")); + return false; + } + if (*typep != '\0') { + error(_("year type \"%s\" is unsupported; use \"-\" instead"), + typep); + return false; + } + /* + ** Day work. + ** Accept things such as: + ** 1 + ** lastSunday + ** last-Sunday (undocumented; warn about this) + ** Sun<=20 + ** Sun>=7 + */ + dp = estrdup(dayp); + if ((lp = byword(dp, lasts)) != NULL) { + rp->r_dycode = DC_DOWLEQ; + rp->r_wday = lp->l_value; + rp->r_dayofmonth = len_months[1][rp->r_month]; + } else { + if ((ep = strchr(dp, '<')) != 0) + rp->r_dycode = DC_DOWLEQ; + else if ((ep = strchr(dp, '>')) != 0) + rp->r_dycode = DC_DOWGEQ; + else { + ep = dp; + rp->r_dycode = DC_DOM; + } + if (rp->r_dycode != DC_DOM) { + *ep++ = 0; + if (*ep++ != '=') { + error(_("invalid day of month")); + free(dp); + return false; + } + if ((lp = byword(dp, wday_names)) == NULL) { + error(_("invalid weekday name")); + free(dp); + return false; + } + rp->r_wday = lp->l_value; + } + if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 || + rp->r_dayofmonth <= 0 || + (rp->r_dayofmonth > len_months[1][rp->r_month])) { + error(_("invalid day of month")); + free(dp); + return false; + } + } + free(dp); + return true; +} + +static void +convert(uint_fast32_t val, char *buf) +{ + register int i; + register int shift; + unsigned char *const b = (unsigned char *) buf; + + for (i = 0, shift = 24; i < 4; ++i, shift -= 8) + b[i] = (val >> shift) & 0xff; +} + +static void +convert64(uint_fast64_t val, char *buf) +{ + register int i; + register int shift; + unsigned char *const b = (unsigned char *) buf; + + for (i = 0, shift = 56; i < 8; ++i, shift -= 8) + b[i] = (val >> shift) & 0xff; +} + +static void +puttzcode(zic_t val, FILE *fp) +{ + char buf[4]; + + convert(val, buf); + fwrite(buf, sizeof buf, 1, fp); +} + +static void +puttzcodepass(zic_t val, FILE *fp, int pass) +{ + if (pass == 1) + puttzcode(val, fp); + else { + char buf[8]; + + convert64(val, buf); + fwrite(buf, sizeof buf, 1, fp); + } +} + +static int +atcomp(const void *avp, const void *bvp) +{ + struct attype const *ap = avp, *bp = bvp; + zic_t a = ap->at, b = bp->at; + return a < b ? -1 : a > b; +} + +struct timerange { + int defaulttype; + ptrdiff_t base, count; + int leapbase, leapcount; + bool leapexpiry; +}; + +static struct timerange +limitrange(struct timerange r, zic_t lo, zic_t hi, + zic_t const *ats, unsigned char const *types) +{ + /* Omit ordinary transitions < LO. */ + while (0 < r.count && ats[r.base] < lo) { + r.defaulttype = types[r.base]; + r.count--; + r.base++; + } + + /* Omit as many initial leap seconds as possible, such that the + first leap second in the truncated list is <= LO, and is a + positive leap second if and only if it has a positive correction. + This supports common TZif readers that assume that the first leap + second is positive if and only if its correction is positive. */ + while (1 < r.leapcount && trans[r.leapbase + 1] <= lo) { + r.leapcount--; + r.leapbase++; + } + while (0 < r.leapbase + && ((corr[r.leapbase - 1] < corr[r.leapbase]) + != (0 < corr[r.leapbase]))) { + r.leapcount++; + r.leapbase--; + } + + + /* Omit ordinary and leap second transitions greater than HI + 1. */ + if (hi < max_time) { + while (0 < r.count && hi + 1 < ats[r.base + r.count - 1]) + r.count--; + while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1]) + r.leapcount--; + } + + /* Determine whether to append an expiration to the leap second table. */ + r.leapexpiry = 0 <= leapexpires && leapexpires - 1 <= hi; + + return r; +} + +static void +writezone(const char *const name, const char *const string, char version, + int defaulttype) +{ + register FILE * fp; + register ptrdiff_t i, j; + register int pass; + char *tempname = NULL; + char const *outname = name; + + /* Allocate the ATS and TYPES arrays via a single malloc, + as this is a bit faster. Do not malloc(0) if !timecnt, + as that might return NULL even on success. */ + zic_t *ats = emalloc(align_to(size_product(timecnt + !timecnt, + sizeof *ats + 1), + alignof(zic_t))); + void *typesptr = ats + timecnt; + unsigned char *types = typesptr; + struct timerange rangeall = {0}, range32, range64; + + /* + ** Sort. + */ + if (timecnt > 1) + qsort(attypes, timecnt, sizeof *attypes, atcomp); + /* + ** Optimize. + */ + { + ptrdiff_t fromi, toi; + + toi = 0; + fromi = 0; + for ( ; fromi < timecnt; ++fromi) { + if (toi != 0 + && ((attypes[fromi].at + + utoffs[attypes[toi - 1].type]) + <= (attypes[toi - 1].at + + utoffs[toi == 1 ? 0 + : attypes[toi - 2].type]))) { + attypes[toi - 1].type = + attypes[fromi].type; + continue; + } + if (toi == 0 + || attypes[fromi].dontmerge + || (utoffs[attypes[toi - 1].type] + != utoffs[attypes[fromi].type]) + || (isdsts[attypes[toi - 1].type] + != isdsts[attypes[fromi].type]) + || (desigidx[attypes[toi - 1].type] + != desigidx[attypes[fromi].type])) + attypes[toi++] = attypes[fromi]; + } + timecnt = toi; + } + + if (noise && timecnt > 1200) { + if (timecnt > TZ_MAX_TIMES) + warning(_("reference clients mishandle" + " more than %d transition times"), + TZ_MAX_TIMES); + else + warning(_("pre-2014 clients may mishandle" + " more than 1200 transition times")); + } + /* + ** Transfer. + */ + for (i = 0; i < timecnt; ++i) { + ats[i] = attypes[i].at; + types[i] = attypes[i].type; + } + + /* + ** Correct for leap seconds. + */ + for (i = 0; i < timecnt; ++i) { + j = leapcnt; + while (--j >= 0) + if (ats[i] > trans[j] - corr[j]) { + ats[i] = tadd(ats[i], corr[j]); + break; + } + } + + rangeall.defaulttype = defaulttype; + rangeall.count = timecnt; + rangeall.leapcount = leapcnt; + range64 = limitrange(rangeall, lo_time, + max(hi_time, + redundant_time - (ZIC_MIN < redundant_time)), + ats, types); + range32 = limitrange(range64, ZIC32_MIN, ZIC32_MAX, ats, types); + + /* TZif version 4 is needed if a no-op transition is appended to + indicate the expiration of the leap second table, or if the first + leap second transition is not to a +1 or -1 correction. */ + for (pass = 1; pass <= 2; pass++) { + struct timerange const *r = pass == 1 ? &range32 : &range64; + if (pass == 1 && !want_bloat()) + continue; + if (r->leapexpiry) { + if (noise) + warning(_("%s: pre-2021b clients may mishandle" + " leap second expiry"), + name); + version = '4'; + } + if (0 < r->leapcount + && corr[r->leapbase] != 1 && corr[r->leapbase] != -1) { + if (noise) + warning(_("%s: pre-2021b clients may mishandle" + " leap second table truncation"), + name); + version = '4'; + } + if (version == '4') + break; + } + + fp = open_outfile(&outname, &tempname); + + for (pass = 1; pass <= 2; ++pass) { + register ptrdiff_t thistimei, thistimecnt, thistimelim; + register int thisleapi, thisleapcnt, thisleaplim; + struct tzhead tzh; + int pretranstype = -1, thisdefaulttype; + bool locut, hicut, thisleapexpiry; + zic_t lo, thismin, thismax; + int old0; + char omittype[TZ_MAX_TYPES]; + int typemap[TZ_MAX_TYPES]; + int thistypecnt, stdcnt, utcnt; + char thischars[TZ_MAX_CHARS]; + int thischarcnt; + bool toomanytimes; + int indmap[TZ_MAX_CHARS]; + + if (pass == 1) { + thisdefaulttype = range32.defaulttype; + thistimei = range32.base; + thistimecnt = range32.count; + toomanytimes = thistimecnt >> 31 >> 1 != 0; + thisleapi = range32.leapbase; + thisleapcnt = range32.leapcount; + thisleapexpiry = range32.leapexpiry; + thismin = ZIC32_MIN; + thismax = ZIC32_MAX; + } else { + thisdefaulttype = range64.defaulttype; + thistimei = range64.base; + thistimecnt = range64.count; + toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0; + thisleapi = range64.leapbase; + thisleapcnt = range64.leapcount; + thisleapexpiry = range64.leapexpiry; + thismin = min_time; + thismax = max_time; + } + if (toomanytimes) + error(_("too many transition times")); + + locut = thismin < lo_time && lo_time <= thismax; + hicut = thismin <= hi_time && hi_time < thismax; + thistimelim = thistimei + thistimecnt; + memset(omittype, true, typecnt); + + /* Determine whether to output a transition before the first + transition in range. This is needed when the output is + truncated at the start, and is also useful when catering to + buggy 32-bit clients that do not use time type 0 for + timestamps before the first transition. */ + if ((locut || (pass == 1 && thistimei)) + && ! (thistimecnt && ats[thistimei] == lo_time)) { + pretranstype = thisdefaulttype; + omittype[pretranstype] = false; + } + + /* Arguably the default time type in the 32-bit data + should be range32.defaulttype, which is suited for + timestamps just before ZIC32_MIN. However, zic + traditionally used the time type of the indefinite + past instead. Internet RFC 8532 says readers should + ignore 32-bit data, so this discrepancy matters only + to obsolete readers where the traditional type might + be more appropriate even if it's "wrong". So, use + the historical zic value, unless -r specifies a low + cutoff that excludes some 32-bit timestamps. */ + if (pass == 1 && lo_time <= thismin) + thisdefaulttype = range64.defaulttype; + + if (locut) + thisdefaulttype = unspecifiedtype; + omittype[thisdefaulttype] = false; + for (i = thistimei; i < thistimelim; i++) + omittype[types[i]] = false; + if (hicut) + omittype[unspecifiedtype] = false; + + /* Reorder types to make THISDEFAULTTYPE type 0. + Use TYPEMAP to swap OLD0 and THISDEFAULTTYPE so that + THISDEFAULTTYPE appears as type 0 in the output instead + of OLD0. TYPEMAP also omits unused types. */ + old0 = strlen(omittype); + +#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH + /* + ** For some pre-2011 systems: if the last-to-be-written + ** standard (or daylight) type has an offset different from the + ** most recently used offset, + ** append an (unused) copy of the most recently used type + ** (to help get global "altzone" and "timezone" variables + ** set correctly). + */ + if (want_bloat()) { + register int mrudst, mrustd, hidst, histd, type; + + hidst = histd = mrudst = mrustd = -1; + if (0 <= pretranstype) { + if (isdsts[pretranstype]) + mrudst = pretranstype; + else + mrustd = pretranstype; + } + for (i = thistimei; i < thistimelim; i++) + if (isdsts[types[i]]) + mrudst = types[i]; + else mrustd = types[i]; + for (i = old0; i < typecnt; i++) { + int h = (i == old0 ? thisdefaulttype + : i == thisdefaulttype ? old0 : i); + if (!omittype[h]) { + if (isdsts[h]) + hidst = i; + else + histd = i; + } + } + if (hidst >= 0 && mrudst >= 0 && hidst != mrudst && + utoffs[hidst] != utoffs[mrudst]) { + isdsts[mrudst] = -1; + type = addtype(utoffs[mrudst], + &chars[desigidx[mrudst]], + true, + ttisstds[mrudst], + ttisuts[mrudst]); + isdsts[mrudst] = 1; + omittype[type] = false; + } + if (histd >= 0 && mrustd >= 0 && histd != mrustd && + utoffs[histd] != utoffs[mrustd]) { + isdsts[mrustd] = -1; + type = addtype(utoffs[mrustd], + &chars[desigidx[mrustd]], + false, + ttisstds[mrustd], + ttisuts[mrustd]); + isdsts[mrustd] = 0; + omittype[type] = false; + } + } +#endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */ + thistypecnt = 0; + for (i = old0; i < typecnt; i++) + if (!omittype[i]) + typemap[i == old0 ? thisdefaulttype + : i == thisdefaulttype ? old0 : i] + = thistypecnt++; + + for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i) + indmap[i] = -1; + thischarcnt = stdcnt = utcnt = 0; + for (i = old0; i < typecnt; i++) { + register char * thisabbr; + + if (omittype[i]) + continue; + if (ttisstds[i]) + stdcnt = thistypecnt; + if (ttisuts[i]) + utcnt = thistypecnt; + if (indmap[desigidx[i]] >= 0) + continue; + thisabbr = &chars[desigidx[i]]; + for (j = 0; j < thischarcnt; ++j) + if (strcmp(&thischars[j], thisabbr) == 0) + break; + if (j == thischarcnt) { + strcpy(&thischars[thischarcnt], thisabbr); + thischarcnt += strlen(thisabbr) + 1; + } + indmap[desigidx[i]] = j; + } + if (pass == 1 && !want_bloat()) { + hicut = thisleapexpiry = false; + pretranstype = -1; + thistimecnt = thisleapcnt = 0; + thistypecnt = thischarcnt = 1; + } +#define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp) + memset(&tzh, 0, sizeof tzh); + memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); + tzh.tzh_version[0] = version; + convert(utcnt, tzh.tzh_ttisutcnt); + convert(stdcnt, tzh.tzh_ttisstdcnt); + convert(thisleapcnt + thisleapexpiry, tzh.tzh_leapcnt); + convert((0 <= pretranstype) + thistimecnt + hicut, + tzh.tzh_timecnt); + convert(thistypecnt, tzh.tzh_typecnt); + convert(thischarcnt, tzh.tzh_charcnt); + DO(tzh_magic); + DO(tzh_version); + DO(tzh_reserved); + DO(tzh_ttisutcnt); + DO(tzh_ttisstdcnt); + DO(tzh_leapcnt); + DO(tzh_timecnt); + DO(tzh_typecnt); + DO(tzh_charcnt); +#undef DO + if (pass == 1 && !want_bloat()) { + /* Output a minimal data block with just one time type. */ + puttzcode(0, fp); /* utoff */ + putc(0, fp); /* dst */ + putc(0, fp); /* index of abbreviation */ + putc(0, fp); /* empty-string abbreviation */ + continue; + } + + /* Output a LO_TIME transition if needed; see limitrange. + But do not go below the minimum representable value + for this pass. */ + lo = pass == 1 && lo_time < ZIC32_MIN ? ZIC32_MIN : lo_time; + + if (0 <= pretranstype) + puttzcodepass(lo, fp, pass); + for (i = thistimei; i < thistimelim; ++i) { + puttzcodepass(ats[i], fp, pass); + } + if (hicut) + puttzcodepass(hi_time + 1, fp, pass); + if (0 <= pretranstype) + putc(typemap[pretranstype], fp); + for (i = thistimei; i < thistimelim; i++) + putc(typemap[types[i]], fp); + if (hicut) + putc(typemap[unspecifiedtype], fp); + + for (i = old0; i < typecnt; i++) { + int h = (i == old0 ? thisdefaulttype + : i == thisdefaulttype ? old0 : i); + if (!omittype[h]) { + puttzcode(utoffs[h], fp); + putc(isdsts[h], fp); + putc(indmap[desigidx[h]], fp); + } + } + if (thischarcnt != 0) + fwrite(thischars, sizeof thischars[0], + thischarcnt, fp); + thisleaplim = thisleapi + thisleapcnt; + for (i = thisleapi; i < thisleaplim; ++i) { + register zic_t todo; + + if (roll[i]) { + if (timecnt == 0 || trans[i] < ats[0]) { + j = 0; + while (isdsts[j]) + if (++j >= typecnt) { + j = 0; + break; + } + } else { + j = 1; + while (j < timecnt && + trans[i] >= ats[j]) + ++j; + j = types[j - 1]; + } + todo = tadd(trans[i], -utoffs[j]); + } else todo = trans[i]; + puttzcodepass(todo, fp, pass); + puttzcode(corr[i], fp); + } + if (thisleapexpiry) { + /* Append a no-op leap correction indicating when the leap + second table expires. Although this does not conform to + Internet RFC 8536, most clients seem to accept this and + the plan is to amend the RFC to allow this in version 4 + TZif files. */ + puttzcodepass(leapexpires, fp, pass); + puttzcode(thisleaplim ? corr[thisleaplim - 1] : 0, fp); + } + if (stdcnt != 0) + for (i = old0; i < typecnt; i++) + if (!omittype[i]) + putc(ttisstds[i], fp); + if (utcnt != 0) + for (i = old0; i < typecnt; i++) + if (!omittype[i]) + putc(ttisuts[i], fp); + } + fprintf(fp, "\n%s\n", string); + close_file(fp, directory, name, tempname); + rename_dest(tempname, name); + free(ats); +} + +static char const * +abbroffset(char *buf, zic_t offset) +{ + char sign = '+'; + int seconds, minutes; + + if (offset < 0) { + offset = -offset; + sign = '-'; + } + + seconds = offset % SECSPERMIN; + offset /= SECSPERMIN; + minutes = offset % MINSPERHOUR; + offset /= MINSPERHOUR; + if (100 <= offset) { + error(_("%%z UT offset magnitude exceeds 99:59:59")); + return "%z"; + } else { + char *p = buf; + *p++ = sign; + *p++ = '0' + offset / 10; + *p++ = '0' + offset % 10; + if (minutes | seconds) { + *p++ = '0' + minutes / 10; + *p++ = '0' + minutes % 10; + if (seconds) { + *p++ = '0' + seconds / 10; + *p++ = '0' + seconds % 10; + } + } + *p = '\0'; + return buf; + } +} + +static char const disable_percent_s[] = ""; + +static ptrdiff_t +doabbr(char *abbr, struct zone const *zp, char const *letters, + bool isdst, zic_t save, bool doquotes) +{ + register char * cp; + register char * slashp; + ptrdiff_t len; + char const *format = zp->z_format; + + slashp = strchr(format, '/'); + if (slashp == NULL) { + char letterbuf[PERCENT_Z_LEN_BOUND + 1]; + if (zp->z_format_specifier == 'z') + letters = abbroffset(letterbuf, zp->z_stdoff + save); + else if (!letters) + letters = "%s"; + else if (letters == disable_percent_s) + return 0; + sprintf(abbr, format, letters); + } else if (isdst) { + strcpy(abbr, slashp + 1); + } else { + memcpy(abbr, format, slashp - format); + abbr[slashp - format] = '\0'; + } + len = strlen(abbr); + if (!doquotes) + return len; + for (cp = abbr; is_alpha(*cp); cp++) + continue; + if (len > 0 && *cp == '\0') + return len; + abbr[len + 2] = '\0'; + abbr[len + 1] = '>'; + memmove(abbr + 1, abbr, len); + abbr[0] = '<'; + return len + 2; +} + +static void +updateminmax(const zic_t x) +{ + if (min_year > x) + min_year = x; + if (max_year < x) + max_year = x; +} + +static int +stringoffset(char *result, zic_t offset) +{ + register int hours; + register int minutes; + register int seconds; + bool negative = offset < 0; + int len = negative; + + if (negative) { + offset = -offset; + result[0] = '-'; + } + seconds = offset % SECSPERMIN; + offset /= SECSPERMIN; + minutes = offset % MINSPERHOUR; + offset /= MINSPERHOUR; + hours = offset; + if (hours >= HOURSPERDAY * DAYSPERWEEK) { + result[0] = '\0'; + return 0; + } + len += sprintf(result + len, "%d", hours); + if (minutes != 0 || seconds != 0) { + len += sprintf(result + len, ":%02d", minutes); + if (seconds != 0) + len += sprintf(result + len, ":%02d", seconds); + } + return len; +} + +static int +stringrule(char *result, struct rule *const rp, zic_t save, zic_t stdoff) +{ + register zic_t tod = rp->r_tod; + register int compat = 0; + + if (rp->r_dycode == DC_DOM) { + register int month, total; + + if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY) + return -1; + total = 0; + for (month = 0; month < rp->r_month; ++month) + total += len_months[0][month]; + /* Omit the "J" in Jan and Feb, as that's shorter. */ + if (rp->r_month <= 1) + result += sprintf(result, "%d", total + rp->r_dayofmonth - 1); + else + result += sprintf(result, "J%d", total + rp->r_dayofmonth); + } else { + register int week; + register int wday = rp->r_wday; + register int wdayoff; + + if (rp->r_dycode == DC_DOWGEQ) { + wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK; + if (wdayoff) + compat = 2013; + wday -= wdayoff; + tod += wdayoff * SECSPERDAY; + week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK; + } else if (rp->r_dycode == DC_DOWLEQ) { + if (rp->r_dayofmonth == len_months[1][rp->r_month]) + week = 5; + else { + wdayoff = rp->r_dayofmonth % DAYSPERWEEK; + if (wdayoff) + compat = 2013; + wday -= wdayoff; + tod += wdayoff * SECSPERDAY; + week = rp->r_dayofmonth / DAYSPERWEEK; + } + } else return -1; /* "cannot happen" */ + if (wday < 0) + wday += DAYSPERWEEK; + result += sprintf(result, "M%d.%d.%d", + rp->r_month + 1, week, wday); + } + if (rp->r_todisut) + tod += stdoff; + if (rp->r_todisstd && !rp->r_isdst) + tod += save; + if (tod != 2 * SECSPERMIN * MINSPERHOUR) { + *result++ = '/'; + if (! stringoffset(result, tod)) + return -1; + if (tod < 0) { + if (compat < 2013) + compat = 2013; + } else if (SECSPERDAY <= tod) { + if (compat < 1994) + compat = 1994; + } + } + return compat; +} + +static int +rule_cmp(struct rule const *a, struct rule const *b) +{ + if (!a) + return -!!b; + if (!b) + return 1; + if (a->r_hiyear != b->r_hiyear) + return a->r_hiyear < b->r_hiyear ? -1 : 1; + if (a->r_hiyear == ZIC_MAX) + return 0; + if (a->r_month - b->r_month != 0) + return a->r_month - b->r_month; + return a->r_dayofmonth - b->r_dayofmonth; +} + +/* Store into RESULT a POSIX.1-2017 TZ string that represent the future + predictions for the zone ZPFIRST with ZONECOUNT entries. Return a + compatibility indicator (a TZDB release year) if successful, a + negative integer if no such TZ string exissts. */ +static int +stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) +{ + register const struct zone * zp; + register struct rule * rp; + register struct rule * stdrp; + register struct rule * dstrp; + register ptrdiff_t i; + register int compat = 0; + register int c; + int offsetlen; + struct rule stdr, dstr; + ptrdiff_t len; + int dstcmp; + struct rule *lastrp[2] = { NULL, NULL }; + struct zone zstr[2]; + struct zone const *stdzp; + struct zone const *dstzp; + + result[0] = '\0'; + + /* Internet RFC 8536 section 5.1 says to use an empty TZ string if + future timestamps are truncated. */ + if (hi_time < max_time) + return -1; + + zp = zpfirst + zonecount - 1; + for (i = 0; i < zp->z_nrules; ++i) { + struct rule **last; + int cmp; + rp = &zp->z_rules[i]; + last = &lastrp[rp->r_isdst]; + cmp = rule_cmp(*last, rp); + if (cmp < 0) + *last = rp; + else if (cmp == 0) + return -1; + } + stdrp = lastrp[false]; + dstrp = lastrp[true]; + dstcmp = zp->z_nrules ? rule_cmp(dstrp, stdrp) : zp->z_isdst ? 1 : -1; + stdzp = dstzp = zp; + + if (dstcmp < 0) { + /* Standard time all year. */ + dstrp = NULL; + } else if (0 < dstcmp) { + /* DST all year. Use an abbreviation like + "XXX3EDT4,0/0,J365/23" for EDT (-04) all year. */ + zic_t save = dstrp ? dstrp->r_save : zp->z_save; + if (0 <= save) + { + /* Positive DST, the typical case for all-year DST. + Fake a timezone with negative DST. */ + stdzp = &zstr[0]; + dstzp = &zstr[1]; + zstr[0].z_stdoff = zp->z_stdoff + 2 * save; + zstr[0].z_format = "XXX"; /* Any 3 letters will do. */ + zstr[0].z_format_specifier = 0; + zstr[1].z_stdoff = zstr[0].z_stdoff; + zstr[1].z_format = zp->z_format; + zstr[1].z_format_specifier = zp->z_format_specifier; + } + dstr.r_month = TM_JANUARY; + dstr.r_dycode = DC_DOM; + dstr.r_dayofmonth = 1; + dstr.r_tod = 0; + dstr.r_todisstd = dstr.r_todisut = false; + dstr.r_isdst = true; + dstr.r_save = save < 0 ? save : -save; + dstr.r_abbrvar = dstrp ? dstrp->r_abbrvar : NULL; + stdr.r_month = TM_DECEMBER; + stdr.r_dycode = DC_DOM; + stdr.r_dayofmonth = 31; + stdr.r_tod = SECSPERDAY + dstr.r_save; + stdr.r_todisstd = stdr.r_todisut = false; + stdr.r_isdst = false; + stdr.r_save = 0; + stdr.r_abbrvar = save < 0 && stdrp ? stdrp->r_abbrvar : NULL; + dstrp = &dstr; + stdrp = &stdr; + } + len = doabbr(result, stdzp, stdrp ? stdrp->r_abbrvar : NULL, + false, 0, true); + offsetlen = stringoffset(result + len, - stdzp->z_stdoff); + if (! offsetlen) { + result[0] = '\0'; + return -1; + } + len += offsetlen; + if (dstrp == NULL) + return compat; + len += doabbr(result + len, dstzp, dstrp->r_abbrvar, + dstrp->r_isdst, dstrp->r_save, true); + if (dstrp->r_save != SECSPERMIN * MINSPERHOUR) { + offsetlen = stringoffset(result + len, + - (dstzp->z_stdoff + dstrp->r_save)); + if (! offsetlen) { + result[0] = '\0'; + return -1; + } + len += offsetlen; + } + result[len++] = ','; + c = stringrule(result + len, dstrp, dstrp->r_save, stdzp->z_stdoff); + if (c < 0) { + result[0] = '\0'; + return -1; + } + if (compat < c) + compat = c; + len += strlen(result + len); + result[len++] = ','; + c = stringrule(result + len, stdrp, dstrp->r_save, stdzp->z_stdoff); + if (c < 0) { + result[0] = '\0'; + return -1; + } + if (compat < c) + compat = c; + return compat; +} + +static void +outzone(const struct zone *zpfirst, ptrdiff_t zonecount) +{ + register ptrdiff_t i, j; + register zic_t starttime, untiltime; + register bool startttisstd; + register bool startttisut; + register char * startbuf; + register char * ab; + register char * envvar; + register int max_abbr_len; + register int max_envvar_len; + register int compat; + register bool do_extend; + register char version; + zic_t nonTZlimtime = ZIC_MIN; + int nonTZlimtype = -1; + zic_t max_year0; + int defaulttype = -1; + + check_for_signal(); + + /* This cannot overflow; see FORMAT_LEN_GROWTH_BOUND. */ + max_abbr_len = 2 + max_format_len + max_abbrvar_len; + max_envvar_len = 2 * max_abbr_len + 5 * 9; + + startbuf = emalloc(max_abbr_len + 1); + ab = emalloc(max_abbr_len + 1); + envvar = emalloc(max_envvar_len + 1); + INITIALIZE(untiltime); + INITIALIZE(starttime); + /* + ** Now. . .finally. . .generate some useful data! + */ + timecnt = 0; + typecnt = 0; + charcnt = 0; + /* + ** Thanks to Earl Chew + ** for noting the need to unconditionally initialize startttisstd. + */ + startttisstd = false; + startttisut = false; + min_year = max_year = EPOCH_YEAR; + if (leapseen) { + updateminmax(leapminyear); + updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX)); + } + for (i = 0; i < zonecount; ++i) { + struct zone const *zp = &zpfirst[i]; + if (i < zonecount - 1) + updateminmax(zp->z_untilrule.r_loyear); + for (j = 0; j < zp->z_nrules; ++j) { + struct rule *rp = &zp->z_rules[j]; + updateminmax(rp->r_loyear); + if (rp->r_hiwasnum) + updateminmax(rp->r_hiyear); + } + } + /* + ** Generate lots of data if a rule can't cover all future times. + */ + compat = stringzone(envvar, zpfirst, zonecount); + version = compat < 2013 ? '2' : '3'; + do_extend = compat < 0; + if (noise) { + if (!*envvar) + warning("%s %s", + _("no POSIX.1-2017 environment variable" + " for zone"), + zpfirst->z_name); + else if (compat != 0) { + /* Circa-COMPAT clients, and earlier clients, might + not work for this zone when given dates before + 1970 or after 2038. */ + warning(_("%s: pre-%d clients may mishandle" + " distant timestamps"), + zpfirst->z_name, compat); + } + } + if (do_extend) { + if (min_year >= ZIC_MIN + years_of_observations) + min_year -= years_of_observations; + else min_year = ZIC_MIN; + if (max_year <= ZIC_MAX - years_of_observations) + max_year += years_of_observations; + else max_year = ZIC_MAX; + } + max_year = max(max_year, (redundant_time / (SECSPERDAY * DAYSPERNYEAR) + + EPOCH_YEAR + 1)); + max_year0 = max_year; + if (want_bloat()) { + /* For the benefit of older systems, + generate data from 1900 through 2038. */ + if (min_year > YEAR_32BIT_MIN - 1) + min_year = YEAR_32BIT_MIN - 1; + if (max_year < YEAR_32BIT_MAX) + max_year = YEAR_32BIT_MAX; + } + + if (min_time < lo_time || hi_time < max_time) + unspecifiedtype = addtype(0, "-00", false, false, false); + + for (i = 0; i < zonecount; ++i) { + /* + ** A guess that may well be corrected later. + */ + zic_t save = 0; + struct zone const *zp = &zpfirst[i]; + bool usestart = i > 0 && (zp - 1)->z_untiltime > min_time; + bool useuntil = i < (zonecount - 1); + zic_t stdoff = zp->z_stdoff; + zic_t startoff = stdoff; + if (useuntil && zp->z_untiltime <= min_time) + continue; + eat(zp->z_filenum, zp->z_linenum); + *startbuf = '\0'; + if (zp->z_nrules == 0) { + int type; + save = zp->z_save; + doabbr(startbuf, zp, NULL, zp->z_isdst, save, false); + type = addtype(oadd(zp->z_stdoff, save), + startbuf, zp->z_isdst, startttisstd, + startttisut); + if (usestart) { + addtt(starttime, type); + if (useuntil && nonTZlimtime < starttime) { + nonTZlimtime = starttime; + nonTZlimtype = type; + } + usestart = false; + } else + defaulttype = type; + } else { + zic_t year; + for (year = min_year; year <= max_year; ++year) { + if (useuntil && year > zp->z_untilrule.r_hiyear) + break; + /* + ** Mark which rules to do in the current year. + ** For those to do, calculate rpytime(rp, year); + ** The former TYPE field was also considered here. + */ + for (j = 0; j < zp->z_nrules; ++j) { + zic_t one = 1; + zic_t y2038_boundary = one << 31; + struct rule *rp = &zp->z_rules[j]; + eats(zp->z_filenum, zp->z_linenum, + rp->r_filenum, rp->r_linenum); + rp->r_todo = year >= rp->r_loyear && + year <= rp->r_hiyear; + if (rp->r_todo) { + rp->r_temp = rpytime(rp, year); + rp->r_todo + = (rp->r_temp < y2038_boundary + || year <= max_year0); + } + } + for ( ; ; ) { + register ptrdiff_t k; + register zic_t jtime, ktime; + register zic_t offset; + struct rule *rp; + int type; + + INITIALIZE(ktime); + if (useuntil) { + /* + ** Turn untiltime into UT + ** assuming the current stdoff and + ** save values. + */ + untiltime = zp->z_untiltime; + if (!zp->z_untilrule.r_todisut) + untiltime = tadd(untiltime, + -stdoff); + if (!zp->z_untilrule.r_todisstd) + untiltime = tadd(untiltime, + -save); + } + /* + ** Find the rule (of those to do, if any) + ** that takes effect earliest in the year. + */ + k = -1; + for (j = 0; j < zp->z_nrules; ++j) { + struct rule *r = &zp->z_rules[j]; + if (!r->r_todo) + continue; + eats(zp->z_filenum, zp->z_linenum, + r->r_filenum, r->r_linenum); + offset = r->r_todisut ? 0 : stdoff; + if (!r->r_todisstd) + offset = oadd(offset, save); + jtime = r->r_temp; + if (jtime == min_time || + jtime == max_time) + continue; + jtime = tadd(jtime, -offset); + if (k < 0 || jtime < ktime) { + k = j; + ktime = jtime; + } else if (jtime == ktime) { + char const *dup_rules_msg = + _("two rules for same instant"); + eats(zp->z_filenum, zp->z_linenum, + r->r_filenum, r->r_linenum); + warning("%s", dup_rules_msg); + r = &zp->z_rules[k]; + eats(zp->z_filenum, zp->z_linenum, + r->r_filenum, r->r_linenum); + error("%s", dup_rules_msg); + } + } + if (k < 0) + break; /* go on to next year */ + rp = &zp->z_rules[k]; + rp->r_todo = false; + if (useuntil && ktime >= untiltime) { + if (!*startbuf + && (oadd(zp->z_stdoff, rp->r_save) + == startoff)) + doabbr(startbuf, zp, rp->r_abbrvar, + rp->r_isdst, rp->r_save, + false); + break; + } + save = rp->r_save; + if (usestart && ktime == starttime) + usestart = false; + if (usestart) { + if (ktime < starttime) { + startoff = oadd(zp->z_stdoff, + save); + doabbr(startbuf, zp, + rp->r_abbrvar, + rp->r_isdst, + rp->r_save, + false); + continue; + } + if (*startbuf == '\0' + && startoff == oadd(zp->z_stdoff, + save)) { + doabbr(startbuf, + zp, + rp->r_abbrvar, + rp->r_isdst, + rp->r_save, + false); + } + } + eats(zp->z_filenum, zp->z_linenum, + rp->r_filenum, rp->r_linenum); + doabbr(ab, zp, rp->r_abbrvar, + rp->r_isdst, rp->r_save, false); + offset = oadd(zp->z_stdoff, rp->r_save); + type = addtype(offset, ab, rp->r_isdst, + rp->r_todisstd, rp->r_todisut); + if (defaulttype < 0 && !rp->r_isdst) + defaulttype = type; + addtt(ktime, type); + if (nonTZlimtime < ktime + && (useuntil || rp->r_hiyear != ZIC_MAX)) { + nonTZlimtime = ktime; + nonTZlimtype = type; + } + } + } + } + if (usestart) { + bool isdst = startoff != zp->z_stdoff; + if (*startbuf == '\0' && zp->z_format) + doabbr(startbuf, zp, disable_percent_s, + isdst, save, false); + eat(zp->z_filenum, zp->z_linenum); + if (*startbuf == '\0') + error(_("can't determine time zone abbreviation" + " to use just after until time")); + else { + int type = addtype(startoff, startbuf, isdst, + startttisstd, startttisut); + if (defaulttype < 0 && !isdst) + defaulttype = type; + addtt(starttime, type); + } + } + /* + ** Now we may get to set starttime for the next zone line. + */ + if (useuntil) { + startttisstd = zp->z_untilrule.r_todisstd; + startttisut = zp->z_untilrule.r_todisut; + starttime = zp->z_untiltime; + if (!startttisstd) + starttime = tadd(starttime, -save); + if (!startttisut) + starttime = tadd(starttime, -stdoff); + } + } + if (defaulttype < 0) + defaulttype = 0; + if (!do_extend && !want_bloat()) { + /* Keep trailing transitions that are no greater than this. */ + zic_t keep_at_max; + + /* The earliest transition into a time governed by the TZ string. */ + zic_t TZstarttime = ZIC_MAX; + for (i = 0; i < timecnt; i++) { + zic_t at = attypes[i].at; + if (nonTZlimtime < at && at < TZstarttime) + TZstarttime = at; + } + if (TZstarttime == ZIC_MAX) + TZstarttime = nonTZlimtime; + + /* Omit trailing transitions deducible from the TZ string, + and not needed for -r or -R. */ + keep_at_max = max(TZstarttime, redundant_time); + for (i = j = 0; i < timecnt; i++) + if (attypes[i].at <= keep_at_max) { + attypes[j].at = attypes[i].at; + attypes[j].dontmerge = (attypes[i].at == TZstarttime + && (nonTZlimtype != attypes[i].type + || strchr(envvar, ','))); + attypes[j].type = attypes[i].type; + j++; + } + timecnt = j; + } + if (do_extend) { + /* + ** If we're extending the explicitly listed observations for + ** 400 years because we can't fill the POSIX.1-2017 TZ field, + ** check whether we actually ended up explicitly listing + ** observations through that period. If there aren't any + ** near the end of the 400-year period, add a redundant + ** one at the end of the final year, to make it clear + ** that we are claiming to have definite knowledge of + ** the lack of transitions up to that point. + */ + struct rule xr; + struct attype *lastat; + xr.r_month = TM_JANUARY; + xr.r_dycode = DC_DOM; + xr.r_dayofmonth = 1; + xr.r_tod = 0; + for (lastat = attypes, i = 1; i < timecnt; i++) + if (attypes[i].at > lastat->at) + lastat = &attypes[i]; + if (!lastat || lastat->at < rpytime(&xr, max_year - 1)) { + addtt(rpytime(&xr, max_year + 1), + lastat ? lastat->type : defaulttype); + attypes[timecnt - 1].dontmerge = true; + } + } + writezone(zpfirst->z_name, envvar, version, defaulttype); + free(startbuf); + free(ab); + free(envvar); +} + +static void +addtt(zic_t starttime, int type) +{ + attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc); + attypes[timecnt].at = starttime; + attypes[timecnt].dontmerge = false; + attypes[timecnt].type = type; + ++timecnt; +} + +static int +addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut) +{ + register int i, j; + + if (! (-1L - 2147483647L <= utoff && utoff <= 2147483647L)) { + error(_("UT offset out of range")); + exit(EXIT_FAILURE); + } + if (!want_bloat()) + ttisstd = ttisut = false; + + for (j = 0; j < charcnt; ++j) + if (strcmp(&chars[j], abbr) == 0) + break; + if (j == charcnt) + newabbr(abbr); + else { + /* If there's already an entry, return its index. */ + for (i = 0; i < typecnt; i++) + if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i] + && ttisstd == ttisstds[i] && ttisut == ttisuts[i]) + return i; + } + /* + ** There isn't one; add a new one, unless there are already too + ** many. + */ + if (typecnt >= TZ_MAX_TYPES) { + error(_("too many local time types")); + exit(EXIT_FAILURE); + } + i = typecnt++; + utoffs[i] = utoff; + isdsts[i] = isdst; + ttisstds[i] = ttisstd; + ttisuts[i] = ttisut; + desigidx[i] = j; + return i; +} + +static void +leapadd(zic_t t, int correction, int rolling) +{ + register int i; + + if (TZ_MAX_LEAPS <= leapcnt) { + error(_("too many leap seconds")); + exit(EXIT_FAILURE); + } + if (rolling && (lo_time != min_time || hi_time != max_time)) { + error(_("Rolling leap seconds not supported with -r")); + exit(EXIT_FAILURE); + } + for (i = 0; i < leapcnt; ++i) + if (t <= trans[i]) + break; + memmove(&trans[i + 1], &trans[i], (leapcnt - i) * sizeof *trans); + memmove(&corr[i + 1], &corr[i], (leapcnt - i) * sizeof *corr); + memmove(&roll[i + 1], &roll[i], (leapcnt - i) * sizeof *roll); + trans[i] = t; + corr[i] = correction; + roll[i] = rolling; + ++leapcnt; +} + +static void +adjleap(void) +{ + register int i; + register zic_t last = 0; + register zic_t prevtrans = 0; + + /* + ** propagate leap seconds forward + */ + for (i = 0; i < leapcnt; ++i) { + if (trans[i] - prevtrans < 28 * SECSPERDAY) { + error(_("Leap seconds too close together")); + exit(EXIT_FAILURE); + } + prevtrans = trans[i]; + trans[i] = tadd(trans[i], last); + last = corr[i] += last; + } + + if (0 <= leapexpires) { + leapexpires = oadd(leapexpires, last); + if (! (leapcnt == 0 || (trans[leapcnt - 1] < leapexpires))) { + error(_("last Leap time does not precede Expires time")); + exit(EXIT_FAILURE); + } + } +} + +/* Is A a space character in the C locale? */ +static bool +is_space(char a) +{ + switch (a) { + default: + return false; + case ' ': case '\f': case '\n': case '\r': case '\t': case '\v': + return true; + } +} + +/* Is A an alphabetic character in the C locale? */ +static bool +is_alpha(char a) +{ + switch (a) { + default: + return false; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': + case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': + case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': + case 'V': case 'W': case 'X': case 'Y': case 'Z': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': + case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': + case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': + case 'v': case 'w': case 'x': case 'y': case 'z': + return true; + } +} + +/* If A is an uppercase character in the C locale, return its lowercase + counterpart. Otherwise, return A. */ +static char +lowerit(char a) +{ + switch (a) { + default: return a; + case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c'; + case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f'; + case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i'; + case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l'; + case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o'; + case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r'; + case 'S': return 's'; case 'T': return 't'; case 'U': return 'u'; + case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x'; + case 'Y': return 'y'; case 'Z': return 'z'; + } +} + +/* case-insensitive equality */ +ATTRIBUTE_REPRODUCIBLE static bool +ciequal(register const char *ap, register const char *bp) +{ + while (lowerit(*ap) == lowerit(*bp++)) + if (*ap++ == '\0') + return true; + return false; +} + +ATTRIBUTE_REPRODUCIBLE static bool +itsabbr(register const char *abbr, register const char *word) +{ + if (lowerit(*abbr) != lowerit(*word)) + return false; + ++word; + while (*++abbr != '\0') + do { + if (*word == '\0') + return false; + } while (lowerit(*word++) != lowerit(*abbr)); + return true; +} + +/* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */ + +ATTRIBUTE_REPRODUCIBLE static bool +ciprefix(char const *abbr, char const *word) +{ + do + if (!*abbr) + return true; + while (lowerit(*abbr++) == lowerit(*word++)); + + return false; +} + +static const struct lookup * +byword(const char *word, const struct lookup *table) +{ + register const struct lookup * foundlp; + register const struct lookup * lp; + + if (word == NULL || table == NULL) + return NULL; + + /* If TABLE is LASTS and the word starts with "last" followed + by a non-'-', skip the "last" and look in WDAY_NAMES instead. + Warn about any usage of the undocumented prefix "last-". */ + if (table == lasts && ciprefix("last", word) && word[4]) { + if (word[4] == '-') + warning(_("\"%s\" is undocumented; use \"last%s\" instead"), + word, word + 5); + else { + word += 4; + table = wday_names; + } + } + + /* + ** Look for exact match. + */ + for (lp = table; lp->l_word != NULL; ++lp) + if (ciequal(word, lp->l_word)) + return lp; + /* + ** Look for inexact match. + */ + foundlp = NULL; + for (lp = table; lp->l_word != NULL; ++lp) + if (ciprefix(word, lp->l_word)) { + if (foundlp == NULL) + foundlp = lp; + else return NULL; /* multiple inexact matches */ + } + + if (foundlp && noise) { + /* Warn about any backward-compatibility issue with pre-2017c zic. */ + bool pre_2017c_match = false; + for (lp = table; lp->l_word; lp++) + if (itsabbr(word, lp->l_word)) { + if (pre_2017c_match) { + warning(_("\"%s\" is ambiguous in pre-2017c zic"), word); + break; + } + pre_2017c_match = true; + } + } + + return foundlp; +} + +static int +getfields(char *cp, char **array, int arrayelts) +{ + register char * dp; + register int nsubs; + + nsubs = 0; + for ( ; ; ) { + char *dstart; + while (is_space(*cp)) + ++cp; + if (*cp == '\0' || *cp == '#') + break; + dstart = dp = cp; + do { + if ((*dp = *cp++) != '"') + ++dp; + else while ((*dp = *cp++) != '"') + if (*dp != '\0') + ++dp; + else { + error(_("Odd number of quotation marks")); + exit(EXIT_FAILURE); + } + } while (*cp && *cp != '#' && !is_space(*cp)); + if (is_space(*cp)) + ++cp; + *dp = '\0'; + if (nsubs == arrayelts) { + error(_("Too many input fields")); + exit(EXIT_FAILURE); + } + array[nsubs++] = dstart + (*dstart == '-' && dp == dstart + 1); + } + return nsubs; +} + +ATTRIBUTE_NORETURN static void +time_overflow(void) +{ + error(_("time overflow")); + exit(EXIT_FAILURE); +} + +ATTRIBUTE_REPRODUCIBLE static zic_t +oadd(zic_t t1, zic_t t2) +{ +#ifdef ckd_add + zic_t sum; + if (!ckd_add(&sum, t1, t2)) + return sum; +#else + if (t1 < 0 ? ZIC_MIN - t1 <= t2 : t2 <= ZIC_MAX - t1) + return t1 + t2; +#endif + time_overflow(); +} + +ATTRIBUTE_REPRODUCIBLE static zic_t +tadd(zic_t t1, zic_t t2) +{ +#ifdef ckd_add + zic_t sum; + if (!ckd_add(&sum, t1, t2) && min_time <= sum && sum <= max_time) + return sum; +#else + if (t1 < 0 ? min_time - t1 <= t2 : t2 <= max_time - t1) + return t1 + t2; +#endif + if (t1 == min_time || t1 == max_time) + return t1; + time_overflow(); +} + +/* +** Given a rule, and a year, compute the date (in seconds since January 1, +** 1970, 00:00 LOCAL time) in that year that the rule refers to. +*/ + +static zic_t +rpytime(const struct rule *rp, zic_t wantedy) +{ + register int m, i; + register zic_t dayoff; /* with a nod to Margaret O. */ + register zic_t t, y; + int yrem; + + if (wantedy == ZIC_MIN) + return min_time; + if (wantedy == ZIC_MAX) + return max_time; + m = TM_JANUARY; + y = EPOCH_YEAR; + + /* dayoff = floor((wantedy - y) / YEARSPERREPEAT) * DAYSPERREPEAT, + sans overflow. */ + yrem = wantedy % YEARSPERREPEAT - y % YEARSPERREPEAT; + dayoff = ((wantedy / YEARSPERREPEAT - y / YEARSPERREPEAT + + yrem / YEARSPERREPEAT - (yrem % YEARSPERREPEAT < 0)) + * DAYSPERREPEAT); + /* wantedy = y + ((wantedy - y) mod YEARSPERREPEAT), sans overflow. */ + wantedy = y + (yrem + 2 * YEARSPERREPEAT) % YEARSPERREPEAT; + + while (wantedy != y) { + i = len_years[isleap(y)]; + dayoff = oadd(dayoff, i); + y++; + } + while (m != rp->r_month) { + i = len_months[isleap(y)][m]; + dayoff = oadd(dayoff, i); + ++m; + } + i = rp->r_dayofmonth; + if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { + if (rp->r_dycode == DC_DOWLEQ) + --i; + else { + error(_("use of 2/29 in non leap-year")); + exit(EXIT_FAILURE); + } + } + --i; + dayoff = oadd(dayoff, i); + if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { + /* + ** Don't trust mod of negative numbers. + */ + zic_t wday = ((EPOCH_WDAY + dayoff % DAYSPERWEEK + DAYSPERWEEK) + % DAYSPERWEEK); + while (wday != rp->r_wday) + if (rp->r_dycode == DC_DOWGEQ) { + dayoff = oadd(dayoff, 1); + if (++wday >= DAYSPERWEEK) + wday = 0; + ++i; + } else { + dayoff = oadd(dayoff, -1); + if (--wday < 0) + wday = DAYSPERWEEK - 1; + --i; + } + if (i < 0 || i >= len_months[isleap(y)][m]) { + if (noise) + warning(_("rule goes past start/end of month; \ +will not work with pre-2004 versions of zic")); + } + } + if (dayoff < min_time / SECSPERDAY) + return min_time; + if (dayoff > max_time / SECSPERDAY) + return max_time; + t = (zic_t) dayoff * SECSPERDAY; + return tadd(t, rp->r_tod); +} + +static void +newabbr(const char *string) +{ + register int i; + + if (strcmp(string, GRANDPARENTED) != 0) { + register const char * cp; + const char * mp; + + cp = string; + mp = NULL; + while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9') + || *cp == '-' || *cp == '+') + ++cp; + if (noise && cp - string < 3) + mp = _("time zone abbreviation has fewer than 3 characters"); + if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN) + mp = _("time zone abbreviation has too many characters"); + if (*cp != '\0') +mp = _("time zone abbreviation differs from POSIX standard"); + if (mp != NULL) + warning("%s (%s)", mp, string); + } + i = strlen(string) + 1; + if (charcnt + i > TZ_MAX_CHARS) { + error(_("too many, or too long, time zone abbreviations")); + exit(EXIT_FAILURE); + } + strcpy(&chars[charcnt], string); + charcnt += i; +} + +/* Ensure that the directories of ARGNAME exist, by making any missing + ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise, + do it for ARGNAME too. Exit with failure if there is trouble. + Do not consider an existing file to be trouble. */ +static void +mkdirs(char const *argname, bool ancestors) +{ + char *name = estrdup(argname); + char *cp = name; + + /* On MS-Windows systems, do not worry about drive letters or + backslashes, as this should suffice in practice. Time zone + names do not use drive letters and backslashes. If the -d + option of zic does not name an already-existing directory, + it can use slashes to separate the already-existing + ancestor prefix from the to-be-created subdirectories. */ + + /* Do not mkdir a root directory, as it must exist. */ + while (*cp == '/') + cp++; + + while (cp && ((cp = strchr(cp, '/')) || !ancestors)) { + if (cp) + *cp = '\0'; + /* + ** Try to create it. It's OK if creation fails because + ** the directory already exists, perhaps because some + ** other process just created it. For simplicity do + ** not check first whether it already exists, as that + ** is checked anyway if the mkdir fails. + */ + if (mkdir(name, MKDIR_UMASK) != 0) { + /* Do not report an error if err == EEXIST, because + some other process might have made the directory + in the meantime. Likewise for ENOSYS, because + Solaris 10 mkdir fails with ENOSYS if the + directory is an automounted mount point. + Likewise for EACCES, since mkdir can fail + with EACCES merely because the parent directory + is unwritable. Likewise for most other error + numbers. */ + int err = errno; + if (err == ELOOP || err == ENAMETOOLONG + || err == ENOENT || err == ENOTDIR) { + error(_("%s: Can't create directory %s: %s"), + progname, name, strerror(err)); + exit(EXIT_FAILURE); + } + } + if (cp) + *cp++ = '/'; + } + free(name); +} diff --git a/vendor/chrono-tz/tz/ziguard.awk b/vendor/chrono-tz/tz/ziguard.awk new file mode 100644 index 0000000000000..7a3404fa4fccd --- /dev/null +++ b/vendor/chrono-tz/tz/ziguard.awk @@ -0,0 +1,386 @@ +# Convert tzdata source into vanguard or rearguard form. + +# Contributed by Paul Eggert. This file is in the public domain. + +# This is not a general-purpose converter; it is designed for current tzdata. +# It just converts from current source to main, vanguard, and rearguard forms. +# Although it might be nice for it to be idempotent, or to be useful +# for converting back and forth between vanguard and rearguard formats, +# it does not do these nonessential tasks now. +# +# Although main and vanguard forms are currently equivalent, +# this need not always be the case. When the two forms differ, +# this script can convert either from main to vanguard form (needed then), +# or from vanguard to main form (this conversion would be needed later, +# after main became rearguard and vanguard became main). +# There is no need to convert rearguard to other forms. +# +# When converting to vanguard form, the output can use the line +# "Zone GMT 0 - GMT" which TZUpdater 2.3.2 mistakenly rejects. +# +# When converting to vanguard form, the output can use negative SAVE +# values. +# +# When converting to rearguard form, the output uses only nonnegative +# SAVE values. The idea is for the output data to simulate the behavior +# of the input data as best it can within the constraints of the +# rearguard format. + +# Given a FIELD like "-0:30", return a minute count like -30. +function get_minutes(field, \ + sign, hours, minutes) +{ + sign = field ~ /^-/ ? -1 : 1 + hours = +field + if (field ~ /:/) { + minutes = field + sub(/[^:]*:/, "", minutes) + } + return 60 * hours + sign * minutes +} + +# Given an OFFSET, which is a minute count like 300 or 330, +# return a %z-style abbreviation like "+05" or "+0530". +function offset_abbr(offset, \ + hours, minutes, sign) +{ + hours = int(offset / 60) + minutes = offset % 60 + if (minutes) { + return sprintf("%+.4d", hours * 100 + minutes); + } else { + return sprintf("%+.2d", hours) + } +} + +# Round TIMESTAMP (a +-hh:mm:ss.dddd string) to the nearest second. +function round_to_second(timestamp, \ + hh, mm, ss, seconds, dot_dddd, subseconds) +{ + dot_dddd = timestamp + if (!sub(/^[+-]?[0-9]+:[0-9]+:[0-9]+\./, ".", dot_dddd)) + return timestamp + hh = mm = ss = timestamp + sub(/^[-+]?[0-9]+:[0-9]+:/, "", ss) + sub(/^[-+]?[0-9]+:/, "", mm) + sub(/^[-+]?/, "", hh) + seconds = 3600 * hh + 60 * mm + ss + subseconds = +dot_dddd + seconds += 0.5 < subseconds || ((subseconds == 0.5) && (seconds % 2)); + return sprintf("%s%d:%.2d:%.2d", timestamp ~ /^-/ ? "-" : "", \ + seconds / 3600, seconds / 60 % 60, seconds % 60) +} + +BEGIN { + dataform_type["vanguard"] = 1 + dataform_type["main"] = 1 + dataform_type["rearguard"] = 1 + + if (PACKRATLIST) { + while (getline =8 25:00" + # to "Sun>=9 1:00", to cater to zic before 2007 and to older Java. + if ($0 ~ /^Rule/ && $2 == "Japan") { + if (DATAFORM == "rearguard") { + if ($7 == "Sat>=8" && $8 == "25:00") { + sub(/Sat>=8/, "Sun>=9") + sub(/25:00/, " 1:00") + } + } else { + if ($7 == "Sun>=9" && $8 == "1:00") { + sub(/Sun>=9/, "Sat>=8") + sub(/ 1:00/, "25:00") + } + } + } + + # In rearguard form, change the Morocco lines with negative SAVE values + # to use positive SAVE values. + if ($2 == "Morocco") { + if ($0 ~ /^Rule/) { + if ($4 ~ /^201[78]$/ && $6 == "Oct") { + if (DATAFORM == "rearguard") { + sub(/\t2018\t/, "\t2017\t") + } else { + sub(/\t2017\t/, "\t2018\t") + } + } + + if (2019 <= $3) { + if ($8 == "2:00") { + if (DATAFORM == "rearguard") { + sub(/\t0\t/, "\t1:00\t") + } else { + sub(/\t1:00\t/, "\t0\t") + } + } else { + if (DATAFORM == "rearguard") { + sub(/\t-1:00\t/, "\t0\t") + } else { + sub(/\t0\t/, "\t-1:00\t") + } + } + } + } + if ($1 ~ /^[+0-9-]/ && NF == 3) { + if (DATAFORM == "rearguard") { + sub(/1:00\tMorocco/, "0:00\tMorocco") + sub(/\t\+01\/\+00$/, "\t+00/+01") + } else { + sub(/0:00\tMorocco/, "1:00\tMorocco") + sub(/\t\+00\/+01$/, "\t+01/+00") + } + } + } +} + +/^Zone/ { + packrat_ignored = FILENAME == PACKRATDATA && PACKRATLIST && !packratlist[$2]; +} +{ + if (packrat_ignored && $0 !~ /^Rule/) { + sub(/^/, "#") + } +} + +# Return a link line resulting by changing OLDLINE to link to TARGET +# from LINKNAME, instead of linking to OLDTARGET from LINKNAME. +# Align data columns the same as they were in OLDLINE. +# Also, replace any existing white space followed by comment with COMMENT. +function make_linkline(oldline, target, linkname, oldtarget, comment, \ + oldprefix, oldprefixlen, oldtargettabs, \ + replsuffix, targettabs) +{ + oldprefix = "Link\t" oldtarget "\t" + oldprefixlen = length(oldprefix) + if (substr(oldline, 1, oldprefixlen) == oldprefix) { + # Use tab stops to preserve LINKNAME's column. + replsuffix = substr(oldline, oldprefixlen + 1) + sub(/[\t ]*#.*/, "", replsuffix) + oldtargettabs = int(length(oldtarget) / 8) + 1 + targettabs = int(length(target) / 8) + 1 + for (; targettabs < oldtargettabs; targettabs++) { + replsuffix = "\t" replsuffix + } + for (; oldtargettabs < targettabs && replsuffix ~ /^\t/; targettabs--) { + replsuffix = substr(replsuffix, 2) + } + } else { + # Odd format line; don't bother lining up its replacement nicely. + replsuffix = linkname + } + return "Link\t" target "\t" replsuffix comment +} + +/^Link/ && $4 == "#=" && DATAFORM == "vanguard" { + $0 = make_linkline($0, $5, $3, $2) +} + +# If a Link line is followed by a Link or Zone line for the same data, comment +# out the Link line. This can happen if backzone overrides a Link +# with a Zone or a different Link. +/^Zone/ { + sub(/^Link/, "#Link", line[linkline[$2]]) +} +/^Link/ { + sub(/^Link/, "#Link", line[linkline[$3]]) + linkline[$3] = NR + linktarget[$3] = $2 +} + +{ line[NR] = $0 } + +function cut_link_chains_short( \ + l, linkname, t, target) +{ + for (linkname in linktarget) { + target = linktarget[linkname] + t = linktarget[target] + if (t) { + # TARGET is itself a link name. Replace the line "Link TARGET LINKNAME" + # with "Link T LINKNAME #= TARGET", where T is at the end of the chain + # of links that LINKNAME points to. + while ((u = linktarget[t])) { + t = u + } + l = linkline[linkname] + line[l] = make_linkline(line[l], t, linkname, target, "\t#= " target) + } + } +} + +END { + if (DATAFORM != "vanguard") { + cut_link_chains_short() + } + for (i = 1; i <= NR; i++) + print line[i] +} diff --git a/vendor/chrono-tz/tz/zishrink.awk b/vendor/chrono-tz/tz/zishrink.awk new file mode 100644 index 0000000000000..c98dc6ae786d3 --- /dev/null +++ b/vendor/chrono-tz/tz/zishrink.awk @@ -0,0 +1,388 @@ +# Convert tzdata source into a smaller version of itself. + +# Contributed by Paul Eggert. This file is in the public domain. + +# This is not a general-purpose converter; it is designed for current tzdata. +# 'zic' should treat this script's output as if it were identical to +# this script's input. + +# Record a hash N for the new name NAME, checking for collisions. + +function record_hash(n, name) +{ + if (used_hashes[n]) { + printf "# ! collision: %s %s\n", used_hashes[n], name + exit 1 + } + used_hashes[n] = name +} + +# Return a shortened rule name representing NAME, +# and record this relationship to the hash table. + +function gen_rule_name(name, \ + n) +{ + # Use a simple mnemonic: the first two letters. + n = substr(name, 1, 2) + record_hash(n, name) + # printf "# %s = %s\n", n, name + return n +} + +function prehash_rule_names( \ + name) +{ + # Rule names are not part of the tzdb API, so substitute shorter + # ones. Shortening them consistently from one release to the next + # simplifies comparison of the output. That being said, the + # 1-letter names below are not standardized in any way, and can + # change arbitrarily from one release to the next, as the main goal + # here is compression not comparison. + + # Abbreviating these rules names to one letter saved the most space + # circa 2018e. + rule["Arg"] = "A" + rule["Brazil"] = "B" + rule["Canada"] = "C" + rule["Denmark"] = "D" + rule["EU"] = "E" + rule["France"] = "F" + rule["GB-Eire"] = "G" + rule["Halifax"] = "H" + rule["Italy"] = "I" + rule["Jordan"] = "J" + rule["Egypt"] = "K" # "Kemet" in ancient Egyptian + rule["Libya"] = "L" + rule["Morocco"] = "M" + rule["Neth"] = "N" + rule["Poland"] = "O" # arbitrary + rule["Palestine"] = "P" + rule["Cuba"] = "Q" # Its start sounds like "Q". + rule["Russia"] = "R" + rule["Syria"] = "S" + rule["Turkey"] = "T" + rule["Uruguay"] = "U" + rule["Vincennes"] = "V" + rule["Winn"] = "W" + rule["Mongol"] = "X" # arbitrary + rule["NT_YK"] = "Y" + rule["Zion"] = "Z" + rule["Austria"] = "a" + rule["Belgium"] = "b" + rule["C-Eur"] = "c" + rule["Algeria"] = "d" # country code DZ + rule["E-Eur"] = "e" + rule["Taiwan"] = "f" # Formosa + rule["Greece"] = "g" + rule["Hungary"] = "h" + rule["Iran"] = "i" + rule["StJohns"] = "j" + rule["Chatham"] = "k" # arbitrary + rule["Lebanon"] = "l" + rule["Mexico"] = "m" + rule["Tunisia"] = "n" # country code TN + rule["Moncton"] = "o" # arbitrary + rule["Port"] = "p" + rule["Albania"] = "q" # arbitrary + rule["Regina"] = "r" + rule["Spain"] = "s" + rule["Toronto"] = "t" + rule["US"] = "u" + rule["Louisville"] = "v" # ville + rule["Iceland"] = "w" # arbitrary + rule["Chile"] = "x" # arbitrary + rule["Para"] = "y" # country code PY + rule["Romania"] = "z" # arbitrary + rule["Macau"] = "_" # arbitrary + + # Use ISO 3166 alpha-2 country codes for remaining names that are countries. + # This is more systematic, and avoids collisions (e.g., Malta and Moldova). + rule["Armenia"] = "AM" + rule["Aus"] = "AU" + rule["Azer"] = "AZ" + rule["Barb"] = "BB" + rule["Dhaka"] = "BD" + rule["Bulg"] = "BG" + rule["Bahamas"] = "BS" + rule["Belize"] = "BZ" + rule["Swiss"] = "CH" + rule["Cook"] = "CK" + rule["PRC"] = "CN" + rule["Cyprus"] = "CY" + rule["Czech"] = "CZ" + rule["Germany"] = "DE" + rule["DR"] = "DO" + rule["Ecuador"] = "EC" + rule["Finland"] = "FI" + rule["Fiji"] = "FJ" + rule["Falk"] = "FK" + rule["Ghana"] = "GH" + rule["Guat"] = "GT" + rule["Hond"] = "HN" + rule["Haiti"] = "HT" + rule["Eire"] = "IE" + rule["Iraq"] = "IQ" + rule["Japan"] = "JP" + rule["Kyrgyz"] = "KG" + rule["ROK"] = "KR" + rule["Latvia"] = "LV" + rule["Lux"] = "LX" + rule["Moldova"] = "MD" + rule["Malta"] = "MT" + rule["Mauritius"] = "MU" + rule["Namibia"] = "NA" + rule["Nic"] = "NI" + rule["Norway"] = "NO" + rule["Peru"] = "PE" + rule["Phil"] = "PH" + rule["Pakistan"] = "PK" + rule["Sudan"] = "SD" + rule["Salv"] = "SV" + rule["Tonga"] = "TO" + rule["Vanuatu"] = "VU" + + # Avoid collisions. + rule["Detroit"] = "Dt" # De = Denver + + for (name in rule) { + record_hash(rule[name], name) + } +} + +function make_line(n, field, \ + f, r) +{ + r = field[1] + for (f = 2; f <= n; f++) + r = r " " field[f] + return r +} + +# Process the input line LINE and save it for later output. + +function process_input_line(line, \ + f, field, end, n, outline, r, \ + linkline, ruleline, zoneline) +{ + # Remove comments, normalize spaces, and append a space to each line. + sub(/#.*/, "", line) + line = line " " + gsub(/[\t ]+/, " ", line) + + # Abbreviate keywords and determine line type. + linkline = sub(/^Link /, "L ", line) + ruleline = sub(/^Rule /, "R ", line) + zoneline = sub(/^Zone /, "Z ", line) + + # Replace FooAsia rules with the same rules without "Asia", as they + # are duplicates. + if (match(line, /[^ ]Asia /)) { + if (ruleline) return + line = substr(line, 1, RSTART) substr(line, RSTART + 5) + } + + # Abbreviate times. + while (match(line, /[: ]0+[0-9]/)) + line = substr(line, 1, RSTART) substr(line, RSTART + RLENGTH - 1) + while (match(line, /:0[^:]/)) + line = substr(line, 1, RSTART - 1) substr(line, RSTART + 2) + + # Abbreviate weekday names. + while (match(line, / (last)?(Mon|Wed|Fri)[ <>]/)) { + end = RSTART + RLENGTH + line = substr(line, 1, end - 4) substr(line, end - 1) + } + while (match(line, / (last)?(Sun|Tue|Thu|Sat)[ <>]/)) { + end = RSTART + RLENGTH + line = substr(line, 1, end - 3) substr(line, end - 1) + } + + # Abbreviate "max", "min", "only" and month names. + # Although "max" and "min" can both be abbreviated to just "m", + # the longer forms "ma" and "mi" are needed with zic 2023d and earlier. + gsub(/ max /, dataform == "vanguard" ? " m " : " ma ", line) + gsub(/ min /, dataform == "vanguard" ? " m " : " mi ", line) + gsub(/ only /, " o ", line) + gsub(/ Jan /, " Ja ", line) + gsub(/ Feb /, " F ", line) + gsub(/ Apr /, " Ap ", line) + gsub(/ Aug /, " Au ", line) + gsub(/ Sep /, " S ", line) + gsub(/ Oct /, " O ", line) + gsub(/ Nov /, " N ", line) + gsub(/ Dec /, " D ", line) + + # Strip leading and trailing space. + sub(/^ /, "", line) + sub(/ $/, "", line) + + # Remove unnecessary trailing zero fields. + sub(/ 0+$/, "", line) + + # Remove unnecessary trailing days-of-month "1". + if (match(line, /[A-Za-z] 1$/)) + line = substr(line, 1, RSTART) + + # Remove unnecessary trailing " Ja" (for January). + sub(/ Ja$/, "", line) + + n = split(line, field) + + # Record which rule names are used, and generate their abbreviations. + f = zoneline ? 4 : linkline || ruleline ? 0 : 2 + r = field[f] + if (r ~ /^[^-+0-9]/) { + rule_used[r] = 1 + } + + if (zoneline) + zonename = startdef = field[2] + else if (linkline) + zonename = startdef = field[3] + else if (ruleline) + zonename = "" + + # Save the information for later output. + outline = make_line(n, field) + if (ruleline) + rule_output_line[nrule_out++] = outline + else if (linkline) { + # In vanguard format with Gawk, links are output sorted by destination. + if (dataform == "vanguard" && PROCINFO["version"]) + linkdef[zonename] = field[2] + else + link_output_line[nlink_out++] = outline + }else + zonedef[zonename] = (zoneline ? "" : zonedef[zonename] "\n") outline +} + +function omit_unused_rules( \ + i, field) +{ + for (i = 0; i < nrule_out; i++) { + split(rule_output_line[i], field) + if (!rule_used[field[2]]) + rule_output_line[i] = "" + } +} + +function abbreviate_rule_names( \ + abbr, f, field, i, n, newdef, newline, r, \ + zoneline, zonelines, zonename) +{ + for (i = 0; i < nrule_out; i++) { + n = split(rule_output_line[i], field) + if (n) { + r = field[2] + if (r ~ /^[^-+0-9]/) { + abbr = rule[r] + if (!abbr) { + rule[r] = abbr = gen_rule_name(r) + } + field[2] = abbr + rule_output_line[i] = make_line(n, field) + } + } + } + for (zonename in zonedef) { + zonelines = split(zonedef[zonename], zoneline, /\n/) + newdef = "" + for (i = 1; i <= zonelines; i++) { + newline = zoneline[i] + n = split(newline, field) + f = i == 1 ? 4 : 2 + r = rule[field[f]] + if (r) { + field[f] = r + newline = make_line(n, field) + } + newdef = (newdef ? newdef "\n" : "") newline + } + zonedef[zonename] = newdef + } +} + +function output_saved_lines( \ + i, zonename) +{ + for (i = 0; i < nrule_out; i++) + if (rule_output_line[i]) + print rule_output_line[i] + + # When using gawk, output zones sorted by name. + # This makes the output a bit more compressible. + PROCINFO["sorted_in"] = "@ind_str_asc" + for (zonename in zonedef) + print zonedef[zonename] + + if (nlink_out) + for (i = 0; i < nlink_out; i++) + print link_output_line[i] + else { + # When using gawk, output links sorted by destination. + # This also helps compressibility a bit. + PROCINFO["sorted_in"] = "@val_type_asc" + for (zonename in linkdef) + printf "L %s %s\n", linkdef[zonename], zonename + } +} + +BEGIN { + # Files that the output normally depends on. + default_dep["africa"] = 1 + default_dep["antarctica"] = 1 + default_dep["asia"] = 1 + default_dep["australasia"] = 1 + default_dep["backward"] = 1 + default_dep["etcetera"] = 1 + default_dep["europe"] = 1 + default_dep["factory"] = 1 + default_dep["northamerica"] = 1 + default_dep["southamerica"] = 1 + default_dep["ziguard.awk"] = 1 + default_dep["zishrink.awk"] = 1 + + # Output a version string from 'version' and related configuration variables + # supported by tzdb's Makefile. If you change the makefile or any other files + # that affect the output of this script, you should append '-SOMETHING' + # to the contents of 'version', where SOMETHING identifies what was changed. + + ndeps = split(deps, dep) + ddeps = "" + for (i = 1; i <= ndeps; i++) { + if (default_dep[dep[i]]) { + default_dep[dep[i]]++ + } else { + ddeps = ddeps " " dep[i] + } + } + for (d in default_dep) { + if (default_dep[d] == 1) { + ddeps = ddeps " !" d + } + } + print "# version", version + if (dataform != "main") { + print "# dataform", dataform + } + if (redo != "posix_right") { + print "# redo " redo + } + if (ddeps) { + print "# ddeps" ddeps + } + print "# This zic input file is in the public domain." + + prehash_rule_names() +} + +/^[\t ]*[^#\t ]/ { + process_input_line($0) +} + +END { + omit_unused_rules() + abbreviate_rule_names() + output_saved_lines() +} diff --git a/vendor/chrono-tz/tz/zone.tab b/vendor/chrono-tz/tz/zone.tab new file mode 100644 index 0000000000000..3fa9306afbad7 --- /dev/null +++ b/vendor/chrono-tz/tz/zone.tab @@ -0,0 +1,448 @@ +# tzdb timezone descriptions (deprecated version) +# +# This file is in the public domain, so clarified as of +# 2009-05-17 by Arthur David Olson. +# +# From Paul Eggert (2021-09-20): +# This file is intended as a backward-compatibility aid for older programs. +# New programs should use zone1970.tab. This file is like zone1970.tab (see +# zone1970.tab's comments), but with the following additional restrictions: +# +# 1. This file contains only ASCII characters. +# 2. The first data column contains exactly one country code. +# +# Because of (2), each row stands for an area that is the intersection +# of a region identified by a country code and of a timezone where civil +# clocks have agreed since 1970; this is a narrower definition than +# that of zone1970.tab. +# +# Unlike zone1970.tab, a row's third column can be a Link from +# 'backward' instead of a Zone. +# +# This table is intended as an aid for users, to help them select timezones +# appropriate for their practical needs. It is not intended to take or +# endorse any position on legal or territorial claims. +# +#country- +#code coordinates TZ comments +AD +4230+00131 Europe/Andorra +AE +2518+05518 Asia/Dubai +AF +3431+06912 Asia/Kabul +AG +1703-06148 America/Antigua +AI +1812-06304 America/Anguilla +AL +4120+01950 Europe/Tirane +AM +4011+04430 Asia/Yerevan +AO -0848+01314 Africa/Luanda +AQ -7750+16636 Antarctica/McMurdo New Zealand time - McMurdo, South Pole +AQ -6617+11031 Antarctica/Casey Casey +AQ -6835+07758 Antarctica/Davis Davis +AQ -6640+14001 Antarctica/DumontDUrville Dumont-d'Urville +AQ -6736+06253 Antarctica/Mawson Mawson +AQ -6448-06406 Antarctica/Palmer Palmer +AQ -6734-06808 Antarctica/Rothera Rothera +AQ -690022+0393524 Antarctica/Syowa Syowa +AQ -720041+0023206 Antarctica/Troll Troll +AQ -7824+10654 Antarctica/Vostok Vostok +AR -3436-05827 America/Argentina/Buenos_Aires Buenos Aires (BA, CF) +AR -3124-06411 America/Argentina/Cordoba Argentina (most areas: CB, CC, CN, ER, FM, MN, SE, SF) +AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) +AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) +AR -2649-06513 America/Argentina/Tucuman Tucuman (TM) +AR -2828-06547 America/Argentina/Catamarca Catamarca (CT), Chubut (CH) +AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) +AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) +AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) +AR -3319-06621 America/Argentina/San_Luis San Luis (SL) +AR -5138-06913 America/Argentina/Rio_Gallegos Santa Cruz (SC) +AR -5448-06818 America/Argentina/Ushuaia Tierra del Fuego (TF) +AS -1416-17042 Pacific/Pago_Pago +AT +4813+01620 Europe/Vienna +AU -3133+15905 Australia/Lord_Howe Lord Howe Island +AU -5430+15857 Antarctica/Macquarie Macquarie Island +AU -4253+14719 Australia/Hobart Tasmania +AU -3749+14458 Australia/Melbourne Victoria +AU -3352+15113 Australia/Sydney New South Wales (most areas) +AU -3157+14127 Australia/Broken_Hill New South Wales (Yancowinna) +AU -2728+15302 Australia/Brisbane Queensland (most areas) +AU -2016+14900 Australia/Lindeman Queensland (Whitsunday Islands) +AU -3455+13835 Australia/Adelaide South Australia +AU -1228+13050 Australia/Darwin Northern Territory +AU -3157+11551 Australia/Perth Western Australia (most areas) +AU -3143+12852 Australia/Eucla Western Australia (Eucla) +AW +1230-06958 America/Aruba +AX +6006+01957 Europe/Mariehamn +AZ +4023+04951 Asia/Baku +BA +4352+01825 Europe/Sarajevo +BB +1306-05937 America/Barbados +BD +2343+09025 Asia/Dhaka +BE +5050+00420 Europe/Brussels +BF +1222-00131 Africa/Ouagadougou +BG +4241+02319 Europe/Sofia +BH +2623+05035 Asia/Bahrain +BI -0323+02922 Africa/Bujumbura +BJ +0629+00237 Africa/Porto-Novo +BL +1753-06251 America/St_Barthelemy +BM +3217-06446 Atlantic/Bermuda +BN +0456+11455 Asia/Brunei +BO -1630-06809 America/La_Paz +BQ +120903-0681636 America/Kralendijk +BR -0351-03225 America/Noronha Atlantic islands +BR -0127-04829 America/Belem Para (east), Amapa +BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) +BR -0803-03454 America/Recife Pernambuco +BR -0712-04812 America/Araguaina Tocantins +BR -0940-03543 America/Maceio Alagoas, Sergipe +BR -1259-03831 America/Bahia Bahia +BR -2332-04637 America/Sao_Paulo Brazil (southeast: GO, DF, MG, ES, RJ, SP, PR, SC, RS) +BR -2027-05437 America/Campo_Grande Mato Grosso do Sul +BR -1535-05605 America/Cuiaba Mato Grosso +BR -0226-05452 America/Santarem Para (west) +BR -0846-06354 America/Porto_Velho Rondonia +BR +0249-06040 America/Boa_Vista Roraima +BR -0308-06001 America/Manaus Amazonas (east) +BR -0640-06952 America/Eirunepe Amazonas (west) +BR -0958-06748 America/Rio_Branco Acre +BS +2505-07721 America/Nassau +BT +2728+08939 Asia/Thimphu +BW -2439+02555 Africa/Gaborone +BY +5354+02734 Europe/Minsk +BZ +1730-08812 America/Belize +CA +4734-05243 America/St_Johns Newfoundland, Labrador (SE) +CA +4439-06336 America/Halifax Atlantic - NS (most areas), PE +CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) +CA +4606-06447 America/Moncton Atlantic - New Brunswick +CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) +CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) +CA +4339-07923 America/Toronto Eastern - ON & QC (most areas) +CA +6344-06828 America/Iqaluit Eastern - NU (most areas) +CA +484531-0913718 America/Atikokan EST - ON (Atikokan), NU (Coral H) +CA +4953-09709 America/Winnipeg Central - ON (west), Manitoba +CA +744144-0944945 America/Resolute Central - NU (Resolute) +CA +624900-0920459 America/Rankin_Inlet Central - NU (central) +CA +5024-10439 America/Regina CST - SK (most areas) +CA +5017-10750 America/Swift_Current CST - SK (midwest) +CA +5333-11328 America/Edmonton Mountain - AB, BC(E), NT(E), SK(W) +CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) +CA +682059-1334300 America/Inuvik Mountain - NT (west) +CA +4906-11631 America/Creston MST - BC (Creston) +CA +5546-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John) +CA +5848-12242 America/Fort_Nelson MST - BC (Ft Nelson) +CA +6043-13503 America/Whitehorse MST - Yukon (east) +CA +6404-13925 America/Dawson MST - Yukon (west) +CA +4916-12307 America/Vancouver Pacific - BC (most areas) +CC -1210+09655 Indian/Cocos +CD -0418+01518 Africa/Kinshasa Dem. Rep. of Congo (west) +CD -1140+02728 Africa/Lubumbashi Dem. Rep. of Congo (east) +CF +0422+01835 Africa/Bangui +CG -0416+01517 Africa/Brazzaville +CH +4723+00832 Europe/Zurich +CI +0519-00402 Africa/Abidjan +CK -2114-15946 Pacific/Rarotonga +CL -3327-07040 America/Santiago most of Chile +CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -2709-10926 Pacific/Easter Easter Island +CM +0403+00942 Africa/Douala +CN +3114+12128 Asia/Shanghai Beijing Time +CN +4348+08735 Asia/Urumqi Xinjiang Time +CO +0436-07405 America/Bogota +CR +0956-08405 America/Costa_Rica +CU +2308-08222 America/Havana +CV +1455-02331 Atlantic/Cape_Verde +CW +1211-06900 America/Curacao +CX -1025+10543 Indian/Christmas +CY +3510+03322 Asia/Nicosia most of Cyprus +CY +3507+03357 Asia/Famagusta Northern Cyprus +CZ +5005+01426 Europe/Prague +DE +5230+01322 Europe/Berlin most of Germany +DE +4742+00841 Europe/Busingen Busingen +DJ +1136+04309 Africa/Djibouti +DK +5540+01235 Europe/Copenhagen +DM +1518-06124 America/Dominica +DO +1828-06954 America/Santo_Domingo +DZ +3647+00303 Africa/Algiers +EC -0210-07950 America/Guayaquil Ecuador (mainland) +EC -0054-08936 Pacific/Galapagos Galapagos Islands +EE +5925+02445 Europe/Tallinn +EG +3003+03115 Africa/Cairo +EH +2709-01312 Africa/El_Aaiun +ER +1520+03853 Africa/Asmara +ES +4024-00341 Europe/Madrid Spain (mainland) +ES +3553-00519 Africa/Ceuta Ceuta, Melilla +ES +2806-01524 Atlantic/Canary Canary Islands +ET +0902+03842 Africa/Addis_Ababa +FI +6010+02458 Europe/Helsinki +FJ -1808+17825 Pacific/Fiji +FK -5142-05751 Atlantic/Stanley +FM +0725+15147 Pacific/Chuuk Chuuk/Truk, Yap +FM +0658+15813 Pacific/Pohnpei Pohnpei/Ponape +FM +0519+16259 Pacific/Kosrae Kosrae +FO +6201-00646 Atlantic/Faroe +FR +4852+00220 Europe/Paris +GA +0023+00927 Africa/Libreville +GB +513030-0000731 Europe/London +GD +1203-06145 America/Grenada +GE +4143+04449 Asia/Tbilisi +GF +0456-05220 America/Cayenne +GG +492717-0023210 Europe/Guernsey +GH +0533-00013 Africa/Accra +GI +3608-00521 Europe/Gibraltar +GL +6411-05144 America/Nuuk most of Greenland +GL +7646-01840 America/Danmarkshavn National Park (east coast) +GL +7029-02158 America/Scoresbysund Scoresbysund/Ittoqqortoormiit +GL +7634-06847 America/Thule Thule/Pituffik +GM +1328-01639 Africa/Banjul +GN +0931-01343 Africa/Conakry +GP +1614-06132 America/Guadeloupe +GQ +0345+00847 Africa/Malabo +GR +3758+02343 Europe/Athens +GS -5416-03632 Atlantic/South_Georgia +GT +1438-09031 America/Guatemala +GU +1328+14445 Pacific/Guam +GW +1151-01535 Africa/Bissau +GY +0648-05810 America/Guyana +HK +2217+11409 Asia/Hong_Kong +HN +1406-08713 America/Tegucigalpa +HR +4548+01558 Europe/Zagreb +HT +1832-07220 America/Port-au-Prince +HU +4730+01905 Europe/Budapest +ID -0610+10648 Asia/Jakarta Java, Sumatra +ID -0002+10920 Asia/Pontianak Borneo (west, central) +ID -0507+11924 Asia/Makassar Borneo (east, south), Sulawesi/Celebes, Bali, Nusa Tengarra, Timor (west) +ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya), Malukus/Moluccas +IE +5320-00615 Europe/Dublin +IL +314650+0351326 Asia/Jerusalem +IM +5409-00428 Europe/Isle_of_Man +IN +2232+08822 Asia/Kolkata +IO -0720+07225 Indian/Chagos +IQ +3321+04425 Asia/Baghdad +IR +3540+05126 Asia/Tehran +IS +6409-02151 Atlantic/Reykjavik +IT +4154+01229 Europe/Rome +JE +491101-0020624 Europe/Jersey +JM +175805-0764736 America/Jamaica +JO +3157+03556 Asia/Amman +JP +353916+1394441 Asia/Tokyo +KE -0117+03649 Africa/Nairobi +KG +4254+07436 Asia/Bishkek +KH +1133+10455 Asia/Phnom_Penh +KI +0125+17300 Pacific/Tarawa Gilbert Islands +KI -0247-17143 Pacific/Kanton Phoenix Islands +KI +0152-15720 Pacific/Kiritimati Line Islands +KM -1141+04316 Indian/Comoro +KN +1718-06243 America/St_Kitts +KP +3901+12545 Asia/Pyongyang +KR +3733+12658 Asia/Seoul +KW +2920+04759 Asia/Kuwait +KY +1918-08123 America/Cayman +KZ +4315+07657 Asia/Almaty most of Kazakhstan +KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda +KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay +KZ +5017+05710 Asia/Aqtobe Aqtobe/Aktobe +KZ +4431+05016 Asia/Aqtau Mangghystau/Mankistau +KZ +4707+05156 Asia/Atyrau Atyrau/Atirau/Gur'yev +KZ +5113+05121 Asia/Oral West Kazakhstan +LA +1758+10236 Asia/Vientiane +LB +3353+03530 Asia/Beirut +LC +1401-06100 America/St_Lucia +LI +4709+00931 Europe/Vaduz +LK +0656+07951 Asia/Colombo +LR +0618-01047 Africa/Monrovia +LS -2928+02730 Africa/Maseru +LT +5441+02519 Europe/Vilnius +LU +4936+00609 Europe/Luxembourg +LV +5657+02406 Europe/Riga +LY +3254+01311 Africa/Tripoli +MA +3339-00735 Africa/Casablanca +MC +4342+00723 Europe/Monaco +MD +4700+02850 Europe/Chisinau +ME +4226+01916 Europe/Podgorica +MF +1804-06305 America/Marigot +MG -1855+04731 Indian/Antananarivo +MH +0709+17112 Pacific/Majuro most of Marshall Islands +MH +0905+16720 Pacific/Kwajalein Kwajalein +MK +4159+02126 Europe/Skopje +ML +1239-00800 Africa/Bamako +MM +1647+09610 Asia/Yangon +MN +4755+10653 Asia/Ulaanbaatar most of Mongolia +MN +4801+09139 Asia/Hovd Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan +MN +4804+11430 Asia/Choibalsan Dornod, Sukhbaatar +MO +221150+1133230 Asia/Macau +MP +1512+14545 Pacific/Saipan +MQ +1436-06105 America/Martinique +MR +1806-01557 Africa/Nouakchott +MS +1643-06213 America/Montserrat +MT +3554+01431 Europe/Malta +MU -2010+05730 Indian/Mauritius +MV +0410+07330 Indian/Maldives +MW -1547+03500 Africa/Blantyre +MX +1924-09909 America/Mexico_City Central Mexico +MX +2105-08646 America/Cancun Quintana Roo +MX +2058-08937 America/Merida Campeche, Yucatan +MX +2540-10019 America/Monterrey Durango; Coahuila, Nuevo Leon, Tamaulipas (most areas) +MX +2550-09730 America/Matamoros Coahuila, Nuevo Leon, Tamaulipas (US border) +MX +2838-10605 America/Chihuahua Chihuahua (most areas) +MX +3144-10629 America/Ciudad_Juarez Chihuahua (US border - west) +MX +2934-10425 America/Ojinaga Chihuahua (US border - east) +MX +2313-10625 America/Mazatlan Baja California Sur, Nayarit (most areas), Sinaloa +MX +2048-10515 America/Bahia_Banderas Bahia de Banderas +MX +2904-11058 America/Hermosillo Sonora +MX +3232-11701 America/Tijuana Baja California +MY +0310+10142 Asia/Kuala_Lumpur Malaysia (peninsula) +MY +0133+11020 Asia/Kuching Sabah, Sarawak +MZ -2558+03235 Africa/Maputo +NA -2234+01706 Africa/Windhoek +NC -2216+16627 Pacific/Noumea +NE +1331+00207 Africa/Niamey +NF -2903+16758 Pacific/Norfolk +NG +0627+00324 Africa/Lagos +NI +1209-08617 America/Managua +NL +5222+00454 Europe/Amsterdam +NO +5955+01045 Europe/Oslo +NP +2743+08519 Asia/Kathmandu +NR -0031+16655 Pacific/Nauru +NU -1901-16955 Pacific/Niue +NZ -3652+17446 Pacific/Auckland most of New Zealand +NZ -4357-17633 Pacific/Chatham Chatham Islands +OM +2336+05835 Asia/Muscat +PA +0858-07932 America/Panama +PE -1203-07703 America/Lima +PF -1732-14934 Pacific/Tahiti Society Islands +PF -0900-13930 Pacific/Marquesas Marquesas Islands +PF -2308-13457 Pacific/Gambier Gambier Islands +PG -0930+14710 Pacific/Port_Moresby most of Papua New Guinea +PG -0613+15534 Pacific/Bougainville Bougainville +PH +1435+12100 Asia/Manila +PK +2452+06703 Asia/Karachi +PL +5215+02100 Europe/Warsaw +PM +4703-05620 America/Miquelon +PN -2504-13005 Pacific/Pitcairn +PR +182806-0660622 America/Puerto_Rico +PS +3130+03428 Asia/Gaza Gaza Strip +PS +313200+0350542 Asia/Hebron West Bank +PT +3843-00908 Europe/Lisbon Portugal (mainland) +PT +3238-01654 Atlantic/Madeira Madeira Islands +PT +3744-02540 Atlantic/Azores Azores +PW +0720+13429 Pacific/Palau +PY -2516-05740 America/Asuncion +QA +2517+05132 Asia/Qatar +RE -2052+05528 Indian/Reunion +RO +4426+02606 Europe/Bucharest +RS +4450+02030 Europe/Belgrade +RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad +RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area +# The obsolescent zone.tab format cannot represent Europe/Simferopol well. +# Put it in RU section and list as UA. See "territorial claims" above. +# Programs should use zone1970.tab instead; see above. +UA +4457+03406 Europe/Simferopol Crimea +RU +5836+04939 Europe/Kirov MSK+00 - Kirov +RU +4844+04425 Europe/Volgograd MSK+00 - Volgograd +RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan +RU +5134+04602 Europe/Saratov MSK+01 - Saratov +RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk +RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia +RU +5651+06036 Asia/Yekaterinburg MSK+02 - Urals +RU +5500+07324 Asia/Omsk MSK+03 - Omsk +RU +5502+08255 Asia/Novosibirsk MSK+04 - Novosibirsk +RU +5322+08345 Asia/Barnaul MSK+04 - Altai +RU +5630+08458 Asia/Tomsk MSK+04 - Tomsk +RU +5345+08707 Asia/Novokuznetsk MSK+04 - Kemerovo +RU +5601+09250 Asia/Krasnoyarsk MSK+04 - Krasnoyarsk area +RU +5216+10420 Asia/Irkutsk MSK+05 - Irkutsk, Buryatia +RU +5203+11328 Asia/Chita MSK+06 - Zabaykalsky +RU +6200+12940 Asia/Yakutsk MSK+06 - Lena River +RU +623923+1353314 Asia/Khandyga MSK+06 - Tomponsky, Ust-Maysky +RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River +RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky +RU +5934+15048 Asia/Magadan MSK+08 - Magadan +RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island +RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E), N Kuril Is +RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka +RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea +RW -0157+03004 Africa/Kigali +SA +2438+04643 Asia/Riyadh +SB -0932+16012 Pacific/Guadalcanal +SC -0440+05528 Indian/Mahe +SD +1536+03232 Africa/Khartoum +SE +5920+01803 Europe/Stockholm +SG +0117+10351 Asia/Singapore +SH -1555-00542 Atlantic/St_Helena +SI +4603+01431 Europe/Ljubljana +SJ +7800+01600 Arctic/Longyearbyen +SK +4809+01707 Europe/Bratislava +SL +0830-01315 Africa/Freetown +SM +4355+01228 Europe/San_Marino +SN +1440-01726 Africa/Dakar +SO +0204+04522 Africa/Mogadishu +SR +0550-05510 America/Paramaribo +SS +0451+03137 Africa/Juba +ST +0020+00644 Africa/Sao_Tome +SV +1342-08912 America/El_Salvador +SX +180305-0630250 America/Lower_Princes +SY +3330+03618 Asia/Damascus +SZ -2618+03106 Africa/Mbabane +TC +2128-07108 America/Grand_Turk +TD +1207+01503 Africa/Ndjamena +TF -492110+0701303 Indian/Kerguelen +TG +0608+00113 Africa/Lome +TH +1345+10031 Asia/Bangkok +TJ +3835+06848 Asia/Dushanbe +TK -0922-17114 Pacific/Fakaofo +TL -0833+12535 Asia/Dili +TM +3757+05823 Asia/Ashgabat +TN +3648+01011 Africa/Tunis +TO -210800-1751200 Pacific/Tongatapu +TR +4101+02858 Europe/Istanbul +TT +1039-06131 America/Port_of_Spain +TV -0831+17913 Pacific/Funafuti +TW +2503+12130 Asia/Taipei +TZ -0648+03917 Africa/Dar_es_Salaam +UA +5026+03031 Europe/Kyiv most of Ukraine +UG +0019+03225 Africa/Kampala +UM +2813-17722 Pacific/Midway Midway Islands +UM +1917+16637 Pacific/Wake Wake Island +US +404251-0740023 America/New_York Eastern (most areas) +US +421953-0830245 America/Detroit Eastern - MI (most areas) +US +381515-0854534 America/Kentucky/Louisville Eastern - KY (Louisville area) +US +364947-0845057 America/Kentucky/Monticello Eastern - KY (Wayne) +US +394606-0860929 America/Indiana/Indianapolis Eastern - IN (most areas) +US +384038-0873143 America/Indiana/Vincennes Eastern - IN (Da, Du, K, Mn) +US +410305-0863611 America/Indiana/Winamac Eastern - IN (Pulaski) +US +382232-0862041 America/Indiana/Marengo Eastern - IN (Crawford) +US +382931-0871643 America/Indiana/Petersburg Eastern - IN (Pike) +US +384452-0850402 America/Indiana/Vevay Eastern - IN (Switzerland) +US +415100-0873900 America/Chicago Central (most areas) +US +375711-0864541 America/Indiana/Tell_City Central - IN (Perry) +US +411745-0863730 America/Indiana/Knox Central - IN (Starke) +US +450628-0873651 America/Menominee Central - MI (Wisconsin border) +US +470659-1011757 America/North_Dakota/Center Central - ND (Oliver) +US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) +US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) +US +394421-1045903 America/Denver Mountain (most areas) +US +433649-1161209 America/Boise Mountain - ID (south), OR (east) +US +332654-1120424 America/Phoenix MST - AZ (except Navajo) +US +340308-1181434 America/Los_Angeles Pacific +US +611305-1495401 America/Anchorage Alaska (most areas) +US +581807-1342511 America/Juneau Alaska - Juneau area +US +571035-1351807 America/Sitka Alaska - Sitka area +US +550737-1313435 America/Metlakatla Alaska - Annette Island +US +593249-1394338 America/Yakutat Alaska - Yakutat +US +643004-1652423 America/Nome Alaska (west) +US +515248-1763929 America/Adak Alaska - western Aleutians +US +211825-1575130 Pacific/Honolulu Hawaii +UY -345433-0561245 America/Montevideo +UZ +3940+06648 Asia/Samarkand Uzbekistan (west) +UZ +4120+06918 Asia/Tashkent Uzbekistan (east) +VA +415408+0122711 Europe/Vatican +VC +1309-06114 America/St_Vincent +VE +1030-06656 America/Caracas +VG +1827-06437 America/Tortola +VI +1821-06456 America/St_Thomas +VN +1045+10640 Asia/Ho_Chi_Minh +VU -1740+16825 Pacific/Efate +WF -1318-17610 Pacific/Wallis +WS -1350-17144 Pacific/Apia +YE +1245+04512 Asia/Aden +YT -1247+04514 Indian/Mayotte +ZA -2615+02800 Africa/Johannesburg +ZM -1525+02817 Africa/Lusaka +ZW -1750+03103 Africa/Harare diff --git a/vendor/chrono-tz/tz/zone1970.tab b/vendor/chrono-tz/tz/zone1970.tab new file mode 100644 index 0000000000000..abd9489753f1a --- /dev/null +++ b/vendor/chrono-tz/tz/zone1970.tab @@ -0,0 +1,375 @@ +# tzdb timezone descriptions +# +# This file is in the public domain. +# +# From Paul Eggert (2018-06-27): +# This file contains a table where each row stands for a timezone where +# civil timestamps have agreed since 1970. Columns are separated by +# a single tab. Lines beginning with '#' are comments. All text uses +# UTF-8 encoding. The columns of the table are as follows: +# +# 1. The countries that overlap the timezone, as a comma-separated list +# of ISO 3166 2-character country codes. See the file 'iso3166.tab'. +# 2. Latitude and longitude of the timezone's principal location +# in ISO 6709 sign-degrees-minutes-seconds format, +# either ±DDMM±DDDMM or ±DDMMSS±DDDMMSS, +# first latitude (+ is north), then longitude (+ is east). +# 3. Timezone name used in value of TZ environment variable. +# Please see the theory.html file for how these names are chosen. +# If multiple timezones overlap a country, each has a row in the +# table, with each column 1 containing the country code. +# 4. Comments; present if and only if countries have multiple timezones, +# and useful only for those countries. For example, the comments +# for the row with countries CH,DE,LI and name Europe/Zurich +# are useful only for DE, since CH and LI have no other timezones. +# +# If a timezone covers multiple countries, the most-populous city is used, +# and that country is listed first in column 1; any other countries +# are listed alphabetically by country code. The table is sorted +# first by country code, then (if possible) by an order within the +# country that (1) makes some geographical sense, and (2) puts the +# most populous timezones first, where that does not contradict (1). +# +# This table is intended as an aid for users, to help them select timezones +# appropriate for their practical needs. It is not intended to take or +# endorse any position on legal or territorial claims. +# +#country- +#codes coordinates TZ comments +AD +4230+00131 Europe/Andorra +AE,OM,RE,SC,TF +2518+05518 Asia/Dubai Crozet +AF +3431+06912 Asia/Kabul +AL +4120+01950 Europe/Tirane +AM +4011+04430 Asia/Yerevan +AQ -6617+11031 Antarctica/Casey Casey +AQ -6835+07758 Antarctica/Davis Davis +AQ -6736+06253 Antarctica/Mawson Mawson +AQ -6448-06406 Antarctica/Palmer Palmer +AQ -6734-06808 Antarctica/Rothera Rothera +AQ -720041+0023206 Antarctica/Troll Troll +AQ -7824+10654 Antarctica/Vostok Vostok +AR -3436-05827 America/Argentina/Buenos_Aires Buenos Aires (BA, CF) +AR -3124-06411 America/Argentina/Cordoba most areas: CB, CC, CN, ER, FM, MN, SE, SF +AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) +AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) +AR -2649-06513 America/Argentina/Tucuman Tucumán (TM) +AR -2828-06547 America/Argentina/Catamarca Catamarca (CT), Chubut (CH) +AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) +AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) +AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) +AR -3319-06621 America/Argentina/San_Luis San Luis (SL) +AR -5138-06913 America/Argentina/Rio_Gallegos Santa Cruz (SC) +AR -5448-06818 America/Argentina/Ushuaia Tierra del Fuego (TF) +AS,UM -1416-17042 Pacific/Pago_Pago Midway +AT +4813+01620 Europe/Vienna +AU -3133+15905 Australia/Lord_Howe Lord Howe Island +AU -5430+15857 Antarctica/Macquarie Macquarie Island +AU -4253+14719 Australia/Hobart Tasmania +AU -3749+14458 Australia/Melbourne Victoria +AU -3352+15113 Australia/Sydney New South Wales (most areas) +AU -3157+14127 Australia/Broken_Hill New South Wales (Yancowinna) +AU -2728+15302 Australia/Brisbane Queensland (most areas) +AU -2016+14900 Australia/Lindeman Queensland (Whitsunday Islands) +AU -3455+13835 Australia/Adelaide South Australia +AU -1228+13050 Australia/Darwin Northern Territory +AU -3157+11551 Australia/Perth Western Australia (most areas) +AU -3143+12852 Australia/Eucla Western Australia (Eucla) +AZ +4023+04951 Asia/Baku +BB +1306-05937 America/Barbados +BD +2343+09025 Asia/Dhaka +BE,LU,NL +5050+00420 Europe/Brussels +BG +4241+02319 Europe/Sofia +BM +3217-06446 Atlantic/Bermuda +BO -1630-06809 America/La_Paz +BR -0351-03225 America/Noronha Atlantic islands +BR -0127-04829 America/Belem Pará (east), Amapá +BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) +BR -0803-03454 America/Recife Pernambuco +BR -0712-04812 America/Araguaina Tocantins +BR -0940-03543 America/Maceio Alagoas, Sergipe +BR -1259-03831 America/Bahia Bahia +BR -2332-04637 America/Sao_Paulo Brazil (southeast: GO, DF, MG, ES, RJ, SP, PR, SC, RS) +BR -2027-05437 America/Campo_Grande Mato Grosso do Sul +BR -1535-05605 America/Cuiaba Mato Grosso +BR -0226-05452 America/Santarem Pará (west) +BR -0846-06354 America/Porto_Velho Rondônia +BR +0249-06040 America/Boa_Vista Roraima +BR -0308-06001 America/Manaus Amazonas (east) +BR -0640-06952 America/Eirunepe Amazonas (west) +BR -0958-06748 America/Rio_Branco Acre +BT +2728+08939 Asia/Thimphu +BY +5354+02734 Europe/Minsk +BZ +1730-08812 America/Belize +CA +4734-05243 America/St_Johns Newfoundland, Labrador (SE) +CA +4439-06336 America/Halifax Atlantic - NS (most areas), PE +CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) +CA +4606-06447 America/Moncton Atlantic - New Brunswick +CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) +CA,BS +4339-07923 America/Toronto Eastern - ON & QC (most areas) +CA +6344-06828 America/Iqaluit Eastern - NU (most areas) +CA +4953-09709 America/Winnipeg Central - ON (west), Manitoba +CA +744144-0944945 America/Resolute Central - NU (Resolute) +CA +624900-0920459 America/Rankin_Inlet Central - NU (central) +CA +5024-10439 America/Regina CST - SK (most areas) +CA +5017-10750 America/Swift_Current CST - SK (midwest) +CA +5333-11328 America/Edmonton Mountain - AB, BC(E), NT(E), SK(W) +CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) +CA +682059-1334300 America/Inuvik Mountain - NT (west) +CA +5546-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John) +CA +5848-12242 America/Fort_Nelson MST - BC (Ft Nelson) +CA +6043-13503 America/Whitehorse MST - Yukon (east) +CA +6404-13925 America/Dawson MST - Yukon (west) +CA +4916-12307 America/Vancouver Pacific - BC (most areas) +CH,DE,LI +4723+00832 Europe/Zurich Büsingen +CI,BF,GH,GM,GN,IS,ML,MR,SH,SL,SN,TG +0519-00402 Africa/Abidjan +CK -2114-15946 Pacific/Rarotonga +CL -3327-07040 America/Santiago most of Chile +CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -2709-10926 Pacific/Easter Easter Island +CN +3114+12128 Asia/Shanghai Beijing Time +CN +4348+08735 Asia/Urumqi Xinjiang Time +CO +0436-07405 America/Bogota +CR +0956-08405 America/Costa_Rica +CU +2308-08222 America/Havana +CV +1455-02331 Atlantic/Cape_Verde +CY +3510+03322 Asia/Nicosia most of Cyprus +CY +3507+03357 Asia/Famagusta Northern Cyprus +CZ,SK +5005+01426 Europe/Prague +DE,DK,NO,SE,SJ +5230+01322 Europe/Berlin most of Germany +DO +1828-06954 America/Santo_Domingo +DZ +3647+00303 Africa/Algiers +EC -0210-07950 America/Guayaquil Ecuador (mainland) +EC -0054-08936 Pacific/Galapagos Galápagos Islands +EE +5925+02445 Europe/Tallinn +EG +3003+03115 Africa/Cairo +EH +2709-01312 Africa/El_Aaiun +ES +4024-00341 Europe/Madrid Spain (mainland) +ES +3553-00519 Africa/Ceuta Ceuta, Melilla +ES +2806-01524 Atlantic/Canary Canary Islands +FI,AX +6010+02458 Europe/Helsinki +FJ -1808+17825 Pacific/Fiji +FK -5142-05751 Atlantic/Stanley +FM +0519+16259 Pacific/Kosrae Kosrae +FO +6201-00646 Atlantic/Faroe +FR,MC +4852+00220 Europe/Paris +GB,GG,IM,JE +513030-0000731 Europe/London +GE +4143+04449 Asia/Tbilisi +GF +0456-05220 America/Cayenne +GI +3608-00521 Europe/Gibraltar +GL +6411-05144 America/Nuuk most of Greenland +GL +7646-01840 America/Danmarkshavn National Park (east coast) +GL +7029-02158 America/Scoresbysund Scoresbysund/Ittoqqortoormiit +GL +7634-06847 America/Thule Thule/Pituffik +GR +3758+02343 Europe/Athens +GS -5416-03632 Atlantic/South_Georgia +GT +1438-09031 America/Guatemala +GU,MP +1328+14445 Pacific/Guam +GW +1151-01535 Africa/Bissau +GY +0648-05810 America/Guyana +HK +2217+11409 Asia/Hong_Kong +HN +1406-08713 America/Tegucigalpa +HT +1832-07220 America/Port-au-Prince +HU +4730+01905 Europe/Budapest +ID -0610+10648 Asia/Jakarta Java, Sumatra +ID -0002+10920 Asia/Pontianak Borneo (west, central) +ID -0507+11924 Asia/Makassar Borneo (east, south), Sulawesi/Celebes, Bali, Nusa Tengarra, Timor (west) +ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya), Malukus/Moluccas +IE +5320-00615 Europe/Dublin +IL +314650+0351326 Asia/Jerusalem +IN +2232+08822 Asia/Kolkata +IO -0720+07225 Indian/Chagos +IQ +3321+04425 Asia/Baghdad +IR +3540+05126 Asia/Tehran +IT,SM,VA +4154+01229 Europe/Rome +JM +175805-0764736 America/Jamaica +JO +3157+03556 Asia/Amman +JP +353916+1394441 Asia/Tokyo +KE,DJ,ER,ET,KM,MG,SO,TZ,UG,YT -0117+03649 Africa/Nairobi +KG +4254+07436 Asia/Bishkek +KI,MH,TV,UM,WF +0125+17300 Pacific/Tarawa Gilberts, Marshalls, Wake +KI -0247-17143 Pacific/Kanton Phoenix Islands +KI +0152-15720 Pacific/Kiritimati Line Islands +KP +3901+12545 Asia/Pyongyang +KR +3733+12658 Asia/Seoul +KZ +4315+07657 Asia/Almaty most of Kazakhstan +KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda +KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay +KZ +5017+05710 Asia/Aqtobe Aqtöbe/Aktobe +KZ +4431+05016 Asia/Aqtau Mangghystaū/Mankistau +KZ +4707+05156 Asia/Atyrau Atyraū/Atirau/Gur'yev +KZ +5113+05121 Asia/Oral West Kazakhstan +LB +3353+03530 Asia/Beirut +LK +0656+07951 Asia/Colombo +LR +0618-01047 Africa/Monrovia +LT +5441+02519 Europe/Vilnius +LV +5657+02406 Europe/Riga +LY +3254+01311 Africa/Tripoli +MA +3339-00735 Africa/Casablanca +MD +4700+02850 Europe/Chisinau +MH +0905+16720 Pacific/Kwajalein Kwajalein +MM,CC +1647+09610 Asia/Yangon +MN +4755+10653 Asia/Ulaanbaatar most of Mongolia +MN +4801+09139 Asia/Hovd Bayan-Ölgii, Govi-Altai, Hovd, Uvs, Zavkhan +MN +4804+11430 Asia/Choibalsan Dornod, Sükhbaatar +MO +221150+1133230 Asia/Macau +MQ +1436-06105 America/Martinique +MT +3554+01431 Europe/Malta +MU -2010+05730 Indian/Mauritius +MV,TF +0410+07330 Indian/Maldives Kerguelen, St Paul I, Amsterdam I +MX +1924-09909 America/Mexico_City Central Mexico +MX +2105-08646 America/Cancun Quintana Roo +MX +2058-08937 America/Merida Campeche, Yucatán +MX +2540-10019 America/Monterrey Durango; Coahuila, Nuevo León, Tamaulipas (most areas) +MX +2550-09730 America/Matamoros Coahuila, Nuevo León, Tamaulipas (US border) +MX +2838-10605 America/Chihuahua Chihuahua (most areas) +MX +3144-10629 America/Ciudad_Juarez Chihuahua (US border - west) +MX +2934-10425 America/Ojinaga Chihuahua (US border - east) +MX +2313-10625 America/Mazatlan Baja California Sur, Nayarit (most areas), Sinaloa +MX +2048-10515 America/Bahia_Banderas Bahía de Banderas +MX +2904-11058 America/Hermosillo Sonora +MX +3232-11701 America/Tijuana Baja California +MY,BN +0133+11020 Asia/Kuching Sabah, Sarawak +MZ,BI,BW,CD,MW,RW,ZM,ZW -2558+03235 Africa/Maputo Central Africa Time +NA -2234+01706 Africa/Windhoek +NC -2216+16627 Pacific/Noumea +NF -2903+16758 Pacific/Norfolk +NG,AO,BJ,CD,CF,CG,CM,GA,GQ,NE +0627+00324 Africa/Lagos West Africa Time +NI +1209-08617 America/Managua +NP +2743+08519 Asia/Kathmandu +NR -0031+16655 Pacific/Nauru +NU -1901-16955 Pacific/Niue +NZ,AQ -3652+17446 Pacific/Auckland New Zealand time +NZ -4357-17633 Pacific/Chatham Chatham Islands +PA,CA,KY +0858-07932 America/Panama EST - ON (Atikokan), NU (Coral H) +PE -1203-07703 America/Lima +PF -1732-14934 Pacific/Tahiti Society Islands +PF -0900-13930 Pacific/Marquesas Marquesas Islands +PF -2308-13457 Pacific/Gambier Gambier Islands +PG,AQ,FM -0930+14710 Pacific/Port_Moresby Papua New Guinea (most areas), Chuuk, Yap, Dumont d'Urville +PG -0613+15534 Pacific/Bougainville Bougainville +PH +1435+12100 Asia/Manila +PK +2452+06703 Asia/Karachi +PL +5215+02100 Europe/Warsaw +PM +4703-05620 America/Miquelon +PN -2504-13005 Pacific/Pitcairn +PR,AG,CA,AI,AW,BL,BQ,CW,DM,GD,GP,KN,LC,MF,MS,SX,TT,VC,VG,VI +182806-0660622 America/Puerto_Rico AST - QC (Lower North Shore) +PS +3130+03428 Asia/Gaza Gaza Strip +PS +313200+0350542 Asia/Hebron West Bank +PT +3843-00908 Europe/Lisbon Portugal (mainland) +PT +3238-01654 Atlantic/Madeira Madeira Islands +PT +3744-02540 Atlantic/Azores Azores +PW +0720+13429 Pacific/Palau +PY -2516-05740 America/Asuncion +QA,BH +2517+05132 Asia/Qatar +RO +4426+02606 Europe/Bucharest +RS,BA,HR,ME,MK,SI +4450+02030 Europe/Belgrade +RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad +RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area +# Mention RU and UA alphabetically. See "territorial claims" above. +RU,UA +4457+03406 Europe/Simferopol Crimea +RU +5836+04939 Europe/Kirov MSK+00 - Kirov +RU +4844+04425 Europe/Volgograd MSK+00 - Volgograd +RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan +RU +5134+04602 Europe/Saratov MSK+01 - Saratov +RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk +RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia +RU +5651+06036 Asia/Yekaterinburg MSK+02 - Urals +RU +5500+07324 Asia/Omsk MSK+03 - Omsk +RU +5502+08255 Asia/Novosibirsk MSK+04 - Novosibirsk +RU +5322+08345 Asia/Barnaul MSK+04 - Altai +RU +5630+08458 Asia/Tomsk MSK+04 - Tomsk +RU +5345+08707 Asia/Novokuznetsk MSK+04 - Kemerovo +RU +5601+09250 Asia/Krasnoyarsk MSK+04 - Krasnoyarsk area +RU +5216+10420 Asia/Irkutsk MSK+05 - Irkutsk, Buryatia +RU +5203+11328 Asia/Chita MSK+06 - Zabaykalsky +RU +6200+12940 Asia/Yakutsk MSK+06 - Lena River +RU +623923+1353314 Asia/Khandyga MSK+06 - Tomponsky, Ust-Maysky +RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River +RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky +RU +5934+15048 Asia/Magadan MSK+08 - Magadan +RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island +RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E), N Kuril Is +RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka +RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea +SA,AQ,KW,YE +2438+04643 Asia/Riyadh Syowa +SB,FM -0932+16012 Pacific/Guadalcanal Pohnpei +SD +1536+03232 Africa/Khartoum +SG,MY +0117+10351 Asia/Singapore peninsular Malaysia +SR +0550-05510 America/Paramaribo +SS +0451+03137 Africa/Juba +ST +0020+00644 Africa/Sao_Tome +SV +1342-08912 America/El_Salvador +SY +3330+03618 Asia/Damascus +TC +2128-07108 America/Grand_Turk +TD +1207+01503 Africa/Ndjamena +TH,CX,KH,LA,VN +1345+10031 Asia/Bangkok north Vietnam +TJ +3835+06848 Asia/Dushanbe +TK -0922-17114 Pacific/Fakaofo +TL -0833+12535 Asia/Dili +TM +3757+05823 Asia/Ashgabat +TN +3648+01011 Africa/Tunis +TO -210800-1751200 Pacific/Tongatapu +TR +4101+02858 Europe/Istanbul +TW +2503+12130 Asia/Taipei +UA +5026+03031 Europe/Kyiv most of Ukraine +US +404251-0740023 America/New_York Eastern (most areas) +US +421953-0830245 America/Detroit Eastern - MI (most areas) +US +381515-0854534 America/Kentucky/Louisville Eastern - KY (Louisville area) +US +364947-0845057 America/Kentucky/Monticello Eastern - KY (Wayne) +US +394606-0860929 America/Indiana/Indianapolis Eastern - IN (most areas) +US +384038-0873143 America/Indiana/Vincennes Eastern - IN (Da, Du, K, Mn) +US +410305-0863611 America/Indiana/Winamac Eastern - IN (Pulaski) +US +382232-0862041 America/Indiana/Marengo Eastern - IN (Crawford) +US +382931-0871643 America/Indiana/Petersburg Eastern - IN (Pike) +US +384452-0850402 America/Indiana/Vevay Eastern - IN (Switzerland) +US +415100-0873900 America/Chicago Central (most areas) +US +375711-0864541 America/Indiana/Tell_City Central - IN (Perry) +US +411745-0863730 America/Indiana/Knox Central - IN (Starke) +US +450628-0873651 America/Menominee Central - MI (Wisconsin border) +US +470659-1011757 America/North_Dakota/Center Central - ND (Oliver) +US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) +US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) +US +394421-1045903 America/Denver Mountain (most areas) +US +433649-1161209 America/Boise Mountain - ID (south), OR (east) +US,CA +332654-1120424 America/Phoenix MST - AZ (most areas), Creston BC +US +340308-1181434 America/Los_Angeles Pacific +US +611305-1495401 America/Anchorage Alaska (most areas) +US +581807-1342511 America/Juneau Alaska - Juneau area +US +571035-1351807 America/Sitka Alaska - Sitka area +US +550737-1313435 America/Metlakatla Alaska - Annette Island +US +593249-1394338 America/Yakutat Alaska - Yakutat +US +643004-1652423 America/Nome Alaska (west) +US +515248-1763929 America/Adak Alaska - western Aleutians +US +211825-1575130 Pacific/Honolulu Hawaii +UY -345433-0561245 America/Montevideo +UZ +3940+06648 Asia/Samarkand Uzbekistan (west) +UZ +4120+06918 Asia/Tashkent Uzbekistan (east) +VE +1030-06656 America/Caracas +VN +1045+10640 Asia/Ho_Chi_Minh south Vietnam +VU -1740+16825 Pacific/Efate +WS -1350-17144 Pacific/Apia +ZA,LS,SZ -2615+02800 Africa/Johannesburg +# +# The next section contains experimental tab-separated comments for +# use by user agents like tzselect that identify continents and oceans. +# +# For example, the comment "#@AQAntarctica/" means the country code +# AQ is in the continent Antarctica regardless of the Zone name, +# so Pacific/Auckland should be listed under Antarctica as well as +# under the Pacific because its line's country codes include AQ. +# +# If more than one country code is affected each is listed separated +# by commas, e.g., #@IS,SHAtlantic/". If a country code is in +# more than one continent or ocean, each is listed separated by +# commas, e.g., the second column of "#@CY,TRAsia/,Europe/". +# +# These experimental comments are present only for country codes where +# the continent or ocean is not already obvious from the Zone name. +# For example, there is no such comment for RU since it already +# corresponds to Zone names starting with both "Europe/" and "Asia/". +# +#@AQ Antarctica/ +#@IS,SH Atlantic/ +#@CY,TR Asia/,Europe/ +#@SJ Arctic/ +#@CC,CX,KM,MG,YT Indian/ diff --git a/vendor/chrono-tz/tz/zonenow.tab b/vendor/chrono-tz/tz/zonenow.tab new file mode 100644 index 0000000000000..b6f2910956fb6 --- /dev/null +++ b/vendor/chrono-tz/tz/zonenow.tab @@ -0,0 +1,303 @@ +# tzdb timezone descriptions, for users who do not care about old timestamps +# +# This file is in the public domain. +# +# From Paul Eggert (2023-12-18): +# This file contains a table where each row stands for a timezone +# where civil timestamps are predicted to agree from now on. +# This file is like zone1970.tab (see zone1970.tab's coments), +# but with the following changes: +# +# 1. Each timezone corresponds to a set of clocks that are planned +# to agree from now on. This is a larger set of clocks than in +# zone1970.tab, where each timezone's clocks must agree from 1970 on. +# 2. The first column is irrelevant and ignored. +# 3. The table is sorted in a different way: +# first by standard time UTC offset; +# then, if DST is used, by daylight saving UTC offset; +# then by time zone abbreviation. +# 4. Every timezone has a nonempty comments column, with wording +# distinguishing the timezone only from other timezones with the +# same UTC offset at some point during the year. +# +# The format of this table is experimental, and may change in future versions. +# +# This table is intended as an aid for users, to help them select timezones +# appropriate for their practical needs. It is not intended to take or +# endorse any position on legal or territorial claims. +# +#XX coordinates TZ comments +# +# -11 - SST +XX -1416-17042 Pacific/Pago_Pago Midway; Samoa ("SST") +# +# -11 +XX -1901-16955 Pacific/Niue Niue +# +# -10 - HST +XX +211825-1575130 Pacific/Honolulu Hawaii ("HST") +# +# -10 +XX -1732-14934 Pacific/Tahiti Tahiti; Cook Islands +# +# -10/-09 - HST / HDT (North America DST) +XX +515248-1763929 America/Adak western Aleutians in Alaska ("HST/HDT") +# +# -09:30 +XX -0900-13930 Pacific/Marquesas Marquesas +# +# -09 +XX -2308-13457 Pacific/Gambier Gambier +# +# -09/-08 - AKST/AKDT (North America DST) +XX +611305-1495401 America/Anchorage most of Alaska ("AKST/AKDT") +# +# -08 +XX -2504-13005 Pacific/Pitcairn Pitcairn +# +# -08/-07 - PST/PDT (North America DST) +XX +340308-1181434 America/Los_Angeles Pacific ("PST/PDT") - US & Canada; Mexico near US border +# +# -07 - MST +XX +332654-1120424 America/Phoenix Mountain Standard ("MST") - Arizona; western Mexico; Yukon +# +# -07/-06 - MST/MDT (North America DST) +XX +394421-1045903 America/Denver Mountain ("MST/MDT") - US & Canada; Mexico near US border +# +# -06 +XX -0054-08936 Pacific/Galapagos Galápagos +# +# -06 - CST +XX +1924-09909 America/Mexico_City Central Standard ("CST") - Saskatchewan; central Mexico; Central America +# +# -06/-05 (Chile DST) +XX -2709-10926 Pacific/Easter Easter Island +# +# -06/-05 - CST/CDT (North America DST) +XX +415100-0873900 America/Chicago Central ("CST/CDT") - US & Canada; Mexico near US border +# +# -05 +XX -1203-07703 America/Lima eastern South America +# +# -05 - EST +XX +175805-0764736 America/Jamaica Eastern Standard ("EST") - Caymans; Jamaica; eastern Mexico; Panama +# +# -05/-04 - CST/CDT (Cuba DST) +XX +2308-08222 America/Havana Cuba +# +# -05/-04 - EST/EDT (North America DST) +XX +404251-0740023 America/New_York Eastern ("EST/EDT") - US & Canada +# +# -04 +XX +1030-06656 America/Caracas western South America +# +# -04 - AST +XX +1828-06954 America/Santo_Domingo Atlantic Standard ("AST") - eastern Caribbean +# +# -04/-03 (Chile DST) +XX -3327-07040 America/Santiago most of Chile +# +# -04/-03 (Paraguay DST) +XX -2516-05740 America/Asuncion Paraguay +# +# -04/-03 - AST/ADT (North America DST) +XX +4439-06336 America/Halifax Atlantic ("AST/ADT") - Canada; Bermuda +# +# -03:30/-02:30 - NST/NDT (North America DST) +XX +4734-05243 America/St_Johns Newfoundland ("NST/NDT") +# +# -03 +XX -2332-04637 America/Sao_Paulo eastern South America +# +# -03/-02 (North America DST) +XX +4703-05620 America/Miquelon St Pierre & Miquelon +# +# -02 +XX -0351-03225 America/Noronha Fernando de Noronha; South Georgia +# +# -02/-01 (EU DST) +XX +6411-05144 America/Nuuk most of Greenland +# +# -01 +XX +1455-02331 Atlantic/Cape_Verde Cape Verde +# +# -01/+00 (EU DST) +XX +3744-02540 Atlantic/Azores Azores +# -01/+00 (EU DST) until 2024-03-31; then -02/-01 (EU DST) +XX +7029-02158 America/Scoresbysund Ittoqqortoormiit +# +# +00 - GMT +XX +0519-00402 Africa/Abidjan far western Africa; Iceland ("GMT") +# +# +00/+01 - GMT/BST (EU DST) +XX +513030-0000731 Europe/London United Kingdom ("GMT/BST") +# +# +00/+01 - WET/WEST (EU DST) +XX +3843-00908 Europe/Lisbon western Europe ("WET/WEST") +# +# +00/+02 - Troll DST +XX -720041+0023206 Antarctica/Troll Troll Station in Antarctica +# +# +01 - CET +XX +3647+00303 Africa/Algiers Algeria, Tunisia ("CET") +# +# +01 - WAT +XX +0627+00324 Africa/Lagos western Africa ("WAT") +# +# +01/+00 - IST/GMT (EU DST in reverse) +XX +5320-00615 Europe/Dublin Ireland ("IST/GMT") +# +# +01/+00 - (Morocco DST) +XX +3339-00735 Africa/Casablanca Morocco +# +# +01/+02 - CET/CEST (EU DST) +XX +4852+00220 Europe/Paris central Europe ("CET/CEST") +# +# +02 - CAT +XX -2558+03235 Africa/Maputo central Africa ("CAT") +# +# +02 - EET +XX +3254+01311 Africa/Tripoli Libya; Kaliningrad ("EET") +# +# +02 - SAST +XX -2615+02800 Africa/Johannesburg southern Africa ("SAST") +# +# +02/+03 - EET/EEST (EU DST) +XX +3758+02343 Europe/Athens eastern Europe ("EET/EEST") +# +# +02/+03 - EET/EEST (Egypt DST) +XX +3003+03115 Africa/Cairo Egypt +# +# +02/+03 - EET/EEST (Lebanon DST) +XX +3353+03530 Asia/Beirut Lebanon +# +# +02/+03 - EET/EEST (Moldova DST) +XX +4700+02850 Europe/Chisinau Moldova +# +# +02/+03 - EET/EEST (Palestine DST) +XX +3130+03428 Asia/Gaza Palestine +# +# +02/+03 - IST/IDT (Israel DST) +XX +314650+0351326 Asia/Jerusalem Israel +# +# +03 +XX +4101+02858 Europe/Istanbul Near East; Belarus +# +# +03 - EAT +XX -0117+03649 Africa/Nairobi eastern Africa ("EAT") +# +# +03 - MSK +XX +554521+0373704 Europe/Moscow Moscow ("MSK") +# +# +03:30 +XX +3540+05126 Asia/Tehran Iran +# +# +04 +XX +2518+05518 Asia/Dubai Russia; Caucasus; Persian Gulf; Seychelles; Réunion +# +# +04:30 +XX +3431+06912 Asia/Kabul Afghanistan +# +# +05 +XX +4120+06918 Asia/Tashkent Russia; west Kazakhstan; Tajikistan; Turkmenistan; Uzbekistan; Maldives +# +# +05 - PKT +XX +2452+06703 Asia/Karachi Pakistan ("PKT") +# +# +05:30 +XX +0656+07951 Asia/Colombo Sri Lanka +# +# +05:30 - IST +XX +2232+08822 Asia/Kolkata India ("IST") +# +# +05:45 +XX +2743+08519 Asia/Kathmandu Nepal +# +# +06 +XX +2343+09025 Asia/Dhaka Russia; Kyrgyzstan; Bhutan; Bangladesh; Chagos +# +06 until 2024-03-01; then +05 +XX +4315+07657 Asia/Almaty Kazakhstan (except western areas) +# +# +06:30 +XX +1647+09610 Asia/Yangon Myanmar; Cocos +# +# +07 +XX +1345+10031 Asia/Bangkok Russia; Indochina; Christmas Island +# +# +07 - WIB +XX -0610+10648 Asia/Jakarta Indonesia ("WIB") +# +# +08 +XX +0117+10351 Asia/Singapore Russia; Brunei; Malaysia; Singapore +# +# +08 - AWST +XX -3157+11551 Australia/Perth Western Australia ("AWST") +# +# +08 - CST +XX +3114+12128 Asia/Shanghai China ("CST") +# +# +08 - HKT +XX +2217+11409 Asia/Hong_Kong Hong Kong ("HKT") +# +# +08 - PHT +XX +1435+12100 Asia/Manila Philippines ("PHT") +# +# +08 - WITA +XX -0507+11924 Asia/Makassar Indonesia ("WITA") +# +# +08:45 +XX -3143+12852 Australia/Eucla Eucla +# +# +09 +XX +5203+11328 Asia/Chita Russia; Palau; East Timor +# +# +09 - JST +XX +353916+1394441 Asia/Tokyo Japan ("JST") +# +# +09 - KST +XX +3733+12658 Asia/Seoul Korea ("KST") +# +# +09 - WIT +XX -0232+14042 Asia/Jayapura Indonesia ("WIT") +# +# +09:30 - ACST +XX -1228+13050 Australia/Darwin Northern Territory ("ACST") +# +# +09:30/+10:30 - ACST/ACDT (Australia DST) +XX -3455+13835 Australia/Adelaide South Australia ("ACST/ACDT") +# +# +10 +XX +4310+13156 Asia/Vladivostok Russia; Yap; Chuuk; Papua New Guinea; Dumont d'Urville +# +# +10 - AEST +XX -2728+15302 Australia/Brisbane Queensland ("AEST") +# +# +10 - ChST +XX +1328+14445 Pacific/Guam Mariana Islands ("ChST") +# +# +10/+11 - AEST/AEDT (Australia DST) +XX -3352+15113 Australia/Sydney southeast Australia ("AEST/AEDT") +# +# +10:30/+11 +XX -3133+15905 Australia/Lord_Howe Lord Howe Island +# +# +11 +XX -0613+15534 Pacific/Bougainville Russia; Kosrae; Bougainville; Solomons +# +# +11/+12 (Australia DST) +XX -2903+16758 Pacific/Norfolk Norfolk Island +# +# +12 +XX +5301+15839 Asia/Kamchatka Russia; Tuvalu; Fiji; etc. +# +# +12/+13 (New Zealand DST) +XX -3652+17446 Pacific/Auckland New Zealand ("NZST/NZDT") +# +# +12:45/+13:45 (Chatham DST) +XX -4357-17633 Pacific/Chatham Chatham Islands +# +# +13 +XX -210800-1751200 Pacific/Tongatapu Kanton; Tokelau; Samoa (western); Tonga +# +# +14 +XX +0152-15720 Pacific/Kiritimati Kiritimati diff --git a/vendor/chrono/CHANGELOG.md b/vendor/chrono/CHANGELOG.md new file mode 100644 index 0000000000000..1e6f6f935e460 --- /dev/null +++ b/vendor/chrono/CHANGELOG.md @@ -0,0 +1,731 @@ +ChangeLog for Chrono +==================== + +This documents notable changes to [Chrono](https://github.com/chronotope/chrono) +up to and including version 0.4.19. For later releases, please review the +release notes on [GitHub](https://github.com/chronotope/chrono/releases). + +## 0.4.19 + +* Correct build on solaris/illumos + +## 0.4.18 + +* Restore support for x86_64-fortanix-unknown-sgx + +## 0.4.17 + +* Fix a name resolution error in wasm-bindgen code introduced by removing the dependency on time + v0.1 + +## 0.4.16 + +### Features + +* Add %Z specifier to the `FromStr`, similar to the glibc strptime + (does not set the offset from the timezone name) + +* Drop the dependency on time v0.1, which is deprecated, unless the `oldtime` + feature is active. This feature is active by default in v0.4.16 for backwards + compatibility, but will likely be removed in v0.5. Code that imports + `time::Duration` should be switched to import `chrono::Duration` instead to + avoid breakage. + +## 0.4.15 + +### Fixes + +* Correct usage of vec in specific feature combinations (@quodlibetor) + +## 0.4.14 **YANKED** + +### Features + +* Add day and week iterators for `NaiveDate` (@gnzlbg & @robyoung) +* Add a `Month` enum (@hhamana) +* Add `locales`. All format functions can now use locales, see the documentation for the + `unstable-locales` feature. +* Fix `Local.from_local_datetime` method for wasm + +### Improvements + +* Added MIN and MAX values for `NaiveTime`, `NaiveDateTime` and `DateTime`. + +## 0.4.13 + +### Features + +* Add `DurationRound` trait that allows rounding and truncating by `Duration` (@robyoung) + +### Internal Improvements + +* Code improvements to impl `From` for `js_sys` in wasm to reuse code (@schrieveslaach) + +## 0.4.12 + +### New Methods and impls + +* `Duration::abs` to ensure that a duration is just a magnitude (#418 @abreis). + +### Compatibility improvements + +* impl `From` for `js_sys` in wasm (#424 @schrieveslaach) +* Bump required version of `time` for redox support. + +### Bugfixes + +* serde modules do a better job with `Option` types (#417 @mwkroening and #429 + @fx-kirin) +* Use js runtime when using wasmbind to get the local offset (#412 + @quodlibetor) + +### Internal Improvements + +* Migrate to github actions from travis-ci, make the overall CI experience more comprehensible, + significantly faster and more correct (#439 @quodlibetor) + +## 0.4.11 + +### Improvements + +* Support a space or `T` in `FromStr` for `DateTime`, meaning that e.g. + `dt.to_string().parse::>()` now correctly works on round-trip. + (@quodlibetor in #378) +* Support "negative UTC" in `parse_from_rfc2822` (@quodlibetor #368 reported in + #102) +* Support comparisons of DateTimes with different timezones (@dlalic in #375) +* Many documentation improvements + +### Bitrot and external integration fixes + +* Don't use wasmbind on wasi (@coolreader18 #365) +* Avoid deprecation warnings for `Error::description` (@AnderEnder and + @quodlibetor #376) + +### Internal improvements + +* Use Criterion for benchmarks (@quodlibetor) + +## 0.4.10 + +### Compatibility notes + +* Putting some functionality behind an `alloc` feature to improve no-std + support (in #341) means that if you were relying on chrono with + `no-default-features` *and* using any of the functions that require alloc + support (i.e. any of the string-generating functions like `to_rfc3339`) you + will need to add the `alloc` feature in your Cargo.toml. + +### Improvements + +* `DateTime::parse_from_str` is more than 2x faster in some cases. (@michalsrb + #358) +* Significant improvements to no-std and alloc support (This should also make + many format/serialization operations induce zero unnecessary allocations) + (@CryZe #341) + +### Features + +* Functions that were accepting `Iterator` of `Item`s (for example + `format_with_items`) now accept `Iterator` of `Borrow`, so one can + use values or references. (@michalsrb #358) +* Add built-in support for structs with nested `Option` etc fields + (@manifest #302) + +### Internal/doc improvements + +* Use markdown footnotes on the `strftime` docs page (@qudlibetor #359) +* Migrate from `try!` -> `?` (question mark) because it is now emitting + deprecation warnings and has been stable since rustc 1.13.0 +* Deny dead code + +## 0.4.9 + +### Fixes + +* Make Datetime arithmatic adjust their offsets after discovering their new + timestamps (@quodlibetor #337) +* Put wasm-bindgen related code and dependencies behind a `wasmbind` feature + gate. (@quodlibetor #335) + +## 0.4.8 + +### Fixes + +* Add '0' to single-digit days in rfc2822 date format (@wyhaya #323) +* Correctly pad DelayedFormat (@SamokhinIlya #320) + +### Features + +* Support `wasm-unknown-unknown` via wasm-bindgen (in addition to + emscripten/`wasm-unknown-emscripten`). (finished by @evq in #331, initial + work by @jjpe #287) + +## 0.4.7 + +### Fixes + +* Disable libc default features so that CI continues to work on rust 1.13 +* Fix panic on negative inputs to timestamp_millis (@cmars #292) +* Make `LocalResult` `Copy/Eq/Hash` + +### Features + +* Add `std::convert::From` conversions between the different timezone formats + (@mqudsi #271) +* Add `timestamp_nanos` methods (@jean-airoldie #308) +* Documentation improvements + +## 0.4.6 + +### Maintenance + +* Doc improvements -- improve README CI verification, external links +* winapi upgrade to 0.3 + +## Unreleased + +### Features + +* Added `NaiveDate::from_weekday_of_month{,_opt}` for getting eg. the 2nd Friday of March 2017. + +## 0.4.5 + +### Features + +* Added several more serde deserialization helpers (@novacrazy #258) +* Enabled all features on the playground (@davidtwco #267) +* Derive `Hash` on `FixedOffset` (@LuoZijun #254) +* Improved docs (@storyfeet #261, @quodlibetor #252) + +## 0.4.4 + +### Features + +* Added support for parsing nanoseconds without the leading dot (@emschwartz #251) + +## 0.4.3 + +### Features + +* Added methods to DateTime/NaiveDateTime to present the stored value as a number + of nanoseconds since the UNIX epoch (@harkonenbade #247) +* Added a serde serialise/deserialise module for nanosecond timestamps. (@harkonenbade #247) +* Added "Permissive" timezone parsing which allows a numeric timezone to + be specified without minutes. (@quodlibetor #242) + +## 0.4.2 + +### Deprecations + +* More strongly deprecate RustcSerialize: remove it from documentation unless + the feature is enabled, issue a deprecation warning if the rustc-serialize + feature is enabled (@quodlibetor #174) + +### Features + +* Move all uses of the system clock behind a `clock` feature, for use in + environments where we don't have access to the current time. (@jethrogb #236) +* Implement subtraction of two `Date`s, `Time`s, or `DateTime`s, returning a + `Duration` (@tobz1000 #237) + +## 0.4.1 + +### Bug Fixes + +* Allow parsing timestamps with subsecond precision (@jonasbb) +* RFC2822 allows times to not include the second (@upsuper) + +### Features + +* New `timestamp_millis` method on `DateTime` and `NaiveDateTim` that returns + number of milliseconds since the epoch. (@quodlibetor) +* Support exact decimal width on subsecond display for RFC3339 via a new + `to_rfc3339_opts` method on `DateTime` (@dekellum) +* Use no_std-compatible num dependencies (@cuviper) +* Add `SubsecRound` trait that allows rounding to the nearest second + (@dekellum) + +### Code Hygiene and Docs + +* Docs! (@alatiera @kosta @quodlibetor @kennytm) +* Run clippy and various fixes (@quodlibetor) + +## 0.4.0 (2017-06-22) + +This was originally planned as a minor release but was pushed to a major +release due to the compatibility concern raised. + +### Added + +- `IsoWeek` has been added for the ISO week without time zone. + +- The `+=` and `-=` operators against `time::Duration` are now supported for + `NaiveDate`, `NaiveTime` and `NaiveDateTime`. (#99) + + (Note that this does not invalidate the eventual deprecation of `time::Duration`.) + +- `SystemTime` and `DateTime` types can be now converted to each other via `From`. + Due to the obvious lack of time zone information in `SystemTime`, + the forward direction is limited to `DateTime` and `DateTime` only. + +### Changed + +- Intermediate implementation modules have been flattened (#161), + and `UTC` has been renamed to `Utc` in accordance with the current convention (#148). + + The full list of changes is as follows: + + Before | After + ---------------------------------------- | ---------------------------- + `chrono::date::Date` | `chrono::Date` + `chrono::date::MIN` | `chrono::MIN_DATE` + `chrono::date::MAX` | `chrono::MAX_DATE` + `chrono::datetime::DateTime` | `chrono::DateTime` + `chrono::naive::time::NaiveTime` | `chrono::naive::NaiveTime` + `chrono::naive::date::NaiveDate` | `chrono::naive::NaiveDate` + `chrono::naive::date::MIN` | `chrono::naive::MIN_DATE` + `chrono::naive::date::MAX` | `chrono::naive::MAX_DATE` + `chrono::naive::datetime::NaiveDateTime` | `chrono::naive::NaiveDateTime` + `chrono::offset::utc::UTC` | `chrono::offset::Utc` + `chrono::offset::fixed::FixedOffset` | `chrono::offset::FixedOffset` + `chrono::offset::local::Local` | `chrono::offset::Local` + `chrono::format::parsed::Parsed` | `chrono::format::Parsed` + + With an exception of `Utc`, this change does not affect any direct usage of + `chrono::*` or `chrono::prelude::*` types. + +- `Datelike::isoweekdate` is replaced by `Datelike::iso_week` which only returns the ISO week. + + The original method used to return a tuple of year number, week number and day of the week, + but this duplicated the `Datelike::weekday` method and it had been hard to deal with + the raw year and week number for the ISO week date. + This change isolates any logic and API for the week date into a separate type. + +- `NaiveDateTime` and `DateTime` can now be deserialized from an integral UNIX timestamp. (#125) + + This turns out to be very common input for web-related usages. + The existing string representation is still supported as well. + +- `chrono::serde` and `chrono::naive::serde` modules have been added + for the serialization utilities. (#125) + + Currently they contain the `ts_seconds` modules that can be used to + serialize `NaiveDateTime` and `DateTime` values into an integral UNIX timestamp. + This can be combined with Serde's `[de]serialize_with` attributes + to fully support the (de)serialization to/from the timestamp. + + For rustc-serialize, there are separate `chrono::TsSeconds` and `chrono::naive::TsSeconds` types + that are newtype wrappers implementing different (de)serialization logics. + This is a suboptimal API, however, and it is strongly recommended to migrate to Serde. + +### Fixed + +- The major version was made to fix the broken Serde dependency issues. (#146, #156, #158, #159) + + The original intention to technically break the dependency was + to facilitate the use of Serde 1.0 at the expense of temporary breakage. + Whether this was appropriate or not is quite debatable, + but it became clear that there are several high-profile crates requiring Serde 0.9 + and it is not feasible to force them to use Serde 1.0 anyway. + + To the end, the new major release was made with some known lower-priority breaking changes. + 0.3.1 is now yanked and any remaining 0.3 users can safely roll back to 0.3.0. + +- Various documentation fixes and goodies. (#92, #131, #136) + +## 0.3.1 (2017-05-02) + +### Added + +- `Weekday` now implements `FromStr`, `Serialize` and `Deserialize`. (#113) + + The syntax is identical to `%A`, i.e. either the shortest or the longest form of English names. + +### Changed + +- Serde 1.0 is now supported. (#142) + + This is technically a breaking change because Serde 0.9 and 1.0 are not compatible, + but this time we decided not to issue a minor version because + we have already seen Serde 0.8 and 0.9 compatibility problems even after 0.3.0 and + a new minor version turned out to be not very helpful for this kind of issues. + +### Fixed + +- Fixed a bug that the leap second can be mapped wrongly in the local time zone. + Only occurs when the local time zone is behind UTC. (#130) + +## 0.3.0 (2017-02-07) + +The project has moved to the [Chronotope](https://github.com/chronotope/) organization. + +### Added + +- `chrono::prelude` module has been added. All other glob imports are now discouraged. + +- `FixedOffset` can be added to or subtracted from any timelike types. + + - `FixedOffset::local_minus_utc` and `FixedOffset::utc_minus_local` methods have been added. + Note that the old `Offset::local_minus_utc` method is gone; see below. + +- Serde support for non-self-describing formats like Bincode is added. (#89) + +- Added `Item::Owned{Literal,Space}` variants for owned formatting items. (#76) + +- Formatting items and the `Parsed` type have been slightly adjusted so that + they can be internally extended without breaking any compatibility. + +- `Weekday` is now `Hash`able. (#109) + +- `ParseError` now implements `Eq` as well as `PartialEq`. (#114) + +- More documentation improvements. (#101, #108, #112) + +### Changed + +- Chrono now only supports Rust 1.13.0 or later (previously: Rust 1.8.0 or later). + +- Serde 0.9 is now supported. + Due to the API difference, support for 0.8 or older is discontinued. (#122) + +- Rustc-serialize implementations are now on par with corresponding Serde implementations. + They both standardize on the `std::fmt::Debug` textual output. + + **This is a silent breaking change (hopefully the last though).** + You should be prepared for the format change if you depended on rustc-serialize. + +- `Offset::local_minus_utc` is now `Offset::fix`, and returns `FixedOffset` instead of a duration. + + This makes every time zone operation operate within a bias less than one day, + and vastly simplifies many logics. + +- `chrono::format::format` now receives `FixedOffset` instead of `time::Duration`. + +- The following methods and implementations have been renamed and older names have been *removed*. + The older names will be reused for the same methods with `std::time::Duration` in the future. + + - `checked_*` → `checked_*_signed` in `Date`, `DateTime`, `NaiveDate` and `NaiveDateTime` types + + - `overflowing_*` → `overflowing_*_signed` in the `NaiveTime` type + + - All subtraction implementations between two time instants have been moved to + `signed_duration_since`, following the naming in `std::time`. + +### Fixed + +- Fixed a panic when the `Local` offset receives a leap second. (#123) + +### Removed + +- Rustc-serialize support for `Date` types and all offset types has been dropped. + + These implementations were automatically derived and never had been in a good shape. + Moreover there are no corresponding Serde implementations, limiting their usefulness. + In the future they may be revived with more complete implementations. + +- The following method aliases deprecated in the 0.2 branch have been removed. + + - `DateTime::num_seconds_from_unix_epoch` (→ `DateTime::timestamp`) + - `NaiveDateTime::from_num_seconds_from_unix_epoch` (→ `NaiveDateTime::from_timestamp`) + - `NaiveDateTime::from_num_seconds_from_unix_epoch_opt` (→ `NaiveDateTime::from_timestamp_opt`) + - `NaiveDateTime::num_seconds_unix_epoch` (→ `NaiveDateTime::timestamp`) + +- Formatting items are no longer `Copy`, except for `chrono::format::Pad`. + +- `chrono::offset::add_with_leapsecond` has been removed. + Use a direct addition with `FixedOffset` instead. + +## 0.2.25 (2016-08-04) + +This is the last version officially supports Rust 1.12.0 or older. + +(0.2.24 was accidentally uploaded without a proper check for warnings in the default state, +and replaced by 0.2.25 very shortly. Duh.) + +### Added + +- Serde 0.8 is now supported. 0.7 also remains supported. (#86) + +### Fixed + +- The deserialization implementation for rustc-serialize now properly verifies the input. + All serialization codes are also now thoroughly tested. (#42) + +## 0.2.23 (2016-08-03) + +### Added + +- The documentation was greatly improved for several types, + and tons of cross-references have been added. (#77, #78, #80, #82) + +- `DateTime::timestamp_subsec_{millis,micros,nanos}` methods have been added. (#81) + +### Fixed + +- When the system time records a leap second, + the nanosecond component was mistakenly reset to zero. (#84) + +- `Local` offset misbehaves in Windows for August and later, + due to the long-standing libtime bug (dates back to mid-2015). + Workaround has been implemented. (#85) + +## 0.2.22 (2016-04-22) + +### Fixed + +- `%.6f` and `%.9f` used to print only three digits when the nanosecond part is zero. (#71) +- The documentation for `%+` has been updated to reflect the current status. (#71) + +## 0.2.21 (2016-03-29) + +### Fixed + +- `Fixed::LongWeekdayName` was unable to recognize `"sunday"` (whoops). (#66) + +## 0.2.20 (2016-03-06) + +### Changed + +- `serde` dependency has been updated to 0.7. (#63, #64) + +## 0.2.19 (2016-02-05) + +### Added + +- The documentation for `Date` is made clear about its ambiguity and guarantees. + +### Fixed + +- `DateTime::date` had been wrong when the local date and the UTC date is in disagreement. (#61) + +## 0.2.18 (2016-01-23) + +### Fixed + +- Chrono no longer pulls a superfluous `rand` dependency. (#57) + +## 0.2.17 (2015-11-22) + +### Added + +- Naive date and time types and `DateTime` now have a `serde` support. + They serialize as an ISO 8601 / RFC 3339 string just like `Debug`. (#51) + +## 0.2.16 (2015-09-06) + +### Added + +- Added `%.3f`, `%.6f` and `%.9f` specifier for formatting fractional seconds + up to 3, 6 or 9 decimal digits. This is a natural extension to the existing `%f`. + Note that this is (not yet) generic, no other value of precision is supported. (#45) + +### Changed + +- Forbade unsized types from implementing `Datelike` and `Timelike`. + This does not make a big harm as any type implementing them should be already sized + to be practical, but this change still can break highly generic codes. (#46) + +### Fixed + +- Fixed a broken link in the `README.md`. (#41) + +## 0.2.15 (2015-07-05) + +### Added + +- Padding modifiers `%_?`, `%-?` and `%0?` are implemented. + They are glibc extensions which seem to be reasonably widespread (e.g. Ruby). + +- Added `%:z` specifier and corresponding formatting items + which is essentially the same as `%z` but with a colon. + +- Added a new specifier `%.f` which precision adapts from the input. + This was added as a response to the UX problems in the original nanosecond specifier `%f`. + +### Fixed + +- `Numeric::Timestamp` specifier (`%s`) was ignoring the time zone offset when provided. + +- Improved the documentation and associated tests for `strftime`. + +## 0.2.14 (2015-05-15) + +### Fixed + +- `NaiveDateTime +/- Duration` or `NaiveTime +/- Duration` could have gone wrong + when the `Duration` to be added is negative and has a fractional second part. + This was caused by an underflow in the conversion from `Duration` to the parts; + the lack of tests for this case allowed a bug. (#37) + +## 0.2.13 (2015-04-29) + +### Added + +- The optional dependency on `rustc_serialize` and + relevant `Rustc{En,De}codable` implementations for supported types has been added. + This is enabled by the `rustc-serialize` Cargo feature. (#34) + +### Changed + +- `chrono::Duration` reexport is changed to that of crates.io `time` crate. + This enables Rust 1.0 beta compatibility. + +## 0.2.4 (2015-03-03) + +### Fixed + +- Clarified the meaning of `Date` and fixed unwanted conversion problem + that only occurs with positive UTC offsets. (#27) + +## 0.2.3 (2015-02-27) + +### Added + +- `DateTime` and `Date` is now `Copy`/`Send` when `Tz::Offset` is `Copy`/`Send`. + The implementations for them were mistakenly omitted. (#25) + +### Fixed + +- `Local::from_utc_datetime` didn't set a correct offset. (#26) + +## 0.2.1 (2015-02-21) + +### Changed + +- `DelayedFormat` no longer conveys a redundant lifetime. + +## 0.2.0 (2015-02-19) + +### Added + +- `Offset` is splitted into `TimeZone` (constructor) and `Offset` (storage) types. + You would normally see only the former, as the latter is mostly an implementation detail. + Most importantly, `Local` now can be used to directly construct timezone-aware values. + + Some types (currently, `UTC` and `FixedOffset`) are both `TimeZone` and `Offset`, + but others aren't (e.g. `Local` is not what is being stored to each `DateTime` values). + +- `LocalResult::map` convenience method has been added. + +- `TimeZone` now allows a construction of `DateTime` values from UNIX timestamp, + via `timestamp` and `timestamp_opt` methods. + +- `TimeZone` now also has a method for parsing `DateTime`, namely `datetime_from_str`. + +- The following methods have been added to all date and time types: + + - `checked_add` + - `checked_sub` + - `format_with_items` + +- The following methods have been added to all timezone-aware types: + + - `timezone` + - `with_timezone` + - `naive_utc` + - `naive_local` + +- `parse_from_str` method has been added to all naive types and `DateTime`. + +- All naive types and instances of `DateTime` with time zones `UTC`, `Local` and `FixedOffset` + implement the `FromStr` trait. They parse what `std::fmt::Debug` would print. + +- `chrono::format` has been greatly rewritten. + + - The formatting syntax parser is modular now, available at `chrono::format::strftime`. + + - The parser and resolution algorithm is also modular, the former is available at + `chrono::format::parse` while the latter is available at `chrono::format::parsed`. + + - Explicit support for RFC 2822 and 3339 syntaxes is landed. + + - There is a minor formatting difference with atypical values, + e.g. for years not between 1 BCE and 9999 CE. + +### Changed + +- Most uses of `Offset` are converted to `TimeZone`. + In fact, *all* user-facing code is expected to be `Offset`-free. + +- `[Naive]DateTime::*num_seconds_from_unix_epoch*` methods have been renamed to + simply `timestamp` or `from_timestamp*`. The original names have been deprecated. + +### Removed + +- `Time` has been removed. This also prompts a related set of methods in `TimeZone`. + + This is in principle possible, but in practice has seen a little use + because it can only be meaningfully constructed via an existing `DateTime` value. + This made many operations to `Time` unintuitive or ambiguous, + so we simply let it go. + + In the case that `Time` is really required, one can use a simpler `NaiveTime`. + `NaiveTime` and `NaiveDate` can be freely combined and splitted, + and `TimeZone::from_{local,utc}_datetime` can be used to convert from/to the local time. + +- `with_offset` method has been removed. Use `with_timezone` method instead. + (This is not deprecated since it is an integral part of offset reform.) + +## 0.1.14 (2015-01-10) + +### Added + +- Added a missing `std::fmt::String` impl for `Local`. + +## 0.1.13 (2015-01-10) + +### Changed + +- Most types now implement both `std::fmt::Show` and `std::fmt::String`, + with the former used for the stricter output and the latter used for more casual output. + +### Removed + +- `Offset::name` has been replaced by a `std::fmt::String` implementation to `Offset`. + +## 0.1.12 (2015-01-08) + +### Removed + +- `Duration + T` no longer works due to the updated impl reachability rules. + Use `T + Duration` as a workaround. + +## 0.1.4 (2014-12-13) + +### Fixed + +- Fixed a bug that `Date::and_*` methods with an offset that can change the date are + off by one day. + +## 0.1.3 (2014-11-28) + +### Added + +- `{Date,Time,DateTime}::with_offset` methods have been added. + +- `LocalResult` now implements a common set of traits. + +- `LocalResult::and_*` methods have been added. + They are useful for safely chaining `LocalResult>` methods + to make `LocalResult>`. + +### Changed + +- `Offset::name` now returns `SendStr`. + +- `{Date,Time} - Duration` overloadings are now allowed. + +## 0.1.2 (2014-11-24) + +### Added + +- `Duration + Date` overloading is now allowed. + +### Changed + +- Chrono no longer needs `num` dependency. + +## 0.1.0 (2014-11-20) + +The initial version that was available to `crates.io`. diff --git a/vendor/chrono/README.md b/vendor/chrono/README.md new file mode 100644 index 0000000000000..0558d88343e49 --- /dev/null +++ b/vendor/chrono/README.md @@ -0,0 +1,83 @@ +[Chrono][docsrs]: Timezone-aware date and time handling +======================================== + +[![Chrono GitHub Actions][gh-image]][gh-checks] +[![Chrono on crates.io][cratesio-image]][cratesio] +[![Chrono on docs.rs][docsrs-image]][docsrs] +[![Chat][discord-image]][discord] +[![codecov.io][codecov-img]][codecov-link] + +[gh-image]: https://github.com/chronotope/chrono/actions/workflows/test.yml/badge.svg?branch=main +[gh-checks]: https://github.com/chronotope/chrono/actions/workflows/test.yml?query=branch%3Amain +[cratesio-image]: https://img.shields.io/crates/v/chrono.svg +[cratesio]: https://crates.io/crates/chrono +[docsrs-image]: https://docs.rs/chrono/badge.svg +[docsrs]: https://docs.rs/chrono +[discord-image]: https://img.shields.io/discord/976380008299917365?logo=discord +[discord]: https://discord.gg/sXpav4PS7M +[codecov-img]: https://img.shields.io/codecov/c/github/chronotope/chrono?logo=codecov +[codecov-link]: https://codecov.io/gh/chronotope/chrono + +Chrono aims to provide all functionality needed to do correct operations on dates and times in the +[proleptic Gregorian calendar](https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar): + +* The [`DateTime`](https://docs.rs/chrono/latest/chrono/struct.DateTime.html) type is timezone-aware + by default, with separate timezone-naive types. +* Operations that may produce an invalid or ambiguous date and time return `Option` or + [`LocalResult`](https://docs.rs/chrono/latest/chrono/offset/enum.LocalResult.html). +* Configurable parsing and formatting with an `strftime` inspired date and time formatting syntax. +* The [`Local`](https://docs.rs/chrono/latest/chrono/offset/struct.Local.html) timezone works with + the current timezone of the OS. +* Types and operations are implemented to be reasonably efficient. + +Timezone data is not shipped with chrono by default to limit binary sizes. Use the companion crate +[Chrono-TZ](https://crates.io/crates/chrono-tz) or [`tzfile`](https://crates.io/crates/tzfile) for +full timezone support. + +## Documentation + +See [docs.rs](https://docs.rs/chrono/latest/chrono/) for the API reference. + +## Limitations + +* Only the proleptic Gregorian calendar (i.e. extended to support older dates) is supported. +* Date types are limited to about +/- 262,000 years from the common epoch. +* Time types are limited to nanosecond accuracy. +* Leap seconds can be represented, but Chrono does not fully support them. + See [Leap Second Handling](https://docs.rs/chrono/latest/chrono/naive/struct.NaiveTime.html#leap-second-handling). + +## Crate features + +Default features: + +* `alloc`: Enable features that depend on allocation (primarily string formatting) +* `std`: Enables functionality that depends on the standard library. This is a superset of `alloc` + and adds interoperation with standard library types and traits. +* `clock`: Enables reading the local timezone (`Local`). This is a superset of `now`. +* `now`: Enables reading the system time (`now`) +* `wasmbind`: Interface with the JS Date API for the `wasm32` target. + +Optional features: + +* `serde`: Enable serialization/deserialization via serde. +* `rkyv`: Enable serialization/deserialization via rkyv. +* `rustc-serialize`: Enable serialization/deserialization via rustc-serialize (deprecated). +* `arbitrary`: construct arbitrary instances of a type with the Arbitrary crate. +* `unstable-locales`: Enable localization. This adds various methods with a `_localized` suffix. + The implementation and API may change or even be removed in a patch release. Feedback welcome. + +## Rust version requirements + +The Minimum Supported Rust Version (MSRV) is currently **Rust 1.61.0**. + +The MSRV is explicitly tested in CI. It may be bumped in minor releases, but this is not done +lightly. + +## License + +This project is licensed under either of + +* [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) +* [MIT License](https://opensource.org/licenses/MIT) + +at your option. diff --git a/vendor/chrono/appveyor.yml b/vendor/chrono/appveyor.yml new file mode 100644 index 0000000000000..6057e851e2411 --- /dev/null +++ b/vendor/chrono/appveyor.yml @@ -0,0 +1,12 @@ +# TODO: delete this without breaking all PRs +environment: + matrix: + - TARGET: nightly-i686-pc-windows-gnu +matrix: + allow_failures: + - channel: nightly + +build: false + +test_script: + - echo "stub" diff --git a/vendor/chrono/deny.toml b/vendor/chrono/deny.toml new file mode 100644 index 0000000000000..186290e039fdb --- /dev/null +++ b/vendor/chrono/deny.toml @@ -0,0 +1,11 @@ +[licenses] +allow-osi-fsf-free = "either" +copyleft = "deny" + +[advisories] +ignore = [ + "RUSTSEC-2022-0004", # rustc_serialize, cannot remove due to compatibility +] +unmaintained = "deny" +unsound = "deny" +yanked = "deny" diff --git a/vendor/chrono/rustfmt.toml b/vendor/chrono/rustfmt.toml new file mode 100644 index 0000000000000..2a35f0230c690 --- /dev/null +++ b/vendor/chrono/rustfmt.toml @@ -0,0 +1 @@ +use_small_heuristics = "Max" diff --git a/vendor/chrono/src/datetime/rustc_serialize.rs b/vendor/chrono/src/datetime/rustc_serialize.rs new file mode 100644 index 0000000000000..f704b2f97b39d --- /dev/null +++ b/vendor/chrono/src/datetime/rustc_serialize.rs @@ -0,0 +1,124 @@ +use super::DateTime; +use crate::format::SecondsFormat; +#[cfg(feature = "clock")] +use crate::offset::Local; +use crate::offset::{FixedOffset, LocalResult, TimeZone, Utc}; +use core::fmt; +use core::ops::Deref; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; + +impl Encodable for DateTime { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + self.to_rfc3339_opts(SecondsFormat::AutoSi, true).encode(s) + } +} + +// lik? function to convert a LocalResult into a serde-ish Result +fn from(me: LocalResult, d: &mut D) -> Result +where + D: Decoder, + T: fmt::Display, +{ + match me { + LocalResult::None => Err(d.error("value is not a legal timestamp")), + LocalResult::Ambiguous(..) => Err(d.error("value is an ambiguous timestamp")), + LocalResult::Single(val) => Ok(val), + } +} + +impl Decodable for DateTime { + fn decode(d: &mut D) -> Result, D::Error> { + d.read_str()?.parse::>().map_err(|_| d.error("invalid date and time")) + } +} + +#[allow(deprecated)] +impl Decodable for TsSeconds { + #[allow(deprecated)] + fn decode(d: &mut D) -> Result, D::Error> { + from(FixedOffset::east_opt(0).unwrap().timestamp_opt(d.read_i64()?, 0), d).map(TsSeconds) + } +} + +impl Decodable for DateTime { + fn decode(d: &mut D) -> Result, D::Error> { + d.read_str()? + .parse::>() + .map(|dt| dt.with_timezone(&Utc)) + .map_err(|_| d.error("invalid date and time")) + } +} + +/// A [`DateTime`] that can be deserialized from a timestamp +/// +/// A timestamp here is seconds since the epoch +#[derive(Debug)] +pub struct TsSeconds(DateTime); + +#[allow(deprecated)] +impl From> for DateTime { + /// Pull the inner `DateTime` out + #[allow(deprecated)] + fn from(obj: TsSeconds) -> DateTime { + obj.0 + } +} + +#[allow(deprecated)] +impl Deref for TsSeconds { + type Target = DateTime; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[allow(deprecated)] +impl Decodable for TsSeconds { + fn decode(d: &mut D) -> Result, D::Error> { + from(Utc.timestamp_opt(d.read_i64()?, 0), d).map(TsSeconds) + } +} + +#[cfg(feature = "clock")] +impl Decodable for DateTime { + fn decode(d: &mut D) -> Result, D::Error> { + match d.read_str()?.parse::>() { + Ok(dt) => Ok(dt.with_timezone(&Local)), + Err(_) => Err(d.error("invalid date and time")), + } + } +} + +#[cfg(feature = "clock")] +#[allow(deprecated)] +impl Decodable for TsSeconds { + #[allow(deprecated)] + fn decode(d: &mut D) -> Result, D::Error> { + from(Utc.timestamp_opt(d.read_i64()?, 0), d).map(|dt| TsSeconds(dt.with_timezone(&Local))) + } +} + +#[cfg(test)] +mod tests { + use crate::datetime::test_encodable_json; + use crate::datetime::{test_decodable_json, test_decodable_json_timestamps}; + use rustc_serialize::json; + + #[test] + fn test_encodable() { + test_encodable_json(json::encode, json::encode); + } + + #[cfg(feature = "clock")] + #[test] + fn test_decodable() { + test_decodable_json(json::decode, json::decode, json::decode); + } + + #[cfg(feature = "clock")] + #[test] + fn test_decodable_timestamps() { + test_decodable_json_timestamps(json::decode, json::decode, json::decode); + } +} diff --git a/vendor/chrono/src/naive/date.rs b/vendor/chrono/src/naive/date.rs new file mode 100644 index 0000000000000..190a6bac6072c --- /dev/null +++ b/vendor/chrono/src/naive/date.rs @@ -0,0 +1,3357 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! ISO 8601 calendar date without timezone. + +#[cfg(feature = "alloc")] +use core::borrow::Borrow; +use core::iter::FusedIterator; +use core::ops::{Add, AddAssign, RangeInclusive, Sub, SubAssign}; +use core::{fmt, str}; + +#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))] +use rkyv::{Archive, Deserialize, Serialize}; + +/// L10n locales. +#[cfg(all(feature = "unstable-locales", feature = "alloc"))] +use pure_rust_locales::Locale; + +#[cfg(feature = "alloc")] +use crate::format::DelayedFormat; +use crate::format::{ + parse, parse_and_remainder, write_hundreds, Item, Numeric, Pad, ParseError, ParseResult, + Parsed, StrftimeItems, +}; +use crate::month::Months; +use crate::naive::{IsoWeek, NaiveDateTime, NaiveTime}; +use crate::{expect, try_opt}; +use crate::{Datelike, TimeDelta, Weekday}; + +use super::internals::{self, DateImpl, Mdf, Of, YearFlags}; +use super::isoweek; + +const MAX_YEAR: i32 = internals::MAX_YEAR; +const MIN_YEAR: i32 = internals::MIN_YEAR; + +/// A week represented by a [`NaiveDate`] and a [`Weekday`] which is the first +/// day of the week. +#[derive(Debug)] +pub struct NaiveWeek { + date: NaiveDate, + start: Weekday, +} + +impl NaiveWeek { + /// Returns a date representing the first day of the week. + /// + /// # Panics + /// + /// Panics if the first day of the week happens to fall just out of range of `NaiveDate` + /// (more than ca. 262,000 years away from common era). + /// + /// # Examples + /// + /// ``` + /// use chrono::{NaiveDate, Weekday}; + /// + /// let date = NaiveDate::from_ymd_opt(2022, 4, 18).unwrap(); + /// let week = date.week(Weekday::Mon); + /// assert!(week.first_day() <= date); + /// ``` + #[inline] + #[must_use] + pub const fn first_day(&self) -> NaiveDate { + let start = self.start.num_days_from_monday() as i32; + let ref_day = self.date.weekday().num_days_from_monday() as i32; + // Calculate the number of days to subtract from `self.date`. + // Do not construct an intermediate date beyond `self.date`, because that may be out of + // range if `date` is close to `NaiveDate::MAX`. + let days = start - ref_day - if start > ref_day { 7 } else { 0 }; + expect!(self.date.add_days(days), "first weekday out of range for `NaiveDate`") + } + + /// Returns a date representing the last day of the week. + /// + /// # Panics + /// + /// Panics if the last day of the week happens to fall just out of range of `NaiveDate` + /// (more than ca. 262,000 years away from common era). + /// + /// # Examples + /// + /// ``` + /// use chrono::{NaiveDate, Weekday}; + /// + /// let date = NaiveDate::from_ymd_opt(2022, 4, 18).unwrap(); + /// let week = date.week(Weekday::Mon); + /// assert!(week.last_day() >= date); + /// ``` + #[inline] + #[must_use] + pub const fn last_day(&self) -> NaiveDate { + let end = self.start.pred().num_days_from_monday() as i32; + let ref_day = self.date.weekday().num_days_from_monday() as i32; + // Calculate the number of days to add to `self.date`. + // Do not construct an intermediate date before `self.date` (like with `first_day()`), + // because that may be out of range if `date` is close to `NaiveDate::MIN`. + let days = end - ref_day + if end < ref_day { 7 } else { 0 }; + expect!(self.date.add_days(days), "last weekday out of range for `NaiveDate`") + } + + /// Returns a [`RangeInclusive`] representing the whole week bounded by + /// [first_day](NaiveWeek::first_day) and [last_day](NaiveWeek::last_day) functions. + /// + /// # Panics + /// + /// Panics if the either the first or last day of the week happens to fall just out of range of + /// `NaiveDate` (more than ca. 262,000 years away from common era). + /// + /// # Examples + /// + /// ``` + /// use chrono::{NaiveDate, Weekday}; + /// + /// let date = NaiveDate::from_ymd_opt(2022, 4, 18).unwrap(); + /// let week = date.week(Weekday::Mon); + /// let days = week.days(); + /// assert!(days.contains(&date)); + /// ``` + #[inline] + #[must_use] + pub const fn days(&self) -> RangeInclusive { + self.first_day()..=self.last_day() + } +} + +/// A duration in calendar days. +/// +/// This is useful because when using `TimeDelta` it is possible that adding `TimeDelta::days(1)` +/// doesn't increment the day value as expected due to it being a fixed number of seconds. This +/// difference applies only when dealing with `DateTime` data types and in other cases +/// `TimeDelta::days(n)` and `Days::new(n)` are equivalent. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +pub struct Days(pub(crate) u64); + +impl Days { + /// Construct a new `Days` from a number of days + pub const fn new(num: u64) -> Self { + Self(num) + } +} + +/// ISO 8601 calendar date without timezone. +/// Allows for every [proleptic Gregorian date] from Jan 1, 262145 BCE to Dec 31, 262143 CE. +/// Also supports the conversion from ISO 8601 ordinal and week date. +/// +/// # Calendar Date +/// +/// The ISO 8601 **calendar date** follows the proleptic Gregorian calendar. +/// It is like a normal civil calendar but note some slight differences: +/// +/// * Dates before the Gregorian calendar's inception in 1582 are defined via the extrapolation. +/// Be careful, as historical dates are often noted in the Julian calendar and others +/// and the transition to Gregorian may differ across countries (as late as early 20C). +/// +/// (Some example: Both Shakespeare from Britain and Cervantes from Spain seemingly died +/// on the same calendar date---April 23, 1616---but in the different calendar. +/// Britain used the Julian calendar at that time, so Shakespeare's death is later.) +/// +/// * ISO 8601 calendars has the year 0, which is 1 BCE (a year before 1 CE). +/// If you need a typical BCE/BC and CE/AD notation for year numbers, +/// use the [`Datelike::year_ce`] method. +/// +/// # Week Date +/// +/// The ISO 8601 **week date** is a triple of year number, week number +/// and [day of the week](Weekday) with the following rules: +/// +/// * A week consists of Monday through Sunday, and is always numbered within some year. +/// The week number ranges from 1 to 52 or 53 depending on the year. +/// +/// * The week 1 of given year is defined as the first week containing January 4 of that year, +/// or equivalently, the first week containing four or more days in that year. +/// +/// * The year number in the week date may *not* correspond to the actual Gregorian year. +/// For example, January 3, 2016 (Sunday) was on the last (53rd) week of 2015. +/// +/// Chrono's date types default to the ISO 8601 [calendar date](#calendar-date), but +/// [`Datelike::iso_week`] and [`Datelike::weekday`] methods can be used to get the corresponding +/// week date. +/// +/// # Ordinal Date +/// +/// The ISO 8601 **ordinal date** is a pair of year number and day of the year ("ordinal"). +/// The ordinal number ranges from 1 to 365 or 366 depending on the year. +/// The year number is the same as that of the [calendar date](#calendar-date). +/// +/// This is currently the internal format of Chrono's date types. +/// +/// [proleptic Gregorian date]: crate::NaiveDate#calendar-date +#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)] +#[cfg_attr( + any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"), + derive(Archive, Deserialize, Serialize), + archive(compare(PartialEq, PartialOrd)), + archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)) +)] +#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))] +pub struct NaiveDate { + ymdf: DateImpl, // (year << 13) | of +} + +/// The minimum possible `NaiveDate` (January 1, 262145 BCE). +#[deprecated(since = "0.4.20", note = "Use NaiveDate::MIN instead")] +pub const MIN_DATE: NaiveDate = NaiveDate::MIN; +/// The maximum possible `NaiveDate` (December 31, 262143 CE). +#[deprecated(since = "0.4.20", note = "Use NaiveDate::MAX instead")] +pub const MAX_DATE: NaiveDate = NaiveDate::MAX; + +#[cfg(all(feature = "arbitrary", feature = "std"))] +impl arbitrary::Arbitrary<'_> for NaiveDate { + fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result { + let year = u.int_in_range(MIN_YEAR..=MAX_YEAR)?; + let max_days = YearFlags::from_year(year).ndays(); + let ord = u.int_in_range(1..=max_days)?; + NaiveDate::from_yo_opt(year, ord).ok_or(arbitrary::Error::IncorrectFormat) + } +} + +impl NaiveDate { + pub(crate) fn weeks_from(&self, day: Weekday) -> i32 { + (self.ordinal() as i32 - self.weekday().num_days_from(day) as i32 + 6) / 7 + } + + /// Makes a new `NaiveDate` from year, ordinal and flags. + /// Does not check whether the flags are correct for the provided year. + const fn from_ordinal_and_flags( + year: i32, + ordinal: u32, + flags: YearFlags, + ) -> Option { + if year < MIN_YEAR || year > MAX_YEAR { + return None; // Out-of-range + } + debug_assert!(YearFlags::from_year(year).0 == flags.0); + match Of::new(ordinal, flags) { + Some(of) => Some(NaiveDate { ymdf: (year << 13) | (of.inner() as DateImpl) }), + None => None, // Invalid: Ordinal outside of the nr of days in a year with those flags. + } + } + + /// Makes a new `NaiveDate` from year and packed month-day-flags. + /// Does not check whether the flags are correct for the provided year. + const fn from_mdf(year: i32, mdf: Mdf) -> Option { + if year < MIN_YEAR || year > MAX_YEAR { + return None; // Out-of-range + } + match mdf.to_of() { + Some(of) => Some(NaiveDate { ymdf: (year << 13) | (of.inner() as DateImpl) }), + None => None, // Non-existing date + } + } + + /// Makes a new `NaiveDate` from the [calendar date](#calendar-date) + /// (year, month and day). + /// + /// # Panics + /// + /// Panics if the specified calendar day does not exist, on invalid values for `month` or `day`, + /// or if `year` is out of range for `NaiveDate`. + #[deprecated(since = "0.4.23", note = "use `from_ymd_opt()` instead")] + #[must_use] + pub const fn from_ymd(year: i32, month: u32, day: u32) -> NaiveDate { + expect!(NaiveDate::from_ymd_opt(year, month, day), "invalid or out-of-range date") + } + + /// Makes a new `NaiveDate` from the [calendar date](#calendar-date) + /// (year, month and day). + /// + /// # Errors + /// + /// Returns `None` if: + /// - The specified calendar day does not exist (for example 2023-04-31). + /// - The value for `month` or `day` is invalid. + /// - `year` is out of range for `NaiveDate`. + /// + /// # Example + /// + /// ``` + /// use chrono::NaiveDate; + /// + /// let from_ymd_opt = NaiveDate::from_ymd_opt; + /// + /// assert!(from_ymd_opt(2015, 3, 14).is_some()); + /// assert!(from_ymd_opt(2015, 0, 14).is_none()); + /// assert!(from_ymd_opt(2015, 2, 29).is_none()); + /// assert!(from_ymd_opt(-4, 2, 29).is_some()); // 5 BCE is a leap year + /// assert!(from_ymd_opt(400000, 1, 1).is_none()); + /// assert!(from_ymd_opt(-400000, 1, 1).is_none()); + /// ``` + #[must_use] + pub const fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option { + let flags = YearFlags::from_year(year); + + if let Some(mdf) = Mdf::new(month, day, flags) { + NaiveDate::from_mdf(year, mdf) + } else { + None + } + } + + /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date) + /// (year and day of the year). + /// + /// # Panics + /// + /// Panics if the specified ordinal day does not exist, on invalid values for `ordinal`, or if + /// `year` is out of range for `NaiveDate`. + #[deprecated(since = "0.4.23", note = "use `from_yo_opt()` instead")] + #[must_use] + pub const fn from_yo(year: i32, ordinal: u32) -> NaiveDate { + expect!(NaiveDate::from_yo_opt(year, ordinal), "invalid or out-of-range date") + } + + /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date) + /// (year and day of the year). + /// + /// # Errors + /// + /// Returns `None` if: + /// - The specified ordinal day does not exist (for example 2023-366). + /// - The value for `ordinal` is invalid (for example: `0`, `400`). + /// - `year` is out of range for `NaiveDate`. + /// + /// # Example + /// + /// ``` + /// use chrono::NaiveDate; + /// + /// let from_yo_opt = NaiveDate::from_yo_opt; + /// + /// assert!(from_yo_opt(2015, 100).is_some()); + /// assert!(from_yo_opt(2015, 0).is_none()); + /// assert!(from_yo_opt(2015, 365).is_some()); + /// assert!(from_yo_opt(2015, 366).is_none()); + /// assert!(from_yo_opt(-4, 366).is_some()); // 5 BCE is a leap year + /// assert!(from_yo_opt(400000, 1).is_none()); + /// assert!(from_yo_opt(-400000, 1).is_none()); + /// ``` + #[must_use] + pub const fn from_yo_opt(year: i32, ordinal: u32) -> Option { + let flags = YearFlags::from_year(year); + NaiveDate::from_ordinal_and_flags(year, ordinal, flags) + } + + /// Makes a new `NaiveDate` from the [ISO week date](#week-date) + /// (year, week number and day of the week). + /// The resulting `NaiveDate` may have a different year from the input year. + /// + /// # Panics + /// + /// Panics if the specified week does not exist in that year, on invalid values for `week`, or + /// if the resulting date is out of range for `NaiveDate`. + #[deprecated(since = "0.4.23", note = "use `from_isoywd_opt()` instead")] + #[must_use] + pub const fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> NaiveDate { + expect!(NaiveDate::from_isoywd_opt(year, week, weekday), "invalid or out-of-range date") + } + + /// Makes a new `NaiveDate` from the [ISO week date](#week-date) + /// (year, week number and day of the week). + /// The resulting `NaiveDate` may have a different year from the input year. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The specified week does not exist in that year (for example 2023 week 53). + /// - The value for `week` is invalid (for example: `0`, `60`). + /// - If the resulting date is out of range for `NaiveDate`. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Weekday}; + /// + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); + /// let from_isoywd_opt = NaiveDate::from_isoywd_opt; + /// + /// assert_eq!(from_isoywd_opt(2015, 0, Weekday::Sun), None); + /// assert_eq!(from_isoywd_opt(2015, 10, Weekday::Sun), Some(from_ymd(2015, 3, 8))); + /// assert_eq!(from_isoywd_opt(2015, 30, Weekday::Mon), Some(from_ymd(2015, 7, 20))); + /// assert_eq!(from_isoywd_opt(2015, 60, Weekday::Mon), None); + /// + /// assert_eq!(from_isoywd_opt(400000, 10, Weekday::Fri), None); + /// assert_eq!(from_isoywd_opt(-400000, 10, Weekday::Sat), None); + /// ``` + /// + /// The year number of ISO week date may differ from that of the calendar date. + /// + /// ``` + /// # use chrono::{NaiveDate, Weekday}; + /// # let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); + /// # let from_isoywd_opt = NaiveDate::from_isoywd_opt; + /// // Mo Tu We Th Fr Sa Su + /// // 2014-W52 22 23 24 25 26 27 28 has 4+ days of new year, + /// // 2015-W01 29 30 31 1 2 3 4 <- so this is the first week + /// assert_eq!(from_isoywd_opt(2014, 52, Weekday::Sun), Some(from_ymd(2014, 12, 28))); + /// assert_eq!(from_isoywd_opt(2014, 53, Weekday::Mon), None); + /// assert_eq!(from_isoywd_opt(2015, 1, Weekday::Mon), Some(from_ymd(2014, 12, 29))); + /// + /// // 2015-W52 21 22 23 24 25 26 27 has 4+ days of old year, + /// // 2015-W53 28 29 30 31 1 2 3 <- so this is the last week + /// // 2016-W01 4 5 6 7 8 9 10 + /// assert_eq!(from_isoywd_opt(2015, 52, Weekday::Sun), Some(from_ymd(2015, 12, 27))); + /// assert_eq!(from_isoywd_opt(2015, 53, Weekday::Sun), Some(from_ymd(2016, 1, 3))); + /// assert_eq!(from_isoywd_opt(2015, 54, Weekday::Mon), None); + /// assert_eq!(from_isoywd_opt(2016, 1, Weekday::Mon), Some(from_ymd(2016, 1, 4))); + /// ``` + #[must_use] + pub const fn from_isoywd_opt(year: i32, week: u32, weekday: Weekday) -> Option { + let flags = YearFlags::from_year(year); + let nweeks = flags.nisoweeks(); + if 1 <= week && week <= nweeks { + // ordinal = week ordinal - delta + let weekord = week * 7 + weekday as u32; + let delta = flags.isoweek_delta(); + if weekord <= delta { + // ordinal < 1, previous year + let prevflags = YearFlags::from_year(year - 1); + NaiveDate::from_ordinal_and_flags( + year - 1, + weekord + prevflags.ndays() - delta, + prevflags, + ) + } else { + let ordinal = weekord - delta; + let ndays = flags.ndays(); + if ordinal <= ndays { + // this year + NaiveDate::from_ordinal_and_flags(year, ordinal, flags) + } else { + // ordinal > ndays, next year + let nextflags = YearFlags::from_year(year + 1); + NaiveDate::from_ordinal_and_flags(year + 1, ordinal - ndays, nextflags) + } + } + } else { + None + } + } + + /// Makes a new `NaiveDate` from a day's number in the proleptic Gregorian calendar, with + /// January 1, 1 being day 1. + /// + /// # Panics + /// + /// Panics if the date is out of range. + #[deprecated(since = "0.4.23", note = "use `from_num_days_from_ce_opt()` instead")] + #[inline] + #[must_use] + pub const fn from_num_days_from_ce(days: i32) -> NaiveDate { + expect!(NaiveDate::from_num_days_from_ce_opt(days), "out-of-range date") + } + + /// Makes a new `NaiveDate` from a day's number in the proleptic Gregorian calendar, with + /// January 1, 1 being day 1. + /// + /// # Errors + /// + /// Returns `None` if the date is out of range. + /// + /// # Example + /// + /// ``` + /// use chrono::NaiveDate; + /// + /// let from_ndays_opt = NaiveDate::from_num_days_from_ce_opt; + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); + /// + /// assert_eq!(from_ndays_opt(730_000), Some(from_ymd(1999, 9, 3))); + /// assert_eq!(from_ndays_opt(1), Some(from_ymd(1, 1, 1))); + /// assert_eq!(from_ndays_opt(0), Some(from_ymd(0, 12, 31))); + /// assert_eq!(from_ndays_opt(-1), Some(from_ymd(0, 12, 30))); + /// assert_eq!(from_ndays_opt(100_000_000), None); + /// assert_eq!(from_ndays_opt(-100_000_000), None); + /// ``` + #[must_use] + pub const fn from_num_days_from_ce_opt(days: i32) -> Option { + let days = try_opt!(days.checked_add(365)); // make December 31, 1 BCE equal to day 0 + let year_div_400 = days.div_euclid(146_097); + let cycle = days.rem_euclid(146_097); + let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); + let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); + NaiveDate::from_ordinal_and_flags(year_div_400 * 400 + year_mod_400 as i32, ordinal, flags) + } + + /// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week + /// since the beginning of the given month. For instance, if you want the 2nd Friday of March + /// 2017, you would use `NaiveDate::from_weekday_of_month(2017, 3, Weekday::Fri, 2)`. + /// + /// `n` is 1-indexed. + /// + /// # Panics + /// + /// Panics if the specified day does not exist in that month, on invalid values for `month` or + /// `n`, or if `year` is out of range for `NaiveDate`. + #[deprecated(since = "0.4.23", note = "use `from_weekday_of_month_opt()` instead")] + #[must_use] + pub const fn from_weekday_of_month( + year: i32, + month: u32, + weekday: Weekday, + n: u8, + ) -> NaiveDate { + expect!(NaiveDate::from_weekday_of_month_opt(year, month, weekday, n), "out-of-range date") + } + + /// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week + /// since the beginning of the given month. For instance, if you want the 2nd Friday of March + /// 2017, you would use `NaiveDate::from_weekday_of_month(2017, 3, Weekday::Fri, 2)`. + /// + /// `n` is 1-indexed. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The specified day does not exist in that month (for example the 5th Monday of Apr. 2023). + /// - The value for `month` or `n` is invalid. + /// - `year` is out of range for `NaiveDate`. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Weekday}; + /// assert_eq!(NaiveDate::from_weekday_of_month_opt(2017, 3, Weekday::Fri, 2), + /// NaiveDate::from_ymd_opt(2017, 3, 10)) + /// ``` + #[must_use] + pub const fn from_weekday_of_month_opt( + year: i32, + month: u32, + weekday: Weekday, + n: u8, + ) -> Option { + if n == 0 { + return None; + } + let first = try_opt!(NaiveDate::from_ymd_opt(year, month, 1)).weekday(); + let first_to_dow = (7 + weekday.number_from_monday() - first.number_from_monday()) % 7; + let day = (n - 1) as u32 * 7 + first_to_dow + 1; + NaiveDate::from_ymd_opt(year, month, day) + } + + /// Parses a string with the specified format string and returns a new `NaiveDate`. + /// See the [`format::strftime` module](crate::format::strftime) + /// on the supported escape sequences. + /// + /// # Example + /// + /// ``` + /// use chrono::NaiveDate; + /// + /// let parse_from_str = NaiveDate::parse_from_str; + /// + /// assert_eq!(parse_from_str("2015-09-05", "%Y-%m-%d"), + /// Ok(NaiveDate::from_ymd_opt(2015, 9, 5).unwrap())); + /// assert_eq!(parse_from_str("5sep2015", "%d%b%Y"), + /// Ok(NaiveDate::from_ymd_opt(2015, 9, 5).unwrap())); + /// ``` + /// + /// Time and offset is ignored for the purpose of parsing. + /// + /// ``` + /// # use chrono::NaiveDate; + /// # let parse_from_str = NaiveDate::parse_from_str; + /// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), + /// Ok(NaiveDate::from_ymd_opt(2014, 5, 17).unwrap())); + /// ``` + /// + /// Out-of-bound dates or insufficient fields are errors. + /// + /// ``` + /// # use chrono::NaiveDate; + /// # let parse_from_str = NaiveDate::parse_from_str; + /// assert!(parse_from_str("2015/9", "%Y/%m").is_err()); + /// assert!(parse_from_str("2015/9/31", "%Y/%m/%d").is_err()); + /// ``` + /// + /// All parsed fields should be consistent to each other, otherwise it's an error. + /// + /// ``` + /// # use chrono::NaiveDate; + /// # let parse_from_str = NaiveDate::parse_from_str; + /// assert!(parse_from_str("Sat, 09 Aug 2013", "%a, %d %b %Y").is_err()); + /// ``` + pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult { + let mut parsed = Parsed::new(); + parse(&mut parsed, s, StrftimeItems::new(fmt))?; + parsed.to_naive_date() + } + + /// Parses a string from a user-specified format into a new `NaiveDate` value, and a slice with + /// the remaining portion of the string. + /// See the [`format::strftime` module](crate::format::strftime) + /// on the supported escape sequences. + /// + /// Similar to [`parse_from_str`](#method.parse_from_str). + /// + /// # Example + /// + /// ```rust + /// # use chrono::{NaiveDate}; + /// let (date, remainder) = NaiveDate::parse_and_remainder( + /// "2015-02-18 trailing text", "%Y-%m-%d").unwrap(); + /// assert_eq!(date, NaiveDate::from_ymd_opt(2015, 2, 18).unwrap()); + /// assert_eq!(remainder, " trailing text"); + /// ``` + pub fn parse_and_remainder<'a>(s: &'a str, fmt: &str) -> ParseResult<(NaiveDate, &'a str)> { + let mut parsed = Parsed::new(); + let remainder = parse_and_remainder(&mut parsed, s, StrftimeItems::new(fmt))?; + parsed.to_naive_date().map(|d| (d, remainder)) + } + + /// Add a duration in [`Months`] to the date + /// + /// Uses the last day of the month if the day does not exist in the resulting month. + /// + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. + /// + /// # Example + /// + /// ``` + /// # use chrono::{NaiveDate, Months}; + /// assert_eq!( + /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_add_months(Months::new(6)), + /// Some(NaiveDate::from_ymd_opt(2022, 8, 20).unwrap()) + /// ); + /// assert_eq!( + /// NaiveDate::from_ymd_opt(2022, 7, 31).unwrap().checked_add_months(Months::new(2)), + /// Some(NaiveDate::from_ymd_opt(2022, 9, 30).unwrap()) + /// ); + /// ``` + #[must_use] + pub const fn checked_add_months(self, months: Months) -> Option { + if months.0 == 0 { + return Some(self); + } + + match months.0 <= core::i32::MAX as u32 { + true => self.diff_months(months.0 as i32), + false => None, + } + } + + /// Subtract a duration in [`Months`] from the date + /// + /// Uses the last day of the month if the day does not exist in the resulting month. + /// + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. + /// + /// # Example + /// + /// ``` + /// # use chrono::{NaiveDate, Months}; + /// assert_eq!( + /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_sub_months(Months::new(6)), + /// Some(NaiveDate::from_ymd_opt(2021, 8, 20).unwrap()) + /// ); + /// + /// assert_eq!( + /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap() + /// .checked_sub_months(Months::new(core::i32::MAX as u32 + 1)), + /// None + /// ); + /// ``` + #[must_use] + pub const fn checked_sub_months(self, months: Months) -> Option { + if months.0 == 0 { + return Some(self); + } + + // Copy `i32::MAX` here so we don't have to do a complicated cast + match months.0 <= 2_147_483_647 { + true => self.diff_months(-(months.0 as i32)), + false => None, + } + } + + const fn diff_months(self, months: i32) -> Option { + let (years, left) = ((months / 12), (months % 12)); + + // Determine new year (without taking months into account for now + + let year = if (years > 0 && years > (MAX_YEAR - self.year())) + || (years < 0 && years < (MIN_YEAR - self.year())) + { + return None; + } else { + self.year() + years + }; + + // Determine new month + + let month = self.month() as i32 + left; + let (year, month) = if month <= 0 { + if year == MIN_YEAR { + return None; + } + + (year - 1, month + 12) + } else if month > 12 { + if year == MAX_YEAR { + return None; + } + + (year + 1, month - 12) + } else { + (year, month) + }; + + // Clamp original day in case new month is shorter + + let flags = YearFlags::from_year(year); + let feb_days = if flags.ndays() == 366 { 29 } else { 28 }; + let days = [31, feb_days, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + let day_max = days[(month - 1) as usize]; + let mut day = self.day(); + if day > day_max { + day = day_max; + }; + + NaiveDate::from_mdf(year, try_opt!(Mdf::new(month as u32, day, flags))) + } + + /// Add a duration in [`Days`] to the date + /// + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. + /// + /// # Example + /// + /// ``` + /// # use chrono::{NaiveDate, Days}; + /// assert_eq!( + /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_add_days(Days::new(9)), + /// Some(NaiveDate::from_ymd_opt(2022, 3, 1).unwrap()) + /// ); + /// assert_eq!( + /// NaiveDate::from_ymd_opt(2022, 7, 31).unwrap().checked_add_days(Days::new(2)), + /// Some(NaiveDate::from_ymd_opt(2022, 8, 2).unwrap()) + /// ); + /// assert_eq!( + /// NaiveDate::from_ymd_opt(2022, 7, 31).unwrap().checked_add_days(Days::new(1000000000000)), + /// None + /// ); + /// ``` + #[must_use] + pub const fn checked_add_days(self, days: Days) -> Option { + match days.0 <= i32::MAX as u64 { + true => self.add_days(days.0 as i32), + false => None, + } + } + + /// Subtract a duration in [`Days`] from the date + /// + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. + /// + /// # Example + /// + /// ``` + /// # use chrono::{NaiveDate, Days}; + /// assert_eq!( + /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_sub_days(Days::new(6)), + /// Some(NaiveDate::from_ymd_opt(2022, 2, 14).unwrap()) + /// ); + /// assert_eq!( + /// NaiveDate::from_ymd_opt(2022, 2, 20).unwrap().checked_sub_days(Days::new(1000000000000)), + /// None + /// ); + /// ``` + #[must_use] + pub const fn checked_sub_days(self, days: Days) -> Option { + match days.0 <= i32::MAX as u64 { + true => self.add_days(-(days.0 as i32)), + false => None, + } + } + + /// Add a duration of `i32` days to the date. + pub(crate) const fn add_days(self, days: i32) -> Option { + // fast path if the result is within the same year + const ORDINAL_MASK: i32 = 0b1_1111_1111_0000; + if let Some(ordinal) = ((self.ymdf & ORDINAL_MASK) >> 4).checked_add(days) { + if ordinal > 0 && ordinal <= 365 { + let year_and_flags = self.ymdf & !ORDINAL_MASK; + return Some(NaiveDate { ymdf: year_and_flags | (ordinal << 4) }); + } + } + // do the full check + let year = self.year(); + let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400); + let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal()); + let cycle = try_opt!((cycle as i32).checked_add(days)); + let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097); + year_div_400 += cycle_div_400y; + + let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); + let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); + NaiveDate::from_ordinal_and_flags(year_div_400 * 400 + year_mod_400 as i32, ordinal, flags) + } + + /// Makes a new `NaiveDateTime` from the current date and given `NaiveTime`. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, NaiveTime, NaiveDateTime}; + /// + /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); + /// let t = NaiveTime::from_hms_milli_opt(12, 34, 56, 789).unwrap(); + /// + /// let dt: NaiveDateTime = d.and_time(t); + /// assert_eq!(dt.date(), d); + /// assert_eq!(dt.time(), t); + /// ``` + #[inline] + #[must_use] + pub const fn and_time(&self, time: NaiveTime) -> NaiveDateTime { + NaiveDateTime::new(*self, time) + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute and second. + /// + /// No [leap second](./struct.NaiveTime.html#leap-second-handling) is allowed here; + /// use `NaiveDate::and_hms_*` methods with a subsecond parameter instead. + /// + /// # Panics + /// + /// Panics on invalid hour, minute and/or second. + #[deprecated(since = "0.4.23", note = "use `and_hms_opt()` instead")] + #[inline] + #[must_use] + pub const fn and_hms(&self, hour: u32, min: u32, sec: u32) -> NaiveDateTime { + expect!(self.and_hms_opt(hour, min, sec), "invalid time") + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute and second. + /// + /// No [leap second](./struct.NaiveTime.html#leap-second-handling) is allowed here; + /// use `NaiveDate::and_hms_*_opt` methods with a subsecond parameter instead. + /// + /// # Errors + /// + /// Returns `None` on invalid hour, minute and/or second. + /// + /// # Example + /// + /// ``` + /// use chrono::NaiveDate; + /// + /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); + /// assert!(d.and_hms_opt(12, 34, 56).is_some()); + /// assert!(d.and_hms_opt(12, 34, 60).is_none()); // use `and_hms_milli_opt` instead + /// assert!(d.and_hms_opt(12, 60, 56).is_none()); + /// assert!(d.and_hms_opt(24, 34, 56).is_none()); + /// ``` + #[inline] + #[must_use] + pub const fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option { + let time = try_opt!(NaiveTime::from_hms_opt(hour, min, sec)); + Some(self.and_time(time)) + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond. + /// + /// The millisecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second]( + /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`. + /// + /// # Panics + /// + /// Panics on invalid hour, minute, second and/or millisecond. + #[deprecated(since = "0.4.23", note = "use `and_hms_milli_opt()` instead")] + #[inline] + #[must_use] + pub const fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> NaiveDateTime { + expect!(self.and_hms_milli_opt(hour, min, sec, milli), "invalid time") + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond. + /// + /// The millisecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second]( + /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`. + /// + /// # Errors + /// + /// Returns `None` on invalid hour, minute, second and/or millisecond. + /// + /// # Example + /// + /// ``` + /// use chrono::NaiveDate; + /// + /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); + /// assert!(d.and_hms_milli_opt(12, 34, 56, 789).is_some()); + /// assert!(d.and_hms_milli_opt(12, 34, 59, 1_789).is_some()); // leap second + /// assert!(d.and_hms_milli_opt(12, 34, 59, 2_789).is_none()); + /// assert!(d.and_hms_milli_opt(12, 34, 60, 789).is_none()); + /// assert!(d.and_hms_milli_opt(12, 60, 56, 789).is_none()); + /// assert!(d.and_hms_milli_opt(24, 34, 56, 789).is_none()); + /// ``` + #[inline] + #[must_use] + pub const fn and_hms_milli_opt( + &self, + hour: u32, + min: u32, + sec: u32, + milli: u32, + ) -> Option { + let time = try_opt!(NaiveTime::from_hms_milli_opt(hour, min, sec, milli)); + Some(self.and_time(time)) + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond. + /// + /// The microsecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second]( + /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`. + /// + /// # Panics + /// + /// Panics on invalid hour, minute, second and/or microsecond. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; + /// + /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); + /// + /// let dt: NaiveDateTime = d.and_hms_micro_opt(12, 34, 56, 789_012).unwrap(); + /// assert_eq!(dt.year(), 2015); + /// assert_eq!(dt.weekday(), Weekday::Wed); + /// assert_eq!(dt.second(), 56); + /// assert_eq!(dt.nanosecond(), 789_012_000); + /// ``` + #[deprecated(since = "0.4.23", note = "use `and_hms_micro_opt()` instead")] + #[inline] + #[must_use] + pub const fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> NaiveDateTime { + expect!(self.and_hms_micro_opt(hour, min, sec, micro), "invalid time") + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond. + /// + /// The microsecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second]( + /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`. + /// + /// # Errors + /// + /// Returns `None` on invalid hour, minute, second and/or microsecond. + /// + /// # Example + /// + /// ``` + /// use chrono::NaiveDate; + /// + /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); + /// assert!(d.and_hms_micro_opt(12, 34, 56, 789_012).is_some()); + /// assert!(d.and_hms_micro_opt(12, 34, 59, 1_789_012).is_some()); // leap second + /// assert!(d.and_hms_micro_opt(12, 34, 59, 2_789_012).is_none()); + /// assert!(d.and_hms_micro_opt(12, 34, 60, 789_012).is_none()); + /// assert!(d.and_hms_micro_opt(12, 60, 56, 789_012).is_none()); + /// assert!(d.and_hms_micro_opt(24, 34, 56, 789_012).is_none()); + /// ``` + #[inline] + #[must_use] + pub const fn and_hms_micro_opt( + &self, + hour: u32, + min: u32, + sec: u32, + micro: u32, + ) -> Option { + let time = try_opt!(NaiveTime::from_hms_micro_opt(hour, min, sec, micro)); + Some(self.and_time(time)) + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond. + /// + /// The nanosecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second]( + /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`. + /// + /// # Panics + /// + /// Panics on invalid hour, minute, second and/or nanosecond. + #[deprecated(since = "0.4.23", note = "use `and_hms_nano_opt()` instead")] + #[inline] + #[must_use] + pub const fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> NaiveDateTime { + expect!(self.and_hms_nano_opt(hour, min, sec, nano), "invalid time") + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond. + /// + /// The nanosecond part is allowed to exceed 1,000,000,000 in order to represent a [leap second]( + /// ./struct.NaiveTime.html#leap-second-handling), but only when `sec == 59`. + /// + /// # Errors + /// + /// Returns `None` on invalid hour, minute, second and/or nanosecond. + /// + /// # Example + /// + /// ``` + /// use chrono::NaiveDate; + /// + /// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); + /// assert!(d.and_hms_nano_opt(12, 34, 56, 789_012_345).is_some()); + /// assert!(d.and_hms_nano_opt(12, 34, 59, 1_789_012_345).is_some()); // leap second + /// assert!(d.and_hms_nano_opt(12, 34, 59, 2_789_012_345).is_none()); + /// assert!(d.and_hms_nano_opt(12, 34, 60, 789_012_345).is_none()); + /// assert!(d.and_hms_nano_opt(12, 60, 56, 789_012_345).is_none()); + /// assert!(d.and_hms_nano_opt(24, 34, 56, 789_012_345).is_none()); + /// ``` + #[inline] + #[must_use] + pub const fn and_hms_nano_opt( + &self, + hour: u32, + min: u32, + sec: u32, + nano: u32, + ) -> Option { + let time = try_opt!(NaiveTime::from_hms_nano_opt(hour, min, sec, nano)); + Some(self.and_time(time)) + } + + /// Returns the packed month-day-flags. + #[inline] + const fn mdf(&self) -> Mdf { + self.of().to_mdf() + } + + /// Returns the packed ordinal-flags. + #[inline] + const fn of(&self) -> Of { + Of::from_date_impl(self.ymdf) + } + + /// Makes a new `NaiveDate` with the packed month-day-flags changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + #[inline] + const fn with_mdf(&self, mdf: Mdf) -> Option { + Some(self.with_of(try_opt!(mdf.to_of()))) + } + + /// Makes a new `NaiveDate` with the packed ordinal-flags changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// Does not check if the year flags match the year. + #[inline] + const fn with_of(&self, of: Of) -> NaiveDate { + NaiveDate { ymdf: (self.ymdf & !0b1_1111_1111_1111) | of.inner() as DateImpl } + } + + /// Makes a new `NaiveDate` for the next calendar date. + /// + /// # Panics + /// + /// Panics when `self` is the last representable date. + #[deprecated(since = "0.4.23", note = "use `succ_opt()` instead")] + #[inline] + #[must_use] + pub const fn succ(&self) -> NaiveDate { + expect!(self.succ_opt(), "out of bound") + } + + /// Makes a new `NaiveDate` for the next calendar date. + /// + /// # Errors + /// + /// Returns `None` when `self` is the last representable date. + /// + /// # Example + /// + /// ``` + /// use chrono::NaiveDate; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 6, 3).unwrap().succ_opt(), + /// Some(NaiveDate::from_ymd_opt(2015, 6, 4).unwrap())); + /// assert_eq!(NaiveDate::MAX.succ_opt(), None); + /// ``` + #[inline] + #[must_use] + pub const fn succ_opt(&self) -> Option { + match self.of().succ() { + Some(of) => Some(self.with_of(of)), + None => NaiveDate::from_ymd_opt(self.year() + 1, 1, 1), + } + } + + /// Makes a new `NaiveDate` for the previous calendar date. + /// + /// # Panics + /// + /// Panics when `self` is the first representable date. + #[deprecated(since = "0.4.23", note = "use `pred_opt()` instead")] + #[inline] + #[must_use] + pub const fn pred(&self) -> NaiveDate { + expect!(self.pred_opt(), "out of bound") + } + + /// Makes a new `NaiveDate` for the previous calendar date. + /// + /// # Errors + /// + /// Returns `None` when `self` is the first representable date. + /// + /// # Example + /// + /// ``` + /// use chrono::NaiveDate; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 6, 3).unwrap().pred_opt(), + /// Some(NaiveDate::from_ymd_opt(2015, 6, 2).unwrap())); + /// assert_eq!(NaiveDate::MIN.pred_opt(), None); + /// ``` + #[inline] + #[must_use] + pub const fn pred_opt(&self) -> Option { + match self.of().pred() { + Some(of) => Some(self.with_of(of)), + None => NaiveDate::from_ymd_opt(self.year() - 1, 12, 31), + } + } + + /// Adds the number of whole days in the given `TimeDelta` to the current date. + /// + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. + /// + /// # Example + /// + /// ``` + /// use chrono::{TimeDelta, NaiveDate}; + /// + /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); + /// assert_eq!(d.checked_add_signed(TimeDelta::days(40)), + /// Some(NaiveDate::from_ymd_opt(2015, 10, 15).unwrap())); + /// assert_eq!(d.checked_add_signed(TimeDelta::days(-40)), + /// Some(NaiveDate::from_ymd_opt(2015, 7, 27).unwrap())); + /// assert_eq!(d.checked_add_signed(TimeDelta::days(1_000_000_000)), None); + /// assert_eq!(d.checked_add_signed(TimeDelta::days(-1_000_000_000)), None); + /// assert_eq!(NaiveDate::MAX.checked_add_signed(TimeDelta::days(1)), None); + /// ``` + #[must_use] + pub const fn checked_add_signed(self, rhs: TimeDelta) -> Option { + let days = rhs.num_days(); + if days < i32::MIN as i64 || days > i32::MAX as i64 { + return None; + } + self.add_days(days as i32) + } + + /// Subtracts the number of whole days in the given `TimeDelta` from the current date. + /// + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. + /// + /// # Example + /// + /// ``` + /// use chrono::{TimeDelta, NaiveDate}; + /// + /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); + /// assert_eq!(d.checked_sub_signed(TimeDelta::days(40)), + /// Some(NaiveDate::from_ymd_opt(2015, 7, 27).unwrap())); + /// assert_eq!(d.checked_sub_signed(TimeDelta::days(-40)), + /// Some(NaiveDate::from_ymd_opt(2015, 10, 15).unwrap())); + /// assert_eq!(d.checked_sub_signed(TimeDelta::days(1_000_000_000)), None); + /// assert_eq!(d.checked_sub_signed(TimeDelta::days(-1_000_000_000)), None); + /// assert_eq!(NaiveDate::MIN.checked_sub_signed(TimeDelta::days(1)), None); + /// ``` + #[must_use] + pub const fn checked_sub_signed(self, rhs: TimeDelta) -> Option { + let days = -rhs.num_days(); + if days < i32::MIN as i64 || days > i32::MAX as i64 { + return None; + } + self.add_days(days as i32) + } + + /// Subtracts another `NaiveDate` from the current date. + /// Returns a `TimeDelta` of integral numbers. + /// + /// This does not overflow or underflow at all, + /// as all possible output fits in the range of `TimeDelta`. + /// + /// # Example + /// + /// ``` + /// use chrono::{TimeDelta, NaiveDate}; + /// + /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); + /// let since = NaiveDate::signed_duration_since; + /// + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 1)), TimeDelta::zero()); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 12, 31)), TimeDelta::days(1)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 2)), TimeDelta::days(-1)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 9, 23)), TimeDelta::days(100)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 1, 1)), TimeDelta::days(365)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2010, 1, 1)), TimeDelta::days(365*4 + 1)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(1614, 1, 1)), TimeDelta::days(365*400 + 97)); + /// ``` + #[must_use] + pub const fn signed_duration_since(self, rhs: NaiveDate) -> TimeDelta { + let year1 = self.year(); + let year2 = rhs.year(); + let (year1_div_400, year1_mod_400) = div_mod_floor(year1, 400); + let (year2_div_400, year2_mod_400) = div_mod_floor(year2, 400); + let cycle1 = internals::yo_to_cycle(year1_mod_400 as u32, self.of().ordinal()) as i64; + let cycle2 = internals::yo_to_cycle(year2_mod_400 as u32, rhs.of().ordinal()) as i64; + TimeDelta::days((year1_div_400 as i64 - year2_div_400 as i64) * 146_097 + (cycle1 - cycle2)) + } + + /// Returns the number of whole years from the given `base` until `self`. + /// + /// # Errors + /// + /// Returns `None` if `base < self`. + #[must_use] + pub const fn years_since(&self, base: Self) -> Option { + let mut years = self.year() - base.year(); + // Comparing tuples is not (yet) possible in const context. Instead we combine month and + // day into one `u32` for easy comparison. + if (self.month() << 5 | self.day()) < (base.month() << 5 | base.day()) { + years -= 1; + } + + match years >= 0 { + true => Some(years as u32), + false => None, + } + } + + /// Formats the date with the specified formatting items. + /// Otherwise it is the same as the ordinary `format` method. + /// + /// The `Iterator` of items should be `Clone`able, + /// since the resulting `DelayedFormat` value may be formatted multiple times. + /// + /// # Example + /// + /// ``` + /// use chrono::NaiveDate; + /// use chrono::format::strftime::StrftimeItems; + /// + /// let fmt = StrftimeItems::new("%Y-%m-%d"); + /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); + /// assert_eq!(d.format_with_items(fmt.clone()).to_string(), "2015-09-05"); + /// assert_eq!(d.format("%Y-%m-%d").to_string(), "2015-09-05"); + /// ``` + /// + /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. + /// + /// ``` + /// # use chrono::NaiveDate; + /// # use chrono::format::strftime::StrftimeItems; + /// # let fmt = StrftimeItems::new("%Y-%m-%d").clone(); + /// # let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); + /// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05"); + /// ``` + #[cfg(feature = "alloc")] + #[inline] + #[must_use] + pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat + where + I: Iterator + Clone, + B: Borrow>, + { + DelayedFormat::new(Some(*self), None, items) + } + + /// Formats the date with the specified format string. + /// See the [`format::strftime` module](crate::format::strftime) + /// on the supported escape sequences. + /// + /// This returns a `DelayedFormat`, + /// which gets converted to a string only when actual formatting happens. + /// You may use the `to_string` method to get a `String`, + /// or just feed it into `print!` and other formatting macros. + /// (In this way it avoids the redundant memory allocation.) + /// + /// A wrong format string does *not* issue an error immediately. + /// Rather, converting or formatting the `DelayedFormat` fails. + /// You are recommended to immediately use `DelayedFormat` for this reason. + /// + /// # Example + /// + /// ``` + /// use chrono::NaiveDate; + /// + /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); + /// assert_eq!(d.format("%Y-%m-%d").to_string(), "2015-09-05"); + /// assert_eq!(d.format("%A, %-d %B, %C%y").to_string(), "Saturday, 5 September, 2015"); + /// ``` + /// + /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. + /// + /// ``` + /// # use chrono::NaiveDate; + /// # let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); + /// assert_eq!(format!("{}", d.format("%Y-%m-%d")), "2015-09-05"); + /// assert_eq!(format!("{}", d.format("%A, %-d %B, %C%y")), "Saturday, 5 September, 2015"); + /// ``` + #[cfg(feature = "alloc")] + #[inline] + #[must_use] + pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat> { + self.format_with_items(StrftimeItems::new(fmt)) + } + + /// Formats the date with the specified formatting items and locale. + #[cfg(all(feature = "unstable-locales", feature = "alloc"))] + #[inline] + #[must_use] + pub fn format_localized_with_items<'a, I, B>( + &self, + items: I, + locale: Locale, + ) -> DelayedFormat + where + I: Iterator + Clone, + B: Borrow>, + { + DelayedFormat::new_with_locale(Some(*self), None, items, locale) + } + + /// Formats the date with the specified format string and locale. + /// + /// See the [`crate::format::strftime`] module on the supported escape + /// sequences. + #[cfg(all(feature = "unstable-locales", feature = "alloc"))] + #[inline] + #[must_use] + pub fn format_localized<'a>( + &self, + fmt: &'a str, + locale: Locale, + ) -> DelayedFormat> { + self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale) + } + + /// Returns an iterator that steps by days across all representable dates. + /// + /// # Example + /// + /// ``` + /// # use chrono::NaiveDate; + /// + /// let expected = [ + /// NaiveDate::from_ymd_opt(2016, 2, 27).unwrap(), + /// NaiveDate::from_ymd_opt(2016, 2, 28).unwrap(), + /// NaiveDate::from_ymd_opt(2016, 2, 29).unwrap(), + /// NaiveDate::from_ymd_opt(2016, 3, 1).unwrap(), + /// ]; + /// + /// let mut count = 0; + /// for (idx, d) in NaiveDate::from_ymd_opt(2016, 2, 27).unwrap().iter_days().take(4).enumerate() { + /// assert_eq!(d, expected[idx]); + /// count += 1; + /// } + /// assert_eq!(count, 4); + /// + /// for d in NaiveDate::from_ymd_opt(2016, 3, 1).unwrap().iter_days().rev().take(4) { + /// count -= 1; + /// assert_eq!(d, expected[count]); + /// } + /// ``` + #[inline] + pub const fn iter_days(&self) -> NaiveDateDaysIterator { + NaiveDateDaysIterator { value: *self } + } + + /// Returns an iterator that steps by weeks across all representable dates. + /// + /// # Example + /// + /// ``` + /// # use chrono::NaiveDate; + /// + /// let expected = [ + /// NaiveDate::from_ymd_opt(2016, 2, 27).unwrap(), + /// NaiveDate::from_ymd_opt(2016, 3, 5).unwrap(), + /// NaiveDate::from_ymd_opt(2016, 3, 12).unwrap(), + /// NaiveDate::from_ymd_opt(2016, 3, 19).unwrap(), + /// ]; + /// + /// let mut count = 0; + /// for (idx, d) in NaiveDate::from_ymd_opt(2016, 2, 27).unwrap().iter_weeks().take(4).enumerate() { + /// assert_eq!(d, expected[idx]); + /// count += 1; + /// } + /// assert_eq!(count, 4); + /// + /// for d in NaiveDate::from_ymd_opt(2016, 3, 19).unwrap().iter_weeks().rev().take(4) { + /// count -= 1; + /// assert_eq!(d, expected[count]); + /// } + /// ``` + #[inline] + pub const fn iter_weeks(&self) -> NaiveDateWeeksIterator { + NaiveDateWeeksIterator { value: *self } + } + + /// Returns the [`NaiveWeek`] that the date belongs to, starting with the [`Weekday`] + /// specified. + #[inline] + pub const fn week(&self, start: Weekday) -> NaiveWeek { + NaiveWeek { date: *self, start } + } + + /// Returns `true` if this is a leap year. + /// + /// ``` + /// # use chrono::NaiveDate; + /// assert_eq!(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().leap_year(), true); + /// assert_eq!(NaiveDate::from_ymd_opt(2001, 1, 1).unwrap().leap_year(), false); + /// assert_eq!(NaiveDate::from_ymd_opt(2002, 1, 1).unwrap().leap_year(), false); + /// assert_eq!(NaiveDate::from_ymd_opt(2003, 1, 1).unwrap().leap_year(), false); + /// assert_eq!(NaiveDate::from_ymd_opt(2004, 1, 1).unwrap().leap_year(), true); + /// assert_eq!(NaiveDate::from_ymd_opt(2100, 1, 1).unwrap().leap_year(), false); + /// ``` + pub const fn leap_year(&self) -> bool { + self.ymdf & (0b1000) == 0 + } + + // This duplicates `Datelike::year()`, because trait methods can't be const yet. + #[inline] + const fn year(&self) -> i32 { + self.ymdf >> 13 + } + + /// Returns the day of year starting from 1. + // This duplicates `Datelike::ordinal()`, because trait methods can't be const yet. + #[inline] + const fn ordinal(&self) -> u32 { + self.of().ordinal() + } + + // This duplicates `Datelike::month()`, because trait methods can't be const yet. + #[inline] + const fn month(&self) -> u32 { + self.mdf().month() + } + + // This duplicates `Datelike::day()`, because trait methods can't be const yet. + #[inline] + const fn day(&self) -> u32 { + self.mdf().day() + } + + // This duplicates `Datelike::weekday()`, because trait methods can't be const yet. + #[inline] + const fn weekday(&self) -> Weekday { + self.of().weekday() + } + + /// Counts the days in the proleptic Gregorian calendar, with January 1, Year 1 (CE) as day 1. + // This duplicates `Datelike::num_days_from_ce()`, because trait methods can't be const yet. + pub(crate) const fn num_days_from_ce(&self) -> i32 { + // we know this wouldn't overflow since year is limited to 1/2^13 of i32's full range. + let mut year = self.year() - 1; + let mut ndays = 0; + if year < 0 { + let excess = 1 + (-year) / 400; + year += excess * 400; + ndays -= excess * 146_097; + } + let div_100 = year / 100; + ndays += ((year * 1461) >> 2) - div_100 + (div_100 >> 2); + ndays + self.ordinal() as i32 + } + + /// The minimum possible `NaiveDate` (January 1, 262144 BCE). + pub const MIN: NaiveDate = NaiveDate { ymdf: (MIN_YEAR << 13) | (1 << 4) | 0o12 /*D*/ }; + /// The maximum possible `NaiveDate` (December 31, 262142 CE). + pub const MAX: NaiveDate = NaiveDate { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o16 /*G*/ }; + + /// One day before the minimum possible `NaiveDate` (December 31, 262145 BCE). + pub(crate) const BEFORE_MIN: NaiveDate = + NaiveDate { ymdf: ((MIN_YEAR - 1) << 13) | (366 << 4) | 0o07 /*FE*/ }; + /// One day after the maximum possible `NaiveDate` (January 1, 262143 CE). + pub(crate) const AFTER_MAX: NaiveDate = + NaiveDate { ymdf: ((MAX_YEAR + 1) << 13) | (1 << 4) | 0o17 /*F*/ }; +} + +impl Datelike for NaiveDate { + /// Returns the year number in the [calendar date](#calendar-date). + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().year(), 2015); + /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().year(), -308); // 309 BCE + /// ``` + #[inline] + fn year(&self) -> i32 { + self.year() + } + + /// Returns the month number starting from 1. + /// + /// The return value ranges from 1 to 12. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().month(), 9); + /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().month(), 3); + /// ``` + #[inline] + fn month(&self) -> u32 { + self.month() + } + + /// Returns the month number starting from 0. + /// + /// The return value ranges from 0 to 11. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().month0(), 8); + /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().month0(), 2); + /// ``` + #[inline] + fn month0(&self) -> u32 { + self.month() - 1 + } + + /// Returns the day of month starting from 1. + /// + /// The return value ranges from 1 to 31. (The last day of month differs by months.) + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().day(), 8); + /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().day(), 14); + /// ``` + /// + /// Combined with [`NaiveDate::pred_opt`](#method.pred_opt), + /// one can determine the number of days in a particular month. + /// (Note that this panics when `year` is out of range.) + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// fn ndays_in_month(year: i32, month: u32) -> u32 { + /// // the first day of the next month... + /// let (y, m) = if month == 12 { (year + 1, 1) } else { (year, month + 1) }; + /// let d = NaiveDate::from_ymd_opt(y, m, 1).unwrap(); + /// + /// // ...is preceded by the last day of the original month + /// d.pred_opt().unwrap().day() + /// } + /// + /// assert_eq!(ndays_in_month(2015, 8), 31); + /// assert_eq!(ndays_in_month(2015, 9), 30); + /// assert_eq!(ndays_in_month(2015, 12), 31); + /// assert_eq!(ndays_in_month(2016, 2), 29); + /// assert_eq!(ndays_in_month(2017, 2), 28); + /// ``` + #[inline] + fn day(&self) -> u32 { + self.day() + } + + /// Returns the day of month starting from 0. + /// + /// The return value ranges from 0 to 30. (The last day of month differs by months.) + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().day0(), 7); + /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().day0(), 13); + /// ``` + #[inline] + fn day0(&self) -> u32 { + self.mdf().day() - 1 + } + + /// Returns the day of year starting from 1. + /// + /// The return value ranges from 1 to 366. (The last day of year differs by years.) + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().ordinal(), 251); + /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().ordinal(), 74); + /// ``` + /// + /// Combined with [`NaiveDate::pred_opt`](#method.pred_opt), + /// one can determine the number of days in a particular year. + /// (Note that this panics when `year` is out of range.) + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// fn ndays_in_year(year: i32) -> u32 { + /// // the first day of the next year... + /// let d = NaiveDate::from_ymd_opt(year + 1, 1, 1).unwrap(); + /// + /// // ...is preceded by the last day of the original year + /// d.pred_opt().unwrap().ordinal() + /// } + /// + /// assert_eq!(ndays_in_year(2015), 365); + /// assert_eq!(ndays_in_year(2016), 366); + /// assert_eq!(ndays_in_year(2017), 365); + /// assert_eq!(ndays_in_year(2000), 366); + /// assert_eq!(ndays_in_year(2100), 365); + /// ``` + #[inline] + fn ordinal(&self) -> u32 { + self.of().ordinal() + } + + /// Returns the day of year starting from 0. + /// + /// The return value ranges from 0 to 365. (The last day of year differs by years.) + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().ordinal0(), 250); + /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().ordinal0(), 73); + /// ``` + #[inline] + fn ordinal0(&self) -> u32 { + self.of().ordinal() - 1 + } + + /// Returns the day of week. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike, Weekday}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().weekday(), Weekday::Tue); + /// assert_eq!(NaiveDate::from_ymd_opt(-308, 3, 14).unwrap().weekday(), Weekday::Fri); + /// ``` + #[inline] + fn weekday(&self) -> Weekday { + self.weekday() + } + + #[inline] + fn iso_week(&self) -> IsoWeek { + isoweek::iso_week_from_yof(self.year(), self.of()) + } + + /// Makes a new `NaiveDate` with the year number changed, while keeping the same month and day. + /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or when the `NaiveDate` would be + /// out of range. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_year(2016), + /// Some(NaiveDate::from_ymd_opt(2016, 9, 8).unwrap())); + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_year(-308), + /// Some(NaiveDate::from_ymd_opt(-308, 9, 8).unwrap())); + /// ``` + /// + /// A leap day (February 29) is a good example that this method can return `None`. + /// + /// ``` + /// # use chrono::{NaiveDate, Datelike}; + /// assert!(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap().with_year(2015).is_none()); + /// assert!(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap().with_year(2020).is_some()); + /// ``` + #[inline] + fn with_year(&self, year: i32) -> Option { + // we need to operate with `mdf` since we should keep the month and day number as is + let mdf = self.mdf(); + + // adjust the flags as needed + let flags = YearFlags::from_year(year); + let mdf = mdf.with_flags(flags); + + NaiveDate::from_mdf(year, mdf) + } + + /// Makes a new `NaiveDate` with the month number (starting from 1) changed. + /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `month` is invalid. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_month(10), + /// Some(NaiveDate::from_ymd_opt(2015, 10, 8).unwrap())); + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_month(13), None); // no month 13 + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().with_month(2), None); // no February 30 + /// ``` + #[inline] + fn with_month(&self, month: u32) -> Option { + self.with_mdf(self.mdf().with_month(month)?) + } + + /// Makes a new `NaiveDate` with the month number (starting from 0) changed. + /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `month0` is + /// invalid. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_month0(9), + /// Some(NaiveDate::from_ymd_opt(2015, 10, 8).unwrap())); + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_month0(12), None); // no month 13 + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap().with_month0(1), None); // no February 30 + /// ``` + #[inline] + fn with_month0(&self, month0: u32) -> Option { + let month = month0.checked_add(1)?; + self.with_mdf(self.mdf().with_month(month)?) + } + + /// Makes a new `NaiveDate` with the day of month (starting from 1) changed. + /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `day` is invalid. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_day(30), + /// Some(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap())); + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_day(31), + /// None); // no September 31 + /// ``` + #[inline] + fn with_day(&self, day: u32) -> Option { + self.with_mdf(self.mdf().with_day(day)?) + } + + /// Makes a new `NaiveDate` with the day of month (starting from 0) changed. + /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `day0` is invalid. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_day0(29), + /// Some(NaiveDate::from_ymd_opt(2015, 9, 30).unwrap())); + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 9, 8).unwrap().with_day0(30), + /// None); // no September 31 + /// ``` + #[inline] + fn with_day0(&self, day0: u32) -> Option { + let day = day0.checked_add(1)?; + self.with_mdf(self.mdf().with_day(day)?) + } + + /// Makes a new `NaiveDate` with the day of year (starting from 1) changed. + /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `ordinal` is + /// invalid. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().with_ordinal(60), + /// Some(NaiveDate::from_ymd_opt(2015, 3, 1).unwrap())); + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().with_ordinal(366), + /// None); // 2015 had only 365 days + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2016, 1, 1).unwrap().with_ordinal(60), + /// Some(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap())); + /// assert_eq!(NaiveDate::from_ymd_opt(2016, 1, 1).unwrap().with_ordinal(366), + /// Some(NaiveDate::from_ymd_opt(2016, 12, 31).unwrap())); + /// ``` + #[inline] + fn with_ordinal(&self, ordinal: u32) -> Option { + self.of().with_ordinal(ordinal).map(|of| self.with_of(of)) + } + + /// Makes a new `NaiveDate` with the day of year (starting from 0) changed. + /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `ordinal0` is + /// invalid. + /// + /// # Example + /// + /// ``` + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().with_ordinal0(59), + /// Some(NaiveDate::from_ymd_opt(2015, 3, 1).unwrap())); + /// assert_eq!(NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().with_ordinal0(365), + /// None); // 2015 had only 365 days + /// + /// assert_eq!(NaiveDate::from_ymd_opt(2016, 1, 1).unwrap().with_ordinal0(59), + /// Some(NaiveDate::from_ymd_opt(2016, 2, 29).unwrap())); + /// assert_eq!(NaiveDate::from_ymd_opt(2016, 1, 1).unwrap().with_ordinal0(365), + /// Some(NaiveDate::from_ymd_opt(2016, 12, 31).unwrap())); + /// ``` + #[inline] + fn with_ordinal0(&self, ordinal0: u32) -> Option { + let ordinal = ordinal0.checked_add(1)?; + self.with_ordinal(ordinal) + } +} + +/// Add `TimeDelta` to `NaiveDate`. +/// +/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of +/// days towards `TimeDelta::zero()`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDate::checked_add_signed`] to get an `Option` instead. +/// +/// # Example +/// +/// ``` +/// use chrono::{TimeDelta, NaiveDate}; +/// +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); +/// +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::zero(), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::seconds(86399), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::seconds(-86399), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(1), from_ymd(2014, 1, 2)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(-1), from_ymd(2013, 12, 31)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(364), from_ymd(2014, 12, 31)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(365*4 + 1), from_ymd(2018, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + TimeDelta::days(365*400 + 97), from_ymd(2414, 1, 1)); +/// ``` +/// +/// [`NaiveDate::checked_add_signed`]: crate::NaiveDate::checked_add_signed +impl Add for NaiveDate { + type Output = NaiveDate; + + #[inline] + fn add(self, rhs: TimeDelta) -> NaiveDate { + self.checked_add_signed(rhs).expect("`NaiveDate + TimeDelta` overflowed") + } +} + +/// Add-assign of `TimeDelta` to `NaiveDate`. +/// +/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of days +/// towards `TimeDelta::zero()`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDate::checked_add_signed`] to get an `Option` instead. +impl AddAssign for NaiveDate { + #[inline] + fn add_assign(&mut self, rhs: TimeDelta) { + *self = self.add(rhs); + } +} + +/// Add `Months` to `NaiveDate`. +/// +/// The result will be clamped to valid days in the resulting month, see `checked_add_months` for +/// details. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using `NaiveDate::checked_add_months` to get an `Option` instead. +/// +/// # Example +/// +/// ``` +/// use chrono::{NaiveDate, Months}; +/// +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); +/// +/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(1), from_ymd(2014, 2, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(11), from_ymd(2014, 12, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(12), from_ymd(2015, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(13), from_ymd(2015, 2, 1)); +/// assert_eq!(from_ymd(2014, 1, 31) + Months::new(1), from_ymd(2014, 2, 28)); +/// assert_eq!(from_ymd(2020, 1, 31) + Months::new(1), from_ymd(2020, 2, 29)); +/// ``` +impl Add for NaiveDate { + type Output = NaiveDate; + + fn add(self, months: Months) -> Self::Output { + self.checked_add_months(months).expect("`NaiveDate + Months` out of range") + } +} + +/// Subtract `Months` from `NaiveDate`. +/// +/// The result will be clamped to valid days in the resulting month, see `checked_sub_months` for +/// details. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using `NaiveDate::checked_sub_months` to get an `Option` instead. +/// +/// # Example +/// +/// ``` +/// use chrono::{NaiveDate, Months}; +/// +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); +/// +/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(11), from_ymd(2013, 2, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(12), from_ymd(2013, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(13), from_ymd(2012, 12, 1)); +/// ``` +impl Sub for NaiveDate { + type Output = NaiveDate; + + fn sub(self, months: Months) -> Self::Output { + self.checked_sub_months(months).expect("`NaiveDate - Months` out of range") + } +} + +/// Add `Days` to `NaiveDate`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using `NaiveDate::checked_add_days` to get an `Option` instead. +impl Add for NaiveDate { + type Output = NaiveDate; + + fn add(self, days: Days) -> Self::Output { + self.checked_add_days(days).expect("`NaiveDate + Days` out of range") + } +} + +/// Subtract `Days` from `NaiveDate`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using `NaiveDate::checked_sub_days` to get an `Option` instead. +impl Sub for NaiveDate { + type Output = NaiveDate; + + fn sub(self, days: Days) -> Self::Output { + self.checked_sub_days(days).expect("`NaiveDate - Days` out of range") + } +} + +/// Subtract `TimeDelta` from `NaiveDate`. +/// +/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of +/// days towards `TimeDelta::zero()`. +/// It is the same as the addition with a negated `TimeDelta`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDate::checked_sub_signed`] to get an `Option` instead. +/// +/// # Example +/// +/// ``` +/// use chrono::{TimeDelta, NaiveDate}; +/// +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); +/// +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::zero(), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::seconds(86399), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::seconds(-86399), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(1), from_ymd(2013, 12, 31)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(-1), from_ymd(2014, 1, 2)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(364), from_ymd(2013, 1, 2)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(365*4 + 1), from_ymd(2010, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - TimeDelta::days(365*400 + 97), from_ymd(1614, 1, 1)); +/// ``` +/// +/// [`NaiveDate::checked_sub_signed`]: crate::NaiveDate::checked_sub_signed +impl Sub for NaiveDate { + type Output = NaiveDate; + + #[inline] + fn sub(self, rhs: TimeDelta) -> NaiveDate { + self.checked_sub_signed(rhs).expect("`NaiveDate - TimeDelta` overflowed") + } +} + +/// Subtract-assign `TimeDelta` from `NaiveDate`. +/// +/// This discards the fractional days in `TimeDelta`, rounding to the closest integral number of +/// days towards `TimeDelta::zero()`. +/// It is the same as the addition with a negated `TimeDelta`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDate::checked_sub_signed`] to get an `Option` instead. +impl SubAssign for NaiveDate { + #[inline] + fn sub_assign(&mut self, rhs: TimeDelta) { + *self = self.sub(rhs); + } +} + +/// Subtracts another `NaiveDate` from the current date. +/// Returns a `TimeDelta` of integral numbers. +/// +/// This does not overflow or underflow at all, +/// as all possible output fits in the range of `TimeDelta`. +/// +/// The implementation is a wrapper around +/// [`NaiveDate::signed_duration_since`](#method.signed_duration_since). +/// +/// # Example +/// +/// ``` +/// use chrono::{TimeDelta, NaiveDate}; +/// +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); +/// +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 1), TimeDelta::zero()); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 12, 31), TimeDelta::days(1)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 2), TimeDelta::days(-1)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 9, 23), TimeDelta::days(100)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 1, 1), TimeDelta::days(365)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2010, 1, 1), TimeDelta::days(365*4 + 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(1614, 1, 1), TimeDelta::days(365*400 + 97)); +/// ``` +impl Sub for NaiveDate { + type Output = TimeDelta; + + #[inline] + fn sub(self, rhs: NaiveDate) -> TimeDelta { + self.signed_duration_since(rhs) + } +} + +impl From for NaiveDate { + fn from(naive_datetime: NaiveDateTime) -> Self { + naive_datetime.date() + } +} + +/// Iterator over `NaiveDate` with a step size of one day. +#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)] +pub struct NaiveDateDaysIterator { + value: NaiveDate, +} + +impl Iterator for NaiveDateDaysIterator { + type Item = NaiveDate; + + fn next(&mut self) -> Option { + // We return the current value, and have no way to return `NaiveDate::MAX`. + let current = self.value; + // This can't panic because current is < NaiveDate::MAX: + self.value = current.succ_opt()?; + Some(current) + } + + fn size_hint(&self) -> (usize, Option) { + let exact_size = NaiveDate::MAX.signed_duration_since(self.value).num_days(); + (exact_size as usize, Some(exact_size as usize)) + } +} + +impl ExactSizeIterator for NaiveDateDaysIterator {} + +impl DoubleEndedIterator for NaiveDateDaysIterator { + fn next_back(&mut self) -> Option { + // We return the current value, and have no way to return `NaiveDate::MIN`. + let current = self.value; + self.value = current.pred_opt()?; + Some(current) + } +} + +impl FusedIterator for NaiveDateDaysIterator {} + +/// Iterator over `NaiveDate` with a step size of one week. +#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)] +pub struct NaiveDateWeeksIterator { + value: NaiveDate, +} + +impl Iterator for NaiveDateWeeksIterator { + type Item = NaiveDate; + + fn next(&mut self) -> Option { + let current = self.value; + self.value = current.checked_add_signed(TimeDelta::weeks(1))?; + Some(current) + } + + fn size_hint(&self) -> (usize, Option) { + let exact_size = NaiveDate::MAX.signed_duration_since(self.value).num_weeks(); + (exact_size as usize, Some(exact_size as usize)) + } +} + +impl ExactSizeIterator for NaiveDateWeeksIterator {} + +impl DoubleEndedIterator for NaiveDateWeeksIterator { + fn next_back(&mut self) -> Option { + let current = self.value; + self.value = current.checked_sub_signed(TimeDelta::weeks(1))?; + Some(current) + } +} + +impl FusedIterator for NaiveDateWeeksIterator {} + +/// The `Debug` output of the naive date `d` is the same as +/// [`d.format("%Y-%m-%d")`](crate::format::strftime). +/// +/// The string printed can be readily parsed via the `parse` method on `str`. +/// +/// # Example +/// +/// ``` +/// use chrono::NaiveDate; +/// +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(2015, 9, 5).unwrap()), "2015-09-05"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt( 0, 1, 1).unwrap()), "0000-01-01"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(9999, 12, 31).unwrap()), "9999-12-31"); +/// ``` +/// +/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. +/// +/// ``` +/// # use chrono::NaiveDate; +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt( -1, 1, 1).unwrap()), "-0001-01-01"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(10000, 12, 31).unwrap()), "+10000-12-31"); +/// ``` +impl fmt::Debug for NaiveDate { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use core::fmt::Write; + + let year = self.year(); + let mdf = self.mdf(); + if (0..=9999).contains(&year) { + write_hundreds(f, (year / 100) as u8)?; + write_hundreds(f, (year % 100) as u8)?; + } else { + // ISO 8601 requires the explicit sign for out-of-range years + write!(f, "{:+05}", year)?; + } + + f.write_char('-')?; + write_hundreds(f, mdf.month() as u8)?; + f.write_char('-')?; + write_hundreds(f, mdf.day() as u8) + } +} + +/// The `Display` output of the naive date `d` is the same as +/// [`d.format("%Y-%m-%d")`](crate::format::strftime). +/// +/// The string printed can be readily parsed via the `parse` method on `str`. +/// +/// # Example +/// +/// ``` +/// use chrono::NaiveDate; +/// +/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt(2015, 9, 5).unwrap()), "2015-09-05"); +/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt( 0, 1, 1).unwrap()), "0000-01-01"); +/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt(9999, 12, 31).unwrap()), "9999-12-31"); +/// ``` +/// +/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. +/// +/// ``` +/// # use chrono::NaiveDate; +/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt( -1, 1, 1).unwrap()), "-0001-01-01"); +/// assert_eq!(format!("{}", NaiveDate::from_ymd_opt(10000, 12, 31).unwrap()), "+10000-12-31"); +/// ``` +impl fmt::Display for NaiveDate { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +/// Parsing a `str` into a `NaiveDate` uses the same format, +/// [`%Y-%m-%d`](crate::format::strftime), as in `Debug` and `Display`. +/// +/// # Example +/// +/// ``` +/// use chrono::NaiveDate; +/// +/// let d = NaiveDate::from_ymd_opt(2015, 9, 18).unwrap(); +/// assert_eq!("2015-09-18".parse::(), Ok(d)); +/// +/// let d = NaiveDate::from_ymd_opt(12345, 6, 7).unwrap(); +/// assert_eq!("+12345-6-7".parse::(), Ok(d)); +/// +/// assert!("foo".parse::().is_err()); +/// ``` +impl str::FromStr for NaiveDate { + type Err = ParseError; + + fn from_str(s: &str) -> ParseResult { + const ITEMS: &[Item<'static>] = &[ + Item::Numeric(Numeric::Year, Pad::Zero), + Item::Space(""), + Item::Literal("-"), + Item::Numeric(Numeric::Month, Pad::Zero), + Item::Space(""), + Item::Literal("-"), + Item::Numeric(Numeric::Day, Pad::Zero), + Item::Space(""), + ]; + + let mut parsed = Parsed::new(); + parse(&mut parsed, s, ITEMS.iter())?; + parsed.to_naive_date() + } +} + +/// The default value for a NaiveDate is 1st of January 1970. +/// +/// # Example +/// +/// ```rust +/// use chrono::NaiveDate; +/// +/// let default_date = NaiveDate::default(); +/// assert_eq!(default_date, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()); +/// ``` +impl Default for NaiveDate { + fn default() -> Self { + NaiveDate::from_ymd_opt(1970, 1, 1).unwrap() + } +} + +const fn div_mod_floor(val: i32, div: i32) -> (i32, i32) { + (val.div_euclid(div), val.rem_euclid(div)) +} + +#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] +fn test_encodable_json(to_string: F) +where + F: Fn(&NaiveDate) -> Result, + E: ::std::fmt::Debug, +{ + assert_eq!( + to_string(&NaiveDate::from_ymd_opt(2014, 7, 24).unwrap()).ok(), + Some(r#""2014-07-24""#.into()) + ); + assert_eq!( + to_string(&NaiveDate::from_ymd_opt(0, 1, 1).unwrap()).ok(), + Some(r#""0000-01-01""#.into()) + ); + assert_eq!( + to_string(&NaiveDate::from_ymd_opt(-1, 12, 31).unwrap()).ok(), + Some(r#""-0001-12-31""#.into()) + ); + assert_eq!(to_string(&NaiveDate::MIN).ok(), Some(r#""-262143-01-01""#.into())); + assert_eq!(to_string(&NaiveDate::MAX).ok(), Some(r#""+262142-12-31""#.into())); +} + +#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] +fn test_decodable_json(from_str: F) +where + F: Fn(&str) -> Result, + E: ::std::fmt::Debug, +{ + use std::{i32, i64}; + + assert_eq!( + from_str(r#""2016-07-08""#).ok(), + Some(NaiveDate::from_ymd_opt(2016, 7, 8).unwrap()) + ); + assert_eq!(from_str(r#""2016-7-8""#).ok(), Some(NaiveDate::from_ymd_opt(2016, 7, 8).unwrap())); + assert_eq!(from_str(r#""+002016-07-08""#).ok(), NaiveDate::from_ymd_opt(2016, 7, 8)); + assert_eq!(from_str(r#""0000-01-01""#).ok(), Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap())); + assert_eq!(from_str(r#""0-1-1""#).ok(), Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap())); + assert_eq!( + from_str(r#""-0001-12-31""#).ok(), + Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap()) + ); + assert_eq!(from_str(r#""-262143-01-01""#).ok(), Some(NaiveDate::MIN)); + assert_eq!(from_str(r#""+262142-12-31""#).ok(), Some(NaiveDate::MAX)); + + // bad formats + assert!(from_str(r#""""#).is_err()); + assert!(from_str(r#""20001231""#).is_err()); + assert!(from_str(r#""2000-00-00""#).is_err()); + assert!(from_str(r#""2000-02-30""#).is_err()); + assert!(from_str(r#""2001-02-29""#).is_err()); + assert!(from_str(r#""2002-002-28""#).is_err()); + assert!(from_str(r#""yyyy-mm-dd""#).is_err()); + assert!(from_str(r#"0"#).is_err()); + assert!(from_str(r#"20.01"#).is_err()); + assert!(from_str(&i32::MIN.to_string()).is_err()); + assert!(from_str(&i32::MAX.to_string()).is_err()); + assert!(from_str(&i64::MIN.to_string()).is_err()); + assert!(from_str(&i64::MAX.to_string()).is_err()); + assert!(from_str(r#"{}"#).is_err()); + // pre-0.3.0 rustc-serialize format is now invalid + assert!(from_str(r#"{"ymdf":20}"#).is_err()); + assert!(from_str(r#"null"#).is_err()); +} + +#[cfg(feature = "rustc-serialize")] +mod rustc_serialize { + use super::NaiveDate; + use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; + + impl Encodable for NaiveDate { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + format!("{:?}", self).encode(s) + } + } + + impl Decodable for NaiveDate { + fn decode(d: &mut D) -> Result { + d.read_str()?.parse().map_err(|_| d.error("invalid date")) + } + } + + #[cfg(test)] + mod tests { + use crate::naive::date::{test_decodable_json, test_encodable_json}; + use rustc_serialize::json; + + #[test] + fn test_encodable() { + test_encodable_json(json::encode); + } + + #[test] + fn test_decodable() { + test_decodable_json(json::decode); + } + } +} + +#[cfg(feature = "serde")] +mod serde { + use super::NaiveDate; + use core::fmt; + use serde::{de, ser}; + + // TODO not very optimized for space (binary formats would want something better) + + impl ser::Serialize for NaiveDate { + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + struct FormatWrapped<'a, D: 'a> { + inner: &'a D, + } + + impl<'a, D: fmt::Debug> fmt::Display for FormatWrapped<'a, D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } + } + + serializer.collect_str(&FormatWrapped { inner: &self }) + } + } + + struct NaiveDateVisitor; + + impl<'de> de::Visitor<'de> for NaiveDateVisitor { + type Value = NaiveDate; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a formatted date string") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + value.parse().map_err(E::custom) + } + } + + impl<'de> de::Deserialize<'de> for NaiveDate { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + deserializer.deserialize_str(NaiveDateVisitor) + } + } + + #[cfg(test)] + mod tests { + use crate::naive::date::{test_decodable_json, test_encodable_json}; + use crate::NaiveDate; + + #[test] + fn test_serde_serialize() { + test_encodable_json(serde_json::to_string); + } + + #[test] + fn test_serde_deserialize() { + test_decodable_json(|input| serde_json::from_str(input)); + } + + #[test] + fn test_serde_bincode() { + // Bincode is relevant to test separately from JSON because + // it is not self-describing. + use bincode::{deserialize, serialize}; + + let d = NaiveDate::from_ymd_opt(2014, 7, 24).unwrap(); + let encoded = serialize(&d).unwrap(); + let decoded: NaiveDate = deserialize(&encoded).unwrap(); + assert_eq!(d, decoded); + } + } +} + +#[cfg(test)] +mod tests { + use super::{Days, Months, NaiveDate, MAX_YEAR, MIN_YEAR}; + use crate::naive::internals::YearFlags; + use crate::{Datelike, TimeDelta, Weekday}; + + // as it is hard to verify year flags in `NaiveDate::MIN` and `NaiveDate::MAX`, + // we use a separate run-time test. + #[test] + fn test_date_bounds() { + let calculated_min = NaiveDate::from_ymd_opt(MIN_YEAR, 1, 1).unwrap(); + let calculated_max = NaiveDate::from_ymd_opt(MAX_YEAR, 12, 31).unwrap(); + assert!( + NaiveDate::MIN == calculated_min, + "`NaiveDate::MIN` should have year flag {:?}", + calculated_min.of().flags() + ); + assert!( + NaiveDate::MAX == calculated_max, + "`NaiveDate::MAX` should have year flag {:?} and ordinal {}", + calculated_max.of().flags(), + calculated_max.of().ordinal() + ); + + // let's also check that the entire range do not exceed 2^44 seconds + // (sometimes used for bounding `TimeDelta` against overflow) + let maxsecs = NaiveDate::MAX.signed_duration_since(NaiveDate::MIN).num_seconds(); + let maxsecs = maxsecs + 86401; // also take care of DateTime + assert!( + maxsecs < (1 << MAX_BITS), + "The entire `NaiveDate` range somehow exceeds 2^{} seconds", + MAX_BITS + ); + + const BEFORE_MIN: NaiveDate = NaiveDate::BEFORE_MIN; + assert_eq!(BEFORE_MIN.of().flags(), YearFlags::from_year(BEFORE_MIN.year())); + assert_eq!((BEFORE_MIN.month(), BEFORE_MIN.day()), (12, 31)); + + const AFTER_MAX: NaiveDate = NaiveDate::AFTER_MAX; + assert_eq!(AFTER_MAX.of().flags(), YearFlags::from_year(AFTER_MAX.year())); + assert_eq!((AFTER_MAX.month(), AFTER_MAX.day()), (1, 1)); + } + + #[test] + fn diff_months() { + // identity + assert_eq!( + NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_add_months(Months::new(0)), + Some(NaiveDate::from_ymd_opt(2022, 8, 3).unwrap()) + ); + + // add with months exceeding `i32::MAX` + assert_eq!( + NaiveDate::from_ymd_opt(2022, 8, 3) + .unwrap() + .checked_add_months(Months::new(i32::MAX as u32 + 1)), + None + ); + + // sub with months exceeding `i32::MIN` + assert_eq!( + NaiveDate::from_ymd_opt(2022, 8, 3) + .unwrap() + .checked_sub_months(Months::new(i32::MIN.unsigned_abs() + 1)), + None + ); + + // add overflowing year + assert_eq!(NaiveDate::MAX.checked_add_months(Months::new(1)), None); + + // add underflowing year + assert_eq!(NaiveDate::MIN.checked_sub_months(Months::new(1)), None); + + // sub crossing year 0 boundary + assert_eq!( + NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_sub_months(Months::new(2050 * 12)), + Some(NaiveDate::from_ymd_opt(-28, 8, 3).unwrap()) + ); + + // add crossing year boundary + assert_eq!( + NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_add_months(Months::new(6)), + Some(NaiveDate::from_ymd_opt(2023, 2, 3).unwrap()) + ); + + // sub crossing year boundary + assert_eq!( + NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_sub_months(Months::new(10)), + Some(NaiveDate::from_ymd_opt(2021, 10, 3).unwrap()) + ); + + // add clamping day, non-leap year + assert_eq!( + NaiveDate::from_ymd_opt(2022, 1, 29).unwrap().checked_add_months(Months::new(1)), + Some(NaiveDate::from_ymd_opt(2022, 2, 28).unwrap()) + ); + + // add to leap day + assert_eq!( + NaiveDate::from_ymd_opt(2022, 10, 29).unwrap().checked_add_months(Months::new(16)), + Some(NaiveDate::from_ymd_opt(2024, 2, 29).unwrap()) + ); + + // add into december + assert_eq!( + NaiveDate::from_ymd_opt(2022, 10, 31).unwrap().checked_add_months(Months::new(2)), + Some(NaiveDate::from_ymd_opt(2022, 12, 31).unwrap()) + ); + + // sub into december + assert_eq!( + NaiveDate::from_ymd_opt(2022, 10, 31).unwrap().checked_sub_months(Months::new(10)), + Some(NaiveDate::from_ymd_opt(2021, 12, 31).unwrap()) + ); + + // add into january + assert_eq!( + NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_add_months(Months::new(5)), + Some(NaiveDate::from_ymd_opt(2023, 1, 3).unwrap()) + ); + + // sub into january + assert_eq!( + NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_sub_months(Months::new(7)), + Some(NaiveDate::from_ymd_opt(2022, 1, 3).unwrap()) + ); + } + + #[test] + fn test_readme_doomsday() { + for y in NaiveDate::MIN.year()..=NaiveDate::MAX.year() { + // even months + let d4 = NaiveDate::from_ymd_opt(y, 4, 4).unwrap(); + let d6 = NaiveDate::from_ymd_opt(y, 6, 6).unwrap(); + let d8 = NaiveDate::from_ymd_opt(y, 8, 8).unwrap(); + let d10 = NaiveDate::from_ymd_opt(y, 10, 10).unwrap(); + let d12 = NaiveDate::from_ymd_opt(y, 12, 12).unwrap(); + + // nine to five, seven-eleven + let d59 = NaiveDate::from_ymd_opt(y, 5, 9).unwrap(); + let d95 = NaiveDate::from_ymd_opt(y, 9, 5).unwrap(); + let d711 = NaiveDate::from_ymd_opt(y, 7, 11).unwrap(); + let d117 = NaiveDate::from_ymd_opt(y, 11, 7).unwrap(); + + // "March 0" + let d30 = NaiveDate::from_ymd_opt(y, 3, 1).unwrap().pred_opt().unwrap(); + + let weekday = d30.weekday(); + let other_dates = [d4, d6, d8, d10, d12, d59, d95, d711, d117]; + assert!(other_dates.iter().all(|d| d.weekday() == weekday)); + } + } + + #[test] + fn test_date_from_ymd() { + let ymd_opt = NaiveDate::from_ymd_opt; + + assert!(ymd_opt(2012, 0, 1).is_none()); + assert!(ymd_opt(2012, 1, 1).is_some()); + assert!(ymd_opt(2012, 2, 29).is_some()); + assert!(ymd_opt(2014, 2, 29).is_none()); + assert!(ymd_opt(2014, 3, 0).is_none()); + assert!(ymd_opt(2014, 3, 1).is_some()); + assert!(ymd_opt(2014, 3, 31).is_some()); + assert!(ymd_opt(2014, 3, 32).is_none()); + assert!(ymd_opt(2014, 12, 31).is_some()); + assert!(ymd_opt(2014, 13, 1).is_none()); + } + + #[test] + fn test_date_from_yo() { + let yo_opt = NaiveDate::from_yo_opt; + let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); + + assert_eq!(yo_opt(2012, 0), None); + assert_eq!(yo_opt(2012, 1), Some(ymd(2012, 1, 1))); + assert_eq!(yo_opt(2012, 2), Some(ymd(2012, 1, 2))); + assert_eq!(yo_opt(2012, 32), Some(ymd(2012, 2, 1))); + assert_eq!(yo_opt(2012, 60), Some(ymd(2012, 2, 29))); + assert_eq!(yo_opt(2012, 61), Some(ymd(2012, 3, 1))); + assert_eq!(yo_opt(2012, 100), Some(ymd(2012, 4, 9))); + assert_eq!(yo_opt(2012, 200), Some(ymd(2012, 7, 18))); + assert_eq!(yo_opt(2012, 300), Some(ymd(2012, 10, 26))); + assert_eq!(yo_opt(2012, 366), Some(ymd(2012, 12, 31))); + assert_eq!(yo_opt(2012, 367), None); + + assert_eq!(yo_opt(2014, 0), None); + assert_eq!(yo_opt(2014, 1), Some(ymd(2014, 1, 1))); + assert_eq!(yo_opt(2014, 2), Some(ymd(2014, 1, 2))); + assert_eq!(yo_opt(2014, 32), Some(ymd(2014, 2, 1))); + assert_eq!(yo_opt(2014, 59), Some(ymd(2014, 2, 28))); + assert_eq!(yo_opt(2014, 60), Some(ymd(2014, 3, 1))); + assert_eq!(yo_opt(2014, 100), Some(ymd(2014, 4, 10))); + assert_eq!(yo_opt(2014, 200), Some(ymd(2014, 7, 19))); + assert_eq!(yo_opt(2014, 300), Some(ymd(2014, 10, 27))); + assert_eq!(yo_opt(2014, 365), Some(ymd(2014, 12, 31))); + assert_eq!(yo_opt(2014, 366), None); + } + + #[test] + fn test_date_from_isoywd() { + let isoywd_opt = NaiveDate::from_isoywd_opt; + let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); + + assert_eq!(isoywd_opt(2004, 0, Weekday::Sun), None); + assert_eq!(isoywd_opt(2004, 1, Weekday::Mon), Some(ymd(2003, 12, 29))); + assert_eq!(isoywd_opt(2004, 1, Weekday::Sun), Some(ymd(2004, 1, 4))); + assert_eq!(isoywd_opt(2004, 2, Weekday::Mon), Some(ymd(2004, 1, 5))); + assert_eq!(isoywd_opt(2004, 2, Weekday::Sun), Some(ymd(2004, 1, 11))); + assert_eq!(isoywd_opt(2004, 52, Weekday::Mon), Some(ymd(2004, 12, 20))); + assert_eq!(isoywd_opt(2004, 52, Weekday::Sun), Some(ymd(2004, 12, 26))); + assert_eq!(isoywd_opt(2004, 53, Weekday::Mon), Some(ymd(2004, 12, 27))); + assert_eq!(isoywd_opt(2004, 53, Weekday::Sun), Some(ymd(2005, 1, 2))); + assert_eq!(isoywd_opt(2004, 54, Weekday::Mon), None); + + assert_eq!(isoywd_opt(2011, 0, Weekday::Sun), None); + assert_eq!(isoywd_opt(2011, 1, Weekday::Mon), Some(ymd(2011, 1, 3))); + assert_eq!(isoywd_opt(2011, 1, Weekday::Sun), Some(ymd(2011, 1, 9))); + assert_eq!(isoywd_opt(2011, 2, Weekday::Mon), Some(ymd(2011, 1, 10))); + assert_eq!(isoywd_opt(2011, 2, Weekday::Sun), Some(ymd(2011, 1, 16))); + + assert_eq!(isoywd_opt(2018, 51, Weekday::Mon), Some(ymd(2018, 12, 17))); + assert_eq!(isoywd_opt(2018, 51, Weekday::Sun), Some(ymd(2018, 12, 23))); + assert_eq!(isoywd_opt(2018, 52, Weekday::Mon), Some(ymd(2018, 12, 24))); + assert_eq!(isoywd_opt(2018, 52, Weekday::Sun), Some(ymd(2018, 12, 30))); + assert_eq!(isoywd_opt(2018, 53, Weekday::Mon), None); + } + + #[test] + fn test_date_from_isoywd_and_iso_week() { + for year in 2000..2401 { + for week in 1..54 { + for &weekday in [ + Weekday::Mon, + Weekday::Tue, + Weekday::Wed, + Weekday::Thu, + Weekday::Fri, + Weekday::Sat, + Weekday::Sun, + ] + .iter() + { + let d = NaiveDate::from_isoywd_opt(year, week, weekday); + if let Some(d) = d { + assert_eq!(d.weekday(), weekday); + let w = d.iso_week(); + assert_eq!(w.year(), year); + assert_eq!(w.week(), week); + } + } + } + } + + for year in 2000..2401 { + for month in 1..13 { + for day in 1..32 { + let d = NaiveDate::from_ymd_opt(year, month, day); + if let Some(d) = d { + let w = d.iso_week(); + let d_ = NaiveDate::from_isoywd_opt(w.year(), w.week(), d.weekday()); + assert_eq!(d, d_.unwrap()); + } + } + } + } + } + + #[test] + fn test_date_from_num_days_from_ce() { + let from_ndays_from_ce = NaiveDate::from_num_days_from_ce_opt; + assert_eq!(from_ndays_from_ce(1), Some(NaiveDate::from_ymd_opt(1, 1, 1).unwrap())); + assert_eq!(from_ndays_from_ce(2), Some(NaiveDate::from_ymd_opt(1, 1, 2).unwrap())); + assert_eq!(from_ndays_from_ce(31), Some(NaiveDate::from_ymd_opt(1, 1, 31).unwrap())); + assert_eq!(from_ndays_from_ce(32), Some(NaiveDate::from_ymd_opt(1, 2, 1).unwrap())); + assert_eq!(from_ndays_from_ce(59), Some(NaiveDate::from_ymd_opt(1, 2, 28).unwrap())); + assert_eq!(from_ndays_from_ce(60), Some(NaiveDate::from_ymd_opt(1, 3, 1).unwrap())); + assert_eq!(from_ndays_from_ce(365), Some(NaiveDate::from_ymd_opt(1, 12, 31).unwrap())); + assert_eq!(from_ndays_from_ce(365 + 1), Some(NaiveDate::from_ymd_opt(2, 1, 1).unwrap())); + assert_eq!( + from_ndays_from_ce(365 * 2 + 1), + Some(NaiveDate::from_ymd_opt(3, 1, 1).unwrap()) + ); + assert_eq!( + from_ndays_from_ce(365 * 3 + 1), + Some(NaiveDate::from_ymd_opt(4, 1, 1).unwrap()) + ); + assert_eq!( + from_ndays_from_ce(365 * 4 + 2), + Some(NaiveDate::from_ymd_opt(5, 1, 1).unwrap()) + ); + assert_eq!( + from_ndays_from_ce(146097 + 1), + Some(NaiveDate::from_ymd_opt(401, 1, 1).unwrap()) + ); + assert_eq!( + from_ndays_from_ce(146097 * 5 + 1), + Some(NaiveDate::from_ymd_opt(2001, 1, 1).unwrap()) + ); + assert_eq!(from_ndays_from_ce(719163), Some(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap())); + assert_eq!(from_ndays_from_ce(0), Some(NaiveDate::from_ymd_opt(0, 12, 31).unwrap())); // 1 BCE + assert_eq!(from_ndays_from_ce(-365), Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap())); + assert_eq!(from_ndays_from_ce(-366), Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap())); // 2 BCE + + for days in (-9999..10001).map(|x| x * 100) { + assert_eq!(from_ndays_from_ce(days).map(|d| d.num_days_from_ce()), Some(days)); + } + + assert_eq!(from_ndays_from_ce(NaiveDate::MIN.num_days_from_ce()), Some(NaiveDate::MIN)); + assert_eq!(from_ndays_from_ce(NaiveDate::MIN.num_days_from_ce() - 1), None); + assert_eq!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce()), Some(NaiveDate::MAX)); + assert_eq!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce() + 1), None); + + assert_eq!(from_ndays_from_ce(i32::MIN), None); + assert_eq!(from_ndays_from_ce(i32::MAX), None); + } + + #[test] + fn test_date_from_weekday_of_month_opt() { + let ymwd = NaiveDate::from_weekday_of_month_opt; + assert_eq!(ymwd(2018, 8, Weekday::Tue, 0), None); + assert_eq!( + ymwd(2018, 8, Weekday::Wed, 1), + Some(NaiveDate::from_ymd_opt(2018, 8, 1).unwrap()) + ); + assert_eq!( + ymwd(2018, 8, Weekday::Thu, 1), + Some(NaiveDate::from_ymd_opt(2018, 8, 2).unwrap()) + ); + assert_eq!( + ymwd(2018, 8, Weekday::Sun, 1), + Some(NaiveDate::from_ymd_opt(2018, 8, 5).unwrap()) + ); + assert_eq!( + ymwd(2018, 8, Weekday::Mon, 1), + Some(NaiveDate::from_ymd_opt(2018, 8, 6).unwrap()) + ); + assert_eq!( + ymwd(2018, 8, Weekday::Tue, 1), + Some(NaiveDate::from_ymd_opt(2018, 8, 7).unwrap()) + ); + assert_eq!( + ymwd(2018, 8, Weekday::Wed, 2), + Some(NaiveDate::from_ymd_opt(2018, 8, 8).unwrap()) + ); + assert_eq!( + ymwd(2018, 8, Weekday::Sun, 2), + Some(NaiveDate::from_ymd_opt(2018, 8, 12).unwrap()) + ); + assert_eq!( + ymwd(2018, 8, Weekday::Thu, 3), + Some(NaiveDate::from_ymd_opt(2018, 8, 16).unwrap()) + ); + assert_eq!( + ymwd(2018, 8, Weekday::Thu, 4), + Some(NaiveDate::from_ymd_opt(2018, 8, 23).unwrap()) + ); + assert_eq!( + ymwd(2018, 8, Weekday::Thu, 5), + Some(NaiveDate::from_ymd_opt(2018, 8, 30).unwrap()) + ); + assert_eq!( + ymwd(2018, 8, Weekday::Fri, 5), + Some(NaiveDate::from_ymd_opt(2018, 8, 31).unwrap()) + ); + assert_eq!(ymwd(2018, 8, Weekday::Sat, 5), None); + } + + #[test] + fn test_date_fields() { + fn check(year: i32, month: u32, day: u32, ordinal: u32) { + let d1 = NaiveDate::from_ymd_opt(year, month, day).unwrap(); + assert_eq!(d1.year(), year); + assert_eq!(d1.month(), month); + assert_eq!(d1.day(), day); + assert_eq!(d1.ordinal(), ordinal); + + let d2 = NaiveDate::from_yo_opt(year, ordinal).unwrap(); + assert_eq!(d2.year(), year); + assert_eq!(d2.month(), month); + assert_eq!(d2.day(), day); + assert_eq!(d2.ordinal(), ordinal); + + assert_eq!(d1, d2); + } + + check(2012, 1, 1, 1); + check(2012, 1, 2, 2); + check(2012, 2, 1, 32); + check(2012, 2, 29, 60); + check(2012, 3, 1, 61); + check(2012, 4, 9, 100); + check(2012, 7, 18, 200); + check(2012, 10, 26, 300); + check(2012, 12, 31, 366); + + check(2014, 1, 1, 1); + check(2014, 1, 2, 2); + check(2014, 2, 1, 32); + check(2014, 2, 28, 59); + check(2014, 3, 1, 60); + check(2014, 4, 10, 100); + check(2014, 7, 19, 200); + check(2014, 10, 27, 300); + check(2014, 12, 31, 365); + } + + #[test] + fn test_date_weekday() { + assert_eq!(NaiveDate::from_ymd_opt(1582, 10, 15).unwrap().weekday(), Weekday::Fri); + // May 20, 1875 = ISO 8601 reference date + assert_eq!(NaiveDate::from_ymd_opt(1875, 5, 20).unwrap().weekday(), Weekday::Thu); + assert_eq!(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().weekday(), Weekday::Sat); + } + + #[test] + fn test_date_with_fields() { + let d = NaiveDate::from_ymd_opt(2000, 2, 29).unwrap(); + assert_eq!(d.with_year(-400), Some(NaiveDate::from_ymd_opt(-400, 2, 29).unwrap())); + assert_eq!(d.with_year(-100), None); + assert_eq!(d.with_year(1600), Some(NaiveDate::from_ymd_opt(1600, 2, 29).unwrap())); + assert_eq!(d.with_year(1900), None); + assert_eq!(d.with_year(2000), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap())); + assert_eq!(d.with_year(2001), None); + assert_eq!(d.with_year(2004), Some(NaiveDate::from_ymd_opt(2004, 2, 29).unwrap())); + assert_eq!(d.with_year(i32::MAX), None); + + let d = NaiveDate::from_ymd_opt(2000, 4, 30).unwrap(); + assert_eq!(d.with_month(0), None); + assert_eq!(d.with_month(1), Some(NaiveDate::from_ymd_opt(2000, 1, 30).unwrap())); + assert_eq!(d.with_month(2), None); + assert_eq!(d.with_month(3), Some(NaiveDate::from_ymd_opt(2000, 3, 30).unwrap())); + assert_eq!(d.with_month(4), Some(NaiveDate::from_ymd_opt(2000, 4, 30).unwrap())); + assert_eq!(d.with_month(12), Some(NaiveDate::from_ymd_opt(2000, 12, 30).unwrap())); + assert_eq!(d.with_month(13), None); + assert_eq!(d.with_month(u32::MAX), None); + + let d = NaiveDate::from_ymd_opt(2000, 2, 8).unwrap(); + assert_eq!(d.with_day(0), None); + assert_eq!(d.with_day(1), Some(NaiveDate::from_ymd_opt(2000, 2, 1).unwrap())); + assert_eq!(d.with_day(29), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap())); + assert_eq!(d.with_day(30), None); + assert_eq!(d.with_day(u32::MAX), None); + + let d = NaiveDate::from_ymd_opt(2000, 5, 5).unwrap(); + assert_eq!(d.with_ordinal(0), None); + assert_eq!(d.with_ordinal(1), Some(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap())); + assert_eq!(d.with_ordinal(60), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap())); + assert_eq!(d.with_ordinal(61), Some(NaiveDate::from_ymd_opt(2000, 3, 1).unwrap())); + assert_eq!(d.with_ordinal(366), Some(NaiveDate::from_ymd_opt(2000, 12, 31).unwrap())); + assert_eq!(d.with_ordinal(367), None); + assert_eq!(d.with_ordinal(u32::MAX), None); + } + + #[test] + fn test_date_num_days_from_ce() { + assert_eq!(NaiveDate::from_ymd_opt(1, 1, 1).unwrap().num_days_from_ce(), 1); + + for year in -9999..10001 { + assert_eq!( + NaiveDate::from_ymd_opt(year, 1, 1).unwrap().num_days_from_ce(), + NaiveDate::from_ymd_opt(year - 1, 12, 31).unwrap().num_days_from_ce() + 1 + ); + } + } + + #[test] + fn test_date_succ() { + let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); + assert_eq!(ymd(2014, 5, 6).succ_opt(), Some(ymd(2014, 5, 7))); + assert_eq!(ymd(2014, 5, 31).succ_opt(), Some(ymd(2014, 6, 1))); + assert_eq!(ymd(2014, 12, 31).succ_opt(), Some(ymd(2015, 1, 1))); + assert_eq!(ymd(2016, 2, 28).succ_opt(), Some(ymd(2016, 2, 29))); + assert_eq!(ymd(NaiveDate::MAX.year(), 12, 31).succ_opt(), None); + } + + #[test] + fn test_date_pred() { + let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); + assert_eq!(ymd(2016, 3, 1).pred_opt(), Some(ymd(2016, 2, 29))); + assert_eq!(ymd(2015, 1, 1).pred_opt(), Some(ymd(2014, 12, 31))); + assert_eq!(ymd(2014, 6, 1).pred_opt(), Some(ymd(2014, 5, 31))); + assert_eq!(ymd(2014, 5, 7).pred_opt(), Some(ymd(2014, 5, 6))); + assert_eq!(ymd(NaiveDate::MIN.year(), 1, 1).pred_opt(), None); + } + + #[test] + fn test_date_add() { + fn check((y1, m1, d1): (i32, u32, u32), rhs: TimeDelta, ymd: Option<(i32, u32, u32)>) { + let lhs = NaiveDate::from_ymd_opt(y1, m1, d1).unwrap(); + let sum = ymd.map(|(y, m, d)| NaiveDate::from_ymd_opt(y, m, d).unwrap()); + assert_eq!(lhs.checked_add_signed(rhs), sum); + assert_eq!(lhs.checked_sub_signed(-rhs), sum); + } + + check((2014, 1, 1), TimeDelta::zero(), Some((2014, 1, 1))); + check((2014, 1, 1), TimeDelta::seconds(86399), Some((2014, 1, 1))); + // always round towards zero + check((2014, 1, 1), TimeDelta::seconds(-86399), Some((2014, 1, 1))); + check((2014, 1, 1), TimeDelta::days(1), Some((2014, 1, 2))); + check((2014, 1, 1), TimeDelta::days(-1), Some((2013, 12, 31))); + check((2014, 1, 1), TimeDelta::days(364), Some((2014, 12, 31))); + check((2014, 1, 1), TimeDelta::days(365 * 4 + 1), Some((2018, 1, 1))); + check((2014, 1, 1), TimeDelta::days(365 * 400 + 97), Some((2414, 1, 1))); + + check((-7, 1, 1), TimeDelta::days(365 * 12 + 3), Some((5, 1, 1))); + + // overflow check + check((0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64), Some((MAX_YEAR, 12, 31))); + check((0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64 + 1), None); + check((0, 1, 1), TimeDelta::max_value(), None); + check((0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64), Some((MIN_YEAR, 1, 1))); + check((0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64 - 1), None); + check((0, 1, 1), TimeDelta::min_value(), None); + } + + #[test] + fn test_date_sub() { + fn check((y1, m1, d1): (i32, u32, u32), (y2, m2, d2): (i32, u32, u32), diff: TimeDelta) { + let lhs = NaiveDate::from_ymd_opt(y1, m1, d1).unwrap(); + let rhs = NaiveDate::from_ymd_opt(y2, m2, d2).unwrap(); + assert_eq!(lhs.signed_duration_since(rhs), diff); + assert_eq!(rhs.signed_duration_since(lhs), -diff); + } + + check((2014, 1, 1), (2014, 1, 1), TimeDelta::zero()); + check((2014, 1, 2), (2014, 1, 1), TimeDelta::days(1)); + check((2014, 12, 31), (2014, 1, 1), TimeDelta::days(364)); + check((2015, 1, 3), (2014, 1, 1), TimeDelta::days(365 + 2)); + check((2018, 1, 1), (2014, 1, 1), TimeDelta::days(365 * 4 + 1)); + check((2414, 1, 1), (2014, 1, 1), TimeDelta::days(365 * 400 + 97)); + + check((MAX_YEAR, 12, 31), (0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64)); + check((MIN_YEAR, 1, 1), (0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64)); + } + + #[test] + fn test_date_add_days() { + fn check((y1, m1, d1): (i32, u32, u32), rhs: Days, ymd: Option<(i32, u32, u32)>) { + let lhs = NaiveDate::from_ymd_opt(y1, m1, d1).unwrap(); + let sum = ymd.map(|(y, m, d)| NaiveDate::from_ymd_opt(y, m, d).unwrap()); + assert_eq!(lhs.checked_add_days(rhs), sum); + } + + check((2014, 1, 1), Days::new(0), Some((2014, 1, 1))); + // always round towards zero + check((2014, 1, 1), Days::new(1), Some((2014, 1, 2))); + check((2014, 1, 1), Days::new(364), Some((2014, 12, 31))); + check((2014, 1, 1), Days::new(365 * 4 + 1), Some((2018, 1, 1))); + check((2014, 1, 1), Days::new(365 * 400 + 97), Some((2414, 1, 1))); + + check((-7, 1, 1), Days::new(365 * 12 + 3), Some((5, 1, 1))); + + // overflow check + check( + (0, 1, 1), + Days::new(MAX_DAYS_FROM_YEAR_0.try_into().unwrap()), + Some((MAX_YEAR, 12, 31)), + ); + check((0, 1, 1), Days::new(u64::try_from(MAX_DAYS_FROM_YEAR_0).unwrap() + 1), None); + } + + #[test] + fn test_date_sub_days() { + fn check((y1, m1, d1): (i32, u32, u32), (y2, m2, d2): (i32, u32, u32), diff: Days) { + let lhs = NaiveDate::from_ymd_opt(y1, m1, d1).unwrap(); + let rhs = NaiveDate::from_ymd_opt(y2, m2, d2).unwrap(); + assert_eq!(lhs - diff, rhs); + } + + check((2014, 1, 1), (2014, 1, 1), Days::new(0)); + check((2014, 1, 2), (2014, 1, 1), Days::new(1)); + check((2014, 12, 31), (2014, 1, 1), Days::new(364)); + check((2015, 1, 3), (2014, 1, 1), Days::new(365 + 2)); + check((2018, 1, 1), (2014, 1, 1), Days::new(365 * 4 + 1)); + check((2414, 1, 1), (2014, 1, 1), Days::new(365 * 400 + 97)); + + check((MAX_YEAR, 12, 31), (0, 1, 1), Days::new(MAX_DAYS_FROM_YEAR_0.try_into().unwrap())); + check((0, 1, 1), (MIN_YEAR, 1, 1), Days::new((-MIN_DAYS_FROM_YEAR_0).try_into().unwrap())); + } + + #[test] + fn test_date_addassignment() { + let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); + let mut date = ymd(2016, 10, 1); + date += TimeDelta::days(10); + assert_eq!(date, ymd(2016, 10, 11)); + date += TimeDelta::days(30); + assert_eq!(date, ymd(2016, 11, 10)); + } + + #[test] + fn test_date_subassignment() { + let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); + let mut date = ymd(2016, 10, 11); + date -= TimeDelta::days(10); + assert_eq!(date, ymd(2016, 10, 1)); + date -= TimeDelta::days(2); + assert_eq!(date, ymd(2016, 9, 29)); + } + + #[test] + fn test_date_fmt() { + assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(2012, 3, 4).unwrap()), "2012-03-04"); + assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(0, 3, 4).unwrap()), "0000-03-04"); + assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(-307, 3, 4).unwrap()), "-0307-03-04"); + assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(12345, 3, 4).unwrap()), "+12345-03-04"); + + assert_eq!(NaiveDate::from_ymd_opt(2012, 3, 4).unwrap().to_string(), "2012-03-04"); + assert_eq!(NaiveDate::from_ymd_opt(0, 3, 4).unwrap().to_string(), "0000-03-04"); + assert_eq!(NaiveDate::from_ymd_opt(-307, 3, 4).unwrap().to_string(), "-0307-03-04"); + assert_eq!(NaiveDate::from_ymd_opt(12345, 3, 4).unwrap().to_string(), "+12345-03-04"); + + // the format specifier should have no effect on `NaiveTime` + assert_eq!(format!("{:+30?}", NaiveDate::from_ymd_opt(1234, 5, 6).unwrap()), "1234-05-06"); + assert_eq!( + format!("{:30?}", NaiveDate::from_ymd_opt(12345, 6, 7).unwrap()), + "+12345-06-07" + ); + } + + #[test] + fn test_date_from_str() { + // valid cases + let valid = [ + "-0000000123456-1-2", + " -123456 - 1 - 2 ", + "-12345-1-2", + "-1234-12-31", + "-7-6-5", + "350-2-28", + "360-02-29", + "0360-02-29", + "2015-2 -18", + "2015-02-18", + "+70-2-18", + "+70000-2-18", + "+00007-2-18", + ]; + for &s in &valid { + eprintln!("test_date_from_str valid {:?}", s); + let d = match s.parse::() { + Ok(d) => d, + Err(e) => panic!("parsing `{}` has failed: {}", s, e), + }; + eprintln!("d {:?} (NaiveDate)", d); + let s_ = format!("{:?}", d); + eprintln!("s_ {:?}", s_); + // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same + let d_ = match s_.parse::() { + Ok(d) => d, + Err(e) => { + panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", s, d, e) + } + }; + eprintln!("d_ {:?} (NaiveDate)", d_); + assert!( + d == d_, + "`{}` is parsed into `{:?}`, but reparsed result \ + `{:?}` does not match", + s, + d, + d_ + ); + } + + // some invalid cases + // since `ParseErrorKind` is private, all we can do is to check if there was an error + let invalid = [ + "", // empty + "x", // invalid + "Fri, 09 Aug 2013 GMT", // valid date, wrong format + "Sat Jun 30 2012", // valid date, wrong format + "1441497364.649", // valid datetime, wrong format + "+1441497364.649", // valid datetime, wrong format + "+1441497364", // valid datetime, wrong format + "2014/02/03", // valid date, wrong format + "2014", // datetime missing data + "2014-01", // datetime missing data + "2014-01-00", // invalid day + "2014-11-32", // invalid day + "2014-13-01", // invalid month + "2014-13-57", // invalid month, day + "9999999-9-9", // invalid year (out of bounds) + ]; + for &s in &invalid { + eprintln!("test_date_from_str invalid {:?}", s); + assert!(s.parse::().is_err()); + } + } + + #[test] + fn test_date_parse_from_str() { + let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); + assert_eq!( + NaiveDate::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), + Ok(ymd(2014, 5, 7)) + ); // ignore time and offset + assert_eq!( + NaiveDate::parse_from_str("2015-W06-1=2015-033", "%G-W%V-%u = %Y-%j"), + Ok(ymd(2015, 2, 2)) + ); + assert_eq!( + NaiveDate::parse_from_str("Fri, 09 Aug 13", "%a, %d %b %y"), + Ok(ymd(2013, 8, 9)) + ); + assert!(NaiveDate::parse_from_str("Sat, 09 Aug 2013", "%a, %d %b %Y").is_err()); + assert!(NaiveDate::parse_from_str("2014-57", "%Y-%m-%d").is_err()); + assert!(NaiveDate::parse_from_str("2014", "%Y").is_err()); // insufficient + + assert_eq!( + NaiveDate::parse_from_str("2020-01-0", "%Y-%W-%w").ok(), + NaiveDate::from_ymd_opt(2020, 1, 12), + ); + + assert_eq!( + NaiveDate::parse_from_str("2019-01-0", "%Y-%W-%w").ok(), + NaiveDate::from_ymd_opt(2019, 1, 13), + ); + } + + #[test] + fn test_day_iterator_limit() { + assert_eq!( + NaiveDate::from_ymd_opt(MAX_YEAR, 12, 29).unwrap().iter_days().take(4).count(), + 2 + ); + assert_eq!( + NaiveDate::from_ymd_opt(MIN_YEAR, 1, 3).unwrap().iter_days().rev().take(4).count(), + 2 + ); + } + + #[test] + fn test_week_iterator_limit() { + assert_eq!( + NaiveDate::from_ymd_opt(MAX_YEAR, 12, 12).unwrap().iter_weeks().take(4).count(), + 2 + ); + assert_eq!( + NaiveDate::from_ymd_opt(MIN_YEAR, 1, 15).unwrap().iter_weeks().rev().take(4).count(), + 2 + ); + } + + #[test] + fn test_naiveweek() { + let date = NaiveDate::from_ymd_opt(2022, 5, 18).unwrap(); + let asserts = [ + (Weekday::Mon, "Mon 2022-05-16", "Sun 2022-05-22"), + (Weekday::Tue, "Tue 2022-05-17", "Mon 2022-05-23"), + (Weekday::Wed, "Wed 2022-05-18", "Tue 2022-05-24"), + (Weekday::Thu, "Thu 2022-05-12", "Wed 2022-05-18"), + (Weekday::Fri, "Fri 2022-05-13", "Thu 2022-05-19"), + (Weekday::Sat, "Sat 2022-05-14", "Fri 2022-05-20"), + (Weekday::Sun, "Sun 2022-05-15", "Sat 2022-05-21"), + ]; + for (start, first_day, last_day) in asserts { + let week = date.week(start); + let days = week.days(); + assert_eq!(Ok(week.first_day()), NaiveDate::parse_from_str(first_day, "%a %Y-%m-%d")); + assert_eq!(Ok(week.last_day()), NaiveDate::parse_from_str(last_day, "%a %Y-%m-%d")); + assert!(days.contains(&date)); + } + } + + #[test] + fn test_naiveweek_min_max() { + let date_max = NaiveDate::MAX; + assert!(date_max.week(Weekday::Mon).first_day() <= date_max); + let date_min = NaiveDate::MIN; + assert!(date_min.week(Weekday::Mon).last_day() >= date_min); + } + + #[test] + fn test_weeks_from() { + // tests per: https://github.com/chronotope/chrono/issues/961 + // these internally use `weeks_from` via the parsing infrastructure + assert_eq!( + NaiveDate::parse_from_str("2020-01-0", "%Y-%W-%w").ok(), + NaiveDate::from_ymd_opt(2020, 1, 12), + ); + assert_eq!( + NaiveDate::parse_from_str("2019-01-0", "%Y-%W-%w").ok(), + NaiveDate::from_ymd_opt(2019, 1, 13), + ); + + // direct tests + for (y, starts_on) in &[ + (2019, Weekday::Tue), + (2020, Weekday::Wed), + (2021, Weekday::Fri), + (2022, Weekday::Sat), + (2023, Weekday::Sun), + (2024, Weekday::Mon), + (2025, Weekday::Wed), + (2026, Weekday::Thu), + ] { + for day in &[ + Weekday::Mon, + Weekday::Tue, + Weekday::Wed, + Weekday::Thu, + Weekday::Fri, + Weekday::Sat, + Weekday::Sun, + ] { + assert_eq!( + NaiveDate::from_ymd_opt(*y, 1, 1).map(|d| d.weeks_from(*day)), + Some(if day == starts_on { 1 } else { 0 }) + ); + + // last day must always be in week 52 or 53 + assert!([52, 53] + .contains(&NaiveDate::from_ymd_opt(*y, 12, 31).unwrap().weeks_from(*day)),); + } + } + + let base = NaiveDate::from_ymd_opt(2019, 1, 1).unwrap(); + + // 400 years covers all year types + for day in &[ + Weekday::Mon, + Weekday::Tue, + Weekday::Wed, + Weekday::Thu, + Weekday::Fri, + Weekday::Sat, + Weekday::Sun, + ] { + // must always be below 54 + for dplus in 1..(400 * 366) { + assert!((base + Days::new(dplus)).weeks_from(*day) < 54) + } + } + } + + #[test] + fn test_with_0_overflow() { + let dt = NaiveDate::from_ymd_opt(2023, 4, 18).unwrap(); + assert!(dt.with_month0(4294967295).is_none()); + assert!(dt.with_day0(4294967295).is_none()); + assert!(dt.with_ordinal0(4294967295).is_none()); + } + + #[test] + fn test_leap_year() { + for year in 0..=MAX_YEAR { + let date = NaiveDate::from_ymd_opt(year, 1, 1).unwrap(); + let is_leap = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); + assert_eq!(date.leap_year(), is_leap); + assert_eq!(date.leap_year(), date.with_ordinal(366).is_some()); + } + } + + #[test] + #[cfg(feature = "rkyv-validation")] + fn test_rkyv_validation() { + let date_min = NaiveDate::MIN; + let bytes = rkyv::to_bytes::<_, 4>(&date_min).unwrap(); + assert_eq!(rkyv::from_bytes::(&bytes).unwrap(), date_min); + + let date_max = NaiveDate::MAX; + let bytes = rkyv::to_bytes::<_, 4>(&date_max).unwrap(); + assert_eq!(rkyv::from_bytes::(&bytes).unwrap(), date_max); + } + + // MAX_YEAR-12-31 minus 0000-01-01 + // = (MAX_YEAR-12-31 minus 0000-12-31) + (0000-12-31 - 0000-01-01) + // = MAX_YEAR * 365 + (# of leap years from 0001 to MAX_YEAR) + 365 + // = (MAX_YEAR + 1) * 365 + (# of leap years from 0001 to MAX_YEAR) + const MAX_DAYS_FROM_YEAR_0: i32 = + (MAX_YEAR + 1) * 365 + MAX_YEAR / 4 - MAX_YEAR / 100 + MAX_YEAR / 400; + + // MIN_YEAR-01-01 minus 0000-01-01 + // = MIN_YEAR * 365 + (# of leap years from MIN_YEAR to 0000) + const MIN_DAYS_FROM_YEAR_0: i32 = + MIN_YEAR * 365 + MIN_YEAR / 4 - MIN_YEAR / 100 + MIN_YEAR / 400; + + // only used for testing, but duplicated in naive::datetime + const MAX_BITS: usize = 44; +} diff --git a/vendor/chrono/src/naive/datetime/rustc_serialize.rs b/vendor/chrono/src/naive/datetime/rustc_serialize.rs new file mode 100644 index 0000000000000..d2b8a87114635 --- /dev/null +++ b/vendor/chrono/src/naive/datetime/rustc_serialize.rs @@ -0,0 +1,75 @@ +use super::NaiveDateTime; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use std::ops::Deref; + +impl Encodable for NaiveDateTime { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + format!("{:?}", self).encode(s) + } +} + +impl Decodable for NaiveDateTime { + fn decode(d: &mut D) -> Result { + d.read_str()?.parse().map_err(|_| d.error("invalid date time string")) + } +} + +/// A `DateTime` that can be deserialized from a seconds-based timestamp +#[derive(Debug)] +#[deprecated( + since = "1.4.2", + note = "RustcSerialize will be removed before chrono 1.0, use Serde instead" +)] +pub struct TsSeconds(NaiveDateTime); + +#[allow(deprecated)] +impl From for NaiveDateTime { + /// Pull the internal NaiveDateTime out + #[allow(deprecated)] + fn from(obj: TsSeconds) -> NaiveDateTime { + obj.0 + } +} + +#[allow(deprecated)] +impl Deref for TsSeconds { + type Target = NaiveDateTime; + + #[allow(deprecated)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[allow(deprecated)] +impl Decodable for TsSeconds { + #[allow(deprecated)] + fn decode(d: &mut D) -> Result { + Ok(TsSeconds( + NaiveDateTime::from_timestamp_opt(d.read_i64()?, 0) + .ok_or_else(|| d.error("invalid timestamp"))?, + )) + } +} + +#[cfg(test)] +mod tests { + use crate::naive::datetime::test_encodable_json; + use crate::naive::datetime::{test_decodable_json, test_decodable_json_timestamp}; + use rustc_serialize::json; + + #[test] + fn test_encodable() { + test_encodable_json(json::encode); + } + + #[test] + fn test_decodable() { + test_decodable_json(json::decode); + } + + #[test] + fn test_decodable_timestamps() { + test_decodable_json_timestamp(json::decode); + } +} diff --git a/vendor/chrono/src/naive/time/rustc_serialize.rs b/vendor/chrono/src/naive/time/rustc_serialize.rs new file mode 100644 index 0000000000000..3c5c47a18b984 --- /dev/null +++ b/vendor/chrono/src/naive/time/rustc_serialize.rs @@ -0,0 +1,30 @@ +use super::NaiveTime; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; + +impl Encodable for NaiveTime { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + format!("{:?}", self).encode(s) + } +} + +impl Decodable for NaiveTime { + fn decode(d: &mut D) -> Result { + d.read_str()?.parse().map_err(|_| d.error("invalid time")) + } +} + +#[cfg(test)] +mod tests { + use crate::naive::time::{test_decodable_json, test_encodable_json}; + use rustc_serialize::json; + + #[test] + fn test_encodable() { + test_encodable_json(json::encode); + } + + #[test] + fn test_decodable() { + test_decodable_json(json::decode); + } +} diff --git a/vendor/chrono/taplo.toml b/vendor/chrono/taplo.toml new file mode 100644 index 0000000000000..5fe42eb83fb39 --- /dev/null +++ b/vendor/chrono/taplo.toml @@ -0,0 +1,4 @@ +include = ["deny.toml", "**/Cargo.toml"] + +[formatting] +inline_table_expand = false diff --git a/vendor/clap-2.34.0/.cargo-checksum.json b/vendor/clap-2.34.0/.cargo-checksum.json new file mode 100644 index 0000000000000..f70b25fc3aa06 --- /dev/null +++ b/vendor/clap-2.34.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"623d43f94b419a5e79f7bc103d4de47f60daf7803d49e63058ba9e24f8f8c6cc","CONTRIBUTORS.md":"9b0d3eee116dda23705b732c19b777ebb2b998a6e4554027ae3f61715376b4bc","Cargo.toml":"e7d0b7019b86f3a6901416714ac94702f666c8de0bf197d717abb8a2f86e7e6a","LICENSE-MIT":"6725d1437fc6c77301f2ff0e7d52914cf4f9509213e1078dc77d9356dbe6eac5","README.md":"6a836ddd7544962b33ae76b03e0f550ace4e4c967aee23e24ce14fc31e58e885","SPONSORS.md":"640b56e535db654d7bf14b1fe63bc837dcfde37a85f14eb4f404663fe1b72af9","clap-test.rs":"b5ca72dedfe1e71c250c42a01a52a3f5f9ea2bb14d9fe09093e73b71880f79fd","justfile":"9ee43d53fda234044fee4edd1ecdac9f19864c7f00a4ea5cb2b6a8a0287c93e3","src/app/help.rs":"037094b39990115fdac105f550c2f6eb1cbbfc8ff8f65b6ca34c65634902c3ab","src/app/meta.rs":"d15a4118e9de562cacf9d2063f1f491e3c3ce4092b4e8ea5d4d92e2631ca247b","src/app/mod.rs":"0aee709776d1be519a5587258b433ba0b54d5ebda14bb0544ce32c0505d5dcec","src/app/parser.rs":"83917c7e8f39f1e5d1807095f0856be3c3450aa88a6abb8e4d7c1d1fe9dbb2c4","src/app/settings.rs":"b29e3f90c282a27865b27674bb5b0a4def2966646f0e70b4f78e587c9649e379","src/app/usage.rs":"65f6b5d6f068a8ded0e78faf59575202bc8729a079e9806d0afeba87fa6ba9fc","src/app/validator.rs":"3124617cbaf959466241f4ba1a9837c1184a7a06325c5cbe3d613a7786febd4e","src/args/any_arg.rs":"5a34d363ce5d74e1829c4feb2a8044e0d3c31d5af2094933cf61d6579e548ecf","src/args/arg.rs":"e9ad38d43bef8d36e96ae6edb2dc6ea2258c6a7287f6479aad5a21b8ed197fd6","src/args/arg_builder/base.rs":"989952f8b827bd60db85bebb09b23de4d3e1296cc1f195e9da447b154f10cd09","src/args/arg_builder/flag.rs":"3c90fc16079b3f921c9e9b3a9607467eb5afddfdc8da53e9528987a43d883e36","src/args/arg_builder/mod.rs":"31844ad665171a2d49d551debd3d1a20e8a77dd74d02f9ff6fc22f63b019db02","src/args/arg_builder/option.rs":"d882e07dc1d6a77aae06fc5dad5502b7a4c1fc6e8124e6ab08b6ec037cb08b85","src/args/arg_builder/positional.rs":"fd6720931b9622a6d6576494dfbe67ae40416b6083d0302c1a0d9e9a86bb2d3d","src/args/arg_builder/switched.rs":"bc4c5acb77741562c4258b643a3dddd6b22e5b1874b71919d333c7d1e03e0ccb","src/args/arg_builder/valued.rs":"5f19d8e84e3d0bd3aee4b6fbb124206a6ab234492fe2ffc7279043e983522765","src/args/arg_matcher.rs":"a3cbe567cab3817c3ec7e37eb36641c9b9af1056b0002748b99a3ce255d65fd5","src/args/arg_matches.rs":"2058c1b0276db9d345b66d0531159fa05677ef865823ac8ec9831473359b64a8","src/args/group.rs":"6f08b7ebcbe2968a6d8462ab7c32dfc36c6b862a00853e9dc13af827196bc923","src/args/macros.rs":"4686d5929c760d2dace4110e96179d6aa7e43d7f911938199b07cb5728dc319b","src/args/matched_arg.rs":"28754509ea5493b66b4a5648d977f7cd9b379507b6eff89d76931be91509e6fe","src/args/mod.rs":"66cc0bb745fafd6387db72caa5ac414514990a07421270bfb5d8aff77ff01600","src/args/settings.rs":"f52313e363c1a928d65a52fbb7abb04b2ae00bd1e319fe267cf809363618fce8","src/args/subcommand.rs":"518418bb276c9758e3f82fc73341d69a242836ce163cd2ef6198075acf6594ba","src/completions/bash.rs":"d086d1e477ed14702650e2e7e0d2d33ba0a977f0a5c9f4e5d3cdb23b6ae5529f","src/completions/elvish.rs":"91e6f6685c258bfa4cdd4d428fa84ec9b59b2133e3d75f0e88072a37454430dc","src/completions/fish.rs":"3a828f824bde8dbe6bfa2d9ea52259b8b534bc547e9d96aec46f56e430b118e4","src/completions/macros.rs":"fd449b9d5fc6c591feb419d209f72cddfff0dd0345a8ec9787c361be6e5275f8","src/completions/mod.rs":"96b1115d6973b68dbbb1b50929f281e4ba9943995bc69dbb0ef08311d623ae33","src/completions/powershell.rs":"738a642a074c74ea28af66de3973b132de97587192c996bed436d54f6dfb6179","src/completions/shell.rs":"f6e132d8ea06ee30435c977f0040a6eb804bfe7a802181041dee8a4f69f64bd1","src/completions/zsh.rs":"0a06b25521714c70bfb943e8a11be62b8010ddb8676a426c2b30b00daccef9fa","src/errors.rs":"7c755e43fa743a9f5071ce30fee224e84684ca7b948ce128844552fbd36cde75","src/fmt.rs":"02c640020993b439133ba6a336f5f6d79d80ca9ede8b81b115c429b0aa2b6944","src/lib.rs":"b55c29b8b6d36b3ff1e4230bbce533d8170139a72a28cf5e0fc26789bbc3383e","src/macros.rs":"86977f1557b943678c1b6feeb4b63b17692e35601075a6be841a40fa0da7acd4","src/map.rs":"0b53139bf9eb768843a478b905929153ae6837082d846d97c81dd0a98d2c5d55","src/osstringext.rs":"92be9bb46ce1673a71bd1e809585621a00e9b38d9eb8caf70f0f29c4a47e0c74","src/strext.rs":"9847933a25ccf757dbcbb1c5a4921a5f8cdaa9dfcd451961bc37d1023d8dd1e1","src/suggestions.rs":"98f6ad3aa5df6cc6c8a1d31a5d1bea9a33cc8fed2b0f5f38255f3878b3cfce37","src/usage_parser.rs":"90b41f753d26cd6dfbf97613a8325c9034c1d98e55cee339c792f0b70baa6595"},"package":"a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"} \ No newline at end of file diff --git a/vendor/clap-2.34.0/CHANGELOG.md b/vendor/clap-2.34.0/CHANGELOG.md new file mode 100644 index 0000000000000..7f61b8410e9df --- /dev/null +++ b/vendor/clap-2.34.0/CHANGELOG.md @@ -0,0 +1,2902 @@ + +## v2.34.0 (2021-11-30) + +- Updates to Rust 2018 edition and bumps the MSRV to Rust 1.46 + + +### v2.33.4 (2021-11-29) + +#### Bug Fixes + +* **prevents `panic`:** swallows broken pipe errors on error output ([7a729bc4](https://github.com/kbknapp/clap-rs/commit/7a729bc4df2646b05f6bf15f001124cd39d076ce)) + + +### v2.33.3 (2020-08-13) + +#### Improvements + +* Suppress deprecation warnings when using `crate_*` macros. + + +### v2.33.2 (2020-08-5) + +#### Documentation + +* Fixed links to `2.x` examples. Now they point to the right place. + + +### v2.33.1 (2020-05-11) + +#### Bug Fixes + +* Windows: Prevent some panics when parsing invalid Unicode on Windows ([922c645](https://github.com/clap-rs/clap/commit/922c64508389170c9c77f1c8a4e597d14d3ed2f0), closes [#1905](https://github.com/clap-rs/clap/issues/1905)) + +#### Documentation + +* fixes versions referenced in the README ([d307466a](https://github.com/kbknapp/clap-rs/commit/d307466af1013f172b8ec0252f01a473e2192d6b)) +* **README.md:** + * cuts down the number of examples to reduce confusion ([6e508ee0](https://github.com/kbknapp/clap-rs/commit/6e508ee09e7153de4adf4e88b0aa6418a537dadd)) + +#### Improvements + +* **Deps:** doesnt compile ansi_term on Windows since its not used ([b57ee946](https://github.com/kbknapp/clap-rs/commit/b57ee94609da3ddc897286cfba968f26ff961491), closes [#1155](https://github.com/kbknapp/clap-rs/issues/1155)) + +#### Minimum Required Rust + +* As of this release, `clap` requires `rustc 1.36.0` or greater. + + +## v2.33.0 (2019-04-06) + +#### New Sponsor + +* Stephen Oats is now a sponsor \o/ ([823457c0](https://github.com/kbknapp/clap-rs/commit/823457c0ef5e994ed7080cf62addbfe1aa3b1833)) +* **SPONSORS.md:** fixes Josh Triplett's info in the sponsor document ([24cb5740](https://github.com/kbknapp/clap-rs/commit/24cb574090a11159b48bba105d5ec2dfb0a20e4e)) + +#### Features + +* **Completions:** adds completion support for Elvish. ([e9d0562a](https://github.com/kbknapp/clap-rs/commit/e9d0562a1dc5dfe731ed7c767e6cee0af08f0cf9)) +* There is a new setting to disable automatic building of `--help` and `-h` flags (`AppSettings::DisableAutoHelp`) + +#### Improvements + +* **arg_matches.rs:** add Debug implementations ([47192b7a](https://github.com/kbknapp/clap-rs/commit/47192b7a2d84ec716b81ae4af621e008a8762dc9)) +* **macros:** Support shorthand syntax for ArgGroups ([df9095e7](https://github.com/kbknapp/clap-rs/commit/df9095e75bb1e7896415251d0d4ffd8a0ebcd559)) + +#### Documentation + +* Refer to macOS rather than OSX. ([ab0d767f](https://github.com/kbknapp/clap-rs/commit/ab0d767f3a5a57e2bbb97d0183c2ef63c8c77a6c)) +* **README.md:** use https for all links ([96a7639a](https://github.com/kbknapp/clap-rs/commit/96a7639a36bcb184c3f45348986883115ef1ab3a)) + +#### Bug Fixes + +* add debug assertion for missing args in subcommand ArgGroup ([2699d9e5](https://github.com/kbknapp/clap-rs/commit/2699d9e51e7eadc258ba64c4e347c5d1fef61343)) +* Restore compat with Rust 1.21 ([6b263de1](https://github.com/kbknapp/clap-rs/commit/6b263de1d42ede692ec5ee55019ad2fc6386f92e)) +* Dont mention unused subcommands ([ef92e2b6](https://github.com/kbknapp/clap-rs/commit/ef92e2b639ed305bdade4741f60fa85cb0101c5a)) +* **OsValues:** Add `ExactSizeIterator` implementation ([356c69e5](https://github.com/kbknapp/clap-rs/commit/356c69e508fd25a9f0ea2d27bf80ae1d9a8d88f4)) +* **arg_enum!:** + * Fix comma position for valid values. ([1f1f9ff3](https://github.com/kbknapp/clap-rs/commit/1f1f9ff3fa38a43231ef8be9cfea89a32e53f518)) + * Invalid expansions of some trailing-comma patterns ([7023184f](https://github.com/kbknapp/clap-rs/commit/7023184fca04e852c270341548d6a16207d13862)) +* **completions:** improve correctness of completions when whitespace is involved ([5a08ff29](https://github.com/kbknapp/clap-rs/commit/5a08ff295b2aa6ce29420df6252a0e3ff4441bdc)) +* **help message:** Unconditionally uses long description for subcommands ([6acc8b6a](https://github.com/kbknapp/clap-rs/commit/6acc8b6a621a765cbf513450188000d943676a30), closes [#897](https://github.com/kbknapp/clap-rs/issues/897)) +* **macros:** fixes broken pattern which prevented calling multi-argument Arg methods ([9e7a352e](https://github.com/kbknapp/clap-rs/commit/9e7a352e13aaf8025d80f2bac5c47fb32528672b)) +* **parser:** Better interaction between AllowExternalSubcommands and SubcommandRequired ([9601c95a](https://github.com/kbknapp/clap-rs/commit/9601c95a03d2b82bf265c328b4769238f1b79002)) + +#### Minimum Required Rust + +* As of this release, `clap` requires `rustc 1.31.0` or greater. + + +## v2.32.0 (2018-06-26) + +#### Minimum Required Rust + +* As of this release, `clap` requires `rustc 1.21.0` or greater. + + +#### Features + +* **Completions:** adds completion support for Elvish. ([e9d0562a](https://github.com/kbknapp/clap-rs/commit/e9d0562a1dc5dfe731ed7c767e6cee0af08f0cf9)) + +#### Improvements + +* **macros:** Support shorthand syntax for ArgGroups ([df9095e7](https://github.com/kbknapp/clap-rs/commit/df9095e75bb1e7896415251d0d4ffd8a0ebcd559)) + +#### Bug Fixes + +* **OsValues:** Add `ExactSizeIterator` implementation ([356c69e5](https://github.com/kbknapp/clap-rs/commit/356c69e508fd25a9f0ea2d27bf80ae1d9a8d88f4)) +* **arg_enum!:** Invalid expansions of some trailing-comma patterns ([7023184f](https://github.com/kbknapp/clap-rs/commit/7023184fca04e852c270341548d6a16207d13862)) +* **help message:** Unconditionally uses long description for subcommands ([6acc8b6a](https://github.com/kbknapp/clap-rs/commit/6acc8b6a621a765cbf513450188000d943676a30), closes [#897](https://github.com/kbknapp/clap-rs/issues/897)) + +#### Documentation + +* Refer to macOS rather than OSX. ([ab0d767f](https://github.com/kbknapp/clap-rs/commit/ab0d767f3a5a57e2bbb97d0183c2ef63c8c77a6c)) + + + + +### v2.31.2 (2018-03-19) + +#### Bug Fixes + +* **Fish Completions:** fixes a bug that only allowed a single completion in in Fish Shell ([e8774a8](https://github.com/kbknapp/clap-rs/pull/1214/commits/e8774a84ee4a319c888036e7c595ab46451d8e48), closes [#1212](https://github.com/kbknapp/clap-rs/issues/1212)) +* **AllowExternalSubcommands**: fixes a bug where external subcommands would be blocked by a similarly named subcommand (suggestions were getting in the way). ([a410e85](https://github.com/kbknapp/clap-rs/pull/1215/commits/a410e855bcd82b05f9efa73fa8b9774dc8842c6b)) + +#### Documentation + +* Fixes some typos in the `README.md` ([c8e685d7](https://github.com/kbknapp/clap-rs/commit/c8e685d76adee2a3cc06cac6952ffcf6f9548089)) + + +### v2.31.1 (2018-03-06) + + +#### Improvements + +* **AllowMissingPositional:** improves the ability of AllowMissingPositional to allow 'skipping' to the last positional arg with '--' ([df20e6e2](https://github.com/kbknapp/clap-rs/commit/df20e6e24b4e782be0b423b484b9798e3e2efe2f)) + + + +## v2.31.0 (2018-03-04) + + +#### Features + +* **Arg Indices:** adds the ability to query argument value indices ([f58d0576](https://github.com/kbknapp/clap-rs/commit/f58d05767ec8133c8eb2de117cb642b9ae29ccbc)) +* **Indices:** implements an Indices iterator ([1e67be44](https://github.com/kbknapp/clap-rs/commit/1e67be44f0ccf161cc84c4e6082382072e89c302)) +* **Raw Args** adds a convenience function to `Arg` that allows implying all of `Arg::last` `Arg::allow_hyphen_values` and `Arg::multiple(true)` ([66a78f29](https://github.com/kbknapp/clap-rs/commit/66a78f2972786f5fe7c07937a1ac23da2542afd2)) + +#### Documentation + +* Fix some typos and markdown issues. ([935ba0dd](https://github.com/kbknapp/clap-rs/commit/935ba0dd547a69c3f636c5486795012019408794)) +* **Arg Indices:** adds the documentation for the arg index querying methods ([50bc0047](https://github.com/kbknapp/clap-rs/commit/50bc00477afa64dc6cdc5de161d3de3ba1d105a7)) +* **CONTRIBUTING.md:** fix url to clippy upstream repo to point to https://github.com/rust-lang-nursery/rust-clippy instead of https://github.com/Manishearth/rust-clippy ([42407d7f](https://github.com/kbknapp/clap-rs/commit/42407d7f21d794103cda61f49d2615aae0a4bcd9)) +* **Values:** improves the docs example of the Values iterator ([74075d65](https://github.com/kbknapp/clap-rs/commit/74075d65e8db1ddb5e2a4558009a5729d749d1b6)) +* Updates readme to hint that the `wrap_help` feature is a thing ([fc7ab227](https://github.com/kbknapp/clap-rs/commit/66a78f2972786f5fe7c07937a1ac23da2542afd2)) + +### Improvements + +* Cargo.toml: use codegen-units = 1 in release and bench profiles ([19f425ea](https://github.com/kbknapp/clap-rs/commit/66a78f2972786f5fe7c07937a1ac23da2542afd2)) +* Adds WASM support (clap now compiles on WASM!) ([689949e5](https://github.com/kbknapp/clap-rs/commit/689949e57d390bb61bc69f3ed91f60a2105738d0)) +* Uses the short help tool-tip for PowerShell completion scripts ([ecda22ce](https://github.com/kbknapp/clap-rs/commit/ecda22ce7210ce56d7b2d1a5445dd1b8a2959656)) + + + +## v2.30.0 (2018-02-13) + +#### Bug Fixes + +* **YAML:** Adds a missing conversion from `Arg::last` when instantiating from a YAML file ([aab77c81a5](https://github.com/kbknapp/clap-rs/pull/1175/commits/aab77c81a519b045f95946ae0dd3e850f9b93070), closes [#1160](https://github.com/kbknapp/clap-rs/issues/1173)) + +#### Improvements + +* **Bash Completions:** instead of completing a generic option name, all bash completions fall back to file completions UNLESS `Arg::possible_values` was used ([872f02ae](https://github.com/kbknapp/clap-rs/commit/872f02aea900ffa376850a279eb164645e1234fa)) +* **Deps:** No longer needlessly compiles `ansi_term` on Windows since its not used ([b57ee946](https://github.com/kbknapp/clap-rs/commit/b57ee94609da3ddc897286cfba968f26ff961491), closes [#1155](https://github.com/kbknapp/clap-rs/issues/1155)) +* **Help Message:** changes the `[values: foo bar baz]` array to `[possible values: foo bar baz]` for consistency with the API ([414707e4e97](https://github.com/kbknapp/clap-rs/pull/1176/commits/414707e4e979d07bfe555247e5d130c546673708), closes [#1160](https://github.com/kbknapp/clap-rs/issues/1160)) + + + +### v2.29.4 (2018-02-06) + + +#### Bug Fixes + +* **Overrides Self:** fixes a bug where options with multiple values couldnt ever have multiple values ([d95907cf](https://github.com/kbknapp/clap-rs/commit/d95907cff6d011a901fe35fa00b0f4e18547a1fb)) + + + + +### v2.29.3 (2018-02-05) + + +#### Improvements + +* **Overrides:** clap now supports arguments which override with themselves ([6c7a0010](https://github.com/kbknapp/clap-rs/commit/6c7a001023ca1eac1cc6ffe6c936b4c4a2aa3c45), closes [#976](https://github.com/kbknapp/clap-rs/issues/976)) + +#### Bug Fixes + +* **Requirements:** fixes an issue where conflicting args would still show up as required ([e06cefac](https://github.com/kbknapp/clap-rs/commit/e06cefac97083838c0a4e1444dcad02a5c3f911e), closes [#1158](https://github.com/kbknapp/clap-rs/issues/1158)) +* Fixes a bug which disallows proper nesting of `--` ([73993fe](https://github.com/kbknapp/clap-rs/commit/73993fe30d135f682e763ec93dcb0814ed518011), closes [#1161](https://github.com/kbknapp/clap-rs/issues/1161)) + +#### New Settings + +* **AllArgsOverrideSelf:** adds a new convenience setting to allow all args to override themselves ([4670325d](https://github.com/kbknapp/clap-rs/commit/4670325d1bf0369addec2ae2bcb56f1be054c924)) + + + + +### v2.29.2 (2018-01-16) + + +#### Features + +* **completions/zsh.rs:** + * Escape possible values for options ([25561dec](https://github.com/kbknapp/clap-rs/commit/25561decf147d329b64634a14d9695673c2fc78f)) + * Implement postional argument possible values completion ([f3b0afd2](https://github.com/kbknapp/clap-rs/commit/f3b0afd2bef8b7be97162f8a7802ddf7603dff36)) + * Complete positional arguments properly ([e39aeab8](https://github.com/kbknapp/clap-rs/commit/e39aeab8487596046fbdbc6a226e5c8820585245)) + +#### Bug Fixes + +* **completions/zsh.rs:** + * Add missing autoload for is-at-least ([a6522607](https://github.com/kbknapp/clap-rs/commit/a652260795d1519f6ec2a7a09ccc1258499cad7b)) + * Don't pass -S to _arguments if Zsh is too old ([16b4f143](https://github.com/kbknapp/clap-rs/commit/16b4f143ff466b7ef18a267bc44ade0f9639109b)) + * Maybe fix completions with mixed positionals and subcommands ([1146f0da](https://github.com/kbknapp/clap-rs/commit/1146f0da154d6796fbfcb09db8efa3593cb0d898)) +* **completions/zsh.zsh:** Remove redundant code from output ([0e185b92](https://github.com/kbknapp/clap-rs/commit/0e185b922ed1e0fd653de00b4cd8d567d72ff68e), closes [#1142](https://github.com/kbknapp/clap-rs/issues/1142)) + + + + +### 2.29.1 (2018-01-09) + + +#### Documentation + +* fixes broken links. ([56e734b8](https://github.com/kbknapp/clap-rs/commit/56e734b839303d733d2e5baf7dac39bd7b97b8e4)) +* updates contributors list ([e1313a5a](https://github.com/kbknapp/clap-rs/commit/e1313a5a0f69d8f4016f73b860a63af8318a6676)) + +#### Performance + +* further debloating by removing generics from error cases ([eb8d919e](https://github.com/kbknapp/clap-rs/commit/eb8d919e6f3443db279ba0c902f15d76676c02dc)) +* debloats clap by deduplicating logic and refactors ([03e413d7](https://github.com/kbknapp/clap-rs/commit/03e413d7175d35827cd7d8908d47dbae15a849a3)) + +#### Bug Fixes + +* fixes the ripgrep benchmark by adding a value to a flag that expects it ([d26ab2b9](https://github.com/kbknapp/clap-rs/commit/d26ab2b97cf9c0ea675b440b7b0eaf6ac3ad01f4)) +* **bash completion:** Change the bash completion script code generation to support hyphens. ([ba7f1d18](https://github.com/kbknapp/clap-rs/commit/ba7f1d18eba7a07ce7f57e0981986f66c994b639)) +* **completions/zsh.rs:** Fix completion of long option values ([46365cf8](https://github.com/kbknapp/clap-rs/commit/46365cf8be5331ba04c895eb183e2f230b5aad51)) + + + +## 2.29.0 (2017-12-02) + + +#### API Additions + +* **Arg:** adds Arg::hide_env_values(bool) which allows one to hide any current env values and display only the key in help messages ([fb41d062](https://github.com/kbknapp/clap-rs/commit/fb41d062eedf37cb4f805c90adca29909bd197d7)) + + + + +## 2.28.0 (2017-11-28) + +The minimum required Rust is now 1.20. This was done to start using bitflags 1.0 and having >1.0 deps is a *very good* thing! + +#### Documentation + +* changes the demo version to 2.28 to stay in sync ([ce6ca492](https://github.com/kbknapp/clap-rs/commit/ce6ca492c7510ab6474075806360b96081b021a9)) +* Fix URL path to github hosted files ([ce72aada](https://github.com/kbknapp/clap-rs/commit/ce72aada56a9581d4a6cb4bf9bdb861c3906f8df), closes [#1106](https://github.com/kbknapp/clap-rs/issues/1106)) +* fix typo ([002b07fc](https://github.com/kbknapp/clap-rs/commit/002b07fc98a1c85acb66296b1eec0b2aba906125)) +* **README.md:** updates the readme and pulls out some redundant sections ([db6caf86](https://github.com/kbknapp/clap-rs/commit/db6caf8663747e679d2f4ed3bd127f33476754aa)) + +#### Improvements + +* adds '[SUBCOMMAND]' to usage strings with only AppSettings::AllowExternalSubcommands is used with no other subcommands ([e78bb757](https://github.com/kbknapp/clap-rs/commit/e78bb757a3df16e82d539e450c06767a6bfcf859), closes [#1093](https://github.com/kbknapp/clap-rs/issues/1093)) + +#### API Additions + +* Adds Arg::case_insensitive(bool) which allows matching Arg::possible_values without worrying about ASCII case ([1fec268e](https://github.com/kbknapp/clap-rs/commit/1fec268e51736602e38e67c76266f439e2e0ef12), closes [#1118](https://github.com/kbknapp/clap-rs/issues/1118)) +* Adds the traits to be used with the clap-derive crate to be able to use Custom Derive ([6f4c3412](https://github.com/kbknapp/clap-rs/commit/6f4c3412415e882f5ca2cc3fbd6d4dce79440828)) + +#### Bug Fixes + +* Fixes a regression where --help couldn't be overridden ([a283d69f](https://github.com/kbknapp/clap-rs/commit/a283d69fc08aa016ae1bf9ba010012abecc7ba69), closes [#1112](https://github.com/kbknapp/clap-rs/issues/1112)) +* fixes a bug that allowed options to pass parsing when no value was provided ([2fb75821](https://github.com/kbknapp/clap-rs/commit/2fb758219c7a60d639da67692e100b855a8165ac), closes [#1105](https://github.com/kbknapp/clap-rs/issues/1105)) +* ignore PropagateGlobalValuesDown deprecation warning ([f61ce3f5](https://github.com/kbknapp/clap-rs/commit/f61ce3f55fe65e16b3db0bd4facdc4575de22767), closes [#1086](https://github.com/kbknapp/clap-rs/issues/1086)) + +#### Deps + +* Updates `bitflags` to 1.0 + + + + +## v2.27.1 (2017-10-24) + + +#### Bug Fixes + +* Adds `term_size` as an optional dependency (with feature `wrap_help`) to fix compile bug + + +## v2.27.0 (2017-10-24) + +** This release raises the minimum required version of Rust to 1.18 ** + +** This release also contains a very minor breaking change to fix a bug ** + +The only CLIs affected will be those using unrestrained multiple values and subcommands where the +subcommand name can coincide with one of the multiple values. + +See the commit [0c223f54](https://github.com/kbknapp/clap-rs/commit/0c223f54ed46da406bc8b43a5806e0b227863b31) for full details. + + +#### Bug Fixes + +* Values from global args are now propagated UP and DOWN! +* fixes a bug where using AppSettings::AllowHyphenValues would allow invalid arguments even when there is no way for them to be valid ([77ed4684](https://github.com/kbknapp/clap-rs/commit/77ed46841fc0263d7aa32fcc5cc49ef703b37c04), closes [#1066](https://github.com/kbknapp/clap-rs/issues/1066)) +* when an argument requires a value and that value happens to match a subcommand name, its parsed as a value ([0c223f54](https://github.com/kbknapp/clap-rs/commit/0c223f54ed46da406bc8b43a5806e0b227863b31), closes [#1031](https://github.com/kbknapp/clap-rs/issues/1031), breaks [#](https://github.com/kbknapp/clap-rs/issues/), [#](https://github.com/kbknapp/clap-rs/issues/)) +* fixes a bug that prevented number_of_values and default_values to be used together ([5eb342a9](https://github.com/kbknapp/clap-rs/commit/5eb342a99dde07b0f011048efde3e283bc1110fc), closes [#1050](https://github.com/kbknapp/clap-rs/issues/1050), [#1056](https://github.com/kbknapp/clap-rs/issues/1056)) +* fixes a bug that didn't allow args with default values to have conflicts ([58b5b4be](https://github.com/kbknapp/clap-rs/commit/58b5b4be315280888d50d9b15119b91a9028f050), closes [#1071](https://github.com/kbknapp/clap-rs/issues/1071)) +* fixes a panic when using global args and calling App::get_matches_from_safe_borrow multiple times ([d86ec797](https://github.com/kbknapp/clap-rs/commit/d86ec79742c77eb3f663fb30e225954515cf25bb), closes [#1076](https://github.com/kbknapp/clap-rs/issues/1076)) +* fixes issues and potential regressions with global args values not being propagated properly or at all ([a43f9dd4](https://github.com/kbknapp/clap-rs/commit/a43f9dd4aaf1864dd14a3c28dec89ccdd70c61e5), closes [#1010](https://github.com/kbknapp/clap-rs/issues/1010), [#1061](https://github.com/kbknapp/clap-rs/issues/1061), [#978](https://github.com/kbknapp/clap-rs/issues/978)) +* fixes a bug where default values are not applied if the option supports zero values ([9c248cbf](https://github.com/kbknapp/clap-rs/commit/9c248cbf7d8a825119bc387c23e9a1d1989682b0), closes [#1047](https://github.com/kbknapp/clap-rs/issues/1047)) + +#### Documentation + +* adds addtional blurbs about using multiples with subcommands ([03455b77](https://github.com/kbknapp/clap-rs/commit/03455b7751a757e7b2f6ffaf2d16168539c99661)) +* updates the docs to reflect changes to global args and that global args values can now be propagated back up the stack ([ead076f0](https://github.com/kbknapp/clap-rs/commit/ead076f03ada4c322bf3e34203925561ec496d87)) +* add html_root_url attribute ([e67a061b](https://github.com/kbknapp/clap-rs/commit/e67a061bcf567c6518d6c2f58852e01f02764b22)) +* sync README version numbers with crate version ([5536361b](https://github.com/kbknapp/clap-rs/commit/5536361bcda29887ed86bb68e43d0b603cbc423f)) + +#### Improvements + +* args that have require_delimiter(true) is now reflected in help and usage strings ([dce61699](https://github.com/kbknapp/clap-rs/commit/dce616998ed9bd95e8ed3bec1f09a4883da47b85), closes [#1052](https://github.com/kbknapp/clap-rs/issues/1052)) +* if all subcommands are hidden, the subcommands section of the help message is no longer displayed ([4ae7b046](https://github.com/kbknapp/clap-rs/commit/4ae7b0464750bc07ec80ece38e43f003fdd1b8ae), closes [#1046](https://github.com/kbknapp/clap-rs/issues/1046)) + +#### Breaking Changes + +* when an argument requires a value and that value happens to match a subcommand name, its parsed as a value ([0c223f54](https://github.com/kbknapp/clap-rs/commit/0c223f54ed46da406bc8b43a5806e0b227863b31), closes [#1031](https://github.com/kbknapp/clap-rs/issues/1031), breaks [#](https://github.com/kbknapp/clap-rs/issues/), [#](https://github.com/kbknapp/clap-rs/issues/)) + +#### Deprecations + +* **AppSettings::PropagateGlobalValuesDown:** this setting is no longer required to propagate values down or up ([2bb5ddce](https://github.com/kbknapp/clap-rs/commit/2bb5ddcee61c791ca1aaca494fbeb4bd5e277488)) + + + + +### v2.26.2 (2017-09-14) + + +#### Improvements + +* if all subcommands are hidden, the subcommands section of the help message is no longer displayed ([4ae7b046](https://github.com/kbknapp/clap-rs/commit/4ae7b0464750bc07ec80ece38e43f003fdd1b8ae), closes [#1046](https://github.com/kbknapp/clap-rs/issues/1046)) + +#### Bug Fixes + +* fixes a bug where default values are not applied if the option supports zero values ([9c248cbf](https://github.com/kbknapp/clap-rs/commit/9c248cbf7d8a825119bc387c23e9a1d1989682b0), closes [#1047](https://github.com/kbknapp/clap-rs/issues/1047)) + + + + +### v2.26.1 (2017-09-14) + + +#### Bug Fixes + +* fixes using require_equals(true) and min_values(0) together ([10ae208f](https://github.com/kbknapp/clap-rs/commit/10ae208f68518eff6e98166724065745f4083174), closes [#1044](https://github.com/kbknapp/clap-rs/issues/1044)) +* escape special characters in zsh and fish completions ([87e019fc](https://github.com/kbknapp/clap-rs/commit/87e019fc84ba6193a8c4ddc26c61eb99efffcd25)) +* avoid panic generating default help msg if term width set to 0 due to bug in textwrap 0.7.0 ([b3eadb0d](https://github.com/kbknapp/clap-rs/commit/b3eadb0de516106db4e08f078ad32e8f6d6e7a57)) +* Change `who's` -> `whose` ([53c1ffe8](https://github.com/kbknapp/clap-rs/commit/53c1ffe87f38b05d8804a0f7832412a952845349)) +* adds a debug assertion to ensure all args added to groups actually exist ([7ad123e2](https://github.com/kbknapp/clap-rs/commit/7ad123e2c02577e3ca30f7e205181e896b157d11), closes [#917](https://github.com/kbknapp/clap-rs/issues/917)) +* fixes a bug where args that allow values to start with a hyphen couldnt contain a double hyphen -- as a value ([ab2f4c9e](https://github.com/kbknapp/clap-rs/commit/ab2f4c9e563e36ec739a4b55d5a5b76fdb9e9fa4), closes [#960](https://github.com/kbknapp/clap-rs/issues/960)) +* fixes a bug where positional argument help text is misaligned ([54c16836](https://github.com/kbknapp/clap-rs/commit/54c16836dea4651806a2cfad53146a83fa3abf21)) +* **Help Message:** fixes long_about not being usable ([a8257ea0](https://github.com/kbknapp/clap-rs/commit/a8257ea0ffb812e552aca256c4a3d2aebfd8065b), closes [#1043](https://github.com/kbknapp/clap-rs/issues/1043)) +* **Suggestions:** output for flag after subcommand ([434ea5ba](https://github.com/kbknapp/clap-rs/commit/434ea5ba71395d8c1afcf88e69f0b0d8339b01a1)) + + + + +## v2.26.0 (2017-07-29) + +Minimum version of Rust is now v1.13.0 (Stable) + + +#### Improvements + +* bumps unicode-segmentation to v1.2 ([cd7b40a2](https://github.com/kbknapp/clap-rs/commit/cd7b40a21c77bae17ba453c5512cb82b7d1ce474)) + + +#### Performance + +* update textwrap to version 0.7.0 ([c2d4e637](https://github.com/kbknapp/clap-rs/commit/c2d4e63756a6f070e38c16dff846e9b0a53d6f93)) + + + + + +### v2.25.1 (2017-07-21) + +#### Improvements + +* impl Default for Values + OsValues for any lifetime. ([fb7d6231f1](https://github.com/kbknapp/clap-rs/commit/fb7d6231f13a2f79f411e62dca210b7dc9994c18)) + +#### Documentation + +* Various documentation typos and grammar fixes + + +### v2.25.0 (2017-06-20) + + +#### Features + +* use textwrap crate for wrapping help texts ([b93870c1](https://github.com/kbknapp/clap-rs/commit/b93870c10ae3bd90d233c586a33e086803117285)) + +#### Improvements + +* **Suggestions:** suggests to use flag after subcommand when applicable ([2671ca72](https://github.com/kbknapp/clap-rs/commit/2671ca7260119d4311d21c4075466aafdd9da734)) +* Bumps bitflags crate to v0.9 + +#### Documentation + +* Change `who's` -> `whose` ([53c1ffe8](https://github.com/kbknapp/clap-rs/commit/53c1ffe87f38b05d8804a0f7832412a952845349)) + +#### Documentation + +* **App::template:** adds details about the necessity to use AppSettings::UnifiedHelpMessage when using {unified} tags in the help template ([cbea3d5a](https://github.com/kbknapp/clap-rs/commit/cbea3d5acf3271a7a734498c4d99c709941c331e), closes [#949](https://github.com/kbknapp/clap-rs/issues/949)) +* **Arg::allow_hyphen_values:** updates the docs to include warnings for allow_hyphen_values and multiple(true) used together ([f9b0d657](https://github.com/kbknapp/clap-rs/commit/f9b0d657835d3f517f313d70962177dc30acf4a7)) +* **README.md:** + * added a warning about using ~ deps ([821929b5](https://github.com/kbknapp/clap-rs/commit/821929b51bd60213955705900a436c9a64fcb79f), closes [#964](https://github.com/kbknapp/clap-rs/issues/964)) +* **clap_app!:** adds using the @group specifier to the macro docs ([826048cb](https://github.com/kbknapp/clap-rs/commit/826048cb3cbc0280169303f1498ff0a2b7395883), closes [#932](https://github.com/kbknapp/clap-rs/issues/932)) + + + + +### v2.24.2 (2017-05-15) + + +#### Bug Fixes + +* adds a debug assertion to ensure all args added to groups actually exist ([14f6b8f3](https://github.com/kbknapp/clap-rs/commit/14f6b8f3a2f6df73aeeec9c54a54909b1acfc158), closes [#917](https://github.com/kbknapp/clap-rs/issues/917)) +* fixes a bug where args that allow values to start with a hyphen couldnt contain a double hyphen -- as a value ([ebf73a09](https://github.com/kbknapp/clap-rs/commit/ebf73a09db6f3c03c19cdd76b1ba6113930e1643), closes [#960](https://github.com/kbknapp/clap-rs/issues/960)) +* fixes a bug where positional argument help text is misaligned ([54c16836](https://github.com/kbknapp/clap-rs/commit/54c16836dea4651806a2cfad53146a83fa3abf21)) + +#### Documentation + +* **App::template:** adds details about the necessity to use AppSettings::UnifiedHelpMessage when using {unified} tags in the help template ([cf569438](https://github.com/kbknapp/clap-rs/commit/cf569438f309c199800bb8e46c9f140187de69d7), closes [#949](https://github.com/kbknapp/clap-rs/issues/949)) +* **Arg::allow_hyphen_values:** updates the docs to include warnings for allow_hyphen_values and multiple(true) used together ([ded5a2f1](https://github.com/kbknapp/clap-rs/commit/ded5a2f15474d4a5bd46a67b130ccb8b6781bd01)) +* **clap_app!:** adds using the @group specifier to the macro docs ([fe85fcb1](https://github.com/kbknapp/clap-rs/commit/fe85fcb1772b61f13b20b7ea5290e2437a76190c), closes [#932](https://github.com/kbknapp/clap-rs/issues/932)) + + + + +### v2.24.0 (2017-05-07) + + +#### Bug Fixes + +* fixes a bug where args with last(true) and required(true) set were not being printed in the usage string ([3ac533fe](https://github.com/kbknapp/clap-rs/commit/3ac533fedabf713943eedf006f830a5a486bbe80), closes [#944](https://github.com/kbknapp/clap-rs/issues/944)) +* fixes a bug that was printing the arg name, instead of value name when Arg::last(true) was used ([e1fe8ac3](https://github.com/kbknapp/clap-rs/commit/e1fe8ac3bc1f9cf4e36df0d881f8419755f1787b), closes [#940](https://github.com/kbknapp/clap-rs/issues/940)) +* fixes a bug where flags were parsed as flags AND positional values when specific combinations of settings were used ([20f83292](https://github.com/kbknapp/clap-rs/commit/20f83292d070038b8cee2a6b47e91f6b0a2f7871), closes [#946](https://github.com/kbknapp/clap-rs/issues/946)) + + + + +## v2.24.0 (2017-05-05) + + +#### Documentation + +* **README.md:** fix some typos ([fa34deac](https://github.com/kbknapp/clap-rs/commit/fa34deac079f334c3af97bb7fb151880ba8887f8)) + +#### API Additions + +* **Arg:** add `default_value_os` ([d5ef8955](https://github.com/kbknapp/clap-rs/commit/d5ef8955414b1587060f7218385256105b639c88)) +* **arg_matches.rs:** Added a Default implementation for Values and OsValues iterators. ([0a4384e3](https://github.com/kbknapp/clap-rs/commit/0a4384e350eed74c2a4dc8964c203f21ac64897f)) + + + +### v2.23.2 (2017-04-19) + + +#### Bug Fixes + +* **PowerShell Completions:** fixes a bug where powershells completions cant be used if no subcommands are defined ([a8bce558](https://github.com/kbknapp/clap-rs/commit/a8bce55837dc4e0fb187dc93180884a40ae09c6f), closes [#931](https://github.com/kbknapp/clap-rs/issues/931)) + +#### Improvements + +* bumps term_size to take advantage of better terminal dimension handling ([e05100b7](https://github.com/kbknapp/clap-rs/commit/e05100b73d74066a90876bf38f952adf5e8ee422)) +* **PowerShell Completions:** massively dedups subcommand names in the generate script to make smaller scripts that are still functionally equiv ([85b0e1cc](https://github.com/kbknapp/clap-rs/commit/85b0e1cc4b9755dda75a93d898d79bc38631552b)) + +#### Documentation + +* Fix a typo the minimum rust version required ([71dabba3](https://github.com/kbknapp/clap-rs/commit/71dabba3ea0a17c88b0e2199c9d99f0acbf3bc17)) + + +### v2.23.1 (2017-04-05) + + +#### Bug Fixes + +* fixes a missing newline character in the autogenerated help and version messages in some instances ([5ae9007d](https://github.com/kbknapp/clap-rs/commit/5ae9007d984ae94ae2752df51bcbaeb0ec89bc15)) + + + +## v2.23.0 (2017-04-05) + + +#### API Additions + +* `App::long_about` +* `App::long_version` +* `App::print_long_help` +* `App::write_long_help` +* `App::print_long_version` +* `App::write_long_version` +* `Arg::long_help` + +#### Features + +* allows distinguishing between short and long version messages (-V/short or --version/long) ([59272b06](https://github.com/kbknapp/clap-rs/commit/59272b06cc213289dc604dbc694cb95d383a5d68)) +* allows distinguishing between short and long help with subcommands in the same manner as args ([6b371891](https://github.com/kbknapp/clap-rs/commit/6b371891a1702173a849d1e95f9fecb168bf6fc4)) +* allows specifying a short help vs a long help (i.e. varying levels of detail depending on if -h or --help was used) ([ef1b24c3](https://github.com/kbknapp/clap-rs/commit/ef1b24c3a0dff2f58c5e2e90880fbc2b69df20ee)) +* **clap_app!:** adds support for arg names with hyphens similar to longs with hyphens ([f7a88779](https://github.com/kbknapp/clap-rs/commit/f7a8877978c8f90e6543d4f0d9600c086cf92cd7), closes [#869](https://github.com/kbknapp/clap-rs/issues/869)) + +#### Bug Fixes + +* fixes a bug that wasn't allowing help and version to be properly overridden ([8b2ceb83](https://github.com/kbknapp/clap-rs/commit/8b2ceb8368bcb70689fadf1c7f4b9549184926c1), closes [#922](https://github.com/kbknapp/clap-rs/issues/922)) + +#### Documentation + +* **clap_app!:** documents the `--("some-arg")` method for using args with hyphens inside them ([bc08ef3e](https://github.com/kbknapp/clap-rs/commit/bc08ef3e185393073d969d301989b6319c616c1f), closes [#919](https://github.com/kbknapp/clap-rs/issues/919)) + + + + +### v2.22.2 (2017-03-30) + + +#### Bug Fixes + +* **Custom Usage Strings:** fixes the usage string regression when using help templates ([0e4fd96d](https://github.com/kbknapp/clap-rs/commit/0e4fd96d74280d306d09e60ac44f938a82321769)) + + + + +### v2.22.1 (2017-03-24) + + +#### Bug Fixes + +* **usage:** fixes a big regression with custom usage strings ([2c41caba](https://github.com/kbknapp/clap-rs/commit/2c41caba3c7d723a2894e315d04da796b0e97759)) + + +## v2.22.0 (2017-03-23) + +#### API Additions + +* **App::name:** adds the ability to change the name of the App instance after creation ([d49e8292](https://github.com/kbknapp/clap-rs/commit/d49e8292b026b06e2b70447cd9f08299f4fcba76), closes [#908](https://github.com/kbknapp/clap-rs/issues/908)) +* **Arg::hide_default_value:** adds ability to hide the default value of an argument from the help string ([89e6ea86](https://github.com/kbknapp/clap-rs/commit/89e6ea861e16a1ad56757ca12f6b32d02253e44a), closes [#902](https://github.com/kbknapp/clap-rs/issues/902)) + + + +### v2.21.3 (2017-03-23) + +#### Bug Fixes + +* **yaml:** adds support for loading author info from yaml ([e04c390c](https://github.com/kbknapp/clap-rs/commit/e04c390c597a55fa27e724050342f16c42f1c5c9)) + + + +### v2.21.2 (2017-03-17) + + +#### Improvements + +* add fish subcommand help support ([f8f68cf8](https://github.com/kbknapp/clap-rs/commit/f8f68cf8251669aef4539a25a7c1166f0ac81ea6)) +* options that use `require_equals(true)` now display the equals sign in help messages, usage strings, and errors" ([c8eb0384](https://github.com/kbknapp/clap-rs/commit/c8eb0384d394d2900ccdc1593099c97808a3fa05), closes [#903](https://github.com/kbknapp/clap-rs/issues/903)) + + +#### Bug Fixes + +* setting the max term width now correctly propagates down through child subcommands + + + + +### v2.21.1 (2017-03-12) + + +#### Bug Fixes + +* **ArgRequiredElseHelp:** fixes the precedence of this error to prioritize over other error messages ([74b751ff](https://github.com/kbknapp/clap-rs/commit/74b751ff2e3631e337b7946347c1119829a41c53), closes [#895](https://github.com/kbknapp/clap-rs/issues/895)) +* **Positionals:** fixes some regression bugs resulting from old asserts in debug mode. ([9a3bc98e](https://github.com/kbknapp/clap-rs/commit/9a3bc98e9b55e7514b74b73374c5ac8b6e5e0508), closes [#896](https://github.com/kbknapp/clap-rs/issues/896)) + + + + +## v2.21.0 (2017-03-09) + +#### Performance + +* doesn't run `arg_post_processing` on multiple values anymore ([ec516182](https://github.com/kbknapp/clap-rs/commit/ec5161828729f6a53f0fccec8648f71697f01f78)) +* changes internal use of `VecMap` to `Vec` for matched values of `Arg`s ([22bf137a](https://github.com/kbknapp/clap-rs/commit/22bf137ac581684c6ed460d2c3c640c503d62621)) +* vastly reduces the amount of cloning when adding non-global args minus when they're added from `App::args` which is forced to clone ([8da0303b](https://github.com/kbknapp/clap-rs/commit/8da0303bc02db5fe047cfc0631a9da41d9dc60f7)) +* refactor to remove unneeded vectors and allocations and checks for significant performance increases ([0efa4119](https://github.com/kbknapp/clap-rs/commit/0efa4119632f134fc5b8b9695b007dd94b76735d)) + +#### Documentation + +* Fix examples link in CONTRIBUTING.md ([60cf875d](https://github.com/kbknapp/clap-rs/commit/60cf875d67a252e19bb85054be57696fac2c57a1)) + +#### Improvements + +* when `AppSettings::SubcommandsNegateReqs` and `ArgsNegateSubcommands` are used, a new more accurate double line usage string is shown ([50f02300](https://github.com/kbknapp/clap-rs/commit/50f02300d81788817acefef0697e157e01b6ca32), closes [#871](https://github.com/kbknapp/clap-rs/issues/871)) + +#### API Additions + +* **Arg::last:** adds the ability to mark a positional argument as 'last' which means it should be used with `--` syntax and can be accessed early ([6a7aea90](https://github.com/kbknapp/clap-rs/commit/6a7aea9043b83badd9ab038b4ecc4c787716147e), closes [#888](https://github.com/kbknapp/clap-rs/issues/888)) +* provides `default_value_os` and `default_value_if[s]_os` ([0f2a3782](https://github.com/kbknapp/clap-rs/commit/0f2a378219a6930748d178ba350fe5925be5dad5), closes [#849](https://github.com/kbknapp/clap-rs/issues/849)) +* provides `App::help_message` and `App::version_message` which allows one to override the auto-generated help/version flag associated help ([389c413](https://github.com/kbknapp/clap-rs/commit/389c413b7023dccab8c76aa00577ea1d048e7a99), closes [#889](https://github.com/kbknapp/clap-rs/issues/889)) + +#### New Settings + +* **InferSubcommands:** adds a setting to allow one to infer shortened subcommands or aliases (i.e. for subcommmand "test", "t", "te", or "tes" would be allowed assuming no other ambiguities) ([11602032](https://github.com/kbknapp/clap-rs/commit/11602032f6ff05881e3adf130356e37d5e66e8f9), closes [#863](https://github.com/kbknapp/clap-rs/issues/863)) + +#### Bug Fixes + +* doesn't print the argument sections in the help message if all args in that section are hidden ([ce5ee5f5](https://github.com/kbknapp/clap-rs/commit/ce5ee5f5a76f838104aeddd01c8ec956dd347f50)) +* doesn't include the various [ARGS] [FLAGS] or [OPTIONS] if the only ones available are hidden ([7b4000af](https://github.com/kbknapp/clap-rs/commit/7b4000af97637703645c5fb2ac8bb65bd546b95b), closes [#882](https://github.com/kbknapp/clap-rs/issues/882)) +* now correctly shows subcommand as required in the usage string when AppSettings::SubcommandRequiredElseHelp is used ([8f0884c1](https://github.com/kbknapp/clap-rs/commit/8f0884c1764983a49b45de52a1eddf8d721564d8)) +* fixes some memory leaks when an error is detected and clap exits ([8c2dd287](https://github.com/kbknapp/clap-rs/commit/8c2dd28718262ace4ae0db98563809548e02a86b)) +* fixes a trait that's marked private accidentlly, but should be crate internal public ([1ae21108](https://github.com/kbknapp/clap-rs/commit/1ae21108015cea87e5360402e1747025116c7878)) +* **Completions:** fixes a bug that tried to propogate global args multiple times when generating multiple completion scripts ([5e9b9cf4](https://github.com/kbknapp/clap-rs/commit/5e9b9cf4dd80fa66a624374fd04e6545635c1f94), closes [#846](https://github.com/kbknapp/clap-rs/issues/846)) + +#### Features + +* **Options:** adds the ability to require the equals syntax with options --opt=val ([f002693d](https://github.com/kbknapp/clap-rs/commit/f002693dec6a6959c4e9590cb7b7bfffd6d6e5bc), closes [#833](https://github.com/kbknapp/clap-rs/issues/833)) + + + + +### v2.20.5 (2017-02-18) + + +#### Bug Fixes + +* **clap_app!:** fixes a critical bug of a missing fragment specifier when using `!property` style tags. ([5635c1f94](https://github.com/kbknapp/clap-rs/commit/5e9b9cf4dd80fa66a624374fd04e6545635c1f94)) + + + +### v2.20.4 (2017-02-15) + + +#### Bug Fixes + +* **Completions:** fixes a bug that tried to propogate global args multiple times when generating multiple completion scripts ([5e9b9cf4](https://github.com/kbknapp/clap-rs/commit/5e9b9cf4dd80fa66a624374fd04e6545635c1f94), closes [#846](https://github.com/kbknapp/clap-rs/issues/846)) + +#### Documentation + +* Fix examples link in CONTRIBUTING.md ([60cf875d](https://github.com/kbknapp/clap-rs/commit/60cf875d67a252e19bb85054be57696fac2c57a1)) + + + +### v2.20.3 (2017-02-03) + + +#### Documentation + +* **Macros:** adds a warning about changing values in Cargo.toml not triggering a rebuild automatically ([112aea3e](https://github.com/kbknapp/clap-rs/commit/112aea3e42ae9e0c0a2d33ebad89496dbdd95e5d), closes [#838](https://github.com/kbknapp/clap-rs/issues/838)) + +#### Bug Fixes + +* fixes a println->debugln typo ([279aa62e](https://github.com/kbknapp/clap-rs/commit/279aa62eaf08f56ce090ba16b937bc763cbb45be)) +* fixes bash completions for commands that have an underscore in the name ([7f5cfa72](https://github.com/kbknapp/clap-rs/commit/7f5cfa724f0ac4e098f5fe466c903febddb2d994), closes [#581](https://github.com/kbknapp/clap-rs/issues/581)) +* fixes a bug where ZSH completions would panic if the binary name had an underscore in it ([891a2a00](https://github.com/kbknapp/clap-rs/commit/891a2a006f775e92c556dda48bb32fac9807c4fb), closes [#581](https://github.com/kbknapp/clap-rs/issues/581)) +* allow final word to be wrapped in wrap_help ([564c5f0f](https://github.com/kbknapp/clap-rs/commit/564c5f0f1730f4a2c1cdd128664f1a981c31dcd4), closes [#828](https://github.com/kbknapp/clap-rs/issues/828)) +* fixes a bug where global args weren't included in the generated completion scripts ([9a1e006e](https://github.com/kbknapp/clap-rs/commit/9a1e006eb75ad5a6057ebd119aa90f7e06c0ace8), closes [#841](https://github.com/kbknapp/clap-rs/issues/841)) + + + + +### v2.20.2 (2017-02-03) + +#### Bug Fixes + +* fixes a critical bug where subcommand settings were being propogated too far ([74648c94](https://github.com/kbknapp/clap-rs/commit/74648c94b893df542bfa5bb595e68c7bb8167e36), closes [#832](https://github.com/kbknapp/clap-rs/issues/832)) + + +#### Improvements + +* adds ArgGroup::multiple to the supported YAML fields for building ArgGroups from YAML ([d8590037](https://github.com/kbknapp/clap-rs/commit/d8590037ce07dafd8cd5b26928aa4a9fd3018288), closes [#840](https://github.com/kbknapp/clap-rs/issues/840)) + + +### v2.20.1 (2017-01-31) + +#### Bug Fixes + +* allow final word to be wrapped in wrap_help ([564c5f0f](https://github.com/kbknapp/clap-rs/commit/564c5f0f1730f4a2c1cdd128664f1a981c31dcd4), closes [#828](https://github.com/kbknapp/clap-rs/issues/828)) +* actually show character in debug output ([84d8c547](https://github.com/kbknapp/clap-rs/commit/84d8c5476de95b7f37d61888bc4f13688b712434)) +* include final character in line lenght ([aff4ba18](https://github.com/kbknapp/clap-rs/commit/aff4ba18da8147e1259b04b0bfbc1fcb5c78a3c0)) + +#### Improvements + +* updates libc and term_size deps for the libc version conflict ([6802ac4a](https://github.com/kbknapp/clap-rs/commit/6802ac4a59c142cda9ec55ca0c45ae5cb9a6ab55)) + +#### Documentation + +* fix link from app_from_crate! to crate_authors! (#822) ([5b29be9b](https://github.com/kbknapp/clap-rs/commit/5b29be9b073330ab1f7227cdd19fe4aab39d5dcb)) +* fix spelling of "guaranteed" ([4f30a65b](https://github.com/kbknapp/clap-rs/commit/4f30a65b9c03eb09607eb91a929a6396637dc105)) + + + +#### New Settings + +* **ArgsNegateSubcommands:** disables args being allowed between subcommands ([5e2af8c9](https://github.com/kbknapp/clap-rs/commit/5e2af8c96adb5ab75fa2d1536237ebcb41869494), closes [#793](https://github.com/kbknapp/clap-rs/issues/793)) +* **DontCollapseArgsInUsage:** disables the collapsing of positional args into `[ARGS]` in the usage string ([c2978afc](https://github.com/kbknapp/clap-rs/commit/c2978afc61fb46d5263ab3b2d87ecde1c9ce1553), closes [#769](https://github.com/kbknapp/clap-rs/issues/769)) +* **DisableHelpSubcommand:** disables building the `help` subcommand ([a10fc859](https://github.com/kbknapp/clap-rs/commit/a10fc859ee20159fbd9ff4337be59b76467a64f2)) +* **AllowMissingPositional:** allows one to implement `$ prog [optional] ` style CLIs where the second postional argument is required, but the first is optional ([1110fdc7](https://github.com/kbknapp/clap-rs/commit/1110fdc7a345c108820dc45783a9bf893fa4c214), closes [#636](https://github.com/kbknapp/clap-rs/issues/636)) +* **PropagateGlobalValuesDown:** automatically propagats global arg's values down through *used* subcommands ([985536c8](https://github.com/kbknapp/clap-rs/commit/985536c8ebcc09af98aac835f42a8072ad58c262), closes [#694](https://github.com/kbknapp/clap-rs/issues/694)) + +#### API Additions + +##### Arg + +* **Arg::value_terminator:** adds the ability to terminate multiple values with a given string or char ([be64ce0c](https://github.com/kbknapp/clap-rs/commit/be64ce0c373efc106384baca3f487ea99fe7b8cf), closes [#782](https://github.com/kbknapp/clap-rs/issues/782)) +* **Arg::default_value_if[s]:** adds new methods for *conditional* default values (such as a particular value from another argument was used) ([eb4010e7](https://github.com/kbknapp/clap-rs/commit/eb4010e7b21724447ef837db11ac441915728f22)) +* **Arg::requires_if[s]:** adds the ability to *conditionally* require additional args (such as if a particular value was used) ([198449d6](https://github.com/kbknapp/clap-rs/commit/198449d64393c265f0bc327aaeac23ec4bb97226)) +* **Arg::required_if[s]:** adds the ability for an arg to be *conditionally* required (i.e. "arg X is only required if arg Y was used with value Z") ([ee9cfddf](https://github.com/kbknapp/clap-rs/commit/ee9cfddf345a6b5ae2af42ba72aa5c89e2ca7f59)) +* **Arg::validator_os:** adds ability to validate values which may contain invalid UTF-8 ([47232498](https://github.com/kbknapp/clap-rs/commit/47232498a813db4f3366ccd3e9faf0bff56433a4)) + +##### Macros + +* **crate_description!:** Uses the `Cargo.toml` description field to fill in the `App::about` method at compile time ([4d9a82db](https://github.com/kbknapp/clap-rs/commit/4d9a82db8e875e9b64a9c2a5c6e22c25afc1279d), closes [#778](https://github.com/kbknapp/clap-rs/issues/778)) +* **crate_name!:** Uses the `Cargo.toml` name field to fill in the `App::new` method at compile time ([4d9a82db](https://github.com/kbknapp/clap-rs/commit/4d9a82db8e875e9b64a9c2a5c6e22c25afc1279d), closes [#778](https://github.com/kbknapp/clap-rs/issues/778)) +* **app_from_crate!:** Combines `crate_version!`, `crate_name!`, `crate_description!`, and `crate_authors!` into a single macro call to build a default `App` instance from the `Cargo.toml` fields ([4d9a82db](https://github.com/kbknapp/clap-rs/commit/4d9a82db8e875e9b64a9c2a5c6e22c25afc1279d), closes [#778](https://github.com/kbknapp/clap-rs/issues/778)) + + +#### Features + +* **no_cargo:** adds a `no_cargo` feature to disable Cargo-env-var-dependent macros for those *not* using `cargo` to build their crates (#786) ([6fdd2f9d](https://github.com/kbknapp/clap-rs/commit/6fdd2f9d693aaf1118fc61bd362273950703f43d)) + +#### Bug Fixes + +* **Options:** fixes a critical bug where options weren't forced to have a value ([5a5f2b1e](https://github.com/kbknapp/clap-rs/commit/5a5f2b1e9f598a0d0280ef3e98abbbba2bc41132), closes [#665](https://github.com/kbknapp/clap-rs/issues/665)) +* fixes a bug where calling the help of a subcommand wasn't ignoring required args of parent commands ([d3d34a2b](https://github.com/kbknapp/clap-rs/commit/d3d34a2b51ef31004055b0ab574f766d801c3adf), closes [#789](https://github.com/kbknapp/clap-rs/issues/789)) +* **Help Subcommand:** fixes a bug where the help subcommand couldn't be overriden ([d34ec3e0](https://github.com/kbknapp/clap-rs/commit/d34ec3e032d03e402d8e87af9b2942fe2819b2da), closes [#787](https://github.com/kbknapp/clap-rs/issues/787)) +* **Low Index Multiples:** fixes a bug which caused combinations of LowIndexMultiples and `Arg::allow_hyphen_values` to fail parsing ([26c670ca](https://github.com/kbknapp/clap-rs/commit/26c670ca16d2c80dc26d5c1ce83380ace6357318)) + +#### Improvements + +* **Default Values:** improves the error message when default values are involved ([1f33de54](https://github.com/kbknapp/clap-rs/commit/1f33de545036e7fd2f80faba251fca009bd519b8), closes [#774](https://github.com/kbknapp/clap-rs/issues/774)) +* **YAML:** adds conditional requirements and conditional default values to YAML ([9a4df327](https://github.com/kbknapp/clap-rs/commit/9a4df327893486adb5558ffefba790c634ccdc6e), closes [#764](https://github.com/kbknapp/clap-rs/issues/764)) +* Support `--("some-arg-name")` syntax for defining long arg names when using `clap_app!` macro ([f41ec962](https://github.com/kbknapp/clap-rs/commit/f41ec962c243a5ffff8b1be1ae2ad63970d3d1d4)) +* Support `("some app name")` syntax for defining app names when using `clap_app!` macro ([9895b671](https://github.com/kbknapp/clap-rs/commit/9895b671cff784f35cf56abcd8270f7c2ba09699), closes [#759](https://github.com/kbknapp/clap-rs/issues/759)) +* **Help Wrapping:** long app names (with spaces), authors, and descriptions are now wrapped appropriately ([ad4691b7](https://github.com/kbknapp/clap-rs/commit/ad4691b71a63e951ace346318238d8834e04ad8a), closes [#777](https://github.com/kbknapp/clap-rs/issues/777)) + + +#### Documentation + +* **Conditional Default Values:** fixes the failing doc tests of Arg::default_value_ifs ([4ef09101](https://github.com/kbknapp/clap-rs/commit/4ef091019c083b4db1a0c13f1c1e95ac363259f2)) +* **Conditional Requirements:** adds docs for Arg::requires_ifs ([7f296e29](https://github.com/kbknapp/clap-rs/commit/7f296e29db7d9036e76e5dbcc9c8b20dfe7b25bd)) +* **README.md:** fix some typos ([f22c21b4](https://github.com/kbknapp/clap-rs/commit/f22c21b422d5b287d1a1ac183a379ee02eebf54f)) +* **src/app/mod.rs:** fix some typos ([5c9b0d47](https://github.com/kbknapp/clap-rs/commit/5c9b0d47ca78dea285c5b9dec79063d24c3e451a)) + + +### v2.19.3 (2016-12-28) + + +#### Bug Fixes + +* fixes a bug where calling the help of a subcommand wasn't ignoring required args of parent commands ([a0ee4993](https://github.com/kbknapp/clap-rs/commit/a0ee4993015ea97b06b5bc9f378d8bcb18f1c51c), closes [#789](https://github.com/kbknapp/clap-rs/issues/789)) + + + + +### v2.19.2 (2016-12-08) + +#### Bug Fixes + +* **ZSH Completions:** escapes square brackets in ZSH completions ([7e17d5a3](https://github.com/kbknapp/clap-rs/commit/7e17d5a36b2cc2cc77e7b15796b14d639ed3cbf7), closes [#771](https://github.com/kbknapp/clap-rs/issues/771)) + +#### Documentation + +* **Examples:** adds subcommand examples ([0e0f3354](https://github.com/kbknapp/clap-rs/commit/0e0f33547a6901425afc1d9fbe19f7ae3832d9a4), closes [#766](https://github.com/kbknapp/clap-rs/issues/766)) +* **README.md:** adds guidance on when to use ~ in version pinning, and clarifies breaking change policy ([591eaefc](https://github.com/kbknapp/clap-rs/commit/591eaefc7319142ba921130e502bb0729feed907), closes [#765](https://github.com/kbknapp/clap-rs/issues/765)) + + + + +### v2.19.1 (2016-12-01) + + +#### Bug Fixes + +* **Help Messages:** fixes help message alignment when specific settings are used on options ([cd94b318](https://github.com/kbknapp/clap-rs/commit/cd94b3188d63b63295a319e90e826bca46befcd2), closes [#760](https://github.com/kbknapp/clap-rs/issues/760)) + +#### Improvements + +* **Bash Completion:** allows bash completion to fall back to traidtional bash completion upon no matching completing function ([b1b16d56](https://github.com/kbknapp/clap-rs/commit/b1b16d56d8fddf819bdbe24b3724bb6a9f3fa613))) + + + +## v2.19.0 (2016-11-21) + +#### Features + +* allows specifying AllowLeadingHyphen style values, but only for specific args vice command wide ([c0d70feb](https://github.com/kbknapp/clap-rs/commit/c0d70febad9996a77a54107054daf1914c50d4ef), closes [#742](https://github.com/kbknapp/clap-rs/issues/742)) + +#### Bug Fixes + +* **Required Unless:** fixes a bug where having required_unless set doesn't work when conflicts are also set ([d20331b6](https://github.com/kbknapp/clap-rs/commit/d20331b6f7940ac3a4e919999f8bb4780875125d), closes [#753](https://github.com/kbknapp/clap-rs/issues/753)) +* **ZSH Completions:** fixes an issue where zsh completions caused panics if there were no subcommands ([49e7cdab](https://github.com/kbknapp/clap-rs/commit/49e7cdab76dd1ccc07221e360f07808ec62648aa), closes [#754](https://github.com/kbknapp/clap-rs/issues/754)) + +#### Improvements + +* **Validators:** improves the error messages for validators ([65eb3385](https://github.com/kbknapp/clap-rs/commit/65eb33859d3ff53e7d3277f02a9d3fd9038a9dfb), closes [#744](https://github.com/kbknapp/clap-rs/issues/744)) + +#### Documentation + +* updates the docs landing page ([01e1e33f](https://github.com/kbknapp/clap-rs/commit/01e1e33f377934099a4a725fab5cd6c5ff50eaa2)) +* adds the macro version back to the readme ([45eb9bf1](https://github.com/kbknapp/clap-rs/commit/45eb9bf130329c3f3853aba0342c2fe3c64ff80f)) +* fix broken docs links ([808e7cee](https://github.com/kbknapp/clap-rs/commit/808e7ceeb86d4a319bdc270f51c23a64621dbfb3)) +* **Compatibility Policy:** adds an official compatibility policy to ([760d66dc](https://github.com/kbknapp/clap-rs/commit/760d66dc17310b357f257776624151da933cd25d), closes [#740](https://github.com/kbknapp/clap-rs/issues/740)) +* **Contributing:** updates the readme to improve the readability and contributing sections ([eb51316c](https://github.com/kbknapp/clap-rs/commit/eb51316cdfdc7258d287ba13b67ef2f42bd2b8f6)) + + +## v2.18.0 (2016-11-05) + + +#### Features + +* **Completions:** adds completion support for PowerShell. ([cff82c88](https://github.com/kbknapp/clap-rs/commit/cff82c880e21064fca63351507b80350df6caadf), closes [#729](https://github.com/kbknapp/clap-rs/issues/729)) + + + + +### v2.17.1 (2016-11-02) + + +#### Bug Fixes + +* **Low Index Multiples:** fixes a bug where using low index multiples was propagated to subcommands ([33924e88](https://github.com/kbknapp/clap-rs/commit/33924e884461983c4e6b5ea1330fecc769a4ade7), closes [#725](https://github.com/kbknapp/clap-rs/issues/725)) + + + + +## v2.17.0 (2016-11-01) + + +#### Features + +* **Positional Args:** allows specifying the second to last positional argument as multiple(true) ([1ced2a74](https://github.com/kbknapp/clap-rs/commit/1ced2a7433ea8937a1b260ea65d708f32ca7c95e), closes [#725](https://github.com/kbknapp/clap-rs/issues/725)) + + + + +### v2.16.4 (2016-10-31) + + +#### Improvements + +* **Error Output:** conflicting errors are now symetrical, meaning more consistent and less confusing ([3d37001d](https://github.com/kbknapp/clap-rs/commit/3d37001d1dc647d73cc597ff172f1072d4beb80d), closes [#718](https://github.com/kbknapp/clap-rs/issues/718)) + +#### Documentation + +* Fix typo in example `13a_enum_values_automatic` ([c22fbc07](https://github.com/kbknapp/clap-rs/commit/c22fbc07356e556ffb5d1a79ec04597d149b915e)) +* **README.md:** fixes failing yaml example (#715) ([21fba9e6](https://github.com/kbknapp/clap-rs/commit/21fba9e6cd8c163012999cd0ce271ec8780c5695)) + +#### Bug Fixes + +* **ZSH Completions:** fixes bug that caused panic on subcommands with aliases ([5c70e1a0](https://github.com/kbknapp/clap-rs/commit/5c70e1a01bc977e44c10015d18bb8e215c32dfc8), closes [#714](https://github.com/kbknapp/clap-rs/issues/714)) +* **debug:** fixes the debug feature (#716) ([6c11ccf4](https://github.com/kbknapp/clap-rs/commit/6c11ccf443d46258d51f7cda33fbcc81e7fe8e90)) + + + + +### v2.16.3 (2016-10-28) + + +#### Bug Fixes + +* Derive display order after propagation ([9cb6facf](https://github.com/kbknapp/clap-rs/commit/9cb6facf507aff7cddd124b8c29714d2b0e7bd13), closes [#706](https://github.com/kbknapp/clap-rs/issues/706)) +* **yaml-example:** inconsistent args ([847f7199](https://github.com/kbknapp/clap-rs/commit/847f7199219ead5065561d91d64780d99ae4b587)) + + + + +### v2.16.2 (2016-10-25) + + +#### Bug Fixes + +* **Fish Completions:** fixes a bug where single quotes are not escaped ([780b4a18](https://github.com/kbknapp/clap-rs/commit/780b4a18281b6f7f7071e1b9db2290fae653c406), closes [#704](https://github.com/kbknapp/clap-rs/issues/704)) + + + +### v2.16.1 (2016-10-24) + + +#### Bug Fixes + +* **Help Message:** fixes a regression bug where args with multiple(true) threw off alignment ([ebddac79](https://github.com/kbknapp/clap-rs/commit/ebddac791f3ceac193d5ad833b4b734b9643a7af), closes [#702](https://github.com/kbknapp/clap-rs/issues/702)) + + + + +## v2.16.0 (2016-10-23) + + +#### Features + +* **Completions:** adds ZSH completion support ([3e36b0ba](https://github.com/kbknapp/clap-rs/commit/3e36b0bac491d3f6194aee14604caf7be26b3d56), closes [#699](https://github.com/kbknapp/clap-rs/issues/699)) + + + + +## v2.15.0 (2016-10-21) + + +#### Features + +* **AppSettings:** adds new setting `AppSettings::AllowNegativeNumbers` ([ab064546](https://github.com/kbknapp/clap-rs/commit/ab06454677fb6aa9b9f804644fcca2168b1eaee3), closes [#696](https://github.com/kbknapp/clap-rs/issues/696)) + +#### Documentation + +* **app/settings.rs:** moves variants to roughly alphabetical order ([9ed4d4d7](https://github.com/kbknapp/clap-rs/commit/9ed4d4d7957a23357aef60081e45639ab9e3905f)) + + + +### v2.14.1 (2016-10-20) + + +#### Documentation + +* Improve documentation around features ([4ee85b95](https://github.com/kbknapp/clap-rs/commit/4ee85b95d2d16708a016a3ba4e6e2c93b89b7fad)) +* reword docs for ErrorKind and app::Settings ([3ccde7a4](https://github.com/kbknapp/clap-rs/commit/3ccde7a4b8f7a2ea8b916a5415c04a8ff4b5cb7a)) +* fix tests that fail when the "suggestions" feature is disabled ([996fc381](https://github.com/kbknapp/clap-rs/commit/996fc381763a48d125c7ea8a58fed057fd0b4ac6)) +* fix the OsString-using doc-tests ([af9e1a39](https://github.com/kbknapp/clap-rs/commit/af9e1a393ce6cdda46a03c8a4f48df222b015a24)) +* tag non-rust code blocks as such instead of ignoring them ([0ba9f4b1](https://github.com/kbknapp/clap-rs/commit/0ba9f4b123f281952581b6dec948f7e51dd22890)) +* **ErrorKind:** improve some errors about subcommands ([9f6217a4](https://github.com/kbknapp/clap-rs/commit/9f6217a424da823343d7b801b9c350dee3cd1906)) +* **yaml:** make sure the doc-tests don't fail before "missing file" ([8c0f5551](https://github.com/kbknapp/clap-rs/commit/8c0f55516f4910c78c9f8a2bdbd822729574f95b)) + +#### Improvements + +* Stabilize clap_app! ([cd516006](https://github.com/kbknapp/clap-rs/commit/cd516006e35c37b005f329338560a0a53d1f3e00)) +* **with_defaults:** Deprecate App::with_defaults() ([26085409](https://github.com/kbknapp/clap-rs/commit/2608540940c8bb66e517b65706bc7dea55510682), closes [#638](https://github.com/kbknapp/clap-rs/issues/638)) + +#### Bug Fixes + +* fixes a bug that made determining when to auto-wrap long help messages inconsistent ([468baadb](https://github.com/kbknapp/clap-rs/commit/468baadb8398fc1d37897b0c49374aef4cf97dca), closes [#688](https://github.com/kbknapp/clap-rs/issues/688)) +* **Completions:** fish completions for nested subcommands ([a61eaf8a](https://github.com/kbknapp/clap-rs/commit/a61eaf8aade76cfe90ccc0f7125751ebf60e3254)) +* **features:** Make lints not enable other nightly-requiring features ([835f75e3](https://github.com/kbknapp/clap-rs/commit/835f75e3ba20999117363ed9f916464d777f36ef)) + + + + +## v2.14.0 (2016-10-05) + + +#### Features + +* **arg_aliases:** Ability to alias arguments ([33b5f6ef](https://github.com/kbknapp/clap-rs/commit/33b5f6ef2c9612ecabb31f96b824793e46bfd3dd), closes [#669](https://github.com/kbknapp/clap-rs/issues/669)) +* **flag_aliases:** Ability to alias flags ([40d6dac9](https://github.com/kbknapp/clap-rs/commit/40d6dac973927dded6ab423481634ef47ee7bfd7)) + +#### Bug Fixes + +* **UsageParser:** Handle non-ascii names / options. ([1d6a7c6e](https://github.com/kbknapp/clap-rs/commit/1d6a7c6e7e6aadc527346aa822f19d8587f714f3), closes [#664](https://github.com/kbknapp/clap-rs/issues/664)) + +#### Documentation + +* typo ([bac417fa](https://github.com/kbknapp/clap-rs/commit/bac417fa1cea3d32308334c7cccfcf54546cd9d8)) + + + +## v2.13.0 (2016-09-18) + + +#### Documentation + +* updates README.md with new website information and updated video tutorials info ([0c19c580](https://github.com/kbknapp/clap-rs/commit/0c19c580cf50f1b82ff32f70b36708ae2bcac132)) +* updates the docs about removing implicit value_delimiter(true) ([c81bc722](https://github.com/kbknapp/clap-rs/commit/c81bc722ebb8a86d22be89b5aec98df9fe222a08)) +* **Default Values:** adds better examples on using default values ([57a8d9ab](https://github.com/kbknapp/clap-rs/commit/57a8d9abb2f973c235a8a14f8fc031673d7a7460), closes [#418](https://github.com/kbknapp/clap-rs/issues/418)) + +#### Bug Fixes + +* **Value Delimiters:** fixes the confusion around implicitly setting value delimiters. (default is now `false`) ([09d4d0a9](https://github.com/kbknapp/clap-rs/commit/09d4d0a9038d7ce2df55c2aec95e16f36189fcee), closes [#666](https://github.com/kbknapp/clap-rs/issues/666)) + + + + +### v2.12.1 (2016-09-13) + + +#### Bug Fixes + +* **Help Wrapping:** fixes a regression-bug where the old {n} newline char stopped working ([92ac353b](https://github.com/kbknapp/clap-rs/commit/92ac353b48b7caa2511ad2a046d94da93c236cf6), closes [#661](https://github.com/kbknapp/clap-rs/issues/661)) + + + + +## v2.12.0 (2016-09-13) + + +#### Features + +* **Help:** adds ability to hide the possible values on a per argument basis ([9151ef73](https://github.com/kbknapp/clap-rs/commit/9151ef739871f2e74910c342299c0de196b95dec), closes [#640](https://github.com/kbknapp/clap-rs/issues/640)) +* **help:** allow for limiting detected terminal width ([a43e28af](https://github.com/kbknapp/clap-rs/commit/a43e28af85c9a9deaedd5ef735f4f13008daab29), closes [#653](https://github.com/kbknapp/clap-rs/issues/653)) + +#### Documentation + +* **Help Wrapping:** removes the verbiage about using `'{n}'` to insert newlines in help text ([c5a2b352](https://github.com/kbknapp/clap-rs/commit/c5a2b352ca600f5b802290ad945731066cd53611)) +* **Value Delimiters:** updates the docs for the Arg::multiple method WRT value delimiters and default settings ([f9d17a06](https://github.com/kbknapp/clap-rs/commit/f9d17a060aa53f10d0a6e1a7eed5d989d1a59533)) +* **appsettings:** Document AppSetting::DisableVersion ([94501965](https://github.com/kbknapp/clap-rs/commit/945019654d2ca67eb2b1d6014fdf80b84d528d30), closes [#589](https://github.com/kbknapp/clap-rs/issues/589)) + +#### Bug Fixes + +* **AllowLeadingHyphen:** fixes a bug where valid args aren't recognized with this setting ([a9699e4d](https://github.com/kbknapp/clap-rs/commit/a9699e4d7cdc9a06e73b845933ff1fe6d76f016a), closes [#588](https://github.com/kbknapp/clap-rs/issues/588)) + +#### Improvements + +* **Help Wrapping:** + * clap now ignores hard newlines in help messages and properly re-aligns text, but still wraps if the term width is too small ([c7678523](https://github.com/kbknapp/clap-rs/commit/c76785239fd42adc8ca04f9202b6fec615aa9f14), closes [#617](https://github.com/kbknapp/clap-rs/issues/617)) + * makes some minor changes to when next line help is automatically used ([01cae799](https://github.com/kbknapp/clap-rs/commit/01cae7990a33167ac35103fb36c811b4fe6eb98f)) +* **Value Delimiters:** changes the default value delimiter rules ([f9e69254](https://github.com/kbknapp/clap-rs/commit/f9e692548e8c94de15f909432de301407d6bb834), closes [#655](https://github.com/kbknapp/clap-rs/issues/655)) +* **YAML:** supports setting Arg::require_delimiter from YAML ([b9b55a39](https://github.com/kbknapp/clap-rs/commit/b9b55a39dfebcdbdc05dca2692927e503db50816)) + +#### Performance + +* **help:** fix redundant contains() checks ([a8afed74](https://github.com/kbknapp/clap-rs/commit/a8afed7428bf0733f8e93bb11ad6c00d9e970fcc)) + + + + +### v2.11.3 (2016-09-07) + + +#### Documentation + +* **Help Wrapping:** removes the verbiage about using `'{n}'` to insert newlines in help text ([c5a2b352](https://github.com/kbknapp/clap-rs/commit/c5a2b352ca600f5b802290ad945731066cd53611)) + +#### Improvements + +* **Help Wrapping:** + * clap now ignores hard newlines in help messages and properly re-aligns text, but still wraps if the term width is too small ([c7678523](https://github.com/kbknapp/clap-rs/commit/c76785239fd42adc8ca04f9202b6fec615aa9f14), closes [#617](https://github.com/kbknapp/clap-rs/issues/617)) + * makes some minor changes to when next line help is automatically used ([01cae799](https://github.com/kbknapp/clap-rs/commit/01cae7990a33167ac35103fb36c811b4fe6eb98f)) +* **YAML:** supports setting Arg::require_delimiter from YAML ([b9b55a39](https://github.com/kbknapp/clap-rs/commit/b9b55a39dfebcdbdc05dca2692927e503db50816)) + + + + + +### v2.11.2 (2016-09-06) + +#### Improvements + +* **Help Wrapping:** makes some minor changes to when next line help is automatically used ([5658b117](https://github.com/kbknapp/clap-rs/commit/5658b117aec3e03adff9c8c52a4c4bc1fcb4e1ff)) + + + +### v2.11.1 (2016-09-05) + + +#### Bug Fixes + +* **Settings:** fixes an issue where settings weren't propogated down through grand-child subcommands ([b3efc107](https://github.com/kbknapp/clap-rs/commit/b3efc107515d78517b20798ff3890b8a2b04498e), closes [#638](https://github.com/kbknapp/clap-rs/issues/638)) + +#### Features + +* **Errors:** Errors with custom description ([58512f2f](https://github.com/kbknapp/clap-rs/commit/58512f2fcb430745f1ee6ee8f1c67f62dc216c73)) + +#### Improvements + +* **help:** use term_size instead of home-grown solution ([fc7327e9](https://github.com/kbknapp/clap-rs/commit/fc7327e9dcf4258ef2baebf0a8714d9c0622855b)) + + + + +### v2.11.0 (2016-08-28) + + +#### Bug Fixes + +* **Groups:** fixes some usage strings that contain both args in groups and ones that conflict with each other ([3d782def](https://github.com/kbknapp/clap-rs/commit/3d782def57725e2de26ca5a5bc5cc2e40ddebefb), closes [#616](https://github.com/kbknapp/clap-rs/issues/616)) + +#### Documentation + +* moves docs to docs.rs ([03209d5e](https://github.com/kbknapp/clap-rs/commit/03209d5e1300906f00bafec1869c2047a92e5071), closes [#634](https://github.com/kbknapp/clap-rs/issues/634)) + +#### Improvements + +* **Completions:** uses standard conventions for bash completion files, namely '{bin}.bash-completion' ([27f5bbfb](https://github.com/kbknapp/clap-rs/commit/27f5bbfbcc9474c2f57c2b92b1feb898ae46ee70), closes [#567](https://github.com/kbknapp/clap-rs/issues/567)) +* **Help:** automatically moves help text to the next line and wraps when term width is determined to be too small, or help text is too long ([150964c4](https://github.com/kbknapp/clap-rs/commit/150964c4e7124d54476c9d9b4b3f2406f0fd00e5), closes [#597](https://github.com/kbknapp/clap-rs/issues/597)) +* **YAML Errors:** vastly improves error messages when using YAML ([f43b7c65](https://github.com/kbknapp/clap-rs/commit/f43b7c65941c53adc0616b8646a21dc255862eb2), closes [#574](https://github.com/kbknapp/clap-rs/issues/574)) + +#### Features + +* adds App::with_defaults to automatically use crate_authors! and crate_version! macros ([5520bb01](https://github.com/kbknapp/clap-rs/commit/5520bb012c127dfd299fd55699443c744d8dcd5b), closes [#600](https://github.com/kbknapp/clap-rs/issues/600)) + + + + +### v2.10.4 (2016-08-25) + + +#### Bug Fixes + +* **Help Wrapping:** fixes a bug where help is wrapped incorrectly and causing a panic with some non-English characters ([d0b442c7](https://github.com/kbknapp/clap-rs/commit/d0b442c7beeecac9764406bc3bd171ced0b8825e), closes [#626](https://github.com/kbknapp/clap-rs/issues/626)) + + + + +### v2.10.3 (2016-08-25) + +#### Features + +* **Help:** adds new short hand way to use source formatting and ignore term width in help messages ([7dfdaf20](https://github.com/kbknapp/clap-rs/commit/7dfdaf200ebb5c431351a045b48f5e0f0d3f31db), closes [#625](https://github.com/kbknapp/clap-rs/issues/625)) + +#### Documentation + +* **Term Width:** adds details about set_term_width(0) ([00b8205d](https://github.com/kbknapp/clap-rs/commit/00b8205d22639d1b54b9c453c55c785aace52cb2)) + +#### Bug Fixes + +* **Unicode:** fixes two bugs where non-English characters were stripped or caused a panic with help wrapping ([763a5c92](https://github.com/kbknapp/clap-rs/commit/763a5c920e23efc74d190af0cb8b5dd714b2d67a), closes [#626](https://github.com/kbknapp/clap-rs/issues/626)) + + + + +### v2.10.2 (2016-08-22) + + +#### Bug Fixes + +* fixes a bug where the help is printed twice ([a643fb28](https://github.com/kbknapp/clap-rs/commit/a643fb283acd9905dc727c4579c5c9fa2ceaa7e7), closes [#623](https://github.com/kbknapp/clap-rs/issues/623)) + + + + +### v2.10.1 (2016-08-21) + + +#### Bug Fixes + +* **Help Subcommand:** fixes misleading usage string when using multi-level subcommmands ([e203515e](https://github.com/kbknapp/clap-rs/commit/e203515e3ac495b405dbba4f78fb6af148fd282e), closes [#618](https://github.com/kbknapp/clap-rs/issues/618)) + +#### Features + +* **YAML:** allows using lists or single values with arg declarations ([9ade2cd4](https://github.com/kbknapp/clap-rs/commit/9ade2cd4b268d6d7fe828319ce6a523c641b9c38), closes [#614](https://github.com/kbknapp/clap-rs/issues/614), [#613](https://github.com/kbknapp/clap-rs/issues/613)) + + + + +## v2.10.0 (2016-07-29) + + +#### Features + +* **Completions:** one can generate a basic fish completions script at compile time ([1979d2f2](https://github.com/kbknapp/clap-rs/commit/1979d2f2f3216e57d02a97e624a8a8f6cf867ed9)) + +#### Bug Fixes + +* **parser:** preserve external subcommand name ([875df243](https://github.com/kbknapp/clap-rs/commit/875df24316c266920a073c13bbefbf546bc1f635)) + +#### Breaking Changes + +* **parser:** preserve external subcommand name ([875df243](https://github.com/kbknapp/clap-rs/commit/875df24316c266920a073c13bbefbf546bc1f635)) + +#### Documentation + +* **YAML:** fixes example 17's incorrect reference to arg_groups instead of groups ([b6c99e13](https://github.com/kbknapp/clap-rs/commit/b6c99e1377f918e78c16c8faced70a71607da931), closes [#601](https://github.com/kbknapp/clap-rs/issues/601)) + + + + +### 2.9.3 (2016-07-24) + + +#### Bug Fixes + +* fixes bug where only first arg in list of required_unless_one is recognized ([1fc3b55b](https://github.com/kbknapp/clap-rs/commit/1fc3b55bd6c8653b02e7c4253749c6b77737d2ac), closes [#575](https://github.com/kbknapp/clap-rs/issues/575)) +* **Settings:** fixes typo subcommandsrequired->subcommandrequired ([fc72cdf5](https://github.com/kbknapp/clap-rs/commit/fc72cdf591d30f5d9375d0b5cc2a2ff3e812f9f6), closes [#593](https://github.com/kbknapp/clap-rs/issues/593)) + +#### Features + +* **Completions:** adds the ability to generate completions to io::Write object ([9f62cf73](https://github.com/kbknapp/clap-rs/commit/9f62cf7378ba5acb5ce8c5bac89b4aa60c30755f)) +* **Settings:** Add unset_setting and unset_settings fns to App (#598) ([0ceba231](https://github.com/kbknapp/clap-rs/commit/0ceba231c6767cd6d88fdb1feeeea41deadf77ff), closes [#590](https://github.com/kbknapp/clap-rs/issues/590)) + + + +### 2.9.2 (2016-07-03) + + +#### Documentation + +* **Completions:** fixes the formatting of the Cargo.toml excerpt in the completions example ([722f2607](https://github.com/kbknapp/clap-rs/commit/722f2607beaef56b6a0e433db5fd09492d9f028c)) + +#### Bug Fixes + +* **Completions:** fixes bug where --help and --version short weren't added to the completion list ([e9f2438e](https://github.com/kbknapp/clap-rs/commit/e9f2438e2ce99af0ae570a2eaf541fc7f55b771b), closes [#536](https://github.com/kbknapp/clap-rs/issues/536)) + + + + +### 2.9.1 (2016-07-02) + + +#### Improvements + +* **Completions:** allows multiple completions to be built by namespacing with bin name ([57484b2d](https://github.com/kbknapp/clap-rs/commit/57484b2daeaac01c1026e8c84efc8bf099e0eb31)) + + + +## v2.9.0 (2016-07-01) + + +#### Documentation + +* **Completions:** + * fixes some errors in the completion docs ([9b359bf0](https://github.com/kbknapp/clap-rs/commit/9b359bf06255d3dad8f489308044b60a9d1e6a87)) + * adds documentation for completion scripts ([c6c519e4](https://github.com/kbknapp/clap-rs/commit/c6c519e40efd6c4533a9ef5efe8e74fd150391b7)) + +#### Features + +* **Completions:** + * one can now generate a bash completions script at compile time! ([e75b6c7b](https://github.com/kbknapp/clap-rs/commit/e75b6c7b75f729afb9eb1d2a2faf61dca7674634), closes [#376](https://github.com/kbknapp/clap-rs/issues/376)) + * completions now include aliases to subcommands, including all subcommand options ([0ab9f840](https://github.com/kbknapp/clap-rs/commit/0ab9f84052a8cf65b5551657f46c0c270841e634), closes [#556](https://github.com/kbknapp/clap-rs/issues/556)) + * completions now continue completing even after first completion ([18fc2e5b](https://github.com/kbknapp/clap-rs/commit/18fc2e5b5af63bf54a94b72cec5e1223d49f4806)) + * allows matching on possible values in options ([89cc2026](https://github.com/kbknapp/clap-rs/commit/89cc2026ba9ac69cf44c5254360bbf99236d4f89), closes [#557](https://github.com/kbknapp/clap-rs/issues/557)) + +#### Bug Fixes + +* **AllowLeadingHyphen:** fixes an issue where isn't ignored like it should be with this setting ([96c24c9a](https://github.com/kbknapp/clap-rs/commit/96c24c9a8fa1f85e06138d3cdd133e51659e19d2), closes [#558](https://github.com/kbknapp/clap-rs/issues/558)) + + +## v2.8.0 (2016-06-30) + + +#### Features + +* **Arg:** adds new setting `Arg::require_delimiter` which requires val delimiter to parse multiple values ([920b5595](https://github.com/kbknapp/clap-rs/commit/920b5595ed72abfb501ce054ab536067d8df2a66)) + +#### Bug Fixes + +* Declare term::Winsize as repr(C) ([5d663d90](https://github.com/kbknapp/clap-rs/commit/5d663d905c9829ce6e7a164f1f0896cdd70236dd)) + +#### Documentation + +* **Arg:** adds docs for ([49af4e38](https://github.com/kbknapp/clap-rs/commit/49af4e38a5dae2ab0a7fc3b4147e2c053d532484)) + + + + +### v2.7.1 (2016-06-29) + + +#### Bug Fixes + +* **Options:** + * options with multiple values and using delimiters no longer parse additional values after a trailing space ([cdc500bd](https://github.com/kbknapp/clap-rs/commit/cdc500bdde6abe238c36ade406ddafc2bafff583)) + * using options with multiple values and with an = no longer parse args after the trailing space as values ([290f61d0](https://github.com/kbknapp/clap-rs/commit/290f61d07177413cf082ada55526d83405f6d011)) + + + + +## v2.7.0 (2016-06-28) + + +#### Documentation + +* fix typos ([43b3d40b](https://github.com/kbknapp/clap-rs/commit/43b3d40b8c38b1571da75af86b5088be96cccec2)) +* **ArgGroup:** vastly improves ArgGroup docs by adding better examples ([9e5f4f5d](https://github.com/kbknapp/clap-rs/commit/9e5f4f5d734d630bca5535c3a0aa4fd4f9db3e39), closes [#534](https://github.com/kbknapp/clap-rs/issues/534)) + +#### Features + +* **ArgGroup:** one can now specify groups which require AT LEAST one of the args ([33689acc](https://github.com/kbknapp/clap-rs/commit/33689acc689b217a8c0ee439f1b1225590c38355), closes [#533](https://github.com/kbknapp/clap-rs/issues/533)) + +#### Bug Fixes + +* **App:** using `App::print_help` now prints the same as would have been printed by `--help` or the like ([e84cc018](https://github.com/kbknapp/clap-rs/commit/e84cc01836bbe0527e97de6db9889bd9e0fd6ba1), closes [#536](https://github.com/kbknapp/clap-rs/issues/536)) +* **Help:** + * prevents invoking help help and displaying incorrect help message ([e3d2893f](https://github.com/kbknapp/clap-rs/commit/e3d2893f377942a2d4cf3c6ff04524d0346e6fdb), closes [#538](https://github.com/kbknapp/clap-rs/issues/538)) + * subcommand help messages requested via help now correctly match --help ([08ad1cff](https://github.com/kbknapp/clap-rs/commit/08ad1cff4fec57224ea957a2891a057b323c01bc), closes [#539](https://github.com/kbknapp/clap-rs/issues/539)) + +#### Improvements + +* **ArgGroup:** Add multiple ArgGroups per Arg ([902e182f](https://github.com/kbknapp/clap-rs/commit/902e182f7a58aff11ff01e0a452abcdbdb2262aa), closes [#426](https://github.com/kbknapp/clap-rs/issues/426)) +* **Usage Strings:** `[FLAGS]` and `[ARGS]` are no longer blindly added to usage strings ([9b2e45b1](https://github.com/kbknapp/clap-rs/commit/9b2e45b170aff567b038d8b3368880b6046c10c6), closes [#537](https://github.com/kbknapp/clap-rs/issues/537)) +* **arg_enum!:** allows using meta items like repr(C) with arg_enum!s ([edf9b233](https://github.com/kbknapp/clap-rs/commit/edf9b2331c17a2cbcc13f961add4c55c2778e773), closes [#543](https://github.com/kbknapp/clap-rs/issues/543)) + + + + +## v2.6.0 (2016-06-14) + + +#### Improvements + +* removes extra newline from help output ([86e61d19](https://github.com/kbknapp/clap-rs/commit/86e61d19a748fb9870fcf1175308984e51ca1115)) +* allows printing version to any io::Write object ([921f5f79](https://github.com/kbknapp/clap-rs/commit/921f5f7916597f1d028cd4a65bfe76a01c801724)) +* removes extra newline when printing version ([7e2e2cbb](https://github.com/kbknapp/clap-rs/commit/7e2e2cbb4a8a0f050bb8072a376f742fc54b8589)) +* **Aliases:** improves readability of asliases in help messages ([ca511de7](https://github.com/kbknapp/clap-rs/commit/ca511de71f5b8c2ac419f1b188658e8c63b67846), closes [#526](https://github.com/kbknapp/clap-rs/issues/526), [#529](https://github.com/kbknapp/clap-rs/issues/529)) +* **Usage Strings:** improves the default usage string when only a single positional arg is present ([ec86f2da](https://github.com/kbknapp/clap-rs/commit/ec86f2dada1545a63fc72355e22fcdc4c466c215), closes [#518](https://github.com/kbknapp/clap-rs/issues/518)) + +#### Features + +* **Help:** allows wrapping at specified term width (Even on Windows!) ([1761dc0d](https://github.com/kbknapp/clap-rs/commit/1761dc0d27d0d621229d792be40c36fbf65c3014), closes [#451](https://github.com/kbknapp/clap-rs/issues/451)) +* **Settings:** + * adds new setting to stop delimiting values with -- or TrailingVarArg ([fc3e0f5a](https://github.com/kbknapp/clap-rs/commit/fc3e0f5afda6d24cdb3c4676614beebe13e1e870), closes [#511](https://github.com/kbknapp/clap-rs/issues/511)) + * one can now set an AppSetting which is propogated down through child subcommands ([e2341835](https://github.com/kbknapp/clap-rs/commit/e23418351a3b98bf08dfd7744bc14377c70d59ee), closes [#519](https://github.com/kbknapp/clap-rs/issues/519)) +* **Subcommands:** adds support for visible aliases ([7b10e7f8](https://github.com/kbknapp/clap-rs/commit/7b10e7f8937a07fdb8d16a6d8df79ce78d080cd3), closes [#522](https://github.com/kbknapp/clap-rs/issues/522)) + +#### Bug Fixes + +* fixes bug where args are printed out of order with templates ([05abb534](https://github.com/kbknapp/clap-rs/commit/05abb534864764102031a0d402e64ac65867aa87)) +* fixes bug where one can't override version or help flags ([90d7d6a2](https://github.com/kbknapp/clap-rs/commit/90d7d6a2ea8240122dd9bf8d82d3c4f5ebb5c703), closes [#514](https://github.com/kbknapp/clap-rs/issues/514)) +* fixes issue where before_help wasn't printed ([b3faff60](https://github.com/kbknapp/clap-rs/commit/b3faff6030f76a23f26afcfa6a90169002ed7106)) +* **Help:** `App::before_help` and `App::after_help` now correctly wrap ([1f4da767](https://github.com/kbknapp/clap-rs/commit/1f4da7676e6e71aa8dda799f3eeefad105a47819), closes [#516](https://github.com/kbknapp/clap-rs/issues/516)) +* **Settings:** fixes bug where new color settings couldn't be converted from strs ([706a7c11](https://github.com/kbknapp/clap-rs/commit/706a7c11b0900be594de6d5a3121938eff197602)) +* **Subcommands:** subcommands with aliases now display help of the aliased subcommand ([5354d14b](https://github.com/kbknapp/clap-rs/commit/5354d14b51f189885ba110e01e6b76cca3752992), closes [#521](https://github.com/kbknapp/clap-rs/issues/521)) +* **Windows:** fixes a failing windows build ([01e7dfd6](https://github.com/kbknapp/clap-rs/commit/01e7dfd6c07228c0be6695b3c7bf9370d82860d4)) +* **YAML:** adds missing YAML methods for App and Arg ([e468faf3](https://github.com/kbknapp/clap-rs/commit/e468faf3f05950fd9f72d84b69aa2061e91c6c64), closes [#528](https://github.com/kbknapp/clap-rs/issues/528)) + + + + +### v2.5.2 (2016-05-31) + + +#### Improvements + +* removes extra newline from help output ([86e61d19](https://github.com/kbknapp/clap-rs/commit/86e61d19a748fb9870fcf1175308984e51ca1115)) +* allows printing version to any io::Write object ([921f5f79](https://github.com/kbknapp/clap-rs/commit/921f5f7916597f1d028cd4a65bfe76a01c801724)) +* removes extra newline when printing version ([7e2e2cbb](https://github.com/kbknapp/clap-rs/commit/7e2e2cbb4a8a0f050bb8072a376f742fc54b8589)) + +#### Bug Fixes + +* fixes bug where args are printed out of order with templates ([3935431d](https://github.com/kbknapp/clap-rs/commit/3935431d5633f577c0826ae2142794b301f4b8ca)) +* fixes bug where one can't override version or help flags ([90d7d6a2](https://github.com/kbknapp/clap-rs/commit/90d7d6a2ea8240122dd9bf8d82d3c4f5ebb5c703), closes [#514](https://github.com/kbknapp/clap-rs/issues/514)) +* fixes issue where before_help wasn't printed ([b3faff60](https://github.com/kbknapp/clap-rs/commit/b3faff6030f76a23f26afcfa6a90169002ed7106)) + +#### Documentation + +* inter-links all types and pages ([3312893d](https://github.com/kbknapp/clap-rs/commit/3312893ddaef3f44d68d8d26ed3d08010be50d97), closes [#505](https://github.com/kbknapp/clap-rs/issues/505)) +* makes all publicly available types viewable in docs ([52ca6505](https://github.com/kbknapp/clap-rs/commit/52ca6505b4fec7b5c2d53d160c072d395eb21da6)) + + +### v2.5.1 (2016-05-11) + + +#### Bug Fixes + +* **Subcommand Aliases**: fixes lifetime issue when setting multiple aliases at once ([ac42f6cf0](https://github.com/kbknapp/clap-rs/commit/ac42f6cf0de6c4920f703807d63061803930b18d)) + + +## v2.5.0 (2016-05-10) + + +#### Improvements + +* **SubCommand Aliases:** adds feature to yaml configs too ([69592195](https://github.com/kbknapp/clap-rs/commit/695921954dde46dfd483399dcdef482c9dd7f34a)) + +#### Features + +* **SubCommands:** adds support for subcommand aliases ([66b4dea6](https://github.com/kbknapp/clap-rs/commit/66b4dea65c44d8f77ff522238a9237aed1bcab6d), closes [#469](https://github.com/kbknapp/clap-rs/issues/469)) + + + +### v2.4.3 (2016-05-10) + + +#### Bug Fixes + +* **Usage Strings:** + * now properly dedups args that are also in groups ([3ca0947c](https://github.com/kbknapp/clap-rs/commit/3ca0947c166b4f8525752255e3a4fa6565eb9689), closes [#498](https://github.com/kbknapp/clap-rs/issues/498)) + * removes duplicate groups from usage strings ([f574fb8a](https://github.com/kbknapp/clap-rs/commit/f574fb8a7cde4d4a2fa4c4481d59be2d0f135427)) + +#### Improvements + +* **Groups:** formats positional args in groups in a better way ([fef11154](https://github.com/kbknapp/clap-rs/commit/fef11154fb7430d1cbf04a672aabb366e456a368)) +* **Help:** + * moves positionals to standard <> formatting ([03dfe5ce](https://github.com/kbknapp/clap-rs/commit/03dfe5ceff1d63f172788ff688567ddad9fe119b)) + * default help subcommand string has been shortened ([5b7fe8e4](https://github.com/kbknapp/clap-rs/commit/5b7fe8e4161e43ab19e2e5fcf55fbe46791134e9), closes [#494](https://github.com/kbknapp/clap-rs/issues/494)) + + +### v2.4.3 (2016-05-10) + +* Ghost Release + + +### v2.4.3 (2016-05-10) + +* Ghost Release + + +## v2.4.0 (2016-05-02) + + +#### Features + +* **Help:** adds support for displaying info before help message ([29fbfa3b](https://github.com/kbknapp/clap-rs/commit/29fbfa3b963f2f3ca7704bf5d3e1201531baa373)) +* **Required:** adds allowing args that are required unless certain args are present ([af1f7916](https://github.com/kbknapp/clap-rs/commit/af1f79168390ea7da4074d0d9777de458ea64971)) + +#### Documentation + +* hides formatting from docs ([cb708093](https://github.com/kbknapp/clap-rs/commit/cb708093a7cd057f08c98b7bd1ed54c2db86ae7e)) +* **required_unless:** adds docs and examples for required_unless ([ca727b52](https://github.com/kbknapp/clap-rs/commit/ca727b52423b9883acd88b2f227b2711bc144573)) + +#### Bug Fixes + +* **Required Args:** fixes issue where missing required args are sometimes duplicatd in error messages ([3beebd81](https://github.com/kbknapp/clap-rs/commit/3beebd81e7bc2faa4115ac109cf570e512c5477f), closes [#492](https://github.com/kbknapp/clap-rs/issues/492)) + + + +## v2.3.0 (2016-04-18) + + +#### Improvements + +* **macros.rs:** Added write_nspaces macro (a new version of write_spaces) ([9d757e86](https://github.com/kbknapp/clap-rs/commit/9d757e8678e334e5a740ac750c76a9ed4e785cba)) +* **parser.rs:** + * Provide a way to create a usage string without the USAGE: title ([a91d378b](https://github.com/kbknapp/clap-rs/commit/a91d378ba0c91b5796457f8c6e881b13226ab735)) + * Make Parser's create_usage public allowing to have function outside the parser to generate the help ([d51945f8](https://github.com/kbknapp/clap-rs/commit/d51945f8b82ebb0963f4f40b384a9e8335783091)) + * Expose Parser's flags, opts and positionals argument as iterators ([9b23e7ee](https://github.com/kbknapp/clap-rs/commit/9b23e7ee40e51f7a823644c4496be955dc6c9d3a)) +* **src/args:** Exposes argument display order by introducing a new Trait ([1321630e](https://github.com/kbknapp/clap-rs/commit/1321630ef56955f152c73376d4d85cceb0bb4a12)) +* **srs/args:** Added longest_filter to AnyArg trait ([65b3f667](https://github.com/kbknapp/clap-rs/commit/65b3f667532685f854c699ddd264d326599cf7e5)) + +#### Features + +* **Authors Macro:** adds a crate_authors macro ([38fb59ab](https://github.com/kbknapp/clap-rs/commit/38fb59abf480eb2b6feca269097412f8b00b5b54), closes [#447](https://github.com/kbknapp/clap-rs/issues/447)) +* **HELP:** + * implements optional colored help messages ([abc8f669](https://github.com/kbknapp/clap-rs/commit/abc8f669c3c8193ffc3a3b0ac6c3ac2198794d4f), closes [#483](https://github.com/kbknapp/clap-rs/issues/483)) + * Add a Templated Help system. ([81e121ed](https://github.com/kbknapp/clap-rs/commit/81e121edd616f7285593f11120c63bcccae0d23e)) + +#### Bug Fixes + +* **HELP:** Adjust Help to semantic changes introduced in 6933b84 ([8d23806b](https://github.com/kbknapp/clap-rs/commit/8d23806bd67530ad412c34a1dcdcb1435555573d)) + + +### v2.2.6 (2016-04-11) + +#### Bug Fixes + +* **Arg Groups**: fixes bug where arg name isn't printed properly ([3019a685](https://github.com/kbknapp/clap-rs/commit/3019a685eee747ccbe6be09ad5dddce0b1d1d4db), closes [#476](https://github.com/kbknapp/clap-rs/issues/476)) + + + +### v2.2.5 (2016-04-03) + + +#### Bug Fixes + +* **Empty Values:** fixes bug where empty values weren't stored ([885d166f](https://github.com/kbknapp/clap-rs/commit/885d166f04eb3fb581898ae5818c6c8032e5a686), closes [#470](https://github.com/kbknapp/clap-rs/issues/470)) +* **Help Message:** fixes bug where arg name is printed twice ([71acf1d5](https://github.com/kbknapp/clap-rs/commit/71acf1d576946658b8bbdb5ae79e6716c43a030f), closes [#472](https://github.com/kbknapp/clap-rs/issues/472)) + + + +### v2.2.4 (2016-03-30) + + +#### Bug Fixes + +* fixes compiling with debug cargo feature ([d4b55450](https://github.com/kbknapp/clap-rs/commit/d4b554509928031ac0808076178075bb21f8c1da)) +* **Empty Values:** fixes bug where empty values weren't stored ([885d166f](https://github.com/kbknapp/clap-rs/commit/885d166f04eb3fb581898ae5818c6c8032e5a686), closes [#470](https://github.com/kbknapp/clap-rs/issues/470)) + + + + +### v2.2.3 (2016-03-28) + + +#### Bug Fixes + +* **Help Subcommand:** fixes issue where help and version flags weren't properly displayed ([205b07bf](https://github.com/kbknapp/clap-rs/commit/205b07bf2e6547851f1290f8cd6b169145e144f1), closes [#466](https://github.com/kbknapp/clap-rs/issues/466)) + + +### v2.2.2 (2016-03-27) + + +#### Bug Fixes + +* **Help Message:** fixes bug with wrapping in the middle of a unicode sequence ([05365ddc](https://github.com/kbknapp/clap-rs/commit/05365ddcc252e4b49e7a75e199d6001a430bd84d), closes [#456](https://github.com/kbknapp/clap-rs/issues/456)) +* **Usage Strings:** fixes small bug where -- would appear needlessly in usage strings ([6933b849](https://github.com/kbknapp/clap-rs/commit/6933b8491c2a7e28cdb61b47dcf10caf33c2f78a), closes [#461](https://github.com/kbknapp/clap-rs/issues/461)) + + + +### 2.2.1 (2016-03-16) + + +#### Features + +* **Help Message:** wraps and aligns the help message of subcommands ([813d75d0](https://github.com/kbknapp/clap-rs/commit/813d75d06fbf077c65762608c0fa5e941cfc393c), closes [#452](https://github.com/kbknapp/clap-rs/issues/452)) + +#### Bug Fixes + +* **Help Message:** fixes a bug where small terminal sizes causing a loop ([1d73b035](https://github.com/kbknapp/clap-rs/commit/1d73b0355236923aeaf6799abc759762ded7e1d0), closes [#453](https://github.com/kbknapp/clap-rs/issues/453)) + + + +## v2.2.0 (2016-03-15) + + +#### Features + +* **Help Message:** can auto wrap and aligning help text to term width ([e36af026](https://github.com/kbknapp/clap-rs/commit/e36af0266635f23e85e951b9088d561e9a5d1bf6), closes [#428](https://github.com/kbknapp/clap-rs/issues/428)) +* **Help Subcommand:** adds support passing additional subcommands to help subcommand ([2c12757b](https://github.com/kbknapp/clap-rs/commit/2c12757bbdf34ce481f3446c074e24c09c2e60fd), closes [#416](https://github.com/kbknapp/clap-rs/issues/416)) +* **Opts and Flags:** adds support for custom ordering in help messages ([9803b51e](https://github.com/kbknapp/clap-rs/commit/9803b51e799904c0befaac457418ee766ccc1ab9)) +* **Settings:** adds support for automatically deriving custom display order of args ([ad86e433](https://github.com/kbknapp/clap-rs/commit/ad86e43334c4f70e86909689a088fb87e26ff95a), closes [#444](https://github.com/kbknapp/clap-rs/issues/444)) +* **Subcommands:** adds support for custom ordering in help messages ([7d2a2ed4](https://github.com/kbknapp/clap-rs/commit/7d2a2ed413f5517d45988eef0765cdcd663b6372), closes [#442](https://github.com/kbknapp/clap-rs/issues/442)) + +#### Bug Fixes + +* **From Usage:** fixes a bug where adding empty lines werent ignored ([c5c58c86](https://github.com/kbknapp/clap-rs/commit/c5c58c86b9c503d8de19da356a5a5cffb59fbe84)) + +#### Documentation + +* **Groups:** explains required ArgGroups better ([4ff0205b](https://github.com/kbknapp/clap-rs/commit/4ff0205b85a45151b59bbaf090a89df13438380f), closes [#439](https://github.com/kbknapp/clap-rs/issues/439)) + + +### v2.1.2 (2016-02-24) + +#### Bug Fixes + +* **Nightly:** fixes failing nightly build ([d752c170](https://github.com/kbknapp/clap-rs/commit/d752c17029598b19037710f204b7943f0830ae75), closes [#434](https://github.com/kbknapp/clap-rs/issues/434)) + + + +### v2.1.1 (2016-02-19) + + +#### Documentation + +* **AppSettings:** clarifies that AppSettings do not propagate ([3c8db0e9](https://github.com/kbknapp/clap-rs/commit/3c8db0e9be1d24edaad364359513cbb02abb4186), closes [#429](https://github.com/kbknapp/clap-rs/issues/429)) +* **Arg Examples:** adds better examples ([1e79cccc](https://github.com/kbknapp/clap-rs/commit/1e79cccc12937bc0e7cd2aad8e404410798e9fff)) + +#### Improvements + +* **Help:** adds setting for next line help by arg ([066df748](https://github.com/kbknapp/clap-rs/commit/066df7486e684cf50a8479a356a12ba972c34ce1), closes [#427](https://github.com/kbknapp/clap-rs/issues/427)) + + + +## v2.1.0 (2016-02-10) + + +#### Features + +* **Defult Values:** adds support for default values in args ([73211952](https://github.com/kbknapp/clap-rs/commit/73211952964a79d97b434dd567e6d7d34be7feb5), closes [#418](https://github.com/kbknapp/clap-rs/issues/418)) + +#### Documentation + +* **Default Values:** adds better examples and notes for default values ([9facd74f](https://github.com/kbknapp/clap-rs/commit/9facd74f843ef3807c5d35259558a344e6c25905)) + + + +### v2.0.6 (2016-02-09) + + +#### Improvements + +* **Positional Arguments:** now displays value name if appropriate ([f0a99916](https://github.com/kbknapp/clap-rs/commit/f0a99916c59ce675515c6dcdfe9a40b130510908), closes [#420](https://github.com/kbknapp/clap-rs/issues/420)) + + + +### v2.0.5 (2016-02-05) + + +#### Bug Fixes + +* **Multiple Values:** fixes bug where number_of_values wasnt respected ([72c387da](https://github.com/kbknapp/clap-rs/commit/72c387da0bb8a6f526f863770f08bb8ca0d3de03)) + + + +### v2.0.4 (2016-02-04) + + +#### Bug Fixes + +* adds support for building ArgGroups from standalone YAML ([fcbc7e12](https://github.com/kbknapp/clap-rs/commit/fcbc7e12f5d7b023b8f30cba8cad28a01cf6cd26)) +* Stop lonely hyphens from causing panic ([85b11468](https://github.com/kbknapp/clap-rs/commit/85b11468b0189d5cc15f1cfac5db40d17a0077dc), closes [#410](https://github.com/kbknapp/clap-rs/issues/410)) +* **AppSettings:** fixes bug where subcmds didn't receive parent ver ([a62e4527](https://github.com/kbknapp/clap-rs/commit/a62e452754b3b0e3ac9a15aa8b5330636229ead1)) + + +### v2.0.3 (2016-02-02) + + +#### Improvements + +* **values:** adds support for up to u64::max values per arg ([c7abf7d7](https://github.com/kbknapp/clap-rs/commit/c7abf7d7611e317b0d31d97632e3d2e13570947c)) +* **occurrences:** Allow for more than 256 occurrences of an argument. ([3731ddb3](https://github.com/kbknapp/clap-rs/commit/3731ddb361163f3d6b86844362871e48c80fa530)) + +#### Features + +* **AppSettings:** adds HidePossibleValuesInHelp to skip writing those values ([cdee7a0e](https://github.com/kbknapp/clap-rs/commit/cdee7a0eb2beeec723cb98acfacf03bf629c1da3)) + +#### Bug Fixes + +* **value_t_or_exit:** fixes typo which causes value_t_or_exit to return a Result ([ee96baff](https://github.com/kbknapp/clap-rs/commit/ee96baffd306cb8d20ddc5575cf739bb1a6354e8)) + + + +### v2.0.2 (2016-01-31) + + +#### Improvements + +* **arg_enum:** enum declared with arg_enum returns [&'static str; #] instead of Vec ([9c4b8a1a](https://github.com/kbknapp/clap-rs/commit/9c4b8a1a6b12949222f17d1074578ad7676b9c0d)) + +#### Bug Fixes + +* clap_app! should be gated by unstable, not nightly feature ([0c8b84af](https://github.com/kbknapp/clap-rs/commit/0c8b84af6161d5baf683688eafc00874846f83fa)) +* **SubCommands:** fixed where subcmds weren't recognized after mult args ([c19c17a8](https://github.com/kbknapp/clap-rs/commit/c19c17a8850602990e24347aeb4427cf43316223), closes [#405](https://github.com/kbknapp/clap-rs/issues/405)) +* **Usage Parser:** fixes a bug where literal single quotes weren't allowed in help strings ([0bcc7120](https://github.com/kbknapp/clap-rs/commit/0bcc71206478074769e311479b34a9f74fe80f5c), closes [#406](https://github.com/kbknapp/clap-rs/issues/406)) + + + +### v2.0.1 (2016-01-30) + + +#### Bug Fixes + +* fixes cargo features to NOT require nightly with unstable features ([dcbcc60c](https://github.com/kbknapp/clap-rs/commit/dcbcc60c9ba17894be636472ea4b07a82d86a9db), closes [#402](https://github.com/kbknapp/clap-rs/issues/402)) + + + +## v2.0.0 (2016-01-28) + + +#### Improvements + +* **From Usage:** vastly improves the usage parser ([fa3a2f86](https://github.com/kbknapp/clap-rs/commit/fa3a2f86bd674c5eb07128c95098fab7d1437247), closes [#350](https://github.com/kbknapp/clap-rs/issues/350)) + +#### Features + +* adds support for external subcommands ([177fe5cc](https://github.com/kbknapp/clap-rs/commit/177fe5cce745c2164a8e38c23be4c4460d2d7211), closes [#372](https://github.com/kbknapp/clap-rs/issues/372)) +* adds support values with a leading hyphen ([e4d429b9](https://github.com/kbknapp/clap-rs/commit/e4d429b9d52e95197bd0b572d59efacecf305a59), closes [#385](https://github.com/kbknapp/clap-rs/issues/385)) +* adds support for turning off the value delimiter ([508db850](https://github.com/kbknapp/clap-rs/commit/508db850a87c2e251cf6b6ddead9ad56b29f9e57), closes [#352](https://github.com/kbknapp/clap-rs/issues/352)) +* adds support changing the value delimiter ([dafeae8a](https://github.com/kbknapp/clap-rs/commit/dafeae8a526162640f6a68da434370c64d190889), closes [#353](https://github.com/kbknapp/clap-rs/issues/353)) +* adds support for comma separated values ([e69da6af](https://github.com/kbknapp/clap-rs/commit/e69da6afcd2fe48a3c458ca031db40997f860eda), closes [#348](https://github.com/kbknapp/clap-rs/issues/348)) +* adds support with options with optional values ([4555736c](https://github.com/kbknapp/clap-rs/commit/4555736cad01441dcde4ea84a285227e0844c16e), closes [#367](https://github.com/kbknapp/clap-rs/issues/367)) +* **UTF-8:** adds support for invalid utf8 in values ([c5c59dec](https://github.com/kbknapp/clap-rs/commit/c5c59dec0bc33b86b2e99d30741336f17ec84282), closes [#269](https://github.com/kbknapp/clap-rs/issues/269)) +* **v2:** implementing the base of 2.x ([a3536054](https://github.com/kbknapp/clap-rs/commit/a3536054512ba833533dc56615ce3663d884381c)) + +#### Bug Fixes + +* fixes nightly build with new lints ([17599195](https://github.com/kbknapp/clap-rs/commit/175991956c37dc83ba9c49396e927a1cb65c5b11)) +* fixes Windows build for 2x release ([674c9b48](https://github.com/kbknapp/clap-rs/commit/674c9b48c7c92079cb180cc650a9e39f34781c32), closes [#392](https://github.com/kbknapp/clap-rs/issues/392)) +* fixes yaml build for 2x base ([adceae64](https://github.com/kbknapp/clap-rs/commit/adceae64c8556d00ab715677377b216f9f468ad7)) + +#### Documentation + +* updates examples for 2x release ([1303b360](https://github.com/kbknapp/clap-rs/commit/1303b3607468f362ab1b452d5614c1a064dc69b4), closes [#394](https://github.com/kbknapp/clap-rs/issues/394)) +* updates examples for 2x release ([0a011f31](https://github.com/kbknapp/clap-rs/commit/0a011f3142aec338d388a6c8bfe22fa7036021bb), closes [#394](https://github.com/kbknapp/clap-rs/issues/394)) +* updates documentation for v2 release ([8d51724e](https://github.com/kbknapp/clap-rs/commit/8d51724ef73dfde5bb94fb9466bc5463a1cc1502)) +* updating docs for 2x release ([576d0e0e](https://github.com/kbknapp/clap-rs/commit/576d0e0e2c7b8f386589179bbf7419b93abacf1c)) +* **README.md:** + * updates readme for v2 release ([acaba01a](https://github.com/kbknapp/clap-rs/commit/acaba01a353c12144b9cd9a3ce447400691849b0), closes [#393](https://github.com/kbknapp/clap-rs/issues/393)) + * fix typo and make documentation conspicuous ([07b9f614](https://github.com/kbknapp/clap-rs/commit/07b9f61495d927f69f7abe6c0d85253f0f4e6107)) + +#### BREAKING CHANGES + +* **Fewer liftimes! Yay!** + * `App<'a, 'b, 'c, 'd, 'e, 'f>` => `App<'a, 'b>` + * `Arg<'a, 'b, 'c, 'd, 'e, 'f>` => `Arg<'a, 'b>` + * `ArgMatches<'a, 'b>` => `ArgMatches<'a>` +* **Simply Renamed** + * `App::arg_group` => `App::group` + * `App::arg_groups` => `App::groups` + * `ArgGroup::add` => `ArgGroup::arg` + * `ArgGroup::add_all` => `ArgGroup::args` + * `ClapError` => `Error` + * struct field `ClapError::error_type` => `Error::kind` + * `ClapResult` => `Result` + * `ClapErrorType` => `ErrorKind` +* **Removed Deprecated Functions and Methods** + * `App::subcommands_negate_reqs` + * `App::subcommand_required` + * `App::arg_required_else_help` + * `App::global_version(bool)` + * `App::versionless_subcommands` + * `App::unified_help_messages` + * `App::wait_on_error` + * `App::subcommand_required_else_help` + * `SubCommand::new` + * `App::error_on_no_subcommand` + * `Arg::new` + * `Arg::mutually_excludes` + * `Arg::mutually_excludes_all` + * `Arg::mutually_overrides_with` + * `simple_enum!` +* **Renamed Error Variants** + * `InvalidUnicode` => `InvalidUtf8` + * `InvalidArgument` => `UnknownArgument` +* **Usage Parser** + * Value names can now be specified inline, i.e. `-o, --option 'some option which takes two files'` + * **There is now a priority of order to determine the name** - This is perhaps the biggest breaking change. See the documentation for full details. Prior to this change, the value name took precedence. **Ensure your args are using the proper names (i.e. typically the long or short and NOT the value name) throughout the code** +* `ArgMatches::values_of` returns an `Values` now which implements `Iterator` (should not break any code) +* `crate_version!` returns `&'static str` instead of `String` +* Using the `clap_app!` macro requires compiling with the `unstable` feature because the syntax could change slightly in the future + + + +### v1.5.5 (2016-01-04) + + +#### Bug Fixes + +* fixes an issue where invalid short args didn't cause an error ([c9bf7e44](https://github.com/kbknapp/clap-rs/commit/c9bf7e4440bd2f9b524ea955311d433c40a7d1e0)) +* prints the name in version and help instead of binary name ([8f3817f6](https://github.com/kbknapp/clap-rs/commit/8f3817f665c0cab6726bc16c56a53b6a61e44448), closes [#368](https://github.com/kbknapp/clap-rs/issues/368)) +* fixes an intentional panic issue discovered via clippy ([ea83a3d4](https://github.com/kbknapp/clap-rs/commit/ea83a3d421ea8856d4cac763942834d108b71406)) + + + +### v1.5.4 (2015-12-18) + + +#### Examples + +* **17_yaml:** conditinonally compile 17_yaml example ([575de089](https://github.com/kbknapp/clap-rs/commit/575de089a3e240c398cb10e6cf5a5c6b68662c01)) + +#### Improvements + +* clippy improvements ([99cdebc2](https://github.com/kbknapp/clap-rs/commit/99cdebc23da3a45a165f14b27bebeb2ed828a2ce)) + +#### Bug Fixes + + +* **errors:** return correct error type in WrongNumValues error builder ([5ba8ba9d](https://github.com/kbknapp/clap-rs/commit/5ba8ba9dcccdfa74dd1c44260e64b359bbb36be6)) +* ArgRequiredElseHelp setting now takes precedence over missing required args ([faad83fb](https://github.com/kbknapp/clap-rs/commit/faad83fbef6752f3093b6e98fca09a9449b830f4), closes [#362](https://github.com/kbknapp/clap-rs/issues/362)) + + + +### v1.5.3 (2015-11-20) + + +#### Bug Fixes + +* **Errors:** fixes some instances when errors are missing a final newline ([c4d2b171](https://github.com/kbknapp/clap-rs/commit/c4d2b1711994479ad64ee52b6b49d2ceccbf2118)) + + + + + +### v1.5.2 (2015-11-14) + + +#### Bug Fixes + +* **Errors:** fixes a compiling bug when built on Windows or without the color feature ([a35f7634](https://github.com/kbknapp/clap-rs/commit/a35f76346fe6ecc88dda6a1eb13627186e7ce185)) + + + + +### v1.5.1 (2015-11-13) + + +#### Bug Fixes + +* **Required Args:** fixes a bug where required args are not correctly accounted for ([f03b88a9](https://github.com/kbknapp/clap-rs/commit/f03b88a9766b331a63879bcd747687f2e5a2661b), closes [#343](https://github.com/kbknapp/clap-rs/issues/343)) + + + + +## v1.5.0 (2015-11-13) + + +#### Bug Fixes + +* fixes a bug with required positional args in usage strings ([c6858f78](https://github.com/kbknapp/clap-rs/commit/c6858f78755f8e860204323c828c8355a066dc83)) + +#### Documentation + +* **FAQ:** updates readme with slight changes to FAQ ([a4ef0fab](https://github.com/kbknapp/clap-rs/commit/a4ef0fab73c8dc68f1b138965d1340459c113398)) + +#### Improvements + +* massive errors overhaul ([cdc29175](https://github.com/kbknapp/clap-rs/commit/cdc29175bc9c53e5b4aec86cbc04c1743154dae6)) +* **ArgMatcher:** huge refactor and deduplication of code ([8988853f](https://github.com/kbknapp/clap-rs/commit/8988853fb8825e8f841fde349834cc12cdbad081)) +* **Errors:** errors have been vastly improved ([e59bc0c1](https://github.com/kbknapp/clap-rs/commit/e59bc0c16046db156a88ba71a037db05028e995c)) +* **Traits:** refactoring some configuration into traits ([5800cdec](https://github.com/kbknapp/clap-rs/commit/5800cdec6dce3def4242b9f7bd136308afb19685)) + +#### Performance + +* **App:** + * more BTreeMap->Vec, Opts and SubCmds ([bc4495b3](https://github.com/kbknapp/clap-rs/commit/bc4495b32ec752b6c4b29719e831c043ef2a26ce)) + * changes flags BTreeMap->Vec ([d357640f](https://github.com/kbknapp/clap-rs/commit/d357640fab55e5964fe83efc3c771e53aa3222fd)) + * removed unneeded BTreeMap ([78971fd6](https://github.com/kbknapp/clap-rs/commit/78971fd68d7dc5c8e6811b4520cdc54e4188f733)) + * changes BTreeMap to VecMap in some instances ([64b921d0](https://github.com/kbknapp/clap-rs/commit/64b921d087fdd03775c95ba0bcf65d3f5d36f812)) + * removed excess clones ([ec0089d4](https://github.com/kbknapp/clap-rs/commit/ec0089d42ed715d293fb668d3a90b0db0aa3ec39)) + + + + +### v1.4.7 (2015-11-03) + + +#### Documentation + +* Clarify behavior of Arg::multiple with options. ([434f497a](https://github.com/kbknapp/clap-rs/commit/434f497ab6d831f8145cf09278c97ca6ee6c6fe7)) +* Fix typos and improve grammar. ([c1f66b5d](https://github.com/kbknapp/clap-rs/commit/c1f66b5de7b5269fbf8760a005ef8c645edd3229)) + +#### Bug Fixes + +* **Error Status:** fixes bug where --help and --version return non-zero exit code ([89b51fdf](https://github.com/kbknapp/clap-rs/commit/89b51fdf8b1ab67607567344e2317ff1a757cb12)) + + + + +### v1.4.6 (2015-10-29) + + +#### Features + +* allows parsing without a binary name for daemons and interactive CLIs ([aff89d57](https://github.com/kbknapp/clap-rs/commit/aff89d579b5b85c3dc81b64f16d5865299ec39a2), closes [#318](https://github.com/kbknapp/clap-rs/issues/318)) + +#### Bug Fixes + +* **Errors:** tones down quoting in some error messages ([34ce59ed](https://github.com/kbknapp/clap-rs/commit/34ce59ede53bfa2eef722c74881cdba7419fd9c7), closes [#309](https://github.com/kbknapp/clap-rs/issues/309)) +* **Help and Version:** only builds help and version once ([e3be87cf](https://github.com/kbknapp/clap-rs/commit/e3be87cfc095fc41c9811adcdc6d2b079f237d5e)) +* **Option Args:** fixes bug with args and multiple values ([c9a9548a](https://github.com/kbknapp/clap-rs/commit/c9a9548a8f96cef8a3dd9a980948325fbbc1b91b), closes [#323](https://github.com/kbknapp/clap-rs/issues/323)) +* **POSIX Overrides:** fixes bug where required args are overridden ([40ed2b50](https://github.com/kbknapp/clap-rs/commit/40ed2b50c3a9fe88bfdbaa43cef9fd6493ecaa8e)) +* **Safe Matches:** using 'safe' forms of the get_matches family no longer exit the process ([c47025dc](https://github.com/kbknapp/clap-rs/commit/c47025dca2b3305dea0a0acfdd741b09af0c0d05), closes [#256](https://github.com/kbknapp/clap-rs/issues/256)) +* **Versionless SubCommands:** fixes a bug where the -V flag was needlessly built ([27df8b9d](https://github.com/kbknapp/clap-rs/commit/27df8b9d98d13709dad3929a009f40ebff089a1a), closes [#329](https://github.com/kbknapp/clap-rs/issues/329)) + +#### Documentation + +* adds comparison in readme ([1a8bf31e](https://github.com/kbknapp/clap-rs/commit/1a8bf31e7a6b87ce48a66af2cde1645b2dd5bc95), closes [#325](https://github.com/kbknapp/clap-rs/issues/325)) + + + + +### v1.4.5 (2015-10-06) + + +#### Bug Fixes + +* fixes crash on invalid arg error ([c78ce128](https://github.com/kbknapp/clap-rs/commit/c78ce128ebbe7b8f730815f8176c29d76f4ade8c)) + + + + +### v1.4.4 (2015-10-06) + + +#### Documentation + +* clean up some formatting ([b7df92d7](https://github.com/kbknapp/clap-rs/commit/b7df92d7ea25835701dd22ddff984b9749f48a00)) +* move the crate-level docs to top of the lib.rs file ([d7233bf1](https://github.com/kbknapp/clap-rs/commit/d7233bf122dbf80ba8fc79e5641be2df8af10e7a)) +* changes doc comments to rustdoc comments ([34b601be](https://github.com/kbknapp/clap-rs/commit/34b601be5fdde76c1a0859385b359b96d66b8732)) +* fixes panic in 14_groups example ([945b00a0](https://github.com/kbknapp/clap-rs/commit/945b00a0c27714b63bdca48d003fe205fcfdc578), closes [#295](https://github.com/kbknapp/clap-rs/issues/295)) +* avoid suggesting star dependencies. ([d33228f4](https://github.com/kbknapp/clap-rs/commit/d33228f40b5fefb84cf3dd51546bfb340dcd9f5a)) +* **Rustdoc:** adds portions of the readme to main rustdoc page ([6f9ee181](https://github.com/kbknapp/clap-rs/commit/6f9ee181e69d90bd4206290e59d6f3f1e8f0cbb2), closes [#293](https://github.com/kbknapp/clap-rs/issues/293)) + +#### Bug Fixes + +* grammar error in some conflicting option errors ([e73b07e1](https://github.com/kbknapp/clap-rs/commit/e73b07e19474323ad2260da66abbf6a6d4ecbd4f)) +* **Unified Help:** sorts both flags and options as a unified category ([2a223dad](https://github.com/kbknapp/clap-rs/commit/2a223dad82901fa2e74baad3bfc4c7b94509300f)) +* **Usage:** fixes a bug where required args aren't filtered properly ([72b453dc](https://github.com/kbknapp/clap-rs/commit/72b453dc170af3050bb123d35364f6da77fc06d7), closes [#277](https://github.com/kbknapp/clap-rs/issues/277)) +* **Usage Strings:** fixes a bug ordering of elements in usage strings ([aaf0d6fe](https://github.com/kbknapp/clap-rs/commit/aaf0d6fe7aa2403e76096c16204d254a9ee61ee2), closes [#298](https://github.com/kbknapp/clap-rs/issues/298)) + +#### Features + +* supports -aValue style options ([0e3733e4](https://github.com/kbknapp/clap-rs/commit/0e3733e4fec2015c2d566a51432dcd92cb69cad3)) +* **Trailing VarArg:** adds opt-in setting for final arg being vararg ([27018b18](https://github.com/kbknapp/clap-rs/commit/27018b1821a4bcd5235cfe92abe71b3c99efc24d), closes [#278](https://github.com/kbknapp/clap-rs/issues/278)) + + + + +### v1.4.3 (2015-09-30) + + +#### Features + +* allows accessing arg values by group name ([c92a4b9e](https://github.com/kbknapp/clap-rs/commit/c92a4b9eff2d679957f61c0c41ff404b40d38a91)) + +#### Documentation + +* use links to examples instead of plain text ([bb4fe237](https://github.com/kbknapp/clap-rs/commit/bb4fe237858535627271465147add537e4556b43)) + +#### Bug Fixes + +* **Help Message:** required args no longer double list in usage ([1412e639](https://github.com/kbknapp/clap-rs/commit/1412e639e0a79df84936d1101a837f90077d1c83), closes [#277](https://github.com/kbknapp/clap-rs/issues/277)) +* **Possible Values:** possible value validation is restored ([f121ae74](https://github.com/kbknapp/clap-rs/commit/f121ae749f8f4bfe754ef2e8a6dfc286504b5b75), closes [#287](https://github.com/kbknapp/clap-rs/issues/287)) + + + + +### v1.4.2 (2015-09-23) + + +#### Bug Fixes + +* **Conflicts:** fixes bug with conflicts not removing required args ([e17fcec5](https://github.com/kbknapp/clap-rs/commit/e17fcec53b3216ad047a13dddc6f740473fad1a1), closes [#271](https://github.com/kbknapp/clap-rs/issues/271)) + + + + +### v1.4.1 (2015-09-22) + + +#### Examples + +* add clap_app quick example ([4ba6249c](https://github.com/kbknapp/clap-rs/commit/4ba6249c3cf4d2e083370d1fe4dcc7025282c28a)) + +#### Features + +* **Unicode:** allows non-panicing on invalid unicode characters ([c5bf7ddc](https://github.com/kbknapp/clap-rs/commit/c5bf7ddc8cfb876ec928a5aaf5591232bbb32e5d)) + +#### Documentation + +* properly names Examples section for rustdoc ([87ba5445](https://github.com/kbknapp/clap-rs/commit/87ba54451d7ec7b1c9b9ef134f90bbe39e6fac69)) +* fixes various typos and spelling ([f85640f9](https://github.com/kbknapp/clap-rs/commit/f85640f9f6d8fd3821a40e9b8b7a34fabb789d02)) +* **Arg:** unhides fields of the Arg struct ([931aea88](https://github.com/kbknapp/clap-rs/commit/931aea88427edf43a3da90d5a500c1ff2b2c3614)) + +#### Bug Fixes + +* flush the buffer in App::print_version() ([cbc42a37](https://github.com/kbknapp/clap-rs/commit/cbc42a37d212d84d22b1777d08e584ff191934e7)) +* Macro benchmarks ([13712da1](https://github.com/kbknapp/clap-rs/commit/13712da1d36dc7614eec3a10ad488257ba615751)) + + + + +## v1.4.0 (2015-09-09) + + +#### Features + +* allows printing help message by library consumers ([56b95f32](https://github.com/kbknapp/clap-rs/commit/56b95f320875c62dda82cb91b29059671e120ed1)) +* allows defining hidden args and subcmds ([2cab4d03](https://github.com/kbknapp/clap-rs/commit/2cab4d0334ea3c2439a1d4bfca5bf9905c7ea9ac), closes [#231](https://github.com/kbknapp/clap-rs/issues/231)) +* Builder macro to assist with App/Arg/Group/SubCommand building ([443841b0](https://github.com/kbknapp/clap-rs/commit/443841b012a8d795cd5c2bd69ae6e23ef9b16477)) +* **Errors:** allows consumers to write to stderr and exit on error ([1e6403b6](https://github.com/kbknapp/clap-rs/commit/1e6403b6a863574fa3cb6946b1fb58f034e8664c)) + + + + +### v1.3.2 (2015-09-08) + + +#### Documentation + +* fixed ErrorKind docs ([dd057843](https://github.com/kbknapp/clap-rs/commit/dd05784327fa070eb6ce5ce89a8507e011d8db94)) +* **ErrorKind:** changed examples content ([b9ca2616](https://github.com/kbknapp/clap-rs/commit/b9ca261634b89613bbf3d98fd74d55cefbb31a8c)) + +#### Bug Fixes + +* fixes a bug where the help subcommand wasn't overridable ([94003db4](https://github.com/kbknapp/clap-rs/commit/94003db4b5eebe552ca337521c1c001295822745)) + +#### Features + +* adds abiltiy not consume self when parsing matches and/or exit on help ([94003db4](https://github.com/kbknapp/clap-rs/commit/94003db4b5eebe552ca337521c1c001295822745)) +* **App:** Added ability for users to handle errors themselves ([934e6fbb](https://github.com/kbknapp/clap-rs/commit/934e6fbb643b2385efc23444fe6fce31494dc288)) + + + + +### v1.3.1 (2015-09-04) + + +#### Examples + +* **17_yaml:** fixed example ([9b848622](https://github.com/kbknapp/clap-rs/commit/9b848622296c8c5c7b9a39b93ddd41f51df790b5)) + +#### Performance + +* changes ArgGroup HashSets to Vec ([3cb4a48e](https://github.com/kbknapp/clap-rs/commit/3cb4a48ebd15c20692f4f3a2a924284dc7fd5e10)) +* changes BTreeSet for Vec in some instances ([baab2e3f](https://github.com/kbknapp/clap-rs/commit/baab2e3f4060e811abee14b1654cbcd5cf3b5fea)) + + + + +## v1.3.0 (2015-09-01) + + +#### Features + +* **YAML:** allows building a CLI from YAML files ([86cf4c45](https://github.com/kbknapp/clap-rs/commit/86cf4c45626a36b8115446952f9069f73c1debc3)) +* **ArgGroups:** adds support for building ArgGroups from yaml ([ecf88665](https://github.com/kbknapp/clap-rs/commit/ecf88665cbff367018b29161a1b75d44a212707d)) +* **Subcommands:** adds support for subcommands from yaml ([e415cf78](https://github.com/kbknapp/clap-rs/commit/e415cf78ba916052d118a8648deba2b9c16b1530)) + +#### Documentation + +* **YAML:** adds examples for using YAML to build a CLI ([ab41d7f3](https://github.com/kbknapp/clap-rs/commit/ab41d7f38219544750e6e1426076dc498073191b)) +* **Args from YAML:** fixes doc examples ([19b348a1](https://github.com/kbknapp/clap-rs/commit/19b348a10050404cd93888dbbbe4f396681b67d0)) +* **Examples:** adds better usage examples instead of having unused variables ([8cbacd88](https://github.com/kbknapp/clap-rs/commit/8cbacd8883004fe71a8ea036ec4391c7dd8efe94)) + +#### Examples + +* Add AppSettings example ([12705079](https://github.com/kbknapp/clap-rs/commit/12705079ca96a709b4dd94f7ddd20a833b26838c)) + +#### Bug Fixes + +* **Unified Help Messages:** fixes a crash from this setting and no opts ([169ffec1](https://github.com/kbknapp/clap-rs/commit/169ffec1003d58d105d7ef2585b3425e57980000), closes [#210](https://github.com/kbknapp/clap-rs/issues/210)) + + + + +### v1.2.5 (2015-08-27) + + +#### Examples + +* add custom validator example ([b9997d1f](https://github.com/kbknapp/clap-rs/commit/b9997d1fca74d4d8f93971f2a01bdf9798f913d5)) +* fix indentation ([d4f1b740](https://github.com/kbknapp/clap-rs/commit/d4f1b740ede410fd2528b9ecd89592c2fd8b1e20)) + +#### Features + +* **Args:** allows opts and args to define a name for help and usage msgs ([ad962ec4](https://github.com/kbknapp/clap-rs/commit/ad962ec478da999c7dba0afdb84c266f4d09b1bd)) + + + + +### v1.2.4 (2015-08-26) + + +#### Bug Fixes + +* **Possible Values:** fixes a bug where suggestions arent made when using --long=value format ([3d5e9a6c](https://github.com/kbknapp/clap-rs/commit/3d5e9a6cedb26668839b481c9978e2fbbab8be6f), closes [#192](https://github.com/kbknapp/clap-rs/issues/192)) + + + + +### v1.2.3 (2015-08-24) + + +#### Bug Fixes + +* **App, Args:** fixed subcommand reqs negation ([b41afa8c](https://github.com/kbknapp/clap-rs/commit/b41afa8c3ded3d1be12f7a2f8ea06cc44afc9458), closes [#188](https://github.com/kbknapp/clap-rs/issues/188)) + + + + +### v1.2.2 (2015-08-23) + + +#### Bug Fixes + +* fixed confusing error message, also added test for it ([fc7a31a7](https://github.com/kbknapp/clap-rs/commit/fc7a31a745efbf1768ee2c62cd3bb72bfe30c708)) +* **App:** fixed requirmets overriding ([9c135eb7](https://github.com/kbknapp/clap-rs/commit/9c135eb790fa16183e5bdb2009ddc3cf9e25f99f)) + + + + +### v1.2.1 (2015-08-20) + + +#### Documentation + +* **README.md:** updates for new features ([16cf9245](https://github.com/kbknapp/clap-rs/commit/16cf9245fb5fc4cf6face898e358368bf9961cbb)) + +#### Features + +* implements posix compatible conflicts for long args ([8c2d48ac](https://github.com/kbknapp/clap-rs/commit/8c2d48acf5473feebd721a9049a9c9b7051e70f9)) +* added overrides to support conflicts in POSIX compatible manner ([0b916a00](https://github.com/kbknapp/clap-rs/commit/0b916a00de26f6941538f6bc5f3365fa302083c1)) +* **Args:** allows defining POSIX compatible argument conflicts ([d715646e](https://github.com/kbknapp/clap-rs/commit/d715646e69759ccd95e01f49b04f489827ecf502)) + +#### Bug Fixes + +* fixed links in cargo and license buttons ([6d9837ad](https://github.com/kbknapp/clap-rs/commit/6d9837ad9a9e006117cd7372fdc60f9a3889c7e2)) + +#### Performance + +* **Args and Apps:** changes HashSet->Vec in some instances for increased performance ([d0c3b379](https://github.com/kbknapp/clap-rs/commit/d0c3b379700757e0a9b0c40af709f8af1f5b4949)) + + + + +### v1.2.0 (2015-08-15) + + +#### Bug Fixes + +* fixed misspell and enum name ([7df170d7](https://github.com/kbknapp/clap-rs/commit/7df170d7f4ecff06608317655d1e0c4298f62076)) +* fixed use for clap crate ([dc3ada73](https://github.com/kbknapp/clap-rs/commit/dc3ada738667d4b689678f79d14251ee82004ece)) + +#### Documentation + +* updates docs for new features ([03496547](https://github.com/kbknapp/clap-rs/commit/034965471782d872ca495045b58d34b31807c5b1)) +* fixed docs for previous changes ([ade36778](https://github.com/kbknapp/clap-rs/commit/ade367780c366425de462506d256e0f554ed3b9c)) + +#### Improvements + +* **AppSettings:** adds ability to add multiple settings at once ([4a00e251](https://github.com/kbknapp/clap-rs/commit/4a00e2510d0ca8d095d5257d51691ba3b61c1374)) + +#### Features + +* Replace application level settings with enum variants ([618dc4e2](https://github.com/kbknapp/clap-rs/commit/618dc4e2c205bf26bc43146164e65eb1f6b920ed)) +* **Args:** allows for custom argument value validations to be defined ([84ae2ddb](https://github.com/kbknapp/clap-rs/commit/84ae2ddbceda34b5cbda98a6959edaa52fde2e1a), closes [#170](https://github.com/kbknapp/clap-rs/issues/170)) + + + + +### v1.1.6 (2015-08-01) + + +#### Bug Fixes + +* fixes two bugs in App when printing newlines in help and subcommands required error ([d63c0136](https://github.com/kbknapp/clap-rs/commit/d63c0136310db9dd2b1c7b4745938311601d8938)) + + + + +### v1.1.5 (2015-07-29) + +#### Performance + +* removes some unneeded allocations ([93e915df](https://github.com/kbknapp/clap-rs/commit/93e915dfe300f7b7d6209ca93323c6a46f89a8c1)) + + +### v1.1.4 (2015-07-20) + + +#### Improvements + +* **Usage Strings** displays a [--] when it may be helpful ([86c3be85](https://github.com/kbknapp/clap-rs/commit/86c3be85fb6f77f83b5a6d2df40ae60937486984)) + +#### Bug Fixes + +* **Macros** fixes a typo in a macro generated error message ([c9195c5f](https://github.com/kbknapp/clap-rs/commit/c9195c5f92abb8cd6a37b4f4fbb2f1fee2a8e368)) +* **Type Errors** fixes formatting of error output when failed type parsing ([fe5d95c6](https://github.com/kbknapp/clap-rs/commit/fe5d95c64f3296e6eddcbec0cb8b86659800145f)) + + + + +### v1.1.3 (2015-07-18) + + +#### Documentation + +* updates README.md to include lack of color support on Windows ([52f81e17](https://github.com/kbknapp/clap-rs/commit/52f81e17377b18d2bd0f34693b642b7f358998ee)) + +#### Bug Fixes + +* fixes formatting bug which prevented compiling on windows ([9cb5dceb](https://github.com/kbknapp/clap-rs/commit/9cb5dceb3e5fe5e0e7b24619ff77e5040672b723), closes [#163](https://github.com/kbknapp/clap-rs/issues/163)) + + + + +### v1.1.2 (2015-07-17) + + +#### Bug Fixes + +* fixes a bug when parsing multiple {n} newlines inside help strings ([6d214b54](https://github.com/kbknapp/clap-rs/commit/6d214b549a9b7e189a94e5fa2b7c92cc333ca637)) + + + + +## v1.1.1 (2015-07-17) + + +#### Bug Fixes + +* fixes a logic bug and allows setting Arg::number_of_values() < 2 ([42b6d1fc](https://github.com/kbknapp/clap-rs/commit/42b6d1fc3c519c92dfb3af15276e7d3b635e6cfe), closes [#161](https://github.com/kbknapp/clap-rs/issues/161)) + + + + +## v1.1.0 (2015-07-16) + + +#### Features + +* allows creating unified help messages, a la docopt or getopts ([52bcd892](https://github.com/kbknapp/clap-rs/commit/52bcd892ea51564ce463bc5865acd64f8fe91cb1), closes [#158](https://github.com/kbknapp/clap-rs/issues/158)) +* allows stating all subcommands should *not* have --version flags ([336c476f](https://github.com/kbknapp/clap-rs/commit/336c476f631d512b54ac56fdca6f29ebdc2c00c5), closes [#156](https://github.com/kbknapp/clap-rs/issues/156)) +* allows setting version number to auto-propagate through subcommands ([bc66d3c6](https://github.com/kbknapp/clap-rs/commit/bc66d3c6deedeca62463fff95369ab1cfcdd366b), closes [#157](https://github.com/kbknapp/clap-rs/issues/157)) + +#### Improvements + +* **Help Strings** properly aligns and handles newlines in long help strings ([f9800a29](https://github.com/kbknapp/clap-rs/commit/f9800a29696dd2cc0b0284bf693b3011831e556f), closes [#145](https://github.com/kbknapp/clap-rs/issues/145)) + + +#### Performance + +* **Help Messages** big performance improvements when printing help messages ([52bcd892](https://github.com/kbknapp/clap-rs/commit/52bcd892ea51564ce463bc5865acd64f8fe91cb1)) + +#### Documentation + +* updates readme with new features ([8232f7bb](https://github.com/kbknapp/clap-rs/commit/8232f7bb52e88862bc13c3d4f99ee4f56cfe4bc0)) +* fix incorrect code example for `App::subcommand_required` ([8889689d](https://github.com/kbknapp/clap-rs/commit/8889689dc6336ccc45b2c9f2cf8e2e483a639e93)) + + + +### v1.0.3 (2015-07-11) + + +#### Improvements + +* **Errors** writes errors to stderr ([cc76ab8c](https://github.com/kbknapp/clap-rs/commit/cc76ab8c2b77c67b42f4717ded530df7806142cf), closes [#154](https://github.com/kbknapp/clap-rs/issues/154)) + +#### Documentation + +* **README.md** updates example help message to new format ([0aca29bd](https://github.com/kbknapp/clap-rs/commit/0aca29bd5d6d1a4e9971bdc88d946ffa58606efa)) + + + + +### v1.0.2 (2015-07-09) + + +#### Improvements + +* **Usage** re-orders optional arguments and required to natural standard ([dc7e1fce](https://github.com/kbknapp/clap-rs/commit/dc7e1fcea5c85d317018fb201d2a9262249131b4), closes [#147](https://github.com/kbknapp/clap-rs/issues/147)) + + + + +### v1.0.1 (2015-07-08) + + +#### Bug Fixes + +* allows empty values when using --long='' syntax ([083f82d3](https://github.com/kbknapp/clap-rs/commit/083f82d333b69720a6ef30074875310921d964d1), closes [#151](https://github.com/kbknapp/clap-rs/issues/151)) + + + + +## v1.0.0 (2015-07-08) + + +#### Documentation + +* **README.md** adds new features to what's new list ([938f7f01](https://github.com/kbknapp/clap-rs/commit/938f7f01340f521969376cf4e2e3d9436bca21f7)) +* **README.md** use with_name for subcommands ([28b7e316](https://github.com/kbknapp/clap-rs/commit/28b7e3161fb772e5309042648fe8c3a420645bac)) + +#### Features + +* args can now be parsed from arbitrary locations, not just std::env::args() ([75312528](https://github.com/kbknapp/clap-rs/commit/753125282b1b9bfff875f1557ce27610edcc59e1)) + + + + +## v1.0.0-beta (2015-06-30) + + +#### Features + +* allows waiting for user input on error ([d0da3bdd](https://github.com/kbknapp/clap-rs/commit/d0da3bdd9d1871541907ea9c645322a74d260e07), closes [#140](https://github.com/kbknapp/clap-rs/issues/140)) +* **Help** allows one to fully override the auto-generated help message ([26d5ae3e](https://github.com/kbknapp/clap-rs/commit/26d5ae3e330d1e150811d5b60b2b01a8f8df854e), closes [#141](https://github.com/kbknapp/clap-rs/issues/141)) + +#### Documentation + +* adds "whats new" section to readme ([ff149a29](https://github.com/kbknapp/clap-rs/commit/ff149a29dd9e179865e6d577cd7dc87c54f8f95c)) + +#### Improvements + +* removes deprecated functions in prep for 1.0 ([274484df](https://github.com/kbknapp/clap-rs/commit/274484dfd08fff4859cefd7e9bef3b73d3a9cb5f)) + + + + +## v0.11.0 (2015-06-17) - BREAKING CHANGE + + +#### Documentation + +* updates docs to new version flag defaults ([ebf442eb](https://github.com/kbknapp/clap-rs/commit/ebf442ebebbcd2ec6bfe2c06566c9d362bccb112)) + +#### Features + +* **Help and Version** default short for version is now `-V` but can be overridden (only breaks manual documentation) (**BREAKING CHANGE** [eb1d9320](https://github.com/kbknapp/clap-rs/commit/eb1d9320c509c1e4e57d7c7959da82bcfe06ada0)) + + + + +### v0.10.5 (2015-06-06) + + +#### Bug Fixes + +* **Global Args** global arguments propogate fully now ([1f377960](https://github.com/kbknapp/clap-rs/commit/1f377960a48c82f54ca5f39eb56bcb393140b046), closes [#137](https://github.com/kbknapp/clap-rs/issues/137)) + + + + +### v0.10.4 (2015-06-06) + + +#### Bug Fixes + +* **Global Args** global arguments propogate fully now ([8f2c0160](https://github.com/kbknapp/clap-rs/commit/8f2c0160c8d844daef375a33dbaec7d89de00a00), closes [#137](https://github.com/kbknapp/clap-rs/issues/137)) + + + + +### v0.10.3 (2015-05-31) + + +#### Bug Fixes + +* **Global Args** fixes a bug where globals only transfer to one subcommand ([a37842ee](https://github.com/kbknapp/clap-rs/commit/a37842eec1ee3162b86fdbda23420b221cdb1e3b), closes [#135](https://github.com/kbknapp/clap-rs/issues/135)) + + + + +### v0.10.2 (2015-05-30) + + +#### Improvements + +* **Binary Names** allows users to override the system determined bin name ([2191fe94](https://github.com/kbknapp/clap-rs/commit/2191fe94bda35771383b52872fb7f5421b178be1), closes [#134](https://github.com/kbknapp/clap-rs/issues/134)) + +#### Documentation + +* adds contributing guidelines ([6f76bd0a](https://github.com/kbknapp/clap-rs/commit/6f76bd0a07e8b7419b391243ab2d6687cd8a9c5f)) + + + + +### v0.10.1 (2015-05-26) + + +#### Features + +* can now specify that an app or subcommand should display help on no args or subcommands ([29ca7b2f](https://github.com/kbknapp/clap-rs/commit/29ca7b2f74376ca0cdb9d8ee3bfa99f7640cc404), closes [#133](https://github.com/kbknapp/clap-rs/issues/133)) + + + + +## v0.10.0 (2015-05-23) + + +#### Features + +* **Global Args** allows args that propagate down to child commands ([2bcc6137](https://github.com/kbknapp/clap-rs/commit/2bcc6137a83cb07757771a0afea953e68e692f0b), closes [#131](https://github.com/kbknapp/clap-rs/issues/131)) + +#### Improvements + +* **Colors** implements more structured colored output ([d6c3ed54](https://github.com/kbknapp/clap-rs/commit/d6c3ed54d21cf7b40d9f130d4280ff5448522fc5), closes [#129](https://github.com/kbknapp/clap-rs/issues/129)) + +#### Deprecations + +* **SubCommand/App** several methods and functions for stable release ([28b73855](https://github.com/kbknapp/clap-rs/commit/28b73855523ad170544afdb20665db98702fbe70)) + +#### Documentation + +* updates for deprecations and new features ([743eefe8](https://github.com/kbknapp/clap-rs/commit/743eefe8dd40c1260065ce086d572e9e9358bc4c)) + + + + +## v0.9.2 (2015-05-20) + + +#### Bug Fixes + +* **help** allows parent requirements to be ignored with help and version ([52218cc1](https://github.com/kbknapp/clap-rs/commit/52218cc1fdb06a42456c964d98cc2c7ac3432412), closes [#124](https://github.com/kbknapp/clap-rs/issues/124)) + + + + +## v0.9.1 (2015-05-18) + + +#### Bug Fixes + +* **help** fixes a bug where requirements are included as program name in help and version ([08ba3f25](https://github.com/kbknapp/clap-rs/commit/08ba3f25cf38b149229ba8b9cb37a5804fe6b789)) + + + + +## v0.9.0 (2015-05-17) + + +#### Improvements + +* **usage** usage strings now include parent command requirements ([dd8f21c7](https://github.com/kbknapp/clap-rs/commit/dd8f21c7c15cde348fdcf44fa7c205f0e98d2e4a), closes [#125](https://github.com/kbknapp/clap-rs/issues/125)) +* **args** allows consumer of clap to decide if empty values are allowed or not ([ab4ec609](https://github.com/kbknapp/clap-rs/commit/ab4ec609ccf692b9b72cccef5c9f74f5577e360d), closes [#122](https://github.com/kbknapp/clap-rs/issues/122)) + +#### Features + +* **subcommands** + * allows optionally specifying that no subcommand is an error ([7554f238](https://github.com/kbknapp/clap-rs/commit/7554f238fd3afdd60b7e4dcf00ff4a9eccf842c1), closes [#126](https://github.com/kbknapp/clap-rs/issues/126)) + * subcommands can optionally negate parent requirements ([4a4229f5](https://github.com/kbknapp/clap-rs/commit/4a4229f500e21c350e1ef78dd09ef27559653288), closes [#123](https://github.com/kbknapp/clap-rs/issues/123)) + + + + +## v0.8.6 (2015-05-17) + + +#### Bug Fixes + +* **args** `-` can now be parsed as a value for an argument ([bc12e78e](https://github.com/kbknapp/clap-rs/commit/bc12e78eadd7eaf9d008a8469fdd2dfd7990cb5d), closes [#121](https://github.com/kbknapp/clap-rs/issues/121)) + + + + +## v0.8.5 (2015-05-15) + + +#### Bug Fixes + +* **macros** makes macro errors consistent with others ([0c264a8c](https://github.com/kbknapp/clap-rs/commit/0c264a8ca57ec1cfdcb74dae79145d766cdc9b97), closes [#118](https://github.com/kbknapp/clap-rs/issues/118)) + +#### Features + +* **macros** + * arg_enum! and simple_enum! provide a Vec<&str> of variant names ([30fa87ba](https://github.com/kbknapp/clap-rs/commit/30fa87ba4e0f3189351d8f4f78b72e616a30d0bd), closes [#119](https://github.com/kbknapp/clap-rs/issues/119)) + * arg_enum! and simple_enum! auto-implement Display ([d1219f0d](https://github.com/kbknapp/clap-rs/commit/d1219f0d1371d872061bd0718057eca4ef47b739), closes [#120](https://github.com/kbknapp/clap-rs/issues/120)) + + + + +## v0.8.4 (2015-05-12) + + +#### Bug Fixes + +* **suggestions** --help and --version now get suggestions ([d2b3b1fa](https://github.com/kbknapp/clap-rs/commit/d2b3b1faa0bdc1c5d2350cc4635aba81e02e9d96), closes [#116](https://github.com/kbknapp/clap-rs/issues/116)) + + + + +## v0.8.3 (2015-05-10) + + +#### Bug Fixes + +* **usage** groups unfold their members in usage strings ([55d15582](https://github.com/kbknapp/clap-rs/commit/55d155827ea4a6b077a83669701e797ce1ad68f4), closes [#114](https://github.com/kbknapp/clap-rs/issues/114)) + +#### Performance + +* **usage** removes unneeded allocations ([fd53cd18](https://github.com/kbknapp/clap-rs/commit/fd53cd188555f5c3dc8bc341c5d7eb04b761a70f)) + + + + +## v0.8.2 (2015-05-08) + + +#### Bug Fixes + +* **usage strings** positional arguments are presented in index order ([eb0e374e](https://github.com/kbknapp/clap-rs/commit/eb0e374ecf952f1eefbc73113f21e0705936e40b), closes [#112](https://github.com/kbknapp/clap-rs/issues/112)) + + + + +## v0.8.1 (2015-05-06) + + +#### Bug Fixes + +* **subcommands** stops parsing multiple values when subcommands are found ([fc79017e](https://github.com/kbknapp/clap-rs/commit/fc79017eced04fd41cc1801331e5054df41fac17), closes [#109](https://github.com/kbknapp/clap-rs/issues/109)) + +#### Improvements + +* **color** reduces color in error messages ([aab44cca](https://github.com/kbknapp/clap-rs/commit/aab44cca6352f47e280c296e50c535f5d752dd46), closes [#110](https://github.com/kbknapp/clap-rs/issues/110)) +* **suggestions** adds suggested arguments to usage strings ([99447414](https://github.com/kbknapp/clap-rs/commit/994474146e9fb8b701af773a52da71553d74d4b7)) + + + + +## v0.8.0 (2015-05-06) + + +#### Bug Fixes + +* **did-you-mean** for review ([0535cfb0](https://github.com/kbknapp/clap-rs/commit/0535cfb0c711331568b4de8080eeef80bd254b68)) +* **Positional** positionals were ignored if they matched a subcmd, even after '--' ([90e7b081](https://github.com/kbknapp/clap-rs/commit/90e7b0818741668b47cbe3becd029bab588e3553)) +* **help** fixes bug where space between arg and help is too long ([632fb115](https://github.com/kbknapp/clap-rs/commit/632fb11514c504999ea86bdce47cdd34f8ebf646)) + +#### Features + +* **from_usage** adds ability to add value names or num of vals in usage string ([3d581976](https://github.com/kbknapp/clap-rs/commit/3d58197674ed7886ca315efb76e411608a327501), closes [#98](https://github.com/kbknapp/clap-rs/issues/98)) +* **did-you-mean** + * gate it behind 'suggestions' ([c0e38351](https://github.com/kbknapp/clap-rs/commit/c0e383515d01bdd5ca459af9c2f7e2cf49e2488b)) + * for possible values ([1cc2deb2](https://github.com/kbknapp/clap-rs/commit/1cc2deb29158e0e4e8b434e4ce26b3d819301a7d)) + * for long flags (i.e. --long) ([52a0b850](https://github.com/kbknapp/clap-rs/commit/52a0b8505c99354bdf5fd1cd256cf41197ac2d81)) + * for subcommands ([06e869b5](https://github.com/kbknapp/clap-rs/commit/06e869b5180258047ed3c60ba099de818dd25fff)) +* **Flags** adds sugestions functionality ([8745071c](https://github.com/kbknapp/clap-rs/commit/8745071c3257dd327c497013516f12a823df9530)) +* **errors** colorizes output red on error ([f8b26b13](https://github.com/kbknapp/clap-rs/commit/f8b26b13da82ba3ba9a932d3d1ab4ea45d1ab036)) + +#### Improvements + +* **arg_enum** allows ascii case insensitivity for enum variants ([b249f965](https://github.com/kbknapp/clap-rs/commit/b249f9657c6921c004764bd80d13ebca81585eec), closes [#104](https://github.com/kbknapp/clap-rs/issues/104)) +* **clap-test** simplified `make test` invocation ([d17dcb29](https://github.com/kbknapp/clap-rs/commit/d17dcb2920637a1f58c61c596b7bd362fd53047c)) + +#### Documentation + +* **README** adds details about optional and new features ([960389de](https://github.com/kbknapp/clap-rs/commit/960389de02c9872aaee9adabe86987f71f986e39)) +* **clap** fix typos caught by codespell ([8891d929](https://github.com/kbknapp/clap-rs/commit/8891d92917aa1a069cca67272be41b99e548356e)) +* **from_usage** explains new usage strings with multiple values ([05476fc6](https://github.com/kbknapp/clap-rs/commit/05476fc61cd1e5f4a4e750d258c878732a3a9c64)) + + + + +## v0.7.6 (2015-05-05) + + +#### Improvements + +* **Options** adds number of values to options in help/usage ([c1c993c4](https://github.com/kbknapp/clap-rs/commit/c1c993c419d18e35c443785053d8de9a2ef88073)) + +#### Features + +* **from_usage** adds ability to add value names or num of vals in usage string ([ad55748c](https://github.com/kbknapp/clap-rs/commit/ad55748c265cf27935c7b210307d2040b6a09125), closes [#98](https://github.com/kbknapp/clap-rs/issues/98)) + +#### Bug Fixes + +* **MultipleValues** properly distinguishes between multiple values and multiple occurrences ([dd2a7564](https://github.com/kbknapp/clap-rs/commit/dd2a75640ca68a91b973faad15f04df891356cef), closes [#99](https://github.com/kbknapp/clap-rs/issues/99)) +* **help** fixes tab alignment with multiple values ([847001ff](https://github.com/kbknapp/clap-rs/commit/847001ff6d8f4d9518e810fefb8edf746dd0f31e)) + +#### Documentation + +* **from_usage** explains new usage strings with multiple values ([5a3a42df](https://github.com/kbknapp/clap-rs/commit/5a3a42dfa3a783537f88dedc0fd5f0edcb8ea372)) + + + + +## v0.7.5 (2015-05-04) + + +#### Bug Fixes + +* **Options** fixes bug where options with no value don't error out ([a1fb94be](https://github.com/kbknapp/clap-rs/commit/a1fb94be53141572ffd97aad037295d4ffec82d0)) + + + + +## v0.7.4 (2015-05-03) + + +#### Bug Fixes + +* **Options** fixes a bug where option arguments in succession get their values skipped ([f66334d0](https://github.com/kbknapp/clap-rs/commit/f66334d0ce984e2b56e5c19abb1dd536fae9342a)) + + + + +## v0.7.3 (2015-05-03) + + +#### Bug Fixes + +* **RequiredValues** fixes a bug where missing values are parsed as missing arguments ([93c4a723](https://github.com/kbknapp/clap-rs/commit/93c4a7231ba1a08152648598f7aa4503ea82e4de)) + +#### Improvements + +* **ErrorMessages** improves error messages and corrections ([a29c3983](https://github.com/kbknapp/clap-rs/commit/a29c3983c4229906655a29146ec15a0e46dd942d)) +* **ArgGroups** improves requirement and confliction support for groups ([c236dc5f](https://github.com/kbknapp/clap-rs/commit/c236dc5ff475110d2a1b80e62903f80296163ad3)) + + + + +## v0.7.2 (2015-05-03) + + +#### Bug Fixes + +* **RequiredArgs** fixes bug where required-by-default arguments are not listed in usage ([12aea961](https://github.com/kbknapp/clap-rs/commit/12aea9612d290845ba86515c240aeeb0a21198db), closes [#96](https://github.com/kbknapp/clap-rs/issues/96)) + + + + +## v0.7.1 (2015-05-01) + + +#### Bug Fixes + +* **MultipleValues** stops evaluating values if the max or exact number of values was reached ([86d92c9f](https://github.com/kbknapp/clap-rs/commit/86d92c9fdbf9f422442e9562977bbaf268dbbae1)) + + + + +## v0.7.0 (2015-04-30) - BREAKING CHANGE + + +#### Bug Fixes + +* **from_usage** removes bug where usage strings have no help text ([ad4e5451](https://github.com/kbknapp/clap-rs/commit/ad4e54510739aeabf75f0da3278fb0952db531b3), closes [#83](https://github.com/kbknapp/clap-rs/issues/83)) + +#### Features + +* **MultipleValues** + * add support for minimum and maximum number of values ([53f6b8c9](https://github.com/kbknapp/clap-rs/commit/53f6b8c9d8dc408b4fa9f833fc3a63683873c42f)) + * adds support limited number and named values ([ae09f05e](https://github.com/kbknapp/clap-rs/commit/ae09f05e92251c1b39a83d372736fcc7b504e432)) + * implement shorthand for options with multiple values ([6669f0a9](https://github.com/kbknapp/clap-rs/commit/6669f0a9687d4f668523145d7bd5c007d1eb59a8)) +* **arg** allow other types besides Vec for multiple value settings (**BREAKING CHANGE** [0cc2f698](https://github.com/kbknapp/clap-rs/commit/0cc2f69839b9b1db5d06330771b494783049a88e), closes [#87](https://github.com/kbknapp/clap-rs/issues/87)) +* **usage** implement smart usage strings on errors ([d77048ef](https://github.com/kbknapp/clap-rs/commit/d77048efb1e595ffe831f1a2bea2f2700db53b9f), closes [#88](https://github.com/kbknapp/clap-rs/issues/88)) + + + + +## v0.6.9 (2015-04-29) + + +#### Bug Fixes + +* **from_usage** removes bug where usage strings have no help text ([ad4e5451](https://github.com/kbknapp/clap-rs/commit/ad4e54510739aeabf75f0da3278fb0952db531b3), closes [#83](https://github.com/kbknapp/clap-rs/issues/83)) + + + + +## 0.6.8 (2015-04-27) + + +#### Bug Fixes + +* **help** change long help --long=long -> --long ([1e25abfc](https://github.com/kbknapp/clap-rs/commit/1e25abfc36679ab89eae71bf98ced4de81992d00)) +* **RequiredArgs** required by default args should no longer be required when their exclusions are present ([4bb4c3cc](https://github.com/kbknapp/clap-rs/commit/4bb4c3cc076b49e86720e882bf8c489877199f2d)) + +#### Features + +* **ArgGroups** add ability to create arg groups ([09eb4d98](https://github.com/kbknapp/clap-rs/commit/09eb4d9893af40c347e50e2b717e1adef552357d)) + + + + +## v0.6.7 (2015-04-22) + + +#### Bug Fixes + +* **from_usage** fix bug causing args to not be required ([b76129e9](https://github.com/kbknapp/clap-rs/commit/b76129e9b71a63365d5c77a7f57b58dbd1e94d49)) + +#### Features + +* **apps** add ability to display additional help info after auto-gen'ed help msg ([65cc259e](https://github.com/kbknapp/clap-rs/commit/65cc259e4559cbe3653c865ec0c4b1e42a389b07)) + + + + +## v0.6.6 (2015-04-19) + + +#### Bug Fixes + +* **from_usage** tabs and spaces should be treated equally ([4fd44181](https://github.com/kbknapp/clap-rs/commit/4fd44181d55d8eb88caab1e625231cfa3129e347)) + +#### Features + +* **macros.rs** add macro to get version from Cargo.toml ([c630969a](https://github.com/kbknapp/clap-rs/commit/c630969aa3bbd386379219cae27ba1305b117f3e)) + + + + +## v0.6.5 (2015-04-19) + + +#### Bug Fixes + +* **macros.rs** fix use statements for trait impls ([86e4075e](https://github.com/kbknapp/clap-rs/commit/86e4075eb111937c8a7bdb344e866e350429f042)) + + + + +## v0.6.4 (2015-04-17) + + +#### Features + +* **macros** add ability to create enums pub or priv with derives ([2c499f80](https://github.com/kbknapp/clap-rs/commit/2c499f8015a199827cdf1fa3ec4f6f171722f8c7)) + + + + +## v0.6.3 (2015-04-16) + + +#### Features + +* **macros** add macro to create custom enums to use as types ([fb672aff](https://github.com/kbknapp/clap-rs/commit/fb672aff561c29db2e343d6c607138f141aca8b6)) + + + + +## v0.6.2 (2015-04-14) + + +#### Features + +* **macros** + * add ability to get multiple typed values or exit ([0b87251f](https://github.com/kbknapp/clap-rs/commit/0b87251fc088234bee51c323c2b652d7254f7a59)) + * add ability to get a typed multiple values ([e243fe38](https://github.com/kbknapp/clap-rs/commit/e243fe38ddbbf845a46c0b9baebaac3778c80927)) + * add convenience macro to get a typed value or exit ([4b7cd3ea](https://github.com/kbknapp/clap-rs/commit/4b7cd3ea4947780d9daa39f3e1ddab53ad4c7fef)) + * add convenience macro to get a typed value ([8752700f](https://github.com/kbknapp/clap-rs/commit/8752700fbb30e89ee68adbce24489ae9a24d33a9)) + + + + +## v0.6.1 (2015-04-13) + + +#### Bug Fixes + +* **from_usage** trim all whitespace before parsing ([91d29045](https://github.com/kbknapp/clap-rs/commit/91d2904599bd602deef2e515dfc65dc2863bdea0)) + + + + +## v0.6.0 (2015-04-13) + + +#### Bug Fixes + +* **tests** fix failing doc tests ([3710cd69](https://github.com/kbknapp/clap-rs/commit/3710cd69162f87221a62464f63437c1ce843ad3c)) + +#### Features + +* **app** add support for building args from usage strings ([d5d48bcf](https://github.com/kbknapp/clap-rs/commit/d5d48bcf463a4e494ef758836bd69a4c220bbbb5)) +* **args** add ability to create basic arguments from a usage string ([ab409a8f](https://github.com/kbknapp/clap-rs/commit/ab409a8f1db9e37cc70200f6f4a84a162692e618)) + + + + +## v0.5.14 (2015-04-10) + + +#### Bug Fixes + +* **usage** + * remove unneeded space ([51372789](https://github.com/kbknapp/clap-rs/commit/5137278942121bc2593ce6e5dc224ec2682549e6)) + * remove warning about unused variables ([ba817b9d](https://github.com/kbknapp/clap-rs/commit/ba817b9d815e37320650973f1bea0e7af3030fd7)) + +#### Features + +* **usage** add ability to get usage string for subcommands too ([3636afc4](https://github.com/kbknapp/clap-rs/commit/3636afc401c2caa966efb5b1869ef4f1ed3384aa)) + + + + +## v0.5.13 (2015-04-09) + + +#### Features + +* **SubCommands** add method to get name and subcommand matches together ([64e53928](https://github.com/kbknapp/clap-rs/commit/64e539280e23e567cf5de393b346eb0ca20e7eb5)) +* **ArgMatches** add method to get default usage string ([02462150](https://github.com/kbknapp/clap-rs/commit/02462150ca750bdc7012627d7e8d96379d494d7f)) + + + + +## v0.5.12 (2015-04-08) + + +#### Features + +* **help** sort arguments by name so as to not display a random order ([f4b2bf57](https://github.com/kbknapp/clap-rs/commit/f4b2bf5767386013069fb74862e6e938dacf44d2)) + + + + +## v0.5.11 (2015-04-08) + + +#### Bug Fixes + +* **flags** fix bug not allowing users to specify -v or -h ([90e72cff](https://github.com/kbknapp/clap-rs/commit/90e72cffdee321b79eea7a2207119533540062b4)) + + + + +## v0.5.10 (2015-04-08) + + +#### Bug Fixes + +* **help** fix spacing when option argument has not long version ([ca17fa49](https://github.com/kbknapp/clap-rs/commit/ca17fa494b68e92da83ee364bf64b0687006824b)) + + + + +## v0.5.9 (2015-04-08) + + +#### Bug Fixes + +* **positional args** all previous positional args become required when a latter one is required ([c14c3f31](https://github.com/kbknapp/clap-rs/commit/c14c3f31fd557c165570b60911d8ee483d89d6eb), closes [#50](https://github.com/kbknapp/clap-rs/issues/50)) +* **clap** remove unstable features for Rust 1.0 ([9abdb438](https://github.com/kbknapp/clap-rs/commit/9abdb438e36e364d41550e7f5d44ebcaa8ee6b10)) +* **args** improve error messages for arguments with mutual exclusions ([18dbcf37](https://github.com/kbknapp/clap-rs/commit/18dbcf37024daf2b76ca099a6f118b53827aa339), closes [#51](https://github.com/kbknapp/clap-rs/issues/51)) + + + + +## v0.5.8 (2015-04-08) + + +#### Bug Fixes + +* **option args** fix bug in getting the wrong number of occurrences for options ([82ad6ad7](https://github.com/kbknapp/clap-rs/commit/82ad6ad77539cf9f9a03b78db466f575ebd972cc)) +* **help** fix formatting for option arguments with no long ([e8691004](https://github.com/kbknapp/clap-rs/commit/e869100423d93fa3acff03c4620cbcc0d0e790a1)) +* **flags** add assertion to catch flags with specific value sets ([a0a2a40f](https://github.com/kbknapp/clap-rs/commit/a0a2a40fed57f7c5ad9d68970d090e9856306c7d), closes [#52](https://github.com/kbknapp/clap-rs/issues/52)) +* **args** improve error messages for arguments with mutual exclusions ([bff945fc](https://github.com/kbknapp/clap-rs/commit/bff945fc5d03bba4266533340adcffb002508d1b), closes [#51](https://github.com/kbknapp/clap-rs/issues/51)) +* **tests** add missing .takes_value(true) to option2 ([bdb0e88f](https://github.com/kbknapp/clap-rs/commit/bdb0e88f696c8595c3def3bfb0e52d538c7be085)) +* **positional args** all previous positional args become required when a latter one is required ([343d47dc](https://github.com/kbknapp/clap-rs/commit/343d47dcbf83786a45c0d0f01b27fd9dd76725de), closes [#50](https://github.com/kbknapp/clap-rs/issues/50)) + + + + +## v0.5.7 (2015-04-08) + + +#### Bug Fixes + +* **args** fix bug in arguments who are required and mutually exclusive ([6ceb88a5](https://github.com/kbknapp/clap-rs/commit/6ceb88a594caae825605abc1cdad95204996bf29)) + + + + +## v0.5.6 (2015-04-08) + + +#### Bug Fixes + +* **help** fix formatting of help and usage ([28691b52](https://github.com/kbknapp/clap-rs/commit/28691b52f67e65c599e10e4ea2a0f6f9765a06b8)) + + + + +## v0.5.5 (2015-04-08) + + +#### Bug Fixes + +* **help** fix formatting of help for flags and options ([6ec10115](https://github.com/kbknapp/clap-rs/commit/6ec1011563a746f0578a93b76d45e63878e0f9a8)) + + + + +## v0.5.4 (2015-04-08) + + +#### Features + +* **help** add '...' to indicate multiple values supported ([297ddba7](https://github.com/kbknapp/clap-rs/commit/297ddba77000e2228762ab0eca50b480f7467386)) + + + + +## v0.5.3 (2015-04-08) + + +#### Features + +* **positionals** + * add assertions for positional args with multiple vals ([b7fa72d4](https://github.com/kbknapp/clap-rs/commit/b7fa72d40f18806ec2042dd67a518401c2cf5681)) + * add support for multiple values ([80784009](https://github.com/kbknapp/clap-rs/commit/807840094109fbf90b348039ae22669ef27889ba)) + + + + +## v0.5.2 (2015-04-08) + + +#### Bug Fixes + +* **apps** allow use of hyphens in application and subcommand names ([da549dcb](https://github.com/kbknapp/clap-rs/commit/da549dcb6c7e0d773044ab17829744483a8b0f7f)) + + + + +## v0.5.1 (2015-04-08) + + +#### Bug Fixes + +* **args** determine if the only arguments allowed are also required ([0a09eb36](https://github.com/kbknapp/clap-rs/commit/0a09eb365ced9a03faf8ed24f083ef730acc90e8)) + + + + +## v0.5.0 (2015-04-08) + + +#### Features + +* **args** add support for a specific set of allowed values on options or positional arguments ([270eb889](https://github.com/kbknapp/clap-rs/commit/270eb88925b6dc2881bff1f31ee344f085d31809)) + + + + +## v0.4.18 (2015-04-08) + + +#### Bug Fixes + +* **usage** display required args in usage, even if only required by others ([1b7316d4](https://github.com/kbknapp/clap-rs/commit/1b7316d4a8df70b0aa584ccbfd33f68966ad2a54)) + +#### Features + +* **subcommands** properly list subcommands in help and usage ([4ee02344](https://github.com/kbknapp/clap-rs/commit/4ee023442abc3dba54b68138006a52b714adf331)) + + + + +## v0.4.17 (2015-04-08) + + +#### Bug Fixes + +* **tests** remove cargo test from claptests makefile ([1cf73817](https://github.com/kbknapp/clap-rs/commit/1cf73817d6fb1dccb5b6a23b46c2efa8b567ad62)) + + + + +## v0.4.16 (2015-04-08) + + +#### Bug Fixes + +* **option** fix bug with option occurrence values ([9af52e93](https://github.com/kbknapp/clap-rs/commit/9af52e93cef9e17ac9974963f132013d0b97b946)) +* **tests** fix testing script bug and formatting ([d8f03a55](https://github.com/kbknapp/clap-rs/commit/d8f03a55c4f74d126710ee06aad5a667246a8001)) + +#### Features + +* **arg** allow lifetimes other than 'static in arguments ([9e8c1fb9](https://github.com/kbknapp/clap-rs/commit/9e8c1fb9406f8448873ca58bab07fe905f1551e5)) diff --git a/vendor/clap-2.34.0/CONTRIBUTORS.md b/vendor/clap-2.34.0/CONTRIBUTORS.md new file mode 100644 index 0000000000000..f0fd77724435d --- /dev/null +++ b/vendor/clap-2.34.0/CONTRIBUTORS.md @@ -0,0 +1,91 @@ +the following is a list of contributors: + + +[kbknapp](https://github.com/kbknapp) |[homu](https://github.com/homu) |[Vinatorul](https://github.com/Vinatorul) |[tormol](https://github.com/tormol) |[willmurphyscode](https://github.com/willmurphyscode) |[little-dude](https://github.com/little-dude) | +:---: |:---: |:---: |:---: |:---: |:---: | +[kbknapp](https://github.com/kbknapp) |[homu](https://github.com/homu) |[Vinatorul](https://github.com/Vinatorul) |[tormol](https://github.com/tormol) |[willmurphyscode](https://github.com/willmurphyscode) |[little-dude](https://github.com/little-dude) | + +[sru](https://github.com/sru) |[mgeisler](https://github.com/mgeisler) |[nabijaczleweli](https://github.com/nabijaczleweli) |[Byron](https://github.com/Byron) |[hgrecco](https://github.com/hgrecco) |[bluejekyll](https://github.com/bluejekyll) | +:---: |:---: |:---: |:---: |:---: |:---: | +[sru](https://github.com/sru) |[mgeisler](https://github.com/mgeisler) |[nabijaczleweli](https://github.com/nabijaczleweli) |[Byron](https://github.com/Byron) |[hgrecco](https://github.com/hgrecco) |[bluejekyll](https://github.com/bluejekyll) | + +[segevfiner](https://github.com/segevfiner) |[ignatenkobrain](https://github.com/ignatenkobrain) |[james-darkfox](https://github.com/james-darkfox) |[H2CO3](https://github.com/H2CO3) |[nateozem](https://github.com/nateozem) |[glowing-chemist](https://github.com/glowing-chemist) | +:---: |:---: |:---: |:---: |:---: |:---: | +[segevfiner](https://github.com/segevfiner) |[ignatenkobrain](https://github.com/ignatenkobrain) |[james-darkfox](https://github.com/james-darkfox) |[H2CO3](https://github.com/H2CO3) |[nateozem](https://github.com/nateozem) |[glowing-chemist](https://github.com/glowing-chemist) | + +[discosultan](https://github.com/discosultan) |[rtaycher](https://github.com/rtaycher) |[Arnavion](https://github.com/Arnavion) |[japaric](https://github.com/japaric) |[untitaker](https://github.com/untitaker) |[afiune](https://github.com/afiune) | +:---: |:---: |:---: |:---: |:---: |:---: | +[discosultan](https://github.com/discosultan) |[rtaycher](https://github.com/rtaycher) |[Arnavion](https://github.com/Arnavion) |[japaric](https://github.com/japaric) |[untitaker](https://github.com/untitaker) |[afiune](https://github.com/afiune) | + +[crazymerlyn](https://github.com/crazymerlyn) |[SuperFluffy](https://github.com/SuperFluffy) |[matthiasbeyer](https://github.com/matthiasbeyer) |[malbarbo](https://github.com/malbarbo) |[tshepang](https://github.com/tshepang) |[golem131](https://github.com/golem131) | +:---: |:---: |:---: |:---: |:---: |:---: | +[crazymerlyn](https://github.com/crazymerlyn) |[SuperFluffy](https://github.com/SuperFluffy) |[matthiasbeyer](https://github.com/matthiasbeyer) |[malbarbo](https://github.com/malbarbo) |[tshepang](https://github.com/tshepang) |[golem131](https://github.com/golem131) | + +[jimmycuadra](https://github.com/jimmycuadra) |[Nemo157](https://github.com/Nemo157) |[severen](https://github.com/severen) |[Eijebong](https://github.com/Eijebong) |[cstorey](https://github.com/cstorey) |[wdv4758h](https://github.com/wdv4758h) | +:---: |:---: |:---: |:---: |:---: |:---: | +[jimmycuadra](https://github.com/jimmycuadra) |[Nemo157](https://github.com/Nemo157) |[severen](https://github.com/severen) |[Eijebong](https://github.com/Eijebong) |[cstorey](https://github.com/cstorey) |[wdv4758h](https://github.com/wdv4758h) | + +[frewsxcv](https://github.com/frewsxcv) |[hoodie](https://github.com/hoodie) |[huonw](https://github.com/huonw) |[GrappigPanda](https://github.com/GrappigPanda) |[shepmaster](https://github.com/shepmaster) |[starkat99](https://github.com/starkat99) | +:---: |:---: |:---: |:---: |:---: |:---: | +[frewsxcv](https://github.com/frewsxcv) |[hoodie](https://github.com/hoodie) |[huonw](https://github.com/huonw) |[GrappigPanda](https://github.com/GrappigPanda) |[shepmaster](https://github.com/shepmaster) |[starkat99](https://github.com/starkat99) | + +[porglezomp](https://github.com/porglezomp) |[kraai](https://github.com/kraai) |[musoke](https://github.com/musoke) |[nelsonjchen](https://github.com/nelsonjchen) |[pkgw](https://github.com/pkgw) |[Deedasmi](https://github.com/Deedasmi) | +:---: |:---: |:---: |:---: |:---: |:---: | +[porglezomp](https://github.com/porglezomp) |[kraai](https://github.com/kraai) |[musoke](https://github.com/musoke) |[nelsonjchen](https://github.com/nelsonjchen) |[pkgw](https://github.com/pkgw) |[Deedasmi](https://github.com/Deedasmi) | + +[vmchale](https://github.com/vmchale) |[etopiei](https://github.com/etopiei) |[messense](https://github.com/messense) |[Keats](https://github.com/Keats) |[kieraneglin](https://github.com/kieraneglin) |[durka](https://github.com/durka) | +:---: |:---: |:---: |:---: |:---: |:---: | +[vmchale](https://github.com/vmchale) |[etopiei](https://github.com/etopiei) |[messense](https://github.com/messense) |[Keats](https://github.com/Keats) |[kieraneglin](https://github.com/kieraneglin) |[durka](https://github.com/durka) | + +[alex-gulyas](https://github.com/alex-gulyas) |[cite-reader](https://github.com/cite-reader) |[alexbool](https://github.com/alexbool) |[AluisioASG](https://github.com/AluisioASG) |[BurntSushi](https://github.com/BurntSushi) |[AndrewGaspar](https://github.com/AndrewGaspar) | +:---: |:---: |:---: |:---: |:---: |:---: | +[alex-gulyas](https://github.com/alex-gulyas) |[cite-reader](https://github.com/cite-reader) |[alexbool](https://github.com/alexbool) |[AluisioASG](https://github.com/AluisioASG) |[BurntSushi](https://github.com/BurntSushi) |[AndrewGaspar](https://github.com/AndrewGaspar) | + +[nox](https://github.com/nox) |[mitsuhiko](https://github.com/mitsuhiko) |[pixelistik](https://github.com/pixelistik) |[ogham](https://github.com/ogham) |[Bilalh](https://github.com/Bilalh) |[dotdash](https://github.com/dotdash) | +:---: |:---: |:---: |:---: |:---: |:---: | +[nox](https://github.com/nox) |[mitsuhiko](https://github.com/mitsuhiko) |[pixelistik](https://github.com/pixelistik) |[ogham](https://github.com/ogham) |[Bilalh](https://github.com/Bilalh) |[dotdash](https://github.com/dotdash) | + +[bradurani](https://github.com/bradurani) |[Seeker14491](https://github.com/Seeker14491) |[brianp](https://github.com/brianp) |[cldershem](https://github.com/cldershem) |[casey](https://github.com/casey) |[volks73](https://github.com/volks73) | +:---: |:---: |:---: |:---: |:---: |:---: | +[bradurani](https://github.com/bradurani) |[Seeker14491](https://github.com/Seeker14491) |[brianp](https://github.com/brianp) |[cldershem](https://github.com/cldershem) |[casey](https://github.com/casey) |[volks73](https://github.com/volks73) | + +[daboross](https://github.com/daboross) |[da-x](https://github.com/da-x) |[mernen](https://github.com/mernen) |[dguo](https://github.com/dguo) |[davidszotten](https://github.com/davidszotten) |[drusellers](https://github.com/drusellers) | +:---: |:---: |:---: |:---: |:---: |:---: | +[daboross](https://github.com/daboross) |[da-x](https://github.com/da-x) |[mernen](https://github.com/mernen) |[dguo](https://github.com/dguo) |[davidszotten](https://github.com/davidszotten) |[drusellers](https://github.com/drusellers) | + +[eddyb](https://github.com/eddyb) |[Enet4](https://github.com/Enet4) |[Fraser999](https://github.com/Fraser999) |[birkenfeld](https://github.com/birkenfeld) |[guanqun](https://github.com/guanqun) |[tanakh](https://github.com/tanakh) | +:---: |:---: |:---: |:---: |:---: |:---: | +[eddyb](https://github.com/eddyb) |[Enet4](https://github.com/Enet4) |[Fraser999](https://github.com/Fraser999) |[birkenfeld](https://github.com/birkenfeld) |[guanqun](https://github.com/guanqun) |[tanakh](https://github.com/tanakh) | + +[SirVer](https://github.com/SirVer) |[idmit](https://github.com/idmit) |[archer884](https://github.com/archer884) |[jacobmischka](https://github.com/jacobmischka) |[jespino](https://github.com/jespino) |[jfrankenau](https://github.com/jfrankenau) | +:---: |:---: |:---: |:---: |:---: |:---: | +[SirVer](https://github.com/SirVer) |[idmit](https://github.com/idmit) |[archer884](https://github.com/archer884) |[jacobmischka](https://github.com/jacobmischka) |[jespino](https://github.com/jespino) |[jfrankenau](https://github.com/jfrankenau) | + +[jtdowney](https://github.com/jtdowney) |[andete](https://github.com/andete) |[joshtriplett](https://github.com/joshtriplett) |[Kalwyn](https://github.com/Kalwyn) |[manuel-rhdt](https://github.com/manuel-rhdt) |[Marwes](https://github.com/Marwes) | +:---: |:---: |:---: |:---: |:---: |:---: | +[jtdowney](https://github.com/jtdowney) |[andete](https://github.com/andete) |[joshtriplett](https://github.com/joshtriplett) |[Kalwyn](https://github.com/Kalwyn) |[manuel-rhdt](https://github.com/manuel-rhdt) |[Marwes](https://github.com/Marwes) | + +[mdaffin](https://github.com/mdaffin) |[iliekturtles](https://github.com/iliekturtles) |[nicompte](https://github.com/nicompte) |[NickeZ](https://github.com/NickeZ) |[nvzqz](https://github.com/nvzqz) |[nuew](https://github.com/nuew) | +:---: |:---: |:---: |:---: |:---: |:---: | +[mdaffin](https://github.com/mdaffin) |[iliekturtles](https://github.com/iliekturtles) |[nicompte](https://github.com/nicompte) |[NickeZ](https://github.com/NickeZ) |[nvzqz](https://github.com/nvzqz) |[nuew](https://github.com/nuew) | + +[Geogi](https://github.com/Geogi) |[focusaurus](https://github.com/focusaurus) |[flying-sheep](https://github.com/flying-sheep) |[Phlosioneer](https://github.com/Phlosioneer) |[peppsac](https://github.com/peppsac) |[golddranks](https://github.com/golddranks) | +:---: |:---: |:---: |:---: |:---: |:---: | +[Geogi](https://github.com/Geogi) |[focusaurus](https://github.com/focusaurus) |[flying-sheep](https://github.com/flying-sheep) |[Phlosioneer](https://github.com/Phlosioneer) |[peppsac](https://github.com/peppsac) |[golddranks](https://github.com/golddranks) | + +[hexjelly](https://github.com/hexjelly) |[rom1v](https://github.com/rom1v) |[rnelson](https://github.com/rnelson) |[swatteau](https://github.com/swatteau) |[tchajed](https://github.com/tchajed) |[tspiteri](https://github.com/tspiteri) | +:---: |:---: |:---: |:---: |:---: |:---: | +[hexjelly](https://github.com/hexjelly) |[rom1v](https://github.com/rom1v) |[rnelson](https://github.com/rnelson) |[swatteau](https://github.com/swatteau) |[tchajed](https://github.com/tchajed) |[tspiteri](https://github.com/tspiteri) | + +[siiptuo](https://github.com/siiptuo) |[vks](https://github.com/vks) |[vsupalov](https://github.com/vsupalov) |[mineo](https://github.com/mineo) |[wabain](https://github.com/wabain) |[grossws](https://github.com/grossws) | +:---: |:---: |:---: |:---: |:---: |:---: | +[siiptuo](https://github.com/siiptuo) |[vks](https://github.com/vks) |[vsupalov](https://github.com/vsupalov) |[mineo](https://github.com/mineo) |[wabain](https://github.com/wabain) |[grossws](https://github.com/grossws) | + +[kennytm](https://github.com/kennytm) |[king6cong](https://github.com/king6cong) |[mvaude](https://github.com/mvaude) |[panicbit](https://github.com/panicbit) |[brennie](https://github.com/brennie) | +:---: |:---: |:---: |:---: |:---: | +[kennytm](https://github.com/kennytm) |[king6cong](https://github.com/king6cong) |[mvaude](https://github.com/mvaude) |[panicbit](https://github.com/panicbit) |[brennie](https://github.com/brennie) | + + + + +This list was generated by [mgechev/github-contributors-list](https://github.com/mgechev/github-contributors-list) diff --git a/vendor/clap-2.34.0/Cargo.toml b/vendor/clap-2.34.0/Cargo.toml new file mode 100644 index 0000000000000..bb6bf093205f3 --- /dev/null +++ b/vendor/clap-2.34.0/Cargo.toml @@ -0,0 +1,132 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "clap" +version = "2.34.0" +authors = ["Kevin K. "] +exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"] +description = "A simple to use, efficient, and full-featured Command Line Argument Parser\n" +homepage = "https://clap.rs/" +documentation = "https://docs.rs/clap/" +readme = "README.md" +keywords = ["argument", "cli", "arg", "parser", "parse"] +categories = ["command-line-interface"] +license = "MIT" +repository = "https://github.com/clap-rs/clap" +[package.metadata.docs.rs] +features = ["doc"] +[profile.bench] +opt-level = 3 +lto = true +codegen-units = 1 +debug = false +debug-assertions = false +rpath = false + +[profile.dev] +opt-level = 0 +lto = false +codegen-units = 4 +debug = true +debug-assertions = true +rpath = false + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 +debug = false +debug-assertions = false +rpath = false + +[profile.test] +opt-level = 1 +lto = false +codegen-units = 4 +debug = true +debug-assertions = true +rpath = false +[dependencies.atty] +version = "0.2.2" +optional = true + +[dependencies.bitflags] +version = "1.0" + +[dependencies.clippy] +version = "~0.0.166" +optional = true + +[dependencies.strsim] +version = "0.8" +optional = true + +[dependencies.term_size] +version = "0.3.0" +optional = true + +[dependencies.textwrap] +version = "0.11.0" + +[dependencies.unicode-width] +version = "0.1.4" + +[dependencies.vec_map] +version = "0.8" +optional = true + +[dependencies.yaml-rust] +version = "0.3.5" +optional = true +[dev-dependencies.lazy_static] +version = "1.3" + +[dev-dependencies.regex] +version = "1" + +[dev-dependencies.version-sync] +version = "0.8" + +[features] +color = ["ansi_term", "atty"] +debug = [] +default = ["suggestions", "color", "vec_map"] +doc = ["yaml"] +nightly = [] +no_cargo = [] +suggestions = ["strsim"] +unstable = [] +wrap_help = ["term_size", "textwrap/term_size"] +yaml = ["yaml-rust"] +[target."cfg(not(windows))".dependencies.ansi_term] +version = "0.12" +optional = true +[badges.appveyor] +repository = "clap-rs/clap" + +[badges.coveralls] +branch = "master" +repository = "clap-rs/clap" + +[badges.is-it-maintained-issue-resolution] +repository = "clap-rs/clap" + +[badges.is-it-maintained-open-issues] +repository = "clap-rs/clap" + +[badges.maintenance] +status = "actively-developed" + +[badges.travis-ci] +repository = "clap-rs/clap" diff --git a/vendor/clap-2.34.0/LICENSE-MIT b/vendor/clap-2.34.0/LICENSE-MIT new file mode 100644 index 0000000000000..5acedf0412212 --- /dev/null +++ b/vendor/clap-2.34.0/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015-2016 Kevin B. Knapp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/clap-2.34.0/README.md b/vendor/clap-2.34.0/README.md new file mode 100644 index 0000000000000..64085b959adf7 --- /dev/null +++ b/vendor/clap-2.34.0/README.md @@ -0,0 +1,542 @@ +clap +==== + +[![Crates.io](https://img.shields.io/crates/v/clap.svg)](https://crates.io/crates/clap) [![Crates.io](https://img.shields.io/crates/d/clap.svg)](https://crates.io/crates/clap) [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/clap-rs/clap/blob/master/LICENSE-MIT) [![Coverage Status](https://coveralls.io/repos/kbknapp/clap-rs/badge.svg?branch=master&service=github)](https://coveralls.io/github/kbknapp/clap-rs?branch=master) [![Join the chat at https://gitter.im/kbknapp/clap-rs](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/kbknapp/clap-rs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +Linux: [![Build Status](https://travis-ci.org/clap-rs/clap.svg?branch=master)](https://travis-ci.org/clap-rs/clap) +Windows: [![Build status](https://ci.appveyor.com/api/projects/status/ejg8c33dn31nhv36/branch/master?svg=true)](https://ci.appveyor.com/project/kbknapp/clap-rs/branch/master) + +Command Line Argument Parser for Rust + +It is a simple-to-use, efficient, and full-featured library for parsing command line arguments and subcommands when writing console/terminal applications. + +* [documentation](https://docs.rs/clap/) +* [website](https://clap.rs/) +* [video tutorials](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U) + +Table of Contents +================= + +* [About](#about) +* [FAQ](#faq) +* [Features](#features) +* [Quick Example](#quick-example) +* [Try it!](#try-it) + * [Pre-Built Test](#pre-built-test) + * [BYOB (Build Your Own Binary)](#byob-build-your-own-binary) +* [Usage](#usage) + * [Optional Dependencies / Features](#optional-dependencies--features) + * [Dependencies Tree](#dependencies-tree) + * [More Information](#more-information) + * [Video Tutorials](#video-tutorials) +* [How to Contribute](#how-to-contribute) + * [Compatibility Policy](#compatibility-policy) + * [Minimum Version of Rust](#minimum-version-of-rust) +* [Related Crates](#related-crates) +* [License](#license) +* [Recent Breaking Changes](#recent-breaking-changes) + * [Deprecations](#deprecations) + +Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc) + +## About + +`clap` is used to parse *and validate* the string of command line arguments provided by a user at runtime. You provide the list of valid possibilities, and `clap` handles the rest. This means you focus on your *applications* functionality, and less on the parsing and validating of arguments. + +`clap` provides many things 'for free' (with no configuration) including the traditional version and help switches (or flags) along with associated messages. If you are using subcommands, `clap` will also auto-generate a `help` subcommand and separate associated help messages. + +Once `clap` parses the user provided string of arguments, it returns the matches along with any applicable values. If the user made an error or typo, `clap` informs them with a friendly message and exits gracefully (or returns a `Result` type and allows you to perform any clean up prior to exit). Because of this, you can make reasonable assumptions in your code about the validity of the arguments prior to your applications main execution. + +## FAQ + +For a full FAQ and more in depth details, see [the wiki page](https://github.com/clap-rs/clap/wiki/FAQ) + +### Comparisons + +First, let me say that these comparisons are highly subjective, and not meant in a critical or harsh manner. All the argument parsing libraries out there (to include `clap`) have their own strengths and weaknesses. Sometimes it just comes down to personal taste when all other factors are equal. When in doubt, try them all and pick one that you enjoy :) There's plenty of room in the Rust community for multiple implementations! + +#### How does `clap` compare to [getopts](https://github.com/rust-lang-nursery/getopts)? + +`getopts` is a very basic, fairly minimalist argument parsing library. This isn't a bad thing, sometimes you don't need tons of features, you just want to parse some simple arguments, and have some help text generated for you based on valid arguments you specify. The downside to this approach is that you must manually implement most of the common features (such as checking to display help messages, usage strings, etc.). If you want a highly custom argument parser, and don't mind writing the majority of the functionality yourself, `getopts` is an excellent base. + +`getopts` also doesn't allocate much, or at all. This gives it a very small performance boost. Although, as you start implementing additional features, that boost quickly disappears. + +Personally, I find many, many uses of `getopts` are manually implementing features that `clap` provides by default. Using `clap` simplifies your codebase allowing you to focus on your application, and not argument parsing. + +#### How does `clap` compare to [docopt.rs](https://github.com/docopt/docopt.rs)? + +I first want to say I'm a big a fan of BurntSushi's work, the creator of `Docopt.rs`. I aspire to produce the quality of libraries that this man does! When it comes to comparing these two libraries they are very different. `docopt` tasks you with writing a help message, and then it parsers that message for you to determine all valid arguments and their use. Some people LOVE this approach, others do not. If you're willing to write a detailed help message, it's nice that you can stick that in your program and have `docopt` do the rest. On the downside, it's far less flexible. + +`docopt` is also excellent at translating arguments into Rust types automatically. There is even a syntax extension which will do all this for you, if you're willing to use a nightly compiler (use of a stable compiler requires you to somewhat manually translate from arguments to Rust types). To use BurntSushi's words, `docopt` is also a sort of black box. You get what you get, and it's hard to tweak implementation or customize the experience for your use case. + +Because `docopt` is doing a ton of work to parse your help messages and determine what you were trying to communicate as valid arguments, it's also one of the more heavy weight parsers performance-wise. For most applications this isn't a concern and this isn't to say `docopt` is slow, in fact far from it. This is just something to keep in mind while comparing. + +#### All else being equal, what are some reasons to use `clap`? (The Pitch) + +`clap` is as fast, and as lightweight as possible while still giving all the features you'd expect from a modern argument parser. In fact, for the amount and type of features `clap` offers it remains about as fast as `getopts`. If you use `clap` when just need some simple arguments parsed, you'll find it's a walk in the park. `clap` also makes it possible to represent extremely complex, and advanced requirements, without too much thought. `clap` aims to be intuitive, easy to use, and fully capable for wide variety use cases and needs. + +#### All else being equal, what are some reasons *not* to use `clap`? (The Anti Pitch) + +Depending on the style in which you choose to define the valid arguments, `clap` can be very verbose. `clap` also offers so many fine-tuning knobs and dials, that learning everything can seem overwhelming. I strive to keep the simple cases simple, but when turning all those custom dials it can get complex. `clap` is also opinionated about parsing. Even though so much can be tweaked and tuned with `clap` (and I'm adding more all the time), there are still certain features which `clap` implements in specific ways which may be contrary to some users use-cases. Finally, `clap` is "stringly typed" when referring to arguments which can cause typos in code. This particular paper-cut is being actively worked on, and should be gone in v3.x. + +## Features + +Below are a few of the features which `clap` supports, full descriptions and usage can be found in the [documentation](https://docs.rs/clap/) and [examples/](examples) directory + +* **Auto-generated Help, Version, and Usage information** + - Can optionally be fully, or partially overridden if you want a custom help, version, or usage statements +* **Auto-generated completion scripts at compile time (Bash, Zsh, Fish, and PowerShell)** + - Even works through many multiple levels of subcommands + - Works with options which only accept certain values + - Works with subcommand aliases +* **Flags / Switches** (i.e. bool fields) + - Both short and long versions supported (i.e. `-f` and `--flag` respectively) + - Supports combining short versions (i.e. `-fBgoZ` is the same as `-f -B -g -o -Z`) + - Supports multiple occurrences (i.e. `-vvv` or `-v -v -v`) +* **Positional Arguments** (i.e. those which are based off an index from the program name) + - Supports multiple values (i.e. `myprog ...` such as `myprog file1.txt file2.txt` being two values for the same "file" argument) + - Supports Specific Value Sets (See below) + - Can set value parameters (such as the minimum number of values, the maximum number of values, or the exact number of values) + - Can set custom validations on values to extend the argument parsing capability to truly custom domains +* **Option Arguments** (i.e. those that take values) + - Both short and long versions supported (i.e. `-o value`, `-ovalue`, `-o=value` and `--option value` or `--option=value` respectively) + - Supports multiple values (i.e. `-o -o ` or `-o `) + - Supports delimited values (i.e. `-o=val1,val2,val3`, can also change the delimiter) + - Supports Specific Value Sets (See below) + - Supports named values so that the usage/help info appears as `-o ` etc. for when you require specific multiple values + - Can set value parameters (such as the minimum number of values, the maximum number of values, or the exact number of values) + - Can set custom validations on values to extend the argument parsing capability to truly custom domains +* **Sub-Commands** (i.e. `git add ` where `add` is a sub-command of `git`) + - Support their own sub-arguments, and sub-sub-commands independent of the parent + - Get their own auto-generated Help, Version, and Usage independent of parent +* **Support for building CLIs from YAML** - This keeps your Rust source nice and tidy and makes supporting localized translation very simple! +* **Requirement Rules**: Arguments can define the following types of requirement rules + - Can be required by default + - Can be required only if certain arguments are present + - Can require other arguments to be present + - Can be required only if certain values of other arguments are used +* **Confliction Rules**: Arguments can optionally define the following types of exclusion rules + - Can be disallowed when certain arguments are present + - Can disallow use of other arguments when present +* **Groups**: Arguments can be made part of a group + - Fully compatible with other relational rules (requirements, conflicts, and overrides) which allows things like requiring the use of any arg in a group, or denying the use of an entire group conditionally +* **Specific Value Sets**: Positional or Option Arguments can define a specific set of allowed values (i.e. imagine a `--mode` option which may *only* have one of two values `fast` or `slow` such as `--mode fast` or `--mode slow`) +* **Default Values** + - Also supports conditional default values (i.e. a default which only applies if specific arguments are used, or specific values of those arguments) +* **Automatic Version from Cargo.toml**: `clap` is fully compatible with Rust's `env!()` macro for automatically setting the version of your application to the version in your Cargo.toml. See [09_auto_version example](examples/09_auto_version.rs) for how to do this (Thanks to [jhelwig](https://github.com/jhelwig) for pointing this out) +* **Typed Values**: You can use several convenience macros provided by `clap` to get typed values (i.e. `i32`, `u8`, etc.) from positional or option arguments so long as the type you request implements `std::str::FromStr` See the [12_typed_values example](examples/12_typed_values.rs). You can also use `clap`s `arg_enum!` macro to create an enum with variants that automatically implement `std::str::FromStr`. See [13a_enum_values_automatic example](examples/13a_enum_values_automatic.rs) for details +* **Suggestions**: Suggests corrections when the user enters a typo. For example, if you defined a `--myoption` argument, and the user mistakenly typed `--moyption` (notice `y` and `o` transposed), they would receive a `Did you mean '--myoption'?` error and exit gracefully. This also works for subcommands and flags. (Thanks to [Byron](https://github.com/Byron) for the implementation) (This feature can optionally be disabled, see 'Optional Dependencies / Features') +* **Colorized Errors (Non Windows OS only)**: Error message are printed in in colored text (this feature can optionally be disabled, see 'Optional Dependencies / Features'). +* **Global Arguments**: Arguments can optionally be defined once, and be available to all child subcommands. There values will also be propagated up/down throughout all subcommands. +* **Custom Validations**: You can define a function to use as a validator of argument values. Imagine defining a function to validate IP addresses, or fail parsing upon error. This means your application logic can be solely focused on *using* values. +* **POSIX Compatible Conflicts/Overrides** - In POSIX args can be conflicting, but not fail parsing because whichever arg comes *last* "wins" so to speak. This allows things such as aliases (i.e. `alias ls='ls -l'` but then using `ls -C` in your terminal which ends up passing `ls -l -C` as the final arguments. Since `-l` and `-C` aren't compatible, this effectively runs `ls -C` in `clap` if you choose...`clap` also supports hard conflicts that fail parsing). (Thanks to [Vinatorul](https://github.com/Vinatorul)!) +* Supports the Unix `--` meaning, only positional arguments follow + +## Quick Example + +The following examples show a quick example of some of the very basic functionality of `clap`. For more advanced usage, such as requirements, conflicts, groups, multiple values and occurrences see the [documentation](https://docs.rs/clap/), [examples/](examples) directory of this repository or the [video tutorials](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U). + + **NOTE:** All of these examples are functionally the same, but show different styles in which to use `clap`. These different styles are purely a matter of personal preference. + +The first example shows a method using the 'Builder Pattern' which allows more advanced configuration options (not shown in this small example), or even dynamically generating arguments when desired. + +```rust +// (Full example with detailed comments in examples/01b_quick_example.rs) +// +// This example demonstrates clap's full 'builder pattern' style of creating arguments which is +// more verbose, but allows easier editing, and at times more advanced options, or the possibility +// to generate arguments dynamically. +extern crate clap; +use clap::{Arg, App, SubCommand}; + +fn main() { + let matches = App::new("My Super Program") + .version("1.0") + .author("Kevin K. ") + .about("Does awesome things") + .arg(Arg::with_name("config") + .short("c") + .long("config") + .value_name("FILE") + .help("Sets a custom config file") + .takes_value(true)) + .arg(Arg::with_name("INPUT") + .help("Sets the input file to use") + .required(true) + .index(1)) + .arg(Arg::with_name("v") + .short("v") + .multiple(true) + .help("Sets the level of verbosity")) + .subcommand(SubCommand::with_name("test") + .about("controls testing features") + .version("1.3") + .author("Someone E. ") + .arg(Arg::with_name("debug") + .short("d") + .help("print debug information verbosely"))) + .get_matches(); + + // Gets a value for config if supplied by user, or defaults to "default.conf" + let config = matches.value_of("config").unwrap_or("default.conf"); + println!("Value for config: {}", config); + + // Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't + // required we could have used an 'if let' to conditionally get the value) + println!("Using input file: {}", matches.value_of("INPUT").unwrap()); + + // Vary the output based on how many times the user used the "verbose" flag + // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v' + match matches.occurrences_of("v") { + 0 => println!("No verbose info"), + 1 => println!("Some verbose info"), + 2 => println!("Tons of verbose info"), + 3 | _ => println!("Don't be crazy"), + } + + // You can handle information about subcommands by requesting their matches by name + // (as below), requesting just the name used, or both at the same time + if let Some(matches) = matches.subcommand_matches("test") { + if matches.is_present("debug") { + println!("Printing debug info..."); + } else { + println!("Printing normally..."); + } + } + + // more program logic goes here... +} +``` + +One could also optionally declare their CLI in YAML format and keep your Rust source tidy +or support multiple localized translations by having different YAML files for each localization. + +First, create the `cli.yml` file to hold your CLI options, but it could be called anything we like: + +```yaml +name: myapp +version: "1.0" +author: Kevin K. +about: Does awesome things +args: + - config: + short: c + long: config + value_name: FILE + help: Sets a custom config file + takes_value: true + - INPUT: + help: Sets the input file to use + required: true + index: 1 + - verbose: + short: v + multiple: true + help: Sets the level of verbosity +subcommands: + - test: + about: controls testing features + version: "1.3" + author: Someone E. + args: + - debug: + short: d + help: print debug information +``` + +Since this feature requires additional dependencies that not everyone may want, it is *not* compiled in by default and we need to enable a feature flag in Cargo.toml: + +Simply change your `clap = "2.34"` to `clap = {version = "2.34", features = ["yaml"]}`. + +Finally we create our `main.rs` file just like we would have with the previous two examples: + +```rust +// (Full example with detailed comments in examples/17_yaml.rs) +// +// This example demonstrates clap's building from YAML style of creating arguments which is far +// more clean, but takes a very small performance hit compared to the other two methods. +#[macro_use] +extern crate clap; +use clap::App; + +fn main() { + // The YAML file is found relative to the current file, similar to how modules are found + let yaml = load_yaml!("cli.yml"); + let matches = App::from_yaml(yaml).get_matches(); + + // Same as previous examples... +} +``` + +If you were to compile any of the above programs and run them with the flag `--help` or `-h` (or `help` subcommand, since we defined `test` as a subcommand) the following would be output + +```sh +$ myprog --help +My Super Program 1.0 +Kevin K. +Does awesome things + +USAGE: + MyApp [FLAGS] [OPTIONS] [SUBCOMMAND] + +FLAGS: + -h, --help Prints help information + -v Sets the level of verbosity + -V, --version Prints version information + +OPTIONS: + -c, --config Sets a custom config file + +ARGS: + INPUT The input file to use + +SUBCOMMANDS: + help Prints this message or the help of the given subcommand(s) + test Controls testing features +``` + +**NOTE:** You could also run `myapp test --help` or `myapp help test` to see the help message for the `test` subcommand. + +There are also two other methods to create CLIs. Which style you choose is largely a matter of personal preference. The two other methods are: + +* Using [usage strings (examples/01a_quick_example.rs)](examples/01a_quick_example.rs) similar to (but not exact) docopt style usage statements. This is far less verbose than the above methods, but incurs a slight runtime penalty. +* Using [a macro (examples/01c_quick_example.rs)](examples/01c_quick_example.rs) which is like a hybrid of the builder and usage string style. It's less verbose, but doesn't incur the runtime penalty of the usage string style. The downside is that it's harder to debug, and more opaque. + +Examples of each method can be found in the [examples/](examples) directory of this repository. + +## Try it! + +### Pre-Built Test + +To try out the pre-built examples, use the following steps: + +* Clone the repository `$ git clone https://github.com/clap-rs/clap && cd clap-rs/` +* Compile the example `$ cargo build --example ` +* Run the help info `$ ./target/debug/examples/ --help` +* Play with the arguments! +* You can also do a onetime run via `$ cargo run --example -- [args to example]` + +### BYOB (Build Your Own Binary) + +To test out `clap`'s default auto-generated help/version follow these steps: +* Create a new cargo project `$ cargo new fake --bin && cd fake` +* Add `clap` to your `Cargo.toml` + +```toml +[dependencies] +clap = "2" +``` + +* Add the following to your `src/main.rs` + +```rust +extern crate clap; +use clap::App; + +fn main() { + App::new("fake").version("v1.0-beta").get_matches(); +} +``` + +* Build your program `$ cargo build --release` +* Run with help or version `$ ./target/release/fake --help` or `$ ./target/release/fake --version` + +## Usage + +For full usage, add `clap` as a dependency in your `Cargo.toml` () to use from crates.io: + +```toml +[dependencies] +clap = "~2.34" +``` + +(**note**: If you are concerned with supporting a minimum version of Rust that is *older* than the current stable Rust minus 2 stable releases, it's recommended to use the `~major.minor.patch` style versions in your `Cargo.toml` which will only update the patch version automatically. For more information see the [Compatibility Policy](#compatibility-policy)) + +Then add `extern crate clap;` to your crate root. + +Define a list of valid arguments for your program (see the [documentation](https://docs.rs/clap/) or [examples/](examples) directory of this repo) + +Then run `cargo build` or `cargo update && cargo build` for your project. + +### Optional Dependencies / Features + +#### Features enabled by default + +* **"suggestions"**: Turns on the `Did you mean '--myoption'?` feature for when users make typos. (builds dependency `strsim`) +* **"color"**: Turns on colored error messages. This feature only works on non-Windows OSs. (builds dependency `ansi-term` only on non-Windows targets) +* **"vec_map"**: Use [`VecMap`](https://crates.io/crates/vec_map) internally instead of a [`BTreeMap`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html). This feature provides a _slight_ performance improvement. (builds dependency `vec_map`) + +To disable these, add this to your `Cargo.toml`: + +```toml +[dependencies.clap] +version = "2.34" +default-features = false +``` + +You can also selectively enable only the features you'd like to include, by adding: + +```toml +[dependencies.clap] +version = "2.34" +default-features = false + +# Cherry-pick the features you'd like to use +features = [ "suggestions", "color" ] +``` + +#### Opt-in features + +* **"yaml"**: Enables building CLIs from YAML documents. (builds dependency `yaml-rust`) +* **"unstable"**: Enables unstable `clap` features that may change from release to release +* **"wrap_help"**: Turns on the help text wrapping feature, based on the terminal size. (builds dependency `term-size`) + +### Dependencies Tree + +The following graphic depicts `clap`s dependency graph (generated using [cargo-graph](https://github.com/kbknapp/cargo-graph)). + + * **Dashed** Line: Optional dependency + * **Red** Color: **NOT** included by default (must use cargo `features` to enable) + * **Blue** Color: Dev dependency, only used while developing. + +![clap dependencies](clap_dep_graph.png) + +### More Information + +You can find complete documentation on the [docs.rs](https://docs.rs/clap/) for this project. + +You can also find usage examples in the [examples/](examples) directory of this repo. + +#### Video Tutorials + +There's also the video tutorial series [Argument Parsing with Rust v2](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U). + +These videos slowly trickle out as I finish them and currently a work in progress. + +## How to Contribute + +Details on how to contribute can be found in the [CONTRIBUTING.md](.github/CONTRIBUTING.md) file. + +### Compatibility Policy + +Because `clap` takes SemVer and compatibility seriously, this is the official policy regarding breaking changes and minimum required versions of Rust. + +`clap` will pin the minimum required version of Rust to the CI builds. Bumping the minimum version of Rust is considered a minor breaking change, meaning *at a minimum* the minor version of `clap` will be bumped. + +In order to keep from being surprised of breaking changes, it is **highly** recommended to use the `~major.minor.patch` style in your `Cargo.toml` only if you wish to target a version of Rust that is *older* than current stable minus two releases: + +```toml +[dependencies] +clap = "~2.34" +``` + +This will cause *only* the patch version to be updated upon a `cargo update` call, and therefore cannot break due to new features, or bumped minimum versions of Rust. + +#### Warning about '~' Dependencies + +Using `~` can cause issues in certain circumstances. + +From @alexcrichton: + +Right now Cargo's version resolution is pretty naive, it's just a brute-force search of the solution space, returning the first resolvable graph. This also means that it currently won't terminate until it proves there is not possible resolvable graph. This leads to situations where workspaces with multiple binaries, for example, have two different dependencies such as: + +```toml,no_sync + +# In one Cargo.toml +[dependencies] +clap = "~2.34.0" + +# In another Cargo.toml +[dependencies] +clap = "2.34.0" +``` + +This is inherently an unresolvable crate graph in Cargo right now. Cargo requires there's only one major version of a crate, and being in the same workspace these two crates must share a version. This is impossible in this location, though, as these version constraints cannot be met. + +#### Minimum Version of Rust + +`clap` will officially support current stable Rust, minus two releases, but may work with prior releases as well. For example, current stable Rust at the time of this writing is 1.41.0, meaning `clap` is guaranteed to compile with 1.39.0 and beyond. + +At the 1.42.0 stable release, `clap` will be guaranteed to compile with 1.40.0 and beyond, etc. + +Upon bumping the minimum version of Rust (assuming it's within the stable-2 range), it *must* be clearly annotated in the `CHANGELOG.md` + +#### Breaking Changes + +`clap` takes a similar policy to Rust and will bump the major version number upon breaking changes with only the following exceptions: + + * The breaking change is to fix a security concern + * The breaking change is to be fixing a bug (i.e. relying on a bug as a feature) + * The breaking change is a feature isn't used in the wild, or all users of said feature have given approval *prior* to the change + +#### Compatibility with Wasm + +A best effort is made to ensure that `clap` will work on projects targeting `wasm32-unknown-unknown`. However there is no dedicated CI build +covering this specific target. + +## License + +`clap` is licensed under the MIT license. Please read the [LICENSE-MIT](LICENSE-MIT) file in this repository for more information. + +## Related Crates + +There are several excellent crates which can be used with `clap`, I recommend checking them all out! If you've got a crate that would be a good fit to be used with `clap` open an issue and let me know, I'd love to add it! + +* [`structopt`](https://github.com/TeXitoi/structopt) - This crate allows you to define a struct, and build a CLI from it! No more "stringly typed" and it uses `clap` behind the scenes! (*Note*: There is work underway to pull this crate into mainline `clap`). +* [`assert_cli`](https://github.com/assert-rs/assert_cli) - This crate allows you test your CLIs in a very intuitive and functional way! + +## Recent Breaking Changes + +`clap` follows semantic versioning, so breaking changes should only happen upon major version bumps. The only exception to this rule is breaking changes that happen due to implementation that was deemed to be a bug, security concerns, or it can be reasonably proved to affect no code. For the full details, see [CHANGELOG.md](./CHANGELOG.md). + +As of 2.27.0: + +* Argument values now take precedence over subcommand names. This only arises by using unrestrained multiple values and subcommands together where the subcommand name can coincide with one of the multiple values. Such as `$ prog ... `. The fix is to place restraints on number of values, or disallow the use of `$ prog ` structure. + +As of 2.0.0 (From 1.x) + +* **Fewer lifetimes! Yay!** + * `App<'a, 'b, 'c, 'd, 'e, 'f>` => `App<'a, 'b>` + * `Arg<'a, 'b, 'c, 'd, 'e, 'f>` => `Arg<'a, 'b>` + * `ArgMatches<'a, 'b>` => `ArgMatches<'a>` +* **Simply Renamed** + * `App::arg_group` => `App::group` + * `App::arg_groups` => `App::groups` + * `ArgGroup::add` => `ArgGroup::arg` + * `ArgGroup::add_all` => `ArgGroup::args` + * `ClapError` => `Error` + * struct field `ClapError::error_type` => `Error::kind` + * `ClapResult` => `Result` + * `ClapErrorType` => `ErrorKind` +* **Removed Deprecated Functions and Methods** + * `App::subcommands_negate_reqs` + * `App::subcommand_required` + * `App::arg_required_else_help` + * `App::global_version(bool)` + * `App::versionless_subcommands` + * `App::unified_help_messages` + * `App::wait_on_error` + * `App::subcommand_required_else_help` + * `SubCommand::new` + * `App::error_on_no_subcommand` + * `Arg::new` + * `Arg::mutually_excludes` + * `Arg::mutually_excludes_all` + * `Arg::mutually_overrides_with` + * `simple_enum!` +* **Renamed Error Variants** + * `InvalidUnicode` => `InvalidUtf8` + * `InvalidArgument` => `UnknownArgument` +* **Usage Parser** + * Value names can now be specified inline, i.e. `-o, --option 'some option which takes two files'` + * **There is now a priority of order to determine the name** - This is perhaps the biggest breaking change. See the documentation for full details. Prior to this change, the value name took precedence. **Ensure your args are using the proper names (i.e. typically the long or short and NOT the value name) throughout the code** +* `ArgMatches::values_of` returns an `Values` now which implements `Iterator` (should not break any code) +* `crate_version!` returns `&'static str` instead of `String` + +### Deprecations + +Old method names will be left around for several minor version bumps, or one major version bump. + +As of 2.27.0: + +* **AppSettings::PropagateGlobalValuesDown:** this setting deprecated and is no longer required to propagate values down or up diff --git a/vendor/clap-2.34.0/SPONSORS.md b/vendor/clap-2.34.0/SPONSORS.md new file mode 100644 index 0000000000000..67f5544f9b468 --- /dev/null +++ b/vendor/clap-2.34.0/SPONSORS.md @@ -0,0 +1,17 @@ +Below is a list of sponsors for the clap-rs project + +If you are interested in becoming a sponsor for this project please our [sponsorship page](https://clap.rs/sponsorship/). + +## Recurring Sponsors: + +| [Noelia Seva-Gonzalez](https://noeliasg.com/about/) | [messense](https://github.com/messense) | [Josh](https://joshtriplett.org) | Stephen Oats | +|:-:|:-:|:-:|:-:| +|Noelia Seva-Gonzalez | Messense | Josh Triplett | Stephen Oats | + + +## Single-Donation and Former Sponsors: + +| [Rob Tsuk](https://github.com/rtsuk)| | | +|:-:|:-:|:-:| +|Rob Tsuk| | | + diff --git a/vendor/clap-2.34.0/clap-test.rs b/vendor/clap-2.34.0/clap-test.rs new file mode 100644 index 0000000000000..7d57ac4f30830 --- /dev/null +++ b/vendor/clap-2.34.0/clap-test.rs @@ -0,0 +1,86 @@ +#[allow(unused_imports, dead_code)] +mod test { + use std::str; + use std::io::{Cursor, Write}; + + use regex::Regex; + + use clap::{App, Arg, SubCommand, ArgGroup}; + + fn compare(l: S, r: S2) -> bool + where S: AsRef, + S2: AsRef + { + let re = Regex::new("\x1b[^m]*m").unwrap(); + // Strip out any mismatching \r character on windows that might sneak in on either side + let ls = l.as_ref().trim().replace("\r", ""); + let rs = r.as_ref().trim().replace("\r", ""); + let left = re.replace_all(&*ls, ""); + let right = re.replace_all(&*rs, ""); + let b = left == right; + if !b { + println!(); + println!("--> left"); + println!("{}", left); + println!("--> right"); + println!("{}", right); + println!("--") + } + b + } + + pub fn compare_output(l: App, args: &str, right: &str, stderr: bool) -> bool { + let mut buf = Cursor::new(Vec::with_capacity(50)); + let res = l.get_matches_from_safe(args.split(' ').collect::>()); + let err = res.unwrap_err(); + err.write_to(&mut buf).unwrap(); + let content = buf.into_inner(); + let left = String::from_utf8(content).unwrap(); + assert_eq!(stderr, err.use_stderr()); + compare(left, right) + } + pub fn compare_output2(l: App, args: &str, right1: &str, right2: &str, stderr: bool) -> bool { + let mut buf = Cursor::new(Vec::with_capacity(50)); + let res = l.get_matches_from_safe(args.split(' ').collect::>()); + let err = res.unwrap_err(); + err.write_to(&mut buf).unwrap(); + let content = buf.into_inner(); + let left = String::from_utf8(content).unwrap(); + assert_eq!(stderr, err.use_stderr()); + compare(&*left, right1) || compare(&*left, right2) + } + + // Legacy tests from the Python script days + + pub fn complex_app() -> App<'static, 'static> { + let args = "-o --option=[opt]... 'tests options' + [positional] 'tests positionals'"; + let opt3_vals = ["fast", "slow"]; + let pos3_vals = ["vi", "emacs"]; + App::new("clap-test") + .version("v1.4.8") + .about("tests clap library") + .author("Kevin K. ") + .args_from_usage(args) + .arg(Arg::from_usage("-f --flag... 'tests flags'") + .global(true)) + .args(&[ + Arg::from_usage("[flag2] -F 'tests flags with exclusions'").conflicts_with("flag").requires("long-option-2"), + Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").conflicts_with("option").requires("positional2"), + Arg::from_usage("[positional2] 'tests positionals with exclusions'"), + Arg::from_usage("-O --Option [option3] 'specific vals'").possible_values(&opt3_vals), + Arg::from_usage("[positional3]... 'tests specific values'").possible_values(&pos3_vals), + Arg::from_usage("--multvals [one] [two] 'Tests multiple values, not mult occs'"), + Arg::from_usage("--multvalsmo... [one] [two] 'Tests multiple values, and mult occs'"), + Arg::from_usage("--minvals2 [minvals]... 'Tests 2 min vals'").min_values(2), + Arg::from_usage("--maxvals3 [maxvals]... 'Tests 3 max vals'").max_values(3) + ]) + .subcommand(SubCommand::with_name("subcmd") + .about("tests subcommands") + .version("0.1") + .author("Kevin K. ") + .arg_from_usage("-o --option [scoption]... 'tests options'") + .arg_from_usage("-s --subcmdarg [subcmdarg] 'tests other args'") + .arg_from_usage("[scpositional] 'tests positionals'")) + } +} diff --git a/vendor/clap-2.34.0/justfile b/vendor/clap-2.34.0/justfile new file mode 100644 index 0000000000000..0768764b30c29 --- /dev/null +++ b/vendor/clap-2.34.0/justfile @@ -0,0 +1,39 @@ +@update-contributors: + echo 'Removing old CONTRIBUTORS.md' + mv CONTRIBUTORS.md CONTRIBUTORS.md.bak + echo 'Downloading a list of new contributors' + echo "the following is a list of contributors:" > CONTRIBUTORS.md + echo "" >> CONTRIBUTORS.md + echo "" >> CONTRIBUTORS.md + githubcontrib --owner clap-rs --repo clap --sha master --cols 6 --format md --showlogin true --sortBy contributions --sortOrder desc >> CONTRIBUTORS.md + echo "" >> CONTRIBUTORS.md + echo "" >> CONTRIBUTORS.md + echo "This list was generated by [mgechev/github-contributors-list](https://github.com/mgechev/github-contributors-list)" >> CONTRIBUTORS.md + rm CONTRIBUTORS.md.bak + +run-test TEST: + cargo test --test {{TEST}} + +debug TEST: + cargo test --test {{TEST}} --features debug + +run-tests: + cargo test --features "yaml unstable" + +@bench: nightly + cargo bench && just remove-nightly + +nightly: + rustup override add nightly + +remove-nightly: + rustup override remove + +@lint: nightly + cargo build --features lints && just remove-nightly + +clean: + cargo clean + find . -type f -name "*.orig" -exec rm {} \; + find . -type f -name "*.bk" -exec rm {} \; + find . -type f -name ".*~" -exec rm {} \; diff --git a/vendor/clap-2.34.0/src/app/help.rs b/vendor/clap-2.34.0/src/app/help.rs new file mode 100644 index 0000000000000..e5f2a608daf18 --- /dev/null +++ b/vendor/clap-2.34.0/src/app/help.rs @@ -0,0 +1,1032 @@ +// Std +use std::{ + borrow::Cow, + cmp, + collections::BTreeMap, + fmt::Display, + io::{self, Cursor, Read, Write}, + usize, +}; + +// Third Party +#[cfg(feature = "wrap_help")] +use term_size; +#[cfg(feature = "wrap_help")] +use textwrap; +use unicode_width::UnicodeWidthStr; + +// Internal +use crate::{ + app::{parser::Parser, usage, App, AppSettings}, + args::{AnyArg, ArgSettings, DispOrder}, + errors::{Error, Result as ClapResult}, + fmt::{Colorizer, ColorizerOption, Format}, + map::VecMap, + INTERNAL_ERROR_MSG, +}; + +#[cfg(not(feature = "wrap_help"))] +mod term_size { + pub fn dimensions() -> Option<(usize, usize)> { + None + } +} + +fn str_width(s: &str) -> usize { + UnicodeWidthStr::width(s) +} + +const TAB: &str = " "; + +// These are just convenient traits to make the code easier to read. +trait ArgWithDisplay<'b, 'c>: AnyArg<'b, 'c> + Display {} +impl<'b, 'c, T> ArgWithDisplay<'b, 'c> for T where T: AnyArg<'b, 'c> + Display {} + +trait ArgWithOrder<'b, 'c>: ArgWithDisplay<'b, 'c> + DispOrder { + fn as_base(&self) -> &ArgWithDisplay<'b, 'c>; +} +impl<'b, 'c, T> ArgWithOrder<'b, 'c> for T +where + T: ArgWithDisplay<'b, 'c> + DispOrder, +{ + fn as_base(&self) -> &ArgWithDisplay<'b, 'c> { + self + } +} + +fn as_arg_trait<'a, 'b, T: ArgWithOrder<'a, 'b>>(x: &T) -> &ArgWithOrder<'a, 'b> { + x +} + +impl<'b, 'c> DispOrder for App<'b, 'c> { + fn disp_ord(&self) -> usize { + 999 + } +} + +macro_rules! color { + ($_self:ident, $s:expr, $c:ident) => { + if $_self.color { + write!($_self.writer, "{}", $_self.cizer.$c($s)) + } else { + write!($_self.writer, "{}", $s) + } + }; + ($_self:ident, $fmt_s:expr, $v:expr, $c:ident) => { + if $_self.color { + write!($_self.writer, "{}", $_self.cizer.$c(format!($fmt_s, $v))) + } else { + write!($_self.writer, $fmt_s, $v) + } + }; +} + +/// `clap` Help Writer. +/// +/// Wraps a writer stream providing different methods to generate help for `clap` objects. +pub struct Help<'a> { + writer: &'a mut Write, + next_line_help: bool, + hide_pv: bool, + term_w: usize, + color: bool, + cizer: Colorizer, + longest: usize, + force_next_line: bool, + use_long: bool, +} + +// Public Functions +impl<'a> Help<'a> { + /// Create a new `Help` instance. + #[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))] + pub fn new( + w: &'a mut Write, + next_line_help: bool, + hide_pv: bool, + color: bool, + cizer: Colorizer, + term_w: Option, + max_w: Option, + use_long: bool, + ) -> Self { + debugln!("Help::new;"); + Help { + writer: w, + next_line_help, + hide_pv, + term_w: match term_w { + Some(width) => { + if width == 0 { + usize::MAX + } else { + width + } + } + None => cmp::min( + term_size::dimensions().map_or(120, |(w, _)| w), + match max_w { + None | Some(0) => usize::MAX, + Some(mw) => mw, + }, + ), + }, + color, + cizer, + longest: 0, + force_next_line: false, + use_long, + } + } + + /// Reads help settings from an App + /// and write its help to the wrapped stream. + pub fn write_app_help(w: &'a mut Write, app: &App, use_long: bool) -> ClapResult<()> { + debugln!("Help::write_app_help;"); + Self::write_parser_help(w, &app.p, use_long) + } + + /// Reads help settings from a Parser + /// and write its help to the wrapped stream. + pub fn write_parser_help(w: &'a mut Write, parser: &Parser, use_long: bool) -> ClapResult<()> { + debugln!("Help::write_parser_help;"); + Self::_write_parser_help(w, parser, false, use_long) + } + + /// Reads help settings from a Parser + /// and write its help to the wrapped stream which will be stderr. This method prevents + /// formatting when required. + pub fn write_parser_help_to_stderr(w: &'a mut Write, parser: &Parser) -> ClapResult<()> { + debugln!("Help::write_parser_help;"); + Self::_write_parser_help(w, parser, true, false) + } + + #[doc(hidden)] + pub fn _write_parser_help( + w: &'a mut Write, + parser: &Parser, + stderr: bool, + use_long: bool, + ) -> ClapResult<()> { + debugln!("Help::write_parser_help;"); + let nlh = parser.is_set(AppSettings::NextLineHelp); + let hide_v = parser.is_set(AppSettings::HidePossibleValuesInHelp); + let color = parser.is_set(AppSettings::ColoredHelp); + let cizer = Colorizer::new(ColorizerOption { + use_stderr: stderr, + when: parser.color(), + }); + Self::new( + w, + nlh, + hide_v, + color, + cizer, + parser.meta.term_w, + parser.meta.max_w, + use_long, + ) + .write_help(parser) + } + + /// Writes the parser help to the wrapped stream. + pub fn write_help(&mut self, parser: &Parser) -> ClapResult<()> { + debugln!("Help::write_help;"); + if let Some(h) = parser.meta.help_str { + write!(self.writer, "{}", h).map_err(Error::from)?; + } else if let Some(tmpl) = parser.meta.template { + self.write_templated_help(parser, tmpl)?; + } else { + self.write_default_help(parser)?; + } + Ok(()) + } +} + +// Methods to write AnyArg help. +impl<'a> Help<'a> { + /// Writes help for each argument in the order they were declared to the wrapped stream. + fn write_args_unsorted<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()> + where + I: Iterator>, + { + debugln!("Help::write_args_unsorted;"); + // The shortest an arg can legally be is 2 (i.e. '-x') + self.longest = 2; + let mut arg_v = Vec::with_capacity(10); + let use_long = self.use_long; + for arg in args.filter(|arg| should_show_arg(use_long, *arg)) { + if arg.longest_filter() { + self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str())); + } + arg_v.push(arg) + } + let mut first = true; + for arg in arg_v { + if first { + first = false; + } else { + self.writer.write_all(b"\n")?; + } + self.write_arg(arg.as_base())?; + } + Ok(()) + } + + /// Sorts arguments by length and display order and write their help to the wrapped stream. + fn write_args<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()> + where + I: Iterator>, + { + debugln!("Help::write_args;"); + // The shortest an arg can legally be is 2 (i.e. '-x') + self.longest = 2; + let mut ord_m = VecMap::new(); + let use_long = self.use_long; + // Determine the longest + for arg in args.filter(|arg| { + // If it's NextLineHelp, but we don't care to compute how long because it may be + // NextLineHelp on purpose *because* it's so long and would throw off all other + // args alignment + should_show_arg(use_long, *arg) + }) { + if arg.longest_filter() { + debugln!("Help::write_args: Current Longest...{}", self.longest); + self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str())); + debugln!("Help::write_args: New Longest...{}", self.longest); + } + let btm = ord_m.entry(arg.disp_ord()).or_insert(BTreeMap::new()); + btm.insert(arg.name(), arg); + } + let mut first = true; + for btm in ord_m.values() { + for arg in btm.values() { + if first { + first = false; + } else { + self.writer.write_all(b"\n")?; + } + self.write_arg(arg.as_base())?; + } + } + Ok(()) + } + + /// Writes help for an argument to the wrapped stream. + fn write_arg<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> { + debugln!("Help::write_arg;"); + self.short(arg)?; + self.long(arg)?; + let spec_vals = self.val(arg)?; + self.help(arg, &*spec_vals)?; + Ok(()) + } + + /// Writes argument's short command to the wrapped stream. + fn short<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> { + debugln!("Help::short;"); + write!(self.writer, "{}", TAB)?; + if let Some(s) = arg.short() { + color!(self, "-{}", s, good) + } else if arg.has_switch() { + write!(self.writer, "{}", TAB) + } else { + Ok(()) + } + } + + /// Writes argument's long command to the wrapped stream. + fn long<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> { + debugln!("Help::long;"); + if !arg.has_switch() { + return Ok(()); + } + if arg.takes_value() { + if let Some(l) = arg.long() { + if arg.short().is_some() { + write!(self.writer, ", ")?; + } + color!(self, "--{}", l, good)? + } + + let sep = if arg.is_set(ArgSettings::RequireEquals) { + "=" + } else { + " " + }; + write!(self.writer, "{}", sep)?; + } else if let Some(l) = arg.long() { + if arg.short().is_some() { + write!(self.writer, ", ")?; + } + color!(self, "--{}", l, good)?; + } + Ok(()) + } + + /// Writes argument's possible values to the wrapped stream. + fn val<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> Result { + debugln!("Help::val: arg={}", arg); + if arg.takes_value() { + let delim = if arg.is_set(ArgSettings::RequireDelimiter) { + arg.val_delim().expect(INTERNAL_ERROR_MSG) + } else { + ' ' + }; + if let Some(vec) = arg.val_names() { + let mut it = vec.iter().peekable(); + while let Some((_, val)) = it.next() { + color!(self, "<{}>", val, good)?; + if it.peek().is_some() { + write!(self.writer, "{}", delim)?; + } + } + let num = vec.len(); + if arg.is_set(ArgSettings::Multiple) && num == 1 { + color!(self, "...", good)?; + } + } else if let Some(num) = arg.num_vals() { + let mut it = (0..num).peekable(); + while let Some(_) = it.next() { + color!(self, "<{}>", arg.name(), good)?; + if it.peek().is_some() { + write!(self.writer, "{}", delim)?; + } + } + if arg.is_set(ArgSettings::Multiple) && num == 1 { + color!(self, "...", good)?; + } + } else if arg.has_switch() { + color!(self, "<{}>", arg.name(), good)?; + if arg.is_set(ArgSettings::Multiple) { + color!(self, "...", good)?; + } + } else { + color!(self, "{}", arg, good)?; + } + } + + let spec_vals = self.spec_vals(arg); + let h = arg.help().unwrap_or(""); + let h_w = str_width(h) + str_width(&*spec_vals); + let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp); + let taken = self.longest + 12; + self.force_next_line = !nlh + && self.term_w >= taken + && (taken as f32 / self.term_w as f32) > 0.40 + && h_w > (self.term_w - taken); + + debug!("Help::val: Has switch..."); + if arg.has_switch() { + sdebugln!("Yes"); + debugln!("Help::val: force_next_line...{:?}", self.force_next_line); + debugln!("Help::val: nlh...{:?}", nlh); + debugln!("Help::val: taken...{}", taken); + debugln!( + "Help::val: help_width > (width - taken)...{} > ({} - {})", + h_w, + self.term_w, + taken + ); + debugln!("Help::val: longest...{}", self.longest); + debug!("Help::val: next_line..."); + if !(nlh || self.force_next_line) { + sdebugln!("No"); + let self_len = str_width(arg.to_string().as_str()); + // subtract ourself + let mut spcs = self.longest - self_len; + // Since we're writing spaces from the tab point we first need to know if we + // had a long and short, or just short + if arg.long().is_some() { + // Only account 4 after the val + spcs += 4; + } else { + // Only account for ', --' + 4 after the val + spcs += 8; + } + + write_nspaces!(self.writer, spcs); + } else { + sdebugln!("Yes"); + } + } else if !(nlh || self.force_next_line) { + sdebugln!("No, and not next_line"); + write_nspaces!( + self.writer, + self.longest + 4 - (str_width(arg.to_string().as_str())) + ); + } else { + sdebugln!("No"); + } + Ok(spec_vals) + } + + fn write_before_after_help(&mut self, h: &str) -> io::Result<()> { + debugln!("Help::write_before_after_help;"); + let mut help = String::from(h); + // determine if our help fits or needs to wrap + debugln!( + "Help::write_before_after_help: Term width...{}", + self.term_w + ); + let too_long = str_width(h) >= self.term_w; + + debug!("Help::write_before_after_help: Too long..."); + if too_long || h.contains("{n}") { + sdebugln!("Yes"); + debugln!("Help::write_before_after_help: help: {}", help); + debugln!( + "Help::write_before_after_help: help width: {}", + str_width(&*help) + ); + // Determine how many newlines we need to insert + debugln!( + "Help::write_before_after_help: Usable space: {}", + self.term_w + ); + help = wrap_help(&help.replace("{n}", "\n"), self.term_w); + } else { + sdebugln!("No"); + } + write!(self.writer, "{}", help)?; + Ok(()) + } + + /// Writes argument's help to the wrapped stream. + fn help<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>, spec_vals: &str) -> io::Result<()> { + debugln!("Help::help;"); + let h = if self.use_long && arg.name() != "" { + arg.long_help().unwrap_or_else(|| arg.help().unwrap_or("")) + } else { + arg.help().unwrap_or_else(|| arg.long_help().unwrap_or("")) + }; + let mut help = String::from(h) + spec_vals; + let nlh = self.next_line_help + || arg.is_set(ArgSettings::NextLineHelp) + || (self.use_long && arg.name() != ""); + debugln!("Help::help: Next Line...{:?}", nlh); + + let spcs = if nlh || self.force_next_line { + 12 // "tab" * 3 + } else { + self.longest + 12 + }; + + let too_long = spcs + str_width(h) + str_width(&*spec_vals) >= self.term_w; + + // Is help on next line, if so then indent + if nlh || self.force_next_line { + write!(self.writer, "\n{}{}{}", TAB, TAB, TAB)?; + } + + debug!("Help::help: Too long..."); + if too_long && spcs <= self.term_w || h.contains("{n}") { + sdebugln!("Yes"); + debugln!("Help::help: help...{}", help); + debugln!("Help::help: help width...{}", str_width(&*help)); + // Determine how many newlines we need to insert + let avail_chars = self.term_w - spcs; + debugln!("Help::help: Usable space...{}", avail_chars); + help = wrap_help(&help.replace("{n}", "\n"), avail_chars); + } else { + sdebugln!("No"); + } + if let Some(part) = help.lines().next() { + write!(self.writer, "{}", part)?; + } + for part in help.lines().skip(1) { + writeln!(self.writer)?; + if nlh || self.force_next_line { + write!(self.writer, "{}{}{}", TAB, TAB, TAB)?; + } else if arg.has_switch() { + write_nspaces!(self.writer, self.longest + 12); + } else { + write_nspaces!(self.writer, self.longest + 8); + } + write!(self.writer, "{}", part)?; + } + if !help.contains('\n') && (nlh || self.force_next_line) { + writeln!(self.writer)?; + } + Ok(()) + } + + fn spec_vals(&self, a: &ArgWithDisplay) -> String { + debugln!("Help::spec_vals: a={}", a); + let mut spec_vals = vec![]; + if let Some(ref env) = a.env() { + debugln!( + "Help::spec_vals: Found environment variable...[{:?}:{:?}]", + env.0, + env.1 + ); + let env_val = if !a.is_set(ArgSettings::HideEnvValues) { + format!( + "={}", + env.1.map_or(Cow::Borrowed(""), |val| val.to_string_lossy()) + ) + } else { + String::new() + }; + let env_info = format!(" [env: {}{}]", env.0.to_string_lossy(), env_val); + spec_vals.push(env_info); + } + if !a.is_set(ArgSettings::HideDefaultValue) { + if let Some(pv) = a.default_val() { + debugln!("Help::spec_vals: Found default value...[{:?}]", pv); + spec_vals.push(format!( + " [default: {}]", + if self.color { + self.cizer.good(pv.to_string_lossy()) + } else { + Format::None(pv.to_string_lossy()) + } + )); + } + } + if let Some(ref aliases) = a.aliases() { + debugln!("Help::spec_vals: Found aliases...{:?}", aliases); + spec_vals.push(format!( + " [aliases: {}]", + if self.color { + aliases + .iter() + .map(|v| format!("{}", self.cizer.good(v))) + .collect::>() + .join(", ") + } else { + aliases.join(", ") + } + )); + } + if !self.hide_pv && !a.is_set(ArgSettings::HidePossibleValues) { + if let Some(pv) = a.possible_vals() { + debugln!("Help::spec_vals: Found possible vals...{:?}", pv); + spec_vals.push(if self.color { + format!( + " [possible values: {}]", + pv.iter() + .map(|v| format!("{}", self.cizer.good(v))) + .collect::>() + .join(", ") + ) + } else { + format!(" [possible values: {}]", pv.join(", ")) + }); + } + } + spec_vals.join(" ") + } +} + +fn should_show_arg(use_long: bool, arg: &ArgWithOrder) -> bool { + if arg.is_set(ArgSettings::Hidden) { + return false; + } + + (!arg.is_set(ArgSettings::HiddenLongHelp) && use_long) + || (!arg.is_set(ArgSettings::HiddenShortHelp) && !use_long) + || arg.is_set(ArgSettings::NextLineHelp) +} + +// Methods to write Parser help. +impl<'a> Help<'a> { + /// Writes help for all arguments (options, flags, args, subcommands) + /// including titles of a Parser Object to the wrapped stream. + pub fn write_all_args(&mut self, parser: &Parser) -> ClapResult<()> { + debugln!("Help::write_all_args;"); + let flags = parser.has_flags(); + let pos = parser + .positionals() + .filter(|arg| !arg.is_set(ArgSettings::Hidden)) + .count() + > 0; + let opts = parser.has_opts(); + let subcmds = parser.has_visible_subcommands(); + + let unified_help = parser.is_set(AppSettings::UnifiedHelpMessage); + + let mut first = true; + + if unified_help && (flags || opts) { + let opts_flags = parser + .flags() + .map(as_arg_trait) + .chain(parser.opts().map(as_arg_trait)); + color!(self, "OPTIONS:\n", warning)?; + self.write_args(opts_flags)?; + first = false; + } else { + if flags { + color!(self, "FLAGS:\n", warning)?; + self.write_args(parser.flags().map(as_arg_trait))?; + first = false; + } + if opts { + if !first { + self.writer.write_all(b"\n\n")?; + } + color!(self, "OPTIONS:\n", warning)?; + self.write_args(parser.opts().map(as_arg_trait))?; + first = false; + } + } + + if pos { + if !first { + self.writer.write_all(b"\n\n")?; + } + color!(self, "ARGS:\n", warning)?; + self.write_args_unsorted(parser.positionals().map(as_arg_trait))?; + first = false; + } + + if subcmds { + if !first { + self.writer.write_all(b"\n\n")?; + } + color!(self, "SUBCOMMANDS:\n", warning)?; + self.write_subcommands(parser)?; + } + + Ok(()) + } + + /// Writes help for subcommands of a Parser Object to the wrapped stream. + fn write_subcommands(&mut self, parser: &Parser) -> io::Result<()> { + debugln!("Help::write_subcommands;"); + // The shortest an arg can legally be is 2 (i.e. '-x') + self.longest = 2; + let mut ord_m = VecMap::new(); + for sc in parser + .subcommands + .iter() + .filter(|s| !s.p.is_set(AppSettings::Hidden)) + { + let btm = ord_m.entry(sc.p.meta.disp_ord).or_insert(BTreeMap::new()); + self.longest = cmp::max(self.longest, str_width(sc.p.meta.name.as_str())); + //self.longest = cmp::max(self.longest, sc.p.meta.name.len()); + btm.insert(sc.p.meta.name.clone(), sc.clone()); + } + + let mut first = true; + for btm in ord_m.values() { + for sc in btm.values() { + if first { + first = false; + } else { + self.writer.write_all(b"\n")?; + } + self.write_arg(sc)?; + } + } + Ok(()) + } + + /// Writes version of a Parser Object to the wrapped stream. + fn write_version(&mut self, parser: &Parser) -> io::Result<()> { + debugln!("Help::write_version;"); + write!(self.writer, "{}", parser.meta.version.unwrap_or(""))?; + Ok(()) + } + + /// Writes binary name of a Parser Object to the wrapped stream. + fn write_bin_name(&mut self, parser: &Parser) -> io::Result<()> { + debugln!("Help::write_bin_name;"); + macro_rules! write_name { + () => {{ + let mut name = parser.meta.name.clone(); + name = name.replace("{n}", "\n"); + color!(self, wrap_help(&name, self.term_w), good)?; + }}; + } + if let Some(bn) = parser.meta.bin_name.as_ref() { + if bn.contains(' ') { + // Incase we're dealing with subcommands i.e. git mv is translated to git-mv + color!(self, bn.replace(" ", "-"), good)? + } else { + write_name!(); + } + } else { + write_name!(); + } + Ok(()) + } + + /// Writes default help for a Parser Object to the wrapped stream. + pub fn write_default_help(&mut self, parser: &Parser) -> ClapResult<()> { + debugln!("Help::write_default_help;"); + if let Some(h) = parser.meta.pre_help { + self.write_before_after_help(h)?; + self.writer.write_all(b"\n\n")?; + } + + macro_rules! write_thing { + ($thing:expr) => {{ + let mut owned_thing = $thing.to_owned(); + owned_thing = owned_thing.replace("{n}", "\n"); + write!(self.writer, "{}\n", wrap_help(&owned_thing, self.term_w))? + }}; + } + // Print the version + self.write_bin_name(parser)?; + self.writer.write_all(b" ")?; + self.write_version(parser)?; + self.writer.write_all(b"\n")?; + if let Some(author) = parser.meta.author { + write_thing!(author) + } + // if self.use_long { + // if let Some(about) = parser.meta.long_about { + // debugln!("Help::write_default_help: writing long about"); + // write_thing!(about) + // } else if let Some(about) = parser.meta.about { + // debugln!("Help::write_default_help: writing about"); + // write_thing!(about) + // } + // } else + if let Some(about) = parser.meta.long_about { + debugln!("Help::write_default_help: writing long about"); + write_thing!(about) + } else if let Some(about) = parser.meta.about { + debugln!("Help::write_default_help: writing about"); + write_thing!(about) + } + + color!(self, "\nUSAGE:", warning)?; + write!( + self.writer, + "\n{}{}\n\n", + TAB, + usage::create_usage_no_title(parser, &[]) + )?; + + let flags = parser.has_flags(); + let pos = parser.has_positionals(); + let opts = parser.has_opts(); + let subcmds = parser.has_subcommands(); + + if flags || opts || pos || subcmds { + self.write_all_args(parser)?; + } + + if let Some(h) = parser.meta.more_help { + if flags || opts || pos || subcmds { + self.writer.write_all(b"\n\n")?; + } + self.write_before_after_help(h)?; + } + + self.writer.flush().map_err(Error::from) + } +} + +/// Possible results for a copying function that stops when a given +/// byte was found. +enum CopyUntilResult { + DelimiterFound(usize), + DelimiterNotFound(usize), + ReaderEmpty, + ReadError(io::Error), + WriteError(io::Error), +} + +/// Copies the contents of a reader into a writer until a delimiter byte is found. +/// On success, the total number of bytes that were +/// copied from reader to writer is returned. +fn copy_until(r: &mut R, w: &mut W, delimiter_byte: u8) -> CopyUntilResult { + debugln!("copy_until;"); + + let mut count = 0; + for wb in r.bytes() { + match wb { + Ok(b) => { + if b == delimiter_byte { + return CopyUntilResult::DelimiterFound(count); + } + match w.write(&[b]) { + Ok(c) => count += c, + Err(e) => return CopyUntilResult::WriteError(e), + } + } + Err(e) => return CopyUntilResult::ReadError(e), + } + } + if count > 0 { + CopyUntilResult::DelimiterNotFound(count) + } else { + CopyUntilResult::ReaderEmpty + } +} + +/// Copies the contents of a reader into a writer until a {tag} is found, +/// copying the tag content to a buffer and returning its size. +/// In addition to errors, there are three possible outputs: +/// - `None`: The reader was consumed. +/// - `Some(Ok(0))`: No tag was captured but the reader still contains data. +/// - `Some(Ok(length>0))`: a tag with `length` was captured to the `tag_buffer`. +fn copy_and_capture( + r: &mut R, + w: &mut W, + tag_buffer: &mut Cursor>, +) -> Option> { + use self::CopyUntilResult::*; + debugln!("copy_and_capture;"); + + // Find the opening byte. + match copy_until(r, w, b'{') { + // The end of the reader was reached without finding the opening tag. + // (either with or without having copied data to the writer) + // Return None indicating that we are done. + ReaderEmpty | DelimiterNotFound(_) => None, + + // Something went wrong. + ReadError(e) | WriteError(e) => Some(Err(e)), + + // The opening byte was found. + // (either with or without having copied data to the writer) + DelimiterFound(_) => { + // Lets reset the buffer first and find out how long it is. + tag_buffer.set_position(0); + let buffer_size = tag_buffer.get_ref().len(); + + // Find the closing byte,limiting the reader to the length of the buffer. + let mut rb = r.take(buffer_size as u64); + match copy_until(&mut rb, tag_buffer, b'}') { + // We were already at the end of the reader. + // Return None indicating that we are done. + ReaderEmpty => None, + + // The closing tag was found. + // Return the tag_length. + DelimiterFound(tag_length) => Some(Ok(tag_length)), + + // The end of the reader was found without finding the closing tag. + // Write the opening byte and captured text to the writer. + // Return 0 indicating that nothing was captured but the reader still contains data. + DelimiterNotFound(not_tag_length) => match w.write(b"{") { + Err(e) => Some(Err(e)), + _ => match w.write(&tag_buffer.get_ref()[0..not_tag_length]) { + Err(e) => Some(Err(e)), + _ => Some(Ok(0)), + }, + }, + + ReadError(e) | WriteError(e) => Some(Err(e)), + } + } + } +} + +// Methods to write Parser help using templates. +impl<'a> Help<'a> { + /// Write help to stream for the parser in the format defined by the template. + /// + /// Tags arg given inside curly brackets: + /// Valid tags are: + /// * `{bin}` - Binary name. + /// * `{version}` - Version number. + /// * `{author}` - Author information. + /// * `{usage}` - Automatically generated or given usage string. + /// * `{all-args}` - Help for all arguments (options, flags, positionals arguments, + /// and subcommands) including titles. + /// * `{unified}` - Unified help for options and flags. + /// * `{flags}` - Help for flags. + /// * `{options}` - Help for options. + /// * `{positionals}` - Help for positionals arguments. + /// * `{subcommands}` - Help for subcommands. + /// * `{after-help}` - Info to be displayed after the help message. + /// * `{before-help}` - Info to be displayed before the help message. + /// + /// The template system is, on purpose, very simple. Therefore the tags have to written + /// in the lowercase and without spacing. + fn write_templated_help(&mut self, parser: &Parser, template: &str) -> ClapResult<()> { + debugln!("Help::write_templated_help;"); + let mut tmplr = Cursor::new(&template); + let mut tag_buf = Cursor::new(vec![0u8; 15]); + + // The strategy is to copy the template from the reader to wrapped stream + // until a tag is found. Depending on its value, the appropriate content is copied + // to the wrapped stream. + // The copy from template is then resumed, repeating this sequence until reading + // the complete template. + + loop { + let tag_length = match copy_and_capture(&mut tmplr, &mut self.writer, &mut tag_buf) { + None => return Ok(()), + Some(Err(e)) => return Err(Error::from(e)), + Some(Ok(val)) if val > 0 => val, + _ => continue, + }; + + debugln!("Help::write_template_help:iter: tag_buf={};", unsafe { + String::from_utf8_unchecked( + tag_buf.get_ref()[0..tag_length] + .iter() + .map(|&i| i) + .collect::>(), + ) + }); + match &tag_buf.get_ref()[0..tag_length] { + b"?" => { + self.writer.write_all(b"Could not decode tag name")?; + } + b"bin" => { + self.write_bin_name(parser)?; + } + b"version" => { + write!( + self.writer, + "{}", + parser.meta.version.unwrap_or("unknown version") + )?; + } + b"author" => { + write!( + self.writer, + "{}", + parser.meta.author.unwrap_or("unknown author") + )?; + } + b"about" => { + write!( + self.writer, + "{}", + parser.meta.about.unwrap_or("unknown about") + )?; + } + b"long-about" => { + write!( + self.writer, + "{}", + parser.meta.long_about.unwrap_or("unknown about") + )?; + } + b"usage" => { + write!(self.writer, "{}", usage::create_usage_no_title(parser, &[]))?; + } + b"all-args" => { + self.write_all_args(parser)?; + } + b"unified" => { + let opts_flags = parser + .flags() + .map(as_arg_trait) + .chain(parser.opts().map(as_arg_trait)); + self.write_args(opts_flags)?; + } + b"flags" => { + self.write_args(parser.flags().map(as_arg_trait))?; + } + b"options" => { + self.write_args(parser.opts().map(as_arg_trait))?; + } + b"positionals" => { + self.write_args(parser.positionals().map(as_arg_trait))?; + } + b"subcommands" => { + self.write_subcommands(parser)?; + } + b"after-help" => { + write!( + self.writer, + "{}", + parser.meta.more_help.unwrap_or("unknown after-help") + )?; + } + b"before-help" => { + write!( + self.writer, + "{}", + parser.meta.pre_help.unwrap_or("unknown before-help") + )?; + } + // Unknown tag, write it back. + r => { + self.writer.write_all(b"{")?; + self.writer.write_all(r)?; + self.writer.write_all(b"}")?; + } + } + } + } +} + +fn wrap_help(help: &str, avail_chars: usize) -> String { + let wrapper = textwrap::Wrapper::new(avail_chars).break_words(false); + help.lines() + .map(|line| wrapper.fill(line)) + .collect::>() + .join("\n") +} + +#[cfg(test)] +mod test { + use super::wrap_help; + + #[test] + fn wrap_help_last_word() { + let help = String::from("foo bar baz"); + assert_eq!(wrap_help(&help, 5), "foo\nbar\nbaz"); + } +} diff --git a/vendor/clap-2.34.0/src/app/meta.rs b/vendor/clap-2.34.0/src/app/meta.rs new file mode 100644 index 0000000000000..8916101015be7 --- /dev/null +++ b/vendor/clap-2.34.0/src/app/meta.rs @@ -0,0 +1,35 @@ +#[doc(hidden)] +#[allow(missing_debug_implementations)] +#[derive(Default, Clone)] +pub struct AppMeta<'b> { + pub name: String, + pub bin_name: Option, + pub author: Option<&'b str>, + pub version: Option<&'b str>, + pub long_version: Option<&'b str>, + pub about: Option<&'b str>, + pub long_about: Option<&'b str>, + pub more_help: Option<&'b str>, + pub pre_help: Option<&'b str>, + pub aliases: Option>, // (name, visible) + pub usage_str: Option<&'b str>, + pub usage: Option, + pub help_str: Option<&'b str>, + pub disp_ord: usize, + pub term_w: Option, + pub max_w: Option, + pub template: Option<&'b str>, +} + +impl<'b> AppMeta<'b> { + pub fn new() -> Self { + Default::default() + } + pub fn with_name(s: String) -> Self { + AppMeta { + name: s, + disp_ord: 999, + ..Default::default() + } + } +} diff --git a/vendor/clap-2.34.0/src/app/mod.rs b/vendor/clap-2.34.0/src/app/mod.rs new file mode 100644 index 0000000000000..c8ae912bc7ce8 --- /dev/null +++ b/vendor/clap-2.34.0/src/app/mod.rs @@ -0,0 +1,1909 @@ +mod help; +mod meta; +pub mod parser; +mod settings; +mod usage; +mod validator; + +// Std +use std::result::Result as StdResult; +use std::{ + env, + ffi::{OsStr, OsString}, + fmt, + io::{self, BufRead, BufWriter, Write}, + path::Path, + process, + rc::Rc, +}; + +// Third Party +#[cfg(feature = "yaml")] +use yaml_rust::Yaml; + +// Internal +use crate::errors::Result as ClapResult; +use crate::{ + app::{help::Help, parser::Parser}, + args::{AnyArg, Arg, ArgGroup, ArgMatcher, ArgMatches, ArgSettings}, + completions::Shell, + map::{self, VecMap}, +}; +pub use settings::AppSettings; + +/// Used to create a representation of a command line program and all possible command line +/// arguments. Application settings are set using the "builder pattern" with the +/// [`App::get_matches`] family of methods being the terminal methods that starts the +/// runtime-parsing process. These methods then return information about the user supplied +/// arguments (or lack there of). +/// +/// **NOTE:** There aren't any mandatory "options" that one must set. The "options" may +/// also appear in any order (so long as one of the [`App::get_matches`] methods is the last method +/// called). +/// +/// # Examples +/// +/// ```no_run +/// # use clap::{App, Arg}; +/// let m = App::new("My Program") +/// .author("Me, me@mail.com") +/// .version("1.0.2") +/// .about("Explains in brief what the program does") +/// .arg( +/// Arg::with_name("in_file").index(1) +/// ) +/// .after_help("Longer explanation to appear after the options when \ +/// displaying the help information from --help or -h") +/// .get_matches(); +/// +/// // Your program logic starts here... +/// ``` +/// [`App::get_matches`]: ./struct.App.html#method.get_matches +#[allow(missing_debug_implementations)] +pub struct App<'a, 'b> +where + 'a: 'b, +{ + #[doc(hidden)] + pub p: Parser<'a, 'b>, +} + +impl<'a, 'b> App<'a, 'b> { + /// Creates a new instance of an application requiring a name. The name may be, but doesn't + /// have to be same as the binary. The name will be displayed to the user when they request to + /// print version or help and usage information. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let prog = App::new("My Program") + /// # ; + /// ``` + pub fn new>(n: S) -> Self { + App { + p: Parser::with_name(n.into()), + } + } + + /// Get the name of the app + pub fn get_name(&self) -> &str { + &self.p.meta.name + } + + /// Get the name of the binary + pub fn get_bin_name(&self) -> Option<&str> { + self.p.meta.bin_name.as_deref() + } + + /// Creates a new instance of an application requiring a name, but uses the [`crate_authors!`] + /// and [`crate_version!`] macros to fill in the [`App::author`] and [`App::version`] fields. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let prog = App::with_defaults("My Program") + /// # ; + /// ``` + /// [`crate_authors!`]: ./macro.crate_authors!.html + /// [`crate_version!`]: ./macro.crate_version!.html + /// [`App::author`]: ./struct.App.html#method.author + /// [`App::version`]: ./struct.App.html#method.author + #[deprecated( + since = "2.14.1", + note = "Can never work; use explicit App::author() and App::version() calls instead" + )] + pub fn with_defaults>(n: S) -> Self { + let mut a = App { + p: Parser::with_name(n.into()), + }; + a.p.meta.author = Some("Kevin K. "); + a.p.meta.version = Some("2.19.2"); + a + } + + /// Creates a new instance of [`App`] from a .yml (YAML) file. A full example of supported YAML + /// objects can be found in [`examples/17_yaml.rs`] and [`examples/17_yaml.yml`]. One great use + /// for using YAML is when supporting multiple languages and dialects, as each language could + /// be a distinct YAML file and determined at compiletime via `cargo` "features" in your + /// `Cargo.toml` + /// + /// In order to use this function you must compile `clap` with the `features = ["yaml"]` in + /// your settings for the `[dependencies.clap]` table of your `Cargo.toml` + /// + /// **NOTE:** Due to how the YAML objects are built there is a convenience macro for loading + /// the YAML file at compile time (relative to the current file, like modules work). That YAML + /// object can then be passed to this function. + /// + /// # Panics + /// + /// The YAML file must be properly formatted or this function will [`panic!`]. A good way to + /// ensure this doesn't happen is to run your program with the `--help` switch. If this passes + /// without error, you needn't worry because the YAML is properly formatted. + /// + /// # Examples + /// + /// The following example shows how to load a properly formatted YAML file to build an instance + /// of an [`App`] struct. + /// + /// ```ignore + /// # #[macro_use] + /// # extern crate clap; + /// # use clap::App; + /// # fn main() { + /// let yml = load_yaml!("app.yml"); + /// let app = App::from_yaml(yml); + /// + /// // continued logic goes here, such as `app.get_matches()` etc. + /// # } + /// ``` + /// [`App`]: ./struct.App.html + /// [`examples/17_yaml.rs`]: https://github.com/clap-rs/clap/blob/v2.33.1/examples/17_yaml.rs + /// [`examples/17_yaml.yml`]: https://github.com/clap-rs/clap/blob/v2.33.1/examples/17_yaml.yml + /// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html + #[cfg(feature = "yaml")] + pub fn from_yaml(yaml: &'a Yaml) -> App<'a, 'a> { + App::from(yaml) + } + + /// Sets a string of author(s) that will be displayed to the user when they + /// request the help information with `--help` or `-h`. + /// + /// **Pro-tip:** Use `clap`s convenience macro [`crate_authors!`] to automatically set your + /// application's author(s) to the same thing as your crate at compile time. See the [`examples/`] + /// directory for more information + /// + /// See the [`examples/`] + /// directory for more information + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .author("Me, me@mymain.com") + /// # ; + /// ``` + /// [`crate_authors!`]: ./macro.crate_authors!.html + /// [`examples/`]: https://github.com/clap-rs/clap/tree/v2.33.1/examples + pub fn author>(mut self, author: S) -> Self { + self.p.meta.author = Some(author.into()); + self + } + + /// Overrides the system-determined binary name. This should only be used when absolutely + /// necessary, such as when the binary name for your application is misleading, or perhaps + /// *not* how the user should invoke your program. + /// + /// **Pro-tip:** When building things such as third party `cargo` subcommands, this setting + /// **should** be used! + /// + /// **NOTE:** This command **should not** be used for [`SubCommand`]s. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("My Program") + /// .bin_name("my_binary") + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + pub fn bin_name>(mut self, name: S) -> Self { + self.p.meta.bin_name = Some(name.into()); + self + } + + /// Sets a string describing what the program does. This will be displayed when displaying help + /// information with `-h`. + /// + /// **NOTE:** If only `about` is provided, and not [`App::long_about`] but the user requests + /// `--help` clap will still display the contents of `about` appropriately + /// + /// **NOTE:** Only [`App::about`] is used in completion script generation in order to be + /// concise + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .about("Does really amazing things to great people") + /// # ; + /// ``` + /// [`App::long_about`]: ./struct.App.html#method.long_about + pub fn about>(mut self, about: S) -> Self { + self.p.meta.about = Some(about.into()); + self + } + + /// Sets a string describing what the program does. This will be displayed when displaying help + /// information. + /// + /// **NOTE:** If only `long_about` is provided, and not [`App::about`] but the user requests + /// `-h` clap will still display the contents of `long_about` appropriately + /// + /// **NOTE:** Only [`App::about`] is used in completion script generation in order to be + /// concise + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .long_about( + /// "Does really amazing things to great people. Now let's talk a little + /// more in depth about how this subcommand really works. It may take about + /// a few lines of text, but that's ok!") + /// # ; + /// ``` + /// [`App::about`]: ./struct.App.html#method.about + pub fn long_about>(mut self, about: S) -> Self { + self.p.meta.long_about = Some(about.into()); + self + } + + /// Sets the program's name. This will be displayed when displaying help information. + /// + /// **Pro-top:** This function is particularly useful when configuring a program via + /// [`App::from_yaml`] in conjunction with the [`crate_name!`] macro to derive the program's + /// name from its `Cargo.toml`. + /// + /// # Examples + /// ```ignore + /// # #[macro_use] + /// # extern crate clap; + /// # use clap::App; + /// # fn main() { + /// let yml = load_yaml!("app.yml"); + /// let app = App::from_yaml(yml) + /// .name(crate_name!()); + /// + /// // continued logic goes here, such as `app.get_matches()` etc. + /// # } + /// ``` + /// + /// [`App::from_yaml`]: ./struct.App.html#method.from_yaml + /// [`crate_name!`]: ./macro.crate_name.html + pub fn name>(mut self, name: S) -> Self { + self.p.meta.name = name.into(); + self + } + + /// Adds additional help information to be displayed in addition to auto-generated help. This + /// information is displayed **after** the auto-generated help information. This is often used + /// to describe how to use the arguments, or caveats to be noted. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::App; + /// App::new("myprog") + /// .after_help("Does really amazing things to great people...but be careful with -R") + /// # ; + /// ``` + pub fn after_help>(mut self, help: S) -> Self { + self.p.meta.more_help = Some(help.into()); + self + } + + /// Adds additional help information to be displayed in addition to auto-generated help. This + /// information is displayed **before** the auto-generated help information. This is often used + /// for header information. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::App; + /// App::new("myprog") + /// .before_help("Some info I'd like to appear before the help info") + /// # ; + /// ``` + pub fn before_help>(mut self, help: S) -> Self { + self.p.meta.pre_help = Some(help.into()); + self + } + + /// Sets a string of the version number to be displayed when displaying version or help + /// information with `-V`. + /// + /// **NOTE:** If only `version` is provided, and not [`App::long_version`] but the user + /// requests `--version` clap will still display the contents of `version` appropriately + /// + /// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your + /// application's version to the same thing as your crate at compile time. See the [`examples/`] + /// directory for more information + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .version("v0.1.24") + /// # ; + /// ``` + /// [`crate_version!`]: ./macro.crate_version!.html + /// [`examples/`]: https://github.com/clap-rs/clap/tree/v2.33.1/examples + /// [`App::long_version`]: ./struct.App.html#method.long_version + pub fn version>(mut self, ver: S) -> Self { + self.p.meta.version = Some(ver.into()); + self + } + + /// Sets a string of the version number to be displayed when displaying version or help + /// information with `--version`. + /// + /// **NOTE:** If only `long_version` is provided, and not [`App::version`] but the user + /// requests `-V` clap will still display the contents of `long_version` appropriately + /// + /// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your + /// application's version to the same thing as your crate at compile time. See the [`examples/`] + /// directory for more information + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .long_version( + /// "v0.1.24 + /// commit: abcdef89726d + /// revision: 123 + /// release: 2 + /// binary: myprog") + /// # ; + /// ``` + /// [`crate_version!`]: ./macro.crate_version!.html + /// [`examples/`]: https://github.com/clap-rs/clap/tree/v2.33.1/examples + /// [`App::version`]: ./struct.App.html#method.version + pub fn long_version>(mut self, ver: S) -> Self { + self.p.meta.long_version = Some(ver.into()); + self + } + + /// Sets a custom usage string to override the auto-generated usage string. + /// + /// This will be displayed to the user when errors are found in argument parsing, or when you + /// call [`ArgMatches::usage`] + /// + /// **CAUTION:** Using this setting disables `clap`s "context-aware" usage strings. After this + /// setting is set, this will be the only usage string displayed to the user! + /// + /// **NOTE:** You do not need to specify the "USAGE: \n\t" portion, as that will + /// still be applied by `clap`, you only need to specify the portion starting + /// with the binary name. + /// + /// **NOTE:** This will not replace the entire help message, *only* the portion + /// showing the usage. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .usage("myapp [-clDas] ") + /// # ; + /// ``` + /// [`ArgMatches::usage`]: ./struct.ArgMatches.html#method.usage + pub fn usage>(mut self, usage: S) -> Self { + self.p.meta.usage_str = Some(usage.into()); + self + } + + /// Sets a custom help message and overrides the auto-generated one. This should only be used + /// when the auto-generated message does not suffice. + /// + /// This will be displayed to the user when they use `--help` or `-h` + /// + /// **NOTE:** This replaces the **entire** help message, so nothing will be auto-generated. + /// + /// **NOTE:** This **only** replaces the help message for the current command, meaning if you + /// are using subcommands, those help messages will still be auto-generated unless you + /// specify a [`Arg::help`] for them as well. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myapp") + /// .help("myapp v1.0\n\ + /// Does awesome things\n\ + /// (C) me@mail.com\n\n\ + /// + /// USAGE: myapp \n\n\ + /// + /// Options:\n\ + /// -h, --help Display this message\n\ + /// -V, --version Display version info\n\ + /// -s Do something with stuff\n\ + /// -v Be verbose\n\n\ + /// + /// Commmands:\n\ + /// help Prints this message\n\ + /// work Do some work") + /// # ; + /// ``` + /// [`Arg::help`]: ./struct.Arg.html#method.help + pub fn help>(mut self, help: S) -> Self { + self.p.meta.help_str = Some(help.into()); + self + } + + /// Sets the [`short`] for the auto-generated `help` argument. + /// + /// By default `clap` automatically assigns `h`, but this can be overridden if you have a + /// different argument which you'd prefer to use the `-h` short with. This can be done by + /// defining your own argument with a lowercase `h` as the [`short`]. + /// + /// `clap` lazily generates these `help` arguments **after** you've defined any arguments of + /// your own. + /// + /// **NOTE:** Any leading `-` characters will be stripped, and only the first + /// non `-` character will be used as the [`short`] version + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .help_short("H") // Using an uppercase `H` instead of the default lowercase `h` + /// # ; + /// ``` + /// [`short`]: ./struct.Arg.html#method.short + pub fn help_short + 'b>(mut self, s: S) -> Self { + self.p.help_short(s.as_ref()); + self + } + + /// Sets the [`short`] for the auto-generated `version` argument. + /// + /// By default `clap` automatically assigns `V`, but this can be overridden if you have a + /// different argument which you'd prefer to use the `-V` short with. This can be done by + /// defining your own argument with an uppercase `V` as the [`short`]. + /// + /// `clap` lazily generates these `version` arguments **after** you've defined any arguments of + /// your own. + /// + /// **NOTE:** Any leading `-` characters will be stripped, and only the first + /// non `-` character will be used as the `short` version + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .version_short("v") // Using a lowercase `v` instead of the default capital `V` + /// # ; + /// ``` + /// [`short`]: ./struct.Arg.html#method.short + pub fn version_short>(mut self, s: S) -> Self { + self.p.version_short(s.as_ref()); + self + } + + /// Sets the help text for the auto-generated `help` argument. + /// + /// By default `clap` sets this to `"Prints help information"`, but if you're using a + /// different convention for your help messages and would prefer a different phrasing you can + /// override it. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .help_message("Print help information") // Perhaps you want imperative help messages + /// + /// # ; + /// ``` + pub fn help_message>(mut self, s: S) -> Self { + self.p.help_message = Some(s.into()); + self + } + + /// Sets the help text for the auto-generated `version` argument. + /// + /// By default `clap` sets this to `"Prints version information"`, but if you're using a + /// different convention for your help messages and would prefer a different phrasing then you + /// can change it. + /// + /// # Examples + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .version_message("Print version information") // Perhaps you want imperative help messages + /// # ; + /// ``` + pub fn version_message>(mut self, s: S) -> Self { + self.p.version_message = Some(s.into()); + self + } + + /// Sets the help template to be used, overriding the default format. + /// + /// Tags arg given inside curly brackets. + /// + /// Valid tags are: + /// + /// * `{bin}` - Binary name. + /// * `{version}` - Version number. + /// * `{author}` - Author information. + /// * `{about}` - General description (from [`App::about`]) + /// * `{usage}` - Automatically generated or given usage string. + /// * `{all-args}` - Help for all arguments (options, flags, positionals arguments, + /// and subcommands) including titles. + /// * `{unified}` - Unified help for options and flags. Note, you must *also* set + /// [`AppSettings::UnifiedHelpMessage`] to fully merge both options and + /// flags, otherwise the ordering is "best effort" + /// * `{flags}` - Help for flags. + /// * `{options}` - Help for options. + /// * `{positionals}` - Help for positionals arguments. + /// * `{subcommands}` - Help for subcommands. + /// * `{after-help}` - Help from [`App::after_help`] + /// * `{before-help}` - Help from [`App::before_help`] + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .version("1.0") + /// .template("{bin} ({version}) - {usage}") + /// # ; + /// ``` + /// **NOTE:** The template system is, on purpose, very simple. Therefore the tags have to be + /// written in lowercase and without spacing. + /// + /// [`App::about`]: ./struct.App.html#method.about + /// [`App::after_help`]: ./struct.App.html#method.after_help + /// [`App::before_help`]: ./struct.App.html#method.before_help + /// [`AppSettings::UnifiedHelpMessage`]: ./enum.AppSettings.html#variant.UnifiedHelpMessage + pub fn template>(mut self, s: S) -> Self { + self.p.meta.template = Some(s.into()); + self + } + + /// Enables a single command, or [`SubCommand`], level settings. + /// + /// See [`AppSettings`] for a full list of possibilities and examples. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::SubcommandRequired) + /// .setting(AppSettings::WaitOnError) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings`]: ./enum.AppSettings.html + pub fn setting(mut self, setting: AppSettings) -> Self { + self.p.set(setting); + self + } + + /// Enables multiple command, or [`SubCommand`], level settings + /// + /// See [`AppSettings`] for a full list of possibilities and examples. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, AppSettings}; + /// App::new("myprog") + /// .settings(&[AppSettings::SubcommandRequired, + /// AppSettings::WaitOnError]) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings`]: ./enum.AppSettings.html + pub fn settings(mut self, settings: &[AppSettings]) -> Self { + for s in settings { + self.p.set(*s); + } + self + } + + /// Enables a single setting that is propagated down through all child [`SubCommand`]s. + /// + /// See [`AppSettings`] for a full list of possibilities and examples. + /// + /// **NOTE**: The setting is *only* propagated *down* and not up through parent commands. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, AppSettings}; + /// App::new("myprog") + /// .global_setting(AppSettings::SubcommandRequired) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings`]: ./enum.AppSettings.html + pub fn global_setting(mut self, setting: AppSettings) -> Self { + self.p.set(setting); + self.p.g_settings.set(setting); + self + } + + /// Enables multiple settings which are propagated *down* through all child [`SubCommand`]s. + /// + /// See [`AppSettings`] for a full list of possibilities and examples. + /// + /// **NOTE**: The setting is *only* propagated *down* and not up through parent commands. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, AppSettings}; + /// App::new("myprog") + /// .global_settings(&[AppSettings::SubcommandRequired, + /// AppSettings::ColoredHelp]) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings`]: ./enum.AppSettings.html + pub fn global_settings(mut self, settings: &[AppSettings]) -> Self { + for s in settings { + self.p.set(*s); + self.p.g_settings.set(*s) + } + self + } + + /// Disables a single command, or [`SubCommand`], level setting. + /// + /// See [`AppSettings`] for a full list of possibilities and examples. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, AppSettings}; + /// App::new("myprog") + /// .unset_setting(AppSettings::ColorAuto) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings`]: ./enum.AppSettings.html + pub fn unset_setting(mut self, setting: AppSettings) -> Self { + self.p.unset(setting); + self + } + + /// Disables multiple command, or [`SubCommand`], level settings. + /// + /// See [`AppSettings`] for a full list of possibilities and examples. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, AppSettings}; + /// App::new("myprog") + /// .unset_settings(&[AppSettings::ColorAuto, + /// AppSettings::AllowInvalidUtf8]) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings`]: ./enum.AppSettings.html + pub fn unset_settings(mut self, settings: &[AppSettings]) -> Self { + for s in settings { + self.p.unset(*s); + } + self + } + + /// Sets the terminal width at which to wrap help messages. Defaults to `120`. Using `0` will + /// ignore terminal widths and use source formatting. + /// + /// `clap` automatically tries to determine the terminal width on Unix, Linux, macOS and Windows + /// if the `wrap_help` cargo "feature" has been used while compiling. If the terminal width + /// cannot be determined, `clap` defaults to `120`. + /// + /// **NOTE:** This setting applies globally and *not* on a per-command basis. + /// + /// **NOTE:** This setting must be set **before** any subcommands are added! + /// + /// # Platform Specific + /// + /// Only Unix, Linux, macOS and Windows support automatic determination of terminal width. + /// Even on those platforms, this setting is useful if for any reason the terminal width + /// cannot be determined. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::App; + /// App::new("myprog") + /// .set_term_width(80) + /// # ; + /// ``` + pub fn set_term_width(mut self, width: usize) -> Self { + self.p.meta.term_w = Some(width); + self + } + + /// Sets the max terminal width at which to wrap help messages. Using `0` will ignore terminal + /// widths and use source formatting. + /// + /// `clap` automatically tries to determine the terminal width on Unix, Linux, macOS and Windows + /// if the `wrap_help` cargo "feature" has been used while compiling, but one might want to + /// limit the size (e.g. when the terminal is running fullscreen). + /// + /// **NOTE:** This setting applies globally and *not* on a per-command basis. + /// + /// **NOTE:** This setting must be set **before** any subcommands are added! + /// + /// # Platform Specific + /// + /// Only Unix, Linux, macOS and Windows support automatic determination of terminal width. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::App; + /// App::new("myprog") + /// .max_term_width(100) + /// # ; + /// ``` + pub fn max_term_width(mut self, w: usize) -> Self { + self.p.meta.max_w = Some(w); + self + } + + /// Adds an [argument] to the list of valid possibilities. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// // Adding a single "flag" argument with a short and help text, using Arg::with_name() + /// .arg( + /// Arg::with_name("debug") + /// .short("d") + /// .help("turns on debugging mode") + /// ) + /// // Adding a single "option" argument with a short, a long, and help text using the less + /// // verbose Arg::from_usage() + /// .arg( + /// Arg::from_usage("-c --config=[CONFIG] 'Optionally sets a config file to use'") + /// ) + /// # ; + /// ``` + /// [argument]: ./struct.Arg.html + pub fn arg>>(mut self, a: A) -> Self { + self.p.add_arg(a.into()); + self + } + + /// Adds multiple [arguments] to the list of valid possibilities + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .args( + /// &[Arg::from_usage("[debug] -d 'turns on debugging info'"), + /// Arg::with_name("input").index(1).help("the input file to use")] + /// ) + /// # ; + /// ``` + /// [arguments]: ./struct.Arg.html + pub fn args(mut self, args: &[Arg<'a, 'b>]) -> Self { + for arg in args { + self.p.add_arg_ref(arg); + } + self + } + + /// A convenience method for adding a single [argument] from a usage type string. The string + /// used follows the same rules and syntax as [`Arg::from_usage`] + /// + /// **NOTE:** The downside to using this method is that you can not set any additional + /// properties of the [`Arg`] other than what [`Arg::from_usage`] supports. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .arg_from_usage("-c --config= 'Sets a configuration file to use'") + /// # ; + /// ``` + /// [argument]: ./struct.Arg.html + /// [`Arg`]: ./struct.Arg.html + /// [`Arg::from_usage`]: ./struct.Arg.html#method.from_usage + pub fn arg_from_usage(mut self, usage: &'a str) -> Self { + self.p.add_arg(Arg::from_usage(usage)); + self + } + + /// Adds multiple [arguments] at once from a usage string, one per line. See + /// [`Arg::from_usage`] for details on the syntax and rules supported. + /// + /// **NOTE:** Like [`App::arg_from_usage`] the downside is you only set properties for the + /// [`Arg`]s which [`Arg::from_usage`] supports. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .args_from_usage( + /// "-c --config=[FILE] 'Sets a configuration file to use' + /// [debug]... -d 'Sets the debugging level' + /// 'The input file to use'" + /// ) + /// # ; + /// ``` + /// [arguments]: ./struct.Arg.html + /// [`Arg::from_usage`]: ./struct.Arg.html#method.from_usage + /// [`App::arg_from_usage`]: ./struct.App.html#method.arg_from_usage + /// [`Arg`]: ./struct.Arg.html + pub fn args_from_usage(mut self, usage: &'a str) -> Self { + for line in usage.lines() { + let l = line.trim(); + if l.is_empty() { + continue; + } + self.p.add_arg(Arg::from_usage(l)); + } + self + } + + /// Allows adding a [`SubCommand`] alias, which function as "hidden" subcommands that + /// automatically dispatch as if this subcommand was used. This is more efficient, and easier + /// than creating multiple hidden subcommands as one only needs to check for the existence of + /// this command, and not all variants. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// let m = App::new("myprog") + /// .subcommand(SubCommand::with_name("test") + /// .alias("do-stuff")) + /// .get_matches_from(vec!["myprog", "do-stuff"]); + /// assert_eq!(m.subcommand_name(), Some("test")); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + pub fn alias>(mut self, name: S) -> Self { + if let Some(ref mut als) = self.p.meta.aliases { + als.push((name.into(), false)); + } else { + self.p.meta.aliases = Some(vec![(name.into(), false)]); + } + self + } + + /// Allows adding [`SubCommand`] aliases, which function as "hidden" subcommands that + /// automatically dispatch as if this subcommand was used. This is more efficient, and easier + /// than creating multiple hidden subcommands as one only needs to check for the existence of + /// this command, and not all variants. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, SubCommand}; + /// let m = App::new("myprog") + /// .subcommand(SubCommand::with_name("test") + /// .aliases(&["do-stuff", "do-tests", "tests"])) + /// .arg(Arg::with_name("input") + /// .help("the file to add") + /// .index(1) + /// .required(false)) + /// .get_matches_from(vec!["myprog", "do-tests"]); + /// assert_eq!(m.subcommand_name(), Some("test")); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + pub fn aliases(mut self, names: &[&'b str]) -> Self { + if let Some(ref mut als) = self.p.meta.aliases { + for n in names { + als.push((n, false)); + } + } else { + self.p.meta.aliases = Some(names.iter().map(|n| (*n, false)).collect::>()); + } + self + } + + /// Allows adding a [`SubCommand`] alias that functions exactly like those defined with + /// [`App::alias`], except that they are visible inside the help message. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// let m = App::new("myprog") + /// .subcommand(SubCommand::with_name("test") + /// .visible_alias("do-stuff")) + /// .get_matches_from(vec!["myprog", "do-stuff"]); + /// assert_eq!(m.subcommand_name(), Some("test")); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`App::alias`]: ./struct.App.html#method.alias + pub fn visible_alias>(mut self, name: S) -> Self { + if let Some(ref mut als) = self.p.meta.aliases { + als.push((name.into(), true)); + } else { + self.p.meta.aliases = Some(vec![(name.into(), true)]); + } + self + } + + /// Allows adding multiple [`SubCommand`] aliases that functions exactly like those defined + /// with [`App::aliases`], except that they are visible inside the help message. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// let m = App::new("myprog") + /// .subcommand(SubCommand::with_name("test") + /// .visible_aliases(&["do-stuff", "tests"])) + /// .get_matches_from(vec!["myprog", "do-stuff"]); + /// assert_eq!(m.subcommand_name(), Some("test")); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`App::aliases`]: ./struct.App.html#method.aliases + pub fn visible_aliases(mut self, names: &[&'b str]) -> Self { + if let Some(ref mut als) = self.p.meta.aliases { + for n in names { + als.push((n, true)); + } + } else { + self.p.meta.aliases = Some(names.iter().map(|n| (*n, true)).collect::>()); + } + self + } + + /// Adds an [`ArgGroup`] to the application. [`ArgGroup`]s are a family of related arguments. + /// By placing them in a logical group, you can build easier requirement and exclusion rules. + /// For instance, you can make an entire [`ArgGroup`] required, meaning that one (and *only* + /// one) argument from that group must be present at runtime. + /// + /// You can also do things such as name an [`ArgGroup`] as a conflict to another argument. + /// Meaning any of the arguments that belong to that group will cause a failure if present with + /// the conflicting argument. + /// + /// Another added benefit of [`ArgGroup`]s is that you can extract a value from a group instead + /// of determining exactly which argument was used. + /// + /// Finally, using [`ArgGroup`]s to ensure exclusion between arguments is another very common + /// use + /// + /// # Examples + /// + /// The following example demonstrates using an [`ArgGroup`] to ensure that one, and only one, + /// of the arguments from the specified group is present at runtime. + /// + /// ```no_run + /// # use clap::{App, ArgGroup}; + /// App::new("app") + /// .args_from_usage( + /// "--set-ver [ver] 'set the version manually' + /// --major 'auto increase major' + /// --minor 'auto increase minor' + /// --patch 'auto increase patch'") + /// .group(ArgGroup::with_name("vers") + /// .args(&["set-ver", "major", "minor","patch"]) + /// .required(true)) + /// # ; + /// ``` + /// [`ArgGroup`]: ./struct.ArgGroup.html + pub fn group(mut self, group: ArgGroup<'a>) -> Self { + self.p.add_group(group); + self + } + + /// Adds multiple [`ArgGroup`]s to the [`App`] at once. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, ArgGroup}; + /// App::new("app") + /// .args_from_usage( + /// "--set-ver [ver] 'set the version manually' + /// --major 'auto increase major' + /// --minor 'auto increase minor' + /// --patch 'auto increase patch' + /// -c [FILE] 'a config file' + /// -i [IFACE] 'an interface'") + /// .groups(&[ + /// ArgGroup::with_name("vers") + /// .args(&["set-ver", "major", "minor","patch"]) + /// .required(true), + /// ArgGroup::with_name("input") + /// .args(&["c", "i"]) + /// ]) + /// # ; + /// ``` + /// [`ArgGroup`]: ./struct.ArgGroup.html + /// [`App`]: ./struct.App.html + pub fn groups(mut self, groups: &[ArgGroup<'a>]) -> Self { + for g in groups { + self = self.group(g.into()); + } + self + } + + /// Adds a [`SubCommand`] to the list of valid possibilities. Subcommands are effectively + /// sub-[`App`]s, because they can contain their own arguments, subcommands, version, usage, + /// etc. They also function just like [`App`]s, in that they get their own auto generated help, + /// version, and usage. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// App::new("myprog") + /// .subcommand(SubCommand::with_name("config") + /// .about("Controls configuration features") + /// .arg_from_usage(" 'Required configuration file to use'")) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`App`]: ./struct.App.html + pub fn subcommand(mut self, subcmd: App<'a, 'b>) -> Self { + self.p.add_subcommand(subcmd); + self + } + + /// Adds multiple subcommands to the list of valid possibilities by iterating over an + /// [`IntoIterator`] of [`SubCommand`]s + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, SubCommand}; + /// # App::new("myprog") + /// .subcommands( vec![ + /// SubCommand::with_name("config").about("Controls configuration functionality") + /// .arg(Arg::with_name("config_file").index(1)), + /// SubCommand::with_name("debug").about("Controls debug functionality")]) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html + pub fn subcommands(mut self, subcmds: I) -> Self + where + I: IntoIterator>, + { + for subcmd in subcmds { + self.p.add_subcommand(subcmd); + } + self + } + + /// Allows custom ordering of [`SubCommand`]s within the help message. Subcommands with a lower + /// value will be displayed first in the help message. This is helpful when one would like to + /// emphasise frequently used subcommands, or prioritize those towards the top of the list. + /// Duplicate values **are** allowed. Subcommands with duplicate display orders will be + /// displayed in alphabetical order. + /// + /// **NOTE:** The default is 999 for all subcommands. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, SubCommand}; + /// let m = App::new("cust-ord") + /// .subcommand(SubCommand::with_name("alpha") // typically subcommands are grouped + /// // alphabetically by name. Subcommands + /// // without a display_order have a value of + /// // 999 and are displayed alphabetically with + /// // all other 999 subcommands + /// .about("Some help and text")) + /// .subcommand(SubCommand::with_name("beta") + /// .display_order(1) // In order to force this subcommand to appear *first* + /// // all we have to do is give it a value lower than 999. + /// // Any other subcommands with a value of 1 will be displayed + /// // alphabetically with this one...then 2 values, then 3, etc. + /// .about("I should be first!")) + /// .get_matches_from(vec![ + /// "cust-ord", "--help" + /// ]); + /// ``` + /// + /// The above example displays the following help message + /// + /// ```text + /// cust-ord + /// + /// USAGE: + /// cust-ord [FLAGS] [OPTIONS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// + /// SUBCOMMANDS: + /// beta I should be first! + /// alpha Some help and text + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + pub fn display_order(mut self, ord: usize) -> Self { + self.p.meta.disp_ord = ord; + self + } + + /// Prints the full help message to [`io::stdout()`] using a [`BufWriter`] using the same + /// method as if someone ran `-h` to request the help message + /// + /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages + /// depending on if the user ran [`-h` (short)] or [`--help` (long)] + /// + /// # Examples + /// + /// ```rust + /// # use clap::App; + /// let mut app = App::new("myprog"); + /// app.print_help(); + /// ``` + /// [`io::stdout()`]: https://doc.rust-lang.org/std/io/fn.stdout.html + /// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html + /// [`-h` (short)]: ./struct.Arg.html#method.help + /// [`--help` (long)]: ./struct.Arg.html#method.long_help + pub fn print_help(&mut self) -> ClapResult<()> { + // If there are global arguments, or settings we need to propagate them down to subcommands + // before parsing incase we run into a subcommand + self.p.propagate_globals(); + self.p.propagate_settings(); + self.p.derive_display_order(); + + self.p.create_help_and_version(); + let out = io::stdout(); + let mut buf_w = BufWriter::new(out.lock()); + self.write_help(&mut buf_w) + } + + /// Prints the full help message to [`io::stdout()`] using a [`BufWriter`] using the same + /// method as if someone ran `--help` to request the help message + /// + /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages + /// depending on if the user ran [`-h` (short)] or [`--help` (long)] + /// + /// # Examples + /// + /// ```rust + /// # use clap::App; + /// let mut app = App::new("myprog"); + /// app.print_long_help(); + /// ``` + /// [`io::stdout()`]: https://doc.rust-lang.org/std/io/fn.stdout.html + /// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html + /// [`-h` (short)]: ./struct.Arg.html#method.help + /// [`--help` (long)]: ./struct.Arg.html#method.long_help + pub fn print_long_help(&mut self) -> ClapResult<()> { + let out = io::stdout(); + let mut buf_w = BufWriter::new(out.lock()); + self.write_long_help(&mut buf_w) + } + + /// Writes the full help message to the user to a [`io::Write`] object in the same method as if + /// the user ran `-h` + /// + /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages + /// depending on if the user ran [`-h` (short)] or [`--help` (long)] + /// + /// **NOTE:** There is a known bug where this method does not write propagated global arguments + /// or autogenerated arguments (i.e. the default help/version args). Prefer + /// [`App::write_long_help`] instead if possible! + /// + /// # Examples + /// + /// ```rust + /// # use clap::App; + /// use std::io; + /// let mut app = App::new("myprog"); + /// let mut out = io::stdout(); + /// app.write_help(&mut out).expect("failed to write to stdout"); + /// ``` + /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html + /// [`-h` (short)]: ./struct.Arg.html#method.help + /// [`--help` (long)]: ./struct.Arg.html#method.long_help + pub fn write_help(&self, w: &mut W) -> ClapResult<()> { + // PENDING ISSUE: 808 + // https://github.com/clap-rs/clap/issues/808 + // If there are global arguments, or settings we need to propagate them down to subcommands + // before parsing incase we run into a subcommand + // self.p.propagate_globals(); + // self.p.propagate_settings(); + // self.p.derive_display_order(); + // self.p.create_help_and_version(); + + Help::write_app_help(w, self, false) + } + + /// Writes the full help message to the user to a [`io::Write`] object in the same method as if + /// the user ran `--help` + /// + /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages + /// depending on if the user ran [`-h` (short)] or [`--help` (long)] + /// + /// # Examples + /// + /// ```rust + /// # use clap::App; + /// use std::io; + /// let mut app = App::new("myprog"); + /// let mut out = io::stdout(); + /// app.write_long_help(&mut out).expect("failed to write to stdout"); + /// ``` + /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html + /// [`-h` (short)]: ./struct.Arg.html#method.help + /// [`--help` (long)]: ./struct.Arg.html#method.long_help + pub fn write_long_help(&mut self, w: &mut W) -> ClapResult<()> { + // If there are global arguments, or settings we need to propagate them down to subcommands + // before parsing incase we run into a subcommand + self.p.propagate_globals(); + self.p.propagate_settings(); + self.p.derive_display_order(); + self.p.create_help_and_version(); + + Help::write_app_help(w, self, true) + } + + /// Writes the version message to the user to a [`io::Write`] object as if the user ran `-V`. + /// + /// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages + /// depending on if the user ran [`-V` (short)] or [`--version` (long)] + /// + /// # Examples + /// + /// ```rust + /// # use clap::App; + /// use std::io; + /// let mut app = App::new("myprog"); + /// let mut out = io::stdout(); + /// app.write_version(&mut out).expect("failed to write to stdout"); + /// ``` + /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html + /// [`-V` (short)]: ./struct.App.html#method.version + /// [`--version` (long)]: ./struct.App.html#method.long_version + pub fn write_version(&self, w: &mut W) -> ClapResult<()> { + self.p.write_version(w, false).map_err(From::from) + } + + /// Writes the version message to the user to a [`io::Write`] object + /// + /// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages + /// depending on if the user ran [`-V` (short)] or [`--version` (long)] + /// + /// # Examples + /// + /// ```rust + /// # use clap::App; + /// use std::io; + /// let mut app = App::new("myprog"); + /// let mut out = io::stdout(); + /// app.write_long_version(&mut out).expect("failed to write to stdout"); + /// ``` + /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html + /// [`-V` (short)]: ./struct.App.html#method.version + /// [`--version` (long)]: ./struct.App.html#method.long_version + pub fn write_long_version(&self, w: &mut W) -> ClapResult<()> { + self.p.write_version(w, true).map_err(From::from) + } + + /// Generate a completions file for a specified shell at compile time. + /// + /// **NOTE:** to generate the file at compile time you must use a `build.rs` "Build Script" + /// + /// # Examples + /// + /// The following example generates a bash completion script via a `build.rs` script. In this + /// simple example, we'll demo a very small application with only a single subcommand and two + /// args. Real applications could be many multiple levels deep in subcommands, and have tens or + /// potentially hundreds of arguments. + /// + /// First, it helps if we separate out our `App` definition into a separate file. Whether you + /// do this as a function, or bare App definition is a matter of personal preference. + /// + /// ``` + /// // src/cli.rs + /// + /// use clap::{App, Arg, SubCommand}; + /// + /// pub fn build_cli() -> App<'static, 'static> { + /// App::new("compl") + /// .about("Tests completions") + /// .arg(Arg::with_name("file") + /// .help("some input file")) + /// .subcommand(SubCommand::with_name("test") + /// .about("tests things") + /// .arg(Arg::with_name("case") + /// .long("case") + /// .takes_value(true) + /// .help("the case to test"))) + /// } + /// ``` + /// + /// In our regular code, we can simply call this `build_cli()` function, then call + /// `get_matches()`, or any of the other normal methods directly after. For example: + /// + /// ```ignore + /// // src/main.rs + /// + /// mod cli; + /// + /// fn main() { + /// let m = cli::build_cli().get_matches(); + /// + /// // normal logic continues... + /// } + /// ``` + /// + /// Next, we set up our `Cargo.toml` to use a `build.rs` build script. + /// + /// ```toml + /// # Cargo.toml + /// build = "build.rs" + /// + /// [build-dependencies] + /// clap = "2.23" + /// ``` + /// + /// Next, we place a `build.rs` in our project root. + /// + /// ```ignore + /// extern crate clap; + /// + /// use clap::Shell; + /// + /// include!("src/cli.rs"); + /// + /// fn main() { + /// let outdir = match env::var_os("OUT_DIR") { + /// None => return, + /// Some(outdir) => outdir, + /// }; + /// let mut app = build_cli(); + /// app.gen_completions("myapp", // We need to specify the bin name manually + /// Shell::Bash, // Then say which shell to build completions for + /// outdir); // Then say where write the completions to + /// } + /// ``` + /// Now, once we compile there will be a `{bin_name}.bash` file in the directory. + /// Assuming we compiled with debug mode, it would be somewhere similar to + /// `/target/debug/build/myapp-/out/myapp.bash`. + /// + /// Fish shell completions will use the file format `{bin_name}.fish` + pub fn gen_completions, S: Into>( + &mut self, + bin_name: S, + for_shell: Shell, + out_dir: T, + ) { + self.p.meta.bin_name = Some(bin_name.into()); + self.p.gen_completions(for_shell, out_dir.into()); + } + + /// Generate a completions file for a specified shell at runtime. Until `cargo install` can + /// install extra files like a completion script, this may be used e.g. in a command that + /// outputs the contents of the completion script, to be redirected into a file by the user. + /// + /// # Examples + /// + /// Assuming a separate `cli.rs` like the [example above](./struct.App.html#method.gen_completions), + /// we can let users generate a completion script using a command: + /// + /// ```ignore + /// // src/main.rs + /// + /// mod cli; + /// use std::io; + /// + /// fn main() { + /// let matches = cli::build_cli().get_matches(); + /// + /// if matches.is_present("generate-bash-completions") { + /// cli::build_cli().gen_completions_to("myapp", Shell::Bash, &mut io::stdout()); + /// } + /// + /// // normal logic continues... + /// } + /// + /// ``` + /// + /// Usage: + /// + /// ```shell + /// $ myapp generate-bash-completions > /usr/share/bash-completion/completions/myapp.bash + /// ``` + pub fn gen_completions_to>( + &mut self, + bin_name: S, + for_shell: Shell, + buf: &mut W, + ) { + self.p.meta.bin_name = Some(bin_name.into()); + self.p.gen_completions_to(for_shell, buf); + } + + /// Starts the parsing process, upon a failed parse an error will be displayed to the user and + /// the process will exit with the appropriate error code. By default this method gets all user + /// provided arguments from [`env::args_os`] in order to allow for invalid UTF-8 code points, + /// which are legal on many platforms. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let matches = App::new("myprog") + /// // Args and options go here... + /// .get_matches(); + /// ``` + /// [`env::args_os`]: https://doc.rust-lang.org/std/env/fn.args_os.html + pub fn get_matches(self) -> ArgMatches<'a> { + self.get_matches_from(&mut env::args_os()) + } + + /// Starts the parsing process. This method will return a [`clap::Result`] type instead of exiting + /// the process on failed parse. By default this method gets matches from [`env::args_os`] + /// + /// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are + /// used. It will return a [`clap::Error`], where the [`kind`] is a + /// [`ErrorKind::HelpDisplayed`] or [`ErrorKind::VersionDisplayed`] respectively. You must call + /// [`Error::exit`] or perform a [`std::process::exit`]. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let matches = App::new("myprog") + /// // Args and options go here... + /// .get_matches_safe() + /// .unwrap_or_else( |e| e.exit() ); + /// ``` + /// [`env::args_os`]: https://doc.rust-lang.org/std/env/fn.args_os.html + /// [`ErrorKind::HelpDisplayed`]: ./enum.ErrorKind.html#variant.HelpDisplayed + /// [`ErrorKind::VersionDisplayed`]: ./enum.ErrorKind.html#variant.VersionDisplayed + /// [`Error::exit`]: ./struct.Error.html#method.exit + /// [`std::process::exit`]: https://doc.rust-lang.org/std/process/fn.exit.html + /// [`clap::Result`]: ./type.Result.html + /// [`clap::Error`]: ./struct.Error.html + /// [`kind`]: ./struct.Error.html + pub fn get_matches_safe(self) -> ClapResult> { + // Start the parsing + self.get_matches_from_safe(&mut env::args_os()) + } + + /// Starts the parsing process. Like [`App::get_matches`] this method does not return a [`clap::Result`] + /// and will automatically exit with an error message. This method, however, lets you specify + /// what iterator to use when performing matches, such as a [`Vec`] of your making. + /// + /// **NOTE:** The first argument will be parsed as the binary name unless + /// [`AppSettings::NoBinaryName`] is used + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"]; + /// + /// let matches = App::new("myprog") + /// // Args and options go here... + /// .get_matches_from(arg_vec); + /// ``` + /// [`App::get_matches`]: ./struct.App.html#method.get_matches + /// [`clap::Result`]: ./type.Result.html + /// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html + /// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName + pub fn get_matches_from(mut self, itr: I) -> ArgMatches<'a> + where + I: IntoIterator, + T: Into + Clone, + { + self.get_matches_from_safe_borrow(itr).unwrap_or_else(|e| { + // Otherwise, write to stderr and exit + if e.use_stderr() { + wlnerr!("{}", e.message); + if self.p.is_set(AppSettings::WaitOnError) { + wlnerr!("\nPress [ENTER] / [RETURN] to continue..."); + let mut s = String::new(); + let i = io::stdin(); + i.lock().read_line(&mut s).unwrap(); + } + drop(self); + drop(e); + process::exit(1); + } + + drop(self); + e.exit() + }) + } + + /// Starts the parsing process. A combination of [`App::get_matches_from`], and + /// [`App::get_matches_safe`] + /// + /// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are + /// used. It will return a [`clap::Error`], where the [`kind`] is a [`ErrorKind::HelpDisplayed`] + /// or [`ErrorKind::VersionDisplayed`] respectively. You must call [`Error::exit`] or + /// perform a [`std::process::exit`] yourself. + /// + /// **NOTE:** The first argument will be parsed as the binary name unless + /// [`AppSettings::NoBinaryName`] is used + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"]; + /// + /// let matches = App::new("myprog") + /// // Args and options go here... + /// .get_matches_from_safe(arg_vec) + /// .unwrap_or_else( |e| { panic!("An error occurs: {}", e) }); + /// ``` + /// [`App::get_matches_from`]: ./struct.App.html#method.get_matches_from + /// [`App::get_matches_safe`]: ./struct.App.html#method.get_matches_safe + /// [`ErrorKind::HelpDisplayed`]: ./enum.ErrorKind.html#variant.HelpDisplayed + /// [`ErrorKind::VersionDisplayed`]: ./enum.ErrorKind.html#variant.VersionDisplayed + /// [`Error::exit`]: ./struct.Error.html#method.exit + /// [`std::process::exit`]: https://doc.rust-lang.org/std/process/fn.exit.html + /// [`clap::Error`]: ./struct.Error.html + /// [`Error::exit`]: ./struct.Error.html#method.exit + /// [`kind`]: ./struct.Error.html + /// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName + pub fn get_matches_from_safe(mut self, itr: I) -> ClapResult> + where + I: IntoIterator, + T: Into + Clone, + { + self.get_matches_from_safe_borrow(itr) + } + + /// Starts the parsing process without consuming the [`App`] struct `self`. This is normally not + /// the desired functionality, instead prefer [`App::get_matches_from_safe`] which *does* + /// consume `self`. + /// + /// **NOTE:** The first argument will be parsed as the binary name unless + /// [`AppSettings::NoBinaryName`] is used + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"]; + /// + /// let mut app = App::new("myprog"); + /// // Args and options go here... + /// let matches = app.get_matches_from_safe_borrow(arg_vec) + /// .unwrap_or_else( |e| { panic!("An error occurs: {}", e) }); + /// ``` + /// [`App`]: ./struct.App.html + /// [`App::get_matches_from_safe`]: ./struct.App.html#method.get_matches_from_safe + /// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName + pub fn get_matches_from_safe_borrow(&mut self, itr: I) -> ClapResult> + where + I: IntoIterator, + T: Into + Clone, + { + // If there are global arguments, or settings we need to propagate them down to subcommands + // before parsing incase we run into a subcommand + if !self.p.is_set(AppSettings::Propagated) { + self.p.propagate_globals(); + self.p.propagate_settings(); + self.p.derive_display_order(); + self.p.set(AppSettings::Propagated); + } + + let mut matcher = ArgMatcher::new(); + + let mut it = itr.into_iter(); + // Get the name of the program (argument 1 of env::args()) and determine the + // actual file + // that was used to execute the program. This is because a program called + // ./target/release/my_prog -a + // will have two arguments, './target/release/my_prog', '-a' but we don't want + // to display + // the full path when displaying help messages and such + if !self.p.is_set(AppSettings::NoBinaryName) { + if let Some(name) = it.next() { + let bn_os = name.into(); + let p = Path::new(&*bn_os); + if let Some(f) = p.file_name() { + if let Some(s) = f.to_os_string().to_str() { + if self.p.meta.bin_name.is_none() { + self.p.meta.bin_name = Some(s.to_owned()); + } + } + } + } + } + + // do the real parsing + if let Err(e) = self.p.get_matches_with(&mut matcher, &mut it.peekable()) { + return Err(e); + } + + let global_arg_vec: Vec<&str> = self.p.global_args.iter().map(|ga| ga.b.name).collect(); + matcher.propagate_globals(&global_arg_vec); + + Ok(matcher.into()) + } +} + +#[cfg(feature = "yaml")] +impl<'a> From<&'a Yaml> for App<'a, 'a> { + fn from(mut yaml: &'a Yaml) -> Self { + use crate::args::SubCommand; + // We WANT this to panic on error...so expect() is good. + let mut is_sc = None; + let mut a = if let Some(name) = yaml["name"].as_str() { + App::new(name) + } else { + let yaml_hash = yaml.as_hash().unwrap(); + let sc_key = yaml_hash.keys().nth(0).unwrap(); + is_sc = Some(yaml_hash.get(sc_key).unwrap()); + App::new(sc_key.as_str().unwrap()) + }; + yaml = if let Some(sc) = is_sc { sc } else { yaml }; + + macro_rules! yaml_str { + ($a:ident, $y:ident, $i:ident) => { + if let Some(v) = $y[stringify!($i)].as_str() { + $a = $a.$i(v); + } else if $y[stringify!($i)] != Yaml::BadValue { + panic!( + "Failed to convert YAML value {:?} to a string", + $y[stringify!($i)] + ); + } + }; + } + + yaml_str!(a, yaml, version); + yaml_str!(a, yaml, long_version); + yaml_str!(a, yaml, author); + yaml_str!(a, yaml, bin_name); + yaml_str!(a, yaml, about); + yaml_str!(a, yaml, long_about); + yaml_str!(a, yaml, before_help); + yaml_str!(a, yaml, after_help); + yaml_str!(a, yaml, template); + yaml_str!(a, yaml, usage); + yaml_str!(a, yaml, help); + yaml_str!(a, yaml, help_short); + yaml_str!(a, yaml, version_short); + yaml_str!(a, yaml, help_message); + yaml_str!(a, yaml, version_message); + yaml_str!(a, yaml, alias); + yaml_str!(a, yaml, visible_alias); + + if let Some(v) = yaml["display_order"].as_i64() { + a = a.display_order(v as usize); + } else if yaml["display_order"] != Yaml::BadValue { + panic!( + "Failed to convert YAML value {:?} to a u64", + yaml["display_order"] + ); + } + if let Some(v) = yaml["setting"].as_str() { + a = a.setting(v.parse().expect("unknown AppSetting found in YAML file")); + } else if yaml["setting"] != Yaml::BadValue { + panic!( + "Failed to convert YAML value {:?} to an AppSetting", + yaml["setting"] + ); + } + if let Some(v) = yaml["settings"].as_vec() { + for ys in v { + if let Some(s) = ys.as_str() { + a = a.setting(s.parse().expect("unknown AppSetting found in YAML file")); + } + } + } else if let Some(v) = yaml["settings"].as_str() { + a = a.setting(v.parse().expect("unknown AppSetting found in YAML file")); + } else if yaml["settings"] != Yaml::BadValue { + panic!( + "Failed to convert YAML value {:?} to a string", + yaml["settings"] + ); + } + if let Some(v) = yaml["global_setting"].as_str() { + a = a.setting(v.parse().expect("unknown AppSetting found in YAML file")); + } else if yaml["global_setting"] != Yaml::BadValue { + panic!( + "Failed to convert YAML value {:?} to an AppSetting", + yaml["setting"] + ); + } + if let Some(v) = yaml["global_settings"].as_vec() { + for ys in v { + if let Some(s) = ys.as_str() { + a = a.global_setting(s.parse().expect("unknown AppSetting found in YAML file")); + } + } + } else if let Some(v) = yaml["global_settings"].as_str() { + a = a.global_setting(v.parse().expect("unknown AppSetting found in YAML file")); + } else if yaml["global_settings"] != Yaml::BadValue { + panic!( + "Failed to convert YAML value {:?} to a string", + yaml["global_settings"] + ); + } + + macro_rules! vec_or_str { + ($a:ident, $y:ident, $as_vec:ident, $as_single:ident) => {{ + let maybe_vec = $y[stringify!($as_vec)].as_vec(); + if let Some(vec) = maybe_vec { + for ys in vec { + if let Some(s) = ys.as_str() { + $a = $a.$as_single(s); + } else { + panic!("Failed to convert YAML value {:?} to a string", ys); + } + } + } else { + if let Some(s) = $y[stringify!($as_vec)].as_str() { + $a = $a.$as_single(s); + } else if $y[stringify!($as_vec)] != Yaml::BadValue { + panic!( + "Failed to convert YAML value {:?} to either a vec or string", + $y[stringify!($as_vec)] + ); + } + } + $a + }}; + } + + a = vec_or_str!(a, yaml, aliases, alias); + a = vec_or_str!(a, yaml, visible_aliases, visible_alias); + + if let Some(v) = yaml["args"].as_vec() { + for arg_yaml in v { + a = a.arg(Arg::from_yaml(arg_yaml.as_hash().unwrap())); + } + } + if let Some(v) = yaml["subcommands"].as_vec() { + for sc_yaml in v { + a = a.subcommand(SubCommand::from_yaml(sc_yaml)); + } + } + if let Some(v) = yaml["groups"].as_vec() { + for ag_yaml in v { + a = a.group(ArgGroup::from(ag_yaml.as_hash().unwrap())); + } + } + + a + } +} + +impl<'a, 'b> Clone for App<'a, 'b> { + fn clone(&self) -> Self { + App { p: self.p.clone() } + } +} + +impl<'n, 'e> AnyArg<'n, 'e> for App<'n, 'e> { + fn name(&self) -> &'n str { + "" + } + fn overrides(&self) -> Option<&[&'e str]> { + None + } + fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { + None + } + fn blacklist(&self) -> Option<&[&'e str]> { + None + } + fn required_unless(&self) -> Option<&[&'e str]> { + None + } + fn val_names(&self) -> Option<&VecMap<&'e str>> { + None + } + fn is_set(&self, _: ArgSettings) -> bool { + false + } + fn val_terminator(&self) -> Option<&'e str> { + None + } + fn set(&mut self, _: ArgSettings) { + unreachable!("App struct does not support AnyArg::set, this is a bug!") + } + fn has_switch(&self) -> bool { + false + } + fn max_vals(&self) -> Option { + None + } + fn num_vals(&self) -> Option { + None + } + fn possible_vals(&self) -> Option<&[&'e str]> { + None + } + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + fn validator(&self) -> Option<&Rc StdResult<(), String>>> { + None + } + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + fn validator_os(&self) -> Option<&Rc StdResult<(), OsString>>> { + None + } + fn min_vals(&self) -> Option { + None + } + fn short(&self) -> Option { + None + } + fn long(&self) -> Option<&'e str> { + None + } + fn val_delim(&self) -> Option { + None + } + fn takes_value(&self) -> bool { + true + } + fn help(&self) -> Option<&'e str> { + self.p.meta.about + } + fn long_help(&self) -> Option<&'e str> { + self.p.meta.long_about + } + fn default_val(&self) -> Option<&'e OsStr> { + None + } + fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { + None + } + fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { + None + } + fn longest_filter(&self) -> bool { + true + } + fn aliases(&self) -> Option> { + if let Some(ref aliases) = self.p.meta.aliases { + let vis_aliases: Vec<_> = aliases + .iter() + .filter_map(|&(n, v)| if v { Some(n) } else { None }) + .collect(); + if vis_aliases.is_empty() { + None + } else { + Some(vis_aliases) + } + } else { + None + } + } +} + +impl<'n, 'e> fmt::Display for App<'n, 'e> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.p.meta.name) + } +} diff --git a/vendor/clap-2.34.0/src/app/parser.rs b/vendor/clap-2.34.0/src/app/parser.rs new file mode 100644 index 0000000000000..12cb2c1311706 --- /dev/null +++ b/vendor/clap-2.34.0/src/app/parser.rs @@ -0,0 +1,2236 @@ +// Std +#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))] +use std::os::unix::ffi::OsStrExt; +use std::{ + cell::Cell, + ffi::{OsStr, OsString}, + fmt::Display, + fs::File, + io::{self, BufWriter, Write}, + iter::Peekable, + path::PathBuf, + slice::Iter, +}; + +// Internal +#[cfg(all(feature = "debug", any(target_os = "windows", target_arch = "wasm32")))] +use crate::osstringext::OsStrExt3; +#[cfg(any(target_os = "windows", target_arch = "wasm32"))] +use crate::osstringext::OsStrExt3; +use crate::{ + app::{ + help::Help, meta::AppMeta, settings::AppFlags, settings::AppSettings as AS, usage, + validator::Validator, App, + }, + args::{ + settings::ArgSettings, AnyArg, Arg, ArgGroup, ArgMatcher, Base, FlagBuilder, OptBuilder, + PosBuilder, Switched, + }, + completions::{ComplGen, Shell}, + errors::Result as ClapResult, + errors::{Error, ErrorKind}, + fmt::ColorWhen, + map::{self, VecMap}, + osstringext::OsStrExt2, + suggestions, SubCommand, INTERNAL_ERROR_MSG, INVALID_UTF8, +}; + +#[derive(Debug, PartialEq, Copy, Clone)] +#[doc(hidden)] +pub enum ParseResult<'a> { + Flag, + Opt(&'a str), + Pos(&'a str), + MaybeHyphenValue, + MaybeNegNum, + NotFound, + ValuesDone, +} + +#[allow(missing_debug_implementations)] +#[doc(hidden)] +#[derive(Clone, Default)] +pub struct Parser<'a, 'b> +where + 'a: 'b, +{ + pub meta: AppMeta<'b>, + settings: AppFlags, + pub g_settings: AppFlags, + pub flags: Vec>, + pub opts: Vec>, + pub positionals: VecMap>, + pub subcommands: Vec>, + pub groups: Vec>, + pub global_args: Vec>, + pub required: Vec<&'a str>, + pub r_ifs: Vec<(&'a str, &'b str, &'a str)>, + pub overrides: Vec<(&'b str, &'a str)>, + help_short: Option, + version_short: Option, + cache: Option<&'a str>, + pub help_message: Option<&'a str>, + pub version_message: Option<&'a str>, + cur_idx: Cell, +} + +impl<'a, 'b> Parser<'a, 'b> +where + 'a: 'b, +{ + pub fn with_name(n: String) -> Self { + Parser { + meta: AppMeta::with_name(n), + g_settings: AppFlags::zeroed(), + cur_idx: Cell::new(0), + ..Default::default() + } + } + + pub fn help_short(&mut self, s: &str) { + let c = s + .trim_left_matches(|c| c == '-') + .chars() + .next() + .unwrap_or('h'); + self.help_short = Some(c); + } + + pub fn version_short(&mut self, s: &str) { + let c = s + .trim_left_matches(|c| c == '-') + .chars() + .next() + .unwrap_or('V'); + self.version_short = Some(c); + } + + pub fn gen_completions_to(&mut self, for_shell: Shell, buf: &mut W) { + if !self.is_set(AS::Propagated) { + self.propagate_help_version(); + self.build_bin_names(); + self.propagate_globals(); + self.propagate_settings(); + self.set(AS::Propagated); + } + + ComplGen::new(self).generate(for_shell, buf) + } + + pub fn gen_completions(&mut self, for_shell: Shell, od: OsString) { + use std::error::Error; + + let out_dir = PathBuf::from(od); + let name = &*self.meta.bin_name.as_ref().unwrap().clone(); + let file_name = match for_shell { + Shell::Bash => format!("{}.bash", name), + Shell::Fish => format!("{}.fish", name), + Shell::Zsh => format!("_{}", name), + Shell::PowerShell => format!("_{}.ps1", name), + Shell::Elvish => format!("{}.elv", name), + }; + + let mut file = match File::create(out_dir.join(file_name)) { + Err(why) => panic!("couldn't create completion file: {}", why.description()), + Ok(file) => file, + }; + self.gen_completions_to(for_shell, &mut file) + } + + #[inline] + fn app_debug_asserts(&self) -> bool { + assert!(self.verify_positionals()); + let should_err = self.groups.iter().all(|g| { + g.args.iter().all(|arg| { + self.flags.iter().any(|f| &f.b.name == arg) + || self.opts.iter().any(|o| &o.b.name == arg) + || self.positionals.values().any(|p| &p.b.name == arg) + || self.groups.iter().any(|g| &g.name == arg) + }) + }); + let g = self.groups.iter().find(|g| { + g.args.iter().any(|arg| { + !(self.flags.iter().any(|f| &f.b.name == arg) + || self.opts.iter().any(|o| &o.b.name == arg) + || self.positionals.values().any(|p| &p.b.name == arg) + || self.groups.iter().any(|g| &g.name == arg)) + }) + }); + assert!( + should_err, + "The group '{}' contains the arg '{}' that doesn't actually exist.", + g.unwrap().name, + g.unwrap() + .args + .iter() + .find(|arg| !(self.flags.iter().any(|f| &&f.b.name == arg) + || self.opts.iter().any(|o| &&o.b.name == arg) + || self.positionals.values().any(|p| &&p.b.name == arg) + || self.groups.iter().any(|g| &&g.name == arg))) + .unwrap() + ); + true + } + + #[inline] + fn debug_asserts(&self, a: &Arg) -> bool { + assert!( + !arg_names!(self).any(|name| name == a.b.name), + "Non-unique argument name: {} is already in use", + a.b.name + ); + if let Some(l) = a.s.long { + assert!( + !self.contains_long(l), + "Argument long must be unique\n\n\t--{} is already in use", + l + ); + } + if let Some(s) = a.s.short { + assert!( + !self.contains_short(s), + "Argument short must be unique\n\n\t-{} is already in use", + s + ); + } + let i = if a.index.is_none() { + self.positionals.len() + 1 + } else { + a.index.unwrap() as usize + }; + assert!( + !self.positionals.contains_key(i), + "Argument \"{}\" has the same index as another positional \ + argument\n\n\tPerhaps try .multiple(true) to allow one positional argument \ + to take multiple values", + a.b.name + ); + assert!( + !(a.is_set(ArgSettings::Required) && a.is_set(ArgSettings::Global)), + "Global arguments cannot be required.\n\n\t'{}' is marked as \ + global and required", + a.b.name + ); + if a.b.is_set(ArgSettings::Last) { + assert!( + !self + .positionals + .values() + .any(|p| p.b.is_set(ArgSettings::Last)), + "Only one positional argument may have last(true) set. Found two." + ); + assert!(a.s.long.is_none(), + "Flags or Options may not have last(true) set. {} has both a long and last(true) set.", + a.b.name); + assert!(a.s.short.is_none(), + "Flags or Options may not have last(true) set. {} has both a short and last(true) set.", + a.b.name); + } + true + } + + #[inline] + fn add_conditional_reqs(&mut self, a: &Arg<'a, 'b>) { + if let Some(ref r_ifs) = a.r_ifs { + for &(arg, val) in r_ifs { + self.r_ifs.push((arg, val, a.b.name)); + } + } + } + + #[inline] + fn add_arg_groups(&mut self, a: &Arg<'a, 'b>) { + if let Some(ref grps) = a.b.groups { + for g in grps { + let mut found = false; + if let Some(ref mut ag) = self.groups.iter_mut().find(|grp| &grp.name == g) { + ag.args.push(a.b.name); + found = true; + } + if !found { + let mut ag = ArgGroup::with_name(g); + ag.args.push(a.b.name); + self.groups.push(ag); + } + } + } + } + + #[inline] + fn add_reqs(&mut self, a: &Arg<'a, 'b>) { + if a.is_set(ArgSettings::Required) { + // If the arg is required, add all it's requirements to master required list + self.required.push(a.b.name); + if let Some(ref areqs) = a.b.requires { + for name in areqs + .iter() + .filter(|&&(val, _)| val.is_none()) + .map(|&(_, name)| name) + { + self.required.push(name); + } + } + } + } + + #[inline] + fn implied_settings(&mut self, a: &Arg<'a, 'b>) { + if a.is_set(ArgSettings::Last) { + // if an arg has `Last` set, we need to imply DontCollapseArgsInUsage so that args + // in the usage string don't get confused or left out. + self.set(AS::DontCollapseArgsInUsage); + self.set(AS::ContainsLast); + } + if let Some(l) = a.s.long { + if l == "version" { + self.unset(AS::NeedsLongVersion); + } else if l == "help" { + self.unset(AS::NeedsLongHelp); + } + } + } + + // actually adds the arguments + pub fn add_arg(&mut self, a: Arg<'a, 'b>) { + // if it's global we have to clone anyways + if a.is_set(ArgSettings::Global) { + return self.add_arg_ref(&a); + } + debug_assert!(self.debug_asserts(&a)); + self.add_conditional_reqs(&a); + self.add_arg_groups(&a); + self.add_reqs(&a); + self.implied_settings(&a); + if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) { + let i = if a.index.is_none() { + self.positionals.len() + 1 + } else { + a.index.unwrap() as usize + }; + self.positionals + .insert(i, PosBuilder::from_arg(a, i as u64)); + } else if a.is_set(ArgSettings::TakesValue) { + let mut ob = OptBuilder::from(a); + ob.s.unified_ord = self.flags.len() + self.opts.len(); + self.opts.push(ob); + } else { + let mut fb = FlagBuilder::from(a); + fb.s.unified_ord = self.flags.len() + self.opts.len(); + self.flags.push(fb); + } + } + // actually adds the arguments but from a borrow (which means we have to do some cloning) + pub fn add_arg_ref(&mut self, a: &Arg<'a, 'b>) { + debug_assert!(self.debug_asserts(a)); + self.add_conditional_reqs(a); + self.add_arg_groups(a); + self.add_reqs(a); + self.implied_settings(a); + if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) { + let i = if a.index.is_none() { + self.positionals.len() + 1 + } else { + a.index.unwrap() as usize + }; + let pb = PosBuilder::from_arg_ref(a, i as u64); + self.positionals.insert(i, pb); + } else if a.is_set(ArgSettings::TakesValue) { + let mut ob = OptBuilder::from(a); + ob.s.unified_ord = self.flags.len() + self.opts.len(); + self.opts.push(ob); + } else { + let mut fb = FlagBuilder::from(a); + fb.s.unified_ord = self.flags.len() + self.opts.len(); + self.flags.push(fb); + } + if a.is_set(ArgSettings::Global) { + self.global_args.push(a.into()); + } + } + + pub fn add_group(&mut self, group: ArgGroup<'a>) { + if group.required { + self.required.push(group.name); + if let Some(ref reqs) = group.requires { + self.required.extend_from_slice(reqs); + } + // if let Some(ref bl) = group.conflicts { + // self.blacklist.extend_from_slice(bl); + // } + } + if self.groups.iter().any(|g| g.name == group.name) { + let grp = self + .groups + .iter_mut() + .find(|g| g.name == group.name) + .expect(INTERNAL_ERROR_MSG); + grp.args.extend_from_slice(&group.args); + grp.requires = group.requires.clone(); + grp.conflicts = group.conflicts.clone(); + grp.required = group.required; + } else { + self.groups.push(group); + } + } + + pub fn add_subcommand(&mut self, mut subcmd: App<'a, 'b>) { + debugln!( + "Parser::add_subcommand: term_w={:?}, name={}", + self.meta.term_w, + subcmd.p.meta.name + ); + subcmd.p.meta.term_w = self.meta.term_w; + if subcmd.p.meta.name == "help" { + self.unset(AS::NeedsSubcommandHelp); + } + + self.subcommands.push(subcmd); + } + + pub fn propagate_settings(&mut self) { + debugln!( + "Parser::propagate_settings: self={}, g_settings={:#?}", + self.meta.name, + self.g_settings + ); + for sc in &mut self.subcommands { + debugln!( + "Parser::propagate_settings: sc={}, settings={:#?}, g_settings={:#?}", + sc.p.meta.name, + sc.p.settings, + sc.p.g_settings + ); + // We have to create a new scope in order to tell rustc the borrow of `sc` is + // done and to recursively call this method + { + let vsc = self.settings.is_set(AS::VersionlessSubcommands); + let gv = self.settings.is_set(AS::GlobalVersion); + + if vsc { + sc.p.set(AS::DisableVersion); + } + if gv && sc.p.meta.version.is_none() && self.meta.version.is_some() { + sc.p.set(AS::GlobalVersion); + sc.p.meta.version = Some(self.meta.version.unwrap()); + } + sc.p.settings = sc.p.settings | self.g_settings; + sc.p.g_settings = sc.p.g_settings | self.g_settings; + sc.p.meta.term_w = self.meta.term_w; + sc.p.meta.max_w = self.meta.max_w; + } + sc.p.propagate_settings(); + } + } + + pub fn derive_display_order(&mut self) { + if self.is_set(AS::DeriveDisplayOrder) { + let unified = self.is_set(AS::UnifiedHelpMessage); + for (i, o) in self + .opts + .iter_mut() + .enumerate() + .filter(|&(_, ref o)| o.s.disp_ord == 999) + { + o.s.disp_ord = if unified { o.s.unified_ord } else { i }; + } + for (i, f) in self + .flags + .iter_mut() + .enumerate() + .filter(|&(_, ref f)| f.s.disp_ord == 999) + { + f.s.disp_ord = if unified { f.s.unified_ord } else { i }; + } + for (i, sc) in &mut self + .subcommands + .iter_mut() + .enumerate() + .filter(|&(_, ref sc)| sc.p.meta.disp_ord == 999) + { + sc.p.meta.disp_ord = i; + } + } + for sc in &mut self.subcommands { + sc.p.derive_display_order(); + } + } + + pub fn required(&self) -> Iter<&str> { + self.required.iter() + } + + #[inline] + pub fn has_args(&self) -> bool { + !(self.flags.is_empty() && self.opts.is_empty() && self.positionals.is_empty()) + } + + #[inline] + pub fn has_opts(&self) -> bool { + !self.opts.is_empty() + } + + #[inline] + pub fn has_flags(&self) -> bool { + !self.flags.is_empty() + } + + #[inline] + pub fn has_positionals(&self) -> bool { + !self.positionals.is_empty() + } + + #[inline] + pub fn has_subcommands(&self) -> bool { + !self.subcommands.is_empty() + } + + #[inline] + pub fn has_visible_opts(&self) -> bool { + if self.opts.is_empty() { + return false; + } + self.opts.iter().any(|o| !o.is_set(ArgSettings::Hidden)) + } + + #[inline] + pub fn has_visible_flags(&self) -> bool { + if self.flags.is_empty() { + return false; + } + self.flags.iter().any(|f| !f.is_set(ArgSettings::Hidden)) + } + + #[inline] + pub fn has_visible_positionals(&self) -> bool { + if self.positionals.is_empty() { + return false; + } + self.positionals + .values() + .any(|p| !p.is_set(ArgSettings::Hidden)) + } + + #[inline] + pub fn has_visible_subcommands(&self) -> bool { + self.has_subcommands() + && self + .subcommands + .iter() + .filter(|sc| sc.p.meta.name != "help") + .any(|sc| !sc.p.is_set(AS::Hidden)) + } + + #[inline] + pub fn is_set(&self, s: AS) -> bool { + self.settings.is_set(s) + } + + #[inline] + pub fn set(&mut self, s: AS) { + self.settings.set(s) + } + + #[inline] + pub fn unset(&mut self, s: AS) { + self.settings.unset(s) + } + + pub fn verify_positionals(&self) -> bool { + // Because you must wait until all arguments have been supplied, this is the first chance + // to make assertions on positional argument indexes + // + // First we verify that the index highest supplied index, is equal to the number of + // positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3 + // but no 2) + if let Some((idx, p)) = self.positionals.iter().rev().next() { + assert!( + !(idx != self.positionals.len()), + "Found positional argument \"{}\" whose index is {} but there \ + are only {} positional arguments defined", + p.b.name, + idx, + self.positionals.len() + ); + } + + // Next we verify that only the highest index has a .multiple(true) (if any) + if self.positionals.values().any(|a| { + a.b.is_set(ArgSettings::Multiple) && (a.index as usize != self.positionals.len()) + }) { + let mut it = self.positionals.values().rev(); + let last = it.next().unwrap(); + let second_to_last = it.next().unwrap(); + // Either the final positional is required + // Or the second to last has a terminator or .last(true) set + let ok = last.is_set(ArgSettings::Required) + || (second_to_last.v.terminator.is_some() + || second_to_last.b.is_set(ArgSettings::Last)) + || last.is_set(ArgSettings::Last); + assert!( + ok, + "When using a positional argument with .multiple(true) that is *not the \ + last* positional argument, the last positional argument (i.e the one \ + with the highest index) *must* have .required(true) or .last(true) set." + ); + let ok = second_to_last.is_set(ArgSettings::Multiple) || last.is_set(ArgSettings::Last); + assert!( + ok, + "Only the last positional argument, or second to last positional \ + argument may be set to .multiple(true)" + ); + + let count = self + .positionals + .values() + .filter(|p| p.b.settings.is_set(ArgSettings::Multiple) && p.v.num_vals.is_none()) + .count(); + let ok = count <= 1 + || (last.is_set(ArgSettings::Last) + && last.is_set(ArgSettings::Multiple) + && second_to_last.is_set(ArgSettings::Multiple) + && count == 2); + assert!( + ok, + "Only one positional argument with .multiple(true) set is allowed per \ + command, unless the second one also has .last(true) set" + ); + } + + let mut found = false; + if self.is_set(AS::AllowMissingPositional) { + // Check that if a required positional argument is found, all positions with a lower + // index are also required. + let mut foundx2 = false; + for p in self.positionals.values().rev() { + if foundx2 && !p.b.settings.is_set(ArgSettings::Required) { + assert!( + p.b.is_set(ArgSettings::Required), + "Found positional argument which is not required with a lower \ + index than a required positional argument by two or more: {:?} \ + index {}", + p.b.name, + p.index + ); + } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) { + // Args that .last(true) don't count since they can be required and have + // positionals with a lower index that aren't required + // Imagine: prog [opt1] -- + // Both of these are valid invocations: + // $ prog r1 -- r2 + // $ prog r1 o1 -- r2 + if found { + foundx2 = true; + continue; + } + found = true; + continue; + } else { + found = false; + } + } + } else { + // Check that if a required positional argument is found, all positions with a lower + // index are also required + for p in self.positionals.values().rev() { + if found { + assert!( + p.b.is_set(ArgSettings::Required), + "Found positional argument which is not required with a lower \ + index than a required positional argument: {:?} index {}", + p.b.name, + p.index + ); + } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) { + // Args that .last(true) don't count since they can be required and have + // positionals with a lower index that aren't required + // Imagine: prog [opt1] -- + // Both of these are valid invocations: + // $ prog r1 -- r2 + // $ prog r1 o1 -- r2 + found = true; + continue; + } + } + } + if self + .positionals + .values() + .any(|p| p.b.is_set(ArgSettings::Last) && p.b.is_set(ArgSettings::Required)) + && self.has_subcommands() + && !self.is_set(AS::SubcommandsNegateReqs) + { + panic!( + "Having a required positional argument with .last(true) set *and* child \ + subcommands without setting SubcommandsNegateReqs isn't compatible." + ); + } + + true + } + + pub fn propagate_globals(&mut self) { + for sc in &mut self.subcommands { + // We have to create a new scope in order to tell rustc the borrow of `sc` is + // done and to recursively call this method + { + for a in &self.global_args { + sc.p.add_arg_ref(a); + } + } + sc.p.propagate_globals(); + } + } + + // Checks if the arg matches a subcommand name, or any of it's aliases (if defined) + fn possible_subcommand(&self, arg_os: &OsStr) -> (bool, Option<&str>) { + debugln!("Parser::possible_subcommand: arg={:?}", arg_os); + fn starts(h: &str, n: &OsStr) -> bool { + let n_bytes = n.as_bytes(); + let h_bytes = OsStr::new(h).as_bytes(); + + h_bytes.starts_with(n_bytes) + } + + if self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound) { + return (false, None); + } + if !self.is_set(AS::InferSubcommands) { + if let Some(sc) = find_subcmd!(self, arg_os) { + return (true, Some(&sc.p.meta.name)); + } + } else { + let v = self + .subcommands + .iter() + .filter(|s| { + starts(&s.p.meta.name[..], &*arg_os) + || (s.p.meta.aliases.is_some() + && s.p + .meta + .aliases + .as_ref() + .unwrap() + .iter() + .filter(|&&(a, _)| starts(a, &*arg_os)) + .count() + == 1) + }) + .map(|sc| &sc.p.meta.name) + .collect::>(); + + for sc in &v { + if OsStr::new(sc) == arg_os { + return (true, Some(sc)); + } + } + + if v.len() == 1 { + return (true, Some(v[0])); + } + } + (false, None) + } + + fn parse_help_subcommand(&self, it: &mut I) -> ClapResult> + where + I: Iterator, + T: Into, + { + debugln!("Parser::parse_help_subcommand;"); + let cmds: Vec = it.map(|c| c.into()).collect(); + let mut help_help = false; + let mut bin_name = self + .meta + .bin_name + .as_ref() + .unwrap_or(&self.meta.name) + .clone(); + let mut sc = { + let mut sc: &Parser = self; + for (i, cmd) in cmds.iter().enumerate() { + if &*cmd.to_string_lossy() == "help" { + // cmd help help + help_help = true; + } + if let Some(c) = sc + .subcommands + .iter() + .find(|s| &*s.p.meta.name == cmd) + .map(|sc| &sc.p) + { + sc = c; + if i == cmds.len() - 1 { + break; + } + } else if let Some(c) = sc + .subcommands + .iter() + .find(|s| { + if let Some(ref als) = s.p.meta.aliases { + als.iter().any(|&(a, _)| a == &*cmd.to_string_lossy()) + } else { + false + } + }) + .map(|sc| &sc.p) + { + sc = c; + if i == cmds.len() - 1 { + break; + } + } else { + return Err(Error::unrecognized_subcommand( + cmd.to_string_lossy().into_owned(), + self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), + self.color(), + )); + } + bin_name = format!("{} {}", bin_name, &*sc.meta.name); + } + sc.clone() + }; + if help_help { + let mut pb = PosBuilder::new("subcommand", 1); + pb.b.help = Some("The subcommand whose help message to display"); + pb.set(ArgSettings::Multiple); + sc.positionals.insert(1, pb); + sc.settings = sc.settings | self.g_settings; + } else { + sc.create_help_and_version(); + } + if sc.meta.bin_name != self.meta.bin_name { + sc.meta.bin_name = Some(format!("{} {}", bin_name, sc.meta.name)); + } + Err(sc._help(false)) + } + + // allow wrong self convention due to self.valid_neg_num = true and it's a private method + #[cfg_attr(feature = "lints", allow(wrong_self_convention))] + fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult) -> bool { + debugln!("Parser::is_new_arg:{:?}:{:?}", arg_os, needs_val_of); + let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) { + true + } else if self.is_set(AS::AllowNegativeNumbers) { + let a = arg_os.to_string_lossy(); + if a.parse::().is_ok() || a.parse::().is_ok() { + self.set(AS::ValidNegNumFound); + true + } else { + false + } + } else { + false + }; + let arg_allows_tac = match needs_val_of { + ParseResult::Opt(name) => { + let o = self + .opts + .iter() + .find(|o| o.b.name == name) + .expect(INTERNAL_ERROR_MSG); + o.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings + } + ParseResult::Pos(name) => { + let p = self + .positionals + .values() + .find(|p| p.b.name == name) + .expect(INTERNAL_ERROR_MSG); + p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings + } + ParseResult::ValuesDone => return true, + _ => false, + }; + debugln!("Parser::is_new_arg: arg_allows_tac={:?}", arg_allows_tac); + + // Is this a new argument, or values from a previous option? + let mut ret = if arg_os.starts_with(b"--") { + debugln!("Parser::is_new_arg: -- found"); + if arg_os.len() == 2 && !arg_allows_tac { + return true; // We have to return true so override everything else + } else if arg_allows_tac { + return false; + } + true + } else if arg_os.starts_with(b"-") { + debugln!("Parser::is_new_arg: - found"); + // a singe '-' by itself is a value and typically means "stdin" on unix systems + arg_os.len() != 1 + } else { + debugln!("Parser::is_new_arg: probably value"); + false + }; + + ret = ret && !arg_allows_tac; + + debugln!("Parser::is_new_arg: starts_new_arg={:?}", ret); + ret + } + + // The actual parsing function + #[cfg_attr( + feature = "cargo-clippy", + allow(clippy::while_let_on_iterator, clippy::nonminimal_bool) + )] + pub fn get_matches_with( + &mut self, + matcher: &mut ArgMatcher<'a>, + it: &mut Peekable, + ) -> ClapResult<()> + where + I: Iterator, + T: Into + Clone, + { + debugln!("Parser::get_matches_with;"); + // Verify all positional assertions pass + debug_assert!(self.app_debug_asserts()); + if self.positionals.values().any(|a| { + a.b.is_set(ArgSettings::Multiple) && (a.index as usize != self.positionals.len()) + }) && self + .positionals + .values() + .last() + .map_or(false, |p| !p.is_set(ArgSettings::Last)) + { + self.settings.set(AS::LowIndexMultiplePositional); + } + let has_args = self.has_args(); + + // Next we create the `--help` and `--version` arguments and add them if + // necessary + self.create_help_and_version(); + + let mut subcmd_name: Option = None; + let mut needs_val_of: ParseResult<'a> = ParseResult::NotFound; + let mut pos_counter = 1; + let mut sc_is_external = false; + while let Some(arg) = it.next() { + let arg_os = arg.into(); + debugln!( + "Parser::get_matches_with: Begin parsing '{:?}' ({:?})", + arg_os, + &*arg_os.as_bytes() + ); + + self.unset(AS::ValidNegNumFound); + // Is this a new argument, or values from a previous option? + let starts_new_arg = self.is_new_arg(&arg_os, needs_val_of); + if !self.is_set(AS::TrailingValues) + && arg_os.starts_with(b"--") + && arg_os.len() == 2 + && starts_new_arg + { + debugln!("Parser::get_matches_with: setting TrailingVals=true"); + self.set(AS::TrailingValues); + continue; + } + + // Has the user already passed '--'? Meaning only positional args follow + if !self.is_set(AS::TrailingValues) { + // Does the arg match a subcommand name, or any of it's aliases (if defined) + { + match needs_val_of { + ParseResult::Opt(_) | ParseResult::Pos(_) => (), + _ => { + let (is_match, sc_name) = self.possible_subcommand(&arg_os); + debugln!( + "Parser::get_matches_with: possible_sc={:?}, sc={:?}", + is_match, + sc_name + ); + if is_match { + let sc_name = sc_name.expect(INTERNAL_ERROR_MSG); + if sc_name == "help" && self.is_set(AS::NeedsSubcommandHelp) { + self.parse_help_subcommand(it)?; + } + subcmd_name = Some(sc_name.to_owned()); + break; + } + } + } + } + + if starts_new_arg { + let check_all = self.is_set(AS::AllArgsOverrideSelf); + { + let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); + matcher.process_arg_overrides( + any_arg, + &mut self.overrides, + &mut self.required, + check_all, + ); + } + + if arg_os.starts_with(b"--") { + needs_val_of = self.parse_long_arg(matcher, &arg_os, it)?; + debugln!( + "Parser:get_matches_with: After parse_long_arg {:?}", + needs_val_of + ); + match needs_val_of { + ParseResult::Flag | ParseResult::Opt(..) | ParseResult::ValuesDone => { + continue + } + _ => (), + } + } else if arg_os.starts_with(b"-") && arg_os.len() != 1 { + // Try to parse short args like normal, if AllowLeadingHyphen or + // AllowNegativeNumbers is set, parse_short_arg will *not* throw + // an error, and instead return Ok(None) + needs_val_of = self.parse_short_arg(matcher, &arg_os)?; + // If it's None, we then check if one of those two AppSettings was set + debugln!( + "Parser:get_matches_with: After parse_short_arg {:?}", + needs_val_of + ); + match needs_val_of { + ParseResult::MaybeNegNum => { + if !(arg_os.to_string_lossy().parse::().is_ok() + || arg_os.to_string_lossy().parse::().is_ok()) + { + return Err(Error::unknown_argument( + &*arg_os.to_string_lossy(), + "", + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + } + ParseResult::Opt(..) | ParseResult::Flag | ParseResult::ValuesDone => { + continue + } + _ => (), + } + } + } else if let ParseResult::Opt(name) = needs_val_of { + // Check to see if parsing a value from a previous arg + let arg = self + .opts + .iter() + .find(|o| o.b.name == name) + .expect(INTERNAL_ERROR_MSG); + // get the OptBuilder so we can check the settings + needs_val_of = self.add_val_to_arg(arg, &arg_os, matcher)?; + // get the next value from the iterator + continue; + } + } + + if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound)) + && !self.is_set(AS::InferSubcommands) + && !self.is_set(AS::AllowExternalSubcommands) + { + if let Some(cdate) = + suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self)) + { + return Err(Error::invalid_subcommand( + arg_os.to_string_lossy().into_owned(), + cdate, + self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + } + + let low_index_mults = self.is_set(AS::LowIndexMultiplePositional) + && pos_counter == (self.positionals.len() - 1); + let missing_pos = self.is_set(AS::AllowMissingPositional) + && (pos_counter == (self.positionals.len() - 1) + && !self.is_set(AS::TrailingValues)); + debugln!( + "Parser::get_matches_with: Positional counter...{}", + pos_counter + ); + debugln!( + "Parser::get_matches_with: Low index multiples...{:?}", + low_index_mults + ); + if low_index_mults || missing_pos { + if let Some(na) = it.peek() { + let n = (*na).clone().into(); + needs_val_of = if needs_val_of != ParseResult::ValuesDone { + if let Some(p) = self.positionals.get(pos_counter) { + ParseResult::Pos(p.b.name) + } else { + ParseResult::ValuesDone + } + } else { + ParseResult::ValuesDone + }; + let sc_match = { self.possible_subcommand(&n).0 }; + if self.is_new_arg(&n, needs_val_of) + || sc_match + || suggestions::did_you_mean(&n.to_string_lossy(), sc_names!(self)) + .is_some() + { + debugln!("Parser::get_matches_with: Bumping the positional counter..."); + pos_counter += 1; + } + } else { + debugln!("Parser::get_matches_with: Bumping the positional counter..."); + pos_counter += 1; + } + } else if (self.is_set(AS::AllowMissingPositional) && self.is_set(AS::TrailingValues)) + || (self.is_set(AS::ContainsLast) && self.is_set(AS::TrailingValues)) + { + // Came to -- and one postional has .last(true) set, so we go immediately + // to the last (highest index) positional + debugln!("Parser::get_matches_with: .last(true) and --, setting last pos"); + pos_counter = self.positionals.len(); + } + if let Some(p) = self.positionals.get(pos_counter) { + if p.is_set(ArgSettings::Last) && !self.is_set(AS::TrailingValues) { + return Err(Error::unknown_argument( + &*arg_os.to_string_lossy(), + "", + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + if !self.is_set(AS::TrailingValues) + && (self.is_set(AS::TrailingVarArg) && pos_counter == self.positionals.len()) + { + self.settings.set(AS::TrailingValues); + } + if self.cache.map_or(true, |name| name != p.b.name) { + let check_all = self.is_set(AS::AllArgsOverrideSelf); + { + let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); + matcher.process_arg_overrides( + any_arg, + &mut self.overrides, + &mut self.required, + check_all, + ); + } + self.cache = Some(p.b.name); + } + let _ = self.add_val_to_arg(p, &arg_os, matcher)?; + + matcher.inc_occurrence_of(p.b.name); + let _ = self + .groups_for_arg(p.b.name) + .map(|vec| matcher.inc_occurrences_of(&*vec)); + + self.settings.set(AS::ValidArgFound); + // Only increment the positional counter if it doesn't allow multiples + if !p.b.settings.is_set(ArgSettings::Multiple) { + pos_counter += 1; + } + self.settings.set(AS::ValidArgFound); + } else if self.is_set(AS::AllowExternalSubcommands) { + // Get external subcommand name + let sc_name = match arg_os.to_str() { + Some(s) => s.to_string(), + None => { + if !self.is_set(AS::StrictUtf8) { + return Err(Error::invalid_utf8( + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + arg_os.to_string_lossy().into_owned() + } + }; + + // Collect the external subcommand args + let mut sc_m = ArgMatcher::new(); + // Due to borrow rules, this has to be a while let... + #[cfg_attr(feature = "cargo-clippy", allow(clippy::while_let_on_iterator))] + while let Some(v) = it.next() { + let a = v.into(); + if a.to_str().is_none() && !self.is_set(AS::StrictUtf8) { + return Err(Error::invalid_utf8( + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + sc_m.add_val_to("", &a); + } + + matcher.subcommand(SubCommand { + name: sc_name, + matches: sc_m.into(), + }); + sc_is_external = true; + } else if !((self.is_set(AS::AllowLeadingHyphen) + || self.is_set(AS::AllowNegativeNumbers)) + && arg_os.starts_with(b"-")) + && !self.is_set(AS::InferSubcommands) + { + return Err(Error::unknown_argument( + &*arg_os.to_string_lossy(), + "", + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } else if !has_args || self.is_set(AS::InferSubcommands) && self.has_subcommands() { + if let Some(cdate) = + suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self)) + { + return Err(Error::invalid_subcommand( + arg_os.to_string_lossy().into_owned(), + cdate, + self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } else { + return Err(Error::unrecognized_subcommand( + arg_os.to_string_lossy().into_owned(), + self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), + self.color(), + )); + } + } else { + return Err(Error::unknown_argument( + &*arg_os.to_string_lossy(), + "", + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + } + + if !sc_is_external { + if let Some(ref pos_sc_name) = subcmd_name { + let sc_name = { + find_subcmd!(self, pos_sc_name) + .expect(INTERNAL_ERROR_MSG) + .p + .meta + .name + .clone() + }; + self.parse_subcommand(&*sc_name, matcher, it)?; + } else if self.is_set(AS::SubcommandRequired) { + let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name); + return Err(Error::missing_subcommand( + bn, + &usage::create_error_usage(self, matcher, None), + self.color(), + )); + } else if self.is_set(AS::SubcommandRequiredElseHelp) { + debugln!("Parser::get_matches_with: SubcommandRequiredElseHelp=true"); + let mut out = vec![]; + self.write_help_err(&mut out)?; + return Err(Error { + message: String::from_utf8_lossy(&*out).into_owned(), + kind: ErrorKind::MissingArgumentOrSubcommand, + info: None, + }); + } + } + + // In case the last arg was new, we need to process it's overrides + let check_all = self.is_set(AS::AllArgsOverrideSelf); + { + let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); + matcher.process_arg_overrides( + any_arg, + &mut self.overrides, + &mut self.required, + check_all, + ); + } + + self.remove_overrides(matcher); + + Validator::new(self).validate(needs_val_of, subcmd_name, matcher) + } + + fn remove_overrides(&mut self, matcher: &mut ArgMatcher) { + debugln!("Parser::remove_overrides:{:?};", self.overrides); + for &(overr, name) in &self.overrides { + debugln!("Parser::remove_overrides:iter:({},{});", overr, name); + if matcher.is_present(overr) { + debugln!( + "Parser::remove_overrides:iter:({},{}): removing {};", + overr, + name, + name + ); + matcher.remove(name); + for i in (0..self.required.len()).rev() { + debugln!( + "Parser::remove_overrides:iter:({},{}): removing required {};", + overr, + name, + name + ); + if self.required[i] == name { + self.required.swap_remove(i); + break; + } + } + } + } + } + + fn propagate_help_version(&mut self) { + debugln!("Parser::propagate_help_version;"); + self.create_help_and_version(); + for sc in &mut self.subcommands { + sc.p.propagate_help_version(); + } + } + + fn build_bin_names(&mut self) { + debugln!("Parser::build_bin_names;"); + for sc in &mut self.subcommands { + debug!("Parser::build_bin_names:iter: bin_name set..."); + if sc.p.meta.bin_name.is_none() { + sdebugln!("No"); + let bin_name = format!( + "{}{}{}", + self.meta + .bin_name + .as_ref() + .unwrap_or(&self.meta.name.clone()), + if self.meta.bin_name.is_some() { + " " + } else { + "" + }, + &*sc.p.meta.name + ); + debugln!( + "Parser::build_bin_names:iter: Setting bin_name of {} to {}", + self.meta.name, + bin_name + ); + sc.p.meta.bin_name = Some(bin_name); + } else { + sdebugln!("yes ({:?})", sc.p.meta.bin_name); + } + debugln!( + "Parser::build_bin_names:iter: Calling build_bin_names from...{}", + sc.p.meta.name + ); + sc.p.build_bin_names(); + } + } + + fn parse_subcommand( + &mut self, + sc_name: &str, + matcher: &mut ArgMatcher<'a>, + it: &mut Peekable, + ) -> ClapResult<()> + where + I: Iterator, + T: Into + Clone, + { + use std::fmt::Write; + debugln!("Parser::parse_subcommand;"); + let mut mid_string = String::new(); + if !self.is_set(AS::SubcommandsNegateReqs) { + let mut hs: Vec<&str> = self.required.iter().map(|n| &**n).collect(); + for k in matcher.arg_names() { + hs.push(k); + } + let reqs = usage::get_required_usage_from(self, &hs, Some(matcher), None, false); + + for s in &reqs { + write!(&mut mid_string, " {}", s).expect(INTERNAL_ERROR_MSG); + } + } + mid_string.push(' '); + if let Some(ref mut sc) = self + .subcommands + .iter_mut() + .find(|s| s.p.meta.name == sc_name) + { + let mut sc_matcher = ArgMatcher::new(); + // bin_name should be parent's bin_name + [] + the sc's name separated by + // a space + sc.p.meta.usage = Some(format!( + "{}{}{}", + self.meta.bin_name.as_ref().unwrap_or(&String::new()), + if self.meta.bin_name.is_some() { + &*mid_string + } else { + "" + }, + &*sc.p.meta.name + )); + sc.p.meta.bin_name = Some(format!( + "{}{}{}", + self.meta.bin_name.as_ref().unwrap_or(&String::new()), + if self.meta.bin_name.is_some() { + " " + } else { + "" + }, + &*sc.p.meta.name + )); + debugln!( + "Parser::parse_subcommand: About to parse sc={}", + sc.p.meta.name + ); + debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.p.settings); + sc.p.get_matches_with(&mut sc_matcher, it)?; + matcher.subcommand(SubCommand { + name: sc.p.meta.name.clone(), + matches: sc_matcher.into(), + }); + } + Ok(()) + } + + pub fn groups_for_arg(&self, name: &str) -> Option> { + debugln!("Parser::groups_for_arg: name={}", name); + + if self.groups.is_empty() { + debugln!("Parser::groups_for_arg: No groups defined"); + return None; + } + let mut res = vec![]; + debugln!("Parser::groups_for_arg: Searching through groups..."); + for grp in &self.groups { + for a in &grp.args { + if a == &name { + sdebugln!("\tFound '{}'", grp.name); + res.push(&*grp.name); + } + } + } + if res.is_empty() { + return None; + } + + Some(res) + } + + pub fn args_in_group(&self, group: &str) -> Vec { + debug_assert!(self.app_debug_asserts()); + + let mut g_vec = vec![]; + let mut args = vec![]; + + for n in &self + .groups + .iter() + .find(|g| g.name == group) + .expect(INTERNAL_ERROR_MSG) + .args + { + if let Some(f) = self.flags.iter().find(|f| &f.b.name == n) { + args.push(f.to_string()); + } else if let Some(f) = self.opts.iter().find(|o| &o.b.name == n) { + args.push(f.to_string()); + } else if let Some(p) = self.positionals.values().find(|p| &p.b.name == n) { + args.push(p.b.name.to_owned()); + } else { + g_vec.push(*n); + } + } + + for av in g_vec.iter().map(|g| self.args_in_group(g)) { + args.extend(av); + } + args.dedup(); + args.iter().map(ToOwned::to_owned).collect() + } + + pub fn arg_names_in_group(&self, group: &str) -> Vec<&'a str> { + let mut g_vec = vec![]; + let mut args = vec![]; + + for n in &self + .groups + .iter() + .find(|g| g.name == group) + .expect(INTERNAL_ERROR_MSG) + .args + { + if self.groups.iter().any(|g| g.name == *n) { + args.extend(self.arg_names_in_group(n)); + g_vec.push(*n); + } else if !args.contains(n) { + args.push(*n); + } + } + + args.iter().copied().collect() + } + + pub fn create_help_and_version(&mut self) { + debugln!("Parser::create_help_and_version;"); + // name is "hclap_help" because flags are sorted by name + if !self.is_set(AS::DisableHelpFlags) && !self.contains_long("help") { + debugln!("Parser::create_help_and_version: Building --help"); + if self.help_short.is_none() && !self.contains_short('h') { + self.help_short = Some('h'); + } + let arg = FlagBuilder { + b: Base { + name: "hclap_help", + help: self.help_message.or(Some("Prints help information")), + ..Default::default() + }, + s: Switched { + short: self.help_short, + long: Some("help"), + ..Default::default() + }, + }; + self.flags.push(arg); + } + if !self.is_set(AS::DisableVersion) && !self.contains_long("version") { + debugln!("Parser::create_help_and_version: Building --version"); + if self.version_short.is_none() && !self.contains_short('V') { + self.version_short = Some('V'); + } + // name is "vclap_version" because flags are sorted by name + let arg = FlagBuilder { + b: Base { + name: "vclap_version", + help: self.version_message.or(Some("Prints version information")), + ..Default::default() + }, + s: Switched { + short: self.version_short, + long: Some("version"), + ..Default::default() + }, + }; + self.flags.push(arg); + } + if !self.subcommands.is_empty() + && !self.is_set(AS::DisableHelpSubcommand) + && self.is_set(AS::NeedsSubcommandHelp) + { + debugln!("Parser::create_help_and_version: Building help"); + self.subcommands.push( + App::new("help") + .about("Prints this message or the help of the given subcommand(s)"), + ); + } + } + + // Retrieves the names of all args the user has supplied thus far, except required ones + // because those will be listed in self.required + fn check_for_help_and_version_str(&self, arg: &OsStr) -> ClapResult<()> { + debugln!("Parser::check_for_help_and_version_str;"); + debug!( + "Parser::check_for_help_and_version_str: Checking if --{} is help or version...", + arg.to_str().unwrap() + ); + if arg == "help" && self.is_set(AS::NeedsLongHelp) { + sdebugln!("Help"); + return Err(self._help(true)); + } + if arg == "version" && self.is_set(AS::NeedsLongVersion) { + sdebugln!("Version"); + return Err(self._version(true)); + } + sdebugln!("Neither"); + + Ok(()) + } + + fn check_for_help_and_version_char(&self, arg: char) -> ClapResult<()> { + debugln!("Parser::check_for_help_and_version_char;"); + debug!( + "Parser::check_for_help_and_version_char: Checking if -{} is help or version...", + arg + ); + if let Some(h) = self.help_short { + if arg == h && self.is_set(AS::NeedsLongHelp) { + sdebugln!("Help"); + return Err(self._help(false)); + } + } + if let Some(v) = self.version_short { + if arg == v && self.is_set(AS::NeedsLongVersion) { + sdebugln!("Version"); + return Err(self._version(false)); + } + } + sdebugln!("Neither"); + Ok(()) + } + + fn use_long_help(&self) -> bool { + // In this case, both must be checked. This allows the retention of + // original formatting, but also ensures that the actual -h or --help + // specified by the user is sent through. If HiddenShortHelp is not included, + // then items specified with hidden_short_help will also be hidden. + let should_long = |v: &Base| { + v.long_help.is_some() + || v.is_set(ArgSettings::HiddenLongHelp) + || v.is_set(ArgSettings::HiddenShortHelp) + }; + + self.meta.long_about.is_some() + || self.flags.iter().any(|f| should_long(&f.b)) + || self.opts.iter().any(|o| should_long(&o.b)) + || self.positionals.values().any(|p| should_long(&p.b)) + || self + .subcommands + .iter() + .any(|s| s.p.meta.long_about.is_some()) + } + + fn _help(&self, mut use_long: bool) -> Error { + debugln!("Parser::_help: use_long={:?}", use_long); + use_long = use_long && self.use_long_help(); + let mut buf = vec![]; + match Help::write_parser_help(&mut buf, self, use_long) { + Err(e) => e, + _ => Error { + message: String::from_utf8(buf).unwrap_or_default(), + kind: ErrorKind::HelpDisplayed, + info: None, + }, + } + } + + fn _version(&self, use_long: bool) -> Error { + debugln!("Parser::_version: "); + let out = io::stdout(); + let mut buf_w = BufWriter::new(out.lock()); + match self.print_version(&mut buf_w, use_long) { + Err(e) => e, + _ => Error { + message: String::new(), + kind: ErrorKind::VersionDisplayed, + info: None, + }, + } + } + + fn parse_long_arg( + &mut self, + matcher: &mut ArgMatcher<'a>, + full_arg: &OsStr, + it: &mut Peekable, + ) -> ClapResult> + where + I: Iterator, + T: Into + Clone, + { + // maybe here lifetime should be 'a + debugln!("Parser::parse_long_arg;"); + + // Update the current index + self.cur_idx.set(self.cur_idx.get() + 1); + + let mut val = None; + debug!("Parser::parse_long_arg: Does it contain '='..."); + let arg = if full_arg.contains_byte(b'=') { + let (p0, p1) = full_arg.trim_left_matches(b'-').split_at_byte(b'='); + sdebugln!("Yes '{:?}'", p1); + val = Some(p1); + p0 + } else { + sdebugln!("No"); + full_arg.trim_left_matches(b'-') + }; + + if let Some(opt) = find_opt_by_long!(@os self, arg) { + debugln!( + "Parser::parse_long_arg: Found valid opt '{}'", + opt.to_string() + ); + self.settings.set(AS::ValidArgFound); + let ret = self.parse_opt(val, opt, val.is_some(), matcher)?; + if self.cache.map_or(true, |name| name != opt.b.name) { + self.cache = Some(opt.b.name); + } + + return Ok(ret); + } else if let Some(flag) = find_flag_by_long!(@os self, arg) { + debugln!( + "Parser::parse_long_arg: Found valid flag '{}'", + flag.to_string() + ); + self.settings.set(AS::ValidArgFound); + // Only flags could be help or version, and we need to check the raw long + // so this is the first point to check + self.check_for_help_and_version_str(arg)?; + + self.parse_flag(flag, matcher)?; + + // Handle conflicts, requirements, etc. + if self.cache.map_or(true, |name| name != flag.b.name) { + self.cache = Some(flag.b.name); + } + + return Ok(ParseResult::Flag); + } else if self.is_set(AS::AllowLeadingHyphen) { + return Ok(ParseResult::MaybeHyphenValue); + } else if self.is_set(AS::ValidNegNumFound) { + return Ok(ParseResult::MaybeNegNum); + } + + debugln!("Parser::parse_long_arg: Didn't match anything"); + + let args_rest: Vec<_> = it.map(|x| x.into()).collect(); + let args_rest2: Vec<_> = args_rest + .iter() + .map(|x| x.to_str().expect(INVALID_UTF8)) + .collect(); + self.did_you_mean_error(arg.to_str().expect(INVALID_UTF8), matcher, &args_rest2[..]) + .map(|_| ParseResult::NotFound) + } + + fn parse_short_arg( + &mut self, + matcher: &mut ArgMatcher<'a>, + full_arg: &OsStr, + ) -> ClapResult> { + debugln!("Parser::parse_short_arg: full_arg={:?}", full_arg); + let arg_os = full_arg.trim_left_matches(b'-'); + let arg = arg_os.to_string_lossy(); + + // If AllowLeadingHyphen is set, we want to ensure `-val` gets parsed as `-val` and not + // `-v` `-a` `-l` assuming `v` `a` and `l` are all, or mostly, valid shorts. + if self.is_set(AS::AllowLeadingHyphen) { + if arg.chars().any(|c| !self.contains_short(c)) { + debugln!( + "Parser::parse_short_arg: LeadingHyphenAllowed yet -{} isn't valid", + arg + ); + return Ok(ParseResult::MaybeHyphenValue); + } + } else if self.is_set(AS::ValidNegNumFound) { + // TODO: Add docs about having AllowNegativeNumbers and `-2` as a valid short + // May be better to move this to *after* not finding a valid flag/opt? + debugln!("Parser::parse_short_arg: Valid negative num..."); + return Ok(ParseResult::MaybeNegNum); + } + + let mut ret = ParseResult::NotFound; + for c in arg.chars() { + debugln!("Parser::parse_short_arg:iter:{}", c); + + // update each index because `-abcd` is four indices to clap + self.cur_idx.set(self.cur_idx.get() + 1); + + // Check for matching short options, and return the name if there is no trailing + // concatenated value: -oval + // Option: -o + // Value: val + if let Some(opt) = find_opt_by_short!(self, c) { + debugln!("Parser::parse_short_arg:iter:{}: Found valid opt", c); + self.settings.set(AS::ValidArgFound); + // Check for trailing concatenated value + let p: Vec<_> = arg.splitn(2, c).collect(); + debugln!( + "Parser::parse_short_arg:iter:{}: p[0]={:?}, p[1]={:?}", + c, + p[0].as_bytes(), + p[1].as_bytes() + ); + let i = p[0].as_bytes().len() + 1; + let val = if !p[1].as_bytes().is_empty() { + debugln!( + "Parser::parse_short_arg:iter:{}: val={:?} (bytes), val={:?} (ascii)", + c, + arg_os.split_at(i).1.as_bytes(), + arg_os.split_at(i).1 + ); + Some(arg_os.split_at(i).1) + } else { + None + }; + + // Default to "we're expecting a value later" + let ret = self.parse_opt(val, opt, false, matcher)?; + + if self.cache.map_or(true, |name| name != opt.b.name) { + self.cache = Some(opt.b.name); + } + + return Ok(ret); + } else if let Some(flag) = find_flag_by_short!(self, c) { + debugln!("Parser::parse_short_arg:iter:{}: Found valid flag", c); + self.settings.set(AS::ValidArgFound); + // Only flags can be help or version + self.check_for_help_and_version_char(c)?; + ret = self.parse_flag(flag, matcher)?; + + // Handle conflicts, requirements, overrides, etc. + // Must be called here due to mutabililty + if self.cache.map_or(true, |name| name != flag.b.name) { + self.cache = Some(flag.b.name); + } + } else { + let arg = format!("-{}", c); + return Err(Error::unknown_argument( + &*arg, + "", + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + } + Ok(ret) + } + + fn parse_opt( + &self, + val: Option<&OsStr>, + opt: &OptBuilder<'a, 'b>, + had_eq: bool, + matcher: &mut ArgMatcher<'a>, + ) -> ClapResult> { + debugln!("Parser::parse_opt; opt={}, val={:?}", opt.b.name, val); + debugln!("Parser::parse_opt; opt.settings={:?}", opt.b.settings); + let mut has_eq = false; + let no_val = val.is_none(); + let empty_vals = opt.is_set(ArgSettings::EmptyValues); + let min_vals_zero = opt.v.min_vals.unwrap_or(1) == 0; + let needs_eq = opt.is_set(ArgSettings::RequireEquals); + + debug!("Parser::parse_opt; Checking for val..."); + if let Some(fv) = val { + has_eq = fv.starts_with(&[b'=']) || had_eq; + let v = fv.trim_left_matches(b'='); + if !empty_vals && (v.is_empty() || (needs_eq && !has_eq)) { + sdebugln!("Found Empty - Error"); + return Err(Error::empty_value( + opt, + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + sdebugln!("Found - {:?}, len: {}", v, v.len()); + debugln!( + "Parser::parse_opt: {:?} contains '='...{:?}", + fv, + fv.starts_with(&[b'=']) + ); + self.add_val_to_arg(opt, v, matcher)?; + } else if needs_eq && !(empty_vals || min_vals_zero) { + sdebugln!("None, but requires equals...Error"); + return Err(Error::empty_value( + opt, + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } else { + sdebugln!("None"); + } + + matcher.inc_occurrence_of(opt.b.name); + // Increment or create the group "args" + if let Some(vec) = self.groups_for_arg(opt.b.name) { + matcher.inc_occurrences_of(&*vec); + } + + let needs_delim = opt.is_set(ArgSettings::RequireDelimiter); + let mult = opt.is_set(ArgSettings::Multiple); + if no_val && min_vals_zero && !has_eq && needs_eq { + debugln!("Parser::parse_opt: More arg vals not required..."); + return Ok(ParseResult::ValuesDone); + } else if no_val || (mult && !needs_delim) && !has_eq && matcher.needs_more_vals(opt) { + debugln!("Parser::parse_opt: More arg vals required..."); + return Ok(ParseResult::Opt(opt.b.name)); + } + debugln!("Parser::parse_opt: More arg vals not required..."); + Ok(ParseResult::ValuesDone) + } + + fn add_val_to_arg( + &self, + arg: &A, + val: &OsStr, + matcher: &mut ArgMatcher<'a>, + ) -> ClapResult> + where + A: AnyArg<'a, 'b> + Display, + { + debugln!("Parser::add_val_to_arg; arg={}, val={:?}", arg.name(), val); + debugln!( + "Parser::add_val_to_arg; trailing_vals={:?}, DontDelimTrailingVals={:?}", + self.is_set(AS::TrailingValues), + self.is_set(AS::DontDelimitTrailingValues) + ); + if !(self.is_set(AS::TrailingValues) && self.is_set(AS::DontDelimitTrailingValues)) { + if let Some(delim) = arg.val_delim() { + if val.is_empty() { + Ok(self.add_single_val_to_arg(arg, val, matcher)?) + } else { + let mut iret = ParseResult::ValuesDone; + for v in val.split(delim as u32 as u8) { + iret = self.add_single_val_to_arg(arg, v, matcher)?; + } + // If there was a delimiter used, we're not looking for more values + if val.contains_byte(delim as u32 as u8) + || arg.is_set(ArgSettings::RequireDelimiter) + { + iret = ParseResult::ValuesDone; + } + Ok(iret) + } + } else { + self.add_single_val_to_arg(arg, val, matcher) + } + } else { + self.add_single_val_to_arg(arg, val, matcher) + } + } + + fn add_single_val_to_arg( + &self, + arg: &A, + v: &OsStr, + matcher: &mut ArgMatcher<'a>, + ) -> ClapResult> + where + A: AnyArg<'a, 'b> + Display, + { + debugln!("Parser::add_single_val_to_arg;"); + debugln!("Parser::add_single_val_to_arg: adding val...{:?}", v); + + // update the current index because each value is a distinct index to clap + self.cur_idx.set(self.cur_idx.get() + 1); + + // @TODO @docs @p4: docs for indices should probably note that a terminator isn't a value + // and therefore not reported in indices + if let Some(t) = arg.val_terminator() { + if t == v { + return Ok(ParseResult::ValuesDone); + } + } + + matcher.add_val_to(arg.name(), v); + matcher.add_index_to(arg.name(), self.cur_idx.get()); + + // Increment or create the group "args" + if let Some(grps) = self.groups_for_arg(arg.name()) { + for grp in grps { + matcher.add_val_to(&*grp, v); + } + } + + if matcher.needs_more_vals(arg) { + return Ok(ParseResult::Opt(arg.name())); + } + Ok(ParseResult::ValuesDone) + } + + fn parse_flag( + &self, + flag: &FlagBuilder<'a, 'b>, + matcher: &mut ArgMatcher<'a>, + ) -> ClapResult> { + debugln!("Parser::parse_flag;"); + + matcher.inc_occurrence_of(flag.b.name); + matcher.add_index_to(flag.b.name, self.cur_idx.get()); + + // Increment or create the group "args" + if let Some(vec) = self.groups_for_arg(flag.b.name) { + matcher.inc_occurrences_of(&*vec); + } + + Ok(ParseResult::Flag) + } + + fn did_you_mean_error( + &self, + arg: &str, + matcher: &mut ArgMatcher<'a>, + args_rest: &[&str], + ) -> ClapResult<()> { + // Didn't match a flag or option + let suffix = + suggestions::did_you_mean_flag_suffix(arg, args_rest, longs!(self), &self.subcommands); + + // Add the arg to the matches to build a proper usage string + if let Some(name) = suffix.1 { + if let Some(opt) = find_opt_by_long!(self, name) { + if let Some(grps) = self.groups_for_arg(&*opt.b.name) { + matcher.inc_occurrences_of(&*grps); + } + matcher.insert(&*opt.b.name); + } else if let Some(flg) = find_flag_by_long!(self, name) { + if let Some(grps) = self.groups_for_arg(&*flg.b.name) { + matcher.inc_occurrences_of(&*grps); + } + matcher.insert(&*flg.b.name); + } + } + + let used_arg = format!("--{}", arg); + Err(Error::unknown_argument( + &*used_arg, + &*suffix.0, + &*usage::create_error_usage(self, matcher, None), + self.color(), + )) + } + + // Prints the version to the user and exits if quit=true + fn print_version(&self, w: &mut W, use_long: bool) -> ClapResult<()> { + self.write_version(w, use_long)?; + w.flush().map_err(Error::from) + } + + pub fn write_version(&self, w: &mut W, use_long: bool) -> io::Result<()> { + let ver = if use_long { + self.meta + .long_version + .unwrap_or_else(|| self.meta.version.unwrap_or("")) + } else { + self.meta + .version + .unwrap_or_else(|| self.meta.long_version.unwrap_or("")) + }; + if let Some(bn) = self.meta.bin_name.as_ref() { + if bn.contains(' ') { + // Incase we're dealing with subcommands i.e. git mv is translated to git-mv + write!(w, "{} {}", bn.replace(" ", "-"), ver) + } else { + write!(w, "{} {}", &self.meta.name[..], ver) + } + } else { + write!(w, "{} {}", &self.meta.name[..], ver) + } + } + + pub fn print_help(&self) -> ClapResult<()> { + let out = io::stdout(); + let mut buf_w = BufWriter::new(out.lock()); + self.write_help(&mut buf_w) + } + + pub fn write_help(&self, w: &mut W) -> ClapResult<()> { + Help::write_parser_help(w, self, false) + } + + pub fn write_long_help(&self, w: &mut W) -> ClapResult<()> { + Help::write_parser_help(w, self, true) + } + + pub fn write_help_err(&self, w: &mut W) -> ClapResult<()> { + Help::write_parser_help_to_stderr(w, self) + } + + pub fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { + debugln!("Parser::add_defaults;"); + macro_rules! add_val { + (@default $_self:ident, $a:ident, $m:ident) => { + if let Some(ref val) = $a.v.default_val { + debugln!("Parser::add_defaults:iter:{}: has default vals", $a.b.name); + if $m.get($a.b.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) { + debugln!("Parser::add_defaults:iter:{}: has no user defined vals", $a.b.name); + $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + + if $_self.cache.map_or(true, |name| name != $a.name()) { + $_self.cache = Some($a.name()); + } + } else if $m.get($a.b.name).is_some() { + debugln!("Parser::add_defaults:iter:{}: has user defined vals", $a.b.name); + } else { + debugln!("Parser::add_defaults:iter:{}: wasn't used", $a.b.name); + + $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + + if $_self.cache.map_or(true, |name| name != $a.name()) { + $_self.cache = Some($a.name()); + } + } + } else { + debugln!("Parser::add_defaults:iter:{}: doesn't have default vals", $a.b.name); + } + }; + ($_self:ident, $a:ident, $m:ident) => { + if let Some(ref vm) = $a.v.default_vals_ifs { + sdebugln!(" has conditional defaults"); + let mut done = false; + if $m.get($a.b.name).is_none() { + for &(arg, val, default) in vm.values() { + let add = if let Some(a) = $m.get(arg) { + if let Some(v) = val { + a.vals.iter().any(|value| v == value) + } else { + true + } + } else { + false + }; + if add { + $_self.add_val_to_arg($a, OsStr::new(default), $m)?; + if $_self.cache.map_or(true, |name| name != $a.name()) { + $_self.cache = Some($a.name()); + } + done = true; + break; + } + } + } + + if done { + continue; // outer loop (outside macro) + } + } else { + sdebugln!(" doesn't have conditional defaults"); + } + add_val!(@default $_self, $a, $m) + }; + } + + for o in &self.opts { + debug!("Parser::add_defaults:iter:{}:", o.b.name); + add_val!(self, o, matcher); + } + for p in self.positionals.values() { + debug!("Parser::add_defaults:iter:{}:", p.b.name); + add_val!(self, p, matcher); + } + Ok(()) + } + + pub fn add_env(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { + macro_rules! add_val { + ($_self:ident, $a:ident, $m:ident) => { + if let Some(ref val) = $a.v.env { + if $m + .get($a.b.name) + .map(|ma| ma.vals.len()) + .map(|len| len == 0) + .unwrap_or(false) + { + if let Some(ref val) = val.1 { + $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + + if $_self.cache.map_or(true, |name| name != $a.name()) { + $_self.cache = Some($a.name()); + } + } + } else { + if let Some(ref val) = val.1 { + $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + + if $_self.cache.map_or(true, |name| name != $a.name()) { + $_self.cache = Some($a.name()); + } + } + } + } + }; + } + + for o in &self.opts { + add_val!(self, o, matcher); + } + for p in self.positionals.values() { + add_val!(self, p, matcher); + } + Ok(()) + } + + pub fn flags(&self) -> Iter> { + self.flags.iter() + } + + pub fn opts(&self) -> Iter> { + self.opts.iter() + } + + pub fn positionals(&self) -> map::Values> { + self.positionals.values() + } + + pub fn subcommands(&self) -> Iter { + self.subcommands.iter() + } + + // Should we color the output? None=determined by output location, true=yes, false=no + #[doc(hidden)] + pub fn color(&self) -> ColorWhen { + debugln!("Parser::color;"); + debug!("Parser::color: Color setting..."); + if self.is_set(AS::ColorNever) { + sdebugln!("Never"); + ColorWhen::Never + } else if self.is_set(AS::ColorAlways) { + sdebugln!("Always"); + ColorWhen::Always + } else { + sdebugln!("Auto"); + ColorWhen::Auto + } + } + + pub fn find_any_arg(&self, name: &str) -> Option<&AnyArg<'a, 'b>> { + if let Some(f) = find_by_name!(self, name, flags, iter) { + return Some(f); + } + if let Some(o) = find_by_name!(self, name, opts, iter) { + return Some(o); + } + if let Some(p) = find_by_name!(self, name, positionals, values) { + return Some(p); + } + None + } + + /// Check is a given string matches the binary name for this parser + fn is_bin_name(&self, value: &str) -> bool { + self.meta + .bin_name + .as_ref() + .map(|name| value == name) + .unwrap_or(false) + } + + /// Check is a given string is an alias for this parser + fn is_alias(&self, value: &str) -> bool { + self.meta + .aliases + .as_ref() + .map(|aliases| { + for alias in aliases { + if alias.0 == value { + return true; + } + } + false + }) + .unwrap_or(false) + } + + // Only used for completion scripts due to bin_name messiness + #[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))] + pub fn find_subcommand(&'b self, sc: &str) -> Option<&'b App<'a, 'b>> { + debugln!("Parser::find_subcommand: sc={}", sc); + debugln!( + "Parser::find_subcommand: Currently in Parser...{}", + self.meta.bin_name.as_ref().unwrap() + ); + for s in &self.subcommands { + if s.p.is_bin_name(sc) { + return Some(s); + } + // XXX: why do we split here? + // isn't `sc` supposed to be single word already? + let last = sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG); + if s.p.is_alias(last) { + return Some(s); + } + + if let Some(app) = s.p.find_subcommand(sc) { + return Some(app); + } + } + None + } + + #[inline] + fn contains_long(&self, l: &str) -> bool { + longs!(self).any(|al| al == &l) + } + + #[inline] + fn contains_short(&self, s: char) -> bool { + shorts!(self).any(|arg_s| arg_s == &s) + } +} diff --git a/vendor/clap-2.34.0/src/app/settings.rs b/vendor/clap-2.34.0/src/app/settings.rs new file mode 100644 index 0000000000000..e387d9e90133a --- /dev/null +++ b/vendor/clap-2.34.0/src/app/settings.rs @@ -0,0 +1,1192 @@ +// Std +#[allow(deprecated, unused_imports)] +use std::ascii::AsciiExt; +use std::ops::BitOr; +use std::str::FromStr; + +bitflags! { + struct Flags: u64 { + const SC_NEGATE_REQS = 1; + const SC_REQUIRED = 1 << 1; + const A_REQUIRED_ELSE_HELP = 1 << 2; + const GLOBAL_VERSION = 1 << 3; + const VERSIONLESS_SC = 1 << 4; + const UNIFIED_HELP = 1 << 5; + const WAIT_ON_ERROR = 1 << 6; + const SC_REQUIRED_ELSE_HELP= 1 << 7; + const NEEDS_LONG_HELP = 1 << 8; + const NEEDS_LONG_VERSION = 1 << 9; + const NEEDS_SC_HELP = 1 << 10; + const DISABLE_VERSION = 1 << 11; + const HIDDEN = 1 << 12; + const TRAILING_VARARG = 1 << 13; + const NO_BIN_NAME = 1 << 14; + const ALLOW_UNK_SC = 1 << 15; + const UTF8_STRICT = 1 << 16; + const UTF8_NONE = 1 << 17; + const LEADING_HYPHEN = 1 << 18; + const NO_POS_VALUES = 1 << 19; + const NEXT_LINE_HELP = 1 << 20; + const DERIVE_DISP_ORDER = 1 << 21; + const COLORED_HELP = 1 << 22; + const COLOR_ALWAYS = 1 << 23; + const COLOR_AUTO = 1 << 24; + const COLOR_NEVER = 1 << 25; + const DONT_DELIM_TRAIL = 1 << 26; + const ALLOW_NEG_NUMS = 1 << 27; + const LOW_INDEX_MUL_POS = 1 << 28; + const DISABLE_HELP_SC = 1 << 29; + const DONT_COLLAPSE_ARGS = 1 << 30; + const ARGS_NEGATE_SCS = 1 << 31; + const PROPAGATE_VALS_DOWN = 1 << 32; + const ALLOW_MISSING_POS = 1 << 33; + const TRAILING_VALUES = 1 << 34; + const VALID_NEG_NUM_FOUND = 1 << 35; + const PROPAGATED = 1 << 36; + const VALID_ARG_FOUND = 1 << 37; + const INFER_SUBCOMMANDS = 1 << 38; + const CONTAINS_LAST = 1 << 39; + const ARGS_OVERRIDE_SELF = 1 << 40; + const DISABLE_HELP_FLAGS = 1 << 41; + } +} + +#[doc(hidden)] +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct AppFlags(Flags); + +impl BitOr for AppFlags { + type Output = Self; + fn bitor(self, rhs: Self) -> Self { + AppFlags(self.0 | rhs.0) + } +} + +impl Default for AppFlags { + fn default() -> Self { + AppFlags( + Flags::NEEDS_LONG_VERSION + | Flags::NEEDS_LONG_HELP + | Flags::NEEDS_SC_HELP + | Flags::UTF8_NONE + | Flags::COLOR_AUTO, + ) + } +} + +#[allow(deprecated)] +impl AppFlags { + pub fn new() -> Self { + AppFlags::default() + } + pub fn zeroed() -> Self { + AppFlags(Flags::empty()) + } + + impl_settings! { AppSettings, + ArgRequiredElseHelp => Flags::A_REQUIRED_ELSE_HELP, + ArgsNegateSubcommands => Flags::ARGS_NEGATE_SCS, + AllArgsOverrideSelf => Flags::ARGS_OVERRIDE_SELF, + AllowExternalSubcommands => Flags::ALLOW_UNK_SC, + AllowInvalidUtf8 => Flags::UTF8_NONE, + AllowLeadingHyphen => Flags::LEADING_HYPHEN, + AllowNegativeNumbers => Flags::ALLOW_NEG_NUMS, + AllowMissingPositional => Flags::ALLOW_MISSING_POS, + ColoredHelp => Flags::COLORED_HELP, + ColorAlways => Flags::COLOR_ALWAYS, + ColorAuto => Flags::COLOR_AUTO, + ColorNever => Flags::COLOR_NEVER, + DontDelimitTrailingValues => Flags::DONT_DELIM_TRAIL, + DontCollapseArgsInUsage => Flags::DONT_COLLAPSE_ARGS, + DeriveDisplayOrder => Flags::DERIVE_DISP_ORDER, + DisableHelpFlags => Flags::DISABLE_HELP_FLAGS, + DisableHelpSubcommand => Flags::DISABLE_HELP_SC, + DisableVersion => Flags::DISABLE_VERSION, + GlobalVersion => Flags::GLOBAL_VERSION, + HidePossibleValuesInHelp => Flags::NO_POS_VALUES, + Hidden => Flags::HIDDEN, + LowIndexMultiplePositional => Flags::LOW_INDEX_MUL_POS, + NeedsLongHelp => Flags::NEEDS_LONG_HELP, + NeedsLongVersion => Flags::NEEDS_LONG_VERSION, + NeedsSubcommandHelp => Flags::NEEDS_SC_HELP, + NoBinaryName => Flags::NO_BIN_NAME, + PropagateGlobalValuesDown=> Flags::PROPAGATE_VALS_DOWN, + StrictUtf8 => Flags::UTF8_STRICT, + SubcommandsNegateReqs => Flags::SC_NEGATE_REQS, + SubcommandRequired => Flags::SC_REQUIRED, + SubcommandRequiredElseHelp => Flags::SC_REQUIRED_ELSE_HELP, + TrailingVarArg => Flags::TRAILING_VARARG, + UnifiedHelpMessage => Flags::UNIFIED_HELP, + NextLineHelp => Flags::NEXT_LINE_HELP, + VersionlessSubcommands => Flags::VERSIONLESS_SC, + WaitOnError => Flags::WAIT_ON_ERROR, + TrailingValues => Flags::TRAILING_VALUES, + ValidNegNumFound => Flags::VALID_NEG_NUM_FOUND, + Propagated => Flags::PROPAGATED, + ValidArgFound => Flags::VALID_ARG_FOUND, + InferSubcommands => Flags::INFER_SUBCOMMANDS, + ContainsLast => Flags::CONTAINS_LAST + } +} + +/// Application level settings, which affect how [`App`] operates +/// +/// **NOTE:** When these settings are used, they apply only to current command, and are *not* +/// propagated down or up through child or parent subcommands +/// +/// [`App`]: ./struct.App.html +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum AppSettings { + /// Specifies that any invalid UTF-8 code points should *not* be treated as an error. + /// This is the default behavior of `clap`. + /// + /// **NOTE:** Using argument values with invalid UTF-8 code points requires using + /// [`ArgMatches::os_value_of`], [`ArgMatches::os_values_of`], [`ArgMatches::lossy_value_of`], + /// or [`ArgMatches::lossy_values_of`] for those particular arguments which may contain invalid + /// UTF-8 values + /// + /// **NOTE:** This rule only applies to argument values, as flags, options, and + /// [`SubCommand`]s themselves only allow valid UTF-8 code points. + /// + /// # Platform Specific + /// + /// Non Windows systems only + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, AppSettings}; + /// use std::ffi::OsString; + /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; + /// + /// let r = App::new("myprog") + /// //.setting(AppSettings::AllowInvalidUtf8) + /// .arg_from_usage(" 'some positional arg'") + /// .get_matches_from_safe( + /// vec![ + /// OsString::from("myprog"), + /// OsString::from_vec(vec![0xe9])]); + /// + /// assert!(r.is_ok()); + /// let m = r.unwrap(); + /// assert_eq!(m.value_of_os("arg").unwrap().as_bytes(), &[0xe9]); + /// ``` + /// [`ArgMatches::os_value_of`]: ./struct.ArgMatches.html#method.os_value_of + /// [`ArgMatches::os_values_of`]: ./struct.ArgMatches.html#method.os_values_of + /// [`ArgMatches::lossy_value_of`]: ./struct.ArgMatches.html#method.lossy_value_of + /// [`ArgMatches::lossy_values_of`]: ./struct.ArgMatches.html#method.lossy_values_of + /// [`SubCommand`]: ./struct.SubCommand.html + AllowInvalidUtf8, + + /// Essentially sets [`Arg::overrides_with("itself")`] for all arguments. + /// + /// **WARNING:** Positional arguments cannot override themselves (or we would never be able + /// to advance to the next positional). This setting ignores positional arguments. + /// [`Arg::overrides_with("itself")`]: ./struct.Arg.html#method.overrides_with + AllArgsOverrideSelf, + + /// Specifies that leading hyphens are allowed in argument *values*, such as negative numbers + /// like `-10`. (which would otherwise be parsed as another flag or option) + /// + /// **NOTE:** Use this setting with caution as it silences certain circumstances which would + /// otherwise be an error (such as accidentally forgetting to specify a value for leading + /// option). It is preferred to set this on a per argument basis, via [`Arg::allow_hyphen_values`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{Arg, App, AppSettings}; + /// // Imagine you needed to represent negative numbers as well, such as -10 + /// let m = App::new("nums") + /// .setting(AppSettings::AllowLeadingHyphen) + /// .arg(Arg::with_name("neg").index(1)) + /// .get_matches_from(vec![ + /// "nums", "-20" + /// ]); + /// + /// assert_eq!(m.value_of("neg"), Some("-20")); + /// # ; + /// ``` + /// [`Arg::allow_hyphen_values`]: ./struct.Arg.html#method.allow_hyphen_values + AllowLeadingHyphen, + + /// Allows negative numbers to pass as values. This is similar to + /// `AllowLeadingHyphen` except that it only allows numbers, all + /// other undefined leading hyphens will fail to parse. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::AllowNegativeNumbers) + /// .arg(Arg::with_name("num")) + /// .get_matches_from_safe(vec![ + /// "myprog", "-20" + /// ]); + /// assert!(res.is_ok()); + /// let m = res.unwrap(); + /// assert_eq!(m.value_of("num").unwrap(), "-20"); + /// ``` + /// [`AllowLeadingHyphen`]: ./enum.AppSettings.html#variant.AllowLeadingHyphen + AllowNegativeNumbers, + + /// Allows one to implement two styles of CLIs where positionals can be used out of order. + /// + /// The first example is a CLI where the second to last positional argument is optional, but + /// the final positional argument is required. Such as `$ prog [optional] ` where one + /// of the two following usages is allowed: + /// + /// * `$ prog [optional] ` + /// * `$ prog ` + /// + /// This would otherwise not be allowed. This is useful when `[optional]` has a default value. + /// + /// **Note:** when using this style of "missing positionals" the final positional *must* be + /// [required] if `--` will not be used to skip to the final positional argument. + /// + /// **Note:** This style also only allows a single positional argument to be "skipped" without + /// the use of `--`. To skip more than one, see the second example. + /// + /// The second example is when one wants to skip multiple optional positional arguments, and use + /// of the `--` operator is OK (but not required if all arguments will be specified anyways). + /// + /// For example, imagine a CLI which has three positional arguments `[foo] [bar] [baz]...` where + /// `baz` accepts multiple values (similar to man `ARGS...` style training arguments). + /// + /// With this setting the following invocations are possible: + /// + /// * `$ prog foo bar baz1 baz2 baz3` + /// * `$ prog foo -- baz1 baz2 baz3` + /// * `$ prog -- baz1 baz2 baz3` + /// + /// # Examples + /// + /// Style number one from above: + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// // Assume there is an external subcommand named "subcmd" + /// let m = App::new("myprog") + /// .setting(AppSettings::AllowMissingPositional) + /// .arg(Arg::with_name("arg1")) + /// .arg(Arg::with_name("arg2") + /// .required(true)) + /// .get_matches_from(vec![ + /// "prog", "other" + /// ]); + /// + /// assert_eq!(m.value_of("arg1"), None); + /// assert_eq!(m.value_of("arg2"), Some("other")); + /// ``` + /// + /// Now the same example, but using a default value for the first optional positional argument + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// // Assume there is an external subcommand named "subcmd" + /// let m = App::new("myprog") + /// .setting(AppSettings::AllowMissingPositional) + /// .arg(Arg::with_name("arg1") + /// .default_value("something")) + /// .arg(Arg::with_name("arg2") + /// .required(true)) + /// .get_matches_from(vec![ + /// "prog", "other" + /// ]); + /// + /// assert_eq!(m.value_of("arg1"), Some("something")); + /// assert_eq!(m.value_of("arg2"), Some("other")); + /// ``` + /// Style number two from above: + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// // Assume there is an external subcommand named "subcmd" + /// let m = App::new("myprog") + /// .setting(AppSettings::AllowMissingPositional) + /// .arg(Arg::with_name("foo")) + /// .arg(Arg::with_name("bar")) + /// .arg(Arg::with_name("baz").multiple(true)) + /// .get_matches_from(vec![ + /// "prog", "foo", "bar", "baz1", "baz2", "baz3" + /// ]); + /// + /// assert_eq!(m.value_of("foo"), Some("foo")); + /// assert_eq!(m.value_of("bar"), Some("bar")); + /// assert_eq!(m.values_of("baz").unwrap().collect::>(), &["baz1", "baz2", "baz3"]); + /// ``` + /// + /// Now notice if we don't specify `foo` or `baz` but use the `--` operator. + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// // Assume there is an external subcommand named "subcmd" + /// let m = App::new("myprog") + /// .setting(AppSettings::AllowMissingPositional) + /// .arg(Arg::with_name("foo")) + /// .arg(Arg::with_name("bar")) + /// .arg(Arg::with_name("baz").multiple(true)) + /// .get_matches_from(vec![ + /// "prog", "--", "baz1", "baz2", "baz3" + /// ]); + /// + /// assert_eq!(m.value_of("foo"), None); + /// assert_eq!(m.value_of("bar"), None); + /// assert_eq!(m.values_of("baz").unwrap().collect::>(), &["baz1", "baz2", "baz3"]); + /// ``` + /// [required]: ./struct.Arg.html#method.required + AllowMissingPositional, + + /// Specifies that an unexpected positional argument, + /// which would otherwise cause a [`ErrorKind::UnknownArgument`] error, + /// should instead be treated as a [`SubCommand`] within the [`ArgMatches`] struct. + /// + /// **NOTE:** Use this setting with caution, + /// as a truly unexpected argument (i.e. one that is *NOT* an external subcommand) + /// will **not** cause an error and instead be treated as a potential subcommand. + /// One should check for such cases manually and inform the user appropriately. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings}; + /// // Assume there is an external subcommand named "subcmd" + /// let m = App::new("myprog") + /// .setting(AppSettings::AllowExternalSubcommands) + /// .get_matches_from(vec![ + /// "myprog", "subcmd", "--option", "value", "-fff", "--flag" + /// ]); + /// + /// // All trailing arguments will be stored under the subcommand's sub-matches using an empty + /// // string argument name + /// match m.subcommand() { + /// (external, Some(ext_m)) => { + /// let ext_args: Vec<&str> = ext_m.values_of("").unwrap().collect(); + /// assert_eq!(external, "subcmd"); + /// assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]); + /// }, + /// _ => {}, + /// } + /// ``` + /// [`ErrorKind::UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`ArgMatches`]: ./struct.ArgMatches.html + AllowExternalSubcommands, + + /// Specifies that use of a valid [argument] negates [subcommands] being used after. By default + /// `clap` allows arguments between subcommands such as + /// ` [cmd_args] [cmd2_args] [cmd3_args]`. This setting disables that + /// functionality and says that arguments can only follow the *final* subcommand. For instance + /// using this setting makes only the following invocations possible: + /// + /// * ` [cmd3_args]` + /// * ` [cmd2_args]` + /// * ` [cmd_args]` + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::ArgsNegateSubcommands) + /// # ; + /// ``` + /// [subcommands]: ./struct.SubCommand.html + /// [argument]: ./struct.Arg.html + ArgsNegateSubcommands, + + /// Specifies that the help text should be displayed (and then exit gracefully), + /// if no arguments are present at runtime (i.e. an empty run such as, `$ myprog`. + /// + /// **NOTE:** [`SubCommand`]s count as arguments + /// + /// **NOTE:** Setting [`Arg::default_value`] effectively disables this option as it will + /// ensure that some argument is always present. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::ArgRequiredElseHelp) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value + ArgRequiredElseHelp, + + /// Uses colorized help messages. + /// + /// **NOTE:** Must be compiled with the `color` cargo feature + /// + /// # Platform Specific + /// + /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms) + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::ColoredHelp) + /// .get_matches(); + /// ``` + ColoredHelp, + + /// Enables colored output only when the output is going to a terminal or TTY. + /// + /// **NOTE:** This is the default behavior of `clap`. + /// + /// **NOTE:** Must be compiled with the `color` cargo feature. + /// + /// # Platform Specific + /// + /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms). + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::ColorAuto) + /// .get_matches(); + /// ``` + ColorAuto, + + /// Enables colored output regardless of whether or not the output is going to a terminal/TTY. + /// + /// **NOTE:** Must be compiled with the `color` cargo feature. + /// + /// # Platform Specific + /// + /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms). + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::ColorAlways) + /// .get_matches(); + /// ``` + ColorAlways, + + /// Disables colored output no matter if the output is going to a terminal/TTY, or not. + /// + /// **NOTE:** Must be compiled with the `color` cargo feature + /// + /// # Platform Specific + /// + /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms) + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::ColorNever) + /// .get_matches(); + /// ``` + ColorNever, + + /// Disables the automatic collapsing of positional args into `[ARGS]` inside the usage string + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::DontCollapseArgsInUsage) + /// .get_matches(); + /// ``` + DontCollapseArgsInUsage, + + /// Disables the automatic delimiting of values when `--` or [`AppSettings::TrailingVarArg`] + /// was used. + /// + /// **NOTE:** The same thing can be done manually by setting the final positional argument to + /// [`Arg::use_delimiter(false)`]. Using this setting is safer, because it's easier to locate + /// when making changes. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::DontDelimitTrailingValues) + /// .get_matches(); + /// ``` + /// [`AppSettings::TrailingVarArg`]: ./enum.AppSettings.html#variant.TrailingVarArg + /// [`Arg::use_delimiter(false)`]: ./struct.Arg.html#method.use_delimiter + DontDelimitTrailingValues, + + /// Disables `-h` and `--help` [`App`] without affecting any of the [`SubCommand`]s + /// (Defaults to `false`; application *does* have help flags) + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .setting(AppSettings::DisableHelpFlags) + /// .get_matches_from_safe(vec![ + /// "myprog", "-h" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// + /// ```rust + /// # use clap::{App, SubCommand, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .setting(AppSettings::DisableHelpFlags) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", "test", "-h" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::HelpDisplayed); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`App`]: ./struct.App.html + DisableHelpFlags, + + /// Disables the `help` subcommand + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings, ErrorKind, SubCommand}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::DisableHelpSubcommand) + /// // Normally, creating a subcommand causes a `help` subcommand to automatically + /// // be generated as well + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", "help" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + DisableHelpSubcommand, + + /// Disables `-V` and `--version` [`App`] without affecting any of the [`SubCommand`]s + /// (Defaults to `false`; application *does* have a version flag) + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::DisableVersion) + /// .get_matches_from_safe(vec![ + /// "myprog", "-V" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// + /// ```rust + /// # use clap::{App, SubCommand, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::DisableVersion) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", "test", "-V" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::VersionDisplayed); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`App`]: ./struct.App.html + DisableVersion, + + /// Displays the arguments and [`SubCommand`]s in the help message in the order that they were + /// declared in, and not alphabetically which is the default. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::DeriveDisplayOrder) + /// .get_matches(); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + DeriveDisplayOrder, + + /// Specifies to use the version of the current command for all child [`SubCommand`]s. + /// (Defaults to `false`; subcommands have independent version strings from their parents.) + /// + /// **NOTE:** The version for the current command **and** this setting must be set **prior** to + /// adding any child subcommands + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::GlobalVersion) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches(); + /// // running `$ myprog test --version` will display + /// // "myprog-test v1.1" + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + GlobalVersion, + + /// Specifies that this [`SubCommand`] should be hidden from help messages + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings, SubCommand}; + /// App::new("myprog") + /// .subcommand(SubCommand::with_name("test") + /// .setting(AppSettings::Hidden)) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + Hidden, + + /// Tells `clap` *not* to print possible values when displaying help information. + /// This can be useful if there are many values, or they are explained elsewhere. + HidePossibleValuesInHelp, + + /// Tries to match unknown args to partial [`subcommands`] or their [aliases]. For example to + /// match a subcommand named `test`, one could use `t`, `te`, `tes`, and `test`. + /// + /// **NOTE:** The match *must not* be ambiguous at all in order to succeed. i.e. to match `te` + /// to `test` there could not also be a subcommand or alias `temp` because both start with `te` + /// + /// **CAUTION:** This setting can interfere with [positional/free arguments], take care when + /// designing CLIs which allow inferred subcommands and have potential positional/free + /// arguments whose values could start with the same characters as subcommands. If this is the + /// case, it's recommended to use settings such as [`AppSeettings::ArgsNegateSubcommands`] in + /// conjunction with this setting. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// let m = App::new("prog") + /// .setting(AppSettings::InferSubcommands) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from(vec![ + /// "prog", "te" + /// ]); + /// assert_eq!(m.subcommand_name(), Some("test")); + /// ``` + /// [`subcommands`]: ./struct.SubCommand.html + /// [positional/free arguments]: ./struct.Arg.html#method.index + /// [aliases]: ./struct.App.html#method.alias + /// [`AppSeettings::ArgsNegateSubcommands`]: ./enum.AppSettings.html#variant.ArgsNegateSubcommands + InferSubcommands, + + /// Specifies that the parser should not assume the first argument passed is the binary name. + /// This is normally the case when using a "daemon" style mode, or an interactive CLI where one + /// one would not normally type the binary or program name for each command. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// let m = App::new("myprog") + /// .setting(AppSettings::NoBinaryName) + /// .arg(Arg::from_usage("... 'commands to run'")) + /// .get_matches_from(vec!["command", "set"]); + /// + /// let cmds: Vec<&str> = m.values_of("cmd").unwrap().collect(); + /// assert_eq!(cmds, ["command", "set"]); + /// ``` + NoBinaryName, + + /// Places the help string for all arguments on the line after the argument. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::NextLineHelp) + /// .get_matches(); + /// ``` + NextLineHelp, + + /// **DEPRECATED**: This setting is no longer required in order to propagate values up or down + /// + /// Specifies that the parser should propagate global arg's values down or up through any *used* + /// child subcommands. Meaning, if a subcommand wasn't used, the values won't be propagated to + /// said subcommand. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings, SubCommand}; + /// let m = App::new("myprog") + /// .arg(Arg::from_usage("[cmd] 'command to run'") + /// .global(true)) + /// .subcommand(SubCommand::with_name("foo")) + /// .get_matches_from(vec!["myprog", "set", "foo"]); + /// + /// assert_eq!(m.value_of("cmd"), Some("set")); + /// + /// let sub_m = m.subcommand_matches("foo").unwrap(); + /// assert_eq!(sub_m.value_of("cmd"), Some("set")); + /// ``` + /// Now doing the same thing, but *not* using any subcommands will result in the value not being + /// propagated down. + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings, SubCommand}; + /// let m = App::new("myprog") + /// .arg(Arg::from_usage("[cmd] 'command to run'") + /// .global(true)) + /// .subcommand(SubCommand::with_name("foo")) + /// .get_matches_from(vec!["myprog", "set"]); + /// + /// assert_eq!(m.value_of("cmd"), Some("set")); + /// + /// assert!(m.subcommand_matches("foo").is_none()); + /// ``` + #[deprecated(since = "2.27.0", note = "No longer required to propagate values")] + PropagateGlobalValuesDown, + + /// Allows [`SubCommand`]s to override all requirements of the parent command. + /// For example if you had a subcommand or top level application with a required argument + /// that is only required as long as there is no subcommand present, + /// using this setting would allow you to set those arguments to [`Arg::required(true)`] + /// and yet receive no error so long as the user uses a valid subcommand instead. + /// + /// **NOTE:** This defaults to false (using subcommand does *not* negate requirements) + /// + /// # Examples + /// + /// This first example shows that it is an error to not use a required argument + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings, SubCommand, ErrorKind}; + /// let err = App::new("myprog") + /// .setting(AppSettings::SubcommandsNegateReqs) + /// .arg(Arg::with_name("opt").required(true)) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog" + /// ]); + /// assert!(err.is_err()); + /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// # ; + /// ``` + /// + /// This next example shows that it is no longer error to not use a required argument if a + /// valid subcommand is used. + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings, SubCommand, ErrorKind}; + /// let noerr = App::new("myprog") + /// .setting(AppSettings::SubcommandsNegateReqs) + /// .arg(Arg::with_name("opt").required(true)) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", "test" + /// ]); + /// assert!(noerr.is_ok()); + /// # ; + /// ``` + /// [`Arg::required(true)`]: ./struct.Arg.html#method.required + /// [`SubCommand`]: ./struct.SubCommand.html + SubcommandsNegateReqs, + + /// Specifies that the help text should be displayed (before exiting gracefully) if no + /// [`SubCommand`]s are present at runtime (i.e. an empty run such as `$ myprog`). + /// + /// **NOTE:** This should *not* be used with [`AppSettings::SubcommandRequired`] as they do + /// nearly same thing; this prints the help text, and the other prints an error. + /// + /// **NOTE:** If the user specifies arguments at runtime, but no subcommand the help text will + /// still be displayed and exit. If this is *not* the desired result, consider using + /// [`AppSettings::ArgRequiredElseHelp`] instead. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::SubcommandRequiredElseHelp) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings::SubcommandRequired`]: ./enum.AppSettings.html#variant.SubcommandRequired + /// [`AppSettings::ArgRequiredElseHelp`]: ./enum.AppSettings.html#variant.ArgRequiredElseHelp + SubcommandRequiredElseHelp, + + /// Specifies that any invalid UTF-8 code points should be treated as an error and fail + /// with a [`ErrorKind::InvalidUtf8`] error. + /// + /// **NOTE:** This rule only applies to argument values; Things such as flags, options, and + /// [`SubCommand`]s themselves only allow valid UTF-8 code points. + /// + /// # Platform Specific + /// + /// Non Windows systems only + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, AppSettings, ErrorKind}; + /// use std::ffi::OsString; + /// use std::os::unix::ffi::OsStringExt; + /// + /// let m = App::new("myprog") + /// .setting(AppSettings::StrictUtf8) + /// .arg_from_usage(" 'some positional arg'") + /// .get_matches_from_safe( + /// vec![ + /// OsString::from("myprog"), + /// OsString::from_vec(vec![0xe9])]); + /// + /// assert!(m.is_err()); + /// assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`ErrorKind::InvalidUtf8`]: ./enum.ErrorKind.html#variant.InvalidUtf8 + StrictUtf8, + + /// Allows specifying that if no [`SubCommand`] is present at runtime, + /// error and exit gracefully. + /// + /// **NOTE:** This defaults to `false` (subcommands do *not* need to be present) + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings, SubCommand, ErrorKind}; + /// let err = App::new("myprog") + /// .setting(AppSettings::SubcommandRequired) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", + /// ]); + /// assert!(err.is_err()); + /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingSubcommand); + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + SubcommandRequired, + + /// Specifies that the final positional argument is a "VarArg" and that `clap` should not + /// attempt to parse any further args. + /// + /// The values of the trailing positional argument will contain all args from itself on. + /// + /// **NOTE:** The final positional argument **must** have [`Arg::multiple(true)`] or the usage + /// string equivalent. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// let m = App::new("myprog") + /// .setting(AppSettings::TrailingVarArg) + /// .arg(Arg::from_usage("... 'commands to run'")) + /// .get_matches_from(vec!["myprog", "arg1", "-r", "val1"]); + /// + /// let trail: Vec<&str> = m.values_of("cmd").unwrap().collect(); + /// assert_eq!(trail, ["arg1", "-r", "val1"]); + /// ``` + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + TrailingVarArg, + + /// Groups flags and options together, presenting a more unified help message + /// (a la `getopts` or `docopt` style). + /// + /// The default is that the auto-generated help message will group flags, and options + /// separately. + /// + /// **NOTE:** This setting is cosmetic only and does not affect any functionality. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::UnifiedHelpMessage) + /// .get_matches(); + /// // running `myprog --help` will display a unified "docopt" or "getopts" style help message + /// ``` + UnifiedHelpMessage, + + /// Disables `-V` and `--version` for all [`SubCommand`]s + /// (Defaults to `false`; subcommands *do* have version flags.) + /// + /// **NOTE:** This setting must be set **prior** to adding any subcommands. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, SubCommand, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::VersionlessSubcommands) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", "test", "-V" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + VersionlessSubcommands, + + /// Will display a message "Press \[ENTER\]/\[RETURN\] to continue..." and wait for user before + /// exiting + /// + /// This is most useful when writing an application which is run from a GUI shortcut, or on + /// Windows where a user tries to open the binary by double-clicking instead of using the + /// command line. + /// + /// **NOTE:** This setting is **not** recursive with [`SubCommand`]s, meaning if you wish this + /// behavior for all subcommands, you must set this on each command (needing this is extremely + /// rare) + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::WaitOnError) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + WaitOnError, + + #[doc(hidden)] + NeedsLongVersion, + + #[doc(hidden)] + NeedsLongHelp, + + #[doc(hidden)] + NeedsSubcommandHelp, + + #[doc(hidden)] + LowIndexMultiplePositional, + + #[doc(hidden)] + TrailingValues, + + #[doc(hidden)] + ValidNegNumFound, + + #[doc(hidden)] + Propagated, + + #[doc(hidden)] + ValidArgFound, + + #[doc(hidden)] + ContainsLast, +} + +impl FromStr for AppSettings { + type Err = String; + fn from_str(s: &str) -> Result::Err> { + match &*s.to_ascii_lowercase() { + "disablehelpflags" => Ok(AppSettings::DisableHelpFlags), + "argrequiredelsehelp" => Ok(AppSettings::ArgRequiredElseHelp), + "argsnegatesubcommands" => Ok(AppSettings::ArgsNegateSubcommands), + "allowinvalidutf8" => Ok(AppSettings::AllowInvalidUtf8), + "allowleadinghyphen" => Ok(AppSettings::AllowLeadingHyphen), + "allowexternalsubcommands" => Ok(AppSettings::AllowExternalSubcommands), + "allownegativenumbers" => Ok(AppSettings::AllowNegativeNumbers), + "colorauto" => Ok(AppSettings::ColorAuto), + "coloralways" => Ok(AppSettings::ColorAlways), + "colornever" => Ok(AppSettings::ColorNever), + "coloredhelp" => Ok(AppSettings::ColoredHelp), + "derivedisplayorder" => Ok(AppSettings::DeriveDisplayOrder), + "dontcollapseargsinusage" => Ok(AppSettings::DontCollapseArgsInUsage), + "dontdelimittrailingvalues" => Ok(AppSettings::DontDelimitTrailingValues), + "disablehelpsubcommand" => Ok(AppSettings::DisableHelpSubcommand), + "disableversion" => Ok(AppSettings::DisableVersion), + "globalversion" => Ok(AppSettings::GlobalVersion), + "hidden" => Ok(AppSettings::Hidden), + "hidepossiblevaluesinhelp" => Ok(AppSettings::HidePossibleValuesInHelp), + "infersubcommands" => Ok(AppSettings::InferSubcommands), + "lowindexmultiplepositional" => Ok(AppSettings::LowIndexMultiplePositional), + "nobinaryname" => Ok(AppSettings::NoBinaryName), + "nextlinehelp" => Ok(AppSettings::NextLineHelp), + "strictutf8" => Ok(AppSettings::StrictUtf8), + "subcommandsnegatereqs" => Ok(AppSettings::SubcommandsNegateReqs), + "subcommandrequired" => Ok(AppSettings::SubcommandRequired), + "subcommandrequiredelsehelp" => Ok(AppSettings::SubcommandRequiredElseHelp), + "trailingvararg" => Ok(AppSettings::TrailingVarArg), + "unifiedhelpmessage" => Ok(AppSettings::UnifiedHelpMessage), + "versionlesssubcommands" => Ok(AppSettings::VersionlessSubcommands), + "waitonerror" => Ok(AppSettings::WaitOnError), + "validnegnumfound" => Ok(AppSettings::ValidNegNumFound), + "validargfound" => Ok(AppSettings::ValidArgFound), + "propagated" => Ok(AppSettings::Propagated), + "trailingvalues" => Ok(AppSettings::TrailingValues), + _ => Err("unknown AppSetting, cannot convert from str".to_owned()), + } + } +} + +#[cfg(test)] +mod test { + use super::AppSettings; + + #[test] + fn app_settings_fromstr() { + assert_eq!( + "disablehelpflags".parse::().unwrap(), + AppSettings::DisableHelpFlags + ); + assert_eq!( + "argsnegatesubcommands".parse::().unwrap(), + AppSettings::ArgsNegateSubcommands + ); + assert_eq!( + "argrequiredelsehelp".parse::().unwrap(), + AppSettings::ArgRequiredElseHelp + ); + assert_eq!( + "allowexternalsubcommands".parse::().unwrap(), + AppSettings::AllowExternalSubcommands + ); + assert_eq!( + "allowinvalidutf8".parse::().unwrap(), + AppSettings::AllowInvalidUtf8 + ); + assert_eq!( + "allowleadinghyphen".parse::().unwrap(), + AppSettings::AllowLeadingHyphen + ); + assert_eq!( + "allownegativenumbers".parse::().unwrap(), + AppSettings::AllowNegativeNumbers + ); + assert_eq!( + "coloredhelp".parse::().unwrap(), + AppSettings::ColoredHelp + ); + assert_eq!( + "colorauto".parse::().unwrap(), + AppSettings::ColorAuto + ); + assert_eq!( + "coloralways".parse::().unwrap(), + AppSettings::ColorAlways + ); + assert_eq!( + "colornever".parse::().unwrap(), + AppSettings::ColorNever + ); + assert_eq!( + "disablehelpsubcommand".parse::().unwrap(), + AppSettings::DisableHelpSubcommand + ); + assert_eq!( + "disableversion".parse::().unwrap(), + AppSettings::DisableVersion + ); + assert_eq!( + "dontcollapseargsinusage".parse::().unwrap(), + AppSettings::DontCollapseArgsInUsage + ); + assert_eq!( + "dontdelimittrailingvalues".parse::().unwrap(), + AppSettings::DontDelimitTrailingValues + ); + assert_eq!( + "derivedisplayorder".parse::().unwrap(), + AppSettings::DeriveDisplayOrder + ); + assert_eq!( + "globalversion".parse::().unwrap(), + AppSettings::GlobalVersion + ); + assert_eq!( + "hidden".parse::().unwrap(), + AppSettings::Hidden + ); + assert_eq!( + "hidepossiblevaluesinhelp".parse::().unwrap(), + AppSettings::HidePossibleValuesInHelp + ); + assert_eq!( + "lowindexmultiplePositional".parse::().unwrap(), + AppSettings::LowIndexMultiplePositional + ); + assert_eq!( + "nobinaryname".parse::().unwrap(), + AppSettings::NoBinaryName + ); + assert_eq!( + "nextlinehelp".parse::().unwrap(), + AppSettings::NextLineHelp + ); + assert_eq!( + "subcommandsnegatereqs".parse::().unwrap(), + AppSettings::SubcommandsNegateReqs + ); + assert_eq!( + "subcommandrequired".parse::().unwrap(), + AppSettings::SubcommandRequired + ); + assert_eq!( + "subcommandrequiredelsehelp".parse::().unwrap(), + AppSettings::SubcommandRequiredElseHelp + ); + assert_eq!( + "strictutf8".parse::().unwrap(), + AppSettings::StrictUtf8 + ); + assert_eq!( + "trailingvararg".parse::().unwrap(), + AppSettings::TrailingVarArg + ); + assert_eq!( + "unifiedhelpmessage".parse::().unwrap(), + AppSettings::UnifiedHelpMessage + ); + assert_eq!( + "versionlesssubcommands".parse::().unwrap(), + AppSettings::VersionlessSubcommands + ); + assert_eq!( + "waitonerror".parse::().unwrap(), + AppSettings::WaitOnError + ); + assert_eq!( + "validnegnumfound".parse::().unwrap(), + AppSettings::ValidNegNumFound + ); + assert_eq!( + "validargfound".parse::().unwrap(), + AppSettings::ValidArgFound + ); + assert_eq!( + "propagated".parse::().unwrap(), + AppSettings::Propagated + ); + assert_eq!( + "trailingvalues".parse::().unwrap(), + AppSettings::TrailingValues + ); + assert_eq!( + "infersubcommands".parse::().unwrap(), + AppSettings::InferSubcommands + ); + assert!("hahahaha".parse::().is_err()); + } +} diff --git a/vendor/clap-2.34.0/src/app/usage.rs b/vendor/clap-2.34.0/src/app/usage.rs new file mode 100644 index 0000000000000..e68f2f4b11494 --- /dev/null +++ b/vendor/clap-2.34.0/src/app/usage.rs @@ -0,0 +1,493 @@ +// std +use std::collections::{BTreeMap, VecDeque}; + +// Internal +use crate::{ + app::{parser::Parser, settings::AppSettings as AS}, + args::{settings::ArgSettings, AnyArg, ArgMatcher, PosBuilder}, + INTERNAL_ERROR_MSG, +}; + +// Creates a usage string for display. This happens just after all arguments were parsed, but before +// any subcommands have been parsed (so as to give subcommands their own usage recursively) +pub fn create_usage_with_title(p: &Parser, used: &[&str]) -> String { + debugln!("usage::create_usage_with_title;"); + let mut usage = String::with_capacity(75); + usage.push_str("USAGE:\n "); + usage.push_str(&*create_usage_no_title(p, used)); + usage +} + +// Creates a usage string to be used in error message (i.e. one with currently used args) +pub fn create_error_usage<'a, 'b>( + p: &Parser<'a, 'b>, + matcher: &'b ArgMatcher<'a>, + extra: Option<&str>, +) -> String { + let mut args: Vec<_> = matcher + .arg_names() + .iter() + .filter(|n| { + if let Some(o) = find_by_name!(p, **n, opts, iter) { + !o.b.is_set(ArgSettings::Required) && !o.b.is_set(ArgSettings::Hidden) + } else if let Some(p) = find_by_name!(p, **n, positionals, values) { + !p.b.is_set(ArgSettings::Required) && p.b.is_set(ArgSettings::Hidden) + } else { + true // flags can't be required, so they're always true + } + }) + .copied() + .collect(); + if let Some(r) = extra { + args.push(r); + } + create_usage_with_title(p, &*args) +} + +// Creates a usage string (*without title*) if one was not provided by the user manually. +pub fn create_usage_no_title(p: &Parser, used: &[&str]) -> String { + debugln!("usage::create_usage_no_title;"); + if let Some(u) = p.meta.usage_str { + String::from(&*u) + } else if used.is_empty() { + create_help_usage(p, true) + } else { + create_smart_usage(p, used) + } +} + +// Creates a usage string for display in help messages (i.e. not for errors) +pub fn create_help_usage(p: &Parser, incl_reqs: bool) -> String { + let mut usage = String::with_capacity(75); + let name = p + .meta + .usage + .as_ref() + .unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name)); + usage.push_str(&*name); + let req_string = if incl_reqs { + let mut reqs: Vec<&str> = p.required().map(|r| &**r).collect(); + reqs.sort_unstable(); + reqs.dedup(); + get_required_usage_from(p, &reqs, None, None, false) + .iter() + .fold(String::new(), |a, s| a + &format!(" {}", s)[..]) + } else { + String::new() + }; + + let flags = needs_flags_tag(p); + if flags && !p.is_set(AS::UnifiedHelpMessage) { + usage.push_str(" [FLAGS]"); + } else if flags { + usage.push_str(" [OPTIONS]"); + } + if !p.is_set(AS::UnifiedHelpMessage) + && p.opts + .iter() + .any(|o| !o.is_set(ArgSettings::Required) && !o.is_set(ArgSettings::Hidden)) + { + usage.push_str(" [OPTIONS]"); + } + + usage.push_str(&req_string[..]); + + let has_last = p.positionals.values().any(|p| p.is_set(ArgSettings::Last)); + // places a '--' in the usage string if there are args and options + // supporting multiple values + if p.opts.iter().any(|o| o.is_set(ArgSettings::Multiple)) + && p.positionals + .values() + .any(|p| !p.is_set(ArgSettings::Required)) + && !(p.has_visible_subcommands() || p.is_set(AS::AllowExternalSubcommands)) + && !has_last + { + usage.push_str(" [--]"); + } + let not_req_or_hidden = |p: &PosBuilder| { + (!p.is_set(ArgSettings::Required) || p.is_set(ArgSettings::Last)) + && !p.is_set(ArgSettings::Hidden) + }; + if p.has_positionals() && p.positionals.values().any(not_req_or_hidden) { + if let Some(args_tag) = get_args_tag(p, incl_reqs) { + usage.push_str(&*args_tag); + } else { + usage.push_str(" [ARGS]"); + } + if has_last && incl_reqs { + let pos = p + .positionals + .values() + .find(|p| p.b.is_set(ArgSettings::Last)) + .expect(INTERNAL_ERROR_MSG); + debugln!("usage::create_help_usage: '{}' has .last(true)", pos.name()); + let req = pos.is_set(ArgSettings::Required); + if req + && p.positionals + .values() + .any(|p| !p.is_set(ArgSettings::Required)) + { + usage.push_str(" -- <"); + } else if req { + usage.push_str(" [--] <"); + } else { + usage.push_str(" [-- <"); + } + usage.push_str(&*pos.name_no_brackets()); + usage.push('>'); + usage.push_str(pos.multiple_str()); + if !req { + usage.push(']'); + } + } + } + + // incl_reqs is only false when this function is called recursively + if p.has_visible_subcommands() && incl_reqs || p.is_set(AS::AllowExternalSubcommands) { + if p.is_set(AS::SubcommandsNegateReqs) || p.is_set(AS::ArgsNegateSubcommands) { + usage.push_str("\n "); + if !p.is_set(AS::ArgsNegateSubcommands) { + usage.push_str(&*create_help_usage(p, false)); + } else { + usage.push_str(&*name); + } + usage.push_str(" "); + } else if p.is_set(AS::SubcommandRequired) || p.is_set(AS::SubcommandRequiredElseHelp) { + usage.push_str(" "); + } else { + usage.push_str(" [SUBCOMMAND]"); + } + } + usage.shrink_to_fit(); + debugln!("usage::create_help_usage: usage={}", usage); + usage +} + +// Creates a context aware usage string, or "smart usage" from currently used +// args, and requirements +fn create_smart_usage(p: &Parser, used: &[&str]) -> String { + debugln!("usage::smart_usage;"); + let mut usage = String::with_capacity(75); + let mut hs: Vec<&str> = p.required().map(|s| &**s).collect(); + hs.extend_from_slice(used); + + let r_string = get_required_usage_from(p, &hs, None, None, false) + .iter() + .fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]); + + usage.push_str( + &p.meta + .usage + .as_ref() + .unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name))[..], + ); + usage.push_str(&*r_string); + if p.is_set(AS::SubcommandRequired) { + usage.push_str(" "); + } + usage.shrink_to_fit(); + usage +} + +// Gets the `[ARGS]` tag for the usage string +fn get_args_tag(p: &Parser, incl_reqs: bool) -> Option { + debugln!("usage::get_args_tag;"); + let mut count = 0; + 'outer: for pos in p + .positionals + .values() + .filter(|pos| !pos.is_set(ArgSettings::Required)) + .filter(|pos| !pos.is_set(ArgSettings::Hidden)) + .filter(|pos| !pos.is_set(ArgSettings::Last)) + { + debugln!("usage::get_args_tag:iter:{}:", pos.b.name); + if let Some(g_vec) = p.groups_for_arg(pos.b.name) { + for grp_s in &g_vec { + debugln!("usage::get_args_tag:iter:{}:iter:{};", pos.b.name, grp_s); + // if it's part of a required group we don't want to count it + if p.groups.iter().any(|g| g.required && (&g.name == grp_s)) { + continue 'outer; + } + } + } + count += 1; + debugln!( + "usage::get_args_tag:iter: {} Args not required or hidden", + count + ); + } + if !p.is_set(AS::DontCollapseArgsInUsage) && count > 1 { + debugln!("usage::get_args_tag:iter: More than one, returning [ARGS]"); + return None; // [ARGS] + } else if count == 1 && incl_reqs { + let pos = p + .positionals + .values() + .find(|pos| { + !pos.is_set(ArgSettings::Required) + && !pos.is_set(ArgSettings::Hidden) + && !pos.is_set(ArgSettings::Last) + }) + .expect(INTERNAL_ERROR_MSG); + debugln!( + "usage::get_args_tag:iter: Exactly one, returning '{}'", + pos.name() + ); + return Some(format!( + " [{}]{}", + pos.name_no_brackets(), + pos.multiple_str() + )); + } else if p.is_set(AS::DontCollapseArgsInUsage) && !p.positionals.is_empty() && incl_reqs { + debugln!("usage::get_args_tag:iter: Don't collapse returning all"); + return Some( + p.positionals + .values() + .filter(|pos| !pos.is_set(ArgSettings::Required)) + .filter(|pos| !pos.is_set(ArgSettings::Hidden)) + .filter(|pos| !pos.is_set(ArgSettings::Last)) + .map(|pos| format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())) + .collect::>() + .join(""), + ); + } else if !incl_reqs { + debugln!("usage::get_args_tag:iter: incl_reqs=false, building secondary usage string"); + let highest_req_pos = p + .positionals + .iter() + .filter_map(|(idx, pos)| { + if pos.b.is_set(ArgSettings::Required) && !pos.b.is_set(ArgSettings::Last) { + Some(idx) + } else { + None + } + }) + .max() + .unwrap_or_else(|| p.positionals.len()); + return Some( + p.positionals + .iter() + .filter_map(|(idx, pos)| { + if idx <= highest_req_pos { + Some(pos) + } else { + None + } + }) + .filter(|pos| !pos.is_set(ArgSettings::Required)) + .filter(|pos| !pos.is_set(ArgSettings::Hidden)) + .filter(|pos| !pos.is_set(ArgSettings::Last)) + .map(|pos| format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())) + .collect::>() + .join(""), + ); + } + Some("".into()) +} + +// Determines if we need the `[FLAGS]` tag in the usage string +fn needs_flags_tag(p: &Parser) -> bool { + debugln!("usage::needs_flags_tag;"); + 'outer: for f in &p.flags { + debugln!("usage::needs_flags_tag:iter: f={};", f.b.name); + if let Some(l) = f.s.long { + if l == "help" || l == "version" { + // Don't print `[FLAGS]` just for help or version + continue; + } + } + if let Some(g_vec) = p.groups_for_arg(f.b.name) { + for grp_s in &g_vec { + debugln!("usage::needs_flags_tag:iter:iter: grp_s={};", grp_s); + if p.groups.iter().any(|g| &g.name == grp_s && g.required) { + debugln!("usage::needs_flags_tag:iter:iter: Group is required"); + continue 'outer; + } + } + } + if f.is_set(ArgSettings::Hidden) { + continue; + } + debugln!("usage::needs_flags_tag:iter: [FLAGS] required"); + return true; + } + + debugln!("usage::needs_flags_tag: [FLAGS] not required"); + false +} + +// Returns the required args in usage string form by fully unrolling all groups +pub fn get_required_usage_from<'a, 'b>( + p: &Parser<'a, 'b>, + reqs: &[&'a str], + matcher: Option<&ArgMatcher<'a>>, + extra: Option<&str>, + incl_last: bool, +) -> VecDeque { + debugln!( + "usage::get_required_usage_from: reqs={:?}, extra={:?}", + reqs, + extra + ); + let mut desc_reqs: Vec<&str> = vec![]; + desc_reqs.extend(extra); + let mut new_reqs: Vec<&str> = vec![]; + macro_rules! get_requires { + (@group $a: ident, $v:ident, $p:ident) => {{ + if let Some(rl) = p + .groups + .iter() + .filter(|g| g.requires.is_some()) + .find(|g| &g.name == $a) + .map(|g| g.requires.as_ref().unwrap()) + { + for r in rl { + if !$p.contains(&r) { + debugln!( + "usage::get_required_usage_from:iter:{}: adding group req={:?}", + $a, + r + ); + $v.push(r); + } + } + } + }}; + ($a:ident, $what:ident, $how:ident, $v:ident, $p:ident) => {{ + if let Some(rl) = p + .$what + .$how() + .filter(|a| a.b.requires.is_some()) + .find(|arg| &arg.b.name == $a) + .map(|a| a.b.requires.as_ref().unwrap()) + { + for &(_, r) in rl.iter() { + if !$p.contains(&r) { + debugln!( + "usage::get_required_usage_from:iter:{}: adding arg req={:?}", + $a, + r + ); + $v.push(r); + } + } + } + }}; + } + // initialize new_reqs + for a in reqs { + get_requires!(a, flags, iter, new_reqs, reqs); + get_requires!(a, opts, iter, new_reqs, reqs); + get_requires!(a, positionals, values, new_reqs, reqs); + get_requires!(@group a, new_reqs, reqs); + } + desc_reqs.extend_from_slice(&*new_reqs); + debugln!( + "usage::get_required_usage_from: after init desc_reqs={:?}", + desc_reqs + ); + loop { + let mut tmp = vec![]; + for a in &new_reqs { + get_requires!(a, flags, iter, tmp, desc_reqs); + get_requires!(a, opts, iter, tmp, desc_reqs); + get_requires!(a, positionals, values, tmp, desc_reqs); + get_requires!(@group a, tmp, desc_reqs); + } + if tmp.is_empty() { + debugln!("usage::get_required_usage_from: no more children"); + break; + } else { + debugln!("usage::get_required_usage_from: after iter tmp={:?}", tmp); + debugln!( + "usage::get_required_usage_from: after iter new_reqs={:?}", + new_reqs + ); + desc_reqs.extend_from_slice(&*new_reqs); + new_reqs.clear(); + new_reqs.extend_from_slice(&*tmp); + debugln!( + "usage::get_required_usage_from: after iter desc_reqs={:?}", + desc_reqs + ); + } + } + desc_reqs.extend_from_slice(reqs); + desc_reqs.sort_unstable(); + desc_reqs.dedup(); + debugln!( + "usage::get_required_usage_from: final desc_reqs={:?}", + desc_reqs + ); + let mut ret_val = VecDeque::new(); + let args_in_groups = p + .groups + .iter() + .filter(|gn| desc_reqs.contains(&gn.name)) + .flat_map(|g| p.arg_names_in_group(g.name)) + .collect::>(); + + let pmap = if let Some(m) = matcher { + desc_reqs + .iter() + .filter(|a| p.positionals.values().any(|p| &&p.b.name == a)) + .filter(|&pos| !m.contains(pos)) + .filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos)) + .filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last)) + .filter(|pos| !args_in_groups.contains(&pos.b.name)) + .map(|pos| (pos.index, pos)) + .collect::>() // sort by index + } else { + desc_reqs + .iter() + .filter(|a| p.positionals.values().any(|pos| &&pos.b.name == a)) + .filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos)) + .filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last)) + .filter(|pos| !args_in_groups.contains(&pos.b.name)) + .map(|pos| (pos.index, pos)) + .collect::>() // sort by index + }; + debugln!( + "usage::get_required_usage_from: args_in_groups={:?}", + args_in_groups + ); + for &p in pmap.values() { + let s = p.to_string(); + if args_in_groups.is_empty() || !args_in_groups.contains(&&*s) { + ret_val.push_back(s); + } + } + for a in desc_reqs + .iter() + .filter(|name| !p.positionals.values().any(|p| &&p.b.name == name)) + .filter(|name| !p.groups.iter().any(|g| &&g.name == name)) + .filter(|name| !args_in_groups.contains(name)) + .filter(|name| !(matcher.is_some() && matcher.as_ref().unwrap().contains(name))) + { + debugln!("usage::get_required_usage_from:iter:{}:", a); + let arg = find_by_name!(p, *a, flags, iter) + .map(|f| f.to_string()) + .unwrap_or_else(|| { + find_by_name!(p, *a, opts, iter) + .map(|o| o.to_string()) + .expect(INTERNAL_ERROR_MSG) + }); + ret_val.push_back(arg); + } + let mut g_vec: Vec = vec![]; + for g in desc_reqs + .iter() + .filter(|n| p.groups.iter().any(|g| &&g.name == n)) + { + let g_string = p.args_in_group(g).join("|"); + let elem = format!("<{}>", &g_string[..g_string.len()]); + if !g_vec.contains(&elem) { + g_vec.push(elem); + } + } + for g in g_vec { + ret_val.push_back(g); + } + + ret_val +} diff --git a/vendor/clap-2.34.0/src/app/validator.rs b/vendor/clap-2.34.0/src/app/validator.rs new file mode 100644 index 0000000000000..1deb67d860b72 --- /dev/null +++ b/vendor/clap-2.34.0/src/app/validator.rs @@ -0,0 +1,584 @@ +// std +#[allow(deprecated, unused_imports)] +use std::{ascii::AsciiExt, fmt::Display}; + +// Internal +use crate::{ + app::{ + parser::{ParseResult, Parser}, + settings::AppSettings as AS, + usage, + }, + args::{settings::ArgSettings, AnyArg, ArgMatcher, MatchedArg}, + errors::{Error, ErrorKind, Result as ClapResult}, + fmt::{Colorizer, ColorizerOption}, + INTERNAL_ERROR_MSG, INVALID_UTF8, +}; + +pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>) +where + 'a: 'b, + 'b: 'z; + +impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { + pub fn new(p: &'z mut Parser<'a, 'b>) -> Self { + Validator(p) + } + + pub fn validate( + &mut self, + needs_val_of: ParseResult<'a>, + subcmd_name: Option, + matcher: &mut ArgMatcher<'a>, + ) -> ClapResult<()> { + debugln!("Validator::validate;"); + let mut reqs_validated = false; + self.0.add_env(matcher)?; + self.0.add_defaults(matcher)?; + if let ParseResult::Opt(a) = needs_val_of { + debugln!("Validator::validate: needs_val_of={:?}", a); + let o = { + self.0 + .opts + .iter() + .find(|o| o.b.name == a) + .expect(INTERNAL_ERROR_MSG) + .clone() + }; + self.validate_required(matcher)?; + reqs_validated = true; + let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) { + v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0) + } else { + true + }; + if should_err { + return Err(Error::empty_value( + &o, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + } + + if matcher.is_empty() + && matcher.subcommand_name().is_none() + && self.0.is_set(AS::ArgRequiredElseHelp) + { + let mut out = vec![]; + self.0.write_help_err(&mut out)?; + return Err(Error { + message: String::from_utf8_lossy(&*out).into_owned(), + kind: ErrorKind::MissingArgumentOrSubcommand, + info: None, + }); + } + self.validate_blacklist(matcher)?; + if !(reqs_validated || self.0.is_set(AS::SubcommandsNegateReqs) && subcmd_name.is_some()) { + self.validate_required(matcher)?; + } + self.validate_matched_args(matcher)?; + matcher.usage(usage::create_usage_with_title(self.0, &[])); + + Ok(()) + } + + fn validate_arg_values( + &self, + arg: &A, + ma: &MatchedArg, + matcher: &ArgMatcher<'a>, + ) -> ClapResult<()> + where + A: AnyArg<'a, 'b> + Display, + { + debugln!("Validator::validate_arg_values: arg={:?}", arg.name()); + for val in &ma.vals { + if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() { + debugln!( + "Validator::validate_arg_values: invalid UTF-8 found in val {:?}", + val + ); + return Err(Error::invalid_utf8( + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + if let Some(p_vals) = arg.possible_vals() { + debugln!("Validator::validate_arg_values: possible_vals={:?}", p_vals); + let val_str = val.to_string_lossy(); + let ok = if arg.is_set(ArgSettings::CaseInsensitive) { + p_vals.iter().any(|pv| pv.eq_ignore_ascii_case(&*val_str)) + } else { + p_vals.contains(&&*val_str) + }; + if !ok { + return Err(Error::invalid_value( + val_str, + p_vals, + arg, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + } + if !arg.is_set(ArgSettings::EmptyValues) + && val.is_empty() + && matcher.contains(&*arg.name()) + { + debugln!("Validator::validate_arg_values: illegal empty val found"); + return Err(Error::empty_value( + arg, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + if let Some(vtor) = arg.validator() { + debug!("Validator::validate_arg_values: checking validator..."); + if let Err(e) = vtor(val.to_string_lossy().into_owned()) { + sdebugln!("error"); + return Err(Error::value_validation(Some(arg), e, self.0.color())); + } else { + sdebugln!("good"); + } + } + if let Some(vtor) = arg.validator_os() { + debug!("Validator::validate_arg_values: checking validator_os..."); + if let Err(e) = vtor(val) { + sdebugln!("error"); + return Err(Error::value_validation( + Some(arg), + (*e).to_string_lossy().to_string(), + self.0.color(), + )); + } else { + sdebugln!("good"); + } + } + } + Ok(()) + } + + fn build_err(&self, name: &str, matcher: &ArgMatcher) -> ClapResult<()> { + debugln!("build_err!: name={}", name); + let mut c_with = find_from!(self.0, &name, blacklist, matcher); + c_with = c_with.or_else(|| { + self.0 + .find_any_arg(name) + .and_then(|aa| aa.blacklist()) + .and_then(|bl| bl.iter().find(|arg| matcher.contains(arg))) + .and_then(|an| self.0.find_any_arg(an)) + .map(|aa| format!("{}", aa)) + }); + debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name); + // matcher.remove(&name); + let usg = usage::create_error_usage(self.0, matcher, None); + if let Some(f) = find_by_name!(self.0, name, flags, iter) { + debugln!("build_err!: It was a flag..."); + Err(Error::argument_conflict(f, c_with, &*usg, self.0.color())) + } else if let Some(o) = find_by_name!(self.0, name, opts, iter) { + debugln!("build_err!: It was an option..."); + Err(Error::argument_conflict(o, c_with, &*usg, self.0.color())) + } else { + match find_by_name!(self.0, name, positionals, values) { + Some(p) => { + debugln!("build_err!: It was a positional..."); + Err(Error::argument_conflict(p, c_with, &*usg, self.0.color())) + } + None => panic!("{}", INTERNAL_ERROR_MSG), + } + } + } + + fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> { + debugln!("Validator::validate_blacklist;"); + let mut conflicts: Vec<&str> = vec![]; + for (&name, _) in matcher.iter() { + debugln!("Validator::validate_blacklist:iter:{};", name); + if let Some(grps) = self.0.groups_for_arg(name) { + for grp in &grps { + if let Some(g) = self.0.groups.iter().find(|g| &g.name == grp) { + if !g.multiple { + for arg in &g.args { + if arg == &name { + continue; + } + conflicts.push(arg); + } + } + if let Some(ref gc) = g.conflicts { + conflicts.extend(&*gc); + } + } + } + } + if let Some(arg) = find_any_by_name!(self.0, name) { + if let Some(bl) = arg.blacklist() { + for conf in bl { + if matcher.get(conf).is_some() { + conflicts.push(conf); + } + } + } + } else { + debugln!("Validator::validate_blacklist:iter:{}:group;", name); + let args = self.0.arg_names_in_group(name); + for arg in &args { + debugln!( + "Validator::validate_blacklist:iter:{}:group:iter:{};", + name, + arg + ); + if let Some(bl) = find_any_by_name!(self.0, *arg).unwrap().blacklist() { + for conf in bl { + if matcher.get(conf).is_some() { + conflicts.push(conf); + } + } + } + } + } + } + + for name in &conflicts { + debugln!( + "Validator::validate_blacklist:iter:{}: Checking blacklisted arg", + name + ); + let mut should_err = false; + if self.0.groups.iter().any(|g| &g.name == name) { + debugln!( + "Validator::validate_blacklist:iter:{}: groups contains it...", + name + ); + for n in self.0.arg_names_in_group(name) { + debugln!( + "Validator::validate_blacklist:iter:{}:iter:{}: looking in group...", + name, + n + ); + if matcher.contains(n) { + debugln!( + "Validator::validate_blacklist:iter:{}:iter:{}: matcher contains it...", + name, + n + ); + return self.build_err(n, matcher); + } + } + } else if let Some(ma) = matcher.get(name) { + debugln!( + "Validator::validate_blacklist:iter:{}: matcher contains it...", + name + ); + should_err = ma.occurs > 0; + } + if should_err { + return self.build_err(*name, matcher); + } + } + Ok(()) + } + + fn validate_matched_args(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { + debugln!("Validator::validate_matched_args;"); + for (name, ma) in matcher.iter() { + debugln!( + "Validator::validate_matched_args:iter:{}: vals={:#?}", + name, + ma.vals + ); + if let Some(opt) = find_by_name!(self.0, *name, opts, iter) { + self.validate_arg_num_vals(opt, ma, matcher)?; + self.validate_arg_values(opt, ma, matcher)?; + self.validate_arg_requires(opt, ma, matcher)?; + self.validate_arg_num_occurs(opt, ma, matcher)?; + } else if let Some(flag) = find_by_name!(self.0, *name, flags, iter) { + self.validate_arg_requires(flag, ma, matcher)?; + self.validate_arg_num_occurs(flag, ma, matcher)?; + } else if let Some(pos) = find_by_name!(self.0, *name, positionals, values) { + self.validate_arg_num_vals(pos, ma, matcher)?; + self.validate_arg_num_occurs(pos, ma, matcher)?; + self.validate_arg_values(pos, ma, matcher)?; + self.validate_arg_requires(pos, ma, matcher)?; + } else { + let grp = self + .0 + .groups + .iter() + .find(|g| &g.name == name) + .expect(INTERNAL_ERROR_MSG); + if let Some(ref g_reqs) = grp.requires { + if g_reqs.iter().any(|&n| !matcher.contains(n)) { + return self.missing_required_error(matcher, None); + } + } + } + } + Ok(()) + } + + fn validate_arg_num_occurs( + &self, + a: &A, + ma: &MatchedArg, + matcher: &ArgMatcher, + ) -> ClapResult<()> + where + A: AnyArg<'a, 'b> + Display, + { + debugln!("Validator::validate_arg_num_occurs: a={};", a.name()); + if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) { + // Not the first time, and we don't allow multiples + return Err(Error::unexpected_multiple_usage( + a, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + Ok(()) + } + + fn validate_arg_num_vals( + &self, + a: &A, + ma: &MatchedArg, + matcher: &ArgMatcher, + ) -> ClapResult<()> + where + A: AnyArg<'a, 'b> + Display, + { + debugln!("Validator::validate_arg_num_vals:{}", a.name()); + if let Some(num) = a.num_vals() { + debugln!("Validator::validate_arg_num_vals: num_vals set...{}", num); + let should_err = if a.is_set(ArgSettings::Multiple) { + ((ma.vals.len() as u64) % num) != 0 + } else { + num != (ma.vals.len() as u64) + }; + if should_err { + debugln!("Validator::validate_arg_num_vals: Sending error WrongNumberOfValues"); + return Err(Error::wrong_number_of_values( + a, + num, + if a.is_set(ArgSettings::Multiple) { + ma.vals.len() % num as usize + } else { + ma.vals.len() + }, + if ma.vals.len() == 1 + || (a.is_set(ArgSettings::Multiple) && (ma.vals.len() % num as usize) == 1) + { + "as" + } else { + "ere" + }, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + } + if let Some(num) = a.max_vals() { + debugln!("Validator::validate_arg_num_vals: max_vals set...{}", num); + if (ma.vals.len() as u64) > num { + debugln!("Validator::validate_arg_num_vals: Sending error TooManyValues"); + return Err(Error::too_many_values( + ma.vals + .iter() + .last() + .expect(INTERNAL_ERROR_MSG) + .to_str() + .expect(INVALID_UTF8), + a, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + } + let min_vals_zero = if let Some(num) = a.min_vals() { + debugln!("Validator::validate_arg_num_vals: min_vals set: {}", num); + if (ma.vals.len() as u64) < num && num != 0 { + debugln!("Validator::validate_arg_num_vals: Sending error TooFewValues"); + return Err(Error::too_few_values( + a, + num, + ma.vals.len(), + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + num == 0 + } else { + false + }; + // Issue 665 (https://github.com/clap-rs/clap/issues/665) + // Issue 1105 (https://github.com/clap-rs/clap/issues/1105) + if a.takes_value() && !min_vals_zero && ma.vals.is_empty() { + return Err(Error::empty_value( + a, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + Ok(()) + } + + fn validate_arg_requires( + &self, + a: &A, + ma: &MatchedArg, + matcher: &ArgMatcher, + ) -> ClapResult<()> + where + A: AnyArg<'a, 'b> + Display, + { + debugln!("Validator::validate_arg_requires:{};", a.name()); + if let Some(a_reqs) = a.requires() { + for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) { + let missing_req = + |v| v == val.expect(INTERNAL_ERROR_MSG) && !matcher.contains(name); + if ma.vals.iter().any(missing_req) { + return self.missing_required_error(matcher, None); + } + } + for &(_, name) in a_reqs.iter().filter(|&&(val, _)| val.is_none()) { + if !matcher.contains(name) { + return self.missing_required_error(matcher, Some(name)); + } + } + } + Ok(()) + } + + fn validate_required(&mut self, matcher: &ArgMatcher) -> ClapResult<()> { + debugln!( + "Validator::validate_required: required={:?};", + self.0.required + ); + + let mut should_err = false; + let mut to_rem = Vec::new(); + for name in &self.0.required { + debugln!("Validator::validate_required:iter:{}:", name); + if matcher.contains(name) { + continue; + } + if to_rem.contains(name) { + continue; + } else if let Some(a) = find_any_by_name!(self.0, *name) { + if self.is_missing_required_ok(a, matcher) { + to_rem.push(a.name()); + if let Some(reqs) = a.requires() { + for r in reqs + .iter() + .filter(|&&(val, _)| val.is_none()) + .map(|&(_, name)| name) + { + to_rem.push(r); + } + } + continue; + } + } + should_err = true; + break; + } + if should_err { + for r in &to_rem { + 'inner: for i in (0..self.0.required.len()).rev() { + if &self.0.required[i] == r { + self.0.required.swap_remove(i); + break 'inner; + } + } + } + return self.missing_required_error(matcher, None); + } + + // Validate the conditionally required args + for &(a, v, r) in &self.0.r_ifs { + if let Some(ma) = matcher.get(a) { + if matcher.get(r).is_none() && ma.vals.iter().any(|val| val == v) { + return self.missing_required_error(matcher, Some(r)); + } + } + } + Ok(()) + } + + fn validate_arg_conflicts(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option { + debugln!("Validator::validate_arg_conflicts: a={:?};", a.name()); + a.blacklist().map(|bl| { + bl.iter().any(|conf| { + matcher.contains(conf) + || self + .0 + .groups + .iter() + .find(|g| &g.name == conf) + .map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg))) + }) + }) + } + + fn validate_required_unless(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option { + debugln!("Validator::validate_required_unless: a={:?};", a.name()); + macro_rules! check { + ($how:ident, $_self:expr, $a:ident, $m:ident) => {{ + $a.required_unless().map(|ru| { + ru.iter().$how(|n| { + $m.contains(n) || { + if let Some(grp) = $_self.groups.iter().find(|g| &g.name == n) { + grp.args.iter().any(|arg| $m.contains(arg)) + } else { + false + } + } + }) + }) + }}; + } + if a.is_set(ArgSettings::RequiredUnlessAll) { + check!(all, self.0, a, matcher) + } else { + check!(any, self.0, a, matcher) + } + } + + fn missing_required_error(&self, matcher: &ArgMatcher, extra: Option<&str>) -> ClapResult<()> { + debugln!("Validator::missing_required_error: extra={:?}", extra); + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: self.0.color(), + }); + let mut reqs = self.0.required.iter().map(|&r| &*r).collect::>(); + if let Some(r) = extra { + reqs.push(r); + } + reqs.retain(|n| !matcher.contains(n)); + reqs.dedup(); + debugln!("Validator::missing_required_error: reqs={:#?}", reqs); + let req_args = + usage::get_required_usage_from(self.0, &reqs[..], Some(matcher), extra, true) + .iter() + .fold(String::new(), |acc, s| { + acc + &format!("\n {}", c.error(s))[..] + }); + debugln!( + "Validator::missing_required_error: req_args={:#?}", + req_args + ); + Err(Error::missing_required_argument( + &*req_args, + &*usage::create_error_usage(self.0, matcher, extra), + self.0.color(), + )) + } + + #[inline] + fn is_missing_required_ok(&self, a: &AnyArg, matcher: &ArgMatcher) -> bool { + debugln!("Validator::is_missing_required_ok: a={}", a.name()); + self.validate_arg_conflicts(a, matcher).unwrap_or(false) + || self.validate_required_unless(a, matcher).unwrap_or(false) + } +} diff --git a/vendor/clap-2.34.0/src/args/any_arg.rs b/vendor/clap-2.34.0/src/args/any_arg.rs new file mode 100644 index 0000000000000..b1c3a6a425389 --- /dev/null +++ b/vendor/clap-2.34.0/src/args/any_arg.rs @@ -0,0 +1,139 @@ +// Std +use std::{ + ffi::{OsStr, OsString}, + fmt as std_fmt, + rc::Rc, +}; + +// Internal +use crate::{ + args::settings::ArgSettings, + map::{self, VecMap}, + INTERNAL_ERROR_MSG, +}; + +#[doc(hidden)] +pub trait AnyArg<'n, 'e>: std_fmt::Display { + fn name(&self) -> &'n str; + fn overrides(&self) -> Option<&[&'e str]>; + fn aliases(&self) -> Option>; + fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]>; + fn blacklist(&self) -> Option<&[&'e str]>; + fn required_unless(&self) -> Option<&[&'e str]>; + fn is_set(&self, setting: ArgSettings) -> bool; + fn set(&mut self, setting: ArgSettings); + fn has_switch(&self) -> bool; + fn max_vals(&self) -> Option; + fn min_vals(&self) -> Option; + fn num_vals(&self) -> Option; + fn possible_vals(&self) -> Option<&[&'e str]>; + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + fn validator(&self) -> Option<&Rc Result<(), String>>>; + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + fn validator_os(&self) -> Option<&Rc Result<(), OsString>>>; + fn short(&self) -> Option; + fn long(&self) -> Option<&'e str>; + fn val_delim(&self) -> Option; + fn takes_value(&self) -> bool; + fn val_names(&self) -> Option<&VecMap<&'e str>>; + fn help(&self) -> Option<&'e str>; + fn long_help(&self) -> Option<&'e str>; + fn default_val(&self) -> Option<&'e OsStr>; + fn default_vals_ifs(&self) -> Option, &'e OsStr)>>; + fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)>; + fn longest_filter(&self) -> bool; + fn val_terminator(&self) -> Option<&'e str>; +} + +pub trait DispOrder { + fn disp_ord(&self) -> usize; +} + +impl<'n, 'e, 'z, T: ?Sized> AnyArg<'n, 'e> for &'z T +where + T: AnyArg<'n, 'e> + 'z, +{ + fn name(&self) -> &'n str { + (*self).name() + } + fn overrides(&self) -> Option<&[&'e str]> { + (*self).overrides() + } + fn aliases(&self) -> Option> { + (*self).aliases() + } + fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { + (*self).requires() + } + fn blacklist(&self) -> Option<&[&'e str]> { + (*self).blacklist() + } + fn required_unless(&self) -> Option<&[&'e str]> { + (*self).required_unless() + } + fn is_set(&self, a: ArgSettings) -> bool { + (*self).is_set(a) + } + fn set(&mut self, _: ArgSettings) { + panic!("{}", INTERNAL_ERROR_MSG) + } + fn has_switch(&self) -> bool { + (*self).has_switch() + } + fn max_vals(&self) -> Option { + (*self).max_vals() + } + fn min_vals(&self) -> Option { + (*self).min_vals() + } + fn num_vals(&self) -> Option { + (*self).num_vals() + } + fn possible_vals(&self) -> Option<&[&'e str]> { + (*self).possible_vals() + } + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + fn validator(&self) -> Option<&Rc Result<(), String>>> { + (*self).validator() + } + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + fn validator_os(&self) -> Option<&Rc Result<(), OsString>>> { + (*self).validator_os() + } + fn short(&self) -> Option { + (*self).short() + } + fn long(&self) -> Option<&'e str> { + (*self).long() + } + fn val_delim(&self) -> Option { + (*self).val_delim() + } + fn takes_value(&self) -> bool { + (*self).takes_value() + } + fn val_names(&self) -> Option<&VecMap<&'e str>> { + (*self).val_names() + } + fn help(&self) -> Option<&'e str> { + (*self).help() + } + fn long_help(&self) -> Option<&'e str> { + (*self).long_help() + } + fn default_val(&self) -> Option<&'e OsStr> { + (*self).default_val() + } + fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { + (*self).default_vals_ifs() + } + fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { + (*self).env() + } + fn longest_filter(&self) -> bool { + (*self).longest_filter() + } + fn val_terminator(&self) -> Option<&'e str> { + (*self).val_terminator() + } +} diff --git a/vendor/clap-2.34.0/src/args/arg.rs b/vendor/clap-2.34.0/src/args/arg.rs new file mode 100644 index 0000000000000..27db8ee11700b --- /dev/null +++ b/vendor/clap-2.34.0/src/args/arg.rs @@ -0,0 +1,3961 @@ +#[cfg(feature = "yaml")] +use std::collections::BTreeMap; +#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))] +use std::os::unix::ffi::OsStrExt; +use std::{ + env, + ffi::{OsStr, OsString}, + rc::Rc, +}; + +#[cfg(feature = "yaml")] +use yaml_rust::Yaml; + +#[cfg(any(target_os = "windows", target_arch = "wasm32"))] +use crate::osstringext::OsStrExt3; +use crate::{ + args::{ + arg_builder::{Base, Switched, Valued}, + settings::ArgSettings, + }, + map::VecMap, + usage_parser::UsageParser, +}; + +/// The abstract representation of a command line argument. Used to set all the options and +/// relationships that define a valid argument for the program. +/// +/// There are two methods for constructing [`Arg`]s, using the builder pattern and setting options +/// manually, or using a usage string which is far less verbose but has fewer options. You can also +/// use a combination of the two methods to achieve the best of both worlds. +/// +/// # Examples +/// +/// ```rust +/// # use clap::Arg; +/// // Using the traditional builder pattern and setting each option manually +/// let cfg = Arg::with_name("config") +/// .short("c") +/// .long("config") +/// .takes_value(true) +/// .value_name("FILE") +/// .help("Provides a config file to myprog"); +/// // Using a usage string (setting a similar argument to the one above) +/// let input = Arg::from_usage("-i, --input=[FILE] 'Provides an input file to the program'"); +/// ``` +/// [`Arg`]: ./struct.Arg.html +#[allow(missing_debug_implementations)] +#[derive(Default, Clone)] +pub struct Arg<'a, 'b> +where + 'a: 'b, +{ + #[doc(hidden)] + pub b: Base<'a, 'b>, + #[doc(hidden)] + pub s: Switched<'b>, + #[doc(hidden)] + pub v: Valued<'a, 'b>, + #[doc(hidden)] + pub index: Option, + #[doc(hidden)] + pub r_ifs: Option>, +} + +impl<'a, 'b> Arg<'a, 'b> { + /// Creates a new instance of [`Arg`] using a unique string name. The name will be used to get + /// information about whether or not the argument was used at runtime, get values, set + /// relationships with other args, etc.. + /// + /// **NOTE:** In the case of arguments that take values (i.e. [`Arg::takes_value(true)`]) + /// and positional arguments (i.e. those without a preceding `-` or `--`) the name will also + /// be displayed when the user prints the usage/help information of the program. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// # ; + /// ``` + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + /// [`Arg`]: ./struct.Arg.html + pub fn with_name(n: &'a str) -> Self { + Arg { + b: Base::new(n), + ..Default::default() + } + } + + /// Creates a new instance of [`Arg`] from a .yml (YAML) file. + /// + /// # Examples + /// + /// ```ignore + /// # #[macro_use] + /// # extern crate clap; + /// # use clap::Arg; + /// # fn main() { + /// let yml = load_yaml!("arg.yml"); + /// let arg = Arg::from_yaml(yml); + /// # } + /// ``` + /// [`Arg`]: ./struct.Arg.html + #[cfg(feature = "yaml")] + pub fn from_yaml(y: &BTreeMap) -> Arg { + // We WANT this to panic on error...so expect() is good. + let name_yml = y.keys().nth(0).unwrap(); + let name_str = name_yml.as_str().unwrap(); + let mut a = Arg::with_name(name_str); + let arg_settings = y.get(name_yml).unwrap().as_hash().unwrap(); + + for (k, v) in arg_settings.iter() { + a = match k.as_str().unwrap() { + "short" => yaml_to_str!(a, v, short), + "long" => yaml_to_str!(a, v, long), + "aliases" => yaml_vec_or_str!(v, a, alias), + "help" => yaml_to_str!(a, v, help), + "long_help" => yaml_to_str!(a, v, long_help), + "required" => yaml_to_bool!(a, v, required), + "required_if" => yaml_tuple2!(a, v, required_if), + "required_ifs" => yaml_tuple2!(a, v, required_if), + "takes_value" => yaml_to_bool!(a, v, takes_value), + "index" => yaml_to_u64!(a, v, index), + "global" => yaml_to_bool!(a, v, global), + "multiple" => yaml_to_bool!(a, v, multiple), + "hidden" => yaml_to_bool!(a, v, hidden), + "next_line_help" => yaml_to_bool!(a, v, next_line_help), + "empty_values" => yaml_to_bool!(a, v, empty_values), + "group" => yaml_to_str!(a, v, group), + "number_of_values" => yaml_to_u64!(a, v, number_of_values), + "max_values" => yaml_to_u64!(a, v, max_values), + "min_values" => yaml_to_u64!(a, v, min_values), + "value_name" => yaml_to_str!(a, v, value_name), + "use_delimiter" => yaml_to_bool!(a, v, use_delimiter), + "allow_hyphen_values" => yaml_to_bool!(a, v, allow_hyphen_values), + "last" => yaml_to_bool!(a, v, last), + "require_delimiter" => yaml_to_bool!(a, v, require_delimiter), + "value_delimiter" => yaml_to_str!(a, v, value_delimiter), + "required_unless" => yaml_to_str!(a, v, required_unless), + "display_order" => yaml_to_usize!(a, v, display_order), + "default_value" => yaml_to_str!(a, v, default_value), + "default_value_if" => yaml_tuple3!(a, v, default_value_if), + "default_value_ifs" => yaml_tuple3!(a, v, default_value_if), + "env" => yaml_to_str!(a, v, env), + "value_names" => yaml_vec_or_str!(v, a, value_name), + "groups" => yaml_vec_or_str!(v, a, group), + "requires" => yaml_vec_or_str!(v, a, requires), + "requires_if" => yaml_tuple2!(a, v, requires_if), + "requires_ifs" => yaml_tuple2!(a, v, requires_if), + "conflicts_with" => yaml_vec_or_str!(v, a, conflicts_with), + "overrides_with" => yaml_vec_or_str!(v, a, overrides_with), + "possible_values" => yaml_vec_or_str!(v, a, possible_value), + "case_insensitive" => yaml_to_bool!(a, v, case_insensitive), + "required_unless_one" => yaml_vec_or_str!(v, a, required_unless), + "required_unless_all" => { + a = yaml_vec_or_str!(v, a, required_unless); + a.setb(ArgSettings::RequiredUnlessAll); + a + } + s => panic!( + "Unknown Arg setting '{}' in YAML file for arg '{}'", + s, name_str + ), + } + } + + a + } + + /// Creates a new instance of [`Arg`] from a usage string. Allows creation of basic settings + /// for the [`Arg`]. The syntax is flexible, but there are some rules to follow. + /// + /// **NOTE**: Not all settings may be set using the usage string method. Some properties are + /// only available via the builder pattern. + /// + /// **NOTE**: Only ASCII values are officially supported in [`Arg::from_usage`] strings. Some + /// UTF-8 codepoints may work just fine, but this is not guaranteed. + /// + /// # Syntax + /// + /// Usage strings typically following the form: + /// + /// ```notrust + /// [explicit name] [short] [long] [value names] [help string] + /// ``` + /// + /// This is not a hard rule as the attributes can appear in other orders. There are also + /// several additional sigils which denote additional settings. Below are the details of each + /// portion of the string. + /// + /// ### Explicit Name + /// + /// This is an optional field, if it's omitted the argument will use one of the additional + /// fields as the name using the following priority order: + /// + /// * Explicit Name (This always takes precedence when present) + /// * Long + /// * Short + /// * Value Name + /// + /// `clap` determines explicit names as the first string of characters between either `[]` or + /// `<>` where `[]` has the dual notation of meaning the argument is optional, and `<>` meaning + /// the argument is required. + /// + /// Explicit names may be followed by: + /// * The multiple denotation `...` + /// + /// Example explicit names as follows (`ename` for an optional argument, and `rname` for a + /// required argument): + /// + /// ```notrust + /// [ename] -s, --long 'some flag' + /// -r, --longer 'some other flag' + /// ``` + /// + /// ### Short + /// + /// This is set by placing a single character after a leading `-`. + /// + /// Shorts may be followed by + /// * The multiple denotation `...` + /// * An optional comma `,` which is cosmetic only + /// * Value notation + /// + /// Example shorts are as follows (`-s`, and `-r`): + /// + /// ```notrust + /// -s, --long 'some flag' + /// -r [val], --longer 'some option' + /// ``` + /// + /// ### Long + /// + /// This is set by placing a word (no spaces) after a leading `--`. + /// + /// Shorts may be followed by + /// * The multiple denotation `...` + /// * Value notation + /// + /// Example longs are as follows (`--some`, and `--rapid`): + /// + /// ```notrust + /// -s, --some 'some flag' + /// --rapid=[FILE] 'some option' + /// ``` + /// + /// ### Values (Value Notation) + /// + /// This is set by placing a word(s) between `[]` or `<>` optionally after `=` (although this + /// is cosmetic only and does not affect functionality). If an explicit name has **not** been + /// set, using `<>` will denote a required argument, and `[]` will denote an optional argument + /// + /// Values may be followed by + /// * The multiple denotation `...` + /// * More Value notation + /// + /// More than one value will also implicitly set the arguments number of values, i.e. having + /// two values, `--option [val1] [val2]` specifies that in order for option to be satisified it + /// must receive exactly two values + /// + /// Example values are as follows (`FILE`, and `SPEED`): + /// + /// ```notrust + /// -s, --some [FILE] 'some option' + /// --rapid=... 'some required multiple option' + /// ``` + /// + /// ### Help String + /// + /// The help string is denoted between a pair of single quotes `''` and may contain any + /// characters. + /// + /// Example help strings are as follows: + /// + /// ```notrust + /// -s, --some [FILE] 'some option' + /// --rapid=... 'some required multiple option' + /// ``` + /// + /// ### Additional Sigils + /// + /// Multiple notation `...` (three consecutive dots/periods) specifies that this argument may + /// be used multiple times. Do not confuse multiple occurrences (`...`) with multiple values. + /// `--option val1 val2` is a single occurrence with multiple values. `--flag --flag` is + /// multiple occurrences (and then you can obviously have instances of both as well) + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// App::new("prog") + /// .args(&[ + /// Arg::from_usage("--config 'a required file for the configuration and no short'"), + /// Arg::from_usage("-d, --debug... 'turns on debugging information and allows multiples'"), + /// Arg::from_usage("[input] 'an optional input file to use'") + /// ]) + /// # ; + /// ``` + /// [`Arg`]: ./struct.Arg.html + /// [`Arg::from_usage`]: ./struct.Arg.html#method.from_usage + pub fn from_usage(u: &'a str) -> Self { + let parser = UsageParser::from_usage(u); + parser.parse() + } + + /// Sets the short version of the argument without the preceding `-`. + /// + /// By default `clap` automatically assigns `V` and `h` to the auto-generated `version` and + /// `help` arguments respectively. You may use the uppercase `V` or lowercase `h` for your own + /// arguments, in which case `clap` simply will not assign those to the auto-generated + /// `version` or `help` arguments. + /// + /// **NOTE:** Any leading `-` characters will be stripped, and only the first + /// non `-` character will be used as the [`short`] version + /// + /// # Examples + /// + /// To set [`short`] use a single valid UTF-8 code point. If you supply a leading `-` such as + /// `-c`, the `-` will be stripped. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .short("c") + /// # ; + /// ``` + /// + /// Setting [`short`] allows using the argument via a single hyphen (`-`) such as `-c` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("config") + /// .short("c")) + /// .get_matches_from(vec![ + /// "prog", "-c" + /// ]); + /// + /// assert!(m.is_present("config")); + /// ``` + /// [`short`]: ./struct.Arg.html#method.short + pub fn short>(mut self, s: S) -> Self { + self.s.short = s.as_ref().trim_left_matches(|c| c == '-').chars().next(); + self + } + + /// Sets the long version of the argument without the preceding `--`. + /// + /// By default `clap` automatically assigns `version` and `help` to the auto-generated + /// `version` and `help` arguments respectively. You may use the word `version` or `help` for + /// the long form of your own arguments, in which case `clap` simply will not assign those to + /// the auto-generated `version` or `help` arguments. + /// + /// **NOTE:** Any leading `-` characters will be stripped + /// + /// # Examples + /// + /// To set `long` use a word containing valid UTF-8 codepoints. If you supply a double leading + /// `--` such as `--config` they will be stripped. Hyphens in the middle of the word, however, + /// will *not* be stripped (i.e. `config-file` is allowed) + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("cfg") + /// .long("config") + /// # ; + /// ``` + /// + /// Setting `long` allows using the argument via a double hyphen (`--`) such as `--config` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config")) + /// .get_matches_from(vec![ + /// "prog", "--config" + /// ]); + /// + /// assert!(m.is_present("cfg")); + /// ``` + pub fn long(mut self, l: &'b str) -> Self { + self.s.long = Some(l.trim_left_matches(|c| c == '-')); + self + } + + /// Allows adding a [`Arg`] alias, which function as "hidden" arguments that + /// automatically dispatch as if this argument was used. This is more efficient, and easier + /// than creating multiple hidden arguments as one only needs to check for the existence of + /// this command, and not all variants. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("test") + /// .long("test") + /// .alias("alias") + /// .takes_value(true)) + /// .get_matches_from(vec![ + /// "prog", "--alias", "cool" + /// ]); + /// assert!(m.is_present("test")); + /// assert_eq!(m.value_of("test"), Some("cool")); + /// ``` + /// [`Arg`]: ./struct.Arg.html + pub fn alias>(mut self, name: S) -> Self { + if let Some(ref mut als) = self.s.aliases { + als.push((name.into(), false)); + } else { + self.s.aliases = Some(vec![(name.into(), false)]); + } + self + } + + /// Allows adding [`Arg`] aliases, which function as "hidden" arguments that + /// automatically dispatch as if this argument was used. This is more efficient, and easier + /// than creating multiple hidden subcommands as one only needs to check for the existence of + /// this command, and not all variants. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("test") + /// .long("test") + /// .aliases(&["do-stuff", "do-tests", "tests"]) + /// .help("the file to add") + /// .required(false)) + /// .get_matches_from(vec![ + /// "prog", "--do-tests" + /// ]); + /// assert!(m.is_present("test")); + /// ``` + /// [`Arg`]: ./struct.Arg.html + pub fn aliases(mut self, names: &[&'b str]) -> Self { + if let Some(ref mut als) = self.s.aliases { + for n in names { + als.push((n, false)); + } + } else { + self.s.aliases = Some(names.iter().map(|n| (*n, false)).collect::>()); + } + self + } + + /// Allows adding a [`Arg`] alias that functions exactly like those defined with + /// [`Arg::alias`], except that they are visible inside the help message. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("test") + /// .visible_alias("something-awesome") + /// .long("test") + /// .takes_value(true)) + /// .get_matches_from(vec![ + /// "prog", "--something-awesome", "coffee" + /// ]); + /// assert!(m.is_present("test")); + /// assert_eq!(m.value_of("test"), Some("coffee")); + /// ``` + /// [`Arg`]: ./struct.Arg.html + /// [`App::alias`]: ./struct.Arg.html#method.alias + pub fn visible_alias>(mut self, name: S) -> Self { + if let Some(ref mut als) = self.s.aliases { + als.push((name.into(), true)); + } else { + self.s.aliases = Some(vec![(name.into(), true)]); + } + self + } + + /// Allows adding multiple [`Arg`] aliases that functions exactly like those defined + /// with [`Arg::aliases`], except that they are visible inside the help message. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("test") + /// .long("test") + /// .visible_aliases(&["something", "awesome", "cool"])) + /// .get_matches_from(vec![ + /// "prog", "--awesome" + /// ]); + /// assert!(m.is_present("test")); + /// ``` + /// [`Arg`]: ./struct.Arg.html + /// [`App::aliases`]: ./struct.Arg.html#method.aliases + pub fn visible_aliases(mut self, names: &[&'b str]) -> Self { + if let Some(ref mut als) = self.s.aliases { + for n in names { + als.push((n, true)); + } + } else { + self.s.aliases = Some(names.iter().map(|n| (*n, true)).collect::>()); + } + self + } + + /// Sets the short help text of the argument that will be displayed to the user when they print + /// the help information with `-h`. Typically, this is a short (one line) description of the + /// arg. + /// + /// **NOTE:** If only `Arg::help` is provided, and not [`Arg::long_help`] but the user requests + /// `--help` clap will still display the contents of `help` appropriately + /// + /// **NOTE:** Only `Arg::help` is used in completion script generation in order to be concise + /// + /// # Examples + /// + /// Any valid UTF-8 is allowed in the help text. The one exception is when one wishes to + /// include a newline in the help text and have the following text be properly aligned with all + /// the other help text. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .help("The config file used by the myprog") + /// # ; + /// ``` + /// + /// Setting `help` displays a short message to the side of the argument when the user passes + /// `-h` or `--help` (by default). + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .help("Some help text describing the --config arg")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// --config Some help text describing the --config arg + /// -h, --help Prints help information + /// -V, --version Prints version information + /// ``` + /// [`Arg::long_help`]: ./struct.Arg.html#method.long_help + pub fn help(mut self, h: &'b str) -> Self { + self.b.help = Some(h); + self + } + + /// Sets the long help text of the argument that will be displayed to the user when they print + /// the help information with `--help`. Typically this a more detailed (multi-line) message + /// that describes the arg. + /// + /// **NOTE:** If only `long_help` is provided, and not [`Arg::help`] but the user requests `-h` + /// clap will still display the contents of `long_help` appropriately + /// + /// **NOTE:** Only [`Arg::help`] is used in completion script generation in order to be concise + /// + /// # Examples + /// + /// Any valid UTF-8 is allowed in the help text. The one exception is when one wishes to + /// include a newline in the help text and have the following text be properly aligned with all + /// the other help text. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .long_help( + /// "The config file used by the myprog must be in JSON format + /// with only valid keys and may not contain other nonsense + /// that cannot be read by this program. Obviously I'm going on + /// and on, so I'll stop now.") + /// # ; + /// ``` + /// + /// Setting `help` displays a short message to the side of the argument when the user passes + /// `-h` or `--help` (by default). + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .long_help( + /// "The config file used by the myprog must be in JSON format + /// with only valid keys and may not contain other nonsense + /// that cannot be read by this program. Obviously I'm going on + /// and on, so I'll stop now.")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// --config + /// The config file used by the myprog must be in JSON format + /// with only valid keys and may not contain other nonsense + /// that cannot be read by this program. Obviously I'm going on + /// and on, so I'll stop now. + /// + /// -h, --help + /// Prints help information + /// + /// -V, --version + /// Prints version information + /// ``` + /// [`Arg::help`]: ./struct.Arg.html#method.help + pub fn long_help(mut self, h: &'b str) -> Self { + self.b.long_help = Some(h); + self + } + + /// Specifies that this arg is the last, or final, positional argument (i.e. has the highest + /// index) and is *only* able to be accessed via the `--` syntax (i.e. `$ prog args -- + /// last_arg`). Even, if no other arguments are left to parse, if the user omits the `--` syntax + /// they will receive an [`UnknownArgument`] error. Setting an argument to `.last(true)` also + /// allows one to access this arg early using the `--` syntax. Accessing an arg early, even with + /// the `--` syntax is otherwise not possible. + /// + /// **NOTE:** This will change the usage string to look like `$ prog [FLAGS] [-- ]` if + /// `ARG` is marked as `.last(true)`. + /// + /// **NOTE:** This setting will imply [`AppSettings::DontCollapseArgsInUsage`] because failing + /// to set this can make the usage string very confusing. + /// + /// **NOTE**: This setting only applies to positional arguments, and has no affect on FLAGS / + /// OPTIONS + /// + /// **CAUTION:** Setting an argument to `.last(true)` *and* having child subcommands is not + /// recommended with the exception of *also* using [`AppSettings::ArgsNegateSubcommands`] + /// (or [`AppSettings::SubcommandsNegateReqs`] if the argument marked `.last(true)` is also + /// marked [`.required(true)`]) + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("args") + /// .last(true) + /// # ; + /// ``` + /// + /// Setting [`Arg::last(true)`] ensures the arg has the highest [index] of all positional args + /// and requires that the `--` syntax be used to access it early. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("first")) + /// .arg(Arg::with_name("second")) + /// .arg(Arg::with_name("third").last(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "one", "--", "three" + /// ]); + /// + /// assert!(res.is_ok()); + /// let m = res.unwrap(); + /// assert_eq!(m.value_of("third"), Some("three")); + /// assert!(m.value_of("second").is_none()); + /// ``` + /// + /// Even if the positional argument marked `.last(true)` is the only argument left to parse, + /// failing to use the `--` syntax results in an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("first")) + /// .arg(Arg::with_name("second")) + /// .arg(Arg::with_name("third").last(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "one", "two", "three" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// [`Arg::last(true)`]: ./struct.Arg.html#method.last + /// [index]: ./struct.Arg.html#method.index + /// [`AppSettings::DontCollapseArgsInUsage`]: ./enum.AppSettings.html#variant.DontCollapseArgsInUsage + /// [`AppSettings::ArgsNegateSubcommands`]: ./enum.AppSettings.html#variant.ArgsNegateSubcommands + /// [`AppSettings::SubcommandsNegateReqs`]: ./enum.AppSettings.html#variant.SubcommandsNegateReqs + /// [`.required(true)`]: ./struct.Arg.html#method.required + /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument + pub fn last(self, l: bool) -> Self { + if l { + self.set(ArgSettings::Last) + } else { + self.unset(ArgSettings::Last) + } + } + + /// Sets whether or not the argument is required by default. Required by default means it is + /// required, when no other conflicting rules have been evaluated. Conflicting rules take + /// precedence over being required. **Default:** `false` + /// + /// **NOTE:** Flags (i.e. not positional, or arguments that take values) cannot be required by + /// default. This is simply because if a flag should be required, it should simply be implied + /// as no additional information is required from user. Flags by their very nature are simply + /// yes/no, or true/false. + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .required(true) + /// # ; + /// ``` + /// + /// Setting [`Arg::required(true)`] requires that the argument be used at runtime. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required(true) + /// .takes_value(true) + /// .long("config")) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "file.conf" + /// ]); + /// + /// assert!(res.is_ok()); + /// ``` + /// + /// Setting [`Arg::required(true)`] and *not* supplying that argument is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required(true) + /// .takes_value(true) + /// .long("config")) + /// .get_matches_from_safe(vec![ + /// "prog" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::required(true)`]: ./struct.Arg.html#method.required + pub fn required(self, r: bool) -> Self { + if r { + self.set(ArgSettings::Required) + } else { + self.unset(ArgSettings::Required) + } + } + + /// Requires that options use the `--option=val` syntax (i.e. an equals between the option and + /// associated value) **Default:** `false` + /// + /// **NOTE:** This setting also removes the default of allowing empty values and implies + /// [`Arg::empty_values(false)`]. + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .long("config") + /// .takes_value(true) + /// .require_equals(true) + /// # ; + /// ``` + /// + /// Setting [`Arg::require_equals(true)`] requires that the option have an equals sign between + /// it and the associated value. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .require_equals(true) + /// .takes_value(true) + /// .long("config")) + /// .get_matches_from_safe(vec![ + /// "prog", "--config=file.conf" + /// ]); + /// + /// assert!(res.is_ok()); + /// ``` + /// + /// Setting [`Arg::require_equals(true)`] and *not* supplying the equals will cause an error + /// unless [`Arg::empty_values(true)`] is set. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .require_equals(true) + /// .takes_value(true) + /// .long("config")) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "file.conf" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); + /// ``` + /// [`Arg::require_equals(true)`]: ./struct.Arg.html#method.require_equals + /// [`Arg::empty_values(true)`]: ./struct.Arg.html#method.empty_values + /// [`Arg::empty_values(false)`]: ./struct.Arg.html#method.empty_values + pub fn require_equals(mut self, r: bool) -> Self { + if r { + self.unsetb(ArgSettings::EmptyValues); + self.set(ArgSettings::RequireEquals) + } else { + self.unset(ArgSettings::RequireEquals) + } + } + + /// Allows values which start with a leading hyphen (`-`) + /// + /// **WARNING**: Take caution when using this setting combined with [`Arg::multiple(true)`], as + /// this becomes ambiguous `$ prog --arg -- -- val`. All three `--, --, val` will be values + /// when the user may have thought the second `--` would constitute the normal, "Only + /// positional args follow" idiom. To fix this, consider using [`Arg::number_of_values(1)`] + /// + /// **WARNING**: When building your CLIs, consider the effects of allowing leading hyphens and + /// the user passing in a value that matches a valid short. For example `prog -opt -F` where + /// `-F` is supposed to be a value, yet `-F` is *also* a valid short for another arg. Care should + /// should be taken when designing these args. This is compounded by the ability to "stack" + /// short args. I.e. if `-val` is supposed to be a value, but `-v`, `-a`, and `-l` are all valid + /// shorts. + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("pattern") + /// .allow_hyphen_values(true) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("pat") + /// .allow_hyphen_values(true) + /// .takes_value(true) + /// .long("pattern")) + /// .get_matches_from(vec![ + /// "prog", "--pattern", "-file" + /// ]); + /// + /// assert_eq!(m.value_of("pat"), Some("-file")); + /// ``` + /// + /// Not setting [`Arg::allow_hyphen_values(true)`] and supplying a value which starts with a + /// hyphen is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("pat") + /// .takes_value(true) + /// .long("pattern")) + /// .get_matches_from_safe(vec![ + /// "prog", "--pattern", "-file" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// [`Arg::allow_hyphen_values(true)`]: ./struct.Arg.html#method.allow_hyphen_values + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + /// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values + pub fn allow_hyphen_values(self, a: bool) -> Self { + if a { + self.set(ArgSettings::AllowLeadingHyphen) + } else { + self.unset(ArgSettings::AllowLeadingHyphen) + } + } + /// Sets an arg that override this arg's required setting. (i.e. this arg will be required + /// unless this other argument is present). + /// + /// **Pro Tip:** Using [`Arg::required_unless`] implies [`Arg::required`] and is therefore not + /// mandatory to also set. + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .required_unless("debug") + /// # ; + /// ``` + /// + /// Setting [`Arg::required_unless(name)`] requires that the argument be used at runtime + /// *unless* `name` is present. In the following example, the required argument is *not* + /// provided, but it's not an error because the `unless` arg has been supplied. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_unless("dbg") + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("dbg") + /// .long("debug")) + /// .get_matches_from_safe(vec![ + /// "prog", "--debug" + /// ]); + /// + /// assert!(res.is_ok()); + /// ``` + /// + /// Setting [`Arg::required_unless(name)`] and *not* supplying `name` or this arg is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_unless("dbg") + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("dbg") + /// .long("debug")) + /// .get_matches_from_safe(vec![ + /// "prog" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::required_unless`]: ./struct.Arg.html#method.required_unless + /// [`Arg::required`]: ./struct.Arg.html#method.required + /// [`Arg::required_unless(name)`]: ./struct.Arg.html#method.required_unless + pub fn required_unless(mut self, name: &'a str) -> Self { + if let Some(ref mut vec) = self.b.r_unless { + vec.push(name); + } else { + self.b.r_unless = Some(vec![name]); + } + self.required(true) + } + + /// Sets args that override this arg's required setting. (i.e. this arg will be required unless + /// all these other arguments are present). + /// + /// **NOTE:** If you wish for this argument to only be required if *one of* these args are + /// present see [`Arg::required_unless_one`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .required_unless_all(&["cfg", "dbg"]) + /// # ; + /// ``` + /// + /// Setting [`Arg::required_unless_all(names)`] requires that the argument be used at runtime + /// *unless* *all* the args in `names` are present. In the following example, the required + /// argument is *not* provided, but it's not an error because all the `unless` args have been + /// supplied. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_unless_all(&["dbg", "infile"]) + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("dbg") + /// .long("debug")) + /// .arg(Arg::with_name("infile") + /// .short("i") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "--debug", "-i", "file" + /// ]); + /// + /// assert!(res.is_ok()); + /// ``` + /// + /// Setting [`Arg::required_unless_all(names)`] and *not* supplying *all* of `names` or this + /// arg is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_unless_all(&["dbg", "infile"]) + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("dbg") + /// .long("debug")) + /// .arg(Arg::with_name("infile") + /// .short("i") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![ + /// "prog" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::required_unless_one`]: ./struct.Arg.html#method.required_unless_one + /// [`Arg::required_unless_all(names)`]: ./struct.Arg.html#method.required_unless_all + pub fn required_unless_all(mut self, names: &[&'a str]) -> Self { + if let Some(ref mut vec) = self.b.r_unless { + for s in names { + vec.push(s); + } + } else { + self.b.r_unless = Some(names.iter().copied().collect()); + } + self.setb(ArgSettings::RequiredUnlessAll); + self.required(true) + } + + /// Sets args that override this arg's [required] setting. (i.e. this arg will be required + /// unless *at least one of* these other arguments are present). + /// + /// **NOTE:** If you wish for this argument to only be required if *all of* these args are + /// present see [`Arg::required_unless_all`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .required_unless_all(&["cfg", "dbg"]) + /// # ; + /// ``` + /// + /// Setting [`Arg::required_unless_one(names)`] requires that the argument be used at runtime + /// *unless* *at least one of* the args in `names` are present. In the following example, the + /// required argument is *not* provided, but it's not an error because one the `unless` args + /// have been supplied. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_unless_one(&["dbg", "infile"]) + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("dbg") + /// .long("debug")) + /// .arg(Arg::with_name("infile") + /// .short("i") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "--debug" + /// ]); + /// + /// assert!(res.is_ok()); + /// ``` + /// + /// Setting [`Arg::required_unless_one(names)`] and *not* supplying *at least one of* `names` + /// or this arg is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_unless_one(&["dbg", "infile"]) + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("dbg") + /// .long("debug")) + /// .arg(Arg::with_name("infile") + /// .short("i") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![ + /// "prog" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [required]: ./struct.Arg.html#method.required + /// [`Arg::required_unless_one(names)`]: ./struct.Arg.html#method.required_unless_one + /// [`Arg::required_unless_all`]: ./struct.Arg.html#method.required_unless_all + pub fn required_unless_one(mut self, names: &[&'a str]) -> Self { + if let Some(ref mut vec) = self.b.r_unless { + for s in names { + vec.push(s); + } + } else { + self.b.r_unless = Some(names.iter().copied().collect()); + } + self.required(true) + } + + /// Sets a conflicting argument by name. I.e. when using this argument, + /// the following argument can't be present and vice versa. + /// + /// **NOTE:** Conflicting rules take precedence over being required by default. Conflict rules + /// only need to be set for one of the two arguments, they do not need to be set for each. + /// + /// **NOTE:** Defining a conflict is two-way, but does *not* need to defined for both arguments + /// (i.e. if A conflicts with B, defining A.conflicts_with(B) is sufficient. You do not need + /// need to also do B.conflicts_with(A)) + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .conflicts_with("debug") + /// # ; + /// ``` + /// + /// Setting conflicting argument, and having both arguments present at runtime is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .conflicts_with("debug") + /// .long("config")) + /// .arg(Arg::with_name("debug") + /// .long("debug")) + /// .get_matches_from_safe(vec![ + /// "prog", "--debug", "--config", "file.conf" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::ArgumentConflict); + /// ``` + pub fn conflicts_with(mut self, name: &'a str) -> Self { + if let Some(ref mut vec) = self.b.blacklist { + vec.push(name); + } else { + self.b.blacklist = Some(vec![name]); + } + self + } + + /// The same as [`Arg::conflicts_with`] but allows specifying multiple two-way conlicts per + /// argument. + /// + /// **NOTE:** Conflicting rules take precedence over being required by default. Conflict rules + /// only need to be set for one of the two arguments, they do not need to be set for each. + /// + /// **NOTE:** Defining a conflict is two-way, but does *not* need to defined for both arguments + /// (i.e. if A conflicts with B, defining A.conflicts_with(B) is sufficient. You do not need + /// need to also do B.conflicts_with(A)) + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .conflicts_with_all(&["debug", "input"]) + /// # ; + /// ``` + /// + /// Setting conflicting argument, and having any of the arguments present at runtime with a + /// conflicting argument is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .conflicts_with_all(&["debug", "input"]) + /// .long("config")) + /// .arg(Arg::with_name("debug") + /// .long("debug")) + /// .arg(Arg::with_name("input") + /// .index(1)) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "file.conf", "file.txt" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::ArgumentConflict); + /// ``` + /// [`Arg::conflicts_with`]: ./struct.Arg.html#method.conflicts_with + pub fn conflicts_with_all(mut self, names: &[&'a str]) -> Self { + if let Some(ref mut vec) = self.b.blacklist { + for s in names { + vec.push(s); + } + } else { + self.b.blacklist = Some(names.iter().copied().collect()); + } + self + } + + /// Sets a overridable argument by name. I.e. this argument and the following argument + /// will override each other in POSIX style (whichever argument was specified at runtime + /// **last** "wins") + /// + /// **NOTE:** When an argument is overridden it is essentially as if it never was used, any + /// conflicts, requirements, etc. are evaluated **after** all "overrides" have been removed + /// + /// **WARNING:** Positional arguments cannot override themselves (or we would never be able + /// to advance to the next positional). If a positional agument lists itself as an override, + /// it is simply ignored. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::from_usage("-f, --flag 'some flag'") + /// .conflicts_with("debug")) + /// .arg(Arg::from_usage("-d, --debug 'other flag'")) + /// .arg(Arg::from_usage("-c, --color 'third flag'") + /// .overrides_with("flag")) + /// .get_matches_from(vec![ + /// "prog", "-f", "-d", "-c"]); + /// // ^~~~~~~~~~~~^~~~~ flag is overridden by color + /// + /// assert!(m.is_present("color")); + /// assert!(m.is_present("debug")); // even though flag conflicts with debug, it's as if flag + /// // was never used because it was overridden with color + /// assert!(!m.is_present("flag")); + /// ``` + /// Care must be taken when using this setting, and having an arg override with itself. This + /// is common practice when supporting things like shell aliases, config files, etc. + /// However, when combined with multiple values, it can get dicy. + /// Here is how clap handles such situations: + /// + /// When a flag overrides itself, it's as if the flag was only ever used once (essentially + /// preventing a "Unexpected multiple usage" error): + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--flag 'some flag'").overrides_with("flag")) + /// .get_matches_from(vec!["posix", "--flag", "--flag"]); + /// assert!(m.is_present("flag")); + /// assert_eq!(m.occurrences_of("flag"), 1); + /// ``` + /// Making a arg `multiple(true)` and override itself is essentially meaningless. Therefore + /// clap ignores an override of self if it's a flag and it already accepts multiple occurrences. + /// + /// ``` + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--flag... 'some flag'").overrides_with("flag")) + /// .get_matches_from(vec!["", "--flag", "--flag", "--flag", "--flag"]); + /// assert!(m.is_present("flag")); + /// assert_eq!(m.occurrences_of("flag"), 4); + /// ``` + /// Now notice with options (which *do not* set `multiple(true)`), it's as if only the last + /// occurrence happened. + /// + /// ``` + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--opt [val] 'some option'").overrides_with("opt")) + /// .get_matches_from(vec!["", "--opt=some", "--opt=other"]); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 1); + /// assert_eq!(m.value_of("opt"), Some("other")); + /// ``` + /// + /// Just like flags, options with `multiple(true)` set, will ignore the "override self" setting. + /// + /// ``` + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--opt [val]... 'some option'") + /// .overrides_with("opt")) + /// .get_matches_from(vec!["", "--opt", "first", "over", "--opt", "other", "val"]); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 2); + /// assert_eq!(m.values_of("opt").unwrap().collect::>(), &["first", "over", "other", "val"]); + /// ``` + /// + /// A safe thing to do if you'd like to support an option which supports multiple values, but + /// also is "overridable" by itself, is to use `use_delimiter(false)` and *not* use + /// `multiple(true)` while telling users to seperate values with a comma (i.e. `val1,val2`) + /// + /// ``` + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--opt [val] 'some option'") + /// .overrides_with("opt") + /// .use_delimiter(false)) + /// .get_matches_from(vec!["", "--opt=some,other", "--opt=one,two"]); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 1); + /// assert_eq!(m.values_of("opt").unwrap().collect::>(), &["one,two"]); + /// ``` + pub fn overrides_with(mut self, name: &'a str) -> Self { + if let Some(ref mut vec) = self.b.overrides { + vec.push(name); + } else { + self.b.overrides = Some(vec![name]); + } + self + } + + /// Sets multiple mutually overridable arguments by name. I.e. this argument and the following + /// argument will override each other in POSIX style (whichever argument was specified at + /// runtime **last** "wins") + /// + /// **NOTE:** When an argument is overridden it is essentially as if it never was used, any + /// conflicts, requirements, etc. are evaluated **after** all "overrides" have been removed + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::from_usage("-f, --flag 'some flag'") + /// .conflicts_with("color")) + /// .arg(Arg::from_usage("-d, --debug 'other flag'")) + /// .arg(Arg::from_usage("-c, --color 'third flag'") + /// .overrides_with_all(&["flag", "debug"])) + /// .get_matches_from(vec![ + /// "prog", "-f", "-d", "-c"]); + /// // ^~~~~~^~~~~~~~~ flag and debug are overridden by color + /// + /// assert!(m.is_present("color")); // even though flag conflicts with color, it's as if flag + /// // and debug were never used because they were overridden + /// // with color + /// assert!(!m.is_present("debug")); + /// assert!(!m.is_present("flag")); + /// ``` + pub fn overrides_with_all(mut self, names: &[&'a str]) -> Self { + if let Some(ref mut vec) = self.b.overrides { + for s in names { + vec.push(s); + } + } else { + self.b.overrides = Some(names.iter().copied().collect()); + } + self + } + + /// Sets an argument by name that is required when this one is present I.e. when + /// using this argument, the following argument *must* be present. + /// + /// **NOTE:** [Conflicting] rules and [override] rules take precedence over being required + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .requires("input") + /// # ; + /// ``` + /// + /// Setting [`Arg::requires(name)`] requires that the argument be used at runtime if the + /// defining argument is used. If the defining argument isn't used, the other argument isn't + /// required + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires("input") + /// .long("config")) + /// .arg(Arg::with_name("input") + /// .index(1)) + /// .get_matches_from_safe(vec![ + /// "prog" + /// ]); + /// + /// assert!(res.is_ok()); // We didn't use cfg, so input wasn't required + /// ``` + /// + /// Setting [`Arg::requires(name)`] and *not* supplying that argument is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires("input") + /// .long("config")) + /// .arg(Arg::with_name("input") + /// .index(1)) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "file.conf" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires + /// [Conflicting]: ./struct.Arg.html#method.conflicts_with + /// [override]: ./struct.Arg.html#method.overrides_with + pub fn requires(mut self, name: &'a str) -> Self { + if let Some(ref mut vec) = self.b.requires { + vec.push((None, name)); + } else { + self.b.requires = Some(vec![(None, name)]); + } + self + } + + /// Allows a conditional requirement. The requirement will only become valid if this arg's value + /// equals `val`. + /// + /// **NOTE:** If using YAML the values should be laid out as follows + /// + /// ```yaml + /// requires_if: + /// - [val, arg] + /// ``` + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .requires_if("val", "arg") + /// # ; + /// ``` + /// + /// Setting [`Arg::requires_if(val, arg)`] requires that the `arg` be used at runtime if the + /// defining argument's value is equal to `val`. If the defining argument is anything other than + /// `val`, the other argument isn't required. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires_if("my.cfg", "other") + /// .long("config")) + /// .arg(Arg::with_name("other")) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "some.cfg" + /// ]); + /// + /// assert!(res.is_ok()); // We didn't use --config=my.cfg, so other wasn't required + /// ``` + /// + /// Setting [`Arg::requires_if(val, arg)`] and setting the value to `val` but *not* supplying + /// `arg` is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires_if("my.cfg", "input") + /// .long("config")) + /// .arg(Arg::with_name("input")) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "my.cfg" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires + /// [Conflicting]: ./struct.Arg.html#method.conflicts_with + /// [override]: ./struct.Arg.html#method.overrides_with + pub fn requires_if(mut self, val: &'b str, arg: &'a str) -> Self { + if let Some(ref mut vec) = self.b.requires { + vec.push((Some(val), arg)); + } else { + self.b.requires = Some(vec![(Some(val), arg)]); + } + self + } + + /// Allows multiple conditional requirements. The requirement will only become valid if this arg's value + /// equals `val`. + /// + /// **NOTE:** If using YAML the values should be laid out as follows + /// + /// ```yaml + /// requires_if: + /// - [val, arg] + /// - [val2, arg2] + /// ``` + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .requires_ifs(&[ + /// ("val", "arg"), + /// ("other_val", "arg2"), + /// ]) + /// # ; + /// ``` + /// + /// Setting [`Arg::requires_ifs(&["val", "arg"])`] requires that the `arg` be used at runtime if the + /// defining argument's value is equal to `val`. If the defining argument's value is anything other + /// than `val`, `arg` isn't required. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires_ifs(&[ + /// ("special.conf", "opt"), + /// ("other.conf", "other"), + /// ]) + /// .long("config")) + /// .arg(Arg::with_name("opt") + /// .long("option") + /// .takes_value(true)) + /// .arg(Arg::with_name("other")) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "special.conf" + /// ]); + /// + /// assert!(res.is_err()); // We used --config=special.conf so --option is required + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires + /// [Conflicting]: ./struct.Arg.html#method.conflicts_with + /// [override]: ./struct.Arg.html#method.overrides_with + pub fn requires_ifs(mut self, ifs: &[(&'b str, &'a str)]) -> Self { + if let Some(ref mut vec) = self.b.requires { + for &(val, arg) in ifs { + vec.push((Some(val), arg)); + } + } else { + let mut vec = vec![]; + for &(val, arg) in ifs { + vec.push((Some(val), arg)); + } + self.b.requires = Some(vec); + } + self + } + + /// Allows specifying that an argument is [required] conditionally. The requirement will only + /// become valid if the specified `arg`'s value equals `val`. + /// + /// **NOTE:** If using YAML the values should be laid out as follows + /// + /// ```yaml + /// required_if: + /// - [arg, val] + /// ``` + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .required_if("other_arg", "value") + /// # ; + /// ``` + /// + /// Setting [`Arg::required_if(arg, val)`] makes this arg required if the `arg` is used at + /// runtime and it's value is equal to `val`. If the `arg`'s value is anything other than `val`, + /// this argument isn't required. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .required_if("other", "special") + /// .long("config")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "--other", "not-special" + /// ]); + /// + /// assert!(res.is_ok()); // We didn't use --other=special, so "cfg" wasn't required + /// ``` + /// + /// Setting [`Arg::required_if(arg, val)`] and having `arg` used with a value of `val` but *not* + /// using this arg is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .required_if("other", "special") + /// .long("config")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "--other", "special" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires + /// [Conflicting]: ./struct.Arg.html#method.conflicts_with + /// [required]: ./struct.Arg.html#method.required + pub fn required_if(mut self, arg: &'a str, val: &'b str) -> Self { + if let Some(ref mut vec) = self.r_ifs { + vec.push((arg, val)); + } else { + self.r_ifs = Some(vec![(arg, val)]); + } + self + } + + /// Allows specifying that an argument is [required] based on multiple conditions. The + /// conditions are set up in a `(arg, val)` style tuple. The requirement will only become valid + /// if one of the specified `arg`'s value equals it's corresponding `val`. + /// + /// **NOTE:** If using YAML the values should be laid out as follows + /// + /// ```yaml + /// required_if: + /// - [arg, val] + /// - [arg2, val2] + /// ``` + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .required_ifs(&[ + /// ("extra", "val"), + /// ("option", "spec") + /// ]) + /// # ; + /// ``` + /// + /// Setting [`Arg::required_ifs(&[(arg, val)])`] makes this arg required if any of the `arg`s + /// are used at runtime and it's corresponding value is equal to `val`. If the `arg`'s value is + /// anything other than `val`, this argument isn't required. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_ifs(&[ + /// ("extra", "val"), + /// ("option", "spec") + /// ]) + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("extra") + /// .takes_value(true) + /// .long("extra")) + /// .arg(Arg::with_name("option") + /// .takes_value(true) + /// .long("option")) + /// .get_matches_from_safe(vec![ + /// "prog", "--option", "other" + /// ]); + /// + /// assert!(res.is_ok()); // We didn't use --option=spec, or --extra=val so "cfg" isn't required + /// ``` + /// + /// Setting [`Arg::required_ifs(&[(arg, val)])`] and having any of the `arg`s used with it's + /// value of `val` but *not* using this arg is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_ifs(&[ + /// ("extra", "val"), + /// ("option", "spec") + /// ]) + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("extra") + /// .takes_value(true) + /// .long("extra")) + /// .arg(Arg::with_name("option") + /// .takes_value(true) + /// .long("option")) + /// .get_matches_from_safe(vec![ + /// "prog", "--option", "spec" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires + /// [Conflicting]: ./struct.Arg.html#method.conflicts_with + /// [required]: ./struct.Arg.html#method.required + pub fn required_ifs(mut self, ifs: &[(&'a str, &'b str)]) -> Self { + if let Some(ref mut vec) = self.r_ifs { + for r_if in ifs { + vec.push((r_if.0, r_if.1)); + } + } else { + let mut vec = vec![]; + for r_if in ifs { + vec.push((r_if.0, r_if.1)); + } + self.r_ifs = Some(vec); + } + self + } + + /// Sets multiple arguments by names that are required when this one is present I.e. when + /// using this argument, the following arguments *must* be present. + /// + /// **NOTE:** [Conflicting] rules and [override] rules take precedence over being required + /// by default. + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .requires_all(&["input", "output"]) + /// # ; + /// ``` + /// + /// Setting [`Arg::requires_all(&[arg, arg2])`] requires that all the arguments be used at + /// runtime if the defining argument is used. If the defining argument isn't used, the other + /// argument isn't required + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires("input") + /// .long("config")) + /// .arg(Arg::with_name("input") + /// .index(1)) + /// .arg(Arg::with_name("output") + /// .index(2)) + /// .get_matches_from_safe(vec![ + /// "prog" + /// ]); + /// + /// assert!(res.is_ok()); // We didn't use cfg, so input and output weren't required + /// ``` + /// + /// Setting [`Arg::requires_all(&[arg, arg2])`] and *not* supplying all the arguments is an + /// error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires_all(&["input", "output"]) + /// .long("config")) + /// .arg(Arg::with_name("input") + /// .index(1)) + /// .arg(Arg::with_name("output") + /// .index(2)) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "file.conf", "in.txt" + /// ]); + /// + /// assert!(res.is_err()); + /// // We didn't use output + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [Conflicting]: ./struct.Arg.html#method.conflicts_with + /// [override]: ./struct.Arg.html#method.overrides_with + /// [`Arg::requires_all(&[arg, arg2])`]: ./struct.Arg.html#method.requires_all + pub fn requires_all(mut self, names: &[&'a str]) -> Self { + if let Some(ref mut vec) = self.b.requires { + for s in names { + vec.push((None, s)); + } + } else { + let mut vec = vec![]; + for s in names { + vec.push((None, *s)); + } + self.b.requires = Some(vec); + } + self + } + + /// Specifies that the argument takes a value at run time. + /// + /// **NOTE:** values for arguments may be specified in any of the following methods + /// + /// * Using a space such as `-o value` or `--option value` + /// * Using an equals and no space such as `-o=value` or `--option=value` + /// * Use a short and no space such as `-ovalue` + /// + /// **NOTE:** By default, args which allow [multiple values] are delimited by commas, meaning + /// `--option=val1,val2,val3` is three values for the `--option` argument. If you wish to + /// change the delimiter to another character you can use [`Arg::value_delimiter(char)`], + /// alternatively you can turn delimiting values **OFF** by using [`Arg::use_delimiter(false)`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .takes_value(true) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .takes_value(true)) + /// .get_matches_from(vec![ + /// "prog", "--mode", "fast" + /// ]); + /// + /// assert!(m.is_present("mode")); + /// assert_eq!(m.value_of("mode"), Some("fast")); + /// ``` + /// [`Arg::value_delimiter(char)`]: ./struct.Arg.html#method.value_delimiter + /// [`Arg::use_delimiter(false)`]: ./struct.Arg.html#method.use_delimiter + /// [multiple values]: ./struct.Arg.html#method.multiple + pub fn takes_value(self, tv: bool) -> Self { + if tv { + self.set(ArgSettings::TakesValue) + } else { + self.unset(ArgSettings::TakesValue) + } + } + + /// Specifies if the possible values of an argument should be displayed in the help text or + /// not. Defaults to `false` (i.e. show possible values) + /// + /// This is useful for args with many values, or ones which are explained elsewhere in the + /// help text. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .hide_possible_values(true) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .possible_values(&["fast", "slow"]) + /// .takes_value(true) + /// .hide_possible_values(true)); + /// + /// ``` + /// + /// If we were to run the above program with `--help` the `[values: fast, slow]` portion of + /// the help text would be omitted. + pub fn hide_possible_values(self, hide: bool) -> Self { + if hide { + self.set(ArgSettings::HidePossibleValues) + } else { + self.unset(ArgSettings::HidePossibleValues) + } + } + + /// Specifies if the default value of an argument should be displayed in the help text or + /// not. Defaults to `false` (i.e. show default value) + /// + /// This is useful when default behavior of an arg is explained elsewhere in the help text. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .hide_default_value(true) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("connect") + /// .arg(Arg::with_name("host") + /// .long("host") + /// .default_value("localhost") + /// .hide_default_value(true)); + /// + /// ``` + /// + /// If we were to run the above program with `--help` the `[default: localhost]` portion of + /// the help text would be omitted. + pub fn hide_default_value(self, hide: bool) -> Self { + if hide { + self.set(ArgSettings::HideDefaultValue) + } else { + self.unset(ArgSettings::HideDefaultValue) + } + } + + /// Specifies the index of a positional argument **starting at** 1. + /// + /// **NOTE:** The index refers to position according to **other positional argument**. It does + /// not define position in the argument list as a whole. + /// + /// **NOTE:** If no [`Arg::short`], or [`Arg::long`] have been defined, you can optionally + /// leave off the `index` method, and the index will be assigned in order of evaluation. + /// Utilizing the `index` method allows for setting indexes out of order + /// + /// **NOTE:** When utilized with [`Arg::multiple(true)`], only the **last** positional argument + /// may be defined as multiple (i.e. with the highest index) + /// + /// # Panics + /// + /// Although not in this method directly, [`App`] will [`panic!`] if indexes are skipped (such + /// as defining `index(1)` and `index(3)` but not `index(2)`, or a positional argument is + /// defined as multiple and is not the highest index + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .index(1) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .index(1)) + /// .arg(Arg::with_name("debug") + /// .long("debug")) + /// .get_matches_from(vec![ + /// "prog", "--debug", "fast" + /// ]); + /// + /// assert!(m.is_present("mode")); + /// assert_eq!(m.value_of("mode"), Some("fast")); // notice index(1) means "first positional" + /// // *not* first argument + /// ``` + /// [`Arg::short`]: ./struct.Arg.html#method.short + /// [`Arg::long`]: ./struct.Arg.html#method.long + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + /// [`App`]: ./struct.App.html + /// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html + pub fn index(mut self, idx: u64) -> Self { + self.index = Some(idx); + self + } + + /// Specifies that the argument may appear more than once. For flags, this results + /// in the number of occurrences of the flag being recorded. For example `-ddd` or `-d -d -d` + /// would count as three occurrences. For options there is a distinct difference in multiple + /// occurrences vs multiple values. + /// + /// For example, `--opt val1 val2` is one occurrence, but two values. Whereas + /// `--opt val1 --opt val2` is two occurrences. + /// + /// **WARNING:** + /// + /// Setting `multiple(true)` for an [option] with no other details, allows multiple values + /// **and** multiple occurrences because it isn't possible to have more occurrences than values + /// for options. Because multiple values are allowed, `--option val1 val2 val3` is perfectly + /// valid, be careful when designing a CLI where positional arguments are expected after a + /// option which accepts multiple values, as `clap` will continue parsing *values* until it + /// reaches the max or specific number of values defined, or another flag or option. + /// + /// **Pro Tip**: + /// + /// It's possible to define an option which allows multiple occurrences, but only one value per + /// occurrence. To do this use [`Arg::number_of_values(1)`] in coordination with + /// [`Arg::multiple(true)`]. + /// + /// **WARNING:** + /// + /// When using args with `multiple(true)` on [options] or [positionals] (i.e. those args that + /// accept values) and [subcommands], one needs to consider the possibility of an argument value + /// being the same as a valid subcommand. By default `clap` will parse the argument in question + /// as a value *only if* a value is possible at that moment. Otherwise it will be parsed as a + /// subcommand. In effect, this means using `multiple(true)` with no additional parameters and + /// a possible value that coincides with a subcommand name, the subcommand cannot be called + /// unless another argument is passed first. + /// + /// As an example, consider a CLI with an option `--ui-paths=...` and subcommand `signer` + /// + /// The following would be parsed as values to `--ui-paths`. + /// + /// ```notrust + /// $ program --ui-paths path1 path2 signer + /// ``` + /// + /// This is because `--ui-paths` accepts multiple values. `clap` will continue parsing values + /// until another argument is reached and it knows `--ui-paths` is done. + /// + /// By adding additional parameters to `--ui-paths` we can solve this issue. Consider adding + /// [`Arg::number_of_values(1)`] as discussed above. The following are all valid, and `signer` + /// is parsed as both a subcommand and a value in the second case. + /// + /// ```notrust + /// $ program --ui-paths path1 signer + /// $ program --ui-paths path1 --ui-paths signer signer + /// ``` + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .short("d") + /// .multiple(true) + /// # ; + /// ``` + /// An example with flags + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("verbose") + /// .multiple(true) + /// .short("v")) + /// .get_matches_from(vec![ + /// "prog", "-v", "-v", "-v" // note, -vvv would have same result + /// ]); + /// + /// assert!(m.is_present("verbose")); + /// assert_eq!(m.occurrences_of("verbose"), 3); + /// ``` + /// + /// An example with options + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("file") + /// .multiple(true) + /// .takes_value(true) + /// .short("F")) + /// .get_matches_from(vec![ + /// "prog", "-F", "file1", "file2", "file3" + /// ]); + /// + /// assert!(m.is_present("file")); + /// assert_eq!(m.occurrences_of("file"), 1); // notice only one occurrence + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3"]); + /// ``` + /// This is functionally equivalent to the example above + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("file") + /// .multiple(true) + /// .takes_value(true) + /// .short("F")) + /// .get_matches_from(vec![ + /// "prog", "-F", "file1", "-F", "file2", "-F", "file3" + /// ]); + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3"]); + /// + /// assert!(m.is_present("file")); + /// assert_eq!(m.occurrences_of("file"), 3); // Notice 3 occurrences + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3"]); + /// ``` + /// + /// A common mistake is to define an option which allows multiples, and a positional argument + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("file") + /// .multiple(true) + /// .takes_value(true) + /// .short("F")) + /// .arg(Arg::with_name("word") + /// .index(1)) + /// .get_matches_from(vec![ + /// "prog", "-F", "file1", "file2", "file3", "word" + /// ]); + /// + /// assert!(m.is_present("file")); + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3", "word"]); // wait...what?! + /// assert!(!m.is_present("word")); // but we clearly used word! + /// ``` + /// The problem is clap doesn't know when to stop parsing values for "files". This is further + /// compounded by if we'd said `word -F file1 file2` it would have worked fine, so it would + /// appear to only fail sometimes...not good! + /// + /// A solution for the example above is to specify that `-F` only accepts one value, but is + /// allowed to appear multiple times + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("file") + /// .multiple(true) + /// .takes_value(true) + /// .number_of_values(1) + /// .short("F")) + /// .arg(Arg::with_name("word") + /// .index(1)) + /// .get_matches_from(vec![ + /// "prog", "-F", "file1", "-F", "file2", "-F", "file3", "word" + /// ]); + /// + /// assert!(m.is_present("file")); + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3"]); + /// assert!(m.is_present("word")); + /// assert_eq!(m.value_of("word"), Some("word")); + /// ``` + /// As a final example, notice if we define [`Arg::number_of_values(1)`] and try to run the + /// problem example above, it would have been a runtime error with a pretty message to the + /// user :) + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .multiple(true) + /// .takes_value(true) + /// .number_of_values(1) + /// .short("F")) + /// .arg(Arg::with_name("word") + /// .index(1)) + /// .get_matches_from_safe(vec![ + /// "prog", "-F", "file1", "file2", "file3", "word" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// [option]: ./struct.Arg.html#method.takes_value + /// [options]: ./struct.Arg.html#method.takes_value + /// [subcommands]: ./struct.SubCommand.html + /// [positionals]: ./struct.Arg.html#method.index + /// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + pub fn multiple(self, multi: bool) -> Self { + if multi { + self.set(ArgSettings::Multiple) + } else { + self.unset(ArgSettings::Multiple) + } + } + + /// Specifies a value that *stops* parsing multiple values of a give argument. By default when + /// one sets [`multiple(true)`] on an argument, clap will continue parsing values for that + /// argument until it reaches another valid argument, or one of the other more specific settings + /// for multiple values is used (such as [`min_values`], [`max_values`] or + /// [`number_of_values`]). + /// + /// **NOTE:** This setting only applies to [options] and [positional arguments] + /// + /// **NOTE:** When the terminator is passed in on the command line, it is **not** stored as one + /// of the values + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("vals") + /// .takes_value(true) + /// .multiple(true) + /// .value_terminator(";") + /// # ; + /// ``` + /// The following example uses two arguments, a sequence of commands, and the location in which + /// to perform them + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cmds") + /// .multiple(true) + /// .allow_hyphen_values(true) + /// .value_terminator(";")) + /// .arg(Arg::with_name("location")) + /// .get_matches_from(vec![ + /// "prog", "find", "-type", "f", "-name", "special", ";", "/home/clap" + /// ]); + /// let cmds: Vec<_> = m.values_of("cmds").unwrap().collect(); + /// assert_eq!(&cmds, &["find", "-type", "f", "-name", "special"]); + /// assert_eq!(m.value_of("location"), Some("/home/clap")); + /// ``` + /// [options]: ./struct.Arg.html#method.takes_value + /// [positional arguments]: ./struct.Arg.html#method.index + /// [`multiple(true)`]: ./struct.Arg.html#method.multiple + /// [`min_values`]: ./struct.Arg.html#method.min_values + /// [`number_of_values`]: ./struct.Arg.html#method.number_of_values + /// [`max_values`]: ./struct.Arg.html#method.max_values + pub fn value_terminator(mut self, term: &'b str) -> Self { + self.setb(ArgSettings::TakesValue); + self.v.terminator = Some(term); + self + } + + /// Specifies that an argument can be matched to all child [`SubCommand`]s. + /// + /// **NOTE:** Global arguments *only* propagate down, **not** up (to parent commands), however + /// their values once a user uses them will be propagated back up to parents. In effect, this + /// means one should *define* all global arguments at the top level, however it doesn't matter + /// where the user *uses* the global argument. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .short("d") + /// .global(true) + /// # ; + /// ``` + /// + /// For example, assume an application with two subcommands, and you'd like to define a + /// `--verbose` flag that can be called on any of the subcommands and parent, but you don't + /// want to clutter the source with three duplicate [`Arg`] definitions. + /// + /// ```rust + /// # use clap::{App, Arg, SubCommand}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("verb") + /// .long("verbose") + /// .short("v") + /// .global(true)) + /// .subcommand(SubCommand::with_name("test")) + /// .subcommand(SubCommand::with_name("do-stuff")) + /// .get_matches_from(vec![ + /// "prog", "do-stuff", "--verbose" + /// ]); + /// + /// assert_eq!(m.subcommand_name(), Some("do-stuff")); + /// let sub_m = m.subcommand_matches("do-stuff").unwrap(); + /// assert!(sub_m.is_present("verb")); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [required]: ./struct.Arg.html#method.required + /// [`ArgMatches`]: ./struct.ArgMatches.html + /// [`ArgMatches::is_present("flag")`]: ./struct.ArgMatches.html#method.is_present + /// [`Arg`]: ./struct.Arg.html + pub fn global(self, g: bool) -> Self { + if g { + self.set(ArgSettings::Global) + } else { + self.unset(ArgSettings::Global) + } + } + + /// Allows an argument to accept explicitly empty values. An empty value must be specified at + /// the command line with an explicit `""`, or `''` + /// + /// **NOTE:** Defaults to `true` (Explicitly empty values are allowed) + /// + /// **NOTE:** Implicitly sets [`Arg::takes_value(true)`] when set to `false` + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("file") + /// .long("file") + /// .empty_values(false) + /// # ; + /// ``` + /// The default is to allow empty values, such as `--option ""` would be an empty value. But + /// we can change to make empty values become an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .short("v") + /// .empty_values(false)) + /// .get_matches_from_safe(vec![ + /// "prog", "--config=" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); + /// ``` + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + pub fn empty_values(mut self, ev: bool) -> Self { + if ev { + self.set(ArgSettings::EmptyValues) + } else { + self = self.set(ArgSettings::TakesValue); + self.unset(ArgSettings::EmptyValues) + } + } + + /// Hides an argument from help message output. + /// + /// **NOTE:** Implicitly sets [`Arg::hidden_short_help(true)`] and [`Arg::hidden_long_help(true)`] + /// when set to true + /// + /// **NOTE:** This does **not** hide the argument from usage strings on error + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .hidden(true) + /// # ; + /// ``` + /// Setting `hidden(true)` will hide the argument when displaying help text + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .hidden(true) + /// .help("Some help text describing the --config arg")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// ``` + /// [`Arg::hidden_short_help(true)`]: ./struct.Arg.html#method.hidden_short_help + /// [`Arg::hidden_long_help(true)`]: ./struct.Arg.html#method.hidden_long_help + pub fn hidden(self, h: bool) -> Self { + if h { + self.set(ArgSettings::Hidden) + } else { + self.unset(ArgSettings::Hidden) + } + } + + /// Specifies a list of possible values for this argument. At runtime, `clap` verifies that + /// only one of the specified values was used, or fails with an error message. + /// + /// **NOTE:** This setting only applies to [options] and [positional arguments] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("mode") + /// .takes_value(true) + /// .possible_values(&["fast", "slow", "medium"]) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .takes_value(true) + /// .possible_values(&["fast", "slow", "medium"])) + /// .get_matches_from(vec![ + /// "prog", "--mode", "fast" + /// ]); + /// assert!(m.is_present("mode")); + /// assert_eq!(m.value_of("mode"), Some("fast")); + /// ``` + /// + /// The next example shows a failed parse from using a value which wasn't defined as one of the + /// possible values. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .takes_value(true) + /// .possible_values(&["fast", "slow", "medium"])) + /// .get_matches_from_safe(vec![ + /// "prog", "--mode", "wrong" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::InvalidValue); + /// ``` + /// [options]: ./struct.Arg.html#method.takes_value + /// [positional arguments]: ./struct.Arg.html#method.index + pub fn possible_values(mut self, names: &[&'b str]) -> Self { + if let Some(ref mut vec) = self.v.possible_vals { + for s in names { + vec.push(s); + } + } else { + self.v.possible_vals = Some(names.iter().copied().collect()); + } + self + } + + /// Specifies a possible value for this argument, one at a time. At runtime, `clap` verifies + /// that only one of the specified values was used, or fails with error message. + /// + /// **NOTE:** This setting only applies to [options] and [positional arguments] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("mode") + /// .takes_value(true) + /// .possible_value("fast") + /// .possible_value("slow") + /// .possible_value("medium") + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .takes_value(true) + /// .possible_value("fast") + /// .possible_value("slow") + /// .possible_value("medium")) + /// .get_matches_from(vec![ + /// "prog", "--mode", "fast" + /// ]); + /// assert!(m.is_present("mode")); + /// assert_eq!(m.value_of("mode"), Some("fast")); + /// ``` + /// + /// The next example shows a failed parse from using a value which wasn't defined as one of the + /// possible values. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .takes_value(true) + /// .possible_value("fast") + /// .possible_value("slow") + /// .possible_value("medium")) + /// .get_matches_from_safe(vec![ + /// "prog", "--mode", "wrong" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::InvalidValue); + /// ``` + /// [options]: ./struct.Arg.html#method.takes_value + /// [positional arguments]: ./struct.Arg.html#method.index + pub fn possible_value(mut self, name: &'b str) -> Self { + if let Some(ref mut vec) = self.v.possible_vals { + vec.push(name); + } else { + self.v.possible_vals = Some(vec![name]); + } + self + } + + /// When used with [`Arg::possible_values`] it allows the argument value to pass validation even if + /// the case differs from that of the specified `possible_value`. + /// + /// **Pro Tip:** Use this setting with [`arg_enum!`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// # use std::ascii::AsciiExt; + /// let m = App::new("pv") + /// .arg(Arg::with_name("option") + /// .long("--option") + /// .takes_value(true) + /// .possible_value("test123") + /// .case_insensitive(true)) + /// .get_matches_from(vec![ + /// "pv", "--option", "TeSt123", + /// ]); + /// + /// assert!(m.value_of("option").unwrap().eq_ignore_ascii_case("test123")); + /// ``` + /// + /// This setting also works when multiple values can be defined: + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("pv") + /// .arg(Arg::with_name("option") + /// .short("-o") + /// .long("--option") + /// .takes_value(true) + /// .possible_value("test123") + /// .possible_value("test321") + /// .multiple(true) + /// .case_insensitive(true)) + /// .get_matches_from(vec![ + /// "pv", "--option", "TeSt123", "teST123", "tESt321" + /// ]); + /// + /// let matched_vals = m.values_of("option").unwrap().collect::>(); + /// assert_eq!(&*matched_vals, &["TeSt123", "teST123", "tESt321"]); + /// ``` + /// [`Arg::case_insensitive(true)`]: ./struct.Arg.html#method.possible_values + /// [`arg_enum!`]: ./macro.arg_enum.html + pub fn case_insensitive(self, ci: bool) -> Self { + if ci { + self.set(ArgSettings::CaseInsensitive) + } else { + self.unset(ArgSettings::CaseInsensitive) + } + } + + /// Specifies the name of the [`ArgGroup`] the argument belongs to. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .long("debug") + /// .group("mode") + /// # ; + /// ``` + /// + /// Multiple arguments can be a member of a single group and then the group checked as if it + /// was one of said arguments. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("debug") + /// .long("debug") + /// .group("mode")) + /// .arg(Arg::with_name("verbose") + /// .long("verbose") + /// .group("mode")) + /// .get_matches_from(vec![ + /// "prog", "--debug" + /// ]); + /// assert!(m.is_present("mode")); + /// ``` + /// [`ArgGroup`]: ./struct.ArgGroup.html + pub fn group(mut self, name: &'a str) -> Self { + if let Some(ref mut vec) = self.b.groups { + vec.push(name); + } else { + self.b.groups = Some(vec![name]); + } + self + } + + /// Specifies the names of multiple [`ArgGroup`]'s the argument belongs to. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .long("debug") + /// .groups(&["mode", "verbosity"]) + /// # ; + /// ``` + /// + /// Arguments can be members of multiple groups and then the group checked as if it + /// was one of said arguments. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("debug") + /// .long("debug") + /// .groups(&["mode", "verbosity"])) + /// .arg(Arg::with_name("verbose") + /// .long("verbose") + /// .groups(&["mode", "verbosity"])) + /// .get_matches_from(vec![ + /// "prog", "--debug" + /// ]); + /// assert!(m.is_present("mode")); + /// assert!(m.is_present("verbosity")); + /// ``` + /// [`ArgGroup`]: ./struct.ArgGroup.html + pub fn groups(mut self, names: &[&'a str]) -> Self { + if let Some(ref mut vec) = self.b.groups { + for s in names { + vec.push(s); + } + } else { + self.b.groups = Some(names.iter().copied().collect()); + } + self + } + + /// Specifies how many values are required to satisfy this argument. For example, if you had a + /// `-f ` argument where you wanted exactly 3 'files' you would set + /// `.number_of_values(3)`, and this argument wouldn't be satisfied unless the user provided + /// 3 and only 3 values. + /// + /// **NOTE:** Does *not* require [`Arg::multiple(true)`] to be set. Setting + /// [`Arg::multiple(true)`] would allow `-f -f ` where + /// as *not* setting [`Arg::multiple(true)`] would only allow one occurrence of this argument. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("file") + /// .short("f") + /// .number_of_values(3) + /// # ; + /// ``` + /// + /// Not supplying the correct number of values is an error + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .takes_value(true) + /// .number_of_values(2) + /// .short("F")) + /// .get_matches_from_safe(vec![ + /// "prog", "-F", "file1" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::WrongNumberOfValues); + /// ``` + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + pub fn number_of_values(mut self, qty: u64) -> Self { + self.setb(ArgSettings::TakesValue); + self.v.num_vals = Some(qty); + self + } + + /// Allows one to perform a custom validation on the argument value. You provide a closure + /// which accepts a [`String`] value, and return a [`Result`] where the [`Err(String)`] is a + /// message displayed to the user. + /// + /// **NOTE:** The error message does *not* need to contain the `error:` portion, only the + /// message as all errors will appear as + /// `error: Invalid value for '': ` where `` is replaced by the actual + /// arg, and `` is the `String` you return as the error. + /// + /// **NOTE:** There is a small performance hit for using validators, as they are implemented + /// with [`Rc`] pointers. And the value to be checked will be allocated an extra time in order + /// to to be passed to the closure. This performance hit is extremely minimal in the grand + /// scheme of things. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// fn has_at(v: String) -> Result<(), String> { + /// if v.contains("@") { return Ok(()); } + /// Err(String::from("The value did not contain the required @ sigil")) + /// } + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .index(1) + /// .validator(has_at)) + /// .get_matches_from_safe(vec![ + /// "prog", "some@file" + /// ]); + /// assert!(res.is_ok()); + /// assert_eq!(res.unwrap().value_of("file"), Some("some@file")); + /// ``` + /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html + /// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html + /// [`Err(String)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err + /// [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html + pub fn validator(mut self, f: F) -> Self + where + F: Fn(String) -> Result<(), String> + 'static, + { + self.v.validator = Some(Rc::new(f)); + self + } + + /// Works identically to Validator but is intended to be used with values that could + /// contain non UTF-8 formatted strings. + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```rust")] + /// # use clap::{App, Arg}; + /// # use std::ffi::{OsStr, OsString}; + /// # use std::os::unix::ffi::OsStrExt; + /// fn has_ampersand(v: &OsStr) -> Result<(), OsString> { + /// if v.as_bytes().iter().any(|b| *b == b'&') { return Ok(()); } + /// Err(OsString::from("The value did not contain the required & sigil")) + /// } + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .index(1) + /// .validator_os(has_ampersand)) + /// .get_matches_from_safe(vec![ + /// "prog", "Fish & chips" + /// ]); + /// assert!(res.is_ok()); + /// assert_eq!(res.unwrap().value_of("file"), Some("Fish & chips")); + /// ``` + /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html + /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html + /// [`OsString`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html + /// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html + /// [`Err(String)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err + /// [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html + pub fn validator_os(mut self, f: F) -> Self + where + F: Fn(&OsStr) -> Result<(), OsString> + 'static, + { + self.v.validator_os = Some(Rc::new(f)); + self + } + + /// Specifies the *maximum* number of values are for this argument. For example, if you had a + /// `-f ` argument where you wanted up to 3 'files' you would set `.max_values(3)`, and + /// this argument would be satisfied if the user provided, 1, 2, or 3 values. + /// + /// **NOTE:** This does *not* implicitly set [`Arg::multiple(true)`]. This is because + /// `-o val -o val` is multiple occurrences but a single value and `-o val1 val2` is a single + /// occurrence with multiple values. For positional arguments this **does** set + /// [`Arg::multiple(true)`] because there is no way to determine the difference between multiple + /// occurrences and multiple values. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("file") + /// .short("f") + /// .max_values(3) + /// # ; + /// ``` + /// + /// Supplying less than the maximum number of values is allowed + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .takes_value(true) + /// .max_values(3) + /// .short("F")) + /// .get_matches_from_safe(vec![ + /// "prog", "-F", "file1", "file2" + /// ]); + /// + /// assert!(res.is_ok()); + /// let m = res.unwrap(); + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2"]); + /// ``` + /// + /// Supplying more than the maximum number of values is an error + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .takes_value(true) + /// .max_values(2) + /// .short("F")) + /// .get_matches_from_safe(vec![ + /// "prog", "-F", "file1", "file2", "file3" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::TooManyValues); + /// ``` + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + pub fn max_values(mut self, qty: u64) -> Self { + self.setb(ArgSettings::TakesValue); + self.v.max_vals = Some(qty); + self + } + + /// Specifies the *minimum* number of values for this argument. For example, if you had a + /// `-f ` argument where you wanted at least 2 'files' you would set + /// `.min_values(2)`, and this argument would be satisfied if the user provided, 2 or more + /// values. + /// + /// **NOTE:** This does not implicitly set [`Arg::multiple(true)`]. This is because + /// `-o val -o val` is multiple occurrences but a single value and `-o val1 val2` is a single + /// occurrence with multiple values. For positional arguments this **does** set + /// [`Arg::multiple(true)`] because there is no way to determine the difference between multiple + /// occurrences and multiple values. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("file") + /// .short("f") + /// .min_values(3) + /// # ; + /// ``` + /// + /// Supplying more than the minimum number of values is allowed + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .takes_value(true) + /// .min_values(2) + /// .short("F")) + /// .get_matches_from_safe(vec![ + /// "prog", "-F", "file1", "file2", "file3" + /// ]); + /// + /// assert!(res.is_ok()); + /// let m = res.unwrap(); + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3"]); + /// ``` + /// + /// Supplying less than the minimum number of values is an error + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .takes_value(true) + /// .min_values(2) + /// .short("F")) + /// .get_matches_from_safe(vec![ + /// "prog", "-F", "file1" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::TooFewValues); + /// ``` + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + pub fn min_values(mut self, qty: u64) -> Self { + self.v.min_vals = Some(qty); + self.set(ArgSettings::TakesValue) + } + + /// Specifies whether or not an argument should allow grouping of multiple values via a + /// delimiter. I.e. should `--option=val1,val2,val3` be parsed as three values (`val1`, `val2`, + /// and `val3`) or as a single value (`val1,val2,val3`). Defaults to using `,` (comma) as the + /// value delimiter for all arguments that accept values (options and positional arguments) + /// + /// **NOTE:** The default is `false`. When set to `true` the default [`Arg::value_delimiter`] + /// is the comma `,`. + /// + /// # Examples + /// + /// The following example shows the default behavior. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let delims = App::new("prog") + /// .arg(Arg::with_name("option") + /// .long("option") + /// .use_delimiter(true) + /// .takes_value(true)) + /// .get_matches_from(vec![ + /// "prog", "--option=val1,val2,val3", + /// ]); + /// + /// assert!(delims.is_present("option")); + /// assert_eq!(delims.occurrences_of("option"), 1); + /// assert_eq!(delims.values_of("option").unwrap().collect::>(), ["val1", "val2", "val3"]); + /// ``` + /// The next example shows the difference when turning delimiters off. This is the default + /// behavior + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let nodelims = App::new("prog") + /// .arg(Arg::with_name("option") + /// .long("option") + /// .use_delimiter(false) + /// .takes_value(true)) + /// .get_matches_from(vec![ + /// "prog", "--option=val1,val2,val3", + /// ]); + /// + /// assert!(nodelims.is_present("option")); + /// assert_eq!(nodelims.occurrences_of("option"), 1); + /// assert_eq!(nodelims.value_of("option").unwrap(), "val1,val2,val3"); + /// ``` + /// [`Arg::value_delimiter`]: ./struct.Arg.html#method.value_delimiter + pub fn use_delimiter(mut self, d: bool) -> Self { + if d { + if self.v.val_delim.is_none() { + self.v.val_delim = Some(','); + } + self.setb(ArgSettings::TakesValue); + self.setb(ArgSettings::UseValueDelimiter); + } else { + self.v.val_delim = None; + self.unsetb(ArgSettings::UseValueDelimiter); + } + self.unset(ArgSettings::ValueDelimiterNotSet) + } + + /// Specifies that *multiple values* may only be set using the delimiter. This means if an + /// if an option is encountered, and no delimiter is found, it automatically assumed that no + /// additional values for that option follow. This is unlike the default, where it is generally + /// assumed that more values will follow regardless of whether or not a delimiter is used. + /// + /// **NOTE:** The default is `false`. + /// + /// **NOTE:** Setting this to true implies [`Arg::use_delimiter(true)`] + /// + /// **NOTE:** It's a good idea to inform the user that use of a delimiter is required, either + /// through help text or other means. + /// + /// # Examples + /// + /// These examples demonstrate what happens when `require_delimiter(true)` is used. Notice + /// everything works in this first example, as we use a delimiter, as expected. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let delims = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .short("o") + /// .takes_value(true) + /// .multiple(true) + /// .require_delimiter(true)) + /// .get_matches_from(vec![ + /// "prog", "-o", "val1,val2,val3", + /// ]); + /// + /// assert!(delims.is_present("opt")); + /// assert_eq!(delims.values_of("opt").unwrap().collect::>(), ["val1", "val2", "val3"]); + /// ``` + /// In this next example, we will *not* use a delimiter. Notice it's now an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .short("o") + /// .takes_value(true) + /// .multiple(true) + /// .require_delimiter(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "-o", "val1", "val2", "val3", + /// ]); + /// + /// assert!(res.is_err()); + /// let err = res.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::UnknownArgument); + /// ``` + /// What's happening is `-o` is getting `val1`, and because delimiters are required yet none + /// were present, it stops parsing `-o`. At this point it reaches `val2` and because no + /// positional arguments have been defined, it's an error of an unexpected argument. + /// + /// In this final example, we contrast the above with `clap`'s default behavior where the above + /// is *not* an error. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let delims = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .short("o") + /// .takes_value(true) + /// .multiple(true)) + /// .get_matches_from(vec![ + /// "prog", "-o", "val1", "val2", "val3", + /// ]); + /// + /// assert!(delims.is_present("opt")); + /// assert_eq!(delims.values_of("opt").unwrap().collect::>(), ["val1", "val2", "val3"]); + /// ``` + /// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter + pub fn require_delimiter(mut self, d: bool) -> Self { + if d { + self = self.use_delimiter(true); + self.unsetb(ArgSettings::ValueDelimiterNotSet); + self.setb(ArgSettings::UseValueDelimiter); + self.set(ArgSettings::RequireDelimiter) + } else { + self = self.use_delimiter(false); + self.unsetb(ArgSettings::UseValueDelimiter); + self.unset(ArgSettings::RequireDelimiter) + } + } + + /// Specifies the separator to use when values are clumped together, defaults to `,` (comma). + /// + /// **NOTE:** implicitly sets [`Arg::use_delimiter(true)`] + /// + /// **NOTE:** implicitly sets [`Arg::takes_value(true)`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("config") + /// .short("c") + /// .long("config") + /// .value_delimiter(";")) + /// .get_matches_from(vec![ + /// "prog", "--config=val1;val2;val3" + /// ]); + /// + /// assert_eq!(m.values_of("config").unwrap().collect::>(), ["val1", "val2", "val3"]) + /// ``` + /// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + pub fn value_delimiter(mut self, d: &str) -> Self { + self.unsetb(ArgSettings::ValueDelimiterNotSet); + self.setb(ArgSettings::TakesValue); + self.setb(ArgSettings::UseValueDelimiter); + self.v.val_delim = Some( + d.chars() + .next() + .expect("Failed to get value_delimiter from arg"), + ); + self + } + + /// Specify multiple names for values of option arguments. These names are cosmetic only, used + /// for help and usage strings only. The names are **not** used to access arguments. The values + /// of the arguments are accessed in numeric order (i.e. if you specify two names `one` and + /// `two` `one` will be the first matched value, `two` will be the second). + /// + /// This setting can be very helpful when describing the type of input the user should be + /// using, such as `FILE`, `INTERFACE`, etc. Although not required, it's somewhat convention to + /// use all capital letters for the value name. + /// + /// **Pro Tip:** It may help to use [`Arg::next_line_help(true)`] if there are long, or + /// multiple value names in order to not throw off the help text alignment of all options. + /// + /// **NOTE:** This implicitly sets [`Arg::number_of_values`] if the number of value names is + /// greater than one. I.e. be aware that the number of "names" you set for the values, will be + /// the *exact* number of values required to satisfy this argument + /// + /// **NOTE:** implicitly sets [`Arg::takes_value(true)`] + /// + /// **NOTE:** Does *not* require or imply [`Arg::multiple(true)`]. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("speed") + /// .short("s") + /// .value_names(&["fast", "slow"]) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("io") + /// .long("io-files") + /// .value_names(&["INFILE", "OUTFILE"])) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// Running the above program produces the following output + /// + /// ```notrust + /// valnames + /// + /// USAGE: + /// valnames [FLAGS] [OPTIONS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// + /// OPTIONS: + /// --io-files Some help text + /// ``` + /// [`Arg::next_line_help(true)`]: ./struct.Arg.html#method.next_line_help + /// [`Arg::number_of_values`]: ./struct.Arg.html#method.number_of_values + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + pub fn value_names(mut self, names: &[&'b str]) -> Self { + self.setb(ArgSettings::TakesValue); + if self.is_set(ArgSettings::ValueDelimiterNotSet) { + self.unsetb(ArgSettings::ValueDelimiterNotSet); + self.setb(ArgSettings::UseValueDelimiter); + } + if let Some(ref mut vals) = self.v.val_names { + let mut l = vals.len(); + for s in names { + vals.insert(l, s); + l += 1; + } + } else { + let mut vm = VecMap::new(); + for (i, n) in names.iter().enumerate() { + vm.insert(i, *n); + } + self.v.val_names = Some(vm); + } + self + } + + /// Specifies the name for value of [option] or [positional] arguments inside of help + /// documentation. This name is cosmetic only, the name is **not** used to access arguments. + /// This setting can be very helpful when describing the type of input the user should be + /// using, such as `FILE`, `INTERFACE`, etc. Although not required, it's somewhat convention to + /// use all capital letters for the value name. + /// + /// **NOTE:** implicitly sets [`Arg::takes_value(true)`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("cfg") + /// .long("config") + /// .value_name("FILE") + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("config") + /// .long("config") + /// .value_name("FILE")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// Running the above program produces the following output + /// + /// ```notrust + /// valnames + /// + /// USAGE: + /// valnames [FLAGS] [OPTIONS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// + /// OPTIONS: + /// --config Some help text + /// ``` + /// [option]: ./struct.Arg.html#method.takes_value + /// [positional]: ./struct.Arg.html#method.index + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + pub fn value_name(mut self, name: &'b str) -> Self { + self.setb(ArgSettings::TakesValue); + if let Some(ref mut vals) = self.v.val_names { + let l = vals.len(); + vals.insert(l, name); + } else { + let mut vm = VecMap::new(); + vm.insert(0, name); + self.v.val_names = Some(vm); + } + self + } + + /// Specifies the value of the argument when *not* specified at runtime. + /// + /// **NOTE:** If the user *does not* use this argument at runtime, [`ArgMatches::occurrences_of`] + /// will return `0` even though the [`ArgMatches::value_of`] will return the default specified. + /// + /// **NOTE:** If the user *does not* use this argument at runtime [`ArgMatches::is_present`] will + /// still return `true`. If you wish to determine whether the argument was used at runtime or + /// not, consider [`ArgMatches::occurrences_of`] which will return `0` if the argument was *not* + /// used at runtime. + /// + /// **NOTE:** This setting is perfectly compatible with [`Arg::default_value_if`] but slightly + /// different. `Arg::default_value` *only* takes affect when the user has not provided this arg + /// at runtime. `Arg::default_value_if` however only takes affect when the user has not provided + /// a value at runtime **and** these other conditions are met as well. If you have set + /// `Arg::default_value` and `Arg::default_value_if`, and the user **did not** provide a this + /// arg at runtime, nor did were the conditions met for `Arg::default_value_if`, the + /// `Arg::default_value` will be applied. + /// + /// **NOTE:** This implicitly sets [`Arg::takes_value(true)`]. + /// + /// **NOTE:** This setting effectively disables `AppSettings::ArgRequiredElseHelp` if used in + /// conjunction as it ensures that some argument will always be present. + /// + /// # Examples + /// + /// First we use the default value without providing any value at runtime. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .long("myopt") + /// .default_value("myval")) + /// .get_matches_from(vec![ + /// "prog" + /// ]); + /// + /// assert_eq!(m.value_of("opt"), Some("myval")); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 0); + /// ``` + /// + /// Next we provide a value at runtime to override the default. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .long("myopt") + /// .default_value("myval")) + /// .get_matches_from(vec![ + /// "prog", "--myopt=non_default" + /// ]); + /// + /// assert_eq!(m.value_of("opt"), Some("non_default")); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 1); + /// ``` + /// [`ArgMatches::occurrences_of`]: ./struct.ArgMatches.html#method.occurrences_of + /// [`ArgMatches::value_of`]: ./struct.ArgMatches.html#method.value_of + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + /// [`ArgMatches::is_present`]: ./struct.ArgMatches.html#method.is_present + /// [`Arg::default_value_if`]: ./struct.Arg.html#method.default_value_if + pub fn default_value(self, val: &'a str) -> Self { + self.default_value_os(OsStr::from_bytes(val.as_bytes())) + } + + /// Provides a default value in the exact same manner as [`Arg::default_value`] + /// only using [`OsStr`]s instead. + /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value + /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html + pub fn default_value_os(mut self, val: &'a OsStr) -> Self { + self.setb(ArgSettings::TakesValue); + self.v.default_val = Some(val); + self + } + + /// Specifies the value of the argument if `arg` has been used at runtime. If `val` is set to + /// `None`, `arg` only needs to be present. If `val` is set to `"some-val"` then `arg` must be + /// present at runtime **and** have the value `val`. + /// + /// **NOTE:** This setting is perfectly compatible with [`Arg::default_value`] but slightly + /// different. `Arg::default_value` *only* takes affect when the user has not provided this arg + /// at runtime. This setting however only takes affect when the user has not provided a value at + /// runtime **and** these other conditions are met as well. If you have set `Arg::default_value` + /// and `Arg::default_value_if`, and the user **did not** provide a this arg at runtime, nor did + /// were the conditions met for `Arg::default_value_if`, the `Arg::default_value` will be + /// applied. + /// + /// **NOTE:** This implicitly sets [`Arg::takes_value(true)`]. + /// + /// **NOTE:** If using YAML the values should be laid out as follows (`None` can be represented + /// as `null` in YAML) + /// + /// ```yaml + /// default_value_if: + /// - [arg, val, default] + /// ``` + /// + /// # Examples + /// + /// First we use the default value only if another arg is present at runtime. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_if("flag", None, "default")) + /// .get_matches_from(vec![ + /// "prog", "--flag" + /// ]); + /// + /// assert_eq!(m.value_of("other"), Some("default")); + /// ``` + /// + /// Next we run the same test, but without providing `--flag`. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_if("flag", None, "default")) + /// .get_matches_from(vec![ + /// "prog" + /// ]); + /// + /// assert_eq!(m.value_of("other"), None); + /// ``` + /// + /// Now lets only use the default value if `--opt` contains the value `special`. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .takes_value(true) + /// .long("opt")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_if("opt", Some("special"), "default")) + /// .get_matches_from(vec![ + /// "prog", "--opt", "special" + /// ]); + /// + /// assert_eq!(m.value_of("other"), Some("default")); + /// ``` + /// + /// We can run the same test and provide any value *other than* `special` and we won't get a + /// default value. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .takes_value(true) + /// .long("opt")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_if("opt", Some("special"), "default")) + /// .get_matches_from(vec![ + /// "prog", "--opt", "hahaha" + /// ]); + /// + /// assert_eq!(m.value_of("other"), None); + /// ``` + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value + pub fn default_value_if(self, arg: &'a str, val: Option<&'b str>, default: &'b str) -> Self { + self.default_value_if_os( + arg, + val.map(str::as_bytes).map(OsStr::from_bytes), + OsStr::from_bytes(default.as_bytes()), + ) + } + + /// Provides a conditional default value in the exact same manner as [`Arg::default_value_if`] + /// only using [`OsStr`]s instead. + /// [`Arg::default_value_if`]: ./struct.Arg.html#method.default_value_if + /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html + pub fn default_value_if_os( + mut self, + arg: &'a str, + val: Option<&'b OsStr>, + default: &'b OsStr, + ) -> Self { + self.setb(ArgSettings::TakesValue); + if let Some(ref mut vm) = self.v.default_vals_ifs { + let l = vm.len(); + vm.insert(l, (arg, val, default)); + } else { + let mut vm = VecMap::new(); + vm.insert(0, (arg, val, default)); + self.v.default_vals_ifs = Some(vm); + } + self + } + + /// Specifies multiple values and conditions in the same manner as [`Arg::default_value_if`]. + /// The method takes a slice of tuples in the `(arg, Option, default)` format. + /// + /// **NOTE**: The conditions are stored in order and evaluated in the same order. I.e. the first + /// if multiple conditions are true, the first one found will be applied and the ultimate value. + /// + /// **NOTE:** If using YAML the values should be laid out as follows + /// + /// ```yaml + /// default_value_if: + /// - [arg, val, default] + /// - [arg2, null, default2] + /// ``` + /// + /// # Examples + /// + /// First we use the default value only if another arg is present at runtime. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag")) + /// .arg(Arg::with_name("opt") + /// .long("opt") + /// .takes_value(true)) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_ifs(&[ + /// ("flag", None, "default"), + /// ("opt", Some("channal"), "chan"), + /// ])) + /// .get_matches_from(vec![ + /// "prog", "--opt", "channal" + /// ]); + /// + /// assert_eq!(m.value_of("other"), Some("chan")); + /// ``` + /// + /// Next we run the same test, but without providing `--flag`. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_ifs(&[ + /// ("flag", None, "default"), + /// ("opt", Some("channal"), "chan"), + /// ])) + /// .get_matches_from(vec![ + /// "prog" + /// ]); + /// + /// assert_eq!(m.value_of("other"), None); + /// ``` + /// + /// We can also see that these values are applied in order, and if more than one condition is + /// true, only the first evaluated "wins" + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag")) + /// .arg(Arg::with_name("opt") + /// .long("opt") + /// .takes_value(true)) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_ifs(&[ + /// ("flag", None, "default"), + /// ("opt", Some("channal"), "chan"), + /// ])) + /// .get_matches_from(vec![ + /// "prog", "--opt", "channal", "--flag" + /// ]); + /// + /// assert_eq!(m.value_of("other"), Some("default")); + /// ``` + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value + pub fn default_value_ifs(mut self, ifs: &[(&'a str, Option<&'b str>, &'b str)]) -> Self { + for &(arg, val, default) in ifs { + self = self.default_value_if_os( + arg, + val.map(str::as_bytes).map(OsStr::from_bytes), + OsStr::from_bytes(default.as_bytes()), + ); + } + self + } + + /// Provides multiple conditional default values in the exact same manner as + /// [`Arg::default_value_ifs`] only using [`OsStr`]s instead. + /// [`Arg::default_value_ifs`]: ./struct.Arg.html#method.default_value_ifs + /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html + pub fn default_value_ifs_os(mut self, ifs: &[(&'a str, Option<&'b OsStr>, &'b OsStr)]) -> Self { + for &(arg, val, default) in ifs { + self = self.default_value_if_os(arg, val, default); + } + self + } + + /// Specifies that if the value is not passed in as an argument, that it should be retrieved + /// from the environment, if available. If it is not present in the environment, then default + /// rules will apply. + /// + /// **NOTE:** If the user *does not* use this argument at runtime, [`ArgMatches::occurrences_of`] + /// will return `0` even though the [`ArgMatches::value_of`] will return the default specified. + /// + /// **NOTE:** If the user *does not* use this argument at runtime [`ArgMatches::is_present`] will + /// return `true` if the variable is present in the environment . If you wish to determine whether + /// the argument was used at runtime or not, consider [`ArgMatches::occurrences_of`] which will + /// return `0` if the argument was *not* used at runtime. + /// + /// **NOTE:** This implicitly sets [`Arg::takes_value(true)`]. + /// + /// **NOTE:** If [`Arg::multiple(true)`] is set then [`Arg::use_delimiter(true)`] should also be + /// set. Otherwise, only a single argument will be returned from the environment variable. The + /// default delimiter is `,` and follows all the other delimiter rules. + /// + /// # Examples + /// + /// In this example, we show the variable coming from the environment: + /// + /// ```rust + /// # use std::env; + /// # use clap::{App, Arg}; + /// + /// env::set_var("MY_FLAG", "env"); + /// + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag") + /// .env("MY_FLAG")) + /// .get_matches_from(vec![ + /// "prog" + /// ]); + /// + /// assert_eq!(m.value_of("flag"), Some("env")); + /// ``` + /// + /// In this example, we show the variable coming from an option on the CLI: + /// + /// ```rust + /// # use std::env; + /// # use clap::{App, Arg}; + /// + /// env::set_var("MY_FLAG", "env"); + /// + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag") + /// .env("MY_FLAG")) + /// .get_matches_from(vec![ + /// "prog", "--flag", "opt" + /// ]); + /// + /// assert_eq!(m.value_of("flag"), Some("opt")); + /// ``` + /// + /// In this example, we show the variable coming from the environment even with the + /// presence of a default: + /// + /// ```rust + /// # use std::env; + /// # use clap::{App, Arg}; + /// + /// env::set_var("MY_FLAG", "env"); + /// + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag") + /// .env("MY_FLAG") + /// .default_value("default")) + /// .get_matches_from(vec![ + /// "prog" + /// ]); + /// + /// assert_eq!(m.value_of("flag"), Some("env")); + /// ``` + /// + /// In this example, we show the use of multiple values in a single environment variable: + /// + /// ```rust + /// # use std::env; + /// # use clap::{App, Arg}; + /// + /// env::set_var("MY_FLAG_MULTI", "env1,env2"); + /// + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag") + /// .env("MY_FLAG_MULTI") + /// .multiple(true) + /// .use_delimiter(true)) + /// .get_matches_from(vec![ + /// "prog" + /// ]); + /// + /// assert_eq!(m.values_of("flag").unwrap().collect::>(), vec!["env1", "env2"]); + /// ``` + /// [`ArgMatches::occurrences_of`]: ./struct.ArgMatches.html#method.occurrences_of + /// [`ArgMatches::value_of`]: ./struct.ArgMatches.html#method.value_of + /// [`ArgMatches::is_present`]: ./struct.ArgMatches.html#method.is_present + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + /// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter + pub fn env(self, name: &'a str) -> Self { + self.env_os(OsStr::new(name)) + } + + /// Specifies that if the value is not passed in as an argument, that it should be retrieved + /// from the environment if available in the exact same manner as [`Arg::env`] only using + /// [`OsStr`]s instead. + pub fn env_os(mut self, name: &'a OsStr) -> Self { + self.setb(ArgSettings::TakesValue); + + self.v.env = Some((name, env::var_os(name))); + self + } + + /// @TODO @p2 @docs @release: write docs + pub fn hide_env_values(self, hide: bool) -> Self { + if hide { + self.set(ArgSettings::HideEnvValues) + } else { + self.unset(ArgSettings::HideEnvValues) + } + } + + /// When set to `true` the help string will be displayed on the line after the argument and + /// indented once. This can be helpful for arguments with very long or complex help messages. + /// This can also be helpful for arguments with very long flag names, or many/long value names. + /// + /// **NOTE:** To apply this setting to all arguments consider using + /// [`AppSettings::NextLineHelp`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .long("long-option-flag") + /// .short("o") + /// .takes_value(true) + /// .value_names(&["value1", "value2"]) + /// .help("Some really long help and complex\n\ + /// help that makes more sense to be\n\ + /// on a line after the option") + /// .next_line_help(true)) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays the following help message + /// + /// ```notrust + /// nlh + /// + /// USAGE: + /// nlh [FLAGS] [OPTIONS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// + /// OPTIONS: + /// -o, --long-option-flag + /// Some really long help and complex + /// help that makes more sense to be + /// on a line after the option + /// ``` + /// [`AppSettings::NextLineHelp`]: ./enum.AppSettings.html#variant.NextLineHelp + pub fn next_line_help(mut self, nlh: bool) -> Self { + if nlh { + self.setb(ArgSettings::NextLineHelp); + } else { + self.unsetb(ArgSettings::NextLineHelp); + } + self + } + + /// Allows custom ordering of args within the help message. Args with a lower value will be + /// displayed first in the help message. This is helpful when one would like to emphasise + /// frequently used args, or prioritize those towards the top of the list. Duplicate values + /// **are** allowed. Args with duplicate display orders will be displayed in alphabetical + /// order. + /// + /// **NOTE:** The default is 999 for all arguments. + /// + /// **NOTE:** This setting is ignored for [positional arguments] which are always displayed in + /// [index] order. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("a") // Typically args are grouped alphabetically by name. + /// // Args without a display_order have a value of 999 and are + /// // displayed alphabetically with all other 999 valued args. + /// .long("long-option") + /// .short("o") + /// .takes_value(true) + /// .help("Some help and text")) + /// .arg(Arg::with_name("b") + /// .long("other-option") + /// .short("O") + /// .takes_value(true) + /// .display_order(1) // In order to force this arg to appear *first* + /// // all we have to do is give it a value lower than 999. + /// // Any other args with a value of 1 will be displayed + /// // alphabetically with this one...then 2 values, then 3, etc. + /// .help("I should be first!")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays the following help message + /// + /// ```notrust + /// cust-ord + /// + /// USAGE: + /// cust-ord [FLAGS] [OPTIONS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// + /// OPTIONS: + /// -O, --other-option I should be first! + /// -o, --long-option Some help and text + /// ``` + /// [positional arguments]: ./struct.Arg.html#method.index + /// [index]: ./struct.Arg.html#method.index + pub fn display_order(mut self, ord: usize) -> Self { + self.s.disp_ord = ord; + self + } + + /// Indicates that all parameters passed after this should not be parsed + /// individually, but rather passed in their entirety. It is worth noting + /// that setting this requires all values to come after a `--` to indicate they + /// should all be captured. For example: + /// + /// ```notrust + /// --foo something -- -v -v -v -b -b -b --baz -q -u -x + /// ``` + /// Will result in everything after `--` to be considered one raw argument. This behavior + /// may not be exactly what you are expecting and using [`AppSettings::TrailingVarArg`] + /// may be more appropriate. + /// + /// **NOTE:** Implicitly sets [`Arg::multiple(true)`], [`Arg::allow_hyphen_values(true)`], and + /// [`Arg::last(true)`] when set to `true` + /// + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + /// [`Arg::allow_hyphen_values(true)`]: ./struct.Arg.html#method.allow_hyphen_values + /// [`Arg::last(true)`]: ./struct.Arg.html#method.last + /// [`AppSettings::TrailingVarArg`]: ./enum.AppSettings.html#variant.TrailingVarArg + pub fn raw(self, raw: bool) -> Self { + self.multiple(raw).allow_hyphen_values(raw).last(raw) + } + + /// Hides an argument from short help message output. + /// + /// **NOTE:** This does **not** hide the argument from usage strings on error + /// + /// **NOTE:** Setting this option will cause next-line-help output style to be used + /// when long help (`--help`) is called. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .hidden_short_help(true) + /// # ; + /// ``` + /// Setting `hidden_short_help(true)` will hide the argument when displaying short help text + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .hidden_short_help(true) + /// .help("Some help text describing the --config arg")) + /// .get_matches_from(vec![ + /// "prog", "-h" + /// ]); + /// ``` + /// + /// The above example displays + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// ``` + /// + /// However, when --help is called + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .hidden_short_help(true) + /// .help("Some help text describing the --config arg")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// Then the following would be displayed + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// --config Some help text describing the --config arg + /// -h, --help Prints help information + /// -V, --version Prints version information + /// ``` + pub fn hidden_short_help(self, hide: bool) -> Self { + if hide { + self.set(ArgSettings::HiddenShortHelp) + } else { + self.unset(ArgSettings::HiddenShortHelp) + } + } + + /// Hides an argument from long help message output. + /// + /// **NOTE:** This does **not** hide the argument from usage strings on error + /// + /// **NOTE:** Setting this option will cause next-line-help output style to be used + /// when long help (`--help`) is called. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .hidden_long_help(true) + /// # ; + /// ``` + /// Setting `hidden_long_help(true)` will hide the argument when displaying long help text + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .hidden_long_help(true) + /// .help("Some help text describing the --config arg")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// ``` + /// + /// However, when -h is called + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .hidden_long_help(true) + /// .help("Some help text describing the --config arg")) + /// .get_matches_from(vec![ + /// "prog", "-h" + /// ]); + /// ``` + /// + /// Then the following would be displayed + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// --config Some help text describing the --config arg + /// -h, --help Prints help information + /// -V, --version Prints version information + /// ``` + pub fn hidden_long_help(self, hide: bool) -> Self { + if hide { + self.set(ArgSettings::HiddenLongHelp) + } else { + self.unset(ArgSettings::HiddenLongHelp) + } + } + + /// Checks if one of the [`ArgSettings`] settings is set for the argument. + /// + /// [`ArgSettings`]: ./enum.ArgSettings.html + pub fn is_set(&self, s: ArgSettings) -> bool { + self.b.is_set(s) + } + + /// Sets one of the [`ArgSettings`] settings for the argument. + /// + /// [`ArgSettings`]: ./enum.ArgSettings.html + pub fn set(mut self, s: ArgSettings) -> Self { + self.setb(s); + self + } + + /// Unsets one of the [`ArgSettings`] settings for the argument. + /// + /// [`ArgSettings`]: ./enum.ArgSettings.html + pub fn unset(mut self, s: ArgSettings) -> Self { + self.unsetb(s); + self + } + + #[doc(hidden)] + pub fn setb(&mut self, s: ArgSettings) { + self.b.set(s); + } + + #[doc(hidden)] + pub fn unsetb(&mut self, s: ArgSettings) { + self.b.unset(s); + } +} + +impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for Arg<'a, 'b> { + fn from(a: &'z Arg<'a, 'b>) -> Self { + Arg { + b: a.b.clone(), + v: a.v.clone(), + s: a.s.clone(), + index: a.index, + r_ifs: a.r_ifs.clone(), + } + } +} + +impl<'n, 'e> PartialEq for Arg<'n, 'e> { + fn eq(&self, other: &Arg<'n, 'e>) -> bool { + self.b == other.b + } +} diff --git a/vendor/clap-2.34.0/src/args/arg_builder/base.rs b/vendor/clap-2.34.0/src/args/arg_builder/base.rs new file mode 100644 index 0000000000000..ae1a2f6ad1dcd --- /dev/null +++ b/vendor/clap-2.34.0/src/args/arg_builder/base.rs @@ -0,0 +1,48 @@ +use crate::args::{Arg, ArgFlags, ArgSettings}; + +#[derive(Debug, Clone, Default)] +pub struct Base<'a, 'b> +where + 'a: 'b, +{ + pub name: &'a str, + pub help: Option<&'b str>, + pub long_help: Option<&'b str>, + pub blacklist: Option>, + pub settings: ArgFlags, + pub r_unless: Option>, + pub overrides: Option>, + pub groups: Option>, + pub requires: Option, &'a str)>>, +} + +impl<'n, 'e> Base<'n, 'e> { + pub fn new(name: &'n str) -> Self { + Base { + name, + ..Default::default() + } + } + + pub fn set(&mut self, s: ArgSettings) { + self.settings.set(s); + } + pub fn unset(&mut self, s: ArgSettings) { + self.settings.unset(s); + } + pub fn is_set(&self, s: ArgSettings) -> bool { + self.settings.is_set(s) + } +} + +impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Base<'n, 'e> { + fn from(a: &'z Arg<'n, 'e>) -> Self { + a.b.clone() + } +} + +impl<'n, 'e> PartialEq for Base<'n, 'e> { + fn eq(&self, other: &Base<'n, 'e>) -> bool { + self.name == other.name + } +} diff --git a/vendor/clap-2.34.0/src/args/arg_builder/flag.rs b/vendor/clap-2.34.0/src/args/arg_builder/flag.rs new file mode 100644 index 0000000000000..e991a6c460d57 --- /dev/null +++ b/vendor/clap-2.34.0/src/args/arg_builder/flag.rs @@ -0,0 +1,216 @@ +// Std +use std::{ + convert::From, + ffi::{OsStr, OsString}, + fmt::{Display, Formatter, Result}, + mem, + rc::Rc, + result::Result as StdResult, +}; + +// Internal +use crate::{ + args::{AnyArg, Arg, ArgSettings, Base, DispOrder, Switched}, + map::{self, VecMap}, +}; + +#[derive(Default, Clone, Debug)] +#[doc(hidden)] +pub struct FlagBuilder<'n, 'e> +where + 'n: 'e, +{ + pub b: Base<'n, 'e>, + pub s: Switched<'e>, +} + +impl<'n, 'e> FlagBuilder<'n, 'e> { + pub fn new(name: &'n str) -> Self { + FlagBuilder { + b: Base::new(name), + ..Default::default() + } + } +} + +impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> { + fn from(a: &'z Arg<'a, 'b>) -> Self { + FlagBuilder { + b: Base::from(a), + s: Switched::from(a), + } + } +} + +impl<'a, 'b> From> for FlagBuilder<'a, 'b> { + fn from(mut a: Arg<'a, 'b>) -> Self { + FlagBuilder { + b: mem::take(&mut a.b), + s: mem::take(&mut a.s), + } + } +} + +impl<'n, 'e> Display for FlagBuilder<'n, 'e> { + fn fmt(&self, f: &mut Formatter) -> Result { + if let Some(l) = self.s.long { + write!(f, "--{}", l)?; + } else { + write!(f, "-{}", self.s.short.unwrap())?; + } + + Ok(()) + } +} + +impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> { + fn name(&self) -> &'n str { + self.b.name + } + fn overrides(&self) -> Option<&[&'e str]> { + self.b.overrides.as_ref().map(|o| &o[..]) + } + fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { + self.b.requires.as_ref().map(|o| &o[..]) + } + fn blacklist(&self) -> Option<&[&'e str]> { + self.b.blacklist.as_ref().map(|o| &o[..]) + } + fn required_unless(&self) -> Option<&[&'e str]> { + self.b.r_unless.as_ref().map(|o| &o[..]) + } + fn is_set(&self, s: ArgSettings) -> bool { + self.b.settings.is_set(s) + } + fn has_switch(&self) -> bool { + true + } + fn takes_value(&self) -> bool { + false + } + fn set(&mut self, s: ArgSettings) { + self.b.settings.set(s) + } + fn max_vals(&self) -> Option { + None + } + fn val_names(&self) -> Option<&VecMap<&'e str>> { + None + } + fn num_vals(&self) -> Option { + None + } + fn possible_vals(&self) -> Option<&[&'e str]> { + None + } + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + fn validator(&self) -> Option<&Rc StdResult<(), String>>> { + None + } + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + fn validator_os(&self) -> Option<&Rc StdResult<(), OsString>>> { + None + } + fn min_vals(&self) -> Option { + None + } + fn short(&self) -> Option { + self.s.short + } + fn long(&self) -> Option<&'e str> { + self.s.long + } + fn val_delim(&self) -> Option { + None + } + fn help(&self) -> Option<&'e str> { + self.b.help + } + fn long_help(&self) -> Option<&'e str> { + self.b.long_help + } + fn val_terminator(&self) -> Option<&'e str> { + None + } + fn default_val(&self) -> Option<&'e OsStr> { + None + } + fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { + None + } + fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { + None + } + fn longest_filter(&self) -> bool { + self.s.long.is_some() + } + fn aliases(&self) -> Option> { + if let Some(ref aliases) = self.s.aliases { + let vis_aliases: Vec<_> = aliases + .iter() + .filter_map(|&(n, v)| if v { Some(n) } else { None }) + .collect(); + if vis_aliases.is_empty() { + None + } else { + Some(vis_aliases) + } + } else { + None + } + } +} + +impl<'n, 'e> DispOrder for FlagBuilder<'n, 'e> { + fn disp_ord(&self) -> usize { + self.s.disp_ord + } +} + +impl<'n, 'e> PartialEq for FlagBuilder<'n, 'e> { + fn eq(&self, other: &FlagBuilder<'n, 'e>) -> bool { + self.b == other.b + } +} + +#[cfg(test)] +mod test { + use super::FlagBuilder; + use crate::args::settings::ArgSettings; + + #[test] + fn flagbuilder_display() { + let mut f = FlagBuilder::new("flg"); + f.b.settings.set(ArgSettings::Multiple); + f.s.long = Some("flag"); + + assert_eq!(&*format!("{}", f), "--flag"); + + let mut f2 = FlagBuilder::new("flg"); + f2.s.short = Some('f'); + + assert_eq!(&*format!("{}", f2), "-f"); + } + + #[test] + fn flagbuilder_display_single_alias() { + let mut f = FlagBuilder::new("flg"); + f.s.long = Some("flag"); + f.s.aliases = Some(vec![("als", true)]); + + assert_eq!(&*format!("{}", f), "--flag"); + } + + #[test] + fn flagbuilder_display_multiple_aliases() { + let mut f = FlagBuilder::new("flg"); + f.s.short = Some('f'); + f.s.aliases = Some(vec![ + ("alias_not_visible", false), + ("f2", true), + ("f3", true), + ("f4", true), + ]); + assert_eq!(&*format!("{}", f), "-f"); + } +} diff --git a/vendor/clap-2.34.0/src/args/arg_builder/mod.rs b/vendor/clap-2.34.0/src/args/arg_builder/mod.rs new file mode 100644 index 0000000000000..2d7920819a5eb --- /dev/null +++ b/vendor/clap-2.34.0/src/args/arg_builder/mod.rs @@ -0,0 +1,13 @@ +pub use self::base::Base; +pub use self::flag::FlagBuilder; +pub use self::option::OptBuilder; +pub use self::positional::PosBuilder; +pub use self::switched::Switched; +pub use self::valued::Valued; + +mod base; +mod flag; +mod option; +mod positional; +mod switched; +mod valued; diff --git a/vendor/clap-2.34.0/src/args/arg_builder/option.rs b/vendor/clap-2.34.0/src/args/arg_builder/option.rs new file mode 100644 index 0000000000000..3894914f61dae --- /dev/null +++ b/vendor/clap-2.34.0/src/args/arg_builder/option.rs @@ -0,0 +1,295 @@ +// Std +use std::{ + ffi::{OsStr, OsString}, + fmt::{Display, Formatter, Result}, + mem, + rc::Rc, + result::Result as StdResult, +}; + +// Internal +use crate::{ + args::{AnyArg, Arg, ArgSettings, Base, DispOrder, Switched, Valued}, + map::{self, VecMap}, + INTERNAL_ERROR_MSG, +}; + +#[allow(missing_debug_implementations)] +#[doc(hidden)] +#[derive(Default, Clone)] +pub struct OptBuilder<'n, 'e> +where + 'n: 'e, +{ + pub b: Base<'n, 'e>, + pub s: Switched<'e>, + pub v: Valued<'n, 'e>, +} + +impl<'n, 'e> OptBuilder<'n, 'e> { + pub fn new(name: &'n str) -> Self { + OptBuilder { + b: Base::new(name), + ..Default::default() + } + } +} + +impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for OptBuilder<'n, 'e> { + fn from(a: &'z Arg<'n, 'e>) -> Self { + OptBuilder { + b: Base::from(a), + s: Switched::from(a), + v: Valued::from(a), + } + } +} + +impl<'n, 'e> From> for OptBuilder<'n, 'e> { + fn from(mut a: Arg<'n, 'e>) -> Self { + a.v.fill_in(); + OptBuilder { + b: mem::take(&mut a.b), + s: mem::take(&mut a.s), + v: mem::take(&mut a.v), + } + } +} + +impl<'n, 'e> Display for OptBuilder<'n, 'e> { + fn fmt(&self, f: &mut Formatter) -> Result { + debugln!("OptBuilder::fmt:{}", self.b.name); + let sep = if self.b.is_set(ArgSettings::RequireEquals) { + "=" + } else { + " " + }; + // Write the name such --long or -l + if let Some(l) = self.s.long { + write!(f, "--{}{}", l, sep)?; + } else { + write!(f, "-{}{}", self.s.short.unwrap(), sep)?; + } + let delim = if self.is_set(ArgSettings::RequireDelimiter) { + self.v.val_delim.expect(INTERNAL_ERROR_MSG) + } else { + ' ' + }; + + // Write the values such as + if let Some(ref vec) = self.v.val_names { + let mut it = vec.iter().peekable(); + while let Some((_, val)) = it.next() { + write!(f, "<{}>", val)?; + if it.peek().is_some() { + write!(f, "{}", delim)?; + } + } + let num = vec.len(); + if self.is_set(ArgSettings::Multiple) && num == 1 { + write!(f, "...")?; + } + } else if let Some(num) = self.v.num_vals { + let mut it = (0..num).peekable(); + while let Some(_) = it.next() { + write!(f, "<{}>", self.b.name)?; + if it.peek().is_some() { + write!(f, "{}", delim)?; + } + } + if self.is_set(ArgSettings::Multiple) && num == 1 { + write!(f, "...")?; + } + } else { + write!( + f, + "<{}>{}", + self.b.name, + if self.is_set(ArgSettings::Multiple) { + "..." + } else { + "" + } + )?; + } + + Ok(()) + } +} + +impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> { + fn name(&self) -> &'n str { + self.b.name + } + fn overrides(&self) -> Option<&[&'e str]> { + self.b.overrides.as_ref().map(|o| &o[..]) + } + fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { + self.b.requires.as_ref().map(|o| &o[..]) + } + fn blacklist(&self) -> Option<&[&'e str]> { + self.b.blacklist.as_ref().map(|o| &o[..]) + } + fn required_unless(&self) -> Option<&[&'e str]> { + self.b.r_unless.as_ref().map(|o| &o[..]) + } + fn val_names(&self) -> Option<&VecMap<&'e str>> { + self.v.val_names.as_ref() + } + fn is_set(&self, s: ArgSettings) -> bool { + self.b.settings.is_set(s) + } + fn has_switch(&self) -> bool { + true + } + fn set(&mut self, s: ArgSettings) { + self.b.settings.set(s) + } + fn max_vals(&self) -> Option { + self.v.max_vals + } + fn val_terminator(&self) -> Option<&'e str> { + self.v.terminator + } + fn num_vals(&self) -> Option { + self.v.num_vals + } + fn possible_vals(&self) -> Option<&[&'e str]> { + self.v.possible_vals.as_ref().map(|o| &o[..]) + } + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + fn validator(&self) -> Option<&Rc StdResult<(), String>>> { + self.v.validator.as_ref() + } + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + fn validator_os(&self) -> Option<&Rc StdResult<(), OsString>>> { + self.v.validator_os.as_ref() + } + fn min_vals(&self) -> Option { + self.v.min_vals + } + fn short(&self) -> Option { + self.s.short + } + fn long(&self) -> Option<&'e str> { + self.s.long + } + fn val_delim(&self) -> Option { + self.v.val_delim + } + fn takes_value(&self) -> bool { + true + } + fn help(&self) -> Option<&'e str> { + self.b.help + } + fn long_help(&self) -> Option<&'e str> { + self.b.long_help + } + fn default_val(&self) -> Option<&'e OsStr> { + self.v.default_val + } + fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { + self.v.default_vals_ifs.as_ref().map(|vm| vm.values()) + } + fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { + self.v + .env + .as_ref() + .map(|&(key, ref value)| (key, value.as_ref())) + } + fn longest_filter(&self) -> bool { + true + } + fn aliases(&self) -> Option> { + if let Some(ref aliases) = self.s.aliases { + let vis_aliases: Vec<_> = aliases + .iter() + .filter_map(|&(n, v)| if v { Some(n) } else { None }) + .collect(); + if vis_aliases.is_empty() { + None + } else { + Some(vis_aliases) + } + } else { + None + } + } +} + +impl<'n, 'e> DispOrder for OptBuilder<'n, 'e> { + fn disp_ord(&self) -> usize { + self.s.disp_ord + } +} + +impl<'n, 'e> PartialEq for OptBuilder<'n, 'e> { + fn eq(&self, other: &OptBuilder<'n, 'e>) -> bool { + self.b == other.b + } +} + +#[cfg(test)] +mod test { + use super::OptBuilder; + use crate::{args::settings::ArgSettings, map::VecMap}; + + #[test] + fn optbuilder_display1() { + let mut o = OptBuilder::new("opt"); + o.s.long = Some("option"); + o.b.settings.set(ArgSettings::Multiple); + + assert_eq!(&*format!("{}", o), "--option ..."); + } + + #[test] + fn optbuilder_display2() { + let mut v_names = VecMap::new(); + v_names.insert(0, "file"); + v_names.insert(1, "name"); + + let mut o2 = OptBuilder::new("opt"); + o2.s.short = Some('o'); + o2.v.val_names = Some(v_names); + + assert_eq!(&*format!("{}", o2), "-o "); + } + + #[test] + fn optbuilder_display3() { + let mut v_names = VecMap::new(); + v_names.insert(0, "file"); + v_names.insert(1, "name"); + + let mut o2 = OptBuilder::new("opt"); + o2.s.short = Some('o'); + o2.v.val_names = Some(v_names); + o2.b.settings.set(ArgSettings::Multiple); + + assert_eq!(&*format!("{}", o2), "-o "); + } + + #[test] + fn optbuilder_display_single_alias() { + let mut o = OptBuilder::new("opt"); + o.s.long = Some("option"); + o.s.aliases = Some(vec![("als", true)]); + + assert_eq!(&*format!("{}", o), "--option "); + } + + #[test] + fn optbuilder_display_multiple_aliases() { + let mut o = OptBuilder::new("opt"); + o.s.long = Some("option"); + o.s.aliases = Some(vec![ + ("als_not_visible", false), + ("als2", true), + ("als3", true), + ("als4", true), + ]); + assert_eq!(&*format!("{}", o), "--option "); + } +} diff --git a/vendor/clap-2.34.0/src/args/arg_builder/positional.rs b/vendor/clap-2.34.0/src/args/arg_builder/positional.rs new file mode 100644 index 0000000000000..9699fb6f50a56 --- /dev/null +++ b/vendor/clap-2.34.0/src/args/arg_builder/positional.rs @@ -0,0 +1,284 @@ +// Std +use std::{ + borrow::Cow, + ffi::{OsStr, OsString}, + fmt::{Display, Formatter, Result}, + mem, + rc::Rc, + result::Result as StdResult, +}; + +// Internal +use crate::{ + args::{AnyArg, Arg, ArgSettings, Base, DispOrder, Valued}, + map::{self, VecMap}, + INTERNAL_ERROR_MSG, +}; + +#[allow(missing_debug_implementations)] +#[doc(hidden)] +#[derive(Clone, Default)] +pub struct PosBuilder<'n, 'e> +where + 'n: 'e, +{ + pub b: Base<'n, 'e>, + pub v: Valued<'n, 'e>, + pub index: u64, +} + +impl<'n, 'e> PosBuilder<'n, 'e> { + pub fn new(name: &'n str, idx: u64) -> Self { + PosBuilder { + b: Base::new(name), + index: idx, + ..Default::default() + } + } + + pub fn from_arg_ref(a: &Arg<'n, 'e>, idx: u64) -> Self { + let mut pb = PosBuilder { + b: Base::from(a), + v: Valued::from(a), + index: idx, + }; + if a.v.max_vals.is_some() + || a.v.min_vals.is_some() + || (a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1) + { + pb.b.settings.set(ArgSettings::Multiple); + } + pb + } + + pub fn from_arg(mut a: Arg<'n, 'e>, idx: u64) -> Self { + if a.v.max_vals.is_some() + || a.v.min_vals.is_some() + || (a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1) + { + a.b.settings.set(ArgSettings::Multiple); + } + PosBuilder { + b: mem::take(&mut a.b), + v: mem::take(&mut a.v), + index: idx, + } + } + + pub fn multiple_str(&self) -> &str { + let mult_vals = self + .v + .val_names + .as_ref() + .map_or(true, |names| names.len() < 2); + if self.is_set(ArgSettings::Multiple) && mult_vals { + "..." + } else { + "" + } + } + + pub fn name_no_brackets(&self) -> Cow { + debugln!("PosBuilder::name_no_brackets;"); + let mut delim = String::new(); + delim.push(if self.is_set(ArgSettings::RequireDelimiter) { + self.v.val_delim.expect(INTERNAL_ERROR_MSG) + } else { + ' ' + }); + if let Some(ref names) = self.v.val_names { + debugln!("PosBuilder:name_no_brackets: val_names={:#?}", names); + if names.len() > 1 { + Cow::Owned( + names + .values() + .map(|n| format!("<{}>", n)) + .collect::>() + .join(&*delim), + ) + } else { + Cow::Borrowed(names.values().next().expect(INTERNAL_ERROR_MSG)) + } + } else { + debugln!("PosBuilder:name_no_brackets: just name"); + Cow::Borrowed(self.b.name) + } + } +} + +impl<'n, 'e> Display for PosBuilder<'n, 'e> { + fn fmt(&self, f: &mut Formatter) -> Result { + let mut delim = String::new(); + delim.push(if self.is_set(ArgSettings::RequireDelimiter) { + self.v.val_delim.expect(INTERNAL_ERROR_MSG) + } else { + ' ' + }); + if let Some(ref names) = self.v.val_names { + write!( + f, + "{}", + names + .values() + .map(|n| format!("<{}>", n)) + .collect::>() + .join(&*delim) + )?; + } else { + write!(f, "<{}>", self.b.name)?; + } + if self.b.settings.is_set(ArgSettings::Multiple) + && (self.v.val_names.is_none() || self.v.val_names.as_ref().unwrap().len() == 1) + { + write!(f, "...")?; + } + + Ok(()) + } +} + +impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> { + fn name(&self) -> &'n str { + self.b.name + } + fn overrides(&self) -> Option<&[&'e str]> { + self.b.overrides.as_ref().map(|o| &o[..]) + } + fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { + self.b.requires.as_ref().map(|o| &o[..]) + } + fn blacklist(&self) -> Option<&[&'e str]> { + self.b.blacklist.as_ref().map(|o| &o[..]) + } + fn required_unless(&self) -> Option<&[&'e str]> { + self.b.r_unless.as_ref().map(|o| &o[..]) + } + fn val_names(&self) -> Option<&VecMap<&'e str>> { + self.v.val_names.as_ref() + } + fn is_set(&self, s: ArgSettings) -> bool { + self.b.settings.is_set(s) + } + fn set(&mut self, s: ArgSettings) { + self.b.settings.set(s) + } + fn has_switch(&self) -> bool { + false + } + fn max_vals(&self) -> Option { + self.v.max_vals + } + fn val_terminator(&self) -> Option<&'e str> { + self.v.terminator + } + fn num_vals(&self) -> Option { + self.v.num_vals + } + fn possible_vals(&self) -> Option<&[&'e str]> { + self.v.possible_vals.as_ref().map(|o| &o[..]) + } + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + fn validator(&self) -> Option<&Rc StdResult<(), String>>> { + self.v.validator.as_ref() + } + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + fn validator_os(&self) -> Option<&Rc StdResult<(), OsString>>> { + self.v.validator_os.as_ref() + } + fn min_vals(&self) -> Option { + self.v.min_vals + } + fn short(&self) -> Option { + None + } + fn long(&self) -> Option<&'e str> { + None + } + fn val_delim(&self) -> Option { + self.v.val_delim + } + fn takes_value(&self) -> bool { + true + } + fn help(&self) -> Option<&'e str> { + self.b.help + } + fn long_help(&self) -> Option<&'e str> { + self.b.long_help + } + fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { + self.v.default_vals_ifs.as_ref().map(|vm| vm.values()) + } + fn default_val(&self) -> Option<&'e OsStr> { + self.v.default_val + } + fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { + self.v + .env + .as_ref() + .map(|&(key, ref value)| (key, value.as_ref())) + } + fn longest_filter(&self) -> bool { + true + } + fn aliases(&self) -> Option> { + None + } +} + +impl<'n, 'e> DispOrder for PosBuilder<'n, 'e> { + fn disp_ord(&self) -> usize { + self.index as usize + } +} + +impl<'n, 'e> PartialEq for PosBuilder<'n, 'e> { + fn eq(&self, other: &PosBuilder<'n, 'e>) -> bool { + self.b == other.b + } +} + +#[cfg(test)] +mod test { + use super::PosBuilder; + use crate::{args::settings::ArgSettings, map::VecMap}; + + #[test] + fn display_mult() { + let mut p = PosBuilder::new("pos", 1); + p.b.settings.set(ArgSettings::Multiple); + + assert_eq!(&*format!("{}", p), "..."); + } + + #[test] + fn display_required() { + let mut p2 = PosBuilder::new("pos", 1); + p2.b.settings.set(ArgSettings::Required); + + assert_eq!(&*format!("{}", p2), ""); + } + + #[test] + fn display_val_names() { + let mut p2 = PosBuilder::new("pos", 1); + let mut vm = VecMap::new(); + vm.insert(0, "file1"); + vm.insert(1, "file2"); + p2.v.val_names = Some(vm); + + assert_eq!(&*format!("{}", p2), " "); + } + + #[test] + fn display_val_names_req() { + let mut p2 = PosBuilder::new("pos", 1); + p2.b.settings.set(ArgSettings::Required); + let mut vm = VecMap::new(); + vm.insert(0, "file1"); + vm.insert(1, "file2"); + p2.v.val_names = Some(vm); + + assert_eq!(&*format!("{}", p2), " "); + } +} diff --git a/vendor/clap-2.34.0/src/args/arg_builder/switched.rs b/vendor/clap-2.34.0/src/args/arg_builder/switched.rs new file mode 100644 index 0000000000000..78af669aff7c0 --- /dev/null +++ b/vendor/clap-2.34.0/src/args/arg_builder/switched.rs @@ -0,0 +1,40 @@ +use crate::Arg; + +#[derive(Debug)] +pub struct Switched<'b> { + pub short: Option, + pub long: Option<&'b str>, + pub aliases: Option>, // (name, visible) + pub disp_ord: usize, + pub unified_ord: usize, +} + +impl<'e> Default for Switched<'e> { + fn default() -> Self { + Switched { + short: None, + long: None, + aliases: None, + disp_ord: 999, + unified_ord: 999, + } + } +} + +impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Switched<'e> { + fn from(a: &'z Arg<'n, 'e>) -> Self { + a.s.clone() + } +} + +impl<'e> Clone for Switched<'e> { + fn clone(&self) -> Self { + Switched { + short: self.short, + long: self.long, + aliases: self.aliases.clone(), + disp_ord: self.disp_ord, + unified_ord: self.unified_ord, + } + } +} diff --git a/vendor/clap-2.34.0/src/args/arg_builder/valued.rs b/vendor/clap-2.34.0/src/args/arg_builder/valued.rs new file mode 100644 index 0000000000000..ae659f7ed77cf --- /dev/null +++ b/vendor/clap-2.34.0/src/args/arg_builder/valued.rs @@ -0,0 +1,70 @@ +use std::{ + ffi::{OsStr, OsString}, + rc::Rc, +}; + +use crate::{map::VecMap, Arg}; + +#[allow(missing_debug_implementations)] +#[derive(Clone)] +pub struct Valued<'a, 'b> +where + 'a: 'b, +{ + pub possible_vals: Option>, + pub val_names: Option>, + pub num_vals: Option, + pub max_vals: Option, + pub min_vals: Option, + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + pub validator: Option Result<(), String>>>, + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + pub validator_os: Option Result<(), OsString>>>, + pub val_delim: Option, + pub default_val: Option<&'b OsStr>, + #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + pub default_vals_ifs: Option, &'b OsStr)>>, + pub env: Option<(&'a OsStr, Option)>, + pub terminator: Option<&'b str>, +} + +impl<'n, 'e> Default for Valued<'n, 'e> { + fn default() -> Self { + Valued { + possible_vals: None, + num_vals: None, + min_vals: None, + max_vals: None, + val_names: None, + validator: None, + validator_os: None, + val_delim: None, + default_val: None, + default_vals_ifs: None, + env: None, + terminator: None, + } + } +} + +impl<'n, 'e> Valued<'n, 'e> { + pub fn fill_in(&mut self) { + if let Some(ref vec) = self.val_names { + if vec.len() > 1 { + self.num_vals = Some(vec.len() as u64); + } + } + } +} + +impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Valued<'n, 'e> { + fn from(a: &'z Arg<'n, 'e>) -> Self { + let mut v = a.v.clone(); + if let Some(ref vec) = a.v.val_names { + if vec.len() > 1 { + v.num_vals = Some(vec.len() as u64); + } + } + v + } +} diff --git a/vendor/clap-2.34.0/src/args/arg_matcher.rs b/vendor/clap-2.34.0/src/args/arg_matcher.rs new file mode 100644 index 0000000000000..5034dcc082078 --- /dev/null +++ b/vendor/clap-2.34.0/src/args/arg_matcher.rs @@ -0,0 +1,274 @@ +// Std +use std::{ + collections::{ + hash_map::{Entry, Iter}, + HashMap, + }, + ffi::OsStr, + mem, + ops::Deref, +}; + +// Internal +use crate::args::{settings::ArgSettings, AnyArg, ArgMatches, MatchedArg, SubCommand}; + +#[doc(hidden)] +#[allow(missing_debug_implementations)] +pub struct ArgMatcher<'a>(pub ArgMatches<'a>); + +impl<'a> Default for ArgMatcher<'a> { + fn default() -> Self { + ArgMatcher(ArgMatches::default()) + } +} + +impl<'a> ArgMatcher<'a> { + pub fn new() -> Self { + ArgMatcher::default() + } + + pub fn process_arg_overrides<'b>( + &mut self, + a: Option<&AnyArg<'a, 'b>>, + overrides: &mut Vec<(&'b str, &'a str)>, + required: &mut Vec<&'a str>, + check_all: bool, + ) { + debugln!( + "ArgMatcher::process_arg_overrides:{:?};", + a.map_or(None, |a| Some(a.name())) + ); + if let Some(aa) = a { + let mut self_done = false; + if let Some(a_overrides) = aa.overrides() { + for overr in a_overrides { + debugln!("ArgMatcher::process_arg_overrides:iter:{};", overr); + if overr == &aa.name() { + self_done = true; + self.handle_self_overrides(a); + } else if self.is_present(overr) { + debugln!( + "ArgMatcher::process_arg_overrides:iter:{}: removing from matches;", + overr + ); + self.remove(overr); + for i in (0..required.len()).rev() { + if &required[i] == overr { + debugln!( + "ArgMatcher::process_arg_overrides:iter:{}: removing required;", + overr + ); + required.swap_remove(i); + break; + } + } + overrides.push((overr, aa.name())); + } else { + overrides.push((overr, aa.name())); + } + } + } + if check_all && !self_done { + self.handle_self_overrides(a); + } + } + } + + pub fn handle_self_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>) { + debugln!( + "ArgMatcher::handle_self_overrides:{:?};", + a.map_or(None, |a| Some(a.name())) + ); + if let Some(aa) = a { + if !aa.has_switch() || aa.is_set(ArgSettings::Multiple) { + // positional args can't override self or else we would never advance to the next + + // Also flags with --multiple set are ignored otherwise we could never have more + // than one + return; + } + if let Some(ma) = self.get_mut(aa.name()) { + if ma.vals.len() > 1 { + // swap_remove(0) would be O(1) but does not preserve order, which + // we need + ma.vals.remove(0); + ma.occurs = 1; + } else if !aa.takes_value() && ma.occurs > 1 { + ma.occurs = 1; + } + } + } + } + + pub fn is_present(&self, name: &str) -> bool { + self.0.is_present(name) + } + + pub fn propagate_globals(&mut self, global_arg_vec: &[&'a str]) { + debugln!( + "ArgMatcher::get_global_values: global_arg_vec={:?}", + global_arg_vec + ); + let mut vals_map = HashMap::new(); + self.fill_in_global_values(global_arg_vec, &mut vals_map); + } + + fn fill_in_global_values( + &mut self, + global_arg_vec: &[&'a str], + vals_map: &mut HashMap<&'a str, MatchedArg>, + ) { + for global_arg in global_arg_vec { + if let Some(ma) = self.get(global_arg) { + // We have to check if the parent's global arg wasn't used but still exists + // such as from a default value. + // + // For example, `myprog subcommand --global-arg=value` where --global-arg defines + // a default value of `other` myprog would have an existing MatchedArg for + // --global-arg where the value is `other`, however the occurs will be 0. + let to_update = if let Some(parent_ma) = vals_map.get(global_arg) { + if parent_ma.occurs > 0 && ma.occurs == 0 { + parent_ma.clone() + } else { + ma.clone() + } + } else { + ma.clone() + }; + vals_map.insert(global_arg, to_update); + } + } + if let Some(ref mut sc) = self.0.subcommand { + let mut am = ArgMatcher(mem::replace(&mut sc.matches, ArgMatches::new())); + am.fill_in_global_values(global_arg_vec, vals_map); + mem::swap(&mut am.0, &mut sc.matches); + } + + for (name, matched_arg) in vals_map.iter_mut() { + self.0.args.insert(name, matched_arg.clone()); + } + } + + pub fn get_mut(&mut self, arg: &str) -> Option<&mut MatchedArg> { + self.0.args.get_mut(arg) + } + + pub fn get(&self, arg: &str) -> Option<&MatchedArg> { + self.0.args.get(arg) + } + + pub fn remove(&mut self, arg: &str) { + self.0.args.remove(arg); + } + + pub fn remove_all(&mut self, args: &[&str]) { + for &arg in args { + self.0.args.remove(arg); + } + } + + pub fn insert(&mut self, name: &'a str) { + self.0.args.insert(name, MatchedArg::new()); + } + + pub fn contains(&self, arg: &str) -> bool { + self.0.args.contains_key(arg) + } + + pub fn is_empty(&self) -> bool { + self.0.args.is_empty() + } + + pub fn usage(&mut self, usage: String) { + self.0.usage = Some(usage); + } + + pub fn arg_names(&'a self) -> Vec<&'a str> { + self.0.args.keys().map(Deref::deref).collect() + } + + pub fn entry(&mut self, arg: &'a str) -> Entry<&'a str, MatchedArg> { + self.0.args.entry(arg) + } + + pub fn subcommand(&mut self, sc: SubCommand<'a>) { + self.0.subcommand = Some(Box::new(sc)); + } + + pub fn subcommand_name(&self) -> Option<&str> { + self.0.subcommand_name() + } + + pub fn iter(&self) -> Iter<&str, MatchedArg> { + self.0.args.iter() + } + + pub fn inc_occurrence_of(&mut self, arg: &'a str) { + debugln!("ArgMatcher::inc_occurrence_of: arg={}", arg); + if let Some(a) = self.get_mut(arg) { + a.occurs += 1; + return; + } + debugln!("ArgMatcher::inc_occurrence_of: first instance"); + self.insert(arg); + } + + pub fn inc_occurrences_of(&mut self, args: &[&'a str]) { + debugln!("ArgMatcher::inc_occurrences_of: args={:?}", args); + for arg in args { + self.inc_occurrence_of(arg); + } + } + + pub fn add_val_to(&mut self, arg: &'a str, val: &OsStr) { + let ma = self.entry(arg).or_insert(MatchedArg { + occurs: 0, + indices: Vec::with_capacity(1), + vals: Vec::with_capacity(1), + }); + ma.vals.push(val.to_owned()); + } + + pub fn add_index_to(&mut self, arg: &'a str, idx: usize) { + let ma = self.entry(arg).or_insert(MatchedArg { + occurs: 0, + indices: Vec::with_capacity(1), + vals: Vec::new(), + }); + ma.indices.push(idx); + } + + pub fn needs_more_vals<'b, A>(&self, o: &A) -> bool + where + A: AnyArg<'a, 'b>, + { + debugln!("ArgMatcher::needs_more_vals: o={}", o.name()); + if let Some(ma) = self.get(o.name()) { + if let Some(num) = o.num_vals() { + debugln!("ArgMatcher::needs_more_vals: num_vals...{}", num); + return if o.is_set(ArgSettings::Multiple) { + ((ma.vals.len() as u64) % num) != 0 + } else { + num != (ma.vals.len() as u64) + }; + } else if let Some(num) = o.max_vals() { + debugln!("ArgMatcher::needs_more_vals: max_vals...{}", num); + return (ma.vals.len() as u64) <= num; + } else if o.min_vals().is_some() { + debugln!("ArgMatcher::needs_more_vals: min_vals...true"); + return true; + } + return o.is_set(ArgSettings::Multiple); + } + true + } +} + +// Not changing to From just to not deal with possible breaking changes on v2 since v3 is coming +// in the future anyways +#[cfg_attr(feature = "cargo-clippy", allow(clippy::from_over_into))] +impl<'a> Into> for ArgMatcher<'a> { + fn into(self) -> ArgMatches<'a> { + self.0 + } +} diff --git a/vendor/clap-2.34.0/src/args/arg_matches.rs b/vendor/clap-2.34.0/src/args/arg_matches.rs new file mode 100644 index 0000000000000..a2c3231ae0d85 --- /dev/null +++ b/vendor/clap-2.34.0/src/args/arg_matches.rs @@ -0,0 +1,1001 @@ +// Std +use std::{ + borrow::Cow, + collections::HashMap, + ffi::{OsStr, OsString}, + iter::Map, + slice::Iter, +}; + +// Internal +use crate::{ + args::{MatchedArg, SubCommand}, + INVALID_UTF8, +}; + +/// Used to get information about the arguments that were supplied to the program at runtime by +/// the user. New instances of this struct are obtained by using the [`App::get_matches`] family of +/// methods. +/// +/// # Examples +/// +/// ```no_run +/// # use clap::{App, Arg}; +/// let matches = App::new("MyApp") +/// .arg(Arg::with_name("out") +/// .long("output") +/// .required(true) +/// .takes_value(true)) +/// .arg(Arg::with_name("debug") +/// .short("d") +/// .multiple(true)) +/// .arg(Arg::with_name("cfg") +/// .short("c") +/// .takes_value(true)) +/// .get_matches(); // builds the instance of ArgMatches +/// +/// // to get information about the "cfg" argument we created, such as the value supplied we use +/// // various ArgMatches methods, such as ArgMatches::value_of +/// if let Some(c) = matches.value_of("cfg") { +/// println!("Value for -c: {}", c); +/// } +/// +/// // The ArgMatches::value_of method returns an Option because the user may not have supplied +/// // that argument at runtime. But if we specified that the argument was "required" as we did +/// // with the "out" argument, we can safely unwrap because `clap` verifies that was actually +/// // used at runtime. +/// println!("Value for --output: {}", matches.value_of("out").unwrap()); +/// +/// // You can check the presence of an argument +/// if matches.is_present("out") { +/// // Another way to check if an argument was present, or if it occurred multiple times is to +/// // use occurrences_of() which returns 0 if an argument isn't found at runtime, or the +/// // number of times that it occurred, if it was. To allow an argument to appear more than +/// // once, you must use the .multiple(true) method, otherwise it will only return 1 or 0. +/// if matches.occurrences_of("debug") > 2 { +/// println!("Debug mode is REALLY on, don't be crazy"); +/// } else { +/// println!("Debug mode kind of on"); +/// } +/// } +/// ``` +/// [`App::get_matches`]: ./struct.App.html#method.get_matches +#[derive(Debug, Clone)] +pub struct ArgMatches<'a> { + #[doc(hidden)] + pub args: HashMap<&'a str, MatchedArg>, + #[doc(hidden)] + pub subcommand: Option>>, + #[doc(hidden)] + pub usage: Option, +} + +impl<'a> Default for ArgMatches<'a> { + fn default() -> Self { + ArgMatches { + args: HashMap::new(), + subcommand: None, + usage: None, + } + } +} + +impl<'a> ArgMatches<'a> { + #[doc(hidden)] + pub fn new() -> Self { + ArgMatches { + ..Default::default() + } + } + + /// Gets the value of a specific [option] or [positional] argument (i.e. an argument that takes + /// an additional value at runtime). If the option wasn't present at runtime + /// it returns `None`. + /// + /// *NOTE:* If getting a value for an option or positional argument that allows multiples, + /// prefer [`ArgMatches::values_of`] as `ArgMatches::value_of` will only return the *first* + /// value. + /// + /// # Panics + /// + /// This method will [`panic!`] if the value contains invalid UTF-8 code points. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("output") + /// .takes_value(true)) + /// .get_matches_from(vec!["myapp", "something"]); + /// + /// assert_eq!(m.value_of("output"), Some("something")); + /// ``` + /// [option]: ./struct.Arg.html#method.takes_value + /// [positional]: ./struct.Arg.html#method.index + /// [`ArgMatches::values_of`]: ./struct.ArgMatches.html#method.values_of + /// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html + pub fn value_of>(&self, name: S) -> Option<&str> { + if let Some(arg) = self.args.get(name.as_ref()) { + if let Some(v) = arg.vals.get(0) { + return Some(v.to_str().expect(INVALID_UTF8)); + } + } + None + } + + /// Gets the lossy value of a specific argument. If the argument wasn't present at runtime + /// it returns `None`. A lossy value is one which contains invalid UTF-8 code points, those + /// invalid points will be replaced with `\u{FFFD}` + /// + /// *NOTE:* If getting a value for an option or positional argument that allows multiples, + /// prefer [`Arg::values_of_lossy`] as `value_of_lossy()` will only return the *first* value. + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, Arg}; + /// use std::ffi::OsString; + /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; + /// + /// let m = App::new("utf8") + /// .arg(Arg::from_usage(" 'some arg'")) + /// .get_matches_from(vec![OsString::from("myprog"), + /// // "Hi {0xe9}!" + /// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]); + /// assert_eq!(&*m.value_of_lossy("arg").unwrap(), "Hi \u{FFFD}!"); + /// ``` + /// [`Arg::values_of_lossy`]: ./struct.ArgMatches.html#method.values_of_lossy + pub fn value_of_lossy>(&'a self, name: S) -> Option> { + if let Some(arg) = self.args.get(name.as_ref()) { + if let Some(v) = arg.vals.get(0) { + return Some(v.to_string_lossy()); + } + } + None + } + + /// Gets the OS version of a string value of a specific argument. If the option wasn't present + /// at runtime it returns `None`. An OS value on Unix-like systems is any series of bytes, + /// regardless of whether or not they contain valid UTF-8 code points. Since [`String`]s in + /// Rust are guaranteed to be valid UTF-8, a valid filename on a Unix system as an argument + /// value may contain invalid UTF-8 code points. + /// + /// *NOTE:* If getting a value for an option or positional argument that allows multiples, + /// prefer [`ArgMatches::values_of_os`] as `Arg::value_of_os` will only return the *first* + /// value. + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, Arg}; + /// use std::ffi::OsString; + /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; + /// + /// let m = App::new("utf8") + /// .arg(Arg::from_usage(" 'some arg'")) + /// .get_matches_from(vec![OsString::from("myprog"), + /// // "Hi {0xe9}!" + /// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]); + /// assert_eq!(&*m.value_of_os("arg").unwrap().as_bytes(), [b'H', b'i', b' ', 0xe9, b'!']); + /// ``` + /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html + /// [`ArgMatches::values_of_os`]: ./struct.ArgMatches.html#method.values_of_os + pub fn value_of_os>(&self, name: S) -> Option<&OsStr> { + self.args + .get(name.as_ref()) + .and_then(|arg| arg.vals.get(0).map(|v| v.as_os_str())) + } + + /// Gets a [`Values`] struct which implements [`Iterator`] for values of a specific argument + /// (i.e. an argument that takes multiple values at runtime). If the option wasn't present at + /// runtime it returns `None` + /// + /// # Panics + /// + /// This method will panic if any of the values contain invalid UTF-8 code points. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("output") + /// .multiple(true) + /// .short("o") + /// .takes_value(true)) + /// .get_matches_from(vec![ + /// "myprog", "-o", "val1", "val2", "val3" + /// ]); + /// let vals: Vec<&str> = m.values_of("output").unwrap().collect(); + /// assert_eq!(vals, ["val1", "val2", "val3"]); + /// ``` + /// [`Values`]: ./struct.Values.html + /// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html + pub fn values_of>(&'a self, name: S) -> Option> { + if let Some(arg) = self.args.get(name.as_ref()) { + fn to_str_slice(o: &OsString) -> &str { + o.to_str().expect(INVALID_UTF8) + } + let to_str_slice: fn(&OsString) -> &str = to_str_slice; // coerce to fn pointer + return Some(Values { + iter: arg.vals.iter().map(to_str_slice), + }); + } + None + } + + /// Gets the lossy values of a specific argument. If the option wasn't present at runtime + /// it returns `None`. A lossy value is one where if it contains invalid UTF-8 code points, + /// those invalid points will be replaced with `\u{FFFD}` + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, Arg}; + /// use std::ffi::OsString; + /// use std::os::unix::ffi::OsStringExt; + /// + /// let m = App::new("utf8") + /// .arg(Arg::from_usage("... 'some arg'")) + /// .get_matches_from(vec![OsString::from("myprog"), + /// // "Hi" + /// OsString::from_vec(vec![b'H', b'i']), + /// // "{0xe9}!" + /// OsString::from_vec(vec![0xe9, b'!'])]); + /// let mut itr = m.values_of_lossy("arg").unwrap().into_iter(); + /// assert_eq!(&itr.next().unwrap()[..], "Hi"); + /// assert_eq!(&itr.next().unwrap()[..], "\u{FFFD}!"); + /// assert_eq!(itr.next(), None); + /// ``` + pub fn values_of_lossy>(&'a self, name: S) -> Option> { + if let Some(arg) = self.args.get(name.as_ref()) { + return Some( + arg.vals + .iter() + .map(|v| v.to_string_lossy().into_owned()) + .collect(), + ); + } + None + } + + /// Gets a [`OsValues`] struct which is implements [`Iterator`] for [`OsString`] values of a + /// specific argument. If the option wasn't present at runtime it returns `None`. An OS value + /// on Unix-like systems is any series of bytes, regardless of whether or not they contain + /// valid UTF-8 code points. Since [`String`]s in Rust are guaranteed to be valid UTF-8, a valid + /// filename as an argument value on Linux (for example) may contain invalid UTF-8 code points. + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, Arg}; + /// use std::ffi::{OsStr,OsString}; + /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; + /// + /// let m = App::new("utf8") + /// .arg(Arg::from_usage("... 'some arg'")) + /// .get_matches_from(vec![OsString::from("myprog"), + /// // "Hi" + /// OsString::from_vec(vec![b'H', b'i']), + /// // "{0xe9}!" + /// OsString::from_vec(vec![0xe9, b'!'])]); + /// + /// let mut itr = m.values_of_os("arg").unwrap().into_iter(); + /// assert_eq!(itr.next(), Some(OsStr::new("Hi"))); + /// assert_eq!(itr.next(), Some(OsStr::from_bytes(&[0xe9, b'!']))); + /// assert_eq!(itr.next(), None); + /// ``` + /// [`OsValues`]: ./struct.OsValues.html + /// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html + /// [`OsString`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html + /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html + pub fn values_of_os>(&'a self, name: S) -> Option> { + fn to_str_slice(o: &OsString) -> &OsStr { + &*o + } + let to_str_slice: fn(&'a OsString) -> &'a OsStr = to_str_slice; // coerce to fn pointer + if let Some(arg) = self.args.get(name.as_ref()) { + return Some(OsValues { + iter: arg.vals.iter().map(to_str_slice), + }); + } + None + } + + /// Returns `true` if an argument was present at runtime, otherwise `false`. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("debug") + /// .short("d")) + /// .get_matches_from(vec![ + /// "myprog", "-d" + /// ]); + /// + /// assert!(m.is_present("debug")); + /// ``` + pub fn is_present>(&self, name: S) -> bool { + if let Some(ref sc) = self.subcommand { + if sc.name == name.as_ref() { + return true; + } + } + self.args.contains_key(name.as_ref()) + } + + /// Returns the number of times an argument was used at runtime. If an argument isn't present + /// it will return `0`. + /// + /// **NOTE:** This returns the number of times the argument was used, *not* the number of + /// values. For example, `-o val1 val2 val3 -o val4` would return `2` (2 occurrences, but 4 + /// values). + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("debug") + /// .short("d") + /// .multiple(true)) + /// .get_matches_from(vec![ + /// "myprog", "-d", "-d", "-d" + /// ]); + /// + /// assert_eq!(m.occurrences_of("debug"), 3); + /// ``` + /// + /// This next example shows that counts actual uses of the argument, not just `-`'s + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("debug") + /// .short("d") + /// .multiple(true)) + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .get_matches_from(vec![ + /// "myprog", "-ddfd" + /// ]); + /// + /// assert_eq!(m.occurrences_of("debug"), 3); + /// assert_eq!(m.occurrences_of("flag"), 1); + /// ``` + pub fn occurrences_of>(&self, name: S) -> u64 { + self.args.get(name.as_ref()).map_or(0, |a| a.occurs) + } + + /// Gets the starting index of the argument in respect to all other arguments. Indices are + /// similar to argv indices, but are not exactly 1:1. + /// + /// For flags (i.e. those arguments which don't have an associated value), indices refer + /// to occurrence of the switch, such as `-f`, or `--flag`. However, for options the indices + /// refer to the *values* `-o val` would therefore not represent two distinct indices, only the + /// index for `val` would be recorded. This is by design. + /// + /// Besides the flag/option descrepancy, the primary difference between an argv index and clap + /// index, is that clap continues counting once all arguments have properly seperated, whereas + /// an argv index does not. + /// + /// The examples should clear this up. + /// + /// *NOTE:* If an argument is allowed multiple times, this method will only give the *first* + /// index. + /// + /// # Examples + /// + /// The argv indices are listed in the comments below. See how they correspond to the clap + /// indices. Note that if it's not listed in a clap index, this is becuase it's not saved in + /// in an `ArgMatches` struct for querying. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true)) + /// .get_matches_from(vec!["myapp", "-f", "-o", "val"]); + /// // ARGV idices: ^0 ^1 ^2 ^3 + /// // clap idices: ^1 ^3 + /// + /// assert_eq!(m.index_of("flag"), Some(1)); + /// assert_eq!(m.index_of("option"), Some(3)); + /// ``` + /// + /// Now notice, if we use one of the other styles of options: + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true)) + /// .get_matches_from(vec!["myapp", "-f", "-o=val"]); + /// // ARGV idices: ^0 ^1 ^2 + /// // clap idices: ^1 ^3 + /// + /// assert_eq!(m.index_of("flag"), Some(1)); + /// assert_eq!(m.index_of("option"), Some(3)); + /// ``` + /// + /// Things become much more complicated, or clear if we look at a more complex combination of + /// flags. Let's also throw in the final option style for good measure. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("flag2") + /// .short("F")) + /// .arg(Arg::with_name("flag3") + /// .short("z")) + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true)) + /// .get_matches_from(vec!["myapp", "-fzF", "-oval"]); + /// // ARGV idices: ^0 ^1 ^2 + /// // clap idices: ^1,2,3 ^5 + /// // + /// // clap sees the above as 'myapp -f -z -F -o val' + /// // ^0 ^1 ^2 ^3 ^4 ^5 + /// assert_eq!(m.index_of("flag"), Some(1)); + /// assert_eq!(m.index_of("flag2"), Some(3)); + /// assert_eq!(m.index_of("flag3"), Some(2)); + /// assert_eq!(m.index_of("option"), Some(5)); + /// ``` + /// + /// One final combination of flags/options to see how they combine: + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("flag2") + /// .short("F")) + /// .arg(Arg::with_name("flag3") + /// .short("z")) + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true) + /// .multiple(true)) + /// .get_matches_from(vec!["myapp", "-fzFoval"]); + /// // ARGV idices: ^0 ^1 + /// // clap idices: ^1,2,3^5 + /// // + /// // clap sees the above as 'myapp -f -z -F -o val' + /// // ^0 ^1 ^2 ^3 ^4 ^5 + /// assert_eq!(m.index_of("flag"), Some(1)); + /// assert_eq!(m.index_of("flag2"), Some(3)); + /// assert_eq!(m.index_of("flag3"), Some(2)); + /// assert_eq!(m.index_of("option"), Some(5)); + /// ``` + /// + /// The last part to mention is when values are sent in multiple groups with a [delimiter]. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true) + /// .multiple(true)) + /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); + /// // ARGV idices: ^0 ^1 + /// // clap idices: ^2 ^3 ^4 + /// // + /// // clap sees the above as 'myapp -o val1 val2 val3' + /// // ^0 ^1 ^2 ^3 ^4 + /// assert_eq!(m.index_of("option"), Some(2)); + /// ``` + /// [`ArgMatches`]: ./struct.ArgMatches.html + /// [delimiter]: ./struct.Arg.html#method.value_delimiter + pub fn index_of>(&self, name: S) -> Option { + if let Some(arg) = self.args.get(name.as_ref()) { + if let Some(i) = arg.indices.get(0) { + return Some(*i); + } + } + None + } + + /// Gets all indices of the argument in respect to all other arguments. Indices are + /// similar to argv indices, but are not exactly 1:1. + /// + /// For flags (i.e. those arguments which don't have an associated value), indices refer + /// to occurrence of the switch, such as `-f`, or `--flag`. However, for options the indices + /// refer to the *values* `-o val` would therefore not represent two distinct indices, only the + /// index for `val` would be recorded. This is by design. + /// + /// *NOTE:* For more information about how clap indices compare to argv indices, see + /// [`ArgMatches::index_of`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true) + /// .use_delimiter(true) + /// .multiple(true)) + /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); + /// // ARGV idices: ^0 ^1 + /// // clap idices: ^2 ^3 ^4 + /// // + /// // clap sees the above as 'myapp -o val1 val2 val3' + /// // ^0 ^1 ^2 ^3 ^4 + /// assert_eq!(m.indices_of("option").unwrap().collect::>(), &[2, 3, 4]); + /// ``` + /// + /// Another quick example is when flags and options are used together + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true) + /// .multiple(true)) + /// .arg(Arg::with_name("flag") + /// .short("f") + /// .multiple(true)) + /// .get_matches_from(vec!["myapp", "-o", "val1", "-f", "-o", "val2", "-f"]); + /// // ARGV idices: ^0 ^1 ^2 ^3 ^4 ^5 ^6 + /// // clap idices: ^2 ^3 ^5 ^6 + /// + /// assert_eq!(m.indices_of("option").unwrap().collect::>(), &[2, 5]); + /// assert_eq!(m.indices_of("flag").unwrap().collect::>(), &[3, 6]); + /// ``` + /// + /// One final example, which is an odd case; if we *don't* use value delimiter as we did with + /// the first example above instead of `val1`, `val2` and `val3` all being distinc values, they + /// would all be a single value of `val1,val2,val3`, in which case case they'd only receive a + /// single index. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true) + /// .multiple(true)) + /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); + /// // ARGV idices: ^0 ^1 + /// // clap idices: ^2 + /// // + /// // clap sees the above as 'myapp -o "val1,val2,val3"' + /// // ^0 ^1 ^2 + /// assert_eq!(m.indices_of("option").unwrap().collect::>(), &[2]); + /// ``` + /// [`ArgMatches`]: ./struct.ArgMatches.html + /// [`ArgMatches::index_of`]: ./struct.ArgMatches.html#method.index_of + /// [delimiter]: ./struct.Arg.html#method.value_delimiter + pub fn indices_of>(&'a self, name: S) -> Option> { + if let Some(arg) = self.args.get(name.as_ref()) { + fn to_usize(i: &usize) -> usize { + *i + } + let to_usize: fn(&usize) -> usize = to_usize; // coerce to fn pointer + return Some(Indices { + iter: arg.indices.iter().map(to_usize), + }); + } + None + } + + /// Because [`Subcommand`]s are essentially "sub-[`App`]s" they have their own [`ArgMatches`] + /// as well. This method returns the [`ArgMatches`] for a particular subcommand or `None` if + /// the subcommand wasn't present at runtime. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, SubCommand}; + /// let app_m = App::new("myprog") + /// .arg(Arg::with_name("debug") + /// .short("d")) + /// .subcommand(SubCommand::with_name("test") + /// .arg(Arg::with_name("opt") + /// .long("option") + /// .takes_value(true))) + /// .get_matches_from(vec![ + /// "myprog", "-d", "test", "--option", "val" + /// ]); + /// + /// // Both parent commands, and child subcommands can have arguments present at the same times + /// assert!(app_m.is_present("debug")); + /// + /// // Get the subcommand's ArgMatches instance + /// if let Some(sub_m) = app_m.subcommand_matches("test") { + /// // Use the struct like normal + /// assert_eq!(sub_m.value_of("opt"), Some("val")); + /// } + /// ``` + /// [`Subcommand`]: ./struct.SubCommand.html + /// [`App`]: ./struct.App.html + /// [`ArgMatches`]: ./struct.ArgMatches.html + pub fn subcommand_matches>(&self, name: S) -> Option<&ArgMatches<'a>> { + if let Some(ref s) = self.subcommand { + if s.name == name.as_ref() { + return Some(&s.matches); + } + } + None + } + + /// Because [`Subcommand`]s are essentially "sub-[`App`]s" they have their own [`ArgMatches`] + /// as well.But simply getting the sub-[`ArgMatches`] doesn't help much if we don't also know + /// which subcommand was actually used. This method returns the name of the subcommand that was + /// used at runtime, or `None` if one wasn't. + /// + /// *NOTE*: Subcommands form a hierarchy, where multiple subcommands can be used at runtime, + /// but only a single subcommand from any group of sibling commands may used at once. + /// + /// An ASCII art depiction may help explain this better...Using a fictional version of `git` as + /// the demo subject. Imagine the following are all subcommands of `git` (note, the author is + /// aware these aren't actually all subcommands in the real `git` interface, but it makes + /// explanation easier) + /// + /// ```notrust + /// Top Level App (git) TOP + /// | + /// ----------------------------------------- + /// / | \ \ + /// clone push add commit LEVEL 1 + /// | / \ / \ | + /// url origin remote ref name message LEVEL 2 + /// / /\ + /// path remote local LEVEL 3 + /// ``` + /// + /// Given the above fictional subcommand hierarchy, valid runtime uses would be (not an all + /// inclusive list, and not including argument options per command for brevity and clarity): + /// + /// ```sh + /// $ git clone url + /// $ git push origin path + /// $ git add ref local + /// $ git commit message + /// ``` + /// + /// Notice only one command per "level" may be used. You could not, for example, do `$ git + /// clone url push origin path` + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// let app_m = App::new("git") + /// .subcommand(SubCommand::with_name("clone")) + /// .subcommand(SubCommand::with_name("push")) + /// .subcommand(SubCommand::with_name("commit")) + /// .get_matches(); + /// + /// match app_m.subcommand_name() { + /// Some("clone") => {}, // clone was used + /// Some("push") => {}, // push was used + /// Some("commit") => {}, // commit was used + /// _ => {}, // Either no subcommand or one not tested for... + /// } + /// ``` + /// [`Subcommand`]: ./struct.SubCommand.html + /// [`App`]: ./struct.App.html + /// [`ArgMatches`]: ./struct.ArgMatches.html + pub fn subcommand_name(&self) -> Option<&str> { + self.subcommand.as_ref().map(|sc| &sc.name[..]) + } + + /// This brings together [`ArgMatches::subcommand_matches`] and [`ArgMatches::subcommand_name`] + /// by returning a tuple with both pieces of information. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// let app_m = App::new("git") + /// .subcommand(SubCommand::with_name("clone")) + /// .subcommand(SubCommand::with_name("push")) + /// .subcommand(SubCommand::with_name("commit")) + /// .get_matches(); + /// + /// match app_m.subcommand() { + /// ("clone", Some(sub_m)) => {}, // clone was used + /// ("push", Some(sub_m)) => {}, // push was used + /// ("commit", Some(sub_m)) => {}, // commit was used + /// _ => {}, // Either no subcommand or one not tested for... + /// } + /// ``` + /// + /// Another useful scenario is when you want to support third party, or external, subcommands. + /// In these cases you can't know the subcommand name ahead of time, so use a variable instead + /// with pattern matching! + /// + /// ```rust + /// # use clap::{App, AppSettings}; + /// // Assume there is an external subcommand named "subcmd" + /// let app_m = App::new("myprog") + /// .setting(AppSettings::AllowExternalSubcommands) + /// .get_matches_from(vec![ + /// "myprog", "subcmd", "--option", "value", "-fff", "--flag" + /// ]); + /// + /// // All trailing arguments will be stored under the subcommand's sub-matches using an empty + /// // string argument name + /// match app_m.subcommand() { + /// (external, Some(sub_m)) => { + /// let ext_args: Vec<&str> = sub_m.values_of("").unwrap().collect(); + /// assert_eq!(external, "subcmd"); + /// assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]); + /// }, + /// _ => {}, + /// } + /// ``` + /// [`ArgMatches::subcommand_matches`]: ./struct.ArgMatches.html#method.subcommand_matches + /// [`ArgMatches::subcommand_name`]: ./struct.ArgMatches.html#method.subcommand_name + pub fn subcommand(&self) -> (&str, Option<&ArgMatches<'a>>) { + self.subcommand + .as_ref() + .map_or(("", None), |sc| (&sc.name[..], Some(&sc.matches))) + } + + /// Returns a string slice of the usage statement for the [`App`] or [`SubCommand`] + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// let app_m = App::new("myprog") + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches(); + /// + /// println!("{}", app_m.usage()); + /// ``` + /// [`Subcommand`]: ./struct.SubCommand.html + /// [`App`]: ./struct.App.html + pub fn usage(&self) -> &str { + self.usage.as_ref().map_or("", |u| &u[..]) + } +} + +// The following were taken and adapated from vec_map source +// repo: https://github.com/contain-rs/vec-map +// commit: be5e1fa3c26e351761b33010ddbdaf5f05dbcc33 +// license: MIT - Copyright (c) 2015 The Rust Project Developers + +/// An iterator for getting multiple values out of an argument via the [`ArgMatches::values_of`] +/// method. +/// +/// # Examples +/// +/// ```rust +/// # use clap::{App, Arg}; +/// let m = App::new("myapp") +/// .arg(Arg::with_name("output") +/// .short("o") +/// .multiple(true) +/// .takes_value(true)) +/// .get_matches_from(vec!["myapp", "-o", "val1", "val2"]); +/// +/// let mut values = m.values_of("output").unwrap(); +/// +/// assert_eq!(values.next(), Some("val1")); +/// assert_eq!(values.next(), Some("val2")); +/// assert_eq!(values.next(), None); +/// ``` +/// [`ArgMatches::values_of`]: ./struct.ArgMatches.html#method.values_of +#[derive(Debug, Clone)] +pub struct Values<'a> { + iter: Map, fn(&'a OsString) -> &'a str>, +} + +impl<'a> Iterator for Values<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a> DoubleEndedIterator for Values<'a> { + fn next_back(&mut self) -> Option<&'a str> { + self.iter.next_back() + } +} + +impl<'a> ExactSizeIterator for Values<'a> {} + +/// Creates an empty iterator. +impl<'a> Default for Values<'a> { + fn default() -> Self { + static EMPTY: [OsString; 0] = []; + // This is never called because the iterator is empty: + fn to_str_slice(_: &OsString) -> &str { + unreachable!() + } + Values { + iter: EMPTY[..].iter().map(to_str_slice), + } + } +} + +/// An iterator for getting multiple values out of an argument via the [`ArgMatches::values_of_os`] +/// method. Usage of this iterator allows values which contain invalid UTF-8 code points unlike +/// [`Values`]. +/// +/// # Examples +/// +#[cfg_attr(not(unix), doc = " ```ignore")] +#[cfg_attr(unix, doc = " ```")] +/// # use clap::{App, Arg}; +/// use std::ffi::OsString; +/// use std::os::unix::ffi::{OsStrExt,OsStringExt}; +/// +/// let m = App::new("utf8") +/// .arg(Arg::from_usage(" 'some arg'")) +/// .get_matches_from(vec![OsString::from("myprog"), +/// // "Hi {0xe9}!" +/// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]); +/// assert_eq!(&*m.value_of_os("arg").unwrap().as_bytes(), [b'H', b'i', b' ', 0xe9, b'!']); +/// ``` +/// [`ArgMatches::values_of_os`]: ./struct.ArgMatches.html#method.values_of_os +/// [`Values`]: ./struct.Values.html +#[derive(Debug, Clone)] +pub struct OsValues<'a> { + iter: Map, fn(&'a OsString) -> &'a OsStr>, +} + +impl<'a> Iterator for OsValues<'a> { + type Item = &'a OsStr; + + fn next(&mut self) -> Option<&'a OsStr> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a> DoubleEndedIterator for OsValues<'a> { + fn next_back(&mut self) -> Option<&'a OsStr> { + self.iter.next_back() + } +} + +impl<'a> ExactSizeIterator for OsValues<'a> {} + +/// Creates an empty iterator. +impl<'a> Default for OsValues<'a> { + fn default() -> Self { + static EMPTY: [OsString; 0] = []; + // This is never called because the iterator is empty: + fn to_str_slice(_: &OsString) -> &OsStr { + unreachable!() + } + OsValues { + iter: EMPTY[..].iter().map(to_str_slice), + } + } +} + +/// An iterator for getting multiple indices out of an argument via the [`ArgMatches::indices_of`] +/// method. +/// +/// # Examples +/// +/// ```rust +/// # use clap::{App, Arg}; +/// let m = App::new("myapp") +/// .arg(Arg::with_name("output") +/// .short("o") +/// .multiple(true) +/// .takes_value(true)) +/// .get_matches_from(vec!["myapp", "-o", "val1", "val2"]); +/// +/// let mut indices = m.indices_of("output").unwrap(); +/// +/// assert_eq!(indices.next(), Some(2)); +/// assert_eq!(indices.next(), Some(3)); +/// assert_eq!(indices.next(), None); +/// ``` +/// [`ArgMatches::indices_of`]: ./struct.ArgMatches.html#method.indices_of +#[derive(Debug, Clone)] +pub struct Indices<'a> { + // would rather use '_, but: https://github.com/rust-lang/rust/issues/48469 + iter: Map, fn(&'a usize) -> usize>, +} + +impl<'a> Iterator for Indices<'a> { + type Item = usize; + + fn next(&mut self) -> Option { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a> DoubleEndedIterator for Indices<'a> { + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} + +impl<'a> ExactSizeIterator for Indices<'a> {} + +/// Creates an empty iterator. +impl<'a> Default for Indices<'a> { + fn default() -> Self { + static EMPTY: [usize; 0] = []; + // This is never called because the iterator is empty: + fn to_usize(_: &usize) -> usize { + unreachable!() + } + Indices { + iter: EMPTY[..].iter().map(to_usize), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_default_values() { + let mut values: Values = Values::default(); + assert_eq!(values.next(), None); + } + + #[test] + fn test_default_values_with_shorter_lifetime() { + let matches = ArgMatches::new(); + let mut values = matches.values_of("").unwrap_or_default(); + assert_eq!(values.next(), None); + } + + #[test] + fn test_default_osvalues() { + let mut values: OsValues = OsValues::default(); + assert_eq!(values.next(), None); + } + + #[test] + fn test_default_osvalues_with_shorter_lifetime() { + let matches = ArgMatches::new(); + let mut values = matches.values_of_os("").unwrap_or_default(); + assert_eq!(values.next(), None); + } + + #[test] + fn test_default_indices() { + let mut indices: Indices = Indices::default(); + assert_eq!(indices.next(), None); + } + + #[test] + fn test_default_indices_with_shorter_lifetime() { + let matches = ArgMatches::new(); + let mut indices = matches.indices_of("").unwrap_or_default(); + assert_eq!(indices.next(), None); + } +} diff --git a/vendor/clap-2.34.0/src/args/group.rs b/vendor/clap-2.34.0/src/args/group.rs new file mode 100644 index 0000000000000..a2992b2970dcb --- /dev/null +++ b/vendor/clap-2.34.0/src/args/group.rs @@ -0,0 +1,637 @@ +#[cfg(feature = "yaml")] +use std::collections::BTreeMap; +use std::fmt::{Debug, Formatter, Result}; + +#[cfg(feature = "yaml")] +use yaml_rust::Yaml; + +/// `ArgGroup`s are a family of related [arguments] and way for you to express, "Any of these +/// arguments". By placing arguments in a logical group, you can create easier requirement and +/// exclusion rules instead of having to list each argument individually, or when you want a rule +/// to apply "any but not all" arguments. +/// +/// For instance, you can make an entire `ArgGroup` required. If [`ArgGroup::multiple(true)`] is +/// set, this means that at least one argument from that group must be present. If +/// [`ArgGroup::multiple(false)`] is set (the default), one and *only* one must be present. +/// +/// You can also do things such as name an entire `ArgGroup` as a [conflict] or [requirement] for +/// another argument, meaning any of the arguments that belong to that group will cause a failure +/// if present, or must present respectively. +/// +/// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be +/// present out of a given set. Imagine that you had multiple arguments, and you want one of them +/// to be required, but making all of them required isn't feasible because perhaps they conflict +/// with each other. For example, lets say that you were building an application where one could +/// set a given version number by supplying a string with an option argument, i.e. +/// `--set-ver v1.2.3`, you also wanted to support automatically using a previous version number +/// and simply incrementing one of the three numbers. So you create three flags `--major`, +/// `--minor`, and `--patch`. All of these arguments shouldn't be used at one time but you want to +/// specify that *at least one* of them is used. For this, you can create a group. +/// +/// Finally, you may use `ArgGroup`s to pull a value from a group of arguments when you don't care +/// exactly which argument was actually used at runtime. +/// +/// # Examples +/// +/// The following example demonstrates using an `ArgGroup` to ensure that one, and only one, of +/// the arguments from the specified group is present at runtime. +/// +/// ```rust +/// # use clap::{App, ArgGroup, ErrorKind}; +/// let result = App::new("app") +/// .args_from_usage( +/// "--set-ver [ver] 'set the version manually' +/// --major 'auto increase major' +/// --minor 'auto increase minor' +/// --patch 'auto increase patch'") +/// .group(ArgGroup::with_name("vers") +/// .args(&["set-ver", "major", "minor", "patch"]) +/// .required(true)) +/// .get_matches_from_safe(vec!["app", "--major", "--patch"]); +/// // Because we used two args in the group it's an error +/// assert!(result.is_err()); +/// let err = result.unwrap_err(); +/// assert_eq!(err.kind, ErrorKind::ArgumentConflict); +/// ``` +/// This next example shows a passing parse of the same scenario +/// +/// ```rust +/// # use clap::{App, ArgGroup}; +/// let result = App::new("app") +/// .args_from_usage( +/// "--set-ver [ver] 'set the version manually' +/// --major 'auto increase major' +/// --minor 'auto increase minor' +/// --patch 'auto increase patch'") +/// .group(ArgGroup::with_name("vers") +/// .args(&["set-ver", "major", "minor","patch"]) +/// .required(true)) +/// .get_matches_from_safe(vec!["app", "--major"]); +/// assert!(result.is_ok()); +/// let matches = result.unwrap(); +/// // We may not know which of the args was used, so we can test for the group... +/// assert!(matches.is_present("vers")); +/// // we could also alternatively check each arg individually (not shown here) +/// ``` +/// [`ArgGroup::multiple(true)`]: ./struct.ArgGroup.html#method.multiple +/// [arguments]: ./struct.Arg.html +/// [conflict]: ./struct.Arg.html#method.conflicts_with +/// [requirement]: ./struct.Arg.html#method.requires +#[derive(Default)] +pub struct ArgGroup<'a> { + #[doc(hidden)] + pub name: &'a str, + #[doc(hidden)] + pub args: Vec<&'a str>, + #[doc(hidden)] + pub required: bool, + #[doc(hidden)] + pub requires: Option>, + #[doc(hidden)] + pub conflicts: Option>, + #[doc(hidden)] + pub multiple: bool, +} + +impl<'a> ArgGroup<'a> { + /// Creates a new instance of `ArgGroup` using a unique string name. The name will be used to + /// get values from the group or refer to the group inside of conflict and requirement rules. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, ArgGroup}; + /// ArgGroup::with_name("config") + /// # ; + /// ``` + pub fn with_name(n: &'a str) -> Self { + ArgGroup { + name: n, + required: false, + args: vec![], + requires: None, + conflicts: None, + multiple: false, + } + } + + /// Creates a new instance of `ArgGroup` from a .yml (YAML) file. + /// + /// # Examples + /// + /// ```ignore + /// # #[macro_use] + /// # extern crate clap; + /// # use clap::ArgGroup; + /// # fn main() { + /// let yml = load_yaml!("group.yml"); + /// let ag = ArgGroup::from_yaml(yml); + /// # } + /// ``` + #[cfg(feature = "yaml")] + pub fn from_yaml(y: &'a Yaml) -> ArgGroup<'a> { + ArgGroup::from(y.as_hash().unwrap()) + } + + /// Adds an [argument] to this group by name + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .group(ArgGroup::with_name("req_flags") + /// .arg("flag") + /// .arg("color")) + /// .get_matches_from(vec!["myprog", "-f"]); + /// // maybe we don't know which of the two flags was used... + /// assert!(m.is_present("req_flags")); + /// // but we can also check individually if needed + /// assert!(m.is_present("flag")); + /// ``` + /// [argument]: ./struct.Arg.html + pub fn arg(mut self, n: &'a str) -> Self { + assert!( + self.name != n, + "ArgGroup '{}' can not have same name as arg inside it", + &*self.name + ); + self.args.push(n); + self + } + + /// Adds multiple [arguments] to this group by name + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"])) + /// .get_matches_from(vec!["myprog", "-f"]); + /// // maybe we don't know which of the two flags was used... + /// assert!(m.is_present("req_flags")); + /// // but we can also check individually if needed + /// assert!(m.is_present("flag")); + /// ``` + /// [arguments]: ./struct.Arg.html + pub fn args(mut self, ns: &[&'a str]) -> Self { + for n in ns { + self = self.arg(n); + } + self + } + + /// Allows more than one of the ['Arg']s in this group to be used. (Default: `false`) + /// + /// # Examples + /// + /// Notice in this example we use *both* the `-f` and `-c` flags which are both part of the + /// group + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"]) + /// .multiple(true)) + /// .get_matches_from(vec!["myprog", "-f", "-c"]); + /// // maybe we don't know which of the two flags was used... + /// assert!(m.is_present("req_flags")); + /// ``` + /// In this next example, we show the default behavior (i.e. `multiple(false)) which will throw + /// an error if more than one of the args in the group was used. + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup, ErrorKind}; + /// let result = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"])) + /// .get_matches_from_safe(vec!["myprog", "-f", "-c"]); + /// // Because we used both args in the group it's an error + /// assert!(result.is_err()); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::ArgumentConflict); + /// ``` + /// ['Arg']: ./struct.Arg.html + pub fn multiple(mut self, m: bool) -> Self { + self.multiple = m; + self + } + + /// Sets the group as required or not. A required group will be displayed in the usage string + /// of the application in the format ``. A required `ArgGroup` simply states + /// that one argument from this group *must* be present at runtime (unless + /// conflicting with another argument). + /// + /// **NOTE:** This setting only applies to the current [`App`] / [`SubCommand`], and not + /// globally. + /// + /// **NOTE:** By default, [`ArgGroup::multiple`] is set to `false` which when combined with + /// `ArgGroup::required(true)` states, "One and *only one* arg must be used from this group. + /// Use of more than one arg is an error." Vice setting `ArgGroup::multiple(true)` which + /// states, '*At least* one arg from this group must be used. Using multiple is OK." + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup, ErrorKind}; + /// let result = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"]) + /// .required(true)) + /// .get_matches_from_safe(vec!["myprog"]); + /// // Because we didn't use any of the args in the group, it's an error + /// assert!(result.is_err()); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`App`]: ./struct.App.html + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`ArgGroup::multiple`]: ./struct.ArgGroup.html#method.multiple + pub fn required(mut self, r: bool) -> Self { + self.required = r; + self + } + + /// Sets the requirement rules of this group. This is not to be confused with a + /// [required group]. Requirement rules function just like [argument requirement rules], you + /// can name other arguments or groups that must be present when any one of the arguments from + /// this group is used. + /// + /// **NOTE:** The name provided may be an argument, or group name + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup, ErrorKind}; + /// let result = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .arg(Arg::with_name("debug") + /// .short("d")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"]) + /// .requires("debug")) + /// .get_matches_from_safe(vec!["myprog", "-c"]); + /// // because we used an arg from the group, and the group requires "-d" to be used, it's an + /// // error + /// assert!(result.is_err()); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [required group]: ./struct.ArgGroup.html#method.required + /// [argument requirement rules]: ./struct.Arg.html#method.requires + pub fn requires(mut self, n: &'a str) -> Self { + if let Some(ref mut reqs) = self.requires { + reqs.push(n); + } else { + self.requires = Some(vec![n]); + } + self + } + + /// Sets the requirement rules of this group. This is not to be confused with a + /// [required group]. Requirement rules function just like [argument requirement rules], you + /// can name other arguments or groups that must be present when one of the arguments from this + /// group is used. + /// + /// **NOTE:** The names provided may be an argument, or group name + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup, ErrorKind}; + /// let result = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .arg(Arg::with_name("debug") + /// .short("d")) + /// .arg(Arg::with_name("verb") + /// .short("v")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"]) + /// .requires_all(&["debug", "verb"])) + /// .get_matches_from_safe(vec!["myprog", "-c", "-d"]); + /// // because we used an arg from the group, and the group requires "-d" and "-v" to be used, + /// // yet we only used "-d" it's an error + /// assert!(result.is_err()); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [required group]: ./struct.ArgGroup.html#method.required + /// [argument requirement rules]: ./struct.Arg.html#method.requires_all + pub fn requires_all(mut self, ns: &[&'a str]) -> Self { + for n in ns { + self = self.requires(n); + } + self + } + + /// Sets the exclusion rules of this group. Exclusion (aka conflict) rules function just like + /// [argument exclusion rules], you can name other arguments or groups that must *not* be + /// present when one of the arguments from this group are used. + /// + /// **NOTE:** The name provided may be an argument, or group name + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup, ErrorKind}; + /// let result = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .arg(Arg::with_name("debug") + /// .short("d")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"]) + /// .conflicts_with("debug")) + /// .get_matches_from_safe(vec!["myprog", "-c", "-d"]); + /// // because we used an arg from the group, and the group conflicts with "-d", it's an error + /// assert!(result.is_err()); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::ArgumentConflict); + /// ``` + /// [argument exclusion rules]: ./struct.Arg.html#method.conflicts_with + pub fn conflicts_with(mut self, n: &'a str) -> Self { + if let Some(ref mut confs) = self.conflicts { + confs.push(n); + } else { + self.conflicts = Some(vec![n]); + } + self + } + + /// Sets the exclusion rules of this group. Exclusion rules function just like + /// [argument exclusion rules], you can name other arguments or groups that must *not* be + /// present when one of the arguments from this group are used. + /// + /// **NOTE:** The names provided may be an argument, or group name + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup, ErrorKind}; + /// let result = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .arg(Arg::with_name("debug") + /// .short("d")) + /// .arg(Arg::with_name("verb") + /// .short("v")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"]) + /// .conflicts_with_all(&["debug", "verb"])) + /// .get_matches_from_safe(vec!["myprog", "-c", "-v"]); + /// // because we used an arg from the group, and the group conflicts with either "-v" or "-d" + /// // it's an error + /// assert!(result.is_err()); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::ArgumentConflict); + /// ``` + /// [argument exclusion rules]: ./struct.Arg.html#method.conflicts_with_all + pub fn conflicts_with_all(mut self, ns: &[&'a str]) -> Self { + for n in ns { + self = self.conflicts_with(n); + } + self + } +} + +impl<'a> Debug for ArgGroup<'a> { + fn fmt(&self, f: &mut Formatter) -> Result { + write!( + f, + "{{\n\ + \tname: {:?},\n\ + \targs: {:?},\n\ + \trequired: {:?},\n\ + \trequires: {:?},\n\ + \tconflicts: {:?},\n\ + }}", + self.name, self.args, self.required, self.requires, self.conflicts + ) + } +} + +impl<'a, 'z> From<&'z ArgGroup<'a>> for ArgGroup<'a> { + fn from(g: &'z ArgGroup<'a>) -> Self { + ArgGroup { + name: g.name, + required: g.required, + args: g.args.clone(), + requires: g.requires.clone(), + conflicts: g.conflicts.clone(), + multiple: g.multiple, + } + } +} + +#[cfg(feature = "yaml")] +impl<'a> From<&'a BTreeMap> for ArgGroup<'a> { + fn from(b: &'a BTreeMap) -> Self { + // We WANT this to panic on error...so expect() is good. + let mut a = ArgGroup::default(); + let group_settings = if b.len() == 1 { + let name_yml = b.keys().nth(0).expect("failed to get name"); + let name_str = name_yml + .as_str() + .expect("failed to convert arg YAML name to str"); + a.name = name_str; + b.get(name_yml) + .expect("failed to get name_str") + .as_hash() + .expect("failed to convert to a hash") + } else { + b + }; + + for (k, v) in group_settings { + a = match k.as_str().unwrap() { + "required" => a.required(v.as_bool().unwrap()), + "multiple" => a.multiple(v.as_bool().unwrap()), + "args" => yaml_vec_or_str!(v, a, arg), + "arg" => { + if let Some(ys) = v.as_str() { + a = a.arg(ys); + } + a + } + "requires" => yaml_vec_or_str!(v, a, requires), + "conflicts_with" => yaml_vec_or_str!(v, a, conflicts_with), + "name" => { + if let Some(ys) = v.as_str() { + a.name = ys; + } + a + } + s => panic!( + "Unknown ArgGroup setting '{}' in YAML file for \ + ArgGroup '{}'", + s, a.name + ), + } + } + + a + } +} + +#[cfg(test)] +mod test { + use super::ArgGroup; + #[cfg(feature = "yaml")] + use yaml_rust::YamlLoader; + + #[test] + fn groups() { + let g = ArgGroup::with_name("test") + .arg("a1") + .arg("a4") + .args(&["a2", "a3"]) + .required(true) + .conflicts_with("c1") + .conflicts_with_all(&["c2", "c3"]) + .conflicts_with("c4") + .requires("r1") + .requires_all(&["r2", "r3"]) + .requires("r4"); + + let args = vec!["a1", "a4", "a2", "a3"]; + let reqs = vec!["r1", "r2", "r3", "r4"]; + let confs = vec!["c1", "c2", "c3", "c4"]; + + assert_eq!(g.args, args); + assert_eq!(g.requires, Some(reqs)); + assert_eq!(g.conflicts, Some(confs)); + } + + #[test] + fn test_debug() { + let g = ArgGroup::with_name("test") + .arg("a1") + .arg("a4") + .args(&["a2", "a3"]) + .required(true) + .conflicts_with("c1") + .conflicts_with_all(&["c2", "c3"]) + .conflicts_with("c4") + .requires("r1") + .requires_all(&["r2", "r3"]) + .requires("r4"); + + let args = vec!["a1", "a4", "a2", "a3"]; + let reqs = vec!["r1", "r2", "r3", "r4"]; + let confs = vec!["c1", "c2", "c3", "c4"]; + + let debug_str = format!( + "{{\n\ + \tname: \"test\",\n\ + \targs: {:?},\n\ + \trequired: {:?},\n\ + \trequires: {:?},\n\ + \tconflicts: {:?},\n\ + }}", + args, + true, + Some(reqs), + Some(confs) + ); + assert_eq!(&*format!("{:?}", g), &*debug_str); + } + + #[test] + fn test_from() { + let g = ArgGroup::with_name("test") + .arg("a1") + .arg("a4") + .args(&["a2", "a3"]) + .required(true) + .conflicts_with("c1") + .conflicts_with_all(&["c2", "c3"]) + .conflicts_with("c4") + .requires("r1") + .requires_all(&["r2", "r3"]) + .requires("r4"); + + let args = vec!["a1", "a4", "a2", "a3"]; + let reqs = vec!["r1", "r2", "r3", "r4"]; + let confs = vec!["c1", "c2", "c3", "c4"]; + + let g2 = ArgGroup::from(&g); + assert_eq!(g2.args, args); + assert_eq!(g2.requires, Some(reqs)); + assert_eq!(g2.conflicts, Some(confs)); + } + + #[cfg(feature = "yaml")] + #[cfg_attr(feature = "yaml", test)] + fn test_yaml() { + let g_yaml = "name: test +args: +- a1 +- a4 +- a2 +- a3 +conflicts_with: +- c1 +- c2 +- c3 +- c4 +requires: +- r1 +- r2 +- r3 +- r4"; + let yml = &YamlLoader::load_from_str(g_yaml).expect("failed to load YAML file")[0]; + let g = ArgGroup::from_yaml(yml); + let args = vec!["a1", "a4", "a2", "a3"]; + let reqs = vec!["r1", "r2", "r3", "r4"]; + let confs = vec!["c1", "c2", "c3", "c4"]; + assert_eq!(g.args, args); + assert_eq!(g.requires, Some(reqs)); + assert_eq!(g.conflicts, Some(confs)); + } +} + +impl<'a> Clone for ArgGroup<'a> { + fn clone(&self) -> Self { + ArgGroup { + name: self.name, + required: self.required, + args: self.args.clone(), + requires: self.requires.clone(), + conflicts: self.conflicts.clone(), + multiple: self.multiple, + } + } +} diff --git a/vendor/clap-2.34.0/src/args/macros.rs b/vendor/clap-2.34.0/src/args/macros.rs new file mode 100644 index 0000000000000..ac4b1a2d55149 --- /dev/null +++ b/vendor/clap-2.34.0/src/args/macros.rs @@ -0,0 +1,121 @@ +#[cfg(feature = "yaml")] +macro_rules! yaml_tuple2 { + ($a:ident, $v:ident, $c:ident) => {{ + if let Some(vec) = $v.as_vec() { + for ys in vec { + if let Some(tup) = ys.as_vec() { + debug_assert_eq!(2, tup.len()); + $a = $a.$c(yaml_str!(tup[0]), yaml_str!(tup[1])); + } else { + panic!("Failed to convert YAML value to vec"); + } + } + } else { + panic!("Failed to convert YAML value to vec"); + } + $a + }}; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_tuple3 { + ($a:ident, $v:ident, $c:ident) => {{ + if let Some(vec) = $v.as_vec() { + for ys in vec { + if let Some(tup) = ys.as_vec() { + debug_assert_eq!(3, tup.len()); + $a = $a.$c(yaml_str!(tup[0]), yaml_opt_str!(tup[1]), yaml_str!(tup[2])); + } else { + panic!("Failed to convert YAML value to vec"); + } + } + } else { + panic!("Failed to convert YAML value to vec"); + } + $a + }}; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_vec_or_str { + ($v:ident, $a:ident, $c:ident) => {{ + let maybe_vec = $v.as_vec(); + if let Some(vec) = maybe_vec { + for ys in vec { + if let Some(s) = ys.as_str() { + $a = $a.$c(s); + } else { + panic!("Failed to convert YAML value {:?} to a string", ys); + } + } + } else { + if let Some(s) = $v.as_str() { + $a = $a.$c(s); + } else { + panic!( + "Failed to convert YAML value {:?} to either a vec or string", + $v + ); + } + } + $a + }}; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_opt_str { + ($v:expr) => {{ + if $v.is_null() { + Some( + $v.as_str() + .unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)), + ) + } else { + None + } + }}; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_str { + ($v:expr) => {{ + $v.as_str() + .unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)) + }}; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_to_str { + ($a:ident, $v:ident, $c:ident) => {{ + $a.$c(yaml_str!($v)) + }}; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_to_bool { + ($a:ident, $v:ident, $c:ident) => {{ + $a.$c($v + .as_bool() + .unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v))) + }}; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_to_u64 { + ($a:ident, $v:ident, $c:ident) => {{ + $a.$c($v + .as_i64() + .unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)) + as u64) + }}; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_to_usize { + ($a:ident, $v:ident, $c:ident) => {{ + $a.$c($v + .as_i64() + .unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)) + as usize) + }}; +} diff --git a/vendor/clap-2.34.0/src/args/matched_arg.rs b/vendor/clap-2.34.0/src/args/matched_arg.rs new file mode 100644 index 0000000000000..681e5d2aa765f --- /dev/null +++ b/vendor/clap-2.34.0/src/args/matched_arg.rs @@ -0,0 +1,29 @@ +// Std +use std::ffi::OsString; + +#[doc(hidden)] +#[derive(Debug, Clone)] +pub struct MatchedArg { + #[doc(hidden)] + pub occurs: u64, + #[doc(hidden)] + pub indices: Vec, + #[doc(hidden)] + pub vals: Vec, +} + +impl Default for MatchedArg { + fn default() -> Self { + MatchedArg { + occurs: 1, + indices: Vec::new(), + vals: Vec::new(), + } + } +} + +impl MatchedArg { + pub fn new() -> Self { + MatchedArg::default() + } +} diff --git a/vendor/clap-2.34.0/src/args/mod.rs b/vendor/clap-2.34.0/src/args/mod.rs new file mode 100644 index 0000000000000..8f076ea5c2936 --- /dev/null +++ b/vendor/clap-2.34.0/src/args/mod.rs @@ -0,0 +1,21 @@ +pub use self::any_arg::{AnyArg, DispOrder}; +pub use self::arg::Arg; +pub use self::arg_builder::{Base, FlagBuilder, OptBuilder, PosBuilder, Switched, Valued}; +pub use self::arg_matcher::ArgMatcher; +pub use self::arg_matches::{ArgMatches, OsValues, Values}; +pub use self::group::ArgGroup; +pub use self::matched_arg::MatchedArg; +pub use self::settings::{ArgFlags, ArgSettings}; +pub use self::subcommand::SubCommand; + +#[macro_use] +mod macros; +pub mod any_arg; +mod arg; +mod arg_builder; +mod arg_matcher; +mod arg_matches; +mod group; +mod matched_arg; +pub mod settings; +mod subcommand; diff --git a/vendor/clap-2.34.0/src/args/settings.rs b/vendor/clap-2.34.0/src/args/settings.rs new file mode 100644 index 0000000000000..833a1eafefa32 --- /dev/null +++ b/vendor/clap-2.34.0/src/args/settings.rs @@ -0,0 +1,237 @@ +// Std +#[allow(deprecated, unused_imports)] +use std::ascii::AsciiExt; +use std::str::FromStr; + +bitflags! { + struct Flags: u32 { + const REQUIRED = 1; + const MULTIPLE = 1 << 1; + const EMPTY_VALS = 1 << 2; + const GLOBAL = 1 << 3; + const HIDDEN = 1 << 4; + const TAKES_VAL = 1 << 5; + const USE_DELIM = 1 << 6; + const NEXT_LINE_HELP = 1 << 7; + const R_UNLESS_ALL = 1 << 8; + const REQ_DELIM = 1 << 9; + const DELIM_NOT_SET = 1 << 10; + const HIDE_POS_VALS = 1 << 11; + const ALLOW_TAC_VALS = 1 << 12; + const REQUIRE_EQUALS = 1 << 13; + const LAST = 1 << 14; + const HIDE_DEFAULT_VAL = 1 << 15; + const CASE_INSENSITIVE = 1 << 16; + const HIDE_ENV_VALS = 1 << 17; + const HIDDEN_SHORT_H = 1 << 18; + const HIDDEN_LONG_H = 1 << 19; + } +} + +#[doc(hidden)] +#[derive(Debug, Clone, Copy)] +pub struct ArgFlags(Flags); + +impl ArgFlags { + pub fn new() -> Self { + ArgFlags::default() + } + + impl_settings! {ArgSettings, + Required => Flags::REQUIRED, + Multiple => Flags::MULTIPLE, + EmptyValues => Flags::EMPTY_VALS, + Global => Flags::GLOBAL, + Hidden => Flags::HIDDEN, + TakesValue => Flags::TAKES_VAL, + UseValueDelimiter => Flags::USE_DELIM, + NextLineHelp => Flags::NEXT_LINE_HELP, + RequiredUnlessAll => Flags::R_UNLESS_ALL, + RequireDelimiter => Flags::REQ_DELIM, + ValueDelimiterNotSet => Flags::DELIM_NOT_SET, + HidePossibleValues => Flags::HIDE_POS_VALS, + AllowLeadingHyphen => Flags::ALLOW_TAC_VALS, + RequireEquals => Flags::REQUIRE_EQUALS, + Last => Flags::LAST, + CaseInsensitive => Flags::CASE_INSENSITIVE, + HideEnvValues => Flags::HIDE_ENV_VALS, + HideDefaultValue => Flags::HIDE_DEFAULT_VAL, + HiddenShortHelp => Flags::HIDDEN_SHORT_H, + HiddenLongHelp => Flags::HIDDEN_LONG_H + } +} + +impl Default for ArgFlags { + fn default() -> Self { + ArgFlags(Flags::EMPTY_VALS | Flags::DELIM_NOT_SET) + } +} + +/// Various settings that apply to arguments and may be set, unset, and checked via getter/setter +/// methods [`Arg::set`], [`Arg::unset`], and [`Arg::is_set`] +/// +/// [`Arg::set`]: ./struct.Arg.html#method.set +/// [`Arg::unset`]: ./struct.Arg.html#method.unset +/// [`Arg::is_set`]: ./struct.Arg.html#method.is_set +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum ArgSettings { + /// The argument must be used + Required, + /// The argument may be used multiple times such as `--flag --flag` + Multiple, + /// The argument allows empty values such as `--option ""` + EmptyValues, + /// The argument should be propagated down through all child [`SubCommand`]s + /// + /// [`SubCommand`]: ./struct.SubCommand.html + Global, + /// The argument should **not** be shown in help text + Hidden, + /// The argument accepts a value, such as `--option ` + TakesValue, + /// Determines if the argument allows values to be grouped via a delimiter + UseValueDelimiter, + /// Prints the help text on the line after the argument + NextLineHelp, + /// Requires the use of a value delimiter for all multiple values + RequireDelimiter, + /// Hides the possible values from the help string + HidePossibleValues, + /// Allows vals that start with a '-' + AllowLeadingHyphen, + /// Require options use `--option=val` syntax + RequireEquals, + /// Specifies that the arg is the last positional argument and may be accessed early via `--` + /// syntax + Last, + /// Hides the default value from the help string + HideDefaultValue, + /// Makes `Arg::possible_values` case insensitive + CaseInsensitive, + /// Hides ENV values in the help message + HideEnvValues, + /// The argument should **not** be shown in short help text + HiddenShortHelp, + /// The argument should **not** be shown in long help text + HiddenLongHelp, + #[doc(hidden)] + RequiredUnlessAll, + #[doc(hidden)] + ValueDelimiterNotSet, +} + +impl FromStr for ArgSettings { + type Err = String; + fn from_str(s: &str) -> Result::Err> { + match &*s.to_ascii_lowercase() { + "required" => Ok(ArgSettings::Required), + "multiple" => Ok(ArgSettings::Multiple), + "global" => Ok(ArgSettings::Global), + "emptyvalues" => Ok(ArgSettings::EmptyValues), + "hidden" => Ok(ArgSettings::Hidden), + "takesvalue" => Ok(ArgSettings::TakesValue), + "usevaluedelimiter" => Ok(ArgSettings::UseValueDelimiter), + "nextlinehelp" => Ok(ArgSettings::NextLineHelp), + "requiredunlessall" => Ok(ArgSettings::RequiredUnlessAll), + "requiredelimiter" => Ok(ArgSettings::RequireDelimiter), + "valuedelimiternotset" => Ok(ArgSettings::ValueDelimiterNotSet), + "hidepossiblevalues" => Ok(ArgSettings::HidePossibleValues), + "allowleadinghyphen" => Ok(ArgSettings::AllowLeadingHyphen), + "requireequals" => Ok(ArgSettings::RequireEquals), + "last" => Ok(ArgSettings::Last), + "hidedefaultvalue" => Ok(ArgSettings::HideDefaultValue), + "caseinsensitive" => Ok(ArgSettings::CaseInsensitive), + "hideenvvalues" => Ok(ArgSettings::HideEnvValues), + "hiddenshorthelp" => Ok(ArgSettings::HiddenShortHelp), + "hiddenlonghelp" => Ok(ArgSettings::HiddenLongHelp), + _ => Err("unknown ArgSetting, cannot convert from str".to_owned()), + } + } +} + +#[cfg(test)] +mod test { + use super::ArgSettings; + + #[test] + fn arg_settings_fromstr() { + assert_eq!( + "allowleadinghyphen".parse::().unwrap(), + ArgSettings::AllowLeadingHyphen + ); + assert_eq!( + "emptyvalues".parse::().unwrap(), + ArgSettings::EmptyValues + ); + assert_eq!( + "global".parse::().unwrap(), + ArgSettings::Global + ); + assert_eq!( + "hidepossiblevalues".parse::().unwrap(), + ArgSettings::HidePossibleValues + ); + assert_eq!( + "hidden".parse::().unwrap(), + ArgSettings::Hidden + ); + assert_eq!( + "multiple".parse::().unwrap(), + ArgSettings::Multiple + ); + assert_eq!( + "nextlinehelp".parse::().unwrap(), + ArgSettings::NextLineHelp + ); + assert_eq!( + "requiredunlessall".parse::().unwrap(), + ArgSettings::RequiredUnlessAll + ); + assert_eq!( + "requiredelimiter".parse::().unwrap(), + ArgSettings::RequireDelimiter + ); + assert_eq!( + "required".parse::().unwrap(), + ArgSettings::Required + ); + assert_eq!( + "takesvalue".parse::().unwrap(), + ArgSettings::TakesValue + ); + assert_eq!( + "usevaluedelimiter".parse::().unwrap(), + ArgSettings::UseValueDelimiter + ); + assert_eq!( + "valuedelimiternotset".parse::().unwrap(), + ArgSettings::ValueDelimiterNotSet + ); + assert_eq!( + "requireequals".parse::().unwrap(), + ArgSettings::RequireEquals + ); + assert_eq!("last".parse::().unwrap(), ArgSettings::Last); + assert_eq!( + "hidedefaultvalue".parse::().unwrap(), + ArgSettings::HideDefaultValue + ); + assert_eq!( + "caseinsensitive".parse::().unwrap(), + ArgSettings::CaseInsensitive + ); + assert_eq!( + "hideenvvalues".parse::().unwrap(), + ArgSettings::HideEnvValues + ); + assert_eq!( + "hiddenshorthelp".parse::().unwrap(), + ArgSettings::HiddenShortHelp + ); + assert_eq!( + "hiddenlonghelp".parse::().unwrap(), + ArgSettings::HiddenLongHelp + ); + assert!("hahahaha".parse::().is_err()); + } +} diff --git a/vendor/clap-2.34.0/src/args/subcommand.rs b/vendor/clap-2.34.0/src/args/subcommand.rs new file mode 100644 index 0000000000000..8ad1c0ed96d9f --- /dev/null +++ b/vendor/clap-2.34.0/src/args/subcommand.rs @@ -0,0 +1,71 @@ +// Third Party +#[cfg(feature = "yaml")] +use yaml_rust::Yaml; + +// Internal +use crate::{App, ArgMatches}; + +/// The abstract representation of a command line subcommand. +/// +/// This struct describes all the valid options of the subcommand for the program. Subcommands are +/// essentially "sub-[`App`]s" and contain all the same possibilities (such as their own +/// [arguments], subcommands, and settings). +/// +/// # Examples +/// +/// ```rust +/// # use clap::{App, Arg, SubCommand}; +/// App::new("myprog") +/// .subcommand( +/// SubCommand::with_name("config") +/// .about("Used for configuration") +/// .arg(Arg::with_name("config_file") +/// .help("The configuration file to use") +/// .index(1))) +/// # ; +/// ``` +/// [`App`]: ./struct.App.html +/// [arguments]: ./struct.Arg.html +#[derive(Debug, Clone)] +pub struct SubCommand<'a> { + #[doc(hidden)] + pub name: String, + #[doc(hidden)] + pub matches: ArgMatches<'a>, +} + +impl<'a> SubCommand<'a> { + /// Creates a new instance of a subcommand requiring a name. The name will be displayed + /// to the user when they print version or help and usage information. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, SubCommand}; + /// App::new("myprog") + /// .subcommand( + /// SubCommand::with_name("config")) + /// # ; + /// ``` + pub fn with_name<'b>(name: &str) -> App<'a, 'b> { + App::new(name) + } + + /// Creates a new instance of a subcommand from a YAML (.yml) document + /// + /// # Examples + /// + /// ```ignore + /// # #[macro_use] + /// # extern crate clap; + /// # use clap::Subcommand; + /// # fn main() { + /// let sc_yaml = load_yaml!("test_subcommand.yml"); + /// let sc = SubCommand::from_yaml(sc_yaml); + /// # } + /// ``` + #[cfg(feature = "yaml")] + pub fn from_yaml(yaml: &Yaml) -> App { + App::from_yaml(yaml) + } +} diff --git a/vendor/clap-2.34.0/src/completions/bash.rs b/vendor/clap-2.34.0/src/completions/bash.rs new file mode 100644 index 0000000000000..5c3df7219c71c --- /dev/null +++ b/vendor/clap-2.34.0/src/completions/bash.rs @@ -0,0 +1,223 @@ +// Std +use std::io::Write; + +// Internal +use crate::{ + app::parser::Parser, + args::{AnyArg, OptBuilder}, + completions, +}; + +pub struct BashGen<'a, 'b> +where + 'a: 'b, +{ + p: &'b Parser<'a, 'b>, +} + +impl<'a, 'b> BashGen<'a, 'b> { + pub fn new(p: &'b Parser<'a, 'b>) -> Self { + BashGen { p } + } + + pub fn generate_to(&self, buf: &mut W) { + w!( + buf, + format!( + r#"_{name}() {{ + local i cur prev opts cmds + COMPREPLY=() + cur="${{COMP_WORDS[COMP_CWORD]}}" + prev="${{COMP_WORDS[COMP_CWORD-1]}}" + cmd="" + opts="" + + for i in ${{COMP_WORDS[@]}} + do + case "${{i}}" in + {name}) + cmd="{name}" + ;; + {subcmds} + *) + ;; + esac + done + + case "${{cmd}}" in + {name}) + opts="{name_opts}" + if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq 1 ]] ; then + COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") ) + return 0 + fi + case "${{prev}}" in + {name_opts_details} + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") ) + return 0 + ;; + {subcmd_details} + esac +}} + +complete -F _{name} -o bashdefault -o default {name} +"#, + name = self.p.meta.bin_name.as_ref().unwrap(), + name_opts = self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()), + name_opts_details = + self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()), + subcmds = self.all_subcommands(), + subcmd_details = self.subcommand_details() + ) + .as_bytes() + ); + } + + fn all_subcommands(&self) -> String { + debugln!("BashGen::all_subcommands;"); + let mut subcmds = String::new(); + let scs = completions::all_subcommand_names(self.p); + + for sc in &scs { + subcmds = format!( + r#"{} + {name}) + cmd+="__{fn_name}" + ;;"#, + subcmds, + name = sc, + fn_name = sc.replace("-", "__") + ); + } + + subcmds + } + + fn subcommand_details(&self) -> String { + debugln!("BashGen::subcommand_details;"); + let mut subcmd_dets = String::new(); + let mut scs = completions::get_all_subcommand_paths(self.p, true); + scs.sort(); + scs.dedup(); + + for sc in &scs { + subcmd_dets = format!( + r#"{} + {subcmd}) + opts="{sc_opts}" + if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then + COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") ) + return 0 + fi + case "${{prev}}" in + {opts_details} + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") ) + return 0 + ;;"#, + subcmd_dets, + subcmd = sc.replace("-", "__"), + sc_opts = self.all_options_for_path(&*sc), + level = sc.split("__").count(), + opts_details = self.option_details_for_path(&*sc) + ); + } + + subcmd_dets + } + + fn option_details_for_path(&self, path: &str) -> String { + debugln!("BashGen::option_details_for_path: path={}", path); + let mut p = self.p; + for sc in path.split("__").skip(1) { + debugln!("BashGen::option_details_for_path:iter: sc={}", sc); + p = &find_subcmd!(p, sc).unwrap().p; + } + let mut opts = String::new(); + for o in p.opts() { + if let Some(l) = o.s.long { + opts = format!( + "{} + --{}) + COMPREPLY=({}) + return 0 + ;;", + opts, + l, + self.vals_for(o) + ); + } + if let Some(s) = o.s.short { + opts = format!( + "{} + -{}) + COMPREPLY=({}) + return 0 + ;;", + opts, + s, + self.vals_for(o) + ); + } + } + opts + } + + fn vals_for(&self, o: &OptBuilder) -> String { + debugln!("BashGen::vals_for: o={}", o.b.name); + if let Some(vals) = o.possible_vals() { + format!(r#"$(compgen -W "{}" -- "${{cur}}")"#, vals.join(" ")) + } else { + String::from(r#"$(compgen -f "${cur}")"#) + } + } + + fn all_options_for_path(&self, path: &str) -> String { + debugln!("BashGen::all_options_for_path: path={}", path); + let mut p = self.p; + for sc in path.split("__").skip(1) { + debugln!("BashGen::all_options_for_path:iter: sc={}", sc); + p = &find_subcmd!(p, sc).unwrap().p; + } + let mut opts = shorts!(p).fold(String::new(), |acc, s| format!("{} -{}", acc, s)); + opts = format!( + "{} {}", + opts, + longs!(p).fold(String::new(), |acc, l| format!("{} --{}", acc, l)) + ); + opts = format!( + "{} {}", + opts, + p.positionals + .values() + .fold(String::new(), |acc, p| format!("{} {}", acc, p)) + ); + opts = format!( + "{} {}", + opts, + p.subcommands + .iter() + .fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name)) + ); + for sc in &p.subcommands { + if let Some(ref aliases) = sc.p.meta.aliases { + opts = format!( + "{} {}", + opts, + aliases + .iter() + .map(|&(n, _)| n) + .fold(String::new(), |acc, a| format!("{} {}", acc, a)) + ); + } + } + opts + } +} diff --git a/vendor/clap-2.34.0/src/completions/elvish.rs b/vendor/clap-2.34.0/src/completions/elvish.rs new file mode 100644 index 0000000000000..c6d8bb634a216 --- /dev/null +++ b/vendor/clap-2.34.0/src/completions/elvish.rs @@ -0,0 +1,127 @@ +// Std +use std::io::Write; + +// Internal +use crate::{app::parser::Parser, INTERNAL_ERROR_MSG}; + +pub struct ElvishGen<'a, 'b> +where + 'a: 'b, +{ + p: &'b Parser<'a, 'b>, +} + +impl<'a, 'b> ElvishGen<'a, 'b> { + pub fn new(p: &'b Parser<'a, 'b>) -> Self { + ElvishGen { p } + } + + pub fn generate_to(&self, buf: &mut W) { + let bin_name = self.p.meta.bin_name.as_ref().unwrap(); + + let mut names = vec![]; + let subcommands_cases = generate_inner(self.p, "", &mut names); + + let result = format!( + r#" +edit:completion:arg-completer[{bin_name}] = [@words]{{ + fn spaces [n]{{ + repeat $n ' ' | joins '' + }} + fn cand [text desc]{{ + edit:complex-candidate $text &display-suffix=' '(spaces (- 14 (wcswidth $text)))$desc + }} + command = '{bin_name}' + for word $words[1:-1] {{ + if (has-prefix $word '-') {{ + break + }} + command = $command';'$word + }} + completions = [{subcommands_cases} + ] + $completions[$command] +}} +"#, + bin_name = bin_name, + subcommands_cases = subcommands_cases + ); + + w!(buf, result.as_bytes()); + } +} + +// Escape string inside single quotes +fn escape_string(string: &str) -> String { + string.replace("'", "''") +} + +fn get_tooltip(help: Option<&str>, data: T) -> String { + match help { + Some(help) => escape_string(help), + _ => data.to_string(), + } +} + +fn generate_inner<'a, 'b, 'p>( + p: &'p Parser<'a, 'b>, + previous_command_name: &str, + names: &mut Vec<&'p str>, +) -> String { + debugln!("ElvishGen::generate_inner;"); + let command_name = if previous_command_name.is_empty() { + p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG).clone() + } else { + format!("{};{}", previous_command_name, &p.meta.name) + }; + + let mut completions = String::new(); + let preamble = String::from("\n cand "); + + for option in p.opts() { + if let Some(data) = option.s.short { + let tooltip = get_tooltip(option.b.help, data); + completions.push_str(&preamble); + completions.push_str(format!("-{} '{}'", data, tooltip).as_str()); + } + if let Some(data) = option.s.long { + let tooltip = get_tooltip(option.b.help, data); + completions.push_str(&preamble); + completions.push_str(format!("--{} '{}'", data, tooltip).as_str()); + } + } + + for flag in p.flags() { + if let Some(data) = flag.s.short { + let tooltip = get_tooltip(flag.b.help, data); + completions.push_str(&preamble); + completions.push_str(format!("-{} '{}'", data, tooltip).as_str()); + } + if let Some(data) = flag.s.long { + let tooltip = get_tooltip(flag.b.help, data); + completions.push_str(&preamble); + completions.push_str(format!("--{} '{}'", data, tooltip).as_str()); + } + } + + for subcommand in &p.subcommands { + let data = &subcommand.p.meta.name; + let tooltip = get_tooltip(subcommand.p.meta.about, data); + completions.push_str(&preamble); + completions.push_str(format!("{} '{}'", data, tooltip).as_str()); + } + + let mut subcommands_cases = format!( + r" + &'{}'= {{{} + }}", + &command_name, completions + ); + + for subcommand in &p.subcommands { + let subcommand_subcommands_cases = generate_inner(&subcommand.p, &command_name, names); + subcommands_cases.push_str(&subcommand_subcommands_cases); + } + + subcommands_cases +} diff --git a/vendor/clap-2.34.0/src/completions/fish.rs b/vendor/clap-2.34.0/src/completions/fish.rs new file mode 100644 index 0000000000000..053f56a97660f --- /dev/null +++ b/vendor/clap-2.34.0/src/completions/fish.rs @@ -0,0 +1,103 @@ +// Std +use std::io::Write; + +// Internal +use crate::app::parser::Parser; + +pub struct FishGen<'a, 'b> +where + 'a: 'b, +{ + p: &'b Parser<'a, 'b>, +} + +impl<'a, 'b> FishGen<'a, 'b> { + pub fn new(p: &'b Parser<'a, 'b>) -> Self { + FishGen { p } + } + + pub fn generate_to(&self, buf: &mut W) { + let command = self.p.meta.bin_name.as_ref().unwrap(); + let mut buffer = String::new(); + gen_fish_inner(command, self, command, &mut buffer); + w!(buf, buffer.as_bytes()); + } +} + +// Escape string inside single quotes +fn escape_string(string: &str) -> String { + string.replace("\\", "\\\\").replace("'", "\\'") +} + +fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, subcommand: &str, buffer: &mut String) { + debugln!("FishGen::gen_fish_inner;"); + // example : + // + // complete + // -c {command} + // -d "{description}" + // -s {short} + // -l {long} + // -a "{possible_arguments}" + // -r # if require parameter + // -f # don't use file completion + // -n "__fish_use_subcommand" # complete for command "myprog" + // -n "__fish_seen_subcommand_from subcmd1" # complete for command "myprog subcmd1" + + let mut basic_template = format!("complete -c {} -n ", root_command); + if root_command == subcommand { + basic_template.push_str("\"__fish_use_subcommand\""); + } else { + basic_template.push_str(format!("\"__fish_seen_subcommand_from {}\"", subcommand).as_str()); + } + + for option in comp_gen.p.opts() { + let mut template = basic_template.clone(); + if let Some(data) = option.s.short { + template.push_str(format!(" -s {}", data).as_str()); + } + if let Some(data) = option.s.long { + template.push_str(format!(" -l {}", data).as_str()); + } + if let Some(data) = option.b.help { + template.push_str(format!(" -d '{}'", escape_string(data)).as_str()); + } + if let Some(ref data) = option.v.possible_vals { + template.push_str(format!(" -r -f -a \"{}\"", data.join(" ")).as_str()); + } + buffer.push_str(template.as_str()); + buffer.push('\n'); + } + + for flag in comp_gen.p.flags() { + let mut template = basic_template.clone(); + if let Some(data) = flag.s.short { + template.push_str(format!(" -s {}", data).as_str()); + } + if let Some(data) = flag.s.long { + template.push_str(format!(" -l {}", data).as_str()); + } + if let Some(data) = flag.b.help { + template.push_str(format!(" -d '{}'", escape_string(data)).as_str()); + } + buffer.push_str(template.as_str()); + buffer.push('\n'); + } + + for subcommand in &comp_gen.p.subcommands { + let mut template = basic_template.clone(); + template.push_str(" -f"); + template.push_str(format!(" -a \"{}\"", &subcommand.p.meta.name).as_str()); + if let Some(data) = subcommand.p.meta.about { + template.push_str(format!(" -d '{}'", escape_string(data)).as_str()) + } + buffer.push_str(template.as_str()); + buffer.push('\n'); + } + + // generate options of subcommands + for subcommand in &comp_gen.p.subcommands { + let sub_comp_gen = FishGen::new(&subcommand.p); + gen_fish_inner(root_command, &sub_comp_gen, &subcommand.to_string(), buffer); + } +} diff --git a/vendor/clap-2.34.0/src/completions/macros.rs b/vendor/clap-2.34.0/src/completions/macros.rs new file mode 100644 index 0000000000000..3a69de5d745fc --- /dev/null +++ b/vendor/clap-2.34.0/src/completions/macros.rs @@ -0,0 +1,28 @@ +macro_rules! w { + ($buf:expr, $to_w:expr) => { + match $buf.write_all($to_w) { + Ok(..) => (), + Err(..) => panic!("Failed to write to completions file"), + } + }; +} + +macro_rules! get_zsh_arg_conflicts { + ($p:ident, $arg:ident, $msg:ident) => { + if let Some(conf_vec) = $arg.blacklist() { + let mut v = vec![]; + for arg_name in conf_vec { + let arg = $p.find_any_arg(arg_name).expect($msg); + if let Some(s) = arg.short() { + v.push(format!("-{}", s)); + } + if let Some(l) = arg.long() { + v.push(format!("--{}", l)); + } + } + v.join(" ") + } else { + String::new() + } + }; +} diff --git a/vendor/clap-2.34.0/src/completions/mod.rs b/vendor/clap-2.34.0/src/completions/mod.rs new file mode 100644 index 0000000000000..ede2fa1aeb21c --- /dev/null +++ b/vendor/clap-2.34.0/src/completions/mod.rs @@ -0,0 +1,182 @@ +#[macro_use] +mod macros; +mod bash; +mod elvish; +mod fish; +mod powershell; +mod shell; +mod zsh; + +// Std +use std::io::Write; + +// Internal +pub use crate::completions::shell::Shell; +use crate::{ + app::parser::Parser, + completions::{ + bash::BashGen, elvish::ElvishGen, fish::FishGen, powershell::PowerShellGen, zsh::ZshGen, + }, +}; + +pub struct ComplGen<'a, 'b> +where + 'a: 'b, +{ + p: &'b Parser<'a, 'b>, +} + +impl<'a, 'b> ComplGen<'a, 'b> { + pub fn new(p: &'b Parser<'a, 'b>) -> Self { + ComplGen { p } + } + + pub fn generate(&self, for_shell: Shell, buf: &mut W) { + match for_shell { + Shell::Bash => BashGen::new(self.p).generate_to(buf), + Shell::Fish => FishGen::new(self.p).generate_to(buf), + Shell::Zsh => ZshGen::new(self.p).generate_to(buf), + Shell::PowerShell => PowerShellGen::new(self.p).generate_to(buf), + Shell::Elvish => ElvishGen::new(self.p).generate_to(buf), + } + } +} + +// Gets all subcommands including child subcommands in the form of 'name' where the name +// is a single word (i.e. "install") of the path to said subcommand (i.e. +// "rustup toolchain install") +// +// Also note, aliases are treated as their own subcommands but duplicates of whatever they're +// aliasing. +pub fn all_subcommand_names(p: &Parser) -> Vec { + debugln!("all_subcommand_names;"); + let mut subcmds: Vec<_> = subcommands_of(p) + .iter() + .map(|&(ref n, _)| n.clone()) + .collect(); + for sc_v in p.subcommands.iter().map(|s| all_subcommand_names(&s.p)) { + subcmds.extend(sc_v); + } + subcmds.sort(); + subcmds.dedup(); + subcmds +} + +// Gets all subcommands including child subcommands in the form of ('name', 'bin_name') where the name +// is a single word (i.e. "install") of the path and full bin_name of said subcommand (i.e. +// "rustup toolchain install") +// +// Also note, aliases are treated as their own subcommands but duplicates of whatever they're +// aliasing. +pub fn all_subcommands(p: &Parser) -> Vec<(String, String)> { + debugln!("all_subcommands;"); + let mut subcmds: Vec<_> = subcommands_of(p); + for sc_v in p.subcommands.iter().map(|s| all_subcommands(&s.p)) { + subcmds.extend(sc_v); + } + subcmds +} + +// Gets all subcommands excluding child subcommands in the form of (name, bin_name) where the name +// is a single word (i.e. "install") and the bin_name is a space delineated list of the path to said +// subcommand (i.e. "rustup toolchain install") +// +// Also note, aliases are treated as their own subcommands but duplicates of whatever they're +// aliasing. +pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> { + debugln!( + "subcommands_of: name={}, bin_name={}", + p.meta.name, + p.meta.bin_name.as_ref().unwrap() + ); + let mut subcmds = vec![]; + + debugln!( + "subcommands_of: Has subcommands...{:?}", + p.has_subcommands() + ); + if !p.has_subcommands() { + let mut ret = vec![]; + debugln!("subcommands_of: Looking for aliases..."); + if let Some(ref aliases) = p.meta.aliases { + for &(n, _) in aliases { + debugln!("subcommands_of:iter:iter: Found alias...{}", n); + let mut als_bin_name: Vec<_> = + p.meta.bin_name.as_ref().unwrap().split(' ').collect(); + als_bin_name.push(n); + let old = als_bin_name.len() - 2; + als_bin_name.swap_remove(old); + ret.push((n.to_owned(), als_bin_name.join(" "))); + } + } + return ret; + } + for sc in &p.subcommands { + debugln!( + "subcommands_of:iter: name={}, bin_name={}", + sc.p.meta.name, + sc.p.meta.bin_name.as_ref().unwrap() + ); + + debugln!("subcommands_of:iter: Looking for aliases..."); + if let Some(ref aliases) = sc.p.meta.aliases { + for &(n, _) in aliases { + debugln!("subcommands_of:iter:iter: Found alias...{}", n); + let mut als_bin_name: Vec<_> = + p.meta.bin_name.as_ref().unwrap().split(' ').collect(); + als_bin_name.push(n); + let old = als_bin_name.len() - 2; + als_bin_name.swap_remove(old); + subcmds.push((n.to_owned(), als_bin_name.join(" "))); + } + } + subcmds.push(( + sc.p.meta.name.clone(), + sc.p.meta.bin_name.as_ref().unwrap().clone(), + )); + } + subcmds +} + +pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec { + debugln!("get_all_subcommand_paths;"); + let mut subcmds = vec![]; + if !p.has_subcommands() { + if !first { + let name = &*p.meta.name; + let path = p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "__"); + let mut ret = vec![path.clone()]; + if let Some(ref aliases) = p.meta.aliases { + for &(n, _) in aliases { + ret.push(path.replace(name, n)); + } + } + return ret; + } + return vec![]; + } + for sc in &p.subcommands { + let name = &*sc.p.meta.name; + let path = + sc.p.meta + .bin_name + .as_ref() + .unwrap() + .clone() + .replace(" ", "__"); + subcmds.push(path.clone()); + if let Some(ref aliases) = sc.p.meta.aliases { + for &(n, _) in aliases { + subcmds.push(path.replace(name, n)); + } + } + } + for sc_v in p + .subcommands + .iter() + .map(|s| get_all_subcommand_paths(&s.p, false)) + { + subcmds.extend(sc_v); + } + subcmds +} diff --git a/vendor/clap-2.34.0/src/completions/powershell.rs b/vendor/clap-2.34.0/src/completions/powershell.rs new file mode 100644 index 0000000000000..ba1fd77537400 --- /dev/null +++ b/vendor/clap-2.34.0/src/completions/powershell.rs @@ -0,0 +1,165 @@ +// Std +use std::io::Write; + +// Internal +use crate::{app::parser::Parser, INTERNAL_ERROR_MSG}; + +pub struct PowerShellGen<'a, 'b> +where + 'a: 'b, +{ + p: &'b Parser<'a, 'b>, +} + +impl<'a, 'b> PowerShellGen<'a, 'b> { + pub fn new(p: &'b Parser<'a, 'b>) -> Self { + PowerShellGen { p } + } + + pub fn generate_to(&self, buf: &mut W) { + let bin_name = self.p.meta.bin_name.as_ref().unwrap(); + + let mut names = vec![]; + let subcommands_cases = generate_inner(self.p, "", &mut names); + + let result = format!( + r#" +using namespace System.Management.Automation +using namespace System.Management.Automation.Language + +Register-ArgumentCompleter -Native -CommandName '{bin_name}' -ScriptBlock {{ + param($wordToComplete, $commandAst, $cursorPosition) + + $commandElements = $commandAst.CommandElements + $command = @( + '{bin_name}' + for ($i = 1; $i -lt $commandElements.Count; $i++) {{ + $element = $commandElements[$i] + if ($element -isnot [StringConstantExpressionAst] -or + $element.StringConstantType -ne [StringConstantType]::BareWord -or + $element.Value.StartsWith('-')) {{ + break + }} + $element.Value + }}) -join ';' + + $completions = @(switch ($command) {{{subcommands_cases} + }}) + + $completions.Where{{ $_.CompletionText -like "$wordToComplete*" }} | + Sort-Object -Property ListItemText +}} +"#, + bin_name = bin_name, + subcommands_cases = subcommands_cases + ); + + w!(buf, result.as_bytes()); + } +} + +// Escape string inside single quotes +fn escape_string(string: &str) -> String { + string.replace("'", "''") +} + +fn get_tooltip(help: Option<&str>, data: T) -> String { + match help { + Some(help) => escape_string(help), + _ => data.to_string(), + } +} + +fn generate_inner<'a, 'b, 'p>( + p: &'p Parser<'a, 'b>, + previous_command_name: &str, + names: &mut Vec<&'p str>, +) -> String { + debugln!("PowerShellGen::generate_inner;"); + let command_name = if previous_command_name.is_empty() { + p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG).clone() + } else { + format!("{};{}", previous_command_name, &p.meta.name) + }; + + let mut completions = String::new(); + let preamble = String::from("\n [CompletionResult]::new("); + + for option in p.opts() { + if let Some(data) = option.s.short { + let tooltip = get_tooltip(option.b.help, data); + completions.push_str(&preamble); + completions.push_str( + format!( + "'-{}', '{}', {}, '{}')", + data, data, "[CompletionResultType]::ParameterName", tooltip + ) + .as_str(), + ); + } + if let Some(data) = option.s.long { + let tooltip = get_tooltip(option.b.help, data); + completions.push_str(&preamble); + completions.push_str( + format!( + "'--{}', '{}', {}, '{}')", + data, data, "[CompletionResultType]::ParameterName", tooltip + ) + .as_str(), + ); + } + } + + for flag in p.flags() { + if let Some(data) = flag.s.short { + let tooltip = get_tooltip(flag.b.help, data); + completions.push_str(&preamble); + completions.push_str( + format!( + "'-{}', '{}', {}, '{}')", + data, data, "[CompletionResultType]::ParameterName", tooltip + ) + .as_str(), + ); + } + if let Some(data) = flag.s.long { + let tooltip = get_tooltip(flag.b.help, data); + completions.push_str(&preamble); + completions.push_str( + format!( + "'--{}', '{}', {}, '{}')", + data, data, "[CompletionResultType]::ParameterName", tooltip + ) + .as_str(), + ); + } + } + + for subcommand in &p.subcommands { + let data = &subcommand.p.meta.name; + let tooltip = get_tooltip(subcommand.p.meta.about, data); + completions.push_str(&preamble); + completions.push_str( + format!( + "'{}', '{}', {}, '{}')", + data, data, "[CompletionResultType]::ParameterValue", tooltip + ) + .as_str(), + ); + } + + let mut subcommands_cases = format!( + r" + '{}' {{{} + break + }}", + &command_name, completions + ); + + for subcommand in &p.subcommands { + let subcommand_subcommands_cases = generate_inner(&subcommand.p, &command_name, names); + subcommands_cases.push_str(&subcommand_subcommands_cases); + } + + subcommands_cases +} diff --git a/vendor/clap-2.34.0/src/completions/shell.rs b/vendor/clap-2.34.0/src/completions/shell.rs new file mode 100644 index 0000000000000..aa5034c661ce0 --- /dev/null +++ b/vendor/clap-2.34.0/src/completions/shell.rs @@ -0,0 +1,56 @@ +#[allow(deprecated, unused_imports)] +use std::ascii::AsciiExt; +use std::fmt; +use std::str::FromStr; + +/// Describes which shell to produce a completions file for +#[derive(Debug, Copy, Clone)] +pub enum Shell { + /// Generates a .bash completion file for the Bourne Again SHell (BASH) + Bash, + /// Generates a .fish completion file for the Friendly Interactive SHell (fish) + Fish, + /// Generates a completion file for the Z SHell (ZSH) + Zsh, + /// Generates a completion file for PowerShell + PowerShell, + /// Generates a completion file for Elvish + Elvish, +} + +impl Shell { + /// A list of possible variants in `&'static str` form + pub fn variants() -> [&'static str; 5] { + ["zsh", "bash", "fish", "powershell", "elvish"] + } +} + +impl FromStr for Shell { + type Err = String; + + #[cfg_attr(feature = "cargo-clippy", allow(clippy::wildcard_in_or_patterns))] + fn from_str(s: &str) -> Result { + match s { + "ZSH" | _ if s.eq_ignore_ascii_case("zsh") => Ok(Shell::Zsh), + "FISH" | _ if s.eq_ignore_ascii_case("fish") => Ok(Shell::Fish), + "BASH" | _ if s.eq_ignore_ascii_case("bash") => Ok(Shell::Bash), + "POWERSHELL" | _ if s.eq_ignore_ascii_case("powershell") => Ok(Shell::PowerShell), + "ELVISH" | _ if s.eq_ignore_ascii_case("elvish") => Ok(Shell::Elvish), + _ => Err(String::from( + "[valid values: bash, fish, zsh, powershell, elvish]", + )), + } + } +} + +impl fmt::Display for Shell { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Shell::Bash => write!(f, "BASH"), + Shell::Fish => write!(f, "FISH"), + Shell::Zsh => write!(f, "ZSH"), + Shell::PowerShell => write!(f, "POWERSHELL"), + Shell::Elvish => write!(f, "ELVISH"), + } + } +} diff --git a/vendor/clap-2.34.0/src/completions/zsh.rs b/vendor/clap-2.34.0/src/completions/zsh.rs new file mode 100644 index 0000000000000..e8ddfbd6175ec --- /dev/null +++ b/vendor/clap-2.34.0/src/completions/zsh.rs @@ -0,0 +1,484 @@ +// Std +#[allow(deprecated, unused_imports)] +use std::{ascii::AsciiExt, io::Write}; + +// Internal +use crate::{ + app::{parser::Parser, App}, + args::{AnyArg, ArgSettings}, + completions, INTERNAL_ERROR_MSG, +}; + +pub struct ZshGen<'a, 'b> +where + 'a: 'b, +{ + p: &'b Parser<'a, 'b>, +} + +impl<'a, 'b> ZshGen<'a, 'b> { + pub fn new(p: &'b Parser<'a, 'b>) -> Self { + debugln!("ZshGen::new;"); + ZshGen { p } + } + + pub fn generate_to(&self, buf: &mut W) { + debugln!("ZshGen::generate_to;"); + w!( + buf, + format!( + "\ +#compdef {name} + +autoload -U is-at-least + +_{name}() {{ + typeset -A opt_args + typeset -a _arguments_options + local ret=1 + + if is-at-least 5.2; then + _arguments_options=(-s -S -C) + else + _arguments_options=(-s -C) + fi + + local context curcontext=\"$curcontext\" state line + {initial_args} + {subcommands} +}} + +{subcommand_details} + +_{name} \"$@\"", + name = self.p.meta.bin_name.as_ref().unwrap(), + initial_args = get_args_of(self.p), + subcommands = get_subcommands_of(self.p), + subcommand_details = subcommand_details(self.p) + ) + .as_bytes() + ); + } +} + +// Displays the commands of a subcommand +// (( $+functions[_[bin_name_underscore]_commands] )) || +// _[bin_name_underscore]_commands() { +// local commands; commands=( +// '[arg_name]:[arg_help]' +// ) +// _describe -t commands '[bin_name] commands' commands "$@" +// +// Where the following variables are present: +// [bin_name_underscore]: The full space delineated bin_name, where spaces have been replaced by +// underscore characters +// [arg_name]: The name of the subcommand +// [arg_help]: The help message of the subcommand +// [bin_name]: The full space delineated bin_name +// +// Here's a snippet from rustup: +// +// (( $+functions[_rustup_commands] )) || +// _rustup_commands() { +// local commands; commands=( +// 'show:Show the active and installed toolchains' +// 'update:Update Rust toolchains' +// # ... snip for brevity +// 'help:Prints this message or the help of the given subcommand(s)' +// ) +// _describe -t commands 'rustup commands' commands "$@" +// +fn subcommand_details(p: &Parser) -> String { + debugln!("ZshGen::subcommand_details;"); + // First we do ourself + let mut ret = vec![format!( + "\ +(( $+functions[_{bin_name_underscore}_commands] )) || +_{bin_name_underscore}_commands() {{ + local commands; commands=( + {subcommands_and_args} + ) + _describe -t commands '{bin_name} commands' commands \"$@\" +}}", + bin_name_underscore = p.meta.bin_name.as_ref().unwrap().replace(" ", "__"), + bin_name = p.meta.bin_name.as_ref().unwrap(), + subcommands_and_args = subcommands_of(p) + )]; + + // Next we start looping through all the children, grandchildren, etc. + let mut all_subcommands = completions::all_subcommands(p); + all_subcommands.sort(); + all_subcommands.dedup(); + for &(_, ref bin_name) in &all_subcommands { + debugln!("ZshGen::subcommand_details:iter: bin_name={}", bin_name); + ret.push(format!( + "\ +(( $+functions[_{bin_name_underscore}_commands] )) || +_{bin_name_underscore}_commands() {{ + local commands; commands=( + {subcommands_and_args} + ) + _describe -t commands '{bin_name} commands' commands \"$@\" +}}", + bin_name_underscore = bin_name.replace(" ", "__"), + bin_name = bin_name, + subcommands_and_args = subcommands_of(parser_of(p, bin_name)) + )); + } + + ret.join("\n") +} + +// Generates subcommand completions in form of +// +// '[arg_name]:[arg_help]' +// +// Where: +// [arg_name]: the subcommand's name +// [arg_help]: the help message of the subcommand +// +// A snippet from rustup: +// 'show:Show the active and installed toolchains' +// 'update:Update Rust toolchains' +fn subcommands_of(p: &Parser) -> String { + debugln!("ZshGen::subcommands_of;"); + let mut ret = vec![]; + fn add_sc(sc: &App, n: &str, ret: &mut Vec) { + debugln!("ZshGen::add_sc;"); + let s = format!( + "\"{name}:{help}\" \\", + name = n, + help = + sc.p.meta + .about + .unwrap_or("") + .replace("[", "\\[") + .replace("]", "\\]") + ); + if !s.is_empty() { + ret.push(s); + } + } + + // The subcommands + for sc in p.subcommands() { + debugln!("ZshGen::subcommands_of:iter: subcommand={}", sc.p.meta.name); + add_sc(sc, &sc.p.meta.name, &mut ret); + if let Some(ref v) = sc.p.meta.aliases { + for alias in v.iter().filter(|&&(_, vis)| vis).map(|&(n, _)| n) { + add_sc(sc, alias, &mut ret); + } + } + } + + ret.join("\n") +} + +// Get's the subcommand section of a completion file +// This looks roughly like: +// +// case $state in +// ([bin_name]_args) +// curcontext=\"${curcontext%:*:*}:[name_hyphen]-command-$words[1]:\" +// case $line[1] in +// +// ([name]) +// _arguments -C -s -S \ +// [subcommand_args] +// && ret=0 +// +// [RECURSIVE_CALLS] +// +// ;;", +// +// [repeat] +// +// esac +// ;; +// esac", +// +// Where the following variables are present: +// [name] = The subcommand name in the form of "install" for "rustup toolchain install" +// [bin_name] = The full space delineated bin_name such as "rustup toolchain install" +// [name_hyphen] = The full space delineated bin_name, but replace spaces with hyphens +// [repeat] = From the same recursive calls, but for all subcommands +// [subcommand_args] = The same as zsh::get_args_of +fn get_subcommands_of(p: &Parser) -> String { + debugln!("get_subcommands_of;"); + + debugln!( + "get_subcommands_of: Has subcommands...{:?}", + p.has_subcommands() + ); + if !p.has_subcommands() { + return String::new(); + } + + let sc_names = completions::subcommands_of(p); + + let mut subcmds = vec![]; + for &(ref name, ref bin_name) in &sc_names { + let mut v = vec![format!("({})", name)]; + let subcommand_args = get_args_of(parser_of(p, &*bin_name)); + if !subcommand_args.is_empty() { + v.push(subcommand_args); + } + let subcommands = get_subcommands_of(parser_of(p, &*bin_name)); + if !subcommands.is_empty() { + v.push(subcommands); + } + v.push(String::from(";;")); + subcmds.push(v.join("\n")); + } + + format!( + "case $state in + ({name}) + words=($line[{pos}] \"${{words[@]}}\") + (( CURRENT += 1 )) + curcontext=\"${{curcontext%:*:*}}:{name_hyphen}-command-$line[{pos}]:\" + case $line[{pos}] in + {subcommands} + esac + ;; +esac", + name = p.meta.name, + name_hyphen = p.meta.bin_name.as_ref().unwrap().replace(" ", "-"), + subcommands = subcmds.join("\n"), + pos = p.positionals().len() + 1 + ) +} + +fn parser_of<'a, 'b>(p: &'b Parser<'a, 'b>, sc: &str) -> &'b Parser<'a, 'b> { + debugln!("parser_of: sc={}", sc); + if sc == p.meta.bin_name.as_ref().unwrap_or(&String::new()) { + return p; + } + &p.find_subcommand(sc).expect(INTERNAL_ERROR_MSG).p +} + +// Writes out the args section, which ends up being the flags, opts and postionals, and a jump to +// another ZSH function if there are subcommands. +// The structer works like this: +// ([conflicting_args]) [multiple] arg [takes_value] [[help]] [: :(possible_values)] +// ^-- list '-v -h' ^--'*' ^--'+' ^-- list 'one two three' +// +// An example from the rustup command: +// +// _arguments -C -s -S \ +// '(-h --help --verbose)-v[Enable verbose output]' \ +// '(-V -v --version --verbose --help)-h[Prints help information]' \ +// # ... snip for brevity +// ':: :_rustup_commands' \ # <-- displays subcommands +// '*::: :->rustup' \ # <-- displays subcommand args and child subcommands +// && ret=0 +// +// The args used for _arguments are as follows: +// -C: modify the $context internal variable +// -s: Allow stacking of short args (i.e. -a -b -c => -abc) +// -S: Do not complete anything after '--' and treat those as argument values +fn get_args_of(p: &Parser) -> String { + debugln!("get_args_of;"); + let mut ret = vec![String::from("_arguments \"${_arguments_options[@]}\" \\")]; + let opts = write_opts_of(p); + let flags = write_flags_of(p); + let positionals = write_positionals_of(p); + let sc_or_a = if p.has_subcommands() { + format!( + "\":: :_{name}_commands\" \\", + name = p.meta.bin_name.as_ref().unwrap().replace(" ", "__") + ) + } else { + String::new() + }; + let sc = if p.has_subcommands() { + format!("\"*::: :->{name}\" \\", name = p.meta.name) + } else { + String::new() + }; + + if !opts.is_empty() { + ret.push(opts); + } + if !flags.is_empty() { + ret.push(flags); + } + if !positionals.is_empty() { + ret.push(positionals); + } + if !sc_or_a.is_empty() { + ret.push(sc_or_a); + } + if !sc.is_empty() { + ret.push(sc); + } + ret.push(String::from("&& ret=0")); + + ret.join("\n") +} + +// Escape help string inside single quotes and brackets +fn escape_help(string: &str) -> String { + string + .replace("\\", "\\\\") + .replace("'", "'\\''") + .replace("[", "\\[") + .replace("]", "\\]") +} + +// Escape value string inside single quotes and parentheses +fn escape_value(string: &str) -> String { + string + .replace("\\", "\\\\") + .replace("'", "'\\''") + .replace("(", "\\(") + .replace(")", "\\)") + .replace(" ", "\\ ") +} + +fn write_opts_of(p: &Parser) -> String { + debugln!("write_opts_of;"); + let mut ret = vec![]; + for o in p.opts() { + debugln!("write_opts_of:iter: o={}", o.name()); + let help = o.help().map_or(String::new(), escape_help); + let mut conflicts = get_zsh_arg_conflicts!(p, o, INTERNAL_ERROR_MSG); + conflicts = if conflicts.is_empty() { + String::new() + } else { + format!("({})", conflicts) + }; + + let multiple = if o.is_set(ArgSettings::Multiple) { + "*" + } else { + "" + }; + let pv = if let Some(pv_vec) = o.possible_vals() { + format!( + ": :({})", + pv_vec + .iter() + .map(|v| escape_value(*v)) + .collect::>() + .join(" ") + ) + } else { + String::new() + }; + if let Some(short) = o.short() { + let s = format!( + "'{conflicts}{multiple}-{arg}+[{help}]{possible_values}' \\", + conflicts = conflicts, + multiple = multiple, + arg = short, + possible_values = pv, + help = help + ); + + debugln!("write_opts_of:iter: Wrote...{}", &*s); + ret.push(s); + } + if let Some(long) = o.long() { + let l = format!( + "'{conflicts}{multiple}--{arg}=[{help}]{possible_values}' \\", + conflicts = conflicts, + multiple = multiple, + arg = long, + possible_values = pv, + help = help + ); + + debugln!("write_opts_of:iter: Wrote...{}", &*l); + ret.push(l); + } + } + + ret.join("\n") +} + +fn write_flags_of(p: &Parser) -> String { + debugln!("write_flags_of;"); + let mut ret = vec![]; + for f in p.flags() { + debugln!("write_flags_of:iter: f={}", f.name()); + let help = f.help().map_or(String::new(), escape_help); + let mut conflicts = get_zsh_arg_conflicts!(p, f, INTERNAL_ERROR_MSG); + conflicts = if conflicts.is_empty() { + String::new() + } else { + format!("({})", conflicts) + }; + + let multiple = if f.is_set(ArgSettings::Multiple) { + "*" + } else { + "" + }; + if let Some(short) = f.short() { + let s = format!( + "'{conflicts}{multiple}-{arg}[{help}]' \\", + multiple = multiple, + conflicts = conflicts, + arg = short, + help = help + ); + + debugln!("write_flags_of:iter: Wrote...{}", &*s); + ret.push(s); + } + + if let Some(long) = f.long() { + let l = format!( + "'{conflicts}{multiple}--{arg}[{help}]' \\", + conflicts = conflicts, + multiple = multiple, + arg = long, + help = help + ); + + debugln!("write_flags_of:iter: Wrote...{}", &*l); + ret.push(l); + } + } + + ret.join("\n") +} + +fn write_positionals_of(p: &Parser) -> String { + debugln!("write_positionals_of;"); + let mut ret = vec![]; + for arg in p.positionals() { + debugln!("write_positionals_of:iter: arg={}", arg.b.name); + let a = format!( + "'{optional}:{name}{help}:{action}' \\", + optional = if !arg.b.is_set(ArgSettings::Required) { + ":" + } else { + "" + }, + name = arg.b.name, + help = arg + .b + .help + .map_or("".to_owned(), |v| " -- ".to_owned() + v) + .replace("[", "\\[") + .replace("]", "\\]"), + action = arg.possible_vals().map_or("_files".to_owned(), |values| { + format!( + "({})", + values + .iter() + .map(|v| escape_value(*v)) + .collect::>() + .join(" ") + ) + }) + ); + + debugln!("write_positionals_of:iter: Wrote...{}", a); + ret.push(a); + } + + ret.join("\n") +} diff --git a/vendor/clap-2.34.0/src/errors.rs b/vendor/clap-2.34.0/src/errors.rs new file mode 100644 index 0000000000000..df01bb19a7dff --- /dev/null +++ b/vendor/clap-2.34.0/src/errors.rs @@ -0,0 +1,933 @@ +// Std +use std::{ + convert::From, + error::Error as StdError, + fmt as std_fmt, + fmt::Display, + io::{self, Write}, + process, + result::Result as StdResult, +}; + +// Internal +use crate::{ + args::AnyArg, + fmt::{ColorWhen, Colorizer, ColorizerOption}, + suggestions, +}; + +/// Short hand for [`Result`] type +/// +/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html +pub type Result = StdResult; + +/// Command line argument parser kind of error +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum ErrorKind { + /// Occurs when an [`Arg`] has a set of possible values, + /// and the user provides a value which isn't in that set. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("speed") + /// .possible_value("fast") + /// .possible_value("slow")) + /// .get_matches_from_safe(vec!["prog", "other"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidValue); + /// ``` + /// [`Arg`]: ./struct.Arg.html + InvalidValue, + + /// Occurs when a user provides a flag, option, argument or subcommand which isn't defined. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::from_usage("--flag 'some flag'")) + /// .get_matches_from_safe(vec!["prog", "--other"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + UnknownArgument, + + /// Occurs when the user provides an unrecognized [`SubCommand`] which meets the threshold for + /// being similar enough to an existing subcommand. + /// If it doesn't meet the threshold, or the 'suggestions' feature is disabled, + /// the more general [`UnknownArgument`] error is returned. + /// + /// # Examples + /// + #[cfg_attr(not(feature = "suggestions"), doc = " ```no_run")] + #[cfg_attr(feature = "suggestions", doc = " ```")] + /// # use clap::{App, Arg, ErrorKind, SubCommand}; + /// let result = App::new("prog") + /// .subcommand(SubCommand::with_name("config") + /// .about("Used for configuration") + /// .arg(Arg::with_name("config_file") + /// .help("The configuration file to use") + /// .index(1))) + /// .get_matches_from_safe(vec!["prog", "confi"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidSubcommand); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument + InvalidSubcommand, + + /// Occurs when the user provides an unrecognized [`SubCommand`] which either + /// doesn't meet the threshold for being similar enough to an existing subcommand, + /// or the 'suggestions' feature is disabled. + /// Otherwise the more detailed [`InvalidSubcommand`] error is returned. + /// + /// This error typically happens when passing additional subcommand names to the `help` + /// subcommand. Otherwise, the more general [`UnknownArgument`] error is used. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind, SubCommand}; + /// let result = App::new("prog") + /// .subcommand(SubCommand::with_name("config") + /// .about("Used for configuration") + /// .arg(Arg::with_name("config_file") + /// .help("The configuration file to use") + /// .index(1))) + /// .get_matches_from_safe(vec!["prog", "help", "nothing"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnrecognizedSubcommand); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`InvalidSubcommand`]: ./enum.ErrorKind.html#variant.InvalidSubcommand + /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument + UnrecognizedSubcommand, + + /// Occurs when the user provides an empty value for an option that does not allow empty + /// values. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("color") + /// .long("color") + /// .empty_values(false)) + /// .get_matches_from_safe(vec!["prog", "--color="]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); + /// ``` + EmptyValue, + + /// Occurs when the user provides a value for an argument with a custom validation and the + /// value fails that validation. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// fn is_numeric(val: String) -> Result<(), String> { + /// match val.parse::() { + /// Ok(..) => Ok(()), + /// Err(..) => Err(String::from("Value wasn't a number!")), + /// } + /// } + /// + /// let result = App::new("prog") + /// .arg(Arg::with_name("num") + /// .validator(is_numeric)) + /// .get_matches_from_safe(vec!["prog", "NotANumber"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::ValueValidation); + /// ``` + ValueValidation, + + /// Occurs when a user provides more values for an argument than were defined by setting + /// [`Arg::max_values`]. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("arg") + /// .multiple(true) + /// .max_values(2)) + /// .get_matches_from_safe(vec!["prog", "too", "many", "values"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::TooManyValues); + /// ``` + /// [`Arg::max_values`]: ./struct.Arg.html#method.max_values + TooManyValues, + + /// Occurs when the user provides fewer values for an argument than were defined by setting + /// [`Arg::min_values`]. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("some_opt") + /// .long("opt") + /// .min_values(3)) + /// .get_matches_from_safe(vec!["prog", "--opt", "too", "few"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::TooFewValues); + /// ``` + /// [`Arg::min_values`]: ./struct.Arg.html#method.min_values + TooFewValues, + + /// Occurs when the user provides a different number of values for an argument than what's + /// been defined by setting [`Arg::number_of_values`] or than was implicitly set by + /// [`Arg::value_names`]. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("some_opt") + /// .long("opt") + /// .takes_value(true) + /// .number_of_values(2)) + /// .get_matches_from_safe(vec!["prog", "--opt", "wrong"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::WrongNumberOfValues); + /// ``` + /// + /// [`Arg::number_of_values`]: ./struct.Arg.html#method.number_of_values + /// [`Arg::value_names`]: ./struct.Arg.html#method.value_names + WrongNumberOfValues, + + /// Occurs when the user provides two values which conflict with each other and can't be used + /// together. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("debug") + /// .long("debug") + /// .conflicts_with("color")) + /// .arg(Arg::with_name("color") + /// .long("color")) + /// .get_matches_from_safe(vec!["prog", "--debug", "--color"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::ArgumentConflict); + /// ``` + ArgumentConflict, + + /// Occurs when the user does not provide one or more required arguments. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("debug") + /// .required(true)) + /// .get_matches_from_safe(vec!["prog"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + MissingRequiredArgument, + + /// Occurs when a subcommand is required (as defined by [`AppSettings::SubcommandRequired`]), + /// but the user does not provide one. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings, SubCommand, ErrorKind}; + /// let err = App::new("prog") + /// .setting(AppSettings::SubcommandRequired) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", + /// ]); + /// assert!(err.is_err()); + /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingSubcommand); + /// # ; + /// ``` + /// [`AppSettings::SubcommandRequired`]: ./enum.AppSettings.html#variant.SubcommandRequired + MissingSubcommand, + + /// Occurs when either an argument or [`SubCommand`] is required, as defined by + /// [`AppSettings::ArgRequiredElseHelp`], but the user did not provide one. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings, ErrorKind, SubCommand}; + /// let result = App::new("prog") + /// .setting(AppSettings::ArgRequiredElseHelp) + /// .subcommand(SubCommand::with_name("config") + /// .about("Used for configuration") + /// .arg(Arg::with_name("config_file") + /// .help("The configuration file to use"))) + /// .get_matches_from_safe(vec!["prog"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::MissingArgumentOrSubcommand); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings::ArgRequiredElseHelp`]: ./enum.AppSettings.html#variant.ArgRequiredElseHelp + MissingArgumentOrSubcommand, + + /// Occurs when the user provides multiple values to an argument which doesn't allow that. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("debug") + /// .long("debug") + /// .multiple(false)) + /// .get_matches_from_safe(vec!["prog", "--debug", "--debug"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnexpectedMultipleUsage); + /// ``` + UnexpectedMultipleUsage, + + /// Occurs when the user provides a value containing invalid UTF-8 for an argument and + /// [`AppSettings::StrictUtf8`] is set. + /// + /// # Platform Specific + /// + /// Non-Windows platforms only (such as Linux, Unix, macOS, etc.) + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, Arg, ErrorKind, AppSettings}; + /// # use std::os::unix::ffi::OsStringExt; + /// # use std::ffi::OsString; + /// let result = App::new("prog") + /// .setting(AppSettings::StrictUtf8) + /// .arg(Arg::with_name("utf8") + /// .short("u") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![OsString::from("myprog"), + /// OsString::from("-u"), + /// OsString::from_vec(vec![0xE9])]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidUtf8); + /// ``` + /// [`AppSettings::StrictUtf8`]: ./enum.AppSettings.html#variant.StrictUtf8 + InvalidUtf8, + + /// Not a true "error" as it means `--help` or similar was used. + /// The help message will be sent to `stdout`. + /// + /// **Note**: If the help is displayed due to an error (such as missing subcommands) it will + /// be sent to `stderr` instead of `stdout`. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .get_matches_from_safe(vec!["prog", "--help"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::HelpDisplayed); + /// ``` + HelpDisplayed, + + /// Not a true "error" as it means `--version` or similar was used. + /// The message will be sent to `stdout`. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .get_matches_from_safe(vec!["prog", "--version"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::VersionDisplayed); + /// ``` + VersionDisplayed, + + /// Occurs when using the [`value_t!`] and [`values_t!`] macros to convert an argument value + /// into type `T`, but the argument you requested wasn't used. I.e. you asked for an argument + /// with name `config` to be converted, but `config` wasn't used by the user. + /// [`value_t!`]: ./macro.value_t!.html + /// [`values_t!`]: ./macro.values_t!.html + ArgumentNotFound, + + /// Represents an [I/O error]. + /// Can occur when writing to `stderr` or `stdout` or reading a configuration file. + /// [I/O error]: https://doc.rust-lang.org/std/io/struct.Error.html + Io, + + /// Represents a [Format error] (which is a part of [`Display`]). + /// Typically caused by writing to `stderr` or `stdout`. + /// + /// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html + /// [Format error]: https://doc.rust-lang.org/std/fmt/struct.Error.html + Format, +} + +/// Command Line Argument Parser Error +#[derive(Debug)] +pub struct Error { + /// Formatted error message + pub message: String, + /// The type of error + pub kind: ErrorKind, + /// Any additional information passed along, such as the argument name that caused the error + pub info: Option>, +} + +impl Error { + /// Should the message be written to `stdout` or not + pub fn use_stderr(&self) -> bool { + !matches!( + self.kind, + ErrorKind::HelpDisplayed | ErrorKind::VersionDisplayed + ) + } + + /// Prints the error message and exits. If `Error::use_stderr` evaluates to `true`, the message + /// will be written to `stderr` and exits with a status of `1`. Otherwise, `stdout` is used + /// with a status of `0`. + pub fn exit(&self) -> ! { + if self.use_stderr() { + wlnerr!(@nopanic "{}", self.message); + process::exit(1); + } + // We are deliberately dropping errors here. We could match on the error kind, and only + // drop things such as `std::io::ErrorKind::BrokenPipe`, however nothing is being bubbled + // up or reported back to the caller and we will be exit'ing the process anyways. + // Additionally, changing this API to bubble up the result would be a breaking change. + // + // Another approach could be to try and write to stdout, if that fails due to a broken pipe + // then use stderr. However, that would change the semantics in what could be argued is a + // breaking change. Simply dropping the error, can always be changed to this "use stderr if + // stdout is closed" approach later if desired. + // + // A good explanation of the types of errors are SIGPIPE where the read side of the pipe + // closes before the write side. See the README in `calm_io` for a good explanation: + // + // https://github.com/myrrlyn/calm_io/blob/a42845575a04cd8b65e92c19d104627f5fcad3d7/README.md + let _ = writeln!(&mut io::stdout().lock(), "{}", self.message); + process::exit(0); + } + + #[doc(hidden)] + pub fn write_to(&self, w: &mut W) -> io::Result<()> { + write!(w, "{}", self.message) + } + + #[doc(hidden)] + pub fn argument_conflict( + arg: &AnyArg, + other: Option, + usage: U, + color: ColorWhen, + ) -> Self + where + O: Into, + U: Display, + { + let mut v = vec![arg.name().to_owned()]; + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The argument '{}' cannot be used with {}\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(&*arg.to_string()), + match other { + Some(name) => { + let n = name.into(); + v.push(n.clone()); + c.warning(format!("'{}'", n)) + } + None => c.none("one or more of the other specified arguments".to_owned()), + }, + usage, + c.good("--help") + ), + kind: ErrorKind::ArgumentConflict, + info: Some(v), + } + } + + #[doc(hidden)] + pub fn empty_value(arg: &AnyArg, usage: U, color: ColorWhen) -> Self + where + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The argument '{}' requires a value but none was supplied\ + \n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(arg.to_string()), + usage, + c.good("--help") + ), + kind: ErrorKind::EmptyValue, + info: Some(vec![arg.name().to_owned()]), + } + } + + #[doc(hidden)] + pub fn invalid_value( + bad_val: B, + good_vals: &[G], + arg: &AnyArg, + usage: U, + color: ColorWhen, + ) -> Self + where + B: AsRef, + G: AsRef + Display, + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + let suffix = suggestions::did_you_mean_value_suffix(bad_val.as_ref(), good_vals.iter()); + + let mut sorted = vec![]; + for v in good_vals { + let val = format!("{}", c.good(v)); + sorted.push(val); + } + sorted.sort(); + let valid_values = sorted.join(", "); + Error { + message: format!( + "{} '{}' isn't a valid value for '{}'\n\t\ + [possible values: {}]\n\ + {}\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(bad_val.as_ref()), + c.warning(arg.to_string()), + valid_values, + suffix.0, + usage, + c.good("--help") + ), + kind: ErrorKind::InvalidValue, + info: Some(vec![arg.name().to_owned(), bad_val.as_ref().to_owned()]), + } + } + + #[doc(hidden)] + pub fn invalid_subcommand( + subcmd: S, + did_you_mean: D, + name: N, + usage: U, + color: ColorWhen, + ) -> Self + where + S: Into, + D: AsRef + Display, + N: Display, + U: Display, + { + let s = subcmd.into(); + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The subcommand '{}' wasn't recognized\n\t\ + Did you mean '{}'?\n\n\ + If you believe you received this message in error, try \ + re-running with '{} {} {}'\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(&*s), + c.good(did_you_mean.as_ref()), + name, + c.good("--"), + &*s, + usage, + c.good("--help") + ), + kind: ErrorKind::InvalidSubcommand, + info: Some(vec![s]), + } + } + + #[doc(hidden)] + pub fn unrecognized_subcommand(subcmd: S, name: N, color: ColorWhen) -> Self + where + S: Into, + N: Display, + { + let s = subcmd.into(); + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The subcommand '{}' wasn't recognized\n\n\ + {}\n\t\ + {} help ...\n\n\ + For more information try {}", + c.error("error:"), + c.warning(&*s), + c.warning("USAGE:"), + name, + c.good("--help") + ), + kind: ErrorKind::UnrecognizedSubcommand, + info: Some(vec![s]), + } + } + + #[doc(hidden)] + pub fn missing_required_argument(required: R, usage: U, color: ColorWhen) -> Self + where + R: Display, + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The following required arguments were not provided:{}\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + required, + usage, + c.good("--help") + ), + kind: ErrorKind::MissingRequiredArgument, + info: None, + } + } + + #[doc(hidden)] + pub fn missing_subcommand(name: N, usage: U, color: ColorWhen) -> Self + where + N: AsRef + Display, + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} '{}' requires a subcommand, but one was not provided\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(name), + usage, + c.good("--help") + ), + kind: ErrorKind::MissingSubcommand, + info: None, + } + } + + #[doc(hidden)] + pub fn invalid_utf8(usage: U, color: ColorWhen) -> Self + where + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} Invalid UTF-8 was detected in one or more arguments\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + usage, + c.good("--help") + ), + kind: ErrorKind::InvalidUtf8, + info: None, + } + } + + #[doc(hidden)] + pub fn too_many_values(val: V, arg: &AnyArg, usage: U, color: ColorWhen) -> Self + where + V: AsRef + Display + ToOwned, + U: Display, + { + let v = val.as_ref(); + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The value '{}' was provided to '{}', but it wasn't expecting \ + any more values\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(v), + c.warning(arg.to_string()), + usage, + c.good("--help") + ), + kind: ErrorKind::TooManyValues, + info: Some(vec![arg.name().to_owned(), v.to_owned()]), + } + } + + #[doc(hidden)] + pub fn too_few_values( + arg: &AnyArg, + min_vals: u64, + curr_vals: usize, + usage: U, + color: ColorWhen, + ) -> Self + where + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The argument '{}' requires at least {} values, but only {} w{} \ + provided\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(arg.to_string()), + c.warning(min_vals.to_string()), + c.warning(curr_vals.to_string()), + if curr_vals > 1 { "ere" } else { "as" }, + usage, + c.good("--help") + ), + kind: ErrorKind::TooFewValues, + info: Some(vec![arg.name().to_owned()]), + } + } + + #[doc(hidden)] + pub fn value_validation(arg: Option<&AnyArg>, err: String, color: ColorWhen) -> Self { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} Invalid value{}: {}", + c.error("error:"), + if let Some(a) = arg { + format!(" for '{}'", c.warning(a.to_string())) + } else { + "".to_string() + }, + err + ), + kind: ErrorKind::ValueValidation, + info: None, + } + } + + #[doc(hidden)] + pub fn value_validation_auto(err: String) -> Self { + let n: Option<&AnyArg> = None; + Error::value_validation(n, err, ColorWhen::Auto) + } + + #[doc(hidden)] + pub fn wrong_number_of_values( + arg: &AnyArg, + num_vals: u64, + curr_vals: usize, + suffix: S, + usage: U, + color: ColorWhen, + ) -> Self + where + S: Display, + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The argument '{}' requires {} values, but {} w{} \ + provided\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(arg.to_string()), + c.warning(num_vals.to_string()), + c.warning(curr_vals.to_string()), + suffix, + usage, + c.good("--help") + ), + kind: ErrorKind::WrongNumberOfValues, + info: Some(vec![arg.name().to_owned()]), + } + } + + #[doc(hidden)] + pub fn unexpected_multiple_usage(arg: &AnyArg, usage: U, color: ColorWhen) -> Self + where + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The argument '{}' was provided more than once, but cannot \ + be used multiple times\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(arg.to_string()), + usage, + c.good("--help") + ), + kind: ErrorKind::UnexpectedMultipleUsage, + info: Some(vec![arg.name().to_owned()]), + } + } + + #[doc(hidden)] + pub fn unknown_argument(arg: A, did_you_mean: &str, usage: U, color: ColorWhen) -> Self + where + A: Into, + U: Display, + { + let a = arg.into(); + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} Found argument '{}' which wasn't expected, or isn't valid in \ + this context{}\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(&*a), + if did_you_mean.is_empty() { + "\n".to_owned() + } else { + format!("{}\n", did_you_mean) + }, + usage, + c.good("--help") + ), + kind: ErrorKind::UnknownArgument, + info: Some(vec![a]), + } + } + + #[doc(hidden)] + pub fn io_error(e: &Error, color: ColorWhen) -> Self { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!("{} {}", c.error("error:"), e.description()), + kind: ErrorKind::Io, + info: None, + } + } + + #[doc(hidden)] + pub fn argument_not_found_auto(arg: A) -> Self + where + A: Into, + { + let a = arg.into(); + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: ColorWhen::Auto, + }); + Error { + message: format!("{} The argument '{}' wasn't found", c.error("error:"), a), + kind: ErrorKind::ArgumentNotFound, + info: Some(vec![a]), + } + } + + /// Create an error with a custom description. + /// + /// This can be used in combination with `Error::exit` to exit your program + /// with a custom error message. + pub fn with_description(description: &str, kind: ErrorKind) -> Self { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: ColorWhen::Auto, + }); + Error { + message: format!("{} {}", c.error("error:"), description), + kind, + info: None, + } + } +} + +impl StdError for Error { + fn description(&self) -> &str { + &*self.message + } +} + +impl Display for Error { + fn fmt(&self, f: &mut std_fmt::Formatter) -> std_fmt::Result { + writeln!(f, "{}", self.message) + } +} + +impl From for Error { + fn from(e: io::Error) -> Self { + Error::with_description(e.description(), ErrorKind::Io) + } +} + +impl From for Error { + fn from(e: std_fmt::Error) -> Self { + Error::with_description(e.description(), ErrorKind::Format) + } +} diff --git a/vendor/clap-2.34.0/src/fmt.rs b/vendor/clap-2.34.0/src/fmt.rs new file mode 100644 index 0000000000000..f447565bd5983 --- /dev/null +++ b/vendor/clap-2.34.0/src/fmt.rs @@ -0,0 +1,192 @@ +#[cfg(all(feature = "color", not(target_os = "windows")))] +use ansi_term::ANSIString; + +#[cfg(all(feature = "color", not(target_os = "windows")))] +use ansi_term::Colour::{Green, Red, Yellow}; + +use std::env; +use std::fmt; + +#[doc(hidden)] +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum ColorWhen { + Auto, + Always, + Never, +} + +#[cfg(feature = "color")] +pub fn is_a_tty(stderr: bool) -> bool { + debugln!("is_a_tty: stderr={:?}", stderr); + let stream = if stderr { + atty::Stream::Stderr + } else { + atty::Stream::Stdout + }; + atty::is(stream) +} + +#[cfg(not(feature = "color"))] +pub fn is_a_tty(_: bool) -> bool { + debugln!("is_a_tty;"); + false +} + +pub fn is_term_dumb() -> bool { + env::var("TERM").ok() == Some(String::from("dumb")) +} + +#[doc(hidden)] +pub struct ColorizerOption { + pub use_stderr: bool, + pub when: ColorWhen, +} + +#[doc(hidden)] +pub struct Colorizer { + when: ColorWhen, +} + +macro_rules! color { + ($_self:ident, $c:ident, $m:expr) => { + match $_self.when { + ColorWhen::Auto => Format::$c($m), + ColorWhen::Always => Format::$c($m), + ColorWhen::Never => Format::None($m), + } + }; +} + +impl Colorizer { + pub fn new(option: ColorizerOption) -> Colorizer { + let is_a_tty = is_a_tty(option.use_stderr); + let is_term_dumb = is_term_dumb(); + Colorizer { + when: match option.when { + ColorWhen::Auto if is_a_tty && !is_term_dumb => ColorWhen::Auto, + ColorWhen::Auto => ColorWhen::Never, + when => when, + }, + } + } + + pub fn good(&self, msg: T) -> Format + where + T: fmt::Display + AsRef, + { + debugln!("Colorizer::good;"); + color!(self, Good, msg) + } + + pub fn warning(&self, msg: T) -> Format + where + T: fmt::Display + AsRef, + { + debugln!("Colorizer::warning;"); + color!(self, Warning, msg) + } + + pub fn error(&self, msg: T) -> Format + where + T: fmt::Display + AsRef, + { + debugln!("Colorizer::error;"); + color!(self, Error, msg) + } + + pub fn none(&self, msg: T) -> Format + where + T: fmt::Display + AsRef, + { + debugln!("Colorizer::none;"); + Format::None(msg) + } +} + +impl Default for Colorizer { + fn default() -> Self { + Colorizer::new(ColorizerOption { + use_stderr: true, + when: ColorWhen::Auto, + }) + } +} + +/// Defines styles for different types of error messages. Defaults to Error=Red, Warning=Yellow, +/// and Good=Green +#[derive(Debug)] +#[doc(hidden)] +pub enum Format { + /// Defines the style used for errors, defaults to Red + Error(T), + /// Defines the style used for warnings, defaults to Yellow + Warning(T), + /// Defines the style used for good values, defaults to Green + Good(T), + /// Defines no formatting style + None(T), +} + +#[cfg(all(feature = "color", not(target_os = "windows")))] +impl> Format { + fn format(&self) -> ANSIString { + match *self { + Format::Error(ref e) => Red.bold().paint(e.as_ref()), + Format::Warning(ref e) => Yellow.paint(e.as_ref()), + Format::Good(ref e) => Green.paint(e.as_ref()), + Format::None(ref e) => ANSIString::from(e.as_ref()), + } + } +} + +#[cfg(any(not(feature = "color"), target_os = "windows"))] +#[cfg_attr(feature = "cargo-clippy", allow(clippy::match_same_arms))] +impl Format { + fn format(&self) -> &T { + match *self { + Format::Error(ref e) => e, + Format::Warning(ref e) => e, + Format::Good(ref e) => e, + Format::None(ref e) => e, + } + } +} + +#[cfg(all(feature = "color", not(target_os = "windows")))] +impl> fmt::Display for Format { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", &self.format()) + } +} + +#[cfg(any(not(feature = "color"), target_os = "windows"))] +impl fmt::Display for Format { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", &self.format()) + } +} + +#[cfg(all(test, feature = "color", not(target_os = "windows")))] +mod test { + use super::Format; + use ansi_term::ANSIString; + use ansi_term::Colour::{Green, Red, Yellow}; + + #[test] + fn colored_output() { + let err = Format::Error("error"); + assert_eq!( + &*format!("{}", err), + &*format!("{}", Red.bold().paint("error")) + ); + let good = Format::Good("good"); + assert_eq!(&*format!("{}", good), &*format!("{}", Green.paint("good"))); + let warn = Format::Warning("warn"); + assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn"))); + let none = Format::None("none"); + assert_eq!( + &*format!("{}", none), + &*format!("{}", ANSIString::from("none")) + ); + } +} diff --git a/vendor/clap-2.34.0/src/lib.rs b/vendor/clap-2.34.0/src/lib.rs new file mode 100644 index 0000000000000..8c47b779ee1e2 --- /dev/null +++ b/vendor/clap-2.34.0/src/lib.rs @@ -0,0 +1,638 @@ +// Copyright â“’ 2015-2016 Kevin B. Knapp and [`clap-rs` contributors](https://github.com/clap-rs/clap/blob/v2.33.1/CONTRIBUTORS.md). +// Licensed under the MIT license +// (see LICENSE or ) All files in the project carrying such +// notice may not be copied, modified, or distributed except according to those terms. + +//! `clap` is a simple-to-use, efficient, and full-featured library for parsing command line +//! arguments and subcommands when writing console/terminal applications. +//! +//! ## About +//! +//! `clap` is used to parse *and validate* the string of command line arguments provided by the user +//! at runtime. You provide the list of valid possibilities, and `clap` handles the rest. This means +//! you focus on your *applications* functionality, and less on the parsing and validating of +//! arguments. +//! +//! `clap` also provides the traditional version and help switches (or flags) 'for free' meaning +//! automatically with no configuration. It does this by checking the list of valid possibilities you +//! supplied and adding only the ones you haven't already defined. If you are using subcommands, +//! `clap` will also auto-generate a `help` subcommand for you in addition to the traditional flags. +//! +//! Once `clap` parses the user provided string of arguments, it returns the matches along with any +//! applicable values. If the user made an error or typo, `clap` informs them of the mistake and +//! exits gracefully (or returns a `Result` type and allows you to perform any clean up prior to +//! exit). Because of this, you can make reasonable assumptions in your code about the validity of +//! the arguments. +//! +//! +//! ## Quick Example +//! +//! The following examples show a quick example of some of the very basic functionality of `clap`. +//! For more advanced usage, such as requirements, conflicts, groups, multiple values and +//! occurrences see the [documentation](https://docs.rs/clap/), [examples/] directory of +//! this repository or the [video tutorials]. +//! +//! **NOTE:** All of these examples are functionally the same, but show different styles in which to +//! use `clap` +//! +//! The first example shows a method that allows more advanced configuration options (not shown in +//! this small example), or even dynamically generating arguments when desired. The downside is it's +//! more verbose. +//! +//! ```no_run +//! // (Full example with detailed comments in examples/01b_quick_example.rs) +//! // +//! // This example demonstrates clap's full 'builder pattern' style of creating arguments which is +//! // more verbose, but allows easier editing, and at times more advanced options, or the possibility +//! // to generate arguments dynamically. +//! extern crate clap; +//! use clap::{Arg, App, SubCommand}; +//! +//! fn main() { +//! let matches = App::new("My Super Program") +//! .version("1.0") +//! .author("Kevin K. ") +//! .about("Does awesome things") +//! .arg(Arg::with_name("config") +//! .short("c") +//! .long("config") +//! .value_name("FILE") +//! .help("Sets a custom config file") +//! .takes_value(true)) +//! .arg(Arg::with_name("INPUT") +//! .help("Sets the input file to use") +//! .required(true) +//! .index(1)) +//! .arg(Arg::with_name("v") +//! .short("v") +//! .multiple(true) +//! .help("Sets the level of verbosity")) +//! .subcommand(SubCommand::with_name("test") +//! .about("controls testing features") +//! .version("1.3") +//! .author("Someone E. ") +//! .arg(Arg::with_name("debug") +//! .short("d") +//! .help("print debug information verbosely"))) +//! .get_matches(); +//! +//! // Gets a value for config if supplied by user, or defaults to "default.conf" +//! let config = matches.value_of("config").unwrap_or("default.conf"); +//! println!("Value for config: {}", config); +//! +//! // Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't +//! // required we could have used an 'if let' to conditionally get the value) +//! println!("Using input file: {}", matches.value_of("INPUT").unwrap()); +//! +//! // Vary the output based on how many times the user used the "verbose" flag +//! // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v' +//! match matches.occurrences_of("v") { +//! 0 => println!("No verbose info"), +//! 1 => println!("Some verbose info"), +//! 2 => println!("Tons of verbose info"), +//! 3 | _ => println!("Don't be crazy"), +//! } +//! +//! // You can handle information about subcommands by requesting their matches by name +//! // (as below), requesting just the name used, or both at the same time +//! if let Some(matches) = matches.subcommand_matches("test") { +//! if matches.is_present("debug") { +//! println!("Printing debug info..."); +//! } else { +//! println!("Printing normally..."); +//! } +//! } +//! +//! // more program logic goes here... +//! } +//! ``` +//! +//! The next example shows a far less verbose method, but sacrifices some of the advanced +//! configuration options (not shown in this small example). This method also takes a *very* minor +//! runtime penalty. +//! +//! ```no_run +//! // (Full example with detailed comments in examples/01a_quick_example.rs) +//! // +//! // This example demonstrates clap's "usage strings" method of creating arguments +//! // which is less verbose +//! extern crate clap; +//! use clap::{Arg, App, SubCommand}; +//! +//! fn main() { +//! let matches = App::new("myapp") +//! .version("1.0") +//! .author("Kevin K. ") +//! .about("Does awesome things") +//! .args_from_usage( +//! "-c, --config=[FILE] 'Sets a custom config file' +//! 'Sets the input file to use' +//! -v... 'Sets the level of verbosity'") +//! .subcommand(SubCommand::with_name("test") +//! .about("controls testing features") +//! .version("1.3") +//! .author("Someone E. ") +//! .arg_from_usage("-d, --debug 'Print debug information'")) +//! .get_matches(); +//! +//! // Same as previous example... +//! } +//! ``` +//! +//! This third method shows how you can use a YAML file to build your CLI and keep your Rust source +//! tidy or support multiple localized translations by having different YAML files for each +//! localization. +//! +//! First, create the `cli.yml` file to hold your CLI options, but it could be called anything we +//! like: +//! +//! ```yaml +//! name: myapp +//! version: "1.0" +//! author: Kevin K. +//! about: Does awesome things +//! args: +//! - config: +//! short: c +//! long: config +//! value_name: FILE +//! help: Sets a custom config file +//! takes_value: true +//! - INPUT: +//! help: Sets the input file to use +//! required: true +//! index: 1 +//! - verbose: +//! short: v +//! multiple: true +//! help: Sets the level of verbosity +//! subcommands: +//! - test: +//! about: controls testing features +//! version: "1.3" +//! author: Someone E. +//! args: +//! - debug: +//! short: d +//! help: print debug information +//! ``` +//! +//! Since this feature requires additional dependencies that not everyone may want, it is *not* +//! compiled in by default and we need to enable a feature flag in Cargo.toml: +//! +//! Simply change your `clap = "~2.27.0"` to `clap = {version = "~2.27.0", features = ["yaml"]}`. +//! +//! At last we create our `main.rs` file just like we would have with the previous two examples: +//! +//! ```ignore +//! // (Full example with detailed comments in examples/17_yaml.rs) +//! // +//! // This example demonstrates clap's building from YAML style of creating arguments which is far +//! // more clean, but takes a very small performance hit compared to the other two methods. +//! #[macro_use] +//! extern crate clap; +//! use clap::App; +//! +//! fn main() { +//! // The YAML file is found relative to the current file, similar to how modules are found +//! let yaml = load_yaml!("cli.yml"); +//! let matches = App::from_yaml(yaml).get_matches(); +//! +//! // Same as previous examples... +//! } +//! ``` +//! +//! Finally there is a macro version, which is like a hybrid approach offering the speed of the +//! builder pattern (the first example), but without all the verbosity. +//! +//! ```no_run +//! #[macro_use] +//! extern crate clap; +//! +//! fn main() { +//! let matches = clap_app!(myapp => +//! (version: "1.0") +//! (author: "Kevin K. ") +//! (about: "Does awesome things") +//! (@arg CONFIG: -c --config +takes_value "Sets a custom config file") +//! (@arg INPUT: +required "Sets the input file to use") +//! (@arg debug: -d ... "Sets the level of debugging information") +//! (@subcommand test => +//! (about: "controls testing features") +//! (version: "1.3") +//! (author: "Someone E. ") +//! (@arg verbose: -v --verbose "Print test information verbosely") +//! ) +//! ).get_matches(); +//! +//! // Same as before... +//! } +//! ``` +//! +//! If you were to compile any of the above programs and run them with the flag `--help` or `-h` (or +//! `help` subcommand, since we defined `test` as a subcommand) the following would be output +//! +//! ```text +//! $ myprog --help +//! My Super Program 1.0 +//! Kevin K. +//! Does awesome things +//! +//! USAGE: +//! MyApp [FLAGS] [OPTIONS] [SUBCOMMAND] +//! +//! FLAGS: +//! -h, --help Prints this message +//! -v Sets the level of verbosity +//! -V, --version Prints version information +//! +//! OPTIONS: +//! -c, --config Sets a custom config file +//! +//! ARGS: +//! INPUT The input file to use +//! +//! SUBCOMMANDS: +//! help Prints this message +//! test Controls testing features +//! ``` +//! +//! **NOTE:** You could also run `myapp test --help` to see similar output and options for the +//! `test` subcommand. +//! +//! ## Try it! +//! +//! ### Pre-Built Test +//! +//! To try out the pre-built example, use the following steps: +//! +//! * Clone the repository `$ git clone https://github.com/clap-rs/clap && cd clap-rs/tests` +//! * Compile the example `$ cargo build --release` +//! * Run the help info `$ ./target/release/claptests --help` +//! * Play with the arguments! +//! +//! ### BYOB (Build Your Own Binary) +//! +//! To test out `clap`'s default auto-generated help/version follow these steps: +//! +//! * Create a new cargo project `$ cargo new fake --bin && cd fake` +//! * Add `clap` to your `Cargo.toml` +//! +//! ```toml +//! [dependencies] +//! clap = "2" +//! ``` +//! +//! * Add the following to your `src/main.rs` +//! +//! ```no_run +//! extern crate clap; +//! use clap::App; +//! +//! fn main() { +//! App::new("fake").version("v1.0-beta").get_matches(); +//! } +//! ``` +//! +//! * Build your program `$ cargo build --release` +//! * Run with help or version `$ ./target/release/fake --help` or `$ ./target/release/fake +//! --version` +//! +//! ## Usage +//! +//! For full usage, add `clap` as a dependency in your `Cargo.toml` (it is **highly** recommended to +//! use the `~major.minor.patch` style versions in your `Cargo.toml`, for more information see +//! [Compatibility Policy](#compatibility-policy)) to use from crates.io: +//! +//! ```toml +//! [dependencies] +//! clap = "~2.27.0" +//! ``` +//! +//! Or get the latest changes from the master branch at github: +//! +//! ```toml +//! [dependencies.clap] +//! git = "https://github.com/clap-rs/clap.git" +//! ``` +//! +//! Add `extern crate clap;` to your crate root. +//! +//! Define a list of valid arguments for your program (see the +//! [documentation](https://docs.rs/clap/) or [examples/] directory of this repo) +//! +//! Then run `cargo build` or `cargo update && cargo build` for your project. +//! +//! ### Optional Dependencies / Features +//! +//! #### Features enabled by default +//! +//! * `suggestions`: Turns on the `Did you mean '--myoption'?` feature for when users make typos. (builds dependency `strsim`) +//! * `color`: Turns on colored error messages. This feature only works on non-Windows OSs. (builds dependency `ansi-term` and `atty`) +//! * `wrap_help`: Wraps the help at the actual terminal width when +//! available, instead of 120 characters. (builds dependency `textwrap` +//! with feature `term_size`) +//! +//! To disable these, add this to your `Cargo.toml`: +//! +//! ```toml +//! [dependencies.clap] +//! version = "~2.27.0" +//! default-features = false +//! ``` +//! +//! You can also selectively enable only the features you'd like to include, by adding: +//! +//! ```toml +//! [dependencies.clap] +//! version = "~2.27.0" +//! default-features = false +//! +//! # Cherry-pick the features you'd like to use +//! features = [ "suggestions", "color" ] +//! ``` +//! +//! #### Opt-in features +//! +//! * **"yaml"**: Enables building CLIs from YAML documents. (builds dependency `yaml-rust`) +//! * **"unstable"**: Enables unstable `clap` features that may change from release to release +//! +//! ### Dependencies Tree +//! +//! The following graphic depicts `clap`s dependency graph (generated using +//! [cargo-graph](https://github.com/kbknapp/cargo-graph)). +//! +//! * **Dashed** Line: Optional dependency +//! * **Red** Color: **NOT** included by default (must use cargo `features` to enable) +//! * **Blue** Color: Dev dependency, only used while developing. +//! +//! ![clap dependencies](https://github.com/clap-rs/clap/blob/v2.34.0/clap_dep_graph.png) +//! +//! ### More Information +//! +//! You can find complete documentation on the [docs.rs](https://docs.rs/clap/) for this project. +//! +//! You can also find usage examples in the [examples/] directory of this repo. +//! +//! #### Video Tutorials +//! +//! There's also the video tutorial series [Argument Parsing with Rust v2][video tutorials]. +//! +//! These videos slowly trickle out as I finish them and currently a work in progress. +//! +//! ## How to Contribute +//! +//! Contributions are always welcome! And there is a multitude of ways in which you can help +//! depending on what you like to do, or are good at. Anything from documentation, code cleanup, +//! issue completion, new features, you name it, even filing issues is contributing and greatly +//! appreciated! +//! +//! Another really great way to help is if you find an interesting, or helpful way in which to use +//! `clap`. You can either add it to the [examples/] directory, or file an issue and tell +//! me. I'm all about giving credit where credit is due :) +//! +//! Please read [CONTRIBUTING.md](https://github.com/clap-rs/clap/blob/v2.34.0/.github/CONTRIBUTING.md) before you start contributing. +//! +//! +//! ### Testing Code +//! +//! To test with all features both enabled and disabled, you can run theese commands: +//! +//! ```text +//! $ cargo test --no-default-features +//! $ cargo test --features "yaml unstable" +//! ``` +//! +//! Alternatively, if you have [`just`](https://github.com/casey/just) installed you can run the +//! prebuilt recipes. *Not* using `just` is perfectly fine as well, it simply bundles commands +//! automatically. +//! +//! For example, to test the code, as above simply run: +//! +//! ```text +//! $ just run-tests +//! ``` +//! +//! From here on, I will list the appropriate `cargo` command as well as the `just` command. +//! +//! Sometimes it's helpful to only run a subset of the tests, which can be done via: +//! +//! ```text +//! $ cargo test --test +//! +//! # Or +//! +//! $ just run-test +//! ``` +//! +//! ### Linting Code +//! +//! During the CI process `clap` runs against many different lints using +//! [`clippy`](https://github.com/Manishearth/rust-clippy). In order to check if these lints pass on +//! your own computer prior to submitting a PR you'll need a nightly compiler. +//! +//! In order to check the code for lints run either: +//! +//! ```text +//! $ rustup override add nightly +//! $ cargo build --features lints +//! $ rustup override remove +//! +//! # Or +//! +//! $ just lint +//! ``` +//! +//! ### Debugging Code +//! +//! Another helpful technique is to see the `clap` debug output while developing features. In order +//! to see the debug output while running the full test suite or individual tests, run: +//! +//! ```text +//! $ cargo test --features debug +//! +//! # Or for individual tests +//! $ cargo test --test --features debug +//! +//! # The corresponding just command for individual debugging tests is: +//! $ just debug +//! ``` +//! +//! ### Goals +//! +//! There are a few goals of `clap` that I'd like to maintain throughout contributions. If your +//! proposed changes break, or go against any of these goals we'll discuss the changes further +//! before merging (but will *not* be ignored, all contributes are welcome!). These are by no means +//! hard-and-fast rules, as I'm no expert and break them myself from time to time (even if by +//! mistake or ignorance). +//! +//! * Remain backwards compatible when possible +//! - If backwards compatibility *must* be broken, use deprecation warnings if at all possible before +//! removing legacy code - This does not apply for security concerns +//! * Parse arguments quickly +//! - Parsing of arguments shouldn't slow down usage of the main program - This is also true of +//! generating help and usage information (although *slightly* less stringent, as the program is about +//! to exit) +//! * Try to be cognizant of memory usage +//! - Once parsing is complete, the memory footprint of `clap` should be low since the main program +//! is the star of the show +//! * `panic!` on *developer* error, exit gracefully on *end-user* error +//! +//! ### Compatibility Policy +//! +//! Because `clap` takes `SemVer` and compatibility seriously, this is the official policy regarding +//! breaking changes and previous versions of Rust. +//! +//! `clap` will pin the minimum required version of Rust to the CI builds. Bumping the minimum +//! version of Rust is considered a minor breaking change, meaning *at a minimum* the minor version +//! of `clap` will be bumped. +//! +//! In order to keep from being surprised by breaking changes, it is **highly** recommended to use +//! the `~major.minor.patch` style in your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] clap = "~2.27.0" +//! ``` +//! +//! This will cause *only* the patch version to be updated upon a `cargo update` call, and therefore +//! cannot break due to new features, or bumped minimum versions of Rust. +//! +//! #### Minimum Version of Rust +//! +//! `clap` will officially support current stable Rust, minus two releases, but may work with prior +//! releases as well. For example, current stable Rust at the time of this writing is 1.21.0, +//! meaning `clap` is guaranteed to compile with 1.19.0 and beyond. At the 1.22.0 release, `clap` +//! will be guaranteed to compile with 1.20.0 and beyond, etc. +//! +//! Upon bumping the minimum version of Rust (assuming it's within the stable-2 range), it *must* be +//! clearly annotated in the `CHANGELOG.md` +//! +//! ## License +//! +//! `clap` is licensed under the MIT license. Please read the [LICENSE-MIT][license] file in +//! this repository for more information. +//! +//! [examples/]: https://github.com/clap-rs/clap/tree/v2.34.0/examples +//! [video tutorials]: https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U +//! [license]: https://github.com/clap-rs/clap/blob/v2.34.0/LICENSE-MIT + +#![crate_type = "lib"] +#![doc(html_root_url = "https://docs.rs/clap/2.34.0")] +#![deny( + missing_docs, + missing_debug_implementations, + missing_copy_implementations, + trivial_casts, + unused_import_braces, + unused_allocation +)] +// Lints we'd like to deny but are currently failing for upstream crates +// unused_qualifications (bitflags, clippy) +// trivial_numeric_casts (bitflags) +#![cfg_attr( + not(any(feature = "cargo-clippy", feature = "nightly")), + forbid(unstable_features) +)] +//#![cfg_attr(feature = "lints", feature(plugin))] +//#![cfg_attr(feature = "lints", plugin(clippy))] +// Need to disable deny(warnings) while deprecations are active +//#![cfg_attr(feature = "cargo-clippy", deny(warnings))] +// Due to our "MSRV for 2.x will remain unchanged" policy, we can't fix these warnings +#![allow(bare_trait_objects, deprecated)] + +#[cfg(all(feature = "color", not(target_os = "windows")))] +extern crate ansi_term; +#[cfg(feature = "color")] +extern crate atty; +#[macro_use] +extern crate bitflags; +#[cfg(feature = "suggestions")] +extern crate strsim; +#[cfg(feature = "wrap_help")] +extern crate term_size; +extern crate textwrap; +extern crate unicode_width; +#[cfg(feature = "vec_map")] +extern crate vec_map; +#[cfg(feature = "yaml")] +extern crate yaml_rust; + +pub use app::{App, AppSettings}; +pub use args::{Arg, ArgGroup, ArgMatches, ArgSettings, OsValues, SubCommand, Values}; +pub use completions::Shell; +pub use errors::{Error, ErrorKind, Result}; +pub use fmt::Format; +#[cfg(feature = "yaml")] +pub use yaml_rust::YamlLoader; + +#[macro_use] +mod macros; +mod app; +mod args; +mod completions; +mod errors; +mod fmt; +mod map; +mod osstringext; +mod strext; +mod suggestions; +mod usage_parser; + +const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \ + report at https://github.com/clap-rs/clap/issues"; +const INVALID_UTF8: &str = "unexpected invalid UTF-8 code point"; + +#[cfg(unstable)] +pub use derive::{ArgEnum, ClapApp, FromArgMatches, IntoApp}; + +#[cfg(unstable)] +mod derive { + /// @TODO @release @docs + pub trait ClapApp: IntoApp + FromArgMatches + Sized { + /// @TODO @release @docs + fn parse() -> Self { + Self::from_argmatches(Self::into_app().get_matches()) + } + + /// @TODO @release @docs + fn parse_from(argv: I) -> Self + where + I: IntoIterator, + T: Into + Clone, + { + Self::from_argmatches(Self::into_app().get_matches_from(argv)) + } + + /// @TODO @release @docs + fn try_parse() -> Result { + Self::try_from_argmatches(Self::into_app().get_matches_safe()?) + } + + /// @TODO @release @docs + fn try_parse_from(argv: I) -> Result + where + I: IntoIterator, + T: Into + Clone, + { + Self::try_from_argmatches(Self::into_app().get_matches_from_safe(argv)?) + } + } + + /// @TODO @release @docs + pub trait IntoApp { + /// @TODO @release @docs + fn into_app<'a, 'b>() -> clap::App<'a, 'b>; + } + + /// @TODO @release @docs + pub trait FromArgMatches: Sized { + /// @TODO @release @docs + fn from_argmatches<'a>(matches: clap::ArgMatches<'a>) -> Self; + + /// @TODO @release @docs + fn try_from_argmatches<'a>(matches: clap::ArgMatches<'a>) -> Result; + } + + /// @TODO @release @docs + pub trait ArgEnum {} +} diff --git a/vendor/clap-2.34.0/src/macros.rs b/vendor/clap-2.34.0/src/macros.rs new file mode 100644 index 0000000000000..01cbca8095daf --- /dev/null +++ b/vendor/clap-2.34.0/src/macros.rs @@ -0,0 +1,1130 @@ +/// A convenience macro for loading the YAML file at compile time (relative to the current file, +/// like modules work). That YAML object can then be passed to this function. +/// +/// # Panics +/// +/// The YAML file must be properly formatted or this function will panic!(). A good way to +/// ensure this doesn't happen is to run your program with the `--help` switch. If this passes +/// without error, you needn't worry because the YAML is properly formatted. +/// +/// # Examples +/// +/// The following example shows how to load a properly formatted YAML file to build an instance +/// of an `App` struct. +/// +/// ```ignore +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let yml = load_yaml!("app.yml"); +/// let app = App::from_yaml(yml); +/// +/// // continued logic goes here, such as `app.get_matches()` etc. +/// # } +/// ``` +#[cfg(feature = "yaml")] +#[macro_export] +macro_rules! load_yaml { + ($yml:expr) => { + &::clap::YamlLoader::load_from_str(include_str!($yml)).expect("failed to load YAML file")[0] + }; +} + +/// Convenience macro getting a typed value `T` where `T` implements [`std::str::FromStr`] from an +/// argument value. This macro returns a `Result` which allows you as the developer to +/// decide what you'd like to do on a failed parse. There are two types of errors, parse failures +/// and those where the argument wasn't present (such as a non-required argument). You can use +/// it to get a single value, or a iterator as with the [`ArgMatches::values_of`] +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let matches = App::new("myapp") +/// .arg_from_usage("[length] 'Set the length to use as a pos whole num, i.e. 20'") +/// .get_matches(); +/// +/// let len = value_t!(matches.value_of("length"), u32).unwrap_or_else(|e| e.exit()); +/// let also_len = value_t!(matches, "length", u32).unwrap_or_else(|e| e.exit()); +/// +/// println!("{} + 2: {}", len, len + 2); +/// # } +/// ``` +/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [`ArgMatches::values_of`]: ./struct.ArgMatches.html#method.values_of +/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html +#[macro_export] +macro_rules! value_t { + ($m:ident, $v:expr, $t:ty) => { + value_t!($m.value_of($v), $t) + }; + ($m:ident.value_of($v:expr), $t:ty) => { + if let Some(v) = $m.value_of($v) { + match v.parse::<$t>() { + Ok(val) => Ok(val), + Err(_) => Err(::clap::Error::value_validation_auto(format!( + "The argument '{}' isn't a valid value", + v + ))), + } + } else { + Err(::clap::Error::argument_not_found_auto($v)) + } + }; +} + +/// Convenience macro getting a typed value `T` where `T` implements [`std::str::FromStr`] or +/// exiting upon error, instead of returning a [`Result`] type. +/// +/// **NOTE:** This macro is for backwards compatibility sake. Prefer +/// [`value_t!(/* ... */).unwrap_or_else(|e| e.exit())`] +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let matches = App::new("myapp") +/// .arg_from_usage("[length] 'Set the length to use as a pos whole num, i.e. 20'") +/// .get_matches(); +/// +/// let len = value_t_or_exit!(matches.value_of("length"), u32); +/// let also_len = value_t_or_exit!(matches, "length", u32); +/// +/// println!("{} + 2: {}", len, len + 2); +/// # } +/// ``` +/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html +/// [`value_t!(/* ... */).unwrap_or_else(|e| e.exit())`]: ./macro.value_t!.html +#[macro_export] +macro_rules! value_t_or_exit { + ($m:ident, $v:expr, $t:ty) => { + value_t_or_exit!($m.value_of($v), $t) + }; + ($m:ident.value_of($v:expr), $t:ty) => { + if let Some(v) = $m.value_of($v) { + match v.parse::<$t>() { + Ok(val) => val, + Err(_) => ::clap::Error::value_validation_auto(format!( + "The argument '{}' isn't a valid value", + v + )) + .exit(), + } + } else { + ::clap::Error::argument_not_found_auto($v).exit() + } + }; +} + +/// Convenience macro getting a typed value [`Vec`] where `T` implements [`std::str::FromStr`] +/// This macro returns a [`clap::Result>`] which allows you as the developer to decide +/// what you'd like to do on a failed parse. +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let matches = App::new("myapp") +/// .arg_from_usage("[seq]... 'A sequence of pos whole nums, i.e. 20 45'") +/// .get_matches(); +/// +/// let vals = values_t!(matches.values_of("seq"), u32).unwrap_or_else(|e| e.exit()); +/// for v in &vals { +/// println!("{} + 2: {}", v, v + 2); +/// } +/// +/// let vals = values_t!(matches, "seq", u32).unwrap_or_else(|e| e.exit()); +/// for v in &vals { +/// println!("{} + 2: {}", v, v + 2); +/// } +/// # } +/// ``` +/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html +/// [`clap::Result>`]: ./type.Result.html +#[macro_export] +macro_rules! values_t { + ($m:ident, $v:expr, $t:ty) => { + values_t!($m.values_of($v), $t) + }; + ($m:ident.values_of($v:expr), $t:ty) => { + if let Some(vals) = $m.values_of($v) { + let mut tmp = vec![]; + let mut err = None; + for pv in vals { + match pv.parse::<$t>() { + Ok(rv) => tmp.push(rv), + Err(..) => { + err = Some(::clap::Error::value_validation_auto(format!( + "The argument '{}' isn't a valid value", + pv + ))); + break; + } + } + } + match err { + Some(e) => Err(e), + None => Ok(tmp), + } + } else { + Err(::clap::Error::argument_not_found_auto($v)) + } + }; +} + +/// Convenience macro getting a typed value [`Vec`] where `T` implements [`std::str::FromStr`] +/// or exiting upon error. +/// +/// **NOTE:** This macro is for backwards compatibility sake. Prefer +/// [`values_t!(/* ... */).unwrap_or_else(|e| e.exit())`] +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let matches = App::new("myapp") +/// .arg_from_usage("[seq]... 'A sequence of pos whole nums, i.e. 20 45'") +/// .get_matches(); +/// +/// let vals = values_t_or_exit!(matches.values_of("seq"), u32); +/// for v in &vals { +/// println!("{} + 2: {}", v, v + 2); +/// } +/// +/// // type for example only +/// let vals: Vec = values_t_or_exit!(matches, "seq", u32); +/// for v in &vals { +/// println!("{} + 2: {}", v, v + 2); +/// } +/// # } +/// ``` +/// [`values_t!(/* ... */).unwrap_or_else(|e| e.exit())`]: ./macro.values_t!.html +/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html +#[macro_export] +macro_rules! values_t_or_exit { + ($m:ident, $v:expr, $t:ty) => { + values_t_or_exit!($m.values_of($v), $t) + }; + ($m:ident.values_of($v:expr), $t:ty) => { + if let Some(vals) = $m.values_of($v) { + vals.map(|v| { + v.parse::<$t>().unwrap_or_else(|_| { + ::clap::Error::value_validation_auto(format!( + "One or more arguments aren't valid values" + )) + .exit() + }) + }) + .collect::>() + } else { + ::clap::Error::argument_not_found_auto($v).exit() + } + }; +} + +// _clap_count_exprs! is derived from https://github.com/DanielKeep/rust-grabbag +// commit: 82a35ca5d9a04c3b920622d542104e3310ee5b07 +// License: MIT +// Copyright â“’ 2015 grabbag contributors. +// Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of +// ), at your option. All +// files in the project carrying such notice may not be copied, modified, +// or distributed except according to those terms. +// +/// Counts the number of comma-delimited expressions passed to it. The result is a compile-time +/// evaluable expression, suitable for use as a static array size, or the value of a `const`. +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate clap; +/// # fn main() { +/// const COUNT: usize = _clap_count_exprs!(a, 5+1, "hi there!".into_string()); +/// assert_eq!(COUNT, 3); +/// # } +/// ``` +#[macro_export] +macro_rules! _clap_count_exprs { + () => { 0 }; + ($e:expr) => { 1 }; + ($e:expr, $($es:expr),+) => { 1 + $crate::_clap_count_exprs!($($es),*) }; +} + +/// Convenience macro to generate more complete enums with variants to be used as a type when +/// parsing arguments. This enum also provides a `variants()` function which can be used to +/// retrieve a `Vec<&'static str>` of the variant names, as well as implementing [`FromStr`] and +/// [`Display`] automatically. +/// +/// **NOTE:** Case insensitivity is supported for ASCII characters only. It's highly recommended to +/// use [`Arg::case_insensitive(true)`] for args that will be used with these enums +/// +/// **NOTE:** This macro automatically implements [`std::str::FromStr`] and [`std::fmt::Display`] +/// +/// **NOTE:** These enums support pub (or not) and uses of the `#[derive()]` traits +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::{App, Arg}; +/// arg_enum!{ +/// #[derive(PartialEq, Debug)] +/// pub enum Foo { +/// Bar, +/// Baz, +/// Qux +/// } +/// } +/// // Foo enum can now be used via Foo::Bar, or Foo::Baz, etc +/// // and implements std::str::FromStr to use with the value_t! macros +/// fn main() { +/// let m = App::new("app") +/// .arg(Arg::from_usage(" 'the foo'") +/// .possible_values(&Foo::variants()) +/// .case_insensitive(true)) +/// .get_matches_from(vec![ +/// "app", "baz" +/// ]); +/// let f = value_t!(m, "foo", Foo).unwrap_or_else(|e| e.exit()); +/// +/// assert_eq!(f, Foo::Baz); +/// } +/// ``` +/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html +/// [`std::fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html +/// [`Arg::case_insensitive(true)`]: ./struct.Arg.html#method.case_insensitive +#[macro_export] +macro_rules! arg_enum { + (@as_item $($i:item)*) => ($($i)*); + (@impls ( $($tts:tt)* ) -> ($e:ident, $($v:ident),+)) => { + arg_enum!(@as_item + $($tts)* + + impl ::std::str::FromStr for $e { + type Err = String; + + fn from_str(s: &str) -> ::std::result::Result { + #[allow(deprecated, unused_imports)] + use ::std::ascii::AsciiExt; + match s { + $(stringify!($v) | + _ if s.eq_ignore_ascii_case(stringify!($v)) => Ok($e::$v)),+, + _ => Err({ + let v = vec![ + $(stringify!($v),)+ + ]; + format!("valid values: {}", + v.join(", ")) + }), + } + } + } + impl ::std::fmt::Display for $e { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match *self { + $($e::$v => write!(f, stringify!($v)),)+ + } + } + } + impl $e { + #[allow(dead_code)] + pub fn variants() -> [&'static str; $crate::_clap_count_exprs!($(stringify!($v)),+)] { + [ + $(stringify!($v),)+ + ] + } + }); + }; + ($(#[$($m:meta),+])+ pub enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => { + arg_enum!(@impls + ($(#[$($m),+])+ + pub enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + ($(#[$($m:meta),+])+ pub enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => { + arg_enum!(@impls + ($(#[$($m),+])+ + pub enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + ($(#[$($m:meta),+])+ enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => { + arg_enum!(@impls + ($(#[$($m),+])+ + enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + ($(#[$($m:meta),+])+ enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => { + arg_enum!(@impls + ($(#[$($m),+])+ + enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + (pub enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => { + arg_enum!(@impls + (pub enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + (pub enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => { + arg_enum!(@impls + (pub enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + (enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => { + arg_enum!(@impls + (enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + (enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => { + arg_enum!(@impls + (enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; +} + +/// Allows you to pull the version from your Cargo.toml at compile time as +/// `MAJOR.MINOR.PATCH_PKGVERSION_PRE` +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let m = App::new("app") +/// .version(crate_version!()) +/// .get_matches(); +/// # } +/// ``` +#[cfg(not(feature = "no_cargo"))] +#[macro_export] +macro_rules! crate_version { + () => { + env!("CARGO_PKG_VERSION") + }; +} + +/// Allows you to pull the authors for the app from your Cargo.toml at +/// compile time in the form: +/// `"author1 lastname :author2 lastname "` +/// +/// You can replace the colons with a custom separator by supplying a +/// replacement string, so, for example, +/// `crate_authors!(",\n")` would become +/// `"author1 lastname ,\nauthor2 lastname ,\nauthor3 lastname "` +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let m = App::new("app") +/// .author(crate_authors!("\n")) +/// .get_matches(); +/// # } +/// ``` +#[cfg(not(feature = "no_cargo"))] +#[macro_export] +macro_rules! crate_authors { + ($sep:expr) => {{ + use std::ops::Deref; + #[allow(deprecated)] + use std::sync::{Once, ONCE_INIT}; + + #[allow(missing_copy_implementations)] + #[allow(dead_code)] + struct CargoAuthors { + __private_field: (), + }; + + impl Deref for CargoAuthors { + type Target = str; + + #[allow(unsafe_code)] + fn deref(&self) -> &'static str { + #[allow(deprecated)] + static ONCE: Once = ONCE_INIT; + static mut VALUE: *const String = 0 as *const String; + + unsafe { + ONCE.call_once(|| { + let s = env!("CARGO_PKG_AUTHORS").replace(':', $sep); + VALUE = Box::into_raw(Box::new(s)); + }); + + &(*VALUE)[..] + } + } + } + + &*CargoAuthors { + __private_field: (), + } + }}; + () => { + env!("CARGO_PKG_AUTHORS") + }; +} + +/// Allows you to pull the description from your Cargo.toml at compile time. +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let m = App::new("app") +/// .about(crate_description!()) +/// .get_matches(); +/// # } +/// ``` +#[cfg(not(feature = "no_cargo"))] +#[macro_export] +macro_rules! crate_description { + () => { + env!("CARGO_PKG_DESCRIPTION") + }; +} + +/// Allows you to pull the name from your Cargo.toml at compile time. +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let m = App::new(crate_name!()) +/// .get_matches(); +/// # } +/// ``` +#[cfg(not(feature = "no_cargo"))] +#[macro_export] +macro_rules! crate_name { + () => { + env!("CARGO_PKG_NAME") + }; +} + +/// Allows you to build the `App` instance from your Cargo.toml at compile time. +/// +/// Equivalent to using the `crate_*!` macros with their respective fields. +/// +/// Provided separator is for the [`crate_authors!`](macro.crate_authors.html) macro, +/// refer to the documentation therefor. +/// +/// **NOTE:** Changing the values in your `Cargo.toml` does not trigger a re-build automatically, +/// and therefore won't change the generated output until you recompile. +/// +/// **Pro Tip:** In some cases you can "trick" the compiler into triggering a rebuild when your +/// `Cargo.toml` is changed by including this in your `src/main.rs` file +/// `include_str!("../Cargo.toml");` +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # fn main() { +/// let m = app_from_crate!().get_matches(); +/// # } +/// ``` +#[cfg(not(feature = "no_cargo"))] +#[macro_export] +macro_rules! app_from_crate { + () => { + $crate::App::new(crate_name!()) + .version(crate_version!()) + .author(crate_authors!()) + .about(crate_description!()) + }; + ($sep:expr) => { + $crate::App::new(crate_name!()) + .version(crate_version!()) + .author(crate_authors!($sep)) + .about(crate_description!()) + }; +} + +/// Build `App`, `Arg`s, `SubCommand`s and `Group`s with Usage-string like input +/// but without the associated parsing runtime cost. +/// +/// `clap_app!` also supports several shorthand syntaxes. +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # fn main() { +/// let matches = clap_app!(myapp => +/// (version: "1.0") +/// (author: "Kevin K. ") +/// (about: "Does awesome things") +/// (@arg CONFIG: -c --config +takes_value "Sets a custom config file") +/// (@arg INPUT: +required "Sets the input file to use") +/// (@arg debug: -d ... "Sets the level of debugging information") +/// (@group difficulty => +/// (@arg hard: -h --hard "Sets hard mode") +/// (@arg normal: -n --normal "Sets normal mode") +/// (@arg easy: -e --easy "Sets easy mode") +/// ) +/// (@subcommand test => +/// (about: "controls testing features") +/// (version: "1.3") +/// (author: "Someone E. ") +/// (@arg verbose: -v --verbose "Print test information verbosely") +/// ) +/// ) +/// .get_matches(); +/// # } +/// ``` +/// # Shorthand Syntax for Args +/// +/// * A single hyphen followed by a character (such as `-c`) sets the [`Arg::short`] +/// * A double hyphen followed by a character or word (such as `--config`) sets [`Arg::long`] +/// * If one wishes to use a [`Arg::long`] with a hyphen inside (i.e. `--config-file`), you +/// must use `--("config-file")` due to limitations of the Rust macro system. +/// * Three dots (`...`) sets [`Arg::multiple(true)`] +/// * Angled brackets after either a short or long will set [`Arg::value_name`] and +/// `Arg::required(true)` such as `--config ` = `Arg::value_name("FILE")` and +/// `Arg::required(true)` +/// * Square brackets after either a short or long will set [`Arg::value_name`] and +/// `Arg::required(false)` such as `--config [FILE]` = `Arg::value_name("FILE")` and +/// `Arg::required(false)` +/// * There are short hand syntaxes for Arg methods that accept booleans +/// * A plus sign will set that method to `true` such as `+required` = `Arg::required(true)` +/// * An exclamation will set that method to `false` such as `!required` = `Arg::required(false)` +/// * A `#{min, max}` will set [`Arg::min_values(min)`] and [`Arg::max_values(max)`] +/// * An asterisk (`*`) will set `Arg::required(true)` +/// * Curly brackets around a `fn` will set [`Arg::validator`] as in `{fn}` = `Arg::validator(fn)` +/// * An Arg method that accepts a string followed by square brackets will set that method such as +/// `conflicts_with[FOO]` will set `Arg::conflicts_with("FOO")` (note the lack of quotes around +/// `FOO` in the macro) +/// * An Arg method that takes a string and can be set multiple times (such as +/// [`Arg::conflicts_with`]) followed by square brackets and a list of values separated by spaces +/// will set that method such as `conflicts_with[FOO BAR BAZ]` will set +/// `Arg::conflicts_with("FOO")`, `Arg::conflicts_with("BAR")`, and `Arg::conflicts_with("BAZ")` +/// (note the lack of quotes around the values in the macro) +/// +/// # Shorthand Syntax for Groups +/// +/// * There are short hand syntaxes for `ArgGroup` methods that accept booleans +/// * A plus sign will set that method to `true` such as `+required` = `ArgGroup::required(true)` +/// * An exclamation will set that method to `false` such as `!required` = `ArgGroup::required(false)` +/// +/// [`Arg::short`]: ./struct.Arg.html#method.short +/// [`Arg::long`]: ./struct.Arg.html#method.long +/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple +/// [`Arg::value_name`]: ./struct.Arg.html#method.value_name +/// [`Arg::min_values(min)`]: ./struct.Arg.html#method.min_values +/// [`Arg::max_values(max)`]: ./struct.Arg.html#method.max_values +/// [`Arg::validator`]: ./struct.Arg.html#method.validator +/// [`Arg::conflicts_with`]: ./struct.Arg.html#method.conflicts_with +#[macro_export] +macro_rules! clap_app { + (@app ($builder:expr)) => { $builder }; + (@app ($builder:expr) (@arg ($name:expr): $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @app + ($builder.arg( + clap_app!{ @arg ($crate::Arg::with_name($name)) (-) $($tail)* })) + $($tt)* + } + }; + (@app ($builder:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @app + ($builder.arg( + clap_app!{ @arg ($crate::Arg::with_name(stringify!($name))) (-) $($tail)* })) + $($tt)* + } + }; + (@app ($builder:expr) (@setting $setting:ident) $($tt:tt)*) => { + clap_app!{ @app + ($builder.setting($crate::AppSettings::$setting)) + $($tt)* + } + }; +// Treat the application builder as an argument to set its attributes + (@app ($builder:expr) (@attributes $($attr:tt)*) $($tt:tt)*) => { + clap_app!{ @app (clap_app!{ @arg ($builder) $($attr)* }) $($tt)* } + }; + (@app ($builder:expr) (@group $name:ident => $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @app + (clap_app!{ @group ($builder, $crate::ArgGroup::with_name(stringify!($name))) $($tail)* }) + $($tt)* + } + }; + (@app ($builder:expr) (@group $name:ident !$ident:ident => $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @app + (clap_app!{ @group ($builder, $crate::ArgGroup::with_name(stringify!($name)).$ident(false)) $($tail)* }) + $($tt)* + } + }; + (@app ($builder:expr) (@group $name:ident +$ident:ident => $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @app + (clap_app!{ @group ($builder, $crate::ArgGroup::with_name(stringify!($name)).$ident(true)) $($tail)* }) + $($tt)* + } + }; +// Handle subcommand creation + (@app ($builder:expr) (@subcommand $name:ident => $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @app + ($builder.subcommand( + clap_app!{ @app ($crate::SubCommand::with_name(stringify!($name))) $($tail)* } + )) + $($tt)* + } + }; +// Yaml like function calls - used for setting various meta directly against the app + (@app ($builder:expr) ($ident:ident: $($v:expr),*) $($tt:tt)*) => { +// clap_app!{ @app ($builder.$ident($($v),*)) $($tt)* } + clap_app!{ @app + ($builder.$ident($($v),*)) + $($tt)* + } + }; + +// Add members to group and continue argument handling with the parent builder + (@group ($builder:expr, $group:expr)) => { $builder.group($group) }; + // Treat the group builder as an argument to set its attributes + (@group ($builder:expr, $group:expr) (@attributes $($attr:tt)*) $($tt:tt)*) => { + clap_app!{ @group ($builder, clap_app!{ @arg ($group) (-) $($attr)* }) $($tt)* } + }; + (@group ($builder:expr, $group:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @group + (clap_app!{ @app ($builder) (@arg $name: $($tail)*) }, + $group.arg(stringify!($name))) + $($tt)* + } + }; + +// No more tokens to munch + (@arg ($arg:expr) $modes:tt) => { $arg }; +// Shorthand tokens influenced by the usage_string + (@arg ($arg:expr) $modes:tt --($long:expr) $($tail:tt)*) => { + clap_app!{ @arg ($arg.long($long)) $modes $($tail)* } + }; + (@arg ($arg:expr) $modes:tt --$long:ident $($tail:tt)*) => { + clap_app!{ @arg ($arg.long(stringify!($long))) $modes $($tail)* } + }; + (@arg ($arg:expr) $modes:tt -$short:ident $($tail:tt)*) => { + clap_app!{ @arg ($arg.short(stringify!($short))) $modes $($tail)* } + }; + (@arg ($arg:expr) (-) <$var:ident> $($tail:tt)*) => { + clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) +takes_value +required $($tail)* } + }; + (@arg ($arg:expr) (+) <$var:ident> $($tail:tt)*) => { + clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) $($tail)* } + }; + (@arg ($arg:expr) (-) [$var:ident] $($tail:tt)*) => { + clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) +takes_value $($tail)* } + }; + (@arg ($arg:expr) (+) [$var:ident] $($tail:tt)*) => { + clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) $($tail)* } + }; + (@arg ($arg:expr) $modes:tt ... $($tail:tt)*) => { + clap_app!{ @arg ($arg) $modes +multiple $($tail)* } + }; +// Shorthand magic + (@arg ($arg:expr) $modes:tt #{$n:expr, $m:expr} $($tail:tt)*) => { + clap_app!{ @arg ($arg) $modes min_values($n) max_values($m) $($tail)* } + }; + (@arg ($arg:expr) $modes:tt * $($tail:tt)*) => { + clap_app!{ @arg ($arg) $modes +required $($tail)* } + }; +// !foo -> .foo(false) + (@arg ($arg:expr) $modes:tt !$ident:ident $($tail:tt)*) => { + clap_app!{ @arg ($arg.$ident(false)) $modes $($tail)* } + }; +// +foo -> .foo(true) + (@arg ($arg:expr) $modes:tt +$ident:ident $($tail:tt)*) => { + clap_app!{ @arg ($arg.$ident(true)) $modes $($tail)* } + }; +// Validator + (@arg ($arg:expr) $modes:tt {$fn_:expr} $($tail:tt)*) => { + clap_app!{ @arg ($arg.validator($fn_)) $modes $($tail)* } + }; + (@as_expr $expr:expr) => { $expr }; +// Help + (@arg ($arg:expr) $modes:tt $desc:tt) => { $arg.help(clap_app!{ @as_expr $desc }) }; +// Handle functions that need to be called multiple times for each argument + (@arg ($arg:expr) $modes:tt $ident:ident[$($target:ident)*] $($tail:tt)*) => { + clap_app!{ @arg ($arg $( .$ident(stringify!($target)) )*) $modes $($tail)* } + }; +// Inherit builder's functions, e.g. `index(2)`, `requires_if("val", "arg")` + (@arg ($arg:expr) $modes:tt $ident:ident($($expr:expr),*) $($tail:tt)*) => { + clap_app!{ @arg ($arg.$ident($($expr),*)) $modes $($tail)* } + }; +// Inherit builder's functions with trailing comma, e.g. `index(2,)`, `requires_if("val", "arg",)` + (@arg ($arg:expr) $modes:tt $ident:ident($($expr:expr,)*) $($tail:tt)*) => { + clap_app!{ @arg ($arg.$ident($($expr),*)) $modes $($tail)* } + }; + +// Build a subcommand outside of an app. + (@subcommand $name:ident => $($tail:tt)*) => { + clap_app!{ @app ($crate::SubCommand::with_name(stringify!($name))) $($tail)* } + }; +// Start the magic + (($name:expr) => $($tail:tt)*) => {{ + clap_app!{ @app ($crate::App::new($name)) $($tail)*} + }}; + + ($name:ident => $($tail:tt)*) => {{ + clap_app!{ @app ($crate::App::new(stringify!($name))) $($tail)*} + }}; +} + +macro_rules! impl_settings { + ($n:ident, $($v:ident => $c:path),+) => { + pub fn set(&mut self, s: $n) { + match s { + $($n::$v => self.0.insert($c)),+ + } + } + + pub fn unset(&mut self, s: $n) { + match s { + $($n::$v => self.0.remove($c)),+ + } + } + + pub fn is_set(&self, s: $n) -> bool { + match s { + $($n::$v => self.0.contains($c)),+ + } + } + }; +} + +// Convenience for writing to stderr thanks to https://github.com/BurntSushi +macro_rules! wlnerr( + (@nopanic $($arg:tt)*) => ({ + use std::io::{Write, stderr}; + let _ = writeln!(&mut stderr().lock(), $($arg)*); + }); + ($($arg:tt)*) => ({ + use std::io::{Write, stderr}; + writeln!(&mut stderr(), $($arg)*).ok(); + }) +); + +#[cfg(feature = "debug")] +#[cfg_attr(feature = "debug", macro_use)] +#[cfg_attr(feature = "debug", allow(unused_macros))] +mod debug_macros { + macro_rules! debugln { + ($fmt:expr) => (println!(concat!("DEBUG:clap:", $fmt))); + ($fmt:expr, $($arg:tt)*) => (println!(concat!("DEBUG:clap:",$fmt), $($arg)*)); + } + macro_rules! sdebugln { + ($fmt:expr) => (println!($fmt)); + ($fmt:expr, $($arg:tt)*) => (println!($fmt, $($arg)*)); + } + macro_rules! debug { + ($fmt:expr) => (print!(concat!("DEBUG:clap:", $fmt))); + ($fmt:expr, $($arg:tt)*) => (print!(concat!("DEBUG:clap:",$fmt), $($arg)*)); + } + macro_rules! sdebug { + ($fmt:expr) => (print!($fmt)); + ($fmt:expr, $($arg:tt)*) => (print!($fmt, $($arg)*)); + } +} + +#[cfg(not(feature = "debug"))] +#[cfg_attr(not(feature = "debug"), macro_use)] +mod debug_macros { + macro_rules! debugln { + ($fmt:expr) => {}; + ($fmt:expr, $($arg:tt)*) => {}; + } + macro_rules! sdebugln { + ($fmt:expr) => {}; + ($fmt:expr, $($arg:tt)*) => {}; + } + macro_rules! debug { + ($fmt:expr) => {}; + ($fmt:expr, $($arg:tt)*) => {}; + } +} + +// Helper/deduplication macro for printing the correct number of spaces in help messages +// used in: +// src/args/arg_builder/*.rs +// src/app/mod.rs +macro_rules! write_nspaces { + ($dst:expr, $num:expr) => {{ + debugln!("write_spaces!: num={}", $num); + for _ in 0..$num { + $dst.write_all(b" ")?; + } + }}; +} + +// convenience macro for remove an item from a vec +//macro_rules! vec_remove_all { +// ($vec:expr, $to_rem:expr) => { +// debugln!("vec_remove_all! to_rem={:?}", $to_rem); +// for i in (0 .. $vec.len()).rev() { +// let should_remove = $to_rem.any(|name| name == &$vec[i]); +// if should_remove { $vec.swap_remove(i); } +// } +// }; +//} +macro_rules! find_from { + ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{ + let mut ret = None; + for k in $matcher.arg_names() { + if let Some(f) = find_by_name!($_self, k, flags, iter) { + if let Some(ref v) = f.$from() { + if v.contains($arg_name) { + ret = Some(f.to_string()); + } + } + } + if let Some(o) = find_by_name!($_self, k, opts, iter) { + if let Some(ref v) = o.$from() { + if v.contains(&$arg_name) { + ret = Some(o.to_string()); + } + } + } + if let Some(pos) = find_by_name!($_self, k, positionals, values) { + if let Some(ref v) = pos.$from() { + if v.contains($arg_name) { + ret = Some(pos.b.name.to_owned()); + } + } + } + } + ret + }}; +} + +//macro_rules! find_name_from { +// ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{ +// let mut ret = None; +// for k in $matcher.arg_names() { +// if let Some(f) = find_by_name!($_self, k, flags, iter) { +// if let Some(ref v) = f.$from() { +// if v.contains($arg_name) { +// ret = Some(f.b.name); +// } +// } +// } +// if let Some(o) = find_by_name!($_self, k, opts, iter) { +// if let Some(ref v) = o.$from() { +// if v.contains(&$arg_name) { +// ret = Some(o.b.name); +// } +// } +// } +// if let Some(pos) = find_by_name!($_self, k, positionals, values) { +// if let Some(ref v) = pos.$from() { +// if v.contains($arg_name) { +// ret = Some(pos.b.name); +// } +// } +// } +// } +// ret +// }}; +//} + +macro_rules! find_any_by_name { + ($p:expr, $name:expr) => {{ + fn as_trait_obj<'a, 'b, T: AnyArg<'a, 'b>>(x: &T) -> &AnyArg<'a, 'b> { + x + } + find_by_name!($p, $name, flags, iter) + .map(as_trait_obj) + .or(find_by_name!($p, $name, opts, iter) + .map(as_trait_obj) + .or(find_by_name!($p, $name, positionals, values).map(as_trait_obj))) + }}; +} +// Finds an arg by name +macro_rules! find_by_name { + ($p:expr, $name:expr, $what:ident, $how:ident) => { + $p.$what.$how().find(|o| o.b.name == $name) + }; +} + +// Finds an option including if it's aliased +macro_rules! find_opt_by_long { + (@os $_self:ident, $long:expr) => {{ + _find_by_long!($_self, $long, opts) + }}; + ($_self:ident, $long:expr) => {{ + _find_by_long!($_self, $long, opts) + }}; +} + +macro_rules! find_flag_by_long { + (@os $_self:ident, $long:expr) => {{ + _find_by_long!($_self, $long, flags) + }}; + ($_self:ident, $long:expr) => {{ + _find_by_long!($_self, $long, flags) + }}; +} + +macro_rules! _find_by_long { + ($_self:ident, $long:expr, $what:ident) => {{ + $_self + .$what + .iter() + .filter(|a| a.s.long.is_some()) + .find(|a| { + a.s.long.unwrap() == $long + || (a.s.aliases.is_some() + && a.s + .aliases + .as_ref() + .unwrap() + .iter() + .any(|&(alias, _)| alias == $long)) + }) + }}; +} + +// Finds an option +macro_rules! find_opt_by_short { + ($_self:ident, $short:expr) => {{ + _find_by_short!($_self, $short, opts) + }}; +} + +macro_rules! find_flag_by_short { + ($_self:ident, $short:expr) => {{ + _find_by_short!($_self, $short, flags) + }}; +} + +macro_rules! _find_by_short { + ($_self:ident, $short:expr, $what:ident) => {{ + $_self + .$what + .iter() + .filter(|a| a.s.short.is_some()) + .find(|a| a.s.short.unwrap() == $short) + }}; +} + +macro_rules! find_subcmd { + ($_self:expr, $sc:expr) => {{ + $_self.subcommands.iter().find(|s| { + &*s.p.meta.name == $sc + || (s.p.meta.aliases.is_some() + && s.p + .meta + .aliases + .as_ref() + .unwrap() + .iter() + .any(|&(n, _)| n == $sc)) + }) + }}; +} + +macro_rules! shorts { + ($_self:ident) => {{ + _shorts_longs!($_self, short) + }}; +} + +macro_rules! longs { + ($_self:ident) => {{ + _shorts_longs!($_self, long) + }}; +} + +macro_rules! _shorts_longs { + ($_self:ident, $what:ident) => {{ + $_self + .flags + .iter() + .filter(|f| f.s.$what.is_some()) + .map(|f| f.s.$what.as_ref().unwrap()) + .chain( + $_self + .opts + .iter() + .filter(|o| o.s.$what.is_some()) + .map(|o| o.s.$what.as_ref().unwrap()), + ) + }}; +} + +macro_rules! arg_names { + ($_self:ident) => {{ + _names!(@args $_self) + }}; +} + +macro_rules! sc_names { + ($_self:ident) => {{ + _names!(@sc $_self) + }}; +} + +macro_rules! _names { + (@args $_self:ident) => {{ + $_self.flags.iter().map(|f| &*f.b.name).chain( + $_self + .opts + .iter() + .map(|o| &*o.b.name) + .chain($_self.positionals.values().map(|p| &*p.b.name)), + ) + }}; + (@sc $_self:ident) => {{ + $_self.subcommands.iter().map(|s| &*s.p.meta.name).chain( + $_self + .subcommands + .iter() + .filter(|s| s.p.meta.aliases.is_some()) + .flat_map(|s| s.p.meta.aliases.as_ref().unwrap().iter().map(|&(n, _)| n)), + ) + }}; +} diff --git a/vendor/clap-2.34.0/src/map.rs b/vendor/clap-2.34.0/src/map.rs new file mode 100644 index 0000000000000..13497834d42ad --- /dev/null +++ b/vendor/clap-2.34.0/src/map.rs @@ -0,0 +1,88 @@ +#[cfg(feature = "vec_map")] +pub use vec_map::{Values, VecMap}; + +#[cfg(not(feature = "vec_map"))] +pub use self::vec_map::{Values, VecMap}; + +#[cfg(not(feature = "vec_map"))] +mod vec_map { + use std::collections::btree_map; + use std::collections::BTreeMap; + use std::fmt::{self, Debug, Formatter}; + + #[derive(Clone, Default, Debug)] + pub struct VecMap { + inner: BTreeMap, + } + + impl VecMap { + pub fn new() -> Self { + VecMap { + inner: Default::default(), + } + } + + pub fn len(&self) -> usize { + self.inner.len() + } + + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + pub fn insert(&mut self, key: usize, value: V) -> Option { + self.inner.insert(key, value) + } + + pub fn values(&self) -> Values { + self.inner.values() + } + + pub fn iter(&self) -> Iter { + Iter { + inner: self.inner.iter(), + } + } + + pub fn contains_key(&self, key: usize) -> bool { + self.inner.contains_key(&key) + } + + pub fn entry(&mut self, key: usize) -> Entry { + self.inner.entry(key) + } + + pub fn get(&self, key: usize) -> Option<&V> { + self.inner.get(&key) + } + } + + pub type Values<'a, V> = btree_map::Values<'a, usize, V>; + + pub type Entry<'a, V> = btree_map::Entry<'a, usize, V>; + + #[derive(Clone)] + pub struct Iter<'a, V: 'a> { + inner: btree_map::Iter<'a, usize, V>, + } + + impl<'a, V: 'a + Debug> Debug for Iter<'a, V> { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_list().entries(self.inner.clone()).finish() + } + } + + impl<'a, V: 'a> Iterator for Iter<'a, V> { + type Item = (usize, &'a V); + + fn next(&mut self) -> Option { + self.inner.next().map(|(k, v)| (*k, v)) + } + } + + impl<'a, V: 'a> DoubleEndedIterator for Iter<'a, V> { + fn next_back(&mut self) -> Option { + self.inner.next_back().map(|(k, v)| (*k, v)) + } + } +} diff --git a/vendor/clap-2.34.0/src/osstringext.rs b/vendor/clap-2.34.0/src/osstringext.rs new file mode 100644 index 0000000000000..ef765c8d1f6fc --- /dev/null +++ b/vendor/clap-2.34.0/src/osstringext.rs @@ -0,0 +1,203 @@ +use std::ffi::OsStr; +#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))] +use std::os::unix::ffi::OsStrExt; +#[cfg(any(target_os = "windows", target_arch = "wasm32"))] +use crate::INVALID_UTF8; + +#[cfg(any(target_os = "windows", target_arch = "wasm32"))] +pub trait OsStrExt3 { + fn from_bytes(b: &[u8]) -> &Self; + fn as_bytes(&self) -> &[u8]; +} + +#[doc(hidden)] +pub trait OsStrExt2 { + fn starts_with(&self, s: &[u8]) -> bool; + fn split_at_byte(&self, b: u8) -> (&OsStr, &OsStr); + fn split_at(&self, i: usize) -> (&OsStr, &OsStr); + fn trim_left_matches(&self, b: u8) -> &OsStr; + fn contains_byte(&self, b: u8) -> bool; + fn split(&self, b: u8) -> OsSplit; +} + +// A starts-with implementation that does not panic when the OsStr contains +// invalid Unicode. +// +// A Windows OsStr is usually UTF-16. If `prefix` is valid UTF-8, we can +// re-encode it as UTF-16, and ask whether `osstr` starts with the same series +// of u16 code units. If `prefix` is not valid UTF-8, then this comparison +// isn't meaningful, and we just return false. +#[cfg(target_os = "windows")] +fn windows_osstr_starts_with(osstr: &OsStr, prefix: &[u8]) -> bool { + use std::os::windows::ffi::OsStrExt; + let prefix_str = if let Ok(s) = std::str::from_utf8(prefix) { + s + } else { + return false; + }; + let mut osstr_units = osstr.encode_wide(); + let mut prefix_units = prefix_str.encode_utf16(); + loop { + match (osstr_units.next(), prefix_units.next()) { + // These code units match. Keep looping. + (Some(o), Some(p)) if o == p => continue, + // We've reached the end of the prefix. It's a match. + (_, None) => return true, + // Otherwise, it's not a match. + _ => return false, + } + } +} + +#[test] +#[cfg(target_os = "windows")] +fn test_windows_osstr_starts_with() { + use std::ffi::OsString; + use std::os::windows::ffi::OsStringExt; + + fn from_ascii(ascii: &[u8]) -> OsString { + let u16_vec: Vec = ascii.iter().map(|&c| c as u16).collect(); + OsString::from_wide(&u16_vec) + } + + // Test all the basic cases. + assert!(windows_osstr_starts_with(&from_ascii(b"abcdef"), b"abc")); + assert!(windows_osstr_starts_with(&from_ascii(b"abcdef"), b"abcdef")); + assert!(!windows_osstr_starts_with(&from_ascii(b"abcdef"), b"def")); + assert!(!windows_osstr_starts_with(&from_ascii(b"abc"), b"abcd")); + + // Test the case where the candidate prefix is not valid UTF-8. Note that a + // standalone \xff byte is valid ASCII but not valid UTF-8. Thus although + // these strings look identical, they do not match. + assert!(!windows_osstr_starts_with(&from_ascii(b"\xff"), b"\xff")); + + // Test the case where the OsString is not valid UTF-16. It should still be + // possible to match the valid characters at the front. + // + // UTF-16 surrogate characters are only valid in pairs. Including one on + // the end by itself makes this invalid UTF-16. + let surrogate_char: u16 = 0xDC00; + let invalid_unicode = + OsString::from_wide(&['a' as u16, 'b' as u16, 'c' as u16, surrogate_char]); + assert!( + invalid_unicode.to_str().is_none(), + "This string is invalid Unicode, and conversion to &str should fail.", + ); + assert!(windows_osstr_starts_with(&invalid_unicode, b"abc")); + assert!(!windows_osstr_starts_with(&invalid_unicode, b"abcd")); +} + +#[cfg(any(target_os = "windows", target_arch = "wasm32"))] +impl OsStrExt3 for OsStr { + fn from_bytes(b: &[u8]) -> &Self { + use std::mem; + unsafe { mem::transmute(b) } + } + fn as_bytes(&self) -> &[u8] { + self.to_str().map(|s| s.as_bytes()).expect(INVALID_UTF8) + } +} + +impl OsStrExt2 for OsStr { + fn starts_with(&self, s: &[u8]) -> bool { + #[cfg(target_os = "windows")] + { + // On Windows, the as_bytes() method will panic if the OsStr + // contains invalid Unicode. To avoid this, we use a + // Windows-specific starts-with function that doesn't rely on + // as_bytes(). This is necessary for Windows command line + // applications to handle non-Unicode arguments successfully. This + // allows common cases like `clap.exe [invalid]` to succeed, though + // cases that require string splitting will still fail, like + // `clap.exe --arg=[invalid]`. Note that this entire module is + // replaced in Clap 3.x, so this workaround is specific to the 2.x + // branch. + windows_osstr_starts_with(self, s) + } + #[cfg(not(target_os = "windows"))] + { + self.as_bytes().starts_with(s) + } + } + + fn contains_byte(&self, byte: u8) -> bool { + for b in self.as_bytes() { + if b == &byte { + return true; + } + } + false + } + + fn split_at_byte(&self, byte: u8) -> (&OsStr, &OsStr) { + for (i, b) in self.as_bytes().iter().enumerate() { + if b == &byte { + return ( + OsStr::from_bytes(&self.as_bytes()[..i]), + OsStr::from_bytes(&self.as_bytes()[i + 1..]), + ); + } + } + ( + &*self, + OsStr::from_bytes(&self.as_bytes()[self.len()..self.len()]), + ) + } + + fn trim_left_matches(&self, byte: u8) -> &OsStr { + let mut found = false; + for (i, b) in self.as_bytes().iter().enumerate() { + if b != &byte { + return OsStr::from_bytes(&self.as_bytes()[i..]); + } else { + found = true; + } + } + if found { + return OsStr::from_bytes(&self.as_bytes()[self.len()..]); + } + &*self + } + + fn split_at(&self, i: usize) -> (&OsStr, &OsStr) { + ( + OsStr::from_bytes(&self.as_bytes()[..i]), + OsStr::from_bytes(&self.as_bytes()[i..]), + ) + } + + fn split(&self, b: u8) -> OsSplit { + OsSplit { + sep: b, + val: self.as_bytes(), + pos: 0, + } + } +} + +#[doc(hidden)] +#[derive(Clone, Debug)] +pub struct OsSplit<'a> { + sep: u8, + val: &'a [u8], + pos: usize, +} + +impl<'a> Iterator for OsSplit<'a> { + type Item = &'a OsStr; + + fn next(&mut self) -> Option<&'a OsStr> { + debugln!("OsSplit::next: self={:?}", self); + if self.pos == self.val.len() { + return None; + } + let start = self.pos; + for b in &self.val[start..] { + self.pos += 1; + if *b == self.sep { + return Some(OsStr::from_bytes(&self.val[start..self.pos - 1])); + } + } + Some(OsStr::from_bytes(&self.val[start..])) + } +} diff --git a/vendor/clap-2.34.0/src/strext.rs b/vendor/clap-2.34.0/src/strext.rs new file mode 100644 index 0000000000000..52efab64f1458 --- /dev/null +++ b/vendor/clap-2.34.0/src/strext.rs @@ -0,0 +1,16 @@ +pub trait _StrExt { + fn _is_char_boundary(&self, index: usize) -> bool; +} + +impl _StrExt for str { + #[inline] + fn _is_char_boundary(&self, index: usize) -> bool { + if index == self.len() { + return true; + } + match self.as_bytes().get(index) { + None => false, + Some(&b) => !(128..192).contains(&b), + } + } +} diff --git a/vendor/clap-2.34.0/src/suggestions.rs b/vendor/clap-2.34.0/src/suggestions.rs new file mode 100644 index 0000000000000..5c549888ff8ee --- /dev/null +++ b/vendor/clap-2.34.0/src/suggestions.rs @@ -0,0 +1,141 @@ +// Internal +use crate::{app::App, fmt::Format}; + +/// Produces a string from a given list of possible values which is similar to +/// the passed in value `v` with a certain confidence. +/// Thus in a list of possible values like ["foo", "bar"], the value "fop" will yield +/// `Some("foo")`, whereas "blark" would yield `None`. +#[cfg(feature = "suggestions")] +#[cfg_attr(feature = "cargo-clippy", allow(clippy::needless_lifetimes))] +pub fn did_you_mean<'a, T: ?Sized, I>(v: &str, possible_values: I) -> Option<&'a str> +where + T: AsRef + 'a, + I: IntoIterator, +{ + let mut candidate: Option<(f64, &str)> = None; + for pv in possible_values { + let confidence = strsim::jaro_winkler(v, pv.as_ref()); + if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence)) + { + candidate = Some((confidence, pv.as_ref())); + } + } + match candidate { + None => None, + Some((_, candidate)) => Some(candidate), + } +} + +#[cfg(not(feature = "suggestions"))] +pub fn did_you_mean<'a, T: ?Sized, I>(_: &str, _: I) -> Option<&'a str> +where + T: AsRef + 'a, + I: IntoIterator, +{ + None +} + +/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase +pub fn did_you_mean_flag_suffix<'z, T, I>( + arg: &str, + args_rest: &'z [&str], + longs: I, + subcommands: &'z [App], +) -> (String, Option<&'z str>) +where + T: AsRef + 'z, + I: IntoIterator, +{ + if let Some(candidate) = did_you_mean(arg, longs) { + let suffix = format!( + "\n\tDid you mean {}{}?", + Format::Good("--"), + Format::Good(candidate) + ); + return (suffix, Some(candidate)); + } + + subcommands + .iter() + .filter_map(|subcommand| { + let opts = subcommand + .p + .flags + .iter() + .filter_map(|f| f.s.long) + .chain(subcommand.p.opts.iter().filter_map(|o| o.s.long)); + + let candidate = match did_you_mean(arg, opts) { + Some(candidate) => candidate, + None => return None, + }; + let score = match args_rest.iter().position(|x| *x == subcommand.get_name()) { + Some(score) => score, + None => return None, + }; + + let suffix = format!( + "\n\tDid you mean to put '{}{}' after the subcommand '{}'?", + Format::Good("--"), + Format::Good(candidate), + Format::Good(subcommand.get_name()) + ); + + Some((score, (suffix, Some(candidate)))) + }) + .min_by_key(|&(score, _)| score) + .map(|(_, suggestion)| suggestion) + .unwrap_or_else(|| (String::new(), None)) +} + +/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase +pub fn did_you_mean_value_suffix<'z, T, I>(arg: &str, values: I) -> (String, Option<&'z str>) +where + T: AsRef + 'z, + I: IntoIterator, +{ + match did_you_mean(arg, values) { + Some(candidate) => { + let suffix = format!("\n\tDid you mean '{}'?", Format::Good(candidate)); + (suffix, Some(candidate)) + } + None => (String::new(), None), + } +} + +#[cfg(all(test, features = "suggestions"))] +mod test { + use super::*; + + #[test] + fn possible_values_match() { + let p_vals = ["test", "possible", "values"]; + assert_eq!(did_you_mean("tst", p_vals.iter()), Some("test")); + } + + #[test] + fn possible_values_nomatch() { + let p_vals = ["test", "possible", "values"]; + assert!(did_you_mean("hahaahahah", p_vals.iter()).is_none()); + } + + #[test] + fn suffix_long() { + let p_vals = ["test", "possible", "values"]; + let suffix = "\n\tDid you mean \'--test\'?"; + assert_eq!( + did_you_mean_flag_suffix("tst", p_vals.iter(), []), + (suffix, Some("test")) + ); + } + + #[test] + fn suffix_enum() { + let p_vals = ["test", "possible", "values"]; + let suffix = "\n\tDid you mean \'test\'?"; + assert_eq!( + did_you_mean_value_suffix("tst", p_vals.iter()), + (suffix, Some("test")) + ); + } +} diff --git a/vendor/clap-2.34.0/src/usage_parser.rs b/vendor/clap-2.34.0/src/usage_parser.rs new file mode 100644 index 0000000000000..d3c1921d6dcc7 --- /dev/null +++ b/vendor/clap-2.34.0/src/usage_parser.rs @@ -0,0 +1,1356 @@ +// Internal +use crate::{ + args::{settings::ArgSettings, Arg}, + map::VecMap, + INTERNAL_ERROR_MSG, +}; + +#[derive(PartialEq, Debug)] +enum UsageToken { + Name, + ValName, + Short, + Long, + Help, + Multiple, + Unknown, +} + +#[doc(hidden)] +#[derive(Debug)] +pub struct UsageParser<'a> { + usage: &'a str, + pos: usize, + start: usize, + prev: UsageToken, + explicit_name_set: bool, +} + +impl<'a> UsageParser<'a> { + fn new(usage: &'a str) -> Self { + debugln!("UsageParser::new: usage={:?}", usage); + UsageParser { + usage, + pos: 0, + start: 0, + prev: UsageToken::Unknown, + explicit_name_set: false, + } + } + + pub fn from_usage(usage: &'a str) -> Self { + debugln!("UsageParser::from_usage;"); + UsageParser::new(usage) + } + + pub fn parse(mut self) -> Arg<'a, 'a> { + debugln!("UsageParser::parse;"); + let mut arg = Arg::default(); + loop { + debugln!("UsageParser::parse:iter: pos={};", self.pos); + self.stop_at(token); + if let Some(&c) = self.usage.as_bytes().get(self.pos) { + match c { + b'-' => self.short_or_long(&mut arg), + b'.' => self.multiple(&mut arg), + b'\'' => self.help(&mut arg), + _ => self.name(&mut arg), + } + } else { + break; + } + } + debug_assert!( + !arg.b.name.is_empty(), + "No name found for Arg when parsing usage string: {}", + self.usage + ); + arg.v.num_vals = match arg.v.val_names { + Some(ref v) if v.len() >= 2 => Some(v.len() as u64), + _ => None, + }; + debugln!("UsageParser::parse: vals...{:?}", arg.v.val_names); + arg + } + + fn name(&mut self, arg: &mut Arg<'a, 'a>) { + debugln!("UsageParser::name;"); + if *self + .usage + .as_bytes() + .get(self.pos) + .expect(INTERNAL_ERROR_MSG) + == b'<' + && !self.explicit_name_set + { + arg.setb(ArgSettings::Required); + } + self.pos += 1; + self.stop_at(name_end); + let name = &self.usage[self.start..self.pos]; + if self.prev == UsageToken::Unknown { + debugln!("UsageParser::name: setting name...{}", name); + arg.b.name = name; + if arg.s.long.is_none() && arg.s.short.is_none() { + debugln!("UsageParser::name: explicit name set..."); + self.explicit_name_set = true; + self.prev = UsageToken::Name; + } + } else { + debugln!("UsageParser::name: setting val name...{}", name); + if let Some(ref mut v) = arg.v.val_names { + let len = v.len(); + v.insert(len, name); + } else { + let mut v = VecMap::new(); + v.insert(0, name); + arg.v.val_names = Some(v); + arg.setb(ArgSettings::TakesValue); + } + self.prev = UsageToken::ValName; + } + } + + fn stop_at(&mut self, f: F) + where + F: Fn(u8) -> bool, + { + debugln!("UsageParser::stop_at;"); + self.start = self.pos; + self.pos += self.usage[self.start..] + .bytes() + .take_while(|&b| f(b)) + .count(); + } + + fn short_or_long(&mut self, arg: &mut Arg<'a, 'a>) { + debugln!("UsageParser::short_or_long;"); + self.pos += 1; + if *self + .usage + .as_bytes() + .get(self.pos) + .expect(INTERNAL_ERROR_MSG) + == b'-' + { + self.pos += 1; + self.long(arg); + return; + } + self.short(arg) + } + + fn long(&mut self, arg: &mut Arg<'a, 'a>) { + debugln!("UsageParser::long;"); + self.stop_at(long_end); + let name = &self.usage[self.start..self.pos]; + if !self.explicit_name_set { + debugln!("UsageParser::long: setting name...{}", name); + arg.b.name = name; + } + debugln!("UsageParser::long: setting long...{}", name); + arg.s.long = Some(name); + self.prev = UsageToken::Long; + } + + fn short(&mut self, arg: &mut Arg<'a, 'a>) { + debugln!("UsageParser::short;"); + let start = &self.usage[self.pos..]; + let short = start.chars().next().expect(INTERNAL_ERROR_MSG); + debugln!("UsageParser::short: setting short...{}", short); + arg.s.short = Some(short); + if arg.b.name.is_empty() { + // --long takes precedence but doesn't set self.explicit_name_set + let name = &start[..short.len_utf8()]; + debugln!("UsageParser::short: setting name...{}", name); + arg.b.name = name; + } + self.prev = UsageToken::Short; + } + + // "something..." + fn multiple(&mut self, arg: &mut Arg) { + debugln!("UsageParser::multiple;"); + let mut dot_counter = 1; + let start = self.pos; + let mut bytes = self.usage[start..].bytes(); + while bytes.next() == Some(b'.') { + dot_counter += 1; + self.pos += 1; + if dot_counter == 3 { + debugln!("UsageParser::multiple: setting multiple"); + arg.setb(ArgSettings::Multiple); + if arg.is_set(ArgSettings::TakesValue) { + arg.setb(ArgSettings::UseValueDelimiter); + arg.unsetb(ArgSettings::ValueDelimiterNotSet); + if arg.v.val_delim.is_none() { + arg.v.val_delim = Some(','); + } + } + self.prev = UsageToken::Multiple; + self.pos += 1; + break; + } + } + } + + fn help(&mut self, arg: &mut Arg<'a, 'a>) { + debugln!("UsageParser::help;"); + self.stop_at(help_start); + self.start = self.pos + 1; + self.pos = self.usage.len() - 1; + debugln!( + "UsageParser::help: setting help...{}", + &self.usage[self.start..self.pos] + ); + arg.b.help = Some(&self.usage[self.start..self.pos]); + self.pos += 1; // Move to next byte to keep from thinking ending ' is a start + self.prev = UsageToken::Help; + } +} + +#[inline] +fn name_end(b: u8) -> bool { + b != b']' && b != b'>' +} + +#[inline] +fn token(b: u8) -> bool { + b != b'\'' && b != b'.' && b != b'<' && b != b'[' && b != b'-' +} + +#[inline] +fn long_end(b: u8) -> bool { + b != b'\'' && b != b'.' && b != b'<' && b != b'[' && b != b'=' && b != b' ' +} + +#[inline] +fn help_start(b: u8) -> bool { + b != b'\'' +} + +#[cfg(test)] +mod test { + use crate::args::{Arg, ArgSettings}; + + #[test] + fn create_flag_usage() { + let a = Arg::from_usage("[flag] -f 'some help info'"); + assert_eq!(a.b.name, "flag"); + assert_eq!(a.s.short.unwrap(), 'f'); + assert!(a.s.long.is_none()); + assert_eq!(a.b.help.unwrap(), "some help info"); + assert!(!a.is_set(ArgSettings::Multiple)); + assert!(a.v.val_names.is_none()); + assert!(a.v.num_vals.is_none()); + + let b = Arg::from_usage("[flag] --flag 'some help info'"); + assert_eq!(b.b.name, "flag"); + assert_eq!(b.s.long.unwrap(), "flag"); + assert!(b.s.short.is_none()); + assert_eq!(b.b.help.unwrap(), "some help info"); + assert!(!b.is_set(ArgSettings::Multiple)); + assert!(a.v.val_names.is_none()); + assert!(a.v.num_vals.is_none()); + + let b = Arg::from_usage("--flag 'some help info'"); + assert_eq!(b.b.name, "flag"); + assert_eq!(b.s.long.unwrap(), "flag"); + assert!(b.s.short.is_none()); + assert_eq!(b.b.help.unwrap(), "some help info"); + assert!(!b.is_set(ArgSettings::Multiple)); + assert!(b.v.val_names.is_none()); + assert!(b.v.num_vals.is_none()); + + let c = Arg::from_usage("[flag] -f --flag 'some help info'"); + assert_eq!(c.b.name, "flag"); + assert_eq!(c.s.short.unwrap(), 'f'); + assert_eq!(c.s.long.unwrap(), "flag"); + assert_eq!(c.b.help.unwrap(), "some help info"); + assert!(!c.is_set(ArgSettings::Multiple)); + assert!(c.v.val_names.is_none()); + assert!(c.v.num_vals.is_none()); + + let d = Arg::from_usage("[flag] -f... 'some help info'"); + assert_eq!(d.b.name, "flag"); + assert_eq!(d.s.short.unwrap(), 'f'); + assert!(d.s.long.is_none()); + assert_eq!(d.b.help.unwrap(), "some help info"); + assert!(d.is_set(ArgSettings::Multiple)); + assert!(d.v.val_names.is_none()); + assert!(d.v.num_vals.is_none()); + + let e = Arg::from_usage("[flag] -f --flag... 'some help info'"); + assert_eq!(e.b.name, "flag"); + assert_eq!(e.s.long.unwrap(), "flag"); + assert_eq!(e.s.short.unwrap(), 'f'); + assert_eq!(e.b.help.unwrap(), "some help info"); + assert!(e.is_set(ArgSettings::Multiple)); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let e = Arg::from_usage("-f --flag... 'some help info'"); + assert_eq!(e.b.name, "flag"); + assert_eq!(e.s.long.unwrap(), "flag"); + assert_eq!(e.s.short.unwrap(), 'f'); + assert_eq!(e.b.help.unwrap(), "some help info"); + assert!(e.is_set(ArgSettings::Multiple)); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let e = Arg::from_usage("--flags"); + assert_eq!(e.b.name, "flags"); + assert_eq!(e.s.long.unwrap(), "flags"); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let e = Arg::from_usage("--flags..."); + assert_eq!(e.b.name, "flags"); + assert_eq!(e.s.long.unwrap(), "flags"); + assert!(e.is_set(ArgSettings::Multiple)); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let e = Arg::from_usage("[flags] -f"); + assert_eq!(e.b.name, "flags"); + assert_eq!(e.s.short.unwrap(), 'f'); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let e = Arg::from_usage("[flags] -f..."); + assert_eq!(e.b.name, "flags"); + assert_eq!(e.s.short.unwrap(), 'f'); + assert!(e.is_set(ArgSettings::Multiple)); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let a = Arg::from_usage("-f 'some help info'"); + assert_eq!(a.b.name, "f"); + assert_eq!(a.s.short.unwrap(), 'f'); + assert!(a.s.long.is_none()); + assert_eq!(a.b.help.unwrap(), "some help info"); + assert!(!a.is_set(ArgSettings::Multiple)); + assert!(a.v.val_names.is_none()); + assert!(a.v.num_vals.is_none()); + + let e = Arg::from_usage("-f"); + assert_eq!(e.b.name, "f"); + assert_eq!(e.s.short.unwrap(), 'f'); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let e = Arg::from_usage("-f..."); + assert_eq!(e.b.name, "f"); + assert_eq!(e.s.short.unwrap(), 'f'); + assert!(e.is_set(ArgSettings::Multiple)); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + } + + #[test] + fn create_option_usage0() { + // Short only + let a = Arg::from_usage("[option] -o [opt] 'some help info'"); + assert_eq!(a.b.name, "option"); + assert_eq!(a.s.short.unwrap(), 'o'); + assert!(a.s.long.is_none()); + assert_eq!(a.b.help.unwrap(), "some help info"); + assert!(!a.is_set(ArgSettings::Multiple)); + assert!(a.is_set(ArgSettings::TakesValue)); + assert!(!a.is_set(ArgSettings::Required)); + assert_eq!( + a.v.val_names.unwrap().values().collect::>(), + [&"opt"] + ); + assert!(a.v.num_vals.is_none()); + } + + #[test] + fn create_option_usage1() { + let b = Arg::from_usage("-o [opt] 'some help info'"); + assert_eq!(b.b.name, "o"); + assert_eq!(b.s.short.unwrap(), 'o'); + assert!(b.s.long.is_none()); + assert_eq!(b.b.help.unwrap(), "some help info"); + assert!(!b.is_set(ArgSettings::Multiple)); + assert!(b.is_set(ArgSettings::TakesValue)); + assert!(!b.is_set(ArgSettings::Required)); + assert_eq!( + b.v.val_names.unwrap().values().collect::>(), + [&"opt"] + ); + assert!(b.v.num_vals.is_none()); + } + + #[test] + fn create_option_usage2() { + let c = Arg::from_usage("
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope1.0347 us1.0564 us1.0725 us
0.33775770.34230510.3397572
Mean692.34 ns775.33 ns854.90 ns
Std. Dev.368.08 ns417.08 ns449.88 ns
Median924.01 ns998.03 ns1.0382 us
MAD115.39 ns174.14 ns269.31 ns
+
+
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+ + + + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/mean.svg new file mode 100644 index 0000000000000..56b40590c2fd7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/mean.svg @@ -0,0 +1,328 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 0.009 + + + + + 0.01 + + + + + 680 + + + + + 700 + + + + + 720 + + + + + 740 + + + + + 760 + + + + + 780 + + + + + 800 + + + + + 820 + + + + + 840 + + + + + 860 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/crate 'object-pool': mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/median.svg new file mode 100644 index 0000000000000..ebaad1c79b804 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/median.svg @@ -0,0 +1,288 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 0.92 + + + + + 0.94 + + + + + 0.96 + + + + + 0.98 + + + + + 1 + + + + + 1.02 + + + + + 1.04 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/crate 'object-pool': median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/pdf.svg new file mode 100644 index 0000000000000..d72b6cf7b566d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/pdf.svg @@ -0,0 +1,405 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 70 + + + + + 80 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/crate 'object-pool' + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/pdf_small.svg new file mode 100644 index 0000000000000..adf40a05c3f0e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/pdf_small.svg @@ -0,0 +1,204 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/regression.svg new file mode 100644 index 0000000000000..51c6c7cbae232 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/regression.svg @@ -0,0 +1,486 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 90 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 90 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + allocation/crate 'object-pool' + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/regression_small.svg new file mode 100644 index 0000000000000..0986ab5ec214b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/regression_small.svg @@ -0,0 +1,464 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 90 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 90 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/slope.svg new file mode 100644 index 0000000000000..cbd464162325b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/slope.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 30 + + + + + 35 + + + + + 40 + + + + + 45 + + + + + 1.035 + + + + + 1.04 + + + + + 1.045 + + + + + 1.05 + + + + + 1.055 + + + + + 1.06 + + + + + 1.065 + + + + + 1.07 + + + + + 1.075 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/crate 'object-pool': slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/typical.svg new file mode 100644 index 0000000000000..79fba58b0f97f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'object-pool'/report/typical.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 30 + + + + + 35 + + + + + 40 + + + + + 45 + + + + + 1.035 + + + + + 1.04 + + + + + 1.045 + + + + + 1.05 + + + + + 1.055 + + + + + 1.06 + + + + + 1.065 + + + + + 1.07 + + + + + 1.075 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/crate 'object-pool': typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/benchmark.json new file mode 100644 index 0000000000000..d1dc59ce8ab32 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"allocation","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"allocation/crate 'sharded-slab'","directory_name":"allocation/crate 'sharded-slab'","title":"allocation/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/estimates.json new file mode 100644 index 0000000000000..85c5dc3b82dae --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1496.8467295266069,"upper_bound":1752.4754301360485},"point_estimate":1626.3848414778902,"standard_error":65.26032145038015},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1514.0450100884682,"upper_bound":1798.5339448004356},"point_estimate":1643.4249804705637,"standard_error":74.81058603438048},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":414.0824528664392,"upper_bound":773.8233301116128},"point_estimate":565.9792218450001,"standard_error":89.9498402439214},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1826.4256437904319,"upper_bound":2082.57813388947},"point_estimate":1958.7109080657997,"standard_error":65.19640103009677},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":557.180068164234,"upper_bound":739.9982157638015},"point_estimate":656.397488247998,"standard_error":46.60310187781404}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/raw.csv new file mode 100644 index 0000000000000..3354af531ff14 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +allocation,crate 'sharded-slab',,,,75187.0,ns,379 +allocation,crate 'sharded-slab',,,,136221.0,ns,758 +allocation,crate 'sharded-slab',,,,237226.0,ns,1137 +allocation,crate 'sharded-slab',,,,241610.0,ns,1516 +allocation,crate 'sharded-slab',,,,276218.0,ns,1895 +allocation,crate 'sharded-slab',,,,2192477.0,ns,2274 +allocation,crate 'sharded-slab',,,,451394.0,ns,2653 +allocation,crate 'sharded-slab',,,,490458.0,ns,3032 +allocation,crate 'sharded-slab',,,,520356.0,ns,3411 +allocation,crate 'sharded-slab',,,,562287.0,ns,3790 +allocation,crate 'sharded-slab',,,,6204776.0,ns,4169 +allocation,crate 'sharded-slab',,,,5857272.0,ns,4548 +allocation,crate 'sharded-slab',,,,5980163.0,ns,4927 +allocation,crate 'sharded-slab',,,,6019358.0,ns,5306 +allocation,crate 'sharded-slab',,,,5998718.0,ns,5685 +allocation,crate 'sharded-slab',,,,6023747.0,ns,6064 +allocation,crate 'sharded-slab',,,,6062734.0,ns,6443 +allocation,crate 'sharded-slab',,,,6082336.0,ns,6822 +allocation,crate 'sharded-slab',,,,6109926.0,ns,7201 +allocation,crate 'sharded-slab',,,,6132205.0,ns,7580 +allocation,crate 'sharded-slab',,,,6205370.0,ns,7959 +allocation,crate 'sharded-slab',,,,16971801.0,ns,8338 +allocation,crate 'sharded-slab',,,,18993746.0,ns,8717 +allocation,crate 'sharded-slab',,,,18990863.0,ns,9096 +allocation,crate 'sharded-slab',,,,19045805.0,ns,9475 +allocation,crate 'sharded-slab',,,,19146840.0,ns,9854 +allocation,crate 'sharded-slab',,,,19163587.0,ns,10233 +allocation,crate 'sharded-slab',,,,19220478.0,ns,10612 +allocation,crate 'sharded-slab',,,,19263168.0,ns,10991 +allocation,crate 'sharded-slab',,,,19661123.0,ns,11370 +allocation,crate 'sharded-slab',,,,19420221.0,ns,11749 +allocation,crate 'sharded-slab',,,,19413521.0,ns,12128 +allocation,crate 'sharded-slab',,,,19473218.0,ns,12507 +allocation,crate 'sharded-slab',,,,19509984.0,ns,12886 +allocation,crate 'sharded-slab',,,,19526969.0,ns,13265 +allocation,crate 'sharded-slab',,,,19570722.0,ns,13644 +allocation,crate 'sharded-slab',,,,19622576.0,ns,14023 +allocation,crate 'sharded-slab',,,,19669505.0,ns,14402 +allocation,crate 'sharded-slab',,,,19900447.0,ns,14781 +allocation,crate 'sharded-slab',,,,20195337.0,ns,15160 +allocation,crate 'sharded-slab',,,,20023443.0,ns,15539 +allocation,crate 'sharded-slab',,,,19948545.0,ns,15918 +allocation,crate 'sharded-slab',,,,19923769.0,ns,16297 +allocation,crate 'sharded-slab',,,,41483649.0,ns,16676 +allocation,crate 'sharded-slab',,,,42243380.0,ns,17055 +allocation,crate 'sharded-slab',,,,43574033.0,ns,17434 +allocation,crate 'sharded-slab',,,,42197059.0,ns,17813 +allocation,crate 'sharded-slab',,,,42171642.0,ns,18192 +allocation,crate 'sharded-slab',,,,42188767.0,ns,18571 +allocation,crate 'sharded-slab',,,,42230126.0,ns,18950 +allocation,crate 'sharded-slab',,,,42243498.0,ns,19329 +allocation,crate 'sharded-slab',,,,42416784.0,ns,19708 +allocation,crate 'sharded-slab',,,,42415114.0,ns,20087 +allocation,crate 'sharded-slab',,,,42866038.0,ns,20466 +allocation,crate 'sharded-slab',,,,42856545.0,ns,20845 +allocation,crate 'sharded-slab',,,,42802489.0,ns,21224 +allocation,crate 'sharded-slab',,,,42880127.0,ns,21603 +allocation,crate 'sharded-slab',,,,42753568.0,ns,21982 +allocation,crate 'sharded-slab',,,,42698590.0,ns,22361 +allocation,crate 'sharded-slab',,,,42709350.0,ns,22740 +allocation,crate 'sharded-slab',,,,42914319.0,ns,23119 +allocation,crate 'sharded-slab',,,,42854769.0,ns,23498 +allocation,crate 'sharded-slab',,,,42943595.0,ns,23877 +allocation,crate 'sharded-slab',,,,42968091.0,ns,24256 +allocation,crate 'sharded-slab',,,,42906122.0,ns,24635 +allocation,crate 'sharded-slab',,,,43332487.0,ns,25014 +allocation,crate 'sharded-slab',,,,43142359.0,ns,25393 +allocation,crate 'sharded-slab',,,,43147381.0,ns,25772 +allocation,crate 'sharded-slab',,,,43213352.0,ns,26151 +allocation,crate 'sharded-slab',,,,43360497.0,ns,26530 +allocation,crate 'sharded-slab',,,,43242712.0,ns,26909 +allocation,crate 'sharded-slab',,,,43236996.0,ns,27288 +allocation,crate 'sharded-slab',,,,43322172.0,ns,27667 +allocation,crate 'sharded-slab',,,,43404602.0,ns,28046 +allocation,crate 'sharded-slab',,,,43499227.0,ns,28425 +allocation,crate 'sharded-slab',,,,43477916.0,ns,28804 +allocation,crate 'sharded-slab',,,,45081132.0,ns,29183 +allocation,crate 'sharded-slab',,,,44370901.0,ns,29562 +allocation,crate 'sharded-slab',,,,43725855.0,ns,29941 +allocation,crate 'sharded-slab',,,,43758725.0,ns,30320 +allocation,crate 'sharded-slab',,,,43916122.0,ns,30699 +allocation,crate 'sharded-slab',,,,43796233.0,ns,31078 +allocation,crate 'sharded-slab',,,,43940814.0,ns,31457 +allocation,crate 'sharded-slab',,,,43880444.0,ns,31836 +allocation,crate 'sharded-slab',,,,43893331.0,ns,32215 +allocation,crate 'sharded-slab',,,,44022411.0,ns,32594 +allocation,crate 'sharded-slab',,,,86597027.0,ns,32973 +allocation,crate 'sharded-slab',,,,88061546.0,ns,33352 +allocation,crate 'sharded-slab',,,,87880755.0,ns,33731 +allocation,crate 'sharded-slab',,,,87911942.0,ns,34110 +allocation,crate 'sharded-slab',,,,88095379.0,ns,34489 +allocation,crate 'sharded-slab',,,,88128123.0,ns,34868 +allocation,crate 'sharded-slab',,,,87994009.0,ns,35247 +allocation,crate 'sharded-slab',,,,88446505.0,ns,35626 +allocation,crate 'sharded-slab',,,,88197868.0,ns,36005 +allocation,crate 'sharded-slab',,,,88383565.0,ns,36384 +allocation,crate 'sharded-slab',,,,88288640.0,ns,36763 +allocation,crate 'sharded-slab',,,,88262334.0,ns,37142 +allocation,crate 'sharded-slab',,,,88422192.0,ns,37521 +allocation,crate 'sharded-slab',,,,88380299.0,ns,37900 diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/sample.json new file mode 100644 index 0000000000000..467bc053919a8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[379.0,758.0,1137.0,1516.0,1895.0,2274.0,2653.0,3032.0,3411.0,3790.0,4169.0,4548.0,4927.0,5306.0,5685.0,6064.0,6443.0,6822.0,7201.0,7580.0,7959.0,8338.0,8717.0,9096.0,9475.0,9854.0,10233.0,10612.0,10991.0,11370.0,11749.0,12128.0,12507.0,12886.0,13265.0,13644.0,14023.0,14402.0,14781.0,15160.0,15539.0,15918.0,16297.0,16676.0,17055.0,17434.0,17813.0,18192.0,18571.0,18950.0,19329.0,19708.0,20087.0,20466.0,20845.0,21224.0,21603.0,21982.0,22361.0,22740.0,23119.0,23498.0,23877.0,24256.0,24635.0,25014.0,25393.0,25772.0,26151.0,26530.0,26909.0,27288.0,27667.0,28046.0,28425.0,28804.0,29183.0,29562.0,29941.0,30320.0,30699.0,31078.0,31457.0,31836.0,32215.0,32594.0,32973.0,33352.0,33731.0,34110.0,34489.0,34868.0,35247.0,35626.0,36005.0,36384.0,36763.0,37142.0,37521.0,37900.0],"times":[75187.0,136221.0,237226.0,241610.0,276218.0,2192477.0,451394.0,490458.0,520356.0,562287.0,6204776.0,5857272.0,5980163.0,6019358.0,5998718.0,6023747.0,6062734.0,6082336.0,6109926.0,6132205.0,6205370.0,16971801.0,18993746.0,18990863.0,19045805.0,19146840.0,19163587.0,19220478.0,19263168.0,19661123.0,19420221.0,19413521.0,19473218.0,19509984.0,19526969.0,19570722.0,19622576.0,19669505.0,19900447.0,20195337.0,20023443.0,19948545.0,19923769.0,41483649.0,42243380.0,43574033.0,42197059.0,42171642.0,42188767.0,42230126.0,42243498.0,42416784.0,42415114.0,42866038.0,42856545.0,42802489.0,42880127.0,42753568.0,42698590.0,42709350.0,42914319.0,42854769.0,42943595.0,42968091.0,42906122.0,43332487.0,43142359.0,43147381.0,43213352.0,43360497.0,43242712.0,43236996.0,43322172.0,43404602.0,43499227.0,43477916.0,45081132.0,44370901.0,43725855.0,43758725.0,43916122.0,43796233.0,43940814.0,43880444.0,43893331.0,44022411.0,86597027.0,88061546.0,87880755.0,87911942.0,88095379.0,88128123.0,87994009.0,88446505.0,88197868.0,88383565.0,88288640.0,88262334.0,88422192.0,88380299.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/tukey.json new file mode 100644 index 0000000000000..9abc035255a71 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/base/tukey.json @@ -0,0 +1 @@ +[-898.0618000799095,225.7492357762958,3222.5786647261766,4346.389700582382] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/benchmark.json new file mode 100644 index 0000000000000..d1dc59ce8ab32 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"allocation","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"allocation/crate 'sharded-slab'","directory_name":"allocation/crate 'sharded-slab'","title":"allocation/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/estimates.json new file mode 100644 index 0000000000000..85c5dc3b82dae --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1496.8467295266069,"upper_bound":1752.4754301360485},"point_estimate":1626.3848414778902,"standard_error":65.26032145038015},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1514.0450100884682,"upper_bound":1798.5339448004356},"point_estimate":1643.4249804705637,"standard_error":74.81058603438048},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":414.0824528664392,"upper_bound":773.8233301116128},"point_estimate":565.9792218450001,"standard_error":89.9498402439214},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1826.4256437904319,"upper_bound":2082.57813388947},"point_estimate":1958.7109080657997,"standard_error":65.19640103009677},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":557.180068164234,"upper_bound":739.9982157638015},"point_estimate":656.397488247998,"standard_error":46.60310187781404}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/raw.csv new file mode 100644 index 0000000000000..3354af531ff14 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +allocation,crate 'sharded-slab',,,,75187.0,ns,379 +allocation,crate 'sharded-slab',,,,136221.0,ns,758 +allocation,crate 'sharded-slab',,,,237226.0,ns,1137 +allocation,crate 'sharded-slab',,,,241610.0,ns,1516 +allocation,crate 'sharded-slab',,,,276218.0,ns,1895 +allocation,crate 'sharded-slab',,,,2192477.0,ns,2274 +allocation,crate 'sharded-slab',,,,451394.0,ns,2653 +allocation,crate 'sharded-slab',,,,490458.0,ns,3032 +allocation,crate 'sharded-slab',,,,520356.0,ns,3411 +allocation,crate 'sharded-slab',,,,562287.0,ns,3790 +allocation,crate 'sharded-slab',,,,6204776.0,ns,4169 +allocation,crate 'sharded-slab',,,,5857272.0,ns,4548 +allocation,crate 'sharded-slab',,,,5980163.0,ns,4927 +allocation,crate 'sharded-slab',,,,6019358.0,ns,5306 +allocation,crate 'sharded-slab',,,,5998718.0,ns,5685 +allocation,crate 'sharded-slab',,,,6023747.0,ns,6064 +allocation,crate 'sharded-slab',,,,6062734.0,ns,6443 +allocation,crate 'sharded-slab',,,,6082336.0,ns,6822 +allocation,crate 'sharded-slab',,,,6109926.0,ns,7201 +allocation,crate 'sharded-slab',,,,6132205.0,ns,7580 +allocation,crate 'sharded-slab',,,,6205370.0,ns,7959 +allocation,crate 'sharded-slab',,,,16971801.0,ns,8338 +allocation,crate 'sharded-slab',,,,18993746.0,ns,8717 +allocation,crate 'sharded-slab',,,,18990863.0,ns,9096 +allocation,crate 'sharded-slab',,,,19045805.0,ns,9475 +allocation,crate 'sharded-slab',,,,19146840.0,ns,9854 +allocation,crate 'sharded-slab',,,,19163587.0,ns,10233 +allocation,crate 'sharded-slab',,,,19220478.0,ns,10612 +allocation,crate 'sharded-slab',,,,19263168.0,ns,10991 +allocation,crate 'sharded-slab',,,,19661123.0,ns,11370 +allocation,crate 'sharded-slab',,,,19420221.0,ns,11749 +allocation,crate 'sharded-slab',,,,19413521.0,ns,12128 +allocation,crate 'sharded-slab',,,,19473218.0,ns,12507 +allocation,crate 'sharded-slab',,,,19509984.0,ns,12886 +allocation,crate 'sharded-slab',,,,19526969.0,ns,13265 +allocation,crate 'sharded-slab',,,,19570722.0,ns,13644 +allocation,crate 'sharded-slab',,,,19622576.0,ns,14023 +allocation,crate 'sharded-slab',,,,19669505.0,ns,14402 +allocation,crate 'sharded-slab',,,,19900447.0,ns,14781 +allocation,crate 'sharded-slab',,,,20195337.0,ns,15160 +allocation,crate 'sharded-slab',,,,20023443.0,ns,15539 +allocation,crate 'sharded-slab',,,,19948545.0,ns,15918 +allocation,crate 'sharded-slab',,,,19923769.0,ns,16297 +allocation,crate 'sharded-slab',,,,41483649.0,ns,16676 +allocation,crate 'sharded-slab',,,,42243380.0,ns,17055 +allocation,crate 'sharded-slab',,,,43574033.0,ns,17434 +allocation,crate 'sharded-slab',,,,42197059.0,ns,17813 +allocation,crate 'sharded-slab',,,,42171642.0,ns,18192 +allocation,crate 'sharded-slab',,,,42188767.0,ns,18571 +allocation,crate 'sharded-slab',,,,42230126.0,ns,18950 +allocation,crate 'sharded-slab',,,,42243498.0,ns,19329 +allocation,crate 'sharded-slab',,,,42416784.0,ns,19708 +allocation,crate 'sharded-slab',,,,42415114.0,ns,20087 +allocation,crate 'sharded-slab',,,,42866038.0,ns,20466 +allocation,crate 'sharded-slab',,,,42856545.0,ns,20845 +allocation,crate 'sharded-slab',,,,42802489.0,ns,21224 +allocation,crate 'sharded-slab',,,,42880127.0,ns,21603 +allocation,crate 'sharded-slab',,,,42753568.0,ns,21982 +allocation,crate 'sharded-slab',,,,42698590.0,ns,22361 +allocation,crate 'sharded-slab',,,,42709350.0,ns,22740 +allocation,crate 'sharded-slab',,,,42914319.0,ns,23119 +allocation,crate 'sharded-slab',,,,42854769.0,ns,23498 +allocation,crate 'sharded-slab',,,,42943595.0,ns,23877 +allocation,crate 'sharded-slab',,,,42968091.0,ns,24256 +allocation,crate 'sharded-slab',,,,42906122.0,ns,24635 +allocation,crate 'sharded-slab',,,,43332487.0,ns,25014 +allocation,crate 'sharded-slab',,,,43142359.0,ns,25393 +allocation,crate 'sharded-slab',,,,43147381.0,ns,25772 +allocation,crate 'sharded-slab',,,,43213352.0,ns,26151 +allocation,crate 'sharded-slab',,,,43360497.0,ns,26530 +allocation,crate 'sharded-slab',,,,43242712.0,ns,26909 +allocation,crate 'sharded-slab',,,,43236996.0,ns,27288 +allocation,crate 'sharded-slab',,,,43322172.0,ns,27667 +allocation,crate 'sharded-slab',,,,43404602.0,ns,28046 +allocation,crate 'sharded-slab',,,,43499227.0,ns,28425 +allocation,crate 'sharded-slab',,,,43477916.0,ns,28804 +allocation,crate 'sharded-slab',,,,45081132.0,ns,29183 +allocation,crate 'sharded-slab',,,,44370901.0,ns,29562 +allocation,crate 'sharded-slab',,,,43725855.0,ns,29941 +allocation,crate 'sharded-slab',,,,43758725.0,ns,30320 +allocation,crate 'sharded-slab',,,,43916122.0,ns,30699 +allocation,crate 'sharded-slab',,,,43796233.0,ns,31078 +allocation,crate 'sharded-slab',,,,43940814.0,ns,31457 +allocation,crate 'sharded-slab',,,,43880444.0,ns,31836 +allocation,crate 'sharded-slab',,,,43893331.0,ns,32215 +allocation,crate 'sharded-slab',,,,44022411.0,ns,32594 +allocation,crate 'sharded-slab',,,,86597027.0,ns,32973 +allocation,crate 'sharded-slab',,,,88061546.0,ns,33352 +allocation,crate 'sharded-slab',,,,87880755.0,ns,33731 +allocation,crate 'sharded-slab',,,,87911942.0,ns,34110 +allocation,crate 'sharded-slab',,,,88095379.0,ns,34489 +allocation,crate 'sharded-slab',,,,88128123.0,ns,34868 +allocation,crate 'sharded-slab',,,,87994009.0,ns,35247 +allocation,crate 'sharded-slab',,,,88446505.0,ns,35626 +allocation,crate 'sharded-slab',,,,88197868.0,ns,36005 +allocation,crate 'sharded-slab',,,,88383565.0,ns,36384 +allocation,crate 'sharded-slab',,,,88288640.0,ns,36763 +allocation,crate 'sharded-slab',,,,88262334.0,ns,37142 +allocation,crate 'sharded-slab',,,,88422192.0,ns,37521 +allocation,crate 'sharded-slab',,,,88380299.0,ns,37900 diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/sample.json new file mode 100644 index 0000000000000..467bc053919a8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[379.0,758.0,1137.0,1516.0,1895.0,2274.0,2653.0,3032.0,3411.0,3790.0,4169.0,4548.0,4927.0,5306.0,5685.0,6064.0,6443.0,6822.0,7201.0,7580.0,7959.0,8338.0,8717.0,9096.0,9475.0,9854.0,10233.0,10612.0,10991.0,11370.0,11749.0,12128.0,12507.0,12886.0,13265.0,13644.0,14023.0,14402.0,14781.0,15160.0,15539.0,15918.0,16297.0,16676.0,17055.0,17434.0,17813.0,18192.0,18571.0,18950.0,19329.0,19708.0,20087.0,20466.0,20845.0,21224.0,21603.0,21982.0,22361.0,22740.0,23119.0,23498.0,23877.0,24256.0,24635.0,25014.0,25393.0,25772.0,26151.0,26530.0,26909.0,27288.0,27667.0,28046.0,28425.0,28804.0,29183.0,29562.0,29941.0,30320.0,30699.0,31078.0,31457.0,31836.0,32215.0,32594.0,32973.0,33352.0,33731.0,34110.0,34489.0,34868.0,35247.0,35626.0,36005.0,36384.0,36763.0,37142.0,37521.0,37900.0],"times":[75187.0,136221.0,237226.0,241610.0,276218.0,2192477.0,451394.0,490458.0,520356.0,562287.0,6204776.0,5857272.0,5980163.0,6019358.0,5998718.0,6023747.0,6062734.0,6082336.0,6109926.0,6132205.0,6205370.0,16971801.0,18993746.0,18990863.0,19045805.0,19146840.0,19163587.0,19220478.0,19263168.0,19661123.0,19420221.0,19413521.0,19473218.0,19509984.0,19526969.0,19570722.0,19622576.0,19669505.0,19900447.0,20195337.0,20023443.0,19948545.0,19923769.0,41483649.0,42243380.0,43574033.0,42197059.0,42171642.0,42188767.0,42230126.0,42243498.0,42416784.0,42415114.0,42866038.0,42856545.0,42802489.0,42880127.0,42753568.0,42698590.0,42709350.0,42914319.0,42854769.0,42943595.0,42968091.0,42906122.0,43332487.0,43142359.0,43147381.0,43213352.0,43360497.0,43242712.0,43236996.0,43322172.0,43404602.0,43499227.0,43477916.0,45081132.0,44370901.0,43725855.0,43758725.0,43916122.0,43796233.0,43940814.0,43880444.0,43893331.0,44022411.0,86597027.0,88061546.0,87880755.0,87911942.0,88095379.0,88128123.0,87994009.0,88446505.0,88197868.0,88383565.0,88288640.0,88262334.0,88422192.0,88380299.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/tukey.json new file mode 100644 index 0000000000000..9abc035255a71 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/new/tukey.json @@ -0,0 +1 @@ +[-898.0618000799095,225.7492357762958,3222.5786647261766,4346.389700582382] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/MAD.svg new file mode 100644 index 0000000000000..b556c4c931c97 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/MAD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 400 + + + + + 450 + + + + + 500 + + + + + 550 + + + + + 600 + + + + + 650 + + + + + 700 + + + + + 750 + + + + + 800 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/crate 'sharded-slab': MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/SD.svg new file mode 100644 index 0000000000000..00ef0660f9d57 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 0.009 + + + + + 550 + + + + + 600 + + + + + 650 + + + + + 700 + + + + + 750 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/crate 'sharded-slab': SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/index.html b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/index.html new file mode 100644 index 0000000000000..23f7db15653fc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/index.html @@ -0,0 +1,203 @@ + + + + + + allocation/crate 'sharded-slab' - Criterion.rs + + + + +
+

allocation/crate 'sharded-slab'

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope1.8264 us1.9587 us2.0826 us
0.19142790.20343340.1928301
Mean1.4968 us1.6264 us1.7525 us
Std. Dev.557.18 ns656.40 ns740.00 ns
Median1.5140 us1.6434 us1.7985 us
MAD414.08 ns565.98 ns773.82 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/mean.svg new file mode 100644 index 0000000000000..b50c2d30df8c6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 1.5 + + + + + 1.55 + + + + + 1.6 + + + + + 1.65 + + + + + 1.7 + + + + + 1.75 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/crate 'sharded-slab': mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/median.svg new file mode 100644 index 0000000000000..958ea184ec972 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/median.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 1.5 + + + + + 1.55 + + + + + 1.6 + + + + + 1.65 + + + + + 1.7 + + + + + 1.75 + + + + + 1.8 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/crate 'sharded-slab': median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/pdf.svg new file mode 100644 index 0000000000000..266861ee1bf2b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/pdf.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 30 + + + + + 35 + + + + + -0.5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/crate 'sharded-slab' + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + + + + + + + gnuplot_plot_5 + + + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/pdf_small.svg new file mode 100644 index 0000000000000..ea243d42ff3c5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/pdf_small.svg @@ -0,0 +1,219 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + -0.5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/regression.svg new file mode 100644 index 0000000000000..2fb8310a0f693 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/regression.svg @@ -0,0 +1,460 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 90 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 35 + + + + + + + + + + + + + 40 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + allocation/crate 'sharded-slab' + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/regression_small.svg new file mode 100644 index 0000000000000..4fba87100d007 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/regression_small.svg @@ -0,0 +1,438 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 90 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 35 + + + + + + + + + + + + + 40 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/slope.svg new file mode 100644 index 0000000000000..281c81ab48338 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/slope.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 1.8 + + + + + 1.85 + + + + + 1.9 + + + + + 1.95 + + + + + 2 + + + + + 2.05 + + + + + 2.1 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/crate 'sharded-slab': slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/typical.svg new file mode 100644 index 0000000000000..6714716476041 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/crate 'sharded-slab'/report/typical.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 1.8 + + + + + 1.85 + + + + + 1.9 + + + + + 1.95 + + + + + 2 + + + + + 2.05 + + + + + 2.1 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/crate 'sharded-slab': typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/benchmark.json new file mode 100644 index 0000000000000..7a554ffd98a83 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"allocation","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"allocation/linear object poll","directory_name":"allocation/linear object poll","title":"allocation/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/estimates.json new file mode 100644 index 0000000000000..fa514fc17df1f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":207.48618424710895,"upper_bound":274.9978377346224},"point_estimate":237.32258076283742,"standard_error":17.38712895942549},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":181.12662895927602,"upper_bound":221.46591756420878},"point_estimate":199.21546703296704,"standard_error":11.74406011127032},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":57.79184583825081,"upper_bound":97.97321448436739},"point_estimate":81.04764027986674,"standard_error":10.786824525787429},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":223.11241604739817,"upper_bound":255.16714488502774},"point_estimate":238.97663713610166,"standard_error":8.167768342099532},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":81.43192907939797,"upper_bound":259.0706677699497},"point_estimate":173.98006038334458,"standard_error":47.25686527223931}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/raw.csv new file mode 100644 index 0000000000000..3b18f9c4b019c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +allocation,linear object poll,,,,4498.0,ns,40 +allocation,linear object poll,,,,6778.0,ns,80 +allocation,linear object poll,,,,15114.0,ns,120 +allocation,linear object poll,,,,10875.0,ns,160 +allocation,linear object poll,,,,15704.0,ns,200 +allocation,linear object poll,,,,18839.0,ns,240 +allocation,linear object poll,,,,21711.0,ns,280 +allocation,linear object poll,,,,25574.0,ns,320 +allocation,linear object poll,,,,32583.0,ns,360 +allocation,linear object poll,,,,594723.0,ns,400 +allocation,linear object poll,,,,78069.0,ns,440 +allocation,linear object poll,,,,83336.0,ns,480 +allocation,linear object poll,,,,147617.0,ns,520 +allocation,linear object poll,,,,88513.0,ns,560 +allocation,linear object poll,,,,95453.0,ns,600 +allocation,linear object poll,,,,93257.0,ns,640 +allocation,linear object poll,,,,151427.0,ns,680 +allocation,linear object poll,,,,107478.0,ns,720 +allocation,linear object poll,,,,106919.0,ns,760 +allocation,linear object poll,,,,112618.0,ns,800 +allocation,linear object poll,,,,166608.0,ns,840 +allocation,linear object poll,,,,120023.0,ns,880 +allocation,linear object poll,,,,128689.0,ns,920 +allocation,linear object poll,,,,128576.0,ns,960 +allocation,linear object poll,,,,184122.0,ns,1000 +allocation,linear object poll,,,,154204.0,ns,1040 +allocation,linear object poll,,,,148472.0,ns,1080 +allocation,linear object poll,,,,318727.0,ns,1120 +allocation,linear object poll,,,,1028061.0,ns,1160 +allocation,linear object poll,,,,327502.0,ns,1200 +allocation,linear object poll,,,,364485.0,ns,1240 +allocation,linear object poll,,,,176150.0,ns,1280 +allocation,linear object poll,,,,1046163.0,ns,1320 +allocation,linear object poll,,,,442982.0,ns,1360 +allocation,linear object poll,,,,631037.0,ns,1400 +allocation,linear object poll,,,,367266.0,ns,1440 +allocation,linear object poll,,,,369135.0,ns,1480 +allocation,linear object poll,,,,441143.0,ns,1520 +allocation,linear object poll,,,,702574.0,ns,1560 +allocation,linear object poll,,,,390723.0,ns,1600 +allocation,linear object poll,,,,699643.0,ns,1640 +allocation,linear object poll,,,,261636.0,ns,1680 +allocation,linear object poll,,,,260618.0,ns,1720 +allocation,linear object poll,,,,243665.0,ns,1760 +allocation,linear object poll,,,,490510.0,ns,1800 +allocation,linear object poll,,,,526959.0,ns,1840 +allocation,linear object poll,,,,355241.0,ns,1880 +allocation,linear object poll,,,,405760.0,ns,1920 +allocation,linear object poll,,,,388642.0,ns,1960 +allocation,linear object poll,,,,364928.0,ns,2000 +allocation,linear object poll,,,,342163.0,ns,2040 +allocation,linear object poll,,,,374564.0,ns,2080 +allocation,linear object poll,,,,438630.0,ns,2120 +allocation,linear object poll,,,,323336.0,ns,2160 +allocation,linear object poll,,,,484578.0,ns,2200 +allocation,linear object poll,,,,368294.0,ns,2240 +allocation,linear object poll,,,,491269.0,ns,2280 +allocation,linear object poll,,,,725526.0,ns,2320 +allocation,linear object poll,,,,836485.0,ns,2360 +allocation,linear object poll,,,,627712.0,ns,2400 +allocation,linear object poll,,,,692882.0,ns,2440 +allocation,linear object poll,,,,634413.0,ns,2480 +allocation,linear object poll,,,,384166.0,ns,2520 +allocation,linear object poll,,,,608904.0,ns,2560 +allocation,linear object poll,,,,520229.0,ns,2600 +allocation,linear object poll,,,,440069.0,ns,2640 +allocation,linear object poll,,,,488164.0,ns,2680 +allocation,linear object poll,,,,418329.0,ns,2720 +allocation,linear object poll,,,,1207909.0,ns,2760 +allocation,linear object poll,,,,391078.0,ns,2800 +allocation,linear object poll,,,,625496.0,ns,2840 +allocation,linear object poll,,,,589472.0,ns,2880 +allocation,linear object poll,,,,596139.0,ns,2920 +allocation,linear object poll,,,,532307.0,ns,2960 +allocation,linear object poll,,,,649155.0,ns,3000 +allocation,linear object poll,,,,585308.0,ns,3040 +allocation,linear object poll,,,,560236.0,ns,3080 +allocation,linear object poll,,,,994469.0,ns,3120 +allocation,linear object poll,,,,554087.0,ns,3160 +allocation,linear object poll,,,,606457.0,ns,3200 +allocation,linear object poll,,,,517551.0,ns,3240 +allocation,linear object poll,,,,582354.0,ns,3280 +allocation,linear object poll,,,,562586.0,ns,3320 +allocation,linear object poll,,,,551578.0,ns,3360 +allocation,linear object poll,,,,619393.0,ns,3400 +allocation,linear object poll,,,,1028871.0,ns,3440 +allocation,linear object poll,,,,1141968.0,ns,3480 +allocation,linear object poll,,,,1122859.0,ns,3520 +allocation,linear object poll,,,,1226791.0,ns,3560 +allocation,linear object poll,,,,1007626.0,ns,3600 +allocation,linear object poll,,,,1034702.0,ns,3640 +allocation,linear object poll,,,,897509.0,ns,3680 +allocation,linear object poll,,,,861374.0,ns,3720 +allocation,linear object poll,,,,819798.0,ns,3760 +allocation,linear object poll,,,,1050607.0,ns,3800 +allocation,linear object poll,,,,1064361.0,ns,3840 +allocation,linear object poll,,,,893979.0,ns,3880 +allocation,linear object poll,,,,930857.0,ns,3920 +allocation,linear object poll,,,,1061321.0,ns,3960 +allocation,linear object poll,,,,1024508.0,ns,4000 diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/sample.json new file mode 100644 index 0000000000000..6c7f137e051bc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[40.0,80.0,120.0,160.0,200.0,240.0,280.0,320.0,360.0,400.0,440.0,480.0,520.0,560.0,600.0,640.0,680.0,720.0,760.0,800.0,840.0,880.0,920.0,960.0,1000.0,1040.0,1080.0,1120.0,1160.0,1200.0,1240.0,1280.0,1320.0,1360.0,1400.0,1440.0,1480.0,1520.0,1560.0,1600.0,1640.0,1680.0,1720.0,1760.0,1800.0,1840.0,1880.0,1920.0,1960.0,2000.0,2040.0,2080.0,2120.0,2160.0,2200.0,2240.0,2280.0,2320.0,2360.0,2400.0,2440.0,2480.0,2520.0,2560.0,2600.0,2640.0,2680.0,2720.0,2760.0,2800.0,2840.0,2880.0,2920.0,2960.0,3000.0,3040.0,3080.0,3120.0,3160.0,3200.0,3240.0,3280.0,3320.0,3360.0,3400.0,3440.0,3480.0,3520.0,3560.0,3600.0,3640.0,3680.0,3720.0,3760.0,3800.0,3840.0,3880.0,3920.0,3960.0,4000.0],"times":[4498.0,6778.0,15114.0,10875.0,15704.0,18839.0,21711.0,25574.0,32583.0,594723.0,78069.0,83336.0,147617.0,88513.0,95453.0,93257.0,151427.0,107478.0,106919.0,112618.0,166608.0,120023.0,128689.0,128576.0,184122.0,154204.0,148472.0,318727.0,1028061.0,327502.0,364485.0,176150.0,1046163.0,442982.0,631037.0,367266.0,369135.0,441143.0,702574.0,390723.0,699643.0,261636.0,260618.0,243665.0,490510.0,526959.0,355241.0,405760.0,388642.0,364928.0,342163.0,374564.0,438630.0,323336.0,484578.0,368294.0,491269.0,725526.0,836485.0,627712.0,692882.0,634413.0,384166.0,608904.0,520229.0,440069.0,488164.0,418329.0,1207909.0,391078.0,625496.0,589472.0,596139.0,532307.0,649155.0,585308.0,560236.0,994469.0,554087.0,606457.0,517551.0,582354.0,562586.0,551578.0,619393.0,1028871.0,1141968.0,1122859.0,1226791.0,1007626.0,1034702.0,897509.0,861374.0,819798.0,1050607.0,1064361.0,893979.0,930857.0,1061321.0,1024508.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/tukey.json new file mode 100644 index 0000000000000..7d4f461b7085a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/base/tukey.json @@ -0,0 +1 @@ +[-200.41832540911105,-22.583591538589133,451.6423654494693,629.4770993199912] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/benchmark.json new file mode 100644 index 0000000000000..7a554ffd98a83 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"allocation","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"allocation/linear object poll","directory_name":"allocation/linear object poll","title":"allocation/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/estimates.json new file mode 100644 index 0000000000000..fa514fc17df1f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":207.48618424710895,"upper_bound":274.9978377346224},"point_estimate":237.32258076283742,"standard_error":17.38712895942549},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":181.12662895927602,"upper_bound":221.46591756420878},"point_estimate":199.21546703296704,"standard_error":11.74406011127032},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":57.79184583825081,"upper_bound":97.97321448436739},"point_estimate":81.04764027986674,"standard_error":10.786824525787429},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":223.11241604739817,"upper_bound":255.16714488502774},"point_estimate":238.97663713610166,"standard_error":8.167768342099532},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":81.43192907939797,"upper_bound":259.0706677699497},"point_estimate":173.98006038334458,"standard_error":47.25686527223931}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/raw.csv new file mode 100644 index 0000000000000..3b18f9c4b019c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +allocation,linear object poll,,,,4498.0,ns,40 +allocation,linear object poll,,,,6778.0,ns,80 +allocation,linear object poll,,,,15114.0,ns,120 +allocation,linear object poll,,,,10875.0,ns,160 +allocation,linear object poll,,,,15704.0,ns,200 +allocation,linear object poll,,,,18839.0,ns,240 +allocation,linear object poll,,,,21711.0,ns,280 +allocation,linear object poll,,,,25574.0,ns,320 +allocation,linear object poll,,,,32583.0,ns,360 +allocation,linear object poll,,,,594723.0,ns,400 +allocation,linear object poll,,,,78069.0,ns,440 +allocation,linear object poll,,,,83336.0,ns,480 +allocation,linear object poll,,,,147617.0,ns,520 +allocation,linear object poll,,,,88513.0,ns,560 +allocation,linear object poll,,,,95453.0,ns,600 +allocation,linear object poll,,,,93257.0,ns,640 +allocation,linear object poll,,,,151427.0,ns,680 +allocation,linear object poll,,,,107478.0,ns,720 +allocation,linear object poll,,,,106919.0,ns,760 +allocation,linear object poll,,,,112618.0,ns,800 +allocation,linear object poll,,,,166608.0,ns,840 +allocation,linear object poll,,,,120023.0,ns,880 +allocation,linear object poll,,,,128689.0,ns,920 +allocation,linear object poll,,,,128576.0,ns,960 +allocation,linear object poll,,,,184122.0,ns,1000 +allocation,linear object poll,,,,154204.0,ns,1040 +allocation,linear object poll,,,,148472.0,ns,1080 +allocation,linear object poll,,,,318727.0,ns,1120 +allocation,linear object poll,,,,1028061.0,ns,1160 +allocation,linear object poll,,,,327502.0,ns,1200 +allocation,linear object poll,,,,364485.0,ns,1240 +allocation,linear object poll,,,,176150.0,ns,1280 +allocation,linear object poll,,,,1046163.0,ns,1320 +allocation,linear object poll,,,,442982.0,ns,1360 +allocation,linear object poll,,,,631037.0,ns,1400 +allocation,linear object poll,,,,367266.0,ns,1440 +allocation,linear object poll,,,,369135.0,ns,1480 +allocation,linear object poll,,,,441143.0,ns,1520 +allocation,linear object poll,,,,702574.0,ns,1560 +allocation,linear object poll,,,,390723.0,ns,1600 +allocation,linear object poll,,,,699643.0,ns,1640 +allocation,linear object poll,,,,261636.0,ns,1680 +allocation,linear object poll,,,,260618.0,ns,1720 +allocation,linear object poll,,,,243665.0,ns,1760 +allocation,linear object poll,,,,490510.0,ns,1800 +allocation,linear object poll,,,,526959.0,ns,1840 +allocation,linear object poll,,,,355241.0,ns,1880 +allocation,linear object poll,,,,405760.0,ns,1920 +allocation,linear object poll,,,,388642.0,ns,1960 +allocation,linear object poll,,,,364928.0,ns,2000 +allocation,linear object poll,,,,342163.0,ns,2040 +allocation,linear object poll,,,,374564.0,ns,2080 +allocation,linear object poll,,,,438630.0,ns,2120 +allocation,linear object poll,,,,323336.0,ns,2160 +allocation,linear object poll,,,,484578.0,ns,2200 +allocation,linear object poll,,,,368294.0,ns,2240 +allocation,linear object poll,,,,491269.0,ns,2280 +allocation,linear object poll,,,,725526.0,ns,2320 +allocation,linear object poll,,,,836485.0,ns,2360 +allocation,linear object poll,,,,627712.0,ns,2400 +allocation,linear object poll,,,,692882.0,ns,2440 +allocation,linear object poll,,,,634413.0,ns,2480 +allocation,linear object poll,,,,384166.0,ns,2520 +allocation,linear object poll,,,,608904.0,ns,2560 +allocation,linear object poll,,,,520229.0,ns,2600 +allocation,linear object poll,,,,440069.0,ns,2640 +allocation,linear object poll,,,,488164.0,ns,2680 +allocation,linear object poll,,,,418329.0,ns,2720 +allocation,linear object poll,,,,1207909.0,ns,2760 +allocation,linear object poll,,,,391078.0,ns,2800 +allocation,linear object poll,,,,625496.0,ns,2840 +allocation,linear object poll,,,,589472.0,ns,2880 +allocation,linear object poll,,,,596139.0,ns,2920 +allocation,linear object poll,,,,532307.0,ns,2960 +allocation,linear object poll,,,,649155.0,ns,3000 +allocation,linear object poll,,,,585308.0,ns,3040 +allocation,linear object poll,,,,560236.0,ns,3080 +allocation,linear object poll,,,,994469.0,ns,3120 +allocation,linear object poll,,,,554087.0,ns,3160 +allocation,linear object poll,,,,606457.0,ns,3200 +allocation,linear object poll,,,,517551.0,ns,3240 +allocation,linear object poll,,,,582354.0,ns,3280 +allocation,linear object poll,,,,562586.0,ns,3320 +allocation,linear object poll,,,,551578.0,ns,3360 +allocation,linear object poll,,,,619393.0,ns,3400 +allocation,linear object poll,,,,1028871.0,ns,3440 +allocation,linear object poll,,,,1141968.0,ns,3480 +allocation,linear object poll,,,,1122859.0,ns,3520 +allocation,linear object poll,,,,1226791.0,ns,3560 +allocation,linear object poll,,,,1007626.0,ns,3600 +allocation,linear object poll,,,,1034702.0,ns,3640 +allocation,linear object poll,,,,897509.0,ns,3680 +allocation,linear object poll,,,,861374.0,ns,3720 +allocation,linear object poll,,,,819798.0,ns,3760 +allocation,linear object poll,,,,1050607.0,ns,3800 +allocation,linear object poll,,,,1064361.0,ns,3840 +allocation,linear object poll,,,,893979.0,ns,3880 +allocation,linear object poll,,,,930857.0,ns,3920 +allocation,linear object poll,,,,1061321.0,ns,3960 +allocation,linear object poll,,,,1024508.0,ns,4000 diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/sample.json new file mode 100644 index 0000000000000..6c7f137e051bc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[40.0,80.0,120.0,160.0,200.0,240.0,280.0,320.0,360.0,400.0,440.0,480.0,520.0,560.0,600.0,640.0,680.0,720.0,760.0,800.0,840.0,880.0,920.0,960.0,1000.0,1040.0,1080.0,1120.0,1160.0,1200.0,1240.0,1280.0,1320.0,1360.0,1400.0,1440.0,1480.0,1520.0,1560.0,1600.0,1640.0,1680.0,1720.0,1760.0,1800.0,1840.0,1880.0,1920.0,1960.0,2000.0,2040.0,2080.0,2120.0,2160.0,2200.0,2240.0,2280.0,2320.0,2360.0,2400.0,2440.0,2480.0,2520.0,2560.0,2600.0,2640.0,2680.0,2720.0,2760.0,2800.0,2840.0,2880.0,2920.0,2960.0,3000.0,3040.0,3080.0,3120.0,3160.0,3200.0,3240.0,3280.0,3320.0,3360.0,3400.0,3440.0,3480.0,3520.0,3560.0,3600.0,3640.0,3680.0,3720.0,3760.0,3800.0,3840.0,3880.0,3920.0,3960.0,4000.0],"times":[4498.0,6778.0,15114.0,10875.0,15704.0,18839.0,21711.0,25574.0,32583.0,594723.0,78069.0,83336.0,147617.0,88513.0,95453.0,93257.0,151427.0,107478.0,106919.0,112618.0,166608.0,120023.0,128689.0,128576.0,184122.0,154204.0,148472.0,318727.0,1028061.0,327502.0,364485.0,176150.0,1046163.0,442982.0,631037.0,367266.0,369135.0,441143.0,702574.0,390723.0,699643.0,261636.0,260618.0,243665.0,490510.0,526959.0,355241.0,405760.0,388642.0,364928.0,342163.0,374564.0,438630.0,323336.0,484578.0,368294.0,491269.0,725526.0,836485.0,627712.0,692882.0,634413.0,384166.0,608904.0,520229.0,440069.0,488164.0,418329.0,1207909.0,391078.0,625496.0,589472.0,596139.0,532307.0,649155.0,585308.0,560236.0,994469.0,554087.0,606457.0,517551.0,582354.0,562586.0,551578.0,619393.0,1028871.0,1141968.0,1122859.0,1226791.0,1007626.0,1034702.0,897509.0,861374.0,819798.0,1050607.0,1064361.0,893979.0,930857.0,1061321.0,1024508.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/tukey.json new file mode 100644 index 0000000000000..7d4f461b7085a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/new/tukey.json @@ -0,0 +1 @@ +[-200.41832540911105,-22.583591538589133,451.6423654494693,629.4770993199912] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/MAD.svg new file mode 100644 index 0000000000000..da5134e0f1892 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/MAD.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 0.04 + + + + + 55 + + + + + 60 + + + + + 65 + + + + + 70 + + + + + 75 + + + + + 80 + + + + + 85 + + + + + 90 + + + + + 95 + + + + + 100 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/linear object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/SD.svg new file mode 100644 index 0000000000000..69bf668224895 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 0.009 + + + + + 0.01 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 250 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/linear object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/index.html new file mode 100644 index 0000000000000..2b2b57a0ecbbd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + allocation/linear object poll - Criterion.rs + + + + +
+

allocation/linear object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope223.11 ns238.98 ns255.17 ns
0.07142380.07389780.0713245
Mean207.49 ns237.32 ns275.00 ns
Std. Dev.81.432 ns173.98 ns259.07 ns
Median181.13 ns199.22 ns221.47 ns
MAD57.792 ns81.048 ns97.973 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/mean.svg new file mode 100644 index 0000000000000..ae6ce92644a1a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/mean.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 200 + + + + + 210 + + + + + 220 + + + + + 230 + + + + + 240 + + + + + 250 + + + + + 260 + + + + + 270 + + + + + 280 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/linear object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/median.svg new file mode 100644 index 0000000000000..63eee3308d068 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/median.svg @@ -0,0 +1,328 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 0.04 + + + + + 0.045 + + + + + 0.05 + + + + + 180 + + + + + 185 + + + + + 190 + + + + + 195 + + + + + 200 + + + + + 205 + + + + + 210 + + + + + 215 + + + + + 220 + + + + + 225 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/linear object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/pdf.svg new file mode 100644 index 0000000000000..5c75489c74953 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/pdf.svg @@ -0,0 +1,440 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 4 + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 4 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/linear object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + gnuplot_plot_5 + + + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..4d36fb4a88141 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/pdf_small.svg @@ -0,0 +1,234 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 4 + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/regression.svg new file mode 100644 index 0000000000000..094a7e320eeb0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/regression.svg @@ -0,0 +1,434 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.2 + + + + + + + + + + + + + 0.4 + + + + + + + + + + + + + 0.6 + + + + + + + + + + + + + 0.8 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.2 + + + + + + + + + + + + + 1.4 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.5 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 2.5 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 3.5 + + + + + + + + + + + + + 4 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + allocation/linear object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/regression_small.svg new file mode 100644 index 0000000000000..a12ae0e55e7f7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/regression_small.svg @@ -0,0 +1,412 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.2 + + + + + + + + + + + + + 0.4 + + + + + + + + + + + + + 0.6 + + + + + + + + + + + + + 0.8 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.2 + + + + + + + + + + + + + 1.4 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.5 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 2.5 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 3.5 + + + + + + + + + + + + + 4 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/slope.svg new file mode 100644 index 0000000000000..bab8384d56f9d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/slope.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 0.04 + + + + + 0.045 + + + + + 0.05 + + + + + 220 + + + + + 225 + + + + + 230 + + + + + 235 + + + + + 240 + + + + + 245 + + + + + 250 + + + + + 255 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/linear object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/typical.svg new file mode 100644 index 0000000000000..9992d85b9d130 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/linear object poll/report/typical.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 0.04 + + + + + 0.045 + + + + + 0.05 + + + + + 220 + + + + + 225 + + + + + 230 + + + + + 235 + + + + + 240 + + + + + 245 + + + + + 250 + + + + + 255 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/linear object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/benchmark.json new file mode 100644 index 0000000000000..0ad79ef97faba --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"allocation","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"allocation/mutex object poll","directory_name":"allocation/mutex object poll","title":"allocation/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/estimates.json new file mode 100644 index 0000000000000..97efa075676aa --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1278.8214619561384,"upper_bound":1335.4732170787388},"point_estimate":1310.7322053778346,"standard_error":14.495267655135489},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1337.3080527318932,"upper_bound":1345.3312029433519},"point_estimate":1342.0825768979703,"standard_error":2.24893141453879},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":10.261758328157693,"upper_bound":21.638223658270782},"point_estimate":16.246509687848004,"standard_error":3.1595485600080857},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1345.6863992501521,"upper_bound":1348.9786472714407},"point_estimate":1347.4581216979252,"standard_error":0.8366165147872252},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":24.96986321583388,"upper_bound":216.32316519664033},"point_estimate":145.39681962609066,"standard_error":44.856325708645294}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/raw.csv new file mode 100644 index 0000000000000..0c9c61314f25f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +allocation,mutex object poll,,,,925550.0,ns,787 +allocation,mutex object poll,,,,1072457.0,ns,1574 +allocation,mutex object poll,,,,1131596.0,ns,2361 +allocation,mutex object poll,,,,1165508.0,ns,3148 +allocation,mutex object poll,,,,5051538.0,ns,3935 +allocation,mutex object poll,,,,6591049.0,ns,4722 +allocation,mutex object poll,,,,7197485.0,ns,5509 +allocation,mutex object poll,,,,8715876.0,ns,6296 +allocation,mutex object poll,,,,9198545.0,ns,7083 +allocation,mutex object poll,,,,10193439.0,ns,7870 +allocation,mutex object poll,,,,11352848.0,ns,8657 +allocation,mutex object poll,,,,12285019.0,ns,9444 +allocation,mutex object poll,,,,13325663.0,ns,10231 +allocation,mutex object poll,,,,14354950.0,ns,11018 +allocation,mutex object poll,,,,15379613.0,ns,11805 +allocation,mutex object poll,,,,16395229.0,ns,12592 +allocation,mutex object poll,,,,17445551.0,ns,13379 +allocation,mutex object poll,,,,18495344.0,ns,14166 +allocation,mutex object poll,,,,19543855.0,ns,14953 +allocation,mutex object poll,,,,20573402.0,ns,15740 +allocation,mutex object poll,,,,21755087.0,ns,16527 +allocation,mutex object poll,,,,23083456.0,ns,17314 +allocation,mutex object poll,,,,23949828.0,ns,18101 +allocation,mutex object poll,,,,25040313.0,ns,18888 +allocation,mutex object poll,,,,26180626.0,ns,19675 +allocation,mutex object poll,,,,27075078.0,ns,20462 +allocation,mutex object poll,,,,28060558.0,ns,21249 +allocation,mutex object poll,,,,29118634.0,ns,22036 +allocation,mutex object poll,,,,30194085.0,ns,22823 +allocation,mutex object poll,,,,31151186.0,ns,23610 +allocation,mutex object poll,,,,32229637.0,ns,24397 +allocation,mutex object poll,,,,34094656.0,ns,25184 +allocation,mutex object poll,,,,34442869.0,ns,25971 +allocation,mutex object poll,,,,35467536.0,ns,26758 +allocation,mutex object poll,,,,36484068.0,ns,27545 +allocation,mutex object poll,,,,37542560.0,ns,28332 +allocation,mutex object poll,,,,38607392.0,ns,29119 +allocation,mutex object poll,,,,39684258.0,ns,29906 +allocation,mutex object poll,,,,40718410.0,ns,30693 +allocation,mutex object poll,,,,41843443.0,ns,31480 +allocation,mutex object poll,,,,42783462.0,ns,32267 +allocation,mutex object poll,,,,44272015.0,ns,33054 +allocation,mutex object poll,,,,45324328.0,ns,33841 +allocation,mutex object poll,,,,46785473.0,ns,34628 +allocation,mutex object poll,,,,47844857.0,ns,35415 +allocation,mutex object poll,,,,48165127.0,ns,36202 +allocation,mutex object poll,,,,49557023.0,ns,36989 +allocation,mutex object poll,,,,50518149.0,ns,37776 +allocation,mutex object poll,,,,51505726.0,ns,38563 +allocation,mutex object poll,,,,52743520.0,ns,39350 +allocation,mutex object poll,,,,53888030.0,ns,40137 +allocation,mutex object poll,,,,54856265.0,ns,40924 +allocation,mutex object poll,,,,55891588.0,ns,41711 +allocation,mutex object poll,,,,57458726.0,ns,42498 +allocation,mutex object poll,,,,58211195.0,ns,43285 +allocation,mutex object poll,,,,59137006.0,ns,44072 +allocation,mutex object poll,,,,60134767.0,ns,44859 +allocation,mutex object poll,,,,61268856.0,ns,45646 +allocation,mutex object poll,,,,62308625.0,ns,46433 +allocation,mutex object poll,,,,63633776.0,ns,47220 +allocation,mutex object poll,,,,64538654.0,ns,48007 +allocation,mutex object poll,,,,66217126.0,ns,48794 +allocation,mutex object poll,,,,66882477.0,ns,49581 +allocation,mutex object poll,,,,67648334.0,ns,50368 +allocation,mutex object poll,,,,68862240.0,ns,51155 +allocation,mutex object poll,,,,69934502.0,ns,51942 +allocation,mutex object poll,,,,70937969.0,ns,52729 +allocation,mutex object poll,,,,72055588.0,ns,53516 +allocation,mutex object poll,,,,73407965.0,ns,54303 +allocation,mutex object poll,,,,74577899.0,ns,55090 +allocation,mutex object poll,,,,75410940.0,ns,55877 +allocation,mutex object poll,,,,76426771.0,ns,56664 +allocation,mutex object poll,,,,77212985.0,ns,57451 +allocation,mutex object poll,,,,78482633.0,ns,58238 +allocation,mutex object poll,,,,79658118.0,ns,59025 +allocation,mutex object poll,,,,81469628.0,ns,59812 +allocation,mutex object poll,,,,81650447.0,ns,60599 +allocation,mutex object poll,,,,82767540.0,ns,61386 +allocation,mutex object poll,,,,83670373.0,ns,62173 +allocation,mutex object poll,,,,84581874.0,ns,62960 +allocation,mutex object poll,,,,85730833.0,ns,63747 +allocation,mutex object poll,,,,87704798.0,ns,64534 +allocation,mutex object poll,,,,87856681.0,ns,65321 +allocation,mutex object poll,,,,89413583.0,ns,66108 +allocation,mutex object poll,,,,90591196.0,ns,66895 +allocation,mutex object poll,,,,91496513.0,ns,67682 +allocation,mutex object poll,,,,93026790.0,ns,68469 +allocation,mutex object poll,,,,94030999.0,ns,69256 +allocation,mutex object poll,,,,94630557.0,ns,70043 +allocation,mutex object poll,,,,95802581.0,ns,70830 +allocation,mutex object poll,,,,96820204.0,ns,71617 +allocation,mutex object poll,,,,98346567.0,ns,72404 +allocation,mutex object poll,,,,99189061.0,ns,73191 +allocation,mutex object poll,,,,99801058.0,ns,73978 +allocation,mutex object poll,,,,100725454.0,ns,74765 +allocation,mutex object poll,,,,101839314.0,ns,75552 +allocation,mutex object poll,,,,103095866.0,ns,76339 +allocation,mutex object poll,,,,104250593.0,ns,77126 +allocation,mutex object poll,,,,105371001.0,ns,77913 +allocation,mutex object poll,,,,106130321.0,ns,78700 diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/sample.json new file mode 100644 index 0000000000000..287b944f7c3d9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[787.0,1574.0,2361.0,3148.0,3935.0,4722.0,5509.0,6296.0,7083.0,7870.0,8657.0,9444.0,10231.0,11018.0,11805.0,12592.0,13379.0,14166.0,14953.0,15740.0,16527.0,17314.0,18101.0,18888.0,19675.0,20462.0,21249.0,22036.0,22823.0,23610.0,24397.0,25184.0,25971.0,26758.0,27545.0,28332.0,29119.0,29906.0,30693.0,31480.0,32267.0,33054.0,33841.0,34628.0,35415.0,36202.0,36989.0,37776.0,38563.0,39350.0,40137.0,40924.0,41711.0,42498.0,43285.0,44072.0,44859.0,45646.0,46433.0,47220.0,48007.0,48794.0,49581.0,50368.0,51155.0,51942.0,52729.0,53516.0,54303.0,55090.0,55877.0,56664.0,57451.0,58238.0,59025.0,59812.0,60599.0,61386.0,62173.0,62960.0,63747.0,64534.0,65321.0,66108.0,66895.0,67682.0,68469.0,69256.0,70043.0,70830.0,71617.0,72404.0,73191.0,73978.0,74765.0,75552.0,76339.0,77126.0,77913.0,78700.0],"times":[925550.0,1072457.0,1131596.0,1165508.0,5051538.0,6591049.0,7197485.0,8715876.0,9198545.0,10193439.0,11352848.0,12285019.0,13325663.0,14354950.0,15379613.0,16395229.0,17445551.0,18495344.0,19543855.0,20573402.0,21755087.0,23083456.0,23949828.0,25040313.0,26180626.0,27075078.0,28060558.0,29118634.0,30194085.0,31151186.0,32229637.0,34094656.0,34442869.0,35467536.0,36484068.0,37542560.0,38607392.0,39684258.0,40718410.0,41843443.0,42783462.0,44272015.0,45324328.0,46785473.0,47844857.0,48165127.0,49557023.0,50518149.0,51505726.0,52743520.0,53888030.0,54856265.0,55891588.0,57458726.0,58211195.0,59137006.0,60134767.0,61268856.0,62308625.0,63633776.0,64538654.0,66217126.0,66882477.0,67648334.0,68862240.0,69934502.0,70937969.0,72055588.0,73407965.0,74577899.0,75410940.0,76426771.0,77212985.0,78482633.0,79658118.0,81469628.0,81650447.0,82767540.0,83670373.0,84581874.0,85730833.0,87704798.0,87856681.0,89413583.0,90591196.0,91496513.0,93026790.0,94030999.0,94630557.0,95802581.0,96820204.0,98346567.0,99189061.0,99801058.0,100725454.0,101839314.0,103095866.0,104250593.0,105371001.0,106130321.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/tukey.json new file mode 100644 index 0000000000000..2180219c4944c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/base/tukey.json @@ -0,0 +1 @@ +[1243.9724961676757,1283.572069415426,1389.1709314094269,1428.770504657177] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/benchmark.json new file mode 100644 index 0000000000000..0ad79ef97faba --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"allocation","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"allocation/mutex object poll","directory_name":"allocation/mutex object poll","title":"allocation/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/estimates.json new file mode 100644 index 0000000000000..97efa075676aa --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1278.8214619561384,"upper_bound":1335.4732170787388},"point_estimate":1310.7322053778346,"standard_error":14.495267655135489},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1337.3080527318932,"upper_bound":1345.3312029433519},"point_estimate":1342.0825768979703,"standard_error":2.24893141453879},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":10.261758328157693,"upper_bound":21.638223658270782},"point_estimate":16.246509687848004,"standard_error":3.1595485600080857},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1345.6863992501521,"upper_bound":1348.9786472714407},"point_estimate":1347.4581216979252,"standard_error":0.8366165147872252},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":24.96986321583388,"upper_bound":216.32316519664033},"point_estimate":145.39681962609066,"standard_error":44.856325708645294}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/raw.csv new file mode 100644 index 0000000000000..0c9c61314f25f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +allocation,mutex object poll,,,,925550.0,ns,787 +allocation,mutex object poll,,,,1072457.0,ns,1574 +allocation,mutex object poll,,,,1131596.0,ns,2361 +allocation,mutex object poll,,,,1165508.0,ns,3148 +allocation,mutex object poll,,,,5051538.0,ns,3935 +allocation,mutex object poll,,,,6591049.0,ns,4722 +allocation,mutex object poll,,,,7197485.0,ns,5509 +allocation,mutex object poll,,,,8715876.0,ns,6296 +allocation,mutex object poll,,,,9198545.0,ns,7083 +allocation,mutex object poll,,,,10193439.0,ns,7870 +allocation,mutex object poll,,,,11352848.0,ns,8657 +allocation,mutex object poll,,,,12285019.0,ns,9444 +allocation,mutex object poll,,,,13325663.0,ns,10231 +allocation,mutex object poll,,,,14354950.0,ns,11018 +allocation,mutex object poll,,,,15379613.0,ns,11805 +allocation,mutex object poll,,,,16395229.0,ns,12592 +allocation,mutex object poll,,,,17445551.0,ns,13379 +allocation,mutex object poll,,,,18495344.0,ns,14166 +allocation,mutex object poll,,,,19543855.0,ns,14953 +allocation,mutex object poll,,,,20573402.0,ns,15740 +allocation,mutex object poll,,,,21755087.0,ns,16527 +allocation,mutex object poll,,,,23083456.0,ns,17314 +allocation,mutex object poll,,,,23949828.0,ns,18101 +allocation,mutex object poll,,,,25040313.0,ns,18888 +allocation,mutex object poll,,,,26180626.0,ns,19675 +allocation,mutex object poll,,,,27075078.0,ns,20462 +allocation,mutex object poll,,,,28060558.0,ns,21249 +allocation,mutex object poll,,,,29118634.0,ns,22036 +allocation,mutex object poll,,,,30194085.0,ns,22823 +allocation,mutex object poll,,,,31151186.0,ns,23610 +allocation,mutex object poll,,,,32229637.0,ns,24397 +allocation,mutex object poll,,,,34094656.0,ns,25184 +allocation,mutex object poll,,,,34442869.0,ns,25971 +allocation,mutex object poll,,,,35467536.0,ns,26758 +allocation,mutex object poll,,,,36484068.0,ns,27545 +allocation,mutex object poll,,,,37542560.0,ns,28332 +allocation,mutex object poll,,,,38607392.0,ns,29119 +allocation,mutex object poll,,,,39684258.0,ns,29906 +allocation,mutex object poll,,,,40718410.0,ns,30693 +allocation,mutex object poll,,,,41843443.0,ns,31480 +allocation,mutex object poll,,,,42783462.0,ns,32267 +allocation,mutex object poll,,,,44272015.0,ns,33054 +allocation,mutex object poll,,,,45324328.0,ns,33841 +allocation,mutex object poll,,,,46785473.0,ns,34628 +allocation,mutex object poll,,,,47844857.0,ns,35415 +allocation,mutex object poll,,,,48165127.0,ns,36202 +allocation,mutex object poll,,,,49557023.0,ns,36989 +allocation,mutex object poll,,,,50518149.0,ns,37776 +allocation,mutex object poll,,,,51505726.0,ns,38563 +allocation,mutex object poll,,,,52743520.0,ns,39350 +allocation,mutex object poll,,,,53888030.0,ns,40137 +allocation,mutex object poll,,,,54856265.0,ns,40924 +allocation,mutex object poll,,,,55891588.0,ns,41711 +allocation,mutex object poll,,,,57458726.0,ns,42498 +allocation,mutex object poll,,,,58211195.0,ns,43285 +allocation,mutex object poll,,,,59137006.0,ns,44072 +allocation,mutex object poll,,,,60134767.0,ns,44859 +allocation,mutex object poll,,,,61268856.0,ns,45646 +allocation,mutex object poll,,,,62308625.0,ns,46433 +allocation,mutex object poll,,,,63633776.0,ns,47220 +allocation,mutex object poll,,,,64538654.0,ns,48007 +allocation,mutex object poll,,,,66217126.0,ns,48794 +allocation,mutex object poll,,,,66882477.0,ns,49581 +allocation,mutex object poll,,,,67648334.0,ns,50368 +allocation,mutex object poll,,,,68862240.0,ns,51155 +allocation,mutex object poll,,,,69934502.0,ns,51942 +allocation,mutex object poll,,,,70937969.0,ns,52729 +allocation,mutex object poll,,,,72055588.0,ns,53516 +allocation,mutex object poll,,,,73407965.0,ns,54303 +allocation,mutex object poll,,,,74577899.0,ns,55090 +allocation,mutex object poll,,,,75410940.0,ns,55877 +allocation,mutex object poll,,,,76426771.0,ns,56664 +allocation,mutex object poll,,,,77212985.0,ns,57451 +allocation,mutex object poll,,,,78482633.0,ns,58238 +allocation,mutex object poll,,,,79658118.0,ns,59025 +allocation,mutex object poll,,,,81469628.0,ns,59812 +allocation,mutex object poll,,,,81650447.0,ns,60599 +allocation,mutex object poll,,,,82767540.0,ns,61386 +allocation,mutex object poll,,,,83670373.0,ns,62173 +allocation,mutex object poll,,,,84581874.0,ns,62960 +allocation,mutex object poll,,,,85730833.0,ns,63747 +allocation,mutex object poll,,,,87704798.0,ns,64534 +allocation,mutex object poll,,,,87856681.0,ns,65321 +allocation,mutex object poll,,,,89413583.0,ns,66108 +allocation,mutex object poll,,,,90591196.0,ns,66895 +allocation,mutex object poll,,,,91496513.0,ns,67682 +allocation,mutex object poll,,,,93026790.0,ns,68469 +allocation,mutex object poll,,,,94030999.0,ns,69256 +allocation,mutex object poll,,,,94630557.0,ns,70043 +allocation,mutex object poll,,,,95802581.0,ns,70830 +allocation,mutex object poll,,,,96820204.0,ns,71617 +allocation,mutex object poll,,,,98346567.0,ns,72404 +allocation,mutex object poll,,,,99189061.0,ns,73191 +allocation,mutex object poll,,,,99801058.0,ns,73978 +allocation,mutex object poll,,,,100725454.0,ns,74765 +allocation,mutex object poll,,,,101839314.0,ns,75552 +allocation,mutex object poll,,,,103095866.0,ns,76339 +allocation,mutex object poll,,,,104250593.0,ns,77126 +allocation,mutex object poll,,,,105371001.0,ns,77913 +allocation,mutex object poll,,,,106130321.0,ns,78700 diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/sample.json new file mode 100644 index 0000000000000..287b944f7c3d9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[787.0,1574.0,2361.0,3148.0,3935.0,4722.0,5509.0,6296.0,7083.0,7870.0,8657.0,9444.0,10231.0,11018.0,11805.0,12592.0,13379.0,14166.0,14953.0,15740.0,16527.0,17314.0,18101.0,18888.0,19675.0,20462.0,21249.0,22036.0,22823.0,23610.0,24397.0,25184.0,25971.0,26758.0,27545.0,28332.0,29119.0,29906.0,30693.0,31480.0,32267.0,33054.0,33841.0,34628.0,35415.0,36202.0,36989.0,37776.0,38563.0,39350.0,40137.0,40924.0,41711.0,42498.0,43285.0,44072.0,44859.0,45646.0,46433.0,47220.0,48007.0,48794.0,49581.0,50368.0,51155.0,51942.0,52729.0,53516.0,54303.0,55090.0,55877.0,56664.0,57451.0,58238.0,59025.0,59812.0,60599.0,61386.0,62173.0,62960.0,63747.0,64534.0,65321.0,66108.0,66895.0,67682.0,68469.0,69256.0,70043.0,70830.0,71617.0,72404.0,73191.0,73978.0,74765.0,75552.0,76339.0,77126.0,77913.0,78700.0],"times":[925550.0,1072457.0,1131596.0,1165508.0,5051538.0,6591049.0,7197485.0,8715876.0,9198545.0,10193439.0,11352848.0,12285019.0,13325663.0,14354950.0,15379613.0,16395229.0,17445551.0,18495344.0,19543855.0,20573402.0,21755087.0,23083456.0,23949828.0,25040313.0,26180626.0,27075078.0,28060558.0,29118634.0,30194085.0,31151186.0,32229637.0,34094656.0,34442869.0,35467536.0,36484068.0,37542560.0,38607392.0,39684258.0,40718410.0,41843443.0,42783462.0,44272015.0,45324328.0,46785473.0,47844857.0,48165127.0,49557023.0,50518149.0,51505726.0,52743520.0,53888030.0,54856265.0,55891588.0,57458726.0,58211195.0,59137006.0,60134767.0,61268856.0,62308625.0,63633776.0,64538654.0,66217126.0,66882477.0,67648334.0,68862240.0,69934502.0,70937969.0,72055588.0,73407965.0,74577899.0,75410940.0,76426771.0,77212985.0,78482633.0,79658118.0,81469628.0,81650447.0,82767540.0,83670373.0,84581874.0,85730833.0,87704798.0,87856681.0,89413583.0,90591196.0,91496513.0,93026790.0,94030999.0,94630557.0,95802581.0,96820204.0,98346567.0,99189061.0,99801058.0,100725454.0,101839314.0,103095866.0,104250593.0,105371001.0,106130321.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/tukey.json new file mode 100644 index 0000000000000..2180219c4944c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/new/tukey.json @@ -0,0 +1 @@ +[1243.9724961676757,1283.572069415426,1389.1709314094269,1428.770504657177] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/MAD.svg new file mode 100644 index 0000000000000..85e892d4c40eb --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + 22 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/mutex object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/SD.svg new file mode 100644 index 0000000000000..4ae1e8de30a62 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 0.009 + + + + + 0.01 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/mutex object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/index.html new file mode 100644 index 0000000000000..1c00f41c8e424 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + allocation/mutex object poll - Criterion.rs + + + + +
+

allocation/mutex object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope1.3457 us1.3475 us1.3490 us
0.98870690.98893780.9887677
Mean1.2788 us1.3107 us1.3355 us
Std. Dev.24.970 ns145.40 ns216.32 ns
Median1.3373 us1.3421 us1.3453 us
MAD10.262 ns16.247 ns21.638 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/mean.svg new file mode 100644 index 0000000000000..7d4bc5a0cef84 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 30 + + + + + 1.28 + + + + + 1.29 + + + + + 1.3 + + + + + 1.31 + + + + + 1.32 + + + + + 1.33 + + + + + 1.34 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/mutex object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/median.svg new file mode 100644 index 0000000000000..20ec6607f1f17 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/median.svg @@ -0,0 +1,308 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 250 + + + + + 300 + + + + + 1.337 + + + + + 1.338 + + + + + 1.339 + + + + + 1.34 + + + + + 1.341 + + + + + 1.342 + + + + + 1.343 + + + + + 1.344 + + + + + 1.345 + + + + + 1.346 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/mutex object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/pdf.svg new file mode 100644 index 0000000000000..3d985edb90f4f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/pdf.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 70 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/mutex object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..166f4e6eb9e05 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/pdf_small.svg @@ -0,0 +1,214 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/regression.svg new file mode 100644 index 0000000000000..b69ae129a3f27 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/regression.svg @@ -0,0 +1,421 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 120 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + allocation/mutex object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/regression_small.svg new file mode 100644 index 0000000000000..705c8ff880649 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/regression_small.svg @@ -0,0 +1,399 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 120 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/slope.svg new file mode 100644 index 0000000000000..120ef448e4998 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/slope.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 250 + + + + + 300 + + + + + 350 + + + + + 400 + + + + + 450 + + + + + 500 + + + + + 1.3455 + + + + + 1.346 + + + + + 1.3465 + + + + + 1.347 + + + + + 1.3475 + + + + + 1.348 + + + + + 1.3485 + + + + + 1.349 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/mutex object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/typical.svg new file mode 100644 index 0000000000000..a2effa54a4fdc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/mutex object poll/report/typical.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 250 + + + + + 300 + + + + + 350 + + + + + 400 + + + + + 450 + + + + + 500 + + + + + 1.3455 + + + + + 1.346 + + + + + 1.3465 + + + + + 1.347 + + + + + 1.3475 + + + + + 1.348 + + + + + 1.3485 + + + + + 1.349 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/mutex object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/benchmark.json new file mode 100644 index 0000000000000..238c176e82f7b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"allocation","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"allocation/none object poll","directory_name":"allocation/none object poll","title":"allocation/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/estimates.json new file mode 100644 index 0000000000000..b70dc7e348ee6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1252.657446309189,"upper_bound":1309.8590747719177},"point_estimate":1284.7527849889013,"standard_error":14.724189275166431},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1304.6709628082479,"upper_bound":1319.5590027391133},"point_estimate":1314.7342871559879,"standard_error":3.7010682927049894},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":19.588523773398606,"upper_bound":36.10284620957007},"point_estimate":28.78799235393434,"standard_error":3.991603921145015},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1323.3150835782267,"upper_bound":1330.8589459629563},"point_estimate":1327.0664432279216,"standard_error":1.9232954458298013},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":27.34346905538246,"upper_bound":218.2974988200446},"point_estimate":147.56441583286133,"standard_error":45.073173782308494}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/raw.csv new file mode 100644 index 0000000000000..9042a4404ff7f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +allocation,none object poll,,,,977917.0,ns,801 +allocation,none object poll,,,,1019213.0,ns,1602 +allocation,none object poll,,,,1061550.0,ns,2403 +allocation,none object poll,,,,1093531.0,ns,3204 +allocation,none object poll,,,,5106026.0,ns,4005 +allocation,none object poll,,,,6107590.0,ns,4806 +allocation,none object poll,,,,7062882.0,ns,5607 +allocation,none object poll,,,,8256566.0,ns,6408 +allocation,none object poll,,,,9162611.0,ns,7209 +allocation,none object poll,,,,10196611.0,ns,8010 +allocation,none object poll,,,,11276872.0,ns,8811 +allocation,none object poll,,,,12173877.0,ns,9612 +allocation,none object poll,,,,13234583.0,ns,10413 +allocation,none object poll,,,,14245720.0,ns,11214 +allocation,none object poll,,,,15243402.0,ns,12015 +allocation,none object poll,,,,16310041.0,ns,12816 +allocation,none object poll,,,,17324266.0,ns,13617 +allocation,none object poll,,,,18334767.0,ns,14418 +allocation,none object poll,,,,19390633.0,ns,15219 +allocation,none object poll,,,,20411973.0,ns,16020 +allocation,none object poll,,,,21547530.0,ns,16821 +allocation,none object poll,,,,22641969.0,ns,17622 +allocation,none object poll,,,,23638377.0,ns,18423 +allocation,none object poll,,,,24663813.0,ns,19224 +allocation,none object poll,,,,25709883.0,ns,20025 +allocation,none object poll,,,,26720937.0,ns,20826 +allocation,none object poll,,,,27844332.0,ns,21627 +allocation,none object poll,,,,28858750.0,ns,22428 +allocation,none object poll,,,,29920441.0,ns,23229 +allocation,none object poll,,,,30971442.0,ns,24030 +allocation,none object poll,,,,32098756.0,ns,24831 +allocation,none object poll,,,,33200387.0,ns,25632 +allocation,none object poll,,,,34498255.0,ns,26433 +allocation,none object poll,,,,35277918.0,ns,27234 +allocation,none object poll,,,,36337705.0,ns,28035 +allocation,none object poll,,,,37312874.0,ns,28836 +allocation,none object poll,,,,38475546.0,ns,29637 +allocation,none object poll,,,,39537900.0,ns,30438 +allocation,none object poll,,,,40272315.0,ns,31239 +allocation,none object poll,,,,41573327.0,ns,32040 +allocation,none object poll,,,,43174912.0,ns,32841 +allocation,none object poll,,,,44175320.0,ns,33642 +allocation,none object poll,,,,45180962.0,ns,34443 +allocation,none object poll,,,,46204482.0,ns,35244 +allocation,none object poll,,,,47697792.0,ns,36045 +allocation,none object poll,,,,48466142.0,ns,36846 +allocation,none object poll,,,,49331756.0,ns,37647 +allocation,none object poll,,,,50406766.0,ns,38448 +allocation,none object poll,,,,51604727.0,ns,39249 +allocation,none object poll,,,,52742526.0,ns,40050 +allocation,none object poll,,,,53691819.0,ns,40851 +allocation,none object poll,,,,54856819.0,ns,41652 +allocation,none object poll,,,,55929468.0,ns,42453 +allocation,none object poll,,,,57167532.0,ns,43254 +allocation,none object poll,,,,58149766.0,ns,44055 +allocation,none object poll,,,,61358098.0,ns,44856 +allocation,none object poll,,,,60616095.0,ns,45657 +allocation,none object poll,,,,61448922.0,ns,46458 +allocation,none object poll,,,,62473599.0,ns,47259 +allocation,none object poll,,,,63431458.0,ns,48060 +allocation,none object poll,,,,64442030.0,ns,48861 +allocation,none object poll,,,,65496093.0,ns,49662 +allocation,none object poll,,,,67151329.0,ns,50463 +allocation,none object poll,,,,67781948.0,ns,51264 +allocation,none object poll,,,,67715787.0,ns,52065 +allocation,none object poll,,,,69768511.0,ns,52866 +allocation,none object poll,,,,70816773.0,ns,53667 +allocation,none object poll,,,,72771991.0,ns,54468 +allocation,none object poll,,,,73319912.0,ns,55269 +allocation,none object poll,,,,74634688.0,ns,56070 +allocation,none object poll,,,,74311721.0,ns,56871 +allocation,none object poll,,,,80690801.0,ns,57672 +allocation,none object poll,,,,79364902.0,ns,58473 +allocation,none object poll,,,,80029980.0,ns,59274 +allocation,none object poll,,,,80122262.0,ns,60075 +allocation,none object poll,,,,81059148.0,ns,60876 +allocation,none object poll,,,,82521070.0,ns,61677 +allocation,none object poll,,,,83444327.0,ns,62478 +allocation,none object poll,,,,85500256.0,ns,63279 +allocation,none object poll,,,,85780189.0,ns,64080 +allocation,none object poll,,,,86570561.0,ns,64881 +allocation,none object poll,,,,88459575.0,ns,65682 +allocation,none object poll,,,,89192720.0,ns,66483 +allocation,none object poll,,,,90098108.0,ns,67284 +allocation,none object poll,,,,91099802.0,ns,68085 +allocation,none object poll,,,,92338183.0,ns,68886 +allocation,none object poll,,,,92177435.0,ns,69687 +allocation,none object poll,,,,94993214.0,ns,70488 +allocation,none object poll,,,,94003940.0,ns,71289 +allocation,none object poll,,,,95109334.0,ns,72090 +allocation,none object poll,,,,96899556.0,ns,72891 +allocation,none object poll,,,,97880090.0,ns,73692 +allocation,none object poll,,,,99111727.0,ns,74493 +allocation,none object poll,,,,99848320.0,ns,75294 +allocation,none object poll,,,,101042878.0,ns,76095 +allocation,none object poll,,,,101881212.0,ns,76896 +allocation,none object poll,,,,102543089.0,ns,77697 +allocation,none object poll,,,,104497346.0,ns,78498 +allocation,none object poll,,,,105014652.0,ns,79299 +allocation,none object poll,,,,105247453.0,ns,80100 diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/sample.json new file mode 100644 index 0000000000000..e90729a1851fc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[801.0,1602.0,2403.0,3204.0,4005.0,4806.0,5607.0,6408.0,7209.0,8010.0,8811.0,9612.0,10413.0,11214.0,12015.0,12816.0,13617.0,14418.0,15219.0,16020.0,16821.0,17622.0,18423.0,19224.0,20025.0,20826.0,21627.0,22428.0,23229.0,24030.0,24831.0,25632.0,26433.0,27234.0,28035.0,28836.0,29637.0,30438.0,31239.0,32040.0,32841.0,33642.0,34443.0,35244.0,36045.0,36846.0,37647.0,38448.0,39249.0,40050.0,40851.0,41652.0,42453.0,43254.0,44055.0,44856.0,45657.0,46458.0,47259.0,48060.0,48861.0,49662.0,50463.0,51264.0,52065.0,52866.0,53667.0,54468.0,55269.0,56070.0,56871.0,57672.0,58473.0,59274.0,60075.0,60876.0,61677.0,62478.0,63279.0,64080.0,64881.0,65682.0,66483.0,67284.0,68085.0,68886.0,69687.0,70488.0,71289.0,72090.0,72891.0,73692.0,74493.0,75294.0,76095.0,76896.0,77697.0,78498.0,79299.0,80100.0],"times":[977917.0,1019213.0,1061550.0,1093531.0,5106026.0,6107590.0,7062882.0,8256566.0,9162611.0,10196611.0,11276872.0,12173877.0,13234583.0,14245720.0,15243402.0,16310041.0,17324266.0,18334767.0,19390633.0,20411973.0,21547530.0,22641969.0,23638377.0,24663813.0,25709883.0,26720937.0,27844332.0,28858750.0,29920441.0,30971442.0,32098756.0,33200387.0,34498255.0,35277918.0,36337705.0,37312874.0,38475546.0,39537900.0,40272315.0,41573327.0,43174912.0,44175320.0,45180962.0,46204482.0,47697792.0,48466142.0,49331756.0,50406766.0,51604727.0,52742526.0,53691819.0,54856819.0,55929468.0,57167532.0,58149766.0,61358098.0,60616095.0,61448922.0,62473599.0,63431458.0,64442030.0,65496093.0,67151329.0,67781948.0,67715787.0,69768511.0,70816773.0,72771991.0,73319912.0,74634688.0,74311721.0,80690801.0,79364902.0,80029980.0,80122262.0,81059148.0,82521070.0,83444327.0,85500256.0,85780189.0,86570561.0,88459575.0,89192720.0,90098108.0,91099802.0,92338183.0,92177435.0,94993214.0,94003940.0,95109334.0,96899556.0,97880090.0,99111727.0,99848320.0,101042878.0,101881212.0,102543089.0,104497346.0,105014652.0,105247453.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/tukey.json new file mode 100644 index 0000000000000..a44007b8c9dd7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/base/tukey.json @@ -0,0 +1 @@ +[1161.974798973942,1224.1193185978227,1389.8380375948382,1451.982557218719] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/benchmark.json new file mode 100644 index 0000000000000..238c176e82f7b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"allocation","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"allocation/none object poll","directory_name":"allocation/none object poll","title":"allocation/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/estimates.json new file mode 100644 index 0000000000000..b70dc7e348ee6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1252.657446309189,"upper_bound":1309.8590747719177},"point_estimate":1284.7527849889013,"standard_error":14.724189275166431},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1304.6709628082479,"upper_bound":1319.5590027391133},"point_estimate":1314.7342871559879,"standard_error":3.7010682927049894},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":19.588523773398606,"upper_bound":36.10284620957007},"point_estimate":28.78799235393434,"standard_error":3.991603921145015},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1323.3150835782267,"upper_bound":1330.8589459629563},"point_estimate":1327.0664432279216,"standard_error":1.9232954458298013},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":27.34346905538246,"upper_bound":218.2974988200446},"point_estimate":147.56441583286133,"standard_error":45.073173782308494}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/raw.csv new file mode 100644 index 0000000000000..9042a4404ff7f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +allocation,none object poll,,,,977917.0,ns,801 +allocation,none object poll,,,,1019213.0,ns,1602 +allocation,none object poll,,,,1061550.0,ns,2403 +allocation,none object poll,,,,1093531.0,ns,3204 +allocation,none object poll,,,,5106026.0,ns,4005 +allocation,none object poll,,,,6107590.0,ns,4806 +allocation,none object poll,,,,7062882.0,ns,5607 +allocation,none object poll,,,,8256566.0,ns,6408 +allocation,none object poll,,,,9162611.0,ns,7209 +allocation,none object poll,,,,10196611.0,ns,8010 +allocation,none object poll,,,,11276872.0,ns,8811 +allocation,none object poll,,,,12173877.0,ns,9612 +allocation,none object poll,,,,13234583.0,ns,10413 +allocation,none object poll,,,,14245720.0,ns,11214 +allocation,none object poll,,,,15243402.0,ns,12015 +allocation,none object poll,,,,16310041.0,ns,12816 +allocation,none object poll,,,,17324266.0,ns,13617 +allocation,none object poll,,,,18334767.0,ns,14418 +allocation,none object poll,,,,19390633.0,ns,15219 +allocation,none object poll,,,,20411973.0,ns,16020 +allocation,none object poll,,,,21547530.0,ns,16821 +allocation,none object poll,,,,22641969.0,ns,17622 +allocation,none object poll,,,,23638377.0,ns,18423 +allocation,none object poll,,,,24663813.0,ns,19224 +allocation,none object poll,,,,25709883.0,ns,20025 +allocation,none object poll,,,,26720937.0,ns,20826 +allocation,none object poll,,,,27844332.0,ns,21627 +allocation,none object poll,,,,28858750.0,ns,22428 +allocation,none object poll,,,,29920441.0,ns,23229 +allocation,none object poll,,,,30971442.0,ns,24030 +allocation,none object poll,,,,32098756.0,ns,24831 +allocation,none object poll,,,,33200387.0,ns,25632 +allocation,none object poll,,,,34498255.0,ns,26433 +allocation,none object poll,,,,35277918.0,ns,27234 +allocation,none object poll,,,,36337705.0,ns,28035 +allocation,none object poll,,,,37312874.0,ns,28836 +allocation,none object poll,,,,38475546.0,ns,29637 +allocation,none object poll,,,,39537900.0,ns,30438 +allocation,none object poll,,,,40272315.0,ns,31239 +allocation,none object poll,,,,41573327.0,ns,32040 +allocation,none object poll,,,,43174912.0,ns,32841 +allocation,none object poll,,,,44175320.0,ns,33642 +allocation,none object poll,,,,45180962.0,ns,34443 +allocation,none object poll,,,,46204482.0,ns,35244 +allocation,none object poll,,,,47697792.0,ns,36045 +allocation,none object poll,,,,48466142.0,ns,36846 +allocation,none object poll,,,,49331756.0,ns,37647 +allocation,none object poll,,,,50406766.0,ns,38448 +allocation,none object poll,,,,51604727.0,ns,39249 +allocation,none object poll,,,,52742526.0,ns,40050 +allocation,none object poll,,,,53691819.0,ns,40851 +allocation,none object poll,,,,54856819.0,ns,41652 +allocation,none object poll,,,,55929468.0,ns,42453 +allocation,none object poll,,,,57167532.0,ns,43254 +allocation,none object poll,,,,58149766.0,ns,44055 +allocation,none object poll,,,,61358098.0,ns,44856 +allocation,none object poll,,,,60616095.0,ns,45657 +allocation,none object poll,,,,61448922.0,ns,46458 +allocation,none object poll,,,,62473599.0,ns,47259 +allocation,none object poll,,,,63431458.0,ns,48060 +allocation,none object poll,,,,64442030.0,ns,48861 +allocation,none object poll,,,,65496093.0,ns,49662 +allocation,none object poll,,,,67151329.0,ns,50463 +allocation,none object poll,,,,67781948.0,ns,51264 +allocation,none object poll,,,,67715787.0,ns,52065 +allocation,none object poll,,,,69768511.0,ns,52866 +allocation,none object poll,,,,70816773.0,ns,53667 +allocation,none object poll,,,,72771991.0,ns,54468 +allocation,none object poll,,,,73319912.0,ns,55269 +allocation,none object poll,,,,74634688.0,ns,56070 +allocation,none object poll,,,,74311721.0,ns,56871 +allocation,none object poll,,,,80690801.0,ns,57672 +allocation,none object poll,,,,79364902.0,ns,58473 +allocation,none object poll,,,,80029980.0,ns,59274 +allocation,none object poll,,,,80122262.0,ns,60075 +allocation,none object poll,,,,81059148.0,ns,60876 +allocation,none object poll,,,,82521070.0,ns,61677 +allocation,none object poll,,,,83444327.0,ns,62478 +allocation,none object poll,,,,85500256.0,ns,63279 +allocation,none object poll,,,,85780189.0,ns,64080 +allocation,none object poll,,,,86570561.0,ns,64881 +allocation,none object poll,,,,88459575.0,ns,65682 +allocation,none object poll,,,,89192720.0,ns,66483 +allocation,none object poll,,,,90098108.0,ns,67284 +allocation,none object poll,,,,91099802.0,ns,68085 +allocation,none object poll,,,,92338183.0,ns,68886 +allocation,none object poll,,,,92177435.0,ns,69687 +allocation,none object poll,,,,94993214.0,ns,70488 +allocation,none object poll,,,,94003940.0,ns,71289 +allocation,none object poll,,,,95109334.0,ns,72090 +allocation,none object poll,,,,96899556.0,ns,72891 +allocation,none object poll,,,,97880090.0,ns,73692 +allocation,none object poll,,,,99111727.0,ns,74493 +allocation,none object poll,,,,99848320.0,ns,75294 +allocation,none object poll,,,,101042878.0,ns,76095 +allocation,none object poll,,,,101881212.0,ns,76896 +allocation,none object poll,,,,102543089.0,ns,77697 +allocation,none object poll,,,,104497346.0,ns,78498 +allocation,none object poll,,,,105014652.0,ns,79299 +allocation,none object poll,,,,105247453.0,ns,80100 diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/sample.json new file mode 100644 index 0000000000000..e90729a1851fc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[801.0,1602.0,2403.0,3204.0,4005.0,4806.0,5607.0,6408.0,7209.0,8010.0,8811.0,9612.0,10413.0,11214.0,12015.0,12816.0,13617.0,14418.0,15219.0,16020.0,16821.0,17622.0,18423.0,19224.0,20025.0,20826.0,21627.0,22428.0,23229.0,24030.0,24831.0,25632.0,26433.0,27234.0,28035.0,28836.0,29637.0,30438.0,31239.0,32040.0,32841.0,33642.0,34443.0,35244.0,36045.0,36846.0,37647.0,38448.0,39249.0,40050.0,40851.0,41652.0,42453.0,43254.0,44055.0,44856.0,45657.0,46458.0,47259.0,48060.0,48861.0,49662.0,50463.0,51264.0,52065.0,52866.0,53667.0,54468.0,55269.0,56070.0,56871.0,57672.0,58473.0,59274.0,60075.0,60876.0,61677.0,62478.0,63279.0,64080.0,64881.0,65682.0,66483.0,67284.0,68085.0,68886.0,69687.0,70488.0,71289.0,72090.0,72891.0,73692.0,74493.0,75294.0,76095.0,76896.0,77697.0,78498.0,79299.0,80100.0],"times":[977917.0,1019213.0,1061550.0,1093531.0,5106026.0,6107590.0,7062882.0,8256566.0,9162611.0,10196611.0,11276872.0,12173877.0,13234583.0,14245720.0,15243402.0,16310041.0,17324266.0,18334767.0,19390633.0,20411973.0,21547530.0,22641969.0,23638377.0,24663813.0,25709883.0,26720937.0,27844332.0,28858750.0,29920441.0,30971442.0,32098756.0,33200387.0,34498255.0,35277918.0,36337705.0,37312874.0,38475546.0,39537900.0,40272315.0,41573327.0,43174912.0,44175320.0,45180962.0,46204482.0,47697792.0,48466142.0,49331756.0,50406766.0,51604727.0,52742526.0,53691819.0,54856819.0,55929468.0,57167532.0,58149766.0,61358098.0,60616095.0,61448922.0,62473599.0,63431458.0,64442030.0,65496093.0,67151329.0,67781948.0,67715787.0,69768511.0,70816773.0,72771991.0,73319912.0,74634688.0,74311721.0,80690801.0,79364902.0,80029980.0,80122262.0,81059148.0,82521070.0,83444327.0,85500256.0,85780189.0,86570561.0,88459575.0,89192720.0,90098108.0,91099802.0,92338183.0,92177435.0,94993214.0,94003940.0,95109334.0,96899556.0,97880090.0,99111727.0,99848320.0,101042878.0,101881212.0,102543089.0,104497346.0,105014652.0,105247453.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/tukey.json new file mode 100644 index 0000000000000..a44007b8c9dd7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/new/tukey.json @@ -0,0 +1 @@ +[1161.974798973942,1224.1193185978227,1389.8380375948382,1451.982557218719] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/MAD.svg new file mode 100644 index 0000000000000..063a78815b5f5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/MAD.svg @@ -0,0 +1,283 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 20 + + + + + 25 + + + + + 30 + + + + + 35 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/none object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/SD.svg new file mode 100644 index 0000000000000..7af8d72c70dcd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 0.009 + + + + + 0.01 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/none object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/index.html new file mode 100644 index 0000000000000..1d74289e3c63d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + allocation/none object poll - Criterion.rs + + + + +
+

allocation/none object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope1.3233 us1.3271 us1.3309 us
0.96896030.97002930.9689368
Mean1.2527 us1.2848 us1.3099 us
Std. Dev.27.343 ns147.56 ns218.30 ns
Median1.3047 us1.3147 us1.3196 us
MAD19.589 ns28.788 ns36.103 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/mean.svg new file mode 100644 index 0000000000000..187b221396319 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 30 + + + + + 1.25 + + + + + 1.26 + + + + + 1.27 + + + + + 1.28 + + + + + 1.29 + + + + + 1.3 + + + + + 1.31 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/none object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/median.svg new file mode 100644 index 0000000000000..2a1c6086f544b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/median.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 250 + + + + + 1.304 + + + + + 1.306 + + + + + 1.308 + + + + + 1.31 + + + + + 1.312 + + + + + 1.314 + + + + + 1.316 + + + + + 1.318 + + + + + 1.32 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/none object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/pdf.svg new file mode 100644 index 0000000000000..af652a55ecd1e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/pdf.svg @@ -0,0 +1,430 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 70 + + + + + 80 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/none object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..4bd1d241d7222 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/pdf_small.svg @@ -0,0 +1,214 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/regression.svg new file mode 100644 index 0000000000000..6171f16e17a9c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/regression.svg @@ -0,0 +1,434 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 120 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 90 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + allocation/none object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/regression_small.svg new file mode 100644 index 0000000000000..c3e4959f8952d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/regression_small.svg @@ -0,0 +1,412 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 120 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 90 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/slope.svg new file mode 100644 index 0000000000000..67d3224011a9e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/slope.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 250 + + + + + 1.323 + + + + + 1.324 + + + + + 1.325 + + + + + 1.326 + + + + + 1.327 + + + + + 1.328 + + + + + 1.329 + + + + + 1.33 + + + + + 1.331 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/none object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/typical.svg new file mode 100644 index 0000000000000..992cd9c2bb810 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/none object poll/report/typical.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 250 + + + + + 1.323 + + + + + 1.324 + + + + + 1.325 + + + + + 1.326 + + + + + 1.327 + + + + + 1.328 + + + + + 1.329 + + + + + 1.33 + + + + + 1.331 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/none object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/report/index.html b/vendor/lockfree-object-pool/benches/criterion/allocation/report/index.html new file mode 100644 index 0000000000000..94053cc241a8e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/report/index.html @@ -0,0 +1,208 @@ + + + + + + allocation Summary - Criterion.rs + + + + +
+

allocation

+

Violin Plot

+ + Violin Plot + +

This chart shows the relationship between function/parameter and iteration time. The thickness of the shaded + region indicates the probability that a measurement of the given function/parameter would take a particular + length of time.

+
+ +

allocation/crate 'object-pool'

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

allocation/crate 'sharded-slab'

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

allocation/linear object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

allocation/mutex object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

allocation/none object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

allocation/spin_lock object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/report/violin.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/report/violin.svg new file mode 100644 index 0000000000000..17a33f5d5abe9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/report/violin.svg @@ -0,0 +1,656 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + allocation/spin_lock object poll + + + + + allocation/none object poll + + + + + allocation/mutex object poll + + + + + allocation/linear object poll + + + + + allocation/crate 'sharded-slab' + + + + + allocation/crate 'object-pool' + + + + + + + + + + + + + -1 + + + + + + + + + + + + + -0.5 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.5 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 2.5 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 3.5 + + + + + + + + + Input + + + + + Average time (us) + + + + + allocation: Violin plot + + + + + PDF + + + PDF + + + + + + + + + + gnuplot_plot_2 + + + + + + + gnuplot_plot_3 + + + + + + + gnuplot_plot_4 + + + + + + + gnuplot_plot_5 + + + + + + + gnuplot_plot_6 + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/benchmark.json new file mode 100644 index 0000000000000..c8029701d15b4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"allocation","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"allocation/spin_lock object poll","directory_name":"allocation/spin_lock object poll","title":"allocation/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/estimates.json new file mode 100644 index 0000000000000..7af2cb4ed0820 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1278.304390147372,"upper_bound":1335.714612839977},"point_estimate":1310.5548378585286,"standard_error":14.65410750087632},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1340.6178507303812,"upper_bound":1346.4878230485233},"point_estimate":1344.122383363472,"standard_error":1.5948897153009551},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.210471997069169,"upper_bound":18.897883604446793},"point_estimate":12.159822133154002,"standard_error":3.074468055074607},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1346.2400768045902,"upper_bound":1348.9098610533713},"point_estimate":1347.6443291251476,"standard_error":0.6796687417253806},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":21.882011242210915,"upper_bound":219.0226432326311},"point_estimate":147.59098528369324,"standard_error":45.84077740252599}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/raw.csv new file mode 100644 index 0000000000000..db3aa6e80b301 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +allocation,spin_lock object poll,,,,984078.0,ns,790 +allocation,spin_lock object poll,,,,1042106.0,ns,1580 +allocation,spin_lock object poll,,,,1098622.0,ns,2370 +allocation,spin_lock object poll,,,,1131412.0,ns,3160 +allocation,spin_lock object poll,,,,5073654.0,ns,3950 +allocation,spin_lock object poll,,,,6217045.0,ns,4740 +allocation,spin_lock object poll,,,,7246928.0,ns,5530 +allocation,spin_lock object poll,,,,8359783.0,ns,6320 +allocation,spin_lock object poll,,,,9228630.0,ns,7110 +allocation,spin_lock object poll,,,,10227671.0,ns,7900 +allocation,spin_lock object poll,,,,11359081.0,ns,8690 +allocation,spin_lock object poll,,,,12330352.0,ns,9480 +allocation,spin_lock object poll,,,,13359102.0,ns,10270 +allocation,spin_lock object poll,,,,14378260.0,ns,11060 +allocation,spin_lock object poll,,,,15447380.0,ns,11850 +allocation,spin_lock object poll,,,,16449284.0,ns,12640 +allocation,spin_lock object poll,,,,17507490.0,ns,13430 +allocation,spin_lock object poll,,,,18535863.0,ns,14220 +allocation,spin_lock object poll,,,,19595029.0,ns,15010 +allocation,spin_lock object poll,,,,20628951.0,ns,15800 +allocation,spin_lock object poll,,,,21878545.0,ns,16590 +allocation,spin_lock object poll,,,,22886465.0,ns,17380 +allocation,spin_lock object poll,,,,23916345.0,ns,18170 +allocation,spin_lock object poll,,,,25030825.0,ns,18960 +allocation,spin_lock object poll,,,,26011831.0,ns,19750 +allocation,spin_lock object poll,,,,27070874.0,ns,20540 +allocation,spin_lock object poll,,,,28120065.0,ns,21330 +allocation,spin_lock object poll,,,,29156340.0,ns,22120 +allocation,spin_lock object poll,,,,30223327.0,ns,22910 +allocation,spin_lock object poll,,,,31303654.0,ns,23700 +allocation,spin_lock object poll,,,,32381880.0,ns,24490 +allocation,spin_lock object poll,,,,33854551.0,ns,25280 +allocation,spin_lock object poll,,,,36727023.0,ns,26070 +allocation,spin_lock object poll,,,,36282972.0,ns,26860 +allocation,spin_lock object poll,,,,36836206.0,ns,27650 +allocation,spin_lock object poll,,,,37671376.0,ns,28440 +allocation,spin_lock object poll,,,,38781256.0,ns,29230 +allocation,spin_lock object poll,,,,40000235.0,ns,30020 +allocation,spin_lock object poll,,,,40995812.0,ns,30810 +allocation,spin_lock object poll,,,,41947472.0,ns,31600 +allocation,spin_lock object poll,,,,43027529.0,ns,32390 +allocation,spin_lock object poll,,,,44438987.0,ns,33180 +allocation,spin_lock object poll,,,,45567322.0,ns,33970 +allocation,spin_lock object poll,,,,46706028.0,ns,34760 +allocation,spin_lock object poll,,,,48075546.0,ns,35550 +allocation,spin_lock object poll,,,,48783941.0,ns,36340 +allocation,spin_lock object poll,,,,49824939.0,ns,37130 +allocation,spin_lock object poll,,,,50942066.0,ns,37920 +allocation,spin_lock object poll,,,,52015653.0,ns,38710 +allocation,spin_lock object poll,,,,53093429.0,ns,39500 +allocation,spin_lock object poll,,,,54425144.0,ns,40290 +allocation,spin_lock object poll,,,,55565507.0,ns,41080 +allocation,spin_lock object poll,,,,56399738.0,ns,41870 +allocation,spin_lock object poll,,,,57828151.0,ns,42660 +allocation,spin_lock object poll,,,,58464548.0,ns,43450 +allocation,spin_lock object poll,,,,59463308.0,ns,44240 +allocation,spin_lock object poll,,,,60471063.0,ns,45030 +allocation,spin_lock object poll,,,,61695169.0,ns,45820 +allocation,spin_lock object poll,,,,62664089.0,ns,46610 +allocation,spin_lock object poll,,,,63739287.0,ns,47400 +allocation,spin_lock object poll,,,,64768038.0,ns,48190 +allocation,spin_lock object poll,,,,66352351.0,ns,48980 +allocation,spin_lock object poll,,,,67105960.0,ns,49770 +allocation,spin_lock object poll,,,,68128775.0,ns,50560 +allocation,spin_lock object poll,,,,70255424.0,ns,51350 +allocation,spin_lock object poll,,,,70443248.0,ns,52140 +allocation,spin_lock object poll,,,,71471584.0,ns,52930 +allocation,spin_lock object poll,,,,72263025.0,ns,53720 +allocation,spin_lock object poll,,,,73666830.0,ns,54510 +allocation,spin_lock object poll,,,,74615936.0,ns,55300 +allocation,spin_lock object poll,,,,75640873.0,ns,56090 +allocation,spin_lock object poll,,,,76767852.0,ns,56880 +allocation,spin_lock object poll,,,,77844884.0,ns,57670 +allocation,spin_lock object poll,,,,78876577.0,ns,58460 +allocation,spin_lock object poll,,,,79999757.0,ns,59250 +allocation,spin_lock object poll,,,,81192819.0,ns,60040 +allocation,spin_lock object poll,,,,82046516.0,ns,60830 +allocation,spin_lock object poll,,,,82965766.0,ns,61620 +allocation,spin_lock object poll,,,,84082952.0,ns,62410 +allocation,spin_lock object poll,,,,84979791.0,ns,63200 +allocation,spin_lock object poll,,,,86149842.0,ns,63990 +allocation,spin_lock object poll,,,,87298011.0,ns,64780 +allocation,spin_lock object poll,,,,88820471.0,ns,65570 +allocation,spin_lock object poll,,,,89893927.0,ns,66360 +allocation,spin_lock object poll,,,,90847044.0,ns,67150 +allocation,spin_lock object poll,,,,91790736.0,ns,67940 +allocation,spin_lock object poll,,,,93215195.0,ns,68730 +allocation,spin_lock object poll,,,,94113162.0,ns,69520 +allocation,spin_lock object poll,,,,94930377.0,ns,70310 +allocation,spin_lock object poll,,,,95863607.0,ns,71100 +allocation,spin_lock object poll,,,,97131472.0,ns,71890 +allocation,spin_lock object poll,,,,98139861.0,ns,72680 +allocation,spin_lock object poll,,,,99323288.0,ns,73470 +allocation,spin_lock object poll,,,,100492725.0,ns,74260 +allocation,spin_lock object poll,,,,101281306.0,ns,75050 +allocation,spin_lock object poll,,,,102123561.0,ns,75840 +allocation,spin_lock object poll,,,,103449925.0,ns,76630 +allocation,spin_lock object poll,,,,104316163.0,ns,77420 +allocation,spin_lock object poll,,,,105187557.0,ns,78210 +allocation,spin_lock object poll,,,,106172038.0,ns,79000 diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/sample.json new file mode 100644 index 0000000000000..4fd7a12475562 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[790.0,1580.0,2370.0,3160.0,3950.0,4740.0,5530.0,6320.0,7110.0,7900.0,8690.0,9480.0,10270.0,11060.0,11850.0,12640.0,13430.0,14220.0,15010.0,15800.0,16590.0,17380.0,18170.0,18960.0,19750.0,20540.0,21330.0,22120.0,22910.0,23700.0,24490.0,25280.0,26070.0,26860.0,27650.0,28440.0,29230.0,30020.0,30810.0,31600.0,32390.0,33180.0,33970.0,34760.0,35550.0,36340.0,37130.0,37920.0,38710.0,39500.0,40290.0,41080.0,41870.0,42660.0,43450.0,44240.0,45030.0,45820.0,46610.0,47400.0,48190.0,48980.0,49770.0,50560.0,51350.0,52140.0,52930.0,53720.0,54510.0,55300.0,56090.0,56880.0,57670.0,58460.0,59250.0,60040.0,60830.0,61620.0,62410.0,63200.0,63990.0,64780.0,65570.0,66360.0,67150.0,67940.0,68730.0,69520.0,70310.0,71100.0,71890.0,72680.0,73470.0,74260.0,75050.0,75840.0,76630.0,77420.0,78210.0,79000.0],"times":[984078.0,1042106.0,1098622.0,1131412.0,5073654.0,6217045.0,7246928.0,8359783.0,9228630.0,10227671.0,11359081.0,12330352.0,13359102.0,14378260.0,15447380.0,16449284.0,17507490.0,18535863.0,19595029.0,20628951.0,21878545.0,22886465.0,23916345.0,25030825.0,26011831.0,27070874.0,28120065.0,29156340.0,30223327.0,31303654.0,32381880.0,33854551.0,36727023.0,36282972.0,36836206.0,37671376.0,38781256.0,40000235.0,40995812.0,41947472.0,43027529.0,44438987.0,45567322.0,46706028.0,48075546.0,48783941.0,49824939.0,50942066.0,52015653.0,53093429.0,54425144.0,55565507.0,56399738.0,57828151.0,58464548.0,59463308.0,60471063.0,61695169.0,62664089.0,63739287.0,64768038.0,66352351.0,67105960.0,68128775.0,70255424.0,70443248.0,71471584.0,72263025.0,73666830.0,74615936.0,75640873.0,76767852.0,77844884.0,78876577.0,79999757.0,81192819.0,82046516.0,82965766.0,84082952.0,84979791.0,86149842.0,87298011.0,88820471.0,89893927.0,90847044.0,91790736.0,93215195.0,94113162.0,94930377.0,95863607.0,97131472.0,98139861.0,99323288.0,100492725.0,101281306.0,102123561.0,103449925.0,104316163.0,105187557.0,106172038.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/tukey.json new file mode 100644 index 0000000000000..bcb821f0aee90 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/base/tukey.json @@ -0,0 +1 @@ +[1225.0520846813288,1271.8599533312208,1396.6809363976,1443.4888050474922] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/benchmark.json new file mode 100644 index 0000000000000..c8029701d15b4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"allocation","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"allocation/spin_lock object poll","directory_name":"allocation/spin_lock object poll","title":"allocation/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/estimates.json new file mode 100644 index 0000000000000..7af2cb4ed0820 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1278.304390147372,"upper_bound":1335.714612839977},"point_estimate":1310.5548378585286,"standard_error":14.65410750087632},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1340.6178507303812,"upper_bound":1346.4878230485233},"point_estimate":1344.122383363472,"standard_error":1.5948897153009551},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.210471997069169,"upper_bound":18.897883604446793},"point_estimate":12.159822133154002,"standard_error":3.074468055074607},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1346.2400768045902,"upper_bound":1348.9098610533713},"point_estimate":1347.6443291251476,"standard_error":0.6796687417253806},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":21.882011242210915,"upper_bound":219.0226432326311},"point_estimate":147.59098528369324,"standard_error":45.84077740252599}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/raw.csv new file mode 100644 index 0000000000000..db3aa6e80b301 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +allocation,spin_lock object poll,,,,984078.0,ns,790 +allocation,spin_lock object poll,,,,1042106.0,ns,1580 +allocation,spin_lock object poll,,,,1098622.0,ns,2370 +allocation,spin_lock object poll,,,,1131412.0,ns,3160 +allocation,spin_lock object poll,,,,5073654.0,ns,3950 +allocation,spin_lock object poll,,,,6217045.0,ns,4740 +allocation,spin_lock object poll,,,,7246928.0,ns,5530 +allocation,spin_lock object poll,,,,8359783.0,ns,6320 +allocation,spin_lock object poll,,,,9228630.0,ns,7110 +allocation,spin_lock object poll,,,,10227671.0,ns,7900 +allocation,spin_lock object poll,,,,11359081.0,ns,8690 +allocation,spin_lock object poll,,,,12330352.0,ns,9480 +allocation,spin_lock object poll,,,,13359102.0,ns,10270 +allocation,spin_lock object poll,,,,14378260.0,ns,11060 +allocation,spin_lock object poll,,,,15447380.0,ns,11850 +allocation,spin_lock object poll,,,,16449284.0,ns,12640 +allocation,spin_lock object poll,,,,17507490.0,ns,13430 +allocation,spin_lock object poll,,,,18535863.0,ns,14220 +allocation,spin_lock object poll,,,,19595029.0,ns,15010 +allocation,spin_lock object poll,,,,20628951.0,ns,15800 +allocation,spin_lock object poll,,,,21878545.0,ns,16590 +allocation,spin_lock object poll,,,,22886465.0,ns,17380 +allocation,spin_lock object poll,,,,23916345.0,ns,18170 +allocation,spin_lock object poll,,,,25030825.0,ns,18960 +allocation,spin_lock object poll,,,,26011831.0,ns,19750 +allocation,spin_lock object poll,,,,27070874.0,ns,20540 +allocation,spin_lock object poll,,,,28120065.0,ns,21330 +allocation,spin_lock object poll,,,,29156340.0,ns,22120 +allocation,spin_lock object poll,,,,30223327.0,ns,22910 +allocation,spin_lock object poll,,,,31303654.0,ns,23700 +allocation,spin_lock object poll,,,,32381880.0,ns,24490 +allocation,spin_lock object poll,,,,33854551.0,ns,25280 +allocation,spin_lock object poll,,,,36727023.0,ns,26070 +allocation,spin_lock object poll,,,,36282972.0,ns,26860 +allocation,spin_lock object poll,,,,36836206.0,ns,27650 +allocation,spin_lock object poll,,,,37671376.0,ns,28440 +allocation,spin_lock object poll,,,,38781256.0,ns,29230 +allocation,spin_lock object poll,,,,40000235.0,ns,30020 +allocation,spin_lock object poll,,,,40995812.0,ns,30810 +allocation,spin_lock object poll,,,,41947472.0,ns,31600 +allocation,spin_lock object poll,,,,43027529.0,ns,32390 +allocation,spin_lock object poll,,,,44438987.0,ns,33180 +allocation,spin_lock object poll,,,,45567322.0,ns,33970 +allocation,spin_lock object poll,,,,46706028.0,ns,34760 +allocation,spin_lock object poll,,,,48075546.0,ns,35550 +allocation,spin_lock object poll,,,,48783941.0,ns,36340 +allocation,spin_lock object poll,,,,49824939.0,ns,37130 +allocation,spin_lock object poll,,,,50942066.0,ns,37920 +allocation,spin_lock object poll,,,,52015653.0,ns,38710 +allocation,spin_lock object poll,,,,53093429.0,ns,39500 +allocation,spin_lock object poll,,,,54425144.0,ns,40290 +allocation,spin_lock object poll,,,,55565507.0,ns,41080 +allocation,spin_lock object poll,,,,56399738.0,ns,41870 +allocation,spin_lock object poll,,,,57828151.0,ns,42660 +allocation,spin_lock object poll,,,,58464548.0,ns,43450 +allocation,spin_lock object poll,,,,59463308.0,ns,44240 +allocation,spin_lock object poll,,,,60471063.0,ns,45030 +allocation,spin_lock object poll,,,,61695169.0,ns,45820 +allocation,spin_lock object poll,,,,62664089.0,ns,46610 +allocation,spin_lock object poll,,,,63739287.0,ns,47400 +allocation,spin_lock object poll,,,,64768038.0,ns,48190 +allocation,spin_lock object poll,,,,66352351.0,ns,48980 +allocation,spin_lock object poll,,,,67105960.0,ns,49770 +allocation,spin_lock object poll,,,,68128775.0,ns,50560 +allocation,spin_lock object poll,,,,70255424.0,ns,51350 +allocation,spin_lock object poll,,,,70443248.0,ns,52140 +allocation,spin_lock object poll,,,,71471584.0,ns,52930 +allocation,spin_lock object poll,,,,72263025.0,ns,53720 +allocation,spin_lock object poll,,,,73666830.0,ns,54510 +allocation,spin_lock object poll,,,,74615936.0,ns,55300 +allocation,spin_lock object poll,,,,75640873.0,ns,56090 +allocation,spin_lock object poll,,,,76767852.0,ns,56880 +allocation,spin_lock object poll,,,,77844884.0,ns,57670 +allocation,spin_lock object poll,,,,78876577.0,ns,58460 +allocation,spin_lock object poll,,,,79999757.0,ns,59250 +allocation,spin_lock object poll,,,,81192819.0,ns,60040 +allocation,spin_lock object poll,,,,82046516.0,ns,60830 +allocation,spin_lock object poll,,,,82965766.0,ns,61620 +allocation,spin_lock object poll,,,,84082952.0,ns,62410 +allocation,spin_lock object poll,,,,84979791.0,ns,63200 +allocation,spin_lock object poll,,,,86149842.0,ns,63990 +allocation,spin_lock object poll,,,,87298011.0,ns,64780 +allocation,spin_lock object poll,,,,88820471.0,ns,65570 +allocation,spin_lock object poll,,,,89893927.0,ns,66360 +allocation,spin_lock object poll,,,,90847044.0,ns,67150 +allocation,spin_lock object poll,,,,91790736.0,ns,67940 +allocation,spin_lock object poll,,,,93215195.0,ns,68730 +allocation,spin_lock object poll,,,,94113162.0,ns,69520 +allocation,spin_lock object poll,,,,94930377.0,ns,70310 +allocation,spin_lock object poll,,,,95863607.0,ns,71100 +allocation,spin_lock object poll,,,,97131472.0,ns,71890 +allocation,spin_lock object poll,,,,98139861.0,ns,72680 +allocation,spin_lock object poll,,,,99323288.0,ns,73470 +allocation,spin_lock object poll,,,,100492725.0,ns,74260 +allocation,spin_lock object poll,,,,101281306.0,ns,75050 +allocation,spin_lock object poll,,,,102123561.0,ns,75840 +allocation,spin_lock object poll,,,,103449925.0,ns,76630 +allocation,spin_lock object poll,,,,104316163.0,ns,77420 +allocation,spin_lock object poll,,,,105187557.0,ns,78210 +allocation,spin_lock object poll,,,,106172038.0,ns,79000 diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/sample.json new file mode 100644 index 0000000000000..4fd7a12475562 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[790.0,1580.0,2370.0,3160.0,3950.0,4740.0,5530.0,6320.0,7110.0,7900.0,8690.0,9480.0,10270.0,11060.0,11850.0,12640.0,13430.0,14220.0,15010.0,15800.0,16590.0,17380.0,18170.0,18960.0,19750.0,20540.0,21330.0,22120.0,22910.0,23700.0,24490.0,25280.0,26070.0,26860.0,27650.0,28440.0,29230.0,30020.0,30810.0,31600.0,32390.0,33180.0,33970.0,34760.0,35550.0,36340.0,37130.0,37920.0,38710.0,39500.0,40290.0,41080.0,41870.0,42660.0,43450.0,44240.0,45030.0,45820.0,46610.0,47400.0,48190.0,48980.0,49770.0,50560.0,51350.0,52140.0,52930.0,53720.0,54510.0,55300.0,56090.0,56880.0,57670.0,58460.0,59250.0,60040.0,60830.0,61620.0,62410.0,63200.0,63990.0,64780.0,65570.0,66360.0,67150.0,67940.0,68730.0,69520.0,70310.0,71100.0,71890.0,72680.0,73470.0,74260.0,75050.0,75840.0,76630.0,77420.0,78210.0,79000.0],"times":[984078.0,1042106.0,1098622.0,1131412.0,5073654.0,6217045.0,7246928.0,8359783.0,9228630.0,10227671.0,11359081.0,12330352.0,13359102.0,14378260.0,15447380.0,16449284.0,17507490.0,18535863.0,19595029.0,20628951.0,21878545.0,22886465.0,23916345.0,25030825.0,26011831.0,27070874.0,28120065.0,29156340.0,30223327.0,31303654.0,32381880.0,33854551.0,36727023.0,36282972.0,36836206.0,37671376.0,38781256.0,40000235.0,40995812.0,41947472.0,43027529.0,44438987.0,45567322.0,46706028.0,48075546.0,48783941.0,49824939.0,50942066.0,52015653.0,53093429.0,54425144.0,55565507.0,56399738.0,57828151.0,58464548.0,59463308.0,60471063.0,61695169.0,62664089.0,63739287.0,64768038.0,66352351.0,67105960.0,68128775.0,70255424.0,70443248.0,71471584.0,72263025.0,73666830.0,74615936.0,75640873.0,76767852.0,77844884.0,78876577.0,79999757.0,81192819.0,82046516.0,82965766.0,84082952.0,84979791.0,86149842.0,87298011.0,88820471.0,89893927.0,90847044.0,91790736.0,93215195.0,94113162.0,94930377.0,95863607.0,97131472.0,98139861.0,99323288.0,100492725.0,101281306.0,102123561.0,103449925.0,104316163.0,105187557.0,106172038.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/tukey.json new file mode 100644 index 0000000000000..bcb821f0aee90 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/new/tukey.json @@ -0,0 +1 @@ +[1225.0520846813288,1271.8599533312208,1396.6809363976,1443.4888050474922] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/MAD.svg new file mode 100644 index 0000000000000..66386c36479cd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/MAD.svg @@ -0,0 +1,308 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 0.16 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/spin_lock object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/SD.svg new file mode 100644 index 0000000000000..901759fbbd24a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/SD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 0.009 + + + + + 0.01 + + + + + 0 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + allocation/spin_lock object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/index.html new file mode 100644 index 0000000000000..dbbac8412a149 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + allocation/spin_lock object poll - Criterion.rs + + + + +
+

allocation/spin_lock object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope1.3462 us1.3476 us1.3489 us
0.98858990.98873710.9886176
Mean1.2783 us1.3106 us1.3357 us
Std. Dev.21.882 ns147.59 ns219.02 ns
Median1.3406 us1.3441 us1.3465 us
MAD7.2105 ns12.160 ns18.898 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/mean.svg new file mode 100644 index 0000000000000..9c82160f70cb6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 30 + + + + + 1.28 + + + + + 1.29 + + + + + 1.3 + + + + + 1.31 + + + + + 1.32 + + + + + 1.33 + + + + + 1.34 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/spin_lock object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/median.svg new file mode 100644 index 0000000000000..8e07fc4ca74db --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/median.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 100 + + + + + 200 + + + + + 300 + + + + + 400 + + + + + 500 + + + + + 600 + + + + + 700 + + + + + 1.34 + + + + + 1.341 + + + + + 1.342 + + + + + 1.343 + + + + + 1.344 + + + + + 1.345 + + + + + 1.346 + + + + + 1.347 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/spin_lock object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/pdf.svg new file mode 100644 index 0000000000000..1a421a0c12be5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/pdf.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 70 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/spin_lock object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..80e5a28f85f34 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/pdf_small.svg @@ -0,0 +1,214 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/regression.svg new file mode 100644 index 0000000000000..e6636aac826e8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/regression.svg @@ -0,0 +1,421 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 120 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + allocation/spin_lock object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/regression_small.svg new file mode 100644 index 0000000000000..49582f01e1934 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/regression_small.svg @@ -0,0 +1,399 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 120 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/slope.svg new file mode 100644 index 0000000000000..5ca0042b0d89b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 100 + + + + + 200 + + + + + 300 + + + + + 400 + + + + + 500 + + + + + 600 + + + + + 1.346 + + + + + 1.3465 + + + + + 1.347 + + + + + 1.3475 + + + + + 1.348 + + + + + 1.3485 + + + + + 1.349 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/spin_lock object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/typical.svg new file mode 100644 index 0000000000000..9d6a7b180f9f4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/allocation/spin_lock object poll/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 100 + + + + + 200 + + + + + 300 + + + + + 400 + + + + + 500 + + + + + 600 + + + + + 1.346 + + + + + 1.3465 + + + + + 1.347 + + + + + 1.3475 + + + + + 1.348 + + + + + 1.3485 + + + + + 1.349 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + allocation/spin_lock object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/benchmark.json new file mode 100644 index 0000000000000..20e14cdd369f3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:1)","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab'","directory_name":"forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'","title":"forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/estimates.json new file mode 100644 index 0000000000000..4ad7cbd0a6766 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":496.09072273944014,"upper_bound":554.6348372420075},"point_estimate":525.8209444401516,"standard_error":14.94565244242569},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":483.0737931034483,"upper_bound":589.4815582279782},"point_estimate":533.4886268343815,"standard_error":26.89894327136015},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":125.50982022318787,"upper_bound":181.91238412775792},"point_estimate":151.30477695885793,"standard_error":14.374296632606134},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":572.125945444529,"upper_bound":619.8708173041647},"point_estimate":597.3042188660658,"standard_error":12.187676125353441},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":126.32552307663828,"upper_bound":171.99777083532135},"point_estimate":150.15530016580976,"standard_error":11.65806615358323}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/raw.csv new file mode 100644 index 0000000000000..556577472ecb3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,173666.0,ns,225 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,47070.0,ns,450 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,176716.0,ns,675 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,92425.0,ns,900 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,374040.0,ns,1125 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,136681.0,ns,1350 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,486833.0,ns,1575 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,243577.0,ns,1800 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,751800.0,ns,2025 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1179022.0,ns,2250 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1240099.0,ns,2475 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1226287.0,ns,2700 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1257634.0,ns,2925 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1171687.0,ns,3150 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1178325.0,ns,3375 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1182198.0,ns,3600 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1222008.0,ns,3825 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1219842.0,ns,4050 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2713619.0,ns,4275 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2705283.0,ns,4500 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2733940.0,ns,4725 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2756720.0,ns,4950 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2788716.0,ns,5175 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2800034.0,ns,5400 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2827181.0,ns,5625 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2900508.0,ns,5850 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2882532.0,ns,6075 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2877780.0,ns,6300 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2901549.0,ns,6525 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2903807.0,ns,6750 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2941641.0,ns,6975 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2923021.0,ns,7200 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2983845.0,ns,7425 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,3002714.0,ns,7650 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,3008516.0,ns,7875 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,3017952.0,ns,8100 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,5979523.0,ns,8325 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,5977934.0,ns,8550 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6002690.0,ns,8775 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6019371.0,ns,9000 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6095128.0,ns,9225 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6048031.0,ns,9450 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6044742.0,ns,9675 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6208749.0,ns,9900 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6219475.0,ns,10125 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6154890.0,ns,10350 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6178843.0,ns,10575 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6219480.0,ns,10800 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6219757.0,ns,11025 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6259552.0,ns,11250 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6288365.0,ns,11475 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6287151.0,ns,11700 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6315646.0,ns,11925 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6326352.0,ns,12150 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,5914654.0,ns,12375 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6385022.0,ns,12600 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6322361.0,ns,12825 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6304113.0,ns,13050 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6349730.0,ns,13275 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6368690.0,ns,13500 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6459818.0,ns,13725 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6409236.0,ns,13950 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6437046.0,ns,14175 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6425679.0,ns,14400 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6520152.0,ns,14625 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6610939.0,ns,14850 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6557360.0,ns,15075 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6629544.0,ns,15300 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6685955.0,ns,15525 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6671812.0,ns,15750 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6652791.0,ns,15975 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6656605.0,ns,16200 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12564319.0,ns,16425 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12713521.0,ns,16650 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12675000.0,ns,16875 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12653488.0,ns,17100 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12660018.0,ns,17325 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12681547.0,ns,17550 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12834736.0,ns,17775 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12936541.0,ns,18000 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12720031.0,ns,18225 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12752987.0,ns,18450 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12816365.0,ns,18675 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12940151.0,ns,18900 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12919978.0,ns,19125 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13112029.0,ns,19350 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13180410.0,ns,19575 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13010720.0,ns,19800 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12927905.0,ns,20025 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12811612.0,ns,20250 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12979603.0,ns,20475 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13280379.0,ns,20700 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13106471.0,ns,20925 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12988602.0,ns,21150 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13031666.0,ns,21375 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13180260.0,ns,21600 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13265371.0,ns,21825 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13450061.0,ns,22050 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13321703.0,ns,22275 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13148661.0,ns,22500 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/sample.json new file mode 100644 index 0000000000000..4554e4b144b70 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[225.0,450.0,675.0,900.0,1125.0,1350.0,1575.0,1800.0,2025.0,2250.0,2475.0,2700.0,2925.0,3150.0,3375.0,3600.0,3825.0,4050.0,4275.0,4500.0,4725.0,4950.0,5175.0,5400.0,5625.0,5850.0,6075.0,6300.0,6525.0,6750.0,6975.0,7200.0,7425.0,7650.0,7875.0,8100.0,8325.0,8550.0,8775.0,9000.0,9225.0,9450.0,9675.0,9900.0,10125.0,10350.0,10575.0,10800.0,11025.0,11250.0,11475.0,11700.0,11925.0,12150.0,12375.0,12600.0,12825.0,13050.0,13275.0,13500.0,13725.0,13950.0,14175.0,14400.0,14625.0,14850.0,15075.0,15300.0,15525.0,15750.0,15975.0,16200.0,16425.0,16650.0,16875.0,17100.0,17325.0,17550.0,17775.0,18000.0,18225.0,18450.0,18675.0,18900.0,19125.0,19350.0,19575.0,19800.0,20025.0,20250.0,20475.0,20700.0,20925.0,21150.0,21375.0,21600.0,21825.0,22050.0,22275.0,22500.0],"times":[173666.0,47070.0,176716.0,92425.0,374040.0,136681.0,486833.0,243577.0,751800.0,1179022.0,1240099.0,1226287.0,1257634.0,1171687.0,1178325.0,1182198.0,1222008.0,1219842.0,2713619.0,2705283.0,2733940.0,2756720.0,2788716.0,2800034.0,2827181.0,2900508.0,2882532.0,2877780.0,2901549.0,2903807.0,2941641.0,2923021.0,2983845.0,3002714.0,3008516.0,3017952.0,5979523.0,5977934.0,6002690.0,6019371.0,6095128.0,6048031.0,6044742.0,6208749.0,6219475.0,6154890.0,6178843.0,6219480.0,6219757.0,6259552.0,6288365.0,6287151.0,6315646.0,6326352.0,5914654.0,6385022.0,6322361.0,6304113.0,6349730.0,6368690.0,6459818.0,6409236.0,6437046.0,6425679.0,6520152.0,6610939.0,6557360.0,6629544.0,6685955.0,6671812.0,6652791.0,6656605.0,12564319.0,12713521.0,12675000.0,12653488.0,12660018.0,12681547.0,12834736.0,12936541.0,12720031.0,12752987.0,12816365.0,12940151.0,12919978.0,13112029.0,13180410.0,13010720.0,12927905.0,12811612.0,12979603.0,13280379.0,13106471.0,12988602.0,13031666.0,13180260.0,13265371.0,13450061.0,13321703.0,13148661.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/tukey.json new file mode 100644 index 0000000000000..173a494febc20 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/base/tukey.json @@ -0,0 +1 @@ +[-177.65507150584625,127.49345363800234,941.2228540215986,1246.3713791654473] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/benchmark.json new file mode 100644 index 0000000000000..20e14cdd369f3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:1)","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab'","directory_name":"forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'","title":"forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/estimates.json new file mode 100644 index 0000000000000..4ad7cbd0a6766 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":496.09072273944014,"upper_bound":554.6348372420075},"point_estimate":525.8209444401516,"standard_error":14.94565244242569},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":483.0737931034483,"upper_bound":589.4815582279782},"point_estimate":533.4886268343815,"standard_error":26.89894327136015},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":125.50982022318787,"upper_bound":181.91238412775792},"point_estimate":151.30477695885793,"standard_error":14.374296632606134},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":572.125945444529,"upper_bound":619.8708173041647},"point_estimate":597.3042188660658,"standard_error":12.187676125353441},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":126.32552307663828,"upper_bound":171.99777083532135},"point_estimate":150.15530016580976,"standard_error":11.65806615358323}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/raw.csv new file mode 100644 index 0000000000000..556577472ecb3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,173666.0,ns,225 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,47070.0,ns,450 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,176716.0,ns,675 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,92425.0,ns,900 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,374040.0,ns,1125 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,136681.0,ns,1350 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,486833.0,ns,1575 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,243577.0,ns,1800 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,751800.0,ns,2025 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1179022.0,ns,2250 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1240099.0,ns,2475 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1226287.0,ns,2700 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1257634.0,ns,2925 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1171687.0,ns,3150 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1178325.0,ns,3375 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1182198.0,ns,3600 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1222008.0,ns,3825 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,1219842.0,ns,4050 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2713619.0,ns,4275 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2705283.0,ns,4500 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2733940.0,ns,4725 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2756720.0,ns,4950 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2788716.0,ns,5175 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2800034.0,ns,5400 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2827181.0,ns,5625 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2900508.0,ns,5850 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2882532.0,ns,6075 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2877780.0,ns,6300 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2901549.0,ns,6525 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2903807.0,ns,6750 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2941641.0,ns,6975 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2923021.0,ns,7200 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,2983845.0,ns,7425 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,3002714.0,ns,7650 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,3008516.0,ns,7875 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,3017952.0,ns,8100 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,5979523.0,ns,8325 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,5977934.0,ns,8550 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6002690.0,ns,8775 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6019371.0,ns,9000 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6095128.0,ns,9225 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6048031.0,ns,9450 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6044742.0,ns,9675 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6208749.0,ns,9900 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6219475.0,ns,10125 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6154890.0,ns,10350 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6178843.0,ns,10575 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6219480.0,ns,10800 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6219757.0,ns,11025 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6259552.0,ns,11250 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6288365.0,ns,11475 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6287151.0,ns,11700 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6315646.0,ns,11925 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6326352.0,ns,12150 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,5914654.0,ns,12375 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6385022.0,ns,12600 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6322361.0,ns,12825 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6304113.0,ns,13050 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6349730.0,ns,13275 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6368690.0,ns,13500 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6459818.0,ns,13725 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6409236.0,ns,13950 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6437046.0,ns,14175 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6425679.0,ns,14400 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6520152.0,ns,14625 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6610939.0,ns,14850 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6557360.0,ns,15075 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6629544.0,ns,15300 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6685955.0,ns,15525 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6671812.0,ns,15750 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6652791.0,ns,15975 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,6656605.0,ns,16200 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12564319.0,ns,16425 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12713521.0,ns,16650 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12675000.0,ns,16875 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12653488.0,ns,17100 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12660018.0,ns,17325 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12681547.0,ns,17550 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12834736.0,ns,17775 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12936541.0,ns,18000 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12720031.0,ns,18225 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12752987.0,ns,18450 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12816365.0,ns,18675 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12940151.0,ns,18900 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12919978.0,ns,19125 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13112029.0,ns,19350 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13180410.0,ns,19575 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13010720.0,ns,19800 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12927905.0,ns,20025 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12811612.0,ns,20250 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12979603.0,ns,20475 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13280379.0,ns,20700 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13106471.0,ns,20925 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,12988602.0,ns,21150 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13031666.0,ns,21375 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13180260.0,ns,21600 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13265371.0,ns,21825 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13450061.0,ns,22050 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13321703.0,ns,22275 +forward msg from pull (nb_writter:1 nb_readder:1),crate 'sharded-slab',,,,13148661.0,ns,22500 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/sample.json new file mode 100644 index 0000000000000..4554e4b144b70 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[225.0,450.0,675.0,900.0,1125.0,1350.0,1575.0,1800.0,2025.0,2250.0,2475.0,2700.0,2925.0,3150.0,3375.0,3600.0,3825.0,4050.0,4275.0,4500.0,4725.0,4950.0,5175.0,5400.0,5625.0,5850.0,6075.0,6300.0,6525.0,6750.0,6975.0,7200.0,7425.0,7650.0,7875.0,8100.0,8325.0,8550.0,8775.0,9000.0,9225.0,9450.0,9675.0,9900.0,10125.0,10350.0,10575.0,10800.0,11025.0,11250.0,11475.0,11700.0,11925.0,12150.0,12375.0,12600.0,12825.0,13050.0,13275.0,13500.0,13725.0,13950.0,14175.0,14400.0,14625.0,14850.0,15075.0,15300.0,15525.0,15750.0,15975.0,16200.0,16425.0,16650.0,16875.0,17100.0,17325.0,17550.0,17775.0,18000.0,18225.0,18450.0,18675.0,18900.0,19125.0,19350.0,19575.0,19800.0,20025.0,20250.0,20475.0,20700.0,20925.0,21150.0,21375.0,21600.0,21825.0,22050.0,22275.0,22500.0],"times":[173666.0,47070.0,176716.0,92425.0,374040.0,136681.0,486833.0,243577.0,751800.0,1179022.0,1240099.0,1226287.0,1257634.0,1171687.0,1178325.0,1182198.0,1222008.0,1219842.0,2713619.0,2705283.0,2733940.0,2756720.0,2788716.0,2800034.0,2827181.0,2900508.0,2882532.0,2877780.0,2901549.0,2903807.0,2941641.0,2923021.0,2983845.0,3002714.0,3008516.0,3017952.0,5979523.0,5977934.0,6002690.0,6019371.0,6095128.0,6048031.0,6044742.0,6208749.0,6219475.0,6154890.0,6178843.0,6219480.0,6219757.0,6259552.0,6288365.0,6287151.0,6315646.0,6326352.0,5914654.0,6385022.0,6322361.0,6304113.0,6349730.0,6368690.0,6459818.0,6409236.0,6437046.0,6425679.0,6520152.0,6610939.0,6557360.0,6629544.0,6685955.0,6671812.0,6652791.0,6656605.0,12564319.0,12713521.0,12675000.0,12653488.0,12660018.0,12681547.0,12834736.0,12936541.0,12720031.0,12752987.0,12816365.0,12940151.0,12919978.0,13112029.0,13180410.0,13010720.0,12927905.0,12811612.0,12979603.0,13280379.0,13106471.0,12988602.0,13031666.0,13180260.0,13265371.0,13450061.0,13321703.0,13148661.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/tukey.json new file mode 100644 index 0000000000000..173a494febc20 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/new/tukey.json @@ -0,0 +1 @@ +[-177.65507150584625,127.49345363800234,941.2228540215986,1246.3713791654473] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/MAD.svg new file mode 100644 index 0000000000000..2e2c5337d22ac --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 120 + + + + + 130 + + + + + 140 + + + + + 150 + + + + + 160 + + + + + 170 + + + + + 180 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab': MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/SD.svg new file mode 100644 index 0000000000000..a4d93e8c20c0f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/SD.svg @@ -0,0 +1,288 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 130 + + + + + 140 + + + + + 150 + + + + + 160 + + + + + 170 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab': SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/index.html new file mode 100644 index 0000000000000..35d8cdc66037a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab' - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab'

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope572.13 ns597.30 ns619.87 ns
0.18110710.18967120.1827300
Mean496.09 ns525.82 ns554.63 ns
Std. Dev.126.33 ns150.16 ns172.00 ns
Median483.07 ns533.49 ns589.48 ns
MAD125.51 ns151.30 ns181.91 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/mean.svg new file mode 100644 index 0000000000000..7e38041184ca9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/mean.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 490 + + + + + 500 + + + + + 510 + + + + + 520 + + + + + 530 + + + + + 540 + + + + + 550 + + + + + 560 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab': mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/median.svg new file mode 100644 index 0000000000000..39615782a5cc3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/median.svg @@ -0,0 +1,313 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 0.018 + + + + + 0.02 + + + + + 480 + + + + + 500 + + + + + 520 + + + + + 540 + + + + + 560 + + + + + 580 + + + + + 600 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab': median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/pdf.svg new file mode 100644 index 0000000000000..42083fd059470 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/pdf.svg @@ -0,0 +1,385 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 0 + + + + + 200 + + + + + 400 + + + + + 600 + + + + + 800 + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab' + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + gnuplot_plot_5 + + + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/pdf_small.svg new file mode 100644 index 0000000000000..ce0431ca0e77c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/pdf_small.svg @@ -0,0 +1,199 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + 0 + + + + + 200 + + + + + 400 + + + + + 600 + + + + + 800 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/regression.svg new file mode 100644 index 0000000000000..ddd34fc2301ca --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/regression.svg @@ -0,0 +1,395 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab' + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/regression_small.svg new file mode 100644 index 0000000000000..9fb9b6f9f940b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/regression_small.svg @@ -0,0 +1,373 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/slope.svg new file mode 100644 index 0000000000000..07db372981cfb --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 570 + + + + + 580 + + + + + 590 + + + + + 600 + + + + + 610 + + + + + 620 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab': slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/typical.svg new file mode 100644 index 0000000000000..ddea92d176bdb --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/crate 'sharded-slab'/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 570 + + + + + 580 + + + + + 590 + + + + + 600 + + + + + 610 + + + + + 620 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab': typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/benchmark.json new file mode 100644 index 0000000000000..08bfb1e0dc54f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:1)","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll","title":"forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/estimates.json new file mode 100644 index 0000000000000..1cfa8070a7dec --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":43.567684912106856,"upper_bound":44.21017430441288},"point_estimate":43.87615702345391,"standard_error":0.16354022366156545},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":43.16295576049184,"upper_bound":43.962383689107824},"point_estimate":43.55279669492874,"standard_error":0.2061010390068694},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1.0330942804530792,"upper_bound":1.728427053902029},"point_estimate":1.4066168991903532,"standard_error":0.18325188684966132},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":43.37226305391049,"upper_bound":43.980657679933095},"point_estimate":43.67656815478769,"standard_error":0.15527534310694113},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1.2640920414657824,"upper_bound":2.0292487778370925},"point_estimate":1.644248185140106,"standard_error":0.19815347147111345}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/raw.csv new file mode 100644 index 0000000000000..54f532cf4eaa4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,173269.0,ns,4350 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,447608.0,ns,8700 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,576116.0,ns,13050 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,747393.0,ns,17400 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,1039757.0,ns,21750 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,1138810.0,ns,26100 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,1384921.0,ns,30450 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,1575725.0,ns,34800 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,1820576.0,ns,39150 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2119441.0,ns,43500 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2267234.0,ns,47850 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2254125.0,ns,52200 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2398810.0,ns,56550 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2560313.0,ns,60900 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2796726.0,ns,65250 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2964036.0,ns,69600 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,3299060.0,ns,73950 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,3349926.0,ns,78300 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,3510277.0,ns,82650 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,3816274.0,ns,87000 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,4280525.0,ns,91350 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,4051987.0,ns,95700 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,4429203.0,ns,100050 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,4429722.0,ns,104400 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,4691446.0,ns,108750 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,5004069.0,ns,113100 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,5223863.0,ns,117450 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,5281797.0,ns,121800 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,5582473.0,ns,126150 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,5977351.0,ns,130500 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,5943666.0,ns,134850 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,6245368.0,ns,139200 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,6467692.0,ns,143550 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,6239806.0,ns,147900 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,6733531.0,ns,152250 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,6741978.0,ns,156600 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,7064563.0,ns,160950 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,6959845.0,ns,165300 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,7326708.0,ns,169650 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,7812386.0,ns,174000 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,7775755.0,ns,178350 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,7760925.0,ns,182700 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,8027632.0,ns,187050 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,8232042.0,ns,191400 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,8673112.0,ns,195750 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9293244.0,ns,200100 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,8923370.0,ns,204450 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9683488.0,ns,208800 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9737349.0,ns,213150 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9376782.0,ns,217500 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9680957.0,ns,221850 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9706932.0,ns,226200 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9892848.0,ns,230550 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10155431.0,ns,234900 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10783272.0,ns,239250 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10174002.0,ns,243600 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10582369.0,ns,247950 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10683501.0,ns,252300 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10844104.0,ns,256650 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10994338.0,ns,261000 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,11997171.0,ns,265350 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,11722915.0,ns,269700 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,11654560.0,ns,274050 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,11991667.0,ns,278400 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,12079735.0,ns,282750 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13295008.0,ns,287100 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,12421998.0,ns,291450 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13023079.0,ns,295800 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13270661.0,ns,300150 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13221805.0,ns,304500 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13948700.0,ns,308850 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13703698.0,ns,313200 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,14239003.0,ns,317550 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,14005001.0,ns,321900 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,14046106.0,ns,326250 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,14415277.0,ns,330600 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13952922.0,ns,334950 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,14539858.0,ns,339300 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,14524904.0,ns,343650 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,15553757.0,ns,348000 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,15255782.0,ns,352350 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,15653219.0,ns,356700 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,15588887.0,ns,361050 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,16063855.0,ns,365400 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,15793640.0,ns,369750 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,16139961.0,ns,374100 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,16082835.0,ns,378450 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,16629009.0,ns,382800 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,17376752.0,ns,387150 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,17446343.0,ns,391500 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,17950406.0,ns,395850 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,18172706.0,ns,400200 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,17299421.0,ns,404550 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,18116587.0,ns,408900 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,18635384.0,ns,413250 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,18850090.0,ns,417600 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,17958544.0,ns,421950 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,17834472.0,ns,426300 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,19308178.0,ns,430650 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,18504180.0,ns,435000 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/sample.json new file mode 100644 index 0000000000000..2612eff02ebf0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[4350.0,8700.0,13050.0,17400.0,21750.0,26100.0,30450.0,34800.0,39150.0,43500.0,47850.0,52200.0,56550.0,60900.0,65250.0,69600.0,73950.0,78300.0,82650.0,87000.0,91350.0,95700.0,100050.0,104400.0,108750.0,113100.0,117450.0,121800.0,126150.0,130500.0,134850.0,139200.0,143550.0,147900.0,152250.0,156600.0,160950.0,165300.0,169650.0,174000.0,178350.0,182700.0,187050.0,191400.0,195750.0,200100.0,204450.0,208800.0,213150.0,217500.0,221850.0,226200.0,230550.0,234900.0,239250.0,243600.0,247950.0,252300.0,256650.0,261000.0,265350.0,269700.0,274050.0,278400.0,282750.0,287100.0,291450.0,295800.0,300150.0,304500.0,308850.0,313200.0,317550.0,321900.0,326250.0,330600.0,334950.0,339300.0,343650.0,348000.0,352350.0,356700.0,361050.0,365400.0,369750.0,374100.0,378450.0,382800.0,387150.0,391500.0,395850.0,400200.0,404550.0,408900.0,413250.0,417600.0,421950.0,426300.0,430650.0,435000.0],"times":[173269.0,447608.0,576116.0,747393.0,1039757.0,1138810.0,1384921.0,1575725.0,1820576.0,2119441.0,2267234.0,2254125.0,2398810.0,2560313.0,2796726.0,2964036.0,3299060.0,3349926.0,3510277.0,3816274.0,4280525.0,4051987.0,4429203.0,4429722.0,4691446.0,5004069.0,5223863.0,5281797.0,5582473.0,5977351.0,5943666.0,6245368.0,6467692.0,6239806.0,6733531.0,6741978.0,7064563.0,6959845.0,7326708.0,7812386.0,7775755.0,7760925.0,8027632.0,8232042.0,8673112.0,9293244.0,8923370.0,9683488.0,9737349.0,9376782.0,9680957.0,9706932.0,9892848.0,10155431.0,10783272.0,10174002.0,10582369.0,10683501.0,10844104.0,10994338.0,11997171.0,11722915.0,11654560.0,11991667.0,12079735.0,13295008.0,12421998.0,13023079.0,13270661.0,13221805.0,13948700.0,13703698.0,14239003.0,14005001.0,14046106.0,14415277.0,13952922.0,14539858.0,14524904.0,15553757.0,15255782.0,15653219.0,15588887.0,16063855.0,15793640.0,16139961.0,16082835.0,16629009.0,17376752.0,17446343.0,17950406.0,18172706.0,17299421.0,18116587.0,18635384.0,18850090.0,17958544.0,17834472.0,19308178.0,18504180.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/tukey.json new file mode 100644 index 0000000000000..9ebab5adaa876 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/base/tukey.json @@ -0,0 +1 @@ +[36.49989922935595,39.62603914435482,47.96241225101849,51.08855216601737] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/benchmark.json new file mode 100644 index 0000000000000..08bfb1e0dc54f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:1)","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll","title":"forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/estimates.json new file mode 100644 index 0000000000000..1cfa8070a7dec --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":43.567684912106856,"upper_bound":44.21017430441288},"point_estimate":43.87615702345391,"standard_error":0.16354022366156545},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":43.16295576049184,"upper_bound":43.962383689107824},"point_estimate":43.55279669492874,"standard_error":0.2061010390068694},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1.0330942804530792,"upper_bound":1.728427053902029},"point_estimate":1.4066168991903532,"standard_error":0.18325188684966132},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":43.37226305391049,"upper_bound":43.980657679933095},"point_estimate":43.67656815478769,"standard_error":0.15527534310694113},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1.2640920414657824,"upper_bound":2.0292487778370925},"point_estimate":1.644248185140106,"standard_error":0.19815347147111345}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/raw.csv new file mode 100644 index 0000000000000..54f532cf4eaa4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,173269.0,ns,4350 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,447608.0,ns,8700 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,576116.0,ns,13050 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,747393.0,ns,17400 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,1039757.0,ns,21750 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,1138810.0,ns,26100 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,1384921.0,ns,30450 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,1575725.0,ns,34800 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,1820576.0,ns,39150 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2119441.0,ns,43500 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2267234.0,ns,47850 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2254125.0,ns,52200 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2398810.0,ns,56550 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2560313.0,ns,60900 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2796726.0,ns,65250 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,2964036.0,ns,69600 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,3299060.0,ns,73950 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,3349926.0,ns,78300 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,3510277.0,ns,82650 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,3816274.0,ns,87000 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,4280525.0,ns,91350 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,4051987.0,ns,95700 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,4429203.0,ns,100050 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,4429722.0,ns,104400 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,4691446.0,ns,108750 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,5004069.0,ns,113100 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,5223863.0,ns,117450 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,5281797.0,ns,121800 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,5582473.0,ns,126150 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,5977351.0,ns,130500 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,5943666.0,ns,134850 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,6245368.0,ns,139200 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,6467692.0,ns,143550 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,6239806.0,ns,147900 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,6733531.0,ns,152250 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,6741978.0,ns,156600 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,7064563.0,ns,160950 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,6959845.0,ns,165300 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,7326708.0,ns,169650 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,7812386.0,ns,174000 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,7775755.0,ns,178350 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,7760925.0,ns,182700 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,8027632.0,ns,187050 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,8232042.0,ns,191400 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,8673112.0,ns,195750 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9293244.0,ns,200100 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,8923370.0,ns,204450 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9683488.0,ns,208800 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9737349.0,ns,213150 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9376782.0,ns,217500 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9680957.0,ns,221850 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9706932.0,ns,226200 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,9892848.0,ns,230550 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10155431.0,ns,234900 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10783272.0,ns,239250 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10174002.0,ns,243600 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10582369.0,ns,247950 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10683501.0,ns,252300 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10844104.0,ns,256650 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,10994338.0,ns,261000 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,11997171.0,ns,265350 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,11722915.0,ns,269700 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,11654560.0,ns,274050 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,11991667.0,ns,278400 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,12079735.0,ns,282750 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13295008.0,ns,287100 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,12421998.0,ns,291450 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13023079.0,ns,295800 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13270661.0,ns,300150 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13221805.0,ns,304500 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13948700.0,ns,308850 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13703698.0,ns,313200 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,14239003.0,ns,317550 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,14005001.0,ns,321900 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,14046106.0,ns,326250 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,14415277.0,ns,330600 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,13952922.0,ns,334950 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,14539858.0,ns,339300 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,14524904.0,ns,343650 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,15553757.0,ns,348000 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,15255782.0,ns,352350 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,15653219.0,ns,356700 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,15588887.0,ns,361050 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,16063855.0,ns,365400 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,15793640.0,ns,369750 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,16139961.0,ns,374100 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,16082835.0,ns,378450 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,16629009.0,ns,382800 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,17376752.0,ns,387150 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,17446343.0,ns,391500 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,17950406.0,ns,395850 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,18172706.0,ns,400200 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,17299421.0,ns,404550 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,18116587.0,ns,408900 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,18635384.0,ns,413250 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,18850090.0,ns,417600 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,17958544.0,ns,421950 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,17834472.0,ns,426300 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,19308178.0,ns,430650 +forward msg from pull (nb_writter:1 nb_readder:1),linear object poll,,,,18504180.0,ns,435000 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/sample.json new file mode 100644 index 0000000000000..2612eff02ebf0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[4350.0,8700.0,13050.0,17400.0,21750.0,26100.0,30450.0,34800.0,39150.0,43500.0,47850.0,52200.0,56550.0,60900.0,65250.0,69600.0,73950.0,78300.0,82650.0,87000.0,91350.0,95700.0,100050.0,104400.0,108750.0,113100.0,117450.0,121800.0,126150.0,130500.0,134850.0,139200.0,143550.0,147900.0,152250.0,156600.0,160950.0,165300.0,169650.0,174000.0,178350.0,182700.0,187050.0,191400.0,195750.0,200100.0,204450.0,208800.0,213150.0,217500.0,221850.0,226200.0,230550.0,234900.0,239250.0,243600.0,247950.0,252300.0,256650.0,261000.0,265350.0,269700.0,274050.0,278400.0,282750.0,287100.0,291450.0,295800.0,300150.0,304500.0,308850.0,313200.0,317550.0,321900.0,326250.0,330600.0,334950.0,339300.0,343650.0,348000.0,352350.0,356700.0,361050.0,365400.0,369750.0,374100.0,378450.0,382800.0,387150.0,391500.0,395850.0,400200.0,404550.0,408900.0,413250.0,417600.0,421950.0,426300.0,430650.0,435000.0],"times":[173269.0,447608.0,576116.0,747393.0,1039757.0,1138810.0,1384921.0,1575725.0,1820576.0,2119441.0,2267234.0,2254125.0,2398810.0,2560313.0,2796726.0,2964036.0,3299060.0,3349926.0,3510277.0,3816274.0,4280525.0,4051987.0,4429203.0,4429722.0,4691446.0,5004069.0,5223863.0,5281797.0,5582473.0,5977351.0,5943666.0,6245368.0,6467692.0,6239806.0,6733531.0,6741978.0,7064563.0,6959845.0,7326708.0,7812386.0,7775755.0,7760925.0,8027632.0,8232042.0,8673112.0,9293244.0,8923370.0,9683488.0,9737349.0,9376782.0,9680957.0,9706932.0,9892848.0,10155431.0,10783272.0,10174002.0,10582369.0,10683501.0,10844104.0,10994338.0,11997171.0,11722915.0,11654560.0,11991667.0,12079735.0,13295008.0,12421998.0,13023079.0,13270661.0,13221805.0,13948700.0,13703698.0,14239003.0,14005001.0,14046106.0,14415277.0,13952922.0,14539858.0,14524904.0,15553757.0,15255782.0,15653219.0,15588887.0,16063855.0,15793640.0,16139961.0,16082835.0,16629009.0,17376752.0,17446343.0,17950406.0,18172706.0,17299421.0,18116587.0,18635384.0,18850090.0,17958544.0,17834472.0,19308178.0,18504180.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/tukey.json new file mode 100644 index 0000000000000..9ebab5adaa876 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/new/tukey.json @@ -0,0 +1 @@ +[36.49989922935595,39.62603914435482,47.96241225101849,51.08855216601737] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/MAD.svg new file mode 100644 index 0000000000000..a75905b949d1a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 1 + + + + + 1.1 + + + + + 1.2 + + + + + 1.3 + + + + + 1.4 + + + + + 1.5 + + + + + 1.6 + + + + + 1.7 + + + + + 1.8 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/SD.svg new file mode 100644 index 0000000000000..ada401c14680d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/SD.svg @@ -0,0 +1,328 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + 1.8 + + + + + 2 + + + + + 1.2 + + + + + 1.3 + + + + + 1.4 + + + + + 1.5 + + + + + 1.6 + + + + + 1.7 + + + + + 1.8 + + + + + 1.9 + + + + + 2 + + + + + 2.1 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/index.html new file mode 100644 index 0000000000000..d78d2fb53e252 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope43.372 ns43.677 ns43.981 ns
0.89467560.90070120.8946841
Mean43.568 ns43.876 ns44.210 ns
Std. Dev.1.2641 ns1.6442 ns2.0292 ns
Median43.163 ns43.553 ns43.962 ns
MAD1.0331 ns1.4066 ns1.7284 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/mean.svg new file mode 100644 index 0000000000000..29081706283fb --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 43.5 + + + + + 43.6 + + + + + 43.7 + + + + + 43.8 + + + + + 43.9 + + + + + 44 + + + + + 44.1 + + + + + 44.2 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/median.svg new file mode 100644 index 0000000000000..cc7c3c98f02d3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/median.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 4 + + + + + 43.1 + + + + + 43.2 + + + + + 43.3 + + + + + 43.4 + + + + + 43.5 + + + + + 43.6 + + + + + 43.7 + + + + + 43.8 + + + + + 43.9 + + + + + 44 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/pdf.svg new file mode 100644 index 0000000000000..394a0fefbeb0b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/pdf.svg @@ -0,0 +1,435 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 250 + + + + + 300 + + + + + 350 + + + + + 400 + + + + + 38 + + + + + 40 + + + + + 42 + + + + + 44 + + + + + 46 + + + + + 48 + + + + + 50 + + + + + 52 + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..3790572f05ab0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/pdf_small.svg @@ -0,0 +1,219 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 38 + + + + + 40 + + + + + 42 + + + + + 44 + + + + + 46 + + + + + 48 + + + + + 50 + + + + + 52 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/regression.svg new file mode 100644 index 0000000000000..3de44076d042d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/regression.svg @@ -0,0 +1,486 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 150 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 250 + + + + + + + + + + + + + 300 + + + + + + + + + + + + + 350 + + + + + + + + + + + + + 400 + + + + + + + + + + + + + 450 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/regression_small.svg new file mode 100644 index 0000000000000..52ad2538e2325 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/regression_small.svg @@ -0,0 +1,464 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 150 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 250 + + + + + + + + + + + + + 300 + + + + + + + + + + + + + 350 + + + + + + + + + + + + + 400 + + + + + + + + + + + + + 450 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/slope.svg new file mode 100644 index 0000000000000..e1ad14e842938 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 43.4 + + + + + 43.5 + + + + + 43.6 + + + + + 43.7 + + + + + 43.8 + + + + + 43.9 + + + + + 44 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/typical.svg new file mode 100644 index 0000000000000..2b8684b0b7210 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/linear object poll/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 43.4 + + + + + 43.5 + + + + + 43.6 + + + + + 43.7 + + + + + 43.8 + + + + + 43.9 + + + + + 44 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/benchmark.json new file mode 100644 index 0000000000000..822ed8ebdd8cd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:1)","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll","title":"forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/estimates.json new file mode 100644 index 0000000000000..cc8e70c97080c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":378.33507268028114,"upper_bound":478.8615327445553},"point_estimate":429.28855367276265,"standard_error":25.710320732540158},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":585.1895910641749,"upper_bound":621.776784199198},"point_estimate":616.0404279877964,"standard_error":21.43272539784937},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":23.2705623249377,"upper_bound":88.07950914815362},"point_estimate":33.493202593855926,"standard_error":28.002510426728442},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":565.5089705919818,"upper_bound":606.8256004251571},"point_estimate":589.1719700129216,"standard_error":10.581863639396115},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":235.58263292311685,"upper_bound":270.93111596382465},"point_estimate":257.84662414993386,"standard_error":9.051397113154165}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/raw.csv new file mode 100644 index 0000000000000..ab3777043163f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,187140.0,ns,297 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,40573.0,ns,594 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,264889.0,ns,891 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,79422.0,ns,1188 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,90761.0,ns,1485 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,220639.0,ns,1782 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,109752.0,ns,2079 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,142421.0,ns,2376 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,167358.0,ns,2673 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,181151.0,ns,2970 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,237516.0,ns,3267 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,236130.0,ns,3564 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,235649.0,ns,3861 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,840196.0,ns,4158 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,290101.0,ns,4455 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,251178.0,ns,4752 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,277158.0,ns,5049 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,315019.0,ns,5346 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,323967.0,ns,5643 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,385517.0,ns,5940 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,359441.0,ns,6237 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,720136.0,ns,6534 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,374751.0,ns,6831 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,376465.0,ns,7128 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,401680.0,ns,7425 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,411954.0,ns,7722 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,464979.0,ns,8019 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,446807.0,ns,8316 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,1089808.0,ns,8613 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,5514603.0,ns,8910 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,5497044.0,ns,9207 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,4261442.0,ns,9504 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,4697081.0,ns,9801 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,6002304.0,ns,10098 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,6442582.0,ns,10395 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,6521193.0,ns,10692 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,6759809.0,ns,10989 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,7063042.0,ns,11286 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,7206906.0,ns,11583 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,7339950.0,ns,11880 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,1648901.0,ns,12177 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,1054062.0,ns,12474 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,673484.0,ns,12771 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,703559.0,ns,13068 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,1079597.0,ns,13365 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,2611448.0,ns,13662 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,8753509.0,ns,13959 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,8691009.0,ns,14256 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,9075460.0,ns,14553 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,3520806.0,ns,14850 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,7880208.0,ns,15147 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,9691738.0,ns,15444 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,9066406.0,ns,15741 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,9830250.0,ns,16038 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,10169387.0,ns,16335 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,10428758.0,ns,16632 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,10444137.0,ns,16929 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,10703491.0,ns,17226 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,5084120.0,ns,17523 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,11039620.0,ns,17820 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,11374092.0,ns,18117 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,11035401.0,ns,18414 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,11179190.0,ns,18711 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,11793613.0,ns,19008 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,12086234.0,ns,19305 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,12108728.0,ns,19602 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,12674925.0,ns,19899 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,12550715.0,ns,20196 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,12916721.0,ns,20493 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,12996690.0,ns,20790 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,13264203.0,ns,21087 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,13613092.0,ns,21384 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,13411841.0,ns,21681 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,13886141.0,ns,21978 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,14112014.0,ns,22275 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,14413358.0,ns,22572 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,14577208.0,ns,22869 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,14499984.0,ns,23166 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,14936957.0,ns,23463 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,15017475.0,ns,23760 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,15024858.0,ns,24057 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,15714838.0,ns,24354 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,15382704.0,ns,24651 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,15328950.0,ns,24948 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,14843482.0,ns,25245 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,16222819.0,ns,25542 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,16325132.0,ns,25839 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,16773317.0,ns,26136 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,16892442.0,ns,26433 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,17047171.0,ns,26730 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,16921066.0,ns,27027 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,17654683.0,ns,27324 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,17626042.0,ns,27621 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,17941415.0,ns,27918 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,18272769.0,ns,28215 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,17965192.0,ns,28512 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,18468221.0,ns,28809 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,18639887.0,ns,29106 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,18780056.0,ns,29403 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,18812088.0,ns,29700 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/sample.json new file mode 100644 index 0000000000000..deda948a466e9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[297.0,594.0,891.0,1188.0,1485.0,1782.0,2079.0,2376.0,2673.0,2970.0,3267.0,3564.0,3861.0,4158.0,4455.0,4752.0,5049.0,5346.0,5643.0,5940.0,6237.0,6534.0,6831.0,7128.0,7425.0,7722.0,8019.0,8316.0,8613.0,8910.0,9207.0,9504.0,9801.0,10098.0,10395.0,10692.0,10989.0,11286.0,11583.0,11880.0,12177.0,12474.0,12771.0,13068.0,13365.0,13662.0,13959.0,14256.0,14553.0,14850.0,15147.0,15444.0,15741.0,16038.0,16335.0,16632.0,16929.0,17226.0,17523.0,17820.0,18117.0,18414.0,18711.0,19008.0,19305.0,19602.0,19899.0,20196.0,20493.0,20790.0,21087.0,21384.0,21681.0,21978.0,22275.0,22572.0,22869.0,23166.0,23463.0,23760.0,24057.0,24354.0,24651.0,24948.0,25245.0,25542.0,25839.0,26136.0,26433.0,26730.0,27027.0,27324.0,27621.0,27918.0,28215.0,28512.0,28809.0,29106.0,29403.0,29700.0],"times":[187140.0,40573.0,264889.0,79422.0,90761.0,220639.0,109752.0,142421.0,167358.0,181151.0,237516.0,236130.0,235649.0,840196.0,290101.0,251178.0,277158.0,315019.0,323967.0,385517.0,359441.0,720136.0,374751.0,376465.0,401680.0,411954.0,464979.0,446807.0,1089808.0,5514603.0,5497044.0,4261442.0,4697081.0,6002304.0,6442582.0,6521193.0,6759809.0,7063042.0,7206906.0,7339950.0,1648901.0,1054062.0,673484.0,703559.0,1079597.0,2611448.0,8753509.0,8691009.0,9075460.0,3520806.0,7880208.0,9691738.0,9066406.0,9830250.0,10169387.0,10428758.0,10444137.0,10703491.0,5084120.0,11039620.0,11374092.0,11035401.0,11179190.0,11793613.0,12086234.0,12108728.0,12674925.0,12550715.0,12916721.0,12996690.0,13264203.0,13613092.0,13411841.0,13886141.0,14112014.0,14413358.0,14577208.0,14499984.0,14936957.0,15017475.0,15024858.0,15714838.0,15382704.0,15328950.0,14843482.0,16222819.0,16325132.0,16773317.0,16892442.0,17047171.0,16921066.0,17654683.0,17626042.0,17941415.0,18272769.0,17965192.0,18468221.0,18639887.0,18780056.0,18812088.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/tukey.json new file mode 100644 index 0000000000000..2c07f4193b9cd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/base/tukey.json @@ -0,0 +1 @@ +[-1572.8351070636654,-747.0381356152936,1455.0871215803647,2280.8840930287365] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/benchmark.json new file mode 100644 index 0000000000000..822ed8ebdd8cd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:1)","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll","title":"forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/estimates.json new file mode 100644 index 0000000000000..cc8e70c97080c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":378.33507268028114,"upper_bound":478.8615327445553},"point_estimate":429.28855367276265,"standard_error":25.710320732540158},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":585.1895910641749,"upper_bound":621.776784199198},"point_estimate":616.0404279877964,"standard_error":21.43272539784937},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":23.2705623249377,"upper_bound":88.07950914815362},"point_estimate":33.493202593855926,"standard_error":28.002510426728442},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":565.5089705919818,"upper_bound":606.8256004251571},"point_estimate":589.1719700129216,"standard_error":10.581863639396115},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":235.58263292311685,"upper_bound":270.93111596382465},"point_estimate":257.84662414993386,"standard_error":9.051397113154165}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/raw.csv new file mode 100644 index 0000000000000..ab3777043163f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,187140.0,ns,297 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,40573.0,ns,594 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,264889.0,ns,891 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,79422.0,ns,1188 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,90761.0,ns,1485 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,220639.0,ns,1782 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,109752.0,ns,2079 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,142421.0,ns,2376 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,167358.0,ns,2673 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,181151.0,ns,2970 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,237516.0,ns,3267 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,236130.0,ns,3564 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,235649.0,ns,3861 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,840196.0,ns,4158 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,290101.0,ns,4455 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,251178.0,ns,4752 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,277158.0,ns,5049 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,315019.0,ns,5346 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,323967.0,ns,5643 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,385517.0,ns,5940 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,359441.0,ns,6237 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,720136.0,ns,6534 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,374751.0,ns,6831 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,376465.0,ns,7128 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,401680.0,ns,7425 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,411954.0,ns,7722 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,464979.0,ns,8019 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,446807.0,ns,8316 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,1089808.0,ns,8613 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,5514603.0,ns,8910 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,5497044.0,ns,9207 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,4261442.0,ns,9504 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,4697081.0,ns,9801 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,6002304.0,ns,10098 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,6442582.0,ns,10395 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,6521193.0,ns,10692 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,6759809.0,ns,10989 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,7063042.0,ns,11286 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,7206906.0,ns,11583 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,7339950.0,ns,11880 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,1648901.0,ns,12177 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,1054062.0,ns,12474 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,673484.0,ns,12771 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,703559.0,ns,13068 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,1079597.0,ns,13365 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,2611448.0,ns,13662 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,8753509.0,ns,13959 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,8691009.0,ns,14256 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,9075460.0,ns,14553 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,3520806.0,ns,14850 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,7880208.0,ns,15147 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,9691738.0,ns,15444 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,9066406.0,ns,15741 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,9830250.0,ns,16038 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,10169387.0,ns,16335 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,10428758.0,ns,16632 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,10444137.0,ns,16929 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,10703491.0,ns,17226 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,5084120.0,ns,17523 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,11039620.0,ns,17820 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,11374092.0,ns,18117 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,11035401.0,ns,18414 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,11179190.0,ns,18711 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,11793613.0,ns,19008 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,12086234.0,ns,19305 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,12108728.0,ns,19602 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,12674925.0,ns,19899 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,12550715.0,ns,20196 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,12916721.0,ns,20493 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,12996690.0,ns,20790 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,13264203.0,ns,21087 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,13613092.0,ns,21384 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,13411841.0,ns,21681 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,13886141.0,ns,21978 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,14112014.0,ns,22275 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,14413358.0,ns,22572 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,14577208.0,ns,22869 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,14499984.0,ns,23166 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,14936957.0,ns,23463 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,15017475.0,ns,23760 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,15024858.0,ns,24057 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,15714838.0,ns,24354 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,15382704.0,ns,24651 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,15328950.0,ns,24948 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,14843482.0,ns,25245 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,16222819.0,ns,25542 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,16325132.0,ns,25839 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,16773317.0,ns,26136 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,16892442.0,ns,26433 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,17047171.0,ns,26730 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,16921066.0,ns,27027 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,17654683.0,ns,27324 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,17626042.0,ns,27621 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,17941415.0,ns,27918 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,18272769.0,ns,28215 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,17965192.0,ns,28512 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,18468221.0,ns,28809 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,18639887.0,ns,29106 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,18780056.0,ns,29403 +forward msg from pull (nb_writter:1 nb_readder:1),mutex object poll,,,,18812088.0,ns,29700 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/sample.json new file mode 100644 index 0000000000000..deda948a466e9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[297.0,594.0,891.0,1188.0,1485.0,1782.0,2079.0,2376.0,2673.0,2970.0,3267.0,3564.0,3861.0,4158.0,4455.0,4752.0,5049.0,5346.0,5643.0,5940.0,6237.0,6534.0,6831.0,7128.0,7425.0,7722.0,8019.0,8316.0,8613.0,8910.0,9207.0,9504.0,9801.0,10098.0,10395.0,10692.0,10989.0,11286.0,11583.0,11880.0,12177.0,12474.0,12771.0,13068.0,13365.0,13662.0,13959.0,14256.0,14553.0,14850.0,15147.0,15444.0,15741.0,16038.0,16335.0,16632.0,16929.0,17226.0,17523.0,17820.0,18117.0,18414.0,18711.0,19008.0,19305.0,19602.0,19899.0,20196.0,20493.0,20790.0,21087.0,21384.0,21681.0,21978.0,22275.0,22572.0,22869.0,23166.0,23463.0,23760.0,24057.0,24354.0,24651.0,24948.0,25245.0,25542.0,25839.0,26136.0,26433.0,26730.0,27027.0,27324.0,27621.0,27918.0,28215.0,28512.0,28809.0,29106.0,29403.0,29700.0],"times":[187140.0,40573.0,264889.0,79422.0,90761.0,220639.0,109752.0,142421.0,167358.0,181151.0,237516.0,236130.0,235649.0,840196.0,290101.0,251178.0,277158.0,315019.0,323967.0,385517.0,359441.0,720136.0,374751.0,376465.0,401680.0,411954.0,464979.0,446807.0,1089808.0,5514603.0,5497044.0,4261442.0,4697081.0,6002304.0,6442582.0,6521193.0,6759809.0,7063042.0,7206906.0,7339950.0,1648901.0,1054062.0,673484.0,703559.0,1079597.0,2611448.0,8753509.0,8691009.0,9075460.0,3520806.0,7880208.0,9691738.0,9066406.0,9830250.0,10169387.0,10428758.0,10444137.0,10703491.0,5084120.0,11039620.0,11374092.0,11035401.0,11179190.0,11793613.0,12086234.0,12108728.0,12674925.0,12550715.0,12916721.0,12996690.0,13264203.0,13613092.0,13411841.0,13886141.0,14112014.0,14413358.0,14577208.0,14499984.0,14936957.0,15017475.0,15024858.0,15714838.0,15382704.0,15328950.0,14843482.0,16222819.0,16325132.0,16773317.0,16892442.0,17047171.0,16921066.0,17654683.0,17626042.0,17941415.0,18272769.0,17965192.0,18468221.0,18639887.0,18780056.0,18812088.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/tukey.json new file mode 100644 index 0000000000000..2c07f4193b9cd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/new/tukey.json @@ -0,0 +1 @@ +[-1572.8351070636654,-747.0381356152936,1455.0871215803647,2280.8840930287365] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/MAD.svg new file mode 100644 index 0000000000000..b2c4a05d6f8a0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 70 + + + + + 80 + + + + + 90 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/SD.svg new file mode 100644 index 0000000000000..d965227a4af9e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/SD.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 0.04 + + + + + 0.045 + + + + + 0.05 + + + + + 235 + + + + + 240 + + + + + 245 + + + + + 250 + + + + + 255 + + + + + 260 + + + + + 265 + + + + + 270 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/index.html new file mode 100644 index 0000000000000..8eee12851e628 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope565.51 ns589.17 ns606.83 ns
0.16713010.17131610.1689607
Mean378.34 ns429.29 ns478.86 ns
Std. Dev.235.58 ns257.85 ns270.93 ns
Median585.19 ns616.04 ns621.78 ns
MAD23.271 ns33.493 ns88.080 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/mean.svg new file mode 100644 index 0000000000000..aa6e98ff5c129 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/mean.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 380 + + + + + 400 + + + + + 420 + + + + + 440 + + + + + 460 + + + + + 480 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/median.svg new file mode 100644 index 0000000000000..08baa34ec3845 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/median.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 0.08 + + + + + 0.09 + + + + + 585 + + + + + 590 + + + + + 595 + + + + + 600 + + + + + 605 + + + + + 610 + + + + + 615 + + + + + 620 + + + + + 625 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/pdf.svg new file mode 100644 index 0000000000000..62de5c74933a4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/pdf.svg @@ -0,0 +1,385 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + -200 + + + + + 0 + + + + + 200 + + + + + 400 + + + + + 600 + + + + + 800 + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..819ab7318e4d4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/pdf_small.svg @@ -0,0 +1,204 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + -200 + + + + + 0 + + + + + 200 + + + + + 400 + + + + + 600 + + + + + 800 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/regression.svg new file mode 100644 index 0000000000000..054da56fb75ea --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/regression.svg @@ -0,0 +1,447 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/regression_small.svg new file mode 100644 index 0000000000000..7287ccba98006 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/regression_small.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/slope.svg new file mode 100644 index 0000000000000..e9e1fba89175f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 0.04 + + + + + 570 + + + + + 580 + + + + + 590 + + + + + 600 + + + + + 610 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/typical.svg new file mode 100644 index 0000000000000..b66e4c55d0391 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/mutex object poll/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 0.04 + + + + + 570 + + + + + 580 + + + + + 590 + + + + + 600 + + + + + 610 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/benchmark.json new file mode 100644 index 0000000000000..d7d777162d231 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:1)","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:1)/none object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_1)/none object poll","title":"forward msg from pull (nb_writter:1 nb_readder:1)/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/estimates.json new file mode 100644 index 0000000000000..d6cf24a4c2069 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":486.1070641727977,"upper_bound":570.8353989275365},"point_estimate":529.7525623568481,"standard_error":21.67116375447838},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":629.2301316431009,"upper_bound":653.5656282947239},"point_estimate":646.294063118864,"standard_error":6.167515457675817},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":28.56036559233413,"upper_bound":67.52969045860011},"point_estimate":40.952368601732836,"standard_error":10.318623899727433},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":619.9109383071217,"upper_bound":648.1961941383115},"point_estimate":635.5392820609553,"standard_error":7.226834558157612},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":181.91316442375768,"upper_bound":244.40769339391812},"point_estimate":217.93173911343712,"standard_error":16.014831202042448}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/raw.csv new file mode 100644 index 0000000000000..cbc1917345842 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,183153.0,ns,293 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,225213.0,ns,586 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,71252.0,ns,879 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,205255.0,ns,1172 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,1020654.0,ns,1465 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,165196.0,ns,1758 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,198080.0,ns,2051 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,451257.0,ns,2344 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,461267.0,ns,2637 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,179795.0,ns,2930 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,351584.0,ns,3223 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,244306.0,ns,3516 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,372651.0,ns,3809 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,280248.0,ns,4102 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,251071.0,ns,4395 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,922220.0,ns,4688 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,398092.0,ns,4981 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,451252.0,ns,5274 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,365628.0,ns,5567 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,442260.0,ns,5860 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,452060.0,ns,6153 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,1331672.0,ns,6446 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,4747510.0,ns,6739 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,4243215.0,ns,7032 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,1223012.0,ns,7325 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,4817418.0,ns,7618 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,5108238.0,ns,7911 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,5323249.0,ns,8204 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,5469845.0,ns,8497 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,5670607.0,ns,8790 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,5929943.0,ns,9083 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6191600.0,ns,9376 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6332604.0,ns,9669 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6522148.0,ns,9962 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6649963.0,ns,10255 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6887347.0,ns,10548 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6392440.0,ns,10841 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7389423.0,ns,11134 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7569908.0,ns,11427 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7704124.0,ns,11720 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7937342.0,ns,12013 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7853989.0,ns,12306 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,8396900.0,ns,12599 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,8350803.0,ns,12892 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,8796916.0,ns,13185 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,8195366.0,ns,13478 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6842448.0,ns,13771 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7619979.0,ns,14064 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,9136622.0,ns,14357 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,9244002.0,ns,14650 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,9995473.0,ns,14943 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,10020733.0,ns,15236 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7962586.0,ns,15529 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,8423507.0,ns,15822 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,10647389.0,ns,16115 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,10324408.0,ns,16408 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,11131415.0,ns,16701 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,11169510.0,ns,16994 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,9187908.0,ns,17287 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,12006204.0,ns,17580 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,8451043.0,ns,17873 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,9177127.0,ns,18166 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,12475610.0,ns,18459 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,12556690.0,ns,18752 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,10099125.0,ns,19045 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,12778102.0,ns,19338 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,10753628.0,ns,19631 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13370283.0,ns,19924 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13008537.0,ns,20217 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,12674004.0,ns,20510 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13580442.0,ns,20803 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,14156750.0,ns,21096 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13971088.0,ns,21389 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,14497041.0,ns,21682 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,14565542.0,ns,21975 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13150921.0,ns,22268 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13818440.0,ns,22561 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,14993636.0,ns,22854 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,14556174.0,ns,23147 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,15773967.0,ns,23440 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,15352280.0,ns,23733 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,16171965.0,ns,24026 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,15604878.0,ns,24319 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,16007213.0,ns,24612 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,16976999.0,ns,24905 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,16302995.0,ns,25198 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,17289784.0,ns,25491 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,16983443.0,ns,25784 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,17831893.0,ns,26077 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,17751932.0,ns,26370 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,17442358.0,ns,26663 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,18192973.0,ns,26956 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,18626473.0,ns,27249 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,17262765.0,ns,27542 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13610216.0,ns,27835 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,19053052.0,ns,28128 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,18950870.0,ns,28421 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,19497457.0,ns,28714 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,20211847.0,ns,29007 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,19882846.0,ns,29300 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/sample.json new file mode 100644 index 0000000000000..bac067c3fc99b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[293.0,586.0,879.0,1172.0,1465.0,1758.0,2051.0,2344.0,2637.0,2930.0,3223.0,3516.0,3809.0,4102.0,4395.0,4688.0,4981.0,5274.0,5567.0,5860.0,6153.0,6446.0,6739.0,7032.0,7325.0,7618.0,7911.0,8204.0,8497.0,8790.0,9083.0,9376.0,9669.0,9962.0,10255.0,10548.0,10841.0,11134.0,11427.0,11720.0,12013.0,12306.0,12599.0,12892.0,13185.0,13478.0,13771.0,14064.0,14357.0,14650.0,14943.0,15236.0,15529.0,15822.0,16115.0,16408.0,16701.0,16994.0,17287.0,17580.0,17873.0,18166.0,18459.0,18752.0,19045.0,19338.0,19631.0,19924.0,20217.0,20510.0,20803.0,21096.0,21389.0,21682.0,21975.0,22268.0,22561.0,22854.0,23147.0,23440.0,23733.0,24026.0,24319.0,24612.0,24905.0,25198.0,25491.0,25784.0,26077.0,26370.0,26663.0,26956.0,27249.0,27542.0,27835.0,28128.0,28421.0,28714.0,29007.0,29300.0],"times":[183153.0,225213.0,71252.0,205255.0,1020654.0,165196.0,198080.0,451257.0,461267.0,179795.0,351584.0,244306.0,372651.0,280248.0,251071.0,922220.0,398092.0,451252.0,365628.0,442260.0,452060.0,1331672.0,4747510.0,4243215.0,1223012.0,4817418.0,5108238.0,5323249.0,5469845.0,5670607.0,5929943.0,6191600.0,6332604.0,6522148.0,6649963.0,6887347.0,6392440.0,7389423.0,7569908.0,7704124.0,7937342.0,7853989.0,8396900.0,8350803.0,8796916.0,8195366.0,6842448.0,7619979.0,9136622.0,9244002.0,9995473.0,10020733.0,7962586.0,8423507.0,10647389.0,10324408.0,11131415.0,11169510.0,9187908.0,12006204.0,8451043.0,9177127.0,12475610.0,12556690.0,10099125.0,12778102.0,10753628.0,13370283.0,13008537.0,12674004.0,13580442.0,14156750.0,13971088.0,14497041.0,14565542.0,13150921.0,13818440.0,14993636.0,14556174.0,15773967.0,15352280.0,16171965.0,15604878.0,16007213.0,16976999.0,16302995.0,17289784.0,16983443.0,17831893.0,17751932.0,17442358.0,18192973.0,18626473.0,17262765.0,13610216.0,19053052.0,18950870.0,19497457.0,20211847.0,19882846.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/tukey.json new file mode 100644 index 0000000000000..ba11dc258cada --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/base/tukey.json @@ -0,0 +1 @@ +[50.31197738621029,280.5871288439987,894.6541993981011,1124.9293508558894] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/benchmark.json new file mode 100644 index 0000000000000..d7d777162d231 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:1)","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:1)/none object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_1)/none object poll","title":"forward msg from pull (nb_writter:1 nb_readder:1)/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/estimates.json new file mode 100644 index 0000000000000..d6cf24a4c2069 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":486.1070641727977,"upper_bound":570.8353989275365},"point_estimate":529.7525623568481,"standard_error":21.67116375447838},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":629.2301316431009,"upper_bound":653.5656282947239},"point_estimate":646.294063118864,"standard_error":6.167515457675817},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":28.56036559233413,"upper_bound":67.52969045860011},"point_estimate":40.952368601732836,"standard_error":10.318623899727433},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":619.9109383071217,"upper_bound":648.1961941383115},"point_estimate":635.5392820609553,"standard_error":7.226834558157612},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":181.91316442375768,"upper_bound":244.40769339391812},"point_estimate":217.93173911343712,"standard_error":16.014831202042448}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/raw.csv new file mode 100644 index 0000000000000..cbc1917345842 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,183153.0,ns,293 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,225213.0,ns,586 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,71252.0,ns,879 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,205255.0,ns,1172 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,1020654.0,ns,1465 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,165196.0,ns,1758 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,198080.0,ns,2051 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,451257.0,ns,2344 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,461267.0,ns,2637 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,179795.0,ns,2930 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,351584.0,ns,3223 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,244306.0,ns,3516 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,372651.0,ns,3809 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,280248.0,ns,4102 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,251071.0,ns,4395 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,922220.0,ns,4688 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,398092.0,ns,4981 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,451252.0,ns,5274 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,365628.0,ns,5567 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,442260.0,ns,5860 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,452060.0,ns,6153 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,1331672.0,ns,6446 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,4747510.0,ns,6739 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,4243215.0,ns,7032 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,1223012.0,ns,7325 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,4817418.0,ns,7618 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,5108238.0,ns,7911 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,5323249.0,ns,8204 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,5469845.0,ns,8497 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,5670607.0,ns,8790 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,5929943.0,ns,9083 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6191600.0,ns,9376 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6332604.0,ns,9669 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6522148.0,ns,9962 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6649963.0,ns,10255 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6887347.0,ns,10548 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6392440.0,ns,10841 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7389423.0,ns,11134 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7569908.0,ns,11427 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7704124.0,ns,11720 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7937342.0,ns,12013 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7853989.0,ns,12306 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,8396900.0,ns,12599 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,8350803.0,ns,12892 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,8796916.0,ns,13185 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,8195366.0,ns,13478 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,6842448.0,ns,13771 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7619979.0,ns,14064 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,9136622.0,ns,14357 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,9244002.0,ns,14650 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,9995473.0,ns,14943 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,10020733.0,ns,15236 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,7962586.0,ns,15529 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,8423507.0,ns,15822 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,10647389.0,ns,16115 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,10324408.0,ns,16408 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,11131415.0,ns,16701 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,11169510.0,ns,16994 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,9187908.0,ns,17287 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,12006204.0,ns,17580 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,8451043.0,ns,17873 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,9177127.0,ns,18166 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,12475610.0,ns,18459 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,12556690.0,ns,18752 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,10099125.0,ns,19045 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,12778102.0,ns,19338 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,10753628.0,ns,19631 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13370283.0,ns,19924 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13008537.0,ns,20217 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,12674004.0,ns,20510 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13580442.0,ns,20803 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,14156750.0,ns,21096 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13971088.0,ns,21389 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,14497041.0,ns,21682 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,14565542.0,ns,21975 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13150921.0,ns,22268 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13818440.0,ns,22561 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,14993636.0,ns,22854 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,14556174.0,ns,23147 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,15773967.0,ns,23440 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,15352280.0,ns,23733 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,16171965.0,ns,24026 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,15604878.0,ns,24319 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,16007213.0,ns,24612 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,16976999.0,ns,24905 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,16302995.0,ns,25198 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,17289784.0,ns,25491 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,16983443.0,ns,25784 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,17831893.0,ns,26077 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,17751932.0,ns,26370 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,17442358.0,ns,26663 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,18192973.0,ns,26956 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,18626473.0,ns,27249 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,17262765.0,ns,27542 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,13610216.0,ns,27835 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,19053052.0,ns,28128 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,18950870.0,ns,28421 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,19497457.0,ns,28714 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,20211847.0,ns,29007 +forward msg from pull (nb_writter:1 nb_readder:1),none object poll,,,,19882846.0,ns,29300 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/sample.json new file mode 100644 index 0000000000000..bac067c3fc99b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[293.0,586.0,879.0,1172.0,1465.0,1758.0,2051.0,2344.0,2637.0,2930.0,3223.0,3516.0,3809.0,4102.0,4395.0,4688.0,4981.0,5274.0,5567.0,5860.0,6153.0,6446.0,6739.0,7032.0,7325.0,7618.0,7911.0,8204.0,8497.0,8790.0,9083.0,9376.0,9669.0,9962.0,10255.0,10548.0,10841.0,11134.0,11427.0,11720.0,12013.0,12306.0,12599.0,12892.0,13185.0,13478.0,13771.0,14064.0,14357.0,14650.0,14943.0,15236.0,15529.0,15822.0,16115.0,16408.0,16701.0,16994.0,17287.0,17580.0,17873.0,18166.0,18459.0,18752.0,19045.0,19338.0,19631.0,19924.0,20217.0,20510.0,20803.0,21096.0,21389.0,21682.0,21975.0,22268.0,22561.0,22854.0,23147.0,23440.0,23733.0,24026.0,24319.0,24612.0,24905.0,25198.0,25491.0,25784.0,26077.0,26370.0,26663.0,26956.0,27249.0,27542.0,27835.0,28128.0,28421.0,28714.0,29007.0,29300.0],"times":[183153.0,225213.0,71252.0,205255.0,1020654.0,165196.0,198080.0,451257.0,461267.0,179795.0,351584.0,244306.0,372651.0,280248.0,251071.0,922220.0,398092.0,451252.0,365628.0,442260.0,452060.0,1331672.0,4747510.0,4243215.0,1223012.0,4817418.0,5108238.0,5323249.0,5469845.0,5670607.0,5929943.0,6191600.0,6332604.0,6522148.0,6649963.0,6887347.0,6392440.0,7389423.0,7569908.0,7704124.0,7937342.0,7853989.0,8396900.0,8350803.0,8796916.0,8195366.0,6842448.0,7619979.0,9136622.0,9244002.0,9995473.0,10020733.0,7962586.0,8423507.0,10647389.0,10324408.0,11131415.0,11169510.0,9187908.0,12006204.0,8451043.0,9177127.0,12475610.0,12556690.0,10099125.0,12778102.0,10753628.0,13370283.0,13008537.0,12674004.0,13580442.0,14156750.0,13971088.0,14497041.0,14565542.0,13150921.0,13818440.0,14993636.0,14556174.0,15773967.0,15352280.0,16171965.0,15604878.0,16007213.0,16976999.0,16302995.0,17289784.0,16983443.0,17831893.0,17751932.0,17442358.0,18192973.0,18626473.0,17262765.0,13610216.0,19053052.0,18950870.0,19497457.0,20211847.0,19882846.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/tukey.json new file mode 100644 index 0000000000000..ba11dc258cada --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/new/tukey.json @@ -0,0 +1 @@ +[50.31197738621029,280.5871288439987,894.6541993981011,1124.9293508558894] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/MAD.svg new file mode 100644 index 0000000000000..6d3834aa7f8c7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/MAD.svg @@ -0,0 +1,328 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 0.04 + + + + + 0.045 + + + + + 0.05 + + + + + 25 + + + + + 30 + + + + + 35 + + + + + 40 + + + + + 45 + + + + + 50 + + + + + 55 + + + + + 60 + + + + + 65 + + + + + 70 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/none object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/SD.svg new file mode 100644 index 0000000000000..64352ac59351d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 180 + + + + + 190 + + + + + 200 + + + + + 210 + + + + + 220 + + + + + 230 + + + + + 240 + + + + + 250 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/none object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/index.html new file mode 100644 index 0000000000000..68415f8ae0e4a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/none object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:1 nb_readder:1)/none object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope619.91 ns635.54 ns648.20 ns
0.38171790.39071550.3847670
Mean486.11 ns529.75 ns570.84 ns
Std. Dev.181.91 ns217.93 ns244.41 ns
Median629.23 ns646.29 ns653.57 ns
MAD28.560 ns40.952 ns67.530 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/mean.svg new file mode 100644 index 0000000000000..f256487eacd0e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/mean.svg @@ -0,0 +1,308 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 0.018 + + + + + 0.02 + + + + + 480 + + + + + 500 + + + + + 520 + + + + + 540 + + + + + 560 + + + + + 580 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/none object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/median.svg new file mode 100644 index 0000000000000..57ca000176938 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/median.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 630 + + + + + 635 + + + + + 640 + + + + + 645 + + + + + 650 + + + + + 655 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/none object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/pdf.svg new file mode 100644 index 0000000000000..96f25aac8f722 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/pdf.svg @@ -0,0 +1,405 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + -200 + + + + + 0 + + + + + 200 + + + + + 400 + + + + + 600 + + + + + 800 + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + 0.003 + + + + + 0.0035 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/none object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_5 + + + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..44a51a9d1bbc3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/pdf_small.svg @@ -0,0 +1,209 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + 0.003 + + + + + -200 + + + + + 0 + + + + + 200 + + + + + 400 + + + + + 600 + + + + + 800 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/regression.svg new file mode 100644 index 0000000000000..df36c51e3a802 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/regression.svg @@ -0,0 +1,382 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/none object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/regression_small.svg new file mode 100644 index 0000000000000..14f208153f51b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/regression_small.svg @@ -0,0 +1,360 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/slope.svg new file mode 100644 index 0000000000000..b30ee67cd5a88 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 620 + + + + + 625 + + + + + 630 + + + + + 635 + + + + + 640 + + + + + 645 + + + + + 650 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/none object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/typical.svg new file mode 100644 index 0000000000000..d4ef01622e7d0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/none object poll/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 620 + + + + + 625 + + + + + 630 + + + + + 635 + + + + + 640 + + + + + 645 + + + + + 650 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/none object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/report/index.html new file mode 100644 index 0000000000000..3613699d5fad5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/report/index.html @@ -0,0 +1,185 @@ + + + + + + forward msg from pull (nb_writter:1 nb_readder:1) Summary - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:1 nb_readder:1)

+

Violin Plot

+ + Violin Plot + +

This chart shows the relationship between function/parameter and iteration time. The thickness of the shaded + region indicates the probability that a measurement of the given function/parameter would take a particular + length of time.

+
+ +

forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab'

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:1 nb_readder:1)/none object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/report/violin.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/report/violin.svg new file mode 100644 index 0000000000000..b8d986aae44dc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/report/violin.svg @@ -0,0 +1,556 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/none object poll + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/mutex object poll + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/linear object poll + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/crate 'sharded-slab' + + + + + + + + + + + + + -400 + + + + + + + + + + + + + -200 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 400 + + + + + + + + + + + + + 600 + + + + + + + + + + + + + 800 + + + + + + + + + + + + + 1000 + + + + + + + + + Input + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1): Violin plot + + + + + PDF + + + PDF + + + + + + + + + + gnuplot_plot_2 + + + + + + + gnuplot_plot_3 + + + + + + + gnuplot_plot_4 + + + + + + + gnuplot_plot_5 + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/benchmark.json new file mode 100644 index 0000000000000..7717cdf8badd4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:1)","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll","title":"forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/estimates.json new file mode 100644 index 0000000000000..d102590e7ec28 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":32.98406996614117,"upper_bound":36.072545101497575},"point_estimate":34.27662569008704,"standard_error":0.8027629629909825},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":32.70968018404078,"upper_bound":34.34293326863212},"point_estimate":33.23465278949766,"standard_error":0.44706225143418654},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":2.323568973827124,"upper_bound":4.151787310460624},"point_estimate":3.048053871879583,"standard_error":0.47807168367023584},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":33.31685849142889,"upper_bound":37.973802525847276},"point_estimate":35.24404893563738,"standard_error":1.2149782601511623},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":3.1876287729265056,"upper_bound":12.704761846646827},"point_estimate":8.035606909241459,"standard_error":2.937395220847503}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/raw.csv new file mode 100644 index 0000000000000..e7d53b77fd59a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,197941.0,ns,6334 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,416537.0,ns,12668 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,566576.0,ns,19002 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,816625.0,ns,25336 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,1042945.0,ns,31670 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,1315009.0,ns,38004 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,1475092.0,ns,44338 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,1622868.0,ns,50672 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,1825174.0,ns,57006 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,2027476.0,ns,63340 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,2253499.0,ns,69674 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,2484643.0,ns,76008 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,2647018.0,ns,82342 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,2848533.0,ns,88676 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,3111541.0,ns,95010 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,3338075.0,ns,101344 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,2863611.0,ns,107678 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,4068698.0,ns,114012 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,4182549.0,ns,120346 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,4363085.0,ns,126680 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,4498309.0,ns,133014 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,5225117.0,ns,139348 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,4741170.0,ns,145682 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,4595795.0,ns,152016 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,5084118.0,ns,158350 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,5374872.0,ns,164684 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,5376513.0,ns,171018 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,5465726.0,ns,177352 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,5768553.0,ns,183686 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6499567.0,ns,190020 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6459015.0,ns,196354 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6951279.0,ns,202688 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6688424.0,ns,209022 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6578836.0,ns,215356 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,7251409.0,ns,221690 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6867280.0,ns,228024 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,7764335.0,ns,234358 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6522180.0,ns,240692 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,7574001.0,ns,247026 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6804757.0,ns,253360 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,7286173.0,ns,259694 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,9644809.0,ns,266028 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10364119.0,ns,272362 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10268853.0,ns,278696 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10987289.0,ns,285030 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11284101.0,ns,291364 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11383858.0,ns,297698 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10689417.0,ns,304032 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11054694.0,ns,310366 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11097021.0,ns,316700 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11343052.0,ns,323034 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11940369.0,ns,329368 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11497308.0,ns,335702 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11933792.0,ns,342036 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10877879.0,ns,348370 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,12274959.0,ns,354704 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11904301.0,ns,361038 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,12208174.0,ns,367372 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,13205590.0,ns,373706 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10831581.0,ns,380040 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10844394.0,ns,386374 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11345664.0,ns,392708 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10772596.0,ns,399042 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11253779.0,ns,405376 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11461333.0,ns,411710 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,16036024.0,ns,418044 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,21514795.0,ns,424378 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,23236021.0,ns,430712 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,16379837.0,ns,437046 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,16397878.0,ns,443380 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17642393.0,ns,449714 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,16283943.0,ns,456048 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,47347708.0,ns,462382 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,18171509.0,ns,468716 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15833528.0,ns,475050 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17068942.0,ns,481384 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,16485211.0,ns,487718 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17259081.0,ns,494052 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15855838.0,ns,500386 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17501539.0,ns,506720 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17669147.0,ns,513054 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17886327.0,ns,519388 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17084187.0,ns,525722 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15700698.0,ns,532056 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15134102.0,ns,538390 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,16924032.0,ns,544724 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15729264.0,ns,551058 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15575281.0,ns,557392 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15088758.0,ns,563726 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,21724923.0,ns,570060 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,21284311.0,ns,576394 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,22079342.0,ns,582728 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,21779243.0,ns,589062 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,21943832.0,ns,595396 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,22193309.0,ns,601730 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,20210959.0,ns,608064 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,20994411.0,ns,614398 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,20937558.0,ns,620732 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,22764251.0,ns,627066 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,20874615.0,ns,633400 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/sample.json new file mode 100644 index 0000000000000..f0ece778a4357 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[6334.0,12668.0,19002.0,25336.0,31670.0,38004.0,44338.0,50672.0,57006.0,63340.0,69674.0,76008.0,82342.0,88676.0,95010.0,101344.0,107678.0,114012.0,120346.0,126680.0,133014.0,139348.0,145682.0,152016.0,158350.0,164684.0,171018.0,177352.0,183686.0,190020.0,196354.0,202688.0,209022.0,215356.0,221690.0,228024.0,234358.0,240692.0,247026.0,253360.0,259694.0,266028.0,272362.0,278696.0,285030.0,291364.0,297698.0,304032.0,310366.0,316700.0,323034.0,329368.0,335702.0,342036.0,348370.0,354704.0,361038.0,367372.0,373706.0,380040.0,386374.0,392708.0,399042.0,405376.0,411710.0,418044.0,424378.0,430712.0,437046.0,443380.0,449714.0,456048.0,462382.0,468716.0,475050.0,481384.0,487718.0,494052.0,500386.0,506720.0,513054.0,519388.0,525722.0,532056.0,538390.0,544724.0,551058.0,557392.0,563726.0,570060.0,576394.0,582728.0,589062.0,595396.0,601730.0,608064.0,614398.0,620732.0,627066.0,633400.0],"times":[197941.0,416537.0,566576.0,816625.0,1042945.0,1315009.0,1475092.0,1622868.0,1825174.0,2027476.0,2253499.0,2484643.0,2647018.0,2848533.0,3111541.0,3338075.0,2863611.0,4068698.0,4182549.0,4363085.0,4498309.0,5225117.0,4741170.0,4595795.0,5084118.0,5374872.0,5376513.0,5465726.0,5768553.0,6499567.0,6459015.0,6951279.0,6688424.0,6578836.0,7251409.0,6867280.0,7764335.0,6522180.0,7574001.0,6804757.0,7286173.0,9644809.0,10364119.0,10268853.0,10987289.0,11284101.0,11383858.0,10689417.0,11054694.0,11097021.0,11343052.0,11940369.0,11497308.0,11933792.0,10877879.0,12274959.0,11904301.0,12208174.0,13205590.0,10831581.0,10844394.0,11345664.0,10772596.0,11253779.0,11461333.0,16036024.0,21514795.0,23236021.0,16379837.0,16397878.0,17642393.0,16283943.0,47347708.0,18171509.0,15833528.0,17068942.0,16485211.0,17259081.0,15855838.0,17501539.0,17669147.0,17886327.0,17084187.0,15700698.0,15134102.0,16924032.0,15729264.0,15575281.0,15088758.0,21724923.0,21284311.0,22079342.0,21779243.0,21943832.0,22193309.0,20210959.0,20994411.0,20937558.0,22764251.0,20874615.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/tukey.json new file mode 100644 index 0000000000000..7b3bd965382b5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/base/tukey.json @@ -0,0 +1 @@ +[18.813288710081338,25.12155503594903,41.94359857159621,48.2518648974639] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/benchmark.json new file mode 100644 index 0000000000000..7717cdf8badd4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:1)","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll","title":"forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/estimates.json new file mode 100644 index 0000000000000..d102590e7ec28 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":32.98406996614117,"upper_bound":36.072545101497575},"point_estimate":34.27662569008704,"standard_error":0.8027629629909825},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":32.70968018404078,"upper_bound":34.34293326863212},"point_estimate":33.23465278949766,"standard_error":0.44706225143418654},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":2.323568973827124,"upper_bound":4.151787310460624},"point_estimate":3.048053871879583,"standard_error":0.47807168367023584},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":33.31685849142889,"upper_bound":37.973802525847276},"point_estimate":35.24404893563738,"standard_error":1.2149782601511623},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":3.1876287729265056,"upper_bound":12.704761846646827},"point_estimate":8.035606909241459,"standard_error":2.937395220847503}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/raw.csv new file mode 100644 index 0000000000000..e7d53b77fd59a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,197941.0,ns,6334 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,416537.0,ns,12668 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,566576.0,ns,19002 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,816625.0,ns,25336 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,1042945.0,ns,31670 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,1315009.0,ns,38004 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,1475092.0,ns,44338 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,1622868.0,ns,50672 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,1825174.0,ns,57006 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,2027476.0,ns,63340 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,2253499.0,ns,69674 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,2484643.0,ns,76008 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,2647018.0,ns,82342 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,2848533.0,ns,88676 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,3111541.0,ns,95010 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,3338075.0,ns,101344 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,2863611.0,ns,107678 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,4068698.0,ns,114012 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,4182549.0,ns,120346 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,4363085.0,ns,126680 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,4498309.0,ns,133014 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,5225117.0,ns,139348 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,4741170.0,ns,145682 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,4595795.0,ns,152016 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,5084118.0,ns,158350 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,5374872.0,ns,164684 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,5376513.0,ns,171018 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,5465726.0,ns,177352 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,5768553.0,ns,183686 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6499567.0,ns,190020 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6459015.0,ns,196354 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6951279.0,ns,202688 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6688424.0,ns,209022 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6578836.0,ns,215356 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,7251409.0,ns,221690 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6867280.0,ns,228024 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,7764335.0,ns,234358 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6522180.0,ns,240692 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,7574001.0,ns,247026 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,6804757.0,ns,253360 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,7286173.0,ns,259694 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,9644809.0,ns,266028 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10364119.0,ns,272362 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10268853.0,ns,278696 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10987289.0,ns,285030 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11284101.0,ns,291364 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11383858.0,ns,297698 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10689417.0,ns,304032 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11054694.0,ns,310366 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11097021.0,ns,316700 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11343052.0,ns,323034 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11940369.0,ns,329368 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11497308.0,ns,335702 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11933792.0,ns,342036 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10877879.0,ns,348370 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,12274959.0,ns,354704 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11904301.0,ns,361038 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,12208174.0,ns,367372 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,13205590.0,ns,373706 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10831581.0,ns,380040 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10844394.0,ns,386374 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11345664.0,ns,392708 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,10772596.0,ns,399042 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11253779.0,ns,405376 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,11461333.0,ns,411710 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,16036024.0,ns,418044 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,21514795.0,ns,424378 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,23236021.0,ns,430712 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,16379837.0,ns,437046 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,16397878.0,ns,443380 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17642393.0,ns,449714 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,16283943.0,ns,456048 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,47347708.0,ns,462382 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,18171509.0,ns,468716 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15833528.0,ns,475050 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17068942.0,ns,481384 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,16485211.0,ns,487718 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17259081.0,ns,494052 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15855838.0,ns,500386 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17501539.0,ns,506720 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17669147.0,ns,513054 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17886327.0,ns,519388 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,17084187.0,ns,525722 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15700698.0,ns,532056 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15134102.0,ns,538390 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,16924032.0,ns,544724 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15729264.0,ns,551058 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15575281.0,ns,557392 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,15088758.0,ns,563726 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,21724923.0,ns,570060 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,21284311.0,ns,576394 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,22079342.0,ns,582728 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,21779243.0,ns,589062 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,21943832.0,ns,595396 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,22193309.0,ns,601730 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,20210959.0,ns,608064 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,20994411.0,ns,614398 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,20937558.0,ns,620732 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,22764251.0,ns,627066 +forward msg from pull (nb_writter:1 nb_readder:1),spin_lock object poll,,,,20874615.0,ns,633400 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/sample.json new file mode 100644 index 0000000000000..f0ece778a4357 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[6334.0,12668.0,19002.0,25336.0,31670.0,38004.0,44338.0,50672.0,57006.0,63340.0,69674.0,76008.0,82342.0,88676.0,95010.0,101344.0,107678.0,114012.0,120346.0,126680.0,133014.0,139348.0,145682.0,152016.0,158350.0,164684.0,171018.0,177352.0,183686.0,190020.0,196354.0,202688.0,209022.0,215356.0,221690.0,228024.0,234358.0,240692.0,247026.0,253360.0,259694.0,266028.0,272362.0,278696.0,285030.0,291364.0,297698.0,304032.0,310366.0,316700.0,323034.0,329368.0,335702.0,342036.0,348370.0,354704.0,361038.0,367372.0,373706.0,380040.0,386374.0,392708.0,399042.0,405376.0,411710.0,418044.0,424378.0,430712.0,437046.0,443380.0,449714.0,456048.0,462382.0,468716.0,475050.0,481384.0,487718.0,494052.0,500386.0,506720.0,513054.0,519388.0,525722.0,532056.0,538390.0,544724.0,551058.0,557392.0,563726.0,570060.0,576394.0,582728.0,589062.0,595396.0,601730.0,608064.0,614398.0,620732.0,627066.0,633400.0],"times":[197941.0,416537.0,566576.0,816625.0,1042945.0,1315009.0,1475092.0,1622868.0,1825174.0,2027476.0,2253499.0,2484643.0,2647018.0,2848533.0,3111541.0,3338075.0,2863611.0,4068698.0,4182549.0,4363085.0,4498309.0,5225117.0,4741170.0,4595795.0,5084118.0,5374872.0,5376513.0,5465726.0,5768553.0,6499567.0,6459015.0,6951279.0,6688424.0,6578836.0,7251409.0,6867280.0,7764335.0,6522180.0,7574001.0,6804757.0,7286173.0,9644809.0,10364119.0,10268853.0,10987289.0,11284101.0,11383858.0,10689417.0,11054694.0,11097021.0,11343052.0,11940369.0,11497308.0,11933792.0,10877879.0,12274959.0,11904301.0,12208174.0,13205590.0,10831581.0,10844394.0,11345664.0,10772596.0,11253779.0,11461333.0,16036024.0,21514795.0,23236021.0,16379837.0,16397878.0,17642393.0,16283943.0,47347708.0,18171509.0,15833528.0,17068942.0,16485211.0,17259081.0,15855838.0,17501539.0,17669147.0,17886327.0,17084187.0,15700698.0,15134102.0,16924032.0,15729264.0,15575281.0,15088758.0,21724923.0,21284311.0,22079342.0,21779243.0,21943832.0,22193309.0,20210959.0,20994411.0,20937558.0,22764251.0,20874615.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/tukey.json new file mode 100644 index 0000000000000..7b3bd965382b5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/new/tukey.json @@ -0,0 +1 @@ +[18.813288710081338,25.12155503594903,41.94359857159621,48.2518648974639] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/MAD.svg new file mode 100644 index 0000000000000..7954154f65e90 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 0.9 + + + + + 1 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 4 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/SD.svg new file mode 100644 index 0000000000000..cff8b7752ab96 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/SD.svg @@ -0,0 +1,288 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/index.html new file mode 100644 index 0000000000000..15cf5af5e494a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope33.317 ns35.244 ns37.974 ns
0.06654260.06901590.0642265
Mean32.984 ns34.277 ns36.073 ns
Std. Dev.3.1876 ns8.0356 ns12.705 ns
Median32.710 ns33.235 ns34.343 ns
MAD2.3236 ns3.0481 ns4.1518 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/mean.svg new file mode 100644 index 0000000000000..e4d9779b3b1bb --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 33 + + + + + 33.5 + + + + + 34 + + + + + 34.5 + + + + + 35 + + + + + 35.5 + + + + + 36 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/median.svg new file mode 100644 index 0000000000000..9f48e51b2a61b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/median.svg @@ -0,0 +1,328 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + 1.8 + + + + + 2 + + + + + 32.6 + + + + + 32.8 + + + + + 33 + + + + + 33.2 + + + + + 33.4 + + + + + 33.6 + + + + + 33.8 + + + + + 34 + + + + + 34.2 + + + + + 34.4 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/pdf.svg new file mode 100644 index 0000000000000..8c1a892ee7941 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/pdf.svg @@ -0,0 +1,440 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 100 + + + + + 200 + + + + + 300 + + + + + 400 + + + + + 500 + + + + + 600 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 70 + + + + + 80 + + + + + 90 + + + + + 100 + + + + + 110 + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 0.08 + + + + + 0.09 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + gnuplot_plot_5 + + + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..f09919d9d6c4f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/pdf_small.svg @@ -0,0 +1,244 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 0.08 + + + + + 0.09 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 70 + + + + + 80 + + + + + 90 + + + + + 100 + + + + + 110 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/regression.svg new file mode 100644 index 0000000000000..83c8575a06042 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/regression.svg @@ -0,0 +1,460 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 35 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 45 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 300 + + + + + + + + + + + + + 400 + + + + + + + + + + + + + 500 + + + + + + + + + + + + + 600 + + + + + + + + + + + + + 700 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/regression_small.svg new file mode 100644 index 0000000000000..ea015056e9951 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/regression_small.svg @@ -0,0 +1,438 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 35 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 45 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 300 + + + + + + + + + + + + + 400 + + + + + + + + + + + + + 500 + + + + + + + + + + + + + 600 + + + + + + + + + + + + + 700 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/slope.svg new file mode 100644 index 0000000000000..557a13162d818 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 33 + + + + + 34 + + + + + 35 + + + + + 36 + + + + + 37 + + + + + 38 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/typical.svg new file mode 100644 index 0000000000000..601bf8f6dae63 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_1)/spin_lock object poll/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 33 + + + + + 34 + + + + + 35 + + + + + 36 + + + + + 37 + + + + + 38 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:1)/spin_lock object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/benchmark.json new file mode 100644 index 0000000000000..57370d48370ae --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:5)","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab'","directory_name":"forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'","title":"forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/estimates.json new file mode 100644 index 0000000000000..88d8d2a85018b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":744.4459700955649,"upper_bound":806.2911296836861},"point_estimate":775.7880519974599,"standard_error":15.844317467228942},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":768.5785490689057,"upper_bound":809.5230182926829},"point_estimate":790.2122728958102,"standard_error":11.197929448282428},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":80.57204450230918,"upper_bound":147.0351053571683},"point_estimate":120.85216767851895,"standard_error":17.1300652745567},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":799.8536852045106,"upper_bound":849.9859423568275},"point_estimate":822.5550000901073,"standard_error":12.764964375429388},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":131.14696340298215,"upper_bound":181.7461279769409},"point_estimate":158.49508601459348,"standard_error":12.854970479047664}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/raw.csv new file mode 100644 index 0000000000000..64b42af38bd68 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,127901.0,ns,164 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,181575.0,ns,328 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,231644.0,ns,492 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,340453.0,ns,656 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,373401.0,ns,820 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,414383.0,ns,984 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,486573.0,ns,1148 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,544278.0,ns,1312 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,587858.0,ns,1476 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,644020.0,ns,1640 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,698296.0,ns,1804 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,705921.0,ns,1968 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,1357693.0,ns,2132 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,1846418.0,ns,2296 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,1892381.0,ns,2460 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,1940872.0,ns,2624 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2051204.0,ns,2788 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2073902.0,ns,2952 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2147276.0,ns,3116 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2173663.0,ns,3280 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2259747.0,ns,3444 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2241493.0,ns,3608 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2408386.0,ns,3772 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2139152.0,ns,3936 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,3430196.0,ns,4100 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4094701.0,ns,4264 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4198598.0,ns,4428 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4184794.0,ns,4592 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4359883.0,ns,4756 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4290844.0,ns,4920 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4008675.0,ns,5084 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4485812.0,ns,5248 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4537205.0,ns,5412 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4558025.0,ns,5576 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4659009.0,ns,5740 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4710269.0,ns,5904 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4752917.0,ns,6068 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4860161.0,ns,6232 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4882040.0,ns,6396 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5121241.0,ns,6560 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5004054.0,ns,6724 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5246164.0,ns,6888 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5185217.0,ns,7052 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5233202.0,ns,7216 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5206383.0,ns,7380 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5278179.0,ns,7544 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5415181.0,ns,7708 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5578412.0,ns,7872 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5695575.0,ns,8036 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,8557412.0,ns,8200 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,8836630.0,ns,8364 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,8815458.0,ns,8528 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,8854539.0,ns,8692 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,8821145.0,ns,8856 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,8901683.0,ns,9020 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9132092.0,ns,9184 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9230880.0,ns,9348 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9196607.0,ns,9512 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9146242.0,ns,9676 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9179065.0,ns,9840 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9311192.0,ns,10004 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9589877.0,ns,10168 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9279898.0,ns,10332 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9451187.0,ns,10496 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9722602.0,ns,10660 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9631101.0,ns,10824 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9152182.0,ns,10988 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9784103.0,ns,11152 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9060756.0,ns,11316 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10062540.0,ns,11480 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10095791.0,ns,11644 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9701402.0,ns,11808 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10367565.0,ns,11972 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10362482.0,ns,12136 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10387576.0,ns,12300 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10536488.0,ns,12464 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10349886.0,ns,12628 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10409608.0,ns,12792 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10754988.0,ns,12956 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10620942.0,ns,13120 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10639534.0,ns,13284 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10759598.0,ns,13448 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10861074.0,ns,13612 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11053863.0,ns,13776 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10863157.0,ns,13940 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10843132.0,ns,14104 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11299345.0,ns,14268 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11461314.0,ns,14432 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10141032.0,ns,14596 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11257156.0,ns,14760 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11497604.0,ns,14924 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11568675.0,ns,15088 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11045879.0,ns,15252 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11544253.0,ns,15416 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,12014436.0,ns,15580 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,12023934.0,ns,15744 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11908016.0,ns,15908 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,12246733.0,ns,16072 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11360758.0,ns,16236 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,18173492.0,ns,16400 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/sample.json new file mode 100644 index 0000000000000..7d59a1466f945 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[164.0,328.0,492.0,656.0,820.0,984.0,1148.0,1312.0,1476.0,1640.0,1804.0,1968.0,2132.0,2296.0,2460.0,2624.0,2788.0,2952.0,3116.0,3280.0,3444.0,3608.0,3772.0,3936.0,4100.0,4264.0,4428.0,4592.0,4756.0,4920.0,5084.0,5248.0,5412.0,5576.0,5740.0,5904.0,6068.0,6232.0,6396.0,6560.0,6724.0,6888.0,7052.0,7216.0,7380.0,7544.0,7708.0,7872.0,8036.0,8200.0,8364.0,8528.0,8692.0,8856.0,9020.0,9184.0,9348.0,9512.0,9676.0,9840.0,10004.0,10168.0,10332.0,10496.0,10660.0,10824.0,10988.0,11152.0,11316.0,11480.0,11644.0,11808.0,11972.0,12136.0,12300.0,12464.0,12628.0,12792.0,12956.0,13120.0,13284.0,13448.0,13612.0,13776.0,13940.0,14104.0,14268.0,14432.0,14596.0,14760.0,14924.0,15088.0,15252.0,15416.0,15580.0,15744.0,15908.0,16072.0,16236.0,16400.0],"times":[127901.0,181575.0,231644.0,340453.0,373401.0,414383.0,486573.0,544278.0,587858.0,644020.0,698296.0,705921.0,1357693.0,1846418.0,1892381.0,1940872.0,2051204.0,2073902.0,2147276.0,2173663.0,2259747.0,2241493.0,2408386.0,2139152.0,3430196.0,4094701.0,4198598.0,4184794.0,4359883.0,4290844.0,4008675.0,4485812.0,4537205.0,4558025.0,4659009.0,4710269.0,4752917.0,4860161.0,4882040.0,5121241.0,5004054.0,5246164.0,5185217.0,5233202.0,5206383.0,5278179.0,5415181.0,5578412.0,5695575.0,8557412.0,8836630.0,8815458.0,8854539.0,8821145.0,8901683.0,9132092.0,9230880.0,9196607.0,9146242.0,9179065.0,9311192.0,9589877.0,9279898.0,9451187.0,9722602.0,9631101.0,9152182.0,9784103.0,9060756.0,10062540.0,10095791.0,9701402.0,10367565.0,10362482.0,10387576.0,10536488.0,10349886.0,10409608.0,10754988.0,10620942.0,10639534.0,10759598.0,10861074.0,11053863.0,10863157.0,10843132.0,11299345.0,11461314.0,10141032.0,11257156.0,11497604.0,11568675.0,11045879.0,11544253.0,12014436.0,12023934.0,11908016.0,12246733.0,11360758.0,18173492.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/tukey.json new file mode 100644 index 0000000000000..387c13a9eb6a3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/base/tukey.json @@ -0,0 +1 @@ +[229.98445977841516,469.3562467612003,1107.6810120486273,1347.0527990314124] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/benchmark.json new file mode 100644 index 0000000000000..57370d48370ae --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:5)","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab'","directory_name":"forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'","title":"forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/estimates.json new file mode 100644 index 0000000000000..88d8d2a85018b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":744.4459700955649,"upper_bound":806.2911296836861},"point_estimate":775.7880519974599,"standard_error":15.844317467228942},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":768.5785490689057,"upper_bound":809.5230182926829},"point_estimate":790.2122728958102,"standard_error":11.197929448282428},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":80.57204450230918,"upper_bound":147.0351053571683},"point_estimate":120.85216767851895,"standard_error":17.1300652745567},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":799.8536852045106,"upper_bound":849.9859423568275},"point_estimate":822.5550000901073,"standard_error":12.764964375429388},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":131.14696340298215,"upper_bound":181.7461279769409},"point_estimate":158.49508601459348,"standard_error":12.854970479047664}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/raw.csv new file mode 100644 index 0000000000000..64b42af38bd68 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,127901.0,ns,164 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,181575.0,ns,328 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,231644.0,ns,492 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,340453.0,ns,656 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,373401.0,ns,820 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,414383.0,ns,984 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,486573.0,ns,1148 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,544278.0,ns,1312 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,587858.0,ns,1476 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,644020.0,ns,1640 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,698296.0,ns,1804 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,705921.0,ns,1968 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,1357693.0,ns,2132 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,1846418.0,ns,2296 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,1892381.0,ns,2460 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,1940872.0,ns,2624 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2051204.0,ns,2788 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2073902.0,ns,2952 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2147276.0,ns,3116 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2173663.0,ns,3280 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2259747.0,ns,3444 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2241493.0,ns,3608 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2408386.0,ns,3772 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,2139152.0,ns,3936 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,3430196.0,ns,4100 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4094701.0,ns,4264 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4198598.0,ns,4428 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4184794.0,ns,4592 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4359883.0,ns,4756 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4290844.0,ns,4920 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4008675.0,ns,5084 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4485812.0,ns,5248 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4537205.0,ns,5412 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4558025.0,ns,5576 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4659009.0,ns,5740 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4710269.0,ns,5904 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4752917.0,ns,6068 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4860161.0,ns,6232 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,4882040.0,ns,6396 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5121241.0,ns,6560 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5004054.0,ns,6724 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5246164.0,ns,6888 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5185217.0,ns,7052 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5233202.0,ns,7216 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5206383.0,ns,7380 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5278179.0,ns,7544 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5415181.0,ns,7708 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5578412.0,ns,7872 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,5695575.0,ns,8036 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,8557412.0,ns,8200 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,8836630.0,ns,8364 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,8815458.0,ns,8528 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,8854539.0,ns,8692 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,8821145.0,ns,8856 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,8901683.0,ns,9020 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9132092.0,ns,9184 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9230880.0,ns,9348 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9196607.0,ns,9512 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9146242.0,ns,9676 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9179065.0,ns,9840 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9311192.0,ns,10004 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9589877.0,ns,10168 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9279898.0,ns,10332 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9451187.0,ns,10496 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9722602.0,ns,10660 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9631101.0,ns,10824 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9152182.0,ns,10988 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9784103.0,ns,11152 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9060756.0,ns,11316 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10062540.0,ns,11480 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10095791.0,ns,11644 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,9701402.0,ns,11808 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10367565.0,ns,11972 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10362482.0,ns,12136 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10387576.0,ns,12300 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10536488.0,ns,12464 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10349886.0,ns,12628 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10409608.0,ns,12792 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10754988.0,ns,12956 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10620942.0,ns,13120 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10639534.0,ns,13284 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10759598.0,ns,13448 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10861074.0,ns,13612 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11053863.0,ns,13776 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10863157.0,ns,13940 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10843132.0,ns,14104 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11299345.0,ns,14268 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11461314.0,ns,14432 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,10141032.0,ns,14596 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11257156.0,ns,14760 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11497604.0,ns,14924 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11568675.0,ns,15088 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11045879.0,ns,15252 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11544253.0,ns,15416 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,12014436.0,ns,15580 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,12023934.0,ns,15744 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11908016.0,ns,15908 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,12246733.0,ns,16072 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,11360758.0,ns,16236 +forward msg from pull (nb_writter:1 nb_readder:5),crate 'sharded-slab',,,,18173492.0,ns,16400 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/sample.json new file mode 100644 index 0000000000000..7d59a1466f945 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[164.0,328.0,492.0,656.0,820.0,984.0,1148.0,1312.0,1476.0,1640.0,1804.0,1968.0,2132.0,2296.0,2460.0,2624.0,2788.0,2952.0,3116.0,3280.0,3444.0,3608.0,3772.0,3936.0,4100.0,4264.0,4428.0,4592.0,4756.0,4920.0,5084.0,5248.0,5412.0,5576.0,5740.0,5904.0,6068.0,6232.0,6396.0,6560.0,6724.0,6888.0,7052.0,7216.0,7380.0,7544.0,7708.0,7872.0,8036.0,8200.0,8364.0,8528.0,8692.0,8856.0,9020.0,9184.0,9348.0,9512.0,9676.0,9840.0,10004.0,10168.0,10332.0,10496.0,10660.0,10824.0,10988.0,11152.0,11316.0,11480.0,11644.0,11808.0,11972.0,12136.0,12300.0,12464.0,12628.0,12792.0,12956.0,13120.0,13284.0,13448.0,13612.0,13776.0,13940.0,14104.0,14268.0,14432.0,14596.0,14760.0,14924.0,15088.0,15252.0,15416.0,15580.0,15744.0,15908.0,16072.0,16236.0,16400.0],"times":[127901.0,181575.0,231644.0,340453.0,373401.0,414383.0,486573.0,544278.0,587858.0,644020.0,698296.0,705921.0,1357693.0,1846418.0,1892381.0,1940872.0,2051204.0,2073902.0,2147276.0,2173663.0,2259747.0,2241493.0,2408386.0,2139152.0,3430196.0,4094701.0,4198598.0,4184794.0,4359883.0,4290844.0,4008675.0,4485812.0,4537205.0,4558025.0,4659009.0,4710269.0,4752917.0,4860161.0,4882040.0,5121241.0,5004054.0,5246164.0,5185217.0,5233202.0,5206383.0,5278179.0,5415181.0,5578412.0,5695575.0,8557412.0,8836630.0,8815458.0,8854539.0,8821145.0,8901683.0,9132092.0,9230880.0,9196607.0,9146242.0,9179065.0,9311192.0,9589877.0,9279898.0,9451187.0,9722602.0,9631101.0,9152182.0,9784103.0,9060756.0,10062540.0,10095791.0,9701402.0,10367565.0,10362482.0,10387576.0,10536488.0,10349886.0,10409608.0,10754988.0,10620942.0,10639534.0,10759598.0,10861074.0,11053863.0,10863157.0,10843132.0,11299345.0,11461314.0,10141032.0,11257156.0,11497604.0,11568675.0,11045879.0,11544253.0,12014436.0,12023934.0,11908016.0,12246733.0,11360758.0,18173492.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/tukey.json new file mode 100644 index 0000000000000..387c13a9eb6a3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/new/tukey.json @@ -0,0 +1 @@ +[229.98445977841516,469.3562467612003,1107.6810120486273,1347.0527990314124] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/MAD.svg new file mode 100644 index 0000000000000..8e33a423697f9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 80 + + + + + 90 + + + + + 100 + + + + + 110 + + + + + 120 + + + + + 130 + + + + + 140 + + + + + 150 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab': MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/SD.svg new file mode 100644 index 0000000000000..a377e8af72e93 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/SD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 130 + + + + + 140 + + + + + 150 + + + + + 160 + + + + + 170 + + + + + 180 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab': SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/index.html new file mode 100644 index 0000000000000..8feff12cc8070 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab' - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab'

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope799.85 ns822.56 ns849.99 ns
0.58232030.59485040.5767309
Mean744.45 ns775.79 ns806.29 ns
Std. Dev.131.15 ns158.50 ns181.75 ns
Median768.58 ns790.21 ns809.52 ns
MAD80.572 ns120.85 ns147.04 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/mean.svg new file mode 100644 index 0000000000000..3d866bdf0a5ba --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 740 + + + + + 750 + + + + + 760 + + + + + 770 + + + + + 780 + + + + + 790 + + + + + 800 + + + + + 810 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab': mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/median.svg new file mode 100644 index 0000000000000..960758db2bd6c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/median.svg @@ -0,0 +1,288 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 770 + + + + + 780 + + + + + 790 + + + + + 800 + + + + + 810 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab': median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/pdf.svg new file mode 100644 index 0000000000000..88afc02d12a64 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/pdf.svg @@ -0,0 +1,415 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab' + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + + + + + + + gnuplot_plot_5 + + + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/pdf_small.svg new file mode 100644 index 0000000000000..d5a77e949af44 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/pdf_small.svg @@ -0,0 +1,209 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/regression.svg new file mode 100644 index 0000000000000..ab3c74922806e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/regression.svg @@ -0,0 +1,486 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab' + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/regression_small.svg new file mode 100644 index 0000000000000..b79e1614a1ec2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/regression_small.svg @@ -0,0 +1,464 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/slope.svg new file mode 100644 index 0000000000000..03eb626525562 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 800 + + + + + 810 + + + + + 820 + + + + + 830 + + + + + 840 + + + + + 850 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab': slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/typical.svg new file mode 100644 index 0000000000000..9dc73273f80f5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/crate 'sharded-slab'/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 800 + + + + + 810 + + + + + 820 + + + + + 830 + + + + + 840 + + + + + 850 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab': typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/benchmark.json new file mode 100644 index 0000000000000..05eaf9da3e0d3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:5)","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll","title":"forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/estimates.json new file mode 100644 index 0000000000000..d34619c5d0e4c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":161.96867350519926,"upper_bound":164.4345403481576},"point_estimate":163.18441157753617,"standard_error":0.6280087618766327},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":161.7928863464291,"upper_bound":163.95269200316707},"point_estimate":162.85723808361422,"standard_error":0.4842803512593368},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":3.908282303410723,"upper_bound":6.230916095727977},"point_estimate":4.841481153738675,"standard_error":0.6256267977910251},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":160.07114693104506,"upper_bound":162.86247014764066},"point_estimate":161.4752894964045,"standard_error":0.7130920190984374},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":5.14681051563144,"upper_bound":7.423967854245774},"point_estimate":6.31836086349586,"standard_error":0.5838059808595696}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/raw.csv new file mode 100644 index 0000000000000..768b10cc7d860 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,229226.0,ns,1263 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,441936.0,ns,2526 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,634115.0,ns,3789 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,823798.0,ns,5052 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,1173823.0,ns,6315 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,1316366.0,ns,7578 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,1411654.0,ns,8841 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,1622406.0,ns,10104 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,1834406.0,ns,11367 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,2156944.0,ns,12630 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,2345034.0,ns,13893 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,2484867.0,ns,15156 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,2668558.0,ns,16419 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,2878117.0,ns,17682 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,3277225.0,ns,18945 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,3240449.0,ns,20208 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,3676540.0,ns,21471 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,3704438.0,ns,22734 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,3849689.0,ns,23997 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,4186609.0,ns,25260 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,4615162.0,ns,26523 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,4477025.0,ns,27786 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,4585689.0,ns,29049 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,5036644.0,ns,30312 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,5260494.0,ns,31575 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,5468432.0,ns,32838 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,5131687.0,ns,34101 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,5856020.0,ns,35364 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,5978988.0,ns,36627 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,6175158.0,ns,37890 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,6281375.0,ns,39153 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,6643668.0,ns,40416 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,6710490.0,ns,41679 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,7109633.0,ns,42942 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,7374075.0,ns,44205 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,7510116.0,ns,45468 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,7879848.0,ns,46731 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,7500462.0,ns,47994 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,8096977.0,ns,49257 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,8108093.0,ns,50520 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,8462413.0,ns,51783 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,8596763.0,ns,53046 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,8753946.0,ns,54309 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,8324600.0,ns,55572 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,9319611.0,ns,56835 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,9459006.0,ns,58098 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,9915064.0,ns,59361 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,10315009.0,ns,60624 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,9894816.0,ns,61887 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,10023875.0,ns,63150 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,10672945.0,ns,64413 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,11751590.0,ns,65676 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,10593587.0,ns,66939 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,10348571.0,ns,68202 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,11316075.0,ns,69465 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,10913853.0,ns,70728 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,11483235.0,ns,71991 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,12536611.0,ns,73254 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,12062815.0,ns,74517 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,12691886.0,ns,75780 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,12178321.0,ns,77043 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,12645840.0,ns,78306 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,12722385.0,ns,79569 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,13148511.0,ns,80832 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,13377052.0,ns,82095 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,13876989.0,ns,83358 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,13157300.0,ns,84621 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,13494186.0,ns,85884 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,14473851.0,ns,87147 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,14640113.0,ns,88410 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,13876880.0,ns,89673 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,14840907.0,ns,90936 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,14516584.0,ns,92199 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,15960101.0,ns,93462 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,15801827.0,ns,94725 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16374163.0,ns,95988 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,14816638.0,ns,97251 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,15941565.0,ns,98514 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16146980.0,ns,99777 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16741589.0,ns,101040 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16548031.0,ns,102303 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16271637.0,ns,103566 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16109339.0,ns,104829 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,17968373.0,ns,106092 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,18154411.0,ns,107355 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16466009.0,ns,108618 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,17801781.0,ns,109881 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,17588431.0,ns,111144 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,17720165.0,ns,112407 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,18534160.0,ns,113670 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,18398926.0,ns,114933 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,19100197.0,ns,116196 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,19572634.0,ns,117459 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,18865526.0,ns,118722 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,19519649.0,ns,119985 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,18223210.0,ns,121248 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,19614762.0,ns,122511 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,19902694.0,ns,123774 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,19403634.0,ns,125037 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,20904127.0,ns,126300 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/sample.json new file mode 100644 index 0000000000000..3c2e859647956 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[1263.0,2526.0,3789.0,5052.0,6315.0,7578.0,8841.0,10104.0,11367.0,12630.0,13893.0,15156.0,16419.0,17682.0,18945.0,20208.0,21471.0,22734.0,23997.0,25260.0,26523.0,27786.0,29049.0,30312.0,31575.0,32838.0,34101.0,35364.0,36627.0,37890.0,39153.0,40416.0,41679.0,42942.0,44205.0,45468.0,46731.0,47994.0,49257.0,50520.0,51783.0,53046.0,54309.0,55572.0,56835.0,58098.0,59361.0,60624.0,61887.0,63150.0,64413.0,65676.0,66939.0,68202.0,69465.0,70728.0,71991.0,73254.0,74517.0,75780.0,77043.0,78306.0,79569.0,80832.0,82095.0,83358.0,84621.0,85884.0,87147.0,88410.0,89673.0,90936.0,92199.0,93462.0,94725.0,95988.0,97251.0,98514.0,99777.0,101040.0,102303.0,103566.0,104829.0,106092.0,107355.0,108618.0,109881.0,111144.0,112407.0,113670.0,114933.0,116196.0,117459.0,118722.0,119985.0,121248.0,122511.0,123774.0,125037.0,126300.0],"times":[229226.0,441936.0,634115.0,823798.0,1173823.0,1316366.0,1411654.0,1622406.0,1834406.0,2156944.0,2345034.0,2484867.0,2668558.0,2878117.0,3277225.0,3240449.0,3676540.0,3704438.0,3849689.0,4186609.0,4615162.0,4477025.0,4585689.0,5036644.0,5260494.0,5468432.0,5131687.0,5856020.0,5978988.0,6175158.0,6281375.0,6643668.0,6710490.0,7109633.0,7374075.0,7510116.0,7879848.0,7500462.0,8096977.0,8108093.0,8462413.0,8596763.0,8753946.0,8324600.0,9319611.0,9459006.0,9915064.0,10315009.0,9894816.0,10023875.0,10672945.0,11751590.0,10593587.0,10348571.0,11316075.0,10913853.0,11483235.0,12536611.0,12062815.0,12691886.0,12178321.0,12645840.0,12722385.0,13148511.0,13377052.0,13876989.0,13157300.0,13494186.0,14473851.0,14640113.0,13876880.0,14840907.0,14516584.0,15960101.0,15801827.0,16374163.0,14816638.0,15941565.0,16146980.0,16741589.0,16548031.0,16271637.0,16109339.0,17968373.0,18154411.0,16466009.0,17801781.0,17588431.0,17720165.0,18534160.0,18398926.0,19100197.0,19572634.0,18865526.0,19519649.0,18223210.0,19614762.0,19902694.0,19403634.0,20904127.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/tukey.json new file mode 100644 index 0000000000000..e5a7ca65d0049 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/base/tukey.json @@ -0,0 +1 @@ +[140.09538901602875,149.9925557066506,176.38500021497555,186.28216690559742] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/benchmark.json new file mode 100644 index 0000000000000..05eaf9da3e0d3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:5)","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll","title":"forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/estimates.json new file mode 100644 index 0000000000000..d34619c5d0e4c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":161.96867350519926,"upper_bound":164.4345403481576},"point_estimate":163.18441157753617,"standard_error":0.6280087618766327},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":161.7928863464291,"upper_bound":163.95269200316707},"point_estimate":162.85723808361422,"standard_error":0.4842803512593368},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":3.908282303410723,"upper_bound":6.230916095727977},"point_estimate":4.841481153738675,"standard_error":0.6256267977910251},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":160.07114693104506,"upper_bound":162.86247014764066},"point_estimate":161.4752894964045,"standard_error":0.7130920190984374},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":5.14681051563144,"upper_bound":7.423967854245774},"point_estimate":6.31836086349586,"standard_error":0.5838059808595696}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/raw.csv new file mode 100644 index 0000000000000..768b10cc7d860 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,229226.0,ns,1263 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,441936.0,ns,2526 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,634115.0,ns,3789 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,823798.0,ns,5052 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,1173823.0,ns,6315 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,1316366.0,ns,7578 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,1411654.0,ns,8841 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,1622406.0,ns,10104 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,1834406.0,ns,11367 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,2156944.0,ns,12630 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,2345034.0,ns,13893 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,2484867.0,ns,15156 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,2668558.0,ns,16419 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,2878117.0,ns,17682 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,3277225.0,ns,18945 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,3240449.0,ns,20208 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,3676540.0,ns,21471 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,3704438.0,ns,22734 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,3849689.0,ns,23997 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,4186609.0,ns,25260 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,4615162.0,ns,26523 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,4477025.0,ns,27786 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,4585689.0,ns,29049 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,5036644.0,ns,30312 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,5260494.0,ns,31575 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,5468432.0,ns,32838 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,5131687.0,ns,34101 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,5856020.0,ns,35364 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,5978988.0,ns,36627 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,6175158.0,ns,37890 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,6281375.0,ns,39153 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,6643668.0,ns,40416 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,6710490.0,ns,41679 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,7109633.0,ns,42942 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,7374075.0,ns,44205 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,7510116.0,ns,45468 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,7879848.0,ns,46731 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,7500462.0,ns,47994 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,8096977.0,ns,49257 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,8108093.0,ns,50520 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,8462413.0,ns,51783 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,8596763.0,ns,53046 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,8753946.0,ns,54309 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,8324600.0,ns,55572 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,9319611.0,ns,56835 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,9459006.0,ns,58098 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,9915064.0,ns,59361 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,10315009.0,ns,60624 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,9894816.0,ns,61887 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,10023875.0,ns,63150 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,10672945.0,ns,64413 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,11751590.0,ns,65676 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,10593587.0,ns,66939 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,10348571.0,ns,68202 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,11316075.0,ns,69465 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,10913853.0,ns,70728 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,11483235.0,ns,71991 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,12536611.0,ns,73254 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,12062815.0,ns,74517 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,12691886.0,ns,75780 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,12178321.0,ns,77043 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,12645840.0,ns,78306 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,12722385.0,ns,79569 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,13148511.0,ns,80832 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,13377052.0,ns,82095 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,13876989.0,ns,83358 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,13157300.0,ns,84621 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,13494186.0,ns,85884 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,14473851.0,ns,87147 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,14640113.0,ns,88410 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,13876880.0,ns,89673 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,14840907.0,ns,90936 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,14516584.0,ns,92199 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,15960101.0,ns,93462 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,15801827.0,ns,94725 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16374163.0,ns,95988 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,14816638.0,ns,97251 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,15941565.0,ns,98514 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16146980.0,ns,99777 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16741589.0,ns,101040 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16548031.0,ns,102303 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16271637.0,ns,103566 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16109339.0,ns,104829 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,17968373.0,ns,106092 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,18154411.0,ns,107355 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,16466009.0,ns,108618 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,17801781.0,ns,109881 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,17588431.0,ns,111144 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,17720165.0,ns,112407 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,18534160.0,ns,113670 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,18398926.0,ns,114933 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,19100197.0,ns,116196 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,19572634.0,ns,117459 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,18865526.0,ns,118722 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,19519649.0,ns,119985 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,18223210.0,ns,121248 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,19614762.0,ns,122511 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,19902694.0,ns,123774 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,19403634.0,ns,125037 +forward msg from pull (nb_writter:1 nb_readder:5),linear object poll,,,,20904127.0,ns,126300 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/sample.json new file mode 100644 index 0000000000000..3c2e859647956 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[1263.0,2526.0,3789.0,5052.0,6315.0,7578.0,8841.0,10104.0,11367.0,12630.0,13893.0,15156.0,16419.0,17682.0,18945.0,20208.0,21471.0,22734.0,23997.0,25260.0,26523.0,27786.0,29049.0,30312.0,31575.0,32838.0,34101.0,35364.0,36627.0,37890.0,39153.0,40416.0,41679.0,42942.0,44205.0,45468.0,46731.0,47994.0,49257.0,50520.0,51783.0,53046.0,54309.0,55572.0,56835.0,58098.0,59361.0,60624.0,61887.0,63150.0,64413.0,65676.0,66939.0,68202.0,69465.0,70728.0,71991.0,73254.0,74517.0,75780.0,77043.0,78306.0,79569.0,80832.0,82095.0,83358.0,84621.0,85884.0,87147.0,88410.0,89673.0,90936.0,92199.0,93462.0,94725.0,95988.0,97251.0,98514.0,99777.0,101040.0,102303.0,103566.0,104829.0,106092.0,107355.0,108618.0,109881.0,111144.0,112407.0,113670.0,114933.0,116196.0,117459.0,118722.0,119985.0,121248.0,122511.0,123774.0,125037.0,126300.0],"times":[229226.0,441936.0,634115.0,823798.0,1173823.0,1316366.0,1411654.0,1622406.0,1834406.0,2156944.0,2345034.0,2484867.0,2668558.0,2878117.0,3277225.0,3240449.0,3676540.0,3704438.0,3849689.0,4186609.0,4615162.0,4477025.0,4585689.0,5036644.0,5260494.0,5468432.0,5131687.0,5856020.0,5978988.0,6175158.0,6281375.0,6643668.0,6710490.0,7109633.0,7374075.0,7510116.0,7879848.0,7500462.0,8096977.0,8108093.0,8462413.0,8596763.0,8753946.0,8324600.0,9319611.0,9459006.0,9915064.0,10315009.0,9894816.0,10023875.0,10672945.0,11751590.0,10593587.0,10348571.0,11316075.0,10913853.0,11483235.0,12536611.0,12062815.0,12691886.0,12178321.0,12645840.0,12722385.0,13148511.0,13377052.0,13876989.0,13157300.0,13494186.0,14473851.0,14640113.0,13876880.0,14840907.0,14516584.0,15960101.0,15801827.0,16374163.0,14816638.0,15941565.0,16146980.0,16741589.0,16548031.0,16271637.0,16109339.0,17968373.0,18154411.0,16466009.0,17801781.0,17588431.0,17720165.0,18534160.0,18398926.0,19100197.0,19572634.0,18865526.0,19519649.0,18223210.0,19614762.0,19902694.0,19403634.0,20904127.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/tukey.json new file mode 100644 index 0000000000000..e5a7ca65d0049 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/new/tukey.json @@ -0,0 +1 @@ +[140.09538901602875,149.9925557066506,176.38500021497555,186.28216690559742] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/MAD.svg new file mode 100644 index 0000000000000..1d95b6569eda3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/MAD.svg @@ -0,0 +1,288 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 4 + + + + + 4.5 + + + + + 5 + + + + + 5.5 + + + + + 6 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/SD.svg new file mode 100644 index 0000000000000..57c6f9c10c2a0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/SD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 5 + + + + + 5.5 + + + + + 6 + + + + + 6.5 + + + + + 7 + + + + + 7.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/index.html new file mode 100644 index 0000000000000..5b0542eb8c8fe --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope160.07 ns161.48 ns162.86 ns
0.86782910.87505080.8680011
Mean161.97 ns163.18 ns164.43 ns
Std. Dev.5.1468 ns6.3184 ns7.4240 ns
Median161.79 ns162.86 ns163.95 ns
MAD3.9083 ns4.8415 ns6.2309 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/mean.svg new file mode 100644 index 0000000000000..672ac5e36784b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 162 + + + + + 162.5 + + + + + 163 + + + + + 163.5 + + + + + 164 + + + + + 164.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/median.svg new file mode 100644 index 0000000000000..9df1f2fa05d53 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/median.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + 1.8 + + + + + 2 + + + + + 162 + + + + + 162.5 + + + + + 163 + + + + + 163.5 + + + + + 164 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/pdf.svg new file mode 100644 index 0000000000000..3c5c7ff49867c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/pdf.svg @@ -0,0 +1,405 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 20 + + + + + 40 + + + + + 60 + + + + + 80 + + + + + 100 + + + + + 120 + + + + + 150 + + + + + 160 + + + + + 170 + + + + + 180 + + + + + 190 + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + + gnuplot_plot_5 + + + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..ec3e2fa894a8a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/pdf_small.svg @@ -0,0 +1,209 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 150 + + + + + 160 + + + + + 170 + + + + + 180 + + + + + 190 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/regression.svg new file mode 100644 index 0000000000000..3661b3dd41569 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/regression.svg @@ -0,0 +1,395 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 120 + + + + + + + + + + + + + 140 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/regression_small.svg new file mode 100644 index 0000000000000..a7975a41250d1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/regression_small.svg @@ -0,0 +1,373 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 120 + + + + + + + + + + + + + 140 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/slope.svg new file mode 100644 index 0000000000000..f740e8b9c0532 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 160 + + + + + 160.5 + + + + + 161 + + + + + 161.5 + + + + + 162 + + + + + 162.5 + + + + + 163 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/typical.svg new file mode 100644 index 0000000000000..48502be5cdff3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/linear object poll/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 160 + + + + + 160.5 + + + + + 161 + + + + + 161.5 + + + + + 162 + + + + + 162.5 + + + + + 163 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/benchmark.json new file mode 100644 index 0000000000000..035f35c2991d2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:5)","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll","title":"forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/estimates.json new file mode 100644 index 0000000000000..8edd0aa69d14c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":205.7731736386855,"upper_bound":208.56684719744203},"point_estimate":207.16722979085876,"standard_error":0.7128603820101649},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":206.60070401877383,"upper_bound":208.817721279585},"point_estimate":207.5706607113451,"standard_error":0.6084305260344248},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":3.732483598253152,"upper_bound":7.138371703871007},"point_estimate":5.44936579282976,"standard_error":0.8784366617871852},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":204.37398023885427,"upper_bound":208.3843448162165},"point_estimate":206.42544240090135,"standard_error":1.0237296054372949},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":5.800246580929711,"upper_bound":8.5130943281284},"point_estimate":7.170910218288525,"standard_error":0.6946847756091789}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/raw.csv new file mode 100644 index 0000000000000..85d5011974100 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,195044.0,ns,974 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,429945.0,ns,1948 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,624614.0,ns,2922 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,916176.0,ns,3896 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,1008467.0,ns,4870 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,1247746.0,ns,5844 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,1373926.0,ns,6818 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,1658641.0,ns,7792 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,1864444.0,ns,8766 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,2090494.0,ns,9740 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,2245643.0,ns,10714 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,2466695.0,ns,11688 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,2569492.0,ns,12662 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,2846165.0,ns,13636 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,3041948.0,ns,14610 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,2999775.0,ns,15584 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,3487358.0,ns,16558 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,3652483.0,ns,17532 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,3887962.0,ns,18506 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,4184991.0,ns,19480 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,4435495.0,ns,20454 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,4414801.0,ns,21428 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,4403610.0,ns,22402 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,4932653.0,ns,23376 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,4869192.0,ns,24350 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,5282276.0,ns,25324 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,5498923.0,ns,26298 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,5590511.0,ns,27272 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,5842610.0,ns,28246 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,6156393.0,ns,29220 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,6068111.0,ns,30194 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,6584890.0,ns,31168 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,6653870.0,ns,32142 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,6675254.0,ns,33116 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,7043018.0,ns,34090 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,7326768.0,ns,35064 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,7266750.0,ns,36038 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,7704817.0,ns,37012 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,8113397.0,ns,37986 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,8157622.0,ns,38960 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,7897753.0,ns,39934 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,8330454.0,ns,40908 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,8605546.0,ns,41882 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,8969698.0,ns,42856 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,9552049.0,ns,43830 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,8901219.0,ns,44804 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,9393329.0,ns,45778 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,9714431.0,ns,46752 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,9577437.0,ns,47726 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,10167978.0,ns,48700 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,10771327.0,ns,49674 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,10284331.0,ns,50648 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,10095779.0,ns,51622 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,10824124.0,ns,52596 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,10278753.0,ns,53570 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,11400285.0,ns,54544 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,11394969.0,ns,55518 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,11673890.0,ns,56492 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,11913986.0,ns,57466 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,12343788.0,ns,58440 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,12306596.0,ns,59414 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,12771624.0,ns,60388 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,12687231.0,ns,61362 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,12026292.0,ns,62336 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,13015671.0,ns,63310 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,13617198.0,ns,64284 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,13212896.0,ns,65258 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,13681954.0,ns,66232 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,13416398.0,ns,67206 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,13824898.0,ns,68180 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,14419254.0,ns,69154 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,14811749.0,ns,70128 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15084463.0,ns,71102 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,14861933.0,ns,72076 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15644752.0,ns,73050 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15464436.0,ns,74024 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,14668736.0,ns,74998 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15615662.0,ns,75972 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15966941.0,ns,76946 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,17234997.0,ns,77920 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,16487972.0,ns,78894 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,16458365.0,ns,79868 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,17192089.0,ns,80842 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15499748.0,ns,81816 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15733592.0,ns,82790 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,17655182.0,ns,83764 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,18644298.0,ns,84738 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,17703414.0,ns,85712 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,17124420.0,ns,86686 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,17939001.0,ns,87660 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,18402955.0,ns,88634 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,19631273.0,ns,89608 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,18139933.0,ns,90582 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,18999033.0,ns,91556 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,19568070.0,ns,92530 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,19471425.0,ns,93504 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,19976064.0,ns,94478 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,20286279.0,ns,95452 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,19780226.0,ns,96426 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,18686693.0,ns,97400 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/sample.json new file mode 100644 index 0000000000000..6fd1739de874b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[974.0,1948.0,2922.0,3896.0,4870.0,5844.0,6818.0,7792.0,8766.0,9740.0,10714.0,11688.0,12662.0,13636.0,14610.0,15584.0,16558.0,17532.0,18506.0,19480.0,20454.0,21428.0,22402.0,23376.0,24350.0,25324.0,26298.0,27272.0,28246.0,29220.0,30194.0,31168.0,32142.0,33116.0,34090.0,35064.0,36038.0,37012.0,37986.0,38960.0,39934.0,40908.0,41882.0,42856.0,43830.0,44804.0,45778.0,46752.0,47726.0,48700.0,49674.0,50648.0,51622.0,52596.0,53570.0,54544.0,55518.0,56492.0,57466.0,58440.0,59414.0,60388.0,61362.0,62336.0,63310.0,64284.0,65258.0,66232.0,67206.0,68180.0,69154.0,70128.0,71102.0,72076.0,73050.0,74024.0,74998.0,75972.0,76946.0,77920.0,78894.0,79868.0,80842.0,81816.0,82790.0,83764.0,84738.0,85712.0,86686.0,87660.0,88634.0,89608.0,90582.0,91556.0,92530.0,93504.0,94478.0,95452.0,96426.0,97400.0],"times":[195044.0,429945.0,624614.0,916176.0,1008467.0,1247746.0,1373926.0,1658641.0,1864444.0,2090494.0,2245643.0,2466695.0,2569492.0,2846165.0,3041948.0,2999775.0,3487358.0,3652483.0,3887962.0,4184991.0,4435495.0,4414801.0,4403610.0,4932653.0,4869192.0,5282276.0,5498923.0,5590511.0,5842610.0,6156393.0,6068111.0,6584890.0,6653870.0,6675254.0,7043018.0,7326768.0,7266750.0,7704817.0,8113397.0,8157622.0,7897753.0,8330454.0,8605546.0,8969698.0,9552049.0,8901219.0,9393329.0,9714431.0,9577437.0,10167978.0,10771327.0,10284331.0,10095779.0,10824124.0,10278753.0,11400285.0,11394969.0,11673890.0,11913986.0,12343788.0,12306596.0,12771624.0,12687231.0,12026292.0,13015671.0,13617198.0,13212896.0,13681954.0,13416398.0,13824898.0,14419254.0,14811749.0,15084463.0,14861933.0,15644752.0,15464436.0,14668736.0,15615662.0,15966941.0,17234997.0,16487972.0,16458365.0,17192089.0,15499748.0,15733592.0,17655182.0,18644298.0,17703414.0,17124420.0,17939001.0,18402955.0,19631273.0,18139933.0,18999033.0,19568070.0,19471425.0,19976064.0,20286279.0,19780226.0,18686693.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/tukey.json new file mode 100644 index 0000000000000..5dc1b7f83ca51 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/base/tukey.json @@ -0,0 +1 @@ +[180.33215449206853,191.91248699003768,222.7933736512888,234.37370614925797] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/benchmark.json new file mode 100644 index 0000000000000..035f35c2991d2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:5)","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll","title":"forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/estimates.json new file mode 100644 index 0000000000000..8edd0aa69d14c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":205.7731736386855,"upper_bound":208.56684719744203},"point_estimate":207.16722979085876,"standard_error":0.7128603820101649},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":206.60070401877383,"upper_bound":208.817721279585},"point_estimate":207.5706607113451,"standard_error":0.6084305260344248},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":3.732483598253152,"upper_bound":7.138371703871007},"point_estimate":5.44936579282976,"standard_error":0.8784366617871852},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":204.37398023885427,"upper_bound":208.3843448162165},"point_estimate":206.42544240090135,"standard_error":1.0237296054372949},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":5.800246580929711,"upper_bound":8.5130943281284},"point_estimate":7.170910218288525,"standard_error":0.6946847756091789}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/raw.csv new file mode 100644 index 0000000000000..85d5011974100 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,195044.0,ns,974 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,429945.0,ns,1948 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,624614.0,ns,2922 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,916176.0,ns,3896 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,1008467.0,ns,4870 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,1247746.0,ns,5844 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,1373926.0,ns,6818 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,1658641.0,ns,7792 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,1864444.0,ns,8766 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,2090494.0,ns,9740 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,2245643.0,ns,10714 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,2466695.0,ns,11688 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,2569492.0,ns,12662 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,2846165.0,ns,13636 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,3041948.0,ns,14610 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,2999775.0,ns,15584 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,3487358.0,ns,16558 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,3652483.0,ns,17532 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,3887962.0,ns,18506 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,4184991.0,ns,19480 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,4435495.0,ns,20454 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,4414801.0,ns,21428 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,4403610.0,ns,22402 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,4932653.0,ns,23376 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,4869192.0,ns,24350 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,5282276.0,ns,25324 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,5498923.0,ns,26298 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,5590511.0,ns,27272 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,5842610.0,ns,28246 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,6156393.0,ns,29220 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,6068111.0,ns,30194 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,6584890.0,ns,31168 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,6653870.0,ns,32142 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,6675254.0,ns,33116 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,7043018.0,ns,34090 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,7326768.0,ns,35064 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,7266750.0,ns,36038 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,7704817.0,ns,37012 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,8113397.0,ns,37986 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,8157622.0,ns,38960 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,7897753.0,ns,39934 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,8330454.0,ns,40908 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,8605546.0,ns,41882 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,8969698.0,ns,42856 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,9552049.0,ns,43830 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,8901219.0,ns,44804 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,9393329.0,ns,45778 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,9714431.0,ns,46752 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,9577437.0,ns,47726 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,10167978.0,ns,48700 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,10771327.0,ns,49674 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,10284331.0,ns,50648 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,10095779.0,ns,51622 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,10824124.0,ns,52596 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,10278753.0,ns,53570 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,11400285.0,ns,54544 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,11394969.0,ns,55518 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,11673890.0,ns,56492 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,11913986.0,ns,57466 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,12343788.0,ns,58440 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,12306596.0,ns,59414 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,12771624.0,ns,60388 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,12687231.0,ns,61362 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,12026292.0,ns,62336 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,13015671.0,ns,63310 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,13617198.0,ns,64284 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,13212896.0,ns,65258 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,13681954.0,ns,66232 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,13416398.0,ns,67206 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,13824898.0,ns,68180 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,14419254.0,ns,69154 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,14811749.0,ns,70128 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15084463.0,ns,71102 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,14861933.0,ns,72076 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15644752.0,ns,73050 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15464436.0,ns,74024 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,14668736.0,ns,74998 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15615662.0,ns,75972 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15966941.0,ns,76946 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,17234997.0,ns,77920 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,16487972.0,ns,78894 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,16458365.0,ns,79868 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,17192089.0,ns,80842 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15499748.0,ns,81816 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,15733592.0,ns,82790 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,17655182.0,ns,83764 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,18644298.0,ns,84738 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,17703414.0,ns,85712 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,17124420.0,ns,86686 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,17939001.0,ns,87660 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,18402955.0,ns,88634 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,19631273.0,ns,89608 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,18139933.0,ns,90582 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,18999033.0,ns,91556 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,19568070.0,ns,92530 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,19471425.0,ns,93504 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,19976064.0,ns,94478 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,20286279.0,ns,95452 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,19780226.0,ns,96426 +forward msg from pull (nb_writter:1 nb_readder:5),mutex object poll,,,,18686693.0,ns,97400 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/sample.json new file mode 100644 index 0000000000000..6fd1739de874b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[974.0,1948.0,2922.0,3896.0,4870.0,5844.0,6818.0,7792.0,8766.0,9740.0,10714.0,11688.0,12662.0,13636.0,14610.0,15584.0,16558.0,17532.0,18506.0,19480.0,20454.0,21428.0,22402.0,23376.0,24350.0,25324.0,26298.0,27272.0,28246.0,29220.0,30194.0,31168.0,32142.0,33116.0,34090.0,35064.0,36038.0,37012.0,37986.0,38960.0,39934.0,40908.0,41882.0,42856.0,43830.0,44804.0,45778.0,46752.0,47726.0,48700.0,49674.0,50648.0,51622.0,52596.0,53570.0,54544.0,55518.0,56492.0,57466.0,58440.0,59414.0,60388.0,61362.0,62336.0,63310.0,64284.0,65258.0,66232.0,67206.0,68180.0,69154.0,70128.0,71102.0,72076.0,73050.0,74024.0,74998.0,75972.0,76946.0,77920.0,78894.0,79868.0,80842.0,81816.0,82790.0,83764.0,84738.0,85712.0,86686.0,87660.0,88634.0,89608.0,90582.0,91556.0,92530.0,93504.0,94478.0,95452.0,96426.0,97400.0],"times":[195044.0,429945.0,624614.0,916176.0,1008467.0,1247746.0,1373926.0,1658641.0,1864444.0,2090494.0,2245643.0,2466695.0,2569492.0,2846165.0,3041948.0,2999775.0,3487358.0,3652483.0,3887962.0,4184991.0,4435495.0,4414801.0,4403610.0,4932653.0,4869192.0,5282276.0,5498923.0,5590511.0,5842610.0,6156393.0,6068111.0,6584890.0,6653870.0,6675254.0,7043018.0,7326768.0,7266750.0,7704817.0,8113397.0,8157622.0,7897753.0,8330454.0,8605546.0,8969698.0,9552049.0,8901219.0,9393329.0,9714431.0,9577437.0,10167978.0,10771327.0,10284331.0,10095779.0,10824124.0,10278753.0,11400285.0,11394969.0,11673890.0,11913986.0,12343788.0,12306596.0,12771624.0,12687231.0,12026292.0,13015671.0,13617198.0,13212896.0,13681954.0,13416398.0,13824898.0,14419254.0,14811749.0,15084463.0,14861933.0,15644752.0,15464436.0,14668736.0,15615662.0,15966941.0,17234997.0,16487972.0,16458365.0,17192089.0,15499748.0,15733592.0,17655182.0,18644298.0,17703414.0,17124420.0,17939001.0,18402955.0,19631273.0,18139933.0,18999033.0,19568070.0,19471425.0,19976064.0,20286279.0,19780226.0,18686693.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/tukey.json new file mode 100644 index 0000000000000..5dc1b7f83ca51 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/new/tukey.json @@ -0,0 +1 @@ +[180.33215449206853,191.91248699003768,222.7933736512888,234.37370614925797] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/MAD.svg new file mode 100644 index 0000000000000..d9c7def6cb5b7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/MAD.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 3.5 + + + + + 4 + + + + + 4.5 + + + + + 5 + + + + + 5.5 + + + + + 6 + + + + + 6.5 + + + + + 7 + + + + + 7.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/SD.svg new file mode 100644 index 0000000000000..7fd346b64c758 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/SD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 5.5 + + + + + 6 + + + + + 6.5 + + + + + 7 + + + + + 7.5 + + + + + 8 + + + + + 8.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/index.html new file mode 100644 index 0000000000000..d963b304fc597 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope204.37 ns206.43 ns208.38 ns
0.79912030.81115340.8001673
Mean205.77 ns207.17 ns208.57 ns
Std. Dev.5.8002 ns7.1709 ns8.5131 ns
Median206.60 ns207.57 ns208.82 ns
MAD3.7325 ns5.4494 ns7.1384 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/mean.svg new file mode 100644 index 0000000000000..ee5985de89c40 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 205.5 + + + + + 206 + + + + + 206.5 + + + + + 207 + + + + + 207.5 + + + + + 208 + + + + + 208.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/median.svg new file mode 100644 index 0000000000000..6aaa845c8a3d1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/median.svg @@ -0,0 +1,308 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 0.9 + + + + + 1 + + + + + 206.5 + + + + + 207 + + + + + 207.5 + + + + + 208 + + + + + 208.5 + + + + + 209 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/pdf.svg new file mode 100644 index 0000000000000..c6cf91e2e01a5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/pdf.svg @@ -0,0 +1,435 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 70 + + + + + 80 + + + + + 90 + + + + + 190 + + + + + 200 + + + + + 210 + + + + + 220 + + + + + 230 + + + + + 240 + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..336ea1e0bcea2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/pdf_small.svg @@ -0,0 +1,214 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 190 + + + + + 200 + + + + + 210 + + + + + 220 + + + + + 230 + + + + + 240 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/regression.svg new file mode 100644 index 0000000000000..db7100f9b0f4f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/regression.svg @@ -0,0 +1,434 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 90 + + + + + + + + + + + + + 100 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/regression_small.svg new file mode 100644 index 0000000000000..cc02f0e47ab93 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/regression_small.svg @@ -0,0 +1,412 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 90 + + + + + + + + + + + + + 100 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/slope.svg new file mode 100644 index 0000000000000..7ef87275b329a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/slope.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 204 + + + + + 204.5 + + + + + 205 + + + + + 205.5 + + + + + 206 + + + + + 206.5 + + + + + 207 + + + + + 207.5 + + + + + 208 + + + + + 208.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/typical.svg new file mode 100644 index 0000000000000..2f2a7f6ce02f6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/mutex object poll/report/typical.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 204 + + + + + 204.5 + + + + + 205 + + + + + 205.5 + + + + + 206 + + + + + 206.5 + + + + + 207 + + + + + 207.5 + + + + + 208 + + + + + 208.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/benchmark.json new file mode 100644 index 0000000000000..e6e3159ce846f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:5)","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:5)/none object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_5)/none object poll","title":"forward msg from pull (nb_writter:1 nb_readder:5)/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/estimates.json new file mode 100644 index 0000000000000..350860fb36a9d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":287.65511177161994,"upper_bound":293.41754835633014},"point_estimate":290.4670464283222,"standard_error":1.4675687412343108},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":287.6113455227379,"upper_bound":292.3939338347704},"point_estimate":290.16224966553466,"standard_error":1.3281660443956276},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":8.544099630272505,"upper_bound":14.018961155239326},"point_estimate":11.525040220452219,"standard_error":1.37965267160143},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":283.4234475224672,"upper_bound":291.2321241514053},"point_estimate":287.34420135193193,"standard_error":1.9926667444286594},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":11.52375085132172,"upper_bound":17.982240777333224},"point_estimate":14.773906469749935,"standard_error":1.6686241099759433}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/raw.csv new file mode 100644 index 0000000000000..c354b0ca87bcd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,251833.0,ns,711 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,420383.0,ns,1422 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,613475.0,ns,2133 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,956587.0,ns,2844 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,1059241.0,ns,3555 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,1223340.0,ns,4266 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,1429565.0,ns,4977 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,1737297.0,ns,5688 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,1724704.0,ns,6399 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,2241975.0,ns,7110 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,2324474.0,ns,7821 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,2528209.0,ns,8532 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,2696748.0,ns,9243 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,2915599.0,ns,9954 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,2946271.0,ns,10665 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,3342114.0,ns,11376 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,3481375.0,ns,12087 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,3785867.0,ns,12798 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,3930453.0,ns,13509 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,4151118.0,ns,14220 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,4217491.0,ns,14931 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,4744431.0,ns,15642 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,4781518.0,ns,16353 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,5030977.0,ns,17064 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,5159657.0,ns,17775 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,5435169.0,ns,18486 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,5880552.0,ns,19197 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,5608969.0,ns,19908 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,5952959.0,ns,20619 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,6102832.0,ns,21330 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,6650810.0,ns,22041 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7080670.0,ns,22752 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,6635741.0,ns,23463 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7732093.0,ns,24174 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7313886.0,ns,24885 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7620365.0,ns,25596 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7578526.0,ns,26307 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7362861.0,ns,27018 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7815875.0,ns,27729 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,8004553.0,ns,28440 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,8455202.0,ns,29151 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,8681385.0,ns,29862 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,8811144.0,ns,30573 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9870603.0,ns,31284 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9543745.0,ns,31995 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9510378.0,ns,32706 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9374306.0,ns,33417 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9948611.0,ns,34128 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,10324361.0,ns,34839 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9617352.0,ns,35550 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9690685.0,ns,36261 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,10447497.0,ns,36972 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,10795232.0,ns,37683 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,11738615.0,ns,38394 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,11008496.0,ns,39105 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,11065335.0,ns,39816 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,11409391.0,ns,40527 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,11622745.0,ns,41238 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12186512.0,ns,41949 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12708989.0,ns,42660 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12097445.0,ns,43371 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12912329.0,ns,44082 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12488544.0,ns,44793 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,13115543.0,ns,45504 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,13146948.0,ns,46215 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,14094518.0,ns,46926 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12701115.0,ns,47637 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12990945.0,ns,48348 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,13909676.0,ns,49059 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,14397517.0,ns,49770 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,13921297.0,ns,50481 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,15439093.0,ns,51192 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,15855907.0,ns,51903 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,15444454.0,ns,52614 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,15377398.0,ns,53325 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16115619.0,ns,54036 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16534843.0,ns,54747 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,17289441.0,ns,55458 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16581913.0,ns,56169 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16425918.0,ns,56880 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16480373.0,ns,57591 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16689758.0,ns,58302 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16016223.0,ns,59013 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,15765660.0,ns,59724 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,17150609.0,ns,60435 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16959848.0,ns,61146 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16997593.0,ns,61857 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,18881936.0,ns,62568 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16192104.0,ns,63279 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,18904194.0,ns,63990 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,20574512.0,ns,64701 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,19041898.0,ns,65412 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,19703917.0,ns,66123 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,17493031.0,ns,66834 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,20296026.0,ns,67545 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,17841338.0,ns,68256 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,20952779.0,ns,68967 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,19619589.0,ns,69678 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,20188423.0,ns,70389 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,20354530.0,ns,71100 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/sample.json new file mode 100644 index 0000000000000..6db0c305dbf63 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[711.0,1422.0,2133.0,2844.0,3555.0,4266.0,4977.0,5688.0,6399.0,7110.0,7821.0,8532.0,9243.0,9954.0,10665.0,11376.0,12087.0,12798.0,13509.0,14220.0,14931.0,15642.0,16353.0,17064.0,17775.0,18486.0,19197.0,19908.0,20619.0,21330.0,22041.0,22752.0,23463.0,24174.0,24885.0,25596.0,26307.0,27018.0,27729.0,28440.0,29151.0,29862.0,30573.0,31284.0,31995.0,32706.0,33417.0,34128.0,34839.0,35550.0,36261.0,36972.0,37683.0,38394.0,39105.0,39816.0,40527.0,41238.0,41949.0,42660.0,43371.0,44082.0,44793.0,45504.0,46215.0,46926.0,47637.0,48348.0,49059.0,49770.0,50481.0,51192.0,51903.0,52614.0,53325.0,54036.0,54747.0,55458.0,56169.0,56880.0,57591.0,58302.0,59013.0,59724.0,60435.0,61146.0,61857.0,62568.0,63279.0,63990.0,64701.0,65412.0,66123.0,66834.0,67545.0,68256.0,68967.0,69678.0,70389.0,71100.0],"times":[251833.0,420383.0,613475.0,956587.0,1059241.0,1223340.0,1429565.0,1737297.0,1724704.0,2241975.0,2324474.0,2528209.0,2696748.0,2915599.0,2946271.0,3342114.0,3481375.0,3785867.0,3930453.0,4151118.0,4217491.0,4744431.0,4781518.0,5030977.0,5159657.0,5435169.0,5880552.0,5608969.0,5952959.0,6102832.0,6650810.0,7080670.0,6635741.0,7732093.0,7313886.0,7620365.0,7578526.0,7362861.0,7815875.0,8004553.0,8455202.0,8681385.0,8811144.0,9870603.0,9543745.0,9510378.0,9374306.0,9948611.0,10324361.0,9617352.0,9690685.0,10447497.0,10795232.0,11738615.0,11008496.0,11065335.0,11409391.0,11622745.0,12186512.0,12708989.0,12097445.0,12912329.0,12488544.0,13115543.0,13146948.0,14094518.0,12701115.0,12990945.0,13909676.0,14397517.0,13921297.0,15439093.0,15855907.0,15444454.0,15377398.0,16115619.0,16534843.0,17289441.0,16581913.0,16425918.0,16480373.0,16689758.0,16016223.0,15765660.0,17150609.0,16959848.0,16997593.0,18881936.0,16192104.0,18904194.0,20574512.0,19041898.0,19703917.0,17493031.0,20296026.0,17841338.0,20952779.0,19619589.0,20188423.0,20354530.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/tukey.json new file mode 100644 index 0000000000000..dcb03188fb63a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/base/tukey.json @@ -0,0 +1 @@ +[234.1464613481964,258.0038405578126,321.62351845012256,345.4808976597388] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/benchmark.json new file mode 100644 index 0000000000000..e6e3159ce846f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:5)","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:5)/none object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_5)/none object poll","title":"forward msg from pull (nb_writter:1 nb_readder:5)/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/estimates.json new file mode 100644 index 0000000000000..350860fb36a9d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":287.65511177161994,"upper_bound":293.41754835633014},"point_estimate":290.4670464283222,"standard_error":1.4675687412343108},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":287.6113455227379,"upper_bound":292.3939338347704},"point_estimate":290.16224966553466,"standard_error":1.3281660443956276},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":8.544099630272505,"upper_bound":14.018961155239326},"point_estimate":11.525040220452219,"standard_error":1.37965267160143},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":283.4234475224672,"upper_bound":291.2321241514053},"point_estimate":287.34420135193193,"standard_error":1.9926667444286594},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":11.52375085132172,"upper_bound":17.982240777333224},"point_estimate":14.773906469749935,"standard_error":1.6686241099759433}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/raw.csv new file mode 100644 index 0000000000000..c354b0ca87bcd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,251833.0,ns,711 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,420383.0,ns,1422 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,613475.0,ns,2133 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,956587.0,ns,2844 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,1059241.0,ns,3555 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,1223340.0,ns,4266 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,1429565.0,ns,4977 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,1737297.0,ns,5688 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,1724704.0,ns,6399 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,2241975.0,ns,7110 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,2324474.0,ns,7821 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,2528209.0,ns,8532 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,2696748.0,ns,9243 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,2915599.0,ns,9954 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,2946271.0,ns,10665 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,3342114.0,ns,11376 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,3481375.0,ns,12087 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,3785867.0,ns,12798 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,3930453.0,ns,13509 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,4151118.0,ns,14220 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,4217491.0,ns,14931 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,4744431.0,ns,15642 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,4781518.0,ns,16353 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,5030977.0,ns,17064 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,5159657.0,ns,17775 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,5435169.0,ns,18486 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,5880552.0,ns,19197 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,5608969.0,ns,19908 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,5952959.0,ns,20619 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,6102832.0,ns,21330 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,6650810.0,ns,22041 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7080670.0,ns,22752 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,6635741.0,ns,23463 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7732093.0,ns,24174 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7313886.0,ns,24885 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7620365.0,ns,25596 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7578526.0,ns,26307 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7362861.0,ns,27018 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,7815875.0,ns,27729 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,8004553.0,ns,28440 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,8455202.0,ns,29151 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,8681385.0,ns,29862 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,8811144.0,ns,30573 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9870603.0,ns,31284 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9543745.0,ns,31995 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9510378.0,ns,32706 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9374306.0,ns,33417 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9948611.0,ns,34128 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,10324361.0,ns,34839 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9617352.0,ns,35550 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,9690685.0,ns,36261 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,10447497.0,ns,36972 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,10795232.0,ns,37683 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,11738615.0,ns,38394 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,11008496.0,ns,39105 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,11065335.0,ns,39816 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,11409391.0,ns,40527 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,11622745.0,ns,41238 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12186512.0,ns,41949 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12708989.0,ns,42660 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12097445.0,ns,43371 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12912329.0,ns,44082 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12488544.0,ns,44793 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,13115543.0,ns,45504 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,13146948.0,ns,46215 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,14094518.0,ns,46926 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12701115.0,ns,47637 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,12990945.0,ns,48348 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,13909676.0,ns,49059 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,14397517.0,ns,49770 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,13921297.0,ns,50481 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,15439093.0,ns,51192 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,15855907.0,ns,51903 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,15444454.0,ns,52614 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,15377398.0,ns,53325 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16115619.0,ns,54036 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16534843.0,ns,54747 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,17289441.0,ns,55458 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16581913.0,ns,56169 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16425918.0,ns,56880 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16480373.0,ns,57591 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16689758.0,ns,58302 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16016223.0,ns,59013 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,15765660.0,ns,59724 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,17150609.0,ns,60435 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16959848.0,ns,61146 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16997593.0,ns,61857 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,18881936.0,ns,62568 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,16192104.0,ns,63279 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,18904194.0,ns,63990 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,20574512.0,ns,64701 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,19041898.0,ns,65412 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,19703917.0,ns,66123 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,17493031.0,ns,66834 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,20296026.0,ns,67545 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,17841338.0,ns,68256 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,20952779.0,ns,68967 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,19619589.0,ns,69678 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,20188423.0,ns,70389 +forward msg from pull (nb_writter:1 nb_readder:5),none object poll,,,,20354530.0,ns,71100 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/sample.json new file mode 100644 index 0000000000000..6db0c305dbf63 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[711.0,1422.0,2133.0,2844.0,3555.0,4266.0,4977.0,5688.0,6399.0,7110.0,7821.0,8532.0,9243.0,9954.0,10665.0,11376.0,12087.0,12798.0,13509.0,14220.0,14931.0,15642.0,16353.0,17064.0,17775.0,18486.0,19197.0,19908.0,20619.0,21330.0,22041.0,22752.0,23463.0,24174.0,24885.0,25596.0,26307.0,27018.0,27729.0,28440.0,29151.0,29862.0,30573.0,31284.0,31995.0,32706.0,33417.0,34128.0,34839.0,35550.0,36261.0,36972.0,37683.0,38394.0,39105.0,39816.0,40527.0,41238.0,41949.0,42660.0,43371.0,44082.0,44793.0,45504.0,46215.0,46926.0,47637.0,48348.0,49059.0,49770.0,50481.0,51192.0,51903.0,52614.0,53325.0,54036.0,54747.0,55458.0,56169.0,56880.0,57591.0,58302.0,59013.0,59724.0,60435.0,61146.0,61857.0,62568.0,63279.0,63990.0,64701.0,65412.0,66123.0,66834.0,67545.0,68256.0,68967.0,69678.0,70389.0,71100.0],"times":[251833.0,420383.0,613475.0,956587.0,1059241.0,1223340.0,1429565.0,1737297.0,1724704.0,2241975.0,2324474.0,2528209.0,2696748.0,2915599.0,2946271.0,3342114.0,3481375.0,3785867.0,3930453.0,4151118.0,4217491.0,4744431.0,4781518.0,5030977.0,5159657.0,5435169.0,5880552.0,5608969.0,5952959.0,6102832.0,6650810.0,7080670.0,6635741.0,7732093.0,7313886.0,7620365.0,7578526.0,7362861.0,7815875.0,8004553.0,8455202.0,8681385.0,8811144.0,9870603.0,9543745.0,9510378.0,9374306.0,9948611.0,10324361.0,9617352.0,9690685.0,10447497.0,10795232.0,11738615.0,11008496.0,11065335.0,11409391.0,11622745.0,12186512.0,12708989.0,12097445.0,12912329.0,12488544.0,13115543.0,13146948.0,14094518.0,12701115.0,12990945.0,13909676.0,14397517.0,13921297.0,15439093.0,15855907.0,15444454.0,15377398.0,16115619.0,16534843.0,17289441.0,16581913.0,16425918.0,16480373.0,16689758.0,16016223.0,15765660.0,17150609.0,16959848.0,16997593.0,18881936.0,16192104.0,18904194.0,20574512.0,19041898.0,19703917.0,17493031.0,20296026.0,17841338.0,20952779.0,19619589.0,20188423.0,20354530.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/tukey.json new file mode 100644 index 0000000000000..dcb03188fb63a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/new/tukey.json @@ -0,0 +1 @@ +[234.1464613481964,258.0038405578126,321.62351845012256,345.4808976597388] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/MAD.svg new file mode 100644 index 0000000000000..710e5456bee44 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/MAD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 14 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/none object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/SD.svg new file mode 100644 index 0000000000000..dde55dc5378a3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/SD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 14 + + + + + 15 + + + + + 16 + + + + + 17 + + + + + 18 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/none object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/index.html new file mode 100644 index 0000000000000..863dbb46f08bd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/none object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:1 nb_readder:5)/none object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope283.42 ns287.34 ns291.23 ns
0.73270170.74705860.7329366
Mean287.66 ns290.47 ns293.42 ns
Std. Dev.11.524 ns14.774 ns17.982 ns
Median287.61 ns290.16 ns292.39 ns
MAD8.5441 ns11.525 ns14.019 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/mean.svg new file mode 100644 index 0000000000000..9b47d516b5fea --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 288 + + + + + 289 + + + + + 290 + + + + + 291 + + + + + 292 + + + + + 293 + + + + + 294 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/none object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/median.svg new file mode 100644 index 0000000000000..4e6a0dc8407d3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/median.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 0.5 + + + + + 288 + + + + + 289 + + + + + 290 + + + + + 291 + + + + + 292 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/none object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/pdf.svg new file mode 100644 index 0000000000000..41e056a28b3c4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/pdf.svg @@ -0,0 +1,430 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 70 + + + + + 240 + + + + + 260 + + + + + 280 + + + + + 300 + + + + + 320 + + + + + 340 + + + + + 360 + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/none object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..d49d998aa47c7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/pdf_small.svg @@ -0,0 +1,214 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 240 + + + + + 260 + + + + + 280 + + + + + 300 + + + + + 320 + + + + + 340 + + + + + 360 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/regression.svg new file mode 100644 index 0000000000000..34318d6817674 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/regression.svg @@ -0,0 +1,408 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/none object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/regression_small.svg new file mode 100644 index 0000000000000..237f695eec1b8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/regression_small.svg @@ -0,0 +1,386 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/slope.svg new file mode 100644 index 0000000000000..d1c2ea83385df --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/slope.svg @@ -0,0 +1,328 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 0.16 + + + + + 0.18 + + + + + 0.2 + + + + + 283 + + + + + 284 + + + + + 285 + + + + + 286 + + + + + 287 + + + + + 288 + + + + + 289 + + + + + 290 + + + + + 291 + + + + + 292 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/none object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/typical.svg new file mode 100644 index 0000000000000..f807d80758934 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/none object poll/report/typical.svg @@ -0,0 +1,328 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 0.16 + + + + + 0.18 + + + + + 0.2 + + + + + 283 + + + + + 284 + + + + + 285 + + + + + 286 + + + + + 287 + + + + + 288 + + + + + 289 + + + + + 290 + + + + + 291 + + + + + 292 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/none object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/report/index.html new file mode 100644 index 0000000000000..72c073334ae4b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/report/index.html @@ -0,0 +1,185 @@ + + + + + + forward msg from pull (nb_writter:1 nb_readder:5) Summary - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:1 nb_readder:5)

+

Violin Plot

+ + Violin Plot + +

This chart shows the relationship between function/parameter and iteration time. The thickness of the shaded + region indicates the probability that a measurement of the given function/parameter would take a particular + length of time.

+
+ +

forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab'

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:1 nb_readder:5)/none object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/report/violin.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/report/violin.svg new file mode 100644 index 0000000000000..737ef8377bd93 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/report/violin.svg @@ -0,0 +1,556 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/none object poll + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/mutex object poll + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/linear object poll + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/crate 'sharded-slab' + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 400 + + + + + + + + + + + + + 600 + + + + + + + + + + + + + 800 + + + + + + + + + + + + + 1000 + + + + + + + + + + + + + 1200 + + + + + + + + + + + + + 1400 + + + + + + + + + Input + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5): Violin plot + + + + + PDF + + + PDF + + + + + + + + + + gnuplot_plot_2 + + + + + + + gnuplot_plot_3 + + + + + + + gnuplot_plot_4 + + + + + + + gnuplot_plot_5 + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/benchmark.json new file mode 100644 index 0000000000000..ce023a6893de7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:5)","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll","title":"forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/estimates.json new file mode 100644 index 0000000000000..5586f4ea25be5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":181.0915333901922,"upper_bound":184.16671023291715},"point_estimate":182.62394377816483,"standard_error":0.7840297954484706},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":181.11970413980697,"upper_bound":183.97227086981903},"point_estimate":182.39921153471943,"standard_error":0.7610668614772096},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":4.0769628783581195,"upper_bound":7.3494561151870865},"point_estimate":5.610631915088671,"standard_error":0.8585545295421367},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":178.87061603738553,"upper_bound":182.80735191029888},"point_estimate":180.86587005497213,"standard_error":1.003244639231668},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":6.513669935272382,"upper_bound":9.150976589375118},"point_estimate":7.901758484610737,"standard_error":0.6724630650913372}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/raw.csv new file mode 100644 index 0000000000000..a8e80ada254f6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,190132.0,ns,1142 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,434439.0,ns,2284 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,621658.0,ns,3426 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,905741.0,ns,4568 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,1053255.0,ns,5710 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,1226396.0,ns,6852 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,1481511.0,ns,7994 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,1857520.0,ns,9136 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,1914343.0,ns,10278 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,2259819.0,ns,11420 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,2602550.0,ns,12562 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,2570487.0,ns,13704 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,2816136.0,ns,14846 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,3142153.0,ns,15988 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,3192635.0,ns,17130 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,3303572.0,ns,18272 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,3498915.0,ns,19414 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,3750385.0,ns,20556 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,3894576.0,ns,21698 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,4092882.0,ns,22840 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,4469548.0,ns,23982 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,4535826.0,ns,25124 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,4713590.0,ns,26266 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,5019730.0,ns,27408 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,5470533.0,ns,28550 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,5414372.0,ns,29692 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,5672601.0,ns,30834 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,5883483.0,ns,31976 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,6078366.0,ns,33118 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,6761077.0,ns,34260 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,6404008.0,ns,35402 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,6715035.0,ns,36544 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,6926408.0,ns,37686 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,7029778.0,ns,38828 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,7383259.0,ns,39970 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,7565070.0,ns,41112 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,7794367.0,ns,42254 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,7459927.0,ns,43396 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,7905388.0,ns,44538 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,8717439.0,ns,45680 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,8211940.0,ns,46822 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,8970564.0,ns,47964 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,9051392.0,ns,49106 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,8657745.0,ns,50248 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,9115956.0,ns,51390 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,9198735.0,ns,52532 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,9721419.0,ns,53674 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,9849313.0,ns,54816 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,10671216.0,ns,55958 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,10225183.0,ns,57100 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,10407131.0,ns,58242 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,10753985.0,ns,59384 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11913887.0,ns,60526 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11232581.0,ns,61668 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11148486.0,ns,62810 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11433438.0,ns,63952 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,12027186.0,ns,65094 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,12036207.0,ns,66236 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11964735.0,ns,67378 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11858974.0,ns,68520 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11723963.0,ns,69662 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,12725046.0,ns,70804 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,13616499.0,ns,71946 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,13371271.0,ns,73088 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,13852136.0,ns,74230 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,12776682.0,ns,75372 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,13175834.0,ns,76514 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,14675830.0,ns,77656 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,14298460.0,ns,78798 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,15716167.0,ns,79940 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,14939916.0,ns,81082 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,15231588.0,ns,82224 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,15339776.0,ns,83366 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,15766580.0,ns,84508 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,15708677.0,ns,85650 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,16003859.0,ns,86792 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,15098027.0,ns,87934 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,14806765.0,ns,89076 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,14540397.0,ns,90218 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,16790984.0,ns,91360 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,17881239.0,ns,92502 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,16586711.0,ns,93644 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,17278770.0,ns,94786 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,17001321.0,ns,95928 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18686904.0,ns,97070 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,17826469.0,ns,98212 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18897205.0,ns,99354 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,16752233.0,ns,100496 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18328559.0,ns,101638 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18320035.0,ns,102780 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18784590.0,ns,103922 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18210064.0,ns,105064 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,19991539.0,ns,106206 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,19942253.0,ns,107348 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,19781910.0,ns,108490 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18741306.0,ns,109632 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,20313362.0,ns,110774 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,20958807.0,ns,111916 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,20578176.0,ns,113058 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,19511937.0,ns,114200 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/sample.json new file mode 100644 index 0000000000000..181b35391ba37 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[1142.0,2284.0,3426.0,4568.0,5710.0,6852.0,7994.0,9136.0,10278.0,11420.0,12562.0,13704.0,14846.0,15988.0,17130.0,18272.0,19414.0,20556.0,21698.0,22840.0,23982.0,25124.0,26266.0,27408.0,28550.0,29692.0,30834.0,31976.0,33118.0,34260.0,35402.0,36544.0,37686.0,38828.0,39970.0,41112.0,42254.0,43396.0,44538.0,45680.0,46822.0,47964.0,49106.0,50248.0,51390.0,52532.0,53674.0,54816.0,55958.0,57100.0,58242.0,59384.0,60526.0,61668.0,62810.0,63952.0,65094.0,66236.0,67378.0,68520.0,69662.0,70804.0,71946.0,73088.0,74230.0,75372.0,76514.0,77656.0,78798.0,79940.0,81082.0,82224.0,83366.0,84508.0,85650.0,86792.0,87934.0,89076.0,90218.0,91360.0,92502.0,93644.0,94786.0,95928.0,97070.0,98212.0,99354.0,100496.0,101638.0,102780.0,103922.0,105064.0,106206.0,107348.0,108490.0,109632.0,110774.0,111916.0,113058.0,114200.0],"times":[190132.0,434439.0,621658.0,905741.0,1053255.0,1226396.0,1481511.0,1857520.0,1914343.0,2259819.0,2602550.0,2570487.0,2816136.0,3142153.0,3192635.0,3303572.0,3498915.0,3750385.0,3894576.0,4092882.0,4469548.0,4535826.0,4713590.0,5019730.0,5470533.0,5414372.0,5672601.0,5883483.0,6078366.0,6761077.0,6404008.0,6715035.0,6926408.0,7029778.0,7383259.0,7565070.0,7794367.0,7459927.0,7905388.0,8717439.0,8211940.0,8970564.0,9051392.0,8657745.0,9115956.0,9198735.0,9721419.0,9849313.0,10671216.0,10225183.0,10407131.0,10753985.0,11913887.0,11232581.0,11148486.0,11433438.0,12027186.0,12036207.0,11964735.0,11858974.0,11723963.0,12725046.0,13616499.0,13371271.0,13852136.0,12776682.0,13175834.0,14675830.0,14298460.0,15716167.0,14939916.0,15231588.0,15339776.0,15766580.0,15708677.0,16003859.0,15098027.0,14806765.0,14540397.0,16790984.0,17881239.0,16586711.0,17278770.0,17001321.0,18686904.0,17826469.0,18897205.0,16752233.0,18328559.0,18320035.0,18784590.0,18210064.0,19991539.0,19942253.0,19781910.0,18741306.0,20313362.0,20958807.0,20578176.0,19511937.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/tukey.json new file mode 100644 index 0000000000000..95c806e67d360 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/base/tukey.json @@ -0,0 +1 @@ +[156.6152739554666,167.7742017450588,197.53134251730467,208.69027030689685] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/benchmark.json new file mode 100644 index 0000000000000..ce023a6893de7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:1 nb_readder:5)","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll","directory_name":"forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll","title":"forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/estimates.json new file mode 100644 index 0000000000000..5586f4ea25be5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":181.0915333901922,"upper_bound":184.16671023291715},"point_estimate":182.62394377816483,"standard_error":0.7840297954484706},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":181.11970413980697,"upper_bound":183.97227086981903},"point_estimate":182.39921153471943,"standard_error":0.7610668614772096},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":4.0769628783581195,"upper_bound":7.3494561151870865},"point_estimate":5.610631915088671,"standard_error":0.8585545295421367},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":178.87061603738553,"upper_bound":182.80735191029888},"point_estimate":180.86587005497213,"standard_error":1.003244639231668},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":6.513669935272382,"upper_bound":9.150976589375118},"point_estimate":7.901758484610737,"standard_error":0.6724630650913372}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/raw.csv new file mode 100644 index 0000000000000..a8e80ada254f6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,190132.0,ns,1142 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,434439.0,ns,2284 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,621658.0,ns,3426 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,905741.0,ns,4568 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,1053255.0,ns,5710 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,1226396.0,ns,6852 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,1481511.0,ns,7994 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,1857520.0,ns,9136 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,1914343.0,ns,10278 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,2259819.0,ns,11420 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,2602550.0,ns,12562 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,2570487.0,ns,13704 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,2816136.0,ns,14846 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,3142153.0,ns,15988 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,3192635.0,ns,17130 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,3303572.0,ns,18272 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,3498915.0,ns,19414 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,3750385.0,ns,20556 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,3894576.0,ns,21698 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,4092882.0,ns,22840 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,4469548.0,ns,23982 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,4535826.0,ns,25124 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,4713590.0,ns,26266 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,5019730.0,ns,27408 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,5470533.0,ns,28550 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,5414372.0,ns,29692 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,5672601.0,ns,30834 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,5883483.0,ns,31976 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,6078366.0,ns,33118 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,6761077.0,ns,34260 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,6404008.0,ns,35402 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,6715035.0,ns,36544 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,6926408.0,ns,37686 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,7029778.0,ns,38828 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,7383259.0,ns,39970 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,7565070.0,ns,41112 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,7794367.0,ns,42254 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,7459927.0,ns,43396 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,7905388.0,ns,44538 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,8717439.0,ns,45680 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,8211940.0,ns,46822 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,8970564.0,ns,47964 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,9051392.0,ns,49106 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,8657745.0,ns,50248 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,9115956.0,ns,51390 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,9198735.0,ns,52532 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,9721419.0,ns,53674 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,9849313.0,ns,54816 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,10671216.0,ns,55958 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,10225183.0,ns,57100 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,10407131.0,ns,58242 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,10753985.0,ns,59384 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11913887.0,ns,60526 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11232581.0,ns,61668 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11148486.0,ns,62810 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11433438.0,ns,63952 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,12027186.0,ns,65094 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,12036207.0,ns,66236 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11964735.0,ns,67378 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11858974.0,ns,68520 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,11723963.0,ns,69662 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,12725046.0,ns,70804 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,13616499.0,ns,71946 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,13371271.0,ns,73088 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,13852136.0,ns,74230 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,12776682.0,ns,75372 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,13175834.0,ns,76514 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,14675830.0,ns,77656 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,14298460.0,ns,78798 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,15716167.0,ns,79940 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,14939916.0,ns,81082 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,15231588.0,ns,82224 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,15339776.0,ns,83366 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,15766580.0,ns,84508 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,15708677.0,ns,85650 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,16003859.0,ns,86792 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,15098027.0,ns,87934 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,14806765.0,ns,89076 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,14540397.0,ns,90218 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,16790984.0,ns,91360 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,17881239.0,ns,92502 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,16586711.0,ns,93644 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,17278770.0,ns,94786 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,17001321.0,ns,95928 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18686904.0,ns,97070 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,17826469.0,ns,98212 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18897205.0,ns,99354 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,16752233.0,ns,100496 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18328559.0,ns,101638 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18320035.0,ns,102780 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18784590.0,ns,103922 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18210064.0,ns,105064 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,19991539.0,ns,106206 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,19942253.0,ns,107348 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,19781910.0,ns,108490 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,18741306.0,ns,109632 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,20313362.0,ns,110774 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,20958807.0,ns,111916 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,20578176.0,ns,113058 +forward msg from pull (nb_writter:1 nb_readder:5),spin_lock object poll,,,,19511937.0,ns,114200 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/sample.json new file mode 100644 index 0000000000000..181b35391ba37 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[1142.0,2284.0,3426.0,4568.0,5710.0,6852.0,7994.0,9136.0,10278.0,11420.0,12562.0,13704.0,14846.0,15988.0,17130.0,18272.0,19414.0,20556.0,21698.0,22840.0,23982.0,25124.0,26266.0,27408.0,28550.0,29692.0,30834.0,31976.0,33118.0,34260.0,35402.0,36544.0,37686.0,38828.0,39970.0,41112.0,42254.0,43396.0,44538.0,45680.0,46822.0,47964.0,49106.0,50248.0,51390.0,52532.0,53674.0,54816.0,55958.0,57100.0,58242.0,59384.0,60526.0,61668.0,62810.0,63952.0,65094.0,66236.0,67378.0,68520.0,69662.0,70804.0,71946.0,73088.0,74230.0,75372.0,76514.0,77656.0,78798.0,79940.0,81082.0,82224.0,83366.0,84508.0,85650.0,86792.0,87934.0,89076.0,90218.0,91360.0,92502.0,93644.0,94786.0,95928.0,97070.0,98212.0,99354.0,100496.0,101638.0,102780.0,103922.0,105064.0,106206.0,107348.0,108490.0,109632.0,110774.0,111916.0,113058.0,114200.0],"times":[190132.0,434439.0,621658.0,905741.0,1053255.0,1226396.0,1481511.0,1857520.0,1914343.0,2259819.0,2602550.0,2570487.0,2816136.0,3142153.0,3192635.0,3303572.0,3498915.0,3750385.0,3894576.0,4092882.0,4469548.0,4535826.0,4713590.0,5019730.0,5470533.0,5414372.0,5672601.0,5883483.0,6078366.0,6761077.0,6404008.0,6715035.0,6926408.0,7029778.0,7383259.0,7565070.0,7794367.0,7459927.0,7905388.0,8717439.0,8211940.0,8970564.0,9051392.0,8657745.0,9115956.0,9198735.0,9721419.0,9849313.0,10671216.0,10225183.0,10407131.0,10753985.0,11913887.0,11232581.0,11148486.0,11433438.0,12027186.0,12036207.0,11964735.0,11858974.0,11723963.0,12725046.0,13616499.0,13371271.0,13852136.0,12776682.0,13175834.0,14675830.0,14298460.0,15716167.0,14939916.0,15231588.0,15339776.0,15766580.0,15708677.0,16003859.0,15098027.0,14806765.0,14540397.0,16790984.0,17881239.0,16586711.0,17278770.0,17001321.0,18686904.0,17826469.0,18897205.0,16752233.0,18328559.0,18320035.0,18784590.0,18210064.0,19991539.0,19942253.0,19781910.0,18741306.0,20313362.0,20958807.0,20578176.0,19511937.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/tukey.json new file mode 100644 index 0000000000000..95c806e67d360 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/new/tukey.json @@ -0,0 +1 @@ +[156.6152739554666,167.7742017450588,197.53134251730467,208.69027030689685] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/MAD.svg new file mode 100644 index 0000000000000..3dd17edf90ae6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/MAD.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 0.5 + + + + + 4 + + + + + 4.5 + + + + + 5 + + + + + 5.5 + + + + + 6 + + + + + 6.5 + + + + + 7 + + + + + 7.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/SD.svg new file mode 100644 index 0000000000000..384b9deba9cf2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/SD.svg @@ -0,0 +1,288 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 6.5 + + + + + 7 + + + + + 7.5 + + + + + 8 + + + + + 8.5 + + + + + 9 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/index.html new file mode 100644 index 0000000000000..39953ffeb49ae --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope178.87 ns180.87 ns182.81 ns
0.75632120.76877900.7569734
Mean181.09 ns182.62 ns184.17 ns
Std. Dev.6.5137 ns7.9018 ns9.1510 ns
Median181.12 ns182.40 ns183.97 ns
MAD4.0770 ns5.6106 ns7.3495 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/mean.svg new file mode 100644 index 0000000000000..70e3cece9f461 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/mean.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 181 + + + + + 181.5 + + + + + 182 + + + + + 182.5 + + + + + 183 + + + + + 183.5 + + + + + 184 + + + + + 184.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/median.svg new file mode 100644 index 0000000000000..2846bcffc032e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/median.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 181 + + + + + 181.5 + + + + + 182 + + + + + 182.5 + + + + + 183 + + + + + 183.5 + + + + + 184 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/pdf.svg new file mode 100644 index 0000000000000..2fe56b852493a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/pdf.svg @@ -0,0 +1,400 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 20 + + + + + 40 + + + + + 60 + + + + + 80 + + + + + 100 + + + + + 160 + + + + + 170 + + + + + 180 + + + + + 190 + + + + + 200 + + + + + 210 + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + + + + + + gnuplot_plot_5 + + + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..e5a8dc14b11c7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/pdf_small.svg @@ -0,0 +1,209 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 160 + + + + + 170 + + + + + 180 + + + + + 190 + + + + + 200 + + + + + 210 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/regression.svg new file mode 100644 index 0000000000000..349236abeef4d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/regression.svg @@ -0,0 +1,382 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 120 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/regression_small.svg new file mode 100644 index 0000000000000..b5d5f927e5bf4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/regression_small.svg @@ -0,0 +1,360 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 80 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 120 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/slope.svg new file mode 100644 index 0000000000000..5c9af536d433b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/slope.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 178.5 + + + + + 179 + + + + + 179.5 + + + + + 180 + + + + + 180.5 + + + + + 181 + + + + + 181.5 + + + + + 182 + + + + + 182.5 + + + + + 183 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/typical.svg new file mode 100644 index 0000000000000..d5331ca73e0ea --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_1 nb_readder_5)/spin_lock object poll/report/typical.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 178.5 + + + + + 179 + + + + + 179.5 + + + + + 180 + + + + + 180.5 + + + + + 181 + + + + + 181.5 + + + + + 182 + + + + + 182.5 + + + + + 183 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:1 nb_readder:5)/spin_lock object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/benchmark.json new file mode 100644 index 0000000000000..c7fe4720d0a1b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:1)","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab'","directory_name":"forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'","title":"forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/estimates.json new file mode 100644 index 0000000000000..ca12ab4470d80 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":881.6596039497817,"upper_bound":1053.5342373924427},"point_estimate":966.8697255719103,"standard_error":43.785277391087284},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":875.8090533384993,"upper_bound":1062.8765085969117},"point_estimate":972.6402376602206,"standard_error":46.14325810146606},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":370.2107007487615,"upper_bound":550.6816999795603},"point_estimate":484.13047441646114,"standard_error":49.44772092277192},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1145.1922571581424,"upper_bound":1342.287907327783},"point_estimate":1244.8475836968234,"standard_error":50.2076181114845},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":387.63242787526843,"upper_bound":485.16490525988206},"point_estimate":440.2378335703316,"standard_error":24.87650176003347}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/raw.csv new file mode 100644 index 0000000000000..d1f479293bcb6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,59756.0,ns,89 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,105750.0,ns,178 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,166239.0,ns,267 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,98876.0,ns,356 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,196765.0,ns,445 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,351710.0,ns,534 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,285170.0,ns,623 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,198022.0,ns,712 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,273254.0,ns,801 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,239530.0,ns,890 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,279878.0,ns,979 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,657693.0,ns,1068 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,304861.0,ns,1157 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,545911.0,ns,1246 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,343962.0,ns,1335 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,397847.0,ns,1424 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,395398.0,ns,1513 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,403223.0,ns,1602 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,436387.0,ns,1691 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,460281.0,ns,1780 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,484661.0,ns,1869 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,529075.0,ns,1958 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,1271009.0,ns,2047 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,1895056.0,ns,2136 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2081114.0,ns,2225 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2160730.0,ns,2314 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2198451.0,ns,2403 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2215606.0,ns,2492 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2231067.0,ns,2581 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2273886.0,ns,2670 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2150275.0,ns,2759 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2311337.0,ns,2848 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2238299.0,ns,2937 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2283677.0,ns,3026 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2374394.0,ns,3115 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2309471.0,ns,3204 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2404635.0,ns,3293 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2370013.0,ns,3382 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2409044.0,ns,3471 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2421633.0,ns,3560 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2231077.0,ns,3649 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2386668.0,ns,3738 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2429279.0,ns,3827 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2529146.0,ns,3916 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2588624.0,ns,4005 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6651365.0,ns,4094 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6309360.0,ns,4183 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6280515.0,ns,4272 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6264528.0,ns,4361 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6315033.0,ns,4450 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6395444.0,ns,4539 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6471955.0,ns,4628 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6544422.0,ns,4717 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6934430.0,ns,4806 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6794415.0,ns,4895 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6772183.0,ns,4984 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6643239.0,ns,5073 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6913877.0,ns,5162 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6376470.0,ns,5251 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6994631.0,ns,5340 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7336827.0,ns,5429 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7376432.0,ns,5518 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6638528.0,ns,5607 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7007138.0,ns,5696 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7209164.0,ns,5785 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7222868.0,ns,5874 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6781753.0,ns,5963 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7485493.0,ns,6052 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7437972.0,ns,6141 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7115112.0,ns,6230 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7577838.0,ns,6319 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7538335.0,ns,6408 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7554403.0,ns,6497 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7542885.0,ns,6586 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7626272.0,ns,6675 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6836340.0,ns,6764 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7451837.0,ns,6853 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7293913.0,ns,6942 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6863978.0,ns,7031 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6972460.0,ns,7120 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6947038.0,ns,7209 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7578023.0,ns,7298 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7454521.0,ns,7387 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7636509.0,ns,7476 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6807438.0,ns,7565 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7547426.0,ns,7654 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6841113.0,ns,7743 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7668516.0,ns,7832 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7776517.0,ns,7921 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7715860.0,ns,8010 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7848219.0,ns,8099 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,14260313.0,ns,8188 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,15084883.0,ns,8277 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,14825494.0,ns,8366 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,14948024.0,ns,8455 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,15467411.0,ns,8544 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,14585962.0,ns,8633 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,15511947.0,ns,8722 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,15305875.0,ns,8811 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,16349097.0,ns,8900 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/sample.json new file mode 100644 index 0000000000000..d62736c54eb5d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[89.0,178.0,267.0,356.0,445.0,534.0,623.0,712.0,801.0,890.0,979.0,1068.0,1157.0,1246.0,1335.0,1424.0,1513.0,1602.0,1691.0,1780.0,1869.0,1958.0,2047.0,2136.0,2225.0,2314.0,2403.0,2492.0,2581.0,2670.0,2759.0,2848.0,2937.0,3026.0,3115.0,3204.0,3293.0,3382.0,3471.0,3560.0,3649.0,3738.0,3827.0,3916.0,4005.0,4094.0,4183.0,4272.0,4361.0,4450.0,4539.0,4628.0,4717.0,4806.0,4895.0,4984.0,5073.0,5162.0,5251.0,5340.0,5429.0,5518.0,5607.0,5696.0,5785.0,5874.0,5963.0,6052.0,6141.0,6230.0,6319.0,6408.0,6497.0,6586.0,6675.0,6764.0,6853.0,6942.0,7031.0,7120.0,7209.0,7298.0,7387.0,7476.0,7565.0,7654.0,7743.0,7832.0,7921.0,8010.0,8099.0,8188.0,8277.0,8366.0,8455.0,8544.0,8633.0,8722.0,8811.0,8900.0],"times":[59756.0,105750.0,166239.0,98876.0,196765.0,351710.0,285170.0,198022.0,273254.0,239530.0,279878.0,657693.0,304861.0,545911.0,343962.0,397847.0,395398.0,403223.0,436387.0,460281.0,484661.0,529075.0,1271009.0,1895056.0,2081114.0,2160730.0,2198451.0,2215606.0,2231067.0,2273886.0,2150275.0,2311337.0,2238299.0,2283677.0,2374394.0,2309471.0,2404635.0,2370013.0,2409044.0,2421633.0,2231077.0,2386668.0,2429279.0,2529146.0,2588624.0,6651365.0,6309360.0,6280515.0,6264528.0,6315033.0,6395444.0,6471955.0,6544422.0,6934430.0,6794415.0,6772183.0,6643239.0,6913877.0,6376470.0,6994631.0,7336827.0,7376432.0,6638528.0,7007138.0,7209164.0,7222868.0,6781753.0,7485493.0,7437972.0,7115112.0,7577838.0,7538335.0,7554403.0,7542885.0,7626272.0,6836340.0,7451837.0,7293913.0,6863978.0,6972460.0,6947038.0,7578023.0,7454521.0,7636509.0,6807438.0,7547426.0,6841113.0,7668516.0,7776517.0,7715860.0,7848219.0,14260313.0,15084883.0,14825494.0,14948024.0,15467411.0,14585962.0,15511947.0,15305875.0,16349097.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/tukey.json new file mode 100644 index 0000000000000..f98355fb0f6ab --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/base/tukey.json @@ -0,0 +1 @@ +[-1201.1629196252202,-277.4697684608906,2185.7119679773214,3109.405119141651] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/benchmark.json new file mode 100644 index 0000000000000..c7fe4720d0a1b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:1)","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab'","directory_name":"forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'","title":"forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/estimates.json new file mode 100644 index 0000000000000..ca12ab4470d80 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":881.6596039497817,"upper_bound":1053.5342373924427},"point_estimate":966.8697255719103,"standard_error":43.785277391087284},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":875.8090533384993,"upper_bound":1062.8765085969117},"point_estimate":972.6402376602206,"standard_error":46.14325810146606},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":370.2107007487615,"upper_bound":550.6816999795603},"point_estimate":484.13047441646114,"standard_error":49.44772092277192},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1145.1922571581424,"upper_bound":1342.287907327783},"point_estimate":1244.8475836968234,"standard_error":50.2076181114845},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":387.63242787526843,"upper_bound":485.16490525988206},"point_estimate":440.2378335703316,"standard_error":24.87650176003347}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/raw.csv new file mode 100644 index 0000000000000..d1f479293bcb6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,59756.0,ns,89 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,105750.0,ns,178 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,166239.0,ns,267 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,98876.0,ns,356 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,196765.0,ns,445 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,351710.0,ns,534 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,285170.0,ns,623 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,198022.0,ns,712 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,273254.0,ns,801 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,239530.0,ns,890 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,279878.0,ns,979 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,657693.0,ns,1068 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,304861.0,ns,1157 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,545911.0,ns,1246 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,343962.0,ns,1335 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,397847.0,ns,1424 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,395398.0,ns,1513 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,403223.0,ns,1602 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,436387.0,ns,1691 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,460281.0,ns,1780 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,484661.0,ns,1869 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,529075.0,ns,1958 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,1271009.0,ns,2047 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,1895056.0,ns,2136 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2081114.0,ns,2225 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2160730.0,ns,2314 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2198451.0,ns,2403 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2215606.0,ns,2492 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2231067.0,ns,2581 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2273886.0,ns,2670 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2150275.0,ns,2759 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2311337.0,ns,2848 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2238299.0,ns,2937 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2283677.0,ns,3026 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2374394.0,ns,3115 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2309471.0,ns,3204 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2404635.0,ns,3293 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2370013.0,ns,3382 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2409044.0,ns,3471 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2421633.0,ns,3560 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2231077.0,ns,3649 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2386668.0,ns,3738 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2429279.0,ns,3827 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2529146.0,ns,3916 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,2588624.0,ns,4005 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6651365.0,ns,4094 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6309360.0,ns,4183 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6280515.0,ns,4272 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6264528.0,ns,4361 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6315033.0,ns,4450 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6395444.0,ns,4539 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6471955.0,ns,4628 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6544422.0,ns,4717 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6934430.0,ns,4806 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6794415.0,ns,4895 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6772183.0,ns,4984 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6643239.0,ns,5073 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6913877.0,ns,5162 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6376470.0,ns,5251 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6994631.0,ns,5340 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7336827.0,ns,5429 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7376432.0,ns,5518 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6638528.0,ns,5607 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7007138.0,ns,5696 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7209164.0,ns,5785 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7222868.0,ns,5874 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6781753.0,ns,5963 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7485493.0,ns,6052 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7437972.0,ns,6141 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7115112.0,ns,6230 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7577838.0,ns,6319 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7538335.0,ns,6408 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7554403.0,ns,6497 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7542885.0,ns,6586 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7626272.0,ns,6675 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6836340.0,ns,6764 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7451837.0,ns,6853 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7293913.0,ns,6942 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6863978.0,ns,7031 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6972460.0,ns,7120 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6947038.0,ns,7209 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7578023.0,ns,7298 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7454521.0,ns,7387 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7636509.0,ns,7476 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6807438.0,ns,7565 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7547426.0,ns,7654 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,6841113.0,ns,7743 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7668516.0,ns,7832 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7776517.0,ns,7921 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7715860.0,ns,8010 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,7848219.0,ns,8099 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,14260313.0,ns,8188 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,15084883.0,ns,8277 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,14825494.0,ns,8366 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,14948024.0,ns,8455 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,15467411.0,ns,8544 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,14585962.0,ns,8633 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,15511947.0,ns,8722 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,15305875.0,ns,8811 +forward msg from pull (nb_writter:5 nb_readder:1),crate 'sharded-slab',,,,16349097.0,ns,8900 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/sample.json new file mode 100644 index 0000000000000..d62736c54eb5d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[89.0,178.0,267.0,356.0,445.0,534.0,623.0,712.0,801.0,890.0,979.0,1068.0,1157.0,1246.0,1335.0,1424.0,1513.0,1602.0,1691.0,1780.0,1869.0,1958.0,2047.0,2136.0,2225.0,2314.0,2403.0,2492.0,2581.0,2670.0,2759.0,2848.0,2937.0,3026.0,3115.0,3204.0,3293.0,3382.0,3471.0,3560.0,3649.0,3738.0,3827.0,3916.0,4005.0,4094.0,4183.0,4272.0,4361.0,4450.0,4539.0,4628.0,4717.0,4806.0,4895.0,4984.0,5073.0,5162.0,5251.0,5340.0,5429.0,5518.0,5607.0,5696.0,5785.0,5874.0,5963.0,6052.0,6141.0,6230.0,6319.0,6408.0,6497.0,6586.0,6675.0,6764.0,6853.0,6942.0,7031.0,7120.0,7209.0,7298.0,7387.0,7476.0,7565.0,7654.0,7743.0,7832.0,7921.0,8010.0,8099.0,8188.0,8277.0,8366.0,8455.0,8544.0,8633.0,8722.0,8811.0,8900.0],"times":[59756.0,105750.0,166239.0,98876.0,196765.0,351710.0,285170.0,198022.0,273254.0,239530.0,279878.0,657693.0,304861.0,545911.0,343962.0,397847.0,395398.0,403223.0,436387.0,460281.0,484661.0,529075.0,1271009.0,1895056.0,2081114.0,2160730.0,2198451.0,2215606.0,2231067.0,2273886.0,2150275.0,2311337.0,2238299.0,2283677.0,2374394.0,2309471.0,2404635.0,2370013.0,2409044.0,2421633.0,2231077.0,2386668.0,2429279.0,2529146.0,2588624.0,6651365.0,6309360.0,6280515.0,6264528.0,6315033.0,6395444.0,6471955.0,6544422.0,6934430.0,6794415.0,6772183.0,6643239.0,6913877.0,6376470.0,6994631.0,7336827.0,7376432.0,6638528.0,7007138.0,7209164.0,7222868.0,6781753.0,7485493.0,7437972.0,7115112.0,7577838.0,7538335.0,7554403.0,7542885.0,7626272.0,6836340.0,7451837.0,7293913.0,6863978.0,6972460.0,6947038.0,7578023.0,7454521.0,7636509.0,6807438.0,7547426.0,6841113.0,7668516.0,7776517.0,7715860.0,7848219.0,14260313.0,15084883.0,14825494.0,14948024.0,15467411.0,14585962.0,15511947.0,15305875.0,16349097.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/tukey.json new file mode 100644 index 0000000000000..f98355fb0f6ab --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/new/tukey.json @@ -0,0 +1 @@ +[-1201.1629196252202,-277.4697684608906,2185.7119679773214,3109.405119141651] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/MAD.svg new file mode 100644 index 0000000000000..8e516ab6a5356 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 0.009 + + + + + 0.01 + + + + + 400 + + + + + 450 + + + + + 500 + + + + + 550 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab': MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/SD.svg new file mode 100644 index 0000000000000..75deed245aff0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 380 + + + + + 400 + + + + + 420 + + + + + 440 + + + + + 460 + + + + + 480 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab': SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/index.html new file mode 100644 index 0000000000000..b4ca9f0eb4b88 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab' - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab'

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope1.1452 us1.2448 us1.3423 us
0.24937040.26345490.2499578
Mean881.66 ns966.87 ns1.0535 us
Std. Dev.387.63 ns440.24 ns485.16 ns
Median875.81 ns972.64 ns1.0629 us
MAD370.21 ns484.13 ns550.68 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/mean.svg new file mode 100644 index 0000000000000..736edd50df840 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/mean.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 0.9 + + + + + 0.95 + + + + + 1 + + + + + 1.05 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab': mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/median.svg new file mode 100644 index 0000000000000..bb294d47fa92e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/median.svg @@ -0,0 +1,273 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 0.9 + + + + + 0.95 + + + + + 1 + + + + + 1.05 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab': median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/pdf.svg new file mode 100644 index 0000000000000..851958ed2072a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/pdf.svg @@ -0,0 +1,410 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab' + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/pdf_small.svg new file mode 100644 index 0000000000000..aa12642407e5b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/pdf_small.svg @@ -0,0 +1,214 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/regression.svg new file mode 100644 index 0000000000000..c8913c9ac6762 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/regression.svg @@ -0,0 +1,473 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 9 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab' + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/regression_small.svg new file mode 100644 index 0000000000000..cb5bc58e0776e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/regression_small.svg @@ -0,0 +1,451 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 9 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/slope.svg new file mode 100644 index 0000000000000..125be774d4d70 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 1.15 + + + + + 1.2 + + + + + 1.25 + + + + + 1.3 + + + + + 1.35 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab': slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/typical.svg new file mode 100644 index 0000000000000..df903e9a77e40 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/crate 'sharded-slab'/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 1.15 + + + + + 1.2 + + + + + 1.25 + + + + + 1.3 + + + + + 1.35 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab': typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/benchmark.json new file mode 100644 index 0000000000000..2b9cc77292d76 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:1)","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll","title":"forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/estimates.json new file mode 100644 index 0000000000000..aad3f01a97e75 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":360.91810293303774,"upper_bound":369.79589473803895},"point_estimate":365.559239207419,"standard_error":2.269924254864251},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":366.6931485237773,"upper_bound":375.70979672200934},"point_estimate":370.3161558786285,"standard_error":2.1191402508097434},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":11.435856818952168,"upper_bound":18.855104137488077},"point_estimate":15.85186152220244,"standard_error":1.971122246205825},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":372.54155246013744,"upper_bound":378.08360345897455},"point_estimate":375.35784582832963,"standard_error":1.4171613750550578},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":16.39128672086025,"upper_bound":28.682562025464325},"point_estimate":22.771818555360195,"standard_error":3.159584545848327}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/raw.csv new file mode 100644 index 0000000000000..43e4cb89d870c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,133887.0,ns,522 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,302762.0,ns,1044 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,483677.0,ns,1566 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,625172.0,ns,2088 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,810208.0,ns,2610 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,1028368.0,ns,3132 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,1164043.0,ns,3654 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,1401113.0,ns,4176 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,1601761.0,ns,4698 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,1680578.0,ns,5220 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,1998406.0,ns,5742 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,2180945.0,ns,6264 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,2407037.0,ns,6786 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,2610703.0,ns,7308 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,2712897.0,ns,7830 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,3088333.0,ns,8352 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,3254035.0,ns,8874 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,3439065.0,ns,9396 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,3425074.0,ns,9918 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,3629114.0,ns,10440 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,4040292.0,ns,10962 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,4238408.0,ns,11484 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,4367306.0,ns,12006 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,4776686.0,ns,12528 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,4872033.0,ns,13050 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,5035772.0,ns,13572 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,5091745.0,ns,14094 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,5506031.0,ns,14616 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,5292349.0,ns,15138 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,5677662.0,ns,15660 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6011521.0,ns,16182 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6291250.0,ns,16704 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6125294.0,ns,17226 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6616951.0,ns,17748 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6753566.0,ns,18270 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6605621.0,ns,18792 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,7270604.0,ns,19314 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6924559.0,ns,19836 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,7649610.0,ns,20358 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,8086807.0,ns,20880 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,7658072.0,ns,21402 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,8207636.0,ns,21924 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,8476085.0,ns,22446 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,8329556.0,ns,22968 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,8524186.0,ns,23490 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,8800164.0,ns,24012 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,9446339.0,ns,24534 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,9664063.0,ns,25056 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,9090171.0,ns,25578 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,9607632.0,ns,26100 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,10189394.0,ns,26622 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,10233799.0,ns,27144 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,10321065.0,ns,27666 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,10761213.0,ns,28188 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11055359.0,ns,28710 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11031573.0,ns,29232 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11271194.0,ns,29754 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11171179.0,ns,30276 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11421766.0,ns,30798 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11218154.0,ns,31320 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11745565.0,ns,31842 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,12174501.0,ns,32364 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,12786937.0,ns,32886 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,12711991.0,ns,33408 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,12943227.0,ns,33930 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,12676597.0,ns,34452 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,13550339.0,ns,34974 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,13474808.0,ns,35496 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,13204752.0,ns,36018 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,14318027.0,ns,36540 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,14378742.0,ns,37062 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,14120677.0,ns,37584 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,13640217.0,ns,38106 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,15021467.0,ns,38628 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,14773504.0,ns,39150 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,14473017.0,ns,39672 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,15331123.0,ns,40194 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,15514032.0,ns,40716 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,15842116.0,ns,41238 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,15125103.0,ns,41760 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,15873340.0,ns,42282 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,16114980.0,ns,42804 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,16521070.0,ns,43326 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,16320491.0,ns,43848 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,16928880.0,ns,44370 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,17492710.0,ns,44892 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,17406493.0,ns,45414 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,17526085.0,ns,45936 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,16863553.0,ns,46458 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,18190492.0,ns,46980 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,18222511.0,ns,47502 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,17318809.0,ns,48024 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,17927415.0,ns,48546 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,19130178.0,ns,49068 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,18893087.0,ns,49590 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,18068594.0,ns,50112 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,19796595.0,ns,50634 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,19433297.0,ns,51156 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,18656233.0,ns,51678 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,18931538.0,ns,52200 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/sample.json new file mode 100644 index 0000000000000..90e25417f658b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[522.0,1044.0,1566.0,2088.0,2610.0,3132.0,3654.0,4176.0,4698.0,5220.0,5742.0,6264.0,6786.0,7308.0,7830.0,8352.0,8874.0,9396.0,9918.0,10440.0,10962.0,11484.0,12006.0,12528.0,13050.0,13572.0,14094.0,14616.0,15138.0,15660.0,16182.0,16704.0,17226.0,17748.0,18270.0,18792.0,19314.0,19836.0,20358.0,20880.0,21402.0,21924.0,22446.0,22968.0,23490.0,24012.0,24534.0,25056.0,25578.0,26100.0,26622.0,27144.0,27666.0,28188.0,28710.0,29232.0,29754.0,30276.0,30798.0,31320.0,31842.0,32364.0,32886.0,33408.0,33930.0,34452.0,34974.0,35496.0,36018.0,36540.0,37062.0,37584.0,38106.0,38628.0,39150.0,39672.0,40194.0,40716.0,41238.0,41760.0,42282.0,42804.0,43326.0,43848.0,44370.0,44892.0,45414.0,45936.0,46458.0,46980.0,47502.0,48024.0,48546.0,49068.0,49590.0,50112.0,50634.0,51156.0,51678.0,52200.0],"times":[133887.0,302762.0,483677.0,625172.0,810208.0,1028368.0,1164043.0,1401113.0,1601761.0,1680578.0,1998406.0,2180945.0,2407037.0,2610703.0,2712897.0,3088333.0,3254035.0,3439065.0,3425074.0,3629114.0,4040292.0,4238408.0,4367306.0,4776686.0,4872033.0,5035772.0,5091745.0,5506031.0,5292349.0,5677662.0,6011521.0,6291250.0,6125294.0,6616951.0,6753566.0,6605621.0,7270604.0,6924559.0,7649610.0,8086807.0,7658072.0,8207636.0,8476085.0,8329556.0,8524186.0,8800164.0,9446339.0,9664063.0,9090171.0,9607632.0,10189394.0,10233799.0,10321065.0,10761213.0,11055359.0,11031573.0,11271194.0,11171179.0,11421766.0,11218154.0,11745565.0,12174501.0,12786937.0,12711991.0,12943227.0,12676597.0,13550339.0,13474808.0,13204752.0,14318027.0,14378742.0,14120677.0,13640217.0,15021467.0,14773504.0,14473017.0,15331123.0,15514032.0,15842116.0,15125103.0,15873340.0,16114980.0,16521070.0,16320491.0,16928880.0,17492710.0,17406493.0,17526085.0,16863553.0,18190492.0,18222511.0,17318809.0,17927415.0,19130178.0,18893087.0,18068594.0,19796595.0,19433297.0,18656233.0,18931538.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/tukey.json new file mode 100644 index 0000000000000..148ebe8010d26 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/base/tukey.json @@ -0,0 +1 @@ +[296.8803854749975,328.4240997857108,412.5406712809461,444.0843855916594] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/benchmark.json new file mode 100644 index 0000000000000..2b9cc77292d76 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:1)","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll","title":"forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/estimates.json new file mode 100644 index 0000000000000..aad3f01a97e75 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":360.91810293303774,"upper_bound":369.79589473803895},"point_estimate":365.559239207419,"standard_error":2.269924254864251},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":366.6931485237773,"upper_bound":375.70979672200934},"point_estimate":370.3161558786285,"standard_error":2.1191402508097434},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":11.435856818952168,"upper_bound":18.855104137488077},"point_estimate":15.85186152220244,"standard_error":1.971122246205825},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":372.54155246013744,"upper_bound":378.08360345897455},"point_estimate":375.35784582832963,"standard_error":1.4171613750550578},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":16.39128672086025,"upper_bound":28.682562025464325},"point_estimate":22.771818555360195,"standard_error":3.159584545848327}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/raw.csv new file mode 100644 index 0000000000000..43e4cb89d870c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,133887.0,ns,522 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,302762.0,ns,1044 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,483677.0,ns,1566 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,625172.0,ns,2088 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,810208.0,ns,2610 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,1028368.0,ns,3132 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,1164043.0,ns,3654 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,1401113.0,ns,4176 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,1601761.0,ns,4698 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,1680578.0,ns,5220 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,1998406.0,ns,5742 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,2180945.0,ns,6264 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,2407037.0,ns,6786 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,2610703.0,ns,7308 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,2712897.0,ns,7830 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,3088333.0,ns,8352 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,3254035.0,ns,8874 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,3439065.0,ns,9396 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,3425074.0,ns,9918 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,3629114.0,ns,10440 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,4040292.0,ns,10962 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,4238408.0,ns,11484 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,4367306.0,ns,12006 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,4776686.0,ns,12528 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,4872033.0,ns,13050 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,5035772.0,ns,13572 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,5091745.0,ns,14094 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,5506031.0,ns,14616 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,5292349.0,ns,15138 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,5677662.0,ns,15660 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6011521.0,ns,16182 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6291250.0,ns,16704 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6125294.0,ns,17226 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6616951.0,ns,17748 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6753566.0,ns,18270 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6605621.0,ns,18792 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,7270604.0,ns,19314 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,6924559.0,ns,19836 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,7649610.0,ns,20358 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,8086807.0,ns,20880 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,7658072.0,ns,21402 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,8207636.0,ns,21924 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,8476085.0,ns,22446 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,8329556.0,ns,22968 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,8524186.0,ns,23490 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,8800164.0,ns,24012 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,9446339.0,ns,24534 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,9664063.0,ns,25056 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,9090171.0,ns,25578 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,9607632.0,ns,26100 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,10189394.0,ns,26622 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,10233799.0,ns,27144 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,10321065.0,ns,27666 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,10761213.0,ns,28188 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11055359.0,ns,28710 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11031573.0,ns,29232 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11271194.0,ns,29754 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11171179.0,ns,30276 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11421766.0,ns,30798 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11218154.0,ns,31320 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,11745565.0,ns,31842 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,12174501.0,ns,32364 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,12786937.0,ns,32886 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,12711991.0,ns,33408 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,12943227.0,ns,33930 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,12676597.0,ns,34452 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,13550339.0,ns,34974 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,13474808.0,ns,35496 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,13204752.0,ns,36018 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,14318027.0,ns,36540 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,14378742.0,ns,37062 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,14120677.0,ns,37584 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,13640217.0,ns,38106 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,15021467.0,ns,38628 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,14773504.0,ns,39150 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,14473017.0,ns,39672 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,15331123.0,ns,40194 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,15514032.0,ns,40716 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,15842116.0,ns,41238 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,15125103.0,ns,41760 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,15873340.0,ns,42282 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,16114980.0,ns,42804 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,16521070.0,ns,43326 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,16320491.0,ns,43848 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,16928880.0,ns,44370 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,17492710.0,ns,44892 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,17406493.0,ns,45414 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,17526085.0,ns,45936 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,16863553.0,ns,46458 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,18190492.0,ns,46980 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,18222511.0,ns,47502 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,17318809.0,ns,48024 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,17927415.0,ns,48546 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,19130178.0,ns,49068 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,18893087.0,ns,49590 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,18068594.0,ns,50112 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,19796595.0,ns,50634 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,19433297.0,ns,51156 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,18656233.0,ns,51678 +forward msg from pull (nb_writter:5 nb_readder:1),linear object poll,,,,18931538.0,ns,52200 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/sample.json new file mode 100644 index 0000000000000..90e25417f658b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[522.0,1044.0,1566.0,2088.0,2610.0,3132.0,3654.0,4176.0,4698.0,5220.0,5742.0,6264.0,6786.0,7308.0,7830.0,8352.0,8874.0,9396.0,9918.0,10440.0,10962.0,11484.0,12006.0,12528.0,13050.0,13572.0,14094.0,14616.0,15138.0,15660.0,16182.0,16704.0,17226.0,17748.0,18270.0,18792.0,19314.0,19836.0,20358.0,20880.0,21402.0,21924.0,22446.0,22968.0,23490.0,24012.0,24534.0,25056.0,25578.0,26100.0,26622.0,27144.0,27666.0,28188.0,28710.0,29232.0,29754.0,30276.0,30798.0,31320.0,31842.0,32364.0,32886.0,33408.0,33930.0,34452.0,34974.0,35496.0,36018.0,36540.0,37062.0,37584.0,38106.0,38628.0,39150.0,39672.0,40194.0,40716.0,41238.0,41760.0,42282.0,42804.0,43326.0,43848.0,44370.0,44892.0,45414.0,45936.0,46458.0,46980.0,47502.0,48024.0,48546.0,49068.0,49590.0,50112.0,50634.0,51156.0,51678.0,52200.0],"times":[133887.0,302762.0,483677.0,625172.0,810208.0,1028368.0,1164043.0,1401113.0,1601761.0,1680578.0,1998406.0,2180945.0,2407037.0,2610703.0,2712897.0,3088333.0,3254035.0,3439065.0,3425074.0,3629114.0,4040292.0,4238408.0,4367306.0,4776686.0,4872033.0,5035772.0,5091745.0,5506031.0,5292349.0,5677662.0,6011521.0,6291250.0,6125294.0,6616951.0,6753566.0,6605621.0,7270604.0,6924559.0,7649610.0,8086807.0,7658072.0,8207636.0,8476085.0,8329556.0,8524186.0,8800164.0,9446339.0,9664063.0,9090171.0,9607632.0,10189394.0,10233799.0,10321065.0,10761213.0,11055359.0,11031573.0,11271194.0,11171179.0,11421766.0,11218154.0,11745565.0,12174501.0,12786937.0,12711991.0,12943227.0,12676597.0,13550339.0,13474808.0,13204752.0,14318027.0,14378742.0,14120677.0,13640217.0,15021467.0,14773504.0,14473017.0,15331123.0,15514032.0,15842116.0,15125103.0,15873340.0,16114980.0,16521070.0,16320491.0,16928880.0,17492710.0,17406493.0,17526085.0,16863553.0,18190492.0,18222511.0,17318809.0,17927415.0,19130178.0,18893087.0,18068594.0,19796595.0,19433297.0,18656233.0,18931538.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/tukey.json new file mode 100644 index 0000000000000..148ebe8010d26 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/new/tukey.json @@ -0,0 +1 @@ +[296.8803854749975,328.4240997857108,412.5406712809461,444.0843855916594] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/MAD.svg new file mode 100644 index 0000000000000..b0a71847713ce --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 14 + + + + + 15 + + + + + 16 + + + + + 17 + + + + + 18 + + + + + 19 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/SD.svg new file mode 100644 index 0000000000000..ae5fec9d24144 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/SD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + 22 + + + + + 24 + + + + + 26 + + + + + 28 + + + + + 30 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/index.html new file mode 100644 index 0000000000000..63e6a6f2bed19 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope372.54 ns375.36 ns378.08 ns
0.88005640.88697910.8804911
Mean360.92 ns365.56 ns369.80 ns
Std. Dev.16.391 ns22.772 ns28.683 ns
Median366.69 ns370.32 ns375.71 ns
MAD11.436 ns15.852 ns18.855 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/mean.svg new file mode 100644 index 0000000000000..0f1384d6ddfa9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/mean.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 0.16 + + + + + 0.18 + + + + + 360 + + + + + 362 + + + + + 364 + + + + + 366 + + + + + 368 + + + + + 370 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/median.svg new file mode 100644 index 0000000000000..699b333b52767 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/median.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 366 + + + + + 368 + + + + + 370 + + + + + 372 + + + + + 374 + + + + + 376 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/pdf.svg new file mode 100644 index 0000000000000..7e14744b45080 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/pdf.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 240 + + + + + 260 + + + + + 280 + + + + + 300 + + + + + 320 + + + + + 340 + + + + + 360 + + + + + 380 + + + + + 400 + + + + + 420 + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..69a9a62b55265 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/pdf_small.svg @@ -0,0 +1,224 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 240 + + + + + 260 + + + + + 280 + + + + + 300 + + + + + 320 + + + + + 340 + + + + + 360 + + + + + 380 + + + + + 400 + + + + + 420 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/regression.svg new file mode 100644 index 0000000000000..838098feb1b32 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/regression.svg @@ -0,0 +1,447 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/regression_small.svg new file mode 100644 index 0000000000000..916f2f99a52a9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/regression_small.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/slope.svg new file mode 100644 index 0000000000000..e56b498f564f8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 372 + + + + + 373 + + + + + 374 + + + + + 375 + + + + + 376 + + + + + 377 + + + + + 378 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/typical.svg new file mode 100644 index 0000000000000..49bb20790c761 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/linear object poll/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 372 + + + + + 373 + + + + + 374 + + + + + 375 + + + + + 376 + + + + + 377 + + + + + 378 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/benchmark.json new file mode 100644 index 0000000000000..0dc8fcaa83d7e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:1)","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll","title":"forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/estimates.json new file mode 100644 index 0000000000000..aa221ca47d0f3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":779.1810582236056,"upper_bound":1044.6112660526055},"point_estimate":909.8776368654571,"standard_error":67.94060620681032},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":402.76346153846157,"upper_bound":692.7835748792271},"point_estimate":449.7049426450742,"standard_error":86.56043014882643},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":107.22913543959055,"upper_bound":544.3007443369662},"point_estimate":197.2167337116019,"standard_error":124.0233535551729},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1219.9882169131083,"upper_bound":1550.7214657596794},"point_estimate":1401.187976996207,"standard_error":84.23376867507271},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":617.1983319190679,"upper_bound":734.0121382822817},"point_estimate":686.1826160581287,"standard_error":29.83935190210843}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/raw.csv new file mode 100644 index 0000000000000..b488f0093417a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,94627.0,ns,60 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,204446.0,ns,120 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,148634.0,ns,180 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,312704.0,ns,240 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,200363.0,ns,300 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,258254.0,ns,360 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,268995.0,ns,420 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,412124.0,ns,480 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,348840.0,ns,540 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,237917.0,ns,600 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,405256.0,ns,660 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,309642.0,ns,720 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,320448.0,ns,780 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,359147.0,ns,840 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,378614.0,ns,900 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,354533.0,ns,960 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,422261.0,ns,1020 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,375070.0,ns,1080 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,510257.0,ns,1140 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,414266.0,ns,1200 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,396112.0,ns,1260 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,728593.0,ns,1320 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,628413.0,ns,1380 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,704960.0,ns,1440 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,572984.0,ns,1500 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,704833.0,ns,1560 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,548408.0,ns,1620 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,780740.0,ns,1680 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,669843.0,ns,1740 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,528837.0,ns,1800 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,687670.0,ns,1860 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,674015.0,ns,1920 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,702972.0,ns,1980 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,833955.0,ns,2040 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,745274.0,ns,2100 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,832103.0,ns,2160 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,974020.0,ns,2220 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,821593.0,ns,2280 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,923589.0,ns,2340 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,907176.0,ns,2400 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,846301.0,ns,2460 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1020210.0,ns,2520 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,936695.0,ns,2580 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,884387.0,ns,2640 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,905682.0,ns,2700 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1216205.0,ns,2760 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,935955.0,ns,2820 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1100676.0,ns,2880 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1025621.0,ns,2940 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1060396.0,ns,3000 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1137514.0,ns,3060 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1094603.0,ns,3120 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1140896.0,ns,3180 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1057794.0,ns,3240 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1069457.0,ns,3300 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1092469.0,ns,3360 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1067457.0,ns,3420 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1127181.0,ns,3480 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1252909.0,ns,3540 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1366455.0,ns,3600 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1236922.0,ns,3660 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1186656.0,ns,3720 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1141191.0,ns,3780 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1147601.0,ns,3840 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1524539.0,ns,3900 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,4193215.0,ns,3960 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,3991092.0,ns,4020 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,3128345.0,ns,4080 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,2868124.0,ns,4140 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,7036260.0,ns,4200 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,5587982.0,ns,4260 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,4602540.0,ns,4320 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,9056010.0,ns,4380 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,9021311.0,ns,4440 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,8022681.0,ns,4500 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,7671875.0,ns,4560 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,8518087.0,ns,4620 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,7410584.0,ns,4680 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,7304949.0,ns,4740 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,9417825.0,ns,4800 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,8899377.0,ns,4860 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,8610543.0,ns,4920 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,8544565.0,ns,4980 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10288096.0,ns,5040 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,9507090.0,ns,5100 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10880398.0,ns,5160 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10469021.0,ns,5220 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10302635.0,ns,5280 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,9366709.0,ns,5340 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,9766631.0,ns,5400 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,11779543.0,ns,5460 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10361568.0,ns,5520 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10606251.0,ns,5580 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10863840.0,ns,5640 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,11192839.0,ns,5700 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,11819742.0,ns,5760 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10512662.0,ns,5820 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10484745.0,ns,5880 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,13239906.0,ns,5940 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,13211159.0,ns,6000 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/sample.json new file mode 100644 index 0000000000000..47062cfa0a2c8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[60.0,120.0,180.0,240.0,300.0,360.0,420.0,480.0,540.0,600.0,660.0,720.0,780.0,840.0,900.0,960.0,1020.0,1080.0,1140.0,1200.0,1260.0,1320.0,1380.0,1440.0,1500.0,1560.0,1620.0,1680.0,1740.0,1800.0,1860.0,1920.0,1980.0,2040.0,2100.0,2160.0,2220.0,2280.0,2340.0,2400.0,2460.0,2520.0,2580.0,2640.0,2700.0,2760.0,2820.0,2880.0,2940.0,3000.0,3060.0,3120.0,3180.0,3240.0,3300.0,3360.0,3420.0,3480.0,3540.0,3600.0,3660.0,3720.0,3780.0,3840.0,3900.0,3960.0,4020.0,4080.0,4140.0,4200.0,4260.0,4320.0,4380.0,4440.0,4500.0,4560.0,4620.0,4680.0,4740.0,4800.0,4860.0,4920.0,4980.0,5040.0,5100.0,5160.0,5220.0,5280.0,5340.0,5400.0,5460.0,5520.0,5580.0,5640.0,5700.0,5760.0,5820.0,5880.0,5940.0,6000.0],"times":[94627.0,204446.0,148634.0,312704.0,200363.0,258254.0,268995.0,412124.0,348840.0,237917.0,405256.0,309642.0,320448.0,359147.0,378614.0,354533.0,422261.0,375070.0,510257.0,414266.0,396112.0,728593.0,628413.0,704960.0,572984.0,704833.0,548408.0,780740.0,669843.0,528837.0,687670.0,674015.0,702972.0,833955.0,745274.0,832103.0,974020.0,821593.0,923589.0,907176.0,846301.0,1020210.0,936695.0,884387.0,905682.0,1216205.0,935955.0,1100676.0,1025621.0,1060396.0,1137514.0,1094603.0,1140896.0,1057794.0,1069457.0,1092469.0,1067457.0,1127181.0,1252909.0,1366455.0,1236922.0,1186656.0,1141191.0,1147601.0,1524539.0,4193215.0,3991092.0,3128345.0,2868124.0,7036260.0,5587982.0,4602540.0,9056010.0,9021311.0,8022681.0,7671875.0,8518087.0,7410584.0,7304949.0,9417825.0,8899377.0,8610543.0,8544565.0,10288096.0,9507090.0,10880398.0,10469021.0,10302635.0,9366709.0,9766631.0,11779543.0,10361568.0,10606251.0,10863840.0,11192839.0,11819742.0,10512662.0,10484745.0,13239906.0,13211159.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/tukey.json new file mode 100644 index 0000000000000..49cbd633c7109 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/base/tukey.json @@ -0,0 +1 @@ +[-3688.8412335448147,-1665.5014486763525,3730.07131097288,5753.411095841342] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/benchmark.json new file mode 100644 index 0000000000000..0dc8fcaa83d7e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:1)","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll","title":"forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/estimates.json new file mode 100644 index 0000000000000..aa221ca47d0f3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":779.1810582236056,"upper_bound":1044.6112660526055},"point_estimate":909.8776368654571,"standard_error":67.94060620681032},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":402.76346153846157,"upper_bound":692.7835748792271},"point_estimate":449.7049426450742,"standard_error":86.56043014882643},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":107.22913543959055,"upper_bound":544.3007443369662},"point_estimate":197.2167337116019,"standard_error":124.0233535551729},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1219.9882169131083,"upper_bound":1550.7214657596794},"point_estimate":1401.187976996207,"standard_error":84.23376867507271},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":617.1983319190679,"upper_bound":734.0121382822817},"point_estimate":686.1826160581287,"standard_error":29.83935190210843}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/raw.csv new file mode 100644 index 0000000000000..b488f0093417a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,94627.0,ns,60 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,204446.0,ns,120 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,148634.0,ns,180 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,312704.0,ns,240 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,200363.0,ns,300 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,258254.0,ns,360 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,268995.0,ns,420 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,412124.0,ns,480 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,348840.0,ns,540 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,237917.0,ns,600 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,405256.0,ns,660 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,309642.0,ns,720 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,320448.0,ns,780 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,359147.0,ns,840 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,378614.0,ns,900 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,354533.0,ns,960 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,422261.0,ns,1020 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,375070.0,ns,1080 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,510257.0,ns,1140 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,414266.0,ns,1200 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,396112.0,ns,1260 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,728593.0,ns,1320 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,628413.0,ns,1380 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,704960.0,ns,1440 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,572984.0,ns,1500 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,704833.0,ns,1560 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,548408.0,ns,1620 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,780740.0,ns,1680 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,669843.0,ns,1740 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,528837.0,ns,1800 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,687670.0,ns,1860 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,674015.0,ns,1920 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,702972.0,ns,1980 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,833955.0,ns,2040 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,745274.0,ns,2100 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,832103.0,ns,2160 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,974020.0,ns,2220 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,821593.0,ns,2280 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,923589.0,ns,2340 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,907176.0,ns,2400 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,846301.0,ns,2460 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1020210.0,ns,2520 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,936695.0,ns,2580 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,884387.0,ns,2640 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,905682.0,ns,2700 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1216205.0,ns,2760 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,935955.0,ns,2820 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1100676.0,ns,2880 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1025621.0,ns,2940 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1060396.0,ns,3000 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1137514.0,ns,3060 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1094603.0,ns,3120 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1140896.0,ns,3180 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1057794.0,ns,3240 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1069457.0,ns,3300 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1092469.0,ns,3360 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1067457.0,ns,3420 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1127181.0,ns,3480 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1252909.0,ns,3540 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1366455.0,ns,3600 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1236922.0,ns,3660 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1186656.0,ns,3720 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1141191.0,ns,3780 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1147601.0,ns,3840 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,1524539.0,ns,3900 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,4193215.0,ns,3960 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,3991092.0,ns,4020 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,3128345.0,ns,4080 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,2868124.0,ns,4140 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,7036260.0,ns,4200 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,5587982.0,ns,4260 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,4602540.0,ns,4320 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,9056010.0,ns,4380 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,9021311.0,ns,4440 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,8022681.0,ns,4500 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,7671875.0,ns,4560 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,8518087.0,ns,4620 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,7410584.0,ns,4680 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,7304949.0,ns,4740 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,9417825.0,ns,4800 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,8899377.0,ns,4860 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,8610543.0,ns,4920 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,8544565.0,ns,4980 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10288096.0,ns,5040 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,9507090.0,ns,5100 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10880398.0,ns,5160 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10469021.0,ns,5220 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10302635.0,ns,5280 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,9366709.0,ns,5340 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,9766631.0,ns,5400 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,11779543.0,ns,5460 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10361568.0,ns,5520 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10606251.0,ns,5580 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10863840.0,ns,5640 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,11192839.0,ns,5700 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,11819742.0,ns,5760 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10512662.0,ns,5820 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,10484745.0,ns,5880 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,13239906.0,ns,5940 +forward msg from pull (nb_writter:5 nb_readder:1),mutex object poll,,,,13211159.0,ns,6000 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/sample.json new file mode 100644 index 0000000000000..47062cfa0a2c8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[60.0,120.0,180.0,240.0,300.0,360.0,420.0,480.0,540.0,600.0,660.0,720.0,780.0,840.0,900.0,960.0,1020.0,1080.0,1140.0,1200.0,1260.0,1320.0,1380.0,1440.0,1500.0,1560.0,1620.0,1680.0,1740.0,1800.0,1860.0,1920.0,1980.0,2040.0,2100.0,2160.0,2220.0,2280.0,2340.0,2400.0,2460.0,2520.0,2580.0,2640.0,2700.0,2760.0,2820.0,2880.0,2940.0,3000.0,3060.0,3120.0,3180.0,3240.0,3300.0,3360.0,3420.0,3480.0,3540.0,3600.0,3660.0,3720.0,3780.0,3840.0,3900.0,3960.0,4020.0,4080.0,4140.0,4200.0,4260.0,4320.0,4380.0,4440.0,4500.0,4560.0,4620.0,4680.0,4740.0,4800.0,4860.0,4920.0,4980.0,5040.0,5100.0,5160.0,5220.0,5280.0,5340.0,5400.0,5460.0,5520.0,5580.0,5640.0,5700.0,5760.0,5820.0,5880.0,5940.0,6000.0],"times":[94627.0,204446.0,148634.0,312704.0,200363.0,258254.0,268995.0,412124.0,348840.0,237917.0,405256.0,309642.0,320448.0,359147.0,378614.0,354533.0,422261.0,375070.0,510257.0,414266.0,396112.0,728593.0,628413.0,704960.0,572984.0,704833.0,548408.0,780740.0,669843.0,528837.0,687670.0,674015.0,702972.0,833955.0,745274.0,832103.0,974020.0,821593.0,923589.0,907176.0,846301.0,1020210.0,936695.0,884387.0,905682.0,1216205.0,935955.0,1100676.0,1025621.0,1060396.0,1137514.0,1094603.0,1140896.0,1057794.0,1069457.0,1092469.0,1067457.0,1127181.0,1252909.0,1366455.0,1236922.0,1186656.0,1141191.0,1147601.0,1524539.0,4193215.0,3991092.0,3128345.0,2868124.0,7036260.0,5587982.0,4602540.0,9056010.0,9021311.0,8022681.0,7671875.0,8518087.0,7410584.0,7304949.0,9417825.0,8899377.0,8610543.0,8544565.0,10288096.0,9507090.0,10880398.0,10469021.0,10302635.0,9366709.0,9766631.0,11779543.0,10361568.0,10606251.0,10863840.0,11192839.0,11819742.0,10512662.0,10484745.0,13239906.0,13211159.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/tukey.json new file mode 100644 index 0000000000000..49cbd633c7109 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/new/tukey.json @@ -0,0 +1 @@ +[-3688.8412335448147,-1665.5014486763525,3730.07131097288,5753.411095841342] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/MAD.svg new file mode 100644 index 0000000000000..1a15840a49690 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/MAD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 100 + + + + + 200 + + + + + 300 + + + + + 400 + + + + + 500 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/SD.svg new file mode 100644 index 0000000000000..4462f35107a90 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 620 + + + + + 640 + + + + + 660 + + + + + 680 + + + + + 700 + + + + + 720 + + + + + 740 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/index.html new file mode 100644 index 0000000000000..4eb2c03e69e75 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope1.2200 us1.4012 us1.5507 us
0.12452720.13157410.1266916
Mean779.18 ns909.88 ns1.0446 us
Std. Dev.617.20 ns686.18 ns734.01 ns
Median402.76 ns449.70 ns692.78 ns
MAD107.23 ns197.22 ns544.30 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/mean.svg new file mode 100644 index 0000000000000..6d9b0d91329ee --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 0.75 + + + + + 0.8 + + + + + 0.85 + + + + + 0.9 + + + + + 0.95 + + + + + 1 + + + + + 1.05 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/median.svg new file mode 100644 index 0000000000000..30a22eef5e053 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/median.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 400 + + + + + 450 + + + + + 500 + + + + + 550 + + + + + 600 + + + + + 650 + + + + + 700 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/pdf.svg new file mode 100644 index 0000000000000..ed95eb014e10f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/pdf.svg @@ -0,0 +1,420 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + -0.5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 0.9 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..543ccbf1a8f6e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/pdf_small.svg @@ -0,0 +1,234 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 0.9 + + + + + -0.5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/regression.svg new file mode 100644 index 0000000000000..c889bc684c578 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/regression.svg @@ -0,0 +1,408 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/regression_small.svg new file mode 100644 index 0000000000000..694e371a7af6c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/regression_small.svg @@ -0,0 +1,386 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/slope.svg new file mode 100644 index 0000000000000..89cf7cb89249e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/slope.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 4 + + + + + 4.5 + + + + + 5 + + + + + 1.2 + + + + + 1.25 + + + + + 1.3 + + + + + 1.35 + + + + + 1.4 + + + + + 1.45 + + + + + 1.5 + + + + + 1.55 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/typical.svg new file mode 100644 index 0000000000000..1079daf153ccd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/mutex object poll/report/typical.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 4 + + + + + 4.5 + + + + + 5 + + + + + 1.2 + + + + + 1.25 + + + + + 1.3 + + + + + 1.35 + + + + + 1.4 + + + + + 1.45 + + + + + 1.5 + + + + + 1.55 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/benchmark.json new file mode 100644 index 0000000000000..7b97c1a280454 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:1)","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:1)/none object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_1)/none object poll","title":"forward msg from pull (nb_writter:5 nb_readder:1)/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/estimates.json new file mode 100644 index 0000000000000..f350fb61a23da --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":862.7548480193778,"upper_bound":984.7740406371402},"point_estimate":926.0524289536957,"standard_error":31.15920377372979},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1006.0749634002927,"upper_bound":1107.610349760059},"point_estimate":1063.8807353015202,"standard_error":29.25800454772408},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":104.09774185966222,"upper_bound":227.40463012837048},"point_estimate":164.57523168708508,"standard_error":33.17395433947288},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1108.6298631319796,"upper_bound":1142.0727444371573},"point_estimate":1126.5435284090713,"standard_error":8.48863515407688},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":264.1681552313307,"upper_bound":352.2256418464361},"point_estimate":314.25220008505846,"standard_error":22.497446754807076}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/raw.csv new file mode 100644 index 0000000000000..47375e8e2cc44 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,128580.0,ns,172 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,151631.0,ns,344 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,221706.0,ns,516 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,443625.0,ns,688 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,283998.0,ns,860 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,372250.0,ns,1032 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,367481.0,ns,1204 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,430229.0,ns,1376 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,425993.0,ns,1548 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,519834.0,ns,1720 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,487615.0,ns,1892 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,643781.0,ns,2064 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,567368.0,ns,2236 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,758597.0,ns,2408 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,714623.0,ns,2580 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,764838.0,ns,2752 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,778934.0,ns,2924 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,839939.0,ns,3096 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,784912.0,ns,3268 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,1235584.0,ns,3440 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,2962666.0,ns,3612 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,2981365.0,ns,3784 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,3033763.0,ns,3956 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,3432981.0,ns,4128 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,3582436.0,ns,4300 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,3797589.0,ns,4472 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,3993494.0,ns,4644 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,4279673.0,ns,4816 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,4427571.0,ns,4988 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,4681234.0,ns,5160 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,4822276.0,ns,5332 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,5138774.0,ns,5504 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,5402432.0,ns,5676 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,5333934.0,ns,5848 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,5566212.0,ns,6020 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,5756355.0,ns,6192 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,5962075.0,ns,6364 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,6509342.0,ns,6536 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,6444961.0,ns,6708 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,6799643.0,ns,6880 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,7220628.0,ns,7052 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,7703111.0,ns,7224 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,7838173.0,ns,7396 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8032973.0,ns,7568 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8085205.0,ns,7740 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8318148.0,ns,7912 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8256716.0,ns,8084 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8514384.0,ns,8256 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,9516875.0,ns,8428 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8694668.0,ns,8600 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8914357.0,ns,8772 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,10267603.0,ns,8944 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,9420344.0,ns,9116 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,10270694.0,ns,9288 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,10330658.0,ns,9460 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,10700254.0,ns,9632 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,10881300.0,ns,9804 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,11327752.0,ns,9976 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,11018057.0,ns,10148 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12454929.0,ns,10320 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12678910.0,ns,10492 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12894315.0,ns,10664 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12056976.0,ns,10836 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,13087174.0,ns,11008 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12080770.0,ns,11180 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12338095.0,ns,11352 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,13604968.0,ns,11524 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12881655.0,ns,11696 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,13665132.0,ns,11868 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,13311800.0,ns,12040 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,13466394.0,ns,12212 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,13741156.0,ns,12384 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,14256651.0,ns,12556 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,15084314.0,ns,12728 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,14257479.0,ns,12900 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,14556777.0,ns,13072 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,15101666.0,ns,13244 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,15936948.0,ns,13416 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,15321486.0,ns,13588 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,15467754.0,ns,13760 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,16196522.0,ns,13932 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,16544600.0,ns,14104 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,16218452.0,ns,14276 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,17331876.0,ns,14448 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,17161126.0,ns,14620 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,16837419.0,ns,14792 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,16884193.0,ns,14964 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,17091137.0,ns,15136 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,17636861.0,ns,15308 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,20019016.0,ns,15480 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,18604169.0,ns,15652 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,18399995.0,ns,15824 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,20294952.0,ns,15996 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,18969282.0,ns,16168 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,19583536.0,ns,16340 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,18741369.0,ns,16512 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,19171985.0,ns,16684 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,19937017.0,ns,16856 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,19410035.0,ns,17028 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,20102105.0,ns,17200 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/sample.json new file mode 100644 index 0000000000000..1caebabe6f5a5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[172.0,344.0,516.0,688.0,860.0,1032.0,1204.0,1376.0,1548.0,1720.0,1892.0,2064.0,2236.0,2408.0,2580.0,2752.0,2924.0,3096.0,3268.0,3440.0,3612.0,3784.0,3956.0,4128.0,4300.0,4472.0,4644.0,4816.0,4988.0,5160.0,5332.0,5504.0,5676.0,5848.0,6020.0,6192.0,6364.0,6536.0,6708.0,6880.0,7052.0,7224.0,7396.0,7568.0,7740.0,7912.0,8084.0,8256.0,8428.0,8600.0,8772.0,8944.0,9116.0,9288.0,9460.0,9632.0,9804.0,9976.0,10148.0,10320.0,10492.0,10664.0,10836.0,11008.0,11180.0,11352.0,11524.0,11696.0,11868.0,12040.0,12212.0,12384.0,12556.0,12728.0,12900.0,13072.0,13244.0,13416.0,13588.0,13760.0,13932.0,14104.0,14276.0,14448.0,14620.0,14792.0,14964.0,15136.0,15308.0,15480.0,15652.0,15824.0,15996.0,16168.0,16340.0,16512.0,16684.0,16856.0,17028.0,17200.0],"times":[128580.0,151631.0,221706.0,443625.0,283998.0,372250.0,367481.0,430229.0,425993.0,519834.0,487615.0,643781.0,567368.0,758597.0,714623.0,764838.0,778934.0,839939.0,784912.0,1235584.0,2962666.0,2981365.0,3033763.0,3432981.0,3582436.0,3797589.0,3993494.0,4279673.0,4427571.0,4681234.0,4822276.0,5138774.0,5402432.0,5333934.0,5566212.0,5756355.0,5962075.0,6509342.0,6444961.0,6799643.0,7220628.0,7703111.0,7838173.0,8032973.0,8085205.0,8318148.0,8256716.0,8514384.0,9516875.0,8694668.0,8914357.0,10267603.0,9420344.0,10270694.0,10330658.0,10700254.0,10881300.0,11327752.0,11018057.0,12454929.0,12678910.0,12894315.0,12056976.0,13087174.0,12080770.0,12338095.0,13604968.0,12881655.0,13665132.0,13311800.0,13466394.0,13741156.0,14256651.0,15084314.0,14257479.0,14556777.0,15101666.0,15936948.0,15321486.0,15467754.0,16196522.0,16544600.0,16218452.0,17331876.0,17161126.0,16837419.0,16884193.0,17091137.0,17636861.0,20019016.0,18604169.0,18399995.0,20294952.0,18969282.0,19583536.0,18741369.0,19171985.0,19937017.0,19410035.0,20102105.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/tukey.json new file mode 100644 index 0000000000000..c4d6b32795009 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/base/tukey.json @@ -0,0 +1 @@ +[-35.34187633238412,404.9168424688705,1578.9400926055496,2019.1988114068042] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/benchmark.json new file mode 100644 index 0000000000000..7b97c1a280454 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:1)","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:1)/none object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_1)/none object poll","title":"forward msg from pull (nb_writter:5 nb_readder:1)/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/estimates.json new file mode 100644 index 0000000000000..f350fb61a23da --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":862.7548480193778,"upper_bound":984.7740406371402},"point_estimate":926.0524289536957,"standard_error":31.15920377372979},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1006.0749634002927,"upper_bound":1107.610349760059},"point_estimate":1063.8807353015202,"standard_error":29.25800454772408},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":104.09774185966222,"upper_bound":227.40463012837048},"point_estimate":164.57523168708508,"standard_error":33.17395433947288},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1108.6298631319796,"upper_bound":1142.0727444371573},"point_estimate":1126.5435284090713,"standard_error":8.48863515407688},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":264.1681552313307,"upper_bound":352.2256418464361},"point_estimate":314.25220008505846,"standard_error":22.497446754807076}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/raw.csv new file mode 100644 index 0000000000000..47375e8e2cc44 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,128580.0,ns,172 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,151631.0,ns,344 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,221706.0,ns,516 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,443625.0,ns,688 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,283998.0,ns,860 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,372250.0,ns,1032 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,367481.0,ns,1204 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,430229.0,ns,1376 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,425993.0,ns,1548 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,519834.0,ns,1720 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,487615.0,ns,1892 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,643781.0,ns,2064 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,567368.0,ns,2236 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,758597.0,ns,2408 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,714623.0,ns,2580 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,764838.0,ns,2752 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,778934.0,ns,2924 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,839939.0,ns,3096 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,784912.0,ns,3268 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,1235584.0,ns,3440 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,2962666.0,ns,3612 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,2981365.0,ns,3784 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,3033763.0,ns,3956 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,3432981.0,ns,4128 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,3582436.0,ns,4300 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,3797589.0,ns,4472 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,3993494.0,ns,4644 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,4279673.0,ns,4816 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,4427571.0,ns,4988 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,4681234.0,ns,5160 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,4822276.0,ns,5332 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,5138774.0,ns,5504 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,5402432.0,ns,5676 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,5333934.0,ns,5848 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,5566212.0,ns,6020 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,5756355.0,ns,6192 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,5962075.0,ns,6364 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,6509342.0,ns,6536 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,6444961.0,ns,6708 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,6799643.0,ns,6880 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,7220628.0,ns,7052 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,7703111.0,ns,7224 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,7838173.0,ns,7396 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8032973.0,ns,7568 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8085205.0,ns,7740 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8318148.0,ns,7912 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8256716.0,ns,8084 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8514384.0,ns,8256 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,9516875.0,ns,8428 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8694668.0,ns,8600 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,8914357.0,ns,8772 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,10267603.0,ns,8944 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,9420344.0,ns,9116 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,10270694.0,ns,9288 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,10330658.0,ns,9460 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,10700254.0,ns,9632 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,10881300.0,ns,9804 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,11327752.0,ns,9976 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,11018057.0,ns,10148 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12454929.0,ns,10320 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12678910.0,ns,10492 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12894315.0,ns,10664 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12056976.0,ns,10836 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,13087174.0,ns,11008 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12080770.0,ns,11180 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12338095.0,ns,11352 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,13604968.0,ns,11524 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,12881655.0,ns,11696 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,13665132.0,ns,11868 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,13311800.0,ns,12040 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,13466394.0,ns,12212 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,13741156.0,ns,12384 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,14256651.0,ns,12556 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,15084314.0,ns,12728 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,14257479.0,ns,12900 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,14556777.0,ns,13072 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,15101666.0,ns,13244 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,15936948.0,ns,13416 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,15321486.0,ns,13588 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,15467754.0,ns,13760 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,16196522.0,ns,13932 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,16544600.0,ns,14104 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,16218452.0,ns,14276 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,17331876.0,ns,14448 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,17161126.0,ns,14620 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,16837419.0,ns,14792 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,16884193.0,ns,14964 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,17091137.0,ns,15136 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,17636861.0,ns,15308 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,20019016.0,ns,15480 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,18604169.0,ns,15652 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,18399995.0,ns,15824 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,20294952.0,ns,15996 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,18969282.0,ns,16168 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,19583536.0,ns,16340 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,18741369.0,ns,16512 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,19171985.0,ns,16684 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,19937017.0,ns,16856 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,19410035.0,ns,17028 +forward msg from pull (nb_writter:5 nb_readder:1),none object poll,,,,20102105.0,ns,17200 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/sample.json new file mode 100644 index 0000000000000..1caebabe6f5a5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[172.0,344.0,516.0,688.0,860.0,1032.0,1204.0,1376.0,1548.0,1720.0,1892.0,2064.0,2236.0,2408.0,2580.0,2752.0,2924.0,3096.0,3268.0,3440.0,3612.0,3784.0,3956.0,4128.0,4300.0,4472.0,4644.0,4816.0,4988.0,5160.0,5332.0,5504.0,5676.0,5848.0,6020.0,6192.0,6364.0,6536.0,6708.0,6880.0,7052.0,7224.0,7396.0,7568.0,7740.0,7912.0,8084.0,8256.0,8428.0,8600.0,8772.0,8944.0,9116.0,9288.0,9460.0,9632.0,9804.0,9976.0,10148.0,10320.0,10492.0,10664.0,10836.0,11008.0,11180.0,11352.0,11524.0,11696.0,11868.0,12040.0,12212.0,12384.0,12556.0,12728.0,12900.0,13072.0,13244.0,13416.0,13588.0,13760.0,13932.0,14104.0,14276.0,14448.0,14620.0,14792.0,14964.0,15136.0,15308.0,15480.0,15652.0,15824.0,15996.0,16168.0,16340.0,16512.0,16684.0,16856.0,17028.0,17200.0],"times":[128580.0,151631.0,221706.0,443625.0,283998.0,372250.0,367481.0,430229.0,425993.0,519834.0,487615.0,643781.0,567368.0,758597.0,714623.0,764838.0,778934.0,839939.0,784912.0,1235584.0,2962666.0,2981365.0,3033763.0,3432981.0,3582436.0,3797589.0,3993494.0,4279673.0,4427571.0,4681234.0,4822276.0,5138774.0,5402432.0,5333934.0,5566212.0,5756355.0,5962075.0,6509342.0,6444961.0,6799643.0,7220628.0,7703111.0,7838173.0,8032973.0,8085205.0,8318148.0,8256716.0,8514384.0,9516875.0,8694668.0,8914357.0,10267603.0,9420344.0,10270694.0,10330658.0,10700254.0,10881300.0,11327752.0,11018057.0,12454929.0,12678910.0,12894315.0,12056976.0,13087174.0,12080770.0,12338095.0,13604968.0,12881655.0,13665132.0,13311800.0,13466394.0,13741156.0,14256651.0,15084314.0,14257479.0,14556777.0,15101666.0,15936948.0,15321486.0,15467754.0,16196522.0,16544600.0,16218452.0,17331876.0,17161126.0,16837419.0,16884193.0,17091137.0,17636861.0,20019016.0,18604169.0,18399995.0,20294952.0,18969282.0,19583536.0,18741369.0,19171985.0,19937017.0,19410035.0,20102105.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/tukey.json new file mode 100644 index 0000000000000..c4d6b32795009 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/new/tukey.json @@ -0,0 +1 @@ +[-35.34187633238412,404.9168424688705,1578.9400926055496,2019.1988114068042] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/MAD.svg new file mode 100644 index 0000000000000..e8675dcced35c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/MAD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 100 + + + + + 120 + + + + + 140 + + + + + 160 + + + + + 180 + + + + + 200 + + + + + 220 + + + + + 240 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/none object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/SD.svg new file mode 100644 index 0000000000000..e476754ac14ee --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/SD.svg @@ -0,0 +1,308 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 0.018 + + + + + 0.02 + + + + + 260 + + + + + 280 + + + + + 300 + + + + + 320 + + + + + 340 + + + + + 360 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/none object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/index.html new file mode 100644 index 0000000000000..5b06ad8c09587 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/none object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:5 nb_readder:1)/none object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope1.1086 us1.1265 us1.1421 us
0.48893510.49566260.4905898
Mean862.75 ns926.05 ns984.77 ns
Std. Dev.264.17 ns314.25 ns352.23 ns
Median1.0061 us1.0639 us1.1076 us
MAD104.10 ns164.58 ns227.40 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/mean.svg new file mode 100644 index 0000000000000..e0400954fbeaa --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/mean.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 860 + + + + + 880 + + + + + 900 + + + + + 920 + + + + + 940 + + + + + 960 + + + + + 980 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/none object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/median.svg new file mode 100644 index 0000000000000..27331709e8d08 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/median.svg @@ -0,0 +1,308 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + 1 + + + + + 1.02 + + + + + 1.04 + + + + + 1.06 + + + + + 1.08 + + + + + 1.1 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/none object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/pdf.svg new file mode 100644 index 0000000000000..e32c379458d91 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/pdf.svg @@ -0,0 +1,450 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + 1.8 + + + + + 2 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/none object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_5 + + + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..a5464bd7ec731 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/pdf_small.svg @@ -0,0 +1,214 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/regression.svg new file mode 100644 index 0000000000000..81b1b6b99d8ea --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/regression.svg @@ -0,0 +1,421 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/none object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/regression_small.svg new file mode 100644 index 0000000000000..a5a3ab5ff6369 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/regression_small.svg @@ -0,0 +1,399 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/slope.svg new file mode 100644 index 0000000000000..612a01d26f2e0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/slope.svg @@ -0,0 +1,323 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 30 + + + + + 35 + + + + + 40 + + + + + 45 + + + + + 50 + + + + + 1.105 + + + + + 1.11 + + + + + 1.115 + + + + + 1.12 + + + + + 1.125 + + + + + 1.13 + + + + + 1.135 + + + + + 1.14 + + + + + 1.145 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/none object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/typical.svg new file mode 100644 index 0000000000000..38adf9e17aa15 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/none object poll/report/typical.svg @@ -0,0 +1,323 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 30 + + + + + 35 + + + + + 40 + + + + + 45 + + + + + 50 + + + + + 1.105 + + + + + 1.11 + + + + + 1.115 + + + + + 1.12 + + + + + 1.125 + + + + + 1.13 + + + + + 1.135 + + + + + 1.14 + + + + + 1.145 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/none object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/report/index.html new file mode 100644 index 0000000000000..dce4c4c23a986 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/report/index.html @@ -0,0 +1,185 @@ + + + + + + forward msg from pull (nb_writter:5 nb_readder:1) Summary - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:5 nb_readder:1)

+

Violin Plot

+ + Violin Plot + +

This chart shows the relationship between function/parameter and iteration time. The thickness of the shaded + region indicates the probability that a measurement of the given function/parameter would take a particular + length of time.

+
+ +

forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab'

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:5 nb_readder:1)/none object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/report/violin.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/report/violin.svg new file mode 100644 index 0000000000000..ede3986e48afd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/report/violin.svg @@ -0,0 +1,582 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/none object poll + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/mutex object poll + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/linear object poll + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/crate 'sharded-slab' + + + + + + + + + + + + + -1 + + + + + + + + + + + + + -0.5 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.5 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 2.5 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 3.5 + + + + + + + + + Input + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1): Violin plot + + + + + PDF + + + PDF + + + + + + + + + + gnuplot_plot_2 + + + + + + + gnuplot_plot_3 + + + + + + + gnuplot_plot_4 + + + + + + + gnuplot_plot_5 + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/benchmark.json new file mode 100644 index 0000000000000..bbf21e243e19a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:1)","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll","title":"forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/estimates.json new file mode 100644 index 0000000000000..ea0ac875dd831 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":963.9476766776341,"upper_bound":1215.7280253878632},"point_estimate":1089.6913990936903,"standard_error":64.44060921464697},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":665.2551630434782,"upper_bound":1560.9158790170131},"point_estimate":1340.5937766410912,"standard_error":219.0926288823107},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":358.209469042355,"upper_bound":989.2960915430945},"point_estimate":702.711235601624,"standard_error":174.1373874211686},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1497.9996857679193,"upper_bound":1644.5445296312166},"point_estimate":1579.46546844983,"standard_error":37.268718884923125},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":609.5928431052798,"upper_bound":677.8415191949384},"point_estimate":648.9217536235926,"standard_error":17.333669025892394}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/raw.csv new file mode 100644 index 0000000000000..7536f1bf15f6d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,122700.0,ns,92 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,181435.0,ns,184 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,247255.0,ns,276 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,230770.0,ns,368 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,234454.0,ns,460 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,357782.0,ns,552 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,269054.0,ns,644 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,346126.0,ns,736 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,318806.0,ns,828 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,363078.0,ns,920 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,258152.0,ns,1012 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,431339.0,ns,1104 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,516775.0,ns,1196 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,582754.0,ns,1288 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,438684.0,ns,1380 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,395006.0,ns,1472 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,421380.0,ns,1564 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,478705.0,ns,1656 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,516132.0,ns,1748 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,784489.0,ns,1840 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,441910.0,ns,1932 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,707447.0,ns,2024 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,648013.0,ns,2116 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,686732.0,ns,2208 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,787431.0,ns,2300 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,609550.0,ns,2392 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,889210.0,ns,2484 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,781991.0,ns,2576 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,899312.0,ns,2668 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,622353.0,ns,2760 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,856337.0,ns,2852 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,809432.0,ns,2944 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,841599.0,ns,3036 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,948393.0,ns,3128 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,749230.0,ns,3220 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,1075779.0,ns,3312 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,779922.0,ns,3404 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,1204613.0,ns,3496 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,858566.0,ns,3588 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,2448139.0,ns,3680 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,991252.0,ns,3772 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,1313544.0,ns,3864 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,1845428.0,ns,3956 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,2428980.0,ns,4048 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,3126287.0,ns,4140 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,3751075.0,ns,4232 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,5430994.0,ns,4324 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,5624192.0,ns,4416 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,5680070.0,ns,4508 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,5907687.0,ns,4600 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,6322432.0,ns,4692 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,6782775.0,ns,4784 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,8239596.0,ns,4876 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,7211676.0,ns,4968 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,8105219.0,ns,5060 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,8492274.0,ns,5152 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,8254324.0,ns,5244 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,8338915.0,ns,5336 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10400559.0,ns,5428 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,7806532.0,ns,5520 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,9007983.0,ns,5612 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,8732991.0,ns,5704 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,9859174.0,ns,5796 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10067576.0,ns,5888 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,9306578.0,ns,5980 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10200997.0,ns,6072 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10276135.0,ns,6164 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,9271630.0,ns,6256 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,9908694.0,ns,6348 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10032030.0,ns,6440 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10958426.0,ns,6532 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,11653847.0,ns,6624 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,11097714.0,ns,6716 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12062978.0,ns,6808 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,11562519.0,ns,6900 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10093327.0,ns,6992 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,11922980.0,ns,7084 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12821332.0,ns,7176 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12344095.0,ns,7268 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12684426.0,ns,7360 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12409850.0,ns,7452 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,13026357.0,ns,7544 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12662854.0,ns,7636 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12754015.0,ns,7728 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,14657928.0,ns,7820 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,13759404.0,ns,7912 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,14410785.0,ns,8004 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,13795093.0,ns,8096 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,14805276.0,ns,8188 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,15263608.0,ns,8280 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,13555638.0,ns,8372 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,15070480.0,ns,8464 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,18460733.0,ns,8556 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,15295618.0,ns,8648 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,15724759.0,ns,8740 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,16676448.0,ns,8832 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,16250287.0,ns,8924 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,16676031.0,ns,9016 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,16675518.0,ns,9108 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,16366502.0,ns,9200 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/sample.json new file mode 100644 index 0000000000000..488c8dadd2559 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[92.0,184.0,276.0,368.0,460.0,552.0,644.0,736.0,828.0,920.0,1012.0,1104.0,1196.0,1288.0,1380.0,1472.0,1564.0,1656.0,1748.0,1840.0,1932.0,2024.0,2116.0,2208.0,2300.0,2392.0,2484.0,2576.0,2668.0,2760.0,2852.0,2944.0,3036.0,3128.0,3220.0,3312.0,3404.0,3496.0,3588.0,3680.0,3772.0,3864.0,3956.0,4048.0,4140.0,4232.0,4324.0,4416.0,4508.0,4600.0,4692.0,4784.0,4876.0,4968.0,5060.0,5152.0,5244.0,5336.0,5428.0,5520.0,5612.0,5704.0,5796.0,5888.0,5980.0,6072.0,6164.0,6256.0,6348.0,6440.0,6532.0,6624.0,6716.0,6808.0,6900.0,6992.0,7084.0,7176.0,7268.0,7360.0,7452.0,7544.0,7636.0,7728.0,7820.0,7912.0,8004.0,8096.0,8188.0,8280.0,8372.0,8464.0,8556.0,8648.0,8740.0,8832.0,8924.0,9016.0,9108.0,9200.0],"times":[122700.0,181435.0,247255.0,230770.0,234454.0,357782.0,269054.0,346126.0,318806.0,363078.0,258152.0,431339.0,516775.0,582754.0,438684.0,395006.0,421380.0,478705.0,516132.0,784489.0,441910.0,707447.0,648013.0,686732.0,787431.0,609550.0,889210.0,781991.0,899312.0,622353.0,856337.0,809432.0,841599.0,948393.0,749230.0,1075779.0,779922.0,1204613.0,858566.0,2448139.0,991252.0,1313544.0,1845428.0,2428980.0,3126287.0,3751075.0,5430994.0,5624192.0,5680070.0,5907687.0,6322432.0,6782775.0,8239596.0,7211676.0,8105219.0,8492274.0,8254324.0,8338915.0,10400559.0,7806532.0,9007983.0,8732991.0,9859174.0,10067576.0,9306578.0,10200997.0,10276135.0,9271630.0,9908694.0,10032030.0,10958426.0,11653847.0,11097714.0,12062978.0,11562519.0,10093327.0,11922980.0,12821332.0,12344095.0,12684426.0,12409850.0,13026357.0,12662854.0,12754015.0,14657928.0,13759404.0,14410785.0,13795093.0,14805276.0,15263608.0,13555638.0,15070480.0,18460733.0,15295618.0,15724759.0,16676448.0,16250287.0,16676031.0,16675518.0,16366502.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/tukey.json new file mode 100644 index 0000000000000..828d0eb411429 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/base/tukey.json @@ -0,0 +1 @@ +[-3661.156905192731,-1656.433904281408,3689.494098148786,5694.217099060109] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/benchmark.json new file mode 100644 index 0000000000000..bbf21e243e19a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:1)","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll","title":"forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/estimates.json new file mode 100644 index 0000000000000..ea0ac875dd831 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":963.9476766776341,"upper_bound":1215.7280253878632},"point_estimate":1089.6913990936903,"standard_error":64.44060921464697},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":665.2551630434782,"upper_bound":1560.9158790170131},"point_estimate":1340.5937766410912,"standard_error":219.0926288823107},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":358.209469042355,"upper_bound":989.2960915430945},"point_estimate":702.711235601624,"standard_error":174.1373874211686},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1497.9996857679193,"upper_bound":1644.5445296312166},"point_estimate":1579.46546844983,"standard_error":37.268718884923125},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":609.5928431052798,"upper_bound":677.8415191949384},"point_estimate":648.9217536235926,"standard_error":17.333669025892394}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/raw.csv new file mode 100644 index 0000000000000..7536f1bf15f6d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,122700.0,ns,92 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,181435.0,ns,184 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,247255.0,ns,276 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,230770.0,ns,368 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,234454.0,ns,460 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,357782.0,ns,552 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,269054.0,ns,644 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,346126.0,ns,736 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,318806.0,ns,828 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,363078.0,ns,920 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,258152.0,ns,1012 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,431339.0,ns,1104 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,516775.0,ns,1196 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,582754.0,ns,1288 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,438684.0,ns,1380 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,395006.0,ns,1472 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,421380.0,ns,1564 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,478705.0,ns,1656 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,516132.0,ns,1748 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,784489.0,ns,1840 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,441910.0,ns,1932 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,707447.0,ns,2024 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,648013.0,ns,2116 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,686732.0,ns,2208 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,787431.0,ns,2300 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,609550.0,ns,2392 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,889210.0,ns,2484 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,781991.0,ns,2576 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,899312.0,ns,2668 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,622353.0,ns,2760 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,856337.0,ns,2852 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,809432.0,ns,2944 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,841599.0,ns,3036 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,948393.0,ns,3128 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,749230.0,ns,3220 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,1075779.0,ns,3312 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,779922.0,ns,3404 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,1204613.0,ns,3496 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,858566.0,ns,3588 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,2448139.0,ns,3680 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,991252.0,ns,3772 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,1313544.0,ns,3864 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,1845428.0,ns,3956 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,2428980.0,ns,4048 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,3126287.0,ns,4140 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,3751075.0,ns,4232 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,5430994.0,ns,4324 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,5624192.0,ns,4416 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,5680070.0,ns,4508 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,5907687.0,ns,4600 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,6322432.0,ns,4692 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,6782775.0,ns,4784 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,8239596.0,ns,4876 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,7211676.0,ns,4968 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,8105219.0,ns,5060 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,8492274.0,ns,5152 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,8254324.0,ns,5244 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,8338915.0,ns,5336 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10400559.0,ns,5428 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,7806532.0,ns,5520 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,9007983.0,ns,5612 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,8732991.0,ns,5704 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,9859174.0,ns,5796 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10067576.0,ns,5888 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,9306578.0,ns,5980 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10200997.0,ns,6072 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10276135.0,ns,6164 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,9271630.0,ns,6256 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,9908694.0,ns,6348 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10032030.0,ns,6440 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10958426.0,ns,6532 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,11653847.0,ns,6624 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,11097714.0,ns,6716 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12062978.0,ns,6808 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,11562519.0,ns,6900 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,10093327.0,ns,6992 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,11922980.0,ns,7084 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12821332.0,ns,7176 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12344095.0,ns,7268 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12684426.0,ns,7360 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12409850.0,ns,7452 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,13026357.0,ns,7544 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12662854.0,ns,7636 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,12754015.0,ns,7728 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,14657928.0,ns,7820 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,13759404.0,ns,7912 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,14410785.0,ns,8004 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,13795093.0,ns,8096 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,14805276.0,ns,8188 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,15263608.0,ns,8280 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,13555638.0,ns,8372 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,15070480.0,ns,8464 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,18460733.0,ns,8556 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,15295618.0,ns,8648 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,15724759.0,ns,8740 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,16676448.0,ns,8832 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,16250287.0,ns,8924 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,16676031.0,ns,9016 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,16675518.0,ns,9108 +forward msg from pull (nb_writter:5 nb_readder:1),spin_lock object poll,,,,16366502.0,ns,9200 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/sample.json new file mode 100644 index 0000000000000..488c8dadd2559 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[92.0,184.0,276.0,368.0,460.0,552.0,644.0,736.0,828.0,920.0,1012.0,1104.0,1196.0,1288.0,1380.0,1472.0,1564.0,1656.0,1748.0,1840.0,1932.0,2024.0,2116.0,2208.0,2300.0,2392.0,2484.0,2576.0,2668.0,2760.0,2852.0,2944.0,3036.0,3128.0,3220.0,3312.0,3404.0,3496.0,3588.0,3680.0,3772.0,3864.0,3956.0,4048.0,4140.0,4232.0,4324.0,4416.0,4508.0,4600.0,4692.0,4784.0,4876.0,4968.0,5060.0,5152.0,5244.0,5336.0,5428.0,5520.0,5612.0,5704.0,5796.0,5888.0,5980.0,6072.0,6164.0,6256.0,6348.0,6440.0,6532.0,6624.0,6716.0,6808.0,6900.0,6992.0,7084.0,7176.0,7268.0,7360.0,7452.0,7544.0,7636.0,7728.0,7820.0,7912.0,8004.0,8096.0,8188.0,8280.0,8372.0,8464.0,8556.0,8648.0,8740.0,8832.0,8924.0,9016.0,9108.0,9200.0],"times":[122700.0,181435.0,247255.0,230770.0,234454.0,357782.0,269054.0,346126.0,318806.0,363078.0,258152.0,431339.0,516775.0,582754.0,438684.0,395006.0,421380.0,478705.0,516132.0,784489.0,441910.0,707447.0,648013.0,686732.0,787431.0,609550.0,889210.0,781991.0,899312.0,622353.0,856337.0,809432.0,841599.0,948393.0,749230.0,1075779.0,779922.0,1204613.0,858566.0,2448139.0,991252.0,1313544.0,1845428.0,2428980.0,3126287.0,3751075.0,5430994.0,5624192.0,5680070.0,5907687.0,6322432.0,6782775.0,8239596.0,7211676.0,8105219.0,8492274.0,8254324.0,8338915.0,10400559.0,7806532.0,9007983.0,8732991.0,9859174.0,10067576.0,9306578.0,10200997.0,10276135.0,9271630.0,9908694.0,10032030.0,10958426.0,11653847.0,11097714.0,12062978.0,11562519.0,10093327.0,11922980.0,12821332.0,12344095.0,12684426.0,12409850.0,13026357.0,12662854.0,12754015.0,14657928.0,13759404.0,14410785.0,13795093.0,14805276.0,15263608.0,13555638.0,15070480.0,18460733.0,15295618.0,15724759.0,16676448.0,16250287.0,16676031.0,16675518.0,16366502.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/tukey.json new file mode 100644 index 0000000000000..828d0eb411429 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/new/tukey.json @@ -0,0 +1 @@ +[-3661.156905192731,-1656.433904281408,3689.494098148786,5694.217099060109] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/MAD.svg new file mode 100644 index 0000000000000..3c152a9caa9c3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/MAD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + 300 + + + + + 400 + + + + + 500 + + + + + 600 + + + + + 700 + + + + + 800 + + + + + 900 + + + + + 1000 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/SD.svg new file mode 100644 index 0000000000000..77b85faca5d81 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/SD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 610 + + + + + 620 + + + + + 630 + + + + + 640 + + + + + 650 + + + + + 660 + + + + + 670 + + + + + 680 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/index.html new file mode 100644 index 0000000000000..86e028db46bcc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope1.4980 us1.5795 us1.6445 us
0.15468910.15954040.1564100
Mean963.95 ns1.0897 us1.2157 us
Std. Dev.609.59 ns648.92 ns677.84 ns
Median665.26 ns1.3406 us1.5609 us
MAD358.21 ns702.71 ns989.30 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/mean.svg new file mode 100644 index 0000000000000..d68d3776dbbd9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 0.95 + + + + + 1 + + + + + 1.05 + + + + + 1.1 + + + + + 1.15 + + + + + 1.2 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/median.svg new file mode 100644 index 0000000000000..479625f7db74d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/median.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/pdf.svg new file mode 100644 index 0000000000000..4253e8097eb10 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/pdf.svg @@ -0,0 +1,420 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + -0.5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..768995cd2a719 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/pdf_small.svg @@ -0,0 +1,219 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + -0.5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/regression.svg new file mode 100644 index 0000000000000..80b76233a499c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/regression.svg @@ -0,0 +1,499 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 9 + + + + + + + + + + + + + 10 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/regression_small.svg new file mode 100644 index 0000000000000..3765c33e02ae1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/regression_small.svg @@ -0,0 +1,477 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 9 + + + + + + + + + + + + + 10 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/slope.svg new file mode 100644 index 0000000000000..04863af35cc32 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/slope.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 1.5 + + + + + 1.52 + + + + + 1.54 + + + + + 1.56 + + + + + 1.58 + + + + + 1.6 + + + + + 1.62 + + + + + 1.64 + + + + + 1.66 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/typical.svg new file mode 100644 index 0000000000000..a78e14af67a05 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_1)/spin_lock object poll/report/typical.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 1.5 + + + + + 1.52 + + + + + 1.54 + + + + + 1.56 + + + + + 1.58 + + + + + 1.6 + + + + + 1.62 + + + + + 1.64 + + + + + 1.66 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:1)/spin_lock object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/benchmark.json new file mode 100644 index 0000000000000..6f1b2d048564e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:5)","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab'","directory_name":"forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'","title":"forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/estimates.json new file mode 100644 index 0000000000000..8967b61d3d37c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1216.5939660932368,"upper_bound":1360.3258099896866},"point_estimate":1289.2073475911252,"standard_error":36.705624301840565},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1299.5865102639295,"upper_bound":1419.1493506493507},"point_estimate":1375.8265306122448,"standard_error":33.23918907201183},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":221.51438387221177,"upper_bound":459.50204920788156},"point_estimate":338.3207403610865,"standard_error":60.80632905596639},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1415.2303514419118,"upper_bound":1498.0499763009773},"point_estimate":1456.1674877509072,"standard_error":21.063028556009836},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":325.9900526540059,"upper_bound":406.9851821034631},"point_estimate":369.9491444025388,"standard_error":20.67514371511026}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/raw.csv new file mode 100644 index 0000000000000..4f21086b94e6a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,105868.0,ns,77 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,218549.0,ns,154 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,308439.0,ns,231 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,209906.0,ns,308 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,318654.0,ns,385 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,375892.0,ns,462 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,761350.0,ns,539 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,465614.0,ns,616 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,497944.0,ns,693 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,507899.0,ns,770 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,514235.0,ns,847 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,885632.0,ns,924 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1070132.0,ns,1001 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,897807.0,ns,1078 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,829605.0,ns,1155 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,751735.0,ns,1232 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,959787.0,ns,1309 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,978728.0,ns,1386 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,998433.0,ns,1463 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1082933.0,ns,1540 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1055512.0,ns,1617 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1258895.0,ns,1694 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1234757.0,ns,1771 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1174067.0,ns,1848 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1356024.0,ns,1925 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1195350.0,ns,2002 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,2034545.0,ns,2079 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,2945436.0,ns,2156 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3110866.0,ns,2233 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3473657.0,ns,2310 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3102113.0,ns,2387 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3210132.0,ns,2464 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3800265.0,ns,2541 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3355209.0,ns,2618 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,4206371.0,ns,2695 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3652735.0,ns,2772 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3983173.0,ns,2849 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3669117.0,ns,2926 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3822825.0,ns,3003 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3911710.0,ns,3080 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,4008569.0,ns,3157 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3646298.0,ns,3234 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3790435.0,ns,3311 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3543364.0,ns,3388 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3485969.0,ns,3465 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3863997.0,ns,3542 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3852207.0,ns,3619 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,4231033.0,ns,3696 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3901721.0,ns,3773 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,4040391.0,ns,3850 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,4072229.0,ns,3927 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,4146816.0,ns,4004 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,7672818.0,ns,4081 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,7757650.0,ns,4158 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8718772.0,ns,4235 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,7928124.0,ns,4312 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8626486.0,ns,4389 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8102508.0,ns,4466 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8600133.0,ns,4543 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8211880.0,ns,4620 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8189083.0,ns,4697 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8852958.0,ns,4774 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8097890.0,ns,4851 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8563320.0,ns,4928 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8582409.0,ns,5005 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8137243.0,ns,5082 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8466374.0,ns,5159 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8922269.0,ns,5236 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8580365.0,ns,5313 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8618966.0,ns,5390 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8437231.0,ns,5467 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8783743.0,ns,5544 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8887096.0,ns,5621 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8957484.0,ns,5698 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8820824.0,ns,5775 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9084281.0,ns,5852 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9043660.0,ns,5929 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9249610.0,ns,6006 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9614699.0,ns,6083 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9469734.0,ns,6160 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8937540.0,ns,6237 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9505460.0,ns,6314 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8889461.0,ns,6391 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9072412.0,ns,6468 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9513671.0,ns,6545 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9491144.0,ns,6622 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9484868.0,ns,6699 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9657804.0,ns,6776 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9497201.0,ns,6853 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9890608.0,ns,6930 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9646845.0,ns,7007 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,10074210.0,ns,7084 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,10391552.0,ns,7161 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,10645627.0,ns,7238 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,10181521.0,ns,7315 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,10074198.0,ns,7392 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9961619.0,ns,7469 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9887594.0,ns,7546 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9839454.0,ns,7623 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,10205448.0,ns,7700 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/sample.json new file mode 100644 index 0000000000000..9f452f724ed1c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[77.0,154.0,231.0,308.0,385.0,462.0,539.0,616.0,693.0,770.0,847.0,924.0,1001.0,1078.0,1155.0,1232.0,1309.0,1386.0,1463.0,1540.0,1617.0,1694.0,1771.0,1848.0,1925.0,2002.0,2079.0,2156.0,2233.0,2310.0,2387.0,2464.0,2541.0,2618.0,2695.0,2772.0,2849.0,2926.0,3003.0,3080.0,3157.0,3234.0,3311.0,3388.0,3465.0,3542.0,3619.0,3696.0,3773.0,3850.0,3927.0,4004.0,4081.0,4158.0,4235.0,4312.0,4389.0,4466.0,4543.0,4620.0,4697.0,4774.0,4851.0,4928.0,5005.0,5082.0,5159.0,5236.0,5313.0,5390.0,5467.0,5544.0,5621.0,5698.0,5775.0,5852.0,5929.0,6006.0,6083.0,6160.0,6237.0,6314.0,6391.0,6468.0,6545.0,6622.0,6699.0,6776.0,6853.0,6930.0,7007.0,7084.0,7161.0,7238.0,7315.0,7392.0,7469.0,7546.0,7623.0,7700.0],"times":[105868.0,218549.0,308439.0,209906.0,318654.0,375892.0,761350.0,465614.0,497944.0,507899.0,514235.0,885632.0,1070132.0,897807.0,829605.0,751735.0,959787.0,978728.0,998433.0,1082933.0,1055512.0,1258895.0,1234757.0,1174067.0,1356024.0,1195350.0,2034545.0,2945436.0,3110866.0,3473657.0,3102113.0,3210132.0,3800265.0,3355209.0,4206371.0,3652735.0,3983173.0,3669117.0,3822825.0,3911710.0,4008569.0,3646298.0,3790435.0,3543364.0,3485969.0,3863997.0,3852207.0,4231033.0,3901721.0,4040391.0,4072229.0,4146816.0,7672818.0,7757650.0,8718772.0,7928124.0,8626486.0,8102508.0,8600133.0,8211880.0,8189083.0,8852958.0,8097890.0,8563320.0,8582409.0,8137243.0,8466374.0,8922269.0,8580365.0,8618966.0,8437231.0,8783743.0,8887096.0,8957484.0,8820824.0,9084281.0,9043660.0,9249610.0,9614699.0,9469734.0,8937540.0,9505460.0,8889461.0,9072412.0,9513671.0,9491144.0,9484868.0,9657804.0,9497201.0,9890608.0,9646845.0,10074210.0,10391552.0,10645627.0,10181521.0,10074198.0,9961619.0,9887594.0,9839454.0,10205448.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/tukey.json new file mode 100644 index 0000000000000..ac6fb22e7f432 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/base/tukey.json @@ -0,0 +1 @@ +[-476.0001138050011,280.32680006406235,2297.198570381565,3053.5254842506283] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/benchmark.json new file mode 100644 index 0000000000000..6f1b2d048564e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:5)","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab'","directory_name":"forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'","title":"forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/estimates.json new file mode 100644 index 0000000000000..8967b61d3d37c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1216.5939660932368,"upper_bound":1360.3258099896866},"point_estimate":1289.2073475911252,"standard_error":36.705624301840565},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1299.5865102639295,"upper_bound":1419.1493506493507},"point_estimate":1375.8265306122448,"standard_error":33.23918907201183},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":221.51438387221177,"upper_bound":459.50204920788156},"point_estimate":338.3207403610865,"standard_error":60.80632905596639},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1415.2303514419118,"upper_bound":1498.0499763009773},"point_estimate":1456.1674877509072,"standard_error":21.063028556009836},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":325.9900526540059,"upper_bound":406.9851821034631},"point_estimate":369.9491444025388,"standard_error":20.67514371511026}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/raw.csv new file mode 100644 index 0000000000000..4f21086b94e6a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,105868.0,ns,77 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,218549.0,ns,154 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,308439.0,ns,231 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,209906.0,ns,308 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,318654.0,ns,385 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,375892.0,ns,462 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,761350.0,ns,539 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,465614.0,ns,616 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,497944.0,ns,693 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,507899.0,ns,770 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,514235.0,ns,847 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,885632.0,ns,924 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1070132.0,ns,1001 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,897807.0,ns,1078 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,829605.0,ns,1155 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,751735.0,ns,1232 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,959787.0,ns,1309 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,978728.0,ns,1386 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,998433.0,ns,1463 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1082933.0,ns,1540 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1055512.0,ns,1617 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1258895.0,ns,1694 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1234757.0,ns,1771 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1174067.0,ns,1848 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1356024.0,ns,1925 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,1195350.0,ns,2002 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,2034545.0,ns,2079 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,2945436.0,ns,2156 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3110866.0,ns,2233 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3473657.0,ns,2310 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3102113.0,ns,2387 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3210132.0,ns,2464 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3800265.0,ns,2541 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3355209.0,ns,2618 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,4206371.0,ns,2695 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3652735.0,ns,2772 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3983173.0,ns,2849 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3669117.0,ns,2926 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3822825.0,ns,3003 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3911710.0,ns,3080 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,4008569.0,ns,3157 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3646298.0,ns,3234 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3790435.0,ns,3311 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3543364.0,ns,3388 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3485969.0,ns,3465 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3863997.0,ns,3542 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3852207.0,ns,3619 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,4231033.0,ns,3696 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,3901721.0,ns,3773 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,4040391.0,ns,3850 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,4072229.0,ns,3927 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,4146816.0,ns,4004 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,7672818.0,ns,4081 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,7757650.0,ns,4158 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8718772.0,ns,4235 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,7928124.0,ns,4312 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8626486.0,ns,4389 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8102508.0,ns,4466 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8600133.0,ns,4543 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8211880.0,ns,4620 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8189083.0,ns,4697 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8852958.0,ns,4774 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8097890.0,ns,4851 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8563320.0,ns,4928 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8582409.0,ns,5005 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8137243.0,ns,5082 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8466374.0,ns,5159 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8922269.0,ns,5236 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8580365.0,ns,5313 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8618966.0,ns,5390 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8437231.0,ns,5467 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8783743.0,ns,5544 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8887096.0,ns,5621 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8957484.0,ns,5698 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8820824.0,ns,5775 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9084281.0,ns,5852 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9043660.0,ns,5929 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9249610.0,ns,6006 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9614699.0,ns,6083 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9469734.0,ns,6160 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8937540.0,ns,6237 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9505460.0,ns,6314 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,8889461.0,ns,6391 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9072412.0,ns,6468 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9513671.0,ns,6545 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9491144.0,ns,6622 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9484868.0,ns,6699 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9657804.0,ns,6776 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9497201.0,ns,6853 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9890608.0,ns,6930 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9646845.0,ns,7007 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,10074210.0,ns,7084 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,10391552.0,ns,7161 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,10645627.0,ns,7238 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,10181521.0,ns,7315 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,10074198.0,ns,7392 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9961619.0,ns,7469 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9887594.0,ns,7546 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,9839454.0,ns,7623 +forward msg from pull (nb_writter:5 nb_readder:5),crate 'sharded-slab',,,,10205448.0,ns,7700 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/sample.json new file mode 100644 index 0000000000000..9f452f724ed1c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[77.0,154.0,231.0,308.0,385.0,462.0,539.0,616.0,693.0,770.0,847.0,924.0,1001.0,1078.0,1155.0,1232.0,1309.0,1386.0,1463.0,1540.0,1617.0,1694.0,1771.0,1848.0,1925.0,2002.0,2079.0,2156.0,2233.0,2310.0,2387.0,2464.0,2541.0,2618.0,2695.0,2772.0,2849.0,2926.0,3003.0,3080.0,3157.0,3234.0,3311.0,3388.0,3465.0,3542.0,3619.0,3696.0,3773.0,3850.0,3927.0,4004.0,4081.0,4158.0,4235.0,4312.0,4389.0,4466.0,4543.0,4620.0,4697.0,4774.0,4851.0,4928.0,5005.0,5082.0,5159.0,5236.0,5313.0,5390.0,5467.0,5544.0,5621.0,5698.0,5775.0,5852.0,5929.0,6006.0,6083.0,6160.0,6237.0,6314.0,6391.0,6468.0,6545.0,6622.0,6699.0,6776.0,6853.0,6930.0,7007.0,7084.0,7161.0,7238.0,7315.0,7392.0,7469.0,7546.0,7623.0,7700.0],"times":[105868.0,218549.0,308439.0,209906.0,318654.0,375892.0,761350.0,465614.0,497944.0,507899.0,514235.0,885632.0,1070132.0,897807.0,829605.0,751735.0,959787.0,978728.0,998433.0,1082933.0,1055512.0,1258895.0,1234757.0,1174067.0,1356024.0,1195350.0,2034545.0,2945436.0,3110866.0,3473657.0,3102113.0,3210132.0,3800265.0,3355209.0,4206371.0,3652735.0,3983173.0,3669117.0,3822825.0,3911710.0,4008569.0,3646298.0,3790435.0,3543364.0,3485969.0,3863997.0,3852207.0,4231033.0,3901721.0,4040391.0,4072229.0,4146816.0,7672818.0,7757650.0,8718772.0,7928124.0,8626486.0,8102508.0,8600133.0,8211880.0,8189083.0,8852958.0,8097890.0,8563320.0,8582409.0,8137243.0,8466374.0,8922269.0,8580365.0,8618966.0,8437231.0,8783743.0,8887096.0,8957484.0,8820824.0,9084281.0,9043660.0,9249610.0,9614699.0,9469734.0,8937540.0,9505460.0,8889461.0,9072412.0,9513671.0,9491144.0,9484868.0,9657804.0,9497201.0,9890608.0,9646845.0,10074210.0,10391552.0,10645627.0,10181521.0,10074198.0,9961619.0,9887594.0,9839454.0,10205448.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/tukey.json new file mode 100644 index 0000000000000..ac6fb22e7f432 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/new/tukey.json @@ -0,0 +1 @@ +[-476.0001138050011,280.32680006406235,2297.198570381565,3053.5254842506283] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/MAD.svg new file mode 100644 index 0000000000000..9a7e974912c5d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/MAD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 200 + + + + + 250 + + + + + 300 + + + + + 350 + + + + + 400 + + + + + 450 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab': MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/SD.svg new file mode 100644 index 0000000000000..4cbcd030f84eb --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/SD.svg @@ -0,0 +1,328 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 0.018 + + + + + 0.02 + + + + + 320 + + + + + 330 + + + + + 340 + + + + + 350 + + + + + 360 + + + + + 370 + + + + + 380 + + + + + 390 + + + + + 400 + + + + + 410 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab': SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/index.html new file mode 100644 index 0000000000000..93e432d08aff2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab' - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab'

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope1.4152 us1.4562 us1.4980 us
0.17650650.18138220.1762851
Mean1.2166 us1.2892 us1.3603 us
Std. Dev.325.99 ns369.95 ns406.99 ns
Median1.2996 us1.3758 us1.4191 us
MAD221.51 ns338.32 ns459.50 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/mean.svg new file mode 100644 index 0000000000000..96dbde70a6b42 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/mean.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 1.22 + + + + + 1.24 + + + + + 1.26 + + + + + 1.28 + + + + + 1.3 + + + + + 1.32 + + + + + 1.34 + + + + + 1.36 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab': mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/median.svg new file mode 100644 index 0000000000000..75345492c9a5e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/median.svg @@ -0,0 +1,288 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 1.3 + + + + + 1.32 + + + + + 1.34 + + + + + 1.36 + + + + + 1.38 + + + + + 1.4 + + + + + 1.42 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab': median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/pdf.svg new file mode 100644 index 0000000000000..e6e7fe1db3caa --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/pdf.svg @@ -0,0 +1,395 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab' + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/pdf_small.svg new file mode 100644 index 0000000000000..661c6054b4d28 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/pdf_small.svg @@ -0,0 +1,204 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/regression.svg new file mode 100644 index 0000000000000..489de5cad8dda --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/regression.svg @@ -0,0 +1,421 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab' + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/regression_small.svg new file mode 100644 index 0000000000000..5f387acea6d8a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/regression_small.svg @@ -0,0 +1,399 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/slope.svg new file mode 100644 index 0000000000000..3b73511d76136 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/slope.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + 1.42 + + + + + 1.44 + + + + + 1.46 + + + + + 1.48 + + + + + 1.5 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab': slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/typical.svg new file mode 100644 index 0000000000000..58024b0802444 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/crate 'sharded-slab'/report/typical.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + 1.42 + + + + + 1.44 + + + + + 1.46 + + + + + 1.48 + + + + + 1.5 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab': typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/benchmark.json new file mode 100644 index 0000000000000..068345294181a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:5)","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll","title":"forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/estimates.json new file mode 100644 index 0000000000000..e5b5f8f504d3d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":324.69311178531126,"upper_bound":329.3797027625745},"point_estimate":326.92145063545473,"standard_error":1.19761733040763},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":322.78343341182625,"upper_bound":325.5083968826205},"point_estimate":324.0604165970807,"standard_error":0.6938976156310456},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":5.308856377935553,"upper_bound":9.261320289598356},"point_estimate":7.35543520753836,"standard_error":0.9932349904063743},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":321.22748404148524,"upper_bound":324.7254737288013},"point_estimate":322.92353094561076,"standard_error":0.8915051736776504},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":8.825056508520467,"upper_bound":14.866267652217367},"point_estimate":12.051869638679857,"standard_error":1.5484379119526712}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/raw.csv new file mode 100644 index 0000000000000..84e868ee00a8a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,218266.0,ns,637 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,479686.0,ns,1274 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,618297.0,ns,1911 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,908917.0,ns,2548 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,1107592.0,ns,3185 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,1399848.0,ns,3822 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,1652254.0,ns,4459 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,1752372.0,ns,5096 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,2077453.0,ns,5733 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,2048565.0,ns,6370 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,2366587.0,ns,7007 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,2568388.0,ns,7644 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,2724038.0,ns,8281 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,2983518.0,ns,8918 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,3336171.0,ns,9555 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,3391298.0,ns,10192 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,3553707.0,ns,10829 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,3785565.0,ns,11466 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,3896484.0,ns,12103 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,4097424.0,ns,12740 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,4306681.0,ns,13377 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,4555673.0,ns,14014 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,4803877.0,ns,14651 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,5126566.0,ns,15288 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,5150565.0,ns,15925 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,5286122.0,ns,16562 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,5490556.0,ns,17199 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,5575590.0,ns,17836 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,6172552.0,ns,18473 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,6204379.0,ns,19110 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,6457824.0,ns,19747 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,6569656.0,ns,20384 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,6823401.0,ns,21021 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,7094465.0,ns,21658 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,7103898.0,ns,22295 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,7140423.0,ns,22932 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,7960995.0,ns,23569 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,7833110.0,ns,24206 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,7867162.0,ns,24843 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,8128834.0,ns,25480 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,8318032.0,ns,26117 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,8894512.0,ns,26754 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,8904028.0,ns,27391 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,9109683.0,ns,28028 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,9503482.0,ns,28665 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,9550596.0,ns,29302 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,9704024.0,ns,29939 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,9881161.0,ns,30576 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,10042657.0,ns,31213 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,10173897.0,ns,31850 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,10752204.0,ns,32487 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,11012868.0,ns,33124 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,10616730.0,ns,33761 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,10724730.0,ns,34398 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,11166260.0,ns,35035 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,11557525.0,ns,35672 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,12031937.0,ns,36309 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,11842450.0,ns,36946 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,12451317.0,ns,37583 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,12841306.0,ns,38220 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,12510632.0,ns,38857 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,12648805.0,ns,39494 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,12877916.0,ns,40131 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,13198788.0,ns,40768 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,13446917.0,ns,41405 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,13408984.0,ns,42042 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,13753474.0,ns,42679 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,14173525.0,ns,43316 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,14062164.0,ns,43953 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,14709982.0,ns,44590 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,14018633.0,ns,45227 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,14246643.0,ns,45864 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,14981294.0,ns,46501 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,15079747.0,ns,47138 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,15402643.0,ns,47775 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,15193666.0,ns,48412 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,15835355.0,ns,49049 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,16728341.0,ns,49686 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,16316926.0,ns,50323 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,16250268.0,ns,50960 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,16403790.0,ns,51597 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,16489769.0,ns,52234 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,17251478.0,ns,52871 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,17297937.0,ns,53508 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,17794259.0,ns,54145 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,17875882.0,ns,54782 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,18021654.0,ns,55419 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,18462642.0,ns,56056 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,17844036.0,ns,56693 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,17931306.0,ns,57330 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,18819239.0,ns,57967 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,19326024.0,ns,58604 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,19323303.0,ns,59241 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,18906378.0,ns,59878 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,19588869.0,ns,60515 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,20780923.0,ns,61152 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,19599046.0,ns,61789 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,20039014.0,ns,62426 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,20382118.0,ns,63063 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,20110110.0,ns,63700 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/sample.json new file mode 100644 index 0000000000000..7e04e08fef7c4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[637.0,1274.0,1911.0,2548.0,3185.0,3822.0,4459.0,5096.0,5733.0,6370.0,7007.0,7644.0,8281.0,8918.0,9555.0,10192.0,10829.0,11466.0,12103.0,12740.0,13377.0,14014.0,14651.0,15288.0,15925.0,16562.0,17199.0,17836.0,18473.0,19110.0,19747.0,20384.0,21021.0,21658.0,22295.0,22932.0,23569.0,24206.0,24843.0,25480.0,26117.0,26754.0,27391.0,28028.0,28665.0,29302.0,29939.0,30576.0,31213.0,31850.0,32487.0,33124.0,33761.0,34398.0,35035.0,35672.0,36309.0,36946.0,37583.0,38220.0,38857.0,39494.0,40131.0,40768.0,41405.0,42042.0,42679.0,43316.0,43953.0,44590.0,45227.0,45864.0,46501.0,47138.0,47775.0,48412.0,49049.0,49686.0,50323.0,50960.0,51597.0,52234.0,52871.0,53508.0,54145.0,54782.0,55419.0,56056.0,56693.0,57330.0,57967.0,58604.0,59241.0,59878.0,60515.0,61152.0,61789.0,62426.0,63063.0,63700.0],"times":[218266.0,479686.0,618297.0,908917.0,1107592.0,1399848.0,1652254.0,1752372.0,2077453.0,2048565.0,2366587.0,2568388.0,2724038.0,2983518.0,3336171.0,3391298.0,3553707.0,3785565.0,3896484.0,4097424.0,4306681.0,4555673.0,4803877.0,5126566.0,5150565.0,5286122.0,5490556.0,5575590.0,6172552.0,6204379.0,6457824.0,6569656.0,6823401.0,7094465.0,7103898.0,7140423.0,7960995.0,7833110.0,7867162.0,8128834.0,8318032.0,8894512.0,8904028.0,9109683.0,9503482.0,9550596.0,9704024.0,9881161.0,10042657.0,10173897.0,10752204.0,11012868.0,10616730.0,10724730.0,11166260.0,11557525.0,12031937.0,11842450.0,12451317.0,12841306.0,12510632.0,12648805.0,12877916.0,13198788.0,13446917.0,13408984.0,13753474.0,14173525.0,14062164.0,14709982.0,14018633.0,14246643.0,14981294.0,15079747.0,15402643.0,15193666.0,15835355.0,16728341.0,16316926.0,16250268.0,16403790.0,16489769.0,17251478.0,17297937.0,17794259.0,17875882.0,18021654.0,18462642.0,17844036.0,17931306.0,18819239.0,19326024.0,19323303.0,18906378.0,19588869.0,20780923.0,19599046.0,20039014.0,20382118.0,20110110.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/tukey.json new file mode 100644 index 0000000000000..04a4da52fa9d1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/base/tukey.json @@ -0,0 +1 @@ +[288.6381908770016,304.2835380694807,346.00446391609165,361.64981110857076] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/benchmark.json new file mode 100644 index 0000000000000..068345294181a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:5)","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll","title":"forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/estimates.json new file mode 100644 index 0000000000000..e5b5f8f504d3d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":324.69311178531126,"upper_bound":329.3797027625745},"point_estimate":326.92145063545473,"standard_error":1.19761733040763},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":322.78343341182625,"upper_bound":325.5083968826205},"point_estimate":324.0604165970807,"standard_error":0.6938976156310456},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":5.308856377935553,"upper_bound":9.261320289598356},"point_estimate":7.35543520753836,"standard_error":0.9932349904063743},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":321.22748404148524,"upper_bound":324.7254737288013},"point_estimate":322.92353094561076,"standard_error":0.8915051736776504},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":8.825056508520467,"upper_bound":14.866267652217367},"point_estimate":12.051869638679857,"standard_error":1.5484379119526712}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/raw.csv new file mode 100644 index 0000000000000..84e868ee00a8a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,218266.0,ns,637 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,479686.0,ns,1274 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,618297.0,ns,1911 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,908917.0,ns,2548 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,1107592.0,ns,3185 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,1399848.0,ns,3822 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,1652254.0,ns,4459 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,1752372.0,ns,5096 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,2077453.0,ns,5733 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,2048565.0,ns,6370 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,2366587.0,ns,7007 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,2568388.0,ns,7644 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,2724038.0,ns,8281 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,2983518.0,ns,8918 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,3336171.0,ns,9555 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,3391298.0,ns,10192 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,3553707.0,ns,10829 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,3785565.0,ns,11466 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,3896484.0,ns,12103 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,4097424.0,ns,12740 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,4306681.0,ns,13377 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,4555673.0,ns,14014 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,4803877.0,ns,14651 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,5126566.0,ns,15288 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,5150565.0,ns,15925 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,5286122.0,ns,16562 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,5490556.0,ns,17199 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,5575590.0,ns,17836 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,6172552.0,ns,18473 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,6204379.0,ns,19110 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,6457824.0,ns,19747 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,6569656.0,ns,20384 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,6823401.0,ns,21021 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,7094465.0,ns,21658 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,7103898.0,ns,22295 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,7140423.0,ns,22932 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,7960995.0,ns,23569 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,7833110.0,ns,24206 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,7867162.0,ns,24843 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,8128834.0,ns,25480 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,8318032.0,ns,26117 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,8894512.0,ns,26754 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,8904028.0,ns,27391 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,9109683.0,ns,28028 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,9503482.0,ns,28665 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,9550596.0,ns,29302 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,9704024.0,ns,29939 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,9881161.0,ns,30576 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,10042657.0,ns,31213 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,10173897.0,ns,31850 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,10752204.0,ns,32487 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,11012868.0,ns,33124 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,10616730.0,ns,33761 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,10724730.0,ns,34398 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,11166260.0,ns,35035 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,11557525.0,ns,35672 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,12031937.0,ns,36309 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,11842450.0,ns,36946 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,12451317.0,ns,37583 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,12841306.0,ns,38220 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,12510632.0,ns,38857 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,12648805.0,ns,39494 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,12877916.0,ns,40131 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,13198788.0,ns,40768 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,13446917.0,ns,41405 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,13408984.0,ns,42042 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,13753474.0,ns,42679 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,14173525.0,ns,43316 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,14062164.0,ns,43953 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,14709982.0,ns,44590 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,14018633.0,ns,45227 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,14246643.0,ns,45864 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,14981294.0,ns,46501 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,15079747.0,ns,47138 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,15402643.0,ns,47775 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,15193666.0,ns,48412 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,15835355.0,ns,49049 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,16728341.0,ns,49686 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,16316926.0,ns,50323 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,16250268.0,ns,50960 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,16403790.0,ns,51597 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,16489769.0,ns,52234 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,17251478.0,ns,52871 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,17297937.0,ns,53508 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,17794259.0,ns,54145 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,17875882.0,ns,54782 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,18021654.0,ns,55419 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,18462642.0,ns,56056 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,17844036.0,ns,56693 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,17931306.0,ns,57330 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,18819239.0,ns,57967 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,19326024.0,ns,58604 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,19323303.0,ns,59241 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,18906378.0,ns,59878 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,19588869.0,ns,60515 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,20780923.0,ns,61152 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,19599046.0,ns,61789 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,20039014.0,ns,62426 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,20382118.0,ns,63063 +forward msg from pull (nb_writter:5 nb_readder:5),linear object poll,,,,20110110.0,ns,63700 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/sample.json new file mode 100644 index 0000000000000..7e04e08fef7c4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[637.0,1274.0,1911.0,2548.0,3185.0,3822.0,4459.0,5096.0,5733.0,6370.0,7007.0,7644.0,8281.0,8918.0,9555.0,10192.0,10829.0,11466.0,12103.0,12740.0,13377.0,14014.0,14651.0,15288.0,15925.0,16562.0,17199.0,17836.0,18473.0,19110.0,19747.0,20384.0,21021.0,21658.0,22295.0,22932.0,23569.0,24206.0,24843.0,25480.0,26117.0,26754.0,27391.0,28028.0,28665.0,29302.0,29939.0,30576.0,31213.0,31850.0,32487.0,33124.0,33761.0,34398.0,35035.0,35672.0,36309.0,36946.0,37583.0,38220.0,38857.0,39494.0,40131.0,40768.0,41405.0,42042.0,42679.0,43316.0,43953.0,44590.0,45227.0,45864.0,46501.0,47138.0,47775.0,48412.0,49049.0,49686.0,50323.0,50960.0,51597.0,52234.0,52871.0,53508.0,54145.0,54782.0,55419.0,56056.0,56693.0,57330.0,57967.0,58604.0,59241.0,59878.0,60515.0,61152.0,61789.0,62426.0,63063.0,63700.0],"times":[218266.0,479686.0,618297.0,908917.0,1107592.0,1399848.0,1652254.0,1752372.0,2077453.0,2048565.0,2366587.0,2568388.0,2724038.0,2983518.0,3336171.0,3391298.0,3553707.0,3785565.0,3896484.0,4097424.0,4306681.0,4555673.0,4803877.0,5126566.0,5150565.0,5286122.0,5490556.0,5575590.0,6172552.0,6204379.0,6457824.0,6569656.0,6823401.0,7094465.0,7103898.0,7140423.0,7960995.0,7833110.0,7867162.0,8128834.0,8318032.0,8894512.0,8904028.0,9109683.0,9503482.0,9550596.0,9704024.0,9881161.0,10042657.0,10173897.0,10752204.0,11012868.0,10616730.0,10724730.0,11166260.0,11557525.0,12031937.0,11842450.0,12451317.0,12841306.0,12510632.0,12648805.0,12877916.0,13198788.0,13446917.0,13408984.0,13753474.0,14173525.0,14062164.0,14709982.0,14018633.0,14246643.0,14981294.0,15079747.0,15402643.0,15193666.0,15835355.0,16728341.0,16316926.0,16250268.0,16403790.0,16489769.0,17251478.0,17297937.0,17794259.0,17875882.0,18021654.0,18462642.0,17844036.0,17931306.0,18819239.0,19326024.0,19323303.0,18906378.0,19588869.0,20780923.0,19599046.0,20039014.0,20382118.0,20110110.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/tukey.json new file mode 100644 index 0000000000000..04a4da52fa9d1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/new/tukey.json @@ -0,0 +1 @@ +[288.6381908770016,304.2835380694807,346.00446391609165,361.64981110857076] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/MAD.svg new file mode 100644 index 0000000000000..bd85fd065d869 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/MAD.svg @@ -0,0 +1,323 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 5 + + + + + 5.5 + + + + + 6 + + + + + 6.5 + + + + + 7 + + + + + 7.5 + + + + + 8 + + + + + 8.5 + + + + + 9 + + + + + 9.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/SD.svg new file mode 100644 index 0000000000000..e3105a2c6b723 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/SD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 14 + + + + + 15 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/index.html new file mode 100644 index 0000000000000..5eb4f72235d6f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope321.23 ns322.92 ns324.73 ns
0.93477550.93845600.9343037
Mean324.69 ns326.92 ns329.38 ns
Std. Dev.8.8251 ns12.052 ns14.866 ns
Median322.78 ns324.06 ns325.51 ns
MAD5.3089 ns7.3554 ns9.2613 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/mean.svg new file mode 100644 index 0000000000000..547f55a23d636 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/mean.svg @@ -0,0 +1,288 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 325 + + + + + 326 + + + + + 327 + + + + + 328 + + + + + 329 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/median.svg new file mode 100644 index 0000000000000..2360e6bceeb34 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/median.svg @@ -0,0 +1,308 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 0.9 + + + + + 322.5 + + + + + 323 + + + + + 323.5 + + + + + 324 + + + + + 324.5 + + + + + 325 + + + + + 325.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/pdf.svg new file mode 100644 index 0000000000000..231ef64b5f311 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/pdf.svg @@ -0,0 +1,450 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 300 + + + + + 310 + + + + + 320 + + + + + 330 + + + + + 340 + + + + + 350 + + + + + 360 + + + + + 370 + + + + + 380 + + + + + 390 + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 0.04 + + + + + 0.045 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..6ad9c3dc82562 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/pdf_small.svg @@ -0,0 +1,244 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 0.04 + + + + + 0.045 + + + + + 300 + + + + + 310 + + + + + 320 + + + + + 330 + + + + + 340 + + + + + 350 + + + + + 360 + + + + + 370 + + + + + 380 + + + + + 390 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/regression.svg new file mode 100644 index 0000000000000..f60e0aad7202c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/regression.svg @@ -0,0 +1,395 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/regression_small.svg new file mode 100644 index 0000000000000..e12c0b22c8c80 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/regression_small.svg @@ -0,0 +1,373 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/slope.svg new file mode 100644 index 0000000000000..21121eca54997 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/slope.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 321 + + + + + 321.5 + + + + + 322 + + + + + 322.5 + + + + + 323 + + + + + 323.5 + + + + + 324 + + + + + 324.5 + + + + + 325 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/typical.svg new file mode 100644 index 0000000000000..d88b4c6de6e00 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/linear object poll/report/typical.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 321 + + + + + 321.5 + + + + + 322 + + + + + 322.5 + + + + + 323 + + + + + 323.5 + + + + + 324 + + + + + 324.5 + + + + + 325 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/benchmark.json new file mode 100644 index 0000000000000..54e2512c8c648 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:5)","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll","title":"forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/estimates.json new file mode 100644 index 0000000000000..5c7c264ddaf49 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":407.21540868220427,"upper_bound":413.1024245448438},"point_estimate":409.9863199215426,"standard_error":1.5018365262650397},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":405.15533285612025,"upper_bound":410.4446194712133},"point_estimate":406.94386694494847,"standard_error":1.4072415731815824},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.299899156818195,"upper_bound":12.28230413120896},"point_estimate":9.386286773489593,"standard_error":1.2957780219546227},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":403.17224595441525,"upper_bound":408.1106956862875},"point_estimate":405.53930538311795,"standard_error":1.2626785544386823},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":9.940809425788094,"upper_bound":19.862292868014936},"point_estimate":15.090376429538992,"standard_error":2.5797038905104546}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/raw.csv new file mode 100644 index 0000000000000..da4228e62fa8e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,219479.0,ns,508 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,490005.0,ns,1016 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,632677.0,ns,1524 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,867303.0,ns,2032 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,1041075.0,ns,2540 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,1263247.0,ns,3048 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,1727842.0,ns,3556 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,1734684.0,ns,4064 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,1898556.0,ns,4572 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,2185498.0,ns,5080 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,2264008.0,ns,5588 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,2571165.0,ns,6096 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,2764428.0,ns,6604 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,2982856.0,ns,7112 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,3231511.0,ns,7620 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,3362932.0,ns,8128 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,3642324.0,ns,8636 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,3764479.0,ns,9144 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,3897537.0,ns,9652 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,4087059.0,ns,10160 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,4392116.0,ns,10668 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,4511032.0,ns,11176 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,4897278.0,ns,11684 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,5023156.0,ns,12192 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,4916572.0,ns,12700 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,5339146.0,ns,13208 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,5696053.0,ns,13716 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6224955.0,ns,14224 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6065819.0,ns,14732 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6165250.0,ns,15240 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6198465.0,ns,15748 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6713090.0,ns,16256 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6671306.0,ns,16764 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,7148704.0,ns,17272 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6983614.0,ns,17780 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,7539446.0,ns,18288 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,7598666.0,ns,18796 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,8105079.0,ns,19304 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,7986158.0,ns,19812 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,8147416.0,ns,20320 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,8291411.0,ns,20828 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,9243824.0,ns,21336 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,8993046.0,ns,21844 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,9096795.0,ns,22352 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,9680980.0,ns,22860 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,9560330.0,ns,23368 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,9723337.0,ns,23876 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,9935071.0,ns,24384 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,10100134.0,ns,24892 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,10530602.0,ns,25400 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,10272299.0,ns,25908 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,10646221.0,ns,26416 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,10694089.0,ns,26924 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,10962865.0,ns,27432 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,11427811.0,ns,27940 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,11730986.0,ns,28448 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,11899304.0,ns,28956 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,12031628.0,ns,29464 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,12194889.0,ns,29972 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,11981096.0,ns,30480 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,12266472.0,ns,30988 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,12501645.0,ns,31496 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,13105939.0,ns,32004 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,13878527.0,ns,32512 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,13134270.0,ns,33020 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,13567091.0,ns,33528 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,13798959.0,ns,34036 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,13874352.0,ns,34544 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,14124087.0,ns,35052 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,14780992.0,ns,35560 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,14785893.0,ns,36068 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,14858002.0,ns,36576 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,14916772.0,ns,37084 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,15281655.0,ns,37592 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,15436160.0,ns,38100 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,15666380.0,ns,38608 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,17331167.0,ns,39116 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,15225540.0,ns,39624 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,16087429.0,ns,40132 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,15930541.0,ns,40640 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,16322187.0,ns,41148 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,16430317.0,ns,41656 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,17448752.0,ns,42164 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,17262118.0,ns,42672 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,17223388.0,ns,43180 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,17777028.0,ns,43688 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,17694440.0,ns,44196 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,18162526.0,ns,44704 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,18614281.0,ns,45212 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,18520616.0,ns,45720 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,18342579.0,ns,46228 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,19387187.0,ns,46736 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,19089659.0,ns,47244 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,19373786.0,ns,47752 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,20236302.0,ns,48260 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,19129898.0,ns,48768 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,20349288.0,ns,49276 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,19666717.0,ns,49784 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,20627940.0,ns,50292 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,20373321.0,ns,50800 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/sample.json new file mode 100644 index 0000000000000..f44b11a78d77d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[508.0,1016.0,1524.0,2032.0,2540.0,3048.0,3556.0,4064.0,4572.0,5080.0,5588.0,6096.0,6604.0,7112.0,7620.0,8128.0,8636.0,9144.0,9652.0,10160.0,10668.0,11176.0,11684.0,12192.0,12700.0,13208.0,13716.0,14224.0,14732.0,15240.0,15748.0,16256.0,16764.0,17272.0,17780.0,18288.0,18796.0,19304.0,19812.0,20320.0,20828.0,21336.0,21844.0,22352.0,22860.0,23368.0,23876.0,24384.0,24892.0,25400.0,25908.0,26416.0,26924.0,27432.0,27940.0,28448.0,28956.0,29464.0,29972.0,30480.0,30988.0,31496.0,32004.0,32512.0,33020.0,33528.0,34036.0,34544.0,35052.0,35560.0,36068.0,36576.0,37084.0,37592.0,38100.0,38608.0,39116.0,39624.0,40132.0,40640.0,41148.0,41656.0,42164.0,42672.0,43180.0,43688.0,44196.0,44704.0,45212.0,45720.0,46228.0,46736.0,47244.0,47752.0,48260.0,48768.0,49276.0,49784.0,50292.0,50800.0],"times":[219479.0,490005.0,632677.0,867303.0,1041075.0,1263247.0,1727842.0,1734684.0,1898556.0,2185498.0,2264008.0,2571165.0,2764428.0,2982856.0,3231511.0,3362932.0,3642324.0,3764479.0,3897537.0,4087059.0,4392116.0,4511032.0,4897278.0,5023156.0,4916572.0,5339146.0,5696053.0,6224955.0,6065819.0,6165250.0,6198465.0,6713090.0,6671306.0,7148704.0,6983614.0,7539446.0,7598666.0,8105079.0,7986158.0,8147416.0,8291411.0,9243824.0,8993046.0,9096795.0,9680980.0,9560330.0,9723337.0,9935071.0,10100134.0,10530602.0,10272299.0,10646221.0,10694089.0,10962865.0,11427811.0,11730986.0,11899304.0,12031628.0,12194889.0,11981096.0,12266472.0,12501645.0,13105939.0,13878527.0,13134270.0,13567091.0,13798959.0,13874352.0,14124087.0,14780992.0,14785893.0,14858002.0,14916772.0,15281655.0,15436160.0,15666380.0,17331167.0,15225540.0,16087429.0,15930541.0,16322187.0,16430317.0,17448752.0,17262118.0,17223388.0,17777028.0,17694440.0,18162526.0,18614281.0,18520616.0,18342579.0,19387187.0,19089659.0,19373786.0,20236302.0,19129898.0,20349288.0,19666717.0,20627940.0,20373321.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/tukey.json new file mode 100644 index 0000000000000..067c7b8144f62 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/base/tukey.json @@ -0,0 +1 @@ +[364.91330833179995,383.50306549280805,433.0757512554963,451.6655084165044] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/benchmark.json new file mode 100644 index 0000000000000..54e2512c8c648 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:5)","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll","title":"forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/estimates.json new file mode 100644 index 0000000000000..5c7c264ddaf49 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":407.21540868220427,"upper_bound":413.1024245448438},"point_estimate":409.9863199215426,"standard_error":1.5018365262650397},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":405.15533285612025,"upper_bound":410.4446194712133},"point_estimate":406.94386694494847,"standard_error":1.4072415731815824},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.299899156818195,"upper_bound":12.28230413120896},"point_estimate":9.386286773489593,"standard_error":1.2957780219546227},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":403.17224595441525,"upper_bound":408.1106956862875},"point_estimate":405.53930538311795,"standard_error":1.2626785544386823},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":9.940809425788094,"upper_bound":19.862292868014936},"point_estimate":15.090376429538992,"standard_error":2.5797038905104546}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/raw.csv new file mode 100644 index 0000000000000..da4228e62fa8e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,219479.0,ns,508 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,490005.0,ns,1016 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,632677.0,ns,1524 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,867303.0,ns,2032 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,1041075.0,ns,2540 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,1263247.0,ns,3048 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,1727842.0,ns,3556 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,1734684.0,ns,4064 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,1898556.0,ns,4572 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,2185498.0,ns,5080 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,2264008.0,ns,5588 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,2571165.0,ns,6096 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,2764428.0,ns,6604 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,2982856.0,ns,7112 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,3231511.0,ns,7620 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,3362932.0,ns,8128 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,3642324.0,ns,8636 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,3764479.0,ns,9144 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,3897537.0,ns,9652 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,4087059.0,ns,10160 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,4392116.0,ns,10668 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,4511032.0,ns,11176 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,4897278.0,ns,11684 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,5023156.0,ns,12192 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,4916572.0,ns,12700 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,5339146.0,ns,13208 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,5696053.0,ns,13716 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6224955.0,ns,14224 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6065819.0,ns,14732 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6165250.0,ns,15240 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6198465.0,ns,15748 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6713090.0,ns,16256 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6671306.0,ns,16764 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,7148704.0,ns,17272 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,6983614.0,ns,17780 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,7539446.0,ns,18288 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,7598666.0,ns,18796 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,8105079.0,ns,19304 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,7986158.0,ns,19812 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,8147416.0,ns,20320 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,8291411.0,ns,20828 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,9243824.0,ns,21336 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,8993046.0,ns,21844 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,9096795.0,ns,22352 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,9680980.0,ns,22860 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,9560330.0,ns,23368 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,9723337.0,ns,23876 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,9935071.0,ns,24384 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,10100134.0,ns,24892 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,10530602.0,ns,25400 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,10272299.0,ns,25908 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,10646221.0,ns,26416 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,10694089.0,ns,26924 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,10962865.0,ns,27432 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,11427811.0,ns,27940 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,11730986.0,ns,28448 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,11899304.0,ns,28956 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,12031628.0,ns,29464 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,12194889.0,ns,29972 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,11981096.0,ns,30480 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,12266472.0,ns,30988 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,12501645.0,ns,31496 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,13105939.0,ns,32004 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,13878527.0,ns,32512 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,13134270.0,ns,33020 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,13567091.0,ns,33528 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,13798959.0,ns,34036 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,13874352.0,ns,34544 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,14124087.0,ns,35052 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,14780992.0,ns,35560 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,14785893.0,ns,36068 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,14858002.0,ns,36576 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,14916772.0,ns,37084 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,15281655.0,ns,37592 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,15436160.0,ns,38100 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,15666380.0,ns,38608 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,17331167.0,ns,39116 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,15225540.0,ns,39624 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,16087429.0,ns,40132 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,15930541.0,ns,40640 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,16322187.0,ns,41148 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,16430317.0,ns,41656 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,17448752.0,ns,42164 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,17262118.0,ns,42672 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,17223388.0,ns,43180 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,17777028.0,ns,43688 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,17694440.0,ns,44196 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,18162526.0,ns,44704 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,18614281.0,ns,45212 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,18520616.0,ns,45720 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,18342579.0,ns,46228 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,19387187.0,ns,46736 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,19089659.0,ns,47244 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,19373786.0,ns,47752 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,20236302.0,ns,48260 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,19129898.0,ns,48768 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,20349288.0,ns,49276 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,19666717.0,ns,49784 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,20627940.0,ns,50292 +forward msg from pull (nb_writter:5 nb_readder:5),mutex object poll,,,,20373321.0,ns,50800 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/sample.json new file mode 100644 index 0000000000000..f44b11a78d77d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[508.0,1016.0,1524.0,2032.0,2540.0,3048.0,3556.0,4064.0,4572.0,5080.0,5588.0,6096.0,6604.0,7112.0,7620.0,8128.0,8636.0,9144.0,9652.0,10160.0,10668.0,11176.0,11684.0,12192.0,12700.0,13208.0,13716.0,14224.0,14732.0,15240.0,15748.0,16256.0,16764.0,17272.0,17780.0,18288.0,18796.0,19304.0,19812.0,20320.0,20828.0,21336.0,21844.0,22352.0,22860.0,23368.0,23876.0,24384.0,24892.0,25400.0,25908.0,26416.0,26924.0,27432.0,27940.0,28448.0,28956.0,29464.0,29972.0,30480.0,30988.0,31496.0,32004.0,32512.0,33020.0,33528.0,34036.0,34544.0,35052.0,35560.0,36068.0,36576.0,37084.0,37592.0,38100.0,38608.0,39116.0,39624.0,40132.0,40640.0,41148.0,41656.0,42164.0,42672.0,43180.0,43688.0,44196.0,44704.0,45212.0,45720.0,46228.0,46736.0,47244.0,47752.0,48260.0,48768.0,49276.0,49784.0,50292.0,50800.0],"times":[219479.0,490005.0,632677.0,867303.0,1041075.0,1263247.0,1727842.0,1734684.0,1898556.0,2185498.0,2264008.0,2571165.0,2764428.0,2982856.0,3231511.0,3362932.0,3642324.0,3764479.0,3897537.0,4087059.0,4392116.0,4511032.0,4897278.0,5023156.0,4916572.0,5339146.0,5696053.0,6224955.0,6065819.0,6165250.0,6198465.0,6713090.0,6671306.0,7148704.0,6983614.0,7539446.0,7598666.0,8105079.0,7986158.0,8147416.0,8291411.0,9243824.0,8993046.0,9096795.0,9680980.0,9560330.0,9723337.0,9935071.0,10100134.0,10530602.0,10272299.0,10646221.0,10694089.0,10962865.0,11427811.0,11730986.0,11899304.0,12031628.0,12194889.0,11981096.0,12266472.0,12501645.0,13105939.0,13878527.0,13134270.0,13567091.0,13798959.0,13874352.0,14124087.0,14780992.0,14785893.0,14858002.0,14916772.0,15281655.0,15436160.0,15666380.0,17331167.0,15225540.0,16087429.0,15930541.0,16322187.0,16430317.0,17448752.0,17262118.0,17223388.0,17777028.0,17694440.0,18162526.0,18614281.0,18520616.0,18342579.0,19387187.0,19089659.0,19373786.0,20236302.0,19129898.0,20349288.0,19666717.0,20627940.0,20373321.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/tukey.json new file mode 100644 index 0000000000000..067c7b8144f62 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/new/tukey.json @@ -0,0 +1 @@ +[364.91330833179995,383.50306549280805,433.0757512554963,451.6655084165044] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/MAD.svg new file mode 100644 index 0000000000000..04f034853a434 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + 12 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/SD.svg new file mode 100644 index 0000000000000..c242421211e16 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/SD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 0.16 + + + + + 0.18 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/index.html new file mode 100644 index 0000000000000..fcf84a8ae0a47 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope403.17 ns405.54 ns408.11 ns
0.91845600.92264530.9177056
Mean407.22 ns409.99 ns413.10 ns
Std. Dev.9.9408 ns15.090 ns19.862 ns
Median405.16 ns406.94 ns410.44 ns
MAD7.2999 ns9.3863 ns12.282 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/mean.svg new file mode 100644 index 0000000000000..f2e1a532989d9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 407 + + + + + 408 + + + + + 409 + + + + + 410 + + + + + 411 + + + + + 412 + + + + + 413 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/median.svg new file mode 100644 index 0000000000000..49a7b6f86ccde --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/median.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 405 + + + + + 406 + + + + + 407 + + + + + 408 + + + + + 409 + + + + + 410 + + + + + 411 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/pdf.svg new file mode 100644 index 0000000000000..dca077db4dc5c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/pdf.svg @@ -0,0 +1,420 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 380 + + + + + 400 + + + + + 420 + + + + + 440 + + + + + 460 + + + + + 480 + + + + + 500 + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..6f9dd77d37cfe --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/pdf_small.svg @@ -0,0 +1,219 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 380 + + + + + 400 + + + + + 420 + + + + + 440 + + + + + 460 + + + + + 480 + + + + + 500 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/regression.svg new file mode 100644 index 0000000000000..1d45765ecbddc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/regression.svg @@ -0,0 +1,382 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/regression_small.svg new file mode 100644 index 0000000000000..b7cc4342c717e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/regression_small.svg @@ -0,0 +1,360 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/slope.svg new file mode 100644 index 0000000000000..817bc32a124d2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 403 + + + + + 404 + + + + + 405 + + + + + 406 + + + + + 407 + + + + + 408 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/typical.svg new file mode 100644 index 0000000000000..a81096d51cf2f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/mutex object poll/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 403 + + + + + 404 + + + + + 405 + + + + + 406 + + + + + 407 + + + + + 408 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/benchmark.json new file mode 100644 index 0000000000000..6da06c3c0cf89 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:5)","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:5)/none object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_5)/none object poll","title":"forward msg from pull (nb_writter:5 nb_readder:5)/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/estimates.json new file mode 100644 index 0000000000000..c7905696003b8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":658.4143242448287,"upper_bound":787.0286193231149},"point_estimate":722.3479160817762,"standard_error":32.86942487480999},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":434.3585749050277,"upper_bound":893.4900662251656},"point_estimate":516.8073512442304,"standard_error":132.53932126681494},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":65.33749283503406,"upper_bound":523.1706836993033},"point_estimate":190.41775648263152,"standard_error":152.9724706050264},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":850.3886334708263,"upper_bound":988.7891130661444},"point_estimate":926.9984689039231,"standard_error":35.41868024582895},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":309.2079275209825,"upper_bound":345.23190726616383},"point_estimate":330.4966523219554,"standard_error":9.135306619420055}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/raw.csv new file mode 100644 index 0000000000000..65ea2b087db9a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,196877.0,ns,151 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,349060.0,ns,302 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,498162.0,ns,453 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,671631.0,ns,604 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,700406.0,ns,755 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,809502.0,ns,906 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,811071.0,ns,1057 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,741783.0,ns,1208 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,801256.0,ns,1359 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,751939.0,ns,1510 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,837090.0,ns,1661 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,871065.0,ns,1812 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,832484.0,ns,1963 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,913742.0,ns,2114 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,932879.0,ns,2265 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1099732.0,ns,2416 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1023104.0,ns,2567 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1148609.0,ns,2718 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1226106.0,ns,2869 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1216765.0,ns,3020 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1336582.0,ns,3171 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1415858.0,ns,3322 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1405082.0,ns,3473 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1580458.0,ns,3624 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1676770.0,ns,3775 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1596104.0,ns,3926 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1686666.0,ns,4077 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1640385.0,ns,4228 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1720995.0,ns,4379 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1722542.0,ns,4530 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2026233.0,ns,4681 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1882577.0,ns,4832 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1949950.0,ns,4983 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1997385.0,ns,5134 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2040418.0,ns,5285 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2342615.0,ns,5436 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2180654.0,ns,5587 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2301932.0,ns,5738 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2358583.0,ns,5889 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2457927.0,ns,6040 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2497156.0,ns,6191 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2706347.0,ns,6342 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2908103.0,ns,6493 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2891612.0,ns,6644 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2702775.0,ns,6795 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3027441.0,ns,6946 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3033928.0,ns,7097 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3838883.0,ns,7248 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,6158879.0,ns,7399 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,5712149.0,ns,7550 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,6136142.0,ns,7701 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,8110467.0,ns,7852 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,7725232.0,ns,8003 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,8048728.0,ns,8154 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,5441390.0,ns,8305 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3575505.0,ns,8456 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3548208.0,ns,8607 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3633442.0,ns,8758 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3548874.0,ns,8909 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3790204.0,ns,9060 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,4090906.0,ns,9211 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3913715.0,ns,9362 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3978483.0,ns,9513 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3757009.0,ns,9664 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,4001051.0,ns,9815 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,4164425.0,ns,9966 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,4145413.0,ns,10117 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,7653401.0,ns,10268 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,10880141.0,ns,10419 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,11324797.0,ns,10570 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,11034311.0,ns,10721 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,11746830.0,ns,10872 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,12412455.0,ns,11023 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,12048163.0,ns,11174 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,10560416.0,ns,11325 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,12016948.0,ns,11476 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,13090513.0,ns,11627 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,12935055.0,ns,11778 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,11726588.0,ns,11929 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,13401244.0,ns,12080 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,12433681.0,ns,12231 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,13897511.0,ns,12382 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,13561375.0,ns,12533 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,14424784.0,ns,12684 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,14970629.0,ns,12835 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,14819796.0,ns,12986 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,15028153.0,ns,13137 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,15751589.0,ns,13288 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,15693714.0,ns,13439 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,13624450.0,ns,13590 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,15877713.0,ns,13741 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,15821758.0,ns,13892 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,16813112.0,ns,14043 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,16076628.0,ns,14194 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,16570359.0,ns,14345 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,16203396.0,ns,14496 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,17124879.0,ns,14647 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,17925475.0,ns,14798 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,17717984.0,ns,14949 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,17819374.0,ns,15100 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/sample.json new file mode 100644 index 0000000000000..306d4fe602800 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[151.0,302.0,453.0,604.0,755.0,906.0,1057.0,1208.0,1359.0,1510.0,1661.0,1812.0,1963.0,2114.0,2265.0,2416.0,2567.0,2718.0,2869.0,3020.0,3171.0,3322.0,3473.0,3624.0,3775.0,3926.0,4077.0,4228.0,4379.0,4530.0,4681.0,4832.0,4983.0,5134.0,5285.0,5436.0,5587.0,5738.0,5889.0,6040.0,6191.0,6342.0,6493.0,6644.0,6795.0,6946.0,7097.0,7248.0,7399.0,7550.0,7701.0,7852.0,8003.0,8154.0,8305.0,8456.0,8607.0,8758.0,8909.0,9060.0,9211.0,9362.0,9513.0,9664.0,9815.0,9966.0,10117.0,10268.0,10419.0,10570.0,10721.0,10872.0,11023.0,11174.0,11325.0,11476.0,11627.0,11778.0,11929.0,12080.0,12231.0,12382.0,12533.0,12684.0,12835.0,12986.0,13137.0,13288.0,13439.0,13590.0,13741.0,13892.0,14043.0,14194.0,14345.0,14496.0,14647.0,14798.0,14949.0,15100.0],"times":[196877.0,349060.0,498162.0,671631.0,700406.0,809502.0,811071.0,741783.0,801256.0,751939.0,837090.0,871065.0,832484.0,913742.0,932879.0,1099732.0,1023104.0,1148609.0,1226106.0,1216765.0,1336582.0,1415858.0,1405082.0,1580458.0,1676770.0,1596104.0,1686666.0,1640385.0,1720995.0,1722542.0,2026233.0,1882577.0,1949950.0,1997385.0,2040418.0,2342615.0,2180654.0,2301932.0,2358583.0,2457927.0,2497156.0,2706347.0,2908103.0,2891612.0,2702775.0,3027441.0,3033928.0,3838883.0,6158879.0,5712149.0,6136142.0,8110467.0,7725232.0,8048728.0,5441390.0,3575505.0,3548208.0,3633442.0,3548874.0,3790204.0,4090906.0,3913715.0,3978483.0,3757009.0,4001051.0,4164425.0,4145413.0,7653401.0,10880141.0,11324797.0,11034311.0,11746830.0,12412455.0,12048163.0,10560416.0,12016948.0,13090513.0,12935055.0,11726588.0,13401244.0,12433681.0,13897511.0,13561375.0,14424784.0,14970629.0,14819796.0,15028153.0,15751589.0,15693714.0,13624450.0,15877713.0,15821758.0,16813112.0,16076628.0,16570359.0,16203396.0,17124879.0,17925475.0,17717984.0,17819374.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/tukey.json new file mode 100644 index 0000000000000..06c3a09e38fa5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/base/tukey.json @@ -0,0 +1 @@ +[-1589.8381934413187,-586.3614831621466,2089.5764109156453,3093.0531211948173] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/benchmark.json new file mode 100644 index 0000000000000..6da06c3c0cf89 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:5)","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:5)/none object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_5)/none object poll","title":"forward msg from pull (nb_writter:5 nb_readder:5)/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/estimates.json new file mode 100644 index 0000000000000..c7905696003b8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":658.4143242448287,"upper_bound":787.0286193231149},"point_estimate":722.3479160817762,"standard_error":32.86942487480999},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":434.3585749050277,"upper_bound":893.4900662251656},"point_estimate":516.8073512442304,"standard_error":132.53932126681494},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":65.33749283503406,"upper_bound":523.1706836993033},"point_estimate":190.41775648263152,"standard_error":152.9724706050264},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":850.3886334708263,"upper_bound":988.7891130661444},"point_estimate":926.9984689039231,"standard_error":35.41868024582895},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":309.2079275209825,"upper_bound":345.23190726616383},"point_estimate":330.4966523219554,"standard_error":9.135306619420055}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/raw.csv new file mode 100644 index 0000000000000..65ea2b087db9a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,196877.0,ns,151 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,349060.0,ns,302 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,498162.0,ns,453 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,671631.0,ns,604 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,700406.0,ns,755 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,809502.0,ns,906 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,811071.0,ns,1057 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,741783.0,ns,1208 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,801256.0,ns,1359 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,751939.0,ns,1510 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,837090.0,ns,1661 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,871065.0,ns,1812 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,832484.0,ns,1963 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,913742.0,ns,2114 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,932879.0,ns,2265 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1099732.0,ns,2416 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1023104.0,ns,2567 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1148609.0,ns,2718 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1226106.0,ns,2869 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1216765.0,ns,3020 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1336582.0,ns,3171 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1415858.0,ns,3322 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1405082.0,ns,3473 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1580458.0,ns,3624 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1676770.0,ns,3775 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1596104.0,ns,3926 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1686666.0,ns,4077 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1640385.0,ns,4228 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1720995.0,ns,4379 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1722542.0,ns,4530 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2026233.0,ns,4681 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1882577.0,ns,4832 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1949950.0,ns,4983 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,1997385.0,ns,5134 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2040418.0,ns,5285 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2342615.0,ns,5436 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2180654.0,ns,5587 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2301932.0,ns,5738 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2358583.0,ns,5889 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2457927.0,ns,6040 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2497156.0,ns,6191 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2706347.0,ns,6342 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2908103.0,ns,6493 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2891612.0,ns,6644 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,2702775.0,ns,6795 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3027441.0,ns,6946 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3033928.0,ns,7097 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3838883.0,ns,7248 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,6158879.0,ns,7399 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,5712149.0,ns,7550 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,6136142.0,ns,7701 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,8110467.0,ns,7852 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,7725232.0,ns,8003 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,8048728.0,ns,8154 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,5441390.0,ns,8305 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3575505.0,ns,8456 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3548208.0,ns,8607 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3633442.0,ns,8758 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3548874.0,ns,8909 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3790204.0,ns,9060 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,4090906.0,ns,9211 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3913715.0,ns,9362 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3978483.0,ns,9513 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,3757009.0,ns,9664 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,4001051.0,ns,9815 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,4164425.0,ns,9966 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,4145413.0,ns,10117 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,7653401.0,ns,10268 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,10880141.0,ns,10419 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,11324797.0,ns,10570 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,11034311.0,ns,10721 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,11746830.0,ns,10872 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,12412455.0,ns,11023 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,12048163.0,ns,11174 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,10560416.0,ns,11325 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,12016948.0,ns,11476 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,13090513.0,ns,11627 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,12935055.0,ns,11778 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,11726588.0,ns,11929 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,13401244.0,ns,12080 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,12433681.0,ns,12231 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,13897511.0,ns,12382 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,13561375.0,ns,12533 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,14424784.0,ns,12684 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,14970629.0,ns,12835 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,14819796.0,ns,12986 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,15028153.0,ns,13137 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,15751589.0,ns,13288 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,15693714.0,ns,13439 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,13624450.0,ns,13590 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,15877713.0,ns,13741 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,15821758.0,ns,13892 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,16813112.0,ns,14043 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,16076628.0,ns,14194 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,16570359.0,ns,14345 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,16203396.0,ns,14496 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,17124879.0,ns,14647 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,17925475.0,ns,14798 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,17717984.0,ns,14949 +forward msg from pull (nb_writter:5 nb_readder:5),none object poll,,,,17819374.0,ns,15100 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/sample.json new file mode 100644 index 0000000000000..306d4fe602800 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[151.0,302.0,453.0,604.0,755.0,906.0,1057.0,1208.0,1359.0,1510.0,1661.0,1812.0,1963.0,2114.0,2265.0,2416.0,2567.0,2718.0,2869.0,3020.0,3171.0,3322.0,3473.0,3624.0,3775.0,3926.0,4077.0,4228.0,4379.0,4530.0,4681.0,4832.0,4983.0,5134.0,5285.0,5436.0,5587.0,5738.0,5889.0,6040.0,6191.0,6342.0,6493.0,6644.0,6795.0,6946.0,7097.0,7248.0,7399.0,7550.0,7701.0,7852.0,8003.0,8154.0,8305.0,8456.0,8607.0,8758.0,8909.0,9060.0,9211.0,9362.0,9513.0,9664.0,9815.0,9966.0,10117.0,10268.0,10419.0,10570.0,10721.0,10872.0,11023.0,11174.0,11325.0,11476.0,11627.0,11778.0,11929.0,12080.0,12231.0,12382.0,12533.0,12684.0,12835.0,12986.0,13137.0,13288.0,13439.0,13590.0,13741.0,13892.0,14043.0,14194.0,14345.0,14496.0,14647.0,14798.0,14949.0,15100.0],"times":[196877.0,349060.0,498162.0,671631.0,700406.0,809502.0,811071.0,741783.0,801256.0,751939.0,837090.0,871065.0,832484.0,913742.0,932879.0,1099732.0,1023104.0,1148609.0,1226106.0,1216765.0,1336582.0,1415858.0,1405082.0,1580458.0,1676770.0,1596104.0,1686666.0,1640385.0,1720995.0,1722542.0,2026233.0,1882577.0,1949950.0,1997385.0,2040418.0,2342615.0,2180654.0,2301932.0,2358583.0,2457927.0,2497156.0,2706347.0,2908103.0,2891612.0,2702775.0,3027441.0,3033928.0,3838883.0,6158879.0,5712149.0,6136142.0,8110467.0,7725232.0,8048728.0,5441390.0,3575505.0,3548208.0,3633442.0,3548874.0,3790204.0,4090906.0,3913715.0,3978483.0,3757009.0,4001051.0,4164425.0,4145413.0,7653401.0,10880141.0,11324797.0,11034311.0,11746830.0,12412455.0,12048163.0,10560416.0,12016948.0,13090513.0,12935055.0,11726588.0,13401244.0,12433681.0,13897511.0,13561375.0,14424784.0,14970629.0,14819796.0,15028153.0,15751589.0,15693714.0,13624450.0,15877713.0,15821758.0,16813112.0,16076628.0,16570359.0,16203396.0,17124879.0,17925475.0,17717984.0,17819374.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/tukey.json new file mode 100644 index 0000000000000..06c3a09e38fa5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/new/tukey.json @@ -0,0 +1 @@ +[-1589.8381934413187,-586.3614831621466,2089.5764109156453,3093.0531211948173] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/MAD.svg new file mode 100644 index 0000000000000..5fcbb9dfe2790 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/MAD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + 0.003 + + + + + 0.0035 + + + + + 0.004 + + + + + 0.0045 + + + + + 0.005 + + + + + 100 + + + + + 200 + + + + + 300 + + + + + 400 + + + + + 500 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/none object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/SD.svg new file mode 100644 index 0000000000000..d18eb0e26dab3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/SD.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 0.04 + + + + + 0.045 + + + + + 0.05 + + + + + 310 + + + + + 315 + + + + + 320 + + + + + 325 + + + + + 330 + + + + + 335 + + + + + 340 + + + + + 345 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/none object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/index.html new file mode 100644 index 0000000000000..e2cd733ed8fea --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/none object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:5 nb_readder:5)/none object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope850.39 ns927.00 ns988.79 ns
0.14594310.15364550.1485454
Mean658.41 ns722.35 ns787.03 ns
Std. Dev.309.21 ns330.50 ns345.23 ns
Median434.36 ns516.81 ns893.49 ns
MAD65.337 ns190.42 ns523.17 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/mean.svg new file mode 100644 index 0000000000000..54854af25f543 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/mean.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 660 + + + + + 680 + + + + + 700 + + + + + 720 + + + + + 740 + + + + + 760 + + + + + 780 + + + + + 800 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/none object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/median.svg new file mode 100644 index 0000000000000..4439c1f091a89 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/median.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 400 + + + + + 500 + + + + + 600 + + + + + 700 + + + + + 800 + + + + + 900 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/none object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/pdf.svg new file mode 100644 index 0000000000000..0e1b7d71263d4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/pdf.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/none object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..9269f0495c959 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/pdf_small.svg @@ -0,0 +1,234 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/regression.svg new file mode 100644 index 0000000000000..6c314de360dcb --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/regression.svg @@ -0,0 +1,460 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/none object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/regression_small.svg new file mode 100644 index 0000000000000..ad9b06596cb12 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/regression_small.svg @@ -0,0 +1,438 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/slope.svg new file mode 100644 index 0000000000000..c2e7de839efd7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/slope.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 840 + + + + + 860 + + + + + 880 + + + + + 900 + + + + + 920 + + + + + 940 + + + + + 960 + + + + + 980 + + + + + 1000 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/none object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/typical.svg new file mode 100644 index 0000000000000..3bf40354ba903 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/none object poll/report/typical.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 840 + + + + + 860 + + + + + 880 + + + + + 900 + + + + + 920 + + + + + 940 + + + + + 960 + + + + + 980 + + + + + 1000 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/none object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/report/index.html new file mode 100644 index 0000000000000..a441b489f77a0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/report/index.html @@ -0,0 +1,185 @@ + + + + + + forward msg from pull (nb_writter:5 nb_readder:5) Summary - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:5 nb_readder:5)

+

Violin Plot

+ + Violin Plot + +

This chart shows the relationship between function/parameter and iteration time. The thickness of the shaded + region indicates the probability that a measurement of the given function/parameter would take a particular + length of time.

+
+ +

forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab'

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:5 nb_readder:5)/none object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/report/violin.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/report/violin.svg new file mode 100644 index 0000000000000..70e6a2f5f9647 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/report/violin.svg @@ -0,0 +1,569 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/none object poll + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/mutex object poll + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/linear object poll + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/crate 'sharded-slab' + + + + + + + + + + + + + -0.5 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.5 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 2.5 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 3.5 + + + + + + + + + Input + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:5): Violin plot + + + + + PDF + + + PDF + + + + + + + + + + gnuplot_plot_2 + + + + + + + gnuplot_plot_3 + + + + + + + gnuplot_plot_4 + + + + + + + gnuplot_plot_5 + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/benchmark.json new file mode 100644 index 0000000000000..6745af22dfcde --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:5)","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll","title":"forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/estimates.json new file mode 100644 index 0000000000000..f83338c705696 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":430.85825985423827,"upper_bound":552.6240963230578},"point_estimate":483.80882991458253,"standard_error":31.489386339972214},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":383.646045557442,"upper_bound":404.86890343757125},"point_estimate":394.3377649853801,"standard_error":5.681346395958857},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":30.423997399024845,"upper_bound":62.98598100498108},"point_estimate":44.18842591465693,"standard_error":7.999173154257495},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":370.7211279944438,"upper_bound":385.03975715446876},"point_estimate":377.39970883272537,"standard_error":3.6325991439506105},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":133.95970240802257,"upper_bound":477.20176630770493},"point_estimate":315.4493583511942,"standard_error":93.46688783297049}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/raw.csv new file mode 100644 index 0000000000000..27521c94a7549 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,167207.0,ns,304 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,1736958.0,ns,608 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,529169.0,ns,912 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,1948825.0,ns,1216 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2157557.0,ns,1520 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2213519.0,ns,1824 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2345618.0,ns,2128 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,965315.0,ns,2432 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2402788.0,ns,2736 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,1572488.0,ns,3040 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2404953.0,ns,3344 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,1402556.0,ns,3648 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2569468.0,ns,3952 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3011567.0,ns,4256 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2687531.0,ns,4560 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2315281.0,ns,4864 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3065009.0,ns,5168 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2481649.0,ns,5472 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3311319.0,ns,5776 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3016241.0,ns,6080 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2590496.0,ns,6384 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3133969.0,ns,6688 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3661712.0,ns,6992 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3142913.0,ns,7296 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2834242.0,ns,7600 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5004974.0,ns,7904 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3318523.0,ns,8208 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3353735.0,ns,8512 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3274783.0,ns,8816 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4925187.0,ns,9120 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4482182.0,ns,9424 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4407420.0,ns,9728 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4824788.0,ns,10032 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4057998.0,ns,10336 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5353227.0,ns,10640 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4874082.0,ns,10944 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4150213.0,ns,11248 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4316236.0,ns,11552 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4593040.0,ns,11856 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5211014.0,ns,12160 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4556108.0,ns,12464 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5273830.0,ns,12768 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5521621.0,ns,13072 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5403347.0,ns,13376 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4957305.0,ns,13680 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5834332.0,ns,13984 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5514087.0,ns,14288 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,6200091.0,ns,14592 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,6224580.0,ns,14896 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,6121572.0,ns,15200 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5663413.0,ns,15504 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,6537204.0,ns,15808 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5834284.0,ns,16112 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7079762.0,ns,16416 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7444764.0,ns,16720 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,6150025.0,ns,17024 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7113156.0,ns,17328 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7092362.0,ns,17632 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7094055.0,ns,17936 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7011889.0,ns,18240 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8309176.0,ns,18544 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7215382.0,ns,18848 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7044195.0,ns,19152 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7791199.0,ns,19456 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7119411.0,ns,19760 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7806837.0,ns,20064 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7736713.0,ns,20368 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8186428.0,ns,20672 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8397991.0,ns,20976 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7721092.0,ns,21280 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8137680.0,ns,21584 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7244230.0,ns,21888 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8272237.0,ns,22192 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7725322.0,ns,22496 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8973489.0,ns,22800 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8649189.0,ns,23104 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8882937.0,ns,23408 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8526159.0,ns,23712 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7903917.0,ns,24016 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8928762.0,ns,24320 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9718470.0,ns,24624 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9769245.0,ns,24928 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8855740.0,ns,25232 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9642869.0,ns,25536 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9491737.0,ns,25840 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9808859.0,ns,26144 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8988551.0,ns,26448 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9525780.0,ns,26752 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10049589.0,ns,27056 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9130090.0,ns,27360 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10638715.0,ns,27664 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9333409.0,ns,27968 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10792234.0,ns,28272 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10608885.0,ns,28576 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10864878.0,ns,28880 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10241257.0,ns,29184 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10804128.0,ns,29488 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9857364.0,ns,29792 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,11007447.0,ns,30096 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10460871.0,ns,30400 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/sample.json new file mode 100644 index 0000000000000..c625e60886a08 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[304.0,608.0,912.0,1216.0,1520.0,1824.0,2128.0,2432.0,2736.0,3040.0,3344.0,3648.0,3952.0,4256.0,4560.0,4864.0,5168.0,5472.0,5776.0,6080.0,6384.0,6688.0,6992.0,7296.0,7600.0,7904.0,8208.0,8512.0,8816.0,9120.0,9424.0,9728.0,10032.0,10336.0,10640.0,10944.0,11248.0,11552.0,11856.0,12160.0,12464.0,12768.0,13072.0,13376.0,13680.0,13984.0,14288.0,14592.0,14896.0,15200.0,15504.0,15808.0,16112.0,16416.0,16720.0,17024.0,17328.0,17632.0,17936.0,18240.0,18544.0,18848.0,19152.0,19456.0,19760.0,20064.0,20368.0,20672.0,20976.0,21280.0,21584.0,21888.0,22192.0,22496.0,22800.0,23104.0,23408.0,23712.0,24016.0,24320.0,24624.0,24928.0,25232.0,25536.0,25840.0,26144.0,26448.0,26752.0,27056.0,27360.0,27664.0,27968.0,28272.0,28576.0,28880.0,29184.0,29488.0,29792.0,30096.0,30400.0],"times":[167207.0,1736958.0,529169.0,1948825.0,2157557.0,2213519.0,2345618.0,965315.0,2402788.0,1572488.0,2404953.0,1402556.0,2569468.0,3011567.0,2687531.0,2315281.0,3065009.0,2481649.0,3311319.0,3016241.0,2590496.0,3133969.0,3661712.0,3142913.0,2834242.0,5004974.0,3318523.0,3353735.0,3274783.0,4925187.0,4482182.0,4407420.0,4824788.0,4057998.0,5353227.0,4874082.0,4150213.0,4316236.0,4593040.0,5211014.0,4556108.0,5273830.0,5521621.0,5403347.0,4957305.0,5834332.0,5514087.0,6200091.0,6224580.0,6121572.0,5663413.0,6537204.0,5834284.0,7079762.0,7444764.0,6150025.0,7113156.0,7092362.0,7094055.0,7011889.0,8309176.0,7215382.0,7044195.0,7791199.0,7119411.0,7806837.0,7736713.0,8186428.0,8397991.0,7721092.0,8137680.0,7244230.0,8272237.0,7725322.0,8973489.0,8649189.0,8882937.0,8526159.0,7903917.0,8928762.0,9718470.0,9769245.0,8855740.0,9642869.0,9491737.0,9808859.0,8988551.0,9525780.0,10049589.0,9130090.0,10638715.0,9333409.0,10792234.0,10608885.0,10864878.0,10241257.0,10804128.0,9857364.0,11007447.0,10460871.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/tukey.json new file mode 100644 index 0000000000000..8de9b45d3b931 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/base/tukey.json @@ -0,0 +1 @@ +[123.19274563310864,246.93739053412492,576.9231102701683,700.6677551711846] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/benchmark.json new file mode 100644 index 0000000000000..6745af22dfcde --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"forward msg from pull (nb_writter:5 nb_readder:5)","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll","directory_name":"forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll","title":"forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/estimates.json new file mode 100644 index 0000000000000..f83338c705696 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":430.85825985423827,"upper_bound":552.6240963230578},"point_estimate":483.80882991458253,"standard_error":31.489386339972214},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":383.646045557442,"upper_bound":404.86890343757125},"point_estimate":394.3377649853801,"standard_error":5.681346395958857},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":30.423997399024845,"upper_bound":62.98598100498108},"point_estimate":44.18842591465693,"standard_error":7.999173154257495},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":370.7211279944438,"upper_bound":385.03975715446876},"point_estimate":377.39970883272537,"standard_error":3.6325991439506105},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":133.95970240802257,"upper_bound":477.20176630770493},"point_estimate":315.4493583511942,"standard_error":93.46688783297049}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/raw.csv new file mode 100644 index 0000000000000..27521c94a7549 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,167207.0,ns,304 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,1736958.0,ns,608 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,529169.0,ns,912 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,1948825.0,ns,1216 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2157557.0,ns,1520 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2213519.0,ns,1824 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2345618.0,ns,2128 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,965315.0,ns,2432 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2402788.0,ns,2736 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,1572488.0,ns,3040 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2404953.0,ns,3344 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,1402556.0,ns,3648 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2569468.0,ns,3952 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3011567.0,ns,4256 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2687531.0,ns,4560 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2315281.0,ns,4864 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3065009.0,ns,5168 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2481649.0,ns,5472 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3311319.0,ns,5776 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3016241.0,ns,6080 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2590496.0,ns,6384 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3133969.0,ns,6688 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3661712.0,ns,6992 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3142913.0,ns,7296 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,2834242.0,ns,7600 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5004974.0,ns,7904 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3318523.0,ns,8208 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3353735.0,ns,8512 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,3274783.0,ns,8816 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4925187.0,ns,9120 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4482182.0,ns,9424 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4407420.0,ns,9728 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4824788.0,ns,10032 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4057998.0,ns,10336 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5353227.0,ns,10640 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4874082.0,ns,10944 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4150213.0,ns,11248 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4316236.0,ns,11552 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4593040.0,ns,11856 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5211014.0,ns,12160 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4556108.0,ns,12464 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5273830.0,ns,12768 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5521621.0,ns,13072 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5403347.0,ns,13376 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,4957305.0,ns,13680 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5834332.0,ns,13984 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5514087.0,ns,14288 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,6200091.0,ns,14592 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,6224580.0,ns,14896 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,6121572.0,ns,15200 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5663413.0,ns,15504 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,6537204.0,ns,15808 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,5834284.0,ns,16112 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7079762.0,ns,16416 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7444764.0,ns,16720 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,6150025.0,ns,17024 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7113156.0,ns,17328 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7092362.0,ns,17632 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7094055.0,ns,17936 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7011889.0,ns,18240 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8309176.0,ns,18544 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7215382.0,ns,18848 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7044195.0,ns,19152 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7791199.0,ns,19456 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7119411.0,ns,19760 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7806837.0,ns,20064 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7736713.0,ns,20368 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8186428.0,ns,20672 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8397991.0,ns,20976 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7721092.0,ns,21280 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8137680.0,ns,21584 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7244230.0,ns,21888 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8272237.0,ns,22192 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7725322.0,ns,22496 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8973489.0,ns,22800 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8649189.0,ns,23104 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8882937.0,ns,23408 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8526159.0,ns,23712 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,7903917.0,ns,24016 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8928762.0,ns,24320 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9718470.0,ns,24624 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9769245.0,ns,24928 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8855740.0,ns,25232 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9642869.0,ns,25536 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9491737.0,ns,25840 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9808859.0,ns,26144 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,8988551.0,ns,26448 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9525780.0,ns,26752 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10049589.0,ns,27056 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9130090.0,ns,27360 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10638715.0,ns,27664 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9333409.0,ns,27968 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10792234.0,ns,28272 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10608885.0,ns,28576 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10864878.0,ns,28880 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10241257.0,ns,29184 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10804128.0,ns,29488 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,9857364.0,ns,29792 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,11007447.0,ns,30096 +forward msg from pull (nb_writter:5 nb_readder:5),spin_lock object poll,,,,10460871.0,ns,30400 diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/sample.json new file mode 100644 index 0000000000000..c625e60886a08 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[304.0,608.0,912.0,1216.0,1520.0,1824.0,2128.0,2432.0,2736.0,3040.0,3344.0,3648.0,3952.0,4256.0,4560.0,4864.0,5168.0,5472.0,5776.0,6080.0,6384.0,6688.0,6992.0,7296.0,7600.0,7904.0,8208.0,8512.0,8816.0,9120.0,9424.0,9728.0,10032.0,10336.0,10640.0,10944.0,11248.0,11552.0,11856.0,12160.0,12464.0,12768.0,13072.0,13376.0,13680.0,13984.0,14288.0,14592.0,14896.0,15200.0,15504.0,15808.0,16112.0,16416.0,16720.0,17024.0,17328.0,17632.0,17936.0,18240.0,18544.0,18848.0,19152.0,19456.0,19760.0,20064.0,20368.0,20672.0,20976.0,21280.0,21584.0,21888.0,22192.0,22496.0,22800.0,23104.0,23408.0,23712.0,24016.0,24320.0,24624.0,24928.0,25232.0,25536.0,25840.0,26144.0,26448.0,26752.0,27056.0,27360.0,27664.0,27968.0,28272.0,28576.0,28880.0,29184.0,29488.0,29792.0,30096.0,30400.0],"times":[167207.0,1736958.0,529169.0,1948825.0,2157557.0,2213519.0,2345618.0,965315.0,2402788.0,1572488.0,2404953.0,1402556.0,2569468.0,3011567.0,2687531.0,2315281.0,3065009.0,2481649.0,3311319.0,3016241.0,2590496.0,3133969.0,3661712.0,3142913.0,2834242.0,5004974.0,3318523.0,3353735.0,3274783.0,4925187.0,4482182.0,4407420.0,4824788.0,4057998.0,5353227.0,4874082.0,4150213.0,4316236.0,4593040.0,5211014.0,4556108.0,5273830.0,5521621.0,5403347.0,4957305.0,5834332.0,5514087.0,6200091.0,6224580.0,6121572.0,5663413.0,6537204.0,5834284.0,7079762.0,7444764.0,6150025.0,7113156.0,7092362.0,7094055.0,7011889.0,8309176.0,7215382.0,7044195.0,7791199.0,7119411.0,7806837.0,7736713.0,8186428.0,8397991.0,7721092.0,8137680.0,7244230.0,8272237.0,7725322.0,8973489.0,8649189.0,8882937.0,8526159.0,7903917.0,8928762.0,9718470.0,9769245.0,8855740.0,9642869.0,9491737.0,9808859.0,8988551.0,9525780.0,10049589.0,9130090.0,10638715.0,9333409.0,10792234.0,10608885.0,10864878.0,10241257.0,10804128.0,9857364.0,11007447.0,10460871.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/tukey.json new file mode 100644 index 0000000000000..8de9b45d3b931 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/new/tukey.json @@ -0,0 +1 @@ +[123.19274563310864,246.93739053412492,576.9231102701683,700.6677551711846] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/MAD.svg new file mode 100644 index 0000000000000..f1b76695a0608 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 30 + + + + + 35 + + + + + 40 + + + + + 45 + + + + + 50 + + + + + 55 + + + + + 60 + + + + + 65 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/SD.svg new file mode 100644 index 0000000000000..7705c1534f899 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/SD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 250 + + + + + 300 + + + + + 350 + + + + + 400 + + + + + 450 + + + + + 500 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/index.html new file mode 100644 index 0000000000000..2019e7b1a6bac --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll - Criterion.rs + + + + +
+

forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope370.72 ns377.40 ns385.04 ns
0.25167750.25633610.2502736
Mean430.86 ns483.81 ns552.62 ns
Std. Dev.133.96 ns315.45 ns477.20 ns
Median383.65 ns394.34 ns404.87 ns
MAD30.424 ns44.188 ns62.986 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/mean.svg new file mode 100644 index 0000000000000..2565288b53e66 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/mean.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 420 + + + + + 440 + + + + + 460 + + + + + 480 + + + + + 500 + + + + + 520 + + + + + 540 + + + + + 560 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/median.svg new file mode 100644 index 0000000000000..adfcc572892f1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/median.svg @@ -0,0 +1,288 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 385 + + + + + 390 + + + + + 395 + + + + + 400 + + + + + 405 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/pdf.svg new file mode 100644 index 0000000000000..740d96400f458 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/pdf.svg @@ -0,0 +1,415 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 30 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..46505b06b306c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/pdf_small.svg @@ -0,0 +1,209 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/regression.svg new file mode 100644 index 0000000000000..0db099ab686ee --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/regression.svg @@ -0,0 +1,408 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 35 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/regression_small.svg new file mode 100644 index 0000000000000..28a00ae6ff3f2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/regression_small.svg @@ -0,0 +1,386 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 35 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/slope.svg new file mode 100644 index 0000000000000..d7987041fa292 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/slope.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 370 + + + + + 372 + + + + + 374 + + + + + 376 + + + + + 378 + + + + + 380 + + + + + 382 + + + + + 384 + + + + + 386 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/typical.svg new file mode 100644 index 0000000000000..d8f51dc287c5d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/forward msg from pull (nb_writter_5 nb_readder_5)/spin_lock object poll/report/typical.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 370 + + + + + 372 + + + + + 374 + + + + + 376 + + + + + 378 + + + + + 380 + + + + + 382 + + + + + 384 + + + + + 386 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + forward msg from pull (nb_writter:5 nb_readder:5)/spin_lock object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/benchmark.json new file mode 100644 index 0000000000000..d19f79483064f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"free","function_id":"crate 'object-pool'","value_str":null,"throughput":null,"full_id":"free/crate 'object-pool'","directory_name":"free/crate 'object-pool'","title":"free/crate 'object-pool'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/estimates.json new file mode 100644 index 0000000000000..370626bbde25c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":20.050239354820363,"upper_bound":20.952796272214545},"point_estimate":20.517095153569763,"standard_error":0.23064407928069464},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":21.327349472377406,"upper_bound":21.46715549348231},"point_estimate":21.38933718794004,"standard_error":0.03596709202667372},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.21525999545062727,"upper_bound":0.3975843685576356},"point_estimate":0.2846549182676507,"standard_error":0.04718730828605707},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":21.336212355351435,"upper_bound":21.4998806735142},"point_estimate":21.4117537953245,"standard_error":0.041702333548815904},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1.8623421368382145,"upper_bound":2.6764789879193156},"point_estimate":2.3231757374387927,"standard_error":0.20758090641449095}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/raw.csv new file mode 100644 index 0000000000000..15b0ddacad84d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +free,crate 'object-pool',,,,12220.0,ns,716 +free,crate 'object-pool',,,,22997.0,ns,1432 +free,crate 'object-pool',,,,33792.0,ns,2148 +free,crate 'object-pool',,,,44951.0,ns,2864 +free,crate 'object-pool',,,,55548.0,ns,3580 +free,crate 'object-pool',,,,66546.0,ns,4296 +free,crate 'object-pool',,,,78136.0,ns,5012 +free,crate 'object-pool',,,,87650.0,ns,5728 +free,crate 'object-pool',,,,98998.0,ns,6444 +free,crate 'object-pool',,,,109476.0,ns,7160 +free,crate 'object-pool',,,,120992.0,ns,7876 +free,crate 'object-pool',,,,132985.0,ns,8592 +free,crate 'object-pool',,,,142469.0,ns,9308 +free,crate 'object-pool',,,,153415.0,ns,10024 +free,crate 'object-pool',,,,165202.0,ns,10740 +free,crate 'object-pool',,,,175759.0,ns,11456 +free,crate 'object-pool',,,,186412.0,ns,12172 +free,crate 'object-pool',,,,266251.0,ns,12888 +free,crate 'object-pool',,,,282771.0,ns,13604 +free,crate 'object-pool',,,,319034.0,ns,14320 +free,crate 'object-pool',,,,317730.0,ns,15036 +free,crate 'object-pool',,,,336539.0,ns,15752 +free,crate 'object-pool',,,,369079.0,ns,16468 +free,crate 'object-pool',,,,368994.0,ns,17184 +free,crate 'object-pool',,,,464764.0,ns,17900 +free,crate 'object-pool',,,,396719.0,ns,18616 +free,crate 'object-pool',,,,411672.0,ns,19332 +free,crate 'object-pool',,,,425405.0,ns,20048 +free,crate 'object-pool',,,,440815.0,ns,20764 +free,crate 'object-pool',,,,452487.0,ns,21480 +free,crate 'object-pool',,,,471548.0,ns,22196 +free,crate 'object-pool',,,,502356.0,ns,22912 +free,crate 'object-pool',,,,509055.0,ns,23628 +free,crate 'object-pool',,,,515261.0,ns,24344 +free,crate 'object-pool',,,,537136.0,ns,25060 +free,crate 'object-pool',,,,569078.0,ns,25776 +free,crate 'object-pool',,,,570952.0,ns,26492 +free,crate 'object-pool',,,,590831.0,ns,27208 +free,crate 'object-pool',,,,606619.0,ns,27924 +free,crate 'object-pool',,,,621761.0,ns,28640 +free,crate 'object-pool',,,,631712.0,ns,29356 +free,crate 'object-pool',,,,649329.0,ns,30072 +free,crate 'object-pool',,,,662893.0,ns,30788 +free,crate 'object-pool',,,,675035.0,ns,31504 +free,crate 'object-pool',,,,692657.0,ns,32220 +free,crate 'object-pool',,,,729415.0,ns,32936 +free,crate 'object-pool',,,,715887.0,ns,33652 +free,crate 'object-pool',,,,737872.0,ns,34368 +free,crate 'object-pool',,,,756228.0,ns,35084 +free,crate 'object-pool',,,,768388.0,ns,35800 +free,crate 'object-pool',,,,788245.0,ns,36516 +free,crate 'object-pool',,,,798942.0,ns,37232 +free,crate 'object-pool',,,,823331.0,ns,37948 +free,crate 'object-pool',,,,830071.0,ns,38664 +free,crate 'object-pool',,,,860625.0,ns,39380 +free,crate 'object-pool',,,,874311.0,ns,40096 +free,crate 'object-pool',,,,880384.0,ns,40812 +free,crate 'object-pool',,,,903036.0,ns,41528 +free,crate 'object-pool',,,,918044.0,ns,42244 +free,crate 'object-pool',,,,922229.0,ns,42960 +free,crate 'object-pool',,,,940691.0,ns,43676 +free,crate 'object-pool',,,,954989.0,ns,44392 +free,crate 'object-pool',,,,969364.0,ns,45108 +free,crate 'object-pool',,,,983338.0,ns,45824 +free,crate 'object-pool',,,,1006955.0,ns,46540 +free,crate 'object-pool',,,,1014513.0,ns,47256 +free,crate 'object-pool',,,,1033402.0,ns,47972 +free,crate 'object-pool',,,,1040889.0,ns,48688 +free,crate 'object-pool',,,,1056958.0,ns,49404 +free,crate 'object-pool',,,,1080337.0,ns,50120 +free,crate 'object-pool',,,,1087058.0,ns,50836 +free,crate 'object-pool',,,,1109597.0,ns,51552 +free,crate 'object-pool',,,,1124292.0,ns,52268 +free,crate 'object-pool',,,,1135575.0,ns,52984 +free,crate 'object-pool',,,,1147024.0,ns,53700 +free,crate 'object-pool',,,,1250874.0,ns,54416 +free,crate 'object-pool',,,,1193099.0,ns,55132 +free,crate 'object-pool',,,,1199660.0,ns,55848 +free,crate 'object-pool',,,,1210536.0,ns,56564 +free,crate 'object-pool',,,,1224255.0,ns,57280 +free,crate 'object-pool',,,,1240085.0,ns,57996 +free,crate 'object-pool',,,,1257966.0,ns,58712 +free,crate 'object-pool',,,,1258702.0,ns,59428 +free,crate 'object-pool',,,,1277184.0,ns,60144 +free,crate 'object-pool',,,,1285318.0,ns,60860 +free,crate 'object-pool',,,,1313341.0,ns,61576 +free,crate 'object-pool',,,,1319424.0,ns,62292 +free,crate 'object-pool',,,,1338149.0,ns,63008 +free,crate 'object-pool',,,,1349868.0,ns,63724 +free,crate 'object-pool',,,,1366276.0,ns,64440 +free,crate 'object-pool',,,,1424380.0,ns,65156 +free,crate 'object-pool',,,,1434677.0,ns,65872 +free,crate 'object-pool',,,,1408453.0,ns,66588 +free,crate 'object-pool',,,,1412945.0,ns,67304 +free,crate 'object-pool',,,,1433613.0,ns,68020 +free,crate 'object-pool',,,,1459301.0,ns,68736 +free,crate 'object-pool',,,,1485196.0,ns,69452 +free,crate 'object-pool',,,,1490288.0,ns,70168 +free,crate 'object-pool',,,,1514794.0,ns,70884 +free,crate 'object-pool',,,,1528163.0,ns,71600 diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/sample.json new file mode 100644 index 0000000000000..1036e630ff700 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[716.0,1432.0,2148.0,2864.0,3580.0,4296.0,5012.0,5728.0,6444.0,7160.0,7876.0,8592.0,9308.0,10024.0,10740.0,11456.0,12172.0,12888.0,13604.0,14320.0,15036.0,15752.0,16468.0,17184.0,17900.0,18616.0,19332.0,20048.0,20764.0,21480.0,22196.0,22912.0,23628.0,24344.0,25060.0,25776.0,26492.0,27208.0,27924.0,28640.0,29356.0,30072.0,30788.0,31504.0,32220.0,32936.0,33652.0,34368.0,35084.0,35800.0,36516.0,37232.0,37948.0,38664.0,39380.0,40096.0,40812.0,41528.0,42244.0,42960.0,43676.0,44392.0,45108.0,45824.0,46540.0,47256.0,47972.0,48688.0,49404.0,50120.0,50836.0,51552.0,52268.0,52984.0,53700.0,54416.0,55132.0,55848.0,56564.0,57280.0,57996.0,58712.0,59428.0,60144.0,60860.0,61576.0,62292.0,63008.0,63724.0,64440.0,65156.0,65872.0,66588.0,67304.0,68020.0,68736.0,69452.0,70168.0,70884.0,71600.0],"times":[12220.0,22997.0,33792.0,44951.0,55548.0,66546.0,78136.0,87650.0,98998.0,109476.0,120992.0,132985.0,142469.0,153415.0,165202.0,175759.0,186412.0,266251.0,282771.0,319034.0,317730.0,336539.0,369079.0,368994.0,464764.0,396719.0,411672.0,425405.0,440815.0,452487.0,471548.0,502356.0,509055.0,515261.0,537136.0,569078.0,570952.0,590831.0,606619.0,621761.0,631712.0,649329.0,662893.0,675035.0,692657.0,729415.0,715887.0,737872.0,756228.0,768388.0,788245.0,798942.0,823331.0,830071.0,860625.0,874311.0,880384.0,903036.0,918044.0,922229.0,940691.0,954989.0,969364.0,983338.0,1006955.0,1014513.0,1033402.0,1040889.0,1056958.0,1080337.0,1087058.0,1109597.0,1124292.0,1135575.0,1147024.0,1250874.0,1193099.0,1199660.0,1210536.0,1224255.0,1240085.0,1257966.0,1258702.0,1277184.0,1285318.0,1313341.0,1319424.0,1338149.0,1349868.0,1366276.0,1424380.0,1434677.0,1408453.0,1412945.0,1433613.0,1459301.0,1485196.0,1490288.0,1514794.0,1528163.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/tukey.json new file mode 100644 index 0000000000000..b365127c63a42 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/base/tukey.json @@ -0,0 +1 @@ +[20.010076802283006,20.586194441003833,22.122508144259378,22.69862578298021] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/benchmark.json new file mode 100644 index 0000000000000..d19f79483064f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"free","function_id":"crate 'object-pool'","value_str":null,"throughput":null,"full_id":"free/crate 'object-pool'","directory_name":"free/crate 'object-pool'","title":"free/crate 'object-pool'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/estimates.json new file mode 100644 index 0000000000000..370626bbde25c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":20.050239354820363,"upper_bound":20.952796272214545},"point_estimate":20.517095153569763,"standard_error":0.23064407928069464},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":21.327349472377406,"upper_bound":21.46715549348231},"point_estimate":21.38933718794004,"standard_error":0.03596709202667372},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.21525999545062727,"upper_bound":0.3975843685576356},"point_estimate":0.2846549182676507,"standard_error":0.04718730828605707},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":21.336212355351435,"upper_bound":21.4998806735142},"point_estimate":21.4117537953245,"standard_error":0.041702333548815904},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1.8623421368382145,"upper_bound":2.6764789879193156},"point_estimate":2.3231757374387927,"standard_error":0.20758090641449095}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/raw.csv new file mode 100644 index 0000000000000..15b0ddacad84d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +free,crate 'object-pool',,,,12220.0,ns,716 +free,crate 'object-pool',,,,22997.0,ns,1432 +free,crate 'object-pool',,,,33792.0,ns,2148 +free,crate 'object-pool',,,,44951.0,ns,2864 +free,crate 'object-pool',,,,55548.0,ns,3580 +free,crate 'object-pool',,,,66546.0,ns,4296 +free,crate 'object-pool',,,,78136.0,ns,5012 +free,crate 'object-pool',,,,87650.0,ns,5728 +free,crate 'object-pool',,,,98998.0,ns,6444 +free,crate 'object-pool',,,,109476.0,ns,7160 +free,crate 'object-pool',,,,120992.0,ns,7876 +free,crate 'object-pool',,,,132985.0,ns,8592 +free,crate 'object-pool',,,,142469.0,ns,9308 +free,crate 'object-pool',,,,153415.0,ns,10024 +free,crate 'object-pool',,,,165202.0,ns,10740 +free,crate 'object-pool',,,,175759.0,ns,11456 +free,crate 'object-pool',,,,186412.0,ns,12172 +free,crate 'object-pool',,,,266251.0,ns,12888 +free,crate 'object-pool',,,,282771.0,ns,13604 +free,crate 'object-pool',,,,319034.0,ns,14320 +free,crate 'object-pool',,,,317730.0,ns,15036 +free,crate 'object-pool',,,,336539.0,ns,15752 +free,crate 'object-pool',,,,369079.0,ns,16468 +free,crate 'object-pool',,,,368994.0,ns,17184 +free,crate 'object-pool',,,,464764.0,ns,17900 +free,crate 'object-pool',,,,396719.0,ns,18616 +free,crate 'object-pool',,,,411672.0,ns,19332 +free,crate 'object-pool',,,,425405.0,ns,20048 +free,crate 'object-pool',,,,440815.0,ns,20764 +free,crate 'object-pool',,,,452487.0,ns,21480 +free,crate 'object-pool',,,,471548.0,ns,22196 +free,crate 'object-pool',,,,502356.0,ns,22912 +free,crate 'object-pool',,,,509055.0,ns,23628 +free,crate 'object-pool',,,,515261.0,ns,24344 +free,crate 'object-pool',,,,537136.0,ns,25060 +free,crate 'object-pool',,,,569078.0,ns,25776 +free,crate 'object-pool',,,,570952.0,ns,26492 +free,crate 'object-pool',,,,590831.0,ns,27208 +free,crate 'object-pool',,,,606619.0,ns,27924 +free,crate 'object-pool',,,,621761.0,ns,28640 +free,crate 'object-pool',,,,631712.0,ns,29356 +free,crate 'object-pool',,,,649329.0,ns,30072 +free,crate 'object-pool',,,,662893.0,ns,30788 +free,crate 'object-pool',,,,675035.0,ns,31504 +free,crate 'object-pool',,,,692657.0,ns,32220 +free,crate 'object-pool',,,,729415.0,ns,32936 +free,crate 'object-pool',,,,715887.0,ns,33652 +free,crate 'object-pool',,,,737872.0,ns,34368 +free,crate 'object-pool',,,,756228.0,ns,35084 +free,crate 'object-pool',,,,768388.0,ns,35800 +free,crate 'object-pool',,,,788245.0,ns,36516 +free,crate 'object-pool',,,,798942.0,ns,37232 +free,crate 'object-pool',,,,823331.0,ns,37948 +free,crate 'object-pool',,,,830071.0,ns,38664 +free,crate 'object-pool',,,,860625.0,ns,39380 +free,crate 'object-pool',,,,874311.0,ns,40096 +free,crate 'object-pool',,,,880384.0,ns,40812 +free,crate 'object-pool',,,,903036.0,ns,41528 +free,crate 'object-pool',,,,918044.0,ns,42244 +free,crate 'object-pool',,,,922229.0,ns,42960 +free,crate 'object-pool',,,,940691.0,ns,43676 +free,crate 'object-pool',,,,954989.0,ns,44392 +free,crate 'object-pool',,,,969364.0,ns,45108 +free,crate 'object-pool',,,,983338.0,ns,45824 +free,crate 'object-pool',,,,1006955.0,ns,46540 +free,crate 'object-pool',,,,1014513.0,ns,47256 +free,crate 'object-pool',,,,1033402.0,ns,47972 +free,crate 'object-pool',,,,1040889.0,ns,48688 +free,crate 'object-pool',,,,1056958.0,ns,49404 +free,crate 'object-pool',,,,1080337.0,ns,50120 +free,crate 'object-pool',,,,1087058.0,ns,50836 +free,crate 'object-pool',,,,1109597.0,ns,51552 +free,crate 'object-pool',,,,1124292.0,ns,52268 +free,crate 'object-pool',,,,1135575.0,ns,52984 +free,crate 'object-pool',,,,1147024.0,ns,53700 +free,crate 'object-pool',,,,1250874.0,ns,54416 +free,crate 'object-pool',,,,1193099.0,ns,55132 +free,crate 'object-pool',,,,1199660.0,ns,55848 +free,crate 'object-pool',,,,1210536.0,ns,56564 +free,crate 'object-pool',,,,1224255.0,ns,57280 +free,crate 'object-pool',,,,1240085.0,ns,57996 +free,crate 'object-pool',,,,1257966.0,ns,58712 +free,crate 'object-pool',,,,1258702.0,ns,59428 +free,crate 'object-pool',,,,1277184.0,ns,60144 +free,crate 'object-pool',,,,1285318.0,ns,60860 +free,crate 'object-pool',,,,1313341.0,ns,61576 +free,crate 'object-pool',,,,1319424.0,ns,62292 +free,crate 'object-pool',,,,1338149.0,ns,63008 +free,crate 'object-pool',,,,1349868.0,ns,63724 +free,crate 'object-pool',,,,1366276.0,ns,64440 +free,crate 'object-pool',,,,1424380.0,ns,65156 +free,crate 'object-pool',,,,1434677.0,ns,65872 +free,crate 'object-pool',,,,1408453.0,ns,66588 +free,crate 'object-pool',,,,1412945.0,ns,67304 +free,crate 'object-pool',,,,1433613.0,ns,68020 +free,crate 'object-pool',,,,1459301.0,ns,68736 +free,crate 'object-pool',,,,1485196.0,ns,69452 +free,crate 'object-pool',,,,1490288.0,ns,70168 +free,crate 'object-pool',,,,1514794.0,ns,70884 +free,crate 'object-pool',,,,1528163.0,ns,71600 diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/sample.json new file mode 100644 index 0000000000000..1036e630ff700 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[716.0,1432.0,2148.0,2864.0,3580.0,4296.0,5012.0,5728.0,6444.0,7160.0,7876.0,8592.0,9308.0,10024.0,10740.0,11456.0,12172.0,12888.0,13604.0,14320.0,15036.0,15752.0,16468.0,17184.0,17900.0,18616.0,19332.0,20048.0,20764.0,21480.0,22196.0,22912.0,23628.0,24344.0,25060.0,25776.0,26492.0,27208.0,27924.0,28640.0,29356.0,30072.0,30788.0,31504.0,32220.0,32936.0,33652.0,34368.0,35084.0,35800.0,36516.0,37232.0,37948.0,38664.0,39380.0,40096.0,40812.0,41528.0,42244.0,42960.0,43676.0,44392.0,45108.0,45824.0,46540.0,47256.0,47972.0,48688.0,49404.0,50120.0,50836.0,51552.0,52268.0,52984.0,53700.0,54416.0,55132.0,55848.0,56564.0,57280.0,57996.0,58712.0,59428.0,60144.0,60860.0,61576.0,62292.0,63008.0,63724.0,64440.0,65156.0,65872.0,66588.0,67304.0,68020.0,68736.0,69452.0,70168.0,70884.0,71600.0],"times":[12220.0,22997.0,33792.0,44951.0,55548.0,66546.0,78136.0,87650.0,98998.0,109476.0,120992.0,132985.0,142469.0,153415.0,165202.0,175759.0,186412.0,266251.0,282771.0,319034.0,317730.0,336539.0,369079.0,368994.0,464764.0,396719.0,411672.0,425405.0,440815.0,452487.0,471548.0,502356.0,509055.0,515261.0,537136.0,569078.0,570952.0,590831.0,606619.0,621761.0,631712.0,649329.0,662893.0,675035.0,692657.0,729415.0,715887.0,737872.0,756228.0,768388.0,788245.0,798942.0,823331.0,830071.0,860625.0,874311.0,880384.0,903036.0,918044.0,922229.0,940691.0,954989.0,969364.0,983338.0,1006955.0,1014513.0,1033402.0,1040889.0,1056958.0,1080337.0,1087058.0,1109597.0,1124292.0,1135575.0,1147024.0,1250874.0,1193099.0,1199660.0,1210536.0,1224255.0,1240085.0,1257966.0,1258702.0,1277184.0,1285318.0,1313341.0,1319424.0,1338149.0,1349868.0,1366276.0,1424380.0,1434677.0,1408453.0,1412945.0,1433613.0,1459301.0,1485196.0,1490288.0,1514794.0,1528163.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/tukey.json new file mode 100644 index 0000000000000..b365127c63a42 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/new/tukey.json @@ -0,0 +1 @@ +[20.010076802283006,20.586194441003833,22.122508144259378,22.69862578298021] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/MAD.svg new file mode 100644 index 0000000000000..5dca7b9e57fee --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/MAD.svg @@ -0,0 +1,283 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 200 + + + + + 250 + + + + + 300 + + + + + 350 + + + + + 400 + + + + + + + + + Density (a.u.) + + + + + Average time (ps) + + + + + free/crate 'object-pool': MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/SD.svg new file mode 100644 index 0000000000000..871bf29bbec02 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/SD.svg @@ -0,0 +1,328 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + 1.8 + + + + + 2 + + + + + 1.8 + + + + + 1.9 + + + + + 2 + + + + + 2.1 + + + + + 2.2 + + + + + 2.3 + + + + + 2.4 + + + + + 2.5 + + + + + 2.6 + + + + + 2.7 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/crate 'object-pool': SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/index.html b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/index.html new file mode 100644 index 0000000000000..6f8b14040d67d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/index.html @@ -0,0 +1,203 @@ + + + + + + free/crate 'object-pool' - Criterion.rs + + + + +
+

free/crate 'object-pool'

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope21.336 ns21.412 ns21.500 ns
0.90971860.91114650.9092043
Mean20.050 ns20.517 ns20.953 ns
Std. Dev.1.8623 ns2.3232 ns2.6765 ns
Median21.327 ns21.389 ns21.467 ns
MAD215.26 ps284.65 ps397.58 ps
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/mean.svg new file mode 100644 index 0000000000000..c34c16251869c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/mean.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + 1.8 + + + + + 20 + + + + + 20.2 + + + + + 20.4 + + + + + 20.6 + + + + + 20.8 + + + + + 21 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/crate 'object-pool': mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/median.svg new file mode 100644 index 0000000000000..de8a464056ed8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/median.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 21.32 + + + + + 21.34 + + + + + 21.36 + + + + + 21.38 + + + + + 21.4 + + + + + 21.42 + + + + + 21.44 + + + + + 21.46 + + + + + 21.48 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/crate 'object-pool': median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/pdf.svg new file mode 100644 index 0000000000000..5b89d34c0e260 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/pdf.svg @@ -0,0 +1,435 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 70 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + 22 + + + + + 24 + + + + + 26 + + + + + 28 + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/crate 'object-pool' + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/pdf_small.svg new file mode 100644 index 0000000000000..885140fca5d4e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/pdf_small.svg @@ -0,0 +1,224 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + 22 + + + + + 24 + + + + + 26 + + + + + 28 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/regression.svg new file mode 100644 index 0000000000000..f38c937de61bd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/regression.svg @@ -0,0 +1,447 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.2 + + + + + + + + + + + + + 0.4 + + + + + + + + + + + + + 0.6 + + + + + + + + + + + + + 0.8 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.2 + + + + + + + + + + + + + 1.4 + + + + + + + + + + + + + 1.6 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + free/crate 'object-pool' + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/regression_small.svg new file mode 100644 index 0000000000000..ca346f3bea378 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/regression_small.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.2 + + + + + + + + + + + + + 0.4 + + + + + + + + + + + + + 0.6 + + + + + + + + + + + + + 0.8 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.2 + + + + + + + + + + + + + 1.4 + + + + + + + + + + + + + 1.6 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 80 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/slope.svg new file mode 100644 index 0000000000000..7801ecf244486 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/slope.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 21.35 + + + + + 21.4 + + + + + 21.45 + + + + + 21.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/crate 'object-pool': slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/typical.svg new file mode 100644 index 0000000000000..80ba06a0a7f45 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'object-pool'/report/typical.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 21.35 + + + + + 21.4 + + + + + 21.45 + + + + + 21.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/crate 'object-pool': typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/benchmark.json new file mode 100644 index 0000000000000..6e91653014d68 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"free","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"free/crate 'sharded-slab'","directory_name":"free/crate 'sharded-slab'","title":"free/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/estimates.json new file mode 100644 index 0000000000000..5c42885a37bbd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":6.900158808029798,"upper_bound":7.19259438884231},"point_estimate":7.039410458952329,"standard_error":0.07431689104860482},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":6.813153310104529,"upper_bound":6.942708416633346},"point_estimate":6.906452999858782,"standard_error":0.037075916603925334},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.18871674521323242,"upper_bound":0.39522455299544584},"point_estimate":0.278249938884077,"standard_error":0.05278298979961195},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.171793081645471,"upper_bound":7.62471780827241},"point_estimate":7.3747239833193365,"standard_error":0.11620257115410591},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.5410912279797436,"upper_bound":0.9623606036867521},"point_estimate":0.748561119274048,"standard_error":0.11000917932218914}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/raw.csv new file mode 100644 index 0000000000000..88369a12d1ead --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +free,crate 'sharded-slab',,,,1939.0,ns,328 +free,crate 'sharded-slab',,,,3946.0,ns,656 +free,crate 'sharded-slab',,,,5779.0,ns,984 +free,crate 'sharded-slab',,,,8246.0,ns,1312 +free,crate 'sharded-slab',,,,9789.0,ns,1640 +free,crate 'sharded-slab',,,,11704.0,ns,1968 +free,crate 'sharded-slab',,,,14187.0,ns,2296 +free,crate 'sharded-slab',,,,16268.0,ns,2624 +free,crate 'sharded-slab',,,,17979.0,ns,2952 +free,crate 'sharded-slab',,,,19967.0,ns,3280 +free,crate 'sharded-slab',,,,21981.0,ns,3608 +free,crate 'sharded-slab',,,,23784.0,ns,3936 +free,crate 'sharded-slab',,,,29051.0,ns,4264 +free,crate 'sharded-slab',,,,31286.0,ns,4592 +free,crate 'sharded-slab',,,,35178.0,ns,4920 +free,crate 'sharded-slab',,,,35087.0,ns,5248 +free,crate 'sharded-slab',,,,37886.0,ns,5576 +free,crate 'sharded-slab',,,,39429.0,ns,5904 +free,crate 'sharded-slab',,,,41973.0,ns,6232 +free,crate 'sharded-slab',,,,43415.0,ns,6560 +free,crate 'sharded-slab',,,,45479.0,ns,6888 +free,crate 'sharded-slab',,,,47840.0,ns,7216 +free,crate 'sharded-slab',,,,50021.0,ns,7544 +free,crate 'sharded-slab',,,,51279.0,ns,7872 +free,crate 'sharded-slab',,,,54979.0,ns,8200 +free,crate 'sharded-slab',,,,58059.0,ns,8528 +free,crate 'sharded-slab',,,,59955.0,ns,8856 +free,crate 'sharded-slab',,,,62146.0,ns,9184 +free,crate 'sharded-slab',,,,64886.0,ns,9512 +free,crate 'sharded-slab',,,,70988.0,ns,9840 +free,crate 'sharded-slab',,,,68962.0,ns,10168 +free,crate 'sharded-slab',,,,71175.0,ns,10496 +free,crate 'sharded-slab',,,,72648.0,ns,10824 +free,crate 'sharded-slab',,,,74785.0,ns,11152 +free,crate 'sharded-slab',,,,77513.0,ns,11480 +free,crate 'sharded-slab',,,,80460.0,ns,11808 +free,crate 'sharded-slab',,,,82480.0,ns,12136 +free,crate 'sharded-slab',,,,84791.0,ns,12464 +free,crate 'sharded-slab',,,,86780.0,ns,12792 +free,crate 'sharded-slab',,,,88592.0,ns,13120 +free,crate 'sharded-slab',,,,90991.0,ns,13448 +free,crate 'sharded-slab',,,,100700.0,ns,13776 +free,crate 'sharded-slab',,,,94513.0,ns,14104 +free,crate 'sharded-slab',,,,98683.0,ns,14432 +free,crate 'sharded-slab',,,,103838.0,ns,14760 +free,crate 'sharded-slab',,,,100850.0,ns,15088 +free,crate 'sharded-slab',,,,104540.0,ns,15416 +free,crate 'sharded-slab',,,,105891.0,ns,15744 +free,crate 'sharded-slab',,,,109554.0,ns,16072 +free,crate 'sharded-slab',,,,113811.0,ns,16400 +free,crate 'sharded-slab',,,,115616.0,ns,16728 +free,crate 'sharded-slab',,,,117842.0,ns,17056 +free,crate 'sharded-slab',,,,119941.0,ns,17384 +free,crate 'sharded-slab',,,,155556.0,ns,17712 +free,crate 'sharded-slab',,,,123737.0,ns,18040 +free,crate 'sharded-slab',,,,133326.0,ns,18368 +free,crate 'sharded-slab',,,,167860.0,ns,18696 +free,crate 'sharded-slab',,,,137718.0,ns,19024 +free,crate 'sharded-slab',,,,163425.0,ns,19352 +free,crate 'sharded-slab',,,,147508.0,ns,19680 +free,crate 'sharded-slab',,,,138970.0,ns,20008 +free,crate 'sharded-slab',,,,149254.0,ns,20336 +free,crate 'sharded-slab',,,,144549.0,ns,20664 +free,crate 'sharded-slab',,,,147503.0,ns,20992 +free,crate 'sharded-slab',,,,149346.0,ns,21320 +free,crate 'sharded-slab',,,,181056.0,ns,21648 +free,crate 'sharded-slab',,,,183714.0,ns,21976 +free,crate 'sharded-slab',,,,156583.0,ns,22304 +free,crate 'sharded-slab',,,,184472.0,ns,22632 +free,crate 'sharded-slab',,,,173541.0,ns,22960 +free,crate 'sharded-slab',,,,161159.0,ns,23288 +free,crate 'sharded-slab',,,,164650.0,ns,23616 +free,crate 'sharded-slab',,,,165451.0,ns,23944 +free,crate 'sharded-slab',,,,169130.0,ns,24272 +free,crate 'sharded-slab',,,,178596.0,ns,24600 +free,crate 'sharded-slab',,,,198001.0,ns,24928 +free,crate 'sharded-slab',,,,178675.0,ns,25256 +free,crate 'sharded-slab',,,,206838.0,ns,25584 +free,crate 'sharded-slab',,,,192322.0,ns,25912 +free,crate 'sharded-slab',,,,227463.0,ns,26240 +free,crate 'sharded-slab',,,,183893.0,ns,26568 +free,crate 'sharded-slab',,,,186498.0,ns,26896 +free,crate 'sharded-slab',,,,187683.0,ns,27224 +free,crate 'sharded-slab',,,,225392.0,ns,27552 +free,crate 'sharded-slab',,,,195495.0,ns,27880 +free,crate 'sharded-slab',,,,233574.0,ns,28208 +free,crate 'sharded-slab',,,,203042.0,ns,28536 +free,crate 'sharded-slab',,,,208565.0,ns,28864 +free,crate 'sharded-slab',,,,205118.0,ns,29192 +free,crate 'sharded-slab',,,,204877.0,ns,29520 +free,crate 'sharded-slab',,,,327464.0,ns,29848 +free,crate 'sharded-slab',,,,234264.0,ns,30176 +free,crate 'sharded-slab',,,,210593.0,ns,30504 +free,crate 'sharded-slab',,,,214625.0,ns,30832 +free,crate 'sharded-slab',,,,218802.0,ns,31160 +free,crate 'sharded-slab',,,,270277.0,ns,31488 +free,crate 'sharded-slab',,,,218344.0,ns,31816 +free,crate 'sharded-slab',,,,222631.0,ns,32144 +free,crate 'sharded-slab',,,,224760.0,ns,32472 +free,crate 'sharded-slab',,,,229808.0,ns,32800 diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/sample.json new file mode 100644 index 0000000000000..27c088f57c149 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[328.0,656.0,984.0,1312.0,1640.0,1968.0,2296.0,2624.0,2952.0,3280.0,3608.0,3936.0,4264.0,4592.0,4920.0,5248.0,5576.0,5904.0,6232.0,6560.0,6888.0,7216.0,7544.0,7872.0,8200.0,8528.0,8856.0,9184.0,9512.0,9840.0,10168.0,10496.0,10824.0,11152.0,11480.0,11808.0,12136.0,12464.0,12792.0,13120.0,13448.0,13776.0,14104.0,14432.0,14760.0,15088.0,15416.0,15744.0,16072.0,16400.0,16728.0,17056.0,17384.0,17712.0,18040.0,18368.0,18696.0,19024.0,19352.0,19680.0,20008.0,20336.0,20664.0,20992.0,21320.0,21648.0,21976.0,22304.0,22632.0,22960.0,23288.0,23616.0,23944.0,24272.0,24600.0,24928.0,25256.0,25584.0,25912.0,26240.0,26568.0,26896.0,27224.0,27552.0,27880.0,28208.0,28536.0,28864.0,29192.0,29520.0,29848.0,30176.0,30504.0,30832.0,31160.0,31488.0,31816.0,32144.0,32472.0,32800.0],"times":[1939.0,3946.0,5779.0,8246.0,9789.0,11704.0,14187.0,16268.0,17979.0,19967.0,21981.0,23784.0,29051.0,31286.0,35178.0,35087.0,37886.0,39429.0,41973.0,43415.0,45479.0,47840.0,50021.0,51279.0,54979.0,58059.0,59955.0,62146.0,64886.0,70988.0,68962.0,71175.0,72648.0,74785.0,77513.0,80460.0,82480.0,84791.0,86780.0,88592.0,90991.0,100700.0,94513.0,98683.0,103838.0,100850.0,104540.0,105891.0,109554.0,113811.0,115616.0,117842.0,119941.0,155556.0,123737.0,133326.0,167860.0,137718.0,163425.0,147508.0,138970.0,149254.0,144549.0,147503.0,149346.0,181056.0,183714.0,156583.0,184472.0,173541.0,161159.0,164650.0,165451.0,169130.0,178596.0,198001.0,178675.0,206838.0,192322.0,227463.0,183893.0,186498.0,187683.0,225392.0,195495.0,233574.0,203042.0,208565.0,205118.0,204877.0,327464.0,234264.0,210593.0,214625.0,218802.0,270277.0,218344.0,222631.0,224760.0,229808.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/tukey.json new file mode 100644 index 0000000000000..640d2eebbcf31 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/base/tukey.json @@ -0,0 +1 @@ +[5.559122202979063,6.145940022782856,7.710787542259638,8.297605362063432] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/benchmark.json new file mode 100644 index 0000000000000..6e91653014d68 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"free","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"free/crate 'sharded-slab'","directory_name":"free/crate 'sharded-slab'","title":"free/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/estimates.json new file mode 100644 index 0000000000000..5c42885a37bbd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":6.900158808029798,"upper_bound":7.19259438884231},"point_estimate":7.039410458952329,"standard_error":0.07431689104860482},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":6.813153310104529,"upper_bound":6.942708416633346},"point_estimate":6.906452999858782,"standard_error":0.037075916603925334},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.18871674521323242,"upper_bound":0.39522455299544584},"point_estimate":0.278249938884077,"standard_error":0.05278298979961195},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.171793081645471,"upper_bound":7.62471780827241},"point_estimate":7.3747239833193365,"standard_error":0.11620257115410591},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.5410912279797436,"upper_bound":0.9623606036867521},"point_estimate":0.748561119274048,"standard_error":0.11000917932218914}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/raw.csv new file mode 100644 index 0000000000000..88369a12d1ead --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +free,crate 'sharded-slab',,,,1939.0,ns,328 +free,crate 'sharded-slab',,,,3946.0,ns,656 +free,crate 'sharded-slab',,,,5779.0,ns,984 +free,crate 'sharded-slab',,,,8246.0,ns,1312 +free,crate 'sharded-slab',,,,9789.0,ns,1640 +free,crate 'sharded-slab',,,,11704.0,ns,1968 +free,crate 'sharded-slab',,,,14187.0,ns,2296 +free,crate 'sharded-slab',,,,16268.0,ns,2624 +free,crate 'sharded-slab',,,,17979.0,ns,2952 +free,crate 'sharded-slab',,,,19967.0,ns,3280 +free,crate 'sharded-slab',,,,21981.0,ns,3608 +free,crate 'sharded-slab',,,,23784.0,ns,3936 +free,crate 'sharded-slab',,,,29051.0,ns,4264 +free,crate 'sharded-slab',,,,31286.0,ns,4592 +free,crate 'sharded-slab',,,,35178.0,ns,4920 +free,crate 'sharded-slab',,,,35087.0,ns,5248 +free,crate 'sharded-slab',,,,37886.0,ns,5576 +free,crate 'sharded-slab',,,,39429.0,ns,5904 +free,crate 'sharded-slab',,,,41973.0,ns,6232 +free,crate 'sharded-slab',,,,43415.0,ns,6560 +free,crate 'sharded-slab',,,,45479.0,ns,6888 +free,crate 'sharded-slab',,,,47840.0,ns,7216 +free,crate 'sharded-slab',,,,50021.0,ns,7544 +free,crate 'sharded-slab',,,,51279.0,ns,7872 +free,crate 'sharded-slab',,,,54979.0,ns,8200 +free,crate 'sharded-slab',,,,58059.0,ns,8528 +free,crate 'sharded-slab',,,,59955.0,ns,8856 +free,crate 'sharded-slab',,,,62146.0,ns,9184 +free,crate 'sharded-slab',,,,64886.0,ns,9512 +free,crate 'sharded-slab',,,,70988.0,ns,9840 +free,crate 'sharded-slab',,,,68962.0,ns,10168 +free,crate 'sharded-slab',,,,71175.0,ns,10496 +free,crate 'sharded-slab',,,,72648.0,ns,10824 +free,crate 'sharded-slab',,,,74785.0,ns,11152 +free,crate 'sharded-slab',,,,77513.0,ns,11480 +free,crate 'sharded-slab',,,,80460.0,ns,11808 +free,crate 'sharded-slab',,,,82480.0,ns,12136 +free,crate 'sharded-slab',,,,84791.0,ns,12464 +free,crate 'sharded-slab',,,,86780.0,ns,12792 +free,crate 'sharded-slab',,,,88592.0,ns,13120 +free,crate 'sharded-slab',,,,90991.0,ns,13448 +free,crate 'sharded-slab',,,,100700.0,ns,13776 +free,crate 'sharded-slab',,,,94513.0,ns,14104 +free,crate 'sharded-slab',,,,98683.0,ns,14432 +free,crate 'sharded-slab',,,,103838.0,ns,14760 +free,crate 'sharded-slab',,,,100850.0,ns,15088 +free,crate 'sharded-slab',,,,104540.0,ns,15416 +free,crate 'sharded-slab',,,,105891.0,ns,15744 +free,crate 'sharded-slab',,,,109554.0,ns,16072 +free,crate 'sharded-slab',,,,113811.0,ns,16400 +free,crate 'sharded-slab',,,,115616.0,ns,16728 +free,crate 'sharded-slab',,,,117842.0,ns,17056 +free,crate 'sharded-slab',,,,119941.0,ns,17384 +free,crate 'sharded-slab',,,,155556.0,ns,17712 +free,crate 'sharded-slab',,,,123737.0,ns,18040 +free,crate 'sharded-slab',,,,133326.0,ns,18368 +free,crate 'sharded-slab',,,,167860.0,ns,18696 +free,crate 'sharded-slab',,,,137718.0,ns,19024 +free,crate 'sharded-slab',,,,163425.0,ns,19352 +free,crate 'sharded-slab',,,,147508.0,ns,19680 +free,crate 'sharded-slab',,,,138970.0,ns,20008 +free,crate 'sharded-slab',,,,149254.0,ns,20336 +free,crate 'sharded-slab',,,,144549.0,ns,20664 +free,crate 'sharded-slab',,,,147503.0,ns,20992 +free,crate 'sharded-slab',,,,149346.0,ns,21320 +free,crate 'sharded-slab',,,,181056.0,ns,21648 +free,crate 'sharded-slab',,,,183714.0,ns,21976 +free,crate 'sharded-slab',,,,156583.0,ns,22304 +free,crate 'sharded-slab',,,,184472.0,ns,22632 +free,crate 'sharded-slab',,,,173541.0,ns,22960 +free,crate 'sharded-slab',,,,161159.0,ns,23288 +free,crate 'sharded-slab',,,,164650.0,ns,23616 +free,crate 'sharded-slab',,,,165451.0,ns,23944 +free,crate 'sharded-slab',,,,169130.0,ns,24272 +free,crate 'sharded-slab',,,,178596.0,ns,24600 +free,crate 'sharded-slab',,,,198001.0,ns,24928 +free,crate 'sharded-slab',,,,178675.0,ns,25256 +free,crate 'sharded-slab',,,,206838.0,ns,25584 +free,crate 'sharded-slab',,,,192322.0,ns,25912 +free,crate 'sharded-slab',,,,227463.0,ns,26240 +free,crate 'sharded-slab',,,,183893.0,ns,26568 +free,crate 'sharded-slab',,,,186498.0,ns,26896 +free,crate 'sharded-slab',,,,187683.0,ns,27224 +free,crate 'sharded-slab',,,,225392.0,ns,27552 +free,crate 'sharded-slab',,,,195495.0,ns,27880 +free,crate 'sharded-slab',,,,233574.0,ns,28208 +free,crate 'sharded-slab',,,,203042.0,ns,28536 +free,crate 'sharded-slab',,,,208565.0,ns,28864 +free,crate 'sharded-slab',,,,205118.0,ns,29192 +free,crate 'sharded-slab',,,,204877.0,ns,29520 +free,crate 'sharded-slab',,,,327464.0,ns,29848 +free,crate 'sharded-slab',,,,234264.0,ns,30176 +free,crate 'sharded-slab',,,,210593.0,ns,30504 +free,crate 'sharded-slab',,,,214625.0,ns,30832 +free,crate 'sharded-slab',,,,218802.0,ns,31160 +free,crate 'sharded-slab',,,,270277.0,ns,31488 +free,crate 'sharded-slab',,,,218344.0,ns,31816 +free,crate 'sharded-slab',,,,222631.0,ns,32144 +free,crate 'sharded-slab',,,,224760.0,ns,32472 +free,crate 'sharded-slab',,,,229808.0,ns,32800 diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/sample.json new file mode 100644 index 0000000000000..27c088f57c149 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[328.0,656.0,984.0,1312.0,1640.0,1968.0,2296.0,2624.0,2952.0,3280.0,3608.0,3936.0,4264.0,4592.0,4920.0,5248.0,5576.0,5904.0,6232.0,6560.0,6888.0,7216.0,7544.0,7872.0,8200.0,8528.0,8856.0,9184.0,9512.0,9840.0,10168.0,10496.0,10824.0,11152.0,11480.0,11808.0,12136.0,12464.0,12792.0,13120.0,13448.0,13776.0,14104.0,14432.0,14760.0,15088.0,15416.0,15744.0,16072.0,16400.0,16728.0,17056.0,17384.0,17712.0,18040.0,18368.0,18696.0,19024.0,19352.0,19680.0,20008.0,20336.0,20664.0,20992.0,21320.0,21648.0,21976.0,22304.0,22632.0,22960.0,23288.0,23616.0,23944.0,24272.0,24600.0,24928.0,25256.0,25584.0,25912.0,26240.0,26568.0,26896.0,27224.0,27552.0,27880.0,28208.0,28536.0,28864.0,29192.0,29520.0,29848.0,30176.0,30504.0,30832.0,31160.0,31488.0,31816.0,32144.0,32472.0,32800.0],"times":[1939.0,3946.0,5779.0,8246.0,9789.0,11704.0,14187.0,16268.0,17979.0,19967.0,21981.0,23784.0,29051.0,31286.0,35178.0,35087.0,37886.0,39429.0,41973.0,43415.0,45479.0,47840.0,50021.0,51279.0,54979.0,58059.0,59955.0,62146.0,64886.0,70988.0,68962.0,71175.0,72648.0,74785.0,77513.0,80460.0,82480.0,84791.0,86780.0,88592.0,90991.0,100700.0,94513.0,98683.0,103838.0,100850.0,104540.0,105891.0,109554.0,113811.0,115616.0,117842.0,119941.0,155556.0,123737.0,133326.0,167860.0,137718.0,163425.0,147508.0,138970.0,149254.0,144549.0,147503.0,149346.0,181056.0,183714.0,156583.0,184472.0,173541.0,161159.0,164650.0,165451.0,169130.0,178596.0,198001.0,178675.0,206838.0,192322.0,227463.0,183893.0,186498.0,187683.0,225392.0,195495.0,233574.0,203042.0,208565.0,205118.0,204877.0,327464.0,234264.0,210593.0,214625.0,218802.0,270277.0,218344.0,222631.0,224760.0,229808.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/tukey.json new file mode 100644 index 0000000000000..640d2eebbcf31 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/new/tukey.json @@ -0,0 +1 @@ +[5.559122202979063,6.145940022782856,7.710787542259638,8.297605362063432] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/MAD.svg new file mode 100644 index 0000000000000..fad1ba1b2a3df --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/MAD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 200 + + + + + 250 + + + + + 300 + + + + + 350 + + + + + 400 + + + + + + + + + Density (a.u.) + + + + + Average time (ps) + + + + + free/crate 'sharded-slab': MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/SD.svg new file mode 100644 index 0000000000000..8e2ced9e58389 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + 0.003 + + + + + 0.0035 + + + + + 0.004 + + + + + 500 + + + + + 600 + + + + + 700 + + + + + 800 + + + + + 900 + + + + + 1000 + + + + + + + + + Density (a.u.) + + + + + Average time (ps) + + + + + free/crate 'sharded-slab': SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/index.html b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/index.html new file mode 100644 index 0000000000000..c3e687fc406de --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/index.html @@ -0,0 +1,203 @@ + + + + + + free/crate 'sharded-slab' - Criterion.rs + + + + +
+

free/crate 'sharded-slab'

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope7.1718 ns7.3747 ns7.6247 ns
0.31737340.33057360.3109464
Mean6.9002 ns7.0394 ns7.1926 ns
Std. Dev.541.09 ps748.56 ps962.36 ps
Median6.8132 ns6.9065 ns6.9427 ns
MAD188.72 ps278.25 ps395.22 ps
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/mean.svg new file mode 100644 index 0000000000000..b8560e1fb256c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 6.9 + + + + + 6.95 + + + + + 7 + + + + + 7.05 + + + + + 7.1 + + + + + 7.15 + + + + + 7.2 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/crate 'sharded-slab': mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/median.svg new file mode 100644 index 0000000000000..855f34150c2b3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/median.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 6.8 + + + + + 6.82 + + + + + 6.84 + + + + + 6.86 + + + + + 6.88 + + + + + 6.9 + + + + + 6.92 + + + + + 6.94 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/crate 'sharded-slab': median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/pdf.svg new file mode 100644 index 0000000000000..24560a6f5266d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/pdf.svg @@ -0,0 +1,430 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 30 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/crate 'sharded-slab' + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + + + + + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/pdf_small.svg new file mode 100644 index 0000000000000..6020b6b4c4bb3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/pdf_small.svg @@ -0,0 +1,224 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/regression.svg new file mode 100644 index 0000000000000..c308025de514a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/regression.svg @@ -0,0 +1,421 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 150 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 250 + + + + + + + + + + + + + 300 + + + + + + + + + + + + + 350 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 35 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + free/crate 'sharded-slab' + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/regression_small.svg new file mode 100644 index 0000000000000..6e48a3b976cf8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/regression_small.svg @@ -0,0 +1,399 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 150 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 250 + + + + + + + + + + + + + 300 + + + + + + + + + + + + + 350 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 35 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/slope.svg new file mode 100644 index 0000000000000..3b6bbda6401b6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/slope.svg @@ -0,0 +1,288 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 7.2 + + + + + 7.3 + + + + + 7.4 + + + + + 7.5 + + + + + 7.6 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/crate 'sharded-slab': slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/typical.svg new file mode 100644 index 0000000000000..5efc82b23a99f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/crate 'sharded-slab'/report/typical.svg @@ -0,0 +1,288 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 7.2 + + + + + 7.3 + + + + + 7.4 + + + + + 7.5 + + + + + 7.6 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/crate 'sharded-slab': typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/benchmark.json new file mode 100644 index 0000000000000..1568c67ff0501 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"free","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"free/linear object poll","directory_name":"free/linear object poll","title":"free/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/estimates.json new file mode 100644 index 0000000000000..370ccc037b3ef --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.415973124025243,"upper_bound":7.662983832664377},"point_estimate":7.537949429842049,"standard_error":0.06291043181151354},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.076923076923077,"upper_bound":7.877828054298643},"point_estimate":7.4649478381096035,"standard_error":0.1660386713912531},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.34118028031439723,"upper_bound":1.0020301481229268},"point_estimate":0.8352488709041169,"standard_error":0.15742171869523508},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.0109702846188044,"upper_bound":7.158671623608744},"point_estimate":7.073776737030764,"standard_error":0.03790474355315091},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.5737699319530375,"upper_bound":0.6844750218130433},"point_estimate":0.6323291467829356,"standard_error":0.02813189271391754}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/raw.csv new file mode 100644 index 0000000000000..16b3a851091a7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +free,linear object poll,,,,357.0,ns,39 +free,linear object poll,,,,646.0,ns,78 +free,linear object poll,,,,950.0,ns,117 +free,linear object poll,,,,1246.0,ns,156 +free,linear object poll,,,,1552.0,ns,195 +free,linear object poll,,,,1866.0,ns,234 +free,linear object poll,,,,2167.0,ns,273 +free,linear object poll,,,,2474.0,ns,312 +free,linear object poll,,,,2782.0,ns,351 +free,linear object poll,,,,3081.0,ns,390 +free,linear object poll,,,,3725.0,ns,429 +free,linear object poll,,,,3980.0,ns,468 +free,linear object poll,,,,4298.0,ns,507 +free,linear object poll,,,,4655.0,ns,546 +free,linear object poll,,,,4939.0,ns,585 +free,linear object poll,,,,5248.0,ns,624 +free,linear object poll,,,,5570.0,ns,663 +free,linear object poll,,,,6007.0,ns,702 +free,linear object poll,,,,6310.0,ns,741 +free,linear object poll,,,,6590.0,ns,780 +free,linear object poll,,,,6945.0,ns,819 +free,linear object poll,,,,7301.0,ns,858 +free,linear object poll,,,,7621.0,ns,897 +free,linear object poll,,,,7682.0,ns,936 +free,linear object poll,,,,7929.0,ns,975 +free,linear object poll,,,,8333.0,ns,1014 +free,linear object poll,,,,8589.0,ns,1053 +free,linear object poll,,,,9014.0,ns,1092 +free,linear object poll,,,,9308.0,ns,1131 +free,linear object poll,,,,9650.0,ns,1170 +free,linear object poll,,,,9942.0,ns,1209 +free,linear object poll,,,,9925.0,ns,1248 +free,linear object poll,,,,10184.0,ns,1287 +free,linear object poll,,,,10446.0,ns,1326 +free,linear object poll,,,,10910.0,ns,1365 +free,linear object poll,,,,11160.0,ns,1404 +free,linear object poll,,,,11390.0,ns,1443 +free,linear object poll,,,,11778.0,ns,1482 +free,linear object poll,,,,12075.0,ns,1521 +free,linear object poll,,,,12372.0,ns,1560 +free,linear object poll,,,,12305.0,ns,1599 +free,linear object poll,,,,12662.0,ns,1638 +free,linear object poll,,,,12984.0,ns,1677 +free,linear object poll,,,,12755.0,ns,1716 +free,linear object poll,,,,13109.0,ns,1755 +free,linear object poll,,,,13405.0,ns,1794 +free,linear object poll,,,,13642.0,ns,1833 +free,linear object poll,,,,13977.0,ns,1872 +free,linear object poll,,,,14286.0,ns,1911 +free,linear object poll,,,,14599.0,ns,1950 +free,linear object poll,,,,14845.0,ns,1989 +free,linear object poll,,,,15264.0,ns,2028 +free,linear object poll,,,,15423.0,ns,2067 +free,linear object poll,,,,15222.0,ns,2106 +free,linear object poll,,,,15496.0,ns,2145 +free,linear object poll,,,,15786.0,ns,2184 +free,linear object poll,,,,16081.0,ns,2223 +free,linear object poll,,,,15940.0,ns,2262 +free,linear object poll,,,,16242.0,ns,2301 +free,linear object poll,,,,16560.0,ns,2340 +free,linear object poll,,,,16871.0,ns,2379 +free,linear object poll,,,,16560.0,ns,2418 +free,linear object poll,,,,16867.0,ns,2457 +free,linear object poll,,,,17150.0,ns,2496 +free,linear object poll,,,,17431.0,ns,2535 +free,linear object poll,,,,17574.0,ns,2574 +free,linear object poll,,,,17993.0,ns,2613 +free,linear object poll,,,,18176.0,ns,2652 +free,linear object poll,,,,18452.0,ns,2691 +free,linear object poll,,,,18701.0,ns,2730 +free,linear object poll,,,,19028.0,ns,2769 +free,linear object poll,,,,19412.0,ns,2808 +free,linear object poll,,,,19633.0,ns,2847 +free,linear object poll,,,,19692.0,ns,2886 +free,linear object poll,,,,20343.0,ns,2925 +free,linear object poll,,,,20297.0,ns,2964 +free,linear object poll,,,,20636.0,ns,3003 +free,linear object poll,,,,21068.0,ns,3042 +free,linear object poll,,,,21195.0,ns,3081 +free,linear object poll,,,,21635.0,ns,3120 +free,linear object poll,,,,21911.0,ns,3159 +free,linear object poll,,,,22089.0,ns,3198 +free,linear object poll,,,,22847.0,ns,3237 +free,linear object poll,,,,26918.0,ns,3276 +free,linear object poll,,,,22784.0,ns,3315 +free,linear object poll,,,,23068.0,ns,3354 +free,linear object poll,,,,23256.0,ns,3393 +free,linear object poll,,,,23829.0,ns,3432 +free,linear object poll,,,,24071.0,ns,3471 +free,linear object poll,,,,24149.0,ns,3510 +free,linear object poll,,,,24437.0,ns,3549 +free,linear object poll,,,,24833.0,ns,3588 +free,linear object poll,,,,24774.0,ns,3627 +free,linear object poll,,,,25359.0,ns,3666 +free,linear object poll,,,,25413.0,ns,3705 +free,linear object poll,,,,25646.0,ns,3744 +free,linear object poll,,,,26008.0,ns,3783 +free,linear object poll,,,,26637.0,ns,3822 +free,linear object poll,,,,26532.0,ns,3861 +free,linear object poll,,,,27076.0,ns,3900 diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/sample.json new file mode 100644 index 0000000000000..24563a7b6558b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[39.0,78.0,117.0,156.0,195.0,234.0,273.0,312.0,351.0,390.0,429.0,468.0,507.0,546.0,585.0,624.0,663.0,702.0,741.0,780.0,819.0,858.0,897.0,936.0,975.0,1014.0,1053.0,1092.0,1131.0,1170.0,1209.0,1248.0,1287.0,1326.0,1365.0,1404.0,1443.0,1482.0,1521.0,1560.0,1599.0,1638.0,1677.0,1716.0,1755.0,1794.0,1833.0,1872.0,1911.0,1950.0,1989.0,2028.0,2067.0,2106.0,2145.0,2184.0,2223.0,2262.0,2301.0,2340.0,2379.0,2418.0,2457.0,2496.0,2535.0,2574.0,2613.0,2652.0,2691.0,2730.0,2769.0,2808.0,2847.0,2886.0,2925.0,2964.0,3003.0,3042.0,3081.0,3120.0,3159.0,3198.0,3237.0,3276.0,3315.0,3354.0,3393.0,3432.0,3471.0,3510.0,3549.0,3588.0,3627.0,3666.0,3705.0,3744.0,3783.0,3822.0,3861.0,3900.0],"times":[357.0,646.0,950.0,1246.0,1552.0,1866.0,2167.0,2474.0,2782.0,3081.0,3725.0,3980.0,4298.0,4655.0,4939.0,5248.0,5570.0,6007.0,6310.0,6590.0,6945.0,7301.0,7621.0,7682.0,7929.0,8333.0,8589.0,9014.0,9308.0,9650.0,9942.0,9925.0,10184.0,10446.0,10910.0,11160.0,11390.0,11778.0,12075.0,12372.0,12305.0,12662.0,12984.0,12755.0,13109.0,13405.0,13642.0,13977.0,14286.0,14599.0,14845.0,15264.0,15423.0,15222.0,15496.0,15786.0,16081.0,15940.0,16242.0,16560.0,16871.0,16560.0,16867.0,17150.0,17431.0,17574.0,17993.0,18176.0,18452.0,18701.0,19028.0,19412.0,19633.0,19692.0,20343.0,20297.0,20636.0,21068.0,21195.0,21635.0,21911.0,22089.0,22847.0,26918.0,22784.0,23068.0,23256.0,23829.0,24071.0,24149.0,24437.0,24833.0,24774.0,25359.0,25413.0,25646.0,26008.0,26637.0,26532.0,27076.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/tukey.json new file mode 100644 index 0000000000000..c08c99498fcf1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/base/tukey.json @@ -0,0 +1 @@ +[3.5441592041992998,5.224257011782072,9.704517832002796,11.384615639585569] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/benchmark.json new file mode 100644 index 0000000000000..1568c67ff0501 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"free","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"free/linear object poll","directory_name":"free/linear object poll","title":"free/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/estimates.json new file mode 100644 index 0000000000000..370ccc037b3ef --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.415973124025243,"upper_bound":7.662983832664377},"point_estimate":7.537949429842049,"standard_error":0.06291043181151354},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.076923076923077,"upper_bound":7.877828054298643},"point_estimate":7.4649478381096035,"standard_error":0.1660386713912531},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.34118028031439723,"upper_bound":1.0020301481229268},"point_estimate":0.8352488709041169,"standard_error":0.15742171869523508},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.0109702846188044,"upper_bound":7.158671623608744},"point_estimate":7.073776737030764,"standard_error":0.03790474355315091},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.5737699319530375,"upper_bound":0.6844750218130433},"point_estimate":0.6323291467829356,"standard_error":0.02813189271391754}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/raw.csv new file mode 100644 index 0000000000000..16b3a851091a7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +free,linear object poll,,,,357.0,ns,39 +free,linear object poll,,,,646.0,ns,78 +free,linear object poll,,,,950.0,ns,117 +free,linear object poll,,,,1246.0,ns,156 +free,linear object poll,,,,1552.0,ns,195 +free,linear object poll,,,,1866.0,ns,234 +free,linear object poll,,,,2167.0,ns,273 +free,linear object poll,,,,2474.0,ns,312 +free,linear object poll,,,,2782.0,ns,351 +free,linear object poll,,,,3081.0,ns,390 +free,linear object poll,,,,3725.0,ns,429 +free,linear object poll,,,,3980.0,ns,468 +free,linear object poll,,,,4298.0,ns,507 +free,linear object poll,,,,4655.0,ns,546 +free,linear object poll,,,,4939.0,ns,585 +free,linear object poll,,,,5248.0,ns,624 +free,linear object poll,,,,5570.0,ns,663 +free,linear object poll,,,,6007.0,ns,702 +free,linear object poll,,,,6310.0,ns,741 +free,linear object poll,,,,6590.0,ns,780 +free,linear object poll,,,,6945.0,ns,819 +free,linear object poll,,,,7301.0,ns,858 +free,linear object poll,,,,7621.0,ns,897 +free,linear object poll,,,,7682.0,ns,936 +free,linear object poll,,,,7929.0,ns,975 +free,linear object poll,,,,8333.0,ns,1014 +free,linear object poll,,,,8589.0,ns,1053 +free,linear object poll,,,,9014.0,ns,1092 +free,linear object poll,,,,9308.0,ns,1131 +free,linear object poll,,,,9650.0,ns,1170 +free,linear object poll,,,,9942.0,ns,1209 +free,linear object poll,,,,9925.0,ns,1248 +free,linear object poll,,,,10184.0,ns,1287 +free,linear object poll,,,,10446.0,ns,1326 +free,linear object poll,,,,10910.0,ns,1365 +free,linear object poll,,,,11160.0,ns,1404 +free,linear object poll,,,,11390.0,ns,1443 +free,linear object poll,,,,11778.0,ns,1482 +free,linear object poll,,,,12075.0,ns,1521 +free,linear object poll,,,,12372.0,ns,1560 +free,linear object poll,,,,12305.0,ns,1599 +free,linear object poll,,,,12662.0,ns,1638 +free,linear object poll,,,,12984.0,ns,1677 +free,linear object poll,,,,12755.0,ns,1716 +free,linear object poll,,,,13109.0,ns,1755 +free,linear object poll,,,,13405.0,ns,1794 +free,linear object poll,,,,13642.0,ns,1833 +free,linear object poll,,,,13977.0,ns,1872 +free,linear object poll,,,,14286.0,ns,1911 +free,linear object poll,,,,14599.0,ns,1950 +free,linear object poll,,,,14845.0,ns,1989 +free,linear object poll,,,,15264.0,ns,2028 +free,linear object poll,,,,15423.0,ns,2067 +free,linear object poll,,,,15222.0,ns,2106 +free,linear object poll,,,,15496.0,ns,2145 +free,linear object poll,,,,15786.0,ns,2184 +free,linear object poll,,,,16081.0,ns,2223 +free,linear object poll,,,,15940.0,ns,2262 +free,linear object poll,,,,16242.0,ns,2301 +free,linear object poll,,,,16560.0,ns,2340 +free,linear object poll,,,,16871.0,ns,2379 +free,linear object poll,,,,16560.0,ns,2418 +free,linear object poll,,,,16867.0,ns,2457 +free,linear object poll,,,,17150.0,ns,2496 +free,linear object poll,,,,17431.0,ns,2535 +free,linear object poll,,,,17574.0,ns,2574 +free,linear object poll,,,,17993.0,ns,2613 +free,linear object poll,,,,18176.0,ns,2652 +free,linear object poll,,,,18452.0,ns,2691 +free,linear object poll,,,,18701.0,ns,2730 +free,linear object poll,,,,19028.0,ns,2769 +free,linear object poll,,,,19412.0,ns,2808 +free,linear object poll,,,,19633.0,ns,2847 +free,linear object poll,,,,19692.0,ns,2886 +free,linear object poll,,,,20343.0,ns,2925 +free,linear object poll,,,,20297.0,ns,2964 +free,linear object poll,,,,20636.0,ns,3003 +free,linear object poll,,,,21068.0,ns,3042 +free,linear object poll,,,,21195.0,ns,3081 +free,linear object poll,,,,21635.0,ns,3120 +free,linear object poll,,,,21911.0,ns,3159 +free,linear object poll,,,,22089.0,ns,3198 +free,linear object poll,,,,22847.0,ns,3237 +free,linear object poll,,,,26918.0,ns,3276 +free,linear object poll,,,,22784.0,ns,3315 +free,linear object poll,,,,23068.0,ns,3354 +free,linear object poll,,,,23256.0,ns,3393 +free,linear object poll,,,,23829.0,ns,3432 +free,linear object poll,,,,24071.0,ns,3471 +free,linear object poll,,,,24149.0,ns,3510 +free,linear object poll,,,,24437.0,ns,3549 +free,linear object poll,,,,24833.0,ns,3588 +free,linear object poll,,,,24774.0,ns,3627 +free,linear object poll,,,,25359.0,ns,3666 +free,linear object poll,,,,25413.0,ns,3705 +free,linear object poll,,,,25646.0,ns,3744 +free,linear object poll,,,,26008.0,ns,3783 +free,linear object poll,,,,26637.0,ns,3822 +free,linear object poll,,,,26532.0,ns,3861 +free,linear object poll,,,,27076.0,ns,3900 diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/sample.json new file mode 100644 index 0000000000000..24563a7b6558b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[39.0,78.0,117.0,156.0,195.0,234.0,273.0,312.0,351.0,390.0,429.0,468.0,507.0,546.0,585.0,624.0,663.0,702.0,741.0,780.0,819.0,858.0,897.0,936.0,975.0,1014.0,1053.0,1092.0,1131.0,1170.0,1209.0,1248.0,1287.0,1326.0,1365.0,1404.0,1443.0,1482.0,1521.0,1560.0,1599.0,1638.0,1677.0,1716.0,1755.0,1794.0,1833.0,1872.0,1911.0,1950.0,1989.0,2028.0,2067.0,2106.0,2145.0,2184.0,2223.0,2262.0,2301.0,2340.0,2379.0,2418.0,2457.0,2496.0,2535.0,2574.0,2613.0,2652.0,2691.0,2730.0,2769.0,2808.0,2847.0,2886.0,2925.0,2964.0,3003.0,3042.0,3081.0,3120.0,3159.0,3198.0,3237.0,3276.0,3315.0,3354.0,3393.0,3432.0,3471.0,3510.0,3549.0,3588.0,3627.0,3666.0,3705.0,3744.0,3783.0,3822.0,3861.0,3900.0],"times":[357.0,646.0,950.0,1246.0,1552.0,1866.0,2167.0,2474.0,2782.0,3081.0,3725.0,3980.0,4298.0,4655.0,4939.0,5248.0,5570.0,6007.0,6310.0,6590.0,6945.0,7301.0,7621.0,7682.0,7929.0,8333.0,8589.0,9014.0,9308.0,9650.0,9942.0,9925.0,10184.0,10446.0,10910.0,11160.0,11390.0,11778.0,12075.0,12372.0,12305.0,12662.0,12984.0,12755.0,13109.0,13405.0,13642.0,13977.0,14286.0,14599.0,14845.0,15264.0,15423.0,15222.0,15496.0,15786.0,16081.0,15940.0,16242.0,16560.0,16871.0,16560.0,16867.0,17150.0,17431.0,17574.0,17993.0,18176.0,18452.0,18701.0,19028.0,19412.0,19633.0,19692.0,20343.0,20297.0,20636.0,21068.0,21195.0,21635.0,21911.0,22089.0,22847.0,26918.0,22784.0,23068.0,23256.0,23829.0,24071.0,24149.0,24437.0,24833.0,24774.0,25359.0,25413.0,25646.0,26008.0,26637.0,26532.0,27076.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/tukey.json new file mode 100644 index 0000000000000..c08c99498fcf1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/new/tukey.json @@ -0,0 +1 @@ +[3.5441592041992998,5.224257011782072,9.704517832002796,11.384615639585569] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/MAD.svg new file mode 100644 index 0000000000000..94393269adad6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 0.9 + + + + + 1 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/linear object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/SD.svg new file mode 100644 index 0000000000000..bf0fde348cf81 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 580 + + + + + 600 + + + + + 620 + + + + + 640 + + + + + 660 + + + + + 680 + + + + + + + + + Density (a.u.) + + + + + Average time (ps) + + + + + free/linear object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/index.html new file mode 100644 index 0000000000000..571aa437c8401 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + free/linear object poll - Criterion.rs + + + + +
+

free/linear object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope7.0110 ns7.0738 ns7.1587 ns
0.68330930.68909210.6785994
Mean7.4160 ns7.5379 ns7.6630 ns
Std. Dev.573.77 ps632.33 ps684.48 ps
Median7.0769 ns7.4649 ns7.8778 ns
MAD341.18 ps835.25 ps1.0020 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/mean.svg new file mode 100644 index 0000000000000..7b3a5ec0a3e42 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 7.4 + + + + + 7.45 + + + + + 7.5 + + + + + 7.55 + + + + + 7.6 + + + + + 7.65 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/linear object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/median.svg new file mode 100644 index 0000000000000..4e8f1f4c8a1e2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/median.svg @@ -0,0 +1,308 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 7 + + + + + 7.1 + + + + + 7.2 + + + + + 7.3 + + + + + 7.4 + + + + + 7.5 + + + + + 7.6 + + + + + 7.7 + + + + + 7.8 + + + + + 7.9 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/linear object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/pdf.svg new file mode 100644 index 0000000000000..255436fd93a33 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/pdf.svg @@ -0,0 +1,410 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 6.5 + + + + + 7 + + + + + 7.5 + + + + + 8 + + + + + 8.5 + + + + + 9 + + + + + 9.5 + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/linear object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..ecd976310d846 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/pdf_small.svg @@ -0,0 +1,219 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 6.5 + + + + + 7 + + + + + 7.5 + + + + + 8 + + + + + 8.5 + + + + + 9 + + + + + 9.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/regression.svg new file mode 100644 index 0000000000000..07c17ee6954d3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/regression.svg @@ -0,0 +1,421 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.5 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 2.5 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 3.5 + + + + + + + + + + + + + 4 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + free/linear object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/regression_small.svg new file mode 100644 index 0000000000000..60386ab4abbe6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/regression_small.svg @@ -0,0 +1,399 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.5 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 2.5 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 3.5 + + + + + + + + + + + + + 4 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/slope.svg new file mode 100644 index 0000000000000..9048232866073 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/slope.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 7 + + + + + 7.02 + + + + + 7.04 + + + + + 7.06 + + + + + 7.08 + + + + + 7.1 + + + + + 7.12 + + + + + 7.14 + + + + + 7.16 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/linear object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/typical.svg new file mode 100644 index 0000000000000..97ea566b45404 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/linear object poll/report/typical.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 7 + + + + + 7.02 + + + + + 7.04 + + + + + 7.06 + + + + + 7.08 + + + + + 7.1 + + + + + 7.12 + + + + + 7.14 + + + + + 7.16 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/linear object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/benchmark.json new file mode 100644 index 0000000000000..63bd5906602e6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"free","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"free/mutex object poll","directory_name":"free/mutex object poll","title":"free/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/estimates.json new file mode 100644 index 0000000000000..deda2a0e55dcc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":25.920946855822997,"upper_bound":26.265985687570264},"point_estimate":26.107700732418554,"standard_error":0.08816609767773428},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":26.048252189694626,"upper_bound":26.205261005860706},"point_estimate":26.08933122724352,"standard_error":0.044534430268230014},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.24355404317119111,"upper_bound":0.44230888405427976},"point_estimate":0.3182442964812654,"standard_error":0.054081585030466804},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":25.884810068905075,"upper_bound":25.98530457808842},"point_estimate":25.931564805745495,"standard_error":0.02566357710918142},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.46018987697060015,"upper_bound":1.248147361217219},"point_estimate":0.8894759959672919,"standard_error":0.20226550714855288}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/raw.csv new file mode 100644 index 0000000000000..b867f83e6e287 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +free,mutex object poll,,,,15989.0,ns,667 +free,mutex object poll,,,,28435.0,ns,1334 +free,mutex object poll,,,,42045.0,ns,2001 +free,mutex object poll,,,,74443.0,ns,2668 +free,mutex object poll,,,,91083.0,ns,3335 +free,mutex object poll,,,,105852.0,ns,4002 +free,mutex object poll,,,,129724.0,ns,4669 +free,mutex object poll,,,,143701.0,ns,5336 +free,mutex object poll,,,,161266.0,ns,6003 +free,mutex object poll,,,,191038.0,ns,6670 +free,mutex object poll,,,,198867.0,ns,7337 +free,mutex object poll,,,,216775.0,ns,8004 +free,mutex object poll,,,,231816.0,ns,8671 +free,mutex object poll,,,,248677.0,ns,9338 +free,mutex object poll,,,,268466.0,ns,10005 +free,mutex object poll,,,,283544.0,ns,10672 +free,mutex object poll,,,,305008.0,ns,11339 +free,mutex object poll,,,,317880.0,ns,12006 +free,mutex object poll,,,,334894.0,ns,12673 +free,mutex object poll,,,,358123.0,ns,13340 +free,mutex object poll,,,,370867.0,ns,14007 +free,mutex object poll,,,,392270.0,ns,14674 +free,mutex object poll,,,,402793.0,ns,15341 +free,mutex object poll,,,,425245.0,ns,16008 +free,mutex object poll,,,,437620.0,ns,16675 +free,mutex object poll,,,,457467.0,ns,17342 +free,mutex object poll,,,,471107.0,ns,18009 +free,mutex object poll,,,,493605.0,ns,18676 +free,mutex object poll,,,,511188.0,ns,19343 +free,mutex object poll,,,,525118.0,ns,20010 +free,mutex object poll,,,,543016.0,ns,20677 +free,mutex object poll,,,,564120.0,ns,21344 +free,mutex object poll,,,,579526.0,ns,22011 +free,mutex object poll,,,,601641.0,ns,22678 +free,mutex object poll,,,,615728.0,ns,23345 +free,mutex object poll,,,,626470.0,ns,24012 +free,mutex object poll,,,,647840.0,ns,24679 +free,mutex object poll,,,,666357.0,ns,25346 +free,mutex object poll,,,,686911.0,ns,26013 +free,mutex object poll,,,,696069.0,ns,26680 +free,mutex object poll,,,,714779.0,ns,27347 +free,mutex object poll,,,,735601.0,ns,28014 +free,mutex object poll,,,,752542.0,ns,28681 +free,mutex object poll,,,,769072.0,ns,29348 +free,mutex object poll,,,,784958.0,ns,30015 +free,mutex object poll,,,,799274.0,ns,30682 +free,mutex object poll,,,,819328.0,ns,31349 +free,mutex object poll,,,,831856.0,ns,32016 +free,mutex object poll,,,,851518.0,ns,32683 +free,mutex object poll,,,,865636.0,ns,33350 +free,mutex object poll,,,,886237.0,ns,34017 +free,mutex object poll,,,,902278.0,ns,34684 +free,mutex object poll,,,,919943.0,ns,35351 +free,mutex object poll,,,,939009.0,ns,36018 +free,mutex object poll,,,,956330.0,ns,36685 +free,mutex object poll,,,,977495.0,ns,37352 +free,mutex object poll,,,,990289.0,ns,38019 +free,mutex object poll,,,,1015565.0,ns,38686 +free,mutex object poll,,,,1036662.0,ns,39353 +free,mutex object poll,,,,1037498.0,ns,40020 +free,mutex object poll,,,,1062608.0,ns,40687 +free,mutex object poll,,,,1088799.0,ns,41354 +free,mutex object poll,,,,1094652.0,ns,42021 +free,mutex object poll,,,,1108688.0,ns,42688 +free,mutex object poll,,,,1129516.0,ns,43355 +free,mutex object poll,,,,1143634.0,ns,44022 +free,mutex object poll,,,,1163224.0,ns,44689 +free,mutex object poll,,,,1181997.0,ns,45356 +free,mutex object poll,,,,1194406.0,ns,46023 +free,mutex object poll,,,,1218101.0,ns,46690 +free,mutex object poll,,,,1226768.0,ns,47357 +free,mutex object poll,,,,1258982.0,ns,48024 +free,mutex object poll,,,,1265570.0,ns,48691 +free,mutex object poll,,,,1293040.0,ns,49358 +free,mutex object poll,,,,1296244.0,ns,50025 +free,mutex object poll,,,,1320438.0,ns,50692 +free,mutex object poll,,,,1323521.0,ns,51359 +free,mutex object poll,,,,1348117.0,ns,52026 +free,mutex object poll,,,,1366320.0,ns,52693 +free,mutex object poll,,,,1383021.0,ns,53360 +free,mutex object poll,,,,1399235.0,ns,54027 +free,mutex object poll,,,,1407388.0,ns,54694 +free,mutex object poll,,,,1429030.0,ns,55361 +free,mutex object poll,,,,1451276.0,ns,56028 +free,mutex object poll,,,,1472364.0,ns,56695 +free,mutex object poll,,,,1476247.0,ns,57362 +free,mutex object poll,,,,1496131.0,ns,58029 +free,mutex object poll,,,,1517944.0,ns,58696 +free,mutex object poll,,,,1534545.0,ns,59363 +free,mutex object poll,,,,1541813.0,ns,60030 +free,mutex object poll,,,,1556047.0,ns,60697 +free,mutex object poll,,,,1580156.0,ns,61364 +free,mutex object poll,,,,1588677.0,ns,62031 +free,mutex object poll,,,,1615952.0,ns,62698 +free,mutex object poll,,,,1622535.0,ns,63365 +free,mutex object poll,,,,1644845.0,ns,64032 +free,mutex object poll,,,,1667679.0,ns,64699 +free,mutex object poll,,,,1681467.0,ns,65366 +free,mutex object poll,,,,1697067.0,ns,66033 +free,mutex object poll,,,,1731421.0,ns,66700 diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/sample.json new file mode 100644 index 0000000000000..a8cae0de0ebc4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[667.0,1334.0,2001.0,2668.0,3335.0,4002.0,4669.0,5336.0,6003.0,6670.0,7337.0,8004.0,8671.0,9338.0,10005.0,10672.0,11339.0,12006.0,12673.0,13340.0,14007.0,14674.0,15341.0,16008.0,16675.0,17342.0,18009.0,18676.0,19343.0,20010.0,20677.0,21344.0,22011.0,22678.0,23345.0,24012.0,24679.0,25346.0,26013.0,26680.0,27347.0,28014.0,28681.0,29348.0,30015.0,30682.0,31349.0,32016.0,32683.0,33350.0,34017.0,34684.0,35351.0,36018.0,36685.0,37352.0,38019.0,38686.0,39353.0,40020.0,40687.0,41354.0,42021.0,42688.0,43355.0,44022.0,44689.0,45356.0,46023.0,46690.0,47357.0,48024.0,48691.0,49358.0,50025.0,50692.0,51359.0,52026.0,52693.0,53360.0,54027.0,54694.0,55361.0,56028.0,56695.0,57362.0,58029.0,58696.0,59363.0,60030.0,60697.0,61364.0,62031.0,62698.0,63365.0,64032.0,64699.0,65366.0,66033.0,66700.0],"times":[15989.0,28435.0,42045.0,74443.0,91083.0,105852.0,129724.0,143701.0,161266.0,191038.0,198867.0,216775.0,231816.0,248677.0,268466.0,283544.0,305008.0,317880.0,334894.0,358123.0,370867.0,392270.0,402793.0,425245.0,437620.0,457467.0,471107.0,493605.0,511188.0,525118.0,543016.0,564120.0,579526.0,601641.0,615728.0,626470.0,647840.0,666357.0,686911.0,696069.0,714779.0,735601.0,752542.0,769072.0,784958.0,799274.0,819328.0,831856.0,851518.0,865636.0,886237.0,902278.0,919943.0,939009.0,956330.0,977495.0,990289.0,1015565.0,1036662.0,1037498.0,1062608.0,1088799.0,1094652.0,1108688.0,1129516.0,1143634.0,1163224.0,1181997.0,1194406.0,1218101.0,1226768.0,1258982.0,1265570.0,1293040.0,1296244.0,1320438.0,1323521.0,1348117.0,1366320.0,1383021.0,1399235.0,1407388.0,1429030.0,1451276.0,1472364.0,1476247.0,1496131.0,1517944.0,1534545.0,1541813.0,1556047.0,1580156.0,1588677.0,1615952.0,1622535.0,1644845.0,1667679.0,1681467.0,1697067.0,1731421.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/tukey.json new file mode 100644 index 0000000000000..7f55165432d50 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/base/tukey.json @@ -0,0 +1 @@ +[24.510526948064435,25.213816469169267,27.08925519211548,27.79254471322031] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/benchmark.json new file mode 100644 index 0000000000000..63bd5906602e6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"free","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"free/mutex object poll","directory_name":"free/mutex object poll","title":"free/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/estimates.json new file mode 100644 index 0000000000000..deda2a0e55dcc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":25.920946855822997,"upper_bound":26.265985687570264},"point_estimate":26.107700732418554,"standard_error":0.08816609767773428},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":26.048252189694626,"upper_bound":26.205261005860706},"point_estimate":26.08933122724352,"standard_error":0.044534430268230014},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.24355404317119111,"upper_bound":0.44230888405427976},"point_estimate":0.3182442964812654,"standard_error":0.054081585030466804},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":25.884810068905075,"upper_bound":25.98530457808842},"point_estimate":25.931564805745495,"standard_error":0.02566357710918142},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.46018987697060015,"upper_bound":1.248147361217219},"point_estimate":0.8894759959672919,"standard_error":0.20226550714855288}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/raw.csv new file mode 100644 index 0000000000000..b867f83e6e287 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +free,mutex object poll,,,,15989.0,ns,667 +free,mutex object poll,,,,28435.0,ns,1334 +free,mutex object poll,,,,42045.0,ns,2001 +free,mutex object poll,,,,74443.0,ns,2668 +free,mutex object poll,,,,91083.0,ns,3335 +free,mutex object poll,,,,105852.0,ns,4002 +free,mutex object poll,,,,129724.0,ns,4669 +free,mutex object poll,,,,143701.0,ns,5336 +free,mutex object poll,,,,161266.0,ns,6003 +free,mutex object poll,,,,191038.0,ns,6670 +free,mutex object poll,,,,198867.0,ns,7337 +free,mutex object poll,,,,216775.0,ns,8004 +free,mutex object poll,,,,231816.0,ns,8671 +free,mutex object poll,,,,248677.0,ns,9338 +free,mutex object poll,,,,268466.0,ns,10005 +free,mutex object poll,,,,283544.0,ns,10672 +free,mutex object poll,,,,305008.0,ns,11339 +free,mutex object poll,,,,317880.0,ns,12006 +free,mutex object poll,,,,334894.0,ns,12673 +free,mutex object poll,,,,358123.0,ns,13340 +free,mutex object poll,,,,370867.0,ns,14007 +free,mutex object poll,,,,392270.0,ns,14674 +free,mutex object poll,,,,402793.0,ns,15341 +free,mutex object poll,,,,425245.0,ns,16008 +free,mutex object poll,,,,437620.0,ns,16675 +free,mutex object poll,,,,457467.0,ns,17342 +free,mutex object poll,,,,471107.0,ns,18009 +free,mutex object poll,,,,493605.0,ns,18676 +free,mutex object poll,,,,511188.0,ns,19343 +free,mutex object poll,,,,525118.0,ns,20010 +free,mutex object poll,,,,543016.0,ns,20677 +free,mutex object poll,,,,564120.0,ns,21344 +free,mutex object poll,,,,579526.0,ns,22011 +free,mutex object poll,,,,601641.0,ns,22678 +free,mutex object poll,,,,615728.0,ns,23345 +free,mutex object poll,,,,626470.0,ns,24012 +free,mutex object poll,,,,647840.0,ns,24679 +free,mutex object poll,,,,666357.0,ns,25346 +free,mutex object poll,,,,686911.0,ns,26013 +free,mutex object poll,,,,696069.0,ns,26680 +free,mutex object poll,,,,714779.0,ns,27347 +free,mutex object poll,,,,735601.0,ns,28014 +free,mutex object poll,,,,752542.0,ns,28681 +free,mutex object poll,,,,769072.0,ns,29348 +free,mutex object poll,,,,784958.0,ns,30015 +free,mutex object poll,,,,799274.0,ns,30682 +free,mutex object poll,,,,819328.0,ns,31349 +free,mutex object poll,,,,831856.0,ns,32016 +free,mutex object poll,,,,851518.0,ns,32683 +free,mutex object poll,,,,865636.0,ns,33350 +free,mutex object poll,,,,886237.0,ns,34017 +free,mutex object poll,,,,902278.0,ns,34684 +free,mutex object poll,,,,919943.0,ns,35351 +free,mutex object poll,,,,939009.0,ns,36018 +free,mutex object poll,,,,956330.0,ns,36685 +free,mutex object poll,,,,977495.0,ns,37352 +free,mutex object poll,,,,990289.0,ns,38019 +free,mutex object poll,,,,1015565.0,ns,38686 +free,mutex object poll,,,,1036662.0,ns,39353 +free,mutex object poll,,,,1037498.0,ns,40020 +free,mutex object poll,,,,1062608.0,ns,40687 +free,mutex object poll,,,,1088799.0,ns,41354 +free,mutex object poll,,,,1094652.0,ns,42021 +free,mutex object poll,,,,1108688.0,ns,42688 +free,mutex object poll,,,,1129516.0,ns,43355 +free,mutex object poll,,,,1143634.0,ns,44022 +free,mutex object poll,,,,1163224.0,ns,44689 +free,mutex object poll,,,,1181997.0,ns,45356 +free,mutex object poll,,,,1194406.0,ns,46023 +free,mutex object poll,,,,1218101.0,ns,46690 +free,mutex object poll,,,,1226768.0,ns,47357 +free,mutex object poll,,,,1258982.0,ns,48024 +free,mutex object poll,,,,1265570.0,ns,48691 +free,mutex object poll,,,,1293040.0,ns,49358 +free,mutex object poll,,,,1296244.0,ns,50025 +free,mutex object poll,,,,1320438.0,ns,50692 +free,mutex object poll,,,,1323521.0,ns,51359 +free,mutex object poll,,,,1348117.0,ns,52026 +free,mutex object poll,,,,1366320.0,ns,52693 +free,mutex object poll,,,,1383021.0,ns,53360 +free,mutex object poll,,,,1399235.0,ns,54027 +free,mutex object poll,,,,1407388.0,ns,54694 +free,mutex object poll,,,,1429030.0,ns,55361 +free,mutex object poll,,,,1451276.0,ns,56028 +free,mutex object poll,,,,1472364.0,ns,56695 +free,mutex object poll,,,,1476247.0,ns,57362 +free,mutex object poll,,,,1496131.0,ns,58029 +free,mutex object poll,,,,1517944.0,ns,58696 +free,mutex object poll,,,,1534545.0,ns,59363 +free,mutex object poll,,,,1541813.0,ns,60030 +free,mutex object poll,,,,1556047.0,ns,60697 +free,mutex object poll,,,,1580156.0,ns,61364 +free,mutex object poll,,,,1588677.0,ns,62031 +free,mutex object poll,,,,1615952.0,ns,62698 +free,mutex object poll,,,,1622535.0,ns,63365 +free,mutex object poll,,,,1644845.0,ns,64032 +free,mutex object poll,,,,1667679.0,ns,64699 +free,mutex object poll,,,,1681467.0,ns,65366 +free,mutex object poll,,,,1697067.0,ns,66033 +free,mutex object poll,,,,1731421.0,ns,66700 diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/sample.json new file mode 100644 index 0000000000000..a8cae0de0ebc4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[667.0,1334.0,2001.0,2668.0,3335.0,4002.0,4669.0,5336.0,6003.0,6670.0,7337.0,8004.0,8671.0,9338.0,10005.0,10672.0,11339.0,12006.0,12673.0,13340.0,14007.0,14674.0,15341.0,16008.0,16675.0,17342.0,18009.0,18676.0,19343.0,20010.0,20677.0,21344.0,22011.0,22678.0,23345.0,24012.0,24679.0,25346.0,26013.0,26680.0,27347.0,28014.0,28681.0,29348.0,30015.0,30682.0,31349.0,32016.0,32683.0,33350.0,34017.0,34684.0,35351.0,36018.0,36685.0,37352.0,38019.0,38686.0,39353.0,40020.0,40687.0,41354.0,42021.0,42688.0,43355.0,44022.0,44689.0,45356.0,46023.0,46690.0,47357.0,48024.0,48691.0,49358.0,50025.0,50692.0,51359.0,52026.0,52693.0,53360.0,54027.0,54694.0,55361.0,56028.0,56695.0,57362.0,58029.0,58696.0,59363.0,60030.0,60697.0,61364.0,62031.0,62698.0,63365.0,64032.0,64699.0,65366.0,66033.0,66700.0],"times":[15989.0,28435.0,42045.0,74443.0,91083.0,105852.0,129724.0,143701.0,161266.0,191038.0,198867.0,216775.0,231816.0,248677.0,268466.0,283544.0,305008.0,317880.0,334894.0,358123.0,370867.0,392270.0,402793.0,425245.0,437620.0,457467.0,471107.0,493605.0,511188.0,525118.0,543016.0,564120.0,579526.0,601641.0,615728.0,626470.0,647840.0,666357.0,686911.0,696069.0,714779.0,735601.0,752542.0,769072.0,784958.0,799274.0,819328.0,831856.0,851518.0,865636.0,886237.0,902278.0,919943.0,939009.0,956330.0,977495.0,990289.0,1015565.0,1036662.0,1037498.0,1062608.0,1088799.0,1094652.0,1108688.0,1129516.0,1143634.0,1163224.0,1181997.0,1194406.0,1218101.0,1226768.0,1258982.0,1265570.0,1293040.0,1296244.0,1320438.0,1323521.0,1348117.0,1366320.0,1383021.0,1399235.0,1407388.0,1429030.0,1451276.0,1472364.0,1476247.0,1496131.0,1517944.0,1534545.0,1541813.0,1556047.0,1580156.0,1588677.0,1615952.0,1622535.0,1644845.0,1667679.0,1681467.0,1697067.0,1731421.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/tukey.json new file mode 100644 index 0000000000000..7f55165432d50 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/new/tukey.json @@ -0,0 +1 @@ +[24.510526948064435,25.213816469169267,27.08925519211548,27.79254471322031] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/MAD.svg new file mode 100644 index 0000000000000..8268b3d2720fd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 0.009 + + + + + 250 + + + + + 300 + + + + + 350 + + + + + 400 + + + + + 450 + + + + + + + + + Density (a.u.) + + + + + Average time (ps) + + + + + free/mutex object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/SD.svg new file mode 100644 index 0000000000000..15ea4796ac5f4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/SD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 0.9 + + + + + 1 + + + + + 1.1 + + + + + 1.2 + + + + + 1.3 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/mutex object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/index.html new file mode 100644 index 0000000000000..9604124c5938e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + free/mutex object poll - Criterion.rs + + + + +
+

free/mutex object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope25.885 ns25.932 ns25.985 ns
0.98928710.98972770.9891457
Mean25.921 ns26.108 ns26.266 ns
Std. Dev.460.19 ps889.48 ps1.2481 ns
Median26.048 ns26.089 ns26.205 ns
MAD243.55 ps318.24 ps442.31 ps
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/mean.svg new file mode 100644 index 0000000000000..325ddb5a9dcf3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/mean.svg @@ -0,0 +1,323 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 4 + + + + + 4.5 + + + + + 5 + + + + + 25.9 + + + + + 25.95 + + + + + 26 + + + + + 26.05 + + + + + 26.1 + + + + + 26.15 + + + + + 26.2 + + + + + 26.25 + + + + + 26.3 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/mutex object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/median.svg new file mode 100644 index 0000000000000..72a587045f9e6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/median.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 26.04 + + + + + 26.06 + + + + + 26.08 + + + + + 26.1 + + + + + 26.12 + + + + + 26.14 + + + + + 26.16 + + + + + 26.18 + + + + + 26.2 + + + + + 26.22 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/mutex object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/pdf.svg new file mode 100644 index 0000000000000..4a5075b64dfac --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/pdf.svg @@ -0,0 +1,445 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 20 + + + + + 21 + + + + + 22 + + + + + 23 + + + + + 24 + + + + + 25 + + + + + 26 + + + + + 27 + + + + + 28 + + + + + 29 + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/mutex object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..490816a9da0ec --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/pdf_small.svg @@ -0,0 +1,239 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 20 + + + + + 21 + + + + + 22 + + + + + 23 + + + + + 24 + + + + + 25 + + + + + 26 + + + + + 27 + + + + + 28 + + + + + 29 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/regression.svg new file mode 100644 index 0000000000000..a34da4cac3a13 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/regression.svg @@ -0,0 +1,447 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.2 + + + + + + + + + + + + + 0.4 + + + + + + + + + + + + + 0.6 + + + + + + + + + + + + + 0.8 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.2 + + + + + + + + + + + + + 1.4 + + + + + + + + + + + + + 1.6 + + + + + + + + + + + + + 1.8 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + free/mutex object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/regression_small.svg new file mode 100644 index 0000000000000..a136e779e68f4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/regression_small.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.2 + + + + + + + + + + + + + 0.4 + + + + + + + + + + + + + 0.6 + + + + + + + + + + + + + 0.8 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.2 + + + + + + + + + + + + + 1.4 + + + + + + + + + + + + + 1.6 + + + + + + + + + + + + + 1.8 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/slope.svg new file mode 100644 index 0000000000000..9506f89f22d8e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/slope.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 25.88 + + + + + 25.9 + + + + + 25.92 + + + + + 25.94 + + + + + 25.96 + + + + + 25.98 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/mutex object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/typical.svg new file mode 100644 index 0000000000000..4a4a30d28e326 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/mutex object poll/report/typical.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 25.88 + + + + + 25.9 + + + + + 25.92 + + + + + 25.94 + + + + + 25.96 + + + + + 25.98 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/mutex object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/benchmark.json new file mode 100644 index 0000000000000..c6c4916cdd1ae --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"free","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"free/none object poll","directory_name":"free/none object poll","title":"free/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/estimates.json new file mode 100644 index 0000000000000..49591b7f0d6fb --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":103.92720532830832,"upper_bound":119.49044076560052},"point_estimate":111.80773794070086,"standard_error":3.970582172313974},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":109.9337962962963,"upper_bound":132.29867803311095},"point_estimate":122.6802251197375,"standard_error":5.543826372265346},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":29.347267220911863,"upper_bound":55.44749270062825},"point_estimate":41.46121741091416,"standard_error":6.588898651786779},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":117.95659436935281,"upper_bound":135.02592171361863},"point_estimate":126.86045352100018,"standard_error":4.3716516408153785},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":34.631271858169654,"upper_bound":44.346469437821234},"point_estimate":39.9428539720069,"standard_error":2.4707997074950954}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/raw.csv new file mode 100644 index 0000000000000..b9a73c5e6ad3f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +free,none object poll,,,,16744.0,ns,684 +free,none object poll,,,,35990.0,ns,1368 +free,none object poll,,,,53947.0,ns,2052 +free,none object poll,,,,77841.0,ns,2736 +free,none object poll,,,,88066.0,ns,3420 +free,none object poll,,,,107780.0,ns,4104 +free,none object poll,,,,123331.0,ns,4788 +free,none object poll,,,,141243.0,ns,5472 +free,none object poll,,,,161246.0,ns,6156 +free,none object poll,,,,634428.0,ns,6840 +free,none object poll,,,,1111509.0,ns,7524 +free,none object poll,,,,609172.0,ns,8208 +free,none object poll,,,,651054.0,ns,8892 +free,none object poll,,,,669567.0,ns,9576 +free,none object poll,,,,720077.0,ns,10260 +free,none object poll,,,,752361.0,ns,10944 +free,none object poll,,,,1395855.0,ns,11628 +free,none object poll,,,,1528077.0,ns,12312 +free,none object poll,,,,1694836.0,ns,12996 +free,none object poll,,,,1855059.0,ns,13680 +free,none object poll,,,,2052299.0,ns,14364 +free,none object poll,,,,2478538.0,ns,15048 +free,none object poll,,,,2434469.0,ns,15732 +free,none object poll,,,,1178798.0,ns,16416 +free,none object poll,,,,1222240.0,ns,17100 +free,none object poll,,,,1277367.0,ns,17784 +free,none object poll,,,,1337474.0,ns,18468 +free,none object poll,,,,1371692.0,ns,19152 +free,none object poll,,,,1985805.0,ns,19836 +free,none object poll,,,,2140662.0,ns,20520 +free,none object poll,,,,2329016.0,ns,21204 +free,none object poll,,,,2485673.0,ns,21888 +free,none object poll,,,,2727228.0,ns,22572 +free,none object poll,,,,2841475.0,ns,23256 +free,none object poll,,,,3011986.0,ns,23940 +free,none object poll,,,,3225557.0,ns,24624 +free,none object poll,,,,3370228.0,ns,25308 +free,none object poll,,,,3562407.0,ns,25992 +free,none object poll,,,,3740332.0,ns,26676 +free,none object poll,,,,3907891.0,ns,27360 +free,none object poll,,,,4062806.0,ns,28044 +free,none object poll,,,,4353190.0,ns,28728 +free,none object poll,,,,4426290.0,ns,29412 +free,none object poll,,,,4602717.0,ns,30096 +free,none object poll,,,,4781805.0,ns,30780 +free,none object poll,,,,4921351.0,ns,31464 +free,none object poll,,,,5168343.0,ns,32148 +free,none object poll,,,,2418847.0,ns,32832 +free,none object poll,,,,2469767.0,ns,33516 +free,none object poll,,,,2508756.0,ns,34200 +free,none object poll,,,,2561818.0,ns,34884 +free,none object poll,,,,2617925.0,ns,35568 +free,none object poll,,,,3265802.0,ns,36252 +free,none object poll,,,,3449439.0,ns,36936 +free,none object poll,,,,3586596.0,ns,37620 +free,none object poll,,,,3751720.0,ns,38304 +free,none object poll,,,,3969778.0,ns,38988 +free,none object poll,,,,4132094.0,ns,39672 +free,none object poll,,,,4321062.0,ns,40356 +free,none object poll,,,,4511683.0,ns,41040 +free,none object poll,,,,4632155.0,ns,41724 +free,none object poll,,,,4823775.0,ns,42408 +free,none object poll,,,,5010248.0,ns,43092 +free,none object poll,,,,5329095.0,ns,43776 +free,none object poll,,,,5476494.0,ns,44460 +free,none object poll,,,,5509778.0,ns,45144 +free,none object poll,,,,5746513.0,ns,45828 +free,none object poll,,,,5883420.0,ns,46512 +free,none object poll,,,,6106006.0,ns,47196 +free,none object poll,,,,6258480.0,ns,47880 +free,none object poll,,,,6424953.0,ns,48564 +free,none object poll,,,,6619833.0,ns,49248 +free,none object poll,,,,6981148.0,ns,49932 +free,none object poll,,,,6996246.0,ns,50616 +free,none object poll,,,,7167748.0,ns,51300 +free,none object poll,,,,7318798.0,ns,51984 +free,none object poll,,,,7518426.0,ns,52668 +free,none object poll,,,,7668844.0,ns,53352 +free,none object poll,,,,7796081.0,ns,54036 +free,none object poll,,,,8064181.0,ns,54720 +free,none object poll,,,,8089235.0,ns,55404 +free,none object poll,,,,8274763.0,ns,56088 +free,none object poll,,,,8405473.0,ns,56772 +free,none object poll,,,,8573695.0,ns,57456 +free,none object poll,,,,8767408.0,ns,58140 +free,none object poll,,,,8899031.0,ns,58824 +free,none object poll,,,,9166720.0,ns,59508 +free,none object poll,,,,9259346.0,ns,60192 +free,none object poll,,,,9540738.0,ns,60876 +free,none object poll,,,,9533938.0,ns,61560 +free,none object poll,,,,9724465.0,ns,62244 +free,none object poll,,,,9852429.0,ns,62928 +free,none object poll,,,,9974904.0,ns,63612 +free,none object poll,,,,10183948.0,ns,64296 +free,none object poll,,,,10269845.0,ns,64980 +free,none object poll,,,,4911662.0,ns,65664 +free,none object poll,,,,4968954.0,ns,66348 +free,none object poll,,,,5005119.0,ns,67032 +free,none object poll,,,,5061314.0,ns,67716 +free,none object poll,,,,5155662.0,ns,68400 diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/sample.json new file mode 100644 index 0000000000000..d4bb2a18d55d1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[684.0,1368.0,2052.0,2736.0,3420.0,4104.0,4788.0,5472.0,6156.0,6840.0,7524.0,8208.0,8892.0,9576.0,10260.0,10944.0,11628.0,12312.0,12996.0,13680.0,14364.0,15048.0,15732.0,16416.0,17100.0,17784.0,18468.0,19152.0,19836.0,20520.0,21204.0,21888.0,22572.0,23256.0,23940.0,24624.0,25308.0,25992.0,26676.0,27360.0,28044.0,28728.0,29412.0,30096.0,30780.0,31464.0,32148.0,32832.0,33516.0,34200.0,34884.0,35568.0,36252.0,36936.0,37620.0,38304.0,38988.0,39672.0,40356.0,41040.0,41724.0,42408.0,43092.0,43776.0,44460.0,45144.0,45828.0,46512.0,47196.0,47880.0,48564.0,49248.0,49932.0,50616.0,51300.0,51984.0,52668.0,53352.0,54036.0,54720.0,55404.0,56088.0,56772.0,57456.0,58140.0,58824.0,59508.0,60192.0,60876.0,61560.0,62244.0,62928.0,63612.0,64296.0,64980.0,65664.0,66348.0,67032.0,67716.0,68400.0],"times":[16744.0,35990.0,53947.0,77841.0,88066.0,107780.0,123331.0,141243.0,161246.0,634428.0,1111509.0,609172.0,651054.0,669567.0,720077.0,752361.0,1395855.0,1528077.0,1694836.0,1855059.0,2052299.0,2478538.0,2434469.0,1178798.0,1222240.0,1277367.0,1337474.0,1371692.0,1985805.0,2140662.0,2329016.0,2485673.0,2727228.0,2841475.0,3011986.0,3225557.0,3370228.0,3562407.0,3740332.0,3907891.0,4062806.0,4353190.0,4426290.0,4602717.0,4781805.0,4921351.0,5168343.0,2418847.0,2469767.0,2508756.0,2561818.0,2617925.0,3265802.0,3449439.0,3586596.0,3751720.0,3969778.0,4132094.0,4321062.0,4511683.0,4632155.0,4823775.0,5010248.0,5329095.0,5476494.0,5509778.0,5746513.0,5883420.0,6106006.0,6258480.0,6424953.0,6619833.0,6981148.0,6996246.0,7167748.0,7318798.0,7518426.0,7668844.0,7796081.0,8064181.0,8089235.0,8274763.0,8405473.0,8573695.0,8767408.0,8899031.0,9166720.0,9259346.0,9540738.0,9533938.0,9724465.0,9852429.0,9974904.0,10183948.0,10269845.0,4911662.0,4968954.0,5005119.0,5061314.0,5155662.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/tukey.json new file mode 100644 index 0000000000000..3c45d907edfb3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/base/tukey.json @@ -0,0 +1 @@ +[-136.5692917477167,-30.922475849681746,250.80236654507814,356.4491824431131] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/benchmark.json new file mode 100644 index 0000000000000..c6c4916cdd1ae --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"free","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"free/none object poll","directory_name":"free/none object poll","title":"free/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/estimates.json new file mode 100644 index 0000000000000..49591b7f0d6fb --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":103.92720532830832,"upper_bound":119.49044076560052},"point_estimate":111.80773794070086,"standard_error":3.970582172313974},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":109.9337962962963,"upper_bound":132.29867803311095},"point_estimate":122.6802251197375,"standard_error":5.543826372265346},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":29.347267220911863,"upper_bound":55.44749270062825},"point_estimate":41.46121741091416,"standard_error":6.588898651786779},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":117.95659436935281,"upper_bound":135.02592171361863},"point_estimate":126.86045352100018,"standard_error":4.3716516408153785},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":34.631271858169654,"upper_bound":44.346469437821234},"point_estimate":39.9428539720069,"standard_error":2.4707997074950954}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/raw.csv new file mode 100644 index 0000000000000..b9a73c5e6ad3f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +free,none object poll,,,,16744.0,ns,684 +free,none object poll,,,,35990.0,ns,1368 +free,none object poll,,,,53947.0,ns,2052 +free,none object poll,,,,77841.0,ns,2736 +free,none object poll,,,,88066.0,ns,3420 +free,none object poll,,,,107780.0,ns,4104 +free,none object poll,,,,123331.0,ns,4788 +free,none object poll,,,,141243.0,ns,5472 +free,none object poll,,,,161246.0,ns,6156 +free,none object poll,,,,634428.0,ns,6840 +free,none object poll,,,,1111509.0,ns,7524 +free,none object poll,,,,609172.0,ns,8208 +free,none object poll,,,,651054.0,ns,8892 +free,none object poll,,,,669567.0,ns,9576 +free,none object poll,,,,720077.0,ns,10260 +free,none object poll,,,,752361.0,ns,10944 +free,none object poll,,,,1395855.0,ns,11628 +free,none object poll,,,,1528077.0,ns,12312 +free,none object poll,,,,1694836.0,ns,12996 +free,none object poll,,,,1855059.0,ns,13680 +free,none object poll,,,,2052299.0,ns,14364 +free,none object poll,,,,2478538.0,ns,15048 +free,none object poll,,,,2434469.0,ns,15732 +free,none object poll,,,,1178798.0,ns,16416 +free,none object poll,,,,1222240.0,ns,17100 +free,none object poll,,,,1277367.0,ns,17784 +free,none object poll,,,,1337474.0,ns,18468 +free,none object poll,,,,1371692.0,ns,19152 +free,none object poll,,,,1985805.0,ns,19836 +free,none object poll,,,,2140662.0,ns,20520 +free,none object poll,,,,2329016.0,ns,21204 +free,none object poll,,,,2485673.0,ns,21888 +free,none object poll,,,,2727228.0,ns,22572 +free,none object poll,,,,2841475.0,ns,23256 +free,none object poll,,,,3011986.0,ns,23940 +free,none object poll,,,,3225557.0,ns,24624 +free,none object poll,,,,3370228.0,ns,25308 +free,none object poll,,,,3562407.0,ns,25992 +free,none object poll,,,,3740332.0,ns,26676 +free,none object poll,,,,3907891.0,ns,27360 +free,none object poll,,,,4062806.0,ns,28044 +free,none object poll,,,,4353190.0,ns,28728 +free,none object poll,,,,4426290.0,ns,29412 +free,none object poll,,,,4602717.0,ns,30096 +free,none object poll,,,,4781805.0,ns,30780 +free,none object poll,,,,4921351.0,ns,31464 +free,none object poll,,,,5168343.0,ns,32148 +free,none object poll,,,,2418847.0,ns,32832 +free,none object poll,,,,2469767.0,ns,33516 +free,none object poll,,,,2508756.0,ns,34200 +free,none object poll,,,,2561818.0,ns,34884 +free,none object poll,,,,2617925.0,ns,35568 +free,none object poll,,,,3265802.0,ns,36252 +free,none object poll,,,,3449439.0,ns,36936 +free,none object poll,,,,3586596.0,ns,37620 +free,none object poll,,,,3751720.0,ns,38304 +free,none object poll,,,,3969778.0,ns,38988 +free,none object poll,,,,4132094.0,ns,39672 +free,none object poll,,,,4321062.0,ns,40356 +free,none object poll,,,,4511683.0,ns,41040 +free,none object poll,,,,4632155.0,ns,41724 +free,none object poll,,,,4823775.0,ns,42408 +free,none object poll,,,,5010248.0,ns,43092 +free,none object poll,,,,5329095.0,ns,43776 +free,none object poll,,,,5476494.0,ns,44460 +free,none object poll,,,,5509778.0,ns,45144 +free,none object poll,,,,5746513.0,ns,45828 +free,none object poll,,,,5883420.0,ns,46512 +free,none object poll,,,,6106006.0,ns,47196 +free,none object poll,,,,6258480.0,ns,47880 +free,none object poll,,,,6424953.0,ns,48564 +free,none object poll,,,,6619833.0,ns,49248 +free,none object poll,,,,6981148.0,ns,49932 +free,none object poll,,,,6996246.0,ns,50616 +free,none object poll,,,,7167748.0,ns,51300 +free,none object poll,,,,7318798.0,ns,51984 +free,none object poll,,,,7518426.0,ns,52668 +free,none object poll,,,,7668844.0,ns,53352 +free,none object poll,,,,7796081.0,ns,54036 +free,none object poll,,,,8064181.0,ns,54720 +free,none object poll,,,,8089235.0,ns,55404 +free,none object poll,,,,8274763.0,ns,56088 +free,none object poll,,,,8405473.0,ns,56772 +free,none object poll,,,,8573695.0,ns,57456 +free,none object poll,,,,8767408.0,ns,58140 +free,none object poll,,,,8899031.0,ns,58824 +free,none object poll,,,,9166720.0,ns,59508 +free,none object poll,,,,9259346.0,ns,60192 +free,none object poll,,,,9540738.0,ns,60876 +free,none object poll,,,,9533938.0,ns,61560 +free,none object poll,,,,9724465.0,ns,62244 +free,none object poll,,,,9852429.0,ns,62928 +free,none object poll,,,,9974904.0,ns,63612 +free,none object poll,,,,10183948.0,ns,64296 +free,none object poll,,,,10269845.0,ns,64980 +free,none object poll,,,,4911662.0,ns,65664 +free,none object poll,,,,4968954.0,ns,66348 +free,none object poll,,,,5005119.0,ns,67032 +free,none object poll,,,,5061314.0,ns,67716 +free,none object poll,,,,5155662.0,ns,68400 diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/sample.json new file mode 100644 index 0000000000000..d4bb2a18d55d1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[684.0,1368.0,2052.0,2736.0,3420.0,4104.0,4788.0,5472.0,6156.0,6840.0,7524.0,8208.0,8892.0,9576.0,10260.0,10944.0,11628.0,12312.0,12996.0,13680.0,14364.0,15048.0,15732.0,16416.0,17100.0,17784.0,18468.0,19152.0,19836.0,20520.0,21204.0,21888.0,22572.0,23256.0,23940.0,24624.0,25308.0,25992.0,26676.0,27360.0,28044.0,28728.0,29412.0,30096.0,30780.0,31464.0,32148.0,32832.0,33516.0,34200.0,34884.0,35568.0,36252.0,36936.0,37620.0,38304.0,38988.0,39672.0,40356.0,41040.0,41724.0,42408.0,43092.0,43776.0,44460.0,45144.0,45828.0,46512.0,47196.0,47880.0,48564.0,49248.0,49932.0,50616.0,51300.0,51984.0,52668.0,53352.0,54036.0,54720.0,55404.0,56088.0,56772.0,57456.0,58140.0,58824.0,59508.0,60192.0,60876.0,61560.0,62244.0,62928.0,63612.0,64296.0,64980.0,65664.0,66348.0,67032.0,67716.0,68400.0],"times":[16744.0,35990.0,53947.0,77841.0,88066.0,107780.0,123331.0,141243.0,161246.0,634428.0,1111509.0,609172.0,651054.0,669567.0,720077.0,752361.0,1395855.0,1528077.0,1694836.0,1855059.0,2052299.0,2478538.0,2434469.0,1178798.0,1222240.0,1277367.0,1337474.0,1371692.0,1985805.0,2140662.0,2329016.0,2485673.0,2727228.0,2841475.0,3011986.0,3225557.0,3370228.0,3562407.0,3740332.0,3907891.0,4062806.0,4353190.0,4426290.0,4602717.0,4781805.0,4921351.0,5168343.0,2418847.0,2469767.0,2508756.0,2561818.0,2617925.0,3265802.0,3449439.0,3586596.0,3751720.0,3969778.0,4132094.0,4321062.0,4511683.0,4632155.0,4823775.0,5010248.0,5329095.0,5476494.0,5509778.0,5746513.0,5883420.0,6106006.0,6258480.0,6424953.0,6619833.0,6981148.0,6996246.0,7167748.0,7318798.0,7518426.0,7668844.0,7796081.0,8064181.0,8089235.0,8274763.0,8405473.0,8573695.0,8767408.0,8899031.0,9166720.0,9259346.0,9540738.0,9533938.0,9724465.0,9852429.0,9974904.0,10183948.0,10269845.0,4911662.0,4968954.0,5005119.0,5061314.0,5155662.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/tukey.json new file mode 100644 index 0000000000000..3c45d907edfb3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/new/tukey.json @@ -0,0 +1 @@ +[-136.5692917477167,-30.922475849681746,250.80236654507814,356.4491824431131] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/MAD.svg new file mode 100644 index 0000000000000..76d9b9f664a01 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/MAD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 30 + + + + + 35 + + + + + 40 + + + + + 45 + + + + + 50 + + + + + 55 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/none object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/SD.svg new file mode 100644 index 0000000000000..ceca2f7e10d77 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 0.16 + + + + + 34 + + + + + 36 + + + + + 38 + + + + + 40 + + + + + 42 + + + + + 44 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/none object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/index.html new file mode 100644 index 0000000000000..989ce9610d695 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + free/none object poll - Criterion.rs + + + + +
+

free/none object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope117.96 ns126.86 ns135.03 ns
0.00479700.00520510.0048575
Mean103.93 ns111.81 ns119.49 ns
Std. Dev.34.631 ns39.943 ns44.346 ns
Median109.93 ns122.68 ns132.30 ns
MAD29.347 ns41.461 ns55.447 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/mean.svg new file mode 100644 index 0000000000000..52129d4aa6da6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/mean.svg @@ -0,0 +1,323 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 0.08 + + + + + 0.09 + + + + + 0.1 + + + + + 104 + + + + + 106 + + + + + 108 + + + + + 110 + + + + + 112 + + + + + 114 + + + + + 116 + + + + + 118 + + + + + 120 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/none object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/median.svg new file mode 100644 index 0000000000000..b196372cdc50a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/median.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 0.16 + + + + + 110 + + + + + 115 + + + + + 120 + + + + + 125 + + + + + 130 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/none object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/pdf.svg new file mode 100644 index 0000000000000..73c8d80fced91 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/pdf.svg @@ -0,0 +1,390 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 0 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/none object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..6276e2e29bf9d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/pdf_small.svg @@ -0,0 +1,199 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/regression.svg new file mode 100644 index 0000000000000..207f46ac49754 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/regression.svg @@ -0,0 +1,408 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + free/none object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/regression_small.svg new file mode 100644 index 0000000000000..64f5a3c9ec8a6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/regression_small.svg @@ -0,0 +1,386 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/slope.svg new file mode 100644 index 0000000000000..d5c1c29417d25 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/slope.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 0.08 + + + + + 0.09 + + + + + 0.1 + + + + + 120 + + + + + 125 + + + + + 130 + + + + + 135 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/none object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/typical.svg new file mode 100644 index 0000000000000..2e41ad3bdd9cf --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/none object poll/report/typical.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 0.08 + + + + + 0.09 + + + + + 0.1 + + + + + 120 + + + + + 125 + + + + + 130 + + + + + 135 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/none object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/report/index.html b/vendor/lockfree-object-pool/benches/criterion/free/report/index.html new file mode 100644 index 0000000000000..d9c85231d953b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/report/index.html @@ -0,0 +1,208 @@ + + + + + + free Summary - Criterion.rs + + + + +
+

free

+

Violin Plot

+ + Violin Plot + +

This chart shows the relationship between function/parameter and iteration time. The thickness of the shaded + region indicates the probability that a measurement of the given function/parameter would take a particular + length of time.

+
+ +

free/crate 'object-pool'

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

free/crate 'sharded-slab'

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

free/linear object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

free/mutex object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

free/none object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

free/spin_lock object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/report/violin.svg b/vendor/lockfree-object-pool/benches/criterion/free/report/violin.svg new file mode 100644 index 0000000000000..b63f1f637b35e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/report/violin.svg @@ -0,0 +1,617 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + free/spin_lock object poll + + + + + free/none object poll + + + + + free/mutex object poll + + + + + free/linear object poll + + + + + free/crate 'sharded-slab' + + + + + free/crate 'object-pool' + + + + + + + + + + + + + -50 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 150 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 250 + + + + + + + + + Input + + + + + Average time (ns) + + + + + free: Violin plot + + + + + PDF + + + PDF + + + + + + + + + + gnuplot_plot_2 + + + + + + + gnuplot_plot_3 + + + + + + + gnuplot_plot_4 + + + + + + + gnuplot_plot_5 + + + + + + + gnuplot_plot_6 + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/benchmark.json new file mode 100644 index 0000000000000..5545c0534f58f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"free","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"free/spin_lock object poll","directory_name":"free/spin_lock object poll","title":"free/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/estimates.json new file mode 100644 index 0000000000000..fd5dbc50a432c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":22.24467572616933,"upper_bound":22.615943048485},"point_estimate":22.44064366554603,"standard_error":0.09446219547073749},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":22.413927978323574,"upper_bound":22.525385270139623},"point_estimate":22.475904657632192,"standard_error":0.03017324592663187},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.2680207223245133,"upper_bound":0.48205826900197246},"point_estimate":0.3805443510860128,"standard_error":0.05639882640440274},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":22.211754406584905,"upper_bound":22.376493648851582},"point_estimate":22.282241091776783,"standard_error":0.04231343645051745},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.5164851442270315,"upper_bound":1.3162438157684764},"point_estimate":0.955249182084287,"standard_error":0.20339770183690095}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/raw.csv new file mode 100644 index 0000000000000..d6fb22240cebc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +free,spin_lock object poll,,,,13308.0,ns,673 +free,spin_lock object poll,,,,23714.0,ns,1346 +free,spin_lock object poll,,,,34719.0,ns,2019 +free,spin_lock object poll,,,,61380.0,ns,2692 +free,spin_lock object poll,,,,79407.0,ns,3365 +free,spin_lock object poll,,,,103913.0,ns,4038 +free,spin_lock object poll,,,,106714.0,ns,4711 +free,spin_lock object poll,,,,121122.0,ns,5384 +free,spin_lock object poll,,,,145760.0,ns,6057 +free,spin_lock object poll,,,,157946.0,ns,6730 +free,spin_lock object poll,,,,167935.0,ns,7403 +free,spin_lock object poll,,,,188975.0,ns,8076 +free,spin_lock object poll,,,,203066.0,ns,8749 +free,spin_lock object poll,,,,220759.0,ns,9422 +free,spin_lock object poll,,,,250722.0,ns,10095 +free,spin_lock object poll,,,,247015.0,ns,10768 +free,spin_lock object poll,,,,262136.0,ns,11441 +free,spin_lock object poll,,,,276471.0,ns,12114 +free,spin_lock object poll,,,,291027.0,ns,12787 +free,spin_lock object poll,,,,309163.0,ns,13460 +free,spin_lock object poll,,,,321494.0,ns,14133 +free,spin_lock object poll,,,,335407.0,ns,14806 +free,spin_lock object poll,,,,349112.0,ns,15479 +free,spin_lock object poll,,,,371401.0,ns,16152 +free,spin_lock object poll,,,,383066.0,ns,16825 +free,spin_lock object poll,,,,395206.0,ns,17498 +free,spin_lock object poll,,,,412310.0,ns,18171 +free,spin_lock object poll,,,,429954.0,ns,18844 +free,spin_lock object poll,,,,444336.0,ns,19517 +free,spin_lock object poll,,,,455718.0,ns,20190 +free,spin_lock object poll,,,,473586.0,ns,20863 +free,spin_lock object poll,,,,484250.0,ns,21536 +free,spin_lock object poll,,,,509623.0,ns,22209 +free,spin_lock object poll,,,,519589.0,ns,22882 +free,spin_lock object poll,,,,536018.0,ns,23555 +free,spin_lock object poll,,,,547038.0,ns,24228 +free,spin_lock object poll,,,,558936.0,ns,24901 +free,spin_lock object poll,,,,574758.0,ns,25574 +free,spin_lock object poll,,,,593671.0,ns,26247 +free,spin_lock object poll,,,,609137.0,ns,26920 +free,spin_lock object poll,,,,623913.0,ns,27593 +free,spin_lock object poll,,,,635349.0,ns,28266 +free,spin_lock object poll,,,,644942.0,ns,28939 +free,spin_lock object poll,,,,666071.0,ns,29612 +free,spin_lock object poll,,,,680867.0,ns,30285 +free,spin_lock object poll,,,,694978.0,ns,30958 +free,spin_lock object poll,,,,709344.0,ns,31631 +free,spin_lock object poll,,,,722402.0,ns,32304 +free,spin_lock object poll,,,,737011.0,ns,32977 +free,spin_lock object poll,,,,753991.0,ns,33650 +free,spin_lock object poll,,,,772047.0,ns,34323 +free,spin_lock object poll,,,,784710.0,ns,34996 +free,spin_lock object poll,,,,794241.0,ns,35669 +free,spin_lock object poll,,,,822230.0,ns,36342 +free,spin_lock object poll,,,,840038.0,ns,37015 +free,spin_lock object poll,,,,848207.0,ns,37688 +free,spin_lock object poll,,,,863002.0,ns,38361 +free,spin_lock object poll,,,,878256.0,ns,39034 +free,spin_lock object poll,,,,908789.0,ns,39707 +free,spin_lock object poll,,,,902143.0,ns,40380 +free,spin_lock object poll,,,,917606.0,ns,41053 +free,spin_lock object poll,,,,936402.0,ns,41726 +free,spin_lock object poll,,,,948660.0,ns,42399 +free,spin_lock object poll,,,,968519.0,ns,43072 +free,spin_lock object poll,,,,981557.0,ns,43745 +free,spin_lock object poll,,,,989643.0,ns,44418 +free,spin_lock object poll,,,,1019354.0,ns,45091 +free,spin_lock object poll,,,,1025751.0,ns,45764 +free,spin_lock object poll,,,,1035708.0,ns,46437 +free,spin_lock object poll,,,,1049682.0,ns,47110 +free,spin_lock object poll,,,,1072615.0,ns,47783 +free,spin_lock object poll,,,,1086304.0,ns,48456 +free,spin_lock object poll,,,,1117550.0,ns,49129 +free,spin_lock object poll,,,,1111950.0,ns,49802 +free,spin_lock object poll,,,,1130996.0,ns,50475 +free,spin_lock object poll,,,,1126145.0,ns,51148 +free,spin_lock object poll,,,,1145302.0,ns,51821 +free,spin_lock object poll,,,,1152702.0,ns,52494 +free,spin_lock object poll,,,,1171369.0,ns,53167 +free,spin_lock object poll,,,,1188190.0,ns,53840 +free,spin_lock object poll,,,,1211600.0,ns,54513 +free,spin_lock object poll,,,,1213638.0,ns,55186 +free,spin_lock object poll,,,,1240772.0,ns,55859 +free,spin_lock object poll,,,,1251999.0,ns,56532 +free,spin_lock object poll,,,,1354237.0,ns,57205 +free,spin_lock object poll,,,,1280797.0,ns,57878 +free,spin_lock object poll,,,,1290128.0,ns,58551 +free,spin_lock object poll,,,,1304842.0,ns,59224 +free,spin_lock object poll,,,,1318685.0,ns,59897 +free,spin_lock object poll,,,,1335703.0,ns,60570 +free,spin_lock object poll,,,,1346933.0,ns,61243 +free,spin_lock object poll,,,,1369060.0,ns,61916 +free,spin_lock object poll,,,,1378557.0,ns,62589 +free,spin_lock object poll,,,,1399999.0,ns,63262 +free,spin_lock object poll,,,,1407270.0,ns,63935 +free,spin_lock object poll,,,,1426108.0,ns,64608 +free,spin_lock object poll,,,,1437927.0,ns,65281 +free,spin_lock object poll,,,,1449969.0,ns,65954 +free,spin_lock object poll,,,,1469988.0,ns,66627 +free,spin_lock object poll,,,,1493628.0,ns,67300 diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/sample.json new file mode 100644 index 0000000000000..8d3de6030b25d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[673.0,1346.0,2019.0,2692.0,3365.0,4038.0,4711.0,5384.0,6057.0,6730.0,7403.0,8076.0,8749.0,9422.0,10095.0,10768.0,11441.0,12114.0,12787.0,13460.0,14133.0,14806.0,15479.0,16152.0,16825.0,17498.0,18171.0,18844.0,19517.0,20190.0,20863.0,21536.0,22209.0,22882.0,23555.0,24228.0,24901.0,25574.0,26247.0,26920.0,27593.0,28266.0,28939.0,29612.0,30285.0,30958.0,31631.0,32304.0,32977.0,33650.0,34323.0,34996.0,35669.0,36342.0,37015.0,37688.0,38361.0,39034.0,39707.0,40380.0,41053.0,41726.0,42399.0,43072.0,43745.0,44418.0,45091.0,45764.0,46437.0,47110.0,47783.0,48456.0,49129.0,49802.0,50475.0,51148.0,51821.0,52494.0,53167.0,53840.0,54513.0,55186.0,55859.0,56532.0,57205.0,57878.0,58551.0,59224.0,59897.0,60570.0,61243.0,61916.0,62589.0,63262.0,63935.0,64608.0,65281.0,65954.0,66627.0,67300.0],"times":[13308.0,23714.0,34719.0,61380.0,79407.0,103913.0,106714.0,121122.0,145760.0,157946.0,167935.0,188975.0,203066.0,220759.0,250722.0,247015.0,262136.0,276471.0,291027.0,309163.0,321494.0,335407.0,349112.0,371401.0,383066.0,395206.0,412310.0,429954.0,444336.0,455718.0,473586.0,484250.0,509623.0,519589.0,536018.0,547038.0,558936.0,574758.0,593671.0,609137.0,623913.0,635349.0,644942.0,666071.0,680867.0,694978.0,709344.0,722402.0,737011.0,753991.0,772047.0,784710.0,794241.0,822230.0,840038.0,848207.0,863002.0,878256.0,908789.0,902143.0,917606.0,936402.0,948660.0,968519.0,981557.0,989643.0,1019354.0,1025751.0,1035708.0,1049682.0,1072615.0,1086304.0,1117550.0,1111950.0,1130996.0,1126145.0,1145302.0,1152702.0,1171369.0,1188190.0,1211600.0,1213638.0,1240772.0,1251999.0,1354237.0,1280797.0,1290128.0,1304842.0,1318685.0,1335703.0,1346933.0,1369060.0,1378557.0,1399999.0,1407270.0,1426108.0,1437927.0,1449969.0,1469988.0,1493628.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/tukey.json new file mode 100644 index 0000000000000..e3433c97ef6a5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/base/tukey.json @@ -0,0 +1 @@ +[20.726242562723936,21.46703300552459,23.442474186326343,24.183264629127002] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/benchmark.json new file mode 100644 index 0000000000000..5545c0534f58f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"free","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"free/spin_lock object poll","directory_name":"free/spin_lock object poll","title":"free/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/estimates.json new file mode 100644 index 0000000000000..fd5dbc50a432c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":22.24467572616933,"upper_bound":22.615943048485},"point_estimate":22.44064366554603,"standard_error":0.09446219547073749},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":22.413927978323574,"upper_bound":22.525385270139623},"point_estimate":22.475904657632192,"standard_error":0.03017324592663187},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.2680207223245133,"upper_bound":0.48205826900197246},"point_estimate":0.3805443510860128,"standard_error":0.05639882640440274},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":22.211754406584905,"upper_bound":22.376493648851582},"point_estimate":22.282241091776783,"standard_error":0.04231343645051745},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.5164851442270315,"upper_bound":1.3162438157684764},"point_estimate":0.955249182084287,"standard_error":0.20339770183690095}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/raw.csv new file mode 100644 index 0000000000000..d6fb22240cebc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +free,spin_lock object poll,,,,13308.0,ns,673 +free,spin_lock object poll,,,,23714.0,ns,1346 +free,spin_lock object poll,,,,34719.0,ns,2019 +free,spin_lock object poll,,,,61380.0,ns,2692 +free,spin_lock object poll,,,,79407.0,ns,3365 +free,spin_lock object poll,,,,103913.0,ns,4038 +free,spin_lock object poll,,,,106714.0,ns,4711 +free,spin_lock object poll,,,,121122.0,ns,5384 +free,spin_lock object poll,,,,145760.0,ns,6057 +free,spin_lock object poll,,,,157946.0,ns,6730 +free,spin_lock object poll,,,,167935.0,ns,7403 +free,spin_lock object poll,,,,188975.0,ns,8076 +free,spin_lock object poll,,,,203066.0,ns,8749 +free,spin_lock object poll,,,,220759.0,ns,9422 +free,spin_lock object poll,,,,250722.0,ns,10095 +free,spin_lock object poll,,,,247015.0,ns,10768 +free,spin_lock object poll,,,,262136.0,ns,11441 +free,spin_lock object poll,,,,276471.0,ns,12114 +free,spin_lock object poll,,,,291027.0,ns,12787 +free,spin_lock object poll,,,,309163.0,ns,13460 +free,spin_lock object poll,,,,321494.0,ns,14133 +free,spin_lock object poll,,,,335407.0,ns,14806 +free,spin_lock object poll,,,,349112.0,ns,15479 +free,spin_lock object poll,,,,371401.0,ns,16152 +free,spin_lock object poll,,,,383066.0,ns,16825 +free,spin_lock object poll,,,,395206.0,ns,17498 +free,spin_lock object poll,,,,412310.0,ns,18171 +free,spin_lock object poll,,,,429954.0,ns,18844 +free,spin_lock object poll,,,,444336.0,ns,19517 +free,spin_lock object poll,,,,455718.0,ns,20190 +free,spin_lock object poll,,,,473586.0,ns,20863 +free,spin_lock object poll,,,,484250.0,ns,21536 +free,spin_lock object poll,,,,509623.0,ns,22209 +free,spin_lock object poll,,,,519589.0,ns,22882 +free,spin_lock object poll,,,,536018.0,ns,23555 +free,spin_lock object poll,,,,547038.0,ns,24228 +free,spin_lock object poll,,,,558936.0,ns,24901 +free,spin_lock object poll,,,,574758.0,ns,25574 +free,spin_lock object poll,,,,593671.0,ns,26247 +free,spin_lock object poll,,,,609137.0,ns,26920 +free,spin_lock object poll,,,,623913.0,ns,27593 +free,spin_lock object poll,,,,635349.0,ns,28266 +free,spin_lock object poll,,,,644942.0,ns,28939 +free,spin_lock object poll,,,,666071.0,ns,29612 +free,spin_lock object poll,,,,680867.0,ns,30285 +free,spin_lock object poll,,,,694978.0,ns,30958 +free,spin_lock object poll,,,,709344.0,ns,31631 +free,spin_lock object poll,,,,722402.0,ns,32304 +free,spin_lock object poll,,,,737011.0,ns,32977 +free,spin_lock object poll,,,,753991.0,ns,33650 +free,spin_lock object poll,,,,772047.0,ns,34323 +free,spin_lock object poll,,,,784710.0,ns,34996 +free,spin_lock object poll,,,,794241.0,ns,35669 +free,spin_lock object poll,,,,822230.0,ns,36342 +free,spin_lock object poll,,,,840038.0,ns,37015 +free,spin_lock object poll,,,,848207.0,ns,37688 +free,spin_lock object poll,,,,863002.0,ns,38361 +free,spin_lock object poll,,,,878256.0,ns,39034 +free,spin_lock object poll,,,,908789.0,ns,39707 +free,spin_lock object poll,,,,902143.0,ns,40380 +free,spin_lock object poll,,,,917606.0,ns,41053 +free,spin_lock object poll,,,,936402.0,ns,41726 +free,spin_lock object poll,,,,948660.0,ns,42399 +free,spin_lock object poll,,,,968519.0,ns,43072 +free,spin_lock object poll,,,,981557.0,ns,43745 +free,spin_lock object poll,,,,989643.0,ns,44418 +free,spin_lock object poll,,,,1019354.0,ns,45091 +free,spin_lock object poll,,,,1025751.0,ns,45764 +free,spin_lock object poll,,,,1035708.0,ns,46437 +free,spin_lock object poll,,,,1049682.0,ns,47110 +free,spin_lock object poll,,,,1072615.0,ns,47783 +free,spin_lock object poll,,,,1086304.0,ns,48456 +free,spin_lock object poll,,,,1117550.0,ns,49129 +free,spin_lock object poll,,,,1111950.0,ns,49802 +free,spin_lock object poll,,,,1130996.0,ns,50475 +free,spin_lock object poll,,,,1126145.0,ns,51148 +free,spin_lock object poll,,,,1145302.0,ns,51821 +free,spin_lock object poll,,,,1152702.0,ns,52494 +free,spin_lock object poll,,,,1171369.0,ns,53167 +free,spin_lock object poll,,,,1188190.0,ns,53840 +free,spin_lock object poll,,,,1211600.0,ns,54513 +free,spin_lock object poll,,,,1213638.0,ns,55186 +free,spin_lock object poll,,,,1240772.0,ns,55859 +free,spin_lock object poll,,,,1251999.0,ns,56532 +free,spin_lock object poll,,,,1354237.0,ns,57205 +free,spin_lock object poll,,,,1280797.0,ns,57878 +free,spin_lock object poll,,,,1290128.0,ns,58551 +free,spin_lock object poll,,,,1304842.0,ns,59224 +free,spin_lock object poll,,,,1318685.0,ns,59897 +free,spin_lock object poll,,,,1335703.0,ns,60570 +free,spin_lock object poll,,,,1346933.0,ns,61243 +free,spin_lock object poll,,,,1369060.0,ns,61916 +free,spin_lock object poll,,,,1378557.0,ns,62589 +free,spin_lock object poll,,,,1399999.0,ns,63262 +free,spin_lock object poll,,,,1407270.0,ns,63935 +free,spin_lock object poll,,,,1426108.0,ns,64608 +free,spin_lock object poll,,,,1437927.0,ns,65281 +free,spin_lock object poll,,,,1449969.0,ns,65954 +free,spin_lock object poll,,,,1469988.0,ns,66627 +free,spin_lock object poll,,,,1493628.0,ns,67300 diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/sample.json new file mode 100644 index 0000000000000..8d3de6030b25d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[673.0,1346.0,2019.0,2692.0,3365.0,4038.0,4711.0,5384.0,6057.0,6730.0,7403.0,8076.0,8749.0,9422.0,10095.0,10768.0,11441.0,12114.0,12787.0,13460.0,14133.0,14806.0,15479.0,16152.0,16825.0,17498.0,18171.0,18844.0,19517.0,20190.0,20863.0,21536.0,22209.0,22882.0,23555.0,24228.0,24901.0,25574.0,26247.0,26920.0,27593.0,28266.0,28939.0,29612.0,30285.0,30958.0,31631.0,32304.0,32977.0,33650.0,34323.0,34996.0,35669.0,36342.0,37015.0,37688.0,38361.0,39034.0,39707.0,40380.0,41053.0,41726.0,42399.0,43072.0,43745.0,44418.0,45091.0,45764.0,46437.0,47110.0,47783.0,48456.0,49129.0,49802.0,50475.0,51148.0,51821.0,52494.0,53167.0,53840.0,54513.0,55186.0,55859.0,56532.0,57205.0,57878.0,58551.0,59224.0,59897.0,60570.0,61243.0,61916.0,62589.0,63262.0,63935.0,64608.0,65281.0,65954.0,66627.0,67300.0],"times":[13308.0,23714.0,34719.0,61380.0,79407.0,103913.0,106714.0,121122.0,145760.0,157946.0,167935.0,188975.0,203066.0,220759.0,250722.0,247015.0,262136.0,276471.0,291027.0,309163.0,321494.0,335407.0,349112.0,371401.0,383066.0,395206.0,412310.0,429954.0,444336.0,455718.0,473586.0,484250.0,509623.0,519589.0,536018.0,547038.0,558936.0,574758.0,593671.0,609137.0,623913.0,635349.0,644942.0,666071.0,680867.0,694978.0,709344.0,722402.0,737011.0,753991.0,772047.0,784710.0,794241.0,822230.0,840038.0,848207.0,863002.0,878256.0,908789.0,902143.0,917606.0,936402.0,948660.0,968519.0,981557.0,989643.0,1019354.0,1025751.0,1035708.0,1049682.0,1072615.0,1086304.0,1117550.0,1111950.0,1130996.0,1126145.0,1145302.0,1152702.0,1171369.0,1188190.0,1211600.0,1213638.0,1240772.0,1251999.0,1354237.0,1280797.0,1290128.0,1304842.0,1318685.0,1335703.0,1346933.0,1369060.0,1378557.0,1399999.0,1407270.0,1426108.0,1437927.0,1449969.0,1469988.0,1493628.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/tukey.json new file mode 100644 index 0000000000000..e3433c97ef6a5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/new/tukey.json @@ -0,0 +1 @@ +[20.726242562723936,21.46703300552459,23.442474186326343,24.183264629127002] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/MAD.svg new file mode 100644 index 0000000000000..268c573b07c30 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 250 + + + + + 300 + + + + + 350 + + + + + 400 + + + + + 450 + + + + + 500 + + + + + + + + + Density (a.u.) + + + + + Average time (ps) + + + + + free/spin_lock object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/SD.svg new file mode 100644 index 0000000000000..143188c2aa552 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/SD.svg @@ -0,0 +1,328 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + 1.8 + + + + + 2 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 0.9 + + + + + 1 + + + + + 1.1 + + + + + 1.2 + + + + + 1.3 + + + + + 1.4 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/spin_lock object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/index.html new file mode 100644 index 0000000000000..69dbc7ca157f6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + free/spin_lock object poll - Criterion.rs + + + + +
+

free/spin_lock object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope22.212 ns22.282 ns22.376 ns
0.96900190.97033250.9679560
Mean22.245 ns22.441 ns22.616 ns
Std. Dev.516.49 ps955.25 ps1.3162 ns
Median22.414 ns22.476 ns22.525 ns
MAD268.02 ps380.54 ps482.06 ps
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/mean.svg new file mode 100644 index 0000000000000..ba50ea652805b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/mean.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 4 + + + + + 4.5 + + + + + 22.25 + + + + + 22.3 + + + + + 22.35 + + + + + 22.4 + + + + + 22.45 + + + + + 22.5 + + + + + 22.55 + + + + + 22.6 + + + + + 22.65 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/spin_lock object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/median.svg new file mode 100644 index 0000000000000..81f9011861f0e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/median.svg @@ -0,0 +1,283 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + 22.42 + + + + + 22.44 + + + + + 22.46 + + + + + 22.48 + + + + + 22.5 + + + + + 22.52 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/spin_lock object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/pdf.svg new file mode 100644 index 0000000000000..c637743333757 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/pdf.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + 22 + + + + + 24 + + + + + 26 + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/spin_lock object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..fa5aaef4439aa --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/pdf_small.svg @@ -0,0 +1,214 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + 22 + + + + + 24 + + + + + 26 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/regression.svg new file mode 100644 index 0000000000000..74bd1fa312463 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/regression.svg @@ -0,0 +1,434 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.2 + + + + + + + + + + + + + 0.4 + + + + + + + + + + + + + 0.6 + + + + + + + + + + + + + 0.8 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.2 + + + + + + + + + + + + + 1.4 + + + + + + + + + + + + + 1.6 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + free/spin_lock object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/regression_small.svg new file mode 100644 index 0000000000000..9264254c13eea --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/regression_small.svg @@ -0,0 +1,412 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.2 + + + + + + + + + + + + + 0.4 + + + + + + + + + + + + + 0.6 + + + + + + + + + + + + + 0.8 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.2 + + + + + + + + + + + + + 1.4 + + + + + + + + + + + + + 1.6 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/slope.svg new file mode 100644 index 0000000000000..067b45a743e60 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/slope.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 22.2 + + + + + 22.25 + + + + + 22.3 + + + + + 22.35 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/spin_lock object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/typical.svg new file mode 100644 index 0000000000000..c4cd675bf0a97 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/free/spin_lock object poll/report/typical.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 22.2 + + + + + 22.25 + + + + + 22.3 + + + + + 22.35 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + free/spin_lock object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/benchmark.json new file mode 100644 index 0000000000000..c3cd7d04f22a8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread allocation","function_id":"crate 'object-pool'","value_str":null,"throughput":null,"full_id":"multi thread allocation/crate 'object-pool'","directory_name":"multi thread allocation/crate 'object-pool'","title":"multi thread allocation/crate 'object-pool'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/estimates.json new file mode 100644 index 0000000000000..ae8e9f35ca084 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":227.4309826372897,"upper_bound":298.42942339064774},"point_estimate":262.2353594830625,"standard_error":18.048914394942017},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":128.6093117408907,"upper_bound":153.07684210526315},"point_estimate":132.7026851851852,"standard_error":18.573790655547995},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":17.104021599176917,"upper_bound":80.79364899221879},"point_estimate":32.39206167041288,"standard_error":22.743805999626748},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":364.70363597873273,"upper_bound":439.04077415611573},"point_estimate":406.00632320938297,"standard_error":18.97716324301338},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":166.49473263419011,"upper_bound":190.54044028813016},"point_estimate":181.4657904196716,"standard_error":6.156613804289979}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/raw.csv new file mode 100644 index 0000000000000..4e12c01556bbf --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread allocation,crate 'object-pool',,,,62009.0,ns,190 +multi thread allocation,crate 'object-pool',,,,85441.0,ns,380 +multi thread allocation,crate 'object-pool',,,,112453.0,ns,570 +multi thread allocation,crate 'object-pool',,,,123303.0,ns,760 +multi thread allocation,crate 'object-pool',,,,145423.0,ns,950 +multi thread allocation,crate 'object-pool',,,,155678.0,ns,1140 +multi thread allocation,crate 'object-pool',,,,166504.0,ns,1330 +multi thread allocation,crate 'object-pool',,,,190815.0,ns,1520 +multi thread allocation,crate 'object-pool',,,,216547.0,ns,1710 +multi thread allocation,crate 'object-pool',,,,221369.0,ns,1900 +multi thread allocation,crate 'object-pool',,,,239674.0,ns,2090 +multi thread allocation,crate 'object-pool',,,,266926.0,ns,2280 +multi thread allocation,crate 'object-pool',,,,296951.0,ns,2470 +multi thread allocation,crate 'object-pool',,,,286524.0,ns,2660 +multi thread allocation,crate 'object-pool',,,,299443.0,ns,2850 +multi thread allocation,crate 'object-pool',,,,356062.0,ns,3040 +multi thread allocation,crate 'object-pool',,,,340661.0,ns,3230 +multi thread allocation,crate 'object-pool',,,,308348.0,ns,3420 +multi thread allocation,crate 'object-pool',,,,355882.0,ns,3610 +multi thread allocation,crate 'object-pool',,,,453844.0,ns,3800 +multi thread allocation,crate 'object-pool',,,,398658.0,ns,3990 +multi thread allocation,crate 'object-pool',,,,428714.0,ns,4180 +multi thread allocation,crate 'object-pool',,,,481491.0,ns,4370 +multi thread allocation,crate 'object-pool',,,,518667.0,ns,4560 +multi thread allocation,crate 'object-pool',,,,537542.0,ns,4750 +multi thread allocation,crate 'object-pool',,,,506360.0,ns,4940 +multi thread allocation,crate 'object-pool',,,,572139.0,ns,5130 +multi thread allocation,crate 'object-pool',,,,632568.0,ns,5320 +multi thread allocation,crate 'object-pool',,,,534941.0,ns,5510 +multi thread allocation,crate 'object-pool',,,,672141.0,ns,5700 +multi thread allocation,crate 'object-pool',,,,707593.0,ns,5890 +multi thread allocation,crate 'object-pool',,,,741261.0,ns,6080 +multi thread allocation,crate 'object-pool',,,,798298.0,ns,6270 +multi thread allocation,crate 'object-pool',,,,809729.0,ns,6460 +multi thread allocation,crate 'object-pool',,,,815011.0,ns,6650 +multi thread allocation,crate 'object-pool',,,,857987.0,ns,6840 +multi thread allocation,crate 'object-pool',,,,877971.0,ns,7030 +multi thread allocation,crate 'object-pool',,,,905576.0,ns,7220 +multi thread allocation,crate 'object-pool',,,,936482.0,ns,7410 +multi thread allocation,crate 'object-pool',,,,921695.0,ns,7600 +multi thread allocation,crate 'object-pool',,,,989372.0,ns,7790 +multi thread allocation,crate 'object-pool',,,,1016914.0,ns,7980 +multi thread allocation,crate 'object-pool',,,,1039760.0,ns,8170 +multi thread allocation,crate 'object-pool',,,,1069156.0,ns,8360 +multi thread allocation,crate 'object-pool',,,,1048649.0,ns,8550 +multi thread allocation,crate 'object-pool',,,,1183257.0,ns,8740 +multi thread allocation,crate 'object-pool',,,,1175666.0,ns,8930 +multi thread allocation,crate 'object-pool',,,,1176298.0,ns,9120 +multi thread allocation,crate 'object-pool',,,,1233597.0,ns,9310 +multi thread allocation,crate 'object-pool',,,,1239173.0,ns,9500 +multi thread allocation,crate 'object-pool',,,,1262678.0,ns,9690 +multi thread allocation,crate 'object-pool',,,,1270660.0,ns,9880 +multi thread allocation,crate 'object-pool',,,,1320061.0,ns,10070 +multi thread allocation,crate 'object-pool',,,,1363349.0,ns,10260 +multi thread allocation,crate 'object-pool',,,,1401959.0,ns,10450 +multi thread allocation,crate 'object-pool',,,,1392568.0,ns,10640 +multi thread allocation,crate 'object-pool',,,,1458000.0,ns,10830 +multi thread allocation,crate 'object-pool',,,,1416800.0,ns,11020 +multi thread allocation,crate 'object-pool',,,,1508858.0,ns,11210 +multi thread allocation,crate 'object-pool',,,,1510789.0,ns,11400 +multi thread allocation,crate 'object-pool',,,,1579518.0,ns,11590 +multi thread allocation,crate 'object-pool',,,,1597832.0,ns,11780 +multi thread allocation,crate 'object-pool',,,,1627502.0,ns,11970 +multi thread allocation,crate 'object-pool',,,,1585914.0,ns,12160 +multi thread allocation,crate 'object-pool',,,,5191059.0,ns,12350 +multi thread allocation,crate 'object-pool',,,,6059434.0,ns,12540 +multi thread allocation,crate 'object-pool',,,,5975546.0,ns,12730 +multi thread allocation,crate 'object-pool',,,,6321682.0,ns,12920 +multi thread allocation,crate 'object-pool',,,,6347280.0,ns,13110 +multi thread allocation,crate 'object-pool',,,,6429517.0,ns,13300 +multi thread allocation,crate 'object-pool',,,,6298060.0,ns,13490 +multi thread allocation,crate 'object-pool',,,,6453007.0,ns,13680 +multi thread allocation,crate 'object-pool',,,,6703162.0,ns,13870 +multi thread allocation,crate 'object-pool',,,,7066436.0,ns,14060 +multi thread allocation,crate 'object-pool',,,,7154939.0,ns,14250 +multi thread allocation,crate 'object-pool',,,,7224148.0,ns,14440 +multi thread allocation,crate 'object-pool',,,,6354987.0,ns,14630 +multi thread allocation,crate 'object-pool',,,,6534593.0,ns,14820 +multi thread allocation,crate 'object-pool',,,,7398552.0,ns,15010 +multi thread allocation,crate 'object-pool',,,,7384626.0,ns,15200 +multi thread allocation,crate 'object-pool',,,,7438694.0,ns,15390 +multi thread allocation,crate 'object-pool',,,,7367454.0,ns,15580 +multi thread allocation,crate 'object-pool',,,,7868407.0,ns,15770 +multi thread allocation,crate 'object-pool',,,,6995522.0,ns,15960 +multi thread allocation,crate 'object-pool',,,,7842053.0,ns,16150 +multi thread allocation,crate 'object-pool',,,,8029623.0,ns,16340 +multi thread allocation,crate 'object-pool',,,,8292169.0,ns,16530 +multi thread allocation,crate 'object-pool',,,,8053127.0,ns,16720 +multi thread allocation,crate 'object-pool',,,,8803725.0,ns,16910 +multi thread allocation,crate 'object-pool',,,,9075508.0,ns,17100 +multi thread allocation,crate 'object-pool',,,,9226901.0,ns,17290 +multi thread allocation,crate 'object-pool',,,,9513902.0,ns,17480 +multi thread allocation,crate 'object-pool',,,,9835576.0,ns,17670 +multi thread allocation,crate 'object-pool',,,,9512692.0,ns,17860 +multi thread allocation,crate 'object-pool',,,,9487021.0,ns,18050 +multi thread allocation,crate 'object-pool',,,,9614011.0,ns,18240 +multi thread allocation,crate 'object-pool',,,,10093848.0,ns,18430 +multi thread allocation,crate 'object-pool',,,,10577827.0,ns,18620 +multi thread allocation,crate 'object-pool',,,,10242761.0,ns,18810 +multi thread allocation,crate 'object-pool',,,,10674647.0,ns,19000 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/sample.json new file mode 100644 index 0000000000000..da22d027c470c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[190.0,380.0,570.0,760.0,950.0,1140.0,1330.0,1520.0,1710.0,1900.0,2090.0,2280.0,2470.0,2660.0,2850.0,3040.0,3230.0,3420.0,3610.0,3800.0,3990.0,4180.0,4370.0,4560.0,4750.0,4940.0,5130.0,5320.0,5510.0,5700.0,5890.0,6080.0,6270.0,6460.0,6650.0,6840.0,7030.0,7220.0,7410.0,7600.0,7790.0,7980.0,8170.0,8360.0,8550.0,8740.0,8930.0,9120.0,9310.0,9500.0,9690.0,9880.0,10070.0,10260.0,10450.0,10640.0,10830.0,11020.0,11210.0,11400.0,11590.0,11780.0,11970.0,12160.0,12350.0,12540.0,12730.0,12920.0,13110.0,13300.0,13490.0,13680.0,13870.0,14060.0,14250.0,14440.0,14630.0,14820.0,15010.0,15200.0,15390.0,15580.0,15770.0,15960.0,16150.0,16340.0,16530.0,16720.0,16910.0,17100.0,17290.0,17480.0,17670.0,17860.0,18050.0,18240.0,18430.0,18620.0,18810.0,19000.0],"times":[62009.0,85441.0,112453.0,123303.0,145423.0,155678.0,166504.0,190815.0,216547.0,221369.0,239674.0,266926.0,296951.0,286524.0,299443.0,356062.0,340661.0,308348.0,355882.0,453844.0,398658.0,428714.0,481491.0,518667.0,537542.0,506360.0,572139.0,632568.0,534941.0,672141.0,707593.0,741261.0,798298.0,809729.0,815011.0,857987.0,877971.0,905576.0,936482.0,921695.0,989372.0,1016914.0,1039760.0,1069156.0,1048649.0,1183257.0,1175666.0,1176298.0,1233597.0,1239173.0,1262678.0,1270660.0,1320061.0,1363349.0,1401959.0,1392568.0,1458000.0,1416800.0,1508858.0,1510789.0,1579518.0,1597832.0,1627502.0,1585914.0,5191059.0,6059434.0,5975546.0,6321682.0,6347280.0,6429517.0,6298060.0,6453007.0,6703162.0,7066436.0,7154939.0,7224148.0,6354987.0,6534593.0,7398552.0,7384626.0,7438694.0,7367454.0,7868407.0,6995522.0,7842053.0,8029623.0,8292169.0,8053127.0,8803725.0,9075508.0,9226901.0,9513902.0,9835576.0,9512692.0,9487021.0,9614011.0,10093848.0,10577827.0,10242761.0,10674647.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/tukey.json new file mode 100644 index 0000000000000..37965d15bc7b3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/base/tukey.json @@ -0,0 +1 @@ +[-959.3954874248022,-418.3846108803209,1024.3110599049628,1565.321936449444] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/benchmark.json new file mode 100644 index 0000000000000..c3cd7d04f22a8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread allocation","function_id":"crate 'object-pool'","value_str":null,"throughput":null,"full_id":"multi thread allocation/crate 'object-pool'","directory_name":"multi thread allocation/crate 'object-pool'","title":"multi thread allocation/crate 'object-pool'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/estimates.json new file mode 100644 index 0000000000000..ae8e9f35ca084 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":227.4309826372897,"upper_bound":298.42942339064774},"point_estimate":262.2353594830625,"standard_error":18.048914394942017},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":128.6093117408907,"upper_bound":153.07684210526315},"point_estimate":132.7026851851852,"standard_error":18.573790655547995},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":17.104021599176917,"upper_bound":80.79364899221879},"point_estimate":32.39206167041288,"standard_error":22.743805999626748},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":364.70363597873273,"upper_bound":439.04077415611573},"point_estimate":406.00632320938297,"standard_error":18.97716324301338},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":166.49473263419011,"upper_bound":190.54044028813016},"point_estimate":181.4657904196716,"standard_error":6.156613804289979}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/raw.csv new file mode 100644 index 0000000000000..4e12c01556bbf --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread allocation,crate 'object-pool',,,,62009.0,ns,190 +multi thread allocation,crate 'object-pool',,,,85441.0,ns,380 +multi thread allocation,crate 'object-pool',,,,112453.0,ns,570 +multi thread allocation,crate 'object-pool',,,,123303.0,ns,760 +multi thread allocation,crate 'object-pool',,,,145423.0,ns,950 +multi thread allocation,crate 'object-pool',,,,155678.0,ns,1140 +multi thread allocation,crate 'object-pool',,,,166504.0,ns,1330 +multi thread allocation,crate 'object-pool',,,,190815.0,ns,1520 +multi thread allocation,crate 'object-pool',,,,216547.0,ns,1710 +multi thread allocation,crate 'object-pool',,,,221369.0,ns,1900 +multi thread allocation,crate 'object-pool',,,,239674.0,ns,2090 +multi thread allocation,crate 'object-pool',,,,266926.0,ns,2280 +multi thread allocation,crate 'object-pool',,,,296951.0,ns,2470 +multi thread allocation,crate 'object-pool',,,,286524.0,ns,2660 +multi thread allocation,crate 'object-pool',,,,299443.0,ns,2850 +multi thread allocation,crate 'object-pool',,,,356062.0,ns,3040 +multi thread allocation,crate 'object-pool',,,,340661.0,ns,3230 +multi thread allocation,crate 'object-pool',,,,308348.0,ns,3420 +multi thread allocation,crate 'object-pool',,,,355882.0,ns,3610 +multi thread allocation,crate 'object-pool',,,,453844.0,ns,3800 +multi thread allocation,crate 'object-pool',,,,398658.0,ns,3990 +multi thread allocation,crate 'object-pool',,,,428714.0,ns,4180 +multi thread allocation,crate 'object-pool',,,,481491.0,ns,4370 +multi thread allocation,crate 'object-pool',,,,518667.0,ns,4560 +multi thread allocation,crate 'object-pool',,,,537542.0,ns,4750 +multi thread allocation,crate 'object-pool',,,,506360.0,ns,4940 +multi thread allocation,crate 'object-pool',,,,572139.0,ns,5130 +multi thread allocation,crate 'object-pool',,,,632568.0,ns,5320 +multi thread allocation,crate 'object-pool',,,,534941.0,ns,5510 +multi thread allocation,crate 'object-pool',,,,672141.0,ns,5700 +multi thread allocation,crate 'object-pool',,,,707593.0,ns,5890 +multi thread allocation,crate 'object-pool',,,,741261.0,ns,6080 +multi thread allocation,crate 'object-pool',,,,798298.0,ns,6270 +multi thread allocation,crate 'object-pool',,,,809729.0,ns,6460 +multi thread allocation,crate 'object-pool',,,,815011.0,ns,6650 +multi thread allocation,crate 'object-pool',,,,857987.0,ns,6840 +multi thread allocation,crate 'object-pool',,,,877971.0,ns,7030 +multi thread allocation,crate 'object-pool',,,,905576.0,ns,7220 +multi thread allocation,crate 'object-pool',,,,936482.0,ns,7410 +multi thread allocation,crate 'object-pool',,,,921695.0,ns,7600 +multi thread allocation,crate 'object-pool',,,,989372.0,ns,7790 +multi thread allocation,crate 'object-pool',,,,1016914.0,ns,7980 +multi thread allocation,crate 'object-pool',,,,1039760.0,ns,8170 +multi thread allocation,crate 'object-pool',,,,1069156.0,ns,8360 +multi thread allocation,crate 'object-pool',,,,1048649.0,ns,8550 +multi thread allocation,crate 'object-pool',,,,1183257.0,ns,8740 +multi thread allocation,crate 'object-pool',,,,1175666.0,ns,8930 +multi thread allocation,crate 'object-pool',,,,1176298.0,ns,9120 +multi thread allocation,crate 'object-pool',,,,1233597.0,ns,9310 +multi thread allocation,crate 'object-pool',,,,1239173.0,ns,9500 +multi thread allocation,crate 'object-pool',,,,1262678.0,ns,9690 +multi thread allocation,crate 'object-pool',,,,1270660.0,ns,9880 +multi thread allocation,crate 'object-pool',,,,1320061.0,ns,10070 +multi thread allocation,crate 'object-pool',,,,1363349.0,ns,10260 +multi thread allocation,crate 'object-pool',,,,1401959.0,ns,10450 +multi thread allocation,crate 'object-pool',,,,1392568.0,ns,10640 +multi thread allocation,crate 'object-pool',,,,1458000.0,ns,10830 +multi thread allocation,crate 'object-pool',,,,1416800.0,ns,11020 +multi thread allocation,crate 'object-pool',,,,1508858.0,ns,11210 +multi thread allocation,crate 'object-pool',,,,1510789.0,ns,11400 +multi thread allocation,crate 'object-pool',,,,1579518.0,ns,11590 +multi thread allocation,crate 'object-pool',,,,1597832.0,ns,11780 +multi thread allocation,crate 'object-pool',,,,1627502.0,ns,11970 +multi thread allocation,crate 'object-pool',,,,1585914.0,ns,12160 +multi thread allocation,crate 'object-pool',,,,5191059.0,ns,12350 +multi thread allocation,crate 'object-pool',,,,6059434.0,ns,12540 +multi thread allocation,crate 'object-pool',,,,5975546.0,ns,12730 +multi thread allocation,crate 'object-pool',,,,6321682.0,ns,12920 +multi thread allocation,crate 'object-pool',,,,6347280.0,ns,13110 +multi thread allocation,crate 'object-pool',,,,6429517.0,ns,13300 +multi thread allocation,crate 'object-pool',,,,6298060.0,ns,13490 +multi thread allocation,crate 'object-pool',,,,6453007.0,ns,13680 +multi thread allocation,crate 'object-pool',,,,6703162.0,ns,13870 +multi thread allocation,crate 'object-pool',,,,7066436.0,ns,14060 +multi thread allocation,crate 'object-pool',,,,7154939.0,ns,14250 +multi thread allocation,crate 'object-pool',,,,7224148.0,ns,14440 +multi thread allocation,crate 'object-pool',,,,6354987.0,ns,14630 +multi thread allocation,crate 'object-pool',,,,6534593.0,ns,14820 +multi thread allocation,crate 'object-pool',,,,7398552.0,ns,15010 +multi thread allocation,crate 'object-pool',,,,7384626.0,ns,15200 +multi thread allocation,crate 'object-pool',,,,7438694.0,ns,15390 +multi thread allocation,crate 'object-pool',,,,7367454.0,ns,15580 +multi thread allocation,crate 'object-pool',,,,7868407.0,ns,15770 +multi thread allocation,crate 'object-pool',,,,6995522.0,ns,15960 +multi thread allocation,crate 'object-pool',,,,7842053.0,ns,16150 +multi thread allocation,crate 'object-pool',,,,8029623.0,ns,16340 +multi thread allocation,crate 'object-pool',,,,8292169.0,ns,16530 +multi thread allocation,crate 'object-pool',,,,8053127.0,ns,16720 +multi thread allocation,crate 'object-pool',,,,8803725.0,ns,16910 +multi thread allocation,crate 'object-pool',,,,9075508.0,ns,17100 +multi thread allocation,crate 'object-pool',,,,9226901.0,ns,17290 +multi thread allocation,crate 'object-pool',,,,9513902.0,ns,17480 +multi thread allocation,crate 'object-pool',,,,9835576.0,ns,17670 +multi thread allocation,crate 'object-pool',,,,9512692.0,ns,17860 +multi thread allocation,crate 'object-pool',,,,9487021.0,ns,18050 +multi thread allocation,crate 'object-pool',,,,9614011.0,ns,18240 +multi thread allocation,crate 'object-pool',,,,10093848.0,ns,18430 +multi thread allocation,crate 'object-pool',,,,10577827.0,ns,18620 +multi thread allocation,crate 'object-pool',,,,10242761.0,ns,18810 +multi thread allocation,crate 'object-pool',,,,10674647.0,ns,19000 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/sample.json new file mode 100644 index 0000000000000..da22d027c470c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[190.0,380.0,570.0,760.0,950.0,1140.0,1330.0,1520.0,1710.0,1900.0,2090.0,2280.0,2470.0,2660.0,2850.0,3040.0,3230.0,3420.0,3610.0,3800.0,3990.0,4180.0,4370.0,4560.0,4750.0,4940.0,5130.0,5320.0,5510.0,5700.0,5890.0,6080.0,6270.0,6460.0,6650.0,6840.0,7030.0,7220.0,7410.0,7600.0,7790.0,7980.0,8170.0,8360.0,8550.0,8740.0,8930.0,9120.0,9310.0,9500.0,9690.0,9880.0,10070.0,10260.0,10450.0,10640.0,10830.0,11020.0,11210.0,11400.0,11590.0,11780.0,11970.0,12160.0,12350.0,12540.0,12730.0,12920.0,13110.0,13300.0,13490.0,13680.0,13870.0,14060.0,14250.0,14440.0,14630.0,14820.0,15010.0,15200.0,15390.0,15580.0,15770.0,15960.0,16150.0,16340.0,16530.0,16720.0,16910.0,17100.0,17290.0,17480.0,17670.0,17860.0,18050.0,18240.0,18430.0,18620.0,18810.0,19000.0],"times":[62009.0,85441.0,112453.0,123303.0,145423.0,155678.0,166504.0,190815.0,216547.0,221369.0,239674.0,266926.0,296951.0,286524.0,299443.0,356062.0,340661.0,308348.0,355882.0,453844.0,398658.0,428714.0,481491.0,518667.0,537542.0,506360.0,572139.0,632568.0,534941.0,672141.0,707593.0,741261.0,798298.0,809729.0,815011.0,857987.0,877971.0,905576.0,936482.0,921695.0,989372.0,1016914.0,1039760.0,1069156.0,1048649.0,1183257.0,1175666.0,1176298.0,1233597.0,1239173.0,1262678.0,1270660.0,1320061.0,1363349.0,1401959.0,1392568.0,1458000.0,1416800.0,1508858.0,1510789.0,1579518.0,1597832.0,1627502.0,1585914.0,5191059.0,6059434.0,5975546.0,6321682.0,6347280.0,6429517.0,6298060.0,6453007.0,6703162.0,7066436.0,7154939.0,7224148.0,6354987.0,6534593.0,7398552.0,7384626.0,7438694.0,7367454.0,7868407.0,6995522.0,7842053.0,8029623.0,8292169.0,8053127.0,8803725.0,9075508.0,9226901.0,9513902.0,9835576.0,9512692.0,9487021.0,9614011.0,10093848.0,10577827.0,10242761.0,10674647.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/tukey.json new file mode 100644 index 0000000000000..37965d15bc7b3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/new/tukey.json @@ -0,0 +1 @@ +[-959.3954874248022,-418.3846108803209,1024.3110599049628,1565.321936449444] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/MAD.svg new file mode 100644 index 0000000000000..18a9c3d206192 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/MAD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 0.04 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 70 + + + + + 80 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/crate 'object-pool': MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/SD.svg new file mode 100644 index 0000000000000..721abc14f5c17 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/SD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 165 + + + + + 170 + + + + + 175 + + + + + 180 + + + + + 185 + + + + + 190 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/crate 'object-pool': SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/index.html new file mode 100644 index 0000000000000..6bd09e60f3b32 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/index.html @@ -0,0 +1,203 @@ + + + + + + multi thread allocation/crate 'object-pool' - Criterion.rs + + + + +
+

multi thread allocation/crate 'object-pool'

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope364.70 ns406.01 ns439.04 ns
0.12670780.13323310.1289839
Mean227.43 ns262.24 ns298.43 ns
Std. Dev.166.49 ns181.47 ns190.54 ns
Median128.61 ns132.70 ns153.08 ns
MAD17.104 ns32.392 ns80.794 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/mean.svg new file mode 100644 index 0000000000000..80c9c053b4929 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/mean.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 220 + + + + + 230 + + + + + 240 + + + + + 250 + + + + + 260 + + + + + 270 + + + + + 280 + + + + + 290 + + + + + 300 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/crate 'object-pool': mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/median.svg new file mode 100644 index 0000000000000..534005d3966d5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/median.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 130 + + + + + 135 + + + + + 140 + + + + + 145 + + + + + 150 + + + + + 155 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/crate 'object-pool': median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/pdf.svg new file mode 100644 index 0000000000000..f909913b60792 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/pdf.svg @@ -0,0 +1,430 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + -100 + + + + + 0 + + + + + 100 + + + + + 200 + + + + + 300 + + + + + 400 + + + + + 500 + + + + + 600 + + + + + 700 + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + 0.003 + + + + + 0.0035 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/crate 'object-pool' + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/pdf_small.svg new file mode 100644 index 0000000000000..93ee2b8adf1d8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/pdf_small.svg @@ -0,0 +1,229 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + 0.003 + + + + + 0.0035 + + + + + -100 + + + + + 0 + + + + + 100 + + + + + 200 + + + + + 300 + + + + + 400 + + + + + 500 + + + + + 600 + + + + + 700 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/regression.svg new file mode 100644 index 0000000000000..32c63e819a311 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/regression.svg @@ -0,0 +1,447 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + multi thread allocation/crate 'object-pool' + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/regression_small.svg new file mode 100644 index 0000000000000..2125ee2336faa --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/regression_small.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/slope.svg new file mode 100644 index 0000000000000..33cc9a396c478 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/slope.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 360 + + + + + 370 + + + + + 380 + + + + + 390 + + + + + 400 + + + + + 410 + + + + + 420 + + + + + 430 + + + + + 440 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/crate 'object-pool': slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/typical.svg new file mode 100644 index 0000000000000..3a0f472a38934 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'object-pool'/report/typical.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 360 + + + + + 370 + + + + + 380 + + + + + 390 + + + + + 400 + + + + + 410 + + + + + 420 + + + + + 430 + + + + + 440 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/crate 'object-pool': typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/benchmark.json new file mode 100644 index 0000000000000..e5a49f89e9326 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread allocation","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"multi thread allocation/crate 'sharded-slab'","directory_name":"multi thread allocation/crate 'sharded-slab'","title":"multi thread allocation/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/estimates.json new file mode 100644 index 0000000000000..ebfe0f65da904 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":743.3288275362728,"upper_bound":908.6925556131182},"point_estimate":826.0725227638465,"standard_error":42.228680040954494},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":730.554883126978,"upper_bound":880.4136712749616},"point_estimate":795.9134694079569,"standard_error":38.1836579863734},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":314.1203361849313,"upper_bound":540.3511021084902},"point_estimate":425.96399034809457,"standard_error":54.99488835092273},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":986.8242177463165,"upper_bound":1183.887455946972},"point_estimate":1088.5457954875892,"standard_error":50.2689257858626},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":371.04567149245105,"upper_bound":470.1606664819302},"point_estimate":424.16204814818775,"standard_error":25.219226454262476}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/raw.csv new file mode 100644 index 0000000000000..7d1295bd23988 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread allocation,crate 'sharded-slab',,,,43369.0,ns,93 +multi thread allocation,crate 'sharded-slab',,,,82301.0,ns,186 +multi thread allocation,crate 'sharded-slab',,,,188353.0,ns,279 +multi thread allocation,crate 'sharded-slab',,,,180327.0,ns,372 +multi thread allocation,crate 'sharded-slab',,,,169816.0,ns,465 +multi thread allocation,crate 'sharded-slab',,,,289050.0,ns,558 +multi thread allocation,crate 'sharded-slab',,,,226996.0,ns,651 +multi thread allocation,crate 'sharded-slab',,,,199965.0,ns,744 +multi thread allocation,crate 'sharded-slab',,,,191491.0,ns,837 +multi thread allocation,crate 'sharded-slab',,,,96691.0,ns,930 +multi thread allocation,crate 'sharded-slab',,,,451083.0,ns,1023 +multi thread allocation,crate 'sharded-slab',,,,432207.0,ns,1116 +multi thread allocation,crate 'sharded-slab',,,,422764.0,ns,1209 +multi thread allocation,crate 'sharded-slab',,,,415522.0,ns,1302 +multi thread allocation,crate 'sharded-slab',,,,170246.0,ns,1395 +multi thread allocation,crate 'sharded-slab',,,,72108.0,ns,1488 +multi thread allocation,crate 'sharded-slab',,,,58482.0,ns,1581 +multi thread allocation,crate 'sharded-slab',,,,62683.0,ns,1674 +multi thread allocation,crate 'sharded-slab',,,,61526.0,ns,1767 +multi thread allocation,crate 'sharded-slab',,,,64786.0,ns,1860 +multi thread allocation,crate 'sharded-slab',,,,76420.0,ns,1953 +multi thread allocation,crate 'sharded-slab',,,,933343.0,ns,2046 +multi thread allocation,crate 'sharded-slab',,,,1905313.0,ns,2139 +multi thread allocation,crate 'sharded-slab',,,,1902334.0,ns,2232 +multi thread allocation,crate 'sharded-slab',,,,1876130.0,ns,2325 +multi thread allocation,crate 'sharded-slab',,,,1879492.0,ns,2418 +multi thread allocation,crate 'sharded-slab',,,,1881111.0,ns,2511 +multi thread allocation,crate 'sharded-slab',,,,1887612.0,ns,2604 +multi thread allocation,crate 'sharded-slab',,,,1895827.0,ns,2697 +multi thread allocation,crate 'sharded-slab',,,,1871737.0,ns,2790 +multi thread allocation,crate 'sharded-slab',,,,1854001.0,ns,2883 +multi thread allocation,crate 'sharded-slab',,,,1861475.0,ns,2976 +multi thread allocation,crate 'sharded-slab',,,,1856519.0,ns,3069 +multi thread allocation,crate 'sharded-slab',,,,1870942.0,ns,3162 +multi thread allocation,crate 'sharded-slab',,,,1874670.0,ns,3255 +multi thread allocation,crate 'sharded-slab',,,,1875506.0,ns,3348 +multi thread allocation,crate 'sharded-slab',,,,1879921.0,ns,3441 +multi thread allocation,crate 'sharded-slab',,,,1893615.0,ns,3534 +multi thread allocation,crate 'sharded-slab',,,,1868373.0,ns,3627 +multi thread allocation,crate 'sharded-slab',,,,1900828.0,ns,3720 +multi thread allocation,crate 'sharded-slab',,,,1909319.0,ns,3813 +multi thread allocation,crate 'sharded-slab',,,,1893190.0,ns,3906 +multi thread allocation,crate 'sharded-slab',,,,1924961.0,ns,3999 +multi thread allocation,crate 'sharded-slab',,,,5768570.0,ns,4092 +multi thread allocation,crate 'sharded-slab',,,,5537586.0,ns,4185 +multi thread allocation,crate 'sharded-slab',,,,5581669.0,ns,4278 +multi thread allocation,crate 'sharded-slab',,,,5548793.0,ns,4371 +multi thread allocation,crate 'sharded-slab',,,,5552572.0,ns,4464 +multi thread allocation,crate 'sharded-slab',,,,5740316.0,ns,4557 +multi thread allocation,crate 'sharded-slab',,,,5681804.0,ns,4650 +multi thread allocation,crate 'sharded-slab',,,,6287889.0,ns,4743 +multi thread allocation,crate 'sharded-slab',,,,6406740.0,ns,4836 +multi thread allocation,crate 'sharded-slab',,,,5685851.0,ns,4929 +multi thread allocation,crate 'sharded-slab',,,,5629039.0,ns,5022 +multi thread allocation,crate 'sharded-slab',,,,5782987.0,ns,5115 +multi thread allocation,crate 'sharded-slab',,,,5728017.0,ns,5208 +multi thread allocation,crate 'sharded-slab',,,,5745351.0,ns,5301 +multi thread allocation,crate 'sharded-slab',,,,5839655.0,ns,5394 +multi thread allocation,crate 'sharded-slab',,,,5782661.0,ns,5487 +multi thread allocation,crate 'sharded-slab',,,,5686362.0,ns,5580 +multi thread allocation,crate 'sharded-slab',,,,5648150.0,ns,5673 +multi thread allocation,crate 'sharded-slab',,,,5644753.0,ns,5766 +multi thread allocation,crate 'sharded-slab',,,,5668432.0,ns,5859 +multi thread allocation,crate 'sharded-slab',,,,5608234.0,ns,5952 +multi thread allocation,crate 'sharded-slab',,,,5738554.0,ns,6045 +multi thread allocation,crate 'sharded-slab',,,,5607005.0,ns,6138 +multi thread allocation,crate 'sharded-slab',,,,5856712.0,ns,6231 +multi thread allocation,crate 'sharded-slab',,,,5690689.0,ns,6324 +multi thread allocation,crate 'sharded-slab',,,,5707171.0,ns,6417 +multi thread allocation,crate 'sharded-slab',,,,5731493.0,ns,6510 +multi thread allocation,crate 'sharded-slab',,,,5721577.0,ns,6603 +multi thread allocation,crate 'sharded-slab',,,,5695382.0,ns,6696 +multi thread allocation,crate 'sharded-slab',,,,5531700.0,ns,6789 +multi thread allocation,crate 'sharded-slab',,,,5868321.0,ns,6882 +multi thread allocation,crate 'sharded-slab',,,,5759368.0,ns,6975 +multi thread allocation,crate 'sharded-slab',,,,5702211.0,ns,7068 +multi thread allocation,crate 'sharded-slab',,,,5724662.0,ns,7161 +multi thread allocation,crate 'sharded-slab',,,,5681396.0,ns,7254 +multi thread allocation,crate 'sharded-slab',,,,5821798.0,ns,7347 +multi thread allocation,crate 'sharded-slab',,,,5778467.0,ns,7440 +multi thread allocation,crate 'sharded-slab',,,,5735630.0,ns,7533 +multi thread allocation,crate 'sharded-slab',,,,5736850.0,ns,7626 +multi thread allocation,crate 'sharded-slab',,,,5682885.0,ns,7719 +multi thread allocation,crate 'sharded-slab',,,,5752086.0,ns,7812 +multi thread allocation,crate 'sharded-slab',,,,5789857.0,ns,7905 +multi thread allocation,crate 'sharded-slab',,,,5746375.0,ns,7998 +multi thread allocation,crate 'sharded-slab',,,,5813764.0,ns,8091 +multi thread allocation,crate 'sharded-slab',,,,12842898.0,ns,8184 +multi thread allocation,crate 'sharded-slab',,,,13232937.0,ns,8277 +multi thread allocation,crate 'sharded-slab',,,,13662829.0,ns,8370 +multi thread allocation,crate 'sharded-slab',,,,14708815.0,ns,8463 +multi thread allocation,crate 'sharded-slab',,,,13402477.0,ns,8556 +multi thread allocation,crate 'sharded-slab',,,,13397324.0,ns,8649 +multi thread allocation,crate 'sharded-slab',,,,13318008.0,ns,8742 +multi thread allocation,crate 'sharded-slab',,,,13301050.0,ns,8835 +multi thread allocation,crate 'sharded-slab',,,,13235599.0,ns,8928 +multi thread allocation,crate 'sharded-slab',,,,13119033.0,ns,9021 +multi thread allocation,crate 'sharded-slab',,,,13208045.0,ns,9114 +multi thread allocation,crate 'sharded-slab',,,,13266163.0,ns,9207 +multi thread allocation,crate 'sharded-slab',,,,13286533.0,ns,9300 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/sample.json new file mode 100644 index 0000000000000..fd67182275394 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[93.0,186.0,279.0,372.0,465.0,558.0,651.0,744.0,837.0,930.0,1023.0,1116.0,1209.0,1302.0,1395.0,1488.0,1581.0,1674.0,1767.0,1860.0,1953.0,2046.0,2139.0,2232.0,2325.0,2418.0,2511.0,2604.0,2697.0,2790.0,2883.0,2976.0,3069.0,3162.0,3255.0,3348.0,3441.0,3534.0,3627.0,3720.0,3813.0,3906.0,3999.0,4092.0,4185.0,4278.0,4371.0,4464.0,4557.0,4650.0,4743.0,4836.0,4929.0,5022.0,5115.0,5208.0,5301.0,5394.0,5487.0,5580.0,5673.0,5766.0,5859.0,5952.0,6045.0,6138.0,6231.0,6324.0,6417.0,6510.0,6603.0,6696.0,6789.0,6882.0,6975.0,7068.0,7161.0,7254.0,7347.0,7440.0,7533.0,7626.0,7719.0,7812.0,7905.0,7998.0,8091.0,8184.0,8277.0,8370.0,8463.0,8556.0,8649.0,8742.0,8835.0,8928.0,9021.0,9114.0,9207.0,9300.0],"times":[43369.0,82301.0,188353.0,180327.0,169816.0,289050.0,226996.0,199965.0,191491.0,96691.0,451083.0,432207.0,422764.0,415522.0,170246.0,72108.0,58482.0,62683.0,61526.0,64786.0,76420.0,933343.0,1905313.0,1902334.0,1876130.0,1879492.0,1881111.0,1887612.0,1895827.0,1871737.0,1854001.0,1861475.0,1856519.0,1870942.0,1874670.0,1875506.0,1879921.0,1893615.0,1868373.0,1900828.0,1909319.0,1893190.0,1924961.0,5768570.0,5537586.0,5581669.0,5548793.0,5552572.0,5740316.0,5681804.0,6287889.0,6406740.0,5685851.0,5629039.0,5782987.0,5728017.0,5745351.0,5839655.0,5782661.0,5686362.0,5648150.0,5644753.0,5668432.0,5608234.0,5738554.0,5607005.0,5856712.0,5690689.0,5707171.0,5731493.0,5721577.0,5695382.0,5531700.0,5868321.0,5759368.0,5702211.0,5724662.0,5681396.0,5821798.0,5778467.0,5735630.0,5736850.0,5682885.0,5752086.0,5789857.0,5746375.0,5813764.0,12842898.0,13232937.0,13662829.0,14708815.0,13402477.0,13397324.0,13318008.0,13301050.0,13235599.0,13119033.0,13208045.0,13266163.0,13286533.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/tukey.json new file mode 100644 index 0000000000000..33987845cdbe4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/base/tukey.json @@ -0,0 +1 @@ +[-1246.1573914063838,-364.43353441286934,1986.8300842365024,2868.553941230017] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/benchmark.json new file mode 100644 index 0000000000000..e5a49f89e9326 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread allocation","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"multi thread allocation/crate 'sharded-slab'","directory_name":"multi thread allocation/crate 'sharded-slab'","title":"multi thread allocation/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/estimates.json new file mode 100644 index 0000000000000..ebfe0f65da904 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":743.3288275362728,"upper_bound":908.6925556131182},"point_estimate":826.0725227638465,"standard_error":42.228680040954494},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":730.554883126978,"upper_bound":880.4136712749616},"point_estimate":795.9134694079569,"standard_error":38.1836579863734},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":314.1203361849313,"upper_bound":540.3511021084902},"point_estimate":425.96399034809457,"standard_error":54.99488835092273},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":986.8242177463165,"upper_bound":1183.887455946972},"point_estimate":1088.5457954875892,"standard_error":50.2689257858626},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":371.04567149245105,"upper_bound":470.1606664819302},"point_estimate":424.16204814818775,"standard_error":25.219226454262476}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/raw.csv new file mode 100644 index 0000000000000..7d1295bd23988 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread allocation,crate 'sharded-slab',,,,43369.0,ns,93 +multi thread allocation,crate 'sharded-slab',,,,82301.0,ns,186 +multi thread allocation,crate 'sharded-slab',,,,188353.0,ns,279 +multi thread allocation,crate 'sharded-slab',,,,180327.0,ns,372 +multi thread allocation,crate 'sharded-slab',,,,169816.0,ns,465 +multi thread allocation,crate 'sharded-slab',,,,289050.0,ns,558 +multi thread allocation,crate 'sharded-slab',,,,226996.0,ns,651 +multi thread allocation,crate 'sharded-slab',,,,199965.0,ns,744 +multi thread allocation,crate 'sharded-slab',,,,191491.0,ns,837 +multi thread allocation,crate 'sharded-slab',,,,96691.0,ns,930 +multi thread allocation,crate 'sharded-slab',,,,451083.0,ns,1023 +multi thread allocation,crate 'sharded-slab',,,,432207.0,ns,1116 +multi thread allocation,crate 'sharded-slab',,,,422764.0,ns,1209 +multi thread allocation,crate 'sharded-slab',,,,415522.0,ns,1302 +multi thread allocation,crate 'sharded-slab',,,,170246.0,ns,1395 +multi thread allocation,crate 'sharded-slab',,,,72108.0,ns,1488 +multi thread allocation,crate 'sharded-slab',,,,58482.0,ns,1581 +multi thread allocation,crate 'sharded-slab',,,,62683.0,ns,1674 +multi thread allocation,crate 'sharded-slab',,,,61526.0,ns,1767 +multi thread allocation,crate 'sharded-slab',,,,64786.0,ns,1860 +multi thread allocation,crate 'sharded-slab',,,,76420.0,ns,1953 +multi thread allocation,crate 'sharded-slab',,,,933343.0,ns,2046 +multi thread allocation,crate 'sharded-slab',,,,1905313.0,ns,2139 +multi thread allocation,crate 'sharded-slab',,,,1902334.0,ns,2232 +multi thread allocation,crate 'sharded-slab',,,,1876130.0,ns,2325 +multi thread allocation,crate 'sharded-slab',,,,1879492.0,ns,2418 +multi thread allocation,crate 'sharded-slab',,,,1881111.0,ns,2511 +multi thread allocation,crate 'sharded-slab',,,,1887612.0,ns,2604 +multi thread allocation,crate 'sharded-slab',,,,1895827.0,ns,2697 +multi thread allocation,crate 'sharded-slab',,,,1871737.0,ns,2790 +multi thread allocation,crate 'sharded-slab',,,,1854001.0,ns,2883 +multi thread allocation,crate 'sharded-slab',,,,1861475.0,ns,2976 +multi thread allocation,crate 'sharded-slab',,,,1856519.0,ns,3069 +multi thread allocation,crate 'sharded-slab',,,,1870942.0,ns,3162 +multi thread allocation,crate 'sharded-slab',,,,1874670.0,ns,3255 +multi thread allocation,crate 'sharded-slab',,,,1875506.0,ns,3348 +multi thread allocation,crate 'sharded-slab',,,,1879921.0,ns,3441 +multi thread allocation,crate 'sharded-slab',,,,1893615.0,ns,3534 +multi thread allocation,crate 'sharded-slab',,,,1868373.0,ns,3627 +multi thread allocation,crate 'sharded-slab',,,,1900828.0,ns,3720 +multi thread allocation,crate 'sharded-slab',,,,1909319.0,ns,3813 +multi thread allocation,crate 'sharded-slab',,,,1893190.0,ns,3906 +multi thread allocation,crate 'sharded-slab',,,,1924961.0,ns,3999 +multi thread allocation,crate 'sharded-slab',,,,5768570.0,ns,4092 +multi thread allocation,crate 'sharded-slab',,,,5537586.0,ns,4185 +multi thread allocation,crate 'sharded-slab',,,,5581669.0,ns,4278 +multi thread allocation,crate 'sharded-slab',,,,5548793.0,ns,4371 +multi thread allocation,crate 'sharded-slab',,,,5552572.0,ns,4464 +multi thread allocation,crate 'sharded-slab',,,,5740316.0,ns,4557 +multi thread allocation,crate 'sharded-slab',,,,5681804.0,ns,4650 +multi thread allocation,crate 'sharded-slab',,,,6287889.0,ns,4743 +multi thread allocation,crate 'sharded-slab',,,,6406740.0,ns,4836 +multi thread allocation,crate 'sharded-slab',,,,5685851.0,ns,4929 +multi thread allocation,crate 'sharded-slab',,,,5629039.0,ns,5022 +multi thread allocation,crate 'sharded-slab',,,,5782987.0,ns,5115 +multi thread allocation,crate 'sharded-slab',,,,5728017.0,ns,5208 +multi thread allocation,crate 'sharded-slab',,,,5745351.0,ns,5301 +multi thread allocation,crate 'sharded-slab',,,,5839655.0,ns,5394 +multi thread allocation,crate 'sharded-slab',,,,5782661.0,ns,5487 +multi thread allocation,crate 'sharded-slab',,,,5686362.0,ns,5580 +multi thread allocation,crate 'sharded-slab',,,,5648150.0,ns,5673 +multi thread allocation,crate 'sharded-slab',,,,5644753.0,ns,5766 +multi thread allocation,crate 'sharded-slab',,,,5668432.0,ns,5859 +multi thread allocation,crate 'sharded-slab',,,,5608234.0,ns,5952 +multi thread allocation,crate 'sharded-slab',,,,5738554.0,ns,6045 +multi thread allocation,crate 'sharded-slab',,,,5607005.0,ns,6138 +multi thread allocation,crate 'sharded-slab',,,,5856712.0,ns,6231 +multi thread allocation,crate 'sharded-slab',,,,5690689.0,ns,6324 +multi thread allocation,crate 'sharded-slab',,,,5707171.0,ns,6417 +multi thread allocation,crate 'sharded-slab',,,,5731493.0,ns,6510 +multi thread allocation,crate 'sharded-slab',,,,5721577.0,ns,6603 +multi thread allocation,crate 'sharded-slab',,,,5695382.0,ns,6696 +multi thread allocation,crate 'sharded-slab',,,,5531700.0,ns,6789 +multi thread allocation,crate 'sharded-slab',,,,5868321.0,ns,6882 +multi thread allocation,crate 'sharded-slab',,,,5759368.0,ns,6975 +multi thread allocation,crate 'sharded-slab',,,,5702211.0,ns,7068 +multi thread allocation,crate 'sharded-slab',,,,5724662.0,ns,7161 +multi thread allocation,crate 'sharded-slab',,,,5681396.0,ns,7254 +multi thread allocation,crate 'sharded-slab',,,,5821798.0,ns,7347 +multi thread allocation,crate 'sharded-slab',,,,5778467.0,ns,7440 +multi thread allocation,crate 'sharded-slab',,,,5735630.0,ns,7533 +multi thread allocation,crate 'sharded-slab',,,,5736850.0,ns,7626 +multi thread allocation,crate 'sharded-slab',,,,5682885.0,ns,7719 +multi thread allocation,crate 'sharded-slab',,,,5752086.0,ns,7812 +multi thread allocation,crate 'sharded-slab',,,,5789857.0,ns,7905 +multi thread allocation,crate 'sharded-slab',,,,5746375.0,ns,7998 +multi thread allocation,crate 'sharded-slab',,,,5813764.0,ns,8091 +multi thread allocation,crate 'sharded-slab',,,,12842898.0,ns,8184 +multi thread allocation,crate 'sharded-slab',,,,13232937.0,ns,8277 +multi thread allocation,crate 'sharded-slab',,,,13662829.0,ns,8370 +multi thread allocation,crate 'sharded-slab',,,,14708815.0,ns,8463 +multi thread allocation,crate 'sharded-slab',,,,13402477.0,ns,8556 +multi thread allocation,crate 'sharded-slab',,,,13397324.0,ns,8649 +multi thread allocation,crate 'sharded-slab',,,,13318008.0,ns,8742 +multi thread allocation,crate 'sharded-slab',,,,13301050.0,ns,8835 +multi thread allocation,crate 'sharded-slab',,,,13235599.0,ns,8928 +multi thread allocation,crate 'sharded-slab',,,,13119033.0,ns,9021 +multi thread allocation,crate 'sharded-slab',,,,13208045.0,ns,9114 +multi thread allocation,crate 'sharded-slab',,,,13266163.0,ns,9207 +multi thread allocation,crate 'sharded-slab',,,,13286533.0,ns,9300 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/sample.json new file mode 100644 index 0000000000000..fd67182275394 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[93.0,186.0,279.0,372.0,465.0,558.0,651.0,744.0,837.0,930.0,1023.0,1116.0,1209.0,1302.0,1395.0,1488.0,1581.0,1674.0,1767.0,1860.0,1953.0,2046.0,2139.0,2232.0,2325.0,2418.0,2511.0,2604.0,2697.0,2790.0,2883.0,2976.0,3069.0,3162.0,3255.0,3348.0,3441.0,3534.0,3627.0,3720.0,3813.0,3906.0,3999.0,4092.0,4185.0,4278.0,4371.0,4464.0,4557.0,4650.0,4743.0,4836.0,4929.0,5022.0,5115.0,5208.0,5301.0,5394.0,5487.0,5580.0,5673.0,5766.0,5859.0,5952.0,6045.0,6138.0,6231.0,6324.0,6417.0,6510.0,6603.0,6696.0,6789.0,6882.0,6975.0,7068.0,7161.0,7254.0,7347.0,7440.0,7533.0,7626.0,7719.0,7812.0,7905.0,7998.0,8091.0,8184.0,8277.0,8370.0,8463.0,8556.0,8649.0,8742.0,8835.0,8928.0,9021.0,9114.0,9207.0,9300.0],"times":[43369.0,82301.0,188353.0,180327.0,169816.0,289050.0,226996.0,199965.0,191491.0,96691.0,451083.0,432207.0,422764.0,415522.0,170246.0,72108.0,58482.0,62683.0,61526.0,64786.0,76420.0,933343.0,1905313.0,1902334.0,1876130.0,1879492.0,1881111.0,1887612.0,1895827.0,1871737.0,1854001.0,1861475.0,1856519.0,1870942.0,1874670.0,1875506.0,1879921.0,1893615.0,1868373.0,1900828.0,1909319.0,1893190.0,1924961.0,5768570.0,5537586.0,5581669.0,5548793.0,5552572.0,5740316.0,5681804.0,6287889.0,6406740.0,5685851.0,5629039.0,5782987.0,5728017.0,5745351.0,5839655.0,5782661.0,5686362.0,5648150.0,5644753.0,5668432.0,5608234.0,5738554.0,5607005.0,5856712.0,5690689.0,5707171.0,5731493.0,5721577.0,5695382.0,5531700.0,5868321.0,5759368.0,5702211.0,5724662.0,5681396.0,5821798.0,5778467.0,5735630.0,5736850.0,5682885.0,5752086.0,5789857.0,5746375.0,5813764.0,12842898.0,13232937.0,13662829.0,14708815.0,13402477.0,13397324.0,13318008.0,13301050.0,13235599.0,13119033.0,13208045.0,13266163.0,13286533.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/tukey.json new file mode 100644 index 0000000000000..33987845cdbe4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/new/tukey.json @@ -0,0 +1 @@ +[-1246.1573914063838,-364.43353441286934,1986.8300842365024,2868.553941230017] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/MAD.svg new file mode 100644 index 0000000000000..50c0e37410cb5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/MAD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 0.009 + + + + + 300 + + + + + 350 + + + + + 400 + + + + + 450 + + + + + 500 + + + + + 550 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/crate 'sharded-slab': MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/SD.svg new file mode 100644 index 0000000000000..4b7c2f1afd4f2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 380 + + + + + 400 + + + + + 420 + + + + + 440 + + + + + 460 + + + + + 480 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/crate 'sharded-slab': SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/index.html new file mode 100644 index 0000000000000..bd3b4bf38c8dc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/index.html @@ -0,0 +1,203 @@ + + + + + + multi thread allocation/crate 'sharded-slab' - Criterion.rs + + + + +
+

multi thread allocation/crate 'sharded-slab'

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope986.82 ns1.0885 us1.1839 us
0.14929860.15907200.1504215
Mean743.33 ns826.07 ns908.69 ns
Std. Dev.371.05 ns424.16 ns470.16 ns
Median730.55 ns795.91 ns880.41 ns
MAD314.12 ns425.96 ns540.35 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/mean.svg new file mode 100644 index 0000000000000..153959a47279c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/mean.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 0.009 + + + + + 0.01 + + + + + 750 + + + + + 800 + + + + + 850 + + + + + 900 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/crate 'sharded-slab': mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/median.svg new file mode 100644 index 0000000000000..52de1307d5033 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/median.svg @@ -0,0 +1,313 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 720 + + + + + 740 + + + + + 760 + + + + + 780 + + + + + 800 + + + + + 820 + + + + + 840 + + + + + 860 + + + + + 880 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/crate 'sharded-slab': median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/pdf.svg new file mode 100644 index 0000000000000..860f6336feb4b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/pdf.svg @@ -0,0 +1,430 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + -0.5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 0.9 + + + + + 1 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/crate 'sharded-slab' + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/pdf_small.svg new file mode 100644 index 0000000000000..dbda3d98d9e0d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/pdf_small.svg @@ -0,0 +1,204 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + -0.5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/regression.svg new file mode 100644 index 0000000000000..e20cd938ef594 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/regression.svg @@ -0,0 +1,473 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 9 + + + + + + + + + + + + + 10 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + multi thread allocation/crate 'sharded-slab' + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/regression_small.svg new file mode 100644 index 0000000000000..eaa57ba2ca7b1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/regression_small.svg @@ -0,0 +1,451 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 9 + + + + + + + + + + + + + 10 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/slope.svg new file mode 100644 index 0000000000000..a0d9dbfac2cd9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 1 + + + + + 1.05 + + + + + 1.1 + + + + + 1.15 + + + + + 1.2 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/crate 'sharded-slab': slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/typical.svg new file mode 100644 index 0000000000000..ed150c1d398bc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/crate 'sharded-slab'/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 1 + + + + + 1.05 + + + + + 1.1 + + + + + 1.15 + + + + + 1.2 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/crate 'sharded-slab': typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/benchmark.json new file mode 100644 index 0000000000000..5b9fcfd70e0af --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread allocation","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"multi thread allocation/linear object poll","directory_name":"multi thread allocation/linear object poll","title":"multi thread allocation/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/estimates.json new file mode 100644 index 0000000000000..f5da0f10bdd70 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":358.39725434253194,"upper_bound":420.98819683892526},"point_estimate":389.1281881162464,"standard_error":15.948598398516442},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":338.8808080808081,"upper_bound":415.1906595226268},"point_estimate":372.0479291738136,"standard_error":21.28334719456712},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":123.61600506674542,"upper_bound":200.2760675294193},"point_estimate":165.37410562103275,"standard_error":19.359156283028074},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":480.36299692153335,"upper_bound":561.7852661149298},"point_estimate":521.1707541948225,"standard_error":20.838308942223083},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":132.95325613072947,"upper_bound":185.6003828949239},"point_estimate":160.46760269632745,"standard_error":13.518048885125749}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/raw.csv new file mode 100644 index 0000000000000..c051113bc7a8a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread allocation,linear object poll,,,,4622.0,ns,22 +multi thread allocation,linear object poll,,,,8461.0,ns,44 +multi thread allocation,linear object poll,,,,9637.0,ns,66 +multi thread allocation,linear object poll,,,,12346.0,ns,88 +multi thread allocation,linear object poll,,,,18375.0,ns,110 +multi thread allocation,linear object poll,,,,21167.0,ns,132 +multi thread allocation,linear object poll,,,,27077.0,ns,154 +multi thread allocation,linear object poll,,,,34938.0,ns,176 +multi thread allocation,linear object poll,,,,38400.0,ns,198 +multi thread allocation,linear object poll,,,,50027.0,ns,220 +multi thread allocation,linear object poll,,,,50111.0,ns,242 +multi thread allocation,linear object poll,,,,49806.0,ns,264 +multi thread allocation,linear object poll,,,,83299.0,ns,286 +multi thread allocation,linear object poll,,,,66078.0,ns,308 +multi thread allocation,linear object poll,,,,76163.0,ns,330 +multi thread allocation,linear object poll,,,,85126.0,ns,352 +multi thread allocation,linear object poll,,,,85508.0,ns,374 +multi thread allocation,linear object poll,,,,96940.0,ns,396 +multi thread allocation,linear object poll,,,,96096.0,ns,418 +multi thread allocation,linear object poll,,,,100371.0,ns,440 +multi thread allocation,linear object poll,,,,115046.0,ns,462 +multi thread allocation,linear object poll,,,,133183.0,ns,484 +multi thread allocation,linear object poll,,,,119371.0,ns,506 +multi thread allocation,linear object poll,,,,135306.0,ns,528 +multi thread allocation,linear object poll,,,,41976.0,ns,550 +multi thread allocation,linear object poll,,,,141150.0,ns,572 +multi thread allocation,linear object poll,,,,170298.0,ns,594 +multi thread allocation,linear object poll,,,,165693.0,ns,616 +multi thread allocation,linear object poll,,,,174408.0,ns,638 +multi thread allocation,linear object poll,,,,184803.0,ns,660 +multi thread allocation,linear object poll,,,,191910.0,ns,682 +multi thread allocation,linear object poll,,,,200009.0,ns,704 +multi thread allocation,linear object poll,,,,221708.0,ns,726 +multi thread allocation,linear object poll,,,,235897.0,ns,748 +multi thread allocation,linear object poll,,,,225961.0,ns,770 +multi thread allocation,linear object poll,,,,375289.0,ns,792 +multi thread allocation,linear object poll,,,,283560.0,ns,814 +multi thread allocation,linear object poll,,,,298083.0,ns,836 +multi thread allocation,linear object poll,,,,275138.0,ns,858 +multi thread allocation,linear object poll,,,,279745.0,ns,880 +multi thread allocation,linear object poll,,,,278342.0,ns,902 +multi thread allocation,linear object poll,,,,312357.0,ns,924 +multi thread allocation,linear object poll,,,,332260.0,ns,946 +multi thread allocation,linear object poll,,,,327375.0,ns,968 +multi thread allocation,linear object poll,,,,335492.0,ns,990 +multi thread allocation,linear object poll,,,,354484.0,ns,1012 +multi thread allocation,linear object poll,,,,359527.0,ns,1034 +multi thread allocation,linear object poll,,,,391937.0,ns,1056 +multi thread allocation,linear object poll,,,,378831.0,ns,1078 +multi thread allocation,linear object poll,,,,389063.0,ns,1100 +multi thread allocation,linear object poll,,,,407828.0,ns,1122 +multi thread allocation,linear object poll,,,,435505.0,ns,1144 +multi thread allocation,linear object poll,,,,434852.0,ns,1166 +multi thread allocation,linear object poll,,,,451698.0,ns,1188 +multi thread allocation,linear object poll,,,,456506.0,ns,1210 +multi thread allocation,linear object poll,,,,469654.0,ns,1232 +multi thread allocation,linear object poll,,,,515355.0,ns,1254 +multi thread allocation,linear object poll,,,,546512.0,ns,1276 +multi thread allocation,linear object poll,,,,580188.0,ns,1298 +multi thread allocation,linear object poll,,,,542990.0,ns,1320 +multi thread allocation,linear object poll,,,,555329.0,ns,1342 +multi thread allocation,linear object poll,,,,565785.0,ns,1364 +multi thread allocation,linear object poll,,,,577372.0,ns,1386 +multi thread allocation,linear object poll,,,,603748.0,ns,1408 +multi thread allocation,linear object poll,,,,590922.0,ns,1430 +multi thread allocation,linear object poll,,,,609068.0,ns,1452 +multi thread allocation,linear object poll,,,,629291.0,ns,1474 +multi thread allocation,linear object poll,,,,681656.0,ns,1496 +multi thread allocation,linear object poll,,,,726389.0,ns,1518 +multi thread allocation,linear object poll,,,,676568.0,ns,1540 +multi thread allocation,linear object poll,,,,674081.0,ns,1562 +multi thread allocation,linear object poll,,,,728003.0,ns,1584 +multi thread allocation,linear object poll,,,,775922.0,ns,1606 +multi thread allocation,linear object poll,,,,788022.0,ns,1628 +multi thread allocation,linear object poll,,,,813900.0,ns,1650 +multi thread allocation,linear object poll,,,,803263.0,ns,1672 +multi thread allocation,linear object poll,,,,831516.0,ns,1694 +multi thread allocation,linear object poll,,,,920272.0,ns,1716 +multi thread allocation,linear object poll,,,,965481.0,ns,1738 +multi thread allocation,linear object poll,,,,982812.0,ns,1760 +multi thread allocation,linear object poll,,,,985153.0,ns,1782 +multi thread allocation,linear object poll,,,,976359.0,ns,1804 +multi thread allocation,linear object poll,,,,1028168.0,ns,1826 +multi thread allocation,linear object poll,,,,1016298.0,ns,1848 +multi thread allocation,linear object poll,,,,1028615.0,ns,1870 +multi thread allocation,linear object poll,,,,953686.0,ns,1892 +multi thread allocation,linear object poll,,,,983755.0,ns,1914 +multi thread allocation,linear object poll,,,,1560345.0,ns,1936 +multi thread allocation,linear object poll,,,,1085873.0,ns,1958 +multi thread allocation,linear object poll,,,,1104174.0,ns,1980 +multi thread allocation,linear object poll,,,,1083886.0,ns,2002 +multi thread allocation,linear object poll,,,,1124029.0,ns,2024 +multi thread allocation,linear object poll,,,,1055966.0,ns,2046 +multi thread allocation,linear object poll,,,,1652820.0,ns,2068 +multi thread allocation,linear object poll,,,,1309539.0,ns,2090 +multi thread allocation,linear object poll,,,,1165601.0,ns,2112 +multi thread allocation,linear object poll,,,,1163756.0,ns,2134 +multi thread allocation,linear object poll,,,,1714472.0,ns,2156 +multi thread allocation,linear object poll,,,,1931090.0,ns,2178 +multi thread allocation,linear object poll,,,,1883115.0,ns,2200 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/sample.json new file mode 100644 index 0000000000000..17ba9b6bb48f7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[22.0,44.0,66.0,88.0,110.0,132.0,154.0,176.0,198.0,220.0,242.0,264.0,286.0,308.0,330.0,352.0,374.0,396.0,418.0,440.0,462.0,484.0,506.0,528.0,550.0,572.0,594.0,616.0,638.0,660.0,682.0,704.0,726.0,748.0,770.0,792.0,814.0,836.0,858.0,880.0,902.0,924.0,946.0,968.0,990.0,1012.0,1034.0,1056.0,1078.0,1100.0,1122.0,1144.0,1166.0,1188.0,1210.0,1232.0,1254.0,1276.0,1298.0,1320.0,1342.0,1364.0,1386.0,1408.0,1430.0,1452.0,1474.0,1496.0,1518.0,1540.0,1562.0,1584.0,1606.0,1628.0,1650.0,1672.0,1694.0,1716.0,1738.0,1760.0,1782.0,1804.0,1826.0,1848.0,1870.0,1892.0,1914.0,1936.0,1958.0,1980.0,2002.0,2024.0,2046.0,2068.0,2090.0,2112.0,2134.0,2156.0,2178.0,2200.0],"times":[4622.0,8461.0,9637.0,12346.0,18375.0,21167.0,27077.0,34938.0,38400.0,50027.0,50111.0,49806.0,83299.0,66078.0,76163.0,85126.0,85508.0,96940.0,96096.0,100371.0,115046.0,133183.0,119371.0,135306.0,41976.0,141150.0,170298.0,165693.0,174408.0,184803.0,191910.0,200009.0,221708.0,235897.0,225961.0,375289.0,283560.0,298083.0,275138.0,279745.0,278342.0,312357.0,332260.0,327375.0,335492.0,354484.0,359527.0,391937.0,378831.0,389063.0,407828.0,435505.0,434852.0,451698.0,456506.0,469654.0,515355.0,546512.0,580188.0,542990.0,555329.0,565785.0,577372.0,603748.0,590922.0,609068.0,629291.0,681656.0,726389.0,676568.0,674081.0,728003.0,775922.0,788022.0,813900.0,803263.0,831516.0,920272.0,965481.0,982812.0,985153.0,976359.0,1028168.0,1016298.0,1028615.0,953686.0,983755.0,1560345.0,1085873.0,1104174.0,1083886.0,1124029.0,1055966.0,1652820.0,1309539.0,1165601.0,1163756.0,1714472.0,1931090.0,1883115.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/tukey.json new file mode 100644 index 0000000000000..9579d2e1bdbe2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/base/tukey.json @@ -0,0 +1 @@ +[-368.1589162341514,-47.94415107497986,805.9618893494776,1126.176654508649] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/benchmark.json new file mode 100644 index 0000000000000..5b9fcfd70e0af --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread allocation","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"multi thread allocation/linear object poll","directory_name":"multi thread allocation/linear object poll","title":"multi thread allocation/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/estimates.json new file mode 100644 index 0000000000000..f5da0f10bdd70 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":358.39725434253194,"upper_bound":420.98819683892526},"point_estimate":389.1281881162464,"standard_error":15.948598398516442},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":338.8808080808081,"upper_bound":415.1906595226268},"point_estimate":372.0479291738136,"standard_error":21.28334719456712},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":123.61600506674542,"upper_bound":200.2760675294193},"point_estimate":165.37410562103275,"standard_error":19.359156283028074},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":480.36299692153335,"upper_bound":561.7852661149298},"point_estimate":521.1707541948225,"standard_error":20.838308942223083},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":132.95325613072947,"upper_bound":185.6003828949239},"point_estimate":160.46760269632745,"standard_error":13.518048885125749}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/raw.csv new file mode 100644 index 0000000000000..c051113bc7a8a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread allocation,linear object poll,,,,4622.0,ns,22 +multi thread allocation,linear object poll,,,,8461.0,ns,44 +multi thread allocation,linear object poll,,,,9637.0,ns,66 +multi thread allocation,linear object poll,,,,12346.0,ns,88 +multi thread allocation,linear object poll,,,,18375.0,ns,110 +multi thread allocation,linear object poll,,,,21167.0,ns,132 +multi thread allocation,linear object poll,,,,27077.0,ns,154 +multi thread allocation,linear object poll,,,,34938.0,ns,176 +multi thread allocation,linear object poll,,,,38400.0,ns,198 +multi thread allocation,linear object poll,,,,50027.0,ns,220 +multi thread allocation,linear object poll,,,,50111.0,ns,242 +multi thread allocation,linear object poll,,,,49806.0,ns,264 +multi thread allocation,linear object poll,,,,83299.0,ns,286 +multi thread allocation,linear object poll,,,,66078.0,ns,308 +multi thread allocation,linear object poll,,,,76163.0,ns,330 +multi thread allocation,linear object poll,,,,85126.0,ns,352 +multi thread allocation,linear object poll,,,,85508.0,ns,374 +multi thread allocation,linear object poll,,,,96940.0,ns,396 +multi thread allocation,linear object poll,,,,96096.0,ns,418 +multi thread allocation,linear object poll,,,,100371.0,ns,440 +multi thread allocation,linear object poll,,,,115046.0,ns,462 +multi thread allocation,linear object poll,,,,133183.0,ns,484 +multi thread allocation,linear object poll,,,,119371.0,ns,506 +multi thread allocation,linear object poll,,,,135306.0,ns,528 +multi thread allocation,linear object poll,,,,41976.0,ns,550 +multi thread allocation,linear object poll,,,,141150.0,ns,572 +multi thread allocation,linear object poll,,,,170298.0,ns,594 +multi thread allocation,linear object poll,,,,165693.0,ns,616 +multi thread allocation,linear object poll,,,,174408.0,ns,638 +multi thread allocation,linear object poll,,,,184803.0,ns,660 +multi thread allocation,linear object poll,,,,191910.0,ns,682 +multi thread allocation,linear object poll,,,,200009.0,ns,704 +multi thread allocation,linear object poll,,,,221708.0,ns,726 +multi thread allocation,linear object poll,,,,235897.0,ns,748 +multi thread allocation,linear object poll,,,,225961.0,ns,770 +multi thread allocation,linear object poll,,,,375289.0,ns,792 +multi thread allocation,linear object poll,,,,283560.0,ns,814 +multi thread allocation,linear object poll,,,,298083.0,ns,836 +multi thread allocation,linear object poll,,,,275138.0,ns,858 +multi thread allocation,linear object poll,,,,279745.0,ns,880 +multi thread allocation,linear object poll,,,,278342.0,ns,902 +multi thread allocation,linear object poll,,,,312357.0,ns,924 +multi thread allocation,linear object poll,,,,332260.0,ns,946 +multi thread allocation,linear object poll,,,,327375.0,ns,968 +multi thread allocation,linear object poll,,,,335492.0,ns,990 +multi thread allocation,linear object poll,,,,354484.0,ns,1012 +multi thread allocation,linear object poll,,,,359527.0,ns,1034 +multi thread allocation,linear object poll,,,,391937.0,ns,1056 +multi thread allocation,linear object poll,,,,378831.0,ns,1078 +multi thread allocation,linear object poll,,,,389063.0,ns,1100 +multi thread allocation,linear object poll,,,,407828.0,ns,1122 +multi thread allocation,linear object poll,,,,435505.0,ns,1144 +multi thread allocation,linear object poll,,,,434852.0,ns,1166 +multi thread allocation,linear object poll,,,,451698.0,ns,1188 +multi thread allocation,linear object poll,,,,456506.0,ns,1210 +multi thread allocation,linear object poll,,,,469654.0,ns,1232 +multi thread allocation,linear object poll,,,,515355.0,ns,1254 +multi thread allocation,linear object poll,,,,546512.0,ns,1276 +multi thread allocation,linear object poll,,,,580188.0,ns,1298 +multi thread allocation,linear object poll,,,,542990.0,ns,1320 +multi thread allocation,linear object poll,,,,555329.0,ns,1342 +multi thread allocation,linear object poll,,,,565785.0,ns,1364 +multi thread allocation,linear object poll,,,,577372.0,ns,1386 +multi thread allocation,linear object poll,,,,603748.0,ns,1408 +multi thread allocation,linear object poll,,,,590922.0,ns,1430 +multi thread allocation,linear object poll,,,,609068.0,ns,1452 +multi thread allocation,linear object poll,,,,629291.0,ns,1474 +multi thread allocation,linear object poll,,,,681656.0,ns,1496 +multi thread allocation,linear object poll,,,,726389.0,ns,1518 +multi thread allocation,linear object poll,,,,676568.0,ns,1540 +multi thread allocation,linear object poll,,,,674081.0,ns,1562 +multi thread allocation,linear object poll,,,,728003.0,ns,1584 +multi thread allocation,linear object poll,,,,775922.0,ns,1606 +multi thread allocation,linear object poll,,,,788022.0,ns,1628 +multi thread allocation,linear object poll,,,,813900.0,ns,1650 +multi thread allocation,linear object poll,,,,803263.0,ns,1672 +multi thread allocation,linear object poll,,,,831516.0,ns,1694 +multi thread allocation,linear object poll,,,,920272.0,ns,1716 +multi thread allocation,linear object poll,,,,965481.0,ns,1738 +multi thread allocation,linear object poll,,,,982812.0,ns,1760 +multi thread allocation,linear object poll,,,,985153.0,ns,1782 +multi thread allocation,linear object poll,,,,976359.0,ns,1804 +multi thread allocation,linear object poll,,,,1028168.0,ns,1826 +multi thread allocation,linear object poll,,,,1016298.0,ns,1848 +multi thread allocation,linear object poll,,,,1028615.0,ns,1870 +multi thread allocation,linear object poll,,,,953686.0,ns,1892 +multi thread allocation,linear object poll,,,,983755.0,ns,1914 +multi thread allocation,linear object poll,,,,1560345.0,ns,1936 +multi thread allocation,linear object poll,,,,1085873.0,ns,1958 +multi thread allocation,linear object poll,,,,1104174.0,ns,1980 +multi thread allocation,linear object poll,,,,1083886.0,ns,2002 +multi thread allocation,linear object poll,,,,1124029.0,ns,2024 +multi thread allocation,linear object poll,,,,1055966.0,ns,2046 +multi thread allocation,linear object poll,,,,1652820.0,ns,2068 +multi thread allocation,linear object poll,,,,1309539.0,ns,2090 +multi thread allocation,linear object poll,,,,1165601.0,ns,2112 +multi thread allocation,linear object poll,,,,1163756.0,ns,2134 +multi thread allocation,linear object poll,,,,1714472.0,ns,2156 +multi thread allocation,linear object poll,,,,1931090.0,ns,2178 +multi thread allocation,linear object poll,,,,1883115.0,ns,2200 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/sample.json new file mode 100644 index 0000000000000..17ba9b6bb48f7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[22.0,44.0,66.0,88.0,110.0,132.0,154.0,176.0,198.0,220.0,242.0,264.0,286.0,308.0,330.0,352.0,374.0,396.0,418.0,440.0,462.0,484.0,506.0,528.0,550.0,572.0,594.0,616.0,638.0,660.0,682.0,704.0,726.0,748.0,770.0,792.0,814.0,836.0,858.0,880.0,902.0,924.0,946.0,968.0,990.0,1012.0,1034.0,1056.0,1078.0,1100.0,1122.0,1144.0,1166.0,1188.0,1210.0,1232.0,1254.0,1276.0,1298.0,1320.0,1342.0,1364.0,1386.0,1408.0,1430.0,1452.0,1474.0,1496.0,1518.0,1540.0,1562.0,1584.0,1606.0,1628.0,1650.0,1672.0,1694.0,1716.0,1738.0,1760.0,1782.0,1804.0,1826.0,1848.0,1870.0,1892.0,1914.0,1936.0,1958.0,1980.0,2002.0,2024.0,2046.0,2068.0,2090.0,2112.0,2134.0,2156.0,2178.0,2200.0],"times":[4622.0,8461.0,9637.0,12346.0,18375.0,21167.0,27077.0,34938.0,38400.0,50027.0,50111.0,49806.0,83299.0,66078.0,76163.0,85126.0,85508.0,96940.0,96096.0,100371.0,115046.0,133183.0,119371.0,135306.0,41976.0,141150.0,170298.0,165693.0,174408.0,184803.0,191910.0,200009.0,221708.0,235897.0,225961.0,375289.0,283560.0,298083.0,275138.0,279745.0,278342.0,312357.0,332260.0,327375.0,335492.0,354484.0,359527.0,391937.0,378831.0,389063.0,407828.0,435505.0,434852.0,451698.0,456506.0,469654.0,515355.0,546512.0,580188.0,542990.0,555329.0,565785.0,577372.0,603748.0,590922.0,609068.0,629291.0,681656.0,726389.0,676568.0,674081.0,728003.0,775922.0,788022.0,813900.0,803263.0,831516.0,920272.0,965481.0,982812.0,985153.0,976359.0,1028168.0,1016298.0,1028615.0,953686.0,983755.0,1560345.0,1085873.0,1104174.0,1083886.0,1124029.0,1055966.0,1652820.0,1309539.0,1165601.0,1163756.0,1714472.0,1931090.0,1883115.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/tukey.json new file mode 100644 index 0000000000000..9579d2e1bdbe2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/new/tukey.json @@ -0,0 +1 @@ +[-368.1589162341514,-47.94415107497986,805.9618893494776,1126.176654508649] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/MAD.svg new file mode 100644 index 0000000000000..bfce7126aa0f0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 120 + + + + + 130 + + + + + 140 + + + + + 150 + + + + + 160 + + + + + 170 + + + + + 180 + + + + + 190 + + + + + 200 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/linear object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/SD.svg new file mode 100644 index 0000000000000..c95c03bf5284c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/SD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 130 + + + + + 140 + + + + + 150 + + + + + 160 + + + + + 170 + + + + + 180 + + + + + 190 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/linear object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/index.html new file mode 100644 index 0000000000000..870827a3d073e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + multi thread allocation/linear object poll - Criterion.rs + + + + +
+

multi thread allocation/linear object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope480.36 ns521.17 ns561.79 ns
0.32059720.33657210.3207410
Mean358.40 ns389.13 ns420.99 ns
Std. Dev.132.95 ns160.47 ns185.60 ns
Median338.88 ns372.05 ns415.19 ns
MAD123.62 ns165.37 ns200.28 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/mean.svg new file mode 100644 index 0000000000000..81734058876cd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 360 + + + + + 370 + + + + + 380 + + + + + 390 + + + + + 400 + + + + + 410 + + + + + 420 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/linear object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/median.svg new file mode 100644 index 0000000000000..4f0a292d8b0c0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/median.svg @@ -0,0 +1,308 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 340 + + + + + 350 + + + + + 360 + + + + + 370 + + + + + 380 + + + + + 390 + + + + + 400 + + + + + 410 + + + + + 420 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/linear object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/pdf.svg new file mode 100644 index 0000000000000..d326a63a78055 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/pdf.svg @@ -0,0 +1,390 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 0 + + + + + 200 + + + + + 400 + + + + + 600 + + + + + 800 + + + + + 1000 + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/linear object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + gnuplot_plot_5 + + + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..ffeff2dc71ea5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/pdf_small.svg @@ -0,0 +1,204 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + 0 + + + + + 200 + + + + + 400 + + + + + 600 + + + + + 800 + + + + + 1000 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/regression.svg new file mode 100644 index 0000000000000..8541efabddeed --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/regression.svg @@ -0,0 +1,434 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.2 + + + + + + + + + + + + + 0.4 + + + + + + + + + + + + + 0.6 + + + + + + + + + + + + + 0.8 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.2 + + + + + + + + + + + + + 1.4 + + + + + + + + + + + + + 1.6 + + + + + + + + + + + + + 1.8 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.5 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 2.5 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + multi thread allocation/linear object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/regression_small.svg new file mode 100644 index 0000000000000..e04230957e871 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/regression_small.svg @@ -0,0 +1,412 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.2 + + + + + + + + + + + + + 0.4 + + + + + + + + + + + + + 0.6 + + + + + + + + + + + + + 0.8 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.2 + + + + + + + + + + + + + 1.4 + + + + + + + + + + + + + 1.6 + + + + + + + + + + + + + 1.8 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.5 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 2.5 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/slope.svg new file mode 100644 index 0000000000000..186638ccd4c87 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/slope.svg @@ -0,0 +1,328 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 0.018 + + + + + 0.02 + + + + + 480 + + + + + 490 + + + + + 500 + + + + + 510 + + + + + 520 + + + + + 530 + + + + + 540 + + + + + 550 + + + + + 560 + + + + + 570 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/linear object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/typical.svg new file mode 100644 index 0000000000000..774ded2b7ac83 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/linear object poll/report/typical.svg @@ -0,0 +1,328 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 0.018 + + + + + 0.02 + + + + + 480 + + + + + 490 + + + + + 500 + + + + + 510 + + + + + 520 + + + + + 530 + + + + + 540 + + + + + 550 + + + + + 560 + + + + + 570 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/linear object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/benchmark.json new file mode 100644 index 0000000000000..9cd23a288f023 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread allocation","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"multi thread allocation/mutex object poll","directory_name":"multi thread allocation/mutex object poll","title":"multi thread allocation/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/estimates.json new file mode 100644 index 0000000000000..56720e8d35ec7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1336.024087378996,"upper_bound":1700.1732619670315},"point_estimate":1517.8289186644915,"standard_error":93.1176226495403},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":906.6413793103449,"upper_bound":2269.413096781853},"point_estimate":1498.6839901477833,"standard_error":460.4215614898425},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":459.2648200476274,"upper_bound":1475.2741680131974},"point_estimate":1427.2658786729016,"standard_error":349.0192504613061},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":2012.168485078357,"upper_bound":2288.3133685394396},"point_estimate":2168.973438390159,"standard_error":70.65516751400467},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":883.7988370468585,"upper_bound":969.3544104058554},"point_estimate":933.8397210362249,"standard_error":21.775491606185735}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/raw.csv new file mode 100644 index 0000000000000..3f49276483501 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread allocation,mutex object poll,,,,138604.0,ns,58 +multi thread allocation,mutex object poll,,,,156330.0,ns,116 +multi thread allocation,mutex object poll,,,,348162.0,ns,174 +multi thread allocation,mutex object poll,,,,329310.0,ns,232 +multi thread allocation,mutex object poll,,,,421931.0,ns,290 +multi thread allocation,mutex object poll,,,,410286.0,ns,348 +multi thread allocation,mutex object poll,,,,626228.0,ns,406 +multi thread allocation,mutex object poll,,,,505550.0,ns,464 +multi thread allocation,mutex object poll,,,,676196.0,ns,522 +multi thread allocation,mutex object poll,,,,690299.0,ns,580 +multi thread allocation,mutex object poll,,,,538291.0,ns,638 +multi thread allocation,mutex object poll,,,,707760.0,ns,696 +multi thread allocation,mutex object poll,,,,723620.0,ns,754 +multi thread allocation,mutex object poll,,,,632021.0,ns,812 +multi thread allocation,mutex object poll,,,,788778.0,ns,870 +multi thread allocation,mutex object poll,,,,815448.0,ns,928 +multi thread allocation,mutex object poll,,,,593494.0,ns,986 +multi thread allocation,mutex object poll,,,,800105.0,ns,1044 +multi thread allocation,mutex object poll,,,,835594.0,ns,1102 +multi thread allocation,mutex object poll,,,,659089.0,ns,1160 +multi thread allocation,mutex object poll,,,,806941.0,ns,1218 +multi thread allocation,mutex object poll,,,,792458.0,ns,1276 +multi thread allocation,mutex object poll,,,,701119.0,ns,1334 +multi thread allocation,mutex object poll,,,,740294.0,ns,1392 +multi thread allocation,mutex object poll,,,,792470.0,ns,1450 +multi thread allocation,mutex object poll,,,,832119.0,ns,1508 +multi thread allocation,mutex object poll,,,,727562.0,ns,1566 +multi thread allocation,mutex object poll,,,,825954.0,ns,1624 +multi thread allocation,mutex object poll,,,,747845.0,ns,1682 +multi thread allocation,mutex object poll,,,,788936.0,ns,1740 +multi thread allocation,mutex object poll,,,,784404.0,ns,1798 +multi thread allocation,mutex object poll,,,,809062.0,ns,1856 +multi thread allocation,mutex object poll,,,,795895.0,ns,1914 +multi thread allocation,mutex object poll,,,,855907.0,ns,1972 +multi thread allocation,mutex object poll,,,,907287.0,ns,2030 +multi thread allocation,mutex object poll,,,,827049.0,ns,2088 +multi thread allocation,mutex object poll,,,,947884.0,ns,2146 +multi thread allocation,mutex object poll,,,,918097.0,ns,2204 +multi thread allocation,mutex object poll,,,,819995.0,ns,2262 +multi thread allocation,mutex object poll,,,,907115.0,ns,2320 +multi thread allocation,mutex object poll,,,,996142.0,ns,2378 +multi thread allocation,mutex object poll,,,,864733.0,ns,2436 +multi thread allocation,mutex object poll,,,,891959.0,ns,2494 +multi thread allocation,mutex object poll,,,,982076.0,ns,2552 +multi thread allocation,mutex object poll,,,,882717.0,ns,2610 +multi thread allocation,mutex object poll,,,,1016958.0,ns,2668 +multi thread allocation,mutex object poll,,,,1038107.0,ns,2726 +multi thread allocation,mutex object poll,,,,964956.0,ns,2784 +multi thread allocation,mutex object poll,,,,1120504.0,ns,2842 +multi thread allocation,mutex object poll,,,,1197513.0,ns,2900 +multi thread allocation,mutex object poll,,,,951768.0,ns,2958 +multi thread allocation,mutex object poll,,,,1134851.0,ns,3016 +multi thread allocation,mutex object poll,,,,1045462.0,ns,3074 +multi thread allocation,mutex object poll,,,,7465713.0,ns,3132 +multi thread allocation,mutex object poll,,,,7545726.0,ns,3190 +multi thread allocation,mutex object poll,,,,7627496.0,ns,3248 +multi thread allocation,mutex object poll,,,,7579681.0,ns,3306 +multi thread allocation,mutex object poll,,,,7535499.0,ns,3364 +multi thread allocation,mutex object poll,,,,7751064.0,ns,3422 +multi thread allocation,mutex object poll,,,,8191862.0,ns,3480 +multi thread allocation,mutex object poll,,,,8361606.0,ns,3538 +multi thread allocation,mutex object poll,,,,7747123.0,ns,3596 +multi thread allocation,mutex object poll,,,,8330082.0,ns,3654 +multi thread allocation,mutex object poll,,,,8440189.0,ns,3712 +multi thread allocation,mutex object poll,,,,8540388.0,ns,3770 +multi thread allocation,mutex object poll,,,,8430091.0,ns,3828 +multi thread allocation,mutex object poll,,,,9088106.0,ns,3886 +multi thread allocation,mutex object poll,,,,9418408.0,ns,3944 +multi thread allocation,mutex object poll,,,,9413636.0,ns,4002 +multi thread allocation,mutex object poll,,,,9570202.0,ns,4060 +multi thread allocation,mutex object poll,,,,9256695.0,ns,4118 +multi thread allocation,mutex object poll,,,,9432118.0,ns,4176 +multi thread allocation,mutex object poll,,,,9535364.0,ns,4234 +multi thread allocation,mutex object poll,,,,10745921.0,ns,4292 +multi thread allocation,mutex object poll,,,,10243556.0,ns,4350 +multi thread allocation,mutex object poll,,,,10977019.0,ns,4408 +multi thread allocation,mutex object poll,,,,10658358.0,ns,4466 +multi thread allocation,mutex object poll,,,,11116263.0,ns,4524 +multi thread allocation,mutex object poll,,,,11783202.0,ns,4582 +multi thread allocation,mutex object poll,,,,11399730.0,ns,4640 +multi thread allocation,mutex object poll,,,,11424670.0,ns,4698 +multi thread allocation,mutex object poll,,,,11796067.0,ns,4756 +multi thread allocation,mutex object poll,,,,11631850.0,ns,4814 +multi thread allocation,mutex object poll,,,,12264347.0,ns,4872 +multi thread allocation,mutex object poll,,,,12619784.0,ns,4930 +multi thread allocation,mutex object poll,,,,13009475.0,ns,4988 +multi thread allocation,mutex object poll,,,,12819072.0,ns,5046 +multi thread allocation,mutex object poll,,,,12971670.0,ns,5104 +multi thread allocation,mutex object poll,,,,13284630.0,ns,5162 +multi thread allocation,mutex object poll,,,,13059679.0,ns,5220 +multi thread allocation,mutex object poll,,,,13420437.0,ns,5278 +multi thread allocation,mutex object poll,,,,13526710.0,ns,5336 +multi thread allocation,mutex object poll,,,,13688410.0,ns,5394 +multi thread allocation,mutex object poll,,,,14057303.0,ns,5452 +multi thread allocation,mutex object poll,,,,14637271.0,ns,5510 +multi thread allocation,mutex object poll,,,,14688616.0,ns,5568 +multi thread allocation,mutex object poll,,,,14620041.0,ns,5626 +multi thread allocation,mutex object poll,,,,15009827.0,ns,5684 +multi thread allocation,mutex object poll,,,,15145077.0,ns,5742 +multi thread allocation,mutex object poll,,,,16002552.0,ns,5800 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/sample.json new file mode 100644 index 0000000000000..bcc7ab5ca02a8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[58.0,116.0,174.0,232.0,290.0,348.0,406.0,464.0,522.0,580.0,638.0,696.0,754.0,812.0,870.0,928.0,986.0,1044.0,1102.0,1160.0,1218.0,1276.0,1334.0,1392.0,1450.0,1508.0,1566.0,1624.0,1682.0,1740.0,1798.0,1856.0,1914.0,1972.0,2030.0,2088.0,2146.0,2204.0,2262.0,2320.0,2378.0,2436.0,2494.0,2552.0,2610.0,2668.0,2726.0,2784.0,2842.0,2900.0,2958.0,3016.0,3074.0,3132.0,3190.0,3248.0,3306.0,3364.0,3422.0,3480.0,3538.0,3596.0,3654.0,3712.0,3770.0,3828.0,3886.0,3944.0,4002.0,4060.0,4118.0,4176.0,4234.0,4292.0,4350.0,4408.0,4466.0,4524.0,4582.0,4640.0,4698.0,4756.0,4814.0,4872.0,4930.0,4988.0,5046.0,5104.0,5162.0,5220.0,5278.0,5336.0,5394.0,5452.0,5510.0,5568.0,5626.0,5684.0,5742.0,5800.0],"times":[138604.0,156330.0,348162.0,329310.0,421931.0,410286.0,626228.0,505550.0,676196.0,690299.0,538291.0,707760.0,723620.0,632021.0,788778.0,815448.0,593494.0,800105.0,835594.0,659089.0,806941.0,792458.0,701119.0,740294.0,792470.0,832119.0,727562.0,825954.0,747845.0,788936.0,784404.0,809062.0,795895.0,855907.0,907287.0,827049.0,947884.0,918097.0,819995.0,907115.0,996142.0,864733.0,891959.0,982076.0,882717.0,1016958.0,1038107.0,964956.0,1120504.0,1197513.0,951768.0,1134851.0,1045462.0,7465713.0,7545726.0,7627496.0,7579681.0,7535499.0,7751064.0,8191862.0,8361606.0,7747123.0,8330082.0,8440189.0,8540388.0,8430091.0,9088106.0,9418408.0,9413636.0,9570202.0,9256695.0,9432118.0,9535364.0,10745921.0,10243556.0,10977019.0,10658358.0,11116263.0,11783202.0,11399730.0,11424670.0,11796067.0,11631850.0,12264347.0,12619784.0,13009475.0,12819072.0,12971670.0,13284630.0,13059679.0,13420437.0,13526710.0,13688410.0,14057303.0,14637271.0,14688616.0,14620041.0,15009827.0,15145077.0,16002552.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/tukey.json new file mode 100644 index 0000000000000..38dfedb3da6d3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/base/tukey.json @@ -0,0 +1 @@ +[-5341.861886626967,-2440.0298896736367,5298.188768868577,8200.020765821908] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/benchmark.json new file mode 100644 index 0000000000000..9cd23a288f023 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread allocation","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"multi thread allocation/mutex object poll","directory_name":"multi thread allocation/mutex object poll","title":"multi thread allocation/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/estimates.json new file mode 100644 index 0000000000000..56720e8d35ec7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1336.024087378996,"upper_bound":1700.1732619670315},"point_estimate":1517.8289186644915,"standard_error":93.1176226495403},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":906.6413793103449,"upper_bound":2269.413096781853},"point_estimate":1498.6839901477833,"standard_error":460.4215614898425},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":459.2648200476274,"upper_bound":1475.2741680131974},"point_estimate":1427.2658786729016,"standard_error":349.0192504613061},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":2012.168485078357,"upper_bound":2288.3133685394396},"point_estimate":2168.973438390159,"standard_error":70.65516751400467},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":883.7988370468585,"upper_bound":969.3544104058554},"point_estimate":933.8397210362249,"standard_error":21.775491606185735}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/raw.csv new file mode 100644 index 0000000000000..3f49276483501 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread allocation,mutex object poll,,,,138604.0,ns,58 +multi thread allocation,mutex object poll,,,,156330.0,ns,116 +multi thread allocation,mutex object poll,,,,348162.0,ns,174 +multi thread allocation,mutex object poll,,,,329310.0,ns,232 +multi thread allocation,mutex object poll,,,,421931.0,ns,290 +multi thread allocation,mutex object poll,,,,410286.0,ns,348 +multi thread allocation,mutex object poll,,,,626228.0,ns,406 +multi thread allocation,mutex object poll,,,,505550.0,ns,464 +multi thread allocation,mutex object poll,,,,676196.0,ns,522 +multi thread allocation,mutex object poll,,,,690299.0,ns,580 +multi thread allocation,mutex object poll,,,,538291.0,ns,638 +multi thread allocation,mutex object poll,,,,707760.0,ns,696 +multi thread allocation,mutex object poll,,,,723620.0,ns,754 +multi thread allocation,mutex object poll,,,,632021.0,ns,812 +multi thread allocation,mutex object poll,,,,788778.0,ns,870 +multi thread allocation,mutex object poll,,,,815448.0,ns,928 +multi thread allocation,mutex object poll,,,,593494.0,ns,986 +multi thread allocation,mutex object poll,,,,800105.0,ns,1044 +multi thread allocation,mutex object poll,,,,835594.0,ns,1102 +multi thread allocation,mutex object poll,,,,659089.0,ns,1160 +multi thread allocation,mutex object poll,,,,806941.0,ns,1218 +multi thread allocation,mutex object poll,,,,792458.0,ns,1276 +multi thread allocation,mutex object poll,,,,701119.0,ns,1334 +multi thread allocation,mutex object poll,,,,740294.0,ns,1392 +multi thread allocation,mutex object poll,,,,792470.0,ns,1450 +multi thread allocation,mutex object poll,,,,832119.0,ns,1508 +multi thread allocation,mutex object poll,,,,727562.0,ns,1566 +multi thread allocation,mutex object poll,,,,825954.0,ns,1624 +multi thread allocation,mutex object poll,,,,747845.0,ns,1682 +multi thread allocation,mutex object poll,,,,788936.0,ns,1740 +multi thread allocation,mutex object poll,,,,784404.0,ns,1798 +multi thread allocation,mutex object poll,,,,809062.0,ns,1856 +multi thread allocation,mutex object poll,,,,795895.0,ns,1914 +multi thread allocation,mutex object poll,,,,855907.0,ns,1972 +multi thread allocation,mutex object poll,,,,907287.0,ns,2030 +multi thread allocation,mutex object poll,,,,827049.0,ns,2088 +multi thread allocation,mutex object poll,,,,947884.0,ns,2146 +multi thread allocation,mutex object poll,,,,918097.0,ns,2204 +multi thread allocation,mutex object poll,,,,819995.0,ns,2262 +multi thread allocation,mutex object poll,,,,907115.0,ns,2320 +multi thread allocation,mutex object poll,,,,996142.0,ns,2378 +multi thread allocation,mutex object poll,,,,864733.0,ns,2436 +multi thread allocation,mutex object poll,,,,891959.0,ns,2494 +multi thread allocation,mutex object poll,,,,982076.0,ns,2552 +multi thread allocation,mutex object poll,,,,882717.0,ns,2610 +multi thread allocation,mutex object poll,,,,1016958.0,ns,2668 +multi thread allocation,mutex object poll,,,,1038107.0,ns,2726 +multi thread allocation,mutex object poll,,,,964956.0,ns,2784 +multi thread allocation,mutex object poll,,,,1120504.0,ns,2842 +multi thread allocation,mutex object poll,,,,1197513.0,ns,2900 +multi thread allocation,mutex object poll,,,,951768.0,ns,2958 +multi thread allocation,mutex object poll,,,,1134851.0,ns,3016 +multi thread allocation,mutex object poll,,,,1045462.0,ns,3074 +multi thread allocation,mutex object poll,,,,7465713.0,ns,3132 +multi thread allocation,mutex object poll,,,,7545726.0,ns,3190 +multi thread allocation,mutex object poll,,,,7627496.0,ns,3248 +multi thread allocation,mutex object poll,,,,7579681.0,ns,3306 +multi thread allocation,mutex object poll,,,,7535499.0,ns,3364 +multi thread allocation,mutex object poll,,,,7751064.0,ns,3422 +multi thread allocation,mutex object poll,,,,8191862.0,ns,3480 +multi thread allocation,mutex object poll,,,,8361606.0,ns,3538 +multi thread allocation,mutex object poll,,,,7747123.0,ns,3596 +multi thread allocation,mutex object poll,,,,8330082.0,ns,3654 +multi thread allocation,mutex object poll,,,,8440189.0,ns,3712 +multi thread allocation,mutex object poll,,,,8540388.0,ns,3770 +multi thread allocation,mutex object poll,,,,8430091.0,ns,3828 +multi thread allocation,mutex object poll,,,,9088106.0,ns,3886 +multi thread allocation,mutex object poll,,,,9418408.0,ns,3944 +multi thread allocation,mutex object poll,,,,9413636.0,ns,4002 +multi thread allocation,mutex object poll,,,,9570202.0,ns,4060 +multi thread allocation,mutex object poll,,,,9256695.0,ns,4118 +multi thread allocation,mutex object poll,,,,9432118.0,ns,4176 +multi thread allocation,mutex object poll,,,,9535364.0,ns,4234 +multi thread allocation,mutex object poll,,,,10745921.0,ns,4292 +multi thread allocation,mutex object poll,,,,10243556.0,ns,4350 +multi thread allocation,mutex object poll,,,,10977019.0,ns,4408 +multi thread allocation,mutex object poll,,,,10658358.0,ns,4466 +multi thread allocation,mutex object poll,,,,11116263.0,ns,4524 +multi thread allocation,mutex object poll,,,,11783202.0,ns,4582 +multi thread allocation,mutex object poll,,,,11399730.0,ns,4640 +multi thread allocation,mutex object poll,,,,11424670.0,ns,4698 +multi thread allocation,mutex object poll,,,,11796067.0,ns,4756 +multi thread allocation,mutex object poll,,,,11631850.0,ns,4814 +multi thread allocation,mutex object poll,,,,12264347.0,ns,4872 +multi thread allocation,mutex object poll,,,,12619784.0,ns,4930 +multi thread allocation,mutex object poll,,,,13009475.0,ns,4988 +multi thread allocation,mutex object poll,,,,12819072.0,ns,5046 +multi thread allocation,mutex object poll,,,,12971670.0,ns,5104 +multi thread allocation,mutex object poll,,,,13284630.0,ns,5162 +multi thread allocation,mutex object poll,,,,13059679.0,ns,5220 +multi thread allocation,mutex object poll,,,,13420437.0,ns,5278 +multi thread allocation,mutex object poll,,,,13526710.0,ns,5336 +multi thread allocation,mutex object poll,,,,13688410.0,ns,5394 +multi thread allocation,mutex object poll,,,,14057303.0,ns,5452 +multi thread allocation,mutex object poll,,,,14637271.0,ns,5510 +multi thread allocation,mutex object poll,,,,14688616.0,ns,5568 +multi thread allocation,mutex object poll,,,,14620041.0,ns,5626 +multi thread allocation,mutex object poll,,,,15009827.0,ns,5684 +multi thread allocation,mutex object poll,,,,15145077.0,ns,5742 +multi thread allocation,mutex object poll,,,,16002552.0,ns,5800 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/sample.json new file mode 100644 index 0000000000000..bcc7ab5ca02a8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[58.0,116.0,174.0,232.0,290.0,348.0,406.0,464.0,522.0,580.0,638.0,696.0,754.0,812.0,870.0,928.0,986.0,1044.0,1102.0,1160.0,1218.0,1276.0,1334.0,1392.0,1450.0,1508.0,1566.0,1624.0,1682.0,1740.0,1798.0,1856.0,1914.0,1972.0,2030.0,2088.0,2146.0,2204.0,2262.0,2320.0,2378.0,2436.0,2494.0,2552.0,2610.0,2668.0,2726.0,2784.0,2842.0,2900.0,2958.0,3016.0,3074.0,3132.0,3190.0,3248.0,3306.0,3364.0,3422.0,3480.0,3538.0,3596.0,3654.0,3712.0,3770.0,3828.0,3886.0,3944.0,4002.0,4060.0,4118.0,4176.0,4234.0,4292.0,4350.0,4408.0,4466.0,4524.0,4582.0,4640.0,4698.0,4756.0,4814.0,4872.0,4930.0,4988.0,5046.0,5104.0,5162.0,5220.0,5278.0,5336.0,5394.0,5452.0,5510.0,5568.0,5626.0,5684.0,5742.0,5800.0],"times":[138604.0,156330.0,348162.0,329310.0,421931.0,410286.0,626228.0,505550.0,676196.0,690299.0,538291.0,707760.0,723620.0,632021.0,788778.0,815448.0,593494.0,800105.0,835594.0,659089.0,806941.0,792458.0,701119.0,740294.0,792470.0,832119.0,727562.0,825954.0,747845.0,788936.0,784404.0,809062.0,795895.0,855907.0,907287.0,827049.0,947884.0,918097.0,819995.0,907115.0,996142.0,864733.0,891959.0,982076.0,882717.0,1016958.0,1038107.0,964956.0,1120504.0,1197513.0,951768.0,1134851.0,1045462.0,7465713.0,7545726.0,7627496.0,7579681.0,7535499.0,7751064.0,8191862.0,8361606.0,7747123.0,8330082.0,8440189.0,8540388.0,8430091.0,9088106.0,9418408.0,9413636.0,9570202.0,9256695.0,9432118.0,9535364.0,10745921.0,10243556.0,10977019.0,10658358.0,11116263.0,11783202.0,11399730.0,11424670.0,11796067.0,11631850.0,12264347.0,12619784.0,13009475.0,12819072.0,12971670.0,13284630.0,13059679.0,13420437.0,13526710.0,13688410.0,14057303.0,14637271.0,14688616.0,14620041.0,15009827.0,15145077.0,16002552.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/tukey.json new file mode 100644 index 0000000000000..38dfedb3da6d3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/new/tukey.json @@ -0,0 +1 @@ +[-5341.861886626967,-2440.0298896736367,5298.188768868577,8200.020765821908] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/MAD.svg new file mode 100644 index 0000000000000..0b65ffb107f47 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/MAD.svg @@ -0,0 +1,283 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/mutex object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/SD.svg new file mode 100644 index 0000000000000..2cb3625152859 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/SD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 0.018 + + + + + 0.02 + + + + + 880 + + + + + 900 + + + + + 920 + + + + + 940 + + + + + 960 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/mutex object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/index.html new file mode 100644 index 0000000000000..45aef816ef9cb --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + multi thread allocation/mutex object poll - Criterion.rs + + + + +
+

multi thread allocation/mutex object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope2.0122 us2.1690 us2.2883 us
0.14085880.14614900.1430374
Mean1.3360 us1.5178 us1.7002 us
Std. Dev.883.80 ns933.84 ns969.35 ns
Median906.64 ns1.4987 us2.2694 us
MAD459.26 ns1.4273 us1.4753 us
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/mean.svg new file mode 100644 index 0000000000000..a9ae17f3b91bd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/mean.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 4 + + + + + 4.5 + + + + + 1.3 + + + + + 1.35 + + + + + 1.4 + + + + + 1.45 + + + + + 1.5 + + + + + 1.55 + + + + + 1.6 + + + + + 1.65 + + + + + 1.7 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/mutex object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/median.svg new file mode 100644 index 0000000000000..16ee27568b923 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/median.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 1.4 + + + + + 1.6 + + + + + 1.8 + + + + + 2 + + + + + 2.2 + + + + + 2.4 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/mutex object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/pdf.svg new file mode 100644 index 0000000000000..d1e1694982f66 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/pdf.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + -0.5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 0.5 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/mutex object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..ec8b2531094ae --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/pdf_small.svg @@ -0,0 +1,219 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + -0.5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/regression.svg new file mode 100644 index 0000000000000..7be825f8a421a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/regression.svg @@ -0,0 +1,434 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + multi thread allocation/mutex object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/regression_small.svg new file mode 100644 index 0000000000000..f3f1cbcabdcad --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/regression_small.svg @@ -0,0 +1,412 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/slope.svg new file mode 100644 index 0000000000000..47d512efad79f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 2 + + + + + 2.05 + + + + + 2.1 + + + + + 2.15 + + + + + 2.2 + + + + + 2.25 + + + + + 2.3 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/mutex object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/typical.svg new file mode 100644 index 0000000000000..ebed2c65f77e1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/mutex object poll/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 2 + + + + + 2.05 + + + + + 2.1 + + + + + 2.15 + + + + + 2.2 + + + + + 2.25 + + + + + 2.3 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/mutex object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/benchmark.json new file mode 100644 index 0000000000000..6ecf87f75b76a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread allocation","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"multi thread allocation/none object poll","directory_name":"multi thread allocation/none object poll","title":"multi thread allocation/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/estimates.json new file mode 100644 index 0000000000000..822f51a4f2926 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":586.3555524860486,"upper_bound":662.1366555536646},"point_estimate":625.0915346184875,"standard_error":19.339094230754498},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":624.0674342105264,"upper_bound":733.6122413176656},"point_estimate":697.4521955058619,"standard_error":29.280550205778617},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":108.23047971966452,"upper_bound":230.71099536942253},"point_estimate":151.17973564226358,"standard_error":30.941594863347955},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":744.7426062750596,"upper_bound":774.8076121722121},"point_estimate":761.2606344976848,"standard_error":7.6851939277484975},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":165.711839256351,"upper_bound":218.77136077550196},"point_estimate":194.72338539989425,"standard_error":13.555340428700283}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/raw.csv new file mode 100644 index 0000000000000..212236e06d232 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread allocation,none object poll,,,,96010.0,ns,192 +multi thread allocation,none object poll,,,,184206.0,ns,384 +multi thread allocation,none object poll,,,,290804.0,ns,576 +multi thread allocation,none object poll,,,,362019.0,ns,768 +multi thread allocation,none object poll,,,,369576.0,ns,960 +multi thread allocation,none object poll,,,,367121.0,ns,1152 +multi thread allocation,none object poll,,,,380108.0,ns,1344 +multi thread allocation,none object poll,,,,389321.0,ns,1536 +multi thread allocation,none object poll,,,,402445.0,ns,1728 +multi thread allocation,none object poll,,,,408184.0,ns,1920 +multi thread allocation,none object poll,,,,537165.0,ns,2112 +multi thread allocation,none object poll,,,,430052.0,ns,2304 +multi thread allocation,none object poll,,,,426208.0,ns,2496 +multi thread allocation,none object poll,,,,421779.0,ns,2688 +multi thread allocation,none object poll,,,,413526.0,ns,2880 +multi thread allocation,none object poll,,,,417714.0,ns,3072 +multi thread allocation,none object poll,,,,1419281.0,ns,3264 +multi thread allocation,none object poll,,,,1470515.0,ns,3456 +multi thread allocation,none object poll,,,,1511555.0,ns,3648 +multi thread allocation,none object poll,,,,1553379.0,ns,3840 +multi thread allocation,none object poll,,,,1590208.0,ns,4032 +multi thread allocation,none object poll,,,,1755509.0,ns,4224 +multi thread allocation,none object poll,,,,1912956.0,ns,4416 +multi thread allocation,none object poll,,,,2034981.0,ns,4608 +multi thread allocation,none object poll,,,,2127469.0,ns,4800 +multi thread allocation,none object poll,,,,2369552.0,ns,4992 +multi thread allocation,none object poll,,,,2671265.0,ns,5184 +multi thread allocation,none object poll,,,,2693567.0,ns,5376 +multi thread allocation,none object poll,,,,2958926.0,ns,5568 +multi thread allocation,none object poll,,,,3168545.0,ns,5760 +multi thread allocation,none object poll,,,,3268790.0,ns,5952 +multi thread allocation,none object poll,,,,3485683.0,ns,6144 +multi thread allocation,none object poll,,,,3694047.0,ns,6336 +multi thread allocation,none object poll,,,,3868657.0,ns,6528 +multi thread allocation,none object poll,,,,4056815.0,ns,6720 +multi thread allocation,none object poll,,,,4078476.0,ns,6912 +multi thread allocation,none object poll,,,,4248493.0,ns,7104 +multi thread allocation,none object poll,,,,4553196.0,ns,7296 +multi thread allocation,none object poll,,,,4562127.0,ns,7488 +multi thread allocation,none object poll,,,,4885976.0,ns,7680 +multi thread allocation,none object poll,,,,4870874.0,ns,7872 +multi thread allocation,none object poll,,,,4973369.0,ns,8064 +multi thread allocation,none object poll,,,,5164462.0,ns,8256 +multi thread allocation,none object poll,,,,5504334.0,ns,8448 +multi thread allocation,none object poll,,,,5849794.0,ns,8640 +multi thread allocation,none object poll,,,,5782946.0,ns,8832 +multi thread allocation,none object poll,,,,6286309.0,ns,9024 +multi thread allocation,none object poll,,,,6518861.0,ns,9216 +multi thread allocation,none object poll,,,,6569449.0,ns,9408 +multi thread allocation,none object poll,,,,7037794.0,ns,9600 +multi thread allocation,none object poll,,,,6678365.0,ns,9792 +multi thread allocation,none object poll,,,,6910520.0,ns,9984 +multi thread allocation,none object poll,,,,7362861.0,ns,10176 +multi thread allocation,none object poll,,,,7530660.0,ns,10368 +multi thread allocation,none object poll,,,,7974143.0,ns,10560 +multi thread allocation,none object poll,,,,7547609.0,ns,10752 +multi thread allocation,none object poll,,,,8705514.0,ns,10944 +multi thread allocation,none object poll,,,,8019280.0,ns,11136 +multi thread allocation,none object poll,,,,8144088.0,ns,11328 +multi thread allocation,none object poll,,,,8360975.0,ns,11520 +multi thread allocation,none object poll,,,,8553551.0,ns,11712 +multi thread allocation,none object poll,,,,9721324.0,ns,11904 +multi thread allocation,none object poll,,,,9034726.0,ns,12096 +multi thread allocation,none object poll,,,,9055037.0,ns,12288 +multi thread allocation,none object poll,,,,9540688.0,ns,12480 +multi thread allocation,none object poll,,,,9542928.0,ns,12672 +multi thread allocation,none object poll,,,,9532310.0,ns,12864 +multi thread allocation,none object poll,,,,10237679.0,ns,13056 +multi thread allocation,none object poll,,,,11230743.0,ns,13248 +multi thread allocation,none object poll,,,,10130936.0,ns,13440 +multi thread allocation,none object poll,,,,10405701.0,ns,13632 +multi thread allocation,none object poll,,,,10751349.0,ns,13824 +multi thread allocation,none object poll,,,,11507893.0,ns,14016 +multi thread allocation,none object poll,,,,11012934.0,ns,14208 +multi thread allocation,none object poll,,,,11216309.0,ns,14400 +multi thread allocation,none object poll,,,,11441381.0,ns,14592 +multi thread allocation,none object poll,,,,11127686.0,ns,14784 +multi thread allocation,none object poll,,,,11951899.0,ns,14976 +multi thread allocation,none object poll,,,,12349749.0,ns,15168 +multi thread allocation,none object poll,,,,12938804.0,ns,15360 +multi thread allocation,none object poll,,,,12044846.0,ns,15552 +multi thread allocation,none object poll,,,,12065591.0,ns,15744 +multi thread allocation,none object poll,,,,12618240.0,ns,15936 +multi thread allocation,none object poll,,,,12630455.0,ns,16128 +multi thread allocation,none object poll,,,,14054714.0,ns,16320 +multi thread allocation,none object poll,,,,13758703.0,ns,16512 +multi thread allocation,none object poll,,,,13211141.0,ns,16704 +multi thread allocation,none object poll,,,,13727351.0,ns,16896 +multi thread allocation,none object poll,,,,13356759.0,ns,17088 +multi thread allocation,none object poll,,,,13720989.0,ns,17280 +multi thread allocation,none object poll,,,,14317995.0,ns,17472 +multi thread allocation,none object poll,,,,14320305.0,ns,17664 +multi thread allocation,none object poll,,,,14233726.0,ns,17856 +multi thread allocation,none object poll,,,,15082054.0,ns,18048 +multi thread allocation,none object poll,,,,14785432.0,ns,18240 +multi thread allocation,none object poll,,,,15184334.0,ns,18432 +multi thread allocation,none object poll,,,,15538964.0,ns,18624 +multi thread allocation,none object poll,,,,14944130.0,ns,18816 +multi thread allocation,none object poll,,,,15221091.0,ns,19008 +multi thread allocation,none object poll,,,,12795710.0,ns,19200 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/sample.json new file mode 100644 index 0000000000000..73a888a41a70d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[192.0,384.0,576.0,768.0,960.0,1152.0,1344.0,1536.0,1728.0,1920.0,2112.0,2304.0,2496.0,2688.0,2880.0,3072.0,3264.0,3456.0,3648.0,3840.0,4032.0,4224.0,4416.0,4608.0,4800.0,4992.0,5184.0,5376.0,5568.0,5760.0,5952.0,6144.0,6336.0,6528.0,6720.0,6912.0,7104.0,7296.0,7488.0,7680.0,7872.0,8064.0,8256.0,8448.0,8640.0,8832.0,9024.0,9216.0,9408.0,9600.0,9792.0,9984.0,10176.0,10368.0,10560.0,10752.0,10944.0,11136.0,11328.0,11520.0,11712.0,11904.0,12096.0,12288.0,12480.0,12672.0,12864.0,13056.0,13248.0,13440.0,13632.0,13824.0,14016.0,14208.0,14400.0,14592.0,14784.0,14976.0,15168.0,15360.0,15552.0,15744.0,15936.0,16128.0,16320.0,16512.0,16704.0,16896.0,17088.0,17280.0,17472.0,17664.0,17856.0,18048.0,18240.0,18432.0,18624.0,18816.0,19008.0,19200.0],"times":[96010.0,184206.0,290804.0,362019.0,369576.0,367121.0,380108.0,389321.0,402445.0,408184.0,537165.0,430052.0,426208.0,421779.0,413526.0,417714.0,1419281.0,1470515.0,1511555.0,1553379.0,1590208.0,1755509.0,1912956.0,2034981.0,2127469.0,2369552.0,2671265.0,2693567.0,2958926.0,3168545.0,3268790.0,3485683.0,3694047.0,3868657.0,4056815.0,4078476.0,4248493.0,4553196.0,4562127.0,4885976.0,4870874.0,4973369.0,5164462.0,5504334.0,5849794.0,5782946.0,6286309.0,6518861.0,6569449.0,7037794.0,6678365.0,6910520.0,7362861.0,7530660.0,7974143.0,7547609.0,8705514.0,8019280.0,8144088.0,8360975.0,8553551.0,9721324.0,9034726.0,9055037.0,9540688.0,9542928.0,9532310.0,10237679.0,11230743.0,10130936.0,10405701.0,10751349.0,11507893.0,11012934.0,11216309.0,11441381.0,11127686.0,11951899.0,12349749.0,12938804.0,12044846.0,12065591.0,12618240.0,12630455.0,14054714.0,13758703.0,13211141.0,13727351.0,13356759.0,13720989.0,14317995.0,14320305.0,14233726.0,15082054.0,14785432.0,15184334.0,15538964.0,14944130.0,15221091.0,12795710.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/tukey.json new file mode 100644 index 0000000000000..8ac454c7c5fe2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/base/tukey.json @@ -0,0 +1 @@ +[-342.8975466283774,78.94606020515653,1203.8623450945804,1625.7059519281142] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/benchmark.json new file mode 100644 index 0000000000000..6ecf87f75b76a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread allocation","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"multi thread allocation/none object poll","directory_name":"multi thread allocation/none object poll","title":"multi thread allocation/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/estimates.json new file mode 100644 index 0000000000000..822f51a4f2926 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":586.3555524860486,"upper_bound":662.1366555536646},"point_estimate":625.0915346184875,"standard_error":19.339094230754498},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":624.0674342105264,"upper_bound":733.6122413176656},"point_estimate":697.4521955058619,"standard_error":29.280550205778617},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":108.23047971966452,"upper_bound":230.71099536942253},"point_estimate":151.17973564226358,"standard_error":30.941594863347955},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":744.7426062750596,"upper_bound":774.8076121722121},"point_estimate":761.2606344976848,"standard_error":7.6851939277484975},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":165.711839256351,"upper_bound":218.77136077550196},"point_estimate":194.72338539989425,"standard_error":13.555340428700283}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/raw.csv new file mode 100644 index 0000000000000..212236e06d232 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread allocation,none object poll,,,,96010.0,ns,192 +multi thread allocation,none object poll,,,,184206.0,ns,384 +multi thread allocation,none object poll,,,,290804.0,ns,576 +multi thread allocation,none object poll,,,,362019.0,ns,768 +multi thread allocation,none object poll,,,,369576.0,ns,960 +multi thread allocation,none object poll,,,,367121.0,ns,1152 +multi thread allocation,none object poll,,,,380108.0,ns,1344 +multi thread allocation,none object poll,,,,389321.0,ns,1536 +multi thread allocation,none object poll,,,,402445.0,ns,1728 +multi thread allocation,none object poll,,,,408184.0,ns,1920 +multi thread allocation,none object poll,,,,537165.0,ns,2112 +multi thread allocation,none object poll,,,,430052.0,ns,2304 +multi thread allocation,none object poll,,,,426208.0,ns,2496 +multi thread allocation,none object poll,,,,421779.0,ns,2688 +multi thread allocation,none object poll,,,,413526.0,ns,2880 +multi thread allocation,none object poll,,,,417714.0,ns,3072 +multi thread allocation,none object poll,,,,1419281.0,ns,3264 +multi thread allocation,none object poll,,,,1470515.0,ns,3456 +multi thread allocation,none object poll,,,,1511555.0,ns,3648 +multi thread allocation,none object poll,,,,1553379.0,ns,3840 +multi thread allocation,none object poll,,,,1590208.0,ns,4032 +multi thread allocation,none object poll,,,,1755509.0,ns,4224 +multi thread allocation,none object poll,,,,1912956.0,ns,4416 +multi thread allocation,none object poll,,,,2034981.0,ns,4608 +multi thread allocation,none object poll,,,,2127469.0,ns,4800 +multi thread allocation,none object poll,,,,2369552.0,ns,4992 +multi thread allocation,none object poll,,,,2671265.0,ns,5184 +multi thread allocation,none object poll,,,,2693567.0,ns,5376 +multi thread allocation,none object poll,,,,2958926.0,ns,5568 +multi thread allocation,none object poll,,,,3168545.0,ns,5760 +multi thread allocation,none object poll,,,,3268790.0,ns,5952 +multi thread allocation,none object poll,,,,3485683.0,ns,6144 +multi thread allocation,none object poll,,,,3694047.0,ns,6336 +multi thread allocation,none object poll,,,,3868657.0,ns,6528 +multi thread allocation,none object poll,,,,4056815.0,ns,6720 +multi thread allocation,none object poll,,,,4078476.0,ns,6912 +multi thread allocation,none object poll,,,,4248493.0,ns,7104 +multi thread allocation,none object poll,,,,4553196.0,ns,7296 +multi thread allocation,none object poll,,,,4562127.0,ns,7488 +multi thread allocation,none object poll,,,,4885976.0,ns,7680 +multi thread allocation,none object poll,,,,4870874.0,ns,7872 +multi thread allocation,none object poll,,,,4973369.0,ns,8064 +multi thread allocation,none object poll,,,,5164462.0,ns,8256 +multi thread allocation,none object poll,,,,5504334.0,ns,8448 +multi thread allocation,none object poll,,,,5849794.0,ns,8640 +multi thread allocation,none object poll,,,,5782946.0,ns,8832 +multi thread allocation,none object poll,,,,6286309.0,ns,9024 +multi thread allocation,none object poll,,,,6518861.0,ns,9216 +multi thread allocation,none object poll,,,,6569449.0,ns,9408 +multi thread allocation,none object poll,,,,7037794.0,ns,9600 +multi thread allocation,none object poll,,,,6678365.0,ns,9792 +multi thread allocation,none object poll,,,,6910520.0,ns,9984 +multi thread allocation,none object poll,,,,7362861.0,ns,10176 +multi thread allocation,none object poll,,,,7530660.0,ns,10368 +multi thread allocation,none object poll,,,,7974143.0,ns,10560 +multi thread allocation,none object poll,,,,7547609.0,ns,10752 +multi thread allocation,none object poll,,,,8705514.0,ns,10944 +multi thread allocation,none object poll,,,,8019280.0,ns,11136 +multi thread allocation,none object poll,,,,8144088.0,ns,11328 +multi thread allocation,none object poll,,,,8360975.0,ns,11520 +multi thread allocation,none object poll,,,,8553551.0,ns,11712 +multi thread allocation,none object poll,,,,9721324.0,ns,11904 +multi thread allocation,none object poll,,,,9034726.0,ns,12096 +multi thread allocation,none object poll,,,,9055037.0,ns,12288 +multi thread allocation,none object poll,,,,9540688.0,ns,12480 +multi thread allocation,none object poll,,,,9542928.0,ns,12672 +multi thread allocation,none object poll,,,,9532310.0,ns,12864 +multi thread allocation,none object poll,,,,10237679.0,ns,13056 +multi thread allocation,none object poll,,,,11230743.0,ns,13248 +multi thread allocation,none object poll,,,,10130936.0,ns,13440 +multi thread allocation,none object poll,,,,10405701.0,ns,13632 +multi thread allocation,none object poll,,,,10751349.0,ns,13824 +multi thread allocation,none object poll,,,,11507893.0,ns,14016 +multi thread allocation,none object poll,,,,11012934.0,ns,14208 +multi thread allocation,none object poll,,,,11216309.0,ns,14400 +multi thread allocation,none object poll,,,,11441381.0,ns,14592 +multi thread allocation,none object poll,,,,11127686.0,ns,14784 +multi thread allocation,none object poll,,,,11951899.0,ns,14976 +multi thread allocation,none object poll,,,,12349749.0,ns,15168 +multi thread allocation,none object poll,,,,12938804.0,ns,15360 +multi thread allocation,none object poll,,,,12044846.0,ns,15552 +multi thread allocation,none object poll,,,,12065591.0,ns,15744 +multi thread allocation,none object poll,,,,12618240.0,ns,15936 +multi thread allocation,none object poll,,,,12630455.0,ns,16128 +multi thread allocation,none object poll,,,,14054714.0,ns,16320 +multi thread allocation,none object poll,,,,13758703.0,ns,16512 +multi thread allocation,none object poll,,,,13211141.0,ns,16704 +multi thread allocation,none object poll,,,,13727351.0,ns,16896 +multi thread allocation,none object poll,,,,13356759.0,ns,17088 +multi thread allocation,none object poll,,,,13720989.0,ns,17280 +multi thread allocation,none object poll,,,,14317995.0,ns,17472 +multi thread allocation,none object poll,,,,14320305.0,ns,17664 +multi thread allocation,none object poll,,,,14233726.0,ns,17856 +multi thread allocation,none object poll,,,,15082054.0,ns,18048 +multi thread allocation,none object poll,,,,14785432.0,ns,18240 +multi thread allocation,none object poll,,,,15184334.0,ns,18432 +multi thread allocation,none object poll,,,,15538964.0,ns,18624 +multi thread allocation,none object poll,,,,14944130.0,ns,18816 +multi thread allocation,none object poll,,,,15221091.0,ns,19008 +multi thread allocation,none object poll,,,,12795710.0,ns,19200 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/sample.json new file mode 100644 index 0000000000000..73a888a41a70d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[192.0,384.0,576.0,768.0,960.0,1152.0,1344.0,1536.0,1728.0,1920.0,2112.0,2304.0,2496.0,2688.0,2880.0,3072.0,3264.0,3456.0,3648.0,3840.0,4032.0,4224.0,4416.0,4608.0,4800.0,4992.0,5184.0,5376.0,5568.0,5760.0,5952.0,6144.0,6336.0,6528.0,6720.0,6912.0,7104.0,7296.0,7488.0,7680.0,7872.0,8064.0,8256.0,8448.0,8640.0,8832.0,9024.0,9216.0,9408.0,9600.0,9792.0,9984.0,10176.0,10368.0,10560.0,10752.0,10944.0,11136.0,11328.0,11520.0,11712.0,11904.0,12096.0,12288.0,12480.0,12672.0,12864.0,13056.0,13248.0,13440.0,13632.0,13824.0,14016.0,14208.0,14400.0,14592.0,14784.0,14976.0,15168.0,15360.0,15552.0,15744.0,15936.0,16128.0,16320.0,16512.0,16704.0,16896.0,17088.0,17280.0,17472.0,17664.0,17856.0,18048.0,18240.0,18432.0,18624.0,18816.0,19008.0,19200.0],"times":[96010.0,184206.0,290804.0,362019.0,369576.0,367121.0,380108.0,389321.0,402445.0,408184.0,537165.0,430052.0,426208.0,421779.0,413526.0,417714.0,1419281.0,1470515.0,1511555.0,1553379.0,1590208.0,1755509.0,1912956.0,2034981.0,2127469.0,2369552.0,2671265.0,2693567.0,2958926.0,3168545.0,3268790.0,3485683.0,3694047.0,3868657.0,4056815.0,4078476.0,4248493.0,4553196.0,4562127.0,4885976.0,4870874.0,4973369.0,5164462.0,5504334.0,5849794.0,5782946.0,6286309.0,6518861.0,6569449.0,7037794.0,6678365.0,6910520.0,7362861.0,7530660.0,7974143.0,7547609.0,8705514.0,8019280.0,8144088.0,8360975.0,8553551.0,9721324.0,9034726.0,9055037.0,9540688.0,9542928.0,9532310.0,10237679.0,11230743.0,10130936.0,10405701.0,10751349.0,11507893.0,11012934.0,11216309.0,11441381.0,11127686.0,11951899.0,12349749.0,12938804.0,12044846.0,12065591.0,12618240.0,12630455.0,14054714.0,13758703.0,13211141.0,13727351.0,13356759.0,13720989.0,14317995.0,14320305.0,14233726.0,15082054.0,14785432.0,15184334.0,15538964.0,14944130.0,15221091.0,12795710.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/tukey.json new file mode 100644 index 0000000000000..8ac454c7c5fe2 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/new/tukey.json @@ -0,0 +1 @@ +[-342.8975466283774,78.94606020515653,1203.8623450945804,1625.7059519281142] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/MAD.svg new file mode 100644 index 0000000000000..3ba36f990e43f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/MAD.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 0.018 + + + + + 0.02 + + + + + 100 + + + + + 120 + + + + + 140 + + + + + 160 + + + + + 180 + + + + + 200 + + + + + 220 + + + + + 240 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/none object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/SD.svg new file mode 100644 index 0000000000000..242705938e67d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/SD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 160 + + + + + 170 + + + + + 180 + + + + + 190 + + + + + 200 + + + + + 210 + + + + + 220 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/none object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/index.html new file mode 100644 index 0000000000000..83747b08a3f0f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + multi thread allocation/none object poll - Criterion.rs + + + + +
+

multi thread allocation/none object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope744.74 ns761.26 ns774.81 ns
0.26470220.27201020.2670511
Mean586.36 ns625.09 ns662.14 ns
Std. Dev.165.71 ns194.72 ns218.77 ns
Median624.07 ns697.45 ns733.61 ns
MAD108.23 ns151.18 ns230.71 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/mean.svg new file mode 100644 index 0000000000000..e8a8806775d8d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/mean.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 580 + + + + + 590 + + + + + 600 + + + + + 610 + + + + + 620 + + + + + 630 + + + + + 640 + + + + + 650 + + + + + 660 + + + + + 670 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/none object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/median.svg new file mode 100644 index 0000000000000..40d51a118f999 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/median.svg @@ -0,0 +1,288 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 620 + + + + + 640 + + + + + 660 + + + + + 680 + + + + + 700 + + + + + 720 + + + + + 740 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/none object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/pdf.svg new file mode 100644 index 0000000000000..6a8bab3eca089 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/pdf.svg @@ -0,0 +1,405 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 0 + + + + + 200 + + + + + 400 + + + + + 600 + + + + + 800 + + + + + 1000 + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/none object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..8265d53f355f9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/pdf_small.svg @@ -0,0 +1,204 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + 0 + + + + + 200 + + + + + 400 + + + + + 600 + + + + + 800 + + + + + 1000 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/regression.svg new file mode 100644 index 0000000000000..5e27d569ac569 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/regression.svg @@ -0,0 +1,473 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + multi thread allocation/none object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/regression_small.svg new file mode 100644 index 0000000000000..8d6166616afbd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/regression_small.svg @@ -0,0 +1,451 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/slope.svg new file mode 100644 index 0000000000000..e555f8651535a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 745 + + + + + 750 + + + + + 755 + + + + + 760 + + + + + 765 + + + + + 770 + + + + + 775 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/none object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/typical.svg new file mode 100644 index 0000000000000..e334623a4d69d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/none object poll/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 745 + + + + + 750 + + + + + 755 + + + + + 760 + + + + + 765 + + + + + 770 + + + + + 775 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/none object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/report/index.html new file mode 100644 index 0000000000000..feb93fbe8c842 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/report/index.html @@ -0,0 +1,208 @@ + + + + + + multi thread allocation Summary - Criterion.rs + + + + +
+

multi thread allocation

+

Violin Plot

+ + Violin Plot + +

This chart shows the relationship between function/parameter and iteration time. The thickness of the shaded + region indicates the probability that a measurement of the given function/parameter would take a particular + length of time.

+
+ +

multi thread allocation/crate 'object-pool'

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

multi thread allocation/crate 'sharded-slab'

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

multi thread allocation/linear object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

multi thread allocation/mutex object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

multi thread allocation/none object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

multi thread allocation/spin_lock object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/report/violin.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/report/violin.svg new file mode 100644 index 0000000000000..f05cc42b70791 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/report/violin.svg @@ -0,0 +1,669 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + multi thread allocation/spin_lock object poll + + + + + multi thread allocation/none object poll + + + + + multi thread allocation/mutex object poll + + + + + multi thread allocation/linear object poll + + + + + multi thread allocation/crate 'sharded-slab' + + + + + multi thread allocation/crate 'object-pool' + + + + + + + + + + + + + -1 + + + + + + + + + + + + + -0.5 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.5 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 2.5 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 3.5 + + + + + + + + + + + + + 4 + + + + + + + + + Input + + + + + Average time (us) + + + + + multi thread allocation: Violin plot + + + + + PDF + + + PDF + + + + + + + + + + gnuplot_plot_2 + + + + + + + gnuplot_plot_3 + + + + + + + gnuplot_plot_4 + + + + + + + gnuplot_plot_5 + + + + + + + gnuplot_plot_6 + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/benchmark.json new file mode 100644 index 0000000000000..f55ddb622249a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread allocation","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"multi thread allocation/spin_lock object poll","directory_name":"multi thread allocation/spin_lock object poll","title":"multi thread allocation/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/estimates.json new file mode 100644 index 0000000000000..b5b42016de271 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1228.636788592407,"upper_bound":1502.7479502068893},"point_estimate":1368.3675326073703,"standard_error":69.67339900507585},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1604.288475177305,"upper_bound":1793.6826774798556},"point_estimate":1669.0606971153848,"standard_error":57.01017544690179},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":303.58098082067175,"upper_bound":693.622148961766},"point_estimate":513.021787736028,"standard_error":109.44429947172195},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1778.9456232097555,"upper_bound":1910.0452670596742},"point_estimate":1853.1973559184278,"standard_error":33.46276224567609},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":634.5946573782245,"upper_bound":748.1818633826315},"point_estimate":701.0890503657536,"standard_error":28.97698319662031}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/raw.csv new file mode 100644 index 0000000000000..3e7327fd6b033 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread allocation,spin_lock object poll,,,,133327.0,ns,80 +multi thread allocation,spin_lock object poll,,,,265844.0,ns,160 +multi thread allocation,spin_lock object poll,,,,241556.0,ns,240 +multi thread allocation,spin_lock object poll,,,,483113.0,ns,320 +multi thread allocation,spin_lock object poll,,,,487307.0,ns,400 +multi thread allocation,spin_lock object poll,,,,528734.0,ns,480 +multi thread allocation,spin_lock object poll,,,,655807.0,ns,560 +multi thread allocation,spin_lock object poll,,,,549103.0,ns,640 +multi thread allocation,spin_lock object poll,,,,542866.0,ns,720 +multi thread allocation,spin_lock object poll,,,,607496.0,ns,800 +multi thread allocation,spin_lock object poll,,,,651934.0,ns,880 +multi thread allocation,spin_lock object poll,,,,629476.0,ns,960 +multi thread allocation,spin_lock object poll,,,,648886.0,ns,1040 +multi thread allocation,spin_lock object poll,,,,616286.0,ns,1120 +multi thread allocation,spin_lock object poll,,,,603420.0,ns,1200 +multi thread allocation,spin_lock object poll,,,,587692.0,ns,1280 +multi thread allocation,spin_lock object poll,,,,547831.0,ns,1360 +multi thread allocation,spin_lock object poll,,,,559359.0,ns,1440 +multi thread allocation,spin_lock object poll,,,,594582.0,ns,1520 +multi thread allocation,spin_lock object poll,,,,549335.0,ns,1600 +multi thread allocation,spin_lock object poll,,,,596689.0,ns,1680 +multi thread allocation,spin_lock object poll,,,,602001.0,ns,1760 +multi thread allocation,spin_lock object poll,,,,618959.0,ns,1840 +multi thread allocation,spin_lock object poll,,,,598722.0,ns,1920 +multi thread allocation,spin_lock object poll,,,,558102.0,ns,2000 +multi thread allocation,spin_lock object poll,,,,655005.0,ns,2080 +multi thread allocation,spin_lock object poll,,,,706715.0,ns,2160 +multi thread allocation,spin_lock object poll,,,,705131.0,ns,2240 +multi thread allocation,spin_lock object poll,,,,715233.0,ns,2320 +multi thread allocation,spin_lock object poll,,,,728609.0,ns,2400 +multi thread allocation,spin_lock object poll,,,,684096.0,ns,2480 +multi thread allocation,spin_lock object poll,,,,669172.0,ns,2560 +multi thread allocation,spin_lock object poll,,,,664280.0,ns,2640 +multi thread allocation,spin_lock object poll,,,,662270.0,ns,2720 +multi thread allocation,spin_lock object poll,,,,679602.0,ns,2800 +multi thread allocation,spin_lock object poll,,,,666846.0,ns,2880 +multi thread allocation,spin_lock object poll,,,,675409.0,ns,2960 +multi thread allocation,spin_lock object poll,,,,683413.0,ns,3040 +multi thread allocation,spin_lock object poll,,,,1352218.0,ns,3120 +multi thread allocation,spin_lock object poll,,,,5540683.0,ns,3200 +multi thread allocation,spin_lock object poll,,,,5424234.0,ns,3280 +multi thread allocation,spin_lock object poll,,,,5412106.0,ns,3360 +multi thread allocation,spin_lock object poll,,,,5550971.0,ns,3440 +multi thread allocation,spin_lock object poll,,,,5654868.0,ns,3520 +multi thread allocation,spin_lock object poll,,,,5819347.0,ns,3600 +multi thread allocation,spin_lock object poll,,,,5944529.0,ns,3680 +multi thread allocation,spin_lock object poll,,,,6007845.0,ns,3760 +multi thread allocation,spin_lock object poll,,,,6247135.0,ns,3840 +multi thread allocation,spin_lock object poll,,,,6226553.0,ns,3920 +multi thread allocation,spin_lock object poll,,,,6651406.0,ns,4000 +multi thread allocation,spin_lock object poll,,,,6481280.0,ns,4080 +multi thread allocation,spin_lock object poll,,,,6953581.0,ns,4160 +multi thread allocation,spin_lock object poll,,,,7712145.0,ns,4240 +multi thread allocation,spin_lock object poll,,,,7386862.0,ns,4320 +multi thread allocation,spin_lock object poll,,,,7586563.0,ns,4400 +multi thread allocation,spin_lock object poll,,,,7837594.0,ns,4480 +multi thread allocation,spin_lock object poll,,,,8012830.0,ns,4560 +multi thread allocation,spin_lock object poll,,,,8190713.0,ns,4640 +multi thread allocation,spin_lock object poll,,,,8424372.0,ns,4720 +multi thread allocation,spin_lock object poll,,,,8576545.0,ns,4800 +multi thread allocation,spin_lock object poll,,,,8796399.0,ns,4880 +multi thread allocation,spin_lock object poll,,,,9008327.0,ns,4960 +multi thread allocation,spin_lock object poll,,,,9215397.0,ns,5040 +multi thread allocation,spin_lock object poll,,,,8566802.0,ns,5120 +multi thread allocation,spin_lock object poll,,,,9728583.0,ns,5200 +multi thread allocation,spin_lock object poll,,,,10004845.0,ns,5280 +multi thread allocation,spin_lock object poll,,,,10188685.0,ns,5360 +multi thread allocation,spin_lock object poll,,,,10167009.0,ns,5440 +multi thread allocation,spin_lock object poll,,,,10627500.0,ns,5520 +multi thread allocation,spin_lock object poll,,,,10824996.0,ns,5600 +multi thread allocation,spin_lock object poll,,,,10979308.0,ns,5680 +multi thread allocation,spin_lock object poll,,,,11186665.0,ns,5760 +multi thread allocation,spin_lock object poll,,,,11132334.0,ns,5840 +multi thread allocation,spin_lock object poll,,,,11343457.0,ns,5920 +multi thread allocation,spin_lock object poll,,,,11590259.0,ns,6000 +multi thread allocation,spin_lock object poll,,,,12050501.0,ns,6080 +multi thread allocation,spin_lock object poll,,,,12205286.0,ns,6160 +multi thread allocation,spin_lock object poll,,,,12313092.0,ns,6240 +multi thread allocation,spin_lock object poll,,,,12232814.0,ns,6320 +multi thread allocation,spin_lock object poll,,,,14848637.0,ns,6400 +multi thread allocation,spin_lock object poll,,,,12624354.0,ns,6480 +multi thread allocation,spin_lock object poll,,,,12854474.0,ns,6560 +multi thread allocation,spin_lock object poll,,,,13176789.0,ns,6640 +multi thread allocation,spin_lock object poll,,,,13266693.0,ns,6720 +multi thread allocation,spin_lock object poll,,,,13653497.0,ns,6800 +multi thread allocation,spin_lock object poll,,,,13737017.0,ns,6880 +multi thread allocation,spin_lock object poll,,,,14345836.0,ns,6960 +multi thread allocation,spin_lock object poll,,,,14507622.0,ns,7040 +multi thread allocation,spin_lock object poll,,,,14293716.0,ns,7120 +multi thread allocation,spin_lock object poll,,,,14560640.0,ns,7200 +multi thread allocation,spin_lock object poll,,,,15202388.0,ns,7280 +multi thread allocation,spin_lock object poll,,,,15118779.0,ns,7360 +multi thread allocation,spin_lock object poll,,,,15585022.0,ns,7440 +multi thread allocation,spin_lock object poll,,,,15391233.0,ns,7520 +multi thread allocation,spin_lock object poll,,,,15808199.0,ns,7600 +multi thread allocation,spin_lock object poll,,,,15786384.0,ns,7680 +multi thread allocation,spin_lock object poll,,,,16243798.0,ns,7760 +multi thread allocation,spin_lock object poll,,,,16603561.0,ns,7840 +multi thread allocation,spin_lock object poll,,,,16409001.0,ns,7920 +multi thread allocation,spin_lock object poll,,,,17153929.0,ns,8000 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/sample.json new file mode 100644 index 0000000000000..2024aaeb11cc9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[80.0,160.0,240.0,320.0,400.0,480.0,560.0,640.0,720.0,800.0,880.0,960.0,1040.0,1120.0,1200.0,1280.0,1360.0,1440.0,1520.0,1600.0,1680.0,1760.0,1840.0,1920.0,2000.0,2080.0,2160.0,2240.0,2320.0,2400.0,2480.0,2560.0,2640.0,2720.0,2800.0,2880.0,2960.0,3040.0,3120.0,3200.0,3280.0,3360.0,3440.0,3520.0,3600.0,3680.0,3760.0,3840.0,3920.0,4000.0,4080.0,4160.0,4240.0,4320.0,4400.0,4480.0,4560.0,4640.0,4720.0,4800.0,4880.0,4960.0,5040.0,5120.0,5200.0,5280.0,5360.0,5440.0,5520.0,5600.0,5680.0,5760.0,5840.0,5920.0,6000.0,6080.0,6160.0,6240.0,6320.0,6400.0,6480.0,6560.0,6640.0,6720.0,6800.0,6880.0,6960.0,7040.0,7120.0,7200.0,7280.0,7360.0,7440.0,7520.0,7600.0,7680.0,7760.0,7840.0,7920.0,8000.0],"times":[133327.0,265844.0,241556.0,483113.0,487307.0,528734.0,655807.0,549103.0,542866.0,607496.0,651934.0,629476.0,648886.0,616286.0,603420.0,587692.0,547831.0,559359.0,594582.0,549335.0,596689.0,602001.0,618959.0,598722.0,558102.0,655005.0,706715.0,705131.0,715233.0,728609.0,684096.0,669172.0,664280.0,662270.0,679602.0,666846.0,675409.0,683413.0,1352218.0,5540683.0,5424234.0,5412106.0,5550971.0,5654868.0,5819347.0,5944529.0,6007845.0,6247135.0,6226553.0,6651406.0,6481280.0,6953581.0,7712145.0,7386862.0,7586563.0,7837594.0,8012830.0,8190713.0,8424372.0,8576545.0,8796399.0,9008327.0,9215397.0,8566802.0,9728583.0,10004845.0,10188685.0,10167009.0,10627500.0,10824996.0,10979308.0,11186665.0,11132334.0,11343457.0,11590259.0,12050501.0,12205286.0,12313092.0,12232814.0,14848637.0,12624354.0,12854474.0,13176789.0,13266693.0,13653497.0,13737017.0,14345836.0,14507622.0,14293716.0,14560640.0,15202388.0,15118779.0,15585022.0,15391233.0,15808199.0,15786384.0,16243798.0,16603561.0,16409001.0,17153929.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/tukey.json new file mode 100644 index 0000000000000..cd9d101653d9e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/base/tukey.json @@ -0,0 +1 @@ +[-3658.017563526597,-1559.806772834727,4035.422002343593,6133.632793035463] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/benchmark.json new file mode 100644 index 0000000000000..f55ddb622249a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread allocation","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"multi thread allocation/spin_lock object poll","directory_name":"multi thread allocation/spin_lock object poll","title":"multi thread allocation/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/estimates.json new file mode 100644 index 0000000000000..b5b42016de271 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1228.636788592407,"upper_bound":1502.7479502068893},"point_estimate":1368.3675326073703,"standard_error":69.67339900507585},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1604.288475177305,"upper_bound":1793.6826774798556},"point_estimate":1669.0606971153848,"standard_error":57.01017544690179},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":303.58098082067175,"upper_bound":693.622148961766},"point_estimate":513.021787736028,"standard_error":109.44429947172195},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1778.9456232097555,"upper_bound":1910.0452670596742},"point_estimate":1853.1973559184278,"standard_error":33.46276224567609},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":634.5946573782245,"upper_bound":748.1818633826315},"point_estimate":701.0890503657536,"standard_error":28.97698319662031}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/raw.csv new file mode 100644 index 0000000000000..3e7327fd6b033 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread allocation,spin_lock object poll,,,,133327.0,ns,80 +multi thread allocation,spin_lock object poll,,,,265844.0,ns,160 +multi thread allocation,spin_lock object poll,,,,241556.0,ns,240 +multi thread allocation,spin_lock object poll,,,,483113.0,ns,320 +multi thread allocation,spin_lock object poll,,,,487307.0,ns,400 +multi thread allocation,spin_lock object poll,,,,528734.0,ns,480 +multi thread allocation,spin_lock object poll,,,,655807.0,ns,560 +multi thread allocation,spin_lock object poll,,,,549103.0,ns,640 +multi thread allocation,spin_lock object poll,,,,542866.0,ns,720 +multi thread allocation,spin_lock object poll,,,,607496.0,ns,800 +multi thread allocation,spin_lock object poll,,,,651934.0,ns,880 +multi thread allocation,spin_lock object poll,,,,629476.0,ns,960 +multi thread allocation,spin_lock object poll,,,,648886.0,ns,1040 +multi thread allocation,spin_lock object poll,,,,616286.0,ns,1120 +multi thread allocation,spin_lock object poll,,,,603420.0,ns,1200 +multi thread allocation,spin_lock object poll,,,,587692.0,ns,1280 +multi thread allocation,spin_lock object poll,,,,547831.0,ns,1360 +multi thread allocation,spin_lock object poll,,,,559359.0,ns,1440 +multi thread allocation,spin_lock object poll,,,,594582.0,ns,1520 +multi thread allocation,spin_lock object poll,,,,549335.0,ns,1600 +multi thread allocation,spin_lock object poll,,,,596689.0,ns,1680 +multi thread allocation,spin_lock object poll,,,,602001.0,ns,1760 +multi thread allocation,spin_lock object poll,,,,618959.0,ns,1840 +multi thread allocation,spin_lock object poll,,,,598722.0,ns,1920 +multi thread allocation,spin_lock object poll,,,,558102.0,ns,2000 +multi thread allocation,spin_lock object poll,,,,655005.0,ns,2080 +multi thread allocation,spin_lock object poll,,,,706715.0,ns,2160 +multi thread allocation,spin_lock object poll,,,,705131.0,ns,2240 +multi thread allocation,spin_lock object poll,,,,715233.0,ns,2320 +multi thread allocation,spin_lock object poll,,,,728609.0,ns,2400 +multi thread allocation,spin_lock object poll,,,,684096.0,ns,2480 +multi thread allocation,spin_lock object poll,,,,669172.0,ns,2560 +multi thread allocation,spin_lock object poll,,,,664280.0,ns,2640 +multi thread allocation,spin_lock object poll,,,,662270.0,ns,2720 +multi thread allocation,spin_lock object poll,,,,679602.0,ns,2800 +multi thread allocation,spin_lock object poll,,,,666846.0,ns,2880 +multi thread allocation,spin_lock object poll,,,,675409.0,ns,2960 +multi thread allocation,spin_lock object poll,,,,683413.0,ns,3040 +multi thread allocation,spin_lock object poll,,,,1352218.0,ns,3120 +multi thread allocation,spin_lock object poll,,,,5540683.0,ns,3200 +multi thread allocation,spin_lock object poll,,,,5424234.0,ns,3280 +multi thread allocation,spin_lock object poll,,,,5412106.0,ns,3360 +multi thread allocation,spin_lock object poll,,,,5550971.0,ns,3440 +multi thread allocation,spin_lock object poll,,,,5654868.0,ns,3520 +multi thread allocation,spin_lock object poll,,,,5819347.0,ns,3600 +multi thread allocation,spin_lock object poll,,,,5944529.0,ns,3680 +multi thread allocation,spin_lock object poll,,,,6007845.0,ns,3760 +multi thread allocation,spin_lock object poll,,,,6247135.0,ns,3840 +multi thread allocation,spin_lock object poll,,,,6226553.0,ns,3920 +multi thread allocation,spin_lock object poll,,,,6651406.0,ns,4000 +multi thread allocation,spin_lock object poll,,,,6481280.0,ns,4080 +multi thread allocation,spin_lock object poll,,,,6953581.0,ns,4160 +multi thread allocation,spin_lock object poll,,,,7712145.0,ns,4240 +multi thread allocation,spin_lock object poll,,,,7386862.0,ns,4320 +multi thread allocation,spin_lock object poll,,,,7586563.0,ns,4400 +multi thread allocation,spin_lock object poll,,,,7837594.0,ns,4480 +multi thread allocation,spin_lock object poll,,,,8012830.0,ns,4560 +multi thread allocation,spin_lock object poll,,,,8190713.0,ns,4640 +multi thread allocation,spin_lock object poll,,,,8424372.0,ns,4720 +multi thread allocation,spin_lock object poll,,,,8576545.0,ns,4800 +multi thread allocation,spin_lock object poll,,,,8796399.0,ns,4880 +multi thread allocation,spin_lock object poll,,,,9008327.0,ns,4960 +multi thread allocation,spin_lock object poll,,,,9215397.0,ns,5040 +multi thread allocation,spin_lock object poll,,,,8566802.0,ns,5120 +multi thread allocation,spin_lock object poll,,,,9728583.0,ns,5200 +multi thread allocation,spin_lock object poll,,,,10004845.0,ns,5280 +multi thread allocation,spin_lock object poll,,,,10188685.0,ns,5360 +multi thread allocation,spin_lock object poll,,,,10167009.0,ns,5440 +multi thread allocation,spin_lock object poll,,,,10627500.0,ns,5520 +multi thread allocation,spin_lock object poll,,,,10824996.0,ns,5600 +multi thread allocation,spin_lock object poll,,,,10979308.0,ns,5680 +multi thread allocation,spin_lock object poll,,,,11186665.0,ns,5760 +multi thread allocation,spin_lock object poll,,,,11132334.0,ns,5840 +multi thread allocation,spin_lock object poll,,,,11343457.0,ns,5920 +multi thread allocation,spin_lock object poll,,,,11590259.0,ns,6000 +multi thread allocation,spin_lock object poll,,,,12050501.0,ns,6080 +multi thread allocation,spin_lock object poll,,,,12205286.0,ns,6160 +multi thread allocation,spin_lock object poll,,,,12313092.0,ns,6240 +multi thread allocation,spin_lock object poll,,,,12232814.0,ns,6320 +multi thread allocation,spin_lock object poll,,,,14848637.0,ns,6400 +multi thread allocation,spin_lock object poll,,,,12624354.0,ns,6480 +multi thread allocation,spin_lock object poll,,,,12854474.0,ns,6560 +multi thread allocation,spin_lock object poll,,,,13176789.0,ns,6640 +multi thread allocation,spin_lock object poll,,,,13266693.0,ns,6720 +multi thread allocation,spin_lock object poll,,,,13653497.0,ns,6800 +multi thread allocation,spin_lock object poll,,,,13737017.0,ns,6880 +multi thread allocation,spin_lock object poll,,,,14345836.0,ns,6960 +multi thread allocation,spin_lock object poll,,,,14507622.0,ns,7040 +multi thread allocation,spin_lock object poll,,,,14293716.0,ns,7120 +multi thread allocation,spin_lock object poll,,,,14560640.0,ns,7200 +multi thread allocation,spin_lock object poll,,,,15202388.0,ns,7280 +multi thread allocation,spin_lock object poll,,,,15118779.0,ns,7360 +multi thread allocation,spin_lock object poll,,,,15585022.0,ns,7440 +multi thread allocation,spin_lock object poll,,,,15391233.0,ns,7520 +multi thread allocation,spin_lock object poll,,,,15808199.0,ns,7600 +multi thread allocation,spin_lock object poll,,,,15786384.0,ns,7680 +multi thread allocation,spin_lock object poll,,,,16243798.0,ns,7760 +multi thread allocation,spin_lock object poll,,,,16603561.0,ns,7840 +multi thread allocation,spin_lock object poll,,,,16409001.0,ns,7920 +multi thread allocation,spin_lock object poll,,,,17153929.0,ns,8000 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/sample.json new file mode 100644 index 0000000000000..2024aaeb11cc9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[80.0,160.0,240.0,320.0,400.0,480.0,560.0,640.0,720.0,800.0,880.0,960.0,1040.0,1120.0,1200.0,1280.0,1360.0,1440.0,1520.0,1600.0,1680.0,1760.0,1840.0,1920.0,2000.0,2080.0,2160.0,2240.0,2320.0,2400.0,2480.0,2560.0,2640.0,2720.0,2800.0,2880.0,2960.0,3040.0,3120.0,3200.0,3280.0,3360.0,3440.0,3520.0,3600.0,3680.0,3760.0,3840.0,3920.0,4000.0,4080.0,4160.0,4240.0,4320.0,4400.0,4480.0,4560.0,4640.0,4720.0,4800.0,4880.0,4960.0,5040.0,5120.0,5200.0,5280.0,5360.0,5440.0,5520.0,5600.0,5680.0,5760.0,5840.0,5920.0,6000.0,6080.0,6160.0,6240.0,6320.0,6400.0,6480.0,6560.0,6640.0,6720.0,6800.0,6880.0,6960.0,7040.0,7120.0,7200.0,7280.0,7360.0,7440.0,7520.0,7600.0,7680.0,7760.0,7840.0,7920.0,8000.0],"times":[133327.0,265844.0,241556.0,483113.0,487307.0,528734.0,655807.0,549103.0,542866.0,607496.0,651934.0,629476.0,648886.0,616286.0,603420.0,587692.0,547831.0,559359.0,594582.0,549335.0,596689.0,602001.0,618959.0,598722.0,558102.0,655005.0,706715.0,705131.0,715233.0,728609.0,684096.0,669172.0,664280.0,662270.0,679602.0,666846.0,675409.0,683413.0,1352218.0,5540683.0,5424234.0,5412106.0,5550971.0,5654868.0,5819347.0,5944529.0,6007845.0,6247135.0,6226553.0,6651406.0,6481280.0,6953581.0,7712145.0,7386862.0,7586563.0,7837594.0,8012830.0,8190713.0,8424372.0,8576545.0,8796399.0,9008327.0,9215397.0,8566802.0,9728583.0,10004845.0,10188685.0,10167009.0,10627500.0,10824996.0,10979308.0,11186665.0,11132334.0,11343457.0,11590259.0,12050501.0,12205286.0,12313092.0,12232814.0,14848637.0,12624354.0,12854474.0,13176789.0,13266693.0,13653497.0,13737017.0,14345836.0,14507622.0,14293716.0,14560640.0,15202388.0,15118779.0,15585022.0,15391233.0,15808199.0,15786384.0,16243798.0,16603561.0,16409001.0,17153929.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/tukey.json new file mode 100644 index 0000000000000..cd9d101653d9e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/new/tukey.json @@ -0,0 +1 @@ +[-3658.017563526597,-1559.806772834727,4035.422002343593,6133.632793035463] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/MAD.svg new file mode 100644 index 0000000000000..5fb14164a9e0d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/MAD.svg @@ -0,0 +1,313 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.0005 + + + + + 0.001 + + + + + 0.0015 + + + + + 0.002 + + + + + 0.0025 + + + + + 0.003 + + + + + 0.0035 + + + + + 0.004 + + + + + 300 + + + + + 350 + + + + + 400 + + + + + 450 + + + + + 500 + + + + + 550 + + + + + 600 + + + + + 650 + + + + + 700 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/spin_lock object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/SD.svg new file mode 100644 index 0000000000000..4f4dbdeda218f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/SD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0.012 + + + + + 0.014 + + + + + 0.016 + + + + + 640 + + + + + 660 + + + + + 680 + + + + + 700 + + + + + 720 + + + + + 740 + + + + + 760 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread allocation/spin_lock object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/index.html new file mode 100644 index 0000000000000..095692f9871d7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + multi thread allocation/spin_lock object poll - Criterion.rs + + + + +
+

multi thread allocation/spin_lock object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope1.7789 us1.8532 us1.9100 us
0.21585440.22115720.2180178
Mean1.2286 us1.3684 us1.5027 us
Std. Dev.634.59 ns701.09 ns748.18 ns
Median1.6043 us1.6691 us1.7937 us
MAD303.58 ns513.02 ns693.62 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/mean.svg new file mode 100644 index 0000000000000..75e4baa36e7c0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 1.2 + + + + + 1.25 + + + + + 1.3 + + + + + 1.35 + + + + + 1.4 + + + + + 1.45 + + + + + 1.5 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/spin_lock object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/median.svg new file mode 100644 index 0000000000000..7382225e0e00f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/median.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 1.6 + + + + + 1.65 + + + + + 1.7 + + + + + 1.75 + + + + + 1.8 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/spin_lock object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/pdf.svg new file mode 100644 index 0000000000000..836a5d3d4729e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/pdf.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + -0.5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/spin_lock object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..fcfa1b040afc5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/pdf_small.svg @@ -0,0 +1,229 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + -0.5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/regression.svg new file mode 100644 index 0000000000000..9bf7d33ccf664 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/regression.svg @@ -0,0 +1,460 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + multi thread allocation/spin_lock object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/regression_small.svg new file mode 100644 index 0000000000000..31d2cb4125dc5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/regression_small.svg @@ -0,0 +1,438 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/slope.svg new file mode 100644 index 0000000000000..ab9d1975f870d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/slope.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 1.78 + + + + + 1.8 + + + + + 1.82 + + + + + 1.84 + + + + + 1.86 + + + + + 1.88 + + + + + 1.9 + + + + + 1.92 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/spin_lock object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/typical.svg new file mode 100644 index 0000000000000..ca6722b31e311 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread allocation/spin_lock object poll/report/typical.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 1.78 + + + + + 1.8 + + + + + 1.82 + + + + + 1.84 + + + + + 1.86 + + + + + 1.88 + + + + + 1.9 + + + + + 1.92 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread allocation/spin_lock object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/benchmark.json new file mode 100644 index 0000000000000..645135189c6b0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread free","function_id":"crate 'object-pool'","value_str":null,"throughput":null,"full_id":"multi thread free/crate 'object-pool'","directory_name":"multi thread free/crate 'object-pool'","title":"multi thread free/crate 'object-pool'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/estimates.json new file mode 100644 index 0000000000000..70ede21cdfd8f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":43.288140725983176,"upper_bound":46.92830299636239},"point_estimate":44.79783491988626,"standard_error":0.9444458911054957},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":43.766736469821765,"upper_bound":45.10553168635875},"point_estimate":44.27780701754386,"standard_error":0.3084270863515177},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":2.4256619061898013,"upper_bound":4.359135201537537},"point_estimate":3.430539988957236,"standard_error":0.4772187503084713},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":43.855622628513096,"upper_bound":46.30628178865771},"point_estimate":45.11798481796333,"standard_error":0.6273439687965535},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":3.688748036286764,"upper_bound":15.324930834459042},"point_estimate":9.507328257030764,"standard_error":3.755876523209489}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/raw.csv new file mode 100644 index 0000000000000..b430d6a067a59 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread free,crate 'object-pool',,,,24404.0,ns,190 +multi thread free,crate 'object-pool',,,,9974.0,ns,380 +multi thread free,crate 'object-pool',,,,17589.0,ns,570 +multi thread free,crate 'object-pool',,,,27984.0,ns,760 +multi thread free,crate 'object-pool',,,,36809.0,ns,950 +multi thread free,crate 'object-pool',,,,50488.0,ns,1140 +multi thread free,crate 'object-pool',,,,55814.0,ns,1330 +multi thread free,crate 'object-pool',,,,66577.0,ns,1520 +multi thread free,crate 'object-pool',,,,71966.0,ns,1710 +multi thread free,crate 'object-pool',,,,84109.0,ns,1900 +multi thread free,crate 'object-pool',,,,88410.0,ns,2090 +multi thread free,crate 'object-pool',,,,100213.0,ns,2280 +multi thread free,crate 'object-pool',,,,108224.0,ns,2470 +multi thread free,crate 'object-pool',,,,103850.0,ns,2660 +multi thread free,crate 'object-pool',,,,111494.0,ns,2850 +multi thread free,crate 'object-pool',,,,118310.0,ns,3040 +multi thread free,crate 'object-pool',,,,118536.0,ns,3230 +multi thread free,crate 'object-pool',,,,143632.0,ns,3420 +multi thread free,crate 'object-pool',,,,155860.0,ns,3610 +multi thread free,crate 'object-pool',,,,168089.0,ns,3800 +multi thread free,crate 'object-pool',,,,172951.0,ns,3990 +multi thread free,crate 'object-pool',,,,181761.0,ns,4180 +multi thread free,crate 'object-pool',,,,187544.0,ns,4370 +multi thread free,crate 'object-pool',,,,177255.0,ns,4560 +multi thread free,crate 'object-pool',,,,206058.0,ns,4750 +multi thread free,crate 'object-pool',,,,239875.0,ns,4940 +multi thread free,crate 'object-pool',,,,213528.0,ns,5130 +multi thread free,crate 'object-pool',,,,235995.0,ns,5320 +multi thread free,crate 'object-pool',,,,221547.0,ns,5510 +multi thread free,crate 'object-pool',,,,236459.0,ns,5700 +multi thread free,crate 'object-pool',,,,253706.0,ns,5890 +multi thread free,crate 'object-pool',,,,269791.0,ns,6080 +multi thread free,crate 'object-pool',,,,284320.0,ns,6270 +multi thread free,crate 'object-pool',,,,290173.0,ns,6460 +multi thread free,crate 'object-pool',,,,293798.0,ns,6650 +multi thread free,crate 'object-pool',,,,300074.0,ns,6840 +multi thread free,crate 'object-pool',,,,302458.0,ns,7030 +multi thread free,crate 'object-pool',,,,302969.0,ns,7220 +multi thread free,crate 'object-pool',,,,325950.0,ns,7410 +multi thread free,crate 'object-pool',,,,309560.0,ns,7600 +multi thread free,crate 'object-pool',,,,337881.0,ns,7790 +multi thread free,crate 'object-pool',,,,330840.0,ns,7980 +multi thread free,crate 'object-pool',,,,345983.0,ns,8170 +multi thread free,crate 'object-pool',,,,380465.0,ns,8360 +multi thread free,crate 'object-pool',,,,392104.0,ns,8550 +multi thread free,crate 'object-pool',,,,398023.0,ns,8740 +multi thread free,crate 'object-pool',,,,422819.0,ns,8930 +multi thread free,crate 'object-pool',,,,402453.0,ns,9120 +multi thread free,crate 'object-pool',,,,416147.0,ns,9310 +multi thread free,crate 'object-pool',,,,418249.0,ns,9500 +multi thread free,crate 'object-pool',,,,433164.0,ns,9690 +multi thread free,crate 'object-pool',,,,452216.0,ns,9880 +multi thread free,crate 'object-pool',,,,467712.0,ns,10070 +multi thread free,crate 'object-pool',,,,454778.0,ns,10260 +multi thread free,crate 'object-pool',,,,476318.0,ns,10450 +multi thread free,crate 'object-pool',,,,501237.0,ns,10640 +multi thread free,crate 'object-pool',,,,504961.0,ns,10830 +multi thread free,crate 'object-pool',,,,498744.0,ns,11020 +multi thread free,crate 'object-pool',,,,548619.0,ns,11210 +multi thread free,crate 'object-pool',,,,475911.0,ns,11400 +multi thread free,crate 'object-pool',,,,569664.0,ns,11590 +multi thread free,crate 'object-pool',,,,524257.0,ns,11780 +multi thread free,crate 'object-pool',,,,558298.0,ns,11970 +multi thread free,crate 'object-pool',,,,554948.0,ns,12160 +multi thread free,crate 'object-pool',,,,513623.0,ns,12350 +multi thread free,crate 'object-pool',,,,632740.0,ns,12540 +multi thread free,crate 'object-pool',,,,592822.0,ns,12730 +multi thread free,crate 'object-pool',,,,653226.0,ns,12920 +multi thread free,crate 'object-pool',,,,688243.0,ns,13110 +multi thread free,crate 'object-pool',,,,628587.0,ns,13300 +multi thread free,crate 'object-pool',,,,666024.0,ns,13490 +multi thread free,crate 'object-pool',,,,713479.0,ns,13680 +multi thread free,crate 'object-pool',,,,652061.0,ns,13870 +multi thread free,crate 'object-pool',,,,644106.0,ns,14060 +multi thread free,crate 'object-pool',,,,710554.0,ns,14250 +multi thread free,crate 'object-pool',,,,723049.0,ns,14440 +multi thread free,crate 'object-pool',,,,660528.0,ns,14630 +multi thread free,crate 'object-pool',,,,517264.0,ns,14820 +multi thread free,crate 'object-pool',,,,728166.0,ns,15010 +multi thread free,crate 'object-pool',,,,757135.0,ns,15200 +multi thread free,crate 'object-pool',,,,649633.0,ns,15390 +multi thread free,crate 'object-pool',,,,712825.0,ns,15580 +multi thread free,crate 'object-pool',,,,643438.0,ns,15770 +multi thread free,crate 'object-pool',,,,589186.0,ns,15960 +multi thread free,crate 'object-pool',,,,610730.0,ns,16150 +multi thread free,crate 'object-pool',,,,593391.0,ns,16340 +multi thread free,crate 'object-pool',,,,722660.0,ns,16530 +multi thread free,crate 'object-pool',,,,747572.0,ns,16720 +multi thread free,crate 'object-pool',,,,803289.0,ns,16910 +multi thread free,crate 'object-pool',,,,817383.0,ns,17100 +multi thread free,crate 'object-pool',,,,822876.0,ns,17290 +multi thread free,crate 'object-pool',,,,632410.0,ns,17480 +multi thread free,crate 'object-pool',,,,855490.0,ns,17670 +multi thread free,crate 'object-pool',,,,886746.0,ns,17860 +multi thread free,crate 'object-pool',,,,941300.0,ns,18050 +multi thread free,crate 'object-pool',,,,873305.0,ns,18240 +multi thread free,crate 'object-pool',,,,849013.0,ns,18430 +multi thread free,crate 'object-pool',,,,839865.0,ns,18620 +multi thread free,crate 'object-pool',,,,695579.0,ns,18810 +multi thread free,crate 'object-pool',,,,824924.0,ns,19000 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/sample.json new file mode 100644 index 0000000000000..19e58adc5af00 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[190.0,380.0,570.0,760.0,950.0,1140.0,1330.0,1520.0,1710.0,1900.0,2090.0,2280.0,2470.0,2660.0,2850.0,3040.0,3230.0,3420.0,3610.0,3800.0,3990.0,4180.0,4370.0,4560.0,4750.0,4940.0,5130.0,5320.0,5510.0,5700.0,5890.0,6080.0,6270.0,6460.0,6650.0,6840.0,7030.0,7220.0,7410.0,7600.0,7790.0,7980.0,8170.0,8360.0,8550.0,8740.0,8930.0,9120.0,9310.0,9500.0,9690.0,9880.0,10070.0,10260.0,10450.0,10640.0,10830.0,11020.0,11210.0,11400.0,11590.0,11780.0,11970.0,12160.0,12350.0,12540.0,12730.0,12920.0,13110.0,13300.0,13490.0,13680.0,13870.0,14060.0,14250.0,14440.0,14630.0,14820.0,15010.0,15200.0,15390.0,15580.0,15770.0,15960.0,16150.0,16340.0,16530.0,16720.0,16910.0,17100.0,17290.0,17480.0,17670.0,17860.0,18050.0,18240.0,18430.0,18620.0,18810.0,19000.0],"times":[24404.0,9974.0,17589.0,27984.0,36809.0,50488.0,55814.0,66577.0,71966.0,84109.0,88410.0,100213.0,108224.0,103850.0,111494.0,118310.0,118536.0,143632.0,155860.0,168089.0,172951.0,181761.0,187544.0,177255.0,206058.0,239875.0,213528.0,235995.0,221547.0,236459.0,253706.0,269791.0,284320.0,290173.0,293798.0,300074.0,302458.0,302969.0,325950.0,309560.0,337881.0,330840.0,345983.0,380465.0,392104.0,398023.0,422819.0,402453.0,416147.0,418249.0,433164.0,452216.0,467712.0,454778.0,476318.0,501237.0,504961.0,498744.0,548619.0,475911.0,569664.0,524257.0,558298.0,554948.0,513623.0,632740.0,592822.0,653226.0,688243.0,628587.0,666024.0,713479.0,652061.0,644106.0,710554.0,723049.0,660528.0,517264.0,728166.0,757135.0,649633.0,712825.0,643438.0,589186.0,610730.0,593391.0,722660.0,747572.0,803289.0,817383.0,822876.0,632410.0,855490.0,886746.0,941300.0,873305.0,849013.0,839865.0,695579.0,824924.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/tukey.json new file mode 100644 index 0000000000000..566d05d347f06 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/base/tukey.json @@ -0,0 +1 @@ +[28.0685232818889,35.029061139691315,53.59049542716442,60.551033284966834] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/benchmark.json new file mode 100644 index 0000000000000..645135189c6b0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread free","function_id":"crate 'object-pool'","value_str":null,"throughput":null,"full_id":"multi thread free/crate 'object-pool'","directory_name":"multi thread free/crate 'object-pool'","title":"multi thread free/crate 'object-pool'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/estimates.json new file mode 100644 index 0000000000000..70ede21cdfd8f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":43.288140725983176,"upper_bound":46.92830299636239},"point_estimate":44.79783491988626,"standard_error":0.9444458911054957},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":43.766736469821765,"upper_bound":45.10553168635875},"point_estimate":44.27780701754386,"standard_error":0.3084270863515177},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":2.4256619061898013,"upper_bound":4.359135201537537},"point_estimate":3.430539988957236,"standard_error":0.4772187503084713},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":43.855622628513096,"upper_bound":46.30628178865771},"point_estimate":45.11798481796333,"standard_error":0.6273439687965535},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":3.688748036286764,"upper_bound":15.324930834459042},"point_estimate":9.507328257030764,"standard_error":3.755876523209489}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/raw.csv new file mode 100644 index 0000000000000..b430d6a067a59 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread free,crate 'object-pool',,,,24404.0,ns,190 +multi thread free,crate 'object-pool',,,,9974.0,ns,380 +multi thread free,crate 'object-pool',,,,17589.0,ns,570 +multi thread free,crate 'object-pool',,,,27984.0,ns,760 +multi thread free,crate 'object-pool',,,,36809.0,ns,950 +multi thread free,crate 'object-pool',,,,50488.0,ns,1140 +multi thread free,crate 'object-pool',,,,55814.0,ns,1330 +multi thread free,crate 'object-pool',,,,66577.0,ns,1520 +multi thread free,crate 'object-pool',,,,71966.0,ns,1710 +multi thread free,crate 'object-pool',,,,84109.0,ns,1900 +multi thread free,crate 'object-pool',,,,88410.0,ns,2090 +multi thread free,crate 'object-pool',,,,100213.0,ns,2280 +multi thread free,crate 'object-pool',,,,108224.0,ns,2470 +multi thread free,crate 'object-pool',,,,103850.0,ns,2660 +multi thread free,crate 'object-pool',,,,111494.0,ns,2850 +multi thread free,crate 'object-pool',,,,118310.0,ns,3040 +multi thread free,crate 'object-pool',,,,118536.0,ns,3230 +multi thread free,crate 'object-pool',,,,143632.0,ns,3420 +multi thread free,crate 'object-pool',,,,155860.0,ns,3610 +multi thread free,crate 'object-pool',,,,168089.0,ns,3800 +multi thread free,crate 'object-pool',,,,172951.0,ns,3990 +multi thread free,crate 'object-pool',,,,181761.0,ns,4180 +multi thread free,crate 'object-pool',,,,187544.0,ns,4370 +multi thread free,crate 'object-pool',,,,177255.0,ns,4560 +multi thread free,crate 'object-pool',,,,206058.0,ns,4750 +multi thread free,crate 'object-pool',,,,239875.0,ns,4940 +multi thread free,crate 'object-pool',,,,213528.0,ns,5130 +multi thread free,crate 'object-pool',,,,235995.0,ns,5320 +multi thread free,crate 'object-pool',,,,221547.0,ns,5510 +multi thread free,crate 'object-pool',,,,236459.0,ns,5700 +multi thread free,crate 'object-pool',,,,253706.0,ns,5890 +multi thread free,crate 'object-pool',,,,269791.0,ns,6080 +multi thread free,crate 'object-pool',,,,284320.0,ns,6270 +multi thread free,crate 'object-pool',,,,290173.0,ns,6460 +multi thread free,crate 'object-pool',,,,293798.0,ns,6650 +multi thread free,crate 'object-pool',,,,300074.0,ns,6840 +multi thread free,crate 'object-pool',,,,302458.0,ns,7030 +multi thread free,crate 'object-pool',,,,302969.0,ns,7220 +multi thread free,crate 'object-pool',,,,325950.0,ns,7410 +multi thread free,crate 'object-pool',,,,309560.0,ns,7600 +multi thread free,crate 'object-pool',,,,337881.0,ns,7790 +multi thread free,crate 'object-pool',,,,330840.0,ns,7980 +multi thread free,crate 'object-pool',,,,345983.0,ns,8170 +multi thread free,crate 'object-pool',,,,380465.0,ns,8360 +multi thread free,crate 'object-pool',,,,392104.0,ns,8550 +multi thread free,crate 'object-pool',,,,398023.0,ns,8740 +multi thread free,crate 'object-pool',,,,422819.0,ns,8930 +multi thread free,crate 'object-pool',,,,402453.0,ns,9120 +multi thread free,crate 'object-pool',,,,416147.0,ns,9310 +multi thread free,crate 'object-pool',,,,418249.0,ns,9500 +multi thread free,crate 'object-pool',,,,433164.0,ns,9690 +multi thread free,crate 'object-pool',,,,452216.0,ns,9880 +multi thread free,crate 'object-pool',,,,467712.0,ns,10070 +multi thread free,crate 'object-pool',,,,454778.0,ns,10260 +multi thread free,crate 'object-pool',,,,476318.0,ns,10450 +multi thread free,crate 'object-pool',,,,501237.0,ns,10640 +multi thread free,crate 'object-pool',,,,504961.0,ns,10830 +multi thread free,crate 'object-pool',,,,498744.0,ns,11020 +multi thread free,crate 'object-pool',,,,548619.0,ns,11210 +multi thread free,crate 'object-pool',,,,475911.0,ns,11400 +multi thread free,crate 'object-pool',,,,569664.0,ns,11590 +multi thread free,crate 'object-pool',,,,524257.0,ns,11780 +multi thread free,crate 'object-pool',,,,558298.0,ns,11970 +multi thread free,crate 'object-pool',,,,554948.0,ns,12160 +multi thread free,crate 'object-pool',,,,513623.0,ns,12350 +multi thread free,crate 'object-pool',,,,632740.0,ns,12540 +multi thread free,crate 'object-pool',,,,592822.0,ns,12730 +multi thread free,crate 'object-pool',,,,653226.0,ns,12920 +multi thread free,crate 'object-pool',,,,688243.0,ns,13110 +multi thread free,crate 'object-pool',,,,628587.0,ns,13300 +multi thread free,crate 'object-pool',,,,666024.0,ns,13490 +multi thread free,crate 'object-pool',,,,713479.0,ns,13680 +multi thread free,crate 'object-pool',,,,652061.0,ns,13870 +multi thread free,crate 'object-pool',,,,644106.0,ns,14060 +multi thread free,crate 'object-pool',,,,710554.0,ns,14250 +multi thread free,crate 'object-pool',,,,723049.0,ns,14440 +multi thread free,crate 'object-pool',,,,660528.0,ns,14630 +multi thread free,crate 'object-pool',,,,517264.0,ns,14820 +multi thread free,crate 'object-pool',,,,728166.0,ns,15010 +multi thread free,crate 'object-pool',,,,757135.0,ns,15200 +multi thread free,crate 'object-pool',,,,649633.0,ns,15390 +multi thread free,crate 'object-pool',,,,712825.0,ns,15580 +multi thread free,crate 'object-pool',,,,643438.0,ns,15770 +multi thread free,crate 'object-pool',,,,589186.0,ns,15960 +multi thread free,crate 'object-pool',,,,610730.0,ns,16150 +multi thread free,crate 'object-pool',,,,593391.0,ns,16340 +multi thread free,crate 'object-pool',,,,722660.0,ns,16530 +multi thread free,crate 'object-pool',,,,747572.0,ns,16720 +multi thread free,crate 'object-pool',,,,803289.0,ns,16910 +multi thread free,crate 'object-pool',,,,817383.0,ns,17100 +multi thread free,crate 'object-pool',,,,822876.0,ns,17290 +multi thread free,crate 'object-pool',,,,632410.0,ns,17480 +multi thread free,crate 'object-pool',,,,855490.0,ns,17670 +multi thread free,crate 'object-pool',,,,886746.0,ns,17860 +multi thread free,crate 'object-pool',,,,941300.0,ns,18050 +multi thread free,crate 'object-pool',,,,873305.0,ns,18240 +multi thread free,crate 'object-pool',,,,849013.0,ns,18430 +multi thread free,crate 'object-pool',,,,839865.0,ns,18620 +multi thread free,crate 'object-pool',,,,695579.0,ns,18810 +multi thread free,crate 'object-pool',,,,824924.0,ns,19000 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/sample.json new file mode 100644 index 0000000000000..19e58adc5af00 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[190.0,380.0,570.0,760.0,950.0,1140.0,1330.0,1520.0,1710.0,1900.0,2090.0,2280.0,2470.0,2660.0,2850.0,3040.0,3230.0,3420.0,3610.0,3800.0,3990.0,4180.0,4370.0,4560.0,4750.0,4940.0,5130.0,5320.0,5510.0,5700.0,5890.0,6080.0,6270.0,6460.0,6650.0,6840.0,7030.0,7220.0,7410.0,7600.0,7790.0,7980.0,8170.0,8360.0,8550.0,8740.0,8930.0,9120.0,9310.0,9500.0,9690.0,9880.0,10070.0,10260.0,10450.0,10640.0,10830.0,11020.0,11210.0,11400.0,11590.0,11780.0,11970.0,12160.0,12350.0,12540.0,12730.0,12920.0,13110.0,13300.0,13490.0,13680.0,13870.0,14060.0,14250.0,14440.0,14630.0,14820.0,15010.0,15200.0,15390.0,15580.0,15770.0,15960.0,16150.0,16340.0,16530.0,16720.0,16910.0,17100.0,17290.0,17480.0,17670.0,17860.0,18050.0,18240.0,18430.0,18620.0,18810.0,19000.0],"times":[24404.0,9974.0,17589.0,27984.0,36809.0,50488.0,55814.0,66577.0,71966.0,84109.0,88410.0,100213.0,108224.0,103850.0,111494.0,118310.0,118536.0,143632.0,155860.0,168089.0,172951.0,181761.0,187544.0,177255.0,206058.0,239875.0,213528.0,235995.0,221547.0,236459.0,253706.0,269791.0,284320.0,290173.0,293798.0,300074.0,302458.0,302969.0,325950.0,309560.0,337881.0,330840.0,345983.0,380465.0,392104.0,398023.0,422819.0,402453.0,416147.0,418249.0,433164.0,452216.0,467712.0,454778.0,476318.0,501237.0,504961.0,498744.0,548619.0,475911.0,569664.0,524257.0,558298.0,554948.0,513623.0,632740.0,592822.0,653226.0,688243.0,628587.0,666024.0,713479.0,652061.0,644106.0,710554.0,723049.0,660528.0,517264.0,728166.0,757135.0,649633.0,712825.0,643438.0,589186.0,610730.0,593391.0,722660.0,747572.0,803289.0,817383.0,822876.0,632410.0,855490.0,886746.0,941300.0,873305.0,849013.0,839865.0,695579.0,824924.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/tukey.json new file mode 100644 index 0000000000000..566d05d347f06 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/new/tukey.json @@ -0,0 +1 @@ +[28.0685232818889,35.029061139691315,53.59049542716442,60.551033284966834] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/MAD.svg new file mode 100644 index 0000000000000..d3f379eddede6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/MAD.svg @@ -0,0 +1,283 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 1.2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 4 + + + + + 4.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'object-pool': MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/SD.svg new file mode 100644 index 0000000000000..b43076f94814c --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'object-pool': SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/index.html new file mode 100644 index 0000000000000..49b325ea7b284 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/index.html @@ -0,0 +1,203 @@ + + + + + + multi thread free/crate 'object-pool' - Criterion.rs + + + + +
+

multi thread free/crate 'object-pool'

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope43.856 ns45.118 ns46.306 ns
0.37896530.39790590.3810311
Mean43.288 ns44.798 ns46.928 ns
Std. Dev.3.6887 ns9.5073 ns15.325 ns
Median43.767 ns44.278 ns45.106 ns
MAD2.4257 ns3.4305 ns4.3591 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/mean.svg new file mode 100644 index 0000000000000..5cef2d830d80d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/mean.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 43 + + + + + 43.5 + + + + + 44 + + + + + 44.5 + + + + + 45 + + + + + 45.5 + + + + + 46 + + + + + 46.5 + + + + + 47 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'object-pool': mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/median.svg new file mode 100644 index 0000000000000..26556d5a78cff --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/median.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 43.8 + + + + + 44 + + + + + 44.2 + + + + + 44.4 + + + + + 44.6 + + + + + 44.8 + + + + + 45 + + + + + 45.2 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'object-pool': median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/pdf.svg new file mode 100644 index 0000000000000..ff1002dd3a063 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/pdf.svg @@ -0,0 +1,445 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + 40 + + + + + 60 + + + + + 80 + + + + + 100 + + + + + 120 + + + + + 140 + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 0.08 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'object-pool' + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/pdf_small.svg new file mode 100644 index 0000000000000..5c7784e934874 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/pdf_small.svg @@ -0,0 +1,219 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 20 + + + + + 40 + + + + + 60 + + + + + 80 + + + + + 100 + + + + + 120 + + + + + 140 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/regression.svg new file mode 100644 index 0000000000000..6c80153deb999 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/regression.svg @@ -0,0 +1,499 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 300 + + + + + + + + + + + + + 400 + + + + + + + + + + + + + 500 + + + + + + + + + + + + + 600 + + + + + + + + + + + + + 700 + + + + + + + + + + + + + 800 + + + + + + + + + + + + + 900 + + + + + + + + + + + + + 1000 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + multi thread free/crate 'object-pool' + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/regression_small.svg new file mode 100644 index 0000000000000..3cf528d9ba52b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/regression_small.svg @@ -0,0 +1,477 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 300 + + + + + + + + + + + + + 400 + + + + + + + + + + + + + 500 + + + + + + + + + + + + + 600 + + + + + + + + + + + + + 700 + + + + + + + + + + + + + 800 + + + + + + + + + + + + + 900 + + + + + + + + + + + + + 1000 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/slope.svg new file mode 100644 index 0000000000000..87cc8a33b6eb9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 44 + + + + + 44.5 + + + + + 45 + + + + + 45.5 + + + + + 46 + + + + + 46.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'object-pool': slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/typical.svg new file mode 100644 index 0000000000000..23059bdc23cf9 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'object-pool'/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 44 + + + + + 44.5 + + + + + 45 + + + + + 45.5 + + + + + 46 + + + + + 46.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'object-pool': typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/benchmark.json new file mode 100644 index 0000000000000..d0f01a69459fb --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread free","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"multi thread free/crate 'sharded-slab'","directory_name":"multi thread free/crate 'sharded-slab'","title":"multi thread free/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/estimates.json new file mode 100644 index 0000000000000..195b0d977bc43 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.848306626969086,"upper_bound":13.606433945626376},"point_estimate":10.282598996449563,"standard_error":1.4894537318295178},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":6.416666666666666,"upper_bound":6.726456339359565},"point_estimate":6.555671175858481,"standard_error":0.08319135454213665},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.777558262648752,"upper_bound":1.3824404845675629},"point_estimate":1.1284279746843764,"standard_error":0.15988501632872873},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":6.1395614273704515,"upper_bound":6.422942483641853},"point_estimate":6.279680994579959,"standard_error":0.0720731346523131},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":5.326838525925312,"upper_bound":23.410743902380716},"point_estimate":14.982301400568197,"standard_error":5.009916720136162}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/raw.csv new file mode 100644 index 0000000000000..8b315ea9cbc70 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread free,crate 'sharded-slab',,,,12081.0,ns,93 +multi thread free,crate 'sharded-slab',,,,12647.0,ns,186 +multi thread free,crate 'sharded-slab',,,,12457.0,ns,279 +multi thread free,crate 'sharded-slab',,,,10736.0,ns,372 +multi thread free,crate 'sharded-slab',,,,11428.0,ns,465 +multi thread free,crate 'sharded-slab',,,,20199.0,ns,558 +multi thread free,crate 'sharded-slab',,,,21029.0,ns,651 +multi thread free,crate 'sharded-slab',,,,17384.0,ns,744 +multi thread free,crate 'sharded-slab',,,,13063.0,ns,837 +multi thread free,crate 'sharded-slab',,,,10061.0,ns,930 +multi thread free,crate 'sharded-slab',,,,12637.0,ns,1023 +multi thread free,crate 'sharded-slab',,,,24506.0,ns,1116 +multi thread free,crate 'sharded-slab',,,,13753.0,ns,1209 +multi thread free,crate 'sharded-slab',,,,15475.0,ns,1302 +multi thread free,crate 'sharded-slab',,,,8803.0,ns,1395 +multi thread free,crate 'sharded-slab',,,,15107.0,ns,1488 +multi thread free,crate 'sharded-slab',,,,10512.0,ns,1581 +multi thread free,crate 'sharded-slab',,,,11941.0,ns,1674 +multi thread free,crate 'sharded-slab',,,,12370.0,ns,1767 +multi thread free,crate 'sharded-slab',,,,5630.0,ns,1860 +multi thread free,crate 'sharded-slab',,,,16377.0,ns,1953 +multi thread free,crate 'sharded-slab',,,,16376.0,ns,2046 +multi thread free,crate 'sharded-slab',,,,20176.0,ns,2139 +multi thread free,crate 'sharded-slab',,,,22770.0,ns,2232 +multi thread free,crate 'sharded-slab',,,,17337.0,ns,2325 +multi thread free,crate 'sharded-slab',,,,10623.0,ns,2418 +multi thread free,crate 'sharded-slab',,,,21282.0,ns,2511 +multi thread free,crate 'sharded-slab',,,,20010.0,ns,2604 +multi thread free,crate 'sharded-slab',,,,20729.0,ns,2697 +multi thread free,crate 'sharded-slab',,,,20899.0,ns,2790 +multi thread free,crate 'sharded-slab',,,,19458.0,ns,2883 +multi thread free,crate 'sharded-slab',,,,16160.0,ns,2976 +multi thread free,crate 'sharded-slab',,,,23194.0,ns,3069 +multi thread free,crate 'sharded-slab',,,,21327.0,ns,3162 +multi thread free,crate 'sharded-slab',,,,21429.0,ns,3255 +multi thread free,crate 'sharded-slab',,,,21601.0,ns,3348 +multi thread free,crate 'sharded-slab',,,,25907.0,ns,3441 +multi thread free,crate 'sharded-slab',,,,16179.0,ns,3534 +multi thread free,crate 'sharded-slab',,,,23391.0,ns,3627 +multi thread free,crate 'sharded-slab',,,,24225.0,ns,3720 +multi thread free,crate 'sharded-slab',,,,24289.0,ns,3813 +multi thread free,crate 'sharded-slab',,,,24999.0,ns,3906 +multi thread free,crate 'sharded-slab',,,,17611.0,ns,3999 +multi thread free,crate 'sharded-slab',,,,28614.0,ns,4092 +multi thread free,crate 'sharded-slab',,,,22570.0,ns,4185 +multi thread free,crate 'sharded-slab',,,,28892.0,ns,4278 +multi thread free,crate 'sharded-slab',,,,28954.0,ns,4371 +multi thread free,crate 'sharded-slab',,,,25200.0,ns,4464 +multi thread free,crate 'sharded-slab',,,,27763.0,ns,4557 +multi thread free,crate 'sharded-slab',,,,35920.0,ns,4650 +multi thread free,crate 'sharded-slab',,,,29685.0,ns,4743 +multi thread free,crate 'sharded-slab',,,,35747.0,ns,4836 +multi thread free,crate 'sharded-slab',,,,31629.0,ns,4929 +multi thread free,crate 'sharded-slab',,,,31230.0,ns,5022 +multi thread free,crate 'sharded-slab',,,,33318.0,ns,5115 +multi thread free,crate 'sharded-slab',,,,31710.0,ns,5208 +multi thread free,crate 'sharded-slab',,,,38748.0,ns,5301 +multi thread free,crate 'sharded-slab',,,,33347.0,ns,5394 +multi thread free,crate 'sharded-slab',,,,36667.0,ns,5487 +multi thread free,crate 'sharded-slab',,,,39367.0,ns,5580 +multi thread free,crate 'sharded-slab',,,,33618.0,ns,5673 +multi thread free,crate 'sharded-slab',,,,41414.0,ns,5766 +multi thread free,crate 'sharded-slab',,,,34580.0,ns,5859 +multi thread free,crate 'sharded-slab',,,,36282.0,ns,5952 +multi thread free,crate 'sharded-slab',,,,37183.0,ns,6045 +multi thread free,crate 'sharded-slab',,,,36136.0,ns,6138 +multi thread free,crate 'sharded-slab',,,,35849.0,ns,6231 +multi thread free,crate 'sharded-slab',,,,33000.0,ns,6324 +multi thread free,crate 'sharded-slab',,,,42506.0,ns,6417 +multi thread free,crate 'sharded-slab',,,,39040.0,ns,6510 +multi thread free,crate 'sharded-slab',,,,38836.0,ns,6603 +multi thread free,crate 'sharded-slab',,,,40084.0,ns,6696 +multi thread free,crate 'sharded-slab',,,,40170.0,ns,6789 +multi thread free,crate 'sharded-slab',,,,39319.0,ns,6882 +multi thread free,crate 'sharded-slab',,,,38462.0,ns,6975 +multi thread free,crate 'sharded-slab',,,,40541.0,ns,7068 +multi thread free,crate 'sharded-slab',,,,41024.0,ns,7161 +multi thread free,crate 'sharded-slab',,,,47117.0,ns,7254 +multi thread free,crate 'sharded-slab',,,,40646.0,ns,7347 +multi thread free,crate 'sharded-slab',,,,42843.0,ns,7440 +multi thread free,crate 'sharded-slab',,,,43596.0,ns,7533 +multi thread free,crate 'sharded-slab',,,,42238.0,ns,7626 +multi thread free,crate 'sharded-slab',,,,43974.0,ns,7719 +multi thread free,crate 'sharded-slab',,,,43283.0,ns,7812 +multi thread free,crate 'sharded-slab',,,,43356.0,ns,7905 +multi thread free,crate 'sharded-slab',,,,43597.0,ns,7998 +multi thread free,crate 'sharded-slab',,,,43761.0,ns,8091 +multi thread free,crate 'sharded-slab',,,,55448.0,ns,8184 +multi thread free,crate 'sharded-slab',,,,53638.0,ns,8277 +multi thread free,crate 'sharded-slab',,,,56146.0,ns,8370 +multi thread free,crate 'sharded-slab',,,,56926.0,ns,8463 +multi thread free,crate 'sharded-slab',,,,56120.0,ns,8556 +multi thread free,crate 'sharded-slab',,,,56670.0,ns,8649 +multi thread free,crate 'sharded-slab',,,,59199.0,ns,8742 +multi thread free,crate 'sharded-slab',,,,58254.0,ns,8835 +multi thread free,crate 'sharded-slab',,,,62241.0,ns,8928 +multi thread free,crate 'sharded-slab',,,,60027.0,ns,9021 +multi thread free,crate 'sharded-slab',,,,58632.0,ns,9114 +multi thread free,crate 'sharded-slab',,,,57355.0,ns,9207 +multi thread free,crate 'sharded-slab',,,,60110.0,ns,9300 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/sample.json new file mode 100644 index 0000000000000..84d7f8ff71321 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[93.0,186.0,279.0,372.0,465.0,558.0,651.0,744.0,837.0,930.0,1023.0,1116.0,1209.0,1302.0,1395.0,1488.0,1581.0,1674.0,1767.0,1860.0,1953.0,2046.0,2139.0,2232.0,2325.0,2418.0,2511.0,2604.0,2697.0,2790.0,2883.0,2976.0,3069.0,3162.0,3255.0,3348.0,3441.0,3534.0,3627.0,3720.0,3813.0,3906.0,3999.0,4092.0,4185.0,4278.0,4371.0,4464.0,4557.0,4650.0,4743.0,4836.0,4929.0,5022.0,5115.0,5208.0,5301.0,5394.0,5487.0,5580.0,5673.0,5766.0,5859.0,5952.0,6045.0,6138.0,6231.0,6324.0,6417.0,6510.0,6603.0,6696.0,6789.0,6882.0,6975.0,7068.0,7161.0,7254.0,7347.0,7440.0,7533.0,7626.0,7719.0,7812.0,7905.0,7998.0,8091.0,8184.0,8277.0,8370.0,8463.0,8556.0,8649.0,8742.0,8835.0,8928.0,9021.0,9114.0,9207.0,9300.0],"times":[12081.0,12647.0,12457.0,10736.0,11428.0,20199.0,21029.0,17384.0,13063.0,10061.0,12637.0,24506.0,13753.0,15475.0,8803.0,15107.0,10512.0,11941.0,12370.0,5630.0,16377.0,16376.0,20176.0,22770.0,17337.0,10623.0,21282.0,20010.0,20729.0,20899.0,19458.0,16160.0,23194.0,21327.0,21429.0,21601.0,25907.0,16179.0,23391.0,24225.0,24289.0,24999.0,17611.0,28614.0,22570.0,28892.0,28954.0,25200.0,27763.0,35920.0,29685.0,35747.0,31629.0,31230.0,33318.0,31710.0,38748.0,33347.0,36667.0,39367.0,33618.0,41414.0,34580.0,36282.0,37183.0,36136.0,35849.0,33000.0,42506.0,39040.0,38836.0,40084.0,40170.0,39319.0,38462.0,40541.0,41024.0,47117.0,40646.0,42843.0,43596.0,42238.0,43974.0,43283.0,43356.0,43597.0,43761.0,55448.0,53638.0,56146.0,56926.0,56120.0,56670.0,59199.0,58254.0,62241.0,60027.0,58632.0,57355.0,60110.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/tukey.json new file mode 100644 index 0000000000000..ea3f2280f8825 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/base/tukey.json @@ -0,0 +1 @@ +[1.1520851054324313,3.5326430993521134,9.8807977498046,12.26135574372428] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/benchmark.json new file mode 100644 index 0000000000000..d0f01a69459fb --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread free","function_id":"crate 'sharded-slab'","value_str":null,"throughput":null,"full_id":"multi thread free/crate 'sharded-slab'","directory_name":"multi thread free/crate 'sharded-slab'","title":"multi thread free/crate 'sharded-slab'"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/estimates.json new file mode 100644 index 0000000000000..195b0d977bc43 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":7.848306626969086,"upper_bound":13.606433945626376},"point_estimate":10.282598996449563,"standard_error":1.4894537318295178},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":6.416666666666666,"upper_bound":6.726456339359565},"point_estimate":6.555671175858481,"standard_error":0.08319135454213665},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.777558262648752,"upper_bound":1.3824404845675629},"point_estimate":1.1284279746843764,"standard_error":0.15988501632872873},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":6.1395614273704515,"upper_bound":6.422942483641853},"point_estimate":6.279680994579959,"standard_error":0.0720731346523131},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":5.326838525925312,"upper_bound":23.410743902380716},"point_estimate":14.982301400568197,"standard_error":5.009916720136162}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/raw.csv new file mode 100644 index 0000000000000..8b315ea9cbc70 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread free,crate 'sharded-slab',,,,12081.0,ns,93 +multi thread free,crate 'sharded-slab',,,,12647.0,ns,186 +multi thread free,crate 'sharded-slab',,,,12457.0,ns,279 +multi thread free,crate 'sharded-slab',,,,10736.0,ns,372 +multi thread free,crate 'sharded-slab',,,,11428.0,ns,465 +multi thread free,crate 'sharded-slab',,,,20199.0,ns,558 +multi thread free,crate 'sharded-slab',,,,21029.0,ns,651 +multi thread free,crate 'sharded-slab',,,,17384.0,ns,744 +multi thread free,crate 'sharded-slab',,,,13063.0,ns,837 +multi thread free,crate 'sharded-slab',,,,10061.0,ns,930 +multi thread free,crate 'sharded-slab',,,,12637.0,ns,1023 +multi thread free,crate 'sharded-slab',,,,24506.0,ns,1116 +multi thread free,crate 'sharded-slab',,,,13753.0,ns,1209 +multi thread free,crate 'sharded-slab',,,,15475.0,ns,1302 +multi thread free,crate 'sharded-slab',,,,8803.0,ns,1395 +multi thread free,crate 'sharded-slab',,,,15107.0,ns,1488 +multi thread free,crate 'sharded-slab',,,,10512.0,ns,1581 +multi thread free,crate 'sharded-slab',,,,11941.0,ns,1674 +multi thread free,crate 'sharded-slab',,,,12370.0,ns,1767 +multi thread free,crate 'sharded-slab',,,,5630.0,ns,1860 +multi thread free,crate 'sharded-slab',,,,16377.0,ns,1953 +multi thread free,crate 'sharded-slab',,,,16376.0,ns,2046 +multi thread free,crate 'sharded-slab',,,,20176.0,ns,2139 +multi thread free,crate 'sharded-slab',,,,22770.0,ns,2232 +multi thread free,crate 'sharded-slab',,,,17337.0,ns,2325 +multi thread free,crate 'sharded-slab',,,,10623.0,ns,2418 +multi thread free,crate 'sharded-slab',,,,21282.0,ns,2511 +multi thread free,crate 'sharded-slab',,,,20010.0,ns,2604 +multi thread free,crate 'sharded-slab',,,,20729.0,ns,2697 +multi thread free,crate 'sharded-slab',,,,20899.0,ns,2790 +multi thread free,crate 'sharded-slab',,,,19458.0,ns,2883 +multi thread free,crate 'sharded-slab',,,,16160.0,ns,2976 +multi thread free,crate 'sharded-slab',,,,23194.0,ns,3069 +multi thread free,crate 'sharded-slab',,,,21327.0,ns,3162 +multi thread free,crate 'sharded-slab',,,,21429.0,ns,3255 +multi thread free,crate 'sharded-slab',,,,21601.0,ns,3348 +multi thread free,crate 'sharded-slab',,,,25907.0,ns,3441 +multi thread free,crate 'sharded-slab',,,,16179.0,ns,3534 +multi thread free,crate 'sharded-slab',,,,23391.0,ns,3627 +multi thread free,crate 'sharded-slab',,,,24225.0,ns,3720 +multi thread free,crate 'sharded-slab',,,,24289.0,ns,3813 +multi thread free,crate 'sharded-slab',,,,24999.0,ns,3906 +multi thread free,crate 'sharded-slab',,,,17611.0,ns,3999 +multi thread free,crate 'sharded-slab',,,,28614.0,ns,4092 +multi thread free,crate 'sharded-slab',,,,22570.0,ns,4185 +multi thread free,crate 'sharded-slab',,,,28892.0,ns,4278 +multi thread free,crate 'sharded-slab',,,,28954.0,ns,4371 +multi thread free,crate 'sharded-slab',,,,25200.0,ns,4464 +multi thread free,crate 'sharded-slab',,,,27763.0,ns,4557 +multi thread free,crate 'sharded-slab',,,,35920.0,ns,4650 +multi thread free,crate 'sharded-slab',,,,29685.0,ns,4743 +multi thread free,crate 'sharded-slab',,,,35747.0,ns,4836 +multi thread free,crate 'sharded-slab',,,,31629.0,ns,4929 +multi thread free,crate 'sharded-slab',,,,31230.0,ns,5022 +multi thread free,crate 'sharded-slab',,,,33318.0,ns,5115 +multi thread free,crate 'sharded-slab',,,,31710.0,ns,5208 +multi thread free,crate 'sharded-slab',,,,38748.0,ns,5301 +multi thread free,crate 'sharded-slab',,,,33347.0,ns,5394 +multi thread free,crate 'sharded-slab',,,,36667.0,ns,5487 +multi thread free,crate 'sharded-slab',,,,39367.0,ns,5580 +multi thread free,crate 'sharded-slab',,,,33618.0,ns,5673 +multi thread free,crate 'sharded-slab',,,,41414.0,ns,5766 +multi thread free,crate 'sharded-slab',,,,34580.0,ns,5859 +multi thread free,crate 'sharded-slab',,,,36282.0,ns,5952 +multi thread free,crate 'sharded-slab',,,,37183.0,ns,6045 +multi thread free,crate 'sharded-slab',,,,36136.0,ns,6138 +multi thread free,crate 'sharded-slab',,,,35849.0,ns,6231 +multi thread free,crate 'sharded-slab',,,,33000.0,ns,6324 +multi thread free,crate 'sharded-slab',,,,42506.0,ns,6417 +multi thread free,crate 'sharded-slab',,,,39040.0,ns,6510 +multi thread free,crate 'sharded-slab',,,,38836.0,ns,6603 +multi thread free,crate 'sharded-slab',,,,40084.0,ns,6696 +multi thread free,crate 'sharded-slab',,,,40170.0,ns,6789 +multi thread free,crate 'sharded-slab',,,,39319.0,ns,6882 +multi thread free,crate 'sharded-slab',,,,38462.0,ns,6975 +multi thread free,crate 'sharded-slab',,,,40541.0,ns,7068 +multi thread free,crate 'sharded-slab',,,,41024.0,ns,7161 +multi thread free,crate 'sharded-slab',,,,47117.0,ns,7254 +multi thread free,crate 'sharded-slab',,,,40646.0,ns,7347 +multi thread free,crate 'sharded-slab',,,,42843.0,ns,7440 +multi thread free,crate 'sharded-slab',,,,43596.0,ns,7533 +multi thread free,crate 'sharded-slab',,,,42238.0,ns,7626 +multi thread free,crate 'sharded-slab',,,,43974.0,ns,7719 +multi thread free,crate 'sharded-slab',,,,43283.0,ns,7812 +multi thread free,crate 'sharded-slab',,,,43356.0,ns,7905 +multi thread free,crate 'sharded-slab',,,,43597.0,ns,7998 +multi thread free,crate 'sharded-slab',,,,43761.0,ns,8091 +multi thread free,crate 'sharded-slab',,,,55448.0,ns,8184 +multi thread free,crate 'sharded-slab',,,,53638.0,ns,8277 +multi thread free,crate 'sharded-slab',,,,56146.0,ns,8370 +multi thread free,crate 'sharded-slab',,,,56926.0,ns,8463 +multi thread free,crate 'sharded-slab',,,,56120.0,ns,8556 +multi thread free,crate 'sharded-slab',,,,56670.0,ns,8649 +multi thread free,crate 'sharded-slab',,,,59199.0,ns,8742 +multi thread free,crate 'sharded-slab',,,,58254.0,ns,8835 +multi thread free,crate 'sharded-slab',,,,62241.0,ns,8928 +multi thread free,crate 'sharded-slab',,,,60027.0,ns,9021 +multi thread free,crate 'sharded-slab',,,,58632.0,ns,9114 +multi thread free,crate 'sharded-slab',,,,57355.0,ns,9207 +multi thread free,crate 'sharded-slab',,,,60110.0,ns,9300 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/sample.json new file mode 100644 index 0000000000000..84d7f8ff71321 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[93.0,186.0,279.0,372.0,465.0,558.0,651.0,744.0,837.0,930.0,1023.0,1116.0,1209.0,1302.0,1395.0,1488.0,1581.0,1674.0,1767.0,1860.0,1953.0,2046.0,2139.0,2232.0,2325.0,2418.0,2511.0,2604.0,2697.0,2790.0,2883.0,2976.0,3069.0,3162.0,3255.0,3348.0,3441.0,3534.0,3627.0,3720.0,3813.0,3906.0,3999.0,4092.0,4185.0,4278.0,4371.0,4464.0,4557.0,4650.0,4743.0,4836.0,4929.0,5022.0,5115.0,5208.0,5301.0,5394.0,5487.0,5580.0,5673.0,5766.0,5859.0,5952.0,6045.0,6138.0,6231.0,6324.0,6417.0,6510.0,6603.0,6696.0,6789.0,6882.0,6975.0,7068.0,7161.0,7254.0,7347.0,7440.0,7533.0,7626.0,7719.0,7812.0,7905.0,7998.0,8091.0,8184.0,8277.0,8370.0,8463.0,8556.0,8649.0,8742.0,8835.0,8928.0,9021.0,9114.0,9207.0,9300.0],"times":[12081.0,12647.0,12457.0,10736.0,11428.0,20199.0,21029.0,17384.0,13063.0,10061.0,12637.0,24506.0,13753.0,15475.0,8803.0,15107.0,10512.0,11941.0,12370.0,5630.0,16377.0,16376.0,20176.0,22770.0,17337.0,10623.0,21282.0,20010.0,20729.0,20899.0,19458.0,16160.0,23194.0,21327.0,21429.0,21601.0,25907.0,16179.0,23391.0,24225.0,24289.0,24999.0,17611.0,28614.0,22570.0,28892.0,28954.0,25200.0,27763.0,35920.0,29685.0,35747.0,31629.0,31230.0,33318.0,31710.0,38748.0,33347.0,36667.0,39367.0,33618.0,41414.0,34580.0,36282.0,37183.0,36136.0,35849.0,33000.0,42506.0,39040.0,38836.0,40084.0,40170.0,39319.0,38462.0,40541.0,41024.0,47117.0,40646.0,42843.0,43596.0,42238.0,43974.0,43283.0,43356.0,43597.0,43761.0,55448.0,53638.0,56146.0,56926.0,56120.0,56670.0,59199.0,58254.0,62241.0,60027.0,58632.0,57355.0,60110.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/tukey.json new file mode 100644 index 0000000000000..ea3f2280f8825 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/new/tukey.json @@ -0,0 +1 @@ +[1.1520851054324313,3.5326430993521134,9.8807977498046,12.26135574372428] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/MAD.svg new file mode 100644 index 0000000000000..1e11e44bcdbb1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/MAD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 0.8 + + + + + 0.9 + + + + + 1 + + + + + 1.1 + + + + + 1.2 + + + + + 1.3 + + + + + 1.4 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'sharded-slab': MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/SD.svg new file mode 100644 index 0000000000000..e9b0295ec0f47 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/SD.svg @@ -0,0 +1,283 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 5 + + + + + 10 + + + + + 15 + + + + + 20 + + + + + 25 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'sharded-slab': SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/index.html new file mode 100644 index 0000000000000..a177760203886 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/index.html @@ -0,0 +1,203 @@ + + + + + + multi thread free/crate 'sharded-slab' - Criterion.rs + + + + +
+

multi thread free/crate 'sharded-slab'

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope6.1396 ns6.2797 ns6.4229 ns
0.21512750.21833590.2149843
Mean7.8483 ns10.283 ns13.606 ns
Std. Dev.5.3268 ns14.982 ns23.411 ns
Median6.4167 ns6.5557 ns6.7265 ns
MAD777.56 ps1.1284 ns1.3824 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/mean.svg new file mode 100644 index 0000000000000..7c89f79168f81 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 14 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'sharded-slab': mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/median.svg new file mode 100644 index 0000000000000..945902b2657d1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/median.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 6.4 + + + + + 6.45 + + + + + 6.5 + + + + + 6.55 + + + + + 6.6 + + + + + 6.65 + + + + + 6.7 + + + + + 6.75 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'sharded-slab': median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/pdf.svg new file mode 100644 index 0000000000000..421f87444a237 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/pdf.svg @@ -0,0 +1,440 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 0 + + + + + 20 + + + + + 40 + + + + + 60 + + + + + 80 + + + + + 100 + + + + + 120 + + + + + 140 + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'sharded-slab' + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/pdf_small.svg new file mode 100644 index 0000000000000..cf9b449913e60 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/pdf_small.svg @@ -0,0 +1,219 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0 + + + + + 20 + + + + + 40 + + + + + 60 + + + + + 80 + + + + + 100 + + + + + 120 + + + + + 140 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/regression.svg new file mode 100644 index 0000000000000..a0b8e9e34930a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/regression.svg @@ -0,0 +1,460 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 9 + + + + + + + + + + + + + 10 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + multi thread free/crate 'sharded-slab' + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/regression_small.svg new file mode 100644 index 0000000000000..f46601893e1dd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/regression_small.svg @@ -0,0 +1,438 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 40 + + + + + + + + + + + + + 50 + + + + + + + + + + + + + 60 + + + + + + + + + + + + + 70 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 9 + + + + + + + + + + + + + 10 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/slope.svg new file mode 100644 index 0000000000000..3ef1cbd378daf --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/slope.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 6.15 + + + + + 6.2 + + + + + 6.25 + + + + + 6.3 + + + + + 6.35 + + + + + 6.4 + + + + + 6.45 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'sharded-slab': slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/typical.svg new file mode 100644 index 0000000000000..78225bfd04015 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/crate 'sharded-slab'/report/typical.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 6.15 + + + + + 6.2 + + + + + 6.25 + + + + + 6.3 + + + + + 6.35 + + + + + 6.4 + + + + + 6.45 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/crate 'sharded-slab': typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/benchmark.json new file mode 100644 index 0000000000000..83acc3c30150a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread free","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"multi thread free/linear object poll","directory_name":"multi thread free/linear object poll","title":"multi thread free/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/estimates.json new file mode 100644 index 0000000000000..34ea02aeeb73d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":16.568768528694452,"upper_bound":82.31273177198803},"point_estimate":41.70676606243806,"standard_error":17.87306215297569},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":12.922266139657443,"upper_bound":17.469327420546932},"point_estimate":14.597456450140868,"standard_error":1.2231469012457705},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":5.75100679164486,"upper_bound":10.055843481026722},"point_estimate":7.825432456637066,"standard_error":1.0951536309998664},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":13.112823719393154,"upper_bound":16.534420986415682},"point_estimate":14.80448620981501,"standard_error":0.8703228466245219},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":9.050799977315386,"upper_bound":296.89201785114193},"point_estimate":179.94955133994517,"standard_error":83.37356015669317}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/raw.csv new file mode 100644 index 0000000000000..1f11df2ee80d8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread free,linear object poll,,,,17991.0,ns,11 +multi thread free,linear object poll,,,,17900.0,ns,22 +multi thread free,linear object poll,,,,1919.0,ns,33 +multi thread free,linear object poll,,,,3692.0,ns,44 +multi thread free,linear object poll,,,,1795.0,ns,55 +multi thread free,linear object poll,,,,1803.0,ns,66 +multi thread free,linear object poll,,,,1576.0,ns,77 +multi thread free,linear object poll,,,,2652.0,ns,88 +multi thread free,linear object poll,,,,1707.0,ns,99 +multi thread free,linear object poll,,,,2374.0,ns,110 +multi thread free,linear object poll,,,,3678.0,ns,121 +multi thread free,linear object poll,,,,2885.0,ns,132 +multi thread free,linear object poll,,,,2453.0,ns,143 +multi thread free,linear object poll,,,,4388.0,ns,154 +multi thread free,linear object poll,,,,3763.0,ns,165 +multi thread free,linear object poll,,,,8609.0,ns,176 +multi thread free,linear object poll,,,,6510.0,ns,187 +multi thread free,linear object poll,,,,3522.0,ns,198 +multi thread free,linear object poll,,,,2937.0,ns,209 +multi thread free,linear object poll,,,,3393.0,ns,220 +multi thread free,linear object poll,,,,4534.0,ns,231 +multi thread free,linear object poll,,,,3363.0,ns,242 +multi thread free,linear object poll,,,,2410.0,ns,253 +multi thread free,linear object poll,,,,1889.0,ns,264 +multi thread free,linear object poll,,,,3571.0,ns,275 +multi thread free,linear object poll,,,,2690.0,ns,286 +multi thread free,linear object poll,,,,9329.0,ns,297 +multi thread free,linear object poll,,,,3699.0,ns,308 +multi thread free,linear object poll,,,,9910.0,ns,319 +multi thread free,linear object poll,,,,9215.0,ns,330 +multi thread free,linear object poll,,,,3835.0,ns,341 +multi thread free,linear object poll,,,,3250.0,ns,352 +multi thread free,linear object poll,,,,4854.0,ns,363 +multi thread free,linear object poll,,,,4564.0,ns,374 +multi thread free,linear object poll,,,,3992.0,ns,385 +multi thread free,linear object poll,,,,2941.0,ns,396 +multi thread free,linear object poll,,,,3524.0,ns,407 +multi thread free,linear object poll,,,,3665.0,ns,418 +multi thread free,linear object poll,,,,3693.0,ns,429 +multi thread free,linear object poll,,,,3283.0,ns,440 +multi thread free,linear object poll,,,,7981.0,ns,451 +multi thread free,linear object poll,,,,10273.0,ns,462 +multi thread free,linear object poll,,,,9793.0,ns,473 +multi thread free,linear object poll,,,,9912.0,ns,484 +multi thread free,linear object poll,,,,4073.0,ns,495 +multi thread free,linear object poll,,,,4286.0,ns,506 +multi thread free,linear object poll,,,,3474.0,ns,517 +multi thread free,linear object poll,,,,13028.0,ns,528 +multi thread free,linear object poll,,,,3140.0,ns,539 +multi thread free,linear object poll,,,,3183.0,ns,550 +multi thread free,linear object poll,,,,7841.0,ns,561 +multi thread free,linear object poll,,,,10600.0,ns,572 +multi thread free,linear object poll,,,,14471.0,ns,583 +multi thread free,linear object poll,,,,9392.0,ns,594 +multi thread free,linear object poll,,,,8425.0,ns,605 +multi thread free,linear object poll,,,,13522.0,ns,616 +multi thread free,linear object poll,,,,10419.0,ns,627 +multi thread free,linear object poll,,,,9096.0,ns,638 +multi thread free,linear object poll,,,,10074.0,ns,649 +multi thread free,linear object poll,,,,10625.0,ns,660 +multi thread free,linear object poll,,,,19420.0,ns,671 +multi thread free,linear object poll,,,,8512.0,ns,682 +multi thread free,linear object poll,,,,11006.0,ns,693 +multi thread free,linear object poll,,,,20700.0,ns,704 +multi thread free,linear object poll,,,,12382.0,ns,715 +multi thread free,linear object poll,,,,4053.0,ns,726 +multi thread free,linear object poll,,,,4111.0,ns,737 +multi thread free,linear object poll,,,,9657.0,ns,748 +multi thread free,linear object poll,,,,9808.0,ns,759 +multi thread free,linear object poll,,,,9206.0,ns,770 +multi thread free,linear object poll,,,,10279.0,ns,781 +multi thread free,linear object poll,,,,10050.0,ns,792 +multi thread free,linear object poll,,,,8356.0,ns,803 +multi thread free,linear object poll,,,,9954.0,ns,814 +multi thread free,linear object poll,,,,10372.0,ns,825 +multi thread free,linear object poll,,,,8084.0,ns,836 +multi thread free,linear object poll,,,,10631.0,ns,847 +multi thread free,linear object poll,,,,20077.0,ns,858 +multi thread free,linear object poll,,,,12981.0,ns,869 +multi thread free,linear object poll,,,,22299.0,ns,880 +multi thread free,linear object poll,,,,26258.0,ns,891 +multi thread free,linear object poll,,,,9350.0,ns,902 +multi thread free,linear object poll,,,,22156.0,ns,913 +multi thread free,linear object poll,,,,12958.0,ns,924 +multi thread free,linear object poll,,,,19145.0,ns,935 +multi thread free,linear object poll,,,,20626.0,ns,946 +multi thread free,linear object poll,,,,3299.0,ns,957 +multi thread free,linear object poll,,,,10508.0,ns,968 +multi thread free,linear object poll,,,,10866.0,ns,979 +multi thread free,linear object poll,,,,10855.0,ns,990 +multi thread free,linear object poll,,,,8708.0,ns,1001 +multi thread free,linear object poll,,,,10219.0,ns,1012 +multi thread free,linear object poll,,,,10876.0,ns,1023 +multi thread free,linear object poll,,,,12950.0,ns,1034 +multi thread free,linear object poll,,,,10441.0,ns,1045 +multi thread free,linear object poll,,,,20675.0,ns,1056 +multi thread free,linear object poll,,,,19674.0,ns,1067 +multi thread free,linear object poll,,,,21323.0,ns,1078 +multi thread free,linear object poll,,,,25388.0,ns,1089 +multi thread free,linear object poll,,,,4300.0,ns,1100 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/sample.json new file mode 100644 index 0000000000000..3128e157ca7f5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[11.0,22.0,33.0,44.0,55.0,66.0,77.0,88.0,99.0,110.0,121.0,132.0,143.0,154.0,165.0,176.0,187.0,198.0,209.0,220.0,231.0,242.0,253.0,264.0,275.0,286.0,297.0,308.0,319.0,330.0,341.0,352.0,363.0,374.0,385.0,396.0,407.0,418.0,429.0,440.0,451.0,462.0,473.0,484.0,495.0,506.0,517.0,528.0,539.0,550.0,561.0,572.0,583.0,594.0,605.0,616.0,627.0,638.0,649.0,660.0,671.0,682.0,693.0,704.0,715.0,726.0,737.0,748.0,759.0,770.0,781.0,792.0,803.0,814.0,825.0,836.0,847.0,858.0,869.0,880.0,891.0,902.0,913.0,924.0,935.0,946.0,957.0,968.0,979.0,990.0,1001.0,1012.0,1023.0,1034.0,1045.0,1056.0,1067.0,1078.0,1089.0,1100.0],"times":[17991.0,17900.0,1919.0,3692.0,1795.0,1803.0,1576.0,2652.0,1707.0,2374.0,3678.0,2885.0,2453.0,4388.0,3763.0,8609.0,6510.0,3522.0,2937.0,3393.0,4534.0,3363.0,2410.0,1889.0,3571.0,2690.0,9329.0,3699.0,9910.0,9215.0,3835.0,3250.0,4854.0,4564.0,3992.0,2941.0,3524.0,3665.0,3693.0,3283.0,7981.0,10273.0,9793.0,9912.0,4073.0,4286.0,3474.0,13028.0,3140.0,3183.0,7841.0,10600.0,14471.0,9392.0,8425.0,13522.0,10419.0,9096.0,10074.0,10625.0,19420.0,8512.0,11006.0,20700.0,12382.0,4053.0,4111.0,9657.0,9808.0,9206.0,10279.0,10050.0,8356.0,9954.0,10372.0,8084.0,10631.0,20077.0,12981.0,22299.0,26258.0,9350.0,22156.0,12958.0,19145.0,20626.0,3299.0,10508.0,10866.0,10855.0,8708.0,10219.0,10876.0,12950.0,10441.0,20675.0,19674.0,21323.0,25388.0,4300.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/tukey.json new file mode 100644 index 0000000000000..4e01a340fc5e8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/base/tukey.json @@ -0,0 +1 @@ +[-23.766964393317686,-6.5959314795897885,39.19348962368461,56.36452253741251] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/benchmark.json new file mode 100644 index 0000000000000..83acc3c30150a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread free","function_id":"linear object poll","value_str":null,"throughput":null,"full_id":"multi thread free/linear object poll","directory_name":"multi thread free/linear object poll","title":"multi thread free/linear object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/estimates.json new file mode 100644 index 0000000000000..34ea02aeeb73d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":16.568768528694452,"upper_bound":82.31273177198803},"point_estimate":41.70676606243806,"standard_error":17.87306215297569},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":12.922266139657443,"upper_bound":17.469327420546932},"point_estimate":14.597456450140868,"standard_error":1.2231469012457705},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":5.75100679164486,"upper_bound":10.055843481026722},"point_estimate":7.825432456637066,"standard_error":1.0951536309998664},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":13.112823719393154,"upper_bound":16.534420986415682},"point_estimate":14.80448620981501,"standard_error":0.8703228466245219},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":9.050799977315386,"upper_bound":296.89201785114193},"point_estimate":179.94955133994517,"standard_error":83.37356015669317}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/raw.csv new file mode 100644 index 0000000000000..1f11df2ee80d8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread free,linear object poll,,,,17991.0,ns,11 +multi thread free,linear object poll,,,,17900.0,ns,22 +multi thread free,linear object poll,,,,1919.0,ns,33 +multi thread free,linear object poll,,,,3692.0,ns,44 +multi thread free,linear object poll,,,,1795.0,ns,55 +multi thread free,linear object poll,,,,1803.0,ns,66 +multi thread free,linear object poll,,,,1576.0,ns,77 +multi thread free,linear object poll,,,,2652.0,ns,88 +multi thread free,linear object poll,,,,1707.0,ns,99 +multi thread free,linear object poll,,,,2374.0,ns,110 +multi thread free,linear object poll,,,,3678.0,ns,121 +multi thread free,linear object poll,,,,2885.0,ns,132 +multi thread free,linear object poll,,,,2453.0,ns,143 +multi thread free,linear object poll,,,,4388.0,ns,154 +multi thread free,linear object poll,,,,3763.0,ns,165 +multi thread free,linear object poll,,,,8609.0,ns,176 +multi thread free,linear object poll,,,,6510.0,ns,187 +multi thread free,linear object poll,,,,3522.0,ns,198 +multi thread free,linear object poll,,,,2937.0,ns,209 +multi thread free,linear object poll,,,,3393.0,ns,220 +multi thread free,linear object poll,,,,4534.0,ns,231 +multi thread free,linear object poll,,,,3363.0,ns,242 +multi thread free,linear object poll,,,,2410.0,ns,253 +multi thread free,linear object poll,,,,1889.0,ns,264 +multi thread free,linear object poll,,,,3571.0,ns,275 +multi thread free,linear object poll,,,,2690.0,ns,286 +multi thread free,linear object poll,,,,9329.0,ns,297 +multi thread free,linear object poll,,,,3699.0,ns,308 +multi thread free,linear object poll,,,,9910.0,ns,319 +multi thread free,linear object poll,,,,9215.0,ns,330 +multi thread free,linear object poll,,,,3835.0,ns,341 +multi thread free,linear object poll,,,,3250.0,ns,352 +multi thread free,linear object poll,,,,4854.0,ns,363 +multi thread free,linear object poll,,,,4564.0,ns,374 +multi thread free,linear object poll,,,,3992.0,ns,385 +multi thread free,linear object poll,,,,2941.0,ns,396 +multi thread free,linear object poll,,,,3524.0,ns,407 +multi thread free,linear object poll,,,,3665.0,ns,418 +multi thread free,linear object poll,,,,3693.0,ns,429 +multi thread free,linear object poll,,,,3283.0,ns,440 +multi thread free,linear object poll,,,,7981.0,ns,451 +multi thread free,linear object poll,,,,10273.0,ns,462 +multi thread free,linear object poll,,,,9793.0,ns,473 +multi thread free,linear object poll,,,,9912.0,ns,484 +multi thread free,linear object poll,,,,4073.0,ns,495 +multi thread free,linear object poll,,,,4286.0,ns,506 +multi thread free,linear object poll,,,,3474.0,ns,517 +multi thread free,linear object poll,,,,13028.0,ns,528 +multi thread free,linear object poll,,,,3140.0,ns,539 +multi thread free,linear object poll,,,,3183.0,ns,550 +multi thread free,linear object poll,,,,7841.0,ns,561 +multi thread free,linear object poll,,,,10600.0,ns,572 +multi thread free,linear object poll,,,,14471.0,ns,583 +multi thread free,linear object poll,,,,9392.0,ns,594 +multi thread free,linear object poll,,,,8425.0,ns,605 +multi thread free,linear object poll,,,,13522.0,ns,616 +multi thread free,linear object poll,,,,10419.0,ns,627 +multi thread free,linear object poll,,,,9096.0,ns,638 +multi thread free,linear object poll,,,,10074.0,ns,649 +multi thread free,linear object poll,,,,10625.0,ns,660 +multi thread free,linear object poll,,,,19420.0,ns,671 +multi thread free,linear object poll,,,,8512.0,ns,682 +multi thread free,linear object poll,,,,11006.0,ns,693 +multi thread free,linear object poll,,,,20700.0,ns,704 +multi thread free,linear object poll,,,,12382.0,ns,715 +multi thread free,linear object poll,,,,4053.0,ns,726 +multi thread free,linear object poll,,,,4111.0,ns,737 +multi thread free,linear object poll,,,,9657.0,ns,748 +multi thread free,linear object poll,,,,9808.0,ns,759 +multi thread free,linear object poll,,,,9206.0,ns,770 +multi thread free,linear object poll,,,,10279.0,ns,781 +multi thread free,linear object poll,,,,10050.0,ns,792 +multi thread free,linear object poll,,,,8356.0,ns,803 +multi thread free,linear object poll,,,,9954.0,ns,814 +multi thread free,linear object poll,,,,10372.0,ns,825 +multi thread free,linear object poll,,,,8084.0,ns,836 +multi thread free,linear object poll,,,,10631.0,ns,847 +multi thread free,linear object poll,,,,20077.0,ns,858 +multi thread free,linear object poll,,,,12981.0,ns,869 +multi thread free,linear object poll,,,,22299.0,ns,880 +multi thread free,linear object poll,,,,26258.0,ns,891 +multi thread free,linear object poll,,,,9350.0,ns,902 +multi thread free,linear object poll,,,,22156.0,ns,913 +multi thread free,linear object poll,,,,12958.0,ns,924 +multi thread free,linear object poll,,,,19145.0,ns,935 +multi thread free,linear object poll,,,,20626.0,ns,946 +multi thread free,linear object poll,,,,3299.0,ns,957 +multi thread free,linear object poll,,,,10508.0,ns,968 +multi thread free,linear object poll,,,,10866.0,ns,979 +multi thread free,linear object poll,,,,10855.0,ns,990 +multi thread free,linear object poll,,,,8708.0,ns,1001 +multi thread free,linear object poll,,,,10219.0,ns,1012 +multi thread free,linear object poll,,,,10876.0,ns,1023 +multi thread free,linear object poll,,,,12950.0,ns,1034 +multi thread free,linear object poll,,,,10441.0,ns,1045 +multi thread free,linear object poll,,,,20675.0,ns,1056 +multi thread free,linear object poll,,,,19674.0,ns,1067 +multi thread free,linear object poll,,,,21323.0,ns,1078 +multi thread free,linear object poll,,,,25388.0,ns,1089 +multi thread free,linear object poll,,,,4300.0,ns,1100 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/sample.json new file mode 100644 index 0000000000000..3128e157ca7f5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[11.0,22.0,33.0,44.0,55.0,66.0,77.0,88.0,99.0,110.0,121.0,132.0,143.0,154.0,165.0,176.0,187.0,198.0,209.0,220.0,231.0,242.0,253.0,264.0,275.0,286.0,297.0,308.0,319.0,330.0,341.0,352.0,363.0,374.0,385.0,396.0,407.0,418.0,429.0,440.0,451.0,462.0,473.0,484.0,495.0,506.0,517.0,528.0,539.0,550.0,561.0,572.0,583.0,594.0,605.0,616.0,627.0,638.0,649.0,660.0,671.0,682.0,693.0,704.0,715.0,726.0,737.0,748.0,759.0,770.0,781.0,792.0,803.0,814.0,825.0,836.0,847.0,858.0,869.0,880.0,891.0,902.0,913.0,924.0,935.0,946.0,957.0,968.0,979.0,990.0,1001.0,1012.0,1023.0,1034.0,1045.0,1056.0,1067.0,1078.0,1089.0,1100.0],"times":[17991.0,17900.0,1919.0,3692.0,1795.0,1803.0,1576.0,2652.0,1707.0,2374.0,3678.0,2885.0,2453.0,4388.0,3763.0,8609.0,6510.0,3522.0,2937.0,3393.0,4534.0,3363.0,2410.0,1889.0,3571.0,2690.0,9329.0,3699.0,9910.0,9215.0,3835.0,3250.0,4854.0,4564.0,3992.0,2941.0,3524.0,3665.0,3693.0,3283.0,7981.0,10273.0,9793.0,9912.0,4073.0,4286.0,3474.0,13028.0,3140.0,3183.0,7841.0,10600.0,14471.0,9392.0,8425.0,13522.0,10419.0,9096.0,10074.0,10625.0,19420.0,8512.0,11006.0,20700.0,12382.0,4053.0,4111.0,9657.0,9808.0,9206.0,10279.0,10050.0,8356.0,9954.0,10372.0,8084.0,10631.0,20077.0,12981.0,22299.0,26258.0,9350.0,22156.0,12958.0,19145.0,20626.0,3299.0,10508.0,10866.0,10855.0,8708.0,10219.0,10876.0,12950.0,10441.0,20675.0,19674.0,21323.0,25388.0,4300.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/tukey.json new file mode 100644 index 0000000000000..4e01a340fc5e8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/new/tukey.json @@ -0,0 +1 @@ +[-23.766964393317686,-6.5959314795897885,39.19348962368461,56.36452253741251] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/MAD.svg new file mode 100644 index 0000000000000..4cf18191fa358 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/MAD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/linear object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/SD.svg new file mode 100644 index 0000000000000..699d3aa99b08e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/SD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 0 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 250 + + + + + 300 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/linear object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/index.html new file mode 100644 index 0000000000000..86b4a537a4445 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + multi thread free/linear object poll - Criterion.rs + + + + +
+

multi thread free/linear object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope13.113 ns14.804 ns16.534 ns
0.00789330.00827120.0078768
Mean16.569 ns41.707 ns82.313 ns
Std. Dev.9.0508 ns179.95 ns296.89 ns
Median12.922 ns14.597 ns17.469 ns
MAD5.7510 ns7.8254 ns10.056 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/mean.svg new file mode 100644 index 0000000000000..9789a8d19dcf8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/mean.svg @@ -0,0 +1,308 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 0.04 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + 60 + + + + + 70 + + + + + 80 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/linear object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/median.svg new file mode 100644 index 0000000000000..945ab0edfaa9e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/median.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 0.9 + + + + + 13 + + + + + 14 + + + + + 15 + + + + + 16 + + + + + 17 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/linear object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/pdf.svg new file mode 100644 index 0000000000000..5c227cda5292b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/pdf.svg @@ -0,0 +1,400 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.2 + + + + + 0.4 + + + + + 0.6 + + + + + 0.8 + + + + + 1 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (us) + + + + + multi thread free/linear object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..8bb97cc6edbcd --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/pdf_small.svg @@ -0,0 +1,194 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + + + + + Density (a.u.) + + + + + Average time (us) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/regression.svg new file mode 100644 index 0000000000000..09eb8722cc520 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/regression.svg @@ -0,0 +1,395 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.2 + + + + + + + + + + + + + 0.4 + + + + + + + + + + + + + 0.6 + + + + + + + + + + + + + 0.8 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.2 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + multi thread free/linear object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/regression_small.svg new file mode 100644 index 0000000000000..dd4b91ed0e263 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/regression_small.svg @@ -0,0 +1,373 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + + + + + + + + + + 20 + + + + + + + + + + + + + 25 + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.2 + + + + + + + + + + + + + 0.4 + + + + + + + + + + + + + 0.6 + + + + + + + + + + + + + 0.8 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.2 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/slope.svg new file mode 100644 index 0000000000000..bdce58d89ee2a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/slope.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 0.5 + + + + + 13 + + + + + 13.5 + + + + + 14 + + + + + 14.5 + + + + + 15 + + + + + 15.5 + + + + + 16 + + + + + 16.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/linear object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/typical.svg new file mode 100644 index 0000000000000..f0792b04f28a7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/linear object poll/report/typical.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 0.5 + + + + + 13 + + + + + 13.5 + + + + + 14 + + + + + 14.5 + + + + + 15 + + + + + 15.5 + + + + + 16 + + + + + 16.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/linear object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/benchmark.json new file mode 100644 index 0000000000000..a67b513d36afc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread free","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"multi thread free/mutex object poll","directory_name":"multi thread free/mutex object poll","title":"multi thread free/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/estimates.json new file mode 100644 index 0000000000000..66252b9bc413f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":99.91326523122909,"upper_bound":104.09116631368788},"point_estimate":101.86057610235693,"standard_error":1.0642652796263734},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":100.31241640930867,"upper_bound":103.22107519141417},"point_estimate":102.00892806530243,"standard_error":0.7875633868233824},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":4.756031737597463,"upper_bound":8.032460508316117},"point_estimate":6.89723097924459,"standard_error":0.8537190194829055},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":97.39190873422537,"upper_bound":101.1845318833791},"point_estimate":99.33697389875593,"standard_error":0.9733534620666945},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":6.764685020486,"upper_bound":15.049977765321314},"point_estimate":10.723445325770578,"standard_error":2.2725853756947743}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/raw.csv new file mode 100644 index 0000000000000..c951d5f1d97e1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread free,mutex object poll,,,,10114.0,ns,59 +multi thread free,mutex object poll,,,,15603.0,ns,118 +multi thread free,mutex object poll,,,,21893.0,ns,177 +multi thread free,mutex object poll,,,,26710.0,ns,236 +multi thread free,mutex object poll,,,,32945.0,ns,295 +multi thread free,mutex object poll,,,,38391.0,ns,354 +multi thread free,mutex object poll,,,,45310.0,ns,413 +multi thread free,mutex object poll,,,,50520.0,ns,472 +multi thread free,mutex object poll,,,,56953.0,ns,531 +multi thread free,mutex object poll,,,,56922.0,ns,590 +multi thread free,mutex object poll,,,,75688.0,ns,649 +multi thread free,mutex object poll,,,,74407.0,ns,708 +multi thread free,mutex object poll,,,,78129.0,ns,767 +multi thread free,mutex object poll,,,,79722.0,ns,826 +multi thread free,mutex object poll,,,,86108.0,ns,885 +multi thread free,mutex object poll,,,,98202.0,ns,944 +multi thread free,mutex object poll,,,,94959.0,ns,1003 +multi thread free,mutex object poll,,,,115881.0,ns,1062 +multi thread free,mutex object poll,,,,111057.0,ns,1121 +multi thread free,mutex object poll,,,,113001.0,ns,1180 +multi thread free,mutex object poll,,,,116415.0,ns,1239 +multi thread free,mutex object poll,,,,136376.0,ns,1298 +multi thread free,mutex object poll,,,,138624.0,ns,1357 +multi thread free,mutex object poll,,,,147254.0,ns,1416 +multi thread free,mutex object poll,,,,136764.0,ns,1475 +multi thread free,mutex object poll,,,,157483.0,ns,1534 +multi thread free,mutex object poll,,,,173691.0,ns,1593 +multi thread free,mutex object poll,,,,167109.0,ns,1652 +multi thread free,mutex object poll,,,,179343.0,ns,1711 +multi thread free,mutex object poll,,,,198913.0,ns,1770 +multi thread free,mutex object poll,,,,180429.0,ns,1829 +multi thread free,mutex object poll,,,,182404.0,ns,1888 +multi thread free,mutex object poll,,,,173445.0,ns,1947 +multi thread free,mutex object poll,,,,217443.0,ns,2006 +multi thread free,mutex object poll,,,,212275.0,ns,2065 +multi thread free,mutex object poll,,,,214430.0,ns,2124 +multi thread free,mutex object poll,,,,225838.0,ns,2183 +multi thread free,mutex object poll,,,,229095.0,ns,2242 +multi thread free,mutex object poll,,,,232882.0,ns,2301 +multi thread free,mutex object poll,,,,223328.0,ns,2360 +multi thread free,mutex object poll,,,,241511.0,ns,2419 +multi thread free,mutex object poll,,,,255207.0,ns,2478 +multi thread free,mutex object poll,,,,239118.0,ns,2537 +multi thread free,mutex object poll,,,,279295.0,ns,2596 +multi thread free,mutex object poll,,,,269602.0,ns,2655 +multi thread free,mutex object poll,,,,268971.0,ns,2714 +multi thread free,mutex object poll,,,,274885.0,ns,2773 +multi thread free,mutex object poll,,,,317578.0,ns,2832 +multi thread free,mutex object poll,,,,285385.0,ns,2891 +multi thread free,mutex object poll,,,,303773.0,ns,2950 +multi thread free,mutex object poll,,,,303264.0,ns,3009 +multi thread free,mutex object poll,,,,298288.0,ns,3068 +multi thread free,mutex object poll,,,,297883.0,ns,3127 +multi thread free,mutex object poll,,,,230967.0,ns,3186 +multi thread free,mutex object poll,,,,342261.0,ns,3245 +multi thread free,mutex object poll,,,,334333.0,ns,3304 +multi thread free,mutex object poll,,,,300549.0,ns,3363 +multi thread free,mutex object poll,,,,356731.0,ns,3422 +multi thread free,mutex object poll,,,,346299.0,ns,3481 +multi thread free,mutex object poll,,,,377369.0,ns,3540 +multi thread free,mutex object poll,,,,321072.0,ns,3599 +multi thread free,mutex object poll,,,,360898.0,ns,3658 +multi thread free,mutex object poll,,,,385874.0,ns,3717 +multi thread free,mutex object poll,,,,378868.0,ns,3776 +multi thread free,mutex object poll,,,,397790.0,ns,3835 +multi thread free,mutex object poll,,,,407511.0,ns,3894 +multi thread free,mutex object poll,,,,420045.0,ns,3953 +multi thread free,mutex object poll,,,,429370.0,ns,4012 +multi thread free,mutex object poll,,,,428015.0,ns,4071 +multi thread free,mutex object poll,,,,418515.0,ns,4130 +multi thread free,mutex object poll,,,,348905.0,ns,4189 +multi thread free,mutex object poll,,,,417899.0,ns,4248 +multi thread free,mutex object poll,,,,462367.0,ns,4307 +multi thread free,mutex object poll,,,,449515.0,ns,4366 +multi thread free,mutex object poll,,,,440578.0,ns,4425 +multi thread free,mutex object poll,,,,375267.0,ns,4484 +multi thread free,mutex object poll,,,,440327.0,ns,4543 +multi thread free,mutex object poll,,,,481550.0,ns,4602 +multi thread free,mutex object poll,,,,476777.0,ns,4661 +multi thread free,mutex object poll,,,,462313.0,ns,4720 +multi thread free,mutex object poll,,,,460890.0,ns,4779 +multi thread free,mutex object poll,,,,433726.0,ns,4838 +multi thread free,mutex object poll,,,,417809.0,ns,4897 +multi thread free,mutex object poll,,,,519761.0,ns,4956 +multi thread free,mutex object poll,,,,481448.0,ns,5015 +multi thread free,mutex object poll,,,,448770.0,ns,5074 +multi thread free,mutex object poll,,,,492341.0,ns,5133 +multi thread free,mutex object poll,,,,501415.0,ns,5192 +multi thread free,mutex object poll,,,,562628.0,ns,5251 +multi thread free,mutex object poll,,,,555770.0,ns,5310 +multi thread free,mutex object poll,,,,560904.0,ns,5369 +multi thread free,mutex object poll,,,,490792.0,ns,5428 +multi thread free,mutex object poll,,,,595588.0,ns,5487 +multi thread free,mutex object poll,,,,584781.0,ns,5546 +multi thread free,mutex object poll,,,,606109.0,ns,5605 +multi thread free,mutex object poll,,,,583975.0,ns,5664 +multi thread free,mutex object poll,,,,547764.0,ns,5723 +multi thread free,mutex object poll,,,,594490.0,ns,5782 +multi thread free,mutex object poll,,,,504268.0,ns,5841 +multi thread free,mutex object poll,,,,598090.0,ns,5900 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/sample.json new file mode 100644 index 0000000000000..df2ab6e8c23ce --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[59.0,118.0,177.0,236.0,295.0,354.0,413.0,472.0,531.0,590.0,649.0,708.0,767.0,826.0,885.0,944.0,1003.0,1062.0,1121.0,1180.0,1239.0,1298.0,1357.0,1416.0,1475.0,1534.0,1593.0,1652.0,1711.0,1770.0,1829.0,1888.0,1947.0,2006.0,2065.0,2124.0,2183.0,2242.0,2301.0,2360.0,2419.0,2478.0,2537.0,2596.0,2655.0,2714.0,2773.0,2832.0,2891.0,2950.0,3009.0,3068.0,3127.0,3186.0,3245.0,3304.0,3363.0,3422.0,3481.0,3540.0,3599.0,3658.0,3717.0,3776.0,3835.0,3894.0,3953.0,4012.0,4071.0,4130.0,4189.0,4248.0,4307.0,4366.0,4425.0,4484.0,4543.0,4602.0,4661.0,4720.0,4779.0,4838.0,4897.0,4956.0,5015.0,5074.0,5133.0,5192.0,5251.0,5310.0,5369.0,5428.0,5487.0,5546.0,5605.0,5664.0,5723.0,5782.0,5841.0,5900.0],"times":[10114.0,15603.0,21893.0,26710.0,32945.0,38391.0,45310.0,50520.0,56953.0,56922.0,75688.0,74407.0,78129.0,79722.0,86108.0,98202.0,94959.0,115881.0,111057.0,113001.0,116415.0,136376.0,138624.0,147254.0,136764.0,157483.0,173691.0,167109.0,179343.0,198913.0,180429.0,182404.0,173445.0,217443.0,212275.0,214430.0,225838.0,229095.0,232882.0,223328.0,241511.0,255207.0,239118.0,279295.0,269602.0,268971.0,274885.0,317578.0,285385.0,303773.0,303264.0,298288.0,297883.0,230967.0,342261.0,334333.0,300549.0,356731.0,346299.0,377369.0,321072.0,360898.0,385874.0,378868.0,397790.0,407511.0,420045.0,429370.0,428015.0,418515.0,348905.0,417899.0,462367.0,449515.0,440578.0,375267.0,440327.0,481550.0,476777.0,462313.0,460890.0,433726.0,417809.0,519761.0,481448.0,448770.0,492341.0,501415.0,562628.0,555770.0,560904.0,490792.0,595588.0,584781.0,606109.0,583975.0,547764.0,594490.0,504268.0,598090.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/tukey.json new file mode 100644 index 0000000000000..5c44b0ff9cf7f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/base/tukey.json @@ -0,0 +1 @@ +[70.77044079057086,83.68664566493104,118.12985866322484,131.046063537585] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/benchmark.json new file mode 100644 index 0000000000000..a67b513d36afc --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread free","function_id":"mutex object poll","value_str":null,"throughput":null,"full_id":"multi thread free/mutex object poll","directory_name":"multi thread free/mutex object poll","title":"multi thread free/mutex object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/estimates.json new file mode 100644 index 0000000000000..66252b9bc413f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":99.91326523122909,"upper_bound":104.09116631368788},"point_estimate":101.86057610235693,"standard_error":1.0642652796263734},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":100.31241640930867,"upper_bound":103.22107519141417},"point_estimate":102.00892806530243,"standard_error":0.7875633868233824},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":4.756031737597463,"upper_bound":8.032460508316117},"point_estimate":6.89723097924459,"standard_error":0.8537190194829055},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":97.39190873422537,"upper_bound":101.1845318833791},"point_estimate":99.33697389875593,"standard_error":0.9733534620666945},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":6.764685020486,"upper_bound":15.049977765321314},"point_estimate":10.723445325770578,"standard_error":2.2725853756947743}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/raw.csv new file mode 100644 index 0000000000000..c951d5f1d97e1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread free,mutex object poll,,,,10114.0,ns,59 +multi thread free,mutex object poll,,,,15603.0,ns,118 +multi thread free,mutex object poll,,,,21893.0,ns,177 +multi thread free,mutex object poll,,,,26710.0,ns,236 +multi thread free,mutex object poll,,,,32945.0,ns,295 +multi thread free,mutex object poll,,,,38391.0,ns,354 +multi thread free,mutex object poll,,,,45310.0,ns,413 +multi thread free,mutex object poll,,,,50520.0,ns,472 +multi thread free,mutex object poll,,,,56953.0,ns,531 +multi thread free,mutex object poll,,,,56922.0,ns,590 +multi thread free,mutex object poll,,,,75688.0,ns,649 +multi thread free,mutex object poll,,,,74407.0,ns,708 +multi thread free,mutex object poll,,,,78129.0,ns,767 +multi thread free,mutex object poll,,,,79722.0,ns,826 +multi thread free,mutex object poll,,,,86108.0,ns,885 +multi thread free,mutex object poll,,,,98202.0,ns,944 +multi thread free,mutex object poll,,,,94959.0,ns,1003 +multi thread free,mutex object poll,,,,115881.0,ns,1062 +multi thread free,mutex object poll,,,,111057.0,ns,1121 +multi thread free,mutex object poll,,,,113001.0,ns,1180 +multi thread free,mutex object poll,,,,116415.0,ns,1239 +multi thread free,mutex object poll,,,,136376.0,ns,1298 +multi thread free,mutex object poll,,,,138624.0,ns,1357 +multi thread free,mutex object poll,,,,147254.0,ns,1416 +multi thread free,mutex object poll,,,,136764.0,ns,1475 +multi thread free,mutex object poll,,,,157483.0,ns,1534 +multi thread free,mutex object poll,,,,173691.0,ns,1593 +multi thread free,mutex object poll,,,,167109.0,ns,1652 +multi thread free,mutex object poll,,,,179343.0,ns,1711 +multi thread free,mutex object poll,,,,198913.0,ns,1770 +multi thread free,mutex object poll,,,,180429.0,ns,1829 +multi thread free,mutex object poll,,,,182404.0,ns,1888 +multi thread free,mutex object poll,,,,173445.0,ns,1947 +multi thread free,mutex object poll,,,,217443.0,ns,2006 +multi thread free,mutex object poll,,,,212275.0,ns,2065 +multi thread free,mutex object poll,,,,214430.0,ns,2124 +multi thread free,mutex object poll,,,,225838.0,ns,2183 +multi thread free,mutex object poll,,,,229095.0,ns,2242 +multi thread free,mutex object poll,,,,232882.0,ns,2301 +multi thread free,mutex object poll,,,,223328.0,ns,2360 +multi thread free,mutex object poll,,,,241511.0,ns,2419 +multi thread free,mutex object poll,,,,255207.0,ns,2478 +multi thread free,mutex object poll,,,,239118.0,ns,2537 +multi thread free,mutex object poll,,,,279295.0,ns,2596 +multi thread free,mutex object poll,,,,269602.0,ns,2655 +multi thread free,mutex object poll,,,,268971.0,ns,2714 +multi thread free,mutex object poll,,,,274885.0,ns,2773 +multi thread free,mutex object poll,,,,317578.0,ns,2832 +multi thread free,mutex object poll,,,,285385.0,ns,2891 +multi thread free,mutex object poll,,,,303773.0,ns,2950 +multi thread free,mutex object poll,,,,303264.0,ns,3009 +multi thread free,mutex object poll,,,,298288.0,ns,3068 +multi thread free,mutex object poll,,,,297883.0,ns,3127 +multi thread free,mutex object poll,,,,230967.0,ns,3186 +multi thread free,mutex object poll,,,,342261.0,ns,3245 +multi thread free,mutex object poll,,,,334333.0,ns,3304 +multi thread free,mutex object poll,,,,300549.0,ns,3363 +multi thread free,mutex object poll,,,,356731.0,ns,3422 +multi thread free,mutex object poll,,,,346299.0,ns,3481 +multi thread free,mutex object poll,,,,377369.0,ns,3540 +multi thread free,mutex object poll,,,,321072.0,ns,3599 +multi thread free,mutex object poll,,,,360898.0,ns,3658 +multi thread free,mutex object poll,,,,385874.0,ns,3717 +multi thread free,mutex object poll,,,,378868.0,ns,3776 +multi thread free,mutex object poll,,,,397790.0,ns,3835 +multi thread free,mutex object poll,,,,407511.0,ns,3894 +multi thread free,mutex object poll,,,,420045.0,ns,3953 +multi thread free,mutex object poll,,,,429370.0,ns,4012 +multi thread free,mutex object poll,,,,428015.0,ns,4071 +multi thread free,mutex object poll,,,,418515.0,ns,4130 +multi thread free,mutex object poll,,,,348905.0,ns,4189 +multi thread free,mutex object poll,,,,417899.0,ns,4248 +multi thread free,mutex object poll,,,,462367.0,ns,4307 +multi thread free,mutex object poll,,,,449515.0,ns,4366 +multi thread free,mutex object poll,,,,440578.0,ns,4425 +multi thread free,mutex object poll,,,,375267.0,ns,4484 +multi thread free,mutex object poll,,,,440327.0,ns,4543 +multi thread free,mutex object poll,,,,481550.0,ns,4602 +multi thread free,mutex object poll,,,,476777.0,ns,4661 +multi thread free,mutex object poll,,,,462313.0,ns,4720 +multi thread free,mutex object poll,,,,460890.0,ns,4779 +multi thread free,mutex object poll,,,,433726.0,ns,4838 +multi thread free,mutex object poll,,,,417809.0,ns,4897 +multi thread free,mutex object poll,,,,519761.0,ns,4956 +multi thread free,mutex object poll,,,,481448.0,ns,5015 +multi thread free,mutex object poll,,,,448770.0,ns,5074 +multi thread free,mutex object poll,,,,492341.0,ns,5133 +multi thread free,mutex object poll,,,,501415.0,ns,5192 +multi thread free,mutex object poll,,,,562628.0,ns,5251 +multi thread free,mutex object poll,,,,555770.0,ns,5310 +multi thread free,mutex object poll,,,,560904.0,ns,5369 +multi thread free,mutex object poll,,,,490792.0,ns,5428 +multi thread free,mutex object poll,,,,595588.0,ns,5487 +multi thread free,mutex object poll,,,,584781.0,ns,5546 +multi thread free,mutex object poll,,,,606109.0,ns,5605 +multi thread free,mutex object poll,,,,583975.0,ns,5664 +multi thread free,mutex object poll,,,,547764.0,ns,5723 +multi thread free,mutex object poll,,,,594490.0,ns,5782 +multi thread free,mutex object poll,,,,504268.0,ns,5841 +multi thread free,mutex object poll,,,,598090.0,ns,5900 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/sample.json new file mode 100644 index 0000000000000..df2ab6e8c23ce --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[59.0,118.0,177.0,236.0,295.0,354.0,413.0,472.0,531.0,590.0,649.0,708.0,767.0,826.0,885.0,944.0,1003.0,1062.0,1121.0,1180.0,1239.0,1298.0,1357.0,1416.0,1475.0,1534.0,1593.0,1652.0,1711.0,1770.0,1829.0,1888.0,1947.0,2006.0,2065.0,2124.0,2183.0,2242.0,2301.0,2360.0,2419.0,2478.0,2537.0,2596.0,2655.0,2714.0,2773.0,2832.0,2891.0,2950.0,3009.0,3068.0,3127.0,3186.0,3245.0,3304.0,3363.0,3422.0,3481.0,3540.0,3599.0,3658.0,3717.0,3776.0,3835.0,3894.0,3953.0,4012.0,4071.0,4130.0,4189.0,4248.0,4307.0,4366.0,4425.0,4484.0,4543.0,4602.0,4661.0,4720.0,4779.0,4838.0,4897.0,4956.0,5015.0,5074.0,5133.0,5192.0,5251.0,5310.0,5369.0,5428.0,5487.0,5546.0,5605.0,5664.0,5723.0,5782.0,5841.0,5900.0],"times":[10114.0,15603.0,21893.0,26710.0,32945.0,38391.0,45310.0,50520.0,56953.0,56922.0,75688.0,74407.0,78129.0,79722.0,86108.0,98202.0,94959.0,115881.0,111057.0,113001.0,116415.0,136376.0,138624.0,147254.0,136764.0,157483.0,173691.0,167109.0,179343.0,198913.0,180429.0,182404.0,173445.0,217443.0,212275.0,214430.0,225838.0,229095.0,232882.0,223328.0,241511.0,255207.0,239118.0,279295.0,269602.0,268971.0,274885.0,317578.0,285385.0,303773.0,303264.0,298288.0,297883.0,230967.0,342261.0,334333.0,300549.0,356731.0,346299.0,377369.0,321072.0,360898.0,385874.0,378868.0,397790.0,407511.0,420045.0,429370.0,428015.0,418515.0,348905.0,417899.0,462367.0,449515.0,440578.0,375267.0,440327.0,481550.0,476777.0,462313.0,460890.0,433726.0,417809.0,519761.0,481448.0,448770.0,492341.0,501415.0,562628.0,555770.0,560904.0,490792.0,595588.0,584781.0,606109.0,583975.0,547764.0,594490.0,504268.0,598090.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/tukey.json new file mode 100644 index 0000000000000..5c44b0ff9cf7f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/new/tukey.json @@ -0,0 +1 @@ +[70.77044079057086,83.68664566493104,118.12985866322484,131.046063537585] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/MAD.svg new file mode 100644 index 0000000000000..22a359b0ea8ab --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/MAD.svg @@ -0,0 +1,318 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 0.5 + + + + + 4.5 + + + + + 5 + + + + + 5.5 + + + + + 6 + + + + + 6.5 + + + + + 7 + + + + + 7.5 + + + + + 8 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/mutex object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/SD.svg new file mode 100644 index 0000000000000..49a53464c5eb0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/SD.svg @@ -0,0 +1,278 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/mutex object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/index.html new file mode 100644 index 0000000000000..cbbcf50b16064 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + multi thread free/mutex object poll - Criterion.rs + + + + +
+

multi thread free/mutex object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope97.392 ns99.337 ns101.18 ns
0.57696570.59379880.5785689
Mean99.913 ns101.86 ns104.09 ns
Std. Dev.6.7647 ns10.723 ns15.050 ns
Median100.31 ns102.01 ns103.22 ns
MAD4.7560 ns6.8972 ns8.0325 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/mean.svg new file mode 100644 index 0000000000000..d19cd027906df --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/mean.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 100 + + + + + 101 + + + + + 102 + + + + + 103 + + + + + 104 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/mutex object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/median.svg new file mode 100644 index 0000000000000..34044a17d04f1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/median.svg @@ -0,0 +1,308 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 100 + + + + + 100.5 + + + + + 101 + + + + + 101.5 + + + + + 102 + + + + + 102.5 + + + + + 103 + + + + + 103.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/mutex object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/pdf.svg new file mode 100644 index 0000000000000..5b3ff008427c6 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/pdf.svg @@ -0,0 +1,415 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 60 + + + + + 80 + + + + + 100 + + + + + 120 + + + + + 140 + + + + + 160 + + + + + 180 + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/mutex object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..47ab239d976b7 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/pdf_small.svg @@ -0,0 +1,209 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 60 + + + + + 80 + + + + + 100 + + + + + 120 + + + + + 140 + + + + + 160 + + + + + 180 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/regression.svg new file mode 100644 index 0000000000000..c220e81cf40ea --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/regression.svg @@ -0,0 +1,408 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 300 + + + + + + + + + + + + + 400 + + + + + + + + + + + + + 500 + + + + + + + + + + + + + 600 + + + + + + + + + + + + + 700 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + multi thread free/mutex object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/regression_small.svg new file mode 100644 index 0000000000000..879d89ec8bf20 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/regression_small.svg @@ -0,0 +1,386 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 300 + + + + + + + + + + + + + 400 + + + + + + + + + + + + + 500 + + + + + + + + + + + + + 600 + + + + + + + + + + + + + 700 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/slope.svg new file mode 100644 index 0000000000000..9e79ef5341675 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/slope.svg @@ -0,0 +1,323 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 97 + + + + + 97.5 + + + + + 98 + + + + + 98.5 + + + + + 99 + + + + + 99.5 + + + + + 100 + + + + + 100.5 + + + + + 101 + + + + + 101.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/mutex object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/typical.svg new file mode 100644 index 0000000000000..f5274f9e64ea4 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/mutex object poll/report/typical.svg @@ -0,0 +1,323 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 0.3 + + + + + 0.35 + + + + + 0.4 + + + + + 0.45 + + + + + 97 + + + + + 97.5 + + + + + 98 + + + + + 98.5 + + + + + 99 + + + + + 99.5 + + + + + 100 + + + + + 100.5 + + + + + 101 + + + + + 101.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/mutex object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/benchmark.json new file mode 100644 index 0000000000000..1bf8e9e8db356 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread free","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"multi thread free/none object poll","directory_name":"multi thread free/none object poll","title":"multi thread free/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/estimates.json new file mode 100644 index 0000000000000..ccd3c5652301a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":85.49596765781351,"upper_bound":101.5529560632594},"point_estimate":93.58534199979576,"standard_error":4.102466781628311},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":83.87995858665963,"upper_bound":115.28061592037056},"point_estimate":94.36605684186807,"standard_error":8.983267925688745},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":35.98390688546617,"upper_bound":63.96569690723438},"point_estimate":57.09984978290107,"standard_error":7.7970233841065},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":119.73590465630548,"upper_bound":128.04203016918848},"point_estimate":124.3863350949651,"standard_error":2.1194745578782554},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":37.58117553580864,"upper_bound":44.30243005086328},"point_estimate":41.27780199825228,"standard_error":1.7081100562311557}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/raw.csv new file mode 100644 index 0000000000000..1f594b21a6736 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread free,none object poll,,,,17987.0,ns,194 +multi thread free,none object poll,,,,9790.0,ns,388 +multi thread free,none object poll,,,,15231.0,ns,582 +multi thread free,none object poll,,,,18766.0,ns,776 +multi thread free,none object poll,,,,24355.0,ns,970 +multi thread free,none object poll,,,,28755.0,ns,1164 +multi thread free,none object poll,,,,37640.0,ns,1358 +multi thread free,none object poll,,,,44637.0,ns,1552 +multi thread free,none object poll,,,,40626.0,ns,1746 +multi thread free,none object poll,,,,51022.0,ns,1940 +multi thread free,none object poll,,,,60995.0,ns,2134 +multi thread free,none object poll,,,,67037.0,ns,2328 +multi thread free,none object poll,,,,75681.0,ns,2522 +multi thread free,none object poll,,,,92471.0,ns,2716 +multi thread free,none object poll,,,,82391.0,ns,2910 +multi thread free,none object poll,,,,432340.0,ns,3104 +multi thread free,none object poll,,,,264257.0,ns,3298 +multi thread free,none object poll,,,,264502.0,ns,3492 +multi thread free,none object poll,,,,219819.0,ns,3686 +multi thread free,none object poll,,,,206751.0,ns,3880 +multi thread free,none object poll,,,,239562.0,ns,4074 +multi thread free,none object poll,,,,242435.0,ns,4268 +multi thread free,none object poll,,,,262129.0,ns,4462 +multi thread free,none object poll,,,,262090.0,ns,4656 +multi thread free,none object poll,,,,273935.0,ns,4850 +multi thread free,none object poll,,,,280239.0,ns,5044 +multi thread free,none object poll,,,,288728.0,ns,5238 +multi thread free,none object poll,,,,312178.0,ns,5432 +multi thread free,none object poll,,,,286801.0,ns,5626 +multi thread free,none object poll,,,,319998.0,ns,5820 +multi thread free,none object poll,,,,332281.0,ns,6014 +multi thread free,none object poll,,,,322344.0,ns,6208 +multi thread free,none object poll,,,,329252.0,ns,6402 +multi thread free,none object poll,,,,341391.0,ns,6596 +multi thread free,none object poll,,,,377875.0,ns,6790 +multi thread free,none object poll,,,,362013.0,ns,6984 +multi thread free,none object poll,,,,603237.0,ns,7178 +multi thread free,none object poll,,,,475612.0,ns,7372 +multi thread free,none object poll,,,,658964.0,ns,7566 +multi thread free,none object poll,,,,681277.0,ns,7760 +multi thread free,none object poll,,,,523255.0,ns,7954 +multi thread free,none object poll,,,,547149.0,ns,8148 +multi thread free,none object poll,,,,635164.0,ns,8342 +multi thread free,none object poll,,,,664353.0,ns,8536 +multi thread free,none object poll,,,,704201.0,ns,8730 +multi thread free,none object poll,,,,817363.0,ns,8924 +multi thread free,none object poll,,,,845936.0,ns,9118 +multi thread free,none object poll,,,,815523.0,ns,9312 +multi thread free,none object poll,,,,909808.0,ns,9506 +multi thread free,none object poll,,,,846307.0,ns,9700 +multi thread free,none object poll,,,,882955.0,ns,9894 +multi thread free,none object poll,,,,1083840.0,ns,10088 +multi thread free,none object poll,,,,1112263.0,ns,10282 +multi thread free,none object poll,,,,1132524.0,ns,10476 +multi thread free,none object poll,,,,1153824.0,ns,10670 +multi thread free,none object poll,,,,1201670.0,ns,10864 +multi thread free,none object poll,,,,1256675.0,ns,11058 +multi thread free,none object poll,,,,1152934.0,ns,11252 +multi thread free,none object poll,,,,1338235.0,ns,11446 +multi thread free,none object poll,,,,1085330.0,ns,11640 +multi thread free,none object poll,,,,1130037.0,ns,11834 +multi thread free,none object poll,,,,1386416.0,ns,12028 +multi thread free,none object poll,,,,1442416.0,ns,12222 +multi thread free,none object poll,,,,1818742.0,ns,12416 +multi thread free,none object poll,,,,1845677.0,ns,12610 +multi thread free,none object poll,,,,1901513.0,ns,12804 +multi thread free,none object poll,,,,1700923.0,ns,12998 +multi thread free,none object poll,,,,1786570.0,ns,13192 +multi thread free,none object poll,,,,1962105.0,ns,13386 +multi thread free,none object poll,,,,2011486.0,ns,13580 +multi thread free,none object poll,,,,2053343.0,ns,13774 +multi thread free,none object poll,,,,2107367.0,ns,13968 +multi thread free,none object poll,,,,2104758.0,ns,14162 +multi thread free,none object poll,,,,2086807.0,ns,14356 +multi thread free,none object poll,,,,1889145.0,ns,14550 +multi thread free,none object poll,,,,1953754.0,ns,14744 +multi thread free,none object poll,,,,1981949.0,ns,14938 +multi thread free,none object poll,,,,2031361.0,ns,15132 +multi thread free,none object poll,,,,2011380.0,ns,15326 +multi thread free,none object poll,,,,2003338.0,ns,15520 +multi thread free,none object poll,,,,2061042.0,ns,15714 +multi thread free,none object poll,,,,2070453.0,ns,15908 +multi thread free,none object poll,,,,2071881.0,ns,16102 +multi thread free,none object poll,,,,2114550.0,ns,16296 +multi thread free,none object poll,,,,2224910.0,ns,16490 +multi thread free,none object poll,,,,2222118.0,ns,16684 +multi thread free,none object poll,,,,2274877.0,ns,16878 +multi thread free,none object poll,,,,2262903.0,ns,17072 +multi thread free,none object poll,,,,2328102.0,ns,17266 +multi thread free,none object poll,,,,2256418.0,ns,17460 +multi thread free,none object poll,,,,2372823.0,ns,17654 +multi thread free,none object poll,,,,2400091.0,ns,17848 +multi thread free,none object poll,,,,2432178.0,ns,18042 +multi thread free,none object poll,,,,2437641.0,ns,18236 +multi thread free,none object poll,,,,2562439.0,ns,18430 +multi thread free,none object poll,,,,2462835.0,ns,18624 +multi thread free,none object poll,,,,2570236.0,ns,18818 +multi thread free,none object poll,,,,2610708.0,ns,19012 +multi thread free,none object poll,,,,2686876.0,ns,19206 +multi thread free,none object poll,,,,2662300.0,ns,19400 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/sample.json new file mode 100644 index 0000000000000..092b4371d8f23 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[194.0,388.0,582.0,776.0,970.0,1164.0,1358.0,1552.0,1746.0,1940.0,2134.0,2328.0,2522.0,2716.0,2910.0,3104.0,3298.0,3492.0,3686.0,3880.0,4074.0,4268.0,4462.0,4656.0,4850.0,5044.0,5238.0,5432.0,5626.0,5820.0,6014.0,6208.0,6402.0,6596.0,6790.0,6984.0,7178.0,7372.0,7566.0,7760.0,7954.0,8148.0,8342.0,8536.0,8730.0,8924.0,9118.0,9312.0,9506.0,9700.0,9894.0,10088.0,10282.0,10476.0,10670.0,10864.0,11058.0,11252.0,11446.0,11640.0,11834.0,12028.0,12222.0,12416.0,12610.0,12804.0,12998.0,13192.0,13386.0,13580.0,13774.0,13968.0,14162.0,14356.0,14550.0,14744.0,14938.0,15132.0,15326.0,15520.0,15714.0,15908.0,16102.0,16296.0,16490.0,16684.0,16878.0,17072.0,17266.0,17460.0,17654.0,17848.0,18042.0,18236.0,18430.0,18624.0,18818.0,19012.0,19206.0,19400.0],"times":[17987.0,9790.0,15231.0,18766.0,24355.0,28755.0,37640.0,44637.0,40626.0,51022.0,60995.0,67037.0,75681.0,92471.0,82391.0,432340.0,264257.0,264502.0,219819.0,206751.0,239562.0,242435.0,262129.0,262090.0,273935.0,280239.0,288728.0,312178.0,286801.0,319998.0,332281.0,322344.0,329252.0,341391.0,377875.0,362013.0,603237.0,475612.0,658964.0,681277.0,523255.0,547149.0,635164.0,664353.0,704201.0,817363.0,845936.0,815523.0,909808.0,846307.0,882955.0,1083840.0,1112263.0,1132524.0,1153824.0,1201670.0,1256675.0,1152934.0,1338235.0,1085330.0,1130037.0,1386416.0,1442416.0,1818742.0,1845677.0,1901513.0,1700923.0,1786570.0,1962105.0,2011486.0,2053343.0,2107367.0,2104758.0,2086807.0,1889145.0,1953754.0,1981949.0,2031361.0,2011380.0,2003338.0,2061042.0,2070453.0,2071881.0,2114550.0,2224910.0,2222118.0,2274877.0,2262903.0,2328102.0,2256418.0,2372823.0,2400091.0,2432178.0,2437641.0,2562439.0,2462835.0,2570236.0,2610708.0,2686876.0,2662300.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/tukey.json new file mode 100644 index 0000000000000..20948f6270707 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/base/tukey.json @@ -0,0 +1 @@ +[-173.8935651078722,-58.881268010489855,247.81819091586306,362.8304880132454] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/benchmark.json new file mode 100644 index 0000000000000..1bf8e9e8db356 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread free","function_id":"none object poll","value_str":null,"throughput":null,"full_id":"multi thread free/none object poll","directory_name":"multi thread free/none object poll","title":"multi thread free/none object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/estimates.json new file mode 100644 index 0000000000000..ccd3c5652301a --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":85.49596765781351,"upper_bound":101.5529560632594},"point_estimate":93.58534199979576,"standard_error":4.102466781628311},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":83.87995858665963,"upper_bound":115.28061592037056},"point_estimate":94.36605684186807,"standard_error":8.983267925688745},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":35.98390688546617,"upper_bound":63.96569690723438},"point_estimate":57.09984978290107,"standard_error":7.7970233841065},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":119.73590465630548,"upper_bound":128.04203016918848},"point_estimate":124.3863350949651,"standard_error":2.1194745578782554},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":37.58117553580864,"upper_bound":44.30243005086328},"point_estimate":41.27780199825228,"standard_error":1.7081100562311557}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/raw.csv new file mode 100644 index 0000000000000..1f594b21a6736 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread free,none object poll,,,,17987.0,ns,194 +multi thread free,none object poll,,,,9790.0,ns,388 +multi thread free,none object poll,,,,15231.0,ns,582 +multi thread free,none object poll,,,,18766.0,ns,776 +multi thread free,none object poll,,,,24355.0,ns,970 +multi thread free,none object poll,,,,28755.0,ns,1164 +multi thread free,none object poll,,,,37640.0,ns,1358 +multi thread free,none object poll,,,,44637.0,ns,1552 +multi thread free,none object poll,,,,40626.0,ns,1746 +multi thread free,none object poll,,,,51022.0,ns,1940 +multi thread free,none object poll,,,,60995.0,ns,2134 +multi thread free,none object poll,,,,67037.0,ns,2328 +multi thread free,none object poll,,,,75681.0,ns,2522 +multi thread free,none object poll,,,,92471.0,ns,2716 +multi thread free,none object poll,,,,82391.0,ns,2910 +multi thread free,none object poll,,,,432340.0,ns,3104 +multi thread free,none object poll,,,,264257.0,ns,3298 +multi thread free,none object poll,,,,264502.0,ns,3492 +multi thread free,none object poll,,,,219819.0,ns,3686 +multi thread free,none object poll,,,,206751.0,ns,3880 +multi thread free,none object poll,,,,239562.0,ns,4074 +multi thread free,none object poll,,,,242435.0,ns,4268 +multi thread free,none object poll,,,,262129.0,ns,4462 +multi thread free,none object poll,,,,262090.0,ns,4656 +multi thread free,none object poll,,,,273935.0,ns,4850 +multi thread free,none object poll,,,,280239.0,ns,5044 +multi thread free,none object poll,,,,288728.0,ns,5238 +multi thread free,none object poll,,,,312178.0,ns,5432 +multi thread free,none object poll,,,,286801.0,ns,5626 +multi thread free,none object poll,,,,319998.0,ns,5820 +multi thread free,none object poll,,,,332281.0,ns,6014 +multi thread free,none object poll,,,,322344.0,ns,6208 +multi thread free,none object poll,,,,329252.0,ns,6402 +multi thread free,none object poll,,,,341391.0,ns,6596 +multi thread free,none object poll,,,,377875.0,ns,6790 +multi thread free,none object poll,,,,362013.0,ns,6984 +multi thread free,none object poll,,,,603237.0,ns,7178 +multi thread free,none object poll,,,,475612.0,ns,7372 +multi thread free,none object poll,,,,658964.0,ns,7566 +multi thread free,none object poll,,,,681277.0,ns,7760 +multi thread free,none object poll,,,,523255.0,ns,7954 +multi thread free,none object poll,,,,547149.0,ns,8148 +multi thread free,none object poll,,,,635164.0,ns,8342 +multi thread free,none object poll,,,,664353.0,ns,8536 +multi thread free,none object poll,,,,704201.0,ns,8730 +multi thread free,none object poll,,,,817363.0,ns,8924 +multi thread free,none object poll,,,,845936.0,ns,9118 +multi thread free,none object poll,,,,815523.0,ns,9312 +multi thread free,none object poll,,,,909808.0,ns,9506 +multi thread free,none object poll,,,,846307.0,ns,9700 +multi thread free,none object poll,,,,882955.0,ns,9894 +multi thread free,none object poll,,,,1083840.0,ns,10088 +multi thread free,none object poll,,,,1112263.0,ns,10282 +multi thread free,none object poll,,,,1132524.0,ns,10476 +multi thread free,none object poll,,,,1153824.0,ns,10670 +multi thread free,none object poll,,,,1201670.0,ns,10864 +multi thread free,none object poll,,,,1256675.0,ns,11058 +multi thread free,none object poll,,,,1152934.0,ns,11252 +multi thread free,none object poll,,,,1338235.0,ns,11446 +multi thread free,none object poll,,,,1085330.0,ns,11640 +multi thread free,none object poll,,,,1130037.0,ns,11834 +multi thread free,none object poll,,,,1386416.0,ns,12028 +multi thread free,none object poll,,,,1442416.0,ns,12222 +multi thread free,none object poll,,,,1818742.0,ns,12416 +multi thread free,none object poll,,,,1845677.0,ns,12610 +multi thread free,none object poll,,,,1901513.0,ns,12804 +multi thread free,none object poll,,,,1700923.0,ns,12998 +multi thread free,none object poll,,,,1786570.0,ns,13192 +multi thread free,none object poll,,,,1962105.0,ns,13386 +multi thread free,none object poll,,,,2011486.0,ns,13580 +multi thread free,none object poll,,,,2053343.0,ns,13774 +multi thread free,none object poll,,,,2107367.0,ns,13968 +multi thread free,none object poll,,,,2104758.0,ns,14162 +multi thread free,none object poll,,,,2086807.0,ns,14356 +multi thread free,none object poll,,,,1889145.0,ns,14550 +multi thread free,none object poll,,,,1953754.0,ns,14744 +multi thread free,none object poll,,,,1981949.0,ns,14938 +multi thread free,none object poll,,,,2031361.0,ns,15132 +multi thread free,none object poll,,,,2011380.0,ns,15326 +multi thread free,none object poll,,,,2003338.0,ns,15520 +multi thread free,none object poll,,,,2061042.0,ns,15714 +multi thread free,none object poll,,,,2070453.0,ns,15908 +multi thread free,none object poll,,,,2071881.0,ns,16102 +multi thread free,none object poll,,,,2114550.0,ns,16296 +multi thread free,none object poll,,,,2224910.0,ns,16490 +multi thread free,none object poll,,,,2222118.0,ns,16684 +multi thread free,none object poll,,,,2274877.0,ns,16878 +multi thread free,none object poll,,,,2262903.0,ns,17072 +multi thread free,none object poll,,,,2328102.0,ns,17266 +multi thread free,none object poll,,,,2256418.0,ns,17460 +multi thread free,none object poll,,,,2372823.0,ns,17654 +multi thread free,none object poll,,,,2400091.0,ns,17848 +multi thread free,none object poll,,,,2432178.0,ns,18042 +multi thread free,none object poll,,,,2437641.0,ns,18236 +multi thread free,none object poll,,,,2562439.0,ns,18430 +multi thread free,none object poll,,,,2462835.0,ns,18624 +multi thread free,none object poll,,,,2570236.0,ns,18818 +multi thread free,none object poll,,,,2610708.0,ns,19012 +multi thread free,none object poll,,,,2686876.0,ns,19206 +multi thread free,none object poll,,,,2662300.0,ns,19400 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/sample.json new file mode 100644 index 0000000000000..092b4371d8f23 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[194.0,388.0,582.0,776.0,970.0,1164.0,1358.0,1552.0,1746.0,1940.0,2134.0,2328.0,2522.0,2716.0,2910.0,3104.0,3298.0,3492.0,3686.0,3880.0,4074.0,4268.0,4462.0,4656.0,4850.0,5044.0,5238.0,5432.0,5626.0,5820.0,6014.0,6208.0,6402.0,6596.0,6790.0,6984.0,7178.0,7372.0,7566.0,7760.0,7954.0,8148.0,8342.0,8536.0,8730.0,8924.0,9118.0,9312.0,9506.0,9700.0,9894.0,10088.0,10282.0,10476.0,10670.0,10864.0,11058.0,11252.0,11446.0,11640.0,11834.0,12028.0,12222.0,12416.0,12610.0,12804.0,12998.0,13192.0,13386.0,13580.0,13774.0,13968.0,14162.0,14356.0,14550.0,14744.0,14938.0,15132.0,15326.0,15520.0,15714.0,15908.0,16102.0,16296.0,16490.0,16684.0,16878.0,17072.0,17266.0,17460.0,17654.0,17848.0,18042.0,18236.0,18430.0,18624.0,18818.0,19012.0,19206.0,19400.0],"times":[17987.0,9790.0,15231.0,18766.0,24355.0,28755.0,37640.0,44637.0,40626.0,51022.0,60995.0,67037.0,75681.0,92471.0,82391.0,432340.0,264257.0,264502.0,219819.0,206751.0,239562.0,242435.0,262129.0,262090.0,273935.0,280239.0,288728.0,312178.0,286801.0,319998.0,332281.0,322344.0,329252.0,341391.0,377875.0,362013.0,603237.0,475612.0,658964.0,681277.0,523255.0,547149.0,635164.0,664353.0,704201.0,817363.0,845936.0,815523.0,909808.0,846307.0,882955.0,1083840.0,1112263.0,1132524.0,1153824.0,1201670.0,1256675.0,1152934.0,1338235.0,1085330.0,1130037.0,1386416.0,1442416.0,1818742.0,1845677.0,1901513.0,1700923.0,1786570.0,1962105.0,2011486.0,2053343.0,2107367.0,2104758.0,2086807.0,1889145.0,1953754.0,1981949.0,2031361.0,2011380.0,2003338.0,2061042.0,2070453.0,2071881.0,2114550.0,2224910.0,2222118.0,2274877.0,2262903.0,2328102.0,2256418.0,2372823.0,2400091.0,2432178.0,2437641.0,2562439.0,2462835.0,2570236.0,2610708.0,2686876.0,2662300.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/tukey.json new file mode 100644 index 0000000000000..20948f6270707 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/new/tukey.json @@ -0,0 +1 @@ +[-173.8935651078722,-58.881268010489855,247.81819091586306,362.8304880132454] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/MAD.svg new file mode 100644 index 0000000000000..326922d11a231 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/MAD.svg @@ -0,0 +1,293 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 35 + + + + + 40 + + + + + 45 + + + + + 50 + + + + + 55 + + + + + 60 + + + + + 65 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/none object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/SD.svg new file mode 100644 index 0000000000000..7be28f227c9ba --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.05 + + + + + 0.1 + + + + + 0.15 + + + + + 0.2 + + + + + 0.25 + + + + + 37 + + + + + 38 + + + + + 39 + + + + + 40 + + + + + 41 + + + + + 42 + + + + + 43 + + + + + 44 + + + + + 45 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/none object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/index.html new file mode 100644 index 0000000000000..41ab4d80d48d0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + multi thread free/none object poll - Criterion.rs + + + + +
+

multi thread free/none object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope119.74 ns124.39 ns128.04 ns
0.24119620.24815390.2438079
Mean85.496 ns93.585 ns101.55 ns
Std. Dev.37.581 ns41.278 ns44.302 ns
Median83.880 ns94.366 ns115.28 ns
MAD35.984 ns57.100 ns63.966 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/mean.svg new file mode 100644 index 0000000000000..9d838a6589eb0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/mean.svg @@ -0,0 +1,328 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 0.08 + + + + + 0.09 + + + + + 0.1 + + + + + 84 + + + + + 86 + + + + + 88 + + + + + 90 + + + + + 92 + + + + + 94 + + + + + 96 + + + + + 98 + + + + + 100 + + + + + 102 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/none object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/median.svg new file mode 100644 index 0000000000000..6b4b8b590d165 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/median.svg @@ -0,0 +1,313 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 0.08 + + + + + 0.09 + + + + + 0.1 + + + + + 85 + + + + + 90 + + + + + 95 + + + + + 100 + + + + + 105 + + + + + 110 + + + + + 115 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/none object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/pdf.svg new file mode 100644 index 0000000000000..2941baf7d7fc1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/pdf.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 0 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 0 + + + + + 0.001 + + + + + 0.002 + + + + + 0.003 + + + + + 0.004 + + + + + 0.005 + + + + + 0.006 + + + + + 0.007 + + + + + 0.008 + + + + + 0.009 + + + + + 0.01 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/none object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + gnuplot_plot_5 + + + + gnuplot_plot_6 + + + + gnuplot_plot_7 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..70aa3d0a44ff5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/pdf_small.svg @@ -0,0 +1,199 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.002 + + + + + 0.004 + + + + + 0.006 + + + + + 0.008 + + + + + 0.01 + + + + + 0 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/regression.svg new file mode 100644 index 0000000000000..707176165417b --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/regression.svg @@ -0,0 +1,447 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.5 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 2.5 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + multi thread free/none object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/regression_small.svg new file mode 100644 index 0000000000000..328f052bf2d0f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/regression_small.svg @@ -0,0 +1,425 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 1.5 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 2.5 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 12 + + + + + + + + + + + + + 14 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + 18 + + + + + + + + + + + + + 20 + + + + + + + + + Total sample time (ms) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/slope.svg new file mode 100644 index 0000000000000..d76c7cabb37c0 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/slope.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 0.16 + + + + + 0.18 + + + + + 0.2 + + + + + 120 + + + + + 122 + + + + + 124 + + + + + 126 + + + + + 128 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/none object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/typical.svg new file mode 100644 index 0000000000000..6df34fc567444 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/none object poll/report/typical.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 0.16 + + + + + 0.18 + + + + + 0.2 + + + + + 120 + + + + + 122 + + + + + 124 + + + + + 126 + + + + + 128 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/none object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread free/report/index.html new file mode 100644 index 0000000000000..a5372b7c58cca --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/report/index.html @@ -0,0 +1,208 @@ + + + + + + multi thread free Summary - Criterion.rs + + + + +
+

multi thread free

+

Violin Plot

+ + Violin Plot + +

This chart shows the relationship between function/parameter and iteration time. The thickness of the shaded + region indicates the probability that a measurement of the given function/parameter would take a particular + length of time.

+
+ +

multi thread free/crate 'object-pool'

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

multi thread free/crate 'sharded-slab'

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

multi thread free/linear object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

multi thread free/mutex object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

multi thread free/none object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ +

multi thread free/spin_lock object poll

+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/report/violin.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/report/violin.svg new file mode 100644 index 0000000000000..0145ec734fac1 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/report/violin.svg @@ -0,0 +1,605 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + multi thread free/spin_lock object poll + + + + + multi thread free/none object poll + + + + + multi thread free/mutex object poll + + + + + multi thread free/linear object poll + + + + + multi thread free/crate 'sharded-slab' + + + + + multi thread free/crate 'object-pool' + + + + + + + + + + + + + -500 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 500 + + + + + + + + + + + + + 1000 + + + + + + + + + + + + + 1500 + + + + + + + + + + + + + 2000 + + + + + + + + + Input + + + + + Average time (ns) + + + + + multi thread free: Violin plot + + + + + PDF + + + PDF + + + + + + + + + + gnuplot_plot_2 + + + + + + + gnuplot_plot_3 + + + + + + + gnuplot_plot_4 + + + + + + + gnuplot_plot_5 + + + + + + + gnuplot_plot_6 + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/benchmark.json new file mode 100644 index 0000000000000..4682855c2b83e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread free","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"multi thread free/spin_lock object poll","directory_name":"multi thread free/spin_lock object poll","title":"multi thread free/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/estimates.json new file mode 100644 index 0000000000000..99dcd45439b9f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":46.22641944536087,"upper_bound":56.37870017258617},"point_estimate":50.10690763908717,"standard_error":2.7262770573735913},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":45.31204151010914,"upper_bound":45.97211579395488},"point_estimate":45.67179326218874,"standard_error":0.17812852551151354},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.9423931376796217,"upper_bound":1.7300436509075916},"point_estimate":1.2359919406378972,"standard_error":0.21464096944595354},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":45.53136420069166,"upper_bound":47.42549265987038},"point_estimate":46.29078206328096,"standard_error":0.5022939032886281},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":3.499324114566629,"upper_bound":45.733022665637264},"point_estimate":27.50785870394609,"standard_error":12.831699335621932}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/raw.csv new file mode 100644 index 0000000000000..63bfe207d5a91 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread free,spin_lock object poll,,,,24523.0,ns,81 +multi thread free,spin_lock object poll,,,,22613.0,ns,162 +multi thread free,spin_lock object poll,,,,10412.0,ns,243 +multi thread free,spin_lock object poll,,,,23102.0,ns,324 +multi thread free,spin_lock object poll,,,,16782.0,ns,405 +multi thread free,spin_lock object poll,,,,23631.0,ns,486 +multi thread free,spin_lock object poll,,,,26959.0,ns,567 +multi thread free,spin_lock object poll,,,,42537.0,ns,648 +multi thread free,spin_lock object poll,,,,34467.0,ns,729 +multi thread free,spin_lock object poll,,,,36623.0,ns,810 +multi thread free,spin_lock object poll,,,,54570.0,ns,891 +multi thread free,spin_lock object poll,,,,48312.0,ns,972 +multi thread free,spin_lock object poll,,,,49734.0,ns,1053 +multi thread free,spin_lock object poll,,,,53608.0,ns,1134 +multi thread free,spin_lock object poll,,,,57684.0,ns,1215 +multi thread free,spin_lock object poll,,,,62661.0,ns,1296 +multi thread free,spin_lock object poll,,,,67169.0,ns,1377 +multi thread free,spin_lock object poll,,,,64008.0,ns,1458 +multi thread free,spin_lock object poll,,,,73984.0,ns,1539 +multi thread free,spin_lock object poll,,,,77698.0,ns,1620 +multi thread free,spin_lock object poll,,,,77100.0,ns,1701 +multi thread free,spin_lock object poll,,,,77470.0,ns,1782 +multi thread free,spin_lock object poll,,,,84312.0,ns,1863 +multi thread free,spin_lock object poll,,,,87598.0,ns,1944 +multi thread free,spin_lock object poll,,,,89688.0,ns,2025 +multi thread free,spin_lock object poll,,,,95162.0,ns,2106 +multi thread free,spin_lock object poll,,,,97709.0,ns,2187 +multi thread free,spin_lock object poll,,,,103058.0,ns,2268 +multi thread free,spin_lock object poll,,,,105549.0,ns,2349 +multi thread free,spin_lock object poll,,,,105550.0,ns,2430 +multi thread free,spin_lock object poll,,,,112782.0,ns,2511 +multi thread free,spin_lock object poll,,,,110098.0,ns,2592 +multi thread free,spin_lock object poll,,,,119433.0,ns,2673 +multi thread free,spin_lock object poll,,,,120793.0,ns,2754 +multi thread free,spin_lock object poll,,,,129898.0,ns,2835 +multi thread free,spin_lock object poll,,,,130380.0,ns,2916 +multi thread free,spin_lock object poll,,,,136479.0,ns,2997 +multi thread free,spin_lock object poll,,,,142050.0,ns,3078 +multi thread free,spin_lock object poll,,,,137384.0,ns,3159 +multi thread free,spin_lock object poll,,,,152883.0,ns,3240 +multi thread free,spin_lock object poll,,,,156297.0,ns,3321 +multi thread free,spin_lock object poll,,,,153123.0,ns,3402 +multi thread free,spin_lock object poll,,,,157030.0,ns,3483 +multi thread free,spin_lock object poll,,,,151537.0,ns,3564 +multi thread free,spin_lock object poll,,,,166992.0,ns,3645 +multi thread free,spin_lock object poll,,,,171470.0,ns,3726 +multi thread free,spin_lock object poll,,,,182074.0,ns,3807 +multi thread free,spin_lock object poll,,,,172837.0,ns,3888 +multi thread free,spin_lock object poll,,,,181942.0,ns,3969 +multi thread free,spin_lock object poll,,,,235685.0,ns,4050 +multi thread free,spin_lock object poll,,,,188700.0,ns,4131 +multi thread free,spin_lock object poll,,,,190796.0,ns,4212 +multi thread free,spin_lock object poll,,,,191926.0,ns,4293 +multi thread free,spin_lock object poll,,,,204539.0,ns,4374 +multi thread free,spin_lock object poll,,,,206183.0,ns,4455 +multi thread free,spin_lock object poll,,,,210096.0,ns,4536 +multi thread free,spin_lock object poll,,,,207711.0,ns,4617 +multi thread free,spin_lock object poll,,,,215977.0,ns,4698 +multi thread free,spin_lock object poll,,,,218231.0,ns,4779 +multi thread free,spin_lock object poll,,,,224319.0,ns,4860 +multi thread free,spin_lock object poll,,,,231629.0,ns,4941 +multi thread free,spin_lock object poll,,,,236340.0,ns,5022 +multi thread free,spin_lock object poll,,,,234209.0,ns,5103 +multi thread free,spin_lock object poll,,,,230240.0,ns,5184 +multi thread free,spin_lock object poll,,,,237755.0,ns,5265 +multi thread free,spin_lock object poll,,,,245161.0,ns,5346 +multi thread free,spin_lock object poll,,,,242382.0,ns,5427 +multi thread free,spin_lock object poll,,,,239958.0,ns,5508 +multi thread free,spin_lock object poll,,,,253249.0,ns,5589 +multi thread free,spin_lock object poll,,,,261999.0,ns,5670 +multi thread free,spin_lock object poll,,,,258645.0,ns,5751 +multi thread free,spin_lock object poll,,,,267330.0,ns,5832 +multi thread free,spin_lock object poll,,,,266887.0,ns,5913 +multi thread free,spin_lock object poll,,,,274221.0,ns,5994 +multi thread free,spin_lock object poll,,,,281520.0,ns,6075 +multi thread free,spin_lock object poll,,,,289094.0,ns,6156 +multi thread free,spin_lock object poll,,,,283347.0,ns,6237 +multi thread free,spin_lock object poll,,,,339732.0,ns,6318 +multi thread free,spin_lock object poll,,,,290406.0,ns,6399 +multi thread free,spin_lock object poll,,,,289874.0,ns,6480 +multi thread free,spin_lock object poll,,,,288671.0,ns,6561 +multi thread free,spin_lock object poll,,,,298212.0,ns,6642 +multi thread free,spin_lock object poll,,,,316942.0,ns,6723 +multi thread free,spin_lock object poll,,,,316410.0,ns,6804 +multi thread free,spin_lock object poll,,,,314902.0,ns,6885 +multi thread free,spin_lock object poll,,,,315433.0,ns,6966 +multi thread free,spin_lock object poll,,,,320339.0,ns,7047 +multi thread free,spin_lock object poll,,,,330007.0,ns,7128 +multi thread free,spin_lock object poll,,,,328297.0,ns,7209 +multi thread free,spin_lock object poll,,,,325691.0,ns,7290 +multi thread free,spin_lock object poll,,,,335600.0,ns,7371 +multi thread free,spin_lock object poll,,,,337369.0,ns,7452 +multi thread free,spin_lock object poll,,,,333905.0,ns,7533 +multi thread free,spin_lock object poll,,,,351839.0,ns,7614 +multi thread free,spin_lock object poll,,,,356407.0,ns,7695 +multi thread free,spin_lock object poll,,,,359074.0,ns,7776 +multi thread free,spin_lock object poll,,,,352278.0,ns,7857 +multi thread free,spin_lock object poll,,,,357899.0,ns,7938 +multi thread free,spin_lock object poll,,,,372077.0,ns,8019 +multi thread free,spin_lock object poll,,,,501256.0,ns,8100 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/sample.json new file mode 100644 index 0000000000000..40052039e240f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[81.0,162.0,243.0,324.0,405.0,486.0,567.0,648.0,729.0,810.0,891.0,972.0,1053.0,1134.0,1215.0,1296.0,1377.0,1458.0,1539.0,1620.0,1701.0,1782.0,1863.0,1944.0,2025.0,2106.0,2187.0,2268.0,2349.0,2430.0,2511.0,2592.0,2673.0,2754.0,2835.0,2916.0,2997.0,3078.0,3159.0,3240.0,3321.0,3402.0,3483.0,3564.0,3645.0,3726.0,3807.0,3888.0,3969.0,4050.0,4131.0,4212.0,4293.0,4374.0,4455.0,4536.0,4617.0,4698.0,4779.0,4860.0,4941.0,5022.0,5103.0,5184.0,5265.0,5346.0,5427.0,5508.0,5589.0,5670.0,5751.0,5832.0,5913.0,5994.0,6075.0,6156.0,6237.0,6318.0,6399.0,6480.0,6561.0,6642.0,6723.0,6804.0,6885.0,6966.0,7047.0,7128.0,7209.0,7290.0,7371.0,7452.0,7533.0,7614.0,7695.0,7776.0,7857.0,7938.0,8019.0,8100.0],"times":[24523.0,22613.0,10412.0,23102.0,16782.0,23631.0,26959.0,42537.0,34467.0,36623.0,54570.0,48312.0,49734.0,53608.0,57684.0,62661.0,67169.0,64008.0,73984.0,77698.0,77100.0,77470.0,84312.0,87598.0,89688.0,95162.0,97709.0,103058.0,105549.0,105550.0,112782.0,110098.0,119433.0,120793.0,129898.0,130380.0,136479.0,142050.0,137384.0,152883.0,156297.0,153123.0,157030.0,151537.0,166992.0,171470.0,182074.0,172837.0,181942.0,235685.0,188700.0,190796.0,191926.0,204539.0,206183.0,210096.0,207711.0,215977.0,218231.0,224319.0,231629.0,236340.0,234209.0,230240.0,237755.0,245161.0,242382.0,239958.0,253249.0,261999.0,258645.0,267330.0,266887.0,274221.0,281520.0,289094.0,283347.0,339732.0,290406.0,289874.0,288671.0,298212.0,316942.0,316410.0,314902.0,315433.0,320339.0,330007.0,328297.0,325691.0,335600.0,337369.0,333905.0,351839.0,356407.0,359074.0,352278.0,357899.0,372077.0,501256.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/tukey.json new file mode 100644 index 0000000000000..4b6544efb73c8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/base/tukey.json @@ -0,0 +1 @@ +[39.01724891954679,41.973116899933245,49.85543151429712,52.811299494683574] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/benchmark.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/benchmark.json new file mode 100644 index 0000000000000..4682855c2b83e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/benchmark.json @@ -0,0 +1 @@ +{"group_id":"multi thread free","function_id":"spin_lock object poll","value_str":null,"throughput":null,"full_id":"multi thread free/spin_lock object poll","directory_name":"multi thread free/spin_lock object poll","title":"multi thread free/spin_lock object poll"} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/estimates.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/estimates.json new file mode 100644 index 0000000000000..99dcd45439b9f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/estimates.json @@ -0,0 +1 @@ +{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":46.22641944536087,"upper_bound":56.37870017258617},"point_estimate":50.10690763908717,"standard_error":2.7262770573735913},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":45.31204151010914,"upper_bound":45.97211579395488},"point_estimate":45.67179326218874,"standard_error":0.17812852551151354},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":0.9423931376796217,"upper_bound":1.7300436509075916},"point_estimate":1.2359919406378972,"standard_error":0.21464096944595354},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":45.53136420069166,"upper_bound":47.42549265987038},"point_estimate":46.29078206328096,"standard_error":0.5022939032886281},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":3.499324114566629,"upper_bound":45.733022665637264},"point_estimate":27.50785870394609,"standard_error":12.831699335621932}} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/raw.csv b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/raw.csv new file mode 100644 index 0000000000000..63bfe207d5a91 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/raw.csv @@ -0,0 +1,101 @@ +group,function,value,throughput_num,throughput_type,sample_measured_value,unit,iteration_count +multi thread free,spin_lock object poll,,,,24523.0,ns,81 +multi thread free,spin_lock object poll,,,,22613.0,ns,162 +multi thread free,spin_lock object poll,,,,10412.0,ns,243 +multi thread free,spin_lock object poll,,,,23102.0,ns,324 +multi thread free,spin_lock object poll,,,,16782.0,ns,405 +multi thread free,spin_lock object poll,,,,23631.0,ns,486 +multi thread free,spin_lock object poll,,,,26959.0,ns,567 +multi thread free,spin_lock object poll,,,,42537.0,ns,648 +multi thread free,spin_lock object poll,,,,34467.0,ns,729 +multi thread free,spin_lock object poll,,,,36623.0,ns,810 +multi thread free,spin_lock object poll,,,,54570.0,ns,891 +multi thread free,spin_lock object poll,,,,48312.0,ns,972 +multi thread free,spin_lock object poll,,,,49734.0,ns,1053 +multi thread free,spin_lock object poll,,,,53608.0,ns,1134 +multi thread free,spin_lock object poll,,,,57684.0,ns,1215 +multi thread free,spin_lock object poll,,,,62661.0,ns,1296 +multi thread free,spin_lock object poll,,,,67169.0,ns,1377 +multi thread free,spin_lock object poll,,,,64008.0,ns,1458 +multi thread free,spin_lock object poll,,,,73984.0,ns,1539 +multi thread free,spin_lock object poll,,,,77698.0,ns,1620 +multi thread free,spin_lock object poll,,,,77100.0,ns,1701 +multi thread free,spin_lock object poll,,,,77470.0,ns,1782 +multi thread free,spin_lock object poll,,,,84312.0,ns,1863 +multi thread free,spin_lock object poll,,,,87598.0,ns,1944 +multi thread free,spin_lock object poll,,,,89688.0,ns,2025 +multi thread free,spin_lock object poll,,,,95162.0,ns,2106 +multi thread free,spin_lock object poll,,,,97709.0,ns,2187 +multi thread free,spin_lock object poll,,,,103058.0,ns,2268 +multi thread free,spin_lock object poll,,,,105549.0,ns,2349 +multi thread free,spin_lock object poll,,,,105550.0,ns,2430 +multi thread free,spin_lock object poll,,,,112782.0,ns,2511 +multi thread free,spin_lock object poll,,,,110098.0,ns,2592 +multi thread free,spin_lock object poll,,,,119433.0,ns,2673 +multi thread free,spin_lock object poll,,,,120793.0,ns,2754 +multi thread free,spin_lock object poll,,,,129898.0,ns,2835 +multi thread free,spin_lock object poll,,,,130380.0,ns,2916 +multi thread free,spin_lock object poll,,,,136479.0,ns,2997 +multi thread free,spin_lock object poll,,,,142050.0,ns,3078 +multi thread free,spin_lock object poll,,,,137384.0,ns,3159 +multi thread free,spin_lock object poll,,,,152883.0,ns,3240 +multi thread free,spin_lock object poll,,,,156297.0,ns,3321 +multi thread free,spin_lock object poll,,,,153123.0,ns,3402 +multi thread free,spin_lock object poll,,,,157030.0,ns,3483 +multi thread free,spin_lock object poll,,,,151537.0,ns,3564 +multi thread free,spin_lock object poll,,,,166992.0,ns,3645 +multi thread free,spin_lock object poll,,,,171470.0,ns,3726 +multi thread free,spin_lock object poll,,,,182074.0,ns,3807 +multi thread free,spin_lock object poll,,,,172837.0,ns,3888 +multi thread free,spin_lock object poll,,,,181942.0,ns,3969 +multi thread free,spin_lock object poll,,,,235685.0,ns,4050 +multi thread free,spin_lock object poll,,,,188700.0,ns,4131 +multi thread free,spin_lock object poll,,,,190796.0,ns,4212 +multi thread free,spin_lock object poll,,,,191926.0,ns,4293 +multi thread free,spin_lock object poll,,,,204539.0,ns,4374 +multi thread free,spin_lock object poll,,,,206183.0,ns,4455 +multi thread free,spin_lock object poll,,,,210096.0,ns,4536 +multi thread free,spin_lock object poll,,,,207711.0,ns,4617 +multi thread free,spin_lock object poll,,,,215977.0,ns,4698 +multi thread free,spin_lock object poll,,,,218231.0,ns,4779 +multi thread free,spin_lock object poll,,,,224319.0,ns,4860 +multi thread free,spin_lock object poll,,,,231629.0,ns,4941 +multi thread free,spin_lock object poll,,,,236340.0,ns,5022 +multi thread free,spin_lock object poll,,,,234209.0,ns,5103 +multi thread free,spin_lock object poll,,,,230240.0,ns,5184 +multi thread free,spin_lock object poll,,,,237755.0,ns,5265 +multi thread free,spin_lock object poll,,,,245161.0,ns,5346 +multi thread free,spin_lock object poll,,,,242382.0,ns,5427 +multi thread free,spin_lock object poll,,,,239958.0,ns,5508 +multi thread free,spin_lock object poll,,,,253249.0,ns,5589 +multi thread free,spin_lock object poll,,,,261999.0,ns,5670 +multi thread free,spin_lock object poll,,,,258645.0,ns,5751 +multi thread free,spin_lock object poll,,,,267330.0,ns,5832 +multi thread free,spin_lock object poll,,,,266887.0,ns,5913 +multi thread free,spin_lock object poll,,,,274221.0,ns,5994 +multi thread free,spin_lock object poll,,,,281520.0,ns,6075 +multi thread free,spin_lock object poll,,,,289094.0,ns,6156 +multi thread free,spin_lock object poll,,,,283347.0,ns,6237 +multi thread free,spin_lock object poll,,,,339732.0,ns,6318 +multi thread free,spin_lock object poll,,,,290406.0,ns,6399 +multi thread free,spin_lock object poll,,,,289874.0,ns,6480 +multi thread free,spin_lock object poll,,,,288671.0,ns,6561 +multi thread free,spin_lock object poll,,,,298212.0,ns,6642 +multi thread free,spin_lock object poll,,,,316942.0,ns,6723 +multi thread free,spin_lock object poll,,,,316410.0,ns,6804 +multi thread free,spin_lock object poll,,,,314902.0,ns,6885 +multi thread free,spin_lock object poll,,,,315433.0,ns,6966 +multi thread free,spin_lock object poll,,,,320339.0,ns,7047 +multi thread free,spin_lock object poll,,,,330007.0,ns,7128 +multi thread free,spin_lock object poll,,,,328297.0,ns,7209 +multi thread free,spin_lock object poll,,,,325691.0,ns,7290 +multi thread free,spin_lock object poll,,,,335600.0,ns,7371 +multi thread free,spin_lock object poll,,,,337369.0,ns,7452 +multi thread free,spin_lock object poll,,,,333905.0,ns,7533 +multi thread free,spin_lock object poll,,,,351839.0,ns,7614 +multi thread free,spin_lock object poll,,,,356407.0,ns,7695 +multi thread free,spin_lock object poll,,,,359074.0,ns,7776 +multi thread free,spin_lock object poll,,,,352278.0,ns,7857 +multi thread free,spin_lock object poll,,,,357899.0,ns,7938 +multi thread free,spin_lock object poll,,,,372077.0,ns,8019 +multi thread free,spin_lock object poll,,,,501256.0,ns,8100 diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/sample.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/sample.json new file mode 100644 index 0000000000000..40052039e240f --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/sample.json @@ -0,0 +1 @@ +{"sampling_mode":"Linear","iters":[81.0,162.0,243.0,324.0,405.0,486.0,567.0,648.0,729.0,810.0,891.0,972.0,1053.0,1134.0,1215.0,1296.0,1377.0,1458.0,1539.0,1620.0,1701.0,1782.0,1863.0,1944.0,2025.0,2106.0,2187.0,2268.0,2349.0,2430.0,2511.0,2592.0,2673.0,2754.0,2835.0,2916.0,2997.0,3078.0,3159.0,3240.0,3321.0,3402.0,3483.0,3564.0,3645.0,3726.0,3807.0,3888.0,3969.0,4050.0,4131.0,4212.0,4293.0,4374.0,4455.0,4536.0,4617.0,4698.0,4779.0,4860.0,4941.0,5022.0,5103.0,5184.0,5265.0,5346.0,5427.0,5508.0,5589.0,5670.0,5751.0,5832.0,5913.0,5994.0,6075.0,6156.0,6237.0,6318.0,6399.0,6480.0,6561.0,6642.0,6723.0,6804.0,6885.0,6966.0,7047.0,7128.0,7209.0,7290.0,7371.0,7452.0,7533.0,7614.0,7695.0,7776.0,7857.0,7938.0,8019.0,8100.0],"times":[24523.0,22613.0,10412.0,23102.0,16782.0,23631.0,26959.0,42537.0,34467.0,36623.0,54570.0,48312.0,49734.0,53608.0,57684.0,62661.0,67169.0,64008.0,73984.0,77698.0,77100.0,77470.0,84312.0,87598.0,89688.0,95162.0,97709.0,103058.0,105549.0,105550.0,112782.0,110098.0,119433.0,120793.0,129898.0,130380.0,136479.0,142050.0,137384.0,152883.0,156297.0,153123.0,157030.0,151537.0,166992.0,171470.0,182074.0,172837.0,181942.0,235685.0,188700.0,190796.0,191926.0,204539.0,206183.0,210096.0,207711.0,215977.0,218231.0,224319.0,231629.0,236340.0,234209.0,230240.0,237755.0,245161.0,242382.0,239958.0,253249.0,261999.0,258645.0,267330.0,266887.0,274221.0,281520.0,289094.0,283347.0,339732.0,290406.0,289874.0,288671.0,298212.0,316942.0,316410.0,314902.0,315433.0,320339.0,330007.0,328297.0,325691.0,335600.0,337369.0,333905.0,351839.0,356407.0,359074.0,352278.0,357899.0,372077.0,501256.0]} \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/tukey.json b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/tukey.json new file mode 100644 index 0000000000000..4b6544efb73c8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/new/tukey.json @@ -0,0 +1 @@ +[39.01724891954679,41.973116899933245,49.85543151429712,52.811299494683574] \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/MAD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/MAD.svg new file mode 100644 index 0000000000000..1f06c471f6373 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/MAD.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 0.9 + + + + + 1 + + + + + 1.1 + + + + + 1.2 + + + + + 1.3 + + + + + 1.4 + + + + + 1.5 + + + + + 1.6 + + + + + 1.7 + + + + + 1.8 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/spin_lock object poll: MAD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/SD.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/SD.svg new file mode 100644 index 0000000000000..3147c44788bc5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/SD.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.01 + + + + + 0.02 + + + + + 0.03 + + + + + 0.04 + + + + + 0.05 + + + + + 0.06 + + + + + 0.07 + + + + + 0.08 + + + + + 0 + + + + + 10 + + + + + 20 + + + + + 30 + + + + + 40 + + + + + 50 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/spin_lock object poll: SD + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/index.html b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/index.html new file mode 100644 index 0000000000000..dc447598be2c8 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/index.html @@ -0,0 +1,203 @@ + + + + + + multi thread free/spin_lock object poll - Criterion.rs + + + + +
+

multi thread free/spin_lock object poll

+
+
+ + + + + + + +
+ + PDF of Slope + + + + Regression + +
+
+
+
+

Additional Statistics:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lower boundEstimateUpper bound
Slope45.531 ns46.291 ns47.425 ns
0.79081700.79913650.7807977
Mean46.226 ns50.107 ns56.379 ns
Std. Dev.3.4993 ns27.508 ns45.733 ns
Median45.312 ns45.672 ns45.972 ns
MAD942.39 ps1.2360 ns1.7300 ns
+
+
+

Additional Plots:

+ +
+
+
+

Understanding this report:

+

The plot on the left displays the average time per iteration for this benchmark. The shaded region + shows the estimated probabilty of an iteration taking a certain amount of time, while the line + shows the mean. Click on the plot for a larger view showing the outliers.

+

The plot on the right shows the linear regression calculated from the measurements. Each point + represents a sample, though here it shows the total time for the sample rather than time per + iteration. The line is the line of best fit for these measurements.

+

See the + documentation for more details on the additional statistics.

+
+
+
+ + + + \ No newline at end of file diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/mean.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/mean.svg new file mode 100644 index 0000000000000..91cd637897f6d --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/mean.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.02 + + + + + 0.04 + + + + + 0.06 + + + + + 0.08 + + + + + 0.1 + + + + + 0.12 + + + + + 0.14 + + + + + 0.16 + + + + + 0.18 + + + + + 46 + + + + + 48 + + + + + 50 + + + + + 52 + + + + + 54 + + + + + 56 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/spin_lock object poll: mean + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/median.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/median.svg new file mode 100644 index 0000000000000..b681092c0d35e --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/median.svg @@ -0,0 +1,303 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.5 + + + + + 1 + + + + + 1.5 + + + + + 2 + + + + + 2.5 + + + + + 3 + + + + + 3.5 + + + + + 45.3 + + + + + 45.4 + + + + + 45.5 + + + + + 45.6 + + + + + 45.7 + + + + + 45.8 + + + + + 45.9 + + + + + 46 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/spin_lock object poll: median + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/pdf.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/pdf.svg new file mode 100644 index 0000000000000..324c0e40bbabb --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/pdf.svg @@ -0,0 +1,430 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 250 + + + + + 300 + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + + + + + Iterations (x 103) + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/spin_lock object poll + + + + + PDF + + + PDF + + + + + + + + + + Mean + + + + + Mean + + + + + + "Clean" sample + + + + + "Clean" sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mild outliers + + + Mild outliers + + + + + + + + Severe outliers + + + Severe outliers + + + + + + + + + + + + + + + gnuplot_plot_6 + + + + + + gnuplot_plot_7 + + + + gnuplot_plot_8 + + + + gnuplot_plot_9 + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/pdf_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/pdf_small.svg new file mode 100644 index 0000000000000..284ef3d93fa49 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/pdf_small.svg @@ -0,0 +1,214 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.005 + + + + + 0.01 + + + + + 0.015 + + + + + 0.02 + + + + + 0.025 + + + + + 0.03 + + + + + 0.035 + + + + + 50 + + + + + 100 + + + + + 150 + + + + + 200 + + + + + 250 + + + + + 300 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + PDF + + + + + + + Mean + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/regression.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/regression.svg new file mode 100644 index 0000000000000..c3cea3f0bfdf5 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/regression.svg @@ -0,0 +1,434 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 300 + + + + + + + + + + + + + 400 + + + + + + + + + + + + + 500 + + + + + + + + + + + + + 600 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 9 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + multi thread free/spin_lock object poll + + + + + Sample + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + Linear regression + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/regression_small.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/regression_small.svg new file mode 100644 index 0000000000000..1761d1dc40491 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/regression_small.svg @@ -0,0 +1,412 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 100 + + + + + + + + + + + + + 200 + + + + + + + + + + + + + 300 + + + + + + + + + + + + + 400 + + + + + + + + + + + + + 500 + + + + + + + + + + + + + 600 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + 8 + + + + + + + + + + + + + 9 + + + + + + + + + Total sample time (us) + + + + + Iterations (x 103) + + + + + Sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear regression + + + + + + Confidence interval + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/slope.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/slope.svg new file mode 100644 index 0000000000000..eb6be33fd06e3 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/slope.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 0.9 + + + + + 45.5 + + + + + 46 + + + + + 46.5 + + + + + 47 + + + + + 47.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/spin_lock object poll: slope + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/typical.svg b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/typical.svg new file mode 100644 index 0000000000000..6a4fb11d30fde --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/multi thread free/spin_lock object poll/report/typical.svg @@ -0,0 +1,298 @@ + + + +Gnuplot +Produced by GNUPLOT 5.2 patchlevel 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0.1 + + + + + 0.2 + + + + + 0.3 + + + + + 0.4 + + + + + 0.5 + + + + + 0.6 + + + + + 0.7 + + + + + 0.8 + + + + + 0.9 + + + + + 45.5 + + + + + 46 + + + + + 46.5 + + + + + 47 + + + + + 47.5 + + + + + + + + + Density (a.u.) + + + + + Average time (ns) + + + + + multi thread free/spin_lock object poll: typical + + + + + Bootstrap distribution + + + + + Bootstrap distribution + + + + + + Confidence interval + + + + + Confidence interval + + + + + + + + + + Point estimate + + + + + Point estimate + + + + + + + + + + + + + + + + diff --git a/vendor/lockfree-object-pool/benches/criterion/report/index.html b/vendor/lockfree-object-pool/benches/criterion/report/index.html new file mode 100644 index 0000000000000..7d50effa44e35 --- /dev/null +++ b/vendor/lockfree-object-pool/benches/criterion/report/index.html @@ -0,0 +1,151 @@ + + + + + + Index - Criterion.rs + + + + + + + + \ No newline at end of file diff --git a/vendor/lua-src/lua-5.4.6/lapi.c b/vendor/lua-src/lua-5.4.6/lapi.c new file mode 100644 index 0000000000000..34e64af1428cd --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lapi.c @@ -0,0 +1,1463 @@ +/* +** $Id: lapi.c $ +** Lua API +** See Copyright Notice in lua.h +*/ + +#define lapi_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" + + + +const char lua_ident[] = + "$LuaVersion: " LUA_COPYRIGHT " $" + "$LuaAuthors: " LUA_AUTHORS " $"; + + + +/* +** Test for a valid index (one that is not the 'nilvalue'). +** '!ttisnil(o)' implies 'o != &G(L)->nilvalue', so it is not needed. +** However, it covers the most common cases in a faster way. +*/ +#define isvalid(L, o) (!ttisnil(o) || o != &G(L)->nilvalue) + + +/* test for pseudo index */ +#define ispseudo(i) ((i) <= LUA_REGISTRYINDEX) + +/* test for upvalue */ +#define isupvalue(i) ((i) < LUA_REGISTRYINDEX) + + +/* +** Convert an acceptable index to a pointer to its respective value. +** Non-valid indices return the special nil value 'G(L)->nilvalue'. +*/ +static TValue *index2value (lua_State *L, int idx) { + CallInfo *ci = L->ci; + if (idx > 0) { + StkId o = ci->func.p + idx; + api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index"); + if (o >= L->top.p) return &G(L)->nilvalue; + else return s2v(o); + } + else if (!ispseudo(idx)) { /* negative index */ + api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1), + "invalid index"); + return s2v(L->top.p + idx); + } + else if (idx == LUA_REGISTRYINDEX) + return &G(L)->l_registry; + else { /* upvalues */ + idx = LUA_REGISTRYINDEX - idx; + api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); + if (ttisCclosure(s2v(ci->func.p))) { /* C closure? */ + CClosure *func = clCvalue(s2v(ci->func.p)); + return (idx <= func->nupvalues) ? &func->upvalue[idx-1] + : &G(L)->nilvalue; + } + else { /* light C function or Lua function (through a hook)?) */ + api_check(L, ttislcf(s2v(ci->func.p)), "caller not a C function"); + return &G(L)->nilvalue; /* no upvalues */ + } + } +} + + + +/* +** Convert a valid actual index (not a pseudo-index) to its address. +*/ +l_sinline StkId index2stack (lua_State *L, int idx) { + CallInfo *ci = L->ci; + if (idx > 0) { + StkId o = ci->func.p + idx; + api_check(L, o < L->top.p, "invalid index"); + return o; + } + else { /* non-positive index */ + api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1), + "invalid index"); + api_check(L, !ispseudo(idx), "invalid index"); + return L->top.p + idx; + } +} + + +LUA_API int lua_checkstack (lua_State *L, int n) { + int res; + CallInfo *ci; + lua_lock(L); + ci = L->ci; + api_check(L, n >= 0, "negative 'n'"); + if (L->stack_last.p - L->top.p > n) /* stack large enough? */ + res = 1; /* yes; check is OK */ + else /* need to grow stack */ + res = luaD_growstack(L, n, 0); + if (res && ci->top.p < L->top.p + n) + ci->top.p = L->top.p + n; /* adjust frame top */ + lua_unlock(L); + return res; +} + + +LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { + int i; + if (from == to) return; + lua_lock(to); + api_checknelems(from, n); + api_check(from, G(from) == G(to), "moving among independent states"); + api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow"); + from->top.p -= n; + for (i = 0; i < n; i++) { + setobjs2s(to, to->top.p, from->top.p + i); + to->top.p++; /* stack already checked by previous 'api_check' */ + } + lua_unlock(to); +} + + +LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { + lua_CFunction old; + lua_lock(L); + old = G(L)->panic; + G(L)->panic = panicf; + lua_unlock(L); + return old; +} + + +LUA_API lua_Number lua_version (lua_State *L) { + UNUSED(L); + return LUA_VERSION_NUM; +} + + + +/* +** basic stack manipulation +*/ + + +/* +** convert an acceptable stack index into an absolute index +*/ +LUA_API int lua_absindex (lua_State *L, int idx) { + return (idx > 0 || ispseudo(idx)) + ? idx + : cast_int(L->top.p - L->ci->func.p) + idx; +} + + +LUA_API int lua_gettop (lua_State *L) { + return cast_int(L->top.p - (L->ci->func.p + 1)); +} + + +LUA_API void lua_settop (lua_State *L, int idx) { + CallInfo *ci; + StkId func, newtop; + ptrdiff_t diff; /* difference for new top */ + lua_lock(L); + ci = L->ci; + func = ci->func.p; + if (idx >= 0) { + api_check(L, idx <= ci->top.p - (func + 1), "new top too large"); + diff = ((func + 1) + idx) - L->top.p; + for (; diff > 0; diff--) + setnilvalue(s2v(L->top.p++)); /* clear new slots */ + } + else { + api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top"); + diff = idx + 1; /* will "subtract" index (as it is negative) */ + } + api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot"); + newtop = L->top.p + diff; + if (diff < 0 && L->tbclist.p >= newtop) { + lua_assert(hastocloseCfunc(ci->nresults)); + newtop = luaF_close(L, newtop, CLOSEKTOP, 0); + } + L->top.p = newtop; /* correct top only after closing any upvalue */ + lua_unlock(L); +} + + +LUA_API void lua_closeslot (lua_State *L, int idx) { + StkId level; + lua_lock(L); + level = index2stack(L, idx); + api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level, + "no variable to close at given level"); + level = luaF_close(L, level, CLOSEKTOP, 0); + setnilvalue(s2v(level)); + lua_unlock(L); +} + + +/* +** Reverse the stack segment from 'from' to 'to' +** (auxiliary to 'lua_rotate') +** Note that we move(copy) only the value inside the stack. +** (We do not move additional fields that may exist.) +*/ +l_sinline void reverse (lua_State *L, StkId from, StkId to) { + for (; from < to; from++, to--) { + TValue temp; + setobj(L, &temp, s2v(from)); + setobjs2s(L, from, to); + setobj2s(L, to, &temp); + } +} + + +/* +** Let x = AB, where A is a prefix of length 'n'. Then, +** rotate x n == BA. But BA == (A^r . B^r)^r. +*/ +LUA_API void lua_rotate (lua_State *L, int idx, int n) { + StkId p, t, m; + lua_lock(L); + t = L->top.p - 1; /* end of stack segment being rotated */ + p = index2stack(L, idx); /* start of segment */ + api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); + m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ + reverse(L, p, m); /* reverse the prefix with length 'n' */ + reverse(L, m + 1, t); /* reverse the suffix */ + reverse(L, p, t); /* reverse the entire segment */ + lua_unlock(L); +} + + +LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { + TValue *fr, *to; + lua_lock(L); + fr = index2value(L, fromidx); + to = index2value(L, toidx); + api_check(L, isvalid(L, to), "invalid index"); + setobj(L, to, fr); + if (isupvalue(toidx)) /* function upvalue? */ + luaC_barrier(L, clCvalue(s2v(L->ci->func.p)), fr); + /* LUA_REGISTRYINDEX does not need gc barrier + (collector revisits it before finishing collection) */ + lua_unlock(L); +} + + +LUA_API void lua_pushvalue (lua_State *L, int idx) { + lua_lock(L); + setobj2s(L, L->top.p, index2value(L, idx)); + api_incr_top(L); + lua_unlock(L); +} + + + +/* +** access functions (stack -> C) +*/ + + +LUA_API int lua_type (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return (isvalid(L, o) ? ttype(o) : LUA_TNONE); +} + + +LUA_API const char *lua_typename (lua_State *L, int t) { + UNUSED(L); + api_check(L, LUA_TNONE <= t && t < LUA_NUMTYPES, "invalid type"); + return ttypename(t); +} + + +LUA_API int lua_iscfunction (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return (ttislcf(o) || (ttisCclosure(o))); +} + + +LUA_API int lua_isinteger (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return ttisinteger(o); +} + + +LUA_API int lua_isnumber (lua_State *L, int idx) { + lua_Number n; + const TValue *o = index2value(L, idx); + return tonumber(o, &n); +} + + +LUA_API int lua_isstring (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return (ttisstring(o) || cvt2str(o)); +} + + +LUA_API int lua_isuserdata (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return (ttisfulluserdata(o) || ttislightuserdata(o)); +} + + +LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { + const TValue *o1 = index2value(L, index1); + const TValue *o2 = index2value(L, index2); + return (isvalid(L, o1) && isvalid(L, o2)) ? luaV_rawequalobj(o1, o2) : 0; +} + + +LUA_API void lua_arith (lua_State *L, int op) { + lua_lock(L); + if (op != LUA_OPUNM && op != LUA_OPBNOT) + api_checknelems(L, 2); /* all other operations expect two operands */ + else { /* for unary operations, add fake 2nd operand */ + api_checknelems(L, 1); + setobjs2s(L, L->top.p, L->top.p - 1); + api_incr_top(L); + } + /* first operand at top - 2, second at top - 1; result go to top - 2 */ + luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2); + L->top.p--; /* remove second operand */ + lua_unlock(L); +} + + +LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { + const TValue *o1; + const TValue *o2; + int i = 0; + lua_lock(L); /* may call tag method */ + o1 = index2value(L, index1); + o2 = index2value(L, index2); + if (isvalid(L, o1) && isvalid(L, o2)) { + switch (op) { + case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break; + case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; + case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; + default: api_check(L, 0, "invalid option"); + } + } + lua_unlock(L); + return i; +} + + +LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) { + size_t sz = luaO_str2num(s, s2v(L->top.p)); + if (sz != 0) + api_incr_top(L); + return sz; +} + + +LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) { + lua_Number n = 0; + const TValue *o = index2value(L, idx); + int isnum = tonumber(o, &n); + if (pisnum) + *pisnum = isnum; + return n; +} + + +LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) { + lua_Integer res = 0; + const TValue *o = index2value(L, idx); + int isnum = tointeger(o, &res); + if (pisnum) + *pisnum = isnum; + return res; +} + + +LUA_API int lua_toboolean (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return !l_isfalse(o); +} + + +LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { + TValue *o; + lua_lock(L); + o = index2value(L, idx); + if (!ttisstring(o)) { + if (!cvt2str(o)) { /* not convertible? */ + if (len != NULL) *len = 0; + lua_unlock(L); + return NULL; + } + luaO_tostring(L, o); + luaC_checkGC(L); + o = index2value(L, idx); /* previous call may reallocate the stack */ + } + if (len != NULL) + *len = vslen(o); + lua_unlock(L); + return svalue(o); +} + + +LUA_API lua_Unsigned lua_rawlen (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + switch (ttypetag(o)) { + case LUA_VSHRSTR: return tsvalue(o)->shrlen; + case LUA_VLNGSTR: return tsvalue(o)->u.lnglen; + case LUA_VUSERDATA: return uvalue(o)->len; + case LUA_VTABLE: return luaH_getn(hvalue(o)); + default: return 0; + } +} + + +LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + if (ttislcf(o)) return fvalue(o); + else if (ttisCclosure(o)) + return clCvalue(o)->f; + else return NULL; /* not a C function */ +} + + +l_sinline void *touserdata (const TValue *o) { + switch (ttype(o)) { + case LUA_TUSERDATA: return getudatamem(uvalue(o)); + case LUA_TLIGHTUSERDATA: return pvalue(o); + default: return NULL; + } +} + + +LUA_API void *lua_touserdata (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return touserdata(o); +} + + +LUA_API lua_State *lua_tothread (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + return (!ttisthread(o)) ? NULL : thvalue(o); +} + + +/* +** Returns a pointer to the internal representation of an object. +** Note that ANSI C does not allow the conversion of a pointer to +** function to a 'void*', so the conversion here goes through +** a 'size_t'. (As the returned pointer is only informative, this +** conversion should not be a problem.) +*/ +LUA_API const void *lua_topointer (lua_State *L, int idx) { + const TValue *o = index2value(L, idx); + switch (ttypetag(o)) { + case LUA_VLCF: return cast_voidp(cast_sizet(fvalue(o))); + case LUA_VUSERDATA: case LUA_VLIGHTUSERDATA: + return touserdata(o); + default: { + if (iscollectable(o)) + return gcvalue(o); + else + return NULL; + } + } +} + + + +/* +** push functions (C -> stack) +*/ + + +LUA_API void lua_pushnil (lua_State *L) { + lua_lock(L); + setnilvalue(s2v(L->top.p)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { + lua_lock(L); + setfltvalue(s2v(L->top.p), n); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { + lua_lock(L); + setivalue(s2v(L->top.p), n); + api_incr_top(L); + lua_unlock(L); +} + + +/* +** Pushes on the stack a string with given length. Avoid using 's' when +** 'len' == 0 (as 's' can be NULL in that case), due to later use of +** 'memcmp' and 'memcpy'. +*/ +LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { + TString *ts; + lua_lock(L); + ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); + setsvalue2s(L, L->top.p, ts); + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return getstr(ts); +} + + +LUA_API const char *lua_pushstring (lua_State *L, const char *s) { + lua_lock(L); + if (s == NULL) + setnilvalue(s2v(L->top.p)); + else { + TString *ts; + ts = luaS_new(L, s); + setsvalue2s(L, L->top.p, ts); + s = getstr(ts); /* internal copy's address */ + } + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return s; +} + + +LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, + va_list argp) { + const char *ret; + lua_lock(L); + ret = luaO_pushvfstring(L, fmt, argp); + luaC_checkGC(L); + lua_unlock(L); + return ret; +} + + +LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { + const char *ret; + va_list argp; + lua_lock(L); + va_start(argp, fmt); + ret = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + luaC_checkGC(L); + lua_unlock(L); + return ret; +} + + +LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { + lua_lock(L); + if (n == 0) { + setfvalue(s2v(L->top.p), fn); + api_incr_top(L); + } + else { + CClosure *cl; + api_checknelems(L, n); + api_check(L, n <= MAXUPVAL, "upvalue index too large"); + cl = luaF_newCclosure(L, n); + cl->f = fn; + L->top.p -= n; + while (n--) { + setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n)); + /* does not need barrier because closure is white */ + lua_assert(iswhite(cl)); + } + setclCvalue(L, s2v(L->top.p), cl); + api_incr_top(L); + luaC_checkGC(L); + } + lua_unlock(L); +} + + +LUA_API void lua_pushboolean (lua_State *L, int b) { + lua_lock(L); + if (b) + setbtvalue(s2v(L->top.p)); + else + setbfvalue(s2v(L->top.p)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { + lua_lock(L); + setpvalue(s2v(L->top.p), p); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API int lua_pushthread (lua_State *L) { + lua_lock(L); + setthvalue(L, s2v(L->top.p), L); + api_incr_top(L); + lua_unlock(L); + return (G(L)->mainthread == L); +} + + + +/* +** get functions (Lua -> stack) +*/ + + +l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) { + const TValue *slot; + TString *str = luaS_new(L, k); + if (luaV_fastget(L, t, str, slot, luaH_getstr)) { + setobj2s(L, L->top.p, slot); + api_incr_top(L); + } + else { + setsvalue2s(L, L->top.p, str); + api_incr_top(L); + luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot); + } + lua_unlock(L); + return ttype(s2v(L->top.p - 1)); +} + + +/* +** Get the global table in the registry. Since all predefined +** indices in the registry were inserted right when the registry +** was created and never removed, they must always be in the array +** part of the registry. +*/ +#define getGtable(L) \ + (&hvalue(&G(L)->l_registry)->array[LUA_RIDX_GLOBALS - 1]) + + +LUA_API int lua_getglobal (lua_State *L, const char *name) { + const TValue *G; + lua_lock(L); + G = getGtable(L); + return auxgetstr(L, G, name); +} + + +LUA_API int lua_gettable (lua_State *L, int idx) { + const TValue *slot; + TValue *t; + lua_lock(L); + t = index2value(L, idx); + if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) { + setobj2s(L, L->top.p - 1, slot); + } + else + luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot); + lua_unlock(L); + return ttype(s2v(L->top.p - 1)); +} + + +LUA_API int lua_getfield (lua_State *L, int idx, const char *k) { + lua_lock(L); + return auxgetstr(L, index2value(L, idx), k); +} + + +LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { + TValue *t; + const TValue *slot; + lua_lock(L); + t = index2value(L, idx); + if (luaV_fastgeti(L, t, n, slot)) { + setobj2s(L, L->top.p, slot); + } + else { + TValue aux; + setivalue(&aux, n); + luaV_finishget(L, t, &aux, L->top.p, slot); + } + api_incr_top(L); + lua_unlock(L); + return ttype(s2v(L->top.p - 1)); +} + + +l_sinline int finishrawget (lua_State *L, const TValue *val) { + if (isempty(val)) /* avoid copying empty items to the stack */ + setnilvalue(s2v(L->top.p)); + else + setobj2s(L, L->top.p, val); + api_incr_top(L); + lua_unlock(L); + return ttype(s2v(L->top.p - 1)); +} + + +static Table *gettable (lua_State *L, int idx) { + TValue *t = index2value(L, idx); + api_check(L, ttistable(t), "table expected"); + return hvalue(t); +} + + +LUA_API int lua_rawget (lua_State *L, int idx) { + Table *t; + const TValue *val; + lua_lock(L); + api_checknelems(L, 1); + t = gettable(L, idx); + val = luaH_get(t, s2v(L->top.p - 1)); + L->top.p--; /* remove key */ + return finishrawget(L, val); +} + + +LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) { + Table *t; + lua_lock(L); + t = gettable(L, idx); + return finishrawget(L, luaH_getint(t, n)); +} + + +LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) { + Table *t; + TValue k; + lua_lock(L); + t = gettable(L, idx); + setpvalue(&k, cast_voidp(p)); + return finishrawget(L, luaH_get(t, &k)); +} + + +LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { + Table *t; + lua_lock(L); + t = luaH_new(L); + sethvalue2s(L, L->top.p, t); + api_incr_top(L); + if (narray > 0 || nrec > 0) + luaH_resize(L, t, narray, nrec); + luaC_checkGC(L); + lua_unlock(L); +} + + +LUA_API int lua_getmetatable (lua_State *L, int objindex) { + const TValue *obj; + Table *mt; + int res = 0; + lua_lock(L); + obj = index2value(L, objindex); + switch (ttype(obj)) { + case LUA_TTABLE: + mt = hvalue(obj)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj)->metatable; + break; + default: + mt = G(L)->mt[ttype(obj)]; + break; + } + if (mt != NULL) { + sethvalue2s(L, L->top.p, mt); + api_incr_top(L); + res = 1; + } + lua_unlock(L); + return res; +} + + +LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) { + TValue *o; + int t; + lua_lock(L); + o = index2value(L, idx); + api_check(L, ttisfulluserdata(o), "full userdata expected"); + if (n <= 0 || n > uvalue(o)->nuvalue) { + setnilvalue(s2v(L->top.p)); + t = LUA_TNONE; + } + else { + setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv); + t = ttype(s2v(L->top.p)); + } + api_incr_top(L); + lua_unlock(L); + return t; +} + + +/* +** set functions (stack -> Lua) +*/ + +/* +** t[k] = value at the top of the stack (where 'k' is a string) +*/ +static void auxsetstr (lua_State *L, const TValue *t, const char *k) { + const TValue *slot; + TString *str = luaS_new(L, k); + api_checknelems(L, 1); + if (luaV_fastget(L, t, str, slot, luaH_getstr)) { + luaV_finishfastset(L, t, slot, s2v(L->top.p - 1)); + L->top.p--; /* pop value */ + } + else { + setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */ + api_incr_top(L); + luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot); + L->top.p -= 2; /* pop value and key */ + } + lua_unlock(L); /* lock done by caller */ +} + + +LUA_API void lua_setglobal (lua_State *L, const char *name) { + const TValue *G; + lua_lock(L); /* unlock done in 'auxsetstr' */ + G = getGtable(L); + auxsetstr(L, G, name); +} + + +LUA_API void lua_settable (lua_State *L, int idx) { + TValue *t; + const TValue *slot; + lua_lock(L); + api_checknelems(L, 2); + t = index2value(L, idx); + if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) { + luaV_finishfastset(L, t, slot, s2v(L->top.p - 1)); + } + else + luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot); + L->top.p -= 2; /* pop index and value */ + lua_unlock(L); +} + + +LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { + lua_lock(L); /* unlock done in 'auxsetstr' */ + auxsetstr(L, index2value(L, idx), k); +} + + +LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { + TValue *t; + const TValue *slot; + lua_lock(L); + api_checknelems(L, 1); + t = index2value(L, idx); + if (luaV_fastgeti(L, t, n, slot)) { + luaV_finishfastset(L, t, slot, s2v(L->top.p - 1)); + } + else { + TValue aux; + setivalue(&aux, n); + luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot); + } + L->top.p--; /* pop value */ + lua_unlock(L); +} + + +static void aux_rawset (lua_State *L, int idx, TValue *key, int n) { + Table *t; + lua_lock(L); + api_checknelems(L, n); + t = gettable(L, idx); + luaH_set(L, t, key, s2v(L->top.p - 1)); + invalidateTMcache(t); + luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1)); + L->top.p -= n; + lua_unlock(L); +} + + +LUA_API void lua_rawset (lua_State *L, int idx) { + aux_rawset(L, idx, s2v(L->top.p - 2), 2); +} + + +LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) { + TValue k; + setpvalue(&k, cast_voidp(p)); + aux_rawset(L, idx, &k, 1); +} + + +LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) { + Table *t; + lua_lock(L); + api_checknelems(L, 1); + t = gettable(L, idx); + luaH_setint(L, t, n, s2v(L->top.p - 1)); + luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1)); + L->top.p--; + lua_unlock(L); +} + + +LUA_API int lua_setmetatable (lua_State *L, int objindex) { + TValue *obj; + Table *mt; + lua_lock(L); + api_checknelems(L, 1); + obj = index2value(L, objindex); + if (ttisnil(s2v(L->top.p - 1))) + mt = NULL; + else { + api_check(L, ttistable(s2v(L->top.p - 1)), "table expected"); + mt = hvalue(s2v(L->top.p - 1)); + } + switch (ttype(obj)) { + case LUA_TTABLE: { + hvalue(obj)->metatable = mt; + if (mt) { + luaC_objbarrier(L, gcvalue(obj), mt); + luaC_checkfinalizer(L, gcvalue(obj), mt); + } + break; + } + case LUA_TUSERDATA: { + uvalue(obj)->metatable = mt; + if (mt) { + luaC_objbarrier(L, uvalue(obj), mt); + luaC_checkfinalizer(L, gcvalue(obj), mt); + } + break; + } + default: { + G(L)->mt[ttype(obj)] = mt; + break; + } + } + L->top.p--; + lua_unlock(L); + return 1; +} + + +LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) { + TValue *o; + int res; + lua_lock(L); + api_checknelems(L, 1); + o = index2value(L, idx); + api_check(L, ttisfulluserdata(o), "full userdata expected"); + if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue))) + res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */ + else { + setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1)); + luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1)); + res = 1; + } + L->top.p--; + lua_unlock(L); + return res; +} + + +/* +** 'load' and 'call' functions (run Lua code) +*/ + + +#define checkresults(L,na,nr) \ + api_check(L, (nr) == LUA_MULTRET \ + || (L->ci->top.p - L->top.p >= (nr) - (na)), \ + "results from function overflow current stack size") + + +LUA_API void lua_callk (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k) { + StkId func; + lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); + api_checknelems(L, nargs+1); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); + checkresults(L, nargs, nresults); + func = L->top.p - (nargs+1); + if (k != NULL && yieldable(L)) { /* need to prepare continuation? */ + L->ci->u.c.k = k; /* save continuation */ + L->ci->u.c.ctx = ctx; /* save context */ + luaD_call(L, func, nresults); /* do the call */ + } + else /* no continuation or no yieldable */ + luaD_callnoyield(L, func, nresults); /* just do the call */ + adjustresults(L, nresults); + lua_unlock(L); +} + + + +/* +** Execute a protected call. +*/ +struct CallS { /* data to 'f_call' */ + StkId func; + int nresults; +}; + + +static void f_call (lua_State *L, void *ud) { + struct CallS *c = cast(struct CallS *, ud); + luaD_callnoyield(L, c->func, c->nresults); +} + + + +LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, + lua_KContext ctx, lua_KFunction k) { + struct CallS c; + int status; + ptrdiff_t func; + lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); + api_checknelems(L, nargs+1); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); + checkresults(L, nargs, nresults); + if (errfunc == 0) + func = 0; + else { + StkId o = index2stack(L, errfunc); + api_check(L, ttisfunction(s2v(o)), "error handler must be a function"); + func = savestack(L, o); + } + c.func = L->top.p - (nargs+1); /* function to be called */ + if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */ + c.nresults = nresults; /* do a 'conventional' protected call */ + status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + } + else { /* prepare continuation (call is already protected by 'resume') */ + CallInfo *ci = L->ci; + ci->u.c.k = k; /* save continuation */ + ci->u.c.ctx = ctx; /* save context */ + /* save information for error recovery */ + ci->u2.funcidx = cast_int(savestack(L, c.func)); + ci->u.c.old_errfunc = L->errfunc; + L->errfunc = func; + setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */ + ci->callstatus |= CIST_YPCALL; /* function can do error recovery */ + luaD_call(L, c.func, nresults); /* do the call */ + ci->callstatus &= ~CIST_YPCALL; + L->errfunc = ci->u.c.old_errfunc; + status = LUA_OK; /* if it is here, there were no errors */ + } + adjustresults(L, nresults); + lua_unlock(L); + return status; +} + + +LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, + const char *chunkname, const char *mode) { + ZIO z; + int status; + lua_lock(L); + if (!chunkname) chunkname = "?"; + luaZ_init(L, &z, reader, data); + status = luaD_protectedparser(L, &z, chunkname, mode); + if (status == LUA_OK) { /* no errors? */ + LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */ + if (f->nupvalues >= 1) { /* does it have an upvalue? */ + /* get global table from registry */ + const TValue *gt = getGtable(L); + /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ + setobj(L, f->upvals[0]->v.p, gt); + luaC_barrier(L, f->upvals[0], gt); + } + } + lua_unlock(L); + return status; +} + + +LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { + int status; + TValue *o; + lua_lock(L); + api_checknelems(L, 1); + o = s2v(L->top.p - 1); + if (isLfunction(o)) + status = luaU_dump(L, getproto(o), writer, data, strip); + else + status = 1; + lua_unlock(L); + return status; +} + + +LUA_API int lua_status (lua_State *L) { + return L->status; +} + + +/* +** Garbage-collection function +*/ +LUA_API int lua_gc (lua_State *L, int what, ...) { + va_list argp; + int res = 0; + global_State *g = G(L); + if (g->gcstp & GCSTPGC) /* internal stop? */ + return -1; /* all options are invalid when stopped */ + lua_lock(L); + va_start(argp, what); + switch (what) { + case LUA_GCSTOP: { + g->gcstp = GCSTPUSR; /* stopped by the user */ + break; + } + case LUA_GCRESTART: { + luaE_setdebt(g, 0); + g->gcstp = 0; /* (GCSTPGC must be already zero here) */ + break; + } + case LUA_GCCOLLECT: { + luaC_fullgc(L, 0); + break; + } + case LUA_GCCOUNT: { + /* GC values are expressed in Kbytes: #bytes/2^10 */ + res = cast_int(gettotalbytes(g) >> 10); + break; + } + case LUA_GCCOUNTB: { + res = cast_int(gettotalbytes(g) & 0x3ff); + break; + } + case LUA_GCSTEP: { + int data = va_arg(argp, int); + l_mem debt = 1; /* =1 to signal that it did an actual step */ + lu_byte oldstp = g->gcstp; + g->gcstp = 0; /* allow GC to run (GCSTPGC must be zero here) */ + if (data == 0) { + luaE_setdebt(g, 0); /* do a basic step */ + luaC_step(L); + } + else { /* add 'data' to total debt */ + debt = cast(l_mem, data) * 1024 + g->GCdebt; + luaE_setdebt(g, debt); + luaC_checkGC(L); + } + g->gcstp = oldstp; /* restore previous state */ + if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ + break; + } + case LUA_GCSETPAUSE: { + int data = va_arg(argp, int); + res = getgcparam(g->gcpause); + setgcparam(g->gcpause, data); + break; + } + case LUA_GCSETSTEPMUL: { + int data = va_arg(argp, int); + res = getgcparam(g->gcstepmul); + setgcparam(g->gcstepmul, data); + break; + } + case LUA_GCISRUNNING: { + res = gcrunning(g); + break; + } + case LUA_GCGEN: { + int minormul = va_arg(argp, int); + int majormul = va_arg(argp, int); + res = isdecGCmodegen(g) ? LUA_GCGEN : LUA_GCINC; + if (minormul != 0) + g->genminormul = minormul; + if (majormul != 0) + setgcparam(g->genmajormul, majormul); + luaC_changemode(L, KGC_GEN); + break; + } + case LUA_GCINC: { + int pause = va_arg(argp, int); + int stepmul = va_arg(argp, int); + int stepsize = va_arg(argp, int); + res = isdecGCmodegen(g) ? LUA_GCGEN : LUA_GCINC; + if (pause != 0) + setgcparam(g->gcpause, pause); + if (stepmul != 0) + setgcparam(g->gcstepmul, stepmul); + if (stepsize != 0) + g->gcstepsize = stepsize; + luaC_changemode(L, KGC_INC); + break; + } + default: res = -1; /* invalid option */ + } + va_end(argp); + lua_unlock(L); + return res; +} + + + +/* +** miscellaneous functions +*/ + + +LUA_API int lua_error (lua_State *L) { + TValue *errobj; + lua_lock(L); + errobj = s2v(L->top.p - 1); + api_checknelems(L, 1); + /* error object is the memory error message? */ + if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg)) + luaM_error(L); /* raise a memory error */ + else + luaG_errormsg(L); /* raise a regular error */ + /* code unreachable; will unlock when control actually leaves the kernel */ + return 0; /* to avoid warnings */ +} + + +LUA_API int lua_next (lua_State *L, int idx) { + Table *t; + int more; + lua_lock(L); + api_checknelems(L, 1); + t = gettable(L, idx); + more = luaH_next(L, t, L->top.p - 1); + if (more) { + api_incr_top(L); + } + else /* no more elements */ + L->top.p -= 1; /* remove key */ + lua_unlock(L); + return more; +} + + +LUA_API void lua_toclose (lua_State *L, int idx) { + int nresults; + StkId o; + lua_lock(L); + o = index2stack(L, idx); + nresults = L->ci->nresults; + api_check(L, L->tbclist.p < o, "given index below or equal a marked one"); + luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */ + if (!hastocloseCfunc(nresults)) /* function not marked yet? */ + L->ci->nresults = codeNresults(nresults); /* mark it */ + lua_assert(hastocloseCfunc(L->ci->nresults)); + lua_unlock(L); +} + + +LUA_API void lua_concat (lua_State *L, int n) { + lua_lock(L); + api_checknelems(L, n); + if (n > 0) + luaV_concat(L, n); + else { /* nothing to concatenate */ + setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */ + api_incr_top(L); + } + luaC_checkGC(L); + lua_unlock(L); +} + + +LUA_API void lua_len (lua_State *L, int idx) { + TValue *t; + lua_lock(L); + t = index2value(L, idx); + luaV_objlen(L, L->top.p, t); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { + lua_Alloc f; + lua_lock(L); + if (ud) *ud = G(L)->ud; + f = G(L)->frealloc; + lua_unlock(L); + return f; +} + + +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { + lua_lock(L); + G(L)->ud = ud; + G(L)->frealloc = f; + lua_unlock(L); +} + + +void lua_setwarnf (lua_State *L, lua_WarnFunction f, void *ud) { + lua_lock(L); + G(L)->ud_warn = ud; + G(L)->warnf = f; + lua_unlock(L); +} + + +void lua_warning (lua_State *L, const char *msg, int tocont) { + lua_lock(L); + luaE_warning(L, msg, tocont); + lua_unlock(L); +} + + + +LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) { + Udata *u; + lua_lock(L); + api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value"); + u = luaS_newudata(L, size, nuvalue); + setuvalue(L, s2v(L->top.p), u); + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return getudatamem(u); +} + + + +static const char *aux_upvalue (TValue *fi, int n, TValue **val, + GCObject **owner) { + switch (ttypetag(fi)) { + case LUA_VCCL: { /* C closure */ + CClosure *f = clCvalue(fi); + if (!(cast_uint(n) - 1u < cast_uint(f->nupvalues))) + return NULL; /* 'n' not in [1, f->nupvalues] */ + *val = &f->upvalue[n-1]; + if (owner) *owner = obj2gco(f); + return ""; + } + case LUA_VLCL: { /* Lua closure */ + LClosure *f = clLvalue(fi); + TString *name; + Proto *p = f->p; + if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues))) + return NULL; /* 'n' not in [1, p->sizeupvalues] */ + *val = f->upvals[n-1]->v.p; + if (owner) *owner = obj2gco(f->upvals[n - 1]); + name = p->upvalues[n-1].name; + return (name == NULL) ? "(no name)" : getstr(name); + } + default: return NULL; /* not a closure */ + } +} + + +LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val = NULL; /* to avoid warnings */ + lua_lock(L); + name = aux_upvalue(index2value(L, funcindex), n, &val, NULL); + if (name) { + setobj2s(L, L->top.p, val); + api_incr_top(L); + } + lua_unlock(L); + return name; +} + + +LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val = NULL; /* to avoid warnings */ + GCObject *owner = NULL; /* to avoid warnings */ + TValue *fi; + lua_lock(L); + fi = index2value(L, funcindex); + api_checknelems(L, 1); + name = aux_upvalue(fi, n, &val, &owner); + if (name) { + L->top.p--; + setobj(L, val, s2v(L->top.p)); + luaC_barrier(L, owner, val); + } + lua_unlock(L); + return name; +} + + +static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { + static const UpVal *const nullup = NULL; + LClosure *f; + TValue *fi = index2value(L, fidx); + api_check(L, ttisLclosure(fi), "Lua function expected"); + f = clLvalue(fi); + if (pf) *pf = f; + if (1 <= n && n <= f->p->sizeupvalues) + return &f->upvals[n - 1]; /* get its upvalue pointer */ + else + return (UpVal**)&nullup; +} + + +LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { + TValue *fi = index2value(L, fidx); + switch (ttypetag(fi)) { + case LUA_VLCL: { /* lua closure */ + return *getupvalref(L, fidx, n, NULL); + } + case LUA_VCCL: { /* C closure */ + CClosure *f = clCvalue(fi); + if (1 <= n && n <= f->nupvalues) + return &f->upvalue[n - 1]; + /* else */ + } /* FALLTHROUGH */ + case LUA_VLCF: + return NULL; /* light C functions have no upvalues */ + default: { + api_check(L, 0, "function expected"); + return NULL; + } + } +} + + +LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, + int fidx2, int n2) { + LClosure *f1; + UpVal **up1 = getupvalref(L, fidx1, n1, &f1); + UpVal **up2 = getupvalref(L, fidx2, n2, NULL); + api_check(L, *up1 != NULL && *up2 != NULL, "invalid upvalue index"); + *up1 = *up2; + luaC_objbarrier(L, f1, *up1); +} + + diff --git a/vendor/lua-src/lua-5.4.6/lapi.h b/vendor/lua-src/lua-5.4.6/lapi.h new file mode 100644 index 0000000000000..a742427cdc796 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lapi.h @@ -0,0 +1,52 @@ +/* +** $Id: lapi.h $ +** Auxiliary functions from Lua API +** See Copyright Notice in lua.h +*/ + +#ifndef lapi_h +#define lapi_h + + +#include "llimits.h" +#include "lstate.h" + + +/* Increments 'L->top.p', checking for stack overflows */ +#define api_incr_top(L) {L->top.p++; \ + api_check(L, L->top.p <= L->ci->top.p, \ + "stack overflow");} + + +/* +** If a call returns too many multiple returns, the callee may not have +** stack space to accommodate all results. In this case, this macro +** increases its stack space ('L->ci->top.p'). +*/ +#define adjustresults(L,nres) \ + { if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \ + L->ci->top.p = L->top.p; } + + +/* Ensure the stack has at least 'n' elements */ +#define api_checknelems(L,n) \ + api_check(L, (n) < (L->top.p - L->ci->func.p), \ + "not enough elements in the stack") + + +/* +** To reduce the overhead of returning from C functions, the presence of +** to-be-closed variables in these functions is coded in the CallInfo's +** field 'nresults', in a way that functions with no to-be-closed variables +** with zero, one, or "all" wanted results have no overhead. Functions +** with other number of wanted results, as well as functions with +** variables to be closed, have an extra check. +*/ + +#define hastocloseCfunc(n) ((n) < LUA_MULTRET) + +/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */ +#define codeNresults(n) (-(n) - 3) +#define decodeNresults(n) (-(n) - 3) + +#endif diff --git a/vendor/lua-src/lua-5.4.6/lauxlib.c b/vendor/lua-src/lua-5.4.6/lauxlib.c new file mode 100644 index 0000000000000..4ca6c65488991 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lauxlib.c @@ -0,0 +1,1112 @@ +/* +** $Id: lauxlib.c $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + +#define lauxlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include + + +/* +** This file uses only the official API of Lua. +** Any function declared here could be written as an application function. +*/ + +#include "lua.h" + +#include "lauxlib.h" + + +#if !defined(MAX_SIZET) +/* maximum value for size_t */ +#define MAX_SIZET ((size_t)(~(size_t)0)) +#endif + + +/* +** {====================================================== +** Traceback +** ======================================================= +*/ + + +#define LEVELS1 10 /* size of the first part of the stack */ +#define LEVELS2 11 /* size of the second part of the stack */ + + + +/* +** Search for 'objidx' in table at index -1. ('objidx' must be an +** absolute index.) Return 1 + string at top if it found a good name. +*/ +static int findfield (lua_State *L, int objidx, int level) { + if (level == 0 || !lua_istable(L, -1)) + return 0; /* not found */ + lua_pushnil(L); /* start 'next' loop */ + while (lua_next(L, -2)) { /* for each pair in table */ + if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ + if (lua_rawequal(L, objidx, -1)) { /* found object? */ + lua_pop(L, 1); /* remove value (but keep name) */ + return 1; + } + else if (findfield(L, objidx, level - 1)) { /* try recursively */ + /* stack: lib_name, lib_table, field_name (top) */ + lua_pushliteral(L, "."); /* place '.' between the two names */ + lua_replace(L, -3); /* (in the slot occupied by table) */ + lua_concat(L, 3); /* lib_name.field_name */ + return 1; + } + } + lua_pop(L, 1); /* remove value */ + } + return 0; /* not found */ +} + + +/* +** Search for a name for a function in all loaded modules +*/ +static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { + int top = lua_gettop(L); + lua_getinfo(L, "f", ar); /* push function */ + lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + if (findfield(L, top + 1, 2)) { + const char *name = lua_tostring(L, -1); + if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */ + lua_pushstring(L, name + 3); /* push name without prefix */ + lua_remove(L, -2); /* remove original name */ + } + lua_copy(L, -1, top + 1); /* copy name to proper place */ + lua_settop(L, top + 1); /* remove table "loaded" and name copy */ + return 1; + } + else { + lua_settop(L, top); /* remove function and global table */ + return 0; + } +} + + +static void pushfuncname (lua_State *L, lua_Debug *ar) { + if (pushglobalfuncname(L, ar)) { /* try first a global name */ + lua_pushfstring(L, "function '%s'", lua_tostring(L, -1)); + lua_remove(L, -2); /* remove name */ + } + else if (*ar->namewhat != '\0') /* is there a name from code? */ + lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */ + else if (*ar->what == 'm') /* main? */ + lua_pushliteral(L, "main chunk"); + else if (*ar->what != 'C') /* for Lua functions, use */ + lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); + else /* nothing left... */ + lua_pushliteral(L, "?"); +} + + +static int lastlevel (lua_State *L) { + lua_Debug ar; + int li = 1, le = 1; + /* find an upper bound */ + while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } + /* do a binary search */ + while (li < le) { + int m = (li + le)/2; + if (lua_getstack(L, m, &ar)) li = m + 1; + else le = m; + } + return le - 1; +} + + +LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, + const char *msg, int level) { + luaL_Buffer b; + lua_Debug ar; + int last = lastlevel(L1); + int limit2show = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1; + luaL_buffinit(L, &b); + if (msg) { + luaL_addstring(&b, msg); + luaL_addchar(&b, '\n'); + } + luaL_addstring(&b, "stack traceback:"); + while (lua_getstack(L1, level++, &ar)) { + if (limit2show-- == 0) { /* too many levels? */ + int n = last - level - LEVELS2 + 1; /* number of levels to skip */ + lua_pushfstring(L, "\n\t...\t(skipping %d levels)", n); + luaL_addvalue(&b); /* add warning about skip */ + level += n; /* and skip to last levels */ + } + else { + lua_getinfo(L1, "Slnt", &ar); + if (ar.currentline <= 0) + lua_pushfstring(L, "\n\t%s: in ", ar.short_src); + else + lua_pushfstring(L, "\n\t%s:%d: in ", ar.short_src, ar.currentline); + luaL_addvalue(&b); + pushfuncname(L, &ar); + luaL_addvalue(&b); + if (ar.istailcall) + luaL_addstring(&b, "\n\t(...tail calls...)"); + } + } + luaL_pushresult(&b); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Error-report functions +** ======================================================= +*/ + +LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) { + lua_Debug ar; + if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ + return luaL_error(L, "bad argument #%d (%s)", arg, extramsg); + lua_getinfo(L, "n", &ar); + if (strcmp(ar.namewhat, "method") == 0) { + arg--; /* do not count 'self' */ + if (arg == 0) /* error is in the self argument itself? */ + return luaL_error(L, "calling '%s' on bad self (%s)", + ar.name, extramsg); + } + if (ar.name == NULL) + ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; + return luaL_error(L, "bad argument #%d to '%s' (%s)", + arg, ar.name, extramsg); +} + + +LUALIB_API int luaL_typeerror (lua_State *L, int arg, const char *tname) { + const char *msg; + const char *typearg; /* name for the type of the actual argument */ + if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) + typearg = lua_tostring(L, -1); /* use the given type name */ + else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA) + typearg = "light userdata"; /* special name for messages */ + else + typearg = luaL_typename(L, arg); /* standard name */ + msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg); + return luaL_argerror(L, arg, msg); +} + + +static void tag_error (lua_State *L, int arg, int tag) { + luaL_typeerror(L, arg, lua_typename(L, tag)); +} + + +/* +** The use of 'lua_pushfstring' ensures this function does not +** need reserved stack space when called. +*/ +LUALIB_API void luaL_where (lua_State *L, int level) { + lua_Debug ar; + if (lua_getstack(L, level, &ar)) { /* check function at level */ + lua_getinfo(L, "Sl", &ar); /* get info about it */ + if (ar.currentline > 0) { /* is there info? */ + lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); + return; + } + } + lua_pushfstring(L, ""); /* else, no information available... */ +} + + +/* +** Again, the use of 'lua_pushvfstring' ensures this function does +** not need reserved stack space when called. (At worst, it generates +** an error with "stack overflow" instead of the given message.) +*/ +LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + luaL_where(L, 1); + lua_pushvfstring(L, fmt, argp); + va_end(argp); + lua_concat(L, 2); + return lua_error(L); +} + + +LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { + int en = errno; /* calls to Lua API may change this value */ + if (stat) { + lua_pushboolean(L, 1); + return 1; + } + else { + luaL_pushfail(L); + if (fname) + lua_pushfstring(L, "%s: %s", fname, strerror(en)); + else + lua_pushstring(L, strerror(en)); + lua_pushinteger(L, en); + return 3; + } +} + + +#if !defined(l_inspectstat) /* { */ + +#if defined(LUA_USE_POSIX) + +#include + +/* +** use appropriate macros to interpret 'pclose' return status +*/ +#define l_inspectstat(stat,what) \ + if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ + else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } + +#else + +#define l_inspectstat(stat,what) /* no op */ + +#endif + +#endif /* } */ + + +LUALIB_API int luaL_execresult (lua_State *L, int stat) { + if (stat != 0 && errno != 0) /* error with an 'errno'? */ + return luaL_fileresult(L, 0, NULL); + else { + const char *what = "exit"; /* type of termination */ + l_inspectstat(stat, what); /* interpret result */ + if (*what == 'e' && stat == 0) /* successful termination? */ + lua_pushboolean(L, 1); + else + luaL_pushfail(L); + lua_pushstring(L, what); + lua_pushinteger(L, stat); + return 3; /* return true/fail,what,code */ + } +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Userdata's metatable manipulation +** ======================================================= +*/ + +LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { + if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */ + return 0; /* leave previous value on top, but return 0 */ + lua_pop(L, 1); + lua_createtable(L, 0, 2); /* create metatable */ + lua_pushstring(L, tname); + lua_setfield(L, -2, "__name"); /* metatable.__name = tname */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ + return 1; +} + + +LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) { + luaL_getmetatable(L, tname); + lua_setmetatable(L, -2); +} + + +LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) { + void *p = lua_touserdata(L, ud); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + luaL_getmetatable(L, tname); /* get correct metatable */ + if (!lua_rawequal(L, -1, -2)) /* not the same? */ + p = NULL; /* value is a userdata with wrong metatable */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } + return NULL; /* value is not a userdata with a metatable */ +} + + +LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { + void *p = luaL_testudata(L, ud, tname); + luaL_argexpected(L, p != NULL, ud, tname); + return p; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Argument check functions +** ======================================================= +*/ + +LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, + const char *const lst[]) { + const char *name = (def) ? luaL_optstring(L, arg, def) : + luaL_checkstring(L, arg); + int i; + for (i=0; lst[i]; i++) + if (strcmp(lst[i], name) == 0) + return i; + return luaL_argerror(L, arg, + lua_pushfstring(L, "invalid option '%s'", name)); +} + + +/* +** Ensures the stack has at least 'space' extra slots, raising an error +** if it cannot fulfill the request. (The error handling needs a few +** extra slots to format the error message. In case of an error without +** this extra space, Lua will generate the same 'stack overflow' error, +** but without 'msg'.) +*/ +LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { + if (l_unlikely(!lua_checkstack(L, space))) { + if (msg) + luaL_error(L, "stack overflow (%s)", msg); + else + luaL_error(L, "stack overflow"); + } +} + + +LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { + if (l_unlikely(lua_type(L, arg) != t)) + tag_error(L, arg, t); +} + + +LUALIB_API void luaL_checkany (lua_State *L, int arg) { + if (l_unlikely(lua_type(L, arg) == LUA_TNONE)) + luaL_argerror(L, arg, "value expected"); +} + + +LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { + const char *s = lua_tolstring(L, arg, len); + if (l_unlikely(!s)) tag_error(L, arg, LUA_TSTRING); + return s; +} + + +LUALIB_API const char *luaL_optlstring (lua_State *L, int arg, + const char *def, size_t *len) { + if (lua_isnoneornil(L, arg)) { + if (len) + *len = (def ? strlen(def) : 0); + return def; + } + else return luaL_checklstring(L, arg, len); +} + + +LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { + int isnum; + lua_Number d = lua_tonumberx(L, arg, &isnum); + if (l_unlikely(!isnum)) + tag_error(L, arg, LUA_TNUMBER); + return d; +} + + +LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) { + return luaL_opt(L, luaL_checknumber, arg, def); +} + + +static void interror (lua_State *L, int arg) { + if (lua_isnumber(L, arg)) + luaL_argerror(L, arg, "number has no integer representation"); + else + tag_error(L, arg, LUA_TNUMBER); +} + + +LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { + int isnum; + lua_Integer d = lua_tointegerx(L, arg, &isnum); + if (l_unlikely(!isnum)) { + interror(L, arg); + } + return d; +} + + +LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg, + lua_Integer def) { + return luaL_opt(L, luaL_checkinteger, arg, def); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + +/* userdata to box arbitrary data */ +typedef struct UBox { + void *box; + size_t bsize; +} UBox; + + +static void *resizebox (lua_State *L, int idx, size_t newsize) { + void *ud; + lua_Alloc allocf = lua_getallocf(L, &ud); + UBox *box = (UBox *)lua_touserdata(L, idx); + void *temp = allocf(ud, box->box, box->bsize, newsize); + if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */ + lua_pushliteral(L, "not enough memory"); + lua_error(L); /* raise a memory error */ + } + box->box = temp; + box->bsize = newsize; + return temp; +} + + +static int boxgc (lua_State *L) { + resizebox(L, 1, 0); + return 0; +} + + +static const luaL_Reg boxmt[] = { /* box metamethods */ + {"__gc", boxgc}, + {"__close", boxgc}, + {NULL, NULL} +}; + + +static void newbox (lua_State *L) { + UBox *box = (UBox *)lua_newuserdatauv(L, sizeof(UBox), 0); + box->box = NULL; + box->bsize = 0; + if (luaL_newmetatable(L, "_UBOX*")) /* creating metatable? */ + luaL_setfuncs(L, boxmt, 0); /* set its metamethods */ + lua_setmetatable(L, -2); +} + + +/* +** check whether buffer is using a userdata on the stack as a temporary +** buffer +*/ +#define buffonstack(B) ((B)->b != (B)->init.b) + + +/* +** Whenever buffer is accessed, slot 'idx' must either be a box (which +** cannot be NULL) or it is a placeholder for the buffer. +*/ +#define checkbufferlevel(B,idx) \ + lua_assert(buffonstack(B) ? lua_touserdata(B->L, idx) != NULL \ + : lua_touserdata(B->L, idx) == (void*)B) + + +/* +** Compute new size for buffer 'B', enough to accommodate extra 'sz' +** bytes. (The test for "not big enough" also gets the case when the +** computation of 'newsize' overflows.) +*/ +static size_t newbuffsize (luaL_Buffer *B, size_t sz) { + size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */ + if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */ + return luaL_error(B->L, "buffer too large"); + if (newsize < B->n + sz) /* not big enough? */ + newsize = B->n + sz; + return newsize; +} + + +/* +** Returns a pointer to a free area with at least 'sz' bytes in buffer +** 'B'. 'boxidx' is the relative position in the stack where is the +** buffer's box or its placeholder. +*/ +static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) { + checkbufferlevel(B, boxidx); + if (B->size - B->n >= sz) /* enough space? */ + return B->b + B->n; + else { + lua_State *L = B->L; + char *newbuff; + size_t newsize = newbuffsize(B, sz); + /* create larger buffer */ + if (buffonstack(B)) /* buffer already has a box? */ + newbuff = (char *)resizebox(L, boxidx, newsize); /* resize it */ + else { /* no box yet */ + lua_remove(L, boxidx); /* remove placeholder */ + newbox(L); /* create a new box */ + lua_insert(L, boxidx); /* move box to its intended position */ + lua_toclose(L, boxidx); + newbuff = (char *)resizebox(L, boxidx, newsize); + memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ + } + B->b = newbuff; + B->size = newsize; + return newbuff + B->n; + } +} + +/* +** returns a pointer to a free area with at least 'sz' bytes +*/ +LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { + return prepbuffsize(B, sz, -1); +} + + +LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { + if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */ + char *b = prepbuffsize(B, l, -1); + memcpy(b, s, l * sizeof(char)); + luaL_addsize(B, l); + } +} + + +LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { + luaL_addlstring(B, s, strlen(s)); +} + + +LUALIB_API void luaL_pushresult (luaL_Buffer *B) { + lua_State *L = B->L; + checkbufferlevel(B, -1); + lua_pushlstring(L, B->b, B->n); + if (buffonstack(B)) + lua_closeslot(L, -2); /* close the box */ + lua_remove(L, -2); /* remove box or placeholder from the stack */ +} + + +LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { + luaL_addsize(B, sz); + luaL_pushresult(B); +} + + +/* +** 'luaL_addvalue' is the only function in the Buffer system where the +** box (if existent) is not on the top of the stack. So, instead of +** calling 'luaL_addlstring', it replicates the code using -2 as the +** last argument to 'prepbuffsize', signaling that the box is (or will +** be) below the string being added to the buffer. (Box creation can +** trigger an emergency GC, so we should not remove the string from the +** stack before we have the space guaranteed.) +*/ +LUALIB_API void luaL_addvalue (luaL_Buffer *B) { + lua_State *L = B->L; + size_t len; + const char *s = lua_tolstring(L, -1, &len); + char *b = prepbuffsize(B, len, -2); + memcpy(b, s, len * sizeof(char)); + luaL_addsize(B, len); + lua_pop(L, 1); /* pop string */ +} + + +LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { + B->L = L; + B->b = B->init.b; + B->n = 0; + B->size = LUAL_BUFFERSIZE; + lua_pushlightuserdata(L, (void*)B); /* push placeholder */ +} + + +LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { + luaL_buffinit(L, B); + return prepbuffsize(B, sz, -1); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Reference system +** ======================================================= +*/ + +/* index of free-list header (after the predefined values) */ +#define freelist (LUA_RIDX_LAST + 1) + +/* +** The previously freed references form a linked list: +** t[freelist] is the index of a first free index, or zero if list is +** empty; t[t[freelist]] is the index of the second element; etc. +*/ +LUALIB_API int luaL_ref (lua_State *L, int t) { + int ref; + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* remove from stack */ + return LUA_REFNIL; /* 'nil' has a unique fixed reference */ + } + t = lua_absindex(L, t); + if (lua_rawgeti(L, t, freelist) == LUA_TNIL) { /* first access? */ + ref = 0; /* list is empty */ + lua_pushinteger(L, 0); /* initialize as an empty list */ + lua_rawseti(L, t, freelist); /* ref = t[freelist] = 0 */ + } + else { /* already initialized */ + lua_assert(lua_isinteger(L, -1)); + ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ + } + lua_pop(L, 1); /* remove element from stack */ + if (ref != 0) { /* any free element? */ + lua_rawgeti(L, t, ref); /* remove it from list */ + lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ + } + else /* no free elements */ + ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ + lua_rawseti(L, t, ref); + return ref; +} + + +LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { + if (ref >= 0) { + t = lua_absindex(L, t); + lua_rawgeti(L, t, freelist); + lua_assert(lua_isinteger(L, -1)); + lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ + lua_pushinteger(L, ref); + lua_rawseti(L, t, freelist); /* t[freelist] = ref */ + } +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Load functions +** ======================================================= +*/ + +typedef struct LoadF { + int n; /* number of pre-read characters */ + FILE *f; /* file being read */ + char buff[BUFSIZ]; /* area for reading file */ +} LoadF; + + +static const char *getF (lua_State *L, void *ud, size_t *size) { + LoadF *lf = (LoadF *)ud; + (void)L; /* not used */ + if (lf->n > 0) { /* are there pre-read characters to be read? */ + *size = lf->n; /* return them (chars already in buffer) */ + lf->n = 0; /* no more pre-read characters */ + } + else { /* read a block from file */ + /* 'fread' can return > 0 *and* set the EOF flag. If next call to + 'getF' called 'fread', it might still wait for user input. + The next check avoids this problem. */ + if (feof(lf->f)) return NULL; + *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ + } + return lf->buff; +} + + +static int errfile (lua_State *L, const char *what, int fnameindex) { + const char *serr = strerror(errno); + const char *filename = lua_tostring(L, fnameindex) + 1; + lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + lua_remove(L, fnameindex); + return LUA_ERRFILE; +} + + +/* +** Skip an optional BOM at the start of a stream. If there is an +** incomplete BOM (the first character is correct but the rest is +** not), returns the first character anyway to force an error +** (as no chunk can start with 0xEF). +*/ +static int skipBOM (FILE *f) { + int c = getc(f); /* read first character */ + if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */ + return getc(f); /* ignore BOM and return next char */ + else /* no (valid) BOM */ + return c; /* return first character */ +} + + +/* +** reads the first character of file 'f' and skips an optional BOM mark +** in its beginning plus its first line if it starts with '#'. Returns +** true if it skipped the first line. In any case, '*cp' has the +** first "valid" character of the file (after the optional BOM and +** a first-line comment). +*/ +static int skipcomment (FILE *f, int *cp) { + int c = *cp = skipBOM(f); + if (c == '#') { /* first line is a comment (Unix exec. file)? */ + do { /* skip first line */ + c = getc(f); + } while (c != EOF && c != '\n'); + *cp = getc(f); /* next character after comment, if present */ + return 1; /* there was a comment */ + } + else return 0; /* no comment */ +} + + +LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, + const char *mode) { + LoadF lf; + int status, readstatus; + int c; + int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + if (filename == NULL) { + lua_pushliteral(L, "=stdin"); + lf.f = stdin; + } + else { + lua_pushfstring(L, "@%s", filename); + lf.f = fopen(filename, "r"); + if (lf.f == NULL) return errfile(L, "open", fnameindex); + } + lf.n = 0; + if (skipcomment(lf.f, &c)) /* read initial portion */ + lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */ + if (c == LUA_SIGNATURE[0]) { /* binary file? */ + lf.n = 0; /* remove possible newline */ + if (filename) { /* "real" file? */ + lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ + if (lf.f == NULL) return errfile(L, "reopen", fnameindex); + skipcomment(lf.f, &c); /* re-read initial portion */ + } + } + if (c != EOF) + lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ + status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); + readstatus = ferror(lf.f); + if (filename) fclose(lf.f); /* close file (even in case of errors) */ + if (readstatus) { + lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ + return errfile(L, "read", fnameindex); + } + lua_remove(L, fnameindex); + return status; +} + + +typedef struct LoadS { + const char *s; + size_t size; +} LoadS; + + +static const char *getS (lua_State *L, void *ud, size_t *size) { + LoadS *ls = (LoadS *)ud; + (void)L; /* not used */ + if (ls->size == 0) return NULL; + *size = ls->size; + ls->size = 0; + return ls->s; +} + + +LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size, + const char *name, const char *mode) { + LoadS ls; + ls.s = buff; + ls.size = size; + return lua_load(L, getS, &ls, name, mode); +} + + +LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { + return luaL_loadbuffer(L, s, strlen(s), s); +} + +/* }====================================================== */ + + + +LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { + if (!lua_getmetatable(L, obj)) /* no metatable? */ + return LUA_TNIL; + else { + int tt; + lua_pushstring(L, event); + tt = lua_rawget(L, -2); + if (tt == LUA_TNIL) /* is metafield nil? */ + lua_pop(L, 2); /* remove metatable and metafield */ + else + lua_remove(L, -2); /* remove only metatable */ + return tt; /* return metafield type */ + } +} + + +LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { + obj = lua_absindex(L, obj); + if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */ + return 0; + lua_pushvalue(L, obj); + lua_call(L, 1, 1); + return 1; +} + + +LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { + lua_Integer l; + int isnum; + lua_len(L, idx); + l = lua_tointegerx(L, -1, &isnum); + if (l_unlikely(!isnum)) + luaL_error(L, "object length is not an integer"); + lua_pop(L, 1); /* remove object */ + return l; +} + + +LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { + idx = lua_absindex(L,idx); + if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */ + if (!lua_isstring(L, -1)) + luaL_error(L, "'__tostring' must return a string"); + } + else { + switch (lua_type(L, idx)) { + case LUA_TNUMBER: { + if (lua_isinteger(L, idx)) + lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx)); + else + lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx)); + break; + } + case LUA_TSTRING: + lua_pushvalue(L, idx); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); + break; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + default: { + int tt = luaL_getmetafield(L, idx, "__name"); /* try name */ + const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : + luaL_typename(L, idx); + lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx)); + if (tt != LUA_TNIL) + lua_remove(L, -2); /* remove '__name' */ + break; + } + } + } + return lua_tolstring(L, -1, len); +} + + +/* +** set functions from list 'l' into table at top - 'nup'; each +** function gets the 'nup' elements at the top as upvalues. +** Returns with only the table at the stack. +*/ +LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { + luaL_checkstack(L, nup, "too many upvalues"); + for (; l->name != NULL; l++) { /* fill the table with given functions */ + if (l->func == NULL) /* place holder? */ + lua_pushboolean(L, 0); + else { + int i; + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -nup); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ + } + lua_setfield(L, -(nup + 2), l->name); + } + lua_pop(L, nup); /* remove upvalues */ +} + + +/* +** ensure that stack[idx][fname] has a table and push that table +** into the stack +*/ +LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { + if (lua_getfield(L, idx, fname) == LUA_TTABLE) + return 1; /* table already there */ + else { + lua_pop(L, 1); /* remove previous result */ + idx = lua_absindex(L, idx); + lua_newtable(L); + lua_pushvalue(L, -1); /* copy to be left at top */ + lua_setfield(L, idx, fname); /* assign new table to field */ + return 0; /* false, because did not find table there */ + } +} + + +/* +** Stripped-down 'require': After checking "loaded" table, calls 'openf' +** to open a module, registers the result in 'package.loaded' table and, +** if 'glb' is true, also registers the result in the global table. +** Leaves resulting module on the top. +*/ +LUALIB_API void luaL_requiref (lua_State *L, const char *modname, + lua_CFunction openf, int glb) { + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_getfield(L, -1, modname); /* LOADED[modname] */ + if (!lua_toboolean(L, -1)) { /* package not already loaded? */ + lua_pop(L, 1); /* remove field */ + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); /* argument to open function */ + lua_call(L, 1, 1); /* call 'openf' to open module */ + lua_pushvalue(L, -1); /* make copy of module (call result) */ + lua_setfield(L, -3, modname); /* LOADED[modname] = module */ + } + lua_remove(L, -2); /* remove LOADED table */ + if (glb) { + lua_pushvalue(L, -1); /* copy of module */ + lua_setglobal(L, modname); /* _G[modname] = module */ + } +} + + +LUALIB_API void luaL_addgsub (luaL_Buffer *b, const char *s, + const char *p, const char *r) { + const char *wild; + size_t l = strlen(p); + while ((wild = strstr(s, p)) != NULL) { + luaL_addlstring(b, s, wild - s); /* push prefix */ + luaL_addstring(b, r); /* push replacement in place of pattern */ + s = wild + l; /* continue after 'p' */ + } + luaL_addstring(b, s); /* push last suffix */ +} + + +LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, + const char *p, const char *r) { + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addgsub(&b, s, p, r); + luaL_pushresult(&b); + return lua_tostring(L, -1); +} + + +static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; (void)osize; /* not used */ + if (nsize == 0) { + free(ptr); + return NULL; + } + else + return realloc(ptr, nsize); +} + + +static int panic (lua_State *L) { + const char *msg = lua_tostring(L, -1); + if (msg == NULL) msg = "error object is not a string"; + lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", + msg); + return 0; /* return to Lua to abort */ +} + + +/* +** Warning functions: +** warnfoff: warning system is off +** warnfon: ready to start a new message +** warnfcont: previous message is to be continued +*/ +static void warnfoff (void *ud, const char *message, int tocont); +static void warnfon (void *ud, const char *message, int tocont); +static void warnfcont (void *ud, const char *message, int tocont); + + +/* +** Check whether message is a control message. If so, execute the +** control or ignore it if unknown. +*/ +static int checkcontrol (lua_State *L, const char *message, int tocont) { + if (tocont || *(message++) != '@') /* not a control message? */ + return 0; + else { + if (strcmp(message, "off") == 0) + lua_setwarnf(L, warnfoff, L); /* turn warnings off */ + else if (strcmp(message, "on") == 0) + lua_setwarnf(L, warnfon, L); /* turn warnings on */ + return 1; /* it was a control message */ + } +} + + +static void warnfoff (void *ud, const char *message, int tocont) { + checkcontrol((lua_State *)ud, message, tocont); +} + + +/* +** Writes the message and handle 'tocont', finishing the message +** if needed and setting the next warn function. +*/ +static void warnfcont (void *ud, const char *message, int tocont) { + lua_State *L = (lua_State *)ud; + lua_writestringerror("%s", message); /* write message */ + if (tocont) /* not the last part? */ + lua_setwarnf(L, warnfcont, L); /* to be continued */ + else { /* last part */ + lua_writestringerror("%s", "\n"); /* finish message with end-of-line */ + lua_setwarnf(L, warnfon, L); /* next call is a new message */ + } +} + + +static void warnfon (void *ud, const char *message, int tocont) { + if (checkcontrol((lua_State *)ud, message, tocont)) /* control message? */ + return; /* nothing else to be done */ + lua_writestringerror("%s", "Lua warning: "); /* start a new warning */ + warnfcont(ud, message, tocont); /* finish processing */ +} + + +LUALIB_API lua_State *luaL_newstate (void) { + lua_State *L = lua_newstate(l_alloc, NULL); + if (l_likely(L)) { + lua_atpanic(L, &panic); + lua_setwarnf(L, warnfoff, L); /* default is warnings off */ + } + return L; +} + + +LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { + lua_Number v = lua_version(L); + if (sz != LUAL_NUMSIZES) /* check numeric types */ + luaL_error(L, "core and library have incompatible numeric types"); + else if (v != ver) + luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", + (LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)v); +} + diff --git a/vendor/lua-src/lua-5.4.6/lauxlib.h b/vendor/lua-src/lua-5.4.6/lauxlib.h new file mode 100644 index 0000000000000..5b977e2a39f13 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lauxlib.h @@ -0,0 +1,301 @@ +/* +** $Id: lauxlib.h $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lauxlib_h +#define lauxlib_h + + +#include +#include + +#include "luaconf.h" +#include "lua.h" + + +/* global table */ +#define LUA_GNAME "_G" + + +typedef struct luaL_Buffer luaL_Buffer; + + +/* extra error code for 'luaL_loadfilex' */ +#define LUA_ERRFILE (LUA_ERRERR+1) + + +/* key, in the registry, for table of loaded modules */ +#define LUA_LOADED_TABLE "_LOADED" + + +/* key, in the registry, for table of preloaded loaders */ +#define LUA_PRELOAD_TABLE "_PRELOAD" + + +typedef struct luaL_Reg { + const char *name; + lua_CFunction func; +} luaL_Reg; + + +#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) + +LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); +#define luaL_checkversion(L) \ + luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) + +LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); +LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); +LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); +LUALIB_API int (luaL_typeerror) (lua_State *L, int arg, const char *tname); +LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, + size_t *l); +LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, + const char *def, size_t *l); +LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); +LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); + +LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); +LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, + lua_Integer def); + +LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); +LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t); +LUALIB_API void (luaL_checkany) (lua_State *L, int arg); + +LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); +LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); +LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); +LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); + +LUALIB_API void (luaL_where) (lua_State *L, int lvl); +LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); + +LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, + const char *const lst[]); + +LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); +LUALIB_API int (luaL_execresult) (lua_State *L, int stat); + + +/* predefined references */ +#define LUA_NOREF (-2) +#define LUA_REFNIL (-1) + +LUALIB_API int (luaL_ref) (lua_State *L, int t); +LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); + +LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, + const char *mode); + +#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) + +LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, + const char *name, const char *mode); +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); + +LUALIB_API lua_State *(luaL_newstate) (void); + +LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); + +LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s, + const char *p, const char *r); +LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, + const char *p, const char *r); + +LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); + +LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname); + +LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, + const char *msg, int level); + +LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, + lua_CFunction openf, int glb); + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + + +#define luaL_newlibtable(L,l) \ + lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) + +#define luaL_newlib(L,l) \ + (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) + +#define luaL_argcheck(L, cond,arg,extramsg) \ + ((void)(luai_likely(cond) || luaL_argerror(L, (arg), (extramsg)))) + +#define luaL_argexpected(L,cond,arg,tname) \ + ((void)(luai_likely(cond) || luaL_typeerror(L, (arg), (tname)))) + +#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) +#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) + +#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) + +#define luaL_dofile(L, fn) \ + (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_dostring(L, s) \ + (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) + +#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) + +#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) + + +/* +** Perform arithmetic operations on lua_Integer values with wrap-around +** semantics, as the Lua core does. +*/ +#define luaL_intop(op,v1,v2) \ + ((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2))) + + +/* push the value used to represent failure/error */ +#define luaL_pushfail(L) lua_pushnil(L) + + +/* +** Internal assertions for in-house debugging +*/ +#if !defined(lua_assert) + +#if defined LUAI_ASSERT + #include + #define lua_assert(c) assert(c) +#else + #define lua_assert(c) ((void)0) +#endif + +#endif + + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + +struct luaL_Buffer { + char *b; /* buffer address */ + size_t size; /* buffer size */ + size_t n; /* number of characters in buffer */ + lua_State *L; + union { + LUAI_MAXALIGN; /* ensure maximum alignment for buffer */ + char b[LUAL_BUFFERSIZE]; /* initial buffer */ + } init; +}; + + +#define luaL_bufflen(bf) ((bf)->n) +#define luaL_buffaddr(bf) ((bf)->b) + + +#define luaL_addchar(B,c) \ + ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ + ((B)->b[(B)->n++] = (c))) + +#define luaL_addsize(B,s) ((B)->n += (s)) + +#define luaL_buffsub(B,s) ((B)->n -= (s)) + +LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); +LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); +LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); +LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); +LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); +LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); + +#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) + +/* }====================================================== */ + + + +/* +** {====================================================== +** File handles for IO library +** ======================================================= +*/ + +/* +** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and +** initial structure 'luaL_Stream' (it may contain other fields +** after that initial structure). +*/ + +#define LUA_FILEHANDLE "FILE*" + + +typedef struct luaL_Stream { + FILE *f; /* stream (NULL for incompletely created streams) */ + lua_CFunction closef; /* to close stream (NULL for closed streams) */ +} luaL_Stream; + +/* }====================================================== */ + +/* +** {================================================================== +** "Abstraction Layer" for basic report of messages and errors +** =================================================================== +*/ + +/* print a string */ +#if !defined(lua_writestring) +#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) +#endif + +/* print a newline and flush the output */ +#if !defined(lua_writeline) +#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) +#endif + +/* print an error message */ +#if !defined(lua_writestringerror) +#define lua_writestringerror(s,p) \ + (fprintf(stderr, (s), (p)), fflush(stderr)) +#endif + +/* }================================================================== */ + + +/* +** {============================================================ +** Compatibility with deprecated conversions +** ============================================================= +*/ +#if defined(LUA_COMPAT_APIINTCASTS) + +#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a)) +#define luaL_optunsigned(L,a,d) \ + ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d))) + +#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) +#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) + +#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) +#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) + +#endif +/* }============================================================ */ + + + +#endif + + diff --git a/vendor/lua-src/lua-5.4.6/lbaselib.c b/vendor/lua-src/lua-5.4.6/lbaselib.c new file mode 100644 index 0000000000000..1d60c9dede596 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lbaselib.c @@ -0,0 +1,549 @@ +/* +** $Id: lbaselib.c $ +** Basic library +** See Copyright Notice in lua.h +*/ + +#define lbaselib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static int luaB_print (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + for (i = 1; i <= n; i++) { /* for each argument */ + size_t l; + const char *s = luaL_tolstring(L, i, &l); /* convert it to string */ + if (i > 1) /* not the first element? */ + lua_writestring("\t", 1); /* add a tab before it */ + lua_writestring(s, l); /* print it */ + lua_pop(L, 1); /* pop result */ + } + lua_writeline(); + return 0; +} + + +/* +** Creates a warning with all given arguments. +** Check first for errors; otherwise an error may interrupt +** the composition of a warning, leaving it unfinished. +*/ +static int luaB_warn (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + luaL_checkstring(L, 1); /* at least one argument */ + for (i = 2; i <= n; i++) + luaL_checkstring(L, i); /* make sure all arguments are strings */ + for (i = 1; i < n; i++) /* compose warning */ + lua_warning(L, lua_tostring(L, i), 1); + lua_warning(L, lua_tostring(L, n), 0); /* close warning */ + return 0; +} + + +#define SPACECHARS " \f\n\r\t\v" + +static const char *b_str2int (const char *s, int base, lua_Integer *pn) { + lua_Unsigned n = 0; + int neg = 0; + s += strspn(s, SPACECHARS); /* skip initial spaces */ + if (*s == '-') { s++; neg = 1; } /* handle sign */ + else if (*s == '+') s++; + if (!isalnum((unsigned char)*s)) /* no digit? */ + return NULL; + do { + int digit = (isdigit((unsigned char)*s)) ? *s - '0' + : (toupper((unsigned char)*s) - 'A') + 10; + if (digit >= base) return NULL; /* invalid numeral */ + n = n * base + digit; + s++; + } while (isalnum((unsigned char)*s)); + s += strspn(s, SPACECHARS); /* skip trailing spaces */ + *pn = (lua_Integer)((neg) ? (0u - n) : n); + return s; +} + + +static int luaB_tonumber (lua_State *L) { + if (lua_isnoneornil(L, 2)) { /* standard conversion? */ + if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */ + lua_settop(L, 1); /* yes; return it */ + return 1; + } + else { + size_t l; + const char *s = lua_tolstring(L, 1, &l); + if (s != NULL && lua_stringtonumber(L, s) == l + 1) + return 1; /* successful conversion to number */ + /* else not a number */ + luaL_checkany(L, 1); /* (but there must be some parameter) */ + } + } + else { + size_t l; + const char *s; + lua_Integer n = 0; /* to avoid warnings */ + lua_Integer base = luaL_checkinteger(L, 2); + luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */ + s = lua_tolstring(L, 1, &l); + luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); + if (b_str2int(s, (int)base, &n) == s + l) { + lua_pushinteger(L, n); + return 1; + } /* else not a number */ + } /* else not a number */ + luaL_pushfail(L); /* not a number */ + return 1; +} + + +static int luaB_error (lua_State *L) { + int level = (int)luaL_optinteger(L, 2, 1); + lua_settop(L, 1); + if (lua_type(L, 1) == LUA_TSTRING && level > 0) { + luaL_where(L, level); /* add extra information */ + lua_pushvalue(L, 1); + lua_concat(L, 2); + } + return lua_error(L); +} + + +static int luaB_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); + return 1; /* no metatable */ + } + luaL_getmetafield(L, 1, "__metatable"); + return 1; /* returns either __metatable field (if present) or metatable */ +} + + +static int luaB_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table"); + if (l_unlikely(luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL)) + return luaL_error(L, "cannot change a protected metatable"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; +} + + +static int luaB_rawequal (lua_State *L) { + luaL_checkany(L, 1); + luaL_checkany(L, 2); + lua_pushboolean(L, lua_rawequal(L, 1, 2)); + return 1; +} + + +static int luaB_rawlen (lua_State *L) { + int t = lua_type(L, 1); + luaL_argexpected(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, + "table or string"); + lua_pushinteger(L, lua_rawlen(L, 1)); + return 1; +} + + +static int luaB_rawget (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_rawget(L, 1); + return 1; +} + +static int luaB_rawset (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + luaL_checkany(L, 3); + lua_settop(L, 3); + lua_rawset(L, 1); + return 1; +} + + +static int pushmode (lua_State *L, int oldmode) { + if (oldmode == -1) + luaL_pushfail(L); /* invalid call to 'lua_gc' */ + else + lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" + : "generational"); + return 1; +} + + +/* +** check whether call to 'lua_gc' was valid (not inside a finalizer) +*/ +#define checkvalres(res) { if (res == -1) break; } + +static int luaB_collectgarbage (lua_State *L) { + static const char *const opts[] = {"stop", "restart", "collect", + "count", "step", "setpause", "setstepmul", + "isrunning", "generational", "incremental", NULL}; + static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, + LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; + int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; + switch (o) { + case LUA_GCCOUNT: { + int k = lua_gc(L, o); + int b = lua_gc(L, LUA_GCCOUNTB); + checkvalres(k); + lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024)); + return 1; + } + case LUA_GCSTEP: { + int step = (int)luaL_optinteger(L, 2, 0); + int res = lua_gc(L, o, step); + checkvalres(res); + lua_pushboolean(L, res); + return 1; + } + case LUA_GCSETPAUSE: + case LUA_GCSETSTEPMUL: { + int p = (int)luaL_optinteger(L, 2, 0); + int previous = lua_gc(L, o, p); + checkvalres(previous); + lua_pushinteger(L, previous); + return 1; + } + case LUA_GCISRUNNING: { + int res = lua_gc(L, o); + checkvalres(res); + lua_pushboolean(L, res); + return 1; + } + case LUA_GCGEN: { + int minormul = (int)luaL_optinteger(L, 2, 0); + int majormul = (int)luaL_optinteger(L, 3, 0); + return pushmode(L, lua_gc(L, o, minormul, majormul)); + } + case LUA_GCINC: { + int pause = (int)luaL_optinteger(L, 2, 0); + int stepmul = (int)luaL_optinteger(L, 3, 0); + int stepsize = (int)luaL_optinteger(L, 4, 0); + return pushmode(L, lua_gc(L, o, pause, stepmul, stepsize)); + } + default: { + int res = lua_gc(L, o); + checkvalres(res); + lua_pushinteger(L, res); + return 1; + } + } + luaL_pushfail(L); /* invalid call (inside a finalizer) */ + return 1; +} + + +static int luaB_type (lua_State *L) { + int t = lua_type(L, 1); + luaL_argcheck(L, t != LUA_TNONE, 1, "value expected"); + lua_pushstring(L, lua_typename(L, t)); + return 1; +} + + +static int luaB_next (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 2); /* create a 2nd argument if there isn't one */ + if (lua_next(L, 1)) + return 2; + else { + lua_pushnil(L); + return 1; + } +} + + +static int pairscont (lua_State *L, int status, lua_KContext k) { + (void)L; (void)status; (void)k; /* unused */ + return 3; +} + +static int luaB_pairs (lua_State *L) { + luaL_checkany(L, 1); + if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */ + lua_pushcfunction(L, luaB_next); /* will return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushnil(L); /* and initial value */ + } + else { + lua_pushvalue(L, 1); /* argument 'self' to metamethod */ + lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */ + } + return 3; +} + + +/* +** Traversal function for 'ipairs' +*/ +static int ipairsaux (lua_State *L) { + lua_Integer i = luaL_checkinteger(L, 2); + i = luaL_intop(+, i, 1); + lua_pushinteger(L, i); + return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; +} + + +/* +** 'ipairs' function. Returns 'ipairsaux', given "table", 0. +** (The given "table" may not be a table.) +*/ +static int luaB_ipairs (lua_State *L) { + luaL_checkany(L, 1); + lua_pushcfunction(L, ipairsaux); /* iteration function */ + lua_pushvalue(L, 1); /* state */ + lua_pushinteger(L, 0); /* initial value */ + return 3; +} + + +static int load_aux (lua_State *L, int status, int envidx) { + if (l_likely(status == LUA_OK)) { + if (envidx != 0) { /* 'env' parameter? */ + lua_pushvalue(L, envidx); /* environment for loaded function */ + if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ + lua_pop(L, 1); /* remove 'env' if not used by previous call */ + } + return 1; + } + else { /* error (message is on top of the stack) */ + luaL_pushfail(L); + lua_insert(L, -2); /* put before error message */ + return 2; /* return fail plus error message */ + } +} + + +static int luaB_loadfile (lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + const char *mode = luaL_optstring(L, 2, NULL); + int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ + int status = luaL_loadfilex(L, fname, mode); + return load_aux(L, status, env); +} + + +/* +** {====================================================== +** Generic Read function +** ======================================================= +*/ + + +/* +** reserved slot, above all arguments, to hold a copy of the returned +** string to avoid it being collected while parsed. 'load' has four +** optional arguments (chunk, source name, mode, and environment). +*/ +#define RESERVEDSLOT 5 + + +/* +** Reader for generic 'load' function: 'lua_load' uses the +** stack for internal stuff, so the reader cannot change the +** stack top. Instead, it keeps its resulting string in a +** reserved slot inside the stack. +*/ +static const char *generic_reader (lua_State *L, void *ud, size_t *size) { + (void)(ud); /* not used */ + luaL_checkstack(L, 2, "too many nested functions"); + lua_pushvalue(L, 1); /* get function */ + lua_call(L, 0, 1); /* call it */ + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* pop result */ + *size = 0; + return NULL; + } + else if (l_unlikely(!lua_isstring(L, -1))) + luaL_error(L, "reader function must return a string"); + lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ + return lua_tolstring(L, RESERVEDSLOT, size); +} + + +static int luaB_load (lua_State *L) { + int status; + size_t l; + const char *s = lua_tolstring(L, 1, &l); + const char *mode = luaL_optstring(L, 3, "bt"); + int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ + if (s != NULL) { /* loading a string? */ + const char *chunkname = luaL_optstring(L, 2, s); + status = luaL_loadbufferx(L, s, l, chunkname, mode); + } + else { /* loading from a reader function */ + const char *chunkname = luaL_optstring(L, 2, "=(load)"); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, RESERVEDSLOT); /* create reserved slot */ + status = lua_load(L, generic_reader, NULL, chunkname, mode); + } + return load_aux(L, status, env); +} + +/* }====================================================== */ + + +static int dofilecont (lua_State *L, int d1, lua_KContext d2) { + (void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */ + return lua_gettop(L) - 1; +} + + +static int luaB_dofile (lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + lua_settop(L, 1); + if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK)) + return lua_error(L); + lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); + return dofilecont(L, 0, 0); +} + + +static int luaB_assert (lua_State *L) { + if (l_likely(lua_toboolean(L, 1))) /* condition is true? */ + return lua_gettop(L); /* return all arguments */ + else { /* error */ + luaL_checkany(L, 1); /* there must be a condition */ + lua_remove(L, 1); /* remove it */ + lua_pushliteral(L, "assertion failed!"); /* default message */ + lua_settop(L, 1); /* leave only message (default if no other one) */ + return luaB_error(L); /* call 'error' */ + } +} + + +static int luaB_select (lua_State *L) { + int n = lua_gettop(L); + if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { + lua_pushinteger(L, n-1); + return 1; + } + else { + lua_Integer i = luaL_checkinteger(L, 1); + if (i < 0) i = n + i; + else if (i > n) i = n; + luaL_argcheck(L, 1 <= i, 1, "index out of range"); + return n - (int)i; + } +} + + +/* +** Continuation function for 'pcall' and 'xpcall'. Both functions +** already pushed a 'true' before doing the call, so in case of success +** 'finishpcall' only has to return everything in the stack minus +** 'extra' values (where 'extra' is exactly the number of items to be +** ignored). +*/ +static int finishpcall (lua_State *L, int status, lua_KContext extra) { + if (l_unlikely(status != LUA_OK && status != LUA_YIELD)) { /* error? */ + lua_pushboolean(L, 0); /* first result (false) */ + lua_pushvalue(L, -2); /* error message */ + return 2; /* return false, msg */ + } + else + return lua_gettop(L) - (int)extra; /* return all results */ +} + + +static int luaB_pcall (lua_State *L) { + int status; + luaL_checkany(L, 1); + lua_pushboolean(L, 1); /* first result if no errors */ + lua_insert(L, 1); /* put it in place */ + status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); + return finishpcall(L, status, 0); +} + + +/* +** Do a protected call with error handling. After 'lua_rotate', the +** stack will have ; so, the function passes +** 2 to 'finishpcall' to skip the 2 first values when returning results. +*/ +static int luaB_xpcall (lua_State *L) { + int status; + int n = lua_gettop(L); + luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ + lua_pushboolean(L, 1); /* first result */ + lua_pushvalue(L, 1); /* function */ + lua_rotate(L, 3, 2); /* move them below function's arguments */ + status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); + return finishpcall(L, status, 2); +} + + +static int luaB_tostring (lua_State *L) { + luaL_checkany(L, 1); + luaL_tolstring(L, 1, NULL); + return 1; +} + + +static const luaL_Reg base_funcs[] = { + {"assert", luaB_assert}, + {"collectgarbage", luaB_collectgarbage}, + {"dofile", luaB_dofile}, + {"error", luaB_error}, + {"getmetatable", luaB_getmetatable}, + {"ipairs", luaB_ipairs}, + {"loadfile", luaB_loadfile}, + {"load", luaB_load}, + {"next", luaB_next}, + {"pairs", luaB_pairs}, + {"pcall", luaB_pcall}, + {"print", luaB_print}, + {"warn", luaB_warn}, + {"rawequal", luaB_rawequal}, + {"rawlen", luaB_rawlen}, + {"rawget", luaB_rawget}, + {"rawset", luaB_rawset}, + {"select", luaB_select}, + {"setmetatable", luaB_setmetatable}, + {"tonumber", luaB_tonumber}, + {"tostring", luaB_tostring}, + {"type", luaB_type}, + {"xpcall", luaB_xpcall}, + /* placeholders */ + {LUA_GNAME, NULL}, + {"_VERSION", NULL}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_base (lua_State *L) { + /* open lib into global table */ + lua_pushglobaltable(L); + luaL_setfuncs(L, base_funcs, 0); + /* set global _G */ + lua_pushvalue(L, -1); + lua_setfield(L, -2, LUA_GNAME); + /* set global _VERSION */ + lua_pushliteral(L, LUA_VERSION); + lua_setfield(L, -2, "_VERSION"); + return 1; +} + diff --git a/vendor/lua-src/lua-5.4.6/lcode.c b/vendor/lua-src/lua-5.4.6/lcode.c new file mode 100644 index 0000000000000..1a371ca943ba8 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lcode.c @@ -0,0 +1,1871 @@ +/* +** $Id: lcode.c $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + +#define lcode_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include +#include +#include + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstring.h" +#include "ltable.h" +#include "lvm.h" + + +/* Maximum number of registers in a Lua function (must fit in 8 bits) */ +#define MAXREGS 255 + + +#define hasjumps(e) ((e)->t != (e)->f) + + +static int codesJ (FuncState *fs, OpCode o, int sj, int k); + + + +/* semantic error */ +l_noret luaK_semerror (LexState *ls, const char *msg) { + ls->t.token = 0; /* remove "near " from final message */ + luaX_syntaxerror(ls, msg); +} + + +/* +** If expression is a numeric constant, fills 'v' with its value +** and returns 1. Otherwise, returns 0. +*/ +static int tonumeral (const expdesc *e, TValue *v) { + if (hasjumps(e)) + return 0; /* not a numeral */ + switch (e->k) { + case VKINT: + if (v) setivalue(v, e->u.ival); + return 1; + case VKFLT: + if (v) setfltvalue(v, e->u.nval); + return 1; + default: return 0; + } +} + + +/* +** Get the constant value from a constant expression +*/ +static TValue *const2val (FuncState *fs, const expdesc *e) { + lua_assert(e->k == VCONST); + return &fs->ls->dyd->actvar.arr[e->u.info].k; +} + + +/* +** If expression is a constant, fills 'v' with its value +** and returns 1. Otherwise, returns 0. +*/ +int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v) { + if (hasjumps(e)) + return 0; /* not a constant */ + switch (e->k) { + case VFALSE: + setbfvalue(v); + return 1; + case VTRUE: + setbtvalue(v); + return 1; + case VNIL: + setnilvalue(v); + return 1; + case VKSTR: { + setsvalue(fs->ls->L, v, e->u.strval); + return 1; + } + case VCONST: { + setobj(fs->ls->L, v, const2val(fs, e)); + return 1; + } + default: return tonumeral(e, v); + } +} + + +/* +** Return the previous instruction of the current code. If there +** may be a jump target between the current instruction and the +** previous one, return an invalid instruction (to avoid wrong +** optimizations). +*/ +static Instruction *previousinstruction (FuncState *fs) { + static const Instruction invalidinstruction = ~(Instruction)0; + if (fs->pc > fs->lasttarget) + return &fs->f->code[fs->pc - 1]; /* previous instruction */ + else + return cast(Instruction*, &invalidinstruction); +} + + +/* +** Create a OP_LOADNIL instruction, but try to optimize: if the previous +** instruction is also OP_LOADNIL and ranges are compatible, adjust +** range of previous instruction instead of emitting a new one. (For +** instance, 'local a; local b' will generate a single opcode.) +*/ +void luaK_nil (FuncState *fs, int from, int n) { + int l = from + n - 1; /* last register to set nil */ + Instruction *previous = previousinstruction(fs); + if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */ + int pfrom = GETARG_A(*previous); /* get previous range */ + int pl = pfrom + GETARG_B(*previous); + if ((pfrom <= from && from <= pl + 1) || + (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ + if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ + if (pl > l) l = pl; /* l = max(l, pl) */ + SETARG_A(*previous, from); + SETARG_B(*previous, l - from); + return; + } /* else go through */ + } + luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ +} + + +/* +** Gets the destination address of a jump instruction. Used to traverse +** a list of jumps. +*/ +static int getjump (FuncState *fs, int pc) { + int offset = GETARG_sJ(fs->f->code[pc]); + if (offset == NO_JUMP) /* point to itself represents end of list */ + return NO_JUMP; /* end of list */ + else + return (pc+1)+offset; /* turn offset into absolute position */ +} + + +/* +** Fix jump instruction at position 'pc' to jump to 'dest'. +** (Jump addresses are relative in Lua) +*/ +static void fixjump (FuncState *fs, int pc, int dest) { + Instruction *jmp = &fs->f->code[pc]; + int offset = dest - (pc + 1); + lua_assert(dest != NO_JUMP); + if (!(-OFFSET_sJ <= offset && offset <= MAXARG_sJ - OFFSET_sJ)) + luaX_syntaxerror(fs->ls, "control structure too long"); + lua_assert(GET_OPCODE(*jmp) == OP_JMP); + SETARG_sJ(*jmp, offset); +} + + +/* +** Concatenate jump-list 'l2' into jump-list 'l1' +*/ +void luaK_concat (FuncState *fs, int *l1, int l2) { + if (l2 == NO_JUMP) return; /* nothing to concatenate? */ + else if (*l1 == NO_JUMP) /* no original list? */ + *l1 = l2; /* 'l1' points to 'l2' */ + else { + int list = *l1; + int next; + while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ + list = next; + fixjump(fs, list, l2); /* last element links to 'l2' */ + } +} + + +/* +** Create a jump instruction and return its position, so its destination +** can be fixed later (with 'fixjump'). +*/ +int luaK_jump (FuncState *fs) { + return codesJ(fs, OP_JMP, NO_JUMP, 0); +} + + +/* +** Code a 'return' instruction +*/ +void luaK_ret (FuncState *fs, int first, int nret) { + OpCode op; + switch (nret) { + case 0: op = OP_RETURN0; break; + case 1: op = OP_RETURN1; break; + default: op = OP_RETURN; break; + } + luaK_codeABC(fs, op, first, nret + 1, 0); +} + + +/* +** Code a "conditional jump", that is, a test or comparison opcode +** followed by a jump. Return jump position. +*/ +static int condjump (FuncState *fs, OpCode op, int A, int B, int C, int k) { + luaK_codeABCk(fs, op, A, B, C, k); + return luaK_jump(fs); +} + + +/* +** returns current 'pc' and marks it as a jump target (to avoid wrong +** optimizations with consecutive instructions not in the same basic block). +*/ +int luaK_getlabel (FuncState *fs) { + fs->lasttarget = fs->pc; + return fs->pc; +} + + +/* +** Returns the position of the instruction "controlling" a given +** jump (that is, its condition), or the jump itself if it is +** unconditional. +*/ +static Instruction *getjumpcontrol (FuncState *fs, int pc) { + Instruction *pi = &fs->f->code[pc]; + if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) + return pi-1; + else + return pi; +} + + +/* +** Patch destination register for a TESTSET instruction. +** If instruction in position 'node' is not a TESTSET, return 0 ("fails"). +** Otherwise, if 'reg' is not 'NO_REG', set it as the destination +** register. Otherwise, change instruction to a simple 'TEST' (produces +** no register value) +*/ +static int patchtestreg (FuncState *fs, int node, int reg) { + Instruction *i = getjumpcontrol(fs, node); + if (GET_OPCODE(*i) != OP_TESTSET) + return 0; /* cannot patch other instructions */ + if (reg != NO_REG && reg != GETARG_B(*i)) + SETARG_A(*i, reg); + else { + /* no register to put value or register already has the value; + change instruction to simple test */ + *i = CREATE_ABCk(OP_TEST, GETARG_B(*i), 0, 0, GETARG_k(*i)); + } + return 1; +} + + +/* +** Traverse a list of tests ensuring no one produces a value +*/ +static void removevalues (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) + patchtestreg(fs, list, NO_REG); +} + + +/* +** Traverse a list of tests, patching their destination address and +** registers: tests producing values jump to 'vtarget' (and put their +** values in 'reg'), other tests jump to 'dtarget'. +*/ +static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, + int dtarget) { + while (list != NO_JUMP) { + int next = getjump(fs, list); + if (patchtestreg(fs, list, reg)) + fixjump(fs, list, vtarget); + else + fixjump(fs, list, dtarget); /* jump to default target */ + list = next; + } +} + + +/* +** Path all jumps in 'list' to jump to 'target'. +** (The assert means that we cannot fix a jump to a forward address +** because we only know addresses once code is generated.) +*/ +void luaK_patchlist (FuncState *fs, int list, int target) { + lua_assert(target <= fs->pc); + patchlistaux(fs, list, target, NO_REG, target); +} + + +void luaK_patchtohere (FuncState *fs, int list) { + int hr = luaK_getlabel(fs); /* mark "here" as a jump target */ + luaK_patchlist(fs, list, hr); +} + + +/* limit for difference between lines in relative line info. */ +#define LIMLINEDIFF 0x80 + + +/* +** Save line info for a new instruction. If difference from last line +** does not fit in a byte, of after that many instructions, save a new +** absolute line info; (in that case, the special value 'ABSLINEINFO' +** in 'lineinfo' signals the existence of this absolute information.) +** Otherwise, store the difference from last line in 'lineinfo'. +*/ +static void savelineinfo (FuncState *fs, Proto *f, int line) { + int linedif = line - fs->previousline; + int pc = fs->pc - 1; /* last instruction coded */ + if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ >= MAXIWTHABS) { + luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo, + f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines"); + f->abslineinfo[fs->nabslineinfo].pc = pc; + f->abslineinfo[fs->nabslineinfo++].line = line; + linedif = ABSLINEINFO; /* signal that there is absolute information */ + fs->iwthabs = 1; /* restart counter */ + } + luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte, + MAX_INT, "opcodes"); + f->lineinfo[pc] = linedif; + fs->previousline = line; /* last line saved */ +} + + +/* +** Remove line information from the last instruction. +** If line information for that instruction is absolute, set 'iwthabs' +** above its max to force the new (replacing) instruction to have +** absolute line info, too. +*/ +static void removelastlineinfo (FuncState *fs) { + Proto *f = fs->f; + int pc = fs->pc - 1; /* last instruction coded */ + if (f->lineinfo[pc] != ABSLINEINFO) { /* relative line info? */ + fs->previousline -= f->lineinfo[pc]; /* correct last line saved */ + fs->iwthabs--; /* undo previous increment */ + } + else { /* absolute line information */ + lua_assert(f->abslineinfo[fs->nabslineinfo - 1].pc == pc); + fs->nabslineinfo--; /* remove it */ + fs->iwthabs = MAXIWTHABS + 1; /* force next line info to be absolute */ + } +} + + +/* +** Remove the last instruction created, correcting line information +** accordingly. +*/ +static void removelastinstruction (FuncState *fs) { + removelastlineinfo(fs); + fs->pc--; +} + + +/* +** Emit instruction 'i', checking for array sizes and saving also its +** line information. Return 'i' position. +*/ +int luaK_code (FuncState *fs, Instruction i) { + Proto *f = fs->f; + /* put new instruction in code array */ + luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, + MAX_INT, "opcodes"); + f->code[fs->pc++] = i; + savelineinfo(fs, f, fs->ls->lastline); + return fs->pc - 1; /* index of new instruction */ +} + + +/* +** Format and emit an 'iABC' instruction. (Assertions check consistency +** of parameters versus opcode.) +*/ +int luaK_codeABCk (FuncState *fs, OpCode o, int a, int b, int c, int k) { + lua_assert(getOpMode(o) == iABC); + lua_assert(a <= MAXARG_A && b <= MAXARG_B && + c <= MAXARG_C && (k & ~1) == 0); + return luaK_code(fs, CREATE_ABCk(o, a, b, c, k)); +} + + +/* +** Format and emit an 'iABx' instruction. +*/ +int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { + lua_assert(getOpMode(o) == iABx); + lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx); + return luaK_code(fs, CREATE_ABx(o, a, bc)); +} + + +/* +** Format and emit an 'iAsBx' instruction. +*/ +int luaK_codeAsBx (FuncState *fs, OpCode o, int a, int bc) { + unsigned int b = bc + OFFSET_sBx; + lua_assert(getOpMode(o) == iAsBx); + lua_assert(a <= MAXARG_A && b <= MAXARG_Bx); + return luaK_code(fs, CREATE_ABx(o, a, b)); +} + + +/* +** Format and emit an 'isJ' instruction. +*/ +static int codesJ (FuncState *fs, OpCode o, int sj, int k) { + unsigned int j = sj + OFFSET_sJ; + lua_assert(getOpMode(o) == isJ); + lua_assert(j <= MAXARG_sJ && (k & ~1) == 0); + return luaK_code(fs, CREATE_sJ(o, j, k)); +} + + +/* +** Emit an "extra argument" instruction (format 'iAx') +*/ +static int codeextraarg (FuncState *fs, int a) { + lua_assert(a <= MAXARG_Ax); + return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); +} + + +/* +** Emit a "load constant" instruction, using either 'OP_LOADK' +** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX' +** instruction with "extra argument". +*/ +static int luaK_codek (FuncState *fs, int reg, int k) { + if (k <= MAXARG_Bx) + return luaK_codeABx(fs, OP_LOADK, reg, k); + else { + int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); + codeextraarg(fs, k); + return p; + } +} + + +/* +** Check register-stack level, keeping track of its maximum size +** in field 'maxstacksize' +*/ +void luaK_checkstack (FuncState *fs, int n) { + int newstack = fs->freereg + n; + if (newstack > fs->f->maxstacksize) { + if (newstack >= MAXREGS) + luaX_syntaxerror(fs->ls, + "function or expression needs too many registers"); + fs->f->maxstacksize = cast_byte(newstack); + } +} + + +/* +** Reserve 'n' registers in register stack +*/ +void luaK_reserveregs (FuncState *fs, int n) { + luaK_checkstack(fs, n); + fs->freereg += n; +} + + +/* +** Free register 'reg', if it is neither a constant index nor +** a local variable. +) +*/ +static void freereg (FuncState *fs, int reg) { + if (reg >= luaY_nvarstack(fs)) { + fs->freereg--; + lua_assert(reg == fs->freereg); + } +} + + +/* +** Free two registers in proper order +*/ +static void freeregs (FuncState *fs, int r1, int r2) { + if (r1 > r2) { + freereg(fs, r1); + freereg(fs, r2); + } + else { + freereg(fs, r2); + freereg(fs, r1); + } +} + + +/* +** Free register used by expression 'e' (if any) +*/ +static void freeexp (FuncState *fs, expdesc *e) { + if (e->k == VNONRELOC) + freereg(fs, e->u.info); +} + + +/* +** Free registers used by expressions 'e1' and 'e2' (if any) in proper +** order. +*/ +static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) { + int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1; + int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1; + freeregs(fs, r1, r2); +} + + +/* +** Add constant 'v' to prototype's list of constants (field 'k'). +** Use scanner's table to cache position of constants in constant list +** and try to reuse constants. Because some values should not be used +** as keys (nil cannot be a key, integer keys can collapse with float +** keys), the caller must provide a useful 'key' for indexing the cache. +** Note that all functions share the same table, so entering or exiting +** a function can make some indices wrong. +*/ +static int addk (FuncState *fs, TValue *key, TValue *v) { + TValue val; + lua_State *L = fs->ls->L; + Proto *f = fs->f; + const TValue *idx = luaH_get(fs->ls->h, key); /* query scanner table */ + int k, oldsize; + if (ttisinteger(idx)) { /* is there an index there? */ + k = cast_int(ivalue(idx)); + /* correct value? (warning: must distinguish floats from integers!) */ + if (k < fs->nk && ttypetag(&f->k[k]) == ttypetag(v) && + luaV_rawequalobj(&f->k[k], v)) + return k; /* reuse index */ + } + /* constant not found; create a new entry */ + oldsize = f->sizek; + k = fs->nk; + /* numerical value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setivalue(&val, k); + luaH_finishset(L, fs->ls->h, key, idx, &val); + luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); + while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[k], v); + fs->nk++; + luaC_barrier(L, f, v); + return k; +} + + +/* +** Add a string to list of constants and return its index. +*/ +static int stringK (FuncState *fs, TString *s) { + TValue o; + setsvalue(fs->ls->L, &o, s); + return addk(fs, &o, &o); /* use string itself as key */ +} + + +/* +** Add an integer to list of constants and return its index. +*/ +static int luaK_intK (FuncState *fs, lua_Integer n) { + TValue o; + setivalue(&o, n); + return addk(fs, &o, &o); /* use integer itself as key */ +} + +/* +** Add a float to list of constants and return its index. Floats +** with integral values need a different key, to avoid collision +** with actual integers. To that, we add to the number its smaller +** power-of-two fraction that is still significant in its scale. +** For doubles, that would be 1/2^52. +** (This method is not bulletproof: there may be another float +** with that value, and for floats larger than 2^53 the result is +** still an integer. At worst, this only wastes an entry with +** a duplicate.) +*/ +static int luaK_numberK (FuncState *fs, lua_Number r) { + TValue o; + lua_Integer ik; + setfltvalue(&o, r); + if (!luaV_flttointeger(r, &ik, F2Ieq)) /* not an integral value? */ + return addk(fs, &o, &o); /* use number itself as key */ + else { /* must build an alternative key */ + const int nbm = l_floatatt(MANT_DIG); + const lua_Number q = l_mathop(ldexp)(l_mathop(1.0), -nbm + 1); + const lua_Number k = (ik == 0) ? q : r + r*q; /* new key */ + TValue kv; + setfltvalue(&kv, k); + /* result is not an integral value, unless value is too large */ + lua_assert(!luaV_flttointeger(k, &ik, F2Ieq) || + l_mathop(fabs)(r) >= l_mathop(1e6)); + return addk(fs, &kv, &o); + } +} + + +/* +** Add a false to list of constants and return its index. +*/ +static int boolF (FuncState *fs) { + TValue o; + setbfvalue(&o); + return addk(fs, &o, &o); /* use boolean itself as key */ +} + + +/* +** Add a true to list of constants and return its index. +*/ +static int boolT (FuncState *fs) { + TValue o; + setbtvalue(&o); + return addk(fs, &o, &o); /* use boolean itself as key */ +} + + +/* +** Add nil to list of constants and return its index. +*/ +static int nilK (FuncState *fs) { + TValue k, v; + setnilvalue(&v); + /* cannot use nil as key; instead use table itself to represent nil */ + sethvalue(fs->ls->L, &k, fs->ls->h); + return addk(fs, &k, &v); +} + + +/* +** Check whether 'i' can be stored in an 'sC' operand. Equivalent to +** (0 <= int2sC(i) && int2sC(i) <= MAXARG_C) but without risk of +** overflows in the hidden addition inside 'int2sC'. +*/ +static int fitsC (lua_Integer i) { + return (l_castS2U(i) + OFFSET_sC <= cast_uint(MAXARG_C)); +} + + +/* +** Check whether 'i' can be stored in an 'sBx' operand. +*/ +static int fitsBx (lua_Integer i) { + return (-OFFSET_sBx <= i && i <= MAXARG_Bx - OFFSET_sBx); +} + + +void luaK_int (FuncState *fs, int reg, lua_Integer i) { + if (fitsBx(i)) + luaK_codeAsBx(fs, OP_LOADI, reg, cast_int(i)); + else + luaK_codek(fs, reg, luaK_intK(fs, i)); +} + + +static void luaK_float (FuncState *fs, int reg, lua_Number f) { + lua_Integer fi; + if (luaV_flttointeger(f, &fi, F2Ieq) && fitsBx(fi)) + luaK_codeAsBx(fs, OP_LOADF, reg, cast_int(fi)); + else + luaK_codek(fs, reg, luaK_numberK(fs, f)); +} + + +/* +** Convert a constant in 'v' into an expression description 'e' +*/ +static void const2exp (TValue *v, expdesc *e) { + switch (ttypetag(v)) { + case LUA_VNUMINT: + e->k = VKINT; e->u.ival = ivalue(v); + break; + case LUA_VNUMFLT: + e->k = VKFLT; e->u.nval = fltvalue(v); + break; + case LUA_VFALSE: + e->k = VFALSE; + break; + case LUA_VTRUE: + e->k = VTRUE; + break; + case LUA_VNIL: + e->k = VNIL; + break; + case LUA_VSHRSTR: case LUA_VLNGSTR: + e->k = VKSTR; e->u.strval = tsvalue(v); + break; + default: lua_assert(0); + } +} + + +/* +** Fix an expression to return the number of results 'nresults'. +** 'e' must be a multi-ret expression (function call or vararg). +*/ +void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { + Instruction *pc = &getinstruction(fs, e); + if (e->k == VCALL) /* expression is an open function call? */ + SETARG_C(*pc, nresults + 1); + else { + lua_assert(e->k == VVARARG); + SETARG_C(*pc, nresults + 1); + SETARG_A(*pc, fs->freereg); + luaK_reserveregs(fs, 1); + } +} + + +/* +** Convert a VKSTR to a VK +*/ +static void str2K (FuncState *fs, expdesc *e) { + lua_assert(e->k == VKSTR); + e->u.info = stringK(fs, e->u.strval); + e->k = VK; +} + + +/* +** Fix an expression to return one result. +** If expression is not a multi-ret expression (function call or +** vararg), it already returns one result, so nothing needs to be done. +** Function calls become VNONRELOC expressions (as its result comes +** fixed in the base register of the call), while vararg expressions +** become VRELOC (as OP_VARARG puts its results where it wants). +** (Calls are created returning one result, so that does not need +** to be fixed.) +*/ +void luaK_setoneret (FuncState *fs, expdesc *e) { + if (e->k == VCALL) { /* expression is an open function call? */ + /* already returns 1 value */ + lua_assert(GETARG_C(getinstruction(fs, e)) == 2); + e->k = VNONRELOC; /* result has fixed position */ + e->u.info = GETARG_A(getinstruction(fs, e)); + } + else if (e->k == VVARARG) { + SETARG_C(getinstruction(fs, e), 2); + e->k = VRELOC; /* can relocate its simple result */ + } +} + + +/* +** Ensure that expression 'e' is not a variable (nor a ). +** (Expression still may have jump lists.) +*/ +void luaK_dischargevars (FuncState *fs, expdesc *e) { + switch (e->k) { + case VCONST: { + const2exp(const2val(fs, e), e); + break; + } + case VLOCAL: { /* already in a register */ + e->u.info = e->u.var.ridx; + e->k = VNONRELOC; /* becomes a non-relocatable value */ + break; + } + case VUPVAL: { /* move value to some (pending) register */ + e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); + e->k = VRELOC; + break; + } + case VINDEXUP: { + e->u.info = luaK_codeABC(fs, OP_GETTABUP, 0, e->u.ind.t, e->u.ind.idx); + e->k = VRELOC; + break; + } + case VINDEXI: { + freereg(fs, e->u.ind.t); + e->u.info = luaK_codeABC(fs, OP_GETI, 0, e->u.ind.t, e->u.ind.idx); + e->k = VRELOC; + break; + } + case VINDEXSTR: { + freereg(fs, e->u.ind.t); + e->u.info = luaK_codeABC(fs, OP_GETFIELD, 0, e->u.ind.t, e->u.ind.idx); + e->k = VRELOC; + break; + } + case VINDEXED: { + freeregs(fs, e->u.ind.t, e->u.ind.idx); + e->u.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.ind.t, e->u.ind.idx); + e->k = VRELOC; + break; + } + case VVARARG: case VCALL: { + luaK_setoneret(fs, e); + break; + } + default: break; /* there is one value available (somewhere) */ + } +} + + +/* +** Ensure expression value is in register 'reg', making 'e' a +** non-relocatable expression. +** (Expression still may have jump lists.) +*/ +static void discharge2reg (FuncState *fs, expdesc *e, int reg) { + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: { + luaK_nil(fs, reg, 1); + break; + } + case VFALSE: { + luaK_codeABC(fs, OP_LOADFALSE, reg, 0, 0); + break; + } + case VTRUE: { + luaK_codeABC(fs, OP_LOADTRUE, reg, 0, 0); + break; + } + case VKSTR: { + str2K(fs, e); + } /* FALLTHROUGH */ + case VK: { + luaK_codek(fs, reg, e->u.info); + break; + } + case VKFLT: { + luaK_float(fs, reg, e->u.nval); + break; + } + case VKINT: { + luaK_int(fs, reg, e->u.ival); + break; + } + case VRELOC: { + Instruction *pc = &getinstruction(fs, e); + SETARG_A(*pc, reg); /* instruction will put result in 'reg' */ + break; + } + case VNONRELOC: { + if (reg != e->u.info) + luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0); + break; + } + default: { + lua_assert(e->k == VJMP); + return; /* nothing to do... */ + } + } + e->u.info = reg; + e->k = VNONRELOC; +} + + +/* +** Ensure expression value is in a register, making 'e' a +** non-relocatable expression. +** (Expression still may have jump lists.) +*/ +static void discharge2anyreg (FuncState *fs, expdesc *e) { + if (e->k != VNONRELOC) { /* no fixed register yet? */ + luaK_reserveregs(fs, 1); /* get a register */ + discharge2reg(fs, e, fs->freereg-1); /* put value there */ + } +} + + +static int code_loadbool (FuncState *fs, int A, OpCode op) { + luaK_getlabel(fs); /* those instructions may be jump targets */ + return luaK_codeABC(fs, op, A, 0, 0); +} + + +/* +** check whether list has any jump that do not produce a value +** or produce an inverted value +*/ +static int need_value (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) { + Instruction i = *getjumpcontrol(fs, list); + if (GET_OPCODE(i) != OP_TESTSET) return 1; + } + return 0; /* not found */ +} + + +/* +** Ensures final expression result (which includes results from its +** jump lists) is in register 'reg'. +** If expression has jumps, need to patch these jumps either to +** its final position or to "load" instructions (for those tests +** that do not produce values). +*/ +static void exp2reg (FuncState *fs, expdesc *e, int reg) { + discharge2reg(fs, e, reg); + if (e->k == VJMP) /* expression itself is a test? */ + luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */ + if (hasjumps(e)) { + int final; /* position after whole expression */ + int p_f = NO_JUMP; /* position of an eventual LOAD false */ + int p_t = NO_JUMP; /* position of an eventual LOAD true */ + if (need_value(fs, e->t) || need_value(fs, e->f)) { + int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); + p_f = code_loadbool(fs, reg, OP_LFALSESKIP); /* skip next inst. */ + p_t = code_loadbool(fs, reg, OP_LOADTRUE); + /* jump around these booleans if 'e' is not a test */ + luaK_patchtohere(fs, fj); + } + final = luaK_getlabel(fs); + patchlistaux(fs, e->f, final, reg, p_f); + patchlistaux(fs, e->t, final, reg, p_t); + } + e->f = e->t = NO_JUMP; + e->u.info = reg; + e->k = VNONRELOC; +} + + +/* +** Ensures final expression result is in next available register. +*/ +void luaK_exp2nextreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + freeexp(fs, e); + luaK_reserveregs(fs, 1); + exp2reg(fs, e, fs->freereg - 1); +} + + +/* +** Ensures final expression result is in some (any) register +** and return that register. +*/ +int luaK_exp2anyreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + if (e->k == VNONRELOC) { /* expression already has a register? */ + if (!hasjumps(e)) /* no jumps? */ + return e->u.info; /* result is already in a register */ + if (e->u.info >= luaY_nvarstack(fs)) { /* reg. is not a local? */ + exp2reg(fs, e, e->u.info); /* put final result in it */ + return e->u.info; + } + /* else expression has jumps and cannot change its register + to hold the jump values, because it is a local variable. + Go through to the default case. */ + } + luaK_exp2nextreg(fs, e); /* default: use next available register */ + return e->u.info; +} + + +/* +** Ensures final expression result is either in a register +** or in an upvalue. +*/ +void luaK_exp2anyregup (FuncState *fs, expdesc *e) { + if (e->k != VUPVAL || hasjumps(e)) + luaK_exp2anyreg(fs, e); +} + + +/* +** Ensures final expression result is either in a register +** or it is a constant. +*/ +void luaK_exp2val (FuncState *fs, expdesc *e) { + if (hasjumps(e)) + luaK_exp2anyreg(fs, e); + else + luaK_dischargevars(fs, e); +} + + +/* +** Try to make 'e' a K expression with an index in the range of R/K +** indices. Return true iff succeeded. +*/ +static int luaK_exp2K (FuncState *fs, expdesc *e) { + if (!hasjumps(e)) { + int info; + switch (e->k) { /* move constants to 'k' */ + case VTRUE: info = boolT(fs); break; + case VFALSE: info = boolF(fs); break; + case VNIL: info = nilK(fs); break; + case VKINT: info = luaK_intK(fs, e->u.ival); break; + case VKFLT: info = luaK_numberK(fs, e->u.nval); break; + case VKSTR: info = stringK(fs, e->u.strval); break; + case VK: info = e->u.info; break; + default: return 0; /* not a constant */ + } + if (info <= MAXINDEXRK) { /* does constant fit in 'argC'? */ + e->k = VK; /* make expression a 'K' expression */ + e->u.info = info; + return 1; + } + } + /* else, expression doesn't fit; leave it unchanged */ + return 0; +} + + +/* +** Ensures final expression result is in a valid R/K index +** (that is, it is either in a register or in 'k' with an index +** in the range of R/K indices). +** Returns 1 iff expression is K. +*/ +int luaK_exp2RK (FuncState *fs, expdesc *e) { + if (luaK_exp2K(fs, e)) + return 1; + else { /* not a constant in the right range: put it in a register */ + luaK_exp2anyreg(fs, e); + return 0; + } +} + + +static void codeABRK (FuncState *fs, OpCode o, int a, int b, + expdesc *ec) { + int k = luaK_exp2RK(fs, ec); + luaK_codeABCk(fs, o, a, b, ec->u.info, k); +} + + +/* +** Generate code to store result of expression 'ex' into variable 'var'. +*/ +void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { + switch (var->k) { + case VLOCAL: { + freeexp(fs, ex); + exp2reg(fs, ex, var->u.var.ridx); /* compute 'ex' into proper place */ + return; + } + case VUPVAL: { + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); + break; + } + case VINDEXUP: { + codeABRK(fs, OP_SETTABUP, var->u.ind.t, var->u.ind.idx, ex); + break; + } + case VINDEXI: { + codeABRK(fs, OP_SETI, var->u.ind.t, var->u.ind.idx, ex); + break; + } + case VINDEXSTR: { + codeABRK(fs, OP_SETFIELD, var->u.ind.t, var->u.ind.idx, ex); + break; + } + case VINDEXED: { + codeABRK(fs, OP_SETTABLE, var->u.ind.t, var->u.ind.idx, ex); + break; + } + default: lua_assert(0); /* invalid var kind to store */ + } + freeexp(fs, ex); +} + + +/* +** Emit SELF instruction (convert expression 'e' into 'e:key(e,'). +*/ +void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { + int ereg; + luaK_exp2anyreg(fs, e); + ereg = e->u.info; /* register where 'e' was placed */ + freeexp(fs, e); + e->u.info = fs->freereg; /* base register for op_self */ + e->k = VNONRELOC; /* self expression has a fixed register */ + luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ + codeABRK(fs, OP_SELF, e->u.info, ereg, key); + freeexp(fs, key); +} + + +/* +** Negate condition 'e' (where 'e' is a comparison). +*/ +static void negatecondition (FuncState *fs, expdesc *e) { + Instruction *pc = getjumpcontrol(fs, e->u.info); + lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && + GET_OPCODE(*pc) != OP_TEST); + SETARG_k(*pc, (GETARG_k(*pc) ^ 1)); +} + + +/* +** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond' +** is true, code will jump if 'e' is true.) Return jump position. +** Optimize when 'e' is 'not' something, inverting the condition +** and removing the 'not'. +*/ +static int jumponcond (FuncState *fs, expdesc *e, int cond) { + if (e->k == VRELOC) { + Instruction ie = getinstruction(fs, e); + if (GET_OPCODE(ie) == OP_NOT) { + removelastinstruction(fs); /* remove previous OP_NOT */ + return condjump(fs, OP_TEST, GETARG_B(ie), 0, 0, !cond); + } + /* else go through */ + } + discharge2anyreg(fs, e); + freeexp(fs, e); + return condjump(fs, OP_TESTSET, NO_REG, e->u.info, 0, cond); +} + + +/* +** Emit code to go through if 'e' is true, jump otherwise. +*/ +void luaK_goiftrue (FuncState *fs, expdesc *e) { + int pc; /* pc of new jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VJMP: { /* condition? */ + negatecondition(fs, e); /* jump when it is false */ + pc = e->u.info; /* save jump position */ + break; + } + case VK: case VKFLT: case VKINT: case VKSTR: case VTRUE: { + pc = NO_JUMP; /* always true; do nothing */ + break; + } + default: { + pc = jumponcond(fs, e, 0); /* jump when false */ + break; + } + } + luaK_concat(fs, &e->f, pc); /* insert new jump in false list */ + luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */ + e->t = NO_JUMP; +} + + +/* +** Emit code to go through if 'e' is false, jump otherwise. +*/ +void luaK_goiffalse (FuncState *fs, expdesc *e) { + int pc; /* pc of new jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VJMP: { + pc = e->u.info; /* already jump if true */ + break; + } + case VNIL: case VFALSE: { + pc = NO_JUMP; /* always false; do nothing */ + break; + } + default: { + pc = jumponcond(fs, e, 1); /* jump if true */ + break; + } + } + luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */ + luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */ + e->f = NO_JUMP; +} + + +/* +** Code 'not e', doing constant folding. +*/ +static void codenot (FuncState *fs, expdesc *e) { + switch (e->k) { + case VNIL: case VFALSE: { + e->k = VTRUE; /* true == not nil == not false */ + break; + } + case VK: case VKFLT: case VKINT: case VKSTR: case VTRUE: { + e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */ + break; + } + case VJMP: { + negatecondition(fs, e); + break; + } + case VRELOC: + case VNONRELOC: { + discharge2anyreg(fs, e); + freeexp(fs, e); + e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); + e->k = VRELOC; + break; + } + default: lua_assert(0); /* cannot happen */ + } + /* interchange true and false lists */ + { int temp = e->f; e->f = e->t; e->t = temp; } + removevalues(fs, e->f); /* values are useless when negated */ + removevalues(fs, e->t); +} + + +/* +** Check whether expression 'e' is a small literal string +*/ +static int isKstr (FuncState *fs, expdesc *e) { + return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_B && + ttisshrstring(&fs->f->k[e->u.info])); +} + +/* +** Check whether expression 'e' is a literal integer. +*/ +int luaK_isKint (expdesc *e) { + return (e->k == VKINT && !hasjumps(e)); +} + + +/* +** Check whether expression 'e' is a literal integer in +** proper range to fit in register C +*/ +static int isCint (expdesc *e) { + return luaK_isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C)); +} + + +/* +** Check whether expression 'e' is a literal integer in +** proper range to fit in register sC +*/ +static int isSCint (expdesc *e) { + return luaK_isKint(e) && fitsC(e->u.ival); +} + + +/* +** Check whether expression 'e' is a literal integer or float in +** proper range to fit in a register (sB or sC). +*/ +static int isSCnumber (expdesc *e, int *pi, int *isfloat) { + lua_Integer i; + if (e->k == VKINT) + i = e->u.ival; + else if (e->k == VKFLT && luaV_flttointeger(e->u.nval, &i, F2Ieq)) + *isfloat = 1; + else + return 0; /* not a number */ + if (!hasjumps(e) && fitsC(i)) { + *pi = int2sC(cast_int(i)); + return 1; + } + else + return 0; +} + + +/* +** Create expression 't[k]'. 't' must have its final result already in a +** register or upvalue. Upvalues can only be indexed by literal strings. +** Keys can be literal strings in the constant table or arbitrary +** values in registers. +*/ +void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { + if (k->k == VKSTR) + str2K(fs, k); + lua_assert(!hasjumps(t) && + (t->k == VLOCAL || t->k == VNONRELOC || t->k == VUPVAL)); + if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */ + luaK_exp2anyreg(fs, t); /* put it in a register */ + if (t->k == VUPVAL) { + t->u.ind.t = t->u.info; /* upvalue index */ + t->u.ind.idx = k->u.info; /* literal string */ + t->k = VINDEXUP; + } + else { + /* register index of the table */ + t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info; + if (isKstr(fs, k)) { + t->u.ind.idx = k->u.info; /* literal string */ + t->k = VINDEXSTR; + } + else if (isCint(k)) { + t->u.ind.idx = cast_int(k->u.ival); /* int. constant in proper range */ + t->k = VINDEXI; + } + else { + t->u.ind.idx = luaK_exp2anyreg(fs, k); /* register */ + t->k = VINDEXED; + } + } +} + + +/* +** Return false if folding can raise an error. +** Bitwise operations need operands convertible to integers; division +** operations cannot have 0 as divisor. +*/ +static int validop (int op, TValue *v1, TValue *v2) { + switch (op) { + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ + lua_Integer i; + return (luaV_tointegerns(v1, &i, LUA_FLOORN2I) && + luaV_tointegerns(v2, &i, LUA_FLOORN2I)); + } + case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ + return (nvalue(v2) != 0); + default: return 1; /* everything else is valid */ + } +} + + +/* +** Try to "constant-fold" an operation; return 1 iff successful. +** (In this case, 'e1' has the final result.) +*/ +static int constfolding (FuncState *fs, int op, expdesc *e1, + const expdesc *e2) { + TValue v1, v2, res; + if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) + return 0; /* non-numeric operands or not safe to fold */ + luaO_rawarith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ + if (ttisinteger(&res)) { + e1->k = VKINT; + e1->u.ival = ivalue(&res); + } + else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */ + lua_Number n = fltvalue(&res); + if (luai_numisnan(n) || n == 0) + return 0; + e1->k = VKFLT; + e1->u.nval = n; + } + return 1; +} + + +/* +** Convert a BinOpr to an OpCode (ORDER OPR - ORDER OP) +*/ +l_sinline OpCode binopr2op (BinOpr opr, BinOpr baser, OpCode base) { + lua_assert(baser <= opr && + ((baser == OPR_ADD && opr <= OPR_SHR) || + (baser == OPR_LT && opr <= OPR_LE))); + return cast(OpCode, (cast_int(opr) - cast_int(baser)) + cast_int(base)); +} + + +/* +** Convert a UnOpr to an OpCode (ORDER OPR - ORDER OP) +*/ +l_sinline OpCode unopr2op (UnOpr opr) { + return cast(OpCode, (cast_int(opr) - cast_int(OPR_MINUS)) + + cast_int(OP_UNM)); +} + + +/* +** Convert a BinOpr to a tag method (ORDER OPR - ORDER TM) +*/ +l_sinline TMS binopr2TM (BinOpr opr) { + lua_assert(OPR_ADD <= opr && opr <= OPR_SHR); + return cast(TMS, (cast_int(opr) - cast_int(OPR_ADD)) + cast_int(TM_ADD)); +} + + +/* +** Emit code for unary expressions that "produce values" +** (everything but 'not'). +** Expression to produce final result will be encoded in 'e'. +*/ +static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) { + int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */ + freeexp(fs, e); + e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */ + e->k = VRELOC; /* all those operations are relocatable */ + luaK_fixline(fs, line); +} + + +/* +** Emit code for binary expressions that "produce values" +** (everything but logical operators 'and'/'or' and comparison +** operators). +** Expression to produce final result will be encoded in 'e1'. +*/ +static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2, + OpCode op, int v2, int flip, int line, + OpCode mmop, TMS event) { + int v1 = luaK_exp2anyreg(fs, e1); + int pc = luaK_codeABCk(fs, op, 0, v1, v2, 0); + freeexps(fs, e1, e2); + e1->u.info = pc; + e1->k = VRELOC; /* all those operations are relocatable */ + luaK_fixline(fs, line); + luaK_codeABCk(fs, mmop, v1, v2, event, flip); /* to call metamethod */ + luaK_fixline(fs, line); +} + + +/* +** Emit code for binary expressions that "produce values" over +** two registers. +*/ +static void codebinexpval (FuncState *fs, BinOpr opr, + expdesc *e1, expdesc *e2, int line) { + OpCode op = binopr2op(opr, OPR_ADD, OP_ADD); + int v2 = luaK_exp2anyreg(fs, e2); /* make sure 'e2' is in a register */ + /* 'e1' must be already in a register or it is a constant */ + lua_assert((VNIL <= e1->k && e1->k <= VKSTR) || + e1->k == VNONRELOC || e1->k == VRELOC); + lua_assert(OP_ADD <= op && op <= OP_SHR); + finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, binopr2TM(opr)); +} + + +/* +** Code binary operators with immediate operands. +*/ +static void codebini (FuncState *fs, OpCode op, + expdesc *e1, expdesc *e2, int flip, int line, + TMS event) { + int v2 = int2sC(cast_int(e2->u.ival)); /* immediate operand */ + lua_assert(e2->k == VKINT); + finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINI, event); +} + + +/* +** Code binary operators with K operand. +*/ +static void codebinK (FuncState *fs, BinOpr opr, + expdesc *e1, expdesc *e2, int flip, int line) { + TMS event = binopr2TM(opr); + int v2 = e2->u.info; /* K index */ + OpCode op = binopr2op(opr, OPR_ADD, OP_ADDK); + finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event); +} + + +/* Try to code a binary operator negating its second operand. +** For the metamethod, 2nd operand must keep its original value. +*/ +static int finishbinexpneg (FuncState *fs, expdesc *e1, expdesc *e2, + OpCode op, int line, TMS event) { + if (!luaK_isKint(e2)) + return 0; /* not an integer constant */ + else { + lua_Integer i2 = e2->u.ival; + if (!(fitsC(i2) && fitsC(-i2))) + return 0; /* not in the proper range */ + else { /* operating a small integer constant */ + int v2 = cast_int(i2); + finishbinexpval(fs, e1, e2, op, int2sC(-v2), 0, line, OP_MMBINI, event); + /* correct metamethod argument */ + SETARG_B(fs->f->code[fs->pc - 1], int2sC(v2)); + return 1; /* successfully coded */ + } + } +} + + +static void swapexps (expdesc *e1, expdesc *e2) { + expdesc temp = *e1; *e1 = *e2; *e2 = temp; /* swap 'e1' and 'e2' */ +} + + +/* +** Code binary operators with no constant operand. +*/ +static void codebinNoK (FuncState *fs, BinOpr opr, + expdesc *e1, expdesc *e2, int flip, int line) { + if (flip) + swapexps(e1, e2); /* back to original order */ + codebinexpval(fs, opr, e1, e2, line); /* use standard operators */ +} + + +/* +** Code arithmetic operators ('+', '-', ...). If second operand is a +** constant in the proper range, use variant opcodes with K operands. +*/ +static void codearith (FuncState *fs, BinOpr opr, + expdesc *e1, expdesc *e2, int flip, int line) { + if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) /* K operand? */ + codebinK(fs, opr, e1, e2, flip, line); + else /* 'e2' is neither an immediate nor a K operand */ + codebinNoK(fs, opr, e1, e2, flip, line); +} + + +/* +** Code commutative operators ('+', '*'). If first operand is a +** numeric constant, change order of operands to try to use an +** immediate or K operator. +*/ +static void codecommutative (FuncState *fs, BinOpr op, + expdesc *e1, expdesc *e2, int line) { + int flip = 0; + if (tonumeral(e1, NULL)) { /* is first operand a numeric constant? */ + swapexps(e1, e2); /* change order */ + flip = 1; + } + if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */ + codebini(fs, OP_ADDI, e1, e2, flip, line, TM_ADD); + else + codearith(fs, op, e1, e2, flip, line); +} + + +/* +** Code bitwise operations; they are all commutative, so the function +** tries to put an integer constant as the 2nd operand (a K operand). +*/ +static void codebitwise (FuncState *fs, BinOpr opr, + expdesc *e1, expdesc *e2, int line) { + int flip = 0; + if (e1->k == VKINT) { + swapexps(e1, e2); /* 'e2' will be the constant operand */ + flip = 1; + } + if (e2->k == VKINT && luaK_exp2K(fs, e2)) /* K operand? */ + codebinK(fs, opr, e1, e2, flip, line); + else /* no constants */ + codebinNoK(fs, opr, e1, e2, flip, line); +} + + +/* +** Emit code for order comparisons. When using an immediate operand, +** 'isfloat' tells whether the original value was a float. +*/ +static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { + int r1, r2; + int im; + int isfloat = 0; + OpCode op; + if (isSCnumber(e2, &im, &isfloat)) { + /* use immediate operand */ + r1 = luaK_exp2anyreg(fs, e1); + r2 = im; + op = binopr2op(opr, OPR_LT, OP_LTI); + } + else if (isSCnumber(e1, &im, &isfloat)) { + /* transform (A < B) to (B > A) and (A <= B) to (B >= A) */ + r1 = luaK_exp2anyreg(fs, e2); + r2 = im; + op = binopr2op(opr, OPR_LT, OP_GTI); + } + else { /* regular case, compare two registers */ + r1 = luaK_exp2anyreg(fs, e1); + r2 = luaK_exp2anyreg(fs, e2); + op = binopr2op(opr, OPR_LT, OP_LT); + } + freeexps(fs, e1, e2); + e1->u.info = condjump(fs, op, r1, r2, isfloat, 1); + e1->k = VJMP; +} + + +/* +** Emit code for equality comparisons ('==', '~='). +** 'e1' was already put as RK by 'luaK_infix'. +*/ +static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { + int r1, r2; + int im; + int isfloat = 0; /* not needed here, but kept for symmetry */ + OpCode op; + if (e1->k != VNONRELOC) { + lua_assert(e1->k == VK || e1->k == VKINT || e1->k == VKFLT); + swapexps(e1, e2); + } + r1 = luaK_exp2anyreg(fs, e1); /* 1st expression must be in register */ + if (isSCnumber(e2, &im, &isfloat)) { + op = OP_EQI; + r2 = im; /* immediate operand */ + } + else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */ + op = OP_EQK; + r2 = e2->u.info; /* constant index */ + } + else { + op = OP_EQ; /* will compare two registers */ + r2 = luaK_exp2anyreg(fs, e2); + } + freeexps(fs, e1, e2); + e1->u.info = condjump(fs, op, r1, r2, isfloat, (opr == OPR_EQ)); + e1->k = VJMP; +} + + +/* +** Apply prefix operation 'op' to expression 'e'. +*/ +void luaK_prefix (FuncState *fs, UnOpr opr, expdesc *e, int line) { + static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; + luaK_dischargevars(fs, e); + switch (opr) { + case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ + if (constfolding(fs, opr + LUA_OPUNM, e, &ef)) + break; + /* else */ /* FALLTHROUGH */ + case OPR_LEN: + codeunexpval(fs, unopr2op(opr), e, line); + break; + case OPR_NOT: codenot(fs, e); break; + default: lua_assert(0); + } +} + + +/* +** Process 1st operand 'v' of binary operation 'op' before reading +** 2nd operand. +*/ +void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { + luaK_dischargevars(fs, v); + switch (op) { + case OPR_AND: { + luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */ + break; + } + case OPR_OR: { + luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */ + break; + } + case OPR_CONCAT: { + luaK_exp2nextreg(fs, v); /* operand must be on the stack */ + break; + } + case OPR_ADD: case OPR_SUB: + case OPR_MUL: case OPR_DIV: case OPR_IDIV: + case OPR_MOD: case OPR_POW: + case OPR_BAND: case OPR_BOR: case OPR_BXOR: + case OPR_SHL: case OPR_SHR: { + if (!tonumeral(v, NULL)) + luaK_exp2anyreg(fs, v); + /* else keep numeral, which may be folded or used as an immediate + operand */ + break; + } + case OPR_EQ: case OPR_NE: { + if (!tonumeral(v, NULL)) + luaK_exp2RK(fs, v); + /* else keep numeral, which may be an immediate operand */ + break; + } + case OPR_LT: case OPR_LE: + case OPR_GT: case OPR_GE: { + int dummy, dummy2; + if (!isSCnumber(v, &dummy, &dummy2)) + luaK_exp2anyreg(fs, v); + /* else keep numeral, which may be an immediate operand */ + break; + } + default: lua_assert(0); + } +} + +/* +** Create code for '(e1 .. e2)'. +** For '(e1 .. e2.1 .. e2.2)' (which is '(e1 .. (e2.1 .. e2.2))', +** because concatenation is right associative), merge both CONCATs. +*/ +static void codeconcat (FuncState *fs, expdesc *e1, expdesc *e2, int line) { + Instruction *ie2 = previousinstruction(fs); + if (GET_OPCODE(*ie2) == OP_CONCAT) { /* is 'e2' a concatenation? */ + int n = GETARG_B(*ie2); /* # of elements concatenated in 'e2' */ + lua_assert(e1->u.info + 1 == GETARG_A(*ie2)); + freeexp(fs, e2); + SETARG_A(*ie2, e1->u.info); /* correct first element ('e1') */ + SETARG_B(*ie2, n + 1); /* will concatenate one more element */ + } + else { /* 'e2' is not a concatenation */ + luaK_codeABC(fs, OP_CONCAT, e1->u.info, 2, 0); /* new concat opcode */ + freeexp(fs, e2); + luaK_fixline(fs, line); + } +} + + +/* +** Finalize code for binary operation, after reading 2nd operand. +*/ +void luaK_posfix (FuncState *fs, BinOpr opr, + expdesc *e1, expdesc *e2, int line) { + luaK_dischargevars(fs, e2); + if (foldbinop(opr) && constfolding(fs, opr + LUA_OPADD, e1, e2)) + return; /* done by folding */ + switch (opr) { + case OPR_AND: { + lua_assert(e1->t == NO_JUMP); /* list closed by 'luaK_infix' */ + luaK_concat(fs, &e2->f, e1->f); + *e1 = *e2; + break; + } + case OPR_OR: { + lua_assert(e1->f == NO_JUMP); /* list closed by 'luaK_infix' */ + luaK_concat(fs, &e2->t, e1->t); + *e1 = *e2; + break; + } + case OPR_CONCAT: { /* e1 .. e2 */ + luaK_exp2nextreg(fs, e2); + codeconcat(fs, e1, e2, line); + break; + } + case OPR_ADD: case OPR_MUL: { + codecommutative(fs, opr, e1, e2, line); + break; + } + case OPR_SUB: { + if (finishbinexpneg(fs, e1, e2, OP_ADDI, line, TM_SUB)) + break; /* coded as (r1 + -I) */ + /* ELSE */ + } /* FALLTHROUGH */ + case OPR_DIV: case OPR_IDIV: case OPR_MOD: case OPR_POW: { + codearith(fs, opr, e1, e2, 0, line); + break; + } + case OPR_BAND: case OPR_BOR: case OPR_BXOR: { + codebitwise(fs, opr, e1, e2, line); + break; + } + case OPR_SHL: { + if (isSCint(e1)) { + swapexps(e1, e2); + codebini(fs, OP_SHLI, e1, e2, 1, line, TM_SHL); /* I << r2 */ + } + else if (finishbinexpneg(fs, e1, e2, OP_SHRI, line, TM_SHL)) { + /* coded as (r1 >> -I) */; + } + else /* regular case (two registers) */ + codebinexpval(fs, opr, e1, e2, line); + break; + } + case OPR_SHR: { + if (isSCint(e2)) + codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */ + else /* regular case (two registers) */ + codebinexpval(fs, opr, e1, e2, line); + break; + } + case OPR_EQ: case OPR_NE: { + codeeq(fs, opr, e1, e2); + break; + } + case OPR_GT: case OPR_GE: { + /* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */ + swapexps(e1, e2); + opr = cast(BinOpr, (opr - OPR_GT) + OPR_LT); + } /* FALLTHROUGH */ + case OPR_LT: case OPR_LE: { + codeorder(fs, opr, e1, e2); + break; + } + default: lua_assert(0); + } +} + + +/* +** Change line information associated with current position, by removing +** previous info and adding it again with new line. +*/ +void luaK_fixline (FuncState *fs, int line) { + removelastlineinfo(fs); + savelineinfo(fs, fs->f, line); +} + + +void luaK_settablesize (FuncState *fs, int pc, int ra, int asize, int hsize) { + Instruction *inst = &fs->f->code[pc]; + int rb = (hsize != 0) ? luaO_ceillog2(hsize) + 1 : 0; /* hash size */ + int extra = asize / (MAXARG_C + 1); /* higher bits of array size */ + int rc = asize % (MAXARG_C + 1); /* lower bits of array size */ + int k = (extra > 0); /* true iff needs extra argument */ + *inst = CREATE_ABCk(OP_NEWTABLE, ra, rb, rc, k); + *(inst + 1) = CREATE_Ax(OP_EXTRAARG, extra); +} + + +/* +** Emit a SETLIST instruction. +** 'base' is register that keeps table; +** 'nelems' is #table plus those to be stored now; +** 'tostore' is number of values (in registers 'base + 1',...) to add to +** table (or LUA_MULTRET to add up to stack top). +*/ +void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { + lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH); + if (tostore == LUA_MULTRET) + tostore = 0; + if (nelems <= MAXARG_C) + luaK_codeABC(fs, OP_SETLIST, base, tostore, nelems); + else { + int extra = nelems / (MAXARG_C + 1); + nelems %= (MAXARG_C + 1); + luaK_codeABCk(fs, OP_SETLIST, base, tostore, nelems, 1); + codeextraarg(fs, extra); + } + fs->freereg = base + 1; /* free registers with list values */ +} + + +/* +** return the final target of a jump (skipping jumps to jumps) +*/ +static int finaltarget (Instruction *code, int i) { + int count; + for (count = 0; count < 100; count++) { /* avoid infinite loops */ + Instruction pc = code[i]; + if (GET_OPCODE(pc) != OP_JMP) + break; + else + i += GETARG_sJ(pc) + 1; + } + return i; +} + + +/* +** Do a final pass over the code of a function, doing small peephole +** optimizations and adjustments. +*/ +void luaK_finish (FuncState *fs) { + int i; + Proto *p = fs->f; + for (i = 0; i < fs->pc; i++) { + Instruction *pc = &p->code[i]; + lua_assert(i == 0 || isOT(*(pc - 1)) == isIT(*pc)); + switch (GET_OPCODE(*pc)) { + case OP_RETURN0: case OP_RETURN1: { + if (!(fs->needclose || p->is_vararg)) + break; /* no extra work */ + /* else use OP_RETURN to do the extra work */ + SET_OPCODE(*pc, OP_RETURN); + } /* FALLTHROUGH */ + case OP_RETURN: case OP_TAILCALL: { + if (fs->needclose) + SETARG_k(*pc, 1); /* signal that it needs to close */ + if (p->is_vararg) + SETARG_C(*pc, p->numparams + 1); /* signal that it is vararg */ + break; + } + case OP_JMP: { + int target = finaltarget(p->code, i); + fixjump(fs, i, target); + break; + } + default: break; + } + } +} diff --git a/vendor/lua-src/lua-5.4.6/lcode.h b/vendor/lua-src/lua-5.4.6/lcode.h new file mode 100644 index 0000000000000..3265824452639 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lcode.h @@ -0,0 +1,104 @@ +/* +** $Id: lcode.h $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lcode_h +#define lcode_h + +#include "llex.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" + + +/* +** Marks the end of a patch list. It is an invalid value both as an absolute +** address, and as a list link (would link an element to itself). +*/ +#define NO_JUMP (-1) + + +/* +** grep "ORDER OPR" if you change these enums (ORDER OP) +*/ +typedef enum BinOpr { + /* arithmetic operators */ + OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, + OPR_DIV, OPR_IDIV, + /* bitwise operators */ + OPR_BAND, OPR_BOR, OPR_BXOR, + OPR_SHL, OPR_SHR, + /* string operator */ + OPR_CONCAT, + /* comparison operators */ + OPR_EQ, OPR_LT, OPR_LE, + OPR_NE, OPR_GT, OPR_GE, + /* logical operators */ + OPR_AND, OPR_OR, + OPR_NOBINOPR +} BinOpr; + + +/* true if operation is foldable (that is, it is arithmetic or bitwise) */ +#define foldbinop(op) ((op) <= OPR_SHR) + + +#define luaK_codeABC(fs,o,a,b,c) luaK_codeABCk(fs,o,a,b,c,0) + + +typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; + + +/* get (pointer to) instruction of given 'expdesc' */ +#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info]) + + +#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) + +#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) + +LUAI_FUNC int luaK_code (FuncState *fs, Instruction i); +LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); +LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); +LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, + int B, int C, int k); +LUAI_FUNC int luaK_isKint (expdesc *e); +LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v); +LUAI_FUNC void luaK_fixline (FuncState *fs, int line); +LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); +LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); +LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); +LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n); +LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); +LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); +LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); +LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); +LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_jump (FuncState *fs); +LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); +LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); +LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); +LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); +LUAI_FUNC int luaK_getlabel (FuncState *fs); +LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); +LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); +LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, + expdesc *v2, int line); +LUAI_FUNC void luaK_settablesize (FuncState *fs, int pc, + int ra, int asize, int hsize); +LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); +LUAI_FUNC void luaK_finish (FuncState *fs); +LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *msg); + + +#endif diff --git a/vendor/lua-src/lua-5.4.6/lcorolib.c b/vendor/lua-src/lua-5.4.6/lcorolib.c new file mode 100644 index 0000000000000..c64adf08a8e1a --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lcorolib.c @@ -0,0 +1,210 @@ +/* +** $Id: lcorolib.c $ +** Coroutine Library +** See Copyright Notice in lua.h +*/ + +#define lcorolib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static lua_State *getco (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + luaL_argexpected(L, co, 1, "thread"); + return co; +} + + +/* +** Resumes a coroutine. Returns the number of results for non-error +** cases or -1 for errors. +*/ +static int auxresume (lua_State *L, lua_State *co, int narg) { + int status, nres; + if (l_unlikely(!lua_checkstack(co, narg))) { + lua_pushliteral(L, "too many arguments to resume"); + return -1; /* error flag */ + } + lua_xmove(L, co, narg); + status = lua_resume(co, L, narg, &nres); + if (l_likely(status == LUA_OK || status == LUA_YIELD)) { + if (l_unlikely(!lua_checkstack(L, nres + 1))) { + lua_pop(co, nres); /* remove results anyway */ + lua_pushliteral(L, "too many results to resume"); + return -1; /* error flag */ + } + lua_xmove(co, L, nres); /* move yielded values */ + return nres; + } + else { + lua_xmove(co, L, 1); /* move error message */ + return -1; /* error flag */ + } +} + + +static int luaB_coresume (lua_State *L) { + lua_State *co = getco(L); + int r; + r = auxresume(L, co, lua_gettop(L) - 1); + if (l_unlikely(r < 0)) { + lua_pushboolean(L, 0); + lua_insert(L, -2); + return 2; /* return false + error message */ + } + else { + lua_pushboolean(L, 1); + lua_insert(L, -(r + 1)); + return r + 1; /* return true + 'resume' returns */ + } +} + + +static int luaB_auxwrap (lua_State *L) { + lua_State *co = lua_tothread(L, lua_upvalueindex(1)); + int r = auxresume(L, co, lua_gettop(L)); + if (l_unlikely(r < 0)) { /* error? */ + int stat = lua_status(co); + if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ + stat = lua_closethread(co, L); /* close its tbc variables */ + lua_assert(stat != LUA_OK); + lua_xmove(co, L, 1); /* move error message to the caller */ + } + if (stat != LUA_ERRMEM && /* not a memory error and ... */ + lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */ + luaL_where(L, 1); /* add extra info, if available */ + lua_insert(L, -2); + lua_concat(L, 2); + } + return lua_error(L); /* propagate error */ + } + return r; +} + + +static int luaB_cocreate (lua_State *L) { + lua_State *NL; + luaL_checktype(L, 1, LUA_TFUNCTION); + NL = lua_newthread(L); + lua_pushvalue(L, 1); /* move function to top */ + lua_xmove(L, NL, 1); /* move function from L to NL */ + return 1; +} + + +static int luaB_cowrap (lua_State *L) { + luaB_cocreate(L); + lua_pushcclosure(L, luaB_auxwrap, 1); + return 1; +} + + +static int luaB_yield (lua_State *L) { + return lua_yield(L, lua_gettop(L)); +} + + +#define COS_RUN 0 +#define COS_DEAD 1 +#define COS_YIELD 2 +#define COS_NORM 3 + + +static const char *const statname[] = + {"running", "dead", "suspended", "normal"}; + + +static int auxstatus (lua_State *L, lua_State *co) { + if (L == co) return COS_RUN; + else { + switch (lua_status(co)) { + case LUA_YIELD: + return COS_YIELD; + case LUA_OK: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar)) /* does it have frames? */ + return COS_NORM; /* it is running */ + else if (lua_gettop(co) == 0) + return COS_DEAD; + else + return COS_YIELD; /* initial state */ + } + default: /* some error occurred */ + return COS_DEAD; + } + } +} + + +static int luaB_costatus (lua_State *L) { + lua_State *co = getco(L); + lua_pushstring(L, statname[auxstatus(L, co)]); + return 1; +} + + +static int luaB_yieldable (lua_State *L) { + lua_State *co = lua_isnone(L, 1) ? L : getco(L); + lua_pushboolean(L, lua_isyieldable(co)); + return 1; +} + + +static int luaB_corunning (lua_State *L) { + int ismain = lua_pushthread(L); + lua_pushboolean(L, ismain); + return 2; +} + + +static int luaB_close (lua_State *L) { + lua_State *co = getco(L); + int status = auxstatus(L, co); + switch (status) { + case COS_DEAD: case COS_YIELD: { + status = lua_closethread(co, L); + if (status == LUA_OK) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushboolean(L, 0); + lua_xmove(co, L, 1); /* move error message */ + return 2; + } + } + default: /* normal or running coroutine */ + return luaL_error(L, "cannot close a %s coroutine", statname[status]); + } +} + + +static const luaL_Reg co_funcs[] = { + {"create", luaB_cocreate}, + {"resume", luaB_coresume}, + {"running", luaB_corunning}, + {"status", luaB_costatus}, + {"wrap", luaB_cowrap}, + {"yield", luaB_yield}, + {"isyieldable", luaB_yieldable}, + {"close", luaB_close}, + {NULL, NULL} +}; + + + +LUAMOD_API int luaopen_coroutine (lua_State *L) { + luaL_newlib(L, co_funcs); + return 1; +} + diff --git a/vendor/lua-src/lua-5.4.6/lctype.c b/vendor/lua-src/lua-5.4.6/lctype.c new file mode 100644 index 0000000000000..95422809423a5 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lctype.c @@ -0,0 +1,64 @@ +/* +** $Id: lctype.c $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#define lctype_c +#define LUA_CORE + +#include "lprefix.h" + + +#include "lctype.h" + +#if !LUA_USE_CTYPE /* { */ + +#include + + +#if defined (LUA_UCID) /* accept UniCode IDentifiers? */ +/* consider all non-ascii codepoints to be alphabetic */ +#define NONA 0x01 +#else +#define NONA 0x00 /* default */ +#endif + + +LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { + 0x00, /* EOZ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ + 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 8. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 9. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* a. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* b. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + 0x00, 0x00, NONA, NONA, NONA, NONA, NONA, NONA, /* c. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* d. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* e. */ + NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, + NONA, NONA, NONA, NONA, NONA, 0x00, 0x00, 0x00, /* f. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +#endif /* } */ diff --git a/vendor/lua-src/lua-5.4.6/lctype.h b/vendor/lua-src/lua-5.4.6/lctype.h new file mode 100644 index 0000000000000..864e1901885df --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lctype.h @@ -0,0 +1,101 @@ +/* +** $Id: lctype.h $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lctype_h +#define lctype_h + +#include "lua.h" + + +/* +** WARNING: the functions defined here do not necessarily correspond +** to the similar functions in the standard C ctype.h. They are +** optimized for the specific needs of Lua. +*/ + +#if !defined(LUA_USE_CTYPE) + +#if 'A' == 65 && '0' == 48 +/* ASCII case: can use its own tables; faster and fixed */ +#define LUA_USE_CTYPE 0 +#else +/* must use standard C ctype */ +#define LUA_USE_CTYPE 1 +#endif + +#endif + + +#if !LUA_USE_CTYPE /* { */ + +#include + +#include "llimits.h" + + +#define ALPHABIT 0 +#define DIGITBIT 1 +#define PRINTBIT 2 +#define SPACEBIT 3 +#define XDIGITBIT 4 + + +#define MASK(B) (1 << (B)) + + +/* +** add 1 to char to allow index -1 (EOZ) +*/ +#define testprop(c,p) (luai_ctype_[(c)+1] & (p)) + +/* +** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' +*/ +#define lislalpha(c) testprop(c, MASK(ALPHABIT)) +#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) +#define lisdigit(c) testprop(c, MASK(DIGITBIT)) +#define lisspace(c) testprop(c, MASK(SPACEBIT)) +#define lisprint(c) testprop(c, MASK(PRINTBIT)) +#define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) + + +/* +** In ASCII, this 'ltolower' is correct for alphabetic characters and +** for '.'. That is enough for Lua needs. ('check_exp' ensures that +** the character either is an upper-case letter or is unchanged by +** the transformation, which holds for lower-case letters and '.'.) +*/ +#define ltolower(c) \ + check_exp(('A' <= (c) && (c) <= 'Z') || (c) == ((c) | ('A' ^ 'a')), \ + (c) | ('A' ^ 'a')) + + +/* one entry for each character and for -1 (EOZ) */ +LUAI_DDEC(const lu_byte luai_ctype_[UCHAR_MAX + 2];) + + +#else /* }{ */ + +/* +** use standard C ctypes +*/ + +#include + + +#define lislalpha(c) (isalpha(c) || (c) == '_') +#define lislalnum(c) (isalnum(c) || (c) == '_') +#define lisdigit(c) (isdigit(c)) +#define lisspace(c) (isspace(c)) +#define lisprint(c) (isprint(c)) +#define lisxdigit(c) (isxdigit(c)) + +#define ltolower(c) (tolower(c)) + +#endif /* } */ + +#endif + diff --git a/vendor/lua-src/lua-5.4.6/ldblib.c b/vendor/lua-src/lua-5.4.6/ldblib.c new file mode 100644 index 0000000000000..6dcbaa9824ba5 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/ldblib.c @@ -0,0 +1,483 @@ +/* +** $Id: ldblib.c $ +** Interface from Lua to its debug API +** See Copyright Notice in lua.h +*/ + +#define ldblib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** The hook table at registry[HOOKKEY] maps threads to their current +** hook function. +*/ +static const char *const HOOKKEY = "_HOOKKEY"; + + +/* +** If L1 != L, L1 can be in any state, and therefore there are no +** guarantees about its stack space; any push in L1 must be +** checked. +*/ +static void checkstack (lua_State *L, lua_State *L1, int n) { + if (l_unlikely(L != L1 && !lua_checkstack(L1, n))) + luaL_error(L, "stack overflow"); +} + + +static int db_getregistry (lua_State *L) { + lua_pushvalue(L, LUA_REGISTRYINDEX); + return 1; +} + + +static int db_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); /* no metatable */ + } + return 1; +} + + +static int db_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; /* return 1st argument */ +} + + +static int db_getuservalue (lua_State *L) { + int n = (int)luaL_optinteger(L, 2, 1); + if (lua_type(L, 1) != LUA_TUSERDATA) + luaL_pushfail(L); + else if (lua_getiuservalue(L, 1, n) != LUA_TNONE) { + lua_pushboolean(L, 1); + return 2; + } + return 1; +} + + +static int db_setuservalue (lua_State *L) { + int n = (int)luaL_optinteger(L, 3, 1); + luaL_checktype(L, 1, LUA_TUSERDATA); + luaL_checkany(L, 2); + lua_settop(L, 2); + if (!lua_setiuservalue(L, 1, n)) + luaL_pushfail(L); + return 1; +} + + +/* +** Auxiliary function used by several library functions: check for +** an optional thread as function's first argument and set 'arg' with +** 1 if this argument is present (so that functions can skip it to +** access their other arguments) +*/ +static lua_State *getthread (lua_State *L, int *arg) { + if (lua_isthread(L, 1)) { + *arg = 1; + return lua_tothread(L, 1); + } + else { + *arg = 0; + return L; /* function will operate over current thread */ + } +} + + +/* +** Variations of 'lua_settable', used by 'db_getinfo' to put results +** from 'lua_getinfo' into result table. Key is always a string; +** value can be a string, an int, or a boolean. +*/ +static void settabss (lua_State *L, const char *k, const char *v) { + lua_pushstring(L, v); + lua_setfield(L, -2, k); +} + +static void settabsi (lua_State *L, const char *k, int v) { + lua_pushinteger(L, v); + lua_setfield(L, -2, k); +} + +static void settabsb (lua_State *L, const char *k, int v) { + lua_pushboolean(L, v); + lua_setfield(L, -2, k); +} + + +/* +** In function 'db_getinfo', the call to 'lua_getinfo' may push +** results on the stack; later it creates the result table to put +** these objects. Function 'treatstackoption' puts the result from +** 'lua_getinfo' on top of the result table so that it can call +** 'lua_setfield'. +*/ +static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { + if (L == L1) + lua_rotate(L, -2, 1); /* exchange object and table */ + else + lua_xmove(L1, L, 1); /* move object to the "main" stack */ + lua_setfield(L, -2, fname); /* put object into table */ +} + + +/* +** Calls 'lua_getinfo' and collects all results in a new table. +** L1 needs stack space for an optional input (function) plus +** two optional outputs (function and line table) from function +** 'lua_getinfo'. +*/ +static int db_getinfo (lua_State *L) { + lua_Debug ar; + int arg; + lua_State *L1 = getthread(L, &arg); + const char *options = luaL_optstring(L, arg+2, "flnSrtu"); + checkstack(L, L1, 3); + luaL_argcheck(L, options[0] != '>', arg + 2, "invalid option '>'"); + if (lua_isfunction(L, arg + 1)) { /* info about a function? */ + options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ + lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ + lua_xmove(L, L1, 1); + } + else { /* stack level */ + if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) { + luaL_pushfail(L); /* level out of range */ + return 1; + } + } + if (!lua_getinfo(L1, options, &ar)) + return luaL_argerror(L, arg+2, "invalid option"); + lua_newtable(L); /* table to collect results */ + if (strchr(options, 'S')) { + lua_pushlstring(L, ar.source, ar.srclen); + lua_setfield(L, -2, "source"); + settabss(L, "short_src", ar.short_src); + settabsi(L, "linedefined", ar.linedefined); + settabsi(L, "lastlinedefined", ar.lastlinedefined); + settabss(L, "what", ar.what); + } + if (strchr(options, 'l')) + settabsi(L, "currentline", ar.currentline); + if (strchr(options, 'u')) { + settabsi(L, "nups", ar.nups); + settabsi(L, "nparams", ar.nparams); + settabsb(L, "isvararg", ar.isvararg); + } + if (strchr(options, 'n')) { + settabss(L, "name", ar.name); + settabss(L, "namewhat", ar.namewhat); + } + if (strchr(options, 'r')) { + settabsi(L, "ftransfer", ar.ftransfer); + settabsi(L, "ntransfer", ar.ntransfer); + } + if (strchr(options, 't')) + settabsb(L, "istailcall", ar.istailcall); + if (strchr(options, 'L')) + treatstackoption(L, L1, "activelines"); + if (strchr(options, 'f')) + treatstackoption(L, L1, "func"); + return 1; /* return table */ +} + + +static int db_getlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */ + if (lua_isfunction(L, arg + 1)) { /* function argument? */ + lua_pushvalue(L, arg + 1); /* push function */ + lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ + return 1; /* return only name (there is no value) */ + } + else { /* stack-level argument */ + lua_Debug ar; + const char *name; + int level = (int)luaL_checkinteger(L, arg + 1); + if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + checkstack(L, L1, 1); + name = lua_getlocal(L1, &ar, nvar); + if (name) { + lua_xmove(L1, L, 1); /* move local value */ + lua_pushstring(L, name); /* push name */ + lua_rotate(L, -2, 1); /* re-order */ + return 2; + } + else { + luaL_pushfail(L); /* no name (nor value) */ + return 1; + } + } +} + + +static int db_setlocal (lua_State *L) { + int arg; + const char *name; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + int level = (int)luaL_checkinteger(L, arg + 1); + int nvar = (int)luaL_checkinteger(L, arg + 2); + if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + luaL_checkany(L, arg+3); + lua_settop(L, arg+3); + checkstack(L, L1, 1); + lua_xmove(L, L1, 1); + name = lua_setlocal(L1, &ar, nvar); + if (name == NULL) + lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ + lua_pushstring(L, name); + return 1; +} + + +/* +** get (if 'get' is true) or set an upvalue from a closure +*/ +static int auxupvalue (lua_State *L, int get) { + const char *name; + int n = (int)luaL_checkinteger(L, 2); /* upvalue index */ + luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ + name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); + if (name == NULL) return 0; + lua_pushstring(L, name); + lua_insert(L, -(get+1)); /* no-op if get is false */ + return get + 1; +} + + +static int db_getupvalue (lua_State *L) { + return auxupvalue(L, 1); +} + + +static int db_setupvalue (lua_State *L) { + luaL_checkany(L, 3); + return auxupvalue(L, 0); +} + + +/* +** Check whether a given upvalue from a given closure exists and +** returns its index +*/ +static void *checkupval (lua_State *L, int argf, int argnup, int *pnup) { + void *id; + int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */ + luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ + id = lua_upvalueid(L, argf, nup); + if (pnup) { + luaL_argcheck(L, id != NULL, argnup, "invalid upvalue index"); + *pnup = nup; + } + return id; +} + + +static int db_upvalueid (lua_State *L) { + void *id = checkupval(L, 1, 2, NULL); + if (id != NULL) + lua_pushlightuserdata(L, id); + else + luaL_pushfail(L); + return 1; +} + + +static int db_upvaluejoin (lua_State *L) { + int n1, n2; + checkupval(L, 1, 2, &n1); + checkupval(L, 3, 4, &n2); + luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); + luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); + lua_upvaluejoin(L, 1, n1, 3, n2); + return 0; +} + + +/* +** Call hook function registered at hook table for the current +** thread (if there is one) +*/ +static void hookf (lua_State *L, lua_Debug *ar) { + static const char *const hooknames[] = + {"call", "return", "line", "count", "tail call"}; + lua_getfield(L, LUA_REGISTRYINDEX, HOOKKEY); + lua_pushthread(L); + if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */ + lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */ + if (ar->currentline >= 0) + lua_pushinteger(L, ar->currentline); /* push current line */ + else lua_pushnil(L); + lua_assert(lua_getinfo(L, "lS", ar)); + lua_call(L, 2, 0); /* call hook function */ + } +} + + +/* +** Convert a string mask (for 'sethook') into a bit mask +*/ +static int makemask (const char *smask, int count) { + int mask = 0; + if (strchr(smask, 'c')) mask |= LUA_MASKCALL; + if (strchr(smask, 'r')) mask |= LUA_MASKRET; + if (strchr(smask, 'l')) mask |= LUA_MASKLINE; + if (count > 0) mask |= LUA_MASKCOUNT; + return mask; +} + + +/* +** Convert a bit mask (for 'gethook') into a string mask +*/ +static char *unmakemask (int mask, char *smask) { + int i = 0; + if (mask & LUA_MASKCALL) smask[i++] = 'c'; + if (mask & LUA_MASKRET) smask[i++] = 'r'; + if (mask & LUA_MASKLINE) smask[i++] = 'l'; + smask[i] = '\0'; + return smask; +} + + +static int db_sethook (lua_State *L) { + int arg, mask, count; + lua_Hook func; + lua_State *L1 = getthread(L, &arg); + if (lua_isnoneornil(L, arg+1)) { /* no hook? */ + lua_settop(L, arg+1); + func = NULL; mask = 0; count = 0; /* turn off hooks */ + } + else { + const char *smask = luaL_checkstring(L, arg+2); + luaL_checktype(L, arg+1, LUA_TFUNCTION); + count = (int)luaL_optinteger(L, arg + 3, 0); + func = hookf; mask = makemask(smask, count); + } + if (!luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)) { + /* table just created; initialize it */ + lua_pushliteral(L, "k"); + lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ + lua_pushvalue(L, -1); + lua_setmetatable(L, -2); /* metatable(hooktable) = hooktable */ + } + checkstack(L, L1, 1); + lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */ + lua_pushvalue(L, arg + 1); /* value (hook function) */ + lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ + lua_sethook(L1, func, mask, count); + return 0; +} + + +static int db_gethook (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + char buff[5]; + int mask = lua_gethookmask(L1); + lua_Hook hook = lua_gethook(L1); + if (hook == NULL) { /* no hook? */ + luaL_pushfail(L); + return 1; + } + else if (hook != hookf) /* external hook? */ + lua_pushliteral(L, "external hook"); + else { /* hook table must exist */ + lua_getfield(L, LUA_REGISTRYINDEX, HOOKKEY); + checkstack(L, L1, 1); + lua_pushthread(L1); lua_xmove(L1, L, 1); + lua_rawget(L, -2); /* 1st result = hooktable[L1] */ + lua_remove(L, -2); /* remove hook table */ + } + lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ + lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ + return 3; +} + + +static int db_debug (lua_State *L) { + for (;;) { + char buffer[250]; + lua_writestringerror("%s", "lua_debug> "); + if (fgets(buffer, sizeof(buffer), stdin) == NULL || + strcmp(buffer, "cont\n") == 0) + return 0; + if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || + lua_pcall(L, 0, 0, 0)) + lua_writestringerror("%s\n", luaL_tolstring(L, -1, NULL)); + lua_settop(L, 0); /* remove eventual returns */ + } +} + + +static int db_traceback (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + const char *msg = lua_tostring(L, arg + 1); + if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ + lua_pushvalue(L, arg + 1); /* return it untouched */ + else { + int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0); + luaL_traceback(L, L1, msg, level); + } + return 1; +} + + +static int db_setcstacklimit (lua_State *L) { + int limit = (int)luaL_checkinteger(L, 1); + int res = lua_setcstacklimit(L, limit); + lua_pushinteger(L, res); + return 1; +} + + +static const luaL_Reg dblib[] = { + {"debug", db_debug}, + {"getuservalue", db_getuservalue}, + {"gethook", db_gethook}, + {"getinfo", db_getinfo}, + {"getlocal", db_getlocal}, + {"getregistry", db_getregistry}, + {"getmetatable", db_getmetatable}, + {"getupvalue", db_getupvalue}, + {"upvaluejoin", db_upvaluejoin}, + {"upvalueid", db_upvalueid}, + {"setuservalue", db_setuservalue}, + {"sethook", db_sethook}, + {"setlocal", db_setlocal}, + {"setmetatable", db_setmetatable}, + {"setupvalue", db_setupvalue}, + {"traceback", db_traceback}, + {"setcstacklimit", db_setcstacklimit}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_debug (lua_State *L) { + luaL_newlib(L, dblib); + return 1; +} + diff --git a/vendor/lua-src/lua-5.4.6/ldebug.c b/vendor/lua-src/lua-5.4.6/ldebug.c new file mode 100644 index 0000000000000..28b1caabf77e3 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/ldebug.c @@ -0,0 +1,924 @@ +/* +** $Id: ldebug.c $ +** Debug Interface +** See Copyright Notice in lua.h +*/ + +#define ldebug_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lapi.h" +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + + +#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) + + +static const char *funcnamefromcall (lua_State *L, CallInfo *ci, + const char **name); + + +static int currentpc (CallInfo *ci) { + lua_assert(isLua(ci)); + return pcRel(ci->u.l.savedpc, ci_func(ci)->p); +} + + +/* +** Get a "base line" to find the line corresponding to an instruction. +** Base lines are regularly placed at MAXIWTHABS intervals, so usually +** an integer division gets the right place. When the source file has +** large sequences of empty/comment lines, it may need extra entries, +** so the original estimate needs a correction. +** If the original estimate is -1, the initial 'if' ensures that the +** 'while' will run at least once. +** The assertion that the estimate is a lower bound for the correct base +** is valid as long as the debug info has been generated with the same +** value for MAXIWTHABS or smaller. (Previous releases use a little +** smaller value.) +*/ +static int getbaseline (const Proto *f, int pc, int *basepc) { + if (f->sizeabslineinfo == 0 || pc < f->abslineinfo[0].pc) { + *basepc = -1; /* start from the beginning */ + return f->linedefined; + } + else { + int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */ + /* estimate must be a lower bound of the correct base */ + lua_assert(i < 0 || + (i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc)); + while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc) + i++; /* low estimate; adjust it */ + *basepc = f->abslineinfo[i].pc; + return f->abslineinfo[i].line; + } +} + + +/* +** Get the line corresponding to instruction 'pc' in function 'f'; +** first gets a base line and from there does the increments until +** the desired instruction. +*/ +int luaG_getfuncline (const Proto *f, int pc) { + if (f->lineinfo == NULL) /* no debug information? */ + return -1; + else { + int basepc; + int baseline = getbaseline(f, pc, &basepc); + while (basepc++ < pc) { /* walk until given instruction */ + lua_assert(f->lineinfo[basepc] != ABSLINEINFO); + baseline += f->lineinfo[basepc]; /* correct line */ + } + return baseline; + } +} + + +static int getcurrentline (CallInfo *ci) { + return luaG_getfuncline(ci_func(ci)->p, currentpc(ci)); +} + + +/* +** Set 'trap' for all active Lua frames. +** This function can be called during a signal, under "reasonable" +** assumptions. A new 'ci' is completely linked in the list before it +** becomes part of the "active" list, and we assume that pointers are +** atomic; see comment in next function. +** (A compiler doing interprocedural optimizations could, theoretically, +** reorder memory writes in such a way that the list could be +** temporarily broken while inserting a new element. We simply assume it +** has no good reasons to do that.) +*/ +static void settraps (CallInfo *ci) { + for (; ci != NULL; ci = ci->previous) + if (isLua(ci)) + ci->u.l.trap = 1; +} + + +/* +** This function can be called during a signal, under "reasonable" +** assumptions. +** Fields 'basehookcount' and 'hookcount' (set by 'resethookcount') +** are for debug only, and it is no problem if they get arbitrary +** values (causes at most one wrong hook call). 'hookmask' is an atomic +** value. We assume that pointers are atomic too (e.g., gcc ensures that +** for all platforms where it runs). Moreover, 'hook' is always checked +** before being called (see 'luaD_hook'). +*/ +LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { + if (func == NULL || mask == 0) { /* turn off hooks? */ + mask = 0; + func = NULL; + } + L->hook = func; + L->basehookcount = count; + resethookcount(L); + L->hookmask = cast_byte(mask); + if (mask) + settraps(L->ci); /* to trace inside 'luaV_execute' */ +} + + +LUA_API lua_Hook lua_gethook (lua_State *L) { + return L->hook; +} + + +LUA_API int lua_gethookmask (lua_State *L) { + return L->hookmask; +} + + +LUA_API int lua_gethookcount (lua_State *L) { + return L->basehookcount; +} + + +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { + int status; + CallInfo *ci; + if (level < 0) return 0; /* invalid (negative) level */ + lua_lock(L); + for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous) + level--; + if (level == 0 && ci != &L->base_ci) { /* level found? */ + status = 1; + ar->i_ci = ci; + } + else status = 0; /* no such level */ + lua_unlock(L); + return status; +} + + +static const char *upvalname (const Proto *p, int uv) { + TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name); + if (s == NULL) return "?"; + else return getstr(s); +} + + +static const char *findvararg (CallInfo *ci, int n, StkId *pos) { + if (clLvalue(s2v(ci->func.p))->p->is_vararg) { + int nextra = ci->u.l.nextraargs; + if (n >= -nextra) { /* 'n' is negative */ + *pos = ci->func.p - nextra - (n + 1); + return "(vararg)"; /* generic name for any vararg */ + } + } + return NULL; /* no such vararg */ +} + + +const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) { + StkId base = ci->func.p + 1; + const char *name = NULL; + if (isLua(ci)) { + if (n < 0) /* access to vararg values? */ + return findvararg(ci, n, pos); + else + name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); + } + if (name == NULL) { /* no 'standard' name? */ + StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p; + if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */ + /* generic name for any valid slot */ + name = isLua(ci) ? "(temporary)" : "(C temporary)"; + } + else + return NULL; /* no name */ + } + if (pos) + *pos = base + (n - 1); + return name; +} + + +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { + const char *name; + lua_lock(L); + if (ar == NULL) { /* information about non-active function? */ + if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */ + name = NULL; + else /* consider live variables at function start (parameters) */ + name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0); + } + else { /* active function; get information through 'ar' */ + StkId pos = NULL; /* to avoid warnings */ + name = luaG_findlocal(L, ar->i_ci, n, &pos); + if (name) { + setobjs2s(L, L->top.p, pos); + api_incr_top(L); + } + } + lua_unlock(L); + return name; +} + + +LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { + StkId pos = NULL; /* to avoid warnings */ + const char *name; + lua_lock(L); + name = luaG_findlocal(L, ar->i_ci, n, &pos); + if (name) { + setobjs2s(L, pos, L->top.p - 1); + L->top.p--; /* pop value */ + } + lua_unlock(L); + return name; +} + + +static void funcinfo (lua_Debug *ar, Closure *cl) { + if (noLuaClosure(cl)) { + ar->source = "=[C]"; + ar->srclen = LL("=[C]"); + ar->linedefined = -1; + ar->lastlinedefined = -1; + ar->what = "C"; + } + else { + const Proto *p = cl->l.p; + if (p->source) { + ar->source = getstr(p->source); + ar->srclen = tsslen(p->source); + } + else { + ar->source = "=?"; + ar->srclen = LL("=?"); + } + ar->linedefined = p->linedefined; + ar->lastlinedefined = p->lastlinedefined; + ar->what = (ar->linedefined == 0) ? "main" : "Lua"; + } + luaO_chunkid(ar->short_src, ar->source, ar->srclen); +} + + +static int nextline (const Proto *p, int currentline, int pc) { + if (p->lineinfo[pc] != ABSLINEINFO) + return currentline + p->lineinfo[pc]; + else + return luaG_getfuncline(p, pc); +} + + +static void collectvalidlines (lua_State *L, Closure *f) { + if (noLuaClosure(f)) { + setnilvalue(s2v(L->top.p)); + api_incr_top(L); + } + else { + int i; + TValue v; + const Proto *p = f->l.p; + int currentline = p->linedefined; + Table *t = luaH_new(L); /* new table to store active lines */ + sethvalue2s(L, L->top.p, t); /* push it on stack */ + api_incr_top(L); + setbtvalue(&v); /* boolean 'true' to be the value of all indices */ + if (!p->is_vararg) /* regular function? */ + i = 0; /* consider all instructions */ + else { /* vararg function */ + lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); + currentline = nextline(p, currentline, 0); + i = 1; /* skip first instruction (OP_VARARGPREP) */ + } + for (; i < p->sizelineinfo; i++) { /* for each instruction */ + currentline = nextline(p, currentline, i); /* get its line */ + luaH_setint(L, t, currentline, &v); /* table[line] = true */ + } + } +} + + +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { + /* calling function is a known function? */ + if (ci != NULL && !(ci->callstatus & CIST_TAIL)) + return funcnamefromcall(L, ci->previous, name); + else return NULL; /* no way to find a name */ +} + + +static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, + Closure *f, CallInfo *ci) { + int status = 1; + for (; *what; what++) { + switch (*what) { + case 'S': { + funcinfo(ar, f); + break; + } + case 'l': { + ar->currentline = (ci && isLua(ci)) ? getcurrentline(ci) : -1; + break; + } + case 'u': { + ar->nups = (f == NULL) ? 0 : f->c.nupvalues; + if (noLuaClosure(f)) { + ar->isvararg = 1; + ar->nparams = 0; + } + else { + ar->isvararg = f->l.p->is_vararg; + ar->nparams = f->l.p->numparams; + } + break; + } + case 't': { + ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0; + break; + } + case 'n': { + ar->namewhat = getfuncname(L, ci, &ar->name); + if (ar->namewhat == NULL) { + ar->namewhat = ""; /* not found */ + ar->name = NULL; + } + break; + } + case 'r': { + if (ci == NULL || !(ci->callstatus & CIST_TRAN)) + ar->ftransfer = ar->ntransfer = 0; + else { + ar->ftransfer = ci->u2.transferinfo.ftransfer; + ar->ntransfer = ci->u2.transferinfo.ntransfer; + } + break; + } + case 'L': + case 'f': /* handled by lua_getinfo */ + break; + default: status = 0; /* invalid option */ + } + } + return status; +} + + +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { + int status; + Closure *cl; + CallInfo *ci; + TValue *func; + lua_lock(L); + if (*what == '>') { + ci = NULL; + func = s2v(L->top.p - 1); + api_check(L, ttisfunction(func), "function expected"); + what++; /* skip the '>' */ + L->top.p--; /* pop function */ + } + else { + ci = ar->i_ci; + func = s2v(ci->func.p); + lua_assert(ttisfunction(func)); + } + cl = ttisclosure(func) ? clvalue(func) : NULL; + status = auxgetinfo(L, what, ar, cl, ci); + if (strchr(what, 'f')) { + setobj2s(L, L->top.p, func); + api_incr_top(L); + } + if (strchr(what, 'L')) + collectvalidlines(L, cl); + lua_unlock(L); + return status; +} + + +/* +** {====================================================== +** Symbolic Execution +** ======================================================= +*/ + +static const char *getobjname (const Proto *p, int lastpc, int reg, + const char **name); + + +/* +** Find a "name" for the constant 'c'. +*/ +static void kname (const Proto *p, int c, const char **name) { + TValue *kvalue = &p->k[c]; + *name = (ttisstring(kvalue)) ? svalue(kvalue) : "?"; +} + + +/* +** Find a "name" for the register 'c'. +*/ +static void rname (const Proto *p, int pc, int c, const char **name) { + const char *what = getobjname(p, pc, c, name); /* search for 'c' */ + if (!(what && *what == 'c')) /* did not find a constant name? */ + *name = "?"; +} + + +/* +** Find a "name" for a 'C' value in an RK instruction. +*/ +static void rkname (const Proto *p, int pc, Instruction i, const char **name) { + int c = GETARG_C(i); /* key index */ + if (GETARG_k(i)) /* is 'c' a constant? */ + kname(p, c, name); + else /* 'c' is a register */ + rname(p, pc, c, name); +} + + +static int filterpc (int pc, int jmptarget) { + if (pc < jmptarget) /* is code conditional (inside a jump)? */ + return -1; /* cannot know who sets that register */ + else return pc; /* current position sets that register */ +} + + +/* +** Try to find last instruction before 'lastpc' that modified register 'reg'. +*/ +static int findsetreg (const Proto *p, int lastpc, int reg) { + int pc; + int setreg = -1; /* keep last instruction that changed 'reg' */ + int jmptarget = 0; /* any code before this address is conditional */ + if (testMMMode(GET_OPCODE(p->code[lastpc]))) + lastpc--; /* previous instruction was not actually executed */ + for (pc = 0; pc < lastpc; pc++) { + Instruction i = p->code[pc]; + OpCode op = GET_OPCODE(i); + int a = GETARG_A(i); + int change; /* true if current instruction changed 'reg' */ + switch (op) { + case OP_LOADNIL: { /* set registers from 'a' to 'a+b' */ + int b = GETARG_B(i); + change = (a <= reg && reg <= a + b); + break; + } + case OP_TFORCALL: { /* affect all regs above its base */ + change = (reg >= a + 2); + break; + } + case OP_CALL: + case OP_TAILCALL: { /* affect all registers above base */ + change = (reg >= a); + break; + } + case OP_JMP: { /* doesn't change registers, but changes 'jmptarget' */ + int b = GETARG_sJ(i); + int dest = pc + 1 + b; + /* jump does not skip 'lastpc' and is larger than current one? */ + if (dest <= lastpc && dest > jmptarget) + jmptarget = dest; /* update 'jmptarget' */ + change = 0; + break; + } + default: /* any instruction that sets A */ + change = (testAMode(op) && reg == a); + break; + } + if (change) + setreg = filterpc(pc, jmptarget); + } + return setreg; +} + + +/* +** Check whether table being indexed by instruction 'i' is the +** environment '_ENV' +*/ +static const char *gxf (const Proto *p, int pc, Instruction i, int isup) { + int t = GETARG_B(i); /* table index */ + const char *name; /* name of indexed variable */ + if (isup) /* is an upvalue? */ + name = upvalname(p, t); + else + getobjname(p, pc, t, &name); + return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field"; +} + + +static const char *getobjname (const Proto *p, int lastpc, int reg, + const char **name) { + int pc; + *name = luaF_getlocalname(p, reg + 1, lastpc); + if (*name) /* is a local? */ + return "local"; + /* else try symbolic execution */ + pc = findsetreg(p, lastpc, reg); + if (pc != -1) { /* could find instruction? */ + Instruction i = p->code[pc]; + OpCode op = GET_OPCODE(i); + switch (op) { + case OP_MOVE: { + int b = GETARG_B(i); /* move from 'b' to 'a' */ + if (b < GETARG_A(i)) + return getobjname(p, pc, b, name); /* get name for 'b' */ + break; + } + case OP_GETTABUP: { + int k = GETARG_C(i); /* key index */ + kname(p, k, name); + return gxf(p, pc, i, 1); + } + case OP_GETTABLE: { + int k = GETARG_C(i); /* key index */ + rname(p, pc, k, name); + return gxf(p, pc, i, 0); + } + case OP_GETI: { + *name = "integer index"; + return "field"; + } + case OP_GETFIELD: { + int k = GETARG_C(i); /* key index */ + kname(p, k, name); + return gxf(p, pc, i, 0); + } + case OP_GETUPVAL: { + *name = upvalname(p, GETARG_B(i)); + return "upvalue"; + } + case OP_LOADK: + case OP_LOADKX: { + int b = (op == OP_LOADK) ? GETARG_Bx(i) + : GETARG_Ax(p->code[pc + 1]); + if (ttisstring(&p->k[b])) { + *name = svalue(&p->k[b]); + return "constant"; + } + break; + } + case OP_SELF: { + rkname(p, pc, i, name); + return "method"; + } + default: break; /* go through to return NULL */ + } + } + return NULL; /* could not find reasonable name */ +} + + +/* +** Try to find a name for a function based on the code that called it. +** (Only works when function was called by a Lua function.) +** Returns what the name is (e.g., "for iterator", "method", +** "metamethod") and sets '*name' to point to the name. +*/ +static const char *funcnamefromcode (lua_State *L, const Proto *p, + int pc, const char **name) { + TMS tm = (TMS)0; /* (initial value avoids warnings) */ + Instruction i = p->code[pc]; /* calling instruction */ + switch (GET_OPCODE(i)) { + case OP_CALL: + case OP_TAILCALL: + return getobjname(p, pc, GETARG_A(i), name); /* get function name */ + case OP_TFORCALL: { /* for iterator */ + *name = "for iterator"; + return "for iterator"; + } + /* other instructions can do calls through metamethods */ + case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: + case OP_GETI: case OP_GETFIELD: + tm = TM_INDEX; + break; + case OP_SETTABUP: case OP_SETTABLE: case OP_SETI: case OP_SETFIELD: + tm = TM_NEWINDEX; + break; + case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: { + tm = cast(TMS, GETARG_C(i)); + break; + } + case OP_UNM: tm = TM_UNM; break; + case OP_BNOT: tm = TM_BNOT; break; + case OP_LEN: tm = TM_LEN; break; + case OP_CONCAT: tm = TM_CONCAT; break; + case OP_EQ: tm = TM_EQ; break; + /* no cases for OP_EQI and OP_EQK, as they don't call metamethods */ + case OP_LT: case OP_LTI: case OP_GTI: tm = TM_LT; break; + case OP_LE: case OP_LEI: case OP_GEI: tm = TM_LE; break; + case OP_CLOSE: case OP_RETURN: tm = TM_CLOSE; break; + default: + return NULL; /* cannot find a reasonable name */ + } + *name = getstr(G(L)->tmname[tm]) + 2; + return "metamethod"; +} + + +/* +** Try to find a name for a function based on how it was called. +*/ +static const char *funcnamefromcall (lua_State *L, CallInfo *ci, + const char **name) { + if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ + *name = "?"; + return "hook"; + } + else if (ci->callstatus & CIST_FIN) { /* was it called as a finalizer? */ + *name = "__gc"; + return "metamethod"; /* report it as such */ + } + else if (isLua(ci)) + return funcnamefromcode(L, ci_func(ci)->p, currentpc(ci), name); + else + return NULL; +} + +/* }====================================================== */ + + + +/* +** Check whether pointer 'o' points to some value in the stack frame of +** the current function and, if so, returns its index. Because 'o' may +** not point to a value in this stack, we cannot compare it with the +** region boundaries (undefined behavior in ISO C). +*/ +static int instack (CallInfo *ci, const TValue *o) { + int pos; + StkId base = ci->func.p + 1; + for (pos = 0; base + pos < ci->top.p; pos++) { + if (o == s2v(base + pos)) + return pos; + } + return -1; /* not found */ +} + + +/* +** Checks whether value 'o' came from an upvalue. (That can only happen +** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on +** upvalues.) +*/ +static const char *getupvalname (CallInfo *ci, const TValue *o, + const char **name) { + LClosure *c = ci_func(ci); + int i; + for (i = 0; i < c->nupvalues; i++) { + if (c->upvals[i]->v.p == o) { + *name = upvalname(c->p, i); + return "upvalue"; + } + } + return NULL; +} + + +static const char *formatvarinfo (lua_State *L, const char *kind, + const char *name) { + if (kind == NULL) + return ""; /* no information */ + else + return luaO_pushfstring(L, " (%s '%s')", kind, name); +} + +/* +** Build a string with a "description" for the value 'o', such as +** "variable 'x'" or "upvalue 'y'". +*/ +static const char *varinfo (lua_State *L, const TValue *o) { + CallInfo *ci = L->ci; + const char *name = NULL; /* to avoid warnings */ + const char *kind = NULL; + if (isLua(ci)) { + kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ + if (!kind) { /* not an upvalue? */ + int reg = instack(ci, o); /* try a register */ + if (reg >= 0) /* is 'o' a register? */ + kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name); + } + } + return formatvarinfo(L, kind, name); +} + + +/* +** Raise a type error +*/ +static l_noret typeerror (lua_State *L, const TValue *o, const char *op, + const char *extra) { + const char *t = luaT_objtypename(L, o); + luaG_runerror(L, "attempt to %s a %s value%s", op, t, extra); +} + + +/* +** Raise a type error with "standard" information about the faulty +** object 'o' (using 'varinfo'). +*/ +l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + typeerror(L, o, op, varinfo(L, o)); +} + + +/* +** Raise an error for calling a non-callable object. Try to find a name +** for the object based on how it was called ('funcnamefromcall'); if it +** cannot get a name there, try 'varinfo'. +*/ +l_noret luaG_callerror (lua_State *L, const TValue *o) { + CallInfo *ci = L->ci; + const char *name = NULL; /* to avoid warnings */ + const char *kind = funcnamefromcall(L, ci, &name); + const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o); + typeerror(L, o, "call", extra); +} + + +l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what) { + luaG_runerror(L, "bad 'for' %s (number expected, got %s)", + what, luaT_objtypename(L, o)); +} + + +l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) { + if (ttisstring(p1) || cvt2str(p1)) p1 = p2; + luaG_typeerror(L, p1, "concatenate"); +} + + +l_noret luaG_opinterror (lua_State *L, const TValue *p1, + const TValue *p2, const char *msg) { + if (!ttisnumber(p1)) /* first operand is wrong? */ + p2 = p1; /* now second is wrong */ + luaG_typeerror(L, p2, msg); +} + + +/* +** Error when both values are convertible to numbers, but not to integers +*/ +l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { + lua_Integer temp; + if (!luaV_tointegerns(p1, &temp, LUA_FLOORN2I)) + p2 = p1; + luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); +} + + +l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { + const char *t1 = luaT_objtypename(L, p1); + const char *t2 = luaT_objtypename(L, p2); + if (strcmp(t1, t2) == 0) + luaG_runerror(L, "attempt to compare two %s values", t1); + else + luaG_runerror(L, "attempt to compare %s with %s", t1, t2); +} + + +/* add src:line information to 'msg' */ +const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, + int line) { + char buff[LUA_IDSIZE]; + if (src) + luaO_chunkid(buff, getstr(src), tsslen(src)); + else { /* no source available; use "?" instead */ + buff[0] = '?'; buff[1] = '\0'; + } + return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); +} + + +l_noret luaG_errormsg (lua_State *L) { + if (L->errfunc != 0) { /* is there an error handling function? */ + StkId errfunc = restorestack(L, L->errfunc); + lua_assert(ttisfunction(s2v(errfunc))); + setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */ + setobjs2s(L, L->top.p - 1, errfunc); /* push function */ + L->top.p++; /* assume EXTRA_STACK */ + luaD_callnoyield(L, L->top.p - 2, 1); /* call it */ + } + luaD_throw(L, LUA_ERRRUN); +} + + +l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { + CallInfo *ci = L->ci; + const char *msg; + va_list argp; + luaC_checkGC(L); /* error message uses memory */ + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); /* format message */ + va_end(argp); + if (isLua(ci)) { /* if Lua function, add source:line information */ + luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci)); + setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */ + L->top.p--; + } + luaG_errormsg(L); +} + + +/* +** Check whether new instruction 'newpc' is in a different line from +** previous instruction 'oldpc'. More often than not, 'newpc' is only +** one or a few instructions after 'oldpc' (it must be after, see +** caller), so try to avoid calling 'luaG_getfuncline'. If they are +** too far apart, there is a good chance of a ABSLINEINFO in the way, +** so it goes directly to 'luaG_getfuncline'. +*/ +static int changedline (const Proto *p, int oldpc, int newpc) { + if (p->lineinfo == NULL) /* no debug information? */ + return 0; + if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */ + int delta = 0; /* line difference */ + int pc = oldpc; + for (;;) { + int lineinfo = p->lineinfo[++pc]; + if (lineinfo == ABSLINEINFO) + break; /* cannot compute delta; fall through */ + delta += lineinfo; + if (pc == newpc) + return (delta != 0); /* delta computed successfully */ + } + } + /* either instructions are too far apart or there is an absolute line + info in the way; compute line difference explicitly */ + return (luaG_getfuncline(p, oldpc) != luaG_getfuncline(p, newpc)); +} + + +/* +** Traces the execution of a Lua function. Called before the execution +** of each opcode, when debug is on. 'L->oldpc' stores the last +** instruction traced, to detect line changes. When entering a new +** function, 'npci' will be zero and will test as a new line whatever +** the value of 'oldpc'. Some exceptional conditions may return to +** a function without setting 'oldpc'. In that case, 'oldpc' may be +** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc' +** at most causes an extra call to a line hook.) +** This function is not "Protected" when called, so it should correct +** 'L->top.p' before calling anything that can run the GC. +*/ +int luaG_traceexec (lua_State *L, const Instruction *pc) { + CallInfo *ci = L->ci; + lu_byte mask = L->hookmask; + const Proto *p = ci_func(ci)->p; + int counthook; + if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */ + ci->u.l.trap = 0; /* don't need to stop again */ + return 0; /* turn off 'trap' */ + } + pc++; /* reference is always next instruction */ + ci->u.l.savedpc = pc; /* save 'pc' */ + counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); + if (counthook) + resethookcount(L); /* reset count */ + else if (!(mask & LUA_MASKLINE)) + return 1; /* no line hook and count != 0; nothing to be done now */ + if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ + ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ + return 1; /* do not call hook again (VM yielded, so it did not move) */ + } + if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */ + L->top.p = ci->top.p; /* correct top */ + if (counthook) + luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ + if (mask & LUA_MASKLINE) { + /* 'L->oldpc' may be invalid; use zero in this case */ + int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0; + int npci = pcRel(pc, p); + if (npci <= oldpc || /* call hook when jump back (loop), */ + changedline(p, oldpc, npci)) { /* or when enter new line */ + int newline = luaG_getfuncline(p, npci); + luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */ + } + L->oldpc = npci; /* 'pc' of last call to line hook */ + } + if (L->status == LUA_YIELD) { /* did hook yield? */ + if (counthook) + L->hookcount = 1; /* undo decrement to zero */ + ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ + luaD_throw(L, LUA_YIELD); + } + return 1; /* keep 'trap' on */ +} + diff --git a/vendor/lua-src/lua-5.4.6/ldebug.h b/vendor/lua-src/lua-5.4.6/ldebug.h new file mode 100644 index 0000000000000..2c3074c61b6fb --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/ldebug.h @@ -0,0 +1,63 @@ +/* +** $Id: ldebug.h $ +** Auxiliary functions from Debug Interface module +** See Copyright Notice in lua.h +*/ + +#ifndef ldebug_h +#define ldebug_h + + +#include "lstate.h" + + +#define pcRel(pc, p) (cast_int((pc) - (p)->code) - 1) + + +/* Active Lua function (given call info) */ +#define ci_func(ci) (clLvalue(s2v((ci)->func.p))) + + +#define resethookcount(L) (L->hookcount = L->basehookcount) + +/* +** mark for entries in 'lineinfo' array that has absolute information in +** 'abslineinfo' array +*/ +#define ABSLINEINFO (-0x80) + + +/* +** MAXimum number of successive Instructions WiTHout ABSolute line +** information. (A power of two allows fast divisions.) +*/ +#if !defined(MAXIWTHABS) +#define MAXIWTHABS 128 +#endif + + +LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc); +LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, + StkId *pos); +LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, + const char *opname); +LUAI_FUNC l_noret luaG_callerror (lua_State *L, const TValue *o); +LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o, + const char *what); +LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, + const TValue *p2, + const char *msg); +LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); +LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, + TString *src, int line); +LUAI_FUNC l_noret luaG_errormsg (lua_State *L); +LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc); + + +#endif diff --git a/vendor/lua-src/lua-5.4.6/ldo.c b/vendor/lua-src/lua-5.4.6/ldo.c new file mode 100644 index 0000000000000..2a0017ca62a31 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/ldo.c @@ -0,0 +1,1024 @@ +/* +** $Id: ldo.c $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +#define ldo_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" +#include "lzio.h" + + + +#define errorstatus(s) ((s) > LUA_YIELD) + + +/* +** {====================================================== +** Error-recovery functions +** ======================================================= +*/ + +/* +** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By +** default, Lua handles errors with exceptions when compiling as +** C++ code, with _longjmp/_setjmp when asked to use them, and with +** longjmp/setjmp otherwise. +*/ +#if !defined(LUAI_THROW) /* { */ + +#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* { */ + +/* C++ exceptions */ +#define LUAI_THROW(L,c) throw(c) +#define LUAI_TRY(L,c,a) \ + try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; } +#define luai_jmpbuf int /* dummy variable */ + +#elif defined(LUA_USE_POSIX) /* }{ */ + +/* in POSIX, try _longjmp/_setjmp (more efficient) */ +#define LUAI_THROW(L,c) _longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#else /* }{ */ + +/* ISO C handling with long jumps */ +#define LUAI_THROW(L,c) longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#endif /* } */ + +#endif /* } */ + + + +/* chain list of long jump buffers */ +struct lua_longjmp { + struct lua_longjmp *previous; + luai_jmpbuf b; + volatile int status; /* error code */ +}; + + +void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { + switch (errcode) { + case LUA_ERRMEM: { /* memory error? */ + setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ + break; + } + case LUA_ERRERR: { + setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); + break; + } + case LUA_OK: { /* special case only for closing upvalues */ + setnilvalue(s2v(oldtop)); /* no error message */ + break; + } + default: { + lua_assert(errorstatus(errcode)); /* real error */ + setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */ + break; + } + } + L->top.p = oldtop + 1; +} + + +l_noret luaD_throw (lua_State *L, int errcode) { + if (L->errorJmp) { /* thread has an error handler? */ + L->errorJmp->status = errcode; /* set status */ + LUAI_THROW(L, L->errorJmp); /* jump to it */ + } + else { /* thread has no error handler */ + global_State *g = G(L); + errcode = luaE_resetthread(L, errcode); /* close all upvalues */ + if (g->mainthread->errorJmp) { /* main thread has a handler? */ + setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */ + luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ + } + else { /* no handler at all; abort */ + if (g->panic) { /* panic function? */ + lua_unlock(L); + g->panic(L); /* call panic function (last chance to jump out) */ + } + abort(); + } + } +} + + +int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { + l_uint32 oldnCcalls = L->nCcalls; + struct lua_longjmp lj; + lj.status = LUA_OK; + lj.previous = L->errorJmp; /* chain new error handler */ + L->errorJmp = &lj; + LUAI_TRY(L, &lj, + (*f)(L, ud); + ); + L->errorJmp = lj.previous; /* restore old error handler */ + L->nCcalls = oldnCcalls; + return lj.status; +} + +/* }====================================================== */ + + +/* +** {================================================================== +** Stack reallocation +** =================================================================== +*/ + + +/* +** Change all pointers to the stack into offsets. +*/ +static void relstack (lua_State *L) { + CallInfo *ci; + UpVal *up; + L->top.offset = savestack(L, L->top.p); + L->tbclist.offset = savestack(L, L->tbclist.p); + for (up = L->openupval; up != NULL; up = up->u.open.next) + up->v.offset = savestack(L, uplevel(up)); + for (ci = L->ci; ci != NULL; ci = ci->previous) { + ci->top.offset = savestack(L, ci->top.p); + ci->func.offset = savestack(L, ci->func.p); + } +} + + +/* +** Change back all offsets into pointers. +*/ +static void correctstack (lua_State *L) { + CallInfo *ci; + UpVal *up; + L->top.p = restorestack(L, L->top.offset); + L->tbclist.p = restorestack(L, L->tbclist.offset); + for (up = L->openupval; up != NULL; up = up->u.open.next) + up->v.p = s2v(restorestack(L, up->v.offset)); + for (ci = L->ci; ci != NULL; ci = ci->previous) { + ci->top.p = restorestack(L, ci->top.offset); + ci->func.p = restorestack(L, ci->func.offset); + if (isLua(ci)) + ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */ + } +} + + +/* some space for error handling */ +#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) + +/* +** Reallocate the stack to a new size, correcting all pointers into it. +** In ISO C, any pointer use after the pointer has been deallocated is +** undefined behavior. So, before the reallocation, all pointers are +** changed to offsets, and after the reallocation they are changed back +** to pointers. As during the reallocation the pointers are invalid, the +** reallocation cannot run emergency collections. +** +** In case of allocation error, raise an error or return false according +** to 'raiseerror'. +*/ +int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { + int oldsize = stacksize(L); + int i; + StkId newstack; + int oldgcstop = G(L)->gcstopem; + lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); + relstack(L); /* change pointers to offsets */ + G(L)->gcstopem = 1; /* stop emergency collection */ + newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK, + newsize + EXTRA_STACK, StackValue); + G(L)->gcstopem = oldgcstop; /* restore emergency collection */ + if (l_unlikely(newstack == NULL)) { /* reallocation failed? */ + correctstack(L); /* change offsets back to pointers */ + if (raiseerror) + luaM_error(L); + else return 0; /* do not raise an error */ + } + L->stack.p = newstack; + correctstack(L); /* change offsets back to pointers */ + L->stack_last.p = L->stack.p + newsize; + for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++) + setnilvalue(s2v(newstack + i)); /* erase new segment */ + return 1; +} + + +/* +** Try to grow the stack by at least 'n' elements. When 'raiseerror' +** is true, raises any error; otherwise, return 0 in case of errors. +*/ +int luaD_growstack (lua_State *L, int n, int raiseerror) { + int size = stacksize(L); + if (l_unlikely(size > LUAI_MAXSTACK)) { + /* if stack is larger than maximum, thread is already using the + extra space reserved for errors, that is, thread is handling + a stack error; cannot grow further than that. */ + lua_assert(stacksize(L) == ERRORSTACKSIZE); + if (raiseerror) + luaD_throw(L, LUA_ERRERR); /* error inside message handler */ + return 0; /* if not 'raiseerror', just signal it */ + } + else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */ + int newsize = 2 * size; /* tentative new size */ + int needed = cast_int(L->top.p - L->stack.p) + n; + if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */ + newsize = LUAI_MAXSTACK; + if (newsize < needed) /* but must respect what was asked for */ + newsize = needed; + if (l_likely(newsize <= LUAI_MAXSTACK)) + return luaD_reallocstack(L, newsize, raiseerror); + } + /* else stack overflow */ + /* add extra size to be able to handle the error message */ + luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror); + if (raiseerror) + luaG_runerror(L, "stack overflow"); + return 0; +} + + +/* +** Compute how much of the stack is being used, by computing the +** maximum top of all call frames in the stack and the current top. +*/ +static int stackinuse (lua_State *L) { + CallInfo *ci; + int res; + StkId lim = L->top.p; + for (ci = L->ci; ci != NULL; ci = ci->previous) { + if (lim < ci->top.p) lim = ci->top.p; + } + lua_assert(lim <= L->stack_last.p + EXTRA_STACK); + res = cast_int(lim - L->stack.p) + 1; /* part of stack in use */ + if (res < LUA_MINSTACK) + res = LUA_MINSTACK; /* ensure a minimum size */ + return res; +} + + +/* +** If stack size is more than 3 times the current use, reduce that size +** to twice the current use. (So, the final stack size is at most 2/3 the +** previous size, and half of its entries are empty.) +** As a particular case, if stack was handling a stack overflow and now +** it is not, 'max' (limited by LUAI_MAXSTACK) will be smaller than +** stacksize (equal to ERRORSTACKSIZE in this case), and so the stack +** will be reduced to a "regular" size. +*/ +void luaD_shrinkstack (lua_State *L) { + int inuse = stackinuse(L); + int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3; + /* if thread is currently not handling a stack overflow and its + size is larger than maximum "reasonable" size, shrink it */ + if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) { + int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2; + luaD_reallocstack(L, nsize, 0); /* ok if that fails */ + } + else /* don't change stack */ + condmovestack(L,{},{}); /* (change only for debugging) */ + luaE_shrinkCI(L); /* shrink CI list */ +} + + +void luaD_inctop (lua_State *L) { + luaD_checkstack(L, 1); + L->top.p++; +} + +/* }================================================================== */ + + +/* +** Call a hook for the given event. Make sure there is a hook to be +** called. (Both 'L->hook' and 'L->hookmask', which trigger this +** function, can be changed asynchronously by signals.) +*/ +void luaD_hook (lua_State *L, int event, int line, + int ftransfer, int ntransfer) { + lua_Hook hook = L->hook; + if (hook && L->allowhook) { /* make sure there is a hook */ + int mask = CIST_HOOKED; + CallInfo *ci = L->ci; + ptrdiff_t top = savestack(L, L->top.p); /* preserve original 'top' */ + ptrdiff_t ci_top = savestack(L, ci->top.p); /* idem for 'ci->top' */ + lua_Debug ar; + ar.event = event; + ar.currentline = line; + ar.i_ci = ci; + if (ntransfer != 0) { + mask |= CIST_TRAN; /* 'ci' has transfer information */ + ci->u2.transferinfo.ftransfer = ftransfer; + ci->u2.transferinfo.ntransfer = ntransfer; + } + if (isLua(ci) && L->top.p < ci->top.p) + L->top.p = ci->top.p; /* protect entire activation register */ + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + if (ci->top.p < L->top.p + LUA_MINSTACK) + ci->top.p = L->top.p + LUA_MINSTACK; + L->allowhook = 0; /* cannot call hooks inside a hook */ + ci->callstatus |= mask; + lua_unlock(L); + (*hook)(L, &ar); + lua_lock(L); + lua_assert(!L->allowhook); + L->allowhook = 1; + ci->top.p = restorestack(L, ci_top); + L->top.p = restorestack(L, top); + ci->callstatus &= ~mask; + } +} + + +/* +** Executes a call hook for Lua functions. This function is called +** whenever 'hookmask' is not zero, so it checks whether call hooks are +** active. +*/ +void luaD_hookcall (lua_State *L, CallInfo *ci) { + L->oldpc = 0; /* set 'oldpc' for new function */ + if (L->hookmask & LUA_MASKCALL) { /* is call hook on? */ + int event = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL + : LUA_HOOKCALL; + Proto *p = ci_func(ci)->p; + ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ + luaD_hook(L, event, -1, 1, p->numparams); + ci->u.l.savedpc--; /* correct 'pc' */ + } +} + + +/* +** Executes a return hook for Lua and C functions and sets/corrects +** 'oldpc'. (Note that this correction is needed by the line hook, so it +** is done even when return hooks are off.) +*/ +static void rethook (lua_State *L, CallInfo *ci, int nres) { + if (L->hookmask & LUA_MASKRET) { /* is return hook on? */ + StkId firstres = L->top.p - nres; /* index of first result */ + int delta = 0; /* correction for vararg functions */ + int ftransfer; + if (isLua(ci)) { + Proto *p = ci_func(ci)->p; + if (p->is_vararg) + delta = ci->u.l.nextraargs + p->numparams + 1; + } + ci->func.p += delta; /* if vararg, back to virtual 'func' */ + ftransfer = cast(unsigned short, firstres - ci->func.p); + luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */ + ci->func.p -= delta; + } + if (isLua(ci = ci->previous)) + L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */ +} + + +/* +** Check whether 'func' has a '__call' metafield. If so, put it in the +** stack, below original 'func', so that 'luaD_precall' can call it. Raise +** an error if there is no '__call' metafield. +*/ +StkId luaD_tryfuncTM (lua_State *L, StkId func) { + const TValue *tm; + StkId p; + checkstackGCp(L, 1, func); /* space for metamethod */ + tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */ + if (l_unlikely(ttisnil(tm))) + luaG_callerror(L, s2v(func)); /* nothing to call */ + for (p = L->top.p; p > func; p--) /* open space for metamethod */ + setobjs2s(L, p, p-1); + L->top.p++; /* stack space pre-allocated by the caller */ + setobj2s(L, func, tm); /* metamethod is the new function to be called */ + return func; +} + + +/* +** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'. +** Handle most typical cases (zero results for commands, one result for +** expressions, multiple results for tail calls/single parameters) +** separated. +*/ +l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) { + StkId firstresult; + int i; + switch (wanted) { /* handle typical cases separately */ + case 0: /* no values needed */ + L->top.p = res; + return; + case 1: /* one value needed */ + if (nres == 0) /* no results? */ + setnilvalue(s2v(res)); /* adjust with nil */ + else /* at least one result */ + setobjs2s(L, res, L->top.p - nres); /* move it to proper place */ + L->top.p = res + 1; + return; + case LUA_MULTRET: + wanted = nres; /* we want all results */ + break; + default: /* two/more results and/or to-be-closed variables */ + if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ + L->ci->callstatus |= CIST_CLSRET; /* in case of yields */ + L->ci->u2.nres = nres; + res = luaF_close(L, res, CLOSEKTOP, 1); + L->ci->callstatus &= ~CIST_CLSRET; + if (L->hookmask) { /* if needed, call hook after '__close's */ + ptrdiff_t savedres = savestack(L, res); + rethook(L, L->ci, nres); + res = restorestack(L, savedres); /* hook can move stack */ + } + wanted = decodeNresults(wanted); + if (wanted == LUA_MULTRET) + wanted = nres; /* we want all results */ + } + break; + } + /* generic case */ + firstresult = L->top.p - nres; /* index of first result */ + if (nres > wanted) /* extra results? */ + nres = wanted; /* don't need them */ + for (i = 0; i < nres; i++) /* move all results to correct place */ + setobjs2s(L, res + i, firstresult + i); + for (; i < wanted; i++) /* complete wanted number of results */ + setnilvalue(s2v(res + i)); + L->top.p = res + wanted; /* top points after the last result */ +} + + +/* +** Finishes a function call: calls hook if necessary, moves current +** number of results to proper place, and returns to previous call +** info. If function has to close variables, hook must be called after +** that. +*/ +void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { + int wanted = ci->nresults; + if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted))) + rethook(L, ci, nres); + /* move results to proper place */ + moveresults(L, ci->func.p, nres, wanted); + /* function cannot be in any of these cases when returning */ + lua_assert(!(ci->callstatus & + (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET))); + L->ci = ci->previous; /* back to caller (after closing variables) */ +} + + + +#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L)) + + +l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, + int mask, StkId top) { + CallInfo *ci = L->ci = next_ci(L); /* new frame */ + ci->func.p = func; + ci->nresults = nret; + ci->callstatus = mask; + ci->top.p = top; + return ci; +} + + +/* +** precall for C functions +*/ +l_sinline int precallC (lua_State *L, StkId func, int nresults, + lua_CFunction f) { + int n; /* number of returns */ + CallInfo *ci; + checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ + L->ci = ci = prepCallInfo(L, func, nresults, CIST_C, + L->top.p + LUA_MINSTACK); + lua_assert(ci->top.p <= L->stack_last.p); + if (l_unlikely(L->hookmask & LUA_MASKCALL)) { + int narg = cast_int(L->top.p - func) - 1; + luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); + } + lua_unlock(L); + n = (*f)(L); /* do the actual call */ + lua_lock(L); + api_checknelems(L, n); + luaD_poscall(L, ci, n); + return n; +} + + +/* +** Prepare a function for a tail call, building its call info on top +** of the current call info. 'narg1' is the number of arguments plus 1 +** (so that it includes the function itself). Return the number of +** results, if it was a C function, or -1 for a Lua function. +*/ +int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, + int narg1, int delta) { + retry: + switch (ttypetag(s2v(func))) { + case LUA_VCCL: /* C closure */ + return precallC(L, func, LUA_MULTRET, clCvalue(s2v(func))->f); + case LUA_VLCF: /* light C function */ + return precallC(L, func, LUA_MULTRET, fvalue(s2v(func))); + case LUA_VLCL: { /* Lua function */ + Proto *p = clLvalue(s2v(func))->p; + int fsize = p->maxstacksize; /* frame size */ + int nfixparams = p->numparams; + int i; + checkstackGCp(L, fsize - delta, func); + ci->func.p -= delta; /* restore 'func' (if vararg) */ + for (i = 0; i < narg1; i++) /* move down function and arguments */ + setobjs2s(L, ci->func.p + i, func + i); + func = ci->func.p; /* moved-down function */ + for (; narg1 <= nfixparams; narg1++) + setnilvalue(s2v(func + narg1)); /* complete missing arguments */ + ci->top.p = func + 1 + fsize; /* top for new function */ + lua_assert(ci->top.p <= L->stack_last.p); + ci->u.l.savedpc = p->code; /* starting point */ + ci->callstatus |= CIST_TAIL; + L->top.p = func + narg1; /* set top */ + return -1; + } + default: { /* not a function */ + func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ + /* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */ + narg1++; + goto retry; /* try again */ + } + } +} + + +/* +** Prepares the call to a function (C or Lua). For C functions, also do +** the call. The function to be called is at '*func'. The arguments +** are on the stack, right after the function. Returns the CallInfo +** to be executed, if it was a Lua function. Otherwise (a C function) +** returns NULL, with all the results on the stack, starting at the +** original function position. +*/ +CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { + retry: + switch (ttypetag(s2v(func))) { + case LUA_VCCL: /* C closure */ + precallC(L, func, nresults, clCvalue(s2v(func))->f); + return NULL; + case LUA_VLCF: /* light C function */ + precallC(L, func, nresults, fvalue(s2v(func))); + return NULL; + case LUA_VLCL: { /* Lua function */ + CallInfo *ci; + Proto *p = clLvalue(s2v(func))->p; + int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */ + int nfixparams = p->numparams; + int fsize = p->maxstacksize; /* frame size */ + checkstackGCp(L, fsize, func); + L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize); + ci->u.l.savedpc = p->code; /* starting point */ + for (; narg < nfixparams; narg++) + setnilvalue(s2v(L->top.p++)); /* complete missing arguments */ + lua_assert(ci->top.p <= L->stack_last.p); + return ci; + } + default: { /* not a function */ + func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ + /* return luaD_precall(L, func, nresults); */ + goto retry; /* try again with metamethod */ + } + } +} + + +/* +** Call a function (C or Lua) through C. 'inc' can be 1 (increment +** number of recursive invocations in the C stack) or nyci (the same +** plus increment number of non-yieldable calls). +** This function can be called with some use of EXTRA_STACK, so it should +** check the stack before doing anything else. 'luaD_precall' already +** does that. +*/ +l_sinline void ccall (lua_State *L, StkId func, int nResults, l_uint32 inc) { + CallInfo *ci; + L->nCcalls += inc; + if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) { + checkstackp(L, 0, func); /* free any use of EXTRA_STACK */ + luaE_checkcstack(L); + } + if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ + ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ + luaV_execute(L, ci); /* call it */ + } + L->nCcalls -= inc; +} + + +/* +** External interface for 'ccall' +*/ +void luaD_call (lua_State *L, StkId func, int nResults) { + ccall(L, func, nResults, 1); +} + + +/* +** Similar to 'luaD_call', but does not allow yields during the call. +*/ +void luaD_callnoyield (lua_State *L, StkId func, int nResults) { + ccall(L, func, nResults, nyci); +} + + +/* +** Finish the job of 'lua_pcallk' after it was interrupted by an yield. +** (The caller, 'finishCcall', does the final call to 'adjustresults'.) +** The main job is to complete the 'luaD_pcall' called by 'lua_pcallk'. +** If a '__close' method yields here, eventually control will be back +** to 'finishCcall' (when that '__close' method finally returns) and +** 'finishpcallk' will run again and close any still pending '__close' +** methods. Similarly, if a '__close' method errs, 'precover' calls +** 'unroll' which calls ''finishCcall' and we are back here again, to +** close any pending '__close' methods. +** Note that, up to the call to 'luaF_close', the corresponding +** 'CallInfo' is not modified, so that this repeated run works like the +** first one (except that it has at least one less '__close' to do). In +** particular, field CIST_RECST preserves the error status across these +** multiple runs, changing only if there is a new error. +*/ +static int finishpcallk (lua_State *L, CallInfo *ci) { + int status = getcistrecst(ci); /* get original status */ + if (l_likely(status == LUA_OK)) /* no error? */ + status = LUA_YIELD; /* was interrupted by an yield */ + else { /* error */ + StkId func = restorestack(L, ci->u2.funcidx); + L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */ + func = luaF_close(L, func, status, 1); /* can yield or raise an error */ + luaD_seterrorobj(L, status, func); + luaD_shrinkstack(L); /* restore stack size in case of overflow */ + setcistrecst(ci, LUA_OK); /* clear original status */ + } + ci->callstatus &= ~CIST_YPCALL; + L->errfunc = ci->u.c.old_errfunc; + /* if it is here, there were errors or yields; unlike 'lua_pcallk', + do not change status */ + return status; +} + + +/* +** Completes the execution of a C function interrupted by an yield. +** The interruption must have happened while the function was either +** closing its tbc variables in 'moveresults' or executing +** 'lua_callk'/'lua_pcallk'. In the first case, it just redoes +** 'luaD_poscall'. In the second case, the call to 'finishpcallk' +** finishes the interrupted execution of 'lua_pcallk'. After that, it +** calls the continuation of the interrupted function and finally it +** completes the job of the 'luaD_call' that called the function. In +** the call to 'adjustresults', we do not know the number of results +** of the function called by 'lua_callk'/'lua_pcallk', so we are +** conservative and use LUA_MULTRET (always adjust). +*/ +static void finishCcall (lua_State *L, CallInfo *ci) { + int n; /* actual number of results from C function */ + if (ci->callstatus & CIST_CLSRET) { /* was returning? */ + lua_assert(hastocloseCfunc(ci->nresults)); + n = ci->u2.nres; /* just redo 'luaD_poscall' */ + /* don't need to reset CIST_CLSRET, as it will be set again anyway */ + } + else { + int status = LUA_YIELD; /* default if there were no errors */ + /* must have a continuation and must be able to call it */ + lua_assert(ci->u.c.k != NULL && yieldable(L)); + if (ci->callstatus & CIST_YPCALL) /* was inside a 'lua_pcallk'? */ + status = finishpcallk(L, ci); /* finish it */ + adjustresults(L, LUA_MULTRET); /* finish 'lua_callk' */ + lua_unlock(L); + n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation */ + lua_lock(L); + api_checknelems(L, n); + } + luaD_poscall(L, ci, n); /* finish 'luaD_call' */ +} + + +/* +** Executes "full continuation" (everything in the stack) of a +** previously interrupted coroutine until the stack is empty (or another +** interruption long-jumps out of the loop). +*/ +static void unroll (lua_State *L, void *ud) { + CallInfo *ci; + UNUSED(ud); + while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ + if (!isLua(ci)) /* C function? */ + finishCcall(L, ci); /* complete its execution */ + else { /* Lua function */ + luaV_finishOp(L); /* finish interrupted instruction */ + luaV_execute(L, ci); /* execute down to higher C 'boundary' */ + } + } +} + + +/* +** Try to find a suspended protected call (a "recover point") for the +** given thread. +*/ +static CallInfo *findpcall (lua_State *L) { + CallInfo *ci; + for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */ + if (ci->callstatus & CIST_YPCALL) + return ci; + } + return NULL; /* no pending pcall */ +} + + +/* +** Signal an error in the call to 'lua_resume', not in the execution +** of the coroutine itself. (Such errors should not be handled by any +** coroutine error handler and should not kill the coroutine.) +*/ +static int resume_error (lua_State *L, const char *msg, int narg) { + L->top.p -= narg; /* remove args from the stack */ + setsvalue2s(L, L->top.p, luaS_new(L, msg)); /* push error message */ + api_incr_top(L); + lua_unlock(L); + return LUA_ERRRUN; +} + + +/* +** Do the work for 'lua_resume' in protected mode. Most of the work +** depends on the status of the coroutine: initial state, suspended +** inside a hook, or regularly suspended (optionally with a continuation +** function), plus erroneous cases: non-suspended coroutine or dead +** coroutine. +*/ +static void resume (lua_State *L, void *ud) { + int n = *(cast(int*, ud)); /* number of arguments */ + StkId firstArg = L->top.p - n; /* first argument */ + CallInfo *ci = L->ci; + if (L->status == LUA_OK) /* starting a coroutine? */ + ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */ + else { /* resuming from previous yield */ + lua_assert(L->status == LUA_YIELD); + L->status = LUA_OK; /* mark that it is running (again) */ + if (isLua(ci)) { /* yielded inside a hook? */ + L->top.p = firstArg; /* discard arguments */ + luaV_execute(L, ci); /* just continue running Lua code */ + } + else { /* 'common' yield */ + if (ci->u.c.k != NULL) { /* does it have a continuation function? */ + lua_unlock(L); + n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ + lua_lock(L); + api_checknelems(L, n); + } + luaD_poscall(L, ci, n); /* finish 'luaD_call' */ + } + unroll(L, NULL); /* run continuation */ + } +} + + +/* +** Unrolls a coroutine in protected mode while there are recoverable +** errors, that is, errors inside a protected call. (Any error +** interrupts 'unroll', and this loop protects it again so it can +** continue.) Stops with a normal end (status == LUA_OK), an yield +** (status == LUA_YIELD), or an unprotected error ('findpcall' doesn't +** find a recover point). +*/ +static int precover (lua_State *L, int status) { + CallInfo *ci; + while (errorstatus(status) && (ci = findpcall(L)) != NULL) { + L->ci = ci; /* go down to recovery functions */ + setcistrecst(ci, status); /* status to finish 'pcall' */ + status = luaD_rawrunprotected(L, unroll, NULL); + } + return status; +} + + +LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, + int *nresults) { + int status; + lua_lock(L); + if (L->status == LUA_OK) { /* may be starting a coroutine */ + if (L->ci != &L->base_ci) /* not in base level? */ + return resume_error(L, "cannot resume non-suspended coroutine", nargs); + else if (L->top.p - (L->ci->func.p + 1) == nargs) /* no function? */ + return resume_error(L, "cannot resume dead coroutine", nargs); + } + else if (L->status != LUA_YIELD) /* ended with errors? */ + return resume_error(L, "cannot resume dead coroutine", nargs); + L->nCcalls = (from) ? getCcalls(from) : 0; + if (getCcalls(L) >= LUAI_MAXCCALLS) + return resume_error(L, "C stack overflow", nargs); + L->nCcalls++; + luai_userstateresume(L, nargs); + api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); + status = luaD_rawrunprotected(L, resume, &nargs); + /* continue running after recoverable errors */ + status = precover(L, status); + if (l_likely(!errorstatus(status))) + lua_assert(status == L->status); /* normal end or yield */ + else { /* unrecoverable error */ + L->status = cast_byte(status); /* mark thread as 'dead' */ + luaD_seterrorobj(L, status, L->top.p); /* push error message */ + L->ci->top.p = L->top.p; + } + *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield + : cast_int(L->top.p - (L->ci->func.p + 1)); + lua_unlock(L); + return status; +} + + +LUA_API int lua_isyieldable (lua_State *L) { + return yieldable(L); +} + + +LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k) { + CallInfo *ci; + luai_userstateyield(L, nresults); + lua_lock(L); + ci = L->ci; + api_checknelems(L, nresults); + if (l_unlikely(!yieldable(L))) { + if (L != G(L)->mainthread) + luaG_runerror(L, "attempt to yield across a C-call boundary"); + else + luaG_runerror(L, "attempt to yield from outside a coroutine"); + } + L->status = LUA_YIELD; + ci->u2.nyield = nresults; /* save number of results */ + if (isLua(ci)) { /* inside a hook? */ + lua_assert(!isLuacode(ci)); + api_check(L, nresults == 0, "hooks cannot yield values"); + api_check(L, k == NULL, "hooks cannot continue after yielding"); + } + else { + if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ + ci->u.c.ctx = ctx; /* save context */ + luaD_throw(L, LUA_YIELD); + } + lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ + lua_unlock(L); + return 0; /* return to 'luaD_hook' */ +} + + +/* +** Auxiliary structure to call 'luaF_close' in protected mode. +*/ +struct CloseP { + StkId level; + int status; +}; + + +/* +** Auxiliary function to call 'luaF_close' in protected mode. +*/ +static void closepaux (lua_State *L, void *ud) { + struct CloseP *pcl = cast(struct CloseP *, ud); + luaF_close(L, pcl->level, pcl->status, 0); +} + + +/* +** Calls 'luaF_close' in protected mode. Return the original status +** or, in case of errors, the new status. +*/ +int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status) { + CallInfo *old_ci = L->ci; + lu_byte old_allowhooks = L->allowhook; + for (;;) { /* keep closing upvalues until no more errors */ + struct CloseP pcl; + pcl.level = restorestack(L, level); pcl.status = status; + status = luaD_rawrunprotected(L, &closepaux, &pcl); + if (l_likely(status == LUA_OK)) /* no more errors? */ + return pcl.status; + else { /* an error occurred; restore saved state and repeat */ + L->ci = old_ci; + L->allowhook = old_allowhooks; + } + } +} + + +/* +** Call the C function 'func' in protected mode, restoring basic +** thread information ('allowhook', etc.) and in particular +** its stack level in case of errors. +*/ +int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t old_top, ptrdiff_t ef) { + int status; + CallInfo *old_ci = L->ci; + lu_byte old_allowhooks = L->allowhook; + ptrdiff_t old_errfunc = L->errfunc; + L->errfunc = ef; + status = luaD_rawrunprotected(L, func, u); + if (l_unlikely(status != LUA_OK)) { /* an error occurred? */ + L->ci = old_ci; + L->allowhook = old_allowhooks; + status = luaD_closeprotected(L, old_top, status); + luaD_seterrorobj(L, status, restorestack(L, old_top)); + luaD_shrinkstack(L); /* restore stack size in case of overflow */ + } + L->errfunc = old_errfunc; + return status; +} + + + +/* +** Execute a protected parser. +*/ +struct SParser { /* data to 'f_parser' */ + ZIO *z; + Mbuffer buff; /* dynamic structure used by the scanner */ + Dyndata dyd; /* dynamic structures used by the parser */ + const char *mode; + const char *name; +}; + + +static void checkmode (lua_State *L, const char *mode, const char *x) { + if (mode && strchr(mode, x[0]) == NULL) { + luaO_pushfstring(L, + "attempt to load a %s chunk (mode is '%s')", x, mode); + luaD_throw(L, LUA_ERRSYNTAX); + } +} + + +static void f_parser (lua_State *L, void *ud) { + LClosure *cl; + struct SParser *p = cast(struct SParser *, ud); + int c = zgetc(p->z); /* read first character */ + if (c == LUA_SIGNATURE[0]) { + checkmode(L, p->mode, "binary"); + cl = luaU_undump(L, p->z, p->name); + } + else { + checkmode(L, p->mode, "text"); + cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); + } + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luaF_initupvals(L, cl); +} + + +int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + const char *mode) { + struct SParser p; + int status; + incnny(L); /* cannot yield during parsing */ + p.z = z; p.name = name; p.mode = mode; + p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0; + p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; + p.dyd.label.arr = NULL; p.dyd.label.size = 0; + luaZ_initbuffer(L, &p.buff); + status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc); + luaZ_freebuffer(L, &p.buff); + luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); + luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); + luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size); + decnny(L); + return status; +} + + diff --git a/vendor/lua-src/lua-5.4.6/ldo.h b/vendor/lua-src/lua-5.4.6/ldo.h new file mode 100644 index 0000000000000..1aa446ad09e90 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/ldo.h @@ -0,0 +1,88 @@ +/* +** $Id: ldo.h $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +#ifndef ldo_h +#define ldo_h + + +#include "llimits.h" +#include "lobject.h" +#include "lstate.h" +#include "lzio.h" + + +/* +** Macro to check stack size and grow stack if needed. Parameters +** 'pre'/'pos' allow the macro to preserve a pointer into the +** stack across reallocations, doing the work only when needed. +** It also allows the running of one GC step when the stack is +** reallocated. +** 'condmovestack' is used in heavy tests to force a stack reallocation +** at every check. +*/ +#define luaD_checkstackaux(L,n,pre,pos) \ + if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \ + { pre; luaD_growstack(L, n, 1); pos; } \ + else { condmovestack(L,pre,pos); } + +/* In general, 'pre'/'pos' are empty (nothing to save) */ +#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0) + + + +#define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p)) +#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n)) + + +/* macro to check stack size, preserving 'p' */ +#define checkstackp(L,n,p) \ + luaD_checkstackaux(L, n, \ + ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \ + p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ + + +/* macro to check stack size and GC, preserving 'p' */ +#define checkstackGCp(L,n,p) \ + luaD_checkstackaux(L, n, \ + ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ + luaC_checkGC(L), /* stack grow uses memory */ \ + p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ + + +/* macro to check stack size and GC */ +#define checkstackGC(L,fsize) \ + luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0) + + +/* type of protected functions, to be ran by 'runprotected' */ +typedef void (*Pfunc) (lua_State *L, void *ud); + +LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); +LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + const char *mode); +LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, + int fTransfer, int nTransfer); +LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); +LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, + int narg1, int delta); +LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); +LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); +LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); +LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func); +LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status); +LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t oldtop, ptrdiff_t ef); +LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres); +LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror); +LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror); +LUAI_FUNC void luaD_shrinkstack (lua_State *L); +LUAI_FUNC void luaD_inctop (lua_State *L); + +LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); +LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); + +#endif + diff --git a/vendor/lua-src/lua-5.4.6/ldump.c b/vendor/lua-src/lua-5.4.6/ldump.c new file mode 100644 index 0000000000000..f231691b77955 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/ldump.c @@ -0,0 +1,230 @@ +/* +** $Id: ldump.c $ +** save precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#define ldump_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lobject.h" +#include "lstate.h" +#include "lundump.h" + + +typedef struct { + lua_State *L; + lua_Writer writer; + void *data; + int strip; + int status; +} DumpState; + + +/* +** All high-level dumps go through dumpVector; you can change it to +** change the endianness of the result +*/ +#define dumpVector(D,v,n) dumpBlock(D,v,(n)*sizeof((v)[0])) + +#define dumpLiteral(D, s) dumpBlock(D,s,sizeof(s) - sizeof(char)) + + +static void dumpBlock (DumpState *D, const void *b, size_t size) { + if (D->status == 0 && size > 0) { + lua_unlock(D->L); + D->status = (*D->writer)(D->L, b, size, D->data); + lua_lock(D->L); + } +} + + +#define dumpVar(D,x) dumpVector(D,&x,1) + + +static void dumpByte (DumpState *D, int y) { + lu_byte x = (lu_byte)y; + dumpVar(D, x); +} + + +/* +** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6" +** rounds up the division.) +*/ +#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7) + +static void dumpSize (DumpState *D, size_t x) { + lu_byte buff[DIBS]; + int n = 0; + do { + buff[DIBS - (++n)] = x & 0x7f; /* fill buffer in reverse order */ + x >>= 7; + } while (x != 0); + buff[DIBS - 1] |= 0x80; /* mark last byte */ + dumpVector(D, buff + DIBS - n, n); +} + + +static void dumpInt (DumpState *D, int x) { + dumpSize(D, x); +} + + +static void dumpNumber (DumpState *D, lua_Number x) { + dumpVar(D, x); +} + + +static void dumpInteger (DumpState *D, lua_Integer x) { + dumpVar(D, x); +} + + +static void dumpString (DumpState *D, const TString *s) { + if (s == NULL) + dumpSize(D, 0); + else { + size_t size = tsslen(s); + const char *str = getstr(s); + dumpSize(D, size + 1); + dumpVector(D, str, size); + } +} + + +static void dumpCode (DumpState *D, const Proto *f) { + dumpInt(D, f->sizecode); + dumpVector(D, f->code, f->sizecode); +} + + +static void dumpFunction(DumpState *D, const Proto *f, TString *psource); + +static void dumpConstants (DumpState *D, const Proto *f) { + int i; + int n = f->sizek; + dumpInt(D, n); + for (i = 0; i < n; i++) { + const TValue *o = &f->k[i]; + int tt = ttypetag(o); + dumpByte(D, tt); + switch (tt) { + case LUA_VNUMFLT: + dumpNumber(D, fltvalue(o)); + break; + case LUA_VNUMINT: + dumpInteger(D, ivalue(o)); + break; + case LUA_VSHRSTR: + case LUA_VLNGSTR: + dumpString(D, tsvalue(o)); + break; + default: + lua_assert(tt == LUA_VNIL || tt == LUA_VFALSE || tt == LUA_VTRUE); + } + } +} + + +static void dumpProtos (DumpState *D, const Proto *f) { + int i; + int n = f->sizep; + dumpInt(D, n); + for (i = 0; i < n; i++) + dumpFunction(D, f->p[i], f->source); +} + + +static void dumpUpvalues (DumpState *D, const Proto *f) { + int i, n = f->sizeupvalues; + dumpInt(D, n); + for (i = 0; i < n; i++) { + dumpByte(D, f->upvalues[i].instack); + dumpByte(D, f->upvalues[i].idx); + dumpByte(D, f->upvalues[i].kind); + } +} + + +static void dumpDebug (DumpState *D, const Proto *f) { + int i, n; + n = (D->strip) ? 0 : f->sizelineinfo; + dumpInt(D, n); + dumpVector(D, f->lineinfo, n); + n = (D->strip) ? 0 : f->sizeabslineinfo; + dumpInt(D, n); + for (i = 0; i < n; i++) { + dumpInt(D, f->abslineinfo[i].pc); + dumpInt(D, f->abslineinfo[i].line); + } + n = (D->strip) ? 0 : f->sizelocvars; + dumpInt(D, n); + for (i = 0; i < n; i++) { + dumpString(D, f->locvars[i].varname); + dumpInt(D, f->locvars[i].startpc); + dumpInt(D, f->locvars[i].endpc); + } + n = (D->strip) ? 0 : f->sizeupvalues; + dumpInt(D, n); + for (i = 0; i < n; i++) + dumpString(D, f->upvalues[i].name); +} + + +static void dumpFunction (DumpState *D, const Proto *f, TString *psource) { + if (D->strip || f->source == psource) + dumpString(D, NULL); /* no debug info or same source as its parent */ + else + dumpString(D, f->source); + dumpInt(D, f->linedefined); + dumpInt(D, f->lastlinedefined); + dumpByte(D, f->numparams); + dumpByte(D, f->is_vararg); + dumpByte(D, f->maxstacksize); + dumpCode(D, f); + dumpConstants(D, f); + dumpUpvalues(D, f); + dumpProtos(D, f); + dumpDebug(D, f); +} + + +static void dumpHeader (DumpState *D) { + dumpLiteral(D, LUA_SIGNATURE); + dumpByte(D, LUAC_VERSION); + dumpByte(D, LUAC_FORMAT); + dumpLiteral(D, LUAC_DATA); + dumpByte(D, sizeof(Instruction)); + dumpByte(D, sizeof(lua_Integer)); + dumpByte(D, sizeof(lua_Number)); + dumpInteger(D, LUAC_INT); + dumpNumber(D, LUAC_NUM); +} + + +/* +** dump Lua function as precompiled chunk +*/ +int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, + int strip) { + DumpState D; + D.L = L; + D.writer = w; + D.data = data; + D.strip = strip; + D.status = 0; + dumpHeader(&D); + dumpByte(&D, f->sizeupvalues); + dumpFunction(&D, f, NULL); + return D.status; +} + diff --git a/vendor/lua-src/lua-5.4.6/lfunc.c b/vendor/lua-src/lua-5.4.6/lfunc.c new file mode 100644 index 0000000000000..0945f241de2d5 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lfunc.c @@ -0,0 +1,294 @@ +/* +** $Id: lfunc.c $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + +#define lfunc_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +CClosure *luaF_newCclosure (lua_State *L, int nupvals) { + GCObject *o = luaC_newobj(L, LUA_VCCL, sizeCclosure(nupvals)); + CClosure *c = gco2ccl(o); + c->nupvalues = cast_byte(nupvals); + return c; +} + + +LClosure *luaF_newLclosure (lua_State *L, int nupvals) { + GCObject *o = luaC_newobj(L, LUA_VLCL, sizeLclosure(nupvals)); + LClosure *c = gco2lcl(o); + c->p = NULL; + c->nupvalues = cast_byte(nupvals); + while (nupvals--) c->upvals[nupvals] = NULL; + return c; +} + + +/* +** fill a closure with new closed upvalues +*/ +void luaF_initupvals (lua_State *L, LClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) { + GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal)); + UpVal *uv = gco2upv(o); + uv->v.p = &uv->u.value; /* make it closed */ + setnilvalue(uv->v.p); + cl->upvals[i] = uv; + luaC_objbarrier(L, cl, uv); + } +} + + +/* +** Create a new upvalue at the given level, and link it to the list of +** open upvalues of 'L' after entry 'prev'. +**/ +static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) { + GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal)); + UpVal *uv = gco2upv(o); + UpVal *next = *prev; + uv->v.p = s2v(level); /* current value lives in the stack */ + uv->u.open.next = next; /* link it to list of open upvalues */ + uv->u.open.previous = prev; + if (next) + next->u.open.previous = &uv->u.open.next; + *prev = uv; + if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ + L->twups = G(L)->twups; /* link it to the list */ + G(L)->twups = L; + } + return uv; +} + + +/* +** Find and reuse, or create if it does not exist, an upvalue +** at the given level. +*/ +UpVal *luaF_findupval (lua_State *L, StkId level) { + UpVal **pp = &L->openupval; + UpVal *p; + lua_assert(isintwups(L) || L->openupval == NULL); + while ((p = *pp) != NULL && uplevel(p) >= level) { /* search for it */ + lua_assert(!isdead(G(L), p)); + if (uplevel(p) == level) /* corresponding upvalue? */ + return p; /* return it */ + pp = &p->u.open.next; + } + /* not found: create a new upvalue after 'pp' */ + return newupval(L, level, pp); +} + + +/* +** Call closing method for object 'obj' with error message 'err'. The +** boolean 'yy' controls whether the call is yieldable. +** (This function assumes EXTRA_STACK.) +*/ +static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) { + StkId top = L->top.p; + const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); + setobj2s(L, top, tm); /* will call metamethod... */ + setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ + setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ + L->top.p = top + 3; /* add function and arguments */ + if (yy) + luaD_call(L, top, 0); + else + luaD_callnoyield(L, top, 0); +} + + +/* +** Check whether object at given level has a close metamethod and raise +** an error if not. +*/ +static void checkclosemth (lua_State *L, StkId level) { + const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE); + if (ttisnil(tm)) { /* no metamethod? */ + int idx = cast_int(level - L->ci->func.p); /* variable index */ + const char *vname = luaG_findlocal(L, L->ci, idx, NULL); + if (vname == NULL) vname = "?"; + luaG_runerror(L, "variable '%s' got a non-closable value", vname); + } +} + + +/* +** Prepare and call a closing method. +** If status is CLOSEKTOP, the call to the closing method will be pushed +** at the top of the stack. Otherwise, values can be pushed right after +** the 'level' of the upvalue being closed, as everything after that +** won't be used again. +*/ +static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) { + TValue *uv = s2v(level); /* value being closed */ + TValue *errobj; + if (status == CLOSEKTOP) + errobj = &G(L)->nilvalue; /* error object is nil */ + else { /* 'luaD_seterrorobj' will set top to level + 2 */ + errobj = s2v(level + 1); /* error object goes after 'uv' */ + luaD_seterrorobj(L, status, level + 1); /* set error object */ + } + callclosemethod(L, uv, errobj, yy); +} + + +/* +** Maximum value for deltas in 'tbclist', dependent on the type +** of delta. (This macro assumes that an 'L' is in scope where it +** is used.) +*/ +#define MAXDELTA \ + ((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1) + + +/* +** Insert a variable in the list of to-be-closed variables. +*/ +void luaF_newtbcupval (lua_State *L, StkId level) { + lua_assert(level > L->tbclist.p); + if (l_isfalse(s2v(level))) + return; /* false doesn't need to be closed */ + checkclosemth(L, level); /* value must have a close method */ + while (cast_uint(level - L->tbclist.p) > MAXDELTA) { + L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */ + L->tbclist.p->tbclist.delta = 0; + } + level->tbclist.delta = cast(unsigned short, level - L->tbclist.p); + L->tbclist.p = level; +} + + +void luaF_unlinkupval (UpVal *uv) { + lua_assert(upisopen(uv)); + *uv->u.open.previous = uv->u.open.next; + if (uv->u.open.next) + uv->u.open.next->u.open.previous = uv->u.open.previous; +} + + +/* +** Close all upvalues up to the given stack level. +*/ +void luaF_closeupval (lua_State *L, StkId level) { + UpVal *uv; + StkId upl; /* stack index pointed by 'uv' */ + while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { + TValue *slot = &uv->u.value; /* new position for value */ + lua_assert(uplevel(uv) < L->top.p); + luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */ + setobj(L, slot, uv->v.p); /* move value to upvalue slot */ + uv->v.p = slot; /* now current value lives here */ + if (!iswhite(uv)) { /* neither white nor dead? */ + nw2black(uv); /* closed upvalues cannot be gray */ + luaC_barrier(L, uv, slot); + } + } +} + + +/* +** Remove first element from the tbclist plus its dummy nodes. +*/ +static void poptbclist (lua_State *L) { + StkId tbc = L->tbclist.p; + lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */ + tbc -= tbc->tbclist.delta; + while (tbc > L->stack.p && tbc->tbclist.delta == 0) + tbc -= MAXDELTA; /* remove dummy nodes */ + L->tbclist.p = tbc; +} + + +/* +** Close all upvalues and to-be-closed variables up to the given stack +** level. Return restored 'level'. +*/ +StkId luaF_close (lua_State *L, StkId level, int status, int yy) { + ptrdiff_t levelrel = savestack(L, level); + luaF_closeupval(L, level); /* first, close the upvalues */ + while (L->tbclist.p >= level) { /* traverse tbc's down to that level */ + StkId tbc = L->tbclist.p; /* get variable index */ + poptbclist(L); /* remove it from list */ + prepcallclosemth(L, tbc, status, yy); /* close variable */ + level = restorestack(L, levelrel); + } + return level; +} + + +Proto *luaF_newproto (lua_State *L) { + GCObject *o = luaC_newobj(L, LUA_VPROTO, sizeof(Proto)); + Proto *f = gco2p(o); + f->k = NULL; + f->sizek = 0; + f->p = NULL; + f->sizep = 0; + f->code = NULL; + f->sizecode = 0; + f->lineinfo = NULL; + f->sizelineinfo = 0; + f->abslineinfo = NULL; + f->sizeabslineinfo = 0; + f->upvalues = NULL; + f->sizeupvalues = 0; + f->numparams = 0; + f->is_vararg = 0; + f->maxstacksize = 0; + f->locvars = NULL; + f->sizelocvars = 0; + f->linedefined = 0; + f->lastlinedefined = 0; + f->source = NULL; + return f; +} + + +void luaF_freeproto (lua_State *L, Proto *f) { + luaM_freearray(L, f->code, f->sizecode); + luaM_freearray(L, f->p, f->sizep); + luaM_freearray(L, f->k, f->sizek); + luaM_freearray(L, f->lineinfo, f->sizelineinfo); + luaM_freearray(L, f->abslineinfo, f->sizeabslineinfo); + luaM_freearray(L, f->locvars, f->sizelocvars); + luaM_freearray(L, f->upvalues, f->sizeupvalues); + luaM_free(L, f); +} + + +/* +** Look for n-th local variable at line 'line' in function 'func'. +** Returns NULL if not found. +*/ +const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { + int i; + for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { + if (pc < f->locvars[i].endpc) { /* is variable active? */ + local_number--; + if (local_number == 0) + return getstr(f->locvars[i].varname); + } + } + return NULL; /* not found */ +} + diff --git a/vendor/lua-src/lua-5.4.6/lfunc.h b/vendor/lua-src/lua-5.4.6/lfunc.h new file mode 100644 index 0000000000000..3be265efb5848 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lfunc.h @@ -0,0 +1,64 @@ +/* +** $Id: lfunc.h $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + +#ifndef lfunc_h +#define lfunc_h + + +#include "lobject.h" + + +#define sizeCclosure(n) (cast_int(offsetof(CClosure, upvalue)) + \ + cast_int(sizeof(TValue)) * (n)) + +#define sizeLclosure(n) (cast_int(offsetof(LClosure, upvals)) + \ + cast_int(sizeof(TValue *)) * (n)) + + +/* test whether thread is in 'twups' list */ +#define isintwups(L) (L->twups != L) + + +/* +** maximum number of upvalues in a closure (both C and Lua). (Value +** must fit in a VM register.) +*/ +#define MAXUPVAL 255 + + +#define upisopen(up) ((up)->v.p != &(up)->u.value) + + +#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p)) + + +/* +** maximum number of misses before giving up the cache of closures +** in prototypes +*/ +#define MAXMISS 10 + + + +/* special status to close upvalues preserving the top of the stack */ +#define CLOSEKTOP (-1) + + +LUAI_FUNC Proto *luaF_newproto (lua_State *L); +LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nupvals); +LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nupvals); +LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); +LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); +LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); +LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level); +LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy); +LUAI_FUNC void luaF_unlinkupval (UpVal *uv); +LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); +LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, + int pc); + + +#endif diff --git a/vendor/lua-src/lua-5.4.6/lgc.c b/vendor/lua-src/lua-5.4.6/lgc.c new file mode 100644 index 0000000000000..a3094ff571268 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lgc.c @@ -0,0 +1,1739 @@ +/* +** $Id: lgc.c $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#define lgc_c +#define LUA_CORE + +#include "lprefix.h" + +#include +#include + + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + +/* +** Maximum number of elements to sweep in each single step. +** (Large enough to dissipate fixed overheads but small enough +** to allow small steps for the collector.) +*/ +#define GCSWEEPMAX 100 + +/* +** Maximum number of finalizers to call in each single step. +*/ +#define GCFINMAX 10 + + +/* +** Cost of calling one finalizer. +*/ +#define GCFINALIZECOST 50 + + +/* +** The equivalent, in bytes, of one unit of "work" (visiting a slot, +** sweeping an object, etc.) +*/ +#define WORK2MEM sizeof(TValue) + + +/* +** macro to adjust 'pause': 'pause' is actually used like +** 'pause / PAUSEADJ' (value chosen by tests) +*/ +#define PAUSEADJ 100 + + +/* mask with all color bits */ +#define maskcolors (bitmask(BLACKBIT) | WHITEBITS) + +/* mask with all GC bits */ +#define maskgcbits (maskcolors | AGEBITS) + + +/* macro to erase all color bits then set only the current white bit */ +#define makewhite(g,x) \ + (x->marked = cast_byte((x->marked & ~maskcolors) | luaC_white(g))) + +/* make an object gray (neither white nor black) */ +#define set2gray(x) resetbits(x->marked, maskcolors) + + +/* make an object black (coming from any color) */ +#define set2black(x) \ + (x->marked = cast_byte((x->marked & ~WHITEBITS) | bitmask(BLACKBIT))) + + +#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) + +#define keyiswhite(n) (keyiscollectable(n) && iswhite(gckey(n))) + + +/* +** Protected access to objects in values +*/ +#define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL) + + +#define markvalue(g,o) { checkliveness(g->mainthread,o); \ + if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } + +#define markkey(g, n) { if keyiswhite(n) reallymarkobject(g,gckey(n)); } + +#define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); } + +/* +** mark an object that can be NULL (either because it is really optional, +** or it was stripped as debug info, or inside an uncompleted structure) +*/ +#define markobjectN(g,t) { if (t) markobject(g,t); } + +static void reallymarkobject (global_State *g, GCObject *o); +static lu_mem atomic (lua_State *L); +static void entersweep (lua_State *L); + + +/* +** {====================================================== +** Generic functions +** ======================================================= +*/ + + +/* +** one after last element in a hash array +*/ +#define gnodelast(h) gnode(h, cast_sizet(sizenode(h))) + + +static GCObject **getgclist (GCObject *o) { + switch (o->tt) { + case LUA_VTABLE: return &gco2t(o)->gclist; + case LUA_VLCL: return &gco2lcl(o)->gclist; + case LUA_VCCL: return &gco2ccl(o)->gclist; + case LUA_VTHREAD: return &gco2th(o)->gclist; + case LUA_VPROTO: return &gco2p(o)->gclist; + case LUA_VUSERDATA: { + Udata *u = gco2u(o); + lua_assert(u->nuvalue > 0); + return &u->gclist; + } + default: lua_assert(0); return 0; + } +} + + +/* +** Link a collectable object 'o' with a known type into the list 'p'. +** (Must be a macro to access the 'gclist' field in different types.) +*/ +#define linkgclist(o,p) linkgclist_(obj2gco(o), &(o)->gclist, &(p)) + +static void linkgclist_ (GCObject *o, GCObject **pnext, GCObject **list) { + lua_assert(!isgray(o)); /* cannot be in a gray list */ + *pnext = *list; + *list = o; + set2gray(o); /* now it is */ +} + + +/* +** Link a generic collectable object 'o' into the list 'p'. +*/ +#define linkobjgclist(o,p) linkgclist_(obj2gco(o), getgclist(o), &(p)) + + + +/* +** Clear keys for empty entries in tables. If entry is empty, mark its +** entry as dead. This allows the collection of the key, but keeps its +** entry in the table: its removal could break a chain and could break +** a table traversal. Other places never manipulate dead keys, because +** its associated empty value is enough to signal that the entry is +** logically empty. +*/ +static void clearkey (Node *n) { + lua_assert(isempty(gval(n))); + if (keyiscollectable(n)) + setdeadkey(n); /* unused key; remove it */ +} + + +/* +** tells whether a key or value can be cleared from a weak +** table. Non-collectable objects are never removed from weak +** tables. Strings behave as 'values', so are never removed too. for +** other objects: if really collected, cannot keep them; for objects +** being finalized, keep them in keys, but not in values +*/ +static int iscleared (global_State *g, const GCObject *o) { + if (o == NULL) return 0; /* non-collectable value */ + else if (novariant(o->tt) == LUA_TSTRING) { + markobject(g, o); /* strings are 'values', so are never weak */ + return 0; + } + else return iswhite(o); +} + + +/* +** Barrier that moves collector forward, that is, marks the white object +** 'v' being pointed by the black object 'o'. In the generational +** mode, 'v' must also become old, if 'o' is old; however, it cannot +** be changed directly to OLD, because it may still point to non-old +** objects. So, it is marked as OLD0. In the next cycle it will become +** OLD1, and in the next it will finally become OLD (regular old). By +** then, any object it points to will also be old. If called in the +** incremental sweep phase, it clears the black object to white (sweep +** it) to avoid other barrier calls for this same object. (That cannot +** be done is generational mode, as its sweep does not distinguish +** whites from deads.) +*/ +void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { + global_State *g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + if (keepinvariant(g)) { /* must keep invariant? */ + reallymarkobject(g, v); /* restore invariant */ + if (isold(o)) { + lua_assert(!isold(v)); /* white object could not be old */ + setage(v, G_OLD0); /* restore generational invariant */ + } + } + else { /* sweep phase */ + lua_assert(issweepphase(g)); + if (g->gckind == KGC_INC) /* incremental mode? */ + makewhite(g, o); /* mark 'o' as white to avoid other barriers */ + } +} + + +/* +** barrier that moves collector backward, that is, mark the black object +** pointing to a white object as gray again. +*/ +void luaC_barrierback_ (lua_State *L, GCObject *o) { + global_State *g = G(L); + lua_assert(isblack(o) && !isdead(g, o)); + lua_assert((g->gckind == KGC_GEN) == (isold(o) && getage(o) != G_TOUCHED1)); + if (getage(o) == G_TOUCHED2) /* already in gray list? */ + set2gray(o); /* make it gray to become touched1 */ + else /* link it in 'grayagain' and paint it gray */ + linkobjgclist(o, g->grayagain); + if (isold(o)) /* generational mode? */ + setage(o, G_TOUCHED1); /* touched in current cycle */ +} + + +void luaC_fix (lua_State *L, GCObject *o) { + global_State *g = G(L); + lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ + set2gray(o); /* they will be gray forever */ + setage(o, G_OLD); /* and old forever */ + g->allgc = o->next; /* remove object from 'allgc' list */ + o->next = g->fixedgc; /* link it to 'fixedgc' list */ + g->fixedgc = o; +} + + +/* +** create a new collectable object (with given type, size, and offset) +** and link it to 'allgc' list. +*/ +GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) { + global_State *g = G(L); + char *p = cast_charp(luaM_newobject(L, novariant(tt), sz)); + GCObject *o = cast(GCObject *, p + offset); + o->marked = luaC_white(g); + o->tt = tt; + o->next = g->allgc; + g->allgc = o; + return o; +} + + +GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { + return luaC_newobjdt(L, tt, sz, 0); +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Mark functions +** ======================================================= +*/ + + +/* +** Mark an object. Userdata with no user values, strings, and closed +** upvalues are visited and turned black here. Open upvalues are +** already indirectly linked through their respective threads in the +** 'twups' list, so they don't go to the gray list; nevertheless, they +** are kept gray to avoid barriers, as their values will be revisited +** by the thread or by 'remarkupvals'. Other objects are added to the +** gray list to be visited (and turned black) later. Both userdata and +** upvalues can call this function recursively, but this recursion goes +** for at most two levels: An upvalue cannot refer to another upvalue +** (only closures can), and a userdata's metatable must be a table. +*/ +static void reallymarkobject (global_State *g, GCObject *o) { + switch (o->tt) { + case LUA_VSHRSTR: + case LUA_VLNGSTR: { + set2black(o); /* nothing to visit */ + break; + } + case LUA_VUPVAL: { + UpVal *uv = gco2upv(o); + if (upisopen(uv)) + set2gray(uv); /* open upvalues are kept gray */ + else + set2black(uv); /* closed upvalues are visited here */ + markvalue(g, uv->v.p); /* mark its content */ + break; + } + case LUA_VUSERDATA: { + Udata *u = gco2u(o); + if (u->nuvalue == 0) { /* no user values? */ + markobjectN(g, u->metatable); /* mark its metatable */ + set2black(u); /* nothing else to mark */ + break; + } + /* else... */ + } /* FALLTHROUGH */ + case LUA_VLCL: case LUA_VCCL: case LUA_VTABLE: + case LUA_VTHREAD: case LUA_VPROTO: { + linkobjgclist(o, g->gray); /* to be visited later */ + break; + } + default: lua_assert(0); break; + } +} + + +/* +** mark metamethods for basic types +*/ +static void markmt (global_State *g) { + int i; + for (i=0; i < LUA_NUMTAGS; i++) + markobjectN(g, g->mt[i]); +} + + +/* +** mark all objects in list of being-finalized +*/ +static lu_mem markbeingfnz (global_State *g) { + GCObject *o; + lu_mem count = 0; + for (o = g->tobefnz; o != NULL; o = o->next) { + count++; + markobject(g, o); + } + return count; +} + + +/* +** For each non-marked thread, simulates a barrier between each open +** upvalue and its value. (If the thread is collected, the value will be +** assigned to the upvalue, but then it can be too late for the barrier +** to act. The "barrier" does not need to check colors: A non-marked +** thread must be young; upvalues cannot be older than their threads; so +** any visited upvalue must be young too.) Also removes the thread from +** the list, as it was already visited. Removes also threads with no +** upvalues, as they have nothing to be checked. (If the thread gets an +** upvalue later, it will be linked in the list again.) +*/ +static int remarkupvals (global_State *g) { + lua_State *thread; + lua_State **p = &g->twups; + int work = 0; /* estimate of how much work was done here */ + while ((thread = *p) != NULL) { + work++; + if (!iswhite(thread) && thread->openupval != NULL) + p = &thread->twups; /* keep marked thread with upvalues in the list */ + else { /* thread is not marked or without upvalues */ + UpVal *uv; + lua_assert(!isold(thread) || thread->openupval == NULL); + *p = thread->twups; /* remove thread from the list */ + thread->twups = thread; /* mark that it is out of list */ + for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { + lua_assert(getage(uv) <= getage(thread)); + work++; + if (!iswhite(uv)) { /* upvalue already visited? */ + lua_assert(upisopen(uv) && isgray(uv)); + markvalue(g, uv->v.p); /* mark its value */ + } + } + } + } + return work; +} + + +static void cleargraylists (global_State *g) { + g->gray = g->grayagain = NULL; + g->weak = g->allweak = g->ephemeron = NULL; +} + + +/* +** mark root set and reset all gray lists, to start a new collection +*/ +static void restartcollection (global_State *g) { + cleargraylists(g); + markobject(g, g->mainthread); + markvalue(g, &g->l_registry); + markmt(g); + markbeingfnz(g); /* mark any finalizing object left from previous cycle */ +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Traverse functions +** ======================================================= +*/ + + +/* +** Check whether object 'o' should be kept in the 'grayagain' list for +** post-processing by 'correctgraylist'. (It could put all old objects +** in the list and leave all the work to 'correctgraylist', but it is +** more efficient to avoid adding elements that will be removed.) Only +** TOUCHED1 objects need to be in the list. TOUCHED2 doesn't need to go +** back to a gray list, but then it must become OLD. (That is what +** 'correctgraylist' does when it finds a TOUCHED2 object.) +*/ +static void genlink (global_State *g, GCObject *o) { + lua_assert(isblack(o)); + if (getage(o) == G_TOUCHED1) { /* touched in this cycle? */ + linkobjgclist(o, g->grayagain); /* link it back in 'grayagain' */ + } /* everything else do not need to be linked back */ + else if (getage(o) == G_TOUCHED2) + changeage(o, G_TOUCHED2, G_OLD); /* advance age */ +} + + +/* +** Traverse a table with weak values and link it to proper list. During +** propagate phase, keep it in 'grayagain' list, to be revisited in the +** atomic phase. In the atomic phase, if table has any white value, +** put it in 'weak' list, to be cleared. +*/ +static void traverseweakvalue (global_State *g, Table *h) { + Node *n, *limit = gnodelast(h); + /* if there is array part, assume it may have white values (it is not + worth traversing it now just to check) */ + int hasclears = (h->alimit > 0); + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ + if (isempty(gval(n))) /* entry is empty? */ + clearkey(n); /* clear its key */ + else { + lua_assert(!keyisnil(n)); + markkey(g, n); + if (!hasclears && iscleared(g, gcvalueN(gval(n)))) /* a white value? */ + hasclears = 1; /* table will have to be cleared */ + } + } + if (g->gcstate == GCSatomic && hasclears) + linkgclist(h, g->weak); /* has to be cleared later */ + else + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ +} + + +/* +** Traverse an ephemeron table and link it to proper list. Returns true +** iff any object was marked during this traversal (which implies that +** convergence has to continue). During propagation phase, keep table +** in 'grayagain' list, to be visited again in the atomic phase. In +** the atomic phase, if table has any white->white entry, it has to +** be revisited during ephemeron convergence (as that key may turn +** black). Otherwise, if it has any white key, table has to be cleared +** (in the atomic phase). In generational mode, some tables +** must be kept in some gray list for post-processing; this is done +** by 'genlink'. +*/ +static int traverseephemeron (global_State *g, Table *h, int inv) { + int marked = 0; /* true if an object is marked in this traversal */ + int hasclears = 0; /* true if table has white keys */ + int hasww = 0; /* true if table has entry "white-key -> white-value" */ + unsigned int i; + unsigned int asize = luaH_realasize(h); + unsigned int nsize = sizenode(h); + /* traverse array part */ + for (i = 0; i < asize; i++) { + if (valiswhite(&h->array[i])) { + marked = 1; + reallymarkobject(g, gcvalue(&h->array[i])); + } + } + /* traverse hash part; if 'inv', traverse descending + (see 'convergeephemerons') */ + for (i = 0; i < nsize; i++) { + Node *n = inv ? gnode(h, nsize - 1 - i) : gnode(h, i); + if (isempty(gval(n))) /* entry is empty? */ + clearkey(n); /* clear its key */ + else if (iscleared(g, gckeyN(n))) { /* key is not marked (yet)? */ + hasclears = 1; /* table must be cleared */ + if (valiswhite(gval(n))) /* value not marked yet? */ + hasww = 1; /* white-white entry */ + } + else if (valiswhite(gval(n))) { /* value not marked yet? */ + marked = 1; + reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ + } + } + /* link table into proper list */ + if (g->gcstate == GCSpropagate) + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ + else if (hasww) /* table has white->white entries? */ + linkgclist(h, g->ephemeron); /* have to propagate again */ + else if (hasclears) /* table has white keys? */ + linkgclist(h, g->allweak); /* may have to clean white keys */ + else + genlink(g, obj2gco(h)); /* check whether collector still needs to see it */ + return marked; +} + + +static void traversestrongtable (global_State *g, Table *h) { + Node *n, *limit = gnodelast(h); + unsigned int i; + unsigned int asize = luaH_realasize(h); + for (i = 0; i < asize; i++) /* traverse array part */ + markvalue(g, &h->array[i]); + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ + if (isempty(gval(n))) /* entry is empty? */ + clearkey(n); /* clear its key */ + else { + lua_assert(!keyisnil(n)); + markkey(g, n); + markvalue(g, gval(n)); + } + } + genlink(g, obj2gco(h)); +} + + +static lu_mem traversetable (global_State *g, Table *h) { + const char *weakkey, *weakvalue; + const TValue *mode = gfasttm(g, h->metatable, TM_MODE); + markobjectN(g, h->metatable); + if (mode && ttisstring(mode) && /* is there a weak mode? */ + (cast_void(weakkey = strchr(svalue(mode), 'k')), + cast_void(weakvalue = strchr(svalue(mode), 'v')), + (weakkey || weakvalue))) { /* is really weak? */ + if (!weakkey) /* strong keys? */ + traverseweakvalue(g, h); + else if (!weakvalue) /* strong values? */ + traverseephemeron(g, h, 0); + else /* all weak */ + linkgclist(h, g->allweak); /* nothing to traverse now */ + } + else /* not weak */ + traversestrongtable(g, h); + return 1 + h->alimit + 2 * allocsizenode(h); +} + + +static int traverseudata (global_State *g, Udata *u) { + int i; + markobjectN(g, u->metatable); /* mark its metatable */ + for (i = 0; i < u->nuvalue; i++) + markvalue(g, &u->uv[i].uv); + genlink(g, obj2gco(u)); + return 1 + u->nuvalue; +} + + +/* +** Traverse a prototype. (While a prototype is being build, its +** arrays can be larger than needed; the extra slots are filled with +** NULL, so the use of 'markobjectN') +*/ +static int traverseproto (global_State *g, Proto *f) { + int i; + markobjectN(g, f->source); + for (i = 0; i < f->sizek; i++) /* mark literals */ + markvalue(g, &f->k[i]); + for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ + markobjectN(g, f->upvalues[i].name); + for (i = 0; i < f->sizep; i++) /* mark nested protos */ + markobjectN(g, f->p[i]); + for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ + markobjectN(g, f->locvars[i].varname); + return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars; +} + + +static int traverseCclosure (global_State *g, CClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ + markvalue(g, &cl->upvalue[i]); + return 1 + cl->nupvalues; +} + +/* +** Traverse a Lua closure, marking its prototype and its upvalues. +** (Both can be NULL while closure is being created.) +*/ +static int traverseLclosure (global_State *g, LClosure *cl) { + int i; + markobjectN(g, cl->p); /* mark its prototype */ + for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ + UpVal *uv = cl->upvals[i]; + markobjectN(g, uv); /* mark upvalue */ + } + return 1 + cl->nupvalues; +} + + +/* +** Traverse a thread, marking the elements in the stack up to its top +** and cleaning the rest of the stack in the final traversal. That +** ensures that the entire stack have valid (non-dead) objects. +** Threads have no barriers. In gen. mode, old threads must be visited +** at every cycle, because they might point to young objects. In inc. +** mode, the thread can still be modified before the end of the cycle, +** and therefore it must be visited again in the atomic phase. To ensure +** these visits, threads must return to a gray list if they are not new +** (which can only happen in generational mode) or if the traverse is in +** the propagate phase (which can only happen in incremental mode). +*/ +static int traversethread (global_State *g, lua_State *th) { + UpVal *uv; + StkId o = th->stack.p; + if (isold(th) || g->gcstate == GCSpropagate) + linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ + if (o == NULL) + return 1; /* stack not completely built yet */ + lua_assert(g->gcstate == GCSatomic || + th->openupval == NULL || isintwups(th)); + for (; o < th->top.p; o++) /* mark live elements in the stack */ + markvalue(g, s2v(o)); + for (uv = th->openupval; uv != NULL; uv = uv->u.open.next) + markobject(g, uv); /* open upvalues cannot be collected */ + if (g->gcstate == GCSatomic) { /* final traversal? */ + for (; o < th->stack_last.p + EXTRA_STACK; o++) + setnilvalue(s2v(o)); /* clear dead stack slice */ + /* 'remarkupvals' may have removed thread from 'twups' list */ + if (!isintwups(th) && th->openupval != NULL) { + th->twups = g->twups; /* link it back to the list */ + g->twups = th; + } + } + else if (!g->gcemergency) + luaD_shrinkstack(th); /* do not change stack in emergency cycle */ + return 1 + stacksize(th); +} + + +/* +** traverse one gray object, turning it to black. +*/ +static lu_mem propagatemark (global_State *g) { + GCObject *o = g->gray; + nw2black(o); + g->gray = *getgclist(o); /* remove from 'gray' list */ + switch (o->tt) { + case LUA_VTABLE: return traversetable(g, gco2t(o)); + case LUA_VUSERDATA: return traverseudata(g, gco2u(o)); + case LUA_VLCL: return traverseLclosure(g, gco2lcl(o)); + case LUA_VCCL: return traverseCclosure(g, gco2ccl(o)); + case LUA_VPROTO: return traverseproto(g, gco2p(o)); + case LUA_VTHREAD: return traversethread(g, gco2th(o)); + default: lua_assert(0); return 0; + } +} + + +static lu_mem propagateall (global_State *g) { + lu_mem tot = 0; + while (g->gray) + tot += propagatemark(g); + return tot; +} + + +/* +** Traverse all ephemeron tables propagating marks from keys to values. +** Repeat until it converges, that is, nothing new is marked. 'dir' +** inverts the direction of the traversals, trying to speed up +** convergence on chains in the same table. +** +*/ +static void convergeephemerons (global_State *g) { + int changed; + int dir = 0; + do { + GCObject *w; + GCObject *next = g->ephemeron; /* get ephemeron list */ + g->ephemeron = NULL; /* tables may return to this list when traversed */ + changed = 0; + while ((w = next) != NULL) { /* for each ephemeron table */ + Table *h = gco2t(w); + next = h->gclist; /* list is rebuilt during loop */ + nw2black(h); /* out of the list (for now) */ + if (traverseephemeron(g, h, dir)) { /* marked some value? */ + propagateall(g); /* propagate changes */ + changed = 1; /* will have to revisit all ephemeron tables */ + } + } + dir = !dir; /* invert direction next time */ + } while (changed); /* repeat until no more changes */ +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Sweep Functions +** ======================================================= +*/ + + +/* +** clear entries with unmarked keys from all weaktables in list 'l' +*/ +static void clearbykeys (global_State *g, GCObject *l) { + for (; l; l = gco2t(l)->gclist) { + Table *h = gco2t(l); + Node *limit = gnodelast(h); + Node *n; + for (n = gnode(h, 0); n < limit; n++) { + if (iscleared(g, gckeyN(n))) /* unmarked key? */ + setempty(gval(n)); /* remove entry */ + if (isempty(gval(n))) /* is entry empty? */ + clearkey(n); /* clear its key */ + } + } +} + + +/* +** clear entries with unmarked values from all weaktables in list 'l' up +** to element 'f' +*/ +static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { + for (; l != f; l = gco2t(l)->gclist) { + Table *h = gco2t(l); + Node *n, *limit = gnodelast(h); + unsigned int i; + unsigned int asize = luaH_realasize(h); + for (i = 0; i < asize; i++) { + TValue *o = &h->array[i]; + if (iscleared(g, gcvalueN(o))) /* value was collected? */ + setempty(o); /* remove entry */ + } + for (n = gnode(h, 0); n < limit; n++) { + if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */ + setempty(gval(n)); /* remove entry */ + if (isempty(gval(n))) /* is entry empty? */ + clearkey(n); /* clear its key */ + } + } +} + + +static void freeupval (lua_State *L, UpVal *uv) { + if (upisopen(uv)) + luaF_unlinkupval(uv); + luaM_free(L, uv); +} + + +static void freeobj (lua_State *L, GCObject *o) { + switch (o->tt) { + case LUA_VPROTO: + luaF_freeproto(L, gco2p(o)); + break; + case LUA_VUPVAL: + freeupval(L, gco2upv(o)); + break; + case LUA_VLCL: { + LClosure *cl = gco2lcl(o); + luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); + break; + } + case LUA_VCCL: { + CClosure *cl = gco2ccl(o); + luaM_freemem(L, cl, sizeCclosure(cl->nupvalues)); + break; + } + case LUA_VTABLE: + luaH_free(L, gco2t(o)); + break; + case LUA_VTHREAD: + luaE_freethread(L, gco2th(o)); + break; + case LUA_VUSERDATA: { + Udata *u = gco2u(o); + luaM_freemem(L, o, sizeudata(u->nuvalue, u->len)); + break; + } + case LUA_VSHRSTR: { + TString *ts = gco2ts(o); + luaS_remove(L, ts); /* remove it from hash table */ + luaM_freemem(L, ts, sizelstring(ts->shrlen)); + break; + } + case LUA_VLNGSTR: { + TString *ts = gco2ts(o); + luaM_freemem(L, ts, sizelstring(ts->u.lnglen)); + break; + } + default: lua_assert(0); + } +} + + +/* +** sweep at most 'countin' elements from a list of GCObjects erasing dead +** objects, where a dead object is one marked with the old (non current) +** white; change all non-dead objects back to white, preparing for next +** collection cycle. Return where to continue the traversal or NULL if +** list is finished. ('*countout' gets the number of elements traversed.) +*/ +static GCObject **sweeplist (lua_State *L, GCObject **p, int countin, + int *countout) { + global_State *g = G(L); + int ow = otherwhite(g); + int i; + int white = luaC_white(g); /* current white */ + for (i = 0; *p != NULL && i < countin; i++) { + GCObject *curr = *p; + int marked = curr->marked; + if (isdeadm(ow, marked)) { /* is 'curr' dead? */ + *p = curr->next; /* remove 'curr' from list */ + freeobj(L, curr); /* erase 'curr' */ + } + else { /* change mark to 'white' */ + curr->marked = cast_byte((marked & ~maskgcbits) | white); + p = &curr->next; /* go to next element */ + } + } + if (countout) + *countout = i; /* number of elements traversed */ + return (*p == NULL) ? NULL : p; +} + + +/* +** sweep a list until a live object (or end of list) +*/ +static GCObject **sweeptolive (lua_State *L, GCObject **p) { + GCObject **old = p; + do { + p = sweeplist(L, p, 1, NULL); + } while (p == old); + return p; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Finalization +** ======================================================= +*/ + +/* +** If possible, shrink string table. +*/ +static void checkSizes (lua_State *L, global_State *g) { + if (!g->gcemergency) { + if (g->strt.nuse < g->strt.size / 4) { /* string table too big? */ + l_mem olddebt = g->GCdebt; + luaS_resize(L, g->strt.size / 2); + g->GCestimate += g->GCdebt - olddebt; /* correct estimate */ + } + } +} + + +/* +** Get the next udata to be finalized from the 'tobefnz' list, and +** link it back into the 'allgc' list. +*/ +static GCObject *udata2finalize (global_State *g) { + GCObject *o = g->tobefnz; /* get first element */ + lua_assert(tofinalize(o)); + g->tobefnz = o->next; /* remove it from 'tobefnz' list */ + o->next = g->allgc; /* return it to 'allgc' list */ + g->allgc = o; + resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ + if (issweepphase(g)) + makewhite(g, o); /* "sweep" object */ + else if (getage(o) == G_OLD1) + g->firstold1 = o; /* it is the first OLD1 object in the list */ + return o; +} + + +static void dothecall (lua_State *L, void *ud) { + UNUSED(ud); + luaD_callnoyield(L, L->top.p - 2, 0); +} + + +static void GCTM (lua_State *L) { + global_State *g = G(L); + const TValue *tm; + TValue v; + lua_assert(!g->gcemergency); + setgcovalue(L, &v, udata2finalize(g)); + tm = luaT_gettmbyobj(L, &v, TM_GC); + if (!notm(tm)) { /* is there a finalizer? */ + int status; + lu_byte oldah = L->allowhook; + int oldgcstp = g->gcstp; + g->gcstp |= GCSTPGC; /* avoid GC steps */ + L->allowhook = 0; /* stop debug hooks during GC metamethod */ + setobj2s(L, L->top.p++, tm); /* push finalizer... */ + setobj2s(L, L->top.p++, &v); /* ... and its argument */ + L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ + status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0); + L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ + L->allowhook = oldah; /* restore hooks */ + g->gcstp = oldgcstp; /* restore state */ + if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */ + luaE_warnerror(L, "__gc"); + L->top.p--; /* pops error object */ + } + } +} + + +/* +** Call a few finalizers +*/ +static int runafewfinalizers (lua_State *L, int n) { + global_State *g = G(L); + int i; + for (i = 0; i < n && g->tobefnz; i++) + GCTM(L); /* call one finalizer */ + return i; +} + + +/* +** call all pending finalizers +*/ +static void callallpendingfinalizers (lua_State *L) { + global_State *g = G(L); + while (g->tobefnz) + GCTM(L); +} + + +/* +** find last 'next' field in list 'p' list (to add elements in its end) +*/ +static GCObject **findlast (GCObject **p) { + while (*p != NULL) + p = &(*p)->next; + return p; +} + + +/* +** Move all unreachable objects (or 'all' objects) that need +** finalization from list 'finobj' to list 'tobefnz' (to be finalized). +** (Note that objects after 'finobjold1' cannot be white, so they +** don't need to be traversed. In incremental mode, 'finobjold1' is NULL, +** so the whole list is traversed.) +*/ +static void separatetobefnz (global_State *g, int all) { + GCObject *curr; + GCObject **p = &g->finobj; + GCObject **lastnext = findlast(&g->tobefnz); + while ((curr = *p) != g->finobjold1) { /* traverse all finalizable objects */ + lua_assert(tofinalize(curr)); + if (!(iswhite(curr) || all)) /* not being collected? */ + p = &curr->next; /* don't bother with it */ + else { + if (curr == g->finobjsur) /* removing 'finobjsur'? */ + g->finobjsur = curr->next; /* correct it */ + *p = curr->next; /* remove 'curr' from 'finobj' list */ + curr->next = *lastnext; /* link at the end of 'tobefnz' list */ + *lastnext = curr; + lastnext = &curr->next; + } + } +} + + +/* +** If pointer 'p' points to 'o', move it to the next element. +*/ +static void checkpointer (GCObject **p, GCObject *o) { + if (o == *p) + *p = o->next; +} + + +/* +** Correct pointers to objects inside 'allgc' list when +** object 'o' is being removed from the list. +*/ +static void correctpointers (global_State *g, GCObject *o) { + checkpointer(&g->survival, o); + checkpointer(&g->old1, o); + checkpointer(&g->reallyold, o); + checkpointer(&g->firstold1, o); +} + + +/* +** if object 'o' has a finalizer, remove it from 'allgc' list (must +** search the list to find it) and link it in 'finobj' list. +*/ +void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { + global_State *g = G(L); + if (tofinalize(o) || /* obj. is already marked... */ + gfasttm(g, mt, TM_GC) == NULL || /* or has no finalizer... */ + (g->gcstp & GCSTPCLS)) /* or closing state? */ + return; /* nothing to be done */ + else { /* move 'o' to 'finobj' list */ + GCObject **p; + if (issweepphase(g)) { + makewhite(g, o); /* "sweep" object 'o' */ + if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ + g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ + } + else + correctpointers(g, o); + /* search for pointer pointing to 'o' */ + for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } + *p = o->next; /* remove 'o' from 'allgc' list */ + o->next = g->finobj; /* link it in 'finobj' list */ + g->finobj = o; + l_setbit(o->marked, FINALIZEDBIT); /* mark it as such */ + } +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Generational Collector +** ======================================================= +*/ + + +/* +** Set the "time" to wait before starting a new GC cycle; cycle will +** start when memory use hits the threshold of ('estimate' * pause / +** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero, +** because Lua cannot even start with less than PAUSEADJ bytes). +*/ +static void setpause (global_State *g) { + l_mem threshold, debt; + int pause = getgcparam(g->gcpause); + l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ + lua_assert(estimate > 0); + threshold = (pause < MAX_LMEM / estimate) /* overflow? */ + ? estimate * pause /* no overflow */ + : MAX_LMEM; /* overflow; truncate to maximum */ + debt = gettotalbytes(g) - threshold; + if (debt > 0) debt = 0; + luaE_setdebt(g, debt); +} + + +/* +** Sweep a list of objects to enter generational mode. Deletes dead +** objects and turns the non dead to old. All non-dead threads---which +** are now old---must be in a gray list. Everything else is not in a +** gray list. Open upvalues are also kept gray. +*/ +static void sweep2old (lua_State *L, GCObject **p) { + GCObject *curr; + global_State *g = G(L); + while ((curr = *p) != NULL) { + if (iswhite(curr)) { /* is 'curr' dead? */ + lua_assert(isdead(g, curr)); + *p = curr->next; /* remove 'curr' from list */ + freeobj(L, curr); /* erase 'curr' */ + } + else { /* all surviving objects become old */ + setage(curr, G_OLD); + if (curr->tt == LUA_VTHREAD) { /* threads must be watched */ + lua_State *th = gco2th(curr); + linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ + } + else if (curr->tt == LUA_VUPVAL && upisopen(gco2upv(curr))) + set2gray(curr); /* open upvalues are always gray */ + else /* everything else is black */ + nw2black(curr); + p = &curr->next; /* go to next element */ + } + } +} + + +/* +** Sweep for generational mode. Delete dead objects. (Because the +** collection is not incremental, there are no "new white" objects +** during the sweep. So, any white object must be dead.) For +** non-dead objects, advance their ages and clear the color of +** new objects. (Old objects keep their colors.) +** The ages of G_TOUCHED1 and G_TOUCHED2 objects cannot be advanced +** here, because these old-generation objects are usually not swept +** here. They will all be advanced in 'correctgraylist'. That function +** will also remove objects turned white here from any gray list. +*/ +static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, + GCObject *limit, GCObject **pfirstold1) { + static const lu_byte nextage[] = { + G_SURVIVAL, /* from G_NEW */ + G_OLD1, /* from G_SURVIVAL */ + G_OLD1, /* from G_OLD0 */ + G_OLD, /* from G_OLD1 */ + G_OLD, /* from G_OLD (do not change) */ + G_TOUCHED1, /* from G_TOUCHED1 (do not change) */ + G_TOUCHED2 /* from G_TOUCHED2 (do not change) */ + }; + int white = luaC_white(g); + GCObject *curr; + while ((curr = *p) != limit) { + if (iswhite(curr)) { /* is 'curr' dead? */ + lua_assert(!isold(curr) && isdead(g, curr)); + *p = curr->next; /* remove 'curr' from list */ + freeobj(L, curr); /* erase 'curr' */ + } + else { /* correct mark and age */ + if (getage(curr) == G_NEW) { /* new objects go back to white */ + int marked = curr->marked & ~maskgcbits; /* erase GC bits */ + curr->marked = cast_byte(marked | G_SURVIVAL | white); + } + else { /* all other objects will be old, and so keep their color */ + setage(curr, nextage[getage(curr)]); + if (getage(curr) == G_OLD1 && *pfirstold1 == NULL) + *pfirstold1 = curr; /* first OLD1 object in the list */ + } + p = &curr->next; /* go to next element */ + } + } + return p; +} + + +/* +** Traverse a list making all its elements white and clearing their +** age. In incremental mode, all objects are 'new' all the time, +** except for fixed strings (which are always old). +*/ +static void whitelist (global_State *g, GCObject *p) { + int white = luaC_white(g); + for (; p != NULL; p = p->next) + p->marked = cast_byte((p->marked & ~maskgcbits) | white); +} + + +/* +** Correct a list of gray objects. Return pointer to where rest of the +** list should be linked. +** Because this correction is done after sweeping, young objects might +** be turned white and still be in the list. They are only removed. +** 'TOUCHED1' objects are advanced to 'TOUCHED2' and remain on the list; +** Non-white threads also remain on the list; 'TOUCHED2' objects become +** regular old; they and anything else are removed from the list. +*/ +static GCObject **correctgraylist (GCObject **p) { + GCObject *curr; + while ((curr = *p) != NULL) { + GCObject **next = getgclist(curr); + if (iswhite(curr)) + goto remove; /* remove all white objects */ + else if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */ + lua_assert(isgray(curr)); + nw2black(curr); /* make it black, for next barrier */ + changeage(curr, G_TOUCHED1, G_TOUCHED2); + goto remain; /* keep it in the list and go to next element */ + } + else if (curr->tt == LUA_VTHREAD) { + lua_assert(isgray(curr)); + goto remain; /* keep non-white threads on the list */ + } + else { /* everything else is removed */ + lua_assert(isold(curr)); /* young objects should be white here */ + if (getage(curr) == G_TOUCHED2) /* advance from TOUCHED2... */ + changeage(curr, G_TOUCHED2, G_OLD); /* ... to OLD */ + nw2black(curr); /* make object black (to be removed) */ + goto remove; + } + remove: *p = *next; continue; + remain: p = next; continue; + } + return p; +} + + +/* +** Correct all gray lists, coalescing them into 'grayagain'. +*/ +static void correctgraylists (global_State *g) { + GCObject **list = correctgraylist(&g->grayagain); + *list = g->weak; g->weak = NULL; + list = correctgraylist(list); + *list = g->allweak; g->allweak = NULL; + list = correctgraylist(list); + *list = g->ephemeron; g->ephemeron = NULL; + correctgraylist(list); +} + + +/* +** Mark black 'OLD1' objects when starting a new young collection. +** Gray objects are already in some gray list, and so will be visited +** in the atomic step. +*/ +static void markold (global_State *g, GCObject *from, GCObject *to) { + GCObject *p; + for (p = from; p != to; p = p->next) { + if (getage(p) == G_OLD1) { + lua_assert(!iswhite(p)); + changeage(p, G_OLD1, G_OLD); /* now they are old */ + if (isblack(p)) + reallymarkobject(g, p); + } + } +} + + +/* +** Finish a young-generation collection. +*/ +static void finishgencycle (lua_State *L, global_State *g) { + correctgraylists(g); + checkSizes(L, g); + g->gcstate = GCSpropagate; /* skip restart */ + if (!g->gcemergency) + callallpendingfinalizers(L); +} + + +/* +** Does a young collection. First, mark 'OLD1' objects. Then does the +** atomic step. Then, sweep all lists and advance pointers. Finally, +** finish the collection. +*/ +static void youngcollection (lua_State *L, global_State *g) { + GCObject **psurvival; /* to point to first non-dead survival object */ + GCObject *dummy; /* dummy out parameter to 'sweepgen' */ + lua_assert(g->gcstate == GCSpropagate); + if (g->firstold1) { /* are there regular OLD1 objects? */ + markold(g, g->firstold1, g->reallyold); /* mark them */ + g->firstold1 = NULL; /* no more OLD1 objects (for now) */ + } + markold(g, g->finobj, g->finobjrold); + markold(g, g->tobefnz, NULL); + atomic(L); + + /* sweep nursery and get a pointer to its last live element */ + g->gcstate = GCSswpallgc; + psurvival = sweepgen(L, g, &g->allgc, g->survival, &g->firstold1); + /* sweep 'survival' */ + sweepgen(L, g, psurvival, g->old1, &g->firstold1); + g->reallyold = g->old1; + g->old1 = *psurvival; /* 'survival' survivals are old now */ + g->survival = g->allgc; /* all news are survivals */ + + /* repeat for 'finobj' lists */ + dummy = NULL; /* no 'firstold1' optimization for 'finobj' lists */ + psurvival = sweepgen(L, g, &g->finobj, g->finobjsur, &dummy); + /* sweep 'survival' */ + sweepgen(L, g, psurvival, g->finobjold1, &dummy); + g->finobjrold = g->finobjold1; + g->finobjold1 = *psurvival; /* 'survival' survivals are old now */ + g->finobjsur = g->finobj; /* all news are survivals */ + + sweepgen(L, g, &g->tobefnz, NULL, &dummy); + finishgencycle(L, g); +} + + +/* +** Clears all gray lists, sweeps objects, and prepare sublists to enter +** generational mode. The sweeps remove dead objects and turn all +** surviving objects to old. Threads go back to 'grayagain'; everything +** else is turned black (not in any gray list). +*/ +static void atomic2gen (lua_State *L, global_State *g) { + cleargraylists(g); + /* sweep all elements making them old */ + g->gcstate = GCSswpallgc; + sweep2old(L, &g->allgc); + /* everything alive now is old */ + g->reallyold = g->old1 = g->survival = g->allgc; + g->firstold1 = NULL; /* there are no OLD1 objects anywhere */ + + /* repeat for 'finobj' lists */ + sweep2old(L, &g->finobj); + g->finobjrold = g->finobjold1 = g->finobjsur = g->finobj; + + sweep2old(L, &g->tobefnz); + + g->gckind = KGC_GEN; + g->lastatomic = 0; + g->GCestimate = gettotalbytes(g); /* base for memory control */ + finishgencycle(L, g); +} + + +/* +** Set debt for the next minor collection, which will happen when +** memory grows 'genminormul'%. +*/ +static void setminordebt (global_State *g) { + luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul)); +} + + +/* +** Enter generational mode. Must go until the end of an atomic cycle +** to ensure that all objects are correctly marked and weak tables +** are cleared. Then, turn all objects into old and finishes the +** collection. +*/ +static lu_mem entergen (lua_State *L, global_State *g) { + lu_mem numobjs; + luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ + luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ + numobjs = atomic(L); /* propagates all and then do the atomic stuff */ + atomic2gen(L, g); + setminordebt(g); /* set debt assuming next cycle will be minor */ + return numobjs; +} + + +/* +** Enter incremental mode. Turn all objects white, make all +** intermediate lists point to NULL (to avoid invalid pointers), +** and go to the pause state. +*/ +static void enterinc (global_State *g) { + whitelist(g, g->allgc); + g->reallyold = g->old1 = g->survival = NULL; + whitelist(g, g->finobj); + whitelist(g, g->tobefnz); + g->finobjrold = g->finobjold1 = g->finobjsur = NULL; + g->gcstate = GCSpause; + g->gckind = KGC_INC; + g->lastatomic = 0; +} + + +/* +** Change collector mode to 'newmode'. +*/ +void luaC_changemode (lua_State *L, int newmode) { + global_State *g = G(L); + if (newmode != g->gckind) { + if (newmode == KGC_GEN) /* entering generational mode? */ + entergen(L, g); + else + enterinc(g); /* entering incremental mode */ + } + g->lastatomic = 0; +} + + +/* +** Does a full collection in generational mode. +*/ +static lu_mem fullgen (lua_State *L, global_State *g) { + enterinc(g); + return entergen(L, g); +} + + +/* +** Does a major collection after last collection was a "bad collection". +** +** When the program is building a big structure, it allocates lots of +** memory but generates very little garbage. In those scenarios, +** the generational mode just wastes time doing small collections, and +** major collections are frequently what we call a "bad collection", a +** collection that frees too few objects. To avoid the cost of switching +** between generational mode and the incremental mode needed for full +** (major) collections, the collector tries to stay in incremental mode +** after a bad collection, and to switch back to generational mode only +** after a "good" collection (one that traverses less than 9/8 objects +** of the previous one). +** The collector must choose whether to stay in incremental mode or to +** switch back to generational mode before sweeping. At this point, it +** does not know the real memory in use, so it cannot use memory to +** decide whether to return to generational mode. Instead, it uses the +** number of objects traversed (returned by 'atomic') as a proxy. The +** field 'g->lastatomic' keeps this count from the last collection. +** ('g->lastatomic != 0' also means that the last collection was bad.) +*/ +static void stepgenfull (lua_State *L, global_State *g) { + lu_mem newatomic; /* count of traversed objects */ + lu_mem lastatomic = g->lastatomic; /* count from last collection */ + if (g->gckind == KGC_GEN) /* still in generational mode? */ + enterinc(g); /* enter incremental mode */ + luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ + newatomic = atomic(L); /* mark everybody */ + if (newatomic < lastatomic + (lastatomic >> 3)) { /* good collection? */ + atomic2gen(L, g); /* return to generational mode */ + setminordebt(g); + } + else { /* another bad collection; stay in incremental mode */ + g->GCestimate = gettotalbytes(g); /* first estimate */; + entersweep(L); + luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ + setpause(g); + g->lastatomic = newatomic; + } +} + + +/* +** Does a generational "step". +** Usually, this means doing a minor collection and setting the debt to +** make another collection when memory grows 'genminormul'% larger. +** +** However, there are exceptions. If memory grows 'genmajormul'% +** larger than it was at the end of the last major collection (kept +** in 'g->GCestimate'), the function does a major collection. At the +** end, it checks whether the major collection was able to free a +** decent amount of memory (at least half the growth in memory since +** previous major collection). If so, the collector keeps its state, +** and the next collection will probably be minor again. Otherwise, +** we have what we call a "bad collection". In that case, set the field +** 'g->lastatomic' to signal that fact, so that the next collection will +** go to 'stepgenfull'. +** +** 'GCdebt <= 0' means an explicit call to GC step with "size" zero; +** in that case, do a minor collection. +*/ +static void genstep (lua_State *L, global_State *g) { + if (g->lastatomic != 0) /* last collection was a bad one? */ + stepgenfull(L, g); /* do a full step */ + else { + lu_mem majorbase = g->GCestimate; /* memory after last major collection */ + lu_mem majorinc = (majorbase / 100) * getgcparam(g->genmajormul); + if (g->GCdebt > 0 && gettotalbytes(g) > majorbase + majorinc) { + lu_mem numobjs = fullgen(L, g); /* do a major collection */ + if (gettotalbytes(g) < majorbase + (majorinc / 2)) { + /* collected at least half of memory growth since last major + collection; keep doing minor collections. */ + lua_assert(g->lastatomic == 0); + } + else { /* bad collection */ + g->lastatomic = numobjs; /* signal that last collection was bad */ + setpause(g); /* do a long wait for next (major) collection */ + } + } + else { /* regular case; do a minor collection */ + youngcollection(L, g); + setminordebt(g); + g->GCestimate = majorbase; /* preserve base value */ + } + } + lua_assert(isdecGCmodegen(g)); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** GC control +** ======================================================= +*/ + + +/* +** Enter first sweep phase. +** The call to 'sweeptolive' makes the pointer point to an object +** inside the list (instead of to the header), so that the real sweep do +** not need to skip objects created between "now" and the start of the +** real sweep. +*/ +static void entersweep (lua_State *L) { + global_State *g = G(L); + g->gcstate = GCSswpallgc; + lua_assert(g->sweepgc == NULL); + g->sweepgc = sweeptolive(L, &g->allgc); +} + + +/* +** Delete all objects in list 'p' until (but not including) object +** 'limit'. +*/ +static void deletelist (lua_State *L, GCObject *p, GCObject *limit) { + while (p != limit) { + GCObject *next = p->next; + freeobj(L, p); + p = next; + } +} + + +/* +** Call all finalizers of the objects in the given Lua state, and +** then free all objects, except for the main thread. +*/ +void luaC_freeallobjects (lua_State *L) { + global_State *g = G(L); + g->gcstp = GCSTPCLS; /* no extra finalizers after here */ + luaC_changemode(L, KGC_INC); + separatetobefnz(g, 1); /* separate all objects with finalizers */ + lua_assert(g->finobj == NULL); + callallpendingfinalizers(L); + deletelist(L, g->allgc, obj2gco(g->mainthread)); + lua_assert(g->finobj == NULL); /* no new finalizers */ + deletelist(L, g->fixedgc, NULL); /* collect fixed objects */ + lua_assert(g->strt.nuse == 0); +} + + +static lu_mem atomic (lua_State *L) { + global_State *g = G(L); + lu_mem work = 0; + GCObject *origweak, *origall; + GCObject *grayagain = g->grayagain; /* save original list */ + g->grayagain = NULL; + lua_assert(g->ephemeron == NULL && g->weak == NULL); + lua_assert(!iswhite(g->mainthread)); + g->gcstate = GCSatomic; + markobject(g, L); /* mark running thread */ + /* registry and global metatables may be changed by API */ + markvalue(g, &g->l_registry); + markmt(g); /* mark global metatables */ + work += propagateall(g); /* empties 'gray' list */ + /* remark occasional upvalues of (maybe) dead threads */ + work += remarkupvals(g); + work += propagateall(g); /* propagate changes */ + g->gray = grayagain; + work += propagateall(g); /* traverse 'grayagain' list */ + convergeephemerons(g); + /* at this point, all strongly accessible objects are marked. */ + /* Clear values from weak tables, before checking finalizers */ + clearbyvalues(g, g->weak, NULL); + clearbyvalues(g, g->allweak, NULL); + origweak = g->weak; origall = g->allweak; + separatetobefnz(g, 0); /* separate objects to be finalized */ + work += markbeingfnz(g); /* mark objects that will be finalized */ + work += propagateall(g); /* remark, to propagate 'resurrection' */ + convergeephemerons(g); + /* at this point, all resurrected objects are marked. */ + /* remove dead objects from weak tables */ + clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron tables */ + clearbykeys(g, g->allweak); /* clear keys from all 'allweak' tables */ + /* clear values from resurrected weak tables */ + clearbyvalues(g, g->weak, origweak); + clearbyvalues(g, g->allweak, origall); + luaS_clearcache(g); + g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ + lua_assert(g->gray == NULL); + return work; /* estimate of slots marked by 'atomic' */ +} + + +static int sweepstep (lua_State *L, global_State *g, + int nextstate, GCObject **nextlist) { + if (g->sweepgc) { + l_mem olddebt = g->GCdebt; + int count; + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX, &count); + g->GCestimate += g->GCdebt - olddebt; /* update estimate */ + return count; + } + else { /* enter next state */ + g->gcstate = nextstate; + g->sweepgc = nextlist; + return 0; /* no work done */ + } +} + + +static lu_mem singlestep (lua_State *L) { + global_State *g = G(L); + lu_mem work; + lua_assert(!g->gcstopem); /* collector is not reentrant */ + g->gcstopem = 1; /* no emergency collections while collecting */ + switch (g->gcstate) { + case GCSpause: { + restartcollection(g); + g->gcstate = GCSpropagate; + work = 1; + break; + } + case GCSpropagate: { + if (g->gray == NULL) { /* no more gray objects? */ + g->gcstate = GCSenteratomic; /* finish propagate phase */ + work = 0; + } + else + work = propagatemark(g); /* traverse one gray object */ + break; + } + case GCSenteratomic: { + work = atomic(L); /* work is what was traversed by 'atomic' */ + entersweep(L); + g->GCestimate = gettotalbytes(g); /* first estimate */; + break; + } + case GCSswpallgc: { /* sweep "regular" objects */ + work = sweepstep(L, g, GCSswpfinobj, &g->finobj); + break; + } + case GCSswpfinobj: { /* sweep objects with finalizers */ + work = sweepstep(L, g, GCSswptobefnz, &g->tobefnz); + break; + } + case GCSswptobefnz: { /* sweep objects to be finalized */ + work = sweepstep(L, g, GCSswpend, NULL); + break; + } + case GCSswpend: { /* finish sweeps */ + checkSizes(L, g); + g->gcstate = GCScallfin; + work = 0; + break; + } + case GCScallfin: { /* call remaining finalizers */ + if (g->tobefnz && !g->gcemergency) { + g->gcstopem = 0; /* ok collections during finalizers */ + work = runafewfinalizers(L, GCFINMAX) * GCFINALIZECOST; + } + else { /* emergency mode or no more finalizers */ + g->gcstate = GCSpause; /* finish collection */ + work = 0; + } + break; + } + default: lua_assert(0); return 0; + } + g->gcstopem = 0; + return work; +} + + +/* +** advances the garbage collector until it reaches a state allowed +** by 'statemask' +*/ +void luaC_runtilstate (lua_State *L, int statesmask) { + global_State *g = G(L); + while (!testbit(statesmask, g->gcstate)) + singlestep(L); +} + + + +/* +** Performs a basic incremental step. The debt and step size are +** converted from bytes to "units of work"; then the function loops +** running single steps until adding that many units of work or +** finishing a cycle (pause state). Finally, it sets the debt that +** controls when next step will be performed. +*/ +static void incstep (lua_State *L, global_State *g) { + int stepmul = (getgcparam(g->gcstepmul) | 1); /* avoid division by 0 */ + l_mem debt = (g->GCdebt / WORK2MEM) * stepmul; + l_mem stepsize = (g->gcstepsize <= log2maxs(l_mem)) + ? ((cast(l_mem, 1) << g->gcstepsize) / WORK2MEM) * stepmul + : MAX_LMEM; /* overflow; keep maximum value */ + do { /* repeat until pause or enough "credit" (negative debt) */ + lu_mem work = singlestep(L); /* perform one single step */ + debt -= work; + } while (debt > -stepsize && g->gcstate != GCSpause); + if (g->gcstate == GCSpause) + setpause(g); /* pause until next cycle */ + else { + debt = (debt / stepmul) * WORK2MEM; /* convert 'work units' to bytes */ + luaE_setdebt(g, debt); + } +} + +/* +** Performs a basic GC step if collector is running. (If collector is +** not running, set a reasonable debt to avoid it being called at +** every single check.) +*/ +void luaC_step (lua_State *L) { + global_State *g = G(L); + if (!gcrunning(g)) /* not running? */ + luaE_setdebt(g, -2000); + else { + if(isdecGCmodegen(g)) + genstep(L, g); + else + incstep(L, g); + } +} + + +/* +** Perform a full collection in incremental mode. +** Before running the collection, check 'keepinvariant'; if it is true, +** there may be some objects marked as black, so the collector has +** to sweep all objects to turn them back to white (as white has not +** changed, nothing will be collected). +*/ +static void fullinc (lua_State *L, global_State *g) { + if (keepinvariant(g)) /* black objects? */ + entersweep(L); /* sweep everything to turn them back to white */ + /* finish any pending sweep phase to start a new cycle */ + luaC_runtilstate(L, bitmask(GCSpause)); + luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ + /* estimate must be correct after a full GC cycle */ + lua_assert(g->GCestimate == gettotalbytes(g)); + luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ + setpause(g); +} + + +/* +** Performs a full GC cycle; if 'isemergency', set a flag to avoid +** some operations which could change the interpreter state in some +** unexpected ways (running finalizers and shrinking some structures). +*/ +void luaC_fullgc (lua_State *L, int isemergency) { + global_State *g = G(L); + lua_assert(!g->gcemergency); + g->gcemergency = isemergency; /* set flag */ + if (g->gckind == KGC_INC) + fullinc(L, g); + else + fullgen(L, g); + g->gcemergency = 0; +} + +/* }====================================================== */ + + diff --git a/vendor/lua-src/lua-5.4.6/lgc.h b/vendor/lua-src/lua-5.4.6/lgc.h new file mode 100644 index 0000000000000..538f6edcccf2a --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lgc.h @@ -0,0 +1,202 @@ +/* +** $Id: lgc.h $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#ifndef lgc_h +#define lgc_h + + +#include "lobject.h" +#include "lstate.h" + +/* +** Collectable objects may have one of three colors: white, which means +** the object is not marked; gray, which means the object is marked, but +** its references may be not marked; and black, which means that the +** object and all its references are marked. The main invariant of the +** garbage collector, while marking objects, is that a black object can +** never point to a white one. Moreover, any gray object must be in a +** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it +** can be visited again before finishing the collection cycle. (Open +** upvalues are an exception to this rule.) These lists have no meaning +** when the invariant is not being enforced (e.g., sweep phase). +*/ + + +/* +** Possible states of the Garbage Collector +*/ +#define GCSpropagate 0 +#define GCSenteratomic 1 +#define GCSatomic 2 +#define GCSswpallgc 3 +#define GCSswpfinobj 4 +#define GCSswptobefnz 5 +#define GCSswpend 6 +#define GCScallfin 7 +#define GCSpause 8 + + +#define issweepphase(g) \ + (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend) + + +/* +** macro to tell when main invariant (white objects cannot point to black +** ones) must be kept. During a collection, the sweep +** phase may break the invariant, as objects turned white may point to +** still-black objects. The invariant is restored when sweep ends and +** all objects are white again. +*/ + +#define keepinvariant(g) ((g)->gcstate <= GCSatomic) + + +/* +** some useful bit tricks +*/ +#define resetbits(x,m) ((x) &= cast_byte(~(m))) +#define setbits(x,m) ((x) |= (m)) +#define testbits(x,m) ((x) & (m)) +#define bitmask(b) (1<<(b)) +#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) +#define l_setbit(x,b) setbits(x, bitmask(b)) +#define resetbit(x,b) resetbits(x, bitmask(b)) +#define testbit(x,b) testbits(x, bitmask(b)) + + +/* +** Layout for bit use in 'marked' field. First three bits are +** used for object "age" in generational mode. Last bit is used +** by tests. +*/ +#define WHITE0BIT 3 /* object is white (type 0) */ +#define WHITE1BIT 4 /* object is white (type 1) */ +#define BLACKBIT 5 /* object is black */ +#define FINALIZEDBIT 6 /* object has been marked for finalization */ + +#define TESTBIT 7 + + + +#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) + + +#define iswhite(x) testbits((x)->marked, WHITEBITS) +#define isblack(x) testbit((x)->marked, BLACKBIT) +#define isgray(x) /* neither white nor black */ \ + (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) + +#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) + +#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) +#define isdeadm(ow,m) ((m) & (ow)) +#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) + +#define changewhite(x) ((x)->marked ^= WHITEBITS) +#define nw2black(x) \ + check_exp(!iswhite(x), l_setbit((x)->marked, BLACKBIT)) + +#define luaC_white(g) cast_byte((g)->currentwhite & WHITEBITS) + + +/* object age in generational mode */ +#define G_NEW 0 /* created in current cycle */ +#define G_SURVIVAL 1 /* created in previous cycle */ +#define G_OLD0 2 /* marked old by frw. barrier in this cycle */ +#define G_OLD1 3 /* first full cycle as old */ +#define G_OLD 4 /* really old object (not to be visited) */ +#define G_TOUCHED1 5 /* old object touched this cycle */ +#define G_TOUCHED2 6 /* old object touched in previous cycle */ + +#define AGEBITS 7 /* all age bits (111) */ + +#define getage(o) ((o)->marked & AGEBITS) +#define setage(o,a) ((o)->marked = cast_byte(((o)->marked & (~AGEBITS)) | a)) +#define isold(o) (getage(o) > G_SURVIVAL) + +#define changeage(o,f,t) \ + check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t))) + + +/* Default Values for GC parameters */ +#define LUAI_GENMAJORMUL 100 +#define LUAI_GENMINORMUL 20 + +/* wait memory to double before starting new cycle */ +#define LUAI_GCPAUSE 200 + +/* +** some gc parameters are stored divided by 4 to allow a maximum value +** up to 1023 in a 'lu_byte'. +*/ +#define getgcparam(p) ((p) * 4) +#define setgcparam(p,v) ((p) = (v) / 4) + +#define LUAI_GCMUL 100 + +/* how much to allocate before next GC step (log2) */ +#define LUAI_GCSTEPSIZE 13 /* 8 KB */ + + +/* +** Check whether the declared GC mode is generational. While in +** generational mode, the collector can go temporarily to incremental +** mode to improve performance. This is signaled by 'g->lastatomic != 0'. +*/ +#define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0) + + +/* +** Control when GC is running: +*/ +#define GCSTPUSR 1 /* bit true when GC stopped by user */ +#define GCSTPGC 2 /* bit true when GC stopped by itself */ +#define GCSTPCLS 4 /* bit true when closing Lua state */ +#define gcrunning(g) ((g)->gcstp == 0) + + +/* +** Does one step of collection when debt becomes positive. 'pre'/'pos' +** allows some adjustments to be done only when needed. macro +** 'condchangemem' is used only for heavy tests (forcing a full +** GC cycle on every opportunity) +*/ +#define luaC_condGC(L,pre,pos) \ + { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \ + condchangemem(L,pre,pos); } + +/* more often than not, 'pre'/'pos' are empty */ +#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) + + +#define luaC_objbarrier(L,p,o) ( \ + (isblack(p) && iswhite(o)) ? \ + luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) + +#define luaC_barrier(L,p,v) ( \ + iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0)) + +#define luaC_objbarrierback(L,p,o) ( \ + (isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0)) + +#define luaC_barrierback(L,p,v) ( \ + iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0)) + +LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); +LUAI_FUNC void luaC_freeallobjects (lua_State *L); +LUAI_FUNC void luaC_step (lua_State *L); +LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); +LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); +LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); +LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, + size_t offset); +LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); +LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); +LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); +LUAI_FUNC void luaC_changemode (lua_State *L, int newmode); + + +#endif diff --git a/vendor/lua-src/lua-5.4.6/linit.c b/vendor/lua-src/lua-5.4.6/linit.c new file mode 100644 index 0000000000000..69808f84f48a1 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/linit.c @@ -0,0 +1,65 @@ +/* +** $Id: linit.c $ +** Initialization of libraries for lua.c and other clients +** See Copyright Notice in lua.h +*/ + + +#define linit_c +#define LUA_LIB + +/* +** If you embed Lua in your program and need to open the standard +** libraries, call luaL_openlibs in your program. If you need a +** different set of libraries, copy this file to your project and edit +** it to suit your needs. +** +** You can also *preload* libraries, so that a later 'require' can +** open the library, which is already linked to the application. +** For that, do the following code: +** +** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); +** lua_pushcfunction(L, luaopen_modname); +** lua_setfield(L, -2, modname); +** lua_pop(L, 1); // remove PRELOAD table +*/ + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "lualib.h" +#include "lauxlib.h" + + +/* +** these libs are loaded by lua.c and are readily available to any Lua +** program +*/ +static const luaL_Reg loadedlibs[] = { + {LUA_GNAME, luaopen_base}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_COLIBNAME, luaopen_coroutine}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_OSLIBNAME, luaopen_os}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_UTF8LIBNAME, luaopen_utf8}, + {LUA_DBLIBNAME, luaopen_debug}, + {NULL, NULL} +}; + + +LUALIB_API void luaL_openlibs (lua_State *L) { + const luaL_Reg *lib; + /* "require" functions from 'loadedlibs' and set results to global table */ + for (lib = loadedlibs; lib->func; lib++) { + luaL_requiref(L, lib->name, lib->func, 1); + lua_pop(L, 1); /* remove lib */ + } +} + diff --git a/vendor/lua-src/lua-5.4.6/liolib.c b/vendor/lua-src/lua-5.4.6/liolib.c new file mode 100644 index 0000000000000..b08397da45da6 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/liolib.c @@ -0,0 +1,828 @@ +/* +** $Id: liolib.c $ +** Standard I/O (and system) library +** See Copyright Notice in lua.h +*/ + +#define liolib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + + +/* +** Change this macro to accept other modes for 'fopen' besides +** the standard ones. +*/ +#if !defined(l_checkmode) + +/* accepted extensions to 'mode' in 'fopen' */ +#if !defined(L_MODEEXT) +#define L_MODEEXT "b" +#endif + +/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */ +static int l_checkmode (const char *mode) { + return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && + (*mode != '+' || ((void)(++mode), 1)) && /* skip if char is '+' */ + (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */ +} + +#endif + +/* +** {====================================================== +** l_popen spawns a new process connected to the current +** one through the file streams. +** ======================================================= +*/ + +#if !defined(l_popen) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#define l_popen(L,c,m) (fflush(NULL), popen(c,m)) +#define l_pclose(L,file) (pclose(file)) + +#elif defined(LUA_USE_WINDOWS) /* }{ */ + +#define l_popen(L,c,m) (_popen(c,m)) +#define l_pclose(L,file) (_pclose(file)) + +#if !defined(l_checkmodep) +/* Windows accepts "[rw][bt]?" as valid modes */ +#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && \ + (m[1] == '\0' || ((m[1] == 'b' || m[1] == 't') && m[2] == '\0'))) +#endif + +#else /* }{ */ + +/* ISO C definitions */ +#define l_popen(L,c,m) \ + ((void)c, (void)m, \ + luaL_error(L, "'popen' not supported"), \ + (FILE*)0) +#define l_pclose(L,file) ((void)L, (void)file, -1) + +#endif /* } */ + +#endif /* } */ + + +#if !defined(l_checkmodep) +/* By default, Lua accepts only "r" or "w" as valid modes */ +#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && m[1] == '\0') +#endif + +/* }====================================================== */ + + +#if !defined(l_getc) /* { */ + +#if defined(LUA_USE_POSIX) +#define l_getc(f) getc_unlocked(f) +#define l_lockfile(f) flockfile(f) +#define l_unlockfile(f) funlockfile(f) +#else +#define l_getc(f) getc(f) +#define l_lockfile(f) ((void)0) +#define l_unlockfile(f) ((void)0) +#endif + +#endif /* } */ + + +/* +** {====================================================== +** l_fseek: configuration for longer offsets +** ======================================================= +*/ + +#if !defined(l_fseek) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#include + +#define l_fseek(f,o,w) fseeko(f,o,w) +#define l_ftell(f) ftello(f) +#define l_seeknum off_t + +#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \ + && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */ + +/* Windows (but not DDK) and Visual C++ 2005 or higher */ +#define l_fseek(f,o,w) _fseeki64(f,o,w) +#define l_ftell(f) _ftelli64(f) +#define l_seeknum __int64 + +#else /* }{ */ + +/* ISO C definitions */ +#define l_fseek(f,o,w) fseek(f,o,w) +#define l_ftell(f) ftell(f) +#define l_seeknum long + +#endif /* } */ + +#endif /* } */ + +/* }====================================================== */ + + + +#define IO_PREFIX "_IO_" +#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) +#define IO_INPUT (IO_PREFIX "input") +#define IO_OUTPUT (IO_PREFIX "output") + + +typedef luaL_Stream LStream; + + +#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) + +#define isclosed(p) ((p)->closef == NULL) + + +static int io_type (lua_State *L) { + LStream *p; + luaL_checkany(L, 1); + p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); + if (p == NULL) + luaL_pushfail(L); /* not a file */ + else if (isclosed(p)) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; +} + + +static int f_tostring (lua_State *L) { + LStream *p = tolstream(L); + if (isclosed(p)) + lua_pushliteral(L, "file (closed)"); + else + lua_pushfstring(L, "file (%p)", p->f); + return 1; +} + + +static FILE *tofile (lua_State *L) { + LStream *p = tolstream(L); + if (l_unlikely(isclosed(p))) + luaL_error(L, "attempt to use a closed file"); + lua_assert(p->f); + return p->f; +} + + +/* +** When creating file handles, always creates a 'closed' file handle +** before opening the actual file; so, if there is a memory error, the +** handle is in a consistent state. +*/ +static LStream *newprefile (lua_State *L) { + LStream *p = (LStream *)lua_newuserdatauv(L, sizeof(LStream), 0); + p->closef = NULL; /* mark file handle as 'closed' */ + luaL_setmetatable(L, LUA_FILEHANDLE); + return p; +} + + +/* +** Calls the 'close' function from a file handle. The 'volatile' avoids +** a bug in some versions of the Clang compiler (e.g., clang 3.0 for +** 32 bits). +*/ +static int aux_close (lua_State *L) { + LStream *p = tolstream(L); + volatile lua_CFunction cf = p->closef; + p->closef = NULL; /* mark stream as closed */ + return (*cf)(L); /* close it */ +} + + +static int f_close (lua_State *L) { + tofile(L); /* make sure argument is an open stream */ + return aux_close(L); +} + + +static int io_close (lua_State *L) { + if (lua_isnone(L, 1)) /* no argument? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use default output */ + return f_close(L); +} + + +static int f_gc (lua_State *L) { + LStream *p = tolstream(L); + if (!isclosed(p) && p->f != NULL) + aux_close(L); /* ignore closed and incompletely open files */ + return 0; +} + + +/* +** function to close regular files +*/ +static int io_fclose (lua_State *L) { + LStream *p = tolstream(L); + int res = fclose(p->f); + return luaL_fileresult(L, (res == 0), NULL); +} + + +static LStream *newfile (lua_State *L) { + LStream *p = newprefile(L); + p->f = NULL; + p->closef = &io_fclose; + return p; +} + + +static void opencheck (lua_State *L, const char *fname, const char *mode) { + LStream *p = newfile(L); + p->f = fopen(fname, mode); + if (l_unlikely(p->f == NULL)) + luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); +} + + +static int io_open (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + LStream *p = newfile(L); + const char *md = mode; /* to traverse/check mode */ + luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); + p->f = fopen(filename, mode); + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; +} + + +/* +** function to close 'popen' files +*/ +static int io_pclose (lua_State *L) { + LStream *p = tolstream(L); + errno = 0; + return luaL_execresult(L, l_pclose(L, p->f)); +} + + +static int io_popen (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + LStream *p = newprefile(L); + luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode"); + p->f = l_popen(L, filename, mode); + p->closef = &io_pclose; + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; +} + + +static int io_tmpfile (lua_State *L) { + LStream *p = newfile(L); + p->f = tmpfile(); + return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; +} + + +static FILE *getiofile (lua_State *L, const char *findex) { + LStream *p; + lua_getfield(L, LUA_REGISTRYINDEX, findex); + p = (LStream *)lua_touserdata(L, -1); + if (l_unlikely(isclosed(p))) + luaL_error(L, "default %s file is closed", findex + IOPREF_LEN); + return p->f; +} + + +static int g_iofile (lua_State *L, const char *f, const char *mode) { + if (!lua_isnoneornil(L, 1)) { + const char *filename = lua_tostring(L, 1); + if (filename) + opencheck(L, filename, mode); + else { + tofile(L); /* check that it's a valid file handle */ + lua_pushvalue(L, 1); + } + lua_setfield(L, LUA_REGISTRYINDEX, f); + } + /* return current value */ + lua_getfield(L, LUA_REGISTRYINDEX, f); + return 1; +} + + +static int io_input (lua_State *L) { + return g_iofile(L, IO_INPUT, "r"); +} + + +static int io_output (lua_State *L) { + return g_iofile(L, IO_OUTPUT, "w"); +} + + +static int io_readline (lua_State *L); + + +/* +** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit +** in the limit for upvalues of a closure) +*/ +#define MAXARGLINE 250 + +/* +** Auxiliary function to create the iteration function for 'lines'. +** The iteration function is a closure over 'io_readline', with +** the following upvalues: +** 1) The file being read (first value in the stack) +** 2) the number of arguments to read +** 3) a boolean, true iff file has to be closed when finished ('toclose') +** *) a variable number of format arguments (rest of the stack) +*/ +static void aux_lines (lua_State *L, int toclose) { + int n = lua_gettop(L) - 1; /* number of arguments to read */ + luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); + lua_pushvalue(L, 1); /* file */ + lua_pushinteger(L, n); /* number of arguments to read */ + lua_pushboolean(L, toclose); /* close/not close file when finished */ + lua_rotate(L, 2, 3); /* move the three values to their positions */ + lua_pushcclosure(L, io_readline, 3 + n); +} + + +static int f_lines (lua_State *L) { + tofile(L); /* check that it's a valid file handle */ + aux_lines(L, 0); + return 1; +} + + +/* +** Return an iteration function for 'io.lines'. If file has to be +** closed, also returns the file itself as a second result (to be +** closed as the state at the exit of a generic for). +*/ +static int io_lines (lua_State *L) { + int toclose; + if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ + if (lua_isnil(L, 1)) { /* no file name? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ + lua_replace(L, 1); /* put it at index 1 */ + tofile(L); /* check that it's a valid file handle */ + toclose = 0; /* do not close it after iteration */ + } + else { /* open a new file */ + const char *filename = luaL_checkstring(L, 1); + opencheck(L, filename, "r"); + lua_replace(L, 1); /* put file at index 1 */ + toclose = 1; /* close it after iteration */ + } + aux_lines(L, toclose); /* push iteration function */ + if (toclose) { + lua_pushnil(L); /* state */ + lua_pushnil(L); /* control */ + lua_pushvalue(L, 1); /* file is the to-be-closed variable (4th result) */ + return 4; + } + else + return 1; +} + + +/* +** {====================================================== +** READ +** ======================================================= +*/ + + +/* maximum length of a numeral */ +#if !defined (L_MAXLENNUM) +#define L_MAXLENNUM 200 +#endif + + +/* auxiliary structure used by 'read_number' */ +typedef struct { + FILE *f; /* file being read */ + int c; /* current character (look ahead) */ + int n; /* number of elements in buffer 'buff' */ + char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */ +} RN; + + +/* +** Add current char to buffer (if not out of space) and read next one +*/ +static int nextc (RN *rn) { + if (l_unlikely(rn->n >= L_MAXLENNUM)) { /* buffer overflow? */ + rn->buff[0] = '\0'; /* invalidate result */ + return 0; /* fail */ + } + else { + rn->buff[rn->n++] = rn->c; /* save current char */ + rn->c = l_getc(rn->f); /* read next one */ + return 1; + } +} + + +/* +** Accept current char if it is in 'set' (of size 2) +*/ +static int test2 (RN *rn, const char *set) { + if (rn->c == set[0] || rn->c == set[1]) + return nextc(rn); + else return 0; +} + + +/* +** Read a sequence of (hex)digits +*/ +static int readdigits (RN *rn, int hex) { + int count = 0; + while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) + count++; + return count; +} + + +/* +** Read a number: first reads a valid prefix of a numeral into a buffer. +** Then it calls 'lua_stringtonumber' to check whether the format is +** correct and to convert it to a Lua number. +*/ +static int read_number (lua_State *L, FILE *f) { + RN rn; + int count = 0; + int hex = 0; + char decp[2]; + rn.f = f; rn.n = 0; + decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ + decp[1] = '.'; /* always accept a dot */ + l_lockfile(rn.f); + do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ + test2(&rn, "-+"); /* optional sign */ + if (test2(&rn, "00")) { + if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ + else count = 1; /* count initial '0' as a valid digit */ + } + count += readdigits(&rn, hex); /* integral part */ + if (test2(&rn, decp)) /* decimal point? */ + count += readdigits(&rn, hex); /* fractional part */ + if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */ + test2(&rn, "-+"); /* exponent sign */ + readdigits(&rn, 0); /* exponent digits */ + } + ungetc(rn.c, rn.f); /* unread look-ahead char */ + l_unlockfile(rn.f); + rn.buff[rn.n] = '\0'; /* finish string */ + if (l_likely(lua_stringtonumber(L, rn.buff))) + return 1; /* ok, it is a valid number */ + else { /* invalid format */ + lua_pushnil(L); /* "result" to be removed */ + return 0; /* read fails */ + } +} + + +static int test_eof (lua_State *L, FILE *f) { + int c = getc(f); + ungetc(c, f); /* no-op when c == EOF */ + lua_pushliteral(L, ""); + return (c != EOF); +} + + +static int read_line (lua_State *L, FILE *f, int chop) { + luaL_Buffer b; + int c; + luaL_buffinit(L, &b); + do { /* may need to read several chunks to get whole line */ + char *buff = luaL_prepbuffer(&b); /* preallocate buffer space */ + int i = 0; + l_lockfile(f); /* no memory errors can happen inside the lock */ + while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') + buff[i++] = c; /* read up to end of line or buffer limit */ + l_unlockfile(f); + luaL_addsize(&b, i); + } while (c != EOF && c != '\n'); /* repeat until end of line */ + if (!chop && c == '\n') /* want a newline and have one? */ + luaL_addchar(&b, c); /* add ending newline to result */ + luaL_pushresult(&b); /* close buffer */ + /* return ok if read something (either a newline or something else) */ + return (c == '\n' || lua_rawlen(L, -1) > 0); +} + + +static void read_all (lua_State *L, FILE *f) { + size_t nr; + luaL_Buffer b; + luaL_buffinit(L, &b); + do { /* read file in chunks of LUAL_BUFFERSIZE bytes */ + char *p = luaL_prepbuffer(&b); + nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); + luaL_addsize(&b, nr); + } while (nr == LUAL_BUFFERSIZE); + luaL_pushresult(&b); /* close buffer */ +} + + +static int read_chars (lua_State *L, FILE *f, size_t n) { + size_t nr; /* number of chars actually read */ + char *p; + luaL_Buffer b; + luaL_buffinit(L, &b); + p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ + nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */ + luaL_addsize(&b, nr); + luaL_pushresult(&b); /* close buffer */ + return (nr > 0); /* true iff read something */ +} + + +static int g_read (lua_State *L, FILE *f, int first) { + int nargs = lua_gettop(L) - 1; + int n, success; + clearerr(f); + if (nargs == 0) { /* no arguments? */ + success = read_line(L, f, 1); + n = first + 1; /* to return 1 result */ + } + else { + /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); + success = 1; + for (n = first; nargs-- && success; n++) { + if (lua_type(L, n) == LUA_TNUMBER) { + size_t l = (size_t)luaL_checkinteger(L, n); + success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); + } + else { + const char *p = luaL_checkstring(L, n); + if (*p == '*') p++; /* skip optional '*' (for compatibility) */ + switch (*p) { + case 'n': /* number */ + success = read_number(L, f); + break; + case 'l': /* line */ + success = read_line(L, f, 1); + break; + case 'L': /* line with end-of-line */ + success = read_line(L, f, 0); + break; + case 'a': /* file */ + read_all(L, f); /* read entire file */ + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (ferror(f)) + return luaL_fileresult(L, 0, NULL); + if (!success) { + lua_pop(L, 1); /* remove last result */ + luaL_pushfail(L); /* push nil instead */ + } + return n - first; +} + + +static int io_read (lua_State *L) { + return g_read(L, getiofile(L, IO_INPUT), 1); +} + + +static int f_read (lua_State *L) { + return g_read(L, tofile(L), 2); +} + + +/* +** Iteration function for 'lines'. +*/ +static int io_readline (lua_State *L) { + LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); + int i; + int n = (int)lua_tointeger(L, lua_upvalueindex(2)); + if (isclosed(p)) /* file is already closed? */ + return luaL_error(L, "file is already closed"); + lua_settop(L , 1); + luaL_checkstack(L, n, "too many arguments"); + for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ + lua_pushvalue(L, lua_upvalueindex(3 + i)); + n = g_read(L, p->f, 2); /* 'n' is number of results */ + lua_assert(n > 0); /* should return at least a nil */ + if (lua_toboolean(L, -n)) /* read at least one value? */ + return n; /* return them */ + else { /* first result is false: EOF or error */ + if (n > 1) { /* is there error information? */ + /* 2nd result is error message */ + return luaL_error(L, "%s", lua_tostring(L, -n + 1)); + } + if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ + lua_settop(L, 0); /* clear stack */ + lua_pushvalue(L, lua_upvalueindex(1)); /* push file at index 1 */ + aux_close(L); /* close it */ + } + return 0; + } +} + +/* }====================================================== */ + + +static int g_write (lua_State *L, FILE *f, int arg) { + int nargs = lua_gettop(L) - arg; + int status = 1; + for (; nargs--; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { + /* optimization: could be done exactly as for strings */ + int len = lua_isinteger(L, arg) + ? fprintf(f, LUA_INTEGER_FMT, + (LUAI_UACINT)lua_tointeger(L, arg)) + : fprintf(f, LUA_NUMBER_FMT, + (LUAI_UACNUMBER)lua_tonumber(L, arg)); + status = status && (len > 0); + } + else { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + status = status && (fwrite(s, sizeof(char), l, f) == l); + } + } + if (l_likely(status)) + return 1; /* file handle already on stack top */ + else return luaL_fileresult(L, status, NULL); +} + + +static int io_write (lua_State *L) { + return g_write(L, getiofile(L, IO_OUTPUT), 1); +} + + +static int f_write (lua_State *L) { + FILE *f = tofile(L); + lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ + return g_write(L, f, 2); +} + + +static int f_seek (lua_State *L) { + static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; + static const char *const modenames[] = {"set", "cur", "end", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, "cur", modenames); + lua_Integer p3 = luaL_optinteger(L, 3, 0); + l_seeknum offset = (l_seeknum)p3; + luaL_argcheck(L, (lua_Integer)offset == p3, 3, + "not an integer in proper range"); + op = l_fseek(f, offset, mode[op]); + if (l_unlikely(op)) + return luaL_fileresult(L, 0, NULL); /* error */ + else { + lua_pushinteger(L, (lua_Integer)l_ftell(f)); + return 1; + } +} + + +static int f_setvbuf (lua_State *L) { + static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; + static const char *const modenames[] = {"no", "full", "line", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, NULL, modenames); + lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); + int res = setvbuf(f, NULL, mode[op], (size_t)sz); + return luaL_fileresult(L, res == 0, NULL); +} + + + +static int io_flush (lua_State *L) { + return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); +} + + +static int f_flush (lua_State *L) { + return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); +} + + +/* +** functions for 'io' library +*/ +static const luaL_Reg iolib[] = { + {"close", io_close}, + {"flush", io_flush}, + {"input", io_input}, + {"lines", io_lines}, + {"open", io_open}, + {"output", io_output}, + {"popen", io_popen}, + {"read", io_read}, + {"tmpfile", io_tmpfile}, + {"type", io_type}, + {"write", io_write}, + {NULL, NULL} +}; + + +/* +** methods for file handles +*/ +static const luaL_Reg meth[] = { + {"read", f_read}, + {"write", f_write}, + {"lines", f_lines}, + {"flush", f_flush}, + {"seek", f_seek}, + {"close", f_close}, + {"setvbuf", f_setvbuf}, + {NULL, NULL} +}; + + +/* +** metamethods for file handles +*/ +static const luaL_Reg metameth[] = { + {"__index", NULL}, /* place holder */ + {"__gc", f_gc}, + {"__close", f_gc}, + {"__tostring", f_tostring}, + {NULL, NULL} +}; + + +static void createmeta (lua_State *L) { + luaL_newmetatable(L, LUA_FILEHANDLE); /* metatable for file handles */ + luaL_setfuncs(L, metameth, 0); /* add metamethods to new metatable */ + luaL_newlibtable(L, meth); /* create method table */ + luaL_setfuncs(L, meth, 0); /* add file methods to method table */ + lua_setfield(L, -2, "__index"); /* metatable.__index = method table */ + lua_pop(L, 1); /* pop metatable */ +} + + +/* +** function to (not) close the standard files stdin, stdout, and stderr +*/ +static int io_noclose (lua_State *L) { + LStream *p = tolstream(L); + p->closef = &io_noclose; /* keep file opened */ + luaL_pushfail(L); + lua_pushliteral(L, "cannot close standard file"); + return 2; +} + + +static void createstdfile (lua_State *L, FILE *f, const char *k, + const char *fname) { + LStream *p = newprefile(L); + p->f = f; + p->closef = &io_noclose; + if (k != NULL) { + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ + } + lua_setfield(L, -2, fname); /* add file to module */ +} + + +LUAMOD_API int luaopen_io (lua_State *L) { + luaL_newlib(L, iolib); /* new module */ + createmeta(L); + /* create (and set) default files */ + createstdfile(L, stdin, IO_INPUT, "stdin"); + createstdfile(L, stdout, IO_OUTPUT, "stdout"); + createstdfile(L, stderr, NULL, "stderr"); + return 1; +} + diff --git a/vendor/lua-src/lua-5.4.6/ljumptab.h b/vendor/lua-src/lua-5.4.6/ljumptab.h new file mode 100644 index 0000000000000..8306f250ccb65 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/ljumptab.h @@ -0,0 +1,112 @@ +/* +** $Id: ljumptab.h $ +** Jump Table for the Lua interpreter +** See Copyright Notice in lua.h +*/ + + +#undef vmdispatch +#undef vmcase +#undef vmbreak + +#define vmdispatch(x) goto *disptab[x]; + +#define vmcase(l) L_##l: + +#define vmbreak vmfetch(); vmdispatch(GET_OPCODE(i)); + + +static const void *const disptab[NUM_OPCODES] = { + +#if 0 +** you can update the following list with this command: +** +** sed -n '/^OP_/\!d; s/OP_/\&\&L_OP_/ ; s/,.*/,/ ; s/\/.*// ; p' lopcodes.h +** +#endif + +&&L_OP_MOVE, +&&L_OP_LOADI, +&&L_OP_LOADF, +&&L_OP_LOADK, +&&L_OP_LOADKX, +&&L_OP_LOADFALSE, +&&L_OP_LFALSESKIP, +&&L_OP_LOADTRUE, +&&L_OP_LOADNIL, +&&L_OP_GETUPVAL, +&&L_OP_SETUPVAL, +&&L_OP_GETTABUP, +&&L_OP_GETTABLE, +&&L_OP_GETI, +&&L_OP_GETFIELD, +&&L_OP_SETTABUP, +&&L_OP_SETTABLE, +&&L_OP_SETI, +&&L_OP_SETFIELD, +&&L_OP_NEWTABLE, +&&L_OP_SELF, +&&L_OP_ADDI, +&&L_OP_ADDK, +&&L_OP_SUBK, +&&L_OP_MULK, +&&L_OP_MODK, +&&L_OP_POWK, +&&L_OP_DIVK, +&&L_OP_IDIVK, +&&L_OP_BANDK, +&&L_OP_BORK, +&&L_OP_BXORK, +&&L_OP_SHRI, +&&L_OP_SHLI, +&&L_OP_ADD, +&&L_OP_SUB, +&&L_OP_MUL, +&&L_OP_MOD, +&&L_OP_POW, +&&L_OP_DIV, +&&L_OP_IDIV, +&&L_OP_BAND, +&&L_OP_BOR, +&&L_OP_BXOR, +&&L_OP_SHL, +&&L_OP_SHR, +&&L_OP_MMBIN, +&&L_OP_MMBINI, +&&L_OP_MMBINK, +&&L_OP_UNM, +&&L_OP_BNOT, +&&L_OP_NOT, +&&L_OP_LEN, +&&L_OP_CONCAT, +&&L_OP_CLOSE, +&&L_OP_TBC, +&&L_OP_JMP, +&&L_OP_EQ, +&&L_OP_LT, +&&L_OP_LE, +&&L_OP_EQK, +&&L_OP_EQI, +&&L_OP_LTI, +&&L_OP_LEI, +&&L_OP_GTI, +&&L_OP_GEI, +&&L_OP_TEST, +&&L_OP_TESTSET, +&&L_OP_CALL, +&&L_OP_TAILCALL, +&&L_OP_RETURN, +&&L_OP_RETURN0, +&&L_OP_RETURN1, +&&L_OP_FORLOOP, +&&L_OP_FORPREP, +&&L_OP_TFORPREP, +&&L_OP_TFORCALL, +&&L_OP_TFORLOOP, +&&L_OP_SETLIST, +&&L_OP_CLOSURE, +&&L_OP_VARARG, +&&L_OP_VARARGPREP, +&&L_OP_EXTRAARG + +}; diff --git a/vendor/lua-src/lua-5.4.6/llex.c b/vendor/lua-src/lua-5.4.6/llex.c new file mode 100644 index 0000000000000..5fc39a5cdec17 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/llex.c @@ -0,0 +1,581 @@ +/* +** $Id: llex.c $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + +#define llex_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lctype.h" +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "llex.h" +#include "lobject.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "lzio.h" + + + +#define next(ls) (ls->current = zgetc(ls->z)) + + + +#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') + + +/* ORDER RESERVED */ +static const char *const luaX_tokens [] = { + "and", "break", "do", "else", "elseif", + "end", "false", "for", "function", "goto", "if", + "in", "local", "nil", "not", "or", "repeat", + "return", "then", "true", "until", "while", + "//", "..", "...", "==", ">=", "<=", "~=", + "<<", ">>", "::", "", + "", "", "", "" +}; + + +#define save_and_next(ls) (save(ls, ls->current), next(ls)) + + +static l_noret lexerror (LexState *ls, const char *msg, int token); + + +static void save (LexState *ls, int c) { + Mbuffer *b = ls->buff; + if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { + size_t newsize; + if (luaZ_sizebuffer(b) >= MAX_SIZE/2) + lexerror(ls, "lexical element too long", 0); + newsize = luaZ_sizebuffer(b) * 2; + luaZ_resizebuffer(ls->L, b, newsize); + } + b->buffer[luaZ_bufflen(b)++] = cast_char(c); +} + + +void luaX_init (lua_State *L) { + int i; + TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */ + luaC_fix(L, obj2gco(e)); /* never collect this name */ + for (i=0; iextra = cast_byte(i+1); /* reserved word */ + } +} + + +const char *luaX_token2str (LexState *ls, int token) { + if (token < FIRST_RESERVED) { /* single-byte symbols? */ + if (lisprint(token)) + return luaO_pushfstring(ls->L, "'%c'", token); + else /* control character */ + return luaO_pushfstring(ls->L, "'<\\%d>'", token); + } + else { + const char *s = luaX_tokens[token - FIRST_RESERVED]; + if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ + return luaO_pushfstring(ls->L, "'%s'", s); + else /* names, strings, and numerals */ + return s; + } +} + + +static const char *txtToken (LexState *ls, int token) { + switch (token) { + case TK_NAME: case TK_STRING: + case TK_FLT: case TK_INT: + save(ls, '\0'); + return luaO_pushfstring(ls->L, "'%s'", luaZ_buffer(ls->buff)); + default: + return luaX_token2str(ls, token); + } +} + + +static l_noret lexerror (LexState *ls, const char *msg, int token) { + msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber); + if (token) + luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token)); + luaD_throw(ls->L, LUA_ERRSYNTAX); +} + + +l_noret luaX_syntaxerror (LexState *ls, const char *msg) { + lexerror(ls, msg, ls->t.token); +} + + +/* +** Creates a new string and anchors it in scanner's table so that it +** will not be collected until the end of the compilation; by that time +** it should be anchored somewhere. It also internalizes long strings, +** ensuring there is only one copy of each unique string. The table +** here is used as a set: the string enters as the key, while its value +** is irrelevant. We use the string itself as the value only because it +** is a TValue readily available. Later, the code generation can change +** this value. +*/ +TString *luaX_newstring (LexState *ls, const char *str, size_t l) { + lua_State *L = ls->L; + TString *ts = luaS_newlstr(L, str, l); /* create new string */ + const TValue *o = luaH_getstr(ls->h, ts); + if (!ttisnil(o)) /* string already present? */ + ts = keystrval(nodefromval(o)); /* get saved copy */ + else { /* not in use yet */ + TValue *stv = s2v(L->top.p++); /* reserve stack space for string */ + setsvalue(L, stv, ts); /* temporarily anchor the string */ + luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */ + /* table is not a metatable, so it does not need to invalidate cache */ + luaC_checkGC(L); + L->top.p--; /* remove string from stack */ + } + return ts; +} + + +/* +** increment line number and skips newline sequence (any of +** \n, \r, \n\r, or \r\n) +*/ +static void inclinenumber (LexState *ls) { + int old = ls->current; + lua_assert(currIsNewline(ls)); + next(ls); /* skip '\n' or '\r' */ + if (currIsNewline(ls) && ls->current != old) + next(ls); /* skip '\n\r' or '\r\n' */ + if (++ls->linenumber >= MAX_INT) + lexerror(ls, "chunk has too many lines", 0); +} + + +void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, + int firstchar) { + ls->t.token = 0; + ls->L = L; + ls->current = firstchar; + ls->lookahead.token = TK_EOS; /* no look-ahead token */ + ls->z = z; + ls->fs = NULL; + ls->linenumber = 1; + ls->lastline = 1; + ls->source = source; + ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */ + luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ +} + + + +/* +** ======================================================= +** LEXICAL ANALYZER +** ======================================================= +*/ + + +static int check_next1 (LexState *ls, int c) { + if (ls->current == c) { + next(ls); + return 1; + } + else return 0; +} + + +/* +** Check whether current char is in set 'set' (with two chars) and +** saves it +*/ +static int check_next2 (LexState *ls, const char *set) { + lua_assert(set[2] == '\0'); + if (ls->current == set[0] || ls->current == set[1]) { + save_and_next(ls); + return 1; + } + else return 0; +} + + +/* LUA_NUMBER */ +/* +** This function is quite liberal in what it accepts, as 'luaO_str2num' +** will reject ill-formed numerals. Roughly, it accepts the following +** pattern: +** +** %d(%x|%.|([Ee][+-]?))* | 0[Xx](%x|%.|([Pp][+-]?))* +** +** The only tricky part is to accept [+-] only after a valid exponent +** mark, to avoid reading '3-4' or '0xe+1' as a single number. +** +** The caller might have already read an initial dot. +*/ +static int read_numeral (LexState *ls, SemInfo *seminfo) { + TValue obj; + const char *expo = "Ee"; + int first = ls->current; + lua_assert(lisdigit(ls->current)); + save_and_next(ls); + if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */ + expo = "Pp"; + for (;;) { + if (check_next2(ls, expo)) /* exponent mark? */ + check_next2(ls, "-+"); /* optional exponent sign */ + else if (lisxdigit(ls->current) || ls->current == '.') /* '%x|%.' */ + save_and_next(ls); + else break; + } + if (lislalpha(ls->current)) /* is numeral touching a letter? */ + save_and_next(ls); /* force an error */ + save(ls, '\0'); + if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */ + lexerror(ls, "malformed number", TK_FLT); + if (ttisinteger(&obj)) { + seminfo->i = ivalue(&obj); + return TK_INT; + } + else { + lua_assert(ttisfloat(&obj)); + seminfo->r = fltvalue(&obj); + return TK_FLT; + } +} + + +/* +** read a sequence '[=*[' or ']=*]', leaving the last bracket. If +** sequence is well formed, return its number of '='s + 2; otherwise, +** return 1 if it is a single bracket (no '='s and no 2nd bracket); +** otherwise (an unfinished '[==...') return 0. +*/ +static size_t skip_sep (LexState *ls) { + size_t count = 0; + int s = ls->current; + lua_assert(s == '[' || s == ']'); + save_and_next(ls); + while (ls->current == '=') { + save_and_next(ls); + count++; + } + return (ls->current == s) ? count + 2 + : (count == 0) ? 1 + : 0; +} + + +static void read_long_string (LexState *ls, SemInfo *seminfo, size_t sep) { + int line = ls->linenumber; /* initial line (for error message) */ + save_and_next(ls); /* skip 2nd '[' */ + if (currIsNewline(ls)) /* string starts with a newline? */ + inclinenumber(ls); /* skip it */ + for (;;) { + switch (ls->current) { + case EOZ: { /* error */ + const char *what = (seminfo ? "string" : "comment"); + const char *msg = luaO_pushfstring(ls->L, + "unfinished long %s (starting at line %d)", what, line); + lexerror(ls, msg, TK_EOS); + break; /* to avoid warnings */ + } + case ']': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd ']' */ + goto endloop; + } + break; + } + case '\n': case '\r': { + save(ls, '\n'); + inclinenumber(ls); + if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ + break; + } + default: { + if (seminfo) save_and_next(ls); + else next(ls); + } + } + } endloop: + if (seminfo) + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + sep, + luaZ_bufflen(ls->buff) - 2 * sep); +} + + +static void esccheck (LexState *ls, int c, const char *msg) { + if (!c) { + if (ls->current != EOZ) + save_and_next(ls); /* add current to buffer for error message */ + lexerror(ls, msg, TK_STRING); + } +} + + +static int gethexa (LexState *ls) { + save_and_next(ls); + esccheck (ls, lisxdigit(ls->current), "hexadecimal digit expected"); + return luaO_hexavalue(ls->current); +} + + +static int readhexaesc (LexState *ls) { + int r = gethexa(ls); + r = (r << 4) + gethexa(ls); + luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */ + return r; +} + + +static unsigned long readutf8esc (LexState *ls) { + unsigned long r; + int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */ + save_and_next(ls); /* skip 'u' */ + esccheck(ls, ls->current == '{', "missing '{'"); + r = gethexa(ls); /* must have at least one digit */ + while (cast_void(save_and_next(ls)), lisxdigit(ls->current)) { + i++; + esccheck(ls, r <= (0x7FFFFFFFu >> 4), "UTF-8 value too large"); + r = (r << 4) + luaO_hexavalue(ls->current); + } + esccheck(ls, ls->current == '}', "missing '}'"); + next(ls); /* skip '}' */ + luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */ + return r; +} + + +static void utf8esc (LexState *ls) { + char buff[UTF8BUFFSZ]; + int n = luaO_utf8esc(buff, readutf8esc(ls)); + for (; n > 0; n--) /* add 'buff' to string */ + save(ls, buff[UTF8BUFFSZ - n]); +} + + +static int readdecesc (LexState *ls) { + int i; + int r = 0; /* result accumulator */ + for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */ + r = 10*r + ls->current - '0'; + save_and_next(ls); + } + esccheck(ls, r <= UCHAR_MAX, "decimal escape too large"); + luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */ + return r; +} + + +static void read_string (LexState *ls, int del, SemInfo *seminfo) { + save_and_next(ls); /* keep delimiter (for error messages) */ + while (ls->current != del) { + switch (ls->current) { + case EOZ: + lexerror(ls, "unfinished string", TK_EOS); + break; /* to avoid warnings */ + case '\n': + case '\r': + lexerror(ls, "unfinished string", TK_STRING); + break; /* to avoid warnings */ + case '\\': { /* escape sequences */ + int c; /* final character to be saved */ + save_and_next(ls); /* keep '\\' for error messages */ + switch (ls->current) { + case 'a': c = '\a'; goto read_save; + case 'b': c = '\b'; goto read_save; + case 'f': c = '\f'; goto read_save; + case 'n': c = '\n'; goto read_save; + case 'r': c = '\r'; goto read_save; + case 't': c = '\t'; goto read_save; + case 'v': c = '\v'; goto read_save; + case 'x': c = readhexaesc(ls); goto read_save; + case 'u': utf8esc(ls); goto no_save; + case '\n': case '\r': + inclinenumber(ls); c = '\n'; goto only_save; + case '\\': case '\"': case '\'': + c = ls->current; goto read_save; + case EOZ: goto no_save; /* will raise an error next loop */ + case 'z': { /* zap following span of spaces */ + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ + next(ls); /* skip the 'z' */ + while (lisspace(ls->current)) { + if (currIsNewline(ls)) inclinenumber(ls); + else next(ls); + } + goto no_save; + } + default: { + esccheck(ls, lisdigit(ls->current), "invalid escape sequence"); + c = readdecesc(ls); /* digital escape '\ddd' */ + goto only_save; + } + } + read_save: + next(ls); + /* go through */ + only_save: + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ + save(ls, c); + /* go through */ + no_save: break; + } + default: + save_and_next(ls); + } + } + save_and_next(ls); /* skip delimiter */ + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, + luaZ_bufflen(ls->buff) - 2); +} + + +static int llex (LexState *ls, SemInfo *seminfo) { + luaZ_resetbuffer(ls->buff); + for (;;) { + switch (ls->current) { + case '\n': case '\r': { /* line breaks */ + inclinenumber(ls); + break; + } + case ' ': case '\f': case '\t': case '\v': { /* spaces */ + next(ls); + break; + } + case '-': { /* '-' or '--' (comment) */ + next(ls); + if (ls->current != '-') return '-'; + /* else is a comment */ + next(ls); + if (ls->current == '[') { /* long comment? */ + size_t sep = skip_sep(ls); + luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */ + if (sep >= 2) { + read_long_string(ls, NULL, sep); /* skip long comment */ + luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ + break; + } + } + /* else short comment */ + while (!currIsNewline(ls) && ls->current != EOZ) + next(ls); /* skip until end of line (or end of file) */ + break; + } + case '[': { /* long string or simply '[' */ + size_t sep = skip_sep(ls); + if (sep >= 2) { + read_long_string(ls, seminfo, sep); + return TK_STRING; + } + else if (sep == 0) /* '[=...' missing second bracket? */ + lexerror(ls, "invalid long string delimiter", TK_STRING); + return '['; + } + case '=': { + next(ls); + if (check_next1(ls, '=')) return TK_EQ; /* '==' */ + else return '='; + } + case '<': { + next(ls); + if (check_next1(ls, '=')) return TK_LE; /* '<=' */ + else if (check_next1(ls, '<')) return TK_SHL; /* '<<' */ + else return '<'; + } + case '>': { + next(ls); + if (check_next1(ls, '=')) return TK_GE; /* '>=' */ + else if (check_next1(ls, '>')) return TK_SHR; /* '>>' */ + else return '>'; + } + case '/': { + next(ls); + if (check_next1(ls, '/')) return TK_IDIV; /* '//' */ + else return '/'; + } + case '~': { + next(ls); + if (check_next1(ls, '=')) return TK_NE; /* '~=' */ + else return '~'; + } + case ':': { + next(ls); + if (check_next1(ls, ':')) return TK_DBCOLON; /* '::' */ + else return ':'; + } + case '"': case '\'': { /* short literal strings */ + read_string(ls, ls->current, seminfo); + return TK_STRING; + } + case '.': { /* '.', '..', '...', or number */ + save_and_next(ls); + if (check_next1(ls, '.')) { + if (check_next1(ls, '.')) + return TK_DOTS; /* '...' */ + else return TK_CONCAT; /* '..' */ + } + else if (!lisdigit(ls->current)) return '.'; + else return read_numeral(ls, seminfo); + } + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + return read_numeral(ls, seminfo); + } + case EOZ: { + return TK_EOS; + } + default: { + if (lislalpha(ls->current)) { /* identifier or reserved word? */ + TString *ts; + do { + save_and_next(ls); + } while (lislalnum(ls->current)); + ts = luaX_newstring(ls, luaZ_buffer(ls->buff), + luaZ_bufflen(ls->buff)); + seminfo->ts = ts; + if (isreserved(ts)) /* reserved word? */ + return ts->extra - 1 + FIRST_RESERVED; + else { + return TK_NAME; + } + } + else { /* single-char tokens ('+', '*', '%', '{', '}', ...) */ + int c = ls->current; + next(ls); + return c; + } + } + } + } +} + + +void luaX_next (LexState *ls) { + ls->lastline = ls->linenumber; + if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ + ls->t = ls->lookahead; /* use this one */ + ls->lookahead.token = TK_EOS; /* and discharge it */ + } + else + ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ +} + + +int luaX_lookahead (LexState *ls) { + lua_assert(ls->lookahead.token == TK_EOS); + ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); + return ls->lookahead.token; +} + diff --git a/vendor/lua-src/lua-5.4.6/llex.h b/vendor/lua-src/lua-5.4.6/llex.h new file mode 100644 index 0000000000000..389d2f863592a --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/llex.h @@ -0,0 +1,91 @@ +/* +** $Id: llex.h $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + +#ifndef llex_h +#define llex_h + +#include + +#include "lobject.h" +#include "lzio.h" + + +/* +** Single-char tokens (terminal symbols) are represented by their own +** numeric code. Other tokens start at the following value. +*/ +#define FIRST_RESERVED (UCHAR_MAX + 1) + + +#if !defined(LUA_ENV) +#define LUA_ENV "_ENV" +#endif + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER RESERVED" +*/ +enum RESERVED { + /* terminal symbols denoted by reserved words */ + TK_AND = FIRST_RESERVED, TK_BREAK, + TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, + TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, + TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, + /* other terminal symbols */ + TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, + TK_SHL, TK_SHR, + TK_DBCOLON, TK_EOS, + TK_FLT, TK_INT, TK_NAME, TK_STRING +}; + +/* number of reserved words */ +#define NUM_RESERVED (cast_int(TK_WHILE-FIRST_RESERVED + 1)) + + +typedef union { + lua_Number r; + lua_Integer i; + TString *ts; +} SemInfo; /* semantics information */ + + +typedef struct Token { + int token; + SemInfo seminfo; +} Token; + + +/* state of the lexer plus state of the parser when shared by all + functions */ +typedef struct LexState { + int current; /* current character (charint) */ + int linenumber; /* input line counter */ + int lastline; /* line of last token 'consumed' */ + Token t; /* current token */ + Token lookahead; /* look ahead token */ + struct FuncState *fs; /* current function (parser) */ + struct lua_State *L; + ZIO *z; /* input stream */ + Mbuffer *buff; /* buffer for tokens */ + Table *h; /* to avoid collection/reuse strings */ + struct Dyndata *dyd; /* dynamic structures used by the parser */ + TString *source; /* current source name */ + TString *envn; /* environment variable name */ +} LexState; + + +LUAI_FUNC void luaX_init (lua_State *L); +LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, + TString *source, int firstchar); +LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); +LUAI_FUNC void luaX_next (LexState *ls); +LUAI_FUNC int luaX_lookahead (LexState *ls); +LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s); +LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); + + +#endif diff --git a/vendor/lua-src/lua-5.4.6/llimits.h b/vendor/lua-src/lua-5.4.6/llimits.h new file mode 100644 index 0000000000000..1c826f7be205b --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/llimits.h @@ -0,0 +1,380 @@ +/* +** $Id: llimits.h $ +** Limits, basic types, and some other 'installation-dependent' definitions +** See Copyright Notice in lua.h +*/ + +#ifndef llimits_h +#define llimits_h + + +#include +#include + + +#include "lua.h" + + +/* +** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count +** the total memory used by Lua (in bytes). Usually, 'size_t' and +** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. +*/ +#if defined(LUAI_MEM) /* { external definitions? */ +typedef LUAI_UMEM lu_mem; +typedef LUAI_MEM l_mem; +#elif LUAI_IS32INT /* }{ */ +typedef size_t lu_mem; +typedef ptrdiff_t l_mem; +#else /* 16-bit ints */ /* }{ */ +typedef unsigned long lu_mem; +typedef long l_mem; +#endif /* } */ + + +/* chars used as small naturals (so that 'char' is reserved for characters) */ +typedef unsigned char lu_byte; +typedef signed char ls_byte; + + +/* maximum value for size_t */ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +/* maximum size visible for Lua (must be representable in a lua_Integer) */ +#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \ + : (size_t)(LUA_MAXINTEGER)) + + +#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)) + +#define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1)) + + +#define MAX_INT INT_MAX /* maximum value of an int */ + + +/* +** floor of the log2 of the maximum signed value for integral type 't'. +** (That is, maximum 'n' such that '2^n' fits in the given signed type.) +*/ +#define log2maxs(t) (sizeof(t) * 8 - 2) + + +/* +** test whether an unsigned value is a power of 2 (or zero) +*/ +#define ispow2(x) (((x) & ((x) - 1)) == 0) + + +/* number of chars of a literal string without the ending \0 */ +#define LL(x) (sizeof(x)/sizeof(char) - 1) + + +/* +** conversion of pointer to unsigned integer: this is for hashing only; +** there is no problem if the integer cannot hold the whole pointer +** value. (In strict ISO C this may cause undefined behavior, but no +** actual machine seems to bother.) +*/ +#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ + __STDC_VERSION__ >= 199901L +#include +#if defined(UINTPTR_MAX) /* even in C99 this type is optional */ +#define L_P2I uintptr_t +#else /* no 'intptr'? */ +#define L_P2I uintmax_t /* use the largest available integer */ +#endif +#else /* C89 option */ +#define L_P2I size_t +#endif + +#define point2uint(p) ((unsigned int)((L_P2I)(p) & UINT_MAX)) + + + +/* types of 'usual argument conversions' for lua_Number and lua_Integer */ +typedef LUAI_UACNUMBER l_uacNumber; +typedef LUAI_UACINT l_uacInt; + + +/* +** Internal assertions for in-house debugging +*/ +#if defined LUAI_ASSERT +#undef NDEBUG +#include +#define lua_assert(c) assert(c) +#endif + +#if defined(lua_assert) +#define check_exp(c,e) (lua_assert(c), (e)) +/* to avoid problems with conditions too long */ +#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0)) +#else +#define lua_assert(c) ((void)0) +#define check_exp(c,e) (e) +#define lua_longassert(c) ((void)0) +#endif + +/* +** assertion for checking API calls +*/ +#if !defined(luai_apicheck) +#define luai_apicheck(l,e) ((void)l, lua_assert(e)) +#endif + +#define api_check(l,e,msg) luai_apicheck(l,(e) && msg) + + +/* macro to avoid warnings about unused variables */ +#if !defined(UNUSED) +#define UNUSED(x) ((void)(x)) +#endif + + +/* type casts (a macro highlights casts in the code) */ +#define cast(t, exp) ((t)(exp)) + +#define cast_void(i) cast(void, (i)) +#define cast_voidp(i) cast(void *, (i)) +#define cast_num(i) cast(lua_Number, (i)) +#define cast_int(i) cast(int, (i)) +#define cast_uint(i) cast(unsigned int, (i)) +#define cast_byte(i) cast(lu_byte, (i)) +#define cast_uchar(i) cast(unsigned char, (i)) +#define cast_char(i) cast(char, (i)) +#define cast_charp(i) cast(char *, (i)) +#define cast_sizet(i) cast(size_t, (i)) + + +/* cast a signed lua_Integer to lua_Unsigned */ +#if !defined(l_castS2U) +#define l_castS2U(i) ((lua_Unsigned)(i)) +#endif + +/* +** cast a lua_Unsigned to a signed lua_Integer; this cast is +** not strict ISO C, but two-complement architectures should +** work fine. +*/ +#if !defined(l_castU2S) +#define l_castU2S(i) ((lua_Integer)(i)) +#endif + + +/* +** non-return type +*/ +#if !defined(l_noret) + +#if defined(__GNUC__) +#define l_noret void __attribute__((noreturn)) +#elif defined(_MSC_VER) && _MSC_VER >= 1200 +#define l_noret void __declspec(noreturn) +#else +#define l_noret void +#endif + +#endif + + +/* +** Inline functions +*/ +#if !defined(LUA_USE_C89) +#define l_inline inline +#elif defined(__GNUC__) +#define l_inline __inline__ +#else +#define l_inline /* empty */ +#endif + +#define l_sinline static l_inline + + +/* +** type for virtual-machine instructions; +** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) +*/ +#if LUAI_IS32INT +typedef unsigned int l_uint32; +#else +typedef unsigned long l_uint32; +#endif + +typedef l_uint32 Instruction; + + + +/* +** Maximum length for short strings, that is, strings that are +** internalized. (Cannot be smaller than reserved words or tags for +** metamethods, as these strings must be internalized; +** #("function") = 8, #("__newindex") = 10.) +*/ +#if !defined(LUAI_MAXSHORTLEN) +#define LUAI_MAXSHORTLEN 40 +#endif + + +/* +** Initial size for the string table (must be power of 2). +** The Lua core alone registers ~50 strings (reserved words + +** metaevent keys + a few others). Libraries would typically add +** a few dozens more. +*/ +#if !defined(MINSTRTABSIZE) +#define MINSTRTABSIZE 128 +#endif + + +/* +** Size of cache for strings in the API. 'N' is the number of +** sets (better be a prime) and "M" is the size of each set (M == 1 +** makes a direct cache.) +*/ +#if !defined(STRCACHE_N) +#define STRCACHE_N 53 +#define STRCACHE_M 2 +#endif + + +/* minimum size for string buffer */ +#if !defined(LUA_MINBUFFER) +#define LUA_MINBUFFER 32 +#endif + + +/* +** Maximum depth for nested C calls, syntactical nested non-terminals, +** and other features implemented through recursion in C. (Value must +** fit in a 16-bit unsigned integer. It must also be compatible with +** the size of the C stack.) +*/ +#if !defined(LUAI_MAXCCALLS) +#define LUAI_MAXCCALLS 200 +#endif + + +/* +** macros that are executed whenever program enters the Lua core +** ('lua_lock') and leaves the core ('lua_unlock') +*/ +#if !defined(lua_lock) +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) +#endif + +/* +** macro executed during Lua functions at points where the +** function can yield. +*/ +#if !defined(luai_threadyield) +#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} +#endif + + +/* +** these macros allow user-specific actions when a thread is +** created/deleted/resumed/yielded. +*/ +#if !defined(luai_userstateopen) +#define luai_userstateopen(L) ((void)L) +#endif + +#if !defined(luai_userstateclose) +#define luai_userstateclose(L) ((void)L) +#endif + +#if !defined(luai_userstatethread) +#define luai_userstatethread(L,L1) ((void)L) +#endif + +#if !defined(luai_userstatefree) +#define luai_userstatefree(L,L1) ((void)L) +#endif + +#if !defined(luai_userstateresume) +#define luai_userstateresume(L,n) ((void)L) +#endif + +#if !defined(luai_userstateyield) +#define luai_userstateyield(L,n) ((void)L) +#endif + + + +/* +** The luai_num* macros define the primitive operations over numbers. +*/ + +/* floor division (defined as 'floor(a/b)') */ +#if !defined(luai_numidiv) +#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b))) +#endif + +/* float division */ +#if !defined(luai_numdiv) +#define luai_numdiv(L,a,b) ((a)/(b)) +#endif + +/* +** modulo: defined as 'a - floor(a/b)*b'; the direct computation +** using this definition has several problems with rounding errors, +** so it is better to use 'fmod'. 'fmod' gives the result of +** 'a - trunc(a/b)*b', and therefore must be corrected when +** 'trunc(a/b) ~= floor(a/b)'. That happens when the division has a +** non-integer negative result: non-integer result is equivalent to +** a non-zero remainder 'm'; negative result is equivalent to 'a' and +** 'b' with different signs, or 'm' and 'b' with different signs +** (as the result 'm' of 'fmod' has the same sign of 'a'). +*/ +#if !defined(luai_nummod) +#define luai_nummod(L,a,b,m) \ + { (void)L; (m) = l_mathop(fmod)(a,b); \ + if (((m) > 0) ? (b) < 0 : ((m) < 0 && (b) > 0)) (m) += (b); } +#endif + +/* exponentiation */ +#if !defined(luai_numpow) +#define luai_numpow(L,a,b) \ + ((void)L, (b == 2) ? (a)*(a) : l_mathop(pow)(a,b)) +#endif + +/* the others are quite standard operations */ +#if !defined(luai_numadd) +#define luai_numadd(L,a,b) ((a)+(b)) +#define luai_numsub(L,a,b) ((a)-(b)) +#define luai_nummul(L,a,b) ((a)*(b)) +#define luai_numunm(L,a) (-(a)) +#define luai_numeq(a,b) ((a)==(b)) +#define luai_numlt(a,b) ((a)<(b)) +#define luai_numle(a,b) ((a)<=(b)) +#define luai_numgt(a,b) ((a)>(b)) +#define luai_numge(a,b) ((a)>=(b)) +#define luai_numisnan(a) (!luai_numeq((a), (a))) +#endif + + + + + +/* +** macro to control inclusion of some hard tests on stack reallocation +*/ +#if !defined(HARDSTACKTESTS) +#define condmovestack(L,pre,pos) ((void)0) +#else +/* realloc stack keeping its size */ +#define condmovestack(L,pre,pos) \ + { int sz_ = stacksize(L); pre; luaD_reallocstack((L), sz_, 0); pos; } +#endif + +#if !defined(HARDMEMTESTS) +#define condchangemem(L,pre,pos) ((void)0) +#else +#define condchangemem(L,pre,pos) \ + { if (gcrunning(G(L))) { pre; luaC_fullgc(L, 0); pos; } } +#endif + +#endif diff --git a/vendor/lua-src/lua-5.4.6/lmathlib.c b/vendor/lua-src/lua-5.4.6/lmathlib.c new file mode 100644 index 0000000000000..d0b1e1e5d6f57 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lmathlib.c @@ -0,0 +1,764 @@ +/* +** $Id: lmathlib.c $ +** Standard mathematical library +** See Copyright Notice in lua.h +*/ + +#define lmathlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#undef PI +#define PI (l_mathop(3.141592653589793238462643383279502884)) + + +static int math_abs (lua_State *L) { + if (lua_isinteger(L, 1)) { + lua_Integer n = lua_tointeger(L, 1); + if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n); + lua_pushinteger(L, n); + } + else + lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sin (lua_State *L) { + lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_cos (lua_State *L) { + lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tan (lua_State *L) { + lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_asin (lua_State *L) { + lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_acos (lua_State *L) { + lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_atan (lua_State *L) { + lua_Number y = luaL_checknumber(L, 1); + lua_Number x = luaL_optnumber(L, 2, 1); + lua_pushnumber(L, l_mathop(atan2)(y, x)); + return 1; +} + + +static int math_toint (lua_State *L) { + int valid; + lua_Integer n = lua_tointegerx(L, 1, &valid); + if (l_likely(valid)) + lua_pushinteger(L, n); + else { + luaL_checkany(L, 1); + luaL_pushfail(L); /* value is not convertible to integer */ + } + return 1; +} + + +static void pushnumint (lua_State *L, lua_Number d) { + lua_Integer n; + if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */ + lua_pushinteger(L, n); /* result is integer */ + else + lua_pushnumber(L, d); /* result is float */ +} + + +static int math_floor (lua_State *L) { + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own floor */ + else { + lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } + return 1; +} + + +static int math_ceil (lua_State *L) { + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own ceil */ + else { + lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } + return 1; +} + + +static int math_fmod (lua_State *L) { + if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) { + lua_Integer d = lua_tointeger(L, 2); + if ((lua_Unsigned)d + 1u <= 1u) { /* special cases: -1 or 0 */ + luaL_argcheck(L, d != 0, 2, "zero"); + lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */ + } + else + lua_pushinteger(L, lua_tointeger(L, 1) % d); + } + else + lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), + luaL_checknumber(L, 2))); + return 1; +} + + +/* +** next function does not use 'modf', avoiding problems with 'double*' +** (which is not compatible with 'float*') when lua_Number is not +** 'double'. +*/ +static int math_modf (lua_State *L) { + if (lua_isinteger(L ,1)) { + lua_settop(L, 1); /* number is its own integer part */ + lua_pushnumber(L, 0); /* no fractional part */ + } + else { + lua_Number n = luaL_checknumber(L, 1); + /* integer part (rounds toward zero) */ + lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n); + pushnumint(L, ip); + /* fractional part (test needed for inf/-inf) */ + lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip)); + } + return 2; +} + + +static int math_sqrt (lua_State *L) { + lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); + return 1; +} + + +static int math_ult (lua_State *L) { + lua_Integer a = luaL_checkinteger(L, 1); + lua_Integer b = luaL_checkinteger(L, 2); + lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b); + return 1; +} + +static int math_log (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + lua_Number res; + if (lua_isnoneornil(L, 2)) + res = l_mathop(log)(x); + else { + lua_Number base = luaL_checknumber(L, 2); +#if !defined(LUA_USE_C89) + if (base == l_mathop(2.0)) + res = l_mathop(log2)(x); + else +#endif + if (base == l_mathop(10.0)) + res = l_mathop(log10)(x); + else + res = l_mathop(log)(x)/l_mathop(log)(base); + } + lua_pushnumber(L, res); + return 1; +} + +static int math_exp (lua_State *L) { + lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_deg (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI)); + return 1; +} + +static int math_rad (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0))); + return 1; +} + + +static int math_min (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int imin = 1; /* index of current minimum value */ + int i; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) { + if (lua_compare(L, i, imin, LUA_OPLT)) + imin = i; + } + lua_pushvalue(L, imin); + return 1; +} + + +static int math_max (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int imax = 1; /* index of current maximum value */ + int i; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) { + if (lua_compare(L, imax, i, LUA_OPLT)) + imax = i; + } + lua_pushvalue(L, imax); + return 1; +} + + +static int math_type (lua_State *L) { + if (lua_type(L, 1) == LUA_TNUMBER) + lua_pushstring(L, (lua_isinteger(L, 1)) ? "integer" : "float"); + else { + luaL_checkany(L, 1); + luaL_pushfail(L); + } + return 1; +} + + + +/* +** {================================================================== +** Pseudo-Random Number Generator based on 'xoshiro256**'. +** =================================================================== +*/ + +/* number of binary digits in the mantissa of a float */ +#define FIGS l_floatatt(MANT_DIG) + +#if FIGS > 64 +/* there are only 64 random bits; use them all */ +#undef FIGS +#define FIGS 64 +#endif + + +/* +** LUA_RAND32 forces the use of 32-bit integers in the implementation +** of the PRN generator (mainly for testing). +*/ +#if !defined(LUA_RAND32) && !defined(Rand64) + +/* try to find an integer type with at least 64 bits */ + +#if ((ULONG_MAX >> 31) >> 31) >= 3 + +/* 'long' has at least 64 bits */ +#define Rand64 unsigned long + +#elif !defined(LUA_USE_C89) && defined(LLONG_MAX) + +/* there is a 'long long' type (which must have at least 64 bits) */ +#define Rand64 unsigned long long + +#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3 + +/* 'lua_Unsigned' has at least 64 bits */ +#define Rand64 lua_Unsigned + +#endif + +#endif + + +#if defined(Rand64) /* { */ + +/* +** Standard implementation, using 64-bit integers. +** If 'Rand64' has more than 64 bits, the extra bits do not interfere +** with the 64 initial bits, except in a right shift. Moreover, the +** final result has to discard the extra bits. +*/ + +/* avoid using extra bits when needed */ +#define trim64(x) ((x) & 0xffffffffffffffffu) + + +/* rotate left 'x' by 'n' bits */ +static Rand64 rotl (Rand64 x, int n) { + return (x << n) | (trim64(x) >> (64 - n)); +} + +static Rand64 nextrand (Rand64 *state) { + Rand64 state0 = state[0]; + Rand64 state1 = state[1]; + Rand64 state2 = state[2] ^ state0; + Rand64 state3 = state[3] ^ state1; + Rand64 res = rotl(state1 * 5, 7) * 9; + state[0] = state0 ^ state3; + state[1] = state1 ^ state2; + state[2] = state2 ^ (state1 << 17); + state[3] = rotl(state3, 45); + return res; +} + + +/* must take care to not shift stuff by more than 63 slots */ + + +/* +** Convert bits from a random integer into a float in the +** interval [0,1), getting the higher FIG bits from the +** random unsigned integer and converting that to a float. +*/ + +/* must throw out the extra (64 - FIGS) bits */ +#define shift64_FIG (64 - FIGS) + +/* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */ +#define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1))) + +static lua_Number I2d (Rand64 x) { + return (lua_Number)(trim64(x) >> shift64_FIG) * scaleFIG; +} + +/* convert a 'Rand64' to a 'lua_Unsigned' */ +#define I2UInt(x) ((lua_Unsigned)trim64(x)) + +/* convert a 'lua_Unsigned' to a 'Rand64' */ +#define Int2I(x) ((Rand64)(x)) + + +#else /* no 'Rand64' }{ */ + +/* get an integer with at least 32 bits */ +#if LUAI_IS32INT +typedef unsigned int lu_int32; +#else +typedef unsigned long lu_int32; +#endif + + +/* +** Use two 32-bit integers to represent a 64-bit quantity. +*/ +typedef struct Rand64 { + lu_int32 h; /* higher half */ + lu_int32 l; /* lower half */ +} Rand64; + + +/* +** If 'lu_int32' has more than 32 bits, the extra bits do not interfere +** with the 32 initial bits, except in a right shift and comparisons. +** Moreover, the final result has to discard the extra bits. +*/ + +/* avoid using extra bits when needed */ +#define trim32(x) ((x) & 0xffffffffu) + + +/* +** basic operations on 'Rand64' values +*/ + +/* build a new Rand64 value */ +static Rand64 packI (lu_int32 h, lu_int32 l) { + Rand64 result; + result.h = h; + result.l = l; + return result; +} + +/* return i << n */ +static Rand64 Ishl (Rand64 i, int n) { + lua_assert(n > 0 && n < 32); + return packI((i.h << n) | (trim32(i.l) >> (32 - n)), i.l << n); +} + +/* i1 ^= i2 */ +static void Ixor (Rand64 *i1, Rand64 i2) { + i1->h ^= i2.h; + i1->l ^= i2.l; +} + +/* return i1 + i2 */ +static Rand64 Iadd (Rand64 i1, Rand64 i2) { + Rand64 result = packI(i1.h + i2.h, i1.l + i2.l); + if (trim32(result.l) < trim32(i1.l)) /* carry? */ + result.h++; + return result; +} + +/* return i * 5 */ +static Rand64 times5 (Rand64 i) { + return Iadd(Ishl(i, 2), i); /* i * 5 == (i << 2) + i */ +} + +/* return i * 9 */ +static Rand64 times9 (Rand64 i) { + return Iadd(Ishl(i, 3), i); /* i * 9 == (i << 3) + i */ +} + +/* return 'i' rotated left 'n' bits */ +static Rand64 rotl (Rand64 i, int n) { + lua_assert(n > 0 && n < 32); + return packI((i.h << n) | (trim32(i.l) >> (32 - n)), + (trim32(i.h) >> (32 - n)) | (i.l << n)); +} + +/* for offsets larger than 32, rotate right by 64 - offset */ +static Rand64 rotl1 (Rand64 i, int n) { + lua_assert(n > 32 && n < 64); + n = 64 - n; + return packI((trim32(i.h) >> n) | (i.l << (32 - n)), + (i.h << (32 - n)) | (trim32(i.l) >> n)); +} + +/* +** implementation of 'xoshiro256**' algorithm on 'Rand64' values +*/ +static Rand64 nextrand (Rand64 *state) { + Rand64 res = times9(rotl(times5(state[1]), 7)); + Rand64 t = Ishl(state[1], 17); + Ixor(&state[2], state[0]); + Ixor(&state[3], state[1]); + Ixor(&state[1], state[2]); + Ixor(&state[0], state[3]); + Ixor(&state[2], t); + state[3] = rotl1(state[3], 45); + return res; +} + + +/* +** Converts a 'Rand64' into a float. +*/ + +/* an unsigned 1 with proper type */ +#define UONE ((lu_int32)1) + + +#if FIGS <= 32 + +/* 2^(-FIGS) */ +#define scaleFIG (l_mathop(0.5) / (UONE << (FIGS - 1))) + +/* +** get up to 32 bits from higher half, shifting right to +** throw out the extra bits. +*/ +static lua_Number I2d (Rand64 x) { + lua_Number h = (lua_Number)(trim32(x.h) >> (32 - FIGS)); + return h * scaleFIG; +} + +#else /* 32 < FIGS <= 64 */ + +/* must take care to not shift stuff by more than 31 slots */ + +/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */ +#define scaleFIG \ + (l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33))) + +/* +** use FIGS - 32 bits from lower half, throwing out the other +** (32 - (FIGS - 32)) = (64 - FIGS) bits +*/ +#define shiftLOW (64 - FIGS) + +/* +** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32) +*/ +#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * l_mathop(2.0)) + + +static lua_Number I2d (Rand64 x) { + lua_Number h = (lua_Number)trim32(x.h) * shiftHI; + lua_Number l = (lua_Number)(trim32(x.l) >> shiftLOW); + return (h + l) * scaleFIG; +} + +#endif + + +/* convert a 'Rand64' to a 'lua_Unsigned' */ +static lua_Unsigned I2UInt (Rand64 x) { + return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l); +} + +/* convert a 'lua_Unsigned' to a 'Rand64' */ +static Rand64 Int2I (lua_Unsigned n) { + return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n); +} + +#endif /* } */ + + +/* +** A state uses four 'Rand64' values. +*/ +typedef struct { + Rand64 s[4]; +} RanState; + + +/* +** Project the random integer 'ran' into the interval [0, n]. +** Because 'ran' has 2^B possible values, the projection can only be +** uniform when the size of the interval is a power of 2 (exact +** division). Otherwise, to get a uniform projection into [0, n], we +** first compute 'lim', the smallest Mersenne number not smaller than +** 'n'. We then project 'ran' into the interval [0, lim]. If the result +** is inside [0, n], we are done. Otherwise, we try with another 'ran', +** until we have a result inside the interval. +*/ +static lua_Unsigned project (lua_Unsigned ran, lua_Unsigned n, + RanState *state) { + if ((n & (n + 1)) == 0) /* is 'n + 1' a power of 2? */ + return ran & n; /* no bias */ + else { + lua_Unsigned lim = n; + /* compute the smallest (2^b - 1) not smaller than 'n' */ + lim |= (lim >> 1); + lim |= (lim >> 2); + lim |= (lim >> 4); + lim |= (lim >> 8); + lim |= (lim >> 16); +#if (LUA_MAXUNSIGNED >> 31) >= 3 + lim |= (lim >> 32); /* integer type has more than 32 bits */ +#endif + lua_assert((lim & (lim + 1)) == 0 /* 'lim + 1' is a power of 2, */ + && lim >= n /* not smaller than 'n', */ + && (lim >> 1) < n); /* and it is the smallest one */ + while ((ran &= lim) > n) /* project 'ran' into [0..lim] */ + ran = I2UInt(nextrand(state->s)); /* not inside [0..n]? try again */ + return ran; + } +} + + +static int math_random (lua_State *L) { + lua_Integer low, up; + lua_Unsigned p; + RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1)); + Rand64 rv = nextrand(state->s); /* next pseudo-random value */ + switch (lua_gettop(L)) { /* check number of arguments */ + case 0: { /* no arguments */ + lua_pushnumber(L, I2d(rv)); /* float between 0 and 1 */ + return 1; + } + case 1: { /* only upper limit */ + low = 1; + up = luaL_checkinteger(L, 1); + if (up == 0) { /* single 0 as argument? */ + lua_pushinteger(L, I2UInt(rv)); /* full random integer */ + return 1; + } + break; + } + case 2: { /* lower and upper limits */ + low = luaL_checkinteger(L, 1); + up = luaL_checkinteger(L, 2); + break; + } + default: return luaL_error(L, "wrong number of arguments"); + } + /* random integer in the interval [low, up] */ + luaL_argcheck(L, low <= up, 1, "interval is empty"); + /* project random integer into the interval [0, up - low] */ + p = project(I2UInt(rv), (lua_Unsigned)up - (lua_Unsigned)low, state); + lua_pushinteger(L, p + (lua_Unsigned)low); + return 1; +} + + +static void setseed (lua_State *L, Rand64 *state, + lua_Unsigned n1, lua_Unsigned n2) { + int i; + state[0] = Int2I(n1); + state[1] = Int2I(0xff); /* avoid a zero state */ + state[2] = Int2I(n2); + state[3] = Int2I(0); + for (i = 0; i < 16; i++) + nextrand(state); /* discard initial values to "spread" seed */ + lua_pushinteger(L, n1); + lua_pushinteger(L, n2); +} + + +/* +** Set a "random" seed. To get some randomness, use the current time +** and the address of 'L' (in case the machine does address space layout +** randomization). +*/ +static void randseed (lua_State *L, RanState *state) { + lua_Unsigned seed1 = (lua_Unsigned)time(NULL); + lua_Unsigned seed2 = (lua_Unsigned)(size_t)L; + setseed(L, state->s, seed1, seed2); +} + + +static int math_randomseed (lua_State *L) { + RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1)); + if (lua_isnone(L, 1)) { + randseed(L, state); + } + else { + lua_Integer n1 = luaL_checkinteger(L, 1); + lua_Integer n2 = luaL_optinteger(L, 2, 0); + setseed(L, state->s, n1, n2); + } + return 2; /* return seeds */ +} + + +static const luaL_Reg randfuncs[] = { + {"random", math_random}, + {"randomseed", math_randomseed}, + {NULL, NULL} +}; + + +/* +** Register the random functions and initialize their state. +*/ +static void setrandfunc (lua_State *L) { + RanState *state = (RanState *)lua_newuserdatauv(L, sizeof(RanState), 0); + randseed(L, state); /* initialize with a "random" seed */ + lua_pop(L, 2); /* remove pushed seeds */ + luaL_setfuncs(L, randfuncs, 1); +} + +/* }================================================================== */ + + +/* +** {================================================================== +** Deprecated functions (for compatibility only) +** =================================================================== +*/ +#if defined(LUA_COMPAT_MATHLIB) + +static int math_cosh (lua_State *L) { + lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sinh (lua_State *L) { + lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tanh (lua_State *L) { + lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_pow (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + lua_Number y = luaL_checknumber(L, 2); + lua_pushnumber(L, l_mathop(pow)(x, y)); + return 1; +} + +static int math_frexp (lua_State *L) { + int e; + lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); + lua_pushinteger(L, e); + return 2; +} + +static int math_ldexp (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + int ep = (int)luaL_checkinteger(L, 2); + lua_pushnumber(L, l_mathop(ldexp)(x, ep)); + return 1; +} + +static int math_log10 (lua_State *L) { + lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); + return 1; +} + +#endif +/* }================================================================== */ + + + +static const luaL_Reg mathlib[] = { + {"abs", math_abs}, + {"acos", math_acos}, + {"asin", math_asin}, + {"atan", math_atan}, + {"ceil", math_ceil}, + {"cos", math_cos}, + {"deg", math_deg}, + {"exp", math_exp}, + {"tointeger", math_toint}, + {"floor", math_floor}, + {"fmod", math_fmod}, + {"ult", math_ult}, + {"log", math_log}, + {"max", math_max}, + {"min", math_min}, + {"modf", math_modf}, + {"rad", math_rad}, + {"sin", math_sin}, + {"sqrt", math_sqrt}, + {"tan", math_tan}, + {"type", math_type}, +#if defined(LUA_COMPAT_MATHLIB) + {"atan2", math_atan}, + {"cosh", math_cosh}, + {"sinh", math_sinh}, + {"tanh", math_tanh}, + {"pow", math_pow}, + {"frexp", math_frexp}, + {"ldexp", math_ldexp}, + {"log10", math_log10}, +#endif + /* placeholders */ + {"random", NULL}, + {"randomseed", NULL}, + {"pi", NULL}, + {"huge", NULL}, + {"maxinteger", NULL}, + {"mininteger", NULL}, + {NULL, NULL} +}; + + +/* +** Open math library +*/ +LUAMOD_API int luaopen_math (lua_State *L) { + luaL_newlib(L, mathlib); + lua_pushnumber(L, PI); + lua_setfield(L, -2, "pi"); + lua_pushnumber(L, (lua_Number)HUGE_VAL); + lua_setfield(L, -2, "huge"); + lua_pushinteger(L, LUA_MAXINTEGER); + lua_setfield(L, -2, "maxinteger"); + lua_pushinteger(L, LUA_MININTEGER); + lua_setfield(L, -2, "mininteger"); + setrandfunc(L); + return 1; +} + diff --git a/vendor/lua-src/lua-5.4.6/lmem.c b/vendor/lua-src/lua-5.4.6/lmem.c new file mode 100644 index 0000000000000..9800a86fc024f --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lmem.c @@ -0,0 +1,215 @@ +/* +** $Id: lmem.c $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + +#define lmem_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +/* +** About the realloc function: +** void *frealloc (void *ud, void *ptr, size_t osize, size_t nsize); +** ('osize' is the old size, 'nsize' is the new size) +** +** - frealloc(ud, p, x, 0) frees the block 'p' and returns NULL. +** Particularly, frealloc(ud, NULL, 0, 0) does nothing, +** which is equivalent to free(NULL) in ISO C. +** +** - frealloc(ud, NULL, x, s) creates a new block of size 's' +** (no matter 'x'). Returns NULL if it cannot create the new block. +** +** - otherwise, frealloc(ud, b, x, y) reallocates the block 'b' from +** size 'x' to size 'y'. Returns NULL if it cannot reallocate the +** block to the new size. +*/ + + +/* +** Macro to call the allocation function. +*/ +#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns)) + + +/* +** When an allocation fails, it will try again after an emergency +** collection, except when it cannot run a collection. The GC should +** not be called while the state is not fully built, as the collector +** is not yet fully initialized. Also, it should not be called when +** 'gcstopem' is true, because then the interpreter is in the middle of +** a collection step. +*/ +#define cantryagain(g) (completestate(g) && !g->gcstopem) + + + + +#if defined(EMERGENCYGCTESTS) +/* +** First allocation will fail except when freeing a block (frees never +** fail) and when it cannot try again; this fail will trigger 'tryagain' +** and a full GC cycle at every allocation. +*/ +static void *firsttry (global_State *g, void *block, size_t os, size_t ns) { + if (ns > 0 && cantryagain(g)) + return NULL; /* fail */ + else /* normal allocation */ + return callfrealloc(g, block, os, ns); +} +#else +#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns) +#endif + + + + + +/* +** {================================================================== +** Functions to allocate/deallocate arrays for the Parser +** =================================================================== +*/ + +/* +** Minimum size for arrays during parsing, to avoid overhead of +** reallocating to size 1, then 2, and then 4. All these arrays +** will be reallocated to exact sizes or erased when parsing ends. +*/ +#define MINSIZEARRAY 4 + + +void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize, + int size_elems, int limit, const char *what) { + void *newblock; + int size = *psize; + if (nelems + 1 <= size) /* does one extra element still fit? */ + return block; /* nothing to be done */ + if (size >= limit / 2) { /* cannot double it? */ + if (l_unlikely(size >= limit)) /* cannot grow even a little? */ + luaG_runerror(L, "too many %s (limit is %d)", what, limit); + size = limit; /* still have at least one free place */ + } + else { + size *= 2; + if (size < MINSIZEARRAY) + size = MINSIZEARRAY; /* minimum size */ + } + lua_assert(nelems + 1 <= size && size <= limit); + /* 'limit' ensures that multiplication will not overflow */ + newblock = luaM_saferealloc_(L, block, cast_sizet(*psize) * size_elems, + cast_sizet(size) * size_elems); + *psize = size; /* update only when everything else is OK */ + return newblock; +} + + +/* +** In prototypes, the size of the array is also its number of +** elements (to save memory). So, if it cannot shrink an array +** to its number of elements, the only option is to raise an +** error. +*/ +void *luaM_shrinkvector_ (lua_State *L, void *block, int *size, + int final_n, int size_elem) { + void *newblock; + size_t oldsize = cast_sizet((*size) * size_elem); + size_t newsize = cast_sizet(final_n * size_elem); + lua_assert(newsize <= oldsize); + newblock = luaM_saferealloc_(L, block, oldsize, newsize); + *size = final_n; + return newblock; +} + +/* }================================================================== */ + + +l_noret luaM_toobig (lua_State *L) { + luaG_runerror(L, "memory allocation error: block too big"); +} + + +/* +** Free memory +*/ +void luaM_free_ (lua_State *L, void *block, size_t osize) { + global_State *g = G(L); + lua_assert((osize == 0) == (block == NULL)); + callfrealloc(g, block, osize, 0); + g->GCdebt -= osize; +} + + +/* +** In case of allocation fail, this function will do an emergency +** collection to free some memory and then try the allocation again. +*/ +static void *tryagain (lua_State *L, void *block, + size_t osize, size_t nsize) { + global_State *g = G(L); + if (cantryagain(g)) { + luaC_fullgc(L, 1); /* try to free some memory... */ + return callfrealloc(g, block, osize, nsize); /* try again */ + } + else return NULL; /* cannot run an emergency collection */ +} + + +/* +** Generic allocation routine. +*/ +void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { + void *newblock; + global_State *g = G(L); + lua_assert((osize == 0) == (block == NULL)); + newblock = firsttry(g, block, osize, nsize); + if (l_unlikely(newblock == NULL && nsize > 0)) { + newblock = tryagain(L, block, osize, nsize); + if (newblock == NULL) /* still no memory? */ + return NULL; /* do not update 'GCdebt' */ + } + lua_assert((nsize == 0) == (newblock == NULL)); + g->GCdebt = (g->GCdebt + nsize) - osize; + return newblock; +} + + +void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize, + size_t nsize) { + void *newblock = luaM_realloc_(L, block, osize, nsize); + if (l_unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */ + luaM_error(L); + return newblock; +} + + +void *luaM_malloc_ (lua_State *L, size_t size, int tag) { + if (size == 0) + return NULL; /* that's all */ + else { + global_State *g = G(L); + void *newblock = firsttry(g, NULL, tag, size); + if (l_unlikely(newblock == NULL)) { + newblock = tryagain(L, NULL, tag, size); + if (newblock == NULL) + luaM_error(L); + } + g->GCdebt += size; + return newblock; + } +} diff --git a/vendor/lua-src/lua-5.4.6/lmem.h b/vendor/lua-src/lua-5.4.6/lmem.h new file mode 100644 index 0000000000000..8c75a44beb475 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lmem.h @@ -0,0 +1,93 @@ +/* +** $Id: lmem.h $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + +#ifndef lmem_h +#define lmem_h + + +#include + +#include "llimits.h" +#include "lua.h" + + +#define luaM_error(L) luaD_throw(L, LUA_ERRMEM) + + +/* +** This macro tests whether it is safe to multiply 'n' by the size of +** type 't' without overflows. Because 'e' is always constant, it avoids +** the runtime division MAX_SIZET/(e). +** (The macro is somewhat complex to avoid warnings: The 'sizeof' +** comparison avoids a runtime comparison when overflow cannot occur. +** The compiler should be able to optimize the real test by itself, but +** when it does it, it may give a warning about "comparison is always +** false due to limited range of data type"; the +1 tricks the compiler, +** avoiding this warning but also this optimization.) +*/ +#define luaM_testsize(n,e) \ + (sizeof(n) >= sizeof(size_t) && cast_sizet((n)) + 1 > MAX_SIZET/(e)) + +#define luaM_checksize(L,n,e) \ + (luaM_testsize(n,e) ? luaM_toobig(L) : cast_void(0)) + + +/* +** Computes the minimum between 'n' and 'MAX_SIZET/sizeof(t)', so that +** the result is not larger than 'n' and cannot overflow a 'size_t' +** when multiplied by the size of type 't'. (Assumes that 'n' is an +** 'int' or 'unsigned int' and that 'int' is not larger than 'size_t'.) +*/ +#define luaM_limitN(n,t) \ + ((cast_sizet(n) <= MAX_SIZET/sizeof(t)) ? (n) : \ + cast_uint((MAX_SIZET/sizeof(t)))) + + +/* +** Arrays of chars do not need any test +*/ +#define luaM_reallocvchar(L,b,on,n) \ + cast_charp(luaM_saferealloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) + +#define luaM_freemem(L, b, s) luaM_free_(L, (b), (s)) +#define luaM_free(L, b) luaM_free_(L, (b), sizeof(*(b))) +#define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b))) + +#define luaM_new(L,t) cast(t*, luaM_malloc_(L, sizeof(t), 0)) +#define luaM_newvector(L,n,t) cast(t*, luaM_malloc_(L, (n)*sizeof(t), 0)) +#define luaM_newvectorchecked(L,n,t) \ + (luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t)) + +#define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag) + +#define luaM_growvector(L,v,nelems,size,t,limit,e) \ + ((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \ + luaM_limitN(limit,t),e))) + +#define luaM_reallocvector(L, v,oldn,n,t) \ + (cast(t *, luaM_realloc_(L, v, cast_sizet(oldn) * sizeof(t), \ + cast_sizet(n) * sizeof(t)))) + +#define luaM_shrinkvector(L,v,size,fs,t) \ + ((v)=cast(t *, luaM_shrinkvector_(L, v, &(size), fs, sizeof(t)))) + +LUAI_FUNC l_noret luaM_toobig (lua_State *L); + +/* not to be called directly */ +LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, + size_t size); +LUAI_FUNC void *luaM_saferealloc_ (lua_State *L, void *block, size_t oldsize, + size_t size); +LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize); +LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems, + int *size, int size_elem, int limit, + const char *what); +LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem, + int final_n, int size_elem); +LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag); + +#endif + diff --git a/vendor/lua-src/lua-5.4.6/loadlib.c b/vendor/lua-src/lua-5.4.6/loadlib.c new file mode 100644 index 0000000000000..d792dffaa03b0 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/loadlib.c @@ -0,0 +1,767 @@ +/* +** $Id: loadlib.c $ +** Dynamic library loader for Lua +** See Copyright Notice in lua.h +** +** This module contains an implementation of loadlib for Unix systems +** that have dlfcn, an implementation for Windows, and a stub for other +** systems. +*/ + +#define loadlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** LUA_IGMARK is a mark to ignore all before it when building the +** luaopen_ function name. +*/ +#if !defined (LUA_IGMARK) +#define LUA_IGMARK "-" +#endif + + +/* +** LUA_CSUBSEP is the character that replaces dots in submodule names +** when searching for a C loader. +** LUA_LSUBSEP is the character that replaces dots in submodule names +** when searching for a Lua loader. +*/ +#if !defined(LUA_CSUBSEP) +#define LUA_CSUBSEP LUA_DIRSEP +#endif + +#if !defined(LUA_LSUBSEP) +#define LUA_LSUBSEP LUA_DIRSEP +#endif + + +/* prefix for open functions in C libraries */ +#define LUA_POF "luaopen_" + +/* separator for open functions in C libraries */ +#define LUA_OFSEP "_" + + +/* +** key for table in the registry that keeps handles +** for all loaded C libraries +*/ +static const char *const CLIBS = "_CLIBS"; + +#define LIB_FAIL "open" + + +#define setprogdir(L) ((void)0) + + +/* +** Special type equivalent to '(void*)' for functions in gcc +** (to suppress warnings when converting function pointers) +*/ +typedef void (*voidf)(void); + + +/* +** system-dependent functions +*/ + +/* +** unload library 'lib' +*/ +static void lsys_unloadlib (void *lib); + +/* +** load C library in file 'path'. If 'seeglb', load with all names in +** the library global. +** Returns the library; in case of error, returns NULL plus an +** error string in the stack. +*/ +static void *lsys_load (lua_State *L, const char *path, int seeglb); + +/* +** Try to find a function named 'sym' in library 'lib'. +** Returns the function; in case of error, returns NULL plus an +** error string in the stack. +*/ +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym); + + + + +#if defined(LUA_USE_DLOPEN) /* { */ +/* +** {======================================================================== +** This is an implementation of loadlib based on the dlfcn interface. +** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, +** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least +** as an emulation layer on top of native functions. +** ========================================================================= +*/ + +#include + +/* +** Macro to convert pointer-to-void* to pointer-to-function. This cast +** is undefined according to ISO C, but POSIX assumes that it works. +** (The '__extension__' in gnu compilers is only to avoid warnings.) +*/ +#if defined(__GNUC__) +#define cast_func(p) (__extension__ (lua_CFunction)(p)) +#else +#define cast_func(p) ((lua_CFunction)(p)) +#endif + + +static void lsys_unloadlib (void *lib) { + dlclose(lib); +} + + +static void *lsys_load (lua_State *L, const char *path, int seeglb) { + void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); + if (l_unlikely(lib == NULL)) + lua_pushstring(L, dlerror()); + return lib; +} + + +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = cast_func(dlsym(lib, sym)); + if (l_unlikely(f == NULL)) + lua_pushstring(L, dlerror()); + return f; +} + +/* }====================================================== */ + + + +#elif defined(LUA_DL_DLL) /* }{ */ +/* +** {====================================================================== +** This is an implementation of loadlib for Windows using native functions. +** ======================================================================= +*/ + +#include + + +/* +** optional flags for LoadLibraryEx +*/ +#if !defined(LUA_LLE_FLAGS) +#define LUA_LLE_FLAGS 0 +#endif + + +#undef setprogdir + + +/* +** Replace in the path (on the top of the stack) any occurrence +** of LUA_EXEC_DIR with the executable's path. +*/ +static void setprogdir (lua_State *L) { + char buff[MAX_PATH + 1]; + char *lb; + DWORD nsize = sizeof(buff)/sizeof(char); + DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */ + if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) + luaL_error(L, "unable to get ModuleFileName"); + else { + *lb = '\0'; /* cut name on the last '\\' to get the path */ + luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); + lua_remove(L, -2); /* remove original string */ + } +} + + + + +static void pusherror (lua_State *L) { + int error = GetLastError(); + char buffer[128]; + if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL)) + lua_pushstring(L, buffer); + else + lua_pushfstring(L, "system error %d\n", error); +} + +static void lsys_unloadlib (void *lib) { + FreeLibrary((HMODULE)lib); +} + + +static void *lsys_load (lua_State *L, const char *path, int seeglb) { + HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); + (void)(seeglb); /* not used: symbols are 'global' by default */ + if (lib == NULL) pusherror(L); + return lib; +} + + +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = (lua_CFunction)(voidf)GetProcAddress((HMODULE)lib, sym); + if (f == NULL) pusherror(L); + return f; +} + +/* }====================================================== */ + + +#else /* }{ */ +/* +** {====================================================== +** Fallback for other systems +** ======================================================= +*/ + +#undef LIB_FAIL +#define LIB_FAIL "absent" + + +#define DLMSG "dynamic libraries not enabled; check your Lua installation" + + +static void lsys_unloadlib (void *lib) { + (void)(lib); /* not used */ +} + + +static void *lsys_load (lua_State *L, const char *path, int seeglb) { + (void)(path); (void)(seeglb); /* not used */ + lua_pushliteral(L, DLMSG); + return NULL; +} + + +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + (void)(lib); (void)(sym); /* not used */ + lua_pushliteral(L, DLMSG); + return NULL; +} + +/* }====================================================== */ +#endif /* } */ + + +/* +** {================================================================== +** Set Paths +** =================================================================== +*/ + +/* +** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment +** variables that Lua check to set its paths. +*/ +#if !defined(LUA_PATH_VAR) +#define LUA_PATH_VAR "LUA_PATH" +#endif + +#if !defined(LUA_CPATH_VAR) +#define LUA_CPATH_VAR "LUA_CPATH" +#endif + + + +/* +** return registry.LUA_NOENV as a boolean +*/ +static int noenv (lua_State *L) { + int b; + lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); + b = lua_toboolean(L, -1); + lua_pop(L, 1); /* remove value */ + return b; +} + + +/* +** Set a path +*/ +static void setpath (lua_State *L, const char *fieldname, + const char *envname, + const char *dft) { + const char *dftmark; + const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX); + const char *path = getenv(nver); /* try versioned name */ + if (path == NULL) /* no versioned environment variable? */ + path = getenv(envname); /* try unversioned name */ + if (path == NULL || noenv(L)) /* no environment variable? */ + lua_pushstring(L, dft); /* use default */ + else if ((dftmark = strstr(path, LUA_PATH_SEP LUA_PATH_SEP)) == NULL) + lua_pushstring(L, path); /* nothing to change */ + else { /* path contains a ";;": insert default path in its place */ + size_t len = strlen(path); + luaL_Buffer b; + luaL_buffinit(L, &b); + if (path < dftmark) { /* is there a prefix before ';;'? */ + luaL_addlstring(&b, path, dftmark - path); /* add it */ + luaL_addchar(&b, *LUA_PATH_SEP); + } + luaL_addstring(&b, dft); /* add default */ + if (dftmark < path + len - 2) { /* is there a suffix after ';;'? */ + luaL_addchar(&b, *LUA_PATH_SEP); + luaL_addlstring(&b, dftmark + 2, (path + len - 2) - dftmark); + } + luaL_pushresult(&b); + } + setprogdir(L); + lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */ + lua_pop(L, 1); /* pop versioned variable name ('nver') */ +} + +/* }================================================================== */ + + +/* +** return registry.CLIBS[path] +*/ +static void *checkclib (lua_State *L, const char *path) { + void *plib; + lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); + lua_getfield(L, -1, path); + plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ + lua_pop(L, 2); /* pop CLIBS table and 'plib' */ + return plib; +} + + +/* +** registry.CLIBS[path] = plib -- for queries +** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries +*/ +static void addtoclib (lua_State *L, const char *path, void *plib) { + lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); + lua_pushlightuserdata(L, plib); + lua_pushvalue(L, -1); + lua_setfield(L, -3, path); /* CLIBS[path] = plib */ + lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ + lua_pop(L, 1); /* pop CLIBS table */ +} + + +/* +** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib +** handles in list CLIBS +*/ +static int gctm (lua_State *L) { + lua_Integer n = luaL_len(L, 1); + for (; n >= 1; n--) { /* for each handle, in reverse order */ + lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ + lsys_unloadlib(lua_touserdata(L, -1)); + lua_pop(L, 1); /* pop handle */ + } + return 0; +} + + + +/* error codes for 'lookforfunc' */ +#define ERRLIB 1 +#define ERRFUNC 2 + +/* +** Look for a C function named 'sym' in a dynamically loaded library +** 'path'. +** First, check whether the library is already loaded; if not, try +** to load it. +** Then, if 'sym' is '*', return true (as library has been loaded). +** Otherwise, look for symbol 'sym' in the library and push a +** C function with that symbol. +** Return 0 and 'true' or a function in the stack; in case of +** errors, return an error code and an error message in the stack. +*/ +static int lookforfunc (lua_State *L, const char *path, const char *sym) { + void *reg = checkclib(L, path); /* check loaded C libraries */ + if (reg == NULL) { /* must load library? */ + reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ + if (reg == NULL) return ERRLIB; /* unable to load library */ + addtoclib(L, path, reg); + } + if (*sym == '*') { /* loading only library (no function)? */ + lua_pushboolean(L, 1); /* return 'true' */ + return 0; /* no errors */ + } + else { + lua_CFunction f = lsys_sym(L, reg, sym); + if (f == NULL) + return ERRFUNC; /* unable to find function */ + lua_pushcfunction(L, f); /* else create new function */ + return 0; /* no errors */ + } +} + + +static int ll_loadlib (lua_State *L) { + const char *path = luaL_checkstring(L, 1); + const char *init = luaL_checkstring(L, 2); + int stat = lookforfunc(L, path, init); + if (l_likely(stat == 0)) /* no errors? */ + return 1; /* return the loaded function */ + else { /* error; error message is on stack top */ + luaL_pushfail(L); + lua_insert(L, -2); + lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); + return 3; /* return fail, error message, and where */ + } +} + + + +/* +** {====================================================== +** 'require' function +** ======================================================= +*/ + + +static int readable (const char *filename) { + FILE *f = fopen(filename, "r"); /* try to open file */ + if (f == NULL) return 0; /* open failed */ + fclose(f); + return 1; +} + + +/* +** Get the next name in '*path' = 'name1;name2;name3;...', changing +** the ending ';' to '\0' to create a zero-terminated string. Return +** NULL when list ends. +*/ +static const char *getnextfilename (char **path, char *end) { + char *sep; + char *name = *path; + if (name == end) + return NULL; /* no more names */ + else if (*name == '\0') { /* from previous iteration? */ + *name = *LUA_PATH_SEP; /* restore separator */ + name++; /* skip it */ + } + sep = strchr(name, *LUA_PATH_SEP); /* find next separator */ + if (sep == NULL) /* separator not found? */ + sep = end; /* name goes until the end */ + *sep = '\0'; /* finish file name */ + *path = sep; /* will start next search from here */ + return name; +} + + +/* +** Given a path such as ";blabla.so;blublu.so", pushes the string +** +** no file 'blabla.so' +** no file 'blublu.so' +*/ +static void pusherrornotfound (lua_State *L, const char *path) { + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addstring(&b, "no file '"); + luaL_addgsub(&b, path, LUA_PATH_SEP, "'\n\tno file '"); + luaL_addstring(&b, "'"); + luaL_pushresult(&b); +} + + +static const char *searchpath (lua_State *L, const char *name, + const char *path, + const char *sep, + const char *dirsep) { + luaL_Buffer buff; + char *pathname; /* path with name inserted */ + char *endpathname; /* its end */ + const char *filename; + /* separator is non-empty and appears in 'name'? */ + if (*sep != '\0' && strchr(name, *sep) != NULL) + name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ + luaL_buffinit(L, &buff); + /* add path to the buffer, replacing marks ('?') with the file name */ + luaL_addgsub(&buff, path, LUA_PATH_MARK, name); + luaL_addchar(&buff, '\0'); + pathname = luaL_buffaddr(&buff); /* writable list of file names */ + endpathname = pathname + luaL_bufflen(&buff) - 1; + while ((filename = getnextfilename(&pathname, endpathname)) != NULL) { + if (readable(filename)) /* does file exist and is readable? */ + return lua_pushstring(L, filename); /* save and return name */ + } + luaL_pushresult(&buff); /* push path to create error message */ + pusherrornotfound(L, lua_tostring(L, -1)); /* create error message */ + return NULL; /* not found */ +} + + +static int ll_searchpath (lua_State *L) { + const char *f = searchpath(L, luaL_checkstring(L, 1), + luaL_checkstring(L, 2), + luaL_optstring(L, 3, "."), + luaL_optstring(L, 4, LUA_DIRSEP)); + if (f != NULL) return 1; + else { /* error message is on top of the stack */ + luaL_pushfail(L); + lua_insert(L, -2); + return 2; /* return fail + error message */ + } +} + + +static const char *findfile (lua_State *L, const char *name, + const char *pname, + const char *dirsep) { + const char *path; + lua_getfield(L, lua_upvalueindex(1), pname); + path = lua_tostring(L, -1); + if (l_unlikely(path == NULL)) + luaL_error(L, "'package.%s' must be a string", pname); + return searchpath(L, name, path, ".", dirsep); +} + + +static int checkload (lua_State *L, int stat, const char *filename) { + if (l_likely(stat)) { /* module loaded successfully? */ + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; /* return open function and file name */ + } + else + return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", + lua_tostring(L, 1), filename, lua_tostring(L, -1)); +} + + +static int searcher_Lua (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + filename = findfile(L, name, "path", LUA_LSUBSEP); + if (filename == NULL) return 1; /* module not found in this path */ + return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); +} + + +/* +** Try to find a load function for module 'modname' at file 'filename'. +** First, change '.' to '_' in 'modname'; then, if 'modname' has +** the form X-Y (that is, it has an "ignore mark"), build a function +** name "luaopen_X" and look for it. (For compatibility, if that +** fails, it also tries "luaopen_Y".) If there is no ignore mark, +** look for a function named "luaopen_modname". +*/ +static int loadfunc (lua_State *L, const char *filename, const char *modname) { + const char *openfunc; + const char *mark; + modname = luaL_gsub(L, modname, ".", LUA_OFSEP); + mark = strchr(modname, *LUA_IGMARK); + if (mark) { + int stat; + openfunc = lua_pushlstring(L, modname, mark - modname); + openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); + stat = lookforfunc(L, filename, openfunc); + if (stat != ERRFUNC) return stat; + modname = mark + 1; /* else go ahead and try old-style name */ + } + openfunc = lua_pushfstring(L, LUA_POF"%s", modname); + return lookforfunc(L, filename, openfunc); +} + + +static int searcher_C (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP); + if (filename == NULL) return 1; /* module not found in this path */ + return checkload(L, (loadfunc(L, filename, name) == 0), filename); +} + + +static int searcher_Croot (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + const char *p = strchr(name, '.'); + int stat; + if (p == NULL) return 0; /* is root */ + lua_pushlstring(L, name, p - name); + filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); + if (filename == NULL) return 1; /* root not found */ + if ((stat = loadfunc(L, filename, name)) != 0) { + if (stat != ERRFUNC) + return checkload(L, 0, filename); /* real error */ + else { /* open function not found */ + lua_pushfstring(L, "no module '%s' in file '%s'", name, filename); + return 1; + } + } + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; +} + + +static int searcher_preload (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + if (lua_getfield(L, -1, name) == LUA_TNIL) { /* not found? */ + lua_pushfstring(L, "no field package.preload['%s']", name); + return 1; + } + else { + lua_pushliteral(L, ":preload:"); + return 2; + } +} + + +static void findloader (lua_State *L, const char *name) { + int i; + luaL_Buffer msg; /* to build error message */ + /* push 'package.searchers' to index 3 in the stack */ + if (l_unlikely(lua_getfield(L, lua_upvalueindex(1), "searchers") + != LUA_TTABLE)) + luaL_error(L, "'package.searchers' must be a table"); + luaL_buffinit(L, &msg); + /* iterate over available searchers to find a loader */ + for (i = 1; ; i++) { + luaL_addstring(&msg, "\n\t"); /* error-message prefix */ + if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */ + lua_pop(L, 1); /* remove nil */ + luaL_buffsub(&msg, 2); /* remove prefix */ + luaL_pushresult(&msg); /* create error message */ + luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); + } + lua_pushstring(L, name); + lua_call(L, 1, 2); /* call it */ + if (lua_isfunction(L, -2)) /* did it find a loader? */ + return; /* module loader found */ + else if (lua_isstring(L, -2)) { /* searcher returned error message? */ + lua_pop(L, 1); /* remove extra return */ + luaL_addvalue(&msg); /* concatenate error message */ + } + else { /* no error message */ + lua_pop(L, 2); /* remove both returns */ + luaL_buffsub(&msg, 2); /* remove prefix */ + } + } +} + + +static int ll_require (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_settop(L, 1); /* LOADED table will be at index 2 */ + lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_getfield(L, 2, name); /* LOADED[name] */ + if (lua_toboolean(L, -1)) /* is it there? */ + return 1; /* package is already loaded */ + /* else must load package */ + lua_pop(L, 1); /* remove 'getfield' result */ + findloader(L, name); + lua_rotate(L, -2, 1); /* function <-> loader data */ + lua_pushvalue(L, 1); /* name is 1st argument to module loader */ + lua_pushvalue(L, -3); /* loader data is 2nd argument */ + /* stack: ...; loader data; loader function; mod. name; loader data */ + lua_call(L, 2, 1); /* run loader to load module */ + /* stack: ...; loader data; result from loader */ + if (!lua_isnil(L, -1)) /* non-nil return? */ + lua_setfield(L, 2, name); /* LOADED[name] = returned value */ + else + lua_pop(L, 1); /* pop nil */ + if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ + lua_pushboolean(L, 1); /* use true as result */ + lua_copy(L, -1, -2); /* replace loader result */ + lua_setfield(L, 2, name); /* LOADED[name] = true */ + } + lua_rotate(L, -2, 1); /* loader data <-> module result */ + return 2; /* return module result and loader data */ +} + +/* }====================================================== */ + + + + +static const luaL_Reg pk_funcs[] = { + {"loadlib", ll_loadlib}, + {"searchpath", ll_searchpath}, + /* placeholders */ + {"preload", NULL}, + {"cpath", NULL}, + {"path", NULL}, + {"searchers", NULL}, + {"loaded", NULL}, + {NULL, NULL} +}; + + +static const luaL_Reg ll_funcs[] = { + {"require", ll_require}, + {NULL, NULL} +}; + + +static void createsearcherstable (lua_State *L) { + static const lua_CFunction searchers[] = { + searcher_preload, + searcher_Lua, + searcher_C, + searcher_Croot, + NULL + }; + int i; + /* create 'searchers' table */ + lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); + /* fill it with predefined searchers */ + for (i=0; searchers[i] != NULL; i++) { + lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ + lua_pushcclosure(L, searchers[i], 1); + lua_rawseti(L, -2, i+1); + } + lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ +} + + +/* +** create table CLIBS to keep track of loaded C libraries, +** setting a finalizer to close all libraries when closing state. +*/ +static void createclibstable (lua_State *L) { + luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */ + lua_createtable(L, 0, 1); /* create metatable for CLIBS */ + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ + lua_setmetatable(L, -2); +} + + +LUAMOD_API int luaopen_package (lua_State *L) { + createclibstable(L); + luaL_newlib(L, pk_funcs); /* create 'package' table */ + createsearcherstable(L); + /* set paths */ + setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); + setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); + /* store config information */ + lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" + LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); + lua_setfield(L, -2, "config"); + /* set field 'loaded' */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_setfield(L, -2, "loaded"); + /* set field 'preload' */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + lua_setfield(L, -2, "preload"); + lua_pushglobaltable(L); + lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ + luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ + lua_pop(L, 1); /* pop global table */ + return 1; /* return 'package' table */ +} + diff --git a/vendor/lua-src/lua-5.4.6/lobject.c b/vendor/lua-src/lua-5.4.6/lobject.c new file mode 100644 index 0000000000000..f73ffc6d92bd5 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lobject.c @@ -0,0 +1,602 @@ +/* +** $Id: lobject.c $ +** Some generic functions over Lua objects +** See Copyright Notice in lua.h +*/ + +#define lobject_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lctype.h" +#include "ldebug.h" +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "lvm.h" + + +/* +** Computes ceil(log2(x)) +*/ +int luaO_ceillog2 (unsigned int x) { + static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */ + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + }; + int l = 0; + x--; + while (x >= 256) { l += 8; x >>= 8; } + return l + log_2[x]; +} + + +static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, + lua_Integer v2) { + switch (op) { + case LUA_OPADD: return intop(+, v1, v2); + case LUA_OPSUB:return intop(-, v1, v2); + case LUA_OPMUL:return intop(*, v1, v2); + case LUA_OPMOD: return luaV_mod(L, v1, v2); + case LUA_OPIDIV: return luaV_idiv(L, v1, v2); + case LUA_OPBAND: return intop(&, v1, v2); + case LUA_OPBOR: return intop(|, v1, v2); + case LUA_OPBXOR: return intop(^, v1, v2); + case LUA_OPSHL: return luaV_shiftl(v1, v2); + case LUA_OPSHR: return luaV_shiftr(v1, v2); + case LUA_OPUNM: return intop(-, 0, v1); + case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); + default: lua_assert(0); return 0; + } +} + + +static lua_Number numarith (lua_State *L, int op, lua_Number v1, + lua_Number v2) { + switch (op) { + case LUA_OPADD: return luai_numadd(L, v1, v2); + case LUA_OPSUB: return luai_numsub(L, v1, v2); + case LUA_OPMUL: return luai_nummul(L, v1, v2); + case LUA_OPDIV: return luai_numdiv(L, v1, v2); + case LUA_OPPOW: return luai_numpow(L, v1, v2); + case LUA_OPIDIV: return luai_numidiv(L, v1, v2); + case LUA_OPUNM: return luai_numunm(L, v1); + case LUA_OPMOD: return luaV_modf(L, v1, v2); + default: lua_assert(0); return 0; + } +} + + +int luaO_rawarith (lua_State *L, int op, const TValue *p1, const TValue *p2, + TValue *res) { + switch (op) { + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: + case LUA_OPBNOT: { /* operate only on integers */ + lua_Integer i1; lua_Integer i2; + if (tointegerns(p1, &i1) && tointegerns(p2, &i2)) { + setivalue(res, intarith(L, op, i1, i2)); + return 1; + } + else return 0; /* fail */ + } + case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */ + lua_Number n1; lua_Number n2; + if (tonumberns(p1, n1) && tonumberns(p2, n2)) { + setfltvalue(res, numarith(L, op, n1, n2)); + return 1; + } + else return 0; /* fail */ + } + default: { /* other operations */ + lua_Number n1; lua_Number n2; + if (ttisinteger(p1) && ttisinteger(p2)) { + setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); + return 1; + } + else if (tonumberns(p1, n1) && tonumberns(p2, n2)) { + setfltvalue(res, numarith(L, op, n1, n2)); + return 1; + } + else return 0; /* fail */ + } + } +} + + +void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, + StkId res) { + if (!luaO_rawarith(L, op, p1, p2, s2v(res))) { + /* could not perform raw operation; try metamethod */ + luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD)); + } +} + + +int luaO_hexavalue (int c) { + if (lisdigit(c)) return c - '0'; + else return (ltolower(c) - 'a') + 10; +} + + +static int isneg (const char **s) { + if (**s == '-') { (*s)++; return 1; } + else if (**s == '+') (*s)++; + return 0; +} + + + +/* +** {================================================================== +** Lua's implementation for 'lua_strx2number' +** =================================================================== +*/ + +#if !defined(lua_strx2number) + +/* maximum number of significant digits to read (to avoid overflows + even with single floats) */ +#define MAXSIGDIG 30 + +/* +** convert a hexadecimal numeric string to a number, following +** C99 specification for 'strtod' +*/ +static lua_Number lua_strx2number (const char *s, char **endptr) { + int dot = lua_getlocaledecpoint(); + lua_Number r = l_mathop(0.0); /* result (accumulator) */ + int sigdig = 0; /* number of significant digits */ + int nosigdig = 0; /* number of non-significant digits */ + int e = 0; /* exponent correction */ + int neg; /* 1 if number is negative */ + int hasdot = 0; /* true after seen a dot */ + *endptr = cast_charp(s); /* nothing is valid yet */ + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); /* check sign */ + if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ + return l_mathop(0.0); /* invalid format (no '0x') */ + for (s += 2; ; s++) { /* skip '0x' and read numeral */ + if (*s == dot) { + if (hasdot) break; /* second dot? stop loop */ + else hasdot = 1; + } + else if (lisxdigit(cast_uchar(*s))) { + if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ + nosigdig++; + else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ + r = (r * l_mathop(16.0)) + luaO_hexavalue(*s); + else e++; /* too many digits; ignore, but still count for exponent */ + if (hasdot) e--; /* decimal digit? correct exponent */ + } + else break; /* neither a dot nor a digit */ + } + if (nosigdig + sigdig == 0) /* no digits? */ + return l_mathop(0.0); /* invalid format */ + *endptr = cast_charp(s); /* valid up to here */ + e *= 4; /* each digit multiplies/divides value by 2^4 */ + if (*s == 'p' || *s == 'P') { /* exponent part? */ + int exp1 = 0; /* exponent value */ + int neg1; /* exponent sign */ + s++; /* skip 'p' */ + neg1 = isneg(&s); /* sign */ + if (!lisdigit(cast_uchar(*s))) + return l_mathop(0.0); /* invalid; must have at least one digit */ + while (lisdigit(cast_uchar(*s))) /* read exponent */ + exp1 = exp1 * 10 + *(s++) - '0'; + if (neg1) exp1 = -exp1; + e += exp1; + *endptr = cast_charp(s); /* valid up to here */ + } + if (neg) r = -r; + return l_mathop(ldexp)(r, e); +} + +#endif +/* }====================================================== */ + + +/* maximum length of a numeral to be converted to a number */ +#if !defined (L_MAXLENNUM) +#define L_MAXLENNUM 200 +#endif + +/* +** Convert string 's' to a Lua number (put in 'result'). Return NULL on +** fail or the address of the ending '\0' on success. ('mode' == 'x') +** means a hexadecimal numeral. +*/ +static const char *l_str2dloc (const char *s, lua_Number *result, int mode) { + char *endptr; + *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */ + : lua_str2number(s, &endptr); + if (endptr == s) return NULL; /* nothing recognized? */ + while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */ + return (*endptr == '\0') ? endptr : NULL; /* OK iff no trailing chars */ +} + + +/* +** Convert string 's' to a Lua number (put in 'result') handling the +** current locale. +** This function accepts both the current locale or a dot as the radix +** mark. If the conversion fails, it may mean number has a dot but +** locale accepts something else. In that case, the code copies 's' +** to a buffer (because 's' is read-only), changes the dot to the +** current locale radix mark, and tries to convert again. +** The variable 'mode' checks for special characters in the string: +** - 'n' means 'inf' or 'nan' (which should be rejected) +** - 'x' means a hexadecimal numeral +** - '.' just optimizes the search for the common case (no special chars) +*/ +static const char *l_str2d (const char *s, lua_Number *result) { + const char *endptr; + const char *pmode = strpbrk(s, ".xXnN"); /* look for special chars */ + int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0; + if (mode == 'n') /* reject 'inf' and 'nan' */ + return NULL; + endptr = l_str2dloc(s, result, mode); /* try to convert */ + if (endptr == NULL) { /* failed? may be a different locale */ + char buff[L_MAXLENNUM + 1]; + const char *pdot = strchr(s, '.'); + if (pdot == NULL || strlen(s) > L_MAXLENNUM) + return NULL; /* string too long or no dot; fail */ + strcpy(buff, s); /* copy string to buffer */ + buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */ + endptr = l_str2dloc(buff, result, mode); /* try again */ + if (endptr != NULL) + endptr = s + (endptr - buff); /* make relative to 's' */ + } + return endptr; +} + + +#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10) +#define MAXLASTD cast_int(LUA_MAXINTEGER % 10) + +static const char *l_str2int (const char *s, lua_Integer *result) { + lua_Unsigned a = 0; + int empty = 1; + int neg; + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); + if (s[0] == '0' && + (s[1] == 'x' || s[1] == 'X')) { /* hex? */ + s += 2; /* skip '0x' */ + for (; lisxdigit(cast_uchar(*s)); s++) { + a = a * 16 + luaO_hexavalue(*s); + empty = 0; + } + } + else { /* decimal */ + for (; lisdigit(cast_uchar(*s)); s++) { + int d = *s - '0'; + if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */ + return NULL; /* do not accept it (as integer) */ + a = a * 10 + d; + empty = 0; + } + } + while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */ + if (empty || *s != '\0') return NULL; /* something wrong in the numeral */ + else { + *result = l_castU2S((neg) ? 0u - a : a); + return s; + } +} + + +size_t luaO_str2num (const char *s, TValue *o) { + lua_Integer i; lua_Number n; + const char *e; + if ((e = l_str2int(s, &i)) != NULL) { /* try as an integer */ + setivalue(o, i); + } + else if ((e = l_str2d(s, &n)) != NULL) { /* else try as a float */ + setfltvalue(o, n); + } + else + return 0; /* conversion failed */ + return (e - s) + 1; /* success; return string size */ +} + + +int luaO_utf8esc (char *buff, unsigned long x) { + int n = 1; /* number of bytes put in buffer (backwards) */ + lua_assert(x <= 0x7FFFFFFFu); + if (x < 0x80) /* ascii? */ + buff[UTF8BUFFSZ - 1] = cast_char(x); + else { /* need continuation bytes */ + unsigned int mfb = 0x3f; /* maximum that fits in first byte */ + do { /* add continuation bytes */ + buff[UTF8BUFFSZ - (n++)] = cast_char(0x80 | (x & 0x3f)); + x >>= 6; /* remove added bits */ + mfb >>= 1; /* now there is one less bit available in first byte */ + } while (x > mfb); /* still needs continuation byte? */ + buff[UTF8BUFFSZ - n] = cast_char((~mfb << 1) | x); /* add first byte */ + } + return n; +} + + +/* +** Maximum length of the conversion of a number to a string. Must be +** enough to accommodate both LUA_INTEGER_FMT and LUA_NUMBER_FMT. +** (For a long long int, this is 19 digits plus a sign and a final '\0', +** adding to 21. For a long double, it can go to a sign, 33 digits, +** the dot, an exponent letter, an exponent sign, 5 exponent digits, +** and a final '\0', adding to 43.) +*/ +#define MAXNUMBER2STR 44 + + +/* +** Convert a number object to a string, adding it to a buffer +*/ +static int tostringbuff (TValue *obj, char *buff) { + int len; + lua_assert(ttisnumber(obj)); + if (ttisinteger(obj)) + len = lua_integer2str(buff, MAXNUMBER2STR, ivalue(obj)); + else { + len = lua_number2str(buff, MAXNUMBER2STR, fltvalue(obj)); + if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */ + buff[len++] = lua_getlocaledecpoint(); + buff[len++] = '0'; /* adds '.0' to result */ + } + } + return len; +} + + +/* +** Convert a number object to a Lua string, replacing the value at 'obj' +*/ +void luaO_tostring (lua_State *L, TValue *obj) { + char buff[MAXNUMBER2STR]; + int len = tostringbuff(obj, buff); + setsvalue(L, obj, luaS_newlstr(L, buff, len)); +} + + + + +/* +** {================================================================== +** 'luaO_pushvfstring' +** =================================================================== +*/ + +/* +** Size for buffer space used by 'luaO_pushvfstring'. It should be +** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages, +** so that 'luaG_addinfo' can work directly on the buffer. +*/ +#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95) + +/* buffer used by 'luaO_pushvfstring' */ +typedef struct BuffFS { + lua_State *L; + int pushed; /* true if there is a part of the result on the stack */ + int blen; /* length of partial string in 'space' */ + char space[BUFVFS]; /* holds last part of the result */ +} BuffFS; + + +/* +** Push given string to the stack, as part of the result, and +** join it to previous partial result if there is one. +** It may call 'luaV_concat' while using one slot from EXTRA_STACK. +** This call cannot invoke metamethods, as both operands must be +** strings. It can, however, raise an error if the result is too +** long. In that case, 'luaV_concat' frees the extra slot before +** raising the error. +*/ +static void pushstr (BuffFS *buff, const char *str, size_t lstr) { + lua_State *L = buff->L; + setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr)); + L->top.p++; /* may use one slot from EXTRA_STACK */ + if (!buff->pushed) /* no previous string on the stack? */ + buff->pushed = 1; /* now there is one */ + else /* join previous string with new one */ + luaV_concat(L, 2); +} + + +/* +** empty the buffer space into the stack +*/ +static void clearbuff (BuffFS *buff) { + pushstr(buff, buff->space, buff->blen); /* push buffer contents */ + buff->blen = 0; /* space now is empty */ +} + + +/* +** Get a space of size 'sz' in the buffer. If buffer has not enough +** space, empty it. 'sz' must fit in an empty buffer. +*/ +static char *getbuff (BuffFS *buff, int sz) { + lua_assert(buff->blen <= BUFVFS); lua_assert(sz <= BUFVFS); + if (sz > BUFVFS - buff->blen) /* not enough space? */ + clearbuff(buff); + return buff->space + buff->blen; +} + + +#define addsize(b,sz) ((b)->blen += (sz)) + + +/* +** Add 'str' to the buffer. If string is larger than the buffer space, +** push the string directly to the stack. +*/ +static void addstr2buff (BuffFS *buff, const char *str, size_t slen) { + if (slen <= BUFVFS) { /* does string fit into buffer? */ + char *bf = getbuff(buff, cast_int(slen)); + memcpy(bf, str, slen); /* add string to buffer */ + addsize(buff, cast_int(slen)); + } + else { /* string larger than buffer */ + clearbuff(buff); /* string comes after buffer's content */ + pushstr(buff, str, slen); /* push string */ + } +} + + +/* +** Add a numeral to the buffer. +*/ +static void addnum2buff (BuffFS *buff, TValue *num) { + char *numbuff = getbuff(buff, MAXNUMBER2STR); + int len = tostringbuff(num, numbuff); /* format number into 'numbuff' */ + addsize(buff, len); +} + + +/* +** this function handles only '%d', '%c', '%f', '%p', '%s', and '%%' + conventional formats, plus Lua-specific '%I' and '%U' +*/ +const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { + BuffFS buff; /* holds last part of the result */ + const char *e; /* points to next '%' */ + buff.pushed = buff.blen = 0; + buff.L = L; + while ((e = strchr(fmt, '%')) != NULL) { + addstr2buff(&buff, fmt, e - fmt); /* add 'fmt' up to '%' */ + switch (*(e + 1)) { /* conversion specifier */ + case 's': { /* zero-terminated string */ + const char *s = va_arg(argp, char *); + if (s == NULL) s = "(null)"; + addstr2buff(&buff, s, strlen(s)); + break; + } + case 'c': { /* an 'int' as a character */ + char c = cast_uchar(va_arg(argp, int)); + addstr2buff(&buff, &c, sizeof(char)); + break; + } + case 'd': { /* an 'int' */ + TValue num; + setivalue(&num, va_arg(argp, int)); + addnum2buff(&buff, &num); + break; + } + case 'I': { /* a 'lua_Integer' */ + TValue num; + setivalue(&num, cast(lua_Integer, va_arg(argp, l_uacInt))); + addnum2buff(&buff, &num); + break; + } + case 'f': { /* a 'lua_Number' */ + TValue num; + setfltvalue(&num, cast_num(va_arg(argp, l_uacNumber))); + addnum2buff(&buff, &num); + break; + } + case 'p': { /* a pointer */ + const int sz = 3 * sizeof(void*) + 8; /* enough space for '%p' */ + char *bf = getbuff(&buff, sz); + void *p = va_arg(argp, void *); + int len = lua_pointer2str(bf, sz, p); + addsize(&buff, len); + break; + } + case 'U': { /* a 'long' as a UTF-8 sequence */ + char bf[UTF8BUFFSZ]; + int len = luaO_utf8esc(bf, va_arg(argp, long)); + addstr2buff(&buff, bf + UTF8BUFFSZ - len, len); + break; + } + case '%': { + addstr2buff(&buff, "%", 1); + break; + } + default: { + luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'", + *(e + 1)); + } + } + fmt = e + 2; /* skip '%' and the specifier */ + } + addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */ + clearbuff(&buff); /* empty buffer into the stack */ + lua_assert(buff.pushed == 1); + return svalue(s2v(L->top.p - 1)); +} + + +const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { + const char *msg; + va_list argp; + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + return msg; +} + +/* }================================================================== */ + + +#define RETS "..." +#define PRE "[string \"" +#define POS "\"]" + +#define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) ) + +void luaO_chunkid (char *out, const char *source, size_t srclen) { + size_t bufflen = LUA_IDSIZE; /* free space in buffer */ + if (*source == '=') { /* 'literal' source */ + if (srclen <= bufflen) /* small enough? */ + memcpy(out, source + 1, srclen * sizeof(char)); + else { /* truncate it */ + addstr(out, source + 1, bufflen - 1); + *out = '\0'; + } + } + else if (*source == '@') { /* file name */ + if (srclen <= bufflen) /* small enough? */ + memcpy(out, source + 1, srclen * sizeof(char)); + else { /* add '...' before rest of name */ + addstr(out, RETS, LL(RETS)); + bufflen -= LL(RETS); + memcpy(out, source + 1 + srclen - bufflen, bufflen * sizeof(char)); + } + } + else { /* string; format as [string "source"] */ + const char *nl = strchr(source, '\n'); /* find first new line (if any) */ + addstr(out, PRE, LL(PRE)); /* add prefix */ + bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */ + if (srclen < bufflen && nl == NULL) { /* small one-line source? */ + addstr(out, source, srclen); /* keep it */ + } + else { + if (nl != NULL) srclen = nl - source; /* stop at first newline */ + if (srclen > bufflen) srclen = bufflen; + addstr(out, source, srclen); + addstr(out, RETS, LL(RETS)); + } + memcpy(out, POS, (LL(POS) + 1) * sizeof(char)); + } +} + diff --git a/vendor/lua-src/lua-5.4.6/lobject.h b/vendor/lua-src/lua-5.4.6/lobject.h new file mode 100644 index 0000000000000..556608e4aa219 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lobject.h @@ -0,0 +1,815 @@ +/* +** $Id: lobject.h $ +** Type definitions for Lua objects +** See Copyright Notice in lua.h +*/ + + +#ifndef lobject_h +#define lobject_h + + +#include + + +#include "llimits.h" +#include "lua.h" + + +/* +** Extra types for collectable non-values +*/ +#define LUA_TUPVAL LUA_NUMTYPES /* upvalues */ +#define LUA_TPROTO (LUA_NUMTYPES+1) /* function prototypes */ +#define LUA_TDEADKEY (LUA_NUMTYPES+2) /* removed keys in tables */ + + + +/* +** number of all possible types (including LUA_TNONE but excluding DEADKEY) +*/ +#define LUA_TOTALTYPES (LUA_TPROTO + 2) + + +/* +** tags for Tagged Values have the following use of bits: +** bits 0-3: actual tag (a LUA_T* constant) +** bits 4-5: variant bits +** bit 6: whether value is collectable +*/ + +/* add variant bits to a type */ +#define makevariant(t,v) ((t) | ((v) << 4)) + + + +/* +** Union of all Lua values +*/ +typedef union Value { + struct GCObject *gc; /* collectable objects */ + void *p; /* light userdata */ + lua_CFunction f; /* light C functions */ + lua_Integer i; /* integer numbers */ + lua_Number n; /* float numbers */ + /* not used, but may avoid warnings for uninitialized value */ + lu_byte ub; +} Value; + + +/* +** Tagged Values. This is the basic representation of values in Lua: +** an actual value plus a tag with its type. +*/ + +#define TValuefields Value value_; lu_byte tt_ + +typedef struct TValue { + TValuefields; +} TValue; + + +#define val_(o) ((o)->value_) +#define valraw(o) (val_(o)) + + +/* raw type tag of a TValue */ +#define rawtt(o) ((o)->tt_) + +/* tag with no variants (bits 0-3) */ +#define novariant(t) ((t) & 0x0F) + +/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */ +#define withvariant(t) ((t) & 0x3F) +#define ttypetag(o) withvariant(rawtt(o)) + +/* type of a TValue */ +#define ttype(o) (novariant(rawtt(o))) + + +/* Macros to test type */ +#define checktag(o,t) (rawtt(o) == (t)) +#define checktype(o,t) (ttype(o) == (t)) + + +/* Macros for internal tests */ + +/* collectable object has the same tag as the original value */ +#define righttt(obj) (ttypetag(obj) == gcvalue(obj)->tt) + +/* +** Any value being manipulated by the program either is non +** collectable, or the collectable object has the right tag +** and it is not dead. The option 'L == NULL' allows other +** macros using this one to be used where L is not available. +*/ +#define checkliveness(L,obj) \ + ((void)L, lua_longassert(!iscollectable(obj) || \ + (righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)))))) + + +/* Macros to set values */ + +/* set a value's tag */ +#define settt_(o,t) ((o)->tt_=(t)) + + +/* main macro to copy values (from 'obj2' to 'obj1') */ +#define setobj(L,obj1,obj2) \ + { TValue *io1=(obj1); const TValue *io2=(obj2); \ + io1->value_ = io2->value_; settt_(io1, io2->tt_); \ + checkliveness(L,io1); lua_assert(!isnonstrictnil(io1)); } + +/* +** Different types of assignments, according to source and destination. +** (They are mostly equal now, but may be different in the future.) +*/ + +/* from stack to stack */ +#define setobjs2s(L,o1,o2) setobj(L,s2v(o1),s2v(o2)) +/* to stack (not from same stack) */ +#define setobj2s(L,o1,o2) setobj(L,s2v(o1),o2) +/* from table to same table */ +#define setobjt2t setobj +/* to new object */ +#define setobj2n setobj +/* to table */ +#define setobj2t setobj + + +/* +** Entries in a Lua stack. Field 'tbclist' forms a list of all +** to-be-closed variables active in this stack. Dummy entries are +** used when the distance between two tbc variables does not fit +** in an unsigned short. They are represented by delta==0, and +** their real delta is always the maximum value that fits in +** that field. +*/ +typedef union StackValue { + TValue val; + struct { + TValuefields; + unsigned short delta; + } tbclist; +} StackValue; + + +/* index to stack elements */ +typedef StackValue *StkId; + + +/* +** When reallocating the stack, change all pointers to the stack into +** proper offsets. +*/ +typedef union { + StkId p; /* actual pointer */ + ptrdiff_t offset; /* used while the stack is being reallocated */ +} StkIdRel; + + +/* convert a 'StackValue' to a 'TValue' */ +#define s2v(o) (&(o)->val) + + + +/* +** {================================================================== +** Nil +** =================================================================== +*/ + +/* Standard nil */ +#define LUA_VNIL makevariant(LUA_TNIL, 0) + +/* Empty slot (which might be different from a slot containing nil) */ +#define LUA_VEMPTY makevariant(LUA_TNIL, 1) + +/* Value returned for a key not found in a table (absent key) */ +#define LUA_VABSTKEY makevariant(LUA_TNIL, 2) + + +/* macro to test for (any kind of) nil */ +#define ttisnil(v) checktype((v), LUA_TNIL) + + +/* macro to test for a standard nil */ +#define ttisstrictnil(o) checktag((o), LUA_VNIL) + + +#define setnilvalue(obj) settt_(obj, LUA_VNIL) + + +#define isabstkey(v) checktag((v), LUA_VABSTKEY) + + +/* +** macro to detect non-standard nils (used only in assertions) +*/ +#define isnonstrictnil(v) (ttisnil(v) && !ttisstrictnil(v)) + + +/* +** By default, entries with any kind of nil are considered empty. +** (In any definition, values associated with absent keys must also +** be accepted as empty.) +*/ +#define isempty(v) ttisnil(v) + + +/* macro defining a value corresponding to an absent key */ +#define ABSTKEYCONSTANT {NULL}, LUA_VABSTKEY + + +/* mark an entry as empty */ +#define setempty(v) settt_(v, LUA_VEMPTY) + + + +/* }================================================================== */ + + +/* +** {================================================================== +** Booleans +** =================================================================== +*/ + + +#define LUA_VFALSE makevariant(LUA_TBOOLEAN, 0) +#define LUA_VTRUE makevariant(LUA_TBOOLEAN, 1) + +#define ttisboolean(o) checktype((o), LUA_TBOOLEAN) +#define ttisfalse(o) checktag((o), LUA_VFALSE) +#define ttistrue(o) checktag((o), LUA_VTRUE) + + +#define l_isfalse(o) (ttisfalse(o) || ttisnil(o)) + + +#define setbfvalue(obj) settt_(obj, LUA_VFALSE) +#define setbtvalue(obj) settt_(obj, LUA_VTRUE) + +/* }================================================================== */ + + +/* +** {================================================================== +** Threads +** =================================================================== +*/ + +#define LUA_VTHREAD makevariant(LUA_TTHREAD, 0) + +#define ttisthread(o) checktag((o), ctb(LUA_VTHREAD)) + +#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc)) + +#define setthvalue(L,obj,x) \ + { TValue *io = (obj); lua_State *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VTHREAD)); \ + checkliveness(L,io); } + +#define setthvalue2s(L,o,t) setthvalue(L,s2v(o),t) + +/* }================================================================== */ + + +/* +** {================================================================== +** Collectable Objects +** =================================================================== +*/ + +/* +** Common Header for all collectable objects (in macro form, to be +** included in other objects) +*/ +#define CommonHeader struct GCObject *next; lu_byte tt; lu_byte marked + + +/* Common type for all collectable objects */ +typedef struct GCObject { + CommonHeader; +} GCObject; + + +/* Bit mark for collectable types */ +#define BIT_ISCOLLECTABLE (1 << 6) + +#define iscollectable(o) (rawtt(o) & BIT_ISCOLLECTABLE) + +/* mark a tag as collectable */ +#define ctb(t) ((t) | BIT_ISCOLLECTABLE) + +#define gcvalue(o) check_exp(iscollectable(o), val_(o).gc) + +#define gcvalueraw(v) ((v).gc) + +#define setgcovalue(L,obj,x) \ + { TValue *io = (obj); GCObject *i_g=(x); \ + val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); } + +/* }================================================================== */ + + +/* +** {================================================================== +** Numbers +** =================================================================== +*/ + +/* Variant tags for numbers */ +#define LUA_VNUMINT makevariant(LUA_TNUMBER, 0) /* integer numbers */ +#define LUA_VNUMFLT makevariant(LUA_TNUMBER, 1) /* float numbers */ + +#define ttisnumber(o) checktype((o), LUA_TNUMBER) +#define ttisfloat(o) checktag((o), LUA_VNUMFLT) +#define ttisinteger(o) checktag((o), LUA_VNUMINT) + +#define nvalue(o) check_exp(ttisnumber(o), \ + (ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o))) +#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n) +#define ivalue(o) check_exp(ttisinteger(o), val_(o).i) + +#define fltvalueraw(v) ((v).n) +#define ivalueraw(v) ((v).i) + +#define setfltvalue(obj,x) \ + { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_VNUMFLT); } + +#define chgfltvalue(obj,x) \ + { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); } + +#define setivalue(obj,x) \ + { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_VNUMINT); } + +#define chgivalue(obj,x) \ + { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); } + +/* }================================================================== */ + + +/* +** {================================================================== +** Strings +** =================================================================== +*/ + +/* Variant tags for strings */ +#define LUA_VSHRSTR makevariant(LUA_TSTRING, 0) /* short strings */ +#define LUA_VLNGSTR makevariant(LUA_TSTRING, 1) /* long strings */ + +#define ttisstring(o) checktype((o), LUA_TSTRING) +#define ttisshrstring(o) checktag((o), ctb(LUA_VSHRSTR)) +#define ttislngstring(o) checktag((o), ctb(LUA_VLNGSTR)) + +#define tsvalueraw(v) (gco2ts((v).gc)) + +#define tsvalue(o) check_exp(ttisstring(o), gco2ts(val_(o).gc)) + +#define setsvalue(L,obj,x) \ + { TValue *io = (obj); TString *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \ + checkliveness(L,io); } + +/* set a string to the stack */ +#define setsvalue2s(L,o,s) setsvalue(L,s2v(o),s) + +/* set a string to a new object */ +#define setsvalue2n setsvalue + + +/* +** Header for a string value. +*/ +typedef struct TString { + CommonHeader; + lu_byte extra; /* reserved words for short strings; "has hash" for longs */ + lu_byte shrlen; /* length for short strings */ + unsigned int hash; + union { + size_t lnglen; /* length for long strings */ + struct TString *hnext; /* linked list for hash table */ + } u; + char contents[1]; +} TString; + + + +/* +** Get the actual string (array of bytes) from a 'TString'. +*/ +#define getstr(ts) ((ts)->contents) + + +/* get the actual string (array of bytes) from a Lua value */ +#define svalue(o) getstr(tsvalue(o)) + +/* get string length from 'TString *s' */ +#define tsslen(s) ((s)->tt == LUA_VSHRSTR ? (s)->shrlen : (s)->u.lnglen) + +/* get string length from 'TValue *o' */ +#define vslen(o) tsslen(tsvalue(o)) + +/* }================================================================== */ + + +/* +** {================================================================== +** Userdata +** =================================================================== +*/ + + +/* +** Light userdata should be a variant of userdata, but for compatibility +** reasons they are also different types. +*/ +#define LUA_VLIGHTUSERDATA makevariant(LUA_TLIGHTUSERDATA, 0) + +#define LUA_VUSERDATA makevariant(LUA_TUSERDATA, 0) + +#define ttislightuserdata(o) checktag((o), LUA_VLIGHTUSERDATA) +#define ttisfulluserdata(o) checktag((o), ctb(LUA_VUSERDATA)) + +#define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p) +#define uvalue(o) check_exp(ttisfulluserdata(o), gco2u(val_(o).gc)) + +#define pvalueraw(v) ((v).p) + +#define setpvalue(obj,x) \ + { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_VLIGHTUSERDATA); } + +#define setuvalue(L,obj,x) \ + { TValue *io = (obj); Udata *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VUSERDATA)); \ + checkliveness(L,io); } + + +/* Ensures that addresses after this type are always fully aligned. */ +typedef union UValue { + TValue uv; + LUAI_MAXALIGN; /* ensures maximum alignment for udata bytes */ +} UValue; + + +/* +** Header for userdata with user values; +** memory area follows the end of this structure. +*/ +typedef struct Udata { + CommonHeader; + unsigned short nuvalue; /* number of user values */ + size_t len; /* number of bytes */ + struct Table *metatable; + GCObject *gclist; + UValue uv[1]; /* user values */ +} Udata; + + +/* +** Header for userdata with no user values. These userdata do not need +** to be gray during GC, and therefore do not need a 'gclist' field. +** To simplify, the code always use 'Udata' for both kinds of userdata, +** making sure it never accesses 'gclist' on userdata with no user values. +** This structure here is used only to compute the correct size for +** this representation. (The 'bindata' field in its end ensures correct +** alignment for binary data following this header.) +*/ +typedef struct Udata0 { + CommonHeader; + unsigned short nuvalue; /* number of user values */ + size_t len; /* number of bytes */ + struct Table *metatable; + union {LUAI_MAXALIGN;} bindata; +} Udata0; + + +/* compute the offset of the memory area of a userdata */ +#define udatamemoffset(nuv) \ + ((nuv) == 0 ? offsetof(Udata0, bindata) \ + : offsetof(Udata, uv) + (sizeof(UValue) * (nuv))) + +/* get the address of the memory block inside 'Udata' */ +#define getudatamem(u) (cast_charp(u) + udatamemoffset((u)->nuvalue)) + +/* compute the size of a userdata */ +#define sizeudata(nuv,nb) (udatamemoffset(nuv) + (nb)) + +/* }================================================================== */ + + +/* +** {================================================================== +** Prototypes +** =================================================================== +*/ + +#define LUA_VPROTO makevariant(LUA_TPROTO, 0) + + +/* +** Description of an upvalue for function prototypes +*/ +typedef struct Upvaldesc { + TString *name; /* upvalue name (for debug information) */ + lu_byte instack; /* whether it is in stack (register) */ + lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ + lu_byte kind; /* kind of corresponding variable */ +} Upvaldesc; + + +/* +** Description of a local variable for function prototypes +** (used for debug information) +*/ +typedef struct LocVar { + TString *varname; + int startpc; /* first point where variable is active */ + int endpc; /* first point where variable is dead */ +} LocVar; + + +/* +** Associates the absolute line source for a given instruction ('pc'). +** The array 'lineinfo' gives, for each instruction, the difference in +** lines from the previous instruction. When that difference does not +** fit into a byte, Lua saves the absolute line for that instruction. +** (Lua also saves the absolute line periodically, to speed up the +** computation of a line number: we can use binary search in the +** absolute-line array, but we must traverse the 'lineinfo' array +** linearly to compute a line.) +*/ +typedef struct AbsLineInfo { + int pc; + int line; +} AbsLineInfo; + +/* +** Function Prototypes +*/ +typedef struct Proto { + CommonHeader; + lu_byte numparams; /* number of fixed (named) parameters */ + lu_byte is_vararg; + lu_byte maxstacksize; /* number of registers needed by this function */ + int sizeupvalues; /* size of 'upvalues' */ + int sizek; /* size of 'k' */ + int sizecode; + int sizelineinfo; + int sizep; /* size of 'p' */ + int sizelocvars; + int sizeabslineinfo; /* size of 'abslineinfo' */ + int linedefined; /* debug information */ + int lastlinedefined; /* debug information */ + TValue *k; /* constants used by the function */ + Instruction *code; /* opcodes */ + struct Proto **p; /* functions defined inside the function */ + Upvaldesc *upvalues; /* upvalue information */ + ls_byte *lineinfo; /* information about source lines (debug information) */ + AbsLineInfo *abslineinfo; /* idem */ + LocVar *locvars; /* information about local variables (debug information) */ + TString *source; /* used for debug information */ + GCObject *gclist; +} Proto; + +/* }================================================================== */ + + +/* +** {================================================================== +** Functions +** =================================================================== +*/ + +#define LUA_VUPVAL makevariant(LUA_TUPVAL, 0) + + +/* Variant tags for functions */ +#define LUA_VLCL makevariant(LUA_TFUNCTION, 0) /* Lua closure */ +#define LUA_VLCF makevariant(LUA_TFUNCTION, 1) /* light C function */ +#define LUA_VCCL makevariant(LUA_TFUNCTION, 2) /* C closure */ + +#define ttisfunction(o) checktype(o, LUA_TFUNCTION) +#define ttisLclosure(o) checktag((o), ctb(LUA_VLCL)) +#define ttislcf(o) checktag((o), LUA_VLCF) +#define ttisCclosure(o) checktag((o), ctb(LUA_VCCL)) +#define ttisclosure(o) (ttisLclosure(o) || ttisCclosure(o)) + + +#define isLfunction(o) ttisLclosure(o) + +#define clvalue(o) check_exp(ttisclosure(o), gco2cl(val_(o).gc)) +#define clLvalue(o) check_exp(ttisLclosure(o), gco2lcl(val_(o).gc)) +#define fvalue(o) check_exp(ttislcf(o), val_(o).f) +#define clCvalue(o) check_exp(ttisCclosure(o), gco2ccl(val_(o).gc)) + +#define fvalueraw(v) ((v).f) + +#define setclLvalue(L,obj,x) \ + { TValue *io = (obj); LClosure *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VLCL)); \ + checkliveness(L,io); } + +#define setclLvalue2s(L,o,cl) setclLvalue(L,s2v(o),cl) + +#define setfvalue(obj,x) \ + { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_VLCF); } + +#define setclCvalue(L,obj,x) \ + { TValue *io = (obj); CClosure *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VCCL)); \ + checkliveness(L,io); } + + +/* +** Upvalues for Lua closures +*/ +typedef struct UpVal { + CommonHeader; + union { + TValue *p; /* points to stack or to its own value */ + ptrdiff_t offset; /* used while the stack is being reallocated */ + } v; + union { + struct { /* (when open) */ + struct UpVal *next; /* linked list */ + struct UpVal **previous; + } open; + TValue value; /* the value (when closed) */ + } u; +} UpVal; + + + +#define ClosureHeader \ + CommonHeader; lu_byte nupvalues; GCObject *gclist + +typedef struct CClosure { + ClosureHeader; + lua_CFunction f; + TValue upvalue[1]; /* list of upvalues */ +} CClosure; + + +typedef struct LClosure { + ClosureHeader; + struct Proto *p; + UpVal *upvals[1]; /* list of upvalues */ +} LClosure; + + +typedef union Closure { + CClosure c; + LClosure l; +} Closure; + + +#define getproto(o) (clLvalue(o)->p) + +/* }================================================================== */ + + +/* +** {================================================================== +** Tables +** =================================================================== +*/ + +#define LUA_VTABLE makevariant(LUA_TTABLE, 0) + +#define ttistable(o) checktag((o), ctb(LUA_VTABLE)) + +#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc)) + +#define sethvalue(L,obj,x) \ + { TValue *io = (obj); Table *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VTABLE)); \ + checkliveness(L,io); } + +#define sethvalue2s(L,o,h) sethvalue(L,s2v(o),h) + + +/* +** Nodes for Hash tables: A pack of two TValue's (key-value pairs) +** plus a 'next' field to link colliding entries. The distribution +** of the key's fields ('key_tt' and 'key_val') not forming a proper +** 'TValue' allows for a smaller size for 'Node' both in 4-byte +** and 8-byte alignments. +*/ +typedef union Node { + struct NodeKey { + TValuefields; /* fields for value */ + lu_byte key_tt; /* key type */ + int next; /* for chaining */ + Value key_val; /* key value */ + } u; + TValue i_val; /* direct access to node's value as a proper 'TValue' */ +} Node; + + +/* copy a value into a key */ +#define setnodekey(L,node,obj) \ + { Node *n_=(node); const TValue *io_=(obj); \ + n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \ + checkliveness(L,io_); } + + +/* copy a value from a key */ +#define getnodekey(L,obj,node) \ + { TValue *io_=(obj); const Node *n_=(node); \ + io_->value_ = n_->u.key_val; io_->tt_ = n_->u.key_tt; \ + checkliveness(L,io_); } + + +/* +** About 'alimit': if 'isrealasize(t)' is true, then 'alimit' is the +** real size of 'array'. Otherwise, the real size of 'array' is the +** smallest power of two not smaller than 'alimit' (or zero iff 'alimit' +** is zero); 'alimit' is then used as a hint for #t. +*/ + +#define BITRAS (1 << 7) +#define isrealasize(t) (!((t)->flags & BITRAS)) +#define setrealasize(t) ((t)->flags &= cast_byte(~BITRAS)) +#define setnorealasize(t) ((t)->flags |= BITRAS) + + +typedef struct Table { + CommonHeader; + lu_byte flags; /* 1<

u.key_tt) +#define keyval(node) ((node)->u.key_val) + +#define keyisnil(node) (keytt(node) == LUA_TNIL) +#define keyisinteger(node) (keytt(node) == LUA_VNUMINT) +#define keyival(node) (keyval(node).i) +#define keyisshrstr(node) (keytt(node) == ctb(LUA_VSHRSTR)) +#define keystrval(node) (gco2ts(keyval(node).gc)) + +#define setnilkey(node) (keytt(node) = LUA_TNIL) + +#define keyiscollectable(n) (keytt(n) & BIT_ISCOLLECTABLE) + +#define gckey(n) (keyval(n).gc) +#define gckeyN(n) (keyiscollectable(n) ? gckey(n) : NULL) + + +/* +** Dead keys in tables have the tag DEADKEY but keep their original +** gcvalue. This distinguishes them from regular keys but allows them to +** be found when searched in a special way. ('next' needs that to find +** keys removed from a table during a traversal.) +*/ +#define setdeadkey(node) (keytt(node) = LUA_TDEADKEY) +#define keyisdead(node) (keytt(node) == LUA_TDEADKEY) + +/* }================================================================== */ + + + +/* +** 'module' operation for hashing (size is always a power of 2) +*/ +#define lmod(s,size) \ + (check_exp((size&(size-1))==0, (cast_int((s) & ((size)-1))))) + + +#define twoto(x) (1<<(x)) +#define sizenode(t) (twoto((t)->lsizenode)) + + +/* size of buffer for 'luaO_utf8esc' function */ +#define UTF8BUFFSZ 8 + +LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x); +LUAI_FUNC int luaO_ceillog2 (unsigned int x); +LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1, + const TValue *p2, TValue *res); +LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1, + const TValue *p2, StkId res); +LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o); +LUAI_FUNC int luaO_hexavalue (int c); +LUAI_FUNC void luaO_tostring (lua_State *L, TValue *obj); +LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, + va_list argp); +LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); +LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t srclen); + + +#endif + diff --git a/vendor/lua-src/lua-5.4.6/lopcodes.c b/vendor/lua-src/lua-5.4.6/lopcodes.c new file mode 100644 index 0000000000000..c67aa227c5879 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lopcodes.c @@ -0,0 +1,104 @@ +/* +** $Id: lopcodes.c $ +** Opcodes for Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#define lopcodes_c +#define LUA_CORE + +#include "lprefix.h" + + +#include "lopcodes.h" + + +/* ORDER OP */ + +LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { +/* MM OT IT T A mode opcode */ + opmode(0, 0, 0, 0, 1, iABC) /* OP_MOVE */ + ,opmode(0, 0, 0, 0, 1, iAsBx) /* OP_LOADI */ + ,opmode(0, 0, 0, 0, 1, iAsBx) /* OP_LOADF */ + ,opmode(0, 0, 0, 0, 1, iABx) /* OP_LOADK */ + ,opmode(0, 0, 0, 0, 1, iABx) /* OP_LOADKX */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADFALSE */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LFALSESKIP */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADTRUE */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADNIL */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETUPVAL */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETUPVAL */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETTABUP */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETTABLE */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETI */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETFIELD */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETTABUP */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETTABLE */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETI */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETFIELD */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_NEWTABLE */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SELF */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDI */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SUBK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_MULK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_MODK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_POWK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_DIVK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_IDIVK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BANDK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BORK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BXORK */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHRI */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHLI */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADD */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SUB */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_MUL */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_MOD */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_POW */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_DIV */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_IDIV */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BAND */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BOR */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BXOR */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHL */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHR */ + ,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBIN */ + ,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINI*/ + ,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINK*/ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_UNM */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BNOT */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_NOT */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LEN */ + ,opmode(0, 0, 0, 0, 1, iABC) /* OP_CONCAT */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_CLOSE */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_TBC */ + ,opmode(0, 0, 0, 0, 0, isJ) /* OP_JMP */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_EQ */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_LT */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_LE */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_EQK */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_EQI */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_LTI */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_LEI */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_GTI */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_GEI */ + ,opmode(0, 0, 0, 1, 0, iABC) /* OP_TEST */ + ,opmode(0, 0, 0, 1, 1, iABC) /* OP_TESTSET */ + ,opmode(0, 1, 1, 0, 1, iABC) /* OP_CALL */ + ,opmode(0, 1, 1, 0, 1, iABC) /* OP_TAILCALL */ + ,opmode(0, 0, 1, 0, 0, iABC) /* OP_RETURN */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_RETURN0 */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_RETURN1 */ + ,opmode(0, 0, 0, 0, 1, iABx) /* OP_FORLOOP */ + ,opmode(0, 0, 0, 0, 1, iABx) /* OP_FORPREP */ + ,opmode(0, 0, 0, 0, 0, iABx) /* OP_TFORPREP */ + ,opmode(0, 0, 0, 0, 0, iABC) /* OP_TFORCALL */ + ,opmode(0, 0, 0, 0, 1, iABx) /* OP_TFORLOOP */ + ,opmode(0, 0, 1, 0, 0, iABC) /* OP_SETLIST */ + ,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */ + ,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */ + ,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */ + ,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */ +}; + diff --git a/vendor/lua-src/lua-5.4.6/lopcodes.h b/vendor/lua-src/lua-5.4.6/lopcodes.h new file mode 100644 index 0000000000000..4c55145399ff9 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lopcodes.h @@ -0,0 +1,405 @@ +/* +** $Id: lopcodes.h $ +** Opcodes for Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lopcodes_h +#define lopcodes_h + +#include "llimits.h" + + +/*=========================================================================== + We assume that instructions are unsigned 32-bit integers. + All instructions have an opcode in the first 7 bits. + Instructions can have the following formats: + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +iABC C(8) | B(8) |k| A(8) | Op(7) | +iABx Bx(17) | A(8) | Op(7) | +iAsBx sBx (signed)(17) | A(8) | Op(7) | +iAx Ax(25) | Op(7) | +isJ sJ (signed)(25) | Op(7) | + + A signed argument is represented in excess K: the represented value is + the written unsigned value minus K, where K is half the maximum for the + corresponding unsigned argument. +===========================================================================*/ + + +enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */ + + +/* +** size and position of opcode arguments. +*/ +#define SIZE_C 8 +#define SIZE_B 8 +#define SIZE_Bx (SIZE_C + SIZE_B + 1) +#define SIZE_A 8 +#define SIZE_Ax (SIZE_Bx + SIZE_A) +#define SIZE_sJ (SIZE_Bx + SIZE_A) + +#define SIZE_OP 7 + +#define POS_OP 0 + +#define POS_A (POS_OP + SIZE_OP) +#define POS_k (POS_A + SIZE_A) +#define POS_B (POS_k + 1) +#define POS_C (POS_B + SIZE_B) + +#define POS_Bx POS_k + +#define POS_Ax POS_A + +#define POS_sJ POS_A + + +/* +** limits for opcode arguments. +** we use (signed) 'int' to manipulate most arguments, +** so they must fit in ints. +*/ + +/* Check whether type 'int' has at least 'b' bits ('b' < 32) */ +#define L_INTHASBITS(b) ((UINT_MAX >> ((b) - 1)) >= 1) + + +#if L_INTHASBITS(SIZE_Bx) +#define MAXARG_Bx ((1<>1) /* 'sBx' is signed */ + + +#if L_INTHASBITS(SIZE_Ax) +#define MAXARG_Ax ((1<> 1) + + +#define MAXARG_A ((1<> 1) + +#define int2sC(i) ((i) + OFFSET_sC) +#define sC2int(i) ((i) - OFFSET_sC) + + +/* creates a mask with 'n' 1 bits at position 'p' */ +#define MASK1(n,p) ((~((~(Instruction)0)<<(n)))<<(p)) + +/* creates a mask with 'n' 0 bits at position 'p' */ +#define MASK0(n,p) (~MASK1(n,p)) + +/* +** the following macros help to manipulate instructions +*/ + +#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0))) +#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ + ((cast(Instruction, o)<>(pos)) & MASK1(size,0))) +#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ + ((cast(Instruction, v)<> sC */ +OP_SHLI,/* A B sC R[A] := sC << R[B] */ + +OP_ADD,/* A B C R[A] := R[B] + R[C] */ +OP_SUB,/* A B C R[A] := R[B] - R[C] */ +OP_MUL,/* A B C R[A] := R[B] * R[C] */ +OP_MOD,/* A B C R[A] := R[B] % R[C] */ +OP_POW,/* A B C R[A] := R[B] ^ R[C] */ +OP_DIV,/* A B C R[A] := R[B] / R[C] */ +OP_IDIV,/* A B C R[A] := R[B] // R[C] */ + +OP_BAND,/* A B C R[A] := R[B] & R[C] */ +OP_BOR,/* A B C R[A] := R[B] | R[C] */ +OP_BXOR,/* A B C R[A] := R[B] ~ R[C] */ +OP_SHL,/* A B C R[A] := R[B] << R[C] */ +OP_SHR,/* A B C R[A] := R[B] >> R[C] */ + +OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] (*) */ +OP_MMBINI,/* A sB C k call C metamethod over R[A] and sB */ +OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */ + +OP_UNM,/* A B R[A] := -R[B] */ +OP_BNOT,/* A B R[A] := ~R[B] */ +OP_NOT,/* A B R[A] := not R[B] */ +OP_LEN,/* A B R[A] := #R[B] (length operator) */ + +OP_CONCAT,/* A B R[A] := R[A].. ... ..R[A + B - 1] */ + +OP_CLOSE,/* A close all upvalues >= R[A] */ +OP_TBC,/* A mark variable A "to be closed" */ +OP_JMP,/* sJ pc += sJ */ +OP_EQ,/* A B k if ((R[A] == R[B]) ~= k) then pc++ */ +OP_LT,/* A B k if ((R[A] < R[B]) ~= k) then pc++ */ +OP_LE,/* A B k if ((R[A] <= R[B]) ~= k) then pc++ */ + +OP_EQK,/* A B k if ((R[A] == K[B]) ~= k) then pc++ */ +OP_EQI,/* A sB k if ((R[A] == sB) ~= k) then pc++ */ +OP_LTI,/* A sB k if ((R[A] < sB) ~= k) then pc++ */ +OP_LEI,/* A sB k if ((R[A] <= sB) ~= k) then pc++ */ +OP_GTI,/* A sB k if ((R[A] > sB) ~= k) then pc++ */ +OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */ + +OP_TEST,/* A k if (not R[A] == k) then pc++ */ +OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] (*) */ + +OP_CALL,/* A B C R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */ +OP_TAILCALL,/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */ + +OP_RETURN,/* A B C k return R[A], ... ,R[A+B-2] (see note) */ +OP_RETURN0,/* return */ +OP_RETURN1,/* A return R[A] */ + +OP_FORLOOP,/* A Bx update counters; if loop continues then pc-=Bx; */ +OP_FORPREP,/* A Bx ; + if not to run then pc+=Bx+1; */ + +OP_TFORPREP,/* A Bx create upvalue for R[A + 3]; pc+=Bx */ +OP_TFORCALL,/* A C R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]); */ +OP_TFORLOOP,/* A Bx if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx } */ + +OP_SETLIST,/* A B C k R[A][C+i] := R[A+i], 1 <= i <= B */ + +OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */ + +OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */ + +OP_VARARGPREP,/*A (adjust vararg parameters) */ + +OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ +} OpCode; + + +#define NUM_OPCODES ((int)(OP_EXTRAARG) + 1) + + + +/*=========================================================================== + Notes: + + (*) Opcode OP_LFALSESKIP is used to convert a condition to a boolean + value, in a code equivalent to (not cond ? false : true). (It + produces false and skips the next instruction producing true.) + + (*) Opcodes OP_MMBIN and variants follow each arithmetic and + bitwise opcode. If the operation succeeds, it skips this next + opcode. Otherwise, this opcode calls the corresponding metamethod. + + (*) Opcode OP_TESTSET is used in short-circuit expressions that need + both to jump and to produce a value, such as (a = b or c). + + (*) In OP_CALL, if (B == 0) then B = top - A. If (C == 0), then + 'top' is set to last_result+1, so next open instruction (OP_CALL, + OP_RETURN*, OP_SETLIST) may use 'top'. + + (*) In OP_VARARG, if (C == 0) then use actual number of varargs and + set top (like in OP_CALL with C == 0). + + (*) In OP_RETURN, if (B == 0) then return up to 'top'. + + (*) In OP_LOADKX and OP_NEWTABLE, the next instruction is always + OP_EXTRAARG. + + (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if k, then + real C = EXTRAARG _ C (the bits of EXTRAARG concatenated with the + bits of C). + + (*) In OP_NEWTABLE, B is log2 of the hash size (which is always a + power of 2) plus 1, or zero for size zero. If not k, the array size + is C. Otherwise, the array size is EXTRAARG _ C. + + (*) For comparisons, k specifies what condition the test should accept + (true or false). + + (*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped + (the constant is the first operand). + + (*) All 'skips' (pc++) assume that next instruction is a jump. + + (*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the + function builds upvalues, which may need to be closed. C > 0 means + the function is vararg, so that its 'func' must be corrected before + returning; in this case, (C - 1) is its number of fixed parameters. + + (*) In comparisons with an immediate operand, C signals whether the + original operand was a float. (It must be corrected in case of + metamethods.) + +===========================================================================*/ + + +/* +** masks for instruction properties. The format is: +** bits 0-2: op mode +** bit 3: instruction set register A +** bit 4: operator is a test (next instruction must be a jump) +** bit 5: instruction uses 'L->top' set by previous instruction (when B == 0) +** bit 6: instruction sets 'L->top' for next instruction (when C == 0) +** bit 7: instruction is an MM instruction (call a metamethod) +*/ + +LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];) + +#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 7)) +#define testAMode(m) (luaP_opmodes[m] & (1 << 3)) +#define testTMode(m) (luaP_opmodes[m] & (1 << 4)) +#define testITMode(m) (luaP_opmodes[m] & (1 << 5)) +#define testOTMode(m) (luaP_opmodes[m] & (1 << 6)) +#define testMMMode(m) (luaP_opmodes[m] & (1 << 7)) + +/* "out top" (set top for next instruction) */ +#define isOT(i) \ + ((testOTMode(GET_OPCODE(i)) && GETARG_C(i) == 0) || \ + GET_OPCODE(i) == OP_TAILCALL) + +/* "in top" (uses top from previous instruction) */ +#define isIT(i) (testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0) + +#define opmode(mm,ot,it,t,a,m) \ + (((mm) << 7) | ((ot) << 6) | ((it) << 5) | ((t) << 4) | ((a) << 3) | (m)) + + +/* number of list items to accumulate before a SETLIST instruction */ +#define LFIELDS_PER_FLUSH 50 + +#endif diff --git a/vendor/lua-src/lua-5.4.6/lopnames.h b/vendor/lua-src/lua-5.4.6/lopnames.h new file mode 100644 index 0000000000000..965cec9bf2fac --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lopnames.h @@ -0,0 +1,103 @@ +/* +** $Id: lopnames.h $ +** Opcode names +** See Copyright Notice in lua.h +*/ + +#if !defined(lopnames_h) +#define lopnames_h + +#include + + +/* ORDER OP */ + +static const char *const opnames[] = { + "MOVE", + "LOADI", + "LOADF", + "LOADK", + "LOADKX", + "LOADFALSE", + "LFALSESKIP", + "LOADTRUE", + "LOADNIL", + "GETUPVAL", + "SETUPVAL", + "GETTABUP", + "GETTABLE", + "GETI", + "GETFIELD", + "SETTABUP", + "SETTABLE", + "SETI", + "SETFIELD", + "NEWTABLE", + "SELF", + "ADDI", + "ADDK", + "SUBK", + "MULK", + "MODK", + "POWK", + "DIVK", + "IDIVK", + "BANDK", + "BORK", + "BXORK", + "SHRI", + "SHLI", + "ADD", + "SUB", + "MUL", + "MOD", + "POW", + "DIV", + "IDIV", + "BAND", + "BOR", + "BXOR", + "SHL", + "SHR", + "MMBIN", + "MMBINI", + "MMBINK", + "UNM", + "BNOT", + "NOT", + "LEN", + "CONCAT", + "CLOSE", + "TBC", + "JMP", + "EQ", + "LT", + "LE", + "EQK", + "EQI", + "LTI", + "LEI", + "GTI", + "GEI", + "TEST", + "TESTSET", + "CALL", + "TAILCALL", + "RETURN", + "RETURN0", + "RETURN1", + "FORLOOP", + "FORPREP", + "TFORPREP", + "TFORCALL", + "TFORLOOP", + "SETLIST", + "CLOSURE", + "VARARG", + "VARARGPREP", + "EXTRAARG", + NULL +}; + +#endif + diff --git a/vendor/lua-src/lua-5.4.6/loslib.c b/vendor/lua-src/lua-5.4.6/loslib.c new file mode 100644 index 0000000000000..ad5a927688521 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/loslib.c @@ -0,0 +1,428 @@ +/* +** $Id: loslib.c $ +** Standard Operating System library +** See Copyright Notice in lua.h +*/ + +#define loslib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** {================================================================== +** List of valid conversion specifiers for the 'strftime' function; +** options are grouped by length; group of length 2 start with '||'. +** =================================================================== +*/ +#if !defined(LUA_STRFTIMEOPTIONS) /* { */ + +#if defined(LUA_USE_WINDOWS) +#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \ + "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */ +#elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */ +#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%" +#else /* C99 specification */ +#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \ + "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */ +#endif + +#endif /* } */ +/* }================================================================== */ + + +/* +** {================================================================== +** Configuration for time-related stuff +** =================================================================== +*/ + +/* +** type to represent time_t in Lua +*/ +#if !defined(LUA_NUMTIME) /* { */ + +#define l_timet lua_Integer +#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) +#define l_gettime(L,arg) luaL_checkinteger(L, arg) + +#else /* }{ */ + +#define l_timet lua_Number +#define l_pushtime(L,t) lua_pushnumber(L,(lua_Number)(t)) +#define l_gettime(L,arg) luaL_checknumber(L, arg) + +#endif /* } */ + + +#if !defined(l_gmtime) /* { */ +/* +** By default, Lua uses gmtime/localtime, except when POSIX is available, +** where it uses gmtime_r/localtime_r +*/ + +#if defined(LUA_USE_POSIX) /* { */ + +#define l_gmtime(t,r) gmtime_r(t,r) +#define l_localtime(t,r) localtime_r(t,r) + +#else /* }{ */ + +/* ISO C definitions */ +#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t)) +#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t)) + +#endif /* } */ + +#endif /* } */ + +/* }================================================================== */ + + +/* +** {================================================================== +** Configuration for 'tmpnam': +** By default, Lua uses tmpnam except when POSIX is available, where +** it uses mkstemp. +** =================================================================== +*/ +#if !defined(lua_tmpnam) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#include + +#define LUA_TMPNAMBUFSIZE 32 + +#if !defined(LUA_TMPNAMTEMPLATE) +#define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX" +#endif + +#define lua_tmpnam(b,e) { \ + strcpy(b, LUA_TMPNAMTEMPLATE); \ + e = mkstemp(b); \ + if (e != -1) close(e); \ + e = (e == -1); } + +#else /* }{ */ + +/* ISO C definitions */ +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } + +#endif /* } */ + +#endif /* } */ +/* }================================================================== */ + + +#if !defined(l_system) +#if defined(LUA_USE_IOS) +/* Despite claiming to be ISO C, iOS does not implement 'system'. */ +#define l_system(cmd) ((cmd) == NULL ? 0 : -1) +#else +#define l_system(cmd) system(cmd) /* default definition */ +#endif +#endif + + +static int os_execute (lua_State *L) { + const char *cmd = luaL_optstring(L, 1, NULL); + int stat; + errno = 0; + stat = l_system(cmd); + if (cmd != NULL) + return luaL_execresult(L, stat); + else { + lua_pushboolean(L, stat); /* true if there is a shell */ + return 1; + } +} + + +static int os_remove (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + return luaL_fileresult(L, remove(filename) == 0, filename); +} + + +static int os_rename (lua_State *L) { + const char *fromname = luaL_checkstring(L, 1); + const char *toname = luaL_checkstring(L, 2); + return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); +} + + +static int os_tmpname (lua_State *L) { + char buff[LUA_TMPNAMBUFSIZE]; + int err; + lua_tmpnam(buff, err); + if (l_unlikely(err)) + return luaL_error(L, "unable to generate a unique filename"); + lua_pushstring(L, buff); + return 1; +} + + +static int os_getenv (lua_State *L) { + lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ + return 1; +} + + +static int os_clock (lua_State *L) { + lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); + return 1; +} + + +/* +** {====================================================== +** Time/Date operations +** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, +** wday=%w+1, yday=%j, isdst=? } +** ======================================================= +*/ + +/* +** About the overflow check: an overflow cannot occur when time +** is represented by a lua_Integer, because either lua_Integer is +** large enough to represent all int fields or it is not large enough +** to represent a time that cause a field to overflow. However, if +** times are represented as doubles and lua_Integer is int, then the +** time 0x1.e1853b0d184f6p+55 would cause an overflow when adding 1900 +** to compute the year. +*/ +static void setfield (lua_State *L, const char *key, int value, int delta) { + #if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX) + if (l_unlikely(value > LUA_MAXINTEGER - delta)) + luaL_error(L, "field '%s' is out-of-bound", key); + #endif + lua_pushinteger(L, (lua_Integer)value + delta); + lua_setfield(L, -2, key); +} + + +static void setboolfield (lua_State *L, const char *key, int value) { + if (value < 0) /* undefined? */ + return; /* does not set field */ + lua_pushboolean(L, value); + lua_setfield(L, -2, key); +} + + +/* +** Set all fields from structure 'tm' in the table on top of the stack +*/ +static void setallfields (lua_State *L, struct tm *stm) { + setfield(L, "year", stm->tm_year, 1900); + setfield(L, "month", stm->tm_mon, 1); + setfield(L, "day", stm->tm_mday, 0); + setfield(L, "hour", stm->tm_hour, 0); + setfield(L, "min", stm->tm_min, 0); + setfield(L, "sec", stm->tm_sec, 0); + setfield(L, "yday", stm->tm_yday, 1); + setfield(L, "wday", stm->tm_wday, 1); + setboolfield(L, "isdst", stm->tm_isdst); +} + + +static int getboolfield (lua_State *L, const char *key) { + int res; + res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); + lua_pop(L, 1); + return res; +} + + +static int getfield (lua_State *L, const char *key, int d, int delta) { + int isnum; + int t = lua_getfield(L, -1, key); /* get field and its type */ + lua_Integer res = lua_tointegerx(L, -1, &isnum); + if (!isnum) { /* field is not an integer? */ + if (l_unlikely(t != LUA_TNIL)) /* some other value? */ + return luaL_error(L, "field '%s' is not an integer", key); + else if (l_unlikely(d < 0)) /* absent field; no default? */ + return luaL_error(L, "field '%s' missing in date table", key); + res = d; + } + else { + if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res)) + return luaL_error(L, "field '%s' is out-of-bound", key); + res -= delta; + } + lua_pop(L, 1); + return (int)res; +} + + +static const char *checkoption (lua_State *L, const char *conv, + ptrdiff_t convlen, char *buff) { + const char *option = LUA_STRFTIMEOPTIONS; + int oplen = 1; /* length of options being checked */ + for (; *option != '\0' && oplen <= convlen; option += oplen) { + if (*option == '|') /* next block? */ + oplen++; /* will check options with next length (+1) */ + else if (memcmp(conv, option, oplen) == 0) { /* match? */ + memcpy(buff, conv, oplen); /* copy valid option to buffer */ + buff[oplen] = '\0'; + return conv + oplen; /* return next item */ + } + } + luaL_argerror(L, 1, + lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv)); + return conv; /* to avoid warnings */ +} + + +static time_t l_checktime (lua_State *L, int arg) { + l_timet t = l_gettime(L, arg); + luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds"); + return (time_t)t; +} + + +/* maximum size for an individual 'strftime' item */ +#define SIZETIMEFMT 250 + + +static int os_date (lua_State *L) { + size_t slen; + const char *s = luaL_optlstring(L, 1, "%c", &slen); + time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); + const char *se = s + slen; /* 's' end */ + struct tm tmr, *stm; + if (*s == '!') { /* UTC? */ + stm = l_gmtime(&t, &tmr); + s++; /* skip '!' */ + } + else + stm = l_localtime(&t, &tmr); + if (stm == NULL) /* invalid date? */ + return luaL_error(L, + "date result cannot be represented in this installation"); + if (strcmp(s, "*t") == 0) { + lua_createtable(L, 0, 9); /* 9 = number of fields */ + setallfields(L, stm); + } + else { + char cc[4]; /* buffer for individual conversion specifiers */ + luaL_Buffer b; + cc[0] = '%'; + luaL_buffinit(L, &b); + while (s < se) { + if (*s != '%') /* not a conversion specifier? */ + luaL_addchar(&b, *s++); + else { + size_t reslen; + char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); + s++; /* skip '%' */ + s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */ + reslen = strftime(buff, SIZETIMEFMT, cc, stm); + luaL_addsize(&b, reslen); + } + } + luaL_pushresult(&b); + } + return 1; +} + + +static int os_time (lua_State *L) { + time_t t; + if (lua_isnoneornil(L, 1)) /* called without args? */ + t = time(NULL); /* get current time */ + else { + struct tm ts; + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); /* make sure table is at the top */ + ts.tm_year = getfield(L, "year", -1, 1900); + ts.tm_mon = getfield(L, "month", -1, 1); + ts.tm_mday = getfield(L, "day", -1, 0); + ts.tm_hour = getfield(L, "hour", 12, 0); + ts.tm_min = getfield(L, "min", 0, 0); + ts.tm_sec = getfield(L, "sec", 0, 0); + ts.tm_isdst = getboolfield(L, "isdst"); + t = mktime(&ts); + setallfields(L, &ts); /* update fields with normalized values */ + } + if (t != (time_t)(l_timet)t || t == (time_t)(-1)) + return luaL_error(L, + "time result cannot be represented in this installation"); + l_pushtime(L, t); + return 1; +} + + +static int os_difftime (lua_State *L) { + time_t t1 = l_checktime(L, 1); + time_t t2 = l_checktime(L, 2); + lua_pushnumber(L, (lua_Number)difftime(t1, t2)); + return 1; +} + +/* }====================================================== */ + + +static int os_setlocale (lua_State *L) { + static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, + LC_NUMERIC, LC_TIME}; + static const char *const catnames[] = {"all", "collate", "ctype", "monetary", + "numeric", "time", NULL}; + const char *l = luaL_optstring(L, 1, NULL); + int op = luaL_checkoption(L, 2, "all", catnames); + lua_pushstring(L, setlocale(cat[op], l)); + return 1; +} + + +static int os_exit (lua_State *L) { + int status; + if (lua_isboolean(L, 1)) + status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); + else + status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS); + if (lua_toboolean(L, 2)) + lua_close(L); + if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ + return 0; +} + + +static const luaL_Reg syslib[] = { + {"clock", os_clock}, + {"date", os_date}, + {"difftime", os_difftime}, + {"execute", os_execute}, + {"exit", os_exit}, + {"getenv", os_getenv}, + {"remove", os_remove}, + {"rename", os_rename}, + {"setlocale", os_setlocale}, + {"time", os_time}, + {"tmpname", os_tmpname}, + {NULL, NULL} +}; + +/* }====================================================== */ + + + +LUAMOD_API int luaopen_os (lua_State *L) { + luaL_newlib(L, syslib); + return 1; +} + diff --git a/vendor/lua-src/lua-5.4.6/lparser.c b/vendor/lua-src/lua-5.4.6/lparser.c new file mode 100644 index 0000000000000..b745f236f0682 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lparser.c @@ -0,0 +1,1967 @@ +/* +** $Id: lparser.c $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + +#define lparser_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" + + + +/* maximum number of local variables per function (must be smaller + than 250, due to the bytecode format) */ +#define MAXVARS 200 + + +#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) + + +/* because all strings are unified by the scanner, the parser + can use pointer equality for string equality */ +#define eqstr(a,b) ((a) == (b)) + + +/* +** nodes for block list (list of active blocks) +*/ +typedef struct BlockCnt { + struct BlockCnt *previous; /* chain */ + int firstlabel; /* index of first label in this block */ + int firstgoto; /* index of first pending goto in this block */ + lu_byte nactvar; /* # active locals outside the block */ + lu_byte upval; /* true if some variable in the block is an upvalue */ + lu_byte isloop; /* true if 'block' is a loop */ + lu_byte insidetbc; /* true if inside the scope of a to-be-closed var. */ +} BlockCnt; + + + +/* +** prototypes for recursive non-terminal functions +*/ +static void statement (LexState *ls); +static void expr (LexState *ls, expdesc *v); + + +static l_noret error_expected (LexState *ls, int token) { + luaX_syntaxerror(ls, + luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); +} + + +static l_noret errorlimit (FuncState *fs, int limit, const char *what) { + lua_State *L = fs->ls->L; + const char *msg; + int line = fs->f->linedefined; + const char *where = (line == 0) + ? "main function" + : luaO_pushfstring(L, "function at line %d", line); + msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s", + what, limit, where); + luaX_syntaxerror(fs->ls, msg); +} + + +static void checklimit (FuncState *fs, int v, int l, const char *what) { + if (v > l) errorlimit(fs, l, what); +} + + +/* +** Test whether next token is 'c'; if so, skip it. +*/ +static int testnext (LexState *ls, int c) { + if (ls->t.token == c) { + luaX_next(ls); + return 1; + } + else return 0; +} + + +/* +** Check that next token is 'c'. +*/ +static void check (LexState *ls, int c) { + if (ls->t.token != c) + error_expected(ls, c); +} + + +/* +** Check that next token is 'c' and skip it. +*/ +static void checknext (LexState *ls, int c) { + check(ls, c); + luaX_next(ls); +} + + +#define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } + + +/* +** Check that next token is 'what' and skip it. In case of error, +** raise an error that the expected 'what' should match a 'who' +** in line 'where' (if that is not the current line). +*/ +static void check_match (LexState *ls, int what, int who, int where) { + if (l_unlikely(!testnext(ls, what))) { + if (where == ls->linenumber) /* all in the same line? */ + error_expected(ls, what); /* do not need a complex message */ + else { + luaX_syntaxerror(ls, luaO_pushfstring(ls->L, + "%s expected (to close %s at line %d)", + luaX_token2str(ls, what), luaX_token2str(ls, who), where)); + } + } +} + + +static TString *str_checkname (LexState *ls) { + TString *ts; + check(ls, TK_NAME); + ts = ls->t.seminfo.ts; + luaX_next(ls); + return ts; +} + + +static void init_exp (expdesc *e, expkind k, int i) { + e->f = e->t = NO_JUMP; + e->k = k; + e->u.info = i; +} + + +static void codestring (expdesc *e, TString *s) { + e->f = e->t = NO_JUMP; + e->k = VKSTR; + e->u.strval = s; +} + + +static void codename (LexState *ls, expdesc *e) { + codestring(e, str_checkname(ls)); +} + + +/* +** Register a new local variable in the active 'Proto' (for debug +** information). +*/ +static int registerlocalvar (LexState *ls, FuncState *fs, TString *varname) { + Proto *f = fs->f; + int oldsize = f->sizelocvars; + luaM_growvector(ls->L, f->locvars, fs->ndebugvars, f->sizelocvars, + LocVar, SHRT_MAX, "local variables"); + while (oldsize < f->sizelocvars) + f->locvars[oldsize++].varname = NULL; + f->locvars[fs->ndebugvars].varname = varname; + f->locvars[fs->ndebugvars].startpc = fs->pc; + luaC_objbarrier(ls->L, f, varname); + return fs->ndebugvars++; +} + + +/* +** Create a new local variable with the given 'name'. Return its index +** in the function. +*/ +static int new_localvar (LexState *ls, TString *name) { + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Dyndata *dyd = ls->dyd; + Vardesc *var; + checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, + MAXVARS, "local variables"); + luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, + dyd->actvar.size, Vardesc, USHRT_MAX, "local variables"); + var = &dyd->actvar.arr[dyd->actvar.n++]; + var->vd.kind = VDKREG; /* default */ + var->vd.name = name; + return dyd->actvar.n - 1 - fs->firstlocal; +} + +#define new_localvarliteral(ls,v) \ + new_localvar(ls, \ + luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1)); + + + +/* +** Return the "variable description" (Vardesc) of a given variable. +** (Unless noted otherwise, all variables are referred to by their +** compiler indices.) +*/ +static Vardesc *getlocalvardesc (FuncState *fs, int vidx) { + return &fs->ls->dyd->actvar.arr[fs->firstlocal + vidx]; +} + + +/* +** Convert 'nvar', a compiler index level, to its corresponding +** register. For that, search for the highest variable below that level +** that is in a register and uses its register index ('ridx') plus one. +*/ +static int reglevel (FuncState *fs, int nvar) { + while (nvar-- > 0) { + Vardesc *vd = getlocalvardesc(fs, nvar); /* get previous variable */ + if (vd->vd.kind != RDKCTC) /* is in a register? */ + return vd->vd.ridx + 1; + } + return 0; /* no variables in registers */ +} + + +/* +** Return the number of variables in the register stack for the given +** function. +*/ +int luaY_nvarstack (FuncState *fs) { + return reglevel(fs, fs->nactvar); +} + + +/* +** Get the debug-information entry for current variable 'vidx'. +*/ +static LocVar *localdebuginfo (FuncState *fs, int vidx) { + Vardesc *vd = getlocalvardesc(fs, vidx); + if (vd->vd.kind == RDKCTC) + return NULL; /* no debug info. for constants */ + else { + int idx = vd->vd.pidx; + lua_assert(idx < fs->ndebugvars); + return &fs->f->locvars[idx]; + } +} + + +/* +** Create an expression representing variable 'vidx' +*/ +static void init_var (FuncState *fs, expdesc *e, int vidx) { + e->f = e->t = NO_JUMP; + e->k = VLOCAL; + e->u.var.vidx = vidx; + e->u.var.ridx = getlocalvardesc(fs, vidx)->vd.ridx; +} + + +/* +** Raises an error if variable described by 'e' is read only +*/ +static void check_readonly (LexState *ls, expdesc *e) { + FuncState *fs = ls->fs; + TString *varname = NULL; /* to be set if variable is const */ + switch (e->k) { + case VCONST: { + varname = ls->dyd->actvar.arr[e->u.info].vd.name; + break; + } + case VLOCAL: { + Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx); + if (vardesc->vd.kind != VDKREG) /* not a regular variable? */ + varname = vardesc->vd.name; + break; + } + case VUPVAL: { + Upvaldesc *up = &fs->f->upvalues[e->u.info]; + if (up->kind != VDKREG) + varname = up->name; + break; + } + default: + return; /* other cases cannot be read-only */ + } + if (varname) { + const char *msg = luaO_pushfstring(ls->L, + "attempt to assign to const variable '%s'", getstr(varname)); + luaK_semerror(ls, msg); /* error */ + } +} + + +/* +** Start the scope for the last 'nvars' created variables. +*/ +static void adjustlocalvars (LexState *ls, int nvars) { + FuncState *fs = ls->fs; + int reglevel = luaY_nvarstack(fs); + int i; + for (i = 0; i < nvars; i++) { + int vidx = fs->nactvar++; + Vardesc *var = getlocalvardesc(fs, vidx); + var->vd.ridx = reglevel++; + var->vd.pidx = registerlocalvar(ls, fs, var->vd.name); + } +} + + +/* +** Close the scope for all variables up to level 'tolevel'. +** (debug info.) +*/ +static void removevars (FuncState *fs, int tolevel) { + fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); + while (fs->nactvar > tolevel) { + LocVar *var = localdebuginfo(fs, --fs->nactvar); + if (var) /* does it have debug information? */ + var->endpc = fs->pc; + } +} + + +/* +** Search the upvalues of the function 'fs' for one +** with the given 'name'. +*/ +static int searchupvalue (FuncState *fs, TString *name) { + int i; + Upvaldesc *up = fs->f->upvalues; + for (i = 0; i < fs->nups; i++) { + if (eqstr(up[i].name, name)) return i; + } + return -1; /* not found */ +} + + +static Upvaldesc *allocupvalue (FuncState *fs) { + Proto *f = fs->f; + int oldsize = f->sizeupvalues; + checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); + luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, + Upvaldesc, MAXUPVAL, "upvalues"); + while (oldsize < f->sizeupvalues) + f->upvalues[oldsize++].name = NULL; + return &f->upvalues[fs->nups++]; +} + + +static int newupvalue (FuncState *fs, TString *name, expdesc *v) { + Upvaldesc *up = allocupvalue(fs); + FuncState *prev = fs->prev; + if (v->k == VLOCAL) { + up->instack = 1; + up->idx = v->u.var.ridx; + up->kind = getlocalvardesc(prev, v->u.var.vidx)->vd.kind; + lua_assert(eqstr(name, getlocalvardesc(prev, v->u.var.vidx)->vd.name)); + } + else { + up->instack = 0; + up->idx = cast_byte(v->u.info); + up->kind = prev->f->upvalues[v->u.info].kind; + lua_assert(eqstr(name, prev->f->upvalues[v->u.info].name)); + } + up->name = name; + luaC_objbarrier(fs->ls->L, fs->f, name); + return fs->nups - 1; +} + + +/* +** Look for an active local variable with the name 'n' in the +** function 'fs'. If found, initialize 'var' with it and return +** its expression kind; otherwise return -1. +*/ +static int searchvar (FuncState *fs, TString *n, expdesc *var) { + int i; + for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { + Vardesc *vd = getlocalvardesc(fs, i); + if (eqstr(n, vd->vd.name)) { /* found? */ + if (vd->vd.kind == RDKCTC) /* compile-time constant? */ + init_exp(var, VCONST, fs->firstlocal + i); + else /* real variable */ + init_var(fs, var, i); + return var->k; + } + } + return -1; /* not found */ +} + + +/* +** Mark block where variable at given level was defined +** (to emit close instructions later). +*/ +static void markupval (FuncState *fs, int level) { + BlockCnt *bl = fs->bl; + while (bl->nactvar > level) + bl = bl->previous; + bl->upval = 1; + fs->needclose = 1; +} + + +/* +** Mark that current block has a to-be-closed variable. +*/ +static void marktobeclosed (FuncState *fs) { + BlockCnt *bl = fs->bl; + bl->upval = 1; + bl->insidetbc = 1; + fs->needclose = 1; +} + + +/* +** Find a variable with the given name 'n'. If it is an upvalue, add +** this upvalue into all intermediate functions. If it is a global, set +** 'var' as 'void' as a flag. +*/ +static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { + if (fs == NULL) /* no more levels? */ + init_exp(var, VVOID, 0); /* default is global */ + else { + int v = searchvar(fs, n, var); /* look up locals at current level */ + if (v >= 0) { /* found? */ + if (v == VLOCAL && !base) + markupval(fs, var->u.var.vidx); /* local will be used as an upval */ + } + else { /* not found as local at current level; try upvalues */ + int idx = searchupvalue(fs, n); /* try existing upvalues */ + if (idx < 0) { /* not found? */ + singlevaraux(fs->prev, n, var, 0); /* try upper levels */ + if (var->k == VLOCAL || var->k == VUPVAL) /* local or upvalue? */ + idx = newupvalue(fs, n, var); /* will be a new upvalue */ + else /* it is a global or a constant */ + return; /* don't need to do anything at this level */ + } + init_exp(var, VUPVAL, idx); /* new or old upvalue */ + } + } +} + + +/* +** Find a variable with the given name 'n', handling global variables +** too. +*/ +static void singlevar (LexState *ls, expdesc *var) { + TString *varname = str_checkname(ls); + FuncState *fs = ls->fs; + singlevaraux(fs, varname, var, 1); + if (var->k == VVOID) { /* global name? */ + expdesc key; + singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ + lua_assert(var->k != VVOID); /* this one must exist */ + luaK_exp2anyregup(fs, var); /* but could be a constant */ + codestring(&key, varname); /* key is variable name */ + luaK_indexed(fs, var, &key); /* env[varname] */ + } +} + + +/* +** Adjust the number of results from an expression list 'e' with 'nexps' +** expressions to 'nvars' values. +*/ +static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { + FuncState *fs = ls->fs; + int needed = nvars - nexps; /* extra values needed */ + if (hasmultret(e->k)) { /* last expression has multiple returns? */ + int extra = needed + 1; /* discount last expression itself */ + if (extra < 0) + extra = 0; + luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ + } + else { + if (e->k != VVOID) /* at least one expression? */ + luaK_exp2nextreg(fs, e); /* close last expression */ + if (needed > 0) /* missing values? */ + luaK_nil(fs, fs->freereg, needed); /* complete with nils */ + } + if (needed > 0) + luaK_reserveregs(fs, needed); /* registers for extra values */ + else /* adding 'needed' is actually a subtraction */ + fs->freereg += needed; /* remove extra values */ +} + + +#define enterlevel(ls) luaE_incCstack(ls->L) + + +#define leavelevel(ls) ((ls)->L->nCcalls--) + + +/* +** Generates an error that a goto jumps into the scope of some +** local variable. +*/ +static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) { + const char *varname = getstr(getlocalvardesc(ls->fs, gt->nactvar)->vd.name); + const char *msg = " at line %d jumps into the scope of local '%s'"; + msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line, varname); + luaK_semerror(ls, msg); /* raise the error */ +} + + +/* +** Solves the goto at index 'g' to given 'label' and removes it +** from the list of pending gotos. +** If it jumps into the scope of some variable, raises an error. +*/ +static void solvegoto (LexState *ls, int g, Labeldesc *label) { + int i; + Labellist *gl = &ls->dyd->gt; /* list of gotos */ + Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */ + lua_assert(eqstr(gt->name, label->name)); + if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */ + jumpscopeerror(ls, gt); + luaK_patchlist(ls->fs, gt->pc, label->pc); + for (i = g; i < gl->n - 1; i++) /* remove goto from pending list */ + gl->arr[i] = gl->arr[i + 1]; + gl->n--; +} + + +/* +** Search for an active label with the given name. +*/ +static Labeldesc *findlabel (LexState *ls, TString *name) { + int i; + Dyndata *dyd = ls->dyd; + /* check labels in current function for a match */ + for (i = ls->fs->firstlabel; i < dyd->label.n; i++) { + Labeldesc *lb = &dyd->label.arr[i]; + if (eqstr(lb->name, name)) /* correct label? */ + return lb; + } + return NULL; /* label not found */ +} + + +/* +** Adds a new label/goto in the corresponding list. +*/ +static int newlabelentry (LexState *ls, Labellist *l, TString *name, + int line, int pc) { + int n = l->n; + luaM_growvector(ls->L, l->arr, n, l->size, + Labeldesc, SHRT_MAX, "labels/gotos"); + l->arr[n].name = name; + l->arr[n].line = line; + l->arr[n].nactvar = ls->fs->nactvar; + l->arr[n].close = 0; + l->arr[n].pc = pc; + l->n = n + 1; + return n; +} + + +static int newgotoentry (LexState *ls, TString *name, int line, int pc) { + return newlabelentry(ls, &ls->dyd->gt, name, line, pc); +} + + +/* +** Solves forward jumps. Check whether new label 'lb' matches any +** pending gotos in current block and solves them. Return true +** if any of the gotos need to close upvalues. +*/ +static int solvegotos (LexState *ls, Labeldesc *lb) { + Labellist *gl = &ls->dyd->gt; + int i = ls->fs->bl->firstgoto; + int needsclose = 0; + while (i < gl->n) { + if (eqstr(gl->arr[i].name, lb->name)) { + needsclose |= gl->arr[i].close; + solvegoto(ls, i, lb); /* will remove 'i' from the list */ + } + else + i++; + } + return needsclose; +} + + +/* +** Create a new label with the given 'name' at the given 'line'. +** 'last' tells whether label is the last non-op statement in its +** block. Solves all pending gotos to this new label and adds +** a close instruction if necessary. +** Returns true iff it added a close instruction. +*/ +static int createlabel (LexState *ls, TString *name, int line, + int last) { + FuncState *fs = ls->fs; + Labellist *ll = &ls->dyd->label; + int l = newlabelentry(ls, ll, name, line, luaK_getlabel(fs)); + if (last) { /* label is last no-op statement in the block? */ + /* assume that locals are already out of scope */ + ll->arr[l].nactvar = fs->bl->nactvar; + } + if (solvegotos(ls, &ll->arr[l])) { /* need close? */ + luaK_codeABC(fs, OP_CLOSE, luaY_nvarstack(fs), 0, 0); + return 1; + } + return 0; +} + + +/* +** Adjust pending gotos to outer level of a block. +*/ +static void movegotosout (FuncState *fs, BlockCnt *bl) { + int i; + Labellist *gl = &fs->ls->dyd->gt; + /* correct pending gotos to current block */ + for (i = bl->firstgoto; i < gl->n; i++) { /* for each pending goto */ + Labeldesc *gt = &gl->arr[i]; + /* leaving a variable scope? */ + if (reglevel(fs, gt->nactvar) > reglevel(fs, bl->nactvar)) + gt->close |= bl->upval; /* jump may need a close */ + gt->nactvar = bl->nactvar; /* update goto level */ + } +} + + +static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { + bl->isloop = isloop; + bl->nactvar = fs->nactvar; + bl->firstlabel = fs->ls->dyd->label.n; + bl->firstgoto = fs->ls->dyd->gt.n; + bl->upval = 0; + bl->insidetbc = (fs->bl != NULL && fs->bl->insidetbc); + bl->previous = fs->bl; + fs->bl = bl; + lua_assert(fs->freereg == luaY_nvarstack(fs)); +} + + +/* +** generates an error for an undefined 'goto'. +*/ +static l_noret undefgoto (LexState *ls, Labeldesc *gt) { + const char *msg; + if (eqstr(gt->name, luaS_newliteral(ls->L, "break"))) { + msg = "break outside loop at line %d"; + msg = luaO_pushfstring(ls->L, msg, gt->line); + } + else { + msg = "no visible label '%s' for at line %d"; + msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); + } + luaK_semerror(ls, msg); +} + + +static void leaveblock (FuncState *fs) { + BlockCnt *bl = fs->bl; + LexState *ls = fs->ls; + int hasclose = 0; + int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */ + removevars(fs, bl->nactvar); /* remove block locals */ + lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */ + if (bl->isloop) /* has to fix pending breaks? */ + hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0); + if (!hasclose && bl->previous && bl->upval) /* still need a 'close'? */ + luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0); + fs->freereg = stklevel; /* free registers */ + ls->dyd->label.n = bl->firstlabel; /* remove local labels */ + fs->bl = bl->previous; /* current block now is previous one */ + if (bl->previous) /* was it a nested block? */ + movegotosout(fs, bl); /* update pending gotos to enclosing block */ + else { + if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */ + undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ + } +} + + +/* +** adds a new prototype into list of prototypes +*/ +static Proto *addprototype (LexState *ls) { + Proto *clp; + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Proto *f = fs->f; /* prototype of current function */ + if (fs->np >= f->sizep) { + int oldsize = f->sizep; + luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); + while (oldsize < f->sizep) + f->p[oldsize++] = NULL; + } + f->p[fs->np++] = clp = luaF_newproto(L); + luaC_objbarrier(L, f, clp); + return clp; +} + + +/* +** codes instruction to create new closure in parent function. +** The OP_CLOSURE instruction uses the last available register, +** so that, if it invokes the GC, the GC knows which registers +** are in use at that time. + +*/ +static void codeclosure (LexState *ls, expdesc *v) { + FuncState *fs = ls->fs->prev; + init_exp(v, VRELOC, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); + luaK_exp2nextreg(fs, v); /* fix it at the last register */ +} + + +static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { + Proto *f = fs->f; + fs->prev = ls->fs; /* linked list of funcstates */ + fs->ls = ls; + ls->fs = fs; + fs->pc = 0; + fs->previousline = f->linedefined; + fs->iwthabs = 0; + fs->lasttarget = 0; + fs->freereg = 0; + fs->nk = 0; + fs->nabslineinfo = 0; + fs->np = 0; + fs->nups = 0; + fs->ndebugvars = 0; + fs->nactvar = 0; + fs->needclose = 0; + fs->firstlocal = ls->dyd->actvar.n; + fs->firstlabel = ls->dyd->label.n; + fs->bl = NULL; + f->source = ls->source; + luaC_objbarrier(ls->L, f, f->source); + f->maxstacksize = 2; /* registers 0/1 are always valid */ + enterblock(fs, bl, 0); +} + + +static void close_func (LexState *ls) { + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Proto *f = fs->f; + luaK_ret(fs, luaY_nvarstack(fs), 0); /* final return */ + leaveblock(fs); + lua_assert(fs->bl == NULL); + luaK_finish(fs); + luaM_shrinkvector(L, f->code, f->sizecode, fs->pc, Instruction); + luaM_shrinkvector(L, f->lineinfo, f->sizelineinfo, fs->pc, ls_byte); + luaM_shrinkvector(L, f->abslineinfo, f->sizeabslineinfo, + fs->nabslineinfo, AbsLineInfo); + luaM_shrinkvector(L, f->k, f->sizek, fs->nk, TValue); + luaM_shrinkvector(L, f->p, f->sizep, fs->np, Proto *); + luaM_shrinkvector(L, f->locvars, f->sizelocvars, fs->ndebugvars, LocVar); + luaM_shrinkvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); + ls->fs = fs->prev; + luaC_checkGC(L); +} + + + +/*============================================================*/ +/* GRAMMAR RULES */ +/*============================================================*/ + + +/* +** check whether current token is in the follow set of a block. +** 'until' closes syntactical blocks, but do not close scope, +** so it is handled in separate. +*/ +static int block_follow (LexState *ls, int withuntil) { + switch (ls->t.token) { + case TK_ELSE: case TK_ELSEIF: + case TK_END: case TK_EOS: + return 1; + case TK_UNTIL: return withuntil; + default: return 0; + } +} + + +static void statlist (LexState *ls) { + /* statlist -> { stat [';'] } */ + while (!block_follow(ls, 1)) { + if (ls->t.token == TK_RETURN) { + statement(ls); + return; /* 'return' must be last statement */ + } + statement(ls); + } +} + + +static void fieldsel (LexState *ls, expdesc *v) { + /* fieldsel -> ['.' | ':'] NAME */ + FuncState *fs = ls->fs; + expdesc key; + luaK_exp2anyregup(fs, v); + luaX_next(ls); /* skip the dot or colon */ + codename(ls, &key); + luaK_indexed(fs, v, &key); +} + + +static void yindex (LexState *ls, expdesc *v) { + /* index -> '[' expr ']' */ + luaX_next(ls); /* skip the '[' */ + expr(ls, v); + luaK_exp2val(ls->fs, v); + checknext(ls, ']'); +} + + +/* +** {====================================================================== +** Rules for Constructors +** ======================================================================= +*/ + + +typedef struct ConsControl { + expdesc v; /* last list item read */ + expdesc *t; /* table descriptor */ + int nh; /* total number of 'record' elements */ + int na; /* number of array elements already stored */ + int tostore; /* number of array elements pending to be stored */ +} ConsControl; + + +static void recfield (LexState *ls, ConsControl *cc) { + /* recfield -> (NAME | '['exp']') = exp */ + FuncState *fs = ls->fs; + int reg = ls->fs->freereg; + expdesc tab, key, val; + if (ls->t.token == TK_NAME) { + checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); + codename(ls, &key); + } + else /* ls->t.token == '[' */ + yindex(ls, &key); + cc->nh++; + checknext(ls, '='); + tab = *cc->t; + luaK_indexed(fs, &tab, &key); + expr(ls, &val); + luaK_storevar(fs, &tab, &val); + fs->freereg = reg; /* free registers */ +} + + +static void closelistfield (FuncState *fs, ConsControl *cc) { + if (cc->v.k == VVOID) return; /* there is no list item */ + luaK_exp2nextreg(fs, &cc->v); + cc->v.k = VVOID; + if (cc->tostore == LFIELDS_PER_FLUSH) { + luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ + cc->na += cc->tostore; + cc->tostore = 0; /* no more items pending */ + } +} + + +static void lastlistfield (FuncState *fs, ConsControl *cc) { + if (cc->tostore == 0) return; + if (hasmultret(cc->v.k)) { + luaK_setmultret(fs, &cc->v); + luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET); + cc->na--; /* do not count last expression (unknown number of elements) */ + } + else { + if (cc->v.k != VVOID) + luaK_exp2nextreg(fs, &cc->v); + luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); + } + cc->na += cc->tostore; +} + + +static void listfield (LexState *ls, ConsControl *cc) { + /* listfield -> exp */ + expr(ls, &cc->v); + cc->tostore++; +} + + +static void field (LexState *ls, ConsControl *cc) { + /* field -> listfield | recfield */ + switch(ls->t.token) { + case TK_NAME: { /* may be 'listfield' or 'recfield' */ + if (luaX_lookahead(ls) != '=') /* expression? */ + listfield(ls, cc); + else + recfield(ls, cc); + break; + } + case '[': { + recfield(ls, cc); + break; + } + default: { + listfield(ls, cc); + break; + } + } +} + + +static void constructor (LexState *ls, expdesc *t) { + /* constructor -> '{' [ field { sep field } [sep] ] '}' + sep -> ',' | ';' */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); + ConsControl cc; + luaK_code(fs, 0); /* space for extra arg. */ + cc.na = cc.nh = cc.tostore = 0; + cc.t = t; + init_exp(t, VNONRELOC, fs->freereg); /* table will be at stack top */ + luaK_reserveregs(fs, 1); + init_exp(&cc.v, VVOID, 0); /* no value (yet) */ + checknext(ls, '{'); + do { + lua_assert(cc.v.k == VVOID || cc.tostore > 0); + if (ls->t.token == '}') break; + closelistfield(fs, &cc); + field(ls, &cc); + } while (testnext(ls, ',') || testnext(ls, ';')); + check_match(ls, '}', '{', line); + lastlistfield(fs, &cc); + luaK_settablesize(fs, pc, t->u.info, cc.na, cc.nh); +} + +/* }====================================================================== */ + + +static void setvararg (FuncState *fs, int nparams) { + fs->f->is_vararg = 1; + luaK_codeABC(fs, OP_VARARGPREP, nparams, 0, 0); +} + + +static void parlist (LexState *ls) { + /* parlist -> [ {NAME ','} (NAME | '...') ] */ + FuncState *fs = ls->fs; + Proto *f = fs->f; + int nparams = 0; + int isvararg = 0; + if (ls->t.token != ')') { /* is 'parlist' not empty? */ + do { + switch (ls->t.token) { + case TK_NAME: { + new_localvar(ls, str_checkname(ls)); + nparams++; + break; + } + case TK_DOTS: { + luaX_next(ls); + isvararg = 1; + break; + } + default: luaX_syntaxerror(ls, " or '...' expected"); + } + } while (!isvararg && testnext(ls, ',')); + } + adjustlocalvars(ls, nparams); + f->numparams = cast_byte(fs->nactvar); + if (isvararg) + setvararg(fs, f->numparams); /* declared vararg */ + luaK_reserveregs(fs, fs->nactvar); /* reserve registers for parameters */ +} + + +static void body (LexState *ls, expdesc *e, int ismethod, int line) { + /* body -> '(' parlist ')' block END */ + FuncState new_fs; + BlockCnt bl; + new_fs.f = addprototype(ls); + new_fs.f->linedefined = line; + open_func(ls, &new_fs, &bl); + checknext(ls, '('); + if (ismethod) { + new_localvarliteral(ls, "self"); /* create 'self' parameter */ + adjustlocalvars(ls, 1); + } + parlist(ls); + checknext(ls, ')'); + statlist(ls); + new_fs.f->lastlinedefined = ls->linenumber; + check_match(ls, TK_END, TK_FUNCTION, line); + codeclosure(ls, e); + close_func(ls); +} + + +static int explist (LexState *ls, expdesc *v) { + /* explist -> expr { ',' expr } */ + int n = 1; /* at least one expression */ + expr(ls, v); + while (testnext(ls, ',')) { + luaK_exp2nextreg(ls->fs, v); + expr(ls, v); + n++; + } + return n; +} + + +static void funcargs (LexState *ls, expdesc *f, int line) { + FuncState *fs = ls->fs; + expdesc args; + int base, nparams; + switch (ls->t.token) { + case '(': { /* funcargs -> '(' [ explist ] ')' */ + luaX_next(ls); + if (ls->t.token == ')') /* arg list is empty? */ + args.k = VVOID; + else { + explist(ls, &args); + if (hasmultret(args.k)) + luaK_setmultret(fs, &args); + } + check_match(ls, ')', '(', line); + break; + } + case '{': { /* funcargs -> constructor */ + constructor(ls, &args); + break; + } + case TK_STRING: { /* funcargs -> STRING */ + codestring(&args, ls->t.seminfo.ts); + luaX_next(ls); /* must use 'seminfo' before 'next' */ + break; + } + default: { + luaX_syntaxerror(ls, "function arguments expected"); + } + } + lua_assert(f->k == VNONRELOC); + base = f->u.info; /* base register for call */ + if (hasmultret(args.k)) + nparams = LUA_MULTRET; /* open call */ + else { + if (args.k != VVOID) + luaK_exp2nextreg(fs, &args); /* close last argument */ + nparams = fs->freereg - (base+1); + } + init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); + luaK_fixline(fs, line); + fs->freereg = base+1; /* call remove function and arguments and leaves + (unless changed) one result */ +} + + + + +/* +** {====================================================================== +** Expression parsing +** ======================================================================= +*/ + + +static void primaryexp (LexState *ls, expdesc *v) { + /* primaryexp -> NAME | '(' expr ')' */ + switch (ls->t.token) { + case '(': { + int line = ls->linenumber; + luaX_next(ls); + expr(ls, v); + check_match(ls, ')', '(', line); + luaK_dischargevars(ls->fs, v); + return; + } + case TK_NAME: { + singlevar(ls, v); + return; + } + default: { + luaX_syntaxerror(ls, "unexpected symbol"); + } + } +} + + +static void suffixedexp (LexState *ls, expdesc *v) { + /* suffixedexp -> + primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + primaryexp(ls, v); + for (;;) { + switch (ls->t.token) { + case '.': { /* fieldsel */ + fieldsel(ls, v); + break; + } + case '[': { /* '[' exp ']' */ + expdesc key; + luaK_exp2anyregup(fs, v); + yindex(ls, &key); + luaK_indexed(fs, v, &key); + break; + } + case ':': { /* ':' NAME funcargs */ + expdesc key; + luaX_next(ls); + codename(ls, &key); + luaK_self(fs, v, &key); + funcargs(ls, v, line); + break; + } + case '(': case TK_STRING: case '{': { /* funcargs */ + luaK_exp2nextreg(fs, v); + funcargs(ls, v, line); + break; + } + default: return; + } + } +} + + +static void simpleexp (LexState *ls, expdesc *v) { + /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... | + constructor | FUNCTION body | suffixedexp */ + switch (ls->t.token) { + case TK_FLT: { + init_exp(v, VKFLT, 0); + v->u.nval = ls->t.seminfo.r; + break; + } + case TK_INT: { + init_exp(v, VKINT, 0); + v->u.ival = ls->t.seminfo.i; + break; + } + case TK_STRING: { + codestring(v, ls->t.seminfo.ts); + break; + } + case TK_NIL: { + init_exp(v, VNIL, 0); + break; + } + case TK_TRUE: { + init_exp(v, VTRUE, 0); + break; + } + case TK_FALSE: { + init_exp(v, VFALSE, 0); + break; + } + case TK_DOTS: { /* vararg */ + FuncState *fs = ls->fs; + check_condition(ls, fs->f->is_vararg, + "cannot use '...' outside a vararg function"); + init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 0, 1)); + break; + } + case '{': { /* constructor */ + constructor(ls, v); + return; + } + case TK_FUNCTION: { + luaX_next(ls); + body(ls, v, 0, ls->linenumber); + return; + } + default: { + suffixedexp(ls, v); + return; + } + } + luaX_next(ls); +} + + +static UnOpr getunopr (int op) { + switch (op) { + case TK_NOT: return OPR_NOT; + case '-': return OPR_MINUS; + case '~': return OPR_BNOT; + case '#': return OPR_LEN; + default: return OPR_NOUNOPR; + } +} + + +static BinOpr getbinopr (int op) { + switch (op) { + case '+': return OPR_ADD; + case '-': return OPR_SUB; + case '*': return OPR_MUL; + case '%': return OPR_MOD; + case '^': return OPR_POW; + case '/': return OPR_DIV; + case TK_IDIV: return OPR_IDIV; + case '&': return OPR_BAND; + case '|': return OPR_BOR; + case '~': return OPR_BXOR; + case TK_SHL: return OPR_SHL; + case TK_SHR: return OPR_SHR; + case TK_CONCAT: return OPR_CONCAT; + case TK_NE: return OPR_NE; + case TK_EQ: return OPR_EQ; + case '<': return OPR_LT; + case TK_LE: return OPR_LE; + case '>': return OPR_GT; + case TK_GE: return OPR_GE; + case TK_AND: return OPR_AND; + case TK_OR: return OPR_OR; + default: return OPR_NOBINOPR; + } +} + + +/* +** Priority table for binary operators. +*/ +static const struct { + lu_byte left; /* left priority for each binary operator */ + lu_byte right; /* right priority */ +} priority[] = { /* ORDER OPR */ + {10, 10}, {10, 10}, /* '+' '-' */ + {11, 11}, {11, 11}, /* '*' '%' */ + {14, 13}, /* '^' (right associative) */ + {11, 11}, {11, 11}, /* '/' '//' */ + {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */ + {7, 7}, {7, 7}, /* '<<' '>>' */ + {9, 8}, /* '..' (right associative) */ + {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ + {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ + {2, 2}, {1, 1} /* and, or */ +}; + +#define UNARY_PRIORITY 12 /* priority for unary operators */ + + +/* +** subexpr -> (simpleexp | unop subexpr) { binop subexpr } +** where 'binop' is any binary operator with a priority higher than 'limit' +*/ +static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { + BinOpr op; + UnOpr uop; + enterlevel(ls); + uop = getunopr(ls->t.token); + if (uop != OPR_NOUNOPR) { /* prefix (unary) operator? */ + int line = ls->linenumber; + luaX_next(ls); /* skip operator */ + subexpr(ls, v, UNARY_PRIORITY); + luaK_prefix(ls->fs, uop, v, line); + } + else simpleexp(ls, v); + /* expand while operators have priorities higher than 'limit' */ + op = getbinopr(ls->t.token); + while (op != OPR_NOBINOPR && priority[op].left > limit) { + expdesc v2; + BinOpr nextop; + int line = ls->linenumber; + luaX_next(ls); /* skip operator */ + luaK_infix(ls->fs, op, v); + /* read sub-expression with higher priority */ + nextop = subexpr(ls, &v2, priority[op].right); + luaK_posfix(ls->fs, op, v, &v2, line); + op = nextop; + } + leavelevel(ls); + return op; /* return first untreated operator */ +} + + +static void expr (LexState *ls, expdesc *v) { + subexpr(ls, v, 0); +} + +/* }==================================================================== */ + + + +/* +** {====================================================================== +** Rules for Statements +** ======================================================================= +*/ + + +static void block (LexState *ls) { + /* block -> statlist */ + FuncState *fs = ls->fs; + BlockCnt bl; + enterblock(fs, &bl, 0); + statlist(ls); + leaveblock(fs); +} + + +/* +** structure to chain all variables in the left-hand side of an +** assignment +*/ +struct LHS_assign { + struct LHS_assign *prev; + expdesc v; /* variable (global, local, upvalue, or indexed) */ +}; + + +/* +** check whether, in an assignment to an upvalue/local variable, the +** upvalue/local variable is begin used in a previous assignment to a +** table. If so, save original upvalue/local value in a safe place and +** use this safe copy in the previous assignment. +*/ +static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { + FuncState *fs = ls->fs; + int extra = fs->freereg; /* eventual position to save local variable */ + int conflict = 0; + for (; lh; lh = lh->prev) { /* check all previous assignments */ + if (vkisindexed(lh->v.k)) { /* assignment to table field? */ + if (lh->v.k == VINDEXUP) { /* is table an upvalue? */ + if (v->k == VUPVAL && lh->v.u.ind.t == v->u.info) { + conflict = 1; /* table is the upvalue being assigned now */ + lh->v.k = VINDEXSTR; + lh->v.u.ind.t = extra; /* assignment will use safe copy */ + } + } + else { /* table is a register */ + if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.ridx) { + conflict = 1; /* table is the local being assigned now */ + lh->v.u.ind.t = extra; /* assignment will use safe copy */ + } + /* is index the local being assigned? */ + if (lh->v.k == VINDEXED && v->k == VLOCAL && + lh->v.u.ind.idx == v->u.var.ridx) { + conflict = 1; + lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ + } + } + } + } + if (conflict) { + /* copy upvalue/local value to a temporary (in position 'extra') */ + if (v->k == VLOCAL) + luaK_codeABC(fs, OP_MOVE, extra, v->u.var.ridx, 0); + else + luaK_codeABC(fs, OP_GETUPVAL, extra, v->u.info, 0); + luaK_reserveregs(fs, 1); + } +} + +/* +** Parse and compile a multiple assignment. The first "variable" +** (a 'suffixedexp') was already read by the caller. +** +** assignment -> suffixedexp restassign +** restassign -> ',' suffixedexp restassign | '=' explist +*/ +static void restassign (LexState *ls, struct LHS_assign *lh, int nvars) { + expdesc e; + check_condition(ls, vkisvar(lh->v.k), "syntax error"); + check_readonly(ls, &lh->v); + if (testnext(ls, ',')) { /* restassign -> ',' suffixedexp restassign */ + struct LHS_assign nv; + nv.prev = lh; + suffixedexp(ls, &nv.v); + if (!vkisindexed(nv.v.k)) + check_conflict(ls, lh, &nv.v); + enterlevel(ls); /* control recursion depth */ + restassign(ls, &nv, nvars+1); + leavelevel(ls); + } + else { /* restassign -> '=' explist */ + int nexps; + checknext(ls, '='); + nexps = explist(ls, &e); + if (nexps != nvars) + adjust_assign(ls, nvars, nexps, &e); + else { + luaK_setoneret(ls->fs, &e); /* close last expression */ + luaK_storevar(ls->fs, &lh->v, &e); + return; /* avoid default */ + } + } + init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ + luaK_storevar(ls->fs, &lh->v, &e); +} + + +static int cond (LexState *ls) { + /* cond -> exp */ + expdesc v; + expr(ls, &v); /* read condition */ + if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */ + luaK_goiftrue(ls->fs, &v); + return v.f; +} + + +static void gotostat (LexState *ls) { + FuncState *fs = ls->fs; + int line = ls->linenumber; + TString *name = str_checkname(ls); /* label's name */ + Labeldesc *lb = findlabel(ls, name); + if (lb == NULL) /* no label? */ + /* forward jump; will be resolved when the label is declared */ + newgotoentry(ls, name, line, luaK_jump(fs)); + else { /* found a label */ + /* backward jump; will be resolved here */ + int lblevel = reglevel(fs, lb->nactvar); /* label level */ + if (luaY_nvarstack(fs) > lblevel) /* leaving the scope of a variable? */ + luaK_codeABC(fs, OP_CLOSE, lblevel, 0, 0); + /* create jump and link it to the label */ + luaK_patchlist(fs, luaK_jump(fs), lb->pc); + } +} + + +/* +** Break statement. Semantically equivalent to "goto break". +*/ +static void breakstat (LexState *ls) { + int line = ls->linenumber; + luaX_next(ls); /* skip break */ + newgotoentry(ls, luaS_newliteral(ls->L, "break"), line, luaK_jump(ls->fs)); +} + + +/* +** Check whether there is already a label with the given 'name'. +*/ +static void checkrepeated (LexState *ls, TString *name) { + Labeldesc *lb = findlabel(ls, name); + if (l_unlikely(lb != NULL)) { /* already defined? */ + const char *msg = "label '%s' already defined on line %d"; + msg = luaO_pushfstring(ls->L, msg, getstr(name), lb->line); + luaK_semerror(ls, msg); /* error */ + } +} + + +static void labelstat (LexState *ls, TString *name, int line) { + /* label -> '::' NAME '::' */ + checknext(ls, TK_DBCOLON); /* skip double colon */ + while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) + statement(ls); /* skip other no-op statements */ + checkrepeated(ls, name); /* check for repeated labels */ + createlabel(ls, name, line, block_follow(ls, 0)); +} + + +static void whilestat (LexState *ls, int line) { + /* whilestat -> WHILE cond DO block END */ + FuncState *fs = ls->fs; + int whileinit; + int condexit; + BlockCnt bl; + luaX_next(ls); /* skip WHILE */ + whileinit = luaK_getlabel(fs); + condexit = cond(ls); + enterblock(fs, &bl, 1); + checknext(ls, TK_DO); + block(ls); + luaK_jumpto(fs, whileinit); + check_match(ls, TK_END, TK_WHILE, line); + leaveblock(fs); + luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ +} + + +static void repeatstat (LexState *ls, int line) { + /* repeatstat -> REPEAT block UNTIL cond */ + int condexit; + FuncState *fs = ls->fs; + int repeat_init = luaK_getlabel(fs); + BlockCnt bl1, bl2; + enterblock(fs, &bl1, 1); /* loop block */ + enterblock(fs, &bl2, 0); /* scope block */ + luaX_next(ls); /* skip REPEAT */ + statlist(ls); + check_match(ls, TK_UNTIL, TK_REPEAT, line); + condexit = cond(ls); /* read condition (inside scope block) */ + leaveblock(fs); /* finish scope */ + if (bl2.upval) { /* upvalues? */ + int exit = luaK_jump(fs); /* normal exit must jump over fix */ + luaK_patchtohere(fs, condexit); /* repetition must close upvalues */ + luaK_codeABC(fs, OP_CLOSE, reglevel(fs, bl2.nactvar), 0, 0); + condexit = luaK_jump(fs); /* repeat after closing upvalues */ + luaK_patchtohere(fs, exit); /* normal exit comes to here */ + } + luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ + leaveblock(fs); /* finish loop */ +} + + +/* +** Read an expression and generate code to put its results in next +** stack slot. +** +*/ +static void exp1 (LexState *ls) { + expdesc e; + expr(ls, &e); + luaK_exp2nextreg(ls->fs, &e); + lua_assert(e.k == VNONRELOC); +} + + +/* +** Fix for instruction at position 'pc' to jump to 'dest'. +** (Jump addresses are relative in Lua). 'back' true means +** a back jump. +*/ +static void fixforjump (FuncState *fs, int pc, int dest, int back) { + Instruction *jmp = &fs->f->code[pc]; + int offset = dest - (pc + 1); + if (back) + offset = -offset; + if (l_unlikely(offset > MAXARG_Bx)) + luaX_syntaxerror(fs->ls, "control structure too long"); + SETARG_Bx(*jmp, offset); +} + + +/* +** Generate code for a 'for' loop. +*/ +static void forbody (LexState *ls, int base, int line, int nvars, int isgen) { + /* forbody -> DO block */ + static const OpCode forprep[2] = {OP_FORPREP, OP_TFORPREP}; + static const OpCode forloop[2] = {OP_FORLOOP, OP_TFORLOOP}; + BlockCnt bl; + FuncState *fs = ls->fs; + int prep, endfor; + checknext(ls, TK_DO); + prep = luaK_codeABx(fs, forprep[isgen], base, 0); + enterblock(fs, &bl, 0); /* scope for declared variables */ + adjustlocalvars(ls, nvars); + luaK_reserveregs(fs, nvars); + block(ls); + leaveblock(fs); /* end of scope for declared variables */ + fixforjump(fs, prep, luaK_getlabel(fs), 0); + if (isgen) { /* generic for? */ + luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); + luaK_fixline(fs, line); + } + endfor = luaK_codeABx(fs, forloop[isgen], base, 0); + fixforjump(fs, endfor, prep + 1, 1); + luaK_fixline(fs, line); +} + + +static void fornum (LexState *ls, TString *varname, int line) { + /* fornum -> NAME = exp,exp[,exp] forbody */ + FuncState *fs = ls->fs; + int base = fs->freereg; + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for state)"); + new_localvar(ls, varname); + checknext(ls, '='); + exp1(ls); /* initial value */ + checknext(ls, ','); + exp1(ls); /* limit */ + if (testnext(ls, ',')) + exp1(ls); /* optional step */ + else { /* default step = 1 */ + luaK_int(fs, fs->freereg, 1); + luaK_reserveregs(fs, 1); + } + adjustlocalvars(ls, 3); /* control variables */ + forbody(ls, base, line, 1, 0); +} + + +static void forlist (LexState *ls, TString *indexname) { + /* forlist -> NAME {,NAME} IN explist forbody */ + FuncState *fs = ls->fs; + expdesc e; + int nvars = 5; /* gen, state, control, toclose, 'indexname' */ + int line; + int base = fs->freereg; + /* create control variables */ + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for state)"); + /* create declared variables */ + new_localvar(ls, indexname); + while (testnext(ls, ',')) { + new_localvar(ls, str_checkname(ls)); + nvars++; + } + checknext(ls, TK_IN); + line = ls->linenumber; + adjust_assign(ls, 4, explist(ls, &e), &e); + adjustlocalvars(ls, 4); /* control variables */ + marktobeclosed(fs); /* last control var. must be closed */ + luaK_checkstack(fs, 3); /* extra space to call generator */ + forbody(ls, base, line, nvars - 4, 1); +} + + +static void forstat (LexState *ls, int line) { + /* forstat -> FOR (fornum | forlist) END */ + FuncState *fs = ls->fs; + TString *varname; + BlockCnt bl; + enterblock(fs, &bl, 1); /* scope for loop and control variables */ + luaX_next(ls); /* skip 'for' */ + varname = str_checkname(ls); /* first variable name */ + switch (ls->t.token) { + case '=': fornum(ls, varname, line); break; + case ',': case TK_IN: forlist(ls, varname); break; + default: luaX_syntaxerror(ls, "'=' or 'in' expected"); + } + check_match(ls, TK_END, TK_FOR, line); + leaveblock(fs); /* loop scope ('break' jumps to this point) */ +} + + +static void test_then_block (LexState *ls, int *escapelist) { + /* test_then_block -> [IF | ELSEIF] cond THEN block */ + BlockCnt bl; + FuncState *fs = ls->fs; + expdesc v; + int jf; /* instruction to skip 'then' code (if condition is false) */ + luaX_next(ls); /* skip IF or ELSEIF */ + expr(ls, &v); /* read condition */ + checknext(ls, TK_THEN); + if (ls->t.token == TK_BREAK) { /* 'if x then break' ? */ + int line = ls->linenumber; + luaK_goiffalse(ls->fs, &v); /* will jump if condition is true */ + luaX_next(ls); /* skip 'break' */ + enterblock(fs, &bl, 0); /* must enter block before 'goto' */ + newgotoentry(ls, luaS_newliteral(ls->L, "break"), line, v.t); + while (testnext(ls, ';')) {} /* skip semicolons */ + if (block_follow(ls, 0)) { /* jump is the entire block? */ + leaveblock(fs); + return; /* and that is it */ + } + else /* must skip over 'then' part if condition is false */ + jf = luaK_jump(fs); + } + else { /* regular case (not a break) */ + luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ + enterblock(fs, &bl, 0); + jf = v.f; + } + statlist(ls); /* 'then' part */ + leaveblock(fs); + if (ls->t.token == TK_ELSE || + ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ + luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ + luaK_patchtohere(fs, jf); +} + + +static void ifstat (LexState *ls, int line) { + /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ + FuncState *fs = ls->fs; + int escapelist = NO_JUMP; /* exit list for finished parts */ + test_then_block(ls, &escapelist); /* IF cond THEN block */ + while (ls->t.token == TK_ELSEIF) + test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ + if (testnext(ls, TK_ELSE)) + block(ls); /* 'else' part */ + check_match(ls, TK_END, TK_IF, line); + luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ +} + + +static void localfunc (LexState *ls) { + expdesc b; + FuncState *fs = ls->fs; + int fvar = fs->nactvar; /* function's variable index */ + new_localvar(ls, str_checkname(ls)); /* new local variable */ + adjustlocalvars(ls, 1); /* enter its scope */ + body(ls, &b, 0, ls->linenumber); /* function created in next register */ + /* debug information will only see the variable after this point! */ + localdebuginfo(fs, fvar)->startpc = fs->pc; +} + + +static int getlocalattribute (LexState *ls) { + /* ATTRIB -> ['<' Name '>'] */ + if (testnext(ls, '<')) { + const char *attr = getstr(str_checkname(ls)); + checknext(ls, '>'); + if (strcmp(attr, "const") == 0) + return RDKCONST; /* read-only variable */ + else if (strcmp(attr, "close") == 0) + return RDKTOCLOSE; /* to-be-closed variable */ + else + luaK_semerror(ls, + luaO_pushfstring(ls->L, "unknown attribute '%s'", attr)); + } + return VDKREG; /* regular variable */ +} + + +static void checktoclose (FuncState *fs, int level) { + if (level != -1) { /* is there a to-be-closed variable? */ + marktobeclosed(fs); + luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0); + } +} + + +static void localstat (LexState *ls) { + /* stat -> LOCAL NAME ATTRIB { ',' NAME ATTRIB } ['=' explist] */ + FuncState *fs = ls->fs; + int toclose = -1; /* index of to-be-closed variable (if any) */ + Vardesc *var; /* last variable */ + int vidx, kind; /* index and kind of last variable */ + int nvars = 0; + int nexps; + expdesc e; + do { + vidx = new_localvar(ls, str_checkname(ls)); + kind = getlocalattribute(ls); + getlocalvardesc(fs, vidx)->vd.kind = kind; + if (kind == RDKTOCLOSE) { /* to-be-closed? */ + if (toclose != -1) /* one already present? */ + luaK_semerror(ls, "multiple to-be-closed variables in local list"); + toclose = fs->nactvar + nvars; + } + nvars++; + } while (testnext(ls, ',')); + if (testnext(ls, '=')) + nexps = explist(ls, &e); + else { + e.k = VVOID; + nexps = 0; + } + var = getlocalvardesc(fs, vidx); /* get last variable */ + if (nvars == nexps && /* no adjustments? */ + var->vd.kind == RDKCONST && /* last variable is const? */ + luaK_exp2const(fs, &e, &var->k)) { /* compile-time constant? */ + var->vd.kind = RDKCTC; /* variable is a compile-time constant */ + adjustlocalvars(ls, nvars - 1); /* exclude last variable */ + fs->nactvar++; /* but count it */ + } + else { + adjust_assign(ls, nvars, nexps, &e); + adjustlocalvars(ls, nvars); + } + checktoclose(fs, toclose); +} + + +static int funcname (LexState *ls, expdesc *v) { + /* funcname -> NAME {fieldsel} [':' NAME] */ + int ismethod = 0; + singlevar(ls, v); + while (ls->t.token == '.') + fieldsel(ls, v); + if (ls->t.token == ':') { + ismethod = 1; + fieldsel(ls, v); + } + return ismethod; +} + + +static void funcstat (LexState *ls, int line) { + /* funcstat -> FUNCTION funcname body */ + int ismethod; + expdesc v, b; + luaX_next(ls); /* skip FUNCTION */ + ismethod = funcname(ls, &v); + body(ls, &b, ismethod, line); + check_readonly(ls, &v); + luaK_storevar(ls->fs, &v, &b); + luaK_fixline(ls->fs, line); /* definition "happens" in the first line */ +} + + +static void exprstat (LexState *ls) { + /* stat -> func | assignment */ + FuncState *fs = ls->fs; + struct LHS_assign v; + suffixedexp(ls, &v.v); + if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */ + v.prev = NULL; + restassign(ls, &v, 1); + } + else { /* stat -> func */ + Instruction *inst; + check_condition(ls, v.v.k == VCALL, "syntax error"); + inst = &getinstruction(fs, &v.v); + SETARG_C(*inst, 1); /* call statement uses no results */ + } +} + + +static void retstat (LexState *ls) { + /* stat -> RETURN [explist] [';'] */ + FuncState *fs = ls->fs; + expdesc e; + int nret; /* number of values being returned */ + int first = luaY_nvarstack(fs); /* first slot to be returned */ + if (block_follow(ls, 1) || ls->t.token == ';') + nret = 0; /* return no values */ + else { + nret = explist(ls, &e); /* optional return values */ + if (hasmultret(e.k)) { + luaK_setmultret(fs, &e); + if (e.k == VCALL && nret == 1 && !fs->bl->insidetbc) { /* tail call? */ + SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL); + lua_assert(GETARG_A(getinstruction(fs,&e)) == luaY_nvarstack(fs)); + } + nret = LUA_MULTRET; /* return all values */ + } + else { + if (nret == 1) /* only one single value? */ + first = luaK_exp2anyreg(fs, &e); /* can use original slot */ + else { /* values must go to the top of the stack */ + luaK_exp2nextreg(fs, &e); + lua_assert(nret == fs->freereg - first); + } + } + } + luaK_ret(fs, first, nret); + testnext(ls, ';'); /* skip optional semicolon */ +} + + +static void statement (LexState *ls) { + int line = ls->linenumber; /* may be needed for error messages */ + enterlevel(ls); + switch (ls->t.token) { + case ';': { /* stat -> ';' (empty statement) */ + luaX_next(ls); /* skip ';' */ + break; + } + case TK_IF: { /* stat -> ifstat */ + ifstat(ls, line); + break; + } + case TK_WHILE: { /* stat -> whilestat */ + whilestat(ls, line); + break; + } + case TK_DO: { /* stat -> DO block END */ + luaX_next(ls); /* skip DO */ + block(ls); + check_match(ls, TK_END, TK_DO, line); + break; + } + case TK_FOR: { /* stat -> forstat */ + forstat(ls, line); + break; + } + case TK_REPEAT: { /* stat -> repeatstat */ + repeatstat(ls, line); + break; + } + case TK_FUNCTION: { /* stat -> funcstat */ + funcstat(ls, line); + break; + } + case TK_LOCAL: { /* stat -> localstat */ + luaX_next(ls); /* skip LOCAL */ + if (testnext(ls, TK_FUNCTION)) /* local function? */ + localfunc(ls); + else + localstat(ls); + break; + } + case TK_DBCOLON: { /* stat -> label */ + luaX_next(ls); /* skip double colon */ + labelstat(ls, str_checkname(ls), line); + break; + } + case TK_RETURN: { /* stat -> retstat */ + luaX_next(ls); /* skip RETURN */ + retstat(ls); + break; + } + case TK_BREAK: { /* stat -> breakstat */ + breakstat(ls); + break; + } + case TK_GOTO: { /* stat -> 'goto' NAME */ + luaX_next(ls); /* skip 'goto' */ + gotostat(ls); + break; + } + default: { /* stat -> func | assignment */ + exprstat(ls); + break; + } + } + lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && + ls->fs->freereg >= luaY_nvarstack(ls->fs)); + ls->fs->freereg = luaY_nvarstack(ls->fs); /* free registers */ + leavelevel(ls); +} + +/* }====================================================================== */ + + +/* +** compiles the main function, which is a regular vararg function with an +** upvalue named LUA_ENV +*/ +static void mainfunc (LexState *ls, FuncState *fs) { + BlockCnt bl; + Upvaldesc *env; + open_func(ls, fs, &bl); + setvararg(fs, 0); /* main function is always declared vararg */ + env = allocupvalue(fs); /* ...set environment upvalue */ + env->instack = 1; + env->idx = 0; + env->kind = VDKREG; + env->name = ls->envn; + luaC_objbarrier(ls->L, fs->f, env->name); + luaX_next(ls); /* read first token */ + statlist(ls); /* parse main body */ + check(ls, TK_EOS); + close_func(ls); +} + + +LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar) { + LexState lexstate; + FuncState funcstate; + LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ + setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */ + luaD_inctop(L); + lexstate.h = luaH_new(L); /* create table for scanner */ + sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */ + luaD_inctop(L); + funcstate.f = cl->p = luaF_newproto(L); + luaC_objbarrier(L, cl, cl->p); + funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ + luaC_objbarrier(L, funcstate.f, funcstate.f->source); + lexstate.buff = buff; + lexstate.dyd = dyd; + dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; + luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar); + mainfunc(&lexstate, &funcstate); + lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); + /* all scopes should be correctly finished */ + lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); + L->top.p--; /* remove scanner's table */ + return cl; /* closure is on the stack, too */ +} + diff --git a/vendor/lua-src/lua-5.4.6/lparser.h b/vendor/lua-src/lua-5.4.6/lparser.h new file mode 100644 index 0000000000000..5e4500f181a80 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lparser.h @@ -0,0 +1,171 @@ +/* +** $Id: lparser.h $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + +#ifndef lparser_h +#define lparser_h + +#include "llimits.h" +#include "lobject.h" +#include "lzio.h" + + +/* +** Expression and variable descriptor. +** Code generation for variables and expressions can be delayed to allow +** optimizations; An 'expdesc' structure describes a potentially-delayed +** variable/expression. It has a description of its "main" value plus a +** list of conditional jumps that can also produce its value (generated +** by short-circuit operators 'and'/'or'). +*/ + +/* kinds of variables/expressions */ +typedef enum { + VVOID, /* when 'expdesc' describes the last expression of a list, + this kind means an empty list (so, no expression) */ + VNIL, /* constant nil */ + VTRUE, /* constant true */ + VFALSE, /* constant false */ + VK, /* constant in 'k'; info = index of constant in 'k' */ + VKFLT, /* floating constant; nval = numerical float value */ + VKINT, /* integer constant; ival = numerical integer value */ + VKSTR, /* string constant; strval = TString address; + (string is fixed by the lexer) */ + VNONRELOC, /* expression has its value in a fixed register; + info = result register */ + VLOCAL, /* local variable; var.ridx = register index; + var.vidx = relative index in 'actvar.arr' */ + VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ + VCONST, /* compile-time variable; + info = absolute index in 'actvar.arr' */ + VINDEXED, /* indexed variable; + ind.t = table register; + ind.idx = key's R index */ + VINDEXUP, /* indexed upvalue; + ind.t = table upvalue; + ind.idx = key's K index */ + VINDEXI, /* indexed variable with constant integer; + ind.t = table register; + ind.idx = key's value */ + VINDEXSTR, /* indexed variable with literal string; + ind.t = table register; + ind.idx = key's K index */ + VJMP, /* expression is a test/comparison; + info = pc of corresponding jump instruction */ + VRELOC, /* expression can put result in any register; + info = instruction pc */ + VCALL, /* expression is a function call; info = instruction pc */ + VVARARG /* vararg expression; info = instruction pc */ +} expkind; + + +#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXSTR) +#define vkisindexed(k) (VINDEXED <= (k) && (k) <= VINDEXSTR) + + +typedef struct expdesc { + expkind k; + union { + lua_Integer ival; /* for VKINT */ + lua_Number nval; /* for VKFLT */ + TString *strval; /* for VKSTR */ + int info; /* for generic use */ + struct { /* for indexed variables */ + short idx; /* index (R or "long" K) */ + lu_byte t; /* table (register or upvalue) */ + } ind; + struct { /* for local variables */ + lu_byte ridx; /* register holding the variable */ + unsigned short vidx; /* compiler index (in 'actvar.arr') */ + } var; + } u; + int t; /* patch list of 'exit when true' */ + int f; /* patch list of 'exit when false' */ +} expdesc; + + +/* kinds of variables */ +#define VDKREG 0 /* regular */ +#define RDKCONST 1 /* constant */ +#define RDKTOCLOSE 2 /* to-be-closed */ +#define RDKCTC 3 /* compile-time constant */ + +/* description of an active local variable */ +typedef union Vardesc { + struct { + TValuefields; /* constant value (if it is a compile-time constant) */ + lu_byte kind; + lu_byte ridx; /* register holding the variable */ + short pidx; /* index of the variable in the Proto's 'locvars' array */ + TString *name; /* variable name */ + } vd; + TValue k; /* constant value (if any) */ +} Vardesc; + + + +/* description of pending goto statements and label statements */ +typedef struct Labeldesc { + TString *name; /* label identifier */ + int pc; /* position in code */ + int line; /* line where it appeared */ + lu_byte nactvar; /* number of active variables in that position */ + lu_byte close; /* goto that escapes upvalues */ +} Labeldesc; + + +/* list of labels or gotos */ +typedef struct Labellist { + Labeldesc *arr; /* array */ + int n; /* number of entries in use */ + int size; /* array size */ +} Labellist; + + +/* dynamic structures used by the parser */ +typedef struct Dyndata { + struct { /* list of all active local variables */ + Vardesc *arr; + int n; + int size; + } actvar; + Labellist gt; /* list of pending gotos */ + Labellist label; /* list of active labels */ +} Dyndata; + + +/* control of blocks */ +struct BlockCnt; /* defined in lparser.c */ + + +/* state needed to generate code for a given function */ +typedef struct FuncState { + Proto *f; /* current function header */ + struct FuncState *prev; /* enclosing function */ + struct LexState *ls; /* lexical state */ + struct BlockCnt *bl; /* chain of current blocks */ + int pc; /* next position to code (equivalent to 'ncode') */ + int lasttarget; /* 'label' of last 'jump label' */ + int previousline; /* last line that was saved in 'lineinfo' */ + int nk; /* number of elements in 'k' */ + int np; /* number of elements in 'p' */ + int nabslineinfo; /* number of elements in 'abslineinfo' */ + int firstlocal; /* index of first local var (in Dyndata array) */ + int firstlabel; /* index of first label (in 'dyd->label->arr') */ + short ndebugvars; /* number of elements in 'f->locvars' */ + lu_byte nactvar; /* number of active local variables */ + lu_byte nups; /* number of upvalues */ + lu_byte freereg; /* first free register */ + lu_byte iwthabs; /* instructions issued since last absolute line info */ + lu_byte needclose; /* function needs to close upvalues when returning */ +} FuncState; + + +LUAI_FUNC int luaY_nvarstack (FuncState *fs); +LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar); + + +#endif diff --git a/vendor/lua-src/lua-5.4.6/lprefix.h b/vendor/lua-src/lua-5.4.6/lprefix.h new file mode 100644 index 0000000000000..484f2ad6fbfc5 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lprefix.h @@ -0,0 +1,45 @@ +/* +** $Id: lprefix.h $ +** Definitions for Lua code that must come before any other header file +** See Copyright Notice in lua.h +*/ + +#ifndef lprefix_h +#define lprefix_h + + +/* +** Allows POSIX/XSI stuff +*/ +#if !defined(LUA_USE_C89) /* { */ + +#if !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE 600 +#elif _XOPEN_SOURCE == 0 +#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ +#endif + +/* +** Allows manipulation of large files in gcc and some other compilers +*/ +#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) +#define _LARGEFILE_SOURCE 1 +#define _FILE_OFFSET_BITS 64 +#endif + +#endif /* } */ + + +/* +** Windows stuff +*/ +#if defined(_WIN32) /* { */ + +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ +#endif + +#endif /* } */ + +#endif + diff --git a/vendor/lua-src/lua-5.4.6/lstate.c b/vendor/lua-src/lua-5.4.6/lstate.c new file mode 100644 index 0000000000000..1e925e5ad4cb2 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lstate.c @@ -0,0 +1,445 @@ +/* +** $Id: lstate.c $ +** Global State +** See Copyright Notice in lua.h +*/ + +#define lstate_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + + +/* +** thread state + extra space +*/ +typedef struct LX { + lu_byte extra_[LUA_EXTRASPACE]; + lua_State l; +} LX; + + +/* +** Main thread combines a thread state and the global state +*/ +typedef struct LG { + LX l; + global_State g; +} LG; + + + +#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) + + +/* +** A macro to create a "random" seed when a state is created; +** the seed is used to randomize string hashes. +*/ +#if !defined(luai_makeseed) + +#include + +/* +** Compute an initial seed with some level of randomness. +** Rely on Address Space Layout Randomization (if present) and +** current time. +*/ +#define addbuff(b,p,e) \ + { size_t t = cast_sizet(e); \ + memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } + +static unsigned int luai_makeseed (lua_State *L) { + char buff[3 * sizeof(size_t)]; + unsigned int h = cast_uint(time(NULL)); + int p = 0; + addbuff(buff, p, L); /* heap variable */ + addbuff(buff, p, &h); /* local variable */ + addbuff(buff, p, &lua_newstate); /* public function */ + lua_assert(p == sizeof(buff)); + return luaS_hash(buff, p, h); +} + +#endif + + +/* +** set GCdebt to a new value keeping the value (totalbytes + GCdebt) +** invariant (and avoiding underflows in 'totalbytes') +*/ +void luaE_setdebt (global_State *g, l_mem debt) { + l_mem tb = gettotalbytes(g); + lua_assert(tb > 0); + if (debt < tb - MAX_LMEM) + debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */ + g->totalbytes = tb - debt; + g->GCdebt = debt; +} + + +LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) { + UNUSED(L); UNUSED(limit); + return LUAI_MAXCCALLS; /* warning?? */ +} + + +CallInfo *luaE_extendCI (lua_State *L) { + CallInfo *ci; + lua_assert(L->ci->next == NULL); + ci = luaM_new(L, CallInfo); + lua_assert(L->ci->next == NULL); + L->ci->next = ci; + ci->previous = L->ci; + ci->next = NULL; + ci->u.l.trap = 0; + L->nci++; + return ci; +} + + +/* +** free all CallInfo structures not in use by a thread +*/ +void luaE_freeCI (lua_State *L) { + CallInfo *ci = L->ci; + CallInfo *next = ci->next; + ci->next = NULL; + while ((ci = next) != NULL) { + next = ci->next; + luaM_free(L, ci); + L->nci--; + } +} + + +/* +** free half of the CallInfo structures not in use by a thread, +** keeping the first one. +*/ +void luaE_shrinkCI (lua_State *L) { + CallInfo *ci = L->ci->next; /* first free CallInfo */ + CallInfo *next; + if (ci == NULL) + return; /* no extra elements */ + while ((next = ci->next) != NULL) { /* two extra elements? */ + CallInfo *next2 = next->next; /* next's next */ + ci->next = next2; /* remove next from the list */ + L->nci--; + luaM_free(L, next); /* free next */ + if (next2 == NULL) + break; /* no more elements */ + else { + next2->previous = ci; + ci = next2; /* continue */ + } + } +} + + +/* +** Called when 'getCcalls(L)' larger or equal to LUAI_MAXCCALLS. +** If equal, raises an overflow error. If value is larger than +** LUAI_MAXCCALLS (which means it is handling an overflow) but +** not much larger, does not report an error (to allow overflow +** handling to work). +*/ +void luaE_checkcstack (lua_State *L) { + if (getCcalls(L) == LUAI_MAXCCALLS) + luaG_runerror(L, "C stack overflow"); + else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11)) + luaD_throw(L, LUA_ERRERR); /* error while handling stack error */ +} + + +LUAI_FUNC void luaE_incCstack (lua_State *L) { + L->nCcalls++; + if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) + luaE_checkcstack(L); +} + + +static void stack_init (lua_State *L1, lua_State *L) { + int i; CallInfo *ci; + /* initialize stack array */ + L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue); + L1->tbclist.p = L1->stack.p; + for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) + setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */ + L1->top.p = L1->stack.p; + L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE; + /* initialize first ci */ + ci = &L1->base_ci; + ci->next = ci->previous = NULL; + ci->callstatus = CIST_C; + ci->func.p = L1->top.p; + ci->u.c.k = NULL; + ci->nresults = 0; + setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */ + L1->top.p++; + ci->top.p = L1->top.p + LUA_MINSTACK; + L1->ci = ci; +} + + +static void freestack (lua_State *L) { + if (L->stack.p == NULL) + return; /* stack not completely built yet */ + L->ci = &L->base_ci; /* free the entire 'ci' list */ + luaE_freeCI(L); + lua_assert(L->nci == 0); + luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */ +} + + +/* +** Create registry table and its predefined values +*/ +static void init_registry (lua_State *L, global_State *g) { + /* create registry */ + Table *registry = luaH_new(L); + sethvalue(L, &g->l_registry, registry); + luaH_resize(L, registry, LUA_RIDX_LAST, 0); + /* registry[LUA_RIDX_MAINTHREAD] = L */ + setthvalue(L, ®istry->array[LUA_RIDX_MAINTHREAD - 1], L); + /* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */ + sethvalue(L, ®istry->array[LUA_RIDX_GLOBALS - 1], luaH_new(L)); +} + + +/* +** open parts of the state that may cause memory-allocation errors. +*/ +static void f_luaopen (lua_State *L, void *ud) { + global_State *g = G(L); + UNUSED(ud); + stack_init(L, L); /* init stack */ + init_registry(L, g); + luaS_init(L); + luaT_init(L); + luaX_init(L); + g->gcstp = 0; /* allow gc */ + setnilvalue(&g->nilvalue); /* now state is complete */ + luai_userstateopen(L); +} + + +/* +** preinitialize a thread with consistent values without allocating +** any memory (to avoid errors) +*/ +static void preinit_thread (lua_State *L, global_State *g) { + G(L) = g; + L->stack.p = NULL; + L->ci = NULL; + L->nci = 0; + L->twups = L; /* thread has no upvalues */ + L->nCcalls = 0; + L->errorJmp = NULL; + L->hook = NULL; + L->hookmask = 0; + L->basehookcount = 0; + L->allowhook = 1; + resethookcount(L); + L->openupval = NULL; + L->status = LUA_OK; + L->errfunc = 0; + L->oldpc = 0; +} + + +static void close_state (lua_State *L) { + global_State *g = G(L); + if (!completestate(g)) /* closing a partially built state? */ + luaC_freeallobjects(L); /* just collect its objects */ + else { /* closing a fully built state */ + L->ci = &L->base_ci; /* unwind CallInfo list */ + luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */ + luaC_freeallobjects(L); /* collect all objects */ + luai_userstateclose(L); + } + luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); + freestack(L); + lua_assert(gettotalbytes(g) == sizeof(LG)); + (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ +} + + +LUA_API lua_State *lua_newthread (lua_State *L) { + global_State *g = G(L); + GCObject *o; + lua_State *L1; + lua_lock(L); + luaC_checkGC(L); + /* create new thread */ + o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l)); + L1 = gco2th(o); + /* anchor it on L stack */ + setthvalue2s(L, L->top.p, L1); + api_incr_top(L); + preinit_thread(L1, g); + L1->hookmask = L->hookmask; + L1->basehookcount = L->basehookcount; + L1->hook = L->hook; + resethookcount(L1); + /* initialize L1 extra space */ + memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), + LUA_EXTRASPACE); + luai_userstatethread(L, L1); + stack_init(L1, L); /* init stack */ + lua_unlock(L); + return L1; +} + + +void luaE_freethread (lua_State *L, lua_State *L1) { + LX *l = fromstate(L1); + luaF_closeupval(L1, L1->stack.p); /* close all upvalues */ + lua_assert(L1->openupval == NULL); + luai_userstatefree(L, L1); + freestack(L1); + luaM_free(L, l); +} + + +int luaE_resetthread (lua_State *L, int status) { + CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */ + setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */ + ci->func.p = L->stack.p; + ci->callstatus = CIST_C; + if (status == LUA_YIELD) + status = LUA_OK; + L->status = LUA_OK; /* so it can run __close metamethods */ + status = luaD_closeprotected(L, 1, status); + if (status != LUA_OK) /* errors? */ + luaD_seterrorobj(L, status, L->stack.p + 1); + else + L->top.p = L->stack.p + 1; + ci->top.p = L->top.p + LUA_MINSTACK; + luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0); + return status; +} + + +LUA_API int lua_closethread (lua_State *L, lua_State *from) { + int status; + lua_lock(L); + L->nCcalls = (from) ? getCcalls(from) : 0; + status = luaE_resetthread(L, L->status); + lua_unlock(L); + return status; +} + + +/* +** Deprecated! Use 'lua_closethread' instead. +*/ +LUA_API int lua_resetthread (lua_State *L) { + return lua_closethread(L, NULL); +} + + +LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { + int i; + lua_State *L; + global_State *g; + LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); + if (l == NULL) return NULL; + L = &l->l.l; + g = &l->g; + L->tt = LUA_VTHREAD; + g->currentwhite = bitmask(WHITE0BIT); + L->marked = luaC_white(g); + preinit_thread(L, g); + g->allgc = obj2gco(L); /* by now, only object is the main thread */ + L->next = NULL; + incnny(L); /* main thread is always non yieldable */ + g->frealloc = f; + g->ud = ud; + g->warnf = NULL; + g->ud_warn = NULL; + g->mainthread = L; + g->seed = luai_makeseed(L); + g->gcstp = GCSTPGC; /* no GC while building state */ + g->strt.size = g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(&g->l_registry); + g->panic = NULL; + g->gcstate = GCSpause; + g->gckind = KGC_INC; + g->gcstopem = 0; + g->gcemergency = 0; + g->finobj = g->tobefnz = g->fixedgc = NULL; + g->firstold1 = g->survival = g->old1 = g->reallyold = NULL; + g->finobjsur = g->finobjold1 = g->finobjrold = NULL; + g->sweepgc = NULL; + g->gray = g->grayagain = NULL; + g->weak = g->ephemeron = g->allweak = NULL; + g->twups = NULL; + g->totalbytes = sizeof(LG); + g->GCdebt = 0; + g->lastatomic = 0; + setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */ + setgcparam(g->gcpause, LUAI_GCPAUSE); + setgcparam(g->gcstepmul, LUAI_GCMUL); + g->gcstepsize = LUAI_GCSTEPSIZE; + setgcparam(g->genmajormul, LUAI_GENMAJORMUL); + g->genminormul = LUAI_GENMINORMUL; + for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; + if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; + } + return L; +} + + +LUA_API void lua_close (lua_State *L) { + lua_lock(L); + L = G(L)->mainthread; /* only the main thread can be closed */ + close_state(L); +} + + +void luaE_warning (lua_State *L, const char *msg, int tocont) { + lua_WarnFunction wf = G(L)->warnf; + if (wf != NULL) + wf(G(L)->ud_warn, msg, tocont); +} + + +/* +** Generate a warning from an error message +*/ +void luaE_warnerror (lua_State *L, const char *where) { + TValue *errobj = s2v(L->top.p - 1); /* error object */ + const char *msg = (ttisstring(errobj)) + ? svalue(errobj) + : "error object is not a string"; + /* produce warning "error in %s (%s)" (where, msg) */ + luaE_warning(L, "error in ", 1); + luaE_warning(L, where, 1); + luaE_warning(L, " (", 1); + luaE_warning(L, msg, 1); + luaE_warning(L, ")", 0); +} + diff --git a/vendor/lua-src/lua-5.4.6/lstate.h b/vendor/lua-src/lua-5.4.6/lstate.h new file mode 100644 index 0000000000000..8bf6600e34416 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lstate.h @@ -0,0 +1,409 @@ +/* +** $Id: lstate.h $ +** Global State +** See Copyright Notice in lua.h +*/ + +#ifndef lstate_h +#define lstate_h + +#include "lua.h" + + +/* Some header files included here need this definition */ +typedef struct CallInfo CallInfo; + + +#include "lobject.h" +#include "ltm.h" +#include "lzio.h" + + +/* +** Some notes about garbage-collected objects: All objects in Lua must +** be kept somehow accessible until being freed, so all objects always +** belong to one (and only one) of these lists, using field 'next' of +** the 'CommonHeader' for the link: +** +** 'allgc': all objects not marked for finalization; +** 'finobj': all objects marked for finalization; +** 'tobefnz': all objects ready to be finalized; +** 'fixedgc': all objects that are not to be collected (currently +** only small strings, such as reserved words). +** +** For the generational collector, some of these lists have marks for +** generations. Each mark points to the first element in the list for +** that particular generation; that generation goes until the next mark. +** +** 'allgc' -> 'survival': new objects; +** 'survival' -> 'old': objects that survived one collection; +** 'old1' -> 'reallyold': objects that became old in last collection; +** 'reallyold' -> NULL: objects old for more than one cycle. +** +** 'finobj' -> 'finobjsur': new objects marked for finalization; +** 'finobjsur' -> 'finobjold1': survived """"; +** 'finobjold1' -> 'finobjrold': just old """"; +** 'finobjrold' -> NULL: really old """". +** +** All lists can contain elements older than their main ages, due +** to 'luaC_checkfinalizer' and 'udata2finalize', which move +** objects between the normal lists and the "marked for finalization" +** lists. Moreover, barriers can age young objects in young lists as +** OLD0, which then become OLD1. However, a list never contains +** elements younger than their main ages. +** +** The generational collector also uses a pointer 'firstold1', which +** points to the first OLD1 object in the list. It is used to optimize +** 'markold'. (Potentially OLD1 objects can be anywhere between 'allgc' +** and 'reallyold', but often the list has no OLD1 objects or they are +** after 'old1'.) Note the difference between it and 'old1': +** 'firstold1': no OLD1 objects before this point; there can be all +** ages after it. +** 'old1': no objects younger than OLD1 after this point. +*/ + +/* +** Moreover, there is another set of lists that control gray objects. +** These lists are linked by fields 'gclist'. (All objects that +** can become gray have such a field. The field is not the same +** in all objects, but it always has this name.) Any gray object +** must belong to one of these lists, and all objects in these lists +** must be gray (with two exceptions explained below): +** +** 'gray': regular gray objects, still waiting to be visited. +** 'grayagain': objects that must be revisited at the atomic phase. +** That includes +** - black objects got in a write barrier; +** - all kinds of weak tables during propagation phase; +** - all threads. +** 'weak': tables with weak values to be cleared; +** 'ephemeron': ephemeron tables with white->white entries; +** 'allweak': tables with weak keys and/or weak values to be cleared. +** +** The exceptions to that "gray rule" are: +** - TOUCHED2 objects in generational mode stay in a gray list (because +** they must be visited again at the end of the cycle), but they are +** marked black because assignments to them must activate barriers (to +** move them back to TOUCHED1). +** - Open upvales are kept gray to avoid barriers, but they stay out +** of gray lists. (They don't even have a 'gclist' field.) +*/ + + + +/* +** About 'nCcalls': This count has two parts: the lower 16 bits counts +** the number of recursive invocations in the C stack; the higher +** 16 bits counts the number of non-yieldable calls in the stack. +** (They are together so that we can change and save both with one +** instruction.) +*/ + + +/* true if this thread does not have non-yieldable calls in the stack */ +#define yieldable(L) (((L)->nCcalls & 0xffff0000) == 0) + +/* real number of C calls */ +#define getCcalls(L) ((L)->nCcalls & 0xffff) + + +/* Increment the number of non-yieldable calls */ +#define incnny(L) ((L)->nCcalls += 0x10000) + +/* Decrement the number of non-yieldable calls */ +#define decnny(L) ((L)->nCcalls -= 0x10000) + +/* Non-yieldable call increment */ +#define nyci (0x10000 | 1) + + + + +struct lua_longjmp; /* defined in ldo.c */ + + +/* +** Atomic type (relative to signals) to better ensure that 'lua_sethook' +** is thread safe +*/ +#if !defined(l_signalT) +#include +#define l_signalT sig_atomic_t +#endif + + +/* +** Extra stack space to handle TM calls and some other extras. This +** space is not included in 'stack_last'. It is used only to avoid stack +** checks, either because the element will be promptly popped or because +** there will be a stack check soon after the push. Function frames +** never use this extra space, so it does not need to be kept clean. +*/ +#define EXTRA_STACK 5 + + +#define BASIC_STACK_SIZE (2*LUA_MINSTACK) + +#define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p) + + +/* kinds of Garbage Collection */ +#define KGC_INC 0 /* incremental gc */ +#define KGC_GEN 1 /* generational gc */ + + +typedef struct stringtable { + TString **hash; + int nuse; /* number of elements */ + int size; +} stringtable; + + +/* +** Information about a call. +** About union 'u': +** - field 'l' is used only for Lua functions; +** - field 'c' is used only for C functions. +** About union 'u2': +** - field 'funcidx' is used only by C functions while doing a +** protected call; +** - field 'nyield' is used only while a function is "doing" an +** yield (from the yield until the next resume); +** - field 'nres' is used only while closing tbc variables when +** returning from a function; +** - field 'transferinfo' is used only during call/returnhooks, +** before the function starts or after it ends. +*/ +struct CallInfo { + StkIdRel func; /* function index in the stack */ + StkIdRel top; /* top for this function */ + struct CallInfo *previous, *next; /* dynamic call link */ + union { + struct { /* only for Lua functions */ + const Instruction *savedpc; + volatile l_signalT trap; + int nextraargs; /* # of extra arguments in vararg functions */ + } l; + struct { /* only for C functions */ + lua_KFunction k; /* continuation in case of yields */ + ptrdiff_t old_errfunc; + lua_KContext ctx; /* context info. in case of yields */ + } c; + } u; + union { + int funcidx; /* called-function index */ + int nyield; /* number of values yielded */ + int nres; /* number of values returned */ + struct { /* info about transferred values (for call/return hooks) */ + unsigned short ftransfer; /* offset of first value transferred */ + unsigned short ntransfer; /* number of values transferred */ + } transferinfo; + } u2; + short nresults; /* expected number of results from this function */ + unsigned short callstatus; +}; + + +/* +** Bits in CallInfo status +*/ +#define CIST_OAH (1<<0) /* original value of 'allowhook' */ +#define CIST_C (1<<1) /* call is running a C function */ +#define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */ +#define CIST_HOOKED (1<<3) /* call is running a debug hook */ +#define CIST_YPCALL (1<<4) /* doing a yieldable protected call */ +#define CIST_TAIL (1<<5) /* call was tail called */ +#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ +#define CIST_FIN (1<<7) /* function "called" a finalizer */ +#define CIST_TRAN (1<<8) /* 'ci' has transfer information */ +#define CIST_CLSRET (1<<9) /* function is closing tbc variables */ +/* Bits 10-12 are used for CIST_RECST (see below) */ +#define CIST_RECST 10 +#if defined(LUA_COMPAT_LT_LE) +#define CIST_LEQ (1<<13) /* using __lt for __le */ +#endif + + +/* +** Field CIST_RECST stores the "recover status", used to keep the error +** status while closing to-be-closed variables in coroutines, so that +** Lua can correctly resume after an yield from a __close method called +** because of an error. (Three bits are enough for error status.) +*/ +#define getcistrecst(ci) (((ci)->callstatus >> CIST_RECST) & 7) +#define setcistrecst(ci,st) \ + check_exp(((st) & 7) == (st), /* status must fit in three bits */ \ + ((ci)->callstatus = ((ci)->callstatus & ~(7 << CIST_RECST)) \ + | ((st) << CIST_RECST))) + + +/* active function is a Lua function */ +#define isLua(ci) (!((ci)->callstatus & CIST_C)) + +/* call is running Lua code (not a hook) */ +#define isLuacode(ci) (!((ci)->callstatus & (CIST_C | CIST_HOOKED))) + +/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */ +#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v)) +#define getoah(st) ((st) & CIST_OAH) + + +/* +** 'global state', shared by all threads of this state +*/ +typedef struct global_State { + lua_Alloc frealloc; /* function to reallocate memory */ + void *ud; /* auxiliary data to 'frealloc' */ + l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ + l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ + lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ + lu_mem lastatomic; /* see function 'genstep' in file 'lgc.c' */ + stringtable strt; /* hash table for strings */ + TValue l_registry; + TValue nilvalue; /* a nil value */ + unsigned int seed; /* randomized seed for hashes */ + lu_byte currentwhite; + lu_byte gcstate; /* state of garbage collector */ + lu_byte gckind; /* kind of GC running */ + lu_byte gcstopem; /* stops emergency collections */ + lu_byte genminormul; /* control for minor generational collections */ + lu_byte genmajormul; /* control for major generational collections */ + lu_byte gcstp; /* control whether GC is running */ + lu_byte gcemergency; /* true if this is an emergency collection */ + lu_byte gcpause; /* size of pause between successive GCs */ + lu_byte gcstepmul; /* GC "speed" */ + lu_byte gcstepsize; /* (log2 of) GC granularity */ + GCObject *allgc; /* list of all collectable objects */ + GCObject **sweepgc; /* current position of sweep in list */ + GCObject *finobj; /* list of collectable objects with finalizers */ + GCObject *gray; /* list of gray objects */ + GCObject *grayagain; /* list of objects to be traversed atomically */ + GCObject *weak; /* list of tables with weak values */ + GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ + GCObject *allweak; /* list of all-weak tables */ + GCObject *tobefnz; /* list of userdata to be GC */ + GCObject *fixedgc; /* list of objects not to be collected */ + /* fields for generational collector */ + GCObject *survival; /* start of objects that survived one GC cycle */ + GCObject *old1; /* start of old1 objects */ + GCObject *reallyold; /* objects more than one cycle old ("really old") */ + GCObject *firstold1; /* first OLD1 object in the list (if any) */ + GCObject *finobjsur; /* list of survival objects with finalizers */ + GCObject *finobjold1; /* list of old1 objects with finalizers */ + GCObject *finobjrold; /* list of really old objects with finalizers */ + struct lua_State *twups; /* list of threads with open upvalues */ + lua_CFunction panic; /* to be called in unprotected errors */ + struct lua_State *mainthread; + TString *memerrmsg; /* message for memory-allocation errors */ + TString *tmname[TM_N]; /* array with tag-method names */ + struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */ + TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ + lua_WarnFunction warnf; /* warning function */ + void *ud_warn; /* auxiliary data to 'warnf' */ +} global_State; + + +/* +** 'per thread' state +*/ +struct lua_State { + CommonHeader; + lu_byte status; + lu_byte allowhook; + unsigned short nci; /* number of items in 'ci' list */ + StkIdRel top; /* first free slot in the stack */ + global_State *l_G; + CallInfo *ci; /* call info for current function */ + StkIdRel stack_last; /* end of stack (last element + 1) */ + StkIdRel stack; /* stack base */ + UpVal *openupval; /* list of open upvalues in this stack */ + StkIdRel tbclist; /* list of to-be-closed variables */ + GCObject *gclist; + struct lua_State *twups; /* list of threads with open upvalues */ + struct lua_longjmp *errorJmp; /* current error recover point */ + CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ + volatile lua_Hook hook; + ptrdiff_t errfunc; /* current error handling function (stack index) */ + l_uint32 nCcalls; /* number of nested (non-yieldable | C) calls */ + int oldpc; /* last pc traced */ + int basehookcount; + int hookcount; + volatile l_signalT hookmask; +}; + + +#define G(L) (L->l_G) + +/* +** 'g->nilvalue' being a nil value flags that the state was completely +** build. +*/ +#define completestate(g) ttisnil(&g->nilvalue) + + +/* +** Union of all collectable objects (only for conversions) +** ISO C99, 6.5.2.3 p.5: +** "if a union contains several structures that share a common initial +** sequence [...], and if the union object currently contains one +** of these structures, it is permitted to inspect the common initial +** part of any of them anywhere that a declaration of the complete type +** of the union is visible." +*/ +union GCUnion { + GCObject gc; /* common header */ + struct TString ts; + struct Udata u; + union Closure cl; + struct Table h; + struct Proto p; + struct lua_State th; /* thread */ + struct UpVal upv; +}; + + +/* +** ISO C99, 6.7.2.1 p.14: +** "A pointer to a union object, suitably converted, points to each of +** its members [...], and vice versa." +*/ +#define cast_u(o) cast(union GCUnion *, (o)) + +/* macros to convert a GCObject into a specific value */ +#define gco2ts(o) \ + check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts)) +#define gco2u(o) check_exp((o)->tt == LUA_VUSERDATA, &((cast_u(o))->u)) +#define gco2lcl(o) check_exp((o)->tt == LUA_VLCL, &((cast_u(o))->cl.l)) +#define gco2ccl(o) check_exp((o)->tt == LUA_VCCL, &((cast_u(o))->cl.c)) +#define gco2cl(o) \ + check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl)) +#define gco2t(o) check_exp((o)->tt == LUA_VTABLE, &((cast_u(o))->h)) +#define gco2p(o) check_exp((o)->tt == LUA_VPROTO, &((cast_u(o))->p)) +#define gco2th(o) check_exp((o)->tt == LUA_VTHREAD, &((cast_u(o))->th)) +#define gco2upv(o) check_exp((o)->tt == LUA_VUPVAL, &((cast_u(o))->upv)) + + +/* +** macro to convert a Lua object into a GCObject +** (The access to 'tt' tries to ensure that 'v' is actually a Lua object.) +*/ +#define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc)) + + +/* actual number of total bytes allocated */ +#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt) + +LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); +LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); +LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); +LUAI_FUNC void luaE_freeCI (lua_State *L); +LUAI_FUNC void luaE_shrinkCI (lua_State *L); +LUAI_FUNC void luaE_checkcstack (lua_State *L); +LUAI_FUNC void luaE_incCstack (lua_State *L); +LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); +LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where); +LUAI_FUNC int luaE_resetthread (lua_State *L, int status); + + +#endif + diff --git a/vendor/lua-src/lua-5.4.6/lstring.c b/vendor/lua-src/lua-5.4.6/lstring.c new file mode 100644 index 0000000000000..13dcaf4259bc0 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lstring.c @@ -0,0 +1,273 @@ +/* +** $Id: lstring.c $ +** String table (keeps all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +#define lstring_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" + + +/* +** Maximum size for string table. +*/ +#define MAXSTRTB cast_int(luaM_limitN(MAX_INT, TString*)) + + +/* +** equality for long strings +*/ +int luaS_eqlngstr (TString *a, TString *b) { + size_t len = a->u.lnglen; + lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR); + return (a == b) || /* same instance or... */ + ((len == b->u.lnglen) && /* equal length and ... */ + (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ +} + + +unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { + unsigned int h = seed ^ cast_uint(l); + for (; l > 0; l--) + h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); + return h; +} + + +unsigned int luaS_hashlongstr (TString *ts) { + lua_assert(ts->tt == LUA_VLNGSTR); + if (ts->extra == 0) { /* no hash? */ + size_t len = ts->u.lnglen; + ts->hash = luaS_hash(getstr(ts), len, ts->hash); + ts->extra = 1; /* now it has its hash */ + } + return ts->hash; +} + + +static void tablerehash (TString **vect, int osize, int nsize) { + int i; + for (i = osize; i < nsize; i++) /* clear new elements */ + vect[i] = NULL; + for (i = 0; i < osize; i++) { /* rehash old part of the array */ + TString *p = vect[i]; + vect[i] = NULL; + while (p) { /* for each string in the list */ + TString *hnext = p->u.hnext; /* save next */ + unsigned int h = lmod(p->hash, nsize); /* new position */ + p->u.hnext = vect[h]; /* chain it into array */ + vect[h] = p; + p = hnext; + } + } +} + + +/* +** Resize the string table. If allocation fails, keep the current size. +** (This can degrade performance, but any non-zero size should work +** correctly.) +*/ +void luaS_resize (lua_State *L, int nsize) { + stringtable *tb = &G(L)->strt; + int osize = tb->size; + TString **newvect; + if (nsize < osize) /* shrinking table? */ + tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */ + newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*); + if (l_unlikely(newvect == NULL)) { /* reallocation failed? */ + if (nsize < osize) /* was it shrinking table? */ + tablerehash(tb->hash, nsize, osize); /* restore to original size */ + /* leave table as it was */ + } + else { /* allocation succeeded */ + tb->hash = newvect; + tb->size = nsize; + if (nsize > osize) + tablerehash(newvect, osize, nsize); /* rehash for new size */ + } +} + + +/* +** Clear API string cache. (Entries cannot be empty, so fill them with +** a non-collectable string.) +*/ +void luaS_clearcache (global_State *g) { + int i, j; + for (i = 0; i < STRCACHE_N; i++) + for (j = 0; j < STRCACHE_M; j++) { + if (iswhite(g->strcache[i][j])) /* will entry be collected? */ + g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */ + } +} + + +/* +** Initialize the string table and the string cache +*/ +void luaS_init (lua_State *L) { + global_State *g = G(L); + int i, j; + stringtable *tb = &G(L)->strt; + tb->hash = luaM_newvector(L, MINSTRTABSIZE, TString*); + tablerehash(tb->hash, 0, MINSTRTABSIZE); /* clear array */ + tb->size = MINSTRTABSIZE; + /* pre-create memory-error message */ + g->memerrmsg = luaS_newliteral(L, MEMERRMSG); + luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ + for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */ + for (j = 0; j < STRCACHE_M; j++) + g->strcache[i][j] = g->memerrmsg; +} + + + +/* +** creates a new string object +*/ +static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) { + TString *ts; + GCObject *o; + size_t totalsize; /* total size of TString object */ + totalsize = sizelstring(l); + o = luaC_newobj(L, tag, totalsize); + ts = gco2ts(o); + ts->hash = h; + ts->extra = 0; + getstr(ts)[l] = '\0'; /* ending 0 */ + return ts; +} + + +TString *luaS_createlngstrobj (lua_State *L, size_t l) { + TString *ts = createstrobj(L, l, LUA_VLNGSTR, G(L)->seed); + ts->u.lnglen = l; + return ts; +} + + +void luaS_remove (lua_State *L, TString *ts) { + stringtable *tb = &G(L)->strt; + TString **p = &tb->hash[lmod(ts->hash, tb->size)]; + while (*p != ts) /* find previous element */ + p = &(*p)->u.hnext; + *p = (*p)->u.hnext; /* remove element from its list */ + tb->nuse--; +} + + +static void growstrtab (lua_State *L, stringtable *tb) { + if (l_unlikely(tb->nuse == MAX_INT)) { /* too many strings? */ + luaC_fullgc(L, 1); /* try to free some... */ + if (tb->nuse == MAX_INT) /* still too many? */ + luaM_error(L); /* cannot even create a message... */ + } + if (tb->size <= MAXSTRTB / 2) /* can grow string table? */ + luaS_resize(L, tb->size * 2); +} + + +/* +** Checks whether short string exists and reuses it or creates a new one. +*/ +static TString *internshrstr (lua_State *L, const char *str, size_t l) { + TString *ts; + global_State *g = G(L); + stringtable *tb = &g->strt; + unsigned int h = luaS_hash(str, l, g->seed); + TString **list = &tb->hash[lmod(h, tb->size)]; + lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ + for (ts = *list; ts != NULL; ts = ts->u.hnext) { + if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { + /* found! */ + if (isdead(g, ts)) /* dead (but not collected yet)? */ + changewhite(ts); /* resurrect it */ + return ts; + } + } + /* else must create a new string */ + if (tb->nuse >= tb->size) { /* need to grow string table? */ + growstrtab(L, tb); + list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */ + } + ts = createstrobj(L, l, LUA_VSHRSTR, h); + memcpy(getstr(ts), str, l * sizeof(char)); + ts->shrlen = cast_byte(l); + ts->u.hnext = *list; + *list = ts; + tb->nuse++; + return ts; +} + + +/* +** new string (with explicit length) +*/ +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { + if (l <= LUAI_MAXSHORTLEN) /* short string? */ + return internshrstr(L, str, l); + else { + TString *ts; + if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) + luaM_toobig(L); + ts = luaS_createlngstrobj(L, l); + memcpy(getstr(ts), str, l * sizeof(char)); + return ts; + } +} + + +/* +** Create or reuse a zero-terminated string, first checking in the +** cache (using the string address as a key). The cache can contain +** only zero-terminated strings, so it is safe to use 'strcmp' to +** check hits. +*/ +TString *luaS_new (lua_State *L, const char *str) { + unsigned int i = point2uint(str) % STRCACHE_N; /* hash */ + int j; + TString **p = G(L)->strcache[i]; + for (j = 0; j < STRCACHE_M; j++) { + if (strcmp(str, getstr(p[j])) == 0) /* hit? */ + return p[j]; /* that is it */ + } + /* normal route */ + for (j = STRCACHE_M - 1; j > 0; j--) + p[j] = p[j - 1]; /* move out last element */ + /* new element is first in the list */ + p[0] = luaS_newlstr(L, str, strlen(str)); + return p[0]; +} + + +Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) { + Udata *u; + int i; + GCObject *o; + if (l_unlikely(s > MAX_SIZE - udatamemoffset(nuvalue))) + luaM_toobig(L); + o = luaC_newobj(L, LUA_VUSERDATA, sizeudata(nuvalue, s)); + u = gco2u(o); + u->len = s; + u->nuvalue = nuvalue; + u->metatable = NULL; + for (i = 0; i < nuvalue; i++) + setnilvalue(&u->uv[i].uv); + return u; +} + diff --git a/vendor/lua-src/lua-5.4.6/lstring.h b/vendor/lua-src/lua-5.4.6/lstring.h new file mode 100644 index 0000000000000..450c2390d1bb2 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lstring.h @@ -0,0 +1,57 @@ +/* +** $Id: lstring.h $ +** String table (keep all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +#ifndef lstring_h +#define lstring_h + +#include "lgc.h" +#include "lobject.h" +#include "lstate.h" + + +/* +** Memory-allocation error message must be preallocated (it cannot +** be created after memory is exhausted) +*/ +#define MEMERRMSG "not enough memory" + + +/* +** Size of a TString: Size of the header plus space for the string +** itself (including final '\0'). +*/ +#define sizelstring(l) (offsetof(TString, contents) + ((l) + 1) * sizeof(char)) + +#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ + (sizeof(s)/sizeof(char))-1)) + + +/* +** test whether a string is a reserved word +*/ +#define isreserved(s) ((s)->tt == LUA_VSHRSTR && (s)->extra > 0) + + +/* +** equality for short strings, which are always internalized +*/ +#define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b)) + + +LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); +LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); +LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); +LUAI_FUNC void luaS_resize (lua_State *L, int newsize); +LUAI_FUNC void luaS_clearcache (global_State *g); +LUAI_FUNC void luaS_init (lua_State *L); +LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); +LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue); +LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); +LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); +LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); + + +#endif diff --git a/vendor/lua-src/lua-5.4.6/lstrlib.c b/vendor/lua-src/lua-5.4.6/lstrlib.c new file mode 100644 index 0000000000000..03167161df188 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lstrlib.c @@ -0,0 +1,1874 @@ +/* +** $Id: lstrlib.c $ +** Standard library for string operations and pattern-matching +** See Copyright Notice in lua.h +*/ + +#define lstrlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** maximum number of captures that a pattern can do during +** pattern-matching. This limit is arbitrary, but must fit in +** an unsigned char. +*/ +#if !defined(LUA_MAXCAPTURES) +#define LUA_MAXCAPTURES 32 +#endif + + +/* macro to 'unsign' a character */ +#define uchar(c) ((unsigned char)(c)) + + +/* +** Some sizes are better limited to fit in 'int', but must also fit in +** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) +*/ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +#define MAXSIZE \ + (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) + + + + +static int str_len (lua_State *L) { + size_t l; + luaL_checklstring(L, 1, &l); + lua_pushinteger(L, (lua_Integer)l); + return 1; +} + + +/* +** translate a relative initial string position +** (negative means back from end): clip result to [1, inf). +** The length of any string in Lua must fit in a lua_Integer, +** so there are no overflows in the casts. +** The inverted comparison avoids a possible overflow +** computing '-pos'. +*/ +static size_t posrelatI (lua_Integer pos, size_t len) { + if (pos > 0) + return (size_t)pos; + else if (pos == 0) + return 1; + else if (pos < -(lua_Integer)len) /* inverted comparison */ + return 1; /* clip to 1 */ + else return len + (size_t)pos + 1; +} + + +/* +** Gets an optional ending string position from argument 'arg', +** with default value 'def'. +** Negative means back from end: clip result to [0, len] +*/ +static size_t getendpos (lua_State *L, int arg, lua_Integer def, + size_t len) { + lua_Integer pos = luaL_optinteger(L, arg, def); + if (pos > (lua_Integer)len) + return len; + else if (pos >= 0) + return (size_t)pos; + else if (pos < -(lua_Integer)len) + return 0; + else return len + (size_t)pos + 1; +} + + +static int str_sub (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + size_t start = posrelatI(luaL_checkinteger(L, 2), l); + size_t end = getendpos(L, 3, -1, l); + if (start <= end) + lua_pushlstring(L, s + start - 1, (end - start) + 1); + else lua_pushliteral(L, ""); + return 1; +} + + +static int str_reverse (lua_State *L) { + size_t l, i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i = 0; i < l; i++) + p[i] = s[l - i - 1]; + luaL_pushresultsize(&b, l); + return 1; +} + + +static int str_lower (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i=0; i MAXSIZE / n)) + return luaL_error(L, "resulting string too large"); + else { + size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; + luaL_Buffer b; + char *p = luaL_buffinitsize(L, &b, totallen); + while (n-- > 1) { /* first n-1 copies (followed by separator) */ + memcpy(p, s, l * sizeof(char)); p += l; + if (lsep > 0) { /* empty 'memcpy' is not that cheap */ + memcpy(p, sep, lsep * sizeof(char)); + p += lsep; + } + } + memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ + luaL_pushresultsize(&b, totallen); + } + return 1; +} + + +static int str_byte (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + lua_Integer pi = luaL_optinteger(L, 2, 1); + size_t posi = posrelatI(pi, l); + size_t pose = getendpos(L, 3, pi, l); + int n, i; + if (posi > pose) return 0; /* empty interval; return no values */ + if (l_unlikely(pose - posi >= (size_t)INT_MAX)) /* arithmetic overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; + luaL_checkstack(L, n, "string slice too long"); + for (i=0; iinit) { + state->init = 1; + luaL_buffinit(L, &state->B); + } + luaL_addlstring(&state->B, (const char *)b, size); + return 0; +} + + +static int str_dump (lua_State *L) { + struct str_Writer state; + int strip = lua_toboolean(L, 2); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 1); /* ensure function is on the top of the stack */ + state.init = 0; + if (l_unlikely(lua_dump(L, writer, &state, strip) != 0)) + return luaL_error(L, "unable to dump given function"); + luaL_pushresult(&state.B); + return 1; +} + + + +/* +** {====================================================== +** METAMETHODS +** ======================================================= +*/ + +#if defined(LUA_NOCVTS2N) /* { */ + +/* no coercion from strings to numbers */ + +static const luaL_Reg stringmetamethods[] = { + {"__index", NULL}, /* placeholder */ + {NULL, NULL} +}; + +#else /* }{ */ + +static int tonum (lua_State *L, int arg) { + if (lua_type(L, arg) == LUA_TNUMBER) { /* already a number? */ + lua_pushvalue(L, arg); + return 1; + } + else { /* check whether it is a numerical string */ + size_t len; + const char *s = lua_tolstring(L, arg, &len); + return (s != NULL && lua_stringtonumber(L, s) == len + 1); + } +} + + +static void trymt (lua_State *L, const char *mtname) { + lua_settop(L, 2); /* back to the original arguments */ + if (l_unlikely(lua_type(L, 2) == LUA_TSTRING || + !luaL_getmetafield(L, 2, mtname))) + luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2, + luaL_typename(L, -2), luaL_typename(L, -1)); + lua_insert(L, -3); /* put metamethod before arguments */ + lua_call(L, 2, 1); /* call metamethod */ +} + + +static int arith (lua_State *L, int op, const char *mtname) { + if (tonum(L, 1) && tonum(L, 2)) + lua_arith(L, op); /* result will be on the top */ + else + trymt(L, mtname); + return 1; +} + + +static int arith_add (lua_State *L) { + return arith(L, LUA_OPADD, "__add"); +} + +static int arith_sub (lua_State *L) { + return arith(L, LUA_OPSUB, "__sub"); +} + +static int arith_mul (lua_State *L) { + return arith(L, LUA_OPMUL, "__mul"); +} + +static int arith_mod (lua_State *L) { + return arith(L, LUA_OPMOD, "__mod"); +} + +static int arith_pow (lua_State *L) { + return arith(L, LUA_OPPOW, "__pow"); +} + +static int arith_div (lua_State *L) { + return arith(L, LUA_OPDIV, "__div"); +} + +static int arith_idiv (lua_State *L) { + return arith(L, LUA_OPIDIV, "__idiv"); +} + +static int arith_unm (lua_State *L) { + return arith(L, LUA_OPUNM, "__unm"); +} + + +static const luaL_Reg stringmetamethods[] = { + {"__add", arith_add}, + {"__sub", arith_sub}, + {"__mul", arith_mul}, + {"__mod", arith_mod}, + {"__pow", arith_pow}, + {"__div", arith_div}, + {"__idiv", arith_idiv}, + {"__unm", arith_unm}, + {"__index", NULL}, /* placeholder */ + {NULL, NULL} +}; + +#endif /* } */ + +/* }====================================================== */ + +/* +** {====================================================== +** PATTERN MATCHING +** ======================================================= +*/ + + +#define CAP_UNFINISHED (-1) +#define CAP_POSITION (-2) + + +typedef struct MatchState { + const char *src_init; /* init of source string */ + const char *src_end; /* end ('\0') of source string */ + const char *p_end; /* end ('\0') of pattern */ + lua_State *L; + int matchdepth; /* control for recursive depth (to avoid C stack overflow) */ + unsigned char level; /* total number of captures (finished or unfinished) */ + struct { + const char *init; + ptrdiff_t len; + } capture[LUA_MAXCAPTURES]; +} MatchState; + + +/* recursive function */ +static const char *match (MatchState *ms, const char *s, const char *p); + + +/* maximum recursion depth for 'match' */ +#if !defined(MAXCCALLS) +#define MAXCCALLS 200 +#endif + + +#define L_ESC '%' +#define SPECIALS "^$*+?.([%-" + + +static int check_capture (MatchState *ms, int l) { + l -= '1'; + if (l_unlikely(l < 0 || l >= ms->level || + ms->capture[l].len == CAP_UNFINISHED)) + return luaL_error(ms->L, "invalid capture index %%%d", l + 1); + return l; +} + + +static int capture_to_close (MatchState *ms) { + int level = ms->level; + for (level--; level>=0; level--) + if (ms->capture[level].len == CAP_UNFINISHED) return level; + return luaL_error(ms->L, "invalid pattern capture"); +} + + +static const char *classend (MatchState *ms, const char *p) { + switch (*p++) { + case L_ESC: { + if (l_unlikely(p == ms->p_end)) + luaL_error(ms->L, "malformed pattern (ends with '%%')"); + return p+1; + } + case '[': { + if (*p == '^') p++; + do { /* look for a ']' */ + if (l_unlikely(p == ms->p_end)) + luaL_error(ms->L, "malformed pattern (missing ']')"); + if (*(p++) == L_ESC && p < ms->p_end) + p++; /* skip escapes (e.g. '%]') */ + } while (*p != ']'); + return p+1; + } + default: { + return p; + } + } +} + + +static int match_class (int c, int cl) { + int res; + switch (tolower(cl)) { + case 'a' : res = isalpha(c); break; + case 'c' : res = iscntrl(c); break; + case 'd' : res = isdigit(c); break; + case 'g' : res = isgraph(c); break; + case 'l' : res = islower(c); break; + case 'p' : res = ispunct(c); break; + case 's' : res = isspace(c); break; + case 'u' : res = isupper(c); break; + case 'w' : res = isalnum(c); break; + case 'x' : res = isxdigit(c); break; + case 'z' : res = (c == 0); break; /* deprecated option */ + default: return (cl == c); + } + return (islower(cl) ? res : !res); +} + + +static int matchbracketclass (int c, const char *p, const char *ec) { + int sig = 1; + if (*(p+1) == '^') { + sig = 0; + p++; /* skip the '^' */ + } + while (++p < ec) { + if (*p == L_ESC) { + p++; + if (match_class(c, uchar(*p))) + return sig; + } + else if ((*(p+1) == '-') && (p+2 < ec)) { + p+=2; + if (uchar(*(p-2)) <= c && c <= uchar(*p)) + return sig; + } + else if (uchar(*p) == c) return sig; + } + return !sig; +} + + +static int singlematch (MatchState *ms, const char *s, const char *p, + const char *ep) { + if (s >= ms->src_end) + return 0; + else { + int c = uchar(*s); + switch (*p) { + case '.': return 1; /* matches any char */ + case L_ESC: return match_class(c, uchar(*(p+1))); + case '[': return matchbracketclass(c, p, ep-1); + default: return (uchar(*p) == c); + } + } +} + + +static const char *matchbalance (MatchState *ms, const char *s, + const char *p) { + if (l_unlikely(p >= ms->p_end - 1)) + luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); + if (*s != *p) return NULL; + else { + int b = *p; + int e = *(p+1); + int cont = 1; + while (++s < ms->src_end) { + if (*s == e) { + if (--cont == 0) return s+1; + } + else if (*s == b) cont++; + } + } + return NULL; /* string ends out of balance */ +} + + +static const char *max_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + ptrdiff_t i = 0; /* counts maximum expand for item */ + while (singlematch(ms, s + i, p, ep)) + i++; + /* keeps trying to match with the maximum repetitions */ + while (i>=0) { + const char *res = match(ms, (s+i), ep+1); + if (res) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ + } + return NULL; +} + + +static const char *min_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + for (;;) { + const char *res = match(ms, s, ep+1); + if (res != NULL) + return res; + else if (singlematch(ms, s, p, ep)) + s++; /* try with one more repetition */ + else return NULL; + } +} + + +static const char *start_capture (MatchState *ms, const char *s, + const char *p, int what) { + const char *res; + int level = ms->level; + if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); + ms->capture[level].init = s; + ms->capture[level].len = what; + ms->level = level+1; + if ((res=match(ms, s, p)) == NULL) /* match failed? */ + ms->level--; /* undo capture */ + return res; +} + + +static const char *end_capture (MatchState *ms, const char *s, + const char *p) { + int l = capture_to_close(ms); + const char *res; + ms->capture[l].len = s - ms->capture[l].init; /* close capture */ + if ((res = match(ms, s, p)) == NULL) /* match failed? */ + ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ + return res; +} + + +static const char *match_capture (MatchState *ms, const char *s, int l) { + size_t len; + l = check_capture(ms, l); + len = ms->capture[l].len; + if ((size_t)(ms->src_end-s) >= len && + memcmp(ms->capture[l].init, s, len) == 0) + return s+len; + else return NULL; +} + + +static const char *match (MatchState *ms, const char *s, const char *p) { + if (l_unlikely(ms->matchdepth-- == 0)) + luaL_error(ms->L, "pattern too complex"); + init: /* using goto to optimize tail recursion */ + if (p != ms->p_end) { /* end of pattern? */ + switch (*p) { + case '(': { /* start capture */ + if (*(p + 1) == ')') /* position capture? */ + s = start_capture(ms, s, p + 2, CAP_POSITION); + else + s = start_capture(ms, s, p + 1, CAP_UNFINISHED); + break; + } + case ')': { /* end capture */ + s = end_capture(ms, s, p + 1); + break; + } + case '$': { + if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ + goto dflt; /* no; go to default */ + s = (s == ms->src_end) ? s : NULL; /* check end of string */ + break; + } + case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ + switch (*(p + 1)) { + case 'b': { /* balanced string? */ + s = matchbalance(ms, s, p + 2); + if (s != NULL) { + p += 4; goto init; /* return match(ms, s, p + 4); */ + } /* else fail (s == NULL) */ + break; + } + case 'f': { /* frontier? */ + const char *ep; char previous; + p += 2; + if (l_unlikely(*p != '[')) + luaL_error(ms->L, "missing '[' after '%%f' in pattern"); + ep = classend(ms, p); /* points to what is next */ + previous = (s == ms->src_init) ? '\0' : *(s - 1); + if (!matchbracketclass(uchar(previous), p, ep - 1) && + matchbracketclass(uchar(*s), p, ep - 1)) { + p = ep; goto init; /* return match(ms, s, ep); */ + } + s = NULL; /* match failed */ + break; + } + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p + 1))); + if (s != NULL) { + p += 2; goto init; /* return match(ms, s, p + 2) */ + } + break; + } + default: goto dflt; + } + break; + } + default: dflt: { /* pattern class plus optional suffix */ + const char *ep = classend(ms, p); /* points to optional suffix */ + /* does not match at least once? */ + if (!singlematch(ms, s, p, ep)) { + if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ + p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ + } + else /* '+' or no suffix */ + s = NULL; /* fail */ + } + else { /* matched once */ + switch (*ep) { /* handle optional suffix */ + case '?': { /* optional */ + const char *res; + if ((res = match(ms, s + 1, ep + 1)) != NULL) + s = res; + else { + p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ + } + break; + } + case '+': /* 1 or more repetitions */ + s++; /* 1 match already done */ + /* FALLTHROUGH */ + case '*': /* 0 or more repetitions */ + s = max_expand(ms, s, p, ep); + break; + case '-': /* 0 or more repetitions (minimum) */ + s = min_expand(ms, s, p, ep); + break; + default: /* no suffix */ + s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ + } + } + break; + } + } + } + ms->matchdepth++; + return s; +} + + + +static const char *lmemfind (const char *s1, size_t l1, + const char *s2, size_t l2) { + if (l2 == 0) return s1; /* empty strings are everywhere */ + else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ + else { + const char *init; /* to search for a '*s2' inside 's1' */ + l2--; /* 1st char will be checked by 'memchr' */ + l1 = l1-l2; /* 's2' cannot be found after that */ + while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { + init++; /* 1st char is already checked */ + if (memcmp(init, s2+1, l2) == 0) + return init-1; + else { /* correct 'l1' and 's1' to try again */ + l1 -= init-s1; + s1 = init; + } + } + return NULL; /* not found */ + } +} + + +/* +** get information about the i-th capture. If there are no captures +** and 'i==0', return information about the whole match, which +** is the range 's'..'e'. If the capture is a string, return +** its length and put its address in '*cap'. If it is an integer +** (a position), push it on the stack and return CAP_POSITION. +*/ +static size_t get_onecapture (MatchState *ms, int i, const char *s, + const char *e, const char **cap) { + if (i >= ms->level) { + if (l_unlikely(i != 0)) + luaL_error(ms->L, "invalid capture index %%%d", i + 1); + *cap = s; + return e - s; + } + else { + ptrdiff_t capl = ms->capture[i].len; + *cap = ms->capture[i].init; + if (l_unlikely(capl == CAP_UNFINISHED)) + luaL_error(ms->L, "unfinished capture"); + else if (capl == CAP_POSITION) + lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); + return capl; + } +} + + +/* +** Push the i-th capture on the stack. +*/ +static void push_onecapture (MatchState *ms, int i, const char *s, + const char *e) { + const char *cap; + ptrdiff_t l = get_onecapture(ms, i, s, e, &cap); + if (l != CAP_POSITION) + lua_pushlstring(ms->L, cap, l); + /* else position was already pushed */ +} + + +static int push_captures (MatchState *ms, const char *s, const char *e) { + int i; + int nlevels = (ms->level == 0 && s) ? 1 : ms->level; + luaL_checkstack(ms->L, nlevels, "too many captures"); + for (i = 0; i < nlevels; i++) + push_onecapture(ms, i, s, e); + return nlevels; /* number of strings pushed */ +} + + +/* check whether pattern has no special characters */ +static int nospecials (const char *p, size_t l) { + size_t upto = 0; + do { + if (strpbrk(p + upto, SPECIALS)) + return 0; /* pattern has a special character */ + upto += strlen(p + upto) + 1; /* may have more after \0 */ + } while (upto <= l); + return 1; /* no special chars found */ +} + + +static void prepstate (MatchState *ms, lua_State *L, + const char *s, size_t ls, const char *p, size_t lp) { + ms->L = L; + ms->matchdepth = MAXCCALLS; + ms->src_init = s; + ms->src_end = s + ls; + ms->p_end = p + lp; +} + + +static void reprepstate (MatchState *ms) { + ms->level = 0; + lua_assert(ms->matchdepth == MAXCCALLS); +} + + +static int str_find_aux (lua_State *L, int find) { + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + size_t init = posrelatI(luaL_optinteger(L, 3, 1), ls) - 1; + if (init > ls) { /* start after string's end? */ + luaL_pushfail(L); /* cannot find anything */ + return 1; + } + /* explicit request or no special characters? */ + if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { + /* do a plain search */ + const char *s2 = lmemfind(s + init, ls - init, p, lp); + if (s2) { + lua_pushinteger(L, (s2 - s) + 1); + lua_pushinteger(L, (s2 - s) + lp); + return 2; + } + } + else { + MatchState ms; + const char *s1 = s + init; + int anchor = (*p == '^'); + if (anchor) { + p++; lp--; /* skip anchor character */ + } + prepstate(&ms, L, s, ls, p, lp); + do { + const char *res; + reprepstate(&ms); + if ((res=match(&ms, s1, p)) != NULL) { + if (find) { + lua_pushinteger(L, (s1 - s) + 1); /* start */ + lua_pushinteger(L, res - s); /* end */ + return push_captures(&ms, NULL, 0) + 2; + } + else + return push_captures(&ms, s1, res); + } + } while (s1++ < ms.src_end && !anchor); + } + luaL_pushfail(L); /* not found */ + return 1; +} + + +static int str_find (lua_State *L) { + return str_find_aux(L, 1); +} + + +static int str_match (lua_State *L) { + return str_find_aux(L, 0); +} + + +/* state for 'gmatch' */ +typedef struct GMatchState { + const char *src; /* current position */ + const char *p; /* pattern */ + const char *lastmatch; /* end of last match */ + MatchState ms; /* match state */ +} GMatchState; + + +static int gmatch_aux (lua_State *L) { + GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); + const char *src; + gm->ms.L = L; + for (src = gm->src; src <= gm->ms.src_end; src++) { + const char *e; + reprepstate(&gm->ms); + if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { + gm->src = gm->lastmatch = e; + return push_captures(&gm->ms, src, e); + } + } + return 0; /* not found */ +} + + +static int gmatch (lua_State *L) { + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + size_t init = posrelatI(luaL_optinteger(L, 3, 1), ls) - 1; + GMatchState *gm; + lua_settop(L, 2); /* keep strings on closure to avoid being collected */ + gm = (GMatchState *)lua_newuserdatauv(L, sizeof(GMatchState), 0); + if (init > ls) /* start after string's end? */ + init = ls + 1; /* avoid overflows in 's + init' */ + prepstate(&gm->ms, L, s, ls, p, lp); + gm->src = s + init; gm->p = p; gm->lastmatch = NULL; + lua_pushcclosure(L, gmatch_aux, 3); + return 1; +} + + +static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e) { + size_t l; + lua_State *L = ms->L; + const char *news = lua_tolstring(L, 3, &l); + const char *p; + while ((p = (char *)memchr(news, L_ESC, l)) != NULL) { + luaL_addlstring(b, news, p - news); + p++; /* skip ESC */ + if (*p == L_ESC) /* '%%' */ + luaL_addchar(b, *p); + else if (*p == '0') /* '%0' */ + luaL_addlstring(b, s, e - s); + else if (isdigit(uchar(*p))) { /* '%n' */ + const char *cap; + ptrdiff_t resl = get_onecapture(ms, *p - '1', s, e, &cap); + if (resl == CAP_POSITION) + luaL_addvalue(b); /* add position to accumulated result */ + else + luaL_addlstring(b, cap, resl); + } + else + luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); + l -= p + 1 - news; + news = p + 1; + } + luaL_addlstring(b, news, l); +} + + +/* +** Add the replacement value to the string buffer 'b'. +** Return true if the original string was changed. (Function calls and +** table indexing resulting in nil or false do not change the subject.) +*/ +static int add_value (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e, int tr) { + lua_State *L = ms->L; + switch (tr) { + case LUA_TFUNCTION: { /* call the function */ + int n; + lua_pushvalue(L, 3); /* push the function */ + n = push_captures(ms, s, e); /* all captures as arguments */ + lua_call(L, n, 1); /* call it */ + break; + } + case LUA_TTABLE: { /* index the table */ + push_onecapture(ms, 0, s, e); /* first capture is the index */ + lua_gettable(L, 3); + break; + } + default: { /* LUA_TNUMBER or LUA_TSTRING */ + add_s(ms, b, s, e); /* add value to the buffer */ + return 1; /* something changed */ + } + } + if (!lua_toboolean(L, -1)) { /* nil or false? */ + lua_pop(L, 1); /* remove value */ + luaL_addlstring(b, s, e - s); /* keep original text */ + return 0; /* no changes */ + } + else if (l_unlikely(!lua_isstring(L, -1))) + return luaL_error(L, "invalid replacement value (a %s)", + luaL_typename(L, -1)); + else { + luaL_addvalue(b); /* add result to accumulator */ + return 1; /* something changed */ + } +} + + +static int str_gsub (lua_State *L) { + size_t srcl, lp; + const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ + const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ + const char *lastmatch = NULL; /* end of last match */ + int tr = lua_type(L, 3); /* replacement type */ + lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ + int anchor = (*p == '^'); + lua_Integer n = 0; /* replacement count */ + int changed = 0; /* change flag */ + MatchState ms; + luaL_Buffer b; + luaL_argexpected(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || + tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, + "string/function/table"); + luaL_buffinit(L, &b); + if (anchor) { + p++; lp--; /* skip anchor character */ + } + prepstate(&ms, L, src, srcl, p, lp); + while (n < max_s) { + const char *e; + reprepstate(&ms); /* (re)prepare state for new match */ + if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ + n++; + changed = add_value(&ms, &b, src, e, tr) | changed; + src = lastmatch = e; + } + else if (src < ms.src_end) /* otherwise, skip one character */ + luaL_addchar(&b, *src++); + else break; /* end of subject */ + if (anchor) break; + } + if (!changed) /* no changes? */ + lua_pushvalue(L, 1); /* return original string */ + else { /* something changed */ + luaL_addlstring(&b, src, ms.src_end-src); + luaL_pushresult(&b); /* create and return new string */ + } + lua_pushinteger(L, n); /* number of substitutions */ + return 2; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** STRING FORMAT +** ======================================================= +*/ + +#if !defined(lua_number2strx) /* { */ + +/* +** Hexadecimal floating-point formatter +*/ + +#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) + + +/* +** Number of bits that goes into the first digit. It can be any value +** between 1 and 4; the following definition tries to align the number +** to nibble boundaries by making what is left after that first digit a +** multiple of 4. +*/ +#define L_NBFD ((l_floatatt(MANT_DIG) - 1)%4 + 1) + + +/* +** Add integer part of 'x' to buffer and return new 'x' +*/ +static lua_Number adddigit (char *buff, int n, lua_Number x) { + lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ + int d = (int)dd; + buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ + return x - dd; /* return what is left */ +} + + +static int num2straux (char *buff, int sz, lua_Number x) { + /* if 'inf' or 'NaN', format it like '%g' */ + if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL) + return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x); + else if (x == 0) { /* can be -0... */ + /* create "0" or "-0" followed by exponent */ + return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x); + } + else { + int e; + lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ + int n = 0; /* character count */ + if (m < 0) { /* is number negative? */ + buff[n++] = '-'; /* add sign */ + m = -m; /* make it positive */ + } + buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ + m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ + e -= L_NBFD; /* this digit goes before the radix point */ + if (m > 0) { /* more digits? */ + buff[n++] = lua_getlocaledecpoint(); /* add radix point */ + do { /* add as many digits as needed */ + m = adddigit(buff, n++, m * 16); + } while (m > 0); + } + n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ + lua_assert(n < sz); + return n; + } +} + + +static int lua_number2strx (lua_State *L, char *buff, int sz, + const char *fmt, lua_Number x) { + int n = num2straux(buff, sz, x); + if (fmt[SIZELENMOD] == 'A') { + int i; + for (i = 0; i < n; i++) + buff[i] = toupper(uchar(buff[i])); + } + else if (l_unlikely(fmt[SIZELENMOD] != 'a')) + return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); + return n; +} + +#endif /* } */ + + +/* +** Maximum size for items formatted with '%f'. This size is produced +** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', +** and '\0') + number of decimal digits to represent maxfloat (which +** is maximum exponent + 1). (99+3+1, adding some extra, 110) +*/ +#define MAX_ITEMF (110 + l_floatatt(MAX_10_EXP)) + + +/* +** All formats except '%f' do not need that large limit. The other +** float formats use exponents, so that they fit in the 99 limit for +** significant digits; 's' for large strings and 'q' add items directly +** to the buffer; all integer formats also fit in the 99 limit. The +** worst case are floats: they may need 99 significant digits, plus +** '0x', '-', '.', 'e+XXXX', and '\0'. Adding some extra, 120. +*/ +#define MAX_ITEM 120 + + +/* valid flags in a format specification */ +#if !defined(L_FMTFLAGSF) + +/* valid flags for a, A, e, E, f, F, g, and G conversions */ +#define L_FMTFLAGSF "-+#0 " + +/* valid flags for o, x, and X conversions */ +#define L_FMTFLAGSX "-#0" + +/* valid flags for d and i conversions */ +#define L_FMTFLAGSI "-+0 " + +/* valid flags for u conversions */ +#define L_FMTFLAGSU "-0" + +/* valid flags for c, p, and s conversions */ +#define L_FMTFLAGSC "-" + +#endif + + +/* +** Maximum size of each format specification (such as "%-099.99d"): +** Initial '%', flags (up to 5), width (2), period, precision (2), +** length modifier (8), conversion specifier, and final '\0', plus some +** extra. +*/ +#define MAX_FORMAT 32 + + +static void addquoted (luaL_Buffer *b, const char *s, size_t len) { + luaL_addchar(b, '"'); + while (len--) { + if (*s == '"' || *s == '\\' || *s == '\n') { + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); + } + else if (iscntrl(uchar(*s))) { + char buff[10]; + if (!isdigit(uchar(*(s+1)))) + l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); + else + l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); + luaL_addstring(b, buff); + } + else + luaL_addchar(b, *s); + s++; + } + luaL_addchar(b, '"'); +} + + +/* +** Serialize a floating-point number in such a way that it can be +** scanned back by Lua. Use hexadecimal format for "common" numbers +** (to preserve precision); inf, -inf, and NaN are handled separately. +** (NaN cannot be expressed as a numeral, so we write '(0/0)' for it.) +*/ +static int quotefloat (lua_State *L, char *buff, lua_Number n) { + const char *s; /* for the fixed representations */ + if (n == (lua_Number)HUGE_VAL) /* inf? */ + s = "1e9999"; + else if (n == -(lua_Number)HUGE_VAL) /* -inf? */ + s = "-1e9999"; + else if (n != n) /* NaN? */ + s = "(0/0)"; + else { /* format number as hexadecimal */ + int nb = lua_number2strx(L, buff, MAX_ITEM, + "%" LUA_NUMBER_FRMLEN "a", n); + /* ensures that 'buff' string uses a dot as the radix character */ + if (memchr(buff, '.', nb) == NULL) { /* no dot? */ + char point = lua_getlocaledecpoint(); /* try locale point */ + char *ppoint = (char *)memchr(buff, point, nb); + if (ppoint) *ppoint = '.'; /* change it to a dot */ + } + return nb; + } + /* for the fixed representations */ + return l_sprintf(buff, MAX_ITEM, "%s", s); +} + + +static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { + switch (lua_type(L, arg)) { + case LUA_TSTRING: { + size_t len; + const char *s = lua_tolstring(L, arg, &len); + addquoted(b, s, len); + break; + } + case LUA_TNUMBER: { + char *buff = luaL_prepbuffsize(b, MAX_ITEM); + int nb; + if (!lua_isinteger(L, arg)) /* float? */ + nb = quotefloat(L, buff, lua_tonumber(L, arg)); + else { /* integers */ + lua_Integer n = lua_tointeger(L, arg); + const char *format = (n == LUA_MININTEGER) /* corner case? */ + ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hex */ + : LUA_INTEGER_FMT; /* else use default format */ + nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); + } + luaL_addsize(b, nb); + break; + } + case LUA_TNIL: case LUA_TBOOLEAN: { + luaL_tolstring(L, arg, NULL); + luaL_addvalue(b); + break; + } + default: { + luaL_argerror(L, arg, "value has no literal form"); + } + } +} + + +static const char *get2digits (const char *s) { + if (isdigit(uchar(*s))) { + s++; + if (isdigit(uchar(*s))) s++; /* (2 digits at most) */ + } + return s; +} + + +/* +** Check whether a conversion specification is valid. When called, +** first character in 'form' must be '%' and last character must +** be a valid conversion specifier. 'flags' are the accepted flags; +** 'precision' signals whether to accept a precision. +*/ +static void checkformat (lua_State *L, const char *form, const char *flags, + int precision) { + const char *spec = form + 1; /* skip '%' */ + spec += strspn(spec, flags); /* skip flags */ + if (*spec != '0') { /* a width cannot start with '0' */ + spec = get2digits(spec); /* skip width */ + if (*spec == '.' && precision) { + spec++; + spec = get2digits(spec); /* skip precision */ + } + } + if (!isalpha(uchar(*spec))) /* did not go to the end? */ + luaL_error(L, "invalid conversion specification: '%s'", form); +} + + +/* +** Get a conversion specification and copy it to 'form'. +** Return the address of its last character. +*/ +static const char *getformat (lua_State *L, const char *strfrmt, + char *form) { + /* spans flags, width, and precision ('0' is included as a flag) */ + size_t len = strspn(strfrmt, L_FMTFLAGSF "123456789."); + len++; /* adds following character (should be the specifier) */ + /* still needs space for '%', '\0', plus a length modifier */ + if (len >= MAX_FORMAT - 10) + luaL_error(L, "invalid format (too long)"); + *(form++) = '%'; + memcpy(form, strfrmt, len * sizeof(char)); + *(form + len) = '\0'; + return strfrmt + len - 1; +} + + +/* +** add length modifier into formats +*/ +static void addlenmod (char *form, const char *lenmod) { + size_t l = strlen(form); + size_t lm = strlen(lenmod); + char spec = form[l - 1]; + strcpy(form + l - 1, lenmod); + form[l + lm - 1] = spec; + form[l + lm] = '\0'; +} + + +static int str_format (lua_State *L) { + int top = lua_gettop(L); + int arg = 1; + size_t sfl; + const char *strfrmt = luaL_checklstring(L, arg, &sfl); + const char *strfrmt_end = strfrmt+sfl; + const char *flags; + luaL_Buffer b; + luaL_buffinit(L, &b); + while (strfrmt < strfrmt_end) { + if (*strfrmt != L_ESC) + luaL_addchar(&b, *strfrmt++); + else if (*++strfrmt == L_ESC) + luaL_addchar(&b, *strfrmt++); /* %% */ + else { /* format item */ + char form[MAX_FORMAT]; /* to store the format ('%...') */ + int maxitem = MAX_ITEM; /* maximum length for the result */ + char *buff = luaL_prepbuffsize(&b, maxitem); /* to put result */ + int nb = 0; /* number of bytes in result */ + if (++arg > top) + return luaL_argerror(L, arg, "no value"); + strfrmt = getformat(L, strfrmt, form); + switch (*strfrmt++) { + case 'c': { + checkformat(L, form, L_FMTFLAGSC, 0); + nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg)); + break; + } + case 'd': case 'i': + flags = L_FMTFLAGSI; + goto intcase; + case 'u': + flags = L_FMTFLAGSU; + goto intcase; + case 'o': case 'x': case 'X': + flags = L_FMTFLAGSX; + intcase: { + lua_Integer n = luaL_checkinteger(L, arg); + checkformat(L, form, flags, 1); + addlenmod(form, LUA_INTEGER_FRMLEN); + nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n); + break; + } + case 'a': case 'A': + checkformat(L, form, L_FMTFLAGSF, 1); + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = lua_number2strx(L, buff, maxitem, form, + luaL_checknumber(L, arg)); + break; + case 'f': + maxitem = MAX_ITEMF; /* extra space for '%f' */ + buff = luaL_prepbuffsize(&b, maxitem); + /* FALLTHROUGH */ + case 'e': case 'E': case 'g': case 'G': { + lua_Number n = luaL_checknumber(L, arg); + checkformat(L, form, L_FMTFLAGSF, 1); + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n); + break; + } + case 'p': { + const void *p = lua_topointer(L, arg); + checkformat(L, form, L_FMTFLAGSC, 0); + if (p == NULL) { /* avoid calling 'printf' with argument NULL */ + p = "(null)"; /* result */ + form[strlen(form) - 1] = 's'; /* format it as a string */ + } + nb = l_sprintf(buff, maxitem, form, p); + break; + } + case 'q': { + if (form[2] != '\0') /* modifiers? */ + return luaL_error(L, "specifier '%%q' cannot have modifiers"); + addliteral(L, &b, arg); + break; + } + case 's': { + size_t l; + const char *s = luaL_tolstring(L, arg, &l); + if (form[2] == '\0') /* no modifiers? */ + luaL_addvalue(&b); /* keep entire string */ + else { + luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); + checkformat(L, form, L_FMTFLAGSC, 1); + if (strchr(form, '.') == NULL && l >= 100) { + /* no precision and string is too long to be formatted */ + luaL_addvalue(&b); /* keep entire string */ + } + else { /* format the string into 'buff' */ + nb = l_sprintf(buff, maxitem, form, s); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ + } + } + break; + } + default: { /* also treat cases 'pnLlh' */ + return luaL_error(L, "invalid conversion '%s' to 'format'", form); + } + } + lua_assert(nb < maxitem); + luaL_addsize(&b, nb); + } + } + luaL_pushresult(&b); + return 1; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** PACK/UNPACK +** ======================================================= +*/ + + +/* value used for padding */ +#if !defined(LUAL_PACKPADBYTE) +#define LUAL_PACKPADBYTE 0x00 +#endif + +/* maximum size for the binary representation of an integer */ +#define MAXINTSIZE 16 + +/* number of bits in a character */ +#define NB CHAR_BIT + +/* mask for one character (NB 1's) */ +#define MC ((1 << NB) - 1) + +/* size of a lua_Integer */ +#define SZINT ((int)sizeof(lua_Integer)) + + +/* dummy union to get native endianness */ +static const union { + int dummy; + char little; /* true iff machine is little endian */ +} nativeendian = {1}; + + +/* +** information to pack/unpack stuff +*/ +typedef struct Header { + lua_State *L; + int islittle; + int maxalign; +} Header; + + +/* +** options for pack/unpack +*/ +typedef enum KOption { + Kint, /* signed integers */ + Kuint, /* unsigned integers */ + Kfloat, /* single-precision floating-point numbers */ + Knumber, /* Lua "native" floating-point numbers */ + Kdouble, /* double-precision floating-point numbers */ + Kchar, /* fixed-length strings */ + Kstring, /* strings with prefixed length */ + Kzstr, /* zero-terminated strings */ + Kpadding, /* padding */ + Kpaddalign, /* padding for alignment */ + Knop /* no-op (configuration or spaces) */ +} KOption; + + +/* +** Read an integer numeral from string 'fmt' or return 'df' if +** there is no numeral +*/ +static int digit (int c) { return '0' <= c && c <= '9'; } + +static int getnum (const char **fmt, int df) { + if (!digit(**fmt)) /* no number? */ + return df; /* return default value */ + else { + int a = 0; + do { + a = a*10 + (*((*fmt)++) - '0'); + } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); + return a; + } +} + + +/* +** Read an integer numeral and raises an error if it is larger +** than the maximum size for integers. +*/ +static int getnumlimit (Header *h, const char **fmt, int df) { + int sz = getnum(fmt, df); + if (l_unlikely(sz > MAXINTSIZE || sz <= 0)) + return luaL_error(h->L, "integral size (%d) out of limits [1,%d]", + sz, MAXINTSIZE); + return sz; +} + + +/* +** Initialize Header +*/ +static void initheader (lua_State *L, Header *h) { + h->L = L; + h->islittle = nativeendian.little; + h->maxalign = 1; +} + + +/* +** Read and classify next option. 'size' is filled with option's size. +*/ +static KOption getoption (Header *h, const char **fmt, int *size) { + /* dummy structure to get native alignment requirements */ + struct cD { char c; union { LUAI_MAXALIGN; } u; }; + int opt = *((*fmt)++); + *size = 0; /* default */ + switch (opt) { + case 'b': *size = sizeof(char); return Kint; + case 'B': *size = sizeof(char); return Kuint; + case 'h': *size = sizeof(short); return Kint; + case 'H': *size = sizeof(short); return Kuint; + case 'l': *size = sizeof(long); return Kint; + case 'L': *size = sizeof(long); return Kuint; + case 'j': *size = sizeof(lua_Integer); return Kint; + case 'J': *size = sizeof(lua_Integer); return Kuint; + case 'T': *size = sizeof(size_t); return Kuint; + case 'f': *size = sizeof(float); return Kfloat; + case 'n': *size = sizeof(lua_Number); return Knumber; + case 'd': *size = sizeof(double); return Kdouble; + case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; + case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; + case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; + case 'c': + *size = getnum(fmt, -1); + if (l_unlikely(*size == -1)) + luaL_error(h->L, "missing size for format option 'c'"); + return Kchar; + case 'z': return Kzstr; + case 'x': *size = 1; return Kpadding; + case 'X': return Kpaddalign; + case ' ': break; + case '<': h->islittle = 1; break; + case '>': h->islittle = 0; break; + case '=': h->islittle = nativeendian.little; break; + case '!': { + const int maxalign = offsetof(struct cD, u); + h->maxalign = getnumlimit(h, fmt, maxalign); + break; + } + default: luaL_error(h->L, "invalid format option '%c'", opt); + } + return Knop; +} + + +/* +** Read, classify, and fill other details about the next option. +** 'psize' is filled with option's size, 'notoalign' with its +** alignment requirements. +** Local variable 'size' gets the size to be aligned. (Kpadal option +** always gets its full alignment, other options are limited by +** the maximum alignment ('maxalign'). Kchar option needs no alignment +** despite its size. +*/ +static KOption getdetails (Header *h, size_t totalsize, + const char **fmt, int *psize, int *ntoalign) { + KOption opt = getoption(h, fmt, psize); + int align = *psize; /* usually, alignment follows size */ + if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ + if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) + luaL_argerror(h->L, 1, "invalid next option for option 'X'"); + } + if (align <= 1 || opt == Kchar) /* need no alignment? */ + *ntoalign = 0; + else { + if (align > h->maxalign) /* enforce maximum alignment */ + align = h->maxalign; + if (l_unlikely((align & (align - 1)) != 0)) /* not a power of 2? */ + luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); + *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); + } + return opt; +} + + +/* +** Pack integer 'n' with 'size' bytes and 'islittle' endianness. +** The final 'if' handles the case when 'size' is larger than +** the size of a Lua integer, correcting the extra sign-extension +** bytes if necessary (by default they would be zeros). +*/ +static void packint (luaL_Buffer *b, lua_Unsigned n, + int islittle, int size, int neg) { + char *buff = luaL_prepbuffsize(b, size); + int i; + buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ + for (i = 1; i < size; i++) { + n >>= NB; + buff[islittle ? i : size - 1 - i] = (char)(n & MC); + } + if (neg && size > SZINT) { /* negative number need sign extension? */ + for (i = SZINT; i < size; i++) /* correct extra bytes */ + buff[islittle ? i : size - 1 - i] = (char)MC; + } + luaL_addsize(b, size); /* add result to buffer */ +} + + +/* +** Copy 'size' bytes from 'src' to 'dest', correcting endianness if +** given 'islittle' is different from native endianness. +*/ +static void copywithendian (char *dest, const char *src, + int size, int islittle) { + if (islittle == nativeendian.little) + memcpy(dest, src, size); + else { + dest += size - 1; + while (size-- != 0) + *(dest--) = *(src++); + } +} + + +static int str_pack (lua_State *L) { + luaL_Buffer b; + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + int arg = 1; /* current argument to pack */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + lua_pushnil(L); /* mark to separate arguments from string buffer */ + luaL_buffinit(L, &b); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + totalsize += ntoalign + size; + while (ntoalign-- > 0) + luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ + arg++; + switch (opt) { + case Kint: { /* signed integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) { /* need overflow check? */ + lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); + luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); + } + packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); + break; + } + case Kuint: { /* unsigned integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) /* need overflow check? */ + luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), + arg, "unsigned overflow"); + packint(&b, (lua_Unsigned)n, h.islittle, size, 0); + break; + } + case Kfloat: { /* C float */ + float f = (float)luaL_checknumber(L, arg); /* get argument */ + char *buff = luaL_prepbuffsize(&b, sizeof(f)); + /* move 'f' to final result, correcting endianness if needed */ + copywithendian(buff, (char *)&f, sizeof(f), h.islittle); + luaL_addsize(&b, size); + break; + } + case Knumber: { /* Lua float */ + lua_Number f = luaL_checknumber(L, arg); /* get argument */ + char *buff = luaL_prepbuffsize(&b, sizeof(f)); + /* move 'f' to final result, correcting endianness if needed */ + copywithendian(buff, (char *)&f, sizeof(f), h.islittle); + luaL_addsize(&b, size); + break; + } + case Kdouble: { /* C double */ + double f = (double)luaL_checknumber(L, arg); /* get argument */ + char *buff = luaL_prepbuffsize(&b, sizeof(f)); + /* move 'f' to final result, correcting endianness if needed */ + copywithendian(buff, (char *)&f, sizeof(f), h.islittle); + luaL_addsize(&b, size); + break; + } + case Kchar: { /* fixed-size string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, len <= (size_t)size, arg, + "string longer than given size"); + luaL_addlstring(&b, s, len); /* add string */ + while (len++ < (size_t)size) /* pad extra space */ + luaL_addchar(&b, LUAL_PACKPADBYTE); + break; + } + case Kstring: { /* strings with length count */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, size >= (int)sizeof(size_t) || + len < ((size_t)1 << (size * NB)), + arg, "string length does not fit in given size"); + packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ + luaL_addlstring(&b, s, len); + totalsize += len; + break; + } + case Kzstr: { /* zero-terminated string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); + luaL_addlstring(&b, s, len); + luaL_addchar(&b, '\0'); /* add zero at the end */ + totalsize += len + 1; + break; + } + case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ + case Kpaddalign: case Knop: + arg--; /* undo increment */ + break; + } + } + luaL_pushresult(&b); + return 1; +} + + +static int str_packsize (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1, + "variable-length format"); + size += ntoalign; /* total space used by option */ + luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, + "format result too large"); + totalsize += size; + } + lua_pushinteger(L, (lua_Integer)totalsize); + return 1; +} + + +/* +** Unpack an integer with 'size' bytes and 'islittle' endianness. +** If size is smaller than the size of a Lua integer and integer +** is signed, must do sign extension (propagating the sign to the +** higher bits); if size is larger than the size of a Lua integer, +** it must check the unread bytes to see whether they do not cause an +** overflow. +*/ +static lua_Integer unpackint (lua_State *L, const char *str, + int islittle, int size, int issigned) { + lua_Unsigned res = 0; + int i; + int limit = (size <= SZINT) ? size : SZINT; + for (i = limit - 1; i >= 0; i--) { + res <<= NB; + res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; + } + if (size < SZINT) { /* real size smaller than lua_Integer? */ + if (issigned) { /* needs sign extension? */ + lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); + res = ((res ^ mask) - mask); /* do sign extension */ + } + } + else if (size > SZINT) { /* must check unread bytes */ + int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; + for (i = limit; i < size; i++) { + if (l_unlikely((unsigned char)str[islittle ? i : size - 1 - i] != mask)) + luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); + } + } + return (lua_Integer)res; +} + + +static int str_unpack (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); + size_t ld; + const char *data = luaL_checklstring(L, 2, &ld); + size_t pos = posrelatI(luaL_optinteger(L, 3, 1), ld) - 1; + int n = 0; /* number of results */ + luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); + luaL_argcheck(L, (size_t)ntoalign + size <= ld - pos, 2, + "data string too short"); + pos += ntoalign; /* skip alignment */ + /* stack space for item + next position */ + luaL_checkstack(L, 2, "too many results"); + n++; + switch (opt) { + case Kint: + case Kuint: { + lua_Integer res = unpackint(L, data + pos, h.islittle, size, + (opt == Kint)); + lua_pushinteger(L, res); + break; + } + case Kfloat: { + float f; + copywithendian((char *)&f, data + pos, sizeof(f), h.islittle); + lua_pushnumber(L, (lua_Number)f); + break; + } + case Knumber: { + lua_Number f; + copywithendian((char *)&f, data + pos, sizeof(f), h.islittle); + lua_pushnumber(L, f); + break; + } + case Kdouble: { + double f; + copywithendian((char *)&f, data + pos, sizeof(f), h.islittle); + lua_pushnumber(L, (lua_Number)f); + break; + } + case Kchar: { + lua_pushlstring(L, data + pos, size); + break; + } + case Kstring: { + size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); + luaL_argcheck(L, len <= ld - pos - size, 2, "data string too short"); + lua_pushlstring(L, data + pos + size, len); + pos += len; /* skip string */ + break; + } + case Kzstr: { + size_t len = strlen(data + pos); + luaL_argcheck(L, pos + len < ld, 2, + "unfinished string for format 'z'"); + lua_pushlstring(L, data + pos, len); + pos += len + 1; /* skip string plus final '\0' */ + break; + } + case Kpaddalign: case Kpadding: case Knop: + n--; /* undo increment */ + break; + } + pos += size; + } + lua_pushinteger(L, pos + 1); /* next position */ + return n + 1; +} + +/* }====================================================== */ + + +static const luaL_Reg strlib[] = { + {"byte", str_byte}, + {"char", str_char}, + {"dump", str_dump}, + {"find", str_find}, + {"format", str_format}, + {"gmatch", gmatch}, + {"gsub", str_gsub}, + {"len", str_len}, + {"lower", str_lower}, + {"match", str_match}, + {"rep", str_rep}, + {"reverse", str_reverse}, + {"sub", str_sub}, + {"upper", str_upper}, + {"pack", str_pack}, + {"packsize", str_packsize}, + {"unpack", str_unpack}, + {NULL, NULL} +}; + + +static void createmetatable (lua_State *L) { + /* table to be metatable for strings */ + luaL_newlibtable(L, stringmetamethods); + luaL_setfuncs(L, stringmetamethods, 0); + lua_pushliteral(L, ""); /* dummy string */ + lua_pushvalue(L, -2); /* copy table */ + lua_setmetatable(L, -2); /* set table as metatable for strings */ + lua_pop(L, 1); /* pop dummy string */ + lua_pushvalue(L, -2); /* get string library */ + lua_setfield(L, -2, "__index"); /* metatable.__index = string */ + lua_pop(L, 1); /* pop metatable */ +} + + +/* +** Open string library +*/ +LUAMOD_API int luaopen_string (lua_State *L) { + luaL_newlib(L, strlib); + createmetatable(L); + return 1; +} + diff --git a/vendor/lua-src/lua-5.4.6/ltable.c b/vendor/lua-src/lua-5.4.6/ltable.c new file mode 100644 index 0000000000000..3c690c5f1751d --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/ltable.c @@ -0,0 +1,980 @@ +/* +** $Id: ltable.c $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +#define ltable_c +#define LUA_CORE + +#include "lprefix.h" + + +/* +** Implementation of tables (aka arrays, objects, or hash tables). +** Tables keep its elements in two parts: an array part and a hash part. +** Non-negative integer keys are all candidates to be kept in the array +** part. The actual size of the array is the largest 'n' such that +** more than half the slots between 1 and n are in use. +** Hash uses a mix of chained scatter table with Brent's variation. +** A main invariant of these tables is that, if an element is not +** in its main position (i.e. the 'original' position that its hash gives +** to it), then the colliding element is in its own main position. +** Hence even when the load factor reaches 100%, performance remains good. +*/ + +#include +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "lvm.h" + + +/* +** MAXABITS is the largest integer such that MAXASIZE fits in an +** unsigned int. +*/ +#define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1) + + +/* +** MAXASIZE is the maximum size of the array part. It is the minimum +** between 2^MAXABITS and the maximum size that, measured in bytes, +** fits in a 'size_t'. +*/ +#define MAXASIZE luaM_limitN(1u << MAXABITS, TValue) + +/* +** MAXHBITS is the largest integer such that 2^MAXHBITS fits in a +** signed int. +*/ +#define MAXHBITS (MAXABITS - 1) + + +/* +** MAXHSIZE is the maximum size of the hash part. It is the minimum +** between 2^MAXHBITS and the maximum size such that, measured in bytes, +** it fits in a 'size_t'. +*/ +#define MAXHSIZE luaM_limitN(1u << MAXHBITS, Node) + + +/* +** When the original hash value is good, hashing by a power of 2 +** avoids the cost of '%'. +*/ +#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) + +/* +** for other types, it is better to avoid modulo by power of 2, as +** they can have many 2 factors. +*/ +#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) + + +#define hashstr(t,str) hashpow2(t, (str)->hash) +#define hashboolean(t,p) hashpow2(t, p) + + +#define hashpointer(t,p) hashmod(t, point2uint(p)) + + +#define dummynode (&dummynode_) + +static const Node dummynode_ = { + {{NULL}, LUA_VEMPTY, /* value's value and type */ + LUA_VNIL, 0, {NULL}} /* key type, next, and key value */ +}; + + +static const TValue absentkey = {ABSTKEYCONSTANT}; + + +/* +** Hash for integers. To allow a good hash, use the remainder operator +** ('%'). If integer fits as a non-negative int, compute an int +** remainder, which is faster. Otherwise, use an unsigned-integer +** remainder, which uses all bits and ensures a non-negative result. +*/ +static Node *hashint (const Table *t, lua_Integer i) { + lua_Unsigned ui = l_castS2U(i); + if (ui <= cast_uint(INT_MAX)) + return hashmod(t, cast_int(ui)); + else + return hashmod(t, ui); +} + + +/* +** Hash for floating-point numbers. +** The main computation should be just +** n = frexp(n, &i); return (n * INT_MAX) + i +** but there are some numerical subtleties. +** In a two-complement representation, INT_MAX does not has an exact +** representation as a float, but INT_MIN does; because the absolute +** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the +** absolute value of the product 'frexp * -INT_MIN' is smaller or equal +** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when +** adding 'i'; the use of '~u' (instead of '-u') avoids problems with +** INT_MIN. +*/ +#if !defined(l_hashfloat) +static int l_hashfloat (lua_Number n) { + int i; + lua_Integer ni; + n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN); + if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */ + lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL)); + return 0; + } + else { /* normal case */ + unsigned int u = cast_uint(i) + cast_uint(ni); + return cast_int(u <= cast_uint(INT_MAX) ? u : ~u); + } +} +#endif + + +/* +** returns the 'main' position of an element in a table (that is, +** the index of its hash value). +*/ +static Node *mainpositionTV (const Table *t, const TValue *key) { + switch (ttypetag(key)) { + case LUA_VNUMINT: { + lua_Integer i = ivalue(key); + return hashint(t, i); + } + case LUA_VNUMFLT: { + lua_Number n = fltvalue(key); + return hashmod(t, l_hashfloat(n)); + } + case LUA_VSHRSTR: { + TString *ts = tsvalue(key); + return hashstr(t, ts); + } + case LUA_VLNGSTR: { + TString *ts = tsvalue(key); + return hashpow2(t, luaS_hashlongstr(ts)); + } + case LUA_VFALSE: + return hashboolean(t, 0); + case LUA_VTRUE: + return hashboolean(t, 1); + case LUA_VLIGHTUSERDATA: { + void *p = pvalue(key); + return hashpointer(t, p); + } + case LUA_VLCF: { + lua_CFunction f = fvalue(key); + return hashpointer(t, f); + } + default: { + GCObject *o = gcvalue(key); + return hashpointer(t, o); + } + } +} + + +l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) { + TValue key; + getnodekey(cast(lua_State *, NULL), &key, nd); + return mainpositionTV(t, &key); +} + + +/* +** Check whether key 'k1' is equal to the key in node 'n2'. This +** equality is raw, so there are no metamethods. Floats with integer +** values have been normalized, so integers cannot be equal to +** floats. It is assumed that 'eqshrstr' is simply pointer equality, so +** that short strings are handled in the default case. +** A true 'deadok' means to accept dead keys as equal to their original +** values. All dead keys are compared in the default case, by pointer +** identity. (Only collectable objects can produce dead keys.) Note that +** dead long strings are also compared by identity. +** Once a key is dead, its corresponding value may be collected, and +** then another value can be created with the same address. If this +** other value is given to 'next', 'equalkey' will signal a false +** positive. In a regular traversal, this situation should never happen, +** as all keys given to 'next' came from the table itself, and therefore +** could not have been collected. Outside a regular traversal, we +** have garbage in, garbage out. What is relevant is that this false +** positive does not break anything. (In particular, 'next' will return +** some other valid item on the table or nil.) +*/ +static int equalkey (const TValue *k1, const Node *n2, int deadok) { + if ((rawtt(k1) != keytt(n2)) && /* not the same variants? */ + !(deadok && keyisdead(n2) && iscollectable(k1))) + return 0; /* cannot be same key */ + switch (keytt(n2)) { + case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: + return 1; + case LUA_VNUMINT: + return (ivalue(k1) == keyival(n2)); + case LUA_VNUMFLT: + return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2))); + case LUA_VLIGHTUSERDATA: + return pvalue(k1) == pvalueraw(keyval(n2)); + case LUA_VLCF: + return fvalue(k1) == fvalueraw(keyval(n2)); + case ctb(LUA_VLNGSTR): + return luaS_eqlngstr(tsvalue(k1), keystrval(n2)); + default: + return gcvalue(k1) == gcvalueraw(keyval(n2)); + } +} + + +/* +** True if value of 'alimit' is equal to the real size of the array +** part of table 't'. (Otherwise, the array part must be larger than +** 'alimit'.) +*/ +#define limitequalsasize(t) (isrealasize(t) || ispow2((t)->alimit)) + + +/* +** Returns the real size of the 'array' array +*/ +LUAI_FUNC unsigned int luaH_realasize (const Table *t) { + if (limitequalsasize(t)) + return t->alimit; /* this is the size */ + else { + unsigned int size = t->alimit; + /* compute the smallest power of 2 not smaller than 'n' */ + size |= (size >> 1); + size |= (size >> 2); + size |= (size >> 4); + size |= (size >> 8); +#if (UINT_MAX >> 14) > 3 /* unsigned int has more than 16 bits */ + size |= (size >> 16); +#if (UINT_MAX >> 30) > 3 + size |= (size >> 32); /* unsigned int has more than 32 bits */ +#endif +#endif + size++; + lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size); + return size; + } +} + + +/* +** Check whether real size of the array is a power of 2. +** (If it is not, 'alimit' cannot be changed to any other value +** without changing the real size.) +*/ +static int ispow2realasize (const Table *t) { + return (!isrealasize(t) || ispow2(t->alimit)); +} + + +static unsigned int setlimittosize (Table *t) { + t->alimit = luaH_realasize(t); + setrealasize(t); + return t->alimit; +} + + +#define limitasasize(t) check_exp(isrealasize(t), t->alimit) + + + +/* +** "Generic" get version. (Not that generic: not valid for integers, +** which may be in array part, nor for floats with integral values.) +** See explanation about 'deadok' in function 'equalkey'. +*/ +static const TValue *getgeneric (Table *t, const TValue *key, int deadok) { + Node *n = mainpositionTV(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (equalkey(key, n, deadok)) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) + return &absentkey; /* not found */ + n += nx; + } + } +} + + +/* +** returns the index for 'k' if 'k' is an appropriate key to live in +** the array part of a table, 0 otherwise. +*/ +static unsigned int arrayindex (lua_Integer k) { + if (l_castS2U(k) - 1u < MAXASIZE) /* 'k' in [1, MAXASIZE]? */ + return cast_uint(k); /* 'key' is an appropriate array index */ + else + return 0; +} + + +/* +** returns the index of a 'key' for table traversals. First goes all +** elements in the array part, then elements in the hash part. The +** beginning of a traversal is signaled by 0. +*/ +static unsigned int findindex (lua_State *L, Table *t, TValue *key, + unsigned int asize) { + unsigned int i; + if (ttisnil(key)) return 0; /* first iteration */ + i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0; + if (i - 1u < asize) /* is 'key' inside array part? */ + return i; /* yes; that's the index */ + else { + const TValue *n = getgeneric(t, key, 1); + if (l_unlikely(isabstkey(n))) + luaG_runerror(L, "invalid key to 'next'"); /* key not found */ + i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */ + /* hash elements are numbered after array ones */ + return (i + 1) + asize; + } +} + + +int luaH_next (lua_State *L, Table *t, StkId key) { + unsigned int asize = luaH_realasize(t); + unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */ + for (; i < asize; i++) { /* try first array part */ + if (!isempty(&t->array[i])) { /* a non-empty entry? */ + setivalue(s2v(key), i + 1); + setobj2s(L, key + 1, &t->array[i]); + return 1; + } + } + for (i -= asize; cast_int(i) < sizenode(t); i++) { /* hash part */ + if (!isempty(gval(gnode(t, i)))) { /* a non-empty entry? */ + Node *n = gnode(t, i); + getnodekey(L, s2v(key), n); + setobj2s(L, key + 1, gval(n)); + return 1; + } + } + return 0; /* no more elements */ +} + + +static void freehash (lua_State *L, Table *t) { + if (!isdummy(t)) + luaM_freearray(L, t->node, cast_sizet(sizenode(t))); +} + + +/* +** {============================================================= +** Rehash +** ============================================================== +*/ + +/* +** Compute the optimal size for the array part of table 't'. 'nums' is a +** "count array" where 'nums[i]' is the number of integers in the table +** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of +** integer keys in the table and leaves with the number of keys that +** will go to the array part; return the optimal size. (The condition +** 'twotoi > 0' in the for loop stops the loop if 'twotoi' overflows.) +*/ +static unsigned int computesizes (unsigned int nums[], unsigned int *pna) { + int i; + unsigned int twotoi; /* 2^i (candidate for optimal size) */ + unsigned int a = 0; /* number of elements smaller than 2^i */ + unsigned int na = 0; /* number of elements to go to array part */ + unsigned int optimal = 0; /* optimal size for array part */ + /* loop while keys can fill more than half of total size */ + for (i = 0, twotoi = 1; + twotoi > 0 && *pna > twotoi / 2; + i++, twotoi *= 2) { + a += nums[i]; + if (a > twotoi/2) { /* more than half elements present? */ + optimal = twotoi; /* optimal size (till now) */ + na = a; /* all elements up to 'optimal' will go to array part */ + } + } + lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal); + *pna = na; + return optimal; +} + + +static int countint (lua_Integer key, unsigned int *nums) { + unsigned int k = arrayindex(key); + if (k != 0) { /* is 'key' an appropriate array index? */ + nums[luaO_ceillog2(k)]++; /* count as such */ + return 1; + } + else + return 0; +} + + +/* +** Count keys in array part of table 't': Fill 'nums[i]' with +** number of keys that will go into corresponding slice and return +** total number of non-nil keys. +*/ +static unsigned int numusearray (const Table *t, unsigned int *nums) { + int lg; + unsigned int ttlg; /* 2^lg */ + unsigned int ause = 0; /* summation of 'nums' */ + unsigned int i = 1; /* count to traverse all array keys */ + unsigned int asize = limitasasize(t); /* real array size */ + /* traverse each slice */ + for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) { + unsigned int lc = 0; /* counter */ + unsigned int lim = ttlg; + if (lim > asize) { + lim = asize; /* adjust upper limit */ + if (i > lim) + break; /* no more elements to count */ + } + /* count elements in range (2^(lg - 1), 2^lg] */ + for (; i <= lim; i++) { + if (!isempty(&t->array[i-1])) + lc++; + } + nums[lg] += lc; + ause += lc; + } + return ause; +} + + +static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { + int totaluse = 0; /* total number of elements */ + int ause = 0; /* elements added to 'nums' (can go to array part) */ + int i = sizenode(t); + while (i--) { + Node *n = &t->node[i]; + if (!isempty(gval(n))) { + if (keyisinteger(n)) + ause += countint(keyival(n), nums); + totaluse++; + } + } + *pna += ause; + return totaluse; +} + + +/* +** Creates an array for the hash part of a table with the given +** size, or reuses the dummy node if size is zero. +** The computation for size overflow is in two steps: the first +** comparison ensures that the shift in the second one does not +** overflow. +*/ +static void setnodevector (lua_State *L, Table *t, unsigned int size) { + if (size == 0) { /* no elements to hash part? */ + t->node = cast(Node *, dummynode); /* use common 'dummynode' */ + t->lsizenode = 0; + t->lastfree = NULL; /* signal that it is using dummy node */ + } + else { + int i; + int lsize = luaO_ceillog2(size); + if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) + luaG_runerror(L, "table overflow"); + size = twoto(lsize); + t->node = luaM_newvector(L, size, Node); + for (i = 0; i < cast_int(size); i++) { + Node *n = gnode(t, i); + gnext(n) = 0; + setnilkey(n); + setempty(gval(n)); + } + t->lsizenode = cast_byte(lsize); + t->lastfree = gnode(t, size); /* all positions are free */ + } +} + + +/* +** (Re)insert all elements from the hash part of 'ot' into table 't'. +*/ +static void reinsert (lua_State *L, Table *ot, Table *t) { + int j; + int size = sizenode(ot); + for (j = 0; j < size; j++) { + Node *old = gnode(ot, j); + if (!isempty(gval(old))) { + /* doesn't need barrier/invalidate cache, as entry was + already present in the table */ + TValue k; + getnodekey(L, &k, old); + luaH_set(L, t, &k, gval(old)); + } + } +} + + +/* +** Exchange the hash part of 't1' and 't2'. +*/ +static void exchangehashpart (Table *t1, Table *t2) { + lu_byte lsizenode = t1->lsizenode; + Node *node = t1->node; + Node *lastfree = t1->lastfree; + t1->lsizenode = t2->lsizenode; + t1->node = t2->node; + t1->lastfree = t2->lastfree; + t2->lsizenode = lsizenode; + t2->node = node; + t2->lastfree = lastfree; +} + + +/* +** Resize table 't' for the new given sizes. Both allocations (for +** the hash part and for the array part) can fail, which creates some +** subtleties. If the first allocation, for the hash part, fails, an +** error is raised and that is it. Otherwise, it copies the elements from +** the shrinking part of the array (if it is shrinking) into the new +** hash. Then it reallocates the array part. If that fails, the table +** is in its original state; the function frees the new hash part and then +** raises the allocation error. Otherwise, it sets the new hash part +** into the table, initializes the new part of the array (if any) with +** nils and reinserts the elements of the old hash back into the new +** parts of the table. +*/ +void luaH_resize (lua_State *L, Table *t, unsigned int newasize, + unsigned int nhsize) { + unsigned int i; + Table newt; /* to keep the new hash part */ + unsigned int oldasize = setlimittosize(t); + TValue *newarray; + /* create new hash part with appropriate size into 'newt' */ + setnodevector(L, &newt, nhsize); + if (newasize < oldasize) { /* will array shrink? */ + t->alimit = newasize; /* pretend array has new size... */ + exchangehashpart(t, &newt); /* and new hash */ + /* re-insert into the new hash the elements from vanishing slice */ + for (i = newasize; i < oldasize; i++) { + if (!isempty(&t->array[i])) + luaH_setint(L, t, i + 1, &t->array[i]); + } + t->alimit = oldasize; /* restore current size... */ + exchangehashpart(t, &newt); /* and hash (in case of errors) */ + } + /* allocate new array */ + newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue); + if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ + freehash(L, &newt); /* release new hash part */ + luaM_error(L); /* raise error (with array unchanged) */ + } + /* allocation ok; initialize new part of the array */ + exchangehashpart(t, &newt); /* 't' has the new hash ('newt' has the old) */ + t->array = newarray; /* set new array part */ + t->alimit = newasize; + for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ + setempty(&t->array[i]); + /* re-insert elements from old hash part into new parts */ + reinsert(L, &newt, t); /* 'newt' now has the old hash */ + freehash(L, &newt); /* free old hash part */ +} + + +void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) { + int nsize = allocsizenode(t); + luaH_resize(L, t, nasize, nsize); +} + +/* +** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i +*/ +static void rehash (lua_State *L, Table *t, const TValue *ek) { + unsigned int asize; /* optimal size for array part */ + unsigned int na; /* number of keys in the array part */ + unsigned int nums[MAXABITS + 1]; + int i; + int totaluse; + for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */ + setlimittosize(t); + na = numusearray(t, nums); /* count keys in array part */ + totaluse = na; /* all those keys are integer keys */ + totaluse += numusehash(t, nums, &na); /* count keys in hash part */ + /* count extra key */ + if (ttisinteger(ek)) + na += countint(ivalue(ek), nums); + totaluse++; + /* compute new size for array part */ + asize = computesizes(nums, &na); + /* resize the table to new computed sizes */ + luaH_resize(L, t, asize, totaluse - na); +} + + + +/* +** }============================================================= +*/ + + +Table *luaH_new (lua_State *L) { + GCObject *o = luaC_newobj(L, LUA_VTABLE, sizeof(Table)); + Table *t = gco2t(o); + t->metatable = NULL; + t->flags = cast_byte(maskflags); /* table has no metamethod fields */ + t->array = NULL; + t->alimit = 0; + setnodevector(L, t, 0); + return t; +} + + +void luaH_free (lua_State *L, Table *t) { + freehash(L, t); + luaM_freearray(L, t->array, luaH_realasize(t)); + luaM_free(L, t); +} + + +static Node *getfreepos (Table *t) { + if (!isdummy(t)) { + while (t->lastfree > t->node) { + t->lastfree--; + if (keyisnil(t->lastfree)) + return t->lastfree; + } + } + return NULL; /* could not find a free place */ +} + + + +/* +** inserts a new key into a hash table; first, check whether key's main +** position is free. If not, check whether colliding node is in its main +** position or not: if it is not, move colliding node to an empty place and +** put new key in its main position; otherwise (colliding node is in its main +** position), new key goes to an empty position. +*/ +void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { + Node *mp; + TValue aux; + if (l_unlikely(ttisnil(key))) + luaG_runerror(L, "table index is nil"); + else if (ttisfloat(key)) { + lua_Number f = fltvalue(key); + lua_Integer k; + if (luaV_flttointeger(f, &k, F2Ieq)) { /* does key fit in an integer? */ + setivalue(&aux, k); + key = &aux; /* insert it as an integer */ + } + else if (l_unlikely(luai_numisnan(f))) + luaG_runerror(L, "table index is NaN"); + } + if (ttisnil(value)) + return; /* do not insert nil values */ + mp = mainpositionTV(t, key); + if (!isempty(gval(mp)) || isdummy(t)) { /* main position is taken? */ + Node *othern; + Node *f = getfreepos(t); /* get a free place */ + if (f == NULL) { /* cannot find a free place? */ + rehash(L, t, key); /* grow table */ + /* whatever called 'newkey' takes care of TM cache */ + luaH_set(L, t, key, value); /* insert key into grown table */ + return; + } + lua_assert(!isdummy(t)); + othern = mainpositionfromnode(t, mp); + if (othern != mp) { /* is colliding node out of its main position? */ + /* yes; move colliding node into free position */ + while (othern + gnext(othern) != mp) /* find previous */ + othern += gnext(othern); + gnext(othern) = cast_int(f - othern); /* rechain to point to 'f' */ + *f = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + if (gnext(mp) != 0) { + gnext(f) += cast_int(mp - f); /* correct 'next' */ + gnext(mp) = 0; /* now 'mp' is free */ + } + setempty(gval(mp)); + } + else { /* colliding node is in its own main position */ + /* new node will go into free position */ + if (gnext(mp) != 0) + gnext(f) = cast_int((mp + gnext(mp)) - f); /* chain new position */ + else lua_assert(gnext(f) == 0); + gnext(mp) = cast_int(f - mp); + mp = f; + } + } + setnodekey(L, mp, key); + luaC_barrierback(L, obj2gco(t), key); + lua_assert(isempty(gval(mp))); + setobj2t(L, gval(mp), value); +} + + +/* +** Search function for integers. If integer is inside 'alimit', get it +** directly from the array part. Otherwise, if 'alimit' is not equal to +** the real size of the array, key still can be in the array part. In +** this case, try to avoid a call to 'luaH_realasize' when key is just +** one more than the limit (so that it can be incremented without +** changing the real size of the array). +*/ +const TValue *luaH_getint (Table *t, lua_Integer key) { + if (l_castS2U(key) - 1u < t->alimit) /* 'key' in [1, t->alimit]? */ + return &t->array[key - 1]; + else if (!limitequalsasize(t) && /* key still may be in the array part? */ + (l_castS2U(key) == t->alimit + 1 || + l_castS2U(key) - 1u < luaH_realasize(t))) { + t->alimit = cast_uint(key); /* probably '#t' is here now */ + return &t->array[key - 1]; + } + else { + Node *n = hashint(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (keyisinteger(n) && keyival(n) == key) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) break; + n += nx; + } + } + return &absentkey; + } +} + + +/* +** search function for short strings +*/ +const TValue *luaH_getshortstr (Table *t, TString *key) { + Node *n = hashstr(t, key); + lua_assert(key->tt == LUA_VSHRSTR); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (keyisshrstr(n) && eqshrstr(keystrval(n), key)) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) + return &absentkey; /* not found */ + n += nx; + } + } +} + + +const TValue *luaH_getstr (Table *t, TString *key) { + if (key->tt == LUA_VSHRSTR) + return luaH_getshortstr(t, key); + else { /* for long strings, use generic case */ + TValue ko; + setsvalue(cast(lua_State *, NULL), &ko, key); + return getgeneric(t, &ko, 0); + } +} + + +/* +** main search function +*/ +const TValue *luaH_get (Table *t, const TValue *key) { + switch (ttypetag(key)) { + case LUA_VSHRSTR: return luaH_getshortstr(t, tsvalue(key)); + case LUA_VNUMINT: return luaH_getint(t, ivalue(key)); + case LUA_VNIL: return &absentkey; + case LUA_VNUMFLT: { + lua_Integer k; + if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* integral index? */ + return luaH_getint(t, k); /* use specialized version */ + /* else... */ + } /* FALLTHROUGH */ + default: + return getgeneric(t, key, 0); + } +} + + +/* +** Finish a raw "set table" operation, where 'slot' is where the value +** should have been (the result of a previous "get table"). +** Beware: when using this function you probably need to check a GC +** barrier and invalidate the TM cache. +*/ +void luaH_finishset (lua_State *L, Table *t, const TValue *key, + const TValue *slot, TValue *value) { + if (isabstkey(slot)) + luaH_newkey(L, t, key, value); + else + setobj2t(L, cast(TValue *, slot), value); +} + + +/* +** beware: when using this function you probably need to check a GC +** barrier and invalidate the TM cache. +*/ +void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) { + const TValue *slot = luaH_get(t, key); + luaH_finishset(L, t, key, slot, value); +} + + +void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { + const TValue *p = luaH_getint(t, key); + if (isabstkey(p)) { + TValue k; + setivalue(&k, key); + luaH_newkey(L, t, &k, value); + } + else + setobj2t(L, cast(TValue *, p), value); +} + + +/* +** Try to find a boundary in the hash part of table 't'. From the +** caller, we know that 'j' is zero or present and that 'j + 1' is +** present. We want to find a larger key that is absent from the +** table, so that we can do a binary search between the two keys to +** find a boundary. We keep doubling 'j' until we get an absent index. +** If the doubling would overflow, we try LUA_MAXINTEGER. If it is +** absent, we are ready for the binary search. ('j', being max integer, +** is larger or equal to 'i', but it cannot be equal because it is +** absent while 'i' is present; so 'j > i'.) Otherwise, 'j' is a +** boundary. ('j + 1' cannot be a present integer key because it is +** not a valid integer in Lua.) +*/ +static lua_Unsigned hash_search (Table *t, lua_Unsigned j) { + lua_Unsigned i; + if (j == 0) j++; /* the caller ensures 'j + 1' is present */ + do { + i = j; /* 'i' is a present index */ + if (j <= l_castS2U(LUA_MAXINTEGER) / 2) + j *= 2; + else { + j = LUA_MAXINTEGER; + if (isempty(luaH_getint(t, j))) /* t[j] not present? */ + break; /* 'j' now is an absent index */ + else /* weird case */ + return j; /* well, max integer is a boundary... */ + } + } while (!isempty(luaH_getint(t, j))); /* repeat until an absent t[j] */ + /* i < j && t[i] present && t[j] absent */ + while (j - i > 1u) { /* do a binary search between them */ + lua_Unsigned m = (i + j) / 2; + if (isempty(luaH_getint(t, m))) j = m; + else i = m; + } + return i; +} + + +static unsigned int binsearch (const TValue *array, unsigned int i, + unsigned int j) { + while (j - i > 1u) { /* binary search */ + unsigned int m = (i + j) / 2; + if (isempty(&array[m - 1])) j = m; + else i = m; + } + return i; +} + + +/* +** Try to find a boundary in table 't'. (A 'boundary' is an integer index +** such that t[i] is present and t[i+1] is absent, or 0 if t[1] is absent +** and 'maxinteger' if t[maxinteger] is present.) +** (In the next explanation, we use Lua indices, that is, with base 1. +** The code itself uses base 0 when indexing the array part of the table.) +** The code starts with 'limit = t->alimit', a position in the array +** part that may be a boundary. +** +** (1) If 't[limit]' is empty, there must be a boundary before it. +** As a common case (e.g., after 't[#t]=nil'), check whether 'limit-1' +** is present. If so, it is a boundary. Otherwise, do a binary search +** between 0 and limit to find a boundary. In both cases, try to +** use this boundary as the new 'alimit', as a hint for the next call. +** +** (2) If 't[limit]' is not empty and the array has more elements +** after 'limit', try to find a boundary there. Again, try first +** the special case (which should be quite frequent) where 'limit+1' +** is empty, so that 'limit' is a boundary. Otherwise, check the +** last element of the array part. If it is empty, there must be a +** boundary between the old limit (present) and the last element +** (absent), which is found with a binary search. (This boundary always +** can be a new limit.) +** +** (3) The last case is when there are no elements in the array part +** (limit == 0) or its last element (the new limit) is present. +** In this case, must check the hash part. If there is no hash part +** or 'limit+1' is absent, 'limit' is a boundary. Otherwise, call +** 'hash_search' to find a boundary in the hash part of the table. +** (In those cases, the boundary is not inside the array part, and +** therefore cannot be used as a new limit.) +*/ +lua_Unsigned luaH_getn (Table *t) { + unsigned int limit = t->alimit; + if (limit > 0 && isempty(&t->array[limit - 1])) { /* (1)? */ + /* there must be a boundary before 'limit' */ + if (limit >= 2 && !isempty(&t->array[limit - 2])) { + /* 'limit - 1' is a boundary; can it be a new limit? */ + if (ispow2realasize(t) && !ispow2(limit - 1)) { + t->alimit = limit - 1; + setnorealasize(t); /* now 'alimit' is not the real size */ + } + return limit - 1; + } + else { /* must search for a boundary in [0, limit] */ + unsigned int boundary = binsearch(t->array, 0, limit); + /* can this boundary represent the real size of the array? */ + if (ispow2realasize(t) && boundary > luaH_realasize(t) / 2) { + t->alimit = boundary; /* use it as the new limit */ + setnorealasize(t); + } + return boundary; + } + } + /* 'limit' is zero or present in table */ + if (!limitequalsasize(t)) { /* (2)? */ + /* 'limit' > 0 and array has more elements after 'limit' */ + if (isempty(&t->array[limit])) /* 'limit + 1' is empty? */ + return limit; /* this is the boundary */ + /* else, try last element in the array */ + limit = luaH_realasize(t); + if (isempty(&t->array[limit - 1])) { /* empty? */ + /* there must be a boundary in the array after old limit, + and it must be a valid new limit */ + unsigned int boundary = binsearch(t->array, t->alimit, limit); + t->alimit = boundary; + return boundary; + } + /* else, new limit is present in the table; check the hash part */ + } + /* (3) 'limit' is the last element and either is zero or present in table */ + lua_assert(limit == luaH_realasize(t) && + (limit == 0 || !isempty(&t->array[limit - 1]))); + if (isdummy(t) || isempty(luaH_getint(t, cast(lua_Integer, limit + 1)))) + return limit; /* 'limit + 1' is absent */ + else /* 'limit + 1' is also present */ + return hash_search(t, limit); +} + + + +#if defined(LUA_DEBUG) + +/* export these functions for the test library */ + +Node *luaH_mainposition (const Table *t, const TValue *key) { + return mainpositionTV(t, key); +} + +#endif diff --git a/vendor/lua-src/lua-5.4.6/ltable.h b/vendor/lua-src/lua-5.4.6/ltable.h new file mode 100644 index 0000000000000..75dd9e26e015b --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/ltable.h @@ -0,0 +1,65 @@ +/* +** $Id: ltable.h $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +#ifndef ltable_h +#define ltable_h + +#include "lobject.h" + + +#define gnode(t,i) (&(t)->node[i]) +#define gval(n) (&(n)->i_val) +#define gnext(n) ((n)->u.next) + + +/* +** Clear all bits of fast-access metamethods, which means that the table +** may have any of these metamethods. (First access that fails after the +** clearing will set the bit again.) +*/ +#define invalidateTMcache(t) ((t)->flags &= ~maskflags) + + +/* true when 't' is using 'dummynode' as its hash part */ +#define isdummy(t) ((t)->lastfree == NULL) + + +/* allocated size for hash nodes */ +#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t)) + + +/* returns the Node, given the value of a table entry */ +#define nodefromval(v) cast(Node *, (v)) + + +LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); +LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, + TValue *value); +LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); +LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); +LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); +LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key, + TValue *value); +LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key, + TValue *value); +LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key, + const TValue *slot, TValue *value); +LUAI_FUNC Table *luaH_new (lua_State *L); +LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, + unsigned int nhsize); +LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); +LUAI_FUNC void luaH_free (lua_State *L, Table *t); +LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); +LUAI_FUNC lua_Unsigned luaH_getn (Table *t); +LUAI_FUNC unsigned int luaH_realasize (const Table *t); + + +#if defined(LUA_DEBUG) +LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); +#endif + + +#endif diff --git a/vendor/lua-src/lua-5.4.6/ltablib.c b/vendor/lua-src/lua-5.4.6/ltablib.c new file mode 100644 index 0000000000000..e6bc4d04af47e --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/ltablib.c @@ -0,0 +1,430 @@ +/* +** $Id: ltablib.c $ +** Library for Table Manipulation +** See Copyright Notice in lua.h +*/ + +#define ltablib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** Operations that an object must define to mimic a table +** (some functions only need some of them) +*/ +#define TAB_R 1 /* read */ +#define TAB_W 2 /* write */ +#define TAB_L 4 /* length */ +#define TAB_RW (TAB_R | TAB_W) /* read/write */ + + +#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) + + +static int checkfield (lua_State *L, const char *key, int n) { + lua_pushstring(L, key); + return (lua_rawget(L, -n) != LUA_TNIL); +} + + +/* +** Check that 'arg' either is a table or can behave like one (that is, +** has a metatable with the required metamethods) +*/ +static void checktab (lua_State *L, int arg, int what) { + if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ + int n = 1; /* number of elements to pop */ + if (lua_getmetatable(L, arg) && /* must have metatable */ + (!(what & TAB_R) || checkfield(L, "__index", ++n)) && + (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && + (!(what & TAB_L) || checkfield(L, "__len", ++n))) { + lua_pop(L, n); /* pop metatable and tested metamethods */ + } + else + luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ + } +} + + +static int tinsert (lua_State *L) { + lua_Integer pos; /* where to insert new element */ + lua_Integer e = aux_getn(L, 1, TAB_RW); + e = luaL_intop(+, e, 1); /* first empty element */ + switch (lua_gettop(L)) { + case 2: { /* called with only 2 arguments */ + pos = e; /* insert new element at the end */ + break; + } + case 3: { + lua_Integer i; + pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ + /* check whether 'pos' is in [1, e] */ + luaL_argcheck(L, (lua_Unsigned)pos - 1u < (lua_Unsigned)e, 2, + "position out of bounds"); + for (i = e; i > pos; i--) { /* move up elements */ + lua_geti(L, 1, i - 1); + lua_seti(L, 1, i); /* t[i] = t[i - 1] */ + } + break; + } + default: { + return luaL_error(L, "wrong number of arguments to 'insert'"); + } + } + lua_seti(L, 1, pos); /* t[pos] = v */ + return 0; +} + + +static int tremove (lua_State *L) { + lua_Integer size = aux_getn(L, 1, TAB_RW); + lua_Integer pos = luaL_optinteger(L, 2, size); + if (pos != size) /* validate 'pos' if given */ + /* check whether 'pos' is in [1, size + 1] */ + luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2, + "position out of bounds"); + lua_geti(L, 1, pos); /* result = t[pos] */ + for ( ; pos < size; pos++) { + lua_geti(L, 1, pos + 1); + lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ + } + lua_pushnil(L); + lua_seti(L, 1, pos); /* remove entry t[pos] */ + return 1; +} + + +/* +** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever +** possible, copy in increasing order, which is better for rehashing. +** "possible" means destination after original range, or smaller +** than origin, or copying to another table. +*/ +static int tmove (lua_State *L) { + lua_Integer f = luaL_checkinteger(L, 2); + lua_Integer e = luaL_checkinteger(L, 3); + lua_Integer t = luaL_checkinteger(L, 4); + int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ + checktab(L, 1, TAB_R); + checktab(L, tt, TAB_W); + if (e >= f) { /* otherwise, nothing to move */ + lua_Integer n, i; + luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, + "too many elements to move"); + n = e - f + 1; /* number of elements to move */ + luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, + "destination wrap around"); + if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { + for (i = 0; i < n; i++) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + else { + for (i = n - 1; i >= 0; i--) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + } + lua_pushvalue(L, tt); /* return destination table */ + return 1; +} + + +static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { + lua_geti(L, 1, i); + if (l_unlikely(!lua_isstring(L, -1))) + luaL_error(L, "invalid value (%s) at index %I in table for 'concat'", + luaL_typename(L, -1), (LUAI_UACINT)i); + luaL_addvalue(b); +} + + +static int tconcat (lua_State *L) { + luaL_Buffer b; + lua_Integer last = aux_getn(L, 1, TAB_R); + size_t lsep; + const char *sep = luaL_optlstring(L, 2, "", &lsep); + lua_Integer i = luaL_optinteger(L, 3, 1); + last = luaL_optinteger(L, 4, last); + luaL_buffinit(L, &b); + for (; i < last; i++) { + addfield(L, &b, i); + luaL_addlstring(&b, sep, lsep); + } + if (i == last) /* add last value (if interval was not empty) */ + addfield(L, &b, i); + luaL_pushresult(&b); + return 1; +} + + +/* +** {====================================================== +** Pack/unpack +** ======================================================= +*/ + +static int tpack (lua_State *L) { + int i; + int n = lua_gettop(L); /* number of elements to pack */ + lua_createtable(L, n, 1); /* create result table */ + lua_insert(L, 1); /* put it at index 1 */ + for (i = n; i >= 1; i--) /* assign elements */ + lua_seti(L, 1, i); + lua_pushinteger(L, n); + lua_setfield(L, 1, "n"); /* t.n = number of elements */ + return 1; /* return table */ +} + + +static int tunpack (lua_State *L) { + lua_Unsigned n; + lua_Integer i = luaL_optinteger(L, 2, 1); + lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); + if (i > e) return 0; /* empty range */ + n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ + if (l_unlikely(n >= (unsigned int)INT_MAX || + !lua_checkstack(L, (int)(++n)))) + return luaL_error(L, "too many results to unpack"); + for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ + lua_geti(L, 1, i); + } + lua_geti(L, 1, e); /* push last element */ + return (int)n; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Quicksort +** (based on 'Algorithms in MODULA-3', Robert Sedgewick; +** Addison-Wesley, 1993.) +** ======================================================= +*/ + + +/* type for array indices */ +typedef unsigned int IdxT; + + +/* +** Produce a "random" 'unsigned int' to randomize pivot choice. This +** macro is used only when 'sort' detects a big imbalance in the result +** of a partition. (If you don't want/need this "randomness", ~0 is a +** good choice.) +*/ +#if !defined(l_randomizePivot) /* { */ + +#include + +/* size of 'e' measured in number of 'unsigned int's */ +#define sof(e) (sizeof(e) / sizeof(unsigned int)) + +/* +** Use 'time' and 'clock' as sources of "randomness". Because we don't +** know the types 'clock_t' and 'time_t', we cannot cast them to +** anything without risking overflows. A safe way to use their values +** is to copy them to an array of a known type and use the array values. +*/ +static unsigned int l_randomizePivot (void) { + clock_t c = clock(); + time_t t = time(NULL); + unsigned int buff[sof(c) + sof(t)]; + unsigned int i, rnd = 0; + memcpy(buff, &c, sof(c) * sizeof(unsigned int)); + memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); + for (i = 0; i < sof(buff); i++) + rnd += buff[i]; + return rnd; +} + +#endif /* } */ + + +/* arrays larger than 'RANLIMIT' may use randomized pivots */ +#define RANLIMIT 100u + + +static void set2 (lua_State *L, IdxT i, IdxT j) { + lua_seti(L, 1, i); + lua_seti(L, 1, j); +} + + +/* +** Return true iff value at stack index 'a' is less than the value at +** index 'b' (according to the order of the sort). +*/ +static int sort_comp (lua_State *L, int a, int b) { + if (lua_isnil(L, 2)) /* no function? */ + return lua_compare(L, a, b, LUA_OPLT); /* a < b */ + else { /* function */ + int res; + lua_pushvalue(L, 2); /* push function */ + lua_pushvalue(L, a-1); /* -1 to compensate function */ + lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ + lua_call(L, 2, 1); /* call function */ + res = lua_toboolean(L, -1); /* get result */ + lua_pop(L, 1); /* pop result */ + return res; + } +} + + +/* +** Does the partition: Pivot P is at the top of the stack. +** precondition: a[lo] <= P == a[up-1] <= a[up], +** so it only needs to do the partition from lo + 1 to up - 2. +** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] +** returns 'i'. +*/ +static IdxT partition (lua_State *L, IdxT lo, IdxT up) { + IdxT i = lo; /* will be incremented before first use */ + IdxT j = up - 1; /* will be decremented before first use */ + /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ + for (;;) { + /* next loop: repeat ++i while a[i] < P */ + while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (l_unlikely(i == up - 1)) /* a[i] < P but a[up - 1] == P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ + /* next loop: repeat --j while P < a[j] */ + while ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { + if (l_unlikely(j < i)) /* j < i but a[j] > P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[j] */ + } + /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ + if (j < i) { /* no elements out of place? */ + /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ + lua_pop(L, 1); /* pop a[j] */ + /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ + set2(L, up - 1, i); + return i; + } + /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ + set2(L, i, j); + } +} + + +/* +** Choose an element in the middle (2nd-3th quarters) of [lo,up] +** "randomized" by 'rnd' +*/ +static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { + IdxT r4 = (up - lo) / 4; /* range/4 */ + IdxT p = rnd % (r4 * 2) + (lo + r4); + lua_assert(lo + r4 <= p && p <= up - r4); + return p; +} + + +/* +** Quicksort algorithm (recursive function) +*/ +static void auxsort (lua_State *L, IdxT lo, IdxT up, + unsigned int rnd) { + while (lo < up) { /* loop for tail recursion */ + IdxT p; /* Pivot index */ + IdxT n; /* to be used later */ + /* sort elements 'lo', 'p', and 'up' */ + lua_geti(L, 1, lo); + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ + set2(L, lo, up); /* swap a[lo] - a[up] */ + else + lua_pop(L, 2); /* remove both values */ + if (up - lo == 1) /* only 2 elements? */ + return; /* already sorted */ + if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ + p = (lo + up)/2; /* middle element is a good pivot */ + else /* for larger intervals, it is worth a random pivot */ + p = choosePivot(lo, up, rnd); + lua_geti(L, 1, p); + lua_geti(L, 1, lo); + if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ + set2(L, p, lo); /* swap a[p] - a[lo] */ + else { + lua_pop(L, 1); /* remove a[lo] */ + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ + set2(L, p, up); /* swap a[up] - a[p] */ + else + lua_pop(L, 2); + } + if (up - lo == 2) /* only 3 elements? */ + return; /* already sorted */ + lua_geti(L, 1, p); /* get middle element (Pivot) */ + lua_pushvalue(L, -1); /* push Pivot */ + lua_geti(L, 1, up - 1); /* push a[up - 1] */ + set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ + p = partition(L, lo, up); + /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ + if (p - lo < up - p) { /* lower interval is smaller? */ + auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ + n = p - lo; /* size of smaller interval */ + lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ + } + else { + auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ + n = up - p; /* size of smaller interval */ + up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ + } + if ((up - lo) / 128 > n) /* partition too imbalanced? */ + rnd = l_randomizePivot(); /* try a new randomization */ + } /* tail call auxsort(L, lo, up, rnd) */ +} + + +static int sort (lua_State *L) { + lua_Integer n = aux_getn(L, 1, TAB_RW); + if (n > 1) { /* non-trivial interval? */ + luaL_argcheck(L, n < INT_MAX, 1, "array too big"); + if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ + luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ + lua_settop(L, 2); /* make sure there are two arguments */ + auxsort(L, 1, (IdxT)n, 0); + } + return 0; +} + +/* }====================================================== */ + + +static const luaL_Reg tab_funcs[] = { + {"concat", tconcat}, + {"insert", tinsert}, + {"pack", tpack}, + {"unpack", tunpack}, + {"remove", tremove}, + {"move", tmove}, + {"sort", sort}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_table (lua_State *L) { + luaL_newlib(L, tab_funcs); + return 1; +} + diff --git a/vendor/lua-src/lua-5.4.6/ltm.c b/vendor/lua-src/lua-5.4.6/ltm.c new file mode 100644 index 0000000000000..07a060811d5c3 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/ltm.c @@ -0,0 +1,271 @@ +/* +** $Id: ltm.c $ +** Tag methods +** See Copyright Notice in lua.h +*/ + +#define ltm_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + +static const char udatatypename[] = "userdata"; + +LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTYPES] = { + "no value", + "nil", "boolean", udatatypename, "number", + "string", "table", "function", udatatypename, "thread", + "upvalue", "proto" /* these last cases are used for tests only */ +}; + + +void luaT_init (lua_State *L) { + static const char *const luaT_eventname[] = { /* ORDER TM */ + "__index", "__newindex", + "__gc", "__mode", "__len", "__eq", + "__add", "__sub", "__mul", "__mod", "__pow", + "__div", "__idiv", + "__band", "__bor", "__bxor", "__shl", "__shr", + "__unm", "__bnot", "__lt", "__le", + "__concat", "__call", "__close" + }; + int i; + for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); + luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ + } +} + + +/* +** function to be used with macro "fasttm": optimized for absence of +** tag methods +*/ +const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { + const TValue *tm = luaH_getshortstr(events, ename); + lua_assert(event <= TM_EQ); + if (notm(tm)) { /* no tag method? */ + events->flags |= cast_byte(1u<metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(o)->metatable; + break; + default: + mt = G(L)->mt[ttype(o)]; + } + return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : &G(L)->nilvalue); +} + + +/* +** Return the name of the type of an object. For tables and userdata +** with metatable, use their '__name' metafield, if present. +*/ +const char *luaT_objtypename (lua_State *L, const TValue *o) { + Table *mt; + if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) || + (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) { + const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name")); + if (ttisstring(name)) /* is '__name' a string? */ + return getstr(tsvalue(name)); /* use it as type name */ + } + return ttypename(ttype(o)); /* else use standard type name */ +} + + +void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, const TValue *p3) { + StkId func = L->top.p; + setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ + setobj2s(L, func + 1, p1); /* 1st argument */ + setobj2s(L, func + 2, p2); /* 2nd argument */ + setobj2s(L, func + 3, p3); /* 3rd argument */ + L->top.p = func + 4; + /* metamethod may yield only when called from Lua code */ + if (isLuacode(L->ci)) + luaD_call(L, func, 0); + else + luaD_callnoyield(L, func, 0); +} + + +void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, StkId res) { + ptrdiff_t result = savestack(L, res); + StkId func = L->top.p; + setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ + setobj2s(L, func + 1, p1); /* 1st argument */ + setobj2s(L, func + 2, p2); /* 2nd argument */ + L->top.p += 3; + /* metamethod may yield only when called from Lua code */ + if (isLuacode(L->ci)) + luaD_call(L, func, 1); + else + luaD_callnoyield(L, func, 1); + res = restorestack(L, result); + setobjs2s(L, res, --L->top.p); /* move result to its place */ +} + + +static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + if (notm(tm)) + tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ + if (notm(tm)) return 0; + luaT_callTMres(L, tm, p1, p2, res); + return 1; +} + + +void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + if (l_unlikely(!callbinTM(L, p1, p2, res, event))) { + switch (event) { + case TM_BAND: case TM_BOR: case TM_BXOR: + case TM_SHL: case TM_SHR: case TM_BNOT: { + if (ttisnumber(p1) && ttisnumber(p2)) + luaG_tointerror(L, p1, p2); + else + luaG_opinterror(L, p1, p2, "perform bitwise operation on"); + } + /* calls never return, but to avoid warnings: *//* FALLTHROUGH */ + default: + luaG_opinterror(L, p1, p2, "perform arithmetic on"); + } + } +} + + +void luaT_tryconcatTM (lua_State *L) { + StkId top = L->top.p; + if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, + TM_CONCAT))) + luaG_concaterror(L, s2v(top - 2), s2v(top - 1)); +} + + +void luaT_trybinassocTM (lua_State *L, const TValue *p1, const TValue *p2, + int flip, StkId res, TMS event) { + if (flip) + luaT_trybinTM(L, p2, p1, res, event); + else + luaT_trybinTM(L, p1, p2, res, event); +} + + +void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2, + int flip, StkId res, TMS event) { + TValue aux; + setivalue(&aux, i2); + luaT_trybinassocTM(L, p1, &aux, flip, res, event); +} + + +/* +** Calls an order tag method. +** For lessequal, LUA_COMPAT_LT_LE keeps compatibility with old +** behavior: if there is no '__le', try '__lt', based on l <= r iff +** !(r < l) (assuming a total order). If the metamethod yields during +** this substitution, the continuation has to know about it (to negate +** the result of rtop.p, event)) /* try original event */ + return !l_isfalse(s2v(L->top.p)); +#if defined(LUA_COMPAT_LT_LE) + else if (event == TM_LE) { + /* try '!(p2 < p1)' for '(p1 <= p2)' */ + L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ + if (callbinTM(L, p2, p1, L->top.p, TM_LT)) { + L->ci->callstatus ^= CIST_LEQ; /* clear mark */ + return l_isfalse(s2v(L->top.p)); + } + /* else error will remove this 'ci'; no need to clear mark */ + } +#endif + luaG_ordererror(L, p1, p2); /* no metamethod found */ + return 0; /* to avoid warnings */ +} + + +int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, + int flip, int isfloat, TMS event) { + TValue aux; const TValue *p2; + if (isfloat) { + setfltvalue(&aux, cast_num(v2)); + } + else + setivalue(&aux, v2); + if (flip) { /* arguments were exchanged? */ + p2 = p1; p1 = &aux; /* correct them */ + } + else + p2 = &aux; + return luaT_callorderTM(L, p1, p2, event); +} + + +void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci, + const Proto *p) { + int i; + int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */ + int nextra = actual - nfixparams; /* number of extra arguments */ + ci->u.l.nextraargs = nextra; + luaD_checkstack(L, p->maxstacksize + 1); + /* copy function to the top of the stack */ + setobjs2s(L, L->top.p++, ci->func.p); + /* move fixed parameters to the top of the stack */ + for (i = 1; i <= nfixparams; i++) { + setobjs2s(L, L->top.p++, ci->func.p + i); + setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */ + } + ci->func.p += actual + 1; + ci->top.p += actual + 1; + lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p); +} + + +void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) { + int i; + int nextra = ci->u.l.nextraargs; + if (wanted < 0) { + wanted = nextra; /* get all extra arguments available */ + checkstackGCp(L, nextra, where); /* ensure stack space */ + L->top.p = where + nextra; /* next instruction will need top */ + } + for (i = 0; i < wanted && i < nextra; i++) + setobjs2s(L, where + i, ci->func.p - nextra + i); + for (; i < wanted; i++) /* complete required results with nil */ + setnilvalue(s2v(where + i)); +} + diff --git a/vendor/lua-src/lua-5.4.6/ltm.h b/vendor/lua-src/lua-5.4.6/ltm.h new file mode 100644 index 0000000000000..c309e2ae10e32 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/ltm.h @@ -0,0 +1,104 @@ +/* +** $Id: ltm.h $ +** Tag methods +** See Copyright Notice in lua.h +*/ + +#ifndef ltm_h +#define ltm_h + + +#include "lobject.h" +#include "lstate.h" + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER TM" and "ORDER OP" +*/ +typedef enum { + TM_INDEX, + TM_NEWINDEX, + TM_GC, + TM_MODE, + TM_LEN, + TM_EQ, /* last tag method with fast access */ + TM_ADD, + TM_SUB, + TM_MUL, + TM_MOD, + TM_POW, + TM_DIV, + TM_IDIV, + TM_BAND, + TM_BOR, + TM_BXOR, + TM_SHL, + TM_SHR, + TM_UNM, + TM_BNOT, + TM_LT, + TM_LE, + TM_CONCAT, + TM_CALL, + TM_CLOSE, + TM_N /* number of elements in the enum */ +} TMS; + + +/* +** Mask with 1 in all fast-access methods. A 1 in any of these bits +** in the flag of a (meta)table means the metatable does not have the +** corresponding metamethod field. (Bit 7 of the flag is used for +** 'isrealasize'.) +*/ +#define maskflags (~(~0u << (TM_EQ + 1))) + + +/* +** Test whether there is no tagmethod. +** (Because tagmethods use raw accesses, the result may be an "empty" nil.) +*/ +#define notm(tm) ttisnil(tm) + + +#define gfasttm(g,et,e) ((et) == NULL ? NULL : \ + ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) + +#define fasttm(l,et,e) gfasttm(G(l), et, e) + +#define ttypename(x) luaT_typenames_[(x) + 1] + +LUAI_DDEC(const char *const luaT_typenames_[LUA_TOTALTYPES];) + + +LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o); + +LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); +LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, + TMS event); +LUAI_FUNC void luaT_init (lua_State *L); + +LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, const TValue *p3); +LUAI_FUNC void luaT_callTMres (lua_State *L, const TValue *f, + const TValue *p1, const TValue *p2, StkId p3); +LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event); +LUAI_FUNC void luaT_tryconcatTM (lua_State *L); +LUAI_FUNC void luaT_trybinassocTM (lua_State *L, const TValue *p1, + const TValue *p2, int inv, StkId res, TMS event); +LUAI_FUNC void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2, + int inv, StkId res, TMS event); +LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, + const TValue *p2, TMS event); +LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, + int inv, int isfloat, TMS event); + +LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, + CallInfo *ci, const Proto *p); +LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci, + StkId where, int wanted); + + +#endif diff --git a/vendor/lua-src/lua-5.4.6/lua.h b/vendor/lua-src/lua-5.4.6/lua.h new file mode 100644 index 0000000000000..fd16cf8050b8d --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lua.h @@ -0,0 +1,523 @@ +/* +** $Id: lua.h $ +** Lua - A Scripting Language +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) +** See Copyright Notice at the end of this file +*/ + + +#ifndef lua_h +#define lua_h + +#include +#include + + +#include "luaconf.h" + + +#define LUA_VERSION_MAJOR "5" +#define LUA_VERSION_MINOR "4" +#define LUA_VERSION_RELEASE "6" + +#define LUA_VERSION_NUM 504 +#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6) + +#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR +#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" + + +/* mark for precompiled code ('Lua') */ +#define LUA_SIGNATURE "\x1bLua" + +/* option for multiple returns in 'lua_pcall' and 'lua_call' */ +#define LUA_MULTRET (-1) + + +/* +** Pseudo-indices +** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty +** space after that to help overflow detection) +*/ +#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000) +#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) + + +/* thread status */ +#define LUA_OK 0 +#define LUA_YIELD 1 +#define LUA_ERRRUN 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRERR 5 + + +typedef struct lua_State lua_State; + + +/* +** basic types +*/ +#define LUA_TNONE (-1) + +#define LUA_TNIL 0 +#define LUA_TBOOLEAN 1 +#define LUA_TLIGHTUSERDATA 2 +#define LUA_TNUMBER 3 +#define LUA_TSTRING 4 +#define LUA_TTABLE 5 +#define LUA_TFUNCTION 6 +#define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 + +#define LUA_NUMTYPES 9 + + + +/* minimum Lua stack available to a C function */ +#define LUA_MINSTACK 20 + + +/* predefined values in the registry */ +#define LUA_RIDX_MAINTHREAD 1 +#define LUA_RIDX_GLOBALS 2 +#define LUA_RIDX_LAST LUA_RIDX_GLOBALS + + +/* type of numbers in Lua */ +typedef LUA_NUMBER lua_Number; + + +/* type for integer functions */ +typedef LUA_INTEGER lua_Integer; + +/* unsigned integer type */ +typedef LUA_UNSIGNED lua_Unsigned; + +/* type for continuation-function contexts */ +typedef LUA_KCONTEXT lua_KContext; + + +/* +** Type for C functions registered with Lua +*/ +typedef int (*lua_CFunction) (lua_State *L); + +/* +** Type for continuation functions +*/ +typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); + + +/* +** Type for functions that read/write blocks when loading/dumping Lua chunks +*/ +typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud); + + +/* +** Type for memory-allocation functions +*/ +typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); + + +/* +** Type for warning functions +*/ +typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont); + + +/* +** Type used by the debug API to collect debug information +*/ +typedef struct lua_Debug lua_Debug; + + +/* +** Functions to be called by the debugger in specific events +*/ +typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); + + +/* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + + +/* +** RCS ident string +*/ +extern const char lua_ident[]; + + +/* +** state manipulation +*/ +LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); +LUA_API void (lua_close) (lua_State *L); +LUA_API lua_State *(lua_newthread) (lua_State *L); +LUA_API int (lua_closethread) (lua_State *L, lua_State *from); +LUA_API int (lua_resetthread) (lua_State *L); /* Deprecated! */ + +LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); + + +LUA_API lua_Number (lua_version) (lua_State *L); + + +/* +** basic stack manipulation +*/ +LUA_API int (lua_absindex) (lua_State *L, int idx); +LUA_API int (lua_gettop) (lua_State *L); +LUA_API void (lua_settop) (lua_State *L, int idx); +LUA_API void (lua_pushvalue) (lua_State *L, int idx); +LUA_API void (lua_rotate) (lua_State *L, int idx, int n); +LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); +LUA_API int (lua_checkstack) (lua_State *L, int n); + +LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); + + +/* +** access functions (stack -> C) +*/ + +LUA_API int (lua_isnumber) (lua_State *L, int idx); +LUA_API int (lua_isstring) (lua_State *L, int idx); +LUA_API int (lua_iscfunction) (lua_State *L, int idx); +LUA_API int (lua_isinteger) (lua_State *L, int idx); +LUA_API int (lua_isuserdata) (lua_State *L, int idx); +LUA_API int (lua_type) (lua_State *L, int idx); +LUA_API const char *(lua_typename) (lua_State *L, int tp); + +LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); +LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); +LUA_API int (lua_toboolean) (lua_State *L, int idx); +LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); +LUA_API lua_Unsigned (lua_rawlen) (lua_State *L, int idx); +LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); +LUA_API void *(lua_touserdata) (lua_State *L, int idx); +LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); +LUA_API const void *(lua_topointer) (lua_State *L, int idx); + + +/* +** Comparison and arithmetic functions +*/ + +#define LUA_OPADD 0 /* ORDER TM, ORDER OP */ +#define LUA_OPSUB 1 +#define LUA_OPMUL 2 +#define LUA_OPMOD 3 +#define LUA_OPPOW 4 +#define LUA_OPDIV 5 +#define LUA_OPIDIV 6 +#define LUA_OPBAND 7 +#define LUA_OPBOR 8 +#define LUA_OPBXOR 9 +#define LUA_OPSHL 10 +#define LUA_OPSHR 11 +#define LUA_OPUNM 12 +#define LUA_OPBNOT 13 + +LUA_API void (lua_arith) (lua_State *L, int op); + +#define LUA_OPEQ 0 +#define LUA_OPLT 1 +#define LUA_OPLE 2 + +LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); + + +/* +** push functions (C -> stack) +*/ +LUA_API void (lua_pushnil) (lua_State *L); +LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); +LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len); +LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); +LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, + va_list argp); +LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); +LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); +LUA_API void (lua_pushboolean) (lua_State *L, int b); +LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); +LUA_API int (lua_pushthread) (lua_State *L); + + +/* +** get functions (Lua -> stack) +*/ +LUA_API int (lua_getglobal) (lua_State *L, const char *name); +LUA_API int (lua_gettable) (lua_State *L, int idx); +LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k); +LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n); +LUA_API int (lua_rawget) (lua_State *L, int idx); +LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); +LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p); + +LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); +LUA_API void *(lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue); +LUA_API int (lua_getmetatable) (lua_State *L, int objindex); +LUA_API int (lua_getiuservalue) (lua_State *L, int idx, int n); + + +/* +** set functions (stack -> Lua) +*/ +LUA_API void (lua_setglobal) (lua_State *L, const char *name); +LUA_API void (lua_settable) (lua_State *L, int idx); +LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n); +LUA_API void (lua_rawset) (lua_State *L, int idx); +LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n); +LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); +LUA_API int (lua_setmetatable) (lua_State *L, int objindex); +LUA_API int (lua_setiuservalue) (lua_State *L, int idx, int n); + + +/* +** 'load' and 'call' functions (load and run Lua code) +*/ +LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k); +#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) + +LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, + lua_KContext ctx, lua_KFunction k); +#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) + +LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, + const char *chunkname, const char *mode); + +LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); + + +/* +** coroutine functions +*/ +LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k); +LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg, + int *nres); +LUA_API int (lua_status) (lua_State *L); +LUA_API int (lua_isyieldable) (lua_State *L); + +#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) + + +/* +** Warning-related functions +*/ +LUA_API void (lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud); +LUA_API void (lua_warning) (lua_State *L, const char *msg, int tocont); + + +/* +** garbage-collection function and options +*/ + +#define LUA_GCSTOP 0 +#define LUA_GCRESTART 1 +#define LUA_GCCOLLECT 2 +#define LUA_GCCOUNT 3 +#define LUA_GCCOUNTB 4 +#define LUA_GCSTEP 5 +#define LUA_GCSETPAUSE 6 +#define LUA_GCSETSTEPMUL 7 +#define LUA_GCISRUNNING 9 +#define LUA_GCGEN 10 +#define LUA_GCINC 11 + +LUA_API int (lua_gc) (lua_State *L, int what, ...); + + +/* +** miscellaneous functions +*/ + +LUA_API int (lua_error) (lua_State *L); + +LUA_API int (lua_next) (lua_State *L, int idx); + +LUA_API void (lua_concat) (lua_State *L, int n); +LUA_API void (lua_len) (lua_State *L, int idx); + +LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); + +LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); +LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); + +LUA_API void (lua_toclose) (lua_State *L, int idx); +LUA_API void (lua_closeslot) (lua_State *L, int idx); + + +/* +** {============================================================== +** some useful macros +** =============================================================== +*/ + +#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE)) + +#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL) +#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL) + +#define lua_pop(L,n) lua_settop(L, -(n)-1) + +#define lua_newtable(L) lua_createtable(L, 0, 0) + +#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) + +#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) + +#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) +#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) +#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) +#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) +#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) +#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) +#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) +#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) + +#define lua_pushliteral(L, s) lua_pushstring(L, "" s) + +#define lua_pushglobaltable(L) \ + ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)) + +#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) + + +#define lua_insert(L,idx) lua_rotate(L, (idx), 1) + +#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1)) + +#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1)) + +/* }============================================================== */ + + +/* +** {============================================================== +** compatibility macros +** =============================================================== +*/ +#if defined(LUA_COMPAT_APIINTCASTS) + +#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) +#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) +#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) + +#endif + +#define lua_newuserdata(L,s) lua_newuserdatauv(L,s,1) +#define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1) +#define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1) + +#define LUA_NUMTAGS LUA_NUMTYPES + +/* }============================================================== */ + +/* +** {====================================================================== +** Debug API +** ======================================================================= +*/ + + +/* +** Event codes +*/ +#define LUA_HOOKCALL 0 +#define LUA_HOOKRET 1 +#define LUA_HOOKLINE 2 +#define LUA_HOOKCOUNT 3 +#define LUA_HOOKTAILCALL 4 + + +/* +** Event masks +*/ +#define LUA_MASKCALL (1 << LUA_HOOKCALL) +#define LUA_MASKRET (1 << LUA_HOOKRET) +#define LUA_MASKLINE (1 << LUA_HOOKLINE) +#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) + + +LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); +LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); +LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n); +LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n); + +LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); +LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, + int fidx2, int n2); + +LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); +LUA_API lua_Hook (lua_gethook) (lua_State *L); +LUA_API int (lua_gethookmask) (lua_State *L); +LUA_API int (lua_gethookcount) (lua_State *L); + +LUA_API int (lua_setcstacklimit) (lua_State *L, unsigned int limit); + +struct lua_Debug { + int event; + const char *name; /* (n) */ + const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ + const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ + const char *source; /* (S) */ + size_t srclen; /* (S) */ + int currentline; /* (l) */ + int linedefined; /* (S) */ + int lastlinedefined; /* (S) */ + unsigned char nups; /* (u) number of upvalues */ + unsigned char nparams;/* (u) number of parameters */ + char isvararg; /* (u) */ + char istailcall; /* (t) */ + unsigned short ftransfer; /* (r) index of first value transferred */ + unsigned short ntransfer; /* (r) number of transferred values */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + struct CallInfo *i_ci; /* active function */ +}; + +/* }====================================================================== */ + + +/****************************************************************************** +* Copyright (C) 1994-2023 Lua.org, PUC-Rio. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ + + +#endif diff --git a/vendor/lua-src/lua-5.4.6/luaconf.h b/vendor/lua-src/lua-5.4.6/luaconf.h new file mode 100644 index 0000000000000..137103edec4ef --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/luaconf.h @@ -0,0 +1,793 @@ +/* +** $Id: luaconf.h $ +** Configuration file for Lua +** See Copyright Notice in lua.h +*/ + + +#ifndef luaconf_h +#define luaconf_h + +#include +#include + + +/* +** =================================================================== +** General Configuration File for Lua +** +** Some definitions here can be changed externally, through the compiler +** (e.g., with '-D' options): They are commented out or protected +** by '#if !defined' guards. However, several other definitions +** should be changed directly here, either because they affect the +** Lua ABI (by making the changes here, you ensure that all software +** connected to Lua, such as C libraries, will be compiled with the same +** configuration); or because they are seldom changed. +** +** Search for "@@" to find all configurable definitions. +** =================================================================== +*/ + + +/* +** {==================================================================== +** System Configuration: macros to adapt (if needed) Lua to some +** particular platform, for instance restricting it to C89. +** ===================================================================== +*/ + +/* +@@ LUA_USE_C89 controls the use of non-ISO-C89 features. +** Define it if you want Lua to avoid the use of a few C99 features +** or Windows-specific features on Windows. +*/ +/* #define LUA_USE_C89 */ + + +/* +** By default, Lua on Windows use (some) specific Windows features +*/ +#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE) +#define LUA_USE_WINDOWS /* enable goodies for regular Windows */ +#endif + + +#if defined(LUA_USE_WINDOWS) +#define LUA_DL_DLL /* enable support for DLL */ +#define LUA_USE_C89 /* broadly, Windows is C89 */ +#endif + + +#if defined(LUA_USE_LINUX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ +#endif + + +#if defined(LUA_USE_MACOSX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* MacOS does not need -ldl */ +#endif + + +#if defined(LUA_USE_IOS) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN +#endif + + +/* +@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits. +*/ +#define LUAI_IS32INT ((UINT_MAX >> 30) >= 3) + +/* }================================================================== */ + + + +/* +** {================================================================== +** Configuration for Number types. These options should not be +** set externally, because any other code connected to Lua must +** use the same configuration. +** =================================================================== +*/ + +/* +@@ LUA_INT_TYPE defines the type for Lua integers. +@@ LUA_FLOAT_TYPE defines the type for Lua floats. +** Lua should work fine with any mix of these options supported +** by your C compiler. The usual configurations are 64-bit integers +** and 'double' (the default), 32-bit integers and 'float' (for +** restricted platforms), and 'long'/'double' (for C compilers not +** compliant with C99, which may not have support for 'long long'). +*/ + +/* predefined options for LUA_INT_TYPE */ +#define LUA_INT_INT 1 +#define LUA_INT_LONG 2 +#define LUA_INT_LONGLONG 3 + +/* predefined options for LUA_FLOAT_TYPE */ +#define LUA_FLOAT_FLOAT 1 +#define LUA_FLOAT_DOUBLE 2 +#define LUA_FLOAT_LONGDOUBLE 3 + + +/* Default configuration ('long long' and 'double', for 64-bit Lua) */ +#define LUA_INT_DEFAULT LUA_INT_LONGLONG +#define LUA_FLOAT_DEFAULT LUA_FLOAT_DOUBLE + + +/* +@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. +*/ +#define LUA_32BITS 0 + + +/* +@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for +** C89 ('long' and 'double'); Windows always has '__int64', so it does +** not need to use this case. +*/ +#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) +#define LUA_C89_NUMBERS 1 +#else +#define LUA_C89_NUMBERS 0 +#endif + + +#if LUA_32BITS /* { */ +/* +** 32-bit integers and 'float' +*/ +#if LUAI_IS32INT /* use 'int' if big enough */ +#define LUA_INT_TYPE LUA_INT_INT +#else /* otherwise use 'long' */ +#define LUA_INT_TYPE LUA_INT_LONG +#endif +#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT + +#elif LUA_C89_NUMBERS /* }{ */ +/* +** largest types available for C89 ('long' and 'double') +*/ +#define LUA_INT_TYPE LUA_INT_LONG +#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE + +#else /* }{ */ +/* use defaults */ + +#define LUA_INT_TYPE LUA_INT_DEFAULT +#define LUA_FLOAT_TYPE LUA_FLOAT_DEFAULT + +#endif /* } */ + + +/* }================================================================== */ + + + +/* +** {================================================================== +** Configuration for Paths. +** =================================================================== +*/ + +/* +** LUA_PATH_SEP is the character that separates templates in a path. +** LUA_PATH_MARK is the string that marks the substitution points in a +** template. +** LUA_EXEC_DIR in a Windows path is replaced by the executable's +** directory. +*/ +#define LUA_PATH_SEP ";" +#define LUA_PATH_MARK "?" +#define LUA_EXEC_DIR "!" + + +/* +@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for +** Lua libraries. +@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for +** C libraries. +** CHANGE them if your machine has a non-conventional directory +** hierarchy or if you want to install your libraries in +** non-conventional directories. +*/ + +#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR +#if defined(_WIN32) /* { */ +/* +** In Windows, any exclamation mark ('!') in the path is replaced by the +** path of the directory of the executable file of the current process. +*/ +#define LUA_LDIR "!\\lua\\" +#define LUA_CDIR "!\\" +#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" + +#if !defined(LUA_PATH_DEFAULT) +#define LUA_PATH_DEFAULT \ + LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ + LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ + ".\\?.lua;" ".\\?\\init.lua" +#endif + +#if !defined(LUA_CPATH_DEFAULT) +#define LUA_CPATH_DEFAULT \ + LUA_CDIR"?.dll;" \ + LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ + LUA_CDIR"loadall.dll;" ".\\?.dll" +#endif + +#else /* }{ */ + +#define LUA_ROOT "/usr/local/" +#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/" +#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/" + +#if !defined(LUA_PATH_DEFAULT) +#define LUA_PATH_DEFAULT \ + LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \ + "./?.lua;" "./?/init.lua" +#endif + +#if !defined(LUA_CPATH_DEFAULT) +#define LUA_CPATH_DEFAULT \ + LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" +#endif + +#endif /* } */ + + +/* +@@ LUA_DIRSEP is the directory separator (for submodules). +** CHANGE it if your machine does not use "/" as the directory separator +** and is not Windows. (On Windows Lua automatically uses "\".) +*/ +#if !defined(LUA_DIRSEP) + +#if defined(_WIN32) +#define LUA_DIRSEP "\\" +#else +#define LUA_DIRSEP "/" +#endif + +#endif + +/* }================================================================== */ + + +/* +** {================================================================== +** Marks for exported symbols in the C code +** =================================================================== +*/ + +/* +@@ LUA_API is a mark for all core API functions. +@@ LUALIB_API is a mark for all auxiliary library functions. +@@ LUAMOD_API is a mark for all standard library opening functions. +** CHANGE them if you need to define those functions in some special way. +** For instance, if you want to create one Windows DLL with the core and +** the libraries, you may want to use the following definition (define +** LUA_BUILD_AS_DLL to get it). +*/ +#if defined(LUA_BUILD_AS_DLL) /* { */ + +#if defined(LUA_CORE) || defined(LUA_LIB) /* { */ +#define LUA_API __declspec(dllexport) +#else /* }{ */ +#define LUA_API __declspec(dllimport) +#endif /* } */ + +#else /* }{ */ + +#define LUA_API extern + +#endif /* } */ + + +/* +** More often than not the libs go together with the core. +*/ +#define LUALIB_API LUA_API +#define LUAMOD_API LUA_API + + +/* +@@ LUAI_FUNC is a mark for all extern functions that are not to be +** exported to outside modules. +@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables, +** none of which to be exported to outside modules (LUAI_DDEF for +** definitions and LUAI_DDEC for declarations). +** CHANGE them if you need to mark them in some special way. Elf/gcc +** (versions 3.2 and later) mark them as "hidden" to optimize access +** when Lua is compiled as a shared library. Not all elf targets support +** this attribute. Unfortunately, gcc does not offer a way to check +** whether the target offers that support, and those without support +** give a warning about it. To avoid these warnings, change to the +** default definition. +*/ +#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ + defined(__ELF__) /* { */ +#define LUAI_FUNC __attribute__((visibility("internal"))) extern +#else /* }{ */ +#define LUAI_FUNC extern +#endif /* } */ + +#define LUAI_DDEC(dec) LUAI_FUNC dec +#define LUAI_DDEF /* empty */ + +/* }================================================================== */ + + +/* +** {================================================================== +** Compatibility with previous versions +** =================================================================== +*/ + +/* +@@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3. +** You can define it to get all options, or change specific options +** to fit your specific needs. +*/ +#if defined(LUA_COMPAT_5_3) /* { */ + +/* +@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated +** functions in the mathematical library. +** (These functions were already officially removed in 5.3; +** nevertheless they are still available here.) +*/ +#define LUA_COMPAT_MATHLIB + +/* +@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for +** manipulating other integer types (lua_pushunsigned, lua_tounsigned, +** luaL_checkint, luaL_checklong, etc.) +** (These macros were also officially removed in 5.3, but they are still +** available here.) +*/ +#define LUA_COMPAT_APIINTCASTS + + +/* +@@ LUA_COMPAT_LT_LE controls the emulation of the '__le' metamethod +** using '__lt'. +*/ +#define LUA_COMPAT_LT_LE + + +/* +@@ The following macros supply trivial compatibility for some +** changes in the API. The macros themselves document how to +** change your code to avoid using them. +** (Once more, these macros were officially removed in 5.3, but they are +** still available here.) +*/ +#define lua_strlen(L,i) lua_rawlen(L, (i)) + +#define lua_objlen(L,i) lua_rawlen(L, (i)) + +#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) +#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) + +#endif /* } */ + +/* }================================================================== */ + + + +/* +** {================================================================== +** Configuration for Numbers (low-level part). +** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* +** satisfy your needs. +** =================================================================== +*/ + +/* +@@ LUAI_UACNUMBER is the result of a 'default argument promotion' +@@ over a floating number. +@@ l_floatatt(x) corrects float attribute 'x' to the proper float type +** by prefixing it with one of FLT/DBL/LDBL. +@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats. +@@ LUA_NUMBER_FMT is the format for writing floats. +@@ lua_number2str converts a float to a string. +@@ l_mathop allows the addition of an 'l' or 'f' to all math operations. +@@ l_floor takes the floor of a float. +@@ lua_str2number converts a decimal numeral to a number. +*/ + + +/* The following definitions are good for most cases here */ + +#define l_floor(x) (l_mathop(floor)(x)) + +#define lua_number2str(s,sz,n) \ + l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n)) + +/* +@@ lua_numbertointeger converts a float number with an integral value +** to an integer, or returns 0 if float is not within the range of +** a lua_Integer. (The range comparisons are tricky because of +** rounding. The tests here assume a two-complement representation, +** where MININTEGER always has an exact representation as a float; +** MAXINTEGER may not have one, and therefore its conversion to float +** may have an ill-defined value.) +*/ +#define lua_numbertointeger(n,p) \ + ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ + (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ + (*(p) = (LUA_INTEGER)(n), 1)) + + +/* now the variable definitions */ + +#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */ + +#define LUA_NUMBER float + +#define l_floatatt(n) (FLT_##n) + +#define LUAI_UACNUMBER double + +#define LUA_NUMBER_FRMLEN "" +#define LUA_NUMBER_FMT "%.7g" + +#define l_mathop(op) op##f + +#define lua_str2number(s,p) strtof((s), (p)) + + +#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */ + +#define LUA_NUMBER long double + +#define l_floatatt(n) (LDBL_##n) + +#define LUAI_UACNUMBER long double + +#define LUA_NUMBER_FRMLEN "L" +#define LUA_NUMBER_FMT "%.19Lg" + +#define l_mathop(op) op##l + +#define lua_str2number(s,p) strtold((s), (p)) + +#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */ + +#define LUA_NUMBER double + +#define l_floatatt(n) (DBL_##n) + +#define LUAI_UACNUMBER double + +#define LUA_NUMBER_FRMLEN "" +#define LUA_NUMBER_FMT "%.14g" + +#define l_mathop(op) op + +#define lua_str2number(s,p) strtod((s), (p)) + +#else /* }{ */ + +#error "numeric float type not defined" + +#endif /* } */ + + + +/* +@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. +@@ LUAI_UACINT is the result of a 'default argument promotion' +@@ over a LUA_INTEGER. +@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. +@@ LUA_INTEGER_FMT is the format for writing integers. +@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. +@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. +@@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED. +@@ lua_integer2str converts an integer to a string. +*/ + + +/* The following definitions are good for most cases here */ + +#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" + +#define LUAI_UACINT LUA_INTEGER + +#define lua_integer2str(s,sz,n) \ + l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n)) + +/* +** use LUAI_UACINT here to avoid problems with promotions (which +** can turn a comparison between unsigneds into a signed comparison) +*/ +#define LUA_UNSIGNED unsigned LUAI_UACINT + + +/* now the variable definitions */ + +#if LUA_INT_TYPE == LUA_INT_INT /* { int */ + +#define LUA_INTEGER int +#define LUA_INTEGER_FRMLEN "" + +#define LUA_MAXINTEGER INT_MAX +#define LUA_MININTEGER INT_MIN + +#define LUA_MAXUNSIGNED UINT_MAX + +#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */ + +#define LUA_INTEGER long +#define LUA_INTEGER_FRMLEN "l" + +#define LUA_MAXINTEGER LONG_MAX +#define LUA_MININTEGER LONG_MIN + +#define LUA_MAXUNSIGNED ULONG_MAX + +#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */ + +/* use presence of macro LLONG_MAX as proxy for C99 compliance */ +#if defined(LLONG_MAX) /* { */ +/* use ISO C99 stuff */ + +#define LUA_INTEGER long long +#define LUA_INTEGER_FRMLEN "ll" + +#define LUA_MAXINTEGER LLONG_MAX +#define LUA_MININTEGER LLONG_MIN + +#define LUA_MAXUNSIGNED ULLONG_MAX + +#elif defined(LUA_USE_WINDOWS) /* }{ */ +/* in Windows, can use specific Windows types */ + +#define LUA_INTEGER __int64 +#define LUA_INTEGER_FRMLEN "I64" + +#define LUA_MAXINTEGER _I64_MAX +#define LUA_MININTEGER _I64_MIN + +#define LUA_MAXUNSIGNED _UI64_MAX + +#else /* }{ */ + +#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \ + or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)" + +#endif /* } */ + +#else /* }{ */ + +#error "numeric integer type not defined" + +#endif /* } */ + +/* }================================================================== */ + + +/* +** {================================================================== +** Dependencies with C99 and other C details +** =================================================================== +*/ + +/* +@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89. +** (All uses in Lua have only one format item.) +*/ +#if !defined(LUA_USE_C89) +#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i) +#else +#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i)) +#endif + + +/* +@@ lua_strx2number converts a hexadecimal numeral to a number. +** In C99, 'strtod' does that conversion. Otherwise, you can +** leave 'lua_strx2number' undefined and Lua will provide its own +** implementation. +*/ +#if !defined(LUA_USE_C89) +#define lua_strx2number(s,p) lua_str2number(s,p) +#endif + + +/* +@@ lua_pointer2str converts a pointer to a readable string in a +** non-specified way. +*/ +#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p) + + +/* +@@ lua_number2strx converts a float to a hexadecimal numeral. +** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. +** Otherwise, you can leave 'lua_number2strx' undefined and Lua will +** provide its own implementation. +*/ +#if !defined(LUA_USE_C89) +#define lua_number2strx(L,b,sz,f,n) \ + ((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n))) +#endif + + +/* +** 'strtof' and 'opf' variants for math functions are not valid in +** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the +** availability of these variants. ('math.h' is already included in +** all files that use these macros.) +*/ +#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF)) +#undef l_mathop /* variants not available */ +#undef lua_str2number +#define l_mathop(op) (lua_Number)op /* no variant */ +#define lua_str2number(s,p) ((lua_Number)strtod((s), (p))) +#endif + + +/* +@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation +** functions. It must be a numerical type; Lua will use 'intptr_t' if +** available, otherwise it will use 'ptrdiff_t' (the nearest thing to +** 'intptr_t' in C89) +*/ +#define LUA_KCONTEXT ptrdiff_t + +#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ + __STDC_VERSION__ >= 199901L +#include +#if defined(INTPTR_MAX) /* even in C99 this type is optional */ +#undef LUA_KCONTEXT +#define LUA_KCONTEXT intptr_t +#endif +#endif + + +/* +@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point). +** Change that if you do not want to use C locales. (Code using this +** macro must include the header 'locale.h'.) +*/ +#if !defined(lua_getlocaledecpoint) +#define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) +#endif + + +/* +** macros to improve jump prediction, used mostly for error handling +** and debug facilities. (Some macros in the Lua API use these macros. +** Define LUA_NOBUILTIN if you do not want '__builtin_expect' in your +** code.) +*/ +#if !defined(luai_likely) + +#if defined(__GNUC__) && !defined(LUA_NOBUILTIN) +#define luai_likely(x) (__builtin_expect(((x) != 0), 1)) +#define luai_unlikely(x) (__builtin_expect(((x) != 0), 0)) +#else +#define luai_likely(x) (x) +#define luai_unlikely(x) (x) +#endif + +#endif + + +#if defined(LUA_CORE) || defined(LUA_LIB) +/* shorter names for Lua's own use */ +#define l_likely(x) luai_likely(x) +#define l_unlikely(x) luai_unlikely(x) +#endif + + + +/* }================================================================== */ + + +/* +** {================================================================== +** Language Variations +** ===================================================================== +*/ + +/* +@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some +** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from +** numbers to strings. Define LUA_NOCVTS2N to turn off automatic +** coercion from strings to numbers. +*/ +/* #define LUA_NOCVTN2S */ +/* #define LUA_NOCVTS2N */ + + +/* +@@ LUA_USE_APICHECK turns on several consistency checks on the C API. +** Define it as a help when debugging C code. +*/ +#if defined(LUA_USE_APICHECK) +#include +#define luai_apicheck(l,e) assert(e) +#endif + +/* }================================================================== */ + + +/* +** {================================================================== +** Macros that affect the API and must be stable (that is, must be the +** same when you compile Lua and when you compile code that links to +** Lua). +** ===================================================================== +*/ + +/* +@@ LUAI_MAXSTACK limits the size of the Lua stack. +** CHANGE it if you need a different limit. This limit is arbitrary; +** its only purpose is to stop Lua from consuming unlimited stack +** space (and to reserve some numbers for pseudo-indices). +** (It must fit into max(size_t)/32 and max(int)/2.) +*/ +#if LUAI_IS32INT +#define LUAI_MAXSTACK 1000000 +#else +#define LUAI_MAXSTACK 15000 +#endif + + +/* +@@ LUA_EXTRASPACE defines the size of a raw memory area associated with +** a Lua state with very fast access. +** CHANGE it if you need a different size. +*/ +#define LUA_EXTRASPACE (sizeof(void *)) + + +/* +@@ LUA_IDSIZE gives the maximum size for the description of the source +** of a function in debug information. +** CHANGE it if you want a different size. +*/ +#define LUA_IDSIZE 60 + + +/* +@@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib +** buffer system. +*/ +#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number))) + + +/* +@@ LUAI_MAXALIGN defines fields that, when used in a union, ensure +** maximum alignment for the other items in that union. +*/ +#define LUAI_MAXALIGN lua_Number n; double u; void *s; lua_Integer i; long l + +/* }================================================================== */ + + + + + +/* =================================================================== */ + +/* +** Local configuration. You can use this space to add your redefinitions +** without modifying the main part of the file. +*/ + + + + + +#endif + diff --git a/vendor/lua-src/lua-5.4.6/lualib.h b/vendor/lua-src/lua-5.4.6/lualib.h new file mode 100644 index 0000000000000..2625529076a8f --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lualib.h @@ -0,0 +1,52 @@ +/* +** $Id: lualib.h $ +** Lua standard libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lualib_h +#define lualib_h + +#include "lua.h" + + +/* version suffix for environment variable names */ +#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR + + +LUAMOD_API int (luaopen_base) (lua_State *L); + +#define LUA_COLIBNAME "coroutine" +LUAMOD_API int (luaopen_coroutine) (lua_State *L); + +#define LUA_TABLIBNAME "table" +LUAMOD_API int (luaopen_table) (lua_State *L); + +#define LUA_IOLIBNAME "io" +LUAMOD_API int (luaopen_io) (lua_State *L); + +#define LUA_OSLIBNAME "os" +LUAMOD_API int (luaopen_os) (lua_State *L); + +#define LUA_STRLIBNAME "string" +LUAMOD_API int (luaopen_string) (lua_State *L); + +#define LUA_UTF8LIBNAME "utf8" +LUAMOD_API int (luaopen_utf8) (lua_State *L); + +#define LUA_MATHLIBNAME "math" +LUAMOD_API int (luaopen_math) (lua_State *L); + +#define LUA_DBLIBNAME "debug" +LUAMOD_API int (luaopen_debug) (lua_State *L); + +#define LUA_LOADLIBNAME "package" +LUAMOD_API int (luaopen_package) (lua_State *L); + + +/* open all previous libraries */ +LUALIB_API void (luaL_openlibs) (lua_State *L); + + +#endif diff --git a/vendor/lua-src/lua-5.4.6/lundump.c b/vendor/lua-src/lua-5.4.6/lundump.c new file mode 100644 index 0000000000000..02aed64fb6226 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lundump.c @@ -0,0 +1,335 @@ +/* +** $Id: lundump.c $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#define lundump_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstring.h" +#include "lundump.h" +#include "lzio.h" + + +#if !defined(luai_verifycode) +#define luai_verifycode(L,f) /* empty */ +#endif + + +typedef struct { + lua_State *L; + ZIO *Z; + const char *name; +} LoadState; + + +static l_noret error (LoadState *S, const char *why) { + luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why); + luaD_throw(S->L, LUA_ERRSYNTAX); +} + + +/* +** All high-level loads go through loadVector; you can change it to +** adapt to the endianness of the input +*/ +#define loadVector(S,b,n) loadBlock(S,b,(n)*sizeof((b)[0])) + +static void loadBlock (LoadState *S, void *b, size_t size) { + if (luaZ_read(S->Z, b, size) != 0) + error(S, "truncated chunk"); +} + + +#define loadVar(S,x) loadVector(S,&x,1) + + +static lu_byte loadByte (LoadState *S) { + int b = zgetc(S->Z); + if (b == EOZ) + error(S, "truncated chunk"); + return cast_byte(b); +} + + +static size_t loadUnsigned (LoadState *S, size_t limit) { + size_t x = 0; + int b; + limit >>= 7; + do { + b = loadByte(S); + if (x >= limit) + error(S, "integer overflow"); + x = (x << 7) | (b & 0x7f); + } while ((b & 0x80) == 0); + return x; +} + + +static size_t loadSize (LoadState *S) { + return loadUnsigned(S, ~(size_t)0); +} + + +static int loadInt (LoadState *S) { + return cast_int(loadUnsigned(S, INT_MAX)); +} + + +static lua_Number loadNumber (LoadState *S) { + lua_Number x; + loadVar(S, x); + return x; +} + + +static lua_Integer loadInteger (LoadState *S) { + lua_Integer x; + loadVar(S, x); + return x; +} + + +/* +** Load a nullable string into prototype 'p'. +*/ +static TString *loadStringN (LoadState *S, Proto *p) { + lua_State *L = S->L; + TString *ts; + size_t size = loadSize(S); + if (size == 0) /* no string? */ + return NULL; + else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */ + char buff[LUAI_MAXSHORTLEN]; + loadVector(S, buff, size); /* load string into buffer */ + ts = luaS_newlstr(L, buff, size); /* create string */ + } + else { /* long string */ + ts = luaS_createlngstrobj(L, size); /* create string */ + setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */ + luaD_inctop(L); + loadVector(S, getstr(ts), size); /* load directly in final place */ + L->top.p--; /* pop string */ + } + luaC_objbarrier(L, p, ts); + return ts; +} + + +/* +** Load a non-nullable string into prototype 'p'. +*/ +static TString *loadString (LoadState *S, Proto *p) { + TString *st = loadStringN(S, p); + if (st == NULL) + error(S, "bad format for constant string"); + return st; +} + + +static void loadCode (LoadState *S, Proto *f) { + int n = loadInt(S); + f->code = luaM_newvectorchecked(S->L, n, Instruction); + f->sizecode = n; + loadVector(S, f->code, n); +} + + +static void loadFunction(LoadState *S, Proto *f, TString *psource); + + +static void loadConstants (LoadState *S, Proto *f) { + int i; + int n = loadInt(S); + f->k = luaM_newvectorchecked(S->L, n, TValue); + f->sizek = n; + for (i = 0; i < n; i++) + setnilvalue(&f->k[i]); + for (i = 0; i < n; i++) { + TValue *o = &f->k[i]; + int t = loadByte(S); + switch (t) { + case LUA_VNIL: + setnilvalue(o); + break; + case LUA_VFALSE: + setbfvalue(o); + break; + case LUA_VTRUE: + setbtvalue(o); + break; + case LUA_VNUMFLT: + setfltvalue(o, loadNumber(S)); + break; + case LUA_VNUMINT: + setivalue(o, loadInteger(S)); + break; + case LUA_VSHRSTR: + case LUA_VLNGSTR: + setsvalue2n(S->L, o, loadString(S, f)); + break; + default: lua_assert(0); + } + } +} + + +static void loadProtos (LoadState *S, Proto *f) { + int i; + int n = loadInt(S); + f->p = luaM_newvectorchecked(S->L, n, Proto *); + f->sizep = n; + for (i = 0; i < n; i++) + f->p[i] = NULL; + for (i = 0; i < n; i++) { + f->p[i] = luaF_newproto(S->L); + luaC_objbarrier(S->L, f, f->p[i]); + loadFunction(S, f->p[i], f->source); + } +} + + +/* +** Load the upvalues for a function. The names must be filled first, +** because the filling of the other fields can raise read errors and +** the creation of the error message can call an emergency collection; +** in that case all prototypes must be consistent for the GC. +*/ +static void loadUpvalues (LoadState *S, Proto *f) { + int i, n; + n = loadInt(S); + f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc); + f->sizeupvalues = n; + for (i = 0; i < n; i++) /* make array valid for GC */ + f->upvalues[i].name = NULL; + for (i = 0; i < n; i++) { /* following calls can raise errors */ + f->upvalues[i].instack = loadByte(S); + f->upvalues[i].idx = loadByte(S); + f->upvalues[i].kind = loadByte(S); + } +} + + +static void loadDebug (LoadState *S, Proto *f) { + int i, n; + n = loadInt(S); + f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte); + f->sizelineinfo = n; + loadVector(S, f->lineinfo, n); + n = loadInt(S); + f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo); + f->sizeabslineinfo = n; + for (i = 0; i < n; i++) { + f->abslineinfo[i].pc = loadInt(S); + f->abslineinfo[i].line = loadInt(S); + } + n = loadInt(S); + f->locvars = luaM_newvectorchecked(S->L, n, LocVar); + f->sizelocvars = n; + for (i = 0; i < n; i++) + f->locvars[i].varname = NULL; + for (i = 0; i < n; i++) { + f->locvars[i].varname = loadStringN(S, f); + f->locvars[i].startpc = loadInt(S); + f->locvars[i].endpc = loadInt(S); + } + n = loadInt(S); + if (n != 0) /* does it have debug information? */ + n = f->sizeupvalues; /* must be this many */ + for (i = 0; i < n; i++) + f->upvalues[i].name = loadStringN(S, f); +} + + +static void loadFunction (LoadState *S, Proto *f, TString *psource) { + f->source = loadStringN(S, f); + if (f->source == NULL) /* no source in dump? */ + f->source = psource; /* reuse parent's source */ + f->linedefined = loadInt(S); + f->lastlinedefined = loadInt(S); + f->numparams = loadByte(S); + f->is_vararg = loadByte(S); + f->maxstacksize = loadByte(S); + loadCode(S, f); + loadConstants(S, f); + loadUpvalues(S, f); + loadProtos(S, f); + loadDebug(S, f); +} + + +static void checkliteral (LoadState *S, const char *s, const char *msg) { + char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ + size_t len = strlen(s); + loadVector(S, buff, len); + if (memcmp(s, buff, len) != 0) + error(S, msg); +} + + +static void fchecksize (LoadState *S, size_t size, const char *tname) { + if (loadByte(S) != size) + error(S, luaO_pushfstring(S->L, "%s size mismatch", tname)); +} + + +#define checksize(S,t) fchecksize(S,sizeof(t),#t) + +static void checkHeader (LoadState *S) { + /* skip 1st char (already read and checked) */ + checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk"); + if (loadByte(S) != LUAC_VERSION) + error(S, "version mismatch"); + if (loadByte(S) != LUAC_FORMAT) + error(S, "format mismatch"); + checkliteral(S, LUAC_DATA, "corrupted chunk"); + checksize(S, Instruction); + checksize(S, lua_Integer); + checksize(S, lua_Number); + if (loadInteger(S) != LUAC_INT) + error(S, "integer format mismatch"); + if (loadNumber(S) != LUAC_NUM) + error(S, "float format mismatch"); +} + + +/* +** Load precompiled chunk. +*/ +LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { + LoadState S; + LClosure *cl; + if (*name == '@' || *name == '=') + S.name = name + 1; + else if (*name == LUA_SIGNATURE[0]) + S.name = "binary string"; + else + S.name = name; + S.L = L; + S.Z = Z; + checkHeader(&S); + cl = luaF_newLclosure(L, loadByte(&S)); + setclLvalue2s(L, L->top.p, cl); + luaD_inctop(L); + cl->p = luaF_newproto(L); + luaC_objbarrier(L, cl, cl->p); + loadFunction(&S, cl->p, NULL); + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luai_verifycode(L, cl->p); + return cl; +} + diff --git a/vendor/lua-src/lua-5.4.6/lundump.h b/vendor/lua-src/lua-5.4.6/lundump.h new file mode 100644 index 0000000000000..f3748a9980754 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lundump.h @@ -0,0 +1,36 @@ +/* +** $Id: lundump.h $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#ifndef lundump_h +#define lundump_h + +#include "llimits.h" +#include "lobject.h" +#include "lzio.h" + + +/* data to catch conversion errors */ +#define LUAC_DATA "\x19\x93\r\n\x1a\n" + +#define LUAC_INT 0x5678 +#define LUAC_NUM cast_num(370.5) + +/* +** Encode major-minor version in one byte, one nibble for each +*/ +#define MYINT(s) (s[0]-'0') /* assume one-digit numerals */ +#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) + +#define LUAC_FORMAT 0 /* this is the official format */ + +/* load one chunk; from lundump.c */ +LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); + +/* dump one chunk; from ldump.c */ +LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, + void* data, int strip); + +#endif diff --git a/vendor/lua-src/lua-5.4.6/lutf8lib.c b/vendor/lua-src/lua-5.4.6/lutf8lib.c new file mode 100644 index 0000000000000..3a5b9bc38a5bb --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lutf8lib.c @@ -0,0 +1,291 @@ +/* +** $Id: lutf8lib.c $ +** Standard library for UTF-8 manipulation +** See Copyright Notice in lua.h +*/ + +#define lutf8lib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#define MAXUNICODE 0x10FFFFu + +#define MAXUTF 0x7FFFFFFFu + + +#define MSGInvalid "invalid UTF-8 code" + +/* +** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits. +*/ +#if (UINT_MAX >> 30) >= 1 +typedef unsigned int utfint; +#else +typedef unsigned long utfint; +#endif + + +#define iscont(c) (((c) & 0xC0) == 0x80) +#define iscontp(p) iscont(*(p)) + + +/* from strlib */ +/* translate a relative string position: negative means back from end */ +static lua_Integer u_posrelat (lua_Integer pos, size_t len) { + if (pos >= 0) return pos; + else if (0u - (size_t)pos > len) return 0; + else return (lua_Integer)len + pos + 1; +} + + +/* +** Decode one UTF-8 sequence, returning NULL if byte sequence is +** invalid. The array 'limits' stores the minimum value for each +** sequence length, to check for overlong representations. Its first +** entry forces an error for non-ascii bytes with no continuation +** bytes (count == 0). +*/ +static const char *utf8_decode (const char *s, utfint *val, int strict) { + static const utfint limits[] = + {~(utfint)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u}; + unsigned int c = (unsigned char)s[0]; + utfint res = 0; /* final result */ + if (c < 0x80) /* ascii? */ + res = c; + else { + int count = 0; /* to count number of continuation bytes */ + for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */ + unsigned int cc = (unsigned char)s[++count]; /* read next byte */ + if (!iscont(cc)) /* not a continuation byte? */ + return NULL; /* invalid byte sequence */ + res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ + } + res |= ((utfint)(c & 0x7F) << (count * 5)); /* add first byte */ + if (count > 5 || res > MAXUTF || res < limits[count]) + return NULL; /* invalid byte sequence */ + s += count; /* skip continuation bytes read */ + } + if (strict) { + /* check for invalid code points; too large or surrogates */ + if (res > MAXUNICODE || (0xD800u <= res && res <= 0xDFFFu)) + return NULL; + } + if (val) *val = res; + return s + 1; /* +1 to include first byte */ +} + + +/* +** utf8len(s [, i [, j [, lax]]]) --> number of characters that +** start in the range [i,j], or nil + current position if 's' is not +** well formed in that interval +*/ +static int utflen (lua_State *L) { + lua_Integer n = 0; /* counter for the number of characters */ + size_t len; /* string length in bytes */ + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); + int lax = lua_toboolean(L, 4); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, + "initial position out of bounds"); + luaL_argcheck(L, --posj < (lua_Integer)len, 3, + "final position out of bounds"); + while (posi <= posj) { + const char *s1 = utf8_decode(s + posi, NULL, !lax); + if (s1 == NULL) { /* conversion error? */ + luaL_pushfail(L); /* return fail ... */ + lua_pushinteger(L, posi + 1); /* ... and current position */ + return 2; + } + posi = s1 - s; + n++; + } + lua_pushinteger(L, n); + return 1; +} + + +/* +** codepoint(s, [i, [j [, lax]]]) -> returns codepoints for all +** characters that start in the range [i,j] +*/ +static int codepoint (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); + int lax = lua_toboolean(L, 4); + int n; + const char *se; + luaL_argcheck(L, posi >= 1, 2, "out of bounds"); + luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of bounds"); + if (posi > pose) return 0; /* empty interval; return no values */ + if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; /* upper bound for number of returns */ + luaL_checkstack(L, n, "string slice too long"); + n = 0; /* count the number of returns */ + se = s + pose; /* string end */ + for (s += posi - 1; s < se;) { + utfint code; + s = utf8_decode(s, &code, !lax); + if (s == NULL) + return luaL_error(L, MSGInvalid); + lua_pushinteger(L, code); + n++; + } + return n; +} + + +static void pushutfchar (lua_State *L, int arg) { + lua_Unsigned code = (lua_Unsigned)luaL_checkinteger(L, arg); + luaL_argcheck(L, code <= MAXUTF, arg, "value out of range"); + lua_pushfstring(L, "%U", (long)code); +} + + +/* +** utfchar(n1, n2, ...) -> char(n1)..char(n2)... +*/ +static int utfchar (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + if (n == 1) /* optimize common case of single char */ + pushutfchar(L, 1); + else { + int i; + luaL_Buffer b; + luaL_buffinit(L, &b); + for (i = 1; i <= n; i++) { + pushutfchar(L, i); + luaL_addvalue(&b); + } + luaL_pushresult(&b); + } + return 1; +} + + +/* +** offset(s, n, [i]) -> index where n-th character counting from +** position 'i' starts; 0 means character at 'i'. +*/ +static int byteoffset (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer n = luaL_checkinteger(L, 2); + lua_Integer posi = (n >= 0) ? 1 : len + 1; + posi = u_posrelat(luaL_optinteger(L, 3, posi), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, + "position out of bounds"); + if (n == 0) { + /* find beginning of current byte sequence */ + while (posi > 0 && iscontp(s + posi)) posi--; + } + else { + if (iscontp(s + posi)) + return luaL_error(L, "initial position is a continuation byte"); + if (n < 0) { + while (n < 0 && posi > 0) { /* move back */ + do { /* find beginning of previous character */ + posi--; + } while (posi > 0 && iscontp(s + posi)); + n++; + } + } + else { + n--; /* do not move for 1st character */ + while (n > 0 && posi < (lua_Integer)len) { + do { /* find beginning of next character */ + posi++; + } while (iscontp(s + posi)); /* (cannot pass final '\0') */ + n--; + } + } + } + if (n == 0) /* did it find given character? */ + lua_pushinteger(L, posi + 1); + else /* no such character */ + luaL_pushfail(L); + return 1; +} + + +static int iter_aux (lua_State *L, int strict) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2); + if (n < len) { + while (iscontp(s + n)) n++; /* go to next character */ + } + if (n >= len) /* (also handles original 'n' being negative) */ + return 0; /* no more codepoints */ + else { + utfint code; + const char *next = utf8_decode(s + n, &code, strict); + if (next == NULL || iscontp(next)) + return luaL_error(L, MSGInvalid); + lua_pushinteger(L, n + 1); + lua_pushinteger(L, code); + return 2; + } +} + + +static int iter_auxstrict (lua_State *L) { + return iter_aux(L, 1); +} + +static int iter_auxlax (lua_State *L) { + return iter_aux(L, 0); +} + + +static int iter_codes (lua_State *L) { + int lax = lua_toboolean(L, 2); + const char *s = luaL_checkstring(L, 1); + luaL_argcheck(L, !iscontp(s), 1, MSGInvalid); + lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict); + lua_pushvalue(L, 1); + lua_pushinteger(L, 0); + return 3; +} + + +/* pattern to match a single UTF-8 character */ +#define UTF8PATT "[\0-\x7F\xC2-\xFD][\x80-\xBF]*" + + +static const luaL_Reg funcs[] = { + {"offset", byteoffset}, + {"codepoint", codepoint}, + {"char", utfchar}, + {"len", utflen}, + {"codes", iter_codes}, + /* placeholders */ + {"charpattern", NULL}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_utf8 (lua_State *L) { + luaL_newlib(L, funcs); + lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); + lua_setfield(L, -2, "charpattern"); + return 1; +} + diff --git a/vendor/lua-src/lua-5.4.6/lvm.c b/vendor/lua-src/lua-5.4.6/lvm.c new file mode 100644 index 0000000000000..8493a770c56f2 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lvm.c @@ -0,0 +1,1901 @@ +/* +** $Id: lvm.c $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#define lvm_c +#define LUA_CORE + +#include "lprefix.h" + +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + +/* +** By default, use jump tables in the main interpreter loop on gcc +** and compatible compilers. +*/ +#if !defined(LUA_USE_JUMPTABLE) +#if defined(__GNUC__) +#define LUA_USE_JUMPTABLE 1 +#else +#define LUA_USE_JUMPTABLE 0 +#endif +#endif + + + +/* limit for table tag-method chains (to avoid infinite loops) */ +#define MAXTAGLOOP 2000 + + +/* +** 'l_intfitsf' checks whether a given integer is in the range that +** can be converted to a float without rounding. Used in comparisons. +*/ + +/* number of bits in the mantissa of a float */ +#define NBM (l_floatatt(MANT_DIG)) + +/* +** Check whether some integers may not fit in a float, testing whether +** (maxinteger >> NBM) > 0. (That implies (1 << NBM) <= maxinteger.) +** (The shifts are done in parts, to avoid shifting by more than the size +** of an integer. In a worst case, NBM == 113 for long double and +** sizeof(long) == 32.) +*/ +#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \ + >> (NBM - (3 * (NBM / 4)))) > 0 + +/* limit for integers that fit in a float */ +#define MAXINTFITSF ((lua_Unsigned)1 << NBM) + +/* check whether 'i' is in the interval [-MAXINTFITSF, MAXINTFITSF] */ +#define l_intfitsf(i) ((MAXINTFITSF + l_castS2U(i)) <= (2 * MAXINTFITSF)) + +#else /* all integers fit in a float precisely */ + +#define l_intfitsf(i) 1 + +#endif + + +/* +** Try to convert a value from string to a number value. +** If the value is not a string or is a string not representing +** a valid numeral (or if coercions from strings to numbers +** are disabled via macro 'cvt2num'), do not modify 'result' +** and return 0. +*/ +static int l_strton (const TValue *obj, TValue *result) { + lua_assert(obj != result); + if (!cvt2num(obj)) /* is object not a string? */ + return 0; + else + return (luaO_str2num(svalue(obj), result) == vslen(obj) + 1); +} + + +/* +** Try to convert a value to a float. The float case is already handled +** by the macro 'tonumber'. +*/ +int luaV_tonumber_ (const TValue *obj, lua_Number *n) { + TValue v; + if (ttisinteger(obj)) { + *n = cast_num(ivalue(obj)); + return 1; + } + else if (l_strton(obj, &v)) { /* string coercible to number? */ + *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ + return 1; + } + else + return 0; /* conversion failed */ +} + + +/* +** try to convert a float to an integer, rounding according to 'mode'. +*/ +int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode) { + lua_Number f = l_floor(n); + if (n != f) { /* not an integral value? */ + if (mode == F2Ieq) return 0; /* fails if mode demands integral value */ + else if (mode == F2Iceil) /* needs ceil? */ + f += 1; /* convert floor to ceil (remember: n != f) */ + } + return lua_numbertointeger(f, p); +} + + +/* +** try to convert a value to an integer, rounding according to 'mode', +** without string coercion. +** ("Fast track" handled by macro 'tointegerns'.) +*/ +int luaV_tointegerns (const TValue *obj, lua_Integer *p, F2Imod mode) { + if (ttisfloat(obj)) + return luaV_flttointeger(fltvalue(obj), p, mode); + else if (ttisinteger(obj)) { + *p = ivalue(obj); + return 1; + } + else + return 0; +} + + +/* +** try to convert a value to an integer. +*/ +int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode) { + TValue v; + if (l_strton(obj, &v)) /* does 'obj' point to a numerical string? */ + obj = &v; /* change it to point to its corresponding number */ + return luaV_tointegerns(obj, p, mode); +} + + +/* +** Try to convert a 'for' limit to an integer, preserving the semantics +** of the loop. Return true if the loop must not run; otherwise, '*p' +** gets the integer limit. +** (The following explanation assumes a positive step; it is valid for +** negative steps mutatis mutandis.) +** If the limit is an integer or can be converted to an integer, +** rounding down, that is the limit. +** Otherwise, check whether the limit can be converted to a float. If +** the float is too large, clip it to LUA_MAXINTEGER. If the float +** is too negative, the loop should not run, because any initial +** integer value is greater than such limit; so, the function returns +** true to signal that. (For this latter case, no integer limit would be +** correct; even a limit of LUA_MININTEGER would run the loop once for +** an initial value equal to LUA_MININTEGER.) +*/ +static int forlimit (lua_State *L, lua_Integer init, const TValue *lim, + lua_Integer *p, lua_Integer step) { + if (!luaV_tointeger(lim, p, (step < 0 ? F2Iceil : F2Ifloor))) { + /* not coercible to in integer */ + lua_Number flim; /* try to convert to float */ + if (!tonumber(lim, &flim)) /* cannot convert to float? */ + luaG_forerror(L, lim, "limit"); + /* else 'flim' is a float out of integer bounds */ + if (luai_numlt(0, flim)) { /* if it is positive, it is too large */ + if (step < 0) return 1; /* initial value must be less than it */ + *p = LUA_MAXINTEGER; /* truncate */ + } + else { /* it is less than min integer */ + if (step > 0) return 1; /* initial value must be greater than it */ + *p = LUA_MININTEGER; /* truncate */ + } + } + return (step > 0 ? init > *p : init < *p); /* not to run? */ +} + + +/* +** Prepare a numerical for loop (opcode OP_FORPREP). +** Return true to skip the loop. Otherwise, +** after preparation, stack will be as follows: +** ra : internal index (safe copy of the control variable) +** ra + 1 : loop counter (integer loops) or limit (float loops) +** ra + 2 : step +** ra + 3 : control variable +*/ +static int forprep (lua_State *L, StkId ra) { + TValue *pinit = s2v(ra); + TValue *plimit = s2v(ra + 1); + TValue *pstep = s2v(ra + 2); + if (ttisinteger(pinit) && ttisinteger(pstep)) { /* integer loop? */ + lua_Integer init = ivalue(pinit); + lua_Integer step = ivalue(pstep); + lua_Integer limit; + if (step == 0) + luaG_runerror(L, "'for' step is zero"); + setivalue(s2v(ra + 3), init); /* control variable */ + if (forlimit(L, init, plimit, &limit, step)) + return 1; /* skip the loop */ + else { /* prepare loop counter */ + lua_Unsigned count; + if (step > 0) { /* ascending loop? */ + count = l_castS2U(limit) - l_castS2U(init); + if (step != 1) /* avoid division in the too common case */ + count /= l_castS2U(step); + } + else { /* step < 0; descending loop */ + count = l_castS2U(init) - l_castS2U(limit); + /* 'step+1' avoids negating 'mininteger' */ + count /= l_castS2U(-(step + 1)) + 1u; + } + /* store the counter in place of the limit (which won't be + needed anymore) */ + setivalue(plimit, l_castU2S(count)); + } + } + else { /* try making all values floats */ + lua_Number init; lua_Number limit; lua_Number step; + if (l_unlikely(!tonumber(plimit, &limit))) + luaG_forerror(L, plimit, "limit"); + if (l_unlikely(!tonumber(pstep, &step))) + luaG_forerror(L, pstep, "step"); + if (l_unlikely(!tonumber(pinit, &init))) + luaG_forerror(L, pinit, "initial value"); + if (step == 0) + luaG_runerror(L, "'for' step is zero"); + if (luai_numlt(0, step) ? luai_numlt(limit, init) + : luai_numlt(init, limit)) + return 1; /* skip the loop */ + else { + /* make sure internal values are all floats */ + setfltvalue(plimit, limit); + setfltvalue(pstep, step); + setfltvalue(s2v(ra), init); /* internal index */ + setfltvalue(s2v(ra + 3), init); /* control variable */ + } + } + return 0; +} + + +/* +** Execute a step of a float numerical for loop, returning +** true iff the loop must continue. (The integer case is +** written online with opcode OP_FORLOOP, for performance.) +*/ +static int floatforloop (StkId ra) { + lua_Number step = fltvalue(s2v(ra + 2)); + lua_Number limit = fltvalue(s2v(ra + 1)); + lua_Number idx = fltvalue(s2v(ra)); /* internal index */ + idx = luai_numadd(L, idx, step); /* increment index */ + if (luai_numlt(0, step) ? luai_numle(idx, limit) + : luai_numle(limit, idx)) { + chgfltvalue(s2v(ra), idx); /* update internal index */ + setfltvalue(s2v(ra + 3), idx); /* and control variable */ + return 1; /* jump back */ + } + else + return 0; /* finish the loop */ +} + + +/* +** Finish the table access 'val = t[key]'. +** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to +** t[k] entry (which must be empty). +*/ +void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, + const TValue *slot) { + int loop; /* counter to avoid infinite loops */ + const TValue *tm; /* metamethod */ + for (loop = 0; loop < MAXTAGLOOP; loop++) { + if (slot == NULL) { /* 't' is not a table? */ + lua_assert(!ttistable(t)); + tm = luaT_gettmbyobj(L, t, TM_INDEX); + if (l_unlikely(notm(tm))) + luaG_typeerror(L, t, "index"); /* no metamethod */ + /* else will try the metamethod */ + } + else { /* 't' is a table */ + lua_assert(isempty(slot)); + tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ + if (tm == NULL) { /* no metamethod? */ + setnilvalue(s2v(val)); /* result is nil */ + return; + } + /* else will try the metamethod */ + } + if (ttisfunction(tm)) { /* is metamethod a function? */ + luaT_callTMres(L, tm, t, key, val); /* call it */ + return; + } + t = tm; /* else try to access 'tm[key]' */ + if (luaV_fastget(L, t, key, slot, luaH_get)) { /* fast track? */ + setobj2s(L, val, slot); /* done */ + return; + } + /* else repeat (tail call 'luaV_finishget') */ + } + luaG_runerror(L, "'__index' chain too long; possible loop"); +} + + +/* +** Finish a table assignment 't[key] = val'. +** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points +** to the entry 't[key]', or to a value with an absent key if there +** is no such entry. (The value at 'slot' must be empty, otherwise +** 'luaV_fastget' would have done the job.) +*/ +void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + TValue *val, const TValue *slot) { + int loop; /* counter to avoid infinite loops */ + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; /* '__newindex' metamethod */ + if (slot != NULL) { /* is 't' a table? */ + Table *h = hvalue(t); /* save 't' table */ + lua_assert(isempty(slot)); /* slot must be empty */ + tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ + if (tm == NULL) { /* no metamethod? */ + luaH_finishset(L, h, key, slot, val); /* set new value */ + invalidateTMcache(h); + luaC_barrierback(L, obj2gco(h), val); + return; + } + /* else will try the metamethod */ + } + else { /* not a table; check metamethod */ + tm = luaT_gettmbyobj(L, t, TM_NEWINDEX); + if (l_unlikely(notm(tm))) + luaG_typeerror(L, t, "index"); + } + /* try the metamethod */ + if (ttisfunction(tm)) { + luaT_callTM(L, tm, t, key, val); + return; + } + t = tm; /* else repeat assignment over 'tm' */ + if (luaV_fastget(L, t, key, slot, luaH_get)) { + luaV_finishfastset(L, t, slot, val); + return; /* done */ + } + /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ + } + luaG_runerror(L, "'__newindex' chain too long; possible loop"); +} + + +/* +** Compare two strings 'ls' x 'rs', returning an integer less-equal- +** -greater than zero if 'ls' is less-equal-greater than 'rs'. +** The code is a little tricky because it allows '\0' in the strings +** and it uses 'strcoll' (to respect locales) for each segments +** of the strings. +*/ +static int l_strcmp (const TString *ls, const TString *rs) { + const char *l = getstr(ls); + size_t ll = tsslen(ls); + const char *r = getstr(rs); + size_t lr = tsslen(rs); + for (;;) { /* for each segment */ + int temp = strcoll(l, r); + if (temp != 0) /* not equal? */ + return temp; /* done */ + else { /* strings are equal up to a '\0' */ + size_t len = strlen(l); /* index of first '\0' in both strings */ + if (len == lr) /* 'rs' is finished? */ + return (len == ll) ? 0 : 1; /* check 'ls' */ + else if (len == ll) /* 'ls' is finished? */ + return -1; /* 'ls' is less than 'rs' ('rs' is not finished) */ + /* both strings longer than 'len'; go on comparing after the '\0' */ + len++; + l += len; ll -= len; r += len; lr -= len; + } + } +} + + +/* +** Check whether integer 'i' is less than float 'f'. If 'i' has an +** exact representation as a float ('l_intfitsf'), compare numbers as +** floats. Otherwise, use the equivalence 'i < f <=> i < ceil(f)'. +** If 'ceil(f)' is out of integer range, either 'f' is greater than +** all integers or less than all integers. +** (The test with 'l_intfitsf' is only for performance; the else +** case is correct for all values, but it is slow due to the conversion +** from float to int.) +** When 'f' is NaN, comparisons must result in false. +*/ +l_sinline int LTintfloat (lua_Integer i, lua_Number f) { + if (l_intfitsf(i)) + return luai_numlt(cast_num(i), f); /* compare them as floats */ + else { /* i < f <=> i < ceil(f) */ + lua_Integer fi; + if (luaV_flttointeger(f, &fi, F2Iceil)) /* fi = ceil(f) */ + return i < fi; /* compare them as integers */ + else /* 'f' is either greater or less than all integers */ + return f > 0; /* greater? */ + } +} + + +/* +** Check whether integer 'i' is less than or equal to float 'f'. +** See comments on previous function. +*/ +l_sinline int LEintfloat (lua_Integer i, lua_Number f) { + if (l_intfitsf(i)) + return luai_numle(cast_num(i), f); /* compare them as floats */ + else { /* i <= f <=> i <= floor(f) */ + lua_Integer fi; + if (luaV_flttointeger(f, &fi, F2Ifloor)) /* fi = floor(f) */ + return i <= fi; /* compare them as integers */ + else /* 'f' is either greater or less than all integers */ + return f > 0; /* greater? */ + } +} + + +/* +** Check whether float 'f' is less than integer 'i'. +** See comments on previous function. +*/ +l_sinline int LTfloatint (lua_Number f, lua_Integer i) { + if (l_intfitsf(i)) + return luai_numlt(f, cast_num(i)); /* compare them as floats */ + else { /* f < i <=> floor(f) < i */ + lua_Integer fi; + if (luaV_flttointeger(f, &fi, F2Ifloor)) /* fi = floor(f) */ + return fi < i; /* compare them as integers */ + else /* 'f' is either greater or less than all integers */ + return f < 0; /* less? */ + } +} + + +/* +** Check whether float 'f' is less than or equal to integer 'i'. +** See comments on previous function. +*/ +l_sinline int LEfloatint (lua_Number f, lua_Integer i) { + if (l_intfitsf(i)) + return luai_numle(f, cast_num(i)); /* compare them as floats */ + else { /* f <= i <=> ceil(f) <= i */ + lua_Integer fi; + if (luaV_flttointeger(f, &fi, F2Iceil)) /* fi = ceil(f) */ + return fi <= i; /* compare them as integers */ + else /* 'f' is either greater or less than all integers */ + return f < 0; /* less? */ + } +} + + +/* +** Return 'l < r', for numbers. +*/ +l_sinline int LTnum (const TValue *l, const TValue *r) { + lua_assert(ttisnumber(l) && ttisnumber(r)); + if (ttisinteger(l)) { + lua_Integer li = ivalue(l); + if (ttisinteger(r)) + return li < ivalue(r); /* both are integers */ + else /* 'l' is int and 'r' is float */ + return LTintfloat(li, fltvalue(r)); /* l < r ? */ + } + else { + lua_Number lf = fltvalue(l); /* 'l' must be float */ + if (ttisfloat(r)) + return luai_numlt(lf, fltvalue(r)); /* both are float */ + else /* 'l' is float and 'r' is int */ + return LTfloatint(lf, ivalue(r)); + } +} + + +/* +** Return 'l <= r', for numbers. +*/ +l_sinline int LEnum (const TValue *l, const TValue *r) { + lua_assert(ttisnumber(l) && ttisnumber(r)); + if (ttisinteger(l)) { + lua_Integer li = ivalue(l); + if (ttisinteger(r)) + return li <= ivalue(r); /* both are integers */ + else /* 'l' is int and 'r' is float */ + return LEintfloat(li, fltvalue(r)); /* l <= r ? */ + } + else { + lua_Number lf = fltvalue(l); /* 'l' must be float */ + if (ttisfloat(r)) + return luai_numle(lf, fltvalue(r)); /* both are float */ + else /* 'l' is float and 'r' is int */ + return LEfloatint(lf, ivalue(r)); + } +} + + +/* +** return 'l < r' for non-numbers. +*/ +static int lessthanothers (lua_State *L, const TValue *l, const TValue *r) { + lua_assert(!ttisnumber(l) || !ttisnumber(r)); + if (ttisstring(l) && ttisstring(r)) /* both are strings? */ + return l_strcmp(tsvalue(l), tsvalue(r)) < 0; + else + return luaT_callorderTM(L, l, r, TM_LT); +} + + +/* +** Main operation less than; return 'l < r'. +*/ +int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { + if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ + return LTnum(l, r); + else return lessthanothers(L, l, r); +} + + +/* +** return 'l <= r' for non-numbers. +*/ +static int lessequalothers (lua_State *L, const TValue *l, const TValue *r) { + lua_assert(!ttisnumber(l) || !ttisnumber(r)); + if (ttisstring(l) && ttisstring(r)) /* both are strings? */ + return l_strcmp(tsvalue(l), tsvalue(r)) <= 0; + else + return luaT_callorderTM(L, l, r, TM_LE); +} + + +/* +** Main operation less than or equal to; return 'l <= r'. +*/ +int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { + if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ + return LEnum(l, r); + else return lessequalothers(L, l, r); +} + + +/* +** Main operation for equality of Lua values; return 't1 == t2'. +** L == NULL means raw equality (no metamethods) +*/ +int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { + const TValue *tm; + if (ttypetag(t1) != ttypetag(t2)) { /* not the same variant? */ + if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER) + return 0; /* only numbers can be equal with different variants */ + else { /* two numbers with different variants */ + /* One of them is an integer. If the other does not have an + integer value, they cannot be equal; otherwise, compare their + integer values. */ + lua_Integer i1, i2; + return (luaV_tointegerns(t1, &i1, F2Ieq) && + luaV_tointegerns(t2, &i2, F2Ieq) && + i1 == i2); + } + } + /* values have same type and same variant */ + switch (ttypetag(t1)) { + case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: return 1; + case LUA_VNUMINT: return (ivalue(t1) == ivalue(t2)); + case LUA_VNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); + case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_VLCF: return fvalue(t1) == fvalue(t2); + case LUA_VSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); + case LUA_VLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); + case LUA_VUSERDATA: { + if (uvalue(t1) == uvalue(t2)) return 1; + else if (L == NULL) return 0; + tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ + } + case LUA_VTABLE: { + if (hvalue(t1) == hvalue(t2)) return 1; + else if (L == NULL) return 0; + tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ + } + default: + return gcvalue(t1) == gcvalue(t2); + } + if (tm == NULL) /* no TM? */ + return 0; /* objects are different */ + else { + luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */ + return !l_isfalse(s2v(L->top.p)); + } +} + + +/* macro used by 'luaV_concat' to ensure that element at 'o' is a string */ +#define tostring(L,o) \ + (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1))) + +#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0) + +/* copy strings in stack from top - n up to top - 1 to buffer */ +static void copy2buff (StkId top, int n, char *buff) { + size_t tl = 0; /* size already copied */ + do { + size_t l = vslen(s2v(top - n)); /* length of string being copied */ + memcpy(buff + tl, svalue(s2v(top - n)), l * sizeof(char)); + tl += l; + } while (--n > 0); +} + + +/* +** Main operation for concatenation: concat 'total' values in the stack, +** from 'L->top.p - total' up to 'L->top.p - 1'. +*/ +void luaV_concat (lua_State *L, int total) { + if (total == 1) + return; /* "all" values already concatenated */ + do { + StkId top = L->top.p; + int n = 2; /* number of elements handled in this pass (at least 2) */ + if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) || + !tostring(L, s2v(top - 1))) + luaT_tryconcatTM(L); /* may invalidate 'top' */ + else if (isemptystr(s2v(top - 1))) /* second operand is empty? */ + cast_void(tostring(L, s2v(top - 2))); /* result is first operand */ + else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */ + setobjs2s(L, top - 2, top - 1); /* result is second op. */ + } + else { + /* at least two non-empty string values; get as many as possible */ + size_t tl = vslen(s2v(top - 1)); + TString *ts; + /* collect total length and number of strings */ + for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { + size_t l = vslen(s2v(top - n - 1)); + if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) { + L->top.p = top - total; /* pop strings to avoid wasting stack */ + luaG_runerror(L, "string length overflow"); + } + tl += l; + } + if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */ + char buff[LUAI_MAXSHORTLEN]; + copy2buff(top, n, buff); /* copy strings to buffer */ + ts = luaS_newlstr(L, buff, tl); + } + else { /* long string; copy strings directly to final result */ + ts = luaS_createlngstrobj(L, tl); + copy2buff(top, n, getstr(ts)); + } + setsvalue2s(L, top - n, ts); /* create result */ + } + total -= n - 1; /* got 'n' strings to create one new */ + L->top.p -= n - 1; /* popped 'n' strings and pushed one */ + } while (total > 1); /* repeat until only 1 result left */ +} + + +/* +** Main operation 'ra = #rb'. +*/ +void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { + const TValue *tm; + switch (ttypetag(rb)) { + case LUA_VTABLE: { + Table *h = hvalue(rb); + tm = fasttm(L, h->metatable, TM_LEN); + if (tm) break; /* metamethod? break switch to call it */ + setivalue(s2v(ra), luaH_getn(h)); /* else primitive len */ + return; + } + case LUA_VSHRSTR: { + setivalue(s2v(ra), tsvalue(rb)->shrlen); + return; + } + case LUA_VLNGSTR: { + setivalue(s2v(ra), tsvalue(rb)->u.lnglen); + return; + } + default: { /* try metamethod */ + tm = luaT_gettmbyobj(L, rb, TM_LEN); + if (l_unlikely(notm(tm))) /* no metamethod? */ + luaG_typeerror(L, rb, "get length of"); + break; + } + } + luaT_callTMres(L, tm, rb, rb, ra); +} + + +/* +** Integer division; return 'm // n', that is, floor(m/n). +** C division truncates its result (rounds towards zero). +** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer, +** otherwise 'floor(q) == trunc(q) - 1'. +*/ +lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) { + if (l_unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to divide by zero"); + return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ + } + else { + lua_Integer q = m / n; /* perform C division */ + if ((m ^ n) < 0 && m % n != 0) /* 'm/n' would be negative non-integer? */ + q -= 1; /* correct result for different rounding */ + return q; + } +} + + +/* +** Integer modulus; return 'm % n'. (Assume that C '%' with +** negative operands follows C99 behavior. See previous comment +** about luaV_idiv.) +*/ +lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { + if (l_unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to perform 'n%%0'"); + return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ + } + else { + lua_Integer r = m % n; + if (r != 0 && (r ^ n) < 0) /* 'm/n' would be non-integer negative? */ + r += n; /* correct result for different rounding */ + return r; + } +} + + +/* +** Float modulus +*/ +lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) { + lua_Number r; + luai_nummod(L, m, n, r); + return r; +} + + +/* number of bits in an integer */ +#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) + + +/* +** Shift left operation. (Shift right just negates 'y'.) +*/ +lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { + if (y < 0) { /* shift right? */ + if (y <= -NBITS) return 0; + else return intop(>>, x, -y); + } + else { /* shift left */ + if (y >= NBITS) return 0; + else return intop(<<, x, y); + } +} + + +/* +** create a new Lua closure, push it in the stack, and initialize +** its upvalues. +*/ +static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, + StkId ra) { + int nup = p->sizeupvalues; + Upvaldesc *uv = p->upvalues; + int i; + LClosure *ncl = luaF_newLclosure(L, nup); + ncl->p = p; + setclLvalue2s(L, ra, ncl); /* anchor new closure in stack */ + for (i = 0; i < nup; i++) { /* fill in its upvalues */ + if (uv[i].instack) /* upvalue refers to local variable? */ + ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); + else /* get upvalue from enclosing function */ + ncl->upvals[i] = encup[uv[i].idx]; + luaC_objbarrier(L, ncl, ncl->upvals[i]); + } +} + + +/* +** finish execution of an opcode interrupted by a yield +*/ +void luaV_finishOp (lua_State *L) { + CallInfo *ci = L->ci; + StkId base = ci->func.p + 1; + Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ + OpCode op = GET_OPCODE(inst); + switch (op) { /* finish its execution */ + case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: { + setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top.p); + break; + } + case OP_UNM: case OP_BNOT: case OP_LEN: + case OP_GETTABUP: case OP_GETTABLE: case OP_GETI: + case OP_GETFIELD: case OP_SELF: { + setobjs2s(L, base + GETARG_A(inst), --L->top.p); + break; + } + case OP_LT: case OP_LE: + case OP_LTI: case OP_LEI: + case OP_GTI: case OP_GEI: + case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */ + int res = !l_isfalse(s2v(L->top.p - 1)); + L->top.p--; +#if defined(LUA_COMPAT_LT_LE) + if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ + ci->callstatus ^= CIST_LEQ; /* clear mark */ + res = !res; /* negate result */ + } +#endif + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); + if (res != GETARG_k(inst)) /* condition failed? */ + ci->u.l.savedpc++; /* skip jump instruction */ + break; + } + case OP_CONCAT: { + StkId top = L->top.p - 1; /* top when 'luaT_tryconcatTM' was called */ + int a = GETARG_A(inst); /* first element to concatenate */ + int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */ + setobjs2s(L, top - 2, top); /* put TM result in proper position */ + L->top.p = top - 1; /* top is one after last element (at top-2) */ + luaV_concat(L, total); /* concat them (may yield again) */ + break; + } + case OP_CLOSE: { /* yielded closing variables */ + ci->u.l.savedpc--; /* repeat instruction to close other vars. */ + break; + } + case OP_RETURN: { /* yielded closing variables */ + StkId ra = base + GETARG_A(inst); + /* adjust top to signal correct number of returns, in case the + return is "up to top" ('isIT') */ + L->top.p = ra + ci->u2.nres; + /* repeat instruction to close other vars. and complete the return */ + ci->u.l.savedpc--; + break; + } + default: { + /* only these other opcodes can yield */ + lua_assert(op == OP_TFORCALL || op == OP_CALL || + op == OP_TAILCALL || op == OP_SETTABUP || op == OP_SETTABLE || + op == OP_SETI || op == OP_SETFIELD); + break; + } + } +} + + + + +/* +** {================================================================== +** Macros for arithmetic/bitwise/comparison opcodes in 'luaV_execute' +** =================================================================== +*/ + +#define l_addi(L,a,b) intop(+, a, b) +#define l_subi(L,a,b) intop(-, a, b) +#define l_muli(L,a,b) intop(*, a, b) +#define l_band(a,b) intop(&, a, b) +#define l_bor(a,b) intop(|, a, b) +#define l_bxor(a,b) intop(^, a, b) + +#define l_lti(a,b) (a < b) +#define l_lei(a,b) (a <= b) +#define l_gti(a,b) (a > b) +#define l_gei(a,b) (a >= b) + + +/* +** Arithmetic operations with immediate operands. 'iop' is the integer +** operation, 'fop' is the float operation. +*/ +#define op_arithI(L,iop,fop) { \ + StkId ra = RA(i); \ + TValue *v1 = vRB(i); \ + int imm = GETARG_sC(i); \ + if (ttisinteger(v1)) { \ + lua_Integer iv1 = ivalue(v1); \ + pc++; setivalue(s2v(ra), iop(L, iv1, imm)); \ + } \ + else if (ttisfloat(v1)) { \ + lua_Number nb = fltvalue(v1); \ + lua_Number fimm = cast_num(imm); \ + pc++; setfltvalue(s2v(ra), fop(L, nb, fimm)); \ + }} + + +/* +** Auxiliary function for arithmetic operations over floats and others +** with two register operands. +*/ +#define op_arithf_aux(L,v1,v2,fop) { \ + lua_Number n1; lua_Number n2; \ + if (tonumberns(v1, n1) && tonumberns(v2, n2)) { \ + pc++; setfltvalue(s2v(ra), fop(L, n1, n2)); \ + }} + + +/* +** Arithmetic operations over floats and others with register operands. +*/ +#define op_arithf(L,fop) { \ + StkId ra = RA(i); \ + TValue *v1 = vRB(i); \ + TValue *v2 = vRC(i); \ + op_arithf_aux(L, v1, v2, fop); } + + +/* +** Arithmetic operations with K operands for floats. +*/ +#define op_arithfK(L,fop) { \ + StkId ra = RA(i); \ + TValue *v1 = vRB(i); \ + TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ + op_arithf_aux(L, v1, v2, fop); } + + +/* +** Arithmetic operations over integers and floats. +*/ +#define op_arith_aux(L,v1,v2,iop,fop) { \ + StkId ra = RA(i); \ + if (ttisinteger(v1) && ttisinteger(v2)) { \ + lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \ + pc++; setivalue(s2v(ra), iop(L, i1, i2)); \ + } \ + else op_arithf_aux(L, v1, v2, fop); } + + +/* +** Arithmetic operations with register operands. +*/ +#define op_arith(L,iop,fop) { \ + TValue *v1 = vRB(i); \ + TValue *v2 = vRC(i); \ + op_arith_aux(L, v1, v2, iop, fop); } + + +/* +** Arithmetic operations with K operands. +*/ +#define op_arithK(L,iop,fop) { \ + TValue *v1 = vRB(i); \ + TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ + op_arith_aux(L, v1, v2, iop, fop); } + + +/* +** Bitwise operations with constant operand. +*/ +#define op_bitwiseK(L,op) { \ + StkId ra = RA(i); \ + TValue *v1 = vRB(i); \ + TValue *v2 = KC(i); \ + lua_Integer i1; \ + lua_Integer i2 = ivalue(v2); \ + if (tointegerns(v1, &i1)) { \ + pc++; setivalue(s2v(ra), op(i1, i2)); \ + }} + + +/* +** Bitwise operations with register operands. +*/ +#define op_bitwise(L,op) { \ + StkId ra = RA(i); \ + TValue *v1 = vRB(i); \ + TValue *v2 = vRC(i); \ + lua_Integer i1; lua_Integer i2; \ + if (tointegerns(v1, &i1) && tointegerns(v2, &i2)) { \ + pc++; setivalue(s2v(ra), op(i1, i2)); \ + }} + + +/* +** Order operations with register operands. 'opn' actually works +** for all numbers, but the fast track improves performance for +** integers. +*/ +#define op_order(L,opi,opn,other) { \ + StkId ra = RA(i); \ + int cond; \ + TValue *rb = vRB(i); \ + if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \ + lua_Integer ia = ivalue(s2v(ra)); \ + lua_Integer ib = ivalue(rb); \ + cond = opi(ia, ib); \ + } \ + else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \ + cond = opn(s2v(ra), rb); \ + else \ + Protect(cond = other(L, s2v(ra), rb)); \ + docondjump(); } + + +/* +** Order operations with immediate operand. (Immediate operand is +** always small enough to have an exact representation as a float.) +*/ +#define op_orderI(L,opi,opf,inv,tm) { \ + StkId ra = RA(i); \ + int cond; \ + int im = GETARG_sB(i); \ + if (ttisinteger(s2v(ra))) \ + cond = opi(ivalue(s2v(ra)), im); \ + else if (ttisfloat(s2v(ra))) { \ + lua_Number fa = fltvalue(s2v(ra)); \ + lua_Number fim = cast_num(im); \ + cond = opf(fa, fim); \ + } \ + else { \ + int isf = GETARG_C(i); \ + Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \ + } \ + docondjump(); } + +/* }================================================================== */ + + +/* +** {================================================================== +** Function 'luaV_execute': main interpreter loop +** =================================================================== +*/ + +/* +** some macros for common tasks in 'luaV_execute' +*/ + + +#define RA(i) (base+GETARG_A(i)) +#define RB(i) (base+GETARG_B(i)) +#define vRB(i) s2v(RB(i)) +#define KB(i) (k+GETARG_B(i)) +#define RC(i) (base+GETARG_C(i)) +#define vRC(i) s2v(RC(i)) +#define KC(i) (k+GETARG_C(i)) +#define RKC(i) ((TESTARG_k(i)) ? k + GETARG_C(i) : s2v(base + GETARG_C(i))) + + + +#define updatetrap(ci) (trap = ci->u.l.trap) + +#define updatebase(ci) (base = ci->func.p + 1) + + +#define updatestack(ci) \ + { if (l_unlikely(trap)) { updatebase(ci); ra = RA(i); } } + + +/* +** Execute a jump instruction. The 'updatetrap' allows signals to stop +** tight loops. (Without it, the local copy of 'trap' could never change.) +*/ +#define dojump(ci,i,e) { pc += GETARG_sJ(i) + e; updatetrap(ci); } + + +/* for test instructions, execute the jump instruction that follows it */ +#define donextjump(ci) { Instruction ni = *pc; dojump(ci, ni, 1); } + +/* +** do a conditional jump: skip next instruction if 'cond' is not what +** was expected (parameter 'k'), else do next instruction, which must +** be a jump. +*/ +#define docondjump() if (cond != GETARG_k(i)) pc++; else donextjump(ci); + + +/* +** Correct global 'pc'. +*/ +#define savepc(L) (ci->u.l.savedpc = pc) + + +/* +** Whenever code can raise errors, the global 'pc' and the global +** 'top' must be correct to report occasional errors. +*/ +#define savestate(L,ci) (savepc(L), L->top.p = ci->top.p) + + +/* +** Protect code that, in general, can raise errors, reallocate the +** stack, and change the hooks. +*/ +#define Protect(exp) (savestate(L,ci), (exp), updatetrap(ci)) + +/* special version that does not change the top */ +#define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci)) + +/* +** Protect code that can only raise errors. (That is, it cannot change +** the stack or hooks.) +*/ +#define halfProtect(exp) (savestate(L,ci), (exp)) + +/* 'c' is the limit of live values in the stack */ +#define checkGC(L,c) \ + { luaC_condGC(L, (savepc(L), L->top.p = (c)), \ + updatetrap(ci)); \ + luai_threadyield(L); } + + +/* fetch an instruction and prepare its execution */ +#define vmfetch() { \ + if (l_unlikely(trap)) { /* stack reallocation or hooks? */ \ + trap = luaG_traceexec(L, pc); /* handle hooks */ \ + updatebase(ci); /* correct stack */ \ + } \ + i = *(pc++); \ +} + +#define vmdispatch(o) switch(o) +#define vmcase(l) case l: +#define vmbreak break + + +void luaV_execute (lua_State *L, CallInfo *ci) { + LClosure *cl; + TValue *k; + StkId base; + const Instruction *pc; + int trap; +#if LUA_USE_JUMPTABLE +#include "ljumptab.h" +#endif + startfunc: + trap = L->hookmask; + returning: /* trap already set */ + cl = clLvalue(s2v(ci->func.p)); + k = cl->p->k; + pc = ci->u.l.savedpc; + if (l_unlikely(trap)) { + if (pc == cl->p->code) { /* first instruction (not resuming)? */ + if (cl->p->is_vararg) + trap = 0; /* hooks will start after VARARGPREP instruction */ + else /* check 'call' hook */ + luaD_hookcall(L, ci); + } + ci->u.l.trap = 1; /* assume trap is on, for now */ + } + base = ci->func.p + 1; + /* main loop of interpreter */ + for (;;) { + Instruction i; /* instruction being executed */ + vmfetch(); + #if 0 + /* low-level line tracing for debugging Lua */ + printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p))); + #endif + lua_assert(base == ci->func.p + 1); + lua_assert(base <= L->top.p && L->top.p <= L->stack_last.p); + /* invalidate top for instructions not expecting it */ + lua_assert(isIT(i) || (cast_void(L->top.p = base), 1)); + vmdispatch (GET_OPCODE(i)) { + vmcase(OP_MOVE) { + StkId ra = RA(i); + setobjs2s(L, ra, RB(i)); + vmbreak; + } + vmcase(OP_LOADI) { + StkId ra = RA(i); + lua_Integer b = GETARG_sBx(i); + setivalue(s2v(ra), b); + vmbreak; + } + vmcase(OP_LOADF) { + StkId ra = RA(i); + int b = GETARG_sBx(i); + setfltvalue(s2v(ra), cast_num(b)); + vmbreak; + } + vmcase(OP_LOADK) { + StkId ra = RA(i); + TValue *rb = k + GETARG_Bx(i); + setobj2s(L, ra, rb); + vmbreak; + } + vmcase(OP_LOADKX) { + StkId ra = RA(i); + TValue *rb; + rb = k + GETARG_Ax(*pc); pc++; + setobj2s(L, ra, rb); + vmbreak; + } + vmcase(OP_LOADFALSE) { + StkId ra = RA(i); + setbfvalue(s2v(ra)); + vmbreak; + } + vmcase(OP_LFALSESKIP) { + StkId ra = RA(i); + setbfvalue(s2v(ra)); + pc++; /* skip next instruction */ + vmbreak; + } + vmcase(OP_LOADTRUE) { + StkId ra = RA(i); + setbtvalue(s2v(ra)); + vmbreak; + } + vmcase(OP_LOADNIL) { + StkId ra = RA(i); + int b = GETARG_B(i); + do { + setnilvalue(s2v(ra++)); + } while (b--); + vmbreak; + } + vmcase(OP_GETUPVAL) { + StkId ra = RA(i); + int b = GETARG_B(i); + setobj2s(L, ra, cl->upvals[b]->v.p); + vmbreak; + } + vmcase(OP_SETUPVAL) { + StkId ra = RA(i); + UpVal *uv = cl->upvals[GETARG_B(i)]; + setobj(L, uv->v.p, s2v(ra)); + luaC_barrier(L, uv, s2v(ra)); + vmbreak; + } + vmcase(OP_GETTABUP) { + StkId ra = RA(i); + const TValue *slot; + TValue *upval = cl->upvals[GETARG_B(i)]->v.p; + TValue *rc = KC(i); + TString *key = tsvalue(rc); /* key must be a string */ + if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { + setobj2s(L, ra, slot); + } + else + Protect(luaV_finishget(L, upval, rc, ra, slot)); + vmbreak; + } + vmcase(OP_GETTABLE) { + StkId ra = RA(i); + const TValue *slot; + TValue *rb = vRB(i); + TValue *rc = vRC(i); + lua_Unsigned n; + if (ttisinteger(rc) /* fast track for integers? */ + ? (cast_void(n = ivalue(rc)), luaV_fastgeti(L, rb, n, slot)) + : luaV_fastget(L, rb, rc, slot, luaH_get)) { + setobj2s(L, ra, slot); + } + else + Protect(luaV_finishget(L, rb, rc, ra, slot)); + vmbreak; + } + vmcase(OP_GETI) { + StkId ra = RA(i); + const TValue *slot; + TValue *rb = vRB(i); + int c = GETARG_C(i); + if (luaV_fastgeti(L, rb, c, slot)) { + setobj2s(L, ra, slot); + } + else { + TValue key; + setivalue(&key, c); + Protect(luaV_finishget(L, rb, &key, ra, slot)); + } + vmbreak; + } + vmcase(OP_GETFIELD) { + StkId ra = RA(i); + const TValue *slot; + TValue *rb = vRB(i); + TValue *rc = KC(i); + TString *key = tsvalue(rc); /* key must be a string */ + if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) { + setobj2s(L, ra, slot); + } + else + Protect(luaV_finishget(L, rb, rc, ra, slot)); + vmbreak; + } + vmcase(OP_SETTABUP) { + const TValue *slot; + TValue *upval = cl->upvals[GETARG_A(i)]->v.p; + TValue *rb = KB(i); + TValue *rc = RKC(i); + TString *key = tsvalue(rb); /* key must be a string */ + if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { + luaV_finishfastset(L, upval, slot, rc); + } + else + Protect(luaV_finishset(L, upval, rb, rc, slot)); + vmbreak; + } + vmcase(OP_SETTABLE) { + StkId ra = RA(i); + const TValue *slot; + TValue *rb = vRB(i); /* key (table is in 'ra') */ + TValue *rc = RKC(i); /* value */ + lua_Unsigned n; + if (ttisinteger(rb) /* fast track for integers? */ + ? (cast_void(n = ivalue(rb)), luaV_fastgeti(L, s2v(ra), n, slot)) + : luaV_fastget(L, s2v(ra), rb, slot, luaH_get)) { + luaV_finishfastset(L, s2v(ra), slot, rc); + } + else + Protect(luaV_finishset(L, s2v(ra), rb, rc, slot)); + vmbreak; + } + vmcase(OP_SETI) { + StkId ra = RA(i); + const TValue *slot; + int c = GETARG_B(i); + TValue *rc = RKC(i); + if (luaV_fastgeti(L, s2v(ra), c, slot)) { + luaV_finishfastset(L, s2v(ra), slot, rc); + } + else { + TValue key; + setivalue(&key, c); + Protect(luaV_finishset(L, s2v(ra), &key, rc, slot)); + } + vmbreak; + } + vmcase(OP_SETFIELD) { + StkId ra = RA(i); + const TValue *slot; + TValue *rb = KB(i); + TValue *rc = RKC(i); + TString *key = tsvalue(rb); /* key must be a string */ + if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) { + luaV_finishfastset(L, s2v(ra), slot, rc); + } + else + Protect(luaV_finishset(L, s2v(ra), rb, rc, slot)); + vmbreak; + } + vmcase(OP_NEWTABLE) { + StkId ra = RA(i); + int b = GETARG_B(i); /* log2(hash size) + 1 */ + int c = GETARG_C(i); /* array size */ + Table *t; + if (b > 0) + b = 1 << (b - 1); /* size is 2^(b - 1) */ + lua_assert((!TESTARG_k(i)) == (GETARG_Ax(*pc) == 0)); + if (TESTARG_k(i)) /* non-zero extra argument? */ + c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */ + pc++; /* skip extra argument */ + L->top.p = ra + 1; /* correct top in case of emergency GC */ + t = luaH_new(L); /* memory allocation */ + sethvalue2s(L, ra, t); + if (b != 0 || c != 0) + luaH_resize(L, t, c, b); /* idem */ + checkGC(L, ra + 1); + vmbreak; + } + vmcase(OP_SELF) { + StkId ra = RA(i); + const TValue *slot; + TValue *rb = vRB(i); + TValue *rc = RKC(i); + TString *key = tsvalue(rc); /* key must be a string */ + setobj2s(L, ra + 1, rb); + if (luaV_fastget(L, rb, key, slot, luaH_getstr)) { + setobj2s(L, ra, slot); + } + else + Protect(luaV_finishget(L, rb, rc, ra, slot)); + vmbreak; + } + vmcase(OP_ADDI) { + op_arithI(L, l_addi, luai_numadd); + vmbreak; + } + vmcase(OP_ADDK) { + op_arithK(L, l_addi, luai_numadd); + vmbreak; + } + vmcase(OP_SUBK) { + op_arithK(L, l_subi, luai_numsub); + vmbreak; + } + vmcase(OP_MULK) { + op_arithK(L, l_muli, luai_nummul); + vmbreak; + } + vmcase(OP_MODK) { + savestate(L, ci); /* in case of division by 0 */ + op_arithK(L, luaV_mod, luaV_modf); + vmbreak; + } + vmcase(OP_POWK) { + op_arithfK(L, luai_numpow); + vmbreak; + } + vmcase(OP_DIVK) { + op_arithfK(L, luai_numdiv); + vmbreak; + } + vmcase(OP_IDIVK) { + savestate(L, ci); /* in case of division by 0 */ + op_arithK(L, luaV_idiv, luai_numidiv); + vmbreak; + } + vmcase(OP_BANDK) { + op_bitwiseK(L, l_band); + vmbreak; + } + vmcase(OP_BORK) { + op_bitwiseK(L, l_bor); + vmbreak; + } + vmcase(OP_BXORK) { + op_bitwiseK(L, l_bxor); + vmbreak; + } + vmcase(OP_SHRI) { + StkId ra = RA(i); + TValue *rb = vRB(i); + int ic = GETARG_sC(i); + lua_Integer ib; + if (tointegerns(rb, &ib)) { + pc++; setivalue(s2v(ra), luaV_shiftl(ib, -ic)); + } + vmbreak; + } + vmcase(OP_SHLI) { + StkId ra = RA(i); + TValue *rb = vRB(i); + int ic = GETARG_sC(i); + lua_Integer ib; + if (tointegerns(rb, &ib)) { + pc++; setivalue(s2v(ra), luaV_shiftl(ic, ib)); + } + vmbreak; + } + vmcase(OP_ADD) { + op_arith(L, l_addi, luai_numadd); + vmbreak; + } + vmcase(OP_SUB) { + op_arith(L, l_subi, luai_numsub); + vmbreak; + } + vmcase(OP_MUL) { + op_arith(L, l_muli, luai_nummul); + vmbreak; + } + vmcase(OP_MOD) { + savestate(L, ci); /* in case of division by 0 */ + op_arith(L, luaV_mod, luaV_modf); + vmbreak; + } + vmcase(OP_POW) { + op_arithf(L, luai_numpow); + vmbreak; + } + vmcase(OP_DIV) { /* float division (always with floats) */ + op_arithf(L, luai_numdiv); + vmbreak; + } + vmcase(OP_IDIV) { /* floor division */ + savestate(L, ci); /* in case of division by 0 */ + op_arith(L, luaV_idiv, luai_numidiv); + vmbreak; + } + vmcase(OP_BAND) { + op_bitwise(L, l_band); + vmbreak; + } + vmcase(OP_BOR) { + op_bitwise(L, l_bor); + vmbreak; + } + vmcase(OP_BXOR) { + op_bitwise(L, l_bxor); + vmbreak; + } + vmcase(OP_SHR) { + op_bitwise(L, luaV_shiftr); + vmbreak; + } + vmcase(OP_SHL) { + op_bitwise(L, luaV_shiftl); + vmbreak; + } + vmcase(OP_MMBIN) { + StkId ra = RA(i); + Instruction pi = *(pc - 2); /* original arith. expression */ + TValue *rb = vRB(i); + TMS tm = (TMS)GETARG_C(i); + StkId result = RA(pi); + lua_assert(OP_ADD <= GET_OPCODE(pi) && GET_OPCODE(pi) <= OP_SHR); + Protect(luaT_trybinTM(L, s2v(ra), rb, result, tm)); + vmbreak; + } + vmcase(OP_MMBINI) { + StkId ra = RA(i); + Instruction pi = *(pc - 2); /* original arith. expression */ + int imm = GETARG_sB(i); + TMS tm = (TMS)GETARG_C(i); + int flip = GETARG_k(i); + StkId result = RA(pi); + Protect(luaT_trybiniTM(L, s2v(ra), imm, flip, result, tm)); + vmbreak; + } + vmcase(OP_MMBINK) { + StkId ra = RA(i); + Instruction pi = *(pc - 2); /* original arith. expression */ + TValue *imm = KB(i); + TMS tm = (TMS)GETARG_C(i); + int flip = GETARG_k(i); + StkId result = RA(pi); + Protect(luaT_trybinassocTM(L, s2v(ra), imm, flip, result, tm)); + vmbreak; + } + vmcase(OP_UNM) { + StkId ra = RA(i); + TValue *rb = vRB(i); + lua_Number nb; + if (ttisinteger(rb)) { + lua_Integer ib = ivalue(rb); + setivalue(s2v(ra), intop(-, 0, ib)); + } + else if (tonumberns(rb, nb)) { + setfltvalue(s2v(ra), luai_numunm(L, nb)); + } + else + Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM)); + vmbreak; + } + vmcase(OP_BNOT) { + StkId ra = RA(i); + TValue *rb = vRB(i); + lua_Integer ib; + if (tointegerns(rb, &ib)) { + setivalue(s2v(ra), intop(^, ~l_castS2U(0), ib)); + } + else + Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT)); + vmbreak; + } + vmcase(OP_NOT) { + StkId ra = RA(i); + TValue *rb = vRB(i); + if (l_isfalse(rb)) + setbtvalue(s2v(ra)); + else + setbfvalue(s2v(ra)); + vmbreak; + } + vmcase(OP_LEN) { + StkId ra = RA(i); + Protect(luaV_objlen(L, ra, vRB(i))); + vmbreak; + } + vmcase(OP_CONCAT) { + StkId ra = RA(i); + int n = GETARG_B(i); /* number of elements to concatenate */ + L->top.p = ra + n; /* mark the end of concat operands */ + ProtectNT(luaV_concat(L, n)); + checkGC(L, L->top.p); /* 'luaV_concat' ensures correct top */ + vmbreak; + } + vmcase(OP_CLOSE) { + StkId ra = RA(i); + Protect(luaF_close(L, ra, LUA_OK, 1)); + vmbreak; + } + vmcase(OP_TBC) { + StkId ra = RA(i); + /* create new to-be-closed upvalue */ + halfProtect(luaF_newtbcupval(L, ra)); + vmbreak; + } + vmcase(OP_JMP) { + dojump(ci, i, 0); + vmbreak; + } + vmcase(OP_EQ) { + StkId ra = RA(i); + int cond; + TValue *rb = vRB(i); + Protect(cond = luaV_equalobj(L, s2v(ra), rb)); + docondjump(); + vmbreak; + } + vmcase(OP_LT) { + op_order(L, l_lti, LTnum, lessthanothers); + vmbreak; + } + vmcase(OP_LE) { + op_order(L, l_lei, LEnum, lessequalothers); + vmbreak; + } + vmcase(OP_EQK) { + StkId ra = RA(i); + TValue *rb = KB(i); + /* basic types do not use '__eq'; we can use raw equality */ + int cond = luaV_rawequalobj(s2v(ra), rb); + docondjump(); + vmbreak; + } + vmcase(OP_EQI) { + StkId ra = RA(i); + int cond; + int im = GETARG_sB(i); + if (ttisinteger(s2v(ra))) + cond = (ivalue(s2v(ra)) == im); + else if (ttisfloat(s2v(ra))) + cond = luai_numeq(fltvalue(s2v(ra)), cast_num(im)); + else + cond = 0; /* other types cannot be equal to a number */ + docondjump(); + vmbreak; + } + vmcase(OP_LTI) { + op_orderI(L, l_lti, luai_numlt, 0, TM_LT); + vmbreak; + } + vmcase(OP_LEI) { + op_orderI(L, l_lei, luai_numle, 0, TM_LE); + vmbreak; + } + vmcase(OP_GTI) { + op_orderI(L, l_gti, luai_numgt, 1, TM_LT); + vmbreak; + } + vmcase(OP_GEI) { + op_orderI(L, l_gei, luai_numge, 1, TM_LE); + vmbreak; + } + vmcase(OP_TEST) { + StkId ra = RA(i); + int cond = !l_isfalse(s2v(ra)); + docondjump(); + vmbreak; + } + vmcase(OP_TESTSET) { + StkId ra = RA(i); + TValue *rb = vRB(i); + if (l_isfalse(rb) == GETARG_k(i)) + pc++; + else { + setobj2s(L, ra, rb); + donextjump(ci); + } + vmbreak; + } + vmcase(OP_CALL) { + StkId ra = RA(i); + CallInfo *newci; + int b = GETARG_B(i); + int nresults = GETARG_C(i) - 1; + if (b != 0) /* fixed number of arguments? */ + L->top.p = ra + b; /* top signals number of arguments */ + /* else previous instruction set top */ + savepc(L); /* in case of errors */ + if ((newci = luaD_precall(L, ra, nresults)) == NULL) + updatetrap(ci); /* C call; nothing else to be done */ + else { /* Lua call: run function in this same C frame */ + ci = newci; + goto startfunc; + } + vmbreak; + } + vmcase(OP_TAILCALL) { + StkId ra = RA(i); + int b = GETARG_B(i); /* number of arguments + 1 (function) */ + int n; /* number of results when calling a C function */ + int nparams1 = GETARG_C(i); + /* delta is virtual 'func' - real 'func' (vararg functions) */ + int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0; + if (b != 0) + L->top.p = ra + b; + else /* previous instruction set top */ + b = cast_int(L->top.p - ra); + savepc(ci); /* several calls here can raise errors */ + if (TESTARG_k(i)) { + luaF_closeupval(L, base); /* close upvalues from current call */ + lua_assert(L->tbclist.p < base); /* no pending tbc variables */ + lua_assert(base == ci->func.p + 1); + } + if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */ + goto startfunc; /* execute the callee */ + else { /* C function? */ + ci->func.p -= delta; /* restore 'func' (if vararg) */ + luaD_poscall(L, ci, n); /* finish caller */ + updatetrap(ci); /* 'luaD_poscall' can change hooks */ + goto ret; /* caller returns after the tail call */ + } + } + vmcase(OP_RETURN) { + StkId ra = RA(i); + int n = GETARG_B(i) - 1; /* number of results */ + int nparams1 = GETARG_C(i); + if (n < 0) /* not fixed? */ + n = cast_int(L->top.p - ra); /* get what is available */ + savepc(ci); + if (TESTARG_k(i)) { /* may there be open upvalues? */ + ci->u2.nres = n; /* save number of returns */ + if (L->top.p < ci->top.p) + L->top.p = ci->top.p; + luaF_close(L, base, CLOSEKTOP, 1); + updatetrap(ci); + updatestack(ci); + } + if (nparams1) /* vararg function? */ + ci->func.p -= ci->u.l.nextraargs + nparams1; + L->top.p = ra + n; /* set call for 'luaD_poscall' */ + luaD_poscall(L, ci, n); + updatetrap(ci); /* 'luaD_poscall' can change hooks */ + goto ret; + } + vmcase(OP_RETURN0) { + if (l_unlikely(L->hookmask)) { + StkId ra = RA(i); + L->top.p = ra; + savepc(ci); + luaD_poscall(L, ci, 0); /* no hurry... */ + trap = 1; + } + else { /* do the 'poscall' here */ + int nres; + L->ci = ci->previous; /* back to caller */ + L->top.p = base - 1; + for (nres = ci->nresults; l_unlikely(nres > 0); nres--) + setnilvalue(s2v(L->top.p++)); /* all results are nil */ + } + goto ret; + } + vmcase(OP_RETURN1) { + if (l_unlikely(L->hookmask)) { + StkId ra = RA(i); + L->top.p = ra + 1; + savepc(ci); + luaD_poscall(L, ci, 1); /* no hurry... */ + trap = 1; + } + else { /* do the 'poscall' here */ + int nres = ci->nresults; + L->ci = ci->previous; /* back to caller */ + if (nres == 0) + L->top.p = base - 1; /* asked for no results */ + else { + StkId ra = RA(i); + setobjs2s(L, base - 1, ra); /* at least this result */ + L->top.p = base; + for (; l_unlikely(nres > 1); nres--) + setnilvalue(s2v(L->top.p++)); /* complete missing results */ + } + } + ret: /* return from a Lua function */ + if (ci->callstatus & CIST_FRESH) + return; /* end this frame */ + else { + ci = ci->previous; + goto returning; /* continue running caller in this frame */ + } + } + vmcase(OP_FORLOOP) { + StkId ra = RA(i); + if (ttisinteger(s2v(ra + 2))) { /* integer loop? */ + lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1))); + if (count > 0) { /* still more iterations? */ + lua_Integer step = ivalue(s2v(ra + 2)); + lua_Integer idx = ivalue(s2v(ra)); /* internal index */ + chgivalue(s2v(ra + 1), count - 1); /* update counter */ + idx = intop(+, idx, step); /* add step to index */ + chgivalue(s2v(ra), idx); /* update internal index */ + setivalue(s2v(ra + 3), idx); /* and control variable */ + pc -= GETARG_Bx(i); /* jump back */ + } + } + else if (floatforloop(ra)) /* float loop */ + pc -= GETARG_Bx(i); /* jump back */ + updatetrap(ci); /* allows a signal to break the loop */ + vmbreak; + } + vmcase(OP_FORPREP) { + StkId ra = RA(i); + savestate(L, ci); /* in case of errors */ + if (forprep(L, ra)) + pc += GETARG_Bx(i) + 1; /* skip the loop */ + vmbreak; + } + vmcase(OP_TFORPREP) { + StkId ra = RA(i); + /* create to-be-closed upvalue (if needed) */ + halfProtect(luaF_newtbcupval(L, ra + 3)); + pc += GETARG_Bx(i); + i = *(pc++); /* go to next instruction */ + lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i)); + goto l_tforcall; + } + vmcase(OP_TFORCALL) { + l_tforcall: { + StkId ra = RA(i); + /* 'ra' has the iterator function, 'ra + 1' has the state, + 'ra + 2' has the control variable, and 'ra + 3' has the + to-be-closed variable. The call will use the stack after + these values (starting at 'ra + 4') + */ + /* push function, state, and control variable */ + memcpy(ra + 4, ra, 3 * sizeof(*ra)); + L->top.p = ra + 4 + 3; + ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */ + updatestack(ci); /* stack may have changed */ + i = *(pc++); /* go to next instruction */ + lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i)); + goto l_tforloop; + }} + vmcase(OP_TFORLOOP) { + l_tforloop: { + StkId ra = RA(i); + if (!ttisnil(s2v(ra + 4))) { /* continue loop? */ + setobjs2s(L, ra + 2, ra + 4); /* save control variable */ + pc -= GETARG_Bx(i); /* jump back */ + } + vmbreak; + }} + vmcase(OP_SETLIST) { + StkId ra = RA(i); + int n = GETARG_B(i); + unsigned int last = GETARG_C(i); + Table *h = hvalue(s2v(ra)); + if (n == 0) + n = cast_int(L->top.p - ra) - 1; /* get up to the top */ + else + L->top.p = ci->top.p; /* correct top in case of emergency GC */ + last += n; + if (TESTARG_k(i)) { + last += GETARG_Ax(*pc) * (MAXARG_C + 1); + pc++; + } + if (last > luaH_realasize(h)) /* needs more space? */ + luaH_resizearray(L, h, last); /* preallocate it at once */ + for (; n > 0; n--) { + TValue *val = s2v(ra + n); + setobj2t(L, &h->array[last - 1], val); + last--; + luaC_barrierback(L, obj2gco(h), val); + } + vmbreak; + } + vmcase(OP_CLOSURE) { + StkId ra = RA(i); + Proto *p = cl->p->p[GETARG_Bx(i)]; + halfProtect(pushclosure(L, p, cl->upvals, base, ra)); + checkGC(L, ra + 1); + vmbreak; + } + vmcase(OP_VARARG) { + StkId ra = RA(i); + int n = GETARG_C(i) - 1; /* required results */ + Protect(luaT_getvarargs(L, ci, ra, n)); + vmbreak; + } + vmcase(OP_VARARGPREP) { + ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p)); + if (l_unlikely(trap)) { /* previous "Protect" updated trap */ + luaD_hookcall(L, ci); + L->oldpc = 1; /* next opcode will be seen as a "new" line */ + } + updatebase(ci); /* function has new base after adjustment */ + vmbreak; + } + vmcase(OP_EXTRAARG) { + lua_assert(0); + vmbreak; + } + } + } +} + +/* }================================================================== */ diff --git a/vendor/lua-src/lua-5.4.6/lvm.h b/vendor/lua-src/lua-5.4.6/lvm.h new file mode 100644 index 0000000000000..dba1ad277025e --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lvm.h @@ -0,0 +1,141 @@ +/* +** $Id: lvm.h $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lvm_h +#define lvm_h + + +#include "ldo.h" +#include "lobject.h" +#include "ltm.h" + + +#if !defined(LUA_NOCVTN2S) +#define cvt2str(o) ttisnumber(o) +#else +#define cvt2str(o) 0 /* no conversion from numbers to strings */ +#endif + + +#if !defined(LUA_NOCVTS2N) +#define cvt2num(o) ttisstring(o) +#else +#define cvt2num(o) 0 /* no conversion from strings to numbers */ +#endif + + +/* +** You can define LUA_FLOORN2I if you want to convert floats to integers +** by flooring them (instead of raising an error if they are not +** integral values) +*/ +#if !defined(LUA_FLOORN2I) +#define LUA_FLOORN2I F2Ieq +#endif + + +/* +** Rounding modes for float->integer coercion + */ +typedef enum { + F2Ieq, /* no rounding; accepts only integral values */ + F2Ifloor, /* takes the floor of the number */ + F2Iceil /* takes the ceil of the number */ +} F2Imod; + + +/* convert an object to a float (including string coercion) */ +#define tonumber(o,n) \ + (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n)) + + +/* convert an object to a float (without string coercion) */ +#define tonumberns(o,n) \ + (ttisfloat(o) ? ((n) = fltvalue(o), 1) : \ + (ttisinteger(o) ? ((n) = cast_num(ivalue(o)), 1) : 0)) + + +/* convert an object to an integer (including string coercion) */ +#define tointeger(o,i) \ + (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \ + : luaV_tointeger(o,i,LUA_FLOORN2I)) + + +/* convert an object to an integer (without string coercion) */ +#define tointegerns(o,i) \ + (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \ + : luaV_tointegerns(o,i,LUA_FLOORN2I)) + + +#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) + +#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2) + + +/* +** fast track for 'gettable': if 't' is a table and 't[k]' is present, +** return 1 with 'slot' pointing to 't[k]' (position of final result). +** Otherwise, return 0 (meaning it will have to check metamethod) +** with 'slot' pointing to an empty 't[k]' (if 't' is a table) or NULL +** (otherwise). 'f' is the raw get function to use. +*/ +#define luaV_fastget(L,t,k,slot,f) \ + (!ttistable(t) \ + ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ + : (slot = f(hvalue(t), k), /* else, do raw access */ \ + !isempty(slot))) /* result not empty? */ + + +/* +** Special case of 'luaV_fastget' for integers, inlining the fast case +** of 'luaH_getint'. +*/ +#define luaV_fastgeti(L,t,k,slot) \ + (!ttistable(t) \ + ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ + : (slot = (l_castS2U(k) - 1u < hvalue(t)->alimit) \ + ? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \ + !isempty(slot))) /* result not empty? */ + + +/* +** Finish a fast set operation (when fast get succeeds). In that case, +** 'slot' points to the place to put the value. +*/ +#define luaV_finishfastset(L,t,slot,v) \ + { setobj2t(L, cast(TValue *,slot), v); \ + luaC_barrierback(L, gcvalue(t), v); } + + +/* +** Shift right is the same as shift left with a negative 'y' +*/ +#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y)) + + + +LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); +LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); +LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); +LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); +LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode); +LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p, + F2Imod mode); +LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode); +LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *slot); +LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + TValue *val, const TValue *slot); +LUAI_FUNC void luaV_finishOp (lua_State *L); +LUAI_FUNC void luaV_execute (lua_State *L, CallInfo *ci); +LUAI_FUNC void luaV_concat (lua_State *L, int total); +LUAI_FUNC lua_Integer luaV_idiv (lua_State *L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Number luaV_modf (lua_State *L, lua_Number x, lua_Number y); +LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); +LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); + +#endif diff --git a/vendor/lua-src/lua-5.4.6/lzio.c b/vendor/lua-src/lua-5.4.6/lzio.c new file mode 100644 index 0000000000000..cd0a02d5f9b91 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lzio.c @@ -0,0 +1,68 @@ +/* +** $Id: lzio.c $ +** Buffered streams +** See Copyright Notice in lua.h +*/ + +#define lzio_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "llimits.h" +#include "lmem.h" +#include "lstate.h" +#include "lzio.h" + + +int luaZ_fill (ZIO *z) { + size_t size; + lua_State *L = z->L; + const char *buff; + lua_unlock(L); + buff = z->reader(L, z->data, &size); + lua_lock(L); + if (buff == NULL || size == 0) + return EOZ; + z->n = size - 1; /* discount char being returned */ + z->p = buff; + return cast_uchar(*(z->p++)); +} + + +void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { + z->L = L; + z->reader = reader; + z->data = data; + z->n = 0; + z->p = NULL; +} + + +/* --------------------------------------------------------------- read --- */ +size_t luaZ_read (ZIO *z, void *b, size_t n) { + while (n) { + size_t m; + if (z->n == 0) { /* no bytes in buffer? */ + if (luaZ_fill(z) == EOZ) /* try to read more */ + return n; /* no more input; return number of missing bytes */ + else { + z->n++; /* luaZ_fill consumed first byte; put it back */ + z->p--; + } + } + m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ + memcpy(b, z->p, m); + z->n -= m; + z->p += m; + b = (char *)b + m; + n -= m; + } + return 0; +} + diff --git a/vendor/lua-src/lua-5.4.6/lzio.h b/vendor/lua-src/lua-5.4.6/lzio.h new file mode 100644 index 0000000000000..38f397fd284e8 --- /dev/null +++ b/vendor/lua-src/lua-5.4.6/lzio.h @@ -0,0 +1,66 @@ +/* +** $Id: lzio.h $ +** Buffered streams +** See Copyright Notice in lua.h +*/ + + +#ifndef lzio_h +#define lzio_h + +#include "lua.h" + +#include "lmem.h" + + +#define EOZ (-1) /* end of stream */ + +typedef struct Zio ZIO; + +#define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) + + +typedef struct Mbuffer { + char *buffer; + size_t n; + size_t buffsize; +} Mbuffer; + +#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) + +#define luaZ_buffer(buff) ((buff)->buffer) +#define luaZ_sizebuffer(buff) ((buff)->buffsize) +#define luaZ_bufflen(buff) ((buff)->n) + +#define luaZ_buffremove(buff,i) ((buff)->n -= (i)) +#define luaZ_resetbuffer(buff) ((buff)->n = 0) + + +#define luaZ_resizebuffer(L, buff, size) \ + ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \ + (buff)->buffsize, size), \ + (buff)->buffsize = size) + +#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) + + +LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, + void *data); +LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ + + + +/* --------- Private Part ------------------ */ + +struct Zio { + size_t n; /* bytes still unread */ + const char *p; /* current position in buffer */ + lua_Reader reader; /* reader function */ + void *data; /* additional data */ + lua_State *L; /* Lua state (for reader) */ +}; + + +LUAI_FUNC int luaZ_fill (ZIO *z); + +#endif diff --git a/vendor/mach2/.cargo-checksum.json b/vendor/mach2/.cargo-checksum.json new file mode 100644 index 0000000000000..1e9ae12f0588f --- /dev/null +++ b/vendor/mach2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"e6cb1c9aa2b65d61801e0f03de848525a9f7104234db25d0b1c9fa337b372626","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-BSD":"044983df14c97f2f9570766aaf977b3cdfc4a06cf1f36b776331c5ff89b4fb89","LICENSE-MIT":"3f9f0f7e5a5911a8042e32c83ff5d061ce1ffd02e8a207ec2135a44ad73b4191","README.md":"c2cb79f8e79e22b13e4c25e43829bf578ef25a3a338d5553081a1e5f39556fa8","src/boolean.rs":"1d24ea9872748881cd7269a383a7c344e3a650df23f0e44e3b6c266fb8205d9a","src/bootstrap.rs":"a5ab69d74ad8bfb8fad1cb45c8c571977c0bf907a70e767309a437580cee184c","src/clock.rs":"a33c1bfb2f174abb695d164c469ee744be52fec4bc345656e6027d063e150d71","src/clock_priv.rs":"a8e6a96896a94eda67c9fb6e45c564581a711cc9fdcf7674251bb6c0c28b47c2","src/clock_reply.rs":"bac04b6602dcdd4daac8e3a0a1e56fa4b6de20cf2c3fe7bb583358166aca8a3b","src/clock_types.rs":"d55d1d2a953e477f9dd064bd684b118235aa7bd79de85cdeaf75e21510aaaefa","src/dyld_kernel.rs":"566a17f597aa29619a1ce15f6b22577fc70ac5356f96e00fddbcb28560a5c83c","src/exc.rs":"2246493bef2c596b92f115ab673a10d50c6003d11abb8e73d7707ebc19e8ae5a","src/exception_types.rs":"c7894831d73145adb1a4b5d2a5d0b346f2b2dc05382b97f2f3f0275d337f6dfc","src/kern_return.rs":"153339995674136ef05d9595bdcf831595db0d0714a737ecd1ccd45391c56657","src/lib.rs":"4c8a9d906303a67246b32b6f96228bff6b045deb0a68073a7f8d1061c8d072bd","src/mach_init.rs":"df49bd287fd05fb74bc76254df7607fad0d6b90cb20da803e9f9a1dc2fcfe2fc","src/mach_port.rs":"d71ef4f4875824410d2d829474303926a56e3218a00fbe04024801a3245b67ad","src/mach_time.rs":"b9493e820acf21fee1f6e7e82a510d887925dc1117d6b71b681acc40cfa776af","src/mach_types.rs":"e2d17741ebcdcdff9686ec9ee5c90fb7a150ce990979507da01c351771fb3a19","src/memory_object_types.rs":"6fcb446c00ddd5ef4920efe618bd89df2e87f7ae3cf660a2bc1d25cf1f331dc2","src/message.rs":"126dfcdef0f690cd17f4403528403721b81f7e6a95821eff867d11dd6bfa9718","src/port.rs":"7ef8af905edd7d0de9c11813d6cf56ae82171e85efdde2c986622be0e7debf6f","src/structs.rs":"132e21e91313e6ec13e3ad5ed9c71852e8a55fbbaba449dbb1b3ca889bed4889","src/task.rs":"282ea602db2d08711785e0050a06b322a3fe4a4aac34b3c9116fe13e033898dd","src/task_info.rs":"cf87cffe567fee8871e0ce9762b7d8bbd5058dfbb309678d382149dedbe7f14a","src/thread_act.rs":"647198e0f9e3fe409a0610ee98560de3af4f152bcc4761f943e67723193b8a25","src/thread_policy.rs":"e8999b03a03d398a456056274ed8ebc4c38a1cbbbba2da931503885da0e9c2e3","src/thread_status.rs":"3fe98fadd61ce01b4f9dc3bc0ef8c9496798f0147822a4ddffe5d0eaf2f32c0a","src/traps.rs":"59a65e0cc3cf67d79180eabfe31248287afa7a2daa58ec367ebb6302ff39f4cb","src/vm.rs":"1e3fe55704dbbc0c287ad543f5642389a823539f72b337cbff726d6927566b23","src/vm_attributes.rs":"7f73f41572d1ca854b45199a17e9008197f3898cfe6a82dba6d14293d49269c6","src/vm_behavior.rs":"a5d195a52602f5ebe2991774c2390a6f20f1bfa82168dd62e88f2804134da1f3","src/vm_inherit.rs":"dbc7432350869733d6e7cf1da8617d97aafbeb1afcb1bdc60ed7ab53e37abf61","src/vm_page_size.rs":"1cd209f8f6fbc4d3b7a44b77f5a3c53c578f357199e3c616b2386a63e5bfe70a","src/vm_prot.rs":"65e5f7179e155c600cec1a1b3e030f2d0d6b446a6ec9ebad0d04f56ccd884a86","src/vm_purgable.rs":"e32963f20905c4edd1cfee364ad489ef646ad7d401967d0ed9e1e7ed6cd57e5d","src/vm_region.rs":"905daa12391c0c3bca9200ceaecbd02dd03550bbdc9c3342dceeeb6e4056184f","src/vm_statistics.rs":"abee2c810b13fa007a7e38dd2b3d6460005e9e78f5972e069d7fc3e0df80190e","src/vm_sync.rs":"e6006b66f0fa1a06c5e853d765a9366aab85009cc77a095b93f902330cf4ec81","src/vm_types.rs":"a47f71193172ce233018dfd40de2b9a56cdfcdfb18e04c1c0761cb6fc36f51b8"},"package":"6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8"} \ No newline at end of file diff --git a/vendor/mach2/Cargo.toml b/vendor/mach2/Cargo.toml new file mode 100644 index 0000000000000..422e53094c614 --- /dev/null +++ b/vendor/mach2/Cargo.toml @@ -0,0 +1,49 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2015" +name = "mach2" +version = "0.4.1" +include = [ + "src/**/*", + "LICENSE-*", + "README.md", +] +description = "A Rust interface to the user-space API of the Mach 3.0 kernel that underlies OSX." +readme = "README.md" +keywords = [ + "kernel", + "macos", + "darwin", +] +categories = [ + "api-bindings", + "external-ffi-bindings", + "no-std", + "os", +] +license = "BSD-2-Clause OR MIT OR Apache-2.0" +repository = "https://github.com/JohnTitor/mach2" + +[package.metadata.docs.rs] +default-target = "x86_64-apple-darwin" + +[features] +default = [] +unstable = [] + +[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.libc] +version = "0.2" +default-features = false + +[badges.maintenance] +status = "passively-maintained" diff --git a/vendor/mach2/LICENSE-APACHE b/vendor/mach2/LICENSE-APACHE new file mode 100644 index 0000000000000..1b5ec8b78e237 --- /dev/null +++ b/vendor/mach2/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/vendor/mach2/LICENSE-BSD b/vendor/mach2/LICENSE-BSD new file mode 100644 index 0000000000000..e02a2d2cfc622 --- /dev/null +++ b/vendor/mach2/LICENSE-BSD @@ -0,0 +1,23 @@ +Copyright (c) 2019 Nick Fitzgerald, 2021 Yuki Okushi +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/mach2/LICENSE-MIT b/vendor/mach2/LICENSE-MIT new file mode 100644 index 0000000000000..08bda86c65f73 --- /dev/null +++ b/vendor/mach2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2019 Nick Fitzgerald, 2021 Yuki Okushi + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/mach2/README.md b/vendor/mach2/README.md new file mode 100644 index 0000000000000..f297ebe6330f2 --- /dev/null +++ b/vendor/mach2/README.md @@ -0,0 +1,92 @@ +# mach2 + +[![Latest Version]][crates.io] [![docs]][docs.rs] + +A Rust interface to the **user-space** API of the Mach 3.0 kernel exposed in +`/usr/include/mach` that underlies macOS and is linked via `libSystem` (and +`libsystem_kernel`). + +This library does not expose the **kernel-space** API of the Mach 3.0 kernel +exposed in +`SDK/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/mach`. + +That is, if you are writing a kernel-resident device drivers or some other +kernel extensions you have to use something else. The user-space kernel API is +often API-incompatible with the kernel space one, and even in the cases where +they match, they are sometimes ABI incompatible such that using this library +would have **undefined behavior**. + +## Usage + +Add the following to your `Cargo.toml` to conditionally include mach on those +platforms that support it. + +```toml +[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.mach] +version = "0.4" +``` + +Available crate feature: + +* **unstable** (disabled by default): Exposes newly changed APIs. Enabling this may + bring breaking changes (see the breaking change policy). + + +### Breaking change policy + +We do the following steps when an item is changed/removed on latest toolchain: + +1. Deprecate an existing one +2. Declare a new one under the `unstable` feature +3. After a month or more since releasing a new version that contains that change, + remove/change an older one + +For instance, if const `FOO` value is changed from `3` to `4`, +we expose the newer one, i.e. `4`, under `unstable` first. +So the `unstable` users should notice the change on the first release since deprecating. +After a month or more, all the users should notice it. + +## Platform support + +The following table describes the current CI set-up: + +| Target | Min. Rust | XCode | build | ctest | run | +|-------------------------|-----------|-----------------|-------|-------|-----| +| `x86_64-apple-darwin` | 1.33.0 | 10.3.0 - 13.1.0 | ✓ | ✓ | ✓ | +| `aarch64-apple-darwin` | nightly | 13.1.0 | ✓ | - | - | +| `aarch64-apple-ios` | nightly | 13.1.0 | ✓ | - | - | +| `aarch64-apple-ios-sim` | nightly | 13.1.0 | ✓ | - | - | +| `x86_64-apple-ios` | nightly | 13.1.0 | ✓ | - | - | + +## License + +This project is licensed under either of + +* A 2-clause BSD License ([LICENSE-BSD](LICENSE-BSD)), or +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +## Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `mach` by you, as defined in the Apache-2.0 license, shall be +triple licensed as above, without any additional terms or conditions. + +To locally test the library, run: + +``` +TARGET=x86_64-apple-darwin RUST_VERSION=nightly ./ci/run.sh +``` + +where you can replace the `TARGET` and `RUST_VERSION` with the target you +want to test (e.g. `aarch64-apple-darwin`) and the Rust version you want to use for +the tests (e.g. `stable`, `1.33.0`, etc.). + +[crates.io]: https://crates.io/crates/mach2 +[Latest Version]: https://img.shields.io/crates/v/mach2.svg +[docs]: https://docs.rs/mach2/badge.svg +[docs.rs]: https://docs.rs/mach2 diff --git a/vendor/mach2/src/boolean.rs b/vendor/mach2/src/boolean.rs new file mode 100644 index 0000000000000..cedffa1220290 --- /dev/null +++ b/vendor/mach2/src/boolean.rs @@ -0,0 +1,7 @@ +//! This module corresponds to `mach/i386/boolean.h`. + +#[cfg(target_arch = "x86_64")] +pub type boolean_t = ::libc::c_uint; + +#[cfg(not(target_arch = "x86_64"))] +pub type boolean_t = ::libc::c_int; diff --git a/vendor/mach2/src/bootstrap.rs b/vendor/mach2/src/bootstrap.rs new file mode 100644 index 0000000000000..3642b94627d9a --- /dev/null +++ b/vendor/mach2/src/bootstrap.rs @@ -0,0 +1,76 @@ +//! This module corresponds to `bootstrap.h` + +use boolean::boolean_t; +use kern_return::kern_return_t; +use port::mach_port_t; + +pub const BOOTSTRAP_MAX_NAME_LEN: ::libc::c_uint = 128; +pub const BOOTSTRAP_MAX_CMD_LEN: ::libc::c_uint = 512; + +pub const BOOTSTRAP_MAX_LOOKUP_COUNT: ::libc::c_uint = 20; + +pub const BOOTSTRAP_SUCCESS: ::libc::c_uint = 0; +pub const BOOTSTRAP_NOT_PRIVILEGED: ::libc::c_uint = 1100; +pub const BOOTSTRAP_NAME_IN_USE: ::libc::c_uint = 1101; +pub const BOOTSTRAP_UNKNOWN_SERVICE: ::libc::c_uint = 1102; +pub const BOOTSTRAP_SERVICE_ACTIVE: ::libc::c_uint = 1103; +pub const BOOTSTRAP_BAD_COUNT: ::libc::c_uint = 1104; +pub const BOOTSTRAP_NO_MEMORY: ::libc::c_uint = 1105; +pub const BOOTSTRAP_NO_CHILDREN: ::libc::c_uint = 1106; + +pub const BOOTSTRAP_STATUS_INACTIVE: ::libc::c_uint = 0; +pub const BOOTSTRAP_STATUS_ACTIVE: ::libc::c_uint = 1; +pub const BOOTSTRAP_STATUS_ON_DEMAND: ::libc::c_uint = 2; + +pub type name_t = [::libc::c_char; 128]; +pub type cmd_t = [::libc::c_char; 512]; +pub type name_array_t = *mut name_t; +pub type bootstrap_status_t = ::libc::c_int; +pub type bootstrap_status_array_t = *mut bootstrap_status_t; +pub type bootstrap_property_t = ::libc::c_uint; +pub type bootstrap_property_array_t = *mut bootstrap_property_t; +pub type bool_array_t = *mut boolean_t; + +extern "C" { + pub static bootstrap_port: mach_port_t; + pub fn bootstrap_create_server( + bp: mach_port_t, + server_cmd: *mut ::libc::c_char, + server_uid: ::libc::uid_t, + on_demand: boolean_t, + server_port: *mut mach_port_t, + ) -> kern_return_t; + pub fn bootstrap_subset( + bp: mach_port_t, + requestor_port: mach_port_t, + subset_port: *mut mach_port_t, + ) -> kern_return_t; + pub fn bootstrap_unprivileged(bp: mach_port_t, unpriv_port: *mut mach_port_t) -> kern_return_t; + pub fn bootstrap_parent(bp: mach_port_t, parent_port: *mut mach_port_t) -> kern_return_t; + pub fn bootstrap_register( + bp: mach_port_t, + service_name: *mut ::libc::c_char, + sp: mach_port_t, + ) -> kern_return_t; + pub fn bootstrap_create_service( + bp: mach_port_t, + service_name: *mut ::libc::c_char, + sp: *mut mach_port_t, + ) -> kern_return_t; + pub fn bootstrap_check_in( + bp: mach_port_t, + service_name: *const ::libc::c_char, + sp: *mut mach_port_t, + ) -> kern_return_t; + pub fn bootstrap_look_up( + bp: mach_port_t, + service_name: *const ::libc::c_char, + sp: *mut mach_port_t, + ) -> kern_return_t; + pub fn bootstrap_status( + bp: mach_port_t, + service_name: *mut ::libc::c_char, + service_active: *mut bootstrap_status_t, + ) -> kern_return_t; + pub fn bootstrap_strerror(r: kern_return_t) -> *const ::libc::c_char; +} diff --git a/vendor/mach2/src/clock.rs b/vendor/mach2/src/clock.rs new file mode 100644 index 0000000000000..1d5437951dd23 --- /dev/null +++ b/vendor/mach2/src/clock.rs @@ -0,0 +1,27 @@ +//! This module roughly corresponds to `mach/clock.h`. + +pub const clock_MSG_COUNT: ::libc::c_uint = 3; + +use clock_types::{alarm_type_t, clock_attr_t, clock_flavor_t, mach_timespec_t}; +use kern_return::kern_return_t; +use mach_types::{clock_reply_t, clock_serv_t}; +use message::mach_msg_type_number_t; + +extern "C" { + pub fn clock_get_time( + clock_serv: clock_serv_t, + cur_time: *mut mach_timespec_t, + ) -> kern_return_t; + pub fn clock_get_attributes( + clock_serv: clock_serv_t, + flavor: clock_flavor_t, + clock_attr: clock_attr_t, + clock_attrCnt: *mut mach_msg_type_number_t, + ) -> kern_return_t; + pub fn clock_alarm( + clock_serv: clock_serv_t, + alarm_type: alarm_type_t, + alarm_time: mach_timespec_t, + alarm_port: clock_reply_t, + ) -> kern_return_t; +} diff --git a/vendor/mach2/src/clock_priv.rs b/vendor/mach2/src/clock_priv.rs new file mode 100644 index 0000000000000..d534e79a3c20e --- /dev/null +++ b/vendor/mach2/src/clock_priv.rs @@ -0,0 +1,16 @@ +//! This module roughly corresponds to `mach/clock_priv.h`. + +use clock_types::{clock_attr_t, clock_flavor_t, mach_timespec_t}; +use kern_return::kern_return_t; +use mach_types::clock_ctrl_t; +use message::mach_msg_type_number_t; + +extern "C" { + pub fn clock_set_time(clock_ctrl: clock_ctrl_t, new_time: mach_timespec_t) -> kern_return_t; + pub fn clock_set_attributes( + clock_ctrl: clock_ctrl_t, + flavor: clock_flavor_t, + clock_attr: clock_attr_t, + clock_attrCnt: mach_msg_type_number_t, + ) -> kern_return_t; +} diff --git a/vendor/mach2/src/clock_reply.rs b/vendor/mach2/src/clock_reply.rs new file mode 100644 index 0000000000000..854eb22bf581d --- /dev/null +++ b/vendor/mach2/src/clock_reply.rs @@ -0,0 +1,16 @@ +//! This module roughly corresponds to `mach/clock_reply.h`. + +use clock_types::{alarm_type_t, mach_timespec_t}; +use kern_return::kern_return_t; +use mach_types::clock_reply_t; +use message::mach_msg_type_name_t; + +extern "C" { + pub fn clock_alarm_reply( + alarm_port: clock_reply_t, + alarm_portPoly: mach_msg_type_name_t, + alarm_code: kern_return_t, + alarm_type: alarm_type_t, + alarm_time: mach_timespec_t, + ) -> kern_return_t; +} diff --git a/vendor/mach2/src/clock_types.rs b/vendor/mach2/src/clock_types.rs new file mode 100644 index 0000000000000..c0949c83158b2 --- /dev/null +++ b/vendor/mach2/src/clock_types.rs @@ -0,0 +1,75 @@ +//! This module roughly corresponds to `mach/clock_types.h`. + +pub type alarm_type_t = ::libc::c_int; +pub type sleep_type_t = ::libc::c_int; +pub type clock_id_t = ::libc::c_int; +pub type clock_flavor_t = ::libc::c_int; +pub type clock_attr_t = *mut ::libc::c_int; +pub type clock_res_t = ::libc::c_int; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct mach_timespec { + pub tv_sec: ::libc::c_uint, + pub tv_nsec: clock_res_t, +} +pub type mach_timespec_t = mach_timespec; + +pub const SYSTEM_CLOCK: ::libc::c_uint = 0; +pub const CALENDAR_CLOCK: ::libc::c_uint = 1; +pub const REALTIME_CLOCK: ::libc::c_uint = 0; + +pub const CLOCK_GET_TIME_RES: ::libc::c_uint = 1; +pub const CLOCK_ALARM_CURRES: ::libc::c_uint = 3; +pub const CLOCK_ALARM_MINRES: ::libc::c_uint = 4; +pub const CLOCK_ALARM_MAXRES: ::libc::c_uint = 5; + +pub const NSEC_PER_USEC: ::libc::c_ulonglong = 1000; +pub const USEC_PER_SEC: ::libc::c_ulonglong = 1_000_000; +pub const NSEC_PER_SEC: ::libc::c_ulonglong = 1_000_000_000; +pub const NSEC_PER_MSEC: ::libc::c_ulonglong = 1_000_000; + +#[allow(non_snake_case)] +pub fn BAD_MACH_TIMESPEC(t: mach_timespec) -> bool { + t.tv_nsec < 0 || (t.tv_nsec as ::libc::c_ulonglong) >= NSEC_PER_SEC +} + +#[allow(non_snake_case)] +pub fn CMP_MACH_TIMESPEC(t1: &mach_timespec, t2: &mach_timespec) -> ::libc::c_ulonglong { + if t1.tv_sec > t2.tv_sec { + return NSEC_PER_SEC; + } + if t1.tv_sec < t2.tv_sec { + return !NSEC_PER_SEC; + } + (t1.tv_nsec as ::libc::c_ulonglong) - (t2.tv_nsec as ::libc::c_ulonglong) +} + +#[allow(non_snake_case)] +pub fn ADD_MACH_TIMESPEC(t1: &mut mach_timespec, t2: &mach_timespec) { + t1.tv_nsec += t2.tv_nsec; + if (t1.tv_nsec as ::libc::c_ulonglong) >= NSEC_PER_SEC { + t1.tv_nsec = (t1.tv_nsec as ::libc::c_ulonglong - NSEC_PER_SEC) as clock_res_t; + t1.tv_sec += 1; + } + t1.tv_sec += t2.tv_sec; +} + +#[allow(non_snake_case)] +pub fn SUB_MACH_TIMESPEC(t1: &mut mach_timespec, t2: &mach_timespec) { + t1.tv_nsec -= t2.tv_nsec; + if t1.tv_nsec < 0 { + t1.tv_nsec = (t1.tv_nsec as ::libc::c_ulonglong + NSEC_PER_SEC) as clock_res_t; + t1.tv_sec -= 1; + } + t1.tv_sec -= t2.tv_sec; +} + +pub const ALRMTYPE: ::libc::c_uint = 0xff; +pub const TIME_ABSOLUTE: ::libc::c_uint = 0x00; +pub const TIME_RELATIVE: ::libc::c_uint = 0x01; + +#[allow(non_snake_case)] +pub fn BAD_ALRMTYPE(t: ::libc::c_uint) -> bool { + t & (!TIME_RELATIVE) != 0 +} diff --git a/vendor/mach2/src/dyld_kernel.rs b/vendor/mach2/src/dyld_kernel.rs new file mode 100644 index 0000000000000..9a264dfafd597 --- /dev/null +++ b/vendor/mach2/src/dyld_kernel.rs @@ -0,0 +1,30 @@ +//! This module roughly corresponds to `mach/dyld_kernel.h`. + +use boolean::boolean_t; +use mach_types::{fsid_t, fsobj_id_t, uuid_t}; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct dyld_kernel_image_info { + pub uuid: uuid_t, + pub fsobjid: fsobj_id_t, + pub fsid: fsid_t, + pub load_addr: u64, +} + +#[allow(non_snake_case)] +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct dyld_kernel_process_info { + pub cache_image_info: dyld_kernel_image_info, + pub timestamp: u64, + pub imageCount: u32, + pub initialImageCount: u32, + pub dyldState: u8, + pub no_cache: boolean_t, + pub private_cache: boolean_t, +} + +pub type dyld_kernel_image_info_t = dyld_kernel_image_info; +pub type dyld_kernel_process_info_t = dyld_kernel_process_info; +pub type dyld_kernel_image_info_array_t = *mut dyld_kernel_image_info_t; diff --git a/vendor/mach2/src/exc.rs b/vendor/mach2/src/exc.rs new file mode 100644 index 0000000000000..9330740c4e29d --- /dev/null +++ b/vendor/mach2/src/exc.rs @@ -0,0 +1,44 @@ +//! This module roughly corresponds to `mach/exc.h`. + +use exception_types::{exception_data_t, exception_type_t}; +use kern_return::kern_return_t; +use message::mach_msg_type_number_t; +use port::mach_port_t; +use thread_status::thread_state_t; + +pub const exc_MSG_COUNT: ::libc::c_uint = 3; + +extern "C" { + pub fn exception_raise( + exception_port: mach_port_t, + thread: mach_port_t, + task: mach_port_t, + exception: exception_type_t, + code: exception_data_t, + codeCnt: mach_msg_type_number_t, + ) -> kern_return_t; + pub fn exception_raise_state( + exception_port: mach_port_t, + exception: exception_type_t, + code: exception_data_t, + codeCnt: mach_msg_type_number_t, + flavor: *mut ::libc::c_int, + old_state: thread_state_t, + old_stateCnt: mach_msg_type_number_t, + new_state: thread_state_t, + new_stateCnt: *mut mach_msg_type_number_t, + ) -> kern_return_t; + pub fn exception_raise_state_identity( + exception_port: mach_port_t, + thread: mach_port_t, + task: mach_port_t, + exception: exception_type_t, + code: exception_data_t, + codeCnt: mach_msg_type_number_t, + flavor: *mut ::libc::c_int, + old_state: thread_state_t, + old_stateCnt: mach_msg_type_number_t, + new_state: thread_state_t, + new_stateCnt: *mut mach_msg_type_number_t, + ) -> kern_return_t; +} diff --git a/vendor/mach2/src/exception_types.rs b/vendor/mach2/src/exception_types.rs new file mode 100644 index 0000000000000..f042443d8a7f0 --- /dev/null +++ b/vendor/mach2/src/exception_types.rs @@ -0,0 +1,56 @@ +//! This module roughly corresponds to `mach/exception_types.h`. + +use port::mach_port_t; +use thread_status::thread_state_flavor_t; +use vm_types::integer_t; + +pub const EXC_BAD_ACCESS: ::libc::c_uint = 1; +pub const EXC_BAD_INSTRUCTION: ::libc::c_uint = 2; +pub const EXC_ARITHMETIC: ::libc::c_uint = 3; +pub const EXC_EMULATION: ::libc::c_uint = 4; +pub const EXC_SOFTWARE: ::libc::c_uint = 5; +pub const EXC_BREAKPOINT: ::libc::c_uint = 6; +pub const EXC_SYSCALL: ::libc::c_uint = 7; +pub const EXC_MACH_SYSCALL: ::libc::c_uint = 8; +pub const EXC_RPC_ALERT: ::libc::c_uint = 9; +pub const EXC_CRASH: ::libc::c_uint = 10; +pub const EXC_RESOURCE: ::libc::c_uint = 11; +pub const EXC_GUARD: ::libc::c_uint = 12; +pub const EXC_CORPSE_NOTIFY: ::libc::c_uint = 13; +pub const EXC_CORPSE_VARIANT_BIT: ::libc::c_uint = 256; +pub const EXCEPTION_DEFAULT: ::libc::c_uint = 1; +pub const EXCEPTION_STATE: ::libc::c_uint = 2; +pub const EXCEPTION_STATE_IDENTITY: ::libc::c_uint = 3; +pub const MACH_EXCEPTION_CODES: ::libc::c_uint = 2_147_483_648; +pub const EXC_MASK_BAD_ACCESS: ::libc::c_uint = 2; +pub const EXC_MASK_BAD_INSTRUCTION: ::libc::c_uint = 4; +pub const EXC_MASK_ARITHMETIC: ::libc::c_uint = 8; +pub const EXC_MASK_EMULATION: ::libc::c_uint = 16; +pub const EXC_MASK_SOFTWARE: ::libc::c_uint = 32; +pub const EXC_MASK_BREAKPOINT: ::libc::c_uint = 64; +pub const EXC_MASK_SYSCALL: ::libc::c_uint = 128; +pub const EXC_MASK_MACH_SYSCALL: ::libc::c_uint = 256; +pub const EXC_MASK_RPC_ALERT: ::libc::c_uint = 512; +pub const EXC_MASK_CRASH: ::libc::c_uint = 1024; +pub const EXC_MASK_RESOURCE: ::libc::c_uint = 2048; +pub const EXC_MASK_GUARD: ::libc::c_uint = 4096; +pub const EXC_MASK_CORPSE_NOTIFY: ::libc::c_uint = 8192; +pub const EXC_MASK_ALL: ::libc::c_uint = 7166; +pub const FIRST_EXCEPTION: ::libc::c_uint = 1; +pub const EXC_SOFT_SIGNAL: ::libc::c_uint = 65_539; +pub const EXC_MACF_MIN: ::libc::c_uint = 131_072; +pub const EXC_MACF_MAX: ::libc::c_uint = 196_607; + +pub type exception_type_t = ::libc::c_int; +pub type exception_data_type_t = integer_t; +pub type mach_exception_data_type_t = i64; +pub type exception_behavior_t = ::libc::c_int; +pub type exception_data_t = *mut exception_data_type_t; +pub type mach_exception_data_t = *mut mach_exception_data_type_t; +pub type exception_mask_t = ::libc::c_uint; +pub type exception_mask_array_t = *mut exception_mask_t; +pub type exception_behavior_array_t = *mut exception_behavior_t; +pub type exception_flavor_array_t = *mut thread_state_flavor_t; +pub type exception_port_array_t = *mut mach_port_t; +pub type mach_exception_code_t = mach_exception_data_type_t; +pub type mach_exception_subcode_t = mach_exception_data_type_t; diff --git a/vendor/mach2/src/kern_return.rs b/vendor/mach2/src/kern_return.rs new file mode 100644 index 0000000000000..3d447b4026645 --- /dev/null +++ b/vendor/mach2/src/kern_return.rs @@ -0,0 +1,58 @@ +//! This module corresponds to `mach/kern_return.h` and +//! `mach/i386/kern_return.h`. + +pub type kern_return_t = ::libc::c_int; + +pub const KERN_SUCCESS: kern_return_t = 0; +pub const KERN_INVALID_ADDRESS: kern_return_t = 1; +pub const KERN_PROTECTION_FAILURE: kern_return_t = 2; +pub const KERN_NO_SPACE: kern_return_t = 3; +pub const KERN_INVALID_ARGUMENT: kern_return_t = 4; +pub const KERN_FAILURE: kern_return_t = 5; +pub const KERN_RESOURCE_SHORTAGE: kern_return_t = 6; +pub const KERN_NOT_RECEIVER: kern_return_t = 7; +pub const KERN_NO_ACCESS: kern_return_t = 8; +pub const KERN_MEMORY_FAILURE: kern_return_t = 9; +pub const KERN_MEMORY_ERROR: kern_return_t = 10; +pub const KERN_ALREADY_IN_SET: kern_return_t = 11; +pub const KERN_NOT_IN_SET: kern_return_t = 12; +pub const KERN_NAME_EXISTS: kern_return_t = 13; +pub const KERN_ABORTED: kern_return_t = 14; +pub const KERN_INVALID_NAME: kern_return_t = 15; +pub const KERN_INVALID_TASK: kern_return_t = 16; +pub const KERN_INVALID_RIGHT: kern_return_t = 17; +pub const KERN_INVALID_VALUE: kern_return_t = 18; +pub const KERN_UREFS_OVERFLOW: kern_return_t = 19; +pub const KERN_INVALID_CAPABILITY: kern_return_t = 20; +pub const KERN_RIGHT_EXISTS: kern_return_t = 21; +pub const KERN_INVALID_HOST: kern_return_t = 22; +pub const KERN_MEMORY_PRESENT: kern_return_t = 23; +pub const KERN_MEMORY_DATA_MOVED: kern_return_t = 24; +pub const KERN_MEMORY_RESTART_COPY: kern_return_t = 25; +pub const KERN_INVALID_PROCESSOR_SET: kern_return_t = 26; +pub const KERN_POLICY_LIMIT: kern_return_t = 27; +pub const KERN_INVALID_POLICY: kern_return_t = 28; +pub const KERN_INVALID_OBJECT: kern_return_t = 29; +pub const KERN_ALREADY_WAITING: kern_return_t = 30; +pub const KERN_DEFAULT_SET: kern_return_t = 31; +pub const KERN_EXCEPTION_PROTECTED: kern_return_t = 32; +pub const KERN_INVALID_LEDGER: kern_return_t = 33; +pub const KERN_INVALID_MEMORY_CONTROL: kern_return_t = 34; +pub const KERN_INVALID_SECURITY: kern_return_t = 35; +pub const KERN_NOT_DEPRESSED: kern_return_t = 36; +pub const KERN_TERMINATED: kern_return_t = 37; +pub const KERN_LOCK_SET_DESTROYED: kern_return_t = 38; +pub const KERN_LOCK_UNSTABLE: kern_return_t = 39; +pub const KERN_LOCK_OWNED: kern_return_t = 40; +pub const KERN_LOCK_OWNED_SELF: kern_return_t = 41; +pub const KERN_SEMAPHORE_DESTROYED: kern_return_t = 42; +pub const KERN_RPC_SERVER_TERMINATED: kern_return_t = 43; +pub const KERN_RPC_TERMINATE_ORPHAN: kern_return_t = 44; +pub const KERN_RPC_CONTINUE_ORPHAN: kern_return_t = 45; +pub const KERN_NOT_SUPPORTED: kern_return_t = 46; +pub const KERN_NODE_DOWN: kern_return_t = 47; +pub const KERN_NOT_WAITING: kern_return_t = 48; +pub const KERN_OPERATION_TIMED_OUT: kern_return_t = 49; +pub const KERN_CODESIGN_ERROR: kern_return_t = 50; +pub const KERN_POLICY_STATIC: kern_return_t = 51; +pub const KERN_RETURN_MAX: kern_return_t = 0x100; diff --git a/vendor/mach2/src/lib.rs b/vendor/mach2/src/lib.rs new file mode 100644 index 0000000000000..0b68a706aad9b --- /dev/null +++ b/vendor/mach2/src/lib.rs @@ -0,0 +1,56 @@ +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] +#![deny(missing_debug_implementations)] +#![deny(missing_copy_implementations)] +#![allow( + clippy::module_name_repetitions, + clippy::cast_sign_loss, + clippy::cast_possible_truncation, + clippy::trivially_copy_pass_by_ref +)] +#![no_std] + +#[cfg(not(any(target_os = "macos", target_os = "ios")))] +compile_error!("mach requires macOS or iOS"); + +extern crate libc; + +#[allow(unused_imports)] +use core::{clone, cmp, default, fmt, hash, marker, mem, option}; + +pub mod boolean; +pub mod bootstrap; +pub mod clock; +pub mod clock_priv; +pub mod clock_reply; +pub mod clock_types; // TODO: test +pub mod dyld_kernel; +// pub mod error; // TODO +pub mod exc; +pub mod exception_types; +pub mod kern_return; +pub mod mach_init; +pub mod mach_port; +pub mod mach_time; +pub mod mach_types; +pub mod memory_object_types; +pub mod message; +pub mod port; +pub mod structs; +pub mod task; +pub mod task_info; +pub mod thread_act; +pub mod thread_policy; +pub mod thread_status; +pub mod traps; +pub mod vm; +pub mod vm_attributes; +pub mod vm_behavior; +pub mod vm_inherit; +pub mod vm_page_size; +pub mod vm_prot; +pub mod vm_purgable; +pub mod vm_region; +pub mod vm_statistics; +pub mod vm_sync; +pub mod vm_types; diff --git a/vendor/mach2/src/mach_init.rs b/vendor/mach2/src/mach_init.rs new file mode 100644 index 0000000000000..5776988cb519f --- /dev/null +++ b/vendor/mach2/src/mach_init.rs @@ -0,0 +1,22 @@ +//! This module corresponds to `mach/mach_init.h`. + +use mach_types::thread_port_t; + +extern "C" { + pub fn mach_thread_self() -> thread_port_t; +} + +#[cfg(test)] +mod tests { + use mach_init::*; + use port::*; + + #[test] + fn mach_thread_self_test() { + unsafe { + let this_thread = mach_thread_self(); + assert!(this_thread != MACH_PORT_NULL); + assert!(this_thread != MACH_PORT_DEAD); + } + } +} diff --git a/vendor/mach2/src/mach_port.rs b/vendor/mach2/src/mach_port.rs new file mode 100644 index 0000000000000..e14a08e957fea --- /dev/null +++ b/vendor/mach2/src/mach_port.rs @@ -0,0 +1,35 @@ +//! This module corresponds to `mach/mach_port.h` + +use kern_return::kern_return_t; +use mach_types::ipc_space_t; +use message::mach_msg_type_name_t; +use port::{mach_port_delta_t, mach_port_name_t, mach_port_right_t, mach_port_t}; + +extern "C" { + pub fn mach_port_allocate( + task: ipc_space_t, + right: mach_port_right_t, + name: *mut mach_port_name_t, + ) -> kern_return_t; + pub fn mach_port_destroy(task: ipc_space_t, name: mach_port_name_t) -> kern_return_t; + pub fn mach_port_deallocate(task: ipc_space_t, name: mach_port_name_t) -> kern_return_t; + pub fn mach_port_insert_right( + task: ipc_space_t, + name: mach_port_name_t, + poly: mach_port_t, + polyPoly: mach_msg_type_name_t, + ) -> kern_return_t; + pub fn mach_port_extract_right( + task: ipc_space_t, + name: mach_port_name_t, + msgt_name: mach_msg_type_name_t, + poly: *mut mach_port_t, + polyPoly: *mut mach_msg_type_name_t, + ) -> kern_return_t; + pub fn mach_port_mod_refs( + task: ipc_space_t, + name: mach_port_name_t, + right: mach_port_right_t, + delta: mach_port_delta_t, + ) -> kern_return_t; +} diff --git a/vendor/mach2/src/mach_time.rs b/vendor/mach2/src/mach_time.rs new file mode 100644 index 0000000000000..9011c0c0af761 --- /dev/null +++ b/vendor/mach2/src/mach_time.rs @@ -0,0 +1,20 @@ +//! This module corresponds to `mach/mach_time.h` +use kern_return::kern_return_t; +pub type mach_timebase_info_t = *mut mach_timebase_info; +pub type mach_timebase_info_data_t = mach_timebase_info; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct mach_timebase_info { + pub numer: u32, + pub denom: u32, +} + +extern "C" { + pub fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t; + pub fn mach_wait_until(deadline: u64) -> kern_return_t; + pub fn mach_absolute_time() -> u64; + pub fn mach_approximate_time() -> u64; + pub fn mach_continuous_time() -> u64; + pub fn mach_continuous_approximate_time() -> u64; +} diff --git a/vendor/mach2/src/mach_types.rs b/vendor/mach2/src/mach_types.rs new file mode 100644 index 0000000000000..fa257b2a53833 --- /dev/null +++ b/vendor/mach2/src/mach_types.rs @@ -0,0 +1,106 @@ +//! This module corresponds to `mach/mach_types.h` + +use port::mach_port_t; + +pub type task_t = mach_port_t; +pub type task_name_t = mach_port_t; +pub type task_suspension_token_t = mach_port_t; +pub type thread_t = mach_port_t; +pub type thread_act_t = mach_port_t; +pub type ipc_space_t = mach_port_t; +pub type coalition_t = mach_port_t; +pub type host_t = mach_port_t; +pub type host_priv_t = mach_port_t; +pub type host_security_t = mach_port_t; +pub type processor_t = mach_port_t; +pub type processor_set_t = mach_port_t; +pub type processor_set_control_t = mach_port_t; +pub type semaphore_t = mach_port_t; +pub type lock_set_t = mach_port_t; +pub type ledger_t = mach_port_t; +pub type alarm_t = mach_port_t; +pub type clock_serv_t = mach_port_t; +pub type clock_ctrl_t = mach_port_t; + +pub type processor_set_name_t = processor_set_t; + +pub type clock_reply_t = mach_port_t; +pub type bootstrap_t = mach_port_t; +pub type mem_entry_name_port_t = mach_port_t; +pub type exception_handler_t = mach_port_t; +pub type exception_handler_array_t = *mut exception_handler_t; +pub type vm_task_entry_t = mach_port_t; +pub type io_master_t = mach_port_t; +pub type UNDServerRef = mach_port_t; + +pub type task_array_t = *mut task_t; +pub type thread_array_t = *mut thread_t; +pub type processor_set_array_t = *mut processor_set_t; +pub type processor_set_name_array_t = *mut processor_set_t; +pub type processor_array_t = *mut processor_t; +pub type thread_act_array_t = *mut thread_act_t; +pub type ledger_array_t = *mut ledger_t; + +pub type task_port_t = task_t; +pub type task_port_array_t = task_array_t; +pub type thread_port_t = thread_t; +pub type thread_port_array_t = thread_array_t; +pub type ipc_space_port_t = ipc_space_t; +pub type host_name_t = host_t; +pub type host_name_port_t = host_t; +pub type processor_set_port_t = processor_set_t; +pub type processor_set_name_port_t = processor_set_t; +pub type processor_set_name_port_array_t = processor_set_array_t; +pub type processor_set_control_port_t = processor_set_t; +pub type processor_port_t = processor_t; +pub type processor_port_array_t = processor_array_t; +pub type thread_act_port_t = thread_act_t; +pub type thread_act_port_array_t = thread_act_array_t; +pub type semaphore_port_t = semaphore_t; +pub type lock_set_port_t = lock_set_t; +pub type ledger_port_t = ledger_t; +pub type ledger_port_array_t = ledger_array_t; +pub type alarm_port_t = alarm_t; +pub type clock_serv_port_t = clock_serv_t; +pub type clock_ctrl_port_t = clock_ctrl_t; +pub type exception_port_t = exception_handler_t; +pub type exception_port_arrary_t = exception_handler_array_t; + +pub const TASK_NULL: task_t = 0; +pub const TASK_NAME_NULL: task_name_t = 0; +pub const THREAD_NULL: thread_t = 0; +pub const TID_NULL: u64 = 0; +pub const THR_ACT_NULL: thread_act_t = 0; +pub const IPC_SPACE_NULL: ipc_space_t = 0; +pub const COALITION_NULL: coalition_t = 0; +pub const HOST_NULL: host_t = 0; +pub const HOST_PRIV_NULL: host_priv_t = 0; +pub const HOST_SECURITY_NULL: host_security_t = 0; +pub const PROCESSOR_SET_NULL: processor_set_t = 0; +pub const PROCESSOR_NULL: processor_t = 0; +pub const SEMAPHORE_NULL: semaphore_t = 0; +pub const LOCK_SET_NULL: lock_set_t = 0; +pub const LEDGER_NULL: ledger_t = 0; +pub const ALARM_NULL: alarm_t = 0; +pub const CLOCK_NULL: ::libc::clock_t = 0; +pub const UND_SERVER_NULL: UNDServerRef = 0; + +// : typedef unsigned char __darwin_uuid_t[16]; +pub type uuid_t = [::libc::c_uchar; 16]; + +// +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct fsid { + pub val: [i32; 2], +} +pub type fsid_t = fsid; + +// +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct fsobj_id { + pub fid_objno: u32, + pub fid_generation: u32, +} +pub type fsobj_id_t = fsobj_id; diff --git a/vendor/mach2/src/memory_object_types.rs b/vendor/mach2/src/memory_object_types.rs new file mode 100644 index 0000000000000..8399e71676a21 --- /dev/null +++ b/vendor/mach2/src/memory_object_types.rs @@ -0,0 +1,9 @@ +//! This module roughly corresponds to `mach/memory_object_types.h`. + +use vm_types::natural_t; + +pub type memory_object_offset_t = ::libc::c_ulonglong; +pub type memory_object_size_t = ::libc::c_ulonglong; +pub type memory_object_cluster_size_t = natural_t; +pub type memory_object_fault_info_t = *mut natural_t; +pub type vm_object_id_t = ::libc::c_ulonglong; diff --git a/vendor/mach2/src/message.rs b/vendor/mach2/src/message.rs new file mode 100644 index 0000000000000..40114ad3edefa --- /dev/null +++ b/vendor/mach2/src/message.rs @@ -0,0 +1,248 @@ +//! This module corresponds to `mach/message.h`. + +use kern_return::kern_return_t; +use port::{mach_port_name_t, mach_port_t}; +use vm_types::{integer_t, natural_t}; + +pub type mach_msg_timeout_t = natural_t; + +pub type mach_msg_bits_t = ::libc::c_uint; +pub type mach_msg_id_t = integer_t; +pub type mach_msg_size_t = natural_t; + +pub type mach_msg_copy_options_t = ::libc::c_uint; +pub type mach_msg_descriptor_type_t = ::libc::c_uint; +pub type mach_msg_type_name_t = ::libc::c_uint; + +pub type mach_msg_trailer_type_t = ::libc::c_uint; +pub type mach_msg_trailer_size_t = ::libc::c_uint; + +pub type mach_msg_option_t = integer_t; + +pub type mach_msg_type_number_t = natural_t; +pub type mach_msg_type_size_t = natural_t; + +pub type mach_msg_return_t = kern_return_t; + +pub const MACH_MSG_TIMEOUT_NONE: mach_msg_timeout_t = 0; + +pub const MACH_MSGH_BITS_ZERO: mach_msg_bits_t = 0x0000_0000; + +pub const MACH_MSGH_BITS_REMOTE_MASK: mach_msg_bits_t = 0x0000_001f; +pub const MACH_MSGH_BITS_LOCAL_MASK: mach_msg_bits_t = 0x0000_1f00; +pub const MACH_MSGH_BITS_VOUCHER_MASK: mach_msg_bits_t = 0x001f_0000; + +pub const MACH_MSGH_BITS_PORTS_MASK: mach_msg_bits_t = + MACH_MSGH_BITS_REMOTE_MASK | MACH_MSGH_BITS_LOCAL_MASK | MACH_MSGH_BITS_VOUCHER_MASK; + +pub const MACH_MSGH_BITS_COMPLEX: mach_msg_bits_t = 0x8000_0000; + +pub const MACH_MSGH_BITS_USER: mach_msg_bits_t = 0x801f_1f1f; + +#[allow(non_snake_case)] +pub fn MACH_MSGH_BITS(remote: mach_msg_bits_t, local: mach_msg_bits_t) -> mach_msg_bits_t { + remote | (local << 8) +} + +pub const MACH_MSG_TYPE_MOVE_RECEIVE: mach_msg_type_name_t = 16; +pub const MACH_MSG_TYPE_MOVE_SEND: mach_msg_type_name_t = 17; +pub const MACH_MSG_TYPE_MOVE_SEND_ONCE: mach_msg_type_name_t = 18; +pub const MACH_MSG_TYPE_COPY_SEND: mach_msg_type_name_t = 19; +pub const MACH_MSG_TYPE_MAKE_SEND: mach_msg_type_name_t = 20; +pub const MACH_MSG_TYPE_MAKE_SEND_ONCE: mach_msg_type_name_t = 21; +pub const MACH_MSG_TYPE_COPY_RECEIVE: mach_msg_type_name_t = 22; +pub const MACH_MSG_TYPE_DISPOSE_RECEIVE: mach_msg_type_name_t = 24; +pub const MACH_MSG_TYPE_DISPOSE_SEND: mach_msg_type_name_t = 25; +pub const MACH_MSG_TYPE_DISPOSE_SEND_ONCE: mach_msg_type_name_t = 26; + +pub const MACH_MSG_PHYSICAL_COPY: mach_msg_copy_options_t = 0; +pub const MACH_MSG_VIRTUAL_COPY: mach_msg_copy_options_t = 1; +pub const MACH_MSG_ALLOCATE: mach_msg_copy_options_t = 2; + +pub const MACH_MSG_PORT_DESCRIPTOR: mach_msg_descriptor_type_t = 0; +pub const MACH_MSG_OOL_DESCRIPTOR: mach_msg_descriptor_type_t = 1; +pub const MACH_MSG_OOL_PORTS_DESCRIPTOR: mach_msg_descriptor_type_t = 2; +pub const MACH_MSG_OOL_VOLATILE_DESCRIPTOR: mach_msg_descriptor_type_t = 3; + +pub const MACH_MSG_OPTION_NONE: mach_msg_option_t = 0x0000_0000; + +pub const MACH_SEND_MSG: mach_msg_option_t = 0x0000_0001; +pub const MACH_RCV_MSG: mach_msg_option_t = 0x0000_0002; + +pub const MACH_RCV_LARGE: mach_msg_option_t = 0x0000_0004; +pub const MACH_RCV_LARGE_IDENTITY: mach_msg_option_t = 0x0000_0008; + +pub const MACH_SEND_TIMEOUT: mach_msg_option_t = 0x0000_0010; +pub const MACH_SEND_INTERRUPT: mach_msg_option_t = 0x0000_0040; +pub const MACH_SEND_NOTIFY: mach_msg_option_t = 0x0000_0080; +pub const MACH_SEND_ALWAYS: mach_msg_option_t = 0x0001_0000; +pub const MACH_SEND_TRAILER: mach_msg_option_t = 0x0002_0000; +pub const MACH_SEND_NOIMPORTANCE: mach_msg_option_t = 0x0004_0000; +pub const MACH_SEND_NODENAP: mach_msg_option_t = MACH_SEND_NOIMPORTANCE; +pub const MACH_SEND_IMPORTANCE: mach_msg_option_t = 0x0008_0000; + +pub const MACH_RCV_TIMEOUT: mach_msg_option_t = 0x0000_0100; +pub const MACH_RCV_NOTIFY: mach_msg_option_t = 0x0000_0000; +pub const MACH_RCV_INTERRUPT: mach_msg_option_t = 0x0000_0400; +pub const MACH_RCV_VOUCHER: mach_msg_option_t = 0x0000_0800; +pub const MACH_RCV_OVERWRITE: mach_msg_option_t = 0x0000_0000; + +pub const MACH_MSG_SUCCESS: mach_msg_return_t = 0x0000_0000; + +pub const MACH_MSG_MASK: mach_msg_return_t = 0x0000_3e00; +pub const MACH_MSG_IPC_SPACE: mach_msg_return_t = 0x0000_2000; +pub const MACH_MSG_VM_SPACE: mach_msg_return_t = 0x0000_1000; +pub const MACH_MSG_IPC_KERNEL: mach_msg_return_t = 0x0000_0800; +pub const MACH_MSG_VM_KERNEL: mach_msg_return_t = 0x0000_0400; + +pub const MACH_SEND_IN_PROGRESS: mach_msg_return_t = 0x1000_0001; +pub const MACH_SEND_INVALID_DATA: mach_msg_return_t = 0x1000_0002; +pub const MACH_SEND_INVALID_DEST: mach_msg_return_t = 0x1000_0003; +pub const MACH_SEND_TIMED_OUT: mach_msg_return_t = 0x1000_0004; +pub const MACH_SEND_INVALID_VOUCHER: mach_msg_return_t = 0x1000_0005; +pub const MACH_SEND_INTERRUPTED: mach_msg_return_t = 0x1000_0007; +pub const MACH_SEND_MSG_TOO_SMALL: mach_msg_return_t = 0x1000_0008; +pub const MACH_SEND_INVALID_REPLY: mach_msg_return_t = 0x1000_0009; +pub const MACH_SEND_INVALID_RIGHT: mach_msg_return_t = 0x1000_000a; +pub const MACH_SEND_INVALID_NOTIFY: mach_msg_return_t = 0x1000_000b; +pub const MACH_SEND_INVALID_MEMORY: mach_msg_return_t = 0x1000_000c; +pub const MACH_SEND_NO_BUFFER: mach_msg_return_t = 0x1000_000d; +pub const MACH_SEND_TOO_LARGE: mach_msg_return_t = 0x1000_000e; +pub const MACH_SEND_INVALID_TYPE: mach_msg_return_t = 0x1000_000f; +pub const MACH_SEND_INVALID_HEADER: mach_msg_return_t = 0x1000_0010; +pub const MACH_SEND_INVALID_TRAILER: mach_msg_return_t = 0x1000_0011; +pub const MACH_SEND_INVALID_RT_OOL_SIZE: mach_msg_return_t = 0x1000_0015; + +pub const MACH_RCV_IN_PROGRESS: mach_msg_return_t = 0x1000_4001; +pub const MACH_RCV_INVALID_NAME: mach_msg_return_t = 0x1000_4002; +pub const MACH_RCV_TIMED_OUT: mach_msg_return_t = 0x1000_4003; +pub const MACH_RCV_TOO_LARGE: mach_msg_return_t = 0x1000_4004; +pub const MACH_RCV_INTERRUPTED: mach_msg_return_t = 0x1000_4005; +pub const MACH_RCV_PORT_CHANGED: mach_msg_return_t = 0x1000_4006; +pub const MACH_RCV_INVALID_NOTIFY: mach_msg_return_t = 0x1000_4007; +pub const MACH_RCV_INVALID_DATA: mach_msg_return_t = 0x1000_4008; +pub const MACH_RCV_PORT_DIED: mach_msg_return_t = 0x1000_4009; +pub const MACH_RCV_IN_SET: mach_msg_return_t = 0x1000_400a; +pub const MACH_RCV_HEADER_ERROR: mach_msg_return_t = 0x1000_400b; +pub const MACH_RCV_BODY_ERROR: mach_msg_return_t = 0x1000_400c; +pub const MACH_RCV_INVALID_TYPE: mach_msg_return_t = 0x1000_400d; +pub const MACH_RCV_SCATTER_SMALL: mach_msg_return_t = 0x1000_400e; +pub const MACH_RCV_INVALID_TRAILER: mach_msg_return_t = 0x1000_400f; +pub const MACH_RCV_IN_PROGRESS_TIMED: mach_msg_return_t = 0x1000_4011; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct mach_msg_header_t { + pub msgh_bits: mach_msg_bits_t, + pub msgh_size: mach_msg_size_t, + pub msgh_remote_port: mach_port_t, + pub msgh_local_port: mach_port_t, + pub msgh_voucher_port: mach_port_name_t, + pub msgh_id: mach_msg_id_t, +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct mach_msg_body_t { + pub msgh_descriptor_count: mach_msg_size_t, +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct mach_msg_base_t { + pub header: mach_msg_header_t, + pub body: mach_msg_body_t, +} + +pub const MACH_MSG_TRAILER_FORMAT_0: mach_msg_trailer_type_t = 0; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct mach_msg_trailer_t { + pub msgh_trailer_type: mach_msg_trailer_type_t, + pub msgh_trailer_size: mach_msg_trailer_size_t, +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct mach_msg_port_descriptor_t { + pub name: mach_port_t, + pub pad1: mach_msg_size_t, + pub pad2: u16, + pub disposition: u8, // mach_msg_type_name_t bitfield + pub type_: u8, // mach_msg_descriptor_type_t bitfield +} + +impl mach_msg_port_descriptor_t { + pub fn new(name: mach_port_t, disposition: mach_msg_type_name_t) -> Self { + Self { + name, + pad1: 0, + pad2: 0, + disposition: disposition as u8, + type_: MACH_MSG_PORT_DESCRIPTOR as u8, + } + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct mach_msg_ool_descriptor_t { + pub address: *mut ::libc::c_void, + #[cfg(not(target_pointer_width = "64"))] + pub size: mach_msg_size_t, + pub deallocate: u8, // boolean_t bitfield + pub copy: u8, // mach_msg_copy_options_t bitfield + pub pad1: u8, + pub type_: u8, // mach_msg_descriptor_type_t bitfield + #[cfg(target_pointer_width = "64")] + pub size: mach_msg_size_t, +} + +impl mach_msg_ool_descriptor_t { + pub fn new( + address: *mut ::libc::c_void, + deallocate: bool, + copy: mach_msg_copy_options_t, + size: u32, + ) -> Self { + Self { + address, + deallocate: if deallocate { 1 } else { 0 }, + copy: copy as u8, + pad1: 0, + type_: MACH_MSG_OOL_DESCRIPTOR as u8, + size, + } + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct mach_msg_ool_ports_descriptor_t { + pub address: *mut ::libc::c_void, + #[cfg(not(target_pointer_width = "64"))] + pub count: mach_msg_size_t, + pub deallocate: u8, // boolean_t bitfield + pub copy: u8, // mach_msg_copy_options_t bitfield + pub disposition: u8, // mach_msg_type_name_t bitfield + pub type_: u8, // mach_msg_descriptor_type_t bitfield + #[cfg(target_pointer_width = "64")] + pub count: mach_msg_size_t, +} + +extern "C" { + pub fn mach_msg( + msg: *mut mach_msg_header_t, + option: mach_msg_option_t, + send_size: mach_msg_size_t, + recv_size: mach_msg_size_t, + recv_name: mach_port_name_t, + timeout: mach_msg_timeout_t, + notify: mach_port_name_t, + ) -> mach_msg_return_t; + + // from mach/mach.h + pub fn mach_msg_send(msg: *mut mach_msg_header_t) -> mach_msg_return_t; + pub fn mach_msg_destroy(msg: *mut mach_msg_header_t); +} diff --git a/vendor/mach2/src/port.rs b/vendor/mach2/src/port.rs new file mode 100644 index 0000000000000..151a3aa40ca0f --- /dev/null +++ b/vendor/mach2/src/port.rs @@ -0,0 +1,28 @@ +//! This module corresponds to `mach/port.h` + +use vm_types::{integer_t, natural_t}; + +pub type mach_port_name_t = natural_t; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct ipc_port; + +pub type ipc_port_t = *mut ipc_port; + +pub type mach_port_t = ::libc::c_uint; + +pub const MACH_PORT_NULL: mach_port_t = 0; +pub const MACH_PORT_DEAD: mach_port_t = !0; + +pub type mach_port_right_t = natural_t; + +pub const MACH_PORT_RIGHT_SEND: mach_port_right_t = 0; +pub const MACH_PORT_RIGHT_RECEIVE: mach_port_right_t = 1; +pub const MACH_PORT_RIGHT_SEND_ONCE: mach_port_right_t = 2; +pub const MACH_PORT_RIGHT_PORT_SET: mach_port_right_t = 3; +pub const MACH_PORT_RIGHT_DEAD_NAME: mach_port_right_t = 4; +pub const MACH_PORT_RIGHT_LABELH: mach_port_right_t = 5; +pub const MACH_PORT_RIGHT_NUMBER: mach_port_right_t = 6; + +pub type mach_port_delta_t = integer_t; diff --git a/vendor/mach2/src/structs.rs b/vendor/mach2/src/structs.rs new file mode 100644 index 0000000000000..75dc0e8dba5fc --- /dev/null +++ b/vendor/mach2/src/structs.rs @@ -0,0 +1,62 @@ +//! This module corresponds to `mach/_structs.h`. + +use mem; +use message::mach_msg_type_number_t; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct x86_thread_state64_t { + pub __rax: u64, + pub __rbx: u64, + pub __rcx: u64, + pub __rdx: u64, + pub __rdi: u64, + pub __rsi: u64, + pub __rbp: u64, + pub __rsp: u64, + pub __r8: u64, + pub __r9: u64, + pub __r10: u64, + pub __r11: u64, + pub __r12: u64, + pub __r13: u64, + pub __r14: u64, + pub __r15: u64, + pub __rip: u64, + pub __rflags: u64, + pub __cs: u64, + pub __fs: u64, + pub __gs: u64, +} + +impl x86_thread_state64_t { + pub fn new() -> Self { + Self { + __rax: 0, + __rbx: 0, + __rcx: 0, + __rdx: 0, + __rdi: 0, + __rsi: 0, + __rbp: 0, + __rsp: 0, + __r8: 0, + __r9: 0, + __r10: 0, + __r11: 0, + __r12: 0, + __r13: 0, + __r14: 0, + __r15: 0, + __rip: 0, + __rflags: 0, + __cs: 0, + __fs: 0, + __gs: 0, + } + } + + pub fn count() -> mach_msg_type_number_t { + (mem::size_of::() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t + } +} diff --git a/vendor/mach2/src/task.rs b/vendor/mach2/src/task.rs new file mode 100644 index 0000000000000..1ca2280eb100d --- /dev/null +++ b/vendor/mach2/src/task.rs @@ -0,0 +1,41 @@ +//! This module corresponds to `mach/task.defs`. + +use kern_return::kern_return_t; +use mach_types::{task_name_t, task_t, thread_act_array_t}; +use message::mach_msg_type_number_t; +use port::mach_port_t; +use task_info::{task_flavor_t, task_info_t}; + +pub type task_special_port_t = ::libc::c_int; + +pub const TASK_KERNEL_PORT: task_special_port_t = 1; +pub const TASK_HOST_PORT: task_special_port_t = 2; +pub const TASK_NAME_PORT: task_special_port_t = 3; +pub const TASK_BOOTSTRAP_PORT: task_special_port_t = 4; + +extern "C" { + pub fn task_resume(target_task: task_t) -> kern_return_t; + pub fn task_suspend(target_task: task_t) -> kern_return_t; + pub fn task_get_special_port( + task: task_t, + which_port: task_special_port_t, + special_port: *mut mach_port_t, + ) -> kern_return_t; + pub fn task_threads( + target_task: task_t, + act_list: *mut thread_act_array_t, + act_list_cnt: *mut mach_msg_type_number_t, + ) -> kern_return_t; + pub fn task_info( + target_task: task_name_t, + flavor: task_flavor_t, + task_info_out: task_info_t, + task_info_outCnt: *mut mach_msg_type_number_t, + ) -> kern_return_t; + pub fn task_set_info( + target_task: task_t, + flavor: task_flavor_t, + task_info_in: task_info_t, + task_info_inCnt: mach_msg_type_number_t, + ) -> kern_return_t; +} diff --git a/vendor/mach2/src/task_info.rs b/vendor/mach2/src/task_info.rs new file mode 100644 index 0000000000000..4a3b8ed710e3e --- /dev/null +++ b/vendor/mach2/src/task_info.rs @@ -0,0 +1,44 @@ +//! This module roughly corresponds to `mach/task_info.h`. + +use vm_types::{integer_t, mach_vm_address_t, mach_vm_size_t, natural_t}; + +pub const TASK_INFO_MAX: ::libc::c_uint = 1024; +pub const TASK_BASIC_INFO_32: ::libc::c_uint = 4; +pub const TASK_BASIC2_INFO_32: ::libc::c_uint = 6; +pub const TASK_BASIC_INFO_64: ::libc::c_uint = 5; +#[cfg(target_arch = "x86_64")] +pub const TASK_BASIC_INFO: ::libc::c_uint = 5; +#[cfg(target_arch = "x86")] +pub const TASK_BASIC_INFO: ::libc::c_uint = 4; +pub const TASK_EVENTS_INFO: ::libc::c_uint = 2; +pub const TASK_THREAD_TIMES_INFO: ::libc::c_uint = 3; +pub const TASK_ABSOLUTETIME_INFO: ::libc::c_uint = 1; +pub const TASK_KERNELMEMORY_INFO: ::libc::c_uint = 7; +pub const TASK_SECURITY_TOKEN: ::libc::c_uint = 13; +pub const TASK_AUDIT_TOKEN: ::libc::c_uint = 15; +pub const TASK_AFFINITY_TAG_INFO: ::libc::c_uint = 16; +pub const TASK_DYLD_INFO: ::libc::c_uint = 17; +pub const TASK_DYLD_ALL_IMAGE_INFO_32: ::libc::c_uint = 0; +pub const TASK_DYLD_ALL_IMAGE_INFO_64: ::libc::c_uint = 1; +pub const TASK_EXTMOD_INFO: ::libc::c_uint = 19; +pub const MACH_TASK_BASIC_INFO: ::libc::c_uint = 20; +pub const TASK_POWER_INFO: ::libc::c_uint = 21; +pub const TASK_VM_INFO: ::libc::c_uint = 22; +pub const TASK_VM_INFO_PURGEABLE: ::libc::c_uint = 23; +pub const TASK_TRACE_MEMORY_INFO: ::libc::c_uint = 24; +pub const TASK_WAIT_STATE_INFO: ::libc::c_uint = 25; +pub const TASK_POWER_INFO_V2: ::libc::c_uint = 26; +pub const TASK_VM_INFO_PURGEABLE_ACCOUNT: ::libc::c_uint = 27; +pub const TASK_FLAGS_INFO: ::libc::c_uint = 28; +pub const TASK_DEBUG_INFO_INTERNAL: ::libc::c_uint = 29; + +pub type task_flavor_t = natural_t; +pub type task_info_t = *mut integer_t; + +#[repr(C, packed(4))] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct task_dyld_info { + pub all_image_info_addr: mach_vm_address_t, + pub all_image_info_size: mach_vm_size_t, + pub all_image_info_format: integer_t, +} diff --git a/vendor/mach2/src/thread_act.rs b/vendor/mach2/src/thread_act.rs new file mode 100644 index 0000000000000..f2f9809a2b7e8 --- /dev/null +++ b/vendor/mach2/src/thread_act.rs @@ -0,0 +1,23 @@ +//! This module corresponds to `mach/thread_act.defs`. + +use kern_return::kern_return_t; +use mach_types::thread_act_t; +use message::mach_msg_type_number_t; +use thread_status::{thread_state_flavor_t, thread_state_t}; + +extern "C" { + pub fn thread_get_state( + target_act: thread_act_t, + flavor: thread_state_flavor_t, + new_state: thread_state_t, + new_state_count: *mut mach_msg_type_number_t, + ) -> kern_return_t; +} + +extern "C" { + pub fn thread_suspend(target_act: thread_act_t) -> kern_return_t; +} + +extern "C" { + pub fn thread_resume(target_act: thread_act_t) -> kern_return_t; +} diff --git a/vendor/mach2/src/thread_policy.rs b/vendor/mach2/src/thread_policy.rs new file mode 100644 index 0000000000000..aa17e6ea31413 --- /dev/null +++ b/vendor/mach2/src/thread_policy.rs @@ -0,0 +1,121 @@ +//! This module corresponds to `mach/thread_policy.h`. + +use boolean::boolean_t; +use kern_return::kern_return_t; +use libc::thread_policy_t; +use mach_types::thread_t; +use message::mach_msg_type_number_t; +use vm_types::{integer_t, natural_t}; + +pub type thread_policy_flavor_t = natural_t; + +pub const THREAD_STANDARD_POLICY: thread_policy_flavor_t = 1; +pub const THREAD_EXTENDED_POLICY: thread_policy_flavor_t = 1; +pub const THREAD_TIME_CONSTRAINT_POLICY: thread_policy_flavor_t = 2; +pub const THREAD_PRECEDENCE_POLICY: thread_policy_flavor_t = 3; +pub const THREAD_AFFINITY_POLICY: thread_policy_flavor_t = 4; +pub const THREAD_BACKGROUND_POLICY: thread_policy_flavor_t = 5; +pub const THREAD_LATENCY_QOS_POLICY: thread_policy_flavor_t = 7; +pub const THREAD_THROUGHPUT_QOS_POLICY: thread_policy_flavor_t = 8; + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct thread_standard_policy { + pub no_data: natural_t, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct thread_extended_policy { + pub timeshare: boolean_t, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct thread_time_constraint_policy { + pub period: u32, + pub computation: u32, + pub constraint: u32, + pub preemptible: boolean_t, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct thread_precedence_policy { + pub importance: integer_t, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct thread_affinity_policy { + pub affinity_tag: integer_t, +} + +pub const THREAD_AFFINITY_TAG_NULL: integer_t = 0; + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct thread_background_policy { + pub priority: integer_t, +} + +pub type thread_latency_qos_t = integer_t; + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct thread_latency_qos_policy { + thread_latency_qos_tier: thread_latency_qos_t, +} + +pub type thread_throughput_qos_t = integer_t; + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct thread_throughput_qos_policy { + thread_throughput_qos_tier: thread_throughput_qos_t, +} + +pub type thread_standard_policy_data_t = thread_standard_policy; +pub type thread_extended_policy_data_t = thread_extended_policy; +pub type thread_time_constraint_policy_data_t = thread_time_constraint_policy; +pub type thread_precedence_policy_data_t = thread_precedence_policy; +pub type thread_affinity_policy_data_t = thread_affinity_policy; +pub type thread_background_policy_data_t = thread_background_policy; +pub type thread_latency_qos_policy_data_t = thread_latency_qos_policy; +pub type thread_throughput_qos_policy_data_t = thread_throughput_qos_policy; + +pub const THREAD_STANDARD_POLICY_COUNT: mach_msg_type_number_t = 0; +pub const THREAD_EXTENDED_POLICY_COUNT: mach_msg_type_number_t = + (core::mem::size_of::() / core::mem::size_of::()) as _; +pub const THREAD_TIME_CONSTRAINT_POLICY_COUNT: mach_msg_type_number_t = + (core::mem::size_of::() / core::mem::size_of::()) + as _; +pub const THREAD_PRECEDENCE_POLICY_COUNT: mach_msg_type_number_t = + (core::mem::size_of::() / core::mem::size_of::()) as _; +pub const THREAD_AFFINITY_POLICY_COUNT: mach_msg_type_number_t = + (core::mem::size_of::() / core::mem::size_of::()) as _; +pub const THREAD_BACKGROUND_POLICY_COUNT: mach_msg_type_number_t = + (core::mem::size_of::() / core::mem::size_of::()) as _; +pub const THREAD_LATENCY_QOS_POLICY_COUNT: mach_msg_type_number_t = + (core::mem::size_of::() / core::mem::size_of::()) as _; +pub const THREAD_THROUGHPUT_QOS_POLICY_COUNT: mach_msg_type_number_t = + (core::mem::size_of::() / core::mem::size_of::()) as _; + +extern "C" { + pub fn thread_policy_set( + thread: thread_t, + flavor: thread_policy_flavor_t, + policy_info: thread_policy_t, + count: mach_msg_type_number_t, + ) -> kern_return_t; +} + +extern "C" { + pub fn thread_policy_get( + thread: thread_t, + flavor: thread_policy_flavor_t, + policy_info: thread_policy_t, + count: *mut mach_msg_type_number_t, + get_default: *mut boolean_t, + ) -> kern_return_t; +} diff --git a/vendor/mach2/src/thread_status.rs b/vendor/mach2/src/thread_status.rs new file mode 100644 index 0000000000000..951256622cd49 --- /dev/null +++ b/vendor/mach2/src/thread_status.rs @@ -0,0 +1,23 @@ +//! This module corresponds to `mach/thread_status.h`. + +use vm_types::natural_t; + +pub type thread_state_t = *mut natural_t; +pub type thread_state_flavor_t = ::libc::c_int; + +pub static x86_THREAD_STATE32: thread_state_flavor_t = 1; +pub static x86_FLOAT_STATE32: thread_state_flavor_t = 2; +pub static x86_EXCEPTION_STATE32: thread_state_flavor_t = 3; +pub static x86_THREAD_STATE64: thread_state_flavor_t = 4; +pub static x86_FLOAT_STATE64: thread_state_flavor_t = 5; +pub static x86_EXCEPTION_STATE64: thread_state_flavor_t = 6; +pub static x86_THREAD_STATE: thread_state_flavor_t = 7; +pub static x86_FLOAT_STATE: thread_state_flavor_t = 8; +pub static x86_EXCEPTION_STATE: thread_state_flavor_t = 9; +pub static x86_DEBUG_STATE32: thread_state_flavor_t = 10; +pub static x86_DEBUG_STATE64: thread_state_flavor_t = 11; +pub static x86_DEBUG_STATE: thread_state_flavor_t = 12; +pub static THREAD_STATE_NONE: thread_state_flavor_t = 13; +pub static x86_AVX_STATE32: thread_state_flavor_t = 16; +pub static x86_AVX_STATE64: thread_state_flavor_t = 17; +pub static x86_AVX_STATE: thread_state_flavor_t = 18; diff --git a/vendor/mach2/src/traps.rs b/vendor/mach2/src/traps.rs new file mode 100644 index 0000000000000..1d3bb93ea3552 --- /dev/null +++ b/vendor/mach2/src/traps.rs @@ -0,0 +1,37 @@ +//! This module corresponds to `mach/mach_traps.h`. +use kern_return::kern_return_t; +use port::{mach_port_name_t, mach_port_t}; + +extern "C" { + static mach_task_self_: mach_port_t; + pub fn task_for_pid( + target_tport: mach_port_name_t, + pid: ::libc::c_int, + tn: *mut mach_port_name_t, + ) -> kern_return_t; +} + +#[allow(clippy::missing_safety_doc)] // FIXME +pub unsafe fn mach_task_self() -> mach_port_t { + mach_task_self_ +} + +#[allow(clippy::missing_safety_doc)] // FIXME +pub unsafe fn current_task() -> mach_port_t { + mach_task_self() +} + +#[cfg(test)] +mod tests { + use port::*; + use traps::*; + + #[test] + fn mach_task_self_sanity() { + unsafe { + let this_task = mach_task_self(); + assert!(this_task != MACH_PORT_NULL); + assert!(this_task != MACH_PORT_DEAD); + } + } +} diff --git a/vendor/mach2/src/vm.rs b/vendor/mach2/src/vm.rs new file mode 100644 index 0000000000000..d0bf6f23abef1 --- /dev/null +++ b/vendor/mach2/src/vm.rs @@ -0,0 +1,248 @@ +//! This module roughly corresponds to `mach/mach_vm.defs`. + +use boolean::boolean_t; +use kern_return::kern_return_t; +use mach_types::{mem_entry_name_port_t, vm_task_entry_t}; +use memory_object_types::{memory_object_offset_t, memory_object_size_t}; +use message::mach_msg_type_number_t; +use port::mach_port_t; +use vm_attributes::{vm_machine_attribute_t, vm_machine_attribute_val_t}; +use vm_behavior::vm_behavior_t; +use vm_inherit::vm_inherit_t; +use vm_prot::vm_prot_t; +use vm_purgable::vm_purgable_t; +use vm_region::mach_vm_read_entry_t; +use vm_region::{ + vm_page_info_flavor_t, vm_page_info_t, vm_region_flavor_t, vm_region_info_t, + vm_region_recurse_info_t, +}; +use vm_sync::vm_sync_t; +use vm_types::{ + integer_t, mach_vm_address_t, mach_vm_offset_t, mach_vm_size_t, natural_t, vm_map_t, + vm_offset_t, vm_size_t, +}; + +extern "C" { + pub fn mach_vm_allocate( + target: vm_task_entry_t, + address: *mut mach_vm_address_t, + size: mach_vm_size_t, + flags: ::libc::c_int, + ) -> kern_return_t; + + pub fn mach_vm_deallocate( + target: vm_task_entry_t, + address: mach_vm_address_t, + size: mach_vm_size_t, + ) -> kern_return_t; + + pub fn mach_vm_protect( + target_task: vm_task_entry_t, + address: mach_vm_address_t, + size: mach_vm_size_t, + set_maximum: boolean_t, + new_protection: vm_prot_t, + ) -> kern_return_t; + + pub fn mach_vm_inherit( + target_task: vm_task_entry_t, + address: mach_vm_address_t, + size: mach_vm_size_t, + new_inheritance: vm_inherit_t, + ) -> kern_return_t; + + pub fn mach_vm_read( + target_task: vm_task_entry_t, + address: mach_vm_address_t, + size: mach_vm_size_t, + data: *mut vm_offset_t, + dataCnt: *mut mach_msg_type_number_t, + ) -> kern_return_t; + + #[allow(improper_ctypes)] + pub fn mach_vm_read_list( + target_task: vm_task_entry_t, + data_list: mach_vm_read_entry_t, + count: natural_t, + ) -> kern_return_t; + + pub fn mach_vm_write( + target_task: vm_map_t, + address: mach_vm_address_t, + data: vm_offset_t, + dataCnt: mach_msg_type_number_t, + ) -> kern_return_t; + + pub fn mach_vm_copy( + target_task: vm_task_entry_t, + source_address: mach_vm_address_t, + size: mach_vm_size_t, + dest_address: mach_vm_address_t, + ) -> kern_return_t; + + pub fn mach_vm_read_overwrite( + target_task: vm_task_entry_t, + address: mach_vm_address_t, + size: mach_vm_size_t, + data: mach_vm_address_t, + outsize: *mut mach_vm_size_t, + ) -> kern_return_t; + + pub fn mach_vm_msync( + target_task: vm_task_entry_t, + address: mach_vm_address_t, + size: mach_vm_size_t, + sync_flags: vm_sync_t, + ) -> kern_return_t; + + pub fn mach_vm_behavior_set( + target_task: vm_task_entry_t, + address: mach_vm_address_t, + size: mach_vm_size_t, + new_behavior: vm_behavior_t, + ) -> kern_return_t; + + pub fn mach_vm_map( + target_task: vm_task_entry_t, + inout: *mut mach_vm_address_t, + size: mach_vm_size_t, + mask: mach_vm_offset_t, + flags: ::libc::c_int, + object: mem_entry_name_port_t, + offset: memory_object_offset_t, + copy: boolean_t, + cur_protection: vm_prot_t, + max_protection: vm_prot_t, + inheritance: vm_inherit_t, + ) -> kern_return_t; + + pub fn mach_vm_machine_attribute( + target_task: vm_task_entry_t, + address: mach_vm_address_t, + size: mach_vm_size_t, + attribute: vm_machine_attribute_t, + value: *mut vm_machine_attribute_val_t, + ) -> kern_return_t; + + pub fn mach_vm_remap( + target_task: vm_task_entry_t, + target_address: *mut mach_vm_address_t, + size: mach_vm_size_t, + mask: mach_vm_offset_t, + flags: ::libc::c_int, + src_task: vm_task_entry_t, + src_address: mach_vm_address_t, + copy: boolean_t, + cur_protection: *mut vm_prot_t, + out: *mut vm_prot_t, + inheritance: vm_inherit_t, + ) -> kern_return_t; + + pub fn mach_vm_page_query( + target_map: vm_map_t, + offset: mach_vm_offset_t, + disposition: *mut integer_t, + ref_count: *mut integer_t, + ) -> kern_return_t; + + pub fn mach_vm_region_recurse( + target_task: vm_task_entry_t, + address: *mut mach_vm_address_t, + size: *mut mach_vm_size_t, + nesting_depth: *mut natural_t, + info: vm_region_recurse_info_t, + infoCnt: *mut mach_msg_type_number_t, + ) -> kern_return_t; + + pub fn mach_vm_region( + target_task: vm_task_entry_t, + address: *mut mach_vm_address_t, + size: *mut mach_vm_size_t, + flavor: vm_region_flavor_t, + info: vm_region_info_t, + infoCnt: *mut mach_msg_type_number_t, + object_name: *mut mach_port_t, + ) -> kern_return_t; + + pub fn mach_make_memory_entry( + target_task: vm_map_t, + size: *mut vm_size_t, + offset: vm_offset_t, + permission: vm_prot_t, + object_handle: *mut mem_entry_name_port_t, + parent_handle: mem_entry_name_port_t, + ) -> kern_return_t; + + pub fn mach_make_memory_entry_64( + target_task: vm_map_t, + size: *mut memory_object_size_t, + offset: memory_object_offset_t, + permission: vm_prot_t, + object_handle: *mut mach_port_t, + parent_entry: mem_entry_name_port_t, + ) -> kern_return_t; + + pub fn mach_vm_purgable_control( + target_task: vm_task_entry_t, + address: mach_vm_address_t, + control: vm_purgable_t, + state: *mut ::libc::c_int, + ) -> kern_return_t; + + pub fn mach_vm_page_info( + target_task: vm_task_entry_t, + address: mach_vm_address_t, + flavor: vm_page_info_flavor_t, + info: vm_page_info_t, + infoCnt: *mut mach_msg_type_number_t, + ) -> kern_return_t; +} + +#[cfg(test)] +mod tests { + use super::*; + use kern_return::KERN_SUCCESS; + use traps::mach_task_self; + use vm_statistics::VM_FLAGS_ANYWHERE; + + #[test] + fn mach_vm_allocate_sanity() { + unsafe { + let size = 0x100; + let task = mach_task_self(); + + let mut address: mach_vm_address_t = 0; + assert_eq!( + mach_vm_allocate(task, &mut address, size, VM_FLAGS_ANYWHERE), + KERN_SUCCESS + ); + assert_eq!(mach_vm_deallocate(task, address, size), KERN_SUCCESS); + } + } + + #[test] + fn mach_vm_region_sanity() { + use mem; + use vm_prot::{VM_PROT_EXECUTE, VM_PROT_READ}; + use vm_region::{vm_region_basic_info_64, VM_REGION_BASIC_INFO_64}; + unsafe { + let mut size = 0x10; + let mut object_name = 0; + let mut address = mach_vm_region_sanity as mach_vm_address_t; + let mut info: vm_region_basic_info_64 = mem::zeroed(); + let mut info_size = vm_region_basic_info_64::count(); + + let result = mach_vm_region( + mach_task_self(), + &mut address, + &mut size, + VM_REGION_BASIC_INFO_64, + (&mut info as *mut _) as vm_region_info_t, + &mut info_size, + &mut object_name, + ); + assert_eq!(result, KERN_SUCCESS); + assert_eq!(info.protection, VM_PROT_READ | VM_PROT_EXECUTE); + } + } +} diff --git a/vendor/mach2/src/vm_attributes.rs b/vendor/mach2/src/vm_attributes.rs new file mode 100644 index 0000000000000..ba3b0d3c70de2 --- /dev/null +++ b/vendor/mach2/src/vm_attributes.rs @@ -0,0 +1,18 @@ +//! This module corresponds to `mach/vm_attributes.h`. + +pub type vm_machine_attribute_t = ::libc::c_uint; + +pub const MATTR_CACHE: vm_machine_attribute_t = 1; +pub const MATTR_MIGRATE: vm_machine_attribute_t = 1 << 1; +pub const MATTR_REPLICATE: vm_machine_attribute_t = 1 << 2; + +pub type vm_machine_attribute_val_t = ::libc::c_int; + +pub const MATTR_VAL_OFF: vm_machine_attribute_val_t = 0; +pub const MATTR_VAL_ON: vm_machine_attribute_val_t = 1; +pub const MATTR_VAL_GET: vm_machine_attribute_val_t = 2; +pub const MATTR_VAL_CACHE_FLUSH: vm_machine_attribute_val_t = 6; +pub const MATTR_VAL_DCACHE_FLUSH: vm_machine_attribute_val_t = 7; +pub const MATTR_VAL_ICACHE_FLUSH: vm_machine_attribute_val_t = 8; +pub const MATTR_VAL_CACHE_SYNC: vm_machine_attribute_val_t = 9; +pub const MATTR_VAL_GET_INFO: vm_machine_attribute_val_t = 10; diff --git a/vendor/mach2/src/vm_behavior.rs b/vendor/mach2/src/vm_behavior.rs new file mode 100644 index 0000000000000..8ab692e550e9d --- /dev/null +++ b/vendor/mach2/src/vm_behavior.rs @@ -0,0 +1,15 @@ +//! This module corresponds to `mach/vm_behavior.h`. + +pub type vm_behavior_t = ::libc::c_int; + +pub const VM_BEHAVIOR_DEFAULT: vm_behavior_t = 0; +pub const VM_BEHAVIOR_RANDOM: vm_behavior_t = 1; +pub const VM_BEHAVIOR_SEQUENTIAL: vm_behavior_t = 2; +pub const VM_BEHAVIOR_RSEQNTL: vm_behavior_t = 3; +pub const VM_BEHAVIOR_WILLNEED: vm_behavior_t = 4; +pub const VM_BEHAVIOR_DONTNEED: vm_behavior_t = 5; +pub const VM_BEHAVIOR_FREE: vm_behavior_t = 6; +pub const VM_BEHAVIOR_ZERO_WIRED_PAGES: vm_behavior_t = 7; +pub const VM_BEHAVIOR_REUSABLE: vm_behavior_t = 8; +pub const VM_BEHAVIOR_REUSE: vm_behavior_t = 9; +pub const VM_BEHAVIOR_CAN_REUSE: vm_behavior_t = 10; diff --git a/vendor/mach2/src/vm_inherit.rs b/vendor/mach2/src/vm_inherit.rs new file mode 100644 index 0000000000000..4f4c9e5ef734e --- /dev/null +++ b/vendor/mach2/src/vm_inherit.rs @@ -0,0 +1,10 @@ +//! This module corresponds to `mach/vm_inherit.h`. + +pub type vm_inherit_t = ::libc::c_uint; + +pub const VM_INHERIT_SHARE: vm_inherit_t = 0; +pub const VM_INHERIT_COPY: vm_inherit_t = 1; +pub const VM_INHERIT_NONE: vm_inherit_t = 2; +pub const VM_INHERIT_DONATE_COPY: vm_inherit_t = 3; +pub const VM_INHERIT_DEFAULT: vm_inherit_t = VM_INHERIT_COPY; +pub const VM_INHERIT_LAST_VALID: vm_inherit_t = VM_INHERIT_NONE; diff --git a/vendor/mach2/src/vm_page_size.rs b/vendor/mach2/src/vm_page_size.rs new file mode 100644 index 0000000000000..f1ab37fcb4271 --- /dev/null +++ b/vendor/mach2/src/vm_page_size.rs @@ -0,0 +1,40 @@ +//! This module roughly corresponds to `mach/vm_page_size.h` + +use vm_types::{mach_vm_offset_t, mach_vm_size_t, vm_size_t}; + +extern "C" { + pub static vm_page_size: vm_size_t; + pub static vm_page_mask: vm_size_t; + pub static vm_page_shift: ::libc::c_int; +} + +#[allow(clippy::missing_safety_doc)] // FIXME +pub unsafe fn mach_vm_trunc_page(x: mach_vm_offset_t) -> mach_vm_offset_t { + x & !(vm_page_mask as mach_vm_size_t) +} + +#[allow(clippy::missing_safety_doc)] // FIXME +pub unsafe fn mach_vm_round_page(x: mach_vm_offset_t) -> mach_vm_offset_t { + (x + vm_page_mask as mach_vm_size_t) & !(vm_page_mask as mach_vm_size_t) +} + +#[cfg(test)] +mod tests { + use vm_page_size::*; + use vm_types::mach_vm_size_t; + + #[test] + fn page_size() { + unsafe { + assert!(vm_page_size > 0); + assert!(vm_page_size % 2 == 0); + assert_eq!(mach_vm_round_page(1), vm_page_size as mach_vm_size_t); + + #[cfg(target_arch = "aarch64")] + assert_eq!(vm_page_size, 16384); + + #[cfg(not(target_arch = "aarch64"))] + assert_eq!(vm_page_size, 4096); + } + } +} diff --git a/vendor/mach2/src/vm_prot.rs b/vendor/mach2/src/vm_prot.rs new file mode 100644 index 0000000000000..0397d25a1d215 --- /dev/null +++ b/vendor/mach2/src/vm_prot.rs @@ -0,0 +1,13 @@ +//! This module corresponds to `mach/vm_prot.h`. + +pub type vm_prot_t = ::libc::c_int; + +pub const VM_PROT_NONE: vm_prot_t = 0; +pub const VM_PROT_READ: vm_prot_t = 1; +pub const VM_PROT_WRITE: vm_prot_t = 1 << 1; +pub const VM_PROT_EXECUTE: vm_prot_t = 1 << 2; +pub const VM_PROT_NO_CHANGE: vm_prot_t = 1 << 3; +pub const VM_PROT_COPY: vm_prot_t = 1 << 4; +pub const VM_PROT_WANTS_COPY: vm_prot_t = 1 << 4; +pub const VM_PROT_DEFAULT: vm_prot_t = VM_PROT_READ | VM_PROT_WRITE; +pub const VM_PROT_ALL: vm_prot_t = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; diff --git a/vendor/mach2/src/vm_purgable.rs b/vendor/mach2/src/vm_purgable.rs new file mode 100644 index 0000000000000..79fc297cb0427 --- /dev/null +++ b/vendor/mach2/src/vm_purgable.rs @@ -0,0 +1,42 @@ +//! This module corresponds to `mach/vm_purgable.h`. + +pub type vm_purgable_t = ::libc::c_int; + +pub const VM_PURGABLE_SET_STATE: vm_purgable_t = 0; +pub const VM_PURGABLE_GET_STATE: vm_purgable_t = 1; + +pub const VM_VOLATILE_GROUP_SHIFT: ::libc::c_int = 8; +pub const VM_VOLATILE_GROUP_MASK: ::libc::c_int = 7 << VM_VOLATILE_GROUP_SHIFT; +pub const VM_VOLATILE_GROUP_DEFAULT: ::libc::c_int = VM_VOLATILE_GROUP_0; + +pub const VM_VOLATILE_GROUP_0: ::libc::c_int = 0 << VM_VOLATILE_GROUP_SHIFT; +pub const VM_VOLATILE_GROUP_1: ::libc::c_int = 1 << VM_VOLATILE_GROUP_SHIFT; +pub const VM_VOLATILE_GROUP_2: ::libc::c_int = 2 << VM_VOLATILE_GROUP_SHIFT; +pub const VM_VOLATILE_GROUP_3: ::libc::c_int = 3 << VM_VOLATILE_GROUP_SHIFT; +pub const VM_VOLATILE_GROUP_4: ::libc::c_int = 4 << VM_VOLATILE_GROUP_SHIFT; +pub const VM_VOLATILE_GROUP_5: ::libc::c_int = 5 << VM_VOLATILE_GROUP_SHIFT; +pub const VM_VOLATILE_GROUP_6: ::libc::c_int = 6 << VM_VOLATILE_GROUP_SHIFT; +pub const VM_VOLATILE_GROUP_7: ::libc::c_int = 7 << VM_VOLATILE_GROUP_SHIFT; + +pub const VM_PURGABLE_BEHAVIOR_SHIFT: ::libc::c_int = 6; +pub const VM_PURGABLE_BEHAVIOR_MASK: ::libc::c_int = 1 << VM_PURGABLE_BEHAVIOR_SHIFT; +pub const VM_PURGABLE_BEHAVIOR_FIFO: ::libc::c_int = 0 << VM_PURGABLE_BEHAVIOR_SHIFT; +pub const VM_PURGABLE_BEHAVIOR_LIFO: ::libc::c_int = 1 << VM_PURGABLE_BEHAVIOR_SHIFT; + +pub const VM_PURGABLE_ORDERING_SHIFT: ::libc::c_int = 5; +pub const VM_PURGABLE_ORDERING_MASK: ::libc::c_int = 1 << VM_PURGABLE_ORDERING_SHIFT; +pub const VM_PURGABLE_ORDERING_OBSOLETE: ::libc::c_int = 1 << VM_PURGABLE_ORDERING_SHIFT; +pub const VM_PURGABLE_ORDERING_NORMAL: ::libc::c_int = 0 << VM_PURGABLE_ORDERING_SHIFT; + +pub const VM_VOLATILE_ORDER_SHIFT: ::libc::c_int = 4; +pub const VM_VOLATILE_ORDER_MASK: ::libc::c_int = 1 << VM_VOLATILE_ORDER_SHIFT; +pub const VM_VOLATILE_MAKE_FIRST_IN_GROUP: ::libc::c_int = 1 << VM_VOLATILE_ORDER_SHIFT; +pub const VM_VOLATILE_MAKE_LAST_IN_GROUP: ::libc::c_int = 0 << VM_VOLATILE_ORDER_SHIFT; + +pub const VM_PURGABLE_STATE_MIN: ::libc::c_int = 0; +pub const VM_PURGABLE_STATE_MAX: ::libc::c_int = 3; +pub const VM_PURGABLE_STATE_MASK: ::libc::c_int = 3; +pub const VM_PURGABLE_NONVOLATILE: ::libc::c_int = 0; +pub const VM_PURGABLE_VOLATILE: ::libc::c_int = 1; +pub const VM_PURGABLE_EMPTY: ::libc::c_int = 2; +pub const VM_PURGABLE_DENY: ::libc::c_int = 3; diff --git a/vendor/mach2/src/vm_region.rs b/vendor/mach2/src/vm_region.rs new file mode 100644 index 0000000000000..b88b59fc56cf6 --- /dev/null +++ b/vendor/mach2/src/vm_region.rs @@ -0,0 +1,238 @@ +//! This module roughly corresponds to `mach/vm_region.h`. + +use boolean::boolean_t; +use mem; +use memory_object_types::{memory_object_offset_t, vm_object_id_t}; +use message::mach_msg_type_number_t; +use vm_behavior::vm_behavior_t; +use vm_inherit::vm_inherit_t; +use vm_prot::vm_prot_t; +use vm_types::{mach_vm_address_t, mach_vm_size_t}; + +pub type vm32_object_id_t = u32; + +pub type vm_region_info_t = *mut ::libc::c_int; +pub type vm_region_info_64_t = *mut ::libc::c_int; +pub type vm_region_recurse_info_t = *mut ::libc::c_int; +pub type vm_region_recurse_info_64_t = *mut ::libc::c_int; +pub type vm_region_flavor_t = ::libc::c_int; +pub type vm_region_info_data_t = [::libc::c_int; VM_REGION_INFO_MAX as usize]; + +pub type vm_region_basic_info_64_t = *mut vm_region_basic_info_64; +pub type vm_region_basic_info_data_64_t = vm_region_basic_info_64; +pub type vm_region_basic_info_t = *mut vm_region_basic_info; +pub type vm_region_basic_info_data_t = vm_region_basic_info; +pub type vm_region_extended_info_t = *mut vm_region_extended_info; +pub type vm_region_extended_info_data_t = vm_region_extended_info; +pub type vm_region_top_info_t = *mut vm_region_top_info; +pub type vm_region_top_info_data_t = vm_region_top_info; +pub type vm_region_submap_info_t = *mut vm_region_submap_info; +pub type vm_region_submap_info_data_t = vm_region_submap_info; +pub type vm_region_submap_info_64_t = *mut vm_region_submap_info_64; +pub type vm_region_submap_info_data_64_t = vm_region_submap_info_64; +pub type vm_region_submap_short_info_64_t = *mut vm_region_submap_short_info_64; +pub type vm_region_submap_short_info_data_64_t = vm_region_submap_short_info_64; +pub type vm_page_info_t = *mut ::libc::c_int; +pub type vm_page_info_flavor_t = ::libc::c_int; +pub type vm_page_info_basic_t = *mut vm_page_info_basic; +pub type vm_page_info_basic_data_t = vm_page_info_basic; +pub type mach_vm_read_entry_t = [mach_vm_read_entry; VM_MAP_ENTRY_MAX as usize]; + +pub const VM_REGION_INFO_MAX: ::libc::c_int = 1 << 10; +pub const VM_MAP_ENTRY_MAX: ::libc::c_int = 1 << 8; + +pub const VM_PAGE_INFO_BASIC: vm_page_info_flavor_t = 1; + +pub const VM_REGION_BASIC_INFO_64: vm_region_flavor_t = 9; +pub const VM_REGION_BASIC_INFO: vm_region_flavor_t = 10; +pub const VM_REGION_EXTENDED_INFO: vm_region_flavor_t = 13; +pub const VM_REGION_TOP_INFO: vm_region_flavor_t = 12; + +pub const SM_COW: ::libc::c_uchar = 1; +pub const SM_PRIVATE: ::libc::c_uchar = 2; +pub const SM_EMPTY: ::libc::c_uchar = 3; +pub const SM_SHARED: ::libc::c_uchar = 4; +pub const SM_TRUESHARED: ::libc::c_uchar = 5; +pub const SM_PRIVATE_ALIASED: ::libc::c_uchar = 6; +pub const SM_SHARED_ALIASED: ::libc::c_uchar = 7; + +#[repr(C, packed(4))] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct vm_region_basic_info_64 { + pub protection: vm_prot_t, + pub max_protection: vm_prot_t, + pub inheritance: vm_inherit_t, + pub shared: boolean_t, + pub reserved: boolean_t, + pub offset: memory_object_offset_t, + pub behavior: vm_behavior_t, + pub user_wired_count: ::libc::c_ushort, +} + +impl vm_region_basic_info_64 { + pub fn count() -> mach_msg_type_number_t { + (mem::size_of::() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct vm_region_basic_info { + pub protection: vm_prot_t, + pub max_protection: vm_prot_t, + pub inheritance: vm_inherit_t, + pub shared: boolean_t, + pub reserved: boolean_t, + pub offset: u32, + pub behavior: vm_behavior_t, + pub user_wired_count: ::libc::c_ushort, +} + +impl vm_region_basic_info { + pub fn count() -> mach_msg_type_number_t { + (mem::size_of::() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct vm_region_extended_info { + pub protection: vm_prot_t, + pub user_tag: ::libc::c_uint, + pub pages_resident: ::libc::c_uint, + pub pages_shared_now_private: ::libc::c_uint, + pub pages_swapped_out: ::libc::c_uint, + pub pages_dirtied: ::libc::c_uint, + pub ref_count: ::libc::c_uint, + pub shadow_depth: ::libc::c_ushort, + pub external_pager: ::libc::c_uchar, + pub share_mode: ::libc::c_uchar, + pub pages_reusable: ::libc::c_uint, +} + +impl vm_region_extended_info { + pub fn count() -> mach_msg_type_number_t { + (mem::size_of::() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct vm_region_top_info { + pub obj_id: ::libc::c_uint, + pub ref_count: ::libc::c_uint, + pub private_pages_resident: ::libc::c_uint, + pub shared_pages_resident: ::libc::c_uint, + pub share_mode: ::libc::c_uchar, +} + +impl vm_region_top_info { + pub fn count() -> mach_msg_type_number_t { + (mem::size_of::() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct vm_region_submap_info { + pub protection: vm_prot_t, + pub max_protection: vm_prot_t, + pub inheritance: vm_inherit_t, + pub offset: u32, + pub user_tag: ::libc::c_uint, + pub pages_resident: ::libc::c_uint, + pub pages_shared_now_private: ::libc::c_uint, + pub pages_swapped_out: ::libc::c_uint, + pub pages_dirtied: ::libc::c_uint, + pub ref_count: ::libc::c_uint, + pub shadow_depth: ::libc::c_ushort, + pub external_pager: ::libc::c_uchar, + pub share_mode: ::libc::c_uchar, + pub is_submap: boolean_t, + pub behavior: vm_behavior_t, + pub object_id: vm32_object_id_t, + pub user_wired_count: ::libc::c_ushort, +} + +impl vm_region_submap_info { + pub fn count() -> mach_msg_type_number_t { + (mem::size_of::() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t + } +} + +#[repr(C, packed(4))] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct vm_region_submap_info_64 { + pub protection: vm_prot_t, + pub max_protection: vm_prot_t, + pub inheritance: vm_inherit_t, + pub offset: memory_object_offset_t, + pub user_tag: ::libc::c_uint, + pub pages_resident: ::libc::c_uint, + pub pages_shared_now_private: ::libc::c_uint, + pub pages_swapped_out: ::libc::c_uint, + pub pages_dirtied: ::libc::c_uint, + pub ref_count: ::libc::c_uint, + pub shadow_depth: ::libc::c_ushort, + pub external_pager: ::libc::c_uchar, + pub share_mode: ::libc::c_uchar, + pub is_submap: boolean_t, + pub behavior: vm_behavior_t, + pub object_id: vm32_object_id_t, + pub user_wired_count: ::libc::c_ushort, + pub pages_reusable: ::libc::c_uint, +} + +impl vm_region_submap_info_64 { + pub fn count() -> mach_msg_type_number_t { + (mem::size_of::() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t + } +} + +#[repr(C, packed(4))] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct vm_region_submap_short_info_64 { + pub protection: vm_prot_t, + pub max_protection: vm_prot_t, + pub inheritance: vm_inherit_t, + pub offset: memory_object_offset_t, + pub user_tag: ::libc::c_uint, + pub ref_count: ::libc::c_uint, + pub shadow_depth: ::libc::c_ushort, + pub external_pager: ::libc::c_uchar, + pub share_mode: ::libc::c_uchar, + pub is_submap: boolean_t, + pub behavior: vm_behavior_t, + pub object_id: vm32_object_id_t, + pub user_wired_count: ::libc::c_ushort, +} + +impl vm_region_submap_short_info_64 { + pub fn count() -> mach_msg_type_number_t { + (mem::size_of::() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct vm_page_info_basic { + pub disposition: ::libc::c_int, + pub ref_count: ::libc::c_int, + pub object_id: vm_object_id_t, + pub offset: memory_object_offset_t, + pub depth: ::libc::c_int, + pub __pad: ::libc::c_int, +} + +impl vm_page_info_basic { + pub fn count() -> mach_msg_type_number_t { + (mem::size_of::() / mem::size_of::<::libc::c_int>()) as mach_msg_type_number_t + } +} + +#[repr(C, packed(4))] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct mach_vm_read_entry { + pub address: mach_vm_address_t, + pub size: mach_vm_size_t, +} diff --git a/vendor/mach2/src/vm_statistics.rs b/vendor/mach2/src/vm_statistics.rs new file mode 100644 index 0000000000000..bd138ca044a2b --- /dev/null +++ b/vendor/mach2/src/vm_statistics.rs @@ -0,0 +1,58 @@ +//! This module roughly corresponds to `mach/vm_statistics.h` + +use vm_types::{integer_t, natural_t}; + +pub type vm_statistics_t = *mut vm_statistics; +pub type vm_statistics_data_t = vm_statistics; + +pub const VM_PAGE_QUERY_PAGE_PRESENT: integer_t = 1; +pub const VM_PAGE_QUERY_PAGE_FICTITIOUS: integer_t = 1 << 1; +pub const VM_PAGE_QUERY_PAGE_REF: integer_t = 1 << 2; +pub const VM_PAGE_QUERY_PAGE_DIRTY: integer_t = 1 << 3; + +pub const VM_MEMORY_MALLOC: ::libc::c_uint = 1; +pub const VM_MEMORY_MALLOC_SMALL: ::libc::c_uint = 2; +pub const VM_MEMORY_MALLOC_LARGE: ::libc::c_uint = 3; +pub const VM_MEMORY_MALLOC_HUGE: ::libc::c_uint = 4; +pub const VM_MEMORY_SBRK: ::libc::c_uint = 5; +pub const VM_MEMORY_ANALYSIS_TOOL: ::libc::c_uint = 10; +pub const VM_MEMORY_MACH_MSG: ::libc::c_uint = 20; +pub const VM_MEMORY_IOKIT: ::libc::c_uint = 21; +pub const VM_MEMORY_STACK: ::libc::c_uint = 30; +pub const VM_MEMORY_GUARD: ::libc::c_uint = 31; +pub const VM_MEMORY_SHARED_PMAP: ::libc::c_uint = 32; +pub const VM_MEMORY_DYLIB: ::libc::c_uint = 33; +pub const VM_MEMORY_APPKIT: ::libc::c_uint = 40; +pub const VM_MEMORY_FOUNDATION: ::libc::c_uint = 41; +pub const VM_MEMORY_COREGRAPHICS: ::libc::c_uint = 42; +pub const VM_MEMORY_CARBON: ::libc::c_uint = 43; +pub const VM_MEMORY_JAVA: ::libc::c_uint = 44; +pub const VM_MEMORY_ATS: ::libc::c_uint = 50; +pub const VM_MEMORY_DYLD: ::libc::c_uint = 60; +pub const VM_MEMORY_DYLD_MALLOC: ::libc::c_uint = 61; +pub const VM_MEMORY_APPLICATION_SPECIFIC_1: ::libc::c_uint = 240; +pub const VM_MEMORY_APPLICATION_SPECIFIC_16: ::libc::c_uint = 255; + +pub const VM_FLAGS_FIXED: ::libc::c_int = 0x0; +pub const VM_FLAGS_ANYWHERE: ::libc::c_int = 0x1; +pub const VM_FLAGS_OVERWRITE: ::libc::c_int = 0x4000; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] +pub struct vm_statistics { + pub free_count: natural_t, + pub active_count: natural_t, + pub inactive_count: natural_t, + pub wire_count: natural_t, + pub zero_fill_count: natural_t, + pub reactivations: natural_t, + pub pageins: natural_t, + pub pageouts: natural_t, + pub faults: natural_t, + pub cow_faults: natural_t, + pub lookups: natural_t, + pub hits: natural_t, + pub purgeable_count: natural_t, + pub purges: natural_t, + pub speculative_count: natural_t, +} diff --git a/vendor/mach2/src/vm_sync.rs b/vendor/mach2/src/vm_sync.rs new file mode 100644 index 0000000000000..c562397358b8d --- /dev/null +++ b/vendor/mach2/src/vm_sync.rs @@ -0,0 +1,11 @@ +//! This module corresponds to `mach/vm_sync.h`. + +pub type vm_sync_t = ::libc::c_uint; + +pub const VM_SYNC_ASYNCHRONOUS: vm_sync_t = 1; +pub const VM_SYNC_SYNCHRONOUS: vm_sync_t = 1 << 1; +pub const VM_SYNC_INVALIDATE: vm_sync_t = 1 << 2; +pub const VM_SYNC_KILLPAGES: vm_sync_t = 1 << 3; +pub const VM_SYNC_DEACTIVATE: vm_sync_t = 1 << 4; +pub const VM_SYNC_CONTIGUOUS: vm_sync_t = 1 << 5; +pub const VM_SYNC_REUSABLEPAGES: vm_sync_t = 1 << 6; diff --git a/vendor/mach2/src/vm_types.rs b/vendor/mach2/src/vm_types.rs new file mode 100644 index 0000000000000..e37b9804c4bc8 --- /dev/null +++ b/vendor/mach2/src/vm_types.rs @@ -0,0 +1,19 @@ +//! This module roughly corresponds to `mach/i386/vm_types.h`. + +pub type natural_t = ::libc::c_uint; +pub type integer_t = ::libc::c_int; + +pub type user_addr_t = u64; + +pub type mach_vm_address_t = u64; +pub type mach_vm_offset_t = u64; +pub type mach_vm_size_t = u64; +pub type vm_map_offset_t = u64; +pub type vm_map_address_t = u64; +pub type vm_map_size_t = u64; +pub type vm_map_t = ::port::mach_port_t; +pub type vm_offset_t = ::libc::uintptr_t; +pub type vm_size_t = ::libc::uintptr_t; +pub type vm_address_t = vm_offset_t; + +pub type mach_port_context_t = mach_vm_address_t; diff --git a/vendor/malloc_buf/.cargo-checksum.json b/vendor/malloc_buf/.cargo-checksum.json new file mode 100644 index 0000000000000..70cd125dfeaee --- /dev/null +++ b/vendor/malloc_buf/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"d87624d9d117489bd49dbaeb70077a0721e00ac2a76eb371faec818a92da5661","src/lib.rs":"1130dacbe045a20c1ea1e65e00976f18eb7513da492b07d538e7b1b5c64b8842"},"package":"62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"} \ No newline at end of file diff --git a/vendor/malloc_buf/Cargo.toml b/vendor/malloc_buf/Cargo.toml new file mode 100644 index 0000000000000..cfb0c082d8748 --- /dev/null +++ b/vendor/malloc_buf/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "malloc_buf" +version = "0.0.6" +authors = ["Steven Sheldon"] + +description = "Structs for handling malloc'd memory passed to Rust." +repository = "https://github.com/SSheldon/malloc_buf" +documentation = "http://ssheldon.github.io/malloc_buf/malloc_buf/" +license = "MIT" + +exclude = [".gitignore"] + +[dependencies] +libc = ">= 0.1, < 0.3" diff --git a/vendor/malloc_buf/src/lib.rs b/vendor/malloc_buf/src/lib.rs new file mode 100644 index 0000000000000..24066b69d418d --- /dev/null +++ b/vendor/malloc_buf/src/lib.rs @@ -0,0 +1,95 @@ +extern crate libc; + +use std::marker::PhantomData; +use std::ops::Deref; +use std::slice; +use libc::c_void; + +struct MallocPtr(*mut c_void); + +impl Drop for MallocPtr { + fn drop(&mut self) { + unsafe { + libc::free(self.0); + } + } +} + +/// A type that represents a `malloc`'d chunk of memory. +pub struct MallocBuffer { + ptr: MallocPtr, + len: usize, + items: PhantomData<[T]>, +} + +impl MallocBuffer { + /// Constructs a new `MallocBuffer` for a `malloc`'d buffer + /// with the given length at the given pointer. + /// Returns `None` if the given pointer is null and the length is not 0. + /// + /// When this `MallocBuffer` drops, the buffer will be `free`'d. + /// + /// Unsafe because there must be `len` contiguous, valid instances of `T` + /// at `ptr`. + pub unsafe fn new(ptr: *mut T, len: usize) -> Option> { + if len > 0 && ptr.is_null() { + None + } else { + Some(MallocBuffer { + ptr: MallocPtr(ptr as *mut c_void), + len: len, + items: PhantomData, + }) + } + } +} + +impl Deref for MallocBuffer { + type Target = [T]; + + fn deref(&self) -> &[T] { + let ptr = if self.len == 0 && self.ptr.0.is_null() { + // Even a 0-size slice cannot be null, so just use another pointer + 0x1 as *const T + } else { + self.ptr.0 as *const T + }; + unsafe { + slice::from_raw_parts(ptr, self.len) + } + } +} + +#[cfg(test)] +mod tests { + use std::ptr; + use libc; + + use super::MallocBuffer; + + #[test] + fn test_null_buf() { + let buf = unsafe { + MallocBuffer::::new(ptr::null_mut(), 0).unwrap() + }; + assert!(&*buf == []); + assert!(Some(&*buf) == Some(&[])); + + let buf = unsafe { + MallocBuffer::::new(ptr::null_mut(), 7) + }; + assert!(buf.is_none()); + } + + #[test] + fn test_buf() { + let buf = unsafe { + let ptr = libc::malloc(12) as *mut u32; + *ptr = 1; + *ptr.offset(1) = 2; + *ptr.offset(2) = 3; + MallocBuffer::new(ptr, 3).unwrap() + }; + assert!(&*buf == [1, 2, 3]); + } +} diff --git a/vendor/memchr/src/tests/x86_64-soft_float.json b/vendor/memchr/src/tests/x86_64-soft_float.json new file mode 100644 index 0000000000000..b77649ef92480 --- /dev/null +++ b/vendor/memchr/src/tests/x86_64-soft_float.json @@ -0,0 +1,15 @@ +{ + "llvm-target": "x86_64-unknown-none", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "arch": "x86_64", + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float", + "executables": true, + "disable-redzone": true, + "panic-strategy": "abort" +} diff --git a/vendor/memoffset-0.7.1/.cargo-checksum.json b/vendor/memoffset-0.7.1/.cargo-checksum.json new file mode 100644 index 0000000000000..60f2c0932bb8b --- /dev/null +++ b/vendor/memoffset-0.7.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"2122b76e5dff09497c7edf7f184155e456e44209c05e4f8abb01632be7241b56","LICENSE":"3234ac55816264ee7b6c7ee27efd61cf0a1fe775806870e3d9b4c41ea73c5cb1","README.md":"7a7935d96a1a40b56afeadca391c742f7ac3a6e0f1deab1d43430553f71b6d23","build.rs":"6d677e33a1c98d588c97ec7985d4d5c3b954683e0a73c3dc53d79db4fbb5e638","src/lib.rs":"e7976d295371a3c1e0cf31b0d50210cd6b1135caba3a5111403a97ec6175c0a2","src/offset_of.rs":"ea04e76e3ab1fa192618fffb0c6a047795c275f1deaf6c6617245badaba8660c","src/raw_field.rs":"ef54087d5f507c2b639a4f61f2881eb1e41a46e22191ffd0e23b2fe9e3f17c25","src/span_of.rs":"b900faef2b852b52c37c55a172c05c9144bfff7d84dbc06e943fb0453d68adfc"},"package":"5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"} \ No newline at end of file diff --git a/vendor/memoffset-0.7.1/Cargo.toml b/vendor/memoffset-0.7.1/Cargo.toml new file mode 100644 index 0000000000000..1677446a88b00 --- /dev/null +++ b/vendor/memoffset-0.7.1/Cargo.toml @@ -0,0 +1,36 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +name = "memoffset" +version = "0.7.1" +authors = ["Gilad Naaman "] +description = "offset_of functionality for Rust structs." +readme = "README.md" +keywords = [ + "mem", + "offset", + "offset_of", + "offsetof", +] +categories = ["no-std"] +license = "MIT" +repository = "https://github.com/Gilnaa/memoffset" + +[dev-dependencies.doc-comment] +version = "0.3" + +[build-dependencies.autocfg] +version = "1" + +[features] +default = [] +unstable_const = [] diff --git a/vendor/memoffset-0.7.1/LICENSE b/vendor/memoffset-0.7.1/LICENSE new file mode 100644 index 0000000000000..61f608134a6bf --- /dev/null +++ b/vendor/memoffset-0.7.1/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2017 Gilad Naaman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/memoffset-0.7.1/README.md b/vendor/memoffset-0.7.1/README.md new file mode 100644 index 0000000000000..e297b33d51005 --- /dev/null +++ b/vendor/memoffset-0.7.1/README.md @@ -0,0 +1,65 @@ +# memoffset # + +[![](https://img.shields.io/crates/v/memoffset.svg)](https://crates.io/crates/memoffset) + +C-Like `offset_of` functionality for Rust structs. + +Introduces the following macros: + * `offset_of!` for obtaining the offset of a member of a struct. + * `offset_of_tuple!` for obtaining the offset of a member of a tuple. (Requires Rust 1.20+) + * `span_of!` for obtaining the range that a field, or fields, span. + +`memoffset` works under `no_std` environments. + +## Usage ## +Add the following dependency to your `Cargo.toml`: + +```toml +[dependencies] +memoffset = "0.7" +``` + +These versions will compile fine with rustc versions greater or equal to 1.19. + +## Examples ## +```rust +use memoffset::{offset_of, span_of}; + +#[repr(C, packed)] +struct Foo { + a: u32, + b: u32, + c: [u8; 5], + d: u32, +} + +fn main() { + assert_eq!(offset_of!(Foo, b), 4); + assert_eq!(offset_of!(Foo, d), 4+4+5); + + assert_eq!(span_of!(Foo, a), 0..4); + assert_eq!(span_of!(Foo, a .. c), 0..8); + assert_eq!(span_of!(Foo, a ..= c), 0..13); + assert_eq!(span_of!(Foo, ..= d), 0..17); + assert_eq!(span_of!(Foo, b ..), 4..17); +} +``` + +## Feature flags ## + +### Usage in constants ### +`memoffset` has **experimental** support for compile-time `offset_of!` on a nightly compiler. + +In order to use it, you must enable the `unstable_const` crate feature and several compiler features. + +Cargo.toml: +```toml +[dependencies.memoffset] +version = "0.7" +features = ["unstable_const"] +``` + +Your crate root: (`lib.rs`/`main.rs`) +```rust,ignore +#![feature(const_ptr_offset_from, const_refs_to_cell)] +``` diff --git a/vendor/memoffset-0.7.1/build.rs b/vendor/memoffset-0.7.1/build.rs new file mode 100644 index 0000000000000..0604c1954efbf --- /dev/null +++ b/vendor/memoffset-0.7.1/build.rs @@ -0,0 +1,22 @@ +extern crate autocfg; + +fn main() { + let ac = autocfg::new(); + + // Check for a minimum version for a few features + if ac.probe_rustc_version(1, 20) { + println!("cargo:rustc-cfg=tuple_ty"); + } + if ac.probe_rustc_version(1, 31) { + println!("cargo:rustc-cfg=allow_clippy"); + } + if ac.probe_rustc_version(1, 36) { + println!("cargo:rustc-cfg=maybe_uninit"); + } + if ac.probe_rustc_version(1, 40) { + println!("cargo:rustc-cfg=doctests"); + } + if ac.probe_rustc_version(1, 51) { + println!("cargo:rustc-cfg=raw_ref_macros"); + } +} diff --git a/vendor/memoffset-0.7.1/src/lib.rs b/vendor/memoffset-0.7.1/src/lib.rs new file mode 100644 index 0000000000000..d80ff17437f9b --- /dev/null +++ b/vendor/memoffset-0.7.1/src/lib.rs @@ -0,0 +1,92 @@ +// Copyright (c) 2017 Gilad Naaman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +//! A crate used for calculating offsets of struct members and their spans. +//! +//! This functionality currently can not be used in compile time code such as `const` or `const fn` definitions. +//! +//! ## Examples +//! ``` +//! use memoffset::{offset_of, span_of}; +//! +//! #[repr(C, packed)] +//! struct HelpMeIAmTrappedInAStructFactory { +//! help_me_before_they_: [u8; 15], +//! a: u32 +//! } +//! +//! fn main() { +//! assert_eq!(offset_of!(HelpMeIAmTrappedInAStructFactory, a), 15); +//! assert_eq!(span_of!(HelpMeIAmTrappedInAStructFactory, a), 15..19); +//! assert_eq!(span_of!(HelpMeIAmTrappedInAStructFactory, help_me_before_they_ .. a), 0..15); +//! } +//! ``` +//! +//! This functionality can be useful, for example, for checksum calculations: +//! +//! ```ignore +//! #[repr(C, packed)] +//! struct Message { +//! header: MessageHeader, +//! fragment_index: u32, +//! fragment_count: u32, +//! payload: [u8; 1024], +//! checksum: u16 +//! } +//! +//! let checksum_range = &raw[span_of!(Message, header..checksum)]; +//! let checksum = crc16(checksum_range); +//! ``` + +#![no_std] +#![cfg_attr( + feature = "unstable_const", + feature(const_ptr_offset_from, const_refs_to_cell) +)] + +#[macro_use] +#[cfg(doctests)] +#[cfg(doctest)] +extern crate doc_comment; +#[cfg(doctests)] +#[cfg(doctest)] +doctest!("../README.md"); + +/// Hidden module for things the macros need to access. +#[doc(hidden)] +pub mod __priv { + #[doc(hidden)] + pub use core::mem; + #[doc(hidden)] + pub use core::ptr; + + /// Use type inference to obtain the size of the pointee (without actually using the pointer). + #[doc(hidden)] + pub fn size_of_pointee(_ptr: *const T) -> usize { + mem::size_of::() + } +} + +#[macro_use] +mod raw_field; +#[macro_use] +mod offset_of; +#[macro_use] +mod span_of; diff --git a/vendor/memoffset-0.7.1/src/offset_of.rs b/vendor/memoffset-0.7.1/src/offset_of.rs new file mode 100644 index 0000000000000..d070181ce7bf5 --- /dev/null +++ b/vendor/memoffset-0.7.1/src/offset_of.rs @@ -0,0 +1,356 @@ +// Copyright (c) 2017 Gilad Naaman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +/// Macro to create a local `base_ptr` raw pointer of the given type, avoiding UB as +/// much as is possible currently. +#[cfg(maybe_uninit)] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset__let_base_ptr { + ($name:ident, $type:ty) => { + // No UB here, and the pointer does not dangle, either. + // But we have to make sure that `uninit` lives long enough, + // so it has to be in the same scope as `$name`. That's why + // `let_base_ptr` declares a variable (several, actually) + // instead of returning one. + let uninit = $crate::__priv::mem::MaybeUninit::<$type>::uninit(); + let $name: *const $type = uninit.as_ptr(); + }; +} +#[cfg(not(maybe_uninit))] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset__let_base_ptr { + ($name:ident, $type:ty) => { + // No UB right here, but we will later dereference this pointer to + // offset into a field, and that is UB because the pointer is dangling. + let $name = $crate::__priv::mem::align_of::<$type>() as *const $type; + }; +} + +/// Macro to compute the distance between two pointers. +#[cfg(feature = "unstable_const")] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset_offset_from_unsafe { + ($field:expr, $base:expr) => {{ + let field = $field; // evaluate $field outside the `unsafe` block + let base = $base; // evaluate $base outside the `unsafe` block + // Compute offset, with unstable `offset_from` for const-compatibility. + // (Requires the pointers to not dangle, but we already need that for `raw_field!` anyway.) + unsafe { (field as *const u8).offset_from(base as *const u8) as usize } + }}; +} +#[cfg(not(feature = "unstable_const"))] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset_offset_from_unsafe { + ($field:expr, $base:expr) => { + // Compute offset. + ($field as usize) - ($base as usize) + }; +} + +/// Calculates the offset of the specified field from the start of the named struct. +/// +/// ## Examples +/// ``` +/// use memoffset::offset_of; +/// +/// #[repr(C, packed)] +/// struct Foo { +/// a: u32, +/// b: u64, +/// c: [u8; 5] +/// } +/// +/// fn main() { +/// assert_eq!(offset_of!(Foo, a), 0); +/// assert_eq!(offset_of!(Foo, b), 4); +/// } +/// ``` +/// +/// ## Notes +/// Rust's ABI is unstable, and [type layout can be changed with each +/// compilation](https://doc.rust-lang.org/reference/type-layout.html). +/// +/// Using `offset_of!` with a `repr(Rust)` struct will return the correct offset of the +/// specified `field` for a particular compilation, but the exact value may change +/// based on the compiler version, concrete struct type, time of day, or rustc's mood. +/// +/// As a result, the value should not be retained and used between different compilations. +#[macro_export(local_inner_macros)] +macro_rules! offset_of { + ($parent:path, $field:tt) => {{ + // Get a base pointer (non-dangling if rustc supports `MaybeUninit`). + _memoffset__let_base_ptr!(base_ptr, $parent); + // Get field pointer. + let field_ptr = raw_field!(base_ptr, $parent, $field); + // Compute offset. + _memoffset_offset_from_unsafe!(field_ptr, base_ptr) + }}; +} + +/// Calculates the offset of the specified field from the start of the tuple. +/// +/// ## Examples +/// ``` +/// use memoffset::offset_of_tuple; +/// +/// fn main() { +/// assert!(offset_of_tuple!((u8, u32), 1) >= 0, "Tuples do not have a defined layout"); +/// } +/// ``` +#[cfg(tuple_ty)] +#[macro_export(local_inner_macros)] +macro_rules! offset_of_tuple { + ($parent:ty, $field:tt) => {{ + // Get a base pointer (non-dangling if rustc supports `MaybeUninit`). + _memoffset__let_base_ptr!(base_ptr, $parent); + // Get field pointer. + let field_ptr = raw_field_tuple!(base_ptr, $parent, $field); + // Compute offset. + _memoffset_offset_from_unsafe!(field_ptr, base_ptr) + }}; +} + +/// Calculates the offset of the specified union member from the start of the union. +/// +/// ## Examples +/// ``` +/// use memoffset::offset_of_union; +/// +/// #[repr(C, packed)] +/// union Foo { +/// foo32: i32, +/// foo64: i64, +/// } +/// +/// fn main() { +/// assert!(offset_of_union!(Foo, foo64) == 0); +/// } +/// ``` +/// +/// ## Note +/// Due to macro_rules limitations, this macro will accept structs with a single field as well as unions. +/// This is not a stable guarantee, and future versions of this crate might fail +/// on any use of this macro with a struct, without a semver bump. +#[macro_export(local_inner_macros)] +macro_rules! offset_of_union { + ($parent:path, $field:tt) => {{ + // Get a base pointer (non-dangling if rustc supports `MaybeUninit`). + _memoffset__let_base_ptr!(base_ptr, $parent); + // Get field pointer. + let field_ptr = raw_field_union!(base_ptr, $parent, $field); + // Compute offset. + _memoffset_offset_from_unsafe!(field_ptr, base_ptr) + }}; +} + +#[cfg(test)] +mod tests { + #[test] + fn offset_simple() { + #[repr(C)] + struct Foo { + a: u32, + b: [u8; 2], + c: i64, + } + + assert_eq!(offset_of!(Foo, a), 0); + assert_eq!(offset_of!(Foo, b), 4); + assert_eq!(offset_of!(Foo, c), 8); + } + + #[test] + #[cfg_attr(miri, ignore)] // this creates unaligned references + fn offset_simple_packed() { + #[repr(C, packed)] + struct Foo { + a: u32, + b: [u8; 2], + c: i64, + } + + assert_eq!(offset_of!(Foo, a), 0); + assert_eq!(offset_of!(Foo, b), 4); + assert_eq!(offset_of!(Foo, c), 6); + } + + #[test] + fn tuple_struct() { + #[repr(C)] + struct Tup(i32, i32); + + assert_eq!(offset_of!(Tup, 0), 0); + assert_eq!(offset_of!(Tup, 1), 4); + } + + #[test] + fn offset_union() { + // Since we're specifying repr(C), all fields are supposed to be at offset 0 + #[repr(C)] + union Foo { + a: u32, + b: [u8; 2], + c: i64, + } + + assert_eq!(offset_of_union!(Foo, a), 0); + assert_eq!(offset_of_union!(Foo, b), 0); + assert_eq!(offset_of_union!(Foo, c), 0); + } + + #[test] + fn path() { + mod sub { + #[repr(C)] + pub struct Foo { + pub x: u32, + } + } + + assert_eq!(offset_of!(sub::Foo, x), 0); + } + + #[test] + fn inside_generic_method() { + struct Pair(T, U); + + fn foo(_: Pair) -> usize { + offset_of!(Pair, 1) + } + + assert_eq!(foo(Pair(0, 0)), 4); + } + + #[cfg(tuple_ty)] + #[test] + fn test_tuple_offset() { + let f = (0i32, 0.0f32, 0u8); + let f_ptr = &f as *const _; + let f1_ptr = &f.1 as *const _; + + assert_eq!( + f1_ptr as usize - f_ptr as usize, + offset_of_tuple!((i32, f32, u8), 1) + ); + } + + #[test] + fn test_raw_field() { + #[repr(C)] + struct Foo { + a: u32, + b: [u8; 2], + c: i64, + } + + let f: Foo = Foo { + a: 0, + b: [0, 0], + c: 0, + }; + let f_ptr = &f as *const _; + assert_eq!(f_ptr as usize + 0, raw_field!(f_ptr, Foo, a) as usize); + assert_eq!(f_ptr as usize + 4, raw_field!(f_ptr, Foo, b) as usize); + assert_eq!(f_ptr as usize + 8, raw_field!(f_ptr, Foo, c) as usize); + } + + #[cfg(tuple_ty)] + #[test] + fn test_raw_field_tuple() { + let t = (0u32, 0u8, false); + let t_ptr = &t as *const _; + let t_addr = t_ptr as usize; + + assert_eq!( + &t.0 as *const _ as usize - t_addr, + raw_field_tuple!(t_ptr, (u32, u8, bool), 0) as usize - t_addr + ); + assert_eq!( + &t.1 as *const _ as usize - t_addr, + raw_field_tuple!(t_ptr, (u32, u8, bool), 1) as usize - t_addr + ); + assert_eq!( + &t.2 as *const _ as usize - t_addr, + raw_field_tuple!(t_ptr, (u32, u8, bool), 2) as usize - t_addr + ); + } + + #[test] + fn test_raw_field_union() { + #[repr(C)] + union Foo { + a: u32, + b: [u8; 2], + c: i64, + } + + let f = Foo { a: 0 }; + let f_ptr = &f as *const _; + assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, a) as usize); + assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, b) as usize); + assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, c) as usize); + } + + #[cfg(feature = "unstable_const")] + #[test] + fn const_offset() { + #[repr(C)] + struct Foo { + a: u32, + b: [u8; 2], + c: i64, + } + + assert_eq!([0; offset_of!(Foo, b)].len(), 4); + } + + #[cfg(feature = "unstable_const")] + #[test] + fn const_offset_interior_mutable() { + #[repr(C)] + struct Foo { + a: u32, + b: core::cell::Cell, + } + + assert_eq!([0; offset_of!(Foo, b)].len(), 4); + } + + #[cfg(feature = "unstable_const")] + #[test] + fn const_fn_offset() { + const fn test_fn() -> usize { + #[repr(C)] + struct Foo { + a: u32, + b: [u8; 2], + c: i64, + } + + offset_of!(Foo, b) + } + + assert_eq!([0; test_fn()].len(), 4); + } +} diff --git a/vendor/memoffset-0.7.1/src/raw_field.rs b/vendor/memoffset-0.7.1/src/raw_field.rs new file mode 100644 index 0000000000000..e16df9f28c82c --- /dev/null +++ b/vendor/memoffset-0.7.1/src/raw_field.rs @@ -0,0 +1,226 @@ +// Copyright (c) 2020 Gilad Naaman, Ralf Jung +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +/// `addr_of!`, or just ref-then-cast when that is not available. +#[cfg(raw_ref_macros)] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset__addr_of { + ($path:expr) => {{ + $crate::__priv::ptr::addr_of!($path) + }}; +} +#[cfg(not(raw_ref_macros))] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset__addr_of { + ($path:expr) => {{ + // This is UB because we create an intermediate reference to uninitialized memory. + // Nothing we can do about that without `addr_of!` though. + &$path as *const _ + }}; +} + +/// Deref-coercion protection macro. +/// +/// Prevents complilation if the specified field name is not a part of the +/// struct definition. +/// +/// ```compile_fail +/// use memoffset::_memoffset__field_check; +/// +/// struct Foo { +/// foo: i32, +/// } +/// +/// type BoxedFoo = Box; +/// +/// _memoffset__field_check!(BoxedFoo, foo); +/// ``` +#[cfg(allow_clippy)] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset__field_check { + ($type:path, $field:tt) => { + // Make sure the field actually exists. This line ensures that a + // compile-time error is generated if $field is accessed through a + // Deref impl. + #[allow(clippy::unneeded_field_pattern)] + let $type { $field: _, .. }; + }; +} +#[cfg(not(allow_clippy))] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset__field_check { + ($type:path, $field:tt) => { + // Make sure the field actually exists. This line ensures that a + // compile-time error is generated if $field is accessed through a + // Deref impl. + let $type { $field: _, .. }; + }; +} + +/// Deref-coercion protection macro. +/// +/// Prevents complilation if the specified type is not a tuple. +/// +/// ```compile_fail +/// use memoffset::_memoffset__field_check_tuple; +/// +/// _memoffset__field_check_tuple!(i32, 0); +/// ``` +#[cfg(allow_clippy)] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset__field_check_tuple { + ($type:ty, $field:tt) => { + // Make sure the type argument is a tuple + #[allow(clippy::unneeded_wildcard_pattern)] + let (_, ..): $type; + }; +} +#[cfg(not(allow_clippy))] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset__field_check_tuple { + ($type:ty, $field:tt) => { + // Make sure the type argument is a tuple + let (_, ..): $type; + }; +} + +/// Deref-coercion protection macro for unions. +/// Unfortunately accepts single-field structs as well, which is not ideal, +/// but ultimately pretty harmless. +/// +/// ```compile_fail +/// use memoffset::_memoffset__field_check_union; +/// +/// union Foo { +/// variant_a: i32, +/// } +/// +/// type BoxedFoo = Box; +/// +/// _memoffset__field_check_union!(BoxedFoo, variant_a); +/// ``` +#[cfg(allow_clippy)] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset__field_check_union { + ($type:path, $field:tt) => { + // Make sure the field actually exists. This line ensures that a + // compile-time error is generated if $field is accessed through a + // Deref impl. + #[allow(clippy::unneeded_wildcard_pattern)] + // rustc1.19 requires unsafe here for the pattern; not needed in newer versions + #[allow(unused_unsafe)] + unsafe { + let $type { $field: _ }; + } + }; +} +#[cfg(not(allow_clippy))] +#[macro_export] +#[doc(hidden)] +macro_rules! _memoffset__field_check_union { + ($type:path, $field:tt) => { + // Make sure the field actually exists. This line ensures that a + // compile-time error is generated if $field is accessed through a + // Deref impl. + // rustc1.19 requires unsafe here for the pattern; not needed in newer versions + #[allow(unused_unsafe)] + unsafe { + let $type { $field: _ }; + } + }; +} + +/// Computes a const raw pointer to the given field of the given base pointer +/// to the given parent type. +/// +/// The `base` pointer *must not* be dangling, but it *may* point to +/// uninitialized memory. +#[macro_export(local_inner_macros)] +macro_rules! raw_field { + ($base:expr, $parent:path, $field:tt) => {{ + _memoffset__field_check!($parent, $field); + let base = $base; // evaluate $base outside the `unsafe` block + + // Get the field address. + // Crucially, we know that this will not trigger a deref coercion because + // of the field check we did above. + #[allow(unused_unsafe)] // for when the macro is used in an unsafe block + unsafe { + _memoffset__addr_of!((*(base as *const $parent)).$field) + } + }}; +} + +/// Computes a const raw pointer to the given field of the given base pointer +/// to the given parent tuple typle. +/// +/// The `base` pointer *must not* be dangling, but it *may* point to +/// uninitialized memory. +#[cfg(tuple_ty)] +#[macro_export(local_inner_macros)] +macro_rules! raw_field_tuple { + ($base:expr, $parent:ty, $field:tt) => {{ + _memoffset__field_check_tuple!($parent, $field); + let base = $base; // evaluate $base outside the `unsafe` block + + // Get the field address. + // Crucially, we know that this will not trigger a deref coercion because + // of the field check we did above. + #[allow(unused_unsafe)] // for when the macro is used in an unsafe block + unsafe { + _memoffset__addr_of!((*(base as *const $parent)).$field) + } + }}; +} + +/// Computes a const raw pointer to the given field of the given base pointer +/// to the given parent tuple typle. +/// +/// The `base` pointer *must not* be dangling, but it *may* point to +/// uninitialized memory. +/// +/// ## Note +/// This macro is the same as `raw_field`, except for a different Deref-coercion check that +/// supports unions. +/// Due to macro_rules limitations, this check will accept structs with a single field as well as unions. +/// This is not a stable guarantee, and future versions of this crate might fail +/// on any use of this macro with a struct, without a semver bump. +#[macro_export(local_inner_macros)] +macro_rules! raw_field_union { + ($base:expr, $parent:path, $field:tt) => {{ + _memoffset__field_check_union!($parent, $field); + let base = $base; // evaluate $base outside the `unsafe` block + + // Get the field address. + // Crucially, we know that this will not trigger a deref coercion because + // of the field check we did above. + #[allow(unused_unsafe)] // for when the macro is used in an unsafe block + unsafe { + _memoffset__addr_of!((*(base as *const $parent)).$field) + } + }}; +} diff --git a/vendor/memoffset-0.7.1/src/span_of.rs b/vendor/memoffset-0.7.1/src/span_of.rs new file mode 100644 index 0000000000000..89fccce9217ef --- /dev/null +++ b/vendor/memoffset-0.7.1/src/span_of.rs @@ -0,0 +1,263 @@ +// Copyright (c) 2017 Gilad Naaman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +/// Reexport for `local_inner_macros`; see +/// . +#[doc(hidden)] +#[macro_export] +macro_rules! _memoffset__compile_error { + ($($inner:tt)*) => { + compile_error! { $($inner)* } + } +} + +/// Produces a range instance representing the sub-slice containing the specified member. +/// +/// This macro provides 2 forms of differing functionalities. +/// +/// The first form is identical to the appearance of the `offset_of!` macro. +/// +/// ```ignore +/// span_of!(Struct, member) +/// ``` +/// +/// The second form of `span_of!` returns a sub-slice which starts at one field, and ends at another. +/// The general pattern of this form is: +/// +/// ```ignore +/// // Exclusive +/// span_of!(Struct, member_a .. member_b) +/// // Inclusive +/// span_of!(Struct, member_a ..= member_b) +/// +/// // Open-ended ranges +/// span_of!(Struct, .. end) +/// span_of!(Struct, start ..) +/// ``` +/// +/// ### Note +/// This macro uses recursion in order to resolve the range expressions, so there is a limit to +/// the complexity of the expression. +/// In order to raise the limit, the compiler's recursion limit should be lifted. +/// +/// ### Safety +/// The inter-field form mentioned above assumes that the first field is positioned before the +/// second. +/// This is only guarenteed for `repr(C)` structs. +/// Usage with `repr(Rust)` structs may yield unexpected results, like downward-going ranges, +/// spans that include unexpected fields, empty spans, or spans that include *unexpected* padding bytes. +/// +/// ## Examples +/// ``` +/// use memoffset::span_of; +/// +/// #[repr(C)] +/// struct Florp { +/// a: u32 +/// } +/// +/// #[repr(C)] +/// struct Blarg { +/// x: [u32; 2], +/// y: [u8; 56], +/// z: Florp, +/// egg: [[u8; 4]; 4] +/// } +/// +/// fn main() { +/// assert_eq!(0..84, span_of!(Blarg, ..)); +/// assert_eq!(0..8, span_of!(Blarg, .. y)); +/// assert_eq!(0..64, span_of!(Blarg, ..= y)); +/// assert_eq!(0..8, span_of!(Blarg, x)); +/// assert_eq!(8..84, span_of!(Blarg, y ..)); +/// assert_eq!(0..8, span_of!(Blarg, x .. y)); +/// assert_eq!(0..64, span_of!(Blarg, x ..= y)); +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! span_of { + (@helper $root:ident, [] ..=) => { + _memoffset__compile_error!("Expected a range, found '..='") + }; + (@helper $root:ident, [] ..) => { + _memoffset__compile_error!("Expected a range, found '..'") + }; + // No explicit begin for range. + (@helper $root:ident, $parent:path, [] ..) => {{ + ($root as usize, + $root as usize + $crate::__priv::size_of_pointee($root)) + }}; + (@helper $root:ident, $parent:path, [] ..= $end:tt) => {{ + let end = raw_field!($root, $parent, $end); + ($root as usize, end as usize + $crate::__priv::size_of_pointee(end)) + }}; + (@helper $root:ident, $parent:path, [] .. $end:tt) => {{ + ($root as usize, raw_field!($root, $parent, $end) as usize) + }}; + // Explicit begin and end for range. + (@helper $root:ident, $parent:path, # $begin:tt [] ..= $end:tt) => {{ + let begin = raw_field!($root, $parent, $begin); + let end = raw_field!($root, $parent, $end); + (begin as usize, end as usize + $crate::__priv::size_of_pointee(end)) + }}; + (@helper $root:ident, $parent:path, # $begin:tt [] .. $end:tt) => {{ + (raw_field!($root, $parent, $begin) as usize, + raw_field!($root, $parent, $end) as usize) + }}; + // No explicit end for range. + (@helper $root:ident, $parent:path, # $begin:tt [] ..) => {{ + (raw_field!($root, $parent, $begin) as usize, + $root as usize + $crate::__priv::size_of_pointee($root)) + }}; + (@helper $root:ident, $parent:path, # $begin:tt [] ..=) => {{ + _memoffset__compile_error!( + "Found inclusive range to the end of a struct. Did you mean '..' instead of '..='?") + }}; + // Just one field. + (@helper $root:ident, $parent:path, # $field:tt []) => {{ + let field = raw_field!($root, $parent, $field); + (field as usize, field as usize + $crate::__priv::size_of_pointee(field)) + }}; + // Parsing. + (@helper $root:ident, $parent:path, $(# $begin:tt)+ [] $tt:tt $($rest:tt)*) => {{ + span_of!(@helper $root, $parent, $(#$begin)* #$tt [] $($rest)*) + }}; + (@helper $root:ident, $parent:path, [] $tt:tt $($rest:tt)*) => {{ + span_of!(@helper $root, $parent, #$tt [] $($rest)*) + }}; + + // Entry point. + ($sty:path, $($exp:tt)+) => ({ + // Get a base pointer. + _memoffset__let_base_ptr!(root, $sty); + let base = root as usize; + let (begin, end) = span_of!(@helper root, $sty, [] $($exp)*); + begin-base..end-base + }); +} + +#[cfg(test)] +mod tests { + use core::mem; + + #[test] + fn span_simple() { + #[repr(C)] + struct Foo { + a: u32, + b: [u8; 2], + c: i64, + } + + assert_eq!(span_of!(Foo, a), 0..4); + assert_eq!(span_of!(Foo, b), 4..6); + assert_eq!(span_of!(Foo, c), 8..8 + 8); + } + + #[test] + #[cfg_attr(miri, ignore)] // this creates unaligned references + fn span_simple_packed() { + #[repr(C, packed)] + struct Foo { + a: u32, + b: [u8; 2], + c: i64, + } + + assert_eq!(span_of!(Foo, a), 0..4); + assert_eq!(span_of!(Foo, b), 4..6); + assert_eq!(span_of!(Foo, c), 6..6 + 8); + } + + #[test] + fn span_forms() { + #[repr(C)] + struct Florp { + a: u32, + } + + #[repr(C)] + struct Blarg { + x: u64, + y: [u8; 56], + z: Florp, + egg: [[u8; 4]; 5], + } + + // Love me some brute force + assert_eq!(0..8, span_of!(Blarg, x)); + assert_eq!(64..68, span_of!(Blarg, z)); + assert_eq!(68..mem::size_of::(), span_of!(Blarg, egg)); + + assert_eq!(8..64, span_of!(Blarg, y..z)); + assert_eq!(0..64, span_of!(Blarg, x..=y)); + } + + #[test] + fn ig_test() { + #[repr(C)] + struct Member { + foo: u32, + } + + #[repr(C)] + struct Test { + x: u64, + y: [u8; 56], + z: Member, + egg: [[u8; 4]; 4], + } + + assert_eq!(span_of!(Test, ..x), 0..0); + assert_eq!(span_of!(Test, ..=x), 0..8); + assert_eq!(span_of!(Test, ..y), 0..8); + assert_eq!(span_of!(Test, ..=y), 0..64); + assert_eq!(span_of!(Test, ..z), 0..64); + assert_eq!(span_of!(Test, ..=z), 0..68); + assert_eq!(span_of!(Test, ..egg), 0..68); + assert_eq!(span_of!(Test, ..=egg), 0..84); + assert_eq!(span_of!(Test, ..), 0..mem::size_of::()); + assert_eq!( + span_of!(Test, x..), + offset_of!(Test, x)..mem::size_of::() + ); + assert_eq!( + span_of!(Test, y..), + offset_of!(Test, y)..mem::size_of::() + ); + + assert_eq!( + span_of!(Test, z..), + offset_of!(Test, z)..mem::size_of::() + ); + assert_eq!( + span_of!(Test, egg..), + offset_of!(Test, egg)..mem::size_of::() + ); + assert_eq!( + span_of!(Test, x..y), + offset_of!(Test, x)..offset_of!(Test, y) + ); + assert_eq!( + span_of!(Test, x..=y), + offset_of!(Test, x)..offset_of!(Test, y) + mem::size_of::<[u8; 56]>() + ); + } +} diff --git a/vendor/metrics-macros/.cargo-checksum.json b/vendor/metrics-macros/.cargo-checksum.json new file mode 100644 index 0000000000000..b86bf4f878119 --- /dev/null +++ b/vendor/metrics-macros/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"017392f5f660552bfd128b8c28669f634b80bfa61f8a5f6802246df0153331ba","Cargo.toml":"7be8107e7bb3c918d31654592d3c58bf965181f6a4525c0071ba2f82b04a6b8c","LICENSE":"efab6bad93b11c2a2bbecbd303e0844de04bbf9c7c3db9bdf4fc7ecc980c37e4","README.md":"802bd965a2c7124afba2e94e22771b45fe710ff0261565ffea76e7a225f2c8bd","src/lib.rs":"8e49589d4a260212dccb2d765a76d487908f1ebceb9aff9f23e8501ef19dd21d","src/tests.rs":"19f2e63974bc1c2d1310cfc4c3ee45abb65266e548606fa21b8e1a2986c14d27"},"package":"ddece26afd34c31585c74a4db0630c376df271c285d682d1e55012197830b6df"} \ No newline at end of file diff --git a/vendor/metrics-macros/CHANGELOG.md b/vendor/metrics-macros/CHANGELOG.md new file mode 100644 index 0000000000000..9169e2069a3f9 --- /dev/null +++ b/vendor/metrics-macros/CHANGELOG.md @@ -0,0 +1,78 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + + +## [Unreleased] - ReleaseDate + +## [0.7.0] - 2023-04-16 + +### Changed + +- Bump MSRV to 1.61.0. + +### Fixed + +- Type paths are now fully qualified in all macros to avoid issues with local import scopes having a + pre-existing `metrics` module. + +## [0.6.0] - 2022-07-22 + +### Changed + +- Updated the describe macros to support the recent change to taking `metrics::SharedString` instead + of `&'static str` for description strings. + +## [0.5.1] - 2022-02-06 + +Maintenance release. + +## [0.5.0] - 2022-01-14 + +### Added +- When describing a metric, a constant can now be used for the description itself. +- Label keys can now be general expressions i.e. constants or variables. Due to limitations in + how procedural macros work, and the facilities available in stable Rust for const traits, even + `&'static str` constants will cause allocations when used for emitting a metric. + +### Changed +- Correctly scoped the required features of various dependencies to reduce build times/transitive dependencies. +- Updated macros to coincide with the update to `metrics` for metric handles. This includes + renaming `register_*` macros to `describe_*`, which are purely for providing data that describes a + metric but does not initialize it in any way, and providing new `register_*` macros which do + initialize a metric. +- Updated the `describe_*` macros -- née `register_*` -- to require a description, and an optional + unit. As describing a metric does not register it in the sense of ensuring that it is present on + the output of an exporter, having the description be optional no longer makes sense. +- Additionally, the describe macros no longer take labels. In practice, varying the description of + a specific metric based on label values would be counter-intuitive, and to support this corner + case requires adds significant complexity to the macro parsing logic. + +### Removed +- Two unecessary dependencies, `lazy_static` and `regex`. + +## [0.4.1] - 2021-12-16 + +### Changed +- Removed unnecessary `proc-macro-hack` dependency. + +## [0.4.0] - 2021-05-18 + +### Changed +- Updates to macros to support the removal of `NameParts` and related machinery. + +## [0.3.0] - 2021-05-03 + +### Changed +- Updates to macros to support changes in `Recorder` around how keys are taken. + +## [0.2.0] - 2021-02-02 +### Changed +- Added support for owned strings as metric names. [#170](https://github.com/metrics-rs/metrics/pull/170) + +## [0.1.0] - 2021-01-22 +### Added +- Effective birth of the crate. diff --git a/vendor/metrics-macros/Cargo.toml b/vendor/metrics-macros/Cargo.toml new file mode 100644 index 0000000000000..f512985642ab0 --- /dev/null +++ b/vendor/metrics-macros/Cargo.toml @@ -0,0 +1,52 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +rust-version = "1.61.0" +name = "metrics-macros" +version = "0.7.0" +authors = ["Toby Lawrence "] +description = "Macros for the metrics crate." +homepage = "https://github.com/metrics-rs/metrics" +documentation = "https://docs.rs/metrics" +readme = "README.md" +keywords = [ + "metrics", + "facade", + "macros", +] +categories = ["development-tools::debugging"] +license = "MIT" +repository = "https://github.com/metrics-rs/metrics" + +[lib] +proc-macro = true + +[dependencies.proc-macro2] +version = "1" +features = ["proc-macro"] +default-features = false + +[dependencies.quote] +version = "1" +default-features = false + +[dependencies.syn] +version = "2" +features = [ + "derive", + "full", + "parsing", + "printing", + "proc-macro", +] +default-features = false diff --git a/vendor/metrics-macros/LICENSE b/vendor/metrics-macros/LICENSE new file mode 100644 index 0000000000000..d4043d2c9b31e --- /dev/null +++ b/vendor/metrics-macros/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2021 Metrics Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/metrics-macros/README.md b/vendor/metrics-macros/README.md new file mode 100644 index 0000000000000..bd6c1b7bd9052 --- /dev/null +++ b/vendor/metrics-macros/README.md @@ -0,0 +1,4 @@ +# metrics-macros + +This crate houses all of the procedural macros that are re-exported by `metrics`. Refer to the +documentation for `metrics` to find examples and more information on the available macros. \ No newline at end of file diff --git a/vendor/metrics-macros/src/lib.rs b/vendor/metrics-macros/src/lib.rs new file mode 100644 index 0000000000000..6b11132f6c538 --- /dev/null +++ b/vendor/metrics-macros/src/lib.rs @@ -0,0 +1,476 @@ +extern crate proc_macro; + +use self::proc_macro::TokenStream; + +use proc_macro2::TokenStream as TokenStream2; +use quote::{format_ident, quote, ToTokens}; +use syn::parse::{Error, Parse, ParseStream, Result}; +use syn::{parse::discouraged::Speculative, Lit}; +use syn::{parse_macro_input, Expr, Token}; + +#[cfg(test)] +mod tests; + +enum Labels { + Existing(Expr), + Inline(Vec<(Expr, Expr)>), +} + +struct WithoutExpression { + key: Expr, + labels: Option, +} + +struct WithExpression { + key: Expr, + op_value: Expr, + labels: Option, +} + +struct Description { + key: Expr, + unit: Option, + description: Expr, +} + +impl Parse for WithoutExpression { + fn parse(mut input: ParseStream) -> Result { + let key = input.parse::()?; + let labels = parse_labels(&mut input)?; + + Ok(WithoutExpression { key, labels }) + } +} + +impl Parse for WithExpression { + fn parse(mut input: ParseStream) -> Result { + let key = input.parse::()?; + + input.parse::()?; + let op_value = input.parse::()?; + + let labels = parse_labels(&mut input)?; + + Ok(WithExpression { key, op_value, labels }) + } +} + +impl Parse for Description { + fn parse(input: ParseStream) -> Result { + let key = input.parse::()?; + + // We accept two possible parameters: unit, and description. + // + // There is only one specific requirement that must be met, and that is that the || _must_ + // have a qualified path of either `metrics::Unit::...` or `Unit::..` for us to properly + // distinguish it amongst the macro parameters. + + // Now try to read out the components. We speculatively try to parse out a unit if it + // exists, and otherwise we just look for the description. + let unit = input + .call(|s| { + let forked = s.fork(); + forked.parse::()?; + + let output = if let Ok(Expr::Path(path)) = forked.parse::() { + let qname = path + .path + .segments + .iter() + .map(|x| x.ident.to_string()) + .collect::>() + .join("::"); + if qname.starts_with("::metrics::Unit") + || qname.starts_with("metrics::Unit") + || qname.starts_with("Unit") + { + Some(Expr::Path(path)) + } else { + None + } + } else { + None + }; + + if output.is_some() { + s.advance_to(&forked); + } + + Ok(output) + }) + .ok() + .flatten(); + + input.parse::()?; + let description = input.parse::()?; + + Ok(Description { key, unit, description }) + } +} + +#[proc_macro] +pub fn describe_counter(input: TokenStream) -> TokenStream { + let Description { key, unit, description } = parse_macro_input!(input as Description); + + get_describe_code("counter", key, unit, description).into() +} + +#[proc_macro] +pub fn describe_gauge(input: TokenStream) -> TokenStream { + let Description { key, unit, description } = parse_macro_input!(input as Description); + + get_describe_code("gauge", key, unit, description).into() +} + +#[proc_macro] +pub fn describe_histogram(input: TokenStream) -> TokenStream { + let Description { key, unit, description } = parse_macro_input!(input as Description); + + get_describe_code("histogram", key, unit, description).into() +} + +#[proc_macro] +pub fn register_counter(input: TokenStream) -> TokenStream { + let WithoutExpression { key, labels } = parse_macro_input!(input as WithoutExpression); + + get_register_and_op_code::("counter", key, labels, None).into() +} + +#[proc_macro] +pub fn register_gauge(input: TokenStream) -> TokenStream { + let WithoutExpression { key, labels } = parse_macro_input!(input as WithoutExpression); + + get_register_and_op_code::("gauge", key, labels, None).into() +} + +#[proc_macro] +pub fn register_histogram(input: TokenStream) -> TokenStream { + let WithoutExpression { key, labels } = parse_macro_input!(input as WithoutExpression); + + get_register_and_op_code::("histogram", key, labels, None).into() +} + +#[proc_macro] +pub fn increment_counter(input: TokenStream) -> TokenStream { + let WithoutExpression { key, labels } = parse_macro_input!(input as WithoutExpression); + + let op_value = quote! { 1 }; + + get_register_and_op_code("counter", key, labels, Some(("increment", op_value))).into() +} + +#[proc_macro] +pub fn counter(input: TokenStream) -> TokenStream { + let WithExpression { key, op_value, labels } = parse_macro_input!(input as WithExpression); + + get_register_and_op_code("counter", key, labels, Some(("increment", op_value))).into() +} + +#[proc_macro] +pub fn absolute_counter(input: TokenStream) -> TokenStream { + let WithExpression { key, op_value, labels } = parse_macro_input!(input as WithExpression); + + get_register_and_op_code("counter", key, labels, Some(("absolute", op_value))).into() +} + +#[proc_macro] +pub fn increment_gauge(input: TokenStream) -> TokenStream { + let WithExpression { key, op_value, labels } = parse_macro_input!(input as WithExpression); + + get_register_and_op_code("gauge", key, labels, Some(("increment", op_value))).into() +} + +#[proc_macro] +pub fn decrement_gauge(input: TokenStream) -> TokenStream { + let WithExpression { key, op_value, labels } = parse_macro_input!(input as WithExpression); + + get_register_and_op_code("gauge", key, labels, Some(("decrement", op_value))).into() +} + +#[proc_macro] +pub fn gauge(input: TokenStream) -> TokenStream { + let WithExpression { key, op_value, labels } = parse_macro_input!(input as WithExpression); + + get_register_and_op_code("gauge", key, labels, Some(("set", op_value))).into() +} + +#[proc_macro] +pub fn histogram(input: TokenStream) -> TokenStream { + let WithExpression { key, op_value, labels } = parse_macro_input!(input as WithExpression); + + get_register_and_op_code("histogram", key, labels, Some(("record", op_value))).into() +} + +fn get_describe_code( + metric_type: &str, + name: Expr, + unit: Option, + description: Expr, +) -> TokenStream2 { + let describe_ident = format_ident!("describe_{}", metric_type); + + let unit = match unit { + Some(e) => quote! { Some(#e) }, + None => quote! { None }, + }; + + quote! { + { + // Only do this work if there's a recorder installed. + if let Some(recorder) = ::metrics::try_recorder() { + recorder.#describe_ident(#name.into(), #unit, #description.into()); + } + } + } +} + +fn get_register_and_op_code( + metric_type: &str, + name: Expr, + labels: Option, + op: Option<(&'static str, V)>, +) -> TokenStream2 +where + V: ToTokens, +{ + let register_ident = format_ident!("register_{}", metric_type); + let statics = generate_statics(&name, &labels); + let (locals, metric_key) = generate_metric_key(&name, &labels); + match op { + Some((op_type, op_value)) => { + let op_ident = format_ident!("{}", op_type); + let op_value = if metric_type == "histogram" { + quote! { ::metrics::__into_f64(#op_value) } + } else { + quote! { #op_value } + }; + + // We've been given values to actually use with the handle, so we actually check if a + // recorder is installed before bothering to create a handle and everything. + quote! { + { + #statics + // Only do this work if there's a recorder installed. + if let Some(recorder) = ::metrics::try_recorder() { + #locals + let handle = recorder.#register_ident(#metric_key); + handle.#op_ident(#op_value); + } + } + } + } + None => { + // If there's no values specified, we simply return the metric handle. + quote! { + { + #statics + #locals + ::metrics::recorder().#register_ident(#metric_key) + } + } + } + } +} + +fn name_is_fast_path(name: &Expr) -> bool { + if let Expr::Lit(lit) = name { + return matches!(lit.lit, Lit::Str(_)); + } + + false +} + +fn labels_are_fast_path(labels: &Labels) -> bool { + match labels { + Labels::Existing(_) => false, + Labels::Inline(pairs) => { + pairs.iter().all(|(k, v)| matches!((k, v), (Expr::Lit(_), Expr::Lit(_)))) + } + } +} + +fn generate_statics(name: &Expr, labels: &Option) -> TokenStream2 { + // Create the static for the name, if possible. + let use_name_static = name_is_fast_path(name); + let name_static = if use_name_static { + quote! { + static METRIC_NAME: &'static str = #name; + } + } else { + quote! {} + }; + + // Create the static for the labels, if possible. + let has_labels = labels.is_some(); + let use_labels_static = match labels.as_ref() { + Some(labels) => labels_are_fast_path(labels), + None => true, + }; + + let labels_static = match labels.as_ref() { + Some(labels) => { + if labels_are_fast_path(labels) { + if let Labels::Inline(pairs) = labels { + let labels = pairs + .iter() + .map( + |(key, val)| quote! { ::metrics::Label::from_static_parts(#key, #val) }, + ) + .collect::>(); + let labels_len = labels.len(); + let labels_len = quote! { #labels_len }; + + quote! { + static METRIC_LABELS: [::metrics::Label; #labels_len] = [#(#labels),*]; + } + } else { + quote! {} + } + } else { + quote! {} + } + } + None => quote! {}, + }; + + let key_static = if use_name_static && use_labels_static { + if has_labels { + quote! { + static METRIC_KEY: ::metrics::Key = ::metrics::Key::from_static_parts(METRIC_NAME, &METRIC_LABELS); + } + } else { + quote! { + static METRIC_KEY: ::metrics::Key = ::metrics::Key::from_static_name(METRIC_NAME); + } + } + } else { + quote! {} + }; + + quote! { + #name_static + #labels_static + #key_static + } +} + +fn generate_metric_key(name: &Expr, labels: &Option) -> (TokenStream2, TokenStream2) { + let use_name_static = name_is_fast_path(name); + + let has_labels = labels.is_some(); + let use_labels_static = match labels.as_ref() { + Some(labels) => labels_are_fast_path(labels), + None => true, + }; + + let mut key_name = quote! { &key }; + let locals = if use_name_static && use_labels_static { + // Key is entirely static, so we can simply reference our generated statics. They will be + // inclusive of whether or not labels were specified. + key_name = quote! { &METRIC_KEY }; + quote! {} + } else if use_name_static && !use_labels_static { + // The name is static, but we have labels which are not static. Since `use_labels_static` + // cannot be false unless labels _are_ specified, we know this unwrap is safe. + let labels = labels.as_ref().unwrap(); + let quoted_labels = labels_to_quoted(labels); + quote! { + let key = ::metrics::Key::from_parts(METRIC_NAME, #quoted_labels); + } + } else if !use_name_static && !use_labels_static { + // The name is not static, and neither are the labels. Since `use_labels_static` + // cannot be false unless labels _are_ specified, we know this unwrap is safe. + let labels = labels.as_ref().unwrap(); + let quoted_labels = labels_to_quoted(labels); + quote! { + let key = ::metrics::Key::from_parts(#name, #quoted_labels); + } + } else { + // The name is not static, but the labels are. This could technically mean that there + // simply are no labels, so we have to discriminate in a slightly different way + // to figure out the correct key. + if has_labels { + quote! { + let key = ::metrics::Key::from_static_labels(#name, &METRIC_LABELS); + } + } else { + quote! { + let key = ::metrics::Key::from_name(#name); + } + } + }; + + (locals, key_name) +} + +fn labels_to_quoted(labels: &Labels) -> proc_macro2::TokenStream { + match labels { + Labels::Inline(pairs) => { + let labels = + pairs.iter().map(|(key, val)| quote! { ::metrics::Label::new(#key, #val) }); + quote! { vec![#(#labels),*] } + } + Labels::Existing(e) => quote! { #e }, + } +} + +fn parse_labels(input: &mut ParseStream) -> Result> { + if input.is_empty() { + return Ok(None); + } + + if !input.peek(Token![,]) { + // This is a hack to generate the proper error message for parsing the comma next without + // actually parsing it and thus removing it from the parse stream. Just makes the following + // code a bit cleaner. + input + .parse::() + .map_err(|e| Error::new(e.span(), "expected labels, but comma not found"))?; + } + + // Two possible states for labels: references to a label iterator, or key/value pairs. + // + // We check to see if we have the ", key =>" part, which tells us that we're taking in key/value + // pairs. If we don't have that, we check to see if we have a "`, ]) { + let mut labels = Vec::new(); + loop { + if input.is_empty() { + break; + } + input.parse::()?; + if input.is_empty() { + break; + } + + let k = input.parse::()?; + input.parse::]>()?; + let v = input.parse::()?; + + labels.push((k, v)); + } + + return Ok(Some(Labels::Inline(labels))); + } + + // Has to be an expression otherwise, or a trailing comma. + input.parse::()?; + + // Unless it was an expression - clear the trailing comma. + if input.is_empty() { + return Ok(None); + } + + let existing = input.parse::().map_err(|e| { + Error::new(e.span(), "expected labels expression, but expression not found") + })?; + + // Expression can end with a trailing comma, handle it. + if input.peek(Token![,]) { + input.parse::()?; + } + + Ok(Some(Labels::Existing(existing))) +} diff --git a/vendor/metrics-macros/src/tests.rs b/vendor/metrics-macros/src/tests.rs new file mode 100644 index 0000000000000..46a5d29fdd3cb --- /dev/null +++ b/vendor/metrics-macros/src/tests.rs @@ -0,0 +1,567 @@ +use syn::parse_quote; +use syn::{Expr, ExprPath}; + +use super::*; + +#[test] +fn test_get_describe_code() { + // Basic registration. + let stream = get_describe_code( + "mytype", + parse_quote! { "mykeyname" }, + None, + parse_quote! { "a counter" }, + ); + + let expected = concat!( + "{ ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "recorder . describe_mytype (\"mykeyname\" . into () , None , \"a counter\" . into ()) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_describe_code_with_qualified_unit_rooted() { + // Now with unit. + let units: ExprPath = parse_quote! { ::metrics::Unit::Nanoseconds }; + let stream = get_describe_code( + "mytype", + parse_quote! { "mykeyname" }, + Some(Expr::Path(units)), + parse_quote! { "a counter" }, + ); + + let expected = concat!( + "{ ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "recorder . describe_mytype (\"mykeyname\" . into () , Some (:: metrics :: Unit :: Nanoseconds) , \"a counter\" . into ()) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_describe_code_with_qualified_unit() { + // Now with unit. + let units: ExprPath = parse_quote! { metrics::Unit::Nanoseconds }; + let stream = get_describe_code( + "mytype", + parse_quote! { "mykeyname" }, + Some(Expr::Path(units)), + parse_quote! { "a counter" }, + ); + + let expected = concat!( + "{ ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "recorder . describe_mytype (\"mykeyname\" . into () , Some (metrics :: Unit :: Nanoseconds) , \"a counter\" . into ()) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_describe_code_with_relative_unit() { + // Now with unit. + let units: ExprPath = parse_quote! { Unit::Nanoseconds }; + let stream = get_describe_code( + "mytype", + parse_quote! { "mykeyname" }, + Some(Expr::Path(units)), + parse_quote! { "a counter" }, + ); + + let expected = concat!( + "{ ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "recorder . describe_mytype (\"mykeyname\" . into () , Some (Unit :: Nanoseconds) , \"a counter\" . into ()) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_describe_code_with_constants() { + // Basic registration. + let stream = + get_describe_code("mytype", parse_quote! { KEY_NAME }, None, parse_quote! { COUNTER_DESC }); + + let expected = concat!( + "{ ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "recorder . describe_mytype (KEY_NAME . into () , None , COUNTER_DESC . into ()) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_describe_code_with_constants_and_with_qualified_unit() { + // Now with unit. + let units: ExprPath = parse_quote! { metrics::Unit::Nanoseconds }; + let stream = get_describe_code( + "mytype", + parse_quote! { KEY_NAME }, + Some(Expr::Path(units)), + parse_quote! { COUNTER_DESC }, + ); + + let expected = concat!( + "{ ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "recorder . describe_mytype (KEY_NAME . into () , Some (metrics :: Unit :: Nanoseconds) , COUNTER_DESC . into ()) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_describe_code_with_constants_and_with_qualified_unit_rooted() { + // Now with unit. + let units: ExprPath = parse_quote! { ::metrics::Unit::Nanoseconds }; + let stream = get_describe_code( + "mytype", + parse_quote! { KEY_NAME }, + Some(Expr::Path(units)), + parse_quote! { COUNTER_DESC }, + ); + + let expected = concat!( + "{ ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "recorder . describe_mytype (KEY_NAME . into () , Some (:: metrics :: Unit :: Nanoseconds) , COUNTER_DESC . into ()) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_describe_code_with_constants_and_with_relative_unit() { + // Now with unit. + let units: ExprPath = parse_quote! { Unit::Nanoseconds }; + let stream = get_describe_code( + "mytype", + parse_quote! { KEY_NAME }, + Some(Expr::Path(units)), + parse_quote! { COUNTER_DESC }, + ); + + let expected = concat!( + "{ ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "recorder . describe_mytype (KEY_NAME . into () , Some (Unit :: Nanoseconds) , COUNTER_DESC . into ()) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_register_and_op_code_register_static_name_no_labels() { + let stream = get_register_and_op_code::("mytype", parse_quote! {"mykeyname"}, None, None); + + let expected = concat!( + "{ ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", + "static METRIC_KEY : :: metrics :: Key = :: metrics :: Key :: from_static_name (METRIC_NAME) ; ", + ":: metrics :: recorder () . register_mytype (& METRIC_KEY) ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_register_and_op_code_register_static_name_static_inline_labels() { + let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { "value1" })]); + let stream = + get_register_and_op_code::("mytype", parse_quote! {"mykeyname"}, Some(labels), None); + + let expected = concat!( + "{ ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", + "static METRIC_LABELS : [:: metrics :: Label ; 1usize] = [:: metrics :: Label :: from_static_parts (\"key1\" , \"value1\")] ; ", + "static METRIC_KEY : :: metrics :: Key = :: metrics :: Key :: from_static_parts (METRIC_NAME , & METRIC_LABELS) ; ", + ":: metrics :: recorder () . register_mytype (& METRIC_KEY) ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_register_and_op_code_register_static_name_dynamic_inline_labels() { + let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { &value1 })]); + let stream = + get_register_and_op_code::("mytype", parse_quote! {"mykeyname"}, Some(labels), None); + + let expected = concat!( + "{ ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", + "let key = :: metrics :: Key :: from_parts (METRIC_NAME , vec ! [:: metrics :: Label :: new (\"key1\" , & value1)]) ; ", + ":: metrics :: recorder () . register_mytype (& key) ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +/// If there are dynamic labels - generate a direct invocation. +#[test] +fn test_get_register_and_op_code_register_static_name_existing_labels() { + let stream = get_register_and_op_code::( + "mytype", + parse_quote! {"mykeyname"}, + Some(Labels::Existing(parse_quote! { mylabels })), + None, + ); + + let expected = concat!( + "{ ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", + "let key = :: metrics :: Key :: from_parts (METRIC_NAME , mylabels) ; ", + ":: metrics :: recorder () . register_mytype (& key) ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_register_and_op_code_register_owned_name_no_labels() { + let stream = get_register_and_op_code::( + "mytype", + parse_quote! { String::from("owned") }, + None, + None, + ); + + let expected = concat!( + "{ ", + "let key = :: metrics :: Key :: from_name (String :: from (\"owned\")) ; ", + ":: metrics :: recorder () . register_mytype (& key) ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_register_and_op_code_register_owned_name_static_inline_labels() { + let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { "value1" })]); + let stream = get_register_and_op_code::( + "mytype", + parse_quote! { String::from("owned") }, + Some(labels), + None, + ); + + let expected = concat!( + "{ ", + "static METRIC_LABELS : [:: metrics :: Label ; 1usize] = [:: metrics :: Label :: from_static_parts (\"key1\" , \"value1\")] ; ", + "let key = :: metrics :: Key :: from_static_labels (String :: from (\"owned\") , & METRIC_LABELS) ; ", + ":: metrics :: recorder () . register_mytype (& key) ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_register_and_op_code_register_owned_name_dynamic_inline_labels() { + let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { &value1 })]); + let stream = get_register_and_op_code::( + "mytype", + parse_quote! { String::from("owned") }, + Some(labels), + None, + ); + + let expected = concat!( + "{ ", + "let key = :: metrics :: Key :: from_parts (String :: from (\"owned\") , vec ! [:: metrics :: Label :: new (\"key1\" , & value1)]) ; ", + ":: metrics :: recorder () . register_mytype (& key) ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +/// If there are dynamic labels - generate a direct invocation. +#[test] +fn test_get_register_and_op_code_register_owned_name_existing_labels() { + let stream = get_register_and_op_code::( + "mytype", + parse_quote! { String::from("owned") }, + Some(Labels::Existing(parse_quote! { mylabels })), + None, + ); + + let expected = concat!( + "{ ", + "let key = :: metrics :: Key :: from_parts (String :: from (\"owned\") , mylabels) ; ", + ":: metrics :: recorder () . register_mytype (& key) ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_register_and_op_code_op_static_name_no_labels() { + let stream = get_register_and_op_code( + "mytype", + parse_quote! {"mykeyname"}, + None, + Some(("myop", quote! { 1 })), + ); + + let expected = concat!( + "{ ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", + "static METRIC_KEY : :: metrics :: Key = :: metrics :: Key :: from_static_name (METRIC_NAME) ; ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "let handle = recorder . register_mytype (& METRIC_KEY) ; ", + "handle . myop (1) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_register_and_op_code_op_static_name_static_inline_labels() { + let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { "value1" })]); + let stream = get_register_and_op_code( + "mytype", + parse_quote! {"mykeyname"}, + Some(labels), + Some(("myop", quote! { 1 })), + ); + + let expected = concat!( + "{ ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", + "static METRIC_LABELS : [:: metrics :: Label ; 1usize] = [:: metrics :: Label :: from_static_parts (\"key1\" , \"value1\")] ; ", + "static METRIC_KEY : :: metrics :: Key = :: metrics :: Key :: from_static_parts (METRIC_NAME , & METRIC_LABELS) ; ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "let handle = recorder . register_mytype (& METRIC_KEY) ; ", + "handle . myop (1) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_register_and_op_code_op_static_name_dynamic_inline_labels() { + let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { &value1 })]); + let stream = get_register_and_op_code( + "mytype", + parse_quote! {"mykeyname"}, + Some(labels), + Some(("myop", quote! { 1 })), + ); + + let expected = concat!( + "{ ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "let key = :: metrics :: Key :: from_parts (METRIC_NAME , vec ! [:: metrics :: Label :: new (\"key1\" , & value1)]) ; ", + "let handle = recorder . register_mytype (& key) ; ", + "handle . myop (1) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +/// If there are dynamic labels - generate a direct invocation. +#[test] +fn test_get_register_and_op_code_op_static_name_existing_labels() { + let stream = get_register_and_op_code( + "mytype", + parse_quote! {"mykeyname"}, + Some(Labels::Existing(parse_quote! { mylabels })), + Some(("myop", quote! { 1 })), + ); + + let expected = concat!( + "{ ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "let key = :: metrics :: Key :: from_parts (METRIC_NAME , mylabels) ; ", + "let handle = recorder . register_mytype (& key) ; ", + "handle . myop (1) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_register_and_op_code_op_owned_name_no_labels() { + let stream = get_register_and_op_code( + "mytype", + parse_quote! { String::from("owned") }, + None, + Some(("myop", quote! { 1 })), + ); + + let expected = concat!( + "{ ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "let key = :: metrics :: Key :: from_name (String :: from (\"owned\")) ; ", + "let handle = recorder . register_mytype (& key) ; ", + "handle . myop (1) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_register_and_op_code_op_owned_name_static_inline_labels() { + let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { "value1" })]); + let stream = get_register_and_op_code( + "mytype", + parse_quote! { String::from("owned") }, + Some(labels), + Some(("myop", quote! { 1 })), + ); + + let expected = concat!( + "{ ", + "static METRIC_LABELS : [:: metrics :: Label ; 1usize] = [:: metrics :: Label :: from_static_parts (\"key1\" , \"value1\")] ; ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "let key = :: metrics :: Key :: from_static_labels (String :: from (\"owned\") , & METRIC_LABELS) ; ", + "let handle = recorder . register_mytype (& key) ; ", + "handle . myop (1) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_register_and_op_code_op_owned_name_dynamic_inline_labels() { + let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { &value1 })]); + let stream = get_register_and_op_code( + "mytype", + parse_quote! { String::from("owned") }, + Some(labels), + Some(("myop", quote! { 1 })), + ); + + let expected = concat!( + "{ ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "let key = :: metrics :: Key :: from_parts (String :: from (\"owned\") , vec ! [:: metrics :: Label :: new (\"key1\" , & value1)]) ; ", + "let handle = recorder . register_mytype (& key) ; ", + "handle . myop (1) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +/// If there are dynamic labels - generate a direct invocation. +#[test] +fn test_get_register_and_op_code_op_owned_name_existing_labels() { + let stream = get_register_and_op_code( + "mytype", + parse_quote! { String::from("owned") }, + Some(Labels::Existing(parse_quote! { mylabels })), + Some(("myop", quote! { 1 })), + ); + + let expected = concat!( + "{ ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "let key = :: metrics :: Key :: from_parts (String :: from (\"owned\") , mylabels) ; ", + "let handle = recorder . register_mytype (& key) ; ", + "handle . myop (1) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_register_and_op_code_op_owned_name_constant_key_labels() { + let stream = get_register_and_op_code( + "mytype", + parse_quote! { String::from("owned") }, + Some(Labels::Inline(vec![(parse_quote! { LABEL_KEY }, parse_quote! { "some_val" })])), + Some(("myop", quote! { 1 })), + ); + + let expected = concat!( + "{ ", + "if let Some (recorder) = :: metrics :: try_recorder () { ", + "let key = :: metrics :: Key :: from_parts (String :: from (\"owned\") , vec ! [:: metrics :: Label :: new (LABEL_KEY , \"some_val\")]) ; ", + "let handle = recorder . register_mytype (& key) ; ", + "handle . myop (1) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_labels_to_quoted_existing_labels() { + let labels = Labels::Existing(Expr::Path(parse_quote! { mylabels })); + let stream = labels_to_quoted(&labels); + let expected = "mylabels"; + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_labels_to_quoted_inline_labels() { + let labels = Labels::Inline(vec![ + (parse_quote! {"mylabel1"}, parse_quote! { mylabel1 }), + (parse_quote! {"mylabel2"}, parse_quote! { "mylabel2" }), + ]); + let stream = labels_to_quoted(&labels); + let expected = concat!( + "vec ! [", + ":: metrics :: Label :: new (\"mylabel1\" , mylabel1) , ", + ":: metrics :: Label :: new (\"mylabel2\" , \"mylabel2\")", + "]" + ); + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_labels_to_quoted_inline_labels_empty() { + let labels = Labels::Inline(vec![]); + let stream = labels_to_quoted(&labels); + let expected = "vec ! []"; + assert_eq!(stream.to_string(), expected); +} diff --git a/vendor/metrics/src/recorder.rs b/vendor/metrics/src/recorder.rs new file mode 100644 index 0000000000000..13ae93ecdafff --- /dev/null +++ b/vendor/metrics/src/recorder.rs @@ -0,0 +1,226 @@ +use std::fmt; + +use self::cell::RecorderOnceCell; +use crate::{Counter, Gauge, Histogram, Key, KeyName, SharedString, Unit}; + +mod cell { + use super::{Recorder, SetRecorderError}; + use std::{ + cell::UnsafeCell, + sync::atomic::{AtomicUsize, Ordering}, + }; + + /// The recorder is uninitialized. + const UNINITIALIZED: usize = 0; + + /// The recorder is currently being initialized. + const INITIALIZING: usize = 1; + + /// The recorder has been initialized successfully and can be read. + const INITIALIZED: usize = 2; + + /// An specialized version of `OnceCell` for `Recorder`. + pub struct RecorderOnceCell { + recorder: UnsafeCell>, + state: AtomicUsize, + } + + impl RecorderOnceCell { + /// Creates an uninitialized `RecorderOnceCell`. + pub const fn new() -> Self { + Self { recorder: UnsafeCell::new(None), state: AtomicUsize::new(UNINITIALIZED) } + } + + pub fn set(&self, recorder: &'static dyn Recorder) -> Result<(), SetRecorderError> { + // Try and transition the cell from `UNINITIALIZED` to `INITIALIZING`, which would give + // us exclusive access to set the recorder. + match self.state.compare_exchange( + UNINITIALIZED, + INITIALIZING, + Ordering::Acquire, + Ordering::Relaxed, + ) { + Ok(UNINITIALIZED) => { + unsafe { + // SAFETY: Access is unique because we can only be here if we won the race + // to transition from `UNINITIALIZED` to `INITIALIZING` above. + self.recorder.get().write(Some(recorder)); + } + + // Mark the recorder as initialized, which will make it visible to readers. + self.state.store(INITIALIZED, Ordering::Release); + Ok(()) + } + _ => Err(SetRecorderError(())), + } + } + + /// Clears the currently installed recorder, allowing a new writer to override it. + /// + /// # Safety + /// + /// The caller must guarantee that no reader has read the state before we do this and then + /// reads the recorder after another writer has written to it after us. + pub unsafe fn clear(&self) { + // Set the state to `UNINITIALIZED` to allow the next writer to write again. This is not + // a problem for readers since their `&'static` refs will remain valid forever. + self.state.store(UNINITIALIZED, Ordering::Relaxed); + } + + pub fn try_load(&self) -> Option<&'static dyn Recorder> { + if self.state.load(Ordering::Acquire) != INITIALIZED { + None + } else { + // SAFETY: If the state is `INITIALIZED`, then we know that the recorder has been + // installed and is safe to read. + unsafe { self.recorder.get().read() } + } + } + } + + // SAFETY: We can only mutate through `set`, which is protected by the `state` and unsafe + // function where the caller has to guarantee synced-ness. + unsafe impl Send for RecorderOnceCell {} + unsafe impl Sync for RecorderOnceCell {} +} + +static RECORDER: RecorderOnceCell = RecorderOnceCell::new(); + +static SET_RECORDER_ERROR: &str = + "attempted to set a recorder after the metrics system was already initialized"; + +/// A trait for registering and recording metrics. +/// +/// This is the core trait that allows interoperability between exporter implementations and the +/// macros provided by `metrics`. +pub trait Recorder { + /// Describes a counter. + /// + /// Callers may provide the unit or a description of the counter being registered. Whether or + /// not a metric can be reregistered to provide a unit/description, if one was already passed + /// or not, as well as how units/descriptions are used by the underlying recorder, is an + /// implementation detail. + fn describe_counter(&self, key: KeyName, unit: Option, description: SharedString); + + /// Describes a gauge. + /// + /// Callers may provide the unit or a description of the gauge being registered. Whether or + /// not a metric can be reregistered to provide a unit/description, if one was already passed + /// or not, as well as how units/descriptions are used by the underlying recorder, is an + /// implementation detail. + fn describe_gauge(&self, key: KeyName, unit: Option, description: SharedString); + + /// Describes a histogram. + /// + /// Callers may provide the unit or a description of the histogram being registered. Whether or + /// not a metric can be reregistered to provide a unit/description, if one was already passed + /// or not, as well as how units/descriptions are used by the underlying recorder, is an + /// implementation detail. + fn describe_histogram(&self, key: KeyName, unit: Option, description: SharedString); + + /// Registers a counter. + fn register_counter(&self, key: &Key) -> Counter; + + /// Registers a gauge. + fn register_gauge(&self, key: &Key) -> Gauge; + + /// Registers a histogram. + fn register_histogram(&self, key: &Key) -> Histogram; +} + +/// A no-op recorder. +/// +/// Used as the default recorder when one has not been installed yet. Useful for acting as the root +/// recorder when testing layers. +pub struct NoopRecorder; + +impl Recorder for NoopRecorder { + fn describe_counter(&self, _key: KeyName, _unit: Option, _description: SharedString) {} + fn describe_gauge(&self, _key: KeyName, _unit: Option, _description: SharedString) {} + fn describe_histogram(&self, _key: KeyName, _unit: Option, _description: SharedString) {} + fn register_counter(&self, _key: &Key) -> Counter { + Counter::noop() + } + fn register_gauge(&self, _key: &Key) -> Gauge { + Gauge::noop() + } + fn register_histogram(&self, _key: &Key) -> Histogram { + Histogram::noop() + } +} + +/// Sets the global recorder to a `&'static Recorder`. +/// +/// This function may only be called once in the lifetime of a program. Any metrics recorded +/// before the call to `set_recorder` occurs will be completely ignored. +/// +/// This function does not typically need to be called manually. Metrics implementations should +/// provide an initialization method that installs the recorder internally. +/// +/// # Errors +/// +/// An error is returned if a recorder has already been set. +pub fn set_recorder(recorder: &'static dyn Recorder) -> Result<(), SetRecorderError> { + RECORDER.set(recorder) +} + +/// Sets the global recorder to a `Box`. +/// +/// This is a simple convenience wrapper over `set_recorder`, which takes a `Box` +/// rather than a `&'static Recorder`. See the documentation for [`set_recorder`] for more +/// details. +/// +/// # Errors +/// +/// An error is returned if a recorder has already been set. +pub fn set_boxed_recorder(recorder: Box) -> Result<(), SetRecorderError> { + RECORDER.set(Box::leak(recorder)) +} + +/// Clears the currently configured recorder. +/// +/// This will leak the currently installed recorder, as we cannot safely drop it due to it being +/// provided via a reference with a `'static` lifetime. +/// +/// This method is typically only useful for testing or benchmarking. +/// +/// # Safety +/// +/// The caller must ensure that this method is not being called while other threads are either +/// loading a reference to the global recorder, or attempting to initialize the global recorder, as +/// it can cause a data race. +#[doc(hidden)] +pub unsafe fn clear_recorder() { + RECORDER.clear(); +} + +/// The type returned by [`set_recorder`] if [`set_recorder`] has already been called. +#[derive(Debug)] +pub struct SetRecorderError(()); + +impl fmt::Display for SetRecorderError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(SET_RECORDER_ERROR) + } +} + +impl std::error::Error for SetRecorderError { + fn description(&self) -> &str { + SET_RECORDER_ERROR + } +} + +/// Returns a reference to the recorder. +/// +/// If a recorder has not been set, a no-op implementation is returned. +pub fn recorder() -> &'static dyn Recorder { + static NOOP: NoopRecorder = NoopRecorder; + try_recorder().unwrap_or(&NOOP) +} + +/// Returns a reference to the recorder. +/// +/// If a recorder has not been set, returns `None`. +pub fn try_recorder() -> Option<&'static dyn Recorder> { + RECORDER.try_load() +} diff --git a/vendor/mio/src/sys/unix/selector/mod.rs b/vendor/mio/src/sys/unix/selector/mod.rs new file mode 100644 index 0000000000000..322673d1d0a08 --- /dev/null +++ b/vendor/mio/src/sys/unix/selector/mod.rs @@ -0,0 +1,80 @@ +#[cfg(all( + not(mio_unsupported_force_poll_poll), + any( + target_os = "android", + target_os = "illumos", + target_os = "linux", + target_os = "redox", + ) +))] +mod epoll; + +#[cfg(all( + not(mio_unsupported_force_poll_poll), + any( + target_os = "android", + target_os = "illumos", + target_os = "linux", + target_os = "redox", + ) +))] +pub(crate) use self::epoll::{event, Event, Events, Selector}; + +#[cfg(any( + mio_unsupported_force_poll_poll, + target_os = "solaris", + target_os = "vita" +))] +mod poll; + +#[cfg(any( + mio_unsupported_force_poll_poll, + target_os = "solaris", + target_os = "vita" +))] +pub(crate) use self::poll::{event, Event, Events, Selector}; + +cfg_io_source! { + #[cfg(any(mio_unsupported_force_poll_poll, target_os = "solaris", target_os = "vita"))] + pub(crate) use self::poll::IoSourceState; +} + +#[cfg(all( + not(mio_unsupported_force_poll_poll), + any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "tvos", + target_os = "watchos", + ) +))] +mod kqueue; + +#[cfg(all( + not(mio_unsupported_force_poll_poll), + any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "tvos", + target_os = "watchos", + ), +))] +pub(crate) use self::kqueue::{event, Event, Events, Selector}; + +/// Lowest file descriptor used in `Selector::try_clone`. +/// +/// # Notes +/// +/// Usually fds 0, 1 and 2 are standard in, out and error. Some application +/// blindly assume this to be true, which means using any one of those a select +/// could result in some interesting and unexpected errors. Avoid that by using +/// an fd that doesn't have a pre-determined usage. +const LOWEST_FD: libc::c_int = 3; diff --git a/vendor/mio/src/sys/unix/uds/socketaddr.rs b/vendor/mio/src/sys/unix/uds/socketaddr.rs new file mode 100644 index 0000000000000..8e0ef53a4a04d --- /dev/null +++ b/vendor/mio/src/sys/unix/uds/socketaddr.rs @@ -0,0 +1,138 @@ +use super::path_offset; +use std::ffi::OsStr; +use std::os::unix::ffi::OsStrExt; +use std::path::Path; +use std::{ascii, fmt}; + +/// An address associated with a `mio` specific Unix socket. +/// +/// This is implemented instead of imported from [`net::SocketAddr`] because +/// there is no way to create a [`net::SocketAddr`]. One must be returned by +/// [`accept`], so this is returned instead. +/// +/// [`net::SocketAddr`]: std::os::unix::net::SocketAddr +/// [`accept`]: #method.accept +pub struct SocketAddr { + sockaddr: libc::sockaddr_un, + socklen: libc::socklen_t, +} + +struct AsciiEscaped<'a>(&'a [u8]); + +enum AddressKind<'a> { + Unnamed, + Pathname(&'a Path), + Abstract(&'a [u8]), +} + +impl SocketAddr { + fn address(&self) -> AddressKind<'_> { + let offset = path_offset(&self.sockaddr); + // Don't underflow in `len` below. + if (self.socklen as usize) < offset { + return AddressKind::Unnamed; + } + let len = self.socklen as usize - offset; + let path = unsafe { &*(&self.sockaddr.sun_path as *const [libc::c_char] as *const [u8]) }; + + // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses + if len == 0 + || (cfg!(not(any(target_os = "linux", target_os = "android"))) + && self.sockaddr.sun_path[0] == 0) + { + AddressKind::Unnamed + } else if self.sockaddr.sun_path[0] == 0 { + AddressKind::Abstract(&path[1..len]) + } else { + AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) + } + } +} + +cfg_os_poll! { + use std::{io, mem}; + + impl SocketAddr { + pub(crate) fn new(f: F) -> io::Result + where + F: FnOnce(*mut libc::sockaddr, &mut libc::socklen_t) -> io::Result, + { + let mut sockaddr = { + let sockaddr = mem::MaybeUninit::::zeroed(); + unsafe { sockaddr.assume_init() } + }; + + let raw_sockaddr = &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr; + let mut socklen = mem::size_of_val(&sockaddr) as libc::socklen_t; + + f(raw_sockaddr, &mut socklen)?; + Ok(SocketAddr::from_parts(sockaddr, socklen)) + } + + pub(crate) fn from_parts(sockaddr: libc::sockaddr_un, socklen: libc::socklen_t) -> SocketAddr { + SocketAddr { sockaddr, socklen } + } + + pub(crate) fn raw_sockaddr(&self) -> &libc::sockaddr_un { + &self.sockaddr + } + + pub(crate) fn raw_socklen(&self) -> &libc::socklen_t { + &self.socklen + } + + /// Returns `true` if the address is unnamed. + /// + /// Documentation reflected in [`SocketAddr`] + /// + /// [`SocketAddr`]: std::os::unix::net::SocketAddr + pub fn is_unnamed(&self) -> bool { + matches!(self.address(), AddressKind::Unnamed) + } + + /// Returns the contents of this address if it is a `pathname` address. + /// + /// Documentation reflected in [`SocketAddr`] + /// + /// [`SocketAddr`]: std::os::unix::net::SocketAddr + pub fn as_pathname(&self) -> Option<&Path> { + if let AddressKind::Pathname(path) = self.address() { + Some(path) + } else { + None + } + } + + /// Returns the contents of this address if it is an abstract namespace + /// without the leading null byte. + // Link to std::os::unix::net::SocketAddr pending + // https://github.com/rust-lang/rust/issues/85410. + pub fn as_abstract_namespace(&self) -> Option<&[u8]> { + if let AddressKind::Abstract(path) = self.address() { + Some(path) + } else { + None + } + } + } +} + +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.address() { + AddressKind::Unnamed => write!(fmt, "(unnamed)"), + AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), + AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), + } + } +} + +impl<'a> fmt::Display for AsciiEscaped<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "\"")?; + for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { + write!(fmt, "{}", byte as char)?; + } + write!(fmt, "\"") + } +} diff --git a/vendor/mio/src/sys/unix/waker.rs b/vendor/mio/src/sys/unix/waker.rs new file mode 100644 index 0000000000000..968f1a876a616 --- /dev/null +++ b/vendor/mio/src/sys/unix/waker.rs @@ -0,0 +1,339 @@ +#[cfg(all( + not(mio_unsupported_force_poll_poll), + not(all( + not(mio_unsupported_force_waker_pipe), + any( + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "tvos", + target_os = "watchos", + ) + )), + not(any(target_os = "solaris", target_os = "vita")), +))] +mod fdbased { + #[cfg(all( + not(mio_unsupported_force_waker_pipe), + any(target_os = "linux", target_os = "android"), + ))] + use crate::sys::unix::waker::eventfd::WakerInternal; + #[cfg(any( + mio_unsupported_force_waker_pipe, + target_os = "aix", + target_os = "dragonfly", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + ))] + use crate::sys::unix::waker::pipe::WakerInternal; + use crate::sys::Selector; + use crate::{Interest, Token}; + use std::io; + use std::os::unix::io::AsRawFd; + + #[derive(Debug)] + pub struct Waker { + waker: WakerInternal, + } + + impl Waker { + pub fn new(selector: &Selector, token: Token) -> io::Result { + let waker = WakerInternal::new()?; + selector.register(waker.as_raw_fd(), token, Interest::READABLE)?; + Ok(Waker { waker }) + } + + pub fn wake(&self) -> io::Result<()> { + self.waker.wake() + } + } +} + +#[cfg(all( + not(mio_unsupported_force_poll_poll), + not(all( + not(mio_unsupported_force_waker_pipe), + any( + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "tvos", + target_os = "watchos", + ) + )), + not(any(target_os = "solaris", target_os = "vita")), +))] +pub use self::fdbased::Waker; + +#[cfg(all( + not(mio_unsupported_force_waker_pipe), + any(target_os = "linux", target_os = "android", target_os = "espidf") +))] +mod eventfd { + use std::fs::File; + use std::io::{self, Read, Write}; + use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; + + /// Waker backed by `eventfd`. + /// + /// `eventfd` is effectively an 64 bit counter. All writes must be of 8 + /// bytes (64 bits) and are converted (native endian) into an 64 bit + /// unsigned integer and added to the count. Reads must also be 8 bytes and + /// reset the count to 0, returning the count. + #[derive(Debug)] + pub struct WakerInternal { + fd: File, + } + + impl WakerInternal { + pub fn new() -> io::Result { + #[cfg(not(target_os = "espidf"))] + let flags = libc::EFD_CLOEXEC | libc::EFD_NONBLOCK; + // ESP-IDF is EFD_NONBLOCK by default and errors if you try to pass this flag. + #[cfg(target_os = "espidf")] + let flags = 0; + let fd = syscall!(eventfd(0, flags))?; + + let file = unsafe { File::from_raw_fd(fd) }; + Ok(WakerInternal { fd: file }) + } + + pub fn wake(&self) -> io::Result<()> { + let buf: [u8; 8] = 1u64.to_ne_bytes(); + match (&self.fd).write(&buf) { + Ok(_) => Ok(()), + Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => { + // Writing only blocks if the counter is going to overflow. + // So we'll reset the counter to 0 and wake it again. + self.reset()?; + self.wake() + } + Err(err) => Err(err), + } + } + + #[cfg(mio_unsupported_force_poll_poll)] + pub fn ack_and_reset(&self) { + let _ = self.reset(); + } + + /// Reset the eventfd object, only need to call this if `wake` fails. + fn reset(&self) -> io::Result<()> { + let mut buf: [u8; 8] = 0u64.to_ne_bytes(); + match (&self.fd).read(&mut buf) { + Ok(_) => Ok(()), + // If the `Waker` hasn't been awoken yet this will return a + // `WouldBlock` error which we can safely ignore. + Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Ok(()), + Err(err) => Err(err), + } + } + } + + impl AsRawFd for WakerInternal { + fn as_raw_fd(&self) -> RawFd { + self.fd.as_raw_fd() + } + } +} + +#[cfg(all( + mio_unsupported_force_poll_poll, + not(mio_unsupported_force_waker_pipe), + any(target_os = "linux", target_os = "android", target_os = "espidf") +))] +pub(crate) use self::eventfd::WakerInternal; + +#[cfg(all( + not(mio_unsupported_force_waker_pipe), + any( + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "tvos", + target_os = "watchos", + ) +))] +mod kqueue { + use crate::sys::Selector; + use crate::Token; + + use std::io; + + /// Waker backed by kqueue user space notifications (`EVFILT_USER`). + /// + /// The implementation is fairly simple, first the kqueue must be setup to + /// receive waker events this done by calling `Selector.setup_waker`. Next + /// we need access to kqueue, thus we need to duplicate the file descriptor. + /// Now waking is as simple as adding an event to the kqueue. + #[derive(Debug)] + pub struct Waker { + selector: Selector, + token: Token, + } + + impl Waker { + pub fn new(selector: &Selector, token: Token) -> io::Result { + let selector = selector.try_clone()?; + selector.setup_waker(token)?; + Ok(Waker { selector, token }) + } + + pub fn wake(&self) -> io::Result<()> { + self.selector.wake(self.token) + } + } +} + +#[cfg(all( + not(mio_unsupported_force_waker_pipe), + any( + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "tvos", + target_os = "watchos", + ) +))] +pub use self::kqueue::Waker; + +#[cfg(any( + mio_unsupported_force_waker_pipe, + target_os = "aix", + target_os = "dragonfly", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "vita", +))] +mod pipe { + use crate::sys::unix::pipe; + use std::fs::File; + use std::io::{self, Read, Write}; + use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; + + /// Waker backed by a unix pipe. + /// + /// Waker controls both the sending and receiving ends and empties the pipe + /// if writing to it (waking) fails. + #[derive(Debug)] + pub struct WakerInternal { + sender: File, + receiver: File, + } + + impl WakerInternal { + pub fn new() -> io::Result { + let [receiver, sender] = pipe::new_raw()?; + let sender = unsafe { File::from_raw_fd(sender) }; + let receiver = unsafe { File::from_raw_fd(receiver) }; + Ok(WakerInternal { sender, receiver }) + } + + pub fn wake(&self) -> io::Result<()> { + // The epoll emulation on some illumos systems currently requires + // the pipe buffer to be completely empty for an edge-triggered + // wakeup on the pipe read side. + #[cfg(target_os = "illumos")] + self.empty(); + + match (&self.sender).write(&[1]) { + Ok(_) => Ok(()), + Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => { + // The reading end is full so we'll empty the buffer and try + // again. + self.empty(); + self.wake() + } + Err(ref err) if err.kind() == io::ErrorKind::Interrupted => self.wake(), + Err(err) => Err(err), + } + } + + #[cfg(any( + mio_unsupported_force_poll_poll, + target_os = "solaris", + target_os = "vita" + ))] + pub fn ack_and_reset(&self) { + self.empty(); + } + + /// Empty the pipe's buffer, only need to call this if `wake` fails. + /// This ignores any errors. + fn empty(&self) { + let mut buf = [0; 4096]; + loop { + match (&self.receiver).read(&mut buf) { + Ok(n) if n > 0 => continue, + _ => return, + } + } + } + } + + impl AsRawFd for WakerInternal { + fn as_raw_fd(&self) -> RawFd { + self.receiver.as_raw_fd() + } + } +} + +#[cfg(any( + all( + mio_unsupported_force_poll_poll, + any( + mio_unsupported_force_waker_pipe, + target_os = "aix", + target_os = "dragonfly", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + ) + ), + target_os = "solaris", + target_os = "vita", +))] +pub(crate) use self::pipe::WakerInternal; + +#[cfg(any( + mio_unsupported_force_poll_poll, + target_os = "solaris", + target_os = "vita" +))] +mod poll { + use crate::sys::Selector; + use crate::Token; + use std::io; + + #[derive(Debug)] + pub struct Waker { + selector: Selector, + token: Token, + } + + impl Waker { + pub fn new(selector: &Selector, token: Token) -> io::Result { + Ok(Waker { + selector: selector.try_clone()?, + token, + }) + } + + pub fn wake(&self) -> io::Result<()> { + self.selector.wake(self.token) + } + } +} + +#[cfg(any( + mio_unsupported_force_poll_poll, + target_os = "solaris", + target_os = "vita" +))] +pub use self::poll::Waker; diff --git a/vendor/nix-0.26.2/.cargo-checksum.json b/vendor/nix-0.26.2/.cargo-checksum.json new file mode 100644 index 0000000000000..0439f839e3276 --- /dev/null +++ b/vendor/nix-0.26.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"8ee4e556e53d1b39400a48675d3ecff0bf27e419accab7ca3be76ab934289548","Cargo.toml":"823d83e685eea7ae0398fe6497b2a076166aecb1f35fd51d2f58da6fe7571dfe","LICENSE":"66e3ee1fa7f909ad3c612d556f2a0cdabcd809ad6e66f3b0605015ac64841b70","README.md":"1ed9a0e26ae6e575b3262ae734dd02889455593b761ee62403ea5a64104f3c9c","src/dir.rs":"0280a2dc480bd913f24ed84fbe26569fa2e8eefa660e5ad7c21e05fc34c14d16","src/env.rs":"028bc5e20139ebba418a655a2978a53335dc7680bf1de43d2c8333dd72cfa5c4","src/errno.rs":"e55d075858e349d9afea9ce0480f7fb7ba4dccccf0694fd7b3280b918836203c","src/fcntl.rs":"ea8f43d8fec0b6c3b7d903333e4c1ce85611684a4afd561c55cfe4b61a979e94","src/features.rs":"5b4a0831e5f4b79a6f0e42ed052fd66c875da18959750be51e41fb59ac19feed","src/ifaddrs.rs":"377865eb48040d28c392a1aec0221320108e3392ea285d23405ae2cfa5c54b20","src/kmod.rs":"c818ced08d55ae36fdf82fa914ba856b688e37234d574d3faa37128211d512fb","src/lib.rs":"a62fac2ba7111157c5b64251f67f8a189f04bd587d5c80703454a596ea7ae5d9","src/macros.rs":"e23d7d8be22ef0bf9febaaf2739585453103607c0139bd3995a324e4a16d011e","src/mount/bsd.rs":"4cf35606a63d7ca41caac3b38f01e2b70c63e71978c0529f19fc79182629dbe0","src/mount/linux.rs":"6e5d61788dedf1ca4416c6c6a3a9c6c747f9352c26d863f4a1d4142e288584d6","src/mount/mod.rs":"ba9f60eb831224ab73bdd87e00e15d13b9ce9efb70b18bf8f3fe60406d522b3e","src/mqueue.rs":"ed0a189036b2437b5f7f7f1312fa545540b06ca72171b451d8bce42cc3627534","src/net/if_.rs":"b32a8a1f952de60d95e549779a5c673fd72aa665e86bfdfc8ec6badf3016b9b1","src/net/mod.rs":"577f70170e53d4a6de1abb70bf8f1031ec3e65c0e63ef5fcf05c907125e7ac17","src/poll.rs":"2fc1d144fb40db51811c6357b520ab7993529702d8f0d8060c903118ff4f7259","src/pty.rs":"27b4f76c23acf02542674017067fee74cdcac907338458700a1aa4d6f6a62e27","src/sched.rs":"403aa5ebed81910263d42a94717612b737550bf053227b7d90f1c8949188d919","src/sys/aio.rs":"ae091de8540c97da374a39e7d154c1b3ce50f41e6fc20a45c6b06eb838e74366","src/sys/epoll.rs":"28e22debf474d1b047e8044a00b354c25dab2fa125960f9f2f14cc34289fd5c9","src/sys/event.rs":"dbd8e84bccb813839295b0a336485783ef19548d2317931f0ceb5ee62f839a40","src/sys/eventfd.rs":"c8db8f5874726fdad289ad5e2603a7d71a1ae5a899dcde3a35d3edff8b498b7e","src/sys/inotify.rs":"5b4da774313afa9c28c3f92f9d07dce9bf4c8d044fd6a16f19480e79a19e808b","src/sys/ioctl/bsd.rs":"bbd02e30b0a78c1cb22777d9b00cfcbba9c68505cffc06118ac68474cf6fea39","src/sys/ioctl/linux.rs":"028181834d119b834bf399f2b8a6176cc57e75144693f28f32059d087d8c8018","src/sys/ioctl/mod.rs":"89b20579476b2e0254e0ecb1b41830cccd7027a22cbdb816a9d4ec3924842ac1","src/sys/memfd.rs":"d6f5d00ad68ac16602f1dd06ac8e974e206a95342ee93a1838eb5c16979ff0fc","src/sys/mman.rs":"17df1bc34ba92bdd6bad1e11e4ef139998117f6c468c8f560421858f3cc899a5","src/sys/mod.rs":"baabf649f758ad4acce849ec1795dd4e4f9c6539e677bad5fa777300a4871dcb","src/sys/personality.rs":"aa89760c023bfec3fca5d8636f9eac9d337f5547933793ce6df7a0de97ae6ee1","src/sys/pthread.rs":"258cdf7ff0b61a4afa6d228109e4cb4fb88d859bb8dfe6c959d95130fb010906","src/sys/ptrace/bsd.rs":"4c590d8f023ff52f396f8b6f2150c08e5c9486d3088d9c173db33a70d616b800","src/sys/ptrace/linux.rs":"c82db3fb18aa97755f9ccb440a957cd46d664968a94045830c5d74d2d53bc19f","src/sys/ptrace/mod.rs":"e9e5d970097f5eafffba900959d4fdbf233bff9ed7f599fc9896bb44d86a57a4","src/sys/quota.rs":"02e698a25f0986fb43aa88689f3d3d8b9edc6ae48496ad02f7214fccaa493e00","src/sys/reboot.rs":"eacdf57694a6629fb05787e16450446102a62818274495f2ad4e445807d09221","src/sys/resource.rs":"d498d0c00fd30e35e1269a8902cb812014d813f63ec95364f8f59f1912ba5657","src/sys/select.rs":"65c39b129d3cc85b8ca026ff26dcf80c5639824f43715881c3c1bbb6bf0c8a60","src/sys/sendfile.rs":"7a62099f9771fecff49b9c11210341e3c1a4acf22f8dfb96d395e29421648676","src/sys/signal.rs":"c3e13a2edea54d190a4b051f62efc97953c00b5051a9fda0e39e3bc732a31939","src/sys/signalfd.rs":"583524434fd37143be3db37fa6f6cbd339f7946416f05b58a95e246947e5cc9d","src/sys/socket/addr.rs":"84df895052f59ec84774b189ffb285d2a37a9703af6c8310ae5040cca1a2583e","src/sys/socket/mod.rs":"6deb55438cad3606385303f036b0efd842dfd759fba93611911f5a4f2613c9dc","src/sys/socket/sockopt.rs":"ed1f920364bfe88bbe6eaeeefb27a63bfcdd7d67604aca2f03e22f2b502df55a","src/sys/stat.rs":"337dea8d55d6177dc85b3235b40b8a3e81af7f4a6e2806a0b2f730bec5424350","src/sys/statfs.rs":"17103659a85279bac046c69cb3b22bf2c11c2492cffb0edfa4c3b233d161a2f2","src/sys/statvfs.rs":"f81e3900ef90d62e7eceaf1b6ff8dcfd965466714c033eb4717687f692171f48","src/sys/sysinfo.rs":"b4519b1ca091c9dbe94d2a6fd6304944bf3df5626973d2c6884022559706f0d9","src/sys/termios.rs":"7923f9846a8122096b6b1cd240d3618b876ce500a751ac434954d172e2e85745","src/sys/time.rs":"9026033b60a5ccc95b70424aef043c8c748722e2ea8c7c86366ecd4585b651a0","src/sys/timer.rs":"8c10f0e7cfac857ad00460be30bc68b957909cc9296e70718d3b5d4a0babafde","src/sys/timerfd.rs":"ef7c48aefdcfac13316eeddbef5da04cf12e9f574b8d9f43402c02b6b8db86b3","src/sys/uio.rs":"e1d59ccbee9d46c65d3aa8c36aa3a3222539beea0d20163a8b707d08fca14e09","src/sys/utsname.rs":"0cdda0cc111caaa0e4ebe2d4588bdc825d878e5bcb7a9136073b15f87a20e11f","src/sys/wait.rs":"cc70d2d9b880ff6c48577a479c209af6127067bc013a90ee22538e4dfad7d2b4","src/time.rs":"d4e0872361a57810837f5bd790cbca3a2b9db1ac4694a3c52d1564ad3532d3be","src/ucontext.rs":"b8f2e04757a9c2bc38c3b1e259d3a013da8a730fe9bfbe5487637395681b43d3","src/unistd.rs":"e19be456124731c5b93aef92ed72a7c4c9092e28db0649814ba3fcc1f0d620fa","test/common/mod.rs":"1d7e28e3635754664cd056f3a1079232ff5c118df619e1d0551a9972eb0b3cd6","test/sys/mod.rs":"87b2891d83067ff21f72b8ff7fde3019dc45b6877282ac278b6da151de45c7a7","test/sys/test_aio.rs":"4dac9f716f852f1f438f78d6e64bf041e6fd316bf15dcb27afffaf0894bdefa6","test/sys/test_aio_drop.rs":"614070155fa16a979b7341d001639c5ce24a1d6f632c3abce45a5a6d49c4039b","test/sys/test_epoll.rs":"ffe95e36c79e37426ef8e8ca3b137b7f35ea0333ce666a20a4b7878db17680e9","test/sys/test_inotify.rs":"a141b9a995892547b51ceeb6761a70a6b86d37e8f38d13ea2c497b81b4b0f49f","test/sys/test_ioctl.rs":"00ccc5afb665e533a0a4b6d6a6be438bcaea19fce335390feef4e91d17b3036c","test/sys/test_mman.rs":"2b4161964c9204b74659028b0f89a88f4e3bcc9886137a3039737cd91d2698cb","test/sys/test_pthread.rs":"ace36a2f5587f1874854281b4fd84e4e4d892a1e3c5cc38ced57975739522ad6","test/sys/test_ptrace.rs":"0385eebc8b1b8c72f655b745769decd9143ad83018198375982da0896310456b","test/sys/test_select.rs":"54cea1c34ad28d5770a613c1c3cbc3b1064b22037ec2b9d3fcd422d3be9e60a7","test/sys/test_signal.rs":"acc9941227bd3e2afad323613c2b8c83902ed0486d3745fd72704f395924f1e4","test/sys/test_signalfd.rs":"0e1060143e2612c490bc3d0168d0bbb042ef55e3f1d91d2578b9e42e4310a14d","test/sys/test_socket.rs":"d2df1001f9a0b2dac0b88051a67c3868bb216e72e4da4eecd11c4448b9fa4b40","test/sys/test_sockopt.rs":"4465f22f718442f3f7b502e052dad02b93cebfa3b71fa55ff4f25fb02534acab","test/sys/test_stat.rs":"6630a28217fd708bb84cd4f7e7101836b74f2420f9888923fdab664ccc331c1d","test/sys/test_sysinfo.rs":"ffd49bc96375914a2c4a4a59730cae8072f85771e2c4a80d3403df38d967e272","test/sys/test_termios.rs":"e5bcef10c84bd7583d600d5601835bcb3cfc88781cb283ab0185bbef5faf4327","test/sys/test_timerfd.rs":"cfed3abf58118611d08f6985251a7739cff67108e11214222a1d2394a3a026ce","test/sys/test_uio.rs":"32656bd0a5699e4d019aa928edf104637937179782914a82d50d37226e84c421","test/sys/test_wait.rs":"6fd59fffeeb09ff620c359baefd062ba777598982b6cb001ccc07b6bc7605493","test/test.rs":"11f40b0718ddd1a150cb9e703d56d0b2a9462306505a2245ddf273a2011f48b5","test/test_clearenv.rs":"45ca548035b3c20ec87314715feaba2be973709a635d85b8cde46fd1d9f1ecd4","test/test_dir.rs":"ae3c11c58cb06da6557aa2a839c6653c54cd7724283fffe9df5a5d3feabdd89a","test/test_fcntl.rs":"71dcb87f7b04d78fc62937ba46cb7f0f1f2dbb330b63a996ea2e8ec9056b98a9","test/test_kmod/hello_mod/Makefile":"0219f7bce0603f97d997fb377ca071966c90333ecc665e78a54dfeb97a9c811b","test/test_kmod/hello_mod/hello.c":"bcac6b19c5bd807e1f3878c15e426acc85785a8ade9840c3bb4d068635c9188c","test/test_kmod/mod.rs":"b4ae25841c2f06f32de9f1acd8230eeccd7095721302ebe78ad454e4e4f9c783","test/test_mount.rs":"6dd242b6e23c9c39e1a75612bbea62573898818ab374c3c032c2cdb97033554d","test/test_mq.rs":"136071f24131aac0e65d5f29ac18e3806641dfae1164813f5570c0e3a6f70553","test/test_net.rs":"f2912327ebb2a3d37e6cff02a5ac3106cf889cc5c74404db4ef0034059ba26f1","test/test_nix_path.rs":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","test/test_nmount.rs":"d6c112547bb80968170b5497cda4b6cbf69dabec6f51d494bd52298995ceff18","test/test_poll.rs":"3e0b8f0397ba080785c61a3bfc3d637bc87f324bc4e52b5f1bf3ca0d32dbc9fe","test/test_pty.rs":"b26238a0783746cb31880e11eebc1913149be999ce75fbc2d6677bdd1e2731b2","test/test_ptymaster_drop.rs":"ae63c815f5028ddc67d194e86559483018ab1816316bdb917f40cee9364fd8a5","test/test_resource.rs":"40aef790ab745cec31a4b333d2ca406b462aa9bdf4a6d3756371e498b8d51e9a","test/test_sched.rs":"c4579bd376fab8816e63b07fa9ace31dc08e63ebb7c855a2c450698090d1d1e8","test/test_sendfile.rs":"bb41b4f3621b518e397d3a5b5ad3c5dcef3fe506afe516eab7572fbab92b77e3","test/test_stat.rs":"c407ca47a5258750076d041afad2f6add4c3563be36628bde1c5b314f5d0765d","test/test_time.rs":"f7a21b1e279e60e84909d5dadda97ded66d3326b131fe317badf9af0a1b50335","test/test_timer.rs":"3ae20d364f075d2811f3ff94eda9886682cc21d8807656007d2464fe36d1e361","test/test_unistd.rs":"20a00be4fbe26302ea5fe50ce25b99265dc763db138663d6aa1d7ac729a1d292"},"package":null} \ No newline at end of file diff --git a/vendor/nix-0.26.2/CHANGELOG.md b/vendor/nix-0.26.2/CHANGELOG.md new file mode 100644 index 0000000000000..283cb86a36469 --- /dev/null +++ b/vendor/nix-0.26.2/CHANGELOG.md @@ -0,0 +1,1585 @@ +# Change Log + +All notable changes to this project will be documented in this file. +This project adheres to [Semantic Versioning](https://semver.org/). + +## [0.26.2] - 2023-01-18 +### Fixed +- Fix `SockaddrIn6` bug that was swapping flowinfo and scope_id byte ordering. + ([#1964](https://github.com/nix-rust/nix/pull/1964)) + +## [0.26.1] - 2022-11-29 +### Fixed +- Fix UB with `sys::socket::sockopt::SockType` using `SOCK_PACKET`. + ([#1821](https://github.com/nix-rust/nix/pull/1821)) + +## [0.26.0] - 2022-11-29 +### Added + +- Added `SockaddrStorage::{as_unix_addr, as_unix_addr_mut}` + ([#1871](https://github.com/nix-rust/nix/pull/1871)) +- Added `MntFlags` and `unmount` on all of the BSDs. +- Added `any()` and `all()` to `poll::PollFd`. + ([#1877](https://github.com/nix-rust/nix/pull/1877)) +- Add `MntFlags` and `unmount` on all of the BSDs. + ([#1849](https://github.com/nix-rust/nix/pull/1849)) +- Added a `Statfs::flags` method. + ([#1849](https://github.com/nix-rust/nix/pull/1849)) +- Added `NSFS_MAGIC` FsType on Linux and Android. + ([#1829](https://github.com/nix-rust/nix/pull/1829)) +- Added `sched_getcpu` on platforms that support it. + ([#1825](https://github.com/nix-rust/nix/pull/1825)) +- Added `sched_getaffinity` and `sched_setaffinity` on FreeBSD. + ([#1804](https://github.com/nix-rust/nix/pull/1804)) +- Added `line_discipline` field to `Termios` on Linux, Android and Haiku + ([#1805](https://github.com/nix-rust/nix/pull/1805)) +- Expose the memfd module on FreeBSD (memfd was added in FreeBSD 13) + ([#1808](https://github.com/nix-rust/nix/pull/1808)) +- Added `domainname` field of `UtsName` on Android and Linux + ([#1817](https://github.com/nix-rust/nix/pull/1817)) +- Re-export `RLIM_INFINITY` from `libc` + ([#1831](https://github.com/nix-rust/nix/pull/1831)) +- Added `syncfs(2)` on Linux + ([#1833](https://github.com/nix-rust/nix/pull/1833)) +- Added `faccessat(2)` on illumos + ([#1841](https://github.com/nix-rust/nix/pull/1841)) +- Added `eaccess()` on FreeBSD, DragonFly and Linux (glibc and musl). + ([#1842](https://github.com/nix-rust/nix/pull/1842)) +- Added `IP_TOS` `SO_PRIORITY` and `IPV6_TCLASS` sockopts for Linux + ([#1853](https://github.com/nix-rust/nix/pull/1853)) +- Added `new_unnamed` and `is_unnamed` for `UnixAddr` on Linux and Android. + ([#1857](https://github.com/nix-rust/nix/pull/1857)) +- Added `SockProtocol::Raw` for raw sockets + ([#1848](https://github.com/nix-rust/nix/pull/1848)) +- added `IP_MTU` (`IpMtu`) `IPPROTO_IP` sockopt on Linux and Android. + ([#1865](https://github.com/nix-rust/nix/pull/1865)) + +### Changed + +- The MSRV is now 1.56.1 + ([#1792](https://github.com/nix-rust/nix/pull/1792)) +- The `addr` argument of `sys::mman::mmap` is now of type `Option`. + ([#1870](https://github.com/nix-rust/nix/pull/1870)) +- The `length` argument of `sys::mman::mmap` is now of type `NonZeroUsize`. + ([#1873](https://github.com/nix-rust/nix/pull/1873)) + +### Fixed + +- Fixed using `SockaddrStorage` to store a Unix-domain socket address on Linux. + ([#1871](https://github.com/nix-rust/nix/pull/1871)) +- Fix microsecond calculation for `TimeSpec`. + ([#1801](https://github.com/nix-rust/nix/pull/1801)) +- Fix `User::from_name` and `Group::from_name` panicking + when given a name containing a nul. + ([#1815](https://github.com/nix-rust/nix/pull/1815)) +- Fix `User::from_uid` and `User::from_name` crash on Android platform. + ([#1824](https://github.com/nix-rust/nix/pull/1824)) +- Workaround XNU bug causing netmasks returned by `getifaddrs` to misbehave. + ([#1788](https://github.com/nix-rust/nix/pull/1788)) + +### Removed + +- Removed deprecated error constants and conversions. + ([#1860](https://github.com/nix-rust/nix/pull/1860)) + +## [0.25.0] - 2022-08-13 +### Added + +- Added `faccessat` + ([#1780](https://github.com/nix-rust/nix/pull/1780)) +- Added `memfd` on Android. + (#[1773](https://github.com/nix-rust/nix/pull/1773)) +- Added `ETH_P_ALL` to `SockProtocol` enum + (#[1768](https://github.com/nix-rust/nix/pull/1768)) +- Added four non-standard Linux `SysconfVar` variants + (#[1761](https://github.com/nix-rust/nix/pull/1761)) +- Added const constructors for `TimeSpec` and `TimeVal` + (#[1760](https://github.com/nix-rust/nix/pull/1760)) +- Added `chflags`. + (#[1758](https://github.com/nix-rust/nix/pull/1758)) +- Added `aio_writev` and `aio_readv`. + (#[1713](https://github.com/nix-rust/nix/pull/1713)) +- impl `From` for `Uid` and `From` for `Gid` + (#[1727](https://github.com/nix-rust/nix/pull/1727)) +- impl `From` for `std::net::SocketAddrV4` and + impl `From` for `std::net::SocketAddrV6`. + (#[1711](https://github.com/nix-rust/nix/pull/1711)) +- Added support for the `x86_64-unknown-haiku` target. + (#[1703](https://github.com/nix-rust/nix/pull/1703)) +- Added `ptrace::read_user` and `ptrace::write_user` for Linux. + (#[1697](https://github.com/nix-rust/nix/pull/1697)) +- Added `getrusage` and helper types `UsageWho` and `Usage` + (#[1747](https://github.com/nix-rust/nix/pull/1747)) +- Added the `DontRoute` SockOpt + (#[1752](https://github.com/nix-rust/nix/pull/1752)) +- Added `signal::SigSet::from_sigset_t_unchecked()`. + (#[1741](https://github.com/nix-rust/nix/pull/1741)) +- Added the `Ipv4OrigDstAddr` sockopt and control message. + (#[1772](https://github.com/nix-rust/nix/pull/1772)) +- Added the `Ipv6OrigDstAddr` sockopt and control message. + (#[1772](https://github.com/nix-rust/nix/pull/1772)) +- Added the `Ipv4SendSrcAddr` control message. + (#[1776](https://github.com/nix-rust/nix/pull/1776)) + +### Changed + +- Reimplemented sendmmsg/recvmmsg to avoid allocations and with better API + (#[1744](https://github.com/nix-rust/nix/pull/1744)) + +- Rewrote the aio module. The new module: + * Does more type checking at compile time rather than runtime. + * Gives the caller control over whether and when to `Box` an aio operation. + * Changes the type of the `priority` arguments to `i32`. + * Changes the return type of `aio_return` to `usize`. + (#[1713](https://github.com/nix-rust/nix/pull/1713)) +- `nix::poll::ppoll`: `sigmask` parameter is now optional. + (#[1739](https://github.com/nix-rust/nix/pull/1739)) +- Changed `gethostname` to return an owned `OsString`. + (#[1745](https://github.com/nix-rust/nix/pull/1745)) +- `signal:SigSet` is now marked as `repr(transparent)`. + (#[1741](https://github.com/nix-rust/nix/pull/1741)) + +### Removed + +- Removed support for resubmitting partially complete `lio_listio` operations. + It was too complicated, and didn't fit Nix's theme of zero-cost abstractions. + Instead, it can be reimplemented downstream. + (#[1713](https://github.com/nix-rust/nix/pull/1713)) + +## [0.24.2] - 2022-07-17 +### Fixed + +- Fixed buffer overflow in `nix::sys::socket::recvfrom`. + (#[1763](https://github.com/nix-rust/nix/pull/1763)) +- Enabled `SockaddrStorage::{as_link_addr, as_link_addr_mut}` for Linux-like + operating systems. + (#[1729](https://github.com/nix-rust/nix/pull/1729)) +- Fixed `SockaddrLike::from_raw` implementations for `VsockAddr` and + `SysControlAddr`. + (#[1736](https://github.com/nix-rust/nix/pull/1736)) + +## [0.24.1] - 2022-04-22 +### Fixed + +- Fixed `UnixAddr::size` on Linux-based OSes. + (#[1702](https://github.com/nix-rust/nix/pull/1702)) + +## [0.24.0] - 2022-04-21 +### Added + +- Added fine-grained features flags. Most Nix functionality can now be + conditionally enabled. By default, all features are enabled. + (#[1611](https://github.com/nix-rust/nix/pull/1611)) +- Added statfs FS type magic constants for `target_os = "android"` + and synced constants with libc v0.2.121. + (#[1690](https://github.com/nix-rust/nix/pull/1690)) +- Added `fexecve` on DragonFly. + (#[1577](https://github.com/nix-rust/nix/pull/1577)) +- `sys::uio::IoVec` is now `Send` and `Sync` + (#[1582](https://github.com/nix-rust/nix/pull/1582)) +- Added `EPOLLEXCLUSIVE` on Android. + (#[1567](https://github.com/nix-rust/nix/pull/1567)) +- Added `fdatasync` for FreeBSD, Fuchsia, NetBSD, and OpenBSD. + (#[1581](https://github.com/nix-rust/nix/pull/1581)) +- Added `sched_setaffinity` and `sched_getaffinity` on DragonFly. + (#[1537](https://github.com/nix-rust/nix/pull/1537)) +- Added `posix_fallocate` on DragonFly. + (#[1621](https://github.com/nix-rust/nix/pull/1621)) +- Added `SO_TIMESTAMPING` support + (#[1547](https://github.com/nix-rust/nix/pull/1547)) +- Added getter methods to `MqAttr` struct + (#[1619](https://github.com/nix-rust/nix/pull/1619)) +- Added the `TxTime` sockopt and control message. + (#[1564](https://github.com/nix-rust/nix/pull/1564)) +- Added POSIX per-process timer support + (#[1622](https://github.com/nix-rust/nix/pull/1622)) +- Added `sendfile` on DragonFly. + (#[1615](https://github.com/nix-rust/nix/pull/1615)) +- Added `UMOUNT_NOFOLLOW`, `FUSE_SUPER_MAGIC` on Linux. + (#[1634](https://github.com/nix-rust/nix/pull/1634)) +- Added `getresuid`, `setresuid`, `getresgid`, and `setresgid` on DragonFly, FreeBSD, and OpenBSD. + (#[1628](https://github.com/nix-rust/nix/pull/1628)) +- Added `MAP_FIXED_NOREPLACE` on Linux. + (#[1636](https://github.com/nix-rust/nix/pull/1636)) +- Added `fspacectl` on FreeBSD + (#[1640](https://github.com/nix-rust/nix/pull/1640)) +- Added `accept4` on DragonFly, Emscripten, Fuchsia, Illumos, and NetBSD. + (#[1654](https://github.com/nix-rust/nix/pull/1654)) +- Added `AsRawFd` implementation on `OwningIter`. + (#[1563](https://github.com/nix-rust/nix/pull/1563)) +- Added `process_vm_readv` and `process_vm_writev` on Android. + (#[1557](https://github.com/nix-rust/nix/pull/1557)) +- Added `nix::uncontext` module on s390x. + (#[1662](https://github.com/nix-rust/nix/pull/1662)) +- Implemented `Extend`, `FromIterator`, and `IntoIterator` for `SigSet` and + added `SigSet::iter` and `SigSetIter`. + (#[1553](https://github.com/nix-rust/nix/pull/1553)) +- Added `ENOTRECOVERABLE` and `EOWNERDEAD` error codes on DragonFly. + (#[1665](https://github.com/nix-rust/nix/pull/1665)) +- Implemented `Read` and `Write` for `&PtyMaster` + (#[1664](https://github.com/nix-rust/nix/pull/1664)) +- Added `MSG_NOSIGNAL` for Android, Dragonfly, FreeBSD, Fuchsia, Haiku, Illumos, Linux, NetBSD, OpenBSD and Solaris. + (#[1670](https://github.com/nix-rust/nix/pull/1670)) +- Added `waitid`. + (#[1584](https://github.com/nix-rust/nix/pull/1584)) +- Added `Ipv6DontFrag` for android, iOS, linux and macOS. +- Added `IpDontFrag` for iOS, macOS. + (#[1692](https://github.com/nix-rust/nix/pull/1692)) + +### Changed + +- `mqueue` functions now operate on a distinct type, `nix::mqueue::MqdT`. + Accessors take this type by reference, not by value. + (#[1639](https://github.com/nix-rust/nix/pull/1639)) +- Removed `SigSet::extend` in favor of `>::extend`. + Because of this change, you now need `use std::iter::Extend` to call `extend` + on a `SigSet`. + (#[1553](https://github.com/nix-rust/nix/pull/1553)) +- Removed the the `PATH_MAX` restriction from APIs accepting paths. Paths + will now be allocated on the heap if they are too long. In addition, large + instruction count improvements (~30x) were made to path handling. + (#[1656](https://github.com/nix-rust/nix/pull/1656)) +- Changed `getrlimit` and `setrlimit` to use `rlim_t` directly + instead of `Option`. + (#[1668](https://github.com/nix-rust/nix/pull/1668)) +- Deprecated `InetAddr` and `SockAddr` in favor of `SockaddrIn`, `SockaddrIn6`, + and `SockaddrStorage`. + (#[1684](https://github.com/nix-rust/nix/pull/1684)) +- Deprecated `IpAddr`, `Ipv4Addr`, and `Ipv6Addr` in favor of their equivalents + from the standard library. + (#[1685](https://github.com/nix-rust/nix/pull/1685)) +- `uname` now returns a `Result` instead of just a `UtsName` and + ignoring failures from libc. And getters on the `UtsName` struct now return + an `&OsStr` instead of `&str`. + (#[1672](https://github.com/nix-rust/nix/pull/1672)) +- Replaced `IoVec` with `IoSlice` and `IoSliceMut`, and replaced `IoVec::from_slice` with + `IoSlice::new`. (#[1643](https://github.com/nix-rust/nix/pull/1643)) + +### Fixed + +- `InetAddr::from_std` now sets the `sin_len`/`sin6_len` fields on the BSDs. + (#[1642](https://github.com/nix-rust/nix/pull/1642)) +- Fixed a panic in `LinkAddr::addr`. That function now returns an `Option`. + (#[1675](https://github.com/nix-rust/nix/pull/1675)) + (#[1677](https://github.com/nix-rust/nix/pull/1677)) + +### Removed + +- Removed public access to the inner fields of `NetlinkAddr`, `AlgAddr`, + `SysControlAddr`, `LinkAddr`, and `VsockAddr`. + (#[1614](https://github.com/nix-rust/nix/pull/1614)) +- Removed `EventFlag::EV_SYSFLAG`. + (#[1635](https://github.com/nix-rust/nix/pull/1635)) + +## [0.23.1] - 2021-12-16 + +### Changed + +- Relaxed the bitflags requirement from 1.3.1 to 1.1. This partially reverts + #1492. From now on, the MSRV is not guaranteed to work with all versions of + all dependencies, just with some version of all dependencies. + (#[1607](https://github.com/nix-rust/nix/pull/1607)) + +### Fixed + +- Fixed soundness issues in `FdSet::insert`, `FdSet::remove`, and + `FdSet::contains` involving file descriptors outside of the range + `0..FD_SETSIZE`. + (#[1575](https://github.com/nix-rust/nix/pull/1575)) + +## [0.23.0] - 2021-09-28 +### Added + +- Added the `LocalPeerCred` sockopt. + (#[1482](https://github.com/nix-rust/nix/pull/1482)) +- Added `TimeSpec::from_duration` and `TimeSpec::from_timespec` + (#[1465](https://github.com/nix-rust/nix/pull/1465)) +- Added `IPV6_V6ONLY` sockopt. + (#[1470](https://github.com/nix-rust/nix/pull/1470)) +- Added `impl From for libc::passwd` trait implementation to convert a `User` + into a `libc::passwd`. Consumes the `User` struct to give ownership over + the member pointers. + (#[1471](https://github.com/nix-rust/nix/pull/1471)) +- Added `pthread_kill`. + (#[1472](https://github.com/nix-rust/nix/pull/1472)) +- Added `mknodat`. + (#[1473](https://github.com/nix-rust/nix/pull/1473)) +- Added `setrlimit` and `getrlimit`. + (#[1302](https://github.com/nix-rust/nix/pull/1302)) +- Added `ptrace::interrupt` method for platforms that support `PTRACE_INTERRUPT` + (#[1422](https://github.com/nix-rust/nix/pull/1422)) +- Added `IP6T_SO_ORIGINAL_DST` sockopt. + (#[1490](https://github.com/nix-rust/nix/pull/1490)) +- Added the `PTRACE_EVENT_STOP` variant to the `sys::ptrace::Event` enum + (#[1335](https://github.com/nix-rust/nix/pull/1335)) +- Exposed `SockAddr::from_raw_sockaddr` + (#[1447](https://github.com/nix-rust/nix/pull/1447)) +- Added `TcpRepair` + (#[1503](https://github.com/nix-rust/nix/pull/1503)) +- Enabled `pwritev` and `preadv` for more operating systems. + (#[1511](https://github.com/nix-rust/nix/pull/1511)) +- Added support for `TCP_MAXSEG` TCP Maximum Segment Size socket options + (#[1292](https://github.com/nix-rust/nix/pull/1292)) +- Added `Ipv4RecvErr` and `Ipv6RecvErr` sockopts and associated control messages. + (#[1514](https://github.com/nix-rust/nix/pull/1514)) +- Added `AsRawFd` implementation on `PollFd`. + (#[1516](https://github.com/nix-rust/nix/pull/1516)) +- Added `Ipv4Ttl` and `Ipv6Ttl` sockopts. + (#[1515](https://github.com/nix-rust/nix/pull/1515)) +- Added `MAP_EXCL`, `MAP_ALIGNED_SUPER`, and `MAP_CONCEAL` mmap flags, and + exposed `MAP_ANONYMOUS` for all operating systems. + (#[1522](https://github.com/nix-rust/nix/pull/1522)) + (#[1525](https://github.com/nix-rust/nix/pull/1525)) + (#[1531](https://github.com/nix-rust/nix/pull/1531)) + (#[1534](https://github.com/nix-rust/nix/pull/1534)) +- Added read/write accessors for 'events' on `PollFd`. + (#[1517](https://github.com/nix-rust/nix/pull/1517)) + +### Changed + +- `FdSet::{contains, highest, fds}` no longer require a mutable reference. + (#[1464](https://github.com/nix-rust/nix/pull/1464)) +- `User::gecos` and corresponding `libc::passwd::pw_gecos` are supported on + 64-bit Android, change conditional compilation to include the field in + 64-bit Android builds + (#[1471](https://github.com/nix-rust/nix/pull/1471)) +- `eventfd`s are supported on Android, change conditional compilation to + include `sys::eventfd::eventfd` and `sys::eventfd::EfdFlags`for Android + builds. + (#[1481](https://github.com/nix-rust/nix/pull/1481)) +- Most enums that come from C, for example `Errno`, are now marked as + `#[non_exhaustive]`. + (#[1474](https://github.com/nix-rust/nix/pull/1474)) +- Many more functions, mostly contructors, are now `const`. + (#[1476](https://github.com/nix-rust/nix/pull/1476)) + (#[1492](https://github.com/nix-rust/nix/pull/1492)) +- `sys::event::KEvent::filter` now returns a `Result` instead of being + infalliable. The only cases where it will now return an error are cases + where it previously would've had undefined behavior. + (#[1484](https://github.com/nix-rust/nix/pull/1484)) +- Minimum supported Rust version is now 1.46.0. + ([#1492](https://github.com/nix-rust/nix/pull/1492)) +- Rework `UnixAddr` to encapsulate internals better in order to fix soundness + issues. No longer allows creating a `UnixAddr` from a raw `sockaddr_un`. + ([#1496](https://github.com/nix-rust/nix/pull/1496)) +- Raised bitflags to 1.3.0 and the MSRV to 1.46.0. + ([#1492](https://github.com/nix-rust/nix/pull/1492)) + +### Fixed + +- `posix_fadvise` now returns errors in the conventional way, rather than as a + non-zero value in `Ok()`. + (#[1538](https://github.com/nix-rust/nix/pull/1538)) +- Added more errno definitions for better backwards compatibility with + Nix 0.21.0. + (#[1467](https://github.com/nix-rust/nix/pull/1467)) +- Fixed potential undefined behavior in `Signal::try_from` on some platforms. + (#[1484](https://github.com/nix-rust/nix/pull/1484)) +- Fixed buffer overflow in `unistd::getgrouplist`. + (#[1545](https://github.com/nix-rust/nix/pull/1545)) + + +### Removed + +- Removed a couple of termios constants on redox that were never actually + supported. + (#[1483](https://github.com/nix-rust/nix/pull/1483)) +- Removed `nix::sys::signal::NSIG`. It was of dubious utility, and not correct + for all platforms. + (#[1484](https://github.com/nix-rust/nix/pull/1484)) +- Removed support for 32-bit Apple targets, since they've been dropped by both + Rustc and Xcode. + (#[1492](https://github.com/nix-rust/nix/pull/1492)) +- Deprecated `SockAddr/InetAddr::to_str` in favor of `ToString::to_string` + (#[1495](https://github.com/nix-rust/nix/pull/1495)) +- Removed `SigevNotify` on OpenBSD and Redox. + (#[1511](https://github.com/nix-rust/nix/pull/1511)) + +## [0.22.3] - 22 January 2022 +### Changed +- Relaxed the bitflags requirement from 1.3.1 to 1.1. This partially reverts + #1492. From now on, the MSRV is not guaranteed to work with all versions of + all dependencies, just with some version of all dependencies. + (#[1607](https://github.com/nix-rust/nix/pull/1607)) + +## [0.22.2] - 28 September 2021 +### Fixed +- Fixed buffer overflow in `unistd::getgrouplist`. + (#[1545](https://github.com/nix-rust/nix/pull/1545)) +- Added more errno definitions for better backwards compatibility with + Nix 0.21.0. + (#[1467](https://github.com/nix-rust/nix/pull/1467)) + +## [0.22.1] - 13 August 2021 +### Fixed +- Locked bitflags to < 1.3.0 to fix the build with rust < 1.46.0. + +### Removed +- Removed a couple of termios constants on redox that were never actually + supported. + (#[1483](https://github.com/nix-rust/nix/pull/1483)) + +## [0.22.0] - 9 July 2021 +### Added +- Added `if_nameindex` (#[1445](https://github.com/nix-rust/nix/pull/1445)) +- Added `nmount` for FreeBSD. + (#[1453](https://github.com/nix-rust/nix/pull/1453)) +- Added `IpFreebind` socket option (sockopt) on Linux, Fuchsia and Android. + (#[1456](https://github.com/nix-rust/nix/pull/1456)) +- Added `TcpUserTimeout` socket option (sockopt) on Linux and Fuchsia. + (#[1457](https://github.com/nix-rust/nix/pull/1457)) +- Added `renameat2` for Linux + (#[1458](https://github.com/nix-rust/nix/pull/1458)) +- Added `RxqOvfl` support on Linux, Fuchsia and Android. + (#[1455](https://github.com/nix-rust/nix/pull/1455)) + +### Changed +- `ptsname_r` now returns a lossily-converted string in the event of bad UTF, + just like `ptsname`. + ([#1446](https://github.com/nix-rust/nix/pull/1446)) +- Nix's error type is now a simple wrapper around the platform's Errno. This + means it is now `Into`. It's also `Clone`, `Copy`, `Eq`, and + has a small fixed size. It also requires less typing. For example, the old + enum variant `nix::Error::Sys(nix::errno::Errno::EINVAL)` is now simply + `nix::Error::EINVAL`. + ([#1446](https://github.com/nix-rust/nix/pull/1446)) + +## [0.21.2] - 29 September 2021 +### Fixed +- Fixed buffer overflow in `unistd::getgrouplist`. + (#[1545](https://github.com/nix-rust/nix/pull/1545)) + +## [0.21.1] - 13 August 2021 +### Fixed +- Locked bitflags to < 1.3.0 to fix the build with rust < 1.46.0. + +### Removed +- Removed a couple of termios constants on redox that were never actually + supported. + (#[1483](https://github.com/nix-rust/nix/pull/1483)) + +## [0.21.0] - 31 May 2021 +### Added +- Added `getresuid` and `getresgid` + (#[1430](https://github.com/nix-rust/nix/pull/1430)) +- Added TIMESTAMPNS support for linux + (#[1402](https://github.com/nix-rust/nix/pull/1402)) +- Added `sendfile64` (#[1439](https://github.com/nix-rust/nix/pull/1439)) +- Added `MS_LAZYTIME` to `MsFlags` + (#[1437](https://github.com/nix-rust/nix/pull/1437)) + +### Changed +- Made `forkpty` unsafe, like `fork` + (#[1390](https://github.com/nix-rust/nix/pull/1390)) +- Made `Uid`, `Gid` and `Pid` methods `from_raw` and `as_raw` a `const fn` + (#[1429](https://github.com/nix-rust/nix/pull/1429)) +- Made `Uid::is_root` a `const fn` + (#[1429](https://github.com/nix-rust/nix/pull/1429)) +- `AioCb` is now always pinned. Once a `libc::aiocb` gets sent to the kernel, + its address in memory must not change. Nix now enforces that by using + `std::pin`. Most users won't need to change anything, except when using + `aio_suspend`. See that method's documentation for the new usage. + (#[1440](https://github.com/nix-rust/nix/pull/1440)) +- `LioCb` is now constructed using a distinct `LioCbBuilder` struct. This + avoids a soundness issue with the old `LioCb`. Usage is similar but + construction now uses the builder pattern. See the documentation for + details. + (#[1440](https://github.com/nix-rust/nix/pull/1440)) +- Minimum supported Rust version is now 1.41.0. + ([#1440](https://github.com/nix-rust/nix/pull/1440)) +- Errno aliases are now associated consts on `Errno`, instead of consts in the + `errno` module. + (#[1452](https://github.com/nix-rust/nix/pull/1452)) + +### Fixed +- Allow `sockaddr_ll` size, as reported by the Linux kernel, to be smaller then it's definition + (#[1395](https://github.com/nix-rust/nix/pull/1395)) +- Fix spurious errors using `sendmmsg` with multiple cmsgs + (#[1414](https://github.com/nix-rust/nix/pull/1414)) +- Added `Errno::EOPNOTSUPP` to FreeBSD, where it was missing. + (#[1452](https://github.com/nix-rust/nix/pull/1452)) + +### Removed + +- Removed `sys::socket::accept4` from Android arm because libc removed it in + version 0.2.87. + ([#1399](https://github.com/nix-rust/nix/pull/1399)) +- `AioCb::from_boxed_slice` and `AioCb::from_boxed_mut_slice` have been + removed. They were useful with earlier versions of Rust, but should no + longer be needed now that async/await are available. `AioCb`s now work + exclusively with borrowed buffers, not owned ones. + (#[1440](https://github.com/nix-rust/nix/pull/1440)) +- Removed some Errno values from platforms where they aren't actually defined. + (#[1452](https://github.com/nix-rust/nix/pull/1452)) + +## [0.20.2] - 28 September 2021 +### Fixed +- Fixed buffer overflow in `unistd::getgrouplist`. + (#[1545](https://github.com/nix-rust/nix/pull/1545)) + +## [0.20.1] - 13 August 2021 +### Fixed +- Locked bitflags to < 1.3.0 to fix the build with rust < 1.46.0. + +### Removed +- Removed a couple of termios constants on redox that were never actually + supported. + (#[1483](https://github.com/nix-rust/nix/pull/1483)) + +## [0.20.0] - 20 February 2021 +### Added + +- Added a `passwd` field to `Group` (#[1338](https://github.com/nix-rust/nix/pull/1338)) +- Added `mremap` (#[1306](https://github.com/nix-rust/nix/pull/1306)) +- Added `personality` (#[1331](https://github.com/nix-rust/nix/pull/1331)) +- Added limited Fuchsia support (#[1285](https://github.com/nix-rust/nix/pull/1285)) +- Added `getpeereid` (#[1342](https://github.com/nix-rust/nix/pull/1342)) +- Implemented `IntoIterator` for `Dir` + (#[1333](https://github.com/nix-rust/nix/pull/1333)). + +### Changed + +- Minimum supported Rust version is now 1.40.0. + ([#1356](https://github.com/nix-rust/nix/pull/1356)) +- i686-apple-darwin has been demoted to Tier 2 support, because it's deprecated + by Xcode. + (#[1350](https://github.com/nix-rust/nix/pull/1350)) +- Fixed calling `recvfrom` on an `AddrFamily::Packet` socket + (#[1344](https://github.com/nix-rust/nix/pull/1344)) + +### Fixed +- `TimerFd` now closes the underlying fd on drop. + ([#1381](https://github.com/nix-rust/nix/pull/1381)) +- Define `*_MAGIC` filesystem constants on Linux s390x + (#[1372](https://github.com/nix-rust/nix/pull/1372)) +- mqueue, sysinfo, timespec, statfs, test_ptrace_syscall() on x32 + (#[1366](https://github.com/nix-rust/nix/pull/1366)) + +### Removed + +- `Dir`, `SignalFd`, and `PtyMaster` are no longer `Clone`. + (#[1382](https://github.com/nix-rust/nix/pull/1382)) +- Removed `SockLevel`, which hasn't been used for a few years + (#[1362](https://github.com/nix-rust/nix/pull/1362)) +- Removed both `Copy` and `Clone` from `TimerFd`. + ([#1381](https://github.com/nix-rust/nix/pull/1381)) + +## [0.19.1] - 28 November 2020 +### Fixed +- Fixed bugs in `recvmmsg`. + (#[1341](https://github.com/nix-rust/nix/pull/1341)) + +## [0.19.0] - 6 October 2020 +### Added +- Added Netlink protocol families to the `SockProtocol` enum + (#[1289](https://github.com/nix-rust/nix/pull/1289)) +- Added `clock_gettime`, `clock_settime`, `clock_getres`, + `clock_getcpuclockid` functions and `ClockId` struct. + (#[1281](https://github.com/nix-rust/nix/pull/1281)) +- Added wrapper functions for `PTRACE_SYSEMU` and `PTRACE_SYSEMU_SINGLESTEP`. + (#[1300](https://github.com/nix-rust/nix/pull/1300)) +- Add support for Vsock on Android rather than just Linux. + (#[1301](https://github.com/nix-rust/nix/pull/1301)) +- Added `TCP_KEEPCNT` and `TCP_KEEPINTVL` TCP keepalive options. + (#[1283](https://github.com/nix-rust/nix/pull/1283)) +### Changed +- Expose `SeekData` and `SeekHole` on all Linux targets + (#[1284](https://github.com/nix-rust/nix/pull/1284)) +- Changed unistd::{execv,execve,execvp,execvpe,fexecve,execveat} to take both `&[&CStr]` and `&[CString]` as its list argument(s). + (#[1278](https://github.com/nix-rust/nix/pull/1278)) +- Made `unistd::fork` an unsafe funtion, bringing it in line with [libstd's decision](https://github.com/rust-lang/rust/pull/58059). + (#[1293](https://github.com/nix-rust/nix/pull/1293)) + +## [0.18.0] - 26 July 2020 +### Added +- Added `fchown(2)` wrapper. + (#[1257](https://github.com/nix-rust/nix/pull/1257)) +- Added support on linux systems for `MAP_HUGE_`_`SIZE`_ family of flags. + (#[1211](https://github.com/nix-rust/nix/pull/1211)) +- Added support for `F_OFD_*` `fcntl` commands on Linux and Android. + (#[1195](https://github.com/nix-rust/nix/pull/1195)) +- Added `env::clearenv()`: calls `libc::clearenv` on platforms + where it's available, and clears the environment of all variables + via `std::env::vars` and `std::env::remove_var` on others. + (#[1185](https://github.com/nix-rust/nix/pull/1185)) +- `FsType` inner value made public. + (#[1187](https://github.com/nix-rust/nix/pull/1187)) +- Added `unistd::setfsuid` and `unistd::setfsgid` to set the user or group + identity for filesystem checks per-thread. + (#[1163](https://github.com/nix-rust/nix/pull/1163)) +- Derived `Ord`, `PartialOrd` for `unistd::Pid` (#[1189](https://github.com/nix-rust/nix/pull/1189)) +- Added `select::FdSet::fds` method to iterate over file descriptors in a set. + ([#1207](https://github.com/nix-rust/nix/pull/1207)) +- Added support for UDP generic segmentation offload (GSO) and generic + receive offload (GRO) ([#1209](https://github.com/nix-rust/nix/pull/1209)) +- Added support for `sendmmsg` and `recvmmsg` calls + (#[1208](https://github.com/nix-rust/nix/pull/1208)) +- Added support for `SCM_CREDS` messages (`UnixCredentials`) on FreeBSD/DragonFly + (#[1216](https://github.com/nix-rust/nix/pull/1216)) +- Added `BindToDevice` socket option (sockopt) on Linux + (#[1233](https://github.com/nix-rust/nix/pull/1233)) +- Added `EventFilter` bitflags for `EV_DISPATCH` and `EV_RECEIPT` on OpenBSD. + (#[1252](https://github.com/nix-rust/nix/pull/1252)) +- Added support for `Ipv4PacketInfo` and `Ipv6PacketInfo` to `ControlMessage`. + (#[1222](https://github.com/nix-rust/nix/pull/1222)) +- `CpuSet` and `UnixCredentials` now implement `Default`. + (#[1244](https://github.com/nix-rust/nix/pull/1244)) +- Added `unistd::ttyname` + (#[1259](https://github.com/nix-rust/nix/pull/1259)) +- Added support for `Ipv4PacketInfo` and `Ipv6PacketInfo` to `ControlMessage` for iOS and Android. + (#[1265](https://github.com/nix-rust/nix/pull/1265)) +- Added support for `TimerFd`. + (#[1261](https://github.com/nix-rust/nix/pull/1261)) + +### Changed +- Changed `fallocate` return type from `c_int` to `()` (#[1201](https://github.com/nix-rust/nix/pull/1201)) +- Enabled `sys::ptrace::setregs` and `sys::ptrace::getregs` on x86_64-unknown-linux-musl target + (#[1198](https://github.com/nix-rust/nix/pull/1198)) +- On Linux, `ptrace::write` is now an `unsafe` function. Caveat programmer. + (#[1245](https://github.com/nix-rust/nix/pull/1245)) +- `execv`, `execve`, `execvp` and `execveat` in `::nix::unistd` and `reboot` in + `::nix::sys::reboot` now return `Result` instead of `Result` (#[1239](https://github.com/nix-rust/nix/pull/1239)) +- `sys::socket::sockaddr_storage_to_addr` is no longer `unsafe`. So is + `offset_of!`. +- `sys::socket::sockaddr_storage_to_addr`, `offset_of!`, and `Errno::clear` are + no longer `unsafe`. +- `SockAddr::as_ffi_pair`,`sys::socket::sockaddr_storage_to_addr`, `offset_of!`, + and `Errno::clear` are no longer `unsafe`. + (#[1244](https://github.com/nix-rust/nix/pull/1244)) +- Several `Inotify` methods now take `self` by value instead of by reference + (#[1244](https://github.com/nix-rust/nix/pull/1244)) +- `nix::poll::ppoll`: `timeout` parameter is now optional, None is equivalent for infinite timeout. + +### Fixed + +- Fixed `getsockopt`. The old code produced UB which triggers a panic with + Rust 1.44.0. + (#[1214](https://github.com/nix-rust/nix/pull/1214)) + +- Fixed a bug in nix::unistd that would result in an infinite loop + when a group or user lookup required a buffer larger than + 16KB. (#[1198](https://github.com/nix-rust/nix/pull/1198)) +- Fixed unaligned casting of `cmsg_data` to `af_alg_iv` (#[1206](https://github.com/nix-rust/nix/pull/1206)) +- Fixed `readlink`/`readlinkat` when reading symlinks longer than `PATH_MAX` (#[1231](https://github.com/nix-rust/nix/pull/1231)) +- `PollFd`, `EpollEvent`, `IpMembershipRequest`, `Ipv6MembershipRequest`, + `TimeVal`, and `IoVec` are now `repr(transparent)`. This is required for + correctness's sake across all architectures and compilers, though now bugs + have been reported so far. + (#[1243](https://github.com/nix-rust/nix/pull/1243)) +- Fixed unaligned pointer read in `Inotify::read_events`. + (#[1244](https://github.com/nix-rust/nix/pull/1244)) + +### Removed + +- Removed `sys::socket::addr::from_libc_sockaddr` from the public API. + (#[1215](https://github.com/nix-rust/nix/pull/1215)) +- Removed `sys::termios::{get_libc_termios, get_libc_termios_mut, update_wrapper` + from the public API. These were previously hidden in the docs but still usable + by downstream. + (#[1235](https://github.com/nix-rust/nix/pull/1235)) + +- Nix no longer implements `NixPath` for `Option

where P: NixPath`. Most + Nix functions that accept `NixPath` arguments can't do anything useful with + `None`. The exceptions (`mount` and `quotactl_sync`) already take explicitly + optional arguments. + (#[1242](https://github.com/nix-rust/nix/pull/1242)) + +- Removed `unistd::daemon` and `unistd::pipe2` on OSX and ios + (#[1255](https://github.com/nix-rust/nix/pull/1255)) + +- Removed `sys::event::FilterFlag::NOTE_EXIT_REPARENTED` and + `sys::event::FilterFlag::NOTE_REAP` on OSX and ios. + (#[1255](https://github.com/nix-rust/nix/pull/1255)) + +- Removed `sys::ptrace::ptrace` on Android and Linux. + (#[1255](https://github.com/nix-rust/nix/pull/1255)) + +- Dropped support for powerpc64-unknown-linux-gnu + (#[1266](https://github.com/nix-rust/nix/pull/1268)) + +## [0.17.0] - 3 February 2020 +### Added +- Add `CLK_TCK` to `SysconfVar` + (#[1177](https://github.com/nix-rust/nix/pull/1177)) +### Removed +- Removed deprecated Error::description from error types + (#[1175](https://github.com/nix-rust/nix/pull/1175)) + +## [0.16.1] - 23 December 2019 +### Fixed + +- Fixed the build for OpenBSD + (#[1168](https://github.com/nix-rust/nix/pull/1168)) + +## [0.16.0] - 1 December 2019 +### Added +- Added `ptrace::seize()`: similar to `attach()` on Linux + but with better-defined semantics. + (#[1154](https://github.com/nix-rust/nix/pull/1154)) + +- Added `Signal::as_str()`: returns signal name as `&'static str` + (#[1138](https://github.com/nix-rust/nix/pull/1138)) + +- Added `posix_fallocate`. + ([#1105](https://github.com/nix-rust/nix/pull/1105)) + +- Implemented `Default` for `FdSet` + ([#1107](https://github.com/nix-rust/nix/pull/1107)) + +- Added `NixPath::is_empty`. + ([#1107](https://github.com/nix-rust/nix/pull/1107)) + +- Added `mkfifoat` + ([#1133](https://github.com/nix-rust/nix/pull/1133)) + +- Added `User::from_uid`, `User::from_name`, `User::from_gid` and + `Group::from_name`, + ([#1139](https://github.com/nix-rust/nix/pull/1139)) + +- Added `linkat` + ([#1101](https://github.com/nix-rust/nix/pull/1101)) + +- Added `sched_getaffinity`. + ([#1148](https://github.com/nix-rust/nix/pull/1148)) + +- Added optional `Signal` argument to `ptrace::{detach, syscall}` for signal + injection. ([#1083](https://github.com/nix-rust/nix/pull/1083)) + +### Changed +- `sys::termios::BaudRate` now implements `TryFrom` instead of + `From`. The old `From` implementation would panic on failure. + ([#1159](https://github.com/nix-rust/nix/pull/1159)) + +- `sys::socket::ControlMessage::ScmCredentials` and + `sys::socket::ControlMessageOwned::ScmCredentials` now wrap `UnixCredentials` + rather than `libc::ucred`. + ([#1160](https://github.com/nix-rust/nix/pull/1160)) + +- `sys::socket::recvmsg` now takes a plain `Vec` instead of a `CmsgBuffer` + implementor. If you were already using `cmsg_space!`, then you needn't worry. + ([#1156](https://github.com/nix-rust/nix/pull/1156)) + +- `sys::socket::recvfrom` now returns + `Result<(usize, Option)>` instead of `Result<(usize, SockAddr)>`. + ([#1145](https://github.com/nix-rust/nix/pull/1145)) + +- `Signal::from_c_int` has been replaced by `Signal::try_from` + ([#1113](https://github.com/nix-rust/nix/pull/1113)) + +- Changed `readlink` and `readlinkat` to return `OsString` + ([#1109](https://github.com/nix-rust/nix/pull/1109)) + + ```rust + # use nix::fcntl::{readlink, readlinkat}; + // the buffer argument of `readlink` and `readlinkat` has been removed, + // and the return value is now an owned type (`OsString`). + // Existing code can be updated by removing the buffer argument + // and removing any clone or similar operation on the output + + // old code `readlink(&path, &mut buf)` can be replaced with the following + let _: OsString = readlink(&path); + + // old code `readlinkat(dirfd, &path, &mut buf)` can be replaced with the following + let _: OsString = readlinkat(dirfd, &path); + ``` + +- Minimum supported Rust version is now 1.36.0. + ([#1108](https://github.com/nix-rust/nix/pull/1108)) + +- `Ipv4Addr::octets`, `Ipv4Addr::to_std`, `Error::as_errno`, + `ForkResult::is_child`, `ForkResult::is_parent`, `Gid::as_raw`, + `Uid::is_root`, `Uid::as_raw`, `Pid::as_raw`, and `PollFd::revents` now take + `self` by value. + ([#1107](https://github.com/nix-rust/nix/pull/1107)) + +- Type `&CString` for parameters of `exec(v|ve|vp|vpe|veat)` are changed to `&CStr`. + ([#1121](https://github.com/nix-rust/nix/pull/1121)) + +### Fixed +- Fix length of abstract socket addresses + ([#1120](https://github.com/nix-rust/nix/pull/1120)) + +- Fix initialization of msghdr in recvmsg/sendmsg when built with musl + ([#1136](https://github.com/nix-rust/nix/pull/1136)) + +### Removed +- Remove the deprecated `CmsgSpace`. + ([#1156](https://github.com/nix-rust/nix/pull/1156)) + +## [0.15.0] - 10 August 2019 +### Added +- Added `MSG_WAITALL` to `MsgFlags` in `sys::socket`. + ([#1079](https://github.com/nix-rust/nix/pull/1079)) +- Implemented `Clone`, `Copy`, `Debug`, `Eq`, `Hash`, and `PartialEq` for most + types that support them. ([#1035](https://github.com/nix-rust/nix/pull/1035)) +- Added `copy_file_range` wrapper + ([#1069](https://github.com/nix-rust/nix/pull/1069)) +- Add `mkdirat`. + ([#1084](https://github.com/nix-rust/nix/pull/1084)) +- Add `posix_fadvise`. + ([#1089](https://github.com/nix-rust/nix/pull/1089)) +- Added `AF_VSOCK` to `AddressFamily`. + ([#1091](https://github.com/nix-rust/nix/pull/1091)) +- Add `unlinkat` + ([#1058](https://github.com/nix-rust/nix/pull/1058)) +- Add `renameat`. + ([#1097](https://github.com/nix-rust/nix/pull/1097)) + +### Changed +- Support for `ifaddrs` now present when building for Android. + ([#1077](https://github.com/nix-rust/nix/pull/1077)) +- Minimum supported Rust version is now 1.31.0 + ([#1035](https://github.com/nix-rust/nix/pull/1035)) + ([#1095](https://github.com/nix-rust/nix/pull/1095)) +- Now functions `statfs()` and `fstatfs()` return result with `Statfs` wrapper + ([#928](https://github.com/nix-rust/nix/pull/928)) + +### Fixed +- Enabled `sched_yield` for all nix hosts. + ([#1090](https://github.com/nix-rust/nix/pull/1090)) + +## [0.14.1] - 2019-06-06 +### Added +- Macros exported by `nix` may now be imported via `use` on the Rust 2018 + edition without importing helper macros on Linux targets. + ([#1066](https://github.com/nix-rust/nix/pull/1066)) + + For example, in Rust 2018, the `ioctl_read_bad!` macro can now be imported + without importing the `convert_ioctl_res!` macro. + + ```rust + use nix::ioctl_read_bad; + + ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios); + ``` + +### Changed +- Changed some public types from reexports of libc types like `uint32_t` to the + native equivalents like `u32.` + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) + +### Fixed +- Fix the build on Android and Linux/mips with recent versions of libc. + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) + +## [0.14.0] - 2019-05-21 +### Added +- Add IP_RECVIF & IP_RECVDSTADDR. Enable IP_PKTINFO and IP6_PKTINFO on netbsd/openbsd. + ([#1002](https://github.com/nix-rust/nix/pull/1002)) +- Added `inotify_init1`, `inotify_add_watch` and `inotify_rm_watch` wrappers for + Android and Linux. ([#1016](https://github.com/nix-rust/nix/pull/1016)) +- Add `ALG_SET_IV`, `ALG_SET_OP` and `ALG_SET_AEAD_ASSOCLEN` control messages and `AF_ALG` + socket types on Linux and Android ([#1031](https://github.com/nix-rust/nix/pull/1031)) +- Add killpg + ([#1034](https://github.com/nix-rust/nix/pull/1034)) +- Added ENOTSUP errno support for Linux and Android. + ([#969](https://github.com/nix-rust/nix/pull/969)) +- Add several errno constants from OpenBSD 6.2 + ([#1036](https://github.com/nix-rust/nix/pull/1036)) +- Added `from_std` and `to_std` methods for `sys::socket::IpAddr` + ([#1043](https://github.com/nix-rust/nix/pull/1043)) +- Added `nix::unistd:seteuid` and `nix::unistd::setegid` for those platforms that do + not support `setresuid` nor `setresgid` respectively. + ([#1044](https://github.com/nix-rust/nix/pull/1044)) +- Added a `access` wrapper + ([#1045](https://github.com/nix-rust/nix/pull/1045)) +- Add `forkpty` + ([#1042](https://github.com/nix-rust/nix/pull/1042)) +- Add `sched_yield` + ([#1050](https://github.com/nix-rust/nix/pull/1050)) + +### Changed +- `PollFd` event flags renamed to `PollFlags` ([#1024](https://github.com/nix-rust/nix/pull/1024/)) +- `recvmsg` now returns an Iterator over `ControlMessageOwned` objects rather + than `ControlMessage` objects. This is sadly not backwards-compatible. Fix + code like this: + ```rust + if let ControlMessage::ScmRights(&fds) = cmsg { + ``` + + By replacing it with code like this: + ```rust + if let ControlMessageOwned::ScmRights(fds) = cmsg { + ``` + ([#1020](https://github.com/nix-rust/nix/pull/1020)) +- Replaced `CmsgSpace` with the `cmsg_space` macro. + ([#1020](https://github.com/nix-rust/nix/pull/1020)) + +### Fixed +- Fixed multiple bugs when using `sendmsg` and `recvmsg` with ancillary control messages + ([#1020](https://github.com/nix-rust/nix/pull/1020)) +- Macros exported by `nix` may now be imported via `use` on the Rust 2018 + edition without importing helper macros for BSD targets. + ([#1041](https://github.com/nix-rust/nix/pull/1041)) + + For example, in Rust 2018, the `ioctl_read_bad!` macro can now be imported + without importing the `convert_ioctl_res!` macro. + + ```rust + use nix::ioctl_read_bad; + + ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios); + ``` + +### Removed +- `Daemon`, `NOTE_REAP`, and `NOTE_EXIT_REPARENTED` are now deprecated on OSX + and iOS. + ([#1033](https://github.com/nix-rust/nix/pull/1033)) +- `PTRACE_GETREGS`, `PTRACE_SETREGS`, `PTRACE_GETFPREGS`, and + `PTRACE_SETFPREGS` have been removed from some platforms where they never + should've been defined in the first place. + ([#1055](https://github.com/nix-rust/nix/pull/1055)) + +## [0.13.1] - 2019-06-10 +### Changed +- Changed some public types from reexports of libc types like `uint32_t` to the + native equivalents like `u32.` + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) + +### Fixed +- Fix the build on Android and Linux/mips with recent versions of libc. + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) +- Fixed build on Linux/arm and Linux/s390x with the latest Rust libc + ([52102cb](https://github.com/nix-rust/nix/commit/52102cb76398c4dfb9ea141b98c5b01a2e050973)) + +### Removed +- `Daemon`, `NOTE_REAP`, and `NOTE_EXIT_REPARENTED` are now deprecated on OSX + and iOS. + ([#1033](https://github.com/nix-rust/nix/pull/1033)) + +## [0.13.0] - 2019-01-15 +### Added +- Added PKTINFO(V4) & V6PKTINFO cmsg support - Android/FreeBSD/iOS/Linux/MacOS. + ([#990](https://github.com/nix-rust/nix/pull/990)) +- Added support of CString type in `setsockopt`. + ([#972](https://github.com/nix-rust/nix/pull/972)) +- Added option `TCP_CONGESTION` in `setsockopt`. + ([#972](https://github.com/nix-rust/nix/pull/972)) +- Added `symlinkat` wrapper. + ([#997](https://github.com/nix-rust/nix/pull/997)) +- Added `ptrace::{getregs, setregs}`. + ([#1010](https://github.com/nix-rust/nix/pull/1010)) +- Added `nix::sys::signal::signal`. + ([#817](https://github.com/nix-rust/nix/pull/817)) +- Added an `mprotect` wrapper. + ([#991](https://github.com/nix-rust/nix/pull/991)) + +### Fixed +- `lutimes` never worked on OpenBSD as it is not implemented on OpenBSD. It has + been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000)) +- `fexecve` never worked on NetBSD or on OpenBSD as it is not implemented on + either OS. It has been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000)) + +## [0.12.1] 2019-06-08 +### Changed +- Changed some public types from reexports of libc types like `uint32_t` to the + native equivalents like `u32.` + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) + +### Fixed +- Fix the build on Android and Linux/mips with recent versions of libc. + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) +- Fixed build on Linux/arm and Linux/s390x with the latest Rust libc + ([52102cb](https://github.com/nix-rust/nix/commit/52102cb76398c4dfb9ea141b98c5b01a2e050973)) + +### Removed +- `fexecve` never worked on NetBSD or on OpenBSD as it is not implemented on + either OS. It has been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000)) +- `Daemon`, `NOTE_REAP`, and `NOTE_EXIT_REPARENTED` are now deprecated on OSX + and iOS. + ([#1033](https://github.com/nix-rust/nix/pull/1033)) + +## [0.12.0] 2018-11-28 + +### Added +- Added `FromStr` and `Display` impls for `nix::sys::Signal` + ([#884](https://github.com/nix-rust/nix/pull/884)) +- Added a `sync` wrapper. + ([#961](https://github.com/nix-rust/nix/pull/961)) +- Added a `sysinfo` wrapper. + ([#922](https://github.com/nix-rust/nix/pull/922)) +- Support the `SO_PEERCRED` socket option and the `UnixCredentials` type on all Linux and Android targets. + ([#921](https://github.com/nix-rust/nix/pull/921)) +- Added support for `SCM_CREDENTIALS`, allowing to send process credentials over Unix sockets. + ([#923](https://github.com/nix-rust/nix/pull/923)) +- Added a `dir` module for reading directories (wraps `fdopendir`, `readdir`, and `rewinddir`). + ([#916](https://github.com/nix-rust/nix/pull/916)) +- Added `kmod` module that allows loading and unloading kernel modules on Linux. + ([#930](https://github.com/nix-rust/nix/pull/930)) +- Added `futimens` and `utimesat` wrappers ([#944](https://github.com/nix-rust/nix/pull/944)), + an `lutimes` wrapper ([#967](https://github.com/nix-rust/nix/pull/967)), + and a `utimes` wrapper ([#946](https://github.com/nix-rust/nix/pull/946)). +- Added `AF_UNSPEC` wrapper to `AddressFamily` ([#948](https://github.com/nix-rust/nix/pull/948)) +- Added the `mode_t` public alias within `sys::stat`. + ([#954](https://github.com/nix-rust/nix/pull/954)) +- Added a `truncate` wrapper. + ([#956](https://github.com/nix-rust/nix/pull/956)) +- Added a `fchownat` wrapper. + ([#955](https://github.com/nix-rust/nix/pull/955)) +- Added support for `ptrace` on BSD operating systems ([#949](https://github.com/nix-rust/nix/pull/949)) +- Added `ptrace` functions for reads and writes to tracee memory and ptrace kill + ([#949](https://github.com/nix-rust/nix/pull/949)) ([#958](https://github.com/nix-rust/nix/pull/958)) +- Added a `acct` wrapper module for enabling and disabling process accounting + ([#952](https://github.com/nix-rust/nix/pull/952)) +- Added the `time_t` and `suseconds_t` public aliases within `sys::time`. + ([#968](https://github.com/nix-rust/nix/pull/968)) +- Added `unistd::execvpe` for Haiku, Linux and OpenBSD + ([#975](https://github.com/nix-rust/nix/pull/975)) +- Added `Error::as_errno`. + ([#977](https://github.com/nix-rust/nix/pull/977)) + +### Changed +- Increased required Rust version to 1.24.1 + ([#900](https://github.com/nix-rust/nix/pull/900)) + ([#966](https://github.com/nix-rust/nix/pull/966)) + +### Fixed +- Made `preadv` take immutable slice of IoVec. + ([#914](https://github.com/nix-rust/nix/pull/914)) +- Fixed passing multiple file descriptors over Unix Sockets. + ([#918](https://github.com/nix-rust/nix/pull/918)) + +## [0.11.1] 2019-06-06 +### Changed +- Changed some public types from reexports of libc types like `uint32_t` to the + native equivalents like `u32.` + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) + +### Fixed +- Fix the build on Android and Linux/mips with recent versions of libc. + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) +- Fixed build on Linux/arm and Linux/s390x with the latest Rust libc + ([52102cb](https://github.com/nix-rust/nix/commit/52102cb76398c4dfb9ea141b98c5b01a2e050973)) + +### Removed +- `fexecve` never worked on NetBSD or on OpenBSD as it is not implemented on + either OS. It has been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000)) +- `Daemon`, `NOTE_REAP`, and `NOTE_EXIT_REPARENTED` are now deprecated on OSX + and iOS. + ([#1033](https://github.com/nix-rust/nix/pull/1033)) + +## [0.11.0] 2018-06-01 + +### Added +- Added `sendfile` on FreeBSD and Darwin. + ([#901](https://github.com/nix-rust/nix/pull/901)) +- Added `pselect` + ([#894](https://github.com/nix-rust/nix/pull/894)) +- Exposed `preadv` and `pwritev` on the BSDs. + ([#883](https://github.com/nix-rust/nix/pull/883)) +- Added `mlockall` and `munlockall` + ([#876](https://github.com/nix-rust/nix/pull/876)) +- Added `SO_MARK` on Linux. + ([#873](https://github.com/nix-rust/nix/pull/873)) +- Added safe support for nearly any buffer type in the `sys::aio` module. + ([#872](https://github.com/nix-rust/nix/pull/872)) +- Added `sys::aio::LioCb` as a wrapper for `libc::lio_listio`. + ([#872](https://github.com/nix-rust/nix/pull/872)) +- Added `unistd::getsid` + ([#850](https://github.com/nix-rust/nix/pull/850)) +- Added `alarm`. ([#830](https://github.com/nix-rust/nix/pull/830)) +- Added interface flags `IFF_NO_PI, IFF_TUN, IFF_TAP` on linux-like systems. + ([#853](https://github.com/nix-rust/nix/pull/853)) +- Added `statvfs` module to all MacOS and Linux architectures. + ([#832](https://github.com/nix-rust/nix/pull/832)) +- Added `EVFILT_EMPTY`, `EVFILT_PROCDESC`, and `EVFILT_SENDFILE` on FreeBSD. + ([#825](https://github.com/nix-rust/nix/pull/825)) +- Exposed `termios::cfmakesane` on FreeBSD. + ([#825](https://github.com/nix-rust/nix/pull/825)) +- Exposed `MSG_CMSG_CLOEXEC` on *BSD. + ([#825](https://github.com/nix-rust/nix/pull/825)) +- Added `fchmod`, `fchmodat`. + ([#857](https://github.com/nix-rust/nix/pull/857)) +- Added `request_code_write_int!` on FreeBSD/DragonFlyBSD + ([#833](https://github.com/nix-rust/nix/pull/833)) + +### Changed +- `Display` and `Debug` for `SysControlAddr` now includes all fields. + ([#837](https://github.com/nix-rust/nix/pull/837)) +- `ioctl!` has been replaced with a family of `ioctl_*!` macros. + ([#833](https://github.com/nix-rust/nix/pull/833)) +- `io!`, `ior!`, `iow!`, and `iorw!` has been renamed to `request_code_none!`, `request_code_read!`, + `request_code_write!`, and `request_code_readwrite!` respectively. These have also now been exposed + in the documentation. + ([#833](https://github.com/nix-rust/nix/pull/833)) +- Enabled more `ptrace::Request` definitions for uncommon Linux platforms + ([#892](https://github.com/nix-rust/nix/pull/892)) +- Emulation of `FD_CLOEXEC` and `O_NONBLOCK` was removed from `socket()`, `accept4()`, and + `socketpair()`. + ([#907](https://github.com/nix-rust/nix/pull/907)) + +### Fixed +- Fixed possible panics when using `SigAction::flags` on Linux + ([#869](https://github.com/nix-rust/nix/pull/869)) +- Properly exposed 460800 and 921600 baud rates on NetBSD + ([#837](https://github.com/nix-rust/nix/pull/837)) +- Fixed `ioctl_write_int!` on FreeBSD/DragonFlyBSD + ([#833](https://github.com/nix-rust/nix/pull/833)) +- `ioctl_write_int!` now properly supports passing a `c_ulong` as the parameter on Linux non-musl targets + ([#833](https://github.com/nix-rust/nix/pull/833)) + +### Removed +- Removed explicit support for the `bytes` crate from the `sys::aio` module. + See `sys::aio::AioCb::from_boxed_slice` examples for alternatives. + ([#872](https://github.com/nix-rust/nix/pull/872)) +- Removed `sys::aio::lio_listio`. Use `sys::aio::LioCb::listio` instead. + ([#872](https://github.com/nix-rust/nix/pull/872)) +- Removed emulated `accept4()` from macos, ios, and netbsd targets + ([#907](https://github.com/nix-rust/nix/pull/907)) +- Removed `IFF_NOTRAILERS` on OpenBSD, as it has been removed in OpenBSD 6.3 + ([#893](https://github.com/nix-rust/nix/pull/893)) + +## [0.10.0] 2018-01-26 + +### Added +- Added specialized wrapper: `sys::ptrace::step` + ([#852](https://github.com/nix-rust/nix/pull/852)) +- Added `AioCb::from_ptr` and `AioCb::from_mut_ptr` + ([#820](https://github.com/nix-rust/nix/pull/820)) +- Added specialized wrappers: `sys::ptrace::{traceme, syscall, cont, attach}`. Using the matching routines + with `sys::ptrace::ptrace` is now deprecated. +- Added `nix::poll` module for all platforms + ([#672](https://github.com/nix-rust/nix/pull/672)) +- Added `nix::ppoll` function for FreeBSD and DragonFly + ([#672](https://github.com/nix-rust/nix/pull/672)) +- Added protocol families in `AddressFamily` enum. + ([#647](https://github.com/nix-rust/nix/pull/647)) +- Added the `pid()` method to `WaitStatus` for extracting the PID. + ([#722](https://github.com/nix-rust/nix/pull/722)) +- Added `nix::unistd:fexecve`. + ([#727](https://github.com/nix-rust/nix/pull/727)) +- Expose `uname()` on all platforms. + ([#739](https://github.com/nix-rust/nix/pull/739)) +- Expose `signalfd` module on Android as well. + ([#739](https://github.com/nix-rust/nix/pull/739)) +- Added `nix::sys::ptrace::detach`. + ([#749](https://github.com/nix-rust/nix/pull/749)) +- Added timestamp socket control message variant: + `nix::sys::socket::ControlMessage::ScmTimestamp` + ([#663](https://github.com/nix-rust/nix/pull/663)) +- Added socket option variant that enables the timestamp socket + control message: `nix::sys::socket::sockopt::ReceiveTimestamp` + ([#663](https://github.com/nix-rust/nix/pull/663)) +- Added more accessor methods for `AioCb` + ([#773](https://github.com/nix-rust/nix/pull/773)) +- Add `nix::sys::fallocate` + ([#768](https:://github.com/nix-rust/nix/pull/768)) +- Added `nix::unistd::mkfifo`. + ([#602](https://github.com/nix-rust/nix/pull/774)) +- Added `ptrace::Options::PTRACE_O_EXITKILL` on Linux and Android. + ([#771](https://github.com/nix-rust/nix/pull/771)) +- Added `nix::sys::uio::{process_vm_readv, process_vm_writev}` on Linux + ([#568](https://github.com/nix-rust/nix/pull/568)) +- Added `nix::unistd::{getgroups, setgroups, getgrouplist, initgroups}`. ([#733](https://github.com/nix-rust/nix/pull/733)) +- Added `nix::sys::socket::UnixAddr::as_abstract` on Linux and Android. + ([#785](https://github.com/nix-rust/nix/pull/785)) +- Added `nix::unistd::execveat` on Linux and Android. + ([#800](https://github.com/nix-rust/nix/pull/800)) +- Added the `from_raw()` method to `WaitStatus` for converting raw status values + to `WaitStatus` independent of syscalls. + ([#741](https://github.com/nix-rust/nix/pull/741)) +- Added more standard trait implementations for various types. + ([#814](https://github.com/nix-rust/nix/pull/814)) +- Added `sigprocmask` to the signal module. + ([#826](https://github.com/nix-rust/nix/pull/826)) +- Added `nix::sys::socket::LinkAddr` on Linux and all bsdlike system. + ([#813](https://github.com/nix-rust/nix/pull/813)) +- Add socket options for `IP_TRANSPARENT` / `BIND_ANY`. + ([#835](https://github.com/nix-rust/nix/pull/835)) + +### Changed +- Exposed the `mqueue` module for all supported operating systems. + ([#834](https://github.com/nix-rust/nix/pull/834)) +- Use native `pipe2` on all BSD targets. Users should notice no difference. + ([#777](https://github.com/nix-rust/nix/pull/777)) +- Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692)) +- Marked `sys::ptrace::ptrace` as `unsafe`. +- Changed function signature of `socket()` and `socketpair()`. The `protocol` argument + has changed type from `c_int` to `SockProtocol`. + It accepts a `None` value for default protocol that was specified with zero using `c_int`. + ([#647](https://github.com/nix-rust/nix/pull/647)) +- Made `select` easier to use, adding the ability to automatically calculate the `nfds` parameter using the new + `FdSet::highest` ([#701](https://github.com/nix-rust/nix/pull/701)) +- Exposed `unistd::setresuid` and `unistd::setresgid` on FreeBSD and OpenBSD + ([#721](https://github.com/nix-rust/nix/pull/721)) +- Refactored the `statvfs` module removing extraneous API functions and the + `statvfs::vfs` module. Additionally `(f)statvfs()` now return the struct + directly. And the returned `Statvfs` struct now exposes its data through + accessor methods. ([#729](https://github.com/nix-rust/nix/pull/729)) +- The `addr` argument to `madvise` and `msync` is now `*mut` to better match the + libc API. ([#731](https://github.com/nix-rust/nix/pull/731)) +- `shm_open` and `shm_unlink` are no longer exposed on Android targets, where + they are not officially supported. ([#731](https://github.com/nix-rust/nix/pull/731)) +- `MapFlags`, `MmapAdvise`, and `MsFlags` expose some more variants and only + officially-supported variants are provided for each target. + ([#731](https://github.com/nix-rust/nix/pull/731)) +- Marked `pty::ptsname` function as `unsafe` + ([#744](https://github.com/nix-rust/nix/pull/744)) +- Moved constants ptrace request, event and options to enums and updated ptrace functions and argument types accordingly. + ([#749](https://github.com/nix-rust/nix/pull/749)) +- `AioCb::Drop` will now panic if the `AioCb` is still in-progress ([#715](https://github.com/nix-rust/nix/pull/715)) +- Restricted `nix::sys::socket::UnixAddr::new_abstract` to Linux and Android only. + ([#785](https://github.com/nix-rust/nix/pull/785)) +- The `ucred` struct has been removed in favor of a `UserCredentials` struct that + contains only getters for its fields. + ([#814](https://github.com/nix-rust/nix/pull/814)) +- Both `ip_mreq` and `ipv6_mreq` have been replaced with `IpMembershipRequest` and + `Ipv6MembershipRequest`. + ([#814](https://github.com/nix-rust/nix/pull/814)) +- Removed return type from `pause`. + ([#829](https://github.com/nix-rust/nix/pull/829)) +- Changed the termios APIs to allow for using a `u32` instead of the `BaudRate` + enum on BSD platforms to support arbitrary baud rates. See the module docs for + `nix::sys::termios` for more details. + ([#843](https://github.com/nix-rust/nix/pull/843)) + +### Fixed +- Fix compilation and tests for OpenBSD targets + ([#688](https://github.com/nix-rust/nix/pull/688)) +- Fixed error handling in `AioCb::fsync`, `AioCb::read`, and `AioCb::write`. + It is no longer an error to drop an `AioCb` that failed to enqueue in the OS. + ([#715](https://github.com/nix-rust/nix/pull/715)) +- Fix potential memory corruption on non-Linux platforms when using + `sendmsg`/`recvmsg`, caused by mismatched `msghdr` definition. + ([#648](https://github.com/nix-rust/nix/pull/648)) + +### Removed +- `AioCb::from_boxed_slice` has been removed. It was never actually safe. Use + `from_bytes` or `from_bytes_mut` instead. + ([#820](https://github.com/nix-rust/nix/pull/820)) +- The syscall module has been removed. This only exposed enough functionality for + `memfd_create()` and `pivot_root()`, which are still exposed as separate functions. + ([#747](https://github.com/nix-rust/nix/pull/747)) +- The `Errno` variants are no longer reexported from the `errno` module. `Errno` itself is no longer reexported from the + crate root and instead must be accessed using the `errno` module. ([#696](https://github.com/nix-rust/nix/pull/696)) +- Removed `MS_VERBOSE`, `MS_NOSEC`, and `MS_BORN` from `MsFlags`. These + are internal kernel flags and should never have been exposed. + ([#814](https://github.com/nix-rust/nix/pull/814)) + + +## [0.9.0] 2017-07-23 + +### Added +- Added `sysconf`, `pathconf`, and `fpathconf` + ([#630](https://github.com/nix-rust/nix/pull/630) +- Added `sys::signal::SigAction::{ flags, mask, handler}` + ([#611](https://github.com/nix-rust/nix/pull/609) +- Added `nix::sys::pthread::pthread_self` + ([#591](https://github.com/nix-rust/nix/pull/591) +- Added `AioCb::from_boxed_slice` + ([#582](https://github.com/nix-rust/nix/pull/582) +- Added `nix::unistd::{openat, fstatat, readlink, readlinkat}` + ([#551](https://github.com/nix-rust/nix/pull/551)) +- Added `nix::pty::{grantpt, posix_openpt, ptsname/ptsname_r, unlockpt}` + ([#556](https://github.com/nix-rust/nix/pull/556) +- Added `nix::ptr::openpty` + ([#456](https://github.com/nix-rust/nix/pull/456)) +- Added `nix::ptrace::{ptrace_get_data, ptrace_getsiginfo, ptrace_setsiginfo + and nix::Error::UnsupportedOperation}` + ([#614](https://github.com/nix-rust/nix/pull/614)) +- Added `cfmakeraw`, `cfsetspeed`, and `tcgetsid`. ([#527](https://github.com/nix-rust/nix/pull/527)) +- Added "bad none", "bad write_ptr", "bad write_int", and "bad readwrite" variants to the `ioctl!` + macro. ([#670](https://github.com/nix-rust/nix/pull/670)) +- On Linux and Android, added support for receiving `PTRACE_O_TRACESYSGOOD` + events from `wait` and `waitpid` using `WaitStatus::PtraceSyscall` + ([#566](https://github.com/nix-rust/nix/pull/566)). + +### Changed +- The `ioctl!` macro and its variants now allow the generated functions to have + doccomments. ([#661](https://github.com/nix-rust/nix/pull/661)) +- Changed `ioctl!(write ...)` into `ioctl!(write_ptr ...)` and `ioctl!(write_int ..)` variants + to more clearly separate those use cases. ([#670](https://github.com/nix-rust/nix/pull/670)) +- Marked `sys::mman::{ mmap, munmap, madvise, munlock, msync }` as unsafe. + ([#559](https://github.com/nix-rust/nix/pull/559)) +- Minimum supported Rust version is now 1.13. +- Removed `revents` argument from `PollFd::new()` as it's an output argument and + will be overwritten regardless of value. + ([#542](https://github.com/nix-rust/nix/pull/542)) +- Changed type signature of `sys::select::FdSet::contains` to make `self` + immutable ([#564](https://github.com/nix-rust/nix/pull/564)) +- Introduced wrapper types for `gid_t`, `pid_t`, and `uid_t` as `Gid`, `Pid`, and `Uid` + respectively. Various functions have been changed to use these new types as + arguments. ([#629](https://github.com/nix-rust/nix/pull/629)) +- Fixed compilation on all Android and iOS targets ([#527](https://github.com/nix-rust/nix/pull/527)) + and promoted them to Tier 2 support. +- `nix::sys::statfs::{statfs,fstatfs}` uses statfs definition from `libc::statfs` instead of own linux specific type `nix::sys::Statfs`. + Also file system type constants like `nix::sys::statfs::ADFS_SUPER_MAGIC` were removed in favor of the libc equivalent. + ([#561](https://github.com/nix-rust/nix/pull/561)) +- Revised the termios API including additional tests and documentation and exposed it on iOS. ([#527](https://github.com/nix-rust/nix/pull/527)) +- `eventfd`, `signalfd`, and `pwritev`/`preadv` functionality is now included by default for all + supported platforms. ([#681](https://github.com/nix-rust/nix/pull/561)) +- The `ioctl!` macro's plain variants has been replaced with "bad read" to be consistent with + other variants. The generated functions also have more strict types for their arguments. The + "*_buf" variants also now calculate total array size and take slice references for improved type + safety. The documentation has also been dramatically improved. + ([#670](https://github.com/nix-rust/nix/pull/670)) + +### Removed +- Removed `io::Error` from `nix::Error` and the conversion from `nix::Error` to `Errno` + ([#614](https://github.com/nix-rust/nix/pull/614)) +- All feature flags have been removed in favor of conditional compilation on supported platforms. + `execvpe` is no longer supported, but this was already broken and will be added back in the next + release. ([#681](https://github.com/nix-rust/nix/pull/561)) +- Removed `ioc_*` functions and many helper constants and macros within the `ioctl` module. These + should always have been private and only the `ioctl!` should be used in public code. + ([#670](https://github.com/nix-rust/nix/pull/670)) + +### Fixed +- Fixed multiple issues compiling under different archetectures and OSes. + Now compiles on Linux/MIPS ([#538](https://github.com/nix-rust/nix/pull/538)), + `Linux/PPC` ([#553](https://github.com/nix-rust/nix/pull/553)), + `MacOS/x86_64,i686` ([#553](https://github.com/nix-rust/nix/pull/553)), + `NetBSD/x64_64` ([#538](https://github.com/nix-rust/nix/pull/538)), + `FreeBSD/x86_64,i686` ([#536](https://github.com/nix-rust/nix/pull/536)), and + `Android` ([#631](https://github.com/nix-rust/nix/pull/631)). +- `bind` and `errno_location` now work correctly on `Android` + ([#631](https://github.com/nix-rust/nix/pull/631)) +- Added `nix::ptrace` on all Linux-kernel-based platforms + [#624](https://github.com/nix-rust/nix/pull/624). Previously it was + only available on x86, x86-64, and ARM, and also not on Android. +- Fixed `sys::socket::sendmsg` with zero entry `cmsgs` parameter. + ([#623](https://github.com/nix-rust/nix/pull/623)) +- Multiple constants related to the termios API have now been properly defined for + all supported platforms. ([#527](https://github.com/nix-rust/nix/pull/527)) +- `ioctl!` macro now supports working with non-int datatypes and properly supports all platforms. + ([#670](https://github.com/nix-rust/nix/pull/670)) + +## [0.8.1] 2017-04-16 + +### Fixed +- Fixed build on FreeBSD. (Cherry-picked + [a859ee3c](https://github.com/nix-rust/nix/commit/a859ee3c9396dfdb118fcc2c8ecc697e2d303467)) + +## [0.8.0] 2017-03-02 + +### Added +- Added `::nix::sys::termios::BaudRate` enum to provide portable baudrate + values. ([#518](https://github.com/nix-rust/nix/pull/518)) +- Added a new `WaitStatus::PtraceEvent` to support ptrace events on Linux + and Android ([#438](https://github.com/nix-rust/nix/pull/438)) +- Added support for POSIX AIO + ([#483](https://github.com/nix-rust/nix/pull/483)) + ([#506](https://github.com/nix-rust/nix/pull/506)) +- Added support for XNU system control sockets + ([#478](https://github.com/nix-rust/nix/pull/478)) +- Added support for `ioctl` calls on BSD platforms + ([#478](https://github.com/nix-rust/nix/pull/478)) +- Added struct `TimeSpec` + ([#475](https://github.com/nix-rust/nix/pull/475)) + ([#483](https://github.com/nix-rust/nix/pull/483)) +- Added complete definitions for all kqueue-related constants on all supported + OSes + ([#415](https://github.com/nix-rust/nix/pull/415)) +- Added function `epoll_create1` and bitflags `EpollCreateFlags` in + `::nix::sys::epoll` in order to support `::libc::epoll_create1`. + ([#410](https://github.com/nix-rust/nix/pull/410)) +- Added `setresuid` and `setresgid` for Linux in `::nix::unistd` + ([#448](https://github.com/nix-rust/nix/pull/448)) +- Added `getpgid` in `::nix::unistd` + ([#433](https://github.com/nix-rust/nix/pull/433)) +- Added `tcgetpgrp` and `tcsetpgrp` in `::nix::unistd` + ([#451](https://github.com/nix-rust/nix/pull/451)) +- Added `CLONE_NEWCGROUP` in `::nix::sched` + ([#457](https://github.com/nix-rust/nix/pull/457)) +- Added `getpgrp` in `::nix::unistd` + ([#491](https://github.com/nix-rust/nix/pull/491)) +- Added `fchdir` in `::nix::unistd` + ([#497](https://github.com/nix-rust/nix/pull/497)) +- Added `major` and `minor` in `::nix::sys::stat` for decomposing `dev_t` + ([#508](https://github.com/nix-rust/nix/pull/508)) +- Fixed the style of many bitflags and use `libc` in more places. + ([#503](https://github.com/nix-rust/nix/pull/503)) +- Added `ppoll` in `::nix::poll` + ([#520](https://github.com/nix-rust/nix/pull/520)) +- Added support for getting and setting pipe size with fcntl(2) on Linux + ([#540](https://github.com/nix-rust/nix/pull/540)) + +### Changed +- `::nix::sys::termios::{cfgetispeed, cfsetispeed, cfgetospeed, cfsetospeed}` + switched to use `BaudRate` enum from `speed_t`. + ([#518](https://github.com/nix-rust/nix/pull/518)) +- `epoll_ctl` now could accept None as argument `event` + when op is `EpollOp::EpollCtlDel`. + ([#480](https://github.com/nix-rust/nix/pull/480)) +- Removed the `bad` keyword from the `ioctl!` macro + ([#478](https://github.com/nix-rust/nix/pull/478)) +- Changed `TimeVal` into an opaque Newtype + ([#475](https://github.com/nix-rust/nix/pull/475)) +- `kill`'s signature, defined in `::nix::sys::signal`, changed, so that the + signal parameter has type `T: Into>`. `None` as an argument + for that parameter will result in a 0 passed to libc's `kill`, while a + `Some`-argument will result in the previous behavior for the contained + `Signal`. + ([#445](https://github.com/nix-rust/nix/pull/445)) +- The minimum supported version of rustc is now 1.7.0. + ([#444](https://github.com/nix-rust/nix/pull/444)) +- Changed `KEvent` to an opaque structure that may only be modified by its + constructor and the `ev_set` method. + ([#415](https://github.com/nix-rust/nix/pull/415)) + ([#442](https://github.com/nix-rust/nix/pull/442)) + ([#463](https://github.com/nix-rust/nix/pull/463)) +- `pipe2` now calls `libc::pipe2` where available. Previously it was emulated + using `pipe`, which meant that setting `O_CLOEXEC` was not atomic. + ([#427](https://github.com/nix-rust/nix/pull/427)) +- Renamed `EpollEventKind` to `EpollFlags` in `::nix::sys::epoll` in order for + it to conform with our conventions. + ([#410](https://github.com/nix-rust/nix/pull/410)) +- `EpollEvent` in `::nix::sys::epoll` is now an opaque proxy for + `::libc::epoll_event`. The formerly public field `events` is now be read-only + accessible with the new method `events()` of `EpollEvent`. Instances of + `EpollEvent` can be constructed using the new method `new()` of EpollEvent. + ([#410](https://github.com/nix-rust/nix/pull/410)) +- `SigFlags` in `::nix::sys::signal` has be renamed to `SigmaskHow` and its type + has changed from `bitflags` to `enum` in order to conform to our conventions. + ([#460](https://github.com/nix-rust/nix/pull/460)) +- `sethostname` now takes a `&str` instead of a `&[u8]` as this provides an API + that makes more sense in normal, correct usage of the API. +- `gethostname` previously did not expose the actual length of the hostname + written from the underlying system call at all. This has been updated to + return a `&CStr` within the provided buffer that is always properly + NUL-terminated (this is not guaranteed by the call with all platforms/libc + implementations). +- Exposed all fcntl(2) operations at the module level, so they can be + imported direclty instead of via `FcntlArg` enum. + ([#541](https://github.com/nix-rust/nix/pull/541)) + +### Fixed +- Fixed multiple issues with Unix domain sockets on non-Linux OSes + ([#474](https://github.com/nix-rust/nix/pull/415)) +- Fixed using kqueue with `EVFILT_USER` on FreeBSD + ([#415](https://github.com/nix-rust/nix/pull/415)) +- Fixed the build on FreeBSD, and fixed the getsockopt, sendmsg, and recvmsg + functions on that same OS. + ([#397](https://github.com/nix-rust/nix/pull/397)) +- Fixed an off-by-one bug in `UnixAddr::new_abstract` in `::nix::sys::socket`. + ([#429](https://github.com/nix-rust/nix/pull/429)) +- Fixed clone passing a potentially unaligned stack. + ([#490](https://github.com/nix-rust/nix/pull/490)) +- Fixed mkdev not creating a `dev_t` the same way as libc. + ([#508](https://github.com/nix-rust/nix/pull/508)) + +## [0.7.0] 2016-09-09 + +### Added +- Added `lseek` and `lseek64` in `::nix::unistd` + ([#377](https://github.com/nix-rust/nix/pull/377)) +- Added `mkdir` and `getcwd` in `::nix::unistd` + ([#416](https://github.com/nix-rust/nix/pull/416)) +- Added accessors `sigmask_mut` and `sigmask` to `UContext` in + `::nix::ucontext`. + ([#370](https://github.com/nix-rust/nix/pull/370)) +- Added `WUNTRACED` to `WaitPidFlag` in `::nix::sys::wait` for non-_linux_ + targets. + ([#379](https://github.com/nix-rust/nix/pull/379)) +- Added new module `::nix::sys::reboot` with enumeration `RebootMode` and + functions `reboot` and `set_cad_enabled`. Currently for _linux_ only. + ([#386](https://github.com/nix-rust/nix/pull/386)) +- `FdSet` in `::nix::sys::select` now also implements `Clone`. + ([#405](https://github.com/nix-rust/nix/pull/405)) +- Added `F_FULLFSYNC` to `FcntlArg` in `::nix::fcntl` for _apple_ targets. + ([#407](https://github.com/nix-rust/nix/pull/407)) +- Added `CpuSet::unset` in `::nix::sched`. + ([#402](https://github.com/nix-rust/nix/pull/402)) +- Added constructor method `new()` to `PollFd` in `::nix::poll`, in order to + allow creation of objects, after removing public access to members. + ([#399](https://github.com/nix-rust/nix/pull/399)) +- Added method `revents()` to `PollFd` in `::nix::poll`, in order to provide + read access to formerly public member `revents`. + ([#399](https://github.com/nix-rust/nix/pull/399)) +- Added `MSG_CMSG_CLOEXEC` to `MsgFlags` in `::nix::sys::socket` for _linux_ only. + ([#422](https://github.com/nix-rust/nix/pull/422)) + +### Changed +- Replaced the reexported integer constants for signals by the enumeration + `Signal` in `::nix::sys::signal`. + ([#362](https://github.com/nix-rust/nix/pull/362)) +- Renamed `EventFdFlag` to `EfdFlags` in `::nix::sys::eventfd`. + ([#383](https://github.com/nix-rust/nix/pull/383)) +- Changed the result types of `CpuSet::is_set` and `CpuSet::set` in + `::nix::sched` to `Result` and `Result<()>`, respectively. They now + return `EINVAL`, if an invalid argument for the `field` parameter is passed. + ([#402](https://github.com/nix-rust/nix/pull/402)) +- `MqAttr` in `::nix::mqueue` is now an opaque proxy for `::libc::mq_attr`, + which has the same structure as the old `MqAttr`. The field `mq_flags` of + `::libc::mq_attr` is readable using the new method `flags()` of `MqAttr`. + `MqAttr` also no longer implements `Debug`. + ([#392](https://github.com/nix-rust/nix/pull/392)) +- The parameter `msq_prio` of `mq_receive` with type `u32` in `::nix::mqueue` + was replaced by a parameter named `msg_prio` with type `&mut u32`, so that + the message priority can be obtained by the caller. + ([#392](https://github.com/nix-rust/nix/pull/392)) +- The type alias `MQd` in `::nix::queue` was replaced by the type alias + `libc::mqd_t`, both of which are aliases for the same type. + ([#392](https://github.com/nix-rust/nix/pull/392)) + +### Removed +- Type alias `SigNum` from `::nix::sys::signal`. + ([#362](https://github.com/nix-rust/nix/pull/362)) +- Type alias `CpuMask` from `::nix::shed`. + ([#402](https://github.com/nix-rust/nix/pull/402)) +- Removed public fields from `PollFd` in `::nix::poll`. (See also added method + `revents()`. + ([#399](https://github.com/nix-rust/nix/pull/399)) + +### Fixed +- Fixed the build problem for NetBSD (Note, that we currently do not support + it, so it might already be broken again). + ([#389](https://github.com/nix-rust/nix/pull/389)) +- Fixed the build on FreeBSD, and fixed the getsockopt, sendmsg, and recvmsg + functions on that same OS. + ([#397](https://github.com/nix-rust/nix/pull/397)) + +## [0.6.0] 2016-06-10 + +### Added +- Added `gettid` in `::nix::unistd` for _linux_ and _android_. + ([#293](https://github.com/nix-rust/nix/pull/293)) +- Some _mips_ support in `::nix::sched` and `::nix::sys::syscall`. + ([#301](https://github.com/nix-rust/nix/pull/301)) +- Added `SIGNALFD_SIGINFO_SIZE` in `::nix::sys::signalfd`. + ([#309](https://github.com/nix-rust/nix/pull/309)) +- Added new module `::nix::ucontext` with struct `UContext`. Currently for + _linux_ only. + ([#311](https://github.com/nix-rust/nix/pull/311)) +- Added `EPOLLEXCLUSIVE` to `EpollEventKind` in `::nix::sys::epoll`. + ([#330](https://github.com/nix-rust/nix/pull/330)) +- Added `pause` to `::nix::unistd`. + ([#336](https://github.com/nix-rust/nix/pull/336)) +- Added `sleep` to `::nix::unistd`. + ([#351](https://github.com/nix-rust/nix/pull/351)) +- Added `S_IFDIR`, `S_IFLNK`, `S_IFMT` to `SFlag` in `::nix::sys::stat`. + ([#359](https://github.com/nix-rust/nix/pull/359)) +- Added `clear` and `extend` functions to `SigSet`'s implementation in + `::nix::sys::signal`. + ([#347](https://github.com/nix-rust/nix/pull/347)) +- `sockaddr_storage_to_addr` in `::nix::sys::socket` now supports `sockaddr_nl` + on _linux_ and _android_. + ([#366](https://github.com/nix-rust/nix/pull/366)) +- Added support for `SO_ORIGINAL_DST` in `::nix::sys::socket` on _linux_. + ([#367](https://github.com/nix-rust/nix/pull/367)) +- Added `SIGINFO` in `::nix::sys::signal` for the _macos_ target as well as + `SIGPWR` and `SIGSTKFLT` in `::nix::sys::signal` for non-_macos_ targets. + ([#361](https://github.com/nix-rust/nix/pull/361)) + +### Changed +- Changed the structure `IoVec` in `::nix::sys::uio`. + ([#304](https://github.com/nix-rust/nix/pull/304)) +- Replaced `CREATE_NEW_FD` by `SIGNALFD_NEW` in `::nix::sys::signalfd`. + ([#309](https://github.com/nix-rust/nix/pull/309)) +- Renamed `SaFlag` to `SaFlags` and `SigFlag` to `SigFlags` in + `::nix::sys::signal`. + ([#314](https://github.com/nix-rust/nix/pull/314)) +- Renamed `Fork` to `ForkResult` and changed its fields in `::nix::unistd`. + ([#332](https://github.com/nix-rust/nix/pull/332)) +- Added the `signal` parameter to `clone`'s signature in `::nix::sched`. + ([#344](https://github.com/nix-rust/nix/pull/344)) +- `execv`, `execve`, and `execvp` now return `Result` instead of + `Result<()>` in `::nix::unistd`. + ([#357](https://github.com/nix-rust/nix/pull/357)) + +### Fixed +- Improved the conversion from `std::net::SocketAddr` to `InetAddr` in + `::nix::sys::socket::addr`. + ([#335](https://github.com/nix-rust/nix/pull/335)) + +## [0.5.0] 2016-03-01 diff --git a/vendor/nix-0.26.2/Cargo.toml b/vendor/nix-0.26.2/Cargo.toml new file mode 100644 index 0000000000000..bc7e79da9a2df --- /dev/null +++ b/vendor/nix-0.26.2/Cargo.toml @@ -0,0 +1,171 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +rust-version = "1.56" +name = "nix" +version = "0.26.2" +authors = ["The nix-rust Project Developers"] +include = [ + "src/**/*", + "test/**/*", + "LICENSE", + "README.md", + "CHANGELOG.md", +] +description = "Rust friendly bindings to *nix APIs" +readme = "README.md" +categories = ["os::unix-apis"] +license = "MIT" +repository = "https://github.com/nix-rust/nix" + +[package.metadata.docs.rs] +rustdoc-args = [ + "--cfg", + "docsrs", +] +targets = [ + "x86_64-unknown-linux-gnu", + "aarch64-linux-android", + "x86_64-apple-darwin", + "aarch64-apple-ios", + "x86_64-unknown-freebsd", + "x86_64-unknown-openbsd", + "x86_64-unknown-netbsd", + "x86_64-unknown-dragonfly", + "x86_64-fuchsia", + "x86_64-unknown-redox", + "x86_64-unknown-illumos", +] + +[[test]] +name = "test" +path = "test/test.rs" + +[[test]] +name = "test-aio-drop" +path = "test/sys/test_aio_drop.rs" + +[[test]] +name = "test-clearenv" +path = "test/test_clearenv.rs" + +[[test]] +name = "test-mount" +path = "test/test_mount.rs" +harness = false + +[[test]] +name = "test-ptymaster-drop" +path = "test/test_ptymaster_drop.rs" + +[dependencies] +bitflags = "1.1" +cfg-if = "1.0" +static_assertions = "1" + +[dependencies.libc] +version = "0.2.137" +features = ["extra_traits"] + +[dependencies.pin-utils] +version = "0.1.0" +optional = true + +[dev-dependencies] +assert-impl = "0.1" +lazy_static = "1.4" +parking_lot = "0.12" +rand = "0.8" +semver = "1.0.7" +tempfile = "3.3.0" + +[features] +acct = [] +aio = ["pin-utils"] +default = [ + "acct", + "aio", + "dir", + "env", + "event", + "feature", + "fs", + "hostname", + "inotify", + "ioctl", + "kmod", + "mman", + "mount", + "mqueue", + "net", + "personality", + "poll", + "process", + "pthread", + "ptrace", + "quota", + "reboot", + "resource", + "sched", + "signal", + "socket", + "term", + "time", + "ucontext", + "uio", + "user", + "zerocopy", +] +dir = ["fs"] +env = [] +event = [] +feature = [] +fs = [] +hostname = [] +inotify = [] +ioctl = [] +kmod = [] +mman = [] +mount = ["uio"] +mqueue = ["fs"] +net = ["socket"] +personality = [] +poll = [] +process = [] +pthread = [] +ptrace = ["process"] +quota = [] +reboot = [] +resource = [] +sched = ["process"] +signal = ["process"] +socket = ["memoffset"] +term = [] +time = [] +ucontext = ["signal"] +uio = [] +user = ["feature"] +zerocopy = [ + "fs", + "uio", +] + +[target."cfg(any(target_os = \"android\", target_os = \"linux\"))".dev-dependencies] +caps = "0.5.3" + +[target."cfg(not(target_os = \"redox\"))".dependencies.memoffset] +version = "0.7" +optional = true + +[target."cfg(target_os = \"freebsd\")".dev-dependencies] +sysctl = "0.4" diff --git a/vendor/nix-0.26.2/LICENSE b/vendor/nix-0.26.2/LICENSE new file mode 100644 index 0000000000000..aff9096fdf11d --- /dev/null +++ b/vendor/nix-0.26.2/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Carl Lerche + nix-rust Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/nix-0.26.2/README.md b/vendor/nix-0.26.2/README.md new file mode 100644 index 0000000000000..2c42b905f79dd --- /dev/null +++ b/vendor/nix-0.26.2/README.md @@ -0,0 +1,105 @@ +# Rust bindings to *nix APIs + +[![Cirrus Build Status](https://api.cirrus-ci.com/github/nix-rust/nix.svg)](https://cirrus-ci.com/github/nix-rust/nix) +[![crates.io](https://img.shields.io/crates/v/nix.svg)](https://crates.io/crates/nix) + +[Documentation (Releases)](https://docs.rs/nix/) + +Nix seeks to provide friendly bindings to various *nix platform APIs (Linux, Darwin, +...). The goal is to not provide a 100% unified interface, but to unify +what can be while still providing platform specific APIs. + +For many system APIs, Nix provides a safe alternative to the unsafe APIs +exposed by the [libc crate](https://github.com/rust-lang/libc). This is done by +wrapping the libc functionality with types/abstractions that enforce legal/safe +usage. + + +As an example of what Nix provides, examine the differences between what is +exposed by libc and nix for the +[gethostname](https://man7.org/linux/man-pages/man2/gethostname.2.html) system +call: + +```rust,ignore +// libc api (unsafe, requires handling return code/errno) +pub unsafe extern fn gethostname(name: *mut c_char, len: size_t) -> c_int; + +// nix api (returns a nix::Result) +pub fn gethostname() -> Result; +``` + +## Supported Platforms + +nix target support consists of two tiers. While nix attempts to support all +platforms supported by [libc](https://github.com/rust-lang/libc), only some +platforms are actively supported due to either technical or manpower +limitations. Support for platforms is split into three tiers: + + * Tier 1 - Builds and tests for this target are run in CI. Failures of either + block the inclusion of new code. + * Tier 2 - Builds for this target are run in CI. Failures during the build + blocks the inclusion of new code. Tests may be run, but failures + in tests don't block the inclusion of new code. + * Tier 3 - Builds for this target are run in CI. Failures during the build + *do not* block the inclusion of new code. Testing may be run, but + failures in tests don't block the inclusion of new code. + +The following targets are supported by `nix`: + +Tier 1: + * aarch64-apple-darwin + * aarch64-unknown-linux-gnu + * arm-unknown-linux-gnueabi + * armv7-unknown-linux-gnueabihf + * i686-unknown-freebsd + * i686-unknown-linux-gnu + * i686-unknown-linux-musl + * mips-unknown-linux-gnu + * mips64-unknown-linux-gnuabi64 + * mips64el-unknown-linux-gnuabi64 + * mipsel-unknown-linux-gnu + * powerpc64le-unknown-linux-gnu + * x86_64-unknown-freebsd + * x86_64-unknown-linux-gnu + * x86_64-unknown-linux-musl + +Tier 2: + * aarch64-apple-ios + * aarch64-linux-android + * arm-linux-androideabi + * arm-unknown-linux-musleabi + * armv7-linux-androideabi + * i686-linux-android + * powerpc-unknown-linux-gnu + * s390x-unknown-linux-gnu + * x86_64-apple-ios + * x86_64-linux-android + * x86_64-apple-darwin + * x86_64-unknown-illumos + * x86_64-unknown-netbsd + +Tier 3: + * armv7-unknown-linux-uclibceabihf + * x86_64-fuchsia + * x86_64-unknown-dragonfly + * x86_64-unknown-haiku + * x86_64-unknown-linux-gnux32 + * x86_64-unknown-openbsd + * x86_64-unknown-redox + +## Minimum Supported Rust Version (MSRV) + +nix is supported on Rust 1.56.1 and higher. Its MSRV will not be +changed in the future without bumping the major or minor version. + +## Contributing + +Contributions are very welcome. Please See [CONTRIBUTING](CONTRIBUTING.md) for +additional details. + +Feel free to join us in [the nix-rust/nix](https://gitter.im/nix-rust/nix) channel on Gitter to +discuss `nix` development. + +## License + +Nix is licensed under the MIT license. See [LICENSE](LICENSE) for more details. diff --git a/vendor/nix-0.26.2/src/dir.rs b/vendor/nix-0.26.2/src/dir.rs new file mode 100644 index 0000000000000..5ce503644e264 --- /dev/null +++ b/vendor/nix-0.26.2/src/dir.rs @@ -0,0 +1,276 @@ +//! List directory contents + +use crate::errno::Errno; +use crate::fcntl::{self, OFlag}; +use crate::sys; +use crate::{Error, NixPath, Result}; +use cfg_if::cfg_if; +use std::ffi; +use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; +use std::ptr; + +#[cfg(target_os = "linux")] +use libc::{dirent64 as dirent, readdir64_r as readdir_r}; + +#[cfg(not(target_os = "linux"))] +use libc::{dirent, readdir_r}; + +/// An open directory. +/// +/// This is a lower-level interface than `std::fs::ReadDir`. Notable differences: +/// * can be opened from a file descriptor (as returned by `openat`, perhaps before knowing +/// if the path represents a file or directory). +/// * implements `AsRawFd`, so it can be passed to `fstat`, `openat`, etc. +/// The file descriptor continues to be owned by the `Dir`, so callers must not keep a `RawFd` +/// after the `Dir` is dropped. +/// * can be iterated through multiple times without closing and reopening the file +/// descriptor. Each iteration rewinds when finished. +/// * returns entries for `.` (current directory) and `..` (parent directory). +/// * returns entries' names as a `CStr` (no allocation or conversion beyond whatever libc +/// does). +#[derive(Debug, Eq, Hash, PartialEq)] +pub struct Dir(ptr::NonNull); + +impl Dir { + /// Opens the given path as with `fcntl::open`. + pub fn open( + path: &P, + oflag: OFlag, + mode: sys::stat::Mode, + ) -> Result { + let fd = fcntl::open(path, oflag, mode)?; + Dir::from_fd(fd) + } + + /// Opens the given path as with `fcntl::openat`. + pub fn openat( + dirfd: RawFd, + path: &P, + oflag: OFlag, + mode: sys::stat::Mode, + ) -> Result { + let fd = fcntl::openat(dirfd, path, oflag, mode)?; + Dir::from_fd(fd) + } + + /// Converts from a descriptor-based object, closing the descriptor on success or failure. + #[inline] + pub fn from(fd: F) -> Result { + Dir::from_fd(fd.into_raw_fd()) + } + + /// Converts from a file descriptor, closing it on success or failure. + #[doc(alias("fdopendir"))] + pub fn from_fd(fd: RawFd) -> Result { + let d = ptr::NonNull::new(unsafe { libc::fdopendir(fd) }).ok_or_else( + || { + let e = Error::last(); + unsafe { libc::close(fd) }; + e + }, + )?; + Ok(Dir(d)) + } + + /// Returns an iterator of `Result` which rewinds when finished. + pub fn iter(&mut self) -> Iter { + Iter(self) + } +} + +// `Dir` is not `Sync`. With the current implementation, it could be, but according to +// https://www.gnu.org/software/libc/manual/html_node/Reading_002fClosing-Directory.html, +// future versions of POSIX are likely to obsolete `readdir_r` and specify that it's unsafe to +// call `readdir` simultaneously from multiple threads. +// +// `Dir` is safe to pass from one thread to another, as it's not reference-counted. +unsafe impl Send for Dir {} + +impl AsRawFd for Dir { + fn as_raw_fd(&self) -> RawFd { + unsafe { libc::dirfd(self.0.as_ptr()) } + } +} + +impl Drop for Dir { + fn drop(&mut self) { + let e = Errno::result(unsafe { libc::closedir(self.0.as_ptr()) }); + if !std::thread::panicking() && e == Err(Errno::EBADF) { + panic!("Closing an invalid file descriptor!"); + }; + } +} + +fn next(dir: &mut Dir) -> Option> { + unsafe { + // Note: POSIX specifies that portable applications should dynamically allocate a + // buffer with room for a `d_name` field of size `pathconf(..., _PC_NAME_MAX)` plus 1 + // for the NUL byte. It doesn't look like the std library does this; it just uses + // fixed-sized buffers (and libc's dirent seems to be sized so this is appropriate). + // Probably fine here too then. + let mut ent = std::mem::MaybeUninit::::uninit(); + let mut result = ptr::null_mut(); + if let Err(e) = Errno::result(readdir_r( + dir.0.as_ptr(), + ent.as_mut_ptr(), + &mut result, + )) { + return Some(Err(e)); + } + if result.is_null() { + return None; + } + assert_eq!(result, ent.as_mut_ptr()); + Some(Ok(Entry(ent.assume_init()))) + } +} + +/// Return type of [`Dir::iter`]. +#[derive(Debug, Eq, Hash, PartialEq)] +pub struct Iter<'d>(&'d mut Dir); + +impl<'d> Iterator for Iter<'d> { + type Item = Result; + + fn next(&mut self) -> Option { + next(self.0) + } +} + +impl<'d> Drop for Iter<'d> { + fn drop(&mut self) { + unsafe { libc::rewinddir((self.0).0.as_ptr()) } + } +} + +/// The return type of [Dir::into_iter] +#[derive(Debug, Eq, Hash, PartialEq)] +pub struct OwningIter(Dir); + +impl Iterator for OwningIter { + type Item = Result; + + fn next(&mut self) -> Option { + next(&mut self.0) + } +} + +/// The file descriptor continues to be owned by the `OwningIter`, +/// so callers must not keep a `RawFd` after the `OwningIter` is dropped. +impl AsRawFd for OwningIter { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl IntoIterator for Dir { + type Item = Result; + type IntoIter = OwningIter; + + /// Creates a owning iterator, that is, one that takes ownership of the + /// `Dir`. The `Dir` cannot be used after calling this. This can be useful + /// when you have a function that both creates a `Dir` instance and returns + /// an `Iterator`. + /// + /// Example: + /// + /// ``` + /// use nix::{dir::Dir, fcntl::OFlag, sys::stat::Mode}; + /// use std::{iter::Iterator, string::String}; + /// + /// fn ls_upper(dirname: &str) -> impl Iterator { + /// let d = Dir::open(dirname, OFlag::O_DIRECTORY, Mode::S_IXUSR).unwrap(); + /// d.into_iter().map(|x| x.unwrap().file_name().as_ref().to_string_lossy().to_ascii_uppercase()) + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + OwningIter(self) + } +} + +/// A directory entry, similar to `std::fs::DirEntry`. +/// +/// Note that unlike the std version, this may represent the `.` or `..` entries. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] +#[repr(transparent)] +pub struct Entry(dirent); + +/// Type of file referenced by a directory entry +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] +pub enum Type { + /// FIFO (Named pipe) + Fifo, + /// Character device + CharacterDevice, + /// Directory + Directory, + /// Block device + BlockDevice, + /// Regular file + File, + /// Symbolic link + Symlink, + /// Unix-domain socket + Socket, +} + +impl Entry { + /// Returns the inode number (`d_ino`) of the underlying `dirent`. + #[allow(clippy::useless_conversion)] // Not useless on all OSes + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + pub fn ino(&self) -> u64 { + cfg_if! { + if #[cfg(any(target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "l4re", + target_os = "linux", + target_os = "macos", + target_os = "solaris"))] { + self.0.d_ino as u64 + } else { + u64::from(self.0.d_fileno) + } + } + } + + /// Returns the bare file name of this directory entry without any other leading path component. + pub fn file_name(&self) -> &ffi::CStr { + unsafe { ::std::ffi::CStr::from_ptr(self.0.d_name.as_ptr()) } + } + + /// Returns the type of this directory entry, if known. + /// + /// See platform `readdir(3)` or `dirent(5)` manpage for when the file type is known; + /// notably, some Linux filesystems don't implement this. The caller should use `stat` or + /// `fstat` if this returns `None`. + pub fn file_type(&self) -> Option { + #[cfg(not(any( + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" + )))] + match self.0.d_type { + libc::DT_FIFO => Some(Type::Fifo), + libc::DT_CHR => Some(Type::CharacterDevice), + libc::DT_DIR => Some(Type::Directory), + libc::DT_BLK => Some(Type::BlockDevice), + libc::DT_REG => Some(Type::File), + libc::DT_LNK => Some(Type::Symlink), + libc::DT_SOCK => Some(Type::Socket), + /* libc::DT_UNKNOWN | */ _ => None, + } + + // illumos, Solaris, and Haiku systems do not have the d_type member at all: + #[cfg(any( + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" + ))] + None + } +} diff --git a/vendor/nix-0.26.2/src/env.rs b/vendor/nix-0.26.2/src/env.rs new file mode 100644 index 0000000000000..95177a1d2a1aa --- /dev/null +++ b/vendor/nix-0.26.2/src/env.rs @@ -0,0 +1,64 @@ +//! Environment variables +use cfg_if::cfg_if; +use std::fmt; + +/// Indicates that [`clearenv`] failed for some unknown reason +#[derive(Clone, Copy, Debug)] +pub struct ClearEnvError; + +impl fmt::Display for ClearEnvError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "clearenv failed") + } +} + +impl std::error::Error for ClearEnvError {} + +/// Clear the environment of all name-value pairs. +/// +/// On platforms where libc provides `clearenv()`, it will be used. libc's +/// `clearenv()` is documented to return an error code but not set errno; if the +/// return value indicates a failure, this function will return +/// [`ClearEnvError`]. +/// +/// On platforms where libc does not provide `clearenv()`, a fallback +/// implementation will be used that iterates over all environment variables and +/// removes them one-by-one. +/// +/// # Safety +/// +/// This function is not threadsafe and can cause undefined behavior in +/// combination with `std::env` or other program components that access the +/// environment. See, for example, the discussion on `std::env::remove_var`; this +/// function is a case of an "inherently unsafe non-threadsafe API" dealing with +/// the environment. +/// +/// The caller must ensure no other threads access the process environment while +/// this function executes and that no raw pointers to an element of libc's +/// `environ` is currently held. The latter is not an issue if the only other +/// environment access in the program is via `std::env`, but the requirement on +/// thread safety must still be upheld. +pub unsafe fn clearenv() -> std::result::Result<(), ClearEnvError> { + cfg_if! { + if #[cfg(any(target_os = "fuchsia", + target_os = "wasi", + target_env = "uclibc", + target_os = "linux", + target_os = "android", + target_os = "emscripten"))] { + let ret = libc::clearenv(); + } else { + use std::env; + for (name, _) in env::vars_os() { + env::remove_var(name); + } + let ret = 0; + } + } + + if ret == 0 { + Ok(()) + } else { + Err(ClearEnvError) + } +} diff --git a/vendor/nix-0.26.2/src/errno.rs b/vendor/nix-0.26.2/src/errno.rs new file mode 100644 index 0000000000000..d8ad28de85466 --- /dev/null +++ b/vendor/nix-0.26.2/src/errno.rs @@ -0,0 +1,3133 @@ +use crate::Result; +use cfg_if::cfg_if; +use libc::{c_int, c_void}; +use std::convert::TryFrom; +use std::{error, fmt, io}; + +pub use self::consts::*; + +cfg_if! { + if #[cfg(any(target_os = "freebsd", + target_os = "ios", + target_os = "macos"))] { + unsafe fn errno_location() -> *mut c_int { + libc::__error() + } + } else if #[cfg(any(target_os = "android", + target_os = "netbsd", + target_os = "openbsd"))] { + unsafe fn errno_location() -> *mut c_int { + libc::__errno() + } + } else if #[cfg(any(target_os = "linux", + target_os = "redox", + target_os = "dragonfly", + target_os = "fuchsia"))] { + unsafe fn errno_location() -> *mut c_int { + libc::__errno_location() + } + } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] { + unsafe fn errno_location() -> *mut c_int { + libc::___errno() + } + } else if #[cfg(any(target_os = "haiku",))] { + unsafe fn errno_location() -> *mut c_int { + libc::_errnop() + } + } +} + +/// Sets the platform-specific errno to no-error +fn clear() { + // Safe because errno is a thread-local variable + unsafe { + *errno_location() = 0; + } +} + +/// Returns the platform-specific value of errno +pub fn errno() -> i32 { + unsafe { *errno_location() } +} + +impl Errno { + pub fn last() -> Self { + last() + } + + pub fn desc(self) -> &'static str { + desc(self) + } + + pub const fn from_i32(err: i32) -> Errno { + from_i32(err) + } + + pub fn clear() { + clear() + } + + /// Returns `Ok(value)` if it does not contain the sentinel value. This + /// should not be used when `-1` is not the errno sentinel value. + #[inline] + pub fn result>(value: S) -> Result { + if value == S::sentinel() { + Err(Self::last()) + } else { + Ok(value) + } + } +} + +/// The sentinel value indicates that a function failed and more detailed +/// information about the error can be found in `errno` +pub trait ErrnoSentinel: Sized { + fn sentinel() -> Self; +} + +impl ErrnoSentinel for isize { + fn sentinel() -> Self { + -1 + } +} + +impl ErrnoSentinel for i32 { + fn sentinel() -> Self { + -1 + } +} + +impl ErrnoSentinel for i64 { + fn sentinel() -> Self { + -1 + } +} + +impl ErrnoSentinel for *mut c_void { + fn sentinel() -> Self { + -1isize as *mut c_void + } +} + +impl ErrnoSentinel for libc::sighandler_t { + fn sentinel() -> Self { + libc::SIG_ERR + } +} + +impl error::Error for Errno {} + +impl fmt::Display for Errno { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}: {}", self, self.desc()) + } +} + +impl From for io::Error { + fn from(err: Errno) -> Self { + io::Error::from_raw_os_error(err as i32) + } +} + +impl TryFrom for Errno { + type Error = io::Error; + + fn try_from(ioerror: io::Error) -> std::result::Result { + ioerror.raw_os_error().map(Errno::from_i32).ok_or(ioerror) + } +} + +fn last() -> Errno { + Errno::from_i32(errno()) +} + +fn desc(errno: Errno) -> &'static str { + use self::Errno::*; + match errno { + UnknownErrno => "Unknown errno", + EPERM => "Operation not permitted", + ENOENT => "No such file or directory", + ESRCH => "No such process", + EINTR => "Interrupted system call", + EIO => "I/O error", + ENXIO => "No such device or address", + E2BIG => "Argument list too long", + ENOEXEC => "Exec format error", + EBADF => "Bad file number", + ECHILD => "No child processes", + EAGAIN => "Try again", + ENOMEM => "Out of memory", + EACCES => "Permission denied", + EFAULT => "Bad address", + #[cfg(not(target_os = "haiku"))] + ENOTBLK => "Block device required", + EBUSY => "Device or resource busy", + EEXIST => "File exists", + EXDEV => "Cross-device link", + ENODEV => "No such device", + ENOTDIR => "Not a directory", + EISDIR => "Is a directory", + EINVAL => "Invalid argument", + ENFILE => "File table overflow", + EMFILE => "Too many open files", + ENOTTY => "Not a typewriter", + ETXTBSY => "Text file busy", + EFBIG => "File too large", + ENOSPC => "No space left on device", + ESPIPE => "Illegal seek", + EROFS => "Read-only file system", + EMLINK => "Too many links", + EPIPE => "Broken pipe", + EDOM => "Math argument out of domain of func", + ERANGE => "Math result not representable", + EDEADLK => "Resource deadlock would occur", + ENAMETOOLONG => "File name too long", + ENOLCK => "No record locks available", + ENOSYS => "Function not implemented", + ENOTEMPTY => "Directory not empty", + ELOOP => "Too many symbolic links encountered", + ENOMSG => "No message of desired type", + EIDRM => "Identifier removed", + EINPROGRESS => "Operation now in progress", + EALREADY => "Operation already in progress", + ENOTSOCK => "Socket operation on non-socket", + EDESTADDRREQ => "Destination address required", + EMSGSIZE => "Message too long", + EPROTOTYPE => "Protocol wrong type for socket", + ENOPROTOOPT => "Protocol not available", + EPROTONOSUPPORT => "Protocol not supported", + #[cfg(not(target_os = "haiku"))] + ESOCKTNOSUPPORT => "Socket type not supported", + #[cfg(not(target_os = "haiku"))] + EPFNOSUPPORT => "Protocol family not supported", + #[cfg(not(target_os = "haiku"))] + EAFNOSUPPORT => "Address family not supported by protocol", + EADDRINUSE => "Address already in use", + EADDRNOTAVAIL => "Cannot assign requested address", + ENETDOWN => "Network is down", + ENETUNREACH => "Network is unreachable", + ENETRESET => "Network dropped connection because of reset", + ECONNABORTED => "Software caused connection abort", + ECONNRESET => "Connection reset by peer", + ENOBUFS => "No buffer space available", + EISCONN => "Transport endpoint is already connected", + ENOTCONN => "Transport endpoint is not connected", + ESHUTDOWN => "Cannot send after transport endpoint shutdown", + #[cfg(not(target_os = "haiku"))] + ETOOMANYREFS => "Too many references: cannot splice", + ETIMEDOUT => "Connection timed out", + ECONNREFUSED => "Connection refused", + EHOSTDOWN => "Host is down", + EHOSTUNREACH => "No route to host", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ECHRNG => "Channel number out of range", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EL2NSYNC => "Level 2 not synchronized", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EL3HLT => "Level 3 halted", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EL3RST => "Level 3 reset", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ELNRNG => "Link number out of range", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EUNATCH => "Protocol driver not attached", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOCSI => "No CSI structure available", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EL2HLT => "Level 2 halted", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EBADE => "Invalid exchange", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EBADR => "Invalid request descriptor", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EXFULL => "Exchange full", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOANO => "No anode", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EBADRQC => "Invalid request code", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EBADSLT => "Invalid slot", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EBFONT => "Bad font file format", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOSTR => "Device not a stream", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENODATA => "No data available", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ETIME => "Timer expired", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOSR => "Out of streams resources", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENONET => "Machine is not on the network", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOPKG => "Package not installed", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EREMOTE => "Object is remote", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOLINK => "Link has been severed", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EADV => "Advertise error", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ESRMNT => "Srmount error", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ECOMM => "Communication error on send", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EPROTO => "Protocol error", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EMULTIHOP => "Multihop attempted", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EDOTDOT => "RFS specific error", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EBADMSG => "Not a data message", + + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + EBADMSG => "Trying to read unreadable message", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "haiku" + ))] + EOVERFLOW => "Value too large for defined data type", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOTUNIQ => "Name not unique on network", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EBADFD => "File descriptor in bad state", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EREMCHG => "Remote address changed", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ELIBACC => "Can not access a needed shared library", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ELIBBAD => "Accessing a corrupted shared library", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ELIBSCN => ".lib section in a.out corrupted", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ELIBMAX => "Attempting to link in too many shared libraries", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ELIBEXEC => "Cannot exec a shared library directly", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia", + target_os = "openbsd" + ))] + EILSEQ => "Illegal byte sequence", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ERESTART => "Interrupted system call should be restarted", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ESTRPIPE => "Streams pipe error", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EUSERS => "Too many users", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "netbsd", + target_os = "redox" + ))] + EOPNOTSUPP => "Operation not supported on transport endpoint", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + ESTALE => "Stale file handle", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EUCLEAN => "Structure needs cleaning", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + ENOTNAM => "Not a XENIX named type file", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + ENAVAIL => "No XENIX semaphores available", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EISNAM => "Is a named type file", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EREMOTEIO => "Remote I/O error", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EDQUOT => "Quota exceeded", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "openbsd", + target_os = "dragonfly" + ))] + ENOMEDIUM => "No medium found", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "openbsd" + ))] + EMEDIUMTYPE => "Wrong medium type", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia", + target_os = "haiku" + ))] + ECANCELED => "Operation canceled", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + ENOKEY => "Required key not available", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EKEYEXPIRED => "Key has expired", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EKEYREVOKED => "Key has been revoked", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EKEYREJECTED => "Key was rejected by service", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EOWNERDEAD => "Owner died", + + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + EOWNERDEAD => "Process died with lock", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + ENOTRECOVERABLE => "State not recoverable", + + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + ENOTRECOVERABLE => "Lock is not recoverable", + + #[cfg(any( + all(target_os = "linux", not(target_arch = "mips")), + target_os = "fuchsia" + ))] + ERFKILL => "Operation not possible due to RF-kill", + + #[cfg(any( + all(target_os = "linux", not(target_arch = "mips")), + target_os = "fuchsia" + ))] + EHWPOISON => "Memory page has hardware error", + + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + EDOOFUS => "Programming error", + + #[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "redox" + ))] + EMULTIHOP => "Multihop attempted", + + #[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "redox" + ))] + ENOLINK => "Link has been severed", + + #[cfg(target_os = "freebsd")] + ENOTCAPABLE => "Capabilities insufficient", + + #[cfg(target_os = "freebsd")] + ECAPMODE => "Not permitted in capability mode", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + ENEEDAUTH => "Need authenticator", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox", + target_os = "illumos", + target_os = "solaris" + ))] + EOVERFLOW => "Value too large to be stored in data type", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "netbsd", + target_os = "redox", + target_os = "haiku" + ))] + EILSEQ => "Illegal byte sequence", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "haiku" + ))] + ENOATTR => "Attribute not found", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox", + target_os = "haiku" + ))] + EBADMSG => "Bad message", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox", + target_os = "haiku" + ))] + EPROTO => "Protocol error", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd" + ))] + ENOTRECOVERABLE => "State not recoverable", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd" + ))] + EOWNERDEAD => "Previous owner died", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" + ))] + ENOTSUP => "Operation not supported", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EPROCLIM => "Too many processes", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox" + ))] + EUSERS => "Too many users", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox", + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" + ))] + EDQUOT => "Disc quota exceeded", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox", + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" + ))] + ESTALE => "Stale NFS file handle", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox" + ))] + EREMOTE => "Too many levels of remote in path", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EBADRPC => "RPC struct is bad", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + ERPCMISMATCH => "RPC version wrong", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EPROGUNAVAIL => "RPC prog. not avail", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EPROGMISMATCH => "Program version wrong", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EPROCUNAVAIL => "Bad procedure for program", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EFTYPE => "Inappropriate file type or format", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EAUTH => "Authentication error", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox" + ))] + ECANCELED => "Operation canceled", + + #[cfg(any(target_os = "macos", target_os = "ios"))] + EPWROFF => "Device power is off", + + #[cfg(any(target_os = "macos", target_os = "ios"))] + EDEVERR => "Device error, e.g. paper out", + + #[cfg(any(target_os = "macos", target_os = "ios"))] + EBADEXEC => "Bad executable", + + #[cfg(any(target_os = "macos", target_os = "ios"))] + EBADARCH => "Bad CPU type in executable", + + #[cfg(any(target_os = "macos", target_os = "ios"))] + ESHLIBVERS => "Shared library version mismatch", + + #[cfg(any(target_os = "macos", target_os = "ios"))] + EBADMACHO => "Malformed Macho file", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "haiku" + ))] + EMULTIHOP => "Reserved", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "redox" + ))] + ENODATA => "No message available on STREAM", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "haiku" + ))] + ENOLINK => "Reserved", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "redox" + ))] + ENOSR => "No STREAM resources", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "redox" + ))] + ENOSTR => "Not a STREAM", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "redox" + ))] + ETIME => "STREAM ioctl timeout", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "illumos", + target_os = "solaris" + ))] + EOPNOTSUPP => "Operation not supported on socket", + + #[cfg(any(target_os = "macos", target_os = "ios"))] + ENOPOLICY => "No such policy registered", + + #[cfg(any(target_os = "macos", target_os = "ios"))] + EQFULL => "Interface output queue is full", + + #[cfg(target_os = "openbsd")] + EOPNOTSUPP => "Operation not supported", + + #[cfg(target_os = "openbsd")] + EIPSEC => "IPsec processing failure", + + #[cfg(target_os = "dragonfly")] + EASYNC => "Async", + + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + EDEADLOCK => "Resource deadlock would occur", + + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + ELOCKUNMAPPED => "Locked lock was unmapped", + + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + ENOTACTIVE => "Facility is not active", + } +} + +#[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))] +mod consts { + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[repr(i32)] + #[non_exhaustive] + pub enum Errno { + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EAGAIN = libc::EAGAIN, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EDEADLK = libc::EDEADLK, + ENAMETOOLONG = libc::ENAMETOOLONG, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + ENOTEMPTY = libc::ENOTEMPTY, + ELOOP = libc::ELOOP, + ENOMSG = libc::ENOMSG, + EIDRM = libc::EIDRM, + ECHRNG = libc::ECHRNG, + EL2NSYNC = libc::EL2NSYNC, + EL3HLT = libc::EL3HLT, + EL3RST = libc::EL3RST, + ELNRNG = libc::ELNRNG, + EUNATCH = libc::EUNATCH, + ENOCSI = libc::ENOCSI, + EL2HLT = libc::EL2HLT, + EBADE = libc::EBADE, + EBADR = libc::EBADR, + EXFULL = libc::EXFULL, + ENOANO = libc::ENOANO, + EBADRQC = libc::EBADRQC, + EBADSLT = libc::EBADSLT, + EBFONT = libc::EBFONT, + ENOSTR = libc::ENOSTR, + ENODATA = libc::ENODATA, + ETIME = libc::ETIME, + ENOSR = libc::ENOSR, + ENONET = libc::ENONET, + ENOPKG = libc::ENOPKG, + EREMOTE = libc::EREMOTE, + ENOLINK = libc::ENOLINK, + EADV = libc::EADV, + ESRMNT = libc::ESRMNT, + ECOMM = libc::ECOMM, + EPROTO = libc::EPROTO, + EMULTIHOP = libc::EMULTIHOP, + EDOTDOT = libc::EDOTDOT, + EBADMSG = libc::EBADMSG, + EOVERFLOW = libc::EOVERFLOW, + ENOTUNIQ = libc::ENOTUNIQ, + EBADFD = libc::EBADFD, + EREMCHG = libc::EREMCHG, + ELIBACC = libc::ELIBACC, + ELIBBAD = libc::ELIBBAD, + ELIBSCN = libc::ELIBSCN, + ELIBMAX = libc::ELIBMAX, + ELIBEXEC = libc::ELIBEXEC, + EILSEQ = libc::EILSEQ, + ERESTART = libc::ERESTART, + ESTRPIPE = libc::ESTRPIPE, + EUSERS = libc::EUSERS, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, + EPROTONOSUPPORT = libc::EPROTONOSUPPORT, + ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, + EOPNOTSUPP = libc::EOPNOTSUPP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + EALREADY = libc::EALREADY, + EINPROGRESS = libc::EINPROGRESS, + ESTALE = libc::ESTALE, + EUCLEAN = libc::EUCLEAN, + ENOTNAM = libc::ENOTNAM, + ENAVAIL = libc::ENAVAIL, + EISNAM = libc::EISNAM, + EREMOTEIO = libc::EREMOTEIO, + EDQUOT = libc::EDQUOT, + ENOMEDIUM = libc::ENOMEDIUM, + EMEDIUMTYPE = libc::EMEDIUMTYPE, + ECANCELED = libc::ECANCELED, + ENOKEY = libc::ENOKEY, + EKEYEXPIRED = libc::EKEYEXPIRED, + EKEYREVOKED = libc::EKEYREVOKED, + EKEYREJECTED = libc::EKEYREJECTED, + EOWNERDEAD = libc::EOWNERDEAD, + ENOTRECOVERABLE = libc::ENOTRECOVERABLE, + #[cfg(not(any(target_os = "android", target_arch = "mips")))] + ERFKILL = libc::ERFKILL, + #[cfg(not(any(target_os = "android", target_arch = "mips")))] + EHWPOISON = libc::EHWPOISON, + } + + impl Errno { + pub const EWOULDBLOCK: Errno = Errno::EAGAIN; + pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const ENOTSUP: Errno = Errno::EOPNOTSUPP; + } + + pub const fn from_i32(e: i32) -> Errno { + use self::Errno::*; + + match e { + libc::EPERM => EPERM, + libc::ENOENT => ENOENT, + libc::ESRCH => ESRCH, + libc::EINTR => EINTR, + libc::EIO => EIO, + libc::ENXIO => ENXIO, + libc::E2BIG => E2BIG, + libc::ENOEXEC => ENOEXEC, + libc::EBADF => EBADF, + libc::ECHILD => ECHILD, + libc::EAGAIN => EAGAIN, + libc::ENOMEM => ENOMEM, + libc::EACCES => EACCES, + libc::EFAULT => EFAULT, + libc::ENOTBLK => ENOTBLK, + libc::EBUSY => EBUSY, + libc::EEXIST => EEXIST, + libc::EXDEV => EXDEV, + libc::ENODEV => ENODEV, + libc::ENOTDIR => ENOTDIR, + libc::EISDIR => EISDIR, + libc::EINVAL => EINVAL, + libc::ENFILE => ENFILE, + libc::EMFILE => EMFILE, + libc::ENOTTY => ENOTTY, + libc::ETXTBSY => ETXTBSY, + libc::EFBIG => EFBIG, + libc::ENOSPC => ENOSPC, + libc::ESPIPE => ESPIPE, + libc::EROFS => EROFS, + libc::EMLINK => EMLINK, + libc::EPIPE => EPIPE, + libc::EDOM => EDOM, + libc::ERANGE => ERANGE, + libc::EDEADLK => EDEADLK, + libc::ENAMETOOLONG => ENAMETOOLONG, + libc::ENOLCK => ENOLCK, + libc::ENOSYS => ENOSYS, + libc::ENOTEMPTY => ENOTEMPTY, + libc::ELOOP => ELOOP, + libc::ENOMSG => ENOMSG, + libc::EIDRM => EIDRM, + libc::ECHRNG => ECHRNG, + libc::EL2NSYNC => EL2NSYNC, + libc::EL3HLT => EL3HLT, + libc::EL3RST => EL3RST, + libc::ELNRNG => ELNRNG, + libc::EUNATCH => EUNATCH, + libc::ENOCSI => ENOCSI, + libc::EL2HLT => EL2HLT, + libc::EBADE => EBADE, + libc::EBADR => EBADR, + libc::EXFULL => EXFULL, + libc::ENOANO => ENOANO, + libc::EBADRQC => EBADRQC, + libc::EBADSLT => EBADSLT, + libc::EBFONT => EBFONT, + libc::ENOSTR => ENOSTR, + libc::ENODATA => ENODATA, + libc::ETIME => ETIME, + libc::ENOSR => ENOSR, + libc::ENONET => ENONET, + libc::ENOPKG => ENOPKG, + libc::EREMOTE => EREMOTE, + libc::ENOLINK => ENOLINK, + libc::EADV => EADV, + libc::ESRMNT => ESRMNT, + libc::ECOMM => ECOMM, + libc::EPROTO => EPROTO, + libc::EMULTIHOP => EMULTIHOP, + libc::EDOTDOT => EDOTDOT, + libc::EBADMSG => EBADMSG, + libc::EOVERFLOW => EOVERFLOW, + libc::ENOTUNIQ => ENOTUNIQ, + libc::EBADFD => EBADFD, + libc::EREMCHG => EREMCHG, + libc::ELIBACC => ELIBACC, + libc::ELIBBAD => ELIBBAD, + libc::ELIBSCN => ELIBSCN, + libc::ELIBMAX => ELIBMAX, + libc::ELIBEXEC => ELIBEXEC, + libc::EILSEQ => EILSEQ, + libc::ERESTART => ERESTART, + libc::ESTRPIPE => ESTRPIPE, + libc::EUSERS => EUSERS, + libc::ENOTSOCK => ENOTSOCK, + libc::EDESTADDRREQ => EDESTADDRREQ, + libc::EMSGSIZE => EMSGSIZE, + libc::EPROTOTYPE => EPROTOTYPE, + libc::ENOPROTOOPT => ENOPROTOOPT, + libc::EPROTONOSUPPORT => EPROTONOSUPPORT, + libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, + libc::EOPNOTSUPP => EOPNOTSUPP, + libc::EPFNOSUPPORT => EPFNOSUPPORT, + libc::EAFNOSUPPORT => EAFNOSUPPORT, + libc::EADDRINUSE => EADDRINUSE, + libc::EADDRNOTAVAIL => EADDRNOTAVAIL, + libc::ENETDOWN => ENETDOWN, + libc::ENETUNREACH => ENETUNREACH, + libc::ENETRESET => ENETRESET, + libc::ECONNABORTED => ECONNABORTED, + libc::ECONNRESET => ECONNRESET, + libc::ENOBUFS => ENOBUFS, + libc::EISCONN => EISCONN, + libc::ENOTCONN => ENOTCONN, + libc::ESHUTDOWN => ESHUTDOWN, + libc::ETOOMANYREFS => ETOOMANYREFS, + libc::ETIMEDOUT => ETIMEDOUT, + libc::ECONNREFUSED => ECONNREFUSED, + libc::EHOSTDOWN => EHOSTDOWN, + libc::EHOSTUNREACH => EHOSTUNREACH, + libc::EALREADY => EALREADY, + libc::EINPROGRESS => EINPROGRESS, + libc::ESTALE => ESTALE, + libc::EUCLEAN => EUCLEAN, + libc::ENOTNAM => ENOTNAM, + libc::ENAVAIL => ENAVAIL, + libc::EISNAM => EISNAM, + libc::EREMOTEIO => EREMOTEIO, + libc::EDQUOT => EDQUOT, + libc::ENOMEDIUM => ENOMEDIUM, + libc::EMEDIUMTYPE => EMEDIUMTYPE, + libc::ECANCELED => ECANCELED, + libc::ENOKEY => ENOKEY, + libc::EKEYEXPIRED => EKEYEXPIRED, + libc::EKEYREVOKED => EKEYREVOKED, + libc::EKEYREJECTED => EKEYREJECTED, + libc::EOWNERDEAD => EOWNERDEAD, + libc::ENOTRECOVERABLE => ENOTRECOVERABLE, + #[cfg(not(any(target_os = "android", target_arch = "mips")))] + libc::ERFKILL => ERFKILL, + #[cfg(not(any(target_os = "android", target_arch = "mips")))] + libc::EHWPOISON => EHWPOISON, + _ => UnknownErrno, + } + } +} + +#[cfg(any(target_os = "macos", target_os = "ios"))] +mod consts { + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[repr(i32)] + #[non_exhaustive] + pub enum Errno { + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, + EPROTONOSUPPORT = libc::EPROTONOSUPPORT, + ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, + ENOTSUP = libc::ENOTSUP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EPROCLIM = libc::EPROCLIM, + EUSERS = libc::EUSERS, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + EREMOTE = libc::EREMOTE, + EBADRPC = libc::EBADRPC, + ERPCMISMATCH = libc::ERPCMISMATCH, + EPROGUNAVAIL = libc::EPROGUNAVAIL, + EPROGMISMATCH = libc::EPROGMISMATCH, + EPROCUNAVAIL = libc::EPROCUNAVAIL, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EFTYPE = libc::EFTYPE, + EAUTH = libc::EAUTH, + ENEEDAUTH = libc::ENEEDAUTH, + EPWROFF = libc::EPWROFF, + EDEVERR = libc::EDEVERR, + EOVERFLOW = libc::EOVERFLOW, + EBADEXEC = libc::EBADEXEC, + EBADARCH = libc::EBADARCH, + ESHLIBVERS = libc::ESHLIBVERS, + EBADMACHO = libc::EBADMACHO, + ECANCELED = libc::ECANCELED, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + EILSEQ = libc::EILSEQ, + ENOATTR = libc::ENOATTR, + EBADMSG = libc::EBADMSG, + EMULTIHOP = libc::EMULTIHOP, + ENODATA = libc::ENODATA, + ENOLINK = libc::ENOLINK, + ENOSR = libc::ENOSR, + ENOSTR = libc::ENOSTR, + EPROTO = libc::EPROTO, + ETIME = libc::ETIME, + EOPNOTSUPP = libc::EOPNOTSUPP, + ENOPOLICY = libc::ENOPOLICY, + ENOTRECOVERABLE = libc::ENOTRECOVERABLE, + EOWNERDEAD = libc::EOWNERDEAD, + EQFULL = libc::EQFULL, + } + + impl Errno { + pub const ELAST: Errno = Errno::EQFULL; + pub const EWOULDBLOCK: Errno = Errno::EAGAIN; + pub const EDEADLOCK: Errno = Errno::EDEADLK; + } + + pub const fn from_i32(e: i32) -> Errno { + use self::Errno::*; + + match e { + libc::EPERM => EPERM, + libc::ENOENT => ENOENT, + libc::ESRCH => ESRCH, + libc::EINTR => EINTR, + libc::EIO => EIO, + libc::ENXIO => ENXIO, + libc::E2BIG => E2BIG, + libc::ENOEXEC => ENOEXEC, + libc::EBADF => EBADF, + libc::ECHILD => ECHILD, + libc::EDEADLK => EDEADLK, + libc::ENOMEM => ENOMEM, + libc::EACCES => EACCES, + libc::EFAULT => EFAULT, + libc::ENOTBLK => ENOTBLK, + libc::EBUSY => EBUSY, + libc::EEXIST => EEXIST, + libc::EXDEV => EXDEV, + libc::ENODEV => ENODEV, + libc::ENOTDIR => ENOTDIR, + libc::EISDIR => EISDIR, + libc::EINVAL => EINVAL, + libc::ENFILE => ENFILE, + libc::EMFILE => EMFILE, + libc::ENOTTY => ENOTTY, + libc::ETXTBSY => ETXTBSY, + libc::EFBIG => EFBIG, + libc::ENOSPC => ENOSPC, + libc::ESPIPE => ESPIPE, + libc::EROFS => EROFS, + libc::EMLINK => EMLINK, + libc::EPIPE => EPIPE, + libc::EDOM => EDOM, + libc::ERANGE => ERANGE, + libc::EAGAIN => EAGAIN, + libc::EINPROGRESS => EINPROGRESS, + libc::EALREADY => EALREADY, + libc::ENOTSOCK => ENOTSOCK, + libc::EDESTADDRREQ => EDESTADDRREQ, + libc::EMSGSIZE => EMSGSIZE, + libc::EPROTOTYPE => EPROTOTYPE, + libc::ENOPROTOOPT => ENOPROTOOPT, + libc::EPROTONOSUPPORT => EPROTONOSUPPORT, + libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, + libc::ENOTSUP => ENOTSUP, + libc::EPFNOSUPPORT => EPFNOSUPPORT, + libc::EAFNOSUPPORT => EAFNOSUPPORT, + libc::EADDRINUSE => EADDRINUSE, + libc::EADDRNOTAVAIL => EADDRNOTAVAIL, + libc::ENETDOWN => ENETDOWN, + libc::ENETUNREACH => ENETUNREACH, + libc::ENETRESET => ENETRESET, + libc::ECONNABORTED => ECONNABORTED, + libc::ECONNRESET => ECONNRESET, + libc::ENOBUFS => ENOBUFS, + libc::EISCONN => EISCONN, + libc::ENOTCONN => ENOTCONN, + libc::ESHUTDOWN => ESHUTDOWN, + libc::ETOOMANYREFS => ETOOMANYREFS, + libc::ETIMEDOUT => ETIMEDOUT, + libc::ECONNREFUSED => ECONNREFUSED, + libc::ELOOP => ELOOP, + libc::ENAMETOOLONG => ENAMETOOLONG, + libc::EHOSTDOWN => EHOSTDOWN, + libc::EHOSTUNREACH => EHOSTUNREACH, + libc::ENOTEMPTY => ENOTEMPTY, + libc::EPROCLIM => EPROCLIM, + libc::EUSERS => EUSERS, + libc::EDQUOT => EDQUOT, + libc::ESTALE => ESTALE, + libc::EREMOTE => EREMOTE, + libc::EBADRPC => EBADRPC, + libc::ERPCMISMATCH => ERPCMISMATCH, + libc::EPROGUNAVAIL => EPROGUNAVAIL, + libc::EPROGMISMATCH => EPROGMISMATCH, + libc::EPROCUNAVAIL => EPROCUNAVAIL, + libc::ENOLCK => ENOLCK, + libc::ENOSYS => ENOSYS, + libc::EFTYPE => EFTYPE, + libc::EAUTH => EAUTH, + libc::ENEEDAUTH => ENEEDAUTH, + libc::EPWROFF => EPWROFF, + libc::EDEVERR => EDEVERR, + libc::EOVERFLOW => EOVERFLOW, + libc::EBADEXEC => EBADEXEC, + libc::EBADARCH => EBADARCH, + libc::ESHLIBVERS => ESHLIBVERS, + libc::EBADMACHO => EBADMACHO, + libc::ECANCELED => ECANCELED, + libc::EIDRM => EIDRM, + libc::ENOMSG => ENOMSG, + libc::EILSEQ => EILSEQ, + libc::ENOATTR => ENOATTR, + libc::EBADMSG => EBADMSG, + libc::EMULTIHOP => EMULTIHOP, + libc::ENODATA => ENODATA, + libc::ENOLINK => ENOLINK, + libc::ENOSR => ENOSR, + libc::ENOSTR => ENOSTR, + libc::EPROTO => EPROTO, + libc::ETIME => ETIME, + libc::EOPNOTSUPP => EOPNOTSUPP, + libc::ENOPOLICY => ENOPOLICY, + libc::ENOTRECOVERABLE => ENOTRECOVERABLE, + libc::EOWNERDEAD => EOWNERDEAD, + libc::EQFULL => EQFULL, + _ => UnknownErrno, + } + } +} + +#[cfg(target_os = "freebsd")] +mod consts { + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[repr(i32)] + #[non_exhaustive] + pub enum Errno { + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, + EPROTONOSUPPORT = libc::EPROTONOSUPPORT, + ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, + ENOTSUP = libc::ENOTSUP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EPROCLIM = libc::EPROCLIM, + EUSERS = libc::EUSERS, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + EREMOTE = libc::EREMOTE, + EBADRPC = libc::EBADRPC, + ERPCMISMATCH = libc::ERPCMISMATCH, + EPROGUNAVAIL = libc::EPROGUNAVAIL, + EPROGMISMATCH = libc::EPROGMISMATCH, + EPROCUNAVAIL = libc::EPROCUNAVAIL, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EFTYPE = libc::EFTYPE, + EAUTH = libc::EAUTH, + ENEEDAUTH = libc::ENEEDAUTH, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + EOVERFLOW = libc::EOVERFLOW, + ECANCELED = libc::ECANCELED, + EILSEQ = libc::EILSEQ, + ENOATTR = libc::ENOATTR, + EDOOFUS = libc::EDOOFUS, + EBADMSG = libc::EBADMSG, + EMULTIHOP = libc::EMULTIHOP, + ENOLINK = libc::ENOLINK, + EPROTO = libc::EPROTO, + ENOTCAPABLE = libc::ENOTCAPABLE, + ECAPMODE = libc::ECAPMODE, + ENOTRECOVERABLE = libc::ENOTRECOVERABLE, + EOWNERDEAD = libc::EOWNERDEAD, + } + + impl Errno { + pub const ELAST: Errno = Errno::EOWNERDEAD; + pub const EWOULDBLOCK: Errno = Errno::EAGAIN; + pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; + } + + pub const fn from_i32(e: i32) -> Errno { + use self::Errno::*; + + match e { + libc::EPERM => EPERM, + libc::ENOENT => ENOENT, + libc::ESRCH => ESRCH, + libc::EINTR => EINTR, + libc::EIO => EIO, + libc::ENXIO => ENXIO, + libc::E2BIG => E2BIG, + libc::ENOEXEC => ENOEXEC, + libc::EBADF => EBADF, + libc::ECHILD => ECHILD, + libc::EDEADLK => EDEADLK, + libc::ENOMEM => ENOMEM, + libc::EACCES => EACCES, + libc::EFAULT => EFAULT, + libc::ENOTBLK => ENOTBLK, + libc::EBUSY => EBUSY, + libc::EEXIST => EEXIST, + libc::EXDEV => EXDEV, + libc::ENODEV => ENODEV, + libc::ENOTDIR => ENOTDIR, + libc::EISDIR => EISDIR, + libc::EINVAL => EINVAL, + libc::ENFILE => ENFILE, + libc::EMFILE => EMFILE, + libc::ENOTTY => ENOTTY, + libc::ETXTBSY => ETXTBSY, + libc::EFBIG => EFBIG, + libc::ENOSPC => ENOSPC, + libc::ESPIPE => ESPIPE, + libc::EROFS => EROFS, + libc::EMLINK => EMLINK, + libc::EPIPE => EPIPE, + libc::EDOM => EDOM, + libc::ERANGE => ERANGE, + libc::EAGAIN => EAGAIN, + libc::EINPROGRESS => EINPROGRESS, + libc::EALREADY => EALREADY, + libc::ENOTSOCK => ENOTSOCK, + libc::EDESTADDRREQ => EDESTADDRREQ, + libc::EMSGSIZE => EMSGSIZE, + libc::EPROTOTYPE => EPROTOTYPE, + libc::ENOPROTOOPT => ENOPROTOOPT, + libc::EPROTONOSUPPORT => EPROTONOSUPPORT, + libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, + libc::ENOTSUP => ENOTSUP, + libc::EPFNOSUPPORT => EPFNOSUPPORT, + libc::EAFNOSUPPORT => EAFNOSUPPORT, + libc::EADDRINUSE => EADDRINUSE, + libc::EADDRNOTAVAIL => EADDRNOTAVAIL, + libc::ENETDOWN => ENETDOWN, + libc::ENETUNREACH => ENETUNREACH, + libc::ENETRESET => ENETRESET, + libc::ECONNABORTED => ECONNABORTED, + libc::ECONNRESET => ECONNRESET, + libc::ENOBUFS => ENOBUFS, + libc::EISCONN => EISCONN, + libc::ENOTCONN => ENOTCONN, + libc::ESHUTDOWN => ESHUTDOWN, + libc::ETOOMANYREFS => ETOOMANYREFS, + libc::ETIMEDOUT => ETIMEDOUT, + libc::ECONNREFUSED => ECONNREFUSED, + libc::ELOOP => ELOOP, + libc::ENAMETOOLONG => ENAMETOOLONG, + libc::EHOSTDOWN => EHOSTDOWN, + libc::EHOSTUNREACH => EHOSTUNREACH, + libc::ENOTEMPTY => ENOTEMPTY, + libc::EPROCLIM => EPROCLIM, + libc::EUSERS => EUSERS, + libc::EDQUOT => EDQUOT, + libc::ESTALE => ESTALE, + libc::EREMOTE => EREMOTE, + libc::EBADRPC => EBADRPC, + libc::ERPCMISMATCH => ERPCMISMATCH, + libc::EPROGUNAVAIL => EPROGUNAVAIL, + libc::EPROGMISMATCH => EPROGMISMATCH, + libc::EPROCUNAVAIL => EPROCUNAVAIL, + libc::ENOLCK => ENOLCK, + libc::ENOSYS => ENOSYS, + libc::EFTYPE => EFTYPE, + libc::EAUTH => EAUTH, + libc::ENEEDAUTH => ENEEDAUTH, + libc::EIDRM => EIDRM, + libc::ENOMSG => ENOMSG, + libc::EOVERFLOW => EOVERFLOW, + libc::ECANCELED => ECANCELED, + libc::EILSEQ => EILSEQ, + libc::ENOATTR => ENOATTR, + libc::EDOOFUS => EDOOFUS, + libc::EBADMSG => EBADMSG, + libc::EMULTIHOP => EMULTIHOP, + libc::ENOLINK => ENOLINK, + libc::EPROTO => EPROTO, + libc::ENOTCAPABLE => ENOTCAPABLE, + libc::ECAPMODE => ECAPMODE, + libc::ENOTRECOVERABLE => ENOTRECOVERABLE, + libc::EOWNERDEAD => EOWNERDEAD, + _ => UnknownErrno, + } + } +} + +#[cfg(target_os = "dragonfly")] +mod consts { + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[repr(i32)] + #[non_exhaustive] + pub enum Errno { + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, + EPROTONOSUPPORT = libc::EPROTONOSUPPORT, + ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, + ENOTSUP = libc::ENOTSUP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EPROCLIM = libc::EPROCLIM, + EUSERS = libc::EUSERS, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + EREMOTE = libc::EREMOTE, + EBADRPC = libc::EBADRPC, + ERPCMISMATCH = libc::ERPCMISMATCH, + EPROGUNAVAIL = libc::EPROGUNAVAIL, + EPROGMISMATCH = libc::EPROGMISMATCH, + EPROCUNAVAIL = libc::EPROCUNAVAIL, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EFTYPE = libc::EFTYPE, + EAUTH = libc::EAUTH, + ENEEDAUTH = libc::ENEEDAUTH, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + EOVERFLOW = libc::EOVERFLOW, + ECANCELED = libc::ECANCELED, + EILSEQ = libc::EILSEQ, + ENOATTR = libc::ENOATTR, + EDOOFUS = libc::EDOOFUS, + EBADMSG = libc::EBADMSG, + EMULTIHOP = libc::EMULTIHOP, + ENOLINK = libc::ENOLINK, + EPROTO = libc::EPROTO, + ENOMEDIUM = libc::ENOMEDIUM, + ENOTRECOVERABLE = libc::ENOTRECOVERABLE, + EOWNERDEAD = libc::EOWNERDEAD, + EASYNC = libc::EASYNC, + } + + impl Errno { + pub const ELAST: Errno = Errno::EASYNC; + pub const EWOULDBLOCK: Errno = Errno::EAGAIN; + pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; + } + + pub const fn from_i32(e: i32) -> Errno { + use self::Errno::*; + + match e { + libc::EPERM => EPERM, + libc::ENOENT => ENOENT, + libc::ESRCH => ESRCH, + libc::EINTR => EINTR, + libc::EIO => EIO, + libc::ENXIO => ENXIO, + libc::E2BIG => E2BIG, + libc::ENOEXEC => ENOEXEC, + libc::EBADF => EBADF, + libc::ECHILD => ECHILD, + libc::EDEADLK => EDEADLK, + libc::ENOMEM => ENOMEM, + libc::EACCES => EACCES, + libc::EFAULT => EFAULT, + libc::ENOTBLK => ENOTBLK, + libc::EBUSY => EBUSY, + libc::EEXIST => EEXIST, + libc::EXDEV => EXDEV, + libc::ENODEV => ENODEV, + libc::ENOTDIR => ENOTDIR, + libc::EISDIR => EISDIR, + libc::EINVAL => EINVAL, + libc::ENFILE => ENFILE, + libc::EMFILE => EMFILE, + libc::ENOTTY => ENOTTY, + libc::ETXTBSY => ETXTBSY, + libc::EFBIG => EFBIG, + libc::ENOSPC => ENOSPC, + libc::ESPIPE => ESPIPE, + libc::EROFS => EROFS, + libc::EMLINK => EMLINK, + libc::EPIPE => EPIPE, + libc::EDOM => EDOM, + libc::ERANGE => ERANGE, + libc::EAGAIN => EAGAIN, + libc::EINPROGRESS => EINPROGRESS, + libc::EALREADY => EALREADY, + libc::ENOTSOCK => ENOTSOCK, + libc::EDESTADDRREQ => EDESTADDRREQ, + libc::EMSGSIZE => EMSGSIZE, + libc::EPROTOTYPE => EPROTOTYPE, + libc::ENOPROTOOPT => ENOPROTOOPT, + libc::EPROTONOSUPPORT => EPROTONOSUPPORT, + libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, + libc::ENOTSUP => ENOTSUP, + libc::EPFNOSUPPORT => EPFNOSUPPORT, + libc::EAFNOSUPPORT => EAFNOSUPPORT, + libc::EADDRINUSE => EADDRINUSE, + libc::EADDRNOTAVAIL => EADDRNOTAVAIL, + libc::ENETDOWN => ENETDOWN, + libc::ENETUNREACH => ENETUNREACH, + libc::ENETRESET => ENETRESET, + libc::ECONNABORTED => ECONNABORTED, + libc::ECONNRESET => ECONNRESET, + libc::ENOBUFS => ENOBUFS, + libc::EISCONN => EISCONN, + libc::ENOTCONN => ENOTCONN, + libc::ESHUTDOWN => ESHUTDOWN, + libc::ETOOMANYREFS => ETOOMANYREFS, + libc::ETIMEDOUT => ETIMEDOUT, + libc::ECONNREFUSED => ECONNREFUSED, + libc::ELOOP => ELOOP, + libc::ENAMETOOLONG => ENAMETOOLONG, + libc::EHOSTDOWN => EHOSTDOWN, + libc::EHOSTUNREACH => EHOSTUNREACH, + libc::ENOTEMPTY => ENOTEMPTY, + libc::EPROCLIM => EPROCLIM, + libc::EUSERS => EUSERS, + libc::EDQUOT => EDQUOT, + libc::ESTALE => ESTALE, + libc::EREMOTE => EREMOTE, + libc::EBADRPC => EBADRPC, + libc::ERPCMISMATCH => ERPCMISMATCH, + libc::EPROGUNAVAIL => EPROGUNAVAIL, + libc::EPROGMISMATCH => EPROGMISMATCH, + libc::EPROCUNAVAIL => EPROCUNAVAIL, + libc::ENOLCK => ENOLCK, + libc::ENOSYS => ENOSYS, + libc::EFTYPE => EFTYPE, + libc::EAUTH => EAUTH, + libc::ENEEDAUTH => ENEEDAUTH, + libc::EIDRM => EIDRM, + libc::ENOMSG => ENOMSG, + libc::EOVERFLOW => EOVERFLOW, + libc::ECANCELED => ECANCELED, + libc::EILSEQ => EILSEQ, + libc::ENOATTR => ENOATTR, + libc::EDOOFUS => EDOOFUS, + libc::EBADMSG => EBADMSG, + libc::EMULTIHOP => EMULTIHOP, + libc::ENOLINK => ENOLINK, + libc::EPROTO => EPROTO, + libc::ENOMEDIUM => ENOMEDIUM, + libc::EASYNC => EASYNC, + _ => UnknownErrno, + } + } +} + +#[cfg(target_os = "openbsd")] +mod consts { + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[repr(i32)] + #[non_exhaustive] + pub enum Errno { + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, + EPROTONOSUPPORT = libc::EPROTONOSUPPORT, + ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, + EOPNOTSUPP = libc::EOPNOTSUPP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EPROCLIM = libc::EPROCLIM, + EUSERS = libc::EUSERS, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + EREMOTE = libc::EREMOTE, + EBADRPC = libc::EBADRPC, + ERPCMISMATCH = libc::ERPCMISMATCH, + EPROGUNAVAIL = libc::EPROGUNAVAIL, + EPROGMISMATCH = libc::EPROGMISMATCH, + EPROCUNAVAIL = libc::EPROCUNAVAIL, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EFTYPE = libc::EFTYPE, + EAUTH = libc::EAUTH, + ENEEDAUTH = libc::ENEEDAUTH, + EIPSEC = libc::EIPSEC, + ENOATTR = libc::ENOATTR, + EILSEQ = libc::EILSEQ, + ENOMEDIUM = libc::ENOMEDIUM, + EMEDIUMTYPE = libc::EMEDIUMTYPE, + EOVERFLOW = libc::EOVERFLOW, + ECANCELED = libc::ECANCELED, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + ENOTSUP = libc::ENOTSUP, + EBADMSG = libc::EBADMSG, + ENOTRECOVERABLE = libc::ENOTRECOVERABLE, + EOWNERDEAD = libc::EOWNERDEAD, + EPROTO = libc::EPROTO, + } + + impl Errno { + pub const ELAST: Errno = Errno::ENOTSUP; + pub const EWOULDBLOCK: Errno = Errno::EAGAIN; + } + + pub const fn from_i32(e: i32) -> Errno { + use self::Errno::*; + + match e { + libc::EPERM => EPERM, + libc::ENOENT => ENOENT, + libc::ESRCH => ESRCH, + libc::EINTR => EINTR, + libc::EIO => EIO, + libc::ENXIO => ENXIO, + libc::E2BIG => E2BIG, + libc::ENOEXEC => ENOEXEC, + libc::EBADF => EBADF, + libc::ECHILD => ECHILD, + libc::EDEADLK => EDEADLK, + libc::ENOMEM => ENOMEM, + libc::EACCES => EACCES, + libc::EFAULT => EFAULT, + libc::ENOTBLK => ENOTBLK, + libc::EBUSY => EBUSY, + libc::EEXIST => EEXIST, + libc::EXDEV => EXDEV, + libc::ENODEV => ENODEV, + libc::ENOTDIR => ENOTDIR, + libc::EISDIR => EISDIR, + libc::EINVAL => EINVAL, + libc::ENFILE => ENFILE, + libc::EMFILE => EMFILE, + libc::ENOTTY => ENOTTY, + libc::ETXTBSY => ETXTBSY, + libc::EFBIG => EFBIG, + libc::ENOSPC => ENOSPC, + libc::ESPIPE => ESPIPE, + libc::EROFS => EROFS, + libc::EMLINK => EMLINK, + libc::EPIPE => EPIPE, + libc::EDOM => EDOM, + libc::ERANGE => ERANGE, + libc::EAGAIN => EAGAIN, + libc::EINPROGRESS => EINPROGRESS, + libc::EALREADY => EALREADY, + libc::ENOTSOCK => ENOTSOCK, + libc::EDESTADDRREQ => EDESTADDRREQ, + libc::EMSGSIZE => EMSGSIZE, + libc::EPROTOTYPE => EPROTOTYPE, + libc::ENOPROTOOPT => ENOPROTOOPT, + libc::EPROTONOSUPPORT => EPROTONOSUPPORT, + libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, + libc::EOPNOTSUPP => EOPNOTSUPP, + libc::EPFNOSUPPORT => EPFNOSUPPORT, + libc::EAFNOSUPPORT => EAFNOSUPPORT, + libc::EADDRINUSE => EADDRINUSE, + libc::EADDRNOTAVAIL => EADDRNOTAVAIL, + libc::ENETDOWN => ENETDOWN, + libc::ENETUNREACH => ENETUNREACH, + libc::ENETRESET => ENETRESET, + libc::ECONNABORTED => ECONNABORTED, + libc::ECONNRESET => ECONNRESET, + libc::ENOBUFS => ENOBUFS, + libc::EISCONN => EISCONN, + libc::ENOTCONN => ENOTCONN, + libc::ESHUTDOWN => ESHUTDOWN, + libc::ETOOMANYREFS => ETOOMANYREFS, + libc::ETIMEDOUT => ETIMEDOUT, + libc::ECONNREFUSED => ECONNREFUSED, + libc::ELOOP => ELOOP, + libc::ENAMETOOLONG => ENAMETOOLONG, + libc::EHOSTDOWN => EHOSTDOWN, + libc::EHOSTUNREACH => EHOSTUNREACH, + libc::ENOTEMPTY => ENOTEMPTY, + libc::EPROCLIM => EPROCLIM, + libc::EUSERS => EUSERS, + libc::EDQUOT => EDQUOT, + libc::ESTALE => ESTALE, + libc::EREMOTE => EREMOTE, + libc::EBADRPC => EBADRPC, + libc::ERPCMISMATCH => ERPCMISMATCH, + libc::EPROGUNAVAIL => EPROGUNAVAIL, + libc::EPROGMISMATCH => EPROGMISMATCH, + libc::EPROCUNAVAIL => EPROCUNAVAIL, + libc::ENOLCK => ENOLCK, + libc::ENOSYS => ENOSYS, + libc::EFTYPE => EFTYPE, + libc::EAUTH => EAUTH, + libc::ENEEDAUTH => ENEEDAUTH, + libc::EIPSEC => EIPSEC, + libc::ENOATTR => ENOATTR, + libc::EILSEQ => EILSEQ, + libc::ENOMEDIUM => ENOMEDIUM, + libc::EMEDIUMTYPE => EMEDIUMTYPE, + libc::EOVERFLOW => EOVERFLOW, + libc::ECANCELED => ECANCELED, + libc::EIDRM => EIDRM, + libc::ENOMSG => ENOMSG, + libc::ENOTSUP => ENOTSUP, + libc::EBADMSG => EBADMSG, + libc::ENOTRECOVERABLE => ENOTRECOVERABLE, + libc::EOWNERDEAD => EOWNERDEAD, + libc::EPROTO => EPROTO, + _ => UnknownErrno, + } + } +} + +#[cfg(target_os = "netbsd")] +mod consts { + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[repr(i32)] + #[non_exhaustive] + pub enum Errno { + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, + EPROTONOSUPPORT = libc::EPROTONOSUPPORT, + ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, + EOPNOTSUPP = libc::EOPNOTSUPP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EPROCLIM = libc::EPROCLIM, + EUSERS = libc::EUSERS, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + EREMOTE = libc::EREMOTE, + EBADRPC = libc::EBADRPC, + ERPCMISMATCH = libc::ERPCMISMATCH, + EPROGUNAVAIL = libc::EPROGUNAVAIL, + EPROGMISMATCH = libc::EPROGMISMATCH, + EPROCUNAVAIL = libc::EPROCUNAVAIL, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EFTYPE = libc::EFTYPE, + EAUTH = libc::EAUTH, + ENEEDAUTH = libc::ENEEDAUTH, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + EOVERFLOW = libc::EOVERFLOW, + EILSEQ = libc::EILSEQ, + ENOTSUP = libc::ENOTSUP, + ECANCELED = libc::ECANCELED, + EBADMSG = libc::EBADMSG, + ENODATA = libc::ENODATA, + ENOSR = libc::ENOSR, + ENOSTR = libc::ENOSTR, + ETIME = libc::ETIME, + ENOATTR = libc::ENOATTR, + EMULTIHOP = libc::EMULTIHOP, + ENOLINK = libc::ENOLINK, + EPROTO = libc::EPROTO, + } + + impl Errno { + pub const ELAST: Errno = Errno::ENOTSUP; + pub const EWOULDBLOCK: Errno = Errno::EAGAIN; + } + + pub const fn from_i32(e: i32) -> Errno { + use self::Errno::*; + + match e { + libc::EPERM => EPERM, + libc::ENOENT => ENOENT, + libc::ESRCH => ESRCH, + libc::EINTR => EINTR, + libc::EIO => EIO, + libc::ENXIO => ENXIO, + libc::E2BIG => E2BIG, + libc::ENOEXEC => ENOEXEC, + libc::EBADF => EBADF, + libc::ECHILD => ECHILD, + libc::EDEADLK => EDEADLK, + libc::ENOMEM => ENOMEM, + libc::EACCES => EACCES, + libc::EFAULT => EFAULT, + libc::ENOTBLK => ENOTBLK, + libc::EBUSY => EBUSY, + libc::EEXIST => EEXIST, + libc::EXDEV => EXDEV, + libc::ENODEV => ENODEV, + libc::ENOTDIR => ENOTDIR, + libc::EISDIR => EISDIR, + libc::EINVAL => EINVAL, + libc::ENFILE => ENFILE, + libc::EMFILE => EMFILE, + libc::ENOTTY => ENOTTY, + libc::ETXTBSY => ETXTBSY, + libc::EFBIG => EFBIG, + libc::ENOSPC => ENOSPC, + libc::ESPIPE => ESPIPE, + libc::EROFS => EROFS, + libc::EMLINK => EMLINK, + libc::EPIPE => EPIPE, + libc::EDOM => EDOM, + libc::ERANGE => ERANGE, + libc::EAGAIN => EAGAIN, + libc::EINPROGRESS => EINPROGRESS, + libc::EALREADY => EALREADY, + libc::ENOTSOCK => ENOTSOCK, + libc::EDESTADDRREQ => EDESTADDRREQ, + libc::EMSGSIZE => EMSGSIZE, + libc::EPROTOTYPE => EPROTOTYPE, + libc::ENOPROTOOPT => ENOPROTOOPT, + libc::EPROTONOSUPPORT => EPROTONOSUPPORT, + libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, + libc::EOPNOTSUPP => EOPNOTSUPP, + libc::EPFNOSUPPORT => EPFNOSUPPORT, + libc::EAFNOSUPPORT => EAFNOSUPPORT, + libc::EADDRINUSE => EADDRINUSE, + libc::EADDRNOTAVAIL => EADDRNOTAVAIL, + libc::ENETDOWN => ENETDOWN, + libc::ENETUNREACH => ENETUNREACH, + libc::ENETRESET => ENETRESET, + libc::ECONNABORTED => ECONNABORTED, + libc::ECONNRESET => ECONNRESET, + libc::ENOBUFS => ENOBUFS, + libc::EISCONN => EISCONN, + libc::ENOTCONN => ENOTCONN, + libc::ESHUTDOWN => ESHUTDOWN, + libc::ETOOMANYREFS => ETOOMANYREFS, + libc::ETIMEDOUT => ETIMEDOUT, + libc::ECONNREFUSED => ECONNREFUSED, + libc::ELOOP => ELOOP, + libc::ENAMETOOLONG => ENAMETOOLONG, + libc::EHOSTDOWN => EHOSTDOWN, + libc::EHOSTUNREACH => EHOSTUNREACH, + libc::ENOTEMPTY => ENOTEMPTY, + libc::EPROCLIM => EPROCLIM, + libc::EUSERS => EUSERS, + libc::EDQUOT => EDQUOT, + libc::ESTALE => ESTALE, + libc::EREMOTE => EREMOTE, + libc::EBADRPC => EBADRPC, + libc::ERPCMISMATCH => ERPCMISMATCH, + libc::EPROGUNAVAIL => EPROGUNAVAIL, + libc::EPROGMISMATCH => EPROGMISMATCH, + libc::EPROCUNAVAIL => EPROCUNAVAIL, + libc::ENOLCK => ENOLCK, + libc::ENOSYS => ENOSYS, + libc::EFTYPE => EFTYPE, + libc::EAUTH => EAUTH, + libc::ENEEDAUTH => ENEEDAUTH, + libc::EIDRM => EIDRM, + libc::ENOMSG => ENOMSG, + libc::EOVERFLOW => EOVERFLOW, + libc::EILSEQ => EILSEQ, + libc::ENOTSUP => ENOTSUP, + libc::ECANCELED => ECANCELED, + libc::EBADMSG => EBADMSG, + libc::ENODATA => ENODATA, + libc::ENOSR => ENOSR, + libc::ENOSTR => ENOSTR, + libc::ETIME => ETIME, + libc::ENOATTR => ENOATTR, + libc::EMULTIHOP => EMULTIHOP, + libc::ENOLINK => ENOLINK, + libc::EPROTO => EPROTO, + _ => UnknownErrno, + } + } +} + +#[cfg(target_os = "redox")] +mod consts { + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[repr(i32)] + #[non_exhaustive] + pub enum Errno { + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, + EPROTONOSUPPORT = libc::EPROTONOSUPPORT, + ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, + EOPNOTSUPP = libc::EOPNOTSUPP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EUSERS = libc::EUSERS, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + EREMOTE = libc::EREMOTE, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + EOVERFLOW = libc::EOVERFLOW, + EILSEQ = libc::EILSEQ, + ECANCELED = libc::ECANCELED, + EBADMSG = libc::EBADMSG, + ENODATA = libc::ENODATA, + ENOSR = libc::ENOSR, + ENOSTR = libc::ENOSTR, + ETIME = libc::ETIME, + EMULTIHOP = libc::EMULTIHOP, + ENOLINK = libc::ENOLINK, + EPROTO = libc::EPROTO, + } + + impl Errno { + pub const EWOULDBLOCK: Errno = Errno::EAGAIN; + } + + pub const fn from_i32(e: i32) -> Errno { + use self::Errno::*; + + match e { + libc::EPERM => EPERM, + libc::ENOENT => ENOENT, + libc::ESRCH => ESRCH, + libc::EINTR => EINTR, + libc::EIO => EIO, + libc::ENXIO => ENXIO, + libc::E2BIG => E2BIG, + libc::ENOEXEC => ENOEXEC, + libc::EBADF => EBADF, + libc::ECHILD => ECHILD, + libc::EDEADLK => EDEADLK, + libc::ENOMEM => ENOMEM, + libc::EACCES => EACCES, + libc::EFAULT => EFAULT, + libc::ENOTBLK => ENOTBLK, + libc::EBUSY => EBUSY, + libc::EEXIST => EEXIST, + libc::EXDEV => EXDEV, + libc::ENODEV => ENODEV, + libc::ENOTDIR => ENOTDIR, + libc::EISDIR => EISDIR, + libc::EINVAL => EINVAL, + libc::ENFILE => ENFILE, + libc::EMFILE => EMFILE, + libc::ENOTTY => ENOTTY, + libc::ETXTBSY => ETXTBSY, + libc::EFBIG => EFBIG, + libc::ENOSPC => ENOSPC, + libc::ESPIPE => ESPIPE, + libc::EROFS => EROFS, + libc::EMLINK => EMLINK, + libc::EPIPE => EPIPE, + libc::EDOM => EDOM, + libc::ERANGE => ERANGE, + libc::EAGAIN => EAGAIN, + libc::EINPROGRESS => EINPROGRESS, + libc::EALREADY => EALREADY, + libc::ENOTSOCK => ENOTSOCK, + libc::EDESTADDRREQ => EDESTADDRREQ, + libc::EMSGSIZE => EMSGSIZE, + libc::EPROTOTYPE => EPROTOTYPE, + libc::ENOPROTOOPT => ENOPROTOOPT, + libc::EPROTONOSUPPORT => EPROTONOSUPPORT, + libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, + libc::EOPNOTSUPP => EOPNOTSUPP, + libc::EPFNOSUPPORT => EPFNOSUPPORT, + libc::EAFNOSUPPORT => EAFNOSUPPORT, + libc::EADDRINUSE => EADDRINUSE, + libc::EADDRNOTAVAIL => EADDRNOTAVAIL, + libc::ENETDOWN => ENETDOWN, + libc::ENETUNREACH => ENETUNREACH, + libc::ENETRESET => ENETRESET, + libc::ECONNABORTED => ECONNABORTED, + libc::ECONNRESET => ECONNRESET, + libc::ENOBUFS => ENOBUFS, + libc::EISCONN => EISCONN, + libc::ENOTCONN => ENOTCONN, + libc::ESHUTDOWN => ESHUTDOWN, + libc::ETOOMANYREFS => ETOOMANYREFS, + libc::ETIMEDOUT => ETIMEDOUT, + libc::ECONNREFUSED => ECONNREFUSED, + libc::ELOOP => ELOOP, + libc::ENAMETOOLONG => ENAMETOOLONG, + libc::EHOSTDOWN => EHOSTDOWN, + libc::EHOSTUNREACH => EHOSTUNREACH, + libc::ENOTEMPTY => ENOTEMPTY, + libc::EUSERS => EUSERS, + libc::EDQUOT => EDQUOT, + libc::ESTALE => ESTALE, + libc::EREMOTE => EREMOTE, + libc::ENOLCK => ENOLCK, + libc::ENOSYS => ENOSYS, + libc::EIDRM => EIDRM, + libc::ENOMSG => ENOMSG, + libc::EOVERFLOW => EOVERFLOW, + libc::EILSEQ => EILSEQ, + libc::ECANCELED => ECANCELED, + libc::EBADMSG => EBADMSG, + libc::ENODATA => ENODATA, + libc::ENOSR => ENOSR, + libc::ENOSTR => ENOSTR, + libc::ETIME => ETIME, + libc::EMULTIHOP => EMULTIHOP, + libc::ENOLINK => ENOLINK, + libc::EPROTO => EPROTO, + _ => UnknownErrno, + } + } +} + +#[cfg(any(target_os = "illumos", target_os = "solaris"))] +mod consts { + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[repr(i32)] + #[non_exhaustive] + pub enum Errno { + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EAGAIN = libc::EAGAIN, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + ENOMSG = libc::ENOMSG, + EIDRM = libc::EIDRM, + ECHRNG = libc::ECHRNG, + EL2NSYNC = libc::EL2NSYNC, + EL3HLT = libc::EL3HLT, + EL3RST = libc::EL3RST, + ELNRNG = libc::ELNRNG, + EUNATCH = libc::EUNATCH, + ENOCSI = libc::ENOCSI, + EL2HLT = libc::EL2HLT, + EDEADLK = libc::EDEADLK, + ENOLCK = libc::ENOLCK, + ECANCELED = libc::ECANCELED, + ENOTSUP = libc::ENOTSUP, + EDQUOT = libc::EDQUOT, + EBADE = libc::EBADE, + EBADR = libc::EBADR, + EXFULL = libc::EXFULL, + ENOANO = libc::ENOANO, + EBADRQC = libc::EBADRQC, + EBADSLT = libc::EBADSLT, + EDEADLOCK = libc::EDEADLOCK, + EBFONT = libc::EBFONT, + EOWNERDEAD = libc::EOWNERDEAD, + ENOTRECOVERABLE = libc::ENOTRECOVERABLE, + ENOSTR = libc::ENOSTR, + ENODATA = libc::ENODATA, + ETIME = libc::ETIME, + ENOSR = libc::ENOSR, + ENONET = libc::ENONET, + ENOPKG = libc::ENOPKG, + EREMOTE = libc::EREMOTE, + ENOLINK = libc::ENOLINK, + EADV = libc::EADV, + ESRMNT = libc::ESRMNT, + ECOMM = libc::ECOMM, + EPROTO = libc::EPROTO, + ELOCKUNMAPPED = libc::ELOCKUNMAPPED, + ENOTACTIVE = libc::ENOTACTIVE, + EMULTIHOP = libc::EMULTIHOP, + EBADMSG = libc::EBADMSG, + ENAMETOOLONG = libc::ENAMETOOLONG, + EOVERFLOW = libc::EOVERFLOW, + ENOTUNIQ = libc::ENOTUNIQ, + EBADFD = libc::EBADFD, + EREMCHG = libc::EREMCHG, + ELIBACC = libc::ELIBACC, + ELIBBAD = libc::ELIBBAD, + ELIBSCN = libc::ELIBSCN, + ELIBMAX = libc::ELIBMAX, + ELIBEXEC = libc::ELIBEXEC, + EILSEQ = libc::EILSEQ, + ENOSYS = libc::ENOSYS, + ELOOP = libc::ELOOP, + ERESTART = libc::ERESTART, + ESTRPIPE = libc::ESTRPIPE, + ENOTEMPTY = libc::ENOTEMPTY, + EUSERS = libc::EUSERS, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, + EPROTONOSUPPORT = libc::EPROTONOSUPPORT, + ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, + EOPNOTSUPP = libc::EOPNOTSUPP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + EALREADY = libc::EALREADY, + EINPROGRESS = libc::EINPROGRESS, + ESTALE = libc::ESTALE, + } + + impl Errno { + pub const ELAST: Errno = Errno::ESTALE; + pub const EWOULDBLOCK: Errno = Errno::EAGAIN; + } + + pub const fn from_i32(e: i32) -> Errno { + use self::Errno::*; + + match e { + libc::EPERM => EPERM, + libc::ENOENT => ENOENT, + libc::ESRCH => ESRCH, + libc::EINTR => EINTR, + libc::EIO => EIO, + libc::ENXIO => ENXIO, + libc::E2BIG => E2BIG, + libc::ENOEXEC => ENOEXEC, + libc::EBADF => EBADF, + libc::ECHILD => ECHILD, + libc::EAGAIN => EAGAIN, + libc::ENOMEM => ENOMEM, + libc::EACCES => EACCES, + libc::EFAULT => EFAULT, + libc::ENOTBLK => ENOTBLK, + libc::EBUSY => EBUSY, + libc::EEXIST => EEXIST, + libc::EXDEV => EXDEV, + libc::ENODEV => ENODEV, + libc::ENOTDIR => ENOTDIR, + libc::EISDIR => EISDIR, + libc::EINVAL => EINVAL, + libc::ENFILE => ENFILE, + libc::EMFILE => EMFILE, + libc::ENOTTY => ENOTTY, + libc::ETXTBSY => ETXTBSY, + libc::EFBIG => EFBIG, + libc::ENOSPC => ENOSPC, + libc::ESPIPE => ESPIPE, + libc::EROFS => EROFS, + libc::EMLINK => EMLINK, + libc::EPIPE => EPIPE, + libc::EDOM => EDOM, + libc::ERANGE => ERANGE, + libc::ENOMSG => ENOMSG, + libc::EIDRM => EIDRM, + libc::ECHRNG => ECHRNG, + libc::EL2NSYNC => EL2NSYNC, + libc::EL3HLT => EL3HLT, + libc::EL3RST => EL3RST, + libc::ELNRNG => ELNRNG, + libc::EUNATCH => EUNATCH, + libc::ENOCSI => ENOCSI, + libc::EL2HLT => EL2HLT, + libc::EDEADLK => EDEADLK, + libc::ENOLCK => ENOLCK, + libc::ECANCELED => ECANCELED, + libc::ENOTSUP => ENOTSUP, + libc::EDQUOT => EDQUOT, + libc::EBADE => EBADE, + libc::EBADR => EBADR, + libc::EXFULL => EXFULL, + libc::ENOANO => ENOANO, + libc::EBADRQC => EBADRQC, + libc::EBADSLT => EBADSLT, + libc::EDEADLOCK => EDEADLOCK, + libc::EBFONT => EBFONT, + libc::EOWNERDEAD => EOWNERDEAD, + libc::ENOTRECOVERABLE => ENOTRECOVERABLE, + libc::ENOSTR => ENOSTR, + libc::ENODATA => ENODATA, + libc::ETIME => ETIME, + libc::ENOSR => ENOSR, + libc::ENONET => ENONET, + libc::ENOPKG => ENOPKG, + libc::EREMOTE => EREMOTE, + libc::ENOLINK => ENOLINK, + libc::EADV => EADV, + libc::ESRMNT => ESRMNT, + libc::ECOMM => ECOMM, + libc::EPROTO => EPROTO, + libc::ELOCKUNMAPPED => ELOCKUNMAPPED, + libc::ENOTACTIVE => ENOTACTIVE, + libc::EMULTIHOP => EMULTIHOP, + libc::EBADMSG => EBADMSG, + libc::ENAMETOOLONG => ENAMETOOLONG, + libc::EOVERFLOW => EOVERFLOW, + libc::ENOTUNIQ => ENOTUNIQ, + libc::EBADFD => EBADFD, + libc::EREMCHG => EREMCHG, + libc::ELIBACC => ELIBACC, + libc::ELIBBAD => ELIBBAD, + libc::ELIBSCN => ELIBSCN, + libc::ELIBMAX => ELIBMAX, + libc::ELIBEXEC => ELIBEXEC, + libc::EILSEQ => EILSEQ, + libc::ENOSYS => ENOSYS, + libc::ELOOP => ELOOP, + libc::ERESTART => ERESTART, + libc::ESTRPIPE => ESTRPIPE, + libc::ENOTEMPTY => ENOTEMPTY, + libc::EUSERS => EUSERS, + libc::ENOTSOCK => ENOTSOCK, + libc::EDESTADDRREQ => EDESTADDRREQ, + libc::EMSGSIZE => EMSGSIZE, + libc::EPROTOTYPE => EPROTOTYPE, + libc::ENOPROTOOPT => ENOPROTOOPT, + libc::EPROTONOSUPPORT => EPROTONOSUPPORT, + libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, + libc::EOPNOTSUPP => EOPNOTSUPP, + libc::EPFNOSUPPORT => EPFNOSUPPORT, + libc::EAFNOSUPPORT => EAFNOSUPPORT, + libc::EADDRINUSE => EADDRINUSE, + libc::EADDRNOTAVAIL => EADDRNOTAVAIL, + libc::ENETDOWN => ENETDOWN, + libc::ENETUNREACH => ENETUNREACH, + libc::ENETRESET => ENETRESET, + libc::ECONNABORTED => ECONNABORTED, + libc::ECONNRESET => ECONNRESET, + libc::ENOBUFS => ENOBUFS, + libc::EISCONN => EISCONN, + libc::ENOTCONN => ENOTCONN, + libc::ESHUTDOWN => ESHUTDOWN, + libc::ETOOMANYREFS => ETOOMANYREFS, + libc::ETIMEDOUT => ETIMEDOUT, + libc::ECONNREFUSED => ECONNREFUSED, + libc::EHOSTDOWN => EHOSTDOWN, + libc::EHOSTUNREACH => EHOSTUNREACH, + libc::EALREADY => EALREADY, + libc::EINPROGRESS => EINPROGRESS, + libc::ESTALE => ESTALE, + _ => UnknownErrno, + } + } +} + +#[cfg(target_os = "haiku")] +mod consts { + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[repr(i32)] + #[non_exhaustive] + pub enum Errno { + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, + EPROTONOSUPPORT = libc::EPROTONOSUPPORT, + ENOTSUP = libc::ENOTSUP, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + EOVERFLOW = libc::EOVERFLOW, + ECANCELED = libc::ECANCELED, + EILSEQ = libc::EILSEQ, + ENOATTR = libc::ENOATTR, + EBADMSG = libc::EBADMSG, + EMULTIHOP = libc::EMULTIHOP, + ENOLINK = libc::ENOLINK, + EPROTO = libc::EPROTO, + } + + impl Errno { + pub const EWOULDBLOCK: Errno = Errno::EAGAIN; + pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; + } + + pub const fn from_i32(e: i32) -> Errno { + use self::Errno::*; + + match e { + libc::EPERM => EPERM, + libc::ENOENT => ENOENT, + libc::ESRCH => ESRCH, + libc::EINTR => EINTR, + libc::EIO => EIO, + libc::ENXIO => ENXIO, + libc::E2BIG => E2BIG, + libc::ENOEXEC => ENOEXEC, + libc::EBADF => EBADF, + libc::ECHILD => ECHILD, + libc::EDEADLK => EDEADLK, + libc::ENOMEM => ENOMEM, + libc::EACCES => EACCES, + libc::EFAULT => EFAULT, + libc::EBUSY => EBUSY, + libc::EEXIST => EEXIST, + libc::EXDEV => EXDEV, + libc::ENODEV => ENODEV, + libc::ENOTDIR => ENOTDIR, + libc::EISDIR => EISDIR, + libc::EINVAL => EINVAL, + libc::ENFILE => ENFILE, + libc::EMFILE => EMFILE, + libc::ENOTTY => ENOTTY, + libc::ETXTBSY => ETXTBSY, + libc::EFBIG => EFBIG, + libc::ENOSPC => ENOSPC, + libc::ESPIPE => ESPIPE, + libc::EROFS => EROFS, + libc::EMLINK => EMLINK, + libc::EPIPE => EPIPE, + libc::EDOM => EDOM, + libc::ERANGE => ERANGE, + libc::EAGAIN => EAGAIN, + libc::EINPROGRESS => EINPROGRESS, + libc::EALREADY => EALREADY, + libc::ENOTSOCK => ENOTSOCK, + libc::EDESTADDRREQ => EDESTADDRREQ, + libc::EMSGSIZE => EMSGSIZE, + libc::EPROTOTYPE => EPROTOTYPE, + libc::ENOPROTOOPT => ENOPROTOOPT, + libc::EPROTONOSUPPORT => EPROTONOSUPPORT, + libc::ENOTSUP => ENOTSUP, + libc::EADDRINUSE => EADDRINUSE, + libc::EADDRNOTAVAIL => EADDRNOTAVAIL, + libc::ENETDOWN => ENETDOWN, + libc::ENETUNREACH => ENETUNREACH, + libc::ENETRESET => ENETRESET, + libc::ECONNABORTED => ECONNABORTED, + libc::ECONNRESET => ECONNRESET, + libc::ENOBUFS => ENOBUFS, + libc::EISCONN => EISCONN, + libc::ENOTCONN => ENOTCONN, + libc::ESHUTDOWN => ESHUTDOWN, + libc::ETIMEDOUT => ETIMEDOUT, + libc::ECONNREFUSED => ECONNREFUSED, + libc::ELOOP => ELOOP, + libc::ENAMETOOLONG => ENAMETOOLONG, + libc::EHOSTDOWN => EHOSTDOWN, + libc::EHOSTUNREACH => EHOSTUNREACH, + libc::ENOTEMPTY => ENOTEMPTY, + libc::EDQUOT => EDQUOT, + libc::ESTALE => ESTALE, + libc::ENOLCK => ENOLCK, + libc::ENOSYS => ENOSYS, + libc::EIDRM => EIDRM, + libc::ENOMSG => ENOMSG, + libc::EOVERFLOW => EOVERFLOW, + libc::ECANCELED => ECANCELED, + libc::EILSEQ => EILSEQ, + libc::ENOATTR => ENOATTR, + libc::EBADMSG => EBADMSG, + libc::EMULTIHOP => EMULTIHOP, + libc::ENOLINK => ENOLINK, + libc::EPROTO => EPROTO, + _ => UnknownErrno, + } + } +} diff --git a/vendor/nix-0.26.2/src/fcntl.rs b/vendor/nix-0.26.2/src/fcntl.rs new file mode 100644 index 0000000000000..650828345b809 --- /dev/null +++ b/vendor/nix-0.26.2/src/fcntl.rs @@ -0,0 +1,882 @@ +use crate::errno::Errno; +use libc::{self, c_char, c_int, c_uint, size_t, ssize_t}; +use std::ffi::OsString; +#[cfg(not(target_os = "redox"))] +use std::os::raw; +use std::os::unix::ffi::OsStringExt; +use std::os::unix::io::RawFd; + +#[cfg(feature = "fs")] +use crate::{sys::stat::Mode, NixPath, Result}; +#[cfg(any(target_os = "android", target_os = "linux"))] +use std::ptr; // For splice and copy_file_range + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "wasi", + target_env = "uclibc", + target_os = "freebsd" +))] +#[cfg(feature = "fs")] +pub use self::posix_fadvise::{posix_fadvise, PosixFadviseAdvice}; + +#[cfg(not(target_os = "redox"))] +#[cfg(any(feature = "fs", feature = "process"))] +libc_bitflags! { + #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "process"))))] + pub struct AtFlags: c_int { + AT_REMOVEDIR; + AT_SYMLINK_FOLLOW; + AT_SYMLINK_NOFOLLOW; + #[cfg(any(target_os = "android", target_os = "linux"))] + AT_NO_AUTOMOUNT; + #[cfg(any(target_os = "android", target_os = "linux"))] + AT_EMPTY_PATH; + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + AT_EACCESS; + } +} + +#[cfg(any(feature = "fs", feature = "term"))] +libc_bitflags!( + /// Configuration options for opened files. + #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "term"))))] + pub struct OFlag: c_int { + /// Mask for the access mode of the file. + O_ACCMODE; + /// Use alternate I/O semantics. + #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_ALT_IO; + /// Open the file in append-only mode. + O_APPEND; + /// Generate a signal when input or output becomes possible. + #[cfg(not(any(target_os = "illumos", target_os = "solaris", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_ASYNC; + /// Closes the file descriptor once an `execve` call is made. + /// + /// Also sets the file offset to the beginning of the file. + O_CLOEXEC; + /// Create the file if it does not exist. + O_CREAT; + /// Try to minimize cache effects of the I/O for this file. + #[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_DIRECT; + /// If the specified path isn't a directory, fail. + #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_DIRECTORY; + /// Implicitly follow each `write()` with an `fdatasync()`. + #[cfg(any(target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_DSYNC; + /// Error out if a file was not created. + O_EXCL; + /// Open for execute only. + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_EXEC; + /// Open with an exclusive file lock. + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_EXLOCK; + /// Same as `O_SYNC`. + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + all(target_os = "linux", not(target_env = "musl")), + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_FSYNC; + /// Allow files whose sizes can't be represented in an `off_t` to be opened. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_LARGEFILE; + /// Do not update the file last access time during `read(2)`s. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_NOATIME; + /// Don't attach the device as the process' controlling terminal. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_NOCTTY; + /// Same as `O_NONBLOCK`. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_NDELAY; + /// `open()` will fail if the given path is a symbolic link. + O_NOFOLLOW; + /// When possible, open the file in nonblocking mode. + O_NONBLOCK; + /// Don't deliver `SIGPIPE`. + #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_NOSIGPIPE; + /// Obtain a file descriptor for low-level access. + /// + /// The file itself is not opened and other file operations will fail. + #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_PATH; + /// Only allow reading. + /// + /// This should not be combined with `O_WRONLY` or `O_RDWR`. + O_RDONLY; + /// Allow both reading and writing. + /// + /// This should not be combined with `O_WRONLY` or `O_RDONLY`. + O_RDWR; + /// Similar to `O_DSYNC` but applies to `read`s instead. + #[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_RSYNC; + /// Skip search permission checks. + #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_SEARCH; + /// Open with a shared file lock. + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_SHLOCK; + /// Implicitly follow each `write()` with an `fsync()`. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_SYNC; + /// Create an unnamed temporary file. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_TMPFILE; + /// Truncate an existing regular file to 0 length if it allows writing. + O_TRUNC; + /// Restore default TTY attributes. + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_TTY_INIT; + /// Only allow writing. + /// + /// This should not be combined with `O_RDONLY` or `O_RDWR`. + O_WRONLY; + } +); + +feature! { +#![feature = "fs"] + +// The conversion is not identical on all operating systems. +#[allow(clippy::useless_conversion)] +pub fn open(path: &P, oflag: OFlag, mode: Mode) -> Result { + let fd = path.with_nix_path(|cstr| { + unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) } + })?; + + Errno::result(fd) +} + +// The conversion is not identical on all operating systems. +#[allow(clippy::useless_conversion)] +#[cfg(not(target_os = "redox"))] +pub fn openat( + dirfd: RawFd, + path: &P, + oflag: OFlag, + mode: Mode, +) -> Result { + let fd = path.with_nix_path(|cstr| { + unsafe { libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) } + })?; + Errno::result(fd) +} + +#[cfg(not(target_os = "redox"))] +pub fn renameat( + old_dirfd: Option, + old_path: &P1, + new_dirfd: Option, + new_path: &P2, +) -> Result<()> { + let res = old_path.with_nix_path(|old_cstr| { + new_path.with_nix_path(|new_cstr| unsafe { + libc::renameat( + at_rawfd(old_dirfd), + old_cstr.as_ptr(), + at_rawfd(new_dirfd), + new_cstr.as_ptr(), + ) + }) + })??; + Errno::result(res).map(drop) +} +} + +#[cfg(all(target_os = "linux", target_env = "gnu",))] +#[cfg(feature = "fs")] +libc_bitflags! { + #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] + pub struct RenameFlags: u32 { + RENAME_EXCHANGE; + RENAME_NOREPLACE; + RENAME_WHITEOUT; + } +} + +feature! { +#![feature = "fs"] +#[cfg(all( + target_os = "linux", + target_env = "gnu", +))] +pub fn renameat2( + old_dirfd: Option, + old_path: &P1, + new_dirfd: Option, + new_path: &P2, + flags: RenameFlags, +) -> Result<()> { + let res = old_path.with_nix_path(|old_cstr| { + new_path.with_nix_path(|new_cstr| unsafe { + libc::renameat2( + at_rawfd(old_dirfd), + old_cstr.as_ptr(), + at_rawfd(new_dirfd), + new_cstr.as_ptr(), + flags.bits(), + ) + }) + })??; + Errno::result(res).map(drop) +} + +fn wrap_readlink_result(mut v: Vec, len: ssize_t) -> Result { + unsafe { v.set_len(len as usize) } + v.shrink_to_fit(); + Ok(OsString::from_vec(v.to_vec())) +} + +fn readlink_maybe_at( + dirfd: Option, + path: &P, + v: &mut Vec, +) -> Result { + path.with_nix_path(|cstr| unsafe { + match dirfd { + #[cfg(target_os = "redox")] + Some(_) => unreachable!(), + #[cfg(not(target_os = "redox"))] + Some(dirfd) => libc::readlinkat( + dirfd, + cstr.as_ptr(), + v.as_mut_ptr() as *mut c_char, + v.capacity() as size_t, + ), + None => libc::readlink( + cstr.as_ptr(), + v.as_mut_ptr() as *mut c_char, + v.capacity() as size_t, + ), + } + }) +} + +fn inner_readlink(dirfd: Option, path: &P) -> Result { + let mut v = Vec::with_capacity(libc::PATH_MAX as usize); + // simple case: result is strictly less than `PATH_MAX` + let res = readlink_maybe_at(dirfd, path, &mut v)?; + let len = Errno::result(res)?; + debug_assert!(len >= 0); + if (len as usize) < v.capacity() { + return wrap_readlink_result(v, res); + } + // Uh oh, the result is too long... + // Let's try to ask lstat how many bytes to allocate. + let reported_size = match dirfd { + #[cfg(target_os = "redox")] + Some(_) => unreachable!(), + #[cfg(any(target_os = "android", target_os = "linux"))] + Some(dirfd) => { + let flags = if path.is_empty() { AtFlags::AT_EMPTY_PATH } else { AtFlags::empty() }; + super::sys::stat::fstatat(dirfd, path, flags | AtFlags::AT_SYMLINK_NOFOLLOW) + }, + #[cfg(not(any(target_os = "android", target_os = "linux", target_os = "redox")))] + Some(dirfd) => super::sys::stat::fstatat(dirfd, path, AtFlags::AT_SYMLINK_NOFOLLOW), + None => super::sys::stat::lstat(path) + } + .map(|x| x.st_size) + .unwrap_or(0); + let mut try_size = if reported_size > 0 { + // Note: even if `lstat`'s apparently valid answer turns out to be + // wrong, we will still read the full symlink no matter what. + reported_size as usize + 1 + } else { + // If lstat doesn't cooperate, or reports an error, be a little less + // precise. + (libc::PATH_MAX as usize).max(128) << 1 + }; + loop { + v.reserve_exact(try_size); + let res = readlink_maybe_at(dirfd, path, &mut v)?; + let len = Errno::result(res)?; + debug_assert!(len >= 0); + if (len as usize) < v.capacity() { + break wrap_readlink_result(v, res); + } else { + // Ugh! Still not big enough! + match try_size.checked_shl(1) { + Some(next_size) => try_size = next_size, + // It's absurd that this would happen, but handle it sanely + // anyway. + None => break Err(Errno::ENAMETOOLONG), + } + } + } +} + +pub fn readlink(path: &P) -> Result { + inner_readlink(None, path) +} + +#[cfg(not(target_os = "redox"))] +pub fn readlinkat(dirfd: RawFd, path: &P) -> Result { + inner_readlink(Some(dirfd), path) +} + +/// Computes the raw fd consumed by a function of the form `*at`. +#[cfg(not(target_os = "redox"))] +pub(crate) fn at_rawfd(fd: Option) -> raw::c_int { + match fd { + None => libc::AT_FDCWD, + Some(fd) => fd, + } +} +} + +#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] +#[cfg(feature = "fs")] +libc_bitflags!( + /// Additional flags for file sealing, which allows for limiting operations on a file. + #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] + pub struct SealFlag: c_int { + /// Prevents further calls to `fcntl()` with `F_ADD_SEALS`. + F_SEAL_SEAL; + /// The file cannot be reduced in size. + F_SEAL_SHRINK; + /// The size of the file cannot be increased. + F_SEAL_GROW; + /// The file contents cannot be modified. + F_SEAL_WRITE; + } +); + +#[cfg(feature = "fs")] +libc_bitflags!( + /// Additional configuration flags for `fcntl`'s `F_SETFD`. + #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] + pub struct FdFlag: c_int { + /// The file descriptor will automatically be closed during a successful `execve(2)`. + FD_CLOEXEC; + } +); + +feature! { +#![feature = "fs"] + +#[cfg(not(target_os = "redox"))] +#[derive(Debug, Eq, Hash, PartialEq)] +#[non_exhaustive] +pub enum FcntlArg<'a> { + F_DUPFD(RawFd), + F_DUPFD_CLOEXEC(RawFd), + F_GETFD, + F_SETFD(FdFlag), // FD_FLAGS + F_GETFL, + F_SETFL(OFlag), // O_NONBLOCK + F_SETLK(&'a libc::flock), + F_SETLKW(&'a libc::flock), + F_GETLK(&'a mut libc::flock), + #[cfg(any(target_os = "linux", target_os = "android"))] + F_OFD_SETLK(&'a libc::flock), + #[cfg(any(target_os = "linux", target_os = "android"))] + F_OFD_SETLKW(&'a libc::flock), + #[cfg(any(target_os = "linux", target_os = "android"))] + F_OFD_GETLK(&'a mut libc::flock), + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + F_ADD_SEALS(SealFlag), + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + F_GET_SEALS, + #[cfg(any(target_os = "macos", target_os = "ios"))] + F_FULLFSYNC, + #[cfg(any(target_os = "linux", target_os = "android"))] + F_GETPIPE_SZ, + #[cfg(any(target_os = "linux", target_os = "android"))] + F_SETPIPE_SZ(c_int), + // TODO: Rest of flags +} + +#[cfg(target_os = "redox")] +#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] +#[non_exhaustive] +pub enum FcntlArg { + F_DUPFD(RawFd), + F_DUPFD_CLOEXEC(RawFd), + F_GETFD, + F_SETFD(FdFlag), // FD_FLAGS + F_GETFL, + F_SETFL(OFlag), // O_NONBLOCK +} +pub use self::FcntlArg::*; + +// TODO: Figure out how to handle value fcntl returns +pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result { + let res = unsafe { + match arg { + F_DUPFD(rawfd) => libc::fcntl(fd, libc::F_DUPFD, rawfd), + F_DUPFD_CLOEXEC(rawfd) => libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, rawfd), + F_GETFD => libc::fcntl(fd, libc::F_GETFD), + F_SETFD(flag) => libc::fcntl(fd, libc::F_SETFD, flag.bits()), + F_GETFL => libc::fcntl(fd, libc::F_GETFL), + F_SETFL(flag) => libc::fcntl(fd, libc::F_SETFL, flag.bits()), + #[cfg(not(target_os = "redox"))] + F_SETLK(flock) => libc::fcntl(fd, libc::F_SETLK, flock), + #[cfg(not(target_os = "redox"))] + F_SETLKW(flock) => libc::fcntl(fd, libc::F_SETLKW, flock), + #[cfg(not(target_os = "redox"))] + F_GETLK(flock) => libc::fcntl(fd, libc::F_GETLK, flock), + #[cfg(any(target_os = "android", target_os = "linux"))] + F_OFD_SETLK(flock) => libc::fcntl(fd, libc::F_OFD_SETLK, flock), + #[cfg(any(target_os = "android", target_os = "linux"))] + F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock), + #[cfg(any(target_os = "android", target_os = "linux"))] + F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock), + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()), + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS), + #[cfg(any(target_os = "macos", target_os = "ios"))] + F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC), + #[cfg(any(target_os = "linux", target_os = "android"))] + F_GETPIPE_SZ => libc::fcntl(fd, libc::F_GETPIPE_SZ), + #[cfg(any(target_os = "linux", target_os = "android"))] + F_SETPIPE_SZ(size) => libc::fcntl(fd, libc::F_SETPIPE_SZ, size), + } + }; + + Errno::result(res) +} + +// TODO: convert to libc_enum +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[non_exhaustive] +pub enum FlockArg { + LockShared, + LockExclusive, + Unlock, + LockSharedNonblock, + LockExclusiveNonblock, + UnlockNonblock, +} + +#[cfg(not(target_os = "redox"))] +pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> { + use self::FlockArg::*; + + let res = unsafe { + match arg { + LockShared => libc::flock(fd, libc::LOCK_SH), + LockExclusive => libc::flock(fd, libc::LOCK_EX), + Unlock => libc::flock(fd, libc::LOCK_UN), + LockSharedNonblock => libc::flock(fd, libc::LOCK_SH | libc::LOCK_NB), + LockExclusiveNonblock => libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB), + UnlockNonblock => libc::flock(fd, libc::LOCK_UN | libc::LOCK_NB), + } + }; + + Errno::result(res).map(drop) +} +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(feature = "zerocopy")] +libc_bitflags! { + /// Additional flags to `splice` and friends. + #[cfg_attr(docsrs, doc(cfg(feature = "zerocopy")))] + pub struct SpliceFFlags: c_uint { + /// Request that pages be moved instead of copied. + /// + /// Not applicable to `vmsplice`. + SPLICE_F_MOVE; + /// Do not block on I/O. + SPLICE_F_NONBLOCK; + /// Hint that more data will be coming in a subsequent splice. + /// + /// Not applicable to `vmsplice`. + SPLICE_F_MORE; + /// Gift the user pages to the kernel. + /// + /// Not applicable to `splice`. + SPLICE_F_GIFT; + } +} + +feature! { +#![feature = "zerocopy"] + +/// Copy a range of data from one file to another +/// +/// The `copy_file_range` system call performs an in-kernel copy between +/// file descriptors `fd_in` and `fd_out` without the additional cost of +/// transferring data from the kernel to user space and then back into the +/// kernel. It copies up to `len` bytes of data from file descriptor `fd_in` to +/// file descriptor `fd_out`, overwriting any data that exists within the +/// requested range of the target file. +/// +/// If the `off_in` and/or `off_out` arguments are used, the values +/// will be mutated to reflect the new position within the file after +/// copying. If they are not used, the relevant filedescriptors will be seeked +/// to the new position. +/// +/// On successful completion the number of bytes actually copied will be +/// returned. +#[cfg(any(target_os = "android", target_os = "linux"))] +pub fn copy_file_range( + fd_in: RawFd, + off_in: Option<&mut libc::loff_t>, + fd_out: RawFd, + off_out: Option<&mut libc::loff_t>, + len: usize, +) -> Result { + let off_in = off_in + .map(|offset| offset as *mut libc::loff_t) + .unwrap_or(ptr::null_mut()); + let off_out = off_out + .map(|offset| offset as *mut libc::loff_t) + .unwrap_or(ptr::null_mut()); + + let ret = unsafe { + libc::syscall( + libc::SYS_copy_file_range, + fd_in, + off_in, + fd_out, + off_out, + len, + 0, + ) + }; + Errno::result(ret).map(|r| r as usize) +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn splice( + fd_in: RawFd, + off_in: Option<&mut libc::loff_t>, + fd_out: RawFd, + off_out: Option<&mut libc::loff_t>, + len: usize, + flags: SpliceFFlags, +) -> Result { + let off_in = off_in + .map(|offset| offset as *mut libc::loff_t) + .unwrap_or(ptr::null_mut()); + let off_out = off_out + .map(|offset| offset as *mut libc::loff_t) + .unwrap_or(ptr::null_mut()); + + let ret = unsafe { libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) }; + Errno::result(ret).map(|r| r as usize) +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Result { + let ret = unsafe { libc::tee(fd_in, fd_out, len, flags.bits()) }; + Errno::result(ret).map(|r| r as usize) +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn vmsplice( + fd: RawFd, + iov: &[std::io::IoSlice<'_>], + flags: SpliceFFlags + ) -> Result +{ + let ret = unsafe { + libc::vmsplice( + fd, + iov.as_ptr() as *const libc::iovec, + iov.len(), + flags.bits(), + ) + }; + Errno::result(ret).map(|r| r as usize) +} +} + +#[cfg(any(target_os = "linux"))] +#[cfg(feature = "fs")] +libc_bitflags!( + /// Mode argument flags for fallocate determining operation performed on a given range. + #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] + pub struct FallocateFlags: c_int { + /// File size is not changed. + /// + /// offset + len can be greater than file size. + FALLOC_FL_KEEP_SIZE; + /// Deallocates space by creating a hole. + /// + /// Must be ORed with FALLOC_FL_KEEP_SIZE. Byte range starts at offset and continues for len bytes. + FALLOC_FL_PUNCH_HOLE; + /// Removes byte range from a file without leaving a hole. + /// + /// Byte range to collapse starts at offset and continues for len bytes. + FALLOC_FL_COLLAPSE_RANGE; + /// Zeroes space in specified byte range. + /// + /// Byte range starts at offset and continues for len bytes. + FALLOC_FL_ZERO_RANGE; + /// Increases file space by inserting a hole within the file size. + /// + /// Does not overwrite existing data. Hole starts at offset and continues for len bytes. + FALLOC_FL_INSERT_RANGE; + /// Shared file data extants are made private to the file. + /// + /// Gaurantees that a subsequent write will not fail due to lack of space. + FALLOC_FL_UNSHARE_RANGE; + } +); + +feature! { +#![feature = "fs"] + +/// Manipulates file space. +/// +/// Allows the caller to directly manipulate the allocated disk space for the +/// file referred to by fd. +#[cfg(any(target_os = "linux"))] +#[cfg(feature = "fs")] +pub fn fallocate( + fd: RawFd, + mode: FallocateFlags, + offset: libc::off_t, + len: libc::off_t, +) -> Result<()> { + let res = unsafe { libc::fallocate(fd, mode.bits(), offset, len) }; + Errno::result(res).map(drop) +} + +/// Argument to [`fspacectl`] describing the range to zero. The first member is +/// the file offset, and the second is the length of the region. +#[cfg(any(target_os = "freebsd"))] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct SpacectlRange(pub libc::off_t, pub libc::off_t); + +#[cfg(any(target_os = "freebsd"))] +impl SpacectlRange { + #[inline] + pub fn is_empty(&self) -> bool { + self.1 == 0 + } + + #[inline] + pub fn len(&self) -> libc::off_t { + self.1 + } + + #[inline] + pub fn offset(&self) -> libc::off_t { + self.0 + } +} + +/// Punch holes in a file. +/// +/// `fspacectl` instructs the file system to deallocate a portion of a file. +/// After a successful operation, this region of the file will return all zeroes +/// if read. If the file system supports deallocation, then it may free the +/// underlying storage, too. +/// +/// # Arguments +/// +/// - `fd` - File to operate on +/// - `range.0` - File offset at which to begin deallocation +/// - `range.1` - Length of the region to deallocate +/// +/// # Returns +/// +/// The operation may deallocate less than the entire requested region. On +/// success, it returns the region that still remains to be deallocated. The +/// caller should loop until the returned region is empty. +/// +/// # Example +/// +#[cfg_attr(fbsd14, doc = " ```")] +#[cfg_attr(not(fbsd14), doc = " ```no_run")] +/// # use std::io::Write; +/// # use std::os::unix::fs::FileExt; +/// # use std::os::unix::io::AsRawFd; +/// # use nix::fcntl::*; +/// # use tempfile::tempfile; +/// const INITIAL: &[u8] = b"0123456789abcdef"; +/// let mut f = tempfile().unwrap(); +/// f.write_all(INITIAL).unwrap(); +/// let mut range = SpacectlRange(3, 6); +/// while (!range.is_empty()) { +/// range = fspacectl(f.as_raw_fd(), range).unwrap(); +/// } +/// let mut buf = vec![0; INITIAL.len()]; +/// f.read_exact_at(&mut buf, 0).unwrap(); +/// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); +/// ``` +#[cfg(target_os = "freebsd")] +pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result { + let mut rqsr = libc::spacectl_range{r_offset: range.0, r_len: range.1}; + let res = unsafe { libc::fspacectl( + fd, + libc::SPACECTL_DEALLOC, // Only one command is supported ATM + &rqsr, + 0, // No flags are currently supported + &mut rqsr + )}; + Errno::result(res).map(|_| SpacectlRange(rqsr.r_offset, rqsr.r_len)) +} + +/// Like [`fspacectl`], but will never return incomplete. +/// +/// # Arguments +/// +/// - `fd` - File to operate on +/// - `offset` - File offset at which to begin deallocation +/// - `len` - Length of the region to deallocate +/// +/// # Returns +/// +/// Returns `()` on success. On failure, the region may or may not be partially +/// deallocated. +/// +/// # Example +/// +#[cfg_attr(fbsd14, doc = " ```")] +#[cfg_attr(not(fbsd14), doc = " ```no_run")] +/// # use std::io::Write; +/// # use std::os::unix::fs::FileExt; +/// # use std::os::unix::io::AsRawFd; +/// # use nix::fcntl::*; +/// # use tempfile::tempfile; +/// const INITIAL: &[u8] = b"0123456789abcdef"; +/// let mut f = tempfile().unwrap(); +/// f.write_all(INITIAL).unwrap(); +/// fspacectl_all(f.as_raw_fd(), 3, 6).unwrap(); +/// let mut buf = vec![0; INITIAL.len()]; +/// f.read_exact_at(&mut buf, 0).unwrap(); +/// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); +/// ``` +#[cfg(target_os = "freebsd")] +pub fn fspacectl_all(fd: RawFd, offset: libc::off_t, len: libc::off_t) + -> Result<()> +{ + let mut rqsr = libc::spacectl_range{r_offset: offset, r_len: len}; + while rqsr.r_len > 0 { + let res = unsafe { libc::fspacectl( + fd, + libc::SPACECTL_DEALLOC, // Only one command is supported ATM + &rqsr, + 0, // No flags are currently supported + &mut rqsr + )}; + Errno::result(res)?; + } + Ok(()) +} + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "wasi", + target_env = "uclibc", + target_os = "freebsd" +))] +mod posix_fadvise { + use crate::errno::Errno; + use std::os::unix::io::RawFd; + use crate::Result; + + #[cfg(feature = "fs")] + libc_enum! { + #[repr(i32)] + #[non_exhaustive] + #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] + pub enum PosixFadviseAdvice { + POSIX_FADV_NORMAL, + POSIX_FADV_SEQUENTIAL, + POSIX_FADV_RANDOM, + POSIX_FADV_NOREUSE, + POSIX_FADV_WILLNEED, + POSIX_FADV_DONTNEED, + } + } + + feature! { + #![feature = "fs"] + pub fn posix_fadvise( + fd: RawFd, + offset: libc::off_t, + len: libc::off_t, + advice: PosixFadviseAdvice, + ) -> Result<()> { + let res = unsafe { libc::posix_fadvise(fd, offset, len, advice as libc::c_int) }; + + if res == 0 { + Ok(()) + } else { + Err(Errno::from_i32(res)) + } + } + } +} + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "wasi", + target_os = "freebsd" +))] +pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Result<()> { + let res = unsafe { libc::posix_fallocate(fd, offset, len) }; + match Errno::result(res) { + Err(err) => Err(err), + Ok(0) => Ok(()), + Ok(errno) => Err(Errno::from_i32(errno)), + } +} +} diff --git a/vendor/nix-0.26.2/src/features.rs b/vendor/nix-0.26.2/src/features.rs new file mode 100644 index 0000000000000..39d17604e1a10 --- /dev/null +++ b/vendor/nix-0.26.2/src/features.rs @@ -0,0 +1,126 @@ +//! Feature tests for OS functionality +pub use self::os::*; + +#[cfg(any(target_os = "linux", target_os = "android"))] +mod os { + use crate::sys::utsname::uname; + use crate::Result; + use std::os::unix::ffi::OsStrExt; + + // Features: + // * atomic cloexec on socket: 2.6.27 + // * pipe2: 2.6.27 + // * accept4: 2.6.28 + + static VERS_UNKNOWN: usize = 1; + static VERS_2_6_18: usize = 2; + static VERS_2_6_27: usize = 3; + static VERS_2_6_28: usize = 4; + static VERS_3: usize = 5; + + #[inline] + fn digit(dst: &mut usize, b: u8) { + *dst *= 10; + *dst += (b - b'0') as usize; + } + + fn parse_kernel_version() -> Result { + let u = uname()?; + + let mut curr: usize = 0; + let mut major: usize = 0; + let mut minor: usize = 0; + let mut patch: usize = 0; + + for &b in u.release().as_bytes() { + if curr >= 3 { + break; + } + + match b { + b'.' | b'-' => { + curr += 1; + } + b'0'..=b'9' => match curr { + 0 => digit(&mut major, b), + 1 => digit(&mut minor, b), + _ => digit(&mut patch, b), + }, + _ => break, + } + } + + Ok(if major >= 3 { + VERS_3 + } else if major >= 2 { + if minor >= 7 { + VERS_UNKNOWN + } else if minor >= 6 { + if patch >= 28 { + VERS_2_6_28 + } else if patch >= 27 { + VERS_2_6_27 + } else { + VERS_2_6_18 + } + } else { + VERS_UNKNOWN + } + } else { + VERS_UNKNOWN + }) + } + + fn kernel_version() -> Result { + static mut KERNEL_VERS: usize = 0; + + unsafe { + if KERNEL_VERS == 0 { + KERNEL_VERS = parse_kernel_version()?; + } + + Ok(KERNEL_VERS) + } + } + + /// Check if the OS supports atomic close-on-exec for sockets + pub fn socket_atomic_cloexec() -> bool { + kernel_version() + .map(|version| version >= VERS_2_6_27) + .unwrap_or(false) + } + + #[test] + pub fn test_parsing_kernel_version() { + assert!(kernel_version().unwrap() > 0); + } +} + +#[cfg(any( + target_os = "dragonfly", // Since ??? + target_os = "freebsd", // Since 10.0 + target_os = "illumos", // Since ??? + target_os = "netbsd", // Since 6.0 + target_os = "openbsd", // Since 5.7 + target_os = "redox", // Since 1-july-2020 +))] +mod os { + /// Check if the OS supports atomic close-on-exec for sockets + pub const fn socket_atomic_cloexec() -> bool { + true + } +} + +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "fuchsia", + target_os = "haiku", + target_os = "solaris" +))] +mod os { + /// Check if the OS supports atomic close-on-exec for sockets + pub const fn socket_atomic_cloexec() -> bool { + false + } +} diff --git a/vendor/nix-0.26.2/src/ifaddrs.rs b/vendor/nix-0.26.2/src/ifaddrs.rs new file mode 100644 index 0000000000000..70b50b01eb86a --- /dev/null +++ b/vendor/nix-0.26.2/src/ifaddrs.rs @@ -0,0 +1,213 @@ +//! Query network interface addresses +//! +//! Uses the Linux and/or BSD specific function `getifaddrs` to query the list +//! of interfaces and their associated addresses. + +use cfg_if::cfg_if; +#[cfg(any(target_os = "ios", target_os = "macos"))] +use std::convert::TryFrom; +use std::ffi; +use std::iter::Iterator; +use std::mem; +use std::option::Option; + +use crate::net::if_::*; +use crate::sys::socket::{SockaddrLike, SockaddrStorage}; +use crate::{Errno, Result}; + +/// Describes a single address for an interface as returned by `getifaddrs`. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct InterfaceAddress { + /// Name of the network interface + pub interface_name: String, + /// Flags as from `SIOCGIFFLAGS` ioctl + pub flags: InterfaceFlags, + /// Network address of this interface + pub address: Option, + /// Netmask of this interface + pub netmask: Option, + /// Broadcast address of this interface, if applicable + pub broadcast: Option, + /// Point-to-point destination address + pub destination: Option, +} + +cfg_if! { + if #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] { + fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr { + info.ifa_ifu + } + } else { + fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr { + info.ifa_dstaddr + } + } +} + +/// Workaround a bug in XNU where netmasks will always have the wrong size in +/// the sa_len field due to the kernel ignoring trailing zeroes in the structure +/// when setting the field. See https://github.com/nix-rust/nix/issues/1709#issuecomment-1199304470 +/// +/// To fix this, we stack-allocate a new sockaddr_storage, zero it out, and +/// memcpy sa_len of the netmask to that new storage. Finally, we reset the +/// ss_len field to sizeof(sockaddr_storage). This is supposedly valid as all +/// members of the sockaddr_storage are "ok" with being zeroed out (there are +/// no pointers). +#[cfg(any(target_os = "ios", target_os = "macos"))] +unsafe fn workaround_xnu_bug(info: &libc::ifaddrs) -> Option { + let src_sock = info.ifa_netmask; + if src_sock.is_null() { + return None; + } + + let mut dst_sock = mem::MaybeUninit::::zeroed(); + + // memcpy only sa_len bytes, assume the rest is zero + std::ptr::copy_nonoverlapping( + src_sock as *const u8, + dst_sock.as_mut_ptr() as *mut u8, + (*src_sock).sa_len.into(), + ); + + // Initialize ss_len to sizeof(libc::sockaddr_storage). + (*dst_sock.as_mut_ptr()).ss_len = + u8::try_from(mem::size_of::()).unwrap(); + let dst_sock = dst_sock.assume_init(); + + let dst_sock_ptr = + &dst_sock as *const libc::sockaddr_storage as *const libc::sockaddr; + + SockaddrStorage::from_raw(dst_sock_ptr, None) +} + +impl InterfaceAddress { + /// Create an `InterfaceAddress` from the libc struct. + fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress { + let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) }; + let address = unsafe { SockaddrStorage::from_raw(info.ifa_addr, None) }; + #[cfg(any(target_os = "ios", target_os = "macos"))] + let netmask = unsafe { workaround_xnu_bug(info) }; + #[cfg(not(any(target_os = "ios", target_os = "macos")))] + let netmask = + unsafe { SockaddrStorage::from_raw(info.ifa_netmask, None) }; + let mut addr = InterfaceAddress { + interface_name: ifname.to_string_lossy().to_string(), + flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32), + address, + netmask, + broadcast: None, + destination: None, + }; + + let ifu = get_ifu_from_sockaddr(info); + if addr.flags.contains(InterfaceFlags::IFF_POINTOPOINT) { + addr.destination = unsafe { SockaddrStorage::from_raw(ifu, None) }; + } else if addr.flags.contains(InterfaceFlags::IFF_BROADCAST) { + addr.broadcast = unsafe { SockaddrStorage::from_raw(ifu, None) }; + } + + addr + } +} + +/// Holds the results of `getifaddrs`. +/// +/// Use the function `getifaddrs` to create this Iterator. Note that the +/// actual list of interfaces can be iterated once and will be freed as +/// soon as the Iterator goes out of scope. +#[derive(Debug, Eq, Hash, PartialEq)] +pub struct InterfaceAddressIterator { + base: *mut libc::ifaddrs, + next: *mut libc::ifaddrs, +} + +impl Drop for InterfaceAddressIterator { + fn drop(&mut self) { + unsafe { libc::freeifaddrs(self.base) }; + } +} + +impl Iterator for InterfaceAddressIterator { + type Item = InterfaceAddress; + fn next(&mut self) -> Option<::Item> { + match unsafe { self.next.as_ref() } { + Some(ifaddr) => { + self.next = ifaddr.ifa_next; + Some(InterfaceAddress::from_libc_ifaddrs(ifaddr)) + } + None => None, + } + } +} + +/// Get interface addresses using libc's `getifaddrs` +/// +/// Note that the underlying implementation differs between OSes. Only the +/// most common address families are supported by the nix crate (due to +/// lack of time and complexity of testing). The address family is encoded +/// in the specific variant of `SockaddrStorage` returned for the fields +/// `address`, `netmask`, `broadcast`, and `destination`. For any entry not +/// supported, the returned list will contain a `None` entry. +/// +/// # Example +/// ``` +/// let addrs = nix::ifaddrs::getifaddrs().unwrap(); +/// for ifaddr in addrs { +/// match ifaddr.address { +/// Some(address) => { +/// println!("interface {} address {}", +/// ifaddr.interface_name, address); +/// }, +/// None => { +/// println!("interface {} with unsupported address family", +/// ifaddr.interface_name); +/// } +/// } +/// } +/// ``` +pub fn getifaddrs() -> Result { + let mut addrs = mem::MaybeUninit::<*mut libc::ifaddrs>::uninit(); + unsafe { + Errno::result(libc::getifaddrs(addrs.as_mut_ptr())).map(|_| { + InterfaceAddressIterator { + base: addrs.assume_init(), + next: addrs.assume_init(), + } + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // Only checks if `getifaddrs` can be invoked without panicking. + #[test] + fn test_getifaddrs() { + let _ = getifaddrs(); + } + + // Ensures getting the netmask works, and in particular that + // `workaround_xnu_bug` works properly. + #[test] + fn test_getifaddrs_netmask_correct() { + let addrs = getifaddrs().unwrap(); + for iface in addrs { + let sock = if let Some(sock) = iface.netmask { + sock + } else { + continue; + }; + if sock.family() == Some(crate::sys::socket::AddressFamily::Inet) { + let _ = sock.as_sockaddr_in().unwrap(); + return; + } else if sock.family() + == Some(crate::sys::socket::AddressFamily::Inet6) + { + let _ = sock.as_sockaddr_in6().unwrap(); + return; + } + } + panic!("No address?"); + } +} diff --git a/vendor/nix-0.26.2/src/kmod.rs b/vendor/nix-0.26.2/src/kmod.rs new file mode 100644 index 0000000000000..1fa6c170d95e3 --- /dev/null +++ b/vendor/nix-0.26.2/src/kmod.rs @@ -0,0 +1,128 @@ +//! Load and unload kernel modules. +//! +//! For more details see + +use std::ffi::CStr; +use std::os::unix::io::AsRawFd; + +use crate::errno::Errno; +use crate::Result; + +/// Loads a kernel module from a buffer. +/// +/// It loads an ELF image into kernel space, +/// performs any necessary symbol relocations, +/// initializes module parameters to values provided by the caller, +/// and then runs the module's init function. +/// +/// This function requires `CAP_SYS_MODULE` privilege. +/// +/// The `module_image` argument points to a buffer containing the binary image +/// to be loaded. The buffer should contain a valid ELF image +/// built for the running kernel. +/// +/// The `param_values` argument is a string containing space-delimited specifications +/// of the values for module parameters. +/// Each of the parameter specifications has the form: +/// +/// `name[=value[,value...]]` +/// +/// # Example +/// +/// ```no_run +/// use std::fs::File; +/// use std::io::Read; +/// use std::ffi::CString; +/// use nix::kmod::init_module; +/// +/// let mut f = File::open("mykernel.ko").unwrap(); +/// let mut contents: Vec = Vec::new(); +/// f.read_to_end(&mut contents).unwrap(); +/// init_module(&mut contents, &CString::new("who=Rust when=Now,12").unwrap()).unwrap(); +/// ``` +/// +/// See [`man init_module(2)`](https://man7.org/linux/man-pages/man2/init_module.2.html) for more information. +pub fn init_module(module_image: &[u8], param_values: &CStr) -> Result<()> { + let res = unsafe { + libc::syscall( + libc::SYS_init_module, + module_image.as_ptr(), + module_image.len(), + param_values.as_ptr(), + ) + }; + + Errno::result(res).map(drop) +} + +libc_bitflags!( + /// Flags used by the `finit_module` function. + pub struct ModuleInitFlags: libc::c_uint { + /// Ignore symbol version hashes. + MODULE_INIT_IGNORE_MODVERSIONS; + /// Ignore kernel version magic. + MODULE_INIT_IGNORE_VERMAGIC; + } +); + +/// Loads a kernel module from a given file descriptor. +/// +/// # Example +/// +/// ```no_run +/// use std::fs::File; +/// use std::ffi::CString; +/// use nix::kmod::{finit_module, ModuleInitFlags}; +/// +/// let f = File::open("mymod.ko").unwrap(); +/// finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()).unwrap(); +/// ``` +/// +/// See [`man init_module(2)`](https://man7.org/linux/man-pages/man2/init_module.2.html) for more information. +pub fn finit_module( + fd: &T, + param_values: &CStr, + flags: ModuleInitFlags, +) -> Result<()> { + let res = unsafe { + libc::syscall( + libc::SYS_finit_module, + fd.as_raw_fd(), + param_values.as_ptr(), + flags.bits(), + ) + }; + + Errno::result(res).map(drop) +} + +libc_bitflags!( + /// Flags used by `delete_module`. + /// + /// See [`man delete_module(2)`](https://man7.org/linux/man-pages/man2/delete_module.2.html) + /// for a detailed description how these flags work. + pub struct DeleteModuleFlags: libc::c_int { + O_NONBLOCK; + O_TRUNC; + } +); + +/// Unloads the kernel module with the given name. +/// +/// # Example +/// +/// ```no_run +/// use std::ffi::CString; +/// use nix::kmod::{delete_module, DeleteModuleFlags}; +/// +/// delete_module(&CString::new("mymod").unwrap(), DeleteModuleFlags::O_NONBLOCK).unwrap(); +/// ``` +/// +/// See [`man delete_module(2)`](https://man7.org/linux/man-pages/man2/delete_module.2.html) for more information. +pub fn delete_module(name: &CStr, flags: DeleteModuleFlags) -> Result<()> { + let res = unsafe { + libc::syscall(libc::SYS_delete_module, name.as_ptr(), flags.bits()) + }; + + Errno::result(res).map(drop) +} diff --git a/vendor/nix-0.26.2/src/lib.rs b/vendor/nix-0.26.2/src/lib.rs new file mode 100644 index 0000000000000..6b8212576129c --- /dev/null +++ b/vendor/nix-0.26.2/src/lib.rs @@ -0,0 +1,333 @@ +//! Rust friendly bindings to the various *nix system functions. +//! +//! Modules are structured according to the C header file that they would be +//! defined in. +//! +//! # Features +//! +//! Nix uses the following Cargo features to enable optional functionality. +//! They may be enabled in any combination. +//! * `acct` - Process accounting +//! * `aio` - POSIX AIO +//! * `dir` - Stuff relating to directory iteration +//! * `env` - Manipulate environment variables +//! * `event` - Event-driven APIs, like `kqueue` and `epoll` +//! * `feature` - Query characteristics of the OS at runtime +//! * `fs` - File system functionality +//! * `hostname` - Get and set the system's hostname +//! * `inotify` - Linux's `inotify` file system notification API +//! * `ioctl` - The `ioctl` syscall, and wrappers for my specific instances +//! * `kmod` - Load and unload kernel modules +//! * `mman` - Stuff relating to memory management +//! * `mount` - Mount and unmount file systems +//! * `mqueue` - POSIX message queues +//! * `net` - Networking-related functionality +//! * `personality` - Set the process execution domain +//! * `poll` - APIs like `poll` and `select` +//! * `process` - Stuff relating to running processes +//! * `pthread` - POSIX threads +//! * `ptrace` - Process tracing and debugging +//! * `quota` - File system quotas +//! * `reboot` - Reboot the system +//! * `resource` - Process resource limits +//! * `sched` - Manipulate process's scheduling +//! * `socket` - Sockets, whether for networking or local use +//! * `signal` - Send and receive signals to processes +//! * `term` - Terminal control APIs +//! * `time` - Query the operating system's clocks +//! * `ucontext` - User thread context +//! * `uio` - Vectored I/O +//! * `user` - Stuff relating to users and groups +//! * `zerocopy` - APIs like `sendfile` and `copy_file_range` +#![crate_name = "nix"] +#![cfg(unix)] +#![cfg_attr(docsrs, doc(cfg(all())))] +#![allow(non_camel_case_types)] +#![cfg_attr(test, deny(warnings))] +#![recursion_limit = "500"] +#![deny(unused)] +#![allow(unused_macros)] +#![cfg_attr(not(feature = "default"), allow(unused_imports))] +#![deny(unstable_features)] +#![deny(missing_copy_implementations)] +#![deny(missing_debug_implementations)] +#![warn(missing_docs)] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![deny(clippy::cast_ptr_alignment)] + +// Re-exported external crates +pub use libc; + +// Private internal modules +#[macro_use] +mod macros; + +// Public crates +#[cfg(not(target_os = "redox"))] +feature! { + #![feature = "dir"] + pub mod dir; +} +feature! { + #![feature = "env"] + pub mod env; +} +#[allow(missing_docs)] +pub mod errno; +feature! { + #![feature = "feature"] + + #[deny(missing_docs)] + pub mod features; +} +#[allow(missing_docs)] +pub mod fcntl; +feature! { + #![feature = "net"] + + #[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd"))] + #[deny(missing_docs)] + pub mod ifaddrs; + #[cfg(not(target_os = "redox"))] + #[deny(missing_docs)] + pub mod net; +} +#[cfg(any(target_os = "android", target_os = "linux"))] +feature! { + #![feature = "kmod"] + #[allow(missing_docs)] + pub mod kmod; +} +feature! { + #![feature = "mount"] + pub mod mount; +} +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd" +))] +feature! { + #![feature = "mqueue"] + pub mod mqueue; +} +feature! { + #![feature = "poll"] + pub mod poll; +} +#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] +feature! { + #![feature = "term"] + #[deny(missing_docs)] + pub mod pty; +} +feature! { + #![feature = "sched"] + pub mod sched; +} +pub mod sys; +feature! { + #![feature = "time"] + #[allow(missing_docs)] + pub mod time; +} +// This can be implemented for other platforms as soon as libc +// provides bindings for them. +#[cfg(all( + target_os = "linux", + any(target_arch = "s390x", target_arch = "x86", target_arch = "x86_64") +))] +feature! { + #![feature = "ucontext"] + #[allow(missing_docs)] + pub mod ucontext; +} +#[allow(missing_docs)] +pub mod unistd; + +use std::ffi::{CStr, CString, OsStr}; +use std::mem::MaybeUninit; +use std::os::unix::ffi::OsStrExt; +use std::path::{Path, PathBuf}; +use std::{ptr, result, slice}; + +use errno::Errno; + +/// Nix Result Type +pub type Result = result::Result; + +/// Nix's main error type. +/// +/// It's a wrapper around Errno. As such, it's very interoperable with +/// [`std::io::Error`], but it has the advantages of: +/// * `Clone` +/// * `Copy` +/// * `Eq` +/// * Small size +/// * Represents all of the system's errnos, instead of just the most common +/// ones. +pub type Error = Errno; + +/// Common trait used to represent file system paths by many Nix functions. +pub trait NixPath { + /// Is the path empty? + fn is_empty(&self) -> bool; + + /// Length of the path in bytes + fn len(&self) -> usize; + + /// Execute a function with this path as a `CStr`. + /// + /// Mostly used internally by Nix. + fn with_nix_path(&self, f: F) -> Result + where + F: FnOnce(&CStr) -> T; +} + +impl NixPath for str { + fn is_empty(&self) -> bool { + NixPath::is_empty(OsStr::new(self)) + } + + fn len(&self) -> usize { + NixPath::len(OsStr::new(self)) + } + + fn with_nix_path(&self, f: F) -> Result + where + F: FnOnce(&CStr) -> T, + { + OsStr::new(self).with_nix_path(f) + } +} + +impl NixPath for OsStr { + fn is_empty(&self) -> bool { + self.as_bytes().is_empty() + } + + fn len(&self) -> usize { + self.as_bytes().len() + } + + fn with_nix_path(&self, f: F) -> Result + where + F: FnOnce(&CStr) -> T, + { + self.as_bytes().with_nix_path(f) + } +} + +impl NixPath for CStr { + fn is_empty(&self) -> bool { + self.to_bytes().is_empty() + } + + fn len(&self) -> usize { + self.to_bytes().len() + } + + fn with_nix_path(&self, f: F) -> Result + where + F: FnOnce(&CStr) -> T, + { + Ok(f(self)) + } +} + +impl NixPath for [u8] { + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn len(&self) -> usize { + self.len() + } + + fn with_nix_path(&self, f: F) -> Result + where + F: FnOnce(&CStr) -> T, + { + // The real PATH_MAX is typically 4096, but it's statistically unlikely to have a path + // longer than ~300 bytes. See the the PR description to get stats for your own machine. + // https://github.com/nix-rust/nix/pull/1656 + // + // By being smaller than a memory page, we also avoid the compiler inserting a probe frame: + // https://docs.rs/compiler_builtins/latest/compiler_builtins/probestack/index.html + const MAX_STACK_ALLOCATION: usize = 1024; + + if self.len() >= MAX_STACK_ALLOCATION { + return with_nix_path_allocating(self, f); + } + + let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit(); + let buf_ptr = buf.as_mut_ptr() as *mut u8; + + unsafe { + ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len()); + buf_ptr.add(self.len()).write(0); + } + + match CStr::from_bytes_with_nul(unsafe { + slice::from_raw_parts(buf_ptr, self.len() + 1) + }) { + Ok(s) => Ok(f(s)), + Err(_) => Err(Errno::EINVAL), + } + } +} + +#[cold] +#[inline(never)] +fn with_nix_path_allocating(from: &[u8], f: F) -> Result +where + F: FnOnce(&CStr) -> T, +{ + match CString::new(from) { + Ok(s) => Ok(f(&s)), + Err(_) => Err(Errno::EINVAL), + } +} + +impl NixPath for Path { + fn is_empty(&self) -> bool { + NixPath::is_empty(self.as_os_str()) + } + + fn len(&self) -> usize { + NixPath::len(self.as_os_str()) + } + + fn with_nix_path(&self, f: F) -> Result + where + F: FnOnce(&CStr) -> T, + { + self.as_os_str().with_nix_path(f) + } +} + +impl NixPath for PathBuf { + fn is_empty(&self) -> bool { + NixPath::is_empty(self.as_os_str()) + } + + fn len(&self) -> usize { + NixPath::len(self.as_os_str()) + } + + fn with_nix_path(&self, f: F) -> Result + where + F: FnOnce(&CStr) -> T, + { + self.as_os_str().with_nix_path(f) + } +} diff --git a/vendor/nix-0.26.2/src/macros.rs b/vendor/nix-0.26.2/src/macros.rs new file mode 100644 index 0000000000000..99e0de88662fb --- /dev/null +++ b/vendor/nix-0.26.2/src/macros.rs @@ -0,0 +1,328 @@ +// Thanks to Tokio for this macro +macro_rules! feature { + ( + #![$meta:meta] + $($item:item)* + ) => { + $( + #[cfg($meta)] + #[cfg_attr(docsrs, doc(cfg($meta)))] + $item + )* + } +} + +/// The `libc_bitflags!` macro helps with a common use case of defining a public bitflags type +/// with values from the libc crate. It is used the same way as the `bitflags!` macro, except +/// that only the name of the flag value has to be given. +/// +/// The `libc` crate must be in scope with the name `libc`. +/// +/// # Example +/// ```ignore +/// libc_bitflags!{ +/// pub struct ProtFlags: libc::c_int { +/// PROT_NONE; +/// PROT_READ; +/// /// PROT_WRITE enables write protect +/// PROT_WRITE; +/// PROT_EXEC; +/// #[cfg(any(target_os = "linux", target_os = "android"))] +/// PROT_GROWSDOWN; +/// #[cfg(any(target_os = "linux", target_os = "android"))] +/// PROT_GROWSUP; +/// } +/// } +/// ``` +/// +/// Example with casting, due to a mistake in libc. In this example, the +/// various flags have different types, so we cast the broken ones to the right +/// type. +/// +/// ```ignore +/// libc_bitflags!{ +/// pub struct SaFlags: libc::c_ulong { +/// SA_NOCLDSTOP as libc::c_ulong; +/// SA_NOCLDWAIT; +/// SA_NODEFER as libc::c_ulong; +/// SA_ONSTACK; +/// SA_RESETHAND as libc::c_ulong; +/// SA_RESTART as libc::c_ulong; +/// SA_SIGINFO; +/// } +/// } +/// ``` +macro_rules! libc_bitflags { + ( + $(#[$outer:meta])* + pub struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + $Flag:ident $(as $cast:ty)*; + )+ + } + ) => { + ::bitflags::bitflags! { + $(#[$outer])* + pub struct $BitFlags: $T { + $( + $(#[$inner $($args)*])* + const $Flag = libc::$Flag $(as $cast)*; + )+ + } + } + }; +} + +/// The `libc_enum!` macro helps with a common use case of defining an enum exclusively using +/// values from the `libc` crate. This macro supports both `pub` and private `enum`s. +/// +/// The `libc` crate must be in scope with the name `libc`. +/// +/// # Example +/// ```ignore +/// libc_enum!{ +/// pub enum ProtFlags { +/// PROT_NONE, +/// PROT_READ, +/// PROT_WRITE, +/// PROT_EXEC, +/// #[cfg(any(target_os = "linux", target_os = "android"))] +/// PROT_GROWSDOWN, +/// #[cfg(any(target_os = "linux", target_os = "android"))] +/// PROT_GROWSUP, +/// } +/// } +/// ``` +// Some targets don't use all rules. +#[allow(unknown_lints)] +#[allow(unused_macro_rules)] +macro_rules! libc_enum { + // Exit rule. + (@make_enum + name: $BitFlags:ident, + { + $v:vis + attrs: [$($attrs:tt)*], + entries: [$($entries:tt)*], + } + ) => { + $($attrs)* + #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] + $v enum $BitFlags { + $($entries)* + } + }; + + // Exit rule including TryFrom + (@make_enum + name: $BitFlags:ident, + { + $v:vis + attrs: [$($attrs:tt)*], + entries: [$($entries:tt)*], + from_type: $repr:path, + try_froms: [$($try_froms:tt)*] + } + ) => { + $($attrs)* + #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] + $v enum $BitFlags { + $($entries)* + } + impl ::std::convert::TryFrom<$repr> for $BitFlags { + type Error = $crate::Error; + #[allow(unused_doc_comments)] + fn try_from(x: $repr) -> $crate::Result { + match x { + $($try_froms)* + _ => Err($crate::Error::EINVAL) + } + } + } + }; + + // Done accumulating. + (@accumulate_entries + name: $BitFlags:ident, + { + $v:vis + attrs: $attrs:tt, + }, + $entries:tt, + $try_froms:tt; + ) => { + libc_enum! { + @make_enum + name: $BitFlags, + { + $v + attrs: $attrs, + entries: $entries, + } + } + }; + + // Done accumulating and want TryFrom + (@accumulate_entries + name: $BitFlags:ident, + { + $v:vis + attrs: $attrs:tt, + from_type: $repr:path, + }, + $entries:tt, + $try_froms:tt; + ) => { + libc_enum! { + @make_enum + name: $BitFlags, + { + $v + attrs: $attrs, + entries: $entries, + from_type: $repr, + try_froms: $try_froms + } + } + }; + + // Munch an attr. + (@accumulate_entries + name: $BitFlags:ident, + $prefix:tt, + [$($entries:tt)*], + [$($try_froms:tt)*]; + #[$attr:meta] $($tail:tt)* + ) => { + libc_enum! { + @accumulate_entries + name: $BitFlags, + $prefix, + [ + $($entries)* + #[$attr] + ], + [ + $($try_froms)* + #[$attr] + ]; + $($tail)* + } + }; + + // Munch last ident if not followed by a comma. + (@accumulate_entries + name: $BitFlags:ident, + $prefix:tt, + [$($entries:tt)*], + [$($try_froms:tt)*]; + $entry:ident + ) => { + libc_enum! { + @accumulate_entries + name: $BitFlags, + $prefix, + [ + $($entries)* + $entry = libc::$entry, + ], + [ + $($try_froms)* + libc::$entry => Ok($BitFlags::$entry), + ]; + } + }; + + // Munch an ident; covers terminating comma case. + (@accumulate_entries + name: $BitFlags:ident, + $prefix:tt, + [$($entries:tt)*], + [$($try_froms:tt)*]; + $entry:ident, + $($tail:tt)* + ) => { + libc_enum! { + @accumulate_entries + name: $BitFlags, + $prefix, + [ + $($entries)* + $entry = libc::$entry, + ], + [ + $($try_froms)* + libc::$entry => Ok($BitFlags::$entry), + ]; + $($tail)* + } + }; + + // Munch an ident and cast it to the given type; covers terminating comma. + (@accumulate_entries + name: $BitFlags:ident, + $prefix:tt, + [$($entries:tt)*], + [$($try_froms:tt)*]; + $entry:ident as $ty:ty, + $($tail:tt)* + ) => { + libc_enum! { + @accumulate_entries + name: $BitFlags, + $prefix, + [ + $($entries)* + $entry = libc::$entry as $ty, + ], + [ + $($try_froms)* + libc::$entry as $ty => Ok($BitFlags::$entry), + ]; + $($tail)* + } + }; + + // Entry rule. + ( + $(#[$attr:meta])* + $v:vis enum $BitFlags:ident { + $($vals:tt)* + } + ) => { + libc_enum! { + @accumulate_entries + name: $BitFlags, + { + $v + attrs: [$(#[$attr])*], + }, + [], + []; + $($vals)* + } + }; + + // Entry rule including TryFrom + ( + $(#[$attr:meta])* + $v:vis enum $BitFlags:ident { + $($vals:tt)* + } + impl TryFrom<$repr:path> + ) => { + libc_enum! { + @accumulate_entries + name: $BitFlags, + { + $v + attrs: [$(#[$attr])*], + from_type: $repr, + }, + [], + []; + $($vals)* + } + }; +} diff --git a/vendor/nix-0.26.2/src/mount/bsd.rs b/vendor/nix-0.26.2/src/mount/bsd.rs new file mode 100644 index 0000000000000..d124f1f9ab14e --- /dev/null +++ b/vendor/nix-0.26.2/src/mount/bsd.rs @@ -0,0 +1,453 @@ +#[cfg(target_os = "freebsd")] +use crate::Error; +use crate::{Errno, NixPath, Result}; +use libc::c_int; +#[cfg(target_os = "freebsd")] +use libc::{c_char, c_uint, c_void}; +#[cfg(target_os = "freebsd")] +use std::{ + borrow::Cow, + ffi::{CStr, CString}, + fmt, io, + marker::PhantomData, +}; + +libc_bitflags!( + /// Used with [`Nmount::nmount`]. + pub struct MntFlags: c_int { + /// ACL support enabled. + #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MNT_ACLS; + /// All I/O to the file system should be done asynchronously. + MNT_ASYNC; + /// dir should instead be a file system ID encoded as “FSID:val0:val1â€. + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MNT_BYFSID; + /// Force a read-write mount even if the file system appears to be + /// unclean. + MNT_FORCE; + /// GEOM journal support enabled. + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MNT_GJOURNAL; + /// MAC support for objects. + #[cfg(any(target_os = "macos", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MNT_MULTILABEL; + /// Disable read clustering. + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MNT_NOCLUSTERR; + /// Disable write clustering. + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MNT_NOCLUSTERW; + /// Enable NFS version 4 ACLs. + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MNT_NFS4ACLS; + /// Do not update access times. + MNT_NOATIME; + /// Disallow program execution. + MNT_NOEXEC; + /// Do not honor setuid or setgid bits on files when executing them. + MNT_NOSUID; + /// Do not follow symlinks. + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MNT_NOSYMFOLLOW; + /// Mount read-only. + MNT_RDONLY; + /// Causes the vfs subsystem to update its data structures pertaining to + /// the specified already mounted file system. + MNT_RELOAD; + /// Create a snapshot of the file system. + /// + /// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs) + #[cfg(any(target_os = "macos", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MNT_SNAPSHOT; + /// Using soft updates. + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MNT_SOFTDEP; + /// Directories with the SUID bit set chown new files to their own + /// owner. + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MNT_SUIDDIR; + /// All I/O to the file system should be done synchronously. + MNT_SYNCHRONOUS; + /// Union with underlying fs. + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MNT_UNION; + /// Indicates that the mount command is being applied to an already + /// mounted file system. + MNT_UPDATE; + /// Check vnode use counts. + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MNT_NONBUSY; + } +); + +/// The Error type of [`Nmount::nmount`]. +/// +/// It wraps an [`Errno`], but also may contain an additional message returned +/// by `nmount(2)`. +#[cfg(target_os = "freebsd")] +#[derive(Debug)] +pub struct NmountError { + errno: Error, + errmsg: Option, +} + +#[cfg(target_os = "freebsd")] +impl NmountError { + /// Returns the additional error string sometimes generated by `nmount(2)`. + pub fn errmsg(&self) -> Option<&str> { + self.errmsg.as_deref() + } + + /// Returns the inner [`Error`] + pub const fn error(&self) -> Error { + self.errno + } + + fn new(error: Error, errmsg: Option<&CStr>) -> Self { + Self { + errno: error, + errmsg: errmsg.map(CStr::to_string_lossy).map(Cow::into_owned), + } + } +} + +#[cfg(target_os = "freebsd")] +impl std::error::Error for NmountError {} + +#[cfg(target_os = "freebsd")] +impl fmt::Display for NmountError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(errmsg) = &self.errmsg { + write!(f, "{:?}: {}: {}", self.errno, errmsg, self.errno.desc()) + } else { + write!(f, "{:?}: {}", self.errno, self.errno.desc()) + } + } +} + +#[cfg(target_os = "freebsd")] +impl From for io::Error { + fn from(err: NmountError) -> Self { + err.errno.into() + } +} + +/// Result type of [`Nmount::nmount`]. +#[cfg(target_os = "freebsd")] +pub type NmountResult = std::result::Result<(), NmountError>; + +/// Mount a FreeBSD file system. +/// +/// The `nmount(2)` system call works similarly to the `mount(8)` program; it +/// takes its options as a series of name-value pairs. Most of the values are +/// strings, as are all of the names. The `Nmount` structure builds up an +/// argument list and then executes the syscall. +/// +/// # Examples +/// +/// To mount `target` onto `mountpoint` with `nullfs`: +/// ``` +/// # use nix::unistd::Uid; +/// # use ::sysctl::{CtlValue, Sysctl}; +/// # let ctl = ::sysctl::Ctl::new("vfs.usermount").unwrap(); +/// # if !Uid::current().is_root() && CtlValue::Int(0) == ctl.value().unwrap() { +/// # return; +/// # }; +/// use nix::mount::{MntFlags, Nmount, unmount}; +/// use std::ffi::CString; +/// use tempfile::tempdir; +/// +/// let mountpoint = tempdir().unwrap(); +/// let target = tempdir().unwrap(); +/// +/// let fstype = CString::new("fstype").unwrap(); +/// let nullfs = CString::new("nullfs").unwrap(); +/// Nmount::new() +/// .str_opt(&fstype, &nullfs) +/// .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) +/// .str_opt_owned("target", target.path().to_str().unwrap()) +/// .nmount(MntFlags::empty()).unwrap(); +/// +/// unmount(mountpoint.path(), MntFlags::empty()).unwrap(); +/// ``` +/// +/// # See Also +/// * [`nmount(2)`](https://www.freebsd.org/cgi/man.cgi?query=nmount) +/// * [`nullfs(5)`](https://www.freebsd.org/cgi/man.cgi?query=nullfs) +#[cfg(target_os = "freebsd")] +#[cfg_attr(docsrs, doc(cfg(all())))] +#[derive(Debug, Default)] +pub struct Nmount<'a> { + // n.b. notgull: In reality, this is a list that contains + // both mutable and immutable pointers. + // Be careful using this. + iov: Vec, + is_owned: Vec, + marker: PhantomData<&'a ()>, +} + +#[cfg(target_os = "freebsd")] +#[cfg_attr(docsrs, doc(cfg(all())))] +impl<'a> Nmount<'a> { + /// Helper function to push a slice onto the `iov` array. + fn push_slice(&mut self, val: &'a [u8], is_owned: bool) { + self.iov.push(libc::iovec { + iov_base: val.as_ptr() as *mut _, + iov_len: val.len(), + }); + self.is_owned.push(is_owned); + } + + /// Helper function to push a pointer and its length onto the `iov` array. + fn push_pointer_and_length( + &mut self, + val: *const u8, + len: usize, + is_owned: bool, + ) { + self.iov.push(libc::iovec { + iov_base: val as *mut _, + iov_len: len, + }); + self.is_owned.push(is_owned); + } + + /// Helper function to push a `nix` path as owned. + fn push_nix_path(&mut self, val: &P) { + val.with_nix_path(|s| { + let len = s.to_bytes_with_nul().len(); + let ptr = s.to_owned().into_raw() as *const u8; + + self.push_pointer_and_length(ptr, len, true); + }) + .unwrap(); + } + + /// Add an opaque mount option. + /// + /// Some file systems take binary-valued mount options. They can be set + /// with this method. + /// + /// # Safety + /// + /// Unsafe because it will cause `Nmount::nmount` to dereference a raw + /// pointer. The user is responsible for ensuring that `val` is valid and + /// its lifetime outlives `self`! An easy way to do that is to give the + /// value a larger scope than `name` + /// + /// # Examples + /// ``` + /// use libc::c_void; + /// use nix::mount::Nmount; + /// use std::ffi::CString; + /// use std::mem; + /// + /// // Note that flags outlives name + /// let mut flags: u32 = 0xdeadbeef; + /// let name = CString::new("flags").unwrap(); + /// let p = &mut flags as *mut u32 as *mut c_void; + /// let len = mem::size_of_val(&flags); + /// let mut nmount = Nmount::new(); + /// unsafe { nmount.mut_ptr_opt(&name, p, len) }; + /// ``` + pub unsafe fn mut_ptr_opt( + &mut self, + name: &'a CStr, + val: *mut c_void, + len: usize, + ) -> &mut Self { + self.push_slice(name.to_bytes_with_nul(), false); + self.push_pointer_and_length(val.cast(), len, false); + self + } + + /// Add a mount option that does not take a value. + /// + /// # Examples + /// ``` + /// use nix::mount::Nmount; + /// use std::ffi::CString; + /// + /// let read_only = CString::new("ro").unwrap(); + /// Nmount::new() + /// .null_opt(&read_only); + /// ``` + pub fn null_opt(&mut self, name: &'a CStr) -> &mut Self { + self.push_slice(name.to_bytes_with_nul(), false); + self.push_slice(&[], false); + self + } + + /// Add a mount option that does not take a value, but whose name must be + /// owned. + /// + /// + /// This has higher runtime cost than [`Nmount::null_opt`], but is useful + /// when the name's lifetime doesn't outlive the `Nmount`, or it's a + /// different string type than `CStr`. + /// + /// # Examples + /// ``` + /// use nix::mount::Nmount; + /// + /// let read_only = "ro"; + /// let mut nmount: Nmount<'static> = Nmount::new(); + /// nmount.null_opt_owned(read_only); + /// ``` + pub fn null_opt_owned( + &mut self, + name: &P, + ) -> &mut Self { + self.push_nix_path(name); + self.push_slice(&[], false); + self + } + + /// Add a mount option as a [`CStr`]. + /// + /// # Examples + /// ``` + /// use nix::mount::Nmount; + /// use std::ffi::CString; + /// + /// let fstype = CString::new("fstype").unwrap(); + /// let nullfs = CString::new("nullfs").unwrap(); + /// Nmount::new() + /// .str_opt(&fstype, &nullfs); + /// ``` + pub fn str_opt(&mut self, name: &'a CStr, val: &'a CStr) -> &mut Self { + self.push_slice(name.to_bytes_with_nul(), false); + self.push_slice(val.to_bytes_with_nul(), false); + self + } + + /// Add a mount option as an owned string. + /// + /// This has higher runtime cost than [`Nmount::str_opt`], but is useful + /// when the value's lifetime doesn't outlive the `Nmount`, or it's a + /// different string type than `CStr`. + /// + /// # Examples + /// ``` + /// use nix::mount::Nmount; + /// use std::path::Path; + /// + /// let mountpoint = Path::new("/mnt"); + /// Nmount::new() + /// .str_opt_owned("fspath", mountpoint.to_str().unwrap()); + /// ``` + pub fn str_opt_owned(&mut self, name: &P1, val: &P2) -> &mut Self + where + P1: ?Sized + NixPath, + P2: ?Sized + NixPath, + { + self.push_nix_path(name); + self.push_nix_path(val); + self + } + + /// Create a new `Nmount` struct with no options + pub fn new() -> Self { + Self::default() + } + + /// Actually mount the file system. + pub fn nmount(&mut self, flags: MntFlags) -> NmountResult { + const ERRMSG_NAME: &[u8] = b"errmsg\0"; + let mut errmsg = vec![0u8; 255]; + + // nmount can return extra error information via a "errmsg" return + // argument. + self.push_slice(ERRMSG_NAME, false); + + // SAFETY: we are pushing a mutable iovec here, so we can't use + // the above method + self.iov.push(libc::iovec { + iov_base: errmsg.as_mut_ptr() as *mut c_void, + iov_len: errmsg.len(), + }); + + let niov = self.iov.len() as c_uint; + let iovp = self.iov.as_mut_ptr() as *mut libc::iovec; + let res = unsafe { libc::nmount(iovp, niov, flags.bits) }; + match Errno::result(res) { + Ok(_) => Ok(()), + Err(error) => { + let errmsg = match errmsg.iter().position(|&x| x == 0) { + None => None, + Some(0) => None, + Some(n) => { + let sl = &errmsg[0..n + 1]; + Some(CStr::from_bytes_with_nul(sl).unwrap()) + } + }; + Err(NmountError::new(error, errmsg)) + } + } + } +} + +#[cfg(target_os = "freebsd")] +impl<'a> Drop for Nmount<'a> { + fn drop(&mut self) { + for (iov, is_owned) in self.iov.iter().zip(self.is_owned.iter()) { + if *is_owned { + // Free the owned string. Safe because we recorded ownership, + // and Nmount does not implement Clone. + unsafe { + drop(CString::from_raw(iov.iov_base as *mut c_char)); + } + } + } + } +} + +/// Unmount the file system mounted at `mountpoint`. +/// +/// Useful flags include +/// * `MNT_FORCE` - Unmount even if still in use. +#[cfg_attr( + target_os = "freebsd", + doc = " +* `MNT_BYFSID` - `mountpoint` is not a path, but a file system ID + encoded as `FSID:val0:val1`, where `val0` and `val1` + are the contents of the `fsid_t val[]` array in decimal. + The file system that has the specified file system ID + will be unmounted. See + [`statfs`](crate::sys::statfs::statfs) to determine the + `fsid`. +" +)] +pub fn unmount

(mountpoint: &P, flags: MntFlags) -> Result<()> +where + P: ?Sized + NixPath, +{ + let res = mountpoint.with_nix_path(|cstr| unsafe { + libc::unmount(cstr.as_ptr(), flags.bits) + })?; + + Errno::result(res).map(drop) +} diff --git a/vendor/nix-0.26.2/src/mount/linux.rs b/vendor/nix-0.26.2/src/mount/linux.rs new file mode 100644 index 0000000000000..cf6a60b017800 --- /dev/null +++ b/vendor/nix-0.26.2/src/mount/linux.rs @@ -0,0 +1,115 @@ +#![allow(missing_docs)] +use crate::errno::Errno; +use crate::{NixPath, Result}; +use libc::{self, c_int, c_ulong}; + +libc_bitflags!( + pub struct MsFlags: c_ulong { + /// Mount read-only + MS_RDONLY; + /// Ignore suid and sgid bits + MS_NOSUID; + /// Disallow access to device special files + MS_NODEV; + /// Disallow program execution + MS_NOEXEC; + /// Writes are synced at once + MS_SYNCHRONOUS; + /// Alter flags of a mounted FS + MS_REMOUNT; + /// Allow mandatory locks on a FS + MS_MANDLOCK; + /// Directory modifications are synchronous + MS_DIRSYNC; + /// Do not update access times + MS_NOATIME; + /// Do not update directory access times + MS_NODIRATIME; + /// Linux 2.4.0 - Bind directory at different place + MS_BIND; + MS_MOVE; + MS_REC; + MS_SILENT; + MS_POSIXACL; + MS_UNBINDABLE; + MS_PRIVATE; + MS_SLAVE; + MS_SHARED; + MS_RELATIME; + MS_KERNMOUNT; + MS_I_VERSION; + MS_STRICTATIME; + MS_LAZYTIME; + MS_ACTIVE; + MS_NOUSER; + MS_RMT_MASK; + MS_MGC_VAL; + MS_MGC_MSK; + } +); + +libc_bitflags!( + pub struct MntFlags: c_int { + MNT_FORCE; + MNT_DETACH; + MNT_EXPIRE; + UMOUNT_NOFOLLOW; + } +); + +pub fn mount< + P1: ?Sized + NixPath, + P2: ?Sized + NixPath, + P3: ?Sized + NixPath, + P4: ?Sized + NixPath, +>( + source: Option<&P1>, + target: &P2, + fstype: Option<&P3>, + flags: MsFlags, + data: Option<&P4>, +) -> Result<()> { + fn with_opt_nix_path(p: Option<&P>, f: F) -> Result + where + P: ?Sized + NixPath, + F: FnOnce(*const libc::c_char) -> T, + { + match p { + Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())), + None => Ok(f(std::ptr::null())), + } + } + + let res = with_opt_nix_path(source, |s| { + target.with_nix_path(|t| { + with_opt_nix_path(fstype, |ty| { + with_opt_nix_path(data, |d| unsafe { + libc::mount( + s, + t.as_ptr(), + ty, + flags.bits, + d as *const libc::c_void, + ) + }) + }) + }) + })????; + + Errno::result(res).map(drop) +} + +pub fn umount(target: &P) -> Result<()> { + let res = + target.with_nix_path(|cstr| unsafe { libc::umount(cstr.as_ptr()) })?; + + Errno::result(res).map(drop) +} + +pub fn umount2(target: &P, flags: MntFlags) -> Result<()> { + let res = target.with_nix_path(|cstr| unsafe { + libc::umount2(cstr.as_ptr(), flags.bits) + })?; + + Errno::result(res).map(drop) +} diff --git a/vendor/nix-0.26.2/src/mount/mod.rs b/vendor/nix-0.26.2/src/mount/mod.rs new file mode 100644 index 0000000000000..e98b49c3435ba --- /dev/null +++ b/vendor/nix-0.26.2/src/mount/mod.rs @@ -0,0 +1,26 @@ +//! Mount file systems +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +mod linux; + +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use self::linux::*; + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] +#[cfg_attr(docsrs, doc(cfg(all())))] +mod bsd; + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] +pub use self::bsd::*; diff --git a/vendor/nix-0.26.2/src/mqueue.rs b/vendor/nix-0.26.2/src/mqueue.rs new file mode 100644 index 0000000000000..33599bf91d540 --- /dev/null +++ b/vendor/nix-0.26.2/src/mqueue.rs @@ -0,0 +1,276 @@ +//! Posix Message Queue functions +//! +//! # Example +//! +// no_run because a kernel module may be required. +//! ```no_run +//! # use std::ffi::CString; +//! # use nix::mqueue::*; +//! use nix::sys::stat::Mode; +//! +//! const MSG_SIZE: mq_attr_member_t = 32; +//! let mq_name= CString::new("/a_nix_test_queue").unwrap(); +//! +//! let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; +//! let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; +//! let mqd0 = mq_open(&mq_name, oflag0, mode, None).unwrap(); +//! let msg_to_send = b"msg_1"; +//! mq_send(&mqd0, msg_to_send, 1).unwrap(); +//! +//! let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY; +//! let mqd1 = mq_open(&mq_name, oflag1, mode, None).unwrap(); +//! let mut buf = [0u8; 32]; +//! let mut prio = 0u32; +//! let len = mq_receive(&mqd1, &mut buf, &mut prio).unwrap(); +//! assert_eq!(prio, 1); +//! assert_eq!(msg_to_send, &buf[0..len]); +//! +//! mq_close(mqd1).unwrap(); +//! mq_close(mqd0).unwrap(); +//! ``` +//! [Further reading and details on the C API](https://man7.org/linux/man-pages/man7/mq_overview.7.html) + +use crate::errno::Errno; +use crate::Result; + +use crate::sys::stat::Mode; +use libc::{self, c_char, mqd_t, size_t}; +use std::ffi::CStr; +use std::mem; + +libc_bitflags! { + /// Used with [`mq_open`]. + pub struct MQ_OFlag: libc::c_int { + /// Open the message queue for receiving messages. + O_RDONLY; + /// Open the queue for sending messages. + O_WRONLY; + /// Open the queue for both receiving and sending messages + O_RDWR; + /// Create a message queue. + O_CREAT; + /// If set along with `O_CREAT`, `mq_open` will fail if the message + /// queue name exists. + O_EXCL; + /// `mq_send` and `mq_receive` should fail with `EAGAIN` rather than + /// wait for resources that are not currently available. + O_NONBLOCK; + /// Set the close-on-exec flag for the message queue descriptor. + O_CLOEXEC; + } +} + +/// A message-queue attribute, optionally used with [`mq_setattr`] and +/// [`mq_getattr`] and optionally [`mq_open`], +#[repr(C)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct MqAttr { + mq_attr: libc::mq_attr, +} + +/// Identifies an open POSIX Message Queue +// A safer wrapper around libc::mqd_t, which is a pointer on some platforms +// Deliberately is not Clone to prevent use-after-close scenarios +#[repr(transparent)] +#[derive(Debug)] +#[allow(missing_copy_implementations)] +pub struct MqdT(mqd_t); + +// x32 compatibility +// See https://sourceware.org/bugzilla/show_bug.cgi?id=21279 +/// Size of a message queue attribute member +#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub type mq_attr_member_t = i64; +/// Size of a message queue attribute member +#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub type mq_attr_member_t = libc::c_long; + +impl MqAttr { + /// Create a new message queue attribute + /// + /// # Arguments + /// + /// - `mq_flags`: Either `0` or `O_NONBLOCK`. + /// - `mq_maxmsg`: Maximum number of messages on the queue. + /// - `mq_msgsize`: Maximum message size in bytes. + /// - `mq_curmsgs`: Number of messages currently in the queue. + pub fn new( + mq_flags: mq_attr_member_t, + mq_maxmsg: mq_attr_member_t, + mq_msgsize: mq_attr_member_t, + mq_curmsgs: mq_attr_member_t, + ) -> MqAttr { + let mut attr = mem::MaybeUninit::::uninit(); + unsafe { + let p = attr.as_mut_ptr(); + (*p).mq_flags = mq_flags; + (*p).mq_maxmsg = mq_maxmsg; + (*p).mq_msgsize = mq_msgsize; + (*p).mq_curmsgs = mq_curmsgs; + MqAttr { + mq_attr: attr.assume_init(), + } + } + } + + /// The current flags, either `0` or `O_NONBLOCK`. + pub const fn flags(&self) -> mq_attr_member_t { + self.mq_attr.mq_flags + } + + /// The max number of messages that can be held by the queue + pub const fn maxmsg(&self) -> mq_attr_member_t { + self.mq_attr.mq_maxmsg + } + + /// The maximum size of each message (in bytes) + pub const fn msgsize(&self) -> mq_attr_member_t { + self.mq_attr.mq_msgsize + } + + /// The number of messages currently held in the queue + pub const fn curmsgs(&self) -> mq_attr_member_t { + self.mq_attr.mq_curmsgs + } +} + +/// Open a message queue +/// +/// See also [`mq_open(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html) +// The mode.bits cast is only lossless on some OSes +#[allow(clippy::cast_lossless)] +pub fn mq_open( + name: &CStr, + oflag: MQ_OFlag, + mode: Mode, + attr: Option<&MqAttr>, +) -> Result { + let res = match attr { + Some(mq_attr) => unsafe { + libc::mq_open( + name.as_ptr(), + oflag.bits(), + mode.bits() as libc::c_int, + &mq_attr.mq_attr as *const libc::mq_attr, + ) + }, + None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) }, + }; + Errno::result(res).map(MqdT) +} + +/// Remove a message queue +/// +/// See also [`mq_unlink(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html) +pub fn mq_unlink(name: &CStr) -> Result<()> { + let res = unsafe { libc::mq_unlink(name.as_ptr()) }; + Errno::result(res).map(drop) +} + +/// Close a message queue +/// +/// See also [`mq_close(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_close.html) +pub fn mq_close(mqdes: MqdT) -> Result<()> { + let res = unsafe { libc::mq_close(mqdes.0) }; + Errno::result(res).map(drop) +} + +/// Receive a message from a message queue +/// +/// See also [`mq_receive(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html) +pub fn mq_receive( + mqdes: &MqdT, + message: &mut [u8], + msg_prio: &mut u32, +) -> Result { + let len = message.len() as size_t; + let res = unsafe { + libc::mq_receive( + mqdes.0, + message.as_mut_ptr() as *mut c_char, + len, + msg_prio as *mut u32, + ) + }; + Errno::result(res).map(|r| r as usize) +} + +/// Send a message to a message queue +/// +/// See also [`mq_send(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html) +pub fn mq_send(mqdes: &MqdT, message: &[u8], msq_prio: u32) -> Result<()> { + let res = unsafe { + libc::mq_send( + mqdes.0, + message.as_ptr() as *const c_char, + message.len(), + msq_prio, + ) + }; + Errno::result(res).map(drop) +} + +/// Get message queue attributes +/// +/// See also [`mq_getattr(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_getattr.html) +pub fn mq_getattr(mqd: &MqdT) -> Result { + let mut attr = mem::MaybeUninit::::uninit(); + let res = unsafe { libc::mq_getattr(mqd.0, attr.as_mut_ptr()) }; + Errno::result(res).map(|_| unsafe { + MqAttr { + mq_attr: attr.assume_init(), + } + }) +} + +/// Set the attributes of the message queue. Only `O_NONBLOCK` can be set, everything else will be ignored +/// Returns the old attributes +/// It is recommend to use the `mq_set_nonblock()` and `mq_remove_nonblock()` convenience functions as they are easier to use +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_setattr.html) +pub fn mq_setattr(mqd: &MqdT, newattr: &MqAttr) -> Result { + let mut attr = mem::MaybeUninit::::uninit(); + let res = unsafe { + libc::mq_setattr( + mqd.0, + &newattr.mq_attr as *const libc::mq_attr, + attr.as_mut_ptr(), + ) + }; + Errno::result(res).map(|_| unsafe { + MqAttr { + mq_attr: attr.assume_init(), + } + }) +} + +/// Convenience function. +/// Sets the `O_NONBLOCK` attribute for a given message queue descriptor +/// Returns the old attributes +#[allow(clippy::useless_conversion)] // Not useless on all OSes +pub fn mq_set_nonblock(mqd: &MqdT) -> Result { + let oldattr = mq_getattr(mqd)?; + let newattr = MqAttr::new( + mq_attr_member_t::from(MQ_OFlag::O_NONBLOCK.bits()), + oldattr.mq_attr.mq_maxmsg, + oldattr.mq_attr.mq_msgsize, + oldattr.mq_attr.mq_curmsgs, + ); + mq_setattr(mqd, &newattr) +} + +/// Convenience function. +/// Removes `O_NONBLOCK` attribute for a given message queue descriptor +/// Returns the old attributes +pub fn mq_remove_nonblock(mqd: &MqdT) -> Result { + let oldattr = mq_getattr(mqd)?; + let newattr = MqAttr::new( + 0, + oldattr.mq_attr.mq_maxmsg, + oldattr.mq_attr.mq_msgsize, + oldattr.mq_attr.mq_curmsgs, + ); + mq_setattr(mqd, &newattr) +} diff --git a/vendor/nix-0.26.2/src/net/if_.rs b/vendor/nix-0.26.2/src/net/if_.rs new file mode 100644 index 0000000000000..b2423bc673363 --- /dev/null +++ b/vendor/nix-0.26.2/src/net/if_.rs @@ -0,0 +1,469 @@ +//! Network interface name resolution. +//! +//! Uses Linux and/or POSIX functions to resolve interface names like "eth0" +//! or "socan1" into device numbers. + +use crate::{Error, NixPath, Result}; +use libc::c_uint; + +/// Resolve an interface into a interface number. +pub fn if_nametoindex(name: &P) -> Result { + let if_index = name + .with_nix_path(|name| unsafe { libc::if_nametoindex(name.as_ptr()) })?; + + if if_index == 0 { + Err(Error::last()) + } else { + Ok(if_index) + } +} + +libc_bitflags!( + /// Standard interface flags, used by `getifaddrs` + pub struct InterfaceFlags: libc::c_int { + /// Interface is running. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + IFF_UP; + /// Valid broadcast address set. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + IFF_BROADCAST; + /// Internal debugging flag. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + #[cfg(not(target_os = "haiku"))] + IFF_DEBUG; + /// Interface is a loopback interface. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + IFF_LOOPBACK; + /// Interface is a point-to-point link. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + IFF_POINTOPOINT; + /// Avoid use of trailers. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_NOTRAILERS; + /// Interface manages own routes. + #[cfg(any(target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_SMART; + /// Resources allocated. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + #[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_RUNNING; + /// No arp protocol, L2 destination address not set. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + IFF_NOARP; + /// Interface is in promiscuous mode. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + IFF_PROMISC; + /// Receive all multicast packets. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + IFF_ALLMULTI; + /// Master of a load balancing bundle. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_MASTER; + /// transmission in progress, tx hardware queue is full + #[cfg(any(target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "ios"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_OACTIVE; + /// Protocol code on board. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_INTELLIGENT; + /// Slave of a load balancing bundle. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_SLAVE; + /// Can't hear own transmissions. + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_SIMPLEX; + /// Supports multicast. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + IFF_MULTICAST; + /// Per link layer defined bit. + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "ios"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_LINK0; + /// Multicast using broadcast. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_MULTI_BCAST; + /// Is able to select media type via ifmap. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_PORTSEL; + /// Per link layer defined bit. + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "ios"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_LINK1; + /// Non-unique address. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_UNNUMBERED; + /// Auto media selection active. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_AUTOMEDIA; + /// Per link layer defined bit. + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "ios"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_LINK2; + /// Use alternate physical connection. + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "ios"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_ALTPHYS; + /// DHCP controls interface. + #[cfg(any(target_os = "solaris", target_os = "illumos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_DHCPRUNNING; + /// The addresses are lost when the interface goes down. (see + /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_DYNAMIC; + /// Do not advertise. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_PRIVATE; + /// Driver signals L1 up. Volatile. + #[cfg(any(target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_LOWER_UP; + /// Interface is in polling mode. + #[cfg(any(target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_POLLING_COMPAT; + /// Unconfigurable using ioctl(2). + #[cfg(any(target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_CANTCONFIG; + /// Do not transmit packets. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_NOXMIT; + /// Driver signals dormant. Volatile. + #[cfg(any(target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_DORMANT; + /// User-requested promisc mode. + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_PPROMISC; + /// Just on-link subnet. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_NOLOCAL; + /// Echo sent packets. Volatile. + #[cfg(any(target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_ECHO; + /// User-requested monitor mode. + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_MONITOR; + /// Address is deprecated. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_DEPRECATED; + /// Static ARP. + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_STATICARP; + /// Address from stateless addrconf. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_ADDRCONF; + /// Interface is in polling mode. + #[cfg(any(target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_NPOLLING; + /// Router on interface. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_ROUTER; + /// Interface is in polling mode. + #[cfg(any(target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_IDIRECT; + /// Interface is winding down + #[cfg(any(target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_DYING; + /// No NUD on interface. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_NONUD; + /// Interface is being renamed + #[cfg(any(target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_RENAMING; + /// Anycast address. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_ANYCAST; + /// Don't exchange routing info. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_NORTEXCH; + /// Do not provide packet information + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_NO_PI as libc::c_int; + /// TUN device (no Ethernet headers) + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_TUN as libc::c_int; + /// TAP device + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_TAP as libc::c_int; + /// IPv4 interface. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_IPV4; + /// IPv6 interface. + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_IPV6; + /// in.mpathd test address + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_NOFAILOVER; + /// Interface has failed + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_FAILED; + /// Interface is a hot-spare + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_STANDBY; + /// Functioning but not used + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_INACTIVE; + /// Interface is offline + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_OFFLINE; + #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_COS_ENABLED; + /// Prefer as source addr. + #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_PREFERRED; + /// RFC3041 + #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_TEMPORARY; + /// MTU set with SIOCSLIFMTU + #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_FIXEDMTU; + /// Cannot send / receive packets + #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_VIRTUAL; + /// Local address in use + #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_DUPLICATE; + /// IPMP IP interface + #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] + IFF_IPMP; + } +); + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +))] +#[cfg_attr(docsrs, doc(cfg(all())))] +mod if_nameindex { + use super::*; + + use std::ffi::CStr; + use std::fmt; + use std::marker::PhantomData; + use std::ptr::NonNull; + + /// A network interface. Has a name like "eth0" or "wlp4s0" or "wlan0", as well as an index + /// (1, 2, 3, etc) that identifies it in the OS's networking stack. + #[allow(missing_copy_implementations)] + #[repr(transparent)] + pub struct Interface(libc::if_nameindex); + + impl Interface { + /// Obtain the index of this interface. + pub fn index(&self) -> c_uint { + self.0.if_index + } + + /// Obtain the name of this interface. + pub fn name(&self) -> &CStr { + unsafe { CStr::from_ptr(self.0.if_name) } + } + } + + impl fmt::Debug for Interface { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Interface") + .field("index", &self.index()) + .field("name", &self.name()) + .finish() + } + } + + /// A list of the network interfaces available on this system. Obtained from [`if_nameindex()`]. + pub struct Interfaces { + ptr: NonNull, + } + + impl Interfaces { + /// Iterate over the interfaces in this list. + #[inline] + pub fn iter(&self) -> InterfacesIter<'_> { + self.into_iter() + } + + /// Convert this to a slice of interfaces. Note that the underlying interfaces list is + /// null-terminated, so calling this calculates the length. If random access isn't needed, + /// [`Interfaces::iter()`] should be used instead. + pub fn to_slice(&self) -> &[Interface] { + let ifs = self.ptr.as_ptr() as *const Interface; + let len = self.iter().count(); + unsafe { std::slice::from_raw_parts(ifs, len) } + } + } + + impl Drop for Interfaces { + fn drop(&mut self) { + unsafe { libc::if_freenameindex(self.ptr.as_ptr()) }; + } + } + + impl fmt::Debug for Interfaces { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.to_slice().fmt(f) + } + } + + impl<'a> IntoIterator for &'a Interfaces { + type IntoIter = InterfacesIter<'a>; + type Item = &'a Interface; + #[inline] + fn into_iter(self) -> Self::IntoIter { + InterfacesIter { + ptr: self.ptr.as_ptr(), + _marker: PhantomData, + } + } + } + + /// An iterator over the interfaces in an [`Interfaces`]. + #[derive(Debug)] + pub struct InterfacesIter<'a> { + ptr: *const libc::if_nameindex, + _marker: PhantomData<&'a Interfaces>, + } + + impl<'a> Iterator for InterfacesIter<'a> { + type Item = &'a Interface; + #[inline] + fn next(&mut self) -> Option { + unsafe { + if (*self.ptr).if_index == 0 { + None + } else { + let ret = &*(self.ptr as *const Interface); + self.ptr = self.ptr.add(1); + Some(ret) + } + } + } + } + + /// Retrieve a list of the network interfaces available on the local system. + /// + /// ``` + /// let interfaces = nix::net::if_::if_nameindex().unwrap(); + /// for iface in &interfaces { + /// println!("Interface #{} is called {}", iface.index(), iface.name().to_string_lossy()); + /// } + /// ``` + pub fn if_nameindex() -> Result { + unsafe { + let ifs = libc::if_nameindex(); + let ptr = NonNull::new(ifs).ok_or_else(Error::last)?; + Ok(Interfaces { ptr }) + } + } +} +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +))] +pub use if_nameindex::*; diff --git a/vendor/nix-0.26.2/src/net/mod.rs b/vendor/nix-0.26.2/src/net/mod.rs new file mode 100644 index 0000000000000..079fcfde6fd44 --- /dev/null +++ b/vendor/nix-0.26.2/src/net/mod.rs @@ -0,0 +1,4 @@ +//! Functionality involving network interfaces +// To avoid clashing with the keyword "if", we use "if_" as the module name. +// The original header is called "net/if.h". +pub mod if_; diff --git a/vendor/nix-0.26.2/src/poll.rs b/vendor/nix-0.26.2/src/poll.rs new file mode 100644 index 0000000000000..6f227fee9e6e5 --- /dev/null +++ b/vendor/nix-0.26.2/src/poll.rs @@ -0,0 +1,197 @@ +//! Wait for events to trigger on specific file descriptors +use std::os::unix::io::{AsRawFd, RawFd}; + +use crate::errno::Errno; +use crate::Result; + +/// This is a wrapper around `libc::pollfd`. +/// +/// It's meant to be used as an argument to the [`poll`](fn.poll.html) and +/// [`ppoll`](fn.ppoll.html) functions to specify the events of interest +/// for a specific file descriptor. +/// +/// After a call to `poll` or `ppoll`, the events that occurred can be +/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`. +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct PollFd { + pollfd: libc::pollfd, +} + +impl PollFd { + /// Creates a new `PollFd` specifying the events of interest + /// for a given file descriptor. + pub const fn new(fd: RawFd, events: PollFlags) -> PollFd { + PollFd { + pollfd: libc::pollfd { + fd, + events: events.bits(), + revents: PollFlags::empty().bits(), + }, + } + } + + /// Returns the events that occurred in the last call to `poll` or `ppoll`. Will only return + /// `None` if the kernel provides status flags that Nix does not know about. + pub fn revents(self) -> Option { + PollFlags::from_bits(self.pollfd.revents) + } + + /// Returns if any of the events of interest occured in the last call to `poll` or `ppoll`. Will + /// only return `None` if the kernel provides status flags that Nix does not know about. + /// + /// Equivalent to `x.revents()? != PollFlags::empty()`. + /// + /// This is marginally more efficient than [`PollFd::all`]. + pub fn any(self) -> Option { + Some(self.revents()? != PollFlags::empty()) + } + + /// Returns if all the events of interest occured in the last call to `poll` or `ppoll`. Will + /// only return `None` if the kernel provides status flags that Nix does not know about. + /// + /// Equivalent to `x.revents()? & x.events() == x.events()`. + /// + /// This is marginally less efficient than [`PollFd::any`]. + pub fn all(self) -> Option { + Some(self.revents()? & self.events() == self.events()) + } + + /// The events of interest for this `PollFd`. + pub fn events(self) -> PollFlags { + PollFlags::from_bits(self.pollfd.events).unwrap() + } + + /// Modify the events of interest for this `PollFd`. + pub fn set_events(&mut self, events: PollFlags) { + self.pollfd.events = events.bits(); + } +} + +impl AsRawFd for PollFd { + fn as_raw_fd(&self) -> RawFd { + self.pollfd.fd + } +} + +libc_bitflags! { + /// These flags define the different events that can be monitored by `poll` and `ppoll` + pub struct PollFlags: libc::c_short { + /// There is data to read. + POLLIN; + /// There is some exceptional condition on the file descriptor. + /// + /// Possibilities include: + /// + /// * There is out-of-band data on a TCP socket (see + /// [tcp(7)](https://man7.org/linux/man-pages/man7/tcp.7.html)). + /// * A pseudoterminal master in packet mode has seen a state + /// change on the slave (see + /// [ioctl_tty(2)](https://man7.org/linux/man-pages/man2/ioctl_tty.2.html)). + /// * A cgroup.events file has been modified (see + /// [cgroups(7)](https://man7.org/linux/man-pages/man7/cgroups.7.html)). + POLLPRI; + /// Writing is now possible, though a write larger that the + /// available space in a socket or pipe will still block (unless + /// `O_NONBLOCK` is set). + POLLOUT; + /// Equivalent to [`POLLIN`](constant.POLLIN.html) + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + POLLRDNORM; + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Equivalent to [`POLLOUT`](constant.POLLOUT.html) + POLLWRNORM; + /// Priority band data can be read (generally unused on Linux). + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + POLLRDBAND; + /// Priority data may be written. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + POLLWRBAND; + /// Error condition (only returned in + /// [`PollFd::revents`](struct.PollFd.html#method.revents); + /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)). + /// This bit is also set for a file descriptor referring to the + /// write end of a pipe when the read end has been closed. + POLLERR; + /// Hang up (only returned in [`PollFd::revents`](struct.PollFd.html#method.revents); + /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)). + /// Note that when reading from a channel such as a pipe or a stream + /// socket, this event merely indicates that the peer closed its + /// end of the channel. Subsequent reads from the channel will + /// return 0 (end of file) only after all outstanding data in the + /// channel has been consumed. + POLLHUP; + /// Invalid request: `fd` not open (only returned in + /// [`PollFd::revents`](struct.PollFd.html#method.revents); + /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)). + POLLNVAL; + } +} + +/// `poll` waits for one of a set of file descriptors to become ready to perform I/O. +/// ([`poll(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html)) +/// +/// `fds` contains all [`PollFd`](struct.PollFd.html) to poll. +/// The function will return as soon as any event occur for any of these `PollFd`s. +/// +/// The `timeout` argument specifies the number of milliseconds that `poll()` +/// should block waiting for a file descriptor to become ready. The call +/// will block until either: +/// +/// * a file descriptor becomes ready; +/// * the call is interrupted by a signal handler; or +/// * the timeout expires. +/// +/// Note that the timeout interval will be rounded up to the system clock +/// granularity, and kernel scheduling delays mean that the blocking +/// interval may overrun by a small amount. Specifying a negative value +/// in timeout means an infinite timeout. Specifying a timeout of zero +/// causes `poll()` to return immediately, even if no file descriptors are +/// ready. +pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result { + let res = unsafe { + libc::poll( + fds.as_mut_ptr() as *mut libc::pollfd, + fds.len() as libc::nfds_t, + timeout, + ) + }; + + Errno::result(res) +} + +feature! { +#![feature = "signal"] +/// `ppoll()` allows an application to safely wait until either a file +/// descriptor becomes ready or until a signal is caught. +/// ([`poll(2)`](https://man7.org/linux/man-pages/man2/poll.2.html)) +/// +/// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it +/// with the `sigmask` argument. If you want `ppoll` to block indefinitely, +/// specify `None` as `timeout` (it is like `timeout = -1` for `poll`). +/// If `sigmask` is `None`, then no signal mask manipulation is performed, +/// so in that case `ppoll` differs from `poll` only in the precision of the +/// timeout argument. +/// +#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] +pub fn ppoll( + fds: &mut [PollFd], + timeout: Option, + sigmask: Option + ) -> Result +{ + let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref()); + let sigmask = sigmask.as_ref().map_or(core::ptr::null(), |r| r.as_ref()); + let res = unsafe { + libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd, + fds.len() as libc::nfds_t, + timeout, + sigmask) + }; + Errno::result(res) +} +} diff --git a/vendor/nix-0.26.2/src/pty.rs b/vendor/nix-0.26.2/src/pty.rs new file mode 100644 index 0000000000000..28ae5e924b632 --- /dev/null +++ b/vendor/nix-0.26.2/src/pty.rs @@ -0,0 +1,371 @@ +//! Create master and slave virtual pseudo-terminals (PTYs) + +pub use libc::pid_t as SessionId; +pub use libc::winsize as Winsize; + +use std::ffi::CStr; +use std::io; +use std::mem; +use std::os::unix::prelude::*; + +use crate::errno::Errno; +use crate::sys::termios::Termios; +#[cfg(feature = "process")] +use crate::unistd::{ForkResult, Pid}; +use crate::{fcntl, unistd, Result}; + +/// Representation of a master/slave pty pair +/// +/// This is returned by `openpty`. Note that this type does *not* implement `Drop`, so the user +/// must manually close the file descriptors. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct OpenptyResult { + /// The master port in a virtual pty pair + pub master: RawFd, + /// The slave port in a virtual pty pair + pub slave: RawFd, +} + +feature! { +#![feature = "process"] +/// Representation of a master with a forked pty +/// +/// This is returned by `forkpty`. Note that this type does *not* implement `Drop`, so the user +/// must manually close the file descriptors. +#[derive(Clone, Copy, Debug)] +pub struct ForkptyResult { + /// The master port in a virtual pty pair + pub master: RawFd, + /// Metadata about forked process + pub fork_result: ForkResult, +} +} + +/// Representation of the Master device in a master/slave pty pair +/// +/// While this datatype is a thin wrapper around `RawFd`, it enforces that the available PTY +/// functions are given the correct file descriptor. Additionally this type implements `Drop`, +/// so that when it's consumed or goes out of scope, it's automatically cleaned-up. +#[derive(Debug, Eq, Hash, PartialEq)] +pub struct PtyMaster(RawFd); + +impl AsRawFd for PtyMaster { + fn as_raw_fd(&self) -> RawFd { + self.0 + } +} + +impl IntoRawFd for PtyMaster { + fn into_raw_fd(self) -> RawFd { + let fd = self.0; + mem::forget(self); + fd + } +} + +impl Drop for PtyMaster { + fn drop(&mut self) { + // On drop, we ignore errors like EINTR and EIO because there's no clear + // way to handle them, we can't return anything, and (on FreeBSD at + // least) the file descriptor is deallocated in these cases. However, + // we must panic on EBADF, because it is always an error to close an + // invalid file descriptor. That frequently indicates a double-close + // condition, which can cause confusing errors for future I/O + // operations. + let e = unistd::close(self.0); + if e == Err(Errno::EBADF) { + panic!("Closing an invalid file descriptor!"); + }; + } +} + +impl io::Read for PtyMaster { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + unistd::read(self.0, buf).map_err(io::Error::from) + } +} + +impl io::Write for PtyMaster { + fn write(&mut self, buf: &[u8]) -> io::Result { + unistd::write(self.0, buf).map_err(io::Error::from) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl io::Read for &PtyMaster { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + unistd::read(self.0, buf).map_err(io::Error::from) + } +} + +impl io::Write for &PtyMaster { + fn write(&mut self, buf: &[u8]) -> io::Result { + unistd::write(self.0, buf).map_err(io::Error::from) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +/// Grant access to a slave pseudoterminal (see +/// [`grantpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html)) +/// +/// `grantpt()` changes the mode and owner of the slave pseudoterminal device corresponding to the +/// master pseudoterminal referred to by `fd`. This is a necessary step towards opening the slave. +#[inline] +pub fn grantpt(fd: &PtyMaster) -> Result<()> { + if unsafe { libc::grantpt(fd.as_raw_fd()) } < 0 { + return Err(Errno::last()); + } + + Ok(()) +} + +/// Open a pseudoterminal device (see +/// [`posix_openpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html)) +/// +/// `posix_openpt()` returns a file descriptor to an existing unused pseudoterminal master device. +/// +/// # Examples +/// +/// A common use case with this function is to open both a master and slave PTY pair. This can be +/// done as follows: +/// +/// ``` +/// use std::path::Path; +/// use nix::fcntl::{OFlag, open}; +/// use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt}; +/// use nix::sys::stat::Mode; +/// +/// # #[allow(dead_code)] +/// # fn run() -> nix::Result<()> { +/// // Open a new PTY master +/// let master_fd = posix_openpt(OFlag::O_RDWR)?; +/// +/// // Allow a slave to be generated for it +/// grantpt(&master_fd)?; +/// unlockpt(&master_fd)?; +/// +/// // Get the name of the slave +/// let slave_name = unsafe { ptsname(&master_fd) }?; +/// +/// // Try to open the slave +/// let _slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, Mode::empty())?; +/// # Ok(()) +/// # } +/// ``` +#[inline] +pub fn posix_openpt(flags: fcntl::OFlag) -> Result { + let fd = unsafe { libc::posix_openpt(flags.bits()) }; + + if fd < 0 { + return Err(Errno::last()); + } + + Ok(PtyMaster(fd)) +} + +/// Get the name of the slave pseudoterminal (see +/// [`ptsname(3)`](https://man7.org/linux/man-pages/man3/ptsname.3.html)) +/// +/// `ptsname()` returns the name of the slave pseudoterminal device corresponding to the master +/// referred to by `fd`. +/// +/// This value is useful for opening the slave pty once the master has already been opened with +/// `posix_openpt()`. +/// +/// # Safety +/// +/// `ptsname()` mutates global variables and is *not* threadsafe. +/// Mutating global variables is always considered `unsafe` by Rust and this +/// function is marked as `unsafe` to reflect that. +/// +/// For a threadsafe and non-`unsafe` alternative on Linux, see `ptsname_r()`. +#[inline] +pub unsafe fn ptsname(fd: &PtyMaster) -> Result { + let name_ptr = libc::ptsname(fd.as_raw_fd()); + if name_ptr.is_null() { + return Err(Errno::last()); + } + + let name = CStr::from_ptr(name_ptr); + Ok(name.to_string_lossy().into_owned()) +} + +/// Get the name of the slave pseudoterminal (see +/// [`ptsname(3)`](https://man7.org/linux/man-pages/man3/ptsname.3.html)) +/// +/// `ptsname_r()` returns the name of the slave pseudoterminal device corresponding to the master +/// referred to by `fd`. This is the threadsafe version of `ptsname()`, but it is not part of the +/// POSIX standard and is instead a Linux-specific extension. +/// +/// This value is useful for opening the slave ptty once the master has already been opened with +/// `posix_openpt()`. +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +#[inline] +pub fn ptsname_r(fd: &PtyMaster) -> Result { + let mut name_buf = Vec::::with_capacity(64); + let name_buf_ptr = name_buf.as_mut_ptr(); + let cname = unsafe { + let cap = name_buf.capacity(); + if libc::ptsname_r(fd.as_raw_fd(), name_buf_ptr, cap) != 0 { + return Err(crate::Error::last()); + } + CStr::from_ptr(name_buf.as_ptr()) + }; + + let name = cname.to_string_lossy().into_owned(); + Ok(name) +} + +/// Unlock a pseudoterminal master/slave pseudoterminal pair (see +/// [`unlockpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlockpt.html)) +/// +/// `unlockpt()` unlocks the slave pseudoterminal device corresponding to the master pseudoterminal +/// referred to by `fd`. This must be called before trying to open the slave side of a +/// pseudoterminal. +#[inline] +pub fn unlockpt(fd: &PtyMaster) -> Result<()> { + if unsafe { libc::unlockpt(fd.as_raw_fd()) } < 0 { + return Err(Errno::last()); + } + + Ok(()) +} + +/// Create a new pseudoterminal, returning the slave and master file descriptors +/// in `OpenptyResult` +/// (see [`openpty`](https://man7.org/linux/man-pages/man3/openpty.3.html)). +/// +/// If `winsize` is not `None`, the window size of the slave will be set to +/// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's +/// terminal settings of the slave will be set to the values in `termios`. +#[inline] +pub fn openpty< + 'a, + 'b, + T: Into>, + U: Into>, +>( + winsize: T, + termios: U, +) -> Result { + use std::ptr; + + let mut slave = mem::MaybeUninit::::uninit(); + let mut master = mem::MaybeUninit::::uninit(); + let ret = { + match (termios.into(), winsize.into()) { + (Some(termios), Some(winsize)) => { + let inner_termios = termios.get_libc_termios(); + unsafe { + libc::openpty( + master.as_mut_ptr(), + slave.as_mut_ptr(), + ptr::null_mut(), + &*inner_termios as *const libc::termios as *mut _, + winsize as *const Winsize as *mut _, + ) + } + } + (None, Some(winsize)) => unsafe { + libc::openpty( + master.as_mut_ptr(), + slave.as_mut_ptr(), + ptr::null_mut(), + ptr::null_mut(), + winsize as *const Winsize as *mut _, + ) + }, + (Some(termios), None) => { + let inner_termios = termios.get_libc_termios(); + unsafe { + libc::openpty( + master.as_mut_ptr(), + slave.as_mut_ptr(), + ptr::null_mut(), + &*inner_termios as *const libc::termios as *mut _, + ptr::null_mut(), + ) + } + } + (None, None) => unsafe { + libc::openpty( + master.as_mut_ptr(), + slave.as_mut_ptr(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ) + }, + } + }; + + Errno::result(ret)?; + + unsafe { + Ok(OpenptyResult { + master: master.assume_init(), + slave: slave.assume_init(), + }) + } +} + +feature! { +#![feature = "process"] +/// Create a new pseudoterminal, returning the master file descriptor and forked pid. +/// in `ForkptyResult` +/// (see [`forkpty`](https://man7.org/linux/man-pages/man3/forkpty.3.html)). +/// +/// If `winsize` is not `None`, the window size of the slave will be set to +/// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's +/// terminal settings of the slave will be set to the values in `termios`. +/// +/// # Safety +/// +/// In a multithreaded program, only [async-signal-safe] functions like `pause` +/// and `_exit` may be called by the child (the parent isn't restricted). Note +/// that memory allocation may **not** be async-signal-safe and thus must be +/// prevented. +/// +/// Those functions are only a small subset of your operating system's API, so +/// special care must be taken to only invoke code you can control and audit. +/// +/// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html +pub unsafe fn forkpty<'a, 'b, T: Into>, U: Into>>( + winsize: T, + termios: U, +) -> Result { + use std::ptr; + + let mut master = mem::MaybeUninit::::uninit(); + + let term = match termios.into() { + Some(termios) => { + let inner_termios = termios.get_libc_termios(); + &*inner_termios as *const libc::termios as *mut _ + }, + None => ptr::null_mut(), + }; + + let win = winsize + .into() + .map(|ws| ws as *const Winsize as *mut _) + .unwrap_or(ptr::null_mut()); + + let res = libc::forkpty(master.as_mut_ptr(), ptr::null_mut(), term, win); + + let fork_result = Errno::result(res).map(|res| match res { + 0 => ForkResult::Child, + res => ForkResult::Parent { child: Pid::from_raw(res) }, + })?; + + Ok(ForkptyResult { + master: master.assume_init(), + fork_result, + }) +} +} diff --git a/vendor/nix-0.26.2/src/sched.rs b/vendor/nix-0.26.2/src/sched.rs new file mode 100644 index 0000000000000..d5b1233cf3baf --- /dev/null +++ b/vendor/nix-0.26.2/src/sched.rs @@ -0,0 +1,324 @@ +//! Execution scheduling +//! +//! See Also +//! [sched.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sched.h.html) +use crate::{Errno, Result}; + +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use self::sched_linux_like::*; + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +mod sched_linux_like { + use crate::errno::Errno; + use crate::unistd::Pid; + use crate::Result; + use libc::{self, c_int, c_void}; + use std::mem; + use std::option::Option; + use std::os::unix::io::RawFd; + + // For some functions taking with a parameter of type CloneFlags, + // only a subset of these flags have an effect. + libc_bitflags! { + /// Options for use with [`clone`] + pub struct CloneFlags: c_int { + /// The calling process and the child process run in the same + /// memory space. + CLONE_VM; + /// The caller and the child process share the same filesystem + /// information. + CLONE_FS; + /// The calling process and the child process share the same file + /// descriptor table. + CLONE_FILES; + /// The calling process and the child process share the same table + /// of signal handlers. + CLONE_SIGHAND; + /// If the calling process is being traced, then trace the child + /// also. + CLONE_PTRACE; + /// The execution of the calling process is suspended until the + /// child releases its virtual memory resources via a call to + /// execve(2) or _exit(2) (as with vfork(2)). + CLONE_VFORK; + /// The parent of the new child (as returned by getppid(2)) + /// will be the same as that of the calling process. + CLONE_PARENT; + /// The child is placed in the same thread group as the calling + /// process. + CLONE_THREAD; + /// The cloned child is started in a new mount namespace. + CLONE_NEWNS; + /// The child and the calling process share a single list of System + /// V semaphore adjustment values + CLONE_SYSVSEM; + // Not supported by Nix due to lack of varargs support in Rust FFI + // CLONE_SETTLS; + // Not supported by Nix due to lack of varargs support in Rust FFI + // CLONE_PARENT_SETTID; + // Not supported by Nix due to lack of varargs support in Rust FFI + // CLONE_CHILD_CLEARTID; + /// Unused since Linux 2.6.2 + #[deprecated(since = "0.23.0", note = "Deprecated by Linux 2.6.2")] + CLONE_DETACHED; + /// A tracing process cannot force `CLONE_PTRACE` on this child + /// process. + CLONE_UNTRACED; + // Not supported by Nix due to lack of varargs support in Rust FFI + // CLONE_CHILD_SETTID; + /// Create the process in a new cgroup namespace. + CLONE_NEWCGROUP; + /// Create the process in a new UTS namespace. + CLONE_NEWUTS; + /// Create the process in a new IPC namespace. + CLONE_NEWIPC; + /// Create the process in a new user namespace. + CLONE_NEWUSER; + /// Create the process in a new PID namespace. + CLONE_NEWPID; + /// Create the process in a new network namespace. + CLONE_NEWNET; + /// The new process shares an I/O context with the calling process. + CLONE_IO; + } + } + + /// Type for the function executed by [`clone`]. + pub type CloneCb<'a> = Box isize + 'a>; + + /// `clone` create a child process + /// ([`clone(2)`](https://man7.org/linux/man-pages/man2/clone.2.html)) + /// + /// `stack` is a reference to an array which will hold the stack of the new + /// process. Unlike when calling `clone(2)` from C, the provided stack + /// address need not be the highest address of the region. Nix will take + /// care of that requirement. The user only needs to provide a reference to + /// a normally allocated buffer. + pub fn clone( + mut cb: CloneCb, + stack: &mut [u8], + flags: CloneFlags, + signal: Option, + ) -> Result { + extern "C" fn callback(data: *mut CloneCb) -> c_int { + let cb: &mut CloneCb = unsafe { &mut *data }; + (*cb)() as c_int + } + + let res = unsafe { + let combined = flags.bits() | signal.unwrap_or(0); + let ptr = stack.as_mut_ptr().add(stack.len()); + let ptr_aligned = ptr.sub(ptr as usize % 16); + libc::clone( + mem::transmute( + callback + as extern "C" fn(*mut Box isize>) -> i32, + ), + ptr_aligned as *mut c_void, + combined, + &mut cb as *mut _ as *mut c_void, + ) + }; + + Errno::result(res).map(Pid::from_raw) + } + + /// disassociate parts of the process execution context + /// + /// See also [unshare(2)](https://man7.org/linux/man-pages/man2/unshare.2.html) + pub fn unshare(flags: CloneFlags) -> Result<()> { + let res = unsafe { libc::unshare(flags.bits()) }; + + Errno::result(res).map(drop) + } + + /// reassociate thread with a namespace + /// + /// See also [setns(2)](https://man7.org/linux/man-pages/man2/setns.2.html) + pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> { + let res = unsafe { libc::setns(fd, nstype.bits()) }; + + Errno::result(res).map(drop) + } +} + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux" +))] +pub use self::sched_affinity::*; + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux" +))] +mod sched_affinity { + use crate::errno::Errno; + use crate::unistd::Pid; + use crate::Result; + use std::mem; + + /// CpuSet represent a bit-mask of CPUs. + /// CpuSets are used by sched_setaffinity and + /// sched_getaffinity for example. + /// + /// This is a wrapper around `libc::cpu_set_t`. + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + pub struct CpuSet { + #[cfg(not(target_os = "freebsd"))] + cpu_set: libc::cpu_set_t, + #[cfg(target_os = "freebsd")] + cpu_set: libc::cpuset_t, + } + + impl CpuSet { + /// Create a new and empty CpuSet. + pub fn new() -> CpuSet { + CpuSet { + cpu_set: unsafe { mem::zeroed() }, + } + } + + /// Test to see if a CPU is in the CpuSet. + /// `field` is the CPU id to test + pub fn is_set(&self, field: usize) -> Result { + if field >= CpuSet::count() { + Err(Errno::EINVAL) + } else { + Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) }) + } + } + + /// Add a CPU to CpuSet. + /// `field` is the CPU id to add + pub fn set(&mut self, field: usize) -> Result<()> { + if field >= CpuSet::count() { + Err(Errno::EINVAL) + } else { + unsafe { + libc::CPU_SET(field, &mut self.cpu_set); + } + Ok(()) + } + } + + /// Remove a CPU from CpuSet. + /// `field` is the CPU id to remove + pub fn unset(&mut self, field: usize) -> Result<()> { + if field >= CpuSet::count() { + Err(Errno::EINVAL) + } else { + unsafe { + libc::CPU_CLR(field, &mut self.cpu_set); + } + Ok(()) + } + } + + /// Return the maximum number of CPU in CpuSet + pub const fn count() -> usize { + #[cfg(not(target_os = "freebsd"))] + let bytes = mem::size_of::(); + #[cfg(target_os = "freebsd")] + let bytes = mem::size_of::(); + + 8 * bytes + } + } + + impl Default for CpuSet { + fn default() -> Self { + Self::new() + } + } + + /// `sched_setaffinity` set a thread's CPU affinity mask + /// ([`sched_setaffinity(2)`](https://man7.org/linux/man-pages/man2/sched_setaffinity.2.html)) + /// + /// `pid` is the thread ID to update. + /// If pid is zero, then the calling thread is updated. + /// + /// The `cpuset` argument specifies the set of CPUs on which the thread + /// will be eligible to run. + /// + /// # Example + /// + /// Binding the current thread to CPU 0 can be done as follows: + /// + /// ```rust,no_run + /// use nix::sched::{CpuSet, sched_setaffinity}; + /// use nix::unistd::Pid; + /// + /// let mut cpu_set = CpuSet::new(); + /// cpu_set.set(0).unwrap(); + /// sched_setaffinity(Pid::from_raw(0), &cpu_set).unwrap(); + /// ``` + pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> { + let res = unsafe { + libc::sched_setaffinity( + pid.into(), + mem::size_of::() as libc::size_t, + &cpuset.cpu_set, + ) + }; + + Errno::result(res).map(drop) + } + + /// `sched_getaffinity` get a thread's CPU affinity mask + /// ([`sched_getaffinity(2)`](https://man7.org/linux/man-pages/man2/sched_getaffinity.2.html)) + /// + /// `pid` is the thread ID to check. + /// If pid is zero, then the calling thread is checked. + /// + /// Returned `cpuset` is the set of CPUs on which the thread + /// is eligible to run. + /// + /// # Example + /// + /// Checking if the current thread can run on CPU 0 can be done as follows: + /// + /// ```rust,no_run + /// use nix::sched::sched_getaffinity; + /// use nix::unistd::Pid; + /// + /// let cpu_set = sched_getaffinity(Pid::from_raw(0)).unwrap(); + /// if cpu_set.is_set(0).unwrap() { + /// println!("Current thread can run on CPU 0"); + /// } + /// ``` + pub fn sched_getaffinity(pid: Pid) -> Result { + let mut cpuset = CpuSet::new(); + let res = unsafe { + libc::sched_getaffinity( + pid.into(), + mem::size_of::() as libc::size_t, + &mut cpuset.cpu_set, + ) + }; + + Errno::result(res).and(Ok(cpuset)) + } + + /// Determines the CPU on which the calling thread is running. + pub fn sched_getcpu() -> Result { + let res = unsafe { libc::sched_getcpu() }; + + Errno::result(res).map(|int| int as usize) + } +} + +/// Explicitly yield the processor to other threads. +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html) +pub fn sched_yield() -> Result<()> { + let res = unsafe { libc::sched_yield() }; + + Errno::result(res).map(drop) +} diff --git a/vendor/nix-0.26.2/src/sys/aio.rs b/vendor/nix-0.26.2/src/sys/aio.rs new file mode 100644 index 0000000000000..e2ce19b79dc81 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/aio.rs @@ -0,0 +1,1241 @@ +// vim: tw=80 +//! POSIX Asynchronous I/O +//! +//! The POSIX AIO interface is used for asynchronous I/O on files and disk-like +//! devices. It supports [`read`](struct.AioRead.html#method.new), +//! [`write`](struct.AioWrite.html#method.new), +//! [`fsync`](struct.AioFsync.html#method.new), +//! [`readv`](struct.AioReadv.html#method.new), and +//! [`writev`](struct.AioWritev.html#method.new), operations, subject to +//! platform support. Completion +//! notifications can optionally be delivered via +//! [signals](../signal/enum.SigevNotify.html#variant.SigevSignal), via the +//! [`aio_suspend`](fn.aio_suspend.html) function, or via polling. Some +//! platforms support other completion +//! notifications, such as +//! [kevent](../signal/enum.SigevNotify.html#variant.SigevKevent). +//! +//! Multiple operations may be submitted in a batch with +//! [`lio_listio`](fn.lio_listio.html), though the standard does not guarantee +//! that they will be executed atomically. +//! +//! Outstanding operations may be cancelled with +//! [`cancel`](trait.Aio.html#method.cancel) or +//! [`aio_cancel_all`](fn.aio_cancel_all.html), though the operating system may +//! not support this for all filesystems and devices. +#[cfg(target_os = "freebsd")] +use std::io::{IoSlice, IoSliceMut}; +use std::{ + convert::TryFrom, + fmt::{self, Debug}, + marker::{PhantomData, PhantomPinned}, + mem, + os::unix::io::RawFd, + pin::Pin, + ptr, thread, +}; + +use libc::{c_void, off_t}; +use pin_utils::unsafe_pinned; + +use crate::{ + errno::Errno, + sys::{signal::*, time::TimeSpec}, + Result, +}; + +libc_enum! { + /// Mode for `AioCb::fsync`. Controls whether only data or both data and + /// metadata are synced. + #[repr(i32)] + #[non_exhaustive] + pub enum AioFsyncMode { + /// do it like `fsync` + O_SYNC, + /// on supported operating systems only, do it like `fdatasync` + #[cfg(any(target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + O_DSYNC + } + impl TryFrom +} + +libc_enum! { + /// Mode for [`lio_listio`](fn.lio_listio.html) + #[repr(i32)] + pub enum LioMode { + /// Requests that [`lio_listio`](fn.lio_listio.html) block until all + /// requested operations have been completed + LIO_WAIT, + /// Requests that [`lio_listio`](fn.lio_listio.html) return immediately + LIO_NOWAIT, + } +} + +/// Return values for [`AioCb::cancel`](struct.AioCb.html#method.cancel) and +/// [`aio_cancel_all`](fn.aio_cancel_all.html) +#[repr(i32)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum AioCancelStat { + /// All outstanding requests were canceled + AioCanceled = libc::AIO_CANCELED, + /// Some requests were not canceled. Their status should be checked with + /// `AioCb::error` + AioNotCanceled = libc::AIO_NOTCANCELED, + /// All of the requests have already finished + AioAllDone = libc::AIO_ALLDONE, +} + +/// Newtype that adds Send and Sync to libc::aiocb, which contains raw pointers +#[repr(transparent)] +struct LibcAiocb(libc::aiocb); + +unsafe impl Send for LibcAiocb {} +unsafe impl Sync for LibcAiocb {} + +/// Base class for all AIO operations. Should only be used directly when +/// checking for completion. +// We could create some kind of AsPinnedMut trait, and implement it for all aio +// ops, allowing the crate's users to get pinned references to `AioCb`. That +// could save some code for things like polling methods. But IMHO it would +// provide polymorphism at the wrong level. Instead, the best place for +// polymorphism is at the level of `Futures`. +#[repr(C)] +struct AioCb { + aiocb: LibcAiocb, + /// Could this `AioCb` potentially have any in-kernel state? + // It would be really nice to perform the in-progress check entirely at + // compile time. But I can't figure out how, because: + // * Future::poll takes a `Pin<&mut self>` rather than `self`, and + // * Rust's lack of an equivalent of C++'s Guaranteed Copy Elision means + // that there's no way to write an AioCb constructor that neither boxes + // the object itself, nor moves it during return. + in_progress: bool, +} + +impl AioCb { + pin_utils::unsafe_unpinned!(aiocb: LibcAiocb); + + fn aio_return(mut self: Pin<&mut Self>) -> Result { + self.in_progress = false; + unsafe { + let p: *mut libc::aiocb = &mut self.aiocb.0; + Errno::result(libc::aio_return(p)) + } + .map(|r| r as usize) + } + + fn cancel(mut self: Pin<&mut Self>) -> Result { + let r = unsafe { + libc::aio_cancel(self.aiocb.0.aio_fildes, &mut self.aiocb.0) + }; + match r { + libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), + libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), + libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), + -1 => Err(Errno::last()), + _ => panic!("unknown aio_cancel return value"), + } + } + + fn common_init(fd: RawFd, prio: i32, sigev_notify: SigevNotify) -> Self { + // Use mem::zeroed instead of explicitly zeroing each field, because the + // number and name of reserved fields is OS-dependent. On some OSes, + // some reserved fields are used the kernel for state, and must be + // explicitly zeroed when allocated. + let mut a = unsafe { mem::zeroed::() }; + a.aio_fildes = fd; + a.aio_reqprio = prio; + a.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); + AioCb { + aiocb: LibcAiocb(a), + in_progress: false, + } + } + + fn error(self: Pin<&mut Self>) -> Result<()> { + let r = unsafe { libc::aio_error(&self.aiocb().0) }; + match r { + 0 => Ok(()), + num if num > 0 => Err(Errno::from_i32(num)), + -1 => Err(Errno::last()), + num => panic!("unknown aio_error return value {:?}", num), + } + } + + fn in_progress(&self) -> bool { + self.in_progress + } + + fn set_in_progress(mut self: Pin<&mut Self>) { + self.as_mut().in_progress = true; + } + + /// Update the notification settings for an existing AIO operation that has + /// not yet been submitted. + // Takes a normal reference rather than a pinned one because this method is + // normally called before the object needs to be pinned, that is, before + // it's been submitted to the kernel. + fn set_sigev_notify(&mut self, sigev_notify: SigevNotify) { + assert!( + !self.in_progress, + "Can't change notification settings for an in-progress operation" + ); + self.aiocb.0.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); + } +} + +impl Debug for AioCb { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("AioCb") + .field("aiocb", &self.aiocb.0) + .field("in_progress", &self.in_progress) + .finish() + } +} + +impl Drop for AioCb { + /// If the `AioCb` has no remaining state in the kernel, just drop it. + /// Otherwise, dropping constitutes a resource leak, which is an error + fn drop(&mut self) { + assert!( + thread::panicking() || !self.in_progress, + "Dropped an in-progress AioCb" + ); + } +} + +/// Methods common to all AIO operations +pub trait Aio { + /// The return type of [`Aio::aio_return`]. + type Output; + + /// Retrieve return status of an asynchronous operation. + /// + /// Should only be called once for each operation, after [`Aio::error`] + /// indicates that it has completed. The result is the same as for the + /// synchronous `read(2)`, `write(2)`, of `fsync(2)` functions. + /// + /// # References + /// + /// [aio_return](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_return.html) + fn aio_return(self: Pin<&mut Self>) -> Result; + + /// Cancels an outstanding AIO request. + /// + /// The operating system is not required to implement cancellation for all + /// file and device types. Even if it does, there is no guarantee that the + /// operation has not already completed. So the caller must check the + /// result and handle operations that were not canceled or that have already + /// completed. + /// + /// # Examples + /// + /// Cancel an outstanding aio operation. Note that we must still call + /// `aio_return` to free resources, even though we don't care about the + /// result. + /// + /// ``` + /// # use nix::errno::Errno; + /// # use nix::Error; + /// # use nix::sys::aio::*; + /// # use nix::sys::signal::SigevNotify; + /// # use std::{thread, time}; + /// # use std::io::Write; + /// # use std::os::unix::io::AsRawFd; + /// # use tempfile::tempfile; + /// let wbuf = b"CDEF"; + /// let mut f = tempfile().unwrap(); + /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), + /// 2, //offset + /// &wbuf[..], + /// 0, //priority + /// SigevNotify::SigevNone)); + /// aiocb.as_mut().submit().unwrap(); + /// let cs = aiocb.as_mut().cancel().unwrap(); + /// if cs == AioCancelStat::AioNotCanceled { + /// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { + /// thread::sleep(time::Duration::from_millis(10)); + /// } + /// } + /// // Must call `aio_return`, but ignore the result + /// let _ = aiocb.as_mut().aio_return(); + /// ``` + /// + /// # References + /// + /// [aio_cancel](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) + fn cancel(self: Pin<&mut Self>) -> Result; + + /// Retrieve error status of an asynchronous operation. + /// + /// If the request has not yet completed, returns `EINPROGRESS`. Otherwise, + /// returns `Ok` or any other error. + /// + /// # Examples + /// + /// Issue an aio operation and use `error` to poll for completion. Polling + /// is an alternative to `aio_suspend`, used by most of the other examples. + /// + /// ``` + /// # use nix::errno::Errno; + /// # use nix::Error; + /// # use nix::sys::aio::*; + /// # use nix::sys::signal::SigevNotify; + /// # use std::{thread, time}; + /// # use std::os::unix::io::AsRawFd; + /// # use tempfile::tempfile; + /// const WBUF: &[u8] = b"abcdef123456"; + /// let mut f = tempfile().unwrap(); + /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), + /// 2, //offset + /// WBUF, + /// 0, //priority + /// SigevNotify::SigevNone)); + /// aiocb.as_mut().submit().unwrap(); + /// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { + /// thread::sleep(time::Duration::from_millis(10)); + /// } + /// assert_eq!(aiocb.as_mut().aio_return().unwrap(), WBUF.len()); + /// ``` + /// + /// # References + /// + /// [aio_error](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_error.html) + fn error(self: Pin<&mut Self>) -> Result<()>; + + /// Returns the underlying file descriptor associated with the operation. + fn fd(&self) -> RawFd; + + /// Does this operation currently have any in-kernel state? + /// + /// Dropping an operation that does have in-kernel state constitutes a + /// resource leak. + /// + /// # Examples + /// + /// ``` + /// # use nix::errno::Errno; + /// # use nix::Error; + /// # use nix::sys::aio::*; + /// # use nix::sys::signal::SigevNotify::SigevNone; + /// # use std::{thread, time}; + /// # use std::os::unix::io::AsRawFd; + /// # use tempfile::tempfile; + /// let f = tempfile().unwrap(); + /// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC, + /// 0, SigevNone)); + /// assert!(!aiof.as_mut().in_progress()); + /// aiof.as_mut().submit().expect("aio_fsync failed early"); + /// assert!(aiof.as_mut().in_progress()); + /// while (aiof.as_mut().error() == Err(Errno::EINPROGRESS)) { + /// thread::sleep(time::Duration::from_millis(10)); + /// } + /// aiof.as_mut().aio_return().expect("aio_fsync failed late"); + /// assert!(!aiof.as_mut().in_progress()); + /// ``` + fn in_progress(&self) -> bool; + + /// Returns the priority of the `AioCb` + fn priority(&self) -> i32; + + /// Update the notification settings for an existing AIO operation that has + /// not yet been submitted. + fn set_sigev_notify(&mut self, sev: SigevNotify); + + /// Returns the `SigEvent` that will be used for notification. + fn sigevent(&self) -> SigEvent; + + /// Actually start the I/O operation. + /// + /// After calling this method and until [`Aio::aio_return`] returns `Ok`, + /// the structure may not be moved in memory. + fn submit(self: Pin<&mut Self>) -> Result<()>; +} + +macro_rules! aio_methods { + () => { + fn cancel(self: Pin<&mut Self>) -> Result { + self.aiocb().cancel() + } + + fn error(self: Pin<&mut Self>) -> Result<()> { + self.aiocb().error() + } + + fn fd(&self) -> RawFd { + self.aiocb.aiocb.0.aio_fildes + } + + fn in_progress(&self) -> bool { + self.aiocb.in_progress() + } + + fn priority(&self) -> i32 { + self.aiocb.aiocb.0.aio_reqprio + } + + fn set_sigev_notify(&mut self, sev: SigevNotify) { + self.aiocb.set_sigev_notify(sev) + } + + fn sigevent(&self) -> SigEvent { + SigEvent::from(&self.aiocb.aiocb.0.aio_sigevent) + } + }; + ($func:ident) => { + aio_methods!(); + + fn aio_return(self: Pin<&mut Self>) -> Result<::Output> { + self.aiocb().aio_return() + } + + fn submit(mut self: Pin<&mut Self>) -> Result<()> { + let p: *mut libc::aiocb = &mut self.as_mut().aiocb().aiocb.0; + Errno::result({ unsafe { libc::$func(p) } }).map(|_| { + self.aiocb().set_in_progress(); + }) + } + }; +} + +/// An asynchronous version of `fsync(2)`. +/// +/// # References +/// +/// [aio_fsync](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_fsync.html) +/// # Examples +/// +/// ``` +/// # use nix::errno::Errno; +/// # use nix::Error; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify::SigevNone; +/// # use std::{thread, time}; +/// # use std::os::unix::io::AsRawFd; +/// # use tempfile::tempfile; +/// let f = tempfile().unwrap(); +/// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC, +/// 0, SigevNone)); +/// aiof.as_mut().submit().expect("aio_fsync failed early"); +/// while (aiof.as_mut().error() == Err(Errno::EINPROGRESS)) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// aiof.as_mut().aio_return().expect("aio_fsync failed late"); +/// ``` +#[derive(Debug)] +#[repr(transparent)] +pub struct AioFsync { + aiocb: AioCb, + _pin: PhantomPinned, +} + +impl AioFsync { + unsafe_pinned!(aiocb: AioCb); + + /// Returns the operation's fsync mode: data and metadata or data only? + pub fn mode(&self) -> AioFsyncMode { + AioFsyncMode::try_from(self.aiocb.aiocb.0.aio_lio_opcode).unwrap() + } + + /// Create a new `AioFsync`. + /// + /// # Arguments + /// + /// * `fd`: File descriptor to sync. + /// * `mode`: Whether to sync file metadata too, or just data. + /// * `prio`: If POSIX Prioritized IO is supported, then the + /// operation will be prioritized at the process's + /// priority level minus `prio`. + /// * `sigev_notify`: Determines how you will be notified of event + /// completion. + pub fn new( + fd: RawFd, + mode: AioFsyncMode, + prio: i32, + sigev_notify: SigevNotify, + ) -> Self { + let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); + // To save some memory, store mode in an unused field of the AioCb. + // True it isn't very much memory, but downstream creates will likely + // create an enum containing this and other AioCb variants and pack + // those enums into data structures like Vec, so it adds up. + aiocb.aiocb.0.aio_lio_opcode = mode as libc::c_int; + AioFsync { + aiocb, + _pin: PhantomPinned, + } + } +} + +impl Aio for AioFsync { + type Output = (); + + aio_methods!(); + + fn aio_return(self: Pin<&mut Self>) -> Result<()> { + self.aiocb().aio_return().map(drop) + } + + fn submit(mut self: Pin<&mut Self>) -> Result<()> { + let aiocb = &mut self.as_mut().aiocb().aiocb.0; + let mode = mem::replace(&mut aiocb.aio_lio_opcode, 0); + let p: *mut libc::aiocb = aiocb; + Errno::result(unsafe { libc::aio_fsync(mode, p) }).map(|_| { + self.aiocb().set_in_progress(); + }) + } +} + +// AioFsync does not need AsMut, since it can't be used with lio_listio + +impl AsRef for AioFsync { + fn as_ref(&self) -> &libc::aiocb { + &self.aiocb.aiocb.0 + } +} + +/// Asynchronously reads from a file descriptor into a buffer +/// +/// # References +/// +/// [aio_read](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_read.html) +/// +/// # Examples +/// +/// +/// ``` +/// # use nix::errno::Errno; +/// # use nix::Error; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use std::{thread, time}; +/// # use std::io::Write; +/// # use std::os::unix::io::AsRawFd; +/// # use tempfile::tempfile; +/// const INITIAL: &[u8] = b"abcdef123456"; +/// const LEN: usize = 4; +/// let mut rbuf = vec![0; LEN]; +/// let mut f = tempfile().unwrap(); +/// f.write_all(INITIAL).unwrap(); +/// { +/// let mut aior = Box::pin( +/// AioRead::new( +/// f.as_raw_fd(), +/// 2, //offset +/// &mut rbuf, +/// 0, //priority +/// SigevNotify::SigevNone +/// ) +/// ); +/// aior.as_mut().submit().unwrap(); +/// while (aior.as_mut().error() == Err(Errno::EINPROGRESS)) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// assert_eq!(aior.as_mut().aio_return().unwrap(), LEN); +/// } +/// assert_eq!(rbuf, b"cdef"); +/// ``` +#[derive(Debug)] +#[repr(transparent)] +pub struct AioRead<'a> { + aiocb: AioCb, + _data: PhantomData<&'a [u8]>, + _pin: PhantomPinned, +} + +impl<'a> AioRead<'a> { + unsafe_pinned!(aiocb: AioCb); + + /// Returns the requested length of the aio operation in bytes + /// + /// This method returns the *requested* length of the operation. To get the + /// number of bytes actually read or written by a completed operation, use + /// `aio_return` instead. + pub fn nbytes(&self) -> usize { + self.aiocb.aiocb.0.aio_nbytes + } + + /// Create a new `AioRead`, placing the data in a mutable slice. + /// + /// # Arguments + /// + /// * `fd`: File descriptor to read from + /// * `offs`: File offset + /// * `buf`: A memory buffer. It must outlive the `AioRead`. + /// * `prio`: If POSIX Prioritized IO is supported, then the + /// operation will be prioritized at the process's + /// priority level minus `prio` + /// * `sigev_notify`: Determines how you will be notified of event + /// completion. + pub fn new( + fd: RawFd, + offs: off_t, + buf: &'a mut [u8], + prio: i32, + sigev_notify: SigevNotify, + ) -> Self { + let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); + aiocb.aiocb.0.aio_nbytes = buf.len(); + aiocb.aiocb.0.aio_buf = buf.as_mut_ptr() as *mut c_void; + aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READ; + aiocb.aiocb.0.aio_offset = offs; + AioRead { + aiocb, + _data: PhantomData, + _pin: PhantomPinned, + } + } + + /// Returns the file offset of the operation. + pub fn offset(&self) -> off_t { + self.aiocb.aiocb.0.aio_offset + } +} + +impl<'a> Aio for AioRead<'a> { + type Output = usize; + + aio_methods!(aio_read); +} + +impl<'a> AsMut for AioRead<'a> { + fn as_mut(&mut self) -> &mut libc::aiocb { + &mut self.aiocb.aiocb.0 + } +} + +impl<'a> AsRef for AioRead<'a> { + fn as_ref(&self) -> &libc::aiocb { + &self.aiocb.aiocb.0 + } +} + +/// Asynchronously reads from a file descriptor into a scatter/gather list of buffers. +/// +/// # References +/// +/// [aio_readv](https://www.freebsd.org/cgi/man.cgi?query=aio_readv) +/// +/// # Examples +/// +/// +#[cfg_attr(fbsd14, doc = " ```")] +#[cfg_attr(not(fbsd14), doc = " ```no_run")] +/// # use nix::errno::Errno; +/// # use nix::Error; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use std::{thread, time}; +/// # use std::io::{IoSliceMut, Write}; +/// # use std::os::unix::io::AsRawFd; +/// # use tempfile::tempfile; +/// const INITIAL: &[u8] = b"abcdef123456"; +/// let mut rbuf0 = vec![0; 4]; +/// let mut rbuf1 = vec![0; 2]; +/// let expected_len = rbuf0.len() + rbuf1.len(); +/// let mut rbufs = [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)]; +/// let mut f = tempfile().unwrap(); +/// f.write_all(INITIAL).unwrap(); +/// { +/// let mut aior = Box::pin( +/// AioReadv::new( +/// f.as_raw_fd(), +/// 2, //offset +/// &mut rbufs, +/// 0, //priority +/// SigevNotify::SigevNone +/// ) +/// ); +/// aior.as_mut().submit().unwrap(); +/// while (aior.as_mut().error() == Err(Errno::EINPROGRESS)) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// assert_eq!(aior.as_mut().aio_return().unwrap(), expected_len); +/// } +/// assert_eq!(rbuf0, b"cdef"); +/// assert_eq!(rbuf1, b"12"); +/// ``` +#[cfg(target_os = "freebsd")] +#[derive(Debug)] +#[repr(transparent)] +pub struct AioReadv<'a> { + aiocb: AioCb, + _data: PhantomData<&'a [&'a [u8]]>, + _pin: PhantomPinned, +} + +#[cfg(target_os = "freebsd")] +impl<'a> AioReadv<'a> { + unsafe_pinned!(aiocb: AioCb); + + /// Returns the number of buffers the operation will read into. + pub fn iovlen(&self) -> usize { + self.aiocb.aiocb.0.aio_nbytes + } + + /// Create a new `AioReadv`, placing the data in a list of mutable slices. + /// + /// # Arguments + /// + /// * `fd`: File descriptor to read from + /// * `offs`: File offset + /// * `bufs`: A scatter/gather list of memory buffers. They must + /// outlive the `AioReadv`. + /// * `prio`: If POSIX Prioritized IO is supported, then the + /// operation will be prioritized at the process's + /// priority level minus `prio` + /// * `sigev_notify`: Determines how you will be notified of event + /// completion. + pub fn new( + fd: RawFd, + offs: off_t, + bufs: &mut [IoSliceMut<'a>], + prio: i32, + sigev_notify: SigevNotify, + ) -> Self { + let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); + // In vectored mode, aio_nbytes stores the length of the iovec array, + // not the byte count. + aiocb.aiocb.0.aio_nbytes = bufs.len(); + aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr() as *mut c_void; + aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READV; + aiocb.aiocb.0.aio_offset = offs; + AioReadv { + aiocb, + _data: PhantomData, + _pin: PhantomPinned, + } + } + + /// Returns the file offset of the operation. + pub fn offset(&self) -> off_t { + self.aiocb.aiocb.0.aio_offset + } +} + +#[cfg(target_os = "freebsd")] +impl<'a> Aio for AioReadv<'a> { + type Output = usize; + + aio_methods!(aio_readv); +} + +#[cfg(target_os = "freebsd")] +impl<'a> AsMut for AioReadv<'a> { + fn as_mut(&mut self) -> &mut libc::aiocb { + &mut self.aiocb.aiocb.0 + } +} + +#[cfg(target_os = "freebsd")] +impl<'a> AsRef for AioReadv<'a> { + fn as_ref(&self) -> &libc::aiocb { + &self.aiocb.aiocb.0 + } +} + +/// Asynchronously writes from a buffer to a file descriptor +/// +/// # References +/// +/// [aio_write](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_write.html) +/// +/// # Examples +/// +/// ``` +/// # use nix::errno::Errno; +/// # use nix::Error; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use std::{thread, time}; +/// # use std::os::unix::io::AsRawFd; +/// # use tempfile::tempfile; +/// const WBUF: &[u8] = b"abcdef123456"; +/// let mut f = tempfile().unwrap(); +/// let mut aiow = Box::pin( +/// AioWrite::new( +/// f.as_raw_fd(), +/// 2, //offset +/// WBUF, +/// 0, //priority +/// SigevNotify::SigevNone +/// ) +/// ); +/// aiow.as_mut().submit().unwrap(); +/// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); +/// ``` +#[derive(Debug)] +#[repr(transparent)] +pub struct AioWrite<'a> { + aiocb: AioCb, + _data: PhantomData<&'a [u8]>, + _pin: PhantomPinned, +} + +impl<'a> AioWrite<'a> { + unsafe_pinned!(aiocb: AioCb); + + /// Returns the requested length of the aio operation in bytes + /// + /// This method returns the *requested* length of the operation. To get the + /// number of bytes actually read or written by a completed operation, use + /// `aio_return` instead. + pub fn nbytes(&self) -> usize { + self.aiocb.aiocb.0.aio_nbytes + } + + /// Construct a new `AioWrite`. + /// + /// # Arguments + /// + /// * `fd`: File descriptor to write to + /// * `offs`: File offset + /// * `buf`: A memory buffer. It must outlive the `AioWrite`. + /// * `prio`: If POSIX Prioritized IO is supported, then the + /// operation will be prioritized at the process's + /// priority level minus `prio` + /// * `sigev_notify`: Determines how you will be notified of event + /// completion. + pub fn new( + fd: RawFd, + offs: off_t, + buf: &'a [u8], + prio: i32, + sigev_notify: SigevNotify, + ) -> Self { + let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); + aiocb.aiocb.0.aio_nbytes = buf.len(); + // casting an immutable buffer to a mutable pointer looks unsafe, + // but technically its only unsafe to dereference it, not to create + // it. Type Safety guarantees that we'll never pass aiocb to + // aio_read or aio_readv. + aiocb.aiocb.0.aio_buf = buf.as_ptr() as *mut c_void; + aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITE; + aiocb.aiocb.0.aio_offset = offs; + AioWrite { + aiocb, + _data: PhantomData, + _pin: PhantomPinned, + } + } + + /// Returns the file offset of the operation. + pub fn offset(&self) -> off_t { + self.aiocb.aiocb.0.aio_offset + } +} + +impl<'a> Aio for AioWrite<'a> { + type Output = usize; + + aio_methods!(aio_write); +} + +impl<'a> AsMut for AioWrite<'a> { + fn as_mut(&mut self) -> &mut libc::aiocb { + &mut self.aiocb.aiocb.0 + } +} + +impl<'a> AsRef for AioWrite<'a> { + fn as_ref(&self) -> &libc::aiocb { + &self.aiocb.aiocb.0 + } +} + +/// Asynchronously writes from a scatter/gather list of buffers to a file descriptor. +/// +/// # References +/// +/// [aio_writev](https://www.freebsd.org/cgi/man.cgi?query=aio_writev) +/// +/// # Examples +/// +#[cfg_attr(fbsd14, doc = " ```")] +#[cfg_attr(not(fbsd14), doc = " ```no_run")] +/// # use nix::errno::Errno; +/// # use nix::Error; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use std::{thread, time}; +/// # use std::io::IoSlice; +/// # use std::os::unix::io::AsRawFd; +/// # use tempfile::tempfile; +/// const wbuf0: &[u8] = b"abcdef"; +/// const wbuf1: &[u8] = b"123456"; +/// let len = wbuf0.len() + wbuf1.len(); +/// let wbufs = [IoSlice::new(wbuf0), IoSlice::new(wbuf1)]; +/// let mut f = tempfile().unwrap(); +/// let mut aiow = Box::pin( +/// AioWritev::new( +/// f.as_raw_fd(), +/// 2, //offset +/// &wbufs, +/// 0, //priority +/// SigevNotify::SigevNone +/// ) +/// ); +/// aiow.as_mut().submit().unwrap(); +/// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// assert_eq!(aiow.as_mut().aio_return().unwrap(), len); +/// ``` +#[cfg(target_os = "freebsd")] +#[derive(Debug)] +#[repr(transparent)] +pub struct AioWritev<'a> { + aiocb: AioCb, + _data: PhantomData<&'a [&'a [u8]]>, + _pin: PhantomPinned, +} + +#[cfg(target_os = "freebsd")] +impl<'a> AioWritev<'a> { + unsafe_pinned!(aiocb: AioCb); + + /// Returns the number of buffers the operation will read into. + pub fn iovlen(&self) -> usize { + self.aiocb.aiocb.0.aio_nbytes + } + + /// Construct a new `AioWritev`. + /// + /// # Arguments + /// + /// * `fd`: File descriptor to write to + /// * `offs`: File offset + /// * `bufs`: A scatter/gather list of memory buffers. They must + /// outlive the `AioWritev`. + /// * `prio`: If POSIX Prioritized IO is supported, then the + /// operation will be prioritized at the process's + /// priority level minus `prio` + /// * `sigev_notify`: Determines how you will be notified of event + /// completion. + pub fn new( + fd: RawFd, + offs: off_t, + bufs: &[IoSlice<'a>], + prio: i32, + sigev_notify: SigevNotify, + ) -> Self { + let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); + // In vectored mode, aio_nbytes stores the length of the iovec array, + // not the byte count. + aiocb.aiocb.0.aio_nbytes = bufs.len(); + // casting an immutable buffer to a mutable pointer looks unsafe, + // but technically its only unsafe to dereference it, not to create + // it. Type Safety guarantees that we'll never pass aiocb to + // aio_read or aio_readv. + aiocb.aiocb.0.aio_buf = bufs.as_ptr() as *mut c_void; + aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITEV; + aiocb.aiocb.0.aio_offset = offs; + AioWritev { + aiocb, + _data: PhantomData, + _pin: PhantomPinned, + } + } + + /// Returns the file offset of the operation. + pub fn offset(&self) -> off_t { + self.aiocb.aiocb.0.aio_offset + } +} + +#[cfg(target_os = "freebsd")] +impl<'a> Aio for AioWritev<'a> { + type Output = usize; + + aio_methods!(aio_writev); +} + +#[cfg(target_os = "freebsd")] +impl<'a> AsMut for AioWritev<'a> { + fn as_mut(&mut self) -> &mut libc::aiocb { + &mut self.aiocb.aiocb.0 + } +} + +#[cfg(target_os = "freebsd")] +impl<'a> AsRef for AioWritev<'a> { + fn as_ref(&self) -> &libc::aiocb { + &self.aiocb.aiocb.0 + } +} + +/// Cancels outstanding AIO requests for a given file descriptor. +/// +/// # Examples +/// +/// Issue an aio operation, then cancel all outstanding operations on that file +/// descriptor. +/// +/// ``` +/// # use nix::errno::Errno; +/// # use nix::Error; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use std::{thread, time}; +/// # use std::io::Write; +/// # use std::os::unix::io::AsRawFd; +/// # use tempfile::tempfile; +/// let wbuf = b"CDEF"; +/// let mut f = tempfile().unwrap(); +/// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), +/// 2, //offset +/// &wbuf[..], +/// 0, //priority +/// SigevNotify::SigevNone)); +/// aiocb.as_mut().submit().unwrap(); +/// let cs = aio_cancel_all(f.as_raw_fd()).unwrap(); +/// if cs == AioCancelStat::AioNotCanceled { +/// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// } +/// // Must call `aio_return`, but ignore the result +/// let _ = aiocb.as_mut().aio_return(); +/// ``` +/// +/// # References +/// +/// [`aio_cancel`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) +pub fn aio_cancel_all(fd: RawFd) -> Result { + match unsafe { libc::aio_cancel(fd, ptr::null_mut()) } { + libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), + libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), + libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), + -1 => Err(Errno::last()), + _ => panic!("unknown aio_cancel return value"), + } +} + +/// Suspends the calling process until at least one of the specified operations +/// have completed, a signal is delivered, or the timeout has passed. +/// +/// If `timeout` is `None`, `aio_suspend` will block indefinitely. +/// +/// # Examples +/// +/// Use `aio_suspend` to block until an aio operation completes. +/// +/// ``` +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use std::os::unix::io::AsRawFd; +/// # use tempfile::tempfile; +/// const WBUF: &[u8] = b"abcdef123456"; +/// let mut f = tempfile().unwrap(); +/// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), +/// 2, //offset +/// WBUF, +/// 0, //priority +/// SigevNotify::SigevNone)); +/// aiocb.as_mut().submit().unwrap(); +/// aio_suspend(&[&*aiocb], None).expect("aio_suspend failed"); +/// assert_eq!(aiocb.as_mut().aio_return().unwrap() as usize, WBUF.len()); +/// ``` +/// # References +/// +/// [`aio_suspend`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_suspend.html) +pub fn aio_suspend( + list: &[&dyn AsRef], + timeout: Option, +) -> Result<()> { + let p = list as *const [&dyn AsRef] + as *const [*const libc::aiocb] as *const *const libc::aiocb; + let timep = match timeout { + None => ptr::null::(), + Some(x) => x.as_ref() as *const libc::timespec, + }; + Errno::result(unsafe { libc::aio_suspend(p, list.len() as i32, timep) }) + .map(drop) +} + +/// Submits multiple asynchronous I/O requests with a single system call. +/// +/// They are not guaranteed to complete atomically, and the order in which the +/// requests are carried out is not specified. Reads, and writes may be freely +/// mixed. +/// +/// # Examples +/// +/// Use `lio_listio` to submit an aio operation and wait for its completion. In +/// this case, there is no need to use aio_suspend to wait or `error` to poll. +/// This mode is useful for otherwise-synchronous programs that want to execute +/// a handful of I/O operations in parallel. +/// ``` +/// # use std::os::unix::io::AsRawFd; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use tempfile::tempfile; +/// const WBUF: &[u8] = b"abcdef123456"; +/// let mut f = tempfile().unwrap(); +/// let mut aiow = Box::pin(AioWrite::new( +/// f.as_raw_fd(), +/// 2, // offset +/// WBUF, +/// 0, // priority +/// SigevNotify::SigevNone +/// )); +/// lio_listio(LioMode::LIO_WAIT, &mut[aiow.as_mut()], SigevNotify::SigevNone) +/// .unwrap(); +/// // At this point, we are guaranteed that aiow is complete. +/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); +/// ``` +/// +/// Use `lio_listio` to submit multiple asynchronous operations with a single +/// syscall, but receive notification individually. This is an efficient +/// technique for reducing overall context-switch overhead, especially when +/// combined with kqueue. +/// ``` +/// # use std::os::unix::io::AsRawFd; +/// # use std::thread; +/// # use std::time; +/// # use nix::errno::Errno; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use tempfile::tempfile; +/// const WBUF: &[u8] = b"abcdef123456"; +/// let mut f = tempfile().unwrap(); +/// let mut aiow = Box::pin(AioWrite::new( +/// f.as_raw_fd(), +/// 2, // offset +/// WBUF, +/// 0, // priority +/// SigevNotify::SigevNone +/// )); +/// lio_listio(LioMode::LIO_NOWAIT, &mut[aiow.as_mut()], SigevNotify::SigevNone) +/// .unwrap(); +/// // We must wait for the completion of each individual operation +/// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); +/// ``` +/// +/// Use `lio_listio` to submit multiple operations, and receive notification +/// only when all of them are complete. This can be useful when there is some +/// logical relationship between the operations. But beware! Errors or system +/// resource limitations may cause `lio_listio` to return `EIO`, `EAGAIN`, or +/// `EINTR`, in which case some but not all operations may have been submitted. +/// In that case, you must check the status of each individual operation, and +/// possibly resubmit some. +/// ``` +/// # use libc::c_int; +/// # use std::os::unix::io::AsRawFd; +/// # use std::sync::atomic::{AtomicBool, Ordering}; +/// # use std::thread; +/// # use std::time; +/// # use lazy_static::lazy_static; +/// # use nix::errno::Errno; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::*; +/// # use tempfile::tempfile; +/// lazy_static! { +/// pub static ref SIGNALED: AtomicBool = AtomicBool::new(false); +/// } +/// +/// extern fn sigfunc(_: c_int) { +/// SIGNALED.store(true, Ordering::Relaxed); +/// } +/// let sa = SigAction::new(SigHandler::Handler(sigfunc), +/// SaFlags::SA_RESETHAND, +/// SigSet::empty()); +/// SIGNALED.store(false, Ordering::Relaxed); +/// unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); +/// +/// const WBUF: &[u8] = b"abcdef123456"; +/// let mut f = tempfile().unwrap(); +/// let mut aiow = Box::pin(AioWrite::new( +/// f.as_raw_fd(), +/// 2, // offset +/// WBUF, +/// 0, // priority +/// SigevNotify::SigevNone +/// )); +/// let sev = SigevNotify::SigevSignal { signal: Signal::SIGUSR2, si_value: 0 }; +/// lio_listio(LioMode::LIO_NOWAIT, &mut[aiow.as_mut()], sev).unwrap(); +/// while !SIGNALED.load(Ordering::Relaxed) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// // At this point, since `lio_listio` returned success and delivered its +/// // notification, we know that all operations are complete. +/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); +/// ``` +pub fn lio_listio( + mode: LioMode, + list: &mut [Pin<&mut dyn AsMut>], + sigev_notify: SigevNotify, +) -> Result<()> { + let p = list as *mut [Pin<&mut dyn AsMut>] + as *mut [*mut libc::aiocb] as *mut *mut libc::aiocb; + let sigev = SigEvent::new(sigev_notify); + let sigevp = &mut sigev.sigevent() as *mut libc::sigevent; + Errno::result(unsafe { + libc::lio_listio(mode as i32, p, list.len() as i32, sigevp) + }) + .map(drop) +} + +#[cfg(test)] +mod t { + use super::*; + + /// aio_suspend relies on casting Rust Aio* struct pointers to libc::aiocb + /// pointers. This test ensures that such casts are valid. + #[test] + fn casting() { + let sev = SigevNotify::SigevNone; + let aiof = AioFsync::new(666, AioFsyncMode::O_SYNC, 0, sev); + assert_eq!( + aiof.as_ref() as *const libc::aiocb, + &aiof as *const AioFsync as *const libc::aiocb + ); + + let mut rbuf = []; + let aior = AioRead::new(666, 0, &mut rbuf, 0, sev); + assert_eq!( + aior.as_ref() as *const libc::aiocb, + &aior as *const AioRead as *const libc::aiocb + ); + + let wbuf = []; + let aiow = AioWrite::new(666, 0, &wbuf, 0, sev); + assert_eq!( + aiow.as_ref() as *const libc::aiocb, + &aiow as *const AioWrite as *const libc::aiocb + ); + } + + #[cfg(target_os = "freebsd")] + #[test] + fn casting_vectored() { + let sev = SigevNotify::SigevNone; + + let mut rbuf = []; + let mut rbufs = [IoSliceMut::new(&mut rbuf)]; + let aiorv = AioReadv::new(666, 0, &mut rbufs[..], 0, sev); + assert_eq!( + aiorv.as_ref() as *const libc::aiocb, + &aiorv as *const AioReadv as *const libc::aiocb + ); + + let wbuf = []; + let wbufs = [IoSlice::new(&wbuf)]; + let aiowv = AioWritev::new(666, 0, &wbufs, 0, sev); + assert_eq!( + aiowv.as_ref() as *const libc::aiocb, + &aiowv as *const AioWritev as *const libc::aiocb + ); + } +} diff --git a/vendor/nix-0.26.2/src/sys/epoll.rs b/vendor/nix-0.26.2/src/sys/epoll.rs new file mode 100644 index 0000000000000..58def2e788026 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/epoll.rs @@ -0,0 +1,128 @@ +use crate::errno::Errno; +use crate::Result; +use libc::{self, c_int}; +use std::mem; +use std::os::unix::io::RawFd; +use std::ptr; + +libc_bitflags!( + pub struct EpollFlags: c_int { + EPOLLIN; + EPOLLPRI; + EPOLLOUT; + EPOLLRDNORM; + EPOLLRDBAND; + EPOLLWRNORM; + EPOLLWRBAND; + EPOLLMSG; + EPOLLERR; + EPOLLHUP; + EPOLLRDHUP; + EPOLLEXCLUSIVE; + #[cfg(not(target_arch = "mips"))] + EPOLLWAKEUP; + EPOLLONESHOT; + EPOLLET; + } +); + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(i32)] +#[non_exhaustive] +pub enum EpollOp { + EpollCtlAdd = libc::EPOLL_CTL_ADD, + EpollCtlDel = libc::EPOLL_CTL_DEL, + EpollCtlMod = libc::EPOLL_CTL_MOD, +} + +libc_bitflags! { + pub struct EpollCreateFlags: c_int { + EPOLL_CLOEXEC; + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(transparent)] +pub struct EpollEvent { + event: libc::epoll_event, +} + +impl EpollEvent { + pub fn new(events: EpollFlags, data: u64) -> Self { + EpollEvent { + event: libc::epoll_event { + events: events.bits() as u32, + u64: data, + }, + } + } + + pub fn empty() -> Self { + unsafe { mem::zeroed::() } + } + + pub fn events(&self) -> EpollFlags { + EpollFlags::from_bits(self.event.events as c_int).unwrap() + } + + pub fn data(&self) -> u64 { + self.event.u64 + } +} + +#[inline] +pub fn epoll_create() -> Result { + let res = unsafe { libc::epoll_create(1024) }; + + Errno::result(res) +} + +#[inline] +pub fn epoll_create1(flags: EpollCreateFlags) -> Result { + let res = unsafe { libc::epoll_create1(flags.bits()) }; + + Errno::result(res) +} + +#[inline] +pub fn epoll_ctl<'a, T>( + epfd: RawFd, + op: EpollOp, + fd: RawFd, + event: T, +) -> Result<()> +where + T: Into>, +{ + let mut event: Option<&mut EpollEvent> = event.into(); + if event.is_none() && op != EpollOp::EpollCtlDel { + Err(Errno::EINVAL) + } else { + let res = unsafe { + if let Some(ref mut event) = event { + libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event) + } else { + libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut()) + } + }; + Errno::result(res).map(drop) + } +} + +#[inline] +pub fn epoll_wait( + epfd: RawFd, + events: &mut [EpollEvent], + timeout_ms: isize, +) -> Result { + let res = unsafe { + libc::epoll_wait( + epfd, + events.as_mut_ptr() as *mut libc::epoll_event, + events.len() as c_int, + timeout_ms as c_int, + ) + }; + + Errno::result(res).map(|r| r as usize) +} diff --git a/vendor/nix-0.26.2/src/sys/event.rs b/vendor/nix-0.26.2/src/sys/event.rs new file mode 100644 index 0000000000000..d8ad628ea2280 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/event.rs @@ -0,0 +1,374 @@ +/* TOOD: Implement for other kqueue based systems + */ + +use crate::{Errno, Result}; +#[cfg(not(target_os = "netbsd"))] +use libc::{c_int, c_long, intptr_t, time_t, timespec, uintptr_t}; +#[cfg(target_os = "netbsd")] +use libc::{c_long, intptr_t, size_t, time_t, timespec, uintptr_t}; +use std::convert::TryInto; +use std::mem; +use std::os::unix::io::RawFd; +use std::ptr; + +// Redefine kevent in terms of programmer-friendly enums and bitfields. +#[repr(C)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct KEvent { + kevent: libc::kevent, +} + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +type type_of_udata = *mut libc::c_void; +#[cfg(any(target_os = "netbsd"))] +type type_of_udata = intptr_t; + +#[cfg(target_os = "netbsd")] +type type_of_event_filter = u32; +#[cfg(not(target_os = "netbsd"))] +type type_of_event_filter = i16; +libc_enum! { + #[cfg_attr(target_os = "netbsd", repr(u32))] + #[cfg_attr(not(target_os = "netbsd"), repr(i16))] + #[non_exhaustive] + pub enum EventFilter { + EVFILT_AIO, + /// Returns whenever there is no remaining data in the write buffer + #[cfg(target_os = "freebsd")] + EVFILT_EMPTY, + #[cfg(target_os = "dragonfly")] + EVFILT_EXCEPT, + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos"))] + EVFILT_FS, + #[cfg(target_os = "freebsd")] + EVFILT_LIO, + #[cfg(any(target_os = "ios", target_os = "macos"))] + EVFILT_MACHPORT, + EVFILT_PROC, + /// Returns events associated with the process referenced by a given + /// process descriptor, created by `pdfork()`. The events to monitor are: + /// + /// - NOTE_EXIT: the process has exited. The exit status will be stored in data. + #[cfg(target_os = "freebsd")] + EVFILT_PROCDESC, + EVFILT_READ, + /// Returns whenever an asynchronous `sendfile()` call completes. + #[cfg(target_os = "freebsd")] + EVFILT_SENDFILE, + EVFILT_SIGNAL, + EVFILT_TIMER, + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos"))] + EVFILT_USER, + #[cfg(any(target_os = "ios", target_os = "macos"))] + EVFILT_VM, + EVFILT_VNODE, + EVFILT_WRITE, + } + impl TryFrom +} + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub type type_of_event_flag = u16; +#[cfg(any(target_os = "netbsd"))] +pub type type_of_event_flag = u32; +libc_bitflags! { + pub struct EventFlag: type_of_event_flag { + EV_ADD; + EV_CLEAR; + EV_DELETE; + EV_DISABLE; + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd"))] + EV_DISPATCH; + #[cfg(target_os = "freebsd")] + EV_DROP; + EV_ENABLE; + EV_EOF; + EV_ERROR; + #[cfg(any(target_os = "macos", target_os = "ios"))] + EV_FLAG0; + EV_FLAG1; + #[cfg(target_os = "dragonfly")] + EV_NODATA; + EV_ONESHOT; + #[cfg(any(target_os = "macos", target_os = "ios"))] + EV_OOBAND; + #[cfg(any(target_os = "macos", target_os = "ios"))] + EV_POLL; + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd"))] + EV_RECEIPT; + } +} + +libc_bitflags!( + pub struct FilterFlag: u32 { + #[cfg(any(target_os = "macos", target_os = "ios"))] + NOTE_ABSOLUTE; + NOTE_ATTRIB; + NOTE_CHILD; + NOTE_DELETE; + #[cfg(target_os = "openbsd")] + NOTE_EOF; + NOTE_EXEC; + NOTE_EXIT; + #[cfg(any(target_os = "macos", target_os = "ios"))] + NOTE_EXITSTATUS; + NOTE_EXTEND; + #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] + NOTE_FFAND; + #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] + NOTE_FFCOPY; + #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] + NOTE_FFCTRLMASK; + #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] + NOTE_FFLAGSMASK; + #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] + NOTE_FFNOP; + #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] + NOTE_FFOR; + NOTE_FORK; + NOTE_LINK; + NOTE_LOWAT; + #[cfg(target_os = "freebsd")] + NOTE_MSECONDS; + #[cfg(any(target_os = "macos", target_os = "ios"))] + NOTE_NONE; + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] + NOTE_NSECONDS; + #[cfg(target_os = "dragonfly")] + NOTE_OOB; + NOTE_PCTRLMASK; + NOTE_PDATAMASK; + NOTE_RENAME; + NOTE_REVOKE; + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] + NOTE_SECONDS; + #[cfg(any(target_os = "macos", target_os = "ios"))] + NOTE_SIGNAL; + NOTE_TRACK; + NOTE_TRACKERR; + #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] + NOTE_TRIGGER; + #[cfg(target_os = "openbsd")] + NOTE_TRUNCATE; + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] + NOTE_USECONDS; + #[cfg(any(target_os = "macos", target_os = "ios"))] + NOTE_VM_ERROR; + #[cfg(any(target_os = "macos", target_os = "ios"))] + NOTE_VM_PRESSURE; + #[cfg(any(target_os = "macos", target_os = "ios"))] + NOTE_VM_PRESSURE_SUDDEN_TERMINATE; + #[cfg(any(target_os = "macos", target_os = "ios"))] + NOTE_VM_PRESSURE_TERMINATE; + NOTE_WRITE; + } +); + +pub fn kqueue() -> Result { + let res = unsafe { libc::kqueue() }; + + Errno::result(res) +} + +// KEvent can't derive Send because on some operating systems, udata is defined +// as a void*. However, KEvent's public API always treats udata as an intptr_t, +// which is safe to Send. +unsafe impl Send for KEvent {} + +impl KEvent { + #[allow(clippy::needless_update)] // Not needless on all platforms. + pub fn new( + ident: uintptr_t, + filter: EventFilter, + flags: EventFlag, + fflags: FilterFlag, + data: intptr_t, + udata: intptr_t, + ) -> KEvent { + KEvent { + kevent: libc::kevent { + ident, + filter: filter as type_of_event_filter, + flags: flags.bits(), + fflags: fflags.bits(), + // data can be either i64 or intptr_t, depending on platform + data: data as _, + udata: udata as type_of_udata, + ..unsafe { mem::zeroed() } + }, + } + } + + pub fn ident(&self) -> uintptr_t { + self.kevent.ident + } + + pub fn filter(&self) -> Result { + self.kevent.filter.try_into() + } + + pub fn flags(&self) -> EventFlag { + EventFlag::from_bits(self.kevent.flags).unwrap() + } + + pub fn fflags(&self) -> FilterFlag { + FilterFlag::from_bits(self.kevent.fflags).unwrap() + } + + pub fn data(&self) -> intptr_t { + self.kevent.data as intptr_t + } + + pub fn udata(&self) -> intptr_t { + self.kevent.udata as intptr_t + } +} + +pub fn kevent( + kq: RawFd, + changelist: &[KEvent], + eventlist: &mut [KEvent], + timeout_ms: usize, +) -> Result { + // Convert ms to timespec + let timeout = timespec { + tv_sec: (timeout_ms / 1000) as time_t, + tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long, + }; + + kevent_ts(kq, changelist, eventlist, Some(timeout)) +} + +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd" +))] +type type_of_nchanges = c_int; +#[cfg(target_os = "netbsd")] +type type_of_nchanges = size_t; + +pub fn kevent_ts( + kq: RawFd, + changelist: &[KEvent], + eventlist: &mut [KEvent], + timeout_opt: Option, +) -> Result { + let res = unsafe { + libc::kevent( + kq, + changelist.as_ptr() as *const libc::kevent, + changelist.len() as type_of_nchanges, + eventlist.as_mut_ptr() as *mut libc::kevent, + eventlist.len() as type_of_nchanges, + if let Some(ref timeout) = timeout_opt { + timeout as *const timespec + } else { + ptr::null() + }, + ) + }; + + Errno::result(res).map(|r| r as usize) +} + +#[inline] +pub fn ev_set( + ev: &mut KEvent, + ident: usize, + filter: EventFilter, + flags: EventFlag, + fflags: FilterFlag, + udata: intptr_t, +) { + ev.kevent.ident = ident as uintptr_t; + ev.kevent.filter = filter as type_of_event_filter; + ev.kevent.flags = flags.bits(); + ev.kevent.fflags = fflags.bits(); + ev.kevent.data = 0; + ev.kevent.udata = udata as type_of_udata; +} + +#[test] +fn test_struct_kevent() { + use std::mem; + + let udata: intptr_t = 12345; + + let actual = KEvent::new( + 0xdead_beef, + EventFilter::EVFILT_READ, + EventFlag::EV_ONESHOT | EventFlag::EV_ADD, + FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, + 0x1337, + udata, + ); + assert_eq!(0xdead_beef, actual.ident()); + let filter = actual.kevent.filter; + assert_eq!(libc::EVFILT_READ, filter); + assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits()); + assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits()); + assert_eq!(0x1337, actual.data()); + assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata); + assert_eq!(mem::size_of::(), mem::size_of::()); +} + +#[test] +fn test_kevent_filter() { + let udata: intptr_t = 12345; + + let actual = KEvent::new( + 0xdead_beef, + EventFilter::EVFILT_READ, + EventFlag::EV_ONESHOT | EventFlag::EV_ADD, + FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, + 0x1337, + udata, + ); + assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap()); +} diff --git a/vendor/nix-0.26.2/src/sys/eventfd.rs b/vendor/nix-0.26.2/src/sys/eventfd.rs new file mode 100644 index 0000000000000..cd906720cd660 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/eventfd.rs @@ -0,0 +1,17 @@ +use crate::errno::Errno; +use crate::Result; +use std::os::unix::io::RawFd; + +libc_bitflags! { + pub struct EfdFlags: libc::c_int { + EFD_CLOEXEC; // Since Linux 2.6.27 + EFD_NONBLOCK; // Since Linux 2.6.27 + EFD_SEMAPHORE; // Since Linux 2.6.30 + } +} + +pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result { + let res = unsafe { libc::eventfd(initval, flags.bits()) }; + + Errno::result(res).map(|r| r as RawFd) +} diff --git a/vendor/nix-0.26.2/src/sys/inotify.rs b/vendor/nix-0.26.2/src/sys/inotify.rs new file mode 100644 index 0000000000000..84356ec70f0e8 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/inotify.rs @@ -0,0 +1,248 @@ +//! Monitoring API for filesystem events. +//! +//! Inotify is a Linux-only API to monitor filesystems events. +//! +//! For more documentation, please read [inotify(7)](https://man7.org/linux/man-pages/man7/inotify.7.html). +//! +//! # Examples +//! +//! Monitor all events happening in directory "test": +//! ```no_run +//! # use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify}; +//! # +//! // We create a new inotify instance. +//! let instance = Inotify::init(InitFlags::empty()).unwrap(); +//! +//! // We add a new watch on directory "test" for all events. +//! let wd = instance.add_watch("test", AddWatchFlags::IN_ALL_EVENTS).unwrap(); +//! +//! loop { +//! // We read from our inotify instance for events. +//! let events = instance.read_events().unwrap(); +//! println!("Events: {:?}", events); +//! } +//! ``` + +use crate::errno::Errno; +use crate::unistd::read; +use crate::NixPath; +use crate::Result; +use cfg_if::cfg_if; +use libc::{c_char, c_int}; +use std::ffi::{CStr, OsStr, OsString}; +use std::mem::{size_of, MaybeUninit}; +use std::os::unix::ffi::OsStrExt; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::ptr; + +libc_bitflags! { + /// Configuration options for [`inotify_add_watch`](fn.inotify_add_watch.html). + pub struct AddWatchFlags: u32 { + /// File was accessed. + IN_ACCESS; + /// File was modified. + IN_MODIFY; + /// Metadata changed. + IN_ATTRIB; + /// Writable file was closed. + IN_CLOSE_WRITE; + /// Nonwritable file was closed. + IN_CLOSE_NOWRITE; + /// File was opened. + IN_OPEN; + /// File was moved from X. + IN_MOVED_FROM; + /// File was moved to Y. + IN_MOVED_TO; + /// Subfile was created. + IN_CREATE; + /// Subfile was deleted. + IN_DELETE; + /// Self was deleted. + IN_DELETE_SELF; + /// Self was moved. + IN_MOVE_SELF; + + /// Backing filesystem was unmounted. + IN_UNMOUNT; + /// Event queue overflowed. + IN_Q_OVERFLOW; + /// File was ignored. + IN_IGNORED; + + /// Combination of `IN_CLOSE_WRITE` and `IN_CLOSE_NOWRITE`. + IN_CLOSE; + /// Combination of `IN_MOVED_FROM` and `IN_MOVED_TO`. + IN_MOVE; + + /// Only watch the path if it is a directory. + IN_ONLYDIR; + /// Don't follow symlinks. + IN_DONT_FOLLOW; + + /// Event occurred against directory. + IN_ISDIR; + /// Only send event once. + IN_ONESHOT; + /// All of the events. + IN_ALL_EVENTS; + } +} + +libc_bitflags! { + /// Configuration options for [`inotify_init1`](fn.inotify_init1.html). + pub struct InitFlags: c_int { + /// Set the `FD_CLOEXEC` flag on the file descriptor. + IN_CLOEXEC; + /// Set the `O_NONBLOCK` flag on the open file description referred to by the new file descriptor. + IN_NONBLOCK; + } +} + +/// An inotify instance. This is also a file descriptor, you can feed it to +/// other interfaces consuming file descriptors, epoll for example. +#[derive(Debug, Clone, Copy)] +pub struct Inotify { + fd: RawFd, +} + +/// This object is returned when you create a new watch on an inotify instance. +/// It is then returned as part of an event once triggered. It allows you to +/// know which watch triggered which event. +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)] +pub struct WatchDescriptor { + wd: i32, +} + +/// A single inotify event. +/// +/// For more documentation see, [inotify(7)](https://man7.org/linux/man-pages/man7/inotify.7.html). +#[derive(Debug)] +pub struct InotifyEvent { + /// Watch descriptor. This field corresponds to the watch descriptor you + /// were issued when calling add_watch. It allows you to know which watch + /// this event comes from. + pub wd: WatchDescriptor, + /// Event mask. This field is a bitfield describing the exact event that + /// occured. + pub mask: AddWatchFlags, + /// This cookie is a number that allows you to connect related events. For + /// now only IN_MOVED_FROM and IN_MOVED_TO can be connected. + pub cookie: u32, + /// Filename. This field exists only if the event was triggered for a file + /// inside the watched directory. + pub name: Option, +} + +impl Inotify { + /// Initialize a new inotify instance. + /// + /// Returns a Result containing an inotify instance. + /// + /// For more information see, [inotify_init(2)](https://man7.org/linux/man-pages/man2/inotify_init.2.html). + pub fn init(flags: InitFlags) -> Result { + let res = Errno::result(unsafe { libc::inotify_init1(flags.bits()) }); + + res.map(|fd| Inotify { fd }) + } + + /// Adds a new watch on the target file or directory. + /// + /// Returns a watch descriptor. This is not a File Descriptor! + /// + /// For more information see, [inotify_add_watch(2)](https://man7.org/linux/man-pages/man2/inotify_add_watch.2.html). + pub fn add_watch( + self, + path: &P, + mask: AddWatchFlags, + ) -> Result { + let res = path.with_nix_path(|cstr| unsafe { + libc::inotify_add_watch(self.fd, cstr.as_ptr(), mask.bits()) + })?; + + Errno::result(res).map(|wd| WatchDescriptor { wd }) + } + + /// Removes an existing watch using the watch descriptor returned by + /// inotify_add_watch. + /// + /// Returns an EINVAL error if the watch descriptor is invalid. + /// + /// For more information see, [inotify_rm_watch(2)](https://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html). + pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> { + cfg_if! { + if #[cfg(target_os = "linux")] { + let arg = wd.wd; + } else if #[cfg(target_os = "android")] { + let arg = wd.wd as u32; + } + } + let res = unsafe { libc::inotify_rm_watch(self.fd, arg) }; + + Errno::result(res).map(drop) + } + + /// Reads a collection of events from the inotify file descriptor. This call + /// can either be blocking or non blocking depending on whether IN_NONBLOCK + /// was set at initialization. + /// + /// Returns as many events as available. If the call was non blocking and no + /// events could be read then the EAGAIN error is returned. + pub fn read_events(self) -> Result> { + let header_size = size_of::(); + const BUFSIZ: usize = 4096; + let mut buffer = [0u8; BUFSIZ]; + let mut events = Vec::new(); + let mut offset = 0; + + let nread = read(self.fd, &mut buffer)?; + + while (nread - offset) >= header_size { + let event = unsafe { + let mut event = MaybeUninit::::uninit(); + ptr::copy_nonoverlapping( + buffer.as_ptr().add(offset), + event.as_mut_ptr() as *mut u8, + (BUFSIZ - offset).min(header_size), + ); + event.assume_init() + }; + + let name = match event.len { + 0 => None, + _ => { + let ptr = unsafe { + buffer.as_ptr().add(offset + header_size) + as *const c_char + }; + let cstr = unsafe { CStr::from_ptr(ptr) }; + + Some(OsStr::from_bytes(cstr.to_bytes()).to_owned()) + } + }; + + events.push(InotifyEvent { + wd: WatchDescriptor { wd: event.wd }, + mask: AddWatchFlags::from_bits_truncate(event.mask), + cookie: event.cookie, + name, + }); + + offset += header_size + event.len as usize; + } + + Ok(events) + } +} + +impl AsRawFd for Inotify { + fn as_raw_fd(&self) -> RawFd { + self.fd + } +} + +impl FromRawFd for Inotify { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + Inotify { fd } + } +} diff --git a/vendor/nix-0.26.2/src/sys/ioctl/bsd.rs b/vendor/nix-0.26.2/src/sys/ioctl/bsd.rs new file mode 100644 index 0000000000000..307994cb969f9 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/ioctl/bsd.rs @@ -0,0 +1,129 @@ +/// The datatype used for the ioctl number +#[doc(hidden)] +#[cfg(not(target_os = "illumos"))] +pub type ioctl_num_type = ::libc::c_ulong; + +#[doc(hidden)] +#[cfg(target_os = "illumos")] +pub type ioctl_num_type = ::libc::c_int; + +/// The datatype used for the 3rd argument +#[doc(hidden)] +pub type ioctl_param_type = ::libc::c_int; + +mod consts { + use crate::sys::ioctl::ioctl_num_type; + #[doc(hidden)] + pub const VOID: ioctl_num_type = 0x2000_0000; + #[doc(hidden)] + pub const OUT: ioctl_num_type = 0x4000_0000; + #[doc(hidden)] + #[allow(overflowing_literals)] + pub const IN: ioctl_num_type = 0x8000_0000; + #[doc(hidden)] + pub const INOUT: ioctl_num_type = IN | OUT; + #[doc(hidden)] + pub const IOCPARM_MASK: ioctl_num_type = 0x1fff; +} + +pub use self::consts::*; + +#[macro_export] +#[doc(hidden)] +macro_rules! ioc { + ($inout:expr, $group:expr, $num:expr, $len:expr) => { + $inout + | (($len as $crate::sys::ioctl::ioctl_num_type + & $crate::sys::ioctl::IOCPARM_MASK) + << 16) + | (($group as $crate::sys::ioctl::ioctl_num_type) << 8) + | ($num as $crate::sys::ioctl::ioctl_num_type) + }; +} + +/// Generate an ioctl request code for a command that passes no data. +/// +/// This is equivalent to the `_IO()` macro exposed by the C ioctl API. +/// +/// You should only use this macro directly if the `ioctl` you're working +/// with is "bad" and you cannot use `ioctl_none!()` directly. +/// +/// # Example +/// +/// ``` +/// # #[macro_use] extern crate nix; +/// const KVMIO: u8 = 0xAE; +/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03)); +/// # fn main() {} +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! request_code_none { + ($g:expr, $n:expr) => { + ioc!($crate::sys::ioctl::VOID, $g, $n, 0) + }; +} + +/// Generate an ioctl request code for a command that passes an integer +/// +/// This is equivalent to the `_IOWINT()` macro exposed by the C ioctl API. +/// +/// You should only use this macro directly if the `ioctl` you're working +/// with is "bad" and you cannot use `ioctl_write_int!()` directly. +#[macro_export(local_inner_macros)] +macro_rules! request_code_write_int { + ($g:expr, $n:expr) => { + ioc!( + $crate::sys::ioctl::VOID, + $g, + $n, + ::std::mem::size_of::<$crate::libc::c_int>() + ) + }; +} + +/// Generate an ioctl request code for a command that reads. +/// +/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API. +/// +/// You should only use this macro directly if the `ioctl` you're working +/// with is "bad" and you cannot use `ioctl_read!()` directly. +/// +/// The read/write direction is relative to userland, so this +/// command would be userland is reading and the kernel is +/// writing. +#[macro_export(local_inner_macros)] +macro_rules! request_code_read { + ($g:expr, $n:expr, $len:expr) => { + ioc!($crate::sys::ioctl::OUT, $g, $n, $len) + }; +} + +/// Generate an ioctl request code for a command that writes. +/// +/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API. +/// +/// You should only use this macro directly if the `ioctl` you're working +/// with is "bad" and you cannot use `ioctl_write!()` directly. +/// +/// The read/write direction is relative to userland, so this +/// command would be userland is writing and the kernel is +/// reading. +#[macro_export(local_inner_macros)] +macro_rules! request_code_write { + ($g:expr, $n:expr, $len:expr) => { + ioc!($crate::sys::ioctl::IN, $g, $n, $len) + }; +} + +/// Generate an ioctl request code for a command that reads and writes. +/// +/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API. +/// +/// You should only use this macro directly if the `ioctl` you're working +/// with is "bad" and you cannot use `ioctl_readwrite!()` directly. +#[macro_export(local_inner_macros)] +macro_rules! request_code_readwrite { + ($g:expr, $n:expr, $len:expr) => { + ioc!($crate::sys::ioctl::INOUT, $g, $n, $len) + }; +} diff --git a/vendor/nix-0.26.2/src/sys/ioctl/linux.rs b/vendor/nix-0.26.2/src/sys/ioctl/linux.rs new file mode 100644 index 0000000000000..0c0a2090538f8 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/ioctl/linux.rs @@ -0,0 +1,172 @@ +/// The datatype used for the ioctl number +#[cfg(any(target_os = "android", target_env = "musl"))] +#[doc(hidden)] +pub type ioctl_num_type = ::libc::c_int; +#[cfg(not(any(target_os = "android", target_env = "musl")))] +#[doc(hidden)] +pub type ioctl_num_type = ::libc::c_ulong; +/// The datatype used for the 3rd argument +#[doc(hidden)] +pub type ioctl_param_type = ::libc::c_ulong; + +#[doc(hidden)] +pub const NRBITS: ioctl_num_type = 8; +#[doc(hidden)] +pub const TYPEBITS: ioctl_num_type = 8; + +#[cfg(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "sparc64" +))] +mod consts { + #[doc(hidden)] + pub const NONE: u8 = 1; + #[doc(hidden)] + pub const READ: u8 = 2; + #[doc(hidden)] + pub const WRITE: u8 = 4; + #[doc(hidden)] + pub const SIZEBITS: u8 = 13; + #[doc(hidden)] + pub const DIRBITS: u8 = 3; +} + +// "Generic" ioctl protocol +#[cfg(any( + target_arch = "x86", + target_arch = "arm", + target_arch = "s390x", + target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "riscv32", + target_arch = "riscv64" +))] +mod consts { + #[doc(hidden)] + pub const NONE: u8 = 0; + #[doc(hidden)] + pub const READ: u8 = 2; + #[doc(hidden)] + pub const WRITE: u8 = 1; + #[doc(hidden)] + pub const SIZEBITS: u8 = 14; + #[doc(hidden)] + pub const DIRBITS: u8 = 2; +} + +pub use self::consts::*; + +#[doc(hidden)] +pub const NRSHIFT: ioctl_num_type = 0; +#[doc(hidden)] +pub const TYPESHIFT: ioctl_num_type = NRSHIFT + NRBITS as ioctl_num_type; +#[doc(hidden)] +pub const SIZESHIFT: ioctl_num_type = TYPESHIFT + TYPEBITS as ioctl_num_type; +#[doc(hidden)] +pub const DIRSHIFT: ioctl_num_type = SIZESHIFT + SIZEBITS as ioctl_num_type; + +#[doc(hidden)] +pub const NRMASK: ioctl_num_type = (1 << NRBITS) - 1; +#[doc(hidden)] +pub const TYPEMASK: ioctl_num_type = (1 << TYPEBITS) - 1; +#[doc(hidden)] +pub const SIZEMASK: ioctl_num_type = (1 << SIZEBITS) - 1; +#[doc(hidden)] +pub const DIRMASK: ioctl_num_type = (1 << DIRBITS) - 1; + +/// Encode an ioctl command. +#[macro_export] +#[doc(hidden)] +macro_rules! ioc { + ($dir:expr, $ty:expr, $nr:expr, $sz:expr) => { + (($dir as $crate::sys::ioctl::ioctl_num_type + & $crate::sys::ioctl::DIRMASK) + << $crate::sys::ioctl::DIRSHIFT) + | (($ty as $crate::sys::ioctl::ioctl_num_type + & $crate::sys::ioctl::TYPEMASK) + << $crate::sys::ioctl::TYPESHIFT) + | (($nr as $crate::sys::ioctl::ioctl_num_type + & $crate::sys::ioctl::NRMASK) + << $crate::sys::ioctl::NRSHIFT) + | (($sz as $crate::sys::ioctl::ioctl_num_type + & $crate::sys::ioctl::SIZEMASK) + << $crate::sys::ioctl::SIZESHIFT) + }; +} + +/// Generate an ioctl request code for a command that passes no data. +/// +/// This is equivalent to the `_IO()` macro exposed by the C ioctl API. +/// +/// You should only use this macro directly if the `ioctl` you're working +/// with is "bad" and you cannot use `ioctl_none!()` directly. +/// +/// # Example +/// +/// ``` +/// # #[macro_use] extern crate nix; +/// const KVMIO: u8 = 0xAE; +/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03)); +/// # fn main() {} +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! request_code_none { + ($ty:expr, $nr:expr) => { + ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0) + }; +} + +/// Generate an ioctl request code for a command that reads. +/// +/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API. +/// +/// You should only use this macro directly if the `ioctl` you're working +/// with is "bad" and you cannot use `ioctl_read!()` directly. +/// +/// The read/write direction is relative to userland, so this +/// command would be userland is reading and the kernel is +/// writing. +#[macro_export(local_inner_macros)] +macro_rules! request_code_read { + ($ty:expr, $nr:expr, $sz:expr) => { + ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz) + }; +} + +/// Generate an ioctl request code for a command that writes. +/// +/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API. +/// +/// You should only use this macro directly if the `ioctl` you're working +/// with is "bad" and you cannot use `ioctl_write!()` directly. +/// +/// The read/write direction is relative to userland, so this +/// command would be userland is writing and the kernel is +/// reading. +#[macro_export(local_inner_macros)] +macro_rules! request_code_write { + ($ty:expr, $nr:expr, $sz:expr) => { + ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz) + }; +} + +/// Generate an ioctl request code for a command that reads and writes. +/// +/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API. +/// +/// You should only use this macro directly if the `ioctl` you're working +/// with is "bad" and you cannot use `ioctl_readwrite!()` directly. +#[macro_export(local_inner_macros)] +macro_rules! request_code_readwrite { + ($ty:expr, $nr:expr, $sz:expr) => { + ioc!( + $crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, + $ty, + $nr, + $sz + ) + }; +} diff --git a/vendor/nix-0.26.2/src/sys/ioctl/mod.rs b/vendor/nix-0.26.2/src/sys/ioctl/mod.rs new file mode 100644 index 0000000000000..98d6b5c99d481 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/ioctl/mod.rs @@ -0,0 +1,786 @@ +//! Provide helpers for making ioctl system calls. +//! +//! This library is pretty low-level and messy. `ioctl` is not fun. +//! +//! What is an `ioctl`? +//! =================== +//! +//! The `ioctl` syscall is the grab-bag syscall on POSIX systems. Don't want to add a new +//! syscall? Make it an `ioctl`! `ioctl` refers to both the syscall, and the commands that can be +//! sent with it. `ioctl` stands for "IO control", and the commands are always sent to a file +//! descriptor. +//! +//! It is common to see `ioctl`s used for the following purposes: +//! +//! * Provide read/write access to out-of-band data related to a device such as configuration +//! (for instance, setting serial port options) +//! * Provide a mechanism for performing full-duplex data transfers (for instance, xfer on SPI +//! devices). +//! * Provide access to control functions on a device (for example, on Linux you can send +//! commands like pause, resume, and eject to the CDROM device. +//! * Do whatever else the device driver creator thought made most sense. +//! +//! `ioctl`s are synchronous system calls and are similar to read and write calls in that regard. +//! They operate on file descriptors and have an identifier that specifies what the ioctl is. +//! Additionally they may read or write data and therefore need to pass along a data pointer. +//! Besides the semantics of the ioctls being confusing, the generation of this identifer can also +//! be difficult. +//! +//! Historically `ioctl` numbers were arbitrary hard-coded values. In Linux (before 2.6) and some +//! unices this has changed to a more-ordered system where the ioctl numbers are partitioned into +//! subcomponents (For linux this is documented in +//! [`Documentation/ioctl/ioctl-number.rst`](https://elixir.bootlin.com/linux/latest/source/Documentation/userspace-api/ioctl/ioctl-number.rst)): +//! +//! * Number: The actual ioctl ID +//! * Type: A grouping of ioctls for a common purpose or driver +//! * Size: The size in bytes of the data that will be transferred +//! * Direction: Whether there is any data and if it's read, write, or both +//! +//! Newer drivers should not generate complete integer identifiers for their `ioctl`s instead +//! preferring to use the 4 components above to generate the final ioctl identifier. Because of +//! how old `ioctl`s are, however, there are many hard-coded `ioctl` identifiers. These are +//! commonly referred to as "bad" in `ioctl` documentation. +//! +//! Defining `ioctl`s +//! ================= +//! +//! This library provides several `ioctl_*!` macros for binding `ioctl`s. These generate public +//! unsafe functions that can then be used for calling the ioctl. This macro has a few different +//! ways it can be used depending on the specific ioctl you're working with. +//! +//! A simple `ioctl` is `SPI_IOC_RD_MODE`. This ioctl works with the SPI interface on Linux. This +//! specific `ioctl` reads the mode of the SPI device as a `u8`. It's declared in +//! `/include/uapi/linux/spi/spidev.h` as `_IOR(SPI_IOC_MAGIC, 1, __u8)`. Since it uses the `_IOR` +//! macro, we know it's a `read` ioctl and can use the `ioctl_read!` macro as follows: +//! +//! ``` +//! # #[macro_use] extern crate nix; +//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h +//! const SPI_IOC_TYPE_MODE: u8 = 1; +//! ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8); +//! # fn main() {} +//! ``` +//! +//! This generates the function: +//! +//! ``` +//! # #[macro_use] extern crate nix; +//! # use std::mem; +//! # use nix::{libc, Result}; +//! # use nix::errno::Errno; +//! # use nix::libc::c_int as c_int; +//! # const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h +//! # const SPI_IOC_TYPE_MODE: u8 = 1; +//! pub unsafe fn spi_read_mode(fd: c_int, data: *mut u8) -> Result { +//! let res = libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::()), data); +//! Errno::result(res) +//! } +//! # fn main() {} +//! ``` +//! +//! The return value for the wrapper functions generated by the `ioctl_*!` macros are `nix::Error`s. +//! These are generated by assuming the return value of the ioctl is `-1` on error and everything +//! else is a valid return value. If this is not the case, `Result::map` can be used to map some +//! of the range of "good" values (-Inf..-2, 0..Inf) into a smaller range in a helper function. +//! +//! Writing `ioctl`s generally use pointers as their data source and these should use the +//! `ioctl_write_ptr!`. But in some cases an `int` is passed directly. For these `ioctl`s use the +//! `ioctl_write_int!` macro. This variant does not take a type as the last argument: +//! +//! ``` +//! # #[macro_use] extern crate nix; +//! const HCI_IOC_MAGIC: u8 = b'k'; +//! const HCI_IOC_HCIDEVUP: u8 = 1; +//! ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP); +//! # fn main() {} +//! ``` +//! +//! Some `ioctl`s don't transfer any data, and those should use `ioctl_none!`. This macro +//! doesn't take a type and so it is declared similar to the `write_int` variant shown above. +//! +//! The mode for a given `ioctl` should be clear from the documentation if it has good +//! documentation. Otherwise it will be clear based on the macro used to generate the `ioctl` +//! number where `_IO`, `_IOR`, `_IOW`, and `_IOWR` map to "none", "read", "write_*", and "readwrite" +//! respectively. To determine the specific `write_` variant to use you'll need to find +//! what the argument type is supposed to be. If it's an `int`, then `write_int` should be used, +//! otherwise it should be a pointer and `write_ptr` should be used. On Linux the +//! [`ioctl_list` man page](https://man7.org/linux/man-pages/man2/ioctl_list.2.html) describes a +//! large number of `ioctl`s and describes their argument data type. +//! +//! Using "bad" `ioctl`s +//! -------------------- +//! +//! As mentioned earlier, there are many old `ioctl`s that do not use the newer method of +//! generating `ioctl` numbers and instead use hardcoded values. These can be used with the +//! `ioctl_*_bad!` macros. This naming comes from the Linux kernel which refers to these +//! `ioctl`s as "bad". These are a different variant as they bypass calling the macro that generates +//! the ioctl number and instead use the defined value directly. +//! +//! For example the `TCGETS` `ioctl` reads a `termios` data structure for a given file descriptor. +//! It's defined as `0x5401` in `ioctls.h` on Linux and can be implemented as: +//! +//! ``` +//! # #[macro_use] extern crate nix; +//! # #[cfg(any(target_os = "android", target_os = "linux"))] +//! # use nix::libc::TCGETS as TCGETS; +//! # #[cfg(any(target_os = "android", target_os = "linux"))] +//! # use nix::libc::termios as termios; +//! # #[cfg(any(target_os = "android", target_os = "linux"))] +//! ioctl_read_bad!(tcgets, TCGETS, termios); +//! # fn main() {} +//! ``` +//! +//! The generated function has the same form as that generated by `ioctl_read!`: +//! +//! ```text +//! pub unsafe fn tcgets(fd: c_int, data: *mut termios) -> Result; +//! ``` +//! +//! Working with Arrays +//! ------------------- +//! +//! Some `ioctl`s work with entire arrays of elements. These are supported by the `ioctl_*_buf` +//! family of macros: `ioctl_read_buf`, `ioctl_write_buf`, and `ioctl_readwrite_buf`. Note that +//! there are no "bad" versions for working with buffers. The generated functions include a `len` +//! argument to specify the number of elements (where the type of each element is specified in the +//! macro). +//! +//! Again looking to the SPI `ioctl`s on Linux for an example, there is a `SPI_IOC_MESSAGE` `ioctl` +//! that queues up multiple SPI messages by writing an entire array of `spi_ioc_transfer` structs. +//! `linux/spi/spidev.h` defines a macro to calculate the `ioctl` number like: +//! +//! ```C +//! #define SPI_IOC_MAGIC 'k' +//! #define SPI_MSGSIZE(N) ... +//! #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) +//! ``` +//! +//! The `SPI_MSGSIZE(N)` calculation is already handled by the `ioctl_*!` macros, so all that's +//! needed to define this `ioctl` is: +//! +//! ``` +//! # #[macro_use] extern crate nix; +//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h +//! const SPI_IOC_TYPE_MESSAGE: u8 = 0; +//! # pub struct spi_ioc_transfer(u64); +//! ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer); +//! # fn main() {} +//! ``` +//! +//! This generates a function like: +//! +//! ``` +//! # #[macro_use] extern crate nix; +//! # use std::mem; +//! # use nix::{libc, Result}; +//! # use nix::errno::Errno; +//! # use nix::libc::c_int as c_int; +//! # const SPI_IOC_MAGIC: u8 = b'k'; +//! # const SPI_IOC_TYPE_MESSAGE: u8 = 0; +//! # pub struct spi_ioc_transfer(u64); +//! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result { +//! let res = libc::ioctl(fd, +//! request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::()), +//! data); +//! Errno::result(res) +//! } +//! # fn main() {} +//! ``` +//! +//! Finding `ioctl` Documentation +//! ----------------------------- +//! +//! For Linux, look at your system's headers. For example, `/usr/include/linux/input.h` has a lot +//! of lines defining macros which use `_IO`, `_IOR`, `_IOW`, `_IOC`, and `_IOWR`. Some `ioctl`s are +//! documented directly in the headers defining their constants, but others have more extensive +//! documentation in man pages (like termios' `ioctl`s which are in `tty_ioctl(4)`). +//! +//! Documenting the Generated Functions +//! =================================== +//! +//! In many cases, users will wish for the functions generated by the `ioctl` +//! macro to be public and documented. For this reason, the generated functions +//! are public by default. If you wish to hide the ioctl, you will need to put +//! them in a private module. +//! +//! For documentation, it is possible to use doc comments inside the `ioctl_*!` macros. Here is an +//! example : +//! +//! ``` +//! # #[macro_use] extern crate nix; +//! # use nix::libc::c_int; +//! ioctl_read! { +//! /// Make the given terminal the controlling terminal of the calling process. The calling +//! /// process must be a session leader and not have a controlling terminal already. If the +//! /// terminal is already the controlling terminal of a different session group then the +//! /// ioctl will fail with **EPERM**, unless the caller is root (more precisely: has the +//! /// **CAP_SYS_ADMIN** capability) and arg equals 1, in which case the terminal is stolen +//! /// and all processes that had it as controlling terminal lose it. +//! tiocsctty, b't', 19, c_int +//! } +//! +//! # fn main() {} +//! ``` +use cfg_if::cfg_if; + +#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] +#[macro_use] +mod linux; + +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "redox" +))] +pub use self::linux::*; + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "haiku", + target_os = "openbsd" +))] +#[macro_use] +mod bsd; + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "haiku", + target_os = "openbsd" +))] +pub use self::bsd::*; + +/// Convert raw ioctl return value to a Nix result +#[macro_export] +#[doc(hidden)] +macro_rules! convert_ioctl_res { + ($w:expr) => {{ + $crate::errno::Errno::result($w) + }}; +} + +/// Generates a wrapper function for an ioctl that passes no data to the kernel. +/// +/// The arguments to this macro are: +/// +/// * The function name +/// * The ioctl identifier +/// * The ioctl sequence number +/// +/// The generated function has the following signature: +/// +/// ```rust,ignore +/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result +/// ``` +/// +/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). +/// +/// # Example +/// +/// The `videodev2` driver on Linux defines the `log_status` `ioctl` as: +/// +/// ```C +/// #define VIDIOC_LOG_STATUS _IO('V', 70) +/// ``` +/// +/// This can be implemented in Rust like: +/// +/// ```no_run +/// # #[macro_use] extern crate nix; +/// ioctl_none!(log_status, b'V', 70); +/// fn main() {} +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! ioctl_none { + ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type)) + } + ) +} + +/// Generates a wrapper function for a "bad" ioctl that passes no data to the kernel. +/// +/// The arguments to this macro are: +/// +/// * The function name +/// * The ioctl request code +/// +/// The generated function has the following signature: +/// +/// ```rust,ignore +/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result +/// ``` +/// +/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). +/// +/// # Example +/// +/// ```no_run +/// # #[macro_use] extern crate nix; +/// # use libc::TIOCNXCL; +/// # use std::fs::File; +/// # use std::os::unix::io::AsRawFd; +/// ioctl_none_bad!(tiocnxcl, TIOCNXCL); +/// fn main() { +/// let file = File::open("/dev/ttyUSB0").unwrap(); +/// unsafe { tiocnxcl(file.as_raw_fd()) }.unwrap(); +/// } +/// ``` +// TODO: add an example using request_code_*!() +#[macro_export(local_inner_macros)] +macro_rules! ioctl_none_bad { + ($(#[$attr:meta])* $name:ident, $nr:expr) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type)) + } + ) +} + +/// Generates a wrapper function for an ioctl that reads data from the kernel. +/// +/// The arguments to this macro are: +/// +/// * The function name +/// * The ioctl identifier +/// * The ioctl sequence number +/// * The data type passed by this ioctl +/// +/// The generated function has the following signature: +/// +/// ```rust,ignore +/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result +/// ``` +/// +/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). +/// +/// # Example +/// +/// ``` +/// # #[macro_use] extern crate nix; +/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h +/// const SPI_IOC_TYPE_MODE: u8 = 1; +/// ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8); +/// # fn main() {} +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! ioctl_read { + ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int, + data: *mut $ty) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + } + ) +} + +/// Generates a wrapper function for a "bad" ioctl that reads data from the kernel. +/// +/// The arguments to this macro are: +/// +/// * The function name +/// * The ioctl request code +/// * The data type passed by this ioctl +/// +/// The generated function has the following signature: +/// +/// ```rust,ignore +/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result +/// ``` +/// +/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). +/// +/// # Example +/// +/// ``` +/// # #[macro_use] extern crate nix; +/// # #[cfg(any(target_os = "android", target_os = "linux"))] +/// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios); +/// # fn main() {} +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! ioctl_read_bad { + ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int, + data: *mut $ty) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + } + ) +} + +/// Generates a wrapper function for an ioctl that writes data through a pointer to the kernel. +/// +/// The arguments to this macro are: +/// +/// * The function name +/// * The ioctl identifier +/// * The ioctl sequence number +/// * The data type passed by this ioctl +/// +/// The generated function has the following signature: +/// +/// ```rust,ignore +/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result +/// ``` +/// +/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). +/// +/// # Example +/// +/// ``` +/// # #[macro_use] extern crate nix; +/// # pub struct v4l2_audio {} +/// ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio); +/// # fn main() {} +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! ioctl_write_ptr { + ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int, + data: *const $ty) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + } + ) +} + +/// Generates a wrapper function for a "bad" ioctl that writes data through a pointer to the kernel. +/// +/// The arguments to this macro are: +/// +/// * The function name +/// * The ioctl request code +/// * The data type passed by this ioctl +/// +/// The generated function has the following signature: +/// +/// ```rust,ignore +/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result +/// ``` +/// +/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). +/// +/// # Example +/// +/// ``` +/// # #[macro_use] extern crate nix; +/// # #[cfg(any(target_os = "android", target_os = "linux"))] +/// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios); +/// # fn main() {} +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! ioctl_write_ptr_bad { + ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int, + data: *const $ty) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + } + ) +} + +cfg_if! { + if #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] { + /// Generates a wrapper function for a ioctl that writes an integer to the kernel. + /// + /// The arguments to this macro are: + /// + /// * The function name + /// * The ioctl identifier + /// * The ioctl sequence number + /// + /// The generated function has the following signature: + /// + /// ```rust,ignore + /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result + /// ``` + /// + /// `nix::sys::ioctl::ioctl_param_type` depends on the OS: + /// * BSD - `libc::c_int` + /// * Linux - `libc::c_ulong` + /// + /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate nix; + /// ioctl_write_int!(vt_activate, b'v', 4); + /// # fn main() {} + /// ``` + #[macro_export(local_inner_macros)] + macro_rules! ioctl_write_int { + ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int, + data: $crate::sys::ioctl::ioctl_param_type) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data)) + } + ) + } + } else { + /// Generates a wrapper function for a ioctl that writes an integer to the kernel. + /// + /// The arguments to this macro are: + /// + /// * The function name + /// * The ioctl identifier + /// * The ioctl sequence number + /// + /// The generated function has the following signature: + /// + /// ```rust,ignore + /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result + /// ``` + /// + /// `nix::sys::ioctl::ioctl_param_type` depends on the OS: + /// * BSD - `libc::c_int` + /// * Linux - `libc::c_ulong` + /// + /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate nix; + /// const HCI_IOC_MAGIC: u8 = b'k'; + /// const HCI_IOC_HCIDEVUP: u8 = 1; + /// ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP); + /// # fn main() {} + /// ``` + #[macro_export(local_inner_macros)] + macro_rules! ioctl_write_int { + ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int, + data: $crate::sys::ioctl::ioctl_param_type) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data)) + } + ) + } + } +} + +/// Generates a wrapper function for a "bad" ioctl that writes an integer to the kernel. +/// +/// The arguments to this macro are: +/// +/// * The function name +/// * The ioctl request code +/// +/// The generated function has the following signature: +/// +/// ```rust,ignore +/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: libc::c_int) -> Result +/// ``` +/// +/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate nix; +/// # #[cfg(any(target_os = "android", target_os = "linux"))] +/// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK); +/// # fn main() {} +/// ``` +/// +/// ```rust +/// # #[macro_use] extern crate nix; +/// const KVMIO: u8 = 0xAE; +/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03)); +/// # fn main() {} +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! ioctl_write_int_bad { + ($(#[$attr:meta])* $name:ident, $nr:expr) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int, + data: $crate::libc::c_int) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + } + ) +} + +/// Generates a wrapper function for an ioctl that reads and writes data to the kernel. +/// +/// The arguments to this macro are: +/// +/// * The function name +/// * The ioctl identifier +/// * The ioctl sequence number +/// * The data type passed by this ioctl +/// +/// The generated function has the following signature: +/// +/// ```rust,ignore +/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result +/// ``` +/// +/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). +/// +/// # Example +/// +/// ``` +/// # #[macro_use] extern crate nix; +/// # pub struct v4l2_audio {} +/// ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio); +/// # fn main() {} +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! ioctl_readwrite { + ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int, + data: *mut $ty) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + } + ) +} + +/// Generates a wrapper function for a "bad" ioctl that reads and writes data to the kernel. +/// +/// The arguments to this macro are: +/// +/// * The function name +/// * The ioctl request code +/// * The data type passed by this ioctl +/// +/// The generated function has the following signature: +/// +/// ```rust,ignore +/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result +/// ``` +/// +/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). +// TODO: Find an example for ioctl_readwrite_bad +#[macro_export(local_inner_macros)] +macro_rules! ioctl_readwrite_bad { + ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int, + data: *mut $ty) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + } + ) +} + +/// Generates a wrapper function for an ioctl that reads an array of elements from the kernel. +/// +/// The arguments to this macro are: +/// +/// * The function name +/// * The ioctl identifier +/// * The ioctl sequence number +/// * The data type passed by this ioctl +/// +/// The generated function has the following signature: +/// +/// ```rust,ignore +/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result +/// ``` +/// +/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). +// TODO: Find an example for ioctl_read_buf +#[macro_export(local_inner_macros)] +macro_rules! ioctl_read_buf { + ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int, + data: &mut [$ty]) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + } + ) +} + +/// Generates a wrapper function for an ioctl that writes an array of elements to the kernel. +/// +/// The arguments to this macro are: +/// +/// * The function name +/// * The ioctl identifier +/// * The ioctl sequence number +/// * The data type passed by this ioctl +/// +/// The generated function has the following signature: +/// +/// ```rust,ignore +/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &[DATA_TYPE]) -> Result +/// ``` +/// +/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate nix; +/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h +/// const SPI_IOC_TYPE_MESSAGE: u8 = 0; +/// # pub struct spi_ioc_transfer(u64); +/// ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer); +/// # fn main() {} +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! ioctl_write_buf { + ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int, + data: &[$ty]) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + } + ) +} + +/// Generates a wrapper function for an ioctl that reads and writes an array of elements to the kernel. +/// +/// The arguments to this macro are: +/// +/// * The function name +/// * The ioctl identifier +/// * The ioctl sequence number +/// * The data type passed by this ioctl +/// +/// The generated function has the following signature: +/// +/// ```rust,ignore +/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result +/// ``` +/// +/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). +// TODO: Find an example for readwrite_buf +#[macro_export(local_inner_macros)] +macro_rules! ioctl_readwrite_buf { + ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( + $(#[$attr])* + pub unsafe fn $name(fd: $crate::libc::c_int, + data: &mut [$ty]) + -> $crate::Result<$crate::libc::c_int> { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + } + ) +} diff --git a/vendor/nix-0.26.2/src/sys/memfd.rs b/vendor/nix-0.26.2/src/sys/memfd.rs new file mode 100644 index 0000000000000..771a421c6c33f --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/memfd.rs @@ -0,0 +1,61 @@ +//! Interfaces for managing memory-backed files. + +use cfg_if::cfg_if; +use std::os::unix::io::RawFd; + +use crate::errno::Errno; +use crate::Result; +use std::ffi::CStr; + +libc_bitflags!( + /// Options that change the behavior of [`memfd_create`]. + pub struct MemFdCreateFlag: libc::c_uint { + /// Set the close-on-exec ([`FD_CLOEXEC`]) flag on the new file descriptor. + /// + /// By default, the new file descriptor is set to remain open across an [`execve`] + /// (the `FD_CLOEXEC` flag is initially disabled). This flag can be used to change + /// this default. The file offset is set to the beginning of the file (see [`lseek`]). + /// + /// See also the description of the `O_CLOEXEC` flag in [`open(2)`]. + /// + /// [`execve`]: crate::unistd::execve + /// [`lseek`]: crate::unistd::lseek + /// [`FD_CLOEXEC`]: crate::fcntl::FdFlag::FD_CLOEXEC + /// [`open(2)`]: https://man7.org/linux/man-pages/man2/open.2.html + MFD_CLOEXEC; + /// Allow sealing operations on this file. + /// + /// See also the file sealing notes given in [`memfd_create(2)`]. + /// + /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html + MFD_ALLOW_SEALING; + } +); + +/// Creates an anonymous file that lives in memory, and return a file-descriptor to it. +/// +/// The file behaves like a regular file, and so can be modified, truncated, memory-mapped, and so on. +/// However, unlike a regular file, it lives in RAM and has a volatile backing storage. +/// +/// For more information, see [`memfd_create(2)`]. +/// +/// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html +pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result { + let res = unsafe { + cfg_if! { + if #[cfg(all( + // Android does not have a memfd_create symbol + not(target_os = "android"), + any( + target_os = "freebsd", + )))] + { + libc::memfd_create(name.as_ptr(), flags.bits()) + } else { + libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits()) + } + } + }; + + Errno::result(res).map(|r| r as RawFd) +} diff --git a/vendor/nix-0.26.2/src/sys/mman.rs b/vendor/nix-0.26.2/src/sys/mman.rs new file mode 100644 index 0000000000000..2bee091610d55 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/mman.rs @@ -0,0 +1,599 @@ +//! Memory management declarations. + +use crate::errno::Errno; +#[cfg(not(target_os = "android"))] +use crate::NixPath; +use crate::Result; +#[cfg(not(target_os = "android"))] +#[cfg(feature = "fs")] +use crate::{fcntl::OFlag, sys::stat::Mode}; +use libc::{self, c_int, c_void, off_t, size_t}; +use std::{os::unix::io::RawFd, num::NonZeroUsize}; + +libc_bitflags! { + /// Desired memory protection of a memory mapping. + pub struct ProtFlags: c_int { + /// Pages cannot be accessed. + PROT_NONE; + /// Pages can be read. + PROT_READ; + /// Pages can be written. + PROT_WRITE; + /// Pages can be executed + PROT_EXEC; + /// Apply protection up to the end of a mapping that grows upwards. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + PROT_GROWSDOWN; + /// Apply protection down to the beginning of a mapping that grows downwards. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + PROT_GROWSUP; + } +} + +libc_bitflags! { + /// Additional parameters for [`mmap`]. + pub struct MapFlags: c_int { + /// Compatibility flag. Ignored. + MAP_FILE; + /// Share this mapping. Mutually exclusive with `MAP_PRIVATE`. + MAP_SHARED; + /// Create a private copy-on-write mapping. Mutually exclusive with `MAP_SHARED`. + MAP_PRIVATE; + /// Place the mapping at exactly the address specified in `addr`. + MAP_FIXED; + /// Place the mapping at exactly the address specified in `addr`, but never clobber an existing range. + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_FIXED_NOREPLACE; + /// To be used with `MAP_FIXED`, to forbid the system + /// to select a different address than the one specified. + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_EXCL; + /// Synonym for `MAP_ANONYMOUS`. + MAP_ANON; + /// The mapping is not backed by any file. + MAP_ANONYMOUS; + /// Put the mapping into the first 2GB of the process address space. + #[cfg(any(all(any(target_os = "android", target_os = "linux"), + any(target_arch = "x86", target_arch = "x86_64")), + all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")), + all(target_os = "freebsd", target_pointer_width = "64")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_32BIT; + /// Used for stacks; indicates to the kernel that the mapping should extend downward in memory. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_GROWSDOWN; + /// Compatibility flag. Ignored. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_DENYWRITE; + /// Compatibility flag. Ignored. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_EXECUTABLE; + /// Mark the mmaped region to be locked in the same way as `mlock(2)`. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_LOCKED; + /// Do not reserve swap space for this mapping. + /// + /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. + #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_NORESERVE; + /// Populate page tables for a mapping. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_POPULATE; + /// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_NONBLOCK; + /// Allocate the mapping using "huge pages." + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HUGETLB; + /// Make use of 64KB huge page (must be supported by the system) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HUGE_64KB; + /// Make use of 512KB huge page (must be supported by the system) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HUGE_512KB; + /// Make use of 1MB huge page (must be supported by the system) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HUGE_1MB; + /// Make use of 2MB huge page (must be supported by the system) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HUGE_2MB; + /// Make use of 8MB huge page (must be supported by the system) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HUGE_8MB; + /// Make use of 16MB huge page (must be supported by the system) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HUGE_16MB; + /// Make use of 32MB huge page (must be supported by the system) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HUGE_32MB; + /// Make use of 256MB huge page (must be supported by the system) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HUGE_256MB; + /// Make use of 512MB huge page (must be supported by the system) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HUGE_512MB; + /// Make use of 1GB huge page (must be supported by the system) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HUGE_1GB; + /// Make use of 2GB huge page (must be supported by the system) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HUGE_2GB; + /// Make use of 16GB huge page (must be supported by the system) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HUGE_16GB; + + /// Lock the mapped region into memory as with `mlock(2)`. + #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_WIRED; + /// Causes dirtied data in the specified range to be flushed to disk only when necessary. + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_NOSYNC; + /// Rename private pages to a file. + /// + /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. + #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_RENAME; + /// Region may contain semaphores. + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_HASSEMAPHORE; + /// Region grows down, like a stack. + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_STACK; + /// Pages in this mapping are not retained in the kernel's memory cache. + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_NOCACHE; + /// Allows the W/X bit on the page, it's necessary on aarch64 architecture. + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_JIT; + /// Allows to use large pages, underlying alignment based on size. + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_ALIGNED_SUPER; + /// Pages will be discarded in the core dumps. + #[cfg(target_os = "openbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_CONCEAL; + } +} + +#[cfg(any(target_os = "linux", target_os = "netbsd"))] +libc_bitflags! { + /// Options for [`mremap`]. + pub struct MRemapFlags: c_int { + /// Permit the kernel to relocate the mapping to a new virtual address, if necessary. + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MREMAP_MAYMOVE; + /// Place the mapping at exactly the address specified in `new_address`. + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MREMAP_FIXED; + /// Place the mapping at exactly the address specified in `new_address`. + #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_FIXED; + /// Allows to duplicate the mapping to be able to apply different flags on the copy. + #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_REMAPDUP; + } +} + +libc_enum! { + /// Usage information for a range of memory to allow for performance optimizations by the kernel. + /// + /// Used by [`madvise`]. + #[repr(i32)] + #[non_exhaustive] + pub enum MmapAdvise { + /// No further special treatment. This is the default. + MADV_NORMAL, + /// Expect random page references. + MADV_RANDOM, + /// Expect sequential page references. + MADV_SEQUENTIAL, + /// Expect access in the near future. + MADV_WILLNEED, + /// Do not expect access in the near future. + MADV_DONTNEED, + /// Free up a given range of pages and its associated backing store. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_REMOVE, + /// Do not make pages in this range available to the child after a `fork(2)`. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_DONTFORK, + /// Undo the effect of `MADV_DONTFORK`. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_DOFORK, + /// Poison the given pages. + /// + /// Subsequent references to those pages are treated like hardware memory corruption. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_HWPOISON, + /// Enable Kernel Samepage Merging (KSM) for the given pages. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_MERGEABLE, + /// Undo the effect of `MADV_MERGEABLE` + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_UNMERGEABLE, + /// Preserve the memory of each page but offline the original page. + #[cfg(any(target_os = "android", + all(target_os = "linux", any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + target_arch = "x86", + target_arch = "x86_64", + target_arch = "sparc64"))))] + MADV_SOFT_OFFLINE, + /// Enable Transparent Huge Pages (THP) for pages in the given range. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_HUGEPAGE, + /// Undo the effect of `MADV_HUGEPAGE`. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_NOHUGEPAGE, + /// Exclude the given range from a core dump. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_DONTDUMP, + /// Undo the effect of an earlier `MADV_DONTDUMP`. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_DODUMP, + /// Specify that the application no longer needs the pages in the given range. + MADV_FREE, + /// Request that the system not flush the current range to disk unless it needs to. + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_NOSYNC, + /// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range. + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_AUTOSYNC, + /// Region is not included in a core file. + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_NOCORE, + /// Include region in a core file + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_CORE, + /// This process should not be killed when swap space is exhausted. + #[cfg(any(target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_PROTECT, + /// Invalidate the hardware page table for the given region. + #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_INVAL, + /// Set the offset of the page directory page to `value` for the virtual page table. + #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_SETMAP, + /// Indicates that the application will not need the data in the given range. + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_ZERO_WIRED_PAGES, + /// Pages can be reused (by anyone). + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_FREE_REUSABLE, + /// Caller wants to reuse those pages. + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MADV_FREE_REUSE, + // Darwin doesn't document this flag's behavior. + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(missing_docs)] + MADV_CAN_REUSE, + } +} + +libc_bitflags! { + /// Configuration flags for [`msync`]. + pub struct MsFlags: c_int { + /// Schedule an update but return immediately. + MS_ASYNC; + /// Invalidate all cached data. + MS_INVALIDATE; + /// Invalidate pages, but leave them mapped. + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MS_KILLPAGES; + /// Deactivate pages, but leave them mapped. + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MS_DEACTIVATE; + /// Perform an update and wait for it to complete. + MS_SYNC; + } +} + +#[cfg(not(target_os = "haiku"))] +libc_bitflags! { + /// Flags for [`mlockall`]. + pub struct MlockAllFlags: c_int { + /// Lock pages that are currently mapped into the address space of the process. + MCL_CURRENT; + /// Lock pages which will become mapped into the address space of the process in the future. + MCL_FUTURE; + } +} + +/// Locks all memory pages that contain part of the address range with `length` +/// bytes starting at `addr`. +/// +/// Locked pages never move to the swap area. +/// +/// # Safety +/// +/// `addr` must meet all the requirements described in the [`mlock(2)`] man page. +/// +/// [`mlock(2)`]: https://man7.org/linux/man-pages/man2/mlock.2.html +pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> { + Errno::result(libc::mlock(addr, length)).map(drop) +} + +/// Unlocks all memory pages that contain part of the address range with +/// `length` bytes starting at `addr`. +/// +/// # Safety +/// +/// `addr` must meet all the requirements described in the [`munlock(2)`] man +/// page. +/// +/// [`munlock(2)`]: https://man7.org/linux/man-pages/man2/munlock.2.html +pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> { + Errno::result(libc::munlock(addr, length)).map(drop) +} + +/// Locks all memory pages mapped into this process' address space. +/// +/// Locked pages never move to the swap area. For more information, see [`mlockall(2)`]. +/// +/// [`mlockall(2)`]: https://man7.org/linux/man-pages/man2/mlockall.2.html +#[cfg(not(target_os = "haiku"))] +pub fn mlockall(flags: MlockAllFlags) -> Result<()> { + unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop) +} + +/// Unlocks all memory pages mapped into this process' address space. +/// +/// For more information, see [`munlockall(2)`]. +/// +/// [`munlockall(2)`]: https://man7.org/linux/man-pages/man2/munlockall.2.html +#[cfg(not(target_os = "haiku"))] +pub fn munlockall() -> Result<()> { + unsafe { Errno::result(libc::munlockall()) }.map(drop) +} + +/// allocate memory, or map files or devices into memory +/// +/// # Safety +/// +/// See the [`mmap(2)`] man page for detailed requirements. +/// +/// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html +pub unsafe fn mmap( + addr: Option, + length: NonZeroUsize, + prot: ProtFlags, + flags: MapFlags, + fd: RawFd, + offset: off_t, +) -> Result<*mut c_void> { + let ptr = addr.map_or( + std::ptr::null_mut(), + |a| usize::from(a) as *mut c_void + ); + + let ret = libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset); + + if ret == libc::MAP_FAILED { + Err(Errno::last()) + } else { + Ok(ret) + } +} + +/// Expands (or shrinks) an existing memory mapping, potentially moving it at +/// the same time. +/// +/// # Safety +/// +/// See the `mremap(2)` [man page](https://man7.org/linux/man-pages/man2/mremap.2.html) for +/// detailed requirements. +#[cfg(any(target_os = "linux", target_os = "netbsd"))] +pub unsafe fn mremap( + addr: *mut c_void, + old_size: size_t, + new_size: size_t, + flags: MRemapFlags, + new_address: Option<*mut c_void>, +) -> Result<*mut c_void> { + #[cfg(target_os = "linux")] + let ret = libc::mremap( + addr, + old_size, + new_size, + flags.bits(), + new_address.unwrap_or(std::ptr::null_mut()), + ); + #[cfg(target_os = "netbsd")] + let ret = libc::mremap( + addr, + old_size, + new_address.unwrap_or(std::ptr::null_mut()), + new_size, + flags.bits(), + ); + + if ret == libc::MAP_FAILED { + Err(Errno::last()) + } else { + Ok(ret) + } +} + +/// remove a mapping +/// +/// # Safety +/// +/// `addr` must meet all the requirements described in the [`munmap(2)`] man +/// page. +/// +/// [`munmap(2)`]: https://man7.org/linux/man-pages/man2/munmap.2.html +pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> { + Errno::result(libc::munmap(addr, len)).map(drop) +} + +/// give advice about use of memory +/// +/// # Safety +/// +/// See the [`madvise(2)`] man page. Take special care when using +/// [`MmapAdvise::MADV_FREE`]. +/// +/// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html +pub unsafe fn madvise( + addr: *mut c_void, + length: size_t, + advise: MmapAdvise, +) -> Result<()> { + Errno::result(libc::madvise(addr, length, advise as i32)).map(drop) +} + +/// Set protection of memory mapping. +/// +/// See [`mprotect(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html) for +/// details. +/// +/// # Safety +/// +/// Calls to `mprotect` are inherently unsafe, as changes to memory protections can lead to +/// SIGSEGVs. +/// +/// ``` +/// # use nix::libc::size_t; +/// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags}; +/// # use std::ptr; +/// const ONE_K: size_t = 1024; +/// let one_k_non_zero = std::num::NonZeroUsize::new(ONE_K).unwrap(); +/// let mut slice: &mut [u8] = unsafe { +/// let mem = mmap(None, one_k_non_zero, ProtFlags::PROT_NONE, +/// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap(); +/// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap(); +/// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) +/// }; +/// assert_eq!(slice[0], 0x00); +/// slice[0] = 0xFF; +/// assert_eq!(slice[0], 0xFF); +/// ``` +pub unsafe fn mprotect( + addr: *mut c_void, + length: size_t, + prot: ProtFlags, +) -> Result<()> { + Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop) +} + +/// synchronize a mapped region +/// +/// # Safety +/// +/// `addr` must meet all the requirements described in the [`msync(2)`] man +/// page. +/// +/// [`msync(2)`]: https://man7.org/linux/man-pages/man2/msync.2.html +pub unsafe fn msync( + addr: *mut c_void, + length: size_t, + flags: MsFlags, +) -> Result<()> { + Errno::result(libc::msync(addr, length, flags.bits())).map(drop) +} + +#[cfg(not(target_os = "android"))] +feature! { +#![feature = "fs"] +/// Creates and opens a new, or opens an existing, POSIX shared memory object. +/// +/// For more information, see [`shm_open(3)`]. +/// +/// [`shm_open(3)`]: https://man7.org/linux/man-pages/man3/shm_open.3.html +pub fn shm_open

( + name: &P, + flag: OFlag, + mode: Mode + ) -> Result + where P: ?Sized + NixPath +{ + let ret = name.with_nix_path(|cstr| { + #[cfg(any(target_os = "macos", target_os = "ios"))] + unsafe { + libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint) + } + #[cfg(not(any(target_os = "macos", target_os = "ios")))] + unsafe { + libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t) + } + })?; + + Errno::result(ret) +} +} + +/// Performs the converse of [`shm_open`], removing an object previously created. +/// +/// For more information, see [`shm_unlink(3)`]. +/// +/// [`shm_unlink(3)`]: https://man7.org/linux/man-pages/man3/shm_unlink.3.html +#[cfg(not(target_os = "android"))] +pub fn shm_unlink(name: &P) -> Result<()> { + let ret = + name.with_nix_path(|cstr| unsafe { libc::shm_unlink(cstr.as_ptr()) })?; + + Errno::result(ret).map(drop) +} diff --git a/vendor/nix-0.26.2/src/sys/mod.rs b/vendor/nix-0.26.2/src/sys/mod.rs new file mode 100644 index 0000000000000..2065059de8dff --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/mod.rs @@ -0,0 +1,228 @@ +//! Mostly platform-specific functionality +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + all(target_os = "linux", not(target_env = "uclibc")), + target_os = "macos", + target_os = "netbsd" +))] +feature! { + #![feature = "aio"] + pub mod aio; +} + +feature! { + #![feature = "event"] + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[allow(missing_docs)] + pub mod epoll; + + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[allow(missing_docs)] + pub mod event; + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[allow(missing_docs)] + pub mod eventfd; +} + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "redox", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd" +))] +#[cfg(feature = "ioctl")] +#[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] +#[macro_use] +pub mod ioctl; + +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +feature! { + #![feature = "fs"] + pub mod memfd; +} + +#[cfg(not(target_os = "redox"))] +feature! { + #![feature = "mman"] + pub mod mman; +} + +#[cfg(target_os = "linux")] +feature! { + #![feature = "personality"] + pub mod personality; +} + +feature! { + #![feature = "pthread"] + pub mod pthread; +} + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] +feature! { + #![feature = "ptrace"] + #[allow(missing_docs)] + pub mod ptrace; +} + +#[cfg(target_os = "linux")] +feature! { + #![feature = "quota"] + pub mod quota; +} + +#[cfg(target_os = "linux")] +feature! { + #![feature = "reboot"] + pub mod reboot; +} + +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "illumos", + target_os = "haiku" +)))] +feature! { + #![feature = "resource"] + pub mod resource; +} + +#[cfg(not(target_os = "redox"))] +feature! { + #![feature = "poll"] + pub mod select; +} + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos" +))] +feature! { + #![feature = "zerocopy"] + pub mod sendfile; +} + +pub mod signal; + +#[cfg(any(target_os = "android", target_os = "linux"))] +feature! { + #![feature = "signal"] + #[allow(missing_docs)] + pub mod signalfd; +} + +#[cfg(not(target_os = "redox"))] +feature! { + #![feature = "socket"] + #[allow(missing_docs)] + pub mod socket; +} + +feature! { + #![feature = "fs"] + #[allow(missing_docs)] + pub mod stat; +} + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" +))] +feature! { + #![feature = "fs"] + pub mod statfs; +} + +feature! { + #![feature = "fs"] + pub mod statvfs; +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +#[allow(missing_docs)] +pub mod sysinfo; + +feature! { + #![feature = "term"] + #[allow(missing_docs)] + pub mod termios; +} + +#[allow(missing_docs)] +pub mod time; + +feature! { + #![feature = "uio"] + pub mod uio; +} + +feature! { + #![feature = "feature"] + pub mod utsname; +} + +feature! { + #![feature = "process"] + pub mod wait; +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +feature! { + #![feature = "inotify"] + pub mod inotify; +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +feature! { + #![feature = "time"] + pub mod timerfd; +} + +#[cfg(all( + any( + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd" + ), + feature = "time", + feature = "signal" +))] +feature! { + #![feature = "time"] + pub mod timer; +} diff --git a/vendor/nix-0.26.2/src/sys/personality.rs b/vendor/nix-0.26.2/src/sys/personality.rs new file mode 100644 index 0000000000000..f295a05fade07 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/personality.rs @@ -0,0 +1,93 @@ +//! Process execution domains +use crate::errno::Errno; +use crate::Result; + +use libc::{self, c_int, c_ulong}; + +libc_bitflags! { + /// Flags used and returned by [`get()`](fn.get.html) and + /// [`set()`](fn.set.html). + pub struct Persona: c_int { + /// Provide the legacy virtual address space layout. + ADDR_COMPAT_LAYOUT; + /// Disable address-space-layout randomization. + ADDR_NO_RANDOMIZE; + /// Limit the address space to 32 bits. + ADDR_LIMIT_32BIT; + /// Use `0xc0000000` as the offset at which to search a virtual memory + /// chunk on [`mmap(2)`], otherwise use `0xffffe000`. + /// + /// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html + ADDR_LIMIT_3GB; + /// User-space function pointers to signal handlers point to descriptors. + #[cfg(not(any(target_env = "musl", target_env = "uclibc")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + FDPIC_FUNCPTRS; + /// Map page 0 as read-only. + MMAP_PAGE_ZERO; + /// `PROT_READ` implies `PROT_EXEC` for [`mmap(2)`]. + /// + /// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html + READ_IMPLIES_EXEC; + /// No effects. + SHORT_INODE; + /// [`select(2)`], [`pselect(2)`], and [`ppoll(2)`] do not modify the + /// returned timeout argument when interrupted by a signal handler. + /// + /// [`select(2)`]: https://man7.org/linux/man-pages/man2/select.2.html + /// [`pselect(2)`]: https://man7.org/linux/man-pages/man2/pselect.2.html + /// [`ppoll(2)`]: https://man7.org/linux/man-pages/man2/ppoll.2.html + STICKY_TIMEOUTS; + /// Have [`uname(2)`] report a 2.6.40+ version number rather than a 3.x + /// version number. + /// + /// [`uname(2)`]: https://man7.org/linux/man-pages/man2/uname.2.html + #[cfg(not(any(target_env = "musl", target_env = "uclibc")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + UNAME26; + /// No effects. + WHOLE_SECONDS; + } +} + +/// Retrieve the current process personality. +/// +/// Returns a Result containing a Persona instance. +/// +/// Example: +/// +/// ``` +/// # use nix::sys::personality::{self, Persona}; +/// let pers = personality::get().unwrap(); +/// assert!(!pers.contains(Persona::WHOLE_SECONDS)); +/// ``` +pub fn get() -> Result { + let res = unsafe { libc::personality(0xFFFFFFFF) }; + + Errno::result(res).map(Persona::from_bits_truncate) +} + +/// Set the current process personality. +/// +/// Returns a Result containing the *previous* personality for the +/// process, as a Persona. +/// +/// For more information, see [personality(2)](https://man7.org/linux/man-pages/man2/personality.2.html) +/// +/// **NOTE**: This call **replaces** the current personality entirely. +/// To **update** the personality, first call `get()` and then `set()` +/// with the modified persona. +/// +/// Example: +/// +/// ``` +/// # use nix::sys::personality::{self, Persona}; +/// let mut pers = personality::get().unwrap(); +/// assert!(!pers.contains(Persona::ADDR_NO_RANDOMIZE)); +/// personality::set(pers | Persona::ADDR_NO_RANDOMIZE).unwrap(); +/// ``` +pub fn set(persona: Persona) -> Result { + let res = unsafe { libc::personality(persona.bits() as c_ulong) }; + + Errno::result(res).map(Persona::from_bits_truncate) +} diff --git a/vendor/nix-0.26.2/src/sys/pthread.rs b/vendor/nix-0.26.2/src/sys/pthread.rs new file mode 100644 index 0000000000000..6bad03a4d4d64 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/pthread.rs @@ -0,0 +1,43 @@ +//! Low level threading primitives + +#[cfg(not(target_os = "redox"))] +use crate::errno::Errno; +#[cfg(not(target_os = "redox"))] +use crate::Result; +use libc::{self, pthread_t}; + +/// Identifies an individual thread. +pub type Pthread = pthread_t; + +/// Obtain ID of the calling thread (see +/// [`pthread_self(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html) +/// +/// The thread ID returned by `pthread_self()` is not the same thing as +/// the kernel thread ID returned by a call to `gettid(2)`. +#[inline] +pub fn pthread_self() -> Pthread { + unsafe { libc::pthread_self() } +} + +feature! { +#![feature = "signal"] + +/// Send a signal to a thread (see [`pthread_kill(3)`]). +/// +/// If `signal` is `None`, `pthread_kill` will only preform error checking and +/// won't send any signal. +/// +/// [`pthread_kill(3)`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_kill.html +#[allow(clippy::not_unsafe_ptr_arg_deref)] +#[cfg(not(target_os = "redox"))] +pub fn pthread_kill(thread: Pthread, signal: T) -> Result<()> + where T: Into> +{ + let sig = match signal.into() { + Some(s) => s as libc::c_int, + None => 0, + }; + let res = unsafe { libc::pthread_kill(thread, sig) }; + Errno::result(res).map(drop) +} +} diff --git a/vendor/nix-0.26.2/src/sys/ptrace/bsd.rs b/vendor/nix-0.26.2/src/sys/ptrace/bsd.rs new file mode 100644 index 0000000000000..ba267c6577f12 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/ptrace/bsd.rs @@ -0,0 +1,195 @@ +use crate::errno::Errno; +use crate::sys::signal::Signal; +use crate::unistd::Pid; +use crate::Result; +use cfg_if::cfg_if; +use libc::{self, c_int}; +use std::ptr; + +pub type RequestType = c_int; + +cfg_if! { + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "openbsd"))] { + #[doc(hidden)] + pub type AddressType = *mut ::libc::c_char; + } else { + #[doc(hidden)] + pub type AddressType = *mut ::libc::c_void; + } +} + +libc_enum! { + #[repr(i32)] + /// Ptrace Request enum defining the action to be taken. + #[non_exhaustive] + pub enum Request { + PT_TRACE_ME, + PT_READ_I, + PT_READ_D, + #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(all())))] + PT_READ_U, + PT_WRITE_I, + PT_WRITE_D, + #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(all())))] + PT_WRITE_U, + PT_CONTINUE, + PT_KILL, + #[cfg(any(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos"), + all(target_os = "openbsd", target_arch = "x86_64"), + all(target_os = "netbsd", any(target_arch = "x86_64", + target_arch = "powerpc"))))] + PT_STEP, + PT_ATTACH, + PT_DETACH, + #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(all())))] + PT_SIGEXC, + #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(all())))] + PT_THUPDATE, + #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(all())))] + PT_ATTACHEXC + } +} + +unsafe fn ptrace_other( + request: Request, + pid: Pid, + addr: AddressType, + data: c_int, +) -> Result { + Errno::result(libc::ptrace( + request as RequestType, + libc::pid_t::from(pid), + addr, + data, + )) + .map(|_| 0) +} + +/// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)` +/// +/// Indicates that this process is to be traced by its parent. +/// This is the only ptrace request to be issued by the tracee. +pub fn traceme() -> Result<()> { + unsafe { + ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0) + .map(drop) + } +} + +/// Attach to a running process, as with `ptrace(PT_ATTACH, ...)` +/// +/// Attaches to the process specified by `pid`, making it a tracee of the calling process. +pub fn attach(pid: Pid) -> Result<()> { + unsafe { + ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) + } +} + +/// Detaches the current running process, as with `ptrace(PT_DETACH, ...)` +/// +/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a +/// signal specified by `sig`. +pub fn detach>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as c_int, + None => 0, + }; + unsafe { + ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), data).map(drop) + } +} + +/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` +/// +/// Continues the execution of the process with PID `pid`, optionally +/// delivering a signal specified by `sig`. +pub fn cont>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as c_int, + None => 0, + }; + unsafe { + // Ignore the useless return value + ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data) + .map(drop) + } +} + +/// Issues a kill request as with `ptrace(PT_KILL, ...)` +/// +/// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);` +pub fn kill(pid: Pid) -> Result<()> { + unsafe { + ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(drop) + } +} + +/// Move the stopped tracee process forward by a single step as with +/// `ptrace(PT_STEP, ...)` +/// +/// Advances the execution of the process with PID `pid` by a single step optionally delivering a +/// signal specified by `sig`. +/// +/// # Example +/// ```rust +/// use nix::sys::ptrace::step; +/// use nix::unistd::Pid; +/// use nix::sys::signal::Signal; +/// use nix::sys::wait::*; +/// // If a process changes state to the stopped state because of a SIGUSR1 +/// // signal, this will step the process forward and forward the user +/// // signal to the stopped process +/// match waitpid(Pid::from_raw(-1), None) { +/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { +/// let _ = step(pid, Signal::SIGUSR1); +/// } +/// _ => {}, +/// } +/// ``` +#[cfg(any( + any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"), + all(target_os = "openbsd", target_arch = "x86_64"), + all( + target_os = "netbsd", + any(target_arch = "x86_64", target_arch = "powerpc") + ) +))] +pub fn step>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as c_int, + None => 0, + }; + unsafe { + ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(drop) + } +} + +/// Reads a word from a processes memory at the given address +// Technically, ptrace doesn't dereference the pointer. It passes it directly +// to the kernel. +#[allow(clippy::not_unsafe_ptr_arg_deref)] +pub fn read(pid: Pid, addr: AddressType) -> Result { + unsafe { + // Traditionally there was a difference between reading data or + // instruction memory but not in modern systems. + ptrace_other(Request::PT_READ_D, pid, addr, 0) + } +} + +/// Writes a word into the processes memory at the given address +// Technically, ptrace doesn't dereference the pointer. It passes it directly +// to the kernel. +#[allow(clippy::not_unsafe_ptr_arg_deref)] +pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> { + unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(drop) } +} diff --git a/vendor/nix-0.26.2/src/sys/ptrace/linux.rs b/vendor/nix-0.26.2/src/sys/ptrace/linux.rs new file mode 100644 index 0000000000000..9687e05d42afe --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/ptrace/linux.rs @@ -0,0 +1,558 @@ +//! For detailed description of the ptrace requests, consult `man ptrace`. + +use crate::errno::Errno; +use crate::sys::signal::Signal; +use crate::unistd::Pid; +use crate::Result; +use cfg_if::cfg_if; +use libc::{self, c_long, c_void, siginfo_t}; +use std::{mem, ptr}; + +pub type AddressType = *mut ::libc::c_void; + +#[cfg(all( + target_os = "linux", + any( + all( + target_arch = "x86_64", + any(target_env = "gnu", target_env = "musl") + ), + all(target_arch = "x86", target_env = "gnu") + ) +))] +use libc::user_regs_struct; + +cfg_if! { + if #[cfg(any(all(target_os = "linux", target_arch = "s390x"), + all(target_os = "linux", target_env = "gnu"), + target_env = "uclibc"))] { + #[doc(hidden)] + pub type RequestType = ::libc::c_uint; + } else { + #[doc(hidden)] + pub type RequestType = ::libc::c_int; + } +} + +libc_enum! { + #[cfg_attr(not(any(target_env = "musl", target_env = "uclibc", target_os = "android")), repr(u32))] + #[cfg_attr(any(target_env = "musl", target_env = "uclibc", target_os = "android"), repr(i32))] + /// Ptrace Request enum defining the action to be taken. + #[non_exhaustive] + pub enum Request { + PTRACE_TRACEME, + PTRACE_PEEKTEXT, + PTRACE_PEEKDATA, + PTRACE_PEEKUSER, + PTRACE_POKETEXT, + PTRACE_POKEDATA, + PTRACE_POKEUSER, + PTRACE_CONT, + PTRACE_KILL, + PTRACE_SINGLESTEP, + #[cfg(any(all(target_os = "android", target_pointer_width = "32"), + all(target_os = "linux", any(target_env = "musl", + target_arch = "mips", + target_arch = "mips64", + target_arch = "x86_64", + target_pointer_width = "32"))))] + PTRACE_GETREGS, + #[cfg(any(all(target_os = "android", target_pointer_width = "32"), + all(target_os = "linux", any(target_env = "musl", + target_arch = "mips", + target_arch = "mips64", + target_arch = "x86_64", + target_pointer_width = "32"))))] + PTRACE_SETREGS, + #[cfg(any(all(target_os = "android", target_pointer_width = "32"), + all(target_os = "linux", any(target_env = "musl", + target_arch = "mips", + target_arch = "mips64", + target_arch = "x86_64", + target_pointer_width = "32"))))] + PTRACE_GETFPREGS, + #[cfg(any(all(target_os = "android", target_pointer_width = "32"), + all(target_os = "linux", any(target_env = "musl", + target_arch = "mips", + target_arch = "mips64", + target_arch = "x86_64", + target_pointer_width = "32"))))] + PTRACE_SETFPREGS, + PTRACE_ATTACH, + PTRACE_DETACH, + #[cfg(all(target_os = "linux", any(target_env = "musl", + target_arch = "mips", + target_arch = "mips64", + target_arch = "x86", + target_arch = "x86_64")))] + PTRACE_GETFPXREGS, + #[cfg(all(target_os = "linux", any(target_env = "musl", + target_arch = "mips", + target_arch = "mips64", + target_arch = "x86", + target_arch = "x86_64")))] + PTRACE_SETFPXREGS, + PTRACE_SYSCALL, + PTRACE_SETOPTIONS, + PTRACE_GETEVENTMSG, + PTRACE_GETSIGINFO, + PTRACE_SETSIGINFO, + #[cfg(all(target_os = "linux", not(any(target_arch = "mips", + target_arch = "mips64"))))] + PTRACE_GETREGSET, + #[cfg(all(target_os = "linux", not(any(target_arch = "mips", + target_arch = "mips64"))))] + PTRACE_SETREGSET, + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + PTRACE_SEIZE, + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + PTRACE_INTERRUPT, + #[cfg(all(target_os = "linux", not(any(target_arch = "mips", + target_arch = "mips64"))))] + PTRACE_LISTEN, + #[cfg(all(target_os = "linux", not(any(target_arch = "mips", + target_arch = "mips64"))))] + PTRACE_PEEKSIGINFO, + #[cfg(all(target_os = "linux", target_env = "gnu", + any(target_arch = "x86", target_arch = "x86_64")))] + PTRACE_SYSEMU, + #[cfg(all(target_os = "linux", target_env = "gnu", + any(target_arch = "x86", target_arch = "x86_64")))] + PTRACE_SYSEMU_SINGLESTEP, + } +} + +libc_enum! { + #[repr(i32)] + /// Using the ptrace options the tracer can configure the tracee to stop + /// at certain events. This enum is used to define those events as defined + /// in `man ptrace`. + #[non_exhaustive] + pub enum Event { + /// Event that stops before a return from fork or clone. + PTRACE_EVENT_FORK, + /// Event that stops before a return from vfork or clone. + PTRACE_EVENT_VFORK, + /// Event that stops before a return from clone. + PTRACE_EVENT_CLONE, + /// Event that stops before a return from execve. + PTRACE_EVENT_EXEC, + /// Event for a return from vfork. + PTRACE_EVENT_VFORK_DONE, + /// Event for a stop before an exit. Unlike the waitpid Exit status program. + /// registers can still be examined + PTRACE_EVENT_EXIT, + /// Stop triggered by a seccomp rule on a tracee. + PTRACE_EVENT_SECCOMP, + /// Stop triggered by the `INTERRUPT` syscall, or a group stop, + /// or when a new child is attached. + PTRACE_EVENT_STOP, + } +} + +libc_bitflags! { + /// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request. + /// See `man ptrace` for more details. + pub struct Options: libc::c_int { + /// When delivering system call traps set a bit to allow tracer to + /// distinguish between normal stops or syscall stops. May not work on + /// all systems. + PTRACE_O_TRACESYSGOOD; + /// Stop tracee at next fork and start tracing the forked process. + PTRACE_O_TRACEFORK; + /// Stop tracee at next vfork call and trace the vforked process. + PTRACE_O_TRACEVFORK; + /// Stop tracee at next clone call and trace the cloned process. + PTRACE_O_TRACECLONE; + /// Stop tracee at next execve call. + PTRACE_O_TRACEEXEC; + /// Stop tracee at vfork completion. + PTRACE_O_TRACEVFORKDONE; + /// Stop tracee at next exit call. Stops before exit commences allowing + /// tracer to see location of exit and register states. + PTRACE_O_TRACEEXIT; + /// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more + /// details. + PTRACE_O_TRACESECCOMP; + /// Send a SIGKILL to the tracee if the tracer exits. This is useful + /// for ptrace jailers to prevent tracees from escaping their control. + PTRACE_O_EXITKILL; + } +} + +fn ptrace_peek( + request: Request, + pid: Pid, + addr: AddressType, + data: *mut c_void, +) -> Result { + let ret = unsafe { + Errno::clear(); + libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data) + }; + match Errno::result(ret) { + Ok(..) | Err(Errno::UnknownErrno) => Ok(ret), + err @ Err(..) => err, + } +} + +/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)` +#[cfg(all( + target_os = "linux", + any( + all( + target_arch = "x86_64", + any(target_env = "gnu", target_env = "musl") + ), + all(target_arch = "x86", target_env = "gnu") + ) +))] +pub fn getregs(pid: Pid) -> Result { + ptrace_get_data::(Request::PTRACE_GETREGS, pid) +} + +/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)` +#[cfg(all( + target_os = "linux", + any( + all( + target_arch = "x86_64", + any(target_env = "gnu", target_env = "musl") + ), + all(target_arch = "x86", target_env = "gnu") + ) +))] +pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> { + let res = unsafe { + libc::ptrace( + Request::PTRACE_SETREGS as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::(), + ®s as *const _ as *const c_void, + ) + }; + Errno::result(res).map(drop) +} + +/// Function for ptrace requests that return values from the data field. +/// Some ptrace get requests populate structs or larger elements than `c_long` +/// and therefore use the data field to return values. This function handles these +/// requests. +fn ptrace_get_data(request: Request, pid: Pid) -> Result { + let mut data = mem::MaybeUninit::uninit(); + let res = unsafe { + libc::ptrace( + request as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::(), + data.as_mut_ptr() as *const _ as *const c_void, + ) + }; + Errno::result(res)?; + Ok(unsafe { data.assume_init() }) +} + +unsafe fn ptrace_other( + request: Request, + pid: Pid, + addr: AddressType, + data: *mut c_void, +) -> Result { + Errno::result(libc::ptrace( + request as RequestType, + libc::pid_t::from(pid), + addr, + data, + )) + .map(|_| 0) +} + +/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`. +pub fn setoptions(pid: Pid, options: Options) -> Result<()> { + let res = unsafe { + libc::ptrace( + Request::PTRACE_SETOPTIONS as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::(), + options.bits() as *mut c_void, + ) + }; + Errno::result(res).map(drop) +} + +/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)` +pub fn getevent(pid: Pid) -> Result { + ptrace_get_data::(Request::PTRACE_GETEVENTMSG, pid) +} + +/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)` +pub fn getsiginfo(pid: Pid) -> Result { + ptrace_get_data::(Request::PTRACE_GETSIGINFO, pid) +} + +/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)` +pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { + let ret = unsafe { + Errno::clear(); + libc::ptrace( + Request::PTRACE_SETSIGINFO as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::(), + sig as *const _ as *const c_void, + ) + }; + match Errno::result(ret) { + Ok(_) => Ok(()), + Err(e) => Err(e), + } +} + +/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)` +/// +/// Indicates that this process is to be traced by its parent. +/// This is the only ptrace request to be issued by the tracee. +pub fn traceme() -> Result<()> { + unsafe { + ptrace_other( + Request::PTRACE_TRACEME, + Pid::from_raw(0), + ptr::null_mut(), + ptr::null_mut(), + ) + .map(drop) // ignore the useless return value + } +} + +/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSCALL, ...)` +/// +/// Arranges for the tracee to be stopped at the next entry to or exit from a system call, +/// optionally delivering a signal specified by `sig`. +pub fn syscall>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as i32 as *mut c_void, + None => ptr::null_mut(), + }; + unsafe { + ptrace_other(Request::PTRACE_SYSCALL, pid, ptr::null_mut(), data) + .map(drop) // ignore the useless return value + } +} + +/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSEMU, ...)` +/// +/// In contrast to the `syscall` function, the syscall stopped at will not be executed. +/// Thus the the tracee will only be stopped once per syscall, +/// optionally delivering a signal specified by `sig`. +#[cfg(all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "x86", target_arch = "x86_64") +))] +pub fn sysemu>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as i32 as *mut c_void, + None => ptr::null_mut(), + }; + unsafe { + ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data) + .map(drop) + // ignore the useless return value + } +} + +/// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)` +/// +/// Attaches to the process specified by `pid`, making it a tracee of the calling process. +pub fn attach(pid: Pid) -> Result<()> { + unsafe { + ptrace_other( + Request::PTRACE_ATTACH, + pid, + ptr::null_mut(), + ptr::null_mut(), + ) + .map(drop) // ignore the useless return value + } +} + +/// Attach to a running process, as with `ptrace(PTRACE_SEIZE, ...)` +/// +/// Attaches to the process specified in pid, making it a tracee of the calling process. +#[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn seize(pid: Pid, options: Options) -> Result<()> { + unsafe { + ptrace_other( + Request::PTRACE_SEIZE, + pid, + ptr::null_mut(), + options.bits() as *mut c_void, + ) + .map(drop) // ignore the useless return value + } +} + +/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)` +/// +/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a +/// signal specified by `sig`. +pub fn detach>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as i32 as *mut c_void, + None => ptr::null_mut(), + }; + unsafe { + ptrace_other(Request::PTRACE_DETACH, pid, ptr::null_mut(), data) + .map(drop) + } +} + +/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` +/// +/// Continues the execution of the process with PID `pid`, optionally +/// delivering a signal specified by `sig`. +pub fn cont>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as i32 as *mut c_void, + None => ptr::null_mut(), + }; + unsafe { + ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) + // ignore the useless return value + } +} + +/// Stop a tracee, as with `ptrace(PTRACE_INTERRUPT, ...)` +/// +/// This request is equivalent to `ptrace(PTRACE_INTERRUPT, ...)` +#[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn interrupt(pid: Pid) -> Result<()> { + unsafe { + ptrace_other( + Request::PTRACE_INTERRUPT, + pid, + ptr::null_mut(), + ptr::null_mut(), + ) + .map(drop) + } +} + +/// Issues a kill request as with `ptrace(PTRACE_KILL, ...)` +/// +/// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);` +pub fn kill(pid: Pid) -> Result<()> { + unsafe { + ptrace_other( + Request::PTRACE_KILL, + pid, + ptr::null_mut(), + ptr::null_mut(), + ) + .map(drop) + } +} + +/// Move the stopped tracee process forward by a single step as with +/// `ptrace(PTRACE_SINGLESTEP, ...)` +/// +/// Advances the execution of the process with PID `pid` by a single step optionally delivering a +/// signal specified by `sig`. +/// +/// # Example +/// ```rust +/// use nix::sys::ptrace::step; +/// use nix::unistd::Pid; +/// use nix::sys::signal::Signal; +/// use nix::sys::wait::*; +/// +/// // If a process changes state to the stopped state because of a SIGUSR1 +/// // signal, this will step the process forward and forward the user +/// // signal to the stopped process +/// match waitpid(Pid::from_raw(-1), None) { +/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { +/// let _ = step(pid, Signal::SIGUSR1); +/// } +/// _ => {}, +/// } +/// ``` +pub fn step>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as i32 as *mut c_void, + None => ptr::null_mut(), + }; + unsafe { + ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data) + .map(drop) + } +} + +/// Move the stopped tracee process forward by a single step or stop at the next syscall +/// as with `ptrace(PTRACE_SYSEMU_SINGLESTEP, ...)` +/// +/// Advances the execution by a single step or until the next syscall. +/// In case the tracee is stopped at a syscall, the syscall will not be executed. +/// Optionally, the signal specified by `sig` is delivered to the tracee upon continuation. +#[cfg(all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "x86", target_arch = "x86_64") +))] +pub fn sysemu_step>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as i32 as *mut c_void, + None => ptr::null_mut(), + }; + unsafe { + ptrace_other( + Request::PTRACE_SYSEMU_SINGLESTEP, + pid, + ptr::null_mut(), + data, + ) + .map(drop) // ignore the useless return value + } +} + +/// Reads a word from a processes memory at the given address +pub fn read(pid: Pid, addr: AddressType) -> Result { + ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut()) +} + +/// Writes a word into the processes memory at the given address +/// +/// # Safety +/// +/// The `data` argument is passed directly to `ptrace(2)`. Read that man page +/// for guidance. +pub unsafe fn write( + pid: Pid, + addr: AddressType, + data: *mut c_void, +) -> Result<()> { + ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop) +} + +/// Reads a word from a user area at `offset`. +/// The user struct definition can be found in `/usr/include/sys/user.h`. +pub fn read_user(pid: Pid, offset: AddressType) -> Result { + ptrace_peek(Request::PTRACE_PEEKUSER, pid, offset, ptr::null_mut()) +} + +/// Writes a word to a user area at `offset`. +/// The user struct definition can be found in `/usr/include/sys/user.h`. +/// +/// # Safety +/// +/// The `data` argument is passed directly to `ptrace(2)`. Read that man page +/// for guidance. +pub unsafe fn write_user( + pid: Pid, + offset: AddressType, + data: *mut c_void, +) -> Result<()> { + ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop) +} diff --git a/vendor/nix-0.26.2/src/sys/ptrace/mod.rs b/vendor/nix-0.26.2/src/sys/ptrace/mod.rs new file mode 100644 index 0000000000000..2b121c0b4d829 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/ptrace/mod.rs @@ -0,0 +1,25 @@ +///! Provides helpers for making ptrace system calls + +#[cfg(any(target_os = "android", target_os = "linux"))] +mod linux; + +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use self::linux::*; + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] +mod bsd; + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] +pub use self::bsd::*; diff --git a/vendor/nix-0.26.2/src/sys/quota.rs b/vendor/nix-0.26.2/src/sys/quota.rs new file mode 100644 index 0000000000000..b3c44ca705223 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/quota.rs @@ -0,0 +1,338 @@ +//! Set and configure disk quotas for users, groups, or projects. +//! +//! # Examples +//! +//! Enabling and setting a quota: +//! +//! ```rust,no_run +//! # use nix::sys::quota::{Dqblk, quotactl_on, quotactl_set, QuotaFmt, QuotaType, QuotaValidFlags}; +//! quotactl_on(QuotaType::USRQUOTA, "/dev/sda1", QuotaFmt::QFMT_VFS_V1, "aquota.user").unwrap(); +//! let mut dqblk: Dqblk = Default::default(); +//! dqblk.set_blocks_hard_limit(10000); +//! dqblk.set_blocks_soft_limit(8000); +//! quotactl_set(QuotaType::USRQUOTA, "/dev/sda1", 50, &dqblk, QuotaValidFlags::QIF_BLIMITS).unwrap(); +//! ``` +use crate::errno::Errno; +use crate::{NixPath, Result}; +use libc::{self, c_char, c_int}; +use std::default::Default; +use std::{mem, ptr}; + +struct QuotaCmd(QuotaSubCmd, QuotaType); + +impl QuotaCmd { + #[allow(unused_unsafe)] + fn as_int(&self) -> c_int { + unsafe { libc::QCMD(self.0 as i32, self.1 as i32) } + } +} + +// linux quota version >= 2 +libc_enum! { + #[repr(i32)] + enum QuotaSubCmd { + Q_SYNC, + Q_QUOTAON, + Q_QUOTAOFF, + Q_GETQUOTA, + Q_SETQUOTA, + } +} + +libc_enum! { + /// The scope of the quota. + #[repr(i32)] + #[non_exhaustive] + pub enum QuotaType { + /// Specify a user quota + USRQUOTA, + /// Specify a group quota + GRPQUOTA, + } +} + +libc_enum! { + /// The type of quota format to use. + #[repr(i32)] + #[non_exhaustive] + pub enum QuotaFmt { + /// Use the original quota format. + QFMT_VFS_OLD, + /// Use the standard VFS v0 quota format. + /// + /// Handles 32-bit UIDs/GIDs and quota limits up to 232 bytes/232 inodes. + QFMT_VFS_V0, + /// Use the VFS v1 quota format. + /// + /// Handles 32-bit UIDs/GIDs and quota limits of 264 bytes/264 inodes. + QFMT_VFS_V1, + } +} + +libc_bitflags!( + /// Indicates the quota fields that are valid to read from. + #[derive(Default)] + pub struct QuotaValidFlags: u32 { + /// The block hard & soft limit fields. + QIF_BLIMITS; + /// The current space field. + QIF_SPACE; + /// The inode hard & soft limit fields. + QIF_ILIMITS; + /// The current inodes field. + QIF_INODES; + /// The disk use time limit field. + QIF_BTIME; + /// The file quote time limit field. + QIF_ITIME; + /// All block & inode limits. + QIF_LIMITS; + /// The space & inodes usage fields. + QIF_USAGE; + /// The time limit fields. + QIF_TIMES; + /// All fields. + QIF_ALL; + } +); + +/// Wrapper type for `if_dqblk` +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct Dqblk(libc::dqblk); + +impl Default for Dqblk { + fn default() -> Dqblk { + Dqblk(libc::dqblk { + dqb_bhardlimit: 0, + dqb_bsoftlimit: 0, + dqb_curspace: 0, + dqb_ihardlimit: 0, + dqb_isoftlimit: 0, + dqb_curinodes: 0, + dqb_btime: 0, + dqb_itime: 0, + dqb_valid: 0, + }) + } +} + +impl Dqblk { + /// The absolute limit on disk quota blocks allocated. + pub fn blocks_hard_limit(&self) -> Option { + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) { + Some(self.0.dqb_bhardlimit) + } else { + None + } + } + + /// Set the absolute limit on disk quota blocks allocated. + pub fn set_blocks_hard_limit(&mut self, limit: u64) { + self.0.dqb_bhardlimit = limit; + } + + /// Preferred limit on disk quota blocks + pub fn blocks_soft_limit(&self) -> Option { + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) { + Some(self.0.dqb_bsoftlimit) + } else { + None + } + } + + /// Set the preferred limit on disk quota blocks allocated. + pub fn set_blocks_soft_limit(&mut self, limit: u64) { + self.0.dqb_bsoftlimit = limit; + } + + /// Current occupied space (bytes). + pub fn occupied_space(&self) -> Option { + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + if valid_fields.contains(QuotaValidFlags::QIF_SPACE) { + Some(self.0.dqb_curspace) + } else { + None + } + } + + /// Maximum number of allocated inodes. + pub fn inodes_hard_limit(&self) -> Option { + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) { + Some(self.0.dqb_ihardlimit) + } else { + None + } + } + + /// Set the maximum number of allocated inodes. + pub fn set_inodes_hard_limit(&mut self, limit: u64) { + self.0.dqb_ihardlimit = limit; + } + + /// Preferred inode limit + pub fn inodes_soft_limit(&self) -> Option { + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) { + Some(self.0.dqb_isoftlimit) + } else { + None + } + } + + /// Set the preferred limit of allocated inodes. + pub fn set_inodes_soft_limit(&mut self, limit: u64) { + self.0.dqb_isoftlimit = limit; + } + + /// Current number of allocated inodes. + pub fn allocated_inodes(&self) -> Option { + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + if valid_fields.contains(QuotaValidFlags::QIF_INODES) { + Some(self.0.dqb_curinodes) + } else { + None + } + } + + /// Time limit for excessive disk use. + pub fn block_time_limit(&self) -> Option { + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + if valid_fields.contains(QuotaValidFlags::QIF_BTIME) { + Some(self.0.dqb_btime) + } else { + None + } + } + + /// Set the time limit for excessive disk use. + pub fn set_block_time_limit(&mut self, limit: u64) { + self.0.dqb_btime = limit; + } + + /// Time limit for excessive files. + pub fn inode_time_limit(&self) -> Option { + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + if valid_fields.contains(QuotaValidFlags::QIF_ITIME) { + Some(self.0.dqb_itime) + } else { + None + } + } + + /// Set the time limit for excessive files. + pub fn set_inode_time_limit(&mut self, limit: u64) { + self.0.dqb_itime = limit; + } +} + +fn quotactl( + cmd: QuotaCmd, + special: Option<&P>, + id: c_int, + addr: *mut c_char, +) -> Result<()> { + unsafe { + Errno::clear(); + let res = match special { + Some(dev) => dev.with_nix_path(|path| { + libc::quotactl(cmd.as_int(), path.as_ptr(), id, addr) + }), + None => Ok(libc::quotactl(cmd.as_int(), ptr::null(), id, addr)), + }?; + + Errno::result(res).map(drop) + } +} + +/// Turn on disk quotas for a block device. +pub fn quotactl_on( + which: QuotaType, + special: &P, + format: QuotaFmt, + quota_file: &P, +) -> Result<()> { + quota_file.with_nix_path(|path| { + let mut path_copy = path.to_bytes_with_nul().to_owned(); + let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char; + quotactl( + QuotaCmd(QuotaSubCmd::Q_QUOTAON, which), + Some(special), + format as c_int, + p, + ) + })? +} + +/// Disable disk quotas for a block device. +pub fn quotactl_off( + which: QuotaType, + special: &P, +) -> Result<()> { + quotactl( + QuotaCmd(QuotaSubCmd::Q_QUOTAOFF, which), + Some(special), + 0, + ptr::null_mut(), + ) +} + +/// Update the on-disk copy of quota usages for a filesystem. +/// +/// If `special` is `None`, then all file systems with active quotas are sync'd. +pub fn quotactl_sync( + which: QuotaType, + special: Option<&P>, +) -> Result<()> { + quotactl( + QuotaCmd(QuotaSubCmd::Q_SYNC, which), + special, + 0, + ptr::null_mut(), + ) +} + +/// Get disk quota limits and current usage for the given user/group id. +pub fn quotactl_get( + which: QuotaType, + special: &P, + id: c_int, +) -> Result { + let mut dqblk = mem::MaybeUninit::uninit(); + quotactl( + QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), + Some(special), + id, + dqblk.as_mut_ptr() as *mut c_char, + )?; + Ok(unsafe { Dqblk(dqblk.assume_init()) }) +} + +/// Configure quota values for the specified fields for a given user/group id. +pub fn quotactl_set( + which: QuotaType, + special: &P, + id: c_int, + dqblk: &Dqblk, + fields: QuotaValidFlags, +) -> Result<()> { + let mut dqblk_copy = *dqblk; + dqblk_copy.0.dqb_valid = fields.bits(); + quotactl( + QuotaCmd(QuotaSubCmd::Q_SETQUOTA, which), + Some(special), + id, + &mut dqblk_copy as *mut _ as *mut c_char, + ) +} diff --git a/vendor/nix-0.26.2/src/sys/reboot.rs b/vendor/nix-0.26.2/src/sys/reboot.rs new file mode 100644 index 0000000000000..02d98162bd0f9 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/reboot.rs @@ -0,0 +1,48 @@ +//! Reboot/shutdown or enable/disable Ctrl-Alt-Delete. + +use crate::errno::Errno; +use crate::Result; +use std::convert::Infallible; +use std::mem::drop; + +libc_enum! { + /// How exactly should the system be rebooted. + /// + /// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for + /// enabling/disabling Ctrl-Alt-Delete. + #[repr(i32)] + #[non_exhaustive] + pub enum RebootMode { + /// Halt the system. + RB_HALT_SYSTEM, + /// Execute a kernel that has been loaded earlier with + /// [`kexec_load(2)`](https://man7.org/linux/man-pages/man2/kexec_load.2.html). + RB_KEXEC, + /// Stop the system and switch off power, if possible. + RB_POWER_OFF, + /// Restart the system. + RB_AUTOBOOT, + // we do not support Restart2. + /// Suspend the system using software suspend. + RB_SW_SUSPEND, + } +} + +/// Reboots or shuts down the system. +pub fn reboot(how: RebootMode) -> Result { + unsafe { libc::reboot(how as libc::c_int) }; + Err(Errno::last()) +} + +/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete). +/// +/// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C. +pub fn set_cad_enabled(enable: bool) -> Result<()> { + let cmd = if enable { + libc::RB_ENABLE_CAD + } else { + libc::RB_DISABLE_CAD + }; + let res = unsafe { libc::reboot(cmd) }; + Errno::result(res).map(drop) +} diff --git a/vendor/nix-0.26.2/src/sys/resource.rs b/vendor/nix-0.26.2/src/sys/resource.rs new file mode 100644 index 0000000000000..892773776308e --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/resource.rs @@ -0,0 +1,443 @@ +//! Configure the process resource limits. +use cfg_if::cfg_if; +use libc::{c_int, c_long, rusage}; + +use crate::errno::Errno; +use crate::sys::time::TimeVal; +use crate::Result; +pub use libc::rlim_t; +pub use libc::RLIM_INFINITY; +use std::mem; + +cfg_if! { + if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ + use libc::{__rlimit_resource_t, rlimit}; + } else if #[cfg(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "dragonfly", + all(target_os = "linux", not(target_env = "gnu")) + ))]{ + use libc::rlimit; + } +} + +libc_enum! { + /// Types of process resources. + /// + /// The Resource enum is platform dependent. Check different platform + /// manuals for more details. Some platform links have been provided for + /// easier reference (non-exhaustive). + /// + /// * [Linux](https://man7.org/linux/man-pages/man2/getrlimit.2.html) + /// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=setrlimit) + /// * [NetBSD](https://man.netbsd.org/setrlimit.2) + + // linux-gnu uses u_int as resource enum, which is implemented in libc as + // well. + // + // https://gcc.gnu.org/legacy-ml/gcc/2015-08/msg00441.html + // https://github.com/rust-lang/libc/blob/master/src/unix/linux_like/linux/gnu/mod.rs + #[cfg_attr(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), repr(u32))] + #[cfg_attr(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "dragonfly", + all(target_os = "linux", not(any(target_env = "gnu", target_env = "uclibc"))) + ), repr(i32))] + #[non_exhaustive] + pub enum Resource { + #[cfg(not(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The maximum amount (in bytes) of virtual memory the process is + /// allowed to map. + RLIMIT_AS, + /// The largest size (in bytes) core(5) file that may be created. + RLIMIT_CORE, + /// The maximum amount of cpu time (in seconds) to be used by each + /// process. + RLIMIT_CPU, + /// The maximum size (in bytes) of the data segment for a process + RLIMIT_DATA, + /// The largest size (in bytes) file that may be created. + RLIMIT_FSIZE, + /// The maximum number of open files for this process. + RLIMIT_NOFILE, + /// The maximum size (in bytes) of the stack segment for a process. + RLIMIT_STACK, + + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The maximum number of kqueues this user id is allowed to create. + RLIMIT_KQUEUES, + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// A limit on the combined number of flock locks and fcntl leases that + /// this process may establish. + RLIMIT_LOCKS, + + #[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "linux", + target_os = "netbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The maximum size (in bytes) which a process may lock into memory + /// using the mlock(2) system call. + RLIMIT_MEMLOCK, + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// A limit on the number of bytes that can be allocated for POSIX + /// message queues for the real user ID of the calling process. + RLIMIT_MSGQUEUE, + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// A ceiling to which the process's nice value can be raised using + /// setpriority or nice. + RLIMIT_NICE, + + #[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", + target_os = "linux", + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The maximum number of simultaneous processes for this user id. + RLIMIT_NPROC, + + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The maximum number of pseudo-terminals this user id is allowed to + /// create. + RLIMIT_NPTS, + + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", + target_os = "linux", + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// When there is memory pressure and swap is available, prioritize + /// eviction of a process' resident pages beyond this amount (in bytes). + RLIMIT_RSS, + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// A ceiling on the real-time priority that may be set for this process + /// using sched_setscheduler and sched_set†param. + RLIMIT_RTPRIO, + + #[cfg(any(target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// A limit (in microseconds) on the amount of CPU time that a process + /// scheduled under a real-time scheduling policy may con†sume without + /// making a blocking system call. + RLIMIT_RTTIME, + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// A limit on the number of signals that may be queued for the real + /// user ID of the calling process. + RLIMIT_SIGPENDING, + + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The maximum size (in bytes) of socket buffer usage for this user. + RLIMIT_SBSIZE, + + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The maximum size (in bytes) of the swap space that may be reserved + /// or used by all of this user id's processes. + RLIMIT_SWAP, + + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// An alias for RLIMIT_AS. + RLIMIT_VMEM, + } +} + +/// Get the current processes resource limits +/// +/// The special value [`RLIM_INFINITY`] indicates that no limit will be +/// enforced. +/// +/// # Parameters +/// +/// * `resource`: The [`Resource`] that we want to get the limits of. +/// +/// # Examples +/// +/// ``` +/// # use nix::sys::resource::{getrlimit, Resource}; +/// +/// let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); +/// println!("current soft_limit: {}", soft_limit); +/// println!("current hard_limit: {}", hard_limit); +/// ``` +/// +/// # References +/// +/// [getrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215) +/// +/// [`Resource`]: enum.Resource.html +pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> { + let mut old_rlim = mem::MaybeUninit::::uninit(); + + cfg_if! { + if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ + let res = unsafe { libc::getrlimit(resource as __rlimit_resource_t, old_rlim.as_mut_ptr()) }; + } else { + let res = unsafe { libc::getrlimit(resource as c_int, old_rlim.as_mut_ptr()) }; + } + } + + Errno::result(res).map(|_| { + let rlimit { rlim_cur, rlim_max } = unsafe { old_rlim.assume_init() }; + (rlim_cur, rlim_max) + }) +} + +/// Set the current processes resource limits +/// +/// # Parameters +/// +/// * `resource`: The [`Resource`] that we want to set the limits of. +/// * `soft_limit`: The value that the kernel enforces for the corresponding +/// resource. +/// * `hard_limit`: The ceiling for the soft limit. Must be lower or equal to +/// the current hard limit for non-root users. +/// +/// The special value [`RLIM_INFINITY`] indicates that no limit will be +/// enforced. +/// +/// # Examples +/// +/// ``` +/// # use nix::sys::resource::{setrlimit, Resource}; +/// +/// let soft_limit = 512; +/// let hard_limit = 1024; +/// setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); +/// ``` +/// +/// # References +/// +/// [setrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215) +/// +/// [`Resource`]: enum.Resource.html +/// +/// Note: `setrlimit` provides a safe wrapper to libc's `setrlimit`. +pub fn setrlimit( + resource: Resource, + soft_limit: rlim_t, + hard_limit: rlim_t, +) -> Result<()> { + let new_rlim = rlimit { + rlim_cur: soft_limit, + rlim_max: hard_limit, + }; + cfg_if! { + if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ + let res = unsafe { libc::setrlimit(resource as __rlimit_resource_t, &new_rlim as *const rlimit) }; + }else{ + let res = unsafe { libc::setrlimit(resource as c_int, &new_rlim as *const rlimit) }; + } + } + + Errno::result(res).map(drop) +} + +libc_enum! { + /// Whose resource usage should be returned by [`getrusage`]. + #[repr(i32)] + #[non_exhaustive] + pub enum UsageWho { + /// Resource usage for the current process. + RUSAGE_SELF, + + /// Resource usage for all the children that have terminated and been waited for. + RUSAGE_CHILDREN, + + #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Resource usage for the calling thread. + RUSAGE_THREAD, + } +} + +/// Output of `getrusage` with information about resource usage. Some of the fields +/// may be unused in some platforms, and will be always zeroed out. See their manuals +/// for details. +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct Usage(rusage); + +impl AsRef for Usage { + fn as_ref(&self) -> &rusage { + &self.0 + } +} + +impl AsMut for Usage { + fn as_mut(&mut self) -> &mut rusage { + &mut self.0 + } +} + +impl Usage { + /// Total amount of time spent executing in user mode. + pub fn user_time(&self) -> TimeVal { + TimeVal::from(self.0.ru_utime) + } + + /// Total amount of time spent executing in kernel mode. + pub fn system_time(&self) -> TimeVal { + TimeVal::from(self.0.ru_stime) + } + + /// The resident set size at its peak, in kilobytes. + pub fn max_rss(&self) -> c_long { + self.0.ru_maxrss + } + + /// Integral value expressed in kilobytes times ticks of execution indicating + /// the amount of text memory shared with other processes. + pub fn shared_integral(&self) -> c_long { + self.0.ru_ixrss + } + + /// Integral value expressed in kilobytes times ticks of execution indicating + /// the amount of unshared memory used by data. + pub fn unshared_data_integral(&self) -> c_long { + self.0.ru_idrss + } + + /// Integral value expressed in kilobytes times ticks of execution indicating + /// the amount of unshared memory used for stack space. + pub fn unshared_stack_integral(&self) -> c_long { + self.0.ru_isrss + } + + /// Number of page faults that were served without resorting to I/O, with pages + /// that have been allocated previously by the kernel. + pub fn minor_page_faults(&self) -> c_long { + self.0.ru_minflt + } + + /// Number of page faults that were served through I/O (i.e. swap). + pub fn major_page_faults(&self) -> c_long { + self.0.ru_majflt + } + + /// Number of times all of the memory was fully swapped out. + pub fn full_swaps(&self) -> c_long { + self.0.ru_nswap + } + + /// Number of times a read was done from a block device. + pub fn block_reads(&self) -> c_long { + self.0.ru_inblock + } + + /// Number of times a write was done to a block device. + pub fn block_writes(&self) -> c_long { + self.0.ru_oublock + } + + /// Number of IPC messages sent. + pub fn ipc_sends(&self) -> c_long { + self.0.ru_msgsnd + } + + /// Number of IPC messages received. + pub fn ipc_receives(&self) -> c_long { + self.0.ru_msgrcv + } + + /// Number of signals received. + pub fn signals(&self) -> c_long { + self.0.ru_nsignals + } + + /// Number of times a context switch was voluntarily invoked. + pub fn voluntary_context_switches(&self) -> c_long { + self.0.ru_nvcsw + } + + /// Number of times a context switch was imposed by the kernel (usually due to + /// time slice expiring or preemption by a higher priority process). + pub fn involuntary_context_switches(&self) -> c_long { + self.0.ru_nivcsw + } +} + +/// Get usage information for a process, its children or the current thread +/// +/// Real time information can be obtained for either the current process or (in some +/// systems) thread, but information about children processes is only provided for +/// those that have terminated and been waited for (see [`super::wait::wait`]). +/// +/// Some information may be missing depending on the platform, and the way information +/// is provided for children may also vary. Check the manuals for details. +/// +/// # References +/// +/// * [getrusage(2)](https://pubs.opengroup.org/onlinepubs/009696699/functions/getrusage.html) +/// * [Linux](https://man7.org/linux/man-pages/man2/getrusage.2.html) +/// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=getrusage) +/// * [NetBSD](https://man.netbsd.org/getrusage.2) +/// * [MacOS](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getrusage.2.html) +/// +/// [`UsageWho`]: enum.UsageWho.html +/// +/// Note: `getrusage` provides a safe wrapper to libc's [`libc::getrusage`]. +pub fn getrusage(who: UsageWho) -> Result { + unsafe { + let mut rusage = mem::MaybeUninit::::uninit(); + let res = libc::getrusage(who as c_int, rusage.as_mut_ptr()); + Errno::result(res).map(|_| Usage(rusage.assume_init())) + } +} + +#[cfg(test)] +mod test { + use super::{getrusage, UsageWho}; + + #[test] + pub fn test_self_cpu_time() { + // Make sure some CPU time is used. + let mut numbers: Vec = (1..1_000_000).collect(); + numbers.iter_mut().for_each(|item| *item *= 2); + + // FIXME: this is here to help ensure the compiler does not optimize the whole + // thing away. Replace the assert with test::black_box once stabilized. + assert_eq!(numbers[100..200].iter().sum::(), 30_100); + + let usage = getrusage(UsageWho::RUSAGE_SELF) + .expect("Failed to call getrusage for SELF"); + let rusage = usage.as_ref(); + + let user = usage.user_time(); + assert!(user.tv_sec() > 0 || user.tv_usec() > 0); + assert_eq!(user.tv_sec(), rusage.ru_utime.tv_sec); + assert_eq!(user.tv_usec(), rusage.ru_utime.tv_usec); + } +} diff --git a/vendor/nix-0.26.2/src/sys/select.rs b/vendor/nix-0.26.2/src/sys/select.rs new file mode 100644 index 0000000000000..7a94cff87ed01 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/select.rs @@ -0,0 +1,455 @@ +//! Portably monitor a group of file descriptors for readiness. +use crate::errno::Errno; +use crate::sys::time::{TimeSpec, TimeVal}; +use crate::Result; +use libc::{self, c_int}; +use std::convert::TryFrom; +use std::iter::FusedIterator; +use std::mem; +use std::ops::Range; +use std::os::unix::io::RawFd; +use std::ptr::{null, null_mut}; + +pub use libc::FD_SETSIZE; + +/// Contains a set of file descriptors used by [`select`] +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct FdSet(libc::fd_set); + +fn assert_fd_valid(fd: RawFd) { + assert!( + usize::try_from(fd).map_or(false, |fd| fd < FD_SETSIZE), + "fd must be in the range 0..FD_SETSIZE", + ); +} + +impl FdSet { + /// Create an empty `FdSet` + pub fn new() -> FdSet { + let mut fdset = mem::MaybeUninit::uninit(); + unsafe { + libc::FD_ZERO(fdset.as_mut_ptr()); + FdSet(fdset.assume_init()) + } + } + + /// Add a file descriptor to an `FdSet` + pub fn insert(&mut self, fd: RawFd) { + assert_fd_valid(fd); + unsafe { libc::FD_SET(fd, &mut self.0) }; + } + + /// Remove a file descriptor from an `FdSet` + pub fn remove(&mut self, fd: RawFd) { + assert_fd_valid(fd); + unsafe { libc::FD_CLR(fd, &mut self.0) }; + } + + /// Test an `FdSet` for the presence of a certain file descriptor. + pub fn contains(&self, fd: RawFd) -> bool { + assert_fd_valid(fd); + unsafe { libc::FD_ISSET(fd, &self.0) } + } + + /// Remove all file descriptors from this `FdSet`. + pub fn clear(&mut self) { + unsafe { libc::FD_ZERO(&mut self.0) }; + } + + /// Finds the highest file descriptor in the set. + /// + /// Returns `None` if the set is empty. + /// + /// This can be used to calculate the `nfds` parameter of the [`select`] function. + /// + /// # Example + /// + /// ``` + /// # use nix::sys::select::FdSet; + /// let mut set = FdSet::new(); + /// set.insert(4); + /// set.insert(9); + /// assert_eq!(set.highest(), Some(9)); + /// ``` + /// + /// [`select`]: fn.select.html + pub fn highest(&self) -> Option { + self.fds(None).next_back() + } + + /// Returns an iterator over the file descriptors in the set. + /// + /// For performance, it takes an optional higher bound: the iterator will + /// not return any elements of the set greater than the given file + /// descriptor. + /// + /// # Examples + /// + /// ``` + /// # use nix::sys::select::FdSet; + /// # use std::os::unix::io::RawFd; + /// let mut set = FdSet::new(); + /// set.insert(4); + /// set.insert(9); + /// let fds: Vec = set.fds(None).collect(); + /// assert_eq!(fds, vec![4, 9]); + /// ``` + #[inline] + pub fn fds(&self, highest: Option) -> Fds { + Fds { + set: self, + range: 0..highest.map(|h| h as usize + 1).unwrap_or(FD_SETSIZE), + } + } +} + +impl Default for FdSet { + fn default() -> Self { + Self::new() + } +} + +/// Iterator over `FdSet`. +#[derive(Debug)] +pub struct Fds<'a> { + set: &'a FdSet, + range: Range, +} + +impl<'a> Iterator for Fds<'a> { + type Item = RawFd; + + fn next(&mut self) -> Option { + for i in &mut self.range { + if self.set.contains(i as RawFd) { + return Some(i as RawFd); + } + } + None + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.range.size_hint(); + (0, upper) + } +} + +impl<'a> DoubleEndedIterator for Fds<'a> { + #[inline] + fn next_back(&mut self) -> Option { + while let Some(i) = self.range.next_back() { + if self.set.contains(i as RawFd) { + return Some(i as RawFd); + } + } + None + } +} + +impl<'a> FusedIterator for Fds<'a> {} + +/// Monitors file descriptors for readiness +/// +/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all +/// file descriptors that are ready for the given operation are set. +/// +/// When this function returns, `timeout` has an implementation-defined value. +/// +/// # Parameters +/// +/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this +/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1 +/// to the maximum of that. +/// * `readfds`: File descriptors to check for being ready to read. +/// * `writefds`: File descriptors to check for being ready to write. +/// * `errorfds`: File descriptors to check for pending error conditions. +/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block +/// indefinitely). +/// +/// # References +/// +/// [select(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html) +/// +/// [`FdSet::highest`]: struct.FdSet.html#method.highest +pub fn select<'a, N, R, W, E, T>( + nfds: N, + readfds: R, + writefds: W, + errorfds: E, + timeout: T, +) -> Result +where + N: Into>, + R: Into>, + W: Into>, + E: Into>, + T: Into>, +{ + let mut readfds = readfds.into(); + let mut writefds = writefds.into(); + let mut errorfds = errorfds.into(); + let timeout = timeout.into(); + + let nfds = nfds.into().unwrap_or_else(|| { + readfds + .iter_mut() + .chain(writefds.iter_mut()) + .chain(errorfds.iter_mut()) + .map(|set| set.highest().unwrap_or(-1)) + .max() + .unwrap_or(-1) + + 1 + }); + + let readfds = readfds + .map(|set| set as *mut _ as *mut libc::fd_set) + .unwrap_or(null_mut()); + let writefds = writefds + .map(|set| set as *mut _ as *mut libc::fd_set) + .unwrap_or(null_mut()); + let errorfds = errorfds + .map(|set| set as *mut _ as *mut libc::fd_set) + .unwrap_or(null_mut()); + let timeout = timeout + .map(|tv| tv as *mut _ as *mut libc::timeval) + .unwrap_or(null_mut()); + + let res = + unsafe { libc::select(nfds, readfds, writefds, errorfds, timeout) }; + + Errno::result(res) +} + +feature! { +#![feature = "signal"] + +use crate::sys::signal::SigSet; + +/// Monitors file descriptors for readiness with an altered signal mask. +/// +/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all +/// file descriptors that are ready for the given operation are set. +/// +/// When this function returns, the original signal mask is restored. +/// +/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value. +/// +/// # Parameters +/// +/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this +/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1 +/// to the maximum of that. +/// * `readfds`: File descriptors to check for read readiness +/// * `writefds`: File descriptors to check for write readiness +/// * `errorfds`: File descriptors to check for pending error conditions. +/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block +/// indefinitely). +/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn +/// ready (`None` to set no alternative signal mask). +/// +/// # References +/// +/// [pselect(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html) +/// +/// [The new pselect() system call](https://lwn.net/Articles/176911/) +/// +/// [`FdSet::highest`]: struct.FdSet.html#method.highest +pub fn pselect<'a, N, R, W, E, T, S>(nfds: N, + readfds: R, + writefds: W, + errorfds: E, + timeout: T, + sigmask: S) -> Result +where + N: Into>, + R: Into>, + W: Into>, + E: Into>, + T: Into>, + S: Into>, +{ + let mut readfds = readfds.into(); + let mut writefds = writefds.into(); + let mut errorfds = errorfds.into(); + let sigmask = sigmask.into(); + let timeout = timeout.into(); + + let nfds = nfds.into().unwrap_or_else(|| { + readfds.iter_mut() + .chain(writefds.iter_mut()) + .chain(errorfds.iter_mut()) + .map(|set| set.highest().unwrap_or(-1)) + .max() + .unwrap_or(-1) + 1 + }); + + let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); + let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); + let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); + let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null()); + let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null()); + + let res = unsafe { + libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask) + }; + + Errno::result(res) +} +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::sys::time::{TimeVal, TimeValLike}; + use crate::unistd::{pipe, write}; + use std::os::unix::io::RawFd; + + #[test] + fn fdset_insert() { + let mut fd_set = FdSet::new(); + + for i in 0..FD_SETSIZE { + assert!(!fd_set.contains(i as RawFd)); + } + + fd_set.insert(7); + + assert!(fd_set.contains(7)); + } + + #[test] + fn fdset_remove() { + let mut fd_set = FdSet::new(); + + for i in 0..FD_SETSIZE { + assert!(!fd_set.contains(i as RawFd)); + } + + fd_set.insert(7); + fd_set.remove(7); + + for i in 0..FD_SETSIZE { + assert!(!fd_set.contains(i as RawFd)); + } + } + + #[test] + fn fdset_clear() { + let mut fd_set = FdSet::new(); + fd_set.insert(1); + fd_set.insert((FD_SETSIZE / 2) as RawFd); + fd_set.insert((FD_SETSIZE - 1) as RawFd); + + fd_set.clear(); + + for i in 0..FD_SETSIZE { + assert!(!fd_set.contains(i as RawFd)); + } + } + + #[test] + fn fdset_highest() { + let mut set = FdSet::new(); + assert_eq!(set.highest(), None); + set.insert(0); + assert_eq!(set.highest(), Some(0)); + set.insert(90); + assert_eq!(set.highest(), Some(90)); + set.remove(0); + assert_eq!(set.highest(), Some(90)); + set.remove(90); + assert_eq!(set.highest(), None); + + set.insert(4); + set.insert(5); + set.insert(7); + assert_eq!(set.highest(), Some(7)); + } + + #[test] + fn fdset_fds() { + let mut set = FdSet::new(); + assert_eq!(set.fds(None).collect::>(), vec![]); + set.insert(0); + assert_eq!(set.fds(None).collect::>(), vec![0]); + set.insert(90); + assert_eq!(set.fds(None).collect::>(), vec![0, 90]); + + // highest limit + assert_eq!(set.fds(Some(89)).collect::>(), vec![0]); + assert_eq!(set.fds(Some(90)).collect::>(), vec![0, 90]); + } + + #[test] + fn test_select() { + let (r1, w1) = pipe().unwrap(); + write(w1, b"hi!").unwrap(); + let (r2, _w2) = pipe().unwrap(); + + let mut fd_set = FdSet::new(); + fd_set.insert(r1); + fd_set.insert(r2); + + let mut timeout = TimeVal::seconds(10); + assert_eq!( + 1, + select(None, &mut fd_set, None, None, &mut timeout).unwrap() + ); + assert!(fd_set.contains(r1)); + assert!(!fd_set.contains(r2)); + } + + #[test] + fn test_select_nfds() { + let (r1, w1) = pipe().unwrap(); + write(w1, b"hi!").unwrap(); + let (r2, _w2) = pipe().unwrap(); + + let mut fd_set = FdSet::new(); + fd_set.insert(r1); + fd_set.insert(r2); + + let mut timeout = TimeVal::seconds(10); + assert_eq!( + 1, + select( + Some(fd_set.highest().unwrap() + 1), + &mut fd_set, + None, + None, + &mut timeout + ) + .unwrap() + ); + assert!(fd_set.contains(r1)); + assert!(!fd_set.contains(r2)); + } + + #[test] + fn test_select_nfds2() { + let (r1, w1) = pipe().unwrap(); + write(w1, b"hi!").unwrap(); + let (r2, _w2) = pipe().unwrap(); + + let mut fd_set = FdSet::new(); + fd_set.insert(r1); + fd_set.insert(r2); + + let mut timeout = TimeVal::seconds(10); + assert_eq!( + 1, + select( + ::std::cmp::max(r1, r2) + 1, + &mut fd_set, + None, + None, + &mut timeout + ) + .unwrap() + ); + assert!(fd_set.contains(r1)); + assert!(!fd_set.contains(r2)); + } +} diff --git a/vendor/nix-0.26.2/src/sys/sendfile.rs b/vendor/nix-0.26.2/src/sys/sendfile.rs new file mode 100644 index 0000000000000..fb293a4e74ab9 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/sendfile.rs @@ -0,0 +1,277 @@ +//! Send data from a file to a socket, bypassing userland. + +use cfg_if::cfg_if; +use std::os::unix::io::RawFd; +use std::ptr; + +use libc::{self, off_t}; + +use crate::errno::Errno; +use crate::Result; + +/// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`. +/// +/// Returns a `Result` with the number of bytes written. +/// +/// If `offset` is `None`, `sendfile` will begin reading at the current offset of `in_fd`and will +/// update the offset of `in_fd`. If `offset` is `Some`, `sendfile` will begin at the specified +/// offset and will not update the offset of `in_fd`. Instead, it will mutate `offset` to point to +/// the byte after the last byte copied. +/// +/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket. +/// +/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn sendfile( + out_fd: RawFd, + in_fd: RawFd, + offset: Option<&mut off_t>, + count: usize, +) -> Result { + let offset = offset + .map(|offset| offset as *mut _) + .unwrap_or(ptr::null_mut()); + let ret = unsafe { libc::sendfile(out_fd, in_fd, offset, count) }; + Errno::result(ret).map(|r| r as usize) +} + +/// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`. +/// +/// Returns a `Result` with the number of bytes written. +/// +/// If `offset` is `None`, `sendfile` will begin reading at the current offset of `in_fd`and will +/// update the offset of `in_fd`. If `offset` is `Some`, `sendfile` will begin at the specified +/// offset and will not update the offset of `in_fd`. Instead, it will mutate `offset` to point to +/// the byte after the last byte copied. +/// +/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket. +/// +/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) +#[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn sendfile64( + out_fd: RawFd, + in_fd: RawFd, + offset: Option<&mut libc::off64_t>, + count: usize, +) -> Result { + let offset = offset + .map(|offset| offset as *mut _) + .unwrap_or(ptr::null_mut()); + let ret = unsafe { libc::sendfile64(out_fd, in_fd, offset, count) }; + Errno::result(ret).map(|r| r as usize) +} + +cfg_if! { + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos"))] { + use std::io::IoSlice; + + #[derive(Clone, Debug)] + struct SendfileHeaderTrailer<'a>( + libc::sf_hdtr, + Option>>, + Option>>, + ); + + impl<'a> SendfileHeaderTrailer<'a> { + fn new( + headers: Option<&'a [&'a [u8]]>, + trailers: Option<&'a [&'a [u8]]> + ) -> SendfileHeaderTrailer<'a> { + let header_iovecs: Option>> = + headers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); + let trailer_iovecs: Option>> = + trailers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); + SendfileHeaderTrailer( + libc::sf_hdtr { + headers: { + header_iovecs + .as_ref() + .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec + }, + hdr_cnt: header_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32, + trailers: { + trailer_iovecs + .as_ref() + .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec + }, + trl_cnt: trailer_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32 + }, + header_iovecs, + trailer_iovecs, + ) + } + } + } +} + +cfg_if! { + if #[cfg(target_os = "freebsd")] { + use libc::c_int; + + libc_bitflags!{ + /// Configuration options for [`sendfile`.](fn.sendfile.html) + pub struct SfFlags: c_int { + /// Causes `sendfile` to return EBUSY instead of blocking when attempting to read a + /// busy page. + SF_NODISKIO; + /// Causes `sendfile` to sleep until the network stack releases its reference to the + /// VM pages read. When `sendfile` returns, the data is not guaranteed to have been + /// sent, but it is safe to modify the file. + SF_SYNC; + /// Causes `sendfile` to cache exactly the number of pages specified in the + /// `readahead` parameter, disabling caching heuristics. + SF_USER_READAHEAD; + /// Causes `sendfile` not to cache the data read. + SF_NOCACHE; + } + } + + /// Read up to `count` bytes from `in_fd` starting at `offset` and write to `out_sock`. + /// + /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if + /// an error occurs. + /// + /// `in_fd` must describe a regular file or shared memory object. `out_sock` must describe a + /// stream socket. + /// + /// If `offset` falls past the end of the file, the function returns success and zero bytes + /// written. + /// + /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of + /// file (EOF). + /// + /// `headers` and `trailers` specify optional slices of byte slices to be sent before and + /// after the data read from `in_fd`, respectively. The length of headers and trailers sent + /// is included in the returned count of bytes written. The values of `offset` and `count` + /// do not apply to headers or trailers. + /// + /// `readahead` specifies the minimum number of pages to cache in memory ahead of the page + /// currently being sent. + /// + /// For more information, see + /// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2) + #[allow(clippy::too_many_arguments)] + pub fn sendfile( + in_fd: RawFd, + out_sock: RawFd, + offset: off_t, + count: Option, + headers: Option<&[&[u8]]>, + trailers: Option<&[&[u8]]>, + flags: SfFlags, + readahead: u16 + ) -> (Result<()>, off_t) { + // Readahead goes in upper 16 bits + // Flags goes in lower 16 bits + // see `man 2 sendfile` + let ra32 = u32::from(readahead); + let flags: u32 = (ra32 << 16) | (flags.bits() as u32); + let mut bytes_sent: off_t = 0; + let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); + let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); + let return_code = unsafe { + libc::sendfile(in_fd, + out_sock, + offset, + count.unwrap_or(0), + hdtr_ptr as *mut libc::sf_hdtr, + &mut bytes_sent as *mut off_t, + flags as c_int) + }; + (Errno::result(return_code).and(Ok(())), bytes_sent) + } + } else if #[cfg(target_os = "dragonfly")] { + /// Read up to `count` bytes from `in_fd` starting at `offset` and write to `out_sock`. + /// + /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if + /// an error occurs. + /// + /// `in_fd` must describe a regular file. `out_sock` must describe a stream socket. + /// + /// If `offset` falls past the end of the file, the function returns success and zero bytes + /// written. + /// + /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of + /// file (EOF). + /// + /// `headers` and `trailers` specify optional slices of byte slices to be sent before and + /// after the data read from `in_fd`, respectively. The length of headers and trailers sent + /// is included in the returned count of bytes written. The values of `offset` and `count` + /// do not apply to headers or trailers. + /// + /// For more information, see + /// [the sendfile(2) man page.](https://leaf.dragonflybsd.org/cgi/web-man?command=sendfile§ion=2) + pub fn sendfile( + in_fd: RawFd, + out_sock: RawFd, + offset: off_t, + count: Option, + headers: Option<&[&[u8]]>, + trailers: Option<&[&[u8]]>, + ) -> (Result<()>, off_t) { + let mut bytes_sent: off_t = 0; + let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); + let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); + let return_code = unsafe { + libc::sendfile(in_fd, + out_sock, + offset, + count.unwrap_or(0), + hdtr_ptr as *mut libc::sf_hdtr, + &mut bytes_sent as *mut off_t, + 0) + }; + (Errno::result(return_code).and(Ok(())), bytes_sent) + } + } else if #[cfg(any(target_os = "ios", target_os = "macos"))] { + /// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to + /// `out_sock`. + /// + /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if + /// an error occurs. + /// + /// `in_fd` must describe a regular file. `out_sock` must describe a stream socket. + /// + /// If `offset` falls past the end of the file, the function returns success and zero bytes + /// written. + /// + /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of + /// file (EOF). + /// + /// `hdtr` specifies an optional list of headers and trailers to be sent before and after + /// the data read from `in_fd`, respectively. The length of headers and trailers sent is + /// included in the returned count of bytes written. If any headers are specified and + /// `count` is non-zero, the length of the headers will be counted in the limit of total + /// bytes sent. Trailers do not count toward the limit of bytes sent and will always be sent + /// regardless. The value of `offset` does not affect headers or trailers. + /// + /// For more information, see + /// [the sendfile(2) man page.](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/sendfile.2.html) + pub fn sendfile( + in_fd: RawFd, + out_sock: RawFd, + offset: off_t, + count: Option, + headers: Option<&[&[u8]]>, + trailers: Option<&[&[u8]]> + ) -> (Result<()>, off_t) { + let mut len = count.unwrap_or(0); + let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); + let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); + let return_code = unsafe { + libc::sendfile(in_fd, + out_sock, + offset, + &mut len as *mut off_t, + hdtr_ptr as *mut libc::sf_hdtr, + 0) + }; + (Errno::result(return_code).and(Ok(())), len) + } + } +} diff --git a/vendor/nix-0.26.2/src/sys/signal.rs b/vendor/nix-0.26.2/src/sys/signal.rs new file mode 100644 index 0000000000000..d3746e609aaae --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/signal.rs @@ -0,0 +1,1348 @@ +// Portions of this file are Copyright 2014 The Rust Project Developers. +// See https://www.rust-lang.org/policies/licenses. + +//! Operating system signals. + +use crate::errno::Errno; +use crate::{Error, Result}; +use cfg_if::cfg_if; +use std::fmt; +use std::mem; +#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] +use std::os::unix::io::RawFd; +use std::ptr; +use std::str::FromStr; + +#[cfg(not(any(target_os = "openbsd", target_os = "redox")))] +#[cfg(any(feature = "aio", feature = "signal"))] +pub use self::sigevent::*; + +#[cfg(any(feature = "aio", feature = "process", feature = "signal"))] +libc_enum! { + /// Types of operating system signals + // Currently there is only one definition of c_int in libc, as well as only one + // type for signal constants. + // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately + // this is not (yet) possible. + #[repr(i32)] + #[non_exhaustive] + #[cfg_attr(docsrs, doc(cfg(any(feature = "aio", feature = "signal"))))] + pub enum Signal { + /// Hangup + SIGHUP, + /// Interrupt + SIGINT, + /// Quit + SIGQUIT, + /// Illegal instruction (not reset when caught) + SIGILL, + /// Trace trap (not reset when caught) + SIGTRAP, + /// Abort + SIGABRT, + /// Bus error + SIGBUS, + /// Floating point exception + SIGFPE, + /// Kill (cannot be caught or ignored) + SIGKILL, + /// User defined signal 1 + SIGUSR1, + /// Segmentation violation + SIGSEGV, + /// User defined signal 2 + SIGUSR2, + /// Write on a pipe with no one to read it + SIGPIPE, + /// Alarm clock + SIGALRM, + /// Software termination signal from kill + SIGTERM, + /// Stack fault (obsolete) + #[cfg(all(any(target_os = "android", target_os = "emscripten", + target_os = "fuchsia", target_os = "linux"), + not(any(target_arch = "mips", target_arch = "mips64", + target_arch = "sparc64"))))] + SIGSTKFLT, + /// To parent on child stop or exit + SIGCHLD, + /// Continue a stopped process + SIGCONT, + /// Sendable stop signal not from tty + SIGSTOP, + /// Stop signal from tty + SIGTSTP, + /// To readers pgrp upon background tty read + SIGTTIN, + /// Like TTIN if (tp->t_local<OSTOP) + SIGTTOU, + /// Urgent condition on IO channel + SIGURG, + /// Exceeded CPU time limit + SIGXCPU, + /// Exceeded file size limit + SIGXFSZ, + /// Virtual time alarm + SIGVTALRM, + /// Profiling time alarm + SIGPROF, + /// Window size changes + SIGWINCH, + /// Input/output possible signal + #[cfg(not(target_os = "haiku"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + SIGIO, + #[cfg(any(target_os = "android", target_os = "emscripten", + target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Power failure imminent. + SIGPWR, + /// Bad system call + SIGSYS, + #[cfg(not(any(target_os = "android", target_os = "emscripten", + target_os = "fuchsia", target_os = "linux", + target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Emulator trap + SIGEMT, + #[cfg(not(any(target_os = "android", target_os = "emscripten", + target_os = "fuchsia", target_os = "linux", + target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Information request + SIGINFO, + } + impl TryFrom +} + +#[cfg(feature = "signal")] +impl FromStr for Signal { + type Err = Error; + fn from_str(s: &str) -> Result { + Ok(match s { + "SIGHUP" => Signal::SIGHUP, + "SIGINT" => Signal::SIGINT, + "SIGQUIT" => Signal::SIGQUIT, + "SIGILL" => Signal::SIGILL, + "SIGTRAP" => Signal::SIGTRAP, + "SIGABRT" => Signal::SIGABRT, + "SIGBUS" => Signal::SIGBUS, + "SIGFPE" => Signal::SIGFPE, + "SIGKILL" => Signal::SIGKILL, + "SIGUSR1" => Signal::SIGUSR1, + "SIGSEGV" => Signal::SIGSEGV, + "SIGUSR2" => Signal::SIGUSR2, + "SIGPIPE" => Signal::SIGPIPE, + "SIGALRM" => Signal::SIGALRM, + "SIGTERM" => Signal::SIGTERM, + #[cfg(all( + any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux" + ), + not(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "sparc64" + )) + ))] + "SIGSTKFLT" => Signal::SIGSTKFLT, + "SIGCHLD" => Signal::SIGCHLD, + "SIGCONT" => Signal::SIGCONT, + "SIGSTOP" => Signal::SIGSTOP, + "SIGTSTP" => Signal::SIGTSTP, + "SIGTTIN" => Signal::SIGTTIN, + "SIGTTOU" => Signal::SIGTTOU, + "SIGURG" => Signal::SIGURG, + "SIGXCPU" => Signal::SIGXCPU, + "SIGXFSZ" => Signal::SIGXFSZ, + "SIGVTALRM" => Signal::SIGVTALRM, + "SIGPROF" => Signal::SIGPROF, + "SIGWINCH" => Signal::SIGWINCH, + #[cfg(not(target_os = "haiku"))] + "SIGIO" => Signal::SIGIO, + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux" + ))] + "SIGPWR" => Signal::SIGPWR, + "SIGSYS" => Signal::SIGSYS, + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux", + target_os = "redox", + target_os = "haiku" + )))] + "SIGEMT" => Signal::SIGEMT, + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux", + target_os = "redox", + target_os = "haiku" + )))] + "SIGINFO" => Signal::SIGINFO, + _ => return Err(Errno::EINVAL), + }) + } +} + +#[cfg(feature = "signal")] +impl Signal { + /// Returns name of signal. + /// + /// This function is equivalent to `>::as_ref()`, + /// with difference that returned string is `'static` + /// and not bound to `self`'s lifetime. + pub const fn as_str(self) -> &'static str { + match self { + Signal::SIGHUP => "SIGHUP", + Signal::SIGINT => "SIGINT", + Signal::SIGQUIT => "SIGQUIT", + Signal::SIGILL => "SIGILL", + Signal::SIGTRAP => "SIGTRAP", + Signal::SIGABRT => "SIGABRT", + Signal::SIGBUS => "SIGBUS", + Signal::SIGFPE => "SIGFPE", + Signal::SIGKILL => "SIGKILL", + Signal::SIGUSR1 => "SIGUSR1", + Signal::SIGSEGV => "SIGSEGV", + Signal::SIGUSR2 => "SIGUSR2", + Signal::SIGPIPE => "SIGPIPE", + Signal::SIGALRM => "SIGALRM", + Signal::SIGTERM => "SIGTERM", + #[cfg(all( + any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux" + ), + not(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "sparc64" + )) + ))] + Signal::SIGSTKFLT => "SIGSTKFLT", + Signal::SIGCHLD => "SIGCHLD", + Signal::SIGCONT => "SIGCONT", + Signal::SIGSTOP => "SIGSTOP", + Signal::SIGTSTP => "SIGTSTP", + Signal::SIGTTIN => "SIGTTIN", + Signal::SIGTTOU => "SIGTTOU", + Signal::SIGURG => "SIGURG", + Signal::SIGXCPU => "SIGXCPU", + Signal::SIGXFSZ => "SIGXFSZ", + Signal::SIGVTALRM => "SIGVTALRM", + Signal::SIGPROF => "SIGPROF", + Signal::SIGWINCH => "SIGWINCH", + #[cfg(not(target_os = "haiku"))] + Signal::SIGIO => "SIGIO", + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux" + ))] + Signal::SIGPWR => "SIGPWR", + Signal::SIGSYS => "SIGSYS", + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux", + target_os = "redox", + target_os = "haiku" + )))] + Signal::SIGEMT => "SIGEMT", + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux", + target_os = "redox", + target_os = "haiku" + )))] + Signal::SIGINFO => "SIGINFO", + } + } +} + +#[cfg(feature = "signal")] +impl AsRef for Signal { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +#[cfg(feature = "signal")] +impl fmt::Display for Signal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.as_ref()) + } +} + +#[cfg(feature = "signal")] +pub use self::Signal::*; + +#[cfg(target_os = "redox")] +#[cfg(feature = "signal")] +const SIGNALS: [Signal; 29] = [ + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, + SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, + SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, + SIGPROF, SIGWINCH, SIGIO, SIGSYS, +]; +#[cfg(target_os = "haiku")] +#[cfg(feature = "signal")] +const SIGNALS: [Signal; 28] = [ + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, + SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, + SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, + SIGPROF, SIGWINCH, SIGSYS, +]; +#[cfg(all( + any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia" + ), + not(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "sparc64" + )) +))] +#[cfg(feature = "signal")] +const SIGNALS: [Signal; 31] = [ + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, + SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT, SIGCHLD, + SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, + SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS, +]; +#[cfg(all( + any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia" + ), + any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64") +))] +#[cfg(feature = "signal")] +const SIGNALS: [Signal; 30] = [ + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, + SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, + SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, + SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS, +]; +#[cfg(not(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "emscripten", + target_os = "redox", + target_os = "haiku" +)))] +#[cfg(feature = "signal")] +const SIGNALS: [Signal; 31] = [ + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, + SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, + SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, + SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT, SIGINFO, +]; + +feature! { +#![feature = "signal"] + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +/// Iterate through all signals defined by this operating system +pub struct SignalIterator { + next: usize, +} + +impl Iterator for SignalIterator { + type Item = Signal; + + fn next(&mut self) -> Option { + if self.next < SIGNALS.len() { + let next_signal = SIGNALS[self.next]; + self.next += 1; + Some(next_signal) + } else { + None + } + } +} + +impl Signal { + /// Iterate through all signals defined by this OS + pub const fn iterator() -> SignalIterator { + SignalIterator{next: 0} + } +} + +/// Alias for [`SIGABRT`] +pub const SIGIOT : Signal = SIGABRT; +/// Alias for [`SIGIO`] +#[cfg(not(target_os = "haiku"))] +pub const SIGPOLL : Signal = SIGIO; +/// Alias for [`SIGSYS`] +pub const SIGUNUSED : Signal = SIGSYS; + +cfg_if! { + if #[cfg(target_os = "redox")] { + type SaFlags_t = libc::c_ulong; + } else if #[cfg(target_env = "uclibc")] { + type SaFlags_t = libc::c_ulong; + } else { + type SaFlags_t = libc::c_int; + } +} +} + +#[cfg(feature = "signal")] +libc_bitflags! { + /// Controls the behavior of a [`SigAction`] + #[cfg_attr(docsrs, doc(cfg(feature = "signal")))] + pub struct SaFlags: SaFlags_t { + /// When catching a [`Signal::SIGCHLD`] signal, the signal will be + /// generated only when a child process exits, not when a child process + /// stops. + SA_NOCLDSTOP; + /// When catching a [`Signal::SIGCHLD`] signal, the system will not + /// create zombie processes when children of the calling process exit. + SA_NOCLDWAIT; + /// Further occurrences of the delivered signal are not masked during + /// the execution of the handler. + SA_NODEFER; + /// The system will deliver the signal to the process on a signal stack, + /// specified by each thread with sigaltstack(2). + SA_ONSTACK; + /// The handler is reset back to the default at the moment the signal is + /// delivered. + SA_RESETHAND; + /// Requests that certain system calls restart if interrupted by this + /// signal. See the man page for complete details. + SA_RESTART; + /// This flag is controlled internally by Nix. + SA_SIGINFO; + } +} + +#[cfg(feature = "signal")] +libc_enum! { + /// Specifies how certain functions should manipulate a signal mask + #[repr(i32)] + #[non_exhaustive] + #[cfg_attr(docsrs, doc(cfg(feature = "signal")))] + pub enum SigmaskHow { + /// The new mask is the union of the current mask and the specified set. + SIG_BLOCK, + /// The new mask is the intersection of the current mask and the + /// complement of the specified set. + SIG_UNBLOCK, + /// The current mask is replaced by the specified set. + SIG_SETMASK, + } +} + +feature! { +#![feature = "signal"] + +use crate::unistd::Pid; +use std::iter::Extend; +use std::iter::FromIterator; +use std::iter::IntoIterator; + +/// Specifies a set of [`Signal`]s that may be blocked, waited for, etc. +// We are using `transparent` here to be super sure that `SigSet` +// is represented exactly like the `sigset_t` struct from C. +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct SigSet { + sigset: libc::sigset_t +} + +impl SigSet { + /// Initialize to include all signals. + #[doc(alias("sigfillset"))] + pub fn all() -> SigSet { + let mut sigset = mem::MaybeUninit::uninit(); + let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) }; + + unsafe{ SigSet { sigset: sigset.assume_init() } } + } + + /// Initialize to include nothing. + #[doc(alias("sigemptyset"))] + pub fn empty() -> SigSet { + let mut sigset = mem::MaybeUninit::uninit(); + let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) }; + + unsafe{ SigSet { sigset: sigset.assume_init() } } + } + + /// Add the specified signal to the set. + #[doc(alias("sigaddset"))] + pub fn add(&mut self, signal: Signal) { + unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; + } + + /// Remove all signals from this set. + #[doc(alias("sigemptyset"))] + pub fn clear(&mut self) { + unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) }; + } + + /// Remove the specified signal from this set. + #[doc(alias("sigdelset"))] + pub fn remove(&mut self, signal: Signal) { + unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; + } + + /// Return whether this set includes the specified signal. + #[doc(alias("sigismember"))] + pub fn contains(&self, signal: Signal) -> bool { + let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) }; + + match res { + 1 => true, + 0 => false, + _ => unreachable!("unexpected value from sigismember"), + } + } + + /// Returns an iterator that yields the signals contained in this set. + pub fn iter(&self) -> SigSetIter<'_> { + self.into_iter() + } + + /// Gets the currently blocked (masked) set of signals for the calling thread. + pub fn thread_get_mask() -> Result { + let mut oldmask = mem::MaybeUninit::uninit(); + do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?; + Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}}) + } + + /// Sets the set of signals as the signal mask for the calling thread. + pub fn thread_set_mask(&self) -> Result<()> { + pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None) + } + + /// Adds the set of signals to the signal mask for the calling thread. + pub fn thread_block(&self) -> Result<()> { + pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None) + } + + /// Removes the set of signals from the signal mask for the calling thread. + pub fn thread_unblock(&self) -> Result<()> { + pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None) + } + + /// Sets the set of signals as the signal mask, and returns the old mask. + pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result { + let mut oldmask = mem::MaybeUninit::uninit(); + do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?; + Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}}) + } + + /// Suspends execution of the calling thread until one of the signals in the + /// signal mask becomes pending, and returns the accepted signal. + #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn wait(&self) -> Result { + use std::convert::TryFrom; + + let mut signum = mem::MaybeUninit::uninit(); + let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) }; + + Errno::result(res).map(|_| unsafe { + Signal::try_from(signum.assume_init()).unwrap() + }) + } + + /// Converts a `libc::sigset_t` object to a [`SigSet`] without checking whether the + /// `libc::sigset_t` is already initialized. + /// + /// # Safety + /// + /// The `sigset` passed in must be a valid an initialized `libc::sigset_t` by calling either + /// [`sigemptyset(3)`](https://man7.org/linux/man-pages/man3/sigemptyset.3p.html) or + /// [`sigfillset(3)`](https://man7.org/linux/man-pages/man3/sigfillset.3p.html). + /// Otherwise, the results are undefined. + pub unsafe fn from_sigset_t_unchecked(sigset: libc::sigset_t) -> SigSet { + SigSet { sigset } + } +} + +impl AsRef for SigSet { + fn as_ref(&self) -> &libc::sigset_t { + &self.sigset + } +} + +// TODO: Consider specialization for the case where T is &SigSet and libc::sigorset is available. +impl Extend for SigSet { + fn extend(&mut self, iter: T) + where T: IntoIterator { + for signal in iter { + self.add(signal); + } + } +} + +impl FromIterator for SigSet { + fn from_iter(iter: T) -> Self + where T: IntoIterator { + let mut sigset = SigSet::empty(); + sigset.extend(iter); + sigset + } +} + +/// Iterator for a [`SigSet`]. +/// +/// Call [`SigSet::iter`] to create an iterator. +#[derive(Clone, Debug)] +pub struct SigSetIter<'a> { + sigset: &'a SigSet, + inner: SignalIterator, +} + +impl Iterator for SigSetIter<'_> { + type Item = Signal; + fn next(&mut self) -> Option { + loop { + match self.inner.next() { + None => return None, + Some(signal) if self.sigset.contains(signal) => return Some(signal), + Some(_signal) => continue, + } + } + } +} + +impl<'a> IntoIterator for &'a SigSet { + type Item = Signal; + type IntoIter = SigSetIter<'a>; + fn into_iter(self) -> Self::IntoIter { + SigSetIter { sigset: self, inner: Signal::iterator() } + } +} + +/// A signal handler. +#[allow(unknown_lints)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum SigHandler { + /// Default signal handling. + SigDfl, + /// Request that the signal be ignored. + SigIgn, + /// Use the given signal-catching function, which takes in the signal. + Handler(extern fn(libc::c_int)), + /// Use the given signal-catching function, which takes in the signal, information about how + /// the signal was generated, and a pointer to the threads `ucontext_t`. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)) +} + +/// Action to take on receipt of a signal. Corresponds to `sigaction`. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct SigAction { + sigaction: libc::sigaction +} + +impl SigAction { + /// Creates a new action. + /// + /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler` + /// is the `SigAction` variant). `mask` specifies other signals to block during execution of + /// the signal-catching function. + pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction { + unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) { + (*p).sa_sigaction = match handler { + SigHandler::SigDfl => libc::SIG_DFL, + SigHandler::SigIgn => libc::SIG_IGN, + SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize, + #[cfg(not(target_os = "redox"))] + SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize, + }; + } + + let mut s = mem::MaybeUninit::::uninit(); + unsafe { + let p = s.as_mut_ptr(); + install_sig(p, handler); + (*p).sa_flags = match handler { + #[cfg(not(target_os = "redox"))] + SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(), + _ => (flags - SaFlags::SA_SIGINFO).bits(), + }; + (*p).sa_mask = mask.sigset; + + SigAction { sigaction: s.assume_init() } + } + } + + /// Returns the flags set on the action. + pub fn flags(&self) -> SaFlags { + SaFlags::from_bits_truncate(self.sigaction.sa_flags) + } + + /// Returns the set of signals that are blocked during execution of the action's + /// signal-catching function. + pub fn mask(&self) -> SigSet { + SigSet { sigset: self.sigaction.sa_mask } + } + + /// Returns the action's handler. + pub fn handler(&self) -> SigHandler { + match self.sigaction.sa_sigaction { + libc::SIG_DFL => SigHandler::SigDfl, + libc::SIG_IGN => SigHandler::SigIgn, + #[cfg(not(target_os = "redox"))] + p if self.flags().contains(SaFlags::SA_SIGINFO) => + SigHandler::SigAction( + // Safe for one of two reasons: + // * The SigHandler was created by SigHandler::new, in which + // case the pointer is correct, or + // * The SigHandler was created by signal or sigaction, which + // are unsafe functions, so the caller should've somehow + // ensured that it is correctly initialized. + unsafe{ + *(&p as *const usize + as *const extern fn(_, _, _)) + } + as extern fn(_, _, _)), + p => SigHandler::Handler( + // Safe for one of two reasons: + // * The SigHandler was created by SigHandler::new, in which + // case the pointer is correct, or + // * The SigHandler was created by signal or sigaction, which + // are unsafe functions, so the caller should've somehow + // ensured that it is correctly initialized. + unsafe{ + *(&p as *const usize + as *const extern fn(libc::c_int)) + } + as extern fn(libc::c_int)), + } + } +} + +/// Changes the action taken by a process on receipt of a specific signal. +/// +/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous +/// action for the given signal. If `sigaction` fails, no new signal handler is installed. +/// +/// # Safety +/// +/// * Signal handlers may be called at any point during execution, which limits +/// what is safe to do in the body of the signal-catching function. Be certain +/// to only make syscalls that are explicitly marked safe for signal handlers +/// and only share global data using atomics. +/// +/// * There is also no guarantee that the old signal handler was installed +/// correctly. If it was installed by this crate, it will be. But if it was +/// installed by, for example, C code, then there is no guarantee its function +/// pointer is valid. In that case, this function effectively dereferences a +/// raw pointer of unknown provenance. +pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result { + let mut oldact = mem::MaybeUninit::::uninit(); + + let res = libc::sigaction(signal as libc::c_int, + &sigaction.sigaction as *const libc::sigaction, + oldact.as_mut_ptr()); + + Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() }) +} + +/// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html)) +/// +/// Installs `handler` for the given `signal`, returning the previous signal +/// handler. `signal` should only be used following another call to `signal` or +/// if the current handler is the default. The return value of `signal` is +/// undefined after setting the handler with [`sigaction`][SigActionFn]. +/// +/// # Safety +/// +/// If the pointer to the previous signal handler is invalid, undefined +/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct]. +/// +/// # Examples +/// +/// Ignore `SIGINT`: +/// +/// ```no_run +/// # use nix::sys::signal::{self, Signal, SigHandler}; +/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); +/// ``` +/// +/// Use a signal handler to set a flag variable: +/// +/// ```no_run +/// # #[macro_use] extern crate lazy_static; +/// # use std::convert::TryFrom; +/// # use std::sync::atomic::{AtomicBool, Ordering}; +/// # use nix::sys::signal::{self, Signal, SigHandler}; +/// lazy_static! { +/// static ref SIGNALED: AtomicBool = AtomicBool::new(false); +/// } +/// +/// extern fn handle_sigint(signal: libc::c_int) { +/// let signal = Signal::try_from(signal).unwrap(); +/// SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); +/// } +/// +/// fn main() { +/// let handler = SigHandler::Handler(handle_sigint); +/// unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap(); +/// } +/// ``` +/// +/// # Errors +/// +/// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is +/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead. +/// +/// `signal` also returns any error from `libc::signal`, such as when an attempt +/// is made to catch a signal that cannot be caught or to ignore a signal that +/// cannot be ignored. +/// +/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation +/// [SigActionStruct]: struct.SigAction.html +/// [sigactionFn]: fn.sigaction.html +pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result { + let signal = signal as libc::c_int; + let res = match handler { + SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL), + SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN), + SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t), + #[cfg(not(target_os = "redox"))] + SigHandler::SigAction(_) => return Err(Errno::ENOTSUP), + }; + Errno::result(res).map(|oldhandler| { + match oldhandler { + libc::SIG_DFL => SigHandler::SigDfl, + libc::SIG_IGN => SigHandler::SigIgn, + p => SigHandler::Handler( + *(&p as *const usize + as *const extern fn(libc::c_int)) + as extern fn(libc::c_int)), + } + }) +} + +fn do_pthread_sigmask(how: SigmaskHow, + set: Option<&SigSet>, + oldset: Option<*mut libc::sigset_t>) -> Result<()> { + if set.is_none() && oldset.is_none() { + return Ok(()) + } + + let res = unsafe { + // if set or oldset is None, pass in null pointers instead + libc::pthread_sigmask(how as libc::c_int, + set.map_or_else(ptr::null::, + |s| &s.sigset as *const libc::sigset_t), + oldset.unwrap_or(ptr::null_mut()) + ) + }; + + Errno::result(res).map(drop) +} + +/// Manages the signal mask (set of blocked signals) for the calling thread. +/// +/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set. +/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored, +/// and no modification will take place. +/// +/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it. +/// +/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset, +/// and then it will be updated with `set`. +/// +/// If both `set` and `oldset` is None, this function is a no-op. +/// +/// For more information, visit the [`pthread_sigmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html), +/// or [`sigprocmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages. +pub fn pthread_sigmask(how: SigmaskHow, + set: Option<&SigSet>, + oldset: Option<&mut SigSet>) -> Result<()> +{ + do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ )) +} + +/// Examine and change blocked signals. +/// +/// For more information see the [`sigprocmask` man +/// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html). +pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> { + if set.is_none() && oldset.is_none() { + return Ok(()) + } + + let res = unsafe { + // if set or oldset is None, pass in null pointers instead + libc::sigprocmask(how as libc::c_int, + set.map_or_else(ptr::null::, + |s| &s.sigset as *const libc::sigset_t), + oldset.map_or_else(ptr::null_mut::, + |os| &mut os.sigset as *mut libc::sigset_t)) + }; + + Errno::result(res).map(drop) +} + +/// Send a signal to a process +/// +/// # Arguments +/// +/// * `pid` - Specifies which processes should receive the signal. +/// - If positive, specifies an individual process. +/// - If zero, the signal will be sent to all processes whose group +/// ID is equal to the process group ID of the sender. This is a +#[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")] +#[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")] +/// - If `-1` and the process has super-user privileges, the signal +/// is sent to all processes exclusing system processes. +/// - If less than `-1`, the signal is sent to all processes whose +/// process group ID is equal to the absolute value of `pid`. +/// * `signal` - Signal to send. If `None`, error checking is performed +/// but no signal is actually sent. +/// +/// See Also +/// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html) +pub fn kill>>(pid: Pid, signal: T) -> Result<()> { + let res = unsafe { libc::kill(pid.into(), + match signal.into() { + Some(s) => s as libc::c_int, + None => 0, + }) }; + + Errno::result(res).map(drop) +} + +/// Send a signal to a process group +/// +/// # Arguments +/// +/// * `pgrp` - Process group to signal. If less then or equal 1, the behavior +/// is platform-specific. +/// * `signal` - Signal to send. If `None`, `killpg` will only preform error +/// checking and won't send any signal. +/// +/// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html). +#[cfg(not(target_os = "fuchsia"))] +pub fn killpg>>(pgrp: Pid, signal: T) -> Result<()> { + let res = unsafe { libc::killpg(pgrp.into(), + match signal.into() { + Some(s) => s as libc::c_int, + None => 0, + }) }; + + Errno::result(res).map(drop) +} + +/// Send a signal to the current thread +/// +/// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html) +pub fn raise(signal: Signal) -> Result<()> { + let res = unsafe { libc::raise(signal as libc::c_int) }; + + Errno::result(res).map(drop) +} +} + +feature! { +#![any(feature = "aio", feature = "signal")] + +/// Identifies a thread for [`SigevNotify::SigevThreadId`] +#[cfg(target_os = "freebsd")] +pub type type_of_thread_id = libc::lwpid_t; +/// Identifies a thread for [`SigevNotify::SigevThreadId`] +#[cfg(target_os = "linux")] +pub type type_of_thread_id = libc::pid_t; + +/// Specifies the notification method used by a [`SigEvent`] +// sigval is actually a union of a int and a void*. But it's never really used +// as a pointer, because neither libc nor the kernel ever dereference it. nix +// therefore presents it as an intptr_t, which is how kevent uses it. +#[cfg(not(any(target_os = "openbsd", target_os = "redox")))] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum SigevNotify { + /// No notification will be delivered + SigevNone, + /// Notify by delivering a signal to the process. + SigevSignal { + /// Signal to deliver + signal: Signal, + /// Will be present in the `si_value` field of the [`libc::siginfo_t`] + /// structure of the queued signal. + si_value: libc::intptr_t + }, + // Note: SIGEV_THREAD is not implemented because libc::sigevent does not + // expose a way to set the union members needed by SIGEV_THREAD. + /// Notify by delivering an event to a kqueue. + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + SigevKevent { + /// File descriptor of the kqueue to notify. + kq: RawFd, + /// Will be contained in the kevent's `udata` field. + udata: libc::intptr_t + }, + /// Notify by delivering a signal to a thread. + #[cfg(any(target_os = "freebsd", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + SigevThreadId { + /// Signal to send + signal: Signal, + /// LWP ID of the thread to notify + thread_id: type_of_thread_id, + /// Will be present in the `si_value` field of the [`libc::siginfo_t`] + /// structure of the queued signal. + si_value: libc::intptr_t + }, +} +} + +#[cfg(not(any(target_os = "openbsd", target_os = "redox")))] +#[cfg_attr(docsrs, doc(cfg(all())))] +mod sigevent { + feature! { + #![any(feature = "aio", feature = "signal")] + + use std::mem; + use std::ptr; + use super::SigevNotify; + #[cfg(any(target_os = "freebsd", target_os = "linux"))] + use super::type_of_thread_id; + + /// Used to request asynchronous notification of the completion of certain + /// events, such as POSIX AIO and timers. + #[repr(C)] + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + pub struct SigEvent { + sigevent: libc::sigevent + } + + impl SigEvent { + /// **Note:** this constructor does not allow the user to set the + /// `sigev_notify_kevent_flags` field. That's considered ok because on FreeBSD + /// at least those flags don't do anything useful. That field is part of a + /// union that shares space with the more genuinely useful fields. + /// + /// **Note:** This constructor also doesn't allow the caller to set the + /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are + /// required for `SIGEV_THREAD`. That's considered ok because on no operating + /// system is `SIGEV_THREAD` the most efficient way to deliver AIO + /// notification. FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`. + /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or + /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the + /// more genuinely useful `sigev_notify_thread_id` + // Allow invalid_value warning on Fuchsia only. + // See https://github.com/nix-rust/nix/issues/1441 + #[cfg_attr(target_os = "fuchsia", allow(invalid_value))] + pub fn new(sigev_notify: SigevNotify) -> SigEvent { + let mut sev = unsafe { mem::MaybeUninit::::zeroed().assume_init() }; + sev.sigev_notify = match sigev_notify { + SigevNotify::SigevNone => libc::SIGEV_NONE, + SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL, + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT, + #[cfg(target_os = "freebsd")] + SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, + #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))] + SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, + #[cfg(all(target_os = "linux", target_env = "uclibc"))] + SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, + #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))] + SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined + }; + sev.sigev_signo = match sigev_notify { + SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int, + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + SigevNotify::SigevKevent{ kq, ..} => kq, + #[cfg(any(target_os = "linux", target_os = "freebsd"))] + SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int, + _ => 0 + }; + sev.sigev_value.sival_ptr = match sigev_notify { + SigevNotify::SigevNone => ptr::null_mut::(), + SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void, + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void, + #[cfg(any(target_os = "freebsd", target_os = "linux"))] + SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void, + }; + SigEvent::set_tid(&mut sev, &sigev_notify); + SigEvent{sigevent: sev} + } + + #[cfg(any(target_os = "freebsd", target_os = "linux"))] + fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) { + sev.sigev_notify_thread_id = match *sigev_notify { + SigevNotify::SigevThreadId { thread_id, .. } => thread_id, + _ => 0 as type_of_thread_id + }; + } + + #[cfg(not(any(target_os = "freebsd", target_os = "linux")))] + fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) { + } + + /// Return a copy of the inner structure + pub fn sigevent(&self) -> libc::sigevent { + self.sigevent + } + + /// Returns a mutable pointer to the `sigevent` wrapped by `self` + pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent { + &mut self.sigevent + } + } + + impl<'a> From<&'a libc::sigevent> for SigEvent { + fn from(sigevent: &libc::sigevent) -> Self { + SigEvent{ sigevent: *sigevent } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[cfg(not(target_os = "redox"))] + use std::thread; + + #[test] + fn test_contains() { + let mut mask = SigSet::empty(); + mask.add(SIGUSR1); + + assert!(mask.contains(SIGUSR1)); + assert!(!mask.contains(SIGUSR2)); + + let all = SigSet::all(); + assert!(all.contains(SIGUSR1)); + assert!(all.contains(SIGUSR2)); + } + + #[test] + fn test_clear() { + let mut set = SigSet::all(); + set.clear(); + for signal in Signal::iterator() { + assert!(!set.contains(signal)); + } + } + + #[test] + fn test_from_str_round_trips() { + for signal in Signal::iterator() { + assert_eq!(signal.as_ref().parse::().unwrap(), signal); + assert_eq!(signal.to_string().parse::().unwrap(), signal); + } + } + + #[test] + fn test_from_str_invalid_value() { + let errval = Err(Errno::EINVAL); + assert_eq!("NOSIGNAL".parse::(), errval); + assert_eq!("kill".parse::(), errval); + assert_eq!("9".parse::(), errval); + } + + #[test] + fn test_extend() { + let mut one_signal = SigSet::empty(); + one_signal.add(SIGUSR1); + + let mut two_signals = SigSet::empty(); + two_signals.add(SIGUSR2); + two_signals.extend(&one_signal); + + assert!(two_signals.contains(SIGUSR1)); + assert!(two_signals.contains(SIGUSR2)); + } + + #[test] + #[cfg(not(target_os = "redox"))] + fn test_thread_signal_set_mask() { + thread::spawn(|| { + let prev_mask = SigSet::thread_get_mask() + .expect("Failed to get existing signal mask!"); + + let mut test_mask = prev_mask; + test_mask.add(SIGUSR1); + + test_mask.thread_set_mask().expect("assertion failed"); + let new_mask = + SigSet::thread_get_mask().expect("Failed to get new mask!"); + + assert!(new_mask.contains(SIGUSR1)); + assert!(!new_mask.contains(SIGUSR2)); + + prev_mask + .thread_set_mask() + .expect("Failed to revert signal mask!"); + }) + .join() + .unwrap(); + } + + #[test] + #[cfg(not(target_os = "redox"))] + fn test_thread_signal_block() { + thread::spawn(|| { + let mut mask = SigSet::empty(); + mask.add(SIGUSR1); + + mask.thread_block().expect("assertion failed"); + + assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); + }) + .join() + .unwrap(); + } + + #[test] + #[cfg(not(target_os = "redox"))] + fn test_thread_signal_unblock() { + thread::spawn(|| { + let mut mask = SigSet::empty(); + mask.add(SIGUSR1); + + mask.thread_unblock().expect("assertion failed"); + + assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); + }) + .join() + .unwrap(); + } + + #[test] + #[cfg(not(target_os = "redox"))] + fn test_thread_signal_swap() { + thread::spawn(|| { + let mut mask = SigSet::empty(); + mask.add(SIGUSR1); + mask.thread_block().unwrap(); + + assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); + + let mut mask2 = SigSet::empty(); + mask2.add(SIGUSR2); + + let oldmask = + mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap(); + + assert!(oldmask.contains(SIGUSR1)); + assert!(!oldmask.contains(SIGUSR2)); + + assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2)); + }) + .join() + .unwrap(); + } + + #[test] + fn test_from_and_into_iterator() { + let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]); + let signals = sigset.into_iter().collect::>(); + assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]); + } + + #[test] + #[cfg(not(target_os = "redox"))] + fn test_sigaction() { + thread::spawn(|| { + extern "C" fn test_sigaction_handler(_: libc::c_int) {} + extern "C" fn test_sigaction_action( + _: libc::c_int, + _: *mut libc::siginfo_t, + _: *mut libc::c_void, + ) { + } + + let handler_sig = SigHandler::Handler(test_sigaction_handler); + + let flags = + SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO; + + let mut mask = SigSet::empty(); + mask.add(SIGUSR1); + + let action_sig = SigAction::new(handler_sig, flags, mask); + + assert_eq!( + action_sig.flags(), + SaFlags::SA_ONSTACK | SaFlags::SA_RESTART + ); + assert_eq!(action_sig.handler(), handler_sig); + + mask = action_sig.mask(); + assert!(mask.contains(SIGUSR1)); + assert!(!mask.contains(SIGUSR2)); + + let handler_act = SigHandler::SigAction(test_sigaction_action); + let action_act = SigAction::new(handler_act, flags, mask); + assert_eq!(action_act.handler(), handler_act); + + let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask); + assert_eq!(action_dfl.handler(), SigHandler::SigDfl); + + let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask); + assert_eq!(action_ign.handler(), SigHandler::SigIgn); + }) + .join() + .unwrap(); + } + + #[test] + #[cfg(not(target_os = "redox"))] + fn test_sigwait() { + thread::spawn(|| { + let mut mask = SigSet::empty(); + mask.add(SIGUSR1); + mask.add(SIGUSR2); + mask.thread_block().unwrap(); + + raise(SIGUSR1).unwrap(); + assert_eq!(mask.wait().unwrap(), SIGUSR1); + }) + .join() + .unwrap(); + } + + #[test] + fn test_from_sigset_t_unchecked() { + let src_set = SigSet::empty(); + let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) }; + + for signal in Signal::iterator() { + assert!(!set.contains(signal)); + } + + let src_set = SigSet::all(); + let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) }; + + for signal in Signal::iterator() { + assert!(set.contains(signal)); + } + } +} diff --git a/vendor/nix-0.26.2/src/sys/signalfd.rs b/vendor/nix-0.26.2/src/sys/signalfd.rs new file mode 100644 index 0000000000000..095e590850828 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/signalfd.rs @@ -0,0 +1,175 @@ +//! Interface for the `signalfd` syscall. +//! +//! # Signal discarding +//! When a signal can't be delivered to a process (or thread), it will become a pending signal. +//! Failure to deliver could happen if the signal is blocked by every thread in the process or if +//! the signal handler is still handling a previous signal. +//! +//! If a signal is sent to a process (or thread) that already has a pending signal of the same +//! type, it will be discarded. This means that if signals of the same type are received faster than +//! they are processed, some of those signals will be dropped. Because of this limitation, +//! `signalfd` in itself cannot be used for reliable communication between processes or threads. +//! +//! Once the signal is unblocked, or the signal handler is finished, and a signal is still pending +//! (ie. not consumed from a signalfd) it will be delivered to the signal handler. +//! +//! Please note that signal discarding is not specific to `signalfd`, but also happens with regular +//! signal handlers. +use crate::errno::Errno; +pub use crate::sys::signal::{self, SigSet}; +use crate::unistd; +use crate::Result; +pub use libc::signalfd_siginfo as siginfo; + +use std::mem; +use std::os::unix::io::{AsRawFd, RawFd}; + +libc_bitflags! { + pub struct SfdFlags: libc::c_int { + SFD_NONBLOCK; + SFD_CLOEXEC; + } +} + +pub const SIGNALFD_NEW: RawFd = -1; +#[deprecated(since = "0.23.0", note = "use mem::size_of::() instead")] +pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::(); + +/// Creates a new file descriptor for reading signals. +/// +/// **Important:** please read the module level documentation about signal discarding before using +/// this function! +/// +/// The `mask` parameter specifies the set of signals that can be accepted via this file descriptor. +/// +/// A signal must be blocked on every thread in a process, otherwise it won't be visible from +/// signalfd (the default handler will be invoked instead). +/// +/// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html) +pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result { + unsafe { + Errno::result(libc::signalfd( + fd as libc::c_int, + mask.as_ref(), + flags.bits(), + )) + } +} + +/// A helper struct for creating, reading and closing a `signalfd` instance. +/// +/// **Important:** please read the module level documentation about signal discarding before using +/// this struct! +/// +/// # Examples +/// +/// ``` +/// # use nix::sys::signalfd::*; +/// // Set the thread to block the SIGUSR1 signal, otherwise the default handler will be used +/// let mut mask = SigSet::empty(); +/// mask.add(signal::SIGUSR1); +/// mask.thread_block().unwrap(); +/// +/// // Signals are queued up on the file descriptor +/// let mut sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); +/// +/// match sfd.read_signal() { +/// // we caught a signal +/// Ok(Some(sig)) => (), +/// // there were no signals waiting (only happens when the SFD_NONBLOCK flag is set, +/// // otherwise the read_signal call blocks) +/// Ok(None) => (), +/// Err(err) => (), // some error happend +/// } +/// ``` +#[derive(Debug, Eq, Hash, PartialEq)] +pub struct SignalFd(RawFd); + +impl SignalFd { + pub fn new(mask: &SigSet) -> Result { + Self::with_flags(mask, SfdFlags::empty()) + } + + pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result { + let fd = signalfd(SIGNALFD_NEW, mask, flags)?; + + Ok(SignalFd(fd)) + } + + pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> { + signalfd(self.0, mask, SfdFlags::empty()).map(drop) + } + + pub fn read_signal(&mut self) -> Result> { + let mut buffer = mem::MaybeUninit::::uninit(); + + let size = mem::size_of_val(&buffer); + let res = Errno::result(unsafe { + libc::read(self.0, buffer.as_mut_ptr() as *mut libc::c_void, size) + }) + .map(|r| r as usize); + match res { + Ok(x) if x == size => Ok(Some(unsafe { buffer.assume_init() })), + Ok(_) => unreachable!("partial read on signalfd"), + Err(Errno::EAGAIN) => Ok(None), + Err(error) => Err(error), + } + } +} + +impl Drop for SignalFd { + fn drop(&mut self) { + let e = unistd::close(self.0); + if !std::thread::panicking() && e == Err(Errno::EBADF) { + panic!("Closing an invalid file descriptor!"); + }; + } +} + +impl AsRawFd for SignalFd { + fn as_raw_fd(&self) -> RawFd { + self.0 + } +} + +impl Iterator for SignalFd { + type Item = siginfo; + + fn next(&mut self) -> Option { + match self.read_signal() { + Ok(Some(sig)) => Some(sig), + Ok(None) | Err(_) => None, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn create_signalfd() { + let mask = SigSet::empty(); + SignalFd::new(&mask).unwrap(); + } + + #[test] + fn create_signalfd_with_opts() { + let mask = SigSet::empty(); + SignalFd::with_flags( + &mask, + SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK, + ) + .unwrap(); + } + + #[test] + fn read_empty_signalfd() { + let mask = SigSet::empty(); + let mut fd = + SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); + + let res = fd.read_signal(); + assert!(res.unwrap().is_none()); + } +} diff --git a/vendor/nix-0.26.2/src/sys/socket/addr.rs b/vendor/nix-0.26.2/src/sys/socket/addr.rs new file mode 100644 index 0000000000000..4e565a5b6854b --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/socket/addr.rs @@ -0,0 +1,3247 @@ +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "haiku", + target_os = "fuchsia" +))] +#[cfg(feature = "net")] +pub use self::datalink::LinkAddr; +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use self::vsock::VsockAddr; +use super::sa_family_t; +use crate::errno::Errno; +#[cfg(any(target_os = "android", target_os = "linux"))] +use crate::sys::socket::addr::alg::AlgAddr; +#[cfg(any(target_os = "android", target_os = "linux"))] +use crate::sys::socket::addr::netlink::NetlinkAddr; +#[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") +))] +use crate::sys::socket::addr::sys_control::SysControlAddr; +use crate::{NixPath, Result}; +use cfg_if::cfg_if; +use memoffset::offset_of; +use std::convert::TryInto; +use std::ffi::OsStr; +use std::hash::{Hash, Hasher}; +use std::os::unix::ffi::OsStrExt; +#[cfg(any(target_os = "ios", target_os = "macos"))] +use std::os::unix::io::RawFd; +use std::path::Path; +use std::{fmt, mem, net, ptr, slice}; + +/// Convert a std::net::Ipv4Addr into the libc form. +#[cfg(feature = "net")] +pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { + static_assertions::assert_eq_size!(net::Ipv4Addr, libc::in_addr); + // Safe because both types have the same memory layout, and no fancy Drop + // impls. + unsafe { + mem::transmute(addr) + } +} + +/// Convert a std::net::Ipv6Addr into the libc form. +#[cfg(feature = "net")] +pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr { + static_assertions::assert_eq_size!(net::Ipv6Addr, libc::in6_addr); + // Safe because both are Newtype wrappers around the same libc type + unsafe { + mem::transmute(*addr) + } +} + +/// These constants specify the protocol family to be used +/// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) +/// +/// # References +/// +/// [address_families(7)](https://man7.org/linux/man-pages/man7/address_families.7.html) +// Should this be u8? +#[repr(i32)] +#[non_exhaustive] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +pub enum AddressFamily { + /// Local communication (see [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html)) + Unix = libc::AF_UNIX, + /// IPv4 Internet protocols (see [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html)) + Inet = libc::AF_INET, + /// IPv6 Internet protocols (see [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html)) + Inet6 = libc::AF_INET6, + /// Kernel user interface device (see [`netlink(7)`](https://man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Netlink = libc::AF_NETLINK, + /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html)) + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "illumos", + target_os = "fuchsia", + target_os = "solaris" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Packet = libc::AF_PACKET, + /// KEXT Controls and Notifications + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + System = libc::AF_SYSTEM, + /// Amateur radio AX.25 protocol + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Ax25 = libc::AF_AX25, + /// IPX - Novell protocols + Ipx = libc::AF_IPX, + /// AppleTalk + AppleTalk = libc::AF_APPLETALK, + /// AX.25 packet layer protocol. + /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetRom = libc::AF_NETROM, + /// Can't be used for creating sockets; mostly used for bridge + /// links in + /// [rtnetlink(7)](https://man7.org/linux/man-pages/man7/rtnetlink.7.html) + /// protocol commands. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Bridge = libc::AF_BRIDGE, + /// Access to raw ATM PVCs + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + AtmPvc = libc::AF_ATMPVC, + /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](https://man7.org/linux/man-pages/man7/x25.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + X25 = libc::AF_X25, + /// RATS (Radio Amateur Telecommunications Society) Open + /// Systems environment (ROSE) AX.25 packet layer protocol. + /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Rose = libc::AF_ROSE, + /// DECet protocol sockets. + #[cfg(not(target_os = "haiku"))] + Decnet = libc::AF_DECnet, + /// Reserved for "802.2LLC project"; never used. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetBeui = libc::AF_NETBEUI, + /// This was a short-lived (between Linux 2.1.30 and + /// 2.1.99pre2) protocol family for firewall upcalls. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Security = libc::AF_SECURITY, + /// Key management protocol. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Key = libc::AF_KEY, + #[allow(missing_docs)] // Not documented anywhere that I can find + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Ash = libc::AF_ASH, + /// Acorn Econet protocol + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Econet = libc::AF_ECONET, + /// Access to ATM Switched Virtual Circuits + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + AtmSvc = libc::AF_ATMSVC, + /// Reliable Datagram Sockets (RDS) protocol + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Rds = libc::AF_RDS, + /// IBM SNA + #[cfg(not(target_os = "haiku"))] + Sna = libc::AF_SNA, + /// Socket interface over IrDA + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Irda = libc::AF_IRDA, + /// Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Pppox = libc::AF_PPPOX, + /// Legacy protocol for wide area network (WAN) connectivity that was used + /// by Sangoma WAN cards + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Wanpipe = libc::AF_WANPIPE, + /// Logical link control (IEEE 802.2 LLC) protocol + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Llc = libc::AF_LLC, + /// InfiniBand native addressing + #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Ib = libc::AF_IB, + /// Multiprotocol Label Switching + #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Mpls = libc::AF_MPLS, + /// Controller Area Network automotive bus protocol + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Can = libc::AF_CAN, + /// TIPC, "cluster domain sockets" protocol + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Tipc = libc::AF_TIPC, + /// Bluetooth low-level socket protocol + #[cfg(not(any( + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "solaris" + )))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Bluetooth = libc::AF_BLUETOOTH, + /// IUCV (inter-user communication vehicle) z/VM protocol for + /// hypervisor-guest interaction + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Iucv = libc::AF_IUCV, + /// Rx, Andrew File System remote procedure call protocol + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + RxRpc = libc::AF_RXRPC, + /// New "modular ISDN" driver interface protocol + #[cfg(not(any( + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" + )))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Isdn = libc::AF_ISDN, + /// Nokia cellular modem IPC/RPC interface + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Phonet = libc::AF_PHONET, + /// IEEE 802.15.4 WPAN (wireless personal area network) raw packet protocol + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Ieee802154 = libc::AF_IEEE802154, + /// Ericsson's Communication CPU to Application CPU interface (CAIF) + /// protocol. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Caif = libc::AF_CAIF, + /// Interface to kernel crypto API + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Alg = libc::AF_ALG, + /// Near field communication + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + Nfc = libc::AF_NFC, + /// VMWare VSockets protocol for hypervisor-guest interaction. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Vsock = libc::AF_VSOCK, + /// ARPANet IMP addresses + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ImpLink = libc::AF_IMPLINK, + /// PUP protocols, e.g. BSP + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Pup = libc::AF_PUP, + /// MIT CHAOS protocols + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Chaos = libc::AF_CHAOS, + /// Novell and Xerox protocol + #[cfg(any( + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Ns = libc::AF_NS, + #[allow(missing_docs)] // Not documented anywhere that I can find + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Iso = libc::AF_ISO, + /// Bell Labs virtual circuit switch ? + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Datakit = libc::AF_DATAKIT, + /// CCITT protocols, X.25 etc + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Ccitt = libc::AF_CCITT, + /// DEC Direct data link interface + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Dli = libc::AF_DLI, + #[allow(missing_docs)] // Not documented anywhere that I can find + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Lat = libc::AF_LAT, + /// NSC Hyperchannel + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Hylink = libc::AF_HYLINK, + /// Link layer interface + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Link = libc::AF_LINK, + /// connection-oriented IP, aka ST II + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Coip = libc::AF_COIP, + /// Computer Network Technology + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Cnt = libc::AF_CNT, + /// Native ATM access + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Natm = libc::AF_NATM, + /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Unspec = libc::AF_UNSPEC, +} + +impl AddressFamily { + /// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from + /// the `sa_family` field of a `sockaddr`. + /// + /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet + /// and System. Returns None for unsupported or unknown address families. + pub const fn from_i32(family: i32) -> Option { + match family { + libc::AF_UNIX => Some(AddressFamily::Unix), + libc::AF_INET => Some(AddressFamily::Inet), + libc::AF_INET6 => Some(AddressFamily::Inet6), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_NETLINK => Some(AddressFamily::Netlink), + #[cfg(any(target_os = "macos", target_os = "macos"))] + libc::AF_SYSTEM => Some(AddressFamily::System), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_PACKET => Some(AddressFamily::Packet), + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd" + ))] + libc::AF_LINK => Some(AddressFamily::Link), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_VSOCK => Some(AddressFamily::Vsock), + _ => None, + } + } +} + +feature! { +#![feature = "net"] + +#[deprecated( + since = "0.24.0", + note = "use SockaddrIn, SockaddrIn6, or SockaddrStorage instead" +)] +#[allow(missing_docs)] // Since they're all deprecated anyway +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum InetAddr { + V4(libc::sockaddr_in), + V6(libc::sockaddr_in6), +} + +#[allow(missing_docs)] // It's deprecated anyway +#[allow(deprecated)] +impl InetAddr { + #[allow(clippy::needless_update)] // It isn't needless on all OSes + pub fn from_std(std: &net::SocketAddr) -> InetAddr { + match *std { + net::SocketAddr::V4(ref addr) => { + InetAddr::V4(libc::sockaddr_in { + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "haiku", target_os = "hermit", + target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd"))] + sin_len: mem::size_of::() as u8, + sin_family: AddressFamily::Inet as sa_family_t, + sin_port: addr.port().to_be(), // network byte order + sin_addr: Ipv4Addr::from_std(addr.ip()).0, + .. unsafe { mem::zeroed() } + }) + } + net::SocketAddr::V6(ref addr) => { + InetAddr::V6(libc::sockaddr_in6 { + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "haiku", target_os = "hermit", + target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd"))] + sin6_len: mem::size_of::() as u8, + sin6_family: AddressFamily::Inet6 as sa_family_t, + sin6_port: addr.port().to_be(), // network byte order + sin6_addr: Ipv6Addr::from_std(addr.ip()).0, + sin6_flowinfo: addr.flowinfo(), // host byte order + sin6_scope_id: addr.scope_id(), // host byte order + .. unsafe { mem::zeroed() } + }) + } + } + } + + #[allow(clippy::needless_update)] // It isn't needless on all OSes + pub fn new(ip: IpAddr, port: u16) -> InetAddr { + match ip { + IpAddr::V4(ref ip) => { + InetAddr::V4(libc::sockaddr_in { + sin_family: AddressFamily::Inet as sa_family_t, + sin_port: port.to_be(), + sin_addr: ip.0, + .. unsafe { mem::zeroed() } + }) + } + IpAddr::V6(ref ip) => { + InetAddr::V6(libc::sockaddr_in6 { + sin6_family: AddressFamily::Inet6 as sa_family_t, + sin6_port: port.to_be(), + sin6_addr: ip.0, + .. unsafe { mem::zeroed() } + }) + } + } + } + /// Gets the IP address associated with this socket address. + pub const fn ip(&self) -> IpAddr { + match *self { + InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)), + InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)), + } + } + + /// Gets the port number associated with this socket address + pub const fn port(&self) -> u16 { + match *self { + InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port), + InetAddr::V4(ref sa) => u16::from_be(sa.sin_port), + } + } + + pub fn to_std(&self) -> net::SocketAddr { + match *self { + InetAddr::V4(ref sa) => net::SocketAddr::V4( + net::SocketAddrV4::new( + Ipv4Addr(sa.sin_addr).to_std(), + self.port())), + InetAddr::V6(ref sa) => net::SocketAddr::V6( + net::SocketAddrV6::new( + Ipv6Addr(sa.sin6_addr).to_std(), + self.port(), + sa.sin6_flowinfo, + sa.sin6_scope_id)), + } + } + + #[deprecated(since = "0.23.0", note = "use .to_string() instead")] + pub fn to_str(&self) -> String { + format!("{}", self) + } +} + +#[allow(deprecated)] +impl fmt::Display for InetAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()), + InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()), + } + } +} + +/* + * + * ===== IpAddr ===== + * + */ +#[allow(missing_docs)] // Since they're all deprecated anyway +#[allow(deprecated)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[deprecated( + since = "0.24.0", + note = "Use std::net::IpAddr instead" +)] +pub enum IpAddr { + V4(Ipv4Addr), + V6(Ipv6Addr), +} + +#[allow(deprecated)] +#[allow(missing_docs)] // Since they're all deprecated anyway +impl IpAddr { + /// Create a new IpAddr that contains an IPv4 address. + /// + /// The result will represent the IP address a.b.c.d + pub const fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr { + IpAddr::V4(Ipv4Addr::new(a, b, c, d)) + } + + /// Create a new IpAddr that contains an IPv6 address. + /// + /// The result will represent the IP address a:b:c:d:e:f + #[allow(clippy::many_single_char_names)] + #[allow(clippy::too_many_arguments)] + pub const fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr { + IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)) + } + + pub fn from_std(std: &net::IpAddr) -> IpAddr { + match *std { + net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)), + net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)), + } + } + + pub const fn to_std(&self) -> net::IpAddr { + match *self { + IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()), + IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()), + } + } +} + +#[allow(deprecated)] +impl fmt::Display for IpAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + IpAddr::V4(ref v4) => v4.fmt(f), + IpAddr::V6(ref v6) => v6.fmt(f) + } + } +} + +/* + * + * ===== Ipv4Addr ===== + * + */ + +#[deprecated( + since = "0.24.0", + note = "Use std::net::Ipv4Addr instead" +)] +#[allow(missing_docs)] // Since they're all deprecated anyway +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(transparent)] +pub struct Ipv4Addr(pub libc::in_addr); + +#[allow(deprecated)] +#[allow(missing_docs)] // Since they're all deprecated anyway +impl Ipv4Addr { + #[allow(clippy::identity_op)] // More readable this way + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + let ip = (((a as u32) << 24) | + ((b as u32) << 16) | + ((c as u32) << 8) | + ((d as u32) << 0)).to_be(); + + Ipv4Addr(libc::in_addr { s_addr: ip }) + } + + // Use pass by reference for symmetry with Ipv6Addr::from_std + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr { + let bits = std.octets(); + Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) + } + + pub const fn any() -> Ipv4Addr { + Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY }) + } + + pub const fn octets(self) -> [u8; 4] { + let bits = u32::from_be(self.0.s_addr); + [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] + } + + pub const fn to_std(self) -> net::Ipv4Addr { + let bits = self.octets(); + net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) + } +} + +#[allow(deprecated)] +impl fmt::Display for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let octets = self.octets(); + write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) + } +} + +/* + * + * ===== Ipv6Addr ===== + * + */ + +#[deprecated( + since = "0.24.0", + note = "Use std::net::Ipv6Addr instead" +)] +#[allow(missing_docs)] // Since they're all deprecated anyway +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(transparent)] +pub struct Ipv6Addr(pub libc::in6_addr); + +// Note that IPv6 addresses are stored in big endian order on all architectures. +// See https://tools.ietf.org/html/rfc1700 or consult your favorite search +// engine. + +macro_rules! to_u8_array { + ($($num:ident),*) => { + [ $(($num>>8) as u8, ($num&0xff) as u8,)* ] + } +} + +macro_rules! to_u16_array { + ($slf:ident, $($first:expr, $second:expr),*) => { + [$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*] + } +} + +#[allow(deprecated)] +#[allow(missing_docs)] // Since they're all deprecated anyway +impl Ipv6Addr { + #[allow(clippy::many_single_char_names)] + #[allow(clippy::too_many_arguments)] + pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { + Ipv6Addr(libc::in6_addr{s6_addr: to_u8_array!(a,b,c,d,e,f,g,h)}) + } + + pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr { + let s = std.segments(); + Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]) + } + + /// Return the eight 16-bit segments that make up this address + pub const fn segments(&self) -> [u16; 8] { + to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) + } + + pub const fn to_std(&self) -> net::Ipv6Addr { + let s = self.segments(); + net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]) + } +} + +#[allow(deprecated)] +impl fmt::Display for Ipv6Addr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + self.to_std().fmt(fmt) + } +} +} + +/// A wrapper around `sockaddr_un`. +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct UnixAddr { + // INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts + sun: libc::sockaddr_un, + /// The length of the valid part of `sun`, including the sun_family field + /// but excluding any trailing nul. + // On the BSDs, this field is built into sun + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + sun_len: u8, +} + +// linux man page unix(7) says there are 3 kinds of unix socket: +// pathname: addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1 +// unnamed: addrlen = sizeof(sa_family_t) +// abstract: addren > sizeof(sa_family_t), name = sun_path[..(addrlen - sizeof(sa_family_t))] +// +// what we call path_len = addrlen - offsetof(struct sockaddr_un, sun_path) +#[derive(PartialEq, Eq, Hash)] +enum UnixAddrKind<'a> { + Pathname(&'a Path), + Unnamed, + #[cfg(any(target_os = "android", target_os = "linux"))] + Abstract(&'a [u8]), +} +impl<'a> UnixAddrKind<'a> { + /// Safety: sun & sun_len must be valid + unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self { + assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path)); + let path_len = + sun_len as usize - offset_of!(libc::sockaddr_un, sun_path); + if path_len == 0 { + return Self::Unnamed; + } + #[cfg(any(target_os = "android", target_os = "linux"))] + if sun.sun_path[0] == 0 { + let name = slice::from_raw_parts( + sun.sun_path.as_ptr().add(1) as *const u8, + path_len - 1, + ); + return Self::Abstract(name); + } + let pathname = + slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len); + if pathname.last() == Some(&0) { + // A trailing NUL is not considered part of the path, and it does + // not need to be included in the addrlen passed to functions like + // bind(). However, Linux adds a trailing NUL, even if one was not + // originally present, when returning addrs from functions like + // getsockname() (the BSDs do not do that). So we need to filter + // out any trailing NUL here, so sockaddrs can round-trip through + // the kernel and still compare equal. + Self::Pathname(Path::new(OsStr::from_bytes( + &pathname[0..pathname.len() - 1], + ))) + } else { + Self::Pathname(Path::new(OsStr::from_bytes(pathname))) + } + } +} + +impl UnixAddr { + /// Create a new sockaddr_un representing a filesystem path. + pub fn new(path: &P) -> Result { + path.with_nix_path(|cstr| unsafe { + let mut ret = libc::sockaddr_un { + sun_family: AddressFamily::Unix as sa_family_t, + ..mem::zeroed() + }; + + let bytes = cstr.to_bytes(); + + if bytes.len() >= ret.sun_path.len() { + return Err(Errno::ENAMETOOLONG); + } + + let sun_len = (bytes.len() + + offset_of!(libc::sockaddr_un, sun_path)) + .try_into() + .unwrap(); + + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + { + ret.sun_len = sun_len; + } + ptr::copy_nonoverlapping( + bytes.as_ptr(), + ret.sun_path.as_mut_ptr() as *mut u8, + bytes.len(), + ); + + Ok(UnixAddr::from_raw_parts(ret, sun_len)) + })? + } + + /// Create a new `sockaddr_un` representing an address in the "abstract namespace". + /// + /// The leading nul byte for the abstract namespace is automatically added; + /// thus the input `path` is expected to be the bare name, not NUL-prefixed. + /// This is a Linux-specific extension, primarily used to allow chrooted + /// processes to communicate with processes having a different filesystem view. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn new_abstract(path: &[u8]) -> Result { + unsafe { + let mut ret = libc::sockaddr_un { + sun_family: AddressFamily::Unix as sa_family_t, + ..mem::zeroed() + }; + + if path.len() >= ret.sun_path.len() { + return Err(Errno::ENAMETOOLONG); + } + let sun_len = + (path.len() + 1 + offset_of!(libc::sockaddr_un, sun_path)) + .try_into() + .unwrap(); + + // Abstract addresses are represented by sun_path[0] == + // b'\0', so copy starting one byte in. + ptr::copy_nonoverlapping( + path.as_ptr(), + ret.sun_path.as_mut_ptr().offset(1) as *mut u8, + path.len(), + ); + + Ok(UnixAddr::from_raw_parts(ret, sun_len)) + } + } + + /// Create a new `sockaddr_un` representing an "unnamed" unix socket address. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn new_unnamed() -> UnixAddr { + let ret = libc::sockaddr_un { + sun_family: AddressFamily::Unix as sa_family_t, + .. unsafe { mem::zeroed() } + }; + + let sun_len: u8 = offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap(); + + unsafe { UnixAddr::from_raw_parts(ret, sun_len) } + } + + /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len` + /// is the size of the valid portion of the struct, excluding any trailing + /// NUL. + /// + /// # Safety + /// This pair of sockaddr_un & sun_len must be a valid unix addr, which + /// means: + /// - sun_len >= offset_of(sockaddr_un, sun_path) + /// - sun_len <= sockaddr_un.sun_path.len() - offset_of(sockaddr_un, sun_path) + /// - if this is a unix addr with a pathname, sun.sun_path is a + /// fs path, not necessarily nul-terminated. + pub(crate) unsafe fn from_raw_parts( + sun: libc::sockaddr_un, + sun_len: u8, + ) -> UnixAddr { + cfg_if! { + if #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + { + UnixAddr { sun, sun_len } + } else { + assert_eq!(sun_len, sun.sun_len); + UnixAddr {sun} + } + } + } + + fn kind(&self) -> UnixAddrKind<'_> { + // SAFETY: our sockaddr is always valid because of the invariant on the struct + unsafe { UnixAddrKind::get(&self.sun, self.sun_len()) } + } + + /// If this address represents a filesystem path, return that path. + pub fn path(&self) -> Option<&Path> { + match self.kind() { + UnixAddrKind::Pathname(path) => Some(path), + _ => None, + } + } + + /// If this address represents an abstract socket, return its name. + /// + /// For abstract sockets only the bare name is returned, without the + /// leading NUL byte. `None` is returned for unnamed or path-backed sockets. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn as_abstract(&self) -> Option<&[u8]> { + match self.kind() { + UnixAddrKind::Abstract(name) => Some(name), + _ => None, + } + } + + /// Check if this address is an "unnamed" unix socket address. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + #[inline] + pub fn is_unnamed(&self) -> bool { + matches!(self.kind(), UnixAddrKind::Unnamed) + } + + /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)` + #[inline] + pub fn path_len(&self) -> usize { + self.sun_len() as usize - offset_of!(libc::sockaddr_un, sun_path) + } + /// Returns a pointer to the raw `sockaddr_un` struct + #[inline] + pub fn as_ptr(&self) -> *const libc::sockaddr_un { + &self.sun + } + /// Returns a mutable pointer to the raw `sockaddr_un` struct + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut libc::sockaddr_un { + &mut self.sun + } + + fn sun_len(&self) -> u8 { + cfg_if! { + if #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + { + self.sun_len + } else { + self.sun.sun_len + } + } + } +} + +impl private::SockaddrLikePriv for UnixAddr {} +impl SockaddrLike for UnixAddr { + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + fn len(&self) -> libc::socklen_t { + self.sun_len.into() + } + + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option, + ) -> Option + where + Self: Sized, + { + if let Some(l) = len { + if (l as usize) < offset_of!(libc::sockaddr_un, sun_path) + || l > u8::MAX as libc::socklen_t + { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_UNIX { + return None; + } + let mut su: libc::sockaddr_un = mem::zeroed(); + let sup = &mut su as *mut libc::sockaddr_un as *mut u8; + cfg_if! { + if #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] { + let su_len = len.unwrap_or( + mem::size_of::() as libc::socklen_t + ); + } else { + let su_len = len.unwrap_or((*addr).sa_len as libc::socklen_t); + } + }; + ptr::copy(addr as *const u8, sup, su_len as usize); + Some(Self::from_raw_parts(su, su_len as u8)) + } + + fn size() -> libc::socklen_t + where + Self: Sized, + { + mem::size_of::() as libc::socklen_t + } +} + +impl AsRef for UnixAddr { + fn as_ref(&self) -> &libc::sockaddr_un { + &self.sun + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +fn fmt_abstract(abs: &[u8], f: &mut fmt::Formatter) -> fmt::Result { + use fmt::Write; + f.write_str("@\"")?; + for &b in abs { + use fmt::Display; + char::from(b).escape_default().fmt(f)?; + } + f.write_char('"')?; + Ok(()) +} + +impl fmt::Display for UnixAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.kind() { + UnixAddrKind::Pathname(path) => path.display().fmt(f), + UnixAddrKind::Unnamed => f.pad(""), + #[cfg(any(target_os = "android", target_os = "linux"))] + UnixAddrKind::Abstract(name) => fmt_abstract(name, f), + } + } +} + +impl PartialEq for UnixAddr { + fn eq(&self, other: &UnixAddr) -> bool { + self.kind() == other.kind() + } +} + +impl Eq for UnixAddr {} + +impl Hash for UnixAddr { + fn hash(&self, s: &mut H) { + self.kind().hash(s) + } +} + +/// Anything that, in C, can be cast back and forth to `sockaddr`. +/// +/// Most implementors also implement `AsRef` to access their +/// inner type read-only. +#[allow(clippy::len_without_is_empty)] +pub trait SockaddrLike: private::SockaddrLikePriv { + /// Returns a raw pointer to the inner structure. Useful for FFI. + fn as_ptr(&self) -> *const libc::sockaddr { + self as *const Self as *const libc::sockaddr + } + + /// Unsafe constructor from a variable length source + /// + /// Some C APIs from provide `len`, and others do not. If it's provided it + /// will be validated. If not, it will be guessed based on the family. + /// + /// # Arguments + /// + /// - `addr`: raw pointer to something that can be cast to a + /// `libc::sockaddr`. For example, `libc::sockaddr_in`, + /// `libc::sockaddr_in6`, etc. + /// - `len`: For fixed-width types like `sockaddr_in`, it will be + /// validated if present and ignored if not. For variable-width + /// types it is required and must be the total length of valid + /// data. For example, if `addr` points to a + /// named `sockaddr_un`, then `len` must be the length of the + /// structure up to but not including the trailing NUL. + /// + /// # Safety + /// + /// `addr` must be valid for the specific type of sockaddr. `len`, if + /// present, must not exceed the length of valid data in `addr`. + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option, + ) -> Option + where + Self: Sized; + + /// Return the address family of this socket + /// + /// # Examples + /// One common use is to match on the family of a union type, like this: + /// ``` + /// # use nix::sys::socket::*; + /// let fd = socket(AddressFamily::Inet, SockType::Stream, + /// SockFlag::empty(), None).unwrap(); + /// let ss: SockaddrStorage = getsockname(fd).unwrap(); + /// match ss.family().unwrap() { + /// AddressFamily::Inet => println!("{}", ss.as_sockaddr_in().unwrap()), + /// AddressFamily::Inet6 => println!("{}", ss.as_sockaddr_in6().unwrap()), + /// _ => println!("Unexpected address family") + /// } + /// ``` + fn family(&self) -> Option { + // Safe since all implementors have a sa_family field at the same + // address, and they're all repr(C) + AddressFamily::from_i32(unsafe { + (*(self as *const Self as *const libc::sockaddr)).sa_family as i32 + }) + } + + cfg_if! { + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] { + /// Return the length of valid data in the sockaddr structure. + /// + /// For fixed-size sockaddrs, this should be the size of the + /// structure. But for variable-sized types like [`UnixAddr`] it + /// may be less. + fn len(&self) -> libc::socklen_t { + // Safe since all implementors have a sa_len field at the same + // address, and they're all repr(transparent). + // Robust for all implementors. + unsafe { + (*(self as *const Self as *const libc::sockaddr)).sa_len + }.into() + } + } else { + /// Return the length of valid data in the sockaddr structure. + /// + /// For fixed-size sockaddrs, this should be the size of the + /// structure. But for variable-sized types like [`UnixAddr`] it + /// may be less. + fn len(&self) -> libc::socklen_t { + // No robust default implementation is possible without an + // sa_len field. Implementors with a variable size must + // override this method. + mem::size_of_val(self) as libc::socklen_t + } + } + } + + /// Return the available space in the structure + fn size() -> libc::socklen_t + where + Self: Sized, + { + mem::size_of::() as libc::socklen_t + } +} + +impl private::SockaddrLikePriv for () { + fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { + ptr::null_mut() + } +} + +/// `()` can be used in place of a real Sockaddr when no address is expected, +/// for example for a field of `Option where S: SockaddrLike`. +// If this RFC ever stabilizes, then ! will be a better choice. +// https://github.com/rust-lang/rust/issues/35121 +impl SockaddrLike for () { + fn as_ptr(&self) -> *const libc::sockaddr { + ptr::null() + } + + unsafe fn from_raw( + _: *const libc::sockaddr, + _: Option, + ) -> Option + where + Self: Sized, + { + None + } + + fn family(&self) -> Option { + None + } + + fn len(&self) -> libc::socklen_t { + 0 + } +} + +/// An IPv4 socket address +// This is identical to net::SocketAddrV4. But the standard library +// doesn't allow direct access to the libc fields, which we need. So we +// reimplement it here. +#[cfg(feature = "net")] +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct SockaddrIn(libc::sockaddr_in); + +#[cfg(feature = "net")] +impl SockaddrIn { + /// Returns the IP address associated with this socket address, in native + /// endian. + pub const fn ip(&self) -> libc::in_addr_t { + u32::from_be(self.0.sin_addr.s_addr) + } + + /// Creates a new socket address from IPv4 octets and a port number. + pub fn new(a: u8, b: u8, c: u8, d: u8, port: u16) -> Self { + Self(libc::sockaddr_in { + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "haiku", + target_os = "openbsd" + ))] + sin_len: Self::size() as u8, + sin_family: AddressFamily::Inet as sa_family_t, + sin_port: u16::to_be(port), + sin_addr: libc::in_addr { + s_addr: u32::from_ne_bytes([a, b, c, d]), + }, + sin_zero: unsafe { mem::zeroed() }, + }) + } + + /// Returns the port number associated with this socket address, in native + /// endian. + pub const fn port(&self) -> u16 { + u16::from_be(self.0.sin_port) + } +} + +#[cfg(feature = "net")] +impl private::SockaddrLikePriv for SockaddrIn {} +#[cfg(feature = "net")] +impl SockaddrLike for SockaddrIn { + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option, + ) -> Option + where + Self: Sized, + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_INET { + return None; + } + Some(Self(ptr::read_unaligned(addr as *const _))) + } +} + +#[cfg(feature = "net")] +impl AsRef for SockaddrIn { + fn as_ref(&self) -> &libc::sockaddr_in { + &self.0 + } +} + +#[cfg(feature = "net")] +impl fmt::Display for SockaddrIn { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let ne = u32::from_be(self.0.sin_addr.s_addr); + let port = u16::from_be(self.0.sin_port); + write!( + f, + "{}.{}.{}.{}:{}", + ne >> 24, + (ne >> 16) & 0xFF, + (ne >> 8) & 0xFF, + ne & 0xFF, + port + ) + } +} + +#[cfg(feature = "net")] +impl From for SockaddrIn { + fn from(addr: net::SocketAddrV4) -> Self { + Self(libc::sockaddr_in { + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "hermit", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + sin_len: mem::size_of::() as u8, + sin_family: AddressFamily::Inet as sa_family_t, + sin_port: addr.port().to_be(), // network byte order + sin_addr: ipv4addr_to_libc(*addr.ip()), + ..unsafe { mem::zeroed() } + }) + } +} + +#[cfg(feature = "net")] +impl From for net::SocketAddrV4 { + fn from(addr: SockaddrIn) -> Self { + net::SocketAddrV4::new( + net::Ipv4Addr::from(addr.0.sin_addr.s_addr.to_ne_bytes()), + u16::from_be(addr.0.sin_port), + ) + } +} + +#[cfg(feature = "net")] +impl std::str::FromStr for SockaddrIn { + type Err = net::AddrParseError; + + fn from_str(s: &str) -> std::result::Result { + net::SocketAddrV4::from_str(s).map(SockaddrIn::from) + } +} + +/// An IPv6 socket address +#[cfg(feature = "net")] +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct SockaddrIn6(libc::sockaddr_in6); + +#[cfg(feature = "net")] +impl SockaddrIn6 { + /// Returns the flow information associated with this address. + pub const fn flowinfo(&self) -> u32 { + self.0.sin6_flowinfo + } + + /// Returns the IP address associated with this socket address. + pub fn ip(&self) -> net::Ipv6Addr { + net::Ipv6Addr::from(self.0.sin6_addr.s6_addr) + } + + /// Returns the port number associated with this socket address, in native + /// endian. + pub const fn port(&self) -> u16 { + u16::from_be(self.0.sin6_port) + } + + /// Returns the scope ID associated with this address. + pub const fn scope_id(&self) -> u32 { + self.0.sin6_scope_id + } +} + +#[cfg(feature = "net")] +impl private::SockaddrLikePriv for SockaddrIn6 {} +#[cfg(feature = "net")] +impl SockaddrLike for SockaddrIn6 { + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option, + ) -> Option + where + Self: Sized, + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_INET6 { + return None; + } + Some(Self(ptr::read_unaligned(addr as *const _))) + } +} + +#[cfg(feature = "net")] +impl AsRef for SockaddrIn6 { + fn as_ref(&self) -> &libc::sockaddr_in6 { + &self.0 + } +} + +#[cfg(feature = "net")] +impl fmt::Display for SockaddrIn6 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // These things are really hard to display properly. Easier to let std + // do it. + let std = net::SocketAddrV6::new( + self.ip(), + self.port(), + self.flowinfo(), + self.scope_id(), + ); + std.fmt(f) + } +} + +#[cfg(feature = "net")] +impl From for SockaddrIn6 { + fn from(addr: net::SocketAddrV6) -> Self { + #[allow(clippy::needless_update)] // It isn't needless on Illumos + Self(libc::sockaddr_in6 { + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "hermit", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + sin6_len: mem::size_of::() as u8, + sin6_family: AddressFamily::Inet6 as sa_family_t, + sin6_port: addr.port().to_be(), // network byte order + sin6_addr: ipv6addr_to_libc(addr.ip()), + sin6_flowinfo: addr.flowinfo(), // host byte order + sin6_scope_id: addr.scope_id(), // host byte order + ..unsafe { mem::zeroed() } + }) + } +} + +#[cfg(feature = "net")] +impl From for net::SocketAddrV6 { + fn from(addr: SockaddrIn6) -> Self { + net::SocketAddrV6::new( + net::Ipv6Addr::from(addr.0.sin6_addr.s6_addr), + u16::from_be(addr.0.sin6_port), + addr.0.sin6_flowinfo, + addr.0.sin6_scope_id, + ) + } +} + +#[cfg(feature = "net")] +impl std::str::FromStr for SockaddrIn6 { + type Err = net::AddrParseError; + + fn from_str(s: &str) -> std::result::Result { + net::SocketAddrV6::from_str(s).map(SockaddrIn6::from) + } +} + +/// A container for any sockaddr type +/// +/// Just like C's `sockaddr_storage`, this type is large enough to hold any type +/// of sockaddr. It can be used as an argument with functions like +/// [`bind`](super::bind) and [`getsockname`](super::getsockname). Though it is +/// a union, it can be safely accessed through the `as_*` methods. +/// +/// # Example +/// ``` +/// # use nix::sys::socket::*; +/// # use std::str::FromStr; +/// let localhost = SockaddrIn::from_str("127.0.0.1:8081").unwrap(); +/// let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), +/// None).unwrap(); +/// bind(fd, &localhost).expect("bind"); +/// let ss: SockaddrStorage = getsockname(fd).expect("getsockname"); +/// assert_eq!(&localhost, ss.as_sockaddr_in().unwrap()); +/// ``` +#[derive(Clone, Copy, Eq)] +#[repr(C)] +pub union SockaddrStorage { + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + alg: AlgAddr, + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + dl: LinkAddr, + #[cfg(any(target_os = "android", target_os = "linux"))] + nl: NetlinkAddr, + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] + #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] + sctl: SysControlAddr, + #[cfg(feature = "net")] + sin: SockaddrIn, + #[cfg(feature = "net")] + sin6: SockaddrIn6, + ss: libc::sockaddr_storage, + su: UnixAddr, + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + vsock: VsockAddr, +} +impl private::SockaddrLikePriv for SockaddrStorage {} +impl SockaddrLike for SockaddrStorage { + unsafe fn from_raw( + addr: *const libc::sockaddr, + l: Option, + ) -> Option + where + Self: Sized, + { + if addr.is_null() { + return None; + } + if let Some(len) = l { + let ulen = len as usize; + if ulen < offset_of!(libc::sockaddr, sa_data) + || ulen > mem::size_of::() + { + None + } else { + let mut ss: libc::sockaddr_storage = mem::zeroed(); + let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8; + ptr::copy(addr as *const u8, ssp, len as usize); + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + if i32::from(ss.ss_family) == libc::AF_UNIX { + // Safe because we UnixAddr is strictly smaller than + // SockaddrStorage, and we just initialized the structure. + (*(&mut ss as *mut libc::sockaddr_storage as *mut UnixAddr)).sun_len = len as u8; + } + Some(Self { ss }) + } + } else { + // If length is not available and addr is of a fixed-length type, + // copy it. If addr is of a variable length type and len is not + // available, then there's nothing we can do. + match (*addr).sa_family as i32 { + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_ALG => { + AlgAddr::from_raw(addr, l).map(|alg| Self { alg }) + } + #[cfg(feature = "net")] + libc::AF_INET => { + SockaddrIn::from_raw(addr, l).map(|sin| Self { sin }) + } + #[cfg(feature = "net")] + libc::AF_INET6 => { + SockaddrIn6::from_raw(addr, l).map(|sin6| Self { sin6 }) + } + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "haiku", + target_os = "openbsd" + ))] + #[cfg(feature = "net")] + libc::AF_LINK => { + LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) + } + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_NETLINK => { + NetlinkAddr::from_raw(addr, l).map(|nl| Self { nl }) + } + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg(feature = "net")] + libc::AF_PACKET => { + LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) + } + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] + libc::AF_SYSTEM => { + SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl }) + } + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_VSOCK => { + VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock }) + } + _ => None, + } + } + } + + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + fn len(&self) -> libc::socklen_t { + match self.as_unix_addr() { + // The UnixAddr type knows its own length + Some(ua) => ua.len(), + // For all else, we're just a boring SockaddrStorage + None => mem::size_of_val(self) as libc::socklen_t + } + } +} + +macro_rules! accessors { + ( + $fname:ident, + $fname_mut:ident, + $sockty:ty, + $family:expr, + $libc_ty:ty, + $field:ident) => { + /// Safely and falliably downcast to an immutable reference + pub fn $fname(&self) -> Option<&$sockty> { + if self.family() == Some($family) + && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t + { + // Safe because family and len are validated + Some(unsafe { &self.$field }) + } else { + None + } + } + + /// Safely and falliably downcast to a mutable reference + pub fn $fname_mut(&mut self) -> Option<&mut $sockty> { + if self.family() == Some($family) + && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t + { + // Safe because family and len are validated + Some(unsafe { &mut self.$field }) + } else { + None + } + } + }; +} + +impl SockaddrStorage { + /// Downcast to an immutable `[UnixAddr]` reference. + pub fn as_unix_addr(&self) -> Option<&UnixAddr> { + cfg_if! { + if #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + { + let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; + // Safe because UnixAddr is strictly smaller than + // sockaddr_storage, and we're fully initialized + let len = unsafe { + (*(p as *const UnixAddr )).sun_len as usize + }; + } else { + let len = self.len() as usize; + } + } + // Sanity checks + if self.family() != Some(AddressFamily::Unix) || + len < offset_of!(libc::sockaddr_un, sun_path) || + len > mem::size_of::() { + None + } else { + Some(unsafe{&self.su}) + } + } + + /// Downcast to a mutable `[UnixAddr]` reference. + pub fn as_unix_addr_mut(&mut self) -> Option<&mut UnixAddr> { + cfg_if! { + if #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + { + let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; + // Safe because UnixAddr is strictly smaller than + // sockaddr_storage, and we're fully initialized + let len = unsafe { + (*(p as *const UnixAddr )).sun_len as usize + }; + } else { + let len = self.len() as usize; + } + } + // Sanity checks + if self.family() != Some(AddressFamily::Unix) || + len < offset_of!(libc::sockaddr_un, sun_path) || + len > mem::size_of::() { + None + } else { + Some(unsafe{&mut self.su}) + } + } + + #[cfg(any(target_os = "android", target_os = "linux"))] + accessors! {as_alg_addr, as_alg_addr_mut, AlgAddr, + AddressFamily::Alg, libc::sockaddr_alg, alg} + + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg(feature = "net")] + accessors! { + as_link_addr, as_link_addr_mut, LinkAddr, + AddressFamily::Packet, libc::sockaddr_ll, dl} + + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg(feature = "net")] + accessors! { + as_link_addr, as_link_addr_mut, LinkAddr, + AddressFamily::Link, libc::sockaddr_dl, dl} + + #[cfg(feature = "net")] + accessors! { + as_sockaddr_in, as_sockaddr_in_mut, SockaddrIn, + AddressFamily::Inet, libc::sockaddr_in, sin} + + #[cfg(feature = "net")] + accessors! { + as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6, + AddressFamily::Inet6, libc::sockaddr_in6, sin6} + + #[cfg(any(target_os = "android", target_os = "linux"))] + accessors! {as_netlink_addr, as_netlink_addr_mut, NetlinkAddr, + AddressFamily::Netlink, libc::sockaddr_nl, nl} + + #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] + #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] + accessors! {as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr, + AddressFamily::System, libc::sockaddr_ctl, sctl} + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr, + AddressFamily::Vsock, libc::sockaddr_vm, vsock} +} + +impl fmt::Debug for SockaddrStorage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SockaddrStorage") + // Safe because sockaddr_storage has the least specific + // field types + .field("ss", unsafe { &self.ss }) + .finish() + } +} + +impl fmt::Display for SockaddrStorage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + unsafe { + match self.ss.ss_family as i32 { + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_ALG => self.alg.fmt(f), + #[cfg(feature = "net")] + libc::AF_INET => self.sin.fmt(f), + #[cfg(feature = "net")] + libc::AF_INET6 => self.sin6.fmt(f), + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg(feature = "net")] + libc::AF_LINK => self.dl.fmt(f), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_NETLINK => self.nl.fmt(f), + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "fuchsia" + ))] + #[cfg(feature = "net")] + libc::AF_PACKET => self.dl.fmt(f), + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(feature = "ioctl")] + libc::AF_SYSTEM => self.sctl.fmt(f), + libc::AF_UNIX => self.su.fmt(f), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_VSOCK => self.vsock.fmt(f), + _ => "

".fmt(f), + } + } + } +} + +#[cfg(feature = "net")] +impl From for SockaddrStorage { + fn from(s: net::SocketAddrV4) -> Self { + unsafe { + let mut ss: Self = mem::zeroed(); + ss.sin = SockaddrIn::from(s); + ss + } + } +} + +#[cfg(feature = "net")] +impl From for SockaddrStorage { + fn from(s: net::SocketAddrV6) -> Self { + unsafe { + let mut ss: Self = mem::zeroed(); + ss.sin6 = SockaddrIn6::from(s); + ss + } + } +} + +#[cfg(feature = "net")] +impl From for SockaddrStorage { + fn from(s: net::SocketAddr) -> Self { + match s { + net::SocketAddr::V4(sa4) => Self::from(sa4), + net::SocketAddr::V6(sa6) => Self::from(sa6), + } + } +} + +impl Hash for SockaddrStorage { + fn hash(&self, s: &mut H) { + unsafe { + match self.ss.ss_family as i32 { + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_ALG => self.alg.hash(s), + #[cfg(feature = "net")] + libc::AF_INET => self.sin.hash(s), + #[cfg(feature = "net")] + libc::AF_INET6 => self.sin6.hash(s), + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg(feature = "net")] + libc::AF_LINK => self.dl.hash(s), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_NETLINK => self.nl.hash(s), + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "fuchsia" + ))] + #[cfg(feature = "net")] + libc::AF_PACKET => self.dl.hash(s), + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(feature = "ioctl")] + libc::AF_SYSTEM => self.sctl.hash(s), + libc::AF_UNIX => self.su.hash(s), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_VSOCK => self.vsock.hash(s), + _ => self.ss.hash(s), + } + } + } +} + +impl PartialEq for SockaddrStorage { + fn eq(&self, other: &Self) -> bool { + unsafe { + match (self.ss.ss_family as i32, other.ss.ss_family as i32) { + #[cfg(any(target_os = "android", target_os = "linux"))] + (libc::AF_ALG, libc::AF_ALG) => self.alg == other.alg, + #[cfg(feature = "net")] + (libc::AF_INET, libc::AF_INET) => self.sin == other.sin, + #[cfg(feature = "net")] + (libc::AF_INET6, libc::AF_INET6) => self.sin6 == other.sin6, + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg(feature = "net")] + (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl, + #[cfg(any(target_os = "android", target_os = "linux"))] + (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl, + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg(feature = "net")] + (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl, + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(feature = "ioctl")] + (libc::AF_SYSTEM, libc::AF_SYSTEM) => self.sctl == other.sctl, + (libc::AF_UNIX, libc::AF_UNIX) => self.su == other.su, + #[cfg(any(target_os = "android", target_os = "linux"))] + (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock, + _ => false, + } + } + } +} + +mod private { + pub trait SockaddrLikePriv { + /// Returns a mutable raw pointer to the inner structure. + /// + /// # Safety + /// + /// This method is technically safe, but modifying the inner structure's + /// `family` or `len` fields may result in violating Nix's invariants. + /// It is best to use this method only with foreign functions that do + /// not change the sockaddr type. + fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { + self as *mut Self as *mut libc::sockaddr + } + } +} + +/// Represents a socket address +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[deprecated( + since = "0.24.0", + note = "use SockaddrLike or SockaddrStorage instead" +)] +#[allow(missing_docs)] // Since they're all deprecated anyway +#[allow(deprecated)] +#[non_exhaustive] +pub enum SockAddr { + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Inet(InetAddr), + Unix(UnixAddr), + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Netlink(NetlinkAddr), + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Alg(AlgAddr), + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] + #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] + SysControl(SysControlAddr), + /// Datalink address (MAC) + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Link(LinkAddr), + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + Vsock(VsockAddr), +} + +#[allow(missing_docs)] // Since they're all deprecated anyway +#[allow(deprecated)] +impl SockAddr { + feature! { + #![feature = "net"] + pub fn new_inet(addr: InetAddr) -> SockAddr { + SockAddr::Inet(addr) + } + } + + pub fn new_unix(path: &P) -> Result { + Ok(SockAddr::Unix(UnixAddr::new(path)?)) + } + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn new_netlink(pid: u32, groups: u32) -> SockAddr { + SockAddr::Netlink(NetlinkAddr::new(pid, groups)) + } + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr { + SockAddr::Alg(AlgAddr::new(alg_type, alg_name)) + } + + feature! { + #![feature = "ioctl"] + #[cfg(any(target_os = "ios", target_os = "macos"))] + pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result { + SysControlAddr::from_name(sockfd, name, unit).map(SockAddr::SysControl) + } + } + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn new_vsock(cid: u32, port: u32) -> SockAddr { + SockAddr::Vsock(VsockAddr::new(cid, port)) + } + + pub fn family(&self) -> AddressFamily { + match *self { + #[cfg(feature = "net")] + SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet, + #[cfg(feature = "net")] + SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6, + SockAddr::Unix(..) => AddressFamily::Unix, + #[cfg(any(target_os = "android", target_os = "linux"))] + SockAddr::Netlink(..) => AddressFamily::Netlink, + #[cfg(any(target_os = "android", target_os = "linux"))] + SockAddr::Alg(..) => AddressFamily::Alg, + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] + SockAddr::SysControl(..) => AddressFamily::System, + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] + SockAddr::Link(..) => AddressFamily::Packet, + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd" + ))] + #[cfg(feature = "net")] + SockAddr::Link(..) => AddressFamily::Link, + #[cfg(any(target_os = "android", target_os = "linux"))] + SockAddr::Vsock(..) => AddressFamily::Vsock, + } + } + + #[deprecated(since = "0.23.0", note = "use .to_string() instead")] + pub fn to_str(&self) -> String { + format!("{}", self) + } + + /// Creates a `SockAddr` struct from libc's sockaddr. + /// + /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System. + /// Returns None for unsupported families. + /// + /// # Safety + /// + /// unsafe because it takes a raw pointer as argument. The caller must + /// ensure that the pointer is valid. + #[cfg(not(target_os = "fuchsia"))] + #[cfg(feature = "net")] + pub(crate) unsafe fn from_libc_sockaddr( + addr: *const libc::sockaddr, + ) -> Option { + if addr.is_null() { + None + } else { + match AddressFamily::from_i32(i32::from((*addr).sa_family)) { + Some(AddressFamily::Unix) => None, + #[cfg(feature = "net")] + Some(AddressFamily::Inet) => Some(SockAddr::Inet( + InetAddr::V4(ptr::read_unaligned(addr as *const _)), + )), + #[cfg(feature = "net")] + Some(AddressFamily::Inet6) => Some(SockAddr::Inet( + InetAddr::V6(ptr::read_unaligned(addr as *const _)), + )), + #[cfg(any(target_os = "android", target_os = "linux"))] + Some(AddressFamily::Netlink) => Some(SockAddr::Netlink( + NetlinkAddr(ptr::read_unaligned(addr as *const _)), + )), + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] + Some(AddressFamily::System) => Some(SockAddr::SysControl( + SysControlAddr(ptr::read_unaligned(addr as *const _)), + )), + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] + Some(AddressFamily::Packet) => Some(SockAddr::Link(LinkAddr( + ptr::read_unaligned(addr as *const _), + ))), + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd" + ))] + #[cfg(feature = "net")] + Some(AddressFamily::Link) => { + let ether_addr = + LinkAddr(ptr::read_unaligned(addr as *const _)); + if ether_addr.is_empty() { + None + } else { + Some(SockAddr::Link(ether_addr)) + } + } + #[cfg(any(target_os = "android", target_os = "linux"))] + Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(VsockAddr( + ptr::read_unaligned(addr as *const _), + ))), + // Other address families are currently not supported and simply yield a None + // entry instead of a proper conversion to a `SockAddr`. + Some(_) | None => None, + } + } + } + + /// Conversion from nix's SockAddr type to the underlying libc sockaddr type. + /// + /// This is useful for interfacing with other libc functions that don't yet have nix wrappers. + /// Returns a reference to the underlying data type (as a sockaddr reference) along + /// with the size of the actual data type. sockaddr is commonly used as a proxy for + /// a superclass as C doesn't support inheritance, so many functions that take + /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back. + pub fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) { + match *self { + #[cfg(feature = "net")] + SockAddr::Inet(InetAddr::V4(ref addr)) => ( + // This cast is always allowed in C + unsafe { + &*(addr as *const libc::sockaddr_in + as *const libc::sockaddr) + }, + mem::size_of_val(addr) as libc::socklen_t, + ), + #[cfg(feature = "net")] + SockAddr::Inet(InetAddr::V6(ref addr)) => ( + // This cast is always allowed in C + unsafe { + &*(addr as *const libc::sockaddr_in6 + as *const libc::sockaddr) + }, + mem::size_of_val(addr) as libc::socklen_t, + ), + SockAddr::Unix(ref unix_addr) => ( + // This cast is always allowed in C + unsafe { + &*(&unix_addr.sun as *const libc::sockaddr_un + as *const libc::sockaddr) + }, + unix_addr.sun_len() as libc::socklen_t, + ), + #[cfg(any(target_os = "android", target_os = "linux"))] + SockAddr::Netlink(NetlinkAddr(ref sa)) => ( + // This cast is always allowed in C + unsafe { + &*(sa as *const libc::sockaddr_nl as *const libc::sockaddr) + }, + mem::size_of_val(sa) as libc::socklen_t, + ), + #[cfg(any(target_os = "android", target_os = "linux"))] + SockAddr::Alg(AlgAddr(ref sa)) => ( + // This cast is always allowed in C + unsafe { + &*(sa as *const libc::sockaddr_alg as *const libc::sockaddr) + }, + mem::size_of_val(sa) as libc::socklen_t, + ), + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] + SockAddr::SysControl(SysControlAddr(ref sa)) => ( + // This cast is always allowed in C + unsafe { + &*(sa as *const libc::sockaddr_ctl as *const libc::sockaddr) + }, + mem::size_of_val(sa) as libc::socklen_t, + ), + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] + SockAddr::Link(LinkAddr(ref addr)) => ( + // This cast is always allowed in C + unsafe { + &*(addr as *const libc::sockaddr_ll + as *const libc::sockaddr) + }, + mem::size_of_val(addr) as libc::socklen_t, + ), + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg(feature = "net")] + SockAddr::Link(LinkAddr(ref addr)) => ( + // This cast is always allowed in C + unsafe { + &*(addr as *const libc::sockaddr_dl + as *const libc::sockaddr) + }, + mem::size_of_val(addr) as libc::socklen_t, + ), + #[cfg(any(target_os = "android", target_os = "linux"))] + SockAddr::Vsock(VsockAddr(ref sa)) => ( + // This cast is always allowed in C + unsafe { + &*(sa as *const libc::sockaddr_vm as *const libc::sockaddr) + }, + mem::size_of_val(sa) as libc::socklen_t, + ), + } + } +} + +#[allow(deprecated)] +impl fmt::Display for SockAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + #[cfg(feature = "net")] + SockAddr::Inet(ref inet) => inet.fmt(f), + SockAddr::Unix(ref unix) => unix.fmt(f), + #[cfg(any(target_os = "android", target_os = "linux"))] + SockAddr::Netlink(ref nl) => nl.fmt(f), + #[cfg(any(target_os = "android", target_os = "linux"))] + SockAddr::Alg(ref nl) => nl.fmt(f), + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] + SockAddr::SysControl(ref sc) => sc.fmt(f), + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd" + ))] + #[cfg(feature = "net")] + SockAddr::Link(ref ether_addr) => ether_addr.fmt(f), + #[cfg(any(target_os = "android", target_os = "linux"))] + SockAddr::Vsock(ref svm) => svm.fmt(f), + } + } +} + +#[cfg(not(target_os = "fuchsia"))] +#[cfg(feature = "net")] +#[allow(deprecated)] +impl private::SockaddrLikePriv for SockAddr {} +#[cfg(not(target_os = "fuchsia"))] +#[cfg(feature = "net")] +#[allow(deprecated)] +impl SockaddrLike for SockAddr { + unsafe fn from_raw( + addr: *const libc::sockaddr, + _len: Option, + ) -> Option { + Self::from_libc_sockaddr(addr) + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub mod netlink { + use super::*; + use crate::sys::socket::addr::AddressFamily; + use libc::{sa_family_t, sockaddr_nl}; + use std::{fmt, mem}; + + /// Address for the Linux kernel user interface device. + /// + /// # References + /// + /// [netlink(7)](https://man7.org/linux/man-pages/man7/netlink.7.html) + #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] + #[repr(transparent)] + pub struct NetlinkAddr(pub(in super::super) sockaddr_nl); + + impl NetlinkAddr { + /// Construct a new socket address from its port ID and multicast groups + /// mask. + pub fn new(pid: u32, groups: u32) -> NetlinkAddr { + let mut addr: sockaddr_nl = unsafe { mem::zeroed() }; + addr.nl_family = AddressFamily::Netlink as sa_family_t; + addr.nl_pid = pid; + addr.nl_groups = groups; + + NetlinkAddr(addr) + } + + /// Return the socket's port ID. + pub const fn pid(&self) -> u32 { + self.0.nl_pid + } + + /// Return the socket's multicast groups mask + pub const fn groups(&self) -> u32 { + self.0.nl_groups + } + } + + impl private::SockaddrLikePriv for NetlinkAddr {} + impl SockaddrLike for NetlinkAddr { + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option, + ) -> Option + where + Self: Sized, + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_NETLINK { + return None; + } + Some(Self(ptr::read_unaligned(addr as *const _))) + } + } + + impl AsRef for NetlinkAddr { + fn as_ref(&self) -> &libc::sockaddr_nl { + &self.0 + } + } + + impl fmt::Display for NetlinkAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "pid: {} groups: {}", self.pid(), self.groups()) + } + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub mod alg { + use super::*; + use libc::{c_char, sockaddr_alg, AF_ALG}; + use std::ffi::CStr; + use std::hash::{Hash, Hasher}; + use std::{fmt, mem, str}; + + /// Socket address for the Linux kernel crypto API + #[derive(Copy, Clone)] + #[repr(transparent)] + pub struct AlgAddr(pub(in super::super) sockaddr_alg); + + impl private::SockaddrLikePriv for AlgAddr {} + impl SockaddrLike for AlgAddr { + unsafe fn from_raw( + addr: *const libc::sockaddr, + l: Option, + ) -> Option + where + Self: Sized, + { + if let Some(l) = l { + if l != mem::size_of::() as libc::socklen_t + { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_ALG { + return None; + } + Some(Self(ptr::read_unaligned(addr as *const _))) + } + } + + impl AsRef for AlgAddr { + fn as_ref(&self) -> &libc::sockaddr_alg { + &self.0 + } + } + + // , PartialEq, Eq, Debug, Hash + impl PartialEq for AlgAddr { + fn eq(&self, other: &Self) -> bool { + let (inner, other) = (self.0, other.0); + ( + inner.salg_family, + &inner.salg_type[..], + inner.salg_feat, + inner.salg_mask, + &inner.salg_name[..], + ) == ( + other.salg_family, + &other.salg_type[..], + other.salg_feat, + other.salg_mask, + &other.salg_name[..], + ) + } + } + + impl Eq for AlgAddr {} + + impl Hash for AlgAddr { + fn hash(&self, s: &mut H) { + let inner = self.0; + ( + inner.salg_family, + &inner.salg_type[..], + inner.salg_feat, + inner.salg_mask, + &inner.salg_name[..], + ) + .hash(s); + } + } + + impl AlgAddr { + /// Construct an `AF_ALG` socket from its cipher name and type. + pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr { + let mut addr: sockaddr_alg = unsafe { mem::zeroed() }; + addr.salg_family = AF_ALG as u16; + addr.salg_type[..alg_type.len()] + .copy_from_slice(alg_type.to_string().as_bytes()); + addr.salg_name[..alg_name.len()] + .copy_from_slice(alg_name.to_string().as_bytes()); + + AlgAddr(addr) + } + + /// Return the socket's cipher type, for example `hash` or `aead`. + pub fn alg_type(&self) -> &CStr { + unsafe { + CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) + } + } + + /// Return the socket's cipher name, for example `sha1`. + pub fn alg_name(&self) -> &CStr { + unsafe { + CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) + } + } + } + + impl fmt::Display for AlgAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "type: {} alg: {}", + self.alg_name().to_string_lossy(), + self.alg_type().to_string_lossy() + ) + } + } + + impl fmt::Debug for AlgAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } + } +} + +feature! { +#![feature = "ioctl"] +#[cfg(any(target_os = "ios", target_os = "macos"))] +pub mod sys_control { + use crate::sys::socket::addr::AddressFamily; + use libc::{self, c_uchar}; + use std::{fmt, mem, ptr}; + use std::os::unix::io::RawFd; + use crate::{Errno, Result}; + use super::{private, SockaddrLike}; + + // FIXME: Move type into `libc` + #[repr(C)] + #[derive(Clone, Copy)] + #[allow(missing_debug_implementations)] + pub struct ctl_ioc_info { + pub ctl_id: u32, + pub ctl_name: [c_uchar; MAX_KCTL_NAME], + } + + const CTL_IOC_MAGIC: u8 = b'N'; + const CTL_IOC_INFO: u8 = 3; + const MAX_KCTL_NAME: usize = 96; + + ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info); + + /// Apple system control socket + /// + /// # References + /// + /// + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + #[repr(transparent)] + pub struct SysControlAddr(pub(in super::super) libc::sockaddr_ctl); + + impl private::SockaddrLikePriv for SysControlAddr {} + impl SockaddrLike for SysControlAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_SYSTEM { + return None; + } + Some(Self(ptr::read_unaligned(addr as *const _))) + } + } + + impl AsRef for SysControlAddr { + fn as_ref(&self) -> &libc::sockaddr_ctl { + &self.0 + } + } + + impl SysControlAddr { + /// Construct a new `SysControlAddr` from its kernel unique identifier + /// and unit number. + pub const fn new(id: u32, unit: u32) -> SysControlAddr { + let addr = libc::sockaddr_ctl { + sc_len: mem::size_of::() as c_uchar, + sc_family: AddressFamily::System as c_uchar, + ss_sysaddr: libc::AF_SYS_CONTROL as u16, + sc_id: id, + sc_unit: unit, + sc_reserved: [0; 5] + }; + + SysControlAddr(addr) + } + + /// Construct a new `SysControlAddr` from its human readable name and + /// unit number. + pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result { + if name.len() > MAX_KCTL_NAME { + return Err(Errno::ENAMETOOLONG); + } + + let mut ctl_name = [0; MAX_KCTL_NAME]; + ctl_name[..name.len()].clone_from_slice(name.as_bytes()); + let mut info = ctl_ioc_info { ctl_id: 0, ctl_name }; + + unsafe { ctl_info(sockfd, &mut info)?; } + + Ok(SysControlAddr::new(info.ctl_id, unit)) + } + + /// Return the kernel unique identifier + pub const fn id(&self) -> u32 { + self.0.sc_id + } + + /// Return the kernel controller private unit number. + pub const fn unit(&self) -> u32 { + self.0.sc_unit + } + } + + impl fmt::Display for SysControlAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self, f) + } + } +} +} + +#[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +mod datalink { + feature! { + #![feature = "net"] + use super::{fmt, mem, private, ptr, SockaddrLike}; + + /// Hardware Address + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + #[repr(transparent)] + pub struct LinkAddr(pub(in super::super) libc::sockaddr_ll); + + impl LinkAddr { + /// Physical-layer protocol + pub fn protocol(&self) -> u16 { + self.0.sll_protocol + } + + /// Interface number + pub fn ifindex(&self) -> usize { + self.0.sll_ifindex as usize + } + + /// ARP hardware type + pub fn hatype(&self) -> u16 { + self.0.sll_hatype + } + + /// Packet type + pub fn pkttype(&self) -> u8 { + self.0.sll_pkttype + } + + /// Length of MAC address + pub fn halen(&self) -> usize { + self.0.sll_halen as usize + } + + /// Physical-layer address (MAC) + // Returns an Option just for cross-platform compatibility + pub fn addr(&self) -> Option<[u8; 6]> { + Some([ + self.0.sll_addr[0], + self.0.sll_addr[1], + self.0.sll_addr[2], + self.0.sll_addr[3], + self.0.sll_addr[4], + self.0.sll_addr[5], + ]) + } + } + + impl fmt::Display for LinkAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(addr) = self.addr() { + write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", + addr[0], + addr[1], + addr[2], + addr[3], + addr[4], + addr[5]) + } else { + Ok(()) + } + } + } + impl private::SockaddrLikePriv for LinkAddr {} + impl SockaddrLike for LinkAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, + len: Option) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_PACKET { + return None; + } + Some(Self(ptr::read_unaligned(addr as *const _))) + } + } + + impl AsRef for LinkAddr { + fn as_ref(&self) -> &libc::sockaddr_ll { + &self.0 + } + } + + } +} + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "haiku", + target_os = "openbsd" +))] +#[cfg_attr(docsrs, doc(cfg(all())))] +mod datalink { + feature! { + #![feature = "net"] + use super::{fmt, mem, private, ptr, SockaddrLike}; + + /// Hardware Address + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + #[repr(transparent)] + pub struct LinkAddr(pub(in super::super) libc::sockaddr_dl); + + impl LinkAddr { + /// interface index, if != 0, system given index for interface + #[cfg(not(target_os = "haiku"))] + pub fn ifindex(&self) -> usize { + self.0.sdl_index as usize + } + + /// Datalink type + #[cfg(not(target_os = "haiku"))] + pub fn datalink_type(&self) -> u8 { + self.0.sdl_type + } + + /// MAC address start position + pub fn nlen(&self) -> usize { + self.0.sdl_nlen as usize + } + + /// link level address length + pub fn alen(&self) -> usize { + self.0.sdl_alen as usize + } + + /// link layer selector length + #[cfg(not(target_os = "haiku"))] + pub fn slen(&self) -> usize { + self.0.sdl_slen as usize + } + + /// if link level address length == 0, + /// or `sdl_data` not be larger. + pub fn is_empty(&self) -> bool { + let nlen = self.nlen(); + let alen = self.alen(); + let data_len = self.0.sdl_data.len(); + + alen == 0 || nlen + alen >= data_len + } + + /// Physical-layer address (MAC) + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + pub fn addr(&self) -> Option<[u8; 6]> { + let nlen = self.nlen(); + let data = self.0.sdl_data; + + if self.is_empty() { + None + } else { + Some([ + data[nlen] as u8, + data[nlen + 1] as u8, + data[nlen + 2] as u8, + data[nlen + 3] as u8, + data[nlen + 4] as u8, + data[nlen + 5] as u8, + ]) + } + } + } + + impl fmt::Display for LinkAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(addr) = self.addr() { + write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", + addr[0], + addr[1], + addr[2], + addr[3], + addr[4], + addr[5]) + } else { + Ok(()) + } + } + } + impl private::SockaddrLikePriv for LinkAddr {} + impl SockaddrLike for LinkAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, + len: Option) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_LINK { + return None; + } + Some(Self(ptr::read_unaligned(addr as *const _))) + } + } + + impl AsRef for LinkAddr { + fn as_ref(&self) -> &libc::sockaddr_dl { + &self.0 + } + } + + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub mod vsock { + use super::*; + use crate::sys::socket::addr::AddressFamily; + use libc::{sa_family_t, sockaddr_vm}; + use std::hash::{Hash, Hasher}; + use std::{fmt, mem}; + + /// Socket address for VMWare VSockets protocol + /// + /// # References + /// + /// [vsock(7)](https://man7.org/linux/man-pages/man7/vsock.7.html) + #[derive(Copy, Clone)] + #[repr(transparent)] + pub struct VsockAddr(pub(in super::super) sockaddr_vm); + + impl private::SockaddrLikePriv for VsockAddr {} + impl SockaddrLike for VsockAddr { + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option, + ) -> Option + where + Self: Sized, + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_VSOCK { + return None; + } + Some(Self(ptr::read_unaligned(addr as *const _))) + } + } + + impl AsRef for VsockAddr { + fn as_ref(&self) -> &libc::sockaddr_vm { + &self.0 + } + } + + impl PartialEq for VsockAddr { + fn eq(&self, other: &Self) -> bool { + let (inner, other) = (self.0, other.0); + (inner.svm_family, inner.svm_cid, inner.svm_port) + == (other.svm_family, other.svm_cid, other.svm_port) + } + } + + impl Eq for VsockAddr {} + + impl Hash for VsockAddr { + fn hash(&self, s: &mut H) { + let inner = self.0; + (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s); + } + } + + /// VSOCK Address + /// + /// The address for AF_VSOCK socket is defined as a combination of a + /// 32-bit Context Identifier (CID) and a 32-bit port number. + impl VsockAddr { + /// Construct a `VsockAddr` from its raw fields. + pub fn new(cid: u32, port: u32) -> VsockAddr { + let mut addr: sockaddr_vm = unsafe { mem::zeroed() }; + addr.svm_family = AddressFamily::Vsock as sa_family_t; + addr.svm_cid = cid; + addr.svm_port = port; + + VsockAddr(addr) + } + + /// Context Identifier (CID) + pub fn cid(&self) -> u32 { + self.0.svm_cid + } + + /// Port number + pub fn port(&self) -> u32 { + self.0.svm_port + } + } + + impl fmt::Display for VsockAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "cid: {} port: {}", self.cid(), self.port()) + } + } + + impl fmt::Debug for VsockAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + mod types { + use super::*; + + #[test] + fn test_ipv4addr_to_libc() { + let s = std::net::Ipv4Addr::new(1, 2, 3, 4); + let l = ipv4addr_to_libc(s); + assert_eq!(l.s_addr, u32::to_be(0x01020304)); + } + + #[test] + fn test_ipv6addr_to_libc() { + let s = std::net::Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8); + let l = ipv6addr_to_libc(&s); + assert_eq!( + l.s6_addr, + [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8] + ); + } + } + + mod link { + #![allow(clippy::cast_ptr_alignment)] + + #[cfg(any( + target_os = "ios", + target_os = "macos", + target_os = "illumos" + ))] + use super::super::super::socklen_t; + use super::*; + + /// Don't panic when trying to display an empty datalink address + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[test] + fn test_datalink_display() { + use super::super::LinkAddr; + use std::mem; + + let la = LinkAddr(libc::sockaddr_dl { + sdl_len: 56, + sdl_family: 18, + sdl_index: 5, + sdl_type: 24, + sdl_nlen: 3, + sdl_alen: 0, + sdl_slen: 0, + ..unsafe { mem::zeroed() } + }); + format!("{}", la); + } + + #[cfg(all( + any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ), + target_endian = "little" + ))] + #[test] + fn linux_loopback() { + #[repr(align(2))] + struct Raw([u8; 20]); + + let bytes = Raw([ + 17u8, 0, 0, 0, 1, 0, 0, 0, 4, 3, 0, 6, 1, 2, 3, 4, 5, 6, 0, 0, + ]); + let sa = bytes.0.as_ptr() as *const libc::sockaddr; + let len = None; + let sock_addr = + unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); + assert_eq!(sock_addr.family(), Some(AddressFamily::Packet)); + match sock_addr.as_link_addr() { + Some(dl) => assert_eq!(dl.addr(), Some([1, 2, 3, 4, 5, 6])), + None => panic!("Can't unwrap sockaddr storage"), + } + } + + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[test] + fn macos_loopback() { + let bytes = + [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0]; + let sa = bytes.as_ptr() as *const libc::sockaddr; + let len = Some(bytes.len() as socklen_t); + let sock_addr = + unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); + assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); + match sock_addr.as_link_addr() { + Some(dl) => { + assert!(dl.addr().is_none()); + } + None => panic!("Can't unwrap sockaddr storage"), + } + } + + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[test] + fn macos_tap() { + let bytes = [ + 20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, + 76, -80, + ]; + let ptr = bytes.as_ptr(); + let sa = ptr as *const libc::sockaddr; + let len = Some(bytes.len() as socklen_t); + + let sock_addr = + unsafe { SockaddrStorage::from_raw(sa, len).unwrap() }; + assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); + match sock_addr.as_link_addr() { + Some(dl) => { + assert_eq!(dl.addr(), Some([24u8, 101, 144, 221, 76, 176])) + } + None => panic!("Can't unwrap sockaddr storage"), + } + } + + #[cfg(target_os = "illumos")] + #[test] + fn illumos_tap() { + let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176]; + let ptr = bytes.as_ptr(); + let sa = ptr as *const libc::sockaddr; + let len = Some(bytes.len() as socklen_t); + let _sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }; + + assert!(_sock_addr.is_some()); + + let sock_addr = _sock_addr.unwrap(); + + assert_eq!(sock_addr.family().unwrap(), AddressFamily::Link); + + assert_eq!( + sock_addr.as_link_addr().unwrap().addr(), + Some([24u8, 101, 144, 221, 76, 176]) + ); + } + + #[test] + fn size() { + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd", + target_os = "haiku" + ))] + let l = mem::size_of::(); + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] + let l = mem::size_of::(); + assert_eq!(LinkAddr::size() as usize, l); + } + } + + mod sockaddr_in { + use super::*; + use std::str::FromStr; + + #[test] + fn display() { + let s = "127.0.0.1:8080"; + let addr = SockaddrIn::from_str(s).unwrap(); + assert_eq!(s, format!("{}", addr)); + } + + #[test] + fn size() { + assert_eq!( + mem::size_of::(), + SockaddrIn::size() as usize + ); + } + } + + mod sockaddr_in6 { + use super::*; + use std::str::FromStr; + + #[test] + fn display() { + let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; + let addr = SockaddrIn6::from_str(s).unwrap(); + assert_eq!(s, format!("{}", addr)); + } + + #[test] + fn size() { + assert_eq!( + mem::size_of::(), + SockaddrIn6::size() as usize + ); + } + + #[test] + // Ensure that we can convert to-and-from std::net variants without change. + fn to_and_from() { + let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; + let mut nix_sin6 = SockaddrIn6::from_str(s).unwrap(); + nix_sin6.0.sin6_flowinfo = 0x12345678; + nix_sin6.0.sin6_scope_id = 0x9abcdef0; + + let std_sin6 : std::net::SocketAddrV6 = nix_sin6.into(); + assert_eq!(nix_sin6, std_sin6.into()); + } + } + + mod sockaddr_storage { + use super::*; + + #[test] + fn from_sockaddr_un_named() { + let ua = UnixAddr::new("/var/run/mysock").unwrap(); + let ptr = ua.as_ptr() as *const libc::sockaddr; + let ss = unsafe { + SockaddrStorage::from_raw(ptr, Some(ua.len())) + }.unwrap(); + assert_eq!(ss.len(), ua.len()); + } + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[test] + fn from_sockaddr_un_abstract_named() { + let name = String::from("nix\0abstract\0test"); + let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap(); + let ptr = ua.as_ptr() as *const libc::sockaddr; + let ss = unsafe { + SockaddrStorage::from_raw(ptr, Some(ua.len())) + }.unwrap(); + assert_eq!(ss.len(), ua.len()); + } + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[test] + fn from_sockaddr_un_abstract_unnamed() { + let ua = UnixAddr::new_unnamed(); + let ptr = ua.as_ptr() as *const libc::sockaddr; + let ss = unsafe { + SockaddrStorage::from_raw(ptr, Some(ua.len())) + }.unwrap(); + assert_eq!(ss.len(), ua.len()); + } + } + + mod unixaddr { + use super::*; + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[test] + fn abstract_sun_path() { + let name = String::from("nix\0abstract\0test"); + let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); + + let sun_path1 = + unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] }; + let sun_path2 = [ + 0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, + 116, 101, 115, 116, + ]; + assert_eq!(sun_path1, sun_path2); + } + + #[test] + fn size() { + assert_eq!( + mem::size_of::(), + UnixAddr::size() as usize + ); + } + } +} diff --git a/vendor/nix-0.26.2/src/sys/socket/mod.rs b/vendor/nix-0.26.2/src/sys/socket/mod.rs new file mode 100644 index 0000000000000..8513b6fbe7c3a --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/socket/mod.rs @@ -0,0 +1,2487 @@ +//! Socket interface functions +//! +//! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html) +#[cfg(target_os = "linux")] +#[cfg(feature = "uio")] +use crate::sys::time::TimeSpec; +#[cfg(feature = "uio")] +use crate::sys::time::TimeVal; +use crate::{errno::Errno, Result}; +use cfg_if::cfg_if; +use libc::{ + self, c_int, c_void, iovec, size_t, socklen_t, CMSG_DATA, CMSG_FIRSTHDR, + CMSG_LEN, CMSG_NXTHDR, +}; +use std::convert::{TryFrom, TryInto}; +use std::io::{IoSlice, IoSliceMut}; +#[cfg(feature = "net")] +use std::net; +use std::os::unix::io::RawFd; +use std::{mem, ptr, slice}; + +#[deny(missing_docs)] +mod addr; +#[deny(missing_docs)] +pub mod sockopt; + +/* + * + * ===== Re-exports ===== + * + */ + +pub use self::addr::{SockaddrLike, SockaddrStorage}; + +#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] +#[allow(deprecated)] +pub use self::addr::{AddressFamily, SockAddr, UnixAddr}; +#[cfg(any(target_os = "illumos", target_os = "solaris"))] +#[allow(deprecated)] +pub use self::addr::{AddressFamily, SockAddr, UnixAddr}; +#[allow(deprecated)] +#[cfg(not(any( + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" +)))] +#[cfg(feature = "net")] +pub use self::addr::{ + InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, LinkAddr, SockaddrIn, SockaddrIn6, +}; +#[allow(deprecated)] +#[cfg(any( + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" +))] +#[cfg(feature = "net")] +pub use self::addr::{ + InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, SockaddrIn, SockaddrIn6, +}; + +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use crate::sys::socket::addr::alg::AlgAddr; +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use crate::sys::socket::addr::netlink::NetlinkAddr; +#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(feature = "ioctl")] +pub use crate::sys::socket::addr::sys_control::SysControlAddr; +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use crate::sys::socket::addr::vsock::VsockAddr; + +#[cfg(feature = "uio")] +pub use libc::{cmsghdr, msghdr}; +pub use libc::{sa_family_t, sockaddr, sockaddr_storage, sockaddr_un}; +#[cfg(feature = "net")] +pub use libc::{sockaddr_in, sockaddr_in6}; + +// Needed by the cmsg_space macro +#[doc(hidden)] +pub use libc::{c_uint, CMSG_SPACE}; + +#[cfg(feature = "net")] +use crate::sys::socket::addr::{ipv4addr_to_libc, ipv6addr_to_libc}; + +/// These constants are used to specify the communication semantics +/// when creating a socket with [`socket()`](fn.socket.html) +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[repr(i32)] +#[non_exhaustive] +pub enum SockType { + /// Provides sequenced, reliable, two-way, connection- + /// based byte streams. An out-of-band data transmission + /// mechanism may be supported. + Stream = libc::SOCK_STREAM, + /// Supports datagrams (connectionless, unreliable + /// messages of a fixed maximum length). + Datagram = libc::SOCK_DGRAM, + /// Provides a sequenced, reliable, two-way connection- + /// based data transmission path for datagrams of fixed + /// maximum length; a consumer is required to read an + /// entire packet with each input system call. + SeqPacket = libc::SOCK_SEQPACKET, + /// Provides raw network protocol access. + Raw = libc::SOCK_RAW, + /// Provides a reliable datagram layer that does not + /// guarantee ordering. + #[cfg(not(any(target_os = "haiku")))] + Rdm = libc::SOCK_RDM, +} +// The TryFrom impl could've been derived using libc_enum!. But for +// backwards-compatibility with Nix-0.25.0 we manually implement it, so as to +// keep the old variant names. +impl TryFrom for SockType { + type Error = crate::Error; + + fn try_from(x: i32) -> Result { + match x { + libc::SOCK_STREAM => Ok(Self::Stream), + libc::SOCK_DGRAM => Ok(Self::Datagram), + libc::SOCK_SEQPACKET => Ok(Self::SeqPacket), + libc::SOCK_RAW => Ok(Self::Raw), + #[cfg(not(any(target_os = "haiku")))] + libc::SOCK_RDM => Ok(Self::Rdm), + _ => Err(Errno::EINVAL) + } + } +} + +/// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) +/// to specify the protocol to use. +#[repr(i32)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[non_exhaustive] +pub enum SockProtocol { + /// TCP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) + Tcp = libc::IPPROTO_TCP, + /// UDP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) + Udp = libc::IPPROTO_UDP, + /// Raw sockets ([raw(7)](https://man7.org/linux/man-pages/man7/raw.7.html)) + Raw = libc::IPPROTO_RAW, + /// Allows applications and other KEXTs to be notified when certain kernel events occur + /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + KextEvent = libc::SYSPROTO_EVENT, + /// Allows applications to configure and control a KEXT + /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + KextControl = libc::SYSPROTO_CONTROL, + /// Receives routing and link updates and may be used to modify the routing tables (both IPv4 and IPv6), IP addresses, link + // parameters, neighbor setups, queueing disciplines, traffic classes and packet classifiers + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkRoute = libc::NETLINK_ROUTE, + /// Reserved for user-mode socket protocols + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkUserSock = libc::NETLINK_USERSOCK, + /// Query information about sockets of various protocol families from the kernel + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkSockDiag = libc::NETLINK_SOCK_DIAG, + /// SELinux event notifications. + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkSELinux = libc::NETLINK_SELINUX, + /// Open-iSCSI + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkISCSI = libc::NETLINK_ISCSI, + /// Auditing + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkAudit = libc::NETLINK_AUDIT, + /// Access to FIB lookup from user space + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP, + /// Netfilter subsystem + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkNetFilter = libc::NETLINK_NETFILTER, + /// SCSI Transports + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT, + /// Infiniband RDMA + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkRDMA = libc::NETLINK_RDMA, + /// Transport IPv6 packets from netfilter to user space. Used by ip6_queue kernel module. + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkIPv6Firewall = libc::NETLINK_IP6_FW, + /// DECnet routing messages + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG, + /// Kernel messages to user space + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT, + /// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow + /// configuration of the kernel crypto API. + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkCrypto = libc::NETLINK_CRYPTO, + /// Non-DIX type protocol number defined for the Ethernet IEEE 802.3 interface that allows packets of all protocols + /// defined in the interface to be received. + /// ([ref](https://man7.org/linux/man-pages/man7/packet.7.html)) + // The protocol number is fed into the socket syscall in network byte order. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + EthAll = libc::ETH_P_ALL.to_be(), +} + +#[cfg(any(target_os = "linux"))] +libc_bitflags! { + /// Configuration flags for `SO_TIMESTAMPING` interface + /// + /// For use with [`Timestamping`][sockopt::Timestamping]. + /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) + pub struct TimestampingFlag: c_uint { + /// Report any software timestamps when available. + SOF_TIMESTAMPING_SOFTWARE; + /// Report hardware timestamps as generated by SOF_TIMESTAMPING_TX_HARDWARE when available. + SOF_TIMESTAMPING_RAW_HARDWARE; + /// Collect transmiting timestamps as reported by hardware + SOF_TIMESTAMPING_TX_HARDWARE; + /// Collect transmiting timestamps as reported by software + SOF_TIMESTAMPING_TX_SOFTWARE; + /// Collect receiving timestamps as reported by hardware + SOF_TIMESTAMPING_RX_HARDWARE; + /// Collect receiving timestamps as reported by software + SOF_TIMESTAMPING_RX_SOFTWARE; + } +} + +libc_bitflags! { + /// Additional socket options + pub struct SockFlag: c_int { + /// Set non-blocking mode on the new socket + #[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + SOCK_NONBLOCK; + /// Set close-on-exec on the new descriptor + #[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + SOCK_CLOEXEC; + /// Return `EPIPE` instead of raising `SIGPIPE` + #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + SOCK_NOSIGPIPE; + /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)` + /// to the DNS port (typically 53) + #[cfg(target_os = "openbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + SOCK_DNS; + } +} + +libc_bitflags! { + /// Flags for send/recv and their relatives + pub struct MsgFlags: c_int { + /// Sends or requests out-of-band data on sockets that support this notion + /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also + /// support out-of-band data. + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 + MSG_OOB; + /// Peeks at an incoming message. The data is treated as unread and the next + /// [`recv()`](fn.recv.html) + /// or similar function shall still return this data. + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 + MSG_PEEK; + /// Receive operation blocks until the full amount of data can be + /// returned. The function may return smaller amount of data if a signal + /// is caught, an error or disconnect occurs. + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 + MSG_WAITALL; + /// Enables nonblocking operation; if the operation would block, + /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar + /// behavior to setting the `O_NONBLOCK` flag + /// (via the [`fcntl`](../../fcntl/fn.fcntl.html) + /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per- + /// call option, whereas `O_NONBLOCK` is a setting on the open file + /// description (see [open(2)](https://man7.org/linux/man-pages/man2/open.2.html)), + /// which will affect all threads in + /// the calling process and as well as other processes that hold + /// file descriptors referring to the same open file description. + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 + MSG_DONTWAIT; + /// Receive flags: Control Data was discarded (buffer too small) + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 + MSG_CTRUNC; + /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram + /// (since Linux 2.4.27/2.6.8), + /// netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4) + /// sockets: return the real length of the packet or datagram, even + /// when it was longer than the passed buffer. Not implemented for UNIX + /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets. + /// + /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp). + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 + MSG_TRUNC; + /// Terminates a record (when this notion is supported, as for + /// sockets of type [`SeqPacket`](enum.SockType.html)). + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 + MSG_EOR; + /// This flag specifies that queued errors should be received from + /// the socket error queue. (For more details, see + /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 + MSG_ERRQUEUE; + /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain + /// file descriptor using the `SCM_RIGHTS` operation (described in + /// [unix(7)](https://linux.die.net/man/7/unix)). + /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of + /// [open(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html). + /// + /// Only used in [`recvmsg`](fn.recvmsg.html) function. + #[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 + MSG_CMSG_CLOEXEC; + /// Requests not to send `SIGPIPE` errors when the other end breaks the connection. + /// (For more details, see [send(2)](https://linux.die.net/man/2/send)). + #[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 + MSG_NOSIGNAL; + } +} + +cfg_if! { + if #[cfg(any(target_os = "android", target_os = "linux"))] { + /// Unix credentials of the sending process. + /// + /// This struct is used with the `SO_PEERCRED` ancillary message + /// and the `SCM_CREDENTIALS` control message for UNIX sockets. + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct UnixCredentials(libc::ucred); + + impl UnixCredentials { + /// Creates a new instance with the credentials of the current process + pub fn new() -> Self { + // Safe because these FFI functions are inherently safe + unsafe { + UnixCredentials(libc::ucred { + pid: libc::getpid(), + uid: libc::getuid(), + gid: libc::getgid() + }) + } + } + + /// Returns the process identifier + pub fn pid(&self) -> libc::pid_t { + self.0.pid + } + + /// Returns the user identifier + pub fn uid(&self) -> libc::uid_t { + self.0.uid + } + + /// Returns the group identifier + pub fn gid(&self) -> libc::gid_t { + self.0.gid + } + } + + impl Default for UnixCredentials { + fn default() -> Self { + Self::new() + } + } + + impl From for UnixCredentials { + fn from(cred: libc::ucred) -> Self { + UnixCredentials(cred) + } + } + + impl From for libc::ucred { + fn from(uc: UnixCredentials) -> Self { + uc.0 + } + } + } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] { + /// Unix credentials of the sending process. + /// + /// This struct is used with the `SCM_CREDS` ancillary message for UNIX sockets. + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct UnixCredentials(libc::cmsgcred); + + impl UnixCredentials { + /// Returns the process identifier + pub fn pid(&self) -> libc::pid_t { + self.0.cmcred_pid + } + + /// Returns the real user identifier + pub fn uid(&self) -> libc::uid_t { + self.0.cmcred_uid + } + + /// Returns the effective user identifier + pub fn euid(&self) -> libc::uid_t { + self.0.cmcred_euid + } + + /// Returns the real group identifier + pub fn gid(&self) -> libc::gid_t { + self.0.cmcred_gid + } + + /// Returns a list group identifiers (the first one being the effective GID) + pub fn groups(&self) -> &[libc::gid_t] { + unsafe { + slice::from_raw_parts( + self.0.cmcred_groups.as_ptr() as *const libc::gid_t, + self.0.cmcred_ngroups as _ + ) + } + } + } + + impl From for UnixCredentials { + fn from(cred: libc::cmsgcred) -> Self { + UnixCredentials(cred) + } + } + } +} + +cfg_if! { + if #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "ios" + ))] { + /// Return type of [`LocalPeerCred`](crate::sys::socket::sockopt::LocalPeerCred) + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct XuCred(libc::xucred); + + impl XuCred { + /// Structure layout version + pub fn version(&self) -> u32 { + self.0.cr_version + } + + /// Effective user ID + pub fn uid(&self) -> libc::uid_t { + self.0.cr_uid + } + + /// Returns a list of group identifiers (the first one being the + /// effective GID) + pub fn groups(&self) -> &[libc::gid_t] { + &self.0.cr_groups + } + } + } +} + +feature! { +#![feature = "net"] +/// Request for multicast socket operations +/// +/// This is a wrapper type around `ip_mreq`. +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct IpMembershipRequest(libc::ip_mreq); + +impl IpMembershipRequest { + /// Instantiate a new `IpMembershipRequest` + /// + /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface. + pub fn new(group: net::Ipv4Addr, interface: Option) + -> Self + { + let imr_addr = match interface { + None => net::Ipv4Addr::UNSPECIFIED, + Some(addr) => addr + }; + IpMembershipRequest(libc::ip_mreq { + imr_multiaddr: ipv4addr_to_libc(group), + imr_interface: ipv4addr_to_libc(imr_addr) + }) + } +} + +/// Request for ipv6 multicast socket operations +/// +/// This is a wrapper type around `ipv6_mreq`. +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct Ipv6MembershipRequest(libc::ipv6_mreq); + +impl Ipv6MembershipRequest { + /// Instantiate a new `Ipv6MembershipRequest` + pub const fn new(group: net::Ipv6Addr) -> Self { + Ipv6MembershipRequest(libc::ipv6_mreq { + ipv6mr_multiaddr: ipv6addr_to_libc(&group), + ipv6mr_interface: 0, + }) + } +} +} + +feature! { +#![feature = "uio"] + +/// Create a buffer large enough for storing some control messages as returned +/// by [`recvmsg`](fn.recvmsg.html). +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate nix; +/// # use nix::sys::time::TimeVal; +/// # use std::os::unix::io::RawFd; +/// # fn main() { +/// // Create a buffer for a `ControlMessageOwned::ScmTimestamp` message +/// let _ = cmsg_space!(TimeVal); +/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message +/// // with two file descriptors +/// let _ = cmsg_space!([RawFd; 2]); +/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message +/// // and a `ControlMessageOwned::ScmTimestamp` message +/// let _ = cmsg_space!(RawFd, TimeVal); +/// # } +/// ``` +// Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a +// stack-allocated array. +#[macro_export] +macro_rules! cmsg_space { + ( $( $x:ty ),* ) => { + { + let mut space = 0; + $( + // CMSG_SPACE is always safe + space += unsafe { + $crate::sys::socket::CMSG_SPACE(::std::mem::size_of::<$x>() as $crate::sys::socket::c_uint) + } as usize; + )* + Vec::::with_capacity(space) + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +/// Contains outcome of sending or receiving a message +/// +/// Use [`cmsgs`][RecvMsg::cmsgs] to access all the control messages present, and +/// [`iovs`][RecvMsg::iovs`] to access underlying io slices. +pub struct RecvMsg<'a, 's, S> { + pub bytes: usize, + cmsghdr: Option<&'a cmsghdr>, + pub address: Option, + pub flags: MsgFlags, + iobufs: std::marker::PhantomData<& 's()>, + mhdr: msghdr, +} + +impl<'a, S> RecvMsg<'a, '_, S> { + /// Iterate over the valid control messages pointed to by this + /// msghdr. + pub fn cmsgs(&self) -> CmsgIterator { + CmsgIterator { + cmsghdr: self.cmsghdr, + mhdr: &self.mhdr + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct CmsgIterator<'a> { + /// Control message buffer to decode from. Must adhere to cmsg alignment. + cmsghdr: Option<&'a cmsghdr>, + mhdr: &'a msghdr +} + +impl<'a> Iterator for CmsgIterator<'a> { + type Item = ControlMessageOwned; + + fn next(&mut self) -> Option { + match self.cmsghdr { + None => None, // No more messages + Some(hdr) => { + // Get the data. + // Safe if cmsghdr points to valid data returned by recvmsg(2) + let cm = unsafe { Some(ControlMessageOwned::decode_from(hdr))}; + // Advance the internal pointer. Safe if mhdr and cmsghdr point + // to valid data returned by recvmsg(2) + self.cmsghdr = unsafe { + let p = CMSG_NXTHDR(self.mhdr as *const _, hdr as *const _); + p.as_ref() + }; + cm + } + } + } +} + +/// A type-safe wrapper around a single control message, as used with +/// [`recvmsg`](#fn.recvmsg). +/// +/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) +// Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and +// sendmsg. However, on some platforms the messages returned by recvmsg may be +// unaligned. ControlMessageOwned takes those messages by copy, obviating any +// alignment issues. +// +// See https://github.com/nix-rust/nix/issues/999 +#[derive(Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum ControlMessageOwned { + /// Received version of [`ControlMessage::ScmRights`] + ScmRights(Vec), + /// Received version of [`ControlMessage::ScmCredentials`] + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ScmCredentials(UnixCredentials), + /// Received version of [`ControlMessage::ScmCreds`] + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ScmCreds(UnixCredentials), + /// A message of type `SCM_TIMESTAMP`, containing the time the + /// packet was received by the kernel. + /// + /// See the kernel's explanation in "SO_TIMESTAMP" of + /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt). + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate nix; + /// # use nix::sys::socket::*; + /// # use nix::sys::time::*; + /// # use std::io::{IoSlice, IoSliceMut}; + /// # use std::time::*; + /// # use std::str::FromStr; + /// # fn main() { + /// // Set up + /// let message = "OhayÅ!".as_bytes(); + /// let in_socket = socket( + /// AddressFamily::Inet, + /// SockType::Datagram, + /// SockFlag::empty(), + /// None).unwrap(); + /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap(); + /// let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); + /// bind(in_socket, &localhost).unwrap(); + /// let address: SockaddrIn = getsockname(in_socket).unwrap(); + /// // Get initial time + /// let time0 = SystemTime::now(); + /// // Send the message + /// let iov = [IoSlice::new(message)]; + /// let flags = MsgFlags::empty(); + /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); + /// assert_eq!(message.len(), l); + /// // Receive the message + /// let mut buffer = vec![0u8; message.len()]; + /// let mut cmsgspace = cmsg_space!(TimeVal); + /// let mut iov = [IoSliceMut::new(&mut buffer)]; + /// let r = recvmsg::(in_socket, &mut iov, Some(&mut cmsgspace), flags) + /// .unwrap(); + /// let rtime = match r.cmsgs().next() { + /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime, + /// Some(_) => panic!("Unexpected control message"), + /// None => panic!("No control message") + /// }; + /// // Check the final time + /// let time1 = SystemTime::now(); + /// // the packet's received timestamp should lie in-between the two system + /// // times, unless the system clock was adjusted in the meantime. + /// let rduration = Duration::new(rtime.tv_sec() as u64, + /// rtime.tv_usec() as u32 * 1000); + /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); + /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); + /// // Close socket + /// nix::unistd::close(in_socket).unwrap(); + /// # } + /// ``` + ScmTimestamp(TimeVal), + /// A set of nanosecond resolution timestamps + /// + /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) + #[cfg(all(target_os = "linux"))] + ScmTimestampsns(Timestamps), + /// Nanoseconds resolution timestamp + /// + /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) + #[cfg(all(target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ScmTimestampns(TimeSpec), + #[cfg(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + ))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv4PacketInfo(libc::in_pktinfo), + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd", + target_os = "netbsd", + ))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv6PacketInfo(libc::in6_pktinfo), + #[cfg(any( + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv4RecvIf(libc::sockaddr_dl), + #[cfg(any( + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv4RecvDstAddr(libc::in_addr), + #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv4OrigDstAddr(libc::sockaddr_in), + #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv6OrigDstAddr(libc::sockaddr_in6), + + /// UDP Generic Receive Offload (GRO) allows receiving multiple UDP + /// packets from a single sender. + /// Fixed-size payloads are following one by one in a receive buffer. + /// This Control Message indicates the size of all smaller packets, + /// except, maybe, the last one. + /// + /// `UdpGroSegment` socket option should be enabled on a socket + /// to allow receiving GRO packets. + #[cfg(target_os = "linux")] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + UdpGroSegments(u16), + + /// SO_RXQ_OVFL indicates that an unsigned 32 bit value + /// ancilliary msg (cmsg) should be attached to recieved + /// skbs indicating the number of packets dropped by the + /// socket between the last recieved packet and this + /// received packet. + /// + /// `RxqOvfl` socket option should be enabled on a socket + /// to allow receiving the drop counter. + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + RxqOvfl(u32), + + /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv4RecvErr(libc::sock_extended_err, Option), + /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv6RecvErr(libc::sock_extended_err, Option), + + /// Catch-all variant for unimplemented cmsg types. + #[doc(hidden)] + Unknown(UnknownCmsg), +} + +/// For representing packet timestamps via `SO_TIMESTAMPING` interface +#[cfg(all(target_os = "linux"))] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct Timestamps { + /// software based timestamp, usually one containing data + pub system: TimeSpec, + /// legacy timestamp, usually empty + pub hw_trans: TimeSpec, + /// hardware based timestamp + pub hw_raw: TimeSpec, +} + +impl ControlMessageOwned { + /// Decodes a `ControlMessageOwned` from raw bytes. + /// + /// This is only safe to call if the data is correct for the message type + /// specified in the header. Normally, the kernel ensures that this is the + /// case. "Correct" in this case includes correct length, alignment and + /// actual content. + // Clippy complains about the pointer alignment of `p`, not understanding + // that it's being fed to a function that can handle that. + #[allow(clippy::cast_ptr_alignment)] + unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned + { + let p = CMSG_DATA(header); + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + let len = header as *const _ as usize + header.cmsg_len as usize + - p as usize; + match (header.cmsg_level, header.cmsg_type) { + (libc::SOL_SOCKET, libc::SCM_RIGHTS) => { + let n = len / mem::size_of::(); + let mut fds = Vec::with_capacity(n); + for i in 0..n { + let fdp = (p as *const RawFd).add(i); + fds.push(ptr::read_unaligned(fdp)); + } + ControlMessageOwned::ScmRights(fds) + }, + #[cfg(any(target_os = "android", target_os = "linux"))] + (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => { + let cred: libc::ucred = ptr::read_unaligned(p as *const _); + ControlMessageOwned::ScmCredentials(cred.into()) + } + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + (libc::SOL_SOCKET, libc::SCM_CREDS) => { + let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _); + ControlMessageOwned::ScmCreds(cred.into()) + } + #[cfg(not(target_os = "haiku"))] + (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => { + let tv: libc::timeval = ptr::read_unaligned(p as *const _); + ControlMessageOwned::ScmTimestamp(TimeVal::from(tv)) + }, + #[cfg(all(target_os = "linux"))] + (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => { + let ts: libc::timespec = ptr::read_unaligned(p as *const _); + ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts)) + } + #[cfg(all(target_os = "linux"))] + (libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => { + let tp = p as *const libc::timespec; + let ts: libc::timespec = ptr::read_unaligned(tp); + let system = TimeSpec::from(ts); + let ts: libc::timespec = ptr::read_unaligned(tp.add(1)); + let hw_trans = TimeSpec::from(ts); + let ts: libc::timespec = ptr::read_unaligned(tp.add(2)); + let hw_raw = TimeSpec::from(ts); + let timestamping = Timestamps { system, hw_trans, hw_raw }; + ControlMessageOwned::ScmTimestampsns(timestamping) + } + #[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos" + ))] + #[cfg(feature = "net")] + (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => { + let info = ptr::read_unaligned(p as *const libc::in6_pktinfo); + ControlMessageOwned::Ipv6PacketInfo(info) + } + #[cfg(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + ))] + #[cfg(feature = "net")] + (libc::IPPROTO_IP, libc::IP_PKTINFO) => { + let info = ptr::read_unaligned(p as *const libc::in_pktinfo); + ControlMessageOwned::Ipv4PacketInfo(info) + } + #[cfg(any( + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[cfg(feature = "net")] + (libc::IPPROTO_IP, libc::IP_RECVIF) => { + let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl); + ControlMessageOwned::Ipv4RecvIf(dl) + }, + #[cfg(any( + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[cfg(feature = "net")] + (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => { + let dl = ptr::read_unaligned(p as *const libc::in_addr); + ControlMessageOwned::Ipv4RecvDstAddr(dl) + }, + #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(feature = "net")] + (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => { + let dl = ptr::read_unaligned(p as *const libc::sockaddr_in); + ControlMessageOwned::Ipv4OrigDstAddr(dl) + }, + #[cfg(target_os = "linux")] + #[cfg(feature = "net")] + (libc::SOL_UDP, libc::UDP_GRO) => { + let gso_size: u16 = ptr::read_unaligned(p as *const _); + ControlMessageOwned::UdpGroSegments(gso_size) + }, + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => { + let drop_counter = ptr::read_unaligned(p as *const u32); + ControlMessageOwned::RxqOvfl(drop_counter) + }, + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] + (libc::IPPROTO_IP, libc::IP_RECVERR) => { + let (err, addr) = Self::recv_err_helper::(p, len); + ControlMessageOwned::Ipv4RecvErr(err, addr) + }, + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] + (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => { + let (err, addr) = Self::recv_err_helper::(p, len); + ControlMessageOwned::Ipv6RecvErr(err, addr) + }, + #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(feature = "net")] + (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => { + let dl = ptr::read_unaligned(p as *const libc::sockaddr_in6); + ControlMessageOwned::Ipv6OrigDstAddr(dl) + }, + (_, _) => { + let sl = slice::from_raw_parts(p, len); + let ucmsg = UnknownCmsg(*header, Vec::::from(sl)); + ControlMessageOwned::Unknown(ucmsg) + } + } + } + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] + #[allow(clippy::cast_ptr_alignment)] // False positive + unsafe fn recv_err_helper(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option) { + let ee = p as *const libc::sock_extended_err; + let err = ptr::read_unaligned(ee); + + // For errors originating on the network, SO_EE_OFFENDER(ee) points inside the p[..len] + // CMSG_DATA buffer. For local errors, there is no address included in the control + // message, and SO_EE_OFFENDER(ee) points beyond the end of the buffer. So, we need to + // validate that the address object is in-bounds before we attempt to copy it. + let addrp = libc::SO_EE_OFFENDER(ee) as *const T; + + if addrp.offset(1) as usize - (p as usize) > len { + (err, None) + } else { + (err, Some(ptr::read_unaligned(addrp))) + } + } +} + +/// A type-safe zero-copy wrapper around a single control message, as used wih +/// [`sendmsg`](#fn.sendmsg). More types may be added to this enum; do not +/// exhaustively pattern-match it. +/// +/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum ControlMessage<'a> { + /// A message of type `SCM_RIGHTS`, containing an array of file + /// descriptors passed between processes. + /// + /// See the description in the "Ancillary messages" section of the + /// [unix(7) man page](https://man7.org/linux/man-pages/man7/unix.7.html). + /// + /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't + /// recommended since it causes platform-dependent behaviour: It might + /// swallow all but the first `ScmRights` message or fail with `EINVAL`. + /// Instead, you can put all fds to be passed into a single `ScmRights` + /// message. + ScmRights(&'a [RawFd]), + /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of + /// a process connected to the socket. + /// + /// This is similar to the socket option `SO_PEERCRED`, but requires a + /// process to explicitly send its credentials. A process running as root is + /// allowed to specify any credentials, while credentials sent by other + /// processes are verified by the kernel. + /// + /// For further information, please refer to the + /// [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html) man page. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ScmCredentials(&'a UnixCredentials), + /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of + /// a process connected to the socket. + /// + /// This is similar to the socket options `LOCAL_CREDS` and `LOCAL_PEERCRED`, but + /// requires a process to explicitly send its credentials. + /// + /// Credentials are always overwritten by the kernel, so this variant does have + /// any data, unlike the receive-side + /// [`ControlMessageOwned::ScmCreds`]. + /// + /// For further information, please refer to the + /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page. + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ScmCreds, + + /// Set IV for `AF_ALG` crypto API. + /// + /// For further information, please refer to the + /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) + #[cfg(any( + target_os = "android", + target_os = "linux", + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + AlgSetIv(&'a [u8]), + /// Set crypto operation for `AF_ALG` crypto API. It may be one of + /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT` + /// + /// For further information, please refer to the + /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) + #[cfg(any( + target_os = "android", + target_os = "linux", + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + AlgSetOp(&'a libc::c_int), + /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms) + /// for `AF_ALG` crypto API. + /// + /// For further information, please refer to the + /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) + #[cfg(any( + target_os = "android", + target_os = "linux", + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + AlgSetAeadAssoclen(&'a u32), + + /// UDP GSO makes it possible for applications to generate network packets + /// for a virtual MTU much greater than the real one. + /// The length of the send data no longer matches the expected length on + /// the wire. + /// The size of the datagram payload as it should appear on the wire may be + /// passed through this control message. + /// Send buffer should consist of multiple fixed-size wire payloads + /// following one by one, and the last, possibly smaller one. + #[cfg(target_os = "linux")] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + UdpGsoSegments(&'a u16), + + /// Configure the sending addressing and interface for v4 + /// + /// For further information, please refer to the + /// [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html) man page. + #[cfg(any(target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "android", + target_os = "ios",))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv4PacketInfo(&'a libc::in_pktinfo), + + /// Configure the sending addressing and interface for v6 + /// + /// For further information, please refer to the + /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page. + #[cfg(any(target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "freebsd", + target_os = "android", + target_os = "ios",))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv6PacketInfo(&'a libc::in6_pktinfo), + + /// Configure the IPv4 source address with `IP_SENDSRCADDR`. + #[cfg(any( + target_os = "netbsd", + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + ))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv4SendSrcAddr(&'a libc::in_addr), + + /// SO_RXQ_OVFL indicates that an unsigned 32 bit value + /// ancilliary msg (cmsg) should be attached to recieved + /// skbs indicating the number of packets dropped by the + /// socket between the last recieved packet and this + /// received packet. + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + RxqOvfl(&'a u32), + + /// Configure the transmission time of packets. + /// + /// For further information, please refer to the + /// [`tc-etf(8)`](https://man7.org/linux/man-pages/man8/tc-etf.8.html) man + /// page. + #[cfg(target_os = "linux")] + TxTime(&'a u64), +} + +// An opaque structure used to prevent cmsghdr from being a public type +#[doc(hidden)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct UnknownCmsg(cmsghdr, Vec); + +impl<'a> ControlMessage<'a> { + /// The value of CMSG_SPACE on this message. + /// Safe because CMSG_SPACE is always safe + fn space(&self) -> usize { + unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize} + } + + /// The value of CMSG_LEN on this message. + /// Safe because CMSG_LEN is always safe + #[cfg(any(target_os = "android", + all(target_os = "linux", not(target_env = "musl"))))] + fn cmsg_len(&self) -> usize { + unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize} + } + + #[cfg(not(any(target_os = "android", + all(target_os = "linux", not(target_env = "musl")))))] + fn cmsg_len(&self) -> libc::c_uint { + unsafe{CMSG_LEN(self.len() as libc::c_uint)} + } + + /// Return a reference to the payload data as a byte pointer + fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) { + let data_ptr = match *self { + ControlMessage::ScmRights(fds) => { + fds as *const _ as *const u8 + }, + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::ScmCredentials(creds) => { + &creds.0 as *const libc::ucred as *const u8 + } + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + ControlMessage::ScmCreds => { + // The kernel overwrites the data, we just zero it + // to make sure it's not uninitialized memory + unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) }; + return + } + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::AlgSetIv(iv) => { + #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501 + let af_alg_iv = libc::af_alg_iv { + ivlen: iv.len() as u32, + iv: [0u8; 0], + }; + + let size = mem::size_of_val(&af_alg_iv); + + unsafe { + ptr::copy_nonoverlapping( + &af_alg_iv as *const _ as *const u8, + cmsg_data, + size, + ); + ptr::copy_nonoverlapping( + iv.as_ptr(), + cmsg_data.add(size), + iv.len() + ); + }; + + return + }, + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::AlgSetOp(op) => { + op as *const _ as *const u8 + }, + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::AlgSetAeadAssoclen(len) => { + len as *const _ as *const u8 + }, + #[cfg(target_os = "linux")] + #[cfg(feature = "net")] + ControlMessage::UdpGsoSegments(gso_size) => { + gso_size as *const _ as *const u8 + }, + #[cfg(any(target_os = "linux", target_os = "macos", + target_os = "netbsd", target_os = "android", + target_os = "ios",))] + #[cfg(feature = "net")] + ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8, + #[cfg(any(target_os = "linux", target_os = "macos", + target_os = "netbsd", target_os = "freebsd", + target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] + ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8, + #[cfg(any(target_os = "netbsd", target_os = "freebsd", + target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(feature = "net")] + ControlMessage::Ipv4SendSrcAddr(addr) => addr as *const _ as *const u8, + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + ControlMessage::RxqOvfl(drop_count) => { + drop_count as *const _ as *const u8 + }, + #[cfg(target_os = "linux")] + ControlMessage::TxTime(tx_time) => { + tx_time as *const _ as *const u8 + }, + }; + unsafe { + ptr::copy_nonoverlapping( + data_ptr, + cmsg_data, + self.len() + ) + }; + } + + /// The size of the payload, excluding its cmsghdr + fn len(&self) -> usize { + match *self { + ControlMessage::ScmRights(fds) => { + mem::size_of_val(fds) + }, + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::ScmCredentials(creds) => { + mem::size_of_val(creds) + } + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + ControlMessage::ScmCreds => { + mem::size_of::() + } + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::AlgSetIv(iv) => { + mem::size_of::<&[u8]>() + iv.len() + }, + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::AlgSetOp(op) => { + mem::size_of_val(op) + }, + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::AlgSetAeadAssoclen(len) => { + mem::size_of_val(len) + }, + #[cfg(target_os = "linux")] + #[cfg(feature = "net")] + ControlMessage::UdpGsoSegments(gso_size) => { + mem::size_of_val(gso_size) + }, + #[cfg(any(target_os = "linux", target_os = "macos", + target_os = "netbsd", target_os = "android", + target_os = "ios",))] + #[cfg(feature = "net")] + ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info), + #[cfg(any(target_os = "linux", target_os = "macos", + target_os = "netbsd", target_os = "freebsd", + target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] + ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info), + #[cfg(any(target_os = "netbsd", target_os = "freebsd", + target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(feature = "net")] + ControlMessage::Ipv4SendSrcAddr(addr) => mem::size_of_val(addr), + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + ControlMessage::RxqOvfl(drop_count) => { + mem::size_of_val(drop_count) + }, + #[cfg(target_os = "linux")] + ControlMessage::TxTime(tx_time) => { + mem::size_of_val(tx_time) + }, + } + } + + /// Returns the value to put into the `cmsg_level` field of the header. + fn cmsg_level(&self) -> libc::c_int { + match *self { + ControlMessage::ScmRights(_) => libc::SOL_SOCKET, + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET, + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + ControlMessage::ScmCreds => libc::SOL_SOCKET, + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) | + ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG, + #[cfg(target_os = "linux")] + #[cfg(feature = "net")] + ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP, + #[cfg(any(target_os = "linux", target_os = "macos", + target_os = "netbsd", target_os = "android", + target_os = "ios",))] + #[cfg(feature = "net")] + ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP, + #[cfg(any(target_os = "linux", target_os = "macos", + target_os = "netbsd", target_os = "freebsd", + target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] + ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6, + #[cfg(any(target_os = "netbsd", target_os = "freebsd", + target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(feature = "net")] + ControlMessage::Ipv4SendSrcAddr(_) => libc::IPPROTO_IP, + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET, + #[cfg(target_os = "linux")] + ControlMessage::TxTime(_) => libc::SOL_SOCKET, + } + } + + /// Returns the value to put into the `cmsg_type` field of the header. + fn cmsg_type(&self) -> libc::c_int { + match *self { + ControlMessage::ScmRights(_) => libc::SCM_RIGHTS, + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS, + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + ControlMessage::ScmCreds => libc::SCM_CREDS, + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::AlgSetIv(_) => { + libc::ALG_SET_IV + }, + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::AlgSetOp(_) => { + libc::ALG_SET_OP + }, + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessage::AlgSetAeadAssoclen(_) => { + libc::ALG_SET_AEAD_ASSOCLEN + }, + #[cfg(target_os = "linux")] + #[cfg(feature = "net")] + ControlMessage::UdpGsoSegments(_) => { + libc::UDP_SEGMENT + }, + #[cfg(any(target_os = "linux", target_os = "macos", + target_os = "netbsd", target_os = "android", + target_os = "ios",))] + #[cfg(feature = "net")] + ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO, + #[cfg(any(target_os = "linux", target_os = "macos", + target_os = "netbsd", target_os = "freebsd", + target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] + ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO, + #[cfg(any(target_os = "netbsd", target_os = "freebsd", + target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(feature = "net")] + ControlMessage::Ipv4SendSrcAddr(_) => libc::IP_SENDSRCADDR, + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + ControlMessage::RxqOvfl(_) => { + libc::SO_RXQ_OVFL + }, + #[cfg(target_os = "linux")] + ControlMessage::TxTime(_) => { + libc::SCM_TXTIME + }, + } + } + + // Unsafe: cmsg must point to a valid cmsghdr with enough space to + // encode self. + unsafe fn encode_into(&self, cmsg: *mut cmsghdr) { + (*cmsg).cmsg_level = self.cmsg_level(); + (*cmsg).cmsg_type = self.cmsg_type(); + (*cmsg).cmsg_len = self.cmsg_len(); + self.copy_to_cmsg_data(CMSG_DATA(cmsg)); + } +} + + +/// Send data in scatter-gather vectors to a socket, possibly accompanied +/// by ancillary data. Optionally direct the message at the given address, +/// as with sendto. +/// +/// Allocates if cmsgs is nonempty. +/// +/// # Examples +/// When not directing to any specific address, use `()` for the generic type +/// ``` +/// # use nix::sys::socket::*; +/// # use nix::unistd::pipe; +/// # use std::io::IoSlice; +/// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, +/// SockFlag::empty()) +/// .unwrap(); +/// let (r, w) = pipe().unwrap(); +/// +/// let iov = [IoSlice::new(b"hello")]; +/// let fds = [r]; +/// let cmsg = ControlMessage::ScmRights(&fds); +/// sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(); +/// ``` +/// When directing to a specific address, the generic type will be inferred. +/// ``` +/// # use nix::sys::socket::*; +/// # use nix::unistd::pipe; +/// # use std::io::IoSlice; +/// # use std::str::FromStr; +/// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap(); +/// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), +/// None).unwrap(); +/// let (r, w) = pipe().unwrap(); +/// +/// let iov = [IoSlice::new(b"hello")]; +/// let fds = [r]; +/// let cmsg = ControlMessage::ScmRights(&fds); +/// sendmsg(fd, &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap(); +/// ``` +pub fn sendmsg(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage], + flags: MsgFlags, addr: Option<&S>) -> Result + where S: SockaddrLike +{ + let capacity = cmsgs.iter().map(|c| c.space()).sum(); + + // First size the buffer needed to hold the cmsgs. It must be zeroed, + // because subsequent code will not clear the padding bytes. + let mut cmsg_buffer = vec![0u8; capacity]; + + let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], iov, cmsgs, addr); + + let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) }; + + Errno::result(ret).map(|r| r as usize) +} + + +/// An extension of `sendmsg` that allows the caller to transmit multiple +/// messages on a socket using a single system call. This has performance +/// benefits for some applications. +/// +/// Allocations are performed for cmsgs and to build `msghdr` buffer +/// +/// # Arguments +/// +/// * `fd`: Socket file descriptor +/// * `data`: Struct that implements `IntoIterator` with `SendMmsgData` items +/// * `flags`: Optional flags passed directly to the operating system. +/// +/// # Returns +/// `Vec` with numbers of sent bytes on each sent message. +/// +/// # References +/// [`sendmsg`](fn.sendmsg.html) +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", +))] +pub fn sendmmsg<'a, XS, AS, C, I, S>( + fd: RawFd, + data: &'a mut MultiHeaders, + slices: XS, + // one address per group of slices + addrs: AS, + // shared across all the messages + cmsgs: C, + flags: MsgFlags +) -> crate::Result> + where + XS: IntoIterator, + AS: AsRef<[Option]>, + I: AsRef<[IoSlice<'a>]> + 'a, + C: AsRef<[ControlMessage<'a>]> + 'a, + S: SockaddrLike + 'a +{ + + let mut count = 0; + + + for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() { + let mut p = &mut mmsghdr.msg_hdr; + p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; + p.msg_iovlen = slice.as_ref().len() as _; + + p.msg_namelen = addr.as_ref().map_or(0, S::len); + p.msg_name = addr.as_ref().map_or(ptr::null(), S::as_ptr) as _; + + // Encode each cmsg. This must happen after initializing the header because + // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields. + // CMSG_FIRSTHDR is always safe + let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(p) }; + for cmsg in cmsgs.as_ref() { + assert_ne!(pmhdr, ptr::null_mut()); + // Safe because we know that pmhdr is valid, and we initialized it with + // sufficient space + unsafe { cmsg.encode_into(pmhdr) }; + // Safe because mhdr is valid + pmhdr = unsafe { CMSG_NXTHDR(p, pmhdr) }; + } + + count = i+1; + } + + let sent = Errno::result(unsafe { + libc::sendmmsg( + fd, + data.items.as_mut_ptr(), + count as _, + flags.bits() as _ + ) + })? as usize; + + Ok(MultiResults { + rmm: data, + current_index: 0, + received: sent + }) + +} + + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", +))] +#[derive(Debug)] +/// Preallocated structures needed for [`recvmmsg`] and [`sendmmsg`] functions +pub struct MultiHeaders { + // preallocated boxed slice of mmsghdr + items: Box<[libc::mmsghdr]>, + addresses: Box<[mem::MaybeUninit]>, + // while we are not using it directly - this is used to store control messages + // and we retain pointers to them inside items array + #[allow(dead_code)] + cmsg_buffers: Option>, + msg_controllen: usize, +} + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", +))] +impl MultiHeaders { + /// Preallocate structure used by [`recvmmsg`] and [`sendmmsg`] takes number of headers to preallocate + /// + /// `cmsg_buffer` should be created with [`cmsg_space!`] if needed + pub fn preallocate(num_slices: usize, cmsg_buffer: Option>) -> Self + where + S: Copy + SockaddrLike, + { + // we will be storing pointers to addresses inside mhdr - convert it into boxed + // slice so it can'be changed later by pushing anything into self.addresses + let mut addresses = vec![std::mem::MaybeUninit::uninit(); num_slices].into_boxed_slice(); + + let msg_controllen = cmsg_buffer.as_ref().map_or(0, |v| v.capacity()); + + // we'll need a cmsg_buffer for each slice, we preallocate a vector and split + // it into "slices" parts + let cmsg_buffers = + cmsg_buffer.map(|v| vec![0u8; v.capacity() * num_slices].into_boxed_slice()); + + let items = addresses + .iter_mut() + .enumerate() + .map(|(ix, address)| { + let (ptr, cap) = match &cmsg_buffers { + Some(v) => ((&v[ix * msg_controllen] as *const u8), msg_controllen), + None => (std::ptr::null(), 0), + }; + let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, address.as_mut_ptr()) }; + libc::mmsghdr { + msg_hdr, + msg_len: 0, + } + }) + .collect::>(); + + Self { + items: items.into_boxed_slice(), + addresses, + cmsg_buffers, + msg_controllen, + } + } +} + +/// An extension of recvmsg that allows the caller to receive multiple messages from a socket using a single system call. +/// +/// This has performance benefits for some applications. +/// +/// This method performs no allocations. +/// +/// Returns an iterator producing [`RecvMsg`], one per received messages. Each `RecvMsg` can produce +/// iterators over [`IoSlice`] with [`iovs`][RecvMsg::iovs`] and +/// `ControlMessageOwned` with [`cmsgs`][RecvMsg::cmsgs]. +/// +/// # Bugs (in underlying implementation, at least in Linux) +/// The timeout argument does not work as intended. The timeout is checked only after the receipt +/// of each datagram, so that if up to `vlen`-1 datagrams are received before the timeout expires, +/// but then no further datagrams are received, the call will block forever. +/// +/// If an error occurs after at least one message has been received, the call succeeds, and returns +/// the number of messages received. The error code is expected to be returned on a subsequent +/// call to recvmmsg(). In the current implementation, however, the error code can be +/// overwritten in the meantime by an unrelated network event on a socket, for example an +/// incoming ICMP packet. + +// On aarch64 linux using recvmmsg and trying to get hardware/kernel timestamps might not +// always produce the desired results - see https://github.com/nix-rust/nix/pull/1744 for more +// details + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", +))] +pub fn recvmmsg<'a, XS, S, I>( + fd: RawFd, + data: &'a mut MultiHeaders, + slices: XS, + flags: MsgFlags, + mut timeout: Option, +) -> crate::Result> +where + XS: IntoIterator, + I: AsRef<[IoSliceMut<'a>]> + 'a, +{ + let mut count = 0; + for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() { + let mut p = &mut mmsghdr.msg_hdr; + p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; + p.msg_iovlen = slice.as_ref().len() as _; + count = i + 1; + } + + let timeout_ptr = timeout + .as_mut() + .map_or_else(std::ptr::null_mut, |t| t as *mut _ as *mut libc::timespec); + + let received = Errno::result(unsafe { + libc::recvmmsg( + fd, + data.items.as_mut_ptr(), + count as _, + flags.bits() as _, + timeout_ptr, + ) + })? as usize; + + Ok(MultiResults { + rmm: data, + current_index: 0, + received, + }) +} + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", +))] +#[derive(Debug)] +/// Iterator over results of [`recvmmsg`]/[`sendmmsg`] +/// +/// +pub struct MultiResults<'a, S> { + // preallocated structures + rmm: &'a MultiHeaders, + current_index: usize, + received: usize, +} + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", +))] +impl<'a, S> Iterator for MultiResults<'a, S> +where + S: Copy + SockaddrLike, +{ + type Item = RecvMsg<'a, 'a, S>; + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + fn next(&mut self) -> Option { + if self.current_index >= self.received { + return None; + } + let mmsghdr = self.rmm.items[self.current_index]; + + // as long as we are not reading past the index writen by recvmmsg - address + // will be initialized + let address = unsafe { self.rmm.addresses[self.current_index].assume_init() }; + + self.current_index += 1; + Some(unsafe { + read_mhdr( + mmsghdr.msg_hdr, + mmsghdr.msg_len as isize, + self.rmm.msg_controllen, + address, + ) + }) + } +} + +impl<'a, S> RecvMsg<'_, 'a, S> { + /// Iterate over the filled io slices pointed by this msghdr + pub fn iovs(&self) -> IoSliceIterator<'a> { + IoSliceIterator { + index: 0, + remaining: self.bytes, + slices: unsafe { + // safe for as long as mgdr is properly initialized and references are valid. + // for multi messages API we initialize it with an empty + // slice and replace with a concrete buffer + // for single message API we hold a lifetime reference to ioslices + std::slice::from_raw_parts(self.mhdr.msg_iov as *const _, self.mhdr.msg_iovlen as _) + }, + } + } +} + +#[derive(Debug)] +pub struct IoSliceIterator<'a> { + index: usize, + remaining: usize, + slices: &'a [IoSlice<'a>], +} + +impl<'a> Iterator for IoSliceIterator<'a> { + type Item = &'a [u8]; + + fn next(&mut self) -> Option { + if self.index >= self.slices.len() { + return None; + } + let slice = &self.slices[self.index][..self.remaining.min(self.slices[self.index].len())]; + self.remaining -= slice.len(); + self.index += 1; + if slice.is_empty() { + return None; + } + + Some(slice) + } +} + +// test contains both recvmmsg and timestaping which is linux only +// there are existing tests for recvmmsg only in tests/ +#[cfg(target_os = "linux")] +#[cfg(test)] +mod test { + use crate::sys::socket::{AddressFamily, ControlMessageOwned}; + use crate::*; + use std::str::FromStr; + + #[cfg_attr(qemu, ignore)] + #[test] + fn test_recvmm2() -> crate::Result<()> { + use crate::sys::socket::{ + sendmsg, setsockopt, socket, sockopt::Timestamping, MsgFlags, SockFlag, SockType, + SockaddrIn, TimestampingFlag, + }; + use std::io::{IoSlice, IoSliceMut}; + + let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); + + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + )?; + + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::SOCK_NONBLOCK, + None, + )?; + + crate::sys::socket::bind(rsock, &sock_addr)?; + + setsockopt(rsock, Timestamping, &TimestampingFlag::all())?; + + let sbuf = (0..400).map(|i| i as u8).collect::>(); + + let mut recv_buf = vec![0; 1024]; + + let mut recv_iovs = Vec::new(); + let mut pkt_iovs = Vec::new(); + + for (ix, chunk) in recv_buf.chunks_mut(256).enumerate() { + pkt_iovs.push(IoSliceMut::new(chunk)); + if ix % 2 == 1 { + recv_iovs.push(pkt_iovs); + pkt_iovs = Vec::new(); + } + } + drop(pkt_iovs); + + let flags = MsgFlags::empty(); + let iov1 = [IoSlice::new(&sbuf)]; + + let cmsg = cmsg_space!(crate::sys::socket::Timestamps); + sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap(); + + let mut data = super::MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg)); + + let t = sys::time::TimeSpec::from_duration(std::time::Duration::from_secs(10)); + + let recv = super::recvmmsg(rsock, &mut data, recv_iovs.iter(), flags, Some(t))?; + + for rmsg in recv { + #[cfg(not(any(qemu, target_arch = "aarch64")))] + let mut saw_time = false; + let mut recvd = 0; + for cmsg in rmsg.cmsgs() { + if let ControlMessageOwned::ScmTimestampsns(timestamps) = cmsg { + let ts = timestamps.system; + + let sys_time = + crate::time::clock_gettime(crate::time::ClockId::CLOCK_REALTIME)?; + let diff = if ts > sys_time { + ts - sys_time + } else { + sys_time - ts + }; + assert!(std::time::Duration::from(diff).as_secs() < 60); + #[cfg(not(any(qemu, target_arch = "aarch64")))] + { + saw_time = true; + } + } + } + + #[cfg(not(any(qemu, target_arch = "aarch64")))] + assert!(saw_time); + + for iov in rmsg.iovs() { + recvd += iov.len(); + } + assert_eq!(recvd, 400); + } + + Ok(()) + } +} +unsafe fn read_mhdr<'a, 'i, S>( + mhdr: msghdr, + r: isize, + msg_controllen: usize, + address: S, +) -> RecvMsg<'a, 'i, S> + where S: SockaddrLike +{ + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + let cmsghdr = { + if mhdr.msg_controllen > 0 { + debug_assert!(!mhdr.msg_control.is_null()); + debug_assert!(msg_controllen >= mhdr.msg_controllen as usize); + CMSG_FIRSTHDR(&mhdr as *const msghdr) + } else { + ptr::null() + }.as_ref() + }; + + RecvMsg { + bytes: r as usize, + cmsghdr, + address: Some(address), + flags: MsgFlags::from_bits_truncate(mhdr.msg_flags), + mhdr, + iobufs: std::marker::PhantomData, + } +} + +/// Pack pointers to various structures into into msghdr +/// +/// # Safety +/// `iov_buffer` and `iov_buffer_len` must point to a slice +/// of `IoSliceMut` and number of available elements or be a null pointer and 0 +/// +/// `cmsg_buffer` and `cmsg_capacity` must point to a byte buffer used +/// to store control headers later or be a null pointer and 0 if control +/// headers are not used +/// +/// Buffers must remain valid for the whole lifetime of msghdr +unsafe fn pack_mhdr_to_receive( + iov_buffer: *const IoSliceMut, + iov_buffer_len: usize, + cmsg_buffer: *const u8, + cmsg_capacity: usize, + address: *mut S, +) -> msghdr + where + S: SockaddrLike +{ + // Musl's msghdr has private fields, so this is the only way to + // initialize it. + let mut mhdr = mem::MaybeUninit::::zeroed(); + let p = mhdr.as_mut_ptr(); + (*p).msg_name = (*address).as_mut_ptr() as *mut c_void; + (*p).msg_namelen = S::size(); + (*p).msg_iov = iov_buffer as *mut iovec; + (*p).msg_iovlen = iov_buffer_len as _; + (*p).msg_control = cmsg_buffer as *mut c_void; + (*p).msg_controllen = cmsg_capacity as _; + (*p).msg_flags = 0; + mhdr.assume_init() +} + +fn pack_mhdr_to_send<'a, I, C, S>( + cmsg_buffer: &mut [u8], + iov: I, + cmsgs: C, + addr: Option<&S> +) -> msghdr + where + I: AsRef<[IoSlice<'a>]>, + C: AsRef<[ControlMessage<'a>]>, + S: SockaddrLike + 'a +{ + let capacity = cmsg_buffer.len(); + + // The message header must be initialized before the individual cmsgs. + let cmsg_ptr = if capacity > 0 { + cmsg_buffer.as_ptr() as *mut c_void + } else { + ptr::null_mut() + }; + + let mhdr = unsafe { + // Musl's msghdr has private fields, so this is the only way to + // initialize it. + let mut mhdr = mem::MaybeUninit::::zeroed(); + let p = mhdr.as_mut_ptr(); + (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()) as *mut _; + (*p).msg_namelen = addr.map(S::len).unwrap_or(0); + // transmute iov into a mutable pointer. sendmsg doesn't really mutate + // the buffer, but the standard says that it takes a mutable pointer + (*p).msg_iov = iov.as_ref().as_ptr() as *mut _; + (*p).msg_iovlen = iov.as_ref().len() as _; + (*p).msg_control = cmsg_ptr; + (*p).msg_controllen = capacity as _; + (*p).msg_flags = 0; + mhdr.assume_init() + }; + + // Encode each cmsg. This must happen after initializing the header because + // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields. + // CMSG_FIRSTHDR is always safe + let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) }; + for cmsg in cmsgs.as_ref() { + assert_ne!(pmhdr, ptr::null_mut()); + // Safe because we know that pmhdr is valid, and we initialized it with + // sufficient space + unsafe { cmsg.encode_into(pmhdr) }; + // Safe because mhdr is valid + pmhdr = unsafe { CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr) }; + } + + mhdr +} + +/// Receive message in scatter-gather vectors from a socket, and +/// optionally receive ancillary data into the provided buffer. +/// If no ancillary data is desired, use () as the type parameter. +/// +/// # Arguments +/// +/// * `fd`: Socket file descriptor +/// * `iov`: Scatter-gather list of buffers to receive the message +/// * `cmsg_buffer`: Space to receive ancillary data. Should be created by +/// [`cmsg_space!`](../../macro.cmsg_space.html) +/// * `flags`: Optional flags passed directly to the operating system. +/// +/// # References +/// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) +pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'inner>], + mut cmsg_buffer: Option<&'a mut Vec>, + flags: MsgFlags) -> Result> + where S: SockaddrLike + 'a, + 'inner: 'outer +{ + let mut address = mem::MaybeUninit::uninit(); + + let (msg_control, msg_controllen) = cmsg_buffer.as_mut() + .map(|v| (v.as_mut_ptr(), v.capacity())) + .unwrap_or((ptr::null_mut(), 0)); + let mut mhdr = unsafe { + pack_mhdr_to_receive(iov.as_ref().as_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr()) + }; + + let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; + + let r = Errno::result(ret)?; + + Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init()) }) +} +} + +/// Create an endpoint for communication +/// +/// The `protocol` specifies a particular protocol to be used with the +/// socket. Normally only a single protocol exists to support a +/// particular socket type within a given protocol family, in which case +/// protocol can be specified as `None`. However, it is possible that many +/// protocols may exist, in which case a particular protocol must be +/// specified in this manner. +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html) +pub fn socket>>( + domain: AddressFamily, + ty: SockType, + flags: SockFlag, + protocol: T, +) -> Result { + let protocol = match protocol.into() { + None => 0, + Some(p) => p as c_int, + }; + + // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a + // little easier to understand by separating it out. So we have to merge these bitfields + // here. + let mut ty = ty as c_int; + ty |= flags.bits(); + + let res = unsafe { libc::socket(domain as c_int, ty, protocol) }; + + Errno::result(res) +} + +/// Create a pair of connected sockets +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html) +pub fn socketpair>>( + domain: AddressFamily, + ty: SockType, + protocol: T, + flags: SockFlag, +) -> Result<(RawFd, RawFd)> { + let protocol = match protocol.into() { + None => 0, + Some(p) => p as c_int, + }; + + // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a + // little easier to understand by separating it out. So we have to merge these bitfields + // here. + let mut ty = ty as c_int; + ty |= flags.bits(); + + let mut fds = [-1, -1]; + + let res = unsafe { + libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) + }; + Errno::result(res)?; + + Ok((fds[0], fds[1])) +} + +/// Listen for connections on a socket +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html) +pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> { + let res = unsafe { libc::listen(sockfd, backlog as c_int) }; + + Errno::result(res).map(drop) +} + +/// Bind a name to a socket +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html) +pub fn bind(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { + let res = unsafe { libc::bind(fd, addr.as_ptr(), addr.len()) }; + + Errno::result(res).map(drop) +} + +/// Accept a connection on a socket +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html) +pub fn accept(sockfd: RawFd) -> Result { + let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) }; + + Errno::result(res) +} + +/// Accept a connection on a socket +/// +/// [Further reading](https://man7.org/linux/man-pages/man2/accept.2.html) +#[cfg(any( + all( + target_os = "android", + any( + target_arch = "aarch64", + target_arch = "x86", + target_arch = "x86_64" + ) + ), + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd" +))] +pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result { + let res = unsafe { + libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) + }; + + Errno::result(res) +} + +/// Initiate a connection on a socket +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html) +pub fn connect(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { + let res = unsafe { libc::connect(fd, addr.as_ptr(), addr.len()) }; + + Errno::result(res).map(drop) +} + +/// Receive data from a connection-oriented socket. Returns the number of +/// bytes read +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html) +pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result { + unsafe { + let ret = libc::recv( + sockfd, + buf.as_ptr() as *mut c_void, + buf.len() as size_t, + flags.bits(), + ); + + Errno::result(ret).map(|r| r as usize) + } +} + +/// Receive data from a connectionless or connection-oriented socket. Returns +/// the number of bytes read and, for connectionless sockets, the socket +/// address of the sender. +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html) +pub fn recvfrom( + sockfd: RawFd, + buf: &mut [u8], +) -> Result<(usize, Option)> { + unsafe { + let mut addr = mem::MaybeUninit::::uninit(); + let mut len = mem::size_of_val(&addr) as socklen_t; + + let ret = Errno::result(libc::recvfrom( + sockfd, + buf.as_ptr() as *mut c_void, + buf.len() as size_t, + 0, + addr.as_mut_ptr() as *mut libc::sockaddr, + &mut len as *mut socklen_t, + ))? as usize; + + Ok(( + ret, + T::from_raw( + addr.assume_init().as_ptr() as *const libc::sockaddr, + Some(len), + ), + )) + } +} + +/// Send a message to a socket +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html) +pub fn sendto( + fd: RawFd, + buf: &[u8], + addr: &dyn SockaddrLike, + flags: MsgFlags, +) -> Result { + let ret = unsafe { + libc::sendto( + fd, + buf.as_ptr() as *const c_void, + buf.len() as size_t, + flags.bits(), + addr.as_ptr(), + addr.len(), + ) + }; + + Errno::result(ret).map(|r| r as usize) +} + +/// Send data to a connection-oriented socket. Returns the number of bytes read +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html) +pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result { + let ret = unsafe { + libc::send( + fd, + buf.as_ptr() as *const c_void, + buf.len() as size_t, + flags.bits(), + ) + }; + + Errno::result(ret).map(|r| r as usize) +} + +/* + * + * ===== Socket Options ===== + * + */ + +/// Represents a socket option that can be retrieved. +pub trait GetSockOpt: Copy { + type Val; + + /// Look up the value of this socket option on the given socket. + fn get(&self, fd: RawFd) -> Result; +} + +/// Represents a socket option that can be set. +pub trait SetSockOpt: Clone { + type Val; + + /// Set the value of this socket option on the given socket. + fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>; +} + +/// Get the current value for the requested socket option +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html) +pub fn getsockopt(fd: RawFd, opt: O) -> Result { + opt.get(fd) +} + +/// Sets the value for the requested socket option +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html) +/// +/// # Examples +/// +/// ``` +/// use nix::sys::socket::setsockopt; +/// use nix::sys::socket::sockopt::KeepAlive; +/// use std::net::TcpListener; +/// use std::os::unix::io::AsRawFd; +/// +/// let listener = TcpListener::bind("0.0.0.0:0").unwrap(); +/// let fd = listener.as_raw_fd(); +/// let res = setsockopt(fd, KeepAlive, &true); +/// assert!(res.is_ok()); +/// ``` +pub fn setsockopt( + fd: RawFd, + opt: O, + val: &O::Val, +) -> Result<()> { + opt.set(fd, val) +} + +/// Get the address of the peer connected to the socket `fd`. +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html) +pub fn getpeername(fd: RawFd) -> Result { + unsafe { + let mut addr = mem::MaybeUninit::::uninit(); + let mut len = T::size(); + + let ret = libc::getpeername( + fd, + addr.as_mut_ptr() as *mut libc::sockaddr, + &mut len, + ); + + Errno::result(ret)?; + + T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL) + } +} + +/// Get the current address to which the socket `fd` is bound. +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html) +pub fn getsockname(fd: RawFd) -> Result { + unsafe { + let mut addr = mem::MaybeUninit::::uninit(); + let mut len = T::size(); + + let ret = libc::getsockname( + fd, + addr.as_mut_ptr() as *mut libc::sockaddr, + &mut len, + ); + + Errno::result(ret)?; + + T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL) + } +} + +/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a +/// certain size. +/// +/// In C this would usually be done by casting. The `len` argument +/// should be the number of bytes in the `sockaddr_storage` that are actually +/// allocated and valid. It must be at least as large as all the useful parts +/// of the structure. Note that in the case of a `sockaddr_un`, `len` need not +/// include the terminating null. +#[deprecated( + since = "0.24.0", + note = "use SockaddrLike or SockaddrStorage instead" +)] +#[allow(deprecated)] +pub fn sockaddr_storage_to_addr( + addr: &sockaddr_storage, + len: usize, +) -> Result { + assert!(len <= mem::size_of::()); + if len < mem::size_of_val(&addr.ss_family) { + return Err(Errno::ENOTCONN); + } + + match c_int::from(addr.ss_family) { + #[cfg(feature = "net")] + libc::AF_INET => { + assert!(len >= mem::size_of::()); + let sin = unsafe { + *(addr as *const sockaddr_storage as *const sockaddr_in) + }; + Ok(SockAddr::Inet(InetAddr::V4(sin))) + } + #[cfg(feature = "net")] + libc::AF_INET6 => { + assert!(len >= mem::size_of::()); + let sin6 = unsafe { *(addr as *const _ as *const sockaddr_in6) }; + Ok(SockAddr::Inet(InetAddr::V6(sin6))) + } + libc::AF_UNIX => unsafe { + let sun = *(addr as *const _ as *const sockaddr_un); + let sun_len = len.try_into().unwrap(); + Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len))) + }, + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] + libc::AF_PACKET => { + use libc::sockaddr_ll; + // Don't assert anything about the size. + // Apparently the Linux kernel can return smaller sizes when + // the value in the last element of sockaddr_ll (`sll_addr`) is + // smaller than the declared size of that field + let sll = unsafe { *(addr as *const _ as *const sockaddr_ll) }; + Ok(SockAddr::Link(LinkAddr(sll))) + } + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_NETLINK => { + use libc::sockaddr_nl; + let snl = unsafe { *(addr as *const _ as *const sockaddr_nl) }; + Ok(SockAddr::Netlink(NetlinkAddr(snl))) + } + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_ALG => { + use libc::sockaddr_alg; + let salg = unsafe { *(addr as *const _ as *const sockaddr_alg) }; + Ok(SockAddr::Alg(AlgAddr(salg))) + } + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_VSOCK => { + use libc::sockaddr_vm; + let svm = unsafe { *(addr as *const _ as *const sockaddr_vm) }; + Ok(SockAddr::Vsock(VsockAddr(svm))) + } + af => panic!("unexpected address family {}", af), + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum Shutdown { + /// Further receptions will be disallowed. + Read, + /// Further transmissions will be disallowed. + Write, + /// Further receptions and transmissions will be disallowed. + Both, +} + +/// Shut down part of a full-duplex connection. +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html) +pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> { + unsafe { + use libc::shutdown; + + let how = match how { + Shutdown::Read => libc::SHUT_RD, + Shutdown::Write => libc::SHUT_WR, + Shutdown::Both => libc::SHUT_RDWR, + }; + + Errno::result(shutdown(df, how)).map(drop) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn can_use_cmsg_space() { + let _ = cmsg_space!(u8); + } +} diff --git a/vendor/nix-0.26.2/src/sys/socket/sockopt.rs b/vendor/nix-0.26.2/src/sys/socket/sockopt.rs new file mode 100644 index 0000000000000..06e9ee4563b54 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/socket/sockopt.rs @@ -0,0 +1,1422 @@ +//! Socket options as used by `setsockopt` and `getsockopt`. +use super::{GetSockOpt, SetSockOpt}; +use crate::errno::Errno; +use crate::sys::time::TimeVal; +use crate::Result; +use cfg_if::cfg_if; +use libc::{self, c_int, c_void, socklen_t}; +use std::ffi::{OsStr, OsString}; +use std::{ + convert::TryFrom, + mem::{self, MaybeUninit} +}; +#[cfg(target_family = "unix")] +use std::os::unix::ffi::OsStrExt; +use std::os::unix::io::RawFd; + +// Constants +// TCP_CA_NAME_MAX isn't defined in user space include files +#[cfg(any(target_os = "freebsd", target_os = "linux"))] +#[cfg(feature = "net")] +const TCP_CA_NAME_MAX: usize = 16; + +/// Helper for implementing `SetSockOpt` for a given socket option. See +/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html). +/// +/// This macro aims to help implementing `SetSockOpt` for different socket options that accept +/// different kinds of data to be used with `setsockopt`. +/// +/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option +/// you are implementing represents a simple type. +/// +/// # Arguments +/// +/// * `$name:ident`: name of the type you want to implement `SetSockOpt` for. +/// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets* +/// (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), +/// and more. Please refer to your system manual for more options. Will be passed as the second +/// argument (`level`) to the `setsockopt` call. +/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, +/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`) +/// to the `setsockopt` call. +/// * Type of the value that you are going to set. +/// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for +/// `bool`, `SetUsize` for `usize`, etc.). +macro_rules! setsockopt_impl { + ($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => { + impl SetSockOpt for $name { + type Val = $ty; + + fn set(&self, fd: RawFd, val: &$ty) -> Result<()> { + unsafe { + let setter: $setter = Set::new(val); + + let res = libc::setsockopt( + fd, + $level, + $flag, + setter.ffi_ptr(), + setter.ffi_len(), + ); + Errno::result(res).map(drop) + } + } + } + }; +} + +/// Helper for implementing `GetSockOpt` for a given socket option. See +/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html). +/// +/// This macro aims to help implementing `GetSockOpt` for different socket options that accept +/// different kinds of data to be use with `getsockopt`. +/// +/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option +/// you are implementing represents a simple type. +/// +/// # Arguments +/// +/// * Name of the type you want to implement `GetSockOpt` for. +/// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`), *ip +/// protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), and more. Please refer +/// to your system manual for more options. Will be passed as the second argument (`level`) to +/// the `getsockopt` call. +/// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, +/// `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to +/// the `getsockopt` call. +/// * Type of the value that you are going to get. +/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for +/// `bool`, `GetUsize` for `usize`, etc.). +macro_rules! getsockopt_impl { + ($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => { + impl GetSockOpt for $name { + type Val = $ty; + + fn get(&self, fd: RawFd) -> Result<$ty> { + unsafe { + let mut getter: $getter = Get::uninit(); + + let res = libc::getsockopt( + fd, + $level, + $flag, + getter.ffi_ptr(), + getter.ffi_len(), + ); + Errno::result(res)?; + + match <$ty>::try_from(getter.assume_init()) { + Err(_) => Err(Errno::EINVAL), + Ok(r) => Ok(r) + } + } + } + } + }; +} + +/// Helper to generate the sockopt accessors. See +/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and +/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html). +/// +/// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options +/// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively. +/// +/// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and +/// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros. +/// +/// # Arguments +/// +/// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or +/// both of them. +/// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for. +/// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets* +/// (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), +/// and more. Please refer to your system manual for more options. Will be passed as the second +/// argument (`level`) to the `getsockopt`/`setsockopt` call. +/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, +/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`) +/// to the `setsockopt`/`getsockopt` call. +/// * `$ty:ty`: type of the value that will be get/set. +/// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`. +/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`. +// Some targets don't use all rules. +#[allow(unknown_lints)] +#[allow(unused_macro_rules)] +macro_rules! sockopt_impl { + ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => { + sockopt_impl!($(#[$attr])* + $name, GetOnly, $level, $flag, bool, GetBool); + }; + + ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => { + sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, GetU8); + }; + + ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) => + { + sockopt_impl!($(#[$attr])* + $name, GetOnly, $level, $flag, usize, GetUsize); + }; + + ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => { + sockopt_impl!($(#[$attr])* + $name, SetOnly, $level, $flag, bool, SetBool); + }; + + ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => { + sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, SetU8); + }; + + ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) => + { + sockopt_impl!($(#[$attr])* + $name, SetOnly, $level, $flag, usize, SetUsize); + }; + + ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => { + sockopt_impl!($(#[$attr])* + $name, Both, $level, $flag, bool, GetBool, SetBool); + }; + + ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => { + sockopt_impl!($(#[$attr])* + $name, Both, $level, $flag, u8, GetU8, SetU8); + }; + + ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => { + sockopt_impl!($(#[$attr])* + $name, Both, $level, $flag, usize, GetUsize, SetUsize); + }; + + ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, + OsString<$array:ty>) => + { + sockopt_impl!($(#[$attr])* + $name, Both, $level, $flag, OsString, GetOsString<$array>, + SetOsString); + }; + + /* + * Matchers with generic getter types must be placed at the end, so + * they'll only match _after_ specialized matchers fail + */ + ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) => + { + sockopt_impl!($(#[$attr])* + $name, GetOnly, $level, $flag, $ty, GetStruct<$ty>); + }; + + ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty, + $getter:ty) => + { + $(#[$attr])* + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + pub struct $name; + + getsockopt_impl!($name, $level, $flag, $ty, $getter); + }; + + ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) => + { + sockopt_impl!($(#[$attr])* + $name, SetOnly, $level, $flag, $ty, SetStruct<$ty>); + }; + + ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty, + $setter:ty) => + { + $(#[$attr])* + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + pub struct $name; + + setsockopt_impl!($name, $level, $flag, $ty, $setter); + }; + + ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty, + $getter:ty, $setter:ty) => + { + $(#[$attr])* + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + pub struct $name; + + setsockopt_impl!($name, $level, $flag, $ty, $setter); + getsockopt_impl!($name, $level, $flag, $ty, $getter); + }; + + ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => { + sockopt_impl!($(#[$attr])* + $name, Both, $level, $flag, $ty, GetStruct<$ty>, + SetStruct<$ty>); + }; +} + +/* + * + * ===== Define sockopts ===== + * + */ + +sockopt_impl!( + /// Enables local address reuse + ReuseAddr, + Both, + libc::SOL_SOCKET, + libc::SO_REUSEADDR, + bool +); +#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] +sockopt_impl!( + /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an + /// identical socket address. + ReusePort, + Both, + libc::SOL_SOCKET, + libc::SO_REUSEPORT, + bool +); +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Under most circumstances, TCP sends data when it is presented; when + /// outstanding data has not yet been acknowledged, it gathers small amounts + /// of output to be sent in a single packet once an acknowledgement is + /// received. For a small number of clients, such as window systems that + /// send a stream of mouse events which receive no replies, this + /// packetization may cause significant delays. The boolean option + /// TCP_NODELAY defeats this algorithm. + TcpNoDelay, + Both, + libc::IPPROTO_TCP, + libc::TCP_NODELAY, + bool +); +sockopt_impl!( + /// When enabled, a close(2) or shutdown(2) will not return until all + /// queued messages for the socket have been successfully sent or the + /// linger timeout has been reached. + Linger, + Both, + libc::SOL_SOCKET, + libc::SO_LINGER, + libc::linger +); +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Join a multicast group + IpAddMembership, + SetOnly, + libc::IPPROTO_IP, + libc::IP_ADD_MEMBERSHIP, + super::IpMembershipRequest +); +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Leave a multicast group. + IpDropMembership, + SetOnly, + libc::IPPROTO_IP, + libc::IP_DROP_MEMBERSHIP, + super::IpMembershipRequest +); +cfg_if! { + if #[cfg(any(target_os = "android", target_os = "linux"))] { + #[cfg(feature = "net")] + sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Join an IPv6 multicast group. + Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest); + #[cfg(feature = "net")] + sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Leave an IPv6 multicast group. + Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest); + } else if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris"))] { + #[cfg(feature = "net")] + sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Join an IPv6 multicast group. + Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, + libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest); + #[cfg(feature = "net")] + sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Leave an IPv6 multicast group. + Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, + libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest); + } +} +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Set or read the time-to-live value of outgoing multicast packets for + /// this socket. + IpMulticastTtl, + Both, + libc::IPPROTO_IP, + libc::IP_MULTICAST_TTL, + u8 +); +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Set or read a boolean integer argument that determines whether sent + /// multicast packets should be looped back to the local sockets. + IpMulticastLoop, + Both, + libc::IPPROTO_IP, + libc::IP_MULTICAST_LOOP, + bool +); +#[cfg(target_os = "linux")] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Set the protocol-defined priority for all packets to be + /// sent on this socket + Priority, + Both, + libc::SOL_SOCKET, + libc::SO_PRIORITY, + libc::c_int +); +#[cfg(target_os = "linux")] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Set or receive the Type-Of-Service (TOS) field that is + /// sent with every IP packet originating from this socket + IpTos, + Both, + libc::IPPROTO_IP, + libc::IP_TOS, + libc::c_int +); +#[cfg(target_os = "linux")] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Traffic class associated with outgoing packets + Ipv6TClass, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_TCLASS, + libc::c_int +); +#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// If enabled, this boolean option allows binding to an IP address that + /// is nonlocal or does not (yet) exist. + IpFreebind, + Both, + libc::IPPROTO_IP, + libc::IP_FREEBIND, + bool +); +sockopt_impl!( + /// Specify the receiving timeout until reporting an error. + ReceiveTimeout, + Both, + libc::SOL_SOCKET, + libc::SO_RCVTIMEO, + TimeVal +); +sockopt_impl!( + /// Specify the sending timeout until reporting an error. + SendTimeout, + Both, + libc::SOL_SOCKET, + libc::SO_SNDTIMEO, + TimeVal +); +sockopt_impl!( + /// Set or get the broadcast flag. + Broadcast, + Both, + libc::SOL_SOCKET, + libc::SO_BROADCAST, + bool +); +sockopt_impl!( + /// If this option is enabled, out-of-band data is directly placed into + /// the receive data stream. + OobInline, + Both, + libc::SOL_SOCKET, + libc::SO_OOBINLINE, + bool +); +sockopt_impl!( + /// Get and clear the pending socket error. + SocketError, + GetOnly, + libc::SOL_SOCKET, + libc::SO_ERROR, + i32 +); +sockopt_impl!( + /// Set or get the don't route flag. + DontRoute, + Both, + libc::SOL_SOCKET, + libc::SO_DONTROUTE, + bool +); +sockopt_impl!( + /// Enable sending of keep-alive messages on connection-oriented sockets. + KeepAlive, + Both, + libc::SOL_SOCKET, + libc::SO_KEEPALIVE, + bool +); +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "ios" +))] +sockopt_impl!( + /// Get the credentials of the peer process of a connected unix domain + /// socket. + LocalPeerCred, + GetOnly, + 0, + libc::LOCAL_PEERCRED, + super::XuCred +); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!( + /// Return the credentials of the foreign process connected to this socket. + PeerCredentials, + GetOnly, + libc::SOL_SOCKET, + libc::SO_PEERCRED, + super::UnixCredentials +); +#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Specify the amount of time, in seconds, that the connection must be idle + /// before keepalive probes (if enabled) are sent. + TcpKeepAlive, + Both, + libc::IPPROTO_TCP, + libc::TCP_KEEPALIVE, + u32 +); +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux" +))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// The time (in seconds) the connection needs to remain idle before TCP + /// starts sending keepalive probes + TcpKeepIdle, + Both, + libc::IPPROTO_TCP, + libc::TCP_KEEPIDLE, + u32 +); +cfg_if! { + if #[cfg(any(target_os = "android", target_os = "linux"))] { + sockopt_impl!( + /// The maximum segment size for outgoing TCP packets. + TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); + } else { + sockopt_impl!( + /// The maximum segment size for outgoing TCP packets. + TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); + } +} +#[cfg(not(any(target_os = "openbsd", target_os = "haiku")))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// The maximum number of keepalive probes TCP should send before + /// dropping the connection. + TcpKeepCount, + Both, + libc::IPPROTO_TCP, + libc::TCP_KEEPCNT, + u32 +); +#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] +sockopt_impl!( + #[allow(missing_docs)] + // Not documented by Linux! + TcpRepair, + Both, + libc::IPPROTO_TCP, + libc::TCP_REPAIR, + u32 +); +#[cfg(not(any(target_os = "openbsd", target_os = "haiku")))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// The time (in seconds) between individual keepalive probes. + TcpKeepInterval, + Both, + libc::IPPROTO_TCP, + libc::TCP_KEEPINTVL, + u32 +); +#[cfg(any(target_os = "fuchsia", target_os = "linux"))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Specifies the maximum amount of time in milliseconds that transmitted + /// data may remain unacknowledged before TCP will forcibly close the + /// corresponding connection + TcpUserTimeout, + Both, + libc::IPPROTO_TCP, + libc::TCP_USER_TIMEOUT, + u32 +); +sockopt_impl!( + /// Sets or gets the maximum socket receive buffer in bytes. + RcvBuf, + Both, + libc::SOL_SOCKET, + libc::SO_RCVBUF, + usize +); +sockopt_impl!( + /// Sets or gets the maximum socket send buffer in bytes. + SndBuf, + Both, + libc::SOL_SOCKET, + libc::SO_SNDBUF, + usize +); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!( + /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can + /// perform the same task as `SO_RCVBUF`, but the `rmem_max limit` can be + /// overridden. + RcvBufForce, + SetOnly, + libc::SOL_SOCKET, + libc::SO_RCVBUFFORCE, + usize +); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!( + /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can + /// perform the same task as `SO_SNDBUF`, but the `wmem_max` limit can be + /// overridden. + SndBufForce, + SetOnly, + libc::SOL_SOCKET, + libc::SO_SNDBUFFORCE, + usize +); +sockopt_impl!( + /// Gets the socket type as an integer. + SockType, + GetOnly, + libc::SOL_SOCKET, + libc::SO_TYPE, + super::SockType, + GetStruct +); +sockopt_impl!( + /// Returns a value indicating whether or not this socket has been marked to + /// accept connections with `listen(2)`. + AcceptConn, + GetOnly, + libc::SOL_SOCKET, + libc::SO_ACCEPTCONN, + bool +); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!( + /// Bind this socket to a particular device like “eth0â€. + BindToDevice, + Both, + libc::SOL_SOCKET, + libc::SO_BINDTODEVICE, + OsString<[u8; libc::IFNAMSIZ]> +); +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + #[allow(missing_docs)] + // Not documented by Linux! + OriginalDst, + GetOnly, + libc::SOL_IP, + libc::SO_ORIGINAL_DST, + libc::sockaddr_in +); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!( + #[allow(missing_docs)] + // Not documented by Linux! + Ip6tOriginalDst, + GetOnly, + libc::SOL_IPV6, + libc::IP6T_SO_ORIGINAL_DST, + libc::sockaddr_in6 +); +#[cfg(any(target_os = "linux"))] +sockopt_impl!( + /// Specifies exact type of timestamping information collected by the kernel + /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) + Timestamping, + Both, + libc::SOL_SOCKET, + libc::SO_TIMESTAMPING, + super::TimestampingFlag +); +#[cfg(not(target_os = "haiku"))] +sockopt_impl!( + /// Enable or disable the receiving of the `SO_TIMESTAMP` control message. + ReceiveTimestamp, + Both, + libc::SOL_SOCKET, + libc::SO_TIMESTAMP, + bool +); +#[cfg(all(target_os = "linux"))] +sockopt_impl!( + /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message. + ReceiveTimestampns, + Both, + libc::SOL_SOCKET, + libc::SO_TIMESTAMPNS, + bool +); +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Setting this boolean option enables transparent proxying on this socket. + IpTransparent, + Both, + libc::SOL_IP, + libc::IP_TRANSPARENT, + bool +); +#[cfg(target_os = "openbsd")] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Allows the socket to be bound to addresses which are not local to the + /// machine, so it can be used to make a transparent proxy. + BindAny, + Both, + libc::SOL_SOCKET, + libc::SO_BINDANY, + bool +); +#[cfg(target_os = "freebsd")] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Can `bind(2)` to any address, even one not bound to any available + /// network interface in the system. + BindAny, + Both, + libc::IPPROTO_IP, + libc::IP_BINDANY, + bool +); +#[cfg(target_os = "linux")] +sockopt_impl!( + /// Set the mark for each packet sent through this socket (similar to the + /// netfilter MARK target but socket-based). + Mark, + Both, + libc::SOL_SOCKET, + libc::SO_MARK, + u32 +); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!( + /// Enable or disable the receiving of the `SCM_CREDENTIALS` control + /// message. + PassCred, + Both, + libc::SOL_SOCKET, + libc::SO_PASSCRED, + bool +); +#[cfg(any(target_os = "freebsd", target_os = "linux"))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// This option allows the caller to set the TCP congestion control + /// algorithm to be used, on a per-socket basis. + TcpCongestion, + Both, + libc::IPPROTO_TCP, + libc::TCP_CONGESTION, + OsString<[u8; TCP_CA_NAME_MAX]> +); +#[cfg(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", +))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Pass an `IP_PKTINFO` ancillary message that contains a pktinfo + /// structure that supplies some information about the incoming packet. + Ipv4PacketInfo, + Both, + libc::IPPROTO_IP, + libc::IP_PKTINFO, + bool +); +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Set delivery of the `IPV6_PKTINFO` control message on incoming + /// datagrams. + Ipv6RecvPacketInfo, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_RECVPKTINFO, + bool +); +#[cfg(any( + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// The `recvmsg(2)` call returns a `struct sockaddr_dl` corresponding to + /// the interface on which the packet was received. + Ipv4RecvIf, + Both, + libc::IPPROTO_IP, + libc::IP_RECVIF, + bool +); +#[cfg(any( + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// The `recvmsg(2)` call will return the destination IP address for a UDP + /// datagram. + Ipv4RecvDstAddr, + Both, + libc::IPPROTO_IP, + libc::IP_RECVDSTADDR, + bool +); +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// The `recvmsg(2)` call will return the destination IP address for a UDP + /// datagram. + Ipv4OrigDstAddr, + Both, + libc::IPPROTO_IP, + libc::IP_ORIGDSTADDR, + bool +); +#[cfg(target_os = "linux")] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + #[allow(missing_docs)] + // Not documented by Linux! + UdpGsoSegment, + Both, + libc::SOL_UDP, + libc::UDP_SEGMENT, + libc::c_int +); +#[cfg(target_os = "linux")] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + #[allow(missing_docs)] + // Not documented by Linux! + UdpGroSegment, + Both, + libc::IPPROTO_UDP, + libc::UDP_GRO, + bool +); +#[cfg(target_os = "linux")] +sockopt_impl!( + /// Configures the behavior of time-based transmission of packets, for use + /// with the `TxTime` control message. + TxTime, + Both, + libc::SOL_SOCKET, + libc::SO_TXTIME, + libc::sock_txtime +); +#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] +sockopt_impl!( + /// Indicates that an unsigned 32-bit value ancillary message (cmsg) should + /// be attached to received skbs indicating the number of packets dropped by + /// the socket since its creation. + RxqOvfl, + Both, + libc::SOL_SOCKET, + libc::SO_RXQ_OVFL, + libc::c_int +); +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// The socket is restricted to sending and receiving IPv6 packets only. + Ipv6V6Only, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_V6ONLY, + bool +); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!( + /// Enable extended reliable error message passing. + Ipv4RecvErr, + Both, + libc::IPPROTO_IP, + libc::IP_RECVERR, + bool +); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!( + /// Control receiving of asynchronous error options. + Ipv6RecvErr, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_RECVERR, + bool +); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!( + /// Fetch the current system-estimated Path MTU. + IpMtu, + GetOnly, + libc::IPPROTO_IP, + libc::IP_MTU, + libc::c_int +); +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +sockopt_impl!( + /// Set or retrieve the current time-to-live field that is used in every + /// packet sent from this socket. + Ipv4Ttl, + Both, + libc::IPPROTO_IP, + libc::IP_TTL, + libc::c_int +); +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +sockopt_impl!( + /// Set the unicast hop limit for the socket. + Ipv6Ttl, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_UNICAST_HOPS, + libc::c_int +); +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// The `recvmsg(2)` call will return the destination IP address for a UDP + /// datagram. + Ipv6OrigDstAddr, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_ORIGDSTADDR, + bool +); +#[cfg(any(target_os = "ios", target_os = "macos"))] +sockopt_impl!( + /// Set "don't fragment packet" flag on the IP packet. + IpDontFrag, + Both, + libc::IPPROTO_IP, + libc::IP_DONTFRAG, + bool +); +#[cfg(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", +))] +sockopt_impl!( + /// Set "don't fragment packet" flag on the IPv6 packet. + Ipv6DontFrag, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_DONTFRAG, + bool +); + +#[allow(missing_docs)] +// Not documented by Linux! +#[cfg(any(target_os = "android", target_os = "linux"))] +#[derive(Copy, Clone, Debug)] +pub struct AlgSetAeadAuthSize; + +// ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len` +// See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222 +#[cfg(any(target_os = "android", target_os = "linux"))] +impl SetSockOpt for AlgSetAeadAuthSize { + type Val = usize; + + fn set(&self, fd: RawFd, val: &usize) -> Result<()> { + unsafe { + let res = libc::setsockopt( + fd, + libc::SOL_ALG, + libc::ALG_SET_AEAD_AUTHSIZE, + ::std::ptr::null(), + *val as libc::socklen_t, + ); + Errno::result(res).map(drop) + } + } +} + +#[allow(missing_docs)] +// Not documented by Linux! +#[cfg(any(target_os = "android", target_os = "linux"))] +#[derive(Clone, Debug)] +pub struct AlgSetKey(::std::marker::PhantomData); + +#[cfg(any(target_os = "android", target_os = "linux"))] +impl Default for AlgSetKey { + fn default() -> Self { + AlgSetKey(Default::default()) + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +impl SetSockOpt for AlgSetKey +where + T: AsRef<[u8]> + Clone, +{ + type Val = T; + + fn set(&self, fd: RawFd, val: &T) -> Result<()> { + unsafe { + let res = libc::setsockopt( + fd, + libc::SOL_ALG, + libc::ALG_SET_KEY, + val.as_ref().as_ptr() as *const _, + val.as_ref().len() as libc::socklen_t, + ); + Errno::result(res).map(drop) + } + } +} + +/* + * + * ===== Accessor helpers ===== + * + */ + +/// Helper trait that describes what is expected from a `GetSockOpt` getter. +trait Get { + /// Returns an uninitialized value. + fn uninit() -> Self; + /// Returns a pointer to the stored value. This pointer will be passed to the system's + /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`). + fn ffi_ptr(&mut self) -> *mut c_void; + /// Returns length of the stored value. This pointer will be passed to the system's + /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`). + fn ffi_len(&mut self) -> *mut socklen_t; + /// Returns the hopefully initialized inner value. + unsafe fn assume_init(self) -> T; +} + +/// Helper trait that describes what is expected from a `SetSockOpt` setter. +trait Set<'a, T> { + /// Initialize the setter with a given value. + fn new(val: &'a T) -> Self; + /// Returns a pointer to the stored value. This pointer will be passed to the system's + /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`). + fn ffi_ptr(&self) -> *const c_void; + /// Returns length of the stored value. This pointer will be passed to the system's + /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`). + fn ffi_len(&self) -> socklen_t; +} + +/// Getter for an arbitrary `struct`. +struct GetStruct { + len: socklen_t, + val: MaybeUninit, +} + +impl Get for GetStruct { + fn uninit() -> Self { + GetStruct { + len: mem::size_of::() as socklen_t, + val: MaybeUninit::uninit(), + } + } + + fn ffi_ptr(&mut self) -> *mut c_void { + self.val.as_mut_ptr() as *mut c_void + } + + fn ffi_len(&mut self) -> *mut socklen_t { + &mut self.len + } + + unsafe fn assume_init(self) -> T { + assert_eq!( + self.len as usize, + mem::size_of::(), + "invalid getsockopt implementation" + ); + self.val.assume_init() + } +} + +/// Setter for an arbitrary `struct`. +struct SetStruct<'a, T: 'static> { + ptr: &'a T, +} + +impl<'a, T> Set<'a, T> for SetStruct<'a, T> { + fn new(ptr: &'a T) -> SetStruct<'a, T> { + SetStruct { ptr } + } + + fn ffi_ptr(&self) -> *const c_void { + self.ptr as *const T as *const c_void + } + + fn ffi_len(&self) -> socklen_t { + mem::size_of::() as socklen_t + } +} + +/// Getter for a boolean value. +struct GetBool { + len: socklen_t, + val: MaybeUninit, +} + +impl Get for GetBool { + fn uninit() -> Self { + GetBool { + len: mem::size_of::() as socklen_t, + val: MaybeUninit::uninit(), + } + } + + fn ffi_ptr(&mut self) -> *mut c_void { + self.val.as_mut_ptr() as *mut c_void + } + + fn ffi_len(&mut self) -> *mut socklen_t { + &mut self.len + } + + unsafe fn assume_init(self) -> bool { + assert_eq!( + self.len as usize, + mem::size_of::(), + "invalid getsockopt implementation" + ); + self.val.assume_init() != 0 + } +} + +/// Setter for a boolean value. +struct SetBool { + val: c_int, +} + +impl<'a> Set<'a, bool> for SetBool { + fn new(val: &'a bool) -> SetBool { + SetBool { + val: i32::from(*val), + } + } + + fn ffi_ptr(&self) -> *const c_void { + &self.val as *const c_int as *const c_void + } + + fn ffi_len(&self) -> socklen_t { + mem::size_of::() as socklen_t + } +} + +/// Getter for an `u8` value. +struct GetU8 { + len: socklen_t, + val: MaybeUninit, +} + +impl Get for GetU8 { + fn uninit() -> Self { + GetU8 { + len: mem::size_of::() as socklen_t, + val: MaybeUninit::uninit(), + } + } + + fn ffi_ptr(&mut self) -> *mut c_void { + self.val.as_mut_ptr() as *mut c_void + } + + fn ffi_len(&mut self) -> *mut socklen_t { + &mut self.len + } + + unsafe fn assume_init(self) -> u8 { + assert_eq!( + self.len as usize, + mem::size_of::(), + "invalid getsockopt implementation" + ); + self.val.assume_init() + } +} + +/// Setter for an `u8` value. +struct SetU8 { + val: u8, +} + +impl<'a> Set<'a, u8> for SetU8 { + fn new(val: &'a u8) -> SetU8 { + SetU8 { val: *val } + } + + fn ffi_ptr(&self) -> *const c_void { + &self.val as *const u8 as *const c_void + } + + fn ffi_len(&self) -> socklen_t { + mem::size_of::() as socklen_t + } +} + +/// Getter for an `usize` value. +struct GetUsize { + len: socklen_t, + val: MaybeUninit, +} + +impl Get for GetUsize { + fn uninit() -> Self { + GetUsize { + len: mem::size_of::() as socklen_t, + val: MaybeUninit::uninit(), + } + } + + fn ffi_ptr(&mut self) -> *mut c_void { + self.val.as_mut_ptr() as *mut c_void + } + + fn ffi_len(&mut self) -> *mut socklen_t { + &mut self.len + } + + unsafe fn assume_init(self) -> usize { + assert_eq!( + self.len as usize, + mem::size_of::(), + "invalid getsockopt implementation" + ); + self.val.assume_init() as usize + } +} + +/// Setter for an `usize` value. +struct SetUsize { + val: c_int, +} + +impl<'a> Set<'a, usize> for SetUsize { + fn new(val: &'a usize) -> SetUsize { + SetUsize { val: *val as c_int } + } + + fn ffi_ptr(&self) -> *const c_void { + &self.val as *const c_int as *const c_void + } + + fn ffi_len(&self) -> socklen_t { + mem::size_of::() as socklen_t + } +} + +/// Getter for a `OsString` value. +struct GetOsString> { + len: socklen_t, + val: MaybeUninit, +} + +impl> Get for GetOsString { + fn uninit() -> Self { + GetOsString { + len: mem::size_of::() as socklen_t, + val: MaybeUninit::uninit(), + } + } + + fn ffi_ptr(&mut self) -> *mut c_void { + self.val.as_mut_ptr() as *mut c_void + } + + fn ffi_len(&mut self) -> *mut socklen_t { + &mut self.len + } + + unsafe fn assume_init(self) -> OsString { + let len = self.len as usize; + let mut v = self.val.assume_init(); + OsStr::from_bytes(&v.as_mut()[0..len]).to_owned() + } +} + +/// Setter for a `OsString` value. +struct SetOsString<'a> { + val: &'a OsStr, +} + +impl<'a> Set<'a, OsString> for SetOsString<'a> { + fn new(val: &'a OsString) -> SetOsString { + SetOsString { + val: val.as_os_str(), + } + } + + fn ffi_ptr(&self) -> *const c_void { + self.val.as_bytes().as_ptr() as *const c_void + } + + fn ffi_len(&self) -> socklen_t { + self.val.len() as socklen_t + } +} + +#[cfg(test)] +mod test { + #[cfg(any(target_os = "android", target_os = "linux"))] + #[test] + fn can_get_peercred_on_unix_socket() { + use super::super::*; + + let (a, b) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + let a_cred = getsockopt(a, super::PeerCredentials).unwrap(); + let b_cred = getsockopt(b, super::PeerCredentials).unwrap(); + assert_eq!(a_cred, b_cred); + assert_ne!(a_cred.pid(), 0); + } + + #[test] + fn is_socket_type_unix() { + use super::super::*; + use crate::unistd::close; + + let (a, b) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + let a_type = getsockopt(a, super::SockType).unwrap(); + assert_eq!(a_type, SockType::Stream); + close(a).unwrap(); + close(b).unwrap(); + } + + #[test] + fn is_socket_type_dgram() { + use super::super::*; + use crate::unistd::close; + + let s = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + let s_type = getsockopt(s, super::SockType).unwrap(); + assert_eq!(s_type, SockType::Datagram); + close(s).unwrap(); + } + + #[cfg(any(target_os = "freebsd", target_os = "linux"))] + #[test] + fn can_get_listen_on_tcp_socket() { + use super::super::*; + use crate::unistd::close; + + let s = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + None, + ) + .unwrap(); + let s_listening = getsockopt(s, super::AcceptConn).unwrap(); + assert!(!s_listening); + listen(s, 10).unwrap(); + let s_listening2 = getsockopt(s, super::AcceptConn).unwrap(); + assert!(s_listening2); + close(s).unwrap(); + } +} diff --git a/vendor/nix-0.26.2/src/sys/stat.rs b/vendor/nix-0.26.2/src/sys/stat.rs new file mode 100644 index 0000000000000..78203bfbe34ce --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/stat.rs @@ -0,0 +1,480 @@ +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] +pub use libc::c_uint; +#[cfg(any( + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly" +))] +pub use libc::c_ulong; +pub use libc::stat as FileStat; +pub use libc::{dev_t, mode_t}; + +#[cfg(not(target_os = "redox"))] +use crate::fcntl::{at_rawfd, AtFlags}; +use crate::sys::time::{TimeSpec, TimeVal}; +use crate::{errno::Errno, NixPath, Result}; +use std::mem; +use std::os::unix::io::RawFd; + +libc_bitflags!( + /// "File type" flags for `mknod` and related functions. + pub struct SFlag: mode_t { + S_IFIFO; + S_IFCHR; + S_IFDIR; + S_IFBLK; + S_IFREG; + S_IFLNK; + S_IFSOCK; + S_IFMT; + } +); + +libc_bitflags! { + /// "File mode / permissions" flags. + pub struct Mode: mode_t { + /// Read, write and execute for owner. + S_IRWXU; + /// Read for owner. + S_IRUSR; + /// Write for owner. + S_IWUSR; + /// Execute for owner. + S_IXUSR; + /// Read write and execute for group. + S_IRWXG; + /// Read fr group. + S_IRGRP; + /// Write for group. + S_IWGRP; + /// Execute for group. + S_IXGRP; + /// Read, write and execute for other. + S_IRWXO; + /// Read for other. + S_IROTH; + /// Write for other. + S_IWOTH; + /// Execute for other. + S_IXOTH; + /// Set user id on execution. + S_ISUID as mode_t; + /// Set group id on execution. + S_ISGID as mode_t; + S_ISVTX as mode_t; + } +} + +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] +pub type type_of_file_flag = c_uint; +#[cfg(any( + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly" +))] +pub type type_of_file_flag = c_ulong; + +#[cfg(any( + target_os = "openbsd", + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios" +))] +libc_bitflags! { + /// File flags. + #[cfg_attr(docsrs, doc(cfg(all())))] + pub struct FileFlag: type_of_file_flag { + /// The file may only be appended to. + SF_APPEND; + /// The file has been archived. + SF_ARCHIVED; + #[cfg(any(target_os = "dragonfly"))] + SF_CACHE; + /// The file may not be changed. + SF_IMMUTABLE; + /// Indicates a WAPBL journal file. + #[cfg(any(target_os = "netbsd"))] + SF_LOG; + /// Do not retain history for file + #[cfg(any(target_os = "dragonfly"))] + SF_NOHISTORY; + /// The file may not be renamed or deleted. + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + SF_NOUNLINK; + /// Mask of superuser changeable flags + SF_SETTABLE; + /// Snapshot is invalid. + #[cfg(any(target_os = "netbsd"))] + SF_SNAPINVAL; + /// The file is a snapshot file. + #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] + SF_SNAPSHOT; + #[cfg(any(target_os = "dragonfly"))] + SF_XLINK; + /// The file may only be appended to. + UF_APPEND; + /// The file needs to be archived. + #[cfg(any(target_os = "freebsd"))] + UF_ARCHIVE; + #[cfg(any(target_os = "dragonfly"))] + UF_CACHE; + /// File is compressed at the file system level. + #[cfg(any(target_os = "macos", target_os = "ios"))] + UF_COMPRESSED; + /// The file may be hidden from directory listings at the application's + /// discretion. + #[cfg(any( + target_os = "freebsd", + target_os = "macos", + target_os = "ios", + ))] + UF_HIDDEN; + /// The file may not be changed. + UF_IMMUTABLE; + /// Do not dump the file. + UF_NODUMP; + #[cfg(any(target_os = "dragonfly"))] + UF_NOHISTORY; + /// The file may not be renamed or deleted. + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + UF_NOUNLINK; + /// The file is offline, or has the Windows and CIFS + /// `FILE_ATTRIBUTE_OFFLINE` attribute. + #[cfg(any(target_os = "freebsd"))] + UF_OFFLINE; + /// The directory is opaque when viewed through a union stack. + UF_OPAQUE; + /// The file is read only, and may not be written or appended. + #[cfg(any(target_os = "freebsd"))] + UF_READONLY; + /// The file contains a Windows reparse point. + #[cfg(any(target_os = "freebsd"))] + UF_REPARSE; + /// Mask of owner changeable flags. + UF_SETTABLE; + /// The file has the Windows `FILE_ATTRIBUTE_SPARSE_FILE` attribute. + #[cfg(any(target_os = "freebsd"))] + UF_SPARSE; + /// The file has the DOS, Windows and CIFS `FILE_ATTRIBUTE_SYSTEM` + /// attribute. + #[cfg(any(target_os = "freebsd"))] + UF_SYSTEM; + /// File renames and deletes are tracked. + #[cfg(any(target_os = "macos", target_os = "ios"))] + UF_TRACKED; + #[cfg(any(target_os = "dragonfly"))] + UF_XLINK; + } +} + +/// Create a special or ordinary file, by pathname. +pub fn mknod( + path: &P, + kind: SFlag, + perm: Mode, + dev: dev_t, +) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) + })?; + + Errno::result(res).map(drop) +} + +/// Create a special or ordinary file, relative to a given directory. +#[cfg(not(any( + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "haiku" +)))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn mknodat( + dirfd: RawFd, + path: &P, + kind: SFlag, + perm: Mode, + dev: dev_t, +) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::mknodat( + dirfd, + cstr.as_ptr(), + kind.bits | perm.bits() as mode_t, + dev, + ) + })?; + + Errno::result(res).map(drop) +} + +#[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub const fn major(dev: dev_t) -> u64 { + ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff) +} + +#[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub const fn minor(dev: dev_t) -> u64 { + ((dev >> 12) & 0xffff_ff00) | ((dev) & 0x0000_00ff) +} + +#[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub const fn makedev(major: u64, minor: u64) -> dev_t { + ((major & 0xffff_f000) << 32) + | ((major & 0x0000_0fff) << 8) + | ((minor & 0xffff_ff00) << 12) + | (minor & 0x0000_00ff) +} + +pub fn umask(mode: Mode) -> Mode { + let prev = unsafe { libc::umask(mode.bits() as mode_t) }; + Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode") +} + +pub fn stat(path: &P) -> Result { + let mut dst = mem::MaybeUninit::uninit(); + let res = path.with_nix_path(|cstr| unsafe { + libc::stat(cstr.as_ptr(), dst.as_mut_ptr()) + })?; + + Errno::result(res)?; + + Ok(unsafe { dst.assume_init() }) +} + +pub fn lstat(path: &P) -> Result { + let mut dst = mem::MaybeUninit::uninit(); + let res = path.with_nix_path(|cstr| unsafe { + libc::lstat(cstr.as_ptr(), dst.as_mut_ptr()) + })?; + + Errno::result(res)?; + + Ok(unsafe { dst.assume_init() }) +} + +pub fn fstat(fd: RawFd) -> Result { + let mut dst = mem::MaybeUninit::uninit(); + let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) }; + + Errno::result(res)?; + + Ok(unsafe { dst.assume_init() }) +} + +#[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn fstatat( + dirfd: RawFd, + pathname: &P, + f: AtFlags, +) -> Result { + let mut dst = mem::MaybeUninit::uninit(); + let res = pathname.with_nix_path(|cstr| unsafe { + libc::fstatat( + dirfd, + cstr.as_ptr(), + dst.as_mut_ptr(), + f.bits() as libc::c_int, + ) + })?; + + Errno::result(res)?; + + Ok(unsafe { dst.assume_init() }) +} + +/// Change the file permission bits of the file specified by a file descriptor. +/// +/// # References +/// +/// [fchmod(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html). +pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> { + let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) }; + + Errno::result(res).map(drop) +} + +/// Flags for `fchmodat` function. +#[derive(Clone, Copy, Debug)] +pub enum FchmodatFlags { + FollowSymlink, + NoFollowSymlink, +} + +/// Change the file permission bits. +/// +/// The file to be changed is determined relative to the directory associated +/// with the file descriptor `dirfd` or the current working directory +/// if `dirfd` is `None`. +/// +/// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link, +/// then the mode of the symbolic link is changed. +/// +/// `fchmodat(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to +/// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented +/// in the `nix` crate. +/// +/// # References +/// +/// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html). +#[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn fchmodat( + dirfd: Option, + path: &P, + mode: Mode, + flag: FchmodatFlags, +) -> Result<()> { + let atflag = match flag { + FchmodatFlags::FollowSymlink => AtFlags::empty(), + FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, + }; + let res = path.with_nix_path(|cstr| unsafe { + libc::fchmodat( + at_rawfd(dirfd), + cstr.as_ptr(), + mode.bits() as mode_t, + atflag.bits() as libc::c_int, + ) + })?; + + Errno::result(res).map(drop) +} + +/// Change the access and modification times of a file. +/// +/// `utimes(path, times)` is identical to +/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former +/// is a deprecated API so prefer using the latter if the platforms you care +/// about support it. +/// +/// # References +/// +/// [utimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html). +pub fn utimes( + path: &P, + atime: &TimeVal, + mtime: &TimeVal, +) -> Result<()> { + let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; + let res = path.with_nix_path(|cstr| unsafe { + libc::utimes(cstr.as_ptr(), ×[0]) + })?; + + Errno::result(res).map(drop) +} + +/// Change the access and modification times of a file without following symlinks. +/// +/// `lutimes(path, times)` is identical to +/// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former +/// is a deprecated API so prefer using the latter if the platforms you care +/// about support it. +/// +/// # References +/// +/// [lutimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html). +#[cfg(any( + target_os = "linux", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd" +))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn lutimes( + path: &P, + atime: &TimeVal, + mtime: &TimeVal, +) -> Result<()> { + let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; + let res = path.with_nix_path(|cstr| unsafe { + libc::lutimes(cstr.as_ptr(), ×[0]) + })?; + + Errno::result(res).map(drop) +} + +/// Change the access and modification times of the file specified by a file descriptor. +/// +/// # References +/// +/// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). +#[inline] +pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> { + let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; + let res = unsafe { libc::futimens(fd, ×[0]) }; + + Errno::result(res).map(drop) +} + +/// Flags for `utimensat` function. +// TODO: replace with fcntl::AtFlags +#[derive(Clone, Copy, Debug)] +pub enum UtimensatFlags { + FollowSymlink, + NoFollowSymlink, +} + +/// Change the access and modification times of a file. +/// +/// The file to be changed is determined relative to the directory associated +/// with the file descriptor `dirfd` or the current working directory +/// if `dirfd` is `None`. +/// +/// If `flag` is `UtimensatFlags::NoFollowSymlink` and `path` names a symbolic link, +/// then the mode of the symbolic link is changed. +/// +/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to +/// `utimes(path, times)`. The latter is a deprecated API so prefer using the +/// former if the platforms you care about support it. +/// +/// # References +/// +/// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html). +#[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn utimensat( + dirfd: Option, + path: &P, + atime: &TimeSpec, + mtime: &TimeSpec, + flag: UtimensatFlags, +) -> Result<()> { + let atflag = match flag { + UtimensatFlags::FollowSymlink => AtFlags::empty(), + UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, + }; + let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; + let res = path.with_nix_path(|cstr| unsafe { + libc::utimensat( + at_rawfd(dirfd), + cstr.as_ptr(), + ×[0], + atflag.bits() as libc::c_int, + ) + })?; + + Errno::result(res).map(drop) +} + +#[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn mkdirat( + fd: RawFd, + path: &P, + mode: Mode, +) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) + })?; + + Errno::result(res).map(drop) +} diff --git a/vendor/nix-0.26.2/src/sys/statfs.rs b/vendor/nix-0.26.2/src/sys/statfs.rs new file mode 100644 index 0000000000000..9be8ca6667354 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/statfs.rs @@ -0,0 +1,853 @@ +//! Get filesystem statistics, non-portably +//! +//! See [`statvfs`](crate::sys::statvfs) for a portable alternative. +#[cfg(not(any(target_os = "linux", target_os = "android")))] +use std::ffi::CStr; +use std::fmt::{self, Debug}; +use std::mem; +use std::os::unix::io::AsRawFd; + +use cfg_if::cfg_if; + +#[cfg(all( + feature = "mount", + any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ) +))] +use crate::mount::MntFlags; +#[cfg(target_os = "linux")] +use crate::sys::statvfs::FsFlags; +use crate::{errno::Errno, NixPath, Result}; + +/// Identifies a mounted file system +#[cfg(target_os = "android")] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub type fsid_t = libc::__fsid_t; +/// Identifies a mounted file system +#[cfg(not(target_os = "android"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub type fsid_t = libc::fsid_t; + +cfg_if! { + if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] { + type type_of_statfs = libc::statfs64; + const LIBC_FSTATFS: unsafe extern fn + (fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int + = libc::fstatfs64; + const LIBC_STATFS: unsafe extern fn + (path: *const libc::c_char, buf: *mut type_of_statfs) -> libc::c_int + = libc::statfs64; + } else { + type type_of_statfs = libc::statfs; + const LIBC_FSTATFS: unsafe extern fn + (fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int + = libc::fstatfs; + const LIBC_STATFS: unsafe extern fn + (path: *const libc::c_char, buf: *mut type_of_statfs) -> libc::c_int + = libc::statfs; + } +} + +/// Describes a mounted file system +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct Statfs(type_of_statfs); + +#[cfg(target_os = "freebsd")] +type fs_type_t = u32; +#[cfg(target_os = "android")] +type fs_type_t = libc::c_ulong; +#[cfg(all(target_os = "linux", target_arch = "s390x"))] +type fs_type_t = libc::c_uint; +#[cfg(all(target_os = "linux", target_env = "musl"))] +type fs_type_t = libc::c_ulong; +#[cfg(all(target_os = "linux", target_env = "uclibc"))] +type fs_type_t = libc::c_int; +#[cfg(all( + target_os = "linux", + not(any( + target_arch = "s390x", + target_env = "musl", + target_env = "uclibc" + )) +))] +type fs_type_t = libc::__fsword_t; + +/// Describes the file system type as known by the operating system. +#[cfg(any( + target_os = "freebsd", + target_os = "android", + all(target_os = "linux", target_arch = "s390x"), + all(target_os = "linux", target_env = "musl"), + all( + target_os = "linux", + not(any(target_arch = "s390x", target_env = "musl")) + ), +))] +#[derive(Eq, Copy, Clone, PartialEq, Debug)] +pub struct FsType(pub fs_type_t); + +// These constants are defined without documentation in the Linux headers, so we +// can't very well document them here. +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const ADFS_SUPER_MAGIC: FsType = + FsType(libc::ADFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const AFFS_SUPER_MAGIC: FsType = + FsType(libc::AFFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const AFS_SUPER_MAGIC: FsType = FsType(libc::AFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const AUTOFS_SUPER_MAGIC: FsType = + FsType(libc::AUTOFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const BPF_FS_MAGIC: FsType = FsType(libc::BPF_FS_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const BTRFS_SUPER_MAGIC: FsType = + FsType(libc::BTRFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const CGROUP2_SUPER_MAGIC: FsType = + FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const CGROUP_SUPER_MAGIC: FsType = + FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const CODA_SUPER_MAGIC: FsType = + FsType(libc::CODA_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const DEBUGFS_MAGIC: FsType = FsType(libc::DEBUGFS_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const DEVPTS_SUPER_MAGIC: FsType = + FsType(libc::DEVPTS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const ECRYPTFS_SUPER_MAGIC: FsType = + FsType(libc::ECRYPTFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const EXT2_SUPER_MAGIC: FsType = + FsType(libc::EXT2_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const EXT3_SUPER_MAGIC: FsType = + FsType(libc::EXT3_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const EXT4_SUPER_MAGIC: FsType = + FsType(libc::EXT4_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const F2FS_SUPER_MAGIC: FsType = + FsType(libc::F2FS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const FUSE_SUPER_MAGIC: FsType = + FsType(libc::FUSE_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const FUTEXFS_SUPER_MAGIC: FsType = + FsType(libc::FUTEXFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const HOSTFS_SUPER_MAGIC: FsType = + FsType(libc::HOSTFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const HPFS_SUPER_MAGIC: FsType = + FsType(libc::HPFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const ISOFS_SUPER_MAGIC: FsType = + FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const JFFS2_SUPER_MAGIC: FsType = + FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const MINIX2_SUPER_MAGIC2: FsType = + FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const MINIX2_SUPER_MAGIC: FsType = + FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const MINIX3_SUPER_MAGIC: FsType = + FsType(libc::MINIX3_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const MINIX_SUPER_MAGIC2: FsType = + FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const MINIX_SUPER_MAGIC: FsType = + FsType(libc::MINIX_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const MSDOS_SUPER_MAGIC: FsType = + FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const NILFS_SUPER_MAGIC: FsType = + FsType(libc::NILFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const OCFS2_SUPER_MAGIC: FsType = + FsType(libc::OCFS2_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const OPENPROM_SUPER_MAGIC: FsType = + FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const OVERLAYFS_SUPER_MAGIC: FsType = + FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const PROC_SUPER_MAGIC: FsType = + FsType(libc::PROC_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const QNX4_SUPER_MAGIC: FsType = + FsType(libc::QNX4_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const QNX6_SUPER_MAGIC: FsType = + FsType(libc::QNX6_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const RDTGROUP_SUPER_MAGIC: FsType = + FsType(libc::RDTGROUP_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const REISERFS_SUPER_MAGIC: FsType = + FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const SECURITYFS_MAGIC: FsType = + FsType(libc::SECURITYFS_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const SELINUX_MAGIC: FsType = FsType(libc::SELINUX_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const SMACK_MAGIC: FsType = FsType(libc::SMACK_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const SYSFS_MAGIC: FsType = FsType(libc::SYSFS_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const TRACEFS_MAGIC: FsType = FsType(libc::TRACEFS_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const UDF_SUPER_MAGIC: FsType = FsType(libc::UDF_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const USBDEVICE_SUPER_MAGIC: FsType = + FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const XENFS_SUPER_MAGIC: FsType = + FsType(libc::XENFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const NSFS_MAGIC: FsType = FsType(libc::NSFS_MAGIC as fs_type_t); +#[cfg(all( + any(target_os = "linux", target_os = "android"), + not(target_env = "musl") +))] +#[allow(missing_docs)] +pub const XFS_SUPER_MAGIC: FsType = FsType(libc::XFS_SUPER_MAGIC as fs_type_t); + +impl Statfs { + /// Magic code defining system type + #[cfg(not(any( + target_os = "openbsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos" + )))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn filesystem_type(&self) -> FsType { + FsType(self.0.f_type) + } + + /// Magic code defining system type + #[cfg(not(any(target_os = "linux", target_os = "android")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn filesystem_type_name(&self) -> &str { + let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) }; + c_str.to_str().unwrap() + } + + /// Optimal transfer block size + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn optimal_transfer_size(&self) -> i32 { + self.0.f_iosize + } + + /// Optimal transfer block size + #[cfg(target_os = "openbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn optimal_transfer_size(&self) -> u32 { + self.0.f_iosize + } + + /// Optimal transfer block size + #[cfg(all(target_os = "linux", target_arch = "s390x"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn optimal_transfer_size(&self) -> u32 { + self.0.f_bsize + } + + /// Optimal transfer block size + #[cfg(any( + target_os = "android", + all(target_os = "linux", target_env = "musl") + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn optimal_transfer_size(&self) -> libc::c_ulong { + self.0.f_bsize + } + + /// Optimal transfer block size + #[cfg(all( + target_os = "linux", + not(any( + target_arch = "s390x", + target_env = "musl", + target_env = "uclibc" + )) + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn optimal_transfer_size(&self) -> libc::__fsword_t { + self.0.f_bsize + } + + /// Optimal transfer block size + #[cfg(all(target_os = "linux", target_env = "uclibc"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn optimal_transfer_size(&self) -> libc::c_int { + self.0.f_bsize + } + + /// Optimal transfer block size + #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn optimal_transfer_size(&self) -> libc::c_long { + self.0.f_iosize + } + + /// Optimal transfer block size + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn optimal_transfer_size(&self) -> u64 { + self.0.f_iosize + } + + /// Size of a block + #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn block_size(&self) -> u32 { + self.0.f_bsize + } + + /// Size of a block + // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 + #[cfg(all(target_os = "linux", target_arch = "s390x"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn block_size(&self) -> u32 { + self.0.f_bsize + } + + /// Size of a block + // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 + #[cfg(all(target_os = "linux", target_env = "musl"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn block_size(&self) -> libc::c_ulong { + self.0.f_bsize + } + + /// Size of a block + // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 + #[cfg(all(target_os = "linux", target_env = "uclibc"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn block_size(&self) -> libc::c_int { + self.0.f_bsize + } + + /// Size of a block + // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 + #[cfg(all( + target_os = "linux", + not(any( + target_arch = "s390x", + target_env = "musl", + target_env = "uclibc" + )) + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn block_size(&self) -> libc::__fsword_t { + self.0.f_bsize + } + + /// Size of a block + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn block_size(&self) -> u64 { + self.0.f_bsize + } + + /// Size of a block + #[cfg(target_os = "android")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn block_size(&self) -> libc::c_ulong { + self.0.f_bsize + } + + /// Size of a block + #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn block_size(&self) -> libc::c_long { + self.0.f_bsize + } + + /// Get the mount flags + #[cfg(all( + feature = "mount", + any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ) + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(clippy::unnecessary_cast)] // Not unnecessary on all arches + pub fn flags(&self) -> MntFlags { + MntFlags::from_bits_truncate(self.0.f_flags as i32) + } + + /// Get the mount flags + // The f_flags field exists on Android and Fuchsia too, but without man + // pages I can't tell if it can be cast to FsFlags. + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn flags(&self) -> FsFlags { + FsFlags::from_bits_truncate(self.0.f_flags as libc::c_ulong) + } + + /// Maximum length of filenames + #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn maximum_name_length(&self) -> u32 { + self.0.f_namemax + } + + /// Maximum length of filenames + #[cfg(all(target_os = "linux", target_arch = "s390x"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn maximum_name_length(&self) -> u32 { + self.0.f_namelen + } + + /// Maximum length of filenames + #[cfg(all(target_os = "linux", target_env = "musl"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn maximum_name_length(&self) -> libc::c_ulong { + self.0.f_namelen + } + + /// Maximum length of filenames + #[cfg(all(target_os = "linux", target_env = "uclibc"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn maximum_name_length(&self) -> libc::c_int { + self.0.f_namelen + } + + /// Maximum length of filenames + #[cfg(all( + target_os = "linux", + not(any( + target_arch = "s390x", + target_env = "musl", + target_env = "uclibc" + )) + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn maximum_name_length(&self) -> libc::__fsword_t { + self.0.f_namelen + } + + /// Maximum length of filenames + #[cfg(target_os = "android")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn maximum_name_length(&self) -> libc::c_ulong { + self.0.f_namelen + } + + /// Total data blocks in filesystem + #[cfg(any( + target_os = "ios", + target_os = "macos", + target_os = "android", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "openbsd", + target_os = "linux", + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn blocks(&self) -> u64 { + self.0.f_blocks + } + + /// Total data blocks in filesystem + #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn blocks(&self) -> libc::c_long { + self.0.f_blocks + } + + /// Total data blocks in filesystem + #[cfg(target_os = "emscripten")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn blocks(&self) -> u32 { + self.0.f_blocks + } + + /// Free blocks in filesystem + #[cfg(any( + target_os = "ios", + target_os = "macos", + target_os = "android", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "openbsd", + target_os = "linux", + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn blocks_free(&self) -> u64 { + self.0.f_bfree + } + + /// Free blocks in filesystem + #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn blocks_free(&self) -> libc::c_long { + self.0.f_bfree + } + + /// Free blocks in filesystem + #[cfg(target_os = "emscripten")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn blocks_free(&self) -> u32 { + self.0.f_bfree + } + + /// Free blocks available to unprivileged user + #[cfg(any( + target_os = "ios", + target_os = "macos", + target_os = "android", + target_os = "fuchsia", + target_os = "linux", + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn blocks_available(&self) -> u64 { + self.0.f_bavail + } + + /// Free blocks available to unprivileged user + #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn blocks_available(&self) -> libc::c_long { + self.0.f_bavail + } + + /// Free blocks available to unprivileged user + #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn blocks_available(&self) -> i64 { + self.0.f_bavail + } + + /// Free blocks available to unprivileged user + #[cfg(target_os = "emscripten")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn blocks_available(&self) -> u32 { + self.0.f_bavail + } + + /// Total file nodes in filesystem + #[cfg(any( + target_os = "ios", + target_os = "macos", + target_os = "android", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "openbsd", + target_os = "linux", + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn files(&self) -> u64 { + self.0.f_files + } + + /// Total file nodes in filesystem + #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn files(&self) -> libc::c_long { + self.0.f_files + } + + /// Total file nodes in filesystem + #[cfg(target_os = "emscripten")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn files(&self) -> u32 { + self.0.f_files + } + + /// Free file nodes in filesystem + #[cfg(any( + target_os = "ios", + target_os = "macos", + target_os = "android", + target_os = "fuchsia", + target_os = "openbsd", + target_os = "linux", + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn files_free(&self) -> u64 { + self.0.f_ffree + } + + /// Free file nodes in filesystem + #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn files_free(&self) -> libc::c_long { + self.0.f_ffree + } + + /// Free file nodes in filesystem + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn files_free(&self) -> i64 { + self.0.f_ffree + } + + /// Free file nodes in filesystem + #[cfg(target_os = "emscripten")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn files_free(&self) -> u32 { + self.0.f_ffree + } + + /// Filesystem ID + pub fn filesystem_id(&self) -> fsid_t { + self.0.f_fsid + } +} + +impl Debug for Statfs { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut ds = f.debug_struct("Statfs"); + ds.field("optimal_transfer_size", &self.optimal_transfer_size()); + ds.field("block_size", &self.block_size()); + ds.field("blocks", &self.blocks()); + ds.field("blocks_free", &self.blocks_free()); + ds.field("blocks_available", &self.blocks_available()); + ds.field("files", &self.files()); + ds.field("files_free", &self.files_free()); + ds.field("filesystem_id", &self.filesystem_id()); + #[cfg(all( + feature = "mount", + any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ) + ))] + ds.field("flags", &self.flags()); + ds.finish() + } +} + +/// Describes a mounted file system. +/// +/// The result is OS-dependent. For a portable alternative, see +/// [`statvfs`](crate::sys::statvfs::statvfs). +/// +/// # Arguments +/// +/// `path` - Path to any file within the file system to describe +pub fn statfs(path: &P) -> Result { + unsafe { + let mut stat = mem::MaybeUninit::::uninit(); + let res = path.with_nix_path(|path| { + LIBC_STATFS(path.as_ptr(), stat.as_mut_ptr()) + })?; + Errno::result(res).map(|_| Statfs(stat.assume_init())) + } +} + +/// Describes a mounted file system. +/// +/// The result is OS-dependent. For a portable alternative, see +/// [`fstatvfs`](crate::sys::statvfs::fstatvfs). +/// +/// # Arguments +/// +/// `fd` - File descriptor of any open file within the file system to describe +pub fn fstatfs(fd: &T) -> Result { + unsafe { + let mut stat = mem::MaybeUninit::::uninit(); + Errno::result(LIBC_FSTATFS(fd.as_raw_fd(), stat.as_mut_ptr())) + .map(|_| Statfs(stat.assume_init())) + } +} + +#[cfg(test)] +mod test { + use std::fs::File; + + use crate::sys::statfs::*; + use crate::sys::statvfs::*; + use std::path::Path; + + #[test] + fn statfs_call() { + check_statfs("/tmp"); + check_statfs("/dev"); + check_statfs("/run"); + check_statfs("/"); + } + + #[test] + fn fstatfs_call() { + check_fstatfs("/tmp"); + check_fstatfs("/dev"); + check_fstatfs("/run"); + check_fstatfs("/"); + } + + fn check_fstatfs(path: &str) { + if !Path::new(path).exists() { + return; + } + let vfs = statvfs(path.as_bytes()).unwrap(); + let file = File::open(path).unwrap(); + let fs = fstatfs(&file).unwrap(); + assert_fs_equals(fs, vfs); + } + + fn check_statfs(path: &str) { + if !Path::new(path).exists() { + return; + } + let vfs = statvfs(path.as_bytes()).unwrap(); + let fs = statfs(path.as_bytes()).unwrap(); + assert_fs_equals(fs, vfs); + } + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + fn assert_fs_equals(fs: Statfs, vfs: Statvfs) { + assert_eq!(fs.files() as u64, vfs.files() as u64); + assert_eq!(fs.blocks() as u64, vfs.blocks() as u64); + assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64); + } + + // This test is ignored because files_free/blocks_free can change after statvfs call and before + // statfs call. + #[test] + #[ignore] + fn statfs_call_strict() { + check_statfs_strict("/tmp"); + check_statfs_strict("/dev"); + check_statfs_strict("/run"); + check_statfs_strict("/"); + } + + // This test is ignored because files_free/blocks_free can change after statvfs call and before + // fstatfs call. + #[test] + #[ignore] + fn fstatfs_call_strict() { + check_fstatfs_strict("/tmp"); + check_fstatfs_strict("/dev"); + check_fstatfs_strict("/run"); + check_fstatfs_strict("/"); + } + + fn check_fstatfs_strict(path: &str) { + if !Path::new(path).exists() { + return; + } + let vfs = statvfs(path.as_bytes()); + let file = File::open(path).unwrap(); + let fs = fstatfs(&file); + assert_fs_equals_strict(fs.unwrap(), vfs.unwrap()) + } + + fn check_statfs_strict(path: &str) { + if !Path::new(path).exists() { + return; + } + let vfs = statvfs(path.as_bytes()); + let fs = statfs(path.as_bytes()); + assert_fs_equals_strict(fs.unwrap(), vfs.unwrap()) + } + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) { + assert_eq!(fs.files_free() as u64, vfs.files_free() as u64); + assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64); + assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64); + assert_eq!(fs.files() as u64, vfs.files() as u64); + assert_eq!(fs.blocks() as u64, vfs.blocks() as u64); + assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64); + } +} diff --git a/vendor/nix-0.26.2/src/sys/statvfs.rs b/vendor/nix-0.26.2/src/sys/statvfs.rs new file mode 100644 index 0000000000000..8de369f421630 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/statvfs.rs @@ -0,0 +1,173 @@ +//! Get filesystem statistics +//! +//! See [the man pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html) +//! for more details. +use std::mem; +use std::os::unix::io::AsRawFd; + +use libc::{self, c_ulong}; + +use crate::{errno::Errno, NixPath, Result}; + +#[cfg(not(target_os = "redox"))] +libc_bitflags!( + /// File system mount Flags + #[repr(C)] + #[derive(Default)] + pub struct FsFlags: c_ulong { + /// Read Only + #[cfg(not(target_os = "haiku"))] + ST_RDONLY; + /// Do not allow the set-uid bits to have an effect + #[cfg(not(target_os = "haiku"))] + ST_NOSUID; + /// Do not interpret character or block-special devices + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ST_NODEV; + /// Do not allow execution of binaries on the filesystem + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ST_NOEXEC; + /// All IO should be done synchronously + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ST_SYNCHRONOUS; + /// Allow mandatory locks on the filesystem + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ST_MANDLOCK; + /// Write on file/directory/symlink + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + ST_WRITE; + /// Append-only file + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + ST_APPEND; + /// Immutable file + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + ST_IMMUTABLE; + /// Do not update access times on files + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ST_NOATIME; + /// Do not update access times on files + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ST_NODIRATIME; + /// Update access time relative to modify/change time + #[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ST_RELATIME; + } +); + +/// Wrapper around the POSIX `statvfs` struct +/// +/// For more information see the [`statvfs(3)` man pages](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html). +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct Statvfs(libc::statvfs); + +impl Statvfs { + /// get the file system block size + pub fn block_size(&self) -> c_ulong { + self.0.f_bsize + } + + /// Get the fundamental file system block size + pub fn fragment_size(&self) -> c_ulong { + self.0.f_frsize + } + + /// Get the number of blocks. + /// + /// Units are in units of `fragment_size()` + pub fn blocks(&self) -> libc::fsblkcnt_t { + self.0.f_blocks + } + + /// Get the number of free blocks in the file system + pub fn blocks_free(&self) -> libc::fsblkcnt_t { + self.0.f_bfree + } + + /// Get the number of free blocks for unprivileged users + pub fn blocks_available(&self) -> libc::fsblkcnt_t { + self.0.f_bavail + } + + /// Get the total number of file inodes + pub fn files(&self) -> libc::fsfilcnt_t { + self.0.f_files + } + + /// Get the number of free file inodes + pub fn files_free(&self) -> libc::fsfilcnt_t { + self.0.f_ffree + } + + /// Get the number of free file inodes for unprivileged users + pub fn files_available(&self) -> libc::fsfilcnt_t { + self.0.f_favail + } + + /// Get the file system id + pub fn filesystem_id(&self) -> c_ulong { + self.0.f_fsid + } + + /// Get the mount flags + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn flags(&self) -> FsFlags { + FsFlags::from_bits_truncate(self.0.f_flag) + } + + /// Get the maximum filename length + pub fn name_max(&self) -> c_ulong { + self.0.f_namemax + } +} + +/// Return a `Statvfs` object with information about the `path` +pub fn statvfs(path: &P) -> Result { + unsafe { + Errno::clear(); + let mut stat = mem::MaybeUninit::::uninit(); + let res = path.with_nix_path(|path| { + libc::statvfs(path.as_ptr(), stat.as_mut_ptr()) + })?; + + Errno::result(res).map(|_| Statvfs(stat.assume_init())) + } +} + +/// Return a `Statvfs` object with information about `fd` +pub fn fstatvfs(fd: &T) -> Result { + unsafe { + Errno::clear(); + let mut stat = mem::MaybeUninit::::uninit(); + Errno::result(libc::fstatvfs(fd.as_raw_fd(), stat.as_mut_ptr())) + .map(|_| Statvfs(stat.assume_init())) + } +} + +#[cfg(test)] +mod test { + use crate::sys::statvfs::*; + use std::fs::File; + + #[test] + fn statvfs_call() { + statvfs(&b"/"[..]).unwrap(); + } + + #[test] + fn fstatvfs_call() { + let root = File::open("/").unwrap(); + fstatvfs(&root).unwrap(); + } +} diff --git a/vendor/nix-0.26.2/src/sys/sysinfo.rs b/vendor/nix-0.26.2/src/sys/sysinfo.rs new file mode 100644 index 0000000000000..e8aa00b00d3d6 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/sysinfo.rs @@ -0,0 +1,83 @@ +use libc::{self, SI_LOAD_SHIFT}; +use std::time::Duration; +use std::{cmp, mem}; + +use crate::errno::Errno; +use crate::Result; + +/// System info structure returned by `sysinfo`. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] +#[repr(transparent)] +pub struct SysInfo(libc::sysinfo); + +// The fields are c_ulong on 32-bit linux, u64 on 64-bit linux; x32's ulong is u32 +#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] +type mem_blocks_t = u64; +#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] +type mem_blocks_t = libc::c_ulong; + +impl SysInfo { + /// Returns the load average tuple. + /// + /// The returned values represent the load average over time intervals of + /// 1, 5, and 15 minutes, respectively. + pub fn load_average(&self) -> (f64, f64, f64) { + ( + self.0.loads[0] as f64 / (1 << SI_LOAD_SHIFT) as f64, + self.0.loads[1] as f64 / (1 << SI_LOAD_SHIFT) as f64, + self.0.loads[2] as f64 / (1 << SI_LOAD_SHIFT) as f64, + ) + } + + /// Returns the time since system boot. + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + pub fn uptime(&self) -> Duration { + // Truncate negative values to 0 + Duration::from_secs(cmp::max(self.0.uptime, 0) as u64) + } + + /// Current number of processes. + pub fn process_count(&self) -> u16 { + self.0.procs + } + + /// Returns the amount of swap memory in Bytes. + pub fn swap_total(&self) -> u64 { + self.scale_mem(self.0.totalswap) + } + + /// Returns the amount of unused swap memory in Bytes. + pub fn swap_free(&self) -> u64 { + self.scale_mem(self.0.freeswap) + } + + /// Returns the total amount of installed RAM in Bytes. + pub fn ram_total(&self) -> u64 { + self.scale_mem(self.0.totalram) + } + + /// Returns the amount of completely unused RAM in Bytes. + /// + /// "Unused" in this context means that the RAM in neither actively used by + /// programs, nor by the operating system as disk cache or buffer. It is + /// "wasted" RAM since it currently serves no purpose. + pub fn ram_unused(&self) -> u64 { + self.scale_mem(self.0.freeram) + } + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + fn scale_mem(&self, units: mem_blocks_t) -> u64 { + units as u64 * self.0.mem_unit as u64 + } +} + +/// Returns system information. +/// +/// [See `sysinfo(2)`](https://man7.org/linux/man-pages/man2/sysinfo.2.html). +pub fn sysinfo() -> Result { + let mut info = mem::MaybeUninit::uninit(); + let res = unsafe { libc::sysinfo(info.as_mut_ptr()) }; + Errno::result(res).map(|_| unsafe { SysInfo(info.assume_init()) }) +} diff --git a/vendor/nix-0.26.2/src/sys/termios.rs b/vendor/nix-0.26.2/src/sys/termios.rs new file mode 100644 index 0000000000000..fba2cd8268d53 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/termios.rs @@ -0,0 +1,1227 @@ +//! An interface for controlling asynchronous communication ports +//! +//! This interface provides a safe wrapper around the termios subsystem defined by POSIX. The +//! underlying types are all implemented in libc for most platforms and either wrapped in safer +//! types here or exported directly. +//! +//! If you are unfamiliar with the `termios` API, you should first read the +//! [API documentation](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html) and +//! then come back to understand how `nix` safely wraps it. +//! +//! It should be noted that this API incurs some runtime overhead above the base `libc` definitions. +//! As this interface is not used with high-bandwidth information, this should be fine in most +//! cases. The primary cost when using this API is that the `Termios` datatype here duplicates the +//! standard fields of the underlying `termios` struct and uses safe type wrappers for those fields. +//! This means that when crossing the FFI interface to the underlying C library, data is first +//! copied into the underlying `termios` struct, then the operation is done, and the data is copied +//! back (with additional sanity checking) into the safe wrapper types. The `termios` struct is +//! relatively small across all platforms (on the order of 32-64 bytes). +//! +//! The following examples highlight some of the API use cases such that users coming from using C +//! or reading the standard documentation will understand how to use the safe API exposed here. +//! +//! Example disabling processing of the end-of-file control character: +//! +//! ``` +//! # use self::nix::sys::termios::SpecialCharacterIndices::VEOF; +//! # use self::nix::sys::termios::{_POSIX_VDISABLE, Termios}; +//! # let mut termios: Termios = unsafe { std::mem::zeroed() }; +//! termios.control_chars[VEOF as usize] = _POSIX_VDISABLE; +//! ``` +//! +//! The flags within `Termios` are defined as bitfields using the `bitflags` crate. This provides +//! an interface for working with bitfields that is similar to working with the raw unsigned +//! integer types but offers type safety because of the internal checking that values will always +//! be a valid combination of the defined flags. +//! +//! An example showing some of the basic operations for interacting with the control flags: +//! +//! ``` +//! # use self::nix::sys::termios::{ControlFlags, Termios}; +//! # let mut termios: Termios = unsafe { std::mem::zeroed() }; +//! termios.control_flags & ControlFlags::CSIZE == ControlFlags::CS5; +//! termios.control_flags |= ControlFlags::CS5; +//! ``` +//! +//! # Baud rates +//! +//! This API is not consistent across platforms when it comes to `BaudRate`: Android and Linux both +//! only support the rates specified by the `BaudRate` enum through their termios API while the BSDs +//! support arbitrary baud rates as the values of the `BaudRate` enum constants are the same integer +//! value of the constant (`B9600` == `9600`). Therefore the `nix::termios` API uses the following +//! conventions: +//! +//! * `cfgetispeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux +//! * `cfgetospeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux +//! * `cfsetispeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux +//! * `cfsetospeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux +//! * `cfsetspeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux +//! +//! The most common use case of specifying a baud rate using the enum will work the same across +//! platforms: +//! +//! ```rust +//! # use nix::sys::termios::{BaudRate, cfsetispeed, cfsetospeed, cfsetspeed, Termios}; +//! # fn main() { +//! # let mut t: Termios = unsafe { std::mem::zeroed() }; +//! cfsetispeed(&mut t, BaudRate::B9600).unwrap(); +//! cfsetospeed(&mut t, BaudRate::B9600).unwrap(); +//! cfsetspeed(&mut t, BaudRate::B9600).unwrap(); +//! # } +//! ``` +//! +//! Additionally round-tripping baud rates is consistent across platforms: +//! +//! ```rust +//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetispeed, cfsetspeed, Termios}; +//! # fn main() { +//! # let mut t: Termios = unsafe { std::mem::zeroed() }; +//! # cfsetspeed(&mut t, BaudRate::B9600).unwrap(); +//! let speed = cfgetispeed(&t); +//! assert_eq!(speed, cfgetospeed(&t)); +//! cfsetispeed(&mut t, speed).unwrap(); +//! # } +//! ``` +//! +//! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`: +//! +#![cfg_attr( + any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ), + doc = " ```rust,ignore" +)] +#![cfg_attr( + not(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + )), + doc = " ```rust" +)] +//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; +//! # fn main() { +//! # let mut t: Termios = unsafe { std::mem::zeroed() }; +//! # cfsetspeed(&mut t, BaudRate::B9600); +//! assert_eq!(cfgetispeed(&t), BaudRate::B9600); +//! assert_eq!(cfgetospeed(&t), BaudRate::B9600); +//! # } +//! ``` +//! +//! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s: +//! +#![cfg_attr( + any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ), + doc = " ```rust" +)] +#![cfg_attr( + not(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + )), + doc = " ```rust,ignore" +)] +//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; +//! # fn main() { +//! # let mut t: Termios = unsafe { std::mem::zeroed() }; +//! # cfsetspeed(&mut t, 9600u32); +//! assert_eq!(cfgetispeed(&t), 9600u32); +//! assert_eq!(cfgetospeed(&t), 9600u32); +//! # } +//! ``` +//! +//! It's trivial to convert from a `BaudRate` to a `u32` on BSDs: +//! +#![cfg_attr( + any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ), + doc = " ```rust" +)] +#![cfg_attr( + not(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + )), + doc = " ```rust,ignore" +)] +//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios}; +//! # fn main() { +//! # let mut t: Termios = unsafe { std::mem::zeroed() }; +//! # cfsetspeed(&mut t, 9600u32); +//! assert_eq!(cfgetispeed(&t), BaudRate::B9600.into()); +//! assert_eq!(u32::from(BaudRate::B9600), 9600u32); +//! # } +//! ``` +//! +//! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support) +//! by specifying baud rates directly using `u32`s: +//! +#![cfg_attr( + any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ), + doc = " ```rust" +)] +#![cfg_attr( + not(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + )), + doc = " ```rust,ignore" +)] +//! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios}; +//! # fn main() { +//! # let mut t: Termios = unsafe { std::mem::zeroed() }; +//! cfsetispeed(&mut t, 9600u32); +//! cfsetospeed(&mut t, 9600u32); +//! cfsetspeed(&mut t, 9600u32); +//! # } +//! ``` +use crate::errno::Errno; +use crate::Result; +use cfg_if::cfg_if; +use libc::{self, c_int, tcflag_t}; +use std::cell::{Ref, RefCell}; +use std::convert::From; +use std::mem; +use std::os::unix::io::RawFd; + +#[cfg(feature = "process")] +use crate::unistd::Pid; + +/// Stores settings for the termios API +/// +/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the +/// standard fields. The only safe way to obtain an instance of this struct is to extract it from +/// an open port using `tcgetattr()`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Termios { + inner: RefCell, + /// Input mode flags (see `termios.c_iflag` documentation) + pub input_flags: InputFlags, + /// Output mode flags (see `termios.c_oflag` documentation) + pub output_flags: OutputFlags, + /// Control mode flags (see `termios.c_cflag` documentation) + pub control_flags: ControlFlags, + /// Local mode flags (see `termios.c_lflag` documentation) + pub local_flags: LocalFlags, + /// Control characters (see `termios.c_cc` documentation) + pub control_chars: [libc::cc_t; NCCS], + /// Line discipline (see `termios.c_line` documentation) + #[cfg(any(target_os = "linux", target_os = "android",))] + pub line_discipline: libc::cc_t, + /// Line discipline (see `termios.c_line` documentation) + #[cfg(target_os = "haiku")] + pub line_discipline: libc::c_char, +} + +impl Termios { + /// Exposes an immutable reference to the underlying `libc::termios` data structure. + /// + /// This is not part of `nix`'s public API because it requires additional work to maintain type + /// safety. + pub(crate) fn get_libc_termios(&self) -> Ref { + { + let mut termios = self.inner.borrow_mut(); + termios.c_iflag = self.input_flags.bits(); + termios.c_oflag = self.output_flags.bits(); + termios.c_cflag = self.control_flags.bits(); + termios.c_lflag = self.local_flags.bits(); + termios.c_cc = self.control_chars; + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "haiku", + ))] + { + termios.c_line = self.line_discipline; + } + } + self.inner.borrow() + } + + /// Exposes the inner `libc::termios` datastore within `Termios`. + /// + /// This is unsafe because if this is used to modify the inner `libc::termios` struct, it will + /// not automatically update the safe wrapper type around it. In this case it should also be + /// paired with a call to `update_wrapper()` so that the wrapper-type and internal + /// representation stay consistent. + pub(crate) unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios { + { + let mut termios = self.inner.borrow_mut(); + termios.c_iflag = self.input_flags.bits(); + termios.c_oflag = self.output_flags.bits(); + termios.c_cflag = self.control_flags.bits(); + termios.c_lflag = self.local_flags.bits(); + termios.c_cc = self.control_chars; + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "haiku", + ))] + { + termios.c_line = self.line_discipline; + } + } + self.inner.as_ptr() + } + + /// Updates the wrapper values from the internal `libc::termios` data structure. + pub(crate) fn update_wrapper(&mut self) { + let termios = *self.inner.borrow_mut(); + self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag); + self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag); + self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag); + self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag); + self.control_chars = termios.c_cc; + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "haiku", + ))] + { + self.line_discipline = termios.c_line; + } + } +} + +impl From for Termios { + fn from(termios: libc::termios) -> Self { + Termios { + inner: RefCell::new(termios), + input_flags: InputFlags::from_bits_truncate(termios.c_iflag), + output_flags: OutputFlags::from_bits_truncate(termios.c_oflag), + control_flags: ControlFlags::from_bits_truncate(termios.c_cflag), + local_flags: LocalFlags::from_bits_truncate(termios.c_lflag), + control_chars: termios.c_cc, + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "haiku", + ))] + line_discipline: termios.c_line, + } + } +} + +impl From for libc::termios { + fn from(termios: Termios) -> Self { + termios.inner.into_inner() + } +} + +libc_enum! { + /// Baud rates supported by the system. + /// + /// For the BSDs, arbitrary baud rates can be specified by using `u32`s directly instead of this + /// enum. + /// + /// B0 is special and will disable the port. + #[cfg_attr(all(any(target_os = "haiku"), target_pointer_width = "64"), repr(u8))] + #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))] + #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos", target_os = "haiku"), target_pointer_width = "64")), repr(u32))] + #[non_exhaustive] + pub enum BaudRate { + B0, + B50, + B75, + B110, + B134, + B150, + B200, + B300, + B600, + B1200, + B1800, + B2400, + B4800, + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B7200, + B9600, + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B14400, + B19200, + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B28800, + B38400, + B57600, + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B76800, + B115200, + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B153600, + B230400, + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B307200, + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B460800, + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B500000, + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B576000, + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B921600, + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B1000000, + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B1152000, + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B1500000, + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B2000000, + #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B2500000, + #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B3000000, + #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B3500000, + #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] + B4000000, + } + impl TryFrom +} + +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] +impl From for u32 { + fn from(b: BaudRate) -> u32 { + b as u32 + } +} + +#[cfg(target_os = "haiku")] +impl From for u8 { + fn from(b: BaudRate) -> u8 { + b as u8 + } +} + +// TODO: Add TCSASOFT, which will require treating this as a bitfield. +libc_enum! { + /// Specify when a port configuration change should occur. + /// + /// Used as an argument to `tcsetattr()` + #[repr(i32)] + #[non_exhaustive] + pub enum SetArg { + /// The change will occur immediately + TCSANOW, + /// The change occurs after all output has been written + TCSADRAIN, + /// Same as `TCSADRAIN`, but will also flush the input buffer + TCSAFLUSH, + } +} + +libc_enum! { + /// Specify a combination of the input and output buffers to flush + /// + /// Used as an argument to `tcflush()`. + #[repr(i32)] + #[non_exhaustive] + pub enum FlushArg { + /// Flush data that was received but not read + TCIFLUSH, + /// Flush data written but not transmitted + TCOFLUSH, + /// Flush both received data not read and written data not transmitted + TCIOFLUSH, + } +} + +libc_enum! { + /// Specify how transmission flow should be altered + /// + /// Used as an argument to `tcflow()`. + #[repr(i32)] + #[non_exhaustive] + pub enum FlowArg { + /// Suspend transmission + TCOOFF, + /// Resume transmission + TCOON, + /// Transmit a STOP character, which should disable a connected terminal device + TCIOFF, + /// Transmit a START character, which should re-enable a connected terminal device + TCION, + } +} + +// TODO: Make this usable directly as a slice index. +#[cfg(not(target_os = "haiku"))] +libc_enum! { + /// Indices into the `termios.c_cc` array for special characters. + #[repr(usize)] + #[non_exhaustive] + pub enum SpecialCharacterIndices { + VDISCARD, + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + VDSUSP, + VEOF, + VEOL, + VEOL2, + VERASE, + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + VERASE2, + VINTR, + VKILL, + VLNEXT, + #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), + target_os = "illumos", target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + VMIN, + VQUIT, + VREPRINT, + VSTART, + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + VSTATUS, + VSTOP, + VSUSP, + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + VSWTC, + #[cfg(any(target_os = "haiku", target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + VSWTCH, + #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), + target_os = "illumos", target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + VTIME, + VWERASE, + #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] + VCHECKPT, + } +} + +#[cfg(any( + all(target_os = "linux", target_arch = "sparc64"), + target_os = "illumos", + target_os = "solaris" +))] +impl SpecialCharacterIndices { + pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF; + pub const VTIME: SpecialCharacterIndices = SpecialCharacterIndices::VEOL; +} + +pub use libc::NCCS; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub use libc::_POSIX_VDISABLE; + +libc_bitflags! { + /// Flags for configuring the input mode of a terminal + pub struct InputFlags: tcflag_t { + IGNBRK; + BRKINT; + IGNPAR; + PARMRK; + INPCK; + ISTRIP; + INLCR; + IGNCR; + ICRNL; + IXON; + IXOFF; + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IXANY; + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IMAXBEL; + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IUTF8; + } +} + +libc_bitflags! { + /// Flags for configuring the output mode of a terminal + pub struct OutputFlags: tcflag_t { + OPOST; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "linux", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + OLCUC; + ONLCR; + OCRNL as tcflag_t; + ONOCR as tcflag_t; + ONLRET as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + OFILL as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + OFDEL as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NL0 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NL1 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CR0 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CR1 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CR2 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CR3 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + TAB0 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + TAB1 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + TAB2 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + TAB3 as tcflag_t; + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + XTABS; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + BS0 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + BS1 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + VT0 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + VT1 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + FF0 as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + FF1 as tcflag_t; + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + OXTABS; + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ONOEOT as tcflag_t; + + // Bitmasks for use with OutputFlags to select specific settings + // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110 + // is resolved. + + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CRDLY as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + TABDLY as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + BSDLY as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + VTDLY as tcflag_t; + #[cfg(any(target_os = "android", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + FFDLY as tcflag_t; + } +} + +libc_bitflags! { + /// Flags for setting the control mode of a terminal + pub struct ControlFlags: tcflag_t { + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CIGNORE; + CS5; + CS6; + CS7; + CS8; + CSTOPB; + CREAD; + PARENB; + PARODD; + HUPCL; + CLOCAL; + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CRTSCTS; + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CBAUD; + #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CMSPAR; + #[cfg(any(target_os = "android", + all(target_os = "linux", + not(any(target_arch = "powerpc", target_arch = "powerpc64")))))] + CIBAUD; + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CBAUDEX; + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MDMBUF; + #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CHWFLOW; + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CCTS_OFLOW; + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CRTS_IFLOW; + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CDTR_IFLOW; + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CDSR_OFLOW; + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + CCAR_OFLOW; + + // Bitmasks for use with ControlFlags to select specific settings + // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110 + // is resolved. + + CSIZE; + } +} + +libc_bitflags! { + /// Flags for setting any local modes + pub struct LocalFlags: tcflag_t { + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ECHOKE; + ECHOE; + ECHOK; + ECHO; + ECHONL; + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ECHOPRT; + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ECHOCTL; + ISIG; + ICANON; + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ALTWERASE; + IEXTEN; + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + EXTPROC; + TOSTOP; + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + FLUSHO; + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NOKERNINFO; + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + PENDIN; + NOFLSH; + } +} + +cfg_if! { + if #[cfg(any(target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] { + /// Get input baud rate (see + /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). + /// + /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + pub fn cfgetispeed(termios: &Termios) -> u32 { + let inner_termios = termios.get_libc_termios(); + unsafe { libc::cfgetispeed(&*inner_termios) as u32 } + } + + /// Get output baud rate (see + /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). + /// + /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + pub fn cfgetospeed(termios: &Termios) -> u32 { + let inner_termios = termios.get_libc_termios(); + unsafe { libc::cfgetospeed(&*inner_termios) as u32 } + } + + /// Set input baud rate (see + /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). + /// + /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. + pub fn cfsetispeed>(termios: &mut Termios, baud: T) -> Result<()> { + let inner_termios = unsafe { termios.get_libc_termios_mut() }; + let res = unsafe { libc::cfsetispeed(inner_termios, baud.into() as libc::speed_t) }; + termios.update_wrapper(); + Errno::result(res).map(drop) + } + + /// Set output baud rate (see + /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). + /// + /// `cfsetospeed()` sets the output baud rate in the given termios structure. + pub fn cfsetospeed>(termios: &mut Termios, baud: T) -> Result<()> { + let inner_termios = unsafe { termios.get_libc_termios_mut() }; + let res = unsafe { libc::cfsetospeed(inner_termios, baud.into() as libc::speed_t) }; + termios.update_wrapper(); + Errno::result(res).map(drop) + } + + /// Set both the input and output baud rates (see + /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)). + /// + /// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that + /// this is part of the 4.4BSD standard and not part of POSIX. + pub fn cfsetspeed>(termios: &mut Termios, baud: T) -> Result<()> { + let inner_termios = unsafe { termios.get_libc_termios_mut() }; + let res = unsafe { libc::cfsetspeed(inner_termios, baud.into() as libc::speed_t) }; + termios.update_wrapper(); + Errno::result(res).map(drop) + } + } else { + use std::convert::TryInto; + + /// Get input baud rate (see + /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). + /// + /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. + pub fn cfgetispeed(termios: &Termios) -> BaudRate { + let inner_termios = termios.get_libc_termios(); + unsafe { libc::cfgetispeed(&*inner_termios) }.try_into().unwrap() + } + + /// Get output baud rate (see + /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). + /// + /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. + pub fn cfgetospeed(termios: &Termios) -> BaudRate { + let inner_termios = termios.get_libc_termios(); + unsafe { libc::cfgetospeed(&*inner_termios) }.try_into().unwrap() + } + + /// Set input baud rate (see + /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). + /// + /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. + pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { + let inner_termios = unsafe { termios.get_libc_termios_mut() }; + let res = unsafe { libc::cfsetispeed(inner_termios, baud as libc::speed_t) }; + termios.update_wrapper(); + Errno::result(res).map(drop) + } + + /// Set output baud rate (see + /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). + /// + /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure. + pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { + let inner_termios = unsafe { termios.get_libc_termios_mut() }; + let res = unsafe { libc::cfsetospeed(inner_termios, baud as libc::speed_t) }; + termios.update_wrapper(); + Errno::result(res).map(drop) + } + + /// Set both the input and output baud rates (see + /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)). + /// + /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that + /// this is part of the 4.4BSD standard and not part of POSIX. + #[cfg(not(target_os = "haiku"))] + pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { + let inner_termios = unsafe { termios.get_libc_termios_mut() }; + let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) }; + termios.update_wrapper(); + Errno::result(res).map(drop) + } + } +} + +/// Configures the port to something like the "raw" mode of the old Version 7 terminal driver (see +/// [termios(3)](https://man7.org/linux/man-pages/man3/termios.3.html)). +/// +/// `cfmakeraw()` configures the termios structure such that input is available character-by- +/// character, echoing is disabled, and all special input and output processing is disabled. Note +/// that this is a non-standard function, but is available on Linux and BSDs. +pub fn cfmakeraw(termios: &mut Termios) { + let inner_termios = unsafe { termios.get_libc_termios_mut() }; + unsafe { + libc::cfmakeraw(inner_termios); + } + termios.update_wrapper(); +} + +/// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see +/// [tcsetattr(3)](https://www.freebsd.org/cgi/man.cgi?query=tcsetattr)). +/// +/// Note that this is a non-standard function, available on FreeBSD. +#[cfg(target_os = "freebsd")] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn cfmakesane(termios: &mut Termios) { + let inner_termios = unsafe { termios.get_libc_termios_mut() }; + unsafe { + libc::cfmakesane(inner_termios); + } + termios.update_wrapper(); +} + +/// Return the configuration of a port +/// [tcgetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html)). +/// +/// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying +/// this structure *will not* reconfigure the port, instead the modifications should be done to +/// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`. +pub fn tcgetattr(fd: RawFd) -> Result { + let mut termios = mem::MaybeUninit::uninit(); + + let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) }; + + Errno::result(res)?; + + unsafe { Ok(termios.assume_init().into()) } +} + +/// Set the configuration for a terminal (see +/// [tcsetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html)). +/// +/// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change +/// takes affect at a time specified by `actions`. Note that this function may return success if +/// *any* of the parameters were successfully set, not only if all were set successfully. +pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> { + let inner_termios = termios.get_libc_termios(); + Errno::result(unsafe { + libc::tcsetattr(fd, actions as c_int, &*inner_termios) + }) + .map(drop) +} + +/// Block until all output data is written (see +/// [tcdrain(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)). +pub fn tcdrain(fd: RawFd) -> Result<()> { + Errno::result(unsafe { libc::tcdrain(fd) }).map(drop) +} + +/// Suspend or resume the transmission or reception of data (see +/// [tcflow(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html)). +/// +/// `tcflow()` suspends of resumes the transmission or reception of data for the given port +/// depending on the value of `action`. +pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> { + Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop) +} + +/// Discard data in the output or input queue (see +/// [tcflush(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html)). +/// +/// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both +/// depending on the value of `action`. +pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> { + Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop) +} + +/// Send a break for a specific duration (see +/// [tcsendbreak(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html)). +/// +/// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream +/// of zero-valued bits for an implementation-defined duration. +pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> { + Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop) +} + +feature! { +#![feature = "process"] +/// Get the session controlled by the given terminal (see +/// [tcgetsid(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)). +pub fn tcgetsid(fd: RawFd) -> Result { + let res = unsafe { libc::tcgetsid(fd) }; + + Errno::result(res).map(Pid::from_raw) +} +} + +#[cfg(test)] +mod test { + use super::*; + use std::convert::TryFrom; + + #[test] + fn try_from() { + assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0)); + #[cfg(not(target_os = "haiku"))] + BaudRate::try_from(999999999).expect_err("assertion failed"); + #[cfg(target_os = "haiku")] + BaudRate::try_from(99).expect_err("assertion failed"); + } +} diff --git a/vendor/nix-0.26.2/src/sys/time.rs b/vendor/nix-0.26.2/src/sys/time.rs new file mode 100644 index 0000000000000..0042c450844c2 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/time.rs @@ -0,0 +1,811 @@ +#[cfg_attr(target_env = "musl", allow(deprecated))] +// https://github.com/rust-lang/libc/issues/1848 +pub use libc::{suseconds_t, time_t}; +use libc::{timespec, timeval}; +use std::convert::From; +use std::time::Duration; +use std::{cmp, fmt, ops}; + +const fn zero_init_timespec() -> timespec { + // `std::mem::MaybeUninit::zeroed()` is not yet a const fn + // (https://github.com/rust-lang/rust/issues/91850) so we will instead initialize an array of + // the appropriate size to zero and then transmute it to a timespec value. + unsafe { std::mem::transmute([0u8; std::mem::size_of::()]) } +} + +#[cfg(any( + all(feature = "time", any(target_os = "android", target_os = "linux")), + all( + any( + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd" + ), + feature = "time", + feature = "signal" + ) +))] +pub(crate) mod timer { + use crate::sys::time::{zero_init_timespec, TimeSpec}; + use bitflags::bitflags; + + #[derive(Debug, Clone, Copy)] + pub(crate) struct TimerSpec(libc::itimerspec); + + impl TimerSpec { + pub const fn none() -> Self { + Self(libc::itimerspec { + it_interval: zero_init_timespec(), + it_value: zero_init_timespec(), + }) + } + } + + impl AsMut for TimerSpec { + fn as_mut(&mut self) -> &mut libc::itimerspec { + &mut self.0 + } + } + + impl AsRef for TimerSpec { + fn as_ref(&self) -> &libc::itimerspec { + &self.0 + } + } + + impl From for TimerSpec { + fn from(expiration: Expiration) -> TimerSpec { + match expiration { + Expiration::OneShot(t) => TimerSpec(libc::itimerspec { + it_interval: zero_init_timespec(), + it_value: *t.as_ref(), + }), + Expiration::IntervalDelayed(start, interval) => { + TimerSpec(libc::itimerspec { + it_interval: *interval.as_ref(), + it_value: *start.as_ref(), + }) + } + Expiration::Interval(t) => TimerSpec(libc::itimerspec { + it_interval: *t.as_ref(), + it_value: *t.as_ref(), + }), + } + } + } + + /// An enumeration allowing the definition of the expiration time of an alarm, + /// recurring or not. + #[derive(Debug, Clone, Copy, Eq, PartialEq)] + pub enum Expiration { + /// Alarm will trigger once after the time given in `TimeSpec` + OneShot(TimeSpec), + /// Alarm will trigger after a specified delay and then every interval of + /// time. + IntervalDelayed(TimeSpec, TimeSpec), + /// Alarm will trigger every specified interval of time. + Interval(TimeSpec), + } + + #[cfg(any(target_os = "android", target_os = "linux"))] + bitflags! { + /// Flags that are used for arming the timer. + pub struct TimerSetTimeFlags: libc::c_int { + const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME; + } + } + #[cfg(any( + target_os = "freebsd", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "illumos" + ))] + bitflags! { + /// Flags that are used for arming the timer. + pub struct TimerSetTimeFlags: libc::c_int { + const TFD_TIMER_ABSTIME = libc::TIMER_ABSTIME; + } + } + + impl From for Expiration { + fn from(timerspec: TimerSpec) -> Expiration { + match timerspec { + TimerSpec(libc::itimerspec { + it_interval: + libc::timespec { + tv_sec: 0, + tv_nsec: 0, + .. + }, + it_value: ts, + }) => Expiration::OneShot(ts.into()), + TimerSpec(libc::itimerspec { + it_interval: int_ts, + it_value: val_ts, + }) => { + if (int_ts.tv_sec == val_ts.tv_sec) + && (int_ts.tv_nsec == val_ts.tv_nsec) + { + Expiration::Interval(int_ts.into()) + } else { + Expiration::IntervalDelayed( + val_ts.into(), + int_ts.into(), + ) + } + } + } + } + } +} + +pub trait TimeValLike: Sized { + #[inline] + fn zero() -> Self { + Self::seconds(0) + } + + #[inline] + fn hours(hours: i64) -> Self { + let secs = hours + .checked_mul(SECS_PER_HOUR) + .expect("TimeValLike::hours ouf of bounds"); + Self::seconds(secs) + } + + #[inline] + fn minutes(minutes: i64) -> Self { + let secs = minutes + .checked_mul(SECS_PER_MINUTE) + .expect("TimeValLike::minutes out of bounds"); + Self::seconds(secs) + } + + fn seconds(seconds: i64) -> Self; + fn milliseconds(milliseconds: i64) -> Self; + fn microseconds(microseconds: i64) -> Self; + fn nanoseconds(nanoseconds: i64) -> Self; + + #[inline] + fn num_hours(&self) -> i64 { + self.num_seconds() / 3600 + } + + #[inline] + fn num_minutes(&self) -> i64 { + self.num_seconds() / 60 + } + + fn num_seconds(&self) -> i64; + fn num_milliseconds(&self) -> i64; + fn num_microseconds(&self) -> i64; + fn num_nanoseconds(&self) -> i64; +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct TimeSpec(timespec); + +const NANOS_PER_SEC: i64 = 1_000_000_000; +const SECS_PER_MINUTE: i64 = 60; +const SECS_PER_HOUR: i64 = 3600; + +#[cfg(target_pointer_width = "64")] +const TS_MAX_SECONDS: i64 = (i64::MAX / NANOS_PER_SEC) - 1; + +#[cfg(target_pointer_width = "32")] +const TS_MAX_SECONDS: i64 = isize::MAX as i64; + +const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS; + +// x32 compatibility +// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437 +#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] +type timespec_tv_nsec_t = i64; +#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] +type timespec_tv_nsec_t = libc::c_long; + +impl From for TimeSpec { + fn from(ts: timespec) -> Self { + Self(ts) + } +} + +impl From for TimeSpec { + fn from(duration: Duration) -> Self { + Self::from_duration(duration) + } +} + +impl From for Duration { + fn from(timespec: TimeSpec) -> Self { + Duration::new(timespec.0.tv_sec as u64, timespec.0.tv_nsec as u32) + } +} + +impl AsRef for TimeSpec { + fn as_ref(&self) -> ×pec { + &self.0 + } +} + +impl AsMut for TimeSpec { + fn as_mut(&mut self) -> &mut timespec { + &mut self.0 + } +} + +impl Ord for TimeSpec { + // The implementation of cmp is simplified by assuming that the struct is + // normalized. That is, tv_nsec must always be within [0, 1_000_000_000) + fn cmp(&self, other: &TimeSpec) -> cmp::Ordering { + if self.tv_sec() == other.tv_sec() { + self.tv_nsec().cmp(&other.tv_nsec()) + } else { + self.tv_sec().cmp(&other.tv_sec()) + } + } +} + +impl PartialOrd for TimeSpec { + fn partial_cmp(&self, other: &TimeSpec) -> Option { + Some(self.cmp(other)) + } +} + +impl TimeValLike for TimeSpec { + #[inline] + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 + fn seconds(seconds: i64) -> TimeSpec { + assert!( + (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds), + "TimeSpec out of bounds; seconds={}", + seconds + ); + let mut ts = zero_init_timespec(); + ts.tv_sec = seconds as time_t; + TimeSpec(ts) + } + + #[inline] + fn milliseconds(milliseconds: i64) -> TimeSpec { + let nanoseconds = milliseconds + .checked_mul(1_000_000) + .expect("TimeSpec::milliseconds out of bounds"); + + TimeSpec::nanoseconds(nanoseconds) + } + + /// Makes a new `TimeSpec` with given number of microseconds. + #[inline] + fn microseconds(microseconds: i64) -> TimeSpec { + let nanoseconds = microseconds + .checked_mul(1_000) + .expect("TimeSpec::milliseconds out of bounds"); + + TimeSpec::nanoseconds(nanoseconds) + } + + /// Makes a new `TimeSpec` with given number of nanoseconds. + #[inline] + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 + fn nanoseconds(nanoseconds: i64) -> TimeSpec { + let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC); + assert!( + (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs), + "TimeSpec out of bounds" + ); + let mut ts = zero_init_timespec(); + ts.tv_sec = secs as time_t; + ts.tv_nsec = nanos as timespec_tv_nsec_t; + TimeSpec(ts) + } + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + fn num_seconds(&self) -> i64 { + if self.tv_sec() < 0 && self.tv_nsec() > 0 { + (self.tv_sec() + 1) as i64 + } else { + self.tv_sec() as i64 + } + } + + fn num_milliseconds(&self) -> i64 { + self.num_nanoseconds() / 1_000_000 + } + + fn num_microseconds(&self) -> i64 { + self.num_nanoseconds() / 1_000 + } + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + fn num_nanoseconds(&self) -> i64 { + let secs = self.num_seconds() * 1_000_000_000; + let nsec = self.nanos_mod_sec(); + secs + nsec as i64 + } +} + +impl TimeSpec { + /// Construct a new `TimeSpec` from its components + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self { + let mut ts = zero_init_timespec(); + ts.tv_sec = seconds; + ts.tv_nsec = nanoseconds; + Self(ts) + } + + fn nanos_mod_sec(&self) -> timespec_tv_nsec_t { + if self.tv_sec() < 0 && self.tv_nsec() > 0 { + self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t + } else { + self.tv_nsec() + } + } + + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + pub const fn tv_sec(&self) -> time_t { + self.0.tv_sec + } + + pub const fn tv_nsec(&self) -> timespec_tv_nsec_t { + self.0.tv_nsec + } + + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 + pub const fn from_duration(duration: Duration) -> Self { + let mut ts = zero_init_timespec(); + ts.tv_sec = duration.as_secs() as time_t; + ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t; + TimeSpec(ts) + } + + pub const fn from_timespec(timespec: timespec) -> Self { + Self(timespec) + } +} + +impl ops::Neg for TimeSpec { + type Output = TimeSpec; + + fn neg(self) -> TimeSpec { + TimeSpec::nanoseconds(-self.num_nanoseconds()) + } +} + +impl ops::Add for TimeSpec { + type Output = TimeSpec; + + fn add(self, rhs: TimeSpec) -> TimeSpec { + TimeSpec::nanoseconds(self.num_nanoseconds() + rhs.num_nanoseconds()) + } +} + +impl ops::Sub for TimeSpec { + type Output = TimeSpec; + + fn sub(self, rhs: TimeSpec) -> TimeSpec { + TimeSpec::nanoseconds(self.num_nanoseconds() - rhs.num_nanoseconds()) + } +} + +impl ops::Mul for TimeSpec { + type Output = TimeSpec; + + fn mul(self, rhs: i32) -> TimeSpec { + let usec = self + .num_nanoseconds() + .checked_mul(i64::from(rhs)) + .expect("TimeSpec multiply out of bounds"); + + TimeSpec::nanoseconds(usec) + } +} + +impl ops::Div for TimeSpec { + type Output = TimeSpec; + + fn div(self, rhs: i32) -> TimeSpec { + let usec = self.num_nanoseconds() / i64::from(rhs); + TimeSpec::nanoseconds(usec) + } +} + +impl fmt::Display for TimeSpec { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let (abs, sign) = if self.tv_sec() < 0 { + (-*self, "-") + } else { + (*self, "") + }; + + let sec = abs.tv_sec(); + + write!(f, "{}", sign)?; + + if abs.tv_nsec() == 0 { + if abs.tv_sec() == 1 { + write!(f, "{} second", sec)?; + } else { + write!(f, "{} seconds", sec)?; + } + } else if abs.tv_nsec() % 1_000_000 == 0 { + write!(f, "{}.{:03} seconds", sec, abs.tv_nsec() / 1_000_000)?; + } else if abs.tv_nsec() % 1_000 == 0 { + write!(f, "{}.{:06} seconds", sec, abs.tv_nsec() / 1_000)?; + } else { + write!(f, "{}.{:09} seconds", sec, abs.tv_nsec())?; + } + + Ok(()) + } +} + +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct TimeVal(timeval); + +const MICROS_PER_SEC: i64 = 1_000_000; + +#[cfg(target_pointer_width = "64")] +const TV_MAX_SECONDS: i64 = (i64::MAX / MICROS_PER_SEC) - 1; + +#[cfg(target_pointer_width = "32")] +const TV_MAX_SECONDS: i64 = isize::MAX as i64; + +const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS; + +impl AsRef for TimeVal { + fn as_ref(&self) -> &timeval { + &self.0 + } +} + +impl AsMut for TimeVal { + fn as_mut(&mut self) -> &mut timeval { + &mut self.0 + } +} + +impl Ord for TimeVal { + // The implementation of cmp is simplified by assuming that the struct is + // normalized. That is, tv_usec must always be within [0, 1_000_000) + fn cmp(&self, other: &TimeVal) -> cmp::Ordering { + if self.tv_sec() == other.tv_sec() { + self.tv_usec().cmp(&other.tv_usec()) + } else { + self.tv_sec().cmp(&other.tv_sec()) + } + } +} + +impl PartialOrd for TimeVal { + fn partial_cmp(&self, other: &TimeVal) -> Option { + Some(self.cmp(other)) + } +} + +impl TimeValLike for TimeVal { + #[inline] + fn seconds(seconds: i64) -> TimeVal { + assert!( + (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds), + "TimeVal out of bounds; seconds={}", + seconds + ); + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 + TimeVal(timeval { + tv_sec: seconds as time_t, + tv_usec: 0, + }) + } + + #[inline] + fn milliseconds(milliseconds: i64) -> TimeVal { + let microseconds = milliseconds + .checked_mul(1_000) + .expect("TimeVal::milliseconds out of bounds"); + + TimeVal::microseconds(microseconds) + } + + /// Makes a new `TimeVal` with given number of microseconds. + #[inline] + fn microseconds(microseconds: i64) -> TimeVal { + let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); + assert!( + (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), + "TimeVal out of bounds" + ); + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 + TimeVal(timeval { + tv_sec: secs as time_t, + tv_usec: micros as suseconds_t, + }) + } + + /// Makes a new `TimeVal` with given number of nanoseconds. Some precision + /// will be lost + #[inline] + fn nanoseconds(nanoseconds: i64) -> TimeVal { + let microseconds = nanoseconds / 1000; + let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); + assert!( + (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), + "TimeVal out of bounds" + ); + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 + TimeVal(timeval { + tv_sec: secs as time_t, + tv_usec: micros as suseconds_t, + }) + } + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + fn num_seconds(&self) -> i64 { + if self.tv_sec() < 0 && self.tv_usec() > 0 { + (self.tv_sec() + 1) as i64 + } else { + self.tv_sec() as i64 + } + } + + fn num_milliseconds(&self) -> i64 { + self.num_microseconds() / 1_000 + } + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + fn num_microseconds(&self) -> i64 { + let secs = self.num_seconds() * 1_000_000; + let usec = self.micros_mod_sec(); + secs + usec as i64 + } + + fn num_nanoseconds(&self) -> i64 { + self.num_microseconds() * 1_000 + } +} + +impl TimeVal { + /// Construct a new `TimeVal` from its components + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + pub const fn new(seconds: time_t, microseconds: suseconds_t) -> Self { + Self(timeval { + tv_sec: seconds, + tv_usec: microseconds, + }) + } + + fn micros_mod_sec(&self) -> suseconds_t { + if self.tv_sec() < 0 && self.tv_usec() > 0 { + self.tv_usec() - MICROS_PER_SEC as suseconds_t + } else { + self.tv_usec() + } + } + + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + pub const fn tv_sec(&self) -> time_t { + self.0.tv_sec + } + + pub const fn tv_usec(&self) -> suseconds_t { + self.0.tv_usec + } +} + +impl ops::Neg for TimeVal { + type Output = TimeVal; + + fn neg(self) -> TimeVal { + TimeVal::microseconds(-self.num_microseconds()) + } +} + +impl ops::Add for TimeVal { + type Output = TimeVal; + + fn add(self, rhs: TimeVal) -> TimeVal { + TimeVal::microseconds(self.num_microseconds() + rhs.num_microseconds()) + } +} + +impl ops::Sub for TimeVal { + type Output = TimeVal; + + fn sub(self, rhs: TimeVal) -> TimeVal { + TimeVal::microseconds(self.num_microseconds() - rhs.num_microseconds()) + } +} + +impl ops::Mul for TimeVal { + type Output = TimeVal; + + fn mul(self, rhs: i32) -> TimeVal { + let usec = self + .num_microseconds() + .checked_mul(i64::from(rhs)) + .expect("TimeVal multiply out of bounds"); + + TimeVal::microseconds(usec) + } +} + +impl ops::Div for TimeVal { + type Output = TimeVal; + + fn div(self, rhs: i32) -> TimeVal { + let usec = self.num_microseconds() / i64::from(rhs); + TimeVal::microseconds(usec) + } +} + +impl fmt::Display for TimeVal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let (abs, sign) = if self.tv_sec() < 0 { + (-*self, "-") + } else { + (*self, "") + }; + + let sec = abs.tv_sec(); + + write!(f, "{}", sign)?; + + if abs.tv_usec() == 0 { + if abs.tv_sec() == 1 { + write!(f, "{} second", sec)?; + } else { + write!(f, "{} seconds", sec)?; + } + } else if abs.tv_usec() % 1000 == 0 { + write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000)?; + } else { + write!(f, "{}.{:06} seconds", sec, abs.tv_usec())?; + } + + Ok(()) + } +} + +impl From for TimeVal { + fn from(tv: timeval) -> Self { + TimeVal(tv) + } +} + +#[inline] +fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { + (div_floor_64(this, other), mod_floor_64(this, other)) +} + +#[inline] +fn div_floor_64(this: i64, other: i64) -> i64 { + match div_rem_64(this, other) { + (d, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => d - 1, + (d, _) => d, + } +} + +#[inline] +fn mod_floor_64(this: i64, other: i64) -> i64 { + match this % other { + r if (r > 0 && other < 0) || (r < 0 && other > 0) => r + other, + r => r, + } +} + +#[inline] +fn div_rem_64(this: i64, other: i64) -> (i64, i64) { + (this / other, this % other) +} + +#[cfg(test)] +mod test { + use super::{TimeSpec, TimeVal, TimeValLike}; + use std::time::Duration; + + #[test] + pub fn test_timespec() { + assert_ne!(TimeSpec::seconds(1), TimeSpec::zero()); + assert_eq!( + TimeSpec::seconds(1) + TimeSpec::seconds(2), + TimeSpec::seconds(3) + ); + assert_eq!( + TimeSpec::minutes(3) + TimeSpec::seconds(2), + TimeSpec::seconds(182) + ); + } + + #[test] + pub fn test_timespec_from() { + let duration = Duration::new(123, 123_456_789); + let timespec = TimeSpec::nanoseconds(123_123_456_789); + + assert_eq!(TimeSpec::from(duration), timespec); + assert_eq!(Duration::from(timespec), duration); + } + + #[test] + pub fn test_timespec_neg() { + let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123); + let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123); + + assert_eq!(a, -b); + } + + #[test] + pub fn test_timespec_ord() { + assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000)); + assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001)); + assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999)); + assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999)); + assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001)); + } + + #[test] + pub fn test_timespec_fmt() { + assert_eq!(TimeSpec::zero().to_string(), "0 seconds"); + assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds"); + assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds"); + assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds"); + assert_eq!( + TimeSpec::nanoseconds(42).to_string(), + "0.000000042 seconds" + ); + assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds"); + } + + #[test] + pub fn test_timeval() { + assert_ne!(TimeVal::seconds(1), TimeVal::zero()); + assert_eq!( + TimeVal::seconds(1) + TimeVal::seconds(2), + TimeVal::seconds(3) + ); + assert_eq!( + TimeVal::minutes(3) + TimeVal::seconds(2), + TimeVal::seconds(182) + ); + } + + #[test] + pub fn test_timeval_ord() { + assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000)); + assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001)); + assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999)); + assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999)); + assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001)); + } + + #[test] + pub fn test_timeval_neg() { + let a = TimeVal::seconds(1) + TimeVal::microseconds(123); + let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123); + + assert_eq!(a, -b); + } + + #[test] + pub fn test_timeval_fmt() { + assert_eq!(TimeVal::zero().to_string(), "0 seconds"); + assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds"); + assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds"); + assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds"); + assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds"); + assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds"); + } +} diff --git a/vendor/nix-0.26.2/src/sys/timer.rs b/vendor/nix-0.26.2/src/sys/timer.rs new file mode 100644 index 0000000000000..e1a34051e8a3d --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/timer.rs @@ -0,0 +1,187 @@ +//! Timer API via signals. +//! +//! Timer is a POSIX API to create timers and get expiration notifications +//! through queued Unix signals, for the current process. This is similar to +//! Linux's timerfd mechanism, except that API is specific to Linux and makes +//! use of file polling. +//! +//! For more documentation, please read [timer_create](https://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_create.html). +//! +//! # Examples +//! +//! Create an interval timer that signals SIGALARM every 250 milliseconds. +//! +//! ```no_run +//! use nix::sys::signal::{self, SigEvent, SigHandler, SigevNotify, Signal}; +//! use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags}; +//! use nix::time::ClockId; +//! use std::convert::TryFrom; +//! use std::sync::atomic::{AtomicU64, Ordering}; +//! use std::thread::yield_now; +//! use std::time::Duration; +//! +//! const SIG: Signal = Signal::SIGALRM; +//! static ALARMS: AtomicU64 = AtomicU64::new(0); +//! +//! extern "C" fn handle_alarm(signal: libc::c_int) { +//! let signal = Signal::try_from(signal).unwrap(); +//! if signal == SIG { +//! ALARMS.fetch_add(1, Ordering::Relaxed); +//! } +//! } +//! +//! fn main() { +//! let clockid = ClockId::CLOCK_MONOTONIC; +//! let sigevent = SigEvent::new(SigevNotify::SigevSignal { +//! signal: SIG, +//! si_value: 0, +//! }); +//! +//! let mut timer = Timer::new(clockid, sigevent).unwrap(); +//! let expiration = Expiration::Interval(Duration::from_millis(250).into()); +//! let flags = TimerSetTimeFlags::empty(); +//! timer.set(expiration, flags).expect("could not set timer"); +//! +//! let handler = SigHandler::Handler(handle_alarm); +//! unsafe { signal::signal(SIG, handler) }.unwrap(); +//! +//! loop { +//! let alarms = ALARMS.load(Ordering::Relaxed); +//! if alarms >= 10 { +//! println!("total alarms handled: {}", alarms); +//! break; +//! } +//! yield_now() +//! } +//! } +//! ``` +use crate::sys::signal::SigEvent; +use crate::sys::time::timer::TimerSpec; +pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags}; +use crate::time::ClockId; +use crate::{errno::Errno, Result}; +use core::mem; + +/// A Unix signal per-process timer. +#[derive(Debug)] +#[repr(transparent)] +pub struct Timer(libc::timer_t); + +impl Timer { + /// Creates a new timer based on the clock defined by `clockid`. The details + /// of the signal and its handler are defined by the passed `sigevent`. + #[doc(alias("timer_create"))] + pub fn new(clockid: ClockId, mut sigevent: SigEvent) -> Result { + let mut timer_id: mem::MaybeUninit = + mem::MaybeUninit::uninit(); + Errno::result(unsafe { + libc::timer_create( + clockid.as_raw(), + sigevent.as_mut_ptr(), + timer_id.as_mut_ptr(), + ) + }) + .map(|_| { + // SAFETY: libc::timer_create is responsible for initializing + // timer_id. + unsafe { Self(timer_id.assume_init()) } + }) + } + + /// Set a new alarm on the timer. + /// + /// # Types of alarm + /// + /// There are 3 types of alarms you can set: + /// + /// - one shot: the alarm will trigger once after the specified amount of + /// time. + /// Example: I want an alarm to go off in 60s and then disable itself. + /// + /// - interval: the alarm will trigger every specified interval of time. + /// Example: I want an alarm to go off every 60s. The alarm will first + /// go off 60s after I set it and every 60s after that. The alarm will + /// not disable itself. + /// + /// - interval delayed: the alarm will trigger after a certain amount of + /// time and then trigger at a specified interval. + /// Example: I want an alarm to go off every 60s but only start in 1h. + /// The alarm will first trigger 1h after I set it and then every 60s + /// after that. The alarm will not disable itself. + /// + /// # Relative vs absolute alarm + /// + /// If you do not set any `TimerSetTimeFlags`, then the `TimeSpec` you pass + /// to the `Expiration` you want is relative. If however you want an alarm + /// to go off at a certain point in time, you can set `TFD_TIMER_ABSTIME`. + /// Then the one shot TimeSpec and the delay TimeSpec of the delayed + /// interval are going to be interpreted as absolute. + /// + /// # Disabling alarms + /// + /// Note: Only one alarm can be set for any given timer. Setting a new alarm + /// actually removes the previous one. + /// + /// Note: Setting a one shot alarm with a 0s TimeSpec disable the alarm + /// altogether. + #[doc(alias("timer_settime"))] + pub fn set( + &mut self, + expiration: Expiration, + flags: TimerSetTimeFlags, + ) -> Result<()> { + let timerspec: TimerSpec = expiration.into(); + Errno::result(unsafe { + libc::timer_settime( + self.0, + flags.bits(), + timerspec.as_ref(), + core::ptr::null_mut(), + ) + }) + .map(drop) + } + + /// Get the parameters for the alarm currently set, if any. + #[doc(alias("timer_gettime"))] + pub fn get(&self) -> Result> { + let mut timerspec = TimerSpec::none(); + Errno::result(unsafe { + libc::timer_gettime(self.0, timerspec.as_mut()) + }) + .map(|_| { + if timerspec.as_ref().it_interval.tv_sec == 0 + && timerspec.as_ref().it_interval.tv_nsec == 0 + && timerspec.as_ref().it_value.tv_sec == 0 + && timerspec.as_ref().it_value.tv_nsec == 0 + { + None + } else { + Some(timerspec.into()) + } + }) + } + + /// Return the number of timers that have overrun + /// + /// Each timer is able to queue one signal to the process at a time, meaning + /// if the signal is not handled before the next expiration the timer has + /// 'overrun'. This function returns how many times that has happened to + /// this timer, up to `libc::DELAYTIMER_MAX`. If more than the maximum + /// number of overruns have happened the return is capped to the maximum. + #[doc(alias("timer_getoverrun"))] + pub fn overruns(&self) -> i32 { + unsafe { libc::timer_getoverrun(self.0) } + } +} + +impl Drop for Timer { + fn drop(&mut self) { + if !std::thread::panicking() { + let result = Errno::result(unsafe { libc::timer_delete(self.0) }); + if let Err(Errno::EINVAL) = result { + panic!("close of Timer encountered EINVAL"); + } + } + } +} diff --git a/vendor/nix-0.26.2/src/sys/timerfd.rs b/vendor/nix-0.26.2/src/sys/timerfd.rs new file mode 100644 index 0000000000000..a35fc927f4616 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/timerfd.rs @@ -0,0 +1,214 @@ +//! Timer API via file descriptors. +//! +//! Timer FD is a Linux-only API to create timers and get expiration +//! notifications through file descriptors. +//! +//! For more documentation, please read [timerfd_create(2)](https://man7.org/linux/man-pages/man2/timerfd_create.2.html). +//! +//! # Examples +//! +//! Create a new one-shot timer that expires after 1 second. +//! ``` +//! # use std::os::unix::io::AsRawFd; +//! # use nix::sys::timerfd::{TimerFd, ClockId, TimerFlags, TimerSetTimeFlags, +//! # Expiration}; +//! # use nix::sys::time::{TimeSpec, TimeValLike}; +//! # use nix::unistd::read; +//! # +//! // We create a new monotonic timer. +//! let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()) +//! .unwrap(); +//! +//! // We set a new one-shot timer in 1 seconds. +//! timer.set( +//! Expiration::OneShot(TimeSpec::seconds(1)), +//! TimerSetTimeFlags::empty() +//! ).unwrap(); +//! +//! // We wait for the timer to expire. +//! timer.wait().unwrap(); +//! ``` +use crate::sys::time::timer::TimerSpec; +pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags}; +use crate::unistd::read; +use crate::{errno::Errno, Result}; +use libc::c_int; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; + +/// A timerfd instance. This is also a file descriptor, you can feed it to +/// other interfaces consuming file descriptors, epoll for example. +#[derive(Debug)] +pub struct TimerFd { + fd: RawFd, +} + +impl AsRawFd for TimerFd { + fn as_raw_fd(&self) -> RawFd { + self.fd + } +} + +impl FromRawFd for TimerFd { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + TimerFd { fd } + } +} + +libc_enum! { + /// The type of the clock used to mark the progress of the timer. For more + /// details on each kind of clock, please refer to [timerfd_create(2)](https://man7.org/linux/man-pages/man2/timerfd_create.2.html). + #[repr(i32)] + #[non_exhaustive] + pub enum ClockId { + /// A settable system-wide real-time clock. + CLOCK_REALTIME, + /// A non-settable monotonically increasing clock. + /// + /// Does not change after system startup. + /// Does not measure time while the system is suspended. + CLOCK_MONOTONIC, + /// Like `CLOCK_MONOTONIC`, except that `CLOCK_BOOTTIME` includes the time + /// that the system was suspended. + CLOCK_BOOTTIME, + /// Like `CLOCK_REALTIME`, but will wake the system if it is suspended. + CLOCK_REALTIME_ALARM, + /// Like `CLOCK_BOOTTIME`, but will wake the system if it is suspended. + CLOCK_BOOTTIME_ALARM, + } +} + +libc_bitflags! { + /// Additional flags to change the behaviour of the file descriptor at the + /// time of creation. + pub struct TimerFlags: c_int { + /// Set the `O_NONBLOCK` flag on the open file description referred to by the new file descriptor. + TFD_NONBLOCK; + /// Set the `FD_CLOEXEC` flag on the file descriptor. + TFD_CLOEXEC; + } +} + +impl TimerFd { + /// Creates a new timer based on the clock defined by `clockid`. The + /// underlying fd can be assigned specific flags with `flags` (CLOEXEC, + /// NONBLOCK). The underlying fd will be closed on drop. + #[doc(alias("timerfd_create"))] + pub fn new(clockid: ClockId, flags: TimerFlags) -> Result { + Errno::result(unsafe { + libc::timerfd_create(clockid as i32, flags.bits()) + }) + .map(|fd| Self { fd }) + } + + /// Sets a new alarm on the timer. + /// + /// # Types of alarm + /// + /// There are 3 types of alarms you can set: + /// + /// - one shot: the alarm will trigger once after the specified amount of + /// time. + /// Example: I want an alarm to go off in 60s and then disable itself. + /// + /// - interval: the alarm will trigger every specified interval of time. + /// Example: I want an alarm to go off every 60s. The alarm will first + /// go off 60s after I set it and every 60s after that. The alarm will + /// not disable itself. + /// + /// - interval delayed: the alarm will trigger after a certain amount of + /// time and then trigger at a specified interval. + /// Example: I want an alarm to go off every 60s but only start in 1h. + /// The alarm will first trigger 1h after I set it and then every 60s + /// after that. The alarm will not disable itself. + /// + /// # Relative vs absolute alarm + /// + /// If you do not set any `TimerSetTimeFlags`, then the `TimeSpec` you pass + /// to the `Expiration` you want is relative. If however you want an alarm + /// to go off at a certain point in time, you can set `TFD_TIMER_ABSTIME`. + /// Then the one shot TimeSpec and the delay TimeSpec of the delayed + /// interval are going to be interpreted as absolute. + /// + /// # Disabling alarms + /// + /// Note: Only one alarm can be set for any given timer. Setting a new alarm + /// actually removes the previous one. + /// + /// Note: Setting a one shot alarm with a 0s TimeSpec disables the alarm + /// altogether. + #[doc(alias("timerfd_settime"))] + pub fn set( + &self, + expiration: Expiration, + flags: TimerSetTimeFlags, + ) -> Result<()> { + let timerspec: TimerSpec = expiration.into(); + Errno::result(unsafe { + libc::timerfd_settime( + self.fd, + flags.bits(), + timerspec.as_ref(), + std::ptr::null_mut(), + ) + }) + .map(drop) + } + + /// Get the parameters for the alarm currently set, if any. + #[doc(alias("timerfd_gettime"))] + pub fn get(&self) -> Result> { + let mut timerspec = TimerSpec::none(); + Errno::result(unsafe { + libc::timerfd_gettime(self.fd, timerspec.as_mut()) + }) + .map(|_| { + if timerspec.as_ref().it_interval.tv_sec == 0 + && timerspec.as_ref().it_interval.tv_nsec == 0 + && timerspec.as_ref().it_value.tv_sec == 0 + && timerspec.as_ref().it_value.tv_nsec == 0 + { + None + } else { + Some(timerspec.into()) + } + }) + } + + /// Remove the alarm if any is set. + #[doc(alias("timerfd_settime"))] + pub fn unset(&self) -> Result<()> { + Errno::result(unsafe { + libc::timerfd_settime( + self.fd, + TimerSetTimeFlags::empty().bits(), + TimerSpec::none().as_ref(), + std::ptr::null_mut(), + ) + }) + .map(drop) + } + + /// Wait for the configured alarm to expire. + /// + /// Note: If the alarm is unset, then you will wait forever. + pub fn wait(&self) -> Result<()> { + while let Err(e) = read(self.fd, &mut [0u8; 8]) { + if e != Errno::EINTR { + return Err(e); + } + } + + Ok(()) + } +} + +impl Drop for TimerFd { + fn drop(&mut self) { + if !std::thread::panicking() { + let result = Errno::result(unsafe { libc::close(self.fd) }); + if let Err(Errno::EBADF) = result { + panic!("close of TimerFd encountered EBADF"); + } + } + } +} diff --git a/vendor/nix-0.26.2/src/sys/uio.rs b/vendor/nix-0.26.2/src/sys/uio.rs new file mode 100644 index 0000000000000..b31c3068a7223 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/uio.rs @@ -0,0 +1,291 @@ +//! Vectored I/O + +use crate::errno::Errno; +use crate::Result; +use libc::{self, c_int, c_void, off_t, size_t}; +use std::io::{IoSlice, IoSliceMut}; +use std::marker::PhantomData; +use std::os::unix::io::RawFd; + +/// Low-level vectored write to a raw file descriptor +/// +/// See also [writev(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html) +pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result { + // SAFETY: to quote the documentation for `IoSlice`: + // + // [IoSlice] is semantically a wrapper around a &[u8], but is + // guaranteed to be ABI compatible with the iovec type on Unix + // platforms. + // + // Because it is ABI compatible, a pointer cast here is valid + let res = unsafe { + libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) + }; + + Errno::result(res).map(|r| r as usize) +} + +/// Low-level vectored read from a raw file descriptor +/// +/// See also [readv(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html) +pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result { + // SAFETY: same as in writev(), IoSliceMut is ABI-compatible with iovec + let res = unsafe { + libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) + }; + + Errno::result(res).map(|r| r as usize) +} + +/// Write to `fd` at `offset` from buffers in `iov`. +/// +/// Buffers in `iov` will be written in order until all buffers have been written +/// or an error occurs. The file offset is not changed. +/// +/// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result { + #[cfg(target_env = "uclibc")] + let offset = offset as libc::off64_t; // uclibc doesn't use off_t + + // SAFETY: same as in writev() + let res = unsafe { + libc::pwritev( + fd, + iov.as_ptr() as *const libc::iovec, + iov.len() as c_int, + offset, + ) + }; + + Errno::result(res).map(|r| r as usize) +} + +/// Read from `fd` at `offset` filling buffers in `iov`. +/// +/// Buffers in `iov` will be filled in order until all buffers have been filled, +/// no more bytes are available, or an error occurs. The file offset is not +/// changed. +/// +/// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html) +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn preadv( + fd: RawFd, + iov: &mut [IoSliceMut<'_>], + offset: off_t, +) -> Result { + #[cfg(target_env = "uclibc")] + let offset = offset as libc::off64_t; // uclibc doesn't use off_t + + // SAFETY: same as in readv() + let res = unsafe { + libc::preadv( + fd, + iov.as_ptr() as *const libc::iovec, + iov.len() as c_int, + offset, + ) + }; + + Errno::result(res).map(|r| r as usize) +} + +/// Low-level write to a file, with specified offset. +/// +/// See also [pwrite(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html) +// TODO: move to unistd +pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result { + let res = unsafe { + libc::pwrite( + fd, + buf.as_ptr() as *const c_void, + buf.len() as size_t, + offset, + ) + }; + + Errno::result(res).map(|r| r as usize) +} + +/// Low-level read from a file, with specified offset. +/// +/// See also [pread(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html) +// TODO: move to unistd +pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result { + let res = unsafe { + libc::pread( + fd, + buf.as_mut_ptr() as *mut c_void, + buf.len() as size_t, + offset, + ) + }; + + Errno::result(res).map(|r| r as usize) +} + +/// A slice of memory in a remote process, starting at address `base` +/// and consisting of `len` bytes. +/// +/// This is the same underlying C structure as `IoSlice`, +/// except that it refers to memory in some other process, and is +/// therefore not represented in Rust by an actual slice as `IoSlice` is. It +/// is used with [`process_vm_readv`](fn.process_vm_readv.html) +/// and [`process_vm_writev`](fn.process_vm_writev.html). +#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +#[repr(C)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct RemoteIoVec { + /// The starting address of this slice (`iov_base`). + pub base: usize, + /// The number of bytes in this slice (`iov_len`). + pub len: usize, +} + +/// A vector of buffers. +/// +/// Vectored I/O methods like [`writev`] and [`readv`] use this structure for +/// both reading and writing. Each `IoVec` specifies the base address and +/// length of an area in memory. +#[deprecated( + since = "0.24.0", + note = "`IoVec` is no longer used in the public interface, use `IoSlice` or `IoSliceMut` instead" +)] +#[repr(transparent)] +#[allow(renamed_and_removed_lints)] +#[allow(clippy::unknown_clippy_lints)] +// Clippy false positive: https://github.com/rust-lang/rust-clippy/issues/8867 +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct IoVec(pub(crate) libc::iovec, PhantomData); + +#[allow(deprecated)] +impl IoVec { + /// View the `IoVec` as a Rust slice. + #[deprecated( + since = "0.24.0", + note = "Use the `Deref` impl of `IoSlice` or `IoSliceMut` instead" + )] + #[inline] + pub fn as_slice(&self) -> &[u8] { + use std::slice; + + unsafe { + slice::from_raw_parts(self.0.iov_base as *const u8, self.0.iov_len) + } + } +} + +#[allow(deprecated)] +impl<'a> IoVec<&'a [u8]> { + /// Create an `IoVec` from a Rust slice. + #[deprecated(since = "0.24.0", note = "Use `IoSlice::new` instead")] + pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> { + IoVec( + libc::iovec { + iov_base: buf.as_ptr() as *mut c_void, + iov_len: buf.len() as size_t, + }, + PhantomData, + ) + } +} + +#[allow(deprecated)] +impl<'a> IoVec<&'a mut [u8]> { + /// Create an `IoVec` from a mutable Rust slice. + #[deprecated(since = "0.24.0", note = "Use `IoSliceMut::new` instead")] + pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> { + IoVec( + libc::iovec { + iov_base: buf.as_ptr() as *mut c_void, + iov_len: buf.len() as size_t, + }, + PhantomData, + ) + } +} + +// The only reason IoVec isn't automatically Send+Sync is because libc::iovec +// contains raw pointers. +#[allow(deprecated)] +unsafe impl Send for IoVec where T: Send {} +#[allow(deprecated)] +unsafe impl Sync for IoVec where T: Sync {} + +feature! { +#![feature = "process"] + +/// Write data directly to another process's virtual memory +/// (see [`process_vm_writev`(2)]). +/// +/// `local_iov` is a list of [`IoSlice`]s containing the data to be written, +/// and `remote_iov` is a list of [`RemoteIoVec`]s identifying where the +/// data should be written in the target process. On success, returns the +/// number of bytes written, which will always be a whole +/// number of `remote_iov` chunks. +/// +/// This requires the same permissions as debugging the process using +/// [ptrace]: you must either be a privileged process (with +/// `CAP_SYS_PTRACE`), or you must be running as the same user as the +/// target process and the OS must have unprivileged debugging enabled. +/// +/// This function is only available on Linux and Android(SDK23+). +/// +/// [`process_vm_writev`(2)]: https://man7.org/linux/man-pages/man2/process_vm_writev.2.html +/// [ptrace]: ../ptrace/index.html +/// [`IoSlice`]: https://doc.rust-lang.org/std/io/struct.IoSlice.html +/// [`RemoteIoVec`]: struct.RemoteIoVec.html +#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] +pub fn process_vm_writev( + pid: crate::unistd::Pid, + local_iov: &[IoSlice<'_>], + remote_iov: &[RemoteIoVec]) -> Result +{ + let res = unsafe { + libc::process_vm_writev(pid.into(), + local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, + remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) + }; + + Errno::result(res).map(|r| r as usize) +} + +/// Read data directly from another process's virtual memory +/// (see [`process_vm_readv`(2)]). +/// +/// `local_iov` is a list of [`IoSliceMut`]s containing the buffer to copy +/// data into, and `remote_iov` is a list of [`RemoteIoVec`]s identifying +/// where the source data is in the target process. On success, +/// returns the number of bytes written, which will always be a whole +/// number of `remote_iov` chunks. +/// +/// This requires the same permissions as debugging the process using +/// [`ptrace`]: you must either be a privileged process (with +/// `CAP_SYS_PTRACE`), or you must be running as the same user as the +/// target process and the OS must have unprivileged debugging enabled. +/// +/// This function is only available on Linux and Android(SDK23+). +/// +/// [`process_vm_readv`(2)]: https://man7.org/linux/man-pages/man2/process_vm_readv.2.html +/// [`ptrace`]: ../ptrace/index.html +/// [`IoSliceMut`]: https://doc.rust-lang.org/std/io/struct.IoSliceMut.html +/// [`RemoteIoVec`]: struct.RemoteIoVec.html +#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] +pub fn process_vm_readv( + pid: crate::unistd::Pid, + local_iov: &mut [IoSliceMut<'_>], + remote_iov: &[RemoteIoVec]) -> Result +{ + let res = unsafe { + libc::process_vm_readv(pid.into(), + local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, + remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) + }; + + Errno::result(res).map(|r| r as usize) +} +} diff --git a/vendor/nix-0.26.2/src/sys/utsname.rs b/vendor/nix-0.26.2/src/sys/utsname.rs new file mode 100644 index 0000000000000..b48ed9f45ee10 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/utsname.rs @@ -0,0 +1,85 @@ +//! Get system identification +use crate::{Errno, Result}; +use libc::c_char; +use std::ffi::OsStr; +use std::mem; +use std::os::unix::ffi::OsStrExt; + +/// Describes the running system. Return type of [`uname`]. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(transparent)] +pub struct UtsName(libc::utsname); + +impl UtsName { + /// Name of the operating system implementation. + pub fn sysname(&self) -> &OsStr { + cast_and_trim(&self.0.sysname) + } + + /// Network name of this machine. + pub fn nodename(&self) -> &OsStr { + cast_and_trim(&self.0.nodename) + } + + /// Release level of the operating system. + pub fn release(&self) -> &OsStr { + cast_and_trim(&self.0.release) + } + + /// Version level of the operating system. + pub fn version(&self) -> &OsStr { + cast_and_trim(&self.0.version) + } + + /// Machine hardware platform. + pub fn machine(&self) -> &OsStr { + cast_and_trim(&self.0.machine) + } + + /// NIS or YP domain name of this machine. + #[cfg(any(target_os = "android", target_os = "linux"))] + pub fn domainname(&self) -> &OsStr { + cast_and_trim(&self.0.domainname) + } +} + +/// Get system identification +pub fn uname() -> Result { + unsafe { + let mut ret = mem::MaybeUninit::zeroed(); + Errno::result(libc::uname(ret.as_mut_ptr()))?; + Ok(UtsName(ret.assume_init())) + } +} + +fn cast_and_trim(slice: &[c_char]) -> &OsStr { + let length = slice + .iter() + .position(|&byte| byte == 0) + .unwrap_or(slice.len()); + let bytes = + unsafe { std::slice::from_raw_parts(slice.as_ptr().cast(), length) }; + + OsStr::from_bytes(bytes) +} + +#[cfg(test)] +mod test { + #[cfg(target_os = "linux")] + #[test] + pub fn test_uname_linux() { + assert_eq!(super::uname().unwrap().sysname(), "Linux"); + } + + #[cfg(any(target_os = "macos", target_os = "ios"))] + #[test] + pub fn test_uname_darwin() { + assert_eq!(super::uname().unwrap().sysname(), "Darwin"); + } + + #[cfg(target_os = "freebsd")] + #[test] + pub fn test_uname_freebsd() { + assert_eq!(super::uname().unwrap().sysname(), "FreeBSD"); + } +} diff --git a/vendor/nix-0.26.2/src/sys/wait.rs b/vendor/nix-0.26.2/src/sys/wait.rs new file mode 100644 index 0000000000000..b6524e8661409 --- /dev/null +++ b/vendor/nix-0.26.2/src/sys/wait.rs @@ -0,0 +1,388 @@ +//! Wait for a process to change status +use crate::errno::Errno; +use crate::sys::signal::Signal; +use crate::unistd::Pid; +use crate::Result; +use cfg_if::cfg_if; +use libc::{self, c_int}; +use std::convert::TryFrom; +#[cfg(any( + target_os = "android", + all(target_os = "linux", not(target_env = "uclibc")), +))] +use std::os::unix::io::RawFd; + +libc_bitflags!( + /// Controls the behavior of [`waitpid`]. + pub struct WaitPidFlag: c_int { + /// Do not block when there are no processes wishing to report status. + WNOHANG; + /// Report the status of selected processes which are stopped due to a + /// [`SIGTTIN`](crate::sys::signal::Signal::SIGTTIN), + /// [`SIGTTOU`](crate::sys::signal::Signal::SIGTTOU), + /// [`SIGTSTP`](crate::sys::signal::Signal::SIGTSTP), or + /// [`SIGSTOP`](crate::sys::signal::Signal::SIGSTOP) signal. + WUNTRACED; + /// Report the status of selected processes which have terminated. + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "redox", + target_os = "macos", + target_os = "netbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + WEXITED; + /// Report the status of selected processes that have continued from a + /// job control stop by receiving a + /// [`SIGCONT`](crate::sys::signal::Signal::SIGCONT) signal. + WCONTINUED; + /// An alias for WUNTRACED. + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "redox", + target_os = "macos", + target_os = "netbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + WSTOPPED; + /// Don't reap, just poll status. + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "redox", + target_os = "macos", + target_os = "netbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + WNOWAIT; + /// Don't wait on children of other threads in this group + #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + __WNOTHREAD; + /// Wait on all children, regardless of type + #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + __WALL; + /// Wait for "clone" children only. + #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + __WCLONE; + } +); + +/// Possible return values from `wait()` or `waitpid()`. +/// +/// Each status (other than `StillAlive`) describes a state transition +/// in a child process `Pid`, such as the process exiting or stopping, +/// plus additional data about the transition if any. +/// +/// Note that there are two Linux-specific enum variants, `PtraceEvent` +/// and `PtraceSyscall`. Portable code should avoid exhaustively +/// matching on `WaitStatus`. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum WaitStatus { + /// The process exited normally (as with `exit()` or returning from + /// `main`) with the given exit code. This case matches the C macro + /// `WIFEXITED(status)`; the second field is `WEXITSTATUS(status)`. + Exited(Pid, i32), + /// The process was killed by the given signal. The third field + /// indicates whether the signal generated a core dump. This case + /// matches the C macro `WIFSIGNALED(status)`; the last two fields + /// correspond to `WTERMSIG(status)` and `WCOREDUMP(status)`. + Signaled(Pid, Signal, bool), + /// The process is alive, but was stopped by the given signal. This + /// is only reported if `WaitPidFlag::WUNTRACED` was passed. This + /// case matches the C macro `WIFSTOPPED(status)`; the second field + /// is `WSTOPSIG(status)`. + Stopped(Pid, Signal), + /// The traced process was stopped by a `PTRACE_EVENT_*` event. See + /// [`nix::sys::ptrace`] and [`ptrace`(2)] for more information. All + /// currently-defined events use `SIGTRAP` as the signal; the third + /// field is the `PTRACE_EVENT_*` value of the event. + /// + /// [`nix::sys::ptrace`]: ../ptrace/index.html + /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html + #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + PtraceEvent(Pid, Signal, c_int), + /// The traced process was stopped by execution of a system call, + /// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for + /// more information. + /// + /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html + #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + PtraceSyscall(Pid), + /// The process was previously stopped but has resumed execution + /// after receiving a `SIGCONT` signal. This is only reported if + /// `WaitPidFlag::WCONTINUED` was passed. This case matches the C + /// macro `WIFCONTINUED(status)`. + Continued(Pid), + /// There are currently no state changes to report in any awaited + /// child process. This is only returned if `WaitPidFlag::WNOHANG` + /// was used (otherwise `wait()` or `waitpid()` would block until + /// there was something to report). + StillAlive, +} + +impl WaitStatus { + /// Extracts the PID from the WaitStatus unless it equals StillAlive. + pub fn pid(&self) -> Option { + use self::WaitStatus::*; + match *self { + Exited(p, _) | Signaled(p, _, _) | Stopped(p, _) | Continued(p) => { + Some(p) + } + StillAlive => None, + #[cfg(any(target_os = "android", target_os = "linux"))] + PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p), + } + } +} + +fn exited(status: i32) -> bool { + libc::WIFEXITED(status) +} + +fn exit_status(status: i32) -> i32 { + libc::WEXITSTATUS(status) +} + +fn signaled(status: i32) -> bool { + libc::WIFSIGNALED(status) +} + +fn term_signal(status: i32) -> Result { + Signal::try_from(libc::WTERMSIG(status)) +} + +fn dumped_core(status: i32) -> bool { + libc::WCOREDUMP(status) +} + +fn stopped(status: i32) -> bool { + libc::WIFSTOPPED(status) +} + +fn stop_signal(status: i32) -> Result { + Signal::try_from(libc::WSTOPSIG(status)) +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +fn syscall_stop(status: i32) -> bool { + // From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect + // of delivering SIGTRAP | 0x80 as the signal number for syscall + // stops. This allows easily distinguishing syscall stops from + // genuine SIGTRAP signals. + libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80 +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +fn stop_additional(status: i32) -> c_int { + (status >> 16) as c_int +} + +fn continued(status: i32) -> bool { + libc::WIFCONTINUED(status) +} + +impl WaitStatus { + /// Convert a raw `wstatus` as returned by `waitpid`/`wait` into a `WaitStatus` + /// + /// # Errors + /// + /// Returns an `Error` corresponding to `EINVAL` for invalid status values. + /// + /// # Examples + /// + /// Convert a `wstatus` obtained from `libc::waitpid` into a `WaitStatus`: + /// + /// ``` + /// use nix::sys::wait::WaitStatus; + /// use nix::sys::signal::Signal; + /// let pid = nix::unistd::Pid::from_raw(1); + /// let status = WaitStatus::from_raw(pid, 0x0002); + /// assert_eq!(status, Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false))); + /// ``` + pub fn from_raw(pid: Pid, status: i32) -> Result { + Ok(if exited(status) { + WaitStatus::Exited(pid, exit_status(status)) + } else if signaled(status) { + WaitStatus::Signaled(pid, term_signal(status)?, dumped_core(status)) + } else if stopped(status) { + cfg_if! { + if #[cfg(any(target_os = "android", target_os = "linux"))] { + fn decode_stopped(pid: Pid, status: i32) -> Result { + let status_additional = stop_additional(status); + Ok(if syscall_stop(status) { + WaitStatus::PtraceSyscall(pid) + } else if status_additional == 0 { + WaitStatus::Stopped(pid, stop_signal(status)?) + } else { + WaitStatus::PtraceEvent(pid, stop_signal(status)?, + stop_additional(status)) + }) + } + } else { + fn decode_stopped(pid: Pid, status: i32) -> Result { + Ok(WaitStatus::Stopped(pid, stop_signal(status)?)) + } + } + } + return decode_stopped(pid, status); + } else { + assert!(continued(status)); + WaitStatus::Continued(pid) + }) + } + + /// Convert a `siginfo_t` as returned by `waitid` to a `WaitStatus` + /// + /// # Errors + /// + /// Returns an `Error` corresponding to `EINVAL` for invalid values. + /// + /// # Safety + /// + /// siginfo_t is actually a union, not all fields may be initialized. + /// The functions si_pid() and si_status() must be valid to call on + /// the passed siginfo_t. + #[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "haiku", + all(target_os = "linux", not(target_env = "uclibc")), + ))] + unsafe fn from_siginfo(siginfo: &libc::siginfo_t) -> Result { + let si_pid = siginfo.si_pid(); + if si_pid == 0 { + return Ok(WaitStatus::StillAlive); + } + + assert_eq!(siginfo.si_signo, libc::SIGCHLD); + + let pid = Pid::from_raw(si_pid); + let si_status = siginfo.si_status(); + + let status = match siginfo.si_code { + libc::CLD_EXITED => WaitStatus::Exited(pid, si_status), + libc::CLD_KILLED | libc::CLD_DUMPED => WaitStatus::Signaled( + pid, + Signal::try_from(si_status)?, + siginfo.si_code == libc::CLD_DUMPED, + ), + libc::CLD_STOPPED => { + WaitStatus::Stopped(pid, Signal::try_from(si_status)?) + } + libc::CLD_CONTINUED => WaitStatus::Continued(pid), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::CLD_TRAPPED => { + if si_status == libc::SIGTRAP | 0x80 { + WaitStatus::PtraceSyscall(pid) + } else { + WaitStatus::PtraceEvent( + pid, + Signal::try_from(si_status & 0xff)?, + (si_status >> 8) as c_int, + ) + } + } + _ => return Err(Errno::EINVAL), + }; + + Ok(status) + } +} + +/// Wait for a process to change status +/// +/// See also [waitpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html) +pub fn waitpid>>( + pid: P, + options: Option, +) -> Result { + use self::WaitStatus::*; + + let mut status: i32 = 0; + + let option_bits = match options { + Some(bits) => bits.bits(), + None => 0, + }; + + let res = unsafe { + libc::waitpid( + pid.into().unwrap_or_else(|| Pid::from_raw(-1)).into(), + &mut status as *mut c_int, + option_bits, + ) + }; + + match Errno::result(res)? { + 0 => Ok(StillAlive), + res => WaitStatus::from_raw(Pid::from_raw(res), status), + } +} + +/// Wait for any child process to change status or a signal is received. +/// +/// See also [wait(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html) +pub fn wait() -> Result { + waitpid(None, None) +} + +/// The ID argument for `waitid` +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "haiku", + all(target_os = "linux", not(target_env = "uclibc")), +))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Id { + /// Wait for any child + All, + /// Wait for the child whose process ID matches the given PID + Pid(Pid), + /// Wait for the child whose process group ID matches the given PID + /// + /// If the PID is zero, the caller's process group is used since Linux 5.4. + PGid(Pid), + /// Wait for the child referred to by the given PID file descriptor + #[cfg(any(target_os = "android", target_os = "linux"))] + PIDFd(RawFd), +} + +/// Wait for a process to change status +/// +/// See also [waitid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitid.html) +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "haiku", + all(target_os = "linux", not(target_env = "uclibc")), +))] +pub fn waitid(id: Id, flags: WaitPidFlag) -> Result { + let (idtype, idval) = match id { + Id::All => (libc::P_ALL, 0), + Id::Pid(pid) => (libc::P_PID, pid.as_raw() as libc::id_t), + Id::PGid(pid) => (libc::P_PGID, pid.as_raw() as libc::id_t), + #[cfg(any(target_os = "android", target_os = "linux"))] + Id::PIDFd(fd) => (libc::P_PIDFD, fd as libc::id_t), + }; + + let siginfo = unsafe { + // Memory is zeroed rather than uninitialized, as not all platforms + // initialize the memory in the StillAlive case + let mut siginfo: libc::siginfo_t = std::mem::zeroed(); + Errno::result(libc::waitid(idtype, idval, &mut siginfo, flags.bits()))?; + siginfo + }; + + unsafe { WaitStatus::from_siginfo(&siginfo) } +} diff --git a/vendor/nix-0.26.2/src/time.rs b/vendor/nix-0.26.2/src/time.rs new file mode 100644 index 0000000000000..2e03c46cf4b09 --- /dev/null +++ b/vendor/nix-0.26.2/src/time.rs @@ -0,0 +1,283 @@ +use crate::sys::time::TimeSpec; +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux", + target_os = "android", + target_os = "emscripten", +))] +#[cfg(feature = "process")] +use crate::unistd::Pid; +use crate::{Errno, Result}; +use libc::{self, clockid_t}; +use std::mem::MaybeUninit; + +/// Clock identifier +/// +/// Newtype pattern around `clockid_t` (which is just alias). It prevents bugs caused by +/// accidentally passing wrong value. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct ClockId(clockid_t); + +impl ClockId { + /// Creates `ClockId` from raw `clockid_t` + pub const fn from_raw(clk_id: clockid_t) -> Self { + ClockId(clk_id) + } + + feature! { + #![feature = "process"] + /// Returns `ClockId` of a `pid` CPU-time clock + #[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn pid_cpu_clock_id(pid: Pid) -> Result { + clock_getcpuclockid(pid) + } + } + + /// Returns resolution of the clock id + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn res(self) -> Result { + clock_getres(self) + } + + /// Returns the current time on the clock id + pub fn now(self) -> Result { + clock_gettime(self) + } + + /// Sets time to `timespec` on the clock id + #[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "redox", + target_os = "hermit", + )))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn set_time(self, timespec: TimeSpec) -> Result<()> { + clock_settime(self, timespec) + } + + /// Gets the raw `clockid_t` wrapped by `self` + pub const fn as_raw(self) -> clockid_t { + self.0 + } + + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME); + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_BOOTTIME_ALARM: ClockId = + ClockId(libc::CLOCK_BOOTTIME_ALARM); + pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC); + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_MONOTONIC_COARSE: ClockId = + ClockId(libc::CLOCK_MONOTONIC_COARSE); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_MONOTONIC_FAST: ClockId = + ClockId(libc::CLOCK_MONOTONIC_FAST); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_MONOTONIC_PRECISE: ClockId = + ClockId(libc::CLOCK_MONOTONIC_PRECISE); + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW); + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "redox", + target_os = "linux" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = + ClockId(libc::CLOCK_PROCESS_CPUTIME_ID); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF); + pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME); + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_REALTIME_ALARM: ClockId = + ClockId(libc::CLOCK_REALTIME_ALARM); + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_REALTIME_COARSE: ClockId = + ClockId(libc::CLOCK_REALTIME_COARSE); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_REALTIME_PRECISE: ClockId = + ClockId(libc::CLOCK_REALTIME_PRECISE); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND); + #[cfg(any( + target_os = "emscripten", + target_os = "fuchsia", + all(target_os = "linux", target_env = "musl") + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE); + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI); + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_THREAD_CPUTIME_ID: ClockId = + ClockId(libc::CLOCK_THREAD_CPUTIME_ID); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_UPTIME_PRECISE: ClockId = + ClockId(libc::CLOCK_UPTIME_PRECISE); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL); +} + +impl From for clockid_t { + fn from(clock_id: ClockId) -> Self { + clock_id.as_raw() + } +} + +impl From for ClockId { + fn from(clk_id: clockid_t) -> Self { + ClockId::from_raw(clk_id) + } +} + +impl std::fmt::Display for ClockId { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + std::fmt::Display::fmt(&self.0, f) + } +} + +/// Get the resolution of the specified clock, (see +/// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)). +#[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn clock_getres(clock_id: ClockId) -> Result { + let mut c_time: MaybeUninit = MaybeUninit::uninit(); + let ret = + unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) }; + Errno::result(ret)?; + let res = unsafe { c_time.assume_init() }; + Ok(TimeSpec::from(res)) +} + +/// Get the time of the specified clock, (see +/// [clock_gettime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_gettime.html)). +pub fn clock_gettime(clock_id: ClockId) -> Result { + let mut c_time: MaybeUninit = MaybeUninit::uninit(); + let ret = + unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) }; + Errno::result(ret)?; + let res = unsafe { c_time.assume_init() }; + Ok(TimeSpec::from(res)) +} + +/// Set the time of the specified clock, (see +/// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)). +#[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "redox", + target_os = "hermit", +)))] +#[cfg_attr(docsrs, doc(cfg(all())))] +pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { + let ret = + unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) }; + Errno::result(ret).map(drop) +} + +/// Get the clock id of the specified process id, (see +/// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)). +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux", + target_os = "android", + target_os = "emscripten", +))] +#[cfg(feature = "process")] +#[cfg_attr(docsrs, doc(cfg(feature = "process")))] +pub fn clock_getcpuclockid(pid: Pid) -> Result { + let mut clk_id: MaybeUninit = MaybeUninit::uninit(); + let ret = + unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) }; + if ret == 0 { + let res = unsafe { clk_id.assume_init() }; + Ok(ClockId::from(res)) + } else { + Err(Errno::from_i32(ret)) + } +} diff --git a/vendor/nix-0.26.2/src/ucontext.rs b/vendor/nix-0.26.2/src/ucontext.rs new file mode 100644 index 0000000000000..b2a39f76994c5 --- /dev/null +++ b/vendor/nix-0.26.2/src/ucontext.rs @@ -0,0 +1,47 @@ +#[cfg(not(target_env = "musl"))] +use crate::errno::Errno; +use crate::sys::signal::SigSet; +#[cfg(not(target_env = "musl"))] +use crate::Result; +#[cfg(not(target_env = "musl"))] +use std::mem; + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct UContext { + context: libc::ucontext_t, +} + +impl UContext { + #[cfg(not(target_env = "musl"))] + pub fn get() -> Result { + let mut context = mem::MaybeUninit::::uninit(); + let res = unsafe { libc::getcontext(context.as_mut_ptr()) }; + Errno::result(res).map(|_| unsafe { + UContext { + context: context.assume_init(), + } + }) + } + + #[cfg(not(target_env = "musl"))] + pub fn set(&self) -> Result<()> { + let res = unsafe { + libc::setcontext(&self.context as *const libc::ucontext_t) + }; + Errno::result(res).map(drop) + } + + pub fn sigmask_mut(&mut self) -> &mut SigSet { + unsafe { + &mut *(&mut self.context.uc_sigmask as *mut libc::sigset_t + as *mut SigSet) + } + } + + pub fn sigmask(&self) -> &SigSet { + unsafe { + &*(&self.context.uc_sigmask as *const libc::sigset_t + as *const SigSet) + } + } +} diff --git a/vendor/nix-0.26.2/src/unistd.rs b/vendor/nix-0.26.2/src/unistd.rs new file mode 100644 index 0000000000000..ca07b34a2e47a --- /dev/null +++ b/vendor/nix-0.26.2/src/unistd.rs @@ -0,0 +1,3383 @@ +//! Safe wrappers around functions found in libc "unistd.h" header + +use crate::errno::{self, Errno}; +#[cfg(not(target_os = "redox"))] +#[cfg(feature = "fs")] +use crate::fcntl::{at_rawfd, AtFlags}; +#[cfg(feature = "fs")] +use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag}; +#[cfg(all( + feature = "fs", + any( + target_os = "openbsd", + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios" + ) +))] +use crate::sys::stat::FileFlag; +#[cfg(feature = "fs")] +use crate::sys::stat::Mode; +use crate::{Error, NixPath, Result}; +#[cfg(not(target_os = "redox"))] +use cfg_if::cfg_if; +use libc::{ + self, c_char, c_int, c_long, c_uint, c_void, gid_t, mode_t, off_t, pid_t, + size_t, uid_t, PATH_MAX, +}; +use std::convert::Infallible; +use std::ffi::{CStr, OsString}; +#[cfg(not(target_os = "redox"))] +use std::ffi::{CString, OsStr}; +#[cfg(not(target_os = "redox"))] +use std::os::unix::ffi::OsStrExt; +use std::os::unix::ffi::OsStringExt; +use std::os::unix::io::RawFd; +use std::path::PathBuf; +use std::{fmt, mem, ptr}; + +feature! { + #![feature = "fs"] + #[cfg(any(target_os = "android", target_os = "linux"))] + pub use self::pivot_root::*; +} + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] +pub use self::setres::*; + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] +pub use self::getres::*; + +feature! { +#![feature = "user"] + +/// User identifier +/// +/// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally +/// passing wrong value. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct Uid(uid_t); + +impl Uid { + /// Creates `Uid` from raw `uid_t`. + pub const fn from_raw(uid: uid_t) -> Self { + Uid(uid) + } + + /// Returns Uid of calling process. This is practically a more Rusty alias for `getuid`. + #[doc(alias("getuid"))] + pub fn current() -> Self { + getuid() + } + + /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`. + #[doc(alias("geteuid"))] + pub fn effective() -> Self { + geteuid() + } + + /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.) + pub const fn is_root(self) -> bool { + self.0 == ROOT.0 + } + + /// Get the raw `uid_t` wrapped by `self`. + pub const fn as_raw(self) -> uid_t { + self.0 + } +} + +impl From for uid_t { + fn from(uid: Uid) -> Self { + uid.0 + } +} + +impl From for Uid { + fn from(uid: uid_t) -> Self { + Uid(uid) + } +} + +impl fmt::Display for Uid { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +/// Constant for UID = 0 +pub const ROOT: Uid = Uid(0); + +/// Group identifier +/// +/// Newtype pattern around `gid_t` (which is just alias). It prevents bugs caused by accidentally +/// passing wrong value. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct Gid(gid_t); + +impl Gid { + /// Creates `Gid` from raw `gid_t`. + pub const fn from_raw(gid: gid_t) -> Self { + Gid(gid) + } + + /// Returns Gid of calling process. This is practically a more Rusty alias for `getgid`. + #[doc(alias("getgid"))] + pub fn current() -> Self { + getgid() + } + + /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getegid`. + #[doc(alias("getegid"))] + pub fn effective() -> Self { + getegid() + } + + /// Get the raw `gid_t` wrapped by `self`. + pub const fn as_raw(self) -> gid_t { + self.0 + } +} + +impl From for gid_t { + fn from(gid: Gid) -> Self { + gid.0 + } +} + +impl From for Gid { + fn from(gid: gid_t) -> Self { + Gid(gid) + } +} + +impl fmt::Display for Gid { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} +} + +feature! { +#![feature = "process"] +/// Process identifier +/// +/// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally +/// passing wrong value. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Pid(pid_t); + +impl Pid { + /// Creates `Pid` from raw `pid_t`. + pub const fn from_raw(pid: pid_t) -> Self { + Pid(pid) + } + + /// Returns PID of calling process + #[doc(alias("getpid"))] + pub fn this() -> Self { + getpid() + } + + /// Returns PID of parent of calling process + #[doc(alias("getppid"))] + pub fn parent() -> Self { + getppid() + } + + /// Get the raw `pid_t` wrapped by `self`. + pub const fn as_raw(self) -> pid_t { + self.0 + } +} + +impl From for pid_t { + fn from(pid: Pid) -> Self { + pid.0 + } +} + +impl fmt::Display for Pid { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + + +/// Represents the successful result of calling `fork` +/// +/// When `fork` is called, the process continues execution in the parent process +/// and in the new child. This return type can be examined to determine whether +/// you are now executing in the parent process or in the child. +#[derive(Clone, Copy, Debug)] +pub enum ForkResult { + Parent { child: Pid }, + Child, +} + +impl ForkResult { + + /// Return `true` if this is the child process of the `fork()` + #[inline] + pub fn is_child(self) -> bool { + matches!(self, ForkResult::Child) + } + + /// Returns `true` if this is the parent process of the `fork()` + #[inline] + pub fn is_parent(self) -> bool { + !self.is_child() + } +} + +/// Create a new child process duplicating the parent process ([see +/// fork(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)). +/// +/// After successfully calling the fork system call, a second process will +/// be created which is identical to the original except for the pid and the +/// return value of this function. As an example: +/// +/// ``` +/// use nix::{sys::wait::waitpid,unistd::{fork, ForkResult, write}}; +/// +/// match unsafe{fork()} { +/// Ok(ForkResult::Parent { child, .. }) => { +/// println!("Continuing execution in parent process, new child has pid: {}", child); +/// waitpid(child, None).unwrap(); +/// } +/// Ok(ForkResult::Child) => { +/// // Unsafe to use `println!` (or `unwrap`) here. See Safety. +/// write(libc::STDOUT_FILENO, "I'm a new child process\n".as_bytes()).ok(); +/// unsafe { libc::_exit(0) }; +/// } +/// Err(_) => println!("Fork failed"), +/// } +/// ``` +/// +/// This will print something like the following (order nondeterministic). The +/// thing to note is that you end up with two processes continuing execution +/// immediately after the fork call but with different match arms. +/// +/// ```text +/// Continuing execution in parent process, new child has pid: 1234 +/// I'm a new child process +/// ``` +/// +/// # Safety +/// +/// In a multithreaded program, only [async-signal-safe] functions like `pause` +/// and `_exit` may be called by the child (the parent isn't restricted). Note +/// that memory allocation may **not** be async-signal-safe and thus must be +/// prevented. +/// +/// Those functions are only a small subset of your operating system's API, so +/// special care must be taken to only invoke code you can control and audit. +/// +/// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html +#[inline] +pub unsafe fn fork() -> Result { + use self::ForkResult::*; + let res = libc::fork(); + + Errno::result(res).map(|res| match res { + 0 => Child, + res => Parent { child: Pid(res) }, + }) +} + +/// Get the pid of this process (see +/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html)). +/// +/// Since you are running code, there is always a pid to return, so there +/// is no error case that needs to be handled. +#[inline] +pub fn getpid() -> Pid { + Pid(unsafe { libc::getpid() }) +} + +/// Get the pid of this processes' parent (see +/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html)). +/// +/// There is always a parent pid to return, so there is no error case that needs +/// to be handled. +#[inline] +pub fn getppid() -> Pid { + Pid(unsafe { libc::getppid() }) // no error handling, according to man page: "These functions are always successful." +} + +/// Set a process group ID (see +/// [setpgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html)). +/// +/// Set the process group id (PGID) of a particular process. If a pid of zero +/// is specified, then the pid of the calling process is used. Process groups +/// may be used to group together a set of processes in order for the OS to +/// apply some operations across the group. +/// +/// `setsid()` may be used to create a new process group. +#[inline] +pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> { + let res = unsafe { libc::setpgid(pid.into(), pgid.into()) }; + Errno::result(res).map(drop) +} +#[inline] +pub fn getpgid(pid: Option) -> Result { + let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) }; + Errno::result(res).map(Pid) +} + +/// Create new session and set process group id (see +/// [setsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html)). +#[inline] +pub fn setsid() -> Result { + Errno::result(unsafe { libc::setsid() }).map(Pid) +} + +/// Get the process group ID of a session leader +/// [getsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html). +/// +/// Obtain the process group ID of the process that is the session leader of the process specified +/// by pid. If pid is zero, it specifies the calling process. +#[inline] +#[cfg(not(target_os = "redox"))] +pub fn getsid(pid: Option) -> Result { + let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) }; + Errno::result(res).map(Pid) +} +} + +feature! { +#![all(feature = "process", feature = "term")] +/// Get the terminal foreground process group (see +/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html)). +/// +/// Get the group process id (GPID) of the foreground process group on the +/// terminal associated to file descriptor (FD). +#[inline] +pub fn tcgetpgrp(fd: c_int) -> Result { + let res = unsafe { libc::tcgetpgrp(fd) }; + Errno::result(res).map(Pid) +} +/// Set the terminal foreground process group (see +/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html)). +/// +/// Get the group process id (PGID) to the foreground process group on the +/// terminal associated to file descriptor (FD). +#[inline] +pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> { + let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) }; + Errno::result(res).map(drop) +} +} + +feature! { +#![feature = "process"] +/// Get the group id of the calling process (see +///[getpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html)). +/// +/// Get the process group id (PGID) of the calling process. +/// According to the man page it is always successful. +#[inline] +pub fn getpgrp() -> Pid { + Pid(unsafe { libc::getpgrp() }) +} + +/// Get the caller's thread ID (see +/// [gettid(2)](https://man7.org/linux/man-pages/man2/gettid.2.html). +/// +/// This function is only available on Linux based systems. In a single +/// threaded process, the main thread will have the same ID as the process. In +/// a multithreaded process, each thread will have a unique thread id but the +/// same process ID. +/// +/// No error handling is required as a thread id should always exist for any +/// process, even if threads are not being used. +#[cfg(any(target_os = "linux", target_os = "android"))] +#[inline] +pub fn gettid() -> Pid { + Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t }) +} +} + +feature! { +#![feature = "fs"] +/// Create a copy of the specified file descriptor (see +/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). +/// +/// The new file descriptor will have a new index but refer to the same +/// resource as the old file descriptor and the old and new file descriptors may +/// be used interchangeably. The new and old file descriptor share the same +/// underlying resource, offset, and file status flags. The actual index used +/// for the file descriptor will be the lowest fd index that is available. +/// +/// The two file descriptors do not share file descriptor flags (e.g. `OFlag::FD_CLOEXEC`). +#[inline] +pub fn dup(oldfd: RawFd) -> Result { + let res = unsafe { libc::dup(oldfd) }; + + Errno::result(res) +} + +/// Create a copy of the specified file descriptor using the specified fd (see +/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). +/// +/// This function behaves similar to `dup()` except that it will try to use the +/// specified fd instead of allocating a new one. See the man pages for more +/// detail on the exact behavior of this function. +#[inline] +pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result { + let res = unsafe { libc::dup2(oldfd, newfd) }; + + Errno::result(res) +} + +/// Create a new copy of the specified file descriptor using the specified fd +/// and flags (see [dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)). +/// +/// This function behaves similar to `dup2()` but allows for flags to be +/// specified. +pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result { + dup3_polyfill(oldfd, newfd, flags) +} + +#[inline] +fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result { + if oldfd == newfd { + return Err(Errno::EINVAL); + } + + let fd = dup2(oldfd, newfd)?; + + if flags.contains(OFlag::O_CLOEXEC) { + if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) { + let _ = close(fd); + return Err(e); + } + } + + Ok(fd) +} + +/// Change the current working directory of the calling process (see +/// [chdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html)). +/// +/// This function may fail in a number of different scenarios. See the man +/// pages for additional details on possible failure cases. +#[inline] +pub fn chdir(path: &P) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { libc::chdir(cstr.as_ptr()) } + })?; + + Errno::result(res).map(drop) +} + +/// Change the current working directory of the process to the one +/// given as an open file descriptor (see +/// [fchdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html)). +/// +/// This function may fail in a number of different scenarios. See the man +/// pages for additional details on possible failure cases. +#[inline] +#[cfg(not(target_os = "fuchsia"))] +pub fn fchdir(dirfd: RawFd) -> Result<()> { + let res = unsafe { libc::fchdir(dirfd) }; + + Errno::result(res).map(drop) +} + +/// Creates new directory `path` with access rights `mode`. (see [mkdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html)) +/// +/// # Errors +/// +/// There are several situations where mkdir might fail: +/// +/// - current user has insufficient rights in the parent directory +/// - the path already exists +/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X) +/// +/// # Example +/// +/// ```rust +/// use nix::unistd; +/// use nix::sys::stat; +/// use tempfile::tempdir; +/// +/// let tmp_dir1 = tempdir().unwrap(); +/// let tmp_dir2 = tmp_dir1.path().join("new_dir"); +/// +/// // create new directory and give read, write and execute rights to the owner +/// match unistd::mkdir(&tmp_dir2, stat::Mode::S_IRWXU) { +/// Ok(_) => println!("created {:?}", tmp_dir2), +/// Err(err) => println!("Error creating directory: {}", err), +/// } +/// ``` +#[inline] +pub fn mkdir(path: &P, mode: Mode) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) } + })?; + + Errno::result(res).map(drop) +} + +/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`. +/// +/// # Errors +/// +/// There are several situations where mkfifo might fail: +/// +/// - current user has insufficient rights in the parent directory +/// - the path already exists +/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X) +/// +/// For a full list consult +/// [posix specification](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html) +/// +/// # Example +/// +/// ```rust +/// use nix::unistd; +/// use nix::sys::stat; +/// use tempfile::tempdir; +/// +/// let tmp_dir = tempdir().unwrap(); +/// let fifo_path = tmp_dir.path().join("foo.pipe"); +/// +/// // create new fifo and give read, write and execute rights to the owner +/// match unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) { +/// Ok(_) => println!("created {:?}", fifo_path), +/// Err(err) => println!("Error creating fifo: {}", err), +/// } +/// ``` +#[inline] +#[cfg(not(target_os = "redox"))] // RedoxFS does not support fifo yet +pub fn mkfifo(path: &P, mode: Mode) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) } + })?; + + Errno::result(res).map(drop) +} + +/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`. +/// +/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor. +/// +/// If `dirfd` is `None`, then `path` is relative to the current working directory. +/// +/// # References +/// +/// [mkfifoat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifoat.html). +// mkfifoat is not implemented in OSX or android +#[inline] +#[cfg(not(any( + target_os = "macos", target_os = "ios", target_os = "haiku", + target_os = "android", target_os = "redox")))] +pub fn mkfifoat(dirfd: Option, path: &P, mode: Mode) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t) + })?; + + Errno::result(res).map(drop) +} + +/// Creates a symbolic link at `path2` which points to `path1`. +/// +/// If `dirfd` has a value, then `path2` is relative to directory associated +/// with the file descriptor. +/// +/// If `dirfd` is `None`, then `path2` is relative to the current working +/// directory. This is identical to `libc::symlink(path1, path2)`. +/// +/// See also [symlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html). +#[cfg(not(target_os = "redox"))] +pub fn symlinkat( + path1: &P1, + dirfd: Option, + path2: &P2) -> Result<()> { + let res = + path1.with_nix_path(|path1| { + path2.with_nix_path(|path2| { + unsafe { + libc::symlinkat( + path1.as_ptr(), + dirfd.unwrap_or(libc::AT_FDCWD), + path2.as_ptr() + ) + } + }) + })??; + Errno::result(res).map(drop) +} +} + +// Double the buffer capacity up to limit. In case it already has +// reached the limit, return Errno::ERANGE. +#[cfg(any(feature = "fs", feature = "user"))] +fn reserve_double_buffer_size(buf: &mut Vec, limit: usize) -> Result<()> { + use std::cmp::min; + + if buf.capacity() >= limit { + return Err(Errno::ERANGE); + } + + let capacity = min(buf.capacity() * 2, limit); + buf.reserve(capacity); + + Ok(()) +} + +feature! { +#![feature = "fs"] + +/// Returns the current directory as a `PathBuf` +/// +/// Err is returned if the current user doesn't have the permission to read or search a component +/// of the current path. +/// +/// # Example +/// +/// ```rust +/// use nix::unistd; +/// +/// // assume that we are allowed to get current directory +/// let dir = unistd::getcwd().unwrap(); +/// println!("The current directory is {:?}", dir); +/// ``` +#[inline] +pub fn getcwd() -> Result { + let mut buf = Vec::with_capacity(512); + loop { + unsafe { + let ptr = buf.as_mut_ptr() as *mut c_char; + + // The buffer must be large enough to store the absolute pathname plus + // a terminating null byte, or else null is returned. + // To safely handle this we start with a reasonable size (512 bytes) + // and double the buffer size upon every error + if !libc::getcwd(ptr, buf.capacity()).is_null() { + let len = CStr::from_ptr(buf.as_ptr() as *const c_char).to_bytes().len(); + buf.set_len(len); + buf.shrink_to_fit(); + return Ok(PathBuf::from(OsString::from_vec(buf))); + } else { + let error = Errno::last(); + // ERANGE means buffer was too small to store directory name + if error != Errno::ERANGE { + return Err(error); + } + } + + // Trigger the internal buffer resizing logic. + reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?; + } + } +} +} + +feature! { +#![all(feature = "user", feature = "fs")] + +/// Computes the raw UID and GID values to pass to a `*chown` call. +// The cast is not unnecessary on all platforms. +#[allow(clippy::unnecessary_cast)] +fn chown_raw_ids(owner: Option, group: Option) -> (libc::uid_t, libc::gid_t) { + // According to the POSIX specification, -1 is used to indicate that owner and group + // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap + // around to get -1. + let uid = owner.map(Into::into) + .unwrap_or_else(|| (0 as uid_t).wrapping_sub(1)); + let gid = group.map(Into::into) + .unwrap_or_else(|| (0 as gid_t).wrapping_sub(1)); + (uid, gid) +} + +/// Change the ownership of the file at `path` to be owned by the specified +/// `owner` (user) and `group` (see +/// [chown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)). +/// +/// The owner/group for the provided path name will not be modified if `None` is +/// provided for that argument. Ownership change will be attempted for the path +/// only if `Some` owner/group is provided. +#[inline] +pub fn chown(path: &P, owner: Option, group: Option) -> Result<()> { + let res = path.with_nix_path(|cstr| { + let (uid, gid) = chown_raw_ids(owner, group); + unsafe { libc::chown(cstr.as_ptr(), uid, gid) } + })?; + + Errno::result(res).map(drop) +} + +/// Change the ownership of the file referred to by the open file descriptor `fd` to be owned by +/// the specified `owner` (user) and `group` (see +/// [fchown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html)). +/// +/// The owner/group for the provided file will not be modified if `None` is +/// provided for that argument. Ownership change will be attempted for the path +/// only if `Some` owner/group is provided. +#[inline] +pub fn fchown(fd: RawFd, owner: Option, group: Option) -> Result<()> { + let (uid, gid) = chown_raw_ids(owner, group); + let res = unsafe { libc::fchown(fd, uid, gid) }; + Errno::result(res).map(drop) +} + +/// Flags for `fchownat` function. +#[derive(Clone, Copy, Debug)] +pub enum FchownatFlags { + FollowSymlink, + NoFollowSymlink, +} + +/// Change the ownership of the file at `path` to be owned by the specified +/// `owner` (user) and `group`. +/// +/// The owner/group for the provided path name will not be modified if `None` is +/// provided for that argument. Ownership change will be attempted for the path +/// only if `Some` owner/group is provided. +/// +/// The file to be changed is determined relative to the directory associated +/// with the file descriptor `dirfd` or the current working directory +/// if `dirfd` is `None`. +/// +/// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link, +/// then the mode of the symbolic link is changed. +/// +/// `fchownat(None, path, owner, group, FchownatFlags::NoFollowSymlink)` is identical to +/// a call `libc::lchown(path, owner, group)`. That's why `lchown` is unimplemented in +/// the `nix` crate. +/// +/// # References +/// +/// [fchownat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html). +#[cfg(not(target_os = "redox"))] +pub fn fchownat( + dirfd: Option, + path: &P, + owner: Option, + group: Option, + flag: FchownatFlags, +) -> Result<()> { + let atflag = + match flag { + FchownatFlags::FollowSymlink => AtFlags::empty(), + FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, + }; + let res = path.with_nix_path(|cstr| unsafe { + let (uid, gid) = chown_raw_ids(owner, group); + libc::fchownat(at_rawfd(dirfd), cstr.as_ptr(), uid, gid, + atflag.bits() as libc::c_int) + })?; + + Errno::result(res).map(drop) +} +} + +feature! { +#![feature = "process"] +fn to_exec_array>(args: &[S]) -> Vec<*const c_char> { + use std::iter::once; + args.iter() + .map(|s| s.as_ref().as_ptr()) + .chain(once(ptr::null())) + .collect() +} + +/// Replace the current process image with a new one (see +/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). +/// +/// See the `::nix::unistd::execve` system call for additional details. `execv` +/// performs the same action but does not allow for customization of the +/// environment for the new process. +#[inline] +pub fn execv>(path: &CStr, argv: &[S]) -> Result { + let args_p = to_exec_array(argv); + + unsafe { + libc::execv(path.as_ptr(), args_p.as_ptr()) + }; + + Err(Errno::last()) +} + + +/// Replace the current process image with a new one (see +/// [execve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). +/// +/// The execve system call allows for another process to be "called" which will +/// replace the current process image. That is, this process becomes the new +/// command that is run. On success, this function will not return. Instead, +/// the new program will run until it exits. +/// +/// `::nix::unistd::execv` and `::nix::unistd::execve` take as arguments a slice +/// of `::std::ffi::CString`s for `args` and `env` (for `execve`). Each element +/// in the `args` list is an argument to the new process. Each element in the +/// `env` list should be a string in the form "key=value". +#[inline] +pub fn execve, SE: AsRef>(path: &CStr, args: &[SA], env: &[SE]) -> Result { + let args_p = to_exec_array(args); + let env_p = to_exec_array(env); + + unsafe { + libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) + }; + + Err(Errno::last()) +} + +/// Replace the current process image with a new one and replicate shell `PATH` +/// searching behavior (see +/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). +/// +/// See `::nix::unistd::execve` for additional details. `execvp` behaves the +/// same as execv except that it will examine the `PATH` environment variables +/// for file names not specified with a leading slash. For example, `execv` +/// would not work if "bash" was specified for the path argument, but `execvp` +/// would assuming that a bash executable was on the system `PATH`. +#[inline] +pub fn execvp>(filename: &CStr, args: &[S]) -> Result { + let args_p = to_exec_array(args); + + unsafe { + libc::execvp(filename.as_ptr(), args_p.as_ptr()) + }; + + Err(Errno::last()) +} + +/// Replace the current process image with a new one and replicate shell `PATH` +/// searching behavior (see +/// [`execvpe(3)`](https://man7.org/linux/man-pages/man3/exec.3.html)). +/// +/// This functions like a combination of `execvp(2)` and `execve(2)` to pass an +/// environment and have a search path. See these two for additional +/// information. +#[cfg(any(target_os = "haiku", + target_os = "linux", + target_os = "openbsd"))] +pub fn execvpe, SE: AsRef>(filename: &CStr, args: &[SA], env: &[SE]) -> Result { + let args_p = to_exec_array(args); + let env_p = to_exec_array(env); + + unsafe { + libc::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) + }; + + Err(Errno::last()) +} + +/// Replace the current process image with a new one (see +/// [fexecve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)). +/// +/// The `fexecve` function allows for another process to be "called" which will +/// replace the current process image. That is, this process becomes the new +/// command that is run. On success, this function will not return. Instead, +/// the new program will run until it exits. +/// +/// This function is similar to `execve`, except that the program to be executed +/// is referenced as a file descriptor instead of a path. +#[cfg(any(target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd"))] +#[inline] +pub fn fexecve ,SE: AsRef>(fd: RawFd, args: &[SA], env: &[SE]) -> Result { + let args_p = to_exec_array(args); + let env_p = to_exec_array(env); + + unsafe { + libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr()) + }; + + Err(Errno::last()) +} + +/// Execute program relative to a directory file descriptor (see +/// [execveat(2)](https://man7.org/linux/man-pages/man2/execveat.2.html)). +/// +/// The `execveat` function allows for another process to be "called" which will +/// replace the current process image. That is, this process becomes the new +/// command that is run. On success, this function will not return. Instead, +/// the new program will run until it exits. +/// +/// This function is similar to `execve`, except that the program to be executed +/// is referenced as a file descriptor to the base directory plus a path. +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +pub fn execveat,SE: AsRef>(dirfd: RawFd, pathname: &CStr, args: &[SA], + env: &[SE], flags: super::fcntl::AtFlags) -> Result { + let args_p = to_exec_array(args); + let env_p = to_exec_array(env); + + unsafe { + libc::syscall(libc::SYS_execveat, dirfd, pathname.as_ptr(), + args_p.as_ptr(), env_p.as_ptr(), flags); + }; + + Err(Errno::last()) +} + +/// Daemonize this process by detaching from the controlling terminal (see +/// [daemon(3)](https://man7.org/linux/man-pages/man3/daemon.3.html)). +/// +/// When a process is launched it is typically associated with a parent and it, +/// in turn, by its controlling terminal/process. In order for a process to run +/// in the "background" it must daemonize itself by detaching itself. Under +/// posix, this is done by doing the following: +/// +/// 1. Parent process (this one) forks +/// 2. Parent process exits +/// 3. Child process continues to run. +/// +/// `nochdir`: +/// +/// * `nochdir = true`: The current working directory after daemonizing will +/// be the current working directory. +/// * `nochdir = false`: The current working directory after daemonizing will +/// be the root direcory, `/`. +/// +/// `noclose`: +/// +/// * `noclose = true`: The process' current stdin, stdout, and stderr file +/// descriptors will remain identical after daemonizing. +/// * `noclose = false`: The process' stdin, stdout, and stderr will point to +/// `/dev/null` after daemonizing. +#[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris"))] +pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { + let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) }; + Errno::result(res).map(drop) +} +} + +feature! { +#![feature = "hostname"] + +/// Set the system host name (see +/// [sethostname(2)](https://man7.org/linux/man-pages/man2/gethostname.2.html)). +/// +/// Given a name, attempt to update the system host name to the given string. +/// On some systems, the host name is limited to as few as 64 bytes. An error +/// will be returned if the name is not valid or the current process does not +/// have permissions to update the host name. +#[cfg(not(target_os = "redox"))] +pub fn sethostname>(name: S) -> Result<()> { + // Handle some differences in type of the len arg across platforms. + cfg_if! { + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "solaris", ))] { + type sethostname_len_t = c_int; + } else { + type sethostname_len_t = size_t; + } + } + let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char; + let len = name.as_ref().len() as sethostname_len_t; + + let res = unsafe { libc::sethostname(ptr, len) }; + Errno::result(res).map(drop) +} + +/// Get the host name and store it in an internally allocated buffer, returning an +/// `OsString` on success (see +/// [gethostname(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html)). +/// +/// This function call attempts to get the host name for the running system and +/// store it in an internal buffer, returning it as an `OsString` if successful. +/// +/// ```no_run +/// use nix::unistd; +/// +/// let hostname = unistd::gethostname().expect("Failed getting hostname"); +/// let hostname = hostname.into_string().expect("Hostname wasn't valid UTF-8"); +/// println!("Hostname: {}", hostname); +/// ``` +pub fn gethostname() -> Result { + // The capacity is the max length of a hostname plus the NUL terminator. + let mut buffer: Vec = Vec::with_capacity(256); + let ptr = buffer.as_mut_ptr() as *mut c_char; + let len = buffer.capacity() as size_t; + + let res = unsafe { libc::gethostname(ptr, len) }; + Errno::result(res).map(|_| { + unsafe { + buffer.as_mut_ptr().wrapping_add(len - 1).write(0); // ensure always null-terminated + let len = CStr::from_ptr(buffer.as_ptr() as *const c_char).len(); + buffer.set_len(len); + } + OsString::from_vec(buffer) + }) +} +} + +/// Close a raw file descriptor +/// +/// Be aware that many Rust types implicitly close-on-drop, including +/// `std::fs::File`. Explicitly closing them with this method too can result in +/// a double-close condition, which can cause confusing `EBADF` errors in +/// seemingly unrelated code. Caveat programmer. See also +/// [close(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html). +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::io::AsRawFd; +/// use nix::unistd::close; +/// +/// let f = tempfile::tempfile().unwrap(); +/// close(f.as_raw_fd()).unwrap(); // Bad! f will also close on drop! +/// ``` +/// +/// ```rust +/// use std::os::unix::io::IntoRawFd; +/// use nix::unistd::close; +/// +/// let f = tempfile::tempfile().unwrap(); +/// close(f.into_raw_fd()).unwrap(); // Good. into_raw_fd consumes f +/// ``` +pub fn close(fd: RawFd) -> Result<()> { + let res = unsafe { libc::close(fd) }; + Errno::result(res).map(drop) +} + +/// Read from a raw file descriptor. +/// +/// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html) +pub fn read(fd: RawFd, buf: &mut [u8]) -> Result { + let res = unsafe { + libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) + }; + + Errno::result(res).map(|r| r as usize) +} + +/// Write to a raw file descriptor. +/// +/// See also [write(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html) +pub fn write(fd: RawFd, buf: &[u8]) -> Result { + let res = unsafe { + libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) + }; + + Errno::result(res).map(|r| r as usize) +} + +feature! { +#![feature = "fs"] + +/// Directive that tells [`lseek`] and [`lseek64`] what the offset is relative to. +/// +/// [`lseek`]: ./fn.lseek.html +/// [`lseek64`]: ./fn.lseek64.html +#[repr(i32)] +#[derive(Clone, Copy, Debug)] +pub enum Whence { + /// Specify an offset relative to the start of the file. + SeekSet = libc::SEEK_SET, + /// Specify an offset relative to the current file location. + SeekCur = libc::SEEK_CUR, + /// Specify an offset relative to the end of the file. + SeekEnd = libc::SEEK_END, + /// Specify an offset relative to the next location in the file greater than or + /// equal to offset that contains some data. If offset points to + /// some data, then the file offset is set to offset. + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "solaris"))] + SeekData = libc::SEEK_DATA, + /// Specify an offset relative to the next hole in the file greater than + /// or equal to offset. If offset points into the middle of a hole, then + /// the file offset should be set to offset. If there is no hole past offset, + /// then the file offset should be adjusted to the end of the file (i.e., there + /// is an implicit hole at the end of any file). + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "solaris"))] + SeekHole = libc::SEEK_HOLE +} + +/// Move the read/write file offset. +/// +/// See also [lseek(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html) +pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result { + let res = unsafe { libc::lseek(fd, offset, whence as i32) }; + + Errno::result(res).map(|r| r as off_t) +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result { + let res = unsafe { libc::lseek64(fd, offset, whence as i32) }; + + Errno::result(res).map(|r| r as libc::off64_t) +} +} + +/// Create an interprocess channel. +/// +/// See also [pipe(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html) +pub fn pipe() -> std::result::Result<(RawFd, RawFd), Error> { + let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); + + let res = unsafe { libc::pipe(fds.as_mut_ptr() as *mut c_int) }; + + Error::result(res)?; + + unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } +} + +feature! { +#![feature = "fs"] +/// Like `pipe`, but allows setting certain file descriptor flags. +/// +/// The following flags are supported, and will be set atomically as the pipe is +/// created: +/// +/// - `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors. +#[cfg_attr(target_os = "linux", doc = "- `O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode.")] +#[cfg_attr(target_os = "netbsd", doc = "- `O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`.")] +/// - `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe. +/// +/// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html) +#[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "redox", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris"))] +pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { + let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); + + let res = unsafe { + libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) + }; + + Errno::result(res)?; + + unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } +} + +/// Truncate a file to a specified length +/// +/// See also +/// [truncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html) +#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] +pub fn truncate(path: &P, len: off_t) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { + libc::truncate(cstr.as_ptr(), len) + } + })?; + + Errno::result(res).map(drop) +} + +/// Truncate a file to a specified length +/// +/// See also +/// [ftruncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html) +pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> { + Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop) +} + +pub fn isatty(fd: RawFd) -> Result { + unsafe { + // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so + // we return `Ok(false)` + if libc::isatty(fd) == 1 { + Ok(true) + } else { + match Errno::last() { + Errno::ENOTTY => Ok(false), + err => Err(err), + } + } + } +} + +/// Flags for `linkat` function. +#[derive(Clone, Copy, Debug)] +pub enum LinkatFlags { + SymlinkFollow, + NoSymlinkFollow, +} + +/// Link one file to another file +/// +/// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the +/// case of a relative `oldpath`, the path is interpreted relative to the directory associated +/// with file descriptor `olddirfd` instead of the current working directory and similiarly for +/// `newpath` and file descriptor `newdirfd`. In case `flag` is LinkatFlags::SymlinkFollow and +/// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created. +/// If either `olddirfd` or `newdirfd` is `None`, `AT_FDCWD` is used respectively where `oldpath` +/// and/or `newpath` is then interpreted relative to the current working directory of the calling +/// process. If either `oldpath` or `newpath` is absolute, then `dirfd` is ignored. +/// +/// # References +/// See also [linkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html) +#[cfg(not(target_os = "redox"))] // RedoxFS does not support symlinks yet +pub fn linkat( + olddirfd: Option, + oldpath: &P, + newdirfd: Option, + newpath: &P, + flag: LinkatFlags, +) -> Result<()> { + + let atflag = + match flag { + LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW, + LinkatFlags::NoSymlinkFollow => AtFlags::empty(), + }; + + let res = + oldpath.with_nix_path(|oldcstr| { + newpath.with_nix_path(|newcstr| { + unsafe { + libc::linkat( + at_rawfd(olddirfd), + oldcstr.as_ptr(), + at_rawfd(newdirfd), + newcstr.as_ptr(), + atflag.bits() as libc::c_int + ) + } + }) + })??; + Errno::result(res).map(drop) +} + + +/// Remove a directory entry +/// +/// See also [unlink(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html) +pub fn unlink(path: &P) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { + libc::unlink(cstr.as_ptr()) + } + })?; + Errno::result(res).map(drop) +} + +/// Flags for `unlinkat` function. +#[derive(Clone, Copy, Debug)] +pub enum UnlinkatFlags { + RemoveDir, + NoRemoveDir, +} + +/// Remove a directory entry +/// +/// In the case of a relative path, the directory entry to be removed is determined relative to +/// the directory associated with the file descriptor `dirfd` or the current working directory +/// if `dirfd` is `None`. In the case of an absolute `path` `dirfd` is ignored. If `flag` is +/// `UnlinkatFlags::RemoveDir` then removal of the directory entry specified by `dirfd` and `path` +/// is performed. +/// +/// # References +/// See also [unlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html) +#[cfg(not(target_os = "redox"))] +pub fn unlinkat( + dirfd: Option, + path: &P, + flag: UnlinkatFlags, +) -> Result<()> { + let atflag = + match flag { + UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR, + UnlinkatFlags::NoRemoveDir => AtFlags::empty(), + }; + let res = path.with_nix_path(|cstr| { + unsafe { + libc::unlinkat(at_rawfd(dirfd), cstr.as_ptr(), atflag.bits() as libc::c_int) + } + })?; + Errno::result(res).map(drop) +} + + +#[inline] +#[cfg(not(target_os = "fuchsia"))] +pub fn chroot(path: &P) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { libc::chroot(cstr.as_ptr()) } + })?; + + Errno::result(res).map(drop) +} + +/// Commit filesystem caches to disk +/// +/// See also [sync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html) +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd" +))] +pub fn sync() { + unsafe { libc::sync() }; +} + +/// Commit filesystem caches containing file referred to by the open file +/// descriptor `fd` to disk +/// +/// See also [syncfs(2)](https://man7.org/linux/man-pages/man2/sync.2.html) +#[cfg(target_os = "linux")] +pub fn syncfs(fd: RawFd) -> Result<()> { + let res = unsafe { libc::syncfs(fd) }; + + Errno::result(res).map(drop) +} + +/// Synchronize changes to a file +/// +/// See also [fsync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html) +#[inline] +pub fn fsync(fd: RawFd) -> Result<()> { + let res = unsafe { libc::fsync(fd) }; + + Errno::result(res).map(drop) +} + +/// Synchronize the data of a file +/// +/// See also +/// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html) +#[cfg(any(target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "netbsd", + target_os = "openbsd", + target_os = "illumos", + target_os = "solaris"))] +#[inline] +pub fn fdatasync(fd: RawFd) -> Result<()> { + let res = unsafe { libc::fdatasync(fd) }; + + Errno::result(res).map(drop) +} +} + +feature! { +#![feature = "user"] + +/// Get a real user ID +/// +/// See also [getuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html) +// POSIX requires that getuid is always successful, so no need to check return +// value or errno. +#[inline] +pub fn getuid() -> Uid { + Uid(unsafe { libc::getuid() }) +} + +/// Get the effective user ID +/// +/// See also [geteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html) +// POSIX requires that geteuid is always successful, so no need to check return +// value or errno. +#[inline] +pub fn geteuid() -> Uid { + Uid(unsafe { libc::geteuid() }) +} + +/// Get the real group ID +/// +/// See also [getgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html) +// POSIX requires that getgid is always successful, so no need to check return +// value or errno. +#[inline] +pub fn getgid() -> Gid { + Gid(unsafe { libc::getgid() }) +} + +/// Get the effective group ID +/// +/// See also [getegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html) +// POSIX requires that getegid is always successful, so no need to check return +// value or errno. +#[inline] +pub fn getegid() -> Gid { + Gid(unsafe { libc::getegid() }) +} + +/// Set the effective user ID +/// +/// See also [seteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/seteuid.html) +#[inline] +pub fn seteuid(euid: Uid) -> Result<()> { + let res = unsafe { libc::seteuid(euid.into()) }; + + Errno::result(res).map(drop) +} + +/// Set the effective group ID +/// +/// See also [setegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setegid.html) +#[inline] +pub fn setegid(egid: Gid) -> Result<()> { + let res = unsafe { libc::setegid(egid.into()) }; + + Errno::result(res).map(drop) +} + +/// Set the user ID +/// +/// See also [setuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html) +#[inline] +pub fn setuid(uid: Uid) -> Result<()> { + let res = unsafe { libc::setuid(uid.into()) }; + + Errno::result(res).map(drop) +} + +/// Set the group ID +/// +/// See also [setgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html) +#[inline] +pub fn setgid(gid: Gid) -> Result<()> { + let res = unsafe { libc::setgid(gid.into()) }; + + Errno::result(res).map(drop) +} +} + +feature! { +#![all(feature = "fs", feature = "user")] +/// Set the user identity used for filesystem checks per-thread. +/// On both success and failure, this call returns the previous filesystem user +/// ID of the caller. +/// +/// See also [setfsuid(2)](https://man7.org/linux/man-pages/man2/setfsuid.2.html) +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn setfsuid(uid: Uid) -> Uid { + let prev_fsuid = unsafe { libc::setfsuid(uid.into()) }; + Uid::from_raw(prev_fsuid as uid_t) +} + +/// Set the group identity used for filesystem checks per-thread. +/// On both success and failure, this call returns the previous filesystem group +/// ID of the caller. +/// +/// See also [setfsgid(2)](https://man7.org/linux/man-pages/man2/setfsgid.2.html) +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn setfsgid(gid: Gid) -> Gid { + let prev_fsgid = unsafe { libc::setfsgid(gid.into()) }; + Gid::from_raw(prev_fsgid as gid_t) +} +} + +feature! { +#![feature = "user"] + +/// Get the list of supplementary group IDs of the calling process. +/// +/// [Further reading](https://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html) +/// +/// **Note:** This function is not available for Apple platforms. On those +/// platforms, checking group membership should be achieved via communication +/// with the `opendirectoryd` service. +#[cfg(not(any(target_os = "ios", target_os = "macos")))] +pub fn getgroups() -> Result> { + // First get the maximum number of groups. The value returned + // shall always be greater than or equal to one and less than or + // equal to the value of {NGROUPS_MAX} + 1. + let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { + Ok(Some(n)) => (n + 1) as usize, + Ok(None) | Err(_) => ::max_value(), + }; + + // Next, get the number of groups so we can size our Vec + let ngroups = unsafe { libc::getgroups(0, ptr::null_mut()) }; + + // If there are no supplementary groups, return early. + // This prevents a potential buffer over-read if the number of groups + // increases from zero before the next call. It would return the total + // number of groups beyond the capacity of the buffer. + if ngroups == 0 { + return Ok(Vec::new()); + } + + // Now actually get the groups. We try multiple times in case the number of + // groups has changed since the first call to getgroups() and the buffer is + // now too small. + let mut groups = Vec::::with_capacity(Errno::result(ngroups)? as usize); + loop { + // FIXME: On the platforms we currently support, the `Gid` struct has + // the same representation in memory as a bare `gid_t`. This is not + // necessarily the case on all Rust platforms, though. See RFC 1785. + let ngroups = unsafe { + libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t) + }; + + match Errno::result(ngroups) { + Ok(s) => { + unsafe { groups.set_len(s as usize) }; + return Ok(groups); + }, + Err(Errno::EINVAL) => { + // EINVAL indicates that the buffer size was too + // small, resize it up to ngroups_max as limit. + reserve_double_buffer_size(&mut groups, ngroups_max) + .or(Err(Errno::EINVAL))?; + }, + Err(e) => return Err(e) + } + } +} + +/// Set the list of supplementary group IDs for the calling process. +/// +/// [Further reading](https://man7.org/linux/man-pages/man2/getgroups.2.html) +/// +/// **Note:** This function is not available for Apple platforms. On those +/// platforms, group membership management should be achieved via communication +/// with the `opendirectoryd` service. +/// +/// # Examples +/// +/// `setgroups` can be used when dropping privileges from the root user to a +/// specific user and group. For example, given the user `www-data` with UID +/// `33` and the group `backup` with the GID `34`, one could switch the user as +/// follows: +/// +/// ```rust,no_run +/// # use std::error::Error; +/// # use nix::unistd::*; +/// # +/// # fn try_main() -> Result<(), Box> { +/// let uid = Uid::from_raw(33); +/// let gid = Gid::from_raw(34); +/// setgroups(&[gid])?; +/// setgid(gid)?; +/// setuid(uid)?; +/// # +/// # Ok(()) +/// # } +/// # +/// # try_main().unwrap(); +/// ``` +#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))] +pub fn setgroups(groups: &[Gid]) -> Result<()> { + cfg_if! { + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd"))] { + type setgroups_ngroups_t = c_int; + } else { + type setgroups_ngroups_t = size_t; + } + } + // FIXME: On the platforms we currently support, the `Gid` struct has the + // same representation in memory as a bare `gid_t`. This is not necessarily + // the case on all Rust platforms, though. See RFC 1785. + let res = unsafe { + libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t) + }; + + Errno::result(res).map(drop) +} + +/// Calculate the supplementary group access list. +/// +/// Gets the group IDs of all groups that `user` is a member of. The additional +/// group `group` is also added to the list. +/// +/// [Further reading](https://man7.org/linux/man-pages/man3/getgrouplist.3.html) +/// +/// **Note:** This function is not available for Apple platforms. On those +/// platforms, checking group membership should be achieved via communication +/// with the `opendirectoryd` service. +/// +/// # Errors +/// +/// Although the `getgrouplist()` call does not return any specific +/// errors on any known platforms, this implementation will return a system +/// error of `EINVAL` if the number of groups to be fetched exceeds the +/// `NGROUPS_MAX` sysconf value. This mimics the behaviour of `getgroups()` +/// and `setgroups()`. Additionally, while some implementations will return a +/// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation +/// will only ever return the complete list or else an error. +#[cfg(not(any(target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "redox")))] +pub fn getgrouplist(user: &CStr, group: Gid) -> Result> { + let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { + Ok(Some(n)) => n as c_int, + Ok(None) | Err(_) => ::max_value(), + }; + use std::cmp::min; + let mut groups = Vec::::with_capacity(min(ngroups_max, 8) as usize); + cfg_if! { + if #[cfg(any(target_os = "ios", target_os = "macos"))] { + type getgrouplist_group_t = c_int; + } else { + type getgrouplist_group_t = gid_t; + } + } + let gid: gid_t = group.into(); + loop { + let mut ngroups = groups.capacity() as i32; + let ret = unsafe { + libc::getgrouplist(user.as_ptr(), + gid as getgrouplist_group_t, + groups.as_mut_ptr() as *mut getgrouplist_group_t, + &mut ngroups) + }; + + // BSD systems only return 0 or -1, Linux returns ngroups on success. + if ret >= 0 { + unsafe { groups.set_len(ngroups as usize) }; + return Ok(groups); + } else if ret == -1 { + // Returns -1 if ngroups is too small, but does not set errno. + // BSD systems will still fill the groups buffer with as many + // groups as possible, but Linux manpages do not mention this + // behavior. + reserve_double_buffer_size(&mut groups, ngroups_max as usize) + .map_err(|_| Errno::EINVAL)?; + } + } +} + +/// Initialize the supplementary group access list. +/// +/// Sets the supplementary group IDs for the calling process using all groups +/// that `user` is a member of. The additional group `group` is also added to +/// the list. +/// +/// [Further reading](https://man7.org/linux/man-pages/man3/initgroups.3.html) +/// +/// **Note:** This function is not available for Apple platforms. On those +/// platforms, group membership management should be achieved via communication +/// with the `opendirectoryd` service. +/// +/// # Examples +/// +/// `initgroups` can be used when dropping privileges from the root user to +/// another user. For example, given the user `www-data`, we could look up the +/// UID and GID for the user in the system's password database (usually found +/// in `/etc/passwd`). If the `www-data` user's UID and GID were `33` and `33`, +/// respectively, one could switch the user as follows: +/// +/// ```rust,no_run +/// # use std::error::Error; +/// # use std::ffi::CString; +/// # use nix::unistd::*; +/// # +/// # fn try_main() -> Result<(), Box> { +/// let user = CString::new("www-data").unwrap(); +/// let uid = Uid::from_raw(33); +/// let gid = Gid::from_raw(33); +/// initgroups(&user, gid)?; +/// setgid(gid)?; +/// setuid(uid)?; +/// # +/// # Ok(()) +/// # } +/// # +/// # try_main().unwrap(); +/// ``` +#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))] +pub fn initgroups(user: &CStr, group: Gid) -> Result<()> { + cfg_if! { + if #[cfg(any(target_os = "ios", target_os = "macos"))] { + type initgroups_group_t = c_int; + } else { + type initgroups_group_t = gid_t; + } + } + let gid: gid_t = group.into(); + let res = unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) }; + + Errno::result(res).map(drop) +} +} + +feature! { +#![feature = "signal"] + +/// Suspend the thread until a signal is received. +/// +/// See also [pause(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html). +#[inline] +#[cfg(not(target_os = "redox"))] +pub fn pause() { + unsafe { libc::pause() }; +} + +pub mod alarm { + //! Alarm signal scheduling. + //! + //! Scheduling an alarm will trigger a `SIGALRM` signal when the time has + //! elapsed, which has to be caught, because the default action for the + //! signal is to terminate the program. This signal also can't be ignored + //! because the system calls like `pause` will not be interrupted, see the + //! second example below. + //! + //! # Examples + //! + //! Canceling an alarm: + //! + //! ``` + //! use nix::unistd::alarm; + //! + //! // Set an alarm for 60 seconds from now. + //! alarm::set(60); + //! + //! // Cancel the above set alarm, which returns the number of seconds left + //! // of the previously set alarm. + //! assert_eq!(alarm::cancel(), Some(60)); + //! ``` + //! + //! Scheduling an alarm and waiting for the signal: + //! +#![cfg_attr(target_os = "redox", doc = " ```rust,ignore")] +#![cfg_attr(not(target_os = "redox"), doc = " ```rust")] + //! use std::time::{Duration, Instant}; + //! + //! use nix::unistd::{alarm, pause}; + //! use nix::sys::signal::*; + //! + //! // We need to setup an empty signal handler to catch the alarm signal, + //! // otherwise the program will be terminated once the signal is delivered. + //! extern fn signal_handler(_: nix::libc::c_int) { } + //! let sa = SigAction::new( + //! SigHandler::Handler(signal_handler), + //! SaFlags::SA_RESTART, + //! SigSet::empty() + //! ); + //! unsafe { + //! sigaction(Signal::SIGALRM, &sa); + //! } + //! + //! let start = Instant::now(); + //! + //! // Set an alarm for 1 second from now. + //! alarm::set(1); + //! + //! // Pause the process until the alarm signal is received. + //! let mut sigset = SigSet::empty(); + //! sigset.add(Signal::SIGALRM); + //! sigset.wait(); + //! + //! assert!(start.elapsed() >= Duration::from_secs(1)); + //! ``` + //! + //! # References + //! + //! See also [alarm(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html). + + /// Schedule an alarm signal. + /// + /// This will cause the system to generate a `SIGALRM` signal for the + /// process after the specified number of seconds have elapsed. + /// + /// Returns the leftover time of a previously set alarm if there was one. + pub fn set(secs: libc::c_uint) -> Option { + assert!(secs != 0, "passing 0 to `alarm::set` is not allowed, to cancel an alarm use `alarm::cancel`"); + alarm(secs) + } + + /// Cancel an previously set alarm signal. + /// + /// Returns the leftover time of a previously set alarm if there was one. + pub fn cancel() -> Option { + alarm(0) + } + + fn alarm(secs: libc::c_uint) -> Option { + match unsafe { libc::alarm(secs) } { + 0 => None, + secs => Some(secs), + } + } +} +} + +/// Suspend execution for an interval of time +/// +/// See also [sleep(2)](https://pubs.opengroup.org/onlinepubs/009695399/functions/sleep.html#tag_03_705_05) +// Per POSIX, does not fail +#[inline] +pub fn sleep(seconds: c_uint) -> c_uint { + unsafe { libc::sleep(seconds) } +} + +feature! { +#![feature = "acct"] + +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +pub mod acct { + use crate::{Result, NixPath}; + use crate::errno::Errno; + use std::ptr; + + /// Enable process accounting + /// + /// See also [acct(2)](https://linux.die.net/man/2/acct) + pub fn enable(filename: &P) -> Result<()> { + let res = filename.with_nix_path(|cstr| { + unsafe { libc::acct(cstr.as_ptr()) } + })?; + + Errno::result(res).map(drop) + } + + /// Disable process accounting + pub fn disable() -> Result<()> { + let res = unsafe { libc::acct(ptr::null()) }; + + Errno::result(res).map(drop) + } +} +} + +feature! { +#![feature = "fs"] +/// Creates a regular file which persists even after process termination +/// +/// * `template`: a path whose 6 rightmost characters must be X, e.g. `/tmp/tmpfile_XXXXXX` +/// * returns: tuple of file descriptor and filename +/// +/// Err is returned either if no temporary filename could be created or the template doesn't +/// end with XXXXXX +/// +/// See also [mkstemp(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkstemp.html) +/// +/// # Example +/// +/// ```rust +/// use nix::unistd; +/// +/// let _ = match unistd::mkstemp("/tmp/tempfile_XXXXXX") { +/// Ok((fd, path)) => { +/// unistd::unlink(path.as_path()).unwrap(); // flag file to be deleted at app termination +/// fd +/// } +/// Err(e) => panic!("mkstemp failed: {}", e) +/// }; +/// // do something with fd +/// ``` +#[inline] +pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { + let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?; + let p = path.as_mut_ptr() as *mut _; + let fd = unsafe { libc::mkstemp(p) }; + let last = path.pop(); // drop the trailing nul + debug_assert!(last == Some(b'\0')); + let pathname = OsString::from_vec(path); + Errno::result(fd)?; + Ok((fd, PathBuf::from(pathname))) +} +} + +feature! { +#![all(feature = "fs", feature = "feature")] + +/// Variable names for `pathconf` +/// +/// Nix uses the same naming convention for these variables as the +/// [getconf(1)](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility. +/// That is, `PathconfVar` variables have the same name as the abstract +/// variables shown in the `pathconf(2)` man page. Usually, it's the same as +/// the C variable name without the leading `_PC_`. +/// +/// POSIX 1003.1-2008 standardizes all of these variables, but some OSes choose +/// not to implement variables that cannot change at runtime. +/// +/// # References +/// +/// - [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) +/// - [limits.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html) +/// - [unistd.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html) +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(i32)] +#[non_exhaustive] +pub enum PathconfVar { + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux", + target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] + /// Minimum number of bits needed to represent, as a signed integer value, + /// the maximum size of a regular file allowed in the specified directory. + #[cfg_attr(docsrs, doc(cfg(all())))] + FILESIZEBITS = libc::_PC_FILESIZEBITS, + /// Maximum number of links to a single file. + LINK_MAX = libc::_PC_LINK_MAX, + /// Maximum number of bytes in a terminal canonical input line. + MAX_CANON = libc::_PC_MAX_CANON, + /// Minimum number of bytes for which space is available in a terminal input + /// queue; therefore, the maximum number of bytes a conforming application + /// may require to be typed as input before reading them. + MAX_INPUT = libc::_PC_MAX_INPUT, + /// Maximum number of bytes in a filename (not including the terminating + /// null of a filename string). + NAME_MAX = libc::_PC_NAME_MAX, + /// Maximum number of bytes the implementation will store as a pathname in a + /// user-supplied buffer of unspecified size, including the terminating null + /// character. Minimum number the implementation will accept as the maximum + /// number of bytes in a pathname. + PATH_MAX = libc::_PC_PATH_MAX, + /// Maximum number of bytes that is guaranteed to be atomic when writing to + /// a pipe. + PIPE_BUF = libc::_PC_PIPE_BUF, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "illumos", + target_os = "linux", target_os = "netbsd", target_os = "openbsd", + target_os = "redox", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Symbolic links can be created. + POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "linux", target_os = "openbsd", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Minimum number of bytes of storage actually allocated for any portion of + /// a file. + POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "linux", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Recommended increment for file transfer sizes between the + /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values. + POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "linux", target_os = "openbsd", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Maximum recommended file transfer size. + POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "linux", target_os = "openbsd", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Minimum recommended file transfer size. + POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "linux", target_os = "openbsd", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Recommended file transfer buffer alignment. + POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "illumos", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_os = "redox", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Maximum number of bytes in a symbolic link. + SYMLINK_MAX = libc::_PC_SYMLINK_MAX, + /// The use of `chown` and `fchown` is restricted to a process with + /// appropriate privileges, and to changing the group ID of a file only to + /// the effective group ID of the process or to one of its supplementary + /// group IDs. + _POSIX_CHOWN_RESTRICTED = libc::_PC_CHOWN_RESTRICTED, + /// Pathname components longer than {NAME_MAX} generate an error. + _POSIX_NO_TRUNC = libc::_PC_NO_TRUNC, + /// This symbol shall be defined to be the value of a character that shall + /// disable terminal special character handling. + _POSIX_VDISABLE = libc::_PC_VDISABLE, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "illumos", target_os = "linux", target_os = "openbsd", + target_os = "redox", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Asynchronous input or output operations may be performed for the + /// associated file. + _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "illumos", target_os = "linux", target_os = "openbsd", + target_os = "redox", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Prioritized input or output operations may be performed for the + /// associated file. + _POSIX_PRIO_IO = libc::_PC_PRIO_IO, + #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "illumos", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_os = "redox", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Synchronized input or output operations may be performed for the + /// associated file. + _POSIX_SYNC_IO = libc::_PC_SYNC_IO, + #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The resolution in nanoseconds for all file timestamps. + _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION +} + +/// Like `pathconf`, but works with file descriptors instead of paths (see +/// [fpathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)) +/// +/// # Parameters +/// +/// - `fd`: The file descriptor whose variable should be interrogated +/// - `var`: The pathconf variable to lookup +/// +/// # Returns +/// +/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its +/// implementation level (for option variables). Implementation levels are +/// usually a decimal-coded date, such as 200112 for POSIX 2001.12 +/// - `Ok(None)`: the variable has no limit (for limit variables) or is +/// unsupported (for option variables) +/// - `Err(x)`: an error occurred +pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result> { + let raw = unsafe { + Errno::clear(); + libc::fpathconf(fd, var as c_int) + }; + if raw == -1 { + if errno::errno() == 0 { + Ok(None) + } else { + Err(Errno::last()) + } + } else { + Ok(Some(raw)) + } +} + +/// Get path-dependent configurable system variables (see +/// [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)) +/// +/// Returns the value of a path-dependent configurable system variable. Most +/// supported variables also have associated compile-time constants, but POSIX +/// allows their values to change at runtime. There are generally two types of +/// `pathconf` variables: options and limits. See [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) for more details. +/// +/// # Parameters +/// +/// - `path`: Lookup the value of `var` for this file or directory +/// - `var`: The `pathconf` variable to lookup +/// +/// # Returns +/// +/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its +/// implementation level (for option variables). Implementation levels are +/// usually a decimal-coded date, such as 200112 for POSIX 2001.12 +/// - `Ok(None)`: the variable has no limit (for limit variables) or is +/// unsupported (for option variables) +/// - `Err(x)`: an error occurred +pub fn pathconf(path: &P, var: PathconfVar) -> Result> { + let raw = path.with_nix_path(|cstr| { + unsafe { + Errno::clear(); + libc::pathconf(cstr.as_ptr(), var as c_int) + } + })?; + if raw == -1 { + if errno::errno() == 0 { + Ok(None) + } else { + Err(Errno::last()) + } + } else { + Ok(Some(raw)) + } +} +} + +feature! { +#![feature = "feature"] + +/// Variable names for `sysconf` +/// +/// Nix uses the same naming convention for these variables as the +/// [getconf(1)](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility. +/// That is, `SysconfVar` variables have the same name as the abstract variables +/// shown in the `sysconf(3)` man page. Usually, it's the same as the C +/// variable name without the leading `_SC_`. +/// +/// All of these symbols are standardized by POSIX 1003.1-2008, but haven't been +/// implemented by all platforms. +/// +/// # References +/// +/// - [sysconf(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html) +/// - [unistd.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html) +/// - [limits.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html) +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(i32)] +#[non_exhaustive] +pub enum SysconfVar { + /// Maximum number of I/O operations in a single list I/O call supported by + /// the implementation. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX, + /// Maximum number of outstanding asynchronous I/O operations supported by + /// the implementation. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + AIO_MAX = libc::_SC_AIO_MAX, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The maximum amount by which a process can decrease its asynchronous I/O + /// priority level from its own scheduling priority. + AIO_PRIO_DELTA_MAX = libc::_SC_AIO_PRIO_DELTA_MAX, + /// Maximum length of argument to the exec functions including environment data. + ARG_MAX = libc::_SC_ARG_MAX, + /// Maximum number of functions that may be registered with `atexit`. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + ATEXIT_MAX = libc::_SC_ATEXIT_MAX, + /// Maximum obase values allowed by the bc utility. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + BC_BASE_MAX = libc::_SC_BC_BASE_MAX, + /// Maximum number of elements permitted in an array by the bc utility. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + BC_DIM_MAX = libc::_SC_BC_DIM_MAX, + /// Maximum scale value allowed by the bc utility. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX, + /// Maximum length of a string constant accepted by the bc utility. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + BC_STRING_MAX = libc::_SC_BC_STRING_MAX, + /// Maximum number of simultaneous processes per real user ID. + CHILD_MAX = libc::_SC_CHILD_MAX, + // The number of clock ticks per second. + CLK_TCK = libc::_SC_CLK_TCK, + /// Maximum number of weights that can be assigned to an entry of the + /// LC_COLLATE order keyword in the locale definition file + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX, + /// Maximum number of timer expiration overruns. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX, + /// Maximum number of expressions that can be nested within parentheses by + /// the expr utility. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Maximum length of a host name (not including the terminating null) as + /// returned from the `gethostname` function + HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX, + /// Maximum number of iovec structures that one process has available for + /// use with `readv` or `writev`. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + IOV_MAX = libc::_SC_IOV_MAX, + /// Unless otherwise noted, the maximum length, in bytes, of a utility's + /// input line (either standard input or another file), when the utility is + /// described as processing text files. The length includes room for the + /// trailing newline. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + LINE_MAX = libc::_SC_LINE_MAX, + /// Maximum length of a login name. + #[cfg(not(target_os = "haiku"))] + LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX, + /// Maximum number of simultaneous supplementary group IDs per process. + NGROUPS_MAX = libc::_SC_NGROUPS_MAX, + /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX, + /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX, + /// The maximum number of open message queue descriptors a process may hold. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX, + /// The maximum number of message priorities supported by the implementation. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX, + /// A value one greater than the maximum value that the system may assign to + /// a newly-created file descriptor. + OPEN_MAX = libc::_SC_OPEN_MAX, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Advisory Information option. + _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports barriers. + _POSIX_BARRIERS = libc::_SC_BARRIERS, + /// The implementation supports asynchronous input and output. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports clock selection. + _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Process CPU-Time Clocks option. + _POSIX_CPUTIME = libc::_SC_CPUTIME, + /// The implementation supports the File Synchronization option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_FSYNC = libc::_SC_FSYNC, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the IPv6 option. + _POSIX_IPV6 = libc::_SC_IPV6, + /// The implementation supports job control. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL, + /// The implementation supports memory mapped Files. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES, + /// The implementation supports the Process Memory Locking option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_MEMLOCK = libc::_SC_MEMLOCK, + /// The implementation supports the Range Memory Locking option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE, + /// The implementation supports memory protection. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION, + /// The implementation supports the Message Passing option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING, + /// The implementation supports the Monotonic Clock option. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "illumos", target_os = "ios", target_os="linux", + target_os = "macos", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Prioritized Input and Output option. + _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO, + /// The implementation supports the Process Scheduling option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Raw Sockets option. + _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports read-write locks. + _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS, + #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports realtime signals. + _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Regular Expression Handling option. + _POSIX_REGEXP = libc::_SC_REGEXP, + /// Each process has a saved set-user-ID and a saved set-group-ID. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS, + /// The implementation supports semaphores. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES, + /// The implementation supports the Shared Memory Objects option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the POSIX shell. + _POSIX_SHELL = libc::_SC_SHELL, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Spawn option. + _POSIX_SPAWN = libc::_SC_SPAWN, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports spin locks. + _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Process Sporadic Server option. + _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER, + #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX, + /// The implementation supports the Synchronized Input and Output option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO, + /// The implementation supports the Thread Stack Address Attribute option. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR, + /// The implementation supports the Thread Stack Size Attribute option. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE, + #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", + target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Thread CPU-Time Clocks option. + _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME, + /// The implementation supports the Non-Robust Mutex Priority Inheritance + /// option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT, + /// The implementation supports the Non-Robust Mutex Priority Protection option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT, + /// The implementation supports the Thread Execution Scheduling option. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Thread Process-Shared Synchronization + /// option. + _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED, + #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Robust Mutex Priority Inheritance option. + _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT, + #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Robust Mutex Priority Protection option. + _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT, + /// The implementation supports thread-safe functions. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Thread Sporadic Server option. + _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER, + /// The implementation supports threads. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_THREADS = libc::_SC_THREADS, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports timeouts. + _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS, + /// The implementation supports timers. + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_TIMERS = libc::_SC_TIMERS, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Trace option. + _POSIX_TRACE = libc::_SC_TRACE, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Trace Event Filter option. + _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER, + #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Trace Inherit option. + _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Trace Log option. + _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG, + #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX, + #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX, + #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Typed Memory Objects option. + _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS, + /// Integer value indicating version of this standard (C-language binding) + /// to which the implementation conforms. For implementations conforming to + /// POSIX.1-2008, the value shall be 200809L. + _POSIX_VERSION = libc::_SC_VERSION, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation provides a C-language compilation environment with + /// 32-bit `int`, `long`, `pointer`, and `off_t` types. + _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation provides a C-language compilation environment with + /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at + /// least 64 bits. + _POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation provides a C-language compilation environment with + /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types. + _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation provides a C-language compilation environment with an + /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types + /// using at least 64 bits. + _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG, + /// The implementation supports the C-Language Binding option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX2_C_BIND = libc::_SC_2_C_BIND, + /// The implementation supports the C-Language Development Utilities option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX2_C_DEV = libc::_SC_2_C_DEV, + /// The implementation supports the Terminal Characteristics option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM, + /// The implementation supports the FORTRAN Development Utilities option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV, + /// The implementation supports the FORTRAN Runtime Utilities option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN, + /// The implementation supports the creation of locales by the localedef + /// utility. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Batch Environment Services and Utilities + /// option. + _POSIX2_PBS = libc::_SC_2_PBS, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Batch Accounting option. + _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Batch Checkpoint/Restart option. + _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Locate Batch Job Request option. + _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Batch Job Message Request option. + _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Track Batch Job Request option. + _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK, + /// The implementation supports the Software Development Utilities option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX2_SW_DEV = libc::_SC_2_SW_DEV, + /// The implementation supports the User Portability Utilities option. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX2_UPE = libc::_SC_2_UPE, + /// Integer value indicating version of the Shell and Utilities volume of + /// POSIX.1 to which the implementation conforms. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _POSIX2_VERSION = libc::_SC_2_VERSION, + /// The size of a system page in bytes. + /// + /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two + /// enum constants to have the same value, so nix omits `PAGESIZE`. + PAGE_SIZE = libc::_SC_PAGE_SIZE, + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS, + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX, + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN, + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX, + #[cfg(not(target_os = "haiku"))] + RE_DUP_MAX = libc::_SC_RE_DUP_MAX, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + RTSIG_MAX = libc::_SC_RTSIG_MAX, + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX, + #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", + target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX, + STREAM_MAX = libc::_SC_STREAM_MAX, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="netbsd", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX, + #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + TIMER_MAX = libc::_SC_TIMER_MAX, + TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX, + TZNAME_MAX = libc::_SC_TZNAME_MAX, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the X/Open Encryption Option Group. + _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the Issue 4, Version 2 Enhanced + /// Internationalization Option Group. + _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the X/Open Realtime Option Group. + _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the X/Open Realtime Threads Option Group. + _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS, + /// The implementation supports the Issue 4, Version 2 Shared Memory Option + /// Group. + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + _XOPEN_SHM = libc::_SC_XOPEN_SHM, + #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", + target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the XSI STREAMS Option Group. + _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the XSI option + _XOPEN_UNIX = libc::_SC_XOPEN_UNIX, + #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", + target_os = "ios", target_os="linux", target_os = "macos", + target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Integer value indicating version of the X/Open Portability Guide to + /// which the implementation conforms. + _XOPEN_VERSION = libc::_SC_XOPEN_VERSION, + /// The number of pages of physical memory. Note that it is possible for + /// the product of this value to overflow. + #[cfg(any(target_os="android", target_os="linux"))] + _PHYS_PAGES = libc::_SC_PHYS_PAGES, + /// The number of currently available pages of physical memory. + #[cfg(any(target_os="android", target_os="linux"))] + _AVPHYS_PAGES = libc::_SC_AVPHYS_PAGES, + /// The number of processors configured. + #[cfg(any(target_os="android", target_os="linux"))] + _NPROCESSORS_CONF = libc::_SC_NPROCESSORS_CONF, + /// The number of processors currently online (available). + #[cfg(any(target_os="android", target_os="linux"))] + _NPROCESSORS_ONLN = libc::_SC_NPROCESSORS_ONLN, +} + +/// Get configurable system variables (see +/// [sysconf(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html)) +/// +/// Returns the value of a configurable system variable. Most supported +/// variables also have associated compile-time constants, but POSIX +/// allows their values to change at runtime. There are generally two types of +/// sysconf variables: options and limits. See sysconf(3) for more details. +/// +/// # Returns +/// +/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its +/// implementation level (for option variables). Implementation levels are +/// usually a decimal-coded date, such as 200112 for POSIX 2001.12 +/// - `Ok(None)`: the variable has no limit (for limit variables) or is +/// unsupported (for option variables) +/// - `Err(x)`: an error occurred +pub fn sysconf(var: SysconfVar) -> Result> { + let raw = unsafe { + Errno::clear(); + libc::sysconf(var as c_int) + }; + if raw == -1 { + if errno::errno() == 0 { + Ok(None) + } else { + Err(Errno::last()) + } + } else { + Ok(Some(raw)) + } +} +} + +feature! { +#![feature = "fs"] + +#[cfg(any(target_os = "android", target_os = "linux"))] +mod pivot_root { + use crate::{Result, NixPath}; + use crate::errno::Errno; + + pub fn pivot_root( + new_root: &P1, put_old: &P2) -> Result<()> { + let res = new_root.with_nix_path(|new_root| { + put_old.with_nix_path(|put_old| { + unsafe { + libc::syscall(libc::SYS_pivot_root, new_root.as_ptr(), put_old.as_ptr()) + } + }) + })??; + + Errno::result(res).map(drop) + } +} +} + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] +mod setres { + feature! { + #![feature = "user"] + + use crate::Result; + use crate::errno::Errno; + use super::{Uid, Gid}; + + /// Sets the real, effective, and saved uid. + /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html)) + /// + /// * `ruid`: real user id + /// * `euid`: effective user id + /// * `suid`: saved user id + /// * returns: Ok or libc error code. + /// + /// Err is returned if the user doesn't have permission to set this UID. + #[inline] + pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> { + let res = unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) }; + + Errno::result(res).map(drop) + } + + /// Sets the real, effective, and saved gid. + /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html)) + /// + /// * `rgid`: real group id + /// * `egid`: effective group id + /// * `sgid`: saved group id + /// * returns: Ok or libc error code. + /// + /// Err is returned if the user doesn't have permission to set this GID. + #[inline] + pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> { + let res = unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) }; + + Errno::result(res).map(drop) + } + } +} + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] +mod getres { + feature! { + #![feature = "user"] + + use crate::Result; + use crate::errno::Errno; + use super::{Uid, Gid}; + + /// Real, effective and saved user IDs. + #[derive(Debug, Copy, Clone, Eq, PartialEq)] + pub struct ResUid { + pub real: Uid, + pub effective: Uid, + pub saved: Uid + } + + /// Real, effective and saved group IDs. + #[derive(Debug, Copy, Clone, Eq, PartialEq)] + pub struct ResGid { + pub real: Gid, + pub effective: Gid, + pub saved: Gid + } + + /// Gets the real, effective, and saved user IDs. + /// + /// ([see getresuid(2)](http://man7.org/linux/man-pages/man2/getresuid.2.html)) + /// + /// #Returns + /// + /// - `Ok((Uid, Uid, Uid))`: tuple of real, effective and saved uids on success. + /// - `Err(x)`: libc error code on failure. + /// + #[inline] + pub fn getresuid() -> Result { + let mut ruid = libc::uid_t::max_value(); + let mut euid = libc::uid_t::max_value(); + let mut suid = libc::uid_t::max_value(); + let res = unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) }; + + Errno::result(res).map(|_| ResUid{ real: Uid(ruid), effective: Uid(euid), saved: Uid(suid) }) + } + + /// Gets the real, effective, and saved group IDs. + /// + /// ([see getresgid(2)](http://man7.org/linux/man-pages/man2/getresgid.2.html)) + /// + /// #Returns + /// + /// - `Ok((Gid, Gid, Gid))`: tuple of real, effective and saved gids on success. + /// - `Err(x)`: libc error code on failure. + /// + #[inline] + pub fn getresgid() -> Result { + let mut rgid = libc::gid_t::max_value(); + let mut egid = libc::gid_t::max_value(); + let mut sgid = libc::gid_t::max_value(); + let res = unsafe { libc::getresgid(&mut rgid, &mut egid, &mut sgid) }; + + Errno::result(res).map(|_| ResGid { real: Gid(rgid), effective: Gid(egid), saved: Gid(sgid) } ) + } + } +} + +#[cfg(feature = "fs")] +libc_bitflags! { + /// Options for access() + #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] + pub struct AccessFlags : c_int { + /// Test for existence of file. + F_OK; + /// Test for read permission. + R_OK; + /// Test for write permission. + W_OK; + /// Test for execute (search) permission. + X_OK; + } +} + +feature! { +#![feature = "fs"] + +/// Checks the file named by `path` for accessibility according to the flags given by `amode` +/// See [access(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html) +pub fn access(path: &P, amode: AccessFlags) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { + libc::access(cstr.as_ptr(), amode.bits) + } + })?; + Errno::result(res).map(drop) +} + +/// Checks the file named by `path` for accessibility according to the flags given by `mode` +/// +/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor. +/// +/// If `dirfd` is `None`, then `path` is relative to the current working directory. +/// +/// # References +/// +/// [faccessat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/faccessat.html) +// redox: does not appear to support the *at family of syscalls. +#[cfg(not(target_os = "redox"))] +pub fn faccessat(dirfd: Option, path: &P, mode: AccessFlags, flags: AtFlags) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { + libc::faccessat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits(), flags.bits()) + } + })?; + Errno::result(res).map(drop) +} + +/// Checks the file named by `path` for accessibility according to the flags given +/// by `mode` using effective UID, effective GID and supplementary group lists. +/// +/// # References +/// +/// * [FreeBSD man page](https://www.freebsd.org/cgi/man.cgi?query=eaccess&sektion=2&n=1) +/// * [Linux man page](https://man7.org/linux/man-pages/man3/euidaccess.3.html) +#[cfg(any( + all(target_os = "linux", not(target_env = "uclibc")), + target_os = "freebsd", + target_os = "dragonfly" +))] +pub fn eaccess(path: &P, mode: AccessFlags) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { + libc::eaccess(cstr.as_ptr(), mode.bits) + } + })?; + Errno::result(res).map(drop) +} +} + +feature! { +#![feature = "user"] + +/// Representation of a User, based on `libc::passwd` +/// +/// The reason some fields in this struct are `String` and others are `CString` is because some +/// fields are based on the user's locale, which could be non-UTF8, while other fields are +/// guaranteed to conform to [`NAME_REGEX`](https://serverfault.com/a/73101/407341), which only +/// contains ASCII. +#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct User { + /// Username + pub name: String, + /// User password (probably hashed) + pub passwd: CString, + /// User ID + pub uid: Uid, + /// Group ID + pub gid: Gid, + /// User information + #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] + pub gecos: CString, + /// Home directory + pub dir: PathBuf, + /// Path to shell + pub shell: PathBuf, + /// Login class + #[cfg(not(any(target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub class: CString, + /// Last password change + #[cfg(not(any(target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub change: libc::time_t, + /// Expiration time of account + #[cfg(not(any(target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub expire: libc::time_t +} + +#[cfg(not(target_os = "redox"))] //RedoxFS does not support passwd +impl From<&libc::passwd> for User { + fn from(pw: &libc::passwd) -> User { + unsafe { + User { + name: if pw.pw_name.is_null() { Default::default() } else { CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned() }, + passwd: if pw.pw_passwd.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes()).unwrap() }, + #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] + gecos: if pw.pw_gecos.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes()).unwrap() }, + dir: if pw.pw_dir.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_dir).to_bytes())) }, + shell: if pw.pw_shell.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_shell).to_bytes())) }, + uid: Uid::from_raw(pw.pw_uid), + gid: Gid::from_raw(pw.pw_gid), + #[cfg(not(any(target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris")))] + class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes()).unwrap(), + #[cfg(not(any(target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris")))] + change: pw.pw_change, + #[cfg(not(any(target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris")))] + expire: pw.pw_expire + } + } + } +} + +#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd +impl From for libc::passwd { + fn from(u: User) -> Self { + let name = match CString::new(u.name) { + Ok(n) => n.into_raw(), + Err(_) => CString::new("").unwrap().into_raw(), + }; + let dir = match u.dir.into_os_string().into_string() { + Ok(s) => CString::new(s.as_str()).unwrap().into_raw(), + Err(_) => CString::new("").unwrap().into_raw(), + }; + let shell = match u.shell.into_os_string().into_string() { + Ok(s) => CString::new(s.as_str()).unwrap().into_raw(), + Err(_) => CString::new("").unwrap().into_raw(), + }; + Self { + pw_name: name, + pw_passwd: u.passwd.into_raw(), + #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] + pw_gecos: u.gecos.into_raw(), + pw_dir: dir, + pw_shell: shell, + pw_uid: u.uid.0, + pw_gid: u.gid.0, + #[cfg(not(any(target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris")))] + pw_class: u.class.into_raw(), + #[cfg(not(any(target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris")))] + pw_change: u.change, + #[cfg(not(any(target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris")))] + pw_expire: u.expire, + #[cfg(target_os = "illumos")] + pw_age: CString::new("").unwrap().into_raw(), + #[cfg(target_os = "illumos")] + pw_comment: CString::new("").unwrap().into_raw(), + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + pw_fields: 0, + } + } +} + +#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd +impl User { + fn from_anything(f: F) -> Result> + where + F: Fn(*mut libc::passwd, + *mut c_char, + libc::size_t, + *mut *mut libc::passwd) -> libc::c_int + { + let buflimit = 1048576; + let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) { + Ok(Some(n)) => n as usize, + Ok(None) | Err(_) => 16384, + }; + + let mut cbuf = Vec::with_capacity(bufsize); + let mut pwd = mem::MaybeUninit::::uninit(); + let mut res = ptr::null_mut(); + + loop { + let error = f(pwd.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res); + if error == 0 { + if res.is_null() { + return Ok(None); + } else { + let pwd = unsafe { pwd.assume_init() }; + return Ok(Some(User::from(&pwd))); + } + } else if Errno::last() == Errno::ERANGE { + // Trigger the internal buffer resizing logic. + reserve_double_buffer_size(&mut cbuf, buflimit)?; + } else { + return Err(Errno::last()); + } + } + } + + /// Get a user by UID. + /// + /// Internally, this function calls + /// [getpwuid_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) + /// + /// # Examples + /// + /// ``` + /// use nix::unistd::{Uid, User}; + /// // Returns an Result>, thus the double unwrap. + /// let res = User::from_uid(Uid::from_raw(0)).unwrap().unwrap(); + /// assert_eq!(res.name, "root"); + /// ``` + pub fn from_uid(uid: Uid) -> Result> { + User::from_anything(|pwd, cbuf, cap, res| { + unsafe { libc::getpwuid_r(uid.0, pwd, cbuf, cap, res) } + }) + } + + /// Get a user by name. + /// + /// Internally, this function calls + /// [getpwnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) + /// + /// # Examples + /// + /// ``` + /// use nix::unistd::User; + /// // Returns an Result>, thus the double unwrap. + /// let res = User::from_name("root").unwrap().unwrap(); + /// assert_eq!(res.name, "root"); + /// ``` + pub fn from_name(name: &str) -> Result> { + let name = match CString::new(name) { + Ok(c_str) => c_str, + Err(_nul_error) => return Ok(None), + }; + User::from_anything(|pwd, cbuf, cap, res| { + unsafe { libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) } + }) + } +} + +/// Representation of a Group, based on `libc::group` +#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Group { + /// Group name + pub name: String, + /// Group password + pub passwd: CString, + /// Group ID + pub gid: Gid, + /// List of Group members + pub mem: Vec +} + +#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd +impl From<&libc::group> for Group { + fn from(gr: &libc::group) -> Group { + unsafe { + Group { + name: CStr::from_ptr(gr.gr_name).to_string_lossy().into_owned(), + passwd: CString::new(CStr::from_ptr(gr.gr_passwd).to_bytes()).unwrap(), + gid: Gid::from_raw(gr.gr_gid), + mem: Group::members(gr.gr_mem) + } + } + } +} + +#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd +impl Group { + unsafe fn members(mem: *mut *mut c_char) -> Vec { + let mut ret = Vec::new(); + + for i in 0.. { + let u = mem.offset(i); + if (*u).is_null() { + break; + } else { + let s = CStr::from_ptr(*u).to_string_lossy().into_owned(); + ret.push(s); + } + } + + ret + } + + fn from_anything(f: F) -> Result> + where + F: Fn(*mut libc::group, + *mut c_char, + libc::size_t, + *mut *mut libc::group) -> libc::c_int + { + let buflimit = 1048576; + let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) { + Ok(Some(n)) => n as usize, + Ok(None) | Err(_) => 16384, + }; + + let mut cbuf = Vec::with_capacity(bufsize); + let mut grp = mem::MaybeUninit::::uninit(); + let mut res = ptr::null_mut(); + + loop { + let error = f(grp.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res); + if error == 0 { + if res.is_null() { + return Ok(None); + } else { + let grp = unsafe { grp.assume_init() }; + return Ok(Some(Group::from(&grp))); + } + } else if Errno::last() == Errno::ERANGE { + // Trigger the internal buffer resizing logic. + reserve_double_buffer_size(&mut cbuf, buflimit)?; + } else { + return Err(Errno::last()); + } + } + } + + /// Get a group by GID. + /// + /// Internally, this function calls + /// [getgrgid_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) + /// + /// # Examples + /// + // Disable this test on all OS except Linux as root group may not exist. + #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")] + #[cfg_attr(target_os = "linux", doc = " ```")] + /// use nix::unistd::{Gid, Group}; + /// // Returns an Result>, thus the double unwrap. + /// let res = Group::from_gid(Gid::from_raw(0)).unwrap().unwrap(); + /// assert!(res.name == "root"); + /// ``` + pub fn from_gid(gid: Gid) -> Result> { + Group::from_anything(|grp, cbuf, cap, res| { + unsafe { libc::getgrgid_r(gid.0, grp, cbuf, cap, res) } + }) + } + + /// Get a group by name. + /// + /// Internally, this function calls + /// [getgrnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) + /// + /// # Examples + /// + // Disable this test on all OS except Linux as root group may not exist. + #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")] + #[cfg_attr(target_os = "linux", doc = " ```")] + /// use nix::unistd::Group; + /// // Returns an Result>, thus the double unwrap. + /// let res = Group::from_name("root").unwrap().unwrap(); + /// assert!(res.name == "root"); + /// ``` + pub fn from_name(name: &str) -> Result> { + let name = match CString::new(name) { + Ok(c_str) => c_str, + Err(_nul_error) => return Ok(None), + }; + Group::from_anything(|grp, cbuf, cap, res| { + unsafe { libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) } + }) + } +} +} + +feature! { +#![feature = "term"] + +/// Get the name of the terminal device that is open on file descriptor fd +/// (see [`ttyname(3)`](https://man7.org/linux/man-pages/man3/ttyname.3.html)). +#[cfg(not(target_os = "fuchsia"))] +pub fn ttyname(fd: RawFd) -> Result { + const PATH_MAX: usize = libc::PATH_MAX as usize; + let mut buf = vec![0_u8; PATH_MAX]; + let c_buf = buf.as_mut_ptr() as *mut libc::c_char; + + let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) }; + if ret != 0 { + return Err(Errno::from_i32(ret)); + } + + let nul = buf.iter().position(|c| *c == b'\0').unwrap(); + buf.truncate(nul); + Ok(OsString::from_vec(buf).into()) +} +} + +feature! { +#![all(feature = "socket", feature = "user")] + +/// Get the effective user ID and group ID associated with a Unix domain socket. +/// +/// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid) +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", +))] +pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> { + let mut uid = 1; + let mut gid = 1; + + let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) }; + + Errno::result(ret).map(|_| (Uid(uid), Gid(gid))) +} +} + +feature! { +#![all(feature = "fs")] + +/// Set the file flags. +/// +/// See also [chflags(2)](https://www.freebsd.org/cgi/man.cgi?query=chflags&sektion=2) +#[cfg(any( + target_os = "openbsd", + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios" +))] +pub fn chflags(path: &P, flags: FileFlag) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::chflags(cstr.as_ptr(), flags.bits()) + })?; + + Errno::result(res).map(drop) +} +} diff --git a/vendor/nix-0.26.2/test/common/mod.rs b/vendor/nix-0.26.2/test/common/mod.rs new file mode 100644 index 0000000000000..bb056aab87c5c --- /dev/null +++ b/vendor/nix-0.26.2/test/common/mod.rs @@ -0,0 +1,149 @@ +use cfg_if::cfg_if; + +#[macro_export] +macro_rules! skip { + ($($reason: expr),+) => { + use ::std::io::{self, Write}; + + let stderr = io::stderr(); + let mut handle = stderr.lock(); + writeln!(handle, $($reason),+).unwrap(); + return; + } +} + +cfg_if! { + if #[cfg(any(target_os = "android", target_os = "linux"))] { + #[macro_export] macro_rules! require_capability { + ($name:expr, $capname:ident) => { + use ::caps::{Capability, CapSet, has_cap}; + + if !has_cap(None, CapSet::Effective, Capability::$capname) + .unwrap() + { + skip!("{} requires capability {}. Skipping test.", $name, Capability::$capname); + } + } + } + } else if #[cfg(not(target_os = "redox"))] { + #[macro_export] macro_rules! require_capability { + ($name:expr, $capname:ident) => {} + } + } +} + +/// Skip the test if we don't have the ability to mount file systems. +#[cfg(target_os = "freebsd")] +#[macro_export] +macro_rules! require_mount { + ($name:expr) => { + use ::sysctl::{CtlValue, Sysctl}; + use nix::unistd::Uid; + + let ctl = ::sysctl::Ctl::new("vfs.usermount").unwrap(); + if !Uid::current().is_root() && CtlValue::Int(0) == ctl.value().unwrap() + { + skip!( + "{} requires the ability to mount file systems. Skipping test.", + $name + ); + } + }; +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +#[macro_export] +macro_rules! skip_if_cirrus { + ($reason:expr) => { + if std::env::var_os("CIRRUS_CI").is_some() { + skip!("{}", $reason); + } + }; +} + +#[cfg(target_os = "freebsd")] +#[macro_export] +macro_rules! skip_if_jailed { + ($name:expr) => { + use ::sysctl::{CtlValue, Sysctl}; + + let ctl = ::sysctl::Ctl::new("security.jail.jailed").unwrap(); + if let CtlValue::Int(1) = ctl.value().unwrap() { + skip!("{} cannot run in a jail. Skipping test.", $name); + } + }; +} + +#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] +#[macro_export] +macro_rules! skip_if_not_root { + ($name:expr) => { + use nix::unistd::Uid; + + if !Uid::current().is_root() { + skip!("{} requires root privileges. Skipping test.", $name); + } + }; +} + +cfg_if! { + if #[cfg(any(target_os = "android", target_os = "linux"))] { + #[macro_export] macro_rules! skip_if_seccomp { + ($name:expr) => { + if let Ok(s) = std::fs::read_to_string("/proc/self/status") { + for l in s.lines() { + let mut fields = l.split_whitespace(); + if fields.next() == Some("Seccomp:") && + fields.next() != Some("0") + { + skip!("{} cannot be run in Seccomp mode. Skipping test.", + stringify!($name)); + } + } + } + } + } + } else if #[cfg(not(target_os = "redox"))] { + #[macro_export] macro_rules! skip_if_seccomp { + ($name:expr) => {} + } + } +} + +cfg_if! { + if #[cfg(target_os = "linux")] { + #[macro_export] macro_rules! require_kernel_version { + ($name:expr, $version_requirement:expr) => { + use semver::{Version, VersionReq}; + + let version_requirement = VersionReq::parse($version_requirement) + .expect("Bad match_version provided"); + + let uname = nix::sys::utsname::uname().unwrap(); + println!("{}", uname.sysname().to_str().unwrap()); + println!("{}", uname.nodename().to_str().unwrap()); + println!("{}", uname.release().to_str().unwrap()); + println!("{}", uname.version().to_str().unwrap()); + println!("{}", uname.machine().to_str().unwrap()); + + // Fix stuff that the semver parser can't handle + let fixed_release = &uname.release().to_str().unwrap().to_string() + // Fedora 33 reports version as 4.18.el8_2.x86_64 or + // 5.18.200-fc33.x86_64. Remove the underscore. + .replace("_", "-") + // Cirrus-CI reports version as 4.19.112+ . Remove the + + .replace("+", ""); + let mut version = Version::parse(fixed_release).unwrap(); + + //Keep only numeric parts + version.pre = semver::Prerelease::EMPTY; + version.build = semver::BuildMetadata::EMPTY; + + if !version_requirement.matches(&version) { + skip!("Skip {} because kernel version `{}` doesn't match the requirement `{}`", + stringify!($name), version, version_requirement); + } + } + } + } +} diff --git a/vendor/nix-0.26.2/test/sys/mod.rs b/vendor/nix-0.26.2/test/sys/mod.rs new file mode 100644 index 0000000000000..20312120a68c0 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/mod.rs @@ -0,0 +1,60 @@ +mod test_signal; + +// NOTE: DragonFly lacks a kernel-level implementation of Posix AIO as of +// this writing. There is an user-level implementation, but whether aio +// works or not heavily depends on which pthread implementation is chosen +// by the user at link time. For this reason we do not want to run aio test +// cases on DragonFly. +#[cfg(any( + target_os = "freebsd", + target_os = "ios", + all(target_os = "linux", not(target_env = "uclibc")), + target_os = "macos", + target_os = "netbsd" +))] +mod test_aio; +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] +mod test_ioctl; +#[cfg(not(target_os = "redox"))] +mod test_mman; +#[cfg(not(target_os = "redox"))] +mod test_select; +#[cfg(target_os = "linux")] +mod test_signalfd; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +mod test_socket; +#[cfg(not(any(target_os = "redox")))] +mod test_sockopt; +mod test_stat; +#[cfg(any(target_os = "android", target_os = "linux"))] +mod test_sysinfo; +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] +mod test_termios; +mod test_uio; +mod test_wait; + +#[cfg(any(target_os = "android", target_os = "linux"))] +mod test_epoll; +#[cfg(target_os = "linux")] +mod test_inotify; +mod test_pthread; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] +mod test_ptrace; +#[cfg(any(target_os = "android", target_os = "linux"))] +mod test_timerfd; diff --git a/vendor/nix-0.26.2/test/sys/test_aio.rs b/vendor/nix-0.26.2/test/sys/test_aio.rs new file mode 100644 index 0000000000000..84086f80ceb71 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_aio.rs @@ -0,0 +1,626 @@ +use std::{ + io::{Read, Seek, Write}, + ops::Deref, + os::unix::io::AsRawFd, + pin::Pin, + sync::atomic::{AtomicBool, Ordering}, + thread, time, +}; + +use libc::c_int; +use nix::{ + errno::*, + sys::{ + aio::*, + signal::{ + sigaction, SaFlags, SigAction, SigHandler, SigSet, SigevNotify, + Signal, + }, + time::{TimeSpec, TimeValLike}, + }, +}; +use tempfile::tempfile; + +lazy_static! { + pub static ref SIGNALED: AtomicBool = AtomicBool::new(false); +} + +extern "C" fn sigfunc(_: c_int) { + SIGNALED.store(true, Ordering::Relaxed); +} + +// Helper that polls an AioCb for completion or error +macro_rules! poll_aio { + ($aiocb: expr) => { + loop { + let err = $aiocb.as_mut().error(); + if err != Err(Errno::EINPROGRESS) { + break err; + }; + thread::sleep(time::Duration::from_millis(10)); + } + }; +} + +mod aio_fsync { + use super::*; + + #[test] + fn test_accessors() { + let aiocb = AioFsync::new( + 1001, + AioFsyncMode::O_SYNC, + 42, + SigevNotify::SigevSignal { + signal: Signal::SIGUSR2, + si_value: 99, + }, + ); + assert_eq!(1001, aiocb.fd()); + assert_eq!(AioFsyncMode::O_SYNC, aiocb.mode()); + assert_eq!(42, aiocb.priority()); + let sev = aiocb.sigevent().sigevent(); + assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); + assert_eq!(99, sev.sigev_value.sival_ptr as i64); + } + + /// `AioFsync::submit` should not modify the `AioCb` object if + /// `libc::aio_fsync` returns an error + // Skip on Linux, because Linux's AIO implementation can't detect errors + // synchronously + #[test] + #[cfg(any(target_os = "freebsd", target_os = "macos"))] + fn error() { + use std::mem; + + const INITIAL: &[u8] = b"abcdef123456"; + // Create an invalid AioFsyncMode + let mode = unsafe { mem::transmute(666) }; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let mut aiof = Box::pin(AioFsync::new( + f.as_raw_fd(), + mode, + 0, + SigevNotify::SigevNone, + )); + let err = aiof.as_mut().submit(); + err.expect_err("assertion failed"); + } + + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn ok() { + const INITIAL: &[u8] = b"abcdef123456"; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let fd = f.as_raw_fd(); + let mut aiof = Box::pin(AioFsync::new( + fd, + AioFsyncMode::O_SYNC, + 0, + SigevNotify::SigevNone, + )); + aiof.as_mut().submit().unwrap(); + poll_aio!(&mut aiof).unwrap(); + aiof.as_mut().aio_return().unwrap(); + } +} + +mod aio_read { + use super::*; + + #[test] + fn test_accessors() { + let mut rbuf = vec![0; 4]; + let aiocb = AioRead::new( + 1001, + 2, //offset + &mut rbuf, + 42, //priority + SigevNotify::SigevSignal { + signal: Signal::SIGUSR2, + si_value: 99, + }, + ); + assert_eq!(1001, aiocb.fd()); + assert_eq!(4, aiocb.nbytes()); + assert_eq!(2, aiocb.offset()); + assert_eq!(42, aiocb.priority()); + let sev = aiocb.sigevent().sigevent(); + assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); + assert_eq!(99, sev.sigev_value.sival_ptr as i64); + } + + // Tests AioWrite.cancel. We aren't trying to test the OS's implementation, + // only our bindings. So it's sufficient to check that cancel + // returned any AioCancelStat value. + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn cancel() { + const INITIAL: &[u8] = b"abcdef123456"; + let mut rbuf = vec![0; 4]; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let fd = f.as_raw_fd(); + let mut aior = + Box::pin(AioRead::new(fd, 2, &mut rbuf, 0, SigevNotify::SigevNone)); + aior.as_mut().submit().unwrap(); + + aior.as_mut().cancel().unwrap(); + + // Wait for aiow to complete, but don't care whether it succeeded + let _ = poll_aio!(&mut aior); + let _ = aior.as_mut().aio_return(); + } + + /// `AioRead::submit` should not modify the `AioCb` object if + /// `libc::aio_read` returns an error + // Skip on Linux, because Linux's AIO implementation can't detect errors + // synchronously + #[test] + #[cfg(any(target_os = "freebsd", target_os = "macos"))] + fn error() { + const INITIAL: &[u8] = b"abcdef123456"; + let mut rbuf = vec![0; 4]; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let mut aior = Box::pin(AioRead::new( + f.as_raw_fd(), + -1, //an invalid offset + &mut rbuf, + 0, //priority + SigevNotify::SigevNone, + )); + aior.as_mut().submit().expect_err("assertion failed"); + } + + // Test a simple aio operation with no completion notification. We must + // poll for completion + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn ok() { + const INITIAL: &[u8] = b"abcdef123456"; + let mut rbuf = vec![0; 4]; + const EXPECT: &[u8] = b"cdef"; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + { + let fd = f.as_raw_fd(); + let mut aior = Box::pin(AioRead::new( + fd, + 2, + &mut rbuf, + 0, + SigevNotify::SigevNone, + )); + aior.as_mut().submit().unwrap(); + + let err = poll_aio!(&mut aior); + assert_eq!(err, Ok(())); + assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len()); + } + assert_eq!(EXPECT, rbuf.deref().deref()); + } + + // Like ok, but allocates the structure on the stack. + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn on_stack() { + const INITIAL: &[u8] = b"abcdef123456"; + let mut rbuf = vec![0; 4]; + const EXPECT: &[u8] = b"cdef"; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + { + let fd = f.as_raw_fd(); + let mut aior = + AioRead::new(fd, 2, &mut rbuf, 0, SigevNotify::SigevNone); + let mut aior = unsafe { Pin::new_unchecked(&mut aior) }; + aior.as_mut().submit().unwrap(); + + let err = poll_aio!(&mut aior); + assert_eq!(err, Ok(())); + assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len()); + } + assert_eq!(EXPECT, rbuf.deref().deref()); + } +} + +#[cfg(target_os = "freebsd")] +#[cfg(fbsd14)] +mod aio_readv { + use std::io::IoSliceMut; + + use super::*; + + #[test] + fn test_accessors() { + let mut rbuf0 = vec![0; 4]; + let mut rbuf1 = vec![0; 8]; + let mut rbufs = + [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)]; + let aiocb = AioReadv::new( + 1001, + 2, //offset + &mut rbufs, + 42, //priority + SigevNotify::SigevSignal { + signal: Signal::SIGUSR2, + si_value: 99, + }, + ); + assert_eq!(1001, aiocb.fd()); + assert_eq!(2, aiocb.iovlen()); + assert_eq!(2, aiocb.offset()); + assert_eq!(42, aiocb.priority()); + let sev = aiocb.sigevent().sigevent(); + assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); + assert_eq!(99, sev.sigev_value.sival_ptr as i64); + } + + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn ok() { + const INITIAL: &[u8] = b"abcdef123456"; + let mut rbuf0 = vec![0; 4]; + let mut rbuf1 = vec![0; 2]; + let mut rbufs = + [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)]; + const EXPECT0: &[u8] = b"cdef"; + const EXPECT1: &[u8] = b"12"; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + { + let fd = f.as_raw_fd(); + let mut aior = Box::pin(AioReadv::new( + fd, + 2, + &mut rbufs, + 0, + SigevNotify::SigevNone, + )); + aior.as_mut().submit().unwrap(); + + let err = poll_aio!(&mut aior); + assert_eq!(err, Ok(())); + assert_eq!( + aior.as_mut().aio_return().unwrap(), + EXPECT0.len() + EXPECT1.len() + ); + } + assert_eq!(&EXPECT0, &rbuf0); + assert_eq!(&EXPECT1, &rbuf1); + } +} + +mod aio_write { + use super::*; + + #[test] + fn test_accessors() { + let wbuf = vec![0; 4]; + let aiocb = AioWrite::new( + 1001, + 2, //offset + &wbuf, + 42, //priority + SigevNotify::SigevSignal { + signal: Signal::SIGUSR2, + si_value: 99, + }, + ); + assert_eq!(1001, aiocb.fd()); + assert_eq!(4, aiocb.nbytes()); + assert_eq!(2, aiocb.offset()); + assert_eq!(42, aiocb.priority()); + let sev = aiocb.sigevent().sigevent(); + assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); + assert_eq!(99, sev.sigev_value.sival_ptr as i64); + } + + // Tests AioWrite.cancel. We aren't trying to test the OS's implementation, + // only our bindings. So it's sufficient to check that cancel + // returned any AioCancelStat value. + #[test] + #[cfg_attr(target_env = "musl", ignore)] + fn cancel() { + let wbuf: &[u8] = b"CDEF"; + + let f = tempfile().unwrap(); + let mut aiow = Box::pin(AioWrite::new( + f.as_raw_fd(), + 0, + wbuf, + 0, + SigevNotify::SigevNone, + )); + aiow.as_mut().submit().unwrap(); + let err = aiow.as_mut().error(); + assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); + + aiow.as_mut().cancel().unwrap(); + + // Wait for aiow to complete, but don't care whether it succeeded + let _ = poll_aio!(&mut aiow); + let _ = aiow.as_mut().aio_return(); + } + + // Test a simple aio operation with no completion notification. We must + // poll for completion. + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn ok() { + const INITIAL: &[u8] = b"abcdef123456"; + let wbuf = "CDEF".to_string().into_bytes(); + let mut rbuf = Vec::new(); + const EXPECT: &[u8] = b"abCDEF123456"; + + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let mut aiow = Box::pin(AioWrite::new( + f.as_raw_fd(), + 2, + &wbuf, + 0, + SigevNotify::SigevNone, + )); + aiow.as_mut().submit().unwrap(); + + let err = poll_aio!(&mut aiow); + assert_eq!(err, Ok(())); + assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len()); + + f.rewind().unwrap(); + let len = f.read_to_end(&mut rbuf).unwrap(); + assert_eq!(len, EXPECT.len()); + assert_eq!(rbuf, EXPECT); + } + + // Like ok, but allocates the structure on the stack. + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn on_stack() { + const INITIAL: &[u8] = b"abcdef123456"; + let wbuf = "CDEF".to_string().into_bytes(); + let mut rbuf = Vec::new(); + const EXPECT: &[u8] = b"abCDEF123456"; + + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let mut aiow = AioWrite::new( + f.as_raw_fd(), + 2, //offset + &wbuf, + 0, //priority + SigevNotify::SigevNone, + ); + let mut aiow = unsafe { Pin::new_unchecked(&mut aiow) }; + aiow.as_mut().submit().unwrap(); + + let err = poll_aio!(&mut aiow); + assert_eq!(err, Ok(())); + assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len()); + + f.rewind().unwrap(); + let len = f.read_to_end(&mut rbuf).unwrap(); + assert_eq!(len, EXPECT.len()); + assert_eq!(rbuf, EXPECT); + } + + /// `AioWrite::write` should not modify the `AioCb` object if + /// `libc::aio_write` returns an error. + // Skip on Linux, because Linux's AIO implementation can't detect errors + // synchronously + #[test] + #[cfg(any(target_os = "freebsd", target_os = "macos"))] + fn error() { + let wbuf = "CDEF".to_string().into_bytes(); + let mut aiow = Box::pin(AioWrite::new( + 666, // An invalid file descriptor + 0, //offset + &wbuf, + 0, //priority + SigevNotify::SigevNone, + )); + aiow.as_mut().submit().expect_err("assertion failed"); + // Dropping the AioWrite at this point should not panic + } +} + +#[cfg(target_os = "freebsd")] +#[cfg(fbsd14)] +mod aio_writev { + use std::io::IoSlice; + + use super::*; + + #[test] + fn test_accessors() { + let wbuf0 = vec![0; 4]; + let wbuf1 = vec![0; 8]; + let wbufs = [IoSlice::new(&wbuf0), IoSlice::new(&wbuf1)]; + let aiocb = AioWritev::new( + 1001, + 2, //offset + &wbufs, + 42, //priority + SigevNotify::SigevSignal { + signal: Signal::SIGUSR2, + si_value: 99, + }, + ); + assert_eq!(1001, aiocb.fd()); + assert_eq!(2, aiocb.iovlen()); + assert_eq!(2, aiocb.offset()); + assert_eq!(42, aiocb.priority()); + let sev = aiocb.sigevent().sigevent(); + assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); + assert_eq!(99, sev.sigev_value.sival_ptr as i64); + } + + // Test a simple aio operation with no completion notification. We must + // poll for completion. + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn ok() { + const INITIAL: &[u8] = b"abcdef123456"; + let wbuf0 = b"BC"; + let wbuf1 = b"DEF"; + let wbufs = [IoSlice::new(wbuf0), IoSlice::new(wbuf1)]; + let wlen = wbuf0.len() + wbuf1.len(); + let mut rbuf = Vec::new(); + const EXPECT: &[u8] = b"aBCDEF123456"; + + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let mut aiow = Box::pin(AioWritev::new( + f.as_raw_fd(), + 1, + &wbufs, + 0, + SigevNotify::SigevNone, + )); + aiow.as_mut().submit().unwrap(); + + let err = poll_aio!(&mut aiow); + assert_eq!(err, Ok(())); + assert_eq!(aiow.as_mut().aio_return().unwrap(), wlen); + + f.rewind().unwrap(); + let len = f.read_to_end(&mut rbuf).unwrap(); + assert_eq!(len, EXPECT.len()); + assert_eq!(rbuf, EXPECT); + } +} + +// Test an aio operation with completion delivered by a signal +#[test] +#[cfg_attr( + any( + all(target_env = "musl", target_arch = "x86_64"), + target_arch = "mips", + target_arch = "mips64" + ), + ignore +)] +fn sigev_signal() { + let _m = crate::SIGNAL_MTX.lock(); + let sa = SigAction::new( + SigHandler::Handler(sigfunc), + SaFlags::SA_RESETHAND, + SigSet::empty(), + ); + SIGNALED.store(false, Ordering::Relaxed); + unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); + + const INITIAL: &[u8] = b"abcdef123456"; + const WBUF: &[u8] = b"CDEF"; + let mut rbuf = Vec::new(); + const EXPECT: &[u8] = b"abCDEF123456"; + + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let mut aiow = Box::pin(AioWrite::new( + f.as_raw_fd(), + 2, //offset + WBUF, + 0, //priority + SigevNotify::SigevSignal { + signal: Signal::SIGUSR2, + si_value: 0, //TODO: validate in sigfunc + }, + )); + aiow.as_mut().submit().unwrap(); + while !SIGNALED.load(Ordering::Relaxed) { + thread::sleep(time::Duration::from_millis(10)); + } + + assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); + f.rewind().unwrap(); + let len = f.read_to_end(&mut rbuf).unwrap(); + assert_eq!(len, EXPECT.len()); + assert_eq!(rbuf, EXPECT); +} + +// Tests using aio_cancel_all for all outstanding IOs. +#[test] +#[cfg_attr(target_env = "musl", ignore)] +fn test_aio_cancel_all() { + let wbuf: &[u8] = b"CDEF"; + + let f = tempfile().unwrap(); + let mut aiocb = Box::pin(AioWrite::new( + f.as_raw_fd(), + 0, //offset + wbuf, + 0, //priority + SigevNotify::SigevNone, + )); + aiocb.as_mut().submit().unwrap(); + let err = aiocb.as_mut().error(); + assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); + + aio_cancel_all(f.as_raw_fd()).unwrap(); + + // Wait for aiocb to complete, but don't care whether it succeeded + let _ = poll_aio!(&mut aiocb); + let _ = aiocb.as_mut().aio_return(); +} + +#[test] +// On Cirrus on Linux, this test fails due to a glibc bug. +// https://github.com/nix-rust/nix/issues/1099 +#[cfg_attr(target_os = "linux", ignore)] +// On Cirrus, aio_suspend is failing with EINVAL +// https://github.com/nix-rust/nix/issues/1361 +#[cfg_attr(target_os = "macos", ignore)] +fn test_aio_suspend() { + const INITIAL: &[u8] = b"abcdef123456"; + const WBUF: &[u8] = b"CDEFG"; + let timeout = TimeSpec::seconds(10); + let mut rbuf = vec![0; 4]; + let rlen = rbuf.len(); + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + + let mut wcb = Box::pin(AioWrite::new( + f.as_raw_fd(), + 2, //offset + WBUF, + 0, //priority + SigevNotify::SigevNone, + )); + + let mut rcb = Box::pin(AioRead::new( + f.as_raw_fd(), + 8, //offset + &mut rbuf, + 0, //priority + SigevNotify::SigevNone, + )); + wcb.as_mut().submit().unwrap(); + rcb.as_mut().submit().unwrap(); + loop { + { + let cbbuf = [ + &*wcb as &dyn AsRef, + &*rcb as &dyn AsRef, + ]; + let r = aio_suspend(&cbbuf[..], Some(timeout)); + match r { + Err(Errno::EINTR) => continue, + Err(e) => panic!("aio_suspend returned {:?}", e), + Ok(_) => (), + }; + } + if rcb.as_mut().error() != Err(Errno::EINPROGRESS) + && wcb.as_mut().error() != Err(Errno::EINPROGRESS) + { + break; + } + } + + assert_eq!(wcb.as_mut().aio_return().unwrap(), WBUF.len()); + assert_eq!(rcb.as_mut().aio_return().unwrap(), rlen); +} diff --git a/vendor/nix-0.26.2/test/sys/test_aio_drop.rs b/vendor/nix-0.26.2/test/sys/test_aio_drop.rs new file mode 100644 index 0000000000000..bbe6623fd77a0 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_aio_drop.rs @@ -0,0 +1,35 @@ +// Test dropping an AioCb that hasn't yet finished. +// This must happen in its own process, because on OSX this test seems to hose +// the AIO subsystem and causes subsequent tests to fail +#[test] +#[should_panic(expected = "Dropped an in-progress AioCb")] +#[cfg(all( + not(target_env = "musl"), + not(target_env = "uclibc"), + any( + target_os = "linux", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd" + ) +))] +fn test_drop() { + use nix::sys::aio::*; + use nix::sys::signal::*; + use std::os::unix::io::AsRawFd; + use tempfile::tempfile; + + const WBUF: &[u8] = b"CDEF"; + + let f = tempfile().unwrap(); + f.set_len(6).unwrap(); + let mut aiocb = Box::pin(AioWrite::new( + f.as_raw_fd(), + 2, //offset + WBUF, + 0, //priority + SigevNotify::SigevNone, + )); + aiocb.as_mut().submit().unwrap(); +} diff --git a/vendor/nix-0.26.2/test/sys/test_epoll.rs b/vendor/nix-0.26.2/test/sys/test_epoll.rs new file mode 100644 index 0000000000000..915691595c4f6 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_epoll.rs @@ -0,0 +1,24 @@ +use nix::errno::Errno; +use nix::sys::epoll::{epoll_create1, epoll_ctl}; +use nix::sys::epoll::{EpollCreateFlags, EpollEvent, EpollFlags, EpollOp}; + +#[test] +pub fn test_epoll_errno() { + let efd = epoll_create1(EpollCreateFlags::empty()).unwrap(); + let result = epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None); + result.expect_err("assertion failed"); + assert_eq!(result.unwrap_err(), Errno::ENOENT); + + let result = epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, None); + result.expect_err("assertion failed"); + assert_eq!(result.unwrap_err(), Errno::EINVAL); +} + +#[test] +pub fn test_epoll_ctl() { + let efd = epoll_create1(EpollCreateFlags::empty()).unwrap(); + let mut event = + EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1); + epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, &mut event).unwrap(); + epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None).unwrap(); +} diff --git a/vendor/nix-0.26.2/test/sys/test_inotify.rs b/vendor/nix-0.26.2/test/sys/test_inotify.rs new file mode 100644 index 0000000000000..bb5851a903c54 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_inotify.rs @@ -0,0 +1,65 @@ +use nix::errno::Errno; +use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify}; +use std::ffi::OsString; +use std::fs::{rename, File}; + +#[test] +pub fn test_inotify() { + let instance = Inotify::init(InitFlags::IN_NONBLOCK).unwrap(); + let tempdir = tempfile::tempdir().unwrap(); + + instance + .add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS) + .unwrap(); + + let events = instance.read_events(); + assert_eq!(events.unwrap_err(), Errno::EAGAIN); + + File::create(tempdir.path().join("test")).unwrap(); + + let events = instance.read_events().unwrap(); + assert_eq!(events[0].name, Some(OsString::from("test"))); +} + +#[test] +pub fn test_inotify_multi_events() { + let instance = Inotify::init(InitFlags::IN_NONBLOCK).unwrap(); + let tempdir = tempfile::tempdir().unwrap(); + + instance + .add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS) + .unwrap(); + + let events = instance.read_events(); + assert_eq!(events.unwrap_err(), Errno::EAGAIN); + + File::create(tempdir.path().join("test")).unwrap(); + rename(tempdir.path().join("test"), tempdir.path().join("test2")).unwrap(); + + // Now there should be 5 events in queue: + // - IN_CREATE on test + // - IN_OPEN on test + // - IN_CLOSE_WRITE on test + // - IN_MOVED_FROM on test with a cookie + // - IN_MOVED_TO on test2 with the same cookie + + let events = instance.read_events().unwrap(); + assert_eq!(events.len(), 5); + + assert_eq!(events[0].mask, AddWatchFlags::IN_CREATE); + assert_eq!(events[0].name, Some(OsString::from("test"))); + + assert_eq!(events[1].mask, AddWatchFlags::IN_OPEN); + assert_eq!(events[1].name, Some(OsString::from("test"))); + + assert_eq!(events[2].mask, AddWatchFlags::IN_CLOSE_WRITE); + assert_eq!(events[2].name, Some(OsString::from("test"))); + + assert_eq!(events[3].mask, AddWatchFlags::IN_MOVED_FROM); + assert_eq!(events[3].name, Some(OsString::from("test"))); + + assert_eq!(events[4].mask, AddWatchFlags::IN_MOVED_TO); + assert_eq!(events[4].name, Some(OsString::from("test2"))); + + assert_eq!(events[3].cookie, events[4].cookie); +} diff --git a/vendor/nix-0.26.2/test/sys/test_ioctl.rs b/vendor/nix-0.26.2/test/sys/test_ioctl.rs new file mode 100644 index 0000000000000..40f60cfdbcd50 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_ioctl.rs @@ -0,0 +1,376 @@ +#![allow(dead_code)] + +// Simple tests to ensure macro generated fns compile +ioctl_none_bad!(do_bad, 0x1234); +ioctl_read_bad!(do_bad_read, 0x1234, u16); +ioctl_write_int_bad!(do_bad_write_int, 0x1234); +ioctl_write_ptr_bad!(do_bad_write_ptr, 0x1234, u8); +ioctl_readwrite_bad!(do_bad_readwrite, 0x1234, u32); +ioctl_none!(do_none, 0, 0); +ioctl_read!(read_test, 0, 0, u32); +ioctl_write_int!(write_ptr_int, 0, 0); +ioctl_write_ptr!(write_ptr_u8, 0, 0, u8); +ioctl_write_ptr!(write_ptr_u32, 0, 0, u32); +ioctl_write_ptr!(write_ptr_u64, 0, 0, u64); +ioctl_readwrite!(readwrite_test, 0, 0, u64); +ioctl_read_buf!(readbuf_test, 0, 0, u32); +const SPI_IOC_MAGIC: u8 = b'k'; +const SPI_IOC_MESSAGE: u8 = 0; +ioctl_write_buf!(writebuf_test_consts, SPI_IOC_MAGIC, SPI_IOC_MESSAGE, u8); +ioctl_write_buf!(writebuf_test_u8, 0, 0, u8); +ioctl_write_buf!(writebuf_test_u32, 0, 0, u32); +ioctl_write_buf!(writebuf_test_u64, 0, 0, u64); +ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32); + +// See C code for source of values for op calculations (does NOT work for mips/powerpc): +// https://gist.github.com/posborne/83ea6880770a1aef332e +// +// TODO: Need a way to compute these constants at test time. Using precomputed +// values is fragile and needs to be maintained. + +#[cfg(any(target_os = "linux", target_os = "android"))] +mod linux { + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + #[test] + fn test_op_none() { + if cfg!(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + assert_eq!(request_code_none!(b'q', 10) as u32, 0x2000_710A); + assert_eq!(request_code_none!(b'a', 255) as u32, 0x2000_61FF); + } else { + assert_eq!(request_code_none!(b'q', 10) as u32, 0x0000_710A); + assert_eq!(request_code_none!(b'a', 255) as u32, 0x0000_61FF); + } + } + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + #[test] + fn test_op_write() { + if cfg!(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x8001_7A0A); + assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x8200_7A0A); + } else { + assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x4001_7A0A); + assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x4200_7A0A); + } + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_write_64() { + if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) { + assert_eq!( + request_code_write!(b'z', 10, 1u64 << 32) as u32, + 0x8000_7A0A + ); + } else { + assert_eq!( + request_code_write!(b'z', 10, 1u64 << 32) as u32, + 0x4000_7A0A + ); + } + } + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + #[test] + fn test_op_read() { + if cfg!(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x4001_7A0A); + assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x4200_7A0A); + } else { + assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x8001_7A0A); + assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x8200_7A0A); + } + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_read_64() { + if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) { + assert_eq!( + request_code_read!(b'z', 10, 1u64 << 32) as u32, + 0x4000_7A0A + ); + } else { + assert_eq!( + request_code_read!(b'z', 10, 1u64 << 32) as u32, + 0x8000_7A0A + ); + } + } + + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + #[test] + fn test_op_read_write() { + assert_eq!(request_code_readwrite!(b'z', 10, 1) as u32, 0xC001_7A0A); + assert_eq!(request_code_readwrite!(b'z', 10, 512) as u32, 0xC200_7A0A); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_read_write_64() { + assert_eq!( + request_code_readwrite!(b'z', 10, 1u64 << 32) as u32, + 0xC000_7A0A + ); + } +} + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] +mod bsd { + #[test] + fn test_op_none() { + assert_eq!(request_code_none!(b'q', 10), 0x2000_710A); + assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF); + } + + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[test] + fn test_op_write_int() { + assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604); + assert_eq!(request_code_write_int!(b'p', 2), 0x2004_7002); + } + + #[test] + fn test_op_write() { + assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A); + assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_write_64() { + assert_eq!(request_code_write!(b'z', 10, 1u64 << 32), 0x8000_7A0A); + } + + #[test] + fn test_op_read() { + assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A); + assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_read_64() { + assert_eq!(request_code_read!(b'z', 10, 1u64 << 32), 0x4000_7A0A); + } + + #[test] + fn test_op_read_write() { + assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A); + assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_read_write_64() { + assert_eq!(request_code_readwrite!(b'z', 10, 1u64 << 32), 0xC000_7A0A); + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +mod linux_ioctls { + use std::mem; + use std::os::unix::io::AsRawFd; + + use libc::{termios, TCGETS, TCSBRK, TCSETS, TIOCNXCL}; + use tempfile::tempfile; + + use nix::errno::Errno; + + ioctl_none_bad!(tiocnxcl, TIOCNXCL); + #[test] + fn test_ioctl_none_bad() { + let file = tempfile().unwrap(); + let res = unsafe { tiocnxcl(file.as_raw_fd()) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } + + ioctl_read_bad!(tcgets, TCGETS, termios); + #[test] + fn test_ioctl_read_bad() { + let file = tempfile().unwrap(); + let mut termios = unsafe { mem::zeroed() }; + let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } + + ioctl_write_int_bad!(tcsbrk, TCSBRK); + #[test] + fn test_ioctl_write_int_bad() { + let file = tempfile().unwrap(); + let res = unsafe { tcsbrk(file.as_raw_fd(), 0) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } + + ioctl_write_ptr_bad!(tcsets, TCSETS, termios); + #[test] + fn test_ioctl_write_ptr_bad() { + let file = tempfile().unwrap(); + let termios: termios = unsafe { mem::zeroed() }; + let res = unsafe { tcsets(file.as_raw_fd(), &termios) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } + + // FIXME: Find a suitable example for `ioctl_readwrite_bad` + + // From linux/videodev2.h + ioctl_none!(log_status, b'V', 70); + #[test] + fn test_ioctl_none() { + let file = tempfile().unwrap(); + let res = unsafe { log_status(file.as_raw_fd()) }; + assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + } + + #[repr(C)] + pub struct v4l2_audio { + index: u32, + name: [u8; 32], + capability: u32, + mode: u32, + reserved: [u32; 2], + } + + // From linux/videodev2.h + ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio); + #[test] + fn test_ioctl_write_ptr() { + let file = tempfile().unwrap(); + let data: v4l2_audio = unsafe { mem::zeroed() }; + let res = unsafe { s_audio(file.as_raw_fd(), &data) }; + assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + } + + // From linux/net/bluetooth/hci_sock.h + const HCI_IOC_MAGIC: u8 = b'H'; + const HCI_IOC_HCIDEVUP: u8 = 201; + ioctl_write_int!(hcidevup, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP); + #[test] + fn test_ioctl_write_int() { + let file = tempfile().unwrap(); + let res = unsafe { hcidevup(file.as_raw_fd(), 0) }; + assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + } + + // From linux/videodev2.h + ioctl_read!(g_audio, b'V', 33, v4l2_audio); + #[test] + fn test_ioctl_read() { + let file = tempfile().unwrap(); + let mut data: v4l2_audio = unsafe { mem::zeroed() }; + let res = unsafe { g_audio(file.as_raw_fd(), &mut data) }; + assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + } + + // From linux/videodev2.h + ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio); + #[test] + fn test_ioctl_readwrite() { + let file = tempfile().unwrap(); + let mut data: v4l2_audio = unsafe { mem::zeroed() }; + let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) }; + assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + } + + // FIXME: Find a suitable example for `ioctl_read_buf`. + + #[repr(C)] + pub struct spi_ioc_transfer { + tx_buf: u64, + rx_buf: u64, + len: u32, + speed_hz: u32, + delay_usecs: u16, + bits_per_word: u8, + cs_change: u8, + tx_nbits: u8, + rx_nbits: u8, + pad: u16, + } + + // From linux/spi/spidev.h + ioctl_write_buf!( + spi_ioc_message, + super::SPI_IOC_MAGIC, + super::SPI_IOC_MESSAGE, + spi_ioc_transfer + ); + #[test] + fn test_ioctl_write_buf() { + let file = tempfile().unwrap(); + let data: [spi_ioc_transfer; 4] = unsafe { mem::zeroed() }; + let res = unsafe { spi_ioc_message(file.as_raw_fd(), &data[..]) }; + assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); + } + + // FIXME: Find a suitable example for `ioctl_readwrite_buf`. +} + +#[cfg(target_os = "freebsd")] +mod freebsd_ioctls { + use std::mem; + use std::os::unix::io::AsRawFd; + + use libc::termios; + use tempfile::tempfile; + + use nix::errno::Errno; + + // From sys/sys/ttycom.h + const TTY_IOC_MAGIC: u8 = b't'; + const TTY_IOC_TYPE_NXCL: u8 = 14; + const TTY_IOC_TYPE_GETA: u8 = 19; + const TTY_IOC_TYPE_SETA: u8 = 20; + + ioctl_none!(tiocnxcl, TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL); + #[test] + fn test_ioctl_none() { + let file = tempfile().unwrap(); + let res = unsafe { tiocnxcl(file.as_raw_fd()) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } + + ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios); + #[test] + fn test_ioctl_read() { + let file = tempfile().unwrap(); + let mut termios = unsafe { mem::zeroed() }; + let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } + + ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios); + #[test] + fn test_ioctl_write_ptr() { + let file = tempfile().unwrap(); + let termios: termios = unsafe { mem::zeroed() }; + let res = unsafe { tiocseta(file.as_raw_fd(), &termios) }; + assert_eq!(res, Err(Errno::ENOTTY)); + } +} diff --git a/vendor/nix-0.26.2/test/sys/test_mman.rs b/vendor/nix-0.26.2/test/sys/test_mman.rs new file mode 100644 index 0000000000000..e748427bcd439 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_mman.rs @@ -0,0 +1,122 @@ +use nix::sys::mman::{mmap, MapFlags, ProtFlags}; +use std::num::NonZeroUsize; + +#[test] +fn test_mmap_anonymous() { + unsafe { + let ptr = mmap( + None, + NonZeroUsize::new(1).unwrap(), + ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, + MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, + -1, + 0, + ) + .unwrap() as *mut u8; + assert_eq!(*ptr, 0x00u8); + *ptr = 0xffu8; + assert_eq!(*ptr, 0xffu8); + } +} + +#[test] +#[cfg(any(target_os = "linux", target_os = "netbsd"))] +fn test_mremap_grow() { + use nix::libc::{c_void, size_t}; + use nix::sys::mman::{mremap, MRemapFlags}; + + const ONE_K: size_t = 1024; + let one_k_non_zero = NonZeroUsize::new(ONE_K).unwrap(); + + let slice: &mut [u8] = unsafe { + let mem = mmap( + None, + one_k_non_zero, + ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, + MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, + -1, + 0, + ) + .unwrap(); + std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) + }; + assert_eq!(slice[ONE_K - 1], 0x00); + slice[ONE_K - 1] = 0xFF; + assert_eq!(slice[ONE_K - 1], 0xFF); + + let slice: &mut [u8] = unsafe { + #[cfg(target_os = "linux")] + let mem = mremap( + slice.as_mut_ptr() as *mut c_void, + ONE_K, + 10 * ONE_K, + MRemapFlags::MREMAP_MAYMOVE, + None, + ) + .unwrap(); + #[cfg(target_os = "netbsd")] + let mem = mremap( + slice.as_mut_ptr() as *mut c_void, + ONE_K, + 10 * ONE_K, + MRemapFlags::MAP_REMAPDUP, + None, + ) + .unwrap(); + std::slice::from_raw_parts_mut(mem as *mut u8, 10 * ONE_K) + }; + + // The first KB should still have the old data in it. + assert_eq!(slice[ONE_K - 1], 0xFF); + + // The additional range should be zero-init'd and accessible. + assert_eq!(slice[10 * ONE_K - 1], 0x00); + slice[10 * ONE_K - 1] = 0xFF; + assert_eq!(slice[10 * ONE_K - 1], 0xFF); +} + +#[test] +#[cfg(any(target_os = "linux", target_os = "netbsd"))] +// Segfaults for unknown reasons under QEMU for 32-bit targets +#[cfg_attr(all(target_pointer_width = "32", qemu), ignore)] +fn test_mremap_shrink() { + use nix::libc::{c_void, size_t}; + use nix::sys::mman::{mremap, MRemapFlags}; + use std::num::NonZeroUsize; + + const ONE_K: size_t = 1024; + let ten_one_k = NonZeroUsize::new(10 * ONE_K).unwrap(); + let slice: &mut [u8] = unsafe { + let mem = mmap( + None, + ten_one_k, + ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, + MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, + -1, + 0, + ) + .unwrap(); + std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) + }; + assert_eq!(slice[ONE_K - 1], 0x00); + slice[ONE_K - 1] = 0xFF; + assert_eq!(slice[ONE_K - 1], 0xFF); + + let slice: &mut [u8] = unsafe { + let mem = mremap( + slice.as_mut_ptr() as *mut c_void, + ten_one_k.into(), + ONE_K, + MRemapFlags::empty(), + None, + ) + .unwrap(); + // Since we didn't supply MREMAP_MAYMOVE, the address should be the + // same. + assert_eq!(mem, slice.as_mut_ptr() as *mut c_void); + std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) + }; + + // The first KB should still be accessible and have the old data in it. + assert_eq!(slice[ONE_K - 1], 0xFF); +} diff --git a/vendor/nix-0.26.2/test/sys/test_pthread.rs b/vendor/nix-0.26.2/test/sys/test_pthread.rs new file mode 100644 index 0000000000000..ce048bae6019a --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_pthread.rs @@ -0,0 +1,22 @@ +use nix::sys::pthread::*; + +#[cfg(any(target_env = "musl", target_os = "redox"))] +#[test] +fn test_pthread_self() { + let tid = pthread_self(); + assert!(!tid.is_null()); +} + +#[cfg(not(any(target_env = "musl", target_os = "redox")))] +#[test] +fn test_pthread_self() { + let tid = pthread_self(); + assert_ne!(tid, 0); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_pthread_kill_none() { + pthread_kill(pthread_self(), None) + .expect("Should be able to send signal to my thread."); +} diff --git a/vendor/nix-0.26.2/test/sys/test_ptrace.rs b/vendor/nix-0.26.2/test/sys/test_ptrace.rs new file mode 100644 index 0000000000000..530560fe175d8 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_ptrace.rs @@ -0,0 +1,275 @@ +#[cfg(all( + target_os = "linux", + any(target_arch = "x86_64", target_arch = "x86"), + target_env = "gnu" +))] +use memoffset::offset_of; +use nix::errno::Errno; +use nix::sys::ptrace; +#[cfg(any(target_os = "android", target_os = "linux"))] +use nix::sys::ptrace::Options; +use nix::unistd::getpid; + +#[cfg(any(target_os = "android", target_os = "linux"))] +use std::mem; + +use crate::*; + +#[test] +fn test_ptrace() { + // Just make sure ptrace can be called at all, for now. + // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS + require_capability!("test_ptrace", CAP_SYS_PTRACE); + let err = ptrace::attach(getpid()).unwrap_err(); + assert!( + err == Errno::EPERM || err == Errno::EINVAL || err == Errno::ENOSYS + ); +} + +// Just make sure ptrace_setoptions can be called at all, for now. +#[test] +#[cfg(any(target_os = "android", target_os = "linux"))] +fn test_ptrace_setoptions() { + require_capability!("test_ptrace_setoptions", CAP_SYS_PTRACE); + let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD) + .unwrap_err(); + assert_ne!(err, Errno::EOPNOTSUPP); +} + +// Just make sure ptrace_getevent can be called at all, for now. +#[test] +#[cfg(any(target_os = "android", target_os = "linux"))] +fn test_ptrace_getevent() { + require_capability!("test_ptrace_getevent", CAP_SYS_PTRACE); + let err = ptrace::getevent(getpid()).unwrap_err(); + assert_ne!(err, Errno::EOPNOTSUPP); +} + +// Just make sure ptrace_getsiginfo can be called at all, for now. +#[test] +#[cfg(any(target_os = "android", target_os = "linux"))] +fn test_ptrace_getsiginfo() { + require_capability!("test_ptrace_getsiginfo", CAP_SYS_PTRACE); + if let Err(Errno::EOPNOTSUPP) = ptrace::getsiginfo(getpid()) { + panic!("ptrace_getsiginfo returns Errno::EOPNOTSUPP!"); + } +} + +// Just make sure ptrace_setsiginfo can be called at all, for now. +#[test] +#[cfg(any(target_os = "android", target_os = "linux"))] +fn test_ptrace_setsiginfo() { + require_capability!("test_ptrace_setsiginfo", CAP_SYS_PTRACE); + let siginfo = unsafe { mem::zeroed() }; + if let Err(Errno::EOPNOTSUPP) = ptrace::setsiginfo(getpid(), &siginfo) { + panic!("ptrace_setsiginfo returns Errno::EOPNOTSUPP!"); + } +} + +#[test] +fn test_ptrace_cont() { + use nix::sys::ptrace; + use nix::sys::signal::{raise, Signal}; + use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus}; + use nix::unistd::fork; + use nix::unistd::ForkResult::*; + + require_capability!("test_ptrace_cont", CAP_SYS_PTRACE); + + let _m = crate::FORK_MTX.lock(); + + // FIXME: qemu-user doesn't implement ptrace on all architectures + // and returns ENOSYS in this case. + // We (ab)use this behavior to detect the affected platforms + // and skip the test then. + // On valid platforms the ptrace call should return Errno::EPERM, this + // is already tested by `test_ptrace`. + let err = ptrace::attach(getpid()).unwrap_err(); + if err == Errno::ENOSYS { + return; + } + + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => { + ptrace::traceme().unwrap(); + // As recommended by ptrace(2), raise SIGTRAP to pause the child + // until the parent is ready to continue + loop { + raise(Signal::SIGTRAP).unwrap(); + } + } + Parent { child } => { + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)) + ); + ptrace::cont(child, None).unwrap(); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)) + ); + ptrace::cont(child, Some(Signal::SIGKILL)).unwrap(); + match waitpid(child, None) { + Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) + if pid == child => + { + // FIXME It's been observed on some systems (apple) the + // tracee may not be killed but remain as a zombie process + // affecting other wait based tests. Add an extra kill just + // to make sure there are no zombies. + let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); + while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { + let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); + } + } + _ => panic!("The process should have been killed"), + } + } + } +} + +#[cfg(target_os = "linux")] +#[test] +fn test_ptrace_interrupt() { + use nix::sys::ptrace; + use nix::sys::signal::Signal; + use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus}; + use nix::unistd::fork; + use nix::unistd::ForkResult::*; + use std::thread::sleep; + use std::time::Duration; + + require_capability!("test_ptrace_interrupt", CAP_SYS_PTRACE); + + let _m = crate::FORK_MTX.lock(); + + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => loop { + sleep(Duration::from_millis(1000)); + }, + Parent { child } => { + ptrace::seize(child, ptrace::Options::PTRACE_O_TRACESYSGOOD) + .unwrap(); + ptrace::interrupt(child).unwrap(); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::PtraceEvent(child, Signal::SIGTRAP, 128)) + ); + ptrace::syscall(child, None).unwrap(); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::PtraceSyscall(child)) + ); + ptrace::detach(child, Some(Signal::SIGKILL)).unwrap(); + match waitpid(child, None) { + Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) + if pid == child => + { + let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); + while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { + let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); + } + } + _ => panic!("The process should have been killed"), + } + } + } +} + +// ptrace::{setoptions, getregs} are only available in these platforms +#[cfg(all( + target_os = "linux", + any(target_arch = "x86_64", target_arch = "x86"), + target_env = "gnu" +))] +#[test] +fn test_ptrace_syscall() { + use nix::sys::ptrace; + use nix::sys::signal::kill; + use nix::sys::signal::Signal; + use nix::sys::wait::{waitpid, WaitStatus}; + use nix::unistd::fork; + use nix::unistd::getpid; + use nix::unistd::ForkResult::*; + + require_capability!("test_ptrace_syscall", CAP_SYS_PTRACE); + + let _m = crate::FORK_MTX.lock(); + + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => { + ptrace::traceme().unwrap(); + // first sigstop until parent is ready to continue + let pid = getpid(); + kill(pid, Signal::SIGSTOP).unwrap(); + kill(pid, Signal::SIGTERM).unwrap(); + unsafe { + ::libc::_exit(0); + } + } + + Parent { child } => { + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Stopped(child, Signal::SIGSTOP)) + ); + + // set this option to recognize syscall-stops + ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD) + .unwrap(); + + #[cfg(target_arch = "x86_64")] + let get_syscall_id = + || ptrace::getregs(child).unwrap().orig_rax as libc::c_long; + + #[cfg(target_arch = "x86")] + let get_syscall_id = + || ptrace::getregs(child).unwrap().orig_eax as libc::c_long; + + // this duplicates `get_syscall_id` for the purpose of testing `ptrace::read_user`. + #[cfg(target_arch = "x86_64")] + let rax_offset = offset_of!(libc::user_regs_struct, orig_rax); + #[cfg(target_arch = "x86")] + let rax_offset = offset_of!(libc::user_regs_struct, orig_eax); + + let get_syscall_from_user_area = || { + // Find the offset of `user.regs.rax` (or `user.regs.eax` for x86) + let rax_offset = offset_of!(libc::user, regs) + rax_offset; + ptrace::read_user(child, rax_offset as _).unwrap() + as libc::c_long + }; + + // kill entry + ptrace::syscall(child, None).unwrap(); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::PtraceSyscall(child)) + ); + assert_eq!(get_syscall_id(), ::libc::SYS_kill); + assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill); + + // kill exit + ptrace::syscall(child, None).unwrap(); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::PtraceSyscall(child)) + ); + assert_eq!(get_syscall_id(), ::libc::SYS_kill); + assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill); + + // receive signal + ptrace::syscall(child, None).unwrap(); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Stopped(child, Signal::SIGTERM)) + ); + + // inject signal + ptrace::syscall(child, Signal::SIGTERM).unwrap(); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false)) + ); + } + } +} diff --git a/vendor/nix-0.26.2/test/sys/test_select.rs b/vendor/nix-0.26.2/test/sys/test_select.rs new file mode 100644 index 0000000000000..40bda4d90acca --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_select.rs @@ -0,0 +1,81 @@ +use nix::sys::select::*; +use nix::sys::signal::SigSet; +use nix::sys::time::{TimeSpec, TimeValLike}; +use nix::unistd::{pipe, write}; + +#[test] +pub fn test_pselect() { + let _mtx = crate::SIGNAL_MTX.lock(); + + let (r1, w1) = pipe().unwrap(); + write(w1, b"hi!").unwrap(); + let (r2, _w2) = pipe().unwrap(); + + let mut fd_set = FdSet::new(); + fd_set.insert(r1); + fd_set.insert(r2); + + let timeout = TimeSpec::seconds(10); + let sigmask = SigSet::empty(); + assert_eq!( + 1, + pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap() + ); + assert!(fd_set.contains(r1)); + assert!(!fd_set.contains(r2)); +} + +#[test] +pub fn test_pselect_nfds2() { + let (r1, w1) = pipe().unwrap(); + write(w1, b"hi!").unwrap(); + let (r2, _w2) = pipe().unwrap(); + + let mut fd_set = FdSet::new(); + fd_set.insert(r1); + fd_set.insert(r2); + + let timeout = TimeSpec::seconds(10); + assert_eq!( + 1, + pselect( + ::std::cmp::max(r1, r2) + 1, + &mut fd_set, + None, + None, + &timeout, + None + ) + .unwrap() + ); + assert!(fd_set.contains(r1)); + assert!(!fd_set.contains(r2)); +} + +macro_rules! generate_fdset_bad_fd_tests { + ($fd:expr, $($method:ident),* $(,)?) => { + $( + #[test] + #[should_panic] + fn $method() { + FdSet::new().$method($fd); + } + )* + } +} + +mod test_fdset_negative_fd { + use super::*; + generate_fdset_bad_fd_tests!(-1, insert, remove, contains); +} + +mod test_fdset_too_large_fd { + use super::*; + use std::convert::TryInto; + generate_fdset_bad_fd_tests!( + FD_SETSIZE.try_into().unwrap(), + insert, + remove, + contains, + ); +} diff --git a/vendor/nix-0.26.2/test/sys/test_signal.rs b/vendor/nix-0.26.2/test/sys/test_signal.rs new file mode 100644 index 0000000000000..3ad14f40c7ca9 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_signal.rs @@ -0,0 +1,147 @@ +#[cfg(not(target_os = "redox"))] +use nix::errno::Errno; +use nix::sys::signal::*; +use nix::unistd::*; +use std::convert::TryFrom; +use std::sync::atomic::{AtomicBool, Ordering}; + +#[test] +fn test_kill_none() { + kill(getpid(), None).expect("Should be able to send signal to myself."); +} + +#[test] +#[cfg(not(target_os = "fuchsia"))] +fn test_killpg_none() { + killpg(getpgrp(), None) + .expect("Should be able to send signal to my process group."); +} + +#[test] +fn test_old_sigaction_flags() { + let _m = crate::SIGNAL_MTX.lock(); + + extern "C" fn handler(_: ::libc::c_int) {} + let act = SigAction::new( + SigHandler::Handler(handler), + SaFlags::empty(), + SigSet::empty(), + ); + let oact = unsafe { sigaction(SIGINT, &act) }.unwrap(); + let _flags = oact.flags(); + let oact = unsafe { sigaction(SIGINT, &act) }.unwrap(); + let _flags = oact.flags(); +} + +#[test] +fn test_sigprocmask_noop() { + sigprocmask(SigmaskHow::SIG_BLOCK, None, None) + .expect("this should be an effective noop"); +} + +#[test] +fn test_sigprocmask() { + let _m = crate::SIGNAL_MTX.lock(); + + // This needs to be a signal that rust doesn't use in the test harness. + const SIGNAL: Signal = Signal::SIGCHLD; + + let mut old_signal_set = SigSet::empty(); + sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) + .expect("expect to be able to retrieve old signals"); + + // Make sure the old set doesn't contain the signal, otherwise the following + // test don't make sense. + assert!( + !old_signal_set.contains(SIGNAL), + "the {:?} signal is already blocked, please change to a \ + different one", + SIGNAL + ); + + // Now block the signal. + let mut signal_set = SigSet::empty(); + signal_set.add(SIGNAL); + sigprocmask(SigmaskHow::SIG_BLOCK, Some(&signal_set), None) + .expect("expect to be able to block signals"); + + // And test it again, to make sure the change was effective. + old_signal_set.clear(); + sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) + .expect("expect to be able to retrieve old signals"); + assert!( + old_signal_set.contains(SIGNAL), + "expected the {:?} to be blocked", + SIGNAL + ); + + // Reset the signal. + sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None) + .expect("expect to be able to block signals"); +} + +lazy_static! { + static ref SIGNALED: AtomicBool = AtomicBool::new(false); +} + +extern "C" fn test_sigaction_handler(signal: libc::c_int) { + let signal = Signal::try_from(signal).unwrap(); + SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); +} + +#[cfg(not(target_os = "redox"))] +extern "C" fn test_sigaction_action( + _: libc::c_int, + _: *mut libc::siginfo_t, + _: *mut libc::c_void, +) { +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_signal_sigaction() { + let _m = crate::SIGNAL_MTX.lock(); + + let action_handler = SigHandler::SigAction(test_sigaction_action); + assert_eq!( + unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), + Errno::ENOTSUP + ); +} + +#[test] +fn test_signal() { + let _m = crate::SIGNAL_MTX.lock(); + + unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); + raise(Signal::SIGINT).unwrap(); + assert_eq!( + unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), + SigHandler::SigIgn + ); + + let handler = SigHandler::Handler(test_sigaction_handler); + assert_eq!( + unsafe { signal(Signal::SIGINT, handler) }.unwrap(), + SigHandler::SigDfl + ); + raise(Signal::SIGINT).unwrap(); + assert!(SIGNALED.load(Ordering::Relaxed)); + + #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] + assert_eq!( + unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), + handler + ); + + // System V based OSes (e.g. illumos and Solaris) always resets the + // disposition to SIG_DFL prior to calling the signal handler + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + assert_eq!( + unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), + SigHandler::SigDfl + ); + + // Restore default signal handler + unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(); +} diff --git a/vendor/nix-0.26.2/test/sys/test_signalfd.rs b/vendor/nix-0.26.2/test/sys/test_signalfd.rs new file mode 100644 index 0000000000000..87153c957204c --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_signalfd.rs @@ -0,0 +1,27 @@ +use std::convert::TryFrom; + +#[test] +fn test_signalfd() { + use nix::sys::signal::{self, raise, SigSet, Signal}; + use nix::sys::signalfd::SignalFd; + + // Grab the mutex for altering signals so we don't interfere with other tests. + let _m = crate::SIGNAL_MTX.lock(); + + // Block the SIGUSR1 signal from automatic processing for this thread + let mut mask = SigSet::empty(); + mask.add(signal::SIGUSR1); + mask.thread_block().unwrap(); + + let mut fd = SignalFd::new(&mask).unwrap(); + + // Send a SIGUSR1 signal to the current process. Note that this uses `raise` instead of `kill` + // because `kill` with `getpid` isn't correct during multi-threaded execution like during a + // cargo test session. Instead use `raise` which does the correct thing by default. + raise(signal::SIGUSR1).expect("Error: raise(SIGUSR1) failed"); + + // And now catch that same signal. + let res = fd.read_signal().unwrap().unwrap(); + let signo = Signal::try_from(res.ssi_signo as i32).unwrap(); + assert_eq!(signo, signal::SIGUSR1); +} diff --git a/vendor/nix-0.26.2/test/sys/test_socket.rs b/vendor/nix-0.26.2/test/sys/test_socket.rs new file mode 100644 index 0000000000000..5adc77ed6b5a6 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_socket.rs @@ -0,0 +1,2628 @@ +#[cfg(any(target_os = "linux", target_os = "android"))] +use crate::*; +use libc::{c_char, sockaddr_storage}; +#[allow(deprecated)] +use nix::sys::socket::InetAddr; +use nix::sys::socket::{ + getsockname, sockaddr, sockaddr_in6, AddressFamily, UnixAddr, +}; +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; +use std::mem::{self, MaybeUninit}; +use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::os::unix::io::RawFd; +use std::path::Path; +use std::slice; +use std::str::FromStr; + +#[allow(deprecated)] +#[test] +pub fn test_inetv4_addr_to_sock_addr() { + let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); + let addr = InetAddr::from_std(&actual); + + match addr { + InetAddr::V4(addr) => { + let ip: u32 = 0x7f00_0001; + let port: u16 = 3000; + let saddr = addr.sin_addr.s_addr; + + assert_eq!(saddr, ip.to_be()); + assert_eq!(addr.sin_port, port.to_be()); + } + _ => panic!("nope"), + } + + assert_eq!(addr.to_string(), "127.0.0.1:3000"); + + let inet = addr.to_std(); + assert_eq!(actual, inet); +} + +#[allow(deprecated)] +#[test] +pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() { + use nix::sys::socket::{sockaddr_storage_to_addr, SockAddr}; + + let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); + let addr = InetAddr::from_std(&actual); + let sockaddr = SockAddr::new_inet(addr); + + let (storage, ffi_size) = { + let mut storage = MaybeUninit::::zeroed(); + let storage_ptr = storage.as_mut_ptr().cast::(); + let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair(); + assert_eq!(mem::size_of::(), ffi_size as usize); + unsafe { + storage_ptr.copy_from_nonoverlapping(ffi_ptr as *const sockaddr, 1); + (storage.assume_init(), ffi_size) + } + }; + + let from_storage = + sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); + assert_eq!(from_storage, sockaddr); + let from_storage = + sockaddr_storage_to_addr(&storage, mem::size_of::()) + .unwrap(); + assert_eq!(from_storage, sockaddr); +} + +#[cfg(any(target_os = "linux"))] +#[cfg_attr(qemu, ignore)] +#[test] +pub fn test_timestamping() { + use nix::sys::socket::{ + recvmsg, sendmsg, setsockopt, socket, sockopt::Timestamping, + ControlMessageOwned, MsgFlags, SockFlag, SockType, SockaddrIn, + TimestampingFlag, + }; + use std::io::{IoSlice, IoSliceMut}; + + let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); + + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + nix::sys::socket::bind(rsock, &sock_addr).unwrap(); + + setsockopt(rsock, Timestamping, &TimestampingFlag::all()).unwrap(); + + let sbuf = [0u8; 2048]; + let mut rbuf = [0u8; 2048]; + let flags = MsgFlags::empty(); + let iov1 = [IoSlice::new(&sbuf)]; + let mut iov2 = [IoSliceMut::new(&mut rbuf)]; + + let mut cmsg = cmsg_space!(nix::sys::socket::Timestamps); + sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap(); + let recv = recvmsg::<()>(rsock, &mut iov2, Some(&mut cmsg), flags).unwrap(); + + let mut ts = None; + for c in recv.cmsgs() { + if let ControlMessageOwned::ScmTimestampsns(timestamps) = c { + ts = Some(timestamps.system); + } + } + let ts = ts.expect("ScmTimestampns is present"); + let sys_time = + ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_REALTIME) + .unwrap(); + let diff = if ts > sys_time { + ts - sys_time + } else { + sys_time - ts + }; + assert!(std::time::Duration::from(diff).as_secs() < 60); +} + +#[allow(deprecated)] +#[test] +pub fn test_inetv6_addr_roundtrip_sockaddr_storage_to_addr() { + use nix::sys::socket::{sockaddr_storage_to_addr, SockAddr}; + + let port: u16 = 3000; + let flowinfo: u32 = 1; + let scope_id: u32 = 2; + let ip: Ipv6Addr = "fe80::1".parse().unwrap(); + + let actual = + SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id)); + let addr = InetAddr::from_std(&actual); + let sockaddr = SockAddr::new_inet(addr); + + let (storage, ffi_size) = { + let mut storage = MaybeUninit::::zeroed(); + let storage_ptr = storage.as_mut_ptr().cast::(); + let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair(); + assert_eq!(mem::size_of::(), ffi_size as usize); + unsafe { + storage_ptr.copy_from_nonoverlapping( + (ffi_ptr as *const sockaddr).cast::(), + 1, + ); + (storage.assume_init(), ffi_size) + } + }; + + let from_storage = + sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); + assert_eq!(from_storage, sockaddr); + let from_storage = + sockaddr_storage_to_addr(&storage, mem::size_of::()) + .unwrap(); + assert_eq!(from_storage, sockaddr); +} + +#[test] +pub fn test_path_to_sock_addr() { + let path = "/foo/bar"; + let actual = Path::new(path); + let addr = UnixAddr::new(actual).unwrap(); + + let expect: &[c_char] = unsafe { + slice::from_raw_parts(path.as_ptr() as *const c_char, path.len()) + }; + assert_eq!(unsafe { &(*addr.as_ptr()).sun_path[..8] }, expect); + + assert_eq!(addr.path(), Some(actual)); +} + +fn calculate_hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() +} + +#[test] +pub fn test_addr_equality_path() { + let path = "/foo/bar"; + let actual = Path::new(path); + let addr1 = UnixAddr::new(actual).unwrap(); + let mut addr2 = addr1; + + unsafe { (*addr2.as_mut_ptr()).sun_path[10] = 127 }; + + assert_eq!(addr1, addr2); + assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +pub fn test_abstract_sun_path_too_long() { + let name = String::from("nix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0testttttnix\0abstract\0test\0make\0sure\0this\0is\0long\0enough"); + let addr = UnixAddr::new_abstract(name.as_bytes()); + addr.expect_err("assertion failed"); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +pub fn test_addr_equality_abstract() { + let name = String::from("nix\0abstract\0test"); + let addr1 = UnixAddr::new_abstract(name.as_bytes()).unwrap(); + let mut addr2 = addr1; + + assert_eq!(addr1, addr2); + assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); + + unsafe { (*addr2.as_mut_ptr()).sun_path[17] = 127 }; + assert_ne!(addr1, addr2); + assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2)); +} + +// Test getting/setting abstract addresses (without unix socket creation) +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +pub fn test_abstract_uds_addr() { + let empty = String::new(); + let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap(); + let sun_path: [u8; 0] = []; + assert_eq!(addr.as_abstract(), Some(&sun_path[..])); + + let name = String::from("nix\0abstract\0test"); + let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); + let sun_path = [ + 110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, + 115, 116, + ]; + assert_eq!(addr.as_abstract(), Some(&sun_path[..])); + assert_eq!(addr.path(), None); + + // Internally, name is null-prefixed (abstract namespace) + assert_eq!(unsafe { (*addr.as_ptr()).sun_path[0] }, 0); +} + +// Test getting an unnamed address (without unix socket creation) +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +pub fn test_unnamed_uds_addr() { + use crate::nix::sys::socket::SockaddrLike; + + let addr = UnixAddr::new_unnamed(); + + assert!(addr.is_unnamed()); + assert_eq!(addr.len(), 2); + assert!(addr.path().is_none()); + assert_eq!(addr.path_len(), 0); + + assert!(addr.as_abstract().is_none()); +} + +#[test] +pub fn test_getsockname() { + use nix::sys::socket::bind; + use nix::sys::socket::{socket, AddressFamily, SockFlag, SockType}; + + let tempdir = tempfile::tempdir().unwrap(); + let sockname = tempdir.path().join("sock"); + let sock = socket( + AddressFamily::Unix, + SockType::Stream, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + let sockaddr = UnixAddr::new(&sockname).unwrap(); + bind(sock, &sockaddr).expect("bind failed"); + assert_eq!(sockaddr, getsockname(sock).expect("getsockname failed")); +} + +#[test] +pub fn test_socketpair() { + use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType}; + use nix::unistd::{read, write}; + + let (fd1, fd2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + write(fd1, b"hello").unwrap(); + let mut buf = [0; 5]; + read(fd2, &mut buf).unwrap(); + + assert_eq!(&buf[..], b"hello"); +} + +#[test] +pub fn test_std_conversions() { + use nix::sys::socket::*; + + let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap(); + let sock_addr = SockaddrIn::from(std_sa); + assert_eq!(std_sa, sock_addr.into()); + + let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap(); + let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa); + assert_eq!(std_sa, sock_addr.into()); +} + +mod recvfrom { + use super::*; + use nix::sys::socket::*; + use nix::{errno::Errno, Result}; + use std::thread; + + const MSG: &[u8] = b"Hello, World!"; + + fn sendrecv( + rsock: RawFd, + ssock: RawFd, + f_send: Fs, + mut f_recv: Fr, + ) -> Option + where + Fs: Fn(RawFd, &[u8], MsgFlags) -> Result + Send + 'static, + Fr: FnMut(usize, Option), + { + let mut buf: [u8; 13] = [0u8; 13]; + let mut l = 0; + let mut from = None; + + let send_thread = thread::spawn(move || { + let mut l = 0; + while l < std::mem::size_of_val(MSG) { + l += f_send(ssock, &MSG[l..], MsgFlags::empty()).unwrap(); + } + }); + + while l < std::mem::size_of_val(MSG) { + let (len, from_) = recvfrom(rsock, &mut buf[l..]).unwrap(); + f_recv(len, from_); + from = from_; + l += len; + } + assert_eq!(&buf, MSG); + send_thread.join().unwrap(); + from + } + + #[test] + pub fn stream() { + let (fd2, fd1) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + // Ignore from for stream sockets + let _ = sendrecv(fd1, fd2, send, |_, _| {}); + } + + #[test] + pub fn udp() { + let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap(); + let sock_addr = SockaddrIn::from(std_sa); + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + bind(rsock, &sock_addr).unwrap(); + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + let from = sendrecv( + rsock, + ssock, + move |s, m, flags| sendto(s, m, &sock_addr, flags), + |_, _| {}, + ); + // UDP sockets should set the from address + assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); + } + + #[cfg(target_os = "linux")] + mod udp_offload { + use super::*; + use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment}; + use std::io::IoSlice; + + #[test] + // Disable the test under emulation because it fails in Cirrus-CI. Lack + // of QEMU support is suspected. + #[cfg_attr(qemu, ignore)] + pub fn gso() { + require_kernel_version!(udp_offload::gso, ">= 4.18"); + + // In this test, we send the data and provide a GSO segment size. + // Since we are sending the buffer of size 13, six UDP packets + // with size 2 and two UDP packet with size 1 will be sent. + let segment_size: u16 = 2; + + let sock_addr = SockaddrIn::new(127, 0, 0, 1, 6791); + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + + setsockopt(rsock, UdpGsoSegment, &(segment_size as _)) + .expect("setsockopt UDP_SEGMENT failed"); + + bind(rsock, &sock_addr).unwrap(); + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + + let mut num_packets_received: i32 = 0; + + sendrecv( + rsock, + ssock, + move |s, m, flags| { + let iov = [IoSlice::new(m)]; + let cmsg = ControlMessage::UdpGsoSegments(&segment_size); + sendmsg(s, &iov, &[cmsg], flags, Some(&sock_addr)) + }, + { + let num_packets_received_ref = &mut num_packets_received; + + move |len, _| { + // check that we receive UDP packets with payload size + // less or equal to segment size + assert!(len <= segment_size as usize); + *num_packets_received_ref += 1; + } + }, + ); + + // Buffer size is 13, we will receive six packets of size 2, + // and one packet of size 1. + assert_eq!(7, num_packets_received); + } + + #[test] + // Disable the test on emulated platforms because it fails in Cirrus-CI. + // Lack of QEMU support is suspected. + #[cfg_attr(qemu, ignore)] + pub fn gro() { + require_kernel_version!(udp_offload::gro, ">= 5.3"); + + // It's hard to guarantee receiving GRO packets. Just checking + // that `setsockopt` doesn't fail with error + + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + + setsockopt(rsock, UdpGroSegment, &true) + .expect("setsockopt UDP_GRO failed"); + } + } + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", + ))] + #[test] + pub fn udp_sendmmsg() { + use std::io::IoSlice; + + let std_sa = SocketAddrV4::from_str("127.0.0.1:6793").unwrap(); + let std_sa2 = SocketAddrV4::from_str("127.0.0.1:6794").unwrap(); + let sock_addr = SockaddrIn::from(std_sa); + let sock_addr2 = SockaddrIn::from(std_sa2); + + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + bind(rsock, &sock_addr).unwrap(); + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + + let from = sendrecv( + rsock, + ssock, + move |s, m, flags| { + let batch_size = 15; + let mut iovs = Vec::with_capacity(1 + batch_size); + let mut addrs = Vec::with_capacity(1 + batch_size); + let mut data = MultiHeaders::preallocate(1 + batch_size, None); + let iov = IoSlice::new(m); + // first chunk: + iovs.push([iov]); + addrs.push(Some(sock_addr)); + + for _ in 0..batch_size { + iovs.push([iov]); + addrs.push(Some(sock_addr2)); + } + + let res = sendmmsg(s, &mut data, &iovs, addrs, [], flags)?; + let mut sent_messages = 0; + let mut sent_bytes = 0; + for item in res { + sent_messages += 1; + sent_bytes += item.bytes; + } + // + assert_eq!(sent_messages, iovs.len()); + assert_eq!(sent_bytes, sent_messages * m.len()); + Ok(sent_messages) + }, + |_, _| {}, + ); + // UDP sockets should set the from address + assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); + } + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", + ))] + #[test] + pub fn udp_recvmmsg() { + use nix::sys::socket::{recvmmsg, MsgFlags}; + use std::io::IoSliceMut; + + const NUM_MESSAGES_SENT: usize = 2; + const DATA: [u8; 2] = [1, 2]; + + let inet_addr = SocketAddrV4::from_str("127.0.0.1:6798").unwrap(); + let sock_addr = SockaddrIn::from(inet_addr); + + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + bind(rsock, &sock_addr).unwrap(); + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + + let send_thread = thread::spawn(move || { + for _ in 0..NUM_MESSAGES_SENT { + sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()) + .unwrap(); + } + }); + + let mut msgs = std::collections::LinkedList::new(); + + // Buffers to receive exactly `NUM_MESSAGES_SENT` messages + let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT]; + msgs.extend( + receive_buffers + .iter_mut() + .map(|buf| [IoSliceMut::new(&mut buf[..])]), + ); + + let mut data = + MultiHeaders::::preallocate(msgs.len(), None); + + let res: Vec> = + recvmmsg(rsock, &mut data, msgs.iter(), MsgFlags::empty(), None) + .expect("recvmmsg") + .collect(); + assert_eq!(res.len(), DATA.len()); + + for RecvMsg { address, bytes, .. } in res.into_iter() { + assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap()); + assert_eq!(DATA.len(), bytes); + } + + for buf in &receive_buffers { + assert_eq!(&buf[..DATA.len()], DATA); + } + + send_thread.join().unwrap(); + } + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", + ))] + #[test] + pub fn udp_recvmmsg_dontwait_short_read() { + use nix::sys::socket::{recvmmsg, MsgFlags}; + use std::io::IoSliceMut; + + const NUM_MESSAGES_SENT: usize = 2; + const DATA: [u8; 4] = [1, 2, 3, 4]; + + let inet_addr = SocketAddrV4::from_str("127.0.0.1:6799").unwrap(); + let sock_addr = SockaddrIn::from(inet_addr); + + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + bind(rsock, &sock_addr).unwrap(); + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + + let send_thread = thread::spawn(move || { + for _ in 0..NUM_MESSAGES_SENT { + sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()) + .unwrap(); + } + }); + // Ensure we've sent all the messages before continuing so `recvmmsg` + // will return right away + send_thread.join().unwrap(); + + let mut msgs = std::collections::LinkedList::new(); + + // Buffers to receive >`NUM_MESSAGES_SENT` messages to ensure `recvmmsg` + // will return when there are fewer than requested messages in the + // kernel buffers when using `MSG_DONTWAIT`. + let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2]; + msgs.extend( + receive_buffers + .iter_mut() + .map(|buf| [IoSliceMut::new(&mut buf[..])]), + ); + + let mut data = MultiHeaders::::preallocate( + NUM_MESSAGES_SENT + 2, + None, + ); + + let res: Vec> = recvmmsg( + rsock, + &mut data, + msgs.iter(), + MsgFlags::MSG_DONTWAIT, + None, + ) + .expect("recvmmsg") + .collect(); + assert_eq!(res.len(), NUM_MESSAGES_SENT); + + for RecvMsg { address, bytes, .. } in res.into_iter() { + assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap()); + assert_eq!(DATA.len(), bytes); + } + + for buf in &receive_buffers[..NUM_MESSAGES_SENT] { + assert_eq!(&buf[..DATA.len()], DATA); + } + } + + #[test] + pub fn udp_inet6() { + let addr = std::net::Ipv6Addr::from_str("::1").unwrap(); + let rport = 6789; + let rstd_sa = SocketAddrV6::new(addr, rport, 0, 0); + let raddr = SockaddrIn6::from(rstd_sa); + let sport = 6790; + let sstd_sa = SocketAddrV6::new(addr, sport, 0, 0); + let saddr = SockaddrIn6::from(sstd_sa); + let rsock = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("receive socket failed"); + match bind(rsock, &raddr) { + Err(Errno::EADDRNOTAVAIL) => { + println!("IPv6 not available, skipping test."); + return; + } + Err(e) => panic!("bind: {}", e), + Ok(()) => (), + } + let ssock = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + bind(ssock, &saddr).unwrap(); + let from = sendrecv( + rsock, + ssock, + move |s, m, flags| sendto(s, m, &raddr, flags), + |_, _| {}, + ); + assert_eq!(AddressFamily::Inet6, from.unwrap().family().unwrap()); + let osent_addr = from.unwrap(); + let sent_addr = osent_addr.as_sockaddr_in6().unwrap(); + assert_eq!(sent_addr.ip(), addr); + assert_eq!(sent_addr.port(), sport); + } +} + +// Test error handling of our recvmsg wrapper +#[test] +pub fn test_recvmsg_ebadf() { + use nix::errno::Errno; + use nix::sys::socket::{recvmsg, MsgFlags}; + use std::io::IoSliceMut; + + let mut buf = [0u8; 5]; + let mut iov = [IoSliceMut::new(&mut buf[..])]; + + let fd = -1; // Bad file descriptor + let r = recvmsg::<()>(fd, &mut iov, None, MsgFlags::empty()); + + assert_eq!(r.err().unwrap(), Errno::EBADF); +} + +// Disable the test on emulated platforms due to a bug in QEMU versions < +// 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808 +#[cfg_attr(qemu, ignore)] +#[test] +pub fn test_scm_rights() { + use nix::sys::socket::{ + recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage, + ControlMessageOwned, MsgFlags, SockFlag, SockType, + }; + use nix::unistd::{close, pipe, read, write}; + use std::io::{IoSlice, IoSliceMut}; + + let (fd1, fd2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + let (r, w) = pipe().unwrap(); + let mut received_r: Option = None; + + { + let iov = [IoSlice::new(b"hello")]; + let fds = [r]; + let cmsg = ControlMessage::ScmRights(&fds); + assert_eq!( + sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), + 5 + ); + close(r).unwrap(); + close(fd1).unwrap(); + } + + { + let mut buf = [0u8; 5]; + + let mut iov = [IoSliceMut::new(&mut buf[..])]; + let mut cmsgspace = cmsg_space!([RawFd; 1]); + let msg = recvmsg::<()>( + fd2, + &mut iov, + Some(&mut cmsgspace), + MsgFlags::empty(), + ) + .unwrap(); + + for cmsg in msg.cmsgs() { + if let ControlMessageOwned::ScmRights(fd) = cmsg { + assert_eq!(received_r, None); + assert_eq!(fd.len(), 1); + received_r = Some(fd[0]); + } else { + panic!("unexpected cmsg"); + } + } + assert_eq!(msg.bytes, 5); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + close(fd2).unwrap(); + } + + let received_r = received_r.expect("Did not receive passed fd"); + // Ensure that the received file descriptor works + write(w, b"world").unwrap(); + let mut buf = [0u8; 5]; + read(received_r, &mut buf).unwrap(); + assert_eq!(&buf[..], b"world"); + close(received_r).unwrap(); + close(w).unwrap(); +} + +// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross +#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg_attr(qemu, ignore)] +#[test] +pub fn test_af_alg_cipher() { + use nix::sys::socket::sockopt::AlgSetKey; + use nix::sys::socket::{ + accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr, + ControlMessage, MsgFlags, SockFlag, SockType, + }; + use nix::unistd::read; + use std::io::IoSlice; + + skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352"); + // Travis's seccomp profile blocks AF_ALG + // https://docs.docker.com/engine/security/seccomp/ + skip_if_seccomp!(test_af_alg_cipher); + + let alg_type = "skcipher"; + let alg_name = "ctr-aes-aesni"; + // 256-bits secret key + let key = vec![0u8; 32]; + // 16-bytes IV + let iv_len = 16; + let iv = vec![1u8; iv_len]; + // 256-bytes plain payload + let payload_len = 256; + let payload = vec![2u8; payload_len]; + + let sock = socket( + AddressFamily::Alg, + SockType::SeqPacket, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + + let sockaddr = AlgAddr::new(alg_type, alg_name); + bind(sock, &sockaddr).expect("bind failed"); + + assert_eq!(sockaddr.alg_name().to_string_lossy(), alg_name); + assert_eq!(sockaddr.alg_type().to_string_lossy(), alg_type); + + setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt"); + let session_socket = accept(sock).expect("accept failed"); + + let msgs = [ + ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), + ControlMessage::AlgSetIv(iv.as_slice()), + ]; + let iov = IoSlice::new(&payload); + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) + .expect("sendmsg encrypt"); + + // allocate buffer for encrypted data + let mut encrypted = vec![0u8; payload_len]; + let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt"); + assert_eq!(num_bytes, payload_len); + + let iov = IoSlice::new(&encrypted); + + let iv = vec![1u8; iv_len]; + + let msgs = [ + ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT), + ControlMessage::AlgSetIv(iv.as_slice()), + ]; + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) + .expect("sendmsg decrypt"); + + // allocate buffer for decrypted data + let mut decrypted = vec![0u8; payload_len]; + let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt"); + + assert_eq!(num_bytes, payload_len); + assert_eq!(decrypted, payload); +} + +// Disable the test on emulated platforms due to not enabled support of AF_ALG +// in QEMU from rust cross +#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg_attr(qemu, ignore)] +#[test] +pub fn test_af_alg_aead() { + use libc::{ALG_OP_DECRYPT, ALG_OP_ENCRYPT}; + use nix::fcntl::{fcntl, FcntlArg, OFlag}; + use nix::sys::socket::sockopt::{AlgSetAeadAuthSize, AlgSetKey}; + use nix::sys::socket::{ + accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr, + ControlMessage, MsgFlags, SockFlag, SockType, + }; + use nix::unistd::{close, read}; + use std::io::IoSlice; + + skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352"); + // Travis's seccomp profile blocks AF_ALG + // https://docs.docker.com/engine/security/seccomp/ + skip_if_seccomp!(test_af_alg_aead); + + let auth_size = 4usize; + let assoc_size = 16u32; + + let alg_type = "aead"; + let alg_name = "gcm(aes)"; + // 256-bits secret key + let key = vec![0u8; 32]; + // 12-bytes IV + let iv_len = 12; + let iv = vec![1u8; iv_len]; + // 256-bytes plain payload + let payload_len = 256; + let mut payload = + vec![2u8; payload_len + (assoc_size as usize) + auth_size]; + + for i in 0..assoc_size { + payload[i as usize] = 10; + } + + let len = payload.len(); + + for i in 0..auth_size { + payload[len - 1 - i] = 0; + } + + let sock = socket( + AddressFamily::Alg, + SockType::SeqPacket, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + + let sockaddr = AlgAddr::new(alg_type, alg_name); + bind(sock, &sockaddr).expect("bind failed"); + + setsockopt(sock, AlgSetAeadAuthSize, &auth_size) + .expect("setsockopt AlgSetAeadAuthSize"); + setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt AlgSetKey"); + let session_socket = accept(sock).expect("accept failed"); + + let msgs = [ + ControlMessage::AlgSetOp(&ALG_OP_ENCRYPT), + ControlMessage::AlgSetIv(iv.as_slice()), + ControlMessage::AlgSetAeadAssoclen(&assoc_size), + ]; + + let iov = IoSlice::new(&payload); + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) + .expect("sendmsg encrypt"); + + // allocate buffer for encrypted data + let mut encrypted = + vec![0u8; (assoc_size as usize) + payload_len + auth_size]; + let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt"); + assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize)); + close(session_socket).expect("close"); + + for i in 0..assoc_size { + encrypted[i as usize] = 10; + } + + let iov = IoSlice::new(&encrypted); + + let iv = vec![1u8; iv_len]; + + let session_socket = accept(sock).expect("accept failed"); + + let msgs = [ + ControlMessage::AlgSetOp(&ALG_OP_DECRYPT), + ControlMessage::AlgSetIv(iv.as_slice()), + ControlMessage::AlgSetAeadAssoclen(&assoc_size), + ]; + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) + .expect("sendmsg decrypt"); + + // allocate buffer for decrypted data + let mut decrypted = + vec![0u8; payload_len + (assoc_size as usize) + auth_size]; + // Starting with kernel 4.9, the interface changed slightly such that the + // authentication tag memory is only needed in the output buffer for encryption + // and in the input buffer for decryption. + // Do not block on read, as we may have fewer bytes than buffer size + fcntl(session_socket, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)) + .expect("fcntl non_blocking"); + let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt"); + + assert!(num_bytes >= payload_len + (assoc_size as usize)); + assert_eq!( + decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))], + payload[(assoc_size as usize)..payload_len + (assoc_size as usize)] + ); +} + +// Verify `ControlMessage::Ipv4PacketInfo` for `sendmsg`. +// This creates a (udp) socket bound to localhost, then sends a message to +// itself but uses Ipv4PacketInfo to force the source address to be localhost. +// +// This would be a more interesting test if we could assume that the test host +// has more than one IP address (since we could select a different address to +// test from). +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd"))] +#[test] +pub fn test_sendmsg_ipv4packetinfo() { + use cfg_if::cfg_if; + use nix::sys::socket::{ + bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags, + SockFlag, SockType, SockaddrIn, + }; + use std::io::IoSlice; + + let sock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + + let sock_addr = SockaddrIn::new(127, 0, 0, 1, 4000); + + bind(sock, &sock_addr).expect("bind failed"); + + let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let iov = [IoSlice::new(&slice)]; + + cfg_if! { + if #[cfg(target_os = "netbsd")] { + let pi = libc::in_pktinfo { + ipi_ifindex: 0, /* Unspecified interface */ + ipi_addr: libc::in_addr { s_addr: 0 }, + }; + } else { + let pi = libc::in_pktinfo { + ipi_ifindex: 0, /* Unspecified interface */ + ipi_addr: libc::in_addr { s_addr: 0 }, + ipi_spec_dst: sock_addr.as_ref().sin_addr, + }; + } + } + + let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)]; + + sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) + .expect("sendmsg"); +} + +// Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`. +// This creates a (udp) socket bound to ip6-localhost, then sends a message to +// itself but uses Ipv6PacketInfo to force the source address to be +// ip6-localhost. +// +// This would be a more interesting test if we could assume that the test host +// has more than one IP address (since we could select a different address to +// test from). +#[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "freebsd" +))] +#[test] +pub fn test_sendmsg_ipv6packetinfo() { + use nix::errno::Errno; + use nix::sys::socket::{ + bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags, + SockFlag, SockType, SockaddrIn6, + }; + use std::io::IoSlice; + + let sock = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + + let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap(); + let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa); + + if let Err(Errno::EADDRNOTAVAIL) = bind(sock, &sock_addr) { + println!("IPv6 not available, skipping test."); + return; + } + + let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let iov = [IoSlice::new(&slice)]; + + let pi = libc::in6_pktinfo { + ipi6_ifindex: 0, /* Unspecified interface */ + ipi6_addr: sock_addr.as_ref().sin6_addr, + }; + + let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)]; + + sendmsg::( + sock, + &iov, + &cmsg, + MsgFlags::empty(), + Some(&sock_addr), + ) + .expect("sendmsg"); +} + +// Verify that ControlMessage::Ipv4SendSrcAddr works for sendmsg. This +// creates a UDP socket bound to all local interfaces (0.0.0.0). It then +// sends message to itself at 127.0.0.1 while explicitly specifying +// 127.0.0.1 as the source address through an Ipv4SendSrcAddr +// (IP_SENDSRCADDR) control message. +// +// Note that binding to 0.0.0.0 is *required* on FreeBSD; sendmsg +// returns EINVAL otherwise. (See FreeBSD's ip(4) man page.) +#[cfg(any( + target_os = "netbsd", + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", +))] +#[test] +pub fn test_sendmsg_ipv4sendsrcaddr() { + use nix::sys::socket::{ + bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags, + SockFlag, SockType, SockaddrIn, + }; + use std::io::IoSlice; + + let sock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + + let unspec_sock_addr = SockaddrIn::new(0, 0, 0, 0, 0); + bind(sock, &unspec_sock_addr).expect("bind failed"); + let bound_sock_addr: SockaddrIn = getsockname(sock).unwrap(); + let localhost_sock_addr: SockaddrIn = + SockaddrIn::new(127, 0, 0, 1, bound_sock_addr.port()); + + let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let iov = [IoSlice::new(&slice)]; + let cmsg = [ControlMessage::Ipv4SendSrcAddr( + &localhost_sock_addr.as_ref().sin_addr, + )]; + + sendmsg( + sock, + &iov, + &cmsg, + MsgFlags::empty(), + Some(&localhost_sock_addr), + ) + .expect("sendmsg"); +} + +/// Tests that passing multiple fds using a single `ControlMessage` works. +// Disable the test on emulated platforms due to a bug in QEMU versions < +// 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808 +#[cfg_attr(qemu, ignore)] +#[test] +fn test_scm_rights_single_cmsg_multiple_fds() { + use nix::sys::socket::{ + recvmsg, sendmsg, ControlMessage, ControlMessageOwned, MsgFlags, + }; + use std::io::{IoSlice, IoSliceMut}; + use std::os::unix::io::{AsRawFd, RawFd}; + use std::os::unix::net::UnixDatagram; + use std::thread; + + let (send, receive) = UnixDatagram::pair().unwrap(); + let thread = thread::spawn(move || { + let mut buf = [0u8; 8]; + let mut iovec = [IoSliceMut::new(&mut buf)]; + + let mut space = cmsg_space!([RawFd; 2]); + let msg = recvmsg::<()>( + receive.as_raw_fd(), + &mut iovec, + Some(&mut space), + MsgFlags::empty(), + ) + .unwrap(); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + + let mut cmsgs = msg.cmsgs(); + match cmsgs.next() { + Some(ControlMessageOwned::ScmRights(fds)) => { + assert_eq!( + fds.len(), + 2, + "unexpected fd count (expected 2 fds, got {})", + fds.len() + ); + } + _ => panic!(), + } + assert!(cmsgs.next().is_none(), "unexpected control msg"); + + assert_eq!(msg.bytes, 8); + assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); + }); + + let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let iov = [IoSlice::new(&slice)]; + let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO]; // pass stdin and stdout + let cmsg = [ControlMessage::ScmRights(&fds)]; + sendmsg::<()>(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None) + .unwrap(); + thread.join().unwrap(); +} + +// Verify `sendmsg` builds a valid `msghdr` when passing an empty +// `cmsgs` argument. This should result in a msghdr with a nullptr +// msg_control field and a msg_controllen of 0 when calling into the +// raw `sendmsg`. +#[test] +pub fn test_sendmsg_empty_cmsgs() { + use nix::sys::socket::{ + recvmsg, sendmsg, socketpair, AddressFamily, MsgFlags, SockFlag, + SockType, + }; + use nix::unistd::close; + use std::io::{IoSlice, IoSliceMut}; + + let (fd1, fd2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + + { + let iov = [IoSlice::new(b"hello")]; + assert_eq!( + sendmsg::<()>(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), + 5 + ); + close(fd1).unwrap(); + } + + { + let mut buf = [0u8; 5]; + let mut iov = [IoSliceMut::new(&mut buf[..])]; + + let mut cmsgspace = cmsg_space!([RawFd; 1]); + let msg = recvmsg::<()>( + fd2, + &mut iov, + Some(&mut cmsgspace), + MsgFlags::empty(), + ) + .unwrap(); + + for _ in msg.cmsgs() { + panic!("unexpected cmsg"); + } + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + assert_eq!(msg.bytes, 5); + close(fd2).unwrap(); + } +} + +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "freebsd", + target_os = "dragonfly", +))] +#[test] +fn test_scm_credentials() { + use nix::sys::socket::{ + recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage, + ControlMessageOwned, MsgFlags, SockFlag, SockType, UnixCredentials, + }; + #[cfg(any(target_os = "android", target_os = "linux"))] + use nix::sys::socket::{setsockopt, sockopt::PassCred}; + use nix::unistd::{close, getgid, getpid, getuid}; + use std::io::{IoSlice, IoSliceMut}; + + let (send, recv) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + #[cfg(any(target_os = "android", target_os = "linux"))] + setsockopt(recv, PassCred, &true).unwrap(); + + { + let iov = [IoSlice::new(b"hello")]; + #[cfg(any(target_os = "android", target_os = "linux"))] + let cred = UnixCredentials::new(); + #[cfg(any(target_os = "android", target_os = "linux"))] + let cmsg = ControlMessage::ScmCredentials(&cred); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + let cmsg = ControlMessage::ScmCreds; + assert_eq!( + sendmsg::<()>(send, &iov, &[cmsg], MsgFlags::empty(), None) + .unwrap(), + 5 + ); + close(send).unwrap(); + } + + { + let mut buf = [0u8; 5]; + let mut iov = [IoSliceMut::new(&mut buf[..])]; + + let mut cmsgspace = cmsg_space!(UnixCredentials); + let msg = recvmsg::<()>( + recv, + &mut iov, + Some(&mut cmsgspace), + MsgFlags::empty(), + ) + .unwrap(); + let mut received_cred = None; + + for cmsg in msg.cmsgs() { + let cred = match cmsg { + #[cfg(any(target_os = "android", target_os = "linux"))] + ControlMessageOwned::ScmCredentials(cred) => cred, + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + ControlMessageOwned::ScmCreds(cred) => cred, + other => panic!("unexpected cmsg {:?}", other), + }; + assert!(received_cred.is_none()); + assert_eq!(cred.pid(), getpid().as_raw()); + assert_eq!(cred.uid(), getuid().as_raw()); + assert_eq!(cred.gid(), getgid().as_raw()); + received_cred = Some(cred); + } + received_cred.expect("no creds received"); + assert_eq!(msg.bytes, 5); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + close(recv).unwrap(); + } +} + +/// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single +/// `sendmsg` call. +#[cfg(any(target_os = "android", target_os = "linux"))] +// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation +// see https://bugs.launchpad.net/qemu/+bug/1781280 +#[cfg_attr(qemu, ignore)] +#[test] +fn test_scm_credentials_and_rights() { + let space = cmsg_space!(libc::ucred, RawFd); + test_impl_scm_credentials_and_rights(space); +} + +/// Ensure that passing a an oversized control message buffer to recvmsg +/// still works. +#[cfg(any(target_os = "android", target_os = "linux"))] +// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation +// see https://bugs.launchpad.net/qemu/+bug/1781280 +#[cfg_attr(qemu, ignore)] +#[test] +fn test_too_large_cmsgspace() { + let space = vec![0u8; 1024]; + test_impl_scm_credentials_and_rights(space); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +fn test_impl_scm_credentials_and_rights(mut space: Vec) { + use libc::ucred; + use nix::sys::socket::sockopt::PassCred; + use nix::sys::socket::{ + recvmsg, sendmsg, setsockopt, socketpair, ControlMessage, + ControlMessageOwned, MsgFlags, SockFlag, SockType, + }; + use nix::unistd::{close, getgid, getpid, getuid, pipe, write}; + use std::io::{IoSlice, IoSliceMut}; + + let (send, recv) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + setsockopt(recv, PassCred, &true).unwrap(); + + let (r, w) = pipe().unwrap(); + let mut received_r: Option = None; + + { + let iov = [IoSlice::new(b"hello")]; + let cred = ucred { + pid: getpid().as_raw(), + uid: getuid().as_raw(), + gid: getgid().as_raw(), + } + .into(); + let fds = [r]; + let cmsgs = [ + ControlMessage::ScmCredentials(&cred), + ControlMessage::ScmRights(&fds), + ]; + assert_eq!( + sendmsg::<()>(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(), + 5 + ); + close(r).unwrap(); + close(send).unwrap(); + } + + { + let mut buf = [0u8; 5]; + let mut iov = [IoSliceMut::new(&mut buf[..])]; + let msg = + recvmsg::<()>(recv, &mut iov, Some(&mut space), MsgFlags::empty()) + .unwrap(); + let mut received_cred = None; + + assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs"); + + for cmsg in msg.cmsgs() { + match cmsg { + ControlMessageOwned::ScmRights(fds) => { + assert_eq!(received_r, None, "already received fd"); + assert_eq!(fds.len(), 1); + received_r = Some(fds[0]); + } + ControlMessageOwned::ScmCredentials(cred) => { + assert!(received_cred.is_none()); + assert_eq!(cred.pid(), getpid().as_raw()); + assert_eq!(cred.uid(), getuid().as_raw()); + assert_eq!(cred.gid(), getgid().as_raw()); + received_cred = Some(cred); + } + _ => panic!("unexpected cmsg"), + } + } + received_cred.expect("no creds received"); + assert_eq!(msg.bytes, 5); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + close(recv).unwrap(); + } + + let received_r = received_r.expect("Did not receive passed fd"); + // Ensure that the received file descriptor works + write(w, b"world").unwrap(); + let mut buf = [0u8; 5]; + read(received_r, &mut buf).unwrap(); + assert_eq!(&buf[..], b"world"); + close(received_r).unwrap(); + close(w).unwrap(); +} + +// Test creating and using named unix domain sockets +#[test] +pub fn test_named_unixdomain() { + use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr}; + use nix::sys::socket::{SockFlag, SockType}; + use nix::unistd::{close, read, write}; + use std::thread; + + let tempdir = tempfile::tempdir().unwrap(); + let sockname = tempdir.path().join("sock"); + let s1 = socket( + AddressFamily::Unix, + SockType::Stream, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + let sockaddr = UnixAddr::new(&sockname).unwrap(); + bind(s1, &sockaddr).expect("bind failed"); + listen(s1, 10).expect("listen failed"); + + let thr = thread::spawn(move || { + let s2 = socket( + AddressFamily::Unix, + SockType::Stream, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + connect(s2, &sockaddr).expect("connect failed"); + write(s2, b"hello").expect("write failed"); + close(s2).unwrap(); + }); + + let s3 = accept(s1).expect("accept failed"); + + let mut buf = [0; 5]; + read(s3, &mut buf).unwrap(); + close(s3).unwrap(); + close(s1).unwrap(); + thr.join().unwrap(); + + assert_eq!(&buf[..], b"hello"); +} + +// Test using unnamed unix domain addresses +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +pub fn test_unnamed_unixdomain() { + use nix::sys::socket::{getsockname, socketpair}; + use nix::sys::socket::{SockFlag, SockType}; + use nix::unistd::close; + + let (fd_1, fd_2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .expect("socketpair failed"); + + let addr_1: UnixAddr = getsockname(fd_1).expect("getsockname failed"); + assert!(addr_1.is_unnamed()); + + close(fd_1).unwrap(); + close(fd_2).unwrap(); +} + +// Test creating and using unnamed unix domain addresses for autobinding sockets +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +pub fn test_unnamed_unixdomain_autobind() { + use nix::sys::socket::{bind, getsockname, socket}; + use nix::sys::socket::{SockFlag, SockType}; + use nix::unistd::close; + + let fd = socket( + AddressFamily::Unix, + SockType::Stream, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + + // unix(7): "If a bind(2) call specifies addrlen as `sizeof(sa_family_t)`, or [...], then the + // socket is autobound to an abstract address" + bind(fd, &UnixAddr::new_unnamed()).expect("bind failed"); + + let addr: UnixAddr = getsockname(fd).expect("getsockname failed"); + let addr = addr.as_abstract().unwrap(); + + // changed from 8 to 5 bytes in Linux 2.3.15, and rust's minimum supported Linux version is 3.2 + // (as of 2022-11) + assert_eq!(addr.len(), 5); + + close(fd).unwrap(); +} + +// Test creating and using named system control sockets +#[cfg(any(target_os = "macos", target_os = "ios"))] +#[test] +pub fn test_syscontrol() { + use nix::errno::Errno; + use nix::sys::socket::{ + socket, SockFlag, SockProtocol, SockType, SysControlAddr, + }; + + let fd = socket( + AddressFamily::System, + SockType::Datagram, + SockFlag::empty(), + SockProtocol::KextControl, + ) + .expect("socket failed"); + SysControlAddr::from_name(fd, "com.apple.net.utun_control", 0) + .expect("resolving sys_control name failed"); + assert_eq!( + SysControlAddr::from_name(fd, "foo.bar.lol", 0).err(), + Some(Errno::ENOENT) + ); + + // requires root privileges + // connect(fd, &sockaddr).expect("connect failed"); +} + +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +))] +fn loopback_address( + family: AddressFamily, +) -> Option { + use nix::ifaddrs::getifaddrs; + use nix::net::if_::*; + use nix::sys::socket::SockaddrLike; + use std::io; + use std::io::Write; + + let mut addrs = match getifaddrs() { + Ok(iter) => iter, + Err(e) => { + let stdioerr = io::stderr(); + let mut handle = stdioerr.lock(); + writeln!(handle, "getifaddrs: {:?}", e).unwrap(); + return None; + } + }; + // return first address matching family + addrs.find(|ifaddr| { + ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK) + && ifaddr.address.as_ref().and_then(SockaddrLike::family) + == Some(family) + }) +} + +#[cfg(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", +))] +// qemu doesn't seem to be emulating this correctly in these architectures +#[cfg_attr( + all( + qemu, + any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + ) + ), + ignore +)] +#[test] +pub fn test_recv_ipv4pktinfo() { + use nix::net::if_::*; + use nix::sys::socket::sockopt::Ipv4PacketInfo; + use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn}; + use nix::sys::socket::{getsockname, setsockopt, socket}; + use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; + use std::io::{IoSlice, IoSliceMut}; + + let lo_ifaddr = loopback_address(AddressFamily::Inet); + let (lo_name, lo) = match lo_ifaddr { + Some(ifaddr) => ( + ifaddr.interface_name, + ifaddr.address.expect("Expect IPv4 address on interface"), + ), + None => return, + }; + let receive = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("receive socket failed"); + bind(receive, &lo).expect("bind failed"); + let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); + setsockopt(receive, Ipv4PacketInfo, &true).expect("setsockopt failed"); + + { + let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let iov = [IoSlice::new(&slice)]; + + let send = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + .expect("sendmsg failed"); + } + + { + let mut buf = [0u8; 8]; + let mut iovec = [IoSliceMut::new(&mut buf)]; + + let mut space = cmsg_space!(libc::in_pktinfo); + let msg = recvmsg::<()>( + receive, + &mut iovec, + Some(&mut space), + MsgFlags::empty(), + ) + .expect("recvmsg failed"); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + + let mut cmsgs = msg.cmsgs(); + if let Some(ControlMessageOwned::Ipv4PacketInfo(pktinfo)) = cmsgs.next() + { + let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); + assert_eq!( + pktinfo.ipi_ifindex as libc::c_uint, i, + "unexpected ifindex (expected {}, got {})", + i, pktinfo.ipi_ifindex + ); + } + assert!(cmsgs.next().is_none(), "unexpected additional control msg"); + assert_eq!(msg.bytes, 8); + assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); + } +} + +#[cfg(any( + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +))] +// qemu doesn't seem to be emulating this correctly in these architectures +#[cfg_attr( + all( + qemu, + any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + ) + ), + ignore +)] +#[test] +pub fn test_recvif() { + use nix::net::if_::*; + use nix::sys::socket::sockopt::{Ipv4RecvDstAddr, Ipv4RecvIf}; + use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn}; + use nix::sys::socket::{getsockname, setsockopt, socket}; + use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; + use std::io::{IoSlice, IoSliceMut}; + + let lo_ifaddr = loopback_address(AddressFamily::Inet); + let (lo_name, lo) = match lo_ifaddr { + Some(ifaddr) => ( + ifaddr.interface_name, + ifaddr.address.expect("Expect IPv4 address on interface"), + ), + None => return, + }; + let receive = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("receive socket failed"); + bind(receive, &lo).expect("bind failed"); + let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); + setsockopt(receive, Ipv4RecvIf, &true) + .expect("setsockopt IP_RECVIF failed"); + setsockopt(receive, Ipv4RecvDstAddr, &true) + .expect("setsockopt IP_RECVDSTADDR failed"); + + { + let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let iov = [IoSlice::new(&slice)]; + + let send = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + .expect("sendmsg failed"); + } + + { + let mut buf = [0u8; 8]; + let mut iovec = [IoSliceMut::new(&mut buf)]; + let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr); + let msg = recvmsg::<()>( + receive, + &mut iovec, + Some(&mut space), + MsgFlags::empty(), + ) + .expect("recvmsg failed"); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs"); + + let mut rx_recvif = false; + let mut rx_recvdstaddr = false; + for cmsg in msg.cmsgs() { + match cmsg { + ControlMessageOwned::Ipv4RecvIf(dl) => { + rx_recvif = true; + let i = if_nametoindex(lo_name.as_bytes()) + .expect("if_nametoindex"); + assert_eq!( + dl.sdl_index as libc::c_uint, i, + "unexpected ifindex (expected {}, got {})", + i, dl.sdl_index + ); + } + ControlMessageOwned::Ipv4RecvDstAddr(addr) => { + rx_recvdstaddr = true; + if let Some(sin) = lo.as_sockaddr_in() { + assert_eq!(sin.as_ref().sin_addr.s_addr, + addr.s_addr, + "unexpected destination address (expected {}, got {})", + sin.as_ref().sin_addr.s_addr, + addr.s_addr); + } else { + panic!("unexpected Sockaddr"); + } + } + _ => panic!("unexpected additional control msg"), + } + } + assert!(rx_recvif); + assert!(rx_recvdstaddr); + assert_eq!(msg.bytes, 8); + assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); + } +} + +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg_attr(qemu, ignore)] +#[test] +pub fn test_recvif_ipv4() { + use nix::sys::socket::sockopt::Ipv4OrigDstAddr; + use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn}; + use nix::sys::socket::{getsockname, setsockopt, socket}; + use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; + use std::io::{IoSlice, IoSliceMut}; + + let lo_ifaddr = loopback_address(AddressFamily::Inet); + let (_lo_name, lo) = match lo_ifaddr { + Some(ifaddr) => ( + ifaddr.interface_name, + ifaddr.address.expect("Expect IPv4 address on interface"), + ), + None => return, + }; + let receive = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("receive socket failed"); + bind(receive, &lo).expect("bind failed"); + let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); + setsockopt(receive, Ipv4OrigDstAddr, &true) + .expect("setsockopt IP_ORIGDSTADDR failed"); + + { + let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let iov = [IoSlice::new(&slice)]; + + let send = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + .expect("sendmsg failed"); + } + + { + let mut buf = [0u8; 8]; + let mut iovec = [IoSliceMut::new(&mut buf)]; + let mut space = cmsg_space!(libc::sockaddr_in); + let msg = recvmsg::<()>( + receive, + &mut iovec, + Some(&mut space), + MsgFlags::empty(), + ) + .expect("recvmsg failed"); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + assert_eq!(msg.cmsgs().count(), 1, "expected 1 cmsgs"); + + let mut rx_recvorigdstaddr = false; + for cmsg in msg.cmsgs() { + match cmsg { + ControlMessageOwned::Ipv4OrigDstAddr(addr) => { + rx_recvorigdstaddr = true; + if let Some(sin) = lo.as_sockaddr_in() { + assert_eq!(sin.as_ref().sin_addr.s_addr, + addr.sin_addr.s_addr, + "unexpected destination address (expected {}, got {})", + sin.as_ref().sin_addr.s_addr, + addr.sin_addr.s_addr); + } else { + panic!("unexpected Sockaddr"); + } + } + _ => panic!("unexpected additional control msg"), + } + } + assert!(rx_recvorigdstaddr); + assert_eq!(msg.bytes, 8); + assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); + } +} + +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg_attr(qemu, ignore)] +#[test] +pub fn test_recvif_ipv6() { + use nix::sys::socket::sockopt::Ipv6OrigDstAddr; + use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn6}; + use nix::sys::socket::{getsockname, setsockopt, socket}; + use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; + use std::io::{IoSlice, IoSliceMut}; + + let lo_ifaddr = loopback_address(AddressFamily::Inet6); + let (_lo_name, lo) = match lo_ifaddr { + Some(ifaddr) => ( + ifaddr.interface_name, + ifaddr.address.expect("Expect IPv6 address on interface"), + ), + None => return, + }; + let receive = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("receive socket failed"); + bind(receive, &lo).expect("bind failed"); + let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed"); + setsockopt(receive, Ipv6OrigDstAddr, &true) + .expect("setsockopt IP_ORIGDSTADDR failed"); + + { + let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let iov = [IoSlice::new(&slice)]; + + let send = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + .expect("sendmsg failed"); + } + + { + let mut buf = [0u8; 8]; + let mut iovec = [IoSliceMut::new(&mut buf)]; + let mut space = cmsg_space!(libc::sockaddr_in6); + let msg = recvmsg::<()>( + receive, + &mut iovec, + Some(&mut space), + MsgFlags::empty(), + ) + .expect("recvmsg failed"); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + assert_eq!(msg.cmsgs().count(), 1, "expected 1 cmsgs"); + + let mut rx_recvorigdstaddr = false; + for cmsg in msg.cmsgs() { + match cmsg { + ControlMessageOwned::Ipv6OrigDstAddr(addr) => { + rx_recvorigdstaddr = true; + if let Some(sin) = lo.as_sockaddr_in6() { + assert_eq!(sin.as_ref().sin6_addr.s6_addr, + addr.sin6_addr.s6_addr, + "unexpected destination address (expected {:?}, got {:?})", + sin.as_ref().sin6_addr.s6_addr, + addr.sin6_addr.s6_addr); + } else { + panic!("unexpected Sockaddr"); + } + } + _ => panic!("unexpected additional control msg"), + } + } + assert!(rx_recvorigdstaddr); + assert_eq!(msg.bytes, 8); + assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); + } +} + +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +))] +// qemu doesn't seem to be emulating this correctly in these architectures +#[cfg_attr( + all( + qemu, + any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + ) + ), + ignore +)] +#[test] +pub fn test_recv_ipv6pktinfo() { + use nix::net::if_::*; + use nix::sys::socket::sockopt::Ipv6RecvPacketInfo; + use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn6}; + use nix::sys::socket::{getsockname, setsockopt, socket}; + use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; + use std::io::{IoSlice, IoSliceMut}; + + let lo_ifaddr = loopback_address(AddressFamily::Inet6); + let (lo_name, lo) = match lo_ifaddr { + Some(ifaddr) => ( + ifaddr.interface_name, + ifaddr.address.expect("Expect IPv6 address on interface"), + ), + None => return, + }; + let receive = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("receive socket failed"); + bind(receive, &lo).expect("bind failed"); + let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed"); + setsockopt(receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed"); + + { + let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let iov = [IoSlice::new(&slice)]; + + let send = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + .expect("sendmsg failed"); + } + + { + let mut buf = [0u8; 8]; + let mut iovec = [IoSliceMut::new(&mut buf)]; + + let mut space = cmsg_space!(libc::in6_pktinfo); + let msg = recvmsg::<()>( + receive, + &mut iovec, + Some(&mut space), + MsgFlags::empty(), + ) + .expect("recvmsg failed"); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + + let mut cmsgs = msg.cmsgs(); + if let Some(ControlMessageOwned::Ipv6PacketInfo(pktinfo)) = cmsgs.next() + { + let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); + assert_eq!( + pktinfo.ipi6_ifindex as libc::c_uint, i, + "unexpected ifindex (expected {}, got {})", + i, pktinfo.ipi6_ifindex + ); + } + assert!(cmsgs.next().is_none(), "unexpected additional control msg"); + assert_eq!(msg.bytes, 8); + assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(graviton, ignore = "Not supported by the CI environment")] +#[test] +pub fn test_vsock() { + use nix::errno::Errno; + use nix::sys::socket::{ + bind, connect, listen, socket, AddressFamily, SockFlag, SockType, + VsockAddr, + }; + use nix::unistd::close; + use std::thread; + + let port: u32 = 3000; + + let s1 = socket( + AddressFamily::Vsock, + SockType::Stream, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + + // VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error. + let sockaddr_hv = VsockAddr::new(libc::VMADDR_CID_HYPERVISOR, port); + assert_eq!(bind(s1, &sockaddr_hv).err(), Some(Errno::EADDRNOTAVAIL)); + + let sockaddr_any = VsockAddr::new(libc::VMADDR_CID_ANY, port); + assert_eq!(bind(s1, &sockaddr_any), Ok(())); + listen(s1, 10).expect("listen failed"); + + let thr = thread::spawn(move || { + let cid: u32 = libc::VMADDR_CID_HOST; + + let s2 = socket( + AddressFamily::Vsock, + SockType::Stream, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + + let sockaddr_host = VsockAddr::new(cid, port); + + // The current implementation does not support loopback devices, so, + // for now, we expect a failure on the connect. + assert_ne!(connect(s2, &sockaddr_host), Ok(())); + + close(s2).unwrap(); + }); + + close(s1).unwrap(); + thr.join().unwrap(); +} + +// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack +// of QEMU support is suspected. +#[cfg_attr(qemu, ignore)] +#[cfg(all(target_os = "linux"))] +#[test] +fn test_recvmsg_timestampns() { + use nix::sys::socket::*; + use nix::sys::time::*; + use std::io::{IoSlice, IoSliceMut}; + use std::time::*; + + // Set up + let message = "OhayÅ!".as_bytes(); + let in_socket = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); + let localhost = SockaddrIn::new(127, 0, 0, 1, 0); + bind(in_socket, &localhost).unwrap(); + let address: SockaddrIn = getsockname(in_socket).unwrap(); + // Get initial time + let time0 = SystemTime::now(); + // Send the message + let iov = [IoSlice::new(message)]; + let flags = MsgFlags::empty(); + let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); + assert_eq!(message.len(), l); + // Receive the message + let mut buffer = vec![0u8; message.len()]; + let mut cmsgspace = nix::cmsg_space!(TimeSpec); + + let mut iov = [IoSliceMut::new(&mut buffer)]; + let r = recvmsg::<()>(in_socket, &mut iov, Some(&mut cmsgspace), flags) + .unwrap(); + let rtime = match r.cmsgs().next() { + Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, + Some(_) => panic!("Unexpected control message"), + None => panic!("No control message"), + }; + // Check the final time + let time1 = SystemTime::now(); + // the packet's received timestamp should lie in-between the two system + // times, unless the system clock was adjusted in the meantime. + let rduration = + Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32); + assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); + assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); + // Close socket + nix::unistd::close(in_socket).unwrap(); +} + +// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack +// of QEMU support is suspected. +#[cfg_attr(qemu, ignore)] +#[cfg(all(target_os = "linux"))] +#[test] +fn test_recvmmsg_timestampns() { + use nix::sys::socket::*; + use nix::sys::time::*; + use std::io::{IoSlice, IoSliceMut}; + use std::time::*; + + // Set up + let message = "OhayÅ!".as_bytes(); + let in_socket = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); + let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); + bind(in_socket, &localhost).unwrap(); + let address: SockaddrIn = getsockname(in_socket).unwrap(); + // Get initial time + let time0 = SystemTime::now(); + // Send the message + let iov = [IoSlice::new(message)]; + let flags = MsgFlags::empty(); + let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); + assert_eq!(message.len(), l); + // Receive the message + let mut buffer = vec![0u8; message.len()]; + let cmsgspace = nix::cmsg_space!(TimeSpec); + let iov = vec![[IoSliceMut::new(&mut buffer)]]; + let mut data = MultiHeaders::preallocate(1, Some(cmsgspace)); + let r: Vec> = + recvmmsg(in_socket, &mut data, iov.iter(), flags, None) + .unwrap() + .collect(); + let rtime = match r[0].cmsgs().next() { + Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, + Some(_) => panic!("Unexpected control message"), + None => panic!("No control message"), + }; + // Check the final time + let time1 = SystemTime::now(); + // the packet's received timestamp should lie in-between the two system + // times, unless the system clock was adjusted in the meantime. + let rduration = + Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32); + assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); + assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); + // Close socket + nix::unistd::close(in_socket).unwrap(); +} + +// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack +// of QEMU support is suspected. +#[cfg_attr(qemu, ignore)] +#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] +#[test] +fn test_recvmsg_rxq_ovfl() { + use nix::sys::socket::sockopt::{RcvBuf, RxqOvfl}; + use nix::sys::socket::*; + use nix::Error; + use std::io::{IoSlice, IoSliceMut}; + + let message = [0u8; 2048]; + let bufsize = message.len() * 2; + + let in_socket = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + let out_socket = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + + let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); + bind(in_socket, &localhost).unwrap(); + + let address: SockaddrIn = getsockname(in_socket).unwrap(); + connect(out_socket, &address).unwrap(); + + // Set SO_RXQ_OVFL flag. + setsockopt(in_socket, RxqOvfl, &1).unwrap(); + + // Set the receiver buffer size to hold only 2 messages. + setsockopt(in_socket, RcvBuf, &bufsize).unwrap(); + + let mut drop_counter = 0; + + for _ in 0..2 { + let iov = [IoSlice::new(&message)]; + let flags = MsgFlags::empty(); + + // Send the 3 messages (the receiver buffer can only hold 2 messages) + // to create an overflow. + for _ in 0..3 { + let l = + sendmsg(out_socket, &iov, &[], flags, Some(&address)).unwrap(); + assert_eq!(message.len(), l); + } + + // Receive the message and check the drop counter if any. + loop { + let mut buffer = vec![0u8; message.len()]; + let mut cmsgspace = nix::cmsg_space!(u32); + + let mut iov = [IoSliceMut::new(&mut buffer)]; + + match recvmsg::<()>( + in_socket, + &mut iov, + Some(&mut cmsgspace), + MsgFlags::MSG_DONTWAIT, + ) { + Ok(r) => { + drop_counter = match r.cmsgs().next() { + Some(ControlMessageOwned::RxqOvfl(drop_counter)) => { + drop_counter + } + Some(_) => panic!("Unexpected control message"), + None => 0, + }; + } + Err(Error::EAGAIN) => { + break; + } + _ => { + panic!("unknown recvmsg() error"); + } + } + } + } + + // One packet lost. + assert_eq!(drop_counter, 1); + + // Close sockets + nix::unistd::close(in_socket).unwrap(); + nix::unistd::close(out_socket).unwrap(); +} + +#[cfg(any(target_os = "linux", target_os = "android",))] +mod linux_errqueue { + use super::FromStr; + use nix::sys::socket::*; + + // Send a UDP datagram to a bogus destination address and observe an ICMP error (v4). + // + // Disable the test on QEMU because QEMU emulation of IP_RECVERR is broken (as documented on PR + // #1514). + #[cfg_attr(qemu, ignore)] + #[test] + fn test_recverr_v4() { + #[repr(u8)] + enum IcmpTypes { + DestUnreach = 3, // ICMP_DEST_UNREACH + } + #[repr(u8)] + enum IcmpUnreachCodes { + PortUnreach = 3, // ICMP_PORT_UNREACH + } + + test_recverr_impl::( + "127.0.0.1:6800", + AddressFamily::Inet, + sockopt::Ipv4RecvErr, + libc::SO_EE_ORIGIN_ICMP, + IcmpTypes::DestUnreach as u8, + IcmpUnreachCodes::PortUnreach as u8, + // Closure handles protocol-specific testing and returns generic sock_extended_err for + // protocol-independent test impl. + |cmsg| { + if let ControlMessageOwned::Ipv4RecvErr(ext_err, err_addr) = + cmsg + { + if let Some(origin) = err_addr { + // Validate that our network error originated from 127.0.0.1:0. + assert_eq!(origin.sin_family, AddressFamily::Inet as _); + assert_eq!( + origin.sin_addr.s_addr, + u32::from_be(0x7f000001) + ); + assert_eq!(origin.sin_port, 0); + } else { + panic!("Expected some error origin"); + } + *ext_err + } else { + panic!("Unexpected control message {:?}", cmsg); + } + }, + ) + } + + // Essentially the same test as v4. + // + // Disable the test on QEMU because QEMU emulation of IPV6_RECVERR is broken (as documented on + // PR #1514). + #[cfg_attr(qemu, ignore)] + #[test] + fn test_recverr_v6() { + #[repr(u8)] + enum IcmpV6Types { + DestUnreach = 1, // ICMPV6_DEST_UNREACH + } + #[repr(u8)] + enum IcmpV6UnreachCodes { + PortUnreach = 4, // ICMPV6_PORT_UNREACH + } + + test_recverr_impl::( + "[::1]:6801", + AddressFamily::Inet6, + sockopt::Ipv6RecvErr, + libc::SO_EE_ORIGIN_ICMP6, + IcmpV6Types::DestUnreach as u8, + IcmpV6UnreachCodes::PortUnreach as u8, + // Closure handles protocol-specific testing and returns generic sock_extended_err for + // protocol-independent test impl. + |cmsg| { + if let ControlMessageOwned::Ipv6RecvErr(ext_err, err_addr) = + cmsg + { + if let Some(origin) = err_addr { + // Validate that our network error originated from localhost:0. + assert_eq!( + origin.sin6_family, + AddressFamily::Inet6 as _ + ); + assert_eq!( + origin.sin6_addr.s6_addr, + std::net::Ipv6Addr::LOCALHOST.octets() + ); + assert_eq!(origin.sin6_port, 0); + } else { + panic!("Expected some error origin"); + } + *ext_err + } else { + panic!("Unexpected control message {:?}", cmsg); + } + }, + ) + } + + fn test_recverr_impl( + sa: &str, + af: AddressFamily, + opt: OPT, + ee_origin: u8, + ee_type: u8, + ee_code: u8, + testf: TESTF, + ) where + OPT: SetSockOpt, + TESTF: FnOnce(&ControlMessageOwned) -> libc::sock_extended_err, + { + use nix::errno::Errno; + use std::io::IoSliceMut; + + const MESSAGE_CONTENTS: &str = "ABCDEF"; + let std_sa = std::net::SocketAddr::from_str(sa).unwrap(); + let sock_addr = SockaddrStorage::from(std_sa); + let sock = socket(af, SockType::Datagram, SockFlag::SOCK_CLOEXEC, None) + .unwrap(); + setsockopt(sock, opt, &true).unwrap(); + if let Err(e) = sendto( + sock, + MESSAGE_CONTENTS.as_bytes(), + &sock_addr, + MsgFlags::empty(), + ) { + assert_eq!(e, Errno::EADDRNOTAVAIL); + println!("{:?} not available, skipping test.", af); + return; + } + + let mut buf = [0u8; 8]; + let mut iovec = [IoSliceMut::new(&mut buf)]; + let mut cspace = cmsg_space!(libc::sock_extended_err, SA); + + let msg = recvmsg( + sock, + &mut iovec, + Some(&mut cspace), + MsgFlags::MSG_ERRQUEUE, + ) + .unwrap(); + // The sent message / destination associated with the error is returned: + assert_eq!(msg.bytes, MESSAGE_CONTENTS.as_bytes().len()); + // recvmsg(2): "The original destination address of the datagram that caused the error is + // supplied via msg_name;" however, this is not literally true. E.g., an earlier version + // of this test used 0.0.0.0 (::0) as the destination address, which was mutated into + // 127.0.0.1 (::1). + assert_eq!(msg.address, Some(sock_addr)); + + // Check for expected control message. + let ext_err = match msg.cmsgs().next() { + Some(cmsg) => testf(&cmsg), + None => panic!("No control message"), + }; + + assert_eq!(ext_err.ee_errno, libc::ECONNREFUSED as u32); + assert_eq!(ext_err.ee_origin, ee_origin); + // ip(7): ee_type and ee_code are set from the type and code fields of the ICMP (ICMPv6) + // header. + assert_eq!(ext_err.ee_type, ee_type); + assert_eq!(ext_err.ee_code, ee_code); + // ip(7): ee_info contains the discovered MTU for EMSGSIZE errors. + assert_eq!(ext_err.ee_info, 0); + + let bytes = msg.bytes; + assert_eq!(&buf[..bytes], MESSAGE_CONTENTS.as_bytes()); + } +} + +// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack +// of QEMU support is suspected. +#[cfg_attr(qemu, ignore)] +#[cfg(target_os = "linux")] +#[test] +pub fn test_txtime() { + use nix::sys::socket::{ + bind, recvmsg, sendmsg, setsockopt, socket, sockopt, ControlMessage, + MsgFlags, SockFlag, SockType, SockaddrIn, + }; + use nix::sys::time::TimeValLike; + use nix::time::{clock_gettime, ClockId}; + + require_kernel_version!(test_txtime, ">= 5.8"); + + let sock_addr = SockaddrIn::from_str("127.0.0.1:6802").unwrap(); + + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + + let txtime_cfg = libc::sock_txtime { + clockid: libc::CLOCK_MONOTONIC, + flags: 0, + }; + setsockopt(ssock, sockopt::TxTime, &txtime_cfg).unwrap(); + + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + bind(rsock, &sock_addr).unwrap(); + + let sbuf = [0u8; 2048]; + let iov1 = [std::io::IoSlice::new(&sbuf)]; + + let now = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap(); + let delay = std::time::Duration::from_secs(1).into(); + let txtime = (now + delay).num_nanoseconds() as u64; + + let cmsg = ControlMessage::TxTime(&txtime); + sendmsg(ssock, &iov1, &[cmsg], MsgFlags::empty(), Some(&sock_addr)) + .unwrap(); + + let mut rbuf = [0u8; 2048]; + let mut iov2 = [std::io::IoSliceMut::new(&mut rbuf)]; + recvmsg::<()>(rsock, &mut iov2, None, MsgFlags::empty()).unwrap(); +} diff --git a/vendor/nix-0.26.2/test/sys/test_sockopt.rs b/vendor/nix-0.26.2/test/sys/test_sockopt.rs new file mode 100644 index 0000000000000..34bef945e1d14 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_sockopt.rs @@ -0,0 +1,431 @@ +#[cfg(any(target_os = "android", target_os = "linux"))] +use crate::*; +use nix::sys::socket::{ + getsockopt, setsockopt, socket, sockopt, AddressFamily, SockFlag, + SockProtocol, SockType, +}; +use rand::{thread_rng, Rng}; + +// NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not. +#[cfg(any(target_os = "dragonfly", target_os = "freebsd",))] +#[test] +pub fn test_local_peercred_seqpacket() { + use nix::{ + sys::socket::socketpair, + unistd::{Gid, Uid}, + }; + + let (fd1, _fd2) = socketpair( + AddressFamily::Unix, + SockType::SeqPacket, + None, + SockFlag::empty(), + ) + .unwrap(); + let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap(); + assert_eq!(xucred.version(), 0); + assert_eq!(Uid::from_raw(xucred.uid()), Uid::current()); + assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); +} + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "ios" +))] +#[test] +pub fn test_local_peercred_stream() { + use nix::{ + sys::socket::socketpair, + unistd::{Gid, Uid}, + }; + + let (fd1, _fd2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap(); + assert_eq!(xucred.version(), 0); + assert_eq!(Uid::from_raw(xucred.uid()), Uid::current()); + assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); +} + +#[cfg(target_os = "linux")] +#[test] +fn is_so_mark_functional() { + use nix::sys::socket::sockopt; + + require_capability!("is_so_mark_functional", CAP_NET_ADMIN); + + let s = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(s, sockopt::Mark, &1337).unwrap(); + let mark = getsockopt(s, sockopt::Mark).unwrap(); + assert_eq!(mark, 1337); +} + +#[test] +fn test_so_buf() { + let fd = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + SockProtocol::Udp, + ) + .unwrap(); + let bufsize: usize = thread_rng().gen_range(4096..131_072); + setsockopt(fd, sockopt::SndBuf, &bufsize).unwrap(); + let actual = getsockopt(fd, sockopt::SndBuf).unwrap(); + assert!(actual >= bufsize); + setsockopt(fd, sockopt::RcvBuf, &bufsize).unwrap(); + let actual = getsockopt(fd, sockopt::RcvBuf).unwrap(); + assert!(actual >= bufsize); +} + +#[test] +fn test_so_tcp_maxseg() { + use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn}; + use nix::unistd::{close, write}; + use std::net::SocketAddrV4; + use std::str::FromStr; + + let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap(); + let sock_addr = SockaddrIn::from(std_sa); + + let rsock = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + bind(rsock, &sock_addr).unwrap(); + listen(rsock, 10).unwrap(); + let initial = getsockopt(rsock, sockopt::TcpMaxSeg).unwrap(); + // Initial MSS is expected to be 536 (https://tools.ietf.org/html/rfc879#section-1) but some + // platforms keep it even lower. This might fail if you've tuned your initial MSS to be larger + // than 700 + cfg_if! { + if #[cfg(any(target_os = "android", target_os = "linux"))] { + let segsize: u32 = 873; + assert!(initial < segsize); + setsockopt(rsock, sockopt::TcpMaxSeg, &segsize).unwrap(); + } else { + assert!(initial < 700); + } + } + + // Connect and check the MSS that was advertised + let ssock = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + connect(ssock, &sock_addr).unwrap(); + let rsess = accept(rsock).unwrap(); + write(rsess, b"hello").unwrap(); + let actual = getsockopt(ssock, sockopt::TcpMaxSeg).unwrap(); + // Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max + // TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary. + cfg_if! { + if #[cfg(any(target_os = "android", target_os = "linux"))] { + assert!((segsize - 100) <= actual); + assert!(actual <= segsize); + } else { + assert!(initial < actual); + assert!(536 < actual); + } + } + close(rsock).unwrap(); + close(ssock).unwrap(); +} + +#[test] +fn test_so_type() { + let sockfd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + None, + ) + .unwrap(); + + assert_eq!(Ok(SockType::Stream), getsockopt(sockfd, sockopt::SockType)); +} + +/// getsockopt(_, sockopt::SockType) should gracefully handle unknown socket +/// types. Regression test for https://github.com/nix-rust/nix/issues/1819 +#[cfg(any(target_os = "android", target_os = "linux",))] +#[test] +fn test_so_type_unknown() { + use nix::errno::Errno; + + require_capability!("test_so_type", CAP_NET_RAW); + let sockfd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) }; + assert!(sockfd >= 0, "Error opening socket: {}", nix::Error::last()); + + assert_eq!(Err(Errno::EINVAL), getsockopt(sockfd, sockopt::SockType)); +} + +// The CI doesn't supported getsockopt and setsockopt on emulated processors. +// It's believed that a QEMU issue, the tests run ok on a fully emulated system. +// Current CI just run the binary with QEMU but the Kernel remains the same as the host. +// So the syscall doesn't work properly unless the kernel is also emulated. +#[test] +#[cfg(all( + any(target_arch = "x86", target_arch = "x86_64"), + any(target_os = "freebsd", target_os = "linux") +))] +fn test_tcp_congestion() { + use std::ffi::OsString; + + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + None, + ) + .unwrap(); + + let val = getsockopt(fd, sockopt::TcpCongestion).unwrap(); + setsockopt(fd, sockopt::TcpCongestion, &val).unwrap(); + + setsockopt( + fd, + sockopt::TcpCongestion, + &OsString::from("tcp_congestion_does_not_exist"), + ) + .unwrap_err(); + + assert_eq!(getsockopt(fd, sockopt::TcpCongestion).unwrap(), val); +} + +#[test] +#[cfg(any(target_os = "android", target_os = "linux"))] +fn test_bindtodevice() { + skip_if_not_root!("test_bindtodevice"); + + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + None, + ) + .unwrap(); + + let val = getsockopt(fd, sockopt::BindToDevice).unwrap(); + setsockopt(fd, sockopt::BindToDevice, &val).unwrap(); + + assert_eq!(getsockopt(fd, sockopt::BindToDevice).unwrap(), val); +} + +#[test] +fn test_so_tcp_keepalive() { + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + setsockopt(fd, sockopt::KeepAlive, &true).unwrap(); + assert!(getsockopt(fd, sockopt::KeepAlive).unwrap()); + + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux" + ))] + { + let x = getsockopt(fd, sockopt::TcpKeepIdle).unwrap(); + setsockopt(fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap(); + assert_eq!(getsockopt(fd, sockopt::TcpKeepIdle).unwrap(), x + 1); + + let x = getsockopt(fd, sockopt::TcpKeepCount).unwrap(); + setsockopt(fd, sockopt::TcpKeepCount, &(x + 1)).unwrap(); + assert_eq!(getsockopt(fd, sockopt::TcpKeepCount).unwrap(), x + 1); + + let x = getsockopt(fd, sockopt::TcpKeepInterval).unwrap(); + setsockopt(fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap(); + assert_eq!(getsockopt(fd, sockopt::TcpKeepInterval).unwrap(), x + 1); + } +} + +#[test] +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(qemu, ignore)] +fn test_get_mtu() { + use nix::sys::socket::{bind, connect, SockaddrIn}; + use std::net::SocketAddrV4; + use std::str::FromStr; + + let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap(); + let std_sb = SocketAddrV4::from_str("127.0.0.1:4002").unwrap(); + + let usock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + SockProtocol::Udp, + ) + .unwrap(); + + // Bind and initiate connection + bind(usock, &SockaddrIn::from(std_sa)).unwrap(); + connect(usock, &SockaddrIn::from(std_sb)).unwrap(); + + // Loopback connections have 2^16 - the maximum - MTU + assert_eq!(getsockopt(usock, sockopt::IpMtu), Ok(u16::MAX as i32)) +} + +#[test] +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +fn test_ttl_opts() { + let fd4 = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(fd4, sockopt::Ipv4Ttl, &1) + .expect("setting ipv4ttl on an inet socket should succeed"); + let fd6 = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(fd6, sockopt::Ipv6Ttl, &1) + .expect("setting ipv6ttl on an inet6 socket should succeed"); +} + +#[test] +#[cfg(any(target_os = "ios", target_os = "macos"))] +fn test_dontfrag_opts() { + let fd4 = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + setsockopt(fd4, sockopt::IpDontFrag, &true) + .expect("setting IP_DONTFRAG on an inet stream socket should succeed"); + setsockopt(fd4, sockopt::IpDontFrag, &false).expect( + "unsetting IP_DONTFRAG on an inet stream socket should succeed", + ); + let fd4d = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(fd4d, sockopt::IpDontFrag, &true).expect( + "setting IP_DONTFRAG on an inet datagram socket should succeed", + ); + setsockopt(fd4d, sockopt::IpDontFrag, &false).expect( + "unsetting IP_DONTFRAG on an inet datagram socket should succeed", + ); +} + +#[test] +#[cfg(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", +))] +// Disable the test under emulation because it fails in Cirrus-CI. Lack +// of QEMU support is suspected. +#[cfg_attr(qemu, ignore)] +fn test_v6dontfrag_opts() { + let fd6 = socket( + AddressFamily::Inet6, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + setsockopt(fd6, sockopt::Ipv6DontFrag, &true).expect( + "setting IPV6_DONTFRAG on an inet6 stream socket should succeed", + ); + setsockopt(fd6, sockopt::Ipv6DontFrag, &false).expect( + "unsetting IPV6_DONTFRAG on an inet6 stream socket should succeed", + ); + let fd6d = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(fd6d, sockopt::Ipv6DontFrag, &true).expect( + "setting IPV6_DONTFRAG on an inet6 datagram socket should succeed", + ); + setsockopt(fd6d, sockopt::Ipv6DontFrag, &false).expect( + "unsetting IPV6_DONTFRAG on an inet6 datagram socket should succeed", + ); +} + +#[test] +#[cfg(target_os = "linux")] +fn test_so_priority() { + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + let priority = 3; + setsockopt(fd, sockopt::Priority, &priority).unwrap(); + assert_eq!(getsockopt(fd, sockopt::Priority).unwrap(), priority); +} + +#[test] +#[cfg(target_os = "linux")] +fn test_ip_tos() { + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + let tos = 0x80; // CS4 + setsockopt(fd, sockopt::IpTos, &tos).unwrap(); + assert_eq!(getsockopt(fd, sockopt::IpTos).unwrap(), tos); +} + +#[test] +#[cfg(target_os = "linux")] +// Disable the test under emulation because it fails in Cirrus-CI. Lack +// of QEMU support is suspected. +#[cfg_attr(qemu, ignore)] +fn test_ipv6_tclass() { + let fd = socket( + AddressFamily::Inet6, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + let class = 0x80; // CS4 + setsockopt(fd, sockopt::Ipv6TClass, &class).unwrap(); + assert_eq!(getsockopt(fd, sockopt::Ipv6TClass).unwrap(), class); +} diff --git a/vendor/nix-0.26.2/test/sys/test_stat.rs b/vendor/nix-0.26.2/test/sys/test_stat.rs new file mode 100644 index 0000000000000..426b4b6588eb7 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_stat.rs @@ -0,0 +1,29 @@ +// The conversion is not useless on all platforms. +#[allow(clippy::useless_conversion)] +#[cfg(target_os = "freebsd")] +#[test] +fn test_chflags() { + use nix::{ + sys::stat::{fstat, FileFlag}, + unistd::chflags, + }; + use std::os::unix::io::AsRawFd; + use tempfile::NamedTempFile; + + let f = NamedTempFile::new().unwrap(); + + let initial = FileFlag::from_bits_truncate( + fstat(f.as_raw_fd()).unwrap().st_flags.into(), + ); + // UF_OFFLINE is preserved by all FreeBSD file systems, but not interpreted + // in any way, so it's handy for testing. + let commanded = initial ^ FileFlag::UF_OFFLINE; + + chflags(f.path(), commanded).unwrap(); + + let changed = FileFlag::from_bits_truncate( + fstat(f.as_raw_fd()).unwrap().st_flags.into(), + ); + + assert_eq!(commanded, changed); +} diff --git a/vendor/nix-0.26.2/test/sys/test_sysinfo.rs b/vendor/nix-0.26.2/test/sys/test_sysinfo.rs new file mode 100644 index 0000000000000..2897366effc90 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_sysinfo.rs @@ -0,0 +1,20 @@ +use nix::sys::sysinfo::*; + +#[test] +fn sysinfo_works() { + let info = sysinfo().unwrap(); + + let (l1, l5, l15) = info.load_average(); + assert!(l1 >= 0.0); + assert!(l5 >= 0.0); + assert!(l15 >= 0.0); + + info.uptime(); // just test Duration construction + + assert!( + info.swap_free() <= info.swap_total(), + "more swap available than installed (free: {}, total: {})", + info.swap_free(), + info.swap_total() + ); +} diff --git a/vendor/nix-0.26.2/test/sys/test_termios.rs b/vendor/nix-0.26.2/test/sys/test_termios.rs new file mode 100644 index 0000000000000..aaf00084fa050 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_termios.rs @@ -0,0 +1,136 @@ +use std::os::unix::prelude::*; +use tempfile::tempfile; + +use nix::errno::Errno; +use nix::fcntl; +use nix::pty::openpty; +use nix::sys::termios::{self, tcgetattr, LocalFlags, OutputFlags}; +use nix::unistd::{close, read, write}; + +/// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s +fn write_all(f: RawFd, buf: &[u8]) { + let mut len = 0; + while len < buf.len() { + len += write(f, &buf[len..]).unwrap(); + } +} + +// Test tcgetattr on a terminal +#[test] +fn test_tcgetattr_pty() { + // openpty uses ptname(3) internally + let _m = crate::PTSNAME_MTX.lock(); + + let pty = openpty(None, None).expect("openpty failed"); + termios::tcgetattr(pty.slave).unwrap(); + close(pty.master).expect("closing the master failed"); + close(pty.slave).expect("closing the slave failed"); +} + +// Test tcgetattr on something that isn't a terminal +#[test] +fn test_tcgetattr_enotty() { + let file = tempfile().unwrap(); + assert_eq!( + termios::tcgetattr(file.as_raw_fd()).err(), + Some(Errno::ENOTTY) + ); +} + +// Test tcgetattr on an invalid file descriptor +#[test] +fn test_tcgetattr_ebadf() { + assert_eq!(termios::tcgetattr(-1).err(), Some(Errno::EBADF)); +} + +// Test modifying output flags +#[test] +fn test_output_flags() { + // openpty uses ptname(3) internally + let _m = crate::PTSNAME_MTX.lock(); + + // Open one pty to get attributes for the second one + let mut termios = { + let pty = openpty(None, None).expect("openpty failed"); + assert!(pty.master > 0); + assert!(pty.slave > 0); + let termios = tcgetattr(pty.slave).expect("tcgetattr failed"); + close(pty.master).unwrap(); + close(pty.slave).unwrap(); + termios + }; + + // Make sure postprocessing '\r' isn't specified by default or this test is useless. + assert!(!termios + .output_flags + .contains(OutputFlags::OPOST | OutputFlags::OCRNL)); + + // Specify that '\r' characters should be transformed to '\n' + // OPOST is specified to enable post-processing + termios + .output_flags + .insert(OutputFlags::OPOST | OutputFlags::OCRNL); + + // Open a pty + let pty = openpty(None, &termios).unwrap(); + assert!(pty.master > 0); + assert!(pty.slave > 0); + + // Write into the master + let string = "foofoofoo\r"; + write_all(pty.master, string.as_bytes()); + + // Read from the slave verifying that the output has been properly transformed + let mut buf = [0u8; 10]; + crate::read_exact(pty.slave, &mut buf); + let transformed_string = "foofoofoo\n"; + close(pty.master).unwrap(); + close(pty.slave).unwrap(); + assert_eq!(&buf, transformed_string.as_bytes()); +} + +// Test modifying local flags +#[test] +fn test_local_flags() { + // openpty uses ptname(3) internally + let _m = crate::PTSNAME_MTX.lock(); + + // Open one pty to get attributes for the second one + let mut termios = { + let pty = openpty(None, None).unwrap(); + assert!(pty.master > 0); + assert!(pty.slave > 0); + let termios = tcgetattr(pty.slave).unwrap(); + close(pty.master).unwrap(); + close(pty.slave).unwrap(); + termios + }; + + // Make sure echo is specified by default or this test is useless. + assert!(termios.local_flags.contains(LocalFlags::ECHO)); + + // Disable local echo + termios.local_flags.remove(LocalFlags::ECHO); + + // Open a new pty with our modified termios settings + let pty = openpty(None, &termios).unwrap(); + assert!(pty.master > 0); + assert!(pty.slave > 0); + + // Set the master is in nonblocking mode or reading will never return. + let flags = fcntl::fcntl(pty.master, fcntl::F_GETFL).unwrap(); + let new_flags = + fcntl::OFlag::from_bits_truncate(flags) | fcntl::OFlag::O_NONBLOCK; + fcntl::fcntl(pty.master, fcntl::F_SETFL(new_flags)).unwrap(); + + // Write into the master + let string = "foofoofoo\r"; + write_all(pty.master, string.as_bytes()); + + // Try to read from the master, which should not have anything as echoing was disabled. + let mut buf = [0u8; 10]; + let read = read(pty.master, &mut buf).unwrap_err(); + close(pty.master).unwrap(); + close(pty.slave).unwrap(); + assert_eq!(read, Errno::EAGAIN); +} diff --git a/vendor/nix-0.26.2/test/sys/test_timerfd.rs b/vendor/nix-0.26.2/test/sys/test_timerfd.rs new file mode 100644 index 0000000000000..08e292106cccb --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_timerfd.rs @@ -0,0 +1,69 @@ +use nix::sys::time::{TimeSpec, TimeValLike}; +use nix::sys::timerfd::{ + ClockId, Expiration, TimerFd, TimerFlags, TimerSetTimeFlags, +}; +use std::time::Instant; + +#[test] +pub fn test_timerfd_oneshot() { + let timer = + TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); + + let before = Instant::now(); + + timer + .set( + Expiration::OneShot(TimeSpec::seconds(1)), + TimerSetTimeFlags::empty(), + ) + .unwrap(); + + timer.wait().unwrap(); + + let millis = before.elapsed().as_millis(); + assert!(millis > 900); +} + +#[test] +pub fn test_timerfd_interval() { + let timer = + TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); + + let before = Instant::now(); + timer + .set( + Expiration::IntervalDelayed( + TimeSpec::seconds(1), + TimeSpec::seconds(2), + ), + TimerSetTimeFlags::empty(), + ) + .unwrap(); + + timer.wait().unwrap(); + + let start_delay = before.elapsed().as_millis(); + assert!(start_delay > 900); + + timer.wait().unwrap(); + + let interval_delay = before.elapsed().as_millis(); + assert!(interval_delay > 2900); +} + +#[test] +pub fn test_timerfd_unset() { + let timer = + TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); + + timer + .set( + Expiration::OneShot(TimeSpec::seconds(1)), + TimerSetTimeFlags::empty(), + ) + .unwrap(); + + timer.unset().unwrap(); + + assert!(timer.get().unwrap().is_none()); +} diff --git a/vendor/nix-0.26.2/test/sys/test_uio.rs b/vendor/nix-0.26.2/test/sys/test_uio.rs new file mode 100644 index 0000000000000..0f4b8a65680cc --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_uio.rs @@ -0,0 +1,270 @@ +use nix::sys::uio::*; +use nix::unistd::*; +use rand::distributions::Alphanumeric; +use rand::{thread_rng, Rng}; +use std::fs::OpenOptions; +use std::io::IoSlice; +use std::os::unix::io::AsRawFd; +use std::{cmp, iter}; + +#[cfg(not(target_os = "redox"))] +use std::io::IoSliceMut; + +use tempfile::tempdir; +#[cfg(not(target_os = "redox"))] +use tempfile::tempfile; + +#[test] +fn test_writev() { + let mut to_write = Vec::with_capacity(16 * 128); + for _ in 0..16 { + let s: String = thread_rng() + .sample_iter(&Alphanumeric) + .map(char::from) + .take(128) + .collect(); + let b = s.as_bytes(); + to_write.extend(b.iter().cloned()); + } + // Allocate and fill iovecs + let mut iovecs = Vec::new(); + let mut consumed = 0; + while consumed < to_write.len() { + let left = to_write.len() - consumed; + let slice_len = if left <= 64 { + left + } else { + thread_rng().gen_range(64..cmp::min(256, left)) + }; + let b = &to_write[consumed..consumed + slice_len]; + iovecs.push(IoSlice::new(b)); + consumed += slice_len; + } + let pipe_res = pipe(); + let (reader, writer) = pipe_res.expect("Couldn't create pipe"); + // FileDesc will close its filedesc (reader). + let mut read_buf: Vec = iter::repeat(0u8).take(128 * 16).collect(); + // Blocking io, should write all data. + let write_res = writev(writer, &iovecs); + let written = write_res.expect("couldn't write"); + // Check whether we written all data + assert_eq!(to_write.len(), written); + let read_res = read(reader, &mut read_buf[..]); + let read = read_res.expect("couldn't read"); + // Check we have read as much as we written + assert_eq!(read, written); + // Check equality of written and read data + assert_eq!(&to_write, &read_buf); + close(writer).expect("closed writer"); + close(reader).expect("closed reader"); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_readv() { + let s: String = thread_rng() + .sample_iter(&Alphanumeric) + .map(char::from) + .take(128) + .collect(); + let to_write = s.as_bytes().to_vec(); + let mut storage = Vec::new(); + let mut allocated = 0; + while allocated < to_write.len() { + let left = to_write.len() - allocated; + let vec_len = if left <= 64 { + left + } else { + thread_rng().gen_range(64..cmp::min(256, left)) + }; + let v: Vec = iter::repeat(0u8).take(vec_len).collect(); + storage.push(v); + allocated += vec_len; + } + let mut iovecs = Vec::with_capacity(storage.len()); + for v in &mut storage { + iovecs.push(IoSliceMut::new(&mut v[..])); + } + let (reader, writer) = pipe().expect("couldn't create pipe"); + // Blocking io, should write all data. + write(writer, &to_write).expect("write failed"); + let read = readv(reader, &mut iovecs[..]).expect("read failed"); + // Check whether we've read all data + assert_eq!(to_write.len(), read); + // Cccumulate data from iovecs + let mut read_buf = Vec::with_capacity(to_write.len()); + for iovec in &iovecs { + read_buf.extend(iovec.iter().cloned()); + } + // Check whether iovecs contain all written data + assert_eq!(read_buf.len(), to_write.len()); + // Check equality of written and read data + assert_eq!(&read_buf, &to_write); + close(reader).expect("couldn't close reader"); + close(writer).expect("couldn't close writer"); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_pwrite() { + use std::io::Read; + + let mut file = tempfile().unwrap(); + let buf = [1u8; 8]; + assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8)); + let mut file_content = Vec::new(); + file.read_to_end(&mut file_content).unwrap(); + let mut expected = vec![0u8; 8]; + expected.extend(vec![1; 8]); + assert_eq!(file_content, expected); +} + +#[test] +fn test_pread() { + use std::io::Write; + + let tempdir = tempdir().unwrap(); + + let path = tempdir.path().join("pread_test_file"); + let mut file = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + let file_content: Vec = (0..64).collect(); + file.write_all(&file_content).unwrap(); + + let mut buf = [0u8; 16]; + assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16)); + let expected: Vec<_> = (16..32).collect(); + assert_eq!(&buf[..], &expected[..]); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_pwritev() { + use std::io::Read; + + let to_write: Vec = (0..128).collect(); + let expected: Vec = [vec![0; 100], to_write.clone()].concat(); + + let iovecs = [ + IoSlice::new(&to_write[0..17]), + IoSlice::new(&to_write[17..64]), + IoSlice::new(&to_write[64..128]), + ]; + + let tempdir = tempdir().unwrap(); + + // pwritev them into a temporary file + let path = tempdir.path().join("pwritev_test_file"); + let mut file = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + + let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap(); + assert_eq!(written, to_write.len()); + + // Read the data back and make sure it matches + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); + assert_eq!(contents, expected); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_preadv() { + use std::io::Write; + + let to_write: Vec = (0..200).collect(); + let expected: Vec = (100..200).collect(); + + let tempdir = tempdir().unwrap(); + + let path = tempdir.path().join("preadv_test_file"); + + let mut file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + file.write_all(&to_write).unwrap(); + + let mut buffers: Vec> = vec![vec![0; 24], vec![0; 1], vec![0; 75]]; + + { + // Borrow the buffers into IoVecs and preadv into them + let mut iovecs: Vec<_> = buffers + .iter_mut() + .map(|buf| IoSliceMut::new(&mut buf[..])) + .collect(); + assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100)); + } + + let all = buffers.concat(); + assert_eq!(all, expected); +} + +#[test] +#[cfg(all(target_os = "linux", not(target_env = "uclibc")))] +// uclibc doesn't implement process_vm_readv +// qemu-user doesn't implement process_vm_readv/writev on most arches +#[cfg_attr(qemu, ignore)] +fn test_process_vm_readv() { + use crate::*; + use nix::sys::signal::*; + use nix::sys::wait::*; + use nix::unistd::ForkResult::*; + + require_capability!("test_process_vm_readv", CAP_SYS_PTRACE); + let _m = crate::FORK_MTX.lock(); + + // Pre-allocate memory in the child, since allocation isn't safe + // post-fork (~= async-signal-safe) + let mut vector = vec![1u8, 2, 3, 4, 5]; + + let (r, w) = pipe().unwrap(); + match unsafe { fork() }.expect("Error: Fork Failed") { + Parent { child } => { + close(w).unwrap(); + // wait for child + read(r, &mut [0u8]).unwrap(); + close(r).unwrap(); + + let ptr = vector.as_ptr() as usize; + let remote_iov = RemoteIoVec { base: ptr, len: 5 }; + let mut buf = vec![0u8; 5]; + + let ret = process_vm_readv( + child, + &mut [IoSliceMut::new(&mut buf)], + &[remote_iov], + ); + + kill(child, SIGTERM).unwrap(); + waitpid(child, None).unwrap(); + + assert_eq!(Ok(5), ret); + assert_eq!(20u8, buf.iter().sum()); + } + Child => { + let _ = close(r); + for i in &mut vector { + *i += 1; + } + let _ = write(w, b"\0"); + let _ = close(w); + loop { + pause(); + } + } + } +} diff --git a/vendor/nix-0.26.2/test/sys/test_wait.rs b/vendor/nix-0.26.2/test/sys/test_wait.rs new file mode 100644 index 0000000000000..d472f1ec19b88 --- /dev/null +++ b/vendor/nix-0.26.2/test/sys/test_wait.rs @@ -0,0 +1,257 @@ +use libc::_exit; +use nix::errno::Errno; +use nix::sys::signal::*; +use nix::sys::wait::*; +use nix::unistd::ForkResult::*; +use nix::unistd::*; + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_wait_signal() { + let _m = crate::FORK_MTX.lock(); + + // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe. + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => { + pause(); + unsafe { _exit(123) } + } + Parent { child } => { + kill(child, Some(SIGKILL)).expect("Error: Kill Failed"); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Signaled(child, SIGKILL, false)) + ); + } + } +} + +#[test] +#[cfg(any( + target_os = "android", + target_os = "freebsd", + //target_os = "haiku", + all(target_os = "linux", not(target_env = "uclibc")), +))] +#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] +fn test_waitid_signal() { + let _m = crate::FORK_MTX.lock(); + + // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe. + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => { + pause(); + unsafe { _exit(123) } + } + Parent { child } => { + kill(child, Some(SIGKILL)).expect("Error: Kill Failed"); + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::Signaled(child, SIGKILL, false)), + ); + } + } +} + +#[test] +fn test_wait_exit() { + let _m = crate::FORK_MTX.lock(); + + // Safe: Child only calls `_exit`, which is async-signal-safe. + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => unsafe { + _exit(12); + }, + Parent { child } => { + assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12))); + } + } +} + +#[cfg(not(target_os = "haiku"))] +#[test] +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "haiku", + all(target_os = "linux", not(target_env = "uclibc")), +))] +#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] +fn test_waitid_exit() { + let _m = crate::FORK_MTX.lock(); + + // Safe: Child only calls `_exit`, which is async-signal-safe. + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => unsafe { + _exit(12); + }, + Parent { child } => { + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::Exited(child, 12)), + ); + } + } +} + +#[test] +fn test_waitstatus_from_raw() { + let pid = Pid::from_raw(1); + assert_eq!( + WaitStatus::from_raw(pid, 0x0002), + Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)) + ); + assert_eq!( + WaitStatus::from_raw(pid, 0x0200), + Ok(WaitStatus::Exited(pid, 2)) + ); + assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Errno::EINVAL)); +} + +#[test] +fn test_waitstatus_pid() { + let _m = crate::FORK_MTX.lock(); + + match unsafe { fork() }.unwrap() { + Child => unsafe { _exit(0) }, + Parent { child } => { + let status = waitpid(child, None).unwrap(); + assert_eq!(status.pid(), Some(child)); + } + } +} + +#[test] +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "haiku", + all(target_os = "linux", not(target_env = "uclibc")), +))] +fn test_waitid_pid() { + let _m = crate::FORK_MTX.lock(); + + match unsafe { fork() }.unwrap() { + Child => unsafe { _exit(0) }, + Parent { child } => { + let status = waitid(Id::Pid(child), WaitPidFlag::WEXITED).unwrap(); + assert_eq!(status.pid(), Some(child)); + } + } +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +// FIXME: qemu-user doesn't implement ptrace on most arches +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +mod ptrace { + use crate::*; + use libc::_exit; + use nix::sys::ptrace::{self, Event, Options}; + use nix::sys::signal::*; + use nix::sys::wait::*; + use nix::unistd::ForkResult::*; + use nix::unistd::*; + + fn ptrace_child() -> ! { + ptrace::traceme().unwrap(); + // As recommended by ptrace(2), raise SIGTRAP to pause the child + // until the parent is ready to continue + raise(SIGTRAP).unwrap(); + unsafe { _exit(0) } + } + + fn ptrace_wait_parent(child: Pid) { + // Wait for the raised SIGTRAP + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Stopped(child, SIGTRAP)) + ); + // We want to test a syscall stop and a PTRACE_EVENT stop + ptrace::setoptions( + child, + Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT, + ) + .expect("setoptions failed"); + + // First, stop on the next system call, which will be exit() + ptrace::syscall(child, None).expect("syscall failed"); + assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); + // Then get the ptrace event for the process exiting + ptrace::cont(child, None).expect("cont failed"); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::PtraceEvent( + child, + SIGTRAP, + Event::PTRACE_EVENT_EXIT as i32 + )) + ); + // Finally get the normal wait() result, now that the process has exited + ptrace::cont(child, None).expect("cont failed"); + assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0))); + } + + #[cfg(not(target_env = "uclibc"))] + fn ptrace_waitid_parent(child: Pid) { + // Wait for the raised SIGTRAP + // + // Unlike waitpid(), waitid() can distinguish trap events from regular + // stop events, so unlike ptrace_wait_parent(), we get a PtraceEvent here + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::PtraceEvent(child, SIGTRAP, 0)), + ); + // We want to test a syscall stop and a PTRACE_EVENT stop + ptrace::setoptions( + child, + Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT, + ) + .expect("setopts failed"); + + // First, stop on the next system call, which will be exit() + ptrace::syscall(child, None).expect("syscall failed"); + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::PtraceSyscall(child)), + ); + // Then get the ptrace event for the process exiting + ptrace::cont(child, None).expect("cont failed"); + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::PtraceEvent( + child, + SIGTRAP, + Event::PTRACE_EVENT_EXIT as i32 + )), + ); + // Finally get the normal wait() result, now that the process has exited + ptrace::cont(child, None).expect("cont failed"); + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::Exited(child, 0)), + ); + } + + #[test] + fn test_wait_ptrace() { + require_capability!("test_wait_ptrace", CAP_SYS_PTRACE); + let _m = crate::FORK_MTX.lock(); + + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => ptrace_child(), + Parent { child } => ptrace_wait_parent(child), + } + } + + #[test] + #[cfg(not(target_env = "uclibc"))] + fn test_waitid_ptrace() { + require_capability!("test_waitid_ptrace", CAP_SYS_PTRACE); + let _m = crate::FORK_MTX.lock(); + + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => ptrace_child(), + Parent { child } => ptrace_waitid_parent(child), + } + } +} diff --git a/vendor/nix-0.26.2/test/test.rs b/vendor/nix-0.26.2/test/test.rs new file mode 100644 index 0000000000000..6b42aad95040c --- /dev/null +++ b/vendor/nix-0.26.2/test/test.rs @@ -0,0 +1,124 @@ +#[macro_use] +extern crate cfg_if; +#[cfg_attr(not(any(target_os = "redox", target_os = "haiku")), macro_use)] +extern crate nix; +#[macro_use] +extern crate lazy_static; + +mod common; +mod sys; +#[cfg(not(target_os = "redox"))] +mod test_dir; +mod test_fcntl; +#[cfg(any(target_os = "android", target_os = "linux"))] +mod test_kmod; +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "fushsia", + target_os = "linux", + target_os = "netbsd" +))] +mod test_mq; +#[cfg(not(target_os = "redox"))] +mod test_net; +mod test_nix_path; +#[cfg(target_os = "freebsd")] +mod test_nmount; +mod test_poll; +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] +mod test_pty; +mod test_resource; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + all(target_os = "freebsd", fbsd14), + target_os = "linux" +))] +mod test_sched; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos" +))] +mod test_sendfile; +mod test_stat; +mod test_time; +#[cfg(all( + any( + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd" + ), + feature = "time", + feature = "signal" +))] +mod test_timer; +mod test_unistd; + +use nix::unistd::{chdir, getcwd, read}; +use parking_lot::{Mutex, RwLock, RwLockWriteGuard}; +use std::os::unix::io::RawFd; +use std::path::PathBuf; + +/// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s +fn read_exact(f: RawFd, buf: &mut [u8]) { + let mut len = 0; + while len < buf.len() { + // get_mut would be better than split_at_mut, but it requires nightly + let (_, remaining) = buf.split_at_mut(len); + len += read(f, remaining).unwrap(); + } +} + +lazy_static! { + /// Any test that changes the process's current working directory must grab + /// the RwLock exclusively. Any process that cares about the current + /// working directory must grab it shared. + pub static ref CWD_LOCK: RwLock<()> = RwLock::new(()); + /// Any test that creates child processes must grab this mutex, regardless + /// of what it does with those children. + pub static ref FORK_MTX: Mutex<()> = Mutex::new(()); + /// Any test that changes the process's supplementary groups must grab this + /// mutex + pub static ref GROUPS_MTX: Mutex<()> = Mutex::new(()); + /// Any tests that loads or unloads kernel modules must grab this mutex + pub static ref KMOD_MTX: Mutex<()> = Mutex::new(()); + /// Any test that calls ptsname(3) must grab this mutex. + pub static ref PTSNAME_MTX: Mutex<()> = Mutex::new(()); + /// Any test that alters signal handling must grab this mutex. + pub static ref SIGNAL_MTX: Mutex<()> = Mutex::new(()); +} + +/// RAII object that restores a test's original directory on drop +struct DirRestore<'a> { + d: PathBuf, + _g: RwLockWriteGuard<'a, ()>, +} + +impl<'a> DirRestore<'a> { + fn new() -> Self { + let guard = crate::CWD_LOCK.write(); + DirRestore { + _g: guard, + d: getcwd().unwrap(), + } + } +} + +impl<'a> Drop for DirRestore<'a> { + fn drop(&mut self) { + let r = chdir(&self.d); + if std::thread::panicking() { + r.unwrap(); + } + } +} diff --git a/vendor/nix-0.26.2/test/test_clearenv.rs b/vendor/nix-0.26.2/test/test_clearenv.rs new file mode 100644 index 0000000000000..28a77680498ca --- /dev/null +++ b/vendor/nix-0.26.2/test/test_clearenv.rs @@ -0,0 +1,9 @@ +use std::env; + +#[test] +fn clearenv() { + env::set_var("FOO", "BAR"); + unsafe { nix::env::clearenv() }.unwrap(); + assert_eq!(env::var("FOO").unwrap_err(), env::VarError::NotPresent); + assert_eq!(env::vars().count(), 0); +} diff --git a/vendor/nix-0.26.2/test/test_dir.rs b/vendor/nix-0.26.2/test/test_dir.rs new file mode 100644 index 0000000000000..2af4aa5c0aa6f --- /dev/null +++ b/vendor/nix-0.26.2/test/test_dir.rs @@ -0,0 +1,65 @@ +use nix::dir::{Dir, Type}; +use nix::fcntl::OFlag; +use nix::sys::stat::Mode; +use std::fs::File; +use tempfile::tempdir; + +#[cfg(test)] +fn flags() -> OFlag { + #[cfg(target_os = "illumos")] + let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC; + + #[cfg(not(target_os = "illumos"))] + let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC | OFlag::O_DIRECTORY; + + f +} + +#[test] +#[allow(clippy::unnecessary_sort_by)] // False positive +fn read() { + let tmp = tempdir().unwrap(); + File::create(tmp.path().join("foo")).unwrap(); + std::os::unix::fs::symlink("foo", tmp.path().join("bar")).unwrap(); + let mut dir = Dir::open(tmp.path(), flags(), Mode::empty()).unwrap(); + let mut entries: Vec<_> = dir.iter().map(|e| e.unwrap()).collect(); + entries.sort_by(|a, b| a.file_name().cmp(b.file_name())); + let entry_names: Vec<_> = entries + .iter() + .map(|e| e.file_name().to_str().unwrap().to_owned()) + .collect(); + assert_eq!(&entry_names[..], &[".", "..", "bar", "foo"]); + + // Check file types. The system is allowed to return DT_UNKNOWN (aka None here) but if it does + // return a type, ensure it's correct. + assert!(&[Some(Type::Directory), None].contains(&entries[0].file_type())); // .: dir + assert!(&[Some(Type::Directory), None].contains(&entries[1].file_type())); // ..: dir + assert!(&[Some(Type::Symlink), None].contains(&entries[2].file_type())); // bar: symlink + assert!(&[Some(Type::File), None].contains(&entries[3].file_type())); // foo: regular file +} + +#[test] +fn rewind() { + let tmp = tempdir().unwrap(); + let mut dir = Dir::open(tmp.path(), flags(), Mode::empty()).unwrap(); + let entries1: Vec<_> = dir + .iter() + .map(|e| e.unwrap().file_name().to_owned()) + .collect(); + let entries2: Vec<_> = dir + .iter() + .map(|e| e.unwrap().file_name().to_owned()) + .collect(); + let entries3: Vec<_> = dir + .into_iter() + .map(|e| e.unwrap().file_name().to_owned()) + .collect(); + assert_eq!(entries1, entries2); + assert_eq!(entries2, entries3); +} + +#[cfg(not(target_os = "haiku"))] +#[test] +fn ebadf() { + assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::EBADF); +} diff --git a/vendor/nix-0.26.2/test/test_fcntl.rs b/vendor/nix-0.26.2/test/test_fcntl.rs new file mode 100644 index 0000000000000..e51044a069cf0 --- /dev/null +++ b/vendor/nix-0.26.2/test/test_fcntl.rs @@ -0,0 +1,565 @@ +#[cfg(not(target_os = "redox"))] +use nix::errno::*; +#[cfg(not(target_os = "redox"))] +use nix::fcntl::{open, readlink, OFlag}; +#[cfg(not(target_os = "redox"))] +use nix::fcntl::{openat, readlinkat, renameat}; +#[cfg(all( + target_os = "linux", + target_env = "gnu", + any( + target_arch = "x86_64", + target_arch = "x32", + target_arch = "powerpc", + target_arch = "s390x" + ) +))] +use nix::fcntl::{renameat2, RenameFlags}; +#[cfg(not(target_os = "redox"))] +use nix::sys::stat::Mode; +#[cfg(not(target_os = "redox"))] +use nix::unistd::{close, read}; +#[cfg(not(target_os = "redox"))] +use std::fs::File; +#[cfg(not(target_os = "redox"))] +use std::io::prelude::*; +#[cfg(not(target_os = "redox"))] +use std::os::unix::fs; +#[cfg(not(target_os = "redox"))] +use tempfile::{self, NamedTempFile}; + +#[test] +#[cfg(not(target_os = "redox"))] +// QEMU does not handle openat well enough to satisfy this test +// https://gitlab.com/qemu-project/qemu/-/issues/829 +#[cfg_attr(qemu, ignore)] +fn test_openat() { + const CONTENTS: &[u8] = b"abcd"; + let mut tmp = NamedTempFile::new().unwrap(); + tmp.write_all(CONTENTS).unwrap(); + + let dirfd = + open(tmp.path().parent().unwrap(), OFlag::empty(), Mode::empty()) + .unwrap(); + let fd = openat( + dirfd, + tmp.path().file_name().unwrap(), + OFlag::O_RDONLY, + Mode::empty(), + ) + .unwrap(); + + let mut buf = [0u8; 1024]; + assert_eq!(4, read(fd, &mut buf).unwrap()); + assert_eq!(CONTENTS, &buf[0..4]); + + close(fd).unwrap(); + close(dirfd).unwrap(); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_renameat() { + let old_dir = tempfile::tempdir().unwrap(); + let old_dirfd = + open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let old_path = old_dir.path().join("old"); + File::create(old_path).unwrap(); + let new_dir = tempfile::tempdir().unwrap(); + let new_dirfd = + open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap(); + assert_eq!( + renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(), + Errno::ENOENT + ); + close(old_dirfd).unwrap(); + close(new_dirfd).unwrap(); + assert!(new_dir.path().join("new").exists()); +} + +#[test] +#[cfg(all( + target_os = "linux", + target_env = "gnu", + any( + target_arch = "x86_64", + target_arch = "x32", + target_arch = "powerpc", + target_arch = "s390x" + ) +))] +fn test_renameat2_behaves_like_renameat_with_no_flags() { + let old_dir = tempfile::tempdir().unwrap(); + let old_dirfd = + open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let old_path = old_dir.path().join("old"); + File::create(old_path).unwrap(); + let new_dir = tempfile::tempdir().unwrap(); + let new_dirfd = + open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + renameat2( + Some(old_dirfd), + "old", + Some(new_dirfd), + "new", + RenameFlags::empty(), + ) + .unwrap(); + assert_eq!( + renameat2( + Some(old_dirfd), + "old", + Some(new_dirfd), + "new", + RenameFlags::empty() + ) + .unwrap_err(), + Errno::ENOENT + ); + close(old_dirfd).unwrap(); + close(new_dirfd).unwrap(); + assert!(new_dir.path().join("new").exists()); +} + +#[test] +#[cfg(all( + target_os = "linux", + target_env = "gnu", + any( + target_arch = "x86_64", + target_arch = "x32", + target_arch = "powerpc", + target_arch = "s390x" + ) +))] +fn test_renameat2_exchange() { + let old_dir = tempfile::tempdir().unwrap(); + let old_dirfd = + open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let old_path = old_dir.path().join("old"); + { + let mut old_f = File::create(&old_path).unwrap(); + old_f.write_all(b"old").unwrap(); + } + let new_dir = tempfile::tempdir().unwrap(); + let new_dirfd = + open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let new_path = new_dir.path().join("new"); + { + let mut new_f = File::create(&new_path).unwrap(); + new_f.write_all(b"new").unwrap(); + } + renameat2( + Some(old_dirfd), + "old", + Some(new_dirfd), + "new", + RenameFlags::RENAME_EXCHANGE, + ) + .unwrap(); + let mut buf = String::new(); + let mut new_f = File::open(&new_path).unwrap(); + new_f.read_to_string(&mut buf).unwrap(); + assert_eq!(buf, "old"); + buf = "".to_string(); + let mut old_f = File::open(&old_path).unwrap(); + old_f.read_to_string(&mut buf).unwrap(); + assert_eq!(buf, "new"); + close(old_dirfd).unwrap(); + close(new_dirfd).unwrap(); +} + +#[test] +#[cfg(all( + target_os = "linux", + target_env = "gnu", + any( + target_arch = "x86_64", + target_arch = "x32", + target_arch = "powerpc", + target_arch = "s390x" + ) +))] +fn test_renameat2_noreplace() { + let old_dir = tempfile::tempdir().unwrap(); + let old_dirfd = + open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let old_path = old_dir.path().join("old"); + File::create(old_path).unwrap(); + let new_dir = tempfile::tempdir().unwrap(); + let new_dirfd = + open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let new_path = new_dir.path().join("new"); + File::create(new_path).unwrap(); + assert_eq!( + renameat2( + Some(old_dirfd), + "old", + Some(new_dirfd), + "new", + RenameFlags::RENAME_NOREPLACE + ) + .unwrap_err(), + Errno::EEXIST + ); + close(old_dirfd).unwrap(); + close(new_dirfd).unwrap(); + assert!(new_dir.path().join("new").exists()); + assert!(old_dir.path().join("old").exists()); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_readlink() { + let tempdir = tempfile::tempdir().unwrap(); + let src = tempdir.path().join("a"); + let dst = tempdir.path().join("b"); + println!("a: {:?}, b: {:?}", &src, &dst); + fs::symlink(src.as_path(), dst.as_path()).unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let expected_dir = src.to_str().unwrap(); + + assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir); + assert_eq!( + readlinkat(dirfd, "b").unwrap().to_str().unwrap(), + expected_dir + ); +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +mod linux_android { + use libc::loff_t; + use std::io::prelude::*; + use std::io::IoSlice; + use std::os::unix::prelude::*; + + use nix::fcntl::*; + use nix::unistd::{close, pipe, read, write}; + + use tempfile::tempfile; + #[cfg(any(target_os = "linux"))] + use tempfile::NamedTempFile; + + use crate::*; + + /// This test creates a temporary file containing the contents + /// 'foobarbaz' and uses the `copy_file_range` call to transfer + /// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The + /// resulting file is read and should contain the contents `bar`. + /// The from_offset should be updated by the call to reflect + /// the 3 bytes read (6). + #[test] + // QEMU does not support copy_file_range. Skip under qemu + #[cfg_attr(qemu, ignore)] + fn test_copy_file_range() { + const CONTENTS: &[u8] = b"foobarbaz"; + + let mut tmp1 = tempfile().unwrap(); + let mut tmp2 = tempfile().unwrap(); + + tmp1.write_all(CONTENTS).unwrap(); + tmp1.flush().unwrap(); + + let mut from_offset: i64 = 3; + copy_file_range( + tmp1.as_raw_fd(), + Some(&mut from_offset), + tmp2.as_raw_fd(), + None, + 3, + ) + .unwrap(); + + let mut res: String = String::new(); + tmp2.rewind().unwrap(); + tmp2.read_to_string(&mut res).unwrap(); + + assert_eq!(res, String::from("bar")); + assert_eq!(from_offset, 6); + } + + #[test] + fn test_splice() { + const CONTENTS: &[u8] = b"abcdef123456"; + let mut tmp = tempfile().unwrap(); + tmp.write_all(CONTENTS).unwrap(); + + let (rd, wr) = pipe().unwrap(); + let mut offset: loff_t = 5; + let res = splice( + tmp.as_raw_fd(), + Some(&mut offset), + wr, + None, + 2, + SpliceFFlags::empty(), + ) + .unwrap(); + + assert_eq!(2, res); + + let mut buf = [0u8; 1024]; + assert_eq!(2, read(rd, &mut buf).unwrap()); + assert_eq!(b"f1", &buf[0..2]); + assert_eq!(7, offset); + + close(rd).unwrap(); + close(wr).unwrap(); + } + + #[test] + fn test_tee() { + let (rd1, wr1) = pipe().unwrap(); + let (rd2, wr2) = pipe().unwrap(); + + write(wr1, b"abc").unwrap(); + let res = tee(rd1, wr2, 2, SpliceFFlags::empty()).unwrap(); + + assert_eq!(2, res); + + let mut buf = [0u8; 1024]; + + // Check the tee'd bytes are at rd2. + assert_eq!(2, read(rd2, &mut buf).unwrap()); + assert_eq!(b"ab", &buf[0..2]); + + // Check all the bytes are still at rd1. + assert_eq!(3, read(rd1, &mut buf).unwrap()); + assert_eq!(b"abc", &buf[0..3]); + + close(rd1).unwrap(); + close(wr1).unwrap(); + close(rd2).unwrap(); + close(wr2).unwrap(); + } + + #[test] + fn test_vmsplice() { + let (rd, wr) = pipe().unwrap(); + + let buf1 = b"abcdef"; + let buf2 = b"defghi"; + let iovecs = vec![IoSlice::new(&buf1[0..3]), IoSlice::new(&buf2[0..3])]; + + let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap(); + + assert_eq!(6, res); + + // Check the bytes can be read at rd. + let mut buf = [0u8; 32]; + assert_eq!(6, read(rd, &mut buf).unwrap()); + assert_eq!(b"abcdef", &buf[0..6]); + + close(rd).unwrap(); + close(wr).unwrap(); + } + + #[cfg(any(target_os = "linux"))] + #[test] + fn test_fallocate() { + let tmp = NamedTempFile::new().unwrap(); + + let fd = tmp.as_raw_fd(); + fallocate(fd, FallocateFlags::empty(), 0, 100).unwrap(); + + // Check if we read exactly 100 bytes + let mut buf = [0u8; 200]; + assert_eq!(100, read(fd, &mut buf).unwrap()); + } + + // The tests below are disabled for the listed targets + // due to OFD locks not being available in the kernel/libc + // versions used in the CI environment, probably because + // they run under QEMU. + + #[test] + #[cfg(all(target_os = "linux", not(target_env = "musl")))] + #[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile + fn test_ofd_write_lock() { + use nix::sys::stat::fstat; + use std::mem; + + let tmp = NamedTempFile::new().unwrap(); + + let fd = tmp.as_raw_fd(); + let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); + if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { + // OverlayFS is a union file system. It returns one inode value in + // stat(2), but a different one shows up in /proc/locks. So we must + // skip the test. + skip!("/proc/locks does not work on overlayfs"); + } + let inode = fstat(fd).expect("fstat failed").st_ino as usize; + + let mut flock: libc::flock = unsafe { + mem::zeroed() // required for Linux/mips + }; + flock.l_type = libc::F_WRLCK as libc::c_short; + flock.l_whence = libc::SEEK_SET as libc::c_short; + flock.l_start = 0; + flock.l_len = 0; + flock.l_pid = 0; + fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write lock failed"); + assert_eq!( + Some(("OFDLCK".to_string(), "WRITE".to_string())), + lock_info(inode) + ); + + flock.l_type = libc::F_UNLCK as libc::c_short; + fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write unlock failed"); + assert_eq!(None, lock_info(inode)); + } + + #[test] + #[cfg(all(target_os = "linux", not(target_env = "musl")))] + #[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile + fn test_ofd_read_lock() { + use nix::sys::stat::fstat; + use std::mem; + + let tmp = NamedTempFile::new().unwrap(); + + let fd = tmp.as_raw_fd(); + let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); + if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { + // OverlayFS is a union file system. It returns one inode value in + // stat(2), but a different one shows up in /proc/locks. So we must + // skip the test. + skip!("/proc/locks does not work on overlayfs"); + } + let inode = fstat(fd).expect("fstat failed").st_ino as usize; + + let mut flock: libc::flock = unsafe { + mem::zeroed() // required for Linux/mips + }; + flock.l_type = libc::F_RDLCK as libc::c_short; + flock.l_whence = libc::SEEK_SET as libc::c_short; + flock.l_start = 0; + flock.l_len = 0; + flock.l_pid = 0; + fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read lock failed"); + assert_eq!( + Some(("OFDLCK".to_string(), "READ".to_string())), + lock_info(inode) + ); + + flock.l_type = libc::F_UNLCK as libc::c_short; + fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read unlock failed"); + assert_eq!(None, lock_info(inode)); + } + + #[cfg(all(target_os = "linux", not(target_env = "musl")))] + fn lock_info(inode: usize) -> Option<(String, String)> { + use std::{fs::File, io::BufReader}; + + let file = File::open("/proc/locks").expect("open /proc/locks failed"); + let buf = BufReader::new(file); + + for line in buf.lines() { + let line = line.unwrap(); + let parts: Vec<_> = line.split_whitespace().collect(); + let lock_type = parts[1]; + let lock_access = parts[3]; + let ino_parts: Vec<_> = parts[5].split(':').collect(); + let ino: usize = ino_parts[2].parse().unwrap(); + if ino == inode { + return Some((lock_type.to_string(), lock_access.to_string())); + } + } + None + } +} + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "wasi", + target_env = "uclibc", + target_os = "freebsd" +))] +mod test_posix_fadvise { + + use nix::errno::Errno; + use nix::fcntl::*; + use nix::unistd::pipe; + use std::os::unix::io::{AsRawFd, RawFd}; + use tempfile::NamedTempFile; + + #[test] + fn test_success() { + let tmp = NamedTempFile::new().unwrap(); + let fd = tmp.as_raw_fd(); + posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED) + .expect("posix_fadvise failed"); + } + + #[test] + fn test_errno() { + let (rd, _wr) = pipe().unwrap(); + let res = posix_fadvise( + rd as RawFd, + 0, + 100, + PosixFadviseAdvice::POSIX_FADV_WILLNEED, + ); + assert_eq!(res, Err(Errno::ESPIPE)); + } +} + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "wasi", + target_os = "freebsd" +))] +mod test_posix_fallocate { + + use nix::errno::Errno; + use nix::fcntl::*; + use nix::unistd::pipe; + use std::{ + io::Read, + os::unix::io::{AsRawFd, RawFd}, + }; + use tempfile::NamedTempFile; + + #[test] + fn success() { + const LEN: usize = 100; + let mut tmp = NamedTempFile::new().unwrap(); + let fd = tmp.as_raw_fd(); + let res = posix_fallocate(fd, 0, LEN as libc::off_t); + match res { + Ok(_) => { + let mut data = [1u8; LEN]; + assert_eq!(tmp.read(&mut data).expect("read failure"), LEN); + assert_eq!(&data[..], &[0u8; LEN][..]); + } + Err(Errno::EINVAL) => { + // POSIX requires posix_fallocate to return EINVAL both for + // invalid arguments (i.e. len < 0) and if the operation is not + // supported by the file system. + // There's no way to tell for sure whether the file system + // supports posix_fallocate, so we must pass the test if it + // returns EINVAL. + } + _ => res.unwrap(), + } + } + + #[test] + fn errno() { + let (rd, _wr) = pipe().unwrap(); + let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err(); + match err { + Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (), + errno => panic!("unexpected errno {}", errno,), + } + } +} diff --git a/vendor/nix-0.26.2/test/test_kmod/hello_mod/Makefile b/vendor/nix-0.26.2/test/test_kmod/hello_mod/Makefile new file mode 100644 index 0000000000000..74c99b77e96e1 --- /dev/null +++ b/vendor/nix-0.26.2/test/test_kmod/hello_mod/Makefile @@ -0,0 +1,7 @@ +obj-m += hello.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean diff --git a/vendor/nix-0.26.2/test/test_kmod/hello_mod/hello.c b/vendor/nix-0.26.2/test/test_kmod/hello_mod/hello.c new file mode 100644 index 0000000000000..1c34987d2ac39 --- /dev/null +++ b/vendor/nix-0.26.2/test/test_kmod/hello_mod/hello.c @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: GPL-2.0+ or MIT + */ +#include +#include + +static int number= 1; +static char *who = "World"; + +module_param(number, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(myint, "Just some number"); +module_param(who, charp, 0000); +MODULE_PARM_DESC(who, "Whot to greet"); + +int init_module(void) +{ + printk(KERN_INFO "Hello %s (%d)!\n", who, number); + return 0; +} + +void cleanup_module(void) +{ + printk(KERN_INFO "Goodbye %s (%d)!\n", who, number); +} + +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/vendor/nix-0.26.2/test/test_kmod/mod.rs b/vendor/nix-0.26.2/test/test_kmod/mod.rs new file mode 100644 index 0000000000000..6f9aaa897f1de --- /dev/null +++ b/vendor/nix-0.26.2/test/test_kmod/mod.rs @@ -0,0 +1,188 @@ +use crate::*; +use std::fs::copy; +use std::path::PathBuf; +use std::process::Command; +use tempfile::{tempdir, TempDir}; + +fn compile_kernel_module() -> (PathBuf, String, TempDir) { + let _m = crate::FORK_MTX.lock(); + + let tmp_dir = + tempdir().expect("unable to create temporary build directory"); + + copy( + "test/test_kmod/hello_mod/hello.c", + tmp_dir.path().join("hello.c"), + ) + .expect("unable to copy hello.c to temporary build directory"); + copy( + "test/test_kmod/hello_mod/Makefile", + tmp_dir.path().join("Makefile"), + ) + .expect("unable to copy Makefile to temporary build directory"); + + let status = Command::new("make") + .current_dir(tmp_dir.path()) + .status() + .expect("failed to run make"); + + assert!(status.success()); + + // Return the relative path of the build kernel module + (tmp_dir.path().join("hello.ko"), "hello".to_owned(), tmp_dir) +} + +use nix::errno::Errno; +use nix::kmod::{delete_module, DeleteModuleFlags}; +use nix::kmod::{finit_module, init_module, ModuleInitFlags}; +use std::ffi::CString; +use std::fs::File; +use std::io::Read; + +#[test] +fn test_finit_and_delete_module() { + require_capability!("test_finit_and_delete_module", CAP_SYS_MODULE); + let _m0 = crate::KMOD_MTX.lock(); + let _m1 = crate::CWD_LOCK.read(); + + let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); + + let f = File::open(kmod_path).expect("unable to open kernel module"); + finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()) + .expect("unable to load kernel module"); + + delete_module( + &CString::new(kmod_name).unwrap(), + DeleteModuleFlags::empty(), + ) + .expect("unable to unload kernel module"); +} + +#[test] +fn test_finit_and_delete_module_with_params() { + require_capability!( + "test_finit_and_delete_module_with_params", + CAP_SYS_MODULE + ); + let _m0 = crate::KMOD_MTX.lock(); + let _m1 = crate::CWD_LOCK.read(); + + let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); + + let f = File::open(kmod_path).expect("unable to open kernel module"); + finit_module( + &f, + &CString::new("who=Rust number=2018").unwrap(), + ModuleInitFlags::empty(), + ) + .expect("unable to load kernel module"); + + delete_module( + &CString::new(kmod_name).unwrap(), + DeleteModuleFlags::empty(), + ) + .expect("unable to unload kernel module"); +} + +#[test] +fn test_init_and_delete_module() { + require_capability!("test_init_and_delete_module", CAP_SYS_MODULE); + let _m0 = crate::KMOD_MTX.lock(); + let _m1 = crate::CWD_LOCK.read(); + + let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); + + let mut f = File::open(kmod_path).expect("unable to open kernel module"); + let mut contents: Vec = Vec::new(); + f.read_to_end(&mut contents) + .expect("unable to read kernel module content to buffer"); + init_module(&contents, &CString::new("").unwrap()) + .expect("unable to load kernel module"); + + delete_module( + &CString::new(kmod_name).unwrap(), + DeleteModuleFlags::empty(), + ) + .expect("unable to unload kernel module"); +} + +#[test] +fn test_init_and_delete_module_with_params() { + require_capability!( + "test_init_and_delete_module_with_params", + CAP_SYS_MODULE + ); + let _m0 = crate::KMOD_MTX.lock(); + let _m1 = crate::CWD_LOCK.read(); + + let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); + + let mut f = File::open(kmod_path).expect("unable to open kernel module"); + let mut contents: Vec = Vec::new(); + f.read_to_end(&mut contents) + .expect("unable to read kernel module content to buffer"); + init_module(&contents, &CString::new("who=Nix number=2015").unwrap()) + .expect("unable to load kernel module"); + + delete_module( + &CString::new(kmod_name).unwrap(), + DeleteModuleFlags::empty(), + ) + .expect("unable to unload kernel module"); +} + +#[test] +fn test_finit_module_invalid() { + require_capability!("test_finit_module_invalid", CAP_SYS_MODULE); + let _m0 = crate::KMOD_MTX.lock(); + let _m1 = crate::CWD_LOCK.read(); + + let kmod_path = "/dev/zero"; + + let f = File::open(kmod_path).expect("unable to open kernel module"); + let result = + finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); + + assert_eq!(result.unwrap_err(), Errno::EINVAL); +} + +#[test] +fn test_finit_module_twice_and_delete_module() { + require_capability!( + "test_finit_module_twice_and_delete_module", + CAP_SYS_MODULE + ); + let _m0 = crate::KMOD_MTX.lock(); + let _m1 = crate::CWD_LOCK.read(); + + let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); + + let f = File::open(kmod_path).expect("unable to open kernel module"); + finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()) + .expect("unable to load kernel module"); + + let result = + finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); + + assert_eq!(result.unwrap_err(), Errno::EEXIST); + + delete_module( + &CString::new(kmod_name).unwrap(), + DeleteModuleFlags::empty(), + ) + .expect("unable to unload kernel module"); +} + +#[test] +fn test_delete_module_not_loaded() { + require_capability!("test_delete_module_not_loaded", CAP_SYS_MODULE); + let _m0 = crate::KMOD_MTX.lock(); + let _m1 = crate::CWD_LOCK.read(); + + let result = delete_module( + &CString::new("hello").unwrap(), + DeleteModuleFlags::empty(), + ); + + assert_eq!(result.unwrap_err(), Errno::ENOENT); +} diff --git a/vendor/nix-0.26.2/test/test_mount.rs b/vendor/nix-0.26.2/test/test_mount.rs new file mode 100644 index 0000000000000..2fd612e358b04 --- /dev/null +++ b/vendor/nix-0.26.2/test/test_mount.rs @@ -0,0 +1,271 @@ +mod common; + +// Implementation note: to allow unprivileged users to run it, this test makes +// use of user and mount namespaces. On systems that allow unprivileged user +// namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run +// without root. + +#[cfg(target_os = "linux")] +mod test_mount { + use std::fs::{self, File}; + use std::io::{self, Read, Write}; + use std::os::unix::fs::OpenOptionsExt; + use std::os::unix::fs::PermissionsExt; + use std::process::{self, Command}; + + use libc::{EACCES, EROFS}; + + use nix::errno::Errno; + use nix::mount::{mount, umount, MsFlags}; + use nix::sched::{unshare, CloneFlags}; + use nix::sys::stat::{self, Mode}; + use nix::unistd::getuid; + + static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh +exit 23"; + + const EXPECTED_STATUS: i32 = 23; + + const NONE: Option<&'static [u8]> = None; + #[allow(clippy::bind_instead_of_map)] // False positive + pub fn test_mount_tmpfs_without_flags_allows_rwx() { + let tempdir = tempfile::tempdir().unwrap(); + + mount( + NONE, + tempdir.path(), + Some(b"tmpfs".as_ref()), + MsFlags::empty(), + NONE, + ) + .unwrap_or_else(|e| panic!("mount failed: {}", e)); + + let test_path = tempdir.path().join("test"); + + // Verify write. + fs::OpenOptions::new() + .create(true) + .write(true) + .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) + .open(&test_path) + .or_else(|e| { + if Errno::from_i32(e.raw_os_error().unwrap()) + == Errno::EOVERFLOW + { + // Skip tests on certain Linux kernels which have a bug + // regarding tmpfs in namespaces. + // Ubuntu 14.04 and 16.04 are known to be affected; 16.10 is + // not. There is no legitimate reason for open(2) to return + // EOVERFLOW here. + // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1659087 + let stderr = io::stderr(); + let mut handle = stderr.lock(); + writeln!( + handle, + "Buggy Linux kernel detected. Skipping test." + ) + .unwrap(); + process::exit(0); + } else { + panic!("open failed: {}", e); + } + }) + .and_then(|mut f| f.write(SCRIPT_CONTENTS)) + .unwrap_or_else(|e| panic!("write failed: {}", e)); + + // Verify read. + let mut buf = Vec::new(); + File::open(&test_path) + .and_then(|mut f| f.read_to_end(&mut buf)) + .unwrap_or_else(|e| panic!("read failed: {}", e)); + assert_eq!(buf, SCRIPT_CONTENTS); + + // Verify execute. + assert_eq!( + EXPECTED_STATUS, + Command::new(&test_path) + .status() + .unwrap_or_else(|e| panic!("exec failed: {}", e)) + .code() + .unwrap_or_else(|| panic!("child killed by signal")) + ); + + umount(tempdir.path()) + .unwrap_or_else(|e| panic!("umount failed: {}", e)); + } + + pub fn test_mount_rdonly_disallows_write() { + let tempdir = tempfile::tempdir().unwrap(); + + mount( + NONE, + tempdir.path(), + Some(b"tmpfs".as_ref()), + MsFlags::MS_RDONLY, + NONE, + ) + .unwrap_or_else(|e| panic!("mount failed: {}", e)); + + // EROFS: Read-only file system + assert_eq!( + EROFS, + File::create(tempdir.path().join("test")) + .unwrap_err() + .raw_os_error() + .unwrap() + ); + + umount(tempdir.path()) + .unwrap_or_else(|e| panic!("umount failed: {}", e)); + } + + pub fn test_mount_noexec_disallows_exec() { + let tempdir = tempfile::tempdir().unwrap(); + + mount( + NONE, + tempdir.path(), + Some(b"tmpfs".as_ref()), + MsFlags::MS_NOEXEC, + NONE, + ) + .unwrap_or_else(|e| panic!("mount failed: {}", e)); + + let test_path = tempdir.path().join("test"); + + fs::OpenOptions::new() + .create(true) + .write(true) + .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) + .open(&test_path) + .and_then(|mut f| f.write(SCRIPT_CONTENTS)) + .unwrap_or_else(|e| panic!("write failed: {}", e)); + + // Verify that we cannot execute despite a+x permissions being set. + let mode = stat::Mode::from_bits_truncate( + fs::metadata(&test_path) + .map(|md| md.permissions().mode()) + .unwrap_or_else(|e| panic!("metadata failed: {}", e)), + ); + + assert!( + mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH), + "{:?} did not have execute permissions", + &test_path + ); + + // EACCES: Permission denied + assert_eq!( + EACCES, + Command::new(&test_path) + .status() + .unwrap_err() + .raw_os_error() + .unwrap() + ); + + umount(tempdir.path()) + .unwrap_or_else(|e| panic!("umount failed: {}", e)); + } + + pub fn test_mount_bind() { + let tempdir = tempfile::tempdir().unwrap(); + let file_name = "test"; + + { + let mount_point = tempfile::tempdir().unwrap(); + + mount( + Some(tempdir.path()), + mount_point.path(), + NONE, + MsFlags::MS_BIND, + NONE, + ) + .unwrap_or_else(|e| panic!("mount failed: {}", e)); + + fs::OpenOptions::new() + .create(true) + .write(true) + .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) + .open(mount_point.path().join(file_name)) + .and_then(|mut f| f.write(SCRIPT_CONTENTS)) + .unwrap_or_else(|e| panic!("write failed: {}", e)); + + umount(mount_point.path()) + .unwrap_or_else(|e| panic!("umount failed: {}", e)); + } + + // Verify the file written in the mount shows up in source directory, even + // after unmounting. + + let mut buf = Vec::new(); + File::open(tempdir.path().join(file_name)) + .and_then(|mut f| f.read_to_end(&mut buf)) + .unwrap_or_else(|e| panic!("read failed: {}", e)); + assert_eq!(buf, SCRIPT_CONTENTS); + } + + pub fn setup_namespaces() { + // Hold on to the uid in the parent namespace. + let uid = getuid(); + + unshare(CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_NEWUSER).unwrap_or_else(|e| { + let stderr = io::stderr(); + let mut handle = stderr.lock(); + writeln!(handle, + "unshare failed: {}. Are unprivileged user namespaces available?", + e).unwrap(); + writeln!(handle, "mount is not being tested").unwrap(); + // Exit with success because not all systems support unprivileged user namespaces, and + // that's not what we're testing for. + process::exit(0); + }); + + // Map user as uid 1000. + fs::OpenOptions::new() + .write(true) + .open("/proc/self/uid_map") + .and_then(|mut f| f.write(format!("1000 {} 1\n", uid).as_bytes())) + .unwrap_or_else(|e| panic!("could not write uid map: {}", e)); + } +} + +// Test runner + +/// Mimic normal test output (hackishly). +#[cfg(target_os = "linux")] +macro_rules! run_tests { + ( $($test_fn:ident),* ) => {{ + println!(); + + $( + print!("test test_mount::{} ... ", stringify!($test_fn)); + $test_fn(); + println!("ok"); + )* + + println!(); + }} +} + +#[cfg(target_os = "linux")] +fn main() { + use test_mount::{ + setup_namespaces, test_mount_bind, test_mount_noexec_disallows_exec, + test_mount_rdonly_disallows_write, + test_mount_tmpfs_without_flags_allows_rwx, + }; + skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1351"); + setup_namespaces(); + + run_tests!( + test_mount_tmpfs_without_flags_allows_rwx, + test_mount_rdonly_disallows_write, + test_mount_noexec_disallows_exec, + test_mount_bind + ); +} + +#[cfg(not(target_os = "linux"))] +fn main() {} diff --git a/vendor/nix-0.26.2/test/test_mq.rs b/vendor/nix-0.26.2/test/test_mq.rs new file mode 100644 index 0000000000000..7b48e7ac78f06 --- /dev/null +++ b/vendor/nix-0.26.2/test/test_mq.rs @@ -0,0 +1,190 @@ +use cfg_if::cfg_if; +use std::ffi::CString; +use std::str; + +use nix::errno::Errno; +use nix::mqueue::{mq_attr_member_t, mq_close, mq_open, mq_receive, mq_send}; +use nix::mqueue::{MQ_OFlag, MqAttr}; +use nix::sys::stat::Mode; + +// Defined as a macro such that the error source is reported as the caller's location. +macro_rules! assert_attr_eq { + ($read_attr:ident, $initial_attr:ident) => { + cfg_if! { + if #[cfg(any(target_os = "dragonfly", target_os = "netbsd"))] { + // NetBSD (and others which inherit its implementation) include other flags + // in read_attr, such as those specified by oflag. Just make sure at least + // the correct bits are set. + assert_eq!($read_attr.flags() & $initial_attr.flags(), $initial_attr.flags()); + assert_eq!($read_attr.maxmsg(), $initial_attr.maxmsg()); + assert_eq!($read_attr.msgsize(), $initial_attr.msgsize()); + assert_eq!($read_attr.curmsgs(), $initial_attr.curmsgs()); + } else { + assert_eq!($read_attr, $initial_attr); + } + } + } +} + +#[test] +fn test_mq_send_and_receive() { + const MSG_SIZE: mq_attr_member_t = 32; + let attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let mq_name = &CString::new(b"/a_nix_test_queue".as_ref()).unwrap(); + + let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; + let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; + let r0 = mq_open(mq_name, oflag0, mode, Some(&attr)); + if let Err(Errno::ENOSYS) = r0 { + println!("message queues not supported or module not loaded?"); + return; + }; + let mqd0 = r0.unwrap(); + let msg_to_send = "msg_1"; + mq_send(&mqd0, msg_to_send.as_bytes(), 1).unwrap(); + + let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY; + let mqd1 = mq_open(mq_name, oflag1, mode, Some(&attr)).unwrap(); + let mut buf = [0u8; 32]; + let mut prio = 0u32; + let len = mq_receive(&mqd1, &mut buf, &mut prio).unwrap(); + assert_eq!(prio, 1); + + mq_close(mqd1).unwrap(); + mq_close(mqd0).unwrap(); + assert_eq!(msg_to_send, str::from_utf8(&buf[0..len]).unwrap()); +} + +#[test] +fn test_mq_getattr() { + use nix::mqueue::mq_getattr; + const MSG_SIZE: mq_attr_member_t = 32; + let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); + let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; + let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; + let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); + if let Err(Errno::ENOSYS) = r { + println!("message queues not supported or module not loaded?"); + return; + }; + let mqd = r.unwrap(); + + let read_attr = mq_getattr(&mqd).unwrap(); + assert_attr_eq!(read_attr, initial_attr); + mq_close(mqd).unwrap(); +} + +// FIXME: Fix failures for mips in QEMU +#[test] +#[cfg_attr( + all(qemu, any(target_arch = "mips", target_arch = "mips64")), + ignore +)] +fn test_mq_setattr() { + use nix::mqueue::{mq_getattr, mq_setattr}; + const MSG_SIZE: mq_attr_member_t = 32; + let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); + let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; + let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; + let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); + if let Err(Errno::ENOSYS) = r { + println!("message queues not supported or module not loaded?"); + return; + }; + let mqd = r.unwrap(); + + let new_attr = MqAttr::new(0, 20, MSG_SIZE * 2, 100); + let old_attr = mq_setattr(&mqd, &new_attr).unwrap(); + assert_attr_eq!(old_attr, initial_attr); + + // No changes here because according to the Linux man page only + // O_NONBLOCK can be set (see tests below) + #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] + { + let new_attr_get = mq_getattr(&mqd).unwrap(); + assert_ne!(new_attr_get, new_attr); + } + + let new_attr_non_blocking = MqAttr::new( + MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t, + 10, + MSG_SIZE, + 0, + ); + mq_setattr(&mqd, &new_attr_non_blocking).unwrap(); + let new_attr_get = mq_getattr(&mqd).unwrap(); + + // now the O_NONBLOCK flag has been set + #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] + { + assert_ne!(new_attr_get, initial_attr); + } + assert_attr_eq!(new_attr_get, new_attr_non_blocking); + mq_close(mqd).unwrap(); +} + +// FIXME: Fix failures for mips in QEMU +#[test] +#[cfg_attr( + all(qemu, any(target_arch = "mips", target_arch = "mips64")), + ignore +)] +fn test_mq_set_nonblocking() { + use nix::mqueue::{mq_getattr, mq_remove_nonblock, mq_set_nonblock}; + const MSG_SIZE: mq_attr_member_t = 32; + let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); + let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; + let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; + let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); + if let Err(Errno::ENOSYS) = r { + println!("message queues not supported or module not loaded?"); + return; + }; + let mqd = r.unwrap(); + mq_set_nonblock(&mqd).unwrap(); + let new_attr = mq_getattr(&mqd); + let o_nonblock_bits = MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t; + assert_eq!(new_attr.unwrap().flags() & o_nonblock_bits, o_nonblock_bits); + mq_remove_nonblock(&mqd).unwrap(); + let new_attr = mq_getattr(&mqd); + assert_eq!(new_attr.unwrap().flags() & o_nonblock_bits, 0); + mq_close(mqd).unwrap(); +} + +#[test] +fn test_mq_unlink() { + use nix::mqueue::mq_unlink; + const MSG_SIZE: mq_attr_member_t = 32; + let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let mq_name_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); + #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] + let mq_name_not_opened = + &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); + let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; + let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; + let r = mq_open(mq_name_opened, oflag, mode, Some(&initial_attr)); + if let Err(Errno::ENOSYS) = r { + println!("message queues not supported or module not loaded?"); + return; + }; + let mqd = r.unwrap(); + + let res_unlink = mq_unlink(mq_name_opened); + assert_eq!(res_unlink, Ok(())); + + // NetBSD (and others which inherit its implementation) defer removing the message + // queue name until all references are closed, whereas Linux and others remove the + // message queue name immediately. + #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] + { + let res_unlink_not_opened = mq_unlink(mq_name_not_opened); + assert_eq!(res_unlink_not_opened, Err(Errno::ENOENT)); + } + + mq_close(mqd).unwrap(); + let res_unlink_after_close = mq_unlink(mq_name_opened); + assert_eq!(res_unlink_after_close, Err(Errno::ENOENT)); +} diff --git a/vendor/nix-0.26.2/test/test_net.rs b/vendor/nix-0.26.2/test/test_net.rs new file mode 100644 index 0000000000000..c44655a4c9b63 --- /dev/null +++ b/vendor/nix-0.26.2/test/test_net.rs @@ -0,0 +1,19 @@ +use nix::net::if_::*; + +#[cfg(any(target_os = "android", target_os = "linux"))] +const LOOPBACK: &[u8] = b"lo"; + +#[cfg(not(any( + target_os = "android", + target_os = "linux", + target_os = "haiku" +)))] +const LOOPBACK: &[u8] = b"lo0"; + +#[cfg(target_os = "haiku")] +const LOOPBACK: &[u8] = b"loop"; + +#[test] +fn test_if_nametoindex() { + if_nametoindex(LOOPBACK).expect("assertion failed"); +} diff --git a/vendor/nix-0.26.2/test/test_nix_path.rs b/vendor/nix-0.26.2/test/test_nix_path.rs new file mode 100644 index 0000000000000..8b137891791fe --- /dev/null +++ b/vendor/nix-0.26.2/test/test_nix_path.rs @@ -0,0 +1 @@ + diff --git a/vendor/nix-0.26.2/test/test_nmount.rs b/vendor/nix-0.26.2/test/test_nmount.rs new file mode 100644 index 0000000000000..dec806a55fb1a --- /dev/null +++ b/vendor/nix-0.26.2/test/test_nmount.rs @@ -0,0 +1,49 @@ +use crate::*; +use nix::{ + errno::Errno, + mount::{unmount, MntFlags, Nmount}, +}; +use std::{ffi::CString, fs::File, path::Path}; +use tempfile::tempdir; + +#[test] +fn ok() { + require_mount!("nullfs"); + + let mountpoint = tempdir().unwrap(); + let target = tempdir().unwrap(); + let _sentry = File::create(target.path().join("sentry")).unwrap(); + + let fstype = CString::new("fstype").unwrap(); + let nullfs = CString::new("nullfs").unwrap(); + Nmount::new() + .str_opt(&fstype, &nullfs) + .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) + .str_opt_owned("target", target.path().to_str().unwrap()) + .nmount(MntFlags::empty()) + .unwrap(); + + // Now check that the sentry is visible through the mountpoint + let exists = Path::exists(&mountpoint.path().join("sentry")); + + // Cleanup the mountpoint before asserting + unmount(mountpoint.path(), MntFlags::empty()).unwrap(); + + assert!(exists); +} + +#[test] +fn bad_fstype() { + let mountpoint = tempdir().unwrap(); + let target = tempdir().unwrap(); + let _sentry = File::create(target.path().join("sentry")).unwrap(); + + let e = Nmount::new() + .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) + .str_opt_owned("target", target.path().to_str().unwrap()) + .nmount(MntFlags::empty()) + .unwrap_err(); + + assert_eq!(e.error(), Errno::EINVAL); + assert_eq!(e.errmsg(), Some("Invalid fstype")); +} diff --git a/vendor/nix-0.26.2/test/test_poll.rs b/vendor/nix-0.26.2/test/test_poll.rs new file mode 100644 index 0000000000000..53964e26bbcc5 --- /dev/null +++ b/vendor/nix-0.26.2/test/test_poll.rs @@ -0,0 +1,84 @@ +use nix::{ + errno::Errno, + poll::{poll, PollFd, PollFlags}, + unistd::{pipe, write}, +}; + +macro_rules! loop_while_eintr { + ($poll_expr: expr) => { + loop { + match $poll_expr { + Ok(nfds) => break nfds, + Err(Errno::EINTR) => (), + Err(e) => panic!("{}", e), + } + } + }; +} + +#[test] +fn test_poll() { + let (r, w) = pipe().unwrap(); + let mut fds = [PollFd::new(r, PollFlags::POLLIN)]; + + // Poll an idle pipe. Should timeout + let nfds = loop_while_eintr!(poll(&mut fds, 100)); + assert_eq!(nfds, 0); + assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); + + write(w, b".").unwrap(); + + // Poll a readable pipe. Should return an event. + let nfds = poll(&mut fds, 100).unwrap(); + assert_eq!(nfds, 1); + assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); +} + +// ppoll(2) is the same as poll except for how it handles timeouts and signals. +// Repeating the test for poll(2) should be sufficient to check that our +// bindings are correct. +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux" +))] +#[test] +fn test_ppoll() { + use nix::poll::ppoll; + use nix::sys::signal::SigSet; + use nix::sys::time::{TimeSpec, TimeValLike}; + + let timeout = TimeSpec::milliseconds(1); + let (r, w) = pipe().unwrap(); + let mut fds = [PollFd::new(r, PollFlags::POLLIN)]; + + // Poll an idle pipe. Should timeout + let sigset = SigSet::empty(); + let nfds = loop_while_eintr!(ppoll(&mut fds, Some(timeout), Some(sigset))); + assert_eq!(nfds, 0); + assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); + + write(w, b".").unwrap(); + + // Poll a readable pipe. Should return an event. + let nfds = ppoll(&mut fds, Some(timeout), None).unwrap(); + assert_eq!(nfds, 1); + assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); +} + +#[test] +fn test_pollfd_fd() { + use std::os::unix::io::AsRawFd; + + let pfd = PollFd::new(0x1234, PollFlags::empty()); + assert_eq!(pfd.as_raw_fd(), 0x1234); +} + +#[test] +fn test_pollfd_events() { + let mut pfd = PollFd::new(-1, PollFlags::POLLIN); + assert_eq!(pfd.events(), PollFlags::POLLIN); + pfd.set_events(PollFlags::POLLOUT); + assert_eq!(pfd.events(), PollFlags::POLLOUT); +} diff --git a/vendor/nix-0.26.2/test/test_pty.rs b/vendor/nix-0.26.2/test/test_pty.rs new file mode 100644 index 0000000000000..5c27e2d632de8 --- /dev/null +++ b/vendor/nix-0.26.2/test/test_pty.rs @@ -0,0 +1,313 @@ +use std::fs::File; +use std::io::{Read, Write}; +use std::os::unix::prelude::*; +use std::path::Path; +use tempfile::tempfile; + +use libc::{_exit, STDOUT_FILENO}; +use nix::fcntl::{open, OFlag}; +use nix::pty::*; +use nix::sys::stat; +use nix::sys::termios::*; +use nix::unistd::{close, pause, write}; + +/// Regression test for Issue #659 +/// This is the correct way to explicitly close a `PtyMaster` +#[test] +fn test_explicit_close() { + let mut f = { + let m = posix_openpt(OFlag::O_RDWR).unwrap(); + close(m.into_raw_fd()).unwrap(); + tempfile().unwrap() + }; + // This should work. But if there's been a double close, then it will + // return EBADF + f.write_all(b"whatever").unwrap(); +} + +/// Test equivalence of `ptsname` and `ptsname_r` +#[test] +#[cfg(any(target_os = "android", target_os = "linux"))] +fn test_ptsname_equivalence() { + let _m = crate::PTSNAME_MTX.lock(); + + // Open a new PTTY master + let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); + assert!(master_fd.as_raw_fd() > 0); + + // Get the name of the slave + let slave_name = unsafe { ptsname(&master_fd) }.unwrap(); + let slave_name_r = ptsname_r(&master_fd).unwrap(); + assert_eq!(slave_name, slave_name_r); +} + +/// Test data copying of `ptsname` +// TODO need to run in a subprocess, since ptsname is non-reentrant +#[test] +#[cfg(any(target_os = "android", target_os = "linux"))] +fn test_ptsname_copy() { + let _m = crate::PTSNAME_MTX.lock(); + + // Open a new PTTY master + let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); + assert!(master_fd.as_raw_fd() > 0); + + // Get the name of the slave + let slave_name1 = unsafe { ptsname(&master_fd) }.unwrap(); + let slave_name2 = unsafe { ptsname(&master_fd) }.unwrap(); + assert_eq!(slave_name1, slave_name2); + // Also make sure that the string was actually copied and they point to different parts of + // memory. + assert_ne!(slave_name1.as_ptr(), slave_name2.as_ptr()); +} + +/// Test data copying of `ptsname_r` +#[test] +#[cfg(any(target_os = "android", target_os = "linux"))] +fn test_ptsname_r_copy() { + // Open a new PTTY master + let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); + assert!(master_fd.as_raw_fd() > 0); + + // Get the name of the slave + let slave_name1 = ptsname_r(&master_fd).unwrap(); + let slave_name2 = ptsname_r(&master_fd).unwrap(); + assert_eq!(slave_name1, slave_name2); + assert_ne!(slave_name1.as_ptr(), slave_name2.as_ptr()); +} + +/// Test that `ptsname` returns different names for different devices +#[test] +#[cfg(any(target_os = "android", target_os = "linux"))] +fn test_ptsname_unique() { + let _m = crate::PTSNAME_MTX.lock(); + + // Open a new PTTY master + let master1_fd = posix_openpt(OFlag::O_RDWR).unwrap(); + assert!(master1_fd.as_raw_fd() > 0); + + // Open a second PTTY master + let master2_fd = posix_openpt(OFlag::O_RDWR).unwrap(); + assert!(master2_fd.as_raw_fd() > 0); + + // Get the name of the slave + let slave_name1 = unsafe { ptsname(&master1_fd) }.unwrap(); + let slave_name2 = unsafe { ptsname(&master2_fd) }.unwrap(); + assert_ne!(slave_name1, slave_name2); +} + +/// Common setup for testing PTTY pairs +fn open_ptty_pair() -> (PtyMaster, File) { + let _m = crate::PTSNAME_MTX.lock(); + + // Open a new PTTY master + let master = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); + + // Allow a slave to be generated for it + grantpt(&master).expect("grantpt failed"); + unlockpt(&master).expect("unlockpt failed"); + + // Get the name of the slave + let slave_name = unsafe { ptsname(&master) }.expect("ptsname failed"); + + // Open the slave device + let slave_fd = + open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()) + .unwrap(); + + #[cfg(target_os = "illumos")] + // TODO: rewrite using ioctl! + #[allow(clippy::comparison_chain)] + { + use libc::{ioctl, I_FIND, I_PUSH}; + + // On illumos systems, as per pts(7D), one must push STREAMS modules + // after opening a device path returned from ptsname(). + let ptem = b"ptem\0"; + let ldterm = b"ldterm\0"; + let r = unsafe { ioctl(slave_fd, I_FIND, ldterm.as_ptr()) }; + if r < 0 { + panic!("I_FIND failure"); + } else if r == 0 { + if unsafe { ioctl(slave_fd, I_PUSH, ptem.as_ptr()) } < 0 { + panic!("I_PUSH ptem failure"); + } + if unsafe { ioctl(slave_fd, I_PUSH, ldterm.as_ptr()) } < 0 { + panic!("I_PUSH ldterm failure"); + } + } + } + + let slave = unsafe { File::from_raw_fd(slave_fd) }; + + (master, slave) +} + +/// Test opening a master/slave PTTY pair +/// +/// This uses a common `open_ptty_pair` because much of these functions aren't useful by +/// themselves. So for this test we perform the basic act of getting a file handle for a +/// master/slave PTTY pair, then just sanity-check the raw values. +#[test] +fn test_open_ptty_pair() { + let (master, slave) = open_ptty_pair(); + assert!(master.as_raw_fd() > 0); + assert!(slave.as_raw_fd() > 0); +} + +/// Put the terminal in raw mode. +fn make_raw(fd: RawFd) { + let mut termios = tcgetattr(fd).unwrap(); + cfmakeraw(&mut termios); + tcsetattr(fd, SetArg::TCSANOW, &termios).unwrap(); +} + +/// Test `io::Read` on the PTTY master +#[test] +fn test_read_ptty_pair() { + let (mut master, mut slave) = open_ptty_pair(); + make_raw(slave.as_raw_fd()); + + let mut buf = [0u8; 5]; + slave.write_all(b"hello").unwrap(); + master.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"hello"); + + let mut master = &master; + slave.write_all(b"hello").unwrap(); + master.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"hello"); +} + +/// Test `io::Write` on the PTTY master +#[test] +fn test_write_ptty_pair() { + let (mut master, mut slave) = open_ptty_pair(); + make_raw(slave.as_raw_fd()); + + let mut buf = [0u8; 5]; + master.write_all(b"adios").unwrap(); + slave.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"adios"); + + let mut master = &master; + master.write_all(b"adios").unwrap(); + slave.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"adios"); +} + +#[test] +fn test_openpty() { + // openpty uses ptname(3) internally + let _m = crate::PTSNAME_MTX.lock(); + + let pty = openpty(None, None).unwrap(); + assert!(pty.master > 0); + assert!(pty.slave > 0); + + // Writing to one should be readable on the other one + let string = "foofoofoo\n"; + let mut buf = [0u8; 10]; + write(pty.master, string.as_bytes()).unwrap(); + crate::read_exact(pty.slave, &mut buf); + + assert_eq!(&buf, string.as_bytes()); + + // Read the echo as well + let echoed_string = "foofoofoo\r\n"; + let mut buf = [0u8; 11]; + crate::read_exact(pty.master, &mut buf); + assert_eq!(&buf, echoed_string.as_bytes()); + + let string2 = "barbarbarbar\n"; + let echoed_string2 = "barbarbarbar\r\n"; + let mut buf = [0u8; 14]; + write(pty.slave, string2.as_bytes()).unwrap(); + crate::read_exact(pty.master, &mut buf); + + assert_eq!(&buf, echoed_string2.as_bytes()); + + close(pty.master).unwrap(); + close(pty.slave).unwrap(); +} + +#[test] +fn test_openpty_with_termios() { + // openpty uses ptname(3) internally + let _m = crate::PTSNAME_MTX.lock(); + + // Open one pty to get attributes for the second one + let mut termios = { + let pty = openpty(None, None).unwrap(); + assert!(pty.master > 0); + assert!(pty.slave > 0); + let termios = tcgetattr(pty.slave).unwrap(); + close(pty.master).unwrap(); + close(pty.slave).unwrap(); + termios + }; + // Make sure newlines are not transformed so the data is preserved when sent. + termios.output_flags.remove(OutputFlags::ONLCR); + + let pty = openpty(None, &termios).unwrap(); + // Must be valid file descriptors + assert!(pty.master > 0); + assert!(pty.slave > 0); + + // Writing to one should be readable on the other one + let string = "foofoofoo\n"; + let mut buf = [0u8; 10]; + write(pty.master, string.as_bytes()).unwrap(); + crate::read_exact(pty.slave, &mut buf); + + assert_eq!(&buf, string.as_bytes()); + + // read the echo as well + let echoed_string = "foofoofoo\n"; + crate::read_exact(pty.master, &mut buf); + assert_eq!(&buf, echoed_string.as_bytes()); + + let string2 = "barbarbarbar\n"; + let echoed_string2 = "barbarbarbar\n"; + let mut buf = [0u8; 13]; + write(pty.slave, string2.as_bytes()).unwrap(); + crate::read_exact(pty.master, &mut buf); + + assert_eq!(&buf, echoed_string2.as_bytes()); + + close(pty.master).unwrap(); + close(pty.slave).unwrap(); +} + +#[test] +fn test_forkpty() { + use nix::sys::signal::*; + use nix::sys::wait::wait; + use nix::unistd::ForkResult::*; + // forkpty calls openpty which uses ptname(3) internally. + let _m0 = crate::PTSNAME_MTX.lock(); + // forkpty spawns a child process + let _m1 = crate::FORK_MTX.lock(); + + let string = "naninani\n"; + let echoed_string = "naninani\r\n"; + let pty = unsafe { forkpty(None, None).unwrap() }; + match pty.fork_result { + Child => { + write(STDOUT_FILENO, string.as_bytes()).unwrap(); + pause(); // we need the child to stay alive until the parent calls read + unsafe { + _exit(0); + } + } + Parent { child } => { + let mut buf = [0u8; 10]; + assert!(child.as_raw() > 0); + crate::read_exact(pty.master, &mut buf); + kill(child, SIGTERM).unwrap(); + wait().unwrap(); // keep other tests using generic wait from getting our child + assert_eq!(&buf, echoed_string.as_bytes()); + close(pty.master).unwrap(); + } + } +} diff --git a/vendor/nix-0.26.2/test/test_ptymaster_drop.rs b/vendor/nix-0.26.2/test/test_ptymaster_drop.rs new file mode 100644 index 0000000000000..ffbaa5697771a --- /dev/null +++ b/vendor/nix-0.26.2/test/test_ptymaster_drop.rs @@ -0,0 +1,20 @@ +#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] +mod t { + use nix::fcntl::OFlag; + use nix::pty::*; + use nix::unistd::close; + use std::os::unix::io::AsRawFd; + + /// Regression test for Issue #659 + /// + /// `PtyMaster` should panic rather than double close the file descriptor + /// This must run in its own test process because it deliberately creates a + /// race condition. + #[test] + #[should_panic(expected = "Closing an invalid file descriptor!")] + fn test_double_close() { + let m = posix_openpt(OFlag::O_RDWR).unwrap(); + close(m.as_raw_fd()).unwrap(); + drop(m); // should panic here + } +} diff --git a/vendor/nix-0.26.2/test/test_resource.rs b/vendor/nix-0.26.2/test/test_resource.rs new file mode 100644 index 0000000000000..2ab581ba29403 --- /dev/null +++ b/vendor/nix-0.26.2/test/test_resource.rs @@ -0,0 +1,34 @@ +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "illumos", + target_os = "haiku" +)))] +use nix::sys::resource::{getrlimit, setrlimit, Resource}; + +/// Tests the RLIMIT_NOFILE functionality of getrlimit(), where the resource RLIMIT_NOFILE refers +/// to the maximum file descriptor number that can be opened by the process (aka the maximum number +/// of file descriptors that the process can open, since Linux 4.5). +/// +/// We first fetch the existing file descriptor maximum values using getrlimit(), then edit the +/// soft limit to make sure it has a new and distinct value to the hard limit. We then setrlimit() +/// to put the new soft limit in effect, and then getrlimit() once more to ensure the limits have +/// been updated. +#[test] +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "illumos", + target_os = "haiku" +)))] +pub fn test_resource_limits_nofile() { + let (mut soft_limit, hard_limit) = + getrlimit(Resource::RLIMIT_NOFILE).unwrap(); + + soft_limit -= 1; + assert_ne!(soft_limit, hard_limit); + setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); + + let (new_soft_limit, _) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); + assert_eq!(new_soft_limit, soft_limit); +} diff --git a/vendor/nix-0.26.2/test/test_sched.rs b/vendor/nix-0.26.2/test/test_sched.rs new file mode 100644 index 0000000000000..c52616b8bb34c --- /dev/null +++ b/vendor/nix-0.26.2/test/test_sched.rs @@ -0,0 +1,39 @@ +use nix::sched::{sched_getaffinity, sched_getcpu, sched_setaffinity, CpuSet}; +use nix::unistd::Pid; + +#[test] +fn test_sched_affinity() { + // If pid is zero, then the mask of the calling process is returned. + let initial_affinity = sched_getaffinity(Pid::from_raw(0)).unwrap(); + let mut at_least_one_cpu = false; + let mut last_valid_cpu = 0; + for field in 0..CpuSet::count() { + if initial_affinity.is_set(field).unwrap() { + at_least_one_cpu = true; + last_valid_cpu = field; + } + } + assert!(at_least_one_cpu); + + // Now restrict the running CPU + let mut new_affinity = CpuSet::new(); + new_affinity.set(last_valid_cpu).unwrap(); + sched_setaffinity(Pid::from_raw(0), &new_affinity).unwrap(); + + // And now re-check the affinity which should be only the one we set. + let updated_affinity = sched_getaffinity(Pid::from_raw(0)).unwrap(); + for field in 0..CpuSet::count() { + // Should be set only for the CPU we set previously + assert_eq!( + updated_affinity.is_set(field).unwrap(), + field == last_valid_cpu + ) + } + + // Now check that we're also currently running on the CPU in question. + let cur_cpu = sched_getcpu().unwrap(); + assert_eq!(cur_cpu, last_valid_cpu); + + // Finally, reset the initial CPU set + sched_setaffinity(Pid::from_raw(0), &initial_affinity).unwrap(); +} diff --git a/vendor/nix-0.26.2/test/test_sendfile.rs b/vendor/nix-0.26.2/test/test_sendfile.rs new file mode 100644 index 0000000000000..f73a3b56c38b5 --- /dev/null +++ b/vendor/nix-0.26.2/test/test_sendfile.rs @@ -0,0 +1,208 @@ +use std::io::prelude::*; +use std::os::unix::prelude::*; + +use libc::off_t; +use nix::sys::sendfile::*; +use tempfile::tempfile; + +cfg_if! { + if #[cfg(any(target_os = "android", target_os = "linux"))] { + use nix::unistd::{close, pipe, read}; + } else if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos"))] { + use std::net::Shutdown; + use std::os::unix::net::UnixStream; + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_sendfile_linux() { + const CONTENTS: &[u8] = b"abcdef123456"; + let mut tmp = tempfile().unwrap(); + tmp.write_all(CONTENTS).unwrap(); + + let (rd, wr) = pipe().unwrap(); + let mut offset: off_t = 5; + let res = sendfile(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap(); + + assert_eq!(2, res); + + let mut buf = [0u8; 1024]; + assert_eq!(2, read(rd, &mut buf).unwrap()); + assert_eq!(b"f1", &buf[0..2]); + assert_eq!(7, offset); + + close(rd).unwrap(); + close(wr).unwrap(); +} + +#[cfg(target_os = "linux")] +#[test] +fn test_sendfile64_linux() { + const CONTENTS: &[u8] = b"abcdef123456"; + let mut tmp = tempfile().unwrap(); + tmp.write_all(CONTENTS).unwrap(); + + let (rd, wr) = pipe().unwrap(); + let mut offset: libc::off64_t = 5; + let res = sendfile64(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap(); + + assert_eq!(2, res); + + let mut buf = [0u8; 1024]; + assert_eq!(2, read(rd, &mut buf).unwrap()); + assert_eq!(b"f1", &buf[0..2]); + assert_eq!(7, offset); + + close(rd).unwrap(); + close(wr).unwrap(); +} + +#[cfg(target_os = "freebsd")] +#[test] +fn test_sendfile_freebsd() { + // Declare the content + let header_strings = + vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; + let body = "Xabcdef123456"; + let body_offset = 1; + let trailer_strings = vec!["\n", "Served by Make Believe\n"]; + + // Write the body to a file + let mut tmp = tempfile().unwrap(); + tmp.write_all(body.as_bytes()).unwrap(); + + // Prepare headers and trailers for sendfile + let headers: Vec<&[u8]> = + header_strings.iter().map(|s| s.as_bytes()).collect(); + let trailers: Vec<&[u8]> = + trailer_strings.iter().map(|s| s.as_bytes()).collect(); + + // Prepare socket pair + let (mut rd, wr) = UnixStream::pair().unwrap(); + + // Call the test method + let (res, bytes_written) = sendfile( + tmp.as_raw_fd(), + wr.as_raw_fd(), + body_offset as off_t, + None, + Some(headers.as_slice()), + Some(trailers.as_slice()), + SfFlags::empty(), + 0, + ); + assert!(res.is_ok()); + wr.shutdown(Shutdown::Both).unwrap(); + + // Prepare the expected result + let expected_string = header_strings.concat() + + &body[body_offset..] + + &trailer_strings.concat(); + + // Verify the message that was sent + assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); + + let mut read_string = String::new(); + let bytes_read = rd.read_to_string(&mut read_string).unwrap(); + assert_eq!(bytes_written as usize, bytes_read); + assert_eq!(expected_string, read_string); +} + +#[cfg(target_os = "dragonfly")] +#[test] +fn test_sendfile_dragonfly() { + // Declare the content + let header_strings = + vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; + let body = "Xabcdef123456"; + let body_offset = 1; + let trailer_strings = vec!["\n", "Served by Make Believe\n"]; + + // Write the body to a file + let mut tmp = tempfile().unwrap(); + tmp.write_all(body.as_bytes()).unwrap(); + + // Prepare headers and trailers for sendfile + let headers: Vec<&[u8]> = + header_strings.iter().map(|s| s.as_bytes()).collect(); + let trailers: Vec<&[u8]> = + trailer_strings.iter().map(|s| s.as_bytes()).collect(); + + // Prepare socket pair + let (mut rd, wr) = UnixStream::pair().unwrap(); + + // Call the test method + let (res, bytes_written) = sendfile( + tmp.as_raw_fd(), + wr.as_raw_fd(), + body_offset as off_t, + None, + Some(headers.as_slice()), + Some(trailers.as_slice()), + ); + assert!(res.is_ok()); + wr.shutdown(Shutdown::Both).unwrap(); + + // Prepare the expected result + let expected_string = header_strings.concat() + + &body[body_offset..] + + &trailer_strings.concat(); + + // Verify the message that was sent + assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); + + let mut read_string = String::new(); + let bytes_read = rd.read_to_string(&mut read_string).unwrap(); + assert_eq!(bytes_written as usize, bytes_read); + assert_eq!(expected_string, read_string); +} + +#[cfg(any(target_os = "ios", target_os = "macos"))] +#[test] +fn test_sendfile_darwin() { + // Declare the content + let header_strings = + vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; + let body = "Xabcdef123456"; + let body_offset = 1; + let trailer_strings = vec!["\n", "Served by Make Believe\n"]; + + // Write the body to a file + let mut tmp = tempfile().unwrap(); + tmp.write_all(body.as_bytes()).unwrap(); + + // Prepare headers and trailers for sendfile + let headers: Vec<&[u8]> = + header_strings.iter().map(|s| s.as_bytes()).collect(); + let trailers: Vec<&[u8]> = + trailer_strings.iter().map(|s| s.as_bytes()).collect(); + + // Prepare socket pair + let (mut rd, wr) = UnixStream::pair().unwrap(); + + // Call the test method + let (res, bytes_written) = sendfile( + tmp.as_raw_fd(), + wr.as_raw_fd(), + body_offset as off_t, + None, + Some(headers.as_slice()), + Some(trailers.as_slice()), + ); + assert!(res.is_ok()); + wr.shutdown(Shutdown::Both).unwrap(); + + // Prepare the expected result + let expected_string = header_strings.concat() + + &body[body_offset..] + + &trailer_strings.concat(); + + // Verify the message that was sent + assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); + + let mut read_string = String::new(); + let bytes_read = rd.read_to_string(&mut read_string).unwrap(); + assert_eq!(bytes_written as usize, bytes_read); + assert_eq!(expected_string, read_string); +} diff --git a/vendor/nix-0.26.2/test/test_stat.rs b/vendor/nix-0.26.2/test/test_stat.rs new file mode 100644 index 0000000000000..55f15c0771d0f --- /dev/null +++ b/vendor/nix-0.26.2/test/test_stat.rs @@ -0,0 +1,421 @@ +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use std::fs; +use std::fs::File; +#[cfg(not(target_os = "redox"))] +use std::os::unix::fs::symlink; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use std::os::unix::fs::PermissionsExt; +use std::os::unix::prelude::AsRawFd; +#[cfg(not(target_os = "redox"))] +use std::path::Path; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use std::time::{Duration, UNIX_EPOCH}; + +use libc::mode_t; +#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] +use libc::{S_IFLNK, S_IFMT}; + +#[cfg(not(target_os = "redox"))] +use nix::errno::Errno; +#[cfg(not(target_os = "redox"))] +use nix::fcntl; +#[cfg(any( + target_os = "linux", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd" +))] +use nix::sys::stat::lutimes; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use nix::sys::stat::utimensat; +#[cfg(not(target_os = "redox"))] +use nix::sys::stat::FchmodatFlags; +use nix::sys::stat::Mode; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use nix::sys::stat::UtimensatFlags; +#[cfg(not(target_os = "redox"))] +use nix::sys::stat::{self}; +use nix::sys::stat::{fchmod, stat}; +#[cfg(not(target_os = "redox"))] +use nix::sys::stat::{fchmodat, mkdirat}; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use nix::sys::stat::{futimens, utimes}; + +#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] +use nix::sys::stat::FileStat; + +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use nix::sys::time::{TimeSpec, TimeVal, TimeValLike}; +#[cfg(not(target_os = "redox"))] +use nix::unistd::chdir; + +#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] +use nix::Result; + +#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] +fn assert_stat_results(stat_result: Result) { + let stats = stat_result.expect("stat call failed"); + assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent + assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent + assert!(stats.st_mode > 0); // must be positive integer + assert_eq!(stats.st_nlink, 1); // there links created, must be 1 + assert_eq!(stats.st_size, 0); // size is 0 because we did not write anything to the file + assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent + assert!(stats.st_blocks <= 16); // Up to 16 blocks can be allocated for a blank file +} + +#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] +// (Android's st_blocks is ulonglong which is always non-negative.) +#[cfg_attr(target_os = "android", allow(unused_comparisons))] +#[allow(clippy::absurd_extreme_comparisons)] // Not absurd on all OSes +fn assert_lstat_results(stat_result: Result) { + let stats = stat_result.expect("stat call failed"); + assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent + assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent + assert!(stats.st_mode > 0); // must be positive integer + + // st_mode is c_uint (u32 on Android) while S_IFMT is mode_t + // (u16 on Android), and that will be a compile error. + // On other platforms they are the same (either both are u16 or u32). + assert_eq!( + (stats.st_mode as usize) & (S_IFMT as usize), + S_IFLNK as usize + ); // should be a link + assert_eq!(stats.st_nlink, 1); // there links created, must be 1 + assert!(stats.st_size > 0); // size is > 0 because it points to another file + assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent + + // st_blocks depends on whether the machine's file system uses fast + // or slow symlinks, so just make sure it's not negative + assert!(stats.st_blocks >= 0); +} + +#[test] +#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] +fn test_stat_and_fstat() { + use nix::sys::stat::fstat; + + let tempdir = tempfile::tempdir().unwrap(); + let filename = tempdir.path().join("foo.txt"); + let file = File::create(&filename).unwrap(); + + let stat_result = stat(&filename); + assert_stat_results(stat_result); + + let fstat_result = fstat(file.as_raw_fd()); + assert_stat_results(fstat_result); +} + +#[test] +#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] +fn test_fstatat() { + let tempdir = tempfile::tempdir().unwrap(); + let filename = tempdir.path().join("foo.txt"); + File::create(&filename).unwrap(); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()); + + let result = + stat::fstatat(dirfd.unwrap(), &filename, fcntl::AtFlags::empty()); + assert_stat_results(result); +} + +#[test] +#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] +fn test_stat_fstat_lstat() { + use nix::sys::stat::{fstat, lstat}; + + let tempdir = tempfile::tempdir().unwrap(); + let filename = tempdir.path().join("bar.txt"); + let linkname = tempdir.path().join("barlink"); + + File::create(&filename).unwrap(); + symlink("bar.txt", &linkname).unwrap(); + let link = File::open(&linkname).unwrap(); + + // should be the same result as calling stat, + // since it's a regular file + let stat_result = stat(&filename); + assert_stat_results(stat_result); + + let lstat_result = lstat(&linkname); + assert_lstat_results(lstat_result); + + let fstat_result = fstat(link.as_raw_fd()); + assert_stat_results(fstat_result); +} + +#[test] +fn test_fchmod() { + let tempdir = tempfile::tempdir().unwrap(); + let filename = tempdir.path().join("foo.txt"); + let file = File::create(&filename).unwrap(); + + let mut mode1 = Mode::empty(); + mode1.insert(Mode::S_IRUSR); + mode1.insert(Mode::S_IWUSR); + fchmod(file.as_raw_fd(), mode1).unwrap(); + + let file_stat1 = stat(&filename).unwrap(); + assert_eq!(file_stat1.st_mode as mode_t & 0o7777, mode1.bits()); + + let mut mode2 = Mode::empty(); + mode2.insert(Mode::S_IROTH); + fchmod(file.as_raw_fd(), mode2).unwrap(); + + let file_stat2 = stat(&filename).unwrap(); + assert_eq!(file_stat2.st_mode as mode_t & 0o7777, mode2.bits()); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_fchmodat() { + let _dr = crate::DirRestore::new(); + let tempdir = tempfile::tempdir().unwrap(); + let filename = "foo.txt"; + let fullpath = tempdir.path().join(filename); + File::create(&fullpath).unwrap(); + + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + + let mut mode1 = Mode::empty(); + mode1.insert(Mode::S_IRUSR); + mode1.insert(Mode::S_IWUSR); + fchmodat(Some(dirfd), filename, mode1, FchmodatFlags::FollowSymlink) + .unwrap(); + + let file_stat1 = stat(&fullpath).unwrap(); + assert_eq!(file_stat1.st_mode as mode_t & 0o7777, mode1.bits()); + + chdir(tempdir.path()).unwrap(); + + let mut mode2 = Mode::empty(); + mode2.insert(Mode::S_IROTH); + fchmodat(None, filename, mode2, FchmodatFlags::FollowSymlink).unwrap(); + + let file_stat2 = stat(&fullpath).unwrap(); + assert_eq!(file_stat2.st_mode as mode_t & 0o7777, mode2.bits()); +} + +/// Asserts that the atime and mtime in a file's metadata match expected values. +/// +/// The atime and mtime are expressed with a resolution of seconds because some file systems +/// (like macOS's HFS+) do not have higher granularity. +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn assert_times_eq( + exp_atime_sec: u64, + exp_mtime_sec: u64, + attr: &fs::Metadata, +) { + assert_eq!( + Duration::new(exp_atime_sec, 0), + attr.accessed().unwrap().duration_since(UNIX_EPOCH).unwrap() + ); + assert_eq!( + Duration::new(exp_mtime_sec, 0), + attr.modified().unwrap().duration_since(UNIX_EPOCH).unwrap() + ); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_utimes() { + let tempdir = tempfile::tempdir().unwrap(); + let fullpath = tempdir.path().join("file"); + drop(File::create(&fullpath).unwrap()); + + utimes(&fullpath, &TimeVal::seconds(9990), &TimeVal::seconds(5550)) + .unwrap(); + assert_times_eq(9990, 5550, &fs::metadata(&fullpath).unwrap()); +} + +#[test] +#[cfg(any( + target_os = "linux", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd" +))] +fn test_lutimes() { + let tempdir = tempfile::tempdir().unwrap(); + let target = tempdir.path().join("target"); + let fullpath = tempdir.path().join("symlink"); + drop(File::create(&target).unwrap()); + symlink(&target, &fullpath).unwrap(); + + let exp_target_metadata = fs::symlink_metadata(&target).unwrap(); + lutimes(&fullpath, &TimeVal::seconds(4560), &TimeVal::seconds(1230)) + .unwrap(); + assert_times_eq(4560, 1230, &fs::symlink_metadata(&fullpath).unwrap()); + + let target_metadata = fs::symlink_metadata(&target).unwrap(); + assert_eq!( + exp_target_metadata.accessed().unwrap(), + target_metadata.accessed().unwrap(), + "atime of symlink target was unexpectedly modified" + ); + assert_eq!( + exp_target_metadata.modified().unwrap(), + target_metadata.modified().unwrap(), + "mtime of symlink target was unexpectedly modified" + ); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_futimens() { + let tempdir = tempfile::tempdir().unwrap(); + let fullpath = tempdir.path().join("file"); + drop(File::create(&fullpath).unwrap()); + + let fd = fcntl::open(&fullpath, fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + + futimens(fd, &TimeSpec::seconds(10), &TimeSpec::seconds(20)).unwrap(); + assert_times_eq(10, 20, &fs::metadata(&fullpath).unwrap()); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_utimensat() { + let _dr = crate::DirRestore::new(); + let tempdir = tempfile::tempdir().unwrap(); + let filename = "foo.txt"; + let fullpath = tempdir.path().join(filename); + drop(File::create(&fullpath).unwrap()); + + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + + utimensat( + Some(dirfd), + filename, + &TimeSpec::seconds(12345), + &TimeSpec::seconds(678), + UtimensatFlags::FollowSymlink, + ) + .unwrap(); + assert_times_eq(12345, 678, &fs::metadata(&fullpath).unwrap()); + + chdir(tempdir.path()).unwrap(); + + utimensat( + None, + filename, + &TimeSpec::seconds(500), + &TimeSpec::seconds(800), + UtimensatFlags::FollowSymlink, + ) + .unwrap(); + assert_times_eq(500, 800, &fs::metadata(&fullpath).unwrap()); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_mkdirat_success_path() { + let tempdir = tempfile::tempdir().unwrap(); + let filename = "example_subdir"; + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); + assert!(Path::exists(&tempdir.path().join(filename))); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_mkdirat_success_mode() { + let expected_bits = + stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits(); + let tempdir = tempfile::tempdir().unwrap(); + let filename = "example_subdir"; + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); + let permissions = fs::metadata(tempdir.path().join(filename)) + .unwrap() + .permissions(); + let mode = permissions.mode(); + assert_eq!(mode as mode_t, expected_bits) +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_mkdirat_fail() { + let tempdir = tempfile::tempdir().unwrap(); + let not_dir_filename = "example_not_dir"; + let filename = "example_subdir_dir"; + let dirfd = fcntl::open( + &tempdir.path().join(not_dir_filename), + fcntl::OFlag::O_CREAT, + stat::Mode::empty(), + ) + .unwrap(); + let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err(); + assert_eq!(result, Errno::ENOTDIR); +} + +#[test] +#[cfg(not(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "haiku", + target_os = "redox" +)))] +fn test_mknod() { + use stat::{lstat, mknod, SFlag}; + + let file_name = "test_file"; + let tempdir = tempfile::tempdir().unwrap(); + let target = tempdir.path().join(file_name); + mknod(&target, SFlag::S_IFREG, Mode::S_IRWXU, 0).unwrap(); + let mode = lstat(&target).unwrap().st_mode as mode_t; + assert_eq!(mode & libc::S_IFREG, libc::S_IFREG); + assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU); +} + +#[test] +#[cfg(not(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "haiku", + target_os = "redox" +)))] +fn test_mknodat() { + use fcntl::{AtFlags, OFlag}; + use nix::dir::Dir; + use stat::{fstatat, mknodat, SFlag}; + + let file_name = "test_file"; + let tempdir = tempfile::tempdir().unwrap(); + let target_dir = + Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap(); + mknodat( + target_dir.as_raw_fd(), + file_name, + SFlag::S_IFREG, + Mode::S_IRWXU, + 0, + ) + .unwrap(); + let mode = fstatat( + target_dir.as_raw_fd(), + file_name, + AtFlags::AT_SYMLINK_NOFOLLOW, + ) + .unwrap() + .st_mode as mode_t; + assert_eq!(mode & libc::S_IFREG, libc::S_IFREG); + assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU); +} diff --git a/vendor/nix-0.26.2/test/test_time.rs b/vendor/nix-0.26.2/test/test_time.rs new file mode 100644 index 0000000000000..5f76e61a2da55 --- /dev/null +++ b/vendor/nix-0.26.2/test/test_time.rs @@ -0,0 +1,59 @@ +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux", + target_os = "android", + target_os = "emscripten", +))] +use nix::time::clock_getcpuclockid; +use nix::time::{clock_gettime, ClockId}; + +#[cfg(not(target_os = "redox"))] +#[test] +pub fn test_clock_getres() { + nix::time::clock_getres(ClockId::CLOCK_REALTIME).expect("assertion failed"); +} + +#[test] +pub fn test_clock_gettime() { + clock_gettime(ClockId::CLOCK_REALTIME).expect("assertion failed"); +} + +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux", + target_os = "android", + target_os = "emscripten", +))] +#[test] +pub fn test_clock_getcpuclockid() { + let clock_id = clock_getcpuclockid(nix::unistd::Pid::this()).unwrap(); + clock_gettime(clock_id).unwrap(); +} + +#[cfg(not(target_os = "redox"))] +#[test] +pub fn test_clock_id_res() { + ClockId::CLOCK_REALTIME.res().unwrap(); +} + +#[test] +pub fn test_clock_id_now() { + ClockId::CLOCK_REALTIME.now().unwrap(); +} + +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux", + target_os = "android", + target_os = "emscripten", +))] +#[test] +pub fn test_clock_id_pid_cpu_clock_id() { + ClockId::pid_cpu_clock_id(nix::unistd::Pid::this()) + .map(ClockId::now) + .unwrap() + .unwrap(); +} diff --git a/vendor/nix-0.26.2/test/test_timer.rs b/vendor/nix-0.26.2/test/test_timer.rs new file mode 100644 index 0000000000000..ffd146867bd1d --- /dev/null +++ b/vendor/nix-0.26.2/test/test_timer.rs @@ -0,0 +1,102 @@ +use nix::sys::signal::{ + sigaction, SaFlags, SigAction, SigEvent, SigHandler, SigSet, SigevNotify, + Signal, +}; +use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags}; +use nix::time::ClockId; +use std::convert::TryFrom; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; +use std::time::{Duration, Instant}; + +const SIG: Signal = Signal::SIGALRM; +static ALARM_CALLED: AtomicBool = AtomicBool::new(false); + +pub extern "C" fn handle_sigalarm(raw_signal: libc::c_int) { + let signal = Signal::try_from(raw_signal).unwrap(); + if signal == SIG { + ALARM_CALLED.store(true, Ordering::Release); + } +} + +#[test] +fn alarm_fires() { + // Avoid interfering with other signal using tests by taking a mutex shared + // among other tests in this crate. + let _m = crate::SIGNAL_MTX.lock(); + const TIMER_PERIOD: Duration = Duration::from_millis(100); + + // + // Setup + // + + // Create a handler for the test signal, `SIG`. The handler is responsible + // for flipping `ALARM_CALLED`. + let handler = SigHandler::Handler(handle_sigalarm); + let signal_action = + SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); + let old_handler = unsafe { + sigaction(SIG, &signal_action) + .expect("unable to set signal handler for alarm") + }; + + // Create the timer. We use the monotonic clock here, though any would do + // really. The timer is set to fire every 250 milliseconds with no delay for + // the initial firing. + let clockid = ClockId::CLOCK_MONOTONIC; + let sigevent = SigEvent::new(SigevNotify::SigevSignal { + signal: SIG, + si_value: 0, + }); + let mut timer = + Timer::new(clockid, sigevent).expect("failed to create timer"); + let expiration = Expiration::Interval(TIMER_PERIOD.into()); + let flags = TimerSetTimeFlags::empty(); + timer.set(expiration, flags).expect("could not set timer"); + + // + // Test + // + + // Determine that there's still an expiration tracked by the + // timer. Depending on when this runs either an `Expiration::Interval` or + // `Expiration::IntervalDelayed` will be present. That is, if the timer has + // not fired yet we'll get our original `expiration`, else the one that + // represents a delay to the next expiration. We're only interested in the + // timer still being extant. + match timer.get() { + Ok(Some(exp)) => assert!(matches!( + exp, + Expiration::Interval(..) | Expiration::IntervalDelayed(..) + )), + _ => panic!("timer lost its expiration"), + } + + // Wait for 2 firings of the alarm before checking that it has fired and + // been handled at least the once. If we wait for 3 seconds and the handler + // is never called something has gone sideways and the test fails. + let starttime = Instant::now(); + loop { + thread::sleep(2 * TIMER_PERIOD); + if ALARM_CALLED.load(Ordering::Acquire) { + break; + } + if starttime.elapsed() > Duration::from_secs(3) { + panic!("Timeout waiting for SIGALRM"); + } + } + + // Cleanup: + // 1) deregister the OS's timer. + // 2) Wait for a full timer period, since POSIX does not require that + // disabling the timer will clear pending signals, and on NetBSD at least + // it does not. + // 2) Replace the old signal handler now that we've completed the test. If + // the test fails this process panics, so the fact we might not get here + // is okay. + drop(timer); + thread::sleep(TIMER_PERIOD); + unsafe { + sigaction(SIG, &old_handler).expect("unable to reset signal handler"); + } +} diff --git a/vendor/nix-0.26.2/test/test_unistd.rs b/vendor/nix-0.26.2/test/test_unistd.rs new file mode 100644 index 0000000000000..9e20f977ecd4d --- /dev/null +++ b/vendor/nix-0.26.2/test/test_unistd.rs @@ -0,0 +1,1407 @@ +use libc::{_exit, mode_t, off_t}; +use nix::errno::Errno; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use nix::fcntl::readlink; +use nix::fcntl::OFlag; +#[cfg(not(target_os = "redox"))] +use nix::fcntl::{self, open}; +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] +use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt}; +#[cfg(not(target_os = "redox"))] +use nix::sys::signal::{ + sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, +}; +use nix::sys::stat::{self, Mode, SFlag}; +use nix::sys::wait::*; +use nix::unistd::ForkResult::*; +use nix::unistd::*; +use std::env; +#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))] +use std::ffi::CString; +#[cfg(not(target_os = "redox"))] +use std::fs::DirBuilder; +use std::fs::{self, File}; +use std::io::Write; +use std::os::unix::prelude::*; +#[cfg(not(any( + target_os = "fuchsia", + target_os = "redox", + target_os = "haiku" +)))] +use std::path::Path; +use tempfile::{tempdir, tempfile}; + +use crate::*; + +#[test] +#[cfg(not(any(target_os = "netbsd")))] +fn test_fork_and_waitpid() { + let _m = crate::FORK_MTX.lock(); + + // Safe: Child only calls `_exit`, which is signal-safe + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => unsafe { _exit(0) }, + Parent { child } => { + // assert that child was created and pid > 0 + let child_raw: ::libc::pid_t = child.into(); + assert!(child_raw > 0); + let wait_status = waitpid(child, None); + match wait_status { + // assert that waitpid returned correct status and the pid is the one of the child + Ok(WaitStatus::Exited(pid_t, _)) => assert_eq!(pid_t, child), + + // panic, must never happen + s @ Ok(_) => { + panic!("Child exited {:?}, should never happen", s) + } + + // panic, waitpid should never fail + Err(s) => panic!("Error: waitpid returned Err({:?}", s), + } + } + } +} + +#[test] +fn test_wait() { + // Grab FORK_MTX so wait doesn't reap a different test's child process + let _m = crate::FORK_MTX.lock(); + + // Safe: Child only calls `_exit`, which is signal-safe + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => unsafe { _exit(0) }, + Parent { child } => { + let wait_status = wait(); + + // just assert that (any) one child returns with WaitStatus::Exited + assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0))); + } + } +} + +#[test] +fn test_mkstemp() { + let mut path = env::temp_dir(); + path.push("nix_tempfile.XXXXXX"); + + let result = mkstemp(&path); + match result { + Ok((fd, path)) => { + close(fd).unwrap(); + unlink(path.as_path()).unwrap(); + } + Err(e) => panic!("mkstemp failed: {}", e), + } +} + +#[test] +fn test_mkstemp_directory() { + // mkstemp should fail if a directory is given + mkstemp(&env::temp_dir()).expect_err("assertion failed"); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_mkfifo() { + let tempdir = tempdir().unwrap(); + let mkfifo_fifo = tempdir.path().join("mkfifo_fifo"); + + mkfifo(&mkfifo_fifo, Mode::S_IRUSR).unwrap(); + + let stats = stat::stat(&mkfifo_fifo).unwrap(); + let typ = stat::SFlag::from_bits_truncate(stats.st_mode as mode_t); + assert_eq!(typ, SFlag::S_IFIFO); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_mkfifo_directory() { + // mkfifo should fail if a directory is given + mkfifo(&env::temp_dir(), Mode::S_IRUSR).expect_err("assertion failed"); +} + +#[test] +#[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "redox", + target_os = "haiku" +)))] +fn test_mkfifoat_none() { + let _m = crate::CWD_LOCK.read(); + + let tempdir = tempdir().unwrap(); + let mkfifoat_fifo = tempdir.path().join("mkfifoat_fifo"); + + mkfifoat(None, &mkfifoat_fifo, Mode::S_IRUSR).unwrap(); + + let stats = stat::stat(&mkfifoat_fifo).unwrap(); + let typ = stat::SFlag::from_bits_truncate(stats.st_mode); + assert_eq!(typ, SFlag::S_IFIFO); +} + +#[test] +#[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "redox", + target_os = "haiku" +)))] +fn test_mkfifoat() { + use nix::fcntl; + + let tempdir = tempdir().unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let mkfifoat_name = "mkfifoat_name"; + + mkfifoat(Some(dirfd), mkfifoat_name, Mode::S_IRUSR).unwrap(); + + let stats = + stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap(); + let typ = stat::SFlag::from_bits_truncate(stats.st_mode); + assert_eq!(typ, SFlag::S_IFIFO); +} + +#[test] +#[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "redox", + target_os = "haiku" +)))] +fn test_mkfifoat_directory_none() { + let _m = crate::CWD_LOCK.read(); + + // mkfifoat should fail if a directory is given + mkfifoat(None, &env::temp_dir(), Mode::S_IRUSR) + .expect_err("assertion failed"); +} + +#[test] +#[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "redox", + target_os = "haiku" +)))] +fn test_mkfifoat_directory() { + // mkfifoat should fail if a directory is given + let tempdir = tempdir().unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let mkfifoat_dir = "mkfifoat_dir"; + stat::mkdirat(dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap(); + + mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR) + .expect_err("assertion failed"); +} + +#[test] +fn test_getpid() { + let pid: ::libc::pid_t = getpid().into(); + let ppid: ::libc::pid_t = getppid().into(); + assert!(pid > 0); + assert!(ppid > 0); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_getsid() { + let none_sid: ::libc::pid_t = getsid(None).unwrap().into(); + let pid_sid: ::libc::pid_t = getsid(Some(getpid())).unwrap().into(); + assert!(none_sid > 0); + assert_eq!(none_sid, pid_sid); +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +mod linux_android { + use nix::unistd::gettid; + + #[test] + fn test_gettid() { + let tid: ::libc::pid_t = gettid().into(); + assert!(tid > 0); + } +} + +#[test] +// `getgroups()` and `setgroups()` do not behave as expected on Apple platforms +#[cfg(not(any( + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] +fn test_setgroups() { + // Skip this test when not run as root as `setgroups()` requires root. + skip_if_not_root!("test_setgroups"); + + let _m = crate::GROUPS_MTX.lock(); + + // Save the existing groups + let old_groups = getgroups().unwrap(); + + // Set some new made up groups + let groups = [Gid::from_raw(123), Gid::from_raw(456)]; + setgroups(&groups).unwrap(); + + let new_groups = getgroups().unwrap(); + assert_eq!(new_groups, groups); + + // Revert back to the old groups + setgroups(&old_groups).unwrap(); +} + +#[test] +// `getgroups()` and `setgroups()` do not behave as expected on Apple platforms +#[cfg(not(any( + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos" +)))] +fn test_initgroups() { + // Skip this test when not run as root as `initgroups()` and `setgroups()` + // require root. + skip_if_not_root!("test_initgroups"); + + let _m = crate::GROUPS_MTX.lock(); + + // Save the existing groups + let old_groups = getgroups().unwrap(); + + // It doesn't matter if the root user is not called "root" or if a user + // called "root" doesn't exist. We are just checking that the extra, + // made-up group, `123`, is set. + // FIXME: Test the other half of initgroups' functionality: whether the + // groups that the user belongs to are also set. + let user = CString::new("root").unwrap(); + let group = Gid::from_raw(123); + let group_list = getgrouplist(&user, group).unwrap(); + assert!(group_list.contains(&group)); + + initgroups(&user, group).unwrap(); + + let new_groups = getgroups().unwrap(); + assert_eq!(new_groups, group_list); + + // Revert back to the old groups + setgroups(&old_groups).unwrap(); +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))] +macro_rules! execve_test_factory ( + ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => ( + + #[cfg(test)] + mod $test_name { + use std::ffi::CStr; + use super::*; + + const EMPTY: &'static [u8] = b"\0"; + const DASH_C: &'static [u8] = b"-c\0"; + const BIGARG: &'static [u8] = b"echo nix!!! && echo foo=$foo && echo baz=$baz\0"; + const FOO: &'static [u8] = b"foo=bar\0"; + const BAZ: &'static [u8] = b"baz=quux\0"; + + fn syscall_cstr_ref() -> Result { + $syscall( + $exe, + $(CString::new($pathname).unwrap().as_c_str(), )* + &[CStr::from_bytes_with_nul(EMPTY).unwrap(), + CStr::from_bytes_with_nul(DASH_C).unwrap(), + CStr::from_bytes_with_nul(BIGARG).unwrap()], + &[CStr::from_bytes_with_nul(FOO).unwrap(), + CStr::from_bytes_with_nul(BAZ).unwrap()] + $(, $flags)*) + } + + fn syscall_cstring() -> Result { + $syscall( + $exe, + $(CString::new($pathname).unwrap().as_c_str(), )* + &[CString::from(CStr::from_bytes_with_nul(EMPTY).unwrap()), + CString::from(CStr::from_bytes_with_nul(DASH_C).unwrap()), + CString::from(CStr::from_bytes_with_nul(BIGARG).unwrap())], + &[CString::from(CStr::from_bytes_with_nul(FOO).unwrap()), + CString::from(CStr::from_bytes_with_nul(BAZ).unwrap())] + $(, $flags)*) + } + + fn common_test(syscall: fn() -> Result) { + if "execveat" == stringify!($syscall) { + // Though undocumented, Docker's default seccomp profile seems to + // block this syscall. https://github.com/nix-rust/nix/issues/1122 + skip_if_seccomp!($test_name); + } + + let m = crate::FORK_MTX.lock(); + // The `exec`d process will write to `writer`, and we'll read that + // data from `reader`. + let (reader, writer) = pipe().unwrap(); + + // Safe: Child calls `exit`, `dup`, `close` and the provided `exec*` family function. + // NOTE: Technically, this makes the macro unsafe to use because you could pass anything. + // The tests make sure not to do that, though. + match unsafe{fork()}.unwrap() { + Child => { + // Make `writer` be the stdout of the new process. + dup2(writer, 1).unwrap(); + let r = syscall(); + let _ = std::io::stderr() + .write_all(format!("{:?}", r).as_bytes()); + // Should only get here in event of error + unsafe{ _exit(1) }; + }, + Parent { child } => { + // Wait for the child to exit. + let ws = waitpid(child, None); + drop(m); + assert_eq!(ws, Ok(WaitStatus::Exited(child, 0))); + // Read 1024 bytes. + let mut buf = [0u8; 1024]; + read(reader, &mut buf).unwrap(); + // It should contain the things we printed using `/bin/sh`. + let string = String::from_utf8_lossy(&buf); + assert!(string.contains("nix!!!")); + assert!(string.contains("foo=bar")); + assert!(string.contains("baz=quux")); + } + } + } + + // These tests frequently fail on musl, probably due to + // https://github.com/nix-rust/nix/issues/555 + #[cfg_attr(target_env = "musl", ignore)] + #[test] + fn test_cstr_ref() { + common_test(syscall_cstr_ref); + } + + // These tests frequently fail on musl, probably due to + // https://github.com/nix-rust/nix/issues/555 + #[cfg_attr(target_env = "musl", ignore)] + #[test] + fn test_cstring() { + common_test(syscall_cstring); + } + } + + ) +); + +cfg_if! { + if #[cfg(target_os = "android")] { + execve_test_factory!(test_execve, execve, CString::new("/system/bin/sh").unwrap().as_c_str()); + execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd()); + } else if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux"))] { + // These tests frequently fail on musl, probably due to + // https://github.com/nix-rust/nix/issues/555 + execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str()); + execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd()); + } else if #[cfg(any(target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris"))] { + execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str()); + // No fexecve() on ios, macos, NetBSD, OpenBSD. + } +} + +#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))] +execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap()); + +cfg_if! { + if #[cfg(target_os = "android")] { + use nix::fcntl::AtFlags; + execve_test_factory!(test_execveat_empty, execveat, + File::open("/system/bin/sh").unwrap().into_raw_fd(), + "", AtFlags::AT_EMPTY_PATH); + execve_test_factory!(test_execveat_relative, execveat, + File::open("/system/bin/").unwrap().into_raw_fd(), + "./sh", AtFlags::empty()); + execve_test_factory!(test_execveat_absolute, execveat, + File::open("/").unwrap().into_raw_fd(), + "/system/bin/sh", AtFlags::empty()); + } else if #[cfg(all(target_os = "linux", any(target_arch ="x86_64", target_arch ="x86")))] { + use nix::fcntl::AtFlags; + execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(), + "", AtFlags::AT_EMPTY_PATH); + execve_test_factory!(test_execveat_relative, execveat, File::open("/bin/").unwrap().into_raw_fd(), + "./sh", AtFlags::empty()); + execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(), + "/bin/sh", AtFlags::empty()); + } +} + +#[test] +#[cfg(not(target_os = "fuchsia"))] +fn test_fchdir() { + // fchdir changes the process's cwd + let _dr = crate::DirRestore::new(); + + let tmpdir = tempdir().unwrap(); + let tmpdir_path = tmpdir.path().canonicalize().unwrap(); + let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd(); + + fchdir(tmpdir_fd).expect("assertion failed"); + assert_eq!(getcwd().unwrap(), tmpdir_path); + + close(tmpdir_fd).expect("assertion failed"); +} + +#[test] +fn test_getcwd() { + // chdir changes the process's cwd + let _dr = crate::DirRestore::new(); + + let tmpdir = tempdir().unwrap(); + let tmpdir_path = tmpdir.path().canonicalize().unwrap(); + chdir(&tmpdir_path).expect("assertion failed"); + assert_eq!(getcwd().unwrap(), tmpdir_path); + + // make path 500 chars longer so that buffer doubling in getcwd + // kicks in. Note: One path cannot be longer than 255 bytes + // (NAME_MAX) whole path cannot be longer than PATH_MAX (usually + // 4096 on linux, 1024 on macos) + let mut inner_tmp_dir = tmpdir_path; + for _ in 0..5 { + let newdir = "a".repeat(100); + inner_tmp_dir.push(newdir); + mkdir(inner_tmp_dir.as_path(), Mode::S_IRWXU) + .expect("assertion failed"); + } + chdir(inner_tmp_dir.as_path()).expect("assertion failed"); + assert_eq!(getcwd().unwrap(), inner_tmp_dir.as_path()); +} + +#[test] +fn test_chown() { + // Testing for anything other than our own UID/GID is hard. + let uid = Some(getuid()); + let gid = Some(getgid()); + + let tempdir = tempdir().unwrap(); + let path = tempdir.path().join("file"); + { + File::create(&path).unwrap(); + } + + chown(&path, uid, gid).unwrap(); + chown(&path, uid, None).unwrap(); + chown(&path, None, gid).unwrap(); + + fs::remove_file(&path).unwrap(); + chown(&path, uid, gid).unwrap_err(); +} + +#[test] +fn test_fchown() { + // Testing for anything other than our own UID/GID is hard. + let uid = Some(getuid()); + let gid = Some(getgid()); + + let path = tempfile().unwrap(); + let fd = path.as_raw_fd(); + + fchown(fd, uid, gid).unwrap(); + fchown(fd, uid, None).unwrap(); + fchown(fd, None, gid).unwrap(); + fchown(999999999, uid, gid).unwrap_err(); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_fchownat() { + let _dr = crate::DirRestore::new(); + // Testing for anything other than our own UID/GID is hard. + let uid = Some(getuid()); + let gid = Some(getgid()); + + let tempdir = tempdir().unwrap(); + let path = tempdir.path().join("file"); + { + File::create(&path).unwrap(); + } + + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); + + fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink) + .unwrap(); + + chdir(tempdir.path()).unwrap(); + fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); + + fs::remove_file(&path).unwrap(); + fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap_err(); +} + +#[test] +fn test_lseek() { + const CONTENTS: &[u8] = b"abcdef123456"; + let mut tmp = tempfile().unwrap(); + tmp.write_all(CONTENTS).unwrap(); + let tmpfd = tmp.into_raw_fd(); + + let offset: off_t = 5; + lseek(tmpfd, offset, Whence::SeekSet).unwrap(); + + let mut buf = [0u8; 7]; + crate::read_exact(tmpfd, &mut buf); + assert_eq!(b"f123456", &buf); + + close(tmpfd).unwrap(); +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +#[test] +fn test_lseek64() { + const CONTENTS: &[u8] = b"abcdef123456"; + let mut tmp = tempfile().unwrap(); + tmp.write_all(CONTENTS).unwrap(); + let tmpfd = tmp.into_raw_fd(); + + lseek64(tmpfd, 5, Whence::SeekSet).unwrap(); + + let mut buf = [0u8; 7]; + crate::read_exact(tmpfd, &mut buf); + assert_eq!(b"f123456", &buf); + + close(tmpfd).unwrap(); +} + +cfg_if! { + if #[cfg(any(target_os = "android", target_os = "linux"))] { + macro_rules! require_acct{ + () => { + require_capability!("test_acct", CAP_SYS_PACCT); + } + } + } else if #[cfg(target_os = "freebsd")] { + macro_rules! require_acct{ + () => { + skip_if_not_root!("test_acct"); + skip_if_jailed!("test_acct"); + } + } + } else if #[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] { + macro_rules! require_acct{ + () => { + skip_if_not_root!("test_acct"); + } + } + } +} + +#[test] +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] +fn test_acct() { + use std::process::Command; + use std::{thread, time}; + use tempfile::NamedTempFile; + + let _m = crate::FORK_MTX.lock(); + require_acct!(); + + let file = NamedTempFile::new().unwrap(); + let path = file.path().to_str().unwrap(); + + acct::enable(path).unwrap(); + + loop { + Command::new("echo").arg("Hello world").output().unwrap(); + let len = fs::metadata(path).unwrap().len(); + if len > 0 { + break; + } + thread::sleep(time::Duration::from_millis(10)); + } + acct::disable().unwrap(); +} + +#[test] +fn test_fpathconf_limited() { + let f = tempfile().unwrap(); + // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test + let path_max = fpathconf(f.as_raw_fd(), PathconfVar::PATH_MAX); + assert!( + path_max + .expect("fpathconf failed") + .expect("PATH_MAX is unlimited") + > 0 + ); +} + +#[test] +fn test_pathconf_limited() { + // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test + let path_max = pathconf("/", PathconfVar::PATH_MAX); + assert!( + path_max + .expect("pathconf failed") + .expect("PATH_MAX is unlimited") + > 0 + ); +} + +#[test] +fn test_sysconf_limited() { + // AFAIK, OPEN_MAX is limited on all platforms, so it makes a good test + let open_max = sysconf(SysconfVar::OPEN_MAX); + assert!( + open_max + .expect("sysconf failed") + .expect("OPEN_MAX is unlimited") + > 0 + ); +} + +#[cfg(target_os = "freebsd")] +#[test] +fn test_sysconf_unsupported() { + // I know of no sysconf variables that are unsupported everywhere, but + // _XOPEN_CRYPT is unsupported on FreeBSD 11.0, which is one of the platforms + // we test. + let open_max = sysconf(SysconfVar::_XOPEN_CRYPT); + assert!(open_max.expect("sysconf failed").is_none()) +} + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] +#[test] +fn test_getresuid() { + let resuids = getresuid().unwrap(); + assert_ne!(resuids.real.as_raw(), libc::uid_t::MAX); + assert_ne!(resuids.effective.as_raw(), libc::uid_t::MAX); + assert_ne!(resuids.saved.as_raw(), libc::uid_t::MAX); +} + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] +#[test] +fn test_getresgid() { + let resgids = getresgid().unwrap(); + assert_ne!(resgids.real.as_raw(), libc::gid_t::MAX); + assert_ne!(resgids.effective.as_raw(), libc::gid_t::MAX); + assert_ne!(resgids.saved.as_raw(), libc::gid_t::MAX); +} + +// Test that we can create a pair of pipes. No need to verify that they pass +// data; that's the domain of the OS, not nix. +#[test] +fn test_pipe() { + let (fd0, fd1) = pipe().unwrap(); + let m0 = stat::SFlag::from_bits_truncate( + stat::fstat(fd0).unwrap().st_mode as mode_t, + ); + // S_IFIFO means it's a pipe + assert_eq!(m0, SFlag::S_IFIFO); + let m1 = stat::SFlag::from_bits_truncate( + stat::fstat(fd1).unwrap().st_mode as mode_t, + ); + assert_eq!(m1, SFlag::S_IFIFO); +} + +// pipe2(2) is the same as pipe(2), except it allows setting some flags. Check +// that we can set a flag. +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris" +))] +#[test] +fn test_pipe2() { + use nix::fcntl::{fcntl, FcntlArg, FdFlag}; + + let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap(); + let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap()); + assert!(f0.contains(FdFlag::FD_CLOEXEC)); + let f1 = FdFlag::from_bits_truncate(fcntl(fd1, FcntlArg::F_GETFD).unwrap()); + assert!(f1.contains(FdFlag::FD_CLOEXEC)); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] +fn test_truncate() { + let tempdir = tempdir().unwrap(); + let path = tempdir.path().join("file"); + + { + let mut tmp = File::create(&path).unwrap(); + const CONTENTS: &[u8] = b"12345678"; + tmp.write_all(CONTENTS).unwrap(); + } + + truncate(&path, 4).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + assert_eq!(4, metadata.len()); +} + +#[test] +fn test_ftruncate() { + let tempdir = tempdir().unwrap(); + let path = tempdir.path().join("file"); + + let tmpfd = { + let mut tmp = File::create(&path).unwrap(); + const CONTENTS: &[u8] = b"12345678"; + tmp.write_all(CONTENTS).unwrap(); + tmp.into_raw_fd() + }; + + ftruncate(tmpfd, 2).unwrap(); + close(tmpfd).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + assert_eq!(2, metadata.len()); +} + +// Used in `test_alarm`. +#[cfg(not(target_os = "redox"))] +static mut ALARM_CALLED: bool = false; + +// Used in `test_alarm`. +#[cfg(not(target_os = "redox"))] +pub extern "C" fn alarm_signal_handler(raw_signal: libc::c_int) { + assert_eq!( + raw_signal, + libc::SIGALRM, + "unexpected signal: {}", + raw_signal + ); + unsafe { ALARM_CALLED = true }; +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_alarm() { + use std::{ + thread, + time::{Duration, Instant}, + }; + + // Maybe other tests that fork interfere with this one? + let _m = crate::SIGNAL_MTX.lock(); + + let handler = SigHandler::Handler(alarm_signal_handler); + let signal_action = + SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); + let old_handler = unsafe { + sigaction(Signal::SIGALRM, &signal_action) + .expect("unable to set signal handler for alarm") + }; + + // Set an alarm. + assert_eq!(alarm::set(60), None); + + // Overwriting an alarm should return the old alarm. + assert_eq!(alarm::set(1), Some(60)); + + // We should be woken up after 1 second by the alarm, so we'll sleep for 3 + // seconds to be sure. + let starttime = Instant::now(); + loop { + thread::sleep(Duration::from_millis(100)); + if unsafe { ALARM_CALLED } { + break; + } + if starttime.elapsed() > Duration::from_secs(3) { + panic!("Timeout waiting for SIGALRM"); + } + } + + // Reset the signal. + unsafe { + sigaction(Signal::SIGALRM, &old_handler) + .expect("unable to set signal handler for alarm"); + } +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_canceling_alarm() { + let _m = crate::SIGNAL_MTX.lock(); + + assert_eq!(alarm::cancel(), None); + + assert_eq!(alarm::set(60), None); + assert_eq!(alarm::cancel(), Some(60)); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_symlinkat() { + let _m = crate::CWD_LOCK.read(); + + let tempdir = tempdir().unwrap(); + + let target = tempdir.path().join("a"); + let linkpath = tempdir.path().join("b"); + symlinkat(&target, None, &linkpath).unwrap(); + assert_eq!( + readlink(&linkpath).unwrap().to_str().unwrap(), + target.to_str().unwrap() + ); + + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let target = "c"; + let linkpath = "d"; + symlinkat(target, Some(dirfd), linkpath).unwrap(); + assert_eq!( + readlink(&tempdir.path().join(linkpath)) + .unwrap() + .to_str() + .unwrap(), + target + ); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_linkat_file() { + let tempdir = tempdir().unwrap(); + let oldfilename = "foo.txt"; + let oldfilepath = tempdir.path().join(oldfilename); + + let newfilename = "bar.txt"; + let newfilepath = tempdir.path().join(newfilename); + + // Create file + File::create(oldfilepath).unwrap(); + + // Get file descriptor for base directory + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + + // Attempt hard link file at relative path + linkat( + Some(dirfd), + oldfilename, + Some(dirfd), + newfilename, + LinkatFlags::SymlinkFollow, + ) + .unwrap(); + assert!(newfilepath.exists()); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_linkat_olddirfd_none() { + let _dr = crate::DirRestore::new(); + + let tempdir_oldfile = tempdir().unwrap(); + let oldfilename = "foo.txt"; + let oldfilepath = tempdir_oldfile.path().join(oldfilename); + + let tempdir_newfile = tempdir().unwrap(); + let newfilename = "bar.txt"; + let newfilepath = tempdir_newfile.path().join(newfilename); + + // Create file + File::create(oldfilepath).unwrap(); + + // Get file descriptor for base directory of new file + let dirfd = fcntl::open( + tempdir_newfile.path(), + fcntl::OFlag::empty(), + stat::Mode::empty(), + ) + .unwrap(); + + // Attempt hard link file using curent working directory as relative path for old file path + chdir(tempdir_oldfile.path()).unwrap(); + linkat( + None, + oldfilename, + Some(dirfd), + newfilename, + LinkatFlags::SymlinkFollow, + ) + .unwrap(); + assert!(newfilepath.exists()); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_linkat_newdirfd_none() { + let _dr = crate::DirRestore::new(); + + let tempdir_oldfile = tempdir().unwrap(); + let oldfilename = "foo.txt"; + let oldfilepath = tempdir_oldfile.path().join(oldfilename); + + let tempdir_newfile = tempdir().unwrap(); + let newfilename = "bar.txt"; + let newfilepath = tempdir_newfile.path().join(newfilename); + + // Create file + File::create(oldfilepath).unwrap(); + + // Get file descriptor for base directory of old file + let dirfd = fcntl::open( + tempdir_oldfile.path(), + fcntl::OFlag::empty(), + stat::Mode::empty(), + ) + .unwrap(); + + // Attempt hard link file using current working directory as relative path for new file path + chdir(tempdir_newfile.path()).unwrap(); + linkat( + Some(dirfd), + oldfilename, + None, + newfilename, + LinkatFlags::SymlinkFollow, + ) + .unwrap(); + assert!(newfilepath.exists()); +} + +#[test] +#[cfg(not(any( + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "haiku" +)))] +fn test_linkat_no_follow_symlink() { + let _m = crate::CWD_LOCK.read(); + + let tempdir = tempdir().unwrap(); + let oldfilename = "foo.txt"; + let oldfilepath = tempdir.path().join(oldfilename); + + let symoldfilename = "symfoo.txt"; + let symoldfilepath = tempdir.path().join(symoldfilename); + + let newfilename = "nofollowsymbar.txt"; + let newfilepath = tempdir.path().join(newfilename); + + // Create file + File::create(&oldfilepath).unwrap(); + + // Create symlink to file + symlinkat(&oldfilepath, None, &symoldfilepath).unwrap(); + + // Get file descriptor for base directory + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + + // Attempt link symlink of file at relative path + linkat( + Some(dirfd), + symoldfilename, + Some(dirfd), + newfilename, + LinkatFlags::NoSymlinkFollow, + ) + .unwrap(); + + // Assert newfile is actually a symlink to oldfile. + assert_eq!( + readlink(&newfilepath).unwrap().to_str().unwrap(), + oldfilepath.to_str().unwrap() + ); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_linkat_follow_symlink() { + let _m = crate::CWD_LOCK.read(); + + let tempdir = tempdir().unwrap(); + let oldfilename = "foo.txt"; + let oldfilepath = tempdir.path().join(oldfilename); + + let symoldfilename = "symfoo.txt"; + let symoldfilepath = tempdir.path().join(symoldfilename); + + let newfilename = "nofollowsymbar.txt"; + let newfilepath = tempdir.path().join(newfilename); + + // Create file + File::create(&oldfilepath).unwrap(); + + // Create symlink to file + symlinkat(&oldfilepath, None, &symoldfilepath).unwrap(); + + // Get file descriptor for base directory + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + + // Attempt link target of symlink of file at relative path + linkat( + Some(dirfd), + symoldfilename, + Some(dirfd), + newfilename, + LinkatFlags::SymlinkFollow, + ) + .unwrap(); + + let newfilestat = stat::stat(&newfilepath).unwrap(); + + // Check the file type of the new link + assert_eq!( + (stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t) + & SFlag::S_IFMT), + SFlag::S_IFREG + ); + + // Check the number of hard links to the original file + assert_eq!(newfilestat.st_nlink, 2); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_unlinkat_dir_noremovedir() { + let tempdir = tempdir().unwrap(); + let dirname = "foo_dir"; + let dirpath = tempdir.path().join(dirname); + + // Create dir + DirBuilder::new().recursive(true).create(dirpath).unwrap(); + + // Get file descriptor for base directory + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + + // Attempt unlink dir at relative path without proper flag + let err_result = + unlinkat(Some(dirfd), dirname, UnlinkatFlags::NoRemoveDir).unwrap_err(); + assert!(err_result == Errno::EISDIR || err_result == Errno::EPERM); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_unlinkat_dir_removedir() { + let tempdir = tempdir().unwrap(); + let dirname = "foo_dir"; + let dirpath = tempdir.path().join(dirname); + + // Create dir + DirBuilder::new().recursive(true).create(&dirpath).unwrap(); + + // Get file descriptor for base directory + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + + // Attempt unlink dir at relative path with proper flag + unlinkat(Some(dirfd), dirname, UnlinkatFlags::RemoveDir).unwrap(); + assert!(!dirpath.exists()); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_unlinkat_file() { + let tempdir = tempdir().unwrap(); + let filename = "foo.txt"; + let filepath = tempdir.path().join(filename); + + // Create file + File::create(&filepath).unwrap(); + + // Get file descriptor for base directory + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + + // Attempt unlink file at relative path + unlinkat(Some(dirfd), filename, UnlinkatFlags::NoRemoveDir).unwrap(); + assert!(!filepath.exists()); +} + +#[test] +fn test_access_not_existing() { + let tempdir = tempdir().unwrap(); + let dir = tempdir.path().join("does_not_exist.txt"); + assert_eq!( + access(&dir, AccessFlags::F_OK).err().unwrap(), + Errno::ENOENT + ); +} + +#[test] +fn test_access_file_exists() { + let tempdir = tempdir().unwrap(); + let path = tempdir.path().join("does_exist.txt"); + let _file = File::create(path.clone()).unwrap(); + access(&path, AccessFlags::R_OK | AccessFlags::W_OK) + .expect("assertion failed"); +} + +//Clippy false positive https://github.com/rust-lang/rust-clippy/issues/9111 +#[allow(clippy::needless_borrow)] +#[cfg(not(target_os = "redox"))] +#[test] +fn test_user_into_passwd() { + // get the UID of the "nobody" user + #[cfg(not(target_os = "haiku"))] + let test_username = "nobody"; + // "nobody" unavailable on haiku + #[cfg(target_os = "haiku")] + let test_username = "user"; + + let nobody = User::from_name(test_username).unwrap().unwrap(); + let pwd: libc::passwd = nobody.into(); + let _: User = (&pwd).into(); +} + +/// Tests setting the filesystem UID with `setfsuid`. +#[cfg(any(target_os = "linux", target_os = "android"))] +#[test] +fn test_setfsuid() { + use std::os::unix::fs::PermissionsExt; + use std::{fs, io, thread}; + require_capability!("test_setfsuid", CAP_SETUID); + + // get the UID of the "nobody" user + let nobody = User::from_name("nobody").unwrap().unwrap(); + + // create a temporary file with permissions '-rw-r-----' + let file = tempfile::NamedTempFile::new_in("/var/tmp").unwrap(); + let temp_path = file.into_temp_path(); + let temp_path_2 = temp_path.to_path_buf(); + let mut permissions = fs::metadata(&temp_path).unwrap().permissions(); + permissions.set_mode(0o640); + + // spawn a new thread where to test setfsuid + thread::spawn(move || { + // set filesystem UID + let fuid = setfsuid(nobody.uid); + // trying to open the temporary file should fail with EACCES + let res = fs::File::open(&temp_path); + let err = res.expect_err("assertion failed"); + assert_eq!(err.kind(), io::ErrorKind::PermissionDenied); + + // assert fuid actually changes + let prev_fuid = setfsuid(Uid::from_raw(-1i32 as u32)); + assert_ne!(prev_fuid, fuid); + }) + .join() + .unwrap(); + + // open the temporary file with the current thread filesystem UID + fs::File::open(temp_path_2).unwrap(); +} + +#[test] +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] +fn test_ttyname() { + let fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); + assert!(fd.as_raw_fd() > 0); + + // on linux, we can just call ttyname on the pty master directly, but + // apparently osx requires that ttyname is called on a slave pty (can't + // find this documented anywhere, but it seems to empirically be the case) + grantpt(&fd).expect("grantpt failed"); + unlockpt(&fd).expect("unlockpt failed"); + let sname = unsafe { ptsname(&fd) }.expect("ptsname failed"); + let fds = open(Path::new(&sname), OFlag::O_RDWR, stat::Mode::empty()) + .expect("open failed"); + assert!(fds > 0); + + let name = ttyname(fds).expect("ttyname failed"); + assert!(name.starts_with("/dev")); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] +fn test_ttyname_not_pty() { + let fd = File::open("/dev/zero").unwrap(); + assert!(fd.as_raw_fd() > 0); + assert_eq!(ttyname(fd.as_raw_fd()), Err(Errno::ENOTTY)); +} + +#[test] +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] +fn test_ttyname_invalid_fd() { + assert_eq!(ttyname(-1), Err(Errno::EBADF)); +} + +#[test] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", +))] +fn test_getpeereid() { + use std::os::unix::net::UnixStream; + let (sock_a, sock_b) = UnixStream::pair().unwrap(); + + let (uid_a, gid_a) = getpeereid(sock_a.as_raw_fd()).unwrap(); + let (uid_b, gid_b) = getpeereid(sock_b.as_raw_fd()).unwrap(); + + let uid = geteuid(); + let gid = getegid(); + + assert_eq!(uid, uid_a); + assert_eq!(gid, gid_a); + assert_eq!(uid_a, uid_b); + assert_eq!(gid_a, gid_b); +} + +#[test] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", +))] +fn test_getpeereid_invalid_fd() { + // getpeereid is not POSIX, so error codes are inconsistent between different Unices. + getpeereid(-1).expect_err("assertion failed"); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_faccessat_none_not_existing() { + use nix::fcntl::AtFlags; + let tempdir = tempfile::tempdir().unwrap(); + let dir = tempdir.path().join("does_not_exist.txt"); + assert_eq!( + faccessat(None, &dir, AccessFlags::F_OK, AtFlags::empty()) + .err() + .unwrap(), + Errno::ENOENT + ); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_faccessat_not_existing() { + use nix::fcntl::AtFlags; + let tempdir = tempfile::tempdir().unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let not_exist_file = "does_not_exist.txt"; + assert_eq!( + faccessat( + Some(dirfd), + not_exist_file, + AccessFlags::F_OK, + AtFlags::empty(), + ) + .err() + .unwrap(), + Errno::ENOENT + ); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_faccessat_none_file_exists() { + use nix::fcntl::AtFlags; + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("does_exist.txt"); + let _file = File::create(path.clone()).unwrap(); + assert!(faccessat( + None, + &path, + AccessFlags::R_OK | AccessFlags::W_OK, + AtFlags::empty(), + ) + .is_ok()); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_faccessat_file_exists() { + use nix::fcntl::AtFlags; + let tempdir = tempfile::tempdir().unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let exist_file = "does_exist.txt"; + let path = tempdir.path().join(exist_file); + let _file = File::create(path.clone()).unwrap(); + assert!(faccessat( + Some(dirfd), + &path, + AccessFlags::R_OK | AccessFlags::W_OK, + AtFlags::empty(), + ) + .is_ok()); +} + +#[test] +#[cfg(any( + all(target_os = "linux", not(target_env = "uclibc")), + target_os = "freebsd", + target_os = "dragonfly" +))] +fn test_eaccess_not_existing() { + let tempdir = tempdir().unwrap(); + let dir = tempdir.path().join("does_not_exist.txt"); + assert_eq!( + eaccess(&dir, AccessFlags::F_OK).err().unwrap(), + Errno::ENOENT + ); +} + +#[test] +#[cfg(any( + all(target_os = "linux", not(target_env = "uclibc")), + target_os = "freebsd", + target_os = "dragonfly" +))] +fn test_eaccess_file_exists() { + let tempdir = tempdir().unwrap(); + let path = tempdir.path().join("does_exist.txt"); + let _file = File::create(path.clone()).unwrap(); + eaccess(&path, AccessFlags::R_OK | AccessFlags::W_OK) + .expect("assertion failed"); +} diff --git a/vendor/num-bigint/build.rs b/vendor/num-bigint/build.rs new file mode 100644 index 0000000000000..5d5406c932576 --- /dev/null +++ b/vendor/num-bigint/build.rs @@ -0,0 +1,94 @@ +use std::env; +use std::error::Error; +use std::fs::File; +use std::io::Write; +use std::path::Path; + +fn main() { + let ptr_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH"); + let u64_digit = ptr_width + .as_ref() + .map(|x| x == "64" || x == "128") + .unwrap_or(false); + + if u64_digit { + autocfg::emit("u64_digit"); + } + + let ac = autocfg::new(); + let std = if ac.probe_sysroot_crate("std") { + "std" + } else { + "core" + }; + + if ac.probe_path(&format!("{}::convert::TryFrom", std)) { + autocfg::emit("has_try_from"); + } + + if let Ok(arch) = env::var("CARGO_CFG_TARGET_ARCH") { + if arch == "x86_64" || arch == "x86" { + let digit = if u64_digit { "u64" } else { "u32" }; + + let addcarry = format!("{}::arch::{}::_addcarry_{}", std, arch, digit); + if ac.probe_path(&addcarry) { + autocfg::emit("use_addcarry"); + } + } + } + + autocfg::rerun_path("build.rs"); + + write_radix_bases().unwrap(); +} + +/// Write tables of the greatest power of each radix for the given bit size. These are returned +/// from `biguint::get_radix_base` to batch the multiplication/division of radix conversions on +/// full `BigUint` values, operating on primitive integers as much as possible. +/// +/// e.g. BASES_16[3] = (59049, 10) // 3¹Ⱐfits in u16, but 3¹¹ is too big +/// BASES_32[3] = (3486784401, 20) +/// BASES_64[3] = (12157665459056928801, 40) +/// +/// Powers of two are not included, just zeroed, as they're implemented with shifts. +fn write_radix_bases() -> Result<(), Box> { + let out_dir = env::var("OUT_DIR")?; + let dest_path = Path::new(&out_dir).join("radix_bases.rs"); + let mut f = File::create(&dest_path)?; + + for &bits in &[16, 32, 64] { + let max = if bits < 64 { + (1 << bits) - 1 + } else { + std::u64::MAX + }; + + writeln!(f, "#[deny(overflowing_literals)]")?; + writeln!( + f, + "pub(crate) static BASES_{bits}: [(u{bits}, usize); 257] = [", + bits = bits + )?; + for radix in 0u64..257 { + let (base, power) = if radix == 0 || radix.is_power_of_two() { + (0, 0) + } else { + let mut power = 1; + let mut base = radix; + + while let Some(b) = base.checked_mul(radix) { + if b > max { + break; + } + base = b; + power += 1; + } + (base, power) + }; + writeln!(f, " ({}, {}), // {}", base, power, radix)?; + } + writeln!(f, "];")?; + } + + Ok(()) +} diff --git a/vendor/num-integer/build.rs b/vendor/num-integer/build.rs new file mode 100644 index 0000000000000..37c985766a384 --- /dev/null +++ b/vendor/num-integer/build.rs @@ -0,0 +1,13 @@ +extern crate autocfg; + +use std::env; + +fn main() { + // If the "i128" feature is explicity requested, don't bother probing for it. + // It will still cause a build error if that was set improperly. + if env::var_os("CARGO_FEATURE_I128").is_some() || autocfg::new().probe_type("i128") { + autocfg::emit("has_i128"); + } + + autocfg::rerun_path("build.rs"); +} diff --git a/vendor/num-iter/build.rs b/vendor/num-iter/build.rs new file mode 100644 index 0000000000000..4f39b83c59212 --- /dev/null +++ b/vendor/num-iter/build.rs @@ -0,0 +1,19 @@ +extern crate autocfg; + +use std::env; + +fn main() { + let autocfg = autocfg::new(); + + // If the "i128" feature is explicity requested, don't bother probing for it. + // It will still cause a build error if that was set improperly. + if env::var_os("CARGO_FEATURE_I128").is_some() || autocfg.probe_type("i128") { + autocfg::emit("has_i128"); + } + + // The RangeBounds trait was stabilized in 1.28, so from that version onwards we + // implement that trait. + autocfg.emit_rustc_version(1, 28); + + autocfg::rerun_path("build.rs"); +} diff --git a/vendor/objc/.cargo-checksum.json b/vendor/objc/.cargo-checksum.json new file mode 100644 index 0000000000000..3b36dfaa71dea --- /dev/null +++ b/vendor/objc/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"b75b0c2c69a1b22b3e8a554f94353c423aef7e3891a66eefdee0b3a0813debf7","Cargo.lock":"a133d68c72c3735526ec3dcae9cfcd8928d19de7532940488f4527d1946fb954","Cargo.toml":"d051e9534ddcac152d11d2c2b6e040136b22397fb5579867fd3de67c0c3b44f3","LICENSE.txt":"e353f37b12aefbb9f9b29490e837cfee05d9bda70804b3562839a3285c1df1e5","README.md":"2798cf78a640ea9fb83bdf27e2c82d98d9f8f7459196ab9db10372fb843c7a65","examples/example.rs":"df5fd939ffa46505b368e4e31aa0a0b144202fbceac72e5343bedb706313ef5e","src/declare.rs":"a4409a3b849413af55398b9b6a86ca482bdea94dd16ce818b39d420228426b54","src/encode.rs":"6e792c73f7cfced248f20cebe93dc038a39d25bdd9cbe1a115464b7baa02885b","src/exception.rs":"a641f9fdb9267e1d44f680b685d650faa2931d5d22949b621c8e2783ed534a4f","src/lib.rs":"1b03c53c792b0abe909d2958d7b692b2264ae0f25a109c15dacf57da2352f6f7","src/macros.rs":"b0d82088510fa6a14b1dfa240e91f85b0d13536bbf1a28d33a5dc932409b7279","src/message/apple/arm.rs":"3df72141b9fa48e7eab13b33acfa76c0eae730c2eedad0cc92ed7f89c51ca0da","src/message/apple/arm64.rs":"3efa598e34232c1e1c2171de864beac7f79e10f85807b23d10537335e0e84bd3","src/message/apple/mod.rs":"8aa9b9419084f92acc4468dae647b6bc3bd4570de0dbffe82dd8b6a18883345e","src/message/apple/x86.rs":"a268b01e54d0c7cbd9ae765815524fbd5f7c92c339f110f1f3d76877e5238597","src/message/apple/x86_64.rs":"bb64ad8de038b65cda61eaa55a46ce56795aeb36b574dc4dbbfd0d328aa23889","src/message/gnustep.rs":"15bbf9abc5aa0edc25b8b1d9622ebcacc33fd1103fe20a6a93ba9d82ca1b262d","src/message/mod.rs":"aa9da24db7d02ed7d827d78d53936c132fc9302e7fdc09380bdf7021ddd16ae6","src/message/verify.rs":"0047219354c49568a14f7aa7a5bb91edca16e5636a30c66c15a1533668759845","src/rc/autorelease.rs":"f56e26a5f866b5dbbe5c336289bbe21d5a5872928d504c5dfdfda3eeaedd5a3e","src/rc/mod.rs":"ce4b5206fa8273ad3931376d18c1b9aca6cef8172eb2ff8daf962fee710db9d7","src/rc/strong.rs":"f472889e5827cd67f6df62f50e55fdc2101bcdfeb59c7d39dacc5f30a0ed06bb","src/rc/weak.rs":"0b4f77abcd9f1eec1993b6cc6f3db564d90aafe3dbf15233a6f268ded48ef6cb","src/runtime.rs":"69b33722d727faef47e3fb14e68bb18b96a970930a1f9b244e2bb4e161d67874","src/test_utils.rs":"db73875ff5ae4761187d3691998829a689e3dfd26b9812bdebc1bcae0388f78b"},"package":"915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"} \ No newline at end of file diff --git a/vendor/objc/CHANGELOG.md b/vendor/objc/CHANGELOG.md new file mode 100644 index 0000000000000..c8b1bf8944f58 --- /dev/null +++ b/vendor/objc/CHANGELOG.md @@ -0,0 +1,117 @@ +## 0.2.7 + +### Fixed + +* Uses of `msg_send!` will now correctly fail to compile if no return type + can be inferred, instead of relying on an edge case of the compiler + that will soon change and silently cause undefined behavior. + +## 0.2.6 + +### Fixed + +* Suppressed a deprecation warning in `sel!`, `msg_send!`, and `class!`. + +## 0.2.5 + +### Added + +* `autoreleasepool` returns the value returned by its body closure. + +## 0.2.4 + +### Added + +* Added an `rc` module with reference counting utilities: + `StrongPtr`, `WeakPtr`, and `autoreleasepool`. + +* Added some reference counting ABI foreign functions to the `runtime` module. + +### Fixed + +* Messaging nil under GNUstep now correctly returns zeroed results for all + return types. + +## 0.2.3 + +### Added + +* Added a `class!` macro for getting statically-known classes. The result is + non-optional (avoiding a need to unwrap) and cached so each usage will only + look up the class once. + +* Added caching to the `sel!` macro so that each usage will only register the + selector once. + +### Fixed + +* Fixed the implementation of `objc::runtime` structs so there can't be unsound + references to uninhabited types. + +## 0.2.2 + +### Added + +* Implemented `Sync` and `Send` for `Sel`. + +## 0.2.1 + +### Added + +* Added support for working with protocols with the `Protocol` struct. + The protocols a class conforms to can be examined with the new + `Class::adopted_protocols` and `Class::conforms_to` methods. + +* Protocols can be declared using the new `ProtocolDecl` struct. + +## 0.2.0 + +### Added + +* Added verification for the types used when sending messages. + This can be enabled for all messages with the `"verify_message"` feature, + or you can test before sending specific messages with the + `Message::verify_message` method. Verification errors are reported using the + new `MessageError` struct. + +* Added support for the GNUstep runtime! + Operating systems besides OSX and iOS will fall back to the GNUstep runtime. + +* Root classes can be declared by using the `ClassDecl::root` constructor. + +### Changed + +* C types are now used from `std::os::raw` rather than `libc`. This means + `Encode` may not be implemented for `libc` types; switch them to the + `std::os::raw` equivalents instead. This avoids an issue that would arise + from simultaneously using different versions of the libc crate. + +* Dynamic messaging was moved into the `Message` trait; instead of + `().send(obj, sel!(description))`, use + `obj.send_message(sel!(description), ())`. + +* Rearranged the parameters to `ClassDecl::new` for consistency; instead of + `ClassDecl::new(superclass, "MyObject")`, use + `ClassDecl::new("MyObject", superclass)`. + +* Overhauled the `MethodImplementation` trait. Encodings are now accessed + through the `MethodImplementation::Args` associated type. The `imp_for` + method was replaced with `imp` and no longer takes a selector or returns an + `UnequalArgsError`, although `ClassDecl::add_method` still validates the + number of arguments. + +* Updated the definition of `Imp` to not use the old dispatch prototypes. + To invoke an `Imp`, it must first be transmuted to the correct type. + +* Removed `objc_msgSend` functions from the `runtime` module; the availability + of these functions varies and they shouldn't be called without trasmuting, + so they are now hidden as an implementation detail of messaging. + +### Fixed + +* Corrected alignment of ivars in `ClassDecl`; declared classes may now have a + smaller size. + +* With the `"exception"` or `"verify_message"` feature enabled, panics from + `msg_send!` will now be triggered from the line and file where the macro is + used, rather than from within the implementation of messaging. diff --git a/vendor/objc/Cargo.lock b/vendor/objc/Cargo.lock new file mode 100644 index 0000000000000..122fb19384a7a --- /dev/null +++ b/vendor/objc/Cargo.lock @@ -0,0 +1,41 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.57" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.57 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "objc" +version = "0.2.7" +dependencies = [ + "malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc_exception 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "objc_exception" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +"checksum libc 0.2.57 (registry+https://github.com/rust-lang/crates.io-index)" = "a844cabbd5a77e60403a58af576f0a1baa83c3dd2670be63e615bd24fc58b82d" +"checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +"checksum objc_exception 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "098cd29a2fa3c230d3463ae069cecccc3fdfd64c0d2496ab5b96f82dab6a00dc" diff --git a/vendor/objc/Cargo.toml b/vendor/objc/Cargo.toml new file mode 100644 index 0000000000000..08272304b6e38 --- /dev/null +++ b/vendor/objc/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "objc" +version = "0.2.7" +authors = ["Steven Sheldon"] +exclude = [".gitignore", ".travis.yml", "doc.sh", "travis_install.sh", "travis_test.sh", "tests-ios/**"] +description = "Objective-C Runtime bindings and wrapper for Rust." +documentation = "http://ssheldon.github.io/rust-objc/objc/" +readme = "README.md" +keywords = ["objective-c", "osx", "ios", "cocoa", "uikit"] +license = "MIT" +repository = "http://github.com/SSheldon/rust-objc" +[dependencies.malloc_buf] +version = "0.0" + +[dependencies.objc_exception] +version = "0.1" +optional = true + +[features] +exception = ["objc_exception"] +verify_message = [] diff --git a/vendor/objc/LICENSE.txt b/vendor/objc/LICENSE.txt new file mode 100644 index 0000000000000..e9ab3babc0d86 --- /dev/null +++ b/vendor/objc/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Steven Sheldon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/objc/README.md b/vendor/objc/README.md new file mode 100644 index 0000000000000..55fba64840d46 --- /dev/null +++ b/vendor/objc/README.md @@ -0,0 +1,99 @@ +Objective-C Runtime bindings and wrapper for Rust. + +* Documentation: http://ssheldon.github.io/rust-objc/objc/ +* Crate: https://crates.io/crates/objc + +## Messaging objects + +Objective-C objects can be messaged using the `msg_send!` macro: + +``` rust +let cls = class!(NSObject); +let obj: *mut Object = msg_send![cls, new]; +let hash: usize = msg_send![obj, hash]; +let is_kind: BOOL = msg_send![obj, isKindOfClass:cls]; +// Even void methods must have their return type annotated +let _: () = msg_send![obj, release]; +``` + +## Reference counting + +The utilities of the `rc` module provide ARC-like semantics for working with +Objective-C's reference counted objects in Rust. +A `StrongPtr` retains an object and releases the object when dropped. +A `WeakPtr` will not retain the object, but can be upgraded to a `StrongPtr` +and safely fails if the object has been deallocated. + +``` rust +// StrongPtr will release the object when dropped +let obj = unsafe { + StrongPtr::new(msg_send![class!(NSObject), new]) +}; + +// Cloning retains the object an additional time +let cloned = obj.clone(); +autoreleasepool(|| { + // Autorelease consumes the StrongPtr, but won't + // actually release until the end of an autoreleasepool + cloned.autorelease(); +}); + +// Weak references won't retain the object +let weak = obj.weak(); +drop(obj); +assert!(weak.load().is_null()); +``` + +## Declaring classes + +Classes can be declared using the `ClassDecl` struct. Instance variables and +methods can then be added before the class is ultimately registered. + +The following example demonstrates declaring a class named `MyNumber` that has +one ivar, a `u32` named `_number` and a `number` method that returns it: + +``` rust +let superclass = class!(NSObject); +let mut decl = ClassDecl::new("MyNumber", superclass).unwrap(); + +// Add an instance variable +decl.add_ivar::("_number"); + +// Add an ObjC method for getting the number +extern fn my_number_get(this: &Object, _cmd: Sel) -> u32 { + unsafe { *this.get_ivar("_number") } +} +unsafe { + decl.add_method(sel!(number), + my_number_get as extern fn(&Object, Sel) -> u32); +} + +decl.register(); +``` + +## Exceptions + +By default, if the `msg_send!` macro causes an exception to be thrown, this +will unwind into Rust resulting in unsafe, undefined behavior. +However, this crate has an `"exception"` feature which, when enabled, wraps +each `msg_send!` in a `@try`/`@catch` and panics if an exception is caught, +preventing Objective-C from unwinding into Rust. + +## Message type verification + +The Objective-C runtime includes encodings for each method that describe the +argument and return types. This crate can take advantage of these encodings to +verify that the types used in Rust match the types encoded for the method. + +To use this functionality, enable the `"verify_message"` feature. +With this feature enabled, type checking is performed for every message send, +which also requires that all arguments and return values for all messages +implement `Encode`. + +If this requirement is burdensome or you'd rather just verify specific messages, +you can call the `Message::verify_message` method for specific selectors. + +## Support for other Operating Systems + +The bindings can be used on Linux or *BSD utilizing the +[GNUstep Objective-C runtime](https://www.github.com/gnustep/libobjc2). diff --git a/vendor/objc/examples/example.rs b/vendor/objc/examples/example.rs new file mode 100644 index 0000000000000..5346b620fbe43 --- /dev/null +++ b/vendor/objc/examples/example.rs @@ -0,0 +1,45 @@ +#[macro_use] +extern crate objc; + +use objc::Encode; +use objc::rc::StrongPtr; +use objc::runtime::{Class, Object}; + +fn main() { + // Get a class + let cls = class!(NSObject); + println!("NSObject size: {}", cls.instance_size()); + + // Inspect its ivars + println!("NSObject ivars:"); + for ivar in cls.instance_variables().iter() { + println!("{}", ivar.name()); + } + + // Allocate an instance + let obj = unsafe { + let obj: *mut Object = msg_send![cls, alloc]; + let obj: *mut Object = msg_send![obj, init]; + StrongPtr::new(obj) + }; + println!("NSObject address: {:p}", obj); + + // Access an ivar of the object + let isa: *const Class = unsafe { + *(**obj).get_ivar("isa") + }; + println!("NSObject isa: {:?}", isa); + + // Inspect a method of the class + let hash_sel = sel!(hash); + let hash_method = cls.instance_method(hash_sel).unwrap(); + let hash_return = hash_method.return_type(); + println!("-[NSObject hash] return type: {:?}", hash_return); + assert!(hash_return == usize::encode()); + + // Invoke a method on the object + let hash: usize = unsafe { + msg_send![*obj, hash] + }; + println!("NSObject hash: {}", hash); +} diff --git a/vendor/objc/src/declare.rs b/vendor/objc/src/declare.rs new file mode 100644 index 0000000000000..ed09015e1a3a3 --- /dev/null +++ b/vendor/objc/src/declare.rs @@ -0,0 +1,340 @@ +/*! +Functionality for declaring Objective-C classes. + +Classes can be declared using the `ClassDecl` struct. Instance variables and +methods can then be added before the class is ultimately registered. + +# Example + +The following example demonstrates declaring a class named `MyNumber` that has +one ivar, a `u32` named `_number` and a `number` method that returns it: + +``` no_run +# #[macro_use] extern crate objc; +# use objc::declare::ClassDecl; +# use objc::runtime::{Class, Object, Sel}; +# fn main() { +let superclass = class!(NSObject); +let mut decl = ClassDecl::new("MyNumber", superclass).unwrap(); + +// Add an instance variable +decl.add_ivar::("_number"); + +// Add an ObjC method for getting the number +extern fn my_number_get(this: &Object, _cmd: Sel) -> u32 { + unsafe { *this.get_ivar("_number") } +} +unsafe { + decl.add_method(sel!(number), + my_number_get as extern fn(&Object, Sel) -> u32); +} + +decl.register(); +# } +``` +*/ + +use std::ffi::CString; +use std::mem; +use std::ptr; + +use runtime::{BOOL, Class, Imp, NO, Object, Protocol, Sel, self}; +use {Encode, EncodeArguments, Encoding, Message}; + +/// Types that can be used as the implementation of an Objective-C method. +pub trait MethodImplementation { + /// The callee type of the method. + type Callee: Message; + /// The return type of the method. + type Ret: Encode; + /// The argument types of the method. + type Args: EncodeArguments; + + /// Returns self as an `Imp` of a method. + fn imp(self) -> Imp; +} + +macro_rules! method_decl_impl { + (-$s:ident, $r:ident, $f:ty, $($t:ident),*) => ( + impl<$s, $r $(, $t)*> MethodImplementation for $f + where $s: Message, $r: Encode $(, $t: Encode)* { + type Callee = $s; + type Ret = $r; + type Args = ($($t,)*); + + fn imp(self) -> Imp { + unsafe { mem::transmute(self) } + } + } + ); + ($($t:ident),*) => ( + method_decl_impl!(-T, R, extern fn(&T, Sel $(, $t)*) -> R, $($t),*); + method_decl_impl!(-T, R, extern fn(&mut T, Sel $(, $t)*) -> R, $($t),*); + ); +} + +method_decl_impl!(); +method_decl_impl!(A); +method_decl_impl!(A, B); +method_decl_impl!(A, B, C); +method_decl_impl!(A, B, C, D); +method_decl_impl!(A, B, C, D, E); +method_decl_impl!(A, B, C, D, E, F); +method_decl_impl!(A, B, C, D, E, F, G); +method_decl_impl!(A, B, C, D, E, F, G, H); +method_decl_impl!(A, B, C, D, E, F, G, H, I); +method_decl_impl!(A, B, C, D, E, F, G, H, I, J); +method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K); +method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K, L); + +fn count_args(sel: Sel) -> usize { + sel.name().chars().filter(|&c| c == ':').count() +} + +fn method_type_encoding(ret: &Encoding, args: &[Encoding]) -> CString { + let mut types = ret.as_str().to_owned(); + // First two arguments are always self and the selector + types.push_str(<*mut Object>::encode().as_str()); + types.push_str(Sel::encode().as_str()); + types.extend(args.iter().map(|e| e.as_str())); + CString::new(types).unwrap() +} + +fn log2_align_of() -> u8 { + let align = mem::align_of::(); + // Alignments are required to be powers of 2 + debug_assert!(align.count_ones() == 1); + // log2 of a power of 2 is the number of trailing zeros + align.trailing_zeros() as u8 +} + +/// A type for declaring a new class and adding new methods and ivars to it +/// before registering it. +pub struct ClassDecl { + cls: *mut Class, +} + +impl ClassDecl { + fn with_superclass(name: &str, superclass: Option<&Class>) + -> Option { + let name = CString::new(name).unwrap(); + let super_ptr = superclass.map_or(ptr::null(), |c| c); + let cls = unsafe { + runtime::objc_allocateClassPair(super_ptr, name.as_ptr(), 0) + }; + if cls.is_null() { + None + } else { + Some(ClassDecl { cls: cls }) + } + } + + /// Constructs a `ClassDecl` with the given name and superclass. + /// Returns `None` if the class couldn't be allocated. + pub fn new(name: &str, superclass: &Class) -> Option { + ClassDecl::with_superclass(name, Some(superclass)) + } + + /** + Constructs a `ClassDecl` declaring a new root class with the given name. + Returns `None` if the class couldn't be allocated. + + An implementation for `+initialize` must also be given; the runtime calls + this method for all classes, so it must be defined on root classes. + + Note that implementing a root class is not a simple endeavor. + For example, your class probably cannot be passed to Cocoa code unless + the entire `NSObject` protocol is implemented. + Functionality it expects, like implementations of `-retain` and `-release` + used by ARC, will not be present otherwise. + */ + pub fn root(name: &str, intitialize_fn: extern fn(&Class, Sel)) + -> Option { + let mut decl = ClassDecl::with_superclass(name, None); + if let Some(ref mut decl) = decl { + unsafe { + decl.add_class_method(sel!(initialize), intitialize_fn); + } + } + decl + } + + /// Adds a method with the given name and implementation to self. + /// Panics if the method wasn't sucessfully added + /// or if the selector and function take different numbers of arguments. + /// Unsafe because the caller must ensure that the types match those that + /// are expected when the method is invoked from Objective-C. + pub unsafe fn add_method(&mut self, sel: Sel, func: F) + where F: MethodImplementation { + let encs = F::Args::encodings(); + let encs = encs.as_ref(); + let sel_args = count_args(sel); + assert!(sel_args == encs.len(), + "Selector accepts {} arguments, but function accepts {}", + sel_args, encs.len(), + ); + + let types = method_type_encoding(&F::Ret::encode(), encs); + let success = runtime::class_addMethod(self.cls, sel, func.imp(), + types.as_ptr()); + assert!(success != NO, "Failed to add method {:?}", sel); + } + + /// Adds a class method with the given name and implementation to self. + /// Panics if the method wasn't sucessfully added + /// or if the selector and function take different numbers of arguments. + /// Unsafe because the caller must ensure that the types match those that + /// are expected when the method is invoked from Objective-C. + pub unsafe fn add_class_method(&mut self, sel: Sel, func: F) + where F: MethodImplementation { + let encs = F::Args::encodings(); + let encs = encs.as_ref(); + let sel_args = count_args(sel); + assert!(sel_args == encs.len(), + "Selector accepts {} arguments, but function accepts {}", + sel_args, encs.len(), + ); + + let types = method_type_encoding(&F::Ret::encode(), encs); + let metaclass = (*self.cls).metaclass() as *const _ as *mut _; + let success = runtime::class_addMethod(metaclass, sel, func.imp(), + types.as_ptr()); + assert!(success != NO, "Failed to add class method {:?}", sel); + } + + /// Adds an ivar with type `T` and the provided name to self. + /// Panics if the ivar wasn't successfully added. + pub fn add_ivar(&mut self, name: &str) where T: Encode { + let c_name = CString::new(name).unwrap(); + let encoding = CString::new(T::encode().as_str()).unwrap(); + let size = mem::size_of::(); + let align = log2_align_of::(); + let success = unsafe { + runtime::class_addIvar(self.cls, c_name.as_ptr(), size, align, + encoding.as_ptr()) + }; + assert!(success != NO, "Failed to add ivar {}", name); + } + + /// Adds a protocol to self. Panics if the protocol wasn't successfully + /// added + pub fn add_protocol(&mut self, proto: &Protocol) { + let success = unsafe { runtime::class_addProtocol(self.cls, proto) }; + assert!(success != NO, "Failed to add protocol {:?}", proto); + } + + /// Registers self, consuming it and returning a reference to the + /// newly registered `Class`. + pub fn register(self) -> &'static Class { + unsafe { + let cls = self.cls; + runtime::objc_registerClassPair(cls); + // Forget self otherwise the class will be disposed in drop + mem::forget(self); + &*cls + } + } +} + +impl Drop for ClassDecl { + fn drop(&mut self) { + unsafe { + runtime::objc_disposeClassPair(self.cls); + } + } +} + +/// A type for declaring a new protocol and adding new methods to it +/// before registering it. +pub struct ProtocolDecl { + proto: *mut Protocol +} + +impl ProtocolDecl { + /// Constructs a `ProtocolDecl` with the given name. Returns `None` if the + /// protocol couldn't be allocated. + pub fn new(name: &str) -> Option { + let c_name = CString::new(name).unwrap(); + let proto = unsafe { + runtime::objc_allocateProtocol(c_name.as_ptr()) + }; + if proto.is_null() { + None + } else { + Some(ProtocolDecl { proto: proto }) + } + } + + fn add_method_description_common(&mut self, sel: Sel, is_required: bool, + is_instance_method: bool) + where Args: EncodeArguments, + Ret: Encode { + let encs = Args::encodings(); + let encs = encs.as_ref(); + let sel_args = count_args(sel); + assert!(sel_args == encs.len(), + "Selector accepts {} arguments, but function accepts {}", + sel_args, encs.len(), + ); + let types = method_type_encoding(&Ret::encode(), encs); + unsafe { + runtime::protocol_addMethodDescription( + self.proto, sel, types.as_ptr(), is_required as BOOL, is_instance_method as BOOL); + } + } + + /// Adds an instance method declaration with a given description to self. + pub fn add_method_description(&mut self, sel: Sel, is_required: bool) + where Args: EncodeArguments, + Ret: Encode { + self.add_method_description_common::(sel, is_required, true) + } + + /// Adds a class method declaration with a given description to self. + pub fn add_class_method_description(&mut self, sel: Sel, is_required: bool) + where Args: EncodeArguments, + Ret: Encode { + self.add_method_description_common::(sel, is_required, false) + } + + /// Adds a requirement on another protocol. + pub fn add_protocol(&mut self, proto: &Protocol) { + unsafe { + runtime::protocol_addProtocol(self.proto, proto); + } + } + + /// Registers self, consuming it and returning a reference to the + /// newly registered `Protocol`. + pub fn register(self) -> &'static Protocol { + unsafe { + runtime::objc_registerProtocol(self.proto); + &*self.proto + } + } +} + +#[cfg(test)] +mod tests { + use test_utils; + + #[test] + fn test_custom_class() { + // Registering the custom class is in test_utils + let obj = test_utils::custom_object(); + unsafe { + let _: () = msg_send![obj, setFoo:13u32]; + let result: u32 = msg_send![obj, foo]; + assert!(result == 13); + } + } + + #[test] + fn test_class_method() { + let cls = test_utils::custom_class(); + unsafe { + let result: u32 = msg_send![cls, classFoo]; + assert!(result == 7); + } + } +} diff --git a/vendor/objc/src/encode.rs b/vendor/objc/src/encode.rs new file mode 100644 index 0000000000000..921479da98d05 --- /dev/null +++ b/vendor/objc/src/encode.rs @@ -0,0 +1,279 @@ +use std::ffi::CStr; +use std::fmt; +use std::os::raw::{c_char, c_void}; +use std::str; +use malloc_buf::MallocBuffer; + +use runtime::{Class, Object, Sel}; + +const QUALIFIERS: &'static [char] = &[ + 'r', // const + 'n', // in + 'N', // inout + 'o', // out + 'O', // bycopy + 'R', // byref + 'V', // oneway +]; + +#[cfg(target_pointer_width = "64")] +const CODE_INLINE_CAP: usize = 30; + +#[cfg(target_pointer_width = "32")] +const CODE_INLINE_CAP: usize = 14; + +enum Code { + Slice(&'static str), + Owned(String), + Inline(u8, [u8; CODE_INLINE_CAP]), + Malloc(MallocBuffer) +} + +/// An Objective-C type encoding. +/// +/// For more information, see Apple's documentation: +/// +pub struct Encoding { + code: Code, +} + +impl Encoding { + /// Constructs an `Encoding` from its string representation. + /// Unsafe because the caller must ensure the string is a valid encoding. + pub unsafe fn from_str(code: &str) -> Encoding { + from_str(code) + } + + /// Returns self as a `str`. + pub fn as_str(&self) -> &str { + match self.code { + Code::Slice(code) => code, + Code::Owned(ref code) => code, + Code::Inline(len, ref bytes) => unsafe { + str::from_utf8_unchecked(&bytes[..len as usize]) + }, + Code::Malloc(ref buf) => unsafe { + str::from_utf8_unchecked(&buf[..buf.len() - 1]) + }, + } + } +} + +impl Clone for Encoding { + fn clone(&self) -> Encoding { + if let Code::Slice(code) = self.code { + from_static_str(code) + } else { + from_str(self.as_str()) + } + } +} + +impl PartialEq for Encoding { + fn eq(&self, other: &Encoding) -> bool { + // strip qualifiers when comparing + let s = self.as_str().trim_left_matches(QUALIFIERS); + let o = other.as_str().trim_left_matches(QUALIFIERS); + s == o + } +} + +impl fmt::Debug for Encoding { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +pub fn from_static_str(code: &'static str) -> Encoding { + Encoding { code: Code::Slice(code) } +} + +pub fn from_str(code: &str) -> Encoding { + if code.len() > CODE_INLINE_CAP { + Encoding { code: Code::Owned(code.to_owned()) } + } else { + let mut bytes = [0; CODE_INLINE_CAP]; + for (dst, byte) in bytes.iter_mut().zip(code.bytes()) { + *dst = byte; + } + Encoding { code: Code::Inline(code.len() as u8, bytes) } + } +} + +pub unsafe fn from_malloc_str(ptr: *mut c_char) -> Encoding { + let s = CStr::from_ptr(ptr); + let bytes = s.to_bytes_with_nul(); + assert!(str::from_utf8(bytes).is_ok()); + let buf = MallocBuffer::new(ptr as *mut u8, bytes.len()).unwrap(); + Encoding { code: Code::Malloc(buf) } +} + +/// Types that have an Objective-C type encoding. +/// +/// Unsafe because Objective-C will make assumptions about the type (like its +/// size and alignment) from its encoding, so the implementer must verify that +/// the encoding is accurate. +pub unsafe trait Encode { + /// Returns the Objective-C type encoding for Self. + fn encode() -> Encoding; +} + +macro_rules! encode_impls { + ($($t:ty : $s:expr,)*) => ($( + unsafe impl Encode for $t { + fn encode() -> Encoding { from_static_str($s) } + } + )*); +} + +encode_impls!( + i8: "c", + i16: "s", + i32: "i", + i64: "q", + u8: "C", + u16: "S", + u32: "I", + u64: "Q", + f32: "f", + f64: "d", + bool: "B", + (): "v", + *mut c_char: "*", + *const c_char: "r*", + *mut c_void: "^v", + *const c_void: "r^v", + Sel: ":", +); + +unsafe impl Encode for isize { + #[cfg(target_pointer_width = "32")] + fn encode() -> Encoding { i32::encode() } + + #[cfg(target_pointer_width = "64")] + fn encode() -> Encoding { i64::encode() } +} + +unsafe impl Encode for usize { + #[cfg(target_pointer_width = "32")] + fn encode() -> Encoding { u32::encode() } + + #[cfg(target_pointer_width = "64")] + fn encode() -> Encoding { u64::encode() } +} + +macro_rules! encode_message_impl { + ($code:expr, $name:ident) => ( + encode_message_impl!($code, $name,); + ); + ($code:expr, $name:ident, $($t:ident),*) => ( + unsafe impl<'a $(, $t)*> $crate::Encode for &'a $name<$($t),*> { + fn encode() -> Encoding { from_static_str($code) } + } + + unsafe impl<'a $(, $t)*> $crate::Encode for &'a mut $name<$($t),*> { + fn encode() -> Encoding { from_static_str($code) } + } + + unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a $name<$($t),*>> { + fn encode() -> Encoding { from_static_str($code) } + } + + unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a mut $name<$($t),*>> { + fn encode() -> Encoding { from_static_str($code) } + } + + unsafe impl<$($t),*> $crate::Encode for *const $name<$($t),*> { + fn encode() -> Encoding { from_static_str($code) } + } + + unsafe impl<$($t),*> $crate::Encode for *mut $name<$($t),*> { + fn encode() -> Encoding { from_static_str($code) } + } + ); +} + +encode_message_impl!("@", Object); + +encode_message_impl!("#", Class); + +/// Types that represent a group of arguments, where each has an Objective-C +/// type encoding. +pub trait EncodeArguments { + /// The type as which the encodings for Self will be returned. + type Encs: AsRef<[Encoding]>; + + /// Returns the Objective-C type encodings for Self. + fn encodings() -> Self::Encs; +} + +macro_rules! count_idents { + () => (0); + ($a:ident) => (1); + ($a:ident, $($b:ident),+) => (1 + count_idents!($($b),*)); +} + +macro_rules! encode_args_impl { + ($($t:ident),*) => ( + impl<$($t: Encode),*> EncodeArguments for ($($t,)*) { + type Encs = [Encoding; count_idents!($($t),*)]; + + fn encodings() -> Self::Encs { + [ + $($t::encode()),* + ] + } + } + ); +} + +encode_args_impl!(); +encode_args_impl!(A); +encode_args_impl!(A, B); +encode_args_impl!(A, B, C); +encode_args_impl!(A, B, C, D); +encode_args_impl!(A, B, C, D, E); +encode_args_impl!(A, B, C, D, E, F); +encode_args_impl!(A, B, C, D, E, F, G); +encode_args_impl!(A, B, C, D, E, F, G, H); +encode_args_impl!(A, B, C, D, E, F, G, H, I); +encode_args_impl!(A, B, C, D, E, F, G, H, I, J); +encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K); +encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L); + +#[cfg(test)] +mod tests { + use runtime::{Class, Object, Sel}; + use super::{Encode, Encoding}; + + #[test] + fn test_encode() { + assert!(u32::encode().as_str() == "I"); + assert!(<()>::encode().as_str() == "v"); + assert!(<&Object>::encode().as_str() == "@"); + assert!(<*mut Object>::encode().as_str() == "@"); + assert!(<&Class>::encode().as_str() == "#"); + assert!(Sel::encode().as_str() == ":"); + } + + #[test] + fn test_inline_encoding() { + let enc = unsafe { Encoding::from_str("C") }; + assert!(enc.as_str() == "C"); + + let enc2 = enc.clone(); + assert!(enc2 == enc); + assert!(enc2.as_str() == "C"); + } + + #[test] + fn test_owned_encoding() { + let s = "{Test=CCCCCCCCCCCCCCCCCCCCCCCCC}"; + let enc = unsafe { Encoding::from_str(s) }; + assert!(enc.as_str() == s); + + let enc2 = enc.clone(); + assert!(enc2 == enc); + assert!(enc2.as_str() == s); + } +} diff --git a/vendor/objc/src/exception.rs b/vendor/objc/src/exception.rs new file mode 100644 index 0000000000000..6fcfa7e87ad32 --- /dev/null +++ b/vendor/objc/src/exception.rs @@ -0,0 +1,11 @@ +use objc_exception; + +use rc::StrongPtr; +use runtime::Object; + +pub unsafe fn try(closure: F) -> Result + where F: FnOnce() -> R { + objc_exception::try(closure).map_err(|exception| { + StrongPtr::new(exception as *mut Object) + }) +} diff --git a/vendor/objc/src/lib.rs b/vendor/objc/src/lib.rs new file mode 100644 index 0000000000000..cdd30f5fd59a7 --- /dev/null +++ b/vendor/objc/src/lib.rs @@ -0,0 +1,90 @@ +/*! +Objective-C Runtime bindings and wrapper for Rust. + +# Messaging objects + +Objective-C objects can be messaged using the [`msg_send!`](macro.msg_send!.html) macro: + +``` no_run +# #[macro_use] extern crate objc; +# use objc::runtime::{BOOL, Class, Object}; +# fn main() { +# unsafe { +let cls = class!(NSObject); +let obj: *mut Object = msg_send![cls, new]; +let hash: usize = msg_send![obj, hash]; +let is_kind: BOOL = msg_send![obj, isKindOfClass:cls]; +// Even void methods must have their return type annotated +let _: () = msg_send![obj, release]; +# } +# } +``` + +# Reference counting + +Utilities for reference counting Objective-C objects are provided in the +[`rc`](rc/index.html) module. + +# Declaring classes + +Objective-C classes can even be declared from Rust using the functionality of +the [`declare`](declare/index.html) module. + +# Exceptions + +By default, if the `msg_send!` macro causes an exception to be thrown, this +will unwind into Rust resulting in unsafe, undefined behavior. +However, this crate has an `"exception"` feature which, when enabled, wraps +each `msg_send!` in a `@try`/`@catch` and panics if an exception is caught, +preventing Objective-C from unwinding into Rust. + +# Message type verification + +The Objective-C runtime includes encodings for each method that describe the +argument and return types. This crate can take advantage of these encodings to +verify that the types used in Rust match the types encoded for the method. + +To use this functionality, enable the `"verify_message"` feature. +With this feature enabled, type checking is performed for every message send, +which also requires that all arguments and return values for all messages +implement `Encode`. + +If this requirement is burdensome or you'd rather +just verify specific messages, you can call the +[`Message::verify_message`](trait.Message.html#method.verify_message) method +for specific selectors. + +# Support for other Operating Systems + +The bindings can be used on Linux or *BSD utilizing the +[GNUstep Objective-C runtime](https://www.github.com/gnustep/libobjc2). +*/ + +#![crate_name = "objc"] +#![crate_type = "lib"] + +#![warn(missing_docs)] + +extern crate malloc_buf; +#[cfg(feature = "exception")] +extern crate objc_exception; + +pub use encode::{Encode, EncodeArguments, Encoding}; +pub use message::{Message, MessageArguments, MessageError}; + +pub use message::send_message as __send_message; +pub use message::send_super_message as __send_super_message; + +#[macro_use] +mod macros; + +pub mod runtime; +pub mod declare; +pub mod rc; +mod encode; +#[cfg(feature = "exception")] +mod exception; +mod message; + +#[cfg(test)] +mod test_utils; diff --git a/vendor/objc/src/macros.rs b/vendor/objc/src/macros.rs new file mode 100644 index 0000000000000..c791f20ff942b --- /dev/null +++ b/vendor/objc/src/macros.rs @@ -0,0 +1,148 @@ +/** +Gets a reference to a `Class`. + +Panics if no class with the given name can be found. +To check for a class that may not exist, use `Class::get`. + +# Example +``` no_run +# #[macro_use] extern crate objc; +# fn main() { +let cls = class!(NSObject); +# } +``` +*/ +#[macro_export] +macro_rules! class { + ($name:ident) => ({ + #[allow(deprecated)] + #[inline(always)] + fn get_class(name: &str) -> Option<&'static $crate::runtime::Class> { + unsafe { + #[cfg_attr(feature = "cargo-clippy", allow(replace_consts))] + static CLASS: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::ATOMIC_USIZE_INIT; + // `Relaxed` should be fine since `objc_getClass` is thread-safe. + let ptr = CLASS.load(::std::sync::atomic::Ordering::Relaxed) as *const $crate::runtime::Class; + if ptr.is_null() { + let cls = $crate::runtime::objc_getClass(name.as_ptr() as *const _); + CLASS.store(cls as usize, ::std::sync::atomic::Ordering::Relaxed); + if cls.is_null() { None } else { Some(&*cls) } + } else { + Some(&*ptr) + } + } + } + match get_class(concat!(stringify!($name), '\0')) { + Some(cls) => cls, + None => panic!("Class with name {} could not be found", stringify!($name)), + } + }) +} + +#[doc(hidden)] +#[macro_export] +macro_rules! sel_impl { + // Declare a function to hide unsafety, otherwise we can trigger the + // unused_unsafe lint; see rust-lang/rust#8472 + ($name:expr) => ({ + #[allow(deprecated)] + #[inline(always)] + fn register_sel(name: &str) -> $crate::runtime::Sel { + unsafe { + #[cfg_attr(feature = "cargo-clippy", allow(replace_consts))] + static SEL: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::ATOMIC_USIZE_INIT; + let ptr = SEL.load(::std::sync::atomic::Ordering::Relaxed) as *const ::std::os::raw::c_void; + // It should be fine to use `Relaxed` ordering here because `sel_registerName` is + // thread-safe. + if ptr.is_null() { + let sel = $crate::runtime::sel_registerName(name.as_ptr() as *const _); + SEL.store(sel.as_ptr() as usize, ::std::sync::atomic::Ordering::Relaxed); + sel + } else { + $crate::runtime::Sel::from_ptr(ptr) + } + } + } + register_sel($name) + }) +} + +/** +Registers a selector, returning a `Sel`. + +# Example +``` +# #[macro_use] extern crate objc; +# fn main() { +let sel = sel!(description); +let sel = sel!(setObject:forKey:); +# } +``` +*/ +#[macro_export] +macro_rules! sel { + ($name:ident) => ({sel_impl!(concat!(stringify!($name), '\0'))}); + ($($name:ident :)+) => ({sel_impl!(concat!($(stringify!($name), ':'),+, '\0'))}); +} + +/** +Sends a message to an object. + +The first argument can be any type that dereferences to a type that implements +`Message`, like a reference, pointer, or an `Id`. +The syntax is similar to the message syntax in Objective-C. +Variadic arguments are not currently supported. + +# Example +``` no_run +# #[macro_use] extern crate objc; +# use objc::runtime::Object; +# fn main() { +# unsafe { +let obj: *mut Object; +# let obj: *mut Object = 0 as *mut Object; +let description: *const Object = msg_send![obj, description]; +let _: () = msg_send![obj, setArg1:1 arg2:2]; +# } +# } +``` +*/ +#[macro_export] +macro_rules! msg_send { + (super($obj:expr, $superclass:expr), $name:ident) => ({ + let sel = sel!($name); + let result; + match $crate::__send_super_message(&*$obj, $superclass, sel, ()) { + Err(s) => panic!("{}", s), + Ok(r) => result = r, + } + result + }); + (super($obj:expr, $superclass:expr), $($name:ident : $arg:expr)+) => ({ + let sel = sel!($($name:)+); + let result; + match $crate::__send_super_message(&*$obj, $superclass, sel, ($($arg,)*)) { + Err(s) => panic!("{}", s), + Ok(r) => result = r, + } + result + }); + ($obj:expr, $name:ident) => ({ + let sel = sel!($name); + let result; + match $crate::__send_message(&*$obj, sel, ()) { + Err(s) => panic!("{}", s), + Ok(r) => result = r, + } + result + }); + ($obj:expr, $($name:ident : $arg:expr)+) => ({ + let sel = sel!($($name:)+); + let result; + match $crate::__send_message(&*$obj, sel, ($($arg,)*)) { + Err(s) => panic!("{}", s), + Ok(r) => result = r, + } + result + }); +} diff --git a/vendor/objc/src/message/apple/arm.rs b/vendor/objc/src/message/apple/arm.rs new file mode 100644 index 0000000000000..d26defc0de766 --- /dev/null +++ b/vendor/objc/src/message/apple/arm.rs @@ -0,0 +1,40 @@ +use std::any::{Any, TypeId}; +use std::mem; + +use runtime::Imp; + +extern { + fn objc_msgSend(); + fn objc_msgSend_stret(); + + fn objc_msgSendSuper(); + fn objc_msgSendSuper_stret(); +} + +pub fn msg_send_fn() -> Imp { + // Double-word sized fundamental data types don't use stret, + // but any composite type larger than 4 bytes does. + // + + let type_id = TypeId::of::(); + if mem::size_of::() <= 4 || + type_id == TypeId::of::() || + type_id == TypeId::of::() || + type_id == TypeId::of::() { + objc_msgSend + } else { + objc_msgSend_stret + } +} + +pub fn msg_send_super_fn() -> Imp { + let type_id = TypeId::of::(); + if mem::size_of::() <= 4 || + type_id == TypeId::of::() || + type_id == TypeId::of::() || + type_id == TypeId::of::() { + objc_msgSendSuper + } else { + objc_msgSendSuper_stret + } +} diff --git a/vendor/objc/src/message/apple/arm64.rs b/vendor/objc/src/message/apple/arm64.rs new file mode 100644 index 0000000000000..54cfc897c5527 --- /dev/null +++ b/vendor/objc/src/message/apple/arm64.rs @@ -0,0 +1,18 @@ +use runtime::Imp; + +extern { + fn objc_msgSend(); + + fn objc_msgSendSuper(); +} + +pub fn msg_send_fn() -> Imp { + // stret is not even available in arm64. + // + + objc_msgSend +} + +pub fn msg_send_super_fn() -> Imp { + objc_msgSendSuper +} diff --git a/vendor/objc/src/message/apple/mod.rs b/vendor/objc/src/message/apple/mod.rs new file mode 100644 index 0000000000000..30f59ca8701d1 --- /dev/null +++ b/vendor/objc/src/message/apple/mod.rs @@ -0,0 +1,40 @@ +use std::any::Any; + +use runtime::{Class, Object, Sel}; +use super::{Message, MessageArguments, MessageError, Super}; + +#[cfg(target_arch = "x86")] +#[path = "x86.rs"] +mod arch; +#[cfg(target_arch = "x86_64")] +#[path = "x86_64.rs"] +mod arch; +#[cfg(target_arch = "arm")] +#[path = "arm.rs"] +mod arch; +#[cfg(target_arch = "aarch64")] +#[path = "arm64.rs"] +mod arch; + +use self::arch::{msg_send_fn, msg_send_super_fn}; + +pub unsafe fn send_unverified(obj: *const T, sel: Sel, args: A) + -> Result + where T: Message, A: MessageArguments, R: Any { + let receiver = obj as *mut T as *mut Object; + let msg_send_fn = msg_send_fn::(); + objc_try!({ + A::invoke(msg_send_fn, receiver, sel, args) + }) +} + +pub unsafe fn send_super_unverified(obj: *const T, superclass: &Class, + sel: Sel, args: A) -> Result + where T: Message, A: MessageArguments, R: Any { + let sup = Super { receiver: obj as *mut T as *mut Object, superclass: superclass }; + let receiver = &sup as *const Super as *mut Object; + let msg_send_fn = msg_send_super_fn::(); + objc_try!({ + A::invoke(msg_send_fn, receiver, sel, args) + }) +} diff --git a/vendor/objc/src/message/apple/x86.rs b/vendor/objc/src/message/apple/x86.rs new file mode 100644 index 0000000000000..93422de24bd1f --- /dev/null +++ b/vendor/objc/src/message/apple/x86.rs @@ -0,0 +1,40 @@ +use std::any::{Any, TypeId}; +use std::mem; + +use runtime::Imp; + +extern { + fn objc_msgSend(); + fn objc_msgSend_fpret(); + fn objc_msgSend_stret(); + + fn objc_msgSendSuper(); + fn objc_msgSendSuper_stret(); +} + +pub fn msg_send_fn() -> Imp { + // Structures 1 or 2 bytes in size are placed in EAX. + // Structures 4 or 8 bytes in size are placed in: EAX and EDX. + // Structures of other sizes are placed at the address supplied by the caller. + // + + let type_id = TypeId::of::(); + let size = mem::size_of::(); + if type_id == TypeId::of::() || + type_id == TypeId::of::() { + objc_msgSend_fpret + } else if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 { + objc_msgSend + } else { + objc_msgSend_stret + } +} + +pub fn msg_send_super_fn() -> Imp { + let size = mem::size_of::(); + if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 { + objc_msgSendSuper + } else { + objc_msgSendSuper_stret + } +} diff --git a/vendor/objc/src/message/apple/x86_64.rs b/vendor/objc/src/message/apple/x86_64.rs new file mode 100644 index 0000000000000..49c90ce53ec6c --- /dev/null +++ b/vendor/objc/src/message/apple/x86_64.rs @@ -0,0 +1,32 @@ +use std::mem; + +use runtime::Imp; + +extern { + fn objc_msgSend(); + fn objc_msgSend_stret(); + + fn objc_msgSendSuper(); + fn objc_msgSendSuper_stret(); +} + +pub fn msg_send_fn() -> Imp { + // If the size of an object is larger than two eightbytes, it has class MEMORY. + // If the type has class MEMORY, then the caller provides space for the return + // value and passes the address of this storage. + // + + if mem::size_of::() <= 16 { + objc_msgSend + } else { + objc_msgSend_stret + } +} + +pub fn msg_send_super_fn() -> Imp { + if mem::size_of::() <= 16 { + objc_msgSendSuper + } else { + objc_msgSendSuper_stret + } +} diff --git a/vendor/objc/src/message/gnustep.rs b/vendor/objc/src/message/gnustep.rs new file mode 100644 index 0000000000000..2e28689cef277 --- /dev/null +++ b/vendor/objc/src/message/gnustep.rs @@ -0,0 +1,35 @@ +use std::any::Any; +use std::mem; + +use runtime::{Class, Object, Imp, Sel}; +use super::{Message, MessageArguments, MessageError, Super}; + +extern { + fn objc_msg_lookup(receiver: *mut Object, op: Sel) -> Imp; + fn objc_msg_lookup_super(sup: *const Super, sel: Sel) -> Imp; +} + +pub unsafe fn send_unverified(obj: *const T, sel: Sel, args: A) + -> Result + where T: Message, A: MessageArguments, R: Any { + if obj.is_null() { + return mem::zeroed(); + } + + let receiver = obj as *mut T as *mut Object; + let msg_send_fn = objc_msg_lookup(receiver, sel); + objc_try!({ + A::invoke(msg_send_fn, receiver, sel, args) + }) +} + +pub unsafe fn send_super_unverified(obj: *const T, superclass: &Class, + sel: Sel, args: A) -> Result + where T: Message, A: MessageArguments, R: Any { + let receiver = obj as *mut T as *mut Object; + let sup = Super { receiver: receiver, superclass: superclass }; + let msg_send_fn = objc_msg_lookup_super(&sup, sel); + objc_try!({ + A::invoke(msg_send_fn, receiver, sel, args) + }) +} diff --git a/vendor/objc/src/message/mod.rs b/vendor/objc/src/message/mod.rs new file mode 100644 index 0000000000000..cb11e993a8cb8 --- /dev/null +++ b/vendor/objc/src/message/mod.rs @@ -0,0 +1,296 @@ +use std::any::Any; +use std::error::Error; +use std::fmt; +use std::mem; + +use runtime::{Class, Imp, Object, Sel}; +use {Encode, EncodeArguments}; + +#[cfg(feature = "exception")] +macro_rules! objc_try { + ($b:block) => ( + $crate::exception::try(|| $b).map_err(|exception| + if exception.is_null() { + MessageError("Uncaught exception nil".to_owned()) + } else { + MessageError(format!("Uncaught exception {:?}", &**exception)) + } + ) + ) +} + +#[cfg(not(feature = "exception"))] +macro_rules! objc_try { + ($b:block) => (Ok($b)) +} + +mod verify; + +#[cfg(any(target_os = "macos", target_os = "ios"))] +#[path = "apple/mod.rs"] +mod platform; +#[cfg(not(any(target_os = "macos", target_os = "ios")))] +#[path = "gnustep.rs"] +mod platform; + +use self::platform::{send_unverified, send_super_unverified}; +use self::verify::verify_message_signature; + +/// Specifies the superclass of an instance. +#[repr(C)] +pub struct Super { + /// Specifies an instance of a class. + pub receiver: *mut Object, + /// Specifies the particular superclass of the instance to message. + pub superclass: *const Class, +} + +/// Types that may be sent Objective-C messages. +/// For example: objects, classes, and blocks. +pub unsafe trait Message { + /** + Sends a message to self with the given selector and arguments. + + The correct version of `objc_msgSend` will be chosen based on the + return type. For more information, see Apple's documentation: + + + If the selector is known at compile-time, it is recommended to use the + `msg_send!` macro rather than this method. + */ + #[cfg(not(feature = "verify_message"))] + unsafe fn send_message(&self, sel: Sel, args: A) + -> Result + where Self: Sized, A: MessageArguments, R: Any { + send_message(self, sel, args) + } + + #[cfg(feature = "verify_message")] + unsafe fn send_message(&self, sel: Sel, args: A) + -> Result + where Self: Sized, A: MessageArguments + EncodeArguments, + R: Any + Encode { + send_message(self, sel, args) + } + + /** + Verifies that the argument and return types match the encoding of the + method for the given selector. + + This will look up the encoding of the method for the given selector, `sel`, + and return a `MessageError` if any encodings differ for the arguments `A` + and return type `R`. + + # Example + ``` no_run + # #[macro_use] extern crate objc; + # use objc::runtime::{BOOL, Class, Object}; + # use objc::Message; + # fn main() { + let obj: &Object; + # obj = unsafe { msg_send![class!(NSObject), new] }; + let sel = sel!(isKindOfClass:); + // Verify isKindOfClass: takes one Class and returns a BOOL + let result = obj.verify_message::<(&Class,), BOOL>(sel); + assert!(result.is_ok()); + # } + ``` + */ + fn verify_message(&self, sel: Sel) -> Result<(), MessageError> + where Self: Sized, A: EncodeArguments, R: Encode { + let obj = unsafe { &*(self as *const _ as *const Object) }; + verify_message_signature::(obj.class(), sel) + } +} + +unsafe impl Message for Object { } + +unsafe impl Message for Class { } + +/// Types that may be used as the arguments of an Objective-C message. +pub trait MessageArguments: Sized { + /// Invoke an `Imp` with the given object, selector, and arguments. + /// + /// This method is the primitive used when sending messages and should not + /// be called directly; instead, use the `msg_send!` macro or, in cases + /// with a dynamic selector, the `Message::send_message` method. + unsafe fn invoke(imp: Imp, obj: *mut Object, sel: Sel, args: Self) -> R + where R: Any; +} + +macro_rules! message_args_impl { + ($($a:ident : $t:ident),*) => ( + impl<$($t),*> MessageArguments for ($($t,)*) { + unsafe fn invoke(imp: Imp, obj: *mut Object, sel: Sel, ($($a,)*): Self) -> R + where R: Any { + let imp: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R = + mem::transmute(imp); + imp(obj, sel $(, $a)*) + } + } + ); +} + +message_args_impl!(); +message_args_impl!(a: A); +message_args_impl!(a: A, b: B); +message_args_impl!(a: A, b: B, c: C); +message_args_impl!(a: A, b: B, c: C, d: D); +message_args_impl!(a: A, b: B, c: C, d: D, e: E); +message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F); +message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G); +message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H); +message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I); +message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J); +message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K); +message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L); + +/** +An error encountered while attempting to send a message. + +Currently, an error may be returned in two cases: + +* an Objective-C exception is thrown and the `exception` feature is enabled +* the encodings of the arguments do not match the encoding of the method + and the `verify_message` feature is enabled +*/ +#[derive(Debug)] +pub struct MessageError(String); + +impl fmt::Display for MessageError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +impl Error for MessageError { + fn description(&self) -> &str { + &self.0 + } +} + +#[doc(hidden)] +#[inline(always)] +#[cfg(not(feature = "verify_message"))] +pub unsafe fn send_message(obj: *const T, sel: Sel, args: A) + -> Result + where T: Message, A: MessageArguments, R: Any { + send_unverified(obj, sel, args) +} + +#[doc(hidden)] +#[inline(always)] +#[cfg(feature = "verify_message")] +pub unsafe fn send_message(obj: *const T, sel: Sel, args: A) + -> Result + where T: Message, A: MessageArguments + EncodeArguments, + R: Any + Encode { + let cls = if obj.is_null() { + return Err(MessageError(format!("Messaging {:?} to nil", sel))); + } else { + (*(obj as *const Object)).class() + }; + + verify_message_signature::(cls, sel).and_then(|_| { + send_unverified(obj, sel, args) + }) +} + +#[doc(hidden)] +#[inline(always)] +#[cfg(not(feature = "verify_message"))] +pub unsafe fn send_super_message(obj: *const T, superclass: &Class, + sel: Sel, args: A) -> Result + where T: Message, A: MessageArguments, R: Any { + send_super_unverified(obj, superclass, sel, args) +} + +#[doc(hidden)] +#[inline(always)] +#[cfg(feature = "verify_message")] +pub unsafe fn send_super_message(obj: *const T, superclass: &Class, + sel: Sel, args: A) -> Result + where T: Message, A: MessageArguments + EncodeArguments, + R: Any + Encode { + if obj.is_null() { + return Err(MessageError(format!("Messaging {:?} to nil", sel))); + } + + verify_message_signature::(superclass, sel).and_then(|_| { + send_super_unverified(obj, superclass, sel, args) + }) +} + +#[cfg(test)] +mod tests { + use test_utils; + use runtime::Object; + use super::Message; + + #[test] + fn test_send_message() { + let obj = test_utils::custom_object(); + let result: u32 = unsafe { + let _: () = msg_send![obj, setFoo:4u32]; + msg_send![obj, foo] + }; + assert!(result == 4); + } + + #[test] + fn test_send_message_stret() { + let obj = test_utils::custom_object(); + let result: test_utils::CustomStruct = unsafe { + msg_send![obj, customStruct] + }; + let expected = test_utils::CustomStruct { a: 1, b:2, c: 3, d: 4 }; + assert!(result == expected); + } + + #[cfg(not(feature = "verify_message"))] + #[test] + fn test_send_message_nil() { + let nil: *mut Object = ::std::ptr::null_mut(); + let result: usize = unsafe { + msg_send![nil, hash] + }; + assert!(result == 0); + + let result: *mut Object = unsafe { + msg_send![nil, description] + }; + assert!(result.is_null()); + + let result: f64 = unsafe { + msg_send![nil, doubleValue] + }; + assert!(result == 0.0); + } + + #[test] + fn test_send_message_super() { + let obj = test_utils::custom_subclass_object(); + let superclass = test_utils::custom_class(); + unsafe { + let _: () = msg_send![obj, setFoo:4u32]; + let foo: u32 = msg_send![super(obj, superclass), foo]; + assert!(foo == 4); + + // The subclass is overriden to return foo + 2 + let foo: u32 = msg_send![obj, foo]; + assert!(foo == 6); + } + } + + #[test] + fn test_verify_message() { + let obj = test_utils::custom_object(); + assert!(obj.verify_message::<(), u32>(sel!(foo)).is_ok()); + assert!(obj.verify_message::<(u32,), ()>(sel!(setFoo:)).is_ok()); + + // Incorrect types + assert!(obj.verify_message::<(), u64>(sel!(setFoo:)).is_err()); + // Unimplemented selector + assert!(obj.verify_message::<(u32,), ()>(sel!(setFoo)).is_err()); + } +} diff --git a/vendor/objc/src/message/verify.rs b/vendor/objc/src/message/verify.rs new file mode 100644 index 0000000000000..61bd4ebb3942b --- /dev/null +++ b/vendor/objc/src/message/verify.rs @@ -0,0 +1,49 @@ +use runtime::{Class, Object, Sel}; +use {Encode, EncodeArguments}; +use super::MessageError; + +pub fn verify_message_signature(cls: &Class, sel: Sel) + -> Result<(), MessageError> + where A: EncodeArguments, R: Encode { + let method = match cls.instance_method(sel) { + Some(method) => method, + None => return Err(MessageError( + format!("Method {:?} not found on class {:?}", + sel, cls) + )), + }; + + let ret = R::encode(); + let expected_ret = method.return_type(); + if ret != expected_ret { + return Err(MessageError( + format!("Return type code {:?} does not match expected {:?} for method {:?}", + ret, expected_ret, method.name()) + )); + } + + let self_and_cmd = [<*mut Object>::encode(), Sel::encode()]; + let args = A::encodings(); + let args = args.as_ref(); + + let count = self_and_cmd.len() + args.len(); + let expected_count = method.arguments_count(); + if count != expected_count { + return Err(MessageError( + format!("Method {:?} accepts {} arguments, but {} were given", + method.name(), expected_count, count) + )); + } + + for (i, arg) in self_and_cmd.iter().chain(args).enumerate() { + let expected = method.argument_type(i).unwrap(); + if *arg != expected { + return Err(MessageError( + format!("Method {:?} expected argument at index {} with type code {:?} but was given {:?}", + method.name(), i, expected, arg) + )); + } + } + + Ok(()) +} diff --git a/vendor/objc/src/rc/autorelease.rs b/vendor/objc/src/rc/autorelease.rs new file mode 100644 index 0000000000000..ad7a5e2847277 --- /dev/null +++ b/vendor/objc/src/rc/autorelease.rs @@ -0,0 +1,30 @@ +use std::os::raw::c_void; +use runtime::{objc_autoreleasePoolPush, objc_autoreleasePoolPop}; + +// we use a struct to ensure that objc_autoreleasePoolPop during unwinding. +struct AutoReleaseHelper { + context: *mut c_void, +} + +impl AutoReleaseHelper { + unsafe fn new() -> Self { + AutoReleaseHelper { context: objc_autoreleasePoolPush() } + } +} + +impl Drop for AutoReleaseHelper { + fn drop(&mut self) { + unsafe { objc_autoreleasePoolPop(self.context) } + } +} + +/** +Execute `f` in the context of a new autorelease pool. The pool is drained +after the execution of `f` completes. + +This corresponds to `@autoreleasepool` blocks in Objective-C and Swift. +*/ +pub fn autoreleasepool T>(f: F) -> T { + let _context = unsafe { AutoReleaseHelper::new() }; + f() +} diff --git a/vendor/objc/src/rc/mod.rs b/vendor/objc/src/rc/mod.rs new file mode 100644 index 0000000000000..f6d26f7a1bf8b --- /dev/null +++ b/vendor/objc/src/rc/mod.rs @@ -0,0 +1,123 @@ +/*! +Utilities for reference counting Objective-C objects. + +The utilities of the `rc` module provide ARC-like semantics for working with +Objective-C's reference counted objects in Rust. +A `StrongPtr` retains an object and releases the object when dropped. +A `WeakPtr` will not retain the object, but can be upgraded to a `StrongPtr` +and safely fails if the object has been deallocated. + +These utilities are not intended to provide a fully safe interface, but can be +useful when writing higher-level Rust wrappers for Objective-C code. + +For more information on Objective-C's reference counting, see Apple's documentation: + + +# Example + +``` no_run +# #[macro_use] extern crate objc; +# use objc::rc::{autoreleasepool, StrongPtr}; +# fn main() { +// StrongPtr will release the object when dropped +let obj = unsafe { + StrongPtr::new(msg_send![class!(NSObject), new]) +}; + +// Cloning retains the object an additional time +let cloned = obj.clone(); +autoreleasepool(|| { + // Autorelease consumes the StrongPtr, but won't + // actually release until the end of an autoreleasepool + cloned.autorelease(); +}); + +// Weak references won't retain the object +let weak = obj.weak(); +drop(obj); +assert!(weak.load().is_null()); +# } +``` +*/ + +mod strong; +mod weak; +mod autorelease; + +pub use self::strong::StrongPtr; +pub use self::weak::WeakPtr; +pub use self::autorelease::autoreleasepool; + +// These tests use NSObject, which isn't present for GNUstep +#[cfg(all(test, any(target_os = "macos", target_os = "ios")))] +mod tests { + use runtime::Object; + use super::StrongPtr; + use super::autoreleasepool; + + #[test] + fn test_strong_clone() { + fn retain_count(obj: *mut Object) -> usize { + unsafe { msg_send![obj, retainCount] } + } + + let obj = unsafe { + StrongPtr::new(msg_send![class!(NSObject), new]) + }; + assert!(retain_count(*obj) == 1); + + let cloned = obj.clone(); + assert!(retain_count(*cloned) == 2); + assert!(retain_count(*obj) == 2); + + drop(obj); + assert!(retain_count(*cloned) == 1); + } + + #[test] + fn test_weak() { + let obj = unsafe { + StrongPtr::new(msg_send![class!(NSObject), new]) + }; + let weak = obj.weak(); + + let strong = weak.load(); + assert!(*strong == *obj); + drop(strong); + + drop(obj); + assert!(weak.load().is_null()); + } + + #[test] + fn test_weak_copy() { + let obj = unsafe { + StrongPtr::new(msg_send![class!(NSObject), new]) + }; + let weak = obj.weak(); + + let weak2 = weak.clone(); + let strong = weak2.load(); + assert!(*strong == *obj); + } + + #[test] + fn test_autorelease() { + let obj = unsafe { + StrongPtr::new(msg_send![class!(NSObject), new]) + }; + + fn retain_count(obj: *mut Object) -> usize { + unsafe { msg_send![obj, retainCount] } + } + let cloned = obj.clone(); + + autoreleasepool(|| { + obj.autorelease(); + assert!(retain_count(*cloned) == 2); + }); + + // make sure that the autoreleased value has been released + assert!(retain_count(*cloned) == 1); + } +} diff --git a/vendor/objc/src/rc/strong.rs b/vendor/objc/src/rc/strong.rs new file mode 100644 index 0000000000000..a61881b6ffd1f --- /dev/null +++ b/vendor/objc/src/rc/strong.rs @@ -0,0 +1,73 @@ +use std::fmt; +use std::mem; +use std::ops::Deref; + +use runtime::{Object, self}; +use super::WeakPtr; + +/// A pointer that strongly references an object, ensuring it won't be deallocated. +pub struct StrongPtr(*mut Object); + +impl StrongPtr { + /// Constructs a `StrongPtr` to a newly created object that already has a + /// +1 retain count. This will not retain the object. + /// When dropped, the object will be released. + /// Unsafe because the caller must ensure the given object pointer is valid. + pub unsafe fn new(ptr: *mut Object) -> Self { + StrongPtr(ptr) + } + + /// Retains the given object and constructs a `StrongPtr` to it. + /// When dropped, the object will be released. + /// Unsafe because the caller must ensure the given object pointer is valid. + pub unsafe fn retain(ptr: *mut Object) -> Self { + StrongPtr(runtime::objc_retain(ptr)) + } + + /// Autoreleases self, meaning that the object is not immediately released, + /// but will be when the autorelease pool is drained. A pointer to the + /// object is returned, but its validity is no longer ensured. + pub fn autorelease(self) -> *mut Object { + let ptr = self.0; + mem::forget(self); + unsafe { + runtime::objc_autorelease(ptr); + } + ptr + } + + /// Returns a `WeakPtr` to self. + pub fn weak(&self) -> WeakPtr { + unsafe { WeakPtr::new(self.0) } + } +} + +impl Drop for StrongPtr { + fn drop(&mut self) { + unsafe { + runtime::objc_release(self.0); + } + } +} + +impl Clone for StrongPtr { + fn clone(&self) -> StrongPtr { + unsafe { + StrongPtr::retain(self.0) + } + } +} + +impl Deref for StrongPtr { + type Target = *mut Object; + + fn deref(&self) -> &*mut Object { + &self.0 + } +} + +impl fmt::Pointer for StrongPtr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&self.0, f) + } +} diff --git a/vendor/objc/src/rc/weak.rs b/vendor/objc/src/rc/weak.rs new file mode 100644 index 0000000000000..289bd8dedb794 --- /dev/null +++ b/vendor/objc/src/rc/weak.rs @@ -0,0 +1,50 @@ +use std::cell::UnsafeCell; +use std::ptr; + +use runtime::{Object, self}; +use super::StrongPtr; + +// Our pointer must have the same address even if we are moved, so Box it. +// Although loading the WeakPtr may modify the pointer, it is thread safe, +// so we must use an UnsafeCell to get a *mut without self being mutable. + +/// A pointer that weakly references an object, allowing to safely check +/// whether it has been deallocated. +pub struct WeakPtr(Box>); + +impl WeakPtr { + /// Constructs a `WeakPtr` to the given object. + /// Unsafe because the caller must ensure the given object pointer is valid. + pub unsafe fn new(obj: *mut Object) -> Self { + let ptr = Box::new(UnsafeCell::new(ptr::null_mut())); + runtime::objc_initWeak(ptr.get(), obj); + WeakPtr(ptr) + } + + /// Loads the object self points to, returning a `StrongPtr`. + /// If the object has been deallocated, the returned pointer will be null. + pub fn load(&self) -> StrongPtr { + unsafe { + let ptr = runtime::objc_loadWeakRetained(self.0.get()); + StrongPtr::new(ptr) + } + } +} + +impl Drop for WeakPtr { + fn drop(&mut self) { + unsafe { + runtime::objc_destroyWeak(self.0.get()); + } + } +} + +impl Clone for WeakPtr { + fn clone(&self) -> Self { + let ptr = Box::new(UnsafeCell::new(ptr::null_mut())); + unsafe { + runtime::objc_copyWeak(ptr.get(), self.0.get()); + } + WeakPtr(ptr) + } +} diff --git a/vendor/objc/src/runtime.rs b/vendor/objc/src/runtime.rs new file mode 100644 index 0000000000000..3b533efe6f0d1 --- /dev/null +++ b/vendor/objc/src/runtime.rs @@ -0,0 +1,632 @@ +//! A Rust interface for the functionality of the Objective-C runtime. +//! +//! For more information on foreign functions, see Apple's documentation: +//! + +use std::ffi::{CStr, CString}; +use std::fmt; +use std::os::raw::{c_char, c_int, c_uint, c_void}; +use std::ptr; +use std::str; +use malloc_buf::MallocBuffer; + +use encode; +use {Encode, Encoding}; + +/// The Objective-C `BOOL` type. +/// +/// To convert an Objective-C `BOOL` into a Rust `bool`, compare it with `NO`. +#[cfg(not(target_arch = "aarch64"))] +pub type BOOL = ::std::os::raw::c_schar; +/// The equivalent of true for Objective-C's `BOOL` type. +#[cfg(not(target_arch = "aarch64"))] +pub const YES: BOOL = 1; +/// The equivalent of false for Objective-C's `BOOL` type. +#[cfg(not(target_arch = "aarch64"))] +pub const NO: BOOL = 0; + +#[cfg(target_arch = "aarch64")] +pub type BOOL = bool; +#[cfg(target_arch = "aarch64")] +pub const YES: BOOL = true; +#[cfg(target_arch = "aarch64")] +pub const NO: BOOL = false; + +/// A type that represents a method selector. +#[repr(C)] +pub struct Sel { + ptr: *const c_void, +} + +/// A marker type to be embedded into other types just so that they cannot be +/// constructed externally. +type PrivateMarker = [u8; 0]; + +/// A type that represents an instance variable. +#[repr(C)] +pub struct Ivar { + _priv: PrivateMarker, +} + +/// A type that represents a method in a class definition. +#[repr(C)] +pub struct Method { + _priv: PrivateMarker, +} + +/// A type that represents an Objective-C class. +#[repr(C)] +pub struct Class { + _priv: PrivateMarker, +} + +/// A type that represents an Objective-C protocol. +#[repr(C)] +pub struct Protocol { + _priv: PrivateMarker +} + +/// A type that represents an instance of a class. +#[repr(C)] +pub struct Object { + _priv: PrivateMarker, +} + +/// A pointer to the start of a method implementation. +pub type Imp = unsafe extern fn(); + +#[link(name = "objc", kind = "dylib")] +extern { + pub fn sel_registerName(name: *const c_char) -> Sel; + pub fn sel_getName(sel: Sel) -> *const c_char; + + pub fn class_getName(cls: *const Class) -> *const c_char; + pub fn class_getSuperclass(cls: *const Class) -> *const Class; + pub fn class_getInstanceSize(cls: *const Class) -> usize; + pub fn class_getInstanceMethod(cls: *const Class, sel: Sel) -> *const Method; + pub fn class_getInstanceVariable(cls: *const Class, name: *const c_char) -> *const Ivar; + pub fn class_copyMethodList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Method; + pub fn class_copyIvarList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Ivar; + pub fn class_addMethod(cls: *mut Class, name: Sel, imp: Imp, types: *const c_char) -> BOOL; + pub fn class_addIvar(cls: *mut Class, name: *const c_char, size: usize, alignment: u8, types: *const c_char) -> BOOL; + pub fn class_addProtocol(cls: *mut Class, proto: *const Protocol) -> BOOL; + pub fn class_conformsToProtocol(cls: *const Class, proto: *const Protocol) -> BOOL; + pub fn class_copyProtocolList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Protocol; + + pub fn objc_allocateClassPair(superclass: *const Class, name: *const c_char, extraBytes: usize) -> *mut Class; + pub fn objc_disposeClassPair(cls: *mut Class); + pub fn objc_registerClassPair(cls: *mut Class); + + pub fn class_createInstance(cls: *const Class, extraBytes: usize) -> *mut Object; + pub fn object_dispose(obj: *mut Object) -> *mut Object; + pub fn object_getClass(obj: *const Object) -> *const Class; + + pub fn objc_getClassList(buffer: *mut *const Class, bufferLen: c_int) -> c_int; + pub fn objc_copyClassList(outCount: *mut c_uint) -> *mut *const Class; + pub fn objc_getClass(name: *const c_char) -> *const Class; + pub fn objc_getProtocol(name: *const c_char) -> *const Protocol; + pub fn objc_copyProtocolList(outCount: *mut c_uint) -> *mut *const Protocol; + pub fn objc_allocateProtocol(name: *const c_char) -> *mut Protocol; + pub fn objc_registerProtocol(proto: *mut Protocol); + + pub fn objc_autoreleasePoolPush() -> *mut c_void; + pub fn objc_autoreleasePoolPop(context: *mut c_void); + + pub fn protocol_addMethodDescription(proto: *mut Protocol, name: Sel, types: *const c_char, isRequiredMethod: BOOL, + isInstanceMethod: BOOL); + pub fn protocol_addProtocol(proto: *mut Protocol, addition: *const Protocol); + pub fn protocol_getName(proto: *const Protocol) -> *const c_char; + pub fn protocol_isEqual(proto: *const Protocol, other: *const Protocol) -> BOOL; + pub fn protocol_copyProtocolList(proto: *const Protocol, outCount: *mut c_uint) -> *mut *const Protocol; + pub fn protocol_conformsToProtocol(proto: *const Protocol, other: *const Protocol) -> BOOL; + + pub fn ivar_getName(ivar: *const Ivar) -> *const c_char; + pub fn ivar_getOffset(ivar: *const Ivar) -> isize; + pub fn ivar_getTypeEncoding(ivar: *const Ivar) -> *const c_char; + + pub fn method_getName(method: *const Method) -> Sel; + pub fn method_getImplementation(method: *const Method) -> Imp; + pub fn method_copyReturnType(method: *const Method) -> *mut c_char; + pub fn method_copyArgumentType(method: *const Method, index: c_uint) -> *mut c_char; + pub fn method_getNumberOfArguments(method: *const Method) -> c_uint; + pub fn method_setImplementation(method: *mut Method, imp: Imp) -> Imp; + pub fn method_exchangeImplementations(m1: *mut Method, m2: *mut Method); + + pub fn objc_retain(obj: *mut Object) -> *mut Object; + pub fn objc_release(obj: *mut Object); + pub fn objc_autorelease(obj: *mut Object); + + pub fn objc_loadWeakRetained(location: *mut *mut Object) -> *mut Object; + pub fn objc_initWeak(location: *mut *mut Object, obj: *mut Object) -> *mut Object; + pub fn objc_destroyWeak(location: *mut *mut Object); + pub fn objc_copyWeak(to: *mut *mut Object, from: *mut *mut Object); +} + +impl Sel { + /// Registers a method with the Objective-C runtime system, + /// maps the method name to a selector, and returns the selector value. + pub fn register(name: &str) -> Sel { + let name = CString::new(name).unwrap(); + unsafe { + sel_registerName(name.as_ptr()) + } + } + + /// Returns the name of the method specified by self. + pub fn name(&self) -> &str { + let name = unsafe { + CStr::from_ptr(sel_getName(*self)) + }; + str::from_utf8(name.to_bytes()).unwrap() + } + + /// Wraps a raw pointer to a selector into a `Sel` object. + /// + /// This is almost never what you want; use `Sel::register()` instead. + #[inline] + pub unsafe fn from_ptr(ptr: *const c_void) -> Sel { + Sel { + ptr: ptr, + } + } + + /// Returns a pointer to the raw selector. + #[inline] + pub fn as_ptr(&self) -> *const c_void { + self.ptr + } +} + +impl PartialEq for Sel { + fn eq(&self, other: &Sel) -> bool { + self.ptr == other.ptr + } +} + +impl Eq for Sel { } + +// Sel is safe to share across threads because it is immutable +unsafe impl Sync for Sel { } +unsafe impl Send for Sel { } + +impl Copy for Sel { } + +impl Clone for Sel { + fn clone(&self) -> Sel { *self } +} + +impl fmt::Debug for Sel { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name()) + } +} + +impl Ivar { + /// Returns the name of self. + pub fn name(&self) -> &str { + let name = unsafe { + CStr::from_ptr(ivar_getName(self)) + }; + str::from_utf8(name.to_bytes()).unwrap() + } + + /// Returns the offset of self. + pub fn offset(&self) -> isize { + let offset = unsafe { + ivar_getOffset(self) + }; + offset as isize + } + + /// Returns the `Encoding` of self. + pub fn type_encoding(&self) -> Encoding { + let encoding = unsafe { + CStr::from_ptr(ivar_getTypeEncoding(self)) + }; + let s = str::from_utf8(encoding.to_bytes()).unwrap(); + encode::from_str(s) + } +} + +impl Method { + /// Returns the name of self. + pub fn name(&self) -> Sel { + unsafe { + method_getName(self) + } + } + + /// Returns the `Encoding` of self's return type. + pub fn return_type(&self) -> Encoding { + unsafe { + let encoding = method_copyReturnType(self); + encode::from_malloc_str(encoding) + } + } + + /// Returns the `Encoding` of a single parameter type of self, or + /// `None` if self has no parameter at the given index. + pub fn argument_type(&self, index: usize) -> Option { + unsafe { + let encoding = method_copyArgumentType(self, index as c_uint); + if encoding.is_null() { + None + } else { + Some(encode::from_malloc_str(encoding)) + } + } + } + + /// Returns the number of arguments accepted by self. + pub fn arguments_count(&self) -> usize { + unsafe { + method_getNumberOfArguments(self) as usize + } + } + + /// Returns the implementation of self. + pub fn implementation(&self) -> Imp { + unsafe { + method_getImplementation(self) + } + } +} + +impl Class { + /// Returns the class definition of a specified class, or `None` if the + /// class is not registered with the Objective-C runtime. + pub fn get(name: &str) -> Option<&'static Class> { + let name = CString::new(name).unwrap(); + unsafe { + let cls = objc_getClass(name.as_ptr()); + if cls.is_null() { None } else { Some(&*cls) } + } + } + + /// Obtains the list of registered class definitions. + pub fn classes() -> MallocBuffer<&'static Class> { + unsafe { + let mut count: c_uint = 0; + let classes = objc_copyClassList(&mut count); + MallocBuffer::new(classes as *mut _, count as usize).unwrap() + } + } + + /// Returns the total number of registered classes. + pub fn classes_count() -> usize { + unsafe { + objc_getClassList(ptr::null_mut(), 0) as usize + } + } + + /// Returns the name of self. + pub fn name(&self) -> &str { + let name = unsafe { + CStr::from_ptr(class_getName(self)) + }; + str::from_utf8(name.to_bytes()).unwrap() + } + + /// Returns the superclass of self, or `None` if self is a root class. + pub fn superclass(&self) -> Option<&Class> { + unsafe { + let superclass = class_getSuperclass(self); + if superclass.is_null() { None } else { Some(&*superclass) } + } + } + + /// Returns the metaclass of self. + pub fn metaclass(&self) -> &Class { + unsafe { + let self_ptr: *const Class = self; + &*object_getClass(self_ptr as *const Object) + } + } + + /// Returns the size of instances of self. + pub fn instance_size(&self) -> usize { + unsafe { + class_getInstanceSize(self) as usize + } + } + + /// Returns a specified instance method for self, or `None` if self and + /// its superclasses do not contain an instance method with the + /// specified selector. + pub fn instance_method(&self, sel: Sel) -> Option<&Method> { + unsafe { + let method = class_getInstanceMethod(self, sel); + if method.is_null() { None } else { Some(&*method) } + } + } + + /// Returns the ivar for a specified instance variable of self, or `None` + /// if self has no ivar with the given name. + pub fn instance_variable(&self, name: &str) -> Option<&Ivar> { + let name = CString::new(name).unwrap(); + unsafe { + let ivar = class_getInstanceVariable(self, name.as_ptr()); + if ivar.is_null() { None } else { Some(&*ivar) } + } + } + + /// Describes the instance methods implemented by self. + pub fn instance_methods(&self) -> MallocBuffer<&Method> { + unsafe { + let mut count: c_uint = 0; + let methods = class_copyMethodList(self, &mut count); + MallocBuffer::new(methods as *mut _, count as usize).unwrap() + } + + } + + /// Checks whether this class conforms to the specified protocol. + pub fn conforms_to(&self, proto: &Protocol) -> bool { + unsafe { class_conformsToProtocol(self, proto) == YES } + } + + /// Get a list of the protocols to which this class conforms. + pub fn adopted_protocols(&self) -> MallocBuffer<&Protocol> { + unsafe { + let mut count: c_uint = 0; + let protos = class_copyProtocolList(self, &mut count); + MallocBuffer::new(protos as *mut _, count as usize).unwrap() + } + } + + /// Describes the instance variables declared by self. + pub fn instance_variables(&self) -> MallocBuffer<&Ivar> { + unsafe { + let mut count: c_uint = 0; + let ivars = class_copyIvarList(self, &mut count); + MallocBuffer::new(ivars as *mut _, count as usize).unwrap() + } + } +} + +impl PartialEq for Class { + fn eq(&self, other: &Class) -> bool { + let self_ptr: *const Class = self; + let other_ptr: *const Class = other; + self_ptr == other_ptr + } +} + +impl Eq for Class { } + +impl fmt::Debug for Class { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name()) + } +} + +impl Protocol { + /// Returns the protocol definition of a specified protocol, or `None` if the + /// protocol is not registered with the Objective-C runtime. + pub fn get(name: &str) -> Option<&'static Protocol> { + let name = CString::new(name).unwrap(); + unsafe { + let proto = objc_getProtocol(name.as_ptr()); + if proto.is_null() { None } else { Some(&*proto) } + } + } + + /// Obtains the list of registered protocol definitions. + pub fn protocols() -> MallocBuffer<&'static Protocol> { + unsafe { + let mut count: c_uint = 0; + let protocols = objc_copyProtocolList(&mut count); + MallocBuffer::new(protocols as *mut _, count as usize).unwrap() + } + } + + /// Get a list of the protocols to which this protocol conforms. + pub fn adopted_protocols(&self) -> MallocBuffer<&Protocol> { + unsafe { + let mut count: c_uint = 0; + let protocols = protocol_copyProtocolList(self, &mut count); + MallocBuffer::new(protocols as *mut _, count as usize).unwrap() + } + } + + /// Checks whether this protocol conforms to the specified protocol. + pub fn conforms_to(&self, proto: &Protocol) -> bool { + unsafe { protocol_conformsToProtocol(self, proto) == YES } + } + + /// Returns the name of self. + pub fn name(&self) -> &str { + let name = unsafe { + CStr::from_ptr(protocol_getName(self)) + }; + str::from_utf8(name.to_bytes()).unwrap() + } +} + +impl PartialEq for Protocol { + fn eq(&self, other: &Protocol) -> bool { + unsafe { protocol_isEqual(self, other) == YES } + } +} + +impl Eq for Protocol { } + +impl fmt::Debug for Protocol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name()) + } +} + +impl Object { + /// Returns the class of self. + pub fn class(&self) -> &Class { + unsafe { + &*object_getClass(self) + } + } + + /// Returns a reference to the ivar of self with the given name. + /// Panics if self has no ivar with the given name. + /// Unsafe because the caller must ensure that the ivar is actually + /// of type `T`. + pub unsafe fn get_ivar(&self, name: &str) -> &T where T: Encode { + let offset = { + let cls = self.class(); + match cls.instance_variable(name) { + Some(ivar) => { + assert!(ivar.type_encoding() == T::encode()); + ivar.offset() + } + None => panic!("Ivar {} not found on class {:?}", name, cls), + } + }; + let ptr = { + let self_ptr: *const Object = self; + (self_ptr as *const u8).offset(offset) as *const T + }; + &*ptr + } + + /// Returns a mutable reference to the ivar of self with the given name. + /// Panics if self has no ivar with the given name. + /// Unsafe because the caller must ensure that the ivar is actually + /// of type `T`. + pub unsafe fn get_mut_ivar(&mut self, name: &str) -> &mut T + where T: Encode { + let offset = { + let cls = self.class(); + match cls.instance_variable(name) { + Some(ivar) => { + assert!(ivar.type_encoding() == T::encode()); + ivar.offset() + } + None => panic!("Ivar {} not found on class {:?}", name, cls), + } + }; + let ptr = { + let self_ptr: *mut Object = self; + (self_ptr as *mut u8).offset(offset) as *mut T + }; + &mut *ptr + } + + /// Sets the value of the ivar of self with the given name. + /// Panics if self has no ivar with the given name. + /// Unsafe because the caller must ensure that the ivar is actually + /// of type `T`. + pub unsafe fn set_ivar(&mut self, name: &str, value: T) + where T: Encode { + *self.get_mut_ivar::(name) = value; + } +} + +impl fmt::Debug for Object { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "<{:?}: {:p}>", self.class(), self) + } +} + +#[cfg(test)] +mod tests { + use test_utils; + use Encode; + use super::{Class, Protocol, Sel}; + + #[test] + fn test_ivar() { + let cls = test_utils::custom_class(); + let ivar = cls.instance_variable("_foo").unwrap(); + assert!(ivar.name() == "_foo"); + assert!(ivar.type_encoding() == ::encode()); + assert!(ivar.offset() > 0); + + let ivars = cls.instance_variables(); + assert!(ivars.len() > 0); + } + + #[test] + fn test_method() { + let cls = test_utils::custom_class(); + let sel = Sel::register("foo"); + let method = cls.instance_method(sel).unwrap(); + assert!(method.name().name() == "foo"); + assert!(method.arguments_count() == 2); + assert!(method.return_type() == ::encode()); + assert!(method.argument_type(1).unwrap() == Sel::encode()); + + let methods = cls.instance_methods(); + assert!(methods.len() > 0); + } + + #[test] + fn test_class() { + let cls = test_utils::custom_class(); + assert!(cls.name() == "CustomObject"); + assert!(cls.instance_size() > 0); + assert!(cls.superclass().is_none()); + + assert!(Class::get(cls.name()) == Some(cls)); + + let metaclass = cls.metaclass(); + // The metaclass of a root class is a subclass of the root class + assert!(metaclass.superclass().unwrap() == cls); + + let subclass = test_utils::custom_subclass(); + assert!(subclass.superclass().unwrap() == cls); + } + + #[test] + fn test_classes() { + assert!(Class::classes_count() > 0); + let classes = Class::classes(); + assert!(classes.len() > 0); + } + + #[test] + fn test_protocol() { + let proto = test_utils::custom_protocol(); + assert!(proto.name() == "CustomProtocol"); + let class = test_utils::custom_class(); + assert!(class.conforms_to(proto)); + let class_protocols = class.adopted_protocols(); + assert!(class_protocols.len() > 0); + } + + #[test] + fn test_protocol_method() { + let class = test_utils::custom_class(); + let result: i32 = unsafe { + msg_send![class, addNumber:1 toNumber:2] + }; + assert_eq!(result, 3); + } + + #[test] + fn test_subprotocols() { + let sub_proto = test_utils::custom_subprotocol(); + let super_proto = test_utils::custom_protocol(); + assert!(sub_proto.conforms_to(super_proto)); + let adopted_protocols = sub_proto.adopted_protocols(); + assert_eq!(adopted_protocols[0], super_proto); + } + + #[test] + fn test_protocols() { + // Ensure that a protocol has been registered on linux + let _ = test_utils::custom_protocol(); + + let protocols = Protocol::protocols(); + assert!(protocols.len() > 0); + } + + #[test] + fn test_object() { + let mut obj = test_utils::custom_object(); + assert!(obj.class() == test_utils::custom_class()); + let result: u32 = unsafe { + obj.set_ivar("_foo", 4u32); + *obj.get_ivar("_foo") + }; + assert!(result == 4); + } +} diff --git a/vendor/objc/src/test_utils.rs b/vendor/objc/src/test_utils.rs new file mode 100644 index 0000000000000..873f82f6b192c --- /dev/null +++ b/vendor/objc/src/test_utils.rs @@ -0,0 +1,187 @@ +use std::ops::{Deref, DerefMut}; +use std::os::raw::c_char; +use std::sync::{Once, ONCE_INIT}; + +use declare::{ClassDecl, ProtocolDecl}; +use runtime::{Class, Object, Protocol, Sel, self}; +use {Encode, Encoding}; + +pub struct CustomObject { + obj: *mut Object, +} + +impl CustomObject { + fn new(class: &Class) -> Self { + let obj = unsafe { + runtime::class_createInstance(class, 0) + }; + CustomObject { obj: obj } + } +} + +impl Deref for CustomObject { + type Target = Object; + + fn deref(&self) -> &Object { + unsafe { &*self.obj } + } +} + +impl DerefMut for CustomObject { + fn deref_mut(&mut self) -> &mut Object { + unsafe { &mut *self.obj } + } +} + +impl Drop for CustomObject { + fn drop(&mut self) { + unsafe { + runtime::object_dispose(self.obj); + } + } +} + +#[derive(Eq, PartialEq)] +pub struct CustomStruct { + pub a: u64, + pub b: u64, + pub c: u64, + pub d: u64, +} + +unsafe impl Encode for CustomStruct { + fn encode() -> Encoding { + let mut code = "{CustomStruct=".to_owned(); + for _ in 0..4 { + code.push_str(u64::encode().as_str()); + } + code.push_str("}"); + unsafe { + Encoding::from_str(&code) + } + } +} + +pub fn custom_class() -> &'static Class { + static REGISTER_CUSTOM_CLASS: Once = ONCE_INIT; + + REGISTER_CUSTOM_CLASS.call_once(|| { + // The runtime will call this method, so it has to be implemented + extern fn custom_obj_class_initialize(_this: &Class, _cmd: Sel) { } + + let mut decl = ClassDecl::root("CustomObject", custom_obj_class_initialize).unwrap(); + let proto = custom_protocol(); + + decl.add_protocol(proto); + decl.add_ivar::("_foo"); + + extern fn custom_obj_set_foo(this: &mut Object, _cmd: Sel, foo: u32) { + unsafe { this.set_ivar::("_foo", foo); } + } + + extern fn custom_obj_get_foo(this: &Object, _cmd: Sel) -> u32 { + unsafe { *this.get_ivar::("_foo") } + } + + extern fn custom_obj_get_struct(_this: &Object, _cmd: Sel) -> CustomStruct { + CustomStruct { a: 1, b: 2, c: 3, d: 4 } + } + + extern fn custom_obj_class_method(_this: &Class, _cmd: Sel) -> u32 { + 7 + } + + extern fn custom_obj_set_bar(this: &mut Object, _cmd: Sel, bar: u32) { + unsafe { this.set_ivar::("_foo", bar) ;} + } + + extern fn custom_obj_add_number_to_number(_this: &Class, _cmd: Sel, fst: i32, snd: i32) -> i32 { + fst + snd + } + + unsafe { + let set_foo: extern fn(&mut Object, Sel, u32) = custom_obj_set_foo; + decl.add_method(sel!(setFoo:), set_foo); + let get_foo: extern fn(&Object, Sel) -> u32 = custom_obj_get_foo; + decl.add_method(sel!(foo), get_foo); + let get_struct: extern fn(&Object, Sel) -> CustomStruct = custom_obj_get_struct; + decl.add_method(sel!(customStruct), get_struct); + let class_method: extern fn(&Class, Sel) -> u32 = custom_obj_class_method; + decl.add_class_method(sel!(classFoo), class_method); + + let protocol_instance_method: extern fn(&mut Object, Sel, u32) = custom_obj_set_bar; + decl.add_method(sel!(setBar:), protocol_instance_method); + let protocol_class_method: extern fn(&Class, Sel, i32, i32) -> i32 = custom_obj_add_number_to_number; + decl.add_class_method(sel!(addNumber:toNumber:), protocol_class_method); + } + + decl.register(); + }); + + class!(CustomObject) +} + +pub fn custom_protocol() -> &'static Protocol { + static REGISTER_CUSTOM_PROTOCOL: Once = ONCE_INIT; + + REGISTER_CUSTOM_PROTOCOL.call_once(|| { + let mut decl = ProtocolDecl::new("CustomProtocol").unwrap(); + + decl.add_method_description::<(i32,), ()>(sel!(setBar:), true); + decl.add_method_description::<(), *const c_char>(sel!(getName), false); + decl.add_class_method_description::<(i32, i32), i32>(sel!(addNumber:toNumber:), true); + + decl.register(); + }); + + Protocol::get("CustomProtocol").unwrap() +} + +pub fn custom_subprotocol() -> &'static Protocol { + static REGISTER_CUSTOM_SUBPROTOCOL: Once = ONCE_INIT; + + REGISTER_CUSTOM_SUBPROTOCOL.call_once(|| { + let super_proto = custom_protocol(); + let mut decl = ProtocolDecl::new("CustomSubProtocol").unwrap(); + + decl.add_protocol(super_proto); + decl.add_method_description::<(u32,), u32>(sel!(calculateFoo:), true); + + decl.register(); + }); + + Protocol::get("CustomSubProtocol").unwrap() +} + +pub fn custom_object() -> CustomObject { + CustomObject::new(custom_class()) +} + +pub fn custom_subclass() -> &'static Class { + static REGISTER_CUSTOM_SUBCLASS: Once = ONCE_INIT; + + REGISTER_CUSTOM_SUBCLASS.call_once(|| { + let superclass = custom_class(); + let mut decl = ClassDecl::new("CustomSubclassObject", superclass).unwrap(); + + extern fn custom_subclass_get_foo(this: &Object, _cmd: Sel) -> u32 { + let foo: u32 = unsafe { + msg_send![super(this, custom_class()), foo] + }; + foo + 2 + } + + unsafe { + let get_foo: extern fn(&Object, Sel) -> u32 = custom_subclass_get_foo; + decl.add_method(sel!(foo), get_foo); + } + + decl.register(); + }); + + class!(CustomSubclassObject) +} + +pub fn custom_subclass_object() -> CustomObject { + CustomObject::new(custom_subclass()) +} diff --git a/vendor/object/clippy.toml b/vendor/object/clippy.toml new file mode 100644 index 0000000000000..16caf02ee9191 --- /dev/null +++ b/vendor/object/clippy.toml @@ -0,0 +1 @@ +msrv = "1.60.0" diff --git a/vendor/object/src/write/coff.rs b/vendor/object/src/write/coff.rs new file mode 100644 index 0000000000000..2277a08e29d26 --- /dev/null +++ b/vendor/object/src/write/coff.rs @@ -0,0 +1,725 @@ +use alloc::vec::Vec; +use core::mem; + +use crate::endian::{LittleEndian as LE, U16Bytes, U32Bytes, U16, U32}; +use crate::pe as coff; +use crate::write::string::*; +use crate::write::util::*; +use crate::write::*; + +#[derive(Default, Clone, Copy)] +struct SectionOffsets { + offset: usize, + str_id: Option, + reloc_offset: usize, + selection: u8, + associative_section: u16, +} + +#[derive(Default, Clone, Copy)] +struct SymbolOffsets { + index: usize, + str_id: Option, + aux_count: u8, +} + +/// Internal format to use for the `.drectve` section containing linker +/// directives for symbol exports. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CoffExportStyle { + /// MSVC format supported by link.exe and LLD. + Msvc, + /// Gnu format supported by GNU LD and LLD. + Gnu, +} + +impl<'a> Object<'a> { + pub(crate) fn coff_section_info( + &self, + section: StandardSection, + ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { + match section { + StandardSection::Text => (&[], &b".text"[..], SectionKind::Text, SectionFlags::None), + StandardSection::Data => (&[], &b".data"[..], SectionKind::Data, SectionFlags::None), + StandardSection::ReadOnlyData + | StandardSection::ReadOnlyDataWithRel + | StandardSection::ReadOnlyString => ( + &[], + &b".rdata"[..], + SectionKind::ReadOnlyData, + SectionFlags::None, + ), + StandardSection::UninitializedData => ( + &[], + &b".bss"[..], + SectionKind::UninitializedData, + SectionFlags::None, + ), + // TLS sections are data sections with a special name. + StandardSection::Tls => (&[], &b".tls$"[..], SectionKind::Data, SectionFlags::None), + StandardSection::UninitializedTls => { + // Unsupported section. + (&[], &[], SectionKind::UninitializedTls, SectionFlags::None) + } + StandardSection::TlsVariables => { + // Unsupported section. + (&[], &[], SectionKind::TlsVariables, SectionFlags::None) + } + StandardSection::Common => { + // Unsupported section. + (&[], &[], SectionKind::Common, SectionFlags::None) + } + StandardSection::GnuProperty => { + // Unsupported section. + (&[], &[], SectionKind::Note, SectionFlags::None) + } + } + } + + pub(crate) fn coff_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec { + let mut name = section.to_vec(); + name.push(b'$'); + name.extend_from_slice(value); + name + } + + pub(crate) fn coff_fixup_relocation(&mut self, relocation: &mut Relocation) -> i64 { + if relocation.kind == RelocationKind::GotRelative { + // Use a stub symbol for the relocation instead. + // This isn't really a GOT, but it's a similar purpose. + // TODO: need to handle DLL imports differently? + relocation.kind = RelocationKind::Relative; + relocation.symbol = self.coff_add_stub_symbol(relocation.symbol); + } else if relocation.kind == RelocationKind::PltRelative { + // Windows doesn't need a separate relocation type for + // references to functions in import libraries. + // For convenience, treat this the same as Relative. + relocation.kind = RelocationKind::Relative; + } + + let constant = match self.architecture { + Architecture::I386 | Architecture::Arm | Architecture::Aarch64 => match relocation.kind + { + RelocationKind::Relative => { + // IMAGE_REL_I386_REL32, IMAGE_REL_ARM_REL32, IMAGE_REL_ARM64_REL32 + relocation.addend + 4 + } + _ => relocation.addend, + }, + Architecture::X86_64 => match relocation.kind { + RelocationKind::Relative => { + // IMAGE_REL_AMD64_REL32 through to IMAGE_REL_AMD64_REL32_5 + if relocation.addend <= -4 && relocation.addend >= -9 { + 0 + } else { + relocation.addend + 4 + } + } + _ => relocation.addend, + }, + _ => unimplemented!(), + }; + relocation.addend -= constant; + constant + } + + fn coff_add_stub_symbol(&mut self, symbol_id: SymbolId) -> SymbolId { + if let Some(stub_id) = self.stub_symbols.get(&symbol_id) { + return *stub_id; + } + let stub_size = self.architecture.address_size().unwrap().bytes(); + + let name = b".rdata$.refptr".to_vec(); + let section_id = self.add_section(Vec::new(), name, SectionKind::ReadOnlyData); + let section = self.section_mut(section_id); + section.set_data(vec![0; stub_size as usize], u64::from(stub_size)); + section.relocations = vec![Relocation { + offset: 0, + size: stub_size * 8, + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + symbol: symbol_id, + addend: 0, + }]; + + let mut name = b".refptr.".to_vec(); + name.extend_from_slice(&self.symbol(symbol_id).name); + let stub_id = self.add_raw_symbol(Symbol { + name, + value: 0, + size: u64::from(stub_size), + kind: SymbolKind::Data, + scope: SymbolScope::Compilation, + weak: false, + section: SymbolSection::Section(section_id), + flags: SymbolFlags::None, + }); + self.stub_symbols.insert(symbol_id, stub_id); + + stub_id + } + + /// Appends linker directives to the `.drectve` section to tell the linker + /// to export all symbols with `SymbolScope::Dynamic`. + /// + /// This must be called after all symbols have been defined. + pub fn add_coff_exports(&mut self, style: CoffExportStyle) { + assert_eq!(self.format, BinaryFormat::Coff); + + let mut directives = vec![]; + for symbol in &self.symbols { + if symbol.scope == SymbolScope::Dynamic { + match style { + CoffExportStyle::Msvc => directives.extend(b" /EXPORT:\""), + CoffExportStyle::Gnu => directives.extend(b" -export:\""), + } + directives.extend(&symbol.name); + directives.extend(b"\""); + if symbol.kind != SymbolKind::Text { + match style { + CoffExportStyle::Msvc => directives.extend(b",DATA"), + CoffExportStyle::Gnu => directives.extend(b",data"), + } + } + } + } + let drectve = self.add_section(vec![], b".drectve".to_vec(), SectionKind::Linker); + self.append_section_data(drectve, &directives, 1); + } + + pub(crate) fn coff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { + // Calculate offsets of everything, and build strtab. + let mut offset = 0; + let mut strtab = StringTable::default(); + + // COFF header. + offset += mem::size_of::(); + + // Section headers. + offset += self.sections.len() * mem::size_of::(); + + // Calculate size of section data and add section strings to strtab. + let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()]; + for (index, section) in self.sections.iter().enumerate() { + if section.name.len() > 8 { + section_offsets[index].str_id = Some(strtab.add(§ion.name)); + } + + let len = section.data.len(); + if len != 0 { + // TODO: not sure what alignment is required here, but this seems to match LLVM + offset = align(offset, 4); + section_offsets[index].offset = offset; + offset += len; + } else { + section_offsets[index].offset = 0; + } + + // Calculate size of relocations. + let mut count = section.relocations.len(); + if count != 0 { + section_offsets[index].reloc_offset = offset; + if count > 0xffff { + count += 1; + } + offset += count * mem::size_of::(); + } + } + + // Set COMDAT flags. + for comdat in &self.comdats { + let symbol = &self.symbols[comdat.symbol.0]; + let comdat_section = match symbol.section { + SymbolSection::Section(id) => id.0, + _ => { + return Err(Error(format!( + "unsupported COMDAT symbol `{}` section {:?}", + symbol.name().unwrap_or(""), + symbol.section + ))); + } + }; + section_offsets[comdat_section].selection = match comdat.kind { + ComdatKind::NoDuplicates => coff::IMAGE_COMDAT_SELECT_NODUPLICATES, + ComdatKind::Any => coff::IMAGE_COMDAT_SELECT_ANY, + ComdatKind::SameSize => coff::IMAGE_COMDAT_SELECT_SAME_SIZE, + ComdatKind::ExactMatch => coff::IMAGE_COMDAT_SELECT_EXACT_MATCH, + ComdatKind::Largest => coff::IMAGE_COMDAT_SELECT_LARGEST, + ComdatKind::Newest => coff::IMAGE_COMDAT_SELECT_NEWEST, + ComdatKind::Unknown => { + return Err(Error(format!( + "unsupported COMDAT symbol `{}` kind {:?}", + symbol.name().unwrap_or(""), + comdat.kind + ))); + } + }; + for id in &comdat.sections { + let section = &self.sections[id.0]; + if section.symbol.is_none() { + return Err(Error(format!( + "missing symbol for COMDAT section `{}`", + section.name().unwrap_or(""), + ))); + } + if id.0 != comdat_section { + section_offsets[id.0].selection = coff::IMAGE_COMDAT_SELECT_ASSOCIATIVE; + section_offsets[id.0].associative_section = comdat_section as u16 + 1; + } + } + } + + // Calculate size of symbols and add symbol strings to strtab. + let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; + let mut symtab_count = 0; + for (index, symbol) in self.symbols.iter().enumerate() { + symbol_offsets[index].index = symtab_count; + symtab_count += 1; + match symbol.kind { + SymbolKind::File => { + // Name goes in auxiliary symbol records. + let aux_count = (symbol.name.len() + coff::IMAGE_SIZEOF_SYMBOL - 1) + / coff::IMAGE_SIZEOF_SYMBOL; + symbol_offsets[index].aux_count = aux_count as u8; + symtab_count += aux_count; + // Don't add name to strtab. + continue; + } + SymbolKind::Section => { + symbol_offsets[index].aux_count = 1; + symtab_count += 1; + } + _ => {} + } + if symbol.name.len() > 8 { + symbol_offsets[index].str_id = Some(strtab.add(&symbol.name)); + } + } + + // Calculate size of symtab. + let symtab_offset = offset; + let symtab_len = symtab_count * coff::IMAGE_SIZEOF_SYMBOL; + offset += symtab_len; + + // Calculate size of strtab. + let strtab_offset = offset; + let mut strtab_data = Vec::new(); + // First 4 bytes of strtab are the length. + strtab.write(4, &mut strtab_data); + let strtab_len = strtab_data.len() + 4; + offset += strtab_len; + + // Start writing. + buffer + .reserve(offset) + .map_err(|_| Error(String::from("Cannot allocate buffer")))?; + + // Write file header. + let header = coff::ImageFileHeader { + machine: U16::new( + LE, + match self.architecture { + Architecture::Arm => coff::IMAGE_FILE_MACHINE_ARMNT, + Architecture::Aarch64 => coff::IMAGE_FILE_MACHINE_ARM64, + Architecture::I386 => coff::IMAGE_FILE_MACHINE_I386, + Architecture::X86_64 => coff::IMAGE_FILE_MACHINE_AMD64, + _ => { + return Err(Error(format!( + "unimplemented architecture {:?}", + self.architecture + ))); + } + }, + ), + number_of_sections: U16::new(LE, self.sections.len() as u16), + time_date_stamp: U32::default(), + pointer_to_symbol_table: U32::new(LE, symtab_offset as u32), + number_of_symbols: U32::new(LE, symtab_count as u32), + size_of_optional_header: U16::default(), + characteristics: match self.flags { + FileFlags::Coff { characteristics } => U16::new(LE, characteristics), + _ => U16::default(), + }, + }; + buffer.write(&header); + + // Write section headers. + for (index, section) in self.sections.iter().enumerate() { + let mut characteristics = if let SectionFlags::Coff { + characteristics, .. + } = section.flags + { + characteristics + } else { + match section.kind { + SectionKind::Text => { + coff::IMAGE_SCN_CNT_CODE + | coff::IMAGE_SCN_MEM_EXECUTE + | coff::IMAGE_SCN_MEM_READ + } + SectionKind::Data => { + coff::IMAGE_SCN_CNT_INITIALIZED_DATA + | coff::IMAGE_SCN_MEM_READ + | coff::IMAGE_SCN_MEM_WRITE + } + SectionKind::UninitializedData => { + coff::IMAGE_SCN_CNT_UNINITIALIZED_DATA + | coff::IMAGE_SCN_MEM_READ + | coff::IMAGE_SCN_MEM_WRITE + } + SectionKind::ReadOnlyData + | SectionKind::ReadOnlyDataWithRel + | SectionKind::ReadOnlyString => { + coff::IMAGE_SCN_CNT_INITIALIZED_DATA | coff::IMAGE_SCN_MEM_READ + } + SectionKind::Debug | SectionKind::Other | SectionKind::OtherString => { + coff::IMAGE_SCN_CNT_INITIALIZED_DATA + | coff::IMAGE_SCN_MEM_READ + | coff::IMAGE_SCN_MEM_DISCARDABLE + } + SectionKind::Linker => coff::IMAGE_SCN_LNK_INFO | coff::IMAGE_SCN_LNK_REMOVE, + SectionKind::Common + | SectionKind::Tls + | SectionKind::UninitializedTls + | SectionKind::TlsVariables + | SectionKind::Note + | SectionKind::Unknown + | SectionKind::Metadata + | SectionKind::Elf(_) => { + return Err(Error(format!( + "unimplemented section `{}` kind {:?}", + section.name().unwrap_or(""), + section.kind + ))); + } + } + }; + if section_offsets[index].selection != 0 { + characteristics |= coff::IMAGE_SCN_LNK_COMDAT; + }; + if section.relocations.len() > 0xffff { + characteristics |= coff::IMAGE_SCN_LNK_NRELOC_OVFL; + } + characteristics |= match section.align { + 1 => coff::IMAGE_SCN_ALIGN_1BYTES, + 2 => coff::IMAGE_SCN_ALIGN_2BYTES, + 4 => coff::IMAGE_SCN_ALIGN_4BYTES, + 8 => coff::IMAGE_SCN_ALIGN_8BYTES, + 16 => coff::IMAGE_SCN_ALIGN_16BYTES, + 32 => coff::IMAGE_SCN_ALIGN_32BYTES, + 64 => coff::IMAGE_SCN_ALIGN_64BYTES, + 128 => coff::IMAGE_SCN_ALIGN_128BYTES, + 256 => coff::IMAGE_SCN_ALIGN_256BYTES, + 512 => coff::IMAGE_SCN_ALIGN_512BYTES, + 1024 => coff::IMAGE_SCN_ALIGN_1024BYTES, + 2048 => coff::IMAGE_SCN_ALIGN_2048BYTES, + 4096 => coff::IMAGE_SCN_ALIGN_4096BYTES, + 8192 => coff::IMAGE_SCN_ALIGN_8192BYTES, + _ => { + return Err(Error(format!( + "unimplemented section `{}` align {}", + section.name().unwrap_or(""), + section.align + ))); + } + }; + let mut coff_section = coff::ImageSectionHeader { + name: [0; 8], + virtual_size: U32::default(), + virtual_address: U32::default(), + size_of_raw_data: U32::new(LE, section.size as u32), + pointer_to_raw_data: U32::new(LE, section_offsets[index].offset as u32), + pointer_to_relocations: U32::new(LE, section_offsets[index].reloc_offset as u32), + pointer_to_linenumbers: U32::default(), + number_of_relocations: if section.relocations.len() > 0xffff { + U16::new(LE, 0xffff) + } else { + U16::new(LE, section.relocations.len() as u16) + }, + number_of_linenumbers: U16::default(), + characteristics: U32::new(LE, characteristics), + }; + if section.name.len() <= 8 { + coff_section.name[..section.name.len()].copy_from_slice(§ion.name); + } else { + let mut str_offset = strtab.get_offset(section_offsets[index].str_id.unwrap()); + if str_offset <= 9_999_999 { + let mut name = [0; 7]; + let mut len = 0; + if str_offset == 0 { + name[6] = b'0'; + len = 1; + } else { + while str_offset != 0 { + let rem = (str_offset % 10) as u8; + str_offset /= 10; + name[6 - len] = b'0' + rem; + len += 1; + } + } + coff_section.name = [0; 8]; + coff_section.name[0] = b'/'; + coff_section.name[1..][..len].copy_from_slice(&name[7 - len..]); + } else if str_offset as u64 <= 0xf_ffff_ffff { + coff_section.name[0] = b'/'; + coff_section.name[1] = b'/'; + for i in 0..6 { + let rem = (str_offset % 64) as u8; + str_offset /= 64; + let c = match rem { + 0..=25 => b'A' + rem, + 26..=51 => b'a' + rem - 26, + 52..=61 => b'0' + rem - 52, + 62 => b'+', + 63 => b'/', + _ => unreachable!(), + }; + coff_section.name[7 - i] = c; + } + } else { + return Err(Error(format!("invalid section name offset {}", str_offset))); + } + } + buffer.write(&coff_section); + } + + // Write section data and relocations. + for (index, section) in self.sections.iter().enumerate() { + let len = section.data.len(); + if len != 0 { + write_align(buffer, 4); + debug_assert_eq!(section_offsets[index].offset, buffer.len()); + buffer.write_bytes(§ion.data); + } + + if !section.relocations.is_empty() { + debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); + if section.relocations.len() > 0xffff { + let coff_relocation = coff::ImageRelocation { + virtual_address: U32Bytes::new(LE, section.relocations.len() as u32 + 1), + symbol_table_index: U32Bytes::new(LE, 0), + typ: U16Bytes::new(LE, 0), + }; + buffer.write(&coff_relocation); + } + for reloc in §ion.relocations { + //assert!(reloc.implicit_addend); + let typ = match self.architecture { + Architecture::I386 => match (reloc.kind, reloc.size, reloc.addend) { + (RelocationKind::Absolute, 16, 0) => coff::IMAGE_REL_I386_DIR16, + (RelocationKind::Relative, 16, 0) => coff::IMAGE_REL_I386_REL16, + (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_I386_DIR32, + (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_I386_DIR32NB, + (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_I386_SECTION, + (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_I386_SECREL, + (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_I386_SECREL7, + (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_I386_REL32, + (RelocationKind::Coff(x), _, _) => x, + _ => { + return Err(Error(format!("unimplemented relocation {:?}", reloc))); + } + }, + Architecture::X86_64 => match (reloc.kind, reloc.size, reloc.addend) { + (RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_AMD64_ADDR64, + (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32, + (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32NB, + (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_AMD64_REL32, + (RelocationKind::Relative, 32, -5) => coff::IMAGE_REL_AMD64_REL32_1, + (RelocationKind::Relative, 32, -6) => coff::IMAGE_REL_AMD64_REL32_2, + (RelocationKind::Relative, 32, -7) => coff::IMAGE_REL_AMD64_REL32_3, + (RelocationKind::Relative, 32, -8) => coff::IMAGE_REL_AMD64_REL32_4, + (RelocationKind::Relative, 32, -9) => coff::IMAGE_REL_AMD64_REL32_5, + (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_AMD64_SECTION, + (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_AMD64_SECREL, + (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_AMD64_SECREL7, + (RelocationKind::Coff(x), _, _) => x, + _ => { + return Err(Error(format!("unimplemented relocation {:?}", reloc))); + } + }, + Architecture::Arm => match (reloc.kind, reloc.size, reloc.addend) { + (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_ARM_ADDR32, + (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_ARM_ADDR32NB, + (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_ARM_REL32, + (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_ARM_SECTION, + (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_ARM_SECREL, + (RelocationKind::Coff(x), _, _) => x, + _ => { + return Err(Error(format!("unimplemented relocation {:?}", reloc))); + } + }, + Architecture::Aarch64 => match (reloc.kind, reloc.size, reloc.addend) { + (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_ARM64_ADDR32, + (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_ARM64_ADDR32NB, + (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_ARM64_SECTION, + (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_ARM64_SECREL, + (RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_ARM64_ADDR64, + (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_ARM64_REL32, + (RelocationKind::Coff(x), _, _) => x, + _ => { + return Err(Error(format!("unimplemented relocation {:?}", reloc))); + } + }, + _ => { + return Err(Error(format!( + "unimplemented architecture {:?}", + self.architecture + ))); + } + }; + let coff_relocation = coff::ImageRelocation { + virtual_address: U32Bytes::new(LE, reloc.offset as u32), + symbol_table_index: U32Bytes::new( + LE, + symbol_offsets[reloc.symbol.0].index as u32, + ), + typ: U16Bytes::new(LE, typ), + }; + buffer.write(&coff_relocation); + } + } + } + + // Write symbols. + debug_assert_eq!(symtab_offset, buffer.len()); + for (index, symbol) in self.symbols.iter().enumerate() { + let mut name = &symbol.name[..]; + let section_number = match symbol.section { + SymbolSection::None => { + debug_assert_eq!(symbol.kind, SymbolKind::File); + coff::IMAGE_SYM_DEBUG as u16 + } + SymbolSection::Undefined => coff::IMAGE_SYM_UNDEFINED as u16, + SymbolSection::Absolute => coff::IMAGE_SYM_ABSOLUTE as u16, + SymbolSection::Common => coff::IMAGE_SYM_UNDEFINED as u16, + SymbolSection::Section(id) => id.0 as u16 + 1, + }; + let typ = if symbol.kind == SymbolKind::Text { + coff::IMAGE_SYM_DTYPE_FUNCTION << coff::IMAGE_SYM_DTYPE_SHIFT + } else { + coff::IMAGE_SYM_TYPE_NULL + }; + let storage_class = match symbol.kind { + SymbolKind::File => { + // Name goes in auxiliary symbol records. + name = b".file"; + coff::IMAGE_SYM_CLASS_FILE + } + SymbolKind::Section => coff::IMAGE_SYM_CLASS_STATIC, + SymbolKind::Label => coff::IMAGE_SYM_CLASS_LABEL, + SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => { + match symbol.section { + SymbolSection::None => { + return Err(Error(format!( + "missing section for symbol `{}`", + symbol.name().unwrap_or("") + ))); + } + SymbolSection::Undefined | SymbolSection::Common => { + coff::IMAGE_SYM_CLASS_EXTERNAL + } + SymbolSection::Absolute | SymbolSection::Section(_) => { + match symbol.scope { + // TODO: does this need aux symbol records too? + _ if symbol.weak => coff::IMAGE_SYM_CLASS_WEAK_EXTERNAL, + SymbolScope::Unknown => { + return Err(Error(format!( + "unimplemented symbol `{}` scope {:?}", + symbol.name().unwrap_or(""), + symbol.scope + ))); + } + SymbolScope::Compilation => coff::IMAGE_SYM_CLASS_STATIC, + SymbolScope::Linkage | SymbolScope::Dynamic => { + coff::IMAGE_SYM_CLASS_EXTERNAL + } + } + } + } + } + SymbolKind::Unknown | SymbolKind::Null => { + return Err(Error(format!( + "unimplemented symbol `{}` kind {:?}", + symbol.name().unwrap_or(""), + symbol.kind + ))); + } + }; + let number_of_aux_symbols = symbol_offsets[index].aux_count; + let value = if symbol.section == SymbolSection::Common { + symbol.size as u32 + } else { + symbol.value as u32 + }; + let mut coff_symbol = coff::ImageSymbol { + name: [0; 8], + value: U32Bytes::new(LE, value), + section_number: U16Bytes::new(LE, section_number), + typ: U16Bytes::new(LE, typ), + storage_class, + number_of_aux_symbols, + }; + if name.len() <= 8 { + coff_symbol.name[..name.len()].copy_from_slice(name); + } else { + let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap()); + coff_symbol.name[4..8].copy_from_slice(&u32::to_le_bytes(str_offset as u32)); + } + buffer.write(&coff_symbol); + + // Write auxiliary symbols. + match symbol.kind { + SymbolKind::File => { + let aux_len = number_of_aux_symbols as usize * coff::IMAGE_SIZEOF_SYMBOL; + debug_assert!(aux_len >= symbol.name.len()); + let old_len = buffer.len(); + buffer.write_bytes(&symbol.name); + buffer.resize(old_len + aux_len); + } + SymbolKind::Section => { + debug_assert_eq!(number_of_aux_symbols, 1); + let section_index = symbol.section.id().unwrap().0; + let section = &self.sections[section_index]; + let aux = coff::ImageAuxSymbolSection { + length: U32Bytes::new(LE, section.size as u32), + number_of_relocations: if section.relocations.len() > 0xffff { + U16Bytes::new(LE, 0xffff) + } else { + U16Bytes::new(LE, section.relocations.len() as u16) + }, + number_of_linenumbers: U16Bytes::default(), + check_sum: U32Bytes::new(LE, checksum(section.data())), + number: U16Bytes::new( + LE, + section_offsets[section_index].associative_section, + ), + selection: section_offsets[section_index].selection, + reserved: 0, + // TODO: bigobj + high_number: U16Bytes::default(), + }; + buffer.write(&aux); + } + _ => { + debug_assert_eq!(number_of_aux_symbols, 0); + } + } + } + + // Write strtab section. + debug_assert_eq!(strtab_offset, buffer.len()); + buffer.write_bytes(&u32::to_le_bytes(strtab_len as u32)); + buffer.write_bytes(&strtab_data); + + debug_assert_eq!(offset, buffer.len()); + + Ok(()) + } +} + +// JamCRC +fn checksum(data: &[u8]) -> u32 { + let mut hasher = crc32fast::Hasher::new_with_initial(0xffff_ffff); + hasher.update(data); + !hasher.finalize() +} diff --git a/vendor/openssl-src/openssl/FAQ.md b/vendor/openssl-src/openssl/FAQ.md new file mode 100644 index 0000000000000..30f5010ce3a48 --- /dev/null +++ b/vendor/openssl-src/openssl/FAQ.md @@ -0,0 +1,6 @@ +Frequently Asked Questions (FAQ) +================================ + +The [Frequently Asked Questions][FAQ] are now maintained on the OpenSSL homepage. + + [FAQ]: https://www.openssl.org/docs/faq.html diff --git a/vendor/ordered-float-3.9.2/.cargo-checksum.json b/vendor/ordered-float-3.9.2/.cargo-checksum.json new file mode 100644 index 0000000000000..634201cb05b6b --- /dev/null +++ b/vendor/ordered-float-3.9.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"89ee5f78395425d688e9a8dd7cb555b18b8f9863a722dbc04ab08872e2d5a7a7","LICENSE-MIT":"f7715d38a3fa1b4ac97c5729740752505a39cb92ee83ab5b102aeb5eaa7cdea4","README.md":"ded338028d49080cc1a036a5e62974425c78cdcb904289777a6a71e8430e69a8","rustfmt.toml":"d72fafaea8c9695f74c40bc666ada205b935bec3f02488bb33e5994e2831bffb","src/lib.rs":"c990f2b86c1276a29f4d60fab4ada05f6714644151fdc65d55e6bc6171192e7b","tests/test.rs":"6794b482e565b83f5e46ac25cf8b388397be96bce61369e51ebb94c4e730eec6"},"package":"f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc"} \ No newline at end of file diff --git a/vendor/ordered-float-3.9.2/Cargo.toml b/vendor/ordered-float-3.9.2/Cargo.toml new file mode 100644 index 0000000000000..dfa1d5f4242fb --- /dev/null +++ b/vendor/ordered-float-3.9.2/Cargo.toml @@ -0,0 +1,106 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "ordered-float" +version = "3.9.2" +authors = [ + "Jonathan Reem ", + "Matt Brubeck ", +] +description = "Wrappers for total ordering on floats" +readme = "README.md" +keywords = [ + "no_std", + "ord", + "f64", + "f32", + "sort", +] +categories = [ + "science", + "rust-patterns", + "no-std", +] +license = "MIT" +repository = "https://github.com/reem/rust-ordered-float" + +[dependencies.arbitrary] +version = "1.0.0" +optional = true + +[dependencies.bytemuck] +version = "1.12.2" +optional = true +default-features = false + +[dependencies.num-traits] +version = "0.2.1" +default-features = false + +[dependencies.proptest] +version = "1.0.0" +optional = true + +[dependencies.rand] +version = "0.8.3" +optional = true +default-features = false + +[dependencies.rkyv] +version = "0.7.41" +features = ["rend"] +optional = true +default-features = false + +[dependencies.schemars] +version = "0.8.8" +optional = true + +[dependencies.serde] +version = "1.0" +optional = true +default-features = false + +[dependencies.speedy] +version = "0.8.3" +optional = true +default-features = false + +[dev-dependencies.serde_test] +version = "1.0" + +[features] +default = ["std"] +randtest = [ + "rand/std", + "rand/std_rng", +] +rkyv = ["rkyv_32"] +rkyv_16 = [ + "dep:rkyv", + "rkyv?/size_16", +] +rkyv_32 = [ + "dep:rkyv", + "rkyv?/size_32", +] +rkyv_64 = [ + "dep:rkyv", + "rkyv?/size_64", +] +rkyv_ck = ["rkyv?/validation"] +serde = [ + "dep:serde", + "rand?/serde1", +] +std = ["num-traits/std"] diff --git a/vendor/ordered-float-3.9.2/LICENSE-MIT b/vendor/ordered-float-3.9.2/LICENSE-MIT new file mode 100644 index 0000000000000..c8e0f5ec7a510 --- /dev/null +++ b/vendor/ordered-float-3.9.2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 Jonathan Reem + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/ordered-float-3.9.2/README.md b/vendor/ordered-float-3.9.2/README.md new file mode 100644 index 0000000000000..c9a41bdd7dc0c --- /dev/null +++ b/vendor/ordered-float-3.9.2/README.md @@ -0,0 +1,34 @@ +# Ordered Floats + +Provides several wrapper types for Ord and Eq implementations on f64 and friends. + +See the [API documentation](https://docs.rs/ordered-float) for further details. + +## no_std + +To use `ordered_float` without requiring the Rust standard library, disable +the default `std` feature: + +```toml +[dependencies] +ordered-float = { version = "3.0", default-features = false } +``` + +## Optional features + +The following optional features can be enabled in `Cargo.toml`: + +* `bytemuck`: Adds implementations for traits provided by the `bytemuck` crate. +* `rand`: Adds implementations for various distribution types provided by the `rand` crate. +* `serde`: Implements the `serde::Serialize` and `serde::Deserialize` traits. +* `schemars`: Implements the `schemars::JsonSchema` trait. +* `proptest`: Implements the `proptest::Arbitrary` trait. +* `rkyv_16`: Implements `rkyv`'s `Archive`, `Serialize` and `Deserialize` traits with `size_16`. +* `rkyv_32`: Implements `rkyv`'s `Archive`, `Serialize` and `Deserialize` traits with `size_32`. +* `rkyv_64`: Implements `rkyv`'s `Archive`, `Serialize` and `Deserialize` traits with `size_64`. +* `rkyv_ck`: Implements the `bytecheck::CheckBytes` trait. +* `speedy`: Implements `speedy`'s `Readable` and `Writable` traits. + +## License + +MIT diff --git a/vendor/ordered-float-3.9.2/rustfmt.toml b/vendor/ordered-float-3.9.2/rustfmt.toml new file mode 100644 index 0000000000000..e333edc9dbbe4 --- /dev/null +++ b/vendor/ordered-float-3.9.2/rustfmt.toml @@ -0,0 +1,3 @@ +# These two unstable options might improve the layout of the code: +#fn_single_line = true +#where_single_line = true diff --git a/vendor/ordered-float-3.9.2/src/lib.rs b/vendor/ordered-float-3.9.2/src/lib.rs new file mode 100644 index 0000000000000..fa400d2ef6937 --- /dev/null +++ b/vendor/ordered-float-3.9.2/src/lib.rs @@ -0,0 +1,2612 @@ +#![no_std] +#![cfg_attr(test, deny(warnings))] +#![deny(missing_docs)] +#![allow(clippy::derive_partial_eq_without_eq)] + +//! Wrappers for total order on Floats. See the [`OrderedFloat`] and [`NotNan`] docs for details. + +#[cfg(feature = "std")] +extern crate std; +#[cfg(feature = "std")] +use std::error::Error; + +use core::borrow::Borrow; +use core::cmp::Ordering; +use core::convert::TryFrom; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::hint::unreachable_unchecked; +use core::iter::{Product, Sum}; +use core::num::FpCategory; +use core::ops::{ + Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, + SubAssign, +}; +use core::str::FromStr; + +#[cfg(not(feature = "std"))] +use num_traits::float::FloatCore as Float; +use num_traits::{ + AsPrimitive, Bounded, FloatConst, FromPrimitive, Num, NumCast, One, Signed, ToPrimitive, Zero, +}; +#[cfg(feature = "std")] +pub use num_traits::{Float, Pow}; + +#[cfg(feature = "rand")] +pub use impl_rand::{UniformNotNan, UniformOrdered}; + +// masks for the parts of the IEEE 754 float +const SIGN_MASK: u64 = 0x8000000000000000u64; +const EXP_MASK: u64 = 0x7ff0000000000000u64; +const MAN_MASK: u64 = 0x000fffffffffffffu64; + +// canonical raw bit patterns (for hashing) +const CANONICAL_NAN_BITS: u64 = 0x7ff8000000000000u64; + +#[inline(always)] +fn canonicalize_signed_zero(x: T) -> T { + // -0.0 + 0.0 == +0.0 under IEEE754 roundTiesToEven rounding mode, + // which Rust guarantees. Thus by adding a positive zero we + // canonicalize signed zero without any branches in one instruction. + x + T::zero() +} + +/// A wrapper around floats providing implementations of `Eq`, `Ord`, and `Hash`. +/// +/// NaN is sorted as *greater* than all other values and *equal* +/// to itself, in contradiction with the IEEE standard. +/// +/// ``` +/// use ordered_float::OrderedFloat; +/// use std::f32::NAN; +/// +/// let mut v = [OrderedFloat(NAN), OrderedFloat(2.0), OrderedFloat(1.0)]; +/// v.sort(); +/// assert_eq!(v, [OrderedFloat(1.0), OrderedFloat(2.0), OrderedFloat(NAN)]); +/// ``` +/// +/// Because `OrderedFloat` implements `Ord` and `Eq`, it can be used as a key in a `HashSet`, +/// `HashMap`, `BTreeMap`, or `BTreeSet` (unlike the primitive `f32` or `f64` types): +/// +/// ``` +/// # use ordered_float::OrderedFloat; +/// # use std::collections::HashSet; +/// # use std::f32::NAN; +/// +/// let mut s: HashSet> = HashSet::new(); +/// s.insert(OrderedFloat(NAN)); +/// assert!(s.contains(&OrderedFloat(NAN))); +/// ``` +#[derive(Debug, Default, Clone, Copy)] +#[repr(transparent)] +pub struct OrderedFloat(pub T); + +impl OrderedFloat { + /// Get the value out. + #[inline] + pub fn into_inner(self) -> T { + self.0 + } +} + +impl AsRef for OrderedFloat { + #[inline] + fn as_ref(&self) -> &T { + &self.0 + } +} + +impl AsMut for OrderedFloat { + #[inline] + fn as_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +impl<'a, T: Float> From<&'a T> for &'a OrderedFloat { + #[inline] + fn from(t: &'a T) -> &'a OrderedFloat { + // Safety: OrderedFloat is #[repr(transparent)] and has no invalid values. + unsafe { &*(t as *const T as *const OrderedFloat) } + } +} + +impl<'a, T: Float> From<&'a mut T> for &'a mut OrderedFloat { + #[inline] + fn from(t: &'a mut T) -> &'a mut OrderedFloat { + // Safety: OrderedFloat is #[repr(transparent)] and has no invalid values. + unsafe { &mut *(t as *mut T as *mut OrderedFloat) } + } +} + +impl PartialOrd for OrderedFloat { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + + #[inline] + fn lt(&self, other: &Self) -> bool { + !self.ge(other) + } + + #[inline] + fn le(&self, other: &Self) -> bool { + other.ge(self) + } + + #[inline] + fn gt(&self, other: &Self) -> bool { + !other.ge(self) + } + + #[inline] + fn ge(&self, other: &Self) -> bool { + // We consider all NaNs equal, and NaN is the largest possible + // value. Thus if self is NaN we always return true. Otherwise + // self >= other is correct. If other is also not NaN it is trivially + // correct, and if it is we note that nothing can be greater or + // equal to NaN except NaN itself, which we already handled earlier. + self.0.is_nan() | (self.0 >= other.0) + } +} + +impl Ord for OrderedFloat { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + #[allow(clippy::comparison_chain)] + if self < other { + Ordering::Less + } else if self > other { + Ordering::Greater + } else { + Ordering::Equal + } + } +} + +impl PartialEq for OrderedFloat { + #[inline] + fn eq(&self, other: &OrderedFloat) -> bool { + if self.0.is_nan() { + other.0.is_nan() + } else { + self.0 == other.0 + } + } +} + +impl PartialEq for OrderedFloat { + #[inline] + fn eq(&self, other: &T) -> bool { + self.0 == *other + } +} + +impl Hash for OrderedFloat { + fn hash(&self, state: &mut H) { + let bits = if self.is_nan() { + CANONICAL_NAN_BITS + } else { + raw_double_bits(&canonicalize_signed_zero(self.0)) + }; + + bits.hash(state) + } +} + +impl fmt::Display for OrderedFloat { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::LowerExp for OrderedFloat { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::UpperExp for OrderedFloat { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl From> for f32 { + #[inline] + fn from(f: OrderedFloat) -> f32 { + f.0 + } +} + +impl From> for f64 { + #[inline] + fn from(f: OrderedFloat) -> f64 { + f.0 + } +} + +impl From for OrderedFloat { + #[inline] + fn from(val: T) -> Self { + OrderedFloat(val) + } +} + +impl From for OrderedFloat { + fn from(val: bool) -> Self { + OrderedFloat(val as u8 as f32) + } +} + +impl From for OrderedFloat { + fn from(val: bool) -> Self { + OrderedFloat(val as u8 as f64) + } +} + +macro_rules! impl_ordered_float_from { + ($dst:ty, $src:ty) => { + impl From<$src> for OrderedFloat<$dst> { + fn from(val: $src) -> Self { + OrderedFloat(val.into()) + } + } + }; +} +impl_ordered_float_from! {f64, i8} +impl_ordered_float_from! {f64, i16} +impl_ordered_float_from! {f64, i32} +impl_ordered_float_from! {f64, u8} +impl_ordered_float_from! {f64, u16} +impl_ordered_float_from! {f64, u32} +impl_ordered_float_from! {f32, i8} +impl_ordered_float_from! {f32, i16} +impl_ordered_float_from! {f32, u8} +impl_ordered_float_from! {f32, u16} + +impl Deref for OrderedFloat { + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for OrderedFloat { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Eq for OrderedFloat {} + +macro_rules! impl_ordered_float_binop { + ($imp:ident, $method:ident, $assign_imp:ident, $assign_method:ident) => { + impl $imp for OrderedFloat { + type Output = OrderedFloat; + + #[inline] + fn $method(self, other: Self) -> Self::Output { + OrderedFloat((self.0).$method(other.0)) + } + } + + impl $imp for OrderedFloat { + type Output = OrderedFloat; + + #[inline] + fn $method(self, other: T) -> Self::Output { + OrderedFloat((self.0).$method(other)) + } + } + + impl<'a, T> $imp<&'a T> for OrderedFloat + where + T: $imp<&'a T>, + { + type Output = OrderedFloat<>::Output>; + + #[inline] + fn $method(self, other: &'a T) -> Self::Output { + OrderedFloat((self.0).$method(other)) + } + } + + impl<'a, T> $imp<&'a Self> for OrderedFloat + where + T: $imp<&'a T>, + { + type Output = OrderedFloat<>::Output>; + + #[inline] + fn $method(self, other: &'a Self) -> Self::Output { + OrderedFloat((self.0).$method(&other.0)) + } + } + + impl<'a, T> $imp> for &'a OrderedFloat + where + &'a T: $imp, + { + type Output = OrderedFloat<<&'a T as $imp>::Output>; + + #[inline] + fn $method(self, other: OrderedFloat) -> Self::Output { + OrderedFloat((self.0).$method(other.0)) + } + } + + impl<'a, T> $imp for &'a OrderedFloat + where + &'a T: $imp, + { + type Output = OrderedFloat<<&'a T as $imp>::Output>; + + #[inline] + fn $method(self, other: T) -> Self::Output { + OrderedFloat((self.0).$method(other)) + } + } + + impl<'a, T> $imp<&'a T> for &'a OrderedFloat + where + &'a T: $imp, + { + type Output = OrderedFloat<<&'a T as $imp>::Output>; + + #[inline] + fn $method(self, other: &'a T) -> Self::Output { + OrderedFloat((self.0).$method(other)) + } + } + + impl $assign_imp for OrderedFloat { + #[inline] + fn $assign_method(&mut self, other: T) { + (self.0).$assign_method(other); + } + } + + impl<'a, T: $assign_imp<&'a T>> $assign_imp<&'a T> for OrderedFloat { + #[inline] + fn $assign_method(&mut self, other: &'a T) { + (self.0).$assign_method(other); + } + } + + impl $assign_imp for OrderedFloat { + #[inline] + fn $assign_method(&mut self, other: Self) { + (self.0).$assign_method(other.0); + } + } + + impl<'a, T: $assign_imp<&'a T>> $assign_imp<&'a Self> for OrderedFloat { + #[inline] + fn $assign_method(&mut self, other: &'a Self) { + (self.0).$assign_method(&other.0); + } + } + }; +} + +impl_ordered_float_binop! {Add, add, AddAssign, add_assign} +impl_ordered_float_binop! {Sub, sub, SubAssign, sub_assign} +impl_ordered_float_binop! {Mul, mul, MulAssign, mul_assign} +impl_ordered_float_binop! {Div, div, DivAssign, div_assign} +impl_ordered_float_binop! {Rem, rem, RemAssign, rem_assign} + +macro_rules! impl_ordered_float_pow { + ($inner:ty, $rhs:ty) => { + #[cfg(feature = "std")] + impl Pow<$rhs> for OrderedFloat<$inner> { + type Output = OrderedFloat<$inner>; + #[inline] + fn pow(self, rhs: $rhs) -> OrderedFloat<$inner> { + OrderedFloat(<$inner>::pow(self.0, rhs)) + } + } + + #[cfg(feature = "std")] + impl<'a> Pow<&'a $rhs> for OrderedFloat<$inner> { + type Output = OrderedFloat<$inner>; + #[inline] + fn pow(self, rhs: &'a $rhs) -> OrderedFloat<$inner> { + OrderedFloat(<$inner>::pow(self.0, *rhs)) + } + } + + #[cfg(feature = "std")] + impl<'a> Pow<$rhs> for &'a OrderedFloat<$inner> { + type Output = OrderedFloat<$inner>; + #[inline] + fn pow(self, rhs: $rhs) -> OrderedFloat<$inner> { + OrderedFloat(<$inner>::pow(self.0, rhs)) + } + } + + #[cfg(feature = "std")] + impl<'a, 'b> Pow<&'a $rhs> for &'b OrderedFloat<$inner> { + type Output = OrderedFloat<$inner>; + #[inline] + fn pow(self, rhs: &'a $rhs) -> OrderedFloat<$inner> { + OrderedFloat(<$inner>::pow(self.0, *rhs)) + } + } + }; +} + +impl_ordered_float_pow! {f32, i8} +impl_ordered_float_pow! {f32, i16} +impl_ordered_float_pow! {f32, u8} +impl_ordered_float_pow! {f32, u16} +impl_ordered_float_pow! {f32, i32} +impl_ordered_float_pow! {f64, i8} +impl_ordered_float_pow! {f64, i16} +impl_ordered_float_pow! {f64, u8} +impl_ordered_float_pow! {f64, u16} +impl_ordered_float_pow! {f64, i32} +impl_ordered_float_pow! {f32, f32} +impl_ordered_float_pow! {f64, f32} +impl_ordered_float_pow! {f64, f64} + +macro_rules! impl_ordered_float_self_pow { + ($base:ty, $exp:ty) => { + #[cfg(feature = "std")] + impl Pow> for OrderedFloat<$base> { + type Output = OrderedFloat<$base>; + #[inline] + fn pow(self, rhs: OrderedFloat<$exp>) -> OrderedFloat<$base> { + OrderedFloat(<$base>::pow(self.0, rhs.0)) + } + } + + #[cfg(feature = "std")] + impl<'a> Pow<&'a OrderedFloat<$exp>> for OrderedFloat<$base> { + type Output = OrderedFloat<$base>; + #[inline] + fn pow(self, rhs: &'a OrderedFloat<$exp>) -> OrderedFloat<$base> { + OrderedFloat(<$base>::pow(self.0, rhs.0)) + } + } + + #[cfg(feature = "std")] + impl<'a> Pow> for &'a OrderedFloat<$base> { + type Output = OrderedFloat<$base>; + #[inline] + fn pow(self, rhs: OrderedFloat<$exp>) -> OrderedFloat<$base> { + OrderedFloat(<$base>::pow(self.0, rhs.0)) + } + } + + #[cfg(feature = "std")] + impl<'a, 'b> Pow<&'a OrderedFloat<$exp>> for &'b OrderedFloat<$base> { + type Output = OrderedFloat<$base>; + #[inline] + fn pow(self, rhs: &'a OrderedFloat<$exp>) -> OrderedFloat<$base> { + OrderedFloat(<$base>::pow(self.0, rhs.0)) + } + } + }; +} + +impl_ordered_float_self_pow! {f32, f32} +impl_ordered_float_self_pow! {f64, f32} +impl_ordered_float_self_pow! {f64, f64} + +/// Adds a float directly. +impl Sum for OrderedFloat { + fn sum>>(iter: I) -> Self { + OrderedFloat(iter.map(|v| v.0).sum()) + } +} + +impl<'a, T: Float + Sum + 'a> Sum<&'a OrderedFloat> for OrderedFloat { + #[inline] + fn sum>>(iter: I) -> Self { + iter.cloned().sum() + } +} + +impl Product for OrderedFloat { + fn product>>(iter: I) -> Self { + OrderedFloat(iter.map(|v| v.0).product()) + } +} + +impl<'a, T: Float + Product + 'a> Product<&'a OrderedFloat> for OrderedFloat { + #[inline] + fn product>>(iter: I) -> Self { + iter.cloned().product() + } +} + +impl Signed for OrderedFloat { + #[inline] + fn abs(&self) -> Self { + OrderedFloat(self.0.abs()) + } + + fn abs_sub(&self, other: &Self) -> Self { + OrderedFloat(Signed::abs_sub(&self.0, &other.0)) + } + + #[inline] + fn signum(&self) -> Self { + OrderedFloat(self.0.signum()) + } + #[inline] + fn is_positive(&self) -> bool { + self.0.is_positive() + } + #[inline] + fn is_negative(&self) -> bool { + self.0.is_negative() + } +} + +impl Bounded for OrderedFloat { + #[inline] + fn min_value() -> Self { + OrderedFloat(T::min_value()) + } + + #[inline] + fn max_value() -> Self { + OrderedFloat(T::max_value()) + } +} + +impl FromStr for OrderedFloat { + type Err = T::Err; + + /// Convert a &str to `OrderedFloat`. Returns an error if the string fails to parse. + /// + /// ``` + /// use ordered_float::OrderedFloat; + /// + /// assert!("-10".parse::>().is_ok()); + /// assert!("abc".parse::>().is_err()); + /// assert!("NaN".parse::>().is_ok()); + /// ``` + fn from_str(s: &str) -> Result { + T::from_str(s).map(OrderedFloat) + } +} + +impl Neg for OrderedFloat { + type Output = OrderedFloat; + + #[inline] + fn neg(self) -> Self::Output { + OrderedFloat(-self.0) + } +} + +impl<'a, T> Neg for &'a OrderedFloat +where + &'a T: Neg, +{ + type Output = OrderedFloat<<&'a T as Neg>::Output>; + + #[inline] + fn neg(self) -> Self::Output { + OrderedFloat(-(&self.0)) + } +} + +impl Zero for OrderedFloat { + #[inline] + fn zero() -> Self { + OrderedFloat(T::zero()) + } + + #[inline] + fn is_zero(&self) -> bool { + self.0.is_zero() + } +} + +impl One for OrderedFloat { + #[inline] + fn one() -> Self { + OrderedFloat(T::one()) + } +} + +impl NumCast for OrderedFloat { + #[inline] + fn from(n: F) -> Option { + T::from(n).map(OrderedFloat) + } +} + +macro_rules! impl_as_primitive { + (@ (NotNan<$T: ty>) => $(#[$cfg:meta])* impl (NotNan<$U: ty>) ) => { + $(#[$cfg])* + impl AsPrimitive> for NotNan<$T> { + #[inline] fn as_(self) -> NotNan<$U> { + // Safety: `NotNan` guarantees that the value is not NaN. + unsafe {NotNan::new_unchecked(self.0 as $U) } + } + } + }; + (@ ($T: ty) => $(#[$cfg:meta])* impl (NotNan<$U: ty>) ) => { + $(#[$cfg])* + impl AsPrimitive> for $T { + #[inline] fn as_(self) -> NotNan<$U> { NotNan(self as $U) } + } + }; + (@ (NotNan<$T: ty>) => $(#[$cfg:meta])* impl ($U: ty) ) => { + $(#[$cfg])* + impl AsPrimitive<$U> for NotNan<$T> { + #[inline] fn as_(self) -> $U { self.0 as $U } + } + }; + (@ (OrderedFloat<$T: ty>) => $(#[$cfg:meta])* impl (OrderedFloat<$U: ty>) ) => { + $(#[$cfg])* + impl AsPrimitive> for OrderedFloat<$T> { + #[inline] fn as_(self) -> OrderedFloat<$U> { OrderedFloat(self.0 as $U) } + } + }; + (@ ($T: ty) => $(#[$cfg:meta])* impl (OrderedFloat<$U: ty>) ) => { + $(#[$cfg])* + impl AsPrimitive> for $T { + #[inline] fn as_(self) -> OrderedFloat<$U> { OrderedFloat(self as $U) } + } + }; + (@ (OrderedFloat<$T: ty>) => $(#[$cfg:meta])* impl ($U: ty) ) => { + $(#[$cfg])* + impl AsPrimitive<$U> for OrderedFloat<$T> { + #[inline] fn as_(self) -> $U { self.0 as $U } + } + }; + ($T: tt => { $( $U: tt ),* } ) => {$( + impl_as_primitive!(@ $T => impl $U); + )*}; +} + +impl_as_primitive!((OrderedFloat) => { (OrderedFloat), (OrderedFloat) }); +impl_as_primitive!((OrderedFloat) => { (OrderedFloat), (OrderedFloat) }); + +impl_as_primitive!((NotNan) => { (NotNan), (NotNan) }); +impl_as_primitive!((NotNan) => { (NotNan), (NotNan) }); + +impl_as_primitive!((u8) => { (OrderedFloat), (OrderedFloat) }); +impl_as_primitive!((i8) => { (OrderedFloat), (OrderedFloat) }); +impl_as_primitive!((u16) => { (OrderedFloat), (OrderedFloat) }); +impl_as_primitive!((i16) => { (OrderedFloat), (OrderedFloat) }); +impl_as_primitive!((u32) => { (OrderedFloat), (OrderedFloat) }); +impl_as_primitive!((i32) => { (OrderedFloat), (OrderedFloat) }); +impl_as_primitive!((u64) => { (OrderedFloat), (OrderedFloat) }); +impl_as_primitive!((i64) => { (OrderedFloat), (OrderedFloat) }); +impl_as_primitive!((usize) => { (OrderedFloat), (OrderedFloat) }); +impl_as_primitive!((isize) => { (OrderedFloat), (OrderedFloat) }); +impl_as_primitive!((f32) => { (OrderedFloat), (OrderedFloat) }); +impl_as_primitive!((f64) => { (OrderedFloat), (OrderedFloat) }); + +impl_as_primitive!((u8) => { (NotNan), (NotNan) }); +impl_as_primitive!((i8) => { (NotNan), (NotNan) }); +impl_as_primitive!((u16) => { (NotNan), (NotNan) }); +impl_as_primitive!((i16) => { (NotNan), (NotNan) }); +impl_as_primitive!((u32) => { (NotNan), (NotNan) }); +impl_as_primitive!((i32) => { (NotNan), (NotNan) }); +impl_as_primitive!((u64) => { (NotNan), (NotNan) }); +impl_as_primitive!((i64) => { (NotNan), (NotNan) }); +impl_as_primitive!((usize) => { (NotNan), (NotNan) }); +impl_as_primitive!((isize) => { (NotNan), (NotNan) }); + +impl_as_primitive!((OrderedFloat) => { (u8), (u16), (u32), (u64), (usize), (i8), (i16), (i32), (i64), (isize), (f32), (f64) }); +impl_as_primitive!((OrderedFloat) => { (u8), (u16), (u32), (u64), (usize), (i8), (i16), (i32), (i64), (isize), (f32), (f64) }); + +impl_as_primitive!((NotNan) => { (u8), (u16), (u32), (u64), (usize), (i8), (i16), (i32), (i64), (isize), (f32), (f64) }); +impl_as_primitive!((NotNan) => { (u8), (u16), (u32), (u64), (usize), (i8), (i16), (i32), (i64), (isize), (f32), (f64) }); + +impl FromPrimitive for OrderedFloat { + fn from_i64(n: i64) -> Option { + T::from_i64(n).map(OrderedFloat) + } + fn from_u64(n: u64) -> Option { + T::from_u64(n).map(OrderedFloat) + } + fn from_isize(n: isize) -> Option { + T::from_isize(n).map(OrderedFloat) + } + fn from_i8(n: i8) -> Option { + T::from_i8(n).map(OrderedFloat) + } + fn from_i16(n: i16) -> Option { + T::from_i16(n).map(OrderedFloat) + } + fn from_i32(n: i32) -> Option { + T::from_i32(n).map(OrderedFloat) + } + fn from_usize(n: usize) -> Option { + T::from_usize(n).map(OrderedFloat) + } + fn from_u8(n: u8) -> Option { + T::from_u8(n).map(OrderedFloat) + } + fn from_u16(n: u16) -> Option { + T::from_u16(n).map(OrderedFloat) + } + fn from_u32(n: u32) -> Option { + T::from_u32(n).map(OrderedFloat) + } + fn from_f32(n: f32) -> Option { + T::from_f32(n).map(OrderedFloat) + } + fn from_f64(n: f64) -> Option { + T::from_f64(n).map(OrderedFloat) + } +} + +impl ToPrimitive for OrderedFloat { + fn to_i64(&self) -> Option { + self.0.to_i64() + } + fn to_u64(&self) -> Option { + self.0.to_u64() + } + fn to_isize(&self) -> Option { + self.0.to_isize() + } + fn to_i8(&self) -> Option { + self.0.to_i8() + } + fn to_i16(&self) -> Option { + self.0.to_i16() + } + fn to_i32(&self) -> Option { + self.0.to_i32() + } + fn to_usize(&self) -> Option { + self.0.to_usize() + } + fn to_u8(&self) -> Option { + self.0.to_u8() + } + fn to_u16(&self) -> Option { + self.0.to_u16() + } + fn to_u32(&self) -> Option { + self.0.to_u32() + } + fn to_f32(&self) -> Option { + self.0.to_f32() + } + fn to_f64(&self) -> Option { + self.0.to_f64() + } +} + +impl num_traits::float::FloatCore for OrderedFloat { + fn nan() -> Self { + OrderedFloat(T::nan()) + } + fn infinity() -> Self { + OrderedFloat(T::infinity()) + } + fn neg_infinity() -> Self { + OrderedFloat(T::neg_infinity()) + } + fn neg_zero() -> Self { + OrderedFloat(T::neg_zero()) + } + fn min_value() -> Self { + OrderedFloat(T::min_value()) + } + fn min_positive_value() -> Self { + OrderedFloat(T::min_positive_value()) + } + fn max_value() -> Self { + OrderedFloat(T::max_value()) + } + fn is_nan(self) -> bool { + self.0.is_nan() + } + fn is_infinite(self) -> bool { + self.0.is_infinite() + } + fn is_finite(self) -> bool { + self.0.is_finite() + } + fn is_normal(self) -> bool { + self.0.is_normal() + } + fn classify(self) -> FpCategory { + self.0.classify() + } + fn floor(self) -> Self { + OrderedFloat(self.0.floor()) + } + fn ceil(self) -> Self { + OrderedFloat(self.0.ceil()) + } + fn round(self) -> Self { + OrderedFloat(self.0.round()) + } + fn trunc(self) -> Self { + OrderedFloat(self.0.trunc()) + } + fn fract(self) -> Self { + OrderedFloat(self.0.fract()) + } + fn abs(self) -> Self { + OrderedFloat(self.0.abs()) + } + fn signum(self) -> Self { + OrderedFloat(self.0.signum()) + } + fn is_sign_positive(self) -> bool { + self.0.is_sign_positive() + } + fn is_sign_negative(self) -> bool { + self.0.is_sign_negative() + } + fn recip(self) -> Self { + OrderedFloat(self.0.recip()) + } + fn powi(self, n: i32) -> Self { + OrderedFloat(self.0.powi(n)) + } + fn integer_decode(self) -> (u64, i16, i8) { + self.0.integer_decode() + } + fn epsilon() -> Self { + OrderedFloat(T::epsilon()) + } + fn to_degrees(self) -> Self { + OrderedFloat(self.0.to_degrees()) + } + fn to_radians(self) -> Self { + OrderedFloat(self.0.to_radians()) + } +} + +#[cfg(feature = "std")] +impl Float for OrderedFloat { + fn nan() -> Self { + OrderedFloat(T::nan()) + } + fn infinity() -> Self { + OrderedFloat(T::infinity()) + } + fn neg_infinity() -> Self { + OrderedFloat(T::neg_infinity()) + } + fn neg_zero() -> Self { + OrderedFloat(T::neg_zero()) + } + fn min_value() -> Self { + OrderedFloat(T::min_value()) + } + fn min_positive_value() -> Self { + OrderedFloat(T::min_positive_value()) + } + fn max_value() -> Self { + OrderedFloat(T::max_value()) + } + fn is_nan(self) -> bool { + self.0.is_nan() + } + fn is_infinite(self) -> bool { + self.0.is_infinite() + } + fn is_finite(self) -> bool { + self.0.is_finite() + } + fn is_normal(self) -> bool { + self.0.is_normal() + } + fn classify(self) -> FpCategory { + self.0.classify() + } + fn floor(self) -> Self { + OrderedFloat(self.0.floor()) + } + fn ceil(self) -> Self { + OrderedFloat(self.0.ceil()) + } + fn round(self) -> Self { + OrderedFloat(self.0.round()) + } + fn trunc(self) -> Self { + OrderedFloat(self.0.trunc()) + } + fn fract(self) -> Self { + OrderedFloat(self.0.fract()) + } + fn abs(self) -> Self { + OrderedFloat(self.0.abs()) + } + fn signum(self) -> Self { + OrderedFloat(self.0.signum()) + } + fn is_sign_positive(self) -> bool { + self.0.is_sign_positive() + } + fn is_sign_negative(self) -> bool { + self.0.is_sign_negative() + } + fn mul_add(self, a: Self, b: Self) -> Self { + OrderedFloat(self.0.mul_add(a.0, b.0)) + } + fn recip(self) -> Self { + OrderedFloat(self.0.recip()) + } + fn powi(self, n: i32) -> Self { + OrderedFloat(self.0.powi(n)) + } + fn powf(self, n: Self) -> Self { + OrderedFloat(self.0.powf(n.0)) + } + fn sqrt(self) -> Self { + OrderedFloat(self.0.sqrt()) + } + fn exp(self) -> Self { + OrderedFloat(self.0.exp()) + } + fn exp2(self) -> Self { + OrderedFloat(self.0.exp2()) + } + fn ln(self) -> Self { + OrderedFloat(self.0.ln()) + } + fn log(self, base: Self) -> Self { + OrderedFloat(self.0.log(base.0)) + } + fn log2(self) -> Self { + OrderedFloat(self.0.log2()) + } + fn log10(self) -> Self { + OrderedFloat(self.0.log10()) + } + fn max(self, other: Self) -> Self { + OrderedFloat(self.0.max(other.0)) + } + fn min(self, other: Self) -> Self { + OrderedFloat(self.0.min(other.0)) + } + fn abs_sub(self, other: Self) -> Self { + OrderedFloat(self.0.abs_sub(other.0)) + } + fn cbrt(self) -> Self { + OrderedFloat(self.0.cbrt()) + } + fn hypot(self, other: Self) -> Self { + OrderedFloat(self.0.hypot(other.0)) + } + fn sin(self) -> Self { + OrderedFloat(self.0.sin()) + } + fn cos(self) -> Self { + OrderedFloat(self.0.cos()) + } + fn tan(self) -> Self { + OrderedFloat(self.0.tan()) + } + fn asin(self) -> Self { + OrderedFloat(self.0.asin()) + } + fn acos(self) -> Self { + OrderedFloat(self.0.acos()) + } + fn atan(self) -> Self { + OrderedFloat(self.0.atan()) + } + fn atan2(self, other: Self) -> Self { + OrderedFloat(self.0.atan2(other.0)) + } + fn sin_cos(self) -> (Self, Self) { + let (a, b) = self.0.sin_cos(); + (OrderedFloat(a), OrderedFloat(b)) + } + fn exp_m1(self) -> Self { + OrderedFloat(self.0.exp_m1()) + } + fn ln_1p(self) -> Self { + OrderedFloat(self.0.ln_1p()) + } + fn sinh(self) -> Self { + OrderedFloat(self.0.sinh()) + } + fn cosh(self) -> Self { + OrderedFloat(self.0.cosh()) + } + fn tanh(self) -> Self { + OrderedFloat(self.0.tanh()) + } + fn asinh(self) -> Self { + OrderedFloat(self.0.asinh()) + } + fn acosh(self) -> Self { + OrderedFloat(self.0.acosh()) + } + fn atanh(self) -> Self { + OrderedFloat(self.0.atanh()) + } + fn integer_decode(self) -> (u64, i16, i8) { + self.0.integer_decode() + } + fn epsilon() -> Self { + OrderedFloat(T::epsilon()) + } + fn to_degrees(self) -> Self { + OrderedFloat(self.0.to_degrees()) + } + fn to_radians(self) -> Self { + OrderedFloat(self.0.to_radians()) + } +} + +impl Num for OrderedFloat { + type FromStrRadixErr = T::FromStrRadixErr; + fn from_str_radix(str: &str, radix: u32) -> Result { + T::from_str_radix(str, radix).map(OrderedFloat) + } +} + +/// A wrapper around floats providing an implementation of `Eq`, `Ord` and `Hash`. +/// +/// A NaN value cannot be stored in this type. +/// +/// ``` +/// use ordered_float::NotNan; +/// +/// let mut v = [ +/// NotNan::new(2.0).unwrap(), +/// NotNan::new(1.0).unwrap(), +/// ]; +/// v.sort(); +/// assert_eq!(v, [1.0, 2.0]); +/// ``` +/// +/// Because `NotNan` implements `Ord` and `Eq`, it can be used as a key in a `HashSet`, +/// `HashMap`, `BTreeMap`, or `BTreeSet` (unlike the primitive `f32` or `f64` types): +/// +/// ``` +/// # use ordered_float::NotNan; +/// # use std::collections::HashSet; +/// +/// let mut s: HashSet> = HashSet::new(); +/// let key = NotNan::new(1.0).unwrap(); +/// s.insert(key); +/// assert!(s.contains(&key)); +/// ``` +/// +/// Arithmetic on NotNan values will panic if it produces a NaN value: +/// +/// ```should_panic +/// # use ordered_float::NotNan; +/// let a = NotNan::new(std::f32::INFINITY).unwrap(); +/// let b = NotNan::new(std::f32::NEG_INFINITY).unwrap(); +/// +/// // This will panic: +/// let c = a + b; +/// ``` +#[derive(PartialOrd, PartialEq, Debug, Default, Clone, Copy)] +#[repr(transparent)] +pub struct NotNan(T); + +impl NotNan { + /// Create a `NotNan` value. + /// + /// Returns `Err` if `val` is NaN + pub fn new(val: T) -> Result { + match val { + ref val if val.is_nan() => Err(FloatIsNan), + val => Ok(NotNan(val)), + } + } +} + +impl NotNan { + /// Get the value out. + #[inline] + pub fn into_inner(self) -> T { + self.0 + } + + /// Create a `NotNan` value from a value that is guaranteed to not be NaN + /// + /// # Safety + /// + /// Behaviour is undefined if `val` is NaN + #[inline] + pub const unsafe fn new_unchecked(val: T) -> Self { + NotNan(val) + } + + /// Create a `NotNan` value from a value that is guaranteed to not be NaN + /// + /// # Safety + /// + /// Behaviour is undefined if `val` is NaN + #[deprecated( + since = "2.5.0", + note = "Please use the new_unchecked function instead." + )] + #[inline] + pub const unsafe fn unchecked_new(val: T) -> Self { + Self::new_unchecked(val) + } +} + +impl AsRef for NotNan { + #[inline] + fn as_ref(&self) -> &T { + &self.0 + } +} + +impl Borrow for NotNan { + #[inline] + fn borrow(&self) -> &f32 { + &self.0 + } +} + +impl Borrow for NotNan { + #[inline] + fn borrow(&self) -> &f64 { + &self.0 + } +} + +#[allow(clippy::derive_ord_xor_partial_ord)] +impl Ord for NotNan { + fn cmp(&self, other: &NotNan) -> Ordering { + match self.partial_cmp(other) { + Some(ord) => ord, + None => unsafe { unreachable_unchecked() }, + } + } +} + +impl Hash for NotNan { + #[inline] + fn hash(&self, state: &mut H) { + let bits = raw_double_bits(&canonicalize_signed_zero(self.0)); + bits.hash(state) + } +} + +impl fmt::Display for NotNan { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl NotNan { + /// Converts this [`NotNan`]`<`[`f64`]`>` to a [`NotNan`]`<`[`f32`]`>` while giving up on + /// precision, [using `roundTiesToEven` as rounding mode, yielding `Infinity` on + /// overflow](https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics). + pub fn as_f32(self) -> NotNan { + // This is not destroying invariants, as it is a pure rounding operation. The only two special + // cases are where f32 would be overflowing, then the operation yields Infinity, or where + // the input is already NaN, in which case the invariant is already broken elsewhere. + NotNan(self.0 as f32) + } +} + +impl From> for f32 { + #[inline] + fn from(value: NotNan) -> Self { + value.0 + } +} + +impl From> for f64 { + #[inline] + fn from(value: NotNan) -> Self { + value.0 + } +} + +impl TryFrom for NotNan { + type Error = FloatIsNan; + #[inline] + fn try_from(v: f32) -> Result { + NotNan::new(v) + } +} + +impl TryFrom for NotNan { + type Error = FloatIsNan; + #[inline] + fn try_from(v: f64) -> Result { + NotNan::new(v) + } +} + +macro_rules! impl_from_int_primitive { + ($primitive:ty, $inner:ty) => { + impl From<$primitive> for NotNan<$inner> { + fn from(source: $primitive) -> Self { + // the primitives with which this macro will be called cannot hold a value that + // f64::from would convert to NaN, so this does not hurt invariants + NotNan(<$inner as From<$primitive>>::from(source)) + } + } + }; +} + +impl_from_int_primitive!(i8, f64); +impl_from_int_primitive!(i16, f64); +impl_from_int_primitive!(i32, f64); +impl_from_int_primitive!(u8, f64); +impl_from_int_primitive!(u16, f64); +impl_from_int_primitive!(u32, f64); + +impl_from_int_primitive!(i8, f32); +impl_from_int_primitive!(i16, f32); +impl_from_int_primitive!(u8, f32); +impl_from_int_primitive!(u16, f32); + +impl From> for NotNan { + #[inline] + fn from(v: NotNan) -> NotNan { + unsafe { NotNan::new_unchecked(v.0 as f64) } + } +} + +impl Deref for NotNan { + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Eq for NotNan {} + +impl PartialEq for NotNan { + #[inline] + fn eq(&self, other: &T) -> bool { + self.0 == *other + } +} + +/// Adds a float directly. +/// +/// Panics if the provided value is NaN or the computation results in NaN +impl Add for NotNan { + type Output = Self; + + #[inline] + fn add(self, other: T) -> Self { + NotNan::new(self.0 + other).expect("Addition resulted in NaN") + } +} + +/// Adds a float directly. +/// +/// Panics if the provided value is NaN. +impl Sum for NotNan { + fn sum>>(iter: I) -> Self { + NotNan::new(iter.map(|v| v.0).sum()).expect("Sum resulted in NaN") + } +} + +impl<'a, T: Float + Sum + 'a> Sum<&'a NotNan> for NotNan { + #[inline] + fn sum>>(iter: I) -> Self { + iter.cloned().sum() + } +} + +/// Subtracts a float directly. +/// +/// Panics if the provided value is NaN or the computation results in NaN +impl Sub for NotNan { + type Output = Self; + + #[inline] + fn sub(self, other: T) -> Self { + NotNan::new(self.0 - other).expect("Subtraction resulted in NaN") + } +} + +/// Multiplies a float directly. +/// +/// Panics if the provided value is NaN or the computation results in NaN +impl Mul for NotNan { + type Output = Self; + + #[inline] + fn mul(self, other: T) -> Self { + NotNan::new(self.0 * other).expect("Multiplication resulted in NaN") + } +} + +impl Product for NotNan { + fn product>>(iter: I) -> Self { + NotNan::new(iter.map(|v| v.0).product()).expect("Product resulted in NaN") + } +} + +impl<'a, T: Float + Product + 'a> Product<&'a NotNan> for NotNan { + #[inline] + fn product>>(iter: I) -> Self { + iter.cloned().product() + } +} + +/// Divides a float directly. +/// +/// Panics if the provided value is NaN or the computation results in NaN +impl Div for NotNan { + type Output = Self; + + #[inline] + fn div(self, other: T) -> Self { + NotNan::new(self.0 / other).expect("Division resulted in NaN") + } +} + +/// Calculates `%` with a float directly. +/// +/// Panics if the provided value is NaN or the computation results in NaN +impl Rem for NotNan { + type Output = Self; + + #[inline] + fn rem(self, other: T) -> Self { + NotNan::new(self.0 % other).expect("Rem resulted in NaN") + } +} + +macro_rules! impl_not_nan_binop { + ($imp:ident, $method:ident, $assign_imp:ident, $assign_method:ident) => { + impl $imp for NotNan { + type Output = Self; + + #[inline] + fn $method(self, other: Self) -> Self { + self.$method(other.0) + } + } + + impl $imp<&T> for NotNan { + type Output = NotNan; + + #[inline] + fn $method(self, other: &T) -> Self::Output { + self.$method(*other) + } + } + + impl $imp<&Self> for NotNan { + type Output = NotNan; + + #[inline] + fn $method(self, other: &Self) -> Self::Output { + self.$method(other.0) + } + } + + impl $imp for &NotNan { + type Output = NotNan; + + #[inline] + fn $method(self, other: Self) -> Self::Output { + (*self).$method(other.0) + } + } + + impl $imp> for &NotNan { + type Output = NotNan; + + #[inline] + fn $method(self, other: NotNan) -> Self::Output { + (*self).$method(other.0) + } + } + + impl $imp for &NotNan { + type Output = NotNan; + + #[inline] + fn $method(self, other: T) -> Self::Output { + (*self).$method(other) + } + } + + impl $imp<&T> for &NotNan { + type Output = NotNan; + + #[inline] + fn $method(self, other: &T) -> Self::Output { + (*self).$method(*other) + } + } + + impl $assign_imp for NotNan { + #[inline] + fn $assign_method(&mut self, other: T) { + *self = (*self).$method(other); + } + } + + impl $assign_imp<&T> for NotNan { + #[inline] + fn $assign_method(&mut self, other: &T) { + *self = (*self).$method(*other); + } + } + + impl $assign_imp for NotNan { + #[inline] + fn $assign_method(&mut self, other: Self) { + (*self).$assign_method(other.0); + } + } + + impl $assign_imp<&Self> for NotNan { + #[inline] + fn $assign_method(&mut self, other: &Self) { + (*self).$assign_method(other.0); + } + } + }; +} + +impl_not_nan_binop! {Add, add, AddAssign, add_assign} +impl_not_nan_binop! {Sub, sub, SubAssign, sub_assign} +impl_not_nan_binop! {Mul, mul, MulAssign, mul_assign} +impl_not_nan_binop! {Div, div, DivAssign, div_assign} +impl_not_nan_binop! {Rem, rem, RemAssign, rem_assign} + +// Will panic if NaN value is return from the operation +macro_rules! impl_not_nan_pow { + ($inner:ty, $rhs:ty) => { + #[cfg(feature = "std")] + impl Pow<$rhs> for NotNan<$inner> { + type Output = NotNan<$inner>; + #[inline] + fn pow(self, rhs: $rhs) -> NotNan<$inner> { + NotNan::new(<$inner>::pow(self.0, rhs)).expect("Pow resulted in NaN") + } + } + + #[cfg(feature = "std")] + impl<'a> Pow<&'a $rhs> for NotNan<$inner> { + type Output = NotNan<$inner>; + #[inline] + fn pow(self, rhs: &'a $rhs) -> NotNan<$inner> { + NotNan::new(<$inner>::pow(self.0, *rhs)).expect("Pow resulted in NaN") + } + } + + #[cfg(feature = "std")] + impl<'a> Pow<$rhs> for &'a NotNan<$inner> { + type Output = NotNan<$inner>; + #[inline] + fn pow(self, rhs: $rhs) -> NotNan<$inner> { + NotNan::new(<$inner>::pow(self.0, rhs)).expect("Pow resulted in NaN") + } + } + + #[cfg(feature = "std")] + impl<'a, 'b> Pow<&'a $rhs> for &'b NotNan<$inner> { + type Output = NotNan<$inner>; + #[inline] + fn pow(self, rhs: &'a $rhs) -> NotNan<$inner> { + NotNan::new(<$inner>::pow(self.0, *rhs)).expect("Pow resulted in NaN") + } + } + }; +} + +impl_not_nan_pow! {f32, i8} +impl_not_nan_pow! {f32, i16} +impl_not_nan_pow! {f32, u8} +impl_not_nan_pow! {f32, u16} +impl_not_nan_pow! {f32, i32} +impl_not_nan_pow! {f64, i8} +impl_not_nan_pow! {f64, i16} +impl_not_nan_pow! {f64, u8} +impl_not_nan_pow! {f64, u16} +impl_not_nan_pow! {f64, i32} +impl_not_nan_pow! {f32, f32} +impl_not_nan_pow! {f64, f32} +impl_not_nan_pow! {f64, f64} + +// This also should panic on NaN +macro_rules! impl_not_nan_self_pow { + ($base:ty, $exp:ty) => { + #[cfg(feature = "std")] + impl Pow> for NotNan<$base> { + type Output = NotNan<$base>; + #[inline] + fn pow(self, rhs: NotNan<$exp>) -> NotNan<$base> { + NotNan::new(self.0.pow(rhs.0)).expect("Pow resulted in NaN") + } + } + + #[cfg(feature = "std")] + impl<'a> Pow<&'a NotNan<$exp>> for NotNan<$base> { + type Output = NotNan<$base>; + #[inline] + fn pow(self, rhs: &'a NotNan<$exp>) -> NotNan<$base> { + NotNan::new(self.0.pow(rhs.0)).expect("Pow resulted in NaN") + } + } + + #[cfg(feature = "std")] + impl<'a> Pow> for &'a NotNan<$base> { + type Output = NotNan<$base>; + #[inline] + fn pow(self, rhs: NotNan<$exp>) -> NotNan<$base> { + NotNan::new(self.0.pow(rhs.0)).expect("Pow resulted in NaN") + } + } + + #[cfg(feature = "std")] + impl<'a, 'b> Pow<&'a NotNan<$exp>> for &'b NotNan<$base> { + type Output = NotNan<$base>; + #[inline] + fn pow(self, rhs: &'a NotNan<$exp>) -> NotNan<$base> { + NotNan::new(self.0.pow(rhs.0)).expect("Pow resulted in NaN") + } + } + }; +} + +impl_not_nan_self_pow! {f32, f32} +impl_not_nan_self_pow! {f64, f32} +impl_not_nan_self_pow! {f64, f64} + +impl Neg for NotNan { + type Output = Self; + + #[inline] + fn neg(self) -> Self { + NotNan(-self.0) + } +} + +impl Neg for &NotNan { + type Output = NotNan; + + #[inline] + fn neg(self) -> Self::Output { + NotNan(-self.0) + } +} + +/// An error indicating an attempt to construct NotNan from a NaN +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct FloatIsNan; + +#[cfg(feature = "std")] +impl Error for FloatIsNan { + fn description(&self) -> &str { + "NotNan constructed with NaN" + } +} + +impl fmt::Display for FloatIsNan { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "NotNan constructed with NaN") + } +} + +#[cfg(feature = "std")] +impl From for std::io::Error { + #[inline] + fn from(e: FloatIsNan) -> std::io::Error { + std::io::Error::new(std::io::ErrorKind::InvalidInput, e) + } +} + +#[inline] +/// Used for hashing. Input must not be zero or NaN. +fn raw_double_bits(f: &F) -> u64 { + let (man, exp, sign) = f.integer_decode(); + let exp_u64 = exp as u16 as u64; + let sign_u64 = (sign > 0) as u64; + (man & MAN_MASK) | ((exp_u64 << 52) & EXP_MASK) | ((sign_u64 << 63) & SIGN_MASK) +} + +impl Zero for NotNan { + #[inline] + fn zero() -> Self { + NotNan(T::zero()) + } + + #[inline] + fn is_zero(&self) -> bool { + self.0.is_zero() + } +} + +impl One for NotNan { + #[inline] + fn one() -> Self { + NotNan(T::one()) + } +} + +impl Bounded for NotNan { + #[inline] + fn min_value() -> Self { + NotNan(T::min_value()) + } + + #[inline] + fn max_value() -> Self { + NotNan(T::max_value()) + } +} + +impl FromStr for NotNan { + type Err = ParseNotNanError; + + /// Convert a &str to `NotNan`. Returns an error if the string fails to parse, + /// or if the resulting value is NaN + /// + /// ``` + /// use ordered_float::NotNan; + /// + /// assert!("-10".parse::>().is_ok()); + /// assert!("abc".parse::>().is_err()); + /// assert!("NaN".parse::>().is_err()); + /// ``` + fn from_str(src: &str) -> Result { + src.parse() + .map_err(ParseNotNanError::ParseFloatError) + .and_then(|f| NotNan::new(f).map_err(|_| ParseNotNanError::IsNaN)) + } +} + +impl FromPrimitive for NotNan { + fn from_i64(n: i64) -> Option { + T::from_i64(n).and_then(|n| NotNan::new(n).ok()) + } + fn from_u64(n: u64) -> Option { + T::from_u64(n).and_then(|n| NotNan::new(n).ok()) + } + + fn from_isize(n: isize) -> Option { + T::from_isize(n).and_then(|n| NotNan::new(n).ok()) + } + fn from_i8(n: i8) -> Option { + T::from_i8(n).and_then(|n| NotNan::new(n).ok()) + } + fn from_i16(n: i16) -> Option { + T::from_i16(n).and_then(|n| NotNan::new(n).ok()) + } + fn from_i32(n: i32) -> Option { + T::from_i32(n).and_then(|n| NotNan::new(n).ok()) + } + fn from_usize(n: usize) -> Option { + T::from_usize(n).and_then(|n| NotNan::new(n).ok()) + } + fn from_u8(n: u8) -> Option { + T::from_u8(n).and_then(|n| NotNan::new(n).ok()) + } + fn from_u16(n: u16) -> Option { + T::from_u16(n).and_then(|n| NotNan::new(n).ok()) + } + fn from_u32(n: u32) -> Option { + T::from_u32(n).and_then(|n| NotNan::new(n).ok()) + } + fn from_f32(n: f32) -> Option { + T::from_f32(n).and_then(|n| NotNan::new(n).ok()) + } + fn from_f64(n: f64) -> Option { + T::from_f64(n).and_then(|n| NotNan::new(n).ok()) + } +} + +impl ToPrimitive for NotNan { + fn to_i64(&self) -> Option { + self.0.to_i64() + } + fn to_u64(&self) -> Option { + self.0.to_u64() + } + + fn to_isize(&self) -> Option { + self.0.to_isize() + } + fn to_i8(&self) -> Option { + self.0.to_i8() + } + fn to_i16(&self) -> Option { + self.0.to_i16() + } + fn to_i32(&self) -> Option { + self.0.to_i32() + } + fn to_usize(&self) -> Option { + self.0.to_usize() + } + fn to_u8(&self) -> Option { + self.0.to_u8() + } + fn to_u16(&self) -> Option { + self.0.to_u16() + } + fn to_u32(&self) -> Option { + self.0.to_u32() + } + fn to_f32(&self) -> Option { + self.0.to_f32() + } + fn to_f64(&self) -> Option { + self.0.to_f64() + } +} + +/// An error indicating a parse error from a string for `NotNan`. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum ParseNotNanError { + /// A plain parse error from the underlying float type. + ParseFloatError(E), + /// The parsed float value resulted in a NaN. + IsNaN, +} + +#[cfg(feature = "std")] +impl Error for ParseNotNanError { + fn description(&self) -> &str { + "Error parsing a not-NaN floating point value" + } + + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + ParseNotNanError::ParseFloatError(e) => Some(e), + ParseNotNanError::IsNaN => None, + } + } +} + +impl fmt::Display for ParseNotNanError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ParseNotNanError::ParseFloatError(e) => write!(f, "Parse error: {}", e), + ParseNotNanError::IsNaN => write!(f, "NotNan parser encounter a NaN"), + } + } +} + +impl Num for NotNan { + type FromStrRadixErr = ParseNotNanError; + + fn from_str_radix(src: &str, radix: u32) -> Result { + T::from_str_radix(src, radix) + .map_err(ParseNotNanError::ParseFloatError) + .and_then(|n| NotNan::new(n).map_err(|_| ParseNotNanError::IsNaN)) + } +} + +impl Signed for NotNan { + #[inline] + fn abs(&self) -> Self { + NotNan(self.0.abs()) + } + + fn abs_sub(&self, other: &Self) -> Self { + NotNan::new(Signed::abs_sub(&self.0, &other.0)).expect("Subtraction resulted in NaN") + } + + #[inline] + fn signum(&self) -> Self { + NotNan(self.0.signum()) + } + #[inline] + fn is_positive(&self) -> bool { + self.0.is_positive() + } + #[inline] + fn is_negative(&self) -> bool { + self.0.is_negative() + } +} + +impl NumCast for NotNan { + fn from(n: F) -> Option { + T::from(n).and_then(|n| NotNan::new(n).ok()) + } +} + +macro_rules! impl_float_const_method { + ($wrapper:expr, $method:ident) => { + #[allow(non_snake_case)] + #[allow(clippy::redundant_closure_call)] + fn $method() -> Self { + $wrapper(T::$method()) + } + }; +} + +macro_rules! impl_float_const { + ($type:ident, $wrapper:expr) => { + impl FloatConst for $type { + impl_float_const_method!($wrapper, E); + impl_float_const_method!($wrapper, FRAC_1_PI); + impl_float_const_method!($wrapper, FRAC_1_SQRT_2); + impl_float_const_method!($wrapper, FRAC_2_PI); + impl_float_const_method!($wrapper, FRAC_2_SQRT_PI); + impl_float_const_method!($wrapper, FRAC_PI_2); + impl_float_const_method!($wrapper, FRAC_PI_3); + impl_float_const_method!($wrapper, FRAC_PI_4); + impl_float_const_method!($wrapper, FRAC_PI_6); + impl_float_const_method!($wrapper, FRAC_PI_8); + impl_float_const_method!($wrapper, LN_10); + impl_float_const_method!($wrapper, LN_2); + impl_float_const_method!($wrapper, LOG10_E); + impl_float_const_method!($wrapper, LOG2_E); + impl_float_const_method!($wrapper, PI); + impl_float_const_method!($wrapper, SQRT_2); + } + }; +} + +impl_float_const!(OrderedFloat, OrderedFloat); +// Float constants are not NaN. +impl_float_const!(NotNan, |x| unsafe { NotNan::new_unchecked(x) }); + +#[cfg(feature = "serde")] +mod impl_serde { + extern crate serde; + use self::serde::de::{Error, Unexpected}; + use self::serde::{Deserialize, Deserializer, Serialize, Serializer}; + use super::{NotNan, OrderedFloat}; + use core::f64; + #[cfg(not(feature = "std"))] + use num_traits::float::FloatCore as Float; + #[cfg(feature = "std")] + use num_traits::Float; + + #[cfg(test)] + extern crate serde_test; + #[cfg(test)] + use self::serde_test::{assert_de_tokens_error, assert_tokens, Token}; + + impl Serialize for OrderedFloat { + #[inline] + fn serialize(&self, s: S) -> Result { + self.0.serialize(s) + } + } + + impl<'de, T: Float + Deserialize<'de>> Deserialize<'de> for OrderedFloat { + #[inline] + fn deserialize>(d: D) -> Result { + T::deserialize(d).map(OrderedFloat) + } + } + + impl Serialize for NotNan { + #[inline] + fn serialize(&self, s: S) -> Result { + self.0.serialize(s) + } + } + + impl<'de, T: Float + Deserialize<'de>> Deserialize<'de> for NotNan { + fn deserialize>(d: D) -> Result { + let float = T::deserialize(d)?; + NotNan::new(float).map_err(|_| { + Error::invalid_value(Unexpected::Float(f64::NAN), &"float (but not NaN)") + }) + } + } + + #[test] + fn test_ordered_float() { + let float = OrderedFloat(1.0f64); + assert_tokens(&float, &[Token::F64(1.0)]); + } + + #[test] + fn test_not_nan() { + let float = NotNan(1.0f64); + assert_tokens(&float, &[Token::F64(1.0)]); + } + + #[test] + fn test_fail_on_nan() { + assert_de_tokens_error::>( + &[Token::F64(f64::NAN)], + "invalid value: floating point `NaN`, expected float (but not NaN)", + ); + } +} + +#[cfg(any(feature = "rkyv_16", feature = "rkyv_32", feature = "rkyv_64"))] +mod impl_rkyv { + use super::{NotNan, OrderedFloat}; + #[cfg(not(feature = "std"))] + use num_traits::float::FloatCore as Float; + #[cfg(feature = "std")] + use num_traits::Float; + #[cfg(test)] + use rkyv::{archived_root, ser::Serializer}; + use rkyv::{Archive, Deserialize, Fallible, Serialize}; + + #[cfg(test)] + type DefaultSerializer = rkyv::ser::serializers::CoreSerializer<16, 16>; + #[cfg(test)] + type DefaultDeserializer = rkyv::Infallible; + + impl Archive for OrderedFloat { + type Archived = OrderedFloat; + + type Resolver = T::Resolver; + + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + self.0.resolve(pos, resolver, out.cast()) + } + } + + impl, S: Fallible + ?Sized> Serialize for OrderedFloat { + fn serialize(&self, s: &mut S) -> Result { + self.0.serialize(s) + } + } + + impl, D: Fallible + ?Sized> Deserialize, D> + for OrderedFloat + { + fn deserialize(&self, d: &mut D) -> Result, D::Error> { + self.0.deserialize(d).map(OrderedFloat) + } + } + + impl Archive for NotNan { + type Archived = NotNan; + + type Resolver = T::Resolver; + + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + self.0.resolve(pos, resolver, out.cast()) + } + } + + impl, S: Fallible + ?Sized> Serialize for NotNan { + fn serialize(&self, s: &mut S) -> Result { + self.0.serialize(s) + } + } + + impl, D: Fallible + ?Sized> Deserialize, D> + for NotNan + { + fn deserialize(&self, d: &mut D) -> Result, D::Error> { + self.0.deserialize(d).map(NotNan) + } + } + + macro_rules! rkyv_eq_ord { + ($main:ident, $float:ty, $rend:ty) => { + impl PartialEq<$main<$float>> for $main<$rend> { + fn eq(&self, other: &$main<$float>) -> bool { + other.eq(&self.0.value()) + } + } + impl PartialEq<$main<$rend>> for $main<$float> { + fn eq(&self, other: &$main<$rend>) -> bool { + self.eq(&other.0.value()) + } + } + + impl PartialOrd<$main<$float>> for $main<$rend> { + fn partial_cmp(&self, other: &$main<$float>) -> Option { + self.0.value().partial_cmp(other) + } + } + + impl PartialOrd<$main<$rend>> for $main<$float> { + fn partial_cmp(&self, other: &$main<$rend>) -> Option { + other + .0 + .value() + .partial_cmp(self) + .map(core::cmp::Ordering::reverse) + } + } + }; + } + + rkyv_eq_ord! { OrderedFloat, f32, rkyv::rend::f32_le } + rkyv_eq_ord! { OrderedFloat, f32, rkyv::rend::f32_be } + rkyv_eq_ord! { OrderedFloat, f64, rkyv::rend::f64_le } + rkyv_eq_ord! { OrderedFloat, f64, rkyv::rend::f64_be } + rkyv_eq_ord! { NotNan, f32, rkyv::rend::f32_le } + rkyv_eq_ord! { NotNan, f32, rkyv::rend::f32_be } + rkyv_eq_ord! { NotNan, f64, rkyv::rend::f64_le } + rkyv_eq_ord! { NotNan, f64, rkyv::rend::f64_be } + + #[cfg(feature = "rkyv_ck")] + use super::FloatIsNan; + #[cfg(feature = "rkyv_ck")] + use core::convert::Infallible; + #[cfg(feature = "rkyv_ck")] + use rkyv::bytecheck::CheckBytes; + + #[cfg(feature = "rkyv_ck")] + impl> CheckBytes for OrderedFloat { + type Error = Infallible; + + #[inline] + unsafe fn check_bytes<'a>(value: *const Self, _: &mut C) -> Result<&'a Self, Self::Error> { + Ok(&*value) + } + } + + #[cfg(feature = "rkyv_ck")] + impl> CheckBytes for NotNan { + type Error = FloatIsNan; + + #[inline] + unsafe fn check_bytes<'a>(value: *const Self, _: &mut C) -> Result<&'a Self, Self::Error> { + Self::new(*(value as *const T)).map(|_| &*value) + } + } + + #[test] + fn test_ordered_float() { + let float = OrderedFloat(1.0f64); + let mut serializer = DefaultSerializer::default(); + serializer + .serialize_value(&float) + .expect("failed to archive value"); + let len = serializer.pos(); + let buffer = serializer.into_serializer().into_inner(); + + let archived_value = unsafe { archived_root::>(&buffer[0..len]) }; + assert_eq!(archived_value, &float); + let mut deserializer = DefaultDeserializer::default(); + let deser_float: OrderedFloat = archived_value.deserialize(&mut deserializer).unwrap(); + assert_eq!(deser_float, float); + } + + #[test] + fn test_not_nan() { + let float = NotNan(1.0f64); + let mut serializer = DefaultSerializer::default(); + serializer + .serialize_value(&float) + .expect("failed to archive value"); + let len = serializer.pos(); + let buffer = serializer.into_serializer().into_inner(); + + let archived_value = unsafe { archived_root::>(&buffer[0..len]) }; + assert_eq!(archived_value, &float); + let mut deserializer = DefaultDeserializer::default(); + let deser_float: NotNan = archived_value.deserialize(&mut deserializer).unwrap(); + assert_eq!(deser_float, float); + } +} + +#[cfg(feature = "speedy")] +mod impl_speedy { + use super::{NotNan, OrderedFloat}; + use num_traits::Float; + use speedy::{Context, Readable, Reader, Writable, Writer}; + + impl Writable for OrderedFloat + where + C: Context, + T: Writable, + { + fn write_to>(&self, writer: &mut W) -> Result<(), C::Error> { + self.0.write_to(writer) + } + + fn bytes_needed(&self) -> Result { + self.0.bytes_needed() + } + } + + impl Writable for NotNan + where + C: Context, + T: Writable, + { + fn write_to>(&self, writer: &mut W) -> Result<(), C::Error> { + self.0.write_to(writer) + } + + fn bytes_needed(&self) -> Result { + self.0.bytes_needed() + } + } + + impl<'a, T, C: Context> Readable<'a, C> for OrderedFloat + where + T: Readable<'a, C>, + { + fn read_from>(reader: &mut R) -> Result { + T::read_from(reader).map(OrderedFloat) + } + + fn minimum_bytes_needed() -> usize { + T::minimum_bytes_needed() + } + } + + impl<'a, T: Float, C: Context> Readable<'a, C> for NotNan + where + T: Readable<'a, C>, + { + fn read_from>(reader: &mut R) -> Result { + let value: T = reader.read_value()?; + Self::new(value).map_err(|error| { + speedy::Error::custom(std::format!("failed to read NotNan: {}", error)).into() + }) + } + + fn minimum_bytes_needed() -> usize { + T::minimum_bytes_needed() + } + } + + #[test] + fn test_ordered_float() { + let float = OrderedFloat(1.0f64); + let buffer = float.write_to_vec().unwrap(); + let deser_float: OrderedFloat = OrderedFloat::read_from_buffer(&buffer).unwrap(); + assert_eq!(deser_float, float); + } + + #[test] + fn test_not_nan() { + let float = NotNan(1.0f64); + let buffer = float.write_to_vec().unwrap(); + let deser_float: NotNan = NotNan::read_from_buffer(&buffer).unwrap(); + assert_eq!(deser_float, float); + } + + #[test] + fn test_not_nan_with_nan() { + let nan_buf = f64::nan().write_to_vec().unwrap(); + let nan_err: Result, _> = NotNan::read_from_buffer(&nan_buf); + assert!(nan_err.is_err()); + } +} + +#[cfg(all(feature = "std", feature = "schemars"))] +mod impl_schemars { + extern crate schemars; + use self::schemars::gen::SchemaGenerator; + use self::schemars::schema::{InstanceType, Schema, SchemaObject}; + use super::{NotNan, OrderedFloat}; + + macro_rules! primitive_float_impl { + ($type:ty, $schema_name:literal) => { + impl schemars::JsonSchema for $type { + fn is_referenceable() -> bool { + false + } + + fn schema_name() -> std::string::String { + std::string::String::from($schema_name) + } + + fn json_schema(_: &mut SchemaGenerator) -> Schema { + SchemaObject { + instance_type: Some(InstanceType::Number.into()), + format: Some(std::string::String::from($schema_name)), + ..Default::default() + } + .into() + } + } + }; + } + + primitive_float_impl!(OrderedFloat, "float"); + primitive_float_impl!(OrderedFloat, "double"); + primitive_float_impl!(NotNan, "float"); + primitive_float_impl!(NotNan, "double"); + + #[test] + fn schema_generation_does_not_panic_for_common_floats() { + { + let schema = schemars::gen::SchemaGenerator::default() + .into_root_schema_for::>(); + assert_eq!( + schema.schema.instance_type, + Some(schemars::schema::SingleOrVec::Single(std::boxed::Box::new( + schemars::schema::InstanceType::Number + ))) + ); + assert_eq!( + schema.schema.metadata.unwrap().title.unwrap(), + std::string::String::from("float") + ); + } + { + let schema = schemars::gen::SchemaGenerator::default() + .into_root_schema_for::>(); + assert_eq!( + schema.schema.instance_type, + Some(schemars::schema::SingleOrVec::Single(std::boxed::Box::new( + schemars::schema::InstanceType::Number + ))) + ); + assert_eq!( + schema.schema.metadata.unwrap().title.unwrap(), + std::string::String::from("double") + ); + } + { + let schema = + schemars::gen::SchemaGenerator::default().into_root_schema_for::>(); + assert_eq!( + schema.schema.instance_type, + Some(schemars::schema::SingleOrVec::Single(std::boxed::Box::new( + schemars::schema::InstanceType::Number + ))) + ); + assert_eq!( + schema.schema.metadata.unwrap().title.unwrap(), + std::string::String::from("float") + ); + } + { + let schema = + schemars::gen::SchemaGenerator::default().into_root_schema_for::>(); + assert_eq!( + schema.schema.instance_type, + Some(schemars::schema::SingleOrVec::Single(std::boxed::Box::new( + schemars::schema::InstanceType::Number + ))) + ); + assert_eq!( + schema.schema.metadata.unwrap().title.unwrap(), + std::string::String::from("double") + ); + } + } + #[test] + fn ordered_float_schema_match_primitive_schema() { + { + let of_schema = schemars::gen::SchemaGenerator::default() + .into_root_schema_for::>(); + let prim_schema = + schemars::gen::SchemaGenerator::default().into_root_schema_for::(); + assert_eq!(of_schema, prim_schema); + } + { + let of_schema = schemars::gen::SchemaGenerator::default() + .into_root_schema_for::>(); + let prim_schema = + schemars::gen::SchemaGenerator::default().into_root_schema_for::(); + assert_eq!(of_schema, prim_schema); + } + { + let of_schema = + schemars::gen::SchemaGenerator::default().into_root_schema_for::>(); + let prim_schema = + schemars::gen::SchemaGenerator::default().into_root_schema_for::(); + assert_eq!(of_schema, prim_schema); + } + { + let of_schema = + schemars::gen::SchemaGenerator::default().into_root_schema_for::>(); + let prim_schema = + schemars::gen::SchemaGenerator::default().into_root_schema_for::(); + assert_eq!(of_schema, prim_schema); + } + } +} + +#[cfg(feature = "rand")] +mod impl_rand { + use super::{NotNan, OrderedFloat}; + use rand::distributions::uniform::*; + use rand::distributions::{Distribution, Open01, OpenClosed01, Standard}; + use rand::Rng; + + macro_rules! impl_distribution { + ($dist:ident, $($f:ty),+) => { + $( + impl Distribution> for $dist { + fn sample(&self, rng: &mut R) -> NotNan<$f> { + // 'rand' never generates NaN values in the Standard, Open01, or + // OpenClosed01 distributions. Using 'new_unchecked' is therefore + // safe. + unsafe { NotNan::new_unchecked(self.sample(rng)) } + } + } + + impl Distribution> for $dist { + fn sample(&self, rng: &mut R) -> OrderedFloat<$f> { + OrderedFloat(self.sample(rng)) + } + } + )* + } + } + + impl_distribution! { Standard, f32, f64 } + impl_distribution! { Open01, f32, f64 } + impl_distribution! { OpenClosed01, f32, f64 } + + /// A sampler for a uniform distribution + #[derive(Clone, Copy, Debug, PartialEq)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] + pub struct UniformNotNan(UniformFloat); + impl SampleUniform for NotNan { + type Sampler = UniformNotNan; + } + impl SampleUniform for NotNan { + type Sampler = UniformNotNan; + } + + /// A sampler for a uniform distribution + #[derive(Clone, Copy, Debug, PartialEq)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] + pub struct UniformOrdered(UniformFloat); + impl SampleUniform for OrderedFloat { + type Sampler = UniformOrdered; + } + impl SampleUniform for OrderedFloat { + type Sampler = UniformOrdered; + } + + macro_rules! impl_uniform_sampler { + ($f:ty) => { + impl UniformSampler for UniformNotNan<$f> { + type X = NotNan<$f>; + fn new(low: B1, high: B2) -> Self + where + B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized, + { + UniformNotNan(UniformFloat::<$f>::new(low.borrow().0, high.borrow().0)) + } + fn new_inclusive(low: B1, high: B2) -> Self + where + B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized, + { + UniformSampler::new(low, high) + } + fn sample(&self, rng: &mut R) -> Self::X { + // UniformFloat.sample() will never return NaN. + unsafe { NotNan::new_unchecked(self.0.sample(rng)) } + } + } + + impl UniformSampler for UniformOrdered<$f> { + type X = OrderedFloat<$f>; + fn new(low: B1, high: B2) -> Self + where + B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized, + { + UniformOrdered(UniformFloat::<$f>::new(low.borrow().0, high.borrow().0)) + } + fn new_inclusive(low: B1, high: B2) -> Self + where + B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized, + { + UniformSampler::new(low, high) + } + fn sample(&self, rng: &mut R) -> Self::X { + OrderedFloat(self.0.sample(rng)) + } + } + }; + } + + impl_uniform_sampler! { f32 } + impl_uniform_sampler! { f64 } + + #[cfg(all(test, feature = "randtest"))] + mod tests { + use super::*; + + fn sample_fuzz() + where + Standard: Distribution>, + Open01: Distribution>, + OpenClosed01: Distribution>, + Standard: Distribution>, + Open01: Distribution>, + OpenClosed01: Distribution>, + T: crate::Float, + { + let mut rng = rand::thread_rng(); + let f1: NotNan = rng.sample(Standard); + let f2: NotNan = rng.sample(Open01); + let f3: NotNan = rng.sample(OpenClosed01); + let _: OrderedFloat = rng.sample(Standard); + let _: OrderedFloat = rng.sample(Open01); + let _: OrderedFloat = rng.sample(OpenClosed01); + assert!(!f1.into_inner().is_nan()); + assert!(!f2.into_inner().is_nan()); + assert!(!f3.into_inner().is_nan()); + } + + #[test] + fn sampling_f32_does_not_panic() { + sample_fuzz::(); + } + + #[test] + fn sampling_f64_does_not_panic() { + sample_fuzz::(); + } + + #[test] + #[should_panic] + fn uniform_sampling_panic_on_infinity_notnan() { + let (low, high) = ( + NotNan::new(0f64).unwrap(), + NotNan::new(core::f64::INFINITY).unwrap(), + ); + let uniform = Uniform::new(low, high); + let _ = uniform.sample(&mut rand::thread_rng()); + } + + #[test] + #[should_panic] + fn uniform_sampling_panic_on_infinity_ordered() { + let (low, high) = (OrderedFloat(0f64), OrderedFloat(core::f64::INFINITY)); + let uniform = Uniform::new(low, high); + let _ = uniform.sample(&mut rand::thread_rng()); + } + + #[test] + #[should_panic] + fn uniform_sampling_panic_on_nan_ordered() { + let (low, high) = (OrderedFloat(0f64), OrderedFloat(core::f64::NAN)); + let uniform = Uniform::new(low, high); + let _ = uniform.sample(&mut rand::thread_rng()); + } + } +} + +#[cfg(feature = "proptest")] +mod impl_proptest { + use super::{NotNan, OrderedFloat}; + use proptest::arbitrary::{Arbitrary, StrategyFor}; + use proptest::num::{f32, f64}; + use proptest::strategy::{FilterMap, Map, Strategy}; + use std::convert::TryFrom; + + macro_rules! impl_arbitrary { + ($($f:ident),+) => { + $( + impl Arbitrary for NotNan<$f> { + type Strategy = FilterMap, fn(_: $f) -> Option>>; + type Parameters = <$f as Arbitrary>::Parameters; + fn arbitrary_with(params: Self::Parameters) -> Self::Strategy { + <$f>::arbitrary_with(params) + .prop_filter_map("filter nan values", |f| NotNan::try_from(f).ok()) + } + } + + impl Arbitrary for OrderedFloat<$f> { + type Strategy = Map, fn(_: $f) -> OrderedFloat<$f>>; + type Parameters = <$f as Arbitrary>::Parameters; + fn arbitrary_with(params: Self::Parameters) -> Self::Strategy { + <$f>::arbitrary_with(params).prop_map(|f| OrderedFloat::from(f)) + } + } + )* + } + } + impl_arbitrary! { f32, f64 } +} + +#[cfg(feature = "arbitrary")] +mod impl_arbitrary { + use super::{FloatIsNan, NotNan, OrderedFloat}; + use arbitrary::{Arbitrary, Unstructured}; + use num_traits::FromPrimitive; + + macro_rules! impl_arbitrary { + ($($f:ident),+) => { + $( + impl<'a> Arbitrary<'a> for NotNan<$f> { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + let float: $f = u.arbitrary()?; + match NotNan::new(float) { + Ok(notnan_value) => Ok(notnan_value), + Err(FloatIsNan) => { + // If our arbitrary float input was a NaN (encoded by exponent = max + // value), then replace it with a finite float, reusing the mantissa + // bits. + // + // This means the output is not uniformly distributed among all + // possible float values, but Arbitrary makes no promise that that + // is true. + // + // An alternative implementation would be to return an + // `arbitrary::Error`, but that is not as useful since it forces the + // caller to retry with new random/fuzzed data; and the precendent of + // `arbitrary`'s built-in implementations is to prefer the approach of + // mangling the input bits to fit. + + let (mantissa, _exponent, sign) = + num_traits::Float::integer_decode(float); + let revised_float = <$f>::from_i64( + i64::from(sign) * mantissa as i64 + ).unwrap(); + + // If this unwrap() fails, then there is a bug in the above code. + Ok(NotNan::new(revised_float).unwrap()) + } + } + } + + fn size_hint(depth: usize) -> (usize, Option) { + <$f as Arbitrary>::size_hint(depth) + } + } + + impl<'a> Arbitrary<'a> for OrderedFloat<$f> { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + let float: $f = u.arbitrary()?; + Ok(OrderedFloat::from(float)) + } + + fn size_hint(depth: usize) -> (usize, Option) { + <$f as Arbitrary>::size_hint(depth) + } + } + )* + } + } + impl_arbitrary! { f32, f64 } +} + +#[cfg(feature = "bytemuck")] +mod impl_bytemuck { + use super::{Float, NotNan, OrderedFloat}; + use bytemuck::{AnyBitPattern, CheckedBitPattern, NoUninit, Pod, Zeroable}; + + unsafe impl Zeroable for OrderedFloat {} + + // The zero bit pattern is indeed not a NaN bit pattern. + unsafe impl Zeroable for NotNan {} + + unsafe impl Pod for OrderedFloat {} + + // `NotNan` can only implement `NoUninit` and not `Pod`, since not every bit pattern is + // valid (NaN bit patterns are invalid). `NoUninit` guarantees that we can read any bit pattern + // from the value, which is fine in this case. + unsafe impl NoUninit for NotNan {} + + unsafe impl CheckedBitPattern for NotNan { + type Bits = T; + + fn is_valid_bit_pattern(bits: &Self::Bits) -> bool { + !bits.is_nan() + } + } + + #[test] + fn test_not_nan_bit_pattern() { + use bytemuck::checked::{try_cast, CheckedCastError}; + + let nan = f64::NAN; + assert_eq!( + try_cast::>(nan), + Err(CheckedCastError::InvalidBitPattern), + ); + + let pi = core::f64::consts::PI; + assert!(try_cast::>(pi).is_ok()); + } +} diff --git a/vendor/ordered-float-3.9.2/tests/test.rs b/vendor/ordered-float-3.9.2/tests/test.rs new file mode 100644 index 0000000000000..ec7eeaab9c82b --- /dev/null +++ b/vendor/ordered-float-3.9.2/tests/test.rs @@ -0,0 +1,888 @@ +#![allow(clippy::float_cmp, clippy::eq_op, clippy::op_ref)] + +extern crate num_traits; +extern crate ordered_float; + +#[cfg(not(feature = "std"))] +pub use num_traits::float::FloatCore as Float; +pub use num_traits::{Bounded, FloatConst, FromPrimitive, Num, One, Signed, ToPrimitive, Zero}; +#[cfg(feature = "std")] +pub use num_traits::{Float, Pow}; +pub use ordered_float::*; + +pub use std::cmp::Ordering::*; +pub use std::convert::TryFrom; +pub use std::{f32, f64, panic}; + +pub use std::collections::hash_map::RandomState; +pub use std::collections::HashSet; +pub use std::hash::*; + +fn not_nan(x: T) -> NotNan { + NotNan::new(x).unwrap() +} + +#[test] +fn test_total_order() { + let numberline = [ + (-f32::INFINITY, 0), + (-1.0, 1), + (-0.0, 2), + (0.0, 2), + (1.0, 3), + (f32::INFINITY, 4), + (f32::NAN, 5), + (-f32::NAN, 5), + ]; + + for &(fi, i) in &numberline { + for &(fj, j) in &numberline { + assert_eq!(OrderedFloat(fi) < OrderedFloat(fj), i < j); + assert_eq!(OrderedFloat(fi) > OrderedFloat(fj), i > j); + assert_eq!(OrderedFloat(fi) <= OrderedFloat(fj), i <= j); + assert_eq!(OrderedFloat(fi) >= OrderedFloat(fj), i >= j); + assert_eq!(OrderedFloat(fi) == OrderedFloat(fj), i == j); + assert_eq!(OrderedFloat(fi) != OrderedFloat(fj), i != j); + assert_eq!(OrderedFloat(fi).cmp(&OrderedFloat(fj)), i.cmp(&j)); + } + } +} + +#[test] +fn ordered_f32_compare_regular_floats() { + assert_eq!(OrderedFloat(7.0f32).cmp(&OrderedFloat(7.0)), Equal); + assert_eq!(OrderedFloat(8.0f32).cmp(&OrderedFloat(7.0)), Greater); + assert_eq!(OrderedFloat(4.0f32).cmp(&OrderedFloat(7.0)), Less); +} + +#[test] +fn ordered_f32_compare_regular_floats_op() { + assert!(OrderedFloat(7.0f32) == OrderedFloat(7.0)); + assert!(OrderedFloat(7.0f32) <= OrderedFloat(7.0)); + assert!(OrderedFloat(7.0f32) >= OrderedFloat(7.0)); + assert!(OrderedFloat(8.0f32) > OrderedFloat(7.0)); + assert!(OrderedFloat(8.0f32) >= OrderedFloat(7.0)); + assert!(OrderedFloat(4.0f32) < OrderedFloat(7.0)); + assert!(OrderedFloat(4.0f32) <= OrderedFloat(7.0)); +} + +#[test] +fn ordered_f32_compare_nan() { + let f32_nan: f32 = Float::nan(); + assert_eq!( + OrderedFloat(f32_nan).cmp(&OrderedFloat(Float::nan())), + Equal + ); + assert_eq!( + OrderedFloat(f32_nan).cmp(&OrderedFloat(-100000.0f32)), + Greater + ); + assert_eq!( + OrderedFloat(-100.0f32).cmp(&OrderedFloat(Float::nan())), + Less + ); +} + +#[test] +fn ordered_f32_compare_nan_op() { + let f32_nan: OrderedFloat = OrderedFloat(Float::nan()); + assert!(f32_nan == f32_nan); + assert!(f32_nan <= f32_nan); + assert!(f32_nan >= f32_nan); + assert!(f32_nan > OrderedFloat(-100000.0f32)); + assert!(f32_nan >= OrderedFloat(-100000.0f32)); + assert!(OrderedFloat(-100.0f32) < f32_nan); + assert!(OrderedFloat(-100.0f32) <= f32_nan); + assert!(f32_nan > OrderedFloat(f32::infinity())); + assert!(f32_nan >= OrderedFloat(f32::infinity())); + assert!(f32_nan > OrderedFloat(f32::neg_infinity())); + assert!(f32_nan >= OrderedFloat(f32::neg_infinity())); +} + +#[test] +fn ordered_f64_compare_regular_floats() { + assert_eq!(OrderedFloat(7.0f64).cmp(&OrderedFloat(7.0)), Equal); + assert_eq!(OrderedFloat(8.0f64).cmp(&OrderedFloat(7.0)), Greater); + assert_eq!(OrderedFloat(4.0f64).cmp(&OrderedFloat(7.0)), Less); +} + +#[test] +fn not_nan32_zero() { + assert_eq!(NotNan::::zero(), 0.0f32); + assert!(NotNan::::zero().is_zero()); +} + +#[test] +fn not_nan32_one() { + assert_eq!(NotNan::::one(), 1.0f32) +} + +#[test] +fn not_nan32_bounded() { + assert_eq!(NotNan::::min_value(), ::min_value()); + assert_eq!(NotNan::::max_value(), ::max_value()); +} + +#[test] +fn not_nan32_from_primitive() { + assert_eq!(NotNan::::from_i8(42i8), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_u8(42u8), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_i16(42i16), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_u16(42u16), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_i32(42i32), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_u32(42u32), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_i64(42i64), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_u64(42u64), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_isize(42isize), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_usize(42usize), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_f32(42f32), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_f32(42f32), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_f64(42f64), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_f64(42f64), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_f32(Float::nan()), None); + assert_eq!(NotNan::::from_f64(Float::nan()), None); +} + +#[test] +fn not_nan32_to_primitive() { + let x = not_nan(42.0f32); + assert_eq!(x.to_u8(), Some(42u8)); + assert_eq!(x.to_i8(), Some(42i8)); + assert_eq!(x.to_u16(), Some(42u16)); + assert_eq!(x.to_i16(), Some(42i16)); + assert_eq!(x.to_u32(), Some(42u32)); + assert_eq!(x.to_i32(), Some(42i32)); + assert_eq!(x.to_u64(), Some(42u64)); + assert_eq!(x.to_i64(), Some(42i64)); + assert_eq!(x.to_usize(), Some(42usize)); + assert_eq!(x.to_isize(), Some(42isize)); + assert_eq!(x.to_f32(), Some(42f32)); + assert_eq!(x.to_f32(), Some(42f32)); + assert_eq!(x.to_f64(), Some(42f64)); + assert_eq!(x.to_f64(), Some(42f64)); +} + +#[test] +fn not_nan32_num() { + assert_eq!(NotNan::::from_str_radix("42.0", 10).unwrap(), 42.0f32); + assert!(NotNan::::from_str_radix("NaN", 10).is_err()); +} + +#[test] +fn not_nan32_signed() { + assert_eq!(not_nan(42f32).abs(), 42f32); + assert_eq!(not_nan(-42f32).abs(), 42f32); + + assert_eq!(not_nan(50f32).abs_sub(¬_nan(8f32)), 42f32); + assert_eq!(not_nan(8f32).abs_sub(¬_nan(50f32)), 0f32); +} + +#[test] +fn not_nan32_num_cast() { + assert_eq!( + as num_traits::NumCast>::from(42).unwrap(), + 42f32 + ); + assert_eq!( as num_traits::NumCast>::from(f32::nan()), None); +} + +#[test] +fn ordered_f64_compare_nan() { + let f64_nan: f64 = Float::nan(); + assert_eq!( + OrderedFloat(f64_nan).cmp(&OrderedFloat(Float::nan())), + Equal + ); + assert_eq!( + OrderedFloat(f64_nan).cmp(&OrderedFloat(-100000.0f64)), + Greater + ); + assert_eq!( + OrderedFloat(-100.0f64).cmp(&OrderedFloat(Float::nan())), + Less + ); +} + +#[test] +fn ordered_f64_compare_regular_floats_op() { + assert!(OrderedFloat(7.0) == OrderedFloat(7.0)); + assert!(OrderedFloat(7.0) <= OrderedFloat(7.0)); + assert!(OrderedFloat(7.0) >= OrderedFloat(7.0)); + assert!(OrderedFloat(8.0) > OrderedFloat(7.0)); + assert!(OrderedFloat(8.0) >= OrderedFloat(7.0)); + assert!(OrderedFloat(4.0) < OrderedFloat(7.0)); + assert!(OrderedFloat(4.0) <= OrderedFloat(7.0)); +} + +#[test] +fn ordered_f64_compare_nan_op() { + let f64_nan: OrderedFloat = OrderedFloat(Float::nan()); + assert!(f64_nan == f64_nan); + assert!(f64_nan <= f64_nan); + assert!(f64_nan >= f64_nan); + assert!(f64_nan > OrderedFloat(-100000.0)); + assert!(f64_nan >= OrderedFloat(-100000.0)); + assert!(OrderedFloat(-100.0) < f64_nan); + assert!(OrderedFloat(-100.0) <= f64_nan); + assert!(f64_nan > OrderedFloat(f64::infinity())); + assert!(f64_nan >= OrderedFloat(f64::infinity())); + assert!(f64_nan > OrderedFloat(f64::neg_infinity())); + assert!(f64_nan >= OrderedFloat(f64::neg_infinity())); +} + +#[test] +fn not_nan32_compare_regular_floats() { + assert_eq!(not_nan(7.0f32).cmp(¬_nan(7.0)), Equal); + assert_eq!(not_nan(8.0f32).cmp(¬_nan(7.0)), Greater); + assert_eq!(not_nan(4.0f32).cmp(¬_nan(7.0)), Less); +} + +#[test] +fn not_nan32_fail_when_constructing_with_nan() { + let f32_nan: f32 = Float::nan(); + assert!(NotNan::new(f32_nan).is_err()); +} + +#[test] +fn not_nan32_calculate_correctly() { + assert_eq!(*(not_nan(5.0f32) + not_nan(4.0f32)), 5.0f32 + 4.0f32); + assert_eq!(*(not_nan(5.0f32) + 4.0f32), 5.0f32 + 4.0f32); + assert_eq!(*(not_nan(5.0f32) - not_nan(4.0f32)), 5.0f32 - 4.0f32); + assert_eq!(*(not_nan(5.0f32) - 4.0f32), 5.0f32 - 4.0f32); + assert_eq!(*(not_nan(5.0f32) * not_nan(4.0f32)), 5.0f32 * 4.0f32); + assert_eq!(*(not_nan(5.0f32) * 4.0f32), 5.0f32 * 4.0f32); + assert_eq!(*(not_nan(8.0f32) / not_nan(4.0f32)), 8.0f32 / 4.0f32); + assert_eq!(*(not_nan(8.0f32) / 4.0f32), 8.0f32 / 4.0f32); + assert_eq!(*(not_nan(8.0f32) % not_nan(4.0f32)), 8.0f32 % 4.0f32); + assert_eq!(*(not_nan(8.0f32) % 4.0f32), 8.0f32 % 4.0f32); + assert_eq!(*(-not_nan(1.0f32)), -1.0f32); + + assert!(panic::catch_unwind(|| not_nan(0.0f32) + f32::NAN).is_err()); + assert!(panic::catch_unwind(|| not_nan(0.0f32) - f32::NAN).is_err()); + assert!(panic::catch_unwind(|| not_nan(0.0f32) * f32::NAN).is_err()); + assert!(panic::catch_unwind(|| not_nan(0.0f32) / f32::NAN).is_err()); + assert!(panic::catch_unwind(|| not_nan(0.0f32) % f32::NAN).is_err()); + + let mut number = not_nan(5.0f32); + number += not_nan(4.0f32); + assert_eq!(*number, 9.0f32); + number -= not_nan(4.0f32); + assert_eq!(*number, 5.0f32); + number *= not_nan(4.0f32); + assert_eq!(*number, 20.0f32); + number /= not_nan(4.0f32); + assert_eq!(*number, 5.0f32); + number %= not_nan(4.0f32); + assert_eq!(*number, 1.0f32); + + number = not_nan(5.0f32); + number += 4.0f32; + assert_eq!(*number, 9.0f32); + number -= 4.0f32; + assert_eq!(*number, 5.0f32); + number *= 4.0f32; + assert_eq!(*number, 20.0f32); + number /= 4.0f32; + assert_eq!(*number, 5.0f32); + number %= 4.0f32; + assert_eq!(*number, 1.0f32); + + assert!(panic::catch_unwind(|| { + let mut tmp = not_nan(0.0f32); + tmp += f32::NAN; + }) + .is_err()); + assert!(panic::catch_unwind(|| { + let mut tmp = not_nan(0.0f32); + tmp -= f32::NAN; + }) + .is_err()); + assert!(panic::catch_unwind(|| { + let mut tmp = not_nan(0.0f32); + tmp *= f32::NAN; + }) + .is_err()); + assert!(panic::catch_unwind(|| { + let mut tmp = not_nan(0.0f32); + tmp /= f32::NAN; + }) + .is_err()); + assert!(panic::catch_unwind(|| { + let mut tmp = not_nan(0.0f32); + tmp %= f32::NAN; + }) + .is_err()); +} + +#[test] +fn not_nan64_compare_regular_floats() { + assert_eq!(not_nan(7.0f64).cmp(¬_nan(7.0)), Equal); + assert_eq!(not_nan(8.0f64).cmp(¬_nan(7.0)), Greater); + assert_eq!(not_nan(4.0f64).cmp(¬_nan(7.0)), Less); +} + +#[test] +fn not_nan64_fail_when_constructing_with_nan() { + let f64_nan: f64 = Float::nan(); + assert!(NotNan::new(f64_nan).is_err()); +} + +#[test] +fn not_nan64_calculate_correctly() { + assert_eq!(*(not_nan(5.0f64) + not_nan(4.0f64)), 5.0f64 + 4.0f64); + assert_eq!(*(not_nan(5.0f64) + 4.0f64), 5.0f64 + 4.0f64); + assert_eq!(*(not_nan(5.0f64) - not_nan(4.0f64)), 5.0f64 - 4.0f64); + assert_eq!(*(not_nan(5.0f64) - 4.0f64), 5.0f64 - 4.0f64); + assert_eq!(*(not_nan(5.0f64) * not_nan(4.0f64)), 5.0f64 * 4.0f64); + assert_eq!(*(not_nan(5.0f64) * 4.0f64), 5.0f64 * 4.0f64); + assert_eq!(*(not_nan(8.0f64) / not_nan(4.0f64)), 8.0f64 / 4.0f64); + assert_eq!(*(not_nan(8.0f64) / 4.0f64), 8.0f64 / 4.0f64); + assert_eq!(*(not_nan(8.0f64) % not_nan(4.0f64)), 8.0f64 % 4.0f64); + assert_eq!(*(not_nan(8.0f64) % 4.0f64), 8.0f64 % 4.0f64); + assert_eq!(*(-not_nan(1.0f64)), -1.0f64); + + assert!(panic::catch_unwind(|| not_nan(0.0f64) + f64::NAN).is_err()); + assert!(panic::catch_unwind(|| not_nan(0.0f64) - f64::NAN).is_err()); + assert!(panic::catch_unwind(|| not_nan(0.0f64) * f64::NAN).is_err()); + assert!(panic::catch_unwind(|| not_nan(0.0f64) / f64::NAN).is_err()); + assert!(panic::catch_unwind(|| not_nan(0.0f64) % f64::NAN).is_err()); + + let mut number = not_nan(5.0f64); + number += not_nan(4.0f64); + assert_eq!(*number, 9.0f64); + number -= not_nan(4.0f64); + assert_eq!(*number, 5.0f64); + number *= not_nan(4.0f64); + assert_eq!(*number, 20.0f64); + number /= not_nan(4.0f64); + assert_eq!(*number, 5.0f64); + number %= not_nan(4.0f64); + assert_eq!(*number, 1.0f64); + + number = not_nan(5.0f64); + number += 4.0f64; + assert_eq!(*number, 9.0f64); + number -= 4.0f64; + assert_eq!(*number, 5.0f64); + number *= 4.0f64; + assert_eq!(*number, 20.0f64); + number /= 4.0f64; + assert_eq!(*number, 5.0f64); + number %= 4.0f64; + assert_eq!(*number, 1.0f64); + + assert!(panic::catch_unwind(|| { + let mut tmp = not_nan(0.0f64); + tmp += f64::NAN; + }) + .is_err()); + assert!(panic::catch_unwind(|| { + let mut tmp = not_nan(0.0f64); + tmp -= f64::NAN; + }) + .is_err()); + assert!(panic::catch_unwind(|| { + let mut tmp = not_nan(0.0f64); + tmp *= f64::NAN; + }) + .is_err()); + assert!(panic::catch_unwind(|| { + let mut tmp = not_nan(0.0f64); + tmp /= f64::NAN; + }) + .is_err()); + assert!(panic::catch_unwind(|| { + let mut tmp = not_nan(0.0f64); + tmp %= f64::NAN; + }) + .is_err()); +} + +#[test] +fn not_nan64_zero() { + assert_eq!(NotNan::::zero(), not_nan(0.0f64)); + assert!(NotNan::::zero().is_zero()); +} + +#[test] +fn not_nan64_one() { + assert_eq!(NotNan::::one(), not_nan(1.0f64)) +} + +#[test] +fn not_nan64_bounded() { + assert_eq!(NotNan::::min_value(), ::min_value()); + assert_eq!(NotNan::::max_value(), ::max_value()); +} + +#[test] +fn not_nan64_from_primitive() { + assert_eq!(NotNan::::from_i8(42i8), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_u8(42u8), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_i16(42i16), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_u16(42u16), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_i32(42i32), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_u32(42u32), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_i64(42i64), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_u64(42u64), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_isize(42isize), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_usize(42usize), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_f64(42f64), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_f64(42f64), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_f64(42f64), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_f64(42f64), Some(not_nan(42.0))); + assert_eq!(NotNan::::from_f64(Float::nan()), None); + assert_eq!(NotNan::::from_f64(Float::nan()), None); +} + +#[test] +fn not_nan64_to_primitive() { + let x = not_nan(42.0f64); + assert_eq!(x.to_u8(), Some(42u8)); + assert_eq!(x.to_i8(), Some(42i8)); + assert_eq!(x.to_u16(), Some(42u16)); + assert_eq!(x.to_i16(), Some(42i16)); + assert_eq!(x.to_u32(), Some(42u32)); + assert_eq!(x.to_i32(), Some(42i32)); + assert_eq!(x.to_u64(), Some(42u64)); + assert_eq!(x.to_i64(), Some(42i64)); + assert_eq!(x.to_usize(), Some(42usize)); + assert_eq!(x.to_isize(), Some(42isize)); + assert_eq!(x.to_f64(), Some(42f64)); + assert_eq!(x.to_f64(), Some(42f64)); + assert_eq!(x.to_f64(), Some(42f64)); + assert_eq!(x.to_f64(), Some(42f64)); +} + +#[test] +fn not_nan64_num() { + assert_eq!( + NotNan::::from_str_radix("42.0", 10).unwrap(), + not_nan(42.0f64) + ); + assert!(NotNan::::from_str_radix("NaN", 10).is_err()); +} + +#[test] +fn not_nan64_signed() { + assert_eq!(not_nan(42f64).abs(), not_nan(42f64)); + assert_eq!(not_nan(-42f64).abs(), not_nan(42f64)); + + assert_eq!(not_nan(50f64).abs_sub(¬_nan(8f64)), not_nan(42f64)); + assert_eq!(not_nan(8f64).abs_sub(¬_nan(50f64)), not_nan(0f64)); +} + +#[test] +fn not_nan64_num_cast() { + assert_eq!( + as num_traits::NumCast>::from(42), + Some(not_nan(42f64)) + ); + assert_eq!( as num_traits::NumCast>::from(f64::nan()), None); +} + +#[test] +fn hash_zero_and_neg_zero_to_the_same_hc_ordered_float64() { + let state = RandomState::new(); + let mut h1 = state.build_hasher(); + let mut h2 = state.build_hasher(); + OrderedFloat::from(0f64).hash(&mut h1); + OrderedFloat::from(-0f64).hash(&mut h2); + assert_eq!(h1.finish(), h2.finish()); +} + +#[test] +fn hash_zero_and_neg_zero_to_the_same_hc_not_nan32() { + let state = RandomState::new(); + let mut h1 = state.build_hasher(); + let mut h2 = state.build_hasher(); + NotNan::try_from(0f32).unwrap().hash(&mut h1); + NotNan::try_from(-0f32).unwrap().hash(&mut h2); + assert_eq!(h1.finish(), h2.finish()); +} + +#[test] +fn hash_different_nans_to_the_same_hc() { + let state = RandomState::new(); + let mut h1 = state.build_hasher(); + let mut h2 = state.build_hasher(); + OrderedFloat::from(f64::nan()).hash(&mut h1); + OrderedFloat::from(-f64::nan()).hash(&mut h2); + assert_eq!(h1.finish(), h2.finish()); +} + +#[test] +fn hash_inf_and_neg_inf_to_different_hcs() { + let state = RandomState::new(); + let mut h1 = state.build_hasher(); + let mut h2 = state.build_hasher(); + OrderedFloat::from(f64::INFINITY).hash(&mut h1); + OrderedFloat::from(f64::NEG_INFINITY).hash(&mut h2); + assert!(h1.finish() != h2.finish()); +} + +#[test] +fn hash_is_good_for_whole_numbers() { + let state = RandomState::new(); + let limit = 10000; + + let mut set = ::std::collections::HashSet::with_capacity(limit); + for i in 0..limit { + let mut h = state.build_hasher(); + OrderedFloat::from(i as f64).hash(&mut h); + set.insert(h.finish()); + } + + // This allows 100 collisions, which is far too + // many, but should guard against transient issues + // that will result from using RandomState + let pct_unique = set.len() as f64 / limit as f64; + assert!(0.99f64 < pct_unique, "percent-unique={}", pct_unique); +} + +#[test] +fn hash_is_good_for_fractional_numbers() { + let state = RandomState::new(); + let limit = 10000; + + let mut set = ::std::collections::HashSet::with_capacity(limit); + for i in 0..limit { + let mut h = state.build_hasher(); + OrderedFloat::from(i as f64 * (1f64 / limit as f64)).hash(&mut h); + set.insert(h.finish()); + } + + // This allows 100 collisions, which is far too + // many, but should guard against transient issues + // that will result from using RandomState + let pct_unique = set.len() as f64 / limit as f64; + assert!(0.99f64 < pct_unique, "percent-unique={}", pct_unique); +} + +#[test] +#[should_panic] +fn test_add_fails_on_nan() { + let a = not_nan(std::f32::INFINITY); + let b = not_nan(std::f32::NEG_INFINITY); + let _c = a + b; +} + +#[test] +#[should_panic] +fn test_add_fails_on_nan_ref() { + let a = not_nan(std::f32::INFINITY); + let b = not_nan(std::f32::NEG_INFINITY); + let _c = a + &b; +} + +#[test] +#[should_panic] +fn test_add_fails_on_nan_ref_ref() { + let a = not_nan(std::f32::INFINITY); + let b = not_nan(std::f32::NEG_INFINITY); + let _c = &a + &b; +} + +#[test] +#[should_panic] +fn test_add_fails_on_nan_t_ref() { + let a = not_nan(std::f32::INFINITY); + let b = std::f32::NEG_INFINITY; + let _c = a + &b; +} + +#[test] +#[should_panic] +fn test_add_fails_on_nan_ref_t_ref() { + let a = not_nan(std::f32::INFINITY); + let b = std::f32::NEG_INFINITY; + let _c = &a + &b; +} + +#[test] +#[should_panic] +fn test_add_fails_on_nan_ref_t() { + let a = not_nan(std::f32::INFINITY); + let b = std::f32::NEG_INFINITY; + let _c = &a + b; +} + +#[test] +#[should_panic] +fn test_add_assign_fails_on_nan_ref() { + let mut a = not_nan(std::f32::INFINITY); + let b = not_nan(std::f32::NEG_INFINITY); + a += &b; +} + +#[test] +#[should_panic] +fn test_add_assign_fails_on_nan_t_ref() { + let mut a = not_nan(std::f32::INFINITY); + let b = std::f32::NEG_INFINITY; + a += &b; +} + +#[test] +#[should_panic] +fn test_add_assign_fails_on_nan_t() { + let mut a = not_nan(std::f32::INFINITY); + let b = std::f32::NEG_INFINITY; + a += b; +} + +#[test] +fn add() { + assert_eq!(not_nan(0.0) + not_nan(0.0), 0.0); + assert_eq!(not_nan(0.0) + ¬_nan(0.0), 0.0); + assert_eq!(¬_nan(0.0) + not_nan(0.0), 0.0); + assert_eq!(¬_nan(0.0) + ¬_nan(0.0), 0.0); + assert_eq!(not_nan(0.0) + 0.0, 0.0); + assert_eq!(not_nan(0.0) + &0.0, 0.0); + assert_eq!(¬_nan(0.0) + 0.0, 0.0); + assert_eq!(¬_nan(0.0) + &0.0, 0.0); + + assert_eq!(OrderedFloat(0.0) + OrderedFloat(0.0), 0.0); + assert_eq!(OrderedFloat(0.0) + &OrderedFloat(0.0), 0.0); + assert_eq!(&OrderedFloat(0.0) + OrderedFloat(0.0), 0.0); + assert_eq!(OrderedFloat(0.0) + 0.0, 0.0); + assert_eq!(OrderedFloat(0.0) + &0.0, 0.0); + assert_eq!(&OrderedFloat(0.0) + 0.0, 0.0); + assert_eq!(&OrderedFloat(0.0) + &0.0, 0.0); +} + +#[test] +fn ordered_f32_neg() { + assert_eq!(OrderedFloat(-7.0f32), -OrderedFloat(7.0f32)); +} + +#[test] +fn ordered_f64_neg() { + assert_eq!(OrderedFloat(-7.0f64), -OrderedFloat(7.0f64)); +} + +#[test] +#[should_panic] +fn test_sum_fails_on_nan() { + let a = not_nan(std::f32::INFINITY); + let b = not_nan(std::f32::NEG_INFINITY); + let _c: NotNan<_> = [a, b].iter().sum(); +} + +#[test] +#[should_panic] +fn test_product_fails_on_nan() { + let a = not_nan(std::f32::INFINITY); + let b = not_nan(0f32); + let _c: NotNan<_> = [a, b].iter().product(); +} + +#[test] +fn not_nan64_sum_product() { + let a = not_nan(2138.1237); + let b = not_nan(132f64); + let c = not_nan(5.1); + + assert_eq!( + std::iter::empty::>().sum::>(), + NotNan::new(0f64).unwrap() + ); + assert_eq!([a].iter().sum::>(), a); + assert_eq!([a, b].iter().sum::>(), a + b); + assert_eq!([a, b, c].iter().sum::>(), a + b + c); + + assert_eq!( + std::iter::empty::>().product::>(), + NotNan::new(1f64).unwrap() + ); + assert_eq!([a].iter().product::>(), a); + assert_eq!([a, b].iter().product::>(), a * b); + assert_eq!([a, b, c].iter().product::>(), a * b * c); +} + +#[test] +fn not_nan_usage_in_const_context() { + const A: NotNan = unsafe { NotNan::new_unchecked(111f32) }; + assert_eq!(A, NotNan::new(111f32).unwrap()); +} + +#[test] +fn not_nan_panic_safety() { + let catch_op = |mut num, op: fn(&mut NotNan<_>)| { + let mut num_ref = panic::AssertUnwindSafe(&mut num); + let _ = panic::catch_unwind(move || op(&mut num_ref)); + num + }; + + assert!(!catch_op(not_nan(f32::INFINITY), |a| *a += f32::NEG_INFINITY).is_nan()); + assert!(!catch_op(not_nan(f32::INFINITY), |a| *a -= f32::INFINITY).is_nan()); + assert!(!catch_op(not_nan(0.0), |a| *a *= f32::INFINITY).is_nan()); + assert!(!catch_op(not_nan(0.0), |a| *a /= 0.0).is_nan()); + assert!(!catch_op(not_nan(0.0), |a| *a %= 0.0).is_nan()); +} + +#[test] +fn from_ref() { + let f = 1.0f32; + let o: &OrderedFloat = (&f).into(); + assert_eq!(*o, 1.0f32); + + let mut f = 1.0f64; + let o: &OrderedFloat = (&f).into(); + assert_eq!(*o, 1.0f64); + + let o: &mut OrderedFloat = (&mut f).into(); + assert_eq!(*o, 1.0f64); + *o = OrderedFloat(2.0); + assert_eq!(*o, 2.0f64); + assert_eq!(f, 2.0f64); +} + +macro_rules! test_float_const_method { + ($type:ident < $inner:ident >, $method:ident) => { + assert_eq!($type::<$inner>::$method().into_inner(), $inner::$method()) + }; +} + +macro_rules! test_float_const_methods { + ($type:ident < $inner:ident >) => { + test_float_const_method!($type<$inner>, E); + test_float_const_method!($type<$inner>, FRAC_1_PI); + test_float_const_method!($type<$inner>, FRAC_1_SQRT_2); + test_float_const_method!($type<$inner>, FRAC_2_PI); + test_float_const_method!($type<$inner>, FRAC_2_SQRT_PI); + test_float_const_method!($type<$inner>, FRAC_PI_2); + test_float_const_method!($type<$inner>, FRAC_PI_3); + test_float_const_method!($type<$inner>, FRAC_PI_4); + test_float_const_method!($type<$inner>, FRAC_PI_6); + test_float_const_method!($type<$inner>, FRAC_PI_8); + test_float_const_method!($type<$inner>, LN_10); + test_float_const_method!($type<$inner>, LN_2); + test_float_const_method!($type<$inner>, LOG10_E); + test_float_const_method!($type<$inner>, LOG2_E); + test_float_const_method!($type<$inner>, PI); + test_float_const_method!($type<$inner>, SQRT_2); + }; +} + +#[test] +fn float_consts_equal_inner() { + test_float_const_methods!(OrderedFloat); + test_float_const_methods!(OrderedFloat); + test_float_const_methods!(NotNan); + test_float_const_methods!(NotNan); +} + +#[cfg(feature = "std")] +macro_rules! test_pow_ord { + ($type:ident < $inner:ident >) => { + assert_eq!($type::<$inner>::from(3.0).pow(2i8), OrderedFloat(9.0)); + assert_eq!($type::<$inner>::from(3.0).pow(2i16), OrderedFloat(9.0)); + assert_eq!($type::<$inner>::from(3.0).pow(2i32), OrderedFloat(9.0)); + assert_eq!($type::<$inner>::from(3.0).pow(2u8), OrderedFloat(9.0)); + assert_eq!($type::<$inner>::from(3.0).pow(2u16), OrderedFloat(9.0)); + assert_eq!($type::<$inner>::from(3.0).pow(2f32), OrderedFloat(9.0)); + }; +} + +#[cfg(feature = "std")] +macro_rules! test_pow_nn { + ($type:ident < $inner:ident >) => { + assert_eq!( + $type::<$inner>::new(3.0).unwrap().pow(2i8), + NotNan::new(9.0).unwrap() + ); + assert_eq!( + $type::<$inner>::new(3.0).unwrap().pow(2u8), + NotNan::new(9.0).unwrap() + ); + assert_eq!( + $type::<$inner>::new(3.0).unwrap().pow(2i16), + NotNan::new(9.0).unwrap() + ); + assert_eq!( + $type::<$inner>::new(3.0).unwrap().pow(2u16), + NotNan::new(9.0).unwrap() + ); + assert_eq!( + $type::<$inner>::new(3.0).unwrap().pow(2i32), + NotNan::new(9.0).unwrap() + ); + assert_eq!( + $type::<$inner>::new(3.0).unwrap().pow(2f32), + NotNan::new(9.0).unwrap() + ); + }; +} + +#[cfg(feature = "std")] +#[test] +fn test_pow_works() { + assert_eq!(OrderedFloat(3.0).pow(OrderedFloat(2.0)), OrderedFloat(9.0)); + test_pow_ord!(OrderedFloat); + test_pow_ord!(OrderedFloat); + assert_eq!( + NotNan::new(3.0).unwrap().pow(NotNan::new(2.0).unwrap()), + NotNan::new(9.0).unwrap() + ); + test_pow_nn!(NotNan); + test_pow_nn!(NotNan); + // Only f64 have Pow impl by default, so checking those seperate from macro + assert_eq!(OrderedFloat::::from(3.0).pow(2f64), OrderedFloat(9.0)); + assert_eq!( + NotNan::::new(3.0).unwrap().pow(2f64), + NotNan::new(9.0).unwrap() + ); +} + +#[cfg(feature = "std")] +#[test] +#[should_panic] +fn test_pow_fails_on_nan() { + let a = not_nan(-1.0); + let b = f32::NAN; + a.pow(b); +} + +#[cfg(feature = "arbitrary")] +mod arbitrary_test { + use super::{NotNan, OrderedFloat}; + use arbitrary::{Arbitrary, Unstructured}; + + #[test] + fn exhaustive() { + // Exhaustively search all patterns of sign and exponent bits plus a few mantissa bits. + for high_bytes in 0..=u16::MAX { + let [h1, h2] = high_bytes.to_be_bytes(); + + // Each of these should not + // * panic, + // * return an error, or + // * need more bytes than given. + let n32: NotNan = Unstructured::new(&[h1, h2, h1, h2]) + .arbitrary() + .expect("NotNan failure"); + let n64: NotNan = Unstructured::new(&[h1, h2, h1, h2, h1, h2, h1, h2]) + .arbitrary() + .expect("NotNan failure"); + let _: OrderedFloat = Unstructured::new(&[h1, h2, h1, h2]) + .arbitrary() + .expect("OrderedFloat failure"); + let _: OrderedFloat = Unstructured::new(&[h1, h2, h1, h2, h1, h2, h1, h2]) + .arbitrary() + .expect("OrderedFloat failure"); + + // Check for violation of NotNan's property of never containing a NaN. + assert!(!n32.into_inner().is_nan()); + assert!(!n64.into_inner().is_nan()); + } + } + + #[test] + fn size_hints() { + assert_eq!(NotNan::::size_hint(0), (4, Some(4))); + assert_eq!(NotNan::::size_hint(0), (8, Some(8))); + assert_eq!(OrderedFloat::::size_hint(0), (4, Some(4))); + assert_eq!(OrderedFloat::::size_hint(0), (8, Some(8))); + } +} diff --git a/vendor/parse-zoneinfo/CHANGELOG.md b/vendor/parse-zoneinfo/CHANGELOG.md new file mode 100644 index 0000000000000..115a275bc1289 --- /dev/null +++ b/vendor/parse-zoneinfo/CHANGELOG.md @@ -0,0 +1,10 @@ +Changes to parse-zoneinfo +========================= + +# 0.3.0 + +- Support overflowing month behavior for >= and <= day in month + +# 0.2.1 + +- Build faster by relying on fewer regex features (PR #6 by @bluetech) diff --git a/vendor/pin-project-lite/tests/lint.rs b/vendor/pin-project-lite/tests/lint.rs new file mode 100644 index 0000000000000..94f72fddfff6a --- /dev/null +++ b/vendor/pin-project-lite/tests/lint.rs @@ -0,0 +1,281 @@ +// Check interoperability with rustc and clippy lints. + +#![forbid(unsafe_code)] +// for old compilers +#![allow(unknown_lints)] +#![warn(nonstandard_style, rust_2018_idioms, unused)] +// Note: This does not guarantee compatibility with forbidding these lints in the future. +// If rustc adds a new lint, we may not be able to keep this. +#![forbid(future_incompatible, rust_2018_compatibility, rust_2021_compatibility)] +// lints forbidden as a part of future_incompatible, rust_2018_compatibility, and rust_2021_compatibility are not included in the list below. +// elided_lifetimes_in_paths, explicit_outlives_requirements, unused_extern_crates: as a part of rust_2018_idioms +// unsafe_op_in_unsafe_fn: requires Rust 1.52. and, we don't generate unsafe fn. +// non_exhaustive_omitted_patterns, multiple_supertrait_upcastable: unstable +// unstable_features: no way to generate #![feature(..)] by macros, expect for unstable inner attribute. and this lint is deprecated: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#unstable-features +// unused_crate_dependencies, must_not_suspend: unrelated +// unsafe_code: checked in forbid_unsafe module +#![warn( + box_pointers, + deprecated_in_future, + fuzzy_provenance_casts, + invalid_reference_casting, + let_underscore_drop, + lossy_provenance_casts, + macro_use_extern_crate, + meta_variable_misuse, + missing_abi, + missing_copy_implementations, + missing_debug_implementations, + missing_docs, + non_ascii_idents, + noop_method_call, + private_bounds, + private_interfaces, + single_use_lifetimes, + trivial_casts, + trivial_numeric_casts, + unnameable_types, + unreachable_pub, + unused_import_braces, + unused_lifetimes, + unused_qualifications, + unused_results, + unused_tuple_struct_fields, + variant_size_differences +)] +#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::restriction)] +#![allow(clippy::blanket_clippy_restriction_lints)] // this is a test, so enable all restriction lints intentionally. +#![allow( + clippy::exhaustive_enums, + clippy::exhaustive_structs, + clippy::min_ident_chars, + clippy::single_char_lifetime_names +)] // TODO + +pub mod basic { + include!("include/basic.rs"); +} + +pub mod box_pointers { + use pin_project_lite::pin_project; + + pin_project! { + #[derive(Debug)] + pub struct Struct { + #[pin] + pub p: Box, + pub u: Box, + } + } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[project(!Unpin)] + #[derive(Debug)] + pub enum Enum { + Struct { + #[pin] + p: Box, + u: Box, + }, + Unit, + } + } +} + +pub mod explicit_outlives_requirements { + use pin_project_lite::pin_project; + + pin_project! { + #[derive(Debug)] + pub struct Struct<'a, T, U> + where + T: ?Sized, + U: ?Sized, + { + #[pin] + pub pinned: &'a mut T, + pub unpinned: &'a mut U, + } + } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[project(!Unpin)] + #[derive(Debug)] + pub enum Enum<'a, T, U> + where + T: ?Sized, + U: ?Sized, + { + Struct { + #[pin] + pinned: &'a mut T, + unpinned: &'a mut U, + }, + Unit, + } + } +} + +pub mod variant_size_differences { + use pin_project_lite::pin_project; + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[project(!Unpin)] + #[allow(missing_debug_implementations, missing_copy_implementations)] // https://github.com/rust-lang/rust/pull/74060 + #[allow(variant_size_differences)] // for the type itself + #[allow(clippy::large_enum_variant)] // for the type itself + pub enum Enum { + V1 { f: u8 }, + V2 { f: [u8; 1024] }, + } + } +} + +pub mod clippy_mut_mut { + use pin_project_lite::pin_project; + + pin_project! { + #[derive(Debug)] + pub struct Struct<'a, T, U> { + #[pin] + pub pinned: &'a mut T, + pub unpinned: &'a mut U, + } + } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[project(!Unpin)] + #[derive(Debug)] + pub enum Enum<'a, T, U> { + Struct { + #[pin] + pinned: &'a mut T, + unpinned: &'a mut U, + }, + Unit, + } + } +} + +#[allow(unreachable_pub)] +mod clippy_redundant_pub_crate { + use pin_project_lite::pin_project; + + pin_project! { + #[derive(Debug)] + pub struct Struct { + #[pin] + pub pinned: T, + pub unpinned: U, + } + } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[project(!Unpin)] + #[derive(Debug)] + pub enum Enum { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Unit, + } + } +} + +#[allow(clippy::use_self)] +pub mod clippy_type_repetition_in_bounds { + use pin_project_lite::pin_project; + + pin_project! { + #[derive(Debug)] + pub struct Struct + where + Struct: Sized, + { + #[pin] + pub pinned: T, + pub unpinned: U, + } + } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[project(!Unpin)] + #[derive(Debug)] + pub enum Enum + where + Enum: Sized, + { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Unit, + } + } +} + +#[allow(missing_debug_implementations)] +pub mod clippy_used_underscore_binding { + use pin_project_lite::pin_project; + + pin_project! { + pub struct Struct { + #[pin] + pub _pinned: T, + pub _unpinned: U, + } + } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[project(!Unpin)] + pub enum Enum { + Struct { + #[pin] + _pinned: T, + _unpinned: U, + }, + } + } +} + +pub mod clippy_ref_option_ref { + use pin_project_lite::pin_project; + + pin_project! { + pub struct Struct<'a> { + #[pin] + pub _pinned: Option<&'a ()>, + pub _unpinned: Option<&'a ()>, + } + } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[project(!Unpin)] + pub enum Enum<'a> { + Struct { + #[pin] + _pinned: Option<&'a ()>, + _unpinned: Option<&'a ()>, + }, + } + } +} diff --git a/vendor/platforms-1.1.0/.cargo-checksum.json b/vendor/platforms-1.1.0/.cargo-checksum.json new file mode 100644 index 0000000000000..34913af252492 --- /dev/null +++ b/vendor/platforms-1.1.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"fc7ced6d08953d3e098c1288b93b7b5bc0f07863d75401e7bf3f2c61b3b19778","CODE_OF_CONDUCT.md":"e192757304769d52d97219b499e32786490622ed0188194f56e194ed6b614cf4","Cargo.toml":"6e87627a64c7cfdc58db9807a75cc69b669004ca83a2e20c9ffaf8ebb664c044","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"a16b1dddf07f6abdcb3898a4410a01a2b597ec3e2cde3b270553e109c5e355c4","README.md":"573331eefd1808a421a55f0f726a17aa6b2d59cc78640358b5021db32e5bb016","build.rs":"367376b0c84cc69863682a34ec6121be00b5945091a51106a881f792071f7bb7","src/error.rs":"37fa811e7e3293e8823d262227e0ee835dedd9601f693f142b259123d87eda09","src/lib.rs":"b186168039c4cdfe73f8e9faf267bf34fe4eb7f9daecfc19f6c47f5869576e6e","src/platform.rs":"4b5dc2fb72d53fe43bcb2040f9ec84400ace2ae411052554b81f46dd604125c4","src/platform/req.rs":"4372de22225f2d331d2f458e8a99866cb5d735d8c28dbc0d7c2672568cd946bc","src/platform/tier.rs":"f2bb5ee278ea0eddc50bbde94dfbd56f99fc3a3e1cc3b876acbac992ce54012f","src/platform/tier1.rs":"f7c81061d162507660e2932fde88b3441389a26f4855d4f6f579c41b8cf44336","src/platform/tier2.rs":"69f8f77fa7ce0df99267daa186b867e379f673952854d556266188ea3284cbea","src/platform/tier3.rs":"ed51c0551e0a2678236ab37fed2629b758fdaa7ae67349c07562012e37aee6be","src/target.rs":"ddc8e53ddc33ca6c4a0319dc12b869a1fd26e3995ba744b7ce34420e6d9b7751","src/target/arch.rs":"a79b2d7237bb8eeabc738483d396a254fe0c95af71c1f254762039761eae9a10","src/target/env.rs":"8e5ff905d6265ab065adf14a67897657636692f8630126de78d096f51372bd33","src/target/os.rs":"36d68399ea1996fca3d42ffc0dcdc653da7ebc024b0f0bcfd4b557c4096effea"},"package":"989d43012e2ca1c4a02507c67282691a0a3207f9dc67cec596b43fe925b3d325"} \ No newline at end of file diff --git a/vendor/platforms-1.1.0/CHANGELOG.md b/vendor/platforms-1.1.0/CHANGELOG.md new file mode 100644 index 0000000000000..c1cd52315ff28 --- /dev/null +++ b/vendor/platforms-1.1.0/CHANGELOG.md @@ -0,0 +1,99 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 1.1.0 (2020-12-28) +### Added +- `aarch64-apple-darwin` platform definition ([#32]) + +[#32]: https://github.com/RustSec/platforms-crate/pull/32 + +## 1.0.3 (2020-10-29) +### Changed +- Source `Platform::guess_current` from `$TARGET` environment variable when + available ([#29]) + +[#29]: https://github.com/RustSec/platforms-crate/pull/29 + +## 1.0.2 (2020-09-14) +### Removed +- `const fn` on `Platforms::all` ([#27]) + +[#27]: https://github.com/RustSec/platforms-crate/pull/27 + +## 1.0.1 (2020-09-14) [YANKED] +### Changed +- Make `Platform::all()` a `const fn` ([#24]) +- Refactor `Platform::find` and `::guess_current` ([#23]) +- Rename `ALL_PLATFORMS` to `Platform::all()` ([#22]) + +[#24]: https://github.com/RustSec/platforms-crate/pull/24 +[#23]: https://github.com/RustSec/platforms-crate/pull/23 +[#22]: https://github.com/RustSec/platforms-crate/pull/22 + +## 1.0.0 (2020-09-13) [YANKED] +### Added +- Ensure all types have `FromStr`, `Display`, and `serde` impls ([#20]) +- `aarch64-pc-windows-msvc` platform ([#17]) + +### Changed +- Make extensible enums `non_exhaustive`; MSRV 1.40+ ([#18]) + +[#20]: https://github.com/RustSec/platforms-crate/pull/20 +[#18]: https://github.com/RustSec/platforms-crate/pull/18 +[#17]: https://github.com/RustSec/platforms-crate/pull/17 + +## 0.2.1 (2019-09-24) + +- Initial GitHub Actions config ([#12]) +- Properly set up `target::os::TARGET_OS` const for unknown OS ([#11]) + +[#12]: https://github.com/RustSec/platforms-crate/pull/12 +[#11]: https://github.com/RustSec/platforms-crate/pull/11 + +## 0.2.0 (2019-01-13) + +- Update platforms to match RustForge ([#9]) +- Update to Rust 2018 edition ([#8]) + +[#9]: https://github.com/RustSec/platforms-crate/pull/9 +[#8]: https://github.com/RustSec/platforms-crate/pull/8 + +## 0.1.4 (2018-07-29) + +- `x86_64-apple-darwin`: fix typo in target triple name ([#6]) +- Have markdown-table-gen output links to Platform structs on docs.rs ([#5]) + +[#6]: https://github.com/RustSec/platforms-crate/pull/6 +[#5]: https://github.com/RustSec/platforms-crate/pull/5 + +## 0.1.3 (2018-07-28) + +- Fix Travis CI badge in Cargo.toml + +## 0.1.2 (2018-07-27) + +- Add table of supported platforms to README.md using Markdown generator ([#4]) + +[#4]: https://github.com/RustSec/platforms-crate/pull/4 + +## 0.1.1 (2018-07-27) + +- Impl `Display` and `std::error::Error` traits for `packages::Error` ([#3]) + +[#3]: https://github.com/RustSec/platforms-crate/pull/3 + +## 0.1.0 (2018-07-26) + +- Add `guess_current()` ([#2]) +- Optional serde support ([#1]) + +[#2]: https://github.com/RustSec/platforms-crate/pull/2 +[#1]: https://github.com/RustSec/platforms-crate/pull/1 + +## 0.0.1 (2018-07-26) + +- Initial release diff --git a/vendor/platforms-1.1.0/CODE_OF_CONDUCT.md b/vendor/platforms-1.1.0/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000000..3b8032720bbf8 --- /dev/null +++ b/vendor/platforms-1.1.0/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at bascule@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/platforms-1.1.0/Cargo.toml b/vendor/platforms-1.1.0/Cargo.toml new file mode 100644 index 0000000000000..3f084ebe43fb7 --- /dev/null +++ b/vendor/platforms-1.1.0/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "platforms" +version = "1.1.0" +authors = ["Tony Arcieri "] +description = "Rust platform registry with information about valid Rust platforms (target\ntriple, target_arch, target_os) sourced from Rust Forge.\n" +homepage = "https://rustsec.org" +readme = "README.md" +keywords = ["architectures", "cpu", "platforms", "os", "targets"] +categories = ["development-tools", "no-std"] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustSec/platforms-crate" +[dependencies.serde] +version = "1" +optional = true + +[features] +default = ["std"] +std = [] +[badges.maintenance] +status = "passively-maintained" diff --git a/vendor/platforms-1.1.0/LICENSE-APACHE b/vendor/platforms-1.1.0/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/vendor/platforms-1.1.0/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/platforms-1.1.0/LICENSE-MIT b/vendor/platforms-1.1.0/LICENSE-MIT new file mode 100644 index 0000000000000..e8f255f7a68ca --- /dev/null +++ b/vendor/platforms-1.1.0/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2018-2020 The Rust Secure Code Working Group + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/platforms-1.1.0/README.md b/vendor/platforms-1.1.0/README.md new file mode 100644 index 0000000000000..a8a7fba81f0a2 --- /dev/null +++ b/vendor/platforms-1.1.0/README.md @@ -0,0 +1,246 @@ +# Rust `platforms` crate + +[![Latest Version][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] +![Apache 2/MIT licensed][license-image] +![MSRV][rustc-image] +[![Project Chat][zulip-image]][zulip-link] + +Rust platform registry: provides programmatic access to information +about valid Rust platforms, sourced from the Rust compiler. + +[Documentation][docs-link] + +## About + +This crate provides programmatic access to information about valid Rust +platforms. This is useful for systems which document/inventory information +relevant to Rust platforms. + +It was created for the [RustSec Advisory Database] and is maintained by the +[Rust Secure Code Working Group][wg-secure-code]. + +It is not intended to be a tool for gating builds based on the current platform +or as a replacement for Rust's existing conditional compilation features: +please use those for build purposes. + +## Minimum Supported Rust Version + +Rust **1.40** or higher. + +Minimum supported Rust version may be changed in the future, but it will be +accompanied by a minor version bump. + +## Registered Platforms + +### Tier 1 + +| target triple | target_arch | target_os | target_env | +|-----------------------------------|-------------|------------|------------| +| [i686-apple-darwin] | x86 | macos | "" | +| [i686-pc-windows-gnu] | x86 | windows | gnu | +| [i686-pc-windows-msvc] | x86 | windows | msvc | +| [i686-unknown-linux-gnu] | x86 | linux | gnu | +| [x86_64-apple-darwin] | x86_64 | macos | "" | +| [x86_64-pc-windows-gnu] | x86_64 | windows | gnu | +| [x86_64-pc-windows-msvc] | x86_64 | windows | msvc | +| [x86_64-unknown-linux-gnu] | x86_64 | linux | gnu | + +### Tier 2 + +| target triple | target_arch | target_os | target_env | +|-----------------------------------|-------------|------------|------------| +| [aarch64-apple-darwin] | aarch64 | macos | "" | +| [aarch64-apple-ios] | aarch64 | ios | "" | +| [aarch64-pc-windows-msvc] | aarch64 | windows | msvc | +| [aarch64-linux-android] | aarch64 | android | "" | +| [aarch64-fuchsia] | aarch64 | fuchsia | "" | +| [aarch64-unknown-linux-gnu] | aarch64 | linux | gnu | +| [aarch64-unknown-linux-musl] | aarch64 | linux | musl | +| [arm-linux-androideabi] | arm | android | "" | +| [arm-unknown-linux-gnueabi] | arm | linux | gnu | +| [arm-unknown-linux-gnueabihf] | arm | linux | gnu | +| [arm-unknown-linux-musleabi] | arm | linux | musl | +| [arm-unknown-linux-musleabihf] | arm | linux | musl | +| [armv5te-unknown-linux-gnueabi] | arm | linux | gnu | +| [armv7-apple-ios] | arm | ios | "" | +| [armv7-linux-androideabi] | arm | android | "" | +| [armv7-unknown-linux-gnueabihf] | arm | linux | gnu | +| [armv7-unknown-linux-musleabihf] | arm | linux | musl | +| [armv7s-apple-ios] | arm | ios | "" | +| [asmjs-unknown-emscripten] | asmjs | emscripten | "" | +| [i386-apple-ios] | x86 | ios | "" | +| [i586-pc-windows-msvc] | x86 | windows | msvc | +| [i586-unknown-linux-gnu] | x86 | linux | gnu | +| [i586-unknown-linux-musl] | x86 | linux | gnu | +| [i686-linux-android] | x86 | android | "" | +| [i686-unknown-freebsd] | x86 | freebsd | "" | +| [i686-unknown-linux-musl] | x86 | linux | musl | +| [mips-unknown-linux-gnu] | mips | linux | gnu | +| [mips-unknown-linux-musl] | mips | linux | musl | +| [mips64-unknown-linux-gnuabi64] | mips64 | linux | gnu | +| [mips64el-unknown-linux-gnuabi64] | mips64 | linux | gnu | +| [mipsel-unknown-linux-gnu] | mips | linux | gnu | +| [mipsel-unknown-linux-musl] | mips | linux | musl | +| [powerpc-unknown-linux-gnu] | powerpc | linux | gnu | +| [powerpc64-unknown-linux-gnu] | powerpc64 | linux | gnu | +| [powerpc64le-unknown-linux-gnu] | powerpc64 | linux | gnu | +| [s390x-unknown-linux-gnu] | s390x | linux | gnu | +| [sparc64-unknown-linux-gnu] | sparc64 | linux | gnu | +| [sparcv9-sun-solaris] | sparc64 | solaris | "" | +| [wasm32-unknown-unknown] | wasm32 | unknown | "" | +| [wasm32-unknown-emscripten] | wasm32 | emscripten | "" | +| [x86_64-apple-ios] | x86_64 | ios | "" | +| [x86_64-linux-android] | x86_64 | android | "" | +| [x86_64-rumprun-netbsd] | x86_64 | netbsd | "" | +| [x86_64-sun-solaris] | x86_64 | solaris | "" | +| [x86_64-unknown-cloudabi] | x86_64 | cloudabi | "" | +| [x86_64-unknown-freebsd] | x86_64 | freebsd | "" | +| [x86_64-fuchsia] | x86_64 | fuchsia | "" | +| [x86_64-unknown-linux-gnux32] | x86_64 | linux | gnu | +| [x86_64-unknown-linux-musl] | x86_64 | linux | musl | +| [x86_64-unknown-netbsd] | x86_64 | netbsd | "" | +| [x86_64-unknown-redox] | x86_64 | redox | "" | +| [aarch64-unknown-cloudabi] | aarch64 | cloudabi | "" | +| [armv7-unknown-cloudabi-eabihf] | arm | cloudabi | "" | +| [i686-unknown-cloudabi] | x86 | cloudabi | "" | +| [powerpc-unknown-linux-gnuspe] | powerpc | linux | gnu | +| [sparc-unknown-linux-gnu] | sparc | linux | gnu | + +### Tier 3 + +| target triple | target_arch | target_os | target_env | +|-----------------------------------|-------------|------------|------------| +| [i686-unknown-haiku] | x86 | haiku | "" | +| [i686-unknown-netbsd] | x86 | netbsd | "" | +| [mips-unknown-linux-uclibc] | mips | linux | uclibc | +| [mipsel-unknown-linux-uclibc] | mips | linux | uclibc | +| [msp430-none-elf] | msp430 | unknown | "" | +| [sparc64-unknown-netbsd] | sparc64 | netbsd | "" | +| [thumbv6m-none-eabi] | thumbv6 | unknown | "" | +| [thumbv7em-none-eabi] | thumbv7 | unknown | "" | +| [thumbv7em-none-eabihf] | thumbv7 | unknown | "" | +| [thumbv7m-none-eabi] | thumbv7 | unknown | "" | +| [x86_64-fortanix-unknown-sgx] | x86_64 | unknown | sgx | +| [x86_64-unknown-bitrig] | x86_64 | bitrig | "" | +| [x86_64-unknown-dragonfly] | x86_64 | dragonfly | "" | +| [x86_64-unknown-haiku] | x86_64 | haiku | "" | +| [x86_64-unknown-openbsd] | x86_64 | openbsd | "" | + +## License + +Licensed under either of: + + * Apache License, Version 2.0 ([LICENSE-APACHE] or https://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT] or https://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you shall be dual licensed as above, without any +additional terms or conditions. + +[//]: # (badges) + +[crate-image]: https://img.shields.io/crates/v/platforms.svg +[crate-link]: https://crates.io/crates/platforms +[docs-image]: https://docs.rs/platforms/badge.svg +[docs-link]: https://docs.rs/platforms/ +[build-image]: https://github.com/rustsec/platforms-crate/workflows/CI/badge.svg +[build-link]: https://github.com/RustSec/platforms-crate/actions?query=workflow:CI +[license-image]: https://img.shields.io/badge/license-Apache2%2FMIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.40+-blue.svg +[zulip-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[zulip-link]: https://rust-lang.zulipchat.com/#narrow/stream/146229-wg-secure-code/ + +[//]: # (general links) + +[RustSec Advisory Database]: https://github.com/RustSec +[wg-secure-code]: https://www.rust-lang.org/governance/wgs/wg-secure-code +[LICENSE-APACHE]: https://github.com/RustSec/platforms-crate/blob/main/LICENSE-APACHE +[LICENSE-MIT]: https://github.com/RustSec/platforms-crate/blob/main/LICENSE-MIT + +[//]: # (platform links) + +[i686-apple-darwin]: https://docs.rs/platforms/latest/platforms/platform/tier1/constant.I686_APPLE_DARWIN.html +[i686-pc-windows-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier1/constant.I686_PC_WINDOWS_GNU.html +[i686-pc-windows-msvc]: https://docs.rs/platforms/latest/platforms/platform/tier1/constant.I686_PC_WINDOWS_MSVC.html +[i686-unknown-linux-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier1/constant.I686_UNKNOWN_LINUX_GNU.html +[x86_64-apple-darwin]: https://docs.rs/platforms/latest/platforms/platform/tier1/constant.X86_64_APPLE_DARWIN.html +[x86_64-pc-windows-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier1/constant.X86_64_PC_WINDOWS_GNU.html +[x86_64-pc-windows-msvc]: https://docs.rs/platforms/latest/platforms/platform/tier1/constant.X86_64_PC_WINDOWS_MSVC.html +[x86_64-unknown-linux-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier1/constant.X86_64_UNKNOWN_LINUX_GNU.html +[aarch64-apple-darwin]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.AARCH64_APPLE_DARWIN.html +[aarch64-apple-ios]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.AARCH64_APPLE_IOS.html +[aarch64-pc-windows-msvc]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.AARCH64_PC_WINDOWS_MSVC.html +[aarch64-linux-android]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.AARCH64_LINUX_ANDROID.html +[aarch64-fuchsia]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.AARCH64_FUCHSIA.html +[aarch64-unknown-linux-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.AARCH64_UNKNOWN_LINUX_GNU.html +[aarch64-unknown-linux-musl]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.AARCH64_UNKNOWN_LINUX_MUSL.html +[arm-linux-androideabi]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.ARM_LINUX_ANDROIDEABI.html +[arm-unknown-linux-gnueabi]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.ARM_UNKNOWN_LINUX_GNUEABI.html +[arm-unknown-linux-gnueabihf]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.ARM_UNKNOWN_LINUX_GNUEABIHF.html +[arm-unknown-linux-musleabi]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.ARM_UNKNOWN_LINUX_MUSLEABI.html +[arm-unknown-linux-musleabihf]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.ARM_UNKNOWN_LINUX_MUSLEABIHF.html +[armv5te-unknown-linux-gnueabi]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.ARMV5TE_UNKNOWN_LINUX_GNUEABI.html +[armv7-apple-ios]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.ARMV7_APPLE_IOS.html +[armv7-linux-androideabi]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.ARMV7_LINUX_ANDROIDEABI.html +[armv7-unknown-linux-gnueabihf]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.ARMV7_UNKNOWN_LINUX_GNUEABIHF.html +[armv7-unknown-linux-musleabihf]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.ARMV7_UNKNOWN_LINUX_MUSLEABIHF.html +[armv7s-apple-ios]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.ARMV7S_APPLE_IOS.html +[asmjs-unknown-emscripten]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.ASMJS_UNKNOWN_EMSCRIPTEN.html +[i386-apple-ios]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.I386_APPLE_IOS.html +[i586-pc-windows-msvc]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.I586_PC_WINDOWS_MSVC.html +[i586-unknown-linux-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.I586_UNKNOWN_LINUX_GNU.html +[i586-unknown-linux-musl]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.I586_UNKNOWN_LINUX_MUSL.html +[i686-linux-android]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.I686_LINUX_ANDROID.html +[i686-unknown-freebsd]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.I686_UNKNOWN_FREEBSD.html +[i686-unknown-linux-musl]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.I686_UNKNOWN_LINUX_MUSL.html +[mips-unknown-linux-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.MIPS_UNKNOWN_LINUX_GNU.html +[mips-unknown-linux-musl]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.MIPS_UNKNOWN_LINUX_MUSL.html +[mips64-unknown-linux-gnuabi64]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.MIPS64_UNKNOWN_LINUX_GNUABI64.html +[mips64el-unknown-linux-gnuabi64]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.MIPS64EL_UNKNOWN_LINUX_GNUABI64.html +[mipsel-unknown-linux-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.MIPSEL_UNKNOWN_LINUX_GNU.html +[mipsel-unknown-linux-musl]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.MIPSEL_UNKNOWN_LINUX_MUSL.html +[powerpc-unknown-linux-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.POWERPC_UNKNOWN_LINUX_GNU.html +[powerpc64-unknown-linux-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.POWERPC64_UNKNOWN_LINUX_GNU.html +[powerpc64le-unknown-linux-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.POWERPC64LE_UNKNOWN_LINUX_GNU.html +[s390x-unknown-linux-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.S390X_UNKNOWN_LINUX_GNU.html +[sparc64-unknown-linux-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.SPARC64_UNKNOWN_LINUX_GNU.html +[sparcv9-sun-solaris]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.SPARCV9_SUN_SOLARIS.html +[wasm32-unknown-unknown]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.WASM32_UNKNOWN_UNKNOWN.html +[wasm32-unknown-emscripten]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.WASM32_UNKNOWN_EMSCRIPTEN.html +[x86_64-apple-ios]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.X86_64_APPLE_IOS.html +[x86_64-linux-android]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.X86_64_LINUX_ANDROID.html +[x86_64-rumprun-netbsd]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.X86_64_RUMPRUN_NETBSD.html +[x86_64-sun-solaris]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.X86_64_SUN_SOLARIS.html +[x86_64-unknown-cloudabi]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.X86_64_UNKNOWN_CLOUDABI.html +[x86_64-unknown-freebsd]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.X86_64_UNKNOWN_FREEBSD.html +[x86_64-fuchsia]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.X86_64_FUCHSIA.html +[x86_64-unknown-linux-gnux32]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.X86_64_UNKNOWN_LINUX_GNUX32.html +[x86_64-unknown-linux-musl]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.X86_64_UNKNOWN_LINUX_MUSL.html +[x86_64-unknown-netbsd]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.X86_64_UNKNOWN_NETBSD.html +[x86_64-unknown-redox]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.X86_64_UNKNOWN_REDOX.html +[aarch64-unknown-cloudabi]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.AARCH64_UNKNOWN_CLOUDABI.html +[armv7-unknown-cloudabi-eabihf]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.ARMV7_UNKNOWN_CLOUDABI_EABIHF.html +[i686-unknown-cloudabi]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.I686_UNKNOWN_CLOUDABI.html +[powerpc-unknown-linux-gnuspe]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.POWERPC_UNKNOWN_LINUX_GNUSPE.html +[sparc-unknown-linux-gnu]: https://docs.rs/platforms/latest/platforms/platform/tier2/constant.SPARC_UNKNOWN_LINUX_GNU.html +[i686-unknown-haiku]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.I686_UNKNOWN_HAIKU.html +[i686-unknown-netbsd]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.I686_UNKNOWN_NETBSD.html +[mips-unknown-linux-uclibc]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.MIPS_UNKNOWN_LINUX_UCLIBC.html +[mipsel-unknown-linux-uclibc]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.MIPSEL_UNKNOWN_LINUX_UCLIBC.html +[msp430-none-elf]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.MSP430_NONE_ELF.html +[sparc64-unknown-netbsd]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.SPARC64_UNKNOWN_NETBSD.html +[thumbv6m-none-eabi]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.THUMBV6M_NONE_EABI.html +[thumbv7em-none-eabi]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.THUMBV7EM_NONE_EABI.html +[thumbv7em-none-eabihf]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.THUMBV7EM_NONE_EABIHF.html +[thumbv7m-none-eabi]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.THUMBV7M_NONE_EABI.html +[x86_64-fortanix-unknown-sgx]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.X86_64_FORTANIX_UNKNOWN_SGX.html +[x86_64-unknown-bitrig]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.X86_64_UNKNOWN_BITRIG.html +[x86_64-unknown-dragonfly]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.X86_64_UNKNOWN_DRAGONFLY.html +[x86_64-unknown-haiku]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.X86_64_UNKNOWN_HAIKU.html +[x86_64-unknown-openbsd]: https://docs.rs/platforms/latest/platforms/platform/tier3/constant.X86_64_UNKNOWN_OPENBSD.html diff --git a/vendor/platforms-1.1.0/build.rs b/vendor/platforms-1.1.0/build.rs new file mode 100644 index 0000000000000..7065a033c34b0 --- /dev/null +++ b/vendor/platforms-1.1.0/build.rs @@ -0,0 +1,4 @@ +fn main() { + let target = std::env::var("TARGET").expect("TARGET env var not set"); + println!("cargo:rustc-env=TARGET={}", target); +} diff --git a/vendor/platforms-1.1.0/src/error.rs b/vendor/platforms-1.1.0/src/error.rs new file mode 100644 index 0000000000000..fade31bbaa1ac --- /dev/null +++ b/vendor/platforms-1.1.0/src/error.rs @@ -0,0 +1,13 @@ +//! Error type + +use core::fmt::{self, Display}; + +/// Error type +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Error; + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("platforms::Error") + } +} diff --git a/vendor/platforms-1.1.0/src/lib.rs b/vendor/platforms-1.1.0/src/lib.rs new file mode 100644 index 0000000000000..36483b7b90e3d --- /dev/null +++ b/vendor/platforms-1.1.0/src/lib.rs @@ -0,0 +1,34 @@ +//! Rust platform registry: provides programmatic access to information about valid Rust platforms +//! +//! This crate provides an interface to the platform data canonically sourced +//! from the Rust compiler: +//! +//! +//! +//! ## Minimum Supported Rust Version +//! +//! Rust **1.40** or higher. +//! +//! Minimum supported Rust version can be changed in the future, but it will be +//! done with a minor version bump. + +#![no_std] +#![doc(html_root_url = "https://docs.rs/platforms/1.1.0")] +#![forbid(unsafe_code)] +#![warn(missing_docs, unused_qualifications, rust_2018_idioms)] + +#[cfg(feature = "std")] +extern crate std; + +pub(crate) mod error; +pub mod platform; +pub mod target; + +pub use crate::{ + error::Error, + platform::{Platform, Tier}, + target::{TARGET_ARCH, TARGET_ENV, TARGET_OS}, +}; + +#[cfg(feature = "std")] +pub use crate::platform::PlatformReq; diff --git a/vendor/platforms-1.1.0/src/platform.rs b/vendor/platforms-1.1.0/src/platform.rs new file mode 100644 index 0000000000000..8b1f049e41a4f --- /dev/null +++ b/vendor/platforms-1.1.0/src/platform.rs @@ -0,0 +1,188 @@ +//! Rust platforms + +pub mod tier1; +pub mod tier2; +pub mod tier3; + +#[cfg(feature = "std")] +mod req; +mod tier; + +pub use self::tier::Tier; + +#[cfg(feature = "std")] +pub use self::req::PlatformReq; + +use crate::target::*; +use core::fmt; + +/// Rust platforms supported by mainline rustc +/// +/// Sourced from +#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +pub struct Platform { + /// "Target triple" string uniquely identifying the platform. See: + /// + /// + /// These are defined in the `rustc_target` crate of the Rust compiler: + /// + pub target_triple: &'static str, + + /// Target architecture `cfg` attribute (i.e. `cfg(target_arch)`) + pub target_arch: Arch, + + /// Target OS `cfg` attribute (i.e. `cfg(target_os)`). + pub target_os: OS, + + /// Target environment `cfg` attribute (i.e. `cfg(target_env)`). + /// Only used when needed for disambiguation, e.g. on many GNU platforms + /// this value will be `None`. + pub target_env: Option, + + /// Tier of this platform: + /// + /// - `Tier::One`: guaranteed to work + /// - `Tier::Two`: guaranteed to build + /// - `Tier::Three`: unofficially supported with no guarantees + pub tier: Tier, +} + +impl Platform { + /// Find a Rust platform by its "target triple", e.g. `i686-apple-darwin` + pub fn find(target_triple: &str) -> Option<&'static Platform> { + Self::all() + .iter() + .find(|platform| platform.target_triple == target_triple) + } + + /// Attempt to guess the current `Platform`. May give inaccurate results. + pub fn guess_current() -> Option<&'static Platform> { + Self::find(env!("TARGET")).or_else(|| { + Self::all().iter().find(|platform| { + platform.target_arch == TARGET_ARCH + && platform.target_env == TARGET_ENV + && platform.target_os == TARGET_OS + }) + }) + } + + /// All valid Rust platforms usable from the mainline compiler + pub fn all() -> &'static [Platform] { + &[ + // Tier 1 + tier1::I686_APPLE_DARWIN, + tier1::I686_PC_WINDOWS_GNU, + tier1::I686_PC_WINDOWS_MSVC, + tier1::I686_UNKNOWN_LINUX_GNU, + tier1::X86_64_APPLE_DARWIN, + tier1::X86_64_PC_WINDOWS_GNU, + tier1::X86_64_PC_WINDOWS_MSVC, + tier1::X86_64_UNKNOWN_LINUX_GNU, + // Tier 2 + tier2::AARCH64_APPLE_DARWIN, + tier2::AARCH64_APPLE_IOS, + tier2::AARCH64_PC_WINDOWS_MSVC, + tier2::AARCH64_LINUX_ANDROID, + tier2::AARCH64_FUCHSIA, + tier2::AARCH64_UNKNOWN_LINUX_GNU, + tier2::AARCH64_UNKNOWN_LINUX_MUSL, + tier2::ARM_LINUX_ANDROIDEABI, + tier2::ARM_UNKNOWN_LINUX_GNUEABI, + tier2::ARM_UNKNOWN_LINUX_GNUEABIHF, + tier2::ARM_UNKNOWN_LINUX_MUSLEABI, + tier2::ARM_UNKNOWN_LINUX_MUSLEABIHF, + tier2::ARMV5TE_UNKNOWN_LINUX_GNUEABI, + tier2::ARMV7_APPLE_IOS, + tier2::ARMV7_LINUX_ANDROIDEABI, + tier2::ARMV7_UNKNOWN_LINUX_GNUEABIHF, + tier2::ARMV7_UNKNOWN_LINUX_MUSLEABIHF, + tier2::ARMV7S_APPLE_IOS, + tier2::ASMJS_UNKNOWN_EMSCRIPTEN, + tier2::I386_APPLE_IOS, + tier2::I586_PC_WINDOWS_MSVC, + tier2::I586_UNKNOWN_LINUX_GNU, + tier2::I586_UNKNOWN_LINUX_MUSL, + tier2::I686_LINUX_ANDROID, + tier2::I686_UNKNOWN_FREEBSD, + tier2::I686_UNKNOWN_LINUX_MUSL, + tier2::MIPS_UNKNOWN_LINUX_GNU, + tier2::MIPS_UNKNOWN_LINUX_MUSL, + tier2::MIPS64_UNKNOWN_LINUX_GNUABI64, + tier2::MIPS64EL_UNKNOWN_LINUX_GNUABI64, + tier2::MIPSEL_UNKNOWN_LINUX_GNU, + tier2::MIPSEL_UNKNOWN_LINUX_MUSL, + tier2::POWERPC_UNKNOWN_LINUX_GNU, + tier2::POWERPC64_UNKNOWN_LINUX_GNU, + tier2::POWERPC64LE_UNKNOWN_LINUX_GNU, + tier2::S390X_UNKNOWN_LINUX_GNU, + tier2::SPARC64_UNKNOWN_LINUX_GNU, + tier2::SPARC64_SUN_SOLARIS, + tier2::WASM_UNKNOWN_UNKNOWN, + tier2::WASM_UNKNOWN_EMSCRIPTEN, + tier2::X86_64_APPLE_IOS, + tier2::X86_64_LINUX_ANDROID, + tier2::X86_64_RUMPRUN_NETBSD, + tier2::X86_64_SUN_SOLARIS, + tier2::X86_64_UNKNOWN_CLOUDABI, + tier2::X86_64_UNKNOWN_FREEBSD, + tier2::X86_64_FUCHSIA, + tier2::X86_64_UNKNOWN_LINUX_GNUX32, + tier2::X86_64_UNKNOWN_LINUX_MUSL, + tier2::X86_64_UNKNOWN_NETBSD, + tier2::X86_64_UNKNOWN_REDOX, + // Tier 2.5 + tier2::AARCH64_UNKNOWN_CLOUDABI, + tier2::ARMV7_UNKNOWN_CLOUDABI_EABIHF, + tier2::I686_UNKNOWN_CLOUDABI, + tier2::POWERPC_UNKNOWN_LINUX_GNUSPE, + tier2::SPARC_UNKNOWN_LINUX_GNU, + // Tier 3 + tier3::I686_UNKNOWN_HAIKU, + tier3::I686_UNKNOWN_NETBSD, + tier3::MIPS_UNKNOWN_LINUX_UCLIBC, + tier3::MIPSEL_UNKNOWN_LINUX_UCLIBC, + tier3::MSP430_NONE_ELF, + tier3::SPARC64_UNKNOWN_NETBSD, + tier3::THUMBV6M_NONE_EABI, + tier3::THUMBV7EM_NONE_EABI, + tier3::THUMBV7EM_NONE_EABIHF, + tier3::THUMBV7M_NONE_EABI, + tier3::X86_64_FORTANIX_UNKNOWN_SGX, + tier3::X86_64_UNKNOWN_BITRIG, + tier3::X86_64_UNKNOWN_DRAGONFLY, + tier3::X86_64_UNKNOWN_HAIKU, + tier3::X86_64_UNKNOWN_OPENBSD, + ] + } +} + +impl fmt::Display for Platform { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.target_triple) + } +} + +#[cfg(all(test, feature = "std"))] +mod tests { + use super::Platform; + use std::collections::HashSet; + + /// Ensure there are no duplicate target triples in the platforms list + #[test] + fn no_dupes_test() { + let mut target_triples = HashSet::new(); + + for platform in Platform::all() { + assert!( + target_triples.insert(platform.target_triple), + "duplicate target triple: {}", + platform.target_triple + ); + } + } + + #[test] + fn guesses_current() { + assert!(Platform::guess_current().is_some()); + } +} diff --git a/vendor/platforms-1.1.0/src/platform/req.rs b/vendor/platforms-1.1.0/src/platform/req.rs new file mode 100644 index 0000000000000..9006ab6828cd9 --- /dev/null +++ b/vendor/platforms-1.1.0/src/platform/req.rs @@ -0,0 +1,219 @@ +//! Platform requirements + +use crate::error::Error; +use crate::platform::Platform; +use std::{fmt, str::FromStr, string::String, vec::Vec}; + +#[cfg(feature = "serde")] +use serde::{de, ser, Deserialize, Serialize}; + +/// Platform requirements: glob-like expressions for matching Rust platforms +/// as identified by a "target triple", e.g. `i686-apple-darwin`. +/// +/// For a list of all valid platforms, "target triples", see: +/// +/// +/// +/// Platforms can be grouped with simple globbing rules: +/// +/// - Start with wildcard: `*-gnu` +/// - End with wildcard: `x86_64-*` +/// - Start and end with wildcard: `*windows*` +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct PlatformReq(String); + +/// Wildcard character used for globbing +pub const WILDCARD: char = '*'; + +impl PlatformReq { + /// Borrow this platform requirement as a string slice + pub fn as_str(&self) -> &str { + self.0.as_ref() + } + + /// Does this platform requirement match the given platform string? + /// + /// This matcher accepts a platform "target triple" string ala + /// `x86_64-unknown-linux-gnu` and matches it against this + /// `Platform`, using simple glob like rules. + pub fn matches(&self, platform: &Platform) -> bool { + let self_len = self.as_str().len(); + + // Universal matcher + if self.0.len() == 1 && self.0.chars().next().unwrap() == WILDCARD { + return true; + } + + let mut chars = self.as_str().chars(); + let starts_with_wildcard = chars.next().unwrap() == WILDCARD; + let ends_with_wildcard = chars.last() == Some(WILDCARD); + + if starts_with_wildcard { + if ends_with_wildcard { + // Contains expression: `*windows*` + platform + .target_triple + .contains(&self.0[1..self_len.checked_sub(1).unwrap()]) + } else { + // Suffix expression: `*-gnu` + platform.target_triple.ends_with(&self.0[1..]) + } + } else if ends_with_wildcard { + // Prefix expression: `x86_64-*` + platform + .target_triple + .starts_with(&self.0[..self_len.checked_sub(1).unwrap()]) + } else { + // No wildcards: direct comparison + self.as_str() == platform.target_triple + } + } + + /// Expand glob expressions into a list of all known matching platforms + pub fn matching_platforms(&self) -> Vec<&'static Platform> { + Platform::all() + .iter() + .filter(|platform| self.matches(*platform)) + .collect() + } +} + +impl FromStr for PlatformReq { + type Err = Error; + + /// Create a new platform requirement. Platforms support glob-like + /// wildcards on the beginning and end, e.g. `*windows*`. + /// + /// Must match at least one known Rust platform "target triple" + /// (e.g. `x86_64-unknown-linux-gnu`) to be considered valid. + fn from_str(req_str: &str) -> Result { + let platform_req = PlatformReq(req_str.into()); + + if platform_req.0.is_empty() || platform_req.matching_platforms().is_empty() { + Err(Error) + } else { + Ok(platform_req) + } + } +} + +impl fmt::Display for PlatformReq { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +#[cfg(feature = "serde")] +impl Serialize for PlatformReq { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_str(self.as_str()) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for PlatformReq { + fn deserialize>(deserializer: D) -> Result { + use de::Error; + String::deserialize(deserializer)? + .parse() + .map_err(D::Error::custom) + } +} + +#[cfg(test)] +mod tests { + use super::{Platform, PlatformReq}; + use std::{str::FromStr, vec::Vec}; + + #[test] + fn prefix_glob_test() { + let req = PlatformReq::from_str("sparc*").unwrap(); + + assert_eq!( + req.matching_platforms() + .iter() + .map(|p| p.target_triple) + .collect::>(), + [ + "sparc64-unknown-linux-gnu", + "sparcv9-sun-solaris", + "sparc-unknown-linux-gnu", + "sparc64-unknown-netbsd" + ] + ); + } + + #[test] + fn suffix_glob_test() { + let req = PlatformReq::from_str("*-musl").unwrap(); + + assert_eq!( + req.matching_platforms() + .iter() + .map(|p| p.target_triple) + .collect::>(), + [ + "aarch64-unknown-linux-musl", + "i586-unknown-linux-musl", + "i686-unknown-linux-musl", + "mips-unknown-linux-musl", + "mipsel-unknown-linux-musl", + "x86_64-unknown-linux-musl" + ] + ); + } + + #[test] + fn contains_glob_test() { + let req = PlatformReq::from_str("*windows*").unwrap(); + + assert_eq!( + req.matching_platforms() + .iter() + .map(|p| p.target_triple) + .collect::>(), + [ + "i686-pc-windows-gnu", + "i686-pc-windows-msvc", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + "aarch64-pc-windows-msvc", + "i586-pc-windows-msvc" + ] + ); + } + + #[test] + fn direct_match_test() { + let req = PlatformReq::from_str("x86_64-unknown-dragonfly").unwrap(); + + assert_eq!( + req.matching_platforms() + .iter() + .map(|p| p.target_triple) + .collect::>(), + ["x86_64-unknown-dragonfly"] + ); + } + + #[test] + fn wildcard_test() { + let req = PlatformReq::from_str("*").unwrap(); + assert_eq!(req.matching_platforms().len(), Platform::all().len()) + } + + // How to handle this is debatable... + #[test] + fn double_wildcard_test() { + let req = PlatformReq::from_str("**").unwrap(); + assert_eq!(req.matching_platforms().len(), Platform::all().len()) + } + + #[test] + fn invalid_req_tests() { + assert!(PlatformReq::from_str("").is_err()); + assert!(PlatformReq::from_str(" ").is_err()); + assert!(PlatformReq::from_str("derp").is_err()); + assert!(PlatformReq::from_str("***").is_err()); + } +} diff --git a/vendor/platforms-1.1.0/src/platform/tier.rs b/vendor/platforms-1.1.0/src/platform/tier.rs new file mode 100644 index 0000000000000..ea128641bf56e --- /dev/null +++ b/vendor/platforms-1.1.0/src/platform/tier.rs @@ -0,0 +1,116 @@ +//! Rust platform tiers + +use crate::error::Error; +use core::{convert::TryFrom, fmt, str::FromStr}; + +#[cfg(feature = "serde")] +use serde::{de, ser, Deserialize, Serialize}; + +/// Rust platform tiers: support levels are organized into three tiers, each +/// with a different set of guarantees. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +pub enum Tier { + /// Tier 1 platforms can be thought of as “guaranteed to workâ€. + /// Specifically they will each satisfy the following requirements: + /// + /// * Official binary releases are provided for the platform. + /// * Automated testing is set up to run tests for the platform. + /// * Landing changes to the rust-lang/rust repository’s master branch + /// is gated on tests passing. + /// * Documentation for how to use and how to build the platform is available. + One, + + /// Tier 2 platforms can be thought of as “guaranteed to buildâ€. Automated + /// tests are not run so it’s not guaranteed to produce a working build, + /// but platforms often work to quite a good degree and patches are always + /// welcome! + /// + /// Specifically, these platforms are required to have each of the following: + /// + /// * Official binary releases are provided for the platform. + /// * Automated building is set up, but may not be running tests. + /// * Landing changes to the rust-lang/rust repository’s master branch is + /// gated on platforms building. For some platforms only the standard + /// library is compiled, but for others rustc and cargo are too. + Two, + + /// Tier 3 platforms are those which the Rust codebase has support for, but + /// which are not built or tested automatically, and may not work. + /// Official builds are not available. + Three, +} + +impl Tier { + /// Get a number identifying this tier + pub fn to_usize(self) -> usize { + match self { + Tier::One => 1, + Tier::Two => 2, + Tier::Three => 3, + } + } + + /// Get a string identifying this tier + pub fn as_str(self) -> &'static str { + match self { + Tier::One => "tier1", + Tier::Two => "tier2", + Tier::Three => "tier3", + } + } +} + +impl From for usize { + fn from(tier: Tier) -> usize { + tier.to_usize() + } +} + +impl TryFrom for Tier { + type Error = Error; + + fn try_from(num: usize) -> Result { + match num { + 1 => Ok(Tier::One), + 2 => Ok(Tier::Two), + 3 => Ok(Tier::Three), + _ => Err(Error), + } + } +} + +impl FromStr for Tier { + type Err = Error; + + fn from_str(s: &str) -> Result { + match s { + "tier1" => Ok(Tier::One), + "tier2" => Ok(Tier::Two), + "tier3" => Ok(Tier::Three), + _ => Err(Error), + } + } +} + +impl fmt::Display for Tier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Tier { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_str(self.as_str()) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for Tier { + fn deserialize>(deserializer: D) -> Result { + use de::Error; + <&str>::deserialize(deserializer)? + .parse() + .map_err(D::Error::custom) + } +} diff --git a/vendor/platforms-1.1.0/src/platform/tier1.rs b/vendor/platforms-1.1.0/src/platform/tier1.rs new file mode 100644 index 0000000000000..557fd787632c7 --- /dev/null +++ b/vendor/platforms-1.1.0/src/platform/tier1.rs @@ -0,0 +1,89 @@ +//! All Tier 1 platforms supported by Rust. Sourced from: +//! +//! +//! +//! Tier 1 platforms can be thought of as “guaranteed to workâ€. +//! Specifically they will each satisfy the following requirements: +//! +//! - Official binary releases are provided for the platform. +//! - Automated testing is set up to run tests for the platform. +//! - Landing changes to the rust-lang/rust repository’s master branch +//! is gated on tests passing. +//! - Documentation for how to use and how to build the platform is available. + +use crate::{ + platform::{Platform, Tier}, + target::{Arch, Env, OS}, +}; + +/// `i686-apple-darwin`: 32-bit OSX (10.7+, Lion+) +pub const I686_APPLE_DARWIN: Platform = Platform { + target_triple: "i686-apple-darwin", + target_arch: Arch::X86, + target_os: OS::MacOS, + target_env: None, + tier: Tier::One, +}; + +/// `i686-pc-windows-gnu`: 32-bit MinGW (Windows 7+) +pub const I686_PC_WINDOWS_GNU: Platform = Platform { + target_triple: "i686-pc-windows-gnu", + target_arch: Arch::X86, + target_os: OS::Windows, + target_env: Some(Env::GNU), + tier: Tier::One, +}; + +/// `i686-pc-windows-msvc`: 32-bit MSVC (Windows 7+) +pub const I686_PC_WINDOWS_MSVC: Platform = Platform { + target_triple: "i686-pc-windows-msvc", + target_arch: Arch::X86, + target_os: OS::Windows, + target_env: Some(Env::MSVC), + tier: Tier::One, +}; + +/// `i686-unknown-linux-gnu`: 32-bit Linux (2.6.18+) +pub const I686_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "i686-unknown-linux-gnu", + target_arch: Arch::X86, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::One, +}; + +/// `x86_64-apple-darwin`: 64-bit OSX (10.7+, Lion+) +pub const X86_64_APPLE_DARWIN: Platform = Platform { + target_triple: "x86_64-apple-darwin", + target_arch: Arch::X86_64, + target_os: OS::MacOS, + target_env: None, + tier: Tier::One, +}; + +/// `x86_64-pc-windows-gnu`: 64-bit MinGW (Windows 7+) +pub const X86_64_PC_WINDOWS_GNU: Platform = Platform { + target_triple: "x86_64-pc-windows-gnu", + target_arch: Arch::X86_64, + target_os: OS::Windows, + target_env: Some(Env::GNU), + tier: Tier::One, +}; + +/// `x86_64-pc-windows-msvc`: 64-bit MSVC (Windows 7+) +pub const X86_64_PC_WINDOWS_MSVC: Platform = Platform { + target_triple: "x86_64-pc-windows-msvc", + target_arch: Arch::X86_64, + target_os: OS::Windows, + target_env: Some(Env::MSVC), + tier: Tier::One, +}; + +/// `x86_64-unknown-linux-gnu`: 64-bit Linux (2.6.18+) +pub const X86_64_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "x86_64-unknown-linux-gnu", + target_arch: Arch::X86_64, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::One, +}; diff --git a/vendor/platforms-1.1.0/src/platform/tier2.rs b/vendor/platforms-1.1.0/src/platform/tier2.rs new file mode 100644 index 0000000000000..49f8460b7afaa --- /dev/null +++ b/vendor/platforms-1.1.0/src/platform/tier2.rs @@ -0,0 +1,542 @@ +//! All Tier 2 platforms supported by Rust. Sourced from: +//! +//! +//! +//! Tier 2 platforms can be thought of as “guaranteed to buildâ€. Automated +//! tests are not run so it’s not guaranteed to produce a working build, +//! but platforms often work to quite a good degree and patches are always +//! welcome! +//! +//! Specifically, these platforms are required to have each of the following: +//! +//! - Official binary releases are provided for the platform. +//! - Automated building is set up, but may not be running tests. +//! - Landing changes to the rust-lang/rust repository’s master branch is +//! gated on platforms building. For some platforms only the standard +//! library is compiled, but for others rustc and cargo are too. + +use crate::{ + platform::{Platform, Tier}, + target::{Arch, Env, OS}, +}; + +/// `aarch64-apple-darwin`: Apple Silicon macOS (11+) +pub const AARCH64_APPLE_DARWIN: Platform = Platform { + target_triple: "aarch64-apple-darwin", + target_arch: Arch::AARCH64, + target_os: OS::MacOS, + target_env: None, + tier: Tier::Two, +}; + +/// `aarch64-apple-ios`: ARM64 iOS +pub const AARCH64_APPLE_IOS: Platform = Platform { + target_triple: "aarch64-apple-ios", + target_arch: Arch::AARCH64, + target_os: OS::iOS, + target_env: None, + tier: Tier::Two, +}; + +/// `aarch64-pc-windows-msvc`: ARM64 MSVC (Windows 10) +pub const AARCH64_PC_WINDOWS_MSVC: Platform = Platform { + target_triple: "aarch64-pc-windows-msvc", + target_arch: Arch::AARCH64, + target_os: OS::Windows, + target_env: Some(Env::MSVC), + tier: Tier::Two, +}; + +/// `aarch64-fuchsia`: ARM64 Fuchsia +pub const AARCH64_FUCHSIA: Platform = Platform { + target_triple: "aarch64-fuchsia", + target_arch: Arch::AARCH64, + target_os: OS::Fuchsia, + target_env: None, + tier: Tier::Two, +}; + +/// `aarch64-linux-android`: ARM64 Android +pub const AARCH64_LINUX_ANDROID: Platform = Platform { + target_triple: "aarch64-linux-android", + target_arch: Arch::AARCH64, + target_os: OS::Android, + target_env: None, + tier: Tier::Two, +}; + +/// `aarch64-unknown-linux-gnu`: ARM64 Linux +pub const AARCH64_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "aarch64-unknown-linux-gnu", + target_arch: Arch::AARCH64, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `aarch64-unknown-linux-musl`: ARM64 Linux with MUSL +pub const AARCH64_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "aarch64-unknown-linux-musl", + target_arch: Arch::AARCH64, + target_os: OS::Linux, + target_env: Some(Env::Musl), + tier: Tier::Two, +}; + +/// `arm-linux-androideabi`: ARMv7 Android +pub const ARM_LINUX_ANDROIDEABI: Platform = Platform { + target_triple: "arm-linux-androideabi", + target_arch: Arch::ARM, + target_os: OS::Android, + target_env: None, + tier: Tier::Two, +}; + +/// `arm-unknown-linux-gnueabi`: ARMv6 Linux +pub const ARM_UNKNOWN_LINUX_GNUEABI: Platform = Platform { + target_triple: "arm-unknown-linux-gnueabi", + target_arch: Arch::ARM, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `arm-unknown-linux-gnueabihf`: ARMv6 Linux, hardfloat +pub const ARM_UNKNOWN_LINUX_GNUEABIHF: Platform = Platform { + target_triple: "arm-unknown-linux-gnueabihf", + target_arch: Arch::ARM, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `arm-unknown-linux-musleabi`: ARMv6 Linux with MUSL +pub const ARM_UNKNOWN_LINUX_MUSLEABI: Platform = Platform { + target_triple: "arm-unknown-linux-musleabi", + target_arch: Arch::ARM, + target_os: OS::Linux, + target_env: Some(Env::Musl), + tier: Tier::Two, +}; + +/// `arm-unknown-linux-musleabihf`: ARMv6 Linux, MUSL, hardfloat +pub const ARM_UNKNOWN_LINUX_MUSLEABIHF: Platform = Platform { + target_triple: "arm-unknown-linux-musleabihf", + target_arch: Arch::ARM, + target_os: OS::Linux, + target_env: Some(Env::Musl), + tier: Tier::Two, +}; + +/// `armv5te-unknown-linux-gnueabi`: ARMv5TE Linux +pub const ARMV5TE_UNKNOWN_LINUX_GNUEABI: Platform = Platform { + target_triple: "armv5te-unknown-linux-gnueabi", + target_arch: Arch::ARM, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `armv7-apple-ios`: ARMv7 iOS, Cortex-a8 +pub const ARMV7_APPLE_IOS: Platform = Platform { + target_triple: "armv7-apple-ios", + target_arch: Arch::ARM, + target_os: OS::iOS, + target_env: None, + tier: Tier::Two, +}; + +/// `armv7-linux-androideabi`: ARMv7a Android +pub const ARMV7_LINUX_ANDROIDEABI: Platform = Platform { + target_triple: "armv7-linux-androideabi", + target_arch: Arch::ARM, + target_os: OS::Android, + target_env: None, + tier: Tier::Two, +}; + +/// `armv7-unknown-linux-gnueabihf`: ARMv7 Linux +pub const ARMV7_UNKNOWN_LINUX_GNUEABIHF: Platform = Platform { + target_triple: "armv7-unknown-linux-gnueabihf", + target_arch: Arch::ARM, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `armv7-unknown-linux-musleabihf`: ARMv7 Linux with MUSL +pub const ARMV7_UNKNOWN_LINUX_MUSLEABIHF: Platform = Platform { + target_triple: "armv7-unknown-linux-musleabihf", + target_arch: Arch::ARM, + target_os: OS::Linux, + target_env: Some(Env::Musl), + tier: Tier::Two, +}; + +/// `armv7s-apple-ios`: ARMv7 iOS, Cortex-a9 +pub const ARMV7S_APPLE_IOS: Platform = Platform { + target_triple: "armv7s-apple-ios", + target_arch: Arch::ARM, + target_os: OS::iOS, + target_env: None, + tier: Tier::Two, +}; + +/// `asmjs-unknown-emscripten`: asm.js via Emscripten +pub const ASMJS_UNKNOWN_EMSCRIPTEN: Platform = Platform { + target_triple: "asmjs-unknown-emscripten", + target_arch: Arch::ASMJS, + target_os: OS::Emscripten, + target_env: None, + tier: Tier::Two, +}; + +/// `i386-apple-ios`: 32-bit x86 iOS +pub const I386_APPLE_IOS: Platform = Platform { + target_triple: "i386-apple-ios", + target_arch: Arch::X86, + target_os: OS::iOS, + target_env: None, + tier: Tier::Two, +}; + +/// `i586-pc-windows-msvc`: 32-bit Windows w/o SSE +pub const I586_PC_WINDOWS_MSVC: Platform = Platform { + target_triple: "i586-pc-windows-msvc", + target_arch: Arch::X86, + target_os: OS::Windows, + target_env: Some(Env::MSVC), + tier: Tier::Two, +}; + +/// `i586-unknown-linux-gnu`: 32-bit Linux w/o SSE +pub const I586_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "i586-unknown-linux-gnu", + target_arch: Arch::X86, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `i586-unknown-linux-musl`: 32-bit Linux w/o SSE, MUSL +pub const I586_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "i586-unknown-linux-musl", + target_arch: Arch::X86, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `i686-linux-android`: 32-bit x86 Android +pub const I686_LINUX_ANDROID: Platform = Platform { + target_triple: "i686-linux-android", + target_arch: Arch::X86, + target_env: None, + target_os: OS::Android, + tier: Tier::Two, +}; + +/// `i686-unknown-freebsd`: 32-bit FreeBSD +pub const I686_UNKNOWN_FREEBSD: Platform = Platform { + target_triple: "i686-unknown-freebsd", + target_arch: Arch::X86, + target_os: OS::FreeBSD, + target_env: None, + tier: Tier::Two, +}; + +/// `i686-unknown-linux-musl`: 32-bit Linux with MUSL +pub const I686_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "i686-unknown-linux-musl", + target_arch: Arch::X86, + target_os: OS::Linux, + target_env: Some(Env::Musl), + tier: Tier::Two, +}; + +/// `mips-unknown-linux-gnu`: MIPS Linux +pub const MIPS_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "mips-unknown-linux-gnu", + target_arch: Arch::MIPS, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `mips-unknown-linux-musl`: MIPS Linux with MUSL +pub const MIPS_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "mips-unknown-linux-musl", + target_arch: Arch::MIPS, + target_os: OS::Linux, + target_env: Some(Env::Musl), + tier: Tier::Two, +}; + +/// `mips64-unknown-linux-gnuabi64`: MIPS64 Linux, n64 ABI +pub const MIPS64_UNKNOWN_LINUX_GNUABI64: Platform = Platform { + target_triple: "mips64-unknown-linux-gnuabi64", + target_arch: Arch::MIPS64, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `mips64el-unknown-linux-gnuabi64`: MIPS64 (LE) Linux, n64 ABI +pub const MIPS64EL_UNKNOWN_LINUX_GNUABI64: Platform = Platform { + target_triple: "mips64el-unknown-linux-gnuabi64", + target_arch: Arch::MIPS64, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `mipsel-unknown-linux-gnu`: MIPS (LE) Linux +pub const MIPSEL_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "mipsel-unknown-linux-gnu", + target_arch: Arch::MIPS, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `mipsel-unknown-linux-musl`: MIPS (LE) Linux with MUSL +pub const MIPSEL_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "mipsel-unknown-linux-musl", + target_arch: Arch::MIPS, + target_os: OS::Linux, + target_env: Some(Env::Musl), + tier: Tier::Two, +}; + +/// `powerpc-unknown-linux-gnu`: PowerPC Linux +pub const POWERPC_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "powerpc-unknown-linux-gnu", + target_arch: Arch::POWERPC, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `powerpc64-unknown-linux-gnu`: PPC64 Linux +pub const POWERPC64_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "powerpc64-unknown-linux-gnu", + target_arch: Arch::POWERPC64, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `powerpc64le-unknown-linux-gnu`: PPC64LE Linux +pub const POWERPC64LE_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "powerpc64le-unknown-linux-gnu", + target_arch: Arch::POWERPC64, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `s390x-unknown-linux-gnu`: S390x Linux +pub const S390X_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "s390x-unknown-linux-gnu", + target_arch: Arch::S390X, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `sparc64-unknown-linux-gnu`: SPARC Linux +pub const SPARC64_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "sparc64-unknown-linux-gnu", + target_arch: Arch::SPARC64, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `sparcv9-sun-solaris`: SPARC Solaris 10/11, illumos +pub const SPARC64_SUN_SOLARIS: Platform = Platform { + target_triple: "sparcv9-sun-solaris", + target_arch: Arch::SPARC64, + target_os: OS::Solaris, + target_env: None, + tier: Tier::Two, +}; + +/// `wasm32-unknown-unknown`: WebAssembly +pub const WASM_UNKNOWN_UNKNOWN: Platform = Platform { + target_triple: "wasm32-unknown-unknown", + target_arch: Arch::WASM32, + target_os: OS::Unknown, + target_env: None, + tier: Tier::Two, +}; + +/// `wasm32-unknown-emscripten`: WebAssembly via Emscripten +pub const WASM_UNKNOWN_EMSCRIPTEN: Platform = Platform { + target_triple: "wasm32-unknown-emscripten", + target_arch: Arch::WASM32, + target_os: OS::Emscripten, + target_env: None, + tier: Tier::Two, +}; + +/// `x86_64-apple-ios`: 64-bit x86 iOS +pub const X86_64_APPLE_IOS: Platform = Platform { + target_triple: "x86_64-apple-ios", + target_arch: Arch::X86_64, + target_env: None, + target_os: OS::iOS, + tier: Tier::Two, +}; + +/// `x86_64-fuchsia`: 64-bit x86 Fuchsia +pub const X86_64_FUCHSIA: Platform = Platform { + target_triple: "x86_64-fuchsia", + target_arch: Arch::X86_64, + target_os: OS::Fuchsia, + target_env: None, + tier: Tier::Two, +}; + +/// `x86_64-linux-android`: 64-bit x86 Android +pub const X86_64_LINUX_ANDROID: Platform = Platform { + target_triple: "x86_64-linux-android", + target_arch: Arch::X86_64, + target_env: None, + target_os: OS::Android, + tier: Tier::Two, +}; + +/// `x86_64-rumprun-netbsd`: 64-bit NetBSD Rump Kernel +pub const X86_64_RUMPRUN_NETBSD: Platform = Platform { + target_triple: "x86_64-rumprun-netbsd", + target_arch: Arch::X86_64, + target_env: None, + target_os: OS::NetBSD, + tier: Tier::Two, +}; + +/// `x86_64-sun-solaris`: 64-bit Solaris 10/11, illumos +pub const X86_64_SUN_SOLARIS: Platform = Platform { + target_triple: "x86_64-sun-solaris", + target_arch: Arch::X86_64, + target_os: OS::Solaris, + target_env: None, + tier: Tier::Two, +}; + +/// `x86_64-unknown-cloudabi`: 64-bit CloudABI +pub const X86_64_UNKNOWN_CLOUDABI: Platform = Platform { + target_triple: "x86_64-unknown-cloudabi", + target_arch: Arch::X86_64, + target_env: None, + target_os: OS::CloudABI, + tier: Tier::Two, +}; + +/// `x86_64-unknown-freebsd`: 64-bit FreeBSD +pub const X86_64_UNKNOWN_FREEBSD: Platform = Platform { + target_triple: "x86_64-unknown-freebsd", + target_arch: Arch::X86_64, + target_os: OS::FreeBSD, + target_env: None, + tier: Tier::Two, +}; + +/// `x86_64-unknown-linux-gnux32`: 64-bit Linux +pub const X86_64_UNKNOWN_LINUX_GNUX32: Platform = Platform { + target_triple: "x86_64-unknown-linux-gnux32", + target_arch: Arch::X86_64, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `x86_64-unknown-linux-musl`: 64-bit Linux with MUSL +pub const X86_64_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "x86_64-unknown-linux-musl", + target_arch: Arch::X86_64, + target_os: OS::Linux, + target_env: Some(Env::Musl), + tier: Tier::Two, +}; + +/// `x86_64-unknown-netbsd`: NetBSD/amd64 +pub const X86_64_UNKNOWN_NETBSD: Platform = Platform { + target_triple: "x86_64-unknown-netbsd", + target_arch: Arch::X86_64, + target_env: None, + target_os: OS::NetBSD, + tier: Tier::Two, +}; + +/// `x86_64-unknown-redox`: Redox OS +pub const X86_64_UNKNOWN_REDOX: Platform = Platform { + target_triple: "x86_64-unknown-redox", + target_arch: Arch::X86_64, + target_env: None, + target_os: OS::Redox, + tier: Tier::Two, +}; + +// +// Tier 2.5 platforms +// +// Tier 2.5 platforms can be thought of as “guaranteed to buildâ€, but without +// builds available through rustup. Automated tests are not run so it’s not +// guaranteed to produce a working build, but platforms often work to quite a +// good degree and patches are always welcome! Specifically, these platforms +// are required to have each of the following: +// +// - Automated building is set up, but may not be running tests. +// - Landing changes to the rust-lang/rust repository’s master branch is gated +// on platforms building. For some platforms only the standard library is +// compiled, but for others rustc and cargo are too. +// +// **This status is accidental: no new platforms should reach this state** +// + +/// `aarch64-unknown-cloudabi`: ARM64 CloudABI +pub const AARCH64_UNKNOWN_CLOUDABI: Platform = Platform { + target_triple: "aarch64-unknown-cloudabi", + target_arch: Arch::AARCH64, + target_os: OS::CloudABI, + target_env: None, + tier: Tier::Two, +}; + +/// `armv7-unknown-cloudabi-eabihf`: ARMv7 CloudABI, hardfloat +pub const ARMV7_UNKNOWN_CLOUDABI_EABIHF: Platform = Platform { + target_triple: "armv7-unknown-cloudabi-eabihf", + target_arch: Arch::ARM, + target_os: OS::CloudABI, + target_env: None, + tier: Tier::Two, +}; + +/// `i686-unknown-cloudabi`: 32-bit CloudABI +pub const I686_UNKNOWN_CLOUDABI: Platform = Platform { + target_triple: "i686-unknown-cloudabi", + target_arch: Arch::X86, + target_os: OS::CloudABI, + target_env: None, + tier: Tier::Two, +}; + +/// `powerpc-unknown-linux-gnuspe`: PowerPC SPE Linux +pub const POWERPC_UNKNOWN_LINUX_GNUSPE: Platform = Platform { + target_triple: "powerpc-unknown-linux-gnuspe", + target_arch: Arch::POWERPC, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; + +/// `sparc-unknown-linux-gnu`: 32-bit SPARC Linux +pub const SPARC_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "sparc-unknown-linux-gnu", + target_arch: Arch::SPARC, + target_os: OS::Linux, + target_env: Some(Env::GNU), + tier: Tier::Two, +}; diff --git a/vendor/platforms-1.1.0/src/platform/tier3.rs b/vendor/platforms-1.1.0/src/platform/tier3.rs new file mode 100644 index 0000000000000..519db6abf8b23 --- /dev/null +++ b/vendor/platforms-1.1.0/src/platform/tier3.rs @@ -0,0 +1,147 @@ +//! All Tier 3 platforms supported by Rust. Sourced from: +//! +//! +//! +//! Tier 3 platforms are those which the Rust codebase has support for, but +//! which are not built or tested automatically, and may not work. +//! Official builds are not available. + +use crate::{ + platform::{Platform, Tier}, + target::{Arch, Env, OS}, +}; + +/// `i686-unknown-haiku`: 32-bit Haiku +pub const I686_UNKNOWN_HAIKU: Platform = Platform { + target_triple: "i686-unknown-haiku", + target_arch: Arch::X86, + target_os: OS::Haiku, + target_env: None, + tier: Tier::Three, +}; + +/// `i686-unknown-netbsd`: NetBSD/i386 with SSE2 +pub const I686_UNKNOWN_NETBSD: Platform = Platform { + target_triple: "i686-unknown-netbsd", + target_arch: Arch::X86, + target_os: OS::NetBSD, + target_env: None, + tier: Tier::Three, +}; + +/// `mips-unknown-linux-uclibc`: MIPS Linux with uClibc +pub const MIPS_UNKNOWN_LINUX_UCLIBC: Platform = Platform { + target_triple: "mips-unknown-linux-uclibc", + target_arch: Arch::MIPS, + target_os: OS::Linux, + target_env: Some(Env::uClibc), + tier: Tier::Three, +}; + +/// `mipsel-unknown-linux-uclibc`: MIPS (LE) Linux with uClibc +pub const MIPSEL_UNKNOWN_LINUX_UCLIBC: Platform = Platform { + target_triple: "mipsel-unknown-linux-uclibc", + target_arch: Arch::MIPS, + target_os: OS::Linux, + target_env: Some(Env::uClibc), + tier: Tier::Three, +}; + +/// `msp430-none-elf`: 16-bit MSP430 microcontrollers +pub const MSP430_NONE_ELF: Platform = Platform { + target_triple: "msp430-none-elf", + target_arch: Arch::MSP430, + target_os: OS::Unknown, + target_env: None, + tier: Tier::Three, +}; + +/// `sparc64-unknown-netbsd`: NetBSD/sparc64 +pub const SPARC64_UNKNOWN_NETBSD: Platform = Platform { + target_triple: "sparc64-unknown-netbsd", + target_arch: Arch::SPARC64, + target_os: OS::NetBSD, + target_env: None, + tier: Tier::Three, +}; + +/// `thumbv6m-none-eabi`: Bare Cortex-M0, M0+, M1 +pub const THUMBV6M_NONE_EABI: Platform = Platform { + target_triple: "thumbv6m-none-eabi", + target_arch: Arch::THUMBV6, + target_os: OS::Unknown, + target_env: None, + tier: Tier::Three, +}; + +/// `thumbv7em-none-eabi`: Bare Cortex-M4, M7 +pub const THUMBV7EM_NONE_EABI: Platform = Platform { + target_triple: "thumbv7em-none-eabi", + target_arch: Arch::THUMBV7, + target_os: OS::Unknown, + target_env: None, + tier: Tier::Three, +}; + +/// `thumbv7em-none-eabihf`: Bare Cortex-M4F, M7F, FPU, hardfloat +pub const THUMBV7EM_NONE_EABIHF: Platform = Platform { + target_triple: "thumbv7em-none-eabihf", + target_arch: Arch::THUMBV7, + target_os: OS::Unknown, + target_env: None, + tier: Tier::Three, +}; + +/// `thumbv7m-none-eabi`: Bare Cortex-M3 +pub const THUMBV7M_NONE_EABI: Platform = Platform { + target_triple: "thumbv7m-none-eabi", + target_arch: Arch::THUMBV7, + target_os: OS::Unknown, + target_env: None, + tier: Tier::Three, +}; + +/// `x86_64-fortanix-unknown-sgx`: Fortanix ABI for 64-bit Intel SGX +pub const X86_64_FORTANIX_UNKNOWN_SGX: Platform = Platform { + target_triple: "x86_64-fortanix-unknown-sgx", + target_arch: Arch::X86_64, + target_os: OS::Unknown, + target_env: Some(Env::SGX), + tier: Tier::Three, +}; + +/// `x86_64-unknown-bitrig`: 64-bit Bitrig +pub const X86_64_UNKNOWN_BITRIG: Platform = Platform { + target_triple: "x86_64-unknown-bitrig", + target_arch: Arch::X86_64, + target_os: OS::Bitrig, + target_env: None, + tier: Tier::Three, +}; + +/// `x86_64-unknown-dragonfly`: 64-bit DragonFlyBSD +pub const X86_64_UNKNOWN_DRAGONFLY: Platform = Platform { + target_triple: "x86_64-unknown-dragonfly", + target_arch: Arch::X86_64, + target_os: OS::Dragonfly, + target_env: None, + tier: Tier::Three, +}; + +/// `x86_64-unknown-haiku`: 64-bit Haiku +pub const X86_64_UNKNOWN_HAIKU: Platform = Platform { + target_triple: "x86_64-unknown-haiku", + target_arch: Arch::X86_64, + target_os: OS::Haiku, + target_env: None, + tier: Tier::Three, +}; + +/// `x86_64-unknown-openbsd`: 64-bit OpenBSD +pub const X86_64_UNKNOWN_OPENBSD: Platform = Platform { + target_triple: "x86_64-unknown-openbsd", + target_arch: Arch::X86_64, + target_os: OS::OpenBSD, + target_env: None, + tier: Tier::Three, +}; diff --git a/vendor/platforms-1.1.0/src/target.rs b/vendor/platforms-1.1.0/src/target.rs new file mode 100644 index 0000000000000..b55dbb21e50b3 --- /dev/null +++ b/vendor/platforms-1.1.0/src/target.rs @@ -0,0 +1,14 @@ +//! Target `cfg` attributes. Documented in the "Conditional compilation" section +//! of the Rust reference: +//! +//! + +mod arch; +mod env; +mod os; + +pub use self::{ + arch::{Arch, TARGET_ARCH}, + env::{Env, TARGET_ENV}, + os::{OS, TARGET_OS}, +}; diff --git a/vendor/platforms/src/platform/platforms.rs b/vendor/platforms/src/platform/platforms.rs new file mode 100644 index 0000000000000..03850ab554bb8 --- /dev/null +++ b/vendor/platforms/src/platform/platforms.rs @@ -0,0 +1,2606 @@ +//! The list of targets. + +// Note: this file is auto-generated. Do not edit it manually! +// If you need to referesh it, re-run the generator included in the source tree. + +// Comments on targets are sourced from +// https://doc.rust-lang.org/nightly/rustc/platform-support.html +// and some of the more obscure targets do not have a comment on them +#![allow(missing_docs)] + +use crate::{ + platform::{Platform, Tier}, + target::{Arch, Endian, Env, PointerWidth, OS}, +}; + +/// The list of all targets recognized by the Rust compiler +pub(crate) const ALL: &[Platform] = &[ + AARCH64_APPLE_DARWIN, + AARCH64_APPLE_IOS, + AARCH64_APPLE_IOS_MACABI, + AARCH64_APPLE_IOS_SIM, + AARCH64_APPLE_TVOS, + AARCH64_APPLE_WATCHOS_SIM, + AARCH64_FUCHSIA, + AARCH64_KMC_SOLID_ASP3, + AARCH64_LINUX_ANDROID, + AARCH64_NINTENDO_SWITCH_FREESTANDING, + AARCH64_PC_WINDOWS_GNULLVM, + AARCH64_PC_WINDOWS_MSVC, + AARCH64_UNKNOWN_FREEBSD, + AARCH64_UNKNOWN_FUCHSIA, + AARCH64_UNKNOWN_HERMIT, + AARCH64_UNKNOWN_LINUX_GNU, + AARCH64_UNKNOWN_LINUX_GNU_ILP32, + AARCH64_UNKNOWN_LINUX_MUSL, + AARCH64_UNKNOWN_LINUX_OHOS, + AARCH64_UNKNOWN_NETBSD, + AARCH64_UNKNOWN_NONE, + AARCH64_UNKNOWN_NONE_SOFTFLOAT, + AARCH64_UNKNOWN_NTO_QNX710, + AARCH64_UNKNOWN_OPENBSD, + AARCH64_UNKNOWN_REDOX, + AARCH64_UNKNOWN_TEEOS, + AARCH64_UNKNOWN_UEFI, + AARCH64_UWP_WINDOWS_MSVC, + AARCH64_WRS_VXWORKS, + AARCH64_BE_UNKNOWN_LINUX_GNU, + AARCH64_BE_UNKNOWN_LINUX_GNU_ILP32, + AARCH64_BE_UNKNOWN_NETBSD, + ARM_LINUX_ANDROIDEABI, + ARM_UNKNOWN_LINUX_GNUEABI, + ARM_UNKNOWN_LINUX_GNUEABIHF, + ARM_UNKNOWN_LINUX_MUSLEABI, + ARM_UNKNOWN_LINUX_MUSLEABIHF, + ARM64_32_APPLE_WATCHOS, + ARMEB_UNKNOWN_LINUX_GNUEABI, + ARMEBV7R_NONE_EABI, + ARMEBV7R_NONE_EABIHF, + ARMV4T_NONE_EABI, + ARMV4T_UNKNOWN_LINUX_GNUEABI, + ARMV5TE_NONE_EABI, + ARMV5TE_UNKNOWN_LINUX_GNUEABI, + ARMV5TE_UNKNOWN_LINUX_MUSLEABI, + ARMV5TE_UNKNOWN_LINUX_UCLIBCEABI, + ARMV6_UNKNOWN_FREEBSD, + ARMV6_UNKNOWN_NETBSD_EABIHF, + ARMV6K_NINTENDO_3DS, + ARMV7_APPLE_IOS, + ARMV7_LINUX_ANDROIDEABI, + ARMV7_SONY_VITA_NEWLIBEABIHF, + ARMV7_UNKNOWN_FREEBSD, + ARMV7_UNKNOWN_LINUX_GNUEABI, + ARMV7_UNKNOWN_LINUX_GNUEABIHF, + ARMV7_UNKNOWN_LINUX_MUSLEABI, + ARMV7_UNKNOWN_LINUX_MUSLEABIHF, + ARMV7_UNKNOWN_LINUX_OHOS, + ARMV7_UNKNOWN_LINUX_UCLIBCEABI, + ARMV7_UNKNOWN_LINUX_UCLIBCEABIHF, + ARMV7_UNKNOWN_NETBSD_EABIHF, + ARMV7_WRS_VXWORKS_EABIHF, + ARMV7A_KMC_SOLID_ASP3_EABI, + ARMV7A_KMC_SOLID_ASP3_EABIHF, + ARMV7A_NONE_EABI, + ARMV7A_NONE_EABIHF, + ARMV7K_APPLE_WATCHOS, + ARMV7R_NONE_EABI, + ARMV7R_NONE_EABIHF, + ARMV7S_APPLE_IOS, + ASMJS_UNKNOWN_EMSCRIPTEN, + AVR_UNKNOWN_GNU_ATMEGA328, + BPFEB_UNKNOWN_NONE, + BPFEL_UNKNOWN_NONE, + CSKY_UNKNOWN_LINUX_GNUABIV2, + HEXAGON_UNKNOWN_LINUX_MUSL, + I386_APPLE_IOS, + I586_PC_NTO_QNX700, + I586_PC_WINDOWS_MSVC, + I586_UNKNOWN_LINUX_GNU, + I586_UNKNOWN_LINUX_MUSL, + I686_APPLE_DARWIN, + I686_LINUX_ANDROID, + I686_PC_WINDOWS_GNU, + I686_PC_WINDOWS_MSVC, + I686_UNKNOWN_FREEBSD, + I686_UNKNOWN_HAIKU, + I686_UNKNOWN_LINUX_GNU, + I686_UNKNOWN_LINUX_MUSL, + I686_UNKNOWN_NETBSD, + I686_UNKNOWN_OPENBSD, + I686_UNKNOWN_UEFI, + I686_UWP_WINDOWS_GNU, + I686_UWP_WINDOWS_MSVC, + I686_WRS_VXWORKS, + LOONGARCH64_UNKNOWN_LINUX_GNU, + LOONGARCH64_UNKNOWN_NONE, + LOONGARCH64_UNKNOWN_NONE_SOFTFLOAT, + M68K_UNKNOWN_LINUX_GNU, + MIPS_UNKNOWN_LINUX_GNU, + MIPS_UNKNOWN_LINUX_MUSL, + MIPS_UNKNOWN_LINUX_UCLIBC, + MIPS64_OPENWRT_LINUX_MUSL, + MIPS64_UNKNOWN_LINUX_GNUABI64, + MIPS64_UNKNOWN_LINUX_MUSLABI64, + MIPS64EL_UNKNOWN_LINUX_GNUABI64, + MIPS64EL_UNKNOWN_LINUX_MUSLABI64, + MIPSEL_SONY_PSP, + MIPSEL_SONY_PSX, + MIPSEL_UNKNOWN_LINUX_GNU, + MIPSEL_UNKNOWN_LINUX_MUSL, + MIPSEL_UNKNOWN_LINUX_UCLIBC, + MIPSEL_UNKNOWN_NONE, + MIPSISA32R6_UNKNOWN_LINUX_GNU, + MIPSISA32R6EL_UNKNOWN_LINUX_GNU, + MIPSISA64R6_UNKNOWN_LINUX_GNUABI64, + MIPSISA64R6EL_UNKNOWN_LINUX_GNUABI64, + MSP430_NONE_ELF, + NVPTX64_NVIDIA_CUDA, + POWERPC_UNKNOWN_FREEBSD, + POWERPC_UNKNOWN_LINUX_GNU, + POWERPC_UNKNOWN_LINUX_GNUSPE, + POWERPC_UNKNOWN_LINUX_MUSL, + POWERPC_UNKNOWN_NETBSD, + POWERPC_UNKNOWN_OPENBSD, + POWERPC_WRS_VXWORKS, + POWERPC_WRS_VXWORKS_SPE, + POWERPC64_IBM_AIX, + POWERPC64_UNKNOWN_FREEBSD, + POWERPC64_UNKNOWN_LINUX_GNU, + POWERPC64_UNKNOWN_LINUX_MUSL, + POWERPC64_UNKNOWN_OPENBSD, + POWERPC64_WRS_VXWORKS, + POWERPC64LE_UNKNOWN_FREEBSD, + POWERPC64LE_UNKNOWN_LINUX_GNU, + POWERPC64LE_UNKNOWN_LINUX_MUSL, + RISCV32GC_UNKNOWN_LINUX_GNU, + RISCV32GC_UNKNOWN_LINUX_MUSL, + RISCV32I_UNKNOWN_NONE_ELF, + RISCV32IM_UNKNOWN_NONE_ELF, + RISCV32IMAC_ESP_ESPIDF, + RISCV32IMAC_UNKNOWN_NONE_ELF, + RISCV32IMAC_UNKNOWN_XOUS_ELF, + RISCV32IMC_ESP_ESPIDF, + RISCV32IMC_UNKNOWN_NONE_ELF, + RISCV64_LINUX_ANDROID, + RISCV64GC_UNKNOWN_FREEBSD, + RISCV64GC_UNKNOWN_FUCHSIA, + RISCV64GC_UNKNOWN_HERMIT, + RISCV64GC_UNKNOWN_LINUX_GNU, + RISCV64GC_UNKNOWN_LINUX_MUSL, + RISCV64GC_UNKNOWN_NETBSD, + RISCV64GC_UNKNOWN_NONE_ELF, + RISCV64GC_UNKNOWN_OPENBSD, + RISCV64IMAC_UNKNOWN_NONE_ELF, + S390X_UNKNOWN_LINUX_GNU, + S390X_UNKNOWN_LINUX_MUSL, + SPARC_UNKNOWN_LINUX_GNU, + SPARC_UNKNOWN_NONE_ELF, + SPARC64_UNKNOWN_LINUX_GNU, + SPARC64_UNKNOWN_NETBSD, + SPARC64_UNKNOWN_OPENBSD, + SPARCV9_SUN_SOLARIS, + THUMBV4T_NONE_EABI, + THUMBV5TE_NONE_EABI, + THUMBV6M_NONE_EABI, + THUMBV7A_PC_WINDOWS_MSVC, + THUMBV7A_UWP_WINDOWS_MSVC, + THUMBV7EM_NONE_EABI, + THUMBV7EM_NONE_EABIHF, + THUMBV7M_NONE_EABI, + THUMBV7NEON_LINUX_ANDROIDEABI, + THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF, + THUMBV7NEON_UNKNOWN_LINUX_MUSLEABIHF, + THUMBV8M_BASE_NONE_EABI, + THUMBV8M_MAIN_NONE_EABI, + THUMBV8M_MAIN_NONE_EABIHF, + WASM32_UNKNOWN_EMSCRIPTEN, + WASM32_UNKNOWN_UNKNOWN, + WASM32_WASI, + WASM32_WASI_PREVIEW1_THREADS, + WASM64_UNKNOWN_UNKNOWN, + X86_64_APPLE_DARWIN, + X86_64_APPLE_IOS, + X86_64_APPLE_IOS_MACABI, + X86_64_APPLE_TVOS, + X86_64_APPLE_WATCHOS_SIM, + X86_64_FORTANIX_UNKNOWN_SGX, + X86_64_FUCHSIA, + X86_64_LINUX_ANDROID, + X86_64_PC_NTO_QNX710, + X86_64_PC_SOLARIS, + X86_64_PC_WINDOWS_GNU, + X86_64_PC_WINDOWS_GNULLVM, + X86_64_PC_WINDOWS_MSVC, + X86_64_SUN_SOLARIS, + X86_64_UNIKRAFT_LINUX_MUSL, + X86_64_UNKNOWN_DRAGONFLY, + X86_64_UNKNOWN_FREEBSD, + X86_64_UNKNOWN_FUCHSIA, + X86_64_UNKNOWN_HAIKU, + X86_64_UNKNOWN_HERMIT, + X86_64_UNKNOWN_ILLUMOS, + X86_64_UNKNOWN_L4RE_UCLIBC, + X86_64_UNKNOWN_LINUX_GNU, + X86_64_UNKNOWN_LINUX_GNUX32, + X86_64_UNKNOWN_LINUX_MUSL, + X86_64_UNKNOWN_LINUX_OHOS, + X86_64_UNKNOWN_NETBSD, + X86_64_UNKNOWN_NONE, + X86_64_UNKNOWN_OPENBSD, + X86_64_UNKNOWN_REDOX, + X86_64_UNKNOWN_UEFI, + X86_64_UWP_WINDOWS_GNU, + X86_64_UWP_WINDOWS_MSVC, + X86_64_WRS_VXWORKS, + X86_64H_APPLE_DARWIN, +]; + +/// ARM64 macOS (11.0+, Big Sur+) +pub(crate) const AARCH64_APPLE_DARWIN: Platform = Platform { + target_triple: "aarch64-apple-darwin", + target_arch: Arch::AArch64, + target_os: OS::MacOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// ARM64 iOS +pub(crate) const AARCH64_APPLE_IOS: Platform = Platform { + target_triple: "aarch64-apple-ios", + target_arch: Arch::AArch64, + target_os: OS::iOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// Apple Catalyst on ARM64 +pub(crate) const AARCH64_APPLE_IOS_MACABI: Platform = Platform { + target_triple: "aarch64-apple-ios-macabi", + target_arch: Arch::AArch64, + target_os: OS::iOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// Apple iOS Simulator on ARM64 +pub(crate) const AARCH64_APPLE_IOS_SIM: Platform = Platform { + target_triple: "aarch64-apple-ios-sim", + target_arch: Arch::AArch64, + target_os: OS::iOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// ARM64 tvOS +pub(crate) const AARCH64_APPLE_TVOS: Platform = Platform { + target_triple: "aarch64-apple-tvos", + target_arch: Arch::AArch64, + target_os: OS::TvOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// ARM64 Apple WatchOS Simulator +pub(crate) const AARCH64_APPLE_WATCHOS_SIM: Platform = Platform { + target_triple: "aarch64-apple-watchos-sim", + target_arch: Arch::AArch64, + target_os: OS::WatchOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// Alias for `aarch64-unknown-fuchsia` +pub(crate) const AARCH64_FUCHSIA: Platform = Platform { + target_triple: "aarch64-fuchsia", + target_arch: Arch::AArch64, + target_os: OS::Fuchsia, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// ARM64 SOLID with TOPPERS/ASP3 +pub(crate) const AARCH64_KMC_SOLID_ASP3: Platform = Platform { + target_triple: "aarch64-kmc-solid_asp3", + target_arch: Arch::AArch64, + target_os: OS::SolidAsp3, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// ARM64 Android +pub(crate) const AARCH64_LINUX_ANDROID: Platform = Platform { + target_triple: "aarch64-linux-android", + target_arch: Arch::AArch64, + target_os: OS::Android, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// ARM64 Nintendo Switch, Horizon +pub(crate) const AARCH64_NINTENDO_SWITCH_FREESTANDING: Platform = Platform { + target_triple: "aarch64-nintendo-switch-freestanding", + target_arch: Arch::AArch64, + target_os: OS::Horizon, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +pub(crate) const AARCH64_PC_WINDOWS_GNULLVM: Platform = Platform { + target_triple: "aarch64-pc-windows-gnullvm", + target_arch: Arch::AArch64, + target_os: OS::Windows, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// ARM64 Windows MSVC +pub(crate) const AARCH64_PC_WINDOWS_MSVC: Platform = Platform { + target_triple: "aarch64-pc-windows-msvc", + target_arch: Arch::AArch64, + target_os: OS::Windows, + target_env: Env::Msvc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// ARM64 FreeBSD +pub(crate) const AARCH64_UNKNOWN_FREEBSD: Platform = Platform { + target_triple: "aarch64-unknown-freebsd", + target_arch: Arch::AArch64, + target_os: OS::FreeBSD, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// ARM64 Fuchsia +pub(crate) const AARCH64_UNKNOWN_FUCHSIA: Platform = Platform { + target_triple: "aarch64-unknown-fuchsia", + target_arch: Arch::AArch64, + target_os: OS::Fuchsia, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// ARM64 Hermit +pub(crate) const AARCH64_UNKNOWN_HERMIT: Platform = Platform { + target_triple: "aarch64-unknown-hermit", + target_arch: Arch::AArch64, + target_os: OS::Hermit, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// ARM64 Linux (kernel 4.1, glibc 2.17+) [^missing-stack-probes] +pub(crate) const AARCH64_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "aarch64-unknown-linux-gnu", + target_arch: Arch::AArch64, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::One, +}; + +/// ARM64 Linux (ILP32 ABI) +pub(crate) const AARCH64_UNKNOWN_LINUX_GNU_ILP32: Platform = Platform { + target_triple: "aarch64-unknown-linux-gnu_ilp32", + target_arch: Arch::AArch64, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARM64 Linux with MUSL +pub(crate) const AARCH64_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "aarch64-unknown-linux-musl", + target_arch: Arch::AArch64, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +pub(crate) const AARCH64_UNKNOWN_LINUX_OHOS: Platform = Platform { + target_triple: "aarch64-unknown-linux-ohos", + target_arch: Arch::AArch64, + target_os: OS::Linux, + target_env: Env::OhOS, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// ARM64 NetBSD +pub(crate) const AARCH64_UNKNOWN_NETBSD: Platform = Platform { + target_triple: "aarch64-unknown-netbsd", + target_arch: Arch::AArch64, + target_os: OS::NetBSD, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// Bare ARM64, hardfloat +pub(crate) const AARCH64_UNKNOWN_NONE: Platform = Platform { + target_triple: "aarch64-unknown-none", + target_arch: Arch::AArch64, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// Bare ARM64, softfloat +pub(crate) const AARCH64_UNKNOWN_NONE_SOFTFLOAT: Platform = Platform { + target_triple: "aarch64-unknown-none-softfloat", + target_arch: Arch::AArch64, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +pub(crate) const AARCH64_UNKNOWN_NTO_QNX710: Platform = Platform { + target_triple: "aarch64-unknown-nto-qnx710", + target_arch: Arch::AArch64, + target_os: OS::Nto, + target_env: Env::Nto71, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// ARM64 OpenBSD +pub(crate) const AARCH64_UNKNOWN_OPENBSD: Platform = Platform { + target_triple: "aarch64-unknown-openbsd", + target_arch: Arch::AArch64, + target_os: OS::OpenBSD, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// ARM64 Redox OS +pub(crate) const AARCH64_UNKNOWN_REDOX: Platform = Platform { + target_triple: "aarch64-unknown-redox", + target_arch: Arch::AArch64, + target_os: OS::Redox, + target_env: Env::Relibc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +pub(crate) const AARCH64_UNKNOWN_TEEOS: Platform = Platform { + target_triple: "aarch64-unknown-teeos", + target_arch: Arch::AArch64, + target_os: OS::TeeOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// ARM64 UEFI +pub(crate) const AARCH64_UNKNOWN_UEFI: Platform = Platform { + target_triple: "aarch64-unknown-uefi", + target_arch: Arch::AArch64, + target_os: OS::Uefi, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +pub(crate) const AARCH64_UWP_WINDOWS_MSVC: Platform = Platform { + target_triple: "aarch64-uwp-windows-msvc", + target_arch: Arch::AArch64, + target_os: OS::Windows, + target_env: Env::Msvc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +pub(crate) const AARCH64_WRS_VXWORKS: Platform = Platform { + target_triple: "aarch64-wrs-vxworks", + target_arch: Arch::AArch64, + target_os: OS::VxWorks, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// ARM64 Linux (big-endian) +pub(crate) const AARCH64_BE_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "aarch64_be-unknown-linux-gnu", + target_arch: Arch::AArch64, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// ARM64 Linux (big-endian, ILP32 ABI) +pub(crate) const AARCH64_BE_UNKNOWN_LINUX_GNU_ILP32: Platform = Platform { + target_triple: "aarch64_be-unknown-linux-gnu_ilp32", + target_arch: Arch::AArch64, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARM64 NetBSD (big-endian) +pub(crate) const AARCH64_BE_UNKNOWN_NETBSD: Platform = Platform { + target_triple: "aarch64_be-unknown-netbsd", + target_arch: Arch::AArch64, + target_os: OS::NetBSD, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// ARMv6 Android +pub(crate) const ARM_LINUX_ANDROIDEABI: Platform = Platform { + target_triple: "arm-linux-androideabi", + target_arch: Arch::Arm, + target_os: OS::Android, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// ARMv6 Linux (kernel 3.2, glibc 2.17) +pub(crate) const ARM_UNKNOWN_LINUX_GNUEABI: Platform = Platform { + target_triple: "arm-unknown-linux-gnueabi", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17) +pub(crate) const ARM_UNKNOWN_LINUX_GNUEABIHF: Platform = Platform { + target_triple: "arm-unknown-linux-gnueabihf", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// ARMv6 Linux with MUSL +pub(crate) const ARM_UNKNOWN_LINUX_MUSLEABI: Platform = Platform { + target_triple: "arm-unknown-linux-musleabi", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// ARMv6 Linux with MUSL, hardfloat +pub(crate) const ARM_UNKNOWN_LINUX_MUSLEABIHF: Platform = Platform { + target_triple: "arm-unknown-linux-musleabihf", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// ARM Apple WatchOS 64-bit with 32-bit pointers +pub(crate) const ARM64_32_APPLE_WATCHOS: Platform = Platform { + target_triple: "arm64_32-apple-watchos", + target_arch: Arch::AArch64, + target_os: OS::WatchOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARM BE8 the default ARM big-endian architecture since [ARMv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en). +pub(crate) const ARMEB_UNKNOWN_LINUX_GNUEABI: Platform = Platform { + target_triple: "armeb-unknown-linux-gnueabi", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// Bare ARMv7-R, Big Endian +pub(crate) const ARMEBV7R_NONE_EABI: Platform = Platform { + target_triple: "armebv7r-none-eabi", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// Bare ARMv7-R, Big Endian, hardfloat +pub(crate) const ARMEBV7R_NONE_EABIHF: Platform = Platform { + target_triple: "armebv7r-none-eabihf", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// Bare ARMv4T +pub(crate) const ARMV4T_NONE_EABI: Platform = Platform { + target_triple: "armv4t-none-eabi", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv4T Linux +pub(crate) const ARMV4T_UNKNOWN_LINUX_GNUEABI: Platform = Platform { + target_triple: "armv4t-unknown-linux-gnueabi", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// Bare ARMv5TE +pub(crate) const ARMV5TE_NONE_EABI: Platform = Platform { + target_triple: "armv5te-none-eabi", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv5TE Linux (kernel 4.4, glibc 2.23) +pub(crate) const ARMV5TE_UNKNOWN_LINUX_GNUEABI: Platform = Platform { + target_triple: "armv5te-unknown-linux-gnueabi", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// ARMv5TE Linux with MUSL +pub(crate) const ARMV5TE_UNKNOWN_LINUX_MUSLEABI: Platform = Platform { + target_triple: "armv5te-unknown-linux-musleabi", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// ARMv5TE Linux with uClibc +pub(crate) const ARMV5TE_UNKNOWN_LINUX_UCLIBCEABI: Platform = Platform { + target_triple: "armv5te-unknown-linux-uclibceabi", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::UClibc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv6 FreeBSD +pub(crate) const ARMV6_UNKNOWN_FREEBSD: Platform = Platform { + target_triple: "armv6-unknown-freebsd", + target_arch: Arch::Arm, + target_os: OS::FreeBSD, + target_env: Env::Gnueabihf, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv6 NetBSD w/hard-float +pub(crate) const ARMV6_UNKNOWN_NETBSD_EABIHF: Platform = Platform { + target_triple: "armv6-unknown-netbsd-eabihf", + target_arch: Arch::Arm, + target_os: OS::NetBSD, + target_env: Env::Eabihf, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain) +pub(crate) const ARMV6K_NINTENDO_3DS: Platform = Platform { + target_triple: "armv6k-nintendo-3ds", + target_arch: Arch::Arm, + target_os: OS::Horizon, + target_env: Env::Newlib, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv7-A Cortex-A8 iOS +pub(crate) const ARMV7_APPLE_IOS: Platform = Platform { + target_triple: "armv7-apple-ios", + target_arch: Arch::Arm, + target_os: OS::iOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv7-A Android +pub(crate) const ARMV7_LINUX_ANDROIDEABI: Platform = Platform { + target_triple: "armv7-linux-androideabi", + target_arch: Arch::Arm, + target_os: OS::Android, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// ARMv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain) +pub(crate) const ARMV7_SONY_VITA_NEWLIBEABIHF: Platform = Platform { + target_triple: "armv7-sony-vita-newlibeabihf", + target_arch: Arch::Arm, + target_os: OS::Vita, + target_env: Env::Newlib, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv7-A FreeBSD +pub(crate) const ARMV7_UNKNOWN_FREEBSD: Platform = Platform { + target_triple: "armv7-unknown-freebsd", + target_arch: Arch::Arm, + target_os: OS::FreeBSD, + target_env: Env::Gnueabihf, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv7-A Linux (kernel 4.15, glibc 2.27) +pub(crate) const ARMV7_UNKNOWN_LINUX_GNUEABI: Platform = Platform { + target_triple: "armv7-unknown-linux-gnueabi", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// ARMv7-A Linux, hardfloat (kernel 3.2, glibc 2.17) +pub(crate) const ARMV7_UNKNOWN_LINUX_GNUEABIHF: Platform = Platform { + target_triple: "armv7-unknown-linux-gnueabihf", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// ARMv7-A Linux with MUSL +pub(crate) const ARMV7_UNKNOWN_LINUX_MUSLEABI: Platform = Platform { + target_triple: "armv7-unknown-linux-musleabi", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// ARMv7-A Linux with MUSL, hardfloat +pub(crate) const ARMV7_UNKNOWN_LINUX_MUSLEABIHF: Platform = Platform { + target_triple: "armv7-unknown-linux-musleabihf", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +pub(crate) const ARMV7_UNKNOWN_LINUX_OHOS: Platform = Platform { + target_triple: "armv7-unknown-linux-ohos", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::OhOS, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv7-A Linux with uClibc, softfloat +pub(crate) const ARMV7_UNKNOWN_LINUX_UCLIBCEABI: Platform = Platform { + target_triple: "armv7-unknown-linux-uclibceabi", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::UClibc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv7-A Linux with uClibc, hardfloat +pub(crate) const ARMV7_UNKNOWN_LINUX_UCLIBCEABIHF: Platform = Platform { + target_triple: "armv7-unknown-linux-uclibceabihf", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::UClibc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv7-A NetBSD w/hard-float +pub(crate) const ARMV7_UNKNOWN_NETBSD_EABIHF: Platform = Platform { + target_triple: "armv7-unknown-netbsd-eabihf", + target_arch: Arch::Arm, + target_os: OS::NetBSD, + target_env: Env::Eabihf, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv7-A for VxWorks +pub(crate) const ARMV7_WRS_VXWORKS_EABIHF: Platform = Platform { + target_triple: "armv7-wrs-vxworks-eabihf", + target_arch: Arch::Arm, + target_os: OS::VxWorks, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARM SOLID with TOPPERS/ASP3 +pub(crate) const ARMV7A_KMC_SOLID_ASP3_EABI: Platform = Platform { + target_triple: "armv7a-kmc-solid_asp3-eabi", + target_arch: Arch::Arm, + target_os: OS::SolidAsp3, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARM SOLID with TOPPERS/ASP3, hardfloat +pub(crate) const ARMV7A_KMC_SOLID_ASP3_EABIHF: Platform = Platform { + target_triple: "armv7a-kmc-solid_asp3-eabihf", + target_arch: Arch::Arm, + target_os: OS::SolidAsp3, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// Bare ARMv7-A +pub(crate) const ARMV7A_NONE_EABI: Platform = Platform { + target_triple: "armv7a-none-eabi", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// Bare ARMv7-A, hardfloat +pub(crate) const ARMV7A_NONE_EABIHF: Platform = Platform { + target_triple: "armv7a-none-eabihf", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// ARMv7-A Apple WatchOS +pub(crate) const ARMV7K_APPLE_WATCHOS: Platform = Platform { + target_triple: "armv7k-apple-watchos", + target_arch: Arch::Arm, + target_os: OS::WatchOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// Bare ARMv7-R +pub(crate) const ARMV7R_NONE_EABI: Platform = Platform { + target_triple: "armv7r-none-eabi", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// Bare ARMv7-R, hardfloat +pub(crate) const ARMV7R_NONE_EABIHF: Platform = Platform { + target_triple: "armv7r-none-eabihf", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// ARMv7-A Apple-A6 Apple iOS +pub(crate) const ARMV7S_APPLE_IOS: Platform = Platform { + target_triple: "armv7s-apple-ios", + target_arch: Arch::Arm, + target_os: OS::iOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// asm.js via Emscripten +pub(crate) const ASMJS_UNKNOWN_EMSCRIPTEN: Platform = Platform { + target_triple: "asmjs-unknown-emscripten", + target_arch: Arch::Wasm32, + target_os: OS::Emscripten, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// AVR. Requires `-Z build-std=core` +pub(crate) const AVR_UNKNOWN_GNU_ATMEGA328: Platform = Platform { + target_triple: "avr-unknown-gnu-atmega328", + target_arch: Arch::Avr, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U16, + tier: Tier::Three, +}; + +/// BPF (big endian) +pub(crate) const BPFEB_UNKNOWN_NONE: Platform = Platform { + target_triple: "bpfeb-unknown-none", + target_arch: Arch::Bpf, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// BPF (little endian) +pub(crate) const BPFEL_UNKNOWN_NONE: Platform = Platform { + target_triple: "bpfel-unknown-none", + target_arch: Arch::Bpf, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// C-SKY abiv2 Linux(little endian) +pub(crate) const CSKY_UNKNOWN_LINUX_GNUABIV2: Platform = Platform { + target_triple: "csky-unknown-linux-gnuabiv2", + target_arch: Arch::Csky, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +pub(crate) const HEXAGON_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "hexagon-unknown-linux-musl", + target_arch: Arch::Hexagon, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// 32-bit x86 iOS +pub(crate) const I386_APPLE_IOS: Platform = Platform { + target_triple: "i386-apple-ios", + target_arch: Arch::X86, + target_os: OS::iOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +pub(crate) const I586_PC_NTO_QNX700: Platform = Platform { + target_triple: "i586-pc-nto-qnx700", + target_arch: Arch::X86, + target_os: OS::Nto, + target_env: Env::Nto70, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// 32-bit Windows w/o SSE +pub(crate) const I586_PC_WINDOWS_MSVC: Platform = Platform { + target_triple: "i586-pc-windows-msvc", + target_arch: Arch::X86, + target_os: OS::Windows, + target_env: Env::Msvc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// 32-bit Linux w/o SSE (kernel 3.2, glibc 2.17) +pub(crate) const I586_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "i586-unknown-linux-gnu", + target_arch: Arch::X86, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// 32-bit Linux w/o SSE, MUSL +pub(crate) const I586_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "i586-unknown-linux-musl", + target_arch: Arch::X86, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// 32-bit macOS (10.7+, Lion+) +pub(crate) const I686_APPLE_DARWIN: Platform = Platform { + target_triple: "i686-apple-darwin", + target_arch: Arch::X86, + target_os: OS::MacOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// 32-bit x86 Android +pub(crate) const I686_LINUX_ANDROID: Platform = Platform { + target_triple: "i686-linux-android", + target_arch: Arch::X86, + target_os: OS::Android, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// 32-bit MinGW (Windows 7+) [^windows-support] +pub(crate) const I686_PC_WINDOWS_GNU: Platform = Platform { + target_triple: "i686-pc-windows-gnu", + target_arch: Arch::X86, + target_os: OS::Windows, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::One, +}; + +/// 32-bit MSVC (Windows 7+) [^windows-support] +pub(crate) const I686_PC_WINDOWS_MSVC: Platform = Platform { + target_triple: "i686-pc-windows-msvc", + target_arch: Arch::X86, + target_os: OS::Windows, + target_env: Env::Msvc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::One, +}; + +/// 32-bit FreeBSD +pub(crate) const I686_UNKNOWN_FREEBSD: Platform = Platform { + target_triple: "i686-unknown-freebsd", + target_arch: Arch::X86, + target_os: OS::FreeBSD, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// 32-bit Haiku +pub(crate) const I686_UNKNOWN_HAIKU: Platform = Platform { + target_triple: "i686-unknown-haiku", + target_arch: Arch::X86, + target_os: OS::Haiku, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// 32-bit Linux (kernel 3.2+, glibc 2.17+) +pub(crate) const I686_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "i686-unknown-linux-gnu", + target_arch: Arch::X86, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::One, +}; + +/// 32-bit Linux with MUSL +pub(crate) const I686_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "i686-unknown-linux-musl", + target_arch: Arch::X86, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// NetBSD/i386 with SSE2 +pub(crate) const I686_UNKNOWN_NETBSD: Platform = Platform { + target_triple: "i686-unknown-netbsd", + target_arch: Arch::X86, + target_os: OS::NetBSD, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// 32-bit OpenBSD +pub(crate) const I686_UNKNOWN_OPENBSD: Platform = Platform { + target_triple: "i686-unknown-openbsd", + target_arch: Arch::X86, + target_os: OS::OpenBSD, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// 32-bit UEFI +pub(crate) const I686_UNKNOWN_UEFI: Platform = Platform { + target_triple: "i686-unknown-uefi", + target_arch: Arch::X86, + target_os: OS::Uefi, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +pub(crate) const I686_UWP_WINDOWS_GNU: Platform = Platform { + target_triple: "i686-uwp-windows-gnu", + target_arch: Arch::X86, + target_os: OS::Windows, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +pub(crate) const I686_UWP_WINDOWS_MSVC: Platform = Platform { + target_triple: "i686-uwp-windows-msvc", + target_arch: Arch::X86, + target_os: OS::Windows, + target_env: Env::Msvc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +pub(crate) const I686_WRS_VXWORKS: Platform = Platform { + target_triple: "i686-wrs-vxworks", + target_arch: Arch::X86, + target_os: OS::VxWorks, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) +pub(crate) const LOONGARCH64_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "loongarch64-unknown-linux-gnu", + target_arch: Arch::Loongarch64, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// LoongArch64 Bare-metal (LP64D ABI) +pub(crate) const LOONGARCH64_UNKNOWN_NONE: Platform = Platform { + target_triple: "loongarch64-unknown-none", + target_arch: Arch::Loongarch64, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// LoongArch64 Bare-metal (LP64S ABI) +pub(crate) const LOONGARCH64_UNKNOWN_NONE_SOFTFLOAT: Platform = Platform { + target_triple: "loongarch64-unknown-none-softfloat", + target_arch: Arch::Loongarch64, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// Motorola 680x0 Linux +pub(crate) const M68K_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "m68k-unknown-linux-gnu", + target_arch: Arch::M68k, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// MIPS Linux (kernel 4.4, glibc 2.23) +pub(crate) const MIPS_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "mips-unknown-linux-gnu", + target_arch: Arch::Mips, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// MIPS Linux with MUSL +pub(crate) const MIPS_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "mips-unknown-linux-musl", + target_arch: Arch::Mips, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// MIPS Linux with uClibc +pub(crate) const MIPS_UNKNOWN_LINUX_UCLIBC: Platform = Platform { + target_triple: "mips-unknown-linux-uclibc", + target_arch: Arch::Mips, + target_os: OS::Linux, + target_env: Env::UClibc, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// MIPS64 for OpenWrt Linux MUSL +pub(crate) const MIPS64_OPENWRT_LINUX_MUSL: Platform = Platform { + target_triple: "mips64-openwrt-linux-musl", + target_arch: Arch::Mips64, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23) +pub(crate) const MIPS64_UNKNOWN_LINUX_GNUABI64: Platform = Platform { + target_triple: "mips64-unknown-linux-gnuabi64", + target_arch: Arch::Mips64, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// MIPS64 Linux, n64 ABI, MUSL +pub(crate) const MIPS64_UNKNOWN_LINUX_MUSLABI64: Platform = Platform { + target_triple: "mips64-unknown-linux-muslabi64", + target_arch: Arch::Mips64, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23) +pub(crate) const MIPS64EL_UNKNOWN_LINUX_GNUABI64: Platform = Platform { + target_triple: "mips64el-unknown-linux-gnuabi64", + target_arch: Arch::Mips64, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// MIPS64 (LE) Linux, n64 ABI, MUSL +pub(crate) const MIPS64EL_UNKNOWN_LINUX_MUSLABI64: Platform = Platform { + target_triple: "mips64el-unknown-linux-muslabi64", + target_arch: Arch::Mips64, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// MIPS (LE) Sony PlayStation Portable (PSP) +pub(crate) const MIPSEL_SONY_PSP: Platform = Platform { + target_triple: "mipsel-sony-psp", + target_arch: Arch::Mips, + target_os: OS::Psp, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// MIPS (LE) Sony PlayStation 1 (PSX) +pub(crate) const MIPSEL_SONY_PSX: Platform = Platform { + target_triple: "mipsel-sony-psx", + target_arch: Arch::Mips, + target_os: OS::None, + target_env: Env::Psx, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// MIPS (LE) Linux (kernel 4.4, glibc 2.23) +pub(crate) const MIPSEL_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "mipsel-unknown-linux-gnu", + target_arch: Arch::Mips, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// MIPS (LE) Linux with MUSL +pub(crate) const MIPSEL_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "mipsel-unknown-linux-musl", + target_arch: Arch::Mips, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// MIPS (LE) Linux with uClibc +pub(crate) const MIPSEL_UNKNOWN_LINUX_UCLIBC: Platform = Platform { + target_triple: "mipsel-unknown-linux-uclibc", + target_arch: Arch::Mips, + target_os: OS::Linux, + target_env: Env::UClibc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// Bare MIPS (LE) softfloat +pub(crate) const MIPSEL_UNKNOWN_NONE: Platform = Platform { + target_triple: "mipsel-unknown-none", + target_arch: Arch::Mips, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// 32-bit MIPS Release 6 Big Endian +pub(crate) const MIPSISA32R6_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "mipsisa32r6-unknown-linux-gnu", + target_arch: Arch::Mips32r6, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// 32-bit MIPS Release 6 Little Endian +pub(crate) const MIPSISA32R6EL_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "mipsisa32r6el-unknown-linux-gnu", + target_arch: Arch::Mips32r6, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// 64-bit MIPS Release 6 Big Endian +pub(crate) const MIPSISA64R6_UNKNOWN_LINUX_GNUABI64: Platform = Platform { + target_triple: "mipsisa64r6-unknown-linux-gnuabi64", + target_arch: Arch::Mips64r6, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// 64-bit MIPS Release 6 Little Endian +pub(crate) const MIPSISA64R6EL_UNKNOWN_LINUX_GNUABI64: Platform = Platform { + target_triple: "mipsisa64r6el-unknown-linux-gnuabi64", + target_arch: Arch::Mips64r6, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// 16-bit MSP430 microcontrollers +pub(crate) const MSP430_NONE_ELF: Platform = Platform { + target_triple: "msp430-none-elf", + target_arch: Arch::Msp430, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U16, + tier: Tier::Three, +}; + +/// --emit=asm generates PTX code that [runs on NVIDIA GPUs] +pub(crate) const NVPTX64_NVIDIA_CUDA: Platform = Platform { + target_triple: "nvptx64-nvidia-cuda", + target_arch: Arch::Nvptx64, + target_os: OS::Cuda, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// PowerPC FreeBSD +pub(crate) const POWERPC_UNKNOWN_FREEBSD: Platform = Platform { + target_triple: "powerpc-unknown-freebsd", + target_arch: Arch::PowerPc, + target_os: OS::FreeBSD, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// PowerPC Linux (kernel 3.2, glibc 2.17) +pub(crate) const POWERPC_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "powerpc-unknown-linux-gnu", + target_arch: Arch::PowerPc, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// PowerPC SPE Linux +pub(crate) const POWERPC_UNKNOWN_LINUX_GNUSPE: Platform = Platform { + target_triple: "powerpc-unknown-linux-gnuspe", + target_arch: Arch::PowerPc, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +pub(crate) const POWERPC_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "powerpc-unknown-linux-musl", + target_arch: Arch::PowerPc, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// NetBSD 32-bit powerpc systems +pub(crate) const POWERPC_UNKNOWN_NETBSD: Platform = Platform { + target_triple: "powerpc-unknown-netbsd", + target_arch: Arch::PowerPc, + target_os: OS::NetBSD, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +pub(crate) const POWERPC_UNKNOWN_OPENBSD: Platform = Platform { + target_triple: "powerpc-unknown-openbsd", + target_arch: Arch::PowerPc, + target_os: OS::OpenBSD, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +pub(crate) const POWERPC_WRS_VXWORKS: Platform = Platform { + target_triple: "powerpc-wrs-vxworks", + target_arch: Arch::PowerPc, + target_os: OS::VxWorks, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +pub(crate) const POWERPC_WRS_VXWORKS_SPE: Platform = Platform { + target_triple: "powerpc-wrs-vxworks-spe", + target_arch: Arch::PowerPc, + target_os: OS::VxWorks, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// 64-bit AIX (7.2 and newer) +pub(crate) const POWERPC64_IBM_AIX: Platform = Platform { + target_triple: "powerpc64-ibm-aix", + target_arch: Arch::PowerPc64, + target_os: OS::Aix, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// PPC64 FreeBSD (ELFv1 and ELFv2) +pub(crate) const POWERPC64_UNKNOWN_FREEBSD: Platform = Platform { + target_triple: "powerpc64-unknown-freebsd", + target_arch: Arch::PowerPc64, + target_os: OS::FreeBSD, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// PPC64 Linux (kernel 3.2, glibc 2.17) +pub(crate) const POWERPC64_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "powerpc64-unknown-linux-gnu", + target_arch: Arch::PowerPc64, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +pub(crate) const POWERPC64_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "powerpc64-unknown-linux-musl", + target_arch: Arch::PowerPc64, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// OpenBSD/powerpc64 +pub(crate) const POWERPC64_UNKNOWN_OPENBSD: Platform = Platform { + target_triple: "powerpc64-unknown-openbsd", + target_arch: Arch::PowerPc64, + target_os: OS::OpenBSD, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +pub(crate) const POWERPC64_WRS_VXWORKS: Platform = Platform { + target_triple: "powerpc64-wrs-vxworks", + target_arch: Arch::PowerPc64, + target_os: OS::VxWorks, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// PPC64LE FreeBSD +pub(crate) const POWERPC64LE_UNKNOWN_FREEBSD: Platform = Platform { + target_triple: "powerpc64le-unknown-freebsd", + target_arch: Arch::PowerPc64, + target_os: OS::FreeBSD, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// PPC64LE Linux (kernel 3.10, glibc 2.17) +pub(crate) const POWERPC64LE_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "powerpc64le-unknown-linux-gnu", + target_arch: Arch::PowerPc64, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +pub(crate) const POWERPC64LE_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "powerpc64le-unknown-linux-musl", + target_arch: Arch::PowerPc64, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// RISC-V Linux (kernel 5.4, glibc 2.33) +pub(crate) const RISCV32GC_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "riscv32gc-unknown-linux-gnu", + target_arch: Arch::Riscv32, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// RISC-V Linux (kernel 5.4, musl + RISCV32 support patches) +pub(crate) const RISCV32GC_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "riscv32gc-unknown-linux-musl", + target_arch: Arch::Riscv32, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// Bare RISC-V (RV32I ISA) +pub(crate) const RISCV32I_UNKNOWN_NONE_ELF: Platform = Platform { + target_triple: "riscv32i-unknown-none-elf", + target_arch: Arch::Riscv32, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// Bare RISC-V (RV32IM ISA) +pub(crate) const RISCV32IM_UNKNOWN_NONE_ELF: Platform = Platform { + target_triple: "riscv32im-unknown-none-elf", + target_arch: Arch::Riscv32, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// RISC-V ESP-IDF +pub(crate) const RISCV32IMAC_ESP_ESPIDF: Platform = Platform { + target_triple: "riscv32imac-esp-espidf", + target_arch: Arch::Riscv32, + target_os: OS::Espidf, + target_env: Env::Newlib, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// Bare RISC-V (RV32IMAC ISA) +pub(crate) const RISCV32IMAC_UNKNOWN_NONE_ELF: Platform = Platform { + target_triple: "riscv32imac-unknown-none-elf", + target_arch: Arch::Riscv32, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// RISC-V Xous (RV32IMAC ISA) +pub(crate) const RISCV32IMAC_UNKNOWN_XOUS_ELF: Platform = Platform { + target_triple: "riscv32imac-unknown-xous-elf", + target_arch: Arch::Riscv32, + target_os: OS::Xous, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// RISC-V ESP-IDF +pub(crate) const RISCV32IMC_ESP_ESPIDF: Platform = Platform { + target_triple: "riscv32imc-esp-espidf", + target_arch: Arch::Riscv32, + target_os: OS::Espidf, + target_env: Env::Newlib, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// Bare RISC-V (RV32IMC ISA) +pub(crate) const RISCV32IMC_UNKNOWN_NONE_ELF: Platform = Platform { + target_triple: "riscv32imc-unknown-none-elf", + target_arch: Arch::Riscv32, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// RISC-V 64-bit Android +pub(crate) const RISCV64_LINUX_ANDROID: Platform = Platform { + target_triple: "riscv64-linux-android", + target_arch: Arch::Riscv64, + target_os: OS::Android, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// RISC-V FreeBSD +pub(crate) const RISCV64GC_UNKNOWN_FREEBSD: Platform = Platform { + target_triple: "riscv64gc-unknown-freebsd", + target_arch: Arch::Riscv64, + target_os: OS::FreeBSD, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// RISC-V Fuchsia +pub(crate) const RISCV64GC_UNKNOWN_FUCHSIA: Platform = Platform { + target_triple: "riscv64gc-unknown-fuchsia", + target_arch: Arch::Riscv64, + target_os: OS::Fuchsia, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// RISC-V Hermit +pub(crate) const RISCV64GC_UNKNOWN_HERMIT: Platform = Platform { + target_triple: "riscv64gc-unknown-hermit", + target_arch: Arch::Riscv64, + target_os: OS::Hermit, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// RISC-V Linux (kernel 4.20, glibc 2.29) +pub(crate) const RISCV64GC_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "riscv64gc-unknown-linux-gnu", + target_arch: Arch::Riscv64, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// RISC-V Linux (kernel 4.20, musl 1.2.0) +pub(crate) const RISCV64GC_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "riscv64gc-unknown-linux-musl", + target_arch: Arch::Riscv64, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// RISC-V NetBSD +pub(crate) const RISCV64GC_UNKNOWN_NETBSD: Platform = Platform { + target_triple: "riscv64gc-unknown-netbsd", + target_arch: Arch::Riscv64, + target_os: OS::NetBSD, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// Bare RISC-V (RV64IMAFDC ISA) +pub(crate) const RISCV64GC_UNKNOWN_NONE_ELF: Platform = Platform { + target_triple: "riscv64gc-unknown-none-elf", + target_arch: Arch::Riscv64, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// OpenBSD/riscv64 +pub(crate) const RISCV64GC_UNKNOWN_OPENBSD: Platform = Platform { + target_triple: "riscv64gc-unknown-openbsd", + target_arch: Arch::Riscv64, + target_os: OS::OpenBSD, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// Bare RISC-V (RV64IMAC ISA) +pub(crate) const RISCV64IMAC_UNKNOWN_NONE_ELF: Platform = Platform { + target_triple: "riscv64imac-unknown-none-elf", + target_arch: Arch::Riscv64, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// S390x Linux (kernel 3.2, glibc 2.17) +pub(crate) const S390X_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "s390x-unknown-linux-gnu", + target_arch: Arch::S390X, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// S390x Linux (kernel 3.2, MUSL) +pub(crate) const S390X_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "s390x-unknown-linux-musl", + target_arch: Arch::S390X, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// 32-bit SPARC Linux +pub(crate) const SPARC_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "sparc-unknown-linux-gnu", + target_arch: Arch::Sparc, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// Bare 32-bit SPARC V7+ +pub(crate) const SPARC_UNKNOWN_NONE_ELF: Platform = Platform { + target_triple: "sparc-unknown-none-elf", + target_arch: Arch::Sparc, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// SPARC Linux (kernel 4.4, glibc 2.23) +pub(crate) const SPARC64_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "sparc64-unknown-linux-gnu", + target_arch: Arch::Sparc64, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// NetBSD/sparc64 +pub(crate) const SPARC64_UNKNOWN_NETBSD: Platform = Platform { + target_triple: "sparc64-unknown-netbsd", + target_arch: Arch::Sparc64, + target_os: OS::NetBSD, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// OpenBSD/sparc64 +pub(crate) const SPARC64_UNKNOWN_OPENBSD: Platform = Platform { + target_triple: "sparc64-unknown-openbsd", + target_arch: Arch::Sparc64, + target_os: OS::OpenBSD, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// SPARC Solaris 10/11, illumos +pub(crate) const SPARCV9_SUN_SOLARIS: Platform = Platform { + target_triple: "sparcv9-sun-solaris", + target_arch: Arch::Sparc64, + target_os: OS::Solaris, + target_env: Env::None, + target_endian: Endian::Big, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// Thumb-mode Bare ARMv4T +pub(crate) const THUMBV4T_NONE_EABI: Platform = Platform { + target_triple: "thumbv4t-none-eabi", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// Thumb-mode Bare ARMv5TE +pub(crate) const THUMBV5TE_NONE_EABI: Platform = Platform { + target_triple: "thumbv5te-none-eabi", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// Bare ARMv6-M +pub(crate) const THUMBV6M_NONE_EABI: Platform = Platform { + target_triple: "thumbv6m-none-eabi", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +pub(crate) const THUMBV7A_PC_WINDOWS_MSVC: Platform = Platform { + target_triple: "thumbv7a-pc-windows-msvc", + target_arch: Arch::Arm, + target_os: OS::Windows, + target_env: Env::Msvc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +pub(crate) const THUMBV7A_UWP_WINDOWS_MSVC: Platform = Platform { + target_triple: "thumbv7a-uwp-windows-msvc", + target_arch: Arch::Arm, + target_os: OS::Windows, + target_env: Env::Msvc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// Bare ARMv7E-M +pub(crate) const THUMBV7EM_NONE_EABI: Platform = Platform { + target_triple: "thumbv7em-none-eabi", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// Bare ARMV7E-M, hardfloat +pub(crate) const THUMBV7EM_NONE_EABIHF: Platform = Platform { + target_triple: "thumbv7em-none-eabihf", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// Bare ARMv7-M +pub(crate) const THUMBV7M_NONE_EABI: Platform = Platform { + target_triple: "thumbv7m-none-eabi", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// Thumb2-mode ARMv7-A Android with NEON +pub(crate) const THUMBV7NEON_LINUX_ANDROIDEABI: Platform = Platform { + target_triple: "thumbv7neon-linux-androideabi", + target_arch: Arch::Arm, + target_os: OS::Android, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// Thumb2-mode ARMv7-A Linux with NEON (kernel 4.4, glibc 2.23) +pub(crate) const THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF: Platform = Platform { + target_triple: "thumbv7neon-unknown-linux-gnueabihf", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// Thumb2-mode ARMv7-A Linux with NEON, MUSL +pub(crate) const THUMBV7NEON_UNKNOWN_LINUX_MUSLEABIHF: Platform = Platform { + target_triple: "thumbv7neon-unknown-linux-musleabihf", + target_arch: Arch::Arm, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// Bare ARMv8-M Baseline +pub(crate) const THUMBV8M_BASE_NONE_EABI: Platform = Platform { + target_triple: "thumbv8m.base-none-eabi", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// Bare ARMv8-M Mainline +pub(crate) const THUMBV8M_MAIN_NONE_EABI: Platform = Platform { + target_triple: "thumbv8m.main-none-eabi", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// Bare ARMv8-M Mainline, hardfloat +pub(crate) const THUMBV8M_MAIN_NONE_EABIHF: Platform = Platform { + target_triple: "thumbv8m.main-none-eabihf", + target_arch: Arch::Arm, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// WebAssembly via Emscripten +pub(crate) const WASM32_UNKNOWN_EMSCRIPTEN: Platform = Platform { + target_triple: "wasm32-unknown-emscripten", + target_arch: Arch::Wasm32, + target_os: OS::Emscripten, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// WebAssembly +pub(crate) const WASM32_UNKNOWN_UNKNOWN: Platform = Platform { + target_triple: "wasm32-unknown-unknown", + target_arch: Arch::Wasm32, + target_os: OS::Unknown, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// WebAssembly with WASI +pub(crate) const WASM32_WASI: Platform = Platform { + target_triple: "wasm32-wasi", + target_arch: Arch::Wasm32, + target_os: OS::Wasi, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// WebAssembly with WASI Preview 1 and threads +pub(crate) const WASM32_WASI_PREVIEW1_THREADS: Platform = Platform { + target_triple: "wasm32-wasi-preview1-threads", + target_arch: Arch::Wasm32, + target_os: OS::Wasi, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Three, +}; + +/// WebAssembly +pub(crate) const WASM64_UNKNOWN_UNKNOWN: Platform = Platform { + target_triple: "wasm64-unknown-unknown", + target_arch: Arch::Wasm64, + target_os: OS::Unknown, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// 64-bit macOS (10.7+, Lion+) +pub(crate) const X86_64_APPLE_DARWIN: Platform = Platform { + target_triple: "x86_64-apple-darwin", + target_arch: Arch::X86_64, + target_os: OS::MacOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::One, +}; + +/// 64-bit x86 iOS +pub(crate) const X86_64_APPLE_IOS: Platform = Platform { + target_triple: "x86_64-apple-ios", + target_arch: Arch::X86_64, + target_os: OS::iOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// Apple Catalyst on x86_64 +pub(crate) const X86_64_APPLE_IOS_MACABI: Platform = Platform { + target_triple: "x86_64-apple-ios-macabi", + target_arch: Arch::X86_64, + target_os: OS::iOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// x86 64-bit tvOS +pub(crate) const X86_64_APPLE_TVOS: Platform = Platform { + target_triple: "x86_64-apple-tvos", + target_arch: Arch::X86_64, + target_os: OS::TvOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// x86 64-bit Apple WatchOS simulator +pub(crate) const X86_64_APPLE_WATCHOS_SIM: Platform = Platform { + target_triple: "x86_64-apple-watchos-sim", + target_arch: Arch::X86_64, + target_os: OS::WatchOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// [Fortanix ABI] for 64-bit Intel SGX +pub(crate) const X86_64_FORTANIX_UNKNOWN_SGX: Platform = Platform { + target_triple: "x86_64-fortanix-unknown-sgx", + target_arch: Arch::X86_64, + target_os: OS::Unknown, + target_env: Env::Sgx, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// Alias for `x86_64-unknown-fuchsia` +pub(crate) const X86_64_FUCHSIA: Platform = Platform { + target_triple: "x86_64-fuchsia", + target_arch: Arch::X86_64, + target_os: OS::Fuchsia, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// 64-bit x86 Android +pub(crate) const X86_64_LINUX_ANDROID: Platform = Platform { + target_triple: "x86_64-linux-android", + target_arch: Arch::X86_64, + target_os: OS::Android, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +pub(crate) const X86_64_PC_NTO_QNX710: Platform = Platform { + target_triple: "x86_64-pc-nto-qnx710", + target_arch: Arch::X86_64, + target_os: OS::Nto, + target_env: Env::Nto71, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// 64-bit Solaris 10/11, illumos +pub(crate) const X86_64_PC_SOLARIS: Platform = Platform { + target_triple: "x86_64-pc-solaris", + target_arch: Arch::X86_64, + target_os: OS::Solaris, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// 64-bit MinGW (Windows 7+) [^windows-support] +pub(crate) const X86_64_PC_WINDOWS_GNU: Platform = Platform { + target_triple: "x86_64-pc-windows-gnu", + target_arch: Arch::X86_64, + target_os: OS::Windows, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::One, +}; + +pub(crate) const X86_64_PC_WINDOWS_GNULLVM: Platform = Platform { + target_triple: "x86_64-pc-windows-gnullvm", + target_arch: Arch::X86_64, + target_os: OS::Windows, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// 64-bit MSVC (Windows 7+) [^windows-support] +pub(crate) const X86_64_PC_WINDOWS_MSVC: Platform = Platform { + target_triple: "x86_64-pc-windows-msvc", + target_arch: Arch::X86_64, + target_os: OS::Windows, + target_env: Env::Msvc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::One, +}; + +/// Deprecated target for 64-bit Solaris 10/11, illumos +pub(crate) const X86_64_SUN_SOLARIS: Platform = Platform { + target_triple: "x86_64-sun-solaris", + target_arch: Arch::X86_64, + target_os: OS::Solaris, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// 64-bit Unikraft with musl +pub(crate) const X86_64_UNIKRAFT_LINUX_MUSL: Platform = Platform { + target_triple: "x86_64-unikraft-linux-musl", + target_arch: Arch::X86_64, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// 64-bit DragonFlyBSD +pub(crate) const X86_64_UNKNOWN_DRAGONFLY: Platform = Platform { + target_triple: "x86_64-unknown-dragonfly", + target_arch: Arch::X86_64, + target_os: OS::Dragonfly, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// 64-bit FreeBSD +pub(crate) const X86_64_UNKNOWN_FREEBSD: Platform = Platform { + target_triple: "x86_64-unknown-freebsd", + target_arch: Arch::X86_64, + target_os: OS::FreeBSD, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// 64-bit x86 Fuchsia +pub(crate) const X86_64_UNKNOWN_FUCHSIA: Platform = Platform { + target_triple: "x86_64-unknown-fuchsia", + target_arch: Arch::X86_64, + target_os: OS::Fuchsia, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// 64-bit Haiku +pub(crate) const X86_64_UNKNOWN_HAIKU: Platform = Platform { + target_triple: "x86_64-unknown-haiku", + target_arch: Arch::X86_64, + target_os: OS::Haiku, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// x86_64 Hermit +pub(crate) const X86_64_UNKNOWN_HERMIT: Platform = Platform { + target_triple: "x86_64-unknown-hermit", + target_arch: Arch::X86_64, + target_os: OS::Hermit, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// illumos +pub(crate) const X86_64_UNKNOWN_ILLUMOS: Platform = Platform { + target_triple: "x86_64-unknown-illumos", + target_arch: Arch::X86_64, + target_os: OS::IllumOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +pub(crate) const X86_64_UNKNOWN_L4RE_UCLIBC: Platform = Platform { + target_triple: "x86_64-unknown-l4re-uclibc", + target_arch: Arch::X86_64, + target_os: OS::L4re, + target_env: Env::UClibc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// 64-bit Linux (kernel 3.2+, glibc 2.17+) +pub(crate) const X86_64_UNKNOWN_LINUX_GNU: Platform = Platform { + target_triple: "x86_64-unknown-linux-gnu", + target_arch: Arch::X86_64, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::One, +}; + +/// 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27) +pub(crate) const X86_64_UNKNOWN_LINUX_GNUX32: Platform = Platform { + target_triple: "x86_64-unknown-linux-gnux32", + target_arch: Arch::X86_64, + target_os: OS::Linux, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U32, + tier: Tier::Two, +}; + +/// 64-bit Linux with MUSL +pub(crate) const X86_64_UNKNOWN_LINUX_MUSL: Platform = Platform { + target_triple: "x86_64-unknown-linux-musl", + target_arch: Arch::X86_64, + target_os: OS::Linux, + target_env: Env::Musl, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +pub(crate) const X86_64_UNKNOWN_LINUX_OHOS: Platform = Platform { + target_triple: "x86_64-unknown-linux-ohos", + target_arch: Arch::X86_64, + target_os: OS::Linux, + target_env: Env::OhOS, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// NetBSD/amd64 +pub(crate) const X86_64_UNKNOWN_NETBSD: Platform = Platform { + target_triple: "x86_64-unknown-netbsd", + target_arch: Arch::X86_64, + target_os: OS::NetBSD, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// Freestanding/bare-metal x86_64, softfloat +pub(crate) const X86_64_UNKNOWN_NONE: Platform = Platform { + target_triple: "x86_64-unknown-none", + target_arch: Arch::X86_64, + target_os: OS::None, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// 64-bit OpenBSD +pub(crate) const X86_64_UNKNOWN_OPENBSD: Platform = Platform { + target_triple: "x86_64-unknown-openbsd", + target_arch: Arch::X86_64, + target_os: OS::OpenBSD, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// Redox OS +pub(crate) const X86_64_UNKNOWN_REDOX: Platform = Platform { + target_triple: "x86_64-unknown-redox", + target_arch: Arch::X86_64, + target_os: OS::Redox, + target_env: Env::Relibc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +/// 64-bit UEFI +pub(crate) const X86_64_UNKNOWN_UEFI: Platform = Platform { + target_triple: "x86_64-unknown-uefi", + target_arch: Arch::X86_64, + target_os: OS::Uefi, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Two, +}; + +pub(crate) const X86_64_UWP_WINDOWS_GNU: Platform = Platform { + target_triple: "x86_64-uwp-windows-gnu", + target_arch: Arch::X86_64, + target_os: OS::Windows, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +pub(crate) const X86_64_UWP_WINDOWS_MSVC: Platform = Platform { + target_triple: "x86_64-uwp-windows-msvc", + target_arch: Arch::X86_64, + target_os: OS::Windows, + target_env: Env::Msvc, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +pub(crate) const X86_64_WRS_VXWORKS: Platform = Platform { + target_triple: "x86_64-wrs-vxworks", + target_arch: Arch::X86_64, + target_os: OS::VxWorks, + target_env: Env::Gnu, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; + +/// macOS with late-gen Intel (at least Haswell) +pub(crate) const X86_64H_APPLE_DARWIN: Platform = Platform { + target_triple: "x86_64h-apple-darwin", + target_arch: Arch::X86_64, + target_os: OS::MacOS, + target_env: Env::None, + target_endian: Endian::Little, + target_pointer_width: PointerWidth::U64, + tier: Tier::Three, +}; diff --git a/vendor/prettydiff/Cargo.lock b/vendor/prettydiff/Cargo.lock new file mode 100644 index 0000000000000..3eab886cc5dd6 --- /dev/null +++ b/vendor/prettydiff/Cargo.lock @@ -0,0 +1,622 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "csv" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "errno" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.45.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "256017f749ab3117e93acb91063009e1f1bb56d03965b14c2c8df4eb02c524d8" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.45.0", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.141" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" + +[[package]] +name = "linux-raw-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "pad" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "prettydiff" +version = "0.6.4" +dependencies = [ + "ansi_term", + "pad", + "prettytable-rs", + "structopt", +] + +[[package]] +name = "prettytable-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" +dependencies = [ + "csv", + "encode_unicode", + "is-terminal", + "lazy_static", + "term", + "unicode-width", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "rustix" +version = "0.37.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "serde" +version = "1.0.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/vendor/prettydiff/src/main.rs b/vendor/prettydiff/src/main.rs new file mode 100644 index 0000000000000..9b6a59bbd5ec4 --- /dev/null +++ b/vendor/prettydiff/src/main.rs @@ -0,0 +1,51 @@ +use std::fs::File; +use std::io::prelude::*; +use std::path::PathBuf; +use structopt::StructOpt; + +/// Side-by-side diff for two files +#[derive(StructOpt, Debug)] +#[structopt(name = "prettydiff")] +struct Opt { + /// Left file + #[structopt(name = "LEFT", parse(from_os_str))] + left: PathBuf, + /// Right file + #[structopt(name = "RIGHT", parse(from_os_str))] + right: PathBuf, + /// Don't show lines numbers + #[structopt(long = "disable_lines")] + disable_lines: bool, + /// Show non-changed blocks + #[structopt(long = "show_same")] + show_same: bool, + /// Align new lines inside change block + #[structopt(long = "disable_align")] + disable_align: bool, +} + +fn read_file(path: &PathBuf) -> std::io::Result { + let mut file = File::open(path)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + Ok(contents) +} + +fn main() -> std::io::Result<()> { + let opt = Opt::from_args(); + + let left_data = read_file(&opt.left)?; + let left_name = opt.left.into_os_string().into_string().unwrap(); + + let right_data = read_file(&opt.right)?; + let right_name = opt.right.into_os_string().into_string().unwrap(); + + prettydiff::diff_lines(&left_data, &right_data) + .names(&left_name, &right_name) + .set_show_lines(!opt.disable_lines) + .set_diff_only(!opt.show_same) + .set_align_new_lines(!opt.disable_align) + .prettytable(); + + Ok(()) +} diff --git a/vendor/prost/FUZZING.md b/vendor/prost/FUZZING.md new file mode 100644 index 0000000000000..b79112d04ef99 --- /dev/null +++ b/vendor/prost/FUZZING.md @@ -0,0 +1,27 @@ +# Fuzzing + +Prost ships a few fuzz tests, using both libfuzzer and aflfuzz. + + +## afl + +To run the afl fuzz tests, first install cargo-afl: + + cargo install -f afl + +Then build a fuzz target and run afl on it: + + cd fuzz/afl// + cargo afl build --bin fuzz-target + cargo afl fuzz -i in -o out target/debug/fuzz-target + +To reproduce a crash: + + cd fuzz/afl// + cargo build --bin reproduce + cargo run --bin reproduce -- out/crashes/ + + +## libfuzzer + +TODO diff --git a/vendor/prost/KANI.md b/vendor/prost/KANI.md new file mode 100644 index 0000000000000..cafb0131d3b2e --- /dev/null +++ b/vendor/prost/KANI.md @@ -0,0 +1,69 @@ +# Kani +This document describes how to **locally** install and use Kani, along +with its experimental PropProof feature. Because of instability in +Kani internals, the GitHub action is the recommended option if you are +running in CI. + +Kani is a software verification tool that complements testing by +proving the absence of certain classes of bugs like unwrap exceptions, +overflows, and assertion failures. See the [Kani +book](https://model-checking.github.io/kani/) for a full list of +capabilities and limitations. + +## Installing Kani and PropProof +- The install instructions for Kani can be [found + here](https://model-checking.github.io/kani/install-guide.html). Once + Kani is installed, you can run with `cargo kani` for projects or + `kani` for individual Rust files. +- **[UNSTABLE]** To use PropProof, first download the source code + from the Kani repository. + ```bash + git clone https://github.com/model-checking/kani.git --branch features/proptest propproof + cd propproof; git submodule update --init + ``` + + Then, use `.cargo/config.toml` enable it in the local directory you + want to run Kani in. This will override the `proptest` import in + your repo. + + ```bash + cd $YOUR_REPO_LOCAL_PATH + mkdir '.cargo' + echo "paths =[\"$PATH_TO_PROPPROOF\"]" > .cargo/config.toml + ``` + +**Please Note**: +- `features/proptest` branch under Kani is likely not the final + location for this code. If these instructions stop working, please + consult the Kani documentation and file an issue on [the Kani + repo](https://github.com/model-checking/kani.git). +- The cargo config file will force cargo to always use PropProof. To + use `proptest`, delete the file. + +## Running Kani +After installing Kani and PropProof, `cargo kani --tests` should +automatically run `proptest!` harnesses inside your crate. Use +`--harness` to run a specific harness, and `-p` for a specific +sub-crate. + +If Kani returns with an error, you can use the concrete playback +feature using `--enable-unstable --concrete-playback print` and paste +in the code to your repository. Running this harness with `cargo test` +will replay the input found by Kani that produced this crash. Please +note that this feature is unstable and using `--concrete-playback +inplace` to automatically inject a replay harness is not supported +when using PropProof. + +## Debugging CI Failure +```yaml + - name: Verify with Kani + uses: model-checking/kani-github-action@v0.xx + with: + enable-propproof: true + args: | + $KANI_ARGUMENTS +``` + +The above GitHub CI workflow is equivalent to `cargo kani +$KANI_ARGUMENTS` with PropProof installed. To replicate issues +locally, run `cargo kani` with the same arguments. diff --git a/vendor/prost/LICENSE b/vendor/prost/LICENSE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/vendor/prost/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/prost/clippy.toml b/vendor/prost/clippy.toml new file mode 100644 index 0000000000000..5988e12d8fc52 --- /dev/null +++ b/vendor/prost/clippy.toml @@ -0,0 +1 @@ +too-many-arguments-threshold=8 diff --git a/vendor/prost/flake.lock b/vendor/prost/flake.lock new file mode 100644 index 0000000000000..5cb2e9ea61585 --- /dev/null +++ b/vendor/prost/flake.lock @@ -0,0 +1,43 @@ +{ + "nodes": { + "flake-utils": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1667969101, + "narHash": "sha256-GL53T705HO7Q/KVfbb5STx8AxFs8YgaGY8pvAZC+O7U=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bbf77421ac51a7c93f5f0f760da99e4dbce614fa", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/vendor/prost/flake.nix b/vendor/prost/flake.nix new file mode 100644 index 0000000000000..a200020e3813d --- /dev/null +++ b/vendor/prost/flake.nix @@ -0,0 +1,20 @@ +{ + description = "Prost dependencies"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + in + { + devShells.default = pkgs.mkShell { + packages = with pkgs; [ cargo rustc ]; + buildInputs = with pkgs; [ pkg-config protobuf curl cmake ninja ]; + }; + }); +} diff --git a/vendor/prost/prepare-release.sh b/vendor/prost/prepare-release.sh new file mode 100755 index 0000000000000..34e5202c24f42 --- /dev/null +++ b/vendor/prost/prepare-release.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# Script which automates modifying source version fields, and creating a release +# commit and tag. The commit and tag are not automatically pushed, nor are the +# crates published (see publish-release.sh). + +set -ex + +if [ "$#" -ne 1 ] +then + echo "Usage: $0 " + exit 1 +fi + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +VERSION="$1" +MINOR="$( echo ${VERSION} | cut -d\. -f1-2 )" + +VERSION_MATCHER="([a-z0-9\\.-]+)" +PROST_CRATE_MATCHER="(prost|prost-[a-z]+)" + +# Update the README.md. +sed -i -E "s/${PROST_CRATE_MATCHER} = \"${VERSION_MATCHER}\"/\1 = \"${MINOR}\"/" "$DIR/README.md" + +# Update html_root_url attributes. +sed -i -E "s~html_root_url = \"https://docs\.rs/${PROST_CRATE_MATCHER}/$VERSION_MATCHER\"~html_root_url = \"https://docs.rs/\1/${VERSION}\"~" \ + "$DIR/src/lib.rs" \ + "$DIR/prost-derive/src/lib.rs" \ + "$DIR/prost-build/src/lib.rs" \ + "$DIR/prost-types/src/lib.rs" + +# Update Cargo.toml version fields. +sed -i -E "s/^version = \"${VERSION_MATCHER}\"$/version = \"${VERSION}\"/" \ + "$DIR/Cargo.toml" \ + "$DIR/prost-derive/Cargo.toml" \ + "$DIR/prost-build/Cargo.toml" \ + "$DIR/prost-types/Cargo.toml" + +# Update Cargo.toml dependency versions. +sed -i -E "s/^${PROST_CRATE_MATCHER} = \{ version = \"${VERSION_MATCHER}\"/\1 = { version = \"${VERSION}\"/" \ + "$DIR/Cargo.toml" \ + "$DIR/prost-derive/Cargo.toml" \ + "$DIR/prost-build/Cargo.toml" \ + "$DIR/prost-types/Cargo.toml" + +git commit -a -m "release ${VERSION}" +git tag -a "v${VERSION}" -m "release ${VERSION}" diff --git a/vendor/prost/publish-release.sh b/vendor/prost/publish-release.sh new file mode 100755 index 0000000000000..9b014af3a5a1b --- /dev/null +++ b/vendor/prost/publish-release.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# Script which automates publishing a crates.io release of the prost crates. + +set -ex + +if [ "$#" -ne 0 ] +then + echo "Usage: $0" + exit 1 +fi + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +CRATES=( \ + "prost-derive" \ + "." \ + "prost-types" \ + "prost-build" \ +) + +for CRATE in "${CRATES[@]}"; do + pushd "$DIR/$CRATE" + + echo "Publishing $CRATE" + + cargo publish + + echo "Sleeping 5 seconds...for the release to be visible" + sleep 5 + + popd +done diff --git a/vendor/quanta-0.11.1/.cargo-checksum.json b/vendor/quanta-0.11.1/.cargo-checksum.json new file mode 100644 index 0000000000000..fa56cb4cdfb63 --- /dev/null +++ b/vendor/quanta-0.11.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"1767e5478469dc4d4ae36364237666397cf875de69c4bffe7d37170e8a1c27db","CODE_OF_CONDUCT.md":"55a5389e814d4a899404c00f4e77bd734d7c41af6b85bf5e76b3288c56b2ebe5","Cargo.toml":"9828b82200a1d5502eaf04be0a0c46e56eeb6d45d5f8b76953ce4f129c450492","LICENSE":"7bdd587c9ff64c56323455bad7ec590698fbf56c02291c8e515b2afc85306282","README.md":"0e73248245e0afb4f18d37ca7d6b8f0c5a81ce37caf1c7cb431d3658e5970409","benches/README.md":"8a90b51749047ad2a87801e5151149cf2b6318536037c66ee990cf54d1161b00","benches/contention.rs":"8c0ecfb1a7b37b7c0c2f0c31513d54a11d0607f787be7d1b1ad2ccb3f04671a1","benches/timing.rs":"7939b6565b7aaf5bda9e6877971055001e376d5dd5a3e6156491799a638b15d1","release.toml":"27e1704eb66df4c4dc0ac14a3d732ad06b8c87b1aca8747443dba573ad5eb639","rust-toolchain.toml":"e5cc0545f232bde807bd9394c2433322d1cd2cf42b060ceab2ac7329bc9cdaa2","src/clocks/counter.rs":"81920c98d85fd7ee57caa5038905c5177960830d4afebe7589be85a2f7c9156e","src/clocks/mod.rs":"6da94f7b5187caca77dfc0c1e11636a1ec80729be36bd9f0be399a2ba0b07d81","src/clocks/monotonic/macos.rs":"827e112b5c1e796a1755ca8db587763b137ba6da8caf93b06ca9a4a5ed78b6ba","src/clocks/monotonic/mod.rs":"4d261187b5fde9cf08dd6a597f0647729dcad3efc02bc189c8525927c2c36341","src/clocks/monotonic/unix.rs":"ab854fd3093ef4b4c0ba82cfcbdd6cafa8f325e68976b32d0bf49bcaf780a177","src/clocks/monotonic/wasm.rs":"3798e3fe972ce768fd523988f91df2959ecd6d7d993ad8df6cc2db872a2d352a","src/clocks/monotonic/windows.rs":"af6a3bd91d699250cb86391853266d67278c48eb53c6ae2372f14876d5e41a8d","src/instant.rs":"7dafb373287160f8f4cb2c0bffc831b481f7b5010194d18ae4ad8999fba31a50","src/lib.rs":"594df9a8477333d62d2f62defd42f1481b2e9db2a5bbfc5fb2ff7e9501772554","src/mock.rs":"7223ce27a1de5fbaae7dc4e900485eb9bc306dd80faf3bef03a5eac2165a6924","src/stats.rs":"591971ca567e3192049e028a45460c77a4b34a0bc1d0cec7ac6730bf6811e7db","src/upkeep.rs":"765269925343f646b17292f388d63f113f516f647bde8e4585d1d86f5d5e58a8"},"package":"a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab"} \ No newline at end of file diff --git a/vendor/quanta-0.11.1/CHANGELOG.md b/vendor/quanta-0.11.1/CHANGELOG.md new file mode 100644 index 0000000000000..00fbd6f8cd0ed --- /dev/null +++ b/vendor/quanta-0.11.1/CHANGELOG.md @@ -0,0 +1,225 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project +adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + + +## [Unreleased] - ReleaseDate + +## [0.11.1] - 2023-05-28 + +### Added + +- Added a new method, `Clock::delta_as_nanos`, for getting the delta between two raw measurements as + the whole number of nanoseconds instead of the initial conversion to `Duration`. ([#86]) + +[#86]: https://github.com/metrics-rs/quanta/pull/86 + +## [0.11.0] - 2023-03-24 + +### Added + +- `Instant::elapsed()` has been added. ([#82]) + +### Changed + +- `Instant::duration_since` and `Instant::sub` now saturates to zero. ([#82]) +- Performance of `Instant::now` under high contention has been improved. ([#82]) + +[#82]: https://github.com/metrics-rs/quanta/pull/82 + +## [0.10.1] - 2022-07-20 + +### Added + +- Implement `std::error::Error` for `quanta::Error`. ([#68]) + +### Changed + +- Fixed build issue on x86/x86_64 platforms that did not have SSE. +- Fix scaling factor for `window.performance.now()` in WASM. ([#72]) + +[#72]: https://github.com/metrics-rs/quanta/pull/72 +[#68]: https://github.com/metrics-rs/quanta/pull/68 + +## [0.10.0] - 2022-05-18 + +### Changed + +- Documentation has been updated to reflect that `quanta` does not track time across system + suspends. +- Fixed a panic in the calibration loop if a certain edge case with TSC measurements is encountered. +- Updated a unit test that was frequently flaky to be more precise. + +### Removed + +- `Instant::as_u64` has been removed. As it provided direct access to an value that could + fundamentally change from version-to-version, it felt like time to remove that footgun and push + users more towards the API that mimics `std::time`. +- `Clock::upkeep` has been removed. It doesn't need to exist on `Clock` directly, as we have had + the `quanta::set_recent` free function for a while now, and was just duplicating that. +- `Clock::start` and `Clock::end` have been removed. They saw limited usage and overall just added somewhat needless API + clutter given that users who are looking to do ultra-precise timing will either want more control or use another + technique such as instruction counting. + +## 0.9.3 - 2021-09-16 + +### Added + +- CI tests for MIPS/ARM. ([#55](https://github.com/metrics-rs/quanta/pull/55)) + +### Changed + +- Fixed compilation issue with `Mock` on MIPS/ARM. ([#55](https://github.com/metrics-rs/quanta/pull/55)) +- Simplified how TSC/RDTSC suppoort is detected, which should avoid some situations where it was + assumed to be present, but actually was not. ([#57](https://github.com/metrics-rs/quanta/pull/57)) + +## 0.9.2 - 2021-08-25 + +### Changed + +- Pinned `crossbeam-utils` to `v0.8.5` where `AtomicCell::fetch_update` was introduced to fix, which + fixes broken builds where Cargo chooses a version between `0.8.0` and `0.8.5`. +- Update `raw-cpuid` to `10.2` and `average` to `0.13`. + +## 0.9.1 - 2021-08-12 + +### Changed + +- Switched from `atomic-shim` to `crossbeam-utils` for better cross-platform atomic support. ([#52](https://github.com/metrics-rs/quanta/pull/52)) + +## 0.9.0 - 2021-06-17 + +### Added + +- Support for WASM/WASI targets. ([#45](https://github.com/metrics-rs/quanta/pull/45)) + +## 0.8.0 - 2021-06-07 + +### Removed + +- `Instant::as_unix_duration` as it was added in error. +- `metrics` feature flag as `metrics-core` is no longer a relevant crate. + +## 0.7.2 - 2021-01-25 +### Changed + +- Bumped dependency on `raw-cpuid` to `9.0` in order to deal with a [RustSec + advisory](https://rustsec.org/advisories/RUSTSEC-2021-0013). + +## 0.7.1 - 2021-01-24 +### Fixed + +- Incorrect method visibility for non-SSE2 implementation of `Counter`. + ([#38](https://github.com/metrics-rs/quanta/issues/38)) + +## 0.7.0 - 2021-01-03 +### Changed + +- MSRV bumped to 1.45.0. +- `Clock::now` takes `&self` instead of `&mut self`. +- Fixed a bug where a failure to spawn the upkeep thread would not allow subsequent attempts to + spawn the upkeep thread to proceed. + +### Added + +- New methods --`Instant::now` and `Instant::recent` for getting the current and recent time, + respectively. +- New free function `quanta::with_clock` for setting an override on the current thread that affects + calls made to `Instant::now` and `Instant::recent`. +- New free function `quanta::set_recent` to allow customization of how global recent time is + updated. + +## 0.6.5 - 2020-09-16 +### Changed + +- Fixed a bug with not being able to start the upkeep thread at all. + ([#29](https://github.com/metrics-rs/quanta/issues/29)) + +## 0.6.4 - 2020-08-27 +### Added + +- Add `Instant::as_unix_duration` to get the duration of time since the Unix epoch from an + `Instant`. + ### Changed +- Remove `clocksource` from dependencies and tests as it no longer compiles on stable or nightly. + +## 0.6.3 - 2020-08-03 +### Changed + +- Publicly expose `Clock::upkeep` for advanced use cases. +- Relax constraints around checking for multiple sockets. + ([#25](https://github.com/metrics-rs/quanta/issues/25)) + +## 0.6.2 - 2020-07-20 +### Added + +- Add support for MIPS/PowerPC. ([#23](https://github.com/metrics-rs/quanta/pull/23)) + +## 0.6.1 - 2020-07-13 +### Added + +- Publicly expose the `Error` type returned by `Upkeep::start`. + +## 0.6.0 - 2020-07-06 + +This version of `quanta` was a massive overhaul of man areas of the API and internals, which was +done in a single PR: ([#19](https://github.com/metrics-rs/quanta/pull/19)). You can read the PR +description for the finer details. All changes below are part of the aforementioned PR. + +### Changed + +- `Clock::now` now returns a monotonic value in all cases. +- No longer possible to get a negative value from `Clock::delta`. +- Calibration is no longer a fixed one second loop, and will complete when it detects it has a + statistically viable calibration ratio, or when it exceeds 200ms of wall-clock time. In most + cases, it should complete in under 10ms. +- Calibration is now shared amongst all `Clock` instances, running only once when the first `Clock` + is created. + +## 0.5.2 - 2020-05-01 +### Changed + +- Fix the logic to figure out when calibration is required. + ([#14](https://github.com/metrics-rs/quanta/pull/14)) + +## 0.5.1 - 2020-04-11 +### Changed + +- Small tweak to the docs. + +## 0.5.0 - 2020-04-11 +### Changed + +- Switch to `mach` for macOS/iOS as it was deprecated in `libc`. + ([#12](https://github.com/metrics-rs/quanta/pull/12)) +- Switch to `core::arch` for instrinics, and drop the feature flagged configuration to use it. + ([#12](https://github.com/metrics-rs/quanta/pull/12)) +- Switch to `criterion` for benchmarking. ([#12](https://github.com/metrics-rs/quanta/pull/12)) + +## 0.4.0 - 2020-02-20 +### Changed + +- Differentiate between raw and scaled time by adding a new `Instant` type. + ([#10](https://github.com/metrics-rs/quanta/pull/10)) + +## 0.2.0 - 2019-03-10 +### Changed + +- Fixed support for Windows. It was in a bad way, but actually works correctly now! +- Switched to Azure Pipelines CI + Cirrus CI, including formatting, tests, and benchmarks, for + Linux, macOS, Windows, and FreeBSD. + +## 0.1.0 - 2019-01-14 +### Added + +- Initial commit. + + +[Unreleased]: https://github.com/metrics-rs/quanta/compare/v0.11.1...HEAD +[0.11.1]: https://github.com/metrics-rs/quanta/compare/v0.11.0...v0.11.1 +[0.11.0]: https://github.com/metrics-rs/quanta/compare/v0.10.1...v0.11.0 +[0.10.1]: https://github.com/metrics-rs/quanta/compare/v0.10.0...v0.10.1 +[0.10.0]: https://github.com/metrics-rs/quanta/releases/tag/v0.10.0 diff --git a/vendor/quanta-0.11.1/CODE_OF_CONDUCT.md b/vendor/quanta-0.11.1/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000000..3cee6e1e40e5d --- /dev/null +++ b/vendor/quanta-0.11.1/CODE_OF_CONDUCT.md @@ -0,0 +1,27 @@ +# The Code of Conduct + +This document is based on the [Rust Code of Conduct](https://www.rust-lang.org/conduct.html) and outlines the standard of conduct which is both expected and enforced as part of this project. + +## Conduct + +**Contact**: [toby@nuclearfurnace.com](mailto:toby@nuclearfurnace.com) + +* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. +* Avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. +* Please be kind and courteous. There's no need to be mean or rude. +* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. +* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. +* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behaviour. We interpret the term "harassment" as including the definition in the Citizen Code of Conduct; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the repository Owners immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. +* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behaviour is not welcome. + +## Moderation + +These are the policies for upholding our community's standards of conduct. If you feel that a thread needs moderation, please use the contact information above, or mention @tobz in the thread. + +1. Remarks that violate this Code of Conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) +2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. + +In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. + +And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. diff --git a/vendor/quanta-0.11.1/Cargo.toml b/vendor/quanta-0.11.1/Cargo.toml new file mode 100644 index 0000000000000..8fc02b1d34ba3 --- /dev/null +++ b/vendor/quanta-0.11.1/Cargo.toml @@ -0,0 +1,96 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.60" +name = "quanta" +version = "0.11.1" +authors = ["Toby Lawrence "] +description = "high-speed timing library" +homepage = "https://github.com/metrics-rs/quanta" +documentation = "https://docs.rs/quanta" +readme = "README.md" +keywords = [ + "rdtsc", + "timing", + "nanosecond", +] +license = "MIT" +repository = "https://github.com/metrics-rs/quanta" + +[package.metadata.docs.rs] +all-features = true + +[lib] +bench = false + +[[bench]] +name = "timing" +harness = false + +[[bench]] +name = "contention" +harness = false + +[dependencies.crossbeam-utils] +version = "0.8.5" + +[dependencies.once_cell] +version = "1.4" + +[dependencies.prost-types] +version = "0.11" +optional = true +default-features = false + +[dev-dependencies.average] +version = "0.13" + +[dev-dependencies.criterion] +version = "=0.3.3" + +[features] +default = ["flaky_tests"] +flaky_tests = [] +prost = ["prost-types"] + +[target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dependencies.web-sys] +version = "0.3" +features = [ + "Window", + "Performance", +] + +[target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dev-dependencies.wasm-bindgen-test] +version = "0.3" + +[target."cfg(all(target_arch = \"wasm32\", target_os = \"wasi\"))".dependencies.wasi] +version = "0.11" + +[target."cfg(not(any(target_os = \"macos\", target_os = \"ios\", target_os = \"windows\", target_arch = \"wasm32\")))".dependencies.libc] +version = "0.2" + +[target."cfg(target_arch = \"x86\")".dependencies.raw-cpuid] +version = "10.2" + +[target."cfg(target_arch = \"x86_64\")".dependencies.raw-cpuid] +version = "10.2" + +[target."cfg(target_os = \"ios\")".dependencies.mach2] +version = "0.4" + +[target."cfg(target_os = \"macos\")".dependencies.mach2] +version = "0.4" + +[target."cfg(target_os = \"windows\")".dependencies.winapi] +version = "0.3" +features = ["profileapi"] diff --git a/vendor/quanta-0.11.1/LICENSE b/vendor/quanta-0.11.1/LICENSE new file mode 100644 index 0000000000000..659dd929b260c --- /dev/null +++ b/vendor/quanta-0.11.1/LICENSE @@ -0,0 +1,19 @@ +// Copyright (c) 2019 Nuclear Furnace +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. diff --git a/vendor/quanta-0.11.1/README.md b/vendor/quanta-0.11.1/README.md new file mode 100644 index 0000000000000..555f126f5f6d6 --- /dev/null +++ b/vendor/quanta-0.11.1/README.md @@ -0,0 +1,97 @@ +# quanta + +[![conduct-badge][]][conduct] [![gh-actions-badge][]][gh-actions] [![downloads-badge][] ![release-badge][]][crate] [![docs-badge][]][docs] [![libraries-io-badge][]][libraries-io] [![license-badge][]](#license) + +[conduct-badge]: https://img.shields.io/badge/%E2%9D%A4-code%20of%20conduct-blue.svg +[gh-actions-badge]: https://github.com/metrics-rs/quanta/workflows/Rust/badge.svg +[downloads-badge]: https://img.shields.io/crates/d/quanta.svg +[release-badge]: https://img.shields.io/crates/v/quanta.svg +[license-badge]: https://img.shields.io/crates/l/quanta.svg +[docs-badge]: https://docs.rs/quanta/badge.svg +[libraries-io-badge]: https://img.shields.io/librariesio/github/metrics-rs/quanta.svg +[libraries-io]: https://libraries.io/cargo/quanta +[conduct]: https://github.com/metrics-rs/quanta/blob/main/CODE_OF_CONDUCT.md +[gh-actions]: https://github.com/metrics-rs/quanta/actions +[crate]: https://crates.io/crates/quanta +[docs]: https://docs.rs/quanta + +__quanta__ is a high-speed timing library, useful for getting the current time _very quickly_, as +well as manipulating it. + +## code of conduct + +**NOTE**: All conversations and contributions to this project shall adhere to the [Code of Conduct][conduct]. + +## usage + +The API documentation of this library can be found at [docs.rs/quanta](https://docs.rs/quanta/). + +## general features +- count CPU cycles via Time Stamp Counter (TSC). or +- get monotonic time, in nanoseconds, based on TSC (or OS fallback) +- extremely low overhead where possible +- mockable +- cross-platform +- fun, science-y name! + +## platform / architecture support + +For most major platforms -- Linux, Windows, and macOS -- with processors made around or after 2008, +you should have no problems using `quanta` with full TSC support. `quanta` will always fallback to +the included stdlib timing facilities if TSC support is not present. The biggest caveat to this, as +evidenced in the compatibility matrix below, is that we only support the TSC on x86/x86_64 platforms. + + +| Platform | stdlib fallback | TSC support? | CI tests? | +|----------------------|-----------------|--------------|-----------| +| Linux (x86/x86_64) | ✅ | ✅ | ✅ | +| Linux (MIPS/ARM) | ✅ | ⌠| ✅ | +| Windows (x86/x86_64) | ✅ | ✅ | ✅ | +| Windows (ARM) | ✅ | ⌠| ⌠| +| macOS (x86/x86_64) | ✅ | ✅ | ✅ | +| macOS (ARM) | ✅ | ⌠| ⌠| +| iOS (ARM) | ✅ | ⌠| ⌠| + +## performance + +`quanta` sits neck-and-neck with native OS time facilities: the cost of `Clock::now` is on par +`Instant::now` from the stdlib, if not better. + +## why use this over stdlib? + +Beyond having a performance edge in specific situations, the ability to use mocked time makes it +easier to actually test that your application is doing the right thing when time is involved. + +Additionally, and as mentioned in the general features section, `quanta` provides a safe/thin +wrapper over accessing the Time Stamp Counter, which allows measuring cycle counts over short +sections of code. This can be relevant/important for accurately measuring performance-critical sections of code. + +## alternative crates + +- [`chrono`](https://docs.rs/chrono): + - based on `std::time::SystemTime`: non-monotonic reads + - focused on timezone-based "date/time" measurements, not intervals/elapsed time + - clock cannot be altered at all (no pause, no discrete updates) +- [`time`](https://docs.rs/time): + - based on `std::time::SystemTime` and `std::time::Instant`: + - `time::Time`/`time::PrimitiveDateTime` use `SystemTime`: non-monotonic reads + - `time::Instant` uses `Instant`: monotonic reads + - focused on timezone-based "date/time" measurements, not interval/elapsed time + - clock cannot be altered at all (no pause, no discrete updates) +- [`clock`](https://docs.rs/clock): + - based on `std::time::SystemTime`: non-monotonic reads + - clock can be swapped (trait-based) + - no free function for acquiring time +- [`clocksource`](https://docs.rs/clocksource): + - based on TSC w/ OS fallback; non-monotonic reads + - clock cannot be altered at all (no pause, no discrete updates) + - depends on unstable `asm!` macro + feature flag to enable TSC + - no free function for acquiring time +- [`pausable_clock`](https://docs.rs/pausable_clock): + - based on `std::time::Instant`: monotonic reads + - clock can be paused (time can be delayed, but not discretely updated) + - no free function for acquiring time + +## license + +__quanta__ is licensed under the MIT license. ([LICENSE](LICENSE) or http://opensource.org/licenses/MIT) diff --git a/vendor/quanta-0.11.1/benches/README.md b/vendor/quanta-0.11.1/benches/README.md new file mode 100644 index 0000000000000..a8f8fe446509b --- /dev/null +++ b/vendor/quanta-0.11.1/benches/README.md @@ -0,0 +1,50 @@ +# Benchmarks + +Benchmarks were performed on an [AMD Ryzen 7 4800HS CPU](https://en.wikichip.org/wiki/amd/ryzen_9/3900). + +```sh +$ cargo bench --bench +$ critcmp new | tail +3 | sort | sed 's# ? ?/sec##' +``` + +## timing +``` +quanta/quanta_instant_now 1.00 9.7±0.01ns +quanta/quanta_instant_recent 1.00 1.5±0.10ns +quanta/quanta_now 1.00 9.1±0.65ns +quanta/quanta_now_delta 1.00 18.4±0.04ns +quanta/quanta_raw 1.00 8.9±0.00ns +quanta/quanta_raw_delta 1.00 18.2±0.03ns +quanta/quanta_raw_scaled 1.00 9.0±0.07ns +quanta/quanta_recent 1.00 1.7±0.00ns +stdlib/instant_delta 1.00 2.2±0.09µs +stdlib/instant_now 1.00 1110.8±48.42ns +``` + +## contention +``` +quanta/now/10 1.00 25.4±9.78ns +quanta/now/1 1.00 10.6±3.50ns +quanta/now/11 1.00 25.5±9.57ns +quanta/now/12 1.00 22.7±4.48ns +quanta/now/2 1.00 16.0±6.11ns +quanta/now/3 1.00 17.4±6.34ns +quanta/now/4 1.00 17.6±5.65ns +quanta/now/5 1.00 16.2±4.96ns +quanta/now/6 1.00 17.9±7.19ns +quanta/now/7 1.00 16.5±5.65ns +quanta/now/8 1.00 17.7±6.06ns +quanta/now/9 1.00 24.4±9.00ns +stdlib/now/10 1.00 1399.3±84.62ns +stdlib/now/1 1.00 1187.1±138.65ns +stdlib/now/11 1.00 1388.3±64.43ns +stdlib/now/12 1.00 1395.2±60.53ns +stdlib/now/2 1.00 1433.9±158.59ns +stdlib/now/3 1.00 1384.1±71.93ns +stdlib/now/4 1.00 1407.1±159.88ns +stdlib/now/5 1.00 1367.0±62.41ns +stdlib/now/6 1.00 1411.6±167.61ns +stdlib/now/7 1.00 1396.0±83.37ns +stdlib/now/8 1.00 1390.6±81.05ns +stdlib/now/9 1.00 1436.7±113.11ns +``` diff --git a/vendor/quanta-0.11.1/benches/contention.rs b/vendor/quanta-0.11.1/benches/contention.rs new file mode 100644 index 0000000000000..2505f96f12caf --- /dev/null +++ b/vendor/quanta-0.11.1/benches/contention.rs @@ -0,0 +1,61 @@ +use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; +use quanta::Instant as QuantaInstant; +use std::{ + sync::Mutex, + thread, + time::{Duration, Instant as StdInstant}, +}; + +const MAX_THREAD_COUNT: u32 = 12; + +fn run(thread_count: u32, iter_count: u64, now: impl Fn() -> I + Sync) -> Duration { + let max_duration = Mutex::new(Duration::new(0, 0)); + + thread::scope(|s| { + for _ in 0..thread_count { + s.spawn(|| { + let start = StdInstant::now(); + + for _ in 0..iter_count { + black_box(now()); + } + + let duration = start.elapsed(); + let mut max_duration = max_duration.lock().unwrap(); + *max_duration = max_duration.max(duration); + }); + } + }); + + let max = *max_duration.lock().unwrap(); + max +} + +fn benchmark(c: &mut Criterion) { + let mut std_group = c.benchmark_group("stdlib"); + for thread_count in 1..=MAX_THREAD_COUNT { + std_group.bench_with_input( + BenchmarkId::new("now", thread_count), + &thread_count, + |b, &thread_count| { + b.iter_custom(|iter_count| run(thread_count, iter_count, StdInstant::now)); + }, + ); + } + std_group.finish(); + + let mut q_group = c.benchmark_group("quanta"); + for thread_count in 1..=MAX_THREAD_COUNT { + q_group.bench_with_input( + BenchmarkId::new("now", thread_count), + &thread_count, + |b, &thread_count| { + b.iter_custom(|iter_count| run(thread_count, iter_count, QuantaInstant::now)); + }, + ); + } + q_group.finish(); +} + +criterion_group!(benches, benchmark); +criterion_main!(benches); diff --git a/vendor/quanta-0.11.1/benches/timing.rs b/vendor/quanta-0.11.1/benches/timing.rs new file mode 100644 index 0000000000000..10f4e07b44754 --- /dev/null +++ b/vendor/quanta-0.11.1/benches/timing.rs @@ -0,0 +1,94 @@ +use criterion::{criterion_group, criterion_main, Bencher, Criterion}; +use quanta::{Clock, Instant as QuantaInstant}; +use std::time::Instant as StdInstant; + +fn time_instant_now(b: &mut Bencher) { + b.iter(StdInstant::now) +} + +fn time_quanta_now(b: &mut Bencher) { + let clock = Clock::new(); + b.iter(|| clock.now()) +} + +fn time_quanta_instant_now(b: &mut Bencher) { + let _ = QuantaInstant::now(); + b.iter(QuantaInstant::now); +} + +fn time_quanta_raw(b: &mut Bencher) { + let clock = Clock::new(); + b.iter(|| clock.raw()) +} + +fn time_quanta_raw_scaled(b: &mut Bencher) { + let clock = Clock::new(); + b.iter(|| clock.scaled(clock.raw())) +} + +fn time_instant_delta(b: &mut Bencher) { + b.iter(|| { + let start = StdInstant::now(); + let d = StdInstant::now() - start; + (d.as_secs() * 1_000_000_000) + u64::from(d.subsec_nanos()) + }) +} + +fn time_quanta_raw_delta(b: &mut Bencher) { + let clock = Clock::new(); + b.iter(|| { + let start = clock.raw(); + let end = clock.raw(); + clock.delta(start, end) + }) +} + +fn time_quanta_raw_delta_as_nanos(b: &mut Bencher) { + let clock = Clock::new(); + b.iter(|| { + let start = clock.raw(); + let end = clock.raw(); + clock.delta_as_nanos(start, end) + }) +} + +fn time_quanta_now_delta(b: &mut Bencher) { + let clock = Clock::new(); + b.iter(|| { + let start = clock.now(); + let end = clock.now(); + end - start + }) +} + +fn time_quanta_recent(b: &mut Bencher) { + let clock = Clock::new(); + b.iter(|| clock.recent()) +} + +fn time_quanta_instant_recent(b: &mut Bencher) { + quanta::set_recent(QuantaInstant::now()); + b.iter(|| QuantaInstant::recent()); +} + +fn benchmark(c: &mut Criterion) { + let mut std_group = c.benchmark_group("stdlib"); + std_group.bench_function("instant_now", time_instant_now); + std_group.bench_function("instant_delta", time_instant_delta); + std_group.finish(); + + let mut q_group = c.benchmark_group("quanta"); + q_group.bench_function("quanta_now", time_quanta_now); + q_group.bench_function("quanta_now_delta", time_quanta_now_delta); + q_group.bench_function("quanta_instant_now", time_quanta_instant_now); + q_group.bench_function("quanta_raw", time_quanta_raw); + q_group.bench_function("quanta_raw_scaled", time_quanta_raw_scaled); + q_group.bench_function("quanta_raw_delta", time_quanta_raw_delta); + q_group.bench_function("quanta_raw_delta_as_nanos", time_quanta_raw_delta_as_nanos); + q_group.bench_function("quanta_recent", time_quanta_recent); + q_group.bench_function("quanta_instant_recent", time_quanta_instant_recent); + q_group.finish(); +} + +criterion_group!(benches, benchmark); +criterion_main!(benches); diff --git a/vendor/quanta-0.11.1/release.toml b/vendor/quanta-0.11.1/release.toml new file mode 100644 index 0000000000000..f573798a1a20a --- /dev/null +++ b/vendor/quanta-0.11.1/release.toml @@ -0,0 +1,10 @@ +no-dev-version = true +sign-commit = true +sign-tag = true +pre-release-replacements = [ + {file="CHANGELOG.md", search="Unreleased", replace="{{version}}"}, + {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1}, + {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}"}, + {file="CHANGELOG.md", search="", replace="\n\n## [Unreleased] - ReleaseDate", exactly=1}, + {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/metrics-rs/quanta/compare/{{tag_name}}...HEAD", exactly=1}, +] diff --git a/vendor/quanta-0.11.1/rust-toolchain.toml b/vendor/quanta-0.11.1/rust-toolchain.toml new file mode 100644 index 0000000000000..292fe499e3b25 --- /dev/null +++ b/vendor/quanta-0.11.1/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" diff --git a/vendor/quanta-0.11.1/src/clocks/counter.rs b/vendor/quanta-0.11.1/src/clocks/counter.rs new file mode 100644 index 0000000000000..0288df67b1152 --- /dev/null +++ b/vendor/quanta-0.11.1/src/clocks/counter.rs @@ -0,0 +1,19 @@ +#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +use core::arch::x86_64::_rdtsc; + +#[derive(Clone, Debug, Default)] +pub struct Counter; + +#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +impl Counter { + pub fn now(&self) -> u64 { + unsafe { _rdtsc() } + } +} + +#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))] +impl Counter { + pub fn now(&self) -> u64 { + panic!("can't use counter without TSC support"); + } +} diff --git a/vendor/quanta-0.11.1/src/clocks/mod.rs b/vendor/quanta-0.11.1/src/clocks/mod.rs new file mode 100644 index 0000000000000..5696393f27bb2 --- /dev/null +++ b/vendor/quanta-0.11.1/src/clocks/mod.rs @@ -0,0 +1,5 @@ +mod counter; +pub use self::counter::Counter; + +mod monotonic; +pub use self::monotonic::Monotonic; diff --git a/vendor/quanta-0.11.1/src/clocks/monotonic/macos.rs b/vendor/quanta-0.11.1/src/clocks/monotonic/macos.rs new file mode 100644 index 0000000000000..8c3ea9f0f14fc --- /dev/null +++ b/vendor/quanta-0.11.1/src/clocks/monotonic/macos.rs @@ -0,0 +1,24 @@ +use mach2::mach_time::{mach_absolute_time, mach_timebase_info}; + +#[derive(Clone, Copy, Debug)] +pub struct Monotonic { + factor: u64, +} +impl Monotonic { + pub fn now(&self) -> u64 { + let raw = unsafe { mach_absolute_time() }; + raw * self.factor + } +} + +impl Default for Monotonic { + fn default() -> Self { + let mut info = mach_timebase_info { numer: 0, denom: 0 }; + unsafe { + mach_timebase_info(&mut info); + } + + let factor = u64::from(info.numer) / u64::from(info.denom); + Self { factor } + } +} diff --git a/vendor/quanta-0.11.1/src/clocks/monotonic/mod.rs b/vendor/quanta-0.11.1/src/clocks/monotonic/mod.rs new file mode 100644 index 0000000000000..3960e4f267667 --- /dev/null +++ b/vendor/quanta-0.11.1/src/clocks/monotonic/mod.rs @@ -0,0 +1,29 @@ +#[cfg(any(target_os = "macos", target_os = "ios"))] +mod macos; +#[cfg(any(target_os = "macos", target_os = "ios"))] +pub use self::macos::Monotonic; + +#[cfg(target_os = "windows")] +mod windows; +#[cfg(target_os = "windows")] +pub use self::windows::Monotonic; + +#[cfg(target_arch = "wasm32")] +mod wasm; +#[cfg(target_arch = "wasm32")] +pub use self::wasm::Monotonic; + +#[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "windows", + target_arch = "wasm32" +)))] +mod unix; +#[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "windows", + target_arch = "wasm32" +)))] +pub use self::unix::Monotonic; diff --git a/vendor/quanta-0.11.1/src/clocks/monotonic/unix.rs b/vendor/quanta-0.11.1/src/clocks/monotonic/unix.rs new file mode 100644 index 0000000000000..74ae076fc0e39 --- /dev/null +++ b/vendor/quanta-0.11.1/src/clocks/monotonic/unix.rs @@ -0,0 +1,36 @@ +#[derive(Clone, Copy, Debug, Default)] +pub struct Monotonic; + +impl Monotonic { + #[allow(clippy::cast_sign_loss)] + pub fn now(self) -> u64 { + let mut ts = libc::timespec { + tv_sec: 0, + tv_nsec: 0, + }; + unsafe { + libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts); + } + + // LINT JUSTIFICATION: + // + // We really don't ever expect to actually _get_ negative values from `clock_gettime`, but + // given the types, it's technically possible. This is due to the fact that `tv_sec` is + // supposed to be `time_t`, which Unix/POSIX-compliant systems implement as a signed number. + // Accordingly, `tv_nsec` follows suit using a signed number. + // + // Given the adjustments made by NTP to clocks like CLOCK_MONOTONIC, and that + // CLOCK_MONOTONIC can be anchored to an arbitrary point, and a whole skew of other + // scenarios where it could be modified... it's technicaly possible to get back valid + // negative values. If we did math between `timespec` objects, the delta should be valid, + // even with negative numbers. + // + // We're returning a u64 here, though, so it is what it is. In practice, I've _never_ seen + // negative values under normal operation. If someone discovers a valid scenario where this + // is violated and that we need to account for, I'll be colored impressed, but also, file an + // issue and we'll do what we have to do to rework the code to try and support it better. + // + // Until then, though, we're just gonna ignore the lint. + ts.tv_sec as u64 * 1_000_000_000 + ts.tv_nsec as u64 + } +} diff --git a/vendor/quanta-0.11.1/src/clocks/monotonic/wasm.rs b/vendor/quanta-0.11.1/src/clocks/monotonic/wasm.rs new file mode 100644 index 0000000000000..24db95f5c340a --- /dev/null +++ b/vendor/quanta-0.11.1/src/clocks/monotonic/wasm.rs @@ -0,0 +1,25 @@ +const WASM_WRONG_ENV: &str = "failed to find the global `window` object: the `wasm32-unknown-unknown` implementation only supports running in web browsers; wse `wasm32-wasi` to run elsewhere"; +const WASM_MISSING_WINDOW_PERF: &str = "failed to find `window.performance`"; + +#[derive(Clone, Copy, Debug, Default)] +pub struct Monotonic; + +#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] +impl Monotonic { + pub fn now(&self) -> u64 { + let now = web_sys::window() + .expect(WASM_WRONG_ENV) + .performance() + .expect(WASM_MISSING_WINDOW_PERF) + .now(); + // `window.performance.now()` returns the time in milliseconds. + return f64::trunc(now * 1_000_000.0) as u64; + } +} + +#[cfg(all(target_arch = "wasm32", target_os = "wasi"))] +impl Monotonic { + pub fn now(&self) -> u64 { + unsafe { wasi::clock_time_get(wasi::CLOCKID_MONOTONIC, 1).expect("failed to get time") } + } +} diff --git a/vendor/quanta-0.11.1/src/clocks/monotonic/windows.rs b/vendor/quanta-0.11.1/src/clocks/monotonic/windows.rs new file mode 100644 index 0000000000000..ee48924e75e16 --- /dev/null +++ b/vendor/quanta-0.11.1/src/clocks/monotonic/windows.rs @@ -0,0 +1,42 @@ +use std::mem; +use winapi::um::profileapi; + +#[derive(Clone, Copy, Debug)] +pub struct Monotonic { + factor: u64, +} + +impl Monotonic { + pub fn now(&self) -> u64 { + let raw = unsafe { + // TODO: Can we do any better than the `mem::zeroed` call here? + let mut count = mem::zeroed(); + if profileapi::QueryPerformanceCounter(&mut count) == 0 { + unreachable!( + "QueryPerformanceCounter on Windows XP or later should never return zero!" + ); + } + *count.QuadPart() as u64 + }; + raw * self.factor + } +} + +impl Default for Monotonic { + fn default() -> Self { + let denom = unsafe { + // TODO: Can we do any better than the `mem::zeroed` call here? + let mut freq = mem::zeroed(); + if profileapi::QueryPerformanceFrequency(&mut freq) == 0 { + unreachable!( + "QueryPerformanceFrequency on Windows XP or later should never return zero!" + ); + } + *freq.QuadPart() as u64 + }; + + Self { + factor: 1_000_000_000 / denom, + } + } +} diff --git a/vendor/quanta-0.11.1/src/instant.rs b/vendor/quanta-0.11.1/src/instant.rs new file mode 100644 index 0000000000000..8ed226dcac953 --- /dev/null +++ b/vendor/quanta-0.11.1/src/instant.rs @@ -0,0 +1,376 @@ +use std::cmp::{Ord, Ordering, PartialOrd}; +use std::fmt; +use std::ops::{Add, AddAssign, Sub, SubAssign}; +use std::time::Duration; + +/// A point-in-time wall-clock measurement. +/// +/// Mimics most of the functionality of [`std::time::Instant`] but provides an additional method for +/// using the "recent time" feature of `quanta`. +/// +/// ## Monotonicity +/// +/// On all platforms, `Instant` will try to use an OS API that guarantees monotonic behavior if +/// available, which is the case for all supported platforms. In practice such guarantees are – +/// under rare circumstances – broken by hardware, virtualization or operating system bugs. To work +/// around these bugs and platforms not offering monotonic clocks [`duration_since`], [`elapsed`] +/// and [`sub`] saturate to zero. In older `quanta` versions this lead to a panic instead. +/// [`checked_duration_since`] can be used to detect and handle situations where monotonicity is +/// violated, or `Instant`s are subtracted in the wrong order. +/// +/// This workaround obscures programming errors where earlier and later instants are accidentally +/// swapped. For this reason future `quanta` versions may reintroduce panics. +/// +/// [`duration_since`]: Instant::duration_since +/// [`elapsed`]: Instant::elapsed +/// [`sub`]: Instant::sub +/// [`checked_duration_since`]: Instant::checked_duration_since +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct Instant(pub(crate) u64); + +impl Instant { + /// Gets the current time, scaled to reference time. + /// + /// This method depends on a lazily initialized global clock, which can take up to 200ms to + /// initialize and calibrate itself. + /// + /// This method is the spiritual equivalent of [`Instant::now`][instant_now]. It is guaranteed to + /// return a monotonically increasing value. + /// + /// [instant_now]: std::time::Instant::now + pub fn now() -> Instant { + crate::get_now() + } + + /// Gets the most recent current time, scaled to reference time. + /// + /// This method provides ultra-low-overhead access to a slightly-delayed version of the current + /// time. Instead of querying the underlying source clock directly, a shared, global value is + /// read directly without the need to scale to reference time. + /// + /// The value is updated by running an "upkeep" thread or by calling [`set_recent`][set_recent]. An + /// upkeep thread can be configured and spawned via [`Upkeep`][upkeep]. + /// + /// If the upkeep thread has not been started, or no value has been set manually, a lazily + /// initialized global clock will be used to get the current time. This clock can take up to + /// 200ms to initialize and calibrate itself. + /// + /// [set_recent]: crate::set_recent + /// [upkeep]: crate::Upkeep + pub fn recent() -> Instant { + crate::get_recent() + } + + /// Returns the amount of time elapsed from another instant to this one. + /// + /// # Panics + /// + /// Previous versions of this method panicked when earlier was later than `self`. Currently, + /// this method saturates to zero. Future versions may reintroduce the panic in some + /// circumstances. See [Monotonicity]. + /// + /// [Monotonicity]: Instant#monotonicity + /// + /// # Examples + /// + /// ```no_run + /// use quanta::Clock; + /// use std::time::Duration; + /// use std::thread::sleep; + /// + /// let mut clock = Clock::new(); + /// let now = clock.now(); + /// sleep(Duration::new(1, 0)); + /// let new_now = clock.now(); + /// println!("{:?}", new_now.duration_since(now)); + /// ``` + pub fn duration_since(&self, earlier: Instant) -> Duration { + self.checked_duration_since(earlier).unwrap_or_default() + } + + /// Returns the amount of time elapsed from another instant to this one, or `None` if that + /// instant is earlier than this one. + /// + /// Due to [monotonicity bugs], even under correct logical ordering of the passed `Instant`s, + /// this method can return `None`. + /// + /// [monotonicity bugs]: Instant#monotonicity + /// + /// # Examples + /// + /// ```no_run + /// use quanta::Clock; + /// use std::time::Duration; + /// use std::thread::sleep; + /// + /// let mut clock = Clock::new(); + /// let now = clock.now(); + /// sleep(Duration::new(1, 0)); + /// let new_now = clock.now(); + /// println!("{:?}", new_now.checked_duration_since(now)); + /// println!("{:?}", now.checked_duration_since(new_now)); // None + /// ``` + pub fn checked_duration_since(&self, earlier: Instant) -> Option { + self.0.checked_sub(earlier.0).map(Duration::from_nanos) + } + + /// Returns the amount of time elapsed from another instant to this one, or zero duration if + /// that instant is earlier than this one. + /// + /// Due to [monotonicity bugs], even under correct logical ordering of the passed `Instant`s, + /// this method can return `None`. + /// + /// [monotonicity bugs]: Instant#monotonicity + /// + /// # Examples + /// + /// ```no_run + /// use quanta::Clock; + /// use std::time::Duration; + /// use std::thread::sleep; + /// + /// let mut clock = Clock::new(); + /// let now = clock.now(); + /// sleep(Duration::new(1, 0)); + /// let new_now = clock.now(); + /// println!("{:?}", new_now.saturating_duration_since(now)); + /// println!("{:?}", now.saturating_duration_since(new_now)); // 0ns + /// ``` + pub fn saturating_duration_since(&self, earlier: Instant) -> Duration { + self.checked_duration_since(earlier).unwrap_or_default() + } + + /// Returns the amount of time elapsed since this instant was created. + /// + /// # Panics + /// + /// Previous `quanta` versions panicked when the current time was earlier than self. Currently + /// this method returns a Duration of zero in that case. Future versions may reintroduce the + /// panic. See [Monotonicity]. + /// + /// [Monotonicity]: Instant#monotonicity + /// + /// # Examples + /// + /// ```no_run + /// use quanta::Clock; + /// use std::time::Duration; + /// use std::thread::sleep; + /// + /// let mut clock = Clock::new(); + /// let now = clock.now(); + /// sleep(Duration::new(1, 0)); + /// let elapsed = now.elapsed(); + /// println!("{:?}", elapsed); // ≥ 1s + /// ``` + pub fn elapsed(&self) -> Duration { + Instant::now() - *self + } + + /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as + /// `Instant` (which means it's inside the bounds of the underlying data structure), `None` + /// otherwise. + pub fn checked_add(&self, duration: Duration) -> Option { + self.0.checked_add(duration.as_nanos() as u64).map(Instant) + } + + /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as + /// `Instant` (which means it's inside the bounds of the underlying data structure), `None` + /// otherwise. + pub fn checked_sub(&self, duration: Duration) -> Option { + self.0.checked_sub(duration.as_nanos() as u64).map(Instant) + } +} + +impl Add for Instant { + type Output = Instant; + + /// # Panics + /// + /// This function may panic if the resulting point in time cannot be represented by the + /// underlying data structure. See [`Instant::checked_add`] for a version without panic. + fn add(self, other: Duration) -> Instant { + self.checked_add(other) + .expect("overflow when adding duration to instant") + } +} + +impl AddAssign for Instant { + fn add_assign(&mut self, other: Duration) { + // This is not millenium-safe, but, I think that's OK. :) + self.0 = self.0 + other.as_nanos() as u64; + } +} + +impl Sub for Instant { + type Output = Instant; + + fn sub(self, other: Duration) -> Instant { + self.checked_sub(other) + .expect("overflow when subtracting duration from instant") + } +} + +impl SubAssign for Instant { + fn sub_assign(&mut self, other: Duration) { + // This is not millenium-safe, but, I think that's OK. :) + self.0 = self.0 - other.as_nanos() as u64; + } +} + +impl Sub for Instant { + type Output = Duration; + + /// Returns the amount of time elapsed from another instant to this one, + /// or zero duration if that instant is later than this one. + /// + /// # Panics + /// + /// Previous `quanta` versions panicked when `other` was later than `self`. Currently this + /// method saturates. Future versions may reintroduce the panic in some circumstances. + /// See [Monotonicity]. + /// + /// [Monotonicity]: Instant#monotonicity + fn sub(self, other: Instant) -> Duration { + self.duration_since(other) + } +} + +impl PartialOrd for Instant { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Instant { + fn cmp(&self, other: &Self) -> Ordering { + self.0.cmp(&other.0) + } +} + +impl fmt::Debug for Instant { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[cfg(feature = "prost")] +impl Into for Instant { + fn into(self) -> prost_types::Timestamp { + let dur = Duration::from_nanos(self.0); + let secs = if dur.as_secs() > i64::MAX as u64 { + i64::MAX + } else { + dur.as_secs() as i64 + }; + let nsecs = if dur.subsec_nanos() > i32::MAX as u32 { + i32::MAX + } else { + dur.subsec_nanos() as i32 + }; + prost_types::Timestamp { + seconds: secs, + nanos: nsecs, + } + } +} + +#[cfg(test)] +mod tests { + use once_cell::sync::Lazy; + + use super::Instant; + use crate::{with_clock, Clock}; + use std::time::Duration; + use std::{sync::Mutex, thread}; + + static RECENT_LOCK: Lazy> = Lazy::new(|| Mutex::new(())); + + #[test] + #[cfg_attr( + all(target_arch = "wasm32", target_os = "unknown"), + ignore = "WASM thread cannot sleep" + )] + fn test_now() { + let _guard = RECENT_LOCK.lock().unwrap(); + + let t0 = Instant::now(); + thread::sleep(Duration::from_millis(15)); + let t1 = Instant::now(); + + assert!(t0.0 > 0); + assert!(t1.0 > 0); + + let result = t1 - t0; + let threshold = Duration::from_millis(14); + assert!(result > threshold); + } + + #[test] + #[cfg_attr( + all(target_arch = "wasm32", target_os = "unknown"), + ignore = "WASM thread cannot sleep" + )] + fn test_recent() { + let _guard = RECENT_LOCK.lock().unwrap(); + + // Ensures that the recent global value is zero so that the fallback logic can kick in. + crate::set_recent(Instant(0)); + + let t0 = Instant::recent(); + thread::sleep(Duration::from_millis(15)); + let t1 = Instant::recent(); + + assert!(t0.0 > 0); + assert!(t1.0 > 0); + + let result = t1 - t0; + let threshold = Duration::from_millis(14); + assert!( + result > threshold, + "t1 should be greater than t0 by at least 14ms, was only {}ms (t0: {}, t1: {})", + result.as_millis(), + t0.0, + t1.0 + ); + + crate::set_recent(Instant(1)); + let t2 = Instant::recent(); + thread::sleep(Duration::from_millis(15)); + let t3 = Instant::recent(); + assert_eq!(t2, t3); + } + + #[test] + #[cfg_attr( + all(target_arch = "wasm32", target_os = "unknown"), + wasm_bindgen_test::wasm_bindgen_test + )] + fn test_mocking() { + let _guard = RECENT_LOCK.lock().unwrap(); + + // Ensures that the recent global value is zero so that the fallback logic can kick in. + crate::set_recent(Instant(0)); + + let (clock, mock) = Clock::mock(); + with_clock(&clock, move || { + let t0 = Instant::now(); + mock.increment(42); + let t1 = Instant::now(); + + assert_eq!(t0.0, 0); + assert_eq!(t1.0, 42); + + let t2 = Instant::recent(); + mock.increment(420); + let t3 = Instant::recent(); + + assert_eq!(t2.0, 42); + assert_eq!(t3.0, 462); + + crate::set_recent(Instant(1440)); + let t4 = Instant::recent(); + assert_eq!(t4.0, 1440); + }) + } +} diff --git a/vendor/quanta-0.11.1/src/lib.rs b/vendor/quanta-0.11.1/src/lib.rs new file mode 100644 index 0000000000000..d5277ff960abd --- /dev/null +++ b/vendor/quanta-0.11.1/src/lib.rs @@ -0,0 +1,753 @@ +//! Performant cross-platform timing with goodies. +//! +//! `quanta` provides a simple and fast API for measuring the current time and the duration between +//! events. It does this by providing a thin layer on top of native OS timing functions, or, if +//! available, using the Time Stamp Counter feature found on modern CPUs. +//! +//! # Design +//! +//! Internally, `quanta` maintains the concept of two potential clock sources: a reference clock and +//! a source clock. +//! +//! The reference clock is provided by the OS, and always available. It is equivalent to what is +//! provided by the standard library in terms of the underlying system calls being made. As it uses +//! the native timing facilities provided by the operating system, we ultimately depend on the OS +//! itself to give us a stable and correct value. +//! +//! The source clock is a potential clock source based on the [Time Stamp Counter][tsc] feature +//! found on modern CPUs. If the TSC feature is not present or is not reliable enough, `quanta` +//! will transparently utilize the reference clock instead. +//! +//! Depending on the underlying processor(s) in the system, `quanta` will figure out the most +//! accurate/efficient way to calibrate the source clock to the reference clock in order to provide +//! measurements scaled to wall clock time. +//! +//! Details on TSC support, and calibration, are detailed below. +//! +//! # Features +//! +//! Beyond simply taking measurements of the current time, `quanta` provides features for more +//! easily working with clocks, as well as being able to enhance performance further: +//! - `Clock` can be mocked for testing +//! - globally accessible "recent" time with amortized overhead +//! +//! ## Mocked time +//! +//! For any code that uses a `Clock`, a mocked version can be substituted. This allows for +//! application authors to control the time in tests, which allows simulating not only the normal +//! passage of time but provides the ability to warp time forwards and backwards in order to test +//! corner cases in logic, etc. Creating a mocked clock can be acheived with [`Clock::mock`], and +//! [`Mock`] contains more details on mock usage. +//! +//! ## Coarsely-updated, or recent, time +//! +//! `quanta` also provides a "recent" time feature, which allows a slightly-delayed version of time +//! to be provided to callers, trading accuracy for speed of access. An upkeep thread is spawned, +//! which is responsible for taking measurements and updating the global recent time. Callers then +//! can access the cached value by calling `Clock::recent`. This interface can be 4-10x faster than +//! directly calling `Clock::now`, even when TSC support is available. As the upkeep thread is the +//! only code updating the recent time, the accuracy of the value given to callers is limited by how +//! often the upkeep thread updates the time, thus the trade off between accuracy and speed of +//! access. +//! +//! # Feature Flags +//! +//! `quanta` comes with feature flags that enable convenient conversions to time types in other +//! popular crates, such as: +//! - `prost` - provides an implementation into [`Timestamp`][prost_types_timestamp] from +//! `prost_types` +//! +//! # Platform Support +//! +//! At a high level, `quanta` carries support for most major operating systems out of the box: +//! - Windows ([`QueryPerformanceCounter`][QueryPerformanceCounter]) +//! - macOS/OS X/iOS ([`mach_absolute_time`][mach_absolute_time]) +//! - Linux/*BSD/Solaris ([`clock_gettime`][clock_gettime]) +//! +//! These platforms are supported in the "reference" clock sense, and support for using the Time +//! Stamp Counter as a clocksource is more subtle, and explained below. +//! +//! ## WASM support +//! +//! This library can be built for WASM targets, but in this case the resolution and accuracy of +//! measurements can be limited by the WASM environment. In particular, when running on the +//! `wasm32-unknown-unknown` target in browsers, `quanta` will use [windows.performance.now] as a +//! clock. This mean the accuracy is limited to milliseconds instead of the usual nanoseconds on +//! other targets. When running within a WASI environment (target `wasm32-wasi`), the accuracy of +//! the clock depends on the VM implementation. +//! +//! # TSC Support +//! +//! Accessing the TSC requires being on the `x86_64` architecture, with access to SSE2. +//! Additionally, the processor must support either constant or nonstop/invariant TSC. This ensures +//! that the TSC ticks at a constant rate which can be easily scaled. +//! +//! A caveat is that "constant" TSC doesn't account for all possible power states (levels of power +//! down or sleep that a CPU can enter to save power under light load, etc) and so a constant TSC +//! can lead to drift in measurements over time, after they've been scaled to reference time. +//! +//! This is a limitation of the TSC mode, as well as the nature of `quanta` not being able to know, +//! as the OS would, when a power state transition has happened, and thus compensate with a +//! recalibration. Nonstop/invariant TSC does not have this limitation and is stable over long +//! periods of time. +//! +//! Roughly speaking, the following list contains the beginning model/generation of processors where +//! you should be able to expect having invariant TSC support: +//! - Intel Nehalem and newer for server-grade +//! - Intel Skylake and newer for desktop-grade +//! - VIA Centaur Nano and newer (circumstantial evidence here) +//! - AMD Phenom and newer +//! +//! Ultimately, `quanta` will query CPUID information to determine if the processor has the required +//! features to use the TSC. +//! +//! # Calibration +//! +//! As the TSC doesn't necessarily tick at reference scale -- i.e. one tick isn't always one +//! nanosecond -- we have to apply a scaling factor when converting from source to reference time +//! scale to provide this. We acquire this scaling factor by repeatedly taking measurements from +//! both the reference and source clocks, until we have a statistically-relevant measure of the +//! average scaling factor. We do some additional work to convert this scaling factor into a +//! power-of-two number that allows us to optimize the code, and thus reduce the generated +//! instructions required to scale a TSC value. +//! +//! This calibration is stored globally and reused. However, the first `Clock` that is created in +//! an application will block for a small period of time as it runs this calibration loop. The time +//! spent in the calibration loop is limited to 200ms overall. In practice, `quanta` will reach a +//! stable calibration quickly (usually 10-20ms, if not less) and so this deadline is unlikely to be +//! reached. +//! +//! # Caveats +//! +//! Utilizing the TSC can be a tricky affair, and so here is a list of caveats that may or may not +//! apply, and is in no way exhaustive: +//! - CPU hotplug behavior is undefined +//! - raw values may time warp +//! - measurements from the TSC may drift past or behind the comparable reference clock +//! +//! Another important caveat is that `quanta` does not track time across system suspends. Simply +//! put, if a time measurement (such as using [`Instant::now`][crate::Instant::now]) is taken, and +//! then the system is suspended, and then another measurement is taken, the difference between +//! those the two would not include the time the system was in suspend. +//! +//! [tsc]: https://en.wikipedia.org/wiki/Time_Stamp_Counter +//! [QueryPerformanceCounter]: https://msdn.microsoft.com/en-us/library/ms644904(v=VS.85).aspx +//! [mach_absolute_time]: https://developer.apple.com/documentation/kernel/1462446-mach_absolute_time +//! [clock_gettime]: https://linux.die.net/man/3/clock_gettime +//! [prost_types_timestamp]: https://docs.rs/prost-types/0.7.0/prost_types/struct.Timestamp.html +//! [windows.performance.now]: https://developer.mozilla.org/en-US/docs/Web/API/Performance/now +#![deny(missing_docs)] +#![deny(clippy::all)] +#![allow(clippy::must_use_candidate)] + +use crossbeam_utils::atomic::AtomicCell; +use std::time::Duration; +use std::{cell::RefCell, sync::Arc}; + +use once_cell::sync::OnceCell; + +mod clocks; +use self::clocks::{Counter, Monotonic}; +mod mock; +pub use self::mock::{IntoNanoseconds, Mock}; +mod instant; +pub use self::instant::Instant; +mod upkeep; +pub use self::upkeep::{Error, Handle, Upkeep}; +mod stats; +use self::stats::Variance; + +// Global clock, used by `Instant::now`. +static GLOBAL_CLOCK: OnceCell = OnceCell::new(); + +// Global recent measurement, used by `Clock::recent` and `Instant::recent`. +static GLOBAL_RECENT: AtomicCell = AtomicCell::new(0); + +// Global calibration, shared by all clocks. +static GLOBAL_CALIBRATION: OnceCell = OnceCell::new(); + +// Per-thread clock override, used by `quanta::with_clock`, `Instant::now`, and sometimes `Instant::recent`. +thread_local! { + static CLOCK_OVERRIDE: RefCell> = RefCell::new(None); +} + +// Run 500 rounds of calibration before we start actually seeing what the numbers look like. +const MINIMUM_CAL_ROUNDS: u64 = 500; + +// We want our maximum error to be 10 nanoseconds. +const MAXIMUM_CAL_ERROR_NS: u64 = 10; + +// Don't run the calibration loop for longer than 200ms of wall time. +const MAXIMUM_CAL_TIME_NS: u64 = 200 * 1000 * 1000; + +#[derive(Debug)] +enum ClockType { + Monotonic(Monotonic), + Counter(Monotonic, Counter, Calibration), + Mock(Arc), +} + +#[derive(Debug, Copy, Clone)] +pub(crate) struct Calibration { + ref_time: u64, + src_time: u64, + scale_factor: u64, + scale_shift: u32, +} + +impl Calibration { + fn new() -> Calibration { + Calibration { + ref_time: 0, + src_time: 0, + scale_factor: 1, + scale_shift: 1, + } + } + + fn reset_timebases(&mut self, reference: Monotonic, source: &Counter) { + self.ref_time = reference.now(); + self.src_time = source.now(); + } + + fn scale_src_to_ref(&self, src_raw: u64) -> u64 { + let delta = src_raw.saturating_sub(self.src_time); + let scaled = mul_div_po2_u64(delta, self.scale_factor, self.scale_shift); + scaled + self.ref_time + } + + fn calibrate(&mut self, reference: Monotonic, source: &Counter) { + let mut variance = Variance::default(); + let deadline = reference.now() + MAXIMUM_CAL_TIME_NS; + + self.reset_timebases(reference, source); + + // Each busy loop should spin for 1 microsecond. (1000 nanoseconds) + let loop_delta = 1000; + loop { + // Busy loop to burn some time. + let mut last = reference.now(); + let target = last + loop_delta; + while last < target { + last = reference.now(); + } + + // We put an upper bound on how long we run calibration before to provide a predictable + // overhead to the calibration process. In practice, even if we hit the calibration + // deadline, we should still have run a sufficient number of rounds to get an accurate + // calibration. + if last >= deadline { + break; + } + + // Adjust our calibration before we take our measurement. + self.adjust_cal_ratio(reference, source); + + let r_time = reference.now(); + let s_raw = source.now(); + let s_time = self.scale_src_to_ref(s_raw); + variance.add(s_time as f64 - r_time as f64); + + // If we've collected enough samples, check what the mean and mean error are. If we're + // already within the target bounds, we can break out of the calibration loop early. + if variance.has_significant_result() { + let mean = variance.mean().abs(); + let mean_error = variance.mean_error().abs(); + let mwe = variance.mean_with_error(); + let samples = variance.samples(); + + if samples > MINIMUM_CAL_ROUNDS + && mwe < MAXIMUM_CAL_ERROR_NS as f64 + && mean_error / mean <= 1.0 + { + break; + } + } + } + } + + fn adjust_cal_ratio(&mut self, reference: Monotonic, source: &Counter) { + // Overall algorithm: measure the delta between our ref/src_time values and "now" versions + // of them, calculate the ratio between the deltas, and then find a numerator and + // denominator to express that ratio such that the denominator is always a power of two. + // + // In practice, this means we take the "source" delta, and find the next biggest number that + // is a power of two. We then figure out the ratio that describes the difference between + // _those_ two values, and multiple the "reference" delta by that much, which becomes our + // numerator while the power-of-two "source" delta becomes our denominator. + // + // Then, conversion from a raw value simply becomes a multiply and a bit shift instead of a + // multiply and full-blown divide. + let ref_end = reference.now(); + let src_end = source.now(); + + let ref_d = ref_end.wrapping_sub(self.ref_time); + let src_d = src_end.wrapping_sub(self.src_time); + + let src_d_po2 = src_d + .checked_next_power_of_two() + .unwrap_or_else(|| 2_u64.pow(63)); + + // TODO: lossy conversion back and forth just to get an approximate value, can we do better + // with integer math? not sure + let po2_ratio = src_d_po2 as f64 / src_d as f64; + self.scale_factor = (ref_d as f64 * po2_ratio) as u64; + self.scale_shift = src_d_po2.trailing_zeros(); + } +} + +impl Default for Calibration { + fn default() -> Self { + Self::new() + } +} + +/// Unified clock for taking measurements. +#[derive(Debug, Clone)] +pub struct Clock { + inner: ClockType, +} + +impl Clock { + /// Creates a new clock with the optimal reference and source clocks. + /// + /// Support for TSC, etc, are checked at the time of creation, not compile-time. + pub fn new() -> Clock { + let reference = Monotonic::default(); + let inner = if has_tsc_support() { + let source = Counter::default(); + let calibration = GLOBAL_CALIBRATION.get_or_init(|| { + let mut calibration = Calibration::new(); + calibration.calibrate(reference, &source); + calibration + }); + ClockType::Counter(reference, source, *calibration) + } else { + ClockType::Monotonic(reference) + }; + + Clock { inner } + } + + /// Creates a new clock that is mocked for controlling the underlying time. + /// + /// Returns a [`Clock`] instance and a handle to the underlying [`Mock`] source so that the + /// caller can control the passage of time. + pub fn mock() -> (Clock, Arc) { + let mock = Arc::new(Mock::new()); + let clock = Clock { + inner: ClockType::Mock(mock.clone()), + }; + + (clock, mock) + } + + /// Gets the current time, scaled to reference time. + /// + /// This method is the spiritual equivalent of [`std::time::Instant::now`]. It is guaranteed + /// to return a monotonically increasing value between calls to the same `Clock` instance. + /// + /// Returns an [`Instant`]. + pub fn now(&self) -> Instant { + match &self.inner { + ClockType::Monotonic(monotonic) => Instant(monotonic.now()), + ClockType::Counter(_, counter, _) => self.scaled(counter.now()), + ClockType::Mock(mock) => Instant(mock.value()), + } + } + + /// Gets the underlying time from the fastest available clock source. + /// + /// As the clock source may or may not be the TSC, value is not guaranteed to be in nanoseconds + /// or to be monotonic. Value can be scaled to reference time by calling either [`scaled`] + /// or [`delta`]. + /// + /// [`scaled`]: Clock::scaled + /// [`delta`]: Clock::delta + pub fn raw(&self) -> u64 { + match &self.inner { + ClockType::Monotonic(monotonic) => monotonic.now(), + ClockType::Counter(_, counter, _) => counter.now(), + ClockType::Mock(mock) => mock.value(), + } + } + + /// Scales a raw measurement to reference time. + /// + /// You must scale raw measurements to ensure your result is in nanoseconds. The raw + /// measurement is not guaranteed to be in nanoseconds and may vary. It is only OK to avoid + /// scaling raw measurements if you don't need actual nanoseconds. + /// + /// Returns an [`Instant`]. + pub fn scaled(&self, value: u64) -> Instant { + let scaled = match &self.inner { + ClockType::Counter(_, _, calibration) => calibration.scale_src_to_ref(value), + _ => value, + }; + + Instant(scaled) + } + + /// Calculates the delta, in nanoseconds, between two raw measurements. + /// + /// This method is very similar to [`delta`] but reduces overhead + /// for high-frequency measurements that work with nanosecond + /// counts internally, as it avoids the conversion of the delta + /// into [`Duration`]. + /// + /// [`delta`]: Clock::delta + pub fn delta_as_nanos(&self, start: u64, end: u64) -> u64 { + // Safety: we want wrapping_sub on the end/start delta calculation so that two measurements + // split across a rollover boundary still return the right result. However, we also know + // the TSC could potentially give us different values between cores/sockets, so we're just + // doing our due diligence here to make sure we're not about to create some wacky duration. + if end <= start { + return 0; + } + + let delta = end.wrapping_sub(start); + match &self.inner { + ClockType::Counter(_, _, calibration) => { + mul_div_po2_u64(delta, calibration.scale_factor, calibration.scale_shift) + } + _ => delta, + } + } + + /// Calculates the delta between two raw measurements. + /// + /// This method is slightly faster when you know you need the delta between two raw + /// measurements, or a start/end measurement, than using [`scaled`] for both conversions. + /// + /// In code that simply needs access to the whole number of nanoseconds + /// between the two measurements, consider [`Clock::delta_as_nanos`] + /// instead, which is slightly faster than having to call both this method + /// and [`Duration::as_nanos`]. + /// + /// [`scaled`]: Clock::scaled + /// [`delta_as_nanos`]: Clock::delta_as_nanos + pub fn delta(&self, start: u64, end: u64) -> Duration { + Duration::from_nanos(self.delta_as_nanos(start, end)) + } + + /// Gets the most recent current time, scaled to reference time. + /// + /// This method provides ultra-low-overhead access to a slightly-delayed version of the current + /// time. Instead of querying the underlying source clock directly, a shared, global value is + /// read directly without the need to scale to reference time. + /// + /// The upkeep thread must be started in order to update the time. You can read the + /// documentation for [`Upkeep`][upkeep] for more information on starting the upkeep thread, as + /// well as the details of the "current time" mechanism. + /// + /// If the upkeep thread has not been started, the return value will be `0`. + /// + /// Returns an [`Instant`]. + /// + /// [upkeep]: crate::Upkeep + pub fn recent(&self) -> Instant { + match &self.inner { + ClockType::Mock(mock) => Instant(mock.value()), + _ => Instant(GLOBAL_RECENT.load()), + } + } + + #[cfg(test)] + fn reset_timebase(&mut self) -> bool { + match &mut self.inner { + ClockType::Counter(reference, source, calibration) => { + calibration.reset_timebases(*reference, source); + true + } + _ => false, + } + } +} + +impl Default for Clock { + fn default() -> Clock { + Clock::new() + } +} + +// A manual `Clone` impl is required because `atomic_shim`'s `AtomicU64` is not `Clone`. +impl Clone for ClockType { + fn clone(&self) -> Self { + match self { + ClockType::Mock(mock) => ClockType::Mock(mock.clone()), + ClockType::Monotonic(monotonic) => ClockType::Monotonic(*monotonic), + ClockType::Counter(monotonic, counter, calibration) => { + ClockType::Counter(*monotonic, counter.clone(), *calibration) + } + } + } +} + +/// Sets this clock as the default for the duration of a closure. +/// +/// This will only affect calls made against [`Instant`]. [`Clock`] is always self-contained. +pub fn with_clock(clock: &Clock, f: impl FnOnce() -> T) -> T { + CLOCK_OVERRIDE.with(|current| { + let old = current.replace(Some(clock.clone())); + let result = f(); + current.replace(old); + result + }) +} + +/// Sets the global recent time. +/// +/// While callers should typically prefer to use [`Upkeep`] to establish a background thread in +/// order to drive the global recent time, this function allows callers to customize how the global +/// recent time is updated. For example, programs using an asynchronous runtime may prefer to +/// schedule a task that does the updating, avoiding an extra thread. +pub fn set_recent(instant: Instant) { + GLOBAL_RECENT.store(instant.0); +} + +#[inline] +pub(crate) fn get_now() -> Instant { + if let Some(instant) = CLOCK_OVERRIDE.with(|clock| clock.borrow().as_ref().map(Clock::now)) { + instant + } else { + GLOBAL_CLOCK.get_or_init(Clock::new).now() + } +} + +#[inline] +pub(crate) fn get_recent() -> Instant { + // We make a small trade-off here where if the global recent time isn't zero, we use that, + // regardless of whether or not there's a thread-specific clock override. Otherwise, we would + // blow our performance budget. + // + // Given that global recent time shouldn't ever be getting _actually_ updated in tests, this + // should be a reasonable trade-off. + let recent = GLOBAL_RECENT.load(); + if recent == 0 { + get_now() + } else { + Instant(recent) + } +} + +#[inline] +fn mul_div_po2_u64(value: u64, numer: u64, denom: u32) -> u64 { + // Modified muldiv routine where the denominator has to be a power of two. `denom` is expected + // to be the number of bits to shift, not the actual decimal value. + let mut v = u128::from(value); + v *= u128::from(numer); + v >>= denom; + v as u64 +} + +#[allow(dead_code)] +#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +fn has_tsc_support() -> bool { + let cpuid = raw_cpuid::CpuId::new(); + let has_invariant_tsc = cpuid + .get_advanced_power_mgmt_info() + .map_or(false, |apm| apm.has_invariant_tsc()); + let has_rdtscp = cpuid + .get_extended_processor_and_feature_identifiers() + .map_or(false, |epf| epf.has_rdtscp()); + + has_invariant_tsc && has_rdtscp +} + +#[allow(dead_code)] +#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))] +fn has_tsc_support() -> bool { + false +} + +#[cfg(test)] +pub mod tests { + use super::{Clock, Counter, Monotonic}; + use average::{Merge, Variance}; + use std::time::{Duration, Instant}; + + #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] + mod configure_wasm_tests { + // Until https://github.com/rustwasm/wasm-bindgen/issues/2571 is resolved, these tests will only run in browsers. + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + } + + #[test] + #[cfg_attr( + all(target_arch = "wasm32", target_os = "unknown"), + wasm_bindgen_test::wasm_bindgen_test + )] + fn test_mock() { + let (clock, mock) = Clock::mock(); + assert_eq!(clock.now().0, 0); + mock.increment(42); + assert_eq!(clock.now().0, 42); + } + + #[test] + #[cfg_attr( + all(target_arch = "wasm32", target_os = "unknown"), + wasm_bindgen_test::wasm_bindgen_test + )] + fn test_now() { + let clock = Clock::new(); + assert!(clock.now().0 > 0); + } + + #[test] + #[cfg_attr( + all(target_arch = "wasm32", target_os = "unknown"), + wasm_bindgen_test::wasm_bindgen_test + )] + fn test_raw() { + let clock = Clock::new(); + assert!(clock.raw() > 0); + } + + #[test] + #[cfg_attr( + all(target_arch = "wasm32", target_os = "unknown"), + wasm_bindgen_test::wasm_bindgen_test + )] + fn test_scaled() { + let clock = Clock::new(); + let raw = clock.raw(); + let scaled = clock.scaled(raw); + assert!(scaled.0 > 0); + } + + #[test] + #[cfg_attr(not(feature = "flaky_tests"), ignore)] + #[cfg_attr( + all(target_arch = "wasm32", target_os = "unknown"), + wasm_bindgen_test::wasm_bindgen_test + )] + + fn test_reference_source_calibration() { + let mut clock = Clock::new(); + let reference = Monotonic::default(); + + let loops = 10000; + + let mut overall = Variance::new(); + let mut src_samples = [0u64; 1024]; + let mut ref_samples = [0u64; 1024]; + + for _ in 0..loops { + // We have to reset the "timebase" of the clock/calibration when testing in this way. + // + // Since `quanta` is designed around mimicing `Instant`, we care about measuring the _passage_ of time, but + // not matching our calculation of wall-clock time to the system's calculation of wall-clock time, in terms + // of their absolute values. + // + // As the system adjusts its clocks over time, whether due to NTP skew, or delays in updating the derived monotonic + // time, and so on, our original measurement base from the reference source -- which we use to anchor how we + // convert our scaled source measurement into the same reference timebase -- can skew further away from the + // current reference time in terms of the rate at which it ticks forward. + // + // Essentially, what we're saying here is that we want to test the scaling ratio that we generated in + // calibration, but not necessarily that the resulting value -- which is meant to be in the same timebase as + // the reference -- is locked to the reference itself. For example, if the reference is in nanoseconds, we + // want our source to be scaled to nanoseconds, too. We don't care if the system shoves the reference back + // and forth via NTP skew, etc... we just need to do enough source-to-reference calibration loops to figure + // out what the right amount is to scale the TSC -- since we require an invariant/nonstop TSC -- to get it + // to nanoseconds. + // + // At the risk of saying _too much_, while the delta between `Clock::now` and `Monotonic::now` may grow over + // time if the timebases are not reset, we can readily observe in this test that the delta between the + // first/last measurement loop for both source/reference are independently close i.e. the ratio by which we + // scale the source measurements gets it close, and stays close, to the reference measurements in terms of + // the _passage_ of time. + clock.reset_timebase(); + + for i in 0..1024 { + src_samples[i] = clock.now().0; + ref_samples[i] = reference.now(); + } + + let is_src_monotonic = src_samples + .iter() + .map(Some) + .reduce(|last, current| last.and_then(|lv| current.filter(|cv| *cv >= lv))) + .flatten() + .copied(); + assert_eq!(is_src_monotonic, Some(src_samples[1023])); + + let is_ref_monotonic = ref_samples + .iter() + .map(Some) + .reduce(|last, current| last.and_then(|lv| current.filter(|cv| *cv >= lv))) + .flatten() + .copied(); + assert_eq!(is_ref_monotonic, Some(ref_samples[1023])); + + let local = src_samples + .iter() + .zip(ref_samples.iter()) + .map(|(s, r)| *s as f64 - *r as f64) + .map(|f| f.abs()) + .collect::(); + + overall.merge(&local); + } + + println!( + "reference/source delta: mean={} error={} mean-var={} samples={}", + overall.mean(), + overall.error(), + overall.variance_of_mean(), + overall.len(), + ); + + // If things are out of sync more than 1000ns, something is likely scaled wrong. + assert!(overall.mean() < 1000.0); + } + + #[test] + #[cfg_attr(not(feature = "flaky_tests"), ignore)] + #[cfg_attr( + all(target_arch = "wasm32", target_os = "unknown"), + wasm_bindgen_test::wasm_bindgen_test + )] + fn measure_source_reference_self_timing() { + let source = Counter::default(); + let reference = Monotonic::default(); + + let loops = 10000; + + let mut src_deltas = Vec::new(); + let mut src_samples = [0u64; 100]; + + for _ in 0..loops { + let start = Instant::now(); + for i in 0..100 { + src_samples[i] = source.now(); + } + + src_deltas.push(start.elapsed().as_secs_f64()); + } + + let mut ref_deltas = Vec::new(); + let mut ref_samples = [0u64; 100]; + + for _ in 0..loops { + let start = Instant::now(); + for i in 0..100 { + ref_samples[i] = reference.now(); + } + + ref_deltas.push(start.elapsed().as_secs_f64()); + } + + let src_variance = src_deltas.into_iter().collect::(); + let ref_variance = ref_deltas.into_iter().collect::(); + + let src_variance_ns = Duration::from_secs_f64(src_variance.mean() / 100.0); + let ref_variance_ns = Duration::from_secs_f64(ref_variance.mean() / 100.0); + + println!( + "source call average: {:?}, reference call average: {:?}", + src_variance_ns, ref_variance_ns + ); + } +} diff --git a/vendor/quanta-0.11.1/src/mock.rs b/vendor/quanta-0.11.1/src/mock.rs new file mode 100644 index 0000000000000..e889c8b9738bf --- /dev/null +++ b/vendor/quanta-0.11.1/src/mock.rs @@ -0,0 +1,66 @@ +use crossbeam_utils::atomic::AtomicCell; +use std::{sync::Arc, time::Duration}; + +/// Type which can be converted into a nanosecond representation. +/// +/// This allows users of [`Mock`] to increment/decrement the time both with raw +/// integer values and the more convenient [`Duration`] type. +pub trait IntoNanoseconds { + /// Consumes this value, converting it to a nanosecond representation. + fn into_nanos(self) -> u64; +} + +impl IntoNanoseconds for u64 { + fn into_nanos(self) -> u64 { + self + } +} + +impl IntoNanoseconds for Duration { + fn into_nanos(self) -> u64 { + self.as_nanos() as u64 + } +} + +/// Controllable time source for use in tests. +/// +/// A mocked clock allows the caller to adjust the given time backwards and forwards by whatever +/// amount they choose. While [`Clock`](crate::Clock) promises monotonic values for normal readings, +/// when running in mocked mode, these guarantees do not apply: the given `Clock`/`Mock` pair are +/// directly coupled. +/// +/// This can be useful for not only testing code that depends on the passage of time, but also for +/// testing that code can handle large shifts in time. +#[derive(Debug, Clone)] +pub struct Mock { + offset: Arc>, +} + +impl Mock { + pub(crate) fn new() -> Self { + Self { + offset: Arc::new(AtomicCell::new(0)), + } + } + + /// Increments the time by the given amount. + pub fn increment(&self, amount: N) { + let amount = amount.into_nanos(); + self.offset + .fetch_update(|current| Some(current + amount)) + .expect("should never return an error"); + } + + /// Decrements the time by the given amount. + pub fn decrement(&self, amount: N) { + let amount = amount.into_nanos(); + self.offset + .fetch_update(|current| Some(current - amount)) + .expect("should never return an error"); + } + + /// Gets the current value of this `Mock`. + pub fn value(&self) -> u64 { + self.offset.load() + } +} diff --git a/vendor/quanta-0.11.1/src/stats.rs b/vendor/quanta-0.11.1/src/stats.rs new file mode 100644 index 0000000000000..7e4a2e837d1ac --- /dev/null +++ b/vendor/quanta-0.11.1/src/stats.rs @@ -0,0 +1,78 @@ +/// Estimates the arithmetic mean (and the error) for a set of samples. +/// +/// This type is written and maintained internally as it is trivial to implement and doesn't warrant +/// a separate dependency. As well, we add some features like exposing the sample count, +/// calculating the mean + error value, etc, that existing crates don't do. +/// +/// Based on [Welford's algorithm][welfords] which computes the mean incrementally, with constant +/// time and space complexity. +/// +/// [welfords]: https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford%27s_online_algorithm +#[derive(Default)] +pub(crate) struct Variance { + mean: f64, + mean2: f64, + n: u64, +} + +impl Variance { + #[inline] + pub fn add(&mut self, sample: f64) { + self.n += 1; + let n_f = self.n as f64; + let delta_sq = (sample - self.mean).powi(2); + self.mean2 += ((n_f - 1.0) * delta_sq) / n_f; + self.mean += (sample - self.mean) / n_f; + } + + #[inline] + pub fn mean(&self) -> f64 { + self.mean + } + + #[inline] + pub fn mean_error(&self) -> f64 { + if self.n < 2 { + return 0.0; + } + + let n_f = self.n as f64; + let sd = (self.mean2 / (n_f - 1.0)).sqrt(); + sd / n_f.sqrt() + } + + #[inline] + pub fn mean_with_error(&self) -> f64 { + let mean = self.mean.abs(); + mean + self.mean_error().abs() + } + + #[inline] + pub fn has_significant_result(&self) -> bool { + self.n >= 2 + } + + #[inline] + pub fn samples(&self) -> u64 { + self.n + } +} + +#[cfg(test)] +mod tests { + use super::Variance; + + #[test] + fn basic() { + let inputs = &[5.0, 10.0, 12.0, 15.0, 20.0]; + let mut variance = Variance::default(); + for input in inputs { + variance.add(*input); + } + + assert_eq!(variance.mean(), 12.4); + + let expected_mean_error = 2.5019; + assert!((variance.mean_error() - expected_mean_error).abs() < 0.001); + } +} diff --git a/vendor/quanta-0.11.1/src/upkeep.rs b/vendor/quanta-0.11.1/src/upkeep.rs new file mode 100644 index 0000000000000..329417d6dbb42 --- /dev/null +++ b/vendor/quanta-0.11.1/src/upkeep.rs @@ -0,0 +1,183 @@ +use crate::{set_recent, Clock}; +use std::{ + fmt, io, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, + thread::{self, JoinHandle}, + time::Duration, +}; + +static GLOBAL_UPKEEP_RUNNING: AtomicBool = AtomicBool::new(false); + +/// Ultra-low-overhead access to slightly-delayed time. +/// +/// In some applications, there can be a need to check the current time very often, so much so that +/// the overhead of checking the time can begin to eat up measurable overhead. For some of these +/// cases, the time may need to be accessed often but does not necessarily need to be incredibly +/// accurate: one millisecond granularity could be entirely acceptable. +/// +/// For these cases, we provide a slightly-delayed version of the time to callers via +/// [`Clock::recent`], which is updated by a background upkeep thread. That thread is configured +/// and spanwed via [`Upkeep`]. +/// +/// [`Upkeep`] can construct a new clock (or be passed an existing clock to use), and given an +/// update interval, and it will faithfully attempt to update the global recent time on the +/// specified interval. There is a trade-off to be struck in terms of how often the time is +/// updated versus the required accuracy. Checking the time and updating the global reference is +/// itself not zero-cost, and so care must be taken to analyze the number of readers in order to +/// ensure that, given a particular update interval, the upkeep thread is saving more CPU time than +/// would be spent otherwise by directly querying the current time. +/// +/// The recent time is read and written atomically. It is global to an application, so if another +/// codepath creates the upkeep thread, the interval chosen by that instantiation will be the one +/// that all callers of [`Clock::recent`] end up using. +/// +/// Multiple upkeep threads cannot exist at the same time. A new upkeep thread can be started if +/// the old one is dropped and returns. +/// +/// In terms of performance, reading the recent time can be up to two to three times as fast as +/// reading the current time in the optimized case of using the Time Stamp Counter source. In +/// practice, while a caller might expect to take 12-14ns to read the TSC and scale it to reference +/// time, the recent time can be read in 4-5ns, with no reference scale conversion required. +#[derive(Debug)] +pub struct Upkeep { + interval: Duration, + clock: Clock, +} + +/// Handle to a running upkeep thread. +/// +/// If a handle is dropped, the upkeep thread will be stopped, and the recent time will cease to +/// update. The upkeep thread can be started again to resume updating the recent time. +#[derive(Debug)] +pub struct Handle { + done: Arc, + handle: Option>, +} + +/// Errors thrown during the creation/spawning of the upkeep thread. +#[derive(Debug)] +pub enum Error { + /// An upkeep thread is already running in this process. + UpkeepRunning, + /// An error occurred when trying to spawn the upkeep thread. + FailedToSpawnUpkeepThread(io::Error), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::UpkeepRunning => write!(f, "upkeep thread already running"), + Error::FailedToSpawnUpkeepThread(e) => { + write!(f, "failed to spawn upkeep thread: {}", e) + } + } + } +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::UpkeepRunning => None, + Self::FailedToSpawnUpkeepThread(e) => Some(e), + } + } +} + +impl Upkeep { + /// Creates a new [`Upkeep`]. + /// + /// This creates a new internal clock for acquiring the current time. If you have an existing + /// [`Clock`] that is already calibrated, it is slightly faster to clone it and construct the + /// builder with [`new_with_clock`](Upkeep::new_with_clock) to avoid recalibrating. + pub fn new(interval: Duration) -> Upkeep { + Self::new_with_clock(interval, Clock::new()) + } + + /// Creates a new [`Upkeep`] with the specified [`Clock`] instance. + pub fn new_with_clock(interval: Duration, clock: Clock) -> Upkeep { + Upkeep { interval, clock } + } + + /// Start the upkeep thread, periodically updating the global coarse time. + /// + /// [`Handle`] represents a drop guard for the upkeep thread if it is successfully spawned. + /// Dropping the handle will also instruct the upkeep thread to stop and exist, so the handle + /// must be held while the upkeep thread should continue to run. + /// + /// # Errors + /// + /// If either an existing upkeep thread is running, or there was an issue when attempting to + /// spawn the upkeep thread, an error variant will be returned describing the error. + pub fn start(self) -> Result { + // If another upkeep thread is running, inform the caller. + let _ = GLOBAL_UPKEEP_RUNNING + .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) + .map_err(|_| Error::UpkeepRunning)?; + + let interval = self.interval; + let clock = self.clock; + + let done = Arc::new(AtomicBool::new(false)); + let their_done = done.clone(); + + let result = thread::Builder::new() + .name("quanta-upkeep".to_string()) + .spawn(move || { + while !their_done.load(Ordering::Acquire) { + set_recent(clock.now()); + + thread::sleep(interval); + } + + GLOBAL_UPKEEP_RUNNING.store(false, Ordering::SeqCst); + }) + .map_err(Error::FailedToSpawnUpkeepThread); + + // Let another caller attempt to spawn the upkeep thread if we failed to do so. + if result.is_err() { + GLOBAL_UPKEEP_RUNNING.store(false, Ordering::SeqCst); + } + + let handle = result?; + + Ok(Handle { + done, + handle: Some(handle), + }) + } +} + +impl Drop for Handle { + fn drop(&mut self) { + self.done.store(true, Ordering::Release); + + if let Some(handle) = self.handle.take() { + let _result = handle + .join() + .map_err(|_| io::Error::new(io::ErrorKind::Other, "failed to stop upkeep thread")); + } + } +} + +#[cfg(test)] +mod tests { + use super::Upkeep; + use std::time::Duration; + + #[test] + #[cfg_attr(target_arch = "wasm32", ignore)] // WASM is single threaded + fn test_spawning_second_upkeep() { + let first = Upkeep::new(Duration::from_millis(250)).start(); + let second = Upkeep::new(Duration::from_millis(250)) + .start() + .map_err(|e| e.to_string()); + + assert!(first.is_ok()); + + let second_err = second.expect_err("second upkeep should be error, got handle"); + assert_eq!(second_err, "upkeep thread already running"); + } +} diff --git a/vendor/ratatui/src/layout/corner.rs b/vendor/ratatui/src/layout/corner.rs new file mode 100644 index 0000000000000..4da845659e188 --- /dev/null +++ b/vendor/ratatui/src/layout/corner.rs @@ -0,0 +1,33 @@ +use strum::{Display, EnumString}; + +#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)] +pub enum Corner { + #[default] + TopLeft, + TopRight, + BottomRight, + BottomLeft, +} +#[cfg(test)] +mod tests { + use strum::ParseError; + + use super::*; + + #[test] + fn corner_to_string() { + assert_eq!(Corner::BottomLeft.to_string(), "BottomLeft"); + assert_eq!(Corner::BottomRight.to_string(), "BottomRight"); + assert_eq!(Corner::TopLeft.to_string(), "TopLeft"); + assert_eq!(Corner::TopRight.to_string(), "TopRight"); + } + + #[test] + fn corner_from_str() { + assert_eq!("BottomLeft".parse::(), Ok(Corner::BottomLeft)); + assert_eq!("BottomRight".parse::(), Ok(Corner::BottomRight)); + assert_eq!("TopLeft".parse::(), Ok(Corner::TopLeft)); + assert_eq!("TopRight".parse::(), Ok(Corner::TopRight)); + assert_eq!("".parse::(), Err(ParseError::VariantNotFound)); + } +} diff --git a/vendor/ratatui/tests/border_macro.rs b/vendor/ratatui/tests/border_macro.rs new file mode 100644 index 0000000000000..fc8cc8cd26317 --- /dev/null +++ b/vendor/ratatui/tests/border_macro.rs @@ -0,0 +1,19 @@ +#![cfg(feature = "macros")] +use ratatui::{border, widgets::Borders}; + +#[test] +fn border_empty_test() { + let empty = Borders::NONE; + assert_eq!(empty, border!()); +} +#[test] +fn border_all_test() { + let all = Borders::ALL; + assert_eq!(all, border!(ALL)); + assert_eq!(all, border!(TOP, BOTTOM, LEFT, RIGHT)); +} +#[test] +fn border_left_right_test() { + let left_right = Borders::from_bits(Borders::LEFT.bits() | Borders::RIGHT.bits()); + assert_eq!(left_right, Some(border!(RIGHT, LEFT))); +} diff --git a/vendor/raw-cpuid-10.7.0/.cargo-checksum.json b/vendor/raw-cpuid-10.7.0/.cargo-checksum.json new file mode 100644 index 0000000000000..1064d0099b009 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"AUTHORS":"62fb7a7ae72a917b7e6bc2bbdb3a20987f1a52aa2d5ae10bb1033e3d7d071e38","CHANGELOG.md":"881ef57251da01b4d561baf4271c466031583515d3084c8f291264f64dcf21c4","Cargo.lock":"4b8e3e2bd846a2a4d84f725b52b213c70ff6a0b7afde81f49efb6b481cddba13","Cargo.toml":"3521d4f83691dca9fbce7e2c2879fda91696dd539b01d25386460340ed1a97cc","LICENSE.md":"cdd45f4d0c552c3a51725728215919e0dedb1e1af250f130e7c2d60eef6721fe","README.md":"123e65ef057a8e584e01d837b5895c74c804655d8372629aaf9b1a19061fd950","examples/cache.rs":"145dbbb2ec70a14c8b6ecb495f24f6000332e5ffaea94ea179d864818315b428","examples/cpu.rs":"c8f7831bd4fe2cb413f986d8793f3084e3f2705876cfebc42d7ef6403d3826c7","examples/topology.rs":"07783f45b10965b9d8ee5fc11c3d43ebe5efac0fc0a68ad7bdeb75300d29fcc9","examples/tsc_frequency.rs":"6f01eb91ed5d469b023a612060d9979c828ad9da8d2800f6a3145d1247174ae1","src/bin/cpuid.rs":"068ac318124ffcd5241ef720a8d103b0d979d817844274c56168448538860986","src/display.rs":"7d0edfc946225fb5b0065e7bf740a9c5f31b636f8ae5516350a20b3230f8e830","src/extended.rs":"07cdc6198fb39f2e9c90f7a83ce7e42f999119d771f0f86cf3e4022b4350cc5f","src/lib.rs":"caa5828c2cf3e559d17e2e5e869b76d24b8c628dca526de982a22bb2c5a7ee12","src/tests/i5_3337u.rs":"31b7c426a8e1e2f17347a6254cfe9b849cd35fd63535d565cd7596b10480f4bb","src/tests/i7_12700k.rs":"d5dd2c0596d0a5e0a206001071917221073364587fd90b1896b4b01340c2d083","src/tests/mod.rs":"6642860f87f8767b8a48234cd9eb3ed3cba69c721544b4a512486a22bac406d7","src/tests/ryzen_matisse.rs":"a81d70d5b9c6eedfcf41dc9d06b86cf02f5fc106e3afa6d41ac18ec26b3550a8","src/tests/xeon_gold_6252.rs":"721fe1fdc5cb21e30913f552619341dd6d0b29f9359992acbf8339c1d70aab88"},"package":"6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"} \ No newline at end of file diff --git a/vendor/raw-cpuid-10.7.0/AUTHORS b/vendor/raw-cpuid-10.7.0/AUTHORS new file mode 100644 index 0000000000000..bd037c3eac4ed --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/AUTHORS @@ -0,0 +1,24 @@ +Gerd Zellweger +Bence Meszaros +Rafal Mielniczuk +Stefan Lankes +Mingshen Sun +Niklas Fiekas +Philipp Schuster +Gabriel Majeri +Bruce Mitchener +John Ericson +Paul Sbarra +Pireax +Tyler Hall +Alex McKenna +Benoît du Garreau +Colin Finck +Gabriel +John Bartholomew +Nathaniel McCallum +Olivier Lemasle +IsaacDynamo <61521674+IsaacDynamo@users.noreply.github.com> +Zavier Divelbiss +Umio Yasuno <53935716+Umio-Yasuno@users.noreply.github.com> +Matt Keeter \ No newline at end of file diff --git a/vendor/raw-cpuid-10.7.0/CHANGELOG.md b/vendor/raw-cpuid-10.7.0/CHANGELOG.md new file mode 100644 index 0000000000000..19101f57bb61c --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/CHANGELOG.md @@ -0,0 +1,170 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [10.7.0] - 2023-02-27 + +- Include the pretty printing code in the library (instead of only having it in + the binary) ([#137](https://github.com/gz/rust-cpuid/pull/137)) This + introduces a new (optional) `display` feature. `display` will also enable + `std` so it can't be used in `no_std` environments. + +## [10.6.1] - 2023-02-03 + +- Fix potential overflow during formatting when using the in cpuid binary to display cache information. ([#133](https://github.com/gz/rust-cpuid/issues/133)) + +## [10.6.0] - 2022-09-12 + +- Updated termimad to 0.20 (only affects `cpuid` binary version) +- Add support for AMD leaf `0x8000_001E` +- Add support for AMD leaf `0x8000_0019` +- Updated `ExtendedFeatures` to include new features + +## [10.5.0] - 2022-08-17 + +- Updated phf to 0.11 (only affects `cfg(test)`) +- Add support for AMD leaf `0x8000_001D` +- Add support for AMD leaf `0x8000_001A` + +## [10.4.0] - 2022-08-01 + +- Added support for cpuid leaf 0x1f (Extended Topology Information v2) +- Improved debug formatting for `ProcessorCapacityAndFeatureInfo` + +## [10.3.0] - 2022-03-15 + +### Added + +- Added ExtendedFeatures::has_avx512vnni(). +- Allow to build/use the crate even if `native_cpuid` is not available on the target (one can still instantiate CpuId using `with_cpuid_fn` in this case). + +## Changed + +- Updated clap dependency. + +## [10.2.0] - 2021-07-30 + +### Added + +- Fix Cache and TLB (leaf 0x02) formatting in cpuid binary. + +## Changed + +- Added JSON and raw formatting to cpuid binary. + +## [10.1.0] - 2021-07-30 + +### Added + +- AMD SVM feature leaf (0x8000_000A) +- Added methods to display upper 64-96 bits of processor serial number (`serial_all`, `serial_upper`) +- Implement `Display` for `CacheType` +- Implement `Display` for `TopologyType` +- Implement `Display` for `DatType` +- Implement `Display` for `Associativity` +- Added `location()` method for `ExtendedState` as an alternative for + `is_in_ia32_xss` and `is_in_xcr0`. +- Added new `register()` method for `ExtendedState` to identify which register + this instance refers to. + +## Changed + +- Better formatting for cpuid binary. + +## [10.0.0] - 2021-07-14 + +### Breaking changes for v10 + +- Removed `get_extended_function_info` / `ExtendedFunctionInfo` due to added AMD support: Use + `get_processor_brand_string`, + `get_extended_processor_and_feature_identifiers`, `get_l1_cache_and_tlb_info`, + `get_l2_l3_cache_and_tlb_info`, `get_advanced_power_mgmt_info`, + `get_processor_capacity_feature_info` instead: + + Migration guide for replacing `get_extended_function_info` / `ExtendedFunctionInfo`: + + | <= v9 | >= v10 | + | -------------------------- | ------------------------------------------------------------------------------ | + | `processor_brand_string()` | `CpuId.get_processor_brand_string` | + | `cache_line_size()` | `Cpuid.get_l2_l3_cache_and_tlb_info().l2cache_line_size()` | + | `l2_associativity()` | `Cpuid.get_l2_l3_cache_and_tlb_info().l2cache_associativity()` | + | `cache_size()` | `Cpuid.get_l2_l3_cache_and_tlb_info().l2cache_size()` | + | `physical_address_bits()` | `CpuId.get_processor_capacity_feature_info().physical_address_bits()` | + | `linear_address_bits()` | `CpuId.get_processor_capacity_feature_info().linear_address_bits()` | + | `has_invariant_tsc()` | `CpuId.get_advanced_power_mgmt_info.has_invariant_tsc()` | + | `has_lahf_sahf()` | `CpuId.get_extended_processor_and_feature_identifiers().has_lahf_sahf()` | + | `has_lzcnt()` | `CpuId.get_extended_processor_and_feature_identifiers().has_lzcnt()` | + | `has_prefetchw()` | `CpuId.get_extended_processor_and_feature_identifiers().has_prefetchw()` | + | `has_syscall_sysret()` | `CpuId.get_extended_processor_and_feature_identifiers().has_syscall_sysret()` | + | `has_execute_disable()` | `CpuId.get_extended_processor_and_feature_identifiers().has_execute_disable()` | + | `has_1gib_pages()` | `CpuId.get_extended_processor_and_feature_identifiers().has_1gib_pages()` | + | `has_rdtscp()` | `CpuId.get_extended_processor_and_feature_identifiers().has_rdtscp()` | + | `has_64bit_mode()` | `CpuId.get_extended_processor_and_feature_identifiers().has_64bit_mode()` | + +- Removed `CpuId.deterministic_address_translation_info`. Use + `CpuId.get_deterministic_address_translation_info` instead. +- Renamed `model_id` and `family_id` to `base_model_id` and `base_family_id` in + `FeatureInfo`. Added new `family_id` and `model_id` functions that compute the actual + model and family according to the spec by joining base and extended family/model. +- Extend Hypervisor enum with more variants + ([#50](https://github.com/gz/rust-cpuid/pull/50)) +- Remove `has_rdseet` function (deprecated since 3.2), clients should use the correctly + named `has_rdseed` function instead. + + Migration guide for `cpuid.get_feature_info()`: + + | <= v9 | >= v10 | + | ----------- | ----------- | + | `has_rdseet()` | `has_rdseed()` | + +- Removed `Default` traits for most structs. `default()` should not be used anymore. + +### Changes + +- Updated Debug trait for SGX iterators. +- Make CpuId derive Clone and Copy ([#53](https://github.com/gz/rust-cpuid/pull/53)) +- Improved documentation in some places by adding leaf numbers. +- Updated AMD leaf 0x8000_001f (Encrypted Memory) to latest manual. +- `ProcessorBrandString.as_str()` now trims the returned string. +- Fix `RdtAllocationInfo.memory_bandwidth_allocation()` which was using l2cat + availability to determine if it exists. + +### Added + +- Added AMD support for leaf 0x8000_0001 +- Added AMD support for leaf 0x8000_0005 +- Added AMD support for leaf 0x8000_0006 +- Added AMD support for leaf 0x8000_0007 +- Added AMD support for leaf 0x8000_0008 + +### Deprecated + +- `VendorInfo.as_string()` is deprecated in favor of `VendorInfo.as_str()` +- `SoCVendorBrand.as_string()` is deprecated in favor of `SoCVendorBrand.as_str()` + +## [9.1.1] - 2021-07-06 + +### Changed + +- Use more idiomatic rust code in readme/doc.rs example. +- Use `str::from_utf8` instead of `str::from_utf8_unchecked` to avoid potential + panics with the Deserialize trait ([#43](https://github.com/gz/rust-cpuid/issues/43)). +- More extensive Debug trait implementation ([#49](https://github.com/gz/rust-cpuid/pull/49)) +- Fix 2 clippy warnings + +## [9.1.0] - 2021-07-03 + +### Added + +- A `CpuId::with_cpuid_fn` that allows to override the default cpuid function. + +### Changed + +- Fixed `RdtAllocationInfo.has_memory_bandwidth_allocation`: was using the wrong bit +- Fixed `capacity_mask_length` in `L3CatInfo` and `L2CatInfo`: add +1 to returned value +- Fixed `MemBwAllocationInfo.max_hba_throttling`: add +1 to returned value +- Refactored tests into a module. +- Started to add tests for Ryzen/AMD. diff --git a/vendor/raw-cpuid-10.7.0/Cargo.lock b/vendor/raw-cpuid-10.7.0/Cargo.lock new file mode 100644 index 0000000000000..7c3ed52d36821 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/Cargo.lock @@ -0,0 +1,774 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "3.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da95d038ede1a964ce99f49cbe27a7fb538d1da595e4b4f70b8c8f338d17bf16" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "coolor" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4d7a805ca0d92f8c61a31c809d4323fdaa939b0b440e544d21db7797c5aaad" +dependencies = [ + "crossterm", +] + +[[package]] +name = "core_affinity" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8a03115cc34fb0d7c321dd154a3914b3ca082ccc5c11d91bf7117dbbe7171f" +dependencies = [ + "kernel32-sys", + "libc", + "num_cpus", + "winapi 0.2.8", +] + +[[package]] +name = "crossbeam" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "crossterm" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17" +dependencies = [ + "bitflags", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi 0.3.9", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimad" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd37b2e65fbd459544194d8f52ed84027e031684335a062c708774c09d172b0b" +dependencies = [ + "once_cell", +] + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "phf" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4724fa946c8d1e7cd881bd3dbee63ce32fc1e9e191e35786b3dc1320a3f68131" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b450720b6f75cfbfabc195814bd3765f337a4f9a83186f8537297cac12f6705" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd94351ac44e70e56b59883e15029a5135f902a8a3020f9c18d580a420e526aa" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd5609d4b2df87167f908a32e1b146ce309c16cf35df76bc11f440b756048e4" +dependencies = [ + "siphasher", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "raw-cpuid" +version = "10.7.0" +dependencies = [ + "bitflags", + "clap", + "core_affinity", + "libc", + "phf", + "rustversion", + "serde", + "serde_derive", + "serde_json", + "termimad", +] + +[[package]] +name = "redox_syscall" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustversion" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" + +[[package]] +name = "serde_derive" +version = "1.0.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "signal-hook" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "siphasher" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "729a25c17d72b06c68cb47955d44fda88ad2d3e7d77e025663fdd69b93dd71a1" + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "termimad" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8a16d7de8d4c97a4149cc3b9d3681c5dba36011c303745bb1af19636e89ba39" +dependencies = [ + "coolor", + "crossbeam", + "crossterm", + "minimad", + "thiserror", + "unicode-width", +] + +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + +[[package]] +name = "thiserror" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/vendor/raw-cpuid-10.7.0/Cargo.toml b/vendor/raw-cpuid-10.7.0/Cargo.toml new file mode 100644 index 0000000000000..85411a93476b9 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/Cargo.toml @@ -0,0 +1,90 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "raw-cpuid" +version = "10.7.0" +authors = ["Gerd Zellweger "] +description = "A library to parse the x86 CPUID instruction, written in rust with no external dependencies. The implementation closely resembles the Intel CPUID manual description. The library does only depend on libcore." +homepage = "https://github.com/gz/rust-cpuid" +documentation = "https://docs.rs/raw-cpuid/" +readme = "README.md" +keywords = [ + "cpuid", + "x86", + "amd64", + "os", + "libcore", +] +license = "MIT" +repository = "https://github.com/gz/rust-cpuid" + +[[bin]] +name = "cpuid" +path = "src/bin/cpuid.rs" +required-features = ["cli"] + +[dependencies.bitflags] +version = "1.2" + +[dependencies.clap] +version = "3.1.6" +features = ["derive"] +optional = true + +[dependencies.serde] +version = "1.0" +optional = true +default-features = false + +[dependencies.serde_derive] +version = "1.0" +optional = true + +[dependencies.serde_json] +version = "1.0" +optional = true + +[dependencies.termimad] +version = "0.20" +optional = true + +[features] +cli = [ + "display", + "clap", +] +display = [ + "std", + "termimad", + "serde_json", + "serialize", +] +serialize = [ + "serde", + "serde_derive", +] +std = [] + +[target."cfg(unix)".dev-dependencies.core_affinity] +version = "0.5.10" + +[target."cfg(unix)".dev-dependencies.libc] +version = "0.2" +default-features = false + +[target."cfg(unix)".dev-dependencies.phf] +version = "0.11" +features = ["macros"] + +[target."cfg(unix)".dev-dependencies.rustversion] +version = "1.0" diff --git a/vendor/raw-cpuid-10.7.0/LICENSE.md b/vendor/raw-cpuid-10.7.0/LICENSE.md new file mode 100644 index 0000000000000..e734b146b0e85 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Gerd Zellweger + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/vendor/raw-cpuid-10.7.0/README.md b/vendor/raw-cpuid-10.7.0/README.md new file mode 100644 index 0000000000000..ac2f6b5aae387 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/README.md @@ -0,0 +1,53 @@ +# cpuid [![Crates.io](https://img.shields.io/crates/v/raw_cpuid.svg)](https://crates.io/crates/raw-cpuid) [![Standard checks](https://github.com/gz/rust-cpuid/actions/workflows/standard.yml/badge.svg)](https://github.com/gz/rust-cpuid/actions/workflows/standard.yml) + +A library to parse the x86 CPUID instruction, written in rust with no external +dependencies. The implementation closely resembles the Intel CPUID manual +description. The library works in `no_std` environments. Some additional cargo +features require `std` (e.g., pretty printing, serialization). + +- For Intel platforms: The code should be in sync with the March 2018 revision of the Intel Architectures SDM. +- For AMD platforms it should be in sync with the [AMD64 systems manual no. 24594](https://www.amd.com/system/files/TechDocs/24594.pdf), Revision 3.32 (March 2021). + +## Library usage + +```rust +use raw_cpuid::CpuId; +let cpuid = CpuId::new(); + +if let Some(vf) = cpuid.get_vendor_info() { + assert!(vf.as_str() == "GenuineIntel" || vf.as_str() == "AuthenticAMD"); +} + +let has_sse = cpuid.get_feature_info().map_or(false, |finfo| finfo.has_sse()); +if has_sse { + println!("CPU supports SSE!"); +} + +if let Some(cparams) = cpuid.get_cache_parameters() { + for cache in cparams { + let size = cache.associativity() * cache.physical_line_partitions() * cache.coherency_line_size() * cache.sets(); + println!("L{}-Cache size is {}", cache.level(), size); + } +} else { + println!("No cache parameter information available") +} +``` + +## `cpuid` binary + +`raw-cpuid` ships with a `cpuid` binary that can be installed to inspect the +output of the CPUID instruction on a host system. + +To install, use: + +```bash +cargo install raw-cpuid --features cli +``` + +The `cli` feature is currently required to build the binary version due to +[cargo limitations](https://github.com/rust-lang/cargo/issues/1982). + +## Documentation + +* [API Documentation](https://docs.rs/raw-cpuid/) +* [Examples](https://github.com/gz/rust-cpuid/tree/master/examples) diff --git a/vendor/raw-cpuid-10.7.0/examples/cache.rs b/vendor/raw-cpuid-10.7.0/examples/cache.rs new file mode 100644 index 0000000000000..02fb8fff6c4b8 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/examples/cache.rs @@ -0,0 +1,52 @@ +//! Example that displays information about the caches. +extern crate raw_cpuid; +use raw_cpuid::{CacheType, CpuId}; + +fn main() { + let cpuid = CpuId::new(); + cpuid.get_cache_parameters().map_or_else( + || println!("No cache parameter information available"), + |cparams| { + for cache in cparams { + let size = cache.associativity() + * cache.physical_line_partitions() + * cache.coherency_line_size() + * cache.sets(); + + let typ = match cache.cache_type() { + CacheType::Data => "Instruction-Cache", + CacheType::Instruction => "Data-Cache", + CacheType::Unified => "Unified-Cache", + _ => "Unknown cache type", + }; + + let associativity = if cache.is_fully_associative() { + "fully associative".to_string() + } else { + format!("{}-way associativity", cache.associativity()) + }; + + let size_repr = if size > 1024 * 1024 { + format!("{} MiB", size / (1024 * 1024)) + } else { + format!("{} KiB", size / 1024) + }; + + let mapping = if cache.has_complex_indexing() { + "hash-based-mapping" + } else { + "direct-mapped" + }; + + println!( + "L{} {}: ({}, {}, {})", + cache.level(), + typ, + size_repr, + associativity, + mapping + ); + } + }, + ); +} diff --git a/vendor/raw-cpuid-10.7.0/examples/cpu.rs b/vendor/raw-cpuid-10.7.0/examples/cpu.rs new file mode 100644 index 0000000000000..167a41cd6729e --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/examples/cpu.rs @@ -0,0 +1,349 @@ +//! An example that displays the type/features/configuration of the CPU. +extern crate raw_cpuid; + +fn main() { + let cpuid = raw_cpuid::CpuId::new(); + + println!( + "Vendor is: {}", + cpuid + .get_vendor_info() + .as_ref() + .map_or_else(|| "unknown", |vf| vf.as_str(),) + ); + + println!( + "CPU Model is: {}", + cpuid + .get_processor_brand_string() + .as_ref() + .map_or_else(|| "n/a", |pbs| pbs.as_str()) + ); + + println!( + "APIC ID is: {}", + cpuid.get_feature_info().as_ref().map_or_else( + || String::from("n/a"), + |finfo| format!("{}", finfo.initial_local_apic_id()), + ) + ); + + // 10.12.8.1 Consistency of APIC IDs and CPUID: "Initial APIC ID (CPUID.01H:EBX[31:24]) is always equal to CPUID.0BH:EDX[7:0]." + println!( + "x2APIC ID is: {}", + cpuid.get_extended_topology_info().map_or_else( + || String::from("n/a"), + |mut topiter| format!("{}", topiter.next().as_ref().unwrap().x2apic_id()), + ) + ); + + cpuid.get_feature_info().as_ref().map_or_else( + || println!("Family: n/a\nExtended Family: n/a\nModel: n/a\nExtended Model: n/a\nStepping: n/a\nBrand Index: n/a"), + |finfo| { + println!( + "Base Family: {}\nExtended Family: {}\nFamily: {}\nBase Model: {}\nExtended Model: {}\nModel: {}\nStepping: {}\nBrand Index: {}", + finfo.base_family_id(), + finfo.extended_family_id(), + finfo.family_id(), + finfo.base_model_id(), + finfo.extended_model_id(), + finfo.model_id(), + finfo.stepping_id(), + finfo.brand_index(), + ); + }, + ); + + println!( + "Serial# is: {}", + cpuid.get_processor_serial().as_ref().map_or_else( + || String::from("n/a"), + |serial_info| format!("{}", serial_info.serial()) + ) + ); + + let mut features = Vec::with_capacity(80); + cpuid.get_feature_info().map(|finfo| { + if finfo.has_sse3() { + features.push("sse3") + } + if finfo.has_pclmulqdq() { + features.push("pclmulqdq") + } + if finfo.has_ds_area() { + features.push("ds_area") + } + if finfo.has_monitor_mwait() { + features.push("monitor_mwait") + } + if finfo.has_cpl() { + features.push("cpl") + } + if finfo.has_vmx() { + features.push("vmx") + } + if finfo.has_smx() { + features.push("smx") + } + if finfo.has_eist() { + features.push("eist") + } + if finfo.has_tm2() { + features.push("tm2") + } + if finfo.has_ssse3() { + features.push("ssse3") + } + if finfo.has_cnxtid() { + features.push("cnxtid") + } + if finfo.has_fma() { + features.push("fma") + } + if finfo.has_cmpxchg16b() { + features.push("cmpxchg16b") + } + if finfo.has_pdcm() { + features.push("pdcm") + } + if finfo.has_pcid() { + features.push("pcid") + } + if finfo.has_dca() { + features.push("dca") + } + if finfo.has_sse41() { + features.push("sse41") + } + if finfo.has_sse42() { + features.push("sse42") + } + if finfo.has_x2apic() { + features.push("x2apic") + } + if finfo.has_movbe() { + features.push("movbe") + } + if finfo.has_popcnt() { + features.push("popcnt") + } + if finfo.has_tsc_deadline() { + features.push("tsc_deadline") + } + if finfo.has_aesni() { + features.push("aesni") + } + if finfo.has_xsave() { + features.push("xsave") + } + if finfo.has_oxsave() { + features.push("oxsave") + } + if finfo.has_avx() { + features.push("avx") + } + if finfo.has_f16c() { + features.push("f16c") + } + if finfo.has_rdrand() { + features.push("rdrand") + } + if finfo.has_fpu() { + features.push("fpu") + } + if finfo.has_vme() { + features.push("vme") + } + if finfo.has_de() { + features.push("de") + } + if finfo.has_pse() { + features.push("pse") + } + if finfo.has_tsc() { + features.push("tsc") + } + if finfo.has_msr() { + features.push("msr") + } + if finfo.has_pae() { + features.push("pae") + } + if finfo.has_mce() { + features.push("mce") + } + if finfo.has_cmpxchg8b() { + features.push("cmpxchg8b") + } + if finfo.has_apic() { + features.push("apic") + } + if finfo.has_sysenter_sysexit() { + features.push("sysenter_sysexit") + } + if finfo.has_mtrr() { + features.push("mtrr") + } + if finfo.has_pge() { + features.push("pge") + } + if finfo.has_mca() { + features.push("mca") + } + if finfo.has_cmov() { + features.push("cmov") + } + if finfo.has_pat() { + features.push("pat") + } + if finfo.has_pse36() { + features.push("pse36") + } + if finfo.has_psn() { + features.push("psn") + } + if finfo.has_clflush() { + features.push("clflush") + } + if finfo.has_ds() { + features.push("ds") + } + if finfo.has_acpi() { + features.push("acpi") + } + if finfo.has_mmx() { + features.push("mmx") + } + if finfo.has_fxsave_fxstor() { + features.push("fxsave_fxstor") + } + if finfo.has_sse() { + features.push("sse") + } + if finfo.has_sse2() { + features.push("sse2") + } + if finfo.has_ss() { + features.push("ss") + } + if finfo.has_htt() { + features.push("htt") + } + if finfo.has_tm() { + features.push("tm") + } + if finfo.has_pbe() { + features.push("pbe") + } + }); + + cpuid.get_extended_feature_info().map(|finfo| { + if finfo.has_bmi1() { + features.push("bmi1") + } + if finfo.has_hle() { + features.push("hle") + } + if finfo.has_avx2() { + features.push("avx2") + } + if finfo.has_fdp() { + features.push("fdp") + } + if finfo.has_smep() { + features.push("smep") + } + if finfo.has_bmi2() { + features.push("bmi2") + } + if finfo.has_rep_movsb_stosb() { + features.push("rep_movsb_stosb") + } + if finfo.has_invpcid() { + features.push("invpcid") + } + if finfo.has_rtm() { + features.push("rtm") + } + if finfo.has_rdtm() { + features.push("rdtm") + } + if finfo.has_fpu_cs_ds_deprecated() { + features.push("fpu_cs_ds_deprecated") + } + if finfo.has_mpx() { + features.push("mpx") + } + if finfo.has_rdta() { + features.push("rdta") + } + if finfo.has_rdseed() { + features.push("rdseed") + } + if finfo.has_adx() { + features.push("adx") + } + if finfo.has_smap() { + features.push("smap") + } + if finfo.has_clflushopt() { + features.push("clflushopt") + } + if finfo.has_processor_trace() { + features.push("processor_trace") + } + if finfo.has_sha() { + features.push("sha") + } + if finfo.has_sgx() { + features.push("sgx") + } + if finfo.has_avx512f() { + features.push("avx512f") + } + if finfo.has_avx512dq() { + features.push("avx512dq") + } + if finfo.has_avx512_ifma() { + features.push("avx512_ifma") + } + if finfo.has_avx512pf() { + features.push("avx512pf") + } + if finfo.has_avx512er() { + features.push("avx512er") + } + if finfo.has_avx512cd() { + features.push("avx512cd") + } + if finfo.has_avx512bw() { + features.push("avx512bw") + } + if finfo.has_avx512vl() { + features.push("avx512vl") + } + if finfo.has_clwb() { + features.push("clwb") + } + if finfo.has_prefetchwt1() { + features.push("prefetchwt1") + } + if finfo.has_umip() { + features.push("umip") + } + if finfo.has_pku() { + features.push("pku") + } + if finfo.has_ospke() { + features.push("ospke") + } + if finfo.has_rdpid() { + features.push("rdpid") + } + if finfo.has_sgx_lc() { + features.push("sgx_lc") + } + }); + + println!("CPU Features: {}", features.join(" ")); +} diff --git a/vendor/raw-cpuid-10.7.0/examples/topology.rs b/vendor/raw-cpuid-10.7.0/examples/topology.rs new file mode 100644 index 0000000000000..9b2874fe14a77 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/examples/topology.rs @@ -0,0 +1,219 @@ +//! An example that uses CPUID to determine the system topology. +//! +//! Intel Topology is a pretty complicated subject (unfortunately): +//! https://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/ +extern crate core_affinity; +extern crate raw_cpuid; + +use raw_cpuid::{CpuId, ExtendedTopologyLevel, TopologyType}; +use std::convert::TryInto; +use std::thread; + +/// Runs CPU ID on every core in the system (to gather all APIC IDs). +/// +/// # Note +/// This won't work on macOS, apparently there is no guarantee after setting the affinity +/// that a thread will really execute on the pinned core. +fn gather_all_xapic_ids() -> Vec { + let core_ids = core_affinity::get_core_ids().unwrap(); + + // Create a thread for each active CPU core. + core_ids + .into_iter() + .map(|id| { + thread::spawn(move || { + // Pin this thread to a single CPU core. + core_affinity::set_for_current(id); + // Do more work after this. + let cpuid = CpuId::new(); + cpuid + .get_feature_info() + .map_or_else(|| 0, |finfo| finfo.initial_local_apic_id()) + }) + .join() + .unwrap_or(0) + }) + .collect::>() +} + +/// Runs CPU ID on every core in the system (to gather all x2APIC IDs). +/// +/// # Note +/// This won't work on macOS, apparently there is no guarantee after setting the affinity +/// that a thread will really execute on the pinned core. +fn gather_all_x2apic_ids() -> Vec { + let core_ids = core_affinity::get_core_ids().unwrap(); + + // Create a thread for each active CPU core. + core_ids + .into_iter() + .map(|id| { + thread::spawn(move || { + // Pin this thread to a single CPU core. + core_affinity::set_for_current(id); + // Do more work after this. + let cpuid = CpuId::new(); + cpuid.get_extended_topology_info().map_or_else( + || 0, + |mut topiter| topiter.next().as_ref().unwrap().x2apic_id(), + ) + }) + .join() + .unwrap_or(0) + }) + .collect::>() +} + +fn enumerate_with_x2apic_ids() { + let cpuid = CpuId::new(); + let mut smt_x2apic_shift: u32 = 0; + let mut core_x2apic_shift: u32 = 0; + + cpuid.get_extended_topology_info().map_or_else( + || println!("No topology information available."), + |topoiter| { + let topology: Vec = topoiter.collect(); + for topolevel in topology.iter() { + match topolevel.level_type() { + TopologyType::SMT => { + smt_x2apic_shift = topolevel.shift_right_for_next_apic_id(); + } + TopologyType::Core => { + core_x2apic_shift = topolevel.shift_right_for_next_apic_id(); + } + _ => panic!("Topology category not supported."), + }; + } + }, + ); + + println!("Enumeration of all cores in the system (with x2APIC IDs):"); + let mut all_x2apic_ids: Vec = gather_all_x2apic_ids(); + all_x2apic_ids.sort_unstable(); + for x2apic_id in all_x2apic_ids { + let smt_select_mask = !(u32::max_value() << smt_x2apic_shift); + let core_select_mask = (!((u32::max_value()) << core_x2apic_shift)) ^ smt_select_mask; + let pkg_select_mask = u32::max_value() << core_x2apic_shift; + + let smt_id = x2apic_id & smt_select_mask; + let core_id = (x2apic_id & core_select_mask) >> smt_x2apic_shift; + let pkg_id = (x2apic_id & pkg_select_mask) >> core_x2apic_shift; + + println!( + "x2APIC#{} (pkg: {}, core: {}, smt: {})", + x2apic_id, pkg_id, core_id, smt_id + ); + } +} + +fn cpuid_bits_needed(count: u8) -> u8 { + let mut mask: u8 = 0x80; + let mut cnt: u8 = 8; + + while (cnt > 0) && ((mask & count) != mask) { + mask >>= 1; + cnt -= 1; + } + + cnt +} + +fn get_processor_limits() -> (u8, u8) { + let cpuid = CpuId::new(); + + // This is for AMD processors: + if let Some(info) = cpuid.get_processor_capacity_feature_info() { + let max_logical_processor_ids = info.num_phys_threads(); + let smt_max_cores_for_package = info.apic_id_size(); + + return ( + max_logical_processor_ids.try_into().unwrap(), + smt_max_cores_for_package.try_into().unwrap(), + ); + } + // This is for Intel processors: + else if let Some(cparams) = cpuid.get_cache_parameters() { + let max_logical_processor_ids = cpuid + .get_feature_info() + .map_or_else(|| 1, |finfo| finfo.max_logical_processor_ids()); + + let mut smt_max_cores_for_package: u8 = 1; + for (ecx, cache) in cparams.enumerate() { + if ecx == 0 { + smt_max_cores_for_package = cache.max_cores_for_package() as u8; + } + } + + return ( + max_logical_processor_ids as u8, + smt_max_cores_for_package as u8, + ); + } + + unreachable!("Example doesn't support this CPU") +} + +fn enumerate_with_xapic_ids() { + let (max_logical_processor_ids, smt_max_cores_for_package) = get_processor_limits(); + + let smt_mask_width: u8 = cpuid_bits_needed( + (max_logical_processor_ids.next_power_of_two() / smt_max_cores_for_package) - 1, + ); + let smt_select_mask: u8 = !(u8::max_value() << smt_mask_width); + let core_mask_width: u8 = cpuid_bits_needed(smt_max_cores_for_package - 1); + let core_only_select_mask = + (!(u8::max_value() << (core_mask_width + smt_mask_width))) ^ smt_select_mask; + let pkg_select_mask = u8::max_value() << (core_mask_width + smt_mask_width); + + println!("Enumeration of all cores in the system (with APIC IDs):"); + let mut all_xapic_ids: Vec = gather_all_xapic_ids(); + all_xapic_ids.sort_unstable(); + + for xapic_id in all_xapic_ids { + let smt_id = xapic_id & smt_select_mask; + let core_id = (xapic_id & core_only_select_mask) >> smt_mask_width; + let pkg_id = (xapic_id & pkg_select_mask) >> (core_mask_width + smt_mask_width); + + println!( + "APIC#{} (pkg: {}, core: {}, smt: {})", + xapic_id, pkg_id, core_id, smt_id + ); + } +} + +fn main() { + let cpuid = CpuId::new(); + + cpuid.get_processor_brand_string().map_or_else( + || println!("CPU model identifier not available."), + |pbs| println!("CPU Model is: {}", pbs.as_str()), + ); + cpuid.get_extended_topology_info().map_or_else( + || println!("No topology information available."), + |topoiter| { + let mut topology: Vec = topoiter.collect(); + topology.reverse(); + + for topolevel in topology.iter() { + let typ = match topolevel.level_type() { + TopologyType::SMT => "SMT-threads", + TopologyType::Core => "cores", + _ => panic!("Topology category not supported."), + }; + + println!( + "At level {} the CPU has: {} {}", + topolevel.level_number(), + topolevel.processors(), + typ, + ); + } + }, + ); + + println!(); + enumerate_with_xapic_ids(); + + println!(); + enumerate_with_x2apic_ids(); +} diff --git a/vendor/raw-cpuid-10.7.0/examples/tsc_frequency.rs b/vendor/raw-cpuid-10.7.0/examples/tsc_frequency.rs new file mode 100644 index 0000000000000..341e735558f6a --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/examples/tsc_frequency.rs @@ -0,0 +1,97 @@ +//! An example that determines the time stamp counter frequency (RDTSC, RDTSCP) . +extern crate raw_cpuid; + +use std::time; + +const MHZ_TO_HZ: u64 = 1000000; +const KHZ_TO_HZ: u64 = 1000; + +#[cfg(target_arch = "x86_64")] +#[rustversion::nightly] +use core::arch::x86_64::_rdtsc as rdtsc; + +#[cfg(target_arch = "x86")] +#[rustversion::nightly] +use core::arch::x86::_rdtsc as rdtsc; + +#[rustversion::not(nightly)] +unsafe fn rdtsc() -> u64 { + 0 +} + +fn main() { + let cpuid = raw_cpuid::CpuId::new(); + let has_tsc = cpuid + .get_feature_info() + .map_or(false, |finfo| finfo.has_tsc()); + + let has_invariant_tsc = cpuid + .get_advanced_power_mgmt_info() + .map_or(false, |efinfo| efinfo.has_invariant_tsc()); + + let tsc_frequency_hz = cpuid.get_tsc_info().map(|tinfo| { + if tinfo.nominal_frequency() != 0 { + tinfo.tsc_frequency() + } else if tinfo.numerator() != 0 && tinfo.denominator() != 0 { + // Skylake and Kabylake don't report the crystal clock, approximate with base frequency: + cpuid + .get_processor_frequency_info() + .map(|pinfo| pinfo.processor_base_frequency() as u64 * MHZ_TO_HZ) + .map(|cpu_base_freq_hz| { + let crystal_hz = + cpu_base_freq_hz * tinfo.denominator() as u64 / tinfo.numerator() as u64; + crystal_hz * tinfo.numerator() as u64 / tinfo.denominator() as u64 + }) + } else { + None + } + }); + + if has_tsc { + // Try to figure out TSC frequency with CPUID + println!( + "TSC Frequency is: {} ({})", + match tsc_frequency_hz { + Some(x) => format!("{} Hz", x.unwrap_or(0)), + None => String::from("unknown"), + }, + if has_invariant_tsc { + "invariant" + } else { + "TSC frequency varies with speed-stepping" + } + ); + + // Check if we run in a VM and the hypervisor can give us the TSC frequency + cpuid.get_hypervisor_info().map(|hv| { + hv.tsc_frequency().map(|tsc_khz| { + let virtual_tsc_frequency_hz = tsc_khz as u64 * KHZ_TO_HZ; + println!( + "Hypervisor reports TSC Frequency at: {} Hz", + virtual_tsc_frequency_hz + ); + }) + }); + + // Determine TSC frequency by measuring it (loop for a second, record ticks) + let one_second = time::Duration::from_secs(1); + let now = time::Instant::now(); + let start = unsafe { rdtsc() }; + if start > 0 { + loop { + if now.elapsed() >= one_second { + break; + } + } + let end = unsafe { rdtsc() }; + println!( + "Empirical measurement of TSC frequency was: {} Hz", + (end - start) + ); + } else { + // Don't have rdtsc on stable! + } + } else { + println!("System does not have a TSC.") + } +} diff --git a/vendor/raw-cpuid-10.7.0/src/bin/cpuid.rs b/vendor/raw-cpuid-10.7.0/src/bin/cpuid.rs new file mode 100644 index 0000000000000..5b4483e6e06a7 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/src/bin/cpuid.rs @@ -0,0 +1,48 @@ +use std::str::FromStr; + +use clap::Parser; +use raw_cpuid::CpuId; + +enum OutputFormat { + Raw, + Json, + Cli, +} + +impl FromStr for OutputFormat { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s { + "raw" => Ok(OutputFormat::Raw), + "json" => Ok(OutputFormat::Json), + "cli" => Ok(OutputFormat::Cli), + _ => Err("no match"), + } + } +} + +/// Prints information about the current x86 CPU to stdout using the cpuid instruction. +#[derive(Parser)] +#[clap(version = "10.2", author = "Gerd Zellweger ")] +#[clap(disable_colored_help(true))] +struct Opts { + /// Configures the output format. + #[clap(short, long, default_value = "cli", possible_values = &["raw", "json", "cli", ])] + format: OutputFormat, +} + +fn main() { + let opts: Opts = Opts::parse(); + match opts.format { + OutputFormat::Raw => raw_cpuid::display::raw(), + OutputFormat::Json => { + let cpuid = CpuId::new(); + raw_cpuid::display::json(cpuid); + } + OutputFormat::Cli => { + let cpuid = CpuId::new(); + raw_cpuid::display::markdown(cpuid); + } + }; +} diff --git a/vendor/raw-cpuid-10.7.0/src/display.rs b/vendor/raw-cpuid-10.7.0/src/display.rs new file mode 100644 index 0000000000000..6a4d3a162994b --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/src/display.rs @@ -0,0 +1,1489 @@ +use std::fmt::Display; + +use crate::{ + cpuid, Associativity, CacheType, CpuId, CpuIdResult, DatType, ExtendedRegisterStateLocation, + SgxSectionInfo, SoCVendorBrand, TopologyType, +}; + +use termimad::{minimad::TextTemplate, minimad::TextTemplateExpander, MadSkin}; + +pub fn raw() { + let _leafs_with_subleafs = &[0x04, 0x0d, 0x0f, 0x10, 0x12]; + + let max_leafs = cpuid!(0x0).eax; + for idx in 0..max_leafs { + let res = cpuid!(idx); + println!("({:#x}, {:#x}) => {:?}", idx, 0x0, res); + } + + let max_hypervisor_leafs = cpuid!(0x4000_0000).eax; + for idx in 0x4000_0000..max_hypervisor_leafs { + println!("({:#x}, {:#x}) => {:?}", idx, 0x0, cpuid!(idx)); + } + + let max_extended_leafs = cpuid!(0x8000_0000).eax; + for idx in 0x8000_0000..max_extended_leafs { + println!("({:#x}, {:#x}) => {:?}", idx, 0x0, cpuid!(idx)); + } +} + +pub fn json(cpuid: CpuId) { + if let Some(info) = cpuid.get_vendor_info() { + println!("VendorInfo {}", serde_json::to_string(&info).unwrap()); + } + if let Some(info) = cpuid.get_feature_info() { + println!("FeatureInfo {}", serde_json::to_string(&info).unwrap()); + } + if let Some(info) = cpuid.get_cache_info() { + println!("CacheInfoIter {}", serde_json::to_string(&info).unwrap()); + } + if let Some(info) = cpuid.get_processor_serial() { + println!("ProcessorSerial {}", serde_json::to_string(&info).unwrap()); + } + if let Some(iter) = cpuid.get_cache_parameters() { + println!( + "CacheParametersIter {}", + serde_json::to_string(&iter).unwrap() + ); + } + if let Some(info) = cpuid.get_monitor_mwait_info() { + println!("MonitorMwaitInfo {}", serde_json::to_string(&info).unwrap()); + } + if let Some(info) = cpuid.get_thermal_power_info() { + println!("ThermalPowerInfo {}", serde_json::to_string(&info).unwrap()); + } + if let Some(info) = cpuid.get_extended_feature_info() { + println!("ExtendedFeatures {}", serde_json::to_string(&info).unwrap()); + } + if let Some(info) = cpuid.get_direct_cache_access_info() { + println!( + "DirectCacheAccessInfo {}", + serde_json::to_string(&info).unwrap() + ); + } + if let Some(info) = cpuid.get_performance_monitoring_info() { + println!( + "PerformanceMonitoringInfo {}", + serde_json::to_string(&info).unwrap() + ); + } + if let Some(info) = cpuid.get_extended_topology_info() { + println!( + "ExtendedTopologyIter {}", + serde_json::to_string(&info).unwrap() + ); + } + if let Some(info) = cpuid.get_extended_state_info() { + println!( + "ExtendedStateInfo {}", + serde_json::to_string(&info).unwrap() + ); + } + if let Some(info) = cpuid.get_rdt_monitoring_info() { + println!( + "RdtMonitoringInfo {}", + serde_json::to_string(&info).unwrap() + ); + if let Some(rmid) = info.l3_monitoring() { + println!("L3MonitoringInfo {}", serde_json::to_string(&rmid).unwrap()); + } + } + if let Some(info) = cpuid.get_rdt_allocation_info() { + println!( + "RdtAllocationInfo {}", + serde_json::to_string(&info).unwrap() + ); + if let Some(l3_cat) = info.l3_cat() { + println!("L3CatInfo {}", serde_json::to_string(&l3_cat).unwrap()); + } + if let Some(l2_cat) = info.l2_cat() { + println!("L2CatInfo {}", serde_json::to_string(&l2_cat).unwrap()); + } + if let Some(mem) = info.memory_bandwidth_allocation() { + println!( + "MemBwAllocationInfo {}", + serde_json::to_string(&mem).unwrap() + ); + } + } + if let Some(info) = cpuid.get_sgx_info() { + println!("SgxInfo {}", serde_json::to_string(&info).unwrap()); + } + if let Some(info) = cpuid.get_processor_trace_info() { + println!( + "ProcessorTraceInfo {}", + serde_json::to_string(&info).unwrap() + ); + } + if let Some(info) = cpuid.get_tsc_info() { + println!("TscInfo {}", serde_json::to_string(&info).unwrap()); + } + if let Some(info) = cpuid.get_processor_frequency_info() { + println!( + "ProcessorFrequencyInfo {}", + serde_json::to_string(&info).unwrap() + ); + } + if let Some(dat_iter) = cpuid.get_deterministic_address_translation_info() { + println!("DatIter {}", serde_json::to_string(&dat_iter).unwrap()); + } + if let Some(info) = cpuid.get_soc_vendor_info() { + println!("SocVendorInfo {}", serde_json::to_string(&info).unwrap()); + if let Some(iter) = info.get_vendor_attributes() { + println!( + "SocVendorAttributesIter {}", + serde_json::to_string(&iter).unwrap() + ); + } + } + if let Some(info) = cpuid.get_processor_brand_string() { + println!( + "ProcessorBrandString {}", + serde_json::to_string(&info).unwrap() + ); + } + if let Some(info) = cpuid.get_l1_cache_and_tlb_info() { + println!("L1CacheTlbInfo {}", serde_json::to_string(&info).unwrap()); + } + if let Some(info) = cpuid.get_l2_l3_cache_and_tlb_info() { + println!( + "L2And3CacheTlbInfo {}", + serde_json::to_string(&info).unwrap() + ); + } + if let Some(info) = cpuid.get_advanced_power_mgmt_info() { + println!("ApmInfo {}", serde_json::to_string(&info).unwrap()); + } + if let Some(info) = cpuid.get_processor_capacity_feature_info() { + println!( + "ProcessorCapacityAndFeatureInfo {}", + serde_json::to_string(&info).unwrap() + ); + } + if let Some(info) = cpuid.get_svm_info() { + println!("SvmFeatures {}", serde_json::to_string(&info).unwrap()); + } + if let Some(info) = cpuid.get_memory_encryption_info() { + println!( + "MemoryEncryptionInfo {}", + serde_json::to_string(&info).unwrap() + ); + } +} + +fn string_to_static_str(s: String) -> &'static str { + Box::leak(s.into_boxed_str()) +} + +fn table2(skin: &MadSkin, attrs: &[(&'static str, String)]) { + let table_template = TextTemplate::from( + r#" +|-:|-:| +${feature-rows +|**${attr-name}**|${attr-avail}| +} +|-|-| + "#, + ); + + fn make_table_display<'a, 'b, D: Display>( + text_template: &'a TextTemplate<'b>, + attrs: &[(&'b str, D)], + ) -> TextTemplateExpander<'a, 'b> { + let mut expander = text_template.expander(); + + for (attr, desc) in attrs { + let sdesc = string_to_static_str(format!("{}", desc)); + expander + .sub("feature-rows") + .set("attr-name", attr) + .set("attr-avail", sdesc); + } + + expander + } + + let table = make_table_display(&table_template, &attrs); + skin.print_expander(table); +} + +fn table3(skin: &MadSkin, attrs: &[(&'static str, &'static str, String)]) { + let table_template3 = TextTemplate::from( + r#" +|:-|-:|-:| +${feature-rows +|**${category-name}**|**${attr-name}**|${attr-avail}| +} +|-|-| + "#, + ); + + fn make_table_display3<'a, 'b, D: Display>( + text_template: &'a TextTemplate<'b>, + attrs: &[(&'b str, &'b str, D)], + ) -> TextTemplateExpander<'a, 'b> { + let mut expander = text_template.expander(); + + for (cat, attr, desc) in attrs { + let sdesc = string_to_static_str(format!("{}", desc)); + expander + .sub("feature-rows") + .set("category-name", cat) + .set("attr-name", attr) + .set("attr-avail", sdesc); + } + + expander + } + + let table = make_table_display3(&table_template3, &attrs); + skin.print_expander(table); +} + +fn print_title_line(skin: &MadSkin, title: &str, attr: Option<&str>) { + if let Some(opt) = attr { + skin.print_text(format!("## {} = \"{}\"\n", title, opt).as_str()); + } else { + skin.print_text(format!("## {}\n", title).as_str()); + } +} + +fn print_title_attr(skin: &MadSkin, title: &str, attr: &str) { + print_title_line(skin, title, Some(attr)); +} + +fn print_title(skin: &MadSkin, title: &str) { + print_title_line(skin, title, None) +} + +fn print_subtitle(skin: &MadSkin, title: &str) { + skin.print_text(format!("### {}\n", title).as_str()); +} + +fn print_attr(skin: &MadSkin, name: T, attr: A) { + skin.print_text(format!("{} = {}", name, attr).as_str()); +} + +fn print_cpuid_result(skin: &MadSkin, name: T, attr: CpuIdResult) { + skin.print_text( + format!( + "{}: eax = {:#x} ebx = {:#x} ecx = {:#x} edx = {:#x}", + name, attr.eax, attr.ebx, attr.ecx, attr.edx, + ) + .as_str(), + ); +} + +fn bool_repr(x: bool) -> String { + if x { + "✅".to_string() + } else { + "âŒ".to_string() + } +} + +trait RowGen { + fn fmt(attr: &Self) -> String; + + fn tuple(t: &'static str, attr: Self) -> (&'static str, String) + where + Self: Sized, + { + (t, RowGen::fmt(&attr)) + } + + fn triple(c: &'static str, t: &'static str, attr: Self) -> (&'static str, &'static str, String) + where + Self: Sized, + { + (c, t, RowGen::fmt(&attr)) + } +} + +impl RowGen for bool { + fn fmt(attr: &Self) -> String { + bool_repr(*attr) + } +} + +impl RowGen for u64 { + fn fmt(attr: &Self) -> String { + format!("{}", attr) + } +} + +impl RowGen for usize { + fn fmt(attr: &Self) -> String { + format!("{}", attr) + } +} + +impl RowGen for u32 { + fn fmt(attr: &Self) -> String { + format!("{}", attr) + } +} + +impl RowGen for u16 { + fn fmt(attr: &Self) -> String { + format!("{}", attr) + } +} + +impl RowGen for u8 { + fn fmt(attr: &Self) -> String { + format!("{}", attr) + } +} + +impl RowGen for String { + fn fmt(attr: &Self) -> String { + format!("{}", attr) + } +} + +impl RowGen for Associativity { + fn fmt(attr: &Self) -> String { + format!("{}", attr) + } +} + +impl RowGen for CacheType { + fn fmt(attr: &Self) -> String { + format!("{}", attr) + } +} + +impl RowGen for TopologyType { + fn fmt(attr: &Self) -> String { + format!("{}", attr) + } +} + +impl RowGen for ExtendedRegisterStateLocation { + fn fmt(attr: &Self) -> String { + format!("{}", attr) + } +} + +impl RowGen for DatType { + fn fmt(attr: &Self) -> String { + format!("{}", attr) + } +} + +impl RowGen for Option { + fn fmt(attr: &Self) -> String { + format!( + "{}", + attr.as_ref() + .map(|v| v.as_str().to_string()) + .unwrap_or(String::from("")) + ) + } +} + +pub fn markdown(cpuid: CpuId) { + let skin = MadSkin::default(); + skin.print_text("# CpuId\n"); + + if let Some(info) = cpuid.get_vendor_info() { + print_title_attr(&skin, "vendor_id (0x00)", info.as_str()); + } + + if let Some(info) = cpuid.get_feature_info() { + print_title(&skin, "version information (1/eax):"); + table2( + &skin, + &[ + RowGen::tuple("base family", info.base_family_id()), + RowGen::tuple("base model", info.base_model_id()), + RowGen::tuple("stepping", info.stepping_id()), + RowGen::tuple("extended family", info.extended_family_id()), + RowGen::tuple("extended model", info.extended_model_id()), + RowGen::tuple("family", info.family_id()), + RowGen::tuple("model", info.model_id()), + ], + ); + + print_title(&skin, "miscellaneous (1/ebx):"); + table2( + &skin, + &[ + RowGen::tuple("processor APIC physical id", info.initial_local_apic_id()), + RowGen::tuple("max. cpus", info.max_logical_processor_ids()), + RowGen::tuple("CLFLUSH line size", info.cflush_cache_line_size()), + RowGen::tuple("brand index", info.brand_index()), + ], + ); + + print_title(&skin, "feature information (1/edx):"); + table2( + &skin, + &[ + RowGen::tuple("fpu", info.has_fpu()), + RowGen::tuple("vme", info.has_vme()), + RowGen::tuple("de", info.has_de()), + RowGen::tuple("pse", info.has_pse()), + RowGen::tuple("tsc", info.has_tsc()), + RowGen::tuple("msr", info.has_msr()), + RowGen::tuple("pae", info.has_pae()), + RowGen::tuple("mce", info.has_mce()), + RowGen::tuple("cmpxchg8b", info.has_cmpxchg8b()), + RowGen::tuple("apic", info.has_apic()), + RowGen::tuple("sysenter_sysexit", info.has_sysenter_sysexit()), + RowGen::tuple("mtrr", info.has_mtrr()), + RowGen::tuple("pge", info.has_pge()), + RowGen::tuple("mca", info.has_mca()), + RowGen::tuple("cmov", info.has_cmov()), + RowGen::tuple("pat", info.has_pat()), + RowGen::tuple("pse36", info.has_pse36()), + RowGen::tuple("psn", info.has_psn()), + RowGen::tuple("clflush", info.has_clflush()), + RowGen::tuple("ds", info.has_ds()), + RowGen::tuple("acpi", info.has_acpi()), + RowGen::tuple("mmx", info.has_mmx()), + RowGen::tuple("fxsave_fxstor", info.has_fxsave_fxstor()), + RowGen::tuple("sse", info.has_sse()), + RowGen::tuple("sse2", info.has_sse2()), + RowGen::tuple("ss", info.has_ss()), + RowGen::tuple("htt", info.has_htt()), + RowGen::tuple("tm", info.has_tm()), + RowGen::tuple("pbe", info.has_pbe()), + ], + ); + + print_title(&skin, "feature information (1/ecx):"); + table2( + &skin, + &[ + RowGen::tuple("sse3", info.has_sse3()), + RowGen::tuple("pclmulqdq", info.has_pclmulqdq()), + RowGen::tuple("ds_area", info.has_ds_area()), + RowGen::tuple("monitor_mwait", info.has_monitor_mwait()), + RowGen::tuple("cpl", info.has_cpl()), + RowGen::tuple("vmx", info.has_vmx()), + RowGen::tuple("smx", info.has_smx()), + RowGen::tuple("eist", info.has_eist()), + RowGen::tuple("tm2", info.has_tm2()), + RowGen::tuple("ssse3", info.has_ssse3()), + RowGen::tuple("cnxtid", info.has_cnxtid()), + RowGen::tuple("fma", info.has_fma()), + RowGen::tuple("cmpxchg16b", info.has_cmpxchg16b()), + RowGen::tuple("pdcm", info.has_pdcm()), + RowGen::tuple("pcid", info.has_pcid()), + RowGen::tuple("dca", info.has_dca()), + RowGen::tuple("sse41", info.has_sse41()), + RowGen::tuple("sse42", info.has_sse42()), + RowGen::tuple("x2apic", info.has_x2apic()), + RowGen::tuple("movbe", info.has_movbe()), + RowGen::tuple("popcnt", info.has_popcnt()), + RowGen::tuple("tsc_deadline", info.has_tsc_deadline()), + RowGen::tuple("aesni", info.has_aesni()), + RowGen::tuple("xsave", info.has_xsave()), + RowGen::tuple("oxsave", info.has_oxsave()), + RowGen::tuple("avx", info.has_avx()), + RowGen::tuple("f16c", info.has_f16c()), + RowGen::tuple("rdrand", info.has_rdrand()), + RowGen::tuple("hypervisor", info.has_hypervisor()), + ], + ); + } + + if let Some(info) = cpuid.get_cache_info() { + print_title(&skin, "Cache and TLB information (0x02):"); + let attrs: Vec<(&str, String)> = info + .map(|cache| { + RowGen::tuple( + string_to_static_str(format!("{:#x}", cache.num)), + cache.desc().to_string(), + ) + }) + .collect(); + table2(&skin, &attrs); + } + + if let Some(info) = cpuid.get_processor_serial() { + print_title_attr( + &skin, + "processor serial number (0x03)", + format!( + "{:0>8x}-{:0>8x}-{:0>8x}", + info.serial_upper(), + info.serial_middle(), + info.serial_lower() + ) + .as_str(), + ); + } + + if let Some(iter) = cpuid.get_cache_parameters() { + print_title(&skin, "deterministic cache parameters (0x04):"); + for cache in iter { + print_subtitle(&skin, format!("L{} Cache:", cache.level()).as_str()); + + let size = (cache.associativity() + * cache.physical_line_partitions() + * cache.coherency_line_size() + * cache.sets()) as u64; + + table2( + &skin, + &[ + RowGen::tuple("cache type", cache.cache_type()), + RowGen::tuple("cache level", cache.level()), + RowGen::tuple( + "self-initializing cache level", + cache.is_self_initializing(), + ), + RowGen::tuple("fully associative cache", cache.is_fully_associative()), + RowGen::tuple("threads sharing this cache", cache.max_cores_for_cache()), + RowGen::tuple("processor cores on this die", cache.max_cores_for_package()), + RowGen::tuple("system coherency line size", cache.coherency_line_size()), + RowGen::tuple("physical line partitions", cache.physical_line_partitions()), + RowGen::tuple("ways of associativity", cache.associativity()), + RowGen::tuple( + "WBINVD/INVD acts on lower caches", + cache.is_write_back_invalidate(), + ), + RowGen::tuple("inclusive to lower caches", cache.is_inclusive()), + RowGen::tuple("complex cache indexing", cache.has_complex_indexing()), + RowGen::tuple("number of sets", cache.sets()), + RowGen::tuple("(size synth.)", size), + ], + ); + } + } + + if let Some(info) = cpuid.get_monitor_mwait_info() { + print_title(&skin, "MONITOR/MWAIT (0x05):"); + table2( + &skin, + &[ + RowGen::tuple("smallest monitor-line size", info.smallest_monitor_line()), + RowGen::tuple("largest monitor-line size", info.largest_monitor_line()), + RowGen::tuple("MONITOR/MWAIT exts", info.extensions_supported()), + RowGen::tuple( + "Interrupts as break-event for MWAIT", + info.interrupts_as_break_event(), + ), + ], + ); + + skin.print_text("number of CX sub C-states using MWAIT:\n"); + let cstate_table = TextTemplate::from( + r#" + | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | + |**C0**|**C1**|**C2**|**C3**|**C4**|**C5**|**C6**|**C7**| + | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | + |${c0}|${c1}|${c2}|${c3}|${c4}|${c5}|${c6}|${c7}| + | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | + "#, + ); + let c0 = format!("{}", info.supported_c0_states()); + let c1 = format!("{}", info.supported_c1_states()); + let c2 = format!("{}", info.supported_c2_states()); + let c3 = format!("{}", info.supported_c3_states()); + let c4 = format!("{}", info.supported_c4_states()); + let c5 = format!("{}", info.supported_c5_states()); + let c6 = format!("{}", info.supported_c6_states()); + let c7 = format!("{}", info.supported_c7_states()); + + let mut ctbl = cstate_table.expander(); + ctbl.set("c0", c0.as_str()); + ctbl.set("c1", c1.as_str()); + ctbl.set("c2", c2.as_str()); + ctbl.set("c3", c3.as_str()); + ctbl.set("c4", c4.as_str()); + ctbl.set("c5", c5.as_str()); + ctbl.set("c6", c6.as_str()); + ctbl.set("c7", c7.as_str()); + skin.print_expander(ctbl); + } + + if let Some(info) = cpuid.get_thermal_power_info() { + print_title(&skin, "Thermal and Power Management Features (0x06):"); + table2( + &skin, + &[ + RowGen::tuple("digital thermometer", info.has_dts()), + RowGen::tuple("Intel Turbo Boost Technology", info.has_turbo_boost()), + RowGen::tuple("ARAT always running APIC timer", info.has_arat()), + RowGen::tuple("PLN power limit notification", info.has_pln()), + RowGen::tuple("ECMD extended clock modulation duty", info.has_ecmd()), + RowGen::tuple("PTM package thermal management", info.has_ptm()), + RowGen::tuple("HWP base registers", info.has_hwp()), + RowGen::tuple("HWP notification", info.has_hwp_notification()), + RowGen::tuple("HWP activity window", info.has_hwp_activity_window()), + RowGen::tuple( + "HWP energy performance preference", + info.has_hwp_energy_performance_preference(), + ), + RowGen::tuple( + "HWP package level request", + info.has_hwp_package_level_request(), + ), + RowGen::tuple("HDC base registers", info.has_hdc()), + RowGen::tuple( + "Intel Turbo Boost Max Technology 3.0", + info.has_turbo_boost3(), + ), + RowGen::tuple("HWP capabilities", info.has_hwp_capabilities()), + RowGen::tuple("HWP PECI override", info.has_hwp_peci_override()), + RowGen::tuple("flexible HWP", info.has_flexible_hwp()), + RowGen::tuple( + "IA32_HWP_REQUEST MSR fast access mode", + info.has_hwp_fast_access_mode(), + ), + RowGen::tuple( + "ignoring idle logical processor HWP req", + info.has_ignore_idle_processor_hwp_request(), + ), + RowGen::tuple("digital thermometer threshold", info.dts_irq_threshold()), + RowGen::tuple( + "hardware coordination feedback", + info.has_hw_coord_feedback(), + ), + RowGen::tuple( + "performance-energy bias capability", + info.has_energy_bias_pref(), + ), + ], + ); + } + + if let Some(info) = cpuid.get_extended_feature_info() { + print_title(&skin, "Extended feature flags (0x07):"); + + table2( + &skin, + &[ + RowGen::tuple("FSGSBASE", info.has_fsgsbase()), + RowGen::tuple("IA32_TSC_ADJUST MSR", info.has_tsc_adjust_msr()), + RowGen::tuple("SGX: Software Guard Extensions", info.has_sgx()), + RowGen::tuple("BMI1", info.has_bmi1()), + RowGen::tuple("HLE hardware lock elision", info.has_hle()), + RowGen::tuple("AVX2: advanced vector extensions 2", info.has_avx2()), + RowGen::tuple("FDP_EXCPTN_ONLY", info.has_fdp()), + RowGen::tuple("SMEP supervisor mode exec protection", info.has_smep()), + RowGen::tuple("BMI2 instructions", info.has_bmi2()), + RowGen::tuple("enhanced REP MOVSB/STOSB", info.has_rep_movsb_stosb()), + RowGen::tuple("INVPCID instruction", info.has_invpcid()), + RowGen::tuple("RTM: restricted transactional memory", info.has_rtm()), + RowGen::tuple("RDT-CMT/PQoS cache monitoring", info.has_rdtm()), + RowGen::tuple("deprecated FPU CS/DS", info.has_fpu_cs_ds_deprecated()), + RowGen::tuple("MPX: intel memory protection extensions", info.has_mpx()), + RowGen::tuple("RDT-CAT/PQE cache allocation", info.has_rdta()), + RowGen::tuple( + "AVX512F: AVX-512 foundation instructions", + info.has_avx512f(), + ), + RowGen::tuple( + "AVX512DQ: double & quadword instructions", + info.has_avx512dq(), + ), + RowGen::tuple("RDSEED instruction", info.has_rdseed()), + RowGen::tuple("ADX instructions", info.has_adx()), + RowGen::tuple("SMAP: supervisor mode access prevention", info.has_smap()), + RowGen::tuple("AVX512IFMA: fused multiply add", info.has_avx512_ifma()), + RowGen::tuple("CLFLUSHOPT instruction", info.has_clflushopt()), + RowGen::tuple("CLWB instruction", info.has_clwb()), + RowGen::tuple("Intel processor trace", info.has_processor_trace()), + RowGen::tuple("AVX512PF: prefetch instructions", info.has_avx512pf()), + RowGen::tuple( + "AVX512ER: exponent & reciprocal instrs", + info.has_avx512er(), + ), + RowGen::tuple("AVX512CD: conflict detection instrs", info.has_avx512cd()), + RowGen::tuple("SHA instructions", info.has_sha()), + RowGen::tuple("AVX512BW: byte & word instructions", info.has_avx512bw()), + RowGen::tuple("AVX512VL: vector length", info.has_avx512vl()), + RowGen::tuple("PREFETCHWT1", info.has_prefetchwt1()), + RowGen::tuple("UMIP: user-mode instruction prevention", info.has_umip()), + RowGen::tuple("PKU protection keys for user-mode", info.has_pku()), + RowGen::tuple("OSPKE CR4.PKE and RDPKRU/WRPKRU", info.has_ospke()), + RowGen::tuple( + "AVX512VNNI: vector neural network instructions", + info.has_avx512vnni(), + ), + RowGen::tuple( + "BNDLDX/BNDSTX MAWAU value in 64-bit mode", + info.mawau_value(), + ), + RowGen::tuple("RDPID: read processor ID", info.has_rdpid()), + RowGen::tuple("SGX_LC: SGX launch config", info.has_sgx_lc()), + ], + ); + } + + if let Some(info) = cpuid.get_direct_cache_access_info() { + print_title(&skin, "Direct Cache Access Parameters (0x09):"); + print_attr(&skin, "PLATFORM_DCA_CAP MSR bits", info.get_dca_cap_value()); + } + + if let Some(info) = cpuid.get_performance_monitoring_info() { + print_title(&skin, "Architecture Performance Monitoring Features (0x0a)"); + + print_subtitle(&skin, "Monitoring Hardware Info (0x0a/{eax, edx}):"); + table2( + &skin, + &[ + RowGen::tuple("version ID", info.version_id()), + RowGen::tuple( + "number of counters per HW thread", + info.number_of_counters(), + ), + RowGen::tuple("bit width of counter", info.counter_bit_width()), + RowGen::tuple("length of EBX bit vector", info.ebx_length()), + RowGen::tuple("number of fixed counters", info.fixed_function_counters()), + RowGen::tuple( + "bit width of fixed counters", + info.fixed_function_counters_bit_width(), + ), + RowGen::tuple("anythread deprecation", info.has_any_thread_deprecation()), + ], + ); + + print_subtitle(&skin, "Monitoring Hardware Features (0x0a/ebx):"); + table2( + &skin, + &[ + RowGen::tuple( + "core cycle event not available", + info.is_core_cyc_ev_unavailable(), + ), + RowGen::tuple( + "instruction retired event not available", + info.is_inst_ret_ev_unavailable(), + ), + RowGen::tuple( + "reference cycles event not available", + info.is_ref_cycle_ev_unavailable(), + ), + RowGen::tuple( + "last-level cache ref event not available", + info.is_cache_ref_ev_unavailable(), + ), + RowGen::tuple( + "last-level cache miss event not avail", + info.is_ll_cache_miss_ev_unavailable(), + ), + RowGen::tuple( + "branch inst retired event not available", + info.is_branch_inst_ret_ev_unavailable(), + ), + RowGen::tuple( + "branch mispred retired event not available", + info.is_branch_midpred_ev_unavailable(), + ), + ], + ); + } + + if let Some(info) = cpuid.get_extended_topology_info() { + print_title(&skin, "x2APIC features / processor topology (0x0b):"); + + for level in info { + print_subtitle(&skin, format!("level {}:", level.level_number()).as_str()); + table2( + &skin, + &[ + RowGen::tuple("level type", level.level_type()), + RowGen::tuple("bit width of level", level.shift_right_for_next_apic_id()), + RowGen::tuple("number of logical processors at level", level.processors()), + RowGen::tuple("x2apic id of current processor", level.x2apic_id()), + ], + ); + } + } + + if let Some(info) = cpuid.get_extended_state_info() { + print_title(&skin, "Extended Register State (0x0d/0):"); + + print_subtitle(&skin, "XCR0/IA32_XSS supported states:"); + table3( + &skin, + &[ + RowGen::triple("XCR0", "x87", info.xcr0_supports_legacy_x87()), + RowGen::triple("XCR0", "SSE state", info.xcr0_supports_sse_128()), + RowGen::triple("XCR0", "AVX state", info.xcr0_supports_avx_256()), + RowGen::triple("XCR0", "MPX BNDREGS", info.xcr0_supports_mpx_bndregs()), + RowGen::triple("XCR0", "MPX BNDCSR", info.xcr0_supports_mpx_bndcsr()), + RowGen::triple("XCR0", "AVX-512 opmask", info.xcr0_supports_avx512_opmask()), + RowGen::triple( + "XCR0", + "AVX-512 ZMM_Hi256", + info.xcr0_supports_avx512_zmm_hi256(), + ), + RowGen::triple( + "XCR0", + "AVX-512 Hi16_ZMM", + info.xcr0_supports_avx512_zmm_hi16(), + ), + RowGen::triple("IA32_XSS", "PT", info.ia32_xss_supports_pt()), + RowGen::triple("XCR0", "PKRU", info.xcr0_supports_pkru()), + //("XCR0", "CET_U state", xxx), + //("XCR0", "CET_S state", xxx), + RowGen::triple("IA32_XSS", "HDC", info.ia32_xss_supports_hdc()), + ], + ); + + table2( + &skin, + &[ + RowGen::tuple( + "bytes required by fields in XCR0", + info.xsave_area_size_enabled_features(), + ), + RowGen::tuple( + "bytes required by XSAVE/XRSTOR area", + info.xsave_area_size_supported_features(), + ), + ], + ); + + print_subtitle(&skin, "XSAVE features (0x0d/1):"); + table2( + &skin, + &[ + RowGen::tuple("XSAVEOPT instruction", info.has_xsaveopt()), + RowGen::tuple("XSAVEC instruction", info.has_xsavec()), + RowGen::tuple("XGETBV instruction", info.has_xgetbv()), + RowGen::tuple("XSAVES/XRSTORS instructions", info.has_xsaves_xrstors()), + RowGen::tuple("SAVE area size [Bytes]", info.xsave_size()), + ], + ); + + for state in info.iter() { + print_subtitle( + &skin, + format!("{} features (0x0d/{}):", state.register(), state.subleaf).as_str(), + ); + table2( + &skin, + &[ + RowGen::tuple("save state size [Bytes]", state.size()), + RowGen::tuple("save state byte offset", state.offset()), + RowGen::tuple("supported in IA32_XSS or XCR0", state.location()), + RowGen::tuple( + "64-byte alignment in compacted XSAVE", + state.is_compacted_format(), + ), + ], + ); + } + } + + if let Some(info) = cpuid.get_rdt_monitoring_info() { + print_title( + &skin, + "Quality of Service Monitoring Resource Type (0x0f/0):", + ); + table2( + &skin, + &[ + RowGen::tuple("Maximum range of RMID", info.rmid_range()), + RowGen::tuple("L3 cache QoS monitoring", info.has_l3_monitoring()), + ], + ); + + if let Some(rmid) = info.l3_monitoring() { + print_subtitle(&skin, "L3 Cache Quality of Service Monitoring (0x0f/1):"); + + table2( + &skin, + &[ + RowGen::tuple( + "Conversion factor from IA32_QM_CTR to bytes", + rmid.conversion_factor(), + ), + RowGen::tuple("Maximum range of RMID", rmid.maximum_rmid_range()), + RowGen::tuple("L3 occupancy monitoring", rmid.has_occupancy_monitoring()), + RowGen::tuple( + "L3 total bandwidth monitoring", + rmid.has_total_bandwidth_monitoring(), + ), + RowGen::tuple( + "L3 local bandwidth monitoring", + rmid.has_local_bandwidth_monitoring(), + ), + ], + ); + } + } + + if let Some(info) = cpuid.get_rdt_allocation_info() { + print_title(&skin, "Resource Director Technology Allocation (0x10/0)"); + table2( + &skin, + &[ + RowGen::tuple("L3 cache allocation technology", info.has_l3_cat()), + RowGen::tuple("L2 cache allocation technology", info.has_l2_cat()), + RowGen::tuple( + "memory bandwidth allocation", + info.has_memory_bandwidth_allocation(), + ), + ], + ); + + if let Some(l3_cat) = info.l3_cat() { + print_subtitle(&skin, "L3 Cache Allocation Technology (0x10/1):"); + table2( + &skin, + &[ + RowGen::tuple("length of capacity bit mask", l3_cat.capacity_mask_length()), + RowGen::tuple( + "Bit-granular map of isolation/contention", + l3_cat.isolation_bitmap(), + ), + RowGen::tuple( + "code and data prioritization", + l3_cat.has_code_data_prioritization(), + ), + RowGen::tuple("highest COS number", l3_cat.highest_cos()), + ], + ); + } + if let Some(l2_cat) = info.l2_cat() { + print_subtitle(&skin, "L2 Cache Allocation Technology (0x10/2):"); + table2( + &skin, + &[ + RowGen::tuple("length of capacity bit mask", l2_cat.capacity_mask_length()), + RowGen::tuple( + "Bit-granular map of isolation/contention", + l2_cat.isolation_bitmap(), + ), + RowGen::tuple("highest COS number", l2_cat.highest_cos()), + ], + ); + } + if let Some(mem) = info.memory_bandwidth_allocation() { + print_subtitle(&skin, "Memory Bandwidth Allocation (0x10/3):"); + table2( + &skin, + &[ + RowGen::tuple("maximum throttling value", mem.max_hba_throttling()), + RowGen::tuple("delay values are linear", mem.has_linear_response_delay()), + RowGen::tuple("highest COS number", mem.highest_cos()), + ], + ); + } + } + + if let Some(info) = cpuid.get_sgx_info() { + print_title(&skin, "SGX - Software Guard Extensions (0x12/{0,1}):"); + + table2( + &skin, + &[ + RowGen::tuple("SGX1", info.has_sgx1()), + RowGen::tuple("SGX2", info.has_sgx2()), + RowGen::tuple( + "SGX ENCLV E*VIRTCHILD, ESETCONTEXT", + info.has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext(), + ), + RowGen::tuple( + "SGX ENCLS ETRACKC, ERDINFO, ELDBC, ELDUC", + info.has_encls_leaves_etrackc_erdinfo_eldbc_elduc(), + ), + RowGen::tuple("MISCSELECT", info.miscselect()), + RowGen::tuple( + "MaxEnclaveSize_Not64 (log2)", + info.max_enclave_size_non_64bit(), + ), + RowGen::tuple("MaxEnclaveSize_64 (log2)", info.max_enclave_size_64bit()), + ], + ); + + for (idx, leaf) in info.iter().enumerate() { + let SgxSectionInfo::Epc(section) = leaf; + print_subtitle( + &skin, + format!("Enclave Page Cache (0x12/{})", idx + 2).as_str(), + ); + table2( + &skin, + &[ + RowGen::tuple("physical base address", section.physical_base()), + RowGen::tuple("size", section.size()), + ], + ); + } + } + + if let Some(info) = cpuid.get_processor_trace_info() { + print_title(&skin, "Intel Processor Trace (0x14):"); + table2( + &skin, + &[ + RowGen::tuple( + "IA32_RTIT_CR3_MATCH is accessible", + info.has_rtit_cr3_match(), + ), + RowGen::tuple( + "configurable PSB & cycle-accurate", + info.has_configurable_psb_and_cycle_accurate_mode(), + ), + RowGen::tuple( + "IP & TraceStop filtering; PT preserve", + info.has_ip_tracestop_filtering(), + ), + RowGen::tuple( + "MTC timing packet; suppress COFI-based", + info.has_mtc_timing_packet_coefi_suppression(), + ), + RowGen::tuple("PTWRITE", info.has_ptwrite()), + RowGen::tuple("power event trace", info.has_power_event_trace()), + RowGen::tuple("ToPA output scheme", info.has_topa()), + RowGen::tuple( + "ToPA can hold many output entries", + info.has_topa_maximum_entries(), + ), + RowGen::tuple( + "single-range output scheme support", + info.has_single_range_output_scheme(), + ), + RowGen::tuple( + "output to trace transport", + info.has_trace_transport_subsystem(), + ), + RowGen::tuple( + "IP payloads have LIP values & CS", + info.has_lip_with_cs_base(), + ), + RowGen::tuple( + "configurable address ranges", + info.configurable_address_ranges(), + ), + RowGen::tuple( + "supported MTC periods bitmask", + info.supported_mtc_period_encodings(), + ), + RowGen::tuple( + "supported cycle threshold bitmask", + info.supported_cycle_threshold_value_encodings(), + ), + RowGen::tuple( + "supported config PSB freq bitmask", + info.supported_psb_frequency_encodings(), + ), + ], + ); + } + + if let Some(info) = cpuid.get_tsc_info() { + print_title( + &skin, + "Time Stamp Counter/Core Crystal Clock Information (0x15):", + ); + table2( + &skin, + &[ + RowGen::tuple( + "TSC/clock ratio", + format!("{} / {}", info.numerator(), info.denominator()), + ), + RowGen::tuple("nominal core crystal clock", info.nominal_frequency()), + ], + ); + } + + if let Some(info) = cpuid.get_processor_frequency_info() { + print_title(&skin, "Processor Frequency Information (0x16):"); + table2( + &skin, + &[ + RowGen::tuple("Core Base Frequency (MHz)", info.processor_base_frequency()), + RowGen::tuple( + "Core Maximum Frequency (MHz)", + info.processor_max_frequency(), + ), + RowGen::tuple("Bus (Reference) Frequency (MHz)", info.bus_frequency()), + ], + ); + } + + if let Some(dat_iter) = cpuid.get_deterministic_address_translation_info() { + for (idx, info) in dat_iter.enumerate() { + print_title( + &skin, + format!( + "Deterministic Address Translation Structure (0x18/{}):", + idx + ) + .as_str(), + ); + table2( + &skin, + &[ + RowGen::tuple("number of sets", info.sets()), + RowGen::tuple("4 KiB page size entries", info.has_4k_entries()), + RowGen::tuple("2 MiB page size entries", info.has_2mb_entries()), + RowGen::tuple("4 MiB page size entries", info.has_4mb_entries()), + RowGen::tuple("1 GiB page size entries", info.has_1gb_entries()), + RowGen::tuple("partitioning", info.partitioning()), + RowGen::tuple("ways of associativity", info.ways()), + RowGen::tuple("translation cache type", info.cache_type()), + RowGen::tuple("translation cache level", info.cache_level()), + RowGen::tuple("fully associative", info.is_fully_associative()), + RowGen::tuple( + "maximum number of addressible IDs", + info.max_addressable_ids(), + ), + RowGen::tuple( + "maximum number of addressible IDs", + info.max_addressable_ids(), + ), + ], + ); + } + } + + if let Some(info) = cpuid.get_soc_vendor_info() { + print_title(&skin, "System-on-Chip (SoC) Vendor Info (0x17):"); + table2( + &skin, + &[ + RowGen::tuple("Vendor ID", info.get_soc_vendor_id()), + RowGen::tuple("Project ID", info.get_project_id()), + RowGen::tuple("Stepping ID", info.get_stepping_id()), + RowGen::tuple("Vendor Brand", info.get_vendor_brand()), + ], + ); + + if let Some(iter) = info.get_vendor_attributes() { + for (idx, attr) in iter.enumerate() { + print_cpuid_result(&skin, format!("0x17 {:#x}", idx + 4), attr); + } + } + } + + if let Some(info) = cpuid.get_processor_brand_string() { + print_attr( + &skin, + "Processor Brand String", + format!("\"**{}**\"", info.as_str()), + ); + } + + if let Some(info) = cpuid.get_l1_cache_and_tlb_info() { + print_title(&skin, "L1 TLB 2/4 MiB entries (0x8000_0005/eax):"); + table2( + &skin, + &[ + RowGen::tuple("iTLB #entries", info.itlb_2m_4m_size()), + RowGen::tuple("iTLB associativity", info.itlb_2m_4m_associativity()), + RowGen::tuple("dTLB #entries", info.dtlb_2m_4m_size()), + RowGen::tuple("dTLB associativity", info.dtlb_2m_4m_associativity()), + ], + ); + + print_title(&skin, "L1 TLB 4 KiB entries (0x8000_0005/ebx):"); + table2( + &skin, + &[ + RowGen::tuple("iTLB #entries", info.itlb_4k_size()), + RowGen::tuple("iTLB associativity", info.itlb_4k_associativity()), + RowGen::tuple("dTLB #entries", info.dtlb_4k_size()), + RowGen::tuple("dTLB associativity", info.dtlb_4k_associativity()), + ], + ); + + print_title(&skin, "L1 dCache (0x8000_0005/ecx):"); + table2( + &skin, + &[ + RowGen::tuple("line size [Bytes]", info.dcache_line_size()), + RowGen::tuple("lines per tag", info.dcache_lines_per_tag()), + RowGen::tuple("associativity", info.dcache_associativity()), + RowGen::tuple("size [KiB]", info.dcache_size()), + ], + ); + + print_title(&skin, "L1 iCache (0x8000_0005/edx):"); + table2( + &skin, + &[ + RowGen::tuple("line size [Bytes]", info.icache_line_size()), + RowGen::tuple("lines per tag", info.icache_lines_per_tag()), + RowGen::tuple("associativity", info.icache_associativity()), + RowGen::tuple("size [KiB]", info.icache_size()), + ], + ); + } + + if let Some(info) = cpuid.get_l2_l3_cache_and_tlb_info() { + print_title(&skin, "L2 TLB 2/4 MiB entries (0x8000_0006/eax):"); + table2( + &skin, + &[ + RowGen::tuple("iTLB #entries", info.itlb_2m_4m_size()), + RowGen::tuple("iTLB associativity", info.itlb_2m_4m_associativity()), + RowGen::tuple("dTLB #entries", info.dtlb_2m_4m_size()), + RowGen::tuple("dTLB associativity", info.dtlb_2m_4m_associativity()), + ], + ); + + print_title(&skin, "L2 TLB 4 KiB entries (0x8000_0006/ebx):"); + table2( + &skin, + &[ + RowGen::tuple("iTLB #entries", info.itlb_4k_size()), + RowGen::tuple("iTLB associativity", info.itlb_4k_associativity()), + RowGen::tuple("dTLB #entries", info.dtlb_4k_size()), + RowGen::tuple("dTLB associativity", info.dtlb_4k_associativity()), + ], + ); + + print_title(&skin, "L2 Cache (0x8000_0006/ecx):"); + table2( + &skin, + &[ + RowGen::tuple("line size [Bytes]", info.l2cache_line_size()), + RowGen::tuple("lines per tag", info.l2cache_lines_per_tag()), + RowGen::tuple("associativity", info.l2cache_associativity()), + RowGen::tuple("size [KiB]", info.l2cache_size()), + ], + ); + + print_title(&skin, "L3 Cache (0x8000_0006/edx):"); + table2( + &skin, + &[ + RowGen::tuple("line size [Bytes]", info.l3cache_line_size()), + RowGen::tuple("lines per tag", info.l3cache_lines_per_tag()), + RowGen::tuple("associativity", info.l3cache_associativity()), + RowGen::tuple("size [KiB]", info.l3cache_size() as usize * 512), + ], + ); + } + + if let Some(info) = cpuid.get_advanced_power_mgmt_info() { + print_title(&skin, "RAS Capability (0x8000_0007/ebx):"); + table2( + &skin, + &[ + RowGen::tuple("MCA overflow recovery", info.has_mca_overflow_recovery()), + RowGen::tuple("SUCCOR", info.has_succor()), + RowGen::tuple("HWA: hardware assert", info.has_hwa()), + ], + ); + + print_title(&skin, "Advanced Power Management (0x8000_0007/ecx):"); + print_attr( + &skin, + "Ratio of Compute Unit Power Acc. sample period to TSC", + info.cpu_pwr_sample_time_ratio(), + ); + + print_title(&skin, "Advanced Power Management (0x8000_0007/edx):"); + table2( + &skin, + &[ + RowGen::tuple("TS: temperature sensing diode", info.has_ts()), + RowGen::tuple("FID: frequency ID control", info.has_freq_id_ctrl()), + RowGen::tuple("VID: voltage ID control", info.has_volt_id_ctrl()), + RowGen::tuple("TTP: thermal trip", info.has_thermtrip()), + RowGen::tuple("TM: thermal monitor", info.has_tm()), + RowGen::tuple("100 MHz multiplier control", info.has_100mhz_steps()), + RowGen::tuple("hardware P-State control", info.has_hw_pstate()), + RowGen::tuple("Invariant TSC", info.has_invariant_tsc()), + RowGen::tuple("CPB: core performance boost", info.has_cpb()), + RowGen::tuple( + "read-only effective frequency interface", + info.has_ro_effective_freq_iface(), + ), + RowGen::tuple("processor feedback interface", info.has_feedback_iface()), + RowGen::tuple("APM power reporting", info.has_power_reporting_iface()), + ], + ); + } + + if let Some(info) = cpuid.get_processor_capacity_feature_info() { + print_title( + &skin, + "Physical Address and Linear Address Size (0x8000_0008/eax):", + ); + table2( + &skin, + &[ + RowGen::tuple( + "maximum physical address [Bits]", + info.physical_address_bits(), + ), + RowGen::tuple( + "maximum linear (virtual) address [Bits]", + info.linear_address_bits(), + ), + RowGen::tuple( + "maximum guest physical address [Bits]", + info.guest_physical_address_bits(), + ), + ], + ); + + print_title(&skin, "Extended Feature Extensions ID (0x8000_0008/ebx):"); + table2( + &skin, + &[ + RowGen::tuple("CLZERO", info.has_cl_zero()), + RowGen::tuple("instructions retired count", info.has_inst_ret_cntr_msr()), + RowGen::tuple( + "always save/restore error pointers", + info.has_restore_fp_error_ptrs(), + ), + RowGen::tuple("RDPRU", info.has_rdpru()), + RowGen::tuple("INVLPGB", info.has_invlpgb()), + RowGen::tuple("MCOMMIT", info.has_mcommit()), + RowGen::tuple("WBNOINVD", info.has_wbnoinvd()), + RowGen::tuple("WBNOINVD/WBINVD interruptible", info.has_int_wbinvd()), + RowGen::tuple("EFER.LMSLE unsupported", info.has_unsupported_efer_lmsle()), + RowGen::tuple("INVLPGB with nested paging", info.has_invlpgb_nested()), + ], + ); + + print_title(&skin, "Size Identifiers (0x8000_0008/ecx):"); + table2( + &skin, + &[ + RowGen::tuple("Logical processors", info.num_phys_threads()), + RowGen::tuple("APIC core ID size", info.apic_id_size()), + RowGen::tuple("Max. logical processors", info.maximum_logical_processors()), + RowGen::tuple("Perf. TSC size [Bits]", info.perf_tsc_size()), + ], + ); + + print_title(&skin, "Size Identifiers (0x8000_0008/edx):"); + table2( + &skin, + &[ + RowGen::tuple("RDPRU max. input value", info.max_rdpru_id()), + RowGen::tuple("INVLPGB max. #pages", info.invlpgb_max_pages()), + ], + ); + } + + if let Some(info) = cpuid.get_svm_info() { + print_title(&skin, "SVM Secure Virtual Machine (0x8000_000a/eax):"); + print_attr(&skin, "Revision", info.revision()); + + print_title(&skin, "SVM Secure Virtual Machine (0x8000_000a/edx):"); + table2( + &skin, + &[ + RowGen::tuple("nested paging", info.has_nested_paging()), + RowGen::tuple("LBR virtualization", info.has_lbr_virtualization()), + RowGen::tuple("SVM lock", info.has_svm_lock()), + RowGen::tuple("NRIP", info.has_nrip()), + RowGen::tuple("MSR based TSC rate control", info.has_tsc_rate_msr()), + RowGen::tuple("VMCB clean bits support", info.has_vmcb_clean_bits()), + RowGen::tuple("flush by ASID", info.has_flush_by_asid()), + RowGen::tuple("decode assists", info.has_decode_assists()), + RowGen::tuple("pause intercept filter", info.has_pause_filter()), + RowGen::tuple("pause filter threshold", info.has_pause_filter_threshold()), + RowGen::tuple("AVIC: virtual interrupt controller", info.has_avic()), + RowGen::tuple( + "virtualized VMLOAD/VMSAVE", + info.has_vmsave_virtualization(), + ), + RowGen::tuple("GIF: virtual global interrupt flag", info.has_gif()), + RowGen::tuple("GMET: guest mode execute trap", info.has_gmet()), + RowGen::tuple("SPEC_CTRL virtualization", info.has_spec_ctrl()), + RowGen::tuple("Supervisor shadow-stack restrictions", info.has_sss_check()), + RowGen::tuple("#MC intercept", info.has_host_mce_override()), + RowGen::tuple("INVLPGB/TLBSYNC virtualization", info.has_tlb_ctrl()), + ], + ); + } + + if let Some(info) = cpuid.get_tlb_1gb_page_info() { + print_title(&skin, "TLB 1-GiB Pages Info (0x8000_0019):"); + table2( + &skin, + &[ + RowGen::tuple("L1 iTLB #entries", info.itlb_l1_1gb_size()), + RowGen::tuple("L1 iTLB associativity", info.itlb_l1_1gb_associativity()), + RowGen::tuple("L1 dTLB #entries", info.dtlb_l1_1gb_size()), + RowGen::tuple("L1 dTLB associativity", info.dtlb_l1_1gb_associativity()), + RowGen::tuple("L2 iTLB #entries", info.itlb_l2_1gb_size()), + RowGen::tuple("L2 iTLB associativity", info.itlb_l2_1gb_associativity()), + RowGen::tuple("L2 dTLB #entries", info.dtlb_l2_1gb_size()), + RowGen::tuple("L2 dTLB associativity", info.dtlb_l2_1gb_associativity()), + ], + ); + } + + if let Some(info) = cpuid.get_performance_optimization_info() { + print_title(&skin, "Performance Optimization Info (0x8000_001a):"); + table2( + &skin, + &[ + RowGen::tuple("128-bits width the internal FP/SIMD", info.has_fp128()), + RowGen::tuple( + "MOVU SSE are efficient more than MOVL/MOVH", + info.has_movu(), + ), + RowGen::tuple("256-bits width the internal FP/SIMD", info.has_fp256()), + ], + ); + } + + if let Some(info) = cpuid.get_processor_topology_info() { + print_title(&skin, "Processor Topology Info (0x8000_001e):"); + table2( + &skin, + &[ + RowGen::tuple("x2APIC ID", info.x2apic_id()), + RowGen::tuple("Core ID", info.core_id()), + RowGen::tuple("Threads per core", info.threads_per_core()), + RowGen::tuple("Node ID", info.node_id()), + RowGen::tuple("Nodes per processor", info.nodes_per_processor()), + ], + ); + } + + if let Some(info) = cpuid.get_memory_encryption_info() { + print_title(&skin, "Memory Encryption Support (0x8000_001f):"); + table2( + &skin, + &[ + RowGen::tuple("SME: Secure Memory Encryption", info.has_sme()), + RowGen::tuple("SEV: Secure Encrypted Virtualization", info.has_sev()), + RowGen::tuple("Page Flush MSR", info.has_page_flush_msr()), + RowGen::tuple("SEV-ES: Encrypted State", info.has_sev_es()), + RowGen::tuple("SEV Secure Nested Paging", info.has_sev_snp()), + RowGen::tuple("VM Permission Levels", info.has_vmpl()), + RowGen::tuple( + "Hardware cache coherency across encryption domains", + info.has_hw_enforced_cache_coh(), + ), + RowGen::tuple("SEV guests only with 64-bit host", info.has_64bit_mode()), + RowGen::tuple("Restricted injection", info.has_restricted_injection()), + RowGen::tuple("Alternate injection", info.has_alternate_injection()), + RowGen::tuple( + "Full debug state swap for SEV-ES guests", + info.has_debug_swap(), + ), + RowGen::tuple( + "Disallowing IBS use by the host supported", + info.has_prevent_host_ibs(), + ), + RowGen::tuple("Virtual Transparent Encryption", info.has_vte()), + RowGen::tuple("C-bit position in page-table", info.c_bit_position()), + RowGen::tuple( + "Physical address bit reduction", + info.physical_address_reduction(), + ), + RowGen::tuple( + "Max. simultaneouslys encrypted guests", + info.max_encrypted_guests(), + ), + RowGen::tuple( + "Minimum ASID value for SEV guest", + info.min_sev_no_es_asid(), + ), + ], + ); + } +} diff --git a/vendor/raw-cpuid-10.7.0/src/extended.rs b/vendor/raw-cpuid-10.7.0/src/extended.rs new file mode 100644 index 0000000000000..ab842367ba094 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/src/extended.rs @@ -0,0 +1,1775 @@ +//! Data-structures / interpretation for extended leafs (>= 0x8000_0000) +use core::fmt::{self, Debug, Display, Formatter}; +use core::mem::size_of; +use core::slice; +use core::str; + +use crate::{get_bits, CpuIdResult, Vendor}; + +/// Extended Processor and Processor Feature Identifiers (LEAF=0x8000_0001) +/// +/// # Platforms +/// ✅ AMD 🟡 Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ExtendedProcessorFeatureIdentifiers { + vendor: Vendor, + eax: u32, + ebx: u32, + ecx: ExtendedFunctionInfoEcx, + edx: ExtendedFunctionInfoEdx, +} + +impl ExtendedProcessorFeatureIdentifiers { + pub(crate) fn new(vendor: Vendor, data: CpuIdResult) -> Self { + Self { + vendor, + eax: data.eax, + ebx: data.ebx, + ecx: ExtendedFunctionInfoEcx::from_bits_truncate(data.ecx), + edx: ExtendedFunctionInfoEdx::from_bits_truncate(data.edx), + } + } + + /// Extended Processor Signature. + /// + /// # AMD + /// The value returned is the same as the value returned in EAX for LEAF=0x0000_0001 + /// (use `CpuId.get_feature_info` instead) + /// + /// # Intel + /// Vague mention of "Extended Processor Signature", not clear what it's supposed to + /// represent. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn extended_signature(&self) -> u32 { + self.eax + } + + /// Returns package type on AMD. + /// + /// Package type. If `(Family[7:0] >= 10h)`, this field is valid. If + /// `(Family[7:0]<10h)`, this field is reserved + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved) + pub fn pkg_type(&self) -> u32 { + get_bits(self.ebx, 28, 31) + } + + /// Returns brand ID on AMD. + /// + /// This field, in conjunction with CPUID `LEAF=0x0000_0001_EBX[8BitBrandId]`, and used + /// by firmware to generate the processor name string. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved) + pub fn brand_id(&self) -> u32 { + get_bits(self.ebx, 0, 15) + } + + /// Is LAHF/SAHF available in 64-bit mode? + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn has_lahf_sahf(&self) -> bool { + self.ecx.contains(ExtendedFunctionInfoEcx::LAHF_SAHF) + } + + /// Check support legacy cmp. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_cmp_legacy(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::CMP_LEGACY) + } + + /// Secure virtual machine supported. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_svm(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::SVM) + } + + /// Extended APIC space. + /// + /// This bit indicates the presence of extended APIC register space starting at offset + /// 400h from the “APIC Base Address Register,†as specified in the BKDG. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_ext_apic_space(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::EXT_APIC_SPACE) + } + + /// LOCK MOV CR0 means MOV CR8. See “MOV(CRn)†in APM3. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_alt_mov_cr8(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::ALTMOVCR8) + } + + /// Is LZCNT available? + /// + /// # AMD + /// It's called ABM (Advanced bit manipulation) on AMD and also adds support for + /// some other instructions. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn has_lzcnt(&self) -> bool { + self.ecx.contains(ExtendedFunctionInfoEcx::LZCNT) + } + + /// XTRQ, INSERTQ, MOVNTSS, and MOVNTSD instruction support. + /// + /// See “EXTRQâ€, “INSERTQâ€,“MOVNTSSâ€, and “MOVNTSD†in APM4. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_sse4a(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::SSE4A) + } + + /// Misaligned SSE mode. See “Misaligned Access Support Added for SSE Instructions†in + /// APM1. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_misaligned_sse_mode(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::MISALIGNSSE) + } + + /// Is PREFETCHW available? + /// + /// # AMD + /// PREFETCH and PREFETCHW instruction support. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn has_prefetchw(&self) -> bool { + self.ecx.contains(ExtendedFunctionInfoEcx::PREFETCHW) + } + + /// Indicates OS-visible workaround support + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_osvw(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::OSVW) + } + + /// Instruction based sampling. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_ibs(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::IBS) + } + + /// Extended operation support. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_xop(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::XOP) + } + + /// SKINIT and STGI are supported. + /// + /// Indicates support for SKINIT and STGI, independent of the value of + /// `MSRC000_0080[SVME]`. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_skinit(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::SKINIT) + } + + /// Watchdog timer support. + /// + /// Indicates support for MSRC001_0074. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_wdt(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::WDT) + } + + /// Lightweight profiling support + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_lwp(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::LWP) + } + + /// Four-operand FMA instruction support. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_fma4(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::FMA4) + } + + /// Trailing bit manipulation instruction support. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_tbm(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::TBM) + } + + /// Topology extensions support. + /// + /// Indicates support for CPUID `Fn8000_001D_EAX_x[N:0]-CPUID Fn8000_001E_EDX`. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_topology_extensions(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::TOPEXT) + } + + /// Processor performance counter extensions support. + /// + /// Indicates support for `MSRC001_020[A,8,6,4,2,0]` and `MSRC001_020[B,9,7,5,3,1]`. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_perf_cntr_extensions(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::PERFCTREXT) + } + + /// NB performance counter extensions support. + /// + /// Indicates support for `MSRC001_024[6,4,2,0]` and `MSRC001_024[7,5,3,1]`. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_nb_perf_cntr_extensions(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::PERFCTREXTNB) + } + + /// Data access breakpoint extension. + /// + /// Indicates support for `MSRC001_1027` and `MSRC001_101[B:9]`. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_data_access_bkpt_extension(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::DATABRKPEXT) + } + + /// Performance time-stamp counter. + /// + /// Indicates support for `MSRC001_0280` `[Performance Time Stamp Counter]`. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_perf_tsc(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::PERFTSC) + } + + /// Support for L3 performance counter extension. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_perf_cntr_llc_extensions(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::PERFCTREXTLLC) + } + + /// Support for MWAITX and MONITORX instructions. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_monitorx_mwaitx(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::MONITORX) + } + + /// Breakpoint Addressing masking extended to bit 31. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_addr_mask_extension(&self) -> bool { + self.vendor == Vendor::Amd && self.ecx.contains(ExtendedFunctionInfoEcx::ADDRMASKEXT) + } + + /// Are fast system calls available. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn has_syscall_sysret(&self) -> bool { + self.edx.contains(ExtendedFunctionInfoEdx::SYSCALL_SYSRET) + } + + /// Is there support for execute disable bit. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn has_execute_disable(&self) -> bool { + self.edx.contains(ExtendedFunctionInfoEdx::EXECUTE_DISABLE) + } + + /// AMD extensions to MMX instructions. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_mmx_extensions(&self) -> bool { + self.vendor == Vendor::Amd && self.edx.contains(ExtendedFunctionInfoEdx::MMXEXT) + } + + /// FXSAVE and FXRSTOR instruction optimizations. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_fast_fxsave_fxstor(&self) -> bool { + self.vendor == Vendor::Amd && self.edx.contains(ExtendedFunctionInfoEdx::FFXSR) + } + + /// Is there support for 1GiB pages. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn has_1gib_pages(&self) -> bool { + self.edx.contains(ExtendedFunctionInfoEdx::GIB_PAGES) + } + + /// Check support for rdtscp instruction. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn has_rdtscp(&self) -> bool { + self.edx.contains(ExtendedFunctionInfoEdx::RDTSCP) + } + + /// Check support for 64-bit mode. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn has_64bit_mode(&self) -> bool { + self.edx.contains(ExtendedFunctionInfoEdx::I64BIT_MODE) + } + + /// 3DNow AMD extensions. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_amd_3dnow_extensions(&self) -> bool { + self.vendor == Vendor::Amd && self.edx.contains(ExtendedFunctionInfoEdx::THREEDNOWEXT) + } + + /// 3DNow extensions. + /// + /// # Platform + /// ✅ AMD ⌠Intel (will return false) + pub fn has_3dnow(&self) -> bool { + self.vendor == Vendor::Amd && self.edx.contains(ExtendedFunctionInfoEdx::THREEDNOW) + } +} + +impl Debug for ExtendedProcessorFeatureIdentifiers { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("ExtendedProcessorFeatureIdentifiers"); + ds.field("extended_signature", &self.extended_signature()); + + if self.vendor == Vendor::Amd { + ds.field("pkg_type", &self.pkg_type()); + ds.field("brand_id", &self.brand_id()); + } + ds.field("ecx_features", &self.ecx); + ds.field("edx_features", &self.edx); + ds.finish() + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct ExtendedFunctionInfoEcx: u32 { + const LAHF_SAHF = 1 << 0; + const CMP_LEGACY = 1 << 1; + const SVM = 1 << 2; + const EXT_APIC_SPACE = 1 << 3; + const ALTMOVCR8 = 1 << 4; + const LZCNT = 1 << 5; + const SSE4A = 1 << 6; + const MISALIGNSSE = 1 << 7; + const PREFETCHW = 1 << 8; + const OSVW = 1 << 9; + const IBS = 1 << 10; + const XOP = 1 << 11; + const SKINIT = 1 << 12; + const WDT = 1 << 13; + const LWP = 1 << 15; + const FMA4 = 1 << 16; + const TBM = 1 << 21; + const TOPEXT = 1 << 22; + const PERFCTREXT = 1 << 23; + const PERFCTREXTNB = 1 << 24; + const DATABRKPEXT = 1 << 26; + const PERFTSC = 1 << 27; + const PERFCTREXTLLC = 1 << 28; + const MONITORX = 1 << 29; + const ADDRMASKEXT = 1 << 30; + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct ExtendedFunctionInfoEdx: u32 { + const SYSCALL_SYSRET = 1 << 11; + const EXECUTE_DISABLE = 1 << 20; + const MMXEXT = 1 << 22; + const FFXSR = 1 << 24; + const GIB_PAGES = 1 << 26; + const RDTSCP = 1 << 27; + const I64BIT_MODE = 1 << 29; + const THREEDNOWEXT = 1 << 30; + const THREEDNOW = 1 << 31; + } +} + +/// Processor name (LEAF=0x8000_0002..=0x8000_0004). +/// +/// ASCII string up to 48 characters in length corresponding to the processor name. +/// +/// # Platforms +/// ✅ AMD ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ProcessorBrandString { + data: [CpuIdResult; 3], +} + +impl ProcessorBrandString { + pub(crate) fn new(data: [CpuIdResult; 3]) -> Self { + Self { data } + } + + /// Return the processor brand string as a rust string. + /// + /// For example: + /// "11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz". + pub fn as_str(&self) -> &str { + // Safety: CpuIdResult is laid out with repr(C), and the array + // self.data contains 3 contiguous elements. + let slice: &[u8] = unsafe { + slice::from_raw_parts( + self.data.as_ptr() as *const u8, + self.data.len() * size_of::(), + ) + }; + + // Brand terminated at nul byte or end, whichever comes first. + let slice = slice.split(|&x| x == 0).next().unwrap(); + str::from_utf8(slice) + .unwrap_or("Invalid Processor Brand String") + .trim() + } +} + +impl Debug for ProcessorBrandString { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ProcessorBrandString") + .field("as_str", &self.as_str()) + .finish() + } +} + +/// L1 Cache and TLB Information (LEAF=0x8000_0005). +/// +/// # Availability +/// ✅ AMD ⌠Intel (reserved=0) +#[derive(PartialEq, Eq, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct L1CacheTlbInfo { + eax: u32, + ebx: u32, + ecx: u32, + edx: u32, +} + +impl L1CacheTlbInfo { + pub(crate) fn new(data: CpuIdResult) -> Self { + Self { + eax: data.eax, + ebx: data.ebx, + ecx: data.ecx, + edx: data.edx, + } + } + + /// Data TLB associativity for 2-MB and 4-MB pages. + pub fn dtlb_2m_4m_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.eax, 24, 31) as u8; + Associativity::for_l1(assoc_bits) + } + + /// Data TLB number of entries for 2-MB and 4-MB pages. + /// + /// The value returned is for the number of entries available for the 2-MB page size; + /// 4-MB pages require two 2-MB entries, so the number of entries available for the + /// 4-MB page size is one-half the returned value. + pub fn dtlb_2m_4m_size(&self) -> u8 { + get_bits(self.eax, 16, 23) as u8 + } + + /// Instruction TLB associativity for 2-MB and 4-MB pages. + pub fn itlb_2m_4m_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.eax, 8, 15) as u8; + Associativity::for_l1(assoc_bits) + } + + /// Instruction TLB number of entries for 2-MB and 4-MB pages. + /// + /// The value returned is for the number of entries available for the 2-MB page size; + /// 4-MB pages require two 2-MB entries, so the number of entries available for the + /// 4-MB page size is one-half the returned value. + pub fn itlb_2m_4m_size(&self) -> u8 { + get_bits(self.eax, 0, 7) as u8 + } + + /// Data TLB associativity for 4K pages. + pub fn dtlb_4k_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.ebx, 24, 31) as u8; + Associativity::for_l1(assoc_bits) + } + + /// Data TLB number of entries for 4K pages. + pub fn dtlb_4k_size(&self) -> u8 { + get_bits(self.ebx, 16, 23) as u8 + } + + /// Instruction TLB associativity for 4K pages. + pub fn itlb_4k_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.ebx, 8, 15) as u8; + Associativity::for_l1(assoc_bits) + } + + /// Instruction TLB number of entries for 4K pages. + pub fn itlb_4k_size(&self) -> u8 { + get_bits(self.ebx, 0, 7) as u8 + } + + /// L1 data cache size in KB + pub fn dcache_size(&self) -> u8 { + get_bits(self.ecx, 24, 31) as u8 + } + + /// L1 data cache associativity. + pub fn dcache_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.ecx, 16, 23) as u8; + Associativity::for_l1(assoc_bits) + } + + /// L1 data cache lines per tag. + pub fn dcache_lines_per_tag(&self) -> u8 { + get_bits(self.ecx, 8, 15) as u8 + } + + /// L1 data cache line size in bytes. + pub fn dcache_line_size(&self) -> u8 { + get_bits(self.ecx, 0, 7) as u8 + } + + /// L1 instruction cache size in KB + pub fn icache_size(&self) -> u8 { + get_bits(self.edx, 24, 31) as u8 + } + + /// L1 instruction cache associativity. + pub fn icache_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.edx, 16, 23) as u8; + Associativity::for_l1(assoc_bits) + } + + /// L1 instruction cache lines per tag. + pub fn icache_lines_per_tag(&self) -> u8 { + get_bits(self.edx, 8, 15) as u8 + } + + /// L1 instruction cache line size in bytes. + pub fn icache_line_size(&self) -> u8 { + get_bits(self.edx, 0, 7) as u8 + } +} + +/// L2/L3 Cache and TLB Information (LEAF=0x8000_0006). +/// +/// # Availability +/// ✅ AMD 🟡 Intel +#[derive(PartialEq, Eq, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct L2And3CacheTlbInfo { + eax: u32, + ebx: u32, + ecx: u32, + edx: u32, +} + +impl L2And3CacheTlbInfo { + pub(crate) fn new(data: CpuIdResult) -> Self { + Self { + eax: data.eax, + ebx: data.ebx, + ecx: data.ecx, + edx: data.edx, + } + } + + /// L2 Data TLB associativity for 2-MB and 4-MB pages. + /// + /// # Availability + /// ✅ AMD ⌠Intel (reserved=0) + pub fn dtlb_2m_4m_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.eax, 28, 31) as u8; + Associativity::for_l2(assoc_bits) + } + + /// L2 Data TLB number of entries for 2-MB and 4-MB pages. + /// + /// The value returned is for the number of entries available for the 2-MB page size; + /// 4-MB pages require two 2-MB entries, so the number of entries available for the + /// 4-MB page size is one-half the returned value. + /// + /// # Availability + /// ✅ AMD ⌠Intel (reserved=0) + pub fn dtlb_2m_4m_size(&self) -> u16 { + get_bits(self.eax, 16, 27) as u16 + } + + /// L2 Instruction TLB associativity for 2-MB and 4-MB pages. + /// + /// # Availability + /// ✅ AMD ⌠Intel (reserved=0) + pub fn itlb_2m_4m_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.eax, 12, 15) as u8; + Associativity::for_l2(assoc_bits) + } + + /// L2 Instruction TLB number of entries for 2-MB and 4-MB pages. + /// + /// The value returned is for the number of entries available for the 2-MB page size; + /// 4-MB pages require two 2-MB entries, so the number of entries available for the + /// 4-MB page size is one-half the returned value. + /// + /// # Availability + /// ✅ AMD ⌠Intel (reserved=0) + pub fn itlb_2m_4m_size(&self) -> u16 { + get_bits(self.eax, 0, 11) as u16 + } + + /// L2 Data TLB associativity for 4K pages. + /// + /// # Availability + /// ✅ AMD ⌠Intel (reserved=0) + pub fn dtlb_4k_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.ebx, 28, 31) as u8; + Associativity::for_l2(assoc_bits) + } + + /// L2 Data TLB number of entries for 4K pages. + /// + /// # Availability + /// ✅ AMD ⌠Intel (reserved=0) + pub fn dtlb_4k_size(&self) -> u16 { + get_bits(self.ebx, 16, 27) as u16 + } + + /// L2 Instruction TLB associativity for 4K pages. + /// + /// # Availability + /// ✅ AMD ⌠Intel (reserved=0) + pub fn itlb_4k_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.ebx, 12, 15) as u8; + Associativity::for_l2(assoc_bits) + } + + /// L2 Instruction TLB number of entries for 4K pages. + /// + /// # Availability + /// ✅ AMD ⌠Intel (reserved=0) + pub fn itlb_4k_size(&self) -> u16 { + get_bits(self.ebx, 0, 11) as u16 + } + + /// L2 Cache Line size in bytes + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn l2cache_line_size(&self) -> u8 { + get_bits(self.ecx, 0, 7) as u8 + } + + /// L2 cache lines per tag. + /// + /// # Availability + /// ✅ AMD ⌠Intel (reserved=0) + pub fn l2cache_lines_per_tag(&self) -> u8 { + get_bits(self.ecx, 8, 11) as u8 + } + + /// L2 Associativity field + /// + /// # Availability + /// ✅ AMD ✅ Intel + pub fn l2cache_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.ecx, 12, 15) as u8; + Associativity::for_l2(assoc_bits) + } + + /// Cache size in KB. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn l2cache_size(&self) -> u16 { + get_bits(self.ecx, 16, 31) as u16 + } + + /// L2 Cache Line size in bytes + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=0) + pub fn l3cache_line_size(&self) -> u8 { + get_bits(self.edx, 0, 7) as u8 + } + + /// L2 cache lines per tag. + /// + /// # Availability + /// ✅ AMD ⌠Intel (reserved=0) + pub fn l3cache_lines_per_tag(&self) -> u8 { + get_bits(self.edx, 8, 11) as u8 + } + + /// L2 Associativity field + /// + /// # Availability + /// ✅ AMD ⌠Intel (reserved=0) + pub fn l3cache_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.edx, 12, 15) as u8; + Associativity::for_l3(assoc_bits) + } + + /// Specifies the L3 cache size range + /// + /// `(L3Size[31:18] * 512KB) <= L3 cache size < ((L3Size[31:18]+1) * 512KB)`. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=0) + pub fn l3cache_size(&self) -> u16 { + get_bits(self.edx, 18, 31) as u16 + } +} + +/// Info about cache Associativity. +#[derive(PartialEq, Eq, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub enum Associativity { + Disabled, + DirectMapped, + NWay(u8), + FullyAssociative, + Unknown, +} + +impl Display for Associativity { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let s = match self { + Associativity::Disabled => "Disabled", + Associativity::DirectMapped => "Direct mapped", + Associativity::NWay(n) => { + return write!(f, "NWay({})", n); + } + Associativity::FullyAssociative => "Fully associative", + Associativity::Unknown => "Unknown (check leaf 0x8000_001d)", + }; + f.write_str(s) + } +} + +impl Associativity { + /// Constructor for L1 Cache and TLB Associativity Field Encodings + fn for_l1(n: u8) -> Associativity { + match n { + 0x0 => Associativity::Disabled, // Intel only, AMD is reserved + 0x1 => Associativity::DirectMapped, + 0x2..=0xfe => Associativity::NWay(n), + 0xff => Associativity::FullyAssociative, + } + } + + /// Constructor for L2 Cache and TLB Associativity Field Encodings + fn for_l2(n: u8) -> Associativity { + match n { + 0x0 => Associativity::Disabled, + 0x1 => Associativity::DirectMapped, + 0x2 => Associativity::NWay(2), + 0x4 => Associativity::NWay(4), + 0x5 => Associativity::NWay(6), // Reserved on Intel + 0x6 => Associativity::NWay(8), + // 0x7 => SDM states: "See CPUID leaf 04H, sub-leaf 2" + 0x8 => Associativity::NWay(16), + 0x9 => Associativity::Unknown, // Intel: Reserved, AMD: Value for all fields should be determined from Fn8000_001D + 0xa => Associativity::NWay(32), + 0xb => Associativity::NWay(48), + 0xc => Associativity::NWay(64), + 0xd => Associativity::NWay(96), + 0xe => Associativity::NWay(128), + 0xF => Associativity::FullyAssociative, + _ => Associativity::Unknown, + } + } + + /// Constructor for L2 Cache and TLB Associativity Field Encodings + fn for_l3(n: u8) -> Associativity { + Associativity::for_l2(n) + } +} + +/// Processor Power Management and RAS Capabilities (LEAF=0x8000_0007). +/// +/// # Platforms +/// ✅ AMD 🟡 Intel +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ApmInfo { + /// Reserved on AMD and Intel. + _eax: u32, + ebx: RasCapabilities, + ecx: u32, + edx: ApmInfoEdx, +} + +impl ApmInfo { + pub(crate) fn new(data: CpuIdResult) -> Self { + Self { + _eax: data.eax, + ebx: RasCapabilities::from_bits_truncate(data.ebx), + ecx: data.ecx, + edx: ApmInfoEdx::from_bits_truncate(data.edx), + } + } + + /// Is MCA overflow recovery available? + /// + /// If set, indicates that MCA overflow conditions (`MCi_STATUS[Overflow]=1`) + /// are not fatal; software may safely ignore such conditions. If clear, MCA + /// overflow conditions require software to shut down the system. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_mca_overflow_recovery(&self) -> bool { + self.ebx.contains(RasCapabilities::MCAOVFLRECOV) + } + + /// Has Software uncorrectable error containment and recovery capability? + /// + /// The processor supports software containment of uncorrectable errors + /// through context synchronizing data poisoning and deferred error + /// interrupts. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_succor(&self) -> bool { + self.ebx.contains(RasCapabilities::SUCCOR) + } + + /// Has Hardware assert supported? + /// + /// Indicates support for `MSRC001_10[DF:C0]`. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_hwa(&self) -> bool { + self.ebx.contains(RasCapabilities::HWA) + } + + /// Specifies the ratio of the compute unit power accumulator sample period + /// to the TSC counter period. + /// + /// Returns a value of 0 if not applicable for the system. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=0) + pub fn cpu_pwr_sample_time_ratio(&self) -> u32 { + self.ecx + } + + /// Is Temperature Sensor available? + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_ts(&self) -> bool { + self.edx.contains(ApmInfoEdx::TS) + } + + /// Frequency ID control. + /// + /// # Note + /// Function replaced by `has_hw_pstate`. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_freq_id_ctrl(&self) -> bool { + self.edx.contains(ApmInfoEdx::FID) + } + + /// Voltage ID control. + /// + /// # Note + /// Function replaced by `has_hw_pstate`. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_volt_id_ctrl(&self) -> bool { + self.edx.contains(ApmInfoEdx::VID) + } + + /// Has THERMTRIP? + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_thermtrip(&self) -> bool { + self.edx.contains(ApmInfoEdx::TTP) + } + + /// Hardware thermal control (HTC)? + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_tm(&self) -> bool { + self.edx.contains(ApmInfoEdx::TM) + } + + /// Has 100 MHz multiplier Control? + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_100mhz_steps(&self) -> bool { + self.edx.contains(ApmInfoEdx::MHZSTEPS100) + } + + /// Has Hardware P-state control? + /// + /// MSRC001_0061 [P-state Current Limit], MSRC001_0062 [P-state Control] and + /// MSRC001_0063 [P-state Status] exist + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_hw_pstate(&self) -> bool { + self.edx.contains(ApmInfoEdx::HWPSTATE) + } + + /// Is Invariant TSC available? + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn has_invariant_tsc(&self) -> bool { + self.edx.contains(ApmInfoEdx::INVTSC) + } + + /// Has Core performance boost? + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_cpb(&self) -> bool { + self.edx.contains(ApmInfoEdx::CPB) + } + + /// Has Read-only effective frequency interface? + /// + /// Indicates presence of MSRC000_00E7 [Read-Only Max Performance Frequency + /// Clock Count (MPerfReadOnly)] and MSRC000_00E8 [Read-Only Actual + /// Performance Frequency Clock Count (APerfReadOnly)]. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_ro_effective_freq_iface(&self) -> bool { + self.edx.contains(ApmInfoEdx::EFFFREQRO) + } + + /// Indicates support for processor feedback interface. + /// + /// # Note + /// This feature is deprecated. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_feedback_iface(&self) -> bool { + self.edx.contains(ApmInfoEdx::PROCFEEDBACKIF) + } + + /// Has Processor power reporting interface? + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_power_reporting_iface(&self) -> bool { + self.edx.contains(ApmInfoEdx::PROCPWRREPORT) + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct ApmInfoEdx: u32 { + const TS = 1 << 0; + const FID = 1 << 1; + const VID = 1 << 2; + const TTP = 1 << 3; + const TM = 1 << 4; + const MHZSTEPS100 = 1 << 6; + const HWPSTATE = 1 << 7; + const INVTSC = 1 << 8; + const CPB = 1 << 9; + const EFFFREQRO = 1 << 10; + const PROCFEEDBACKIF = 1 << 11; + const PROCPWRREPORT = 1 << 12; + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct RasCapabilities: u32 { + const MCAOVFLRECOV = 1 << 0; + const SUCCOR = 1 << 1; + const HWA = 1 << 2; + } +} + +/// Processor Capacity Parameters and Extended Feature Identification +/// (LEAF=0x8000_0008). +/// +/// This function provides the size or capacity of various architectural +/// parameters that vary by implementation, as well as an extension to the +/// 0x8000_0001 feature identifiers. +/// +/// # Platforms +/// ✅ AMD 🟡 Intel +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ProcessorCapacityAndFeatureInfo { + eax: u32, + ebx: ProcessorCapacityAndFeatureEbx, + ecx: u32, + edx: u32, +} + +impl ProcessorCapacityAndFeatureInfo { + pub(crate) fn new(data: CpuIdResult) -> Self { + Self { + eax: data.eax, + ebx: ProcessorCapacityAndFeatureEbx::from_bits_truncate(data.ebx), + ecx: data.ecx, + edx: data.edx, + } + } + + /// Physical Address Bits + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn physical_address_bits(&self) -> u8 { + get_bits(self.eax, 0, 7) as u8 + } + + /// Linear Address Bits + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn linear_address_bits(&self) -> u8 { + get_bits(self.eax, 8, 15) as u8 + } + + /// Guest Physical Address Bits + /// + /// This number applies only to guests using nested paging. When this field + /// is zero, refer to the PhysAddrSize field for the maximum guest physical + /// address size. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=0) + pub fn guest_physical_address_bits(&self) -> u8 { + get_bits(self.eax, 16, 23) as u8 + } + + /// CLZERO instruction supported if set. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_cl_zero(&self) -> bool { + self.ebx.contains(ProcessorCapacityAndFeatureEbx::CLZERO) + } + + /// Instruction Retired Counter MSR available if set. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_inst_ret_cntr_msr(&self) -> bool { + self.ebx + .contains(ProcessorCapacityAndFeatureEbx::INST_RETCNT_MSR) + } + + /// FP Error Pointers Restored by XRSTOR if set. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_restore_fp_error_ptrs(&self) -> bool { + self.ebx + .contains(ProcessorCapacityAndFeatureEbx::RSTR_FP_ERR_PTRS) + } + + /// INVLPGB and TLBSYNC instruction supported if set. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_invlpgb(&self) -> bool { + self.ebx.contains(ProcessorCapacityAndFeatureEbx::INVLPGB) + } + + /// RDPRU instruction supported if set. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_rdpru(&self) -> bool { + self.ebx.contains(ProcessorCapacityAndFeatureEbx::RDPRU) + } + + /// MCOMMIT instruction supported if set. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_mcommit(&self) -> bool { + self.ebx.contains(ProcessorCapacityAndFeatureEbx::MCOMMIT) + } + + /// WBNOINVD instruction supported if set. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn has_wbnoinvd(&self) -> bool { + self.ebx.contains(ProcessorCapacityAndFeatureEbx::WBNOINVD) + } + + /// WBINVD/WBNOINVD are interruptible if set. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_int_wbinvd(&self) -> bool { + self.ebx + .contains(ProcessorCapacityAndFeatureEbx::INT_WBINVD) + } + + /// EFER.LMSLE is unsupported if set. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_unsupported_efer_lmsle(&self) -> bool { + self.ebx + .contains(ProcessorCapacityAndFeatureEbx::EFER_LMSLE_UNSUPP) + } + + /// INVLPGB support for invalidating guest nested translations if set. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn has_invlpgb_nested(&self) -> bool { + self.ebx + .contains(ProcessorCapacityAndFeatureEbx::INVLPGB_NESTED) + } + + /// Performance time-stamp counter size (in bits). + /// + /// Indicates the size of `MSRC001_0280[PTSC]`. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=false) + pub fn perf_tsc_size(&self) -> usize { + let s = get_bits(self.ecx, 16, 17) as u8; + match s & 0b11 { + 0b00 => 40, + 0b01 => 48, + 0b10 => 56, + 0b11 => 64, + _ => unreachable!("AND with 0b11 in match"), + } + } + + /// APIC ID size. + /// + /// A value of zero indicates that legacy methods must be used to determine + /// the maximum number of logical processors, as indicated by CPUID + /// `Fn8000_0008_ECX[NC]`. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=0) + pub fn apic_id_size(&self) -> u8 { + get_bits(self.ecx, 12, 15) as u8 + } + + /// The size of the `apic_id_size` field determines the maximum number of + /// logical processors (MNLP) that the package could theoretically support, + /// and not the actual number of logical processors that are implemented or + /// enabled in the package, as indicated by CPUID `Fn8000_0008_ECX[NC]`. + /// + /// `MNLP = (2 raised to the power of ApicIdSize[3:0])` (if not 0) + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=0) + pub fn maximum_logical_processors(&self) -> usize { + usize::pow(2, self.apic_id_size() as u32) + } + + /// Number of physical threads in the processor. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=0) + pub fn num_phys_threads(&self) -> usize { + get_bits(self.ecx, 0, 7) as usize + 1 + } + + /// Maximum page count for INVLPGB instruction. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=0) + pub fn invlpgb_max_pages(&self) -> u16 { + get_bits(self.edx, 0, 15) as u16 + } + + /// The maximum ECX value recognized by RDPRU. + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved=0) + pub fn max_rdpru_id(&self) -> u16 { + get_bits(self.edx, 16, 31) as u16 + } +} + +impl Debug for ProcessorCapacityAndFeatureInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("ProcessorCapacityAndFeatureInfo") + .field("physical_address_bits", &self.physical_address_bits()) + .field("linear_address_bits", &self.linear_address_bits()) + .field( + "guest_physical_address_bits", + &self.guest_physical_address_bits(), + ) + .field("has_cl_zero", &self.has_cl_zero()) + .field("has_inst_ret_cntr_msr", &self.has_inst_ret_cntr_msr()) + .field( + "has_restore_fp_error_ptrs", + &self.has_restore_fp_error_ptrs(), + ) + .field("has_invlpgb", &self.has_invlpgb()) + .field("has_rdpru", &self.has_rdpru()) + .field("has_mcommit", &self.has_mcommit()) + .field("has_wbnoinvd", &self.has_wbnoinvd()) + .field("has_int_wbinvd", &self.has_int_wbinvd()) + .field( + "has_unsupported_efer_lmsle", + &self.has_unsupported_efer_lmsle(), + ) + .field("has_invlpgb_nested", &self.has_invlpgb_nested()) + .field("perf_tsc_size", &self.perf_tsc_size()) + .field("apic_id_size", &self.apic_id_size()) + .field( + "maximum_logical_processors", + &self.maximum_logical_processors(), + ) + .field("num_phys_threads", &self.num_phys_threads()) + .field("invlpgb_max_pages", &self.invlpgb_max_pages()) + .field("max_rdpru_id", &self.max_rdpru_id()) + .finish() + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct ProcessorCapacityAndFeatureEbx: u32 { + const CLZERO = 1 << 0; + const INST_RETCNT_MSR = 1 << 1; + const RSTR_FP_ERR_PTRS = 1 << 2; + const INVLPGB = 1 << 3; + const RDPRU = 1 << 4; + const MCOMMIT = 1 << 8; + const WBNOINVD = 1 << 9; + const INT_WBINVD = 1 << 13; + const EFER_LMSLE_UNSUPP = 1 << 20; + const INVLPGB_NESTED = 1 << 21; + } +} + +/// Information about the SVM features that the processory supports (LEAF=0x8000_000A). +/// +/// # Note +/// If SVM is not supported ([ExtendedProcessorFeatureIdentifiers::has_svm] is false), +/// this leaf is reserved ([crate::CpuId] will return None in this case). +/// +/// # Platforms +/// ✅ AMD ⌠Intel +#[derive(PartialEq, Eq, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct SvmFeatures { + eax: u32, + ebx: u32, + /// Reserved + _ecx: u32, + edx: SvmFeaturesEdx, +} + +impl SvmFeatures { + pub(crate) fn new(data: CpuIdResult) -> Self { + Self { + eax: data.eax, + ebx: data.ebx, + _ecx: data.ecx, + edx: SvmFeaturesEdx::from_bits_truncate(data.edx), + } + } + + /// SVM revision number. + pub fn revision(&self) -> u8 { + get_bits(self.eax, 0, 7) as u8 + } + + /// Number of available address space identifiers (ASID). + pub fn supported_asids(&self) -> u32 { + self.ebx + } + + /// Nested paging supported if set. + pub fn has_nested_paging(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::NP) + } + + /// Indicates support for LBR Virtualization. + pub fn has_lbr_virtualization(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::LBR_VIRT) + } + + /// Indicates support for SVM-Lock if set. + pub fn has_svm_lock(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::SVML) + } + + /// Indicates support for NRIP save on #VMEXIT if set. + pub fn has_nrip(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::NRIPS) + } + + /// Indicates support for MSR TSC ratio (MSR `0xC000_0104`) if set. + pub fn has_tsc_rate_msr(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::TSC_RATE_MSR) + } + + /// Indicates support for VMCB clean bits if set. + pub fn has_vmcb_clean_bits(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::VMCB_CLEAN) + } + + /// Indicates that TLB flush events, including CR3 writes and CR4.PGE toggles, flush + /// only the current ASID's TLB entries. + /// + /// Also indicates support for the extended VMCB TLB_Control. + pub fn has_flush_by_asid(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::FLUSH_BY_ASID) + } + + /// Indicates support for the decode assists if set. + pub fn has_decode_assists(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::DECODE_ASSISTS) + } + + /// Indicates support for the pause intercept filter if set. + pub fn has_pause_filter(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::PAUSE_FILTER) + } + + /// Indicates support for the PAUSE filter cycle count threshold if set. + pub fn has_pause_filter_threshold(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::PAUSE_FILTER_THRESHOLD) + } + + /// Support for the AMD advanced virtual interrupt controller if set. + pub fn has_avic(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::AVIC) + } + + /// VMSAVE and VMLOAD virtualization supported if set. + pub fn has_vmsave_virtualization(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::VMSAVE_VIRT) + } + + /// GIF -- virtualized global interrupt flag if set. + pub fn has_gif(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::VGIF) + } + + /// Guest Mode Execution Trap supported if set. + pub fn has_gmet(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::GMET) + } + + /// SVM supervisor shadow stack restrictions if set. + pub fn has_sss_check(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::SSS_CHECK) + } + + /// SPEC_CTRL virtualization supported if set. + pub fn has_spec_ctrl(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::SPEC_CTRL) + } + + /// When host `CR4.MCE=1` and guest `CR4.MCE=0`, machine check exceptions (`#MC`) in a + /// guest do not cause shutdown and are always intercepted if set. + pub fn has_host_mce_override(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::HOST_MCE_OVERRIDE) + } + + /// Support for INVLPGB/TLBSYNC hypervisor enable in VMCB and TLBSYNC intercept if + /// set. + pub fn has_tlb_ctrl(&self) -> bool { + self.edx.contains(SvmFeaturesEdx::TLB_CTL) + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct SvmFeaturesEdx: u32 { + const NP = 1 << 0; + const LBR_VIRT = 1 << 1; + const SVML = 1 << 2; + const NRIPS = 1 << 3; + const TSC_RATE_MSR = 1 << 4; + const VMCB_CLEAN = 1 << 5; + const FLUSH_BY_ASID = 1 << 6; + const DECODE_ASSISTS = 1 << 7; + const PAUSE_FILTER = 1 << 10; + const PAUSE_FILTER_THRESHOLD = 1 << 12; + const AVIC = 1 << 13; + const VMSAVE_VIRT = 1 << 15; + const VGIF = 1 << 16; + const GMET = 1 << 17; + const SSS_CHECK = 1 << 19; + const SPEC_CTRL = 1 << 20; + const HOST_MCE_OVERRIDE = 1 << 23; + const TLB_CTL = 1 << 24; + } +} + +/// TLB 1-GiB Pages Information (LEAF=0x8000_0019). +/// +/// # Platforms +/// ✅ AMD ⌠Intel +#[derive(PartialEq, Eq, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct Tlb1gbPageInfo { + eax: u32, + ebx: u32, + /// Reserved + _ecx: u32, + /// Reserved + _edx: u32, +} + +impl Tlb1gbPageInfo { + pub(crate) fn new(data: CpuIdResult) -> Self { + Self { + eax: data.eax, + ebx: data.ebx, + _ecx: data.ecx, + _edx: data.edx, + } + } + + /// L1 Data TLB associativity for 1-GB pages. + pub fn dtlb_l1_1gb_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.eax, 28, 31) as u8; + Associativity::for_l2(assoc_bits) + } + + /// L1 Data TLB number of entries for 1-GB pages. + pub fn dtlb_l1_1gb_size(&self) -> u8 { + get_bits(self.eax, 16, 27) as u8 + } + + /// L1 Instruction TLB associativity for 1-GB pages. + pub fn itlb_l1_1gb_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.eax, 12, 15) as u8; + Associativity::for_l2(assoc_bits) + } + + /// L1 Instruction TLB number of entries for 1-GB pages. + pub fn itlb_l1_1gb_size(&self) -> u8 { + get_bits(self.eax, 0, 11) as u8 + } + + /// L2 Data TLB associativity for 1-GB pages. + pub fn dtlb_l2_1gb_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.ebx, 28, 31) as u8; + Associativity::for_l2(assoc_bits) + } + + /// L2 Data TLB number of entries for 1-GB pages. + pub fn dtlb_l2_1gb_size(&self) -> u8 { + get_bits(self.ebx, 16, 27) as u8 + } + + /// L2 Instruction TLB associativity for 1-GB pages. + pub fn itlb_l2_1gb_associativity(&self) -> Associativity { + let assoc_bits = get_bits(self.ebx, 12, 15) as u8; + Associativity::for_l2(assoc_bits) + } + + /// L2 Instruction TLB number of entries for 1-GB pages. + pub fn itlb_l2_1gb_size(&self) -> u8 { + get_bits(self.ebx, 0, 11) as u8 + } +} + +/// Performance Optimization Identifier (LEAF=0x8000_001A). +/// +/// # Platforms +/// ✅ AMD ⌠Intel +#[derive(PartialEq, Eq, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct PerformanceOptimizationInfo { + eax: PerformanceOptimizationInfoEax, + /// Reserved + _ebx: u32, + /// Reserved + _ecx: u32, + /// Reserved + _edx: u32, +} + +impl PerformanceOptimizationInfo { + pub(crate) fn new(data: CpuIdResult) -> Self { + Self { + eax: PerformanceOptimizationInfoEax::from_bits_truncate(data.eax), + _ebx: data.ebx, + _ecx: data.ecx, + _edx: data.edx, + } + } + + /// The internal FP/SIMD execution datapath is 128 bits wide if set. + pub fn has_fp128(&self) -> bool { + self.eax.contains(PerformanceOptimizationInfoEax::FP128) + } + + /// MOVU (Move Unaligned) SSE instructions are efficient more than + /// MOVL/MOVH SSE if set. + pub fn has_movu(&self) -> bool { + self.eax.contains(PerformanceOptimizationInfoEax::MOVU) + } + + /// The internal FP/SIMD execution datapath is 256 bits wide if set. + pub fn has_fp256(&self) -> bool { + self.eax.contains(PerformanceOptimizationInfoEax::FP256) + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct PerformanceOptimizationInfoEax: u32 { + const FP128 = 1 << 0; + const MOVU = 1 << 1; + const FP256 = 1 << 2; + } +} + +/// Processor Topology Information (LEAF=0x8000_001E). +/// +/// # Platforms +/// ✅ AMD ⌠Intel +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ProcessorTopologyInfo { + eax: u32, + ebx: u32, + ecx: u32, + /// Reserved + _edx: u32, +} + +impl ProcessorTopologyInfo { + pub(crate) fn new(data: CpuIdResult) -> Self { + Self { + eax: data.eax, + ebx: data.ebx, + ecx: data.ecx, + _edx: data.edx, + } + } + + /// x2APIC ID + pub fn x2apic_id(&self) -> u32 { + self.eax + } + + /// Core ID + /// + /// # Note + /// `Core ID` means `Compute Unit ID` if AMD Family 15h-16h Processors. + pub fn core_id(&self) -> u8 { + get_bits(self.ebx, 0, 7) as u8 + } + + /// Threads per core + /// + /// # Note + /// `Threads per Core` means `Cores per Compute Unit` if AMD Family 15h-16h Processors. + pub fn threads_per_core(&self) -> u8 { + get_bits(self.ebx, 8, 15) as u8 + 1 + } + + /// Node ID + pub fn node_id(&self) -> u8 { + get_bits(self.ecx, 0, 7) as u8 + } + + /// Nodes per processor + pub fn nodes_per_processor(&self) -> u8 { + get_bits(self.ecx, 8, 10) as u8 + 1 + } +} + +impl Debug for ProcessorTopologyInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("ProcessorTopologyInfo") + .field("x2apic_id", &self.x2apic_id()) + .field("core_id", &self.core_id()) + .field("threads_per_core", &self.threads_per_core()) + .field("node_id", &self.node_id()) + .field("nodes_per_processor", &self.nodes_per_processor()) + .finish() + } +} + +/// Encrypted Memory Capabilities (LEAF=0x8000_001F). +/// +/// # Platforms +/// ✅ AMD ⌠Intel +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct MemoryEncryptionInfo { + eax: MemoryEncryptionInfoEax, + ebx: u32, + ecx: u32, + edx: u32, +} + +impl MemoryEncryptionInfo { + pub(crate) fn new(data: CpuIdResult) -> Self { + Self { + eax: MemoryEncryptionInfoEax::from_bits_truncate(data.eax), + ebx: data.ebx, + ecx: data.ecx, + edx: data.edx, + } + } + + /// Secure Memory Encryption is supported if set. + pub fn has_sme(&self) -> bool { + self.eax.contains(MemoryEncryptionInfoEax::SME) + } + + /// Secure Encrypted Virtualization is supported if set. + pub fn has_sev(&self) -> bool { + self.eax.contains(MemoryEncryptionInfoEax::SEV) + } + + /// The Page Flush MSR is available if set. + pub fn has_page_flush_msr(&self) -> bool { + self.eax.contains(MemoryEncryptionInfoEax::PAGE_FLUSH_MSR) + } + + /// SEV Encrypted State is supported if set. + pub fn has_sev_es(&self) -> bool { + self.eax.contains(MemoryEncryptionInfoEax::SEV_ES) + } + + /// SEV Secure Nested Paging supported if set. + pub fn has_sev_snp(&self) -> bool { + self.eax.contains(MemoryEncryptionInfoEax::SEV_SNP) + } + + /// VM Permission Levels supported if set. + pub fn has_vmpl(&self) -> bool { + self.eax.contains(MemoryEncryptionInfoEax::VMPL) + } + + /// Hardware cache coherency across encryption domains enforced if set. + pub fn has_hw_enforced_cache_coh(&self) -> bool { + self.eax.contains(MemoryEncryptionInfoEax::HWENFCACHECOH) + } + + /// SEV guest execution only allowed from a 64-bit host if set. + pub fn has_64bit_mode(&self) -> bool { + self.eax.contains(MemoryEncryptionInfoEax::HOST64) + } + + /// Restricted Injection supported if set. + pub fn has_restricted_injection(&self) -> bool { + self.eax.contains(MemoryEncryptionInfoEax::RESTINJECT) + } + + /// Alternate Injection supported if set. + pub fn has_alternate_injection(&self) -> bool { + self.eax.contains(MemoryEncryptionInfoEax::ALTINJECT) + } + + /// Full debug state swap supported for SEV-ES guests. + pub fn has_debug_swap(&self) -> bool { + self.eax.contains(MemoryEncryptionInfoEax::DBGSWP) + } + + /// Disallowing IBS use by the host supported if set. + pub fn has_prevent_host_ibs(&self) -> bool { + self.eax.contains(MemoryEncryptionInfoEax::PREVHOSTIBS) + } + + /// Virtual Transparent Encryption supported if set. + pub fn has_vte(&self) -> bool { + self.eax.contains(MemoryEncryptionInfoEax::VTE) + } + + /// C-bit location in page table entry + pub fn c_bit_position(&self) -> u8 { + get_bits(self.ebx, 0, 5) as u8 + } + + /// Physical Address bit reduction + pub fn physical_address_reduction(&self) -> u8 { + get_bits(self.ebx, 6, 11) as u8 + } + + /// Number of encrypted guests supported simultaneouslys + pub fn max_encrypted_guests(&self) -> u32 { + self.ecx + } + + /// Minimum ASID value for an SEV enabled, SEV-ES disabled guest + pub fn min_sev_no_es_asid(&self) -> u32 { + self.edx + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct MemoryEncryptionInfoEax: u32 { + const SME = 1 << 0; + const SEV = 1 << 1; + const PAGE_FLUSH_MSR = 1 << 2; + const SEV_ES = 1 << 3; + const SEV_SNP = 1 << 4; + const VMPL = 1 << 5; + const HWENFCACHECOH = 1 << 10; + const HOST64 = 1 << 11; + const RESTINJECT = 1 << 12; + const ALTINJECT = 1 << 13; + const DBGSWP = 1 << 14; + const PREVHOSTIBS = 1 << 15; + const VTE = 1 << 16; + } +} diff --git a/vendor/raw-cpuid-10.7.0/src/lib.rs b/vendor/raw-cpuid-10.7.0/src/lib.rs new file mode 100644 index 0000000000000..bfd0b2847c668 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/src/lib.rs @@ -0,0 +1,5663 @@ +//! A library to parse the x86 CPUID instruction, written in rust with no +//! external dependencies. The implementation closely resembles the Intel CPUID +//! manual description. The library works with no_std. +//! +//! ## Example +//! ```rust +//! use raw_cpuid::CpuId; +//! let cpuid = CpuId::new(); +//! +//! if let Some(vf) = cpuid.get_vendor_info() { +//! assert!(vf.as_str() == "GenuineIntel" || vf.as_str() == "AuthenticAMD"); +//! } +//! +//! let has_sse = cpuid.get_feature_info().map_or(false, |finfo| finfo.has_sse()); +//! if has_sse { +//! println!("CPU supports SSE!"); +//! } +//! +//! if let Some(cparams) = cpuid.get_cache_parameters() { +//! for cache in cparams { +//! let size = cache.associativity() * cache.physical_line_partitions() * cache.coherency_line_size() * cache.sets(); +//! println!("L{}-Cache size is {}", cache.level(), size); +//! } +//! } else { +//! println!("No cache parameter information available") +//! } +//! ``` +//! +//! # Platform support +//! +//! CPU vendors may choose to not support certain functions/leafs in cpuid or +//! only support them partially. We highlight this with the following emojis +//! throughout the documentation: +//! +//! - ✅: This struct/function is fully supported by the vendor. +//! - 🟡: This struct is partially supported by the vendor, refer to individual +//! functions for more information. +//! - âŒ: This struct/function is not supported by the vendor. When queried on +//! this platform, we will return None/false/0 (or some other sane default). +//! - â“: This struct/function is not supported by the vendor according to the +//! manual, but the in practice it still may return valid information. +//! +//! Note that the presence of a ✅ does not guarantee that a specific feature +//! will exist for your CPU -- just that it is potentially supported by the +//! vendor on some of its chips. You will still have to query it at runtime. + +#![cfg_attr(not(feature = "std"), no_std)] +#![crate_name = "raw_cpuid"] +#![crate_type = "lib"] + +#[cfg(test)] +#[macro_use] +extern crate std; + +#[cfg(feature = "display")] +pub mod display; +mod extended; +#[cfg(test)] +mod tests; +#[cfg(feature = "serialize")] +#[macro_use] +extern crate serde_derive; + +#[cfg(feature = "serialize")] +extern crate serde; + +#[macro_use] +extern crate bitflags; + +#[cfg(all( + feature = "serialize", + not(any( + all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"), + all(target_arch = "x86_64", not(target_env = "sgx")) + )) +))] +core::compile_error!("Feature `serialize` is not supported on targets that do not have native cpuid. x86 and x86_64 targets with SGX and x86 targets without SSE are consider to not have native cpuid."); + +/// Uses Rust's `cpuid` function from the `arch` module. +#[cfg(any( + all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"), + all(target_arch = "x86_64", not(target_env = "sgx")) +))] +pub mod native_cpuid { + use crate::CpuIdResult; + + #[cfg(all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"))] + use core::arch::x86 as arch; + #[cfg(all(target_arch = "x86_64", not(target_env = "sgx")))] + use core::arch::x86_64 as arch; + + pub fn cpuid_count(a: u32, c: u32) -> CpuIdResult { + // Safety: CPUID is supported on all x86_64 CPUs and all x86 CPUs with + // SSE, but not by SGX. + let result = unsafe { self::arch::__cpuid_count(a, c) }; + + CpuIdResult { + eax: result.eax, + ebx: result.ebx, + ecx: result.ecx, + edx: result.edx, + } + } +} + +use core::fmt::{self, Debug, Formatter}; +use core::mem::size_of; +use core::slice; +use core::str; + +pub use extended::*; + +#[cfg(not(test))] +mod std { + pub use core::ops; + pub use core::option; +} + +/// Macro which queries cpuid directly. +/// +/// First parameter is cpuid leaf (EAX register value), +/// second optional parameter is the subleaf (ECX register value). +#[cfg(any( + all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"), + all(target_arch = "x86_64", not(target_env = "sgx")) +))] +#[macro_export] +macro_rules! cpuid { + ($eax:expr) => { + $crate::native_cpuid::cpuid_count($eax as u32, 0) + }; + + ($eax:expr, $ecx:expr) => { + $crate::native_cpuid::cpuid_count($eax as u32, $ecx as u32) + }; +} + +fn get_bits(r: u32, from: u32, to: u32) -> u32 { + assert!(from <= 31); + assert!(to <= 31); + assert!(from <= to); + + let mask = match to { + 31 => 0xffffffff, + _ => (1 << (to + 1)) - 1, + }; + + (r & mask) >> from +} + +macro_rules! check_flag { + ($doc:meta, $fun:ident, $flags:ident, $flag:expr) => { + #[$doc] + pub fn $fun(&self) -> bool { + self.$flags.contains($flag) + } + }; +} + +macro_rules! is_bit_set { + ($field:expr, $bit:expr) => { + $field & (1 << $bit) > 0 + }; +} + +macro_rules! check_bit_fn { + ($doc:meta, $fun:ident, $field:ident, $bit:expr) => { + #[$doc] + pub fn $fun(&self) -> bool { + is_bit_set!(self.$field, $bit) + } + }; +} + +/// Implements function to read/write cpuid. +/// This allows to conveniently swap out the underlying cpuid implementation +/// with one that returns data that is deterministic (for unit-testing). +#[derive(Debug, Clone, Copy)] +struct CpuIdReader { + cpuid_fn: fn(u32, u32) -> CpuIdResult, +} + +impl CpuIdReader { + fn new(cpuid_fn: fn(u32, u32) -> CpuIdResult) -> Self { + Self { cpuid_fn } + } + + fn cpuid1(&self, eax: u32) -> CpuIdResult { + (self.cpuid_fn)(eax, 0) + } + + fn cpuid2(&self, eax: u32, ecx: u32) -> CpuIdResult { + (self.cpuid_fn)(eax, ecx) + } +} + +#[cfg(any( + all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"), + all(target_arch = "x86_64", not(target_env = "sgx")) +))] +impl Default for CpuIdReader { + fn default() -> Self { + Self { + cpuid_fn: native_cpuid::cpuid_count, + } + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +enum Vendor { + Intel, + Amd, + Unknown(u32, u32, u32), +} + +impl Vendor { + fn from_vendor_leaf(res: CpuIdResult) -> Self { + let vi = VendorInfo { + ebx: res.ebx, + ecx: res.ecx, + edx: res.edx, + }; + + match vi.as_str() { + "GenuineIntel" => Vendor::Intel, + "AuthenticAMD" => Vendor::Amd, + _ => Vendor::Unknown(res.ebx, res.ecx, res.edx), + } + } +} + +/// The main type used to query information about the CPU we're running on. +/// +/// Other structs can be accessed by going through this type. +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[derive(Clone, Copy)] +pub struct CpuId { + #[cfg_attr(feature = "serialize", serde(skip))] + read: CpuIdReader, + /// CPU vendor to differntiate cases where logic needs to differ in code . + vendor: Vendor, + /// How many basic leafs are supported (EAX < EAX_HYPERVISOR_INFO) + supported_leafs: u32, + /// How many extended leafs are supported (e.g., leafs with EAX > EAX_EXTENDED_FUNCTION_INFO) + supported_extended_leafs: u32, +} + +#[cfg(any( + all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"), + all(target_arch = "x86_64", not(target_env = "sgx")) +))] +impl Default for CpuId { + fn default() -> CpuId { + CpuId::with_cpuid_fn(native_cpuid::cpuid_count) + } +} + +/// Low-level data-structure to store result of cpuid instruction. +#[derive(Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[repr(C)] +pub struct CpuIdResult { + /// Return value EAX register + pub eax: u32, + /// Return value EBX register + pub ebx: u32, + /// Return value ECX register + pub ecx: u32, + /// Return value EDX register + pub edx: u32, +} + +impl CpuIdResult { + pub fn all_zero(&self) -> bool { + self.eax == 0 && self.ebx == 0 && self.ecx == 0 && self.edx == 0 + } +} + +impl Debug for CpuIdResult { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("CpuIdResult") + .field("eax", &(self.eax as *const u32)) + .field("ebx", &(self.ebx as *const u32)) + .field("ecx", &(self.ecx as *const u32)) + .field("edx", &(self.edx as *const u32)) + .finish() + } +} + +// +// Normal leafs: +// +const EAX_VENDOR_INFO: u32 = 0x0; +const EAX_FEATURE_INFO: u32 = 0x1; +const EAX_CACHE_INFO: u32 = 0x2; +const EAX_PROCESSOR_SERIAL: u32 = 0x3; +const EAX_CACHE_PARAMETERS: u32 = 0x4; +const EAX_MONITOR_MWAIT_INFO: u32 = 0x5; +const EAX_THERMAL_POWER_INFO: u32 = 0x6; +const EAX_STRUCTURED_EXTENDED_FEATURE_INFO: u32 = 0x7; +const EAX_DIRECT_CACHE_ACCESS_INFO: u32 = 0x9; +const EAX_PERFORMANCE_MONITOR_INFO: u32 = 0xA; +const EAX_EXTENDED_TOPOLOGY_INFO: u32 = 0xB; +const EAX_EXTENDED_STATE_INFO: u32 = 0xD; +const EAX_RDT_MONITORING: u32 = 0xF; +const EAX_RDT_ALLOCATION: u32 = 0x10; +const EAX_SGX: u32 = 0x12; +const EAX_TRACE_INFO: u32 = 0x14; +const EAX_TIME_STAMP_COUNTER_INFO: u32 = 0x15; +const EAX_FREQUENCY_INFO: u32 = 0x16; +const EAX_SOC_VENDOR_INFO: u32 = 0x17; +const EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO: u32 = 0x18; +const EAX_EXTENDED_TOPOLOGY_INFO_V2: u32 = 0x1F; + +/// Hypervisor leaf +const EAX_HYPERVISOR_INFO: u32 = 0x4000_0000; + +// +// Extended leafs: +// +const EAX_EXTENDED_FUNCTION_INFO: u32 = 0x8000_0000; +const EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS: u32 = 0x8000_0001; +const EAX_EXTENDED_BRAND_STRING: u32 = 0x8000_0002; +const EAX_L1_CACHE_INFO: u32 = 0x8000_0005; +const EAX_L2_L3_CACHE_INFO: u32 = 0x8000_0006; +const EAX_ADVANCED_POWER_MGMT_INFO: u32 = 0x8000_0007; +const EAX_PROCESSOR_CAPACITY_INFO: u32 = 0x8000_0008; +const EAX_TLB_1GB_PAGE_INFO: u32 = 0x8000_0019; +const EAX_PERFORMANCE_OPTIMIZATION_INFO: u32 = 0x8000_001A; +const EAX_CACHE_PARAMETERS_AMD: u32 = 0x8000_001D; +const EAX_PROCESSOR_TOPOLOGY_INFO: u32 = 0x8000_001E; +const EAX_MEMORY_ENCRYPTION_INFO: u32 = 0x8000_001F; +const EAX_SVM_FEATURES: u32 = 0x8000_000A; + +impl CpuId { + /// Return new CpuId struct. + #[cfg(any( + all(target_arch = "x86", not(target_env = "sgx"), target_feature = "sse"), + all(target_arch = "x86_64", not(target_env = "sgx")) + ))] + pub fn new() -> Self { + Self::default() + } + + /// Return new CpuId struct with custom reader function. + /// + /// This is useful for example when testing code or if we want to interpose + /// on the CPUID calls this library makes. + pub fn with_cpuid_fn(cpuid_fn: fn(u32, u32) -> CpuIdResult) -> Self { + let read = CpuIdReader::new(cpuid_fn); + let vendor_leaf = read.cpuid1(EAX_VENDOR_INFO); + let extended_leaf = read.cpuid1(EAX_EXTENDED_FUNCTION_INFO); + CpuId { + supported_leafs: vendor_leaf.eax, + supported_extended_leafs: extended_leaf.eax, + vendor: Vendor::from_vendor_leaf(vendor_leaf), + read, + } + } + + /// Check if a non extended leaf (`val`) is supported. + fn leaf_is_supported(&self, val: u32) -> bool { + // Exclude reserved functions/leafs on AMD + if self.vendor == Vendor::Amd && ((0x2..=0x4).contains(&val) || (0x8..=0xa).contains(&val)) + { + return false; + } + + if val < EAX_EXTENDED_FUNCTION_INFO { + val <= self.supported_leafs + } else { + val <= self.supported_extended_leafs + } + } + + /// Return information about the vendor (LEAF=0x00). + /// + /// This leaf will contain a ASCII readable string such as "GenuineIntel" + /// for Intel CPUs or "AuthenticAMD" for AMD CPUs. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn get_vendor_info(&self) -> Option { + if self.leaf_is_supported(EAX_VENDOR_INFO) { + let res = self.read.cpuid1(EAX_VENDOR_INFO); + Some(VendorInfo { + ebx: res.ebx, + ecx: res.ecx, + edx: res.edx, + }) + } else { + None + } + } + + /// Query a set of features that are available on this CPU (LEAF=0x01). + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn get_feature_info(&self) -> Option { + if self.leaf_is_supported(EAX_FEATURE_INFO) { + let res = self.read.cpuid1(EAX_FEATURE_INFO); + Some(FeatureInfo { + vendor: self.vendor, + eax: res.eax, + ebx: res.ebx, + edx_ecx: FeatureInfoFlags { + bits: (((res.edx as u64) << 32) | (res.ecx as u64)), + }, + }) + } else { + None + } + } + + /// Query basic information about caches (LEAF=0x02). + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn get_cache_info(&self) -> Option { + if self.leaf_is_supported(EAX_CACHE_INFO) { + let res = self.read.cpuid1(EAX_CACHE_INFO); + Some(CacheInfoIter { + current: 1, + eax: res.eax, + ebx: res.ebx, + ecx: res.ecx, + edx: res.edx, + }) + } else { + None + } + } + + /// Retrieve serial number of processor (LEAF=0x03). + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn get_processor_serial(&self) -> Option { + if self.leaf_is_supported(EAX_PROCESSOR_SERIAL) { + // upper 64-96 bits are in res1.eax: + let res1 = self.read.cpuid1(EAX_FEATURE_INFO); + let res = self.read.cpuid1(EAX_PROCESSOR_SERIAL); + Some(ProcessorSerial { + ecx: res.ecx, + edx: res.edx, + eax: res1.eax, + }) + } else { + None + } + } + + /// Retrieve more elaborate information about caches (LEAF=0x04 or 0x8000_001D). + /// + /// As opposed to [get_cache_info](CpuId::get_cache_info), this will tell us + /// about associativity, set size, line size of each level in the cache + /// hierarchy. + /// + /// # Platforms + /// 🟡 AMD ✅ Intel + pub fn get_cache_parameters(&self) -> Option { + if self.leaf_is_supported(EAX_CACHE_PARAMETERS) + || (self.vendor == Vendor::Amd && self.leaf_is_supported(EAX_CACHE_PARAMETERS_AMD)) + { + Some(CacheParametersIter { + read: self.read, + leaf: if self.vendor == Vendor::Amd { + EAX_CACHE_PARAMETERS_AMD + } else { + EAX_CACHE_PARAMETERS + }, + current: 0, + }) + } else { + None + } + } + + /// Information about how monitor/mwait works on this CPU (LEAF=0x05). + /// + /// # Platforms + /// 🟡 AMD ✅ Intel + pub fn get_monitor_mwait_info(&self) -> Option { + if self.leaf_is_supported(EAX_MONITOR_MWAIT_INFO) { + let res = self.read.cpuid1(EAX_MONITOR_MWAIT_INFO); + Some(MonitorMwaitInfo { + eax: res.eax, + ebx: res.ebx, + ecx: res.ecx, + edx: res.edx, + }) + } else { + None + } + } + + /// Query information about thermal and power management features of the CPU (LEAF=0x06). + /// + /// # Platforms + /// 🟡 AMD ✅ Intel + pub fn get_thermal_power_info(&self) -> Option { + if self.leaf_is_supported(EAX_THERMAL_POWER_INFO) { + let res = self.read.cpuid1(EAX_THERMAL_POWER_INFO); + Some(ThermalPowerInfo { + eax: ThermalPowerFeaturesEax { bits: res.eax }, + ebx: res.ebx, + ecx: ThermalPowerFeaturesEcx { bits: res.ecx }, + _edx: res.edx, + }) + } else { + None + } + } + + /// Find out about more features supported by this CPU (LEAF=0x07). + /// + /// # Platforms + /// 🟡 AMD ✅ Intel + pub fn get_extended_feature_info(&self) -> Option { + if self.leaf_is_supported(EAX_STRUCTURED_EXTENDED_FEATURE_INFO) { + let res = self.read.cpuid1(EAX_STRUCTURED_EXTENDED_FEATURE_INFO); + Some(ExtendedFeatures { + _eax: res.eax, + ebx: ExtendedFeaturesEbx { bits: res.ebx }, + ecx: ExtendedFeaturesEcx { bits: res.ecx }, + _edx: res.edx, + }) + } else { + None + } + } + + /// Direct cache access info (LEAF=0x09). + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn get_direct_cache_access_info(&self) -> Option { + if self.leaf_is_supported(EAX_DIRECT_CACHE_ACCESS_INFO) { + let res = self.read.cpuid1(EAX_DIRECT_CACHE_ACCESS_INFO); + Some(DirectCacheAccessInfo { eax: res.eax }) + } else { + None + } + } + + /// Info about performance monitoring (LEAF=0x0A). + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn get_performance_monitoring_info(&self) -> Option { + if self.leaf_is_supported(EAX_PERFORMANCE_MONITOR_INFO) { + let res = self.read.cpuid1(EAX_PERFORMANCE_MONITOR_INFO); + Some(PerformanceMonitoringInfo { + eax: res.eax, + ebx: PerformanceMonitoringFeaturesEbx { bits: res.ebx }, + _ecx: res.ecx, + edx: res.edx, + }) + } else { + None + } + } + + /// Information about topology (LEAF=0x0B). + /// + /// Intel SDM suggests software should check support for leaf 0x1F + /// ([`CpuId::get_extended_topology_info_v2`]), and if supported, enumerate + /// that leaf instead. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn get_extended_topology_info(&self) -> Option { + if self.leaf_is_supported(EAX_EXTENDED_TOPOLOGY_INFO) { + Some(ExtendedTopologyIter { + read: self.read, + level: 0, + is_v2: false, + }) + } else { + None + } + } + + /// Extended information about topology (LEAF=0x1F). + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn get_extended_topology_info_v2(&self) -> Option { + if self.leaf_is_supported(EAX_EXTENDED_TOPOLOGY_INFO_V2) { + Some(ExtendedTopologyIter { + read: self.read, + level: 0, + is_v2: true, + }) + } else { + None + } + } + + /// Information for saving/restoring extended register state (LEAF=0x0D). + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn get_extended_state_info(&self) -> Option { + if self.leaf_is_supported(EAX_EXTENDED_STATE_INFO) { + let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, 0); + let res1 = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, 1); + Some(ExtendedStateInfo { + read: self.read, + eax: ExtendedStateInfoXCR0Flags { bits: res.eax }, + ebx: res.ebx, + ecx: res.ecx, + _edx: res.edx, + eax1: res1.eax, + ebx1: res1.ebx, + ecx1: ExtendedStateInfoXSSFlags { bits: res1.ecx }, + _edx1: res1.edx, + }) + } else { + None + } + } + + /// Quality of service monitoring information (LEAF=0x0F). + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn get_rdt_monitoring_info(&self) -> Option { + let res = self.read.cpuid1(EAX_RDT_MONITORING); + + if self.leaf_is_supported(EAX_RDT_MONITORING) { + Some(RdtMonitoringInfo { + read: self.read, + ebx: res.ebx, + edx: res.edx, + }) + } else { + None + } + } + + /// Quality of service enforcement information (LEAF=0x10). + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn get_rdt_allocation_info(&self) -> Option { + let res = self.read.cpuid1(EAX_RDT_ALLOCATION); + + if self.leaf_is_supported(EAX_RDT_ALLOCATION) { + Some(RdtAllocationInfo { + read: self.read, + ebx: res.ebx, + }) + } else { + None + } + } + + /// Information about secure enclave support (LEAF=0x12). + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn get_sgx_info(&self) -> Option { + // Leaf 12H sub-leaf 0 (ECX = 0) is supported if CPUID.(EAX=07H, ECX=0H):EBX[SGX] = 1. + self.get_extended_feature_info().and_then(|info| { + if self.leaf_is_supported(EAX_SGX) && info.has_sgx() { + let res = self.read.cpuid2(EAX_SGX, 0); + let res1 = self.read.cpuid2(EAX_SGX, 1); + Some(SgxInfo { + read: self.read, + eax: res.eax, + ebx: res.ebx, + _ecx: res.ecx, + edx: res.edx, + eax1: res1.eax, + ebx1: res1.ebx, + ecx1: res1.ecx, + edx1: res1.edx, + }) + } else { + None + } + }) + } + + /// Intel Processor Trace Enumeration Information (LEAF=0x14). + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn get_processor_trace_info(&self) -> Option { + if self.leaf_is_supported(EAX_TRACE_INFO) { + let res = self.read.cpuid2(EAX_TRACE_INFO, 0); + let res1 = if res.eax >= 1 { + Some(self.read.cpuid2(EAX_TRACE_INFO, 1)) + } else { + None + }; + + Some(ProcessorTraceInfo { + _eax: res.eax, + ebx: res.ebx, + ecx: res.ecx, + _edx: res.edx, + leaf1: res1, + }) + } else { + None + } + } + + /// Time Stamp Counter/Core Crystal Clock Information (LEAF=0x15). + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn get_tsc_info(&self) -> Option { + if self.leaf_is_supported(EAX_TIME_STAMP_COUNTER_INFO) { + let res = self.read.cpuid2(EAX_TIME_STAMP_COUNTER_INFO, 0); + Some(TscInfo { + eax: res.eax, + ebx: res.ebx, + ecx: res.ecx, + }) + } else { + None + } + } + + /// Processor Frequency Information (LEAF=0x16). + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn get_processor_frequency_info(&self) -> Option { + if self.leaf_is_supported(EAX_FREQUENCY_INFO) { + let res = self.read.cpuid1(EAX_FREQUENCY_INFO); + Some(ProcessorFrequencyInfo { + eax: res.eax, + ebx: res.ebx, + ecx: res.ecx, + }) + } else { + None + } + } + + /// Contains SoC vendor specific information (LEAF=0x17). + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn get_soc_vendor_info(&self) -> Option { + if self.leaf_is_supported(EAX_SOC_VENDOR_INFO) { + let res = self.read.cpuid1(EAX_SOC_VENDOR_INFO); + Some(SoCVendorInfo { + read: self.read, + eax: res.eax, + ebx: res.ebx, + ecx: res.ecx, + edx: res.edx, + }) + } else { + None + } + } + + /// Query deterministic address translation feature (LEAF=0x18). + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn get_deterministic_address_translation_info(&self) -> Option { + if self.leaf_is_supported(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO) { + let res = self + .read + .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, 0); + Some(DatIter { + read: self.read, + current: 0, + count: res.eax, + }) + } else { + None + } + } + + /// Returns information provided by the hypervisor, if running + /// in a virtual environment (LEAF=0x4000_00xx). + /// + /// # Platform + /// Needs to be a virtual CPU to be supported. + pub fn get_hypervisor_info(&self) -> Option { + // We only fetch HypervisorInfo, if the Hypervisor-Flag is set. + // See https://github.com/gz/rust-cpuid/issues/52 + self.get_feature_info() + .filter(|fi| fi.has_hypervisor()) + .map(|_| { + let res = self.read.cpuid1(EAX_HYPERVISOR_INFO); + if res.eax > 0 { + Some(HypervisorInfo { + read: self.read, + res, + }) + } else { + None + } + }) + .flatten() + } + + /// Extended Processor and Processor Feature Identifiers (LEAF=0x8000_0001). + /// + /// # Platforms + /// ✅ AMD 🟡 Intel + pub fn get_extended_processor_and_feature_identifiers( + &self, + ) -> Option { + if self.leaf_is_supported(EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS) { + Some(ExtendedProcessorFeatureIdentifiers::new( + self.vendor, + self.read + .cpuid1(EAX_EXTENDED_PROCESSOR_AND_FEATURE_IDENTIFIERS), + )) + } else { + None + } + } + + /// Retrieve processor brand string (LEAF=0x8000_000{2..4}). + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn get_processor_brand_string(&self) -> Option { + if self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING) + && self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING + 1) + && self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING + 2) + { + Some(ProcessorBrandString::new([ + self.read.cpuid1(EAX_EXTENDED_BRAND_STRING), + self.read.cpuid1(EAX_EXTENDED_BRAND_STRING + 1), + self.read.cpuid1(EAX_EXTENDED_BRAND_STRING + 2), + ])) + } else { + None + } + } + + /// L1 Instruction Cache Information (LEAF=0x8000_0005) + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved) + pub fn get_l1_cache_and_tlb_info(&self) -> Option { + if self.vendor == Vendor::Amd && self.leaf_is_supported(EAX_L1_CACHE_INFO) { + Some(L1CacheTlbInfo::new(self.read.cpuid1(EAX_L1_CACHE_INFO))) + } else { + None + } + } + + /// L2/L3 Cache and TLB Information (LEAF=0x8000_0006). + /// + /// # Platforms + /// ✅ AMD 🟡 Intel + pub fn get_l2_l3_cache_and_tlb_info(&self) -> Option { + if self.leaf_is_supported(EAX_L2_L3_CACHE_INFO) { + Some(L2And3CacheTlbInfo::new( + self.read.cpuid1(EAX_L2_L3_CACHE_INFO), + )) + } else { + None + } + } + + /// Advanced Power Management Information (LEAF=0x8000_0007). + /// + /// # Platforms + /// ✅ AMD 🟡 Intel + pub fn get_advanced_power_mgmt_info(&self) -> Option { + if self.leaf_is_supported(EAX_ADVANCED_POWER_MGMT_INFO) { + Some(ApmInfo::new(self.read.cpuid1(EAX_ADVANCED_POWER_MGMT_INFO))) + } else { + None + } + } + + /// Processor Capacity Parameters and Extended Feature Identification (LEAF=0x8000_0008). + /// + /// # Platforms + /// ✅ AMD 🟡 Intel + pub fn get_processor_capacity_feature_info(&self) -> Option { + if self.leaf_is_supported(EAX_PROCESSOR_CAPACITY_INFO) { + Some(ProcessorCapacityAndFeatureInfo::new( + self.read.cpuid1(EAX_PROCESSOR_CAPACITY_INFO), + )) + } else { + None + } + } + + /// This function provides information about the SVM features that the processory + /// supports. (LEAF=0x8000_000A) + /// + /// If SVM is not supported if [ExtendedProcessorFeatureIdentifiers::has_svm] is + /// false, this function is reserved then. + /// + /// # Platforms + /// ✅ AMD ⌠Intel + pub fn get_svm_info(&self) -> Option { + let has_svm = self + .get_extended_processor_and_feature_identifiers() + .map_or(false, |f| f.has_svm()); + if has_svm && self.leaf_is_supported(EAX_SVM_FEATURES) { + Some(SvmFeatures::new(self.read.cpuid1(EAX_SVM_FEATURES))) + } else { + None + } + } + + /// TLB 1-GiB Pages Information (LEAF=0x8000_0019) + /// + /// # Platforms + /// ✅ AMD ⌠Intel + pub fn get_tlb_1gb_page_info(&self) -> Option { + if self.leaf_is_supported(EAX_TLB_1GB_PAGE_INFO) { + Some(Tlb1gbPageInfo::new(self.read.cpuid1(EAX_TLB_1GB_PAGE_INFO))) + } else { + None + } + } + + /// Informations about performance optimization (LEAF=0x8000_001A) + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved) + pub fn get_performance_optimization_info(&self) -> Option { + if self.leaf_is_supported(EAX_PERFORMANCE_OPTIMIZATION_INFO) { + Some(PerformanceOptimizationInfo::new( + self.read.cpuid1(EAX_PERFORMANCE_OPTIMIZATION_INFO), + )) + } else { + None + } + } + + /// Informations about processor topology (LEAF=0x8000_001E) + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved) + pub fn get_processor_topology_info(&self) -> Option { + if self.leaf_is_supported(EAX_PROCESSOR_TOPOLOGY_INFO) { + Some(ProcessorTopologyInfo::new( + self.read.cpuid1(EAX_PROCESSOR_TOPOLOGY_INFO), + )) + } else { + None + } + } + + /// Informations about memory encryption support (LEAF=0x8000_001F) + /// + /// # Platforms + /// ✅ AMD ⌠Intel (reserved) + pub fn get_memory_encryption_info(&self) -> Option { + if self.leaf_is_supported(EAX_MEMORY_ENCRYPTION_INFO) { + Some(MemoryEncryptionInfo::new( + self.read.cpuid1(EAX_MEMORY_ENCRYPTION_INFO), + )) + } else { + None + } + } +} + +impl Debug for CpuId { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("CpuId") + .field("vendor", &self.vendor) + // .field("supported_leafs", &(self.supported_leafs as *const u32)) + // .field("supported_extended_leafs", &(self.supported_extended_leafs as *const u32)) + .field("vendor_info", &self.get_vendor_info()) + .field("feature_info", &self.get_feature_info()) + .field("cache_info", &self.get_cache_info()) + .field("processor_serial", &self.get_processor_serial()) + .field("cache_parameters", &self.get_cache_parameters()) + .field("monitor_mwait_info", &self.get_monitor_mwait_info()) + .field("thermal_power_info", &self.get_thermal_power_info()) + .field("extended_feature_info", &self.get_extended_feature_info()) + .field( + "direct_cache_access_info", + &self.get_direct_cache_access_info(), + ) + .field( + "performance_monitoring_info", + &self.get_performance_monitoring_info(), + ) + .field("extended_topology_info", &self.get_extended_topology_info()) + .field("extended_state_info", &self.get_extended_state_info()) + .field("rdt_monitoring_info", &self.get_rdt_monitoring_info()) + .field("rdt_allocation_info", &self.get_rdt_allocation_info()) + .field("sgx_info", &self.get_sgx_info()) + .field("processor_trace_info", &self.get_processor_trace_info()) + .field("tsc_info", &self.get_tsc_info()) + .field( + "processor_frequency_info", + &self.get_processor_frequency_info(), + ) + .field( + "deterministic_address_translation_info", + &self.get_deterministic_address_translation_info(), + ) + .field("soc_vendor_info", &self.get_soc_vendor_info()) + .field("hypervisor_info", &self.get_hypervisor_info()) + .field( + "extended_processor_and_feature_identifiers", + &self.get_extended_processor_and_feature_identifiers(), + ) + .field("processor_brand_string", &self.get_processor_brand_string()) + .field("l1_cache_and_tlb_info", &self.get_l1_cache_and_tlb_info()) + .field( + "l2_l3_cache_and_tlb_info", + &self.get_l2_l3_cache_and_tlb_info(), + ) + .field( + "advanced_power_mgmt_info", + &self.get_advanced_power_mgmt_info(), + ) + .field( + "processor_capacity_feature_info", + &self.get_processor_capacity_feature_info(), + ) + .field("svm_info", &self.get_svm_info()) + .field("tlb_1gb_page_info", &self.get_tlb_1gb_page_info()) + .field( + "performance_optimization_info", + &self.get_performance_optimization_info(), + ) + .field( + "processor_topology_info", + &self.get_processor_topology_info(), + ) + .field("memory_encryption_info", &self.get_memory_encryption_info()) + .finish() + } +} + +/// Vendor Info String (LEAF=0x0) +/// +/// A string that can be for example "AuthenticAMD" or "GenuineIntel". +/// +/// # Technical Background +/// +/// The vendor info is a 12-byte (96 bit) long string stored in `ebx`, `edx` and +/// `ecx` by the corresponding `cpuid` instruction. +/// +/// # Platforms +/// ✅ AMD ✅ Intel +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[repr(C)] +pub struct VendorInfo { + ebx: u32, + edx: u32, + ecx: u32, +} + +impl VendorInfo { + /// Return vendor identification as human readable string. + pub fn as_str(&self) -> &str { + let brand_string_start = self as *const VendorInfo as *const u8; + let slice = unsafe { + // Safety: VendorInfo is laid out with repr(C) and exactly + // 12 byte long without any padding. + slice::from_raw_parts(brand_string_start, size_of::()) + }; + + str::from_utf8(slice).unwrap_or("InvalidVendorString") + } + + #[deprecated( + since = "10.0.0", + note = "Use idiomatic function name `as_str` instead" + )] + pub fn as_string(&self) -> &str { + self.as_str() + } +} + +impl Debug for VendorInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("VendorInfo") + .field("brand_string", &self.as_str()) + .finish() + } +} + +impl fmt::Display for VendorInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +/// Iterates over cache information (LEAF=0x02). +/// +/// This will just return an index into a static table of cache descriptions +/// (see [CACHE_INFO_TABLE](crate::CACHE_INFO_TABLE)). +/// +/// # Platforms +/// ⌠AMD ✅ Intel +#[derive(PartialEq, Eq, Clone)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct CacheInfoIter { + current: u32, + eax: u32, + ebx: u32, + ecx: u32, + edx: u32, +} + +impl Iterator for CacheInfoIter { + type Item = CacheInfo; + + /// Iterate over all cache information. + fn next(&mut self) -> Option { + // Every byte of the 4 register values returned by cpuid + // can contain information about a cache (except the + // very first one). + if self.current >= 4 * 4 { + return None; + } + let reg_index = self.current % 4; + let byte_index = self.current / 4; + + let reg = match reg_index { + 0 => self.eax, + 1 => self.ebx, + 2 => self.ecx, + 3 => self.edx, + _ => unreachable!(), + }; + + let byte = match byte_index { + 0 => reg, + 1 => reg >> 8, + 2 => reg >> 16, + 3 => reg >> 24, + _ => unreachable!(), + } as u8; + + if byte == 0 { + self.current += 1; + return self.next(); + } + + for cache_info in CACHE_INFO_TABLE.iter() { + if cache_info.num == byte { + self.current += 1; + return Some(*cache_info); + } + } + + None + } +} + +impl Debug for CacheInfoIter { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + let mut debug = f.debug_list(); + self.clone().for_each(|ref item| { + debug.entry(item); + }); + debug.finish() + } +} + +/// What type of cache are we dealing with? +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub enum CacheInfoType { + General, + Cache, + TLB, + STLB, + DTLB, + Prefetch, +} + +/// Describes any kind of cache (TLB, Data and Instruction caches plus prefetchers). +#[derive(Copy, Clone)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct CacheInfo { + /// Number as retrieved from cpuid + pub num: u8, + /// Cache type + pub typ: CacheInfoType, +} + +impl CacheInfo { + /// Description of the cache (from Intel Manual) + pub fn desc(&self) -> &'static str { + match self.num { + 0x00 => "Null descriptor, this byte contains no information", + 0x01 => "Instruction TLB: 4 KByte pages, 4-way set associative, 32 entries", + 0x02 => "Instruction TLB: 4 MByte pages, fully associative, 2 entries", + 0x03 => "Data TLB: 4 KByte pages, 4-way set associative, 64 entries", + 0x04 => "Data TLB: 4 MByte pages, 4-way set associative, 8 entries", + 0x05 => "Data TLB1: 4 MByte pages, 4-way set associative, 32 entries", + 0x06 => "1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size", + 0x08 => "1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size", + 0x09 => "1st-level instruction cache: 32KBytes, 4-way set associative, 64 byte line size", + 0x0A => "1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size", + 0x0B => "Instruction TLB: 4 MByte pages, 4-way set associative, 4 entries", + 0x0C => "1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size", + 0x0D => "1st-level data cache: 16 KBytes, 4-way set associative, 64 byte line size", + 0x0E => "1st-level data cache: 24 KBytes, 6-way set associative, 64 byte line size", + 0x1D => "2nd-level cache: 128 KBytes, 2-way set associative, 64 byte line size", + 0x21 => "2nd-level cache: 256 KBytes, 8-way set associative, 64 byte line size", + 0x22 => "3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector", + 0x23 => "3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector", + 0x24 => "2nd-level cache: 1 MBytes, 16-way set associative, 64 byte line size", + 0x25 => "3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector", + 0x29 => "3rd-level cache: 4 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector", + 0x2C => "1st-level data cache: 32 KBytes, 8-way set associative, 64 byte line size", + 0x30 => "1st-level instruction cache: 32 KBytes, 8-way set associative, 64 byte line size", + 0x40 => "No 2nd-level cache or, if processor contains a valid 2nd-level cache, no 3rd-level cache", + 0x41 => "2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size", + 0x42 => "2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size", + 0x43 => "2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size", + 0x44 => "2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size", + 0x45 => "2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size", + 0x46 => "3rd-level cache: 4 MByte, 4-way set associative, 64 byte line size", + 0x47 => "3rd-level cache: 8 MByte, 8-way set associative, 64 byte line size", + 0x48 => "2nd-level cache: 3MByte, 12-way set associative, 64 byte line size", + 0x49 => "3rd-level cache: 4MB, 16-way set associative, 64-byte line size (Intel Xeon processor MP, Family 0FH, Model 06H); 2nd-level cache: 4 MByte, 16-way set ssociative, 64 byte line size", + 0x4A => "3rd-level cache: 6MByte, 12-way set associative, 64 byte line size", + 0x4B => "3rd-level cache: 8MByte, 16-way set associative, 64 byte line size", + 0x4C => "3rd-level cache: 12MByte, 12-way set associative, 64 byte line size", + 0x4D => "3rd-level cache: 16MByte, 16-way set associative, 64 byte line size", + 0x4E => "2nd-level cache: 6MByte, 24-way set associative, 64 byte line size", + 0x4F => "Instruction TLB: 4 KByte pages, 32 entries", + 0x50 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 64 entries", + 0x51 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 128 entries", + 0x52 => "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 256 entries", + 0x55 => "Instruction TLB: 2-MByte or 4-MByte pages, fully associative, 7 entries", + 0x56 => "Data TLB0: 4 MByte pages, 4-way set associative, 16 entries", + 0x57 => "Data TLB0: 4 KByte pages, 4-way associative, 16 entries", + 0x59 => "Data TLB0: 4 KByte pages, fully associative, 16 entries", + 0x5A => "Data TLB0: 2-MByte or 4 MByte pages, 4-way set associative, 32 entries", + 0x5B => "Data TLB: 4 KByte and 4 MByte pages, 64 entries", + 0x5C => "Data TLB: 4 KByte and 4 MByte pages,128 entries", + 0x5D => "Data TLB: 4 KByte and 4 MByte pages,256 entries", + 0x60 => "1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size", + 0x61 => "Instruction TLB: 4 KByte pages, fully associative, 48 entries", + 0x63 => "Data TLB: 2 MByte or 4 MByte pages, 4-way set associative, 32 entries and a separate array with 1 GByte pages, 4-way set associative, 4 entries", + 0x64 => "Data TLB: 4 KByte pages, 4-way set associative, 512 entries", + 0x66 => "1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size", + 0x67 => "1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size", + 0x68 => "1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size", + 0x6A => "uTLB: 4 KByte pages, 8-way set associative, 64 entries", + 0x6B => "DTLB: 4 KByte pages, 8-way set associative, 256 entries", + 0x6C => "DTLB: 2M/4M pages, 8-way set associative, 128 entries", + 0x6D => "DTLB: 1 GByte pages, fully associative, 16 entries", + 0x70 => "Trace cache: 12 K-μop, 8-way set associative", + 0x71 => "Trace cache: 16 K-μop, 8-way set associative", + 0x72 => "Trace cache: 32 K-μop, 8-way set associative", + 0x76 => "Instruction TLB: 2M/4M pages, fully associative, 8 entries", + 0x78 => "2nd-level cache: 1 MByte, 4-way set associative, 64byte line size", + 0x79 => "2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector", + 0x7A => "2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector", + 0x7B => "2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector", + 0x7C => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector", + 0x7D => "2nd-level cache: 2 MByte, 8-way set associative, 64byte line size", + 0x7F => "2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size", + 0x80 => "2nd-level cache: 512 KByte, 8-way set associative, 64-byte line size", + 0x82 => "2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size", + 0x83 => "2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size", + 0x84 => "2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size", + 0x85 => "2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size", + 0x86 => "2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size", + 0x87 => "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size", + 0xA0 => "DTLB: 4k pages, fully associative, 32 entries", + 0xB0 => "Instruction TLB: 4 KByte pages, 4-way set associative, 128 entries", + 0xB1 => "Instruction TLB: 2M pages, 4-way, 8 entries or 4M pages, 4-way, 4 entries", + 0xB2 => "Instruction TLB: 4KByte pages, 4-way set associative, 64 entries", + 0xB3 => "Data TLB: 4 KByte pages, 4-way set associative, 128 entries", + 0xB4 => "Data TLB1: 4 KByte pages, 4-way associative, 256 entries", + 0xB5 => "Instruction TLB: 4KByte pages, 8-way set associative, 64 entries", + 0xB6 => "Instruction TLB: 4KByte pages, 8-way set associative, 128 entries", + 0xBA => "Data TLB1: 4 KByte pages, 4-way associative, 64 entries", + 0xC0 => "Data TLB: 4 KByte and 4 MByte pages, 4-way associative, 8 entries", + 0xC1 => "Shared 2nd-Level TLB: 4 KByte/2MByte pages, 8-way associative, 1024 entries", + 0xC2 => "DTLB: 2 MByte/$MByte pages, 4-way associative, 16 entries", + 0xC3 => "Shared 2nd-Level TLB: 4 KByte /2 MByte pages, 6-way associative, 1536 entries. Also 1GBbyte pages, 4-way, 16 entries.", + 0xC4 => "DTLB: 2M/4M Byte pages, 4-way associative, 32 entries", + 0xCA => "Shared 2nd-Level TLB: 4 KByte pages, 4-way associative, 512 entries", + 0xD0 => "3rd-level cache: 512 KByte, 4-way set associative, 64 byte line size", + 0xD1 => "3rd-level cache: 1 MByte, 4-way set associative, 64 byte line size", + 0xD2 => "3rd-level cache: 2 MByte, 4-way set associative, 64 byte line size", + 0xD6 => "3rd-level cache: 1 MByte, 8-way set associative, 64 byte line size", + 0xD7 => "3rd-level cache: 2 MByte, 8-way set associative, 64 byte line size", + 0xD8 => "3rd-level cache: 4 MByte, 8-way set associative, 64 byte line size", + 0xDC => "3rd-level cache: 1.5 MByte, 12-way set associative, 64 byte line size", + 0xDD => "3rd-level cache: 3 MByte, 12-way set associative, 64 byte line size", + 0xDE => "3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size", + 0xE2 => "3rd-level cache: 2 MByte, 16-way set associative, 64 byte line size", + 0xE3 => "3rd-level cache: 4 MByte, 16-way set associative, 64 byte line size", + 0xE4 => "3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size", + 0xEA => "3rd-level cache: 12MByte, 24-way set associative, 64 byte line size", + 0xEB => "3rd-level cache: 18MByte, 24-way set associative, 64 byte line size", + 0xEC => "3rd-level cache: 24MByte, 24-way set associative, 64 byte line size", + 0xF0 => "64-Byte prefetching", + 0xF1 => "128-Byte prefetching", + 0xFE => "CPUID leaf 2 does not report TLB descriptor information; use CPUID leaf 18H to query TLB and other address translation parameters.", + 0xFF => "CPUID leaf 2 does not report cache descriptor information, use CPUID leaf 4 to query cache parameters", + _ => "Unknown cache type!" + } + } +} + +impl Debug for CacheInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("CacheInfo") + .field("typ", &self.typ) + .field("desc", &self.desc()) + .finish() + } +} + +impl fmt::Display for CacheInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let typ = match self.typ { + CacheInfoType::General => "N/A", + CacheInfoType::Cache => "Cache", + CacheInfoType::TLB => "TLB", + CacheInfoType::STLB => "STLB", + CacheInfoType::DTLB => "DTLB", + CacheInfoType::Prefetch => "Prefetcher", + }; + + write!(f, "{:x}:\t {}: {}", self.num, typ, self.desc()) + } +} + +/// This table is taken from Intel manual (Section CPUID instruction). +pub const CACHE_INFO_TABLE: [CacheInfo; 108] = [ + CacheInfo { + num: 0x00, + typ: CacheInfoType::General, + }, + CacheInfo { + num: 0x01, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x02, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x03, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x04, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x05, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x06, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x08, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x09, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x0A, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x0B, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x0C, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x0D, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x0E, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x21, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x22, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x23, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x24, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x25, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x29, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x2C, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x30, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x40, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x41, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x42, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x43, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x44, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x45, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x46, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x47, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x48, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x49, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x4A, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x4B, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x4C, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x4D, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x4E, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x4F, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x50, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x51, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x52, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x55, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x56, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x57, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x59, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x5A, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x5B, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x5C, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x5D, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x60, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x61, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x63, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x66, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x67, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x68, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x6A, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x6B, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x6C, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x6D, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x70, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x71, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x72, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x76, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0x78, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x79, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x7A, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x7B, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x7C, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x7D, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x7F, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x80, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x82, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x83, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x84, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x85, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x86, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0x87, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xB0, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0xB1, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0xB2, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0xB3, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0xB4, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0xB5, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0xB6, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0xBA, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0xC0, + typ: CacheInfoType::TLB, + }, + CacheInfo { + num: 0xC1, + typ: CacheInfoType::STLB, + }, + CacheInfo { + num: 0xC2, + typ: CacheInfoType::DTLB, + }, + CacheInfo { + num: 0xCA, + typ: CacheInfoType::STLB, + }, + CacheInfo { + num: 0xD0, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xD1, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xD2, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xD6, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xD7, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xD8, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xDC, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xDD, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xDE, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xE2, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xE3, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xE4, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xEA, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xEB, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xEC, + typ: CacheInfoType::Cache, + }, + CacheInfo { + num: 0xF0, + typ: CacheInfoType::Prefetch, + }, + CacheInfo { + num: 0xF1, + typ: CacheInfoType::Prefetch, + }, + CacheInfo { + num: 0xFE, + typ: CacheInfoType::General, + }, + CacheInfo { + num: 0xFF, + typ: CacheInfoType::General, + }, +]; + +/// Processor Serial Number (LEAF=0x3). +/// +/// # Deprecated +/// +/// Processor serial number (PSN) is not supported in the Pentium 4 processor or +/// later. On all models, use the PSN flag (returned using CPUID) to check for +/// PSN support before accessing the feature. +/// +/// # Platforms +/// ⌠AMD ✅ Intel +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ProcessorSerial { + /// Lower bits + ecx: u32, + /// Middle bits + edx: u32, + /// Upper bits (come from leaf 0x1) + eax: u32, +} + +impl ProcessorSerial { + /// Bits 00-31 of 96 bit processor serial number. + /// + /// (Available in Pentium III processor only; otherwise, the value in this register is reserved.) + pub fn serial_lower(&self) -> u32 { + self.ecx + } + + /// Bits 32-63 of 96 bit processor serial number. + /// + /// (Available in Pentium III processor only; otherwise, the value in this register is reserved.) + pub fn serial_middle(&self) -> u32 { + self.edx + } + + /// Bits 64-96 of 96 bit processor serial number. + pub fn serial_upper(&self) -> u32 { + self.eax + } + + /// Combination of bits 00-31 and 32-63 of 96 bit processor serial number. + pub fn serial(&self) -> u64 { + (self.serial_lower() as u64) | (self.serial_middle() as u64) << 32 + } + + /// 96 bit processor serial number. + pub fn serial_all(&self) -> u128 { + (self.serial_lower() as u128) + | ((self.serial_middle() as u128) << 32) + | ((self.serial_upper() as u128) << 64) + } +} + +impl Debug for ProcessorSerial { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ProcessorSerial") + .field("serial_lower", &self.serial_lower()) + .field("serial_middle", &self.serial_middle()) + .finish() + } +} + +/// Processor and Processor Feature Identifiers (LEAF=0x01). +/// +/// # Platforms +/// ✅ AMD ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct FeatureInfo { + vendor: Vendor, + eax: u32, + ebx: u32, + edx_ecx: FeatureInfoFlags, +} + +impl FeatureInfo { + /// Version Information: Extended Family + pub fn extended_family_id(&self) -> u8 { + get_bits(self.eax, 20, 27) as u8 + } + + /// Version Information: Extended Model + pub fn extended_model_id(&self) -> u8 { + get_bits(self.eax, 16, 19) as u8 + } + + /// Version Information: Family + pub fn base_family_id(&self) -> u8 { + get_bits(self.eax, 8, 11) as u8 + } + + /// Version Information: Model + pub fn base_model_id(&self) -> u8 { + get_bits(self.eax, 4, 7) as u8 + } + + pub fn family_id(&self) -> u8 { + let base_family_id = self.base_family_id(); + let extended_family_id = self.extended_family_id(); + let just_use_base = (self.vendor == Vendor::Amd && base_family_id < 0xf) + || (self.vendor == Vendor::Intel && base_family_id != 0xf); + + if just_use_base { + base_family_id + } else { + base_family_id + extended_family_id + } + } + + pub fn model_id(&self) -> u8 { + let base_family_id = self.base_family_id(); + let base_model_id = self.base_model_id(); + let extended_model_id = self.extended_model_id(); + let just_use_base = (self.vendor == Vendor::Amd && base_family_id < 0xf) + || (self.vendor == Vendor::Intel && base_family_id != 0xf && base_family_id != 0x6); + + if just_use_base { + base_model_id + } else { + (extended_model_id << 4) | base_model_id + } + } + + /// Version Information: Stepping ID + pub fn stepping_id(&self) -> u8 { + get_bits(self.eax, 0, 3) as u8 + } + + /// Brand Index + pub fn brand_index(&self) -> u8 { + get_bits(self.ebx, 0, 7) as u8 + } + + /// CLFLUSH line size (Value ∗ 8 = cache line size in bytes) + pub fn cflush_cache_line_size(&self) -> u8 { + get_bits(self.ebx, 8, 15) as u8 + } + + /// Initial APIC ID + pub fn initial_local_apic_id(&self) -> u8 { + get_bits(self.ebx, 24, 31) as u8 + } + + /// Maximum number of addressable IDs for logical processors in this physical package. + pub fn max_logical_processor_ids(&self) -> u8 { + get_bits(self.ebx, 16, 23) as u8 + } + + check_flag!( + doc = "Streaming SIMD Extensions 3 (SSE3). A value of 1 indicates the processor \ + supports this technology.", + has_sse3, + edx_ecx, + FeatureInfoFlags::SSE3 + ); + + check_flag!( + doc = "PCLMULQDQ. A value of 1 indicates the processor supports the PCLMULQDQ \ + instruction", + has_pclmulqdq, + edx_ecx, + FeatureInfoFlags::PCLMULQDQ + ); + + check_flag!( + doc = "64-bit DS Area. A value of 1 indicates the processor supports DS area \ + using 64-bit layout", + has_ds_area, + edx_ecx, + FeatureInfoFlags::DTES64 + ); + + check_flag!( + doc = "MONITOR/MWAIT. A value of 1 indicates the processor supports this feature.", + has_monitor_mwait, + edx_ecx, + FeatureInfoFlags::MONITOR + ); + + check_flag!( + doc = "CPL Qualified Debug Store. A value of 1 indicates the processor supports \ + the extensions to the Debug Store feature to allow for branch message \ + storage qualified by CPL.", + has_cpl, + edx_ecx, + FeatureInfoFlags::DSCPL + ); + + check_flag!( + doc = "Virtual Machine Extensions. A value of 1 indicates that the processor \ + supports this technology.", + has_vmx, + edx_ecx, + FeatureInfoFlags::VMX + ); + + check_flag!( + doc = "Safer Mode Extensions. A value of 1 indicates that the processor supports \ + this technology. See Chapter 5, Safer Mode Extensions Reference.", + has_smx, + edx_ecx, + FeatureInfoFlags::SMX + ); + + check_flag!( + doc = "Enhanced Intel SpeedStep® technology. A value of 1 indicates that the \ + processor supports this technology.", + has_eist, + edx_ecx, + FeatureInfoFlags::EIST + ); + + check_flag!( + doc = "Thermal Monitor 2. A value of 1 indicates whether the processor supports \ + this technology.", + has_tm2, + edx_ecx, + FeatureInfoFlags::TM2 + ); + + check_flag!( + doc = "A value of 1 indicates the presence of the Supplemental Streaming SIMD \ + Extensions 3 (SSSE3). A value of 0 indicates the instruction extensions \ + are not present in the processor", + has_ssse3, + edx_ecx, + FeatureInfoFlags::SSSE3 + ); + + check_flag!( + doc = "L1 Context ID. A value of 1 indicates the L1 data cache mode can be set \ + to either adaptive mode or shared mode. A value of 0 indicates this \ + feature is not supported. See definition of the IA32_MISC_ENABLE MSR Bit \ + 24 (L1 Data Cache Context Mode) for details.", + has_cnxtid, + edx_ecx, + FeatureInfoFlags::CNXTID + ); + + check_flag!( + doc = "A value of 1 indicates the processor supports FMA extensions using YMM \ + state.", + has_fma, + edx_ecx, + FeatureInfoFlags::FMA + ); + + check_flag!( + doc = "CMPXCHG16B Available. A value of 1 indicates that the feature is \ + available. See the CMPXCHG8B/CMPXCHG16B Compare and Exchange Bytes \ + section. 14", + has_cmpxchg16b, + edx_ecx, + FeatureInfoFlags::CMPXCHG16B + ); + + check_flag!( + doc = "Perfmon and Debug Capability: A value of 1 indicates the processor \ + supports the performance and debug feature indication MSR \ + IA32_PERF_CAPABILITIES.", + has_pdcm, + edx_ecx, + FeatureInfoFlags::PDCM + ); + + check_flag!( + doc = "Process-context identifiers. A value of 1 indicates that the processor \ + supports PCIDs and the software may set CR4.PCIDE to 1.", + has_pcid, + edx_ecx, + FeatureInfoFlags::PCID + ); + + check_flag!( + doc = "A value of 1 indicates the processor supports the ability to prefetch \ + data from a memory mapped device.", + has_dca, + edx_ecx, + FeatureInfoFlags::DCA + ); + + check_flag!( + doc = "A value of 1 indicates that the processor supports SSE4.1.", + has_sse41, + edx_ecx, + FeatureInfoFlags::SSE41 + ); + + check_flag!( + doc = "A value of 1 indicates that the processor supports SSE4.2.", + has_sse42, + edx_ecx, + FeatureInfoFlags::SSE42 + ); + + check_flag!( + doc = "A value of 1 indicates that the processor supports x2APIC feature.", + has_x2apic, + edx_ecx, + FeatureInfoFlags::X2APIC + ); + + check_flag!( + doc = "A value of 1 indicates that the processor supports MOVBE instruction.", + has_movbe, + edx_ecx, + FeatureInfoFlags::MOVBE + ); + + check_flag!( + doc = "A value of 1 indicates that the processor supports the POPCNT instruction.", + has_popcnt, + edx_ecx, + FeatureInfoFlags::POPCNT + ); + + check_flag!( + doc = "A value of 1 indicates that the processors local APIC timer supports \ + one-shot operation using a TSC deadline value.", + has_tsc_deadline, + edx_ecx, + FeatureInfoFlags::TSC_DEADLINE + ); + + check_flag!( + doc = "A value of 1 indicates that the processor supports the AESNI instruction \ + extensions.", + has_aesni, + edx_ecx, + FeatureInfoFlags::AESNI + ); + + check_flag!( + doc = "A value of 1 indicates that the processor supports the XSAVE/XRSTOR \ + processor extended states feature, the XSETBV/XGETBV instructions, and \ + XCR0.", + has_xsave, + edx_ecx, + FeatureInfoFlags::XSAVE + ); + + check_flag!( + doc = "A value of 1 indicates that the OS has enabled XSETBV/XGETBV instructions \ + to access XCR0, and support for processor extended state management using \ + XSAVE/XRSTOR.", + has_oxsave, + edx_ecx, + FeatureInfoFlags::OSXSAVE + ); + + check_flag!( + doc = "A value of 1 indicates the processor supports the AVX instruction \ + extensions.", + has_avx, + edx_ecx, + FeatureInfoFlags::AVX + ); + + check_flag!( + doc = "A value of 1 indicates that processor supports 16-bit floating-point \ + conversion instructions.", + has_f16c, + edx_ecx, + FeatureInfoFlags::F16C + ); + + check_flag!( + doc = "A value of 1 indicates that processor supports RDRAND instruction.", + has_rdrand, + edx_ecx, + FeatureInfoFlags::RDRAND + ); + + check_flag!( + doc = "A value of 1 indicates the indicates the presence of a hypervisor.", + has_hypervisor, + edx_ecx, + FeatureInfoFlags::HYPERVISOR + ); + + check_flag!( + doc = "Floating Point Unit On-Chip. The processor contains an x87 FPU.", + has_fpu, + edx_ecx, + FeatureInfoFlags::FPU + ); + + check_flag!( + doc = "Virtual 8086 Mode Enhancements. Virtual 8086 mode enhancements, including \ + CR4.VME for controlling the feature, CR4.PVI for protected mode virtual \ + interrupts, software interrupt indirection, expansion of the TSS with the \ + software indirection bitmap, and EFLAGS.VIF and EFLAGS.VIP flags.", + has_vme, + edx_ecx, + FeatureInfoFlags::VME + ); + + check_flag!( + doc = "Debugging Extensions. Support for I/O breakpoints, including CR4.DE for \ + controlling the feature, and optional trapping of accesses to DR4 and DR5.", + has_de, + edx_ecx, + FeatureInfoFlags::DE + ); + + check_flag!( + doc = "Page Size Extension. Large pages of size 4 MByte are supported, including \ + CR4.PSE for controlling the feature, the defined dirty bit in PDE (Page \ + Directory Entries), optional reserved bit trapping in CR3, PDEs, and PTEs.", + has_pse, + edx_ecx, + FeatureInfoFlags::PSE + ); + + check_flag!( + doc = "Time Stamp Counter. The RDTSC instruction is supported, including CR4.TSD \ + for controlling privilege.", + has_tsc, + edx_ecx, + FeatureInfoFlags::TSC + ); + + check_flag!( + doc = "Model Specific Registers RDMSR and WRMSR Instructions. The RDMSR and \ + WRMSR instructions are supported. Some of the MSRs are implementation \ + dependent.", + has_msr, + edx_ecx, + FeatureInfoFlags::MSR + ); + + check_flag!( + doc = "Physical Address Extension. Physical addresses greater than 32 bits are \ + supported: extended page table entry formats, an extra level in the page \ + translation tables is defined, 2-MByte pages are supported instead of 4 \ + Mbyte pages if PAE bit is 1.", + has_pae, + edx_ecx, + FeatureInfoFlags::PAE + ); + + check_flag!( + doc = "Machine Check Exception. Exception 18 is defined for Machine Checks, \ + including CR4.MCE for controlling the feature. This feature does not \ + define the model-specific implementations of machine-check error logging, \ + reporting, and processor shutdowns. Machine Check exception handlers may \ + have to depend on processor version to do model specific processing of \ + the exception, or test for the presence of the Machine Check feature.", + has_mce, + edx_ecx, + FeatureInfoFlags::MCE + ); + + check_flag!( + doc = "CMPXCHG8B Instruction. The compare-and-exchange 8 bytes (64 bits) \ + instruction is supported (implicitly locked and atomic).", + has_cmpxchg8b, + edx_ecx, + FeatureInfoFlags::CX8 + ); + + check_flag!( + doc = "APIC On-Chip. The processor contains an Advanced Programmable Interrupt \ + Controller (APIC), responding to memory mapped commands in the physical \ + address range FFFE0000H to FFFE0FFFH (by default - some processors permit \ + the APIC to be relocated).", + has_apic, + edx_ecx, + FeatureInfoFlags::APIC + ); + + check_flag!( + doc = "SYSENTER and SYSEXIT Instructions. The SYSENTER and SYSEXIT and \ + associated MSRs are supported.", + has_sysenter_sysexit, + edx_ecx, + FeatureInfoFlags::SEP + ); + + check_flag!( + doc = "Memory Type Range Registers. MTRRs are supported. The MTRRcap MSR \ + contains feature bits that describe what memory types are supported, how \ + many variable MTRRs are supported, and whether fixed MTRRs are supported.", + has_mtrr, + edx_ecx, + FeatureInfoFlags::MTRR + ); + + check_flag!( + doc = "Page Global Bit. The global bit is supported in paging-structure entries \ + that map a page, indicating TLB entries that are common to different \ + processes and need not be flushed. The CR4.PGE bit controls this feature.", + has_pge, + edx_ecx, + FeatureInfoFlags::PGE + ); + + check_flag!( + doc = "Machine Check Architecture. A value of 1 indicates the Machine Check \ + Architecture of reporting machine errors is supported. The MCG_CAP MSR \ + contains feature bits describing how many banks of error reporting MSRs \ + are supported.", + has_mca, + edx_ecx, + FeatureInfoFlags::MCA + ); + + check_flag!( + doc = "Conditional Move Instructions. The conditional move instruction CMOV is \ + supported. In addition, if x87 FPU is present as indicated by the \ + CPUID.FPU feature bit, then the FCOMI and FCMOV instructions are supported", + has_cmov, + edx_ecx, + FeatureInfoFlags::CMOV + ); + + check_flag!( + doc = "Page Attribute Table. Page Attribute Table is supported. This feature \ + augments the Memory Type Range Registers (MTRRs), allowing an operating \ + system to specify attributes of memory accessed through a linear address \ + on a 4KB granularity.", + has_pat, + edx_ecx, + FeatureInfoFlags::PAT + ); + + check_flag!( + doc = "36-Bit Page Size Extension. 4-MByte pages addressing physical memory \ + beyond 4 GBytes are supported with 32-bit paging. This feature indicates \ + that upper bits of the physical address of a 4-MByte page are encoded in \ + bits 20:13 of the page-directory entry. Such physical addresses are \ + limited by MAXPHYADDR and may be up to 40 bits in size.", + has_pse36, + edx_ecx, + FeatureInfoFlags::PSE36 + ); + + check_flag!( + doc = "Processor Serial Number. The processor supports the 96-bit processor \ + identification number feature and the feature is enabled.", + has_psn, + edx_ecx, + FeatureInfoFlags::PSN + ); + + check_flag!( + doc = "CLFLUSH Instruction. CLFLUSH Instruction is supported.", + has_clflush, + edx_ecx, + FeatureInfoFlags::CLFSH + ); + + check_flag!( + doc = "Debug Store. The processor supports the ability to write debug \ + information into a memory resident buffer. This feature is used by the \ + branch trace store (BTS) and processor event-based sampling (PEBS) \ + facilities (see Chapter 23, Introduction to Virtual-Machine Extensions, \ + in the Intel® 64 and IA-32 Architectures Software Developers Manual, \ + Volume 3C).", + has_ds, + edx_ecx, + FeatureInfoFlags::DS + ); + + check_flag!( + doc = "Thermal Monitor and Software Controlled Clock Facilities. The processor \ + implements internal MSRs that allow processor temperature to be monitored \ + and processor performance to be modulated in predefined duty cycles under \ + software control.", + has_acpi, + edx_ecx, + FeatureInfoFlags::ACPI + ); + + check_flag!( + doc = "Intel MMX Technology. The processor supports the Intel MMX technology.", + has_mmx, + edx_ecx, + FeatureInfoFlags::MMX + ); + + check_flag!( + doc = "FXSAVE and FXRSTOR Instructions. The FXSAVE and FXRSTOR instructions are \ + supported for fast save and restore of the floating point context. \ + Presence of this bit also indicates that CR4.OSFXSR is available for an \ + operating system to indicate that it supports the FXSAVE and FXRSTOR \ + instructions.", + has_fxsave_fxstor, + edx_ecx, + FeatureInfoFlags::FXSR + ); + + check_flag!( + doc = "SSE. The processor supports the SSE extensions.", + has_sse, + edx_ecx, + FeatureInfoFlags::SSE + ); + + check_flag!( + doc = "SSE2. The processor supports the SSE2 extensions.", + has_sse2, + edx_ecx, + FeatureInfoFlags::SSE2 + ); + + check_flag!( + doc = "Self Snoop. The processor supports the management of conflicting memory \ + types by performing a snoop of its own cache structure for transactions \ + issued to the bus.", + has_ss, + edx_ecx, + FeatureInfoFlags::SS + ); + + check_flag!( + doc = "Max APIC IDs reserved field is Valid. A value of 0 for HTT indicates \ + there is only a single logical processor in the package and software \ + should assume only a single APIC ID is reserved. A value of 1 for HTT \ + indicates the value in CPUID.1.EBX\\[23:16\\] (the Maximum number of \ + addressable IDs for logical processors in this package) is valid for the \ + package.", + has_htt, + edx_ecx, + FeatureInfoFlags::HTT + ); + + check_flag!( + doc = "Thermal Monitor. The processor implements the thermal monitor automatic \ + thermal control circuitry (TCC).", + has_tm, + edx_ecx, + FeatureInfoFlags::TM + ); + + check_flag!( + doc = "Pending Break Enable. The processor supports the use of the FERR#/PBE# \ + pin when the processor is in the stop-clock state (STPCLK# is asserted) \ + to signal the processor that an interrupt is pending and that the \ + processor should return to normal operation to handle the interrupt. Bit \ + 10 (PBE enable) in the IA32_MISC_ENABLE MSR enables this capability.", + has_pbe, + edx_ecx, + FeatureInfoFlags::PBE + ); +} + +impl Debug for FeatureInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("FeatureInfo") + .field("extended_family_id", &self.extended_family_id()) + .field("extended_model_id", &self.extended_model_id()) + .field("family_id", &self.family_id()) + .field("model_id", &self.model_id()) + .field("stepping_id", &self.stepping_id()) + .field("brand_index", &self.brand_index()) + .field("cflush_cache_line_size", &self.cflush_cache_line_size()) + .field("initial_local_apic_id", &self.initial_local_apic_id()) + .field( + "max_logical_processor_ids", + &self.max_logical_processor_ids(), + ) + .field("edx_ecx", &self.edx_ecx) + .finish() + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct FeatureInfoFlags: u64 { + + // ECX flags + + /// Streaming SIMD Extensions 3 (SSE3). A value of 1 indicates the processor supports this technology. + const SSE3 = 1 << 0; + /// PCLMULQDQ. A value of 1 indicates the processor supports the PCLMULQDQ instruction + const PCLMULQDQ = 1 << 1; + /// 64-bit DS Area. A value of 1 indicates the processor supports DS area using 64-bit layout + const DTES64 = 1 << 2; + /// MONITOR/MWAIT. A value of 1 indicates the processor supports this feature. + const MONITOR = 1 << 3; + /// CPL Qualified Debug Store. A value of 1 indicates the processor supports the extensions to the Debug Store feature to allow for branch message storage qualified by CPL. + const DSCPL = 1 << 4; + /// Virtual Machine Extensions. A value of 1 indicates that the processor supports this technology. + const VMX = 1 << 5; + /// Safer Mode Extensions. A value of 1 indicates that the processor supports this technology. See Chapter 5, Safer Mode Extensions Reference. + const SMX = 1 << 6; + /// Enhanced Intel SpeedStep® technology. A value of 1 indicates that the processor supports this technology. + const EIST = 1 << 7; + /// Thermal Monitor 2. A value of 1 indicates whether the processor supports this technology. + const TM2 = 1 << 8; + /// A value of 1 indicates the presence of the Supplemental Streaming SIMD Extensions 3 (SSSE3). A value of 0 indicates the instruction extensions are not present in the processor + const SSSE3 = 1 << 9; + /// L1 Context ID. A value of 1 indicates the L1 data cache mode can be set to either adaptive mode or shared mode. A value of 0 indicates this feature is not supported. See definition of the IA32_MISC_ENABLE MSR Bit 24 (L1 Data Cache Context Mode) for details. + const CNXTID = 1 << 10; + /// A value of 1 indicates the processor supports FMA extensions using YMM state. + const FMA = 1 << 12; + /// CMPXCHG16B Available. A value of 1 indicates that the feature is available. See the CMPXCHG8B/CMPXCHG16B Compare and Exchange Bytes section. 14 + const CMPXCHG16B = 1 << 13; + /// Perfmon and Debug Capability: A value of 1 indicates the processor supports the performance and debug feature indication MSR IA32_PERF_CAPABILITIES. + const PDCM = 1 << 15; + /// Process-context identifiers. A value of 1 indicates that the processor supports PCIDs and the software may set CR4.PCIDE to 1. + const PCID = 1 << 17; + /// A value of 1 indicates the processor supports the ability to prefetch data from a memory mapped device. + const DCA = 1 << 18; + /// A value of 1 indicates that the processor supports SSE4.1. + const SSE41 = 1 << 19; + /// A value of 1 indicates that the processor supports SSE4.2. + const SSE42 = 1 << 20; + /// A value of 1 indicates that the processor supports x2APIC feature. + const X2APIC = 1 << 21; + /// A value of 1 indicates that the processor supports MOVBE instruction. + const MOVBE = 1 << 22; + /// A value of 1 indicates that the processor supports the POPCNT instruction. + const POPCNT = 1 << 23; + /// A value of 1 indicates that the processors local APIC timer supports one-shot operation using a TSC deadline value. + const TSC_DEADLINE = 1 << 24; + /// A value of 1 indicates that the processor supports the AESNI instruction extensions. + const AESNI = 1 << 25; + /// A value of 1 indicates that the processor supports the XSAVE/XRSTOR processor extended states feature, the XSETBV/XGETBV instructions, and XCR0. + const XSAVE = 1 << 26; + /// A value of 1 indicates that the OS has enabled XSETBV/XGETBV instructions to access XCR0, and support for processor extended state management using XSAVE/XRSTOR. + const OSXSAVE = 1 << 27; + /// A value of 1 indicates the processor supports the AVX instruction extensions. + const AVX = 1 << 28; + /// A value of 1 indicates that processor supports 16-bit floating-point conversion instructions. + const F16C = 1 << 29; + /// A value of 1 indicates that processor supports RDRAND instruction. + const RDRAND = 1 << 30; + /// A value of 1 indicates the indicates the presence of a hypervisor. + const HYPERVISOR = 1 << 31; + + + // EDX flags + + /// Floating Point Unit On-Chip. The processor contains an x87 FPU. + const FPU = 1 << 32; + /// Virtual 8086 Mode Enhancements. Virtual 8086 mode enhancements, including CR4.VME for controlling the feature, CR4.PVI for protected mode virtual interrupts, software interrupt indirection, expansion of the TSS with the software indirection bitmap, and EFLAGS.VIF and EFLAGS.VIP flags. + const VME = 1 << (32 + 1); + /// Debugging Extensions. Support for I/O breakpoints, including CR4.DE for controlling the feature, and optional trapping of accesses to DR4 and DR5. + const DE = 1 << (32 + 2); + /// Page Size Extension. Large pages of size 4 MByte are supported, including CR4.PSE for controlling the feature, the defined dirty bit in PDE (Page Directory Entries), optional reserved bit trapping in CR3, PDEs, and PTEs. + const PSE = 1 << (32 + 3); + /// Time Stamp Counter. The RDTSC instruction is supported, including CR4.TSD for controlling privilege. + const TSC = 1 << (32 + 4); + /// Model Specific Registers RDMSR and WRMSR Instructions. The RDMSR and WRMSR instructions are supported. Some of the MSRs are implementation dependent. + const MSR = 1 << (32 + 5); + /// Physical Address Extension. Physical addresses greater than 32 bits are supported: extended page table entry formats, an extra level in the page translation tables is defined, 2-MByte pages are supported instead of 4 Mbyte pages if PAE bit is 1. + const PAE = 1 << (32 + 6); + /// Machine Check Exception. Exception 18 is defined for Machine Checks, including CR4.MCE for controlling the feature. This feature does not define the model-specific implementations of machine-check error logging, reporting, and processor shutdowns. Machine Check exception handlers may have to depend on processor version to do model specific processing of the exception, or test for the presence of the Machine Check feature. + const MCE = 1 << (32 + 7); + /// CMPXCHG8B Instruction. The compare-and-exchange 8 bytes (64 bits) instruction is supported (implicitly locked and atomic). + const CX8 = 1 << (32 + 8); + /// APIC On-Chip. The processor contains an Advanced Programmable Interrupt Controller (APIC), responding to memory mapped commands in the physical address range FFFE0000H to FFFE0FFFH (by default - some processors permit the APIC to be relocated). + const APIC = 1 << (32 + 9); + /// SYSENTER and SYSEXIT Instructions. The SYSENTER and SYSEXIT and associated MSRs are supported. + const SEP = 1 << (32 + 11); + /// Memory Type Range Registers. MTRRs are supported. The MTRRcap MSR contains feature bits that describe what memory types are supported, how many variable MTRRs are supported, and whether fixed MTRRs are supported. + const MTRR = 1 << (32 + 12); + /// Page Global Bit. The global bit is supported in paging-structure entries that map a page, indicating TLB entries that are common to different processes and need not be flushed. The CR4.PGE bit controls this feature. + const PGE = 1 << (32 + 13); + /// Machine Check Architecture. The Machine Check exArchitecture, which provides a compatible mechanism for error reporting in P6 family, Pentium 4, Intel Xeon processors, and future processors, is supported. The MCG_CAP MSR contains feature bits describing how many banks of error reporting MSRs are supported. + const MCA = 1 << (32 + 14); + /// Conditional Move Instructions. The conditional move instruction CMOV is supported. In addition, if x87 FPU is present as indicated by the CPUID.FPU feature bit, then the FCOMI and FCMOV instructions are supported + const CMOV = 1 << (32 + 15); + /// Page Attribute Table. Page Attribute Table is supported. This feature augments the Memory Type Range Registers (MTRRs), allowing an operating system to specify attributes of memory accessed through a linear address on a 4KB granularity. + const PAT = 1 << (32 + 16); + /// 36-Bit Page Size Extension. 4-MByte pages addressing physical memory beyond 4 GBytes are supported with 32-bit paging. This feature indicates that upper bits of the physical address of a 4-MByte page are encoded in bits 20:13 of the page-directory entry. Such physical addresses are limited by MAXPHYADDR and may be up to 40 bits in size. + const PSE36 = 1 << (32 + 17); + /// Processor Serial Number. The processor supports the 96-bit processor identification number feature and the feature is enabled. + const PSN = 1 << (32 + 18); + /// CLFLUSH Instruction. CLFLUSH Instruction is supported. + const CLFSH = 1 << (32 + 19); + /// Debug Store. The processor supports the ability to write debug information into a memory resident buffer. This feature is used by the branch trace store (BTS) and precise event-based sampling (PEBS) facilities (see Chapter 23, Introduction to Virtual-Machine Extensions, in the Intel® 64 and IA-32 Architectures Software Developers Manual, Volume 3C). + const DS = 1 << (32 + 21); + /// Thermal Monitor and Software Controlled Clock Facilities. The processor implements internal MSRs that allow processor temperature to be monitored and processor performance to be modulated in predefined duty cycles under software control. + const ACPI = 1 << (32 + 22); + /// Intel MMX Technology. The processor supports the Intel MMX technology. + const MMX = 1 << (32 + 23); + /// FXSAVE and FXRSTOR Instructions. The FXSAVE and FXRSTOR instructions are supported for fast save and restore of the floating point context. Presence of this bit also indicates that CR4.OSFXSR is available for an operating system to indicate that it supports the FXSAVE and FXRSTOR instructions. + const FXSR = 1 << (32 + 24); + /// SSE. The processor supports the SSE extensions. + const SSE = 1 << (32 + 25); + /// SSE2. The processor supports the SSE2 extensions. + const SSE2 = 1 << (32 + 26); + /// Self Snoop. The processor supports the management of conflicting memory types by performing a snoop of its own cache structure for transactions issued to the bus. + const SS = 1 << (32 + 27); + /// Max APIC IDs reserved field is Valid. A value of 0 for HTT indicates there is only a single logical processor in the package and software should assume only a single APIC ID is reserved. A value of 1 for HTT indicates the value in CPUID.1.EBX[23:16] (the Maximum number of addressable IDs for logical processors in this package) is valid for the package. + const HTT = 1 << (32 + 28); + /// Thermal Monitor. The processor implements the thermal monitor automatic thermal control circuitry (TCC). + const TM = 1 << (32 + 29); + /// Pending Break Enable. The processor supports the use of the FERR#/PBE# pin when the processor is in the stop-clock state (STPCLK# is asserted) to signal the processor that an interrupt is pending and that the processor should return to normal operation to handle the interrupt. Bit 10 (PBE enable) in the IA32_MISC_ENABLE MSR enables this capability. + const PBE = 1 << (32 + 31); + } +} + +/// Iterator over caches (LEAF=0x04). +/// +/// Yields a [CacheParameter] for each cache. +/// +/// # Platforms +/// 🟡 AMD ✅ Intel +#[derive(Clone)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct CacheParametersIter { + #[cfg_attr(feature = "serialize", serde(skip))] + read: CpuIdReader, + leaf: u32, + current: u32, +} + +impl Iterator for CacheParametersIter { + type Item = CacheParameter; + + /// Iterate over all cache info subleafs for this CPU. + /// + /// # Note + /// cpuid is called every-time we advance the iterator to get information + /// about the next cache. + fn next(&mut self) -> Option { + let res = self.read.cpuid2(self.leaf, self.current); + let cp = CacheParameter { + eax: res.eax, + ebx: res.ebx, + ecx: res.ecx, + edx: res.edx, + }; + + match cp.cache_type() { + CacheType::Null => None, + CacheType::Reserved => None, + _ => { + self.current += 1; + Some(cp) + } + } + } +} + +impl Debug for CacheParametersIter { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + let mut debug = f.debug_list(); + self.clone().for_each(|ref item| { + debug.entry(item); + }); + debug.finish() + } +} + +/// Information about an individual cache in the hierarchy. +/// +/// # Platforms +/// 🟡 AMD ✅ Intel +#[derive(Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct CacheParameter { + eax: u32, + ebx: u32, + ecx: u32, + edx: u32, +} + +/// Info about a what a given cache caches (instructions, data, etc.) +#[derive(PartialEq, Eq, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub enum CacheType { + /// Null - No more caches + Null = 0, + /// Data cache + Data, + /// Instruction cache + Instruction, + /// Data and Instruction cache + Unified, + /// 4-31 = Reserved + Reserved, +} + +impl fmt::Display for CacheType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let typ = match self { + CacheType::Null => "Null", + CacheType::Data => "Data", + CacheType::Instruction => "Instruction", + CacheType::Unified => "Unified", + CacheType::Reserved => "Reserved", + }; + + f.write_str(typ) + } +} + +impl CacheParameter { + /// Cache Type + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn cache_type(&self) -> CacheType { + let typ = get_bits(self.eax, 0, 4) as u8; + match typ { + 0 => CacheType::Null, + 1 => CacheType::Data, + 2 => CacheType::Instruction, + 3 => CacheType::Unified, + _ => CacheType::Reserved, + } + } + + /// Cache Level (starts at 1) + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn level(&self) -> u8 { + get_bits(self.eax, 5, 7) as u8 + } + + /// Self Initializing cache level (does not need SW initialization). + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn is_self_initializing(&self) -> bool { + get_bits(self.eax, 8, 8) == 1 + } + + /// Fully Associative cache + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn is_fully_associative(&self) -> bool { + get_bits(self.eax, 9, 9) == 1 + } + + /// Maximum number of addressable IDs for logical processors sharing this cache + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn max_cores_for_cache(&self) -> usize { + (get_bits(self.eax, 14, 25) + 1) as usize + } + + /// Maximum number of addressable IDs for processor cores in the physical package + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn max_cores_for_package(&self) -> usize { + (get_bits(self.eax, 26, 31) + 1) as usize + } + + /// System Coherency Line Size (Bits 11-00) + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn coherency_line_size(&self) -> usize { + (get_bits(self.ebx, 0, 11) + 1) as usize + } + + /// Physical Line partitions (Bits 21-12) + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn physical_line_partitions(&self) -> usize { + (get_bits(self.ebx, 12, 21) + 1) as usize + } + + /// Ways of associativity (Bits 31-22) + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn associativity(&self) -> usize { + (get_bits(self.ebx, 22, 31) + 1) as usize + } + + /// Number of Sets (Bits 31-00) + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn sets(&self) -> usize { + (self.ecx + 1) as usize + } + + /// Write-Back Invalidate/Invalidate (Bit 0) + /// False: WBINVD/INVD from threads sharing this cache acts upon lower level caches for threads sharing this cache. + /// True: WBINVD/INVD is not guaranteed to act upon lower level caches of non-originating threads sharing this cache. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn is_write_back_invalidate(&self) -> bool { + get_bits(self.edx, 0, 0) == 1 + } + + /// Cache Inclusiveness (Bit 1) + /// False: Cache is not inclusive of lower cache levels. + /// True: Cache is inclusive of lower cache levels. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn is_inclusive(&self) -> bool { + get_bits(self.edx, 1, 1) == 1 + } + + /// Complex Cache Indexing (Bit 2) + /// False: Direct mapped cache. + /// True: A complex function is used to index the cache, potentially using all address bits. + /// + /// # Platforms + /// ⌠AMD ✅ Intel + pub fn has_complex_indexing(&self) -> bool { + get_bits(self.edx, 2, 2) == 1 + } +} + +impl Debug for CacheParameter { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("CacheParameter") + .field("cache_type", &self.cache_type()) + .field("level", &self.level()) + .field("is_self_initializing", &self.is_self_initializing()) + .field("is_fully_associative", &self.is_fully_associative()) + .field("max_cores_for_cache", &self.max_cores_for_cache()) + .field("max_cores_for_package", &self.max_cores_for_package()) + .field("coherency_line_size", &self.coherency_line_size()) + .field("physical_line_partitions", &self.physical_line_partitions()) + .field("associativity", &self.associativity()) + .field("sets", &self.sets()) + .field("is_write_back_invalidate", &self.is_write_back_invalidate()) + .field("is_inclusive", &self.is_inclusive()) + .field("has_complex_indexing", &self.has_complex_indexing()) + .finish() + } +} + +/// Information about how monitor/mwait works on this CPU (LEAF=0x05). +/// +/// # Platforms +/// 🟡 AMD ✅ Intel +#[derive(Eq, PartialEq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct MonitorMwaitInfo { + eax: u32, + ebx: u32, + ecx: u32, + edx: u32, +} + +impl MonitorMwaitInfo { + /// Smallest monitor-line size in bytes (default is processor's monitor granularity) + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn smallest_monitor_line(&self) -> u16 { + get_bits(self.eax, 0, 15) as u16 + } + + /// Largest monitor-line size in bytes (default is processor's monitor granularity + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn largest_monitor_line(&self) -> u16 { + get_bits(self.ebx, 0, 15) as u16 + } + + /// Enumeration of Monitor-Mwait extensions (beyond EAX and EBX registers) supported + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn extensions_supported(&self) -> bool { + get_bits(self.ecx, 0, 0) == 1 + } + + /// Supports treating interrupts as break-event for MWAIT, even when interrupts disabled + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn interrupts_as_break_event(&self) -> bool { + get_bits(self.ecx, 1, 1) == 1 + } + + /// Number of C0 sub C-states supported using MWAIT (Bits 03 - 00) + /// + /// # Platforms + /// ⌠AMD (undefined/reserved) ✅ Intel + pub fn supported_c0_states(&self) -> u16 { + get_bits(self.edx, 0, 3) as u16 + } + + /// Number of C1 sub C-states supported using MWAIT (Bits 07 - 04) + /// + /// # Platforms + /// ⌠AMD (undefined/reserved) ✅ Intel + pub fn supported_c1_states(&self) -> u16 { + get_bits(self.edx, 4, 7) as u16 + } + + /// Number of C2 sub C-states supported using MWAIT (Bits 11 - 08) + /// + /// # Platforms + /// ⌠AMD (undefined/reserved) ✅ Intel + pub fn supported_c2_states(&self) -> u16 { + get_bits(self.edx, 8, 11) as u16 + } + + /// Number of C3 sub C-states supported using MWAIT (Bits 15 - 12) + /// + /// # Platforms + /// ⌠AMD (undefined/reserved) ✅ Intel + pub fn supported_c3_states(&self) -> u16 { + get_bits(self.edx, 12, 15) as u16 + } + + /// Number of C4 sub C-states supported using MWAIT (Bits 19 - 16) + /// + /// # Platforms + /// ⌠AMD (undefined/reserved) ✅ Intel + pub fn supported_c4_states(&self) -> u16 { + get_bits(self.edx, 16, 19) as u16 + } + + /// Number of C5 sub C-states supported using MWAIT (Bits 23 - 20) + /// + /// # Platforms + /// ⌠AMD (undefined/reserved) ✅ Intel + pub fn supported_c5_states(&self) -> u16 { + get_bits(self.edx, 20, 23) as u16 + } + + /// Number of C6 sub C-states supported using MWAIT (Bits 27 - 24) + /// + /// # Platforms + /// ⌠AMD (undefined/reserved) ✅ Intel + pub fn supported_c6_states(&self) -> u16 { + get_bits(self.edx, 24, 27) as u16 + } + + /// Number of C7 sub C-states supported using MWAIT (Bits 31 - 28) + /// + /// # Platforms + /// ⌠AMD (undefined/reserved) ✅ Intel + pub fn supported_c7_states(&self) -> u16 { + get_bits(self.edx, 28, 31) as u16 + } +} + +impl Debug for MonitorMwaitInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("MonitorMwaitInfo") + .field("smallest_monitor_line", &self.smallest_monitor_line()) + .field("largest_monitor_line", &self.largest_monitor_line()) + .field("extensions_supported", &self.extensions_supported()) + .field( + "interrupts_as_break_event", + &self.interrupts_as_break_event(), + ) + .field("supported_c0_states", &self.supported_c0_states()) + .field("supported_c1_states", &self.supported_c1_states()) + .field("supported_c2_states", &self.supported_c2_states()) + .field("supported_c3_states", &self.supported_c3_states()) + .field("supported_c4_states", &self.supported_c4_states()) + .field("supported_c5_states", &self.supported_c5_states()) + .field("supported_c6_states", &self.supported_c6_states()) + .field("supported_c7_states", &self.supported_c7_states()) + .finish() + } +} + +/// Query information about thermal and power management features of the CPU (LEAF=0x06). +/// +/// # Platforms +/// 🟡 AMD ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ThermalPowerInfo { + eax: ThermalPowerFeaturesEax, + ebx: u32, + ecx: ThermalPowerFeaturesEcx, + _edx: u32, +} + +impl ThermalPowerInfo { + /// Number of Interrupt Thresholds in Digital Thermal Sensor + /// + /// # Platforms + /// ⌠AMD (undefined/reserved) ✅ Intel + pub fn dts_irq_threshold(&self) -> u8 { + get_bits(self.ebx, 0, 3) as u8 + } + + /// Digital temperature sensor is supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_dts(&self) -> bool { + self.eax.contains(ThermalPowerFeaturesEax::DTS) + } + + /// Intel Turbo Boost Technology Available (see description of + /// IA32_MISC_ENABLE\[38\]). + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_turbo_boost(&self) -> bool { + self.eax.contains(ThermalPowerFeaturesEax::TURBO_BOOST) + } + + /// ARAT. APIC-Timer-always-running feature is supported if set. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn has_arat(&self) -> bool { + self.eax.contains(ThermalPowerFeaturesEax::ARAT) + } + + /// PLN. Power limit notification controls are supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_pln(&self) -> bool { + self.eax.contains(ThermalPowerFeaturesEax::PLN) + } + + /// ECMD. Clock modulation duty cycle extension is supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_ecmd(&self) -> bool { + self.eax.contains(ThermalPowerFeaturesEax::ECMD) + } + + /// PTM. Package thermal management is supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_ptm(&self) -> bool { + self.eax.contains(ThermalPowerFeaturesEax::PTM) + } + + /// HWP. HWP base registers (IA32_PM_ENABLE[bit 0], IA32_HWP_CAPABILITIES, + /// IA32_HWP_REQUEST, IA32_HWP_STATUS) are supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_hwp(&self) -> bool { + self.eax.contains(ThermalPowerFeaturesEax::HWP) + } + + /// HWP Notification. IA32_HWP_INTERRUPT MSR is supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_hwp_notification(&self) -> bool { + self.eax.contains(ThermalPowerFeaturesEax::HWP_NOTIFICATION) + } + + /// HWP Activity Window. IA32_HWP_REQUEST[bits 41:32] is supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_hwp_activity_window(&self) -> bool { + self.eax + .contains(ThermalPowerFeaturesEax::HWP_ACTIVITY_WINDOW) + } + + /// HWP Energy Performance Preference. IA32_HWP_REQUEST[bits 31:24] is + /// supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_hwp_energy_performance_preference(&self) -> bool { + self.eax + .contains(ThermalPowerFeaturesEax::HWP_ENERGY_PERFORMANCE_PREFERENCE) + } + + /// HWP Package Level Request. IA32_HWP_REQUEST_PKG MSR is supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_hwp_package_level_request(&self) -> bool { + self.eax + .contains(ThermalPowerFeaturesEax::HWP_PACKAGE_LEVEL_REQUEST) + } + + /// HDC. HDC base registers IA32_PKG_HDC_CTL, IA32_PM_CTL1, + /// IA32_THREAD_STALL MSRs are supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_hdc(&self) -> bool { + self.eax.contains(ThermalPowerFeaturesEax::HDC) + } + + /// Intel® Turbo Boost Max Technology 3.0 available. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_turbo_boost3(&self) -> bool { + self.eax.contains(ThermalPowerFeaturesEax::TURBO_BOOST_3) + } + + /// HWP Capabilities. Highest Performance change is supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_hwp_capabilities(&self) -> bool { + self.eax.contains(ThermalPowerFeaturesEax::HWP_CAPABILITIES) + } + + /// HWP PECI override is supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_hwp_peci_override(&self) -> bool { + self.eax + .contains(ThermalPowerFeaturesEax::HWP_PECI_OVERRIDE) + } + + /// Flexible HWP is supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_flexible_hwp(&self) -> bool { + self.eax.contains(ThermalPowerFeaturesEax::FLEXIBLE_HWP) + } + + /// Fast access mode for the IA32_HWP_REQUEST MSR is supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_hwp_fast_access_mode(&self) -> bool { + self.eax + .contains(ThermalPowerFeaturesEax::HWP_REQUEST_MSR_FAST_ACCESS) + } + + /// Ignoring Idle Logical Processor HWP request is supported if set. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_ignore_idle_processor_hwp_request(&self) -> bool { + self.eax + .contains(ThermalPowerFeaturesEax::IGNORE_IDLE_PROCESSOR_HWP_REQUEST) + } + + /// Hardware Coordination Feedback Capability + /// + /// Presence of IA32_MPERF and IA32_APERF. + /// + /// The capability to provide a measure of delivered processor performance + /// (since last reset of the counters), as a percentage of expected + /// processor performance at frequency specified in CPUID Brand String Bits + /// 02 - 01 + /// + /// # Platforms + /// ✅ AMD ✅ Intel + pub fn has_hw_coord_feedback(&self) -> bool { + self.ecx + .contains(ThermalPowerFeaturesEcx::HW_COORD_FEEDBACK) + } + + /// The processor supports performance-energy bias preference if + /// CPUID.06H:ECX.SETBH[bit 3] is set and it also implies the presence of a + /// new architectural MSR called IA32_ENERGY_PERF_BIAS (1B0H) + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + pub fn has_energy_bias_pref(&self) -> bool { + self.ecx.contains(ThermalPowerFeaturesEcx::ENERGY_BIAS_PREF) + } +} + +impl Debug for ThermalPowerInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ThermalPowerInfo") + .field("dts_irq_threshold", &self.dts_irq_threshold()) + .field("has_dts", &self.has_dts()) + .field("has_arat", &self.has_arat()) + .field("has_pln", &self.has_pln()) + .field("has_ecmd", &self.has_ecmd()) + .field("has_ptm", &self.has_ptm()) + .field("has_hwp", &self.has_hwp()) + .field("has_hwp_notification", &self.has_hwp_notification()) + .field("has_hwp_activity_window", &self.has_hwp_activity_window()) + .field( + "has_hwp_energy_performance_preference", + &self.has_hwp_energy_performance_preference(), + ) + .field( + "has_hwp_package_level_request", + &self.has_hwp_package_level_request(), + ) + .field("has_hdc", &self.has_hdc()) + .field("has_turbo_boost3", &self.has_turbo_boost3()) + .field("has_hwp_capabilities", &self.has_hwp_capabilities()) + .field("has_hwp_peci_override", &self.has_hwp_peci_override()) + .field("has_flexible_hwp", &self.has_flexible_hwp()) + .field("has_hwp_fast_access_mode", &self.has_hwp_fast_access_mode()) + .field( + "has_ignore_idle_processor_hwp_request", + &self.has_ignore_idle_processor_hwp_request(), + ) + .field("has_hw_coord_feedback", &self.has_hw_coord_feedback()) + .field("has_energy_bias_pref", &self.has_energy_bias_pref()) + .finish() + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct ThermalPowerFeaturesEax: u32 { + /// Digital temperature sensor is supported if set. (Bit 00) + const DTS = 1 << 0; + /// Intel Turbo Boost Technology Available (see description of IA32_MISC_ENABLE[38]). (Bit 01) + const TURBO_BOOST = 1 << 1; + /// ARAT. APIC-Timer-always-running feature is supported if set. (Bit 02) + const ARAT = 1 << 2; + /// Bit 3: Reserved. + const RESERVED_3 = 1 << 3; + /// PLN. Power limit notification controls are supported if set. (Bit 04) + const PLN = 1 << 4; + /// ECMD. Clock modulation duty cycle extension is supported if set. (Bit 05) + const ECMD = 1 << 5; + /// PTM. Package thermal management is supported if set. (Bit 06) + const PTM = 1 << 6; + /// Bit 07: HWP. HWP base registers (IA32_PM_ENABLE[bit 0], IA32_HWP_CAPABILITIES, IA32_HWP_REQUEST, IA32_HWP_STATUS) are supported if set. + const HWP = 1 << 7; + /// Bit 08: HWP_Notification. IA32_HWP_INTERRUPT MSR is supported if set. + const HWP_NOTIFICATION = 1 << 8; + /// Bit 09: HWP_Activity_Window. IA32_HWP_REQUEST[bits 41:32] is supported if set. + const HWP_ACTIVITY_WINDOW = 1 << 9; + /// Bit 10: HWP_Energy_Performance_Preference. IA32_HWP_REQUEST[bits 31:24] is supported if set. + const HWP_ENERGY_PERFORMANCE_PREFERENCE = 1 << 10; + /// Bit 11: HWP_Package_Level_Request. IA32_HWP_REQUEST_PKG MSR is supported if set. + const HWP_PACKAGE_LEVEL_REQUEST = 1 << 11; + /// Bit 12: Reserved. + const RESERVED_12 = 1 << 12; + /// Bit 13: HDC. HDC base registers IA32_PKG_HDC_CTL, IA32_PM_CTL1, IA32_THREAD_STALL MSRs are supported if set. + const HDC = 1 << 13; + /// Bit 14: Intel® Turbo Boost Max Technology 3.0 available. + const TURBO_BOOST_3 = 1 << 14; + /// Bit 15: HWP Capabilities. Highest Performance change is supported if set. + const HWP_CAPABILITIES = 1 << 15; + /// Bit 16: HWP PECI override is supported if set. + const HWP_PECI_OVERRIDE = 1 << 16; + /// Bit 17: Flexible HWP is supported if set. + const FLEXIBLE_HWP = 1 << 17; + /// Bit 18: Fast access mode for the IA32_HWP_REQUEST MSR is supported if set. + const HWP_REQUEST_MSR_FAST_ACCESS = 1 << 18; + /// Bit 19: Reserved. + const RESERVED_19 = 1 << 19; + /// Bit 20: Ignoring Idle Logical Processor HWP request is supported if set. + const IGNORE_IDLE_PROCESSOR_HWP_REQUEST = 1 << 20; + // Bits 31 - 21: Reserved + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct ThermalPowerFeaturesEcx: u32 { + const HW_COORD_FEEDBACK = 1 << 0; + + /// The processor supports performance-energy bias preference if CPUID.06H:ECX.SETBH[bit 3] is set and it also implies the presence of a new architectural MSR called IA32_ENERGY_PERF_BIAS (1B0H) + const ENERGY_BIAS_PREF = 1 << 3; + } +} + +/// Structured Extended Feature Identifiers (LEAF=0x07). +/// +/// # Platforms +/// 🟡 AMD ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ExtendedFeatures { + _eax: u32, + ebx: ExtendedFeaturesEbx, + ecx: ExtendedFeaturesEcx, + _edx: u32, +} + +impl ExtendedFeatures { + /// FSGSBASE. Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE if 1. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + #[inline] + pub const fn has_fsgsbase(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::FSGSBASE) + } + + /// IA32_TSC_ADJUST MSR is supported if 1. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_tsc_adjust_msr(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::ADJUST_MSR) + } + + /// BMI1 + /// + /// # Platforms + /// ✅ AMD ✅ Intel + #[inline] + pub const fn has_bmi1(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::BMI1) + } + + /// HLE + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_hle(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::HLE) + } + + /// AVX2 + /// + /// # Platforms + /// ✅ AMD ✅ Intel + #[inline] + pub const fn has_avx2(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::AVX2) + } + + /// FDP_EXCPTN_ONLY. x87 FPU Data Pointer updated only on x87 exceptions if + /// 1. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_fdp(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::FDP) + } + + /// SMEP. Supports Supervisor-Mode Execution Prevention if 1. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + #[inline] + pub const fn has_smep(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::SMEP) + } + + /// BMI2 + /// + /// # Platforms + /// ✅ AMD ✅ Intel + #[inline] + pub const fn has_bmi2(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::BMI2) + } + + /// Supports Enhanced REP MOVSB/STOSB if 1. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_rep_movsb_stosb(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::REP_MOVSB_STOSB) + } + + /// INVPCID. If 1, supports INVPCID instruction for system software that + /// manages process-context identifiers. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_invpcid(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::INVPCID) + } + + /// RTM + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_rtm(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::RTM) + } + + /// Supports Intel Resource Director Technology (RDT) Monitoring capability. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_rdtm(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::RDTM) + } + + /// Deprecates FPU CS and FPU DS values if 1. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_fpu_cs_ds_deprecated(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::DEPRECATE_FPU_CS_DS) + } + + /// MPX. Supports Intel Memory Protection Extensions if 1. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_mpx(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::MPX) + } + + /// Supports Intel Resource Director Technology (RDT) Allocation capability. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_rdta(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::RDTA) + } + + /// Supports RDSEED. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + #[inline] + pub const fn has_rdseed(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::RDSEED) + } + + /// Supports ADX. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + #[inline] + pub const fn has_adx(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::ADX) + } + + /// SMAP. Supports Supervisor-Mode Access Prevention (and the CLAC/STAC + /// instructions) if 1. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + #[inline] + pub const fn has_smap(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::SMAP) + } + + /// Supports CLFLUSHOPT. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + #[inline] + pub const fn has_clflushopt(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::CLFLUSHOPT) + } + + /// Supports Intel Processor Trace. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_processor_trace(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::PROCESSOR_TRACE) + } + + /// Supports SHA Instructions. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_sha(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::SHA) + } + + /// Supports Intel® Software Guard Extensions (Intel® SGX Extensions). + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_sgx(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::SGX) + } + + /// Supports AVX512F. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_avx512f(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::AVX512F) + } + + /// Supports AVX512DQ. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_avx512dq(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::AVX512DQ) + } + + /// AVX512_IFMA + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_avx512_ifma(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::AVX512_IFMA) + } + + /// AVX512PF + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_avx512pf(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::AVX512PF) + } + + /// AVX512ER + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_avx512er(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::AVX512ER) + } + + /// AVX512CD + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_avx512cd(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::AVX512CD) + } + + /// AVX512BW + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_avx512bw(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::AVX512BW) + } + + /// AVX512VL + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_avx512vl(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::AVX512VL) + } + + /// CLWB + /// + /// # Platforms + /// ✅ AMD ✅ Intel + #[inline] + pub const fn has_clwb(&self) -> bool { + self.ebx.contains(ExtendedFeaturesEbx::CLWB) + } + + /// Has PREFETCHWT1 (Intel® Xeon Phiâ„¢ only). + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_prefetchwt1(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::PREFETCHWT1) + } + + /// Supports user-mode instruction prevention if 1. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_umip(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::UMIP) + } + + /// Supports protection keys for user-mode pages. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_pku(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::PKU) + } + + /// OS has set CR4.PKE to enable protection keys (and the RDPKRU/WRPKRU + /// instructions. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_ospke(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::OSPKE) + } + + /// WAITPKG + /// + /// â“ AMD ✅ Intel + #[inline] + pub const fn has_waitpkg(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::WAITPKG) + } + + /// AVX512VBMI2 + /// + /// â“ AMD ✅ Intel + #[inline] + pub const fn has_av512vbmi2(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::AVX512VBMI2) + } + + /// Supports CET shadow stack features. Processors that set this bit define bits 0..2 of the + /// IA32_U_CET and IA32_S_CET MSRs. Enumerates support for the following MSRs: + /// IA32_INTERRUPT_SPP_TABLE_ADDR, IA32_PL3_SSP, IA32_PL2_SSP, IA32_PL1_SSP, and IA32_PL0_SSP. + /// + /// â“ AMD ✅ Intel + #[inline] + pub const fn has_cet_ss(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::GFNI) + } + + /// GFNI + /// + /// â“ AMD ✅ Intel + #[inline] + pub const fn has_gfni(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::GFNI) + } + + /// VAES + /// + /// â“ AMD ✅ Intel + #[inline] + pub const fn has_vaes(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::VAES) + } + + /// VPCLMULQDQ + /// + /// â“ AMD ✅ Intel + #[inline] + pub const fn has_vpclmulqdq(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::VPCLMULQDQ) + } + + /// AVX512VNNI + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_avx512vnni(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::AVX512VNNI) + } + + /// AVX512BITALG + /// + /// â“ AMD ✅ Intel + #[inline] + pub const fn has_avx512bitalg(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::AVX512BITALG) + } + + /// Indicates the following MSRs are supported: IA32_TME_CAPABILITY, IA32_TME_ACTIVATE, + /// IA32_TME_EXCLUDE_MASK, and IA32_TME_EXCLUDE_BASE. + /// + /// â“ AMD ✅ Intel + #[inline] + pub const fn has_tme_en(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::TMEEN) + } + + /// AVX512VPOPCNTDQ + /// + /// â“ AMD ✅ Intel + #[inline] + pub const fn has_avx512vpopcntdq(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::AVX512VPOPCNTDQ) + } + + /// Supports 57-bit linear addresses and five-level paging if 1. + /// + /// # Platforms + /// â“ AMD ✅ Intel + #[inline] + pub const fn has_la57(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::LA57) + } + + /// RDPID and IA32_TSC_AUX are available. + /// + /// # Bug + /// The Intel manual lists RDPID as bit 22 in the ECX register, but AMD + /// lists it as bit 22 in the ebx register. We assumed that the AMD manual + /// was wrong and query ecx, let's see what happens. + /// + /// # Platforms + /// ✅ AMD ✅ Intel + #[inline] + pub const fn has_rdpid(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::RDPID) + } + + /// Supports SGX Launch Configuration. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub const fn has_sgx_lc(&self) -> bool { + self.ecx.contains(ExtendedFeaturesEcx::SGX_LC) + } + + /// The value of MAWAU used by the BNDLDX and BNDSTX instructions in 64-bit mode. + /// + /// # Platforms + /// ⌠AMD (reserved) ✅ Intel + #[inline] + pub fn mawau_value(&self) -> u8 { + get_bits(self.ecx.bits(), 17, 21) as u8 + } +} + +impl Debug for ExtendedFeatures { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ExtendedFeatures") + .field("ebx", &self.ebx) + .field("ecx", &self.ecx) + .field("mawau_value", &self.mawau_value()) + .finish() + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct ExtendedFeaturesEbx: u32 { + /// FSGSBASE. Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE if 1. (Bit 00) + const FSGSBASE = 1 << 0; + /// IA32_TSC_ADJUST MSR is supported if 1. (Bit 01) + const ADJUST_MSR = 1 << 1; + /// Bit 02: SGX. Supports Intel® Software Guard Extensions (Intel® SGX Extensions) if 1. + const SGX = 1 << 2; + /// BMI1 (Bit 03) + const BMI1 = 1 << 3; + /// HLE (Bit 04) + const HLE = 1 << 4; + /// AVX2 (Bit 05) + const AVX2 = 1 << 5; + /// FDP_EXCPTN_ONLY. x87 FPU Data Pointer updated only on x87 exceptions if 1. + const FDP = 1 << 6; + /// SMEP. Supports Supervisor-Mode Execution Prevention if 1. (Bit 07) + const SMEP = 1 << 7; + /// BMI2 (Bit 08) + const BMI2 = 1 << 8; + /// Supports Enhanced REP MOVSB/STOSB if 1. (Bit 09) + const REP_MOVSB_STOSB = 1 << 9; + /// INVPCID. If 1, supports INVPCID instruction for system software that manages process-context identifiers. (Bit 10) + const INVPCID = 1 << 10; + /// RTM (Bit 11) + const RTM = 1 << 11; + /// Supports Intel Resource Director Technology (RDT) Monitoring. (Bit 12) + const RDTM = 1 << 12; + /// Deprecates FPU CS and FPU DS values if 1. (Bit 13) + const DEPRECATE_FPU_CS_DS = 1 << 13; + /// Deprecates FPU CS and FPU DS values if 1. (Bit 14) + const MPX = 1 << 14; + /// Supports Intel Resource Director Technology (RDT) Allocation capability if 1. + const RDTA = 1 << 15; + /// Bit 16: AVX512F. + const AVX512F = 1 << 16; + /// Bit 17: AVX512DQ. + const AVX512DQ = 1 << 17; + /// Supports RDSEED. + const RDSEED = 1 << 18; + /// Supports ADX. + const ADX = 1 << 19; + /// SMAP. Supports Supervisor-Mode Access Prevention (and the CLAC/STAC instructions) if 1. + const SMAP = 1 << 20; + /// Bit 21: AVX512_IFMA. + const AVX512_IFMA = 1 << 21; + // Bit 22: Reserved. + /// Bit 23: CLFLUSHOPT + const CLFLUSHOPT = 1 << 23; + /// Bit 24: CLWB. + const CLWB = 1 << 24; + /// Bit 25: Intel Processor Trace + const PROCESSOR_TRACE = 1 << 25; + /// Bit 26: AVX512PF. (Intel® Xeon Phiâ„¢ only.) + const AVX512PF = 1 << 26; + /// Bit 27: AVX512ER. (Intel® Xeon Phiâ„¢ only.) + const AVX512ER = 1 << 27; + /// Bit 28: AVX512CD. + const AVX512CD = 1 << 28; + /// Bit 29: Intel SHA Extensions + const SHA = 1 << 29; + /// Bit 30: AVX512BW. + const AVX512BW = 1 << 30; + /// Bit 31: AVX512VL. + const AVX512VL = 1 << 31; + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct ExtendedFeaturesEcx: u32 { + /// Bit 0: Prefetch WT1. (Intel® Xeon Phiâ„¢ only). + const PREFETCHWT1 = 1 << 0; + // Bit 01: AVX512_VBMI + const AVX512VBMI = 1 << 1; + /// Bit 02: UMIP. Supports user-mode instruction prevention if 1. + const UMIP = 1 << 2; + /// Bit 03: PKU. Supports protection keys for user-mode pages if 1. + const PKU = 1 << 3; + /// Bit 04: OSPKE. If 1, OS has set CR4.PKE to enable protection keys (and the RDPKRU/WRPKRU instruc-tions). + const OSPKE = 1 << 4; + /// Bit 5: WAITPKG + const WAITPKG = 1 >> 5; + /// Bit 6: AV512_VBMI2 + const AVX512VBMI2 = 1 << 6; + /// Bit 7: CET_SS. Supports CET shadow stack features if 1. Processors that set this bit define bits 0..2 of the + /// IA32_U_CET and IA32_S_CET MSRs. Enumerates support for the following MSRs: + /// IA32_INTERRUPT_SPP_TABLE_ADDR, IA32_PL3_SSP, IA32_PL2_SSP, IA32_PL1_SSP, and IA32_PL0_SSP. + const CETSS = 1 << 7; + /// Bit 8: GFNI + const GFNI = 1 << 8; + /// Bit 9: VAES + const VAES = 1 << 9; + /// Bit 10: VPCLMULQDQ + const VPCLMULQDQ = 1 << 10; + /// Bit 11: AVX512_VNNI + const AVX512VNNI = 1 << 11; + /// Bit 12: AVX512_BITALG + const AVX512BITALG = 1 << 12; + /// Bit 13: TME_EN. If 1, the following MSRs are supported: IA32_TME_CAPABILITY, IA32_TME_ACTIVATE, + /// IA32_TME_EXCLUDE_MASK, and IA32_TME_EXCLUDE_BASE. + const TMEEN = 1 << 13; + /// Bit 14: AVX512_VPOPCNTDQ + const AVX512VPOPCNTDQ = 1 << 14; + + // Bit 15: Reserved. + + /// Bit 16: Supports 57-bit linear addresses and five-level paging if 1. + const LA57 = 1 << 16; + + // Bits 21 - 17: The value of MAWAU used by the BNDLDX and BNDSTX instructions in 64-bit mode + + /// Bit 22: RDPID. RDPID and IA32_TSC_AUX are available if 1. + const RDPID = 1 << 22; + + // Bits 29 - 23: Reserved. + + /// Bit 30: SGX_LC. Supports SGX Launch Configuration if 1. + const SGX_LC = 1 << 30; + } +} + +/// Direct cache access info (LEAF=0x09). +/// +/// # Platforms +/// ⌠AMD (reserved) ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct DirectCacheAccessInfo { + eax: u32, +} + +impl DirectCacheAccessInfo { + /// Value of bits \[31:0\] of IA32_PLATFORM_DCA_CAP MSR (address 1F8H) + pub fn get_dca_cap_value(&self) -> u32 { + self.eax + } +} + +impl Debug for DirectCacheAccessInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("DirectCacheAccessInfo") + .field("dca_cap_value", &self.get_dca_cap_value()) + .finish() + } +} + +/// Info about performance monitoring -- how many counters etc. (LEAF=0x0A) +/// +/// # Platforms +/// ⌠AMD ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct PerformanceMonitoringInfo { + eax: u32, + ebx: PerformanceMonitoringFeaturesEbx, + _ecx: u32, + edx: u32, +} + +impl PerformanceMonitoringInfo { + /// Version ID of architectural performance monitoring. (Bits 07 - 00) + pub fn version_id(&self) -> u8 { + get_bits(self.eax, 0, 7) as u8 + } + + /// Number of general-purpose performance monitoring counter per logical processor. (Bits 15- 08) + pub fn number_of_counters(&self) -> u8 { + get_bits(self.eax, 8, 15) as u8 + } + + /// Bit width of general-purpose, performance monitoring counter. (Bits 23 - 16) + pub fn counter_bit_width(&self) -> u8 { + get_bits(self.eax, 16, 23) as u8 + } + + /// Length of EBX bit vector to enumerate architectural performance monitoring events. (Bits 31 - 24) + pub fn ebx_length(&self) -> u8 { + get_bits(self.eax, 24, 31) as u8 + } + + /// Number of fixed-function performance counters (if Version ID > 1). (Bits 04 - 00) + pub fn fixed_function_counters(&self) -> u8 { + get_bits(self.edx, 0, 4) as u8 + } + + /// Bit width of fixed-function performance counters (if Version ID > 1). (Bits 12- 05) + pub fn fixed_function_counters_bit_width(&self) -> u8 { + get_bits(self.edx, 5, 12) as u8 + } + + check_bit_fn!( + doc = "AnyThread deprecation", + has_any_thread_deprecation, + edx, + 15 + ); + + check_flag!( + doc = "Core cycle event not available if 1.", + is_core_cyc_ev_unavailable, + ebx, + PerformanceMonitoringFeaturesEbx::CORE_CYC_EV_UNAVAILABLE + ); + + check_flag!( + doc = "Instruction retired event not available if 1.", + is_inst_ret_ev_unavailable, + ebx, + PerformanceMonitoringFeaturesEbx::INST_RET_EV_UNAVAILABLE + ); + + check_flag!( + doc = "Reference cycles event not available if 1.", + is_ref_cycle_ev_unavailable, + ebx, + PerformanceMonitoringFeaturesEbx::REF_CYC_EV_UNAVAILABLE + ); + + check_flag!( + doc = "Last-level cache reference event not available if 1.", + is_cache_ref_ev_unavailable, + ebx, + PerformanceMonitoringFeaturesEbx::CACHE_REF_EV_UNAVAILABLE + ); + + check_flag!( + doc = "Last-level cache misses event not available if 1.", + is_ll_cache_miss_ev_unavailable, + ebx, + PerformanceMonitoringFeaturesEbx::LL_CACHE_MISS_EV_UNAVAILABLE + ); + + check_flag!( + doc = "Branch instruction retired event not available if 1.", + is_branch_inst_ret_ev_unavailable, + ebx, + PerformanceMonitoringFeaturesEbx::BRANCH_INST_RET_EV_UNAVAILABLE + ); + + check_flag!( + doc = "Branch mispredict retired event not available if 1.", + is_branch_midpred_ev_unavailable, + ebx, + PerformanceMonitoringFeaturesEbx::BRANCH_MISPRED_EV_UNAVAILABLE + ); +} + +impl Debug for PerformanceMonitoringInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("PerformanceMonitoringInfo") + .field("version_id", &self.version_id()) + .field("number_of_counters", &self.number_of_counters()) + .field("counter_bit_width", &self.counter_bit_width()) + .field("ebx_length", &self.ebx_length()) + .field("fixed_function_counters", &self.fixed_function_counters()) + .field( + "fixed_function_counters_bit_width", + &self.fixed_function_counters_bit_width(), + ) + .finish() + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct PerformanceMonitoringFeaturesEbx: u32 { + /// Core cycle event not available if 1. (Bit 0) + const CORE_CYC_EV_UNAVAILABLE = 1 << 0; + /// Instruction retired event not available if 1. (Bit 01) + const INST_RET_EV_UNAVAILABLE = 1 << 1; + /// Reference cycles event not available if 1. (Bit 02) + const REF_CYC_EV_UNAVAILABLE = 1 << 2; + /// Last-level cache reference event not available if 1. (Bit 03) + const CACHE_REF_EV_UNAVAILABLE = 1 << 3; + /// Last-level cache misses event not available if 1. (Bit 04) + const LL_CACHE_MISS_EV_UNAVAILABLE = 1 << 4; + /// Branch instruction retired event not available if 1. (Bit 05) + const BRANCH_INST_RET_EV_UNAVAILABLE = 1 << 5; + /// Branch mispredict retired event not available if 1. (Bit 06) + const BRANCH_MISPRED_EV_UNAVAILABLE = 1 << 6; + } +} + +/// Information about topology (LEAF=0x0B). +/// +/// Iterates over the system topology in order to retrieve more system +/// information at each level of the topology: how many cores and what kind of +/// cores +/// +/// # Platforms +/// ✅ AMD ✅ Intel +#[derive(Clone)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ExtendedTopologyIter { + #[cfg_attr(feature = "serialize", serde(skip))] + read: CpuIdReader, + level: u32, + is_v2: bool, +} + +/// Gives information about the current level in the topology. +/// +/// How many cores, what type etc. +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ExtendedTopologyLevel { + eax: u32, + ebx: u32, + ecx: u32, + edx: u32, +} + +impl fmt::Debug for ExtendedTopologyLevel { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ExtendedTopologyLevel") + .field("processors", &self.processors()) + .field("number", &self.level_number()) + .field("type", &self.level_type()) + .field("x2apic_id", &self.x2apic_id()) + .field("next_apic_id", &self.shift_right_for_next_apic_id()) + .finish() + } +} + +impl ExtendedTopologyLevel { + /// Number of logical processors at this level type. + /// The number reflects configuration as shipped. + pub fn processors(&self) -> u16 { + get_bits(self.ebx, 0, 15) as u16 + } + + /// Level number. + pub fn level_number(&self) -> u8 { + get_bits(self.ecx, 0, 7) as u8 + } + + // Level type. + pub fn level_type(&self) -> TopologyType { + match get_bits(self.ecx, 8, 15) { + 0 => TopologyType::Invalid, + 1 => TopologyType::SMT, + 2 => TopologyType::Core, + 3 => TopologyType::Module, + 4 => TopologyType::Tile, + 5 => TopologyType::Die, + _ => unreachable!(), + } + } + + /// x2APIC ID the current logical processor. (Bits 31-00) + pub fn x2apic_id(&self) -> u32 { + self.edx + } + + /// Number of bits to shift right on x2APIC ID to get a unique topology ID of the next level type. (Bits 04-00) + /// All logical processors with the same next level ID share current level. + pub fn shift_right_for_next_apic_id(&self) -> u32 { + get_bits(self.eax, 0, 4) + } +} + +/// What type of core we have at this level in the topology (real CPU or hyper-threaded). +#[derive(PartialEq, Eq, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub enum TopologyType { + Invalid = 0, + /// Hyper-thread (Simultaneous multithreading) + SMT = 1, + Core = 2, + Module = 3, + Tile = 4, + Die = 5, +} + +impl fmt::Display for TopologyType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let data = match self { + TopologyType::Invalid => "Invalid", + TopologyType::SMT => "SMT", + TopologyType::Core => "Core", + TopologyType::Module => "Module", + TopologyType::Tile => "Tile", + TopologyType::Die => "Die", + }; + + f.write_str(data) + } +} + +impl Iterator for ExtendedTopologyIter { + type Item = ExtendedTopologyLevel; + + fn next(&mut self) -> Option { + let res = if self.is_v2 { + self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO_V2, self.level) + } else { + self.read.cpuid2(EAX_EXTENDED_TOPOLOGY_INFO, self.level) + }; + self.level += 1; + + let et = ExtendedTopologyLevel { + eax: res.eax, + ebx: res.ebx, + ecx: res.ecx, + edx: res.edx, + }; + + match et.level_type() { + TopologyType::Invalid => None, + _ => Some(et), + } + } +} + +impl Debug for ExtendedTopologyIter { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + let mut debug = f.debug_list(); + self.clone().for_each(|ref item| { + debug.entry(item); + }); + debug.finish() + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct ExtendedStateInfoXCR0Flags: u32 { + /// legacy x87 (Bit 00). + const LEGACY_X87 = 1 << 0; + + /// 128-bit SSE (Bit 01). + const SSE128 = 1 << 1; + + /// 256-bit AVX (Bit 02). + const AVX256 = 1 << 2; + + /// MPX BNDREGS (Bit 03). + const MPX_BNDREGS = 1 << 3; + + /// MPX BNDCSR (Bit 04). + const MPX_BNDCSR = 1 << 4; + + /// AVX512 OPMASK (Bit 05). + const AVX512_OPMASK = 1 << 5; + + /// AVX ZMM Hi256 (Bit 06). + const AVX512_ZMM_HI256 = 1 << 6; + + /// AVX 512 ZMM Hi16 (Bit 07). + const AVX512_ZMM_HI16 = 1 << 7; + + /// PKRU state (Bit 09). + const PKRU = 1 << 9; + + /// IA32_XSS HDC State (Bit 13). + const IA32_XSS_HDC = 1 << 13; + } +} + +bitflags! { + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + struct ExtendedStateInfoXSSFlags: u32 { + /// IA32_XSS PT (Trace Packet) State (Bit 08). + const PT = 1 << 8; + + /// IA32_XSS HDC State (Bit 13). + const HDC = 1 << 13; + } +} + +/// Information for saving/restoring extended register state (LEAF=0x0D). +/// +/// # Platforms +/// ✅ AMD ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ExtendedStateInfo { + #[cfg_attr(feature = "serialize", serde(skip))] + read: CpuIdReader, + eax: ExtendedStateInfoXCR0Flags, + ebx: u32, + ecx: u32, + _edx: u32, + eax1: u32, + ebx1: u32, + ecx1: ExtendedStateInfoXSSFlags, + _edx1: u32, +} + +impl ExtendedStateInfo { + check_flag!( + doc = "Support for legacy x87 in XCR0.", + xcr0_supports_legacy_x87, + eax, + ExtendedStateInfoXCR0Flags::LEGACY_X87 + ); + + check_flag!( + doc = "Support for SSE 128-bit in XCR0.", + xcr0_supports_sse_128, + eax, + ExtendedStateInfoXCR0Flags::SSE128 + ); + + check_flag!( + doc = "Support for AVX 256-bit in XCR0.", + xcr0_supports_avx_256, + eax, + ExtendedStateInfoXCR0Flags::AVX256 + ); + + check_flag!( + doc = "Support for MPX BNDREGS in XCR0.", + xcr0_supports_mpx_bndregs, + eax, + ExtendedStateInfoXCR0Flags::MPX_BNDREGS + ); + + check_flag!( + doc = "Support for MPX BNDCSR in XCR0.", + xcr0_supports_mpx_bndcsr, + eax, + ExtendedStateInfoXCR0Flags::MPX_BNDCSR + ); + + check_flag!( + doc = "Support for AVX512 OPMASK in XCR0.", + xcr0_supports_avx512_opmask, + eax, + ExtendedStateInfoXCR0Flags::AVX512_OPMASK + ); + + check_flag!( + doc = "Support for AVX512 ZMM Hi256 XCR0.", + xcr0_supports_avx512_zmm_hi256, + eax, + ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI256 + ); + + check_flag!( + doc = "Support for AVX512 ZMM Hi16 in XCR0.", + xcr0_supports_avx512_zmm_hi16, + eax, + ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI16 + ); + + check_flag!( + doc = "Support for PKRU in XCR0.", + xcr0_supports_pkru, + eax, + ExtendedStateInfoXCR0Flags::PKRU + ); + + check_flag!( + doc = "Support for PT in IA32_XSS.", + ia32_xss_supports_pt, + ecx1, + ExtendedStateInfoXSSFlags::PT + ); + + check_flag!( + doc = "Support for HDC in IA32_XSS.", + ia32_xss_supports_hdc, + ecx1, + ExtendedStateInfoXSSFlags::HDC + ); + + /// Maximum size (bytes, from the beginning of the XSAVE/XRSTOR save area) required by + /// enabled features in XCR0. May be different than ECX if some features at the end of the XSAVE save area + /// are not enabled. + pub fn xsave_area_size_enabled_features(&self) -> u32 { + self.ebx + } + + /// Maximum size (bytes, from the beginning of the XSAVE/XRSTOR save area) of the + /// XSAVE/XRSTOR save area required by all supported features in the processor, + /// i.e all the valid bit fields in XCR0. + pub fn xsave_area_size_supported_features(&self) -> u32 { + self.ecx + } + + /// CPU has xsaveopt feature. + pub fn has_xsaveopt(&self) -> bool { + self.eax1 & 0x1 > 0 + } + + /// Supports XSAVEC and the compacted form of XRSTOR if set. + pub fn has_xsavec(&self) -> bool { + self.eax1 & 0b10 > 0 + } + + /// Supports XGETBV with ECX = 1 if set. + pub fn has_xgetbv(&self) -> bool { + self.eax1 & 0b100 > 0 + } + + /// Supports XSAVES/XRSTORS and IA32_XSS if set. + pub fn has_xsaves_xrstors(&self) -> bool { + self.eax1 & 0b1000 > 0 + } + + /// The size in bytes of the XSAVE area containing all states enabled by XCRO | IA32_XSS. + pub fn xsave_size(&self) -> u32 { + self.ebx1 + } + + /// Iterator over extended state enumeration levels >= 2. + pub fn iter(&self) -> ExtendedStateIter { + ExtendedStateIter { + read: self.read, + level: 1, + supported_xcr0: self.eax.bits(), + supported_xss: self.ecx1.bits(), + } + } +} + +impl Debug for ExtendedStateInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ExtendedStateInfo") + .field("eax", &self.eax) + .field("ecx1", &self.ecx1) + .field( + "xsave_area_size_enabled_features", + &self.xsave_area_size_enabled_features(), + ) + .field( + "xsave_area_size_supported_features", + &self.xsave_area_size_supported_features(), + ) + .field("has_xsaveopt", &self.has_xsaveopt()) + .field("has_xsavec", &self.has_xsavec()) + .field("has_xgetbv", &self.has_xgetbv()) + .field("has_xsaves_xrstors", &self.has_xsaves_xrstors()) + .field("xsave_size", &self.xsave_size()) + .field("extended_state_iter", &self.iter()) + .finish() + } +} + +/// Yields [ExtendedState] structs. +#[derive(Clone)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ExtendedStateIter { + #[cfg_attr(feature = "serialize", serde(skip))] + read: CpuIdReader, + level: u32, + supported_xcr0: u32, + supported_xss: u32, +} + +/// When CPUID executes with EAX set to 0DH and ECX = n (n > 1, and is a valid +/// sub-leaf index), the processor returns information about the size and offset +/// of each processor extended state save area within the XSAVE/XRSTOR area. +/// +/// The iterator goes over the valid sub-leaves and obtain size and offset +/// information for each processor extended state save area: +impl Iterator for ExtendedStateIter { + type Item = ExtendedState; + + fn next(&mut self) -> Option { + self.level += 1; + if self.level > 31 { + return None; + } + + let bit = 1 << self.level; + if (self.supported_xcr0 & bit > 0) || (self.supported_xss & bit > 0) { + let res = self.read.cpuid2(EAX_EXTENDED_STATE_INFO, self.level); + return Some(ExtendedState { + subleaf: self.level, + eax: res.eax, + ebx: res.ebx, + ecx: res.ecx, + }); + } + + self.next() + } +} + +impl Debug for ExtendedStateIter { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let mut debug = f.debug_list(); + self.clone().for_each(|ref item| { + debug.entry(item); + }); + debug.finish() + } +} + +/// What kidn of extended register state this is. +#[derive(PartialEq, Eq, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[repr(u32)] +pub enum ExtendedRegisterType { + Avx, + MpxBndregs, + MpxBndcsr, + Avx512Opmask, + Avx512ZmmHi256, + Avx512ZmmHi16, + Pt, + Pkru, + Hdc, + Unknown(u32), +} + +impl From for ExtendedRegisterType { + fn from(value: u32) -> ExtendedRegisterType { + match value { + 0x2 => ExtendedRegisterType::Avx, + 0x3 => ExtendedRegisterType::MpxBndregs, + 0x4 => ExtendedRegisterType::MpxBndcsr, + 0x5 => ExtendedRegisterType::Avx512Opmask, + 0x6 => ExtendedRegisterType::Avx512ZmmHi256, + 0x7 => ExtendedRegisterType::Avx512ZmmHi16, + 0x8 => ExtendedRegisterType::Pt, + 0x9 => ExtendedRegisterType::Pkru, + 0xd => ExtendedRegisterType::Hdc, + x => ExtendedRegisterType::Unknown(x), + } + } +} + +impl fmt::Display for ExtendedRegisterType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let data = match self { + ExtendedRegisterType::Avx => "AVX/YMM", + ExtendedRegisterType::MpxBndregs => "MPX BNDREGS", + ExtendedRegisterType::MpxBndcsr => "MPX BNDCSR", + ExtendedRegisterType::Avx512Opmask => "AVX-512 opmask", + ExtendedRegisterType::Avx512ZmmHi256 => "AVX-512 ZMM_Hi256", + ExtendedRegisterType::Avx512ZmmHi16 => "AVX-512 Hi16_ZMM", + ExtendedRegisterType::Pkru => "PKRU", + ExtendedRegisterType::Pt => "PT", + ExtendedRegisterType::Hdc => "HDC", + ExtendedRegisterType::Unknown(t) => { + return write!(f, "Unknown({})", t); + } + }; + + f.write_str(data) + } +} + +/// Where the extended register state is stored. +#[derive(PartialEq, Eq, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub enum ExtendedRegisterStateLocation { + Xcr0, + Ia32Xss, +} + +impl fmt::Display for ExtendedRegisterStateLocation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let data = match self { + ExtendedRegisterStateLocation::Xcr0 => "XCR0 (user state)", + ExtendedRegisterStateLocation::Ia32Xss => "IA32_XSS (supervisor state)", + }; + + f.write_str(data) + } +} + +/// ExtendedState subleaf structure for things that need to be restored. +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ExtendedState { + pub subleaf: u32, + eax: u32, + ebx: u32, + ecx: u32, +} + +impl ExtendedState { + /// Returns which register this specific extended subleaf contains information for. + pub fn register(&self) -> ExtendedRegisterType { + self.subleaf.into() + } + + /// The size in bytes (from the offset specified in EBX) of the save area + /// for an extended state feature associated with a valid sub-leaf index, n. + /// This field reports 0 if the sub-leaf index, n, is invalid. + pub fn size(&self) -> u32 { + self.eax + } + + /// The offset in bytes of this extended state components save area + /// from the beginning of the XSAVE/XRSTOR area. + pub fn offset(&self) -> u32 { + self.ebx + } + + pub fn location(&self) -> ExtendedRegisterStateLocation { + if self.is_in_xcr0() { + ExtendedRegisterStateLocation::Xcr0 + } else { + ExtendedRegisterStateLocation::Ia32Xss + } + } + + /// True if the bit n (corresponding to the sub-leaf index) + /// is supported in the IA32_XSS MSR; + /// + /// # Deprecation note + /// This will likely be removed in the future. Use `location()` instead. + pub fn is_in_ia32_xss(&self) -> bool { + self.ecx & 0b1 > 0 + } + + /// True if bit n is supported in XCR0. + /// + /// # Deprecation note + /// This will likely be removed in the future. Use `location()` instead. + pub fn is_in_xcr0(&self) -> bool { + self.ecx & 0b1 == 0 + } + + /// Returns true when the compacted format of an XSAVE area is used, + /// this extended state component located on the next 64-byte + /// boundary following the preceding state component + /// (otherwise, it is located immediately following the preceding state component). + pub fn is_compacted_format(&self) -> bool { + self.ecx & 0b10 > 0 + } +} + +impl Debug for ExtendedState { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("ExtendedState") + .field("size", &self.size()) + .field("offset", &self.offset()) + .field("is_in_ia32_xss", &self.is_in_ia32_xss()) + .field("is_in_xcr0", &self.is_in_xcr0()) + .field("is_compacted_format", &self.is_compacted_format()) + .finish() + } +} + +/// Intel Resource Director Technology RDT (LEAF=0x0F). +/// +/// Monitoring Enumeration Sub-leaf (EAX = 0FH, ECX = 0 and ECX = 1) +/// # Platforms +/// ⌠AMD ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct RdtMonitoringInfo { + #[cfg_attr(feature = "serialize", serde(skip))] + read: CpuIdReader, + ebx: u32, + edx: u32, +} + +impl RdtMonitoringInfo { + /// Maximum range (zero-based) of RMID within this physical processor of all types. + pub fn rmid_range(&self) -> u32 { + self.ebx + } + + check_bit_fn!( + doc = "Supports L3 Cache Intel RDT Monitoring.", + has_l3_monitoring, + edx, + 1 + ); + + /// L3 Cache Monitoring. + pub fn l3_monitoring(&self) -> Option { + if self.has_l3_monitoring() { + let res = self.read.cpuid2(EAX_RDT_MONITORING, 1); + Some(L3MonitoringInfo { + ebx: res.ebx, + ecx: res.ecx, + edx: res.edx, + }) + } else { + None + } + } +} + +impl Debug for RdtMonitoringInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("RdtMonitoringInfo") + .field("rmid_range", &self.rmid_range()) + .field("l3_monitoring", &self.l3_monitoring()) + .finish() + } +} + +/// Information about L3 cache monitoring. +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct L3MonitoringInfo { + ebx: u32, + ecx: u32, + edx: u32, +} + +impl L3MonitoringInfo { + /// Conversion factor from reported IA32_QM_CTR value to occupancy metric (bytes). + pub fn conversion_factor(&self) -> u32 { + self.ebx + } + + /// Maximum range (zero-based) of RMID of L3. + pub fn maximum_rmid_range(&self) -> u32 { + self.ecx + } + + check_bit_fn!( + doc = "Supports occupancy monitoring.", + has_occupancy_monitoring, + edx, + 0 + ); + + check_bit_fn!( + doc = "Supports total bandwidth monitoring.", + has_total_bandwidth_monitoring, + edx, + 1 + ); + + check_bit_fn!( + doc = "Supports local bandwidth monitoring.", + has_local_bandwidth_monitoring, + edx, + 2 + ); +} + +impl Debug for L3MonitoringInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("L3MonitoringInfo") + .field("conversion_factor", &self.conversion_factor()) + .field("maximum_rmid_range", &self.maximum_rmid_range()) + .finish() + } +} + +/// Quality of service enforcement information (LEAF=0x10). +/// +/// # Platforms +/// ⌠AMD ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct RdtAllocationInfo { + #[cfg_attr(feature = "serialize", serde(skip))] + read: CpuIdReader, + ebx: u32, +} + +impl RdtAllocationInfo { + check_bit_fn!(doc = "Supports L3 Cache Allocation.", has_l3_cat, ebx, 1); + + check_bit_fn!(doc = "Supports L2 Cache Allocation.", has_l2_cat, ebx, 2); + + check_bit_fn!( + doc = "Supports Memory Bandwidth Allocation.", + has_memory_bandwidth_allocation, + ebx, + 3 + ); + + /// L3 Cache Allocation Information. + pub fn l3_cat(&self) -> Option { + if self.has_l3_cat() { + let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 1); + Some(L3CatInfo { + eax: res.eax, + ebx: res.ebx, + ecx: res.ecx, + edx: res.edx, + }) + } else { + None + } + } + + /// L2 Cache Allocation Information. + pub fn l2_cat(&self) -> Option { + if self.has_l2_cat() { + let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 2); + Some(L2CatInfo { + eax: res.eax, + ebx: res.ebx, + edx: res.edx, + }) + } else { + None + } + } + + /// Memory Bandwidth Allocation Information. + pub fn memory_bandwidth_allocation(&self) -> Option { + if self.has_memory_bandwidth_allocation() { + let res = self.read.cpuid2(EAX_RDT_ALLOCATION, 3); + Some(MemBwAllocationInfo { + eax: res.eax, + ecx: res.ecx, + edx: res.edx, + }) + } else { + None + } + } +} + +impl Debug for RdtAllocationInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("RdtAllocationInfo") + .field("l3_cat", &self.l3_cat()) + .field("l2_cat", &self.l2_cat()) + .field( + "memory_bandwidth_allocation", + &self.memory_bandwidth_allocation(), + ) + .finish() + } +} + +/// L3 Cache Allocation Technology Enumeration Sub-leaf (LEAF=0x10, SUBLEAF=1). +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct L3CatInfo { + eax: u32, + ebx: u32, + ecx: u32, + edx: u32, +} + +impl L3CatInfo { + /// Length of the capacity bit mask. + pub fn capacity_mask_length(&self) -> u8 { + (get_bits(self.eax, 0, 4) + 1) as u8 + } + + /// Bit-granular map of isolation/contention of allocation units. + pub fn isolation_bitmap(&self) -> u32 { + self.ebx + } + + /// Highest COS number supported for this Leaf. + pub fn highest_cos(&self) -> u16 { + get_bits(self.edx, 0, 15) as u16 + } + + check_bit_fn!( + doc = "Is Code and Data Prioritization Technology supported?", + has_code_data_prioritization, + ecx, + 2 + ); +} + +impl Debug for L3CatInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("L3CatInfo") + .field("capacity_mask_length", &self.capacity_mask_length()) + .field("isolation_bitmap", &self.isolation_bitmap()) + .field("highest_cos", &self.highest_cos()) + .finish() + } +} + +/// L2 Cache Allocation Technology Enumeration Sub-leaf (LEAF=0x10, SUBLEAF=2). +#[derive(Eq, PartialEq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct L2CatInfo { + eax: u32, + ebx: u32, + edx: u32, +} + +impl L2CatInfo { + /// Length of the capacity bit mask. + pub fn capacity_mask_length(&self) -> u8 { + (get_bits(self.eax, 0, 4) + 1) as u8 + } + + /// Bit-granular map of isolation/contention of allocation units. + pub fn isolation_bitmap(&self) -> u32 { + self.ebx + } + + /// Highest COS number supported for this Leaf. + pub fn highest_cos(&self) -> u16 { + get_bits(self.edx, 0, 15) as u16 + } +} + +impl Debug for L2CatInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("L2CatInfo") + .field("capacity_mask_length", &self.capacity_mask_length()) + .field("isolation_bitmap", &self.isolation_bitmap()) + .field("highest_cos", &self.highest_cos()) + .finish() + } +} + +/// Memory Bandwidth Allocation Enumeration Sub-leaf (LEAF=0x10, SUBLEAF=3). +#[derive(Eq, PartialEq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct MemBwAllocationInfo { + eax: u32, + ecx: u32, + edx: u32, +} + +impl MemBwAllocationInfo { + /// Reports the maximum MBA throttling value supported for the corresponding ResID. + pub fn max_hba_throttling(&self) -> u16 { + (get_bits(self.eax, 0, 11) + 1) as u16 + } + + /// Highest COS number supported for this Leaf. + pub fn highest_cos(&self) -> u16 { + get_bits(self.edx, 0, 15) as u16 + } + + check_bit_fn!( + doc = "Reports whether the response of the delay values is linear.", + has_linear_response_delay, + ecx, + 2 + ); +} + +impl Debug for MemBwAllocationInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("MemBwAllocationInfo") + .field("max_hba_throttling", &self.max_hba_throttling()) + .field("highest_cos", &self.highest_cos()) + .field( + "has_linear_response_delay", + &self.has_linear_response_delay(), + ) + .finish() + } +} + +/// Intel SGX Capability Enumeration Leaf (LEAF=0x12). +/// +/// Two sub-leafs: (EAX = 12H, ECX = 0 and ECX = 1) +/// +/// # Platforms +/// ⌠AMD ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct SgxInfo { + #[cfg_attr(feature = "serialize", serde(skip))] + read: CpuIdReader, + eax: u32, + ebx: u32, + _ecx: u32, + edx: u32, + eax1: u32, + ebx1: u32, + ecx1: u32, + edx1: u32, +} + +impl SgxInfo { + check_bit_fn!(doc = "Has SGX1 support.", has_sgx1, eax, 0); + check_bit_fn!(doc = "Has SGX2 support.", has_sgx2, eax, 1); + + check_bit_fn!( + doc = "Supports ENCLV instruction leaves EINCVIRTCHILD, EDECVIRTCHILD, and ESETCONTEXT.", + has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext, + eax, + 5 + ); + + check_bit_fn!( + doc = "Supports ENCLS instruction leaves ETRACKC, ERDINFO, ELDBC, and ELDUC.", + has_encls_leaves_etrackc_erdinfo_eldbc_elduc, + eax, + 6 + ); + + /// Bit vector of supported extended SGX features. + pub fn miscselect(&self) -> u32 { + self.ebx + } + + /// The maximum supported enclave size in non-64-bit mode is 2^retval. + pub fn max_enclave_size_non_64bit(&self) -> u8 { + get_bits(self.edx, 0, 7) as u8 + } + + /// The maximum supported enclave size in 64-bit mode is 2^retval. + pub fn max_enclave_size_64bit(&self) -> u8 { + get_bits(self.edx, 8, 15) as u8 + } + + /// Reports the valid bits of SECS.ATTRIBUTES\[127:0\] that software can set with ECREATE. + pub fn secs_attributes(&self) -> (u64, u64) { + let lower = self.eax1 as u64 | (self.ebx1 as u64) << 32; + let upper = self.ecx1 as u64 | (self.edx1 as u64) << 32; + (lower, upper) + } + /// Iterator over SGX sub-leafs. + pub fn iter(&self) -> SgxSectionIter { + SgxSectionIter { + read: self.read, + current: 2, + } + } +} + +impl Debug for SgxInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("SgxInfo") + .field("has_sgx1", &self.has_sgx1()) + .field("has_sgx2", &self.has_sgx2()) + .field("miscselect", &self.miscselect()) + .field( + "max_enclave_size_non_64bit", + &self.max_enclave_size_non_64bit(), + ) + .field("max_enclave_size_64bit", &self.max_enclave_size_64bit()) + .field( + "has_encls_leaves_etrackc_erdinfo_eldbc_elduc", + &self.has_encls_leaves_etrackc_erdinfo_eldbc_elduc(), + ) + .field( + "has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext", + &self.has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext(), + ) + .field("sgx_section_iter", &self.iter()) + .finish() + } +} + +/// Iterator over the SGX sub-leafs (ECX >= 2). +#[derive(Clone)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct SgxSectionIter { + #[cfg_attr(feature = "serialize", serde(skip))] + read: CpuIdReader, + current: u32, +} + +impl Iterator for SgxSectionIter { + type Item = SgxSectionInfo; + + fn next(&mut self) -> Option { + let res = self.read.cpuid2(EAX_SGX, self.current); + self.current += 1; + match get_bits(res.eax, 0, 3) { + 0b0001 => Some(SgxSectionInfo::Epc(EpcSection { + eax: res.eax, + ebx: res.ebx, + ecx: res.ecx, + edx: res.edx, + })), + _ => None, + } + } +} + +impl Debug for SgxSectionIter { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + let mut debug = f.debug_list(); + self.clone().for_each(|ref item| { + debug.entry(item); + }); + debug.finish() + } +} + +/// Intel SGX EPC Enumeration Leaf +/// +/// Sub-leaves 2 or higher. +#[derive(Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub enum SgxSectionInfo { + // This would be nice: https://github.com/rust-lang/rfcs/pull/1450 + Epc(EpcSection), +} + +/// EBX:EAX and EDX:ECX provide information on the Enclave Page Cache (EPC) section +#[derive(Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct EpcSection { + eax: u32, + ebx: u32, + ecx: u32, + edx: u32, +} + +impl EpcSection { + /// The physical address of the base of the EPC section + pub fn physical_base(&self) -> u64 { + let lower = (get_bits(self.eax, 12, 31) << 12) as u64; + let upper = (get_bits(self.ebx, 0, 19) as u64) << 32; + lower | upper + } + + /// Size of the corresponding EPC section within the Processor Reserved Memory. + pub fn size(&self) -> u64 { + let lower = (get_bits(self.ecx, 12, 31) << 12) as u64; + let upper = (get_bits(self.edx, 0, 19) as u64) << 32; + lower | upper + } +} + +/// Intel Processor Trace Information (LEAF=0x14). +/// +/// # Platforms +/// ⌠AMD ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ProcessorTraceInfo { + _eax: u32, + ebx: u32, + ecx: u32, + _edx: u32, + leaf1: Option, +} + +impl ProcessorTraceInfo { + // EBX features + check_bit_fn!( + doc = "If true, Indicates that IA32_RTIT_CTL.CR3Filter can be set to 1, and \ + that IA32_RTIT_CR3_MATCH MSR can be accessed.", + has_rtit_cr3_match, + ebx, + 0 + ); + check_bit_fn!( + doc = "If true, Indicates support of Configurable PSB and Cycle-Accurate Mode.", + has_configurable_psb_and_cycle_accurate_mode, + ebx, + 1 + ); + check_bit_fn!( + doc = "If true, Indicates support of IP Filtering, TraceStop filtering, and \ + preservation of Intel PT MSRs across warm reset.", + has_ip_tracestop_filtering, + ebx, + 2 + ); + check_bit_fn!( + doc = "If true, Indicates support of MTC timing packet and suppression of \ + COFI-based packets.", + has_mtc_timing_packet_coefi_suppression, + ebx, + 3 + ); + + check_bit_fn!( + doc = "Indicates support of PTWRITE. Writes can set IA32_RTIT_CTL\\[12\\] (PTWEn \ + and IA32_RTIT_CTL\\[5\\] (FUPonPTW), and PTWRITE can generate packets", + has_ptwrite, + ebx, + 4 + ); + + check_bit_fn!( + doc = "Support of Power Event Trace. Writes can set IA32_RTIT_CTL\\[4\\] (PwrEvtEn) \ + enabling Power Event Trace packet generation.", + has_power_event_trace, + ebx, + 5 + ); + + // ECX features + check_bit_fn!( + doc = "If true, Tracing can be enabled with IA32_RTIT_CTL.ToPA = 1, hence \ + utilizing the ToPA output scheme; IA32_RTIT_OUTPUT_BASE and \ + IA32_RTIT_OUTPUT_MASK_PTRS MSRs can be accessed.", + has_topa, + ecx, + 0 + ); + check_bit_fn!( + doc = "If true, ToPA tables can hold any number of output entries, up to the \ + maximum allowed by the MaskOrTableOffset field of \ + IA32_RTIT_OUTPUT_MASK_PTRS.", + has_topa_maximum_entries, + ecx, + 1 + ); + check_bit_fn!( + doc = "If true, Indicates support of Single-Range Output scheme.", + has_single_range_output_scheme, + ecx, + 2 + ); + check_bit_fn!( + doc = "If true, Indicates support of output to Trace Transport subsystem.", + has_trace_transport_subsystem, + ecx, + 3 + ); + check_bit_fn!( + doc = "If true, Generated packets which contain IP payloads have LIP values, \ + which include the CS base component.", + has_lip_with_cs_base, + ecx, + 31 + ); + + /// Number of configurable Address Ranges for filtering (Bits 2:0). + pub fn configurable_address_ranges(&self) -> u8 { + self.leaf1.map_or(0, |res| get_bits(res.eax, 0, 2) as u8) + } + + /// Bitmap of supported MTC period encodings (Bit 31:16). + pub fn supported_mtc_period_encodings(&self) -> u16 { + self.leaf1.map_or(0, |res| get_bits(res.eax, 16, 31) as u16) + } + + /// Bitmap of supported Cycle Threshold value encodings (Bits 15-0). + pub fn supported_cycle_threshold_value_encodings(&self) -> u16 { + self.leaf1.map_or(0, |res| get_bits(res.ebx, 0, 15) as u16) + } + + /// Bitmap of supported Configurable PSB frequency encodings (Bit 31:16) + pub fn supported_psb_frequency_encodings(&self) -> u16 { + self.leaf1.map_or(0, |res| get_bits(res.ebx, 16, 31) as u16) + } +} + +impl Debug for ProcessorTraceInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ProcessorTraceInfo") + .field( + "configurable_address_ranges", + &self.configurable_address_ranges(), + ) + .field( + "supported_mtc_period_encodings", + &self.supported_mtc_period_encodings(), + ) + .field( + "supported_cycle_threshold_value_encodings", + &self.supported_cycle_threshold_value_encodings(), + ) + .field( + "supported_psb_frequency_encodings", + &self.supported_psb_frequency_encodings(), + ) + .finish() + } +} + +/// Time Stamp Counter/Core Crystal Clock Information (LEAF=0x15). +/// +/// # Platforms +/// ⌠AMD ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct TscInfo { + eax: u32, + ebx: u32, + ecx: u32, +} + +impl fmt::Debug for TscInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("TscInfo") + .field("denominator", &self.denominator()) + .field("numerator", &self.numerator()) + .field("nominal_frequency", &self.nominal_frequency()) + .field("tsc_frequency", &self.tsc_frequency()) + .finish() + } +} + +impl TscInfo { + /// An unsigned integer which is the denominator of the TSC/â€core crystal clock†ratio. + pub fn denominator(&self) -> u32 { + self.eax + } + + /// An unsigned integer which is the numerator of the TSC/â€core crystal clock†ratio. + /// + /// If this is 0, the TSC/â€core crystal clock†ratio is not enumerated. + pub fn numerator(&self) -> u32 { + self.ebx + } + + /// An unsigned integer which is the nominal frequency of the core crystal clock in Hz. + /// + /// If this is 0, the nominal core crystal clock frequency is not enumerated. + pub fn nominal_frequency(&self) -> u32 { + self.ecx + } + + /// “TSC frequency†= “core crystal clock frequency†* EBX/EAX. + pub fn tsc_frequency(&self) -> Option { + // In some case TscInfo is a valid leaf, but the values reported are still 0 + // we should avoid a division by zero in case denominator ends up being 0. + if self.nominal_frequency() == 0 || self.numerator() == 0 || self.denominator() == 0 { + return None; + } + + Some(self.nominal_frequency() as u64 * self.numerator() as u64 / self.denominator() as u64) + } +} + +/// Processor Frequency Information (LEAF=0x16). +/// +/// # Platforms +/// ⌠AMD ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct ProcessorFrequencyInfo { + eax: u32, + ebx: u32, + ecx: u32, +} + +impl ProcessorFrequencyInfo { + /// Processor Base Frequency (in MHz). + pub fn processor_base_frequency(&self) -> u16 { + get_bits(self.eax, 0, 15) as u16 + } + + /// Maximum Frequency (in MHz). + pub fn processor_max_frequency(&self) -> u16 { + get_bits(self.ebx, 0, 15) as u16 + } + + /// Bus (Reference) Frequency (in MHz). + pub fn bus_frequency(&self) -> u16 { + get_bits(self.ecx, 0, 15) as u16 + } +} + +impl fmt::Debug for ProcessorFrequencyInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ProcessorFrequencyInfo") + .field("processor_base_frequency", &self.processor_base_frequency()) + .field("processor_max_frequency", &self.processor_max_frequency()) + .field("bus_frequency", &self.bus_frequency()) + .finish() + } +} + +/// Deterministic Address Translation Structure Iterator (LEAF=0x18). +/// +/// # Platforms +/// ⌠AMD ✅ Intel +#[derive(Clone)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct DatIter { + #[cfg_attr(feature = "serialize", serde(skip))] + read: CpuIdReader, + current: u32, + count: u32, +} + +impl Iterator for DatIter { + type Item = DatInfo; + + /// Iterate over each sub-leaf with an address translation structure. + fn next(&mut self) -> Option { + loop { + // Sub-leaf index n is invalid if n exceeds the value that sub-leaf 0 returns in EAX + if self.current > self.count { + return None; + } + + let res = self + .read + .cpuid2(EAX_DETERMINISTIC_ADDRESS_TRANSLATION_INFO, self.current); + self.current += 1; + + // A sub-leaf index is also invalid if EDX[4:0] returns 0. + if get_bits(res.edx, 0, 4) == 0 { + // Valid sub-leaves do not need to be contiguous or in any particular order. + // A valid sub-leaf may be in a higher input ECX value than an invalid sub-leaf + // or than a valid sub-leaf of a higher or lower-level struc-ture + continue; + } + + return Some(DatInfo { + _eax: res.eax, + ebx: res.ebx, + ecx: res.ecx, + edx: res.edx, + }); + } + } +} + +impl Debug for DatIter { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let mut debug = f.debug_list(); + self.clone().for_each(|ref item| { + debug.entry(item); + }); + debug.finish() + } +} + +/// Deterministic Address Translation Structure +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct DatInfo { + _eax: u32, + ebx: u32, + ecx: u32, + edx: u32, +} + +impl DatInfo { + check_bit_fn!( + doc = "4K page size entries supported by this structure", + has_4k_entries, + ebx, + 0 + ); + + check_bit_fn!( + doc = "2MB page size entries supported by this structure", + has_2mb_entries, + ebx, + 1 + ); + + check_bit_fn!( + doc = "4MB page size entries supported by this structure", + has_4mb_entries, + ebx, + 2 + ); + + check_bit_fn!( + doc = "1GB page size entries supported by this structure", + has_1gb_entries, + ebx, + 3 + ); + + check_bit_fn!( + doc = "Fully associative structure", + is_fully_associative, + edx, + 8 + ); + + /// Partitioning (0: Soft partitioning between the logical processors sharing this structure). + pub fn partitioning(&self) -> u8 { + get_bits(self.ebx, 8, 10) as u8 + } + + /// Ways of associativity. + pub fn ways(&self) -> u16 { + get_bits(self.ebx, 16, 31) as u16 + } + + /// Number of Sets. + pub fn sets(&self) -> u32 { + self.ecx + } + + /// Translation cache type field. + pub fn cache_type(&self) -> DatType { + match get_bits(self.edx, 0, 4) as u8 { + 0b00001 => DatType::DataTLB, + 0b00010 => DatType::InstructionTLB, + 0b00011 => DatType::UnifiedTLB, + 0b00000 => DatType::Null, // should never be returned as this indicates invalid struct! + 0b00100 => DatType::LoadOnly, + 0b00101 => DatType::StoreOnly, + _ => DatType::Unknown, + } + } + + /// Translation cache level (starts at 1) + pub fn cache_level(&self) -> u8 { + get_bits(self.edx, 5, 7) as u8 + } + + /// Maximum number of addressable IDs for logical processors sharing this translation cache + pub fn max_addressable_ids(&self) -> u16 { + // Add one to the return value to get the result: + (get_bits(self.edx, 14, 25) + 1) as u16 + } +} + +impl Debug for DatInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("DatInfo") + .field("has_4k_entries", &self.has_4k_entries()) + .field("has_2mb_entries", &self.has_2mb_entries()) + .field("has_4mb_entries", &self.has_4mb_entries()) + .field("has_1gb_entries", &self.has_1gb_entries()) + .field("is_fully_associative", &self.is_fully_associative()) + .finish() + } +} + +/// Deterministic Address Translation cache type (EDX bits 04 -- 00) +#[derive(Eq, PartialEq, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub enum DatType { + /// Null (indicates this sub-leaf is not valid). + Null = 0b00000, + DataTLB = 0b00001, + InstructionTLB = 0b00010, + /// Some unified TLBs will allow a single TLB entry to satisfy data read/write + /// and instruction fetches. Others will require separate entries (e.g., one + /// loaded on data read/write and another loaded on an instruction fetch) . + /// Please see the Intel® 64 and IA-32 Architectures Optimization Reference Manual + /// for details of a particular product. + UnifiedTLB = 0b00011, + LoadOnly = 0b0100, + StoreOnly = 0b0101, + Unknown, +} + +impl fmt::Display for DatType { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let t = match self { + DatType::Null => "invalid (0)", + DatType::DataTLB => "Data TLB", + DatType::InstructionTLB => "Instruction TLB", + DatType::UnifiedTLB => "Unified TLB", + DatType::LoadOnly => "Load Only", + DatType::StoreOnly => "Store Only", + DatType::Unknown => "Unknown", + }; + f.write_str(t) + } +} + +/// SoC vendor specific information (LEAF=0x17). +/// +/// # Platforms +/// ⌠AMD ✅ Intel +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct SoCVendorInfo { + #[cfg_attr(feature = "serialize", serde(skip))] + read: CpuIdReader, + /// MaxSOCID_Index + eax: u32, + ebx: u32, + ecx: u32, + edx: u32, +} + +impl SoCVendorInfo { + pub fn get_soc_vendor_id(&self) -> u16 { + get_bits(self.ebx, 0, 15) as u16 + } + + pub fn get_project_id(&self) -> u32 { + self.ecx + } + + pub fn get_stepping_id(&self) -> u32 { + self.edx + } + + pub fn get_vendor_brand(&self) -> Option { + // Leaf 17H is valid if MaxSOCID_Index >= 3. + if self.eax >= 3 { + let r1 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 1); + let r2 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 2); + let r3 = self.read.cpuid2(EAX_SOC_VENDOR_INFO, 3); + Some(SoCVendorBrand { data: [r1, r2, r3] }) + } else { + None + } + } + + pub fn get_vendor_attributes(&self) -> Option { + if self.eax > 3 { + Some(SoCVendorAttributesIter { + read: self.read, + count: self.eax, + current: 3, + }) + } else { + None + } + } +} + +impl fmt::Debug for SoCVendorInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SoCVendorInfo") + .field("soc_vendor_id", &self.get_soc_vendor_id()) + .field("project_id", &self.get_project_id()) + .field("stepping_id", &self.get_stepping_id()) + .field("vendor_brand", &self.get_vendor_brand()) + .field("vendor_attributes", &self.get_vendor_attributes()) + .finish() + } +} + +/// Iterator for SoC vendor attributes. +#[derive(Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct SoCVendorAttributesIter { + #[cfg_attr(feature = "serialize", serde(skip))] + read: CpuIdReader, + count: u32, + current: u32, +} + +impl Iterator for SoCVendorAttributesIter { + type Item = CpuIdResult; + + /// Iterate over all SoC vendor specific attributes. + fn next(&mut self) -> Option { + if self.current > self.count { + return None; + } + self.count += 1; + Some(self.read.cpuid2(EAX_SOC_VENDOR_INFO, self.count)) + } +} + +/// A vendor brand string as queried from the cpuid leaf. +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[repr(C)] +pub struct SoCVendorBrand { + data: [CpuIdResult; 3], +} + +impl SoCVendorBrand { + /// Return the SocVendorBrand as a string. + pub fn as_str(&self) -> &str { + let brand_string_start = self as *const SoCVendorBrand as *const u8; + let slice = unsafe { + // Safety: SoCVendorBrand is laid out with repr(C). + slice::from_raw_parts(brand_string_start, size_of::()) + }; + str::from_utf8(slice).unwrap_or("InvalidSoCVendorString") + } + + #[deprecated( + since = "10.0.0", + note = "Use idiomatic function name `as_str` instead" + )] + pub fn as_string(&self) -> &str { + self.as_str() + } +} + +impl fmt::Display for SoCVendorBrand { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +/// Information about Hypervisor (LEAF=0x4000_0001) +/// +/// More information about this semi-official leaf can be found here +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +pub struct HypervisorInfo { + #[cfg_attr(feature = "serialize", serde(skip))] + read: CpuIdReader, + res: CpuIdResult, +} + +impl fmt::Debug for HypervisorInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("HypervisorInfo") + .field("identify", &self.identify()) + .field("tsc_frequency", &self.tsc_frequency()) + .field("apic_frequency", &self.apic_frequency()) + .finish() + } +} + +/// Identifies the different Hypervisor products. +#[derive(Debug, Eq, PartialEq)] +pub enum Hypervisor { + Xen, + VMware, + HyperV, + KVM, + /// QEMU is the hypervisor identity when QEMU is used + /// without an accelerator, such as KVM. + QEMU, + Bhyve, + QNX, + ACRN, + Unknown(u32, u32, u32), +} + +impl HypervisorInfo { + /// Returns the identity of the [`Hypervisor`]. + /// + /// ## Technical Background + /// + /// The value is a 12-byte (12 character) fixed-length ASCII string. + /// + /// Usually all of these IDs can be found in the original source code on + /// Github relatively easy (if the project is open source). Once you + /// have an ID, you find cumulated lists with all kinds of IDs on Github + /// relatively easy. + pub fn identify(&self) -> Hypervisor { + match (self.res.ebx, self.res.ecx, self.res.edx) { + // "VMwareVMware" (0x56 => V, 0x4d => M, ...) + (0x61774d56, 0x4d566572, 0x65726177) => Hypervisor::VMware, + // "XenVMMXenVMM" + (0x566e6558, 0x65584d4d, 0x4d4d566e) => Hypervisor::Xen, + // "Microsoft Hv" + (0x7263694d, 0x666f736f, 0x76482074) => Hypervisor::HyperV, + // "KVMKVMKVM\0\0\0" + (0x4b4d564b, 0x564b4d56, 0x0000004d) => Hypervisor::KVM, + // "TCGTCGTCGTCG" + // see https://github.com/qemu/qemu/blob/6512fa497c2fa9751b9d774ab32d87a9764d1958/target/i386/cpu.c + (0x54474354, 0x43544743, 0x47435447) => Hypervisor::QEMU, + // "bhyve bhyve " + // found this in another library ("heim-virt") + (0x76796862, 0x68622065, 0x20657679) => Hypervisor::Bhyve, + // "BHyVE BHyVE " + // But this value is in the original source code. To be safe, we keep both. + // See https://github.com/lattera/bhyve/blob/5946a9115d2771a1d27f14a835c7fbc05b30f7f9/sys/amd64/vmm/x86.c#L165 + (0x56794842, 0x48422045, 0x20455679) => Hypervisor::Bhyve, + // "QNXQVMBSQG" + // This can be verified in multiple Git repos (e.g. by Intel) + // https://github.com/search?q=QNXQVMBSQG&type=code + (0x51584e51, 0x53424d56, 0x00004751) => Hypervisor::QNX, + // "ACRNACRNACRN" + (0x4e524341, 0x4e524341, 0x4e524341) => Hypervisor::ACRN, + (ebx, ecx, edx) => Hypervisor::Unknown(ebx, ecx, edx), + } + } + + /// TSC frequency in kHz. + pub fn tsc_frequency(&self) -> Option { + // vm aware tsc frequency retrieval: + // # EAX: (Virtual) TSC frequency in kHz. + if self.res.eax >= 0x40000010 { + let virt_tinfo = self.read.cpuid2(0x40000010, 0); + Some(virt_tinfo.eax) + } else { + None + } + } + + /// (Virtual) Bus (local apic timer) frequency in kHz. + pub fn apic_frequency(&self) -> Option { + // # EBX: (Virtual) Bus (local apic timer) frequency in kHz. + if self.res.eax >= 0x40000010 { + let virt_tinfo = self.read.cpuid2(0x40000010, 0); + Some(virt_tinfo.ebx) + } else { + None + } + } +} + +#[cfg(doctest)] +mod test_readme { + macro_rules! external_doc_test { + ($x:expr) => { + #[doc = $x] + extern "C" {} + }; + } + + external_doc_test!(include_str!("../README.md")); +} diff --git a/vendor/raw-cpuid-10.7.0/src/tests/i5_3337u.rs b/vendor/raw-cpuid-10.7.0/src/tests/i5_3337u.rs new file mode 100644 index 0000000000000..b36eb56a79179 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/src/tests/i5_3337u.rs @@ -0,0 +1,743 @@ +use crate::*; + +#[test] +fn genuine_intel() { + let vf = VendorInfo { + ebx: 1970169159, + edx: 1231384169, + ecx: 1818588270, + }; + assert!(vf.as_str() == "GenuineIntel"); +} + +#[test] +fn feature_info() { + let finfo = FeatureInfo { + vendor: Vendor::Intel, + eax: 198313, + ebx: 34605056, + edx_ecx: FeatureInfoFlags { + bits: 2109399999 | 3219913727 << 32, + }, + }; + + assert!(finfo.base_model_id() == 10); + assert!(finfo.extended_model_id() == 3); + assert!(finfo.stepping_id() == 9); + assert!(finfo.extended_family_id() == 0); + assert!(finfo.base_family_id() == 6); + assert!(finfo.stepping_id() == 9); + assert!(finfo.brand_index() == 0); + + assert!(finfo.edx_ecx.contains(FeatureInfoFlags::SSE2)); + assert!(finfo.edx_ecx.contains(FeatureInfoFlags::SSE41)); +} + +#[test] +fn cache_info() { + let cinfos = CacheInfoIter { + current: 1, + eax: 1979931137, + ebx: 15774463, + ecx: 0, + edx: 13238272, + }; + for (idx, cache) in cinfos.enumerate() { + match idx { + 0 => assert!(cache.num == 0xff), + 1 => assert!(cache.num == 0x5a), + 2 => assert!(cache.num == 0xb2), + 3 => assert!(cache.num == 0x03), + 4 => assert!(cache.num == 0xf0), + 5 => assert!(cache.num == 0xca), + 6 => assert!(cache.num == 0x76), + _ => unreachable!(), + } + } +} + +#[test] +fn cache_parameters() { + let caches: [CacheParameter; 4] = [ + CacheParameter { + eax: 469778721, + ebx: 29360191, + ecx: 63, + edx: 0, + }, + CacheParameter { + eax: 469778722, + ebx: 29360191, + ecx: 63, + edx: 0, + }, + CacheParameter { + eax: 469778755, + ebx: 29360191, + ecx: 511, + edx: 0, + }, + CacheParameter { + eax: 470008163, + ebx: 46137407, + ecx: 4095, + edx: 6, + }, + ]; + + for (idx, cache) in caches.iter().enumerate() { + match idx { + 0 => { + assert!(cache.cache_type() == CacheType::Data); + assert!(cache.level() == 1); + assert!(cache.is_self_initializing()); + assert!(!cache.is_fully_associative()); + assert!(cache.max_cores_for_cache() == 2); + assert!(cache.max_cores_for_package() == 8); + assert!(cache.coherency_line_size() == 64); + assert!(cache.physical_line_partitions() == 1); + assert!(cache.associativity() == 8); + assert!(!cache.is_write_back_invalidate()); + assert!(!cache.is_inclusive()); + assert!(!cache.has_complex_indexing()); + assert!(cache.sets() == 64); + } + 1 => { + assert!(cache.cache_type() == CacheType::Instruction); + assert!(cache.level() == 1); + assert!(cache.is_self_initializing()); + assert!(!cache.is_fully_associative()); + assert!(cache.max_cores_for_cache() == 2); + assert!(cache.max_cores_for_package() == 8); + assert!(cache.coherency_line_size() == 64); + assert!(cache.physical_line_partitions() == 1); + assert!(cache.associativity() == 8); + assert!(!cache.is_write_back_invalidate()); + assert!(!cache.is_inclusive()); + assert!(!cache.has_complex_indexing()); + assert!(cache.sets() == 64); + } + 2 => { + assert!(cache.cache_type() == CacheType::Unified); + assert!(cache.level() == 2); + assert!(cache.is_self_initializing()); + assert!(!cache.is_fully_associative()); + assert!(cache.max_cores_for_cache() == 2); + assert!(cache.max_cores_for_package() == 8); + assert!(cache.coherency_line_size() == 64); + assert!(cache.physical_line_partitions() == 1); + assert!(cache.associativity() == 8); + assert!(!cache.is_write_back_invalidate()); + assert!(!cache.is_inclusive()); + assert!(!cache.has_complex_indexing()); + assert!(cache.sets() == 512); + } + 3 => { + assert!(cache.cache_type() == CacheType::Unified); + assert!(cache.level() == 3); + assert!(cache.is_self_initializing()); + assert!(!cache.is_fully_associative()); + assert!(cache.max_cores_for_cache() == 16); + assert!(cache.max_cores_for_package() == 8); + assert!(cache.coherency_line_size() == 64); + assert!(cache.physical_line_partitions() == 1); + assert!(cache.associativity() == 12); + assert!(!cache.is_write_back_invalidate()); + assert!(cache.is_inclusive()); + assert!(cache.has_complex_indexing()); + assert!(cache.sets() == 4096); + } + _ => unreachable!(), + } + } +} + +#[test] +fn monitor_mwait_features() { + let mmfeatures = MonitorMwaitInfo { + eax: 64, + ebx: 64, + ecx: 3, + edx: 135456, + }; + assert!(mmfeatures.smallest_monitor_line() == 64); + assert!(mmfeatures.largest_monitor_line() == 64); + assert!(mmfeatures.extensions_supported()); + assert!(mmfeatures.interrupts_as_break_event()); + assert!(mmfeatures.supported_c0_states() == 0); + assert!(mmfeatures.supported_c1_states() == 2); + assert!(mmfeatures.supported_c2_states() == 1); + assert!(mmfeatures.supported_c3_states() == 1); + assert!(mmfeatures.supported_c4_states() == 2); + assert!(mmfeatures.supported_c5_states() == 0); + assert!(mmfeatures.supported_c6_states() == 0); + assert!(mmfeatures.supported_c7_states() == 0); +} + +#[test] +fn thermal_power_features() { + let tpfeatures = ThermalPowerInfo { + eax: ThermalPowerFeaturesEax { bits: 119 }, + ebx: 2, + ecx: ThermalPowerFeaturesEcx { bits: 9 }, + _edx: 0, + }; + + assert!(tpfeatures.eax.contains(ThermalPowerFeaturesEax::DTS)); + assert!(tpfeatures + .eax + .contains(ThermalPowerFeaturesEax::TURBO_BOOST)); + assert!(tpfeatures.eax.contains(ThermalPowerFeaturesEax::ARAT)); + assert!(tpfeatures.eax.contains(ThermalPowerFeaturesEax::PLN)); + assert!(tpfeatures.eax.contains(ThermalPowerFeaturesEax::ECMD)); + assert!(tpfeatures.eax.contains(ThermalPowerFeaturesEax::PTM)); + + assert!(tpfeatures + .ecx + .contains(ThermalPowerFeaturesEcx::HW_COORD_FEEDBACK)); + assert!(tpfeatures + .ecx + .contains(ThermalPowerFeaturesEcx::ENERGY_BIAS_PREF)); + + assert!(tpfeatures.dts_irq_threshold() == 0x2); + let tpfeatures = ThermalPowerInfo { + eax: ThermalPowerFeaturesEax::DTS + | ThermalPowerFeaturesEax::TURBO_BOOST + | ThermalPowerFeaturesEax::ARAT + | ThermalPowerFeaturesEax::PLN + | ThermalPowerFeaturesEax::ECMD + | ThermalPowerFeaturesEax::PTM + | ThermalPowerFeaturesEax::HWP + | ThermalPowerFeaturesEax::HWP_NOTIFICATION + | ThermalPowerFeaturesEax::HWP_ACTIVITY_WINDOW + | ThermalPowerFeaturesEax::HWP_ENERGY_PERFORMANCE_PREFERENCE + | ThermalPowerFeaturesEax::HDC, + ebx: 2, + ecx: ThermalPowerFeaturesEcx::HW_COORD_FEEDBACK | ThermalPowerFeaturesEcx::ENERGY_BIAS_PREF, + _edx: 0, + }; + + assert!(tpfeatures.has_dts()); + assert!(!tpfeatures.has_turbo_boost3()); + assert!(tpfeatures.has_turbo_boost()); + assert!(tpfeatures.has_arat()); + assert!(tpfeatures.has_pln()); + assert!(tpfeatures.has_ecmd()); + assert!(tpfeatures.has_ptm()); + assert!(tpfeatures.has_hwp()); + assert!(tpfeatures.has_hwp_notification()); + assert!(tpfeatures.has_hwp_activity_window()); + assert!(tpfeatures.has_hwp_energy_performance_preference()); + assert!(!tpfeatures.has_hwp_package_level_request()); + assert!(tpfeatures.has_hdc()); + assert!(tpfeatures.has_hw_coord_feedback()); + assert!(tpfeatures.has_energy_bias_pref()); + assert!(tpfeatures.dts_irq_threshold() == 0x2); +} + +#[test] +fn extended_features() { + let tpfeatures = ExtendedFeatures { + _eax: 0, + ebx: ExtendedFeaturesEbx { bits: 641 }, + ecx: ExtendedFeaturesEcx { bits: 0 }, + _edx: 0, + }; + assert!(tpfeatures._eax == 0); + assert!(tpfeatures.has_fsgsbase()); + assert!(!tpfeatures.has_tsc_adjust_msr()); + assert!(!tpfeatures.has_bmi1()); + assert!(!tpfeatures.has_hle()); + assert!(!tpfeatures.has_avx2()); + assert!(tpfeatures.has_smep()); + assert!(!tpfeatures.has_bmi2()); + assert!(tpfeatures.has_rep_movsb_stosb()); + assert!(!tpfeatures.has_invpcid()); + assert!(!tpfeatures.has_rtm()); + assert!(!tpfeatures.has_rdtm()); + assert!(!tpfeatures.has_fpu_cs_ds_deprecated()); + + let tpfeatures2 = ExtendedFeatures { + _eax: 0, + ebx: ExtendedFeaturesEbx::FSGSBASE + | ExtendedFeaturesEbx::ADJUST_MSR + | ExtendedFeaturesEbx::BMI1 + | ExtendedFeaturesEbx::AVX2 + | ExtendedFeaturesEbx::SMEP + | ExtendedFeaturesEbx::BMI2 + | ExtendedFeaturesEbx::REP_MOVSB_STOSB + | ExtendedFeaturesEbx::INVPCID + | ExtendedFeaturesEbx::DEPRECATE_FPU_CS_DS + | ExtendedFeaturesEbx::MPX + | ExtendedFeaturesEbx::RDSEED + | ExtendedFeaturesEbx::ADX + | ExtendedFeaturesEbx::SMAP + | ExtendedFeaturesEbx::CLFLUSHOPT + | ExtendedFeaturesEbx::PROCESSOR_TRACE, + ecx: ExtendedFeaturesEcx { bits: 0 }, + _edx: 201326592, + }; + + assert!(tpfeatures2.has_fsgsbase()); + assert!(tpfeatures2.has_tsc_adjust_msr()); + assert!(tpfeatures2.has_bmi1()); + assert!(tpfeatures2.has_avx2()); + assert!(tpfeatures2.has_smep()); + assert!(tpfeatures2.has_bmi2()); + assert!(tpfeatures2.has_rep_movsb_stosb()); + assert!(tpfeatures2.has_invpcid()); + assert!(tpfeatures2.has_fpu_cs_ds_deprecated()); + assert!(tpfeatures2.has_mpx()); + assert!(tpfeatures2.has_rdseed()); + assert!(tpfeatures2.has_adx()); + assert!(tpfeatures2.has_smap()); + assert!(tpfeatures2.has_clflushopt()); + assert!(tpfeatures2.has_processor_trace()); +} + +#[test] +fn direct_cache_access_info() { + let dca = DirectCacheAccessInfo { eax: 0x1 }; + assert!(dca.get_dca_cap_value() == 0x1); +} + +#[test] +fn performance_monitoring_info() { + let pm = PerformanceMonitoringInfo { + eax: 120587267, + ebx: PerformanceMonitoringFeaturesEbx { bits: 0 }, + _ecx: 0, + edx: 1539, + }; + + assert!(pm.version_id() == 3); + assert!(pm.number_of_counters() == 4); + assert!(pm.counter_bit_width() == 48); + assert!(pm.ebx_length() == 7); + assert!(pm.fixed_function_counters() == 3); + assert!(pm.fixed_function_counters_bit_width() == 48); + + assert!(!pm + .ebx + .contains(PerformanceMonitoringFeaturesEbx::CORE_CYC_EV_UNAVAILABLE)); + assert!(!pm + .ebx + .contains(PerformanceMonitoringFeaturesEbx::INST_RET_EV_UNAVAILABLE)); + assert!(!pm + .ebx + .contains(PerformanceMonitoringFeaturesEbx::REF_CYC_EV_UNAVAILABLE)); + assert!(!pm + .ebx + .contains(PerformanceMonitoringFeaturesEbx::CACHE_REF_EV_UNAVAILABLE)); + assert!(!pm + .ebx + .contains(PerformanceMonitoringFeaturesEbx::LL_CACHE_MISS_EV_UNAVAILABLE)); + assert!(!pm + .ebx + .contains(PerformanceMonitoringFeaturesEbx::BRANCH_INST_RET_EV_UNAVAILABLE)); + assert!(!pm + .ebx + .contains(PerformanceMonitoringFeaturesEbx::BRANCH_MISPRED_EV_UNAVAILABLE)); +} + +#[cfg(test)] +#[test] +fn extended_topology_info() { + let l1 = ExtendedTopologyLevel { + eax: 1, + ebx: 2, + ecx: 256, + edx: 3, + }; + let l2 = ExtendedTopologyLevel { + eax: 4, + ebx: 4, + ecx: 513, + edx: 3, + }; + + assert!(l1.processors() == 2); + assert!(l1.level_number() == 0); + assert!(l1.level_type() == TopologyType::SMT); + assert!(l1.x2apic_id() == 3); + assert!(l1.shift_right_for_next_apic_id() == 1); + + assert!(l2.processors() == 4); + assert!(l2.level_number() == 1); + assert!(l2.level_type() == TopologyType::Core); + assert!(l2.x2apic_id() == 3); + assert!(l2.shift_right_for_next_apic_id() == 4); +} + +#[cfg(test)] +#[test] +fn extended_topology_info_v2() { + let l1 = ExtendedTopologyLevel { + eax: 1, + ebx: 2, + ecx: 256, + edx: 3, + }; + let l2 = ExtendedTopologyLevel { + eax: 4, + ebx: 4, + ecx: 513, + edx: 3, + }; + + assert!(l1.processors() == 2); + assert!(l1.level_number() == 0); + assert!(l1.level_type() == TopologyType::SMT); + assert!(l1.x2apic_id() == 3); + assert!(l1.shift_right_for_next_apic_id() == 1); + + assert!(l2.processors() == 4); + assert!(l2.level_number() == 1); + assert!(l2.level_type() == TopologyType::Core); + assert!(l2.x2apic_id() == 3); + assert!(l2.shift_right_for_next_apic_id() == 4); +} + +#[test] +fn extended_state_info() { + let es = ExtendedStateInfo { + read: Default::default(), + eax: ExtendedStateInfoXCR0Flags { bits: 7 }, + ebx: 832, + ecx: 832, + _edx: 0, + eax1: 1, + ebx1: 0, + ecx1: ExtendedStateInfoXSSFlags { bits: 0 }, + _edx1: 0, + }; + + assert!(es.xsave_area_size_enabled_features() == 832); + assert!(es.xsave_area_size_supported_features() == 832); + assert!(es.has_xsaveopt()); +} + +#[test] +fn extended_state_info3() { + /*let cpuid = CpuId::new(); + cpuid.get_extended_state_info().map(|info| { + println!("{:?}", info); + use std::vec::Vec; + let es: Vec = info.iter().collect(); + println!("{:?}", es); + });*/ + + let esi = ExtendedStateInfo { + read: Default::default(), + eax: ExtendedStateInfoXCR0Flags::LEGACY_X87 + | ExtendedStateInfoXCR0Flags::SSE128 + | ExtendedStateInfoXCR0Flags::AVX256 + | ExtendedStateInfoXCR0Flags::MPX_BNDREGS + | ExtendedStateInfoXCR0Flags::MPX_BNDCSR + | ExtendedStateInfoXCR0Flags::AVX512_OPMASK + | ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI256 + | ExtendedStateInfoXCR0Flags::AVX512_ZMM_HI16 + | ExtendedStateInfoXCR0Flags::PKRU, + ebx: 2688, + ecx: 2696, + _edx: 0, + eax1: 15, + ebx1: 2560, + ecx1: ExtendedStateInfoXSSFlags::PT, + _edx1: 0, + }; + + assert!(esi.xcr0_supports_legacy_x87()); + assert!(esi.xcr0_supports_sse_128()); + assert!(esi.xcr0_supports_avx_256()); + assert!(esi.xcr0_supports_mpx_bndregs()); + assert!(esi.xcr0_supports_mpx_bndcsr()); + assert!(esi.xcr0_supports_avx512_opmask()); + assert!(esi.xcr0_supports_avx512_zmm_hi256()); + assert!(esi.xcr0_supports_avx512_zmm_hi16()); + assert!(esi.xcr0_supports_pkru()); + assert!(esi.ia32_xss_supports_pt()); + assert!(!esi.ia32_xss_supports_hdc()); + + assert!(esi.xsave_area_size_enabled_features() == 2688); + assert!(esi.xsave_area_size_supported_features() == 2696); + + assert!(esi.has_xsaveopt()); + assert!(esi.has_xsavec()); + assert!(esi.has_xgetbv()); + assert!(esi.has_xsaves_xrstors()); + assert!(esi.xsave_size() == 2560); + + let es = [ + ExtendedState { + subleaf: 2, + eax: 256, + ebx: 576, + ecx: 0, + }, + ExtendedState { + subleaf: 3, + eax: 64, + ebx: 960, + ecx: 0, + }, + ExtendedState { + subleaf: 4, + eax: 64, + ebx: 1024, + ecx: 0, + }, + ExtendedState { + subleaf: 5, + eax: 64, + ebx: 1088, + ecx: 0, + }, + ExtendedState { + subleaf: 6, + eax: 512, + ebx: 1152, + ecx: 0, + }, + ExtendedState { + subleaf: 7, + eax: 1024, + ebx: 1664, + ecx: 0, + }, + ExtendedState { + subleaf: 8, + eax: 128, + ebx: 0, + ecx: 1, + }, + ExtendedState { + subleaf: 9, + eax: 8, + ebx: 2688, + ecx: 0, + }, + ]; + + let e = &es[0]; + assert!(e.subleaf == 2); + assert!(e.size() == 256); + assert!(e.offset() == 576); + assert!(e.is_in_xcr0()); + assert!(!e.is_in_ia32_xss()); + assert!(!e.is_compacted_format()); + + let e = &es[1]; + assert!(e.subleaf == 3); + assert!(e.size() == 64); + assert!(e.offset() == 960); + assert!(e.is_in_xcr0()); + assert!(!e.is_in_ia32_xss()); + assert!(!e.is_compacted_format()); + + let e = &es[2]; + assert!(e.subleaf == 4); + assert!(e.size() == 64); + assert!(e.offset() == 1024); + assert!(e.is_in_xcr0()); + assert!(!e.is_in_ia32_xss()); + assert!(!e.is_compacted_format()); + + let e = &es[3]; + assert!(e.subleaf == 5); + assert!(e.size() == 64); + assert!(e.offset() == 1088); + assert!(e.is_in_xcr0()); + assert!(!e.is_in_ia32_xss()); + assert!(!e.is_compacted_format()); + + let e = &es[4]; + assert!(e.subleaf == 6); + assert!(e.size() == 512); + assert!(e.offset() == 1152); + assert!(e.is_in_xcr0()); + assert!(!e.is_in_ia32_xss()); + assert!(!e.is_compacted_format()); + + let e = &es[5]; + assert!(e.subleaf == 7); + assert!(e.size() == 1024); + assert!(e.offset() == 1664); + assert!(e.is_in_xcr0()); + assert!(!e.is_in_ia32_xss()); + assert!(!e.is_compacted_format()); + + let e = &es[6]; + assert!(e.subleaf == 8); + assert!(e.size() == 128); + assert!(e.offset() == 0); + assert!(!e.is_in_xcr0()); + assert!(e.is_in_ia32_xss()); + assert!(!e.is_compacted_format()); + + let e = &es[7]; + assert!(e.subleaf == 9); + assert!(e.size() == 8); + assert!(e.offset() == 2688); + assert!(e.is_in_xcr0()); + assert!(!e.is_in_ia32_xss()); + assert!(!e.is_compacted_format()); +} + +#[test] +fn extended_state_info2() { + let es = ExtendedStateInfo { + read: Default::default(), + eax: ExtendedStateInfoXCR0Flags { bits: 31 }, + ebx: 1088, + ecx: 1088, + _edx: 0, + eax1: 15, + ebx1: 960, + ecx1: ExtendedStateInfoXSSFlags { bits: 256 }, + _edx1: 0, + }; + + assert!(es.xcr0_supports_legacy_x87()); + assert!(es.xcr0_supports_sse_128()); + assert!(es.xcr0_supports_avx_256()); + assert!(es.xcr0_supports_mpx_bndregs()); + assert!(es.xcr0_supports_mpx_bndcsr()); + assert!(!es.xcr0_supports_avx512_opmask()); + assert!(!es.xcr0_supports_pkru()); + assert!(es.ia32_xss_supports_pt()); + + assert!(es.xsave_area_size_enabled_features() == 0x440); + assert!(es.xsave_area_size_supported_features() == 0x440); + + assert!(es.has_xsaveopt()); + assert!(es.has_xsavec()); + assert!(es.has_xgetbv()); + assert!(es.has_xsaves_xrstors()); + assert!(es.xsave_size() == 0x3c0); + + let esiter: [ExtendedState; 3] = [ + ExtendedState { + subleaf: 2, + eax: 256, + ebx: 576, + ecx: 0, + }, + ExtendedState { + subleaf: 3, + eax: 64, + ebx: 960, + ecx: 0, + }, + ExtendedState { + subleaf: 4, + eax: 64, + ebx: 1024, + ecx: 0, + }, + ]; + + let e = &esiter[0]; + assert!(e.subleaf == 2); + assert!(e.size() == 256); + assert!(e.offset() == 576); + assert!(e.is_in_xcr0()); + assert!(!e.is_in_ia32_xss()); + + let e = &esiter[1]; + assert!(e.subleaf == 3); + assert!(e.size() == 64); + assert!(e.offset() == 960); + assert!(e.is_in_xcr0()); + assert!(!e.is_in_ia32_xss()); + + let e = &esiter[2]; + assert!(e.subleaf == 4); + assert!(e.size() == 64); + assert!(e.offset() == 1024); + assert!(e.is_in_xcr0()); + assert!(!e.is_in_ia32_xss()); +} + +#[test] +fn quality_of_service_info() { + let qos = RdtMonitoringInfo { + read: Default::default(), + ebx: 832, + edx: 0, + }; + + assert!(qos.rmid_range() == 832); + assert!(!qos.has_l3_monitoring()); +} + +#[test] +fn extended_processor_feature_identifiers() { + let ef = ExtendedProcessorFeatureIdentifiers::new( + Vendor::Intel, + CpuIdResult { + eax: 0, + ebx: 0, + ecx: 1, + edx: 672139264, + }, + ); + + assert!(ef.has_lahf_sahf()); + assert!(!ef.has_lzcnt()); + assert!(!ef.has_prefetchw()); + assert!(ef.has_syscall_sysret()); + assert!(ef.has_execute_disable()); + assert!(!ef.has_1gib_pages()); + assert!(ef.has_rdtscp()); + assert!(ef.has_64bit_mode()); +} + +#[test] +fn processor_brand_string() { + let pbs = crate::extended::ProcessorBrandString::new([ + CpuIdResult { + eax: 538976288, + ebx: 1226842144, + ecx: 1818588270, + edx: 539578920, + }, + CpuIdResult { + eax: 1701998403, + ebx: 692933672, + ecx: 758475040, + edx: 926102323, + }, + CpuIdResult { + eax: 1346576469, + ebx: 541073493, + ecx: 808988209, + edx: 8013895, + }, + ]); + + assert_eq!(pbs.as_str(), "Intel(R) Core(TM) i5-3337U CPU @ 1.80GHz"); +} + +#[cfg(test)] +#[test] +fn sgx_test() { + let sgx = SgxInfo { + read: Default::default(), + eax: 1, + ebx: 0, + _ecx: 0, + edx: 9247, + eax1: 54, + ebx1: 0, + ecx1: 31, + edx1: 0, + }; + + assert!(sgx.max_enclave_size_64bit() == 0x24); + assert!(sgx.max_enclave_size_non_64bit() == 0x1f); + assert!(sgx.has_sgx1()); + assert!(!sgx.has_sgx2()); + assert!(sgx.miscselect() == 0x0); + assert!(sgx.secs_attributes() == (0x0000000000000036, 0x000000000000001f)); +} diff --git a/vendor/raw-cpuid-10.7.0/src/tests/i7_12700k.rs b/vendor/raw-cpuid-10.7.0/src/tests/i7_12700k.rs new file mode 100644 index 0000000000000..90a07a684d1a2 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/src/tests/i7_12700k.rs @@ -0,0 +1,1541 @@ +use crate::{CpuId, CpuIdResult}; + +// CPU: +// vendor_id = "GenuineIntel" +// version information (1/eax): +// processor type = primary processor (0) +// family = 0x6 (6) +// model = 0x7 (7) +// stepping id = 0x2 (2) +// extended family = 0x0 (0) +// extended model = 0x9 (9) +// (family synth) = 0x6 (6) +// (model synth) = 0x97 (151) +// (simple synth) = Intel Atom (Alder Lake-S) [Golden Cove], 10nm +// miscellaneous (1/ebx): +// process local APIC physical ID = 0x0 (0) +// maximum IDs for CPUs in pkg = 0x80 (128) +// CLFLUSH line size = 0x8 (8) +// brand index = 0x0 (0) +// brand id = 0x00 (0): unknown +// feature information (1/edx): +// x87 FPU on chip = true +// VME: virtual-8086 mode enhancement = true +// DE: debugging extensions = true +// PSE: page size extensions = true +// TSC: time stamp counter = true +// RDMSR and WRMSR support = true +// PAE: physical address extensions = true +// MCE: machine check exception = true +// CMPXCHG8B inst. = true +// APIC on chip = true +// SYSENTER and SYSEXIT = true +// MTRR: memory type range registers = true +// PTE global bit = true +// MCA: machine check architecture = true +// CMOV: conditional move/compare instr = true +// PAT: page attribute table = true +// PSE-36: page size extension = true +// PSN: processor serial number = false +// CLFLUSH instruction = true +// DS: debug store = true +// ACPI: thermal monitor and clock ctrl = true +// MMX Technology = true +// FXSAVE/FXRSTOR = true +// SSE extensions = true +// SSE2 extensions = true +// SS: self snoop = true +// hyper-threading / multi-core supported = true +// TM: therm. monitor = true +// IA64 = false +// PBE: pending break event = true +// feature information (1/ecx): +// PNI/SSE3: Prescott New Instructions = true +// PCLMULDQ instruction = true +// DTES64: 64-bit debug store = true +// MONITOR/MWAIT = true +// CPL-qualified debug store = true +// VMX: virtual machine extensions = true +// SMX: safer mode extensions = true +// Enhanced Intel SpeedStep Technology = true +// TM2: thermal monitor 2 = true +// SSSE3 extensions = true +// context ID: adaptive or shared L1 data = false +// SDBG: IA32_DEBUG_INTERFACE = true +// FMA instruction = true +// CMPXCHG16B instruction = true +// xTPR disable = true +// PDCM: perfmon and debug = true +// PCID: process context identifiers = true +// DCA: direct cache access = false +// SSE4.1 extensions = true +// SSE4.2 extensions = true +// x2APIC: extended xAPIC support = true +// MOVBE instruction = true +// POPCNT instruction = true +// time stamp counter deadline = true +// AES instruction = true +// XSAVE/XSTOR states = true +// OS-enabled XSAVE/XSTOR = true +// AVX: advanced vector extensions = true +// F16C half-precision convert instruction = true +// RDRAND instruction = true +// hypervisor guest status = false +// cache and TLB information (2): +// 0xff: cache data is in CPUID leaf 4 +// 0xfe: TLB data is in CPUID leaf 0x18 +// 0xf0: 64 byte prefetching +// processor serial number = 0009-0672-0000-0000-0000-0000 +// deterministic cache parameters (4): +// --- cache 0 --- +// cache type = data cache (1) +// cache level = 0x1 (1) +// self-initializing cache level = true +// fully associative cache = false +// maximum IDs for CPUs sharing cache = 0x1 (1) +// maximum IDs for cores in pkg = 0x3f (63) +// system coherency line size = 0x40 (64) +// physical line partitions = 0x1 (1) +// ways of associativity = 0xc (12) +// number of sets = 0x40 (64) +// WBINVD/INVD acts on lower caches = false +// inclusive to lower caches = false +// complex cache indexing = false +// number of sets (s) = 64 +// (size synth) = 49152 (48 KB) +// --- cache 1 --- +// cache type = instruction cache (2) +// cache level = 0x1 (1) +// self-initializing cache level = true +// fully associative cache = false +// maximum IDs for CPUs sharing cache = 0x1 (1) +// maximum IDs for cores in pkg = 0x3f (63) +// system coherency line size = 0x40 (64) +// physical line partitions = 0x1 (1) +// ways of associativity = 0x8 (8) +// number of sets = 0x40 (64) +// WBINVD/INVD acts on lower caches = false +// inclusive to lower caches = false +// complex cache indexing = false +// number of sets (s) = 64 +// (size synth) = 32768 (32 KB) +// --- cache 2 --- +// cache type = unified cache (3) +// cache level = 0x2 (2) +// self-initializing cache level = true +// fully associative cache = false +// maximum IDs for CPUs sharing cache = 0x7 (7) +// maximum IDs for cores in pkg = 0x3f (63) +// system coherency line size = 0x40 (64) +// physical line partitions = 0x1 (1) +// ways of associativity = 0xa (10) +// number of sets = 0x800 (2048) +// WBINVD/INVD acts on lower caches = false +// inclusive to lower caches = false +// complex cache indexing = false +// number of sets (s) = 2048 +// (size synth) = 1310720 (1.2 MB) +// --- cache 3 --- +// cache type = unified cache (3) +// cache level = 0x3 (3) +// self-initializing cache level = true +// fully associative cache = false +// maximum IDs for CPUs sharing cache = 0x7f (127) +// maximum IDs for cores in pkg = 0x3f (63) +// system coherency line size = 0x40 (64) +// physical line partitions = 0x1 (1) +// ways of associativity = 0xa (10) +// number of sets = 0xa000 (40960) +// WBINVD/INVD acts on lower caches = false +// inclusive to lower caches = false +// complex cache indexing = true +// number of sets (s) = 40960 +// (size synth) = 26214400 (25 MB) +// MONITOR/MWAIT (5): +// smallest monitor-line size (bytes) = 0x40 (64) +// largest monitor-line size (bytes) = 0x40 (64) +// enum of Monitor-MWAIT exts supported = true +// supports intrs as break-event for MWAIT = true +// number of C0 sub C-states using MWAIT = 0x0 (0) +// number of C1 sub C-states using MWAIT = 0x2 (2) +// number of C2 sub C-states using MWAIT = 0x0 (0) +// number of C3 sub C-states using MWAIT = 0x2 (2) +// number of C4 sub C-states using MWAIT = 0x0 (0) +// number of C5 sub C-states using MWAIT = 0x1 (1) +// number of C6 sub C-states using MWAIT = 0x0 (0) +// number of C7 sub C-states using MWAIT = 0x1 (1) +// Thermal and Power Management Features (6): +// digital thermometer = true +// Intel Turbo Boost Technology = true +// ARAT always running APIC timer = true +// PLN power limit notification = true +// ECMD extended clock modulation duty = true +// PTM package thermal management = true +// HWP base registers = true +// HWP notification = true +// HWP activity window = true +// HWP energy performance preference = true +// HWP package level request = true +// HDC base registers = false +// Intel Turbo Boost Max Technology 3.0 = true +// HWP capabilities = true +// HWP PECI override = true +// flexible HWP = true +// IA32_HWP_REQUEST MSR fast access mode = true +// HW_FEEDBACK MSRs supported = true +// ignoring idle logical processor HWP req = true +// enhanced hardware feedback interface = true +// digital thermometer thresholds = 0x2 (2) +// hardware coordination feedback = true +// ACNT2 available = false +// performance-energy bias capability = false +// number of enh hardware feedback classes = 0x4 (4) +// performance capability reporting = true +// energy efficiency capability reporting = true +// size of feedback struct (4KB pages) = 0x1 (1) +// index of CPU's row in feedback struct = 0x0 (0) +// extended feature flags (7): +// FSGSBASE instructions = true +// IA32_TSC_ADJUST MSR supported = true +// SGX: Software Guard Extensions supported = false +// BMI1 instructions = true +// HLE hardware lock elision = false +// AVX2: advanced vector extensions 2 = true +// FDP_EXCPTN_ONLY = true +// SMEP supervisor mode exec protection = true +// BMI2 instructions = true +// enhanced REP MOVSB/STOSB = true +// INVPCID instruction = true +// RTM: restricted transactional memory = false +// RDT-CMT/PQoS cache monitoring = false +// deprecated FPU CS/DS = true +// MPX: intel memory protection extensions = false +// RDT-CAT/PQE cache allocation = false +// AVX512F: AVX-512 foundation instructions = false +// AVX512DQ: double & quadword instructions = false +// RDSEED instruction = true +// ADX instructions = true +// SMAP: supervisor mode access prevention = true +// AVX512IFMA: fused multiply add = false +// PCOMMIT instruction = false +// CLFLUSHOPT instruction = true +// CLWB instruction = true +// Intel processor trace = true +// AVX512PF: prefetch instructions = false +// AVX512ER: exponent & reciprocal instrs = false +// AVX512CD: conflict detection instrs = false +// SHA instructions = true +// AVX512BW: byte & word instructions = false +// AVX512VL: vector length = false +// PREFETCHWT1 = false +// AVX512VBMI: vector byte manipulation = false +// UMIP: user-mode instruction prevention = true +// PKU protection keys for user-mode = true +// OSPKE CR4.PKE and RDPKRU/WRPKRU = true +// WAITPKG instructions = true +// AVX512_VBMI2: byte VPCOMPRESS, VPEXPAND = false +// CET_SS: CET shadow stack = true +// GFNI: Galois Field New Instructions = true +// VAES instructions = true +// VPCLMULQDQ instruction = true +// AVX512_VNNI: neural network instructions = false +// AVX512_BITALG: bit count/shiffle = false +// TME: Total Memory Encryption = true +// AVX512: VPOPCNTDQ instruction = false +// 5-level paging = false +// BNDLDX/BNDSTX MAWAU value in 64-bit mode = 0x0 (0) +// RDPID: read processor D supported = true +// KL: key locker = true +// CLDEMOTE supports cache line demote = false +// MOVDIRI instruction = true +// MOVDIR64B instruction = true +// ENQCMD instruction = false +// SGX_LC: SGX launch config supported = false +// PKS: supervisor protection keys = true +// AVX512_4VNNIW: neural network instrs = false +// AVX512_4FMAPS: multiply acc single prec = false +// fast short REP MOV = true +// UINTR: user interrupts = false +// AVX512_VP2INTERSECT: intersect mask regs = false +// SRBDS mitigation MSR available = false +// VERW MD_CLEAR microcode support = true +// SERIALIZE instruction = true +// hybrid part = true +// TSXLDTRK: TSX suspend load addr tracking = false +// PCONFIG instruction = true +// LBR: architectural last branch records = true +// CET_IBT: CET indirect branch tracking = true +// AMX-BF16: tile bfloat16 support = false +// AVX512_FP16: fp16 support = false +// AMX-TILE: tile architecture support = false +// AMX-INT8: tile 8-bit integer support = false +// IBRS/IBPB: indirect branch restrictions = true +// STIBP: 1 thr indirect branch predictor = true +// L1D_FLUSH: IA32_FLUSH_CMD MSR = true +// IA32_ARCH_CAPABILITIES MSR = true +// IA32_CORE_CAPABILITIES MSR = true +// SSBD: speculative store bypass disable = true +// AVX-VNNI: AVX VNNI neural network instrs = true +// AVX512_BF16: bfloat16 instructions = false +// zero-length MOVSB = false +// fast short STOSB = true +// fast short CMPSB, SCASB = false +// HRESET: history reset support = true +// Direct Cache Access Parameters (9): +// PLATFORM_DCA_CAP MSR bits = 0 +// Architecture Performance Monitoring Features (0xa): +// version ID = 0x5 (5) +// number of counters per logical processor = 0x6 (6) +// bit width of counter = 0x30 (48) +// length of EBX bit vector = 0x7 (7) +// core cycle event not available = false +// instruction retired event not available = false +// reference cycles event not available = false +// last-level cache ref event not available = false +// last-level cache miss event not avail = false +// branch inst retired event not available = false +// branch mispred retired event not avail = false +// fixed counter 0 supported = true +// fixed counter 1 supported = true +// fixed counter 2 supported = true +// fixed counter 3 supported = false +// fixed counter 4 supported = false +// fixed counter 5 supported = false +// fixed counter 6 supported = false +// fixed counter 7 supported = false +// fixed counter 8 supported = false +// fixed counter 9 supported = false +// fixed counter 10 supported = false +// fixed counter 11 supported = false +// fixed counter 12 supported = false +// fixed counter 13 supported = false +// fixed counter 14 supported = false +// fixed counter 15 supported = false +// fixed counter 16 supported = false +// fixed counter 17 supported = false +// fixed counter 18 supported = false +// fixed counter 19 supported = false +// fixed counter 20 supported = false +// fixed counter 21 supported = false +// fixed counter 22 supported = false +// fixed counter 23 supported = false +// fixed counter 24 supported = false +// fixed counter 25 supported = false +// fixed counter 26 supported = false +// fixed counter 27 supported = false +// fixed counter 28 supported = false +// fixed counter 29 supported = false +// fixed counter 30 supported = false +// fixed counter 31 supported = false +// number of fixed counters = 0x3 (3) +// bit width of fixed counters = 0x30 (48) +// anythread deprecation = true +// x2APIC features / processor topology (0xb): +// extended APIC ID = 0 +// --- level 0 --- +// level number = 0x0 (0) +// level type = thread (1) +// bit width of level = 0x1 (1) +// number of logical processors at level = 0x2 (2) +// --- level 1 --- +// level number = 0x1 (1) +// level type = core (2) +// bit width of level = 0x7 (7) +// number of logical processors at level = 0x14 (20) +// XSAVE features (0xd/0): +// XCR0 lower 32 bits valid bit field mask = 0x00000207 +// XCR0 upper 32 bits valid bit field mask = 0x00000000 +// XCR0 supported: x87 state = true +// XCR0 supported: SSE state = true +// XCR0 supported: AVX state = true +// XCR0 supported: MPX BNDREGS = false +// XCR0 supported: MPX BNDCSR = false +// XCR0 supported: AVX-512 opmask = false +// XCR0 supported: AVX-512 ZMM_Hi256 = false +// XCR0 supported: AVX-512 Hi16_ZMM = false +// IA32_XSS supported: PT state = false +// XCR0 supported: PKRU state = true +// XCR0 supported: CET_U state = false +// XCR0 supported: CET_S state = false +// IA32_XSS supported: HDC state = false +// IA32_XSS supported: UINTR state = false +// LBR supported = false +// IA32_XSS supported: HWP state = false +// XTILECFG supported = false +// XTILEDATA supported = false +// bytes required by fields in XCR0 = 0x00000a88 (2696) +// bytes required by XSAVE/XRSTOR area = 0x00000a88 (2696) +// XSAVE features (0xd/1): +// XSAVEOPT instruction = true +// XSAVEC instruction = true +// XGETBV instruction = true +// XSAVES/XRSTORS instructions = true +// XFD: extended feature disable supported = false +// SAVE area size in bytes = 0x00000670 (1648) +// IA32_XSS lower 32 bits valid bit field mask = 0x00019900 +// IA32_XSS upper 32 bits valid bit field mask = 0x00000000 +// AVX/YMM features (0xd/2): +// AVX/YMM save state byte size = 0x00000100 (256) +// AVX/YMM save state byte offset = 0x00000240 (576) +// supported in IA32_XSS or XCR0 = XCR0 (user state) +// 64-byte alignment in compacted XSAVE = false +// XFD faulting supported = false +// PT features (0xd/8): +// PT save state byte size = 0x00000080 (128) +// PT save state byte offset = 0x00000000 (0) +// supported in IA32_XSS or XCR0 = IA32_XSS (supervisor state) +// 64-byte alignment in compacted XSAVE = false +// XFD faulting supported = false +// PKRU features (0xd/9): +// PKRU save state byte size = 0x00000008 (8) +// PKRU save state byte offset = 0x00000a80 (2688) +// supported in IA32_XSS or XCR0 = XCR0 (user state) +// 64-byte alignment in compacted XSAVE = false +// XFD faulting supported = false +// CET_U state features (0xd/0xb): +// CET_U state save state byte size = 0x00000010 (16) +// CET_U state save state byte offset = 0x00000000 (0) +// supported in IA32_XSS or XCR0 = IA32_XSS (supervisor state) +// 64-byte alignment in compacted XSAVE = false +// XFD faulting supported = false +// CET_S state features (0xd/0xc): +// CET_S state save state byte size = 0x00000018 (24) +// CET_S state save state byte offset = 0x00000000 (0) +// supported in IA32_XSS or XCR0 = IA32_XSS (supervisor state) +// 64-byte alignment in compacted XSAVE = false +// XFD faulting supported = false +// LBR features (0xd/0xf): +// LBR save state byte size = 0x00000328 (808) +// LBR save state byte offset = 0x00000000 (0) +// supported in IA32_XSS or XCR0 = IA32_XSS (supervisor state) +// 64-byte alignment in compacted XSAVE = false +// XFD faulting supported = false +// HWP state features (0xd/0x10): +// HWP state save state byte size = 0x00000008 (8) +// HWP state save state byte offset = 0x00000000 (0) +// supported in IA32_XSS or XCR0 = IA32_XSS (supervisor state) +// 64-byte alignment in compacted XSAVE = false +// XFD faulting supported = false +// Quality of Service Monitoring Resource Type (0xf/0): +// Maximum range of RMID = 0 +// supports L3 cache QoS monitoring = false +// Resource Director Technology Allocation (0x10/0): +// L3 cache allocation technology supported = false +// L2 cache allocation technology supported = false +// memory bandwidth allocation supported = false +// 0x00000011 0x00: eax=0x00000000 ebx=0x00000000 ecx=0x00000000 edx=0x00000000 +// Software Guard Extensions (SGX) capability (0x12/0): +// SGX1 supported = false +// SGX2 supported = false +// SGX ENCLV E*VIRTCHILD, ESETCONTEXT = false +// SGX ENCLS ETRACKC, ERDINFO, ELDBC, ELDUC = false +// MISCSELECT.EXINFO supported: #PF & #GP = false +// MISCSELECT.CPINFO supported: #CP = false +// MaxEnclaveSize_Not64 (log2) = 0x0 (0) +// MaxEnclaveSize_64 (log2) = 0x0 (0) +// 0x00000013 0x00: eax=0x00000000 ebx=0x00000000 ecx=0x00000000 edx=0x00000000 +// Intel Processor Trace (0x14): +// IA32_RTIT_CR3_MATCH is accessible = true +// configurable PSB & cycle-accurate = true +// IP & TraceStop filtering; PT preserve = true +// MTC timing packet; suppress COFI-based = true +// PTWRITE support = true +// power event trace support = false +// ToPA output scheme support = true +// ToPA can hold many output entries = true +// single-range output scheme support = true +// output to trace transport = false +// IP payloads have LIP values & CS = false +// configurable address ranges = 0x2 (2) +// supported MTC periods bitmask = 0x249 (585) +// supported cycle threshold bitmask = 0x3f (63) +// supported config PSB freq bitmask = 0x3f (63) +// Time Stamp Counter/Core Crystal Clock Information (0x15): +// TSC/clock ratio = 188/2 +// nominal core crystal clock = 38400000 Hz +// Processor Frequency Information (0x16): +// Core Base Frequency (MHz) = 0xe10 (3600) +// Core Maximum Frequency (MHz) = 0x1388 (5000) +// Bus (Reference) Frequency (MHz) = 0x64 (100) +// System-On-Chip Vendor Attribute (0x17/0): +// vendor id = 0x0 (0) +// vendor scheme = assigned by intel +// project id = 0x00000000 (0) +// stepping id = 0x00000000 (0) +// Deterministic Address Translation Parameters (0x18/0): +// 4KB page size entries supported = false +// 2MB page size entries supported = false +// 4MB page size entries supported = false +// 1GB page size entries supported = false +// partitioning = soft between logical processors +// ways of associativity = 0x0 (0) +// number of sets = 0x00000000 (0) +// translation cache type = invalid (0) +// translation cache level = 0x1 (1) +// fully associative = false +// maximum number of addressible IDs = 0x0 (0) +// Deterministic Address Translation Parameters (0x18/1): +// 4KB page size entries supported = true +// 2MB page size entries supported = false +// 4MB page size entries supported = false +// 1GB page size entries supported = false +// partitioning = soft between logical processors +// ways of associativity = 0x8 (8) +// number of sets = 0x00000020 (32) +// translation cache type = instruction TLB +// translation cache level = 0x2 (2) +// fully associative = false +// maximum number of addressible IDs = 0x1 (1) +// Deterministic Address Translation Parameters (0x18/2): +// 4KB page size entries supported = false +// 2MB page size entries supported = true +// 4MB page size entries supported = true +// 1GB page size entries supported = false +// partitioning = soft between logical processors +// ways of associativity = 0x8 (8) +// number of sets = 0x00000004 (4) +// translation cache type = instruction TLB +// translation cache level = 0x2 (2) +// fully associative = false +// maximum number of addressible IDs = 0x1 (1) +// Deterministic Address Translation Parameters (0x18/3): +// 4KB page size entries supported = true +// 2MB page size entries supported = true +// 4MB page size entries supported = true +// 1GB page size entries supported = true +// partitioning = soft between logical processors +// ways of associativity = 0x10 (16) +// number of sets = 0x00000001 (1) +// translation cache type = store-only TLB +// translation cache level = 0x2 (2) +// fully associative = true +// maximum number of addressible IDs = 0x1 (1) +// Deterministic Address Translation Parameters (0x18/4): +// 4KB page size entries supported = true +// 2MB page size entries supported = false +// 4MB page size entries supported = false +// 1GB page size entries supported = false +// partitioning = soft between logical processors +// ways of associativity = 0x4 (4) +// number of sets = 0x00000010 (16) +// translation cache type = load-only TLB +// translation cache level = 0x2 (2) +// fully associative = false +// maximum number of addressible IDs = 0x1 (1) +// Deterministic Address Translation Parameters (0x18/5): +// 4KB page size entries supported = false +// 2MB page size entries supported = true +// 4MB page size entries supported = true +// 1GB page size entries supported = false +// partitioning = soft between logical processors +// ways of associativity = 0x4 (4) +// number of sets = 0x00000008 (8) +// translation cache type = load-only TLB +// translation cache level = 0x2 (2) +// fully associative = false +// maximum number of addressible IDs = 0x1 (1) +// Deterministic Address Translation Parameters (0x18/6): +// 4KB page size entries supported = false +// 2MB page size entries supported = false +// 4MB page size entries supported = false +// 1GB page size entries supported = true +// partitioning = soft between logical processors +// ways of associativity = 0x8 (8) +// number of sets = 0x00000001 (1) +// translation cache type = load-only TLB +// translation cache level = 0x2 (2) +// fully associative = true +// maximum number of addressible IDs = 0x1 (1) +// Deterministic Address Translation Parameters (0x18/7): +// 4KB page size entries supported = true +// 2MB page size entries supported = true +// 4MB page size entries supported = true +// 1GB page size entries supported = false +// partitioning = soft between logical processors +// ways of associativity = 0x8 (8) +// number of sets = 0x00000080 (128) +// translation cache type = unified TLB +// translation cache level = 0x3 (3) +// fully associative = false +// maximum number of addressible IDs = 0x1 (1) +// Deterministic Address Translation Parameters (0x18/8): +// 4KB page size entries supported = true +// 2MB page size entries supported = false +// 4MB page size entries supported = false +// 1GB page size entries supported = true +// partitioning = soft between logical processors +// ways of associativity = 0x8 (8) +// number of sets = 0x00000080 (128) +// translation cache type = unified TLB +// translation cache level = 0x3 (3) +// fully associative = false +// maximum number of addressible IDs = 0x1 (1) +// Key Locker information (0x19): +// CPL0-only restriction supported = true +// no-encrypt restriction supported = true +// no-decrypt restriction supported = true +// AESKLE: AES instructions = false +// AES wide instructions = true +// MSRs & IWKEY backups = true +// LOADIWKEY NoBackup parameter = true +// IWKEY randomization supported = true +// Hybrid Information (0x1a/0): +// native model ID of core = 0x1 (1) +// core type = Intel Core +// PCONFIG information (0x1b/n): +// sub-leaf type = target identifier (1) +// identifier of target 1 = 0x00000001 (1) +// identifier of target 2 = 0x00000000 (0) +// identifier of target 3 = 0x00000000 (0) +// Architectural LBR Capabilities (0x1c/0): +// IA32_LBR_DEPTH.DEPTH 8 supported = true +// IA32_LBR_DEPTH.DEPTH 16 supported = true +// IA32_LBR_DEPTH.DEPTH 24 supported = false +// IA32_LBR_DEPTH.DEPTH 32 supported = true +// IA32_LBR_DEPTH.DEPTH 40 supported = false +// IA32_LBR_DEPTH.DEPTH 48 supported = false +// IA32_LBR_DEPTH.DEPTH 56 supported = false +// IA32_LBR_DEPTH.DEPTH 64 supported = false +// deep C-state reset supported = true +// LBR IP values contain = EIP (0) +// CPL filtering supported = true +// branch filtering supported = true +// call-stack mode supported = true +// mispredict bit supported = true +// timed LBRs supported = true +// branch type field supported = true +// Tile Information (0x1d/0): +// max_palette = 0 +// TMUL Information (0x1e/0): +// tmul_maxk = 0x0 (0) +// tmul_maxn = 0x0 (0) +// V2 extended topology (0x1f): +// x2APIC ID of logical processor = 0x0 (0) +// --- level 0 --- +// level number = 0x0 (0) +// level type = thread (1) +// bit width of level = 0x1 (1) +// number of logical processors at level = 0x2 (2) +// --- level 1 --- +// level number = 0x1 (1) +// level type = core (2) +// bit width of level = 0x7 (7) +// number of logical processors at level = 0x14 (20) +// --- level 2 --- +// level number = 0x2 (2) +// level type = invalid (0) +// bit width of level = 0x0 (0) +// number of logical processors at level = 0x0 (0) +// Processor History Reset information (0x20): +// HRESET supported: EHFI history = true +// extended feature flags (0x80000001/edx): +// SYSCALL and SYSRET instructions = true +// execution disable = true +// 1-GB large page support = true +// RDTSCP = true +// 64-bit extensions technology available = true +// Intel feature flags (0x80000001/ecx): +// LAHF/SAHF supported in 64-bit mode = true +// LZCNT advanced bit manipulation = true +// 3DNow! PREFETCH/PREFETCHW instructions = true +// brand = "12th Gen Intel(R) Core(TM) i7-12700K" +// L1 TLB/cache information: 2M/4M pages & L1 TLB (0x80000005/eax): +// instruction # entries = 0x0 (0) +// instruction associativity = 0x0 (0) +// data # entries = 0x0 (0) +// data associativity = 0x0 (0) +// L1 TLB/cache information: 4K pages & L1 TLB (0x80000005/ebx): +// instruction # entries = 0x0 (0) +// instruction associativity = 0x0 (0) +// data # entries = 0x0 (0) +// data associativity = 0x0 (0) +// L1 data cache information (0x80000005/ecx): +// line size (bytes) = 0x0 (0) +// lines per tag = 0x0 (0) +// associativity = 0x0 (0) +// size (KB) = 0x0 (0) +// L1 instruction cache information (0x80000005/edx): +// line size (bytes) = 0x0 (0) +// lines per tag = 0x0 (0) +// associativity = 0x0 (0) +// size (KB) = 0x0 (0) +// L2 TLB/cache information: 2M/4M pages & L2 TLB (0x80000006/eax): +// instruction # entries = 0x0 (0) +// instruction associativity = L2 off (0) +// data # entries = 0x0 (0) +// data associativity = L2 off (0) +// L2 TLB/cache information: 4K pages & L2 TLB (0x80000006/ebx): +// instruction # entries = 0x0 (0) +// instruction associativity = L2 off (0) +// data # entries = 0x0 (0) +// data associativity = L2 off (0) +// L2 unified cache information (0x80000006/ecx): +// line size (bytes) = 0x40 (64) +// lines per tag = 0x0 (0) +// associativity = 0x7 (7) +// size (KB) = 0x500 (1280) +// L3 cache information (0x80000006/edx): +// line size (bytes) = 0x0 (0) +// lines per tag = 0x0 (0) +// associativity = L2 off (0) +// size (in 512KB units) = 0x0 (0) +// RAS Capability (0x80000007/ebx): +// MCA overflow recovery support = false +// SUCCOR support = false +// HWA: hardware assert support = false +// scalable MCA support = false +// Advanced Power Management Features (0x80000007/ecx): +// CmpUnitPwrSampleTimeRatio = 0x0 (0) +// Advanced Power Management Features (0x80000007/edx): +// TS: temperature sensing diode = false +// FID: frequency ID control = false +// VID: voltage ID control = false +// TTP: thermal trip = false +// TM: thermal monitor = false +// STC: software thermal control = false +// 100 MHz multiplier control = false +// hardware P-State control = false +// TscInvariant = true +// CPB: core performance boost = false +// read-only effective frequency interface = false +// processor feedback interface = false +// APM power reporting = false +// connected standby = false +// RAPL: running average power limit = false +// Physical Address and Linear Address Size (0x80000008/eax): +// maximum physical address bits = 0x2e (46) +// maximum linear (virtual) address bits = 0x30 (48) +// maximum guest physical address bits = 0x0 (0) +// Extended Feature Extensions ID (0x80000008/ebx): +// CLZERO instruction = false +// instructions retired count support = false +// always save/restore error pointers = false +// RDPRU instruction = false +// memory bandwidth enforcement = false +// WBNOINVD instruction = false +// IBPB: indirect branch prediction barrier = false +// IBRS: indirect branch restr speculation = false +// STIBP: 1 thr indirect branch predictor = false +// STIBP always on preferred mode = false +// ppin processor id number supported = false +// SSBD: speculative store bypass disable = false +// virtualized SSBD = false +// SSBD fixed in hardware = false +// Size Identifiers (0x80000008/ecx): +// number of CPU cores = 0x1 (1) +// ApicIdCoreIdSize = 0x0 (0) +// performance time-stamp counter size = 0x0 (0) +// Feature Extended Size (0x80000008/edx): +// RDPRU instruction max input support = 0x0 (0) +// (multi-processing synth) = multi-core (c=20), hyper-threaded (t=2) +// (multi-processing method) = Intel leaf 0x1f +// (APIC widths synth): CORE_width=7 SMT_width=1 +// (APIC synth): PKG_ID=0 CORE_ID=0 SMT_ID=0 +// (uarch synth) = Intel Golden Cove, 10nm +// (synth) = Intel Atom (Alder Lake-S) [Golden Cove], 10nm + +static CPUID_VALUE_MAP: phf::Map = phf::phf_map! { + 0x00000000_00000000u64 => CpuIdResult { eax: 0x00000020, ebx: 0x756e6547, ecx: 0x6c65746e, edx: 0x49656e69 }, + 0x00000001_00000000u64 => CpuIdResult { eax: 0x00090672, ebx: 0x00800800, ecx: 0x7ffafbff, edx: 0xbfebfbff }, + 0x00000002_00000000u64 => CpuIdResult { eax: 0x00feff01, ebx: 0x000000f0, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000003_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000004_00000000u64 => CpuIdResult { eax: 0xfc004121, ebx: 0x02c0003f, ecx: 0x0000003f, edx: 0x00000000 }, + 0x00000004_00000001u64 => CpuIdResult { eax: 0xfc004122, ebx: 0x01c0003f, ecx: 0x0000003f, edx: 0x00000000 }, + 0x00000004_00000002u64 => CpuIdResult { eax: 0xfc01c143, ebx: 0x0240003f, ecx: 0x000007ff, edx: 0x00000000 }, + 0x00000004_00000003u64 => CpuIdResult { eax: 0xfc1fc163, ebx: 0x0240003f, ecx: 0x00009fff, edx: 0x00000004 }, + 0x00000005_00000000u64 => CpuIdResult { eax: 0x00000040, ebx: 0x00000040, ecx: 0x00000003, edx: 0x10102020 }, + 0x00000006_00000000u64 => CpuIdResult { eax: 0x00dfcff7, ebx: 0x00000002, ecx: 0x00000401, edx: 0x00000003 }, + 0x00000007_00000000u64 => CpuIdResult { eax: 0x00000002, ebx: 0x239c27eb, ecx: 0x98c027bc, edx: 0xfc1cc410 }, + 0x00000007_00000001u64 => CpuIdResult { eax: 0x00400810, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000007_00000002u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000001 }, + 0x00000008_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000009_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000a_00000000u64 => CpuIdResult { eax: 0x07300605, ebx: 0x00000000, ecx: 0x00000007, edx: 0x00008603 }, + 0x0000000b_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x00000002, ecx: 0x00000100, edx: 0x00000000 }, + 0x0000000b_00000001u64 => CpuIdResult { eax: 0x00000007, ebx: 0x00000014, ecx: 0x00000201, edx: 0x00000000 }, + 0x0000000c_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000d_00000000u64 => CpuIdResult { eax: 0x00000207, ebx: 0x00000a88, ecx: 0x00000a88, edx: 0x00000000 }, + 0x0000000d_00000001u64 => CpuIdResult { eax: 0x0000000f, ebx: 0x00000670, ecx: 0x00019900, edx: 0x00000000 }, + 0x0000000d_00000002u64 => CpuIdResult { eax: 0x00000100, ebx: 0x00000240, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000d_00000008u64 => CpuIdResult { eax: 0x00000080, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, + 0x0000000d_00000009u64 => CpuIdResult { eax: 0x00000008, ebx: 0x00000a80, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000d_0000000bu64 => CpuIdResult { eax: 0x00000010, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, + 0x0000000d_0000000cu64 => CpuIdResult { eax: 0x00000018, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, + 0x0000000d_0000000fu64 => CpuIdResult { eax: 0x00000328, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, + 0x0000000d_00000010u64 => CpuIdResult { eax: 0x00000008, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, + 0x0000000e_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000f_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000010_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000011_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000012_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000013_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000014_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x0000005f, ecx: 0x00000007, edx: 0x00000000 }, + 0x00000014_00000001u64 => CpuIdResult { eax: 0x02490002, ebx: 0x003f003f, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000015_00000000u64 => CpuIdResult { eax: 0x00000002, ebx: 0x000000bc, ecx: 0x0249f000, edx: 0x00000000 }, + 0x00000016_00000000u64 => CpuIdResult { eax: 0x00000e10, ebx: 0x00001388, ecx: 0x00000064, edx: 0x00000000 }, + 0x00000017_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000018_00000000u64 => CpuIdResult { eax: 0x00000008, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000018_00000001u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00080001, ecx: 0x00000020, edx: 0x00004022 }, + 0x00000018_00000002u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00080006, ecx: 0x00000004, edx: 0x00004022 }, + 0x00000018_00000003u64 => CpuIdResult { eax: 0x00000000, ebx: 0x0010000f, ecx: 0x00000001, edx: 0x00004125 }, + 0x00000018_00000004u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00040001, ecx: 0x00000010, edx: 0x00004024 }, + 0x00000018_00000005u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00040006, ecx: 0x00000008, edx: 0x00004024 }, + 0x00000018_00000006u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00080008, ecx: 0x00000001, edx: 0x00004124 }, + 0x00000018_00000007u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00080007, ecx: 0x00000080, edx: 0x00004043 }, + 0x00000018_00000008u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00080009, ecx: 0x00000080, edx: 0x00004043 }, + 0x00000019_00000000u64 => CpuIdResult { eax: 0x00000007, ebx: 0x00000014, ecx: 0x00000003, edx: 0x00000000 }, + 0x0000001a_00000000u64 => CpuIdResult { eax: 0x40000001, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000001b_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x00000001, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000001c_00000000u64 => CpuIdResult { eax: 0x4000000b, ebx: 0x00000007, ecx: 0x00000007, edx: 0x00000000 }, + 0x0000001d_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000001e_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000001f_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x00000002, ecx: 0x00000100, edx: 0x00000000 }, + 0x0000001f_00000001u64 => CpuIdResult { eax: 0x00000007, ebx: 0x00000014, ecx: 0x00000201, edx: 0x00000000 }, + 0x0000001f_00000002u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000002, edx: 0x00000000 }, + 0x00000020_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000001, ecx: 0x00000000, edx: 0x00000000 }, + 0x20000000_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000001, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000000_00000000u64 => CpuIdResult { eax: 0x80000008, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000001_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000121, edx: 0x2c100800 }, + 0x80000002_00000000u64 => CpuIdResult { eax: 0x68743231, ebx: 0x6e654720, ecx: 0x746e4920, edx: 0x52286c65 }, + 0x80000003_00000000u64 => CpuIdResult { eax: 0x6f432029, ebx: 0x54286572, ecx: 0x6920294d, edx: 0x32312d37 }, + 0x80000004_00000000u64 => CpuIdResult { eax: 0x4b303037, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000005_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000006_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x05007040, edx: 0x00000000 }, + 0x80000007_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000100 }, + 0x80000008_00000000u64 => CpuIdResult { eax: 0x0000302e, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80860000_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000001, ecx: 0x00000000, edx: 0x00000000 }, + 0xc0000000_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000001, ecx: 0x00000000, edx: 0x00000000 }, +}; + +fn cpuid_reader(eax: u32, ecx: u32) -> CpuIdResult { + let key = (eax as u64) << u32::BITS | ecx as u64; + CPUID_VALUE_MAP[&key] +} + +/// Check that vendor is AuthenticAMD. +#[test] +fn vendor_check() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let v = cpuid.get_vendor_info().expect("Need to find vendor info"); + assert_eq!(v.as_str(), "GenuineIntel"); +} + +/// Check feature info gives correct values for CPU +#[test] +fn version_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let f = cpuid.get_feature_info().expect("Need to find feature info"); + + assert_eq!(f.base_family_id(), 6); + assert_eq!(f.base_model_id(), 7); + assert_eq!(f.stepping_id(), 2); + assert_eq!(f.extended_family_id(), 0); + assert_eq!(f.extended_model_id(), 9); + assert_eq!(f.family_id(), 6); + assert_eq!(f.model_id(), 151); + + assert_eq!(f.max_logical_processor_ids(), 128); + assert_eq!(f.initial_local_apic_id(), 0); + assert_eq!(f.cflush_cache_line_size(), 0x8); + assert_eq!(f.brand_index(), 0x0); + + assert!(f.has_fpu()); + assert!(f.has_vme()); + assert!(f.has_de()); + assert!(f.has_pse()); + assert!(f.has_tsc()); + assert!(f.has_msr()); + assert!(f.has_pae()); + assert!(f.has_mce()); + assert!(f.has_cmpxchg8b()); + assert!(f.has_apic()); + assert!(f.has_sysenter_sysexit()); + assert!(f.has_mtrr()); + assert!(f.has_pge()); + assert!(f.has_mca()); + assert!(f.has_cmov()); + assert!(f.has_pat()); + assert!(f.has_pse36()); + assert!(!f.has_psn()); + assert!(f.has_clflush()); + assert!(f.has_ds()); + assert!(f.has_acpi()); + assert!(f.has_mmx()); + assert!(f.has_fxsave_fxstor()); + assert!(f.has_sse()); + assert!(f.has_sse2()); + assert!(f.has_ss()); + assert!(f.has_htt()); + assert!(f.has_tm()); + assert!(f.has_pbe()); + + assert!(f.has_sse3()); + assert!(f.has_pclmulqdq()); + assert!(f.has_ds_area()); + assert!(f.has_monitor_mwait()); + assert!(f.has_cpl()); + assert!(f.has_vmx()); + assert!(f.has_smx()); + assert!(f.has_eist()); + assert!(f.has_tm2()); + assert!(f.has_ssse3()); + assert!(!f.has_cnxtid()); + // has_SDBG + assert!(f.has_fma()); + assert!(f.has_cmpxchg16b()); + // xTPR + assert!(f.has_pdcm()); + assert!(f.has_pcid()); + assert!(!f.has_dca()); + assert!(f.has_sse41()); + assert!(f.has_sse42()); + assert!(f.has_x2apic()); + assert!(f.has_movbe()); + assert!(f.has_popcnt()); + assert!(f.has_tsc_deadline()); + assert!(f.has_aesni()); + assert!(f.has_xsave()); + assert!(f.has_oxsave()); + assert!(f.has_avx()); + assert!(f.has_f16c()); + assert!(f.has_rdrand()); + assert!(!f.has_hypervisor()); +} + +#[test] +fn cache_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let ci = cpuid.get_cache_info().expect("Leaf is supported"); + + for (idx, cache) in ci.enumerate() { + match idx { + 0 => assert_eq!(cache.num, 0xf0), + 1 => assert_eq!(cache.num, 0xff), + 2 => assert_eq!(cache.num, 0xfe), + 3 => assert_eq!(cache.num, 0x03), + 4 => assert_eq!(cache.num, 0xf0), + 5 => assert_eq!(cache.num, 0x76), + 6 => assert_eq!(cache.num, 0xc3), + _ => unreachable!(), + } + } +} + +#[test] +fn processor_serial() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let psn = cpuid.get_processor_serial().expect("Leaf is supported"); + assert_eq!(psn.serial_lower(), 0x0); + assert_eq!(psn.serial_middle(), 0x0); +} + +#[test] +fn monitor_mwait() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let mw = cpuid.get_monitor_mwait_info().expect("Leaf is supported"); + assert_eq!(mw.largest_monitor_line(), 64); + assert_eq!(mw.smallest_monitor_line(), 64); + assert!(mw.interrupts_as_break_event()); + assert!(mw.extensions_supported()); + + assert_eq!(mw.supported_c0_states(), 0x0); + assert_eq!(mw.supported_c1_states(), 0x2); + assert_eq!(mw.supported_c2_states(), 0x0); + assert_eq!(mw.supported_c3_states(), 0x2); + assert_eq!(mw.supported_c4_states(), 0x0); + assert_eq!(mw.supported_c5_states(), 0x1); + assert_eq!(mw.supported_c6_states(), 0x0); + assert_eq!(mw.supported_c7_states(), 0x1); +} + +#[test] +fn thermal_power() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let mw = cpuid.get_thermal_power_info().expect("Leaf is supported"); + + assert!(mw.has_dts()); + assert!(mw.has_turbo_boost()); + assert!(mw.has_arat()); + assert!(mw.has_pln()); + assert!(mw.has_ecmd()); + assert!(mw.has_ptm()); + assert!(mw.has_hwp()); + assert!(mw.has_hwp_notification()); + assert!(mw.has_hwp_activity_window()); + assert!(mw.has_hwp_energy_performance_preference()); + assert!(mw.has_hwp_package_level_request()); + assert!(!mw.has_hdc()); + assert!(mw.has_turbo_boost3()); + assert!(mw.has_hwp_capabilities()); + assert!(mw.has_hwp_peci_override()); + assert!(mw.has_flexible_hwp()); + assert!(mw.has_hwp_fast_access_mode()); + assert!(mw.has_hw_coord_feedback()); + assert!(mw.has_ignore_idle_processor_hwp_request()); + // some missing + assert_eq!(mw.dts_irq_threshold(), 0x2); + // some missing + assert!(!mw.has_energy_bias_pref()); +} + +#[test] +fn extended_features() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_extended_feature_info() + .expect("Leaf is supported"); + + assert!(e.has_fsgsbase()); + assert!(e.has_tsc_adjust_msr()); + assert!(!e.has_sgx()); + assert!(e.has_bmi1()); + assert!(!e.has_hle()); + assert!(e.has_avx2()); + assert!(e.has_fdp()); + assert!(e.has_smep()); + assert!(e.has_bmi2()); + assert!(e.has_rep_movsb_stosb()); + assert!(e.has_invpcid()); + assert!(!e.has_rtm()); + assert!(!e.has_rdtm()); + assert!(e.has_fpu_cs_ds_deprecated()); + assert!(!e.has_mpx()); + assert!(!e.has_rdta()); + assert!(!e.has_avx512f()); + assert!(!e.has_avx512dq()); + assert!(e.has_rdseed()); + assert!(e.has_adx()); + assert!(e.has_smap()); + assert!(!e.has_avx512_ifma()); + assert!(e.has_clflushopt()); + assert!(e.has_clwb()); + assert!(e.has_processor_trace()); + assert!(!e.has_avx512pf()); + assert!(!e.has_avx512er()); + assert!(!e.has_avx512cd()); + assert!(e.has_sha()); + assert!(!e.has_avx512bw()); + assert!(!e.has_avx512vl()); + assert!(!e.has_prefetchwt1()); + // ... + assert!(e.has_umip()); + assert!(e.has_pku()); + assert!(e.has_ospke()); + assert!(!e.has_avx512vnni()); + assert!(e.has_rdpid()); + assert!(!e.has_sgx_lc()); + assert_eq!(e.mawau_value(), 0x0); +} + +#[test] +fn direct_cache_access() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let dca = cpuid.get_direct_cache_access_info().expect("Leaf exists"); + assert_eq!(dca.get_dca_cap_value(), 0x0); +} + +#[test] +fn perfmon_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let pm = cpuid + .get_performance_monitoring_info() + .expect("Leaf exists"); + + assert_eq!(pm.version_id(), 0x5); + + assert_eq!(pm.number_of_counters(), 0x6); + assert_eq!(pm.counter_bit_width(), 0x30); + assert_eq!(pm.ebx_length(), 0x7); + + assert!(!pm.is_core_cyc_ev_unavailable()); + assert!(!pm.is_inst_ret_ev_unavailable()); + assert!(!pm.is_ref_cycle_ev_unavailable()); + assert!(!pm.is_cache_ref_ev_unavailable()); + assert!(!pm.is_ll_cache_miss_ev_unavailable()); + assert!(!pm.is_branch_inst_ret_ev_unavailable()); + assert!(!pm.is_branch_midpred_ev_unavailable()); + + assert_eq!(pm.fixed_function_counters(), 0x3); + assert_eq!(pm.fixed_function_counters_bit_width(), 0x30); + assert!(pm.has_any_thread_deprecation()); +} + +#[test] +fn extended_topology_info() { + use crate::TopologyType; + + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let mut e = cpuid + .get_extended_topology_info() + .expect("Leaf is supported"); + + let t = e.next().expect("Have level 0"); + assert_eq!(t.x2apic_id(), 0); + assert_eq!(t.level_number(), 0); + assert_eq!(t.level_type(), TopologyType::SMT); + assert_eq!(t.shift_right_for_next_apic_id(), 0x1); + assert_eq!(t.processors(), 2); + + let t = e.next().expect("Have level 1"); + assert_eq!(t.level_number(), 1); + assert_eq!(t.level_type(), TopologyType::Core); + assert_eq!(t.shift_right_for_next_apic_id(), 0x7); + assert_eq!(t.processors(), 20); + assert_eq!(t.x2apic_id(), 0); +} + +#[test] +fn extended_topology_info_v2() { + use crate::TopologyType; + + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let mut e = cpuid + .get_extended_topology_info_v2() + .expect("Leaf is supported"); + + let t = e.next().expect("Have level 0"); + assert_eq!(t.x2apic_id(), 0); + assert_eq!(t.level_number(), 0); + assert_eq!(t.level_type(), TopologyType::SMT); + assert_eq!(t.shift_right_for_next_apic_id(), 0x1); + assert_eq!(t.processors(), 2); + + let t = e.next().expect("Have level 1"); + assert_eq!(t.level_number(), 1); + assert_eq!(t.level_type(), TopologyType::Core); + assert_eq!(t.shift_right_for_next_apic_id(), 0x7); + assert_eq!(t.processors(), 20); + assert_eq!(t.x2apic_id(), 0); +} + +#[test] +fn extended_state_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_extended_state_info().expect("Leaf is supported"); + + assert!(e.xcr0_supports_legacy_x87()); + assert!(e.xcr0_supports_sse_128()); + assert!(e.xcr0_supports_avx_256()); + assert!(!e.xcr0_supports_mpx_bndregs()); + assert!(!e.xcr0_supports_mpx_bndcsr()); + assert!(!e.xcr0_supports_avx512_opmask()); + assert!(!e.xcr0_supports_avx512_zmm_hi256()); + assert!(!e.xcr0_supports_avx512_zmm_hi16()); + // cpuid binary says this isn't supported, I think it's a bug there and it's + // supposed to read from ecx1 like we do: + assert!(e.ia32_xss_supports_pt()); + assert!(e.xcr0_supports_pkru()); + // ... + assert!(!e.ia32_xss_supports_hdc()); + + assert_eq!(e.xsave_area_size_enabled_features(), 2696); + assert_eq!(e.xsave_area_size_supported_features(), 2696); + assert!(e.has_xsaveopt()); + assert!(e.has_xsavec()); + assert!(e.has_xgetbv()); + assert!(e.has_xsaves_xrstors()); + // ... + assert_eq!(e.xsave_size(), 1648); + // ... + + let mut e = e.iter(); + let ee = e.next().expect("Has level 2"); + assert_eq!(ee.size(), 256); + assert_eq!(ee.offset(), 576); + assert!(ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 3"); + assert_eq!(ee.size(), 128); + assert_eq!(ee.offset(), 0); + assert!(!ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 4"); + assert_eq!(ee.size(), 8); + assert_eq!(ee.offset(), 2688); + assert!(ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 5"); + assert_eq!(ee.size(), 16); + assert_eq!(ee.offset(), 0); + assert!(!ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 6"); + assert_eq!(ee.size(), 24); + assert_eq!(ee.offset(), 0); + assert!(!ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 7"); + assert_eq!(ee.size(), 808); + assert_eq!(ee.offset(), 0); + assert!(!ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 8"); + assert_eq!(ee.size(), 8); + assert_eq!(ee.offset(), 0); + assert!(!ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); +} + +#[test] +fn rdt_monitoring_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_rdt_monitoring_info().expect("Leaf is supported"); + + assert_eq!(e.rmid_range(), 0); + assert!(!e.has_l3_monitoring()); +} + +#[test] +fn rdt_allocation_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_rdt_allocation_info().expect("Leaf is supported"); + + assert!(!e.has_l3_cat()); + assert!(!e.has_l2_cat()); + assert!(!e.has_memory_bandwidth_allocation()); + + assert!(e.l2_cat().is_none()); + assert!(e.l3_cat().is_none()); +} + +#[test] +fn sgx_test() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + assert!(cpuid.get_sgx_info().is_none()); +} + +#[test] +fn processor_trace() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let pt = cpuid.get_processor_trace_info().expect("Leaf is available"); + + assert!(pt.has_rtit_cr3_match()); + assert!(pt.has_configurable_psb_and_cycle_accurate_mode()); + assert!(pt.has_ip_tracestop_filtering()); + assert!(pt.has_mtc_timing_packet_coefi_suppression()); + assert!(pt.has_ptwrite()); + assert!(!pt.has_power_event_trace()); + assert!(pt.has_topa()); + assert!(pt.has_topa_maximum_entries()); + assert!(pt.has_single_range_output_scheme()); + assert!(!pt.has_trace_transport_subsystem()); + assert!(!pt.has_lip_with_cs_base()); + + assert_eq!(pt.configurable_address_ranges(), 2); + assert_eq!(pt.supported_mtc_period_encodings(), 585); + assert_eq!(pt.supported_cycle_threshold_value_encodings(), 63); + assert_eq!(pt.supported_psb_frequency_encodings(), 63); +} + +#[test] +fn tsc() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_tsc_info().expect("Leaf is available"); + assert_eq!(e.denominator(), 2); + assert_eq!(e.numerator(), 188); + assert_eq!(e.nominal_frequency(), 38400000); + assert_eq!(e.tsc_frequency(), Some(3609600000)); +} + +#[test] +fn processor_frequency() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_processor_frequency_info() + .expect("Leaf is supported"); + + assert_eq!(e.processor_base_frequency(), 3600); + assert_eq!(e.processor_max_frequency(), 5000); + assert_eq!(e.bus_frequency(), 100); +} + +#[test] +fn extended_processor_and_feature_identifiers() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_extended_processor_and_feature_identifiers() + .expect("Leaf is supported"); + + assert_eq!(e.pkg_type(), 0x0); // reserved on Intel + assert_eq!(e.brand_id(), 0x0); // reserved on Intel + + assert!(e.has_lahf_sahf()); + assert!(!e.has_cmp_legacy()); + assert!(!e.has_svm()); + assert!(!e.has_ext_apic_space()); + assert!(!e.has_alt_mov_cr8()); + assert!(e.has_lzcnt()); + assert!(!e.has_sse4a()); + assert!(!e.has_misaligned_sse_mode()); + assert!(e.has_prefetchw()); + assert!(!e.has_osvw()); + assert!(!e.has_ibs()); + assert!(!e.has_xop()); + assert!(!e.has_skinit()); + assert!(!e.has_wdt()); + assert!(!e.has_lwp()); + assert!(!e.has_fma4()); + assert!(!e.has_tbm()); + assert!(!e.has_topology_extensions()); + assert!(!e.has_perf_cntr_extensions()); + assert!(!e.has_nb_perf_cntr_extensions()); + assert!(!e.has_data_access_bkpt_extension()); + assert!(!e.has_perf_tsc()); + assert!(!e.has_perf_cntr_llc_extensions()); + assert!(!e.has_monitorx_mwaitx()); + assert!(!e.has_addr_mask_extension()); + assert!(e.has_syscall_sysret()); + assert!(e.has_execute_disable()); + assert!(!e.has_mmx_extensions()); + assert!(!e.has_fast_fxsave_fxstor()); + assert!(e.has_1gib_pages()); + assert!(e.has_rdtscp()); + assert!(e.has_64bit_mode()); + assert!(!e.has_amd_3dnow_extensions()); + assert!(!e.has_3dnow()); +} + +#[test] +fn brand_string() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_processor_brand_string() + .expect("Leaf is supported"); + + assert_eq!(e.as_str(), "12th Gen Intel(R) Core(TM) i7-12700K"); +} + +#[test] +fn l1_tlb_cache() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + assert!(cpuid.get_l1_cache_and_tlb_info().is_none()); +} + +#[test] +fn l2_l3_tlb_cache() { + use crate::Associativity; + + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_l2_l3_cache_and_tlb_info() + .expect("Leaf is supported"); + + // Unsupported on Intel + assert_eq!(e.itlb_2m_4m_associativity(), Associativity::Disabled); + assert_eq!(e.itlb_2m_4m_size(), 0); + assert_eq!(e.dtlb_2m_4m_associativity(), Associativity::Disabled); + assert_eq!(e.dtlb_2m_4m_size(), 0); + assert_eq!(e.itlb_4k_size(), 0); + assert_eq!(e.itlb_4k_associativity(), Associativity::Disabled); + assert_eq!(e.dtlb_4k_size(), 0); + assert_eq!(e.dtlb_4k_associativity(), Associativity::Disabled); + + // Supported on Intel + assert_eq!(e.l2cache_line_size(), 64); + assert_eq!(e.l2cache_lines_per_tag(), 0); + assert_eq!(e.l2cache_associativity(), Associativity::Unknown); + assert_eq!(e.l2cache_size(), 1280); + + // Unsupported on Intel + assert_eq!(e.l3cache_line_size(), 0); + assert_eq!(e.l3cache_lines_per_tag(), 0); + assert_eq!(e.l3cache_associativity(), Associativity::Disabled); + assert_eq!(e.l3cache_size(), 0); +} + +#[test] +fn apm() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_advanced_power_mgmt_info() + .expect("Leaf is supported"); + + assert!(!e.has_mca_overflow_recovery()); + assert!(!e.has_succor()); + assert!(!e.has_hwa()); + // ... + assert_eq!(e.cpu_pwr_sample_time_ratio(), 0x0); + + assert!(!e.has_ts()); + assert!(!e.has_freq_id_ctrl()); + assert!(!e.has_volt_id_ctrl()); + assert!(!e.has_thermtrip()); + assert!(!e.has_tm()); + assert!(!e.has_100mhz_steps()); + assert!(!e.has_hw_pstate()); + assert!(e.has_invariant_tsc()); // The only Intel supported feature here + assert!(!e.has_cpb()); + assert!(!e.has_ro_effective_freq_iface()); + assert!(!e.has_feedback_iface()); + assert!(!e.has_power_reporting_iface()); +} + +#[test] +fn processor_capcity_features() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_processor_capacity_feature_info() + .expect("Leaf is supported"); + + assert_eq!(e.physical_address_bits(), 46); + assert_eq!(e.linear_address_bits(), 48); + assert_eq!(e.guest_physical_address_bits(), 0); + + assert!(!e.has_cl_zero()); + assert!(!e.has_inst_ret_cntr_msr()); + assert!(!e.has_restore_fp_error_ptrs()); + assert!(!e.has_invlpgb()); + assert!(!e.has_rdpru()); + assert!(!e.has_mcommit()); + assert!(!e.has_wbnoinvd()); + assert!(!e.has_int_wbinvd()); + assert!(!e.has_unsupported_efer_lmsle()); + assert!(!e.has_invlpgb_nested()); + + assert_eq!(e.invlpgb_max_pages(), 0x0); + + assert_eq!(e.maximum_logical_processors(), 1); // Not sure why this is set, it's reserved :( + assert_eq!(e.num_phys_threads(), 1); // Not sure why this is set, it's reserved :( + assert_eq!(e.apic_id_size(), 0); + assert_eq!(e.perf_tsc_size(), 40); // Not sure why this is set, it's reserved :( + assert_eq!(e.max_rdpru_id(), 0); +} + +#[test] +fn get_deterministic_address_translation_info() { + use crate::DatType; + + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let mut e = cpuid + .get_deterministic_address_translation_info() + .expect("Leaf is supported"); + + // This is a null entry, so all of this should be 0/false/invalid/null + let t = e.next().expect("Have level 1"); + assert!(t.has_4k_entries()); + assert!(!t.has_2mb_entries()); + assert!(!t.has_4mb_entries()); + assert!(!t.has_1gb_entries()); + assert_eq!(t.partitioning(), 0); + assert_eq!(t.ways(), 8); + assert_eq!(t.sets(), 32); + assert_eq!(t.cache_type(), DatType::InstructionTLB); + assert_eq!(t.cache_level(), 1); + assert!(!t.is_fully_associative()); + assert_eq!(t.max_addressable_ids(), 2); + + let t = e.next().expect("Have level 2"); + assert!(!t.has_4k_entries()); + assert!(t.has_2mb_entries()); + assert!(t.has_4mb_entries()); + assert!(!t.has_1gb_entries()); + assert_eq!(t.partitioning(), 0); + assert_eq!(t.ways(), 8); + assert_eq!(t.sets(), 4); + assert_eq!(t.cache_type(), DatType::InstructionTLB); + assert_eq!(t.cache_level(), 1); + assert!(!t.is_fully_associative()); + assert_eq!(t.max_addressable_ids(), 2); + + let t = e.next().expect("Have level 3"); + assert!(t.has_4k_entries()); + assert!(t.has_2mb_entries()); + assert!(t.has_4mb_entries()); + assert!(t.has_1gb_entries()); + assert_eq!(t.partitioning(), 0); + assert_eq!(t.ways(), 16); + assert_eq!(t.sets(), 1); + assert_eq!(t.cache_type(), DatType::StoreOnly); + assert_eq!(t.cache_level(), 1); + assert!(t.is_fully_associative()); + assert_eq!(t.max_addressable_ids(), 2); + + let t = e.next().expect("Have level 4"); + assert!(t.has_4k_entries()); + assert!(!t.has_2mb_entries()); + assert!(!t.has_4mb_entries()); + assert!(!t.has_1gb_entries()); + assert_eq!(t.partitioning(), 0); + assert_eq!(t.ways(), 4); + assert_eq!(t.sets(), 16); + assert_eq!(t.cache_type(), DatType::LoadOnly); + assert_eq!(t.cache_level(), 1); + assert!(!t.is_fully_associative()); + assert_eq!(t.max_addressable_ids(), 2); + + let t = e.next().expect("Have level 5"); + assert!(!t.has_4k_entries()); + assert!(t.has_2mb_entries()); + assert!(t.has_4mb_entries()); + assert!(!t.has_1gb_entries()); + assert_eq!(t.partitioning(), 0); + assert_eq!(t.ways(), 4); + assert_eq!(t.sets(), 8); + assert_eq!(t.cache_type(), DatType::LoadOnly); + assert_eq!(t.cache_level(), 1); + assert!(!t.is_fully_associative()); + assert_eq!(t.max_addressable_ids(), 2); + + let t = e.next().expect("Have level 6"); + assert!(!t.has_4k_entries()); + assert!(!t.has_2mb_entries()); + assert!(!t.has_4mb_entries()); + assert!(t.has_1gb_entries()); + assert_eq!(t.partitioning(), 0); + assert_eq!(t.ways(), 8); + assert_eq!(t.sets(), 1); + assert_eq!(t.cache_type(), DatType::LoadOnly); + assert_eq!(t.cache_level(), 1); + assert!(t.is_fully_associative()); + assert_eq!(t.max_addressable_ids(), 2); + + let t = e.next().expect("Have level 7"); + assert!(t.has_4k_entries()); + assert!(t.has_2mb_entries()); + assert!(t.has_4mb_entries()); + assert!(!t.has_1gb_entries()); + assert_eq!(t.partitioning(), 0); + assert_eq!(t.ways(), 8); + assert_eq!(t.sets(), 128); + assert_eq!(t.cache_type(), DatType::UnifiedTLB); + assert_eq!(t.cache_level(), 2); + assert!(!t.is_fully_associative()); + assert_eq!(t.max_addressable_ids(), 2); + + let t = e.next().expect("Have level 8"); + assert!(t.has_4k_entries()); + assert!(!t.has_2mb_entries()); + assert!(!t.has_4mb_entries()); + assert!(t.has_1gb_entries()); + assert_eq!(t.partitioning(), 0); + assert_eq!(t.ways(), 8); + assert_eq!(t.sets(), 128); + assert_eq!(t.cache_type(), DatType::UnifiedTLB); + assert_eq!(t.cache_level(), 2); + assert!(!t.is_fully_associative()); + assert_eq!(t.max_addressable_ids(), 2); +} + +#[test] +fn get_soc_vendor() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_soc_vendor_info().expect("Leaf is supported"); + + assert_eq!(e.get_project_id(), 0); + assert_eq!(e.get_soc_vendor_id(), 0); + assert_eq!(e.get_stepping_id(), 0); + + if let Some(attr_iter) = e.get_vendor_attributes() { + for attr in attr_iter { + println!("{:?}", attr); + } + } + + println!("{:?}", e.get_vendor_brand()); +} diff --git a/vendor/raw-cpuid-10.7.0/src/tests/mod.rs b/vendor/raw-cpuid-10.7.0/src/tests/mod.rs new file mode 100644 index 0000000000000..4237dfeebc0e6 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/src/tests/mod.rs @@ -0,0 +1,4 @@ +mod i5_3337u; +mod i7_12700k; +mod ryzen_matisse; +mod xeon_gold_6252; diff --git a/vendor/raw-cpuid-10.7.0/src/tests/ryzen_matisse.rs b/vendor/raw-cpuid-10.7.0/src/tests/ryzen_matisse.rs new file mode 100644 index 0000000000000..1d4d495a5fc8f --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/src/tests/ryzen_matisse.rs @@ -0,0 +1,1270 @@ +use crate::{Associativity, CpuId, CpuIdResult, TopologyType}; +use phf::phf_map; + +/// Raw dump of ryzen mantisse cpuid values. +/// +/// Key format is (eax << 32 | ecx) e.g., two 32 bit values packed in one 64 bit value +/// +/// +/// # Representation of Hex Values +/// +/// ```log +/// vendor_id = "AuthenticAMD" +/// version information (1/eax): +/// processor type = primary processor (0) +/// family = 0xf (15) +/// model = 0x1 (1) +/// stepping id = 0x0 (0) +/// extended family = 0x8 (8) +/// extended model = 0x7 (7) +/// (family synth) = 0x17 (23) +/// (model synth) = 0x71 (113) +/// (simple synth) = AMD Ryzen (Matisse B0) [Zen 2], 7nm +/// miscellaneous (1/ebx): +/// process local APIC physical ID = 0xa (10) +/// cpu count = 0xc (12) +/// CLFLUSH line size = 0x8 (8) +/// brand index = 0x0 (0) +/// brand id = 0x00 (0): unknown +/// feature information (1/edx): +/// x87 FPU on chip = true +/// VME: virtual-8086 mode enhancement = true +/// DE: debugging extensions = true +/// PSE: page size extensions = true +/// TSC: time stamp counter = true +/// RDMSR and WRMSR support = true +/// PAE: physical address extensions = true +/// MCE: machine check exception = true +/// CMPXCHG8B inst. = true +/// APIC on chip = true +/// SYSENTER and SYSEXIT = true +/// MTRR: memory type range registers = true +/// PTE global bit = true +/// MCA: machine check architecture = true +/// CMOV: conditional move/compare instr = true +/// PAT: page attribute table = true +/// PSE-36: page size extension = true +/// PSN: processor serial number = false +/// CLFLUSH instruction = true +/// DS: debug store = false +/// ACPI: thermal monitor and clock ctrl = false +/// MMX Technology = true +/// FXSAVE/FXRSTOR = true +/// SSE extensions = true +/// SSE2 extensions = true +/// SS: self snoop = false +/// hyper-threading / multi-core supported = true +/// TM: therm. monitor = false +/// IA64 = false +/// PBE: pending break event = false +/// feature information (1/ecx): +/// PNI/SSE3: Prescott New Instructions = true +/// PCLMULDQ instruction = true +/// DTES64: 64-bit debug store = false +/// MONITOR/MWAIT = true +/// CPL-qualified debug store = false +/// VMX: virtual machine extensions = false +/// SMX: safer mode extensions = false +/// Enhanced Intel SpeedStep Technology = false +/// TM2: thermal monitor 2 = false +/// SSSE3 extensions = true +/// context ID: adaptive or shared L1 data = false +/// SDBG: IA32_DEBUG_INTERFACE = false +/// FMA instruction = true +/// CMPXCHG16B instruction = true +/// xTPR disable = false +/// PDCM: perfmon and debug = false +/// PCID: process context identifiers = false +/// DCA: direct cache access = false +/// SSE4.1 extensions = true +/// SSE4.2 extensions = true +/// x2APIC: extended xAPIC support = false +/// MOVBE instruction = true +/// POPCNT instruction = true +/// time stamp counter deadline = false +/// AES instruction = true +/// XSAVE/XSTOR states = true +/// OS-enabled XSAVE/XSTOR = true +/// AVX: advanced vector extensions = true +/// F16C half-precision convert instruction = true +/// RDRAND instruction = true +/// hypervisor guest status = false +/// cache and TLB information (2): +/// processor serial number = 0087-0F10-0000-0000-0000-0000 +/// MONITOR/MWAIT (5): +/// smallest monitor-line size (bytes) = 0x40 (64) +/// largest monitor-line size (bytes) = 0x40 (64) +/// enum of Monitor-MWAIT exts supported = true +/// supports intrs as break-event for MWAIT = true +/// number of C0 sub C-states using MWAIT = 0x1 (1) +/// number of C1 sub C-states using MWAIT = 0x1 (1) +/// number of C2 sub C-states using MWAIT = 0x0 (0) +/// number of C3 sub C-states using MWAIT = 0x0 (0) +/// number of C4 sub C-states using MWAIT = 0x0 (0) +/// number of C5 sub C-states using MWAIT = 0x0 (0) +/// number of C6 sub C-states using MWAIT = 0x0 (0) +/// number of C7 sub C-states using MWAIT = 0x0 (0) +/// Thermal and Power Management Features (6): +/// digital thermometer = false +/// Intel Turbo Boost Technology = false +/// ARAT always running APIC timer = true +/// PLN power limit notification = false +/// ECMD extended clock modulation duty = false +/// PTM package thermal management = false +/// HWP base registers = false +/// HWP notification = false +/// HWP activity window = false +/// HWP energy performance preference = false +/// HWP package level request = false +/// HDC base registers = false +/// Intel Turbo Boost Max Technology 3.0 = false +/// HWP capabilities = false +/// HWP PECI override = false +/// flexible HWP = false +/// IA32_HWP_REQUEST MSR fast access mode = false +/// HW_FEEDBACK = false +/// ignoring idle logical processor HWP req = false +/// digital thermometer thresholds = 0x0 (0) +/// hardware coordination feedback = true +/// ACNT2 available = false +/// performance-energy bias capability = false +/// performance capability reporting = false +/// energy efficiency capability reporting = false +/// size of feedback struct (4KB pages) = 0x0 (0) +/// index of CPU's row in feedback struct = 0x0 (0) +/// extended feature flags (7): +/// FSGSBASE instructions = true +/// IA32_TSC_ADJUST MSR supported = false +/// SGX: Software Guard Extensions supported = false +/// BMI1 instructions = true +/// HLE hardware lock elision = false +/// AVX2: advanced vector extensions 2 = true +/// FDP_EXCPTN_ONLY = false +/// SMEP supervisor mode exec protection = true +/// BMI2 instructions = true +/// enhanced REP MOVSB/STOSB = false +/// INVPCID instruction = false +/// RTM: restricted transactional memory = false +/// RDT-CMT/PQoS cache monitoring = true +/// deprecated FPU CS/DS = false +/// MPX: intel memory protection extensions = false +/// RDT-CAT/PQE cache allocation = true +/// AVX512F: AVX-512 foundation instructions = false +/// AVX512DQ: double & quadword instructions = false +/// RDSEED instruction = true +/// ADX instructions = true +/// SMAP: supervisor mode access prevention = true +/// AVX512IFMA: fused multiply add = false +/// PCOMMIT instruction = false +/// CLFLUSHOPT instruction = true +/// CLWB instruction = true +/// Intel processor trace = false +/// AVX512PF: prefetch instructions = false +/// AVX512ER: exponent & reciprocal instrs = false +/// AVX512CD: conflict detection instrs = false +/// SHA instructions = true +/// AVX512BW: byte & word instructions = false +/// AVX512VL: vector length = false +/// PREFETCHWT1 = false +/// AVX512VBMI: vector byte manipulation = false +/// UMIP: user-mode instruction prevention = true +/// PKU protection keys for user-mode = false +/// OSPKE CR4.PKE and RDPKRU/WRPKRU = false +/// WAITPKG instructions = false +/// AVX512_VBMI2: byte VPCOMPRESS, VPEXPAND = false +/// CET_SS: CET shadow stack = false +/// GFNI: Galois Field New Instructions = false +/// VAES instructions = false +/// VPCLMULQDQ instruction = false +/// AVX512_VNNI: neural network instructions = false +/// AVX512_BITALG: bit count/shiffle = false +/// TME: Total Memory Encryption = false +/// AVX512: VPOPCNTDQ instruction = false +/// 5-level paging = false +/// BNDLDX/BNDSTX MAWAU value in 64-bit mode = 0x0 (0) +/// RDPID: read processor D supported = true +/// CLDEMOTE supports cache line demote = false +/// MOVDIRI instruction = false +/// MOVDIR64B instruction = false +/// ENQCMD instruction = false +/// SGX_LC: SGX launch config supported = false +/// AVX512_4VNNIW: neural network instrs = false +/// AVX512_4FMAPS: multiply acc single prec = false +/// fast short REP MOV = false +/// AVX512_VP2INTERSECT: intersect mask regs = false +/// VERW md-clear microcode support = false +/// hybrid part = false +/// PCONFIG instruction = false +/// CET_IBT: CET indirect branch tracking = false +/// IBRS/IBPB: indirect branch restrictions = false +/// STIBP: 1 thr indirect branch predictor = false +/// L1D_FLUSH: IA32_FLUSH_CMD MSR = false +/// IA32_ARCH_CAPABILITIES MSR = false +/// IA32_CORE_CAPABILITIES MSR = false +/// SSBD: speculative store bypass disable = false +/// Direct Cache Access Parameters (9): +/// PLATFORM_DCA_CAP MSR bits = 0 +/// Architecture Performance Monitoring Features (0xa/eax): +/// version ID = 0x0 (0) +/// number of counters per logical processor = 0x0 (0) +/// bit width of counter = 0x0 (0) +/// length of EBX bit vector = 0x0 (0) +/// Architecture Performance Monitoring Features (0xa/ebx): +/// core cycle event not available = false +/// instruction retired event not available = false +/// reference cycles event not available = false +/// last-level cache ref event not available = false +/// last-level cache miss event not avail = false +/// branch inst retired event not available = false +/// branch mispred retired event not avail = false +/// Architecture Performance Monitoring Features (0xa/edx): +/// number of fixed counters = 0x0 (0) +/// bit width of fixed counters = 0x0 (0) +/// anythread deprecation = false +/// x2APIC features / processor topology (0xb): +/// extended APIC ID = 10 +/// --- level 0 --- +/// level number = 0x0 (0) +/// level type = thread (1) +/// bit width of level = 0x1 (1) +/// number of logical processors at level = 0x2 (2) +/// --- level 1 --- +/// level number = 0x1 (1) +/// level type = core (2) +/// bit width of level = 0x7 (7) +/// number of logical processors at level = 0xc (12) +/// XSAVE features (0xd/0): +/// XCR0 lower 32 bits valid bit field mask = 0x00000207 +/// XCR0 upper 32 bits valid bit field mask = 0x00000000 +/// XCR0 supported: x87 state = true +/// XCR0 supported: SSE state = true +/// XCR0 supported: AVX state = true +/// XCR0 supported: MPX BNDREGS = false +/// XCR0 supported: MPX BNDCSR = false +/// XCR0 supported: AVX-512 opmask = false +/// XCR0 supported: AVX-512 ZMM_Hi256 = false +/// XCR0 supported: AVX-512 Hi16_ZMM = false +/// IA32_XSS supported: PT state = false +/// XCR0 supported: PKRU state = true +/// XCR0 supported: CET_U state = false +/// XCR0 supported: CET_S state = false +/// IA32_XSS supported: HDC state = false +/// bytes required by fields in XCR0 = 0x00000340 (832) +/// bytes required by XSAVE/XRSTOR area = 0x00000380 (896) +/// XSAVE features (0xd/1): +/// XSAVEOPT instruction = true +/// XSAVEC instruction = true +/// XGETBV instruction = true +/// XSAVES/XRSTORS instructions = true +/// SAVE area size in bytes = 0x00000340 (832) +/// IA32_XSS lower 32 bits valid bit field mask = 0x00000000 +/// IA32_XSS upper 32 bits valid bit field mask = 0x00000000 +/// AVX/YMM features (0xd/2): +/// AVX/YMM save state byte size = 0x00000100 (256) +/// AVX/YMM save state byte offset = 0x00000240 (576) +/// supported in IA32_XSS or XCR0 = XCR0 (user state) +/// 64-byte alignment in compacted XSAVE = false +/// PKRU features (0xd/9): +/// PKRU save state byte size = 0x00000040 (64) +/// PKRU save state byte offset = 0x00000340 (832) +/// supported in IA32_XSS or XCR0 = XCR0 (user state) +/// 64-byte alignment in compacted XSAVE = false +/// Quality of Service Monitoring Resource Type (0xf/0): +/// Maximum range of RMID = 255 +/// supports L3 cache QoS monitoring = true +/// L3 Cache Quality of Service Monitoring (0xf/1): +/// Conversion factor from IA32_QM_CTR to bytes = 64 +/// Maximum range of RMID = 255 +/// supports L3 occupancy monitoring = true +/// supports L3 total bandwidth monitoring = true +/// supports L3 local bandwidth monitoring = true +/// Resource Director Technology Allocation (0x10/0): +/// L3 cache allocation technology supported = true +/// L2 cache allocation technology supported = false +/// memory bandwidth allocation supported = false +/// L3 Cache Allocation Technology (0x10/1): +/// length of capacity bit mask = 0x10 (16) +/// Bit-granular map of isolation/contention = 0x00000000 +/// infrequent updates of COS = false +/// code and data prioritization supported = true +/// highest COS number supported = 0xf (15) +/// extended processor signature (0x80000001/eax): +/// family/generation = 0xf (15) +/// model = 0x1 (1) +/// stepping id = 0x0 (0) +/// extended family = 0x8 (8) +/// extended model = 0x7 (7) +/// (family synth) = 0x17 (23) +/// (model synth) = 0x71 (113) +/// (simple synth) = AMD Ryzen (Matisse B0) [Zen 2], 7nm +/// extended feature flags (0x80000001/edx): +/// x87 FPU on chip = true +/// virtual-8086 mode enhancement = true +/// debugging extensions = true +/// page size extensions = true +/// time stamp counter = true +/// RDMSR and WRMSR support = true +/// physical address extensions = true +/// machine check exception = true +/// CMPXCHG8B inst. = true +/// APIC on chip = true +/// SYSCALL and SYSRET instructions = true +/// memory type range registers = true +/// global paging extension = true +/// machine check architecture = true +/// conditional move/compare instruction = true +/// page attribute table = true +/// page size extension = true +/// multiprocessing capable = false +/// no-execute page protection = true +/// AMD multimedia instruction extensions = true +/// MMX Technology = true +/// FXSAVE/FXRSTOR = true +/// SSE extensions = true +/// 1-GB large page support = true +/// RDTSCP = true +/// long mode (AA-64) = true +/// 3DNow! instruction extensions = false +/// 3DNow! instructions = false +/// extended brand id (0x80000001/ebx): +/// raw = 0x20000000 (536870912) +/// BrandId = 0x0 (0) +/// PkgType = AM4 (2) +/// AMD feature flags (0x80000001/ecx): +/// LAHF/SAHF supported in 64-bit mode = true +/// CMP Legacy = true +/// SVM: secure virtual machine = true +/// extended APIC space = true +/// AltMovCr8 = true +/// LZCNT advanced bit manipulation = true +/// SSE4A support = true +/// misaligned SSE mode = true +/// 3DNow! PREFETCH/PREFETCHW instructions = true +/// OS visible workaround = true +/// instruction based sampling = true +/// XOP support = false +/// SKINIT/STGI support = true +/// watchdog timer support = true +/// lightweight profiling support = false +/// 4-operand FMA instruction = false +/// TCE: translation cache extension = true +/// NodeId MSR C001100C = false +/// TBM support = false +/// topology extensions = true +/// core performance counter extensions = true +/// NB/DF performance counter extensions = true +/// data breakpoint extension = true +/// performance time-stamp counter support = false +/// LLC performance counter extensions = true +/// MWAITX/MONITORX supported = true +/// Address mask extension support = true +/// brand = "AMD Ryzen 5 3600X 6-Core Processor " +/// L1 TLB/cache information: 2M/4M pages & L1 TLB (0x80000005/eax): +/// instruction # entries = 0x40 (64) +/// instruction associativity = 0xff (255) +/// data # entries = 0x40 (64) +/// data associativity = 0xff (255) +/// L1 TLB/cache information: 4K pages & L1 TLB (0x80000005/ebx): +/// instruction # entries = 0x40 (64) +/// instruction associativity = 0xff (255) +/// data # entries = 0x40 (64) +/// data associativity = 0xff (255) +/// L1 data cache information (0x80000005/ecx): +/// line size (bytes) = 0x40 (64) +/// lines per tag = 0x1 (1) +/// associativity = 0x8 (8) +/// size (KB) = 0x20 (32) +/// L1 instruction cache information (0x80000005/edx): +/// line size (bytes) = 0x40 (64) +/// lines per tag = 0x1 (1) +/// associativity = 0x8 (8) +/// size (KB) = 0x20 (32) +/// L2 TLB/cache information: 2M/4M pages & L2 TLB (0x80000006/eax): +/// instruction # entries = 0x400 (1024) +/// instruction associativity = 8-way (6) +/// data # entries = 0x800 (2048) +/// data associativity = 4-way (4) +/// L2 TLB/cache information: 4K pages & L2 TLB (0x80000006/ebx): +/// instruction # entries = 0x400 (1024) +/// instruction associativity = 8-way (6) +/// data # entries = 0x800 (2048) +/// data associativity = 8-way (6) +/// L2 unified cache information (0x80000006/ecx): +/// line size (bytes) = 0x40 (64) +/// lines per tag = 0x1 (1) +/// associativity = 8-way (6) +/// size (KB) = 0x200 (512) +/// L3 cache information (0x80000006/edx): +/// line size (bytes) = 0x40 (64) +/// lines per tag = 0x1 (1) +/// associativity = 0x9 (9) +/// size (in 512KB units) = 0x40 (64) +/// RAS Capability (0x80000007/ebx): +/// MCA overflow recovery support = true +/// SUCCOR support = true +/// HWA: hardware assert support = false +/// scalable MCA support = true +/// Advanced Power Management Features (0x80000007/ecx): +/// CmpUnitPwrSampleTimeRatio = 0x0 (0) +/// Advanced Power Management Features (0x80000007/edx): +/// TS: temperature sensing diode = true +/// FID: frequency ID control = false +/// VID: voltage ID control = false +/// TTP: thermal trip = true +/// TM: thermal monitor = true +/// STC: software thermal control = false +/// 100 MHz multiplier control = false +/// hardware P-State control = true +/// TscInvariant = true +/// CPB: core performance boost = true +/// read-only effective frequency interface = true +/// processor feedback interface = false +/// APM power reporting = false +/// connected standby = true +/// RAPL: running average power limit = true +/// Physical Address and Linear Address Size (0x80000008/eax): +/// maximum physical address bits = 0x30 (48) +/// maximum linear (virtual) address bits = 0x30 (48) +/// maximum guest physical address bits = 0x0 (0) +/// Extended Feature Extensions ID (0x80000008/ebx): +/// CLZERO instruction = true +/// instructions retired count support = true +/// always save/restore error pointers = true +/// RDPRU instruction = true +/// memory bandwidth enforcement = true +/// WBNOINVD instruction = true +/// IBPB: indirect branch prediction barrier = true +/// IBRS: indirect branch restr speculation = false +/// STIBP: 1 thr indirect branch predictor = true +/// STIBP always on preferred mode = true +/// ppin processor id number supported = false +/// SSBD: speculative store bypass disable = true +/// virtualized SSBD = false +/// SSBD fixed in hardware = false +/// Size Identifiers (0x80000008/ecx): +/// number of threads = 0xc (12) +/// ApicIdCoreIdSize = 0x7 (7) +/// performance time-stamp counter size = 0x0 (0) +/// Feature Extended Size (0x80000008/edx): +/// RDPRU instruction max input support = 0x1 (1) +/// SVM Secure Virtual Machine (0x8000000a/eax): +/// SvmRev: SVM revision = 0x1 (1) +/// SVM Secure Virtual Machine (0x8000000a/edx): +/// nested paging = true +/// LBR virtualization = true +/// SVM lock = true +/// NRIP save = true +/// MSR based TSC rate control = true +/// VMCB clean bits support = true +/// flush by ASID = true +/// decode assists = true +/// SSSE3/SSE5 opcode set disable = false +/// pause intercept filter = true +/// pause filter threshold = true +/// AVIC: AMD virtual interrupt controller = true +/// virtualized VMLOAD/VMSAVE = true +/// virtualized global interrupt flag (GIF) = true +/// GMET: guest mode execute trap = true +/// guest Spec_ctl support = true +/// NASID: number of address space identifiers = 0x8000 (32768): +/// L1 TLB information: 1G pages (0x80000019/eax): +/// instruction # entries = 0x40 (64) +/// instruction associativity = full (15) +/// data # entries = 0x40 (64) +/// data associativity = full (15) +/// L2 TLB information: 1G pages (0x80000019/ebx): +/// instruction # entries = 0x0 (0) +/// instruction associativity = L2 off (0) +/// data # entries = 0x0 (0) +/// data associativity = L2 off (0) +/// SVM Secure Virtual Machine (0x8000001a/eax): +/// 128-bit SSE executed full-width = false +/// MOVU* better than MOVL*/MOVH* = true +/// 256-bit SSE executed full-width = true +/// Instruction Based Sampling Identifiers (0x8000001b/eax): +/// IBS feature flags valid = true +/// IBS fetch sampling = true +/// IBS execution sampling = true +/// read write of op counter = true +/// op counting mode = true +/// branch target address reporting = true +/// IbsOpCurCnt and IbsOpMaxCnt extend 7 = true +/// invalid RIP indication support = true +/// fused branch micro-op indication support = true +/// IBS fetch control extended MSR support = true +/// IBS op data 4 MSR support = false +/// Lightweight Profiling Capabilities: Availability (0x8000001c/eax): +/// lightweight profiling = false +/// LWPVAL instruction = false +/// instruction retired event = false +/// branch retired event = false +/// DC miss event = false +/// core clocks not halted event = false +/// core reference clocks not halted event = false +/// interrupt on threshold overflow = false +/// Lightweight Profiling Capabilities: Supported (0x8000001c/edx): +/// lightweight profiling = false +/// LWPVAL instruction = false +/// instruction retired event = false +/// branch retired event = false +/// DC miss event = false +/// core clocks not halted event = false +/// core reference clocks not halted event = false +/// interrupt on threshold overflow = false +/// Lightweight Profiling Capabilities (0x8000001c/ebx): +/// LWPCB byte size = 0x0 (0) +/// event record byte size = 0x0 (0) +/// maximum EventId = 0x0 (0) +/// EventInterval1 field offset = 0x0 (0) +/// Lightweight Profiling Capabilities (0x8000001c/ecx): +/// latency counter bit size = 0x0 (0) +/// data cache miss address valid = false +/// amount cache latency is rounded = 0x0 (0) +/// LWP implementation version = 0x0 (0) +/// event ring buffer size in records = 0x0 (0) +/// branch prediction filtering = false +/// IP filtering = false +/// cache level filtering = false +/// cache latency filteing = false +/// Cache Properties (0x8000001d): +/// --- cache 0 --- +/// type = data (1) +/// level = 0x1 (1) +/// self-initializing = true +/// fully associative = false +/// extra cores sharing this cache = 0x1 (1) +/// line size in bytes = 0x40 (64) +/// physical line partitions = 0x1 (1) +/// number of ways = 0x8 (8) +/// number of sets = 64 +/// write-back invalidate = false +/// cache inclusive of lower levels = false +/// (synth size) = 32768 (32 KB) +/// --- cache 1 --- +/// type = instruction (2) +/// level = 0x1 (1) +/// self-initializing = true +/// fully associative = false +/// extra cores sharing this cache = 0x1 (1) +/// line size in bytes = 0x40 (64) +/// physical line partitions = 0x1 (1) +/// number of ways = 0x8 (8) +/// number of sets = 64 +/// write-back invalidate = false +/// cache inclusive of lower levels = false +/// (synth size) = 32768 (32 KB) +/// --- cache 2 --- +/// type = unified (3) +/// level = 0x2 (2) +/// self-initializing = true +/// fully associative = false +/// extra cores sharing this cache = 0x1 (1) +/// line size in bytes = 0x40 (64) +/// physical line partitions = 0x1 (1) +/// number of ways = 0x8 (8) +/// number of sets = 1024 +/// write-back invalidate = false +/// cache inclusive of lower levels = true +/// (synth size) = 524288 (512 KB) +/// --- cache 3 --- +/// type = unified (3) +/// level = 0x3 (3) +/// self-initializing = true +/// fully associative = false +/// extra cores sharing this cache = 0x5 (5) +/// line size in bytes = 0x40 (64) +/// physical line partitions = 0x1 (1) +/// number of ways = 0x10 (16) +/// number of sets = 16384 +/// write-back invalidate = true +/// cache inclusive of lower levels = false +/// (synth size) = 16777216 (16 MB) +/// extended APIC ID = 10 +/// Core Identifiers (0x8000001e/ebx): +/// core ID = 0x5 (5) +/// threads per core = 0x2 (2) +/// Node Identifiers (0x8000001e/ecx): +/// node ID = 0x0 (0) +/// nodes per processor = 0x1 (1) +/// AMD Secure Encryption (0x8000001f): +/// SME: secure memory encryption support = true +/// SEV: secure encrypted virtualize support = true +/// VM page flush MSR support = true +/// SEV-ES: SEV encrypted state support = true +/// encryption bit position in PTE = 0x2f (47) +/// physical address space width reduction = 0x5 (5) +/// number of SEV-enabled guests supported = 0x1fd (509) +/// minimum SEV guest ASID = 0x1 (1) +/// PQoS Enforcement for Memory Bandwidth (0x80000020): +/// memory bandwidth enforcement support = true +/// capacity bitmask length = 0xc (12) +/// number of classes of service = 0xf (15) +/// (instruction supported synth): +/// CMPXCHG8B = true +/// conditional move/compare = true +/// PREFETCH/PREFETCHW = true +/// (multi-processing synth) = multi-core (c=12) +/// (multi-processing method) = AMD +/// (APIC widths synth): CORE_width=3 SMT_width=1 +/// (APIC synth): PKG_ID=0 CORE_ID=5 SMT_ID=0 +/// (uarch synth) = AMD Zen 2, 7nm +/// (synth) = AMD Ryzen (Matisse B0) [Zen 2], 7nm +/// ``` +static CPUID_VALUE_MAP: phf::Map = phf_map! { + 0x00000000_00000000u64 => CpuIdResult { eax: 0x00000010, ebx: 0x68747541, ecx: 0x444d4163, edx: 0x69746e65 }, + 0x00000001_00000000u64 => CpuIdResult { eax: 0x00870f10, ebx: 0x000c0800, ecx: 0x7ed8320b, edx: 0x178bfbff }, + 0x00000002_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000003_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000005_00000000u64 => CpuIdResult { eax: 0x00000040, ebx: 0x00000040, ecx: 0x00000003, edx: 0x00000011 }, + 0x00000006_00000000u64 => CpuIdResult { eax: 0x00000004, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, + 0x00000007_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x219c91a9, ecx: 0x00400004, edx: 0x00000000 }, + 0x00000008_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000009_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000a_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000b_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x00000002, ecx: 0x00000100, edx: 0x00000000 }, + 0x0000000b_00000001u64 => CpuIdResult { eax: 0x00000007, ebx: 0x0000000c, ecx: 0x00000201, edx: 0x00000000 }, + 0x0000000c_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000d_00000000u64 => CpuIdResult { eax: 0x00000207, ebx: 0x00000340, ecx: 0x00000380, edx: 0x00000000 }, + 0x0000000d_00000001u64 => CpuIdResult { eax: 0x0000000f, ebx: 0x00000340, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000d_00000002u64 => CpuIdResult { eax: 0x00000100, ebx: 0x00000240, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000d_00000009u64 => CpuIdResult { eax: 0x00000040, ebx: 0x00000340, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000e_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000f_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x000000ff, ecx: 0x00000000, edx: 0x00000002 }, + 0x0000000f_00000001u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000040, ecx: 0x000000ff, edx: 0x00000007 }, + 0x00000010_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000002, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000010_00000001u64 => CpuIdResult { eax: 0x0000000f, ebx: 0x00000000, ecx: 0x00000004, edx: 0x0000000f }, + 0x20000000_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000000_00000000u64 => CpuIdResult { eax: 0x80000020, ebx: 0x68747541, ecx: 0x444d4163, edx: 0x69746e65 }, + 0x80000001_00000000u64 => CpuIdResult { eax: 0x00870f10, ebx: 0x20000000, ecx: 0x75c237ff, edx: 0x2fd3fbff }, + 0x80000002_00000000u64 => CpuIdResult { eax: 0x20444d41, ebx: 0x657a7952, ecx: 0x2035206e, edx: 0x30303633 }, + 0x80000003_00000000u64 => CpuIdResult { eax: 0x2d362058, ebx: 0x65726f43, ecx: 0x6f725020, edx: 0x73736563 }, + 0x80000004_00000000u64 => CpuIdResult { eax: 0x2020726f, ebx: 0x20202020, ecx: 0x20202020, edx: 0x00202020 }, + 0x80000005_00000000u64 => CpuIdResult { eax: 0xff40ff40, ebx: 0xff40ff40, ecx: 0x20080140, edx: 0x20080140 }, + 0x80000006_00000000u64 => CpuIdResult { eax: 0x48006400, ebx: 0x68006400, ecx: 0x02006140, edx: 0x01009140 }, + 0x80000007_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x0000001b, ecx: 0x00000000, edx: 0x00006799 }, + 0x80000008_00000000u64 => CpuIdResult { eax: 0x00003030, ebx: 0x010eb757, ecx: 0x0000700b, edx: 0x00010000 }, + 0x80000009_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x8000000a_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x00008000, ecx: 0x00000000, edx: 0x0013bcff }, + 0x8000000b_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x8000000c_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x8000000d_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x8000000e_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x8000000f_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000010_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000011_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000012_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000013_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000014_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000015_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000016_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000017_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000018_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000019_00000000u64 => CpuIdResult { eax: 0xf040f040, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x8000001a_00000000u64 => CpuIdResult { eax: 0x00000006, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x8000001b_00000000u64 => CpuIdResult { eax: 0x000003ff, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x8000001c_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x8000001d_00000000u64 => CpuIdResult { eax: 0x00004121, ebx: 0x01c0003f, ecx: 0x0000003f, edx: 0x00000000 }, + 0x8000001d_00000001u64 => CpuIdResult { eax: 0x00004122, ebx: 0x01c0003f, ecx: 0x0000003f, edx: 0x00000000 }, + 0x8000001d_00000002u64 => CpuIdResult { eax: 0x00004143, ebx: 0x01c0003f, ecx: 0x000003ff, edx: 0x00000002 }, + 0x8000001d_00000003u64 => CpuIdResult { eax: 0x00014163, ebx: 0x03c0003f, ecx: 0x00003fff, edx: 0x00000001 }, + 0x8000001e_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000100, ecx: 0x00000000, edx: 0x00000000 }, + 0x8000001f_00000000u64 => CpuIdResult { eax: 0x0001000f, ebx: 0x0000016f, ecx: 0x000001fd, edx: 0x00000001 }, + 0x80000020_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000002, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000020_00000001u64 => CpuIdResult { eax: 0x0000000b, ebx: 0x00000000, ecx: 0x00000000, edx: 0x0000000f }, + 0x80860000_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0xc0000000_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, +}; + +fn cpuid_reader(eax: u32, ecx: u32) -> CpuIdResult { + let key = (eax as u64) << u32::BITS | ecx as u64; + CPUID_VALUE_MAP[&key] +} + +/// Check that vendor is AuthenticAMD. +#[test] +fn vendor_check() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let v = cpuid.get_vendor_info().expect("Need to find vendor info"); + assert_eq!(v.as_str(), "AuthenticAMD"); +} + +/// Check feature info gives correct values for CPU +#[test] +fn version_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let f = cpuid.get_feature_info().expect("Need to find feature info"); + + assert_eq!(f.base_family_id(), 0xf); + assert_eq!(f.base_model_id(), 0x1); + assert_eq!(f.stepping_id(), 0x0); + assert_eq!(f.extended_family_id(), 0x8); + assert_eq!(f.extended_model_id(), 0x7); + assert_eq!(f.brand_index(), 0x0); + assert_eq!(f.cflush_cache_line_size(), 0x8); + assert_eq!(f.max_logical_processor_ids(), 0xc); + + assert!(f.has_fpu()); + assert!(f.has_vme()); + assert!(f.has_de()); + assert!(f.has_pse()); + assert!(f.has_tsc()); + assert!(f.has_msr()); + assert!(f.has_pae()); + assert!(f.has_mce()); + assert!(f.has_cmpxchg8b()); + assert!(f.has_apic()); + assert!(f.has_sysenter_sysexit()); + assert!(f.has_mtrr()); + assert!(f.has_pge()); + assert!(f.has_mca()); + assert!(f.has_cmov()); + assert!(f.has_pat()); + assert!(f.has_pse36()); + assert!(!f.has_psn()); + assert!(f.has_clflush()); + assert!(!f.has_ds()); + assert!(!f.has_acpi()); + assert!(f.has_mmx()); + assert!(f.has_fxsave_fxstor()); + assert!(f.has_sse()); + assert!(f.has_sse2()); + assert!(!f.has_ss()); + assert!(f.has_htt()); + assert!(!f.has_tm()); + assert!(!f.has_pbe()); + + assert!(f.has_sse3()); + assert!(f.has_pclmulqdq()); + assert!(!f.has_ds_area()); + assert!(f.has_monitor_mwait()); + assert!(!f.has_cpl()); + assert!(!f.has_vmx()); + assert!(!f.has_smx()); + assert!(!f.has_eist()); + assert!(!f.has_tm2()); + assert!(f.has_ssse3()); + assert!(!f.has_cnxtid()); + // has_SDBG + assert!(f.has_fma()); + assert!(f.has_cmpxchg16b()); + // xTPR + assert!(!f.has_pdcm()); + assert!(!f.has_pcid()); + assert!(!f.has_dca()); + assert!(f.has_sse41()); + assert!(f.has_sse42()); + assert!(!f.has_x2apic()); + assert!(f.has_movbe()); + assert!(f.has_popcnt()); + assert!(!f.has_tsc_deadline()); + assert!(f.has_aesni()); + assert!(f.has_xsave()); + assert!(f.has_oxsave()); + assert!(f.has_avx()); + assert!(f.has_f16c()); + assert!(f.has_rdrand()); + assert!(!f.has_hypervisor()); +} + +#[test] +fn cache_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + assert!(cpuid.get_cache_info().is_none(), "Not supported by AMD"); +} + +#[test] +fn processor_serial() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + assert!( + cpuid.get_processor_serial().is_none(), + "Not supported by AMD" + ); +} + +#[test] +fn monitor_mwait() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let mw = cpuid.get_monitor_mwait_info().expect("Leaf is supported"); + assert_eq!(mw.largest_monitor_line(), 64); + assert_eq!(mw.smallest_monitor_line(), 64); + assert!(mw.interrupts_as_break_event()); + assert!(mw.extensions_supported()); + // supported_cX_states functions are not supported according to the manual +} + +#[test] +fn thermal_power() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let mw = cpuid.get_thermal_power_info().expect("Leaf is supported"); + + assert_eq!(mw.dts_irq_threshold(), 0x0); + assert!(!mw.has_dts()); + assert!(mw.has_arat()); + assert!(!mw.has_turbo_boost()); + assert!(!mw.has_pln()); + assert!(!mw.has_ecmd()); + assert!(!mw.has_ptm()); + assert!(!mw.has_hwp()); + assert!(!mw.has_hwp_notification()); + assert!(!mw.has_hwp_activity_window()); + assert!(!mw.has_hwp_energy_performance_preference()); + assert!(!mw.has_hwp_package_level_request()); + assert!(!mw.has_hdc()); + assert!(!mw.has_turbo_boost3()); + assert!(!mw.has_hwp_capabilities()); + assert!(!mw.has_hwp_peci_override()); + assert!(!mw.has_flexible_hwp()); + assert!(!mw.has_hwp_fast_access_mode()); + assert!(!mw.has_ignore_idle_processor_hwp_request()); + assert!(mw.has_hw_coord_feedback()); + assert!(!mw.has_energy_bias_pref()); +} + +#[test] +fn extended_features() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_extended_feature_info() + .expect("Leaf is supported"); + + assert!(e.has_fsgsbase()); + assert!(!e.has_tsc_adjust_msr()); + assert!(e.has_bmi1()); + assert!(!e.has_hle()); + assert!(e.has_avx2()); + assert!(!e.has_fdp()); + assert!(e.has_smep()); + assert!(e.has_bmi2()); + assert!(!e.has_rep_movsb_stosb()); + assert!(!e.has_invpcid()); + assert!(!e.has_rtm()); + assert!(e.has_rdtm()); + assert!(!e.has_fpu_cs_ds_deprecated()); + assert!(!e.has_mpx()); + assert!(e.has_rdta()); + assert!(e.has_rdseed()); + assert!(e.has_adx()); + assert!(e.has_smap()); + assert!(e.has_clflushopt()); + assert!(!e.has_processor_trace()); + assert!(e.has_sha()); + assert!(!e.has_sgx()); + assert!(!e.has_avx512f()); + assert!(!e.has_avx512dq()); + assert!(!e.has_avx512_ifma()); + assert!(!e.has_avx512pf()); + assert!(!e.has_avx512er()); + assert!(!e.has_avx512cd()); + assert!(!e.has_avx512bw()); + assert!(!e.has_avx512vl()); + assert!(e.has_clwb()); + assert!(!e.has_prefetchwt1()); + assert!(e.has_umip()); + assert!(!e.has_pku()); + assert!(!e.has_ospke()); + assert!(!e.has_avx512vnni()); + assert!(e.has_rdpid()); + assert!(!e.has_sgx_lc()); + assert_eq!(e.mawau_value(), 0x0); +} + +#[test] +fn direct_cache_access() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + assert!( + cpuid.get_direct_cache_access_info().is_none(), + "Not supported by AMD" + ); +} + +#[test] +fn perfmon_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + assert!( + cpuid.get_performance_monitoring_info().is_none(), + "Not supported by AMD" + ); +} + +#[test] +fn extended_topology_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let mut e = cpuid + .get_extended_topology_info() + .expect("Leaf is supported"); + + let t = e.next().expect("Have level 0"); + assert_eq!(t.processors(), 2); + assert_eq!(t.level_number(), 0); + assert_eq!(t.level_type(), TopologyType::SMT); + assert_eq!(t.x2apic_id(), 0x0); + assert_eq!(t.shift_right_for_next_apic_id(), 0x1); + + let t = e.next().expect("Have level 1"); + assert_eq!(t.processors(), 12); + assert_eq!(t.level_number(), 1); + assert_eq!(t.level_type(), TopologyType::Core); + assert_eq!(t.x2apic_id(), 0x0); + assert_eq!(t.shift_right_for_next_apic_id(), 0x7); +} + +#[test] +fn extended_state_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_extended_state_info().expect("Leaf is supported"); + + assert!(e.xcr0_supports_legacy_x87()); + assert!(e.xcr0_supports_sse_128()); + assert!(e.xcr0_supports_avx_256()); + assert!(!e.xcr0_supports_mpx_bndregs()); + assert!(!e.xcr0_supports_mpx_bndcsr()); + assert!(!e.xcr0_supports_avx512_opmask()); + assert!(!e.xcr0_supports_avx512_zmm_hi256()); + assert!(!e.xcr0_supports_avx512_zmm_hi16()); + assert!(e.xcr0_supports_pkru()); + assert!(!e.ia32_xss_supports_pt()); + assert!(!e.ia32_xss_supports_hdc()); + assert_eq!(e.xsave_area_size_enabled_features(), 0x00000340); + assert_eq!(e.xsave_area_size_supported_features(), 0x00000380); + assert!(e.has_xsaveopt()); + assert!(e.has_xsavec()); + assert!(e.has_xgetbv()); + assert!(e.has_xsaves_xrstors()); + assert_eq!(e.xsave_size(), 0x00000340); + + let mut e = e.iter(); + let ee = e.next().expect("Has level 2"); + assert_eq!(ee.size(), 256); + assert_eq!(ee.offset(), 576); + assert!(ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 9"); + assert_eq!(ee.size(), 64); + assert_eq!(ee.offset(), 832); + assert!(ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); +} + +#[test] +fn rdt_monitoring_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_rdt_monitoring_info().expect("Leaf is supported"); + + assert!(e.has_l3_monitoring()); + assert_eq!(e.rmid_range(), 255); + + let l3m = e.l3_monitoring().expect("Leaf is available"); + assert_eq!(l3m.conversion_factor(), 64); + assert_eq!(l3m.maximum_rmid_range(), 255); + assert!(l3m.has_occupancy_monitoring()); + assert!(l3m.has_total_bandwidth_monitoring()); + assert!(l3m.has_local_bandwidth_monitoring()); +} + +#[test] +fn rdt_allocation_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_rdt_allocation_info().expect("Leaf is supported"); + + assert!(e.has_l3_cat()); + assert!(!e.has_l2_cat()); + assert!(!e.has_memory_bandwidth_allocation()); + assert!(e.l2_cat().is_none()); + assert!(e.memory_bandwidth_allocation().is_none()); + + let l3c = e.l3_cat().expect("Leaf is available"); + assert_eq!(l3c.capacity_mask_length(), 0x10); + assert_eq!(l3c.isolation_bitmap(), 0x0); + assert_eq!(l3c.highest_cos(), 15); + assert!(l3c.has_code_data_prioritization()); +} + +#[test] +fn extended_processor_and_feature_identifiers() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_extended_processor_and_feature_identifiers() + .expect("Leaf is supported"); + + assert_eq!(e.pkg_type(), 0x2); + assert_eq!(e.brand_id(), 0x0); + + assert!(e.has_lahf_sahf()); + assert!(e.has_cmp_legacy()); + assert!(e.has_svm()); + assert!(e.has_ext_apic_space()); + assert!(e.has_alt_mov_cr8()); + assert!(e.has_lzcnt()); + assert!(e.has_sse4a()); + assert!(e.has_misaligned_sse_mode()); + assert!(e.has_prefetchw()); + assert!(e.has_osvw()); + assert!(e.has_ibs()); + assert!(!e.has_xop()); + assert!(e.has_skinit()); + assert!(e.has_wdt()); + assert!(!e.has_lwp()); + assert!(!e.has_fma4()); + assert!(!e.has_tbm()); + assert!(e.has_topology_extensions()); + assert!(e.has_perf_cntr_extensions()); + assert!(e.has_nb_perf_cntr_extensions()); + assert!(e.has_data_access_bkpt_extension()); + assert!(!e.has_perf_tsc()); + assert!(e.has_perf_cntr_llc_extensions()); + assert!(e.has_monitorx_mwaitx()); + assert!(e.has_addr_mask_extension()); + assert!(e.has_syscall_sysret()); + assert!(e.has_execute_disable()); + assert!(e.has_mmx_extensions()); + assert!(e.has_fast_fxsave_fxstor()); + assert!(e.has_1gib_pages()); + assert!(e.has_rdtscp()); + assert!(e.has_64bit_mode()); + assert!(!e.has_amd_3dnow_extensions()); + assert!(!e.has_3dnow()); +} + +#[test] +fn brand_string() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_processor_brand_string() + .expect("Leaf is supported"); + + assert_eq!(e.as_str(), "AMD Ryzen 5 3600X 6-Core Processor"); +} + +#[test] +fn l1_tlb_cache() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_l1_cache_and_tlb_info() + .expect("Leaf is supported"); + + assert_eq!( + e.dtlb_2m_4m_associativity(), + Associativity::FullyAssociative + ); + assert_eq!(e.dtlb_2m_4m_size(), 64); + + assert_eq!( + e.itlb_2m_4m_associativity(), + Associativity::FullyAssociative + ); + assert_eq!(e.itlb_2m_4m_size(), 64); + + assert_eq!(e.dtlb_4k_associativity(), Associativity::FullyAssociative); + assert_eq!(e.dtlb_4k_size(), 64); + assert_eq!(e.itlb_4k_associativity(), Associativity::FullyAssociative); + assert_eq!(e.itlb_4k_size(), 64); + + assert_eq!(e.dcache_line_size(), 64); + assert_eq!(e.dcache_lines_per_tag(), 1); + assert_eq!(e.dcache_associativity(), Associativity::NWay(8)); + assert_eq!(e.dcache_size(), 32); + + assert_eq!(e.icache_line_size(), 64); + assert_eq!(e.icache_lines_per_tag(), 1); + assert_eq!(e.icache_associativity(), Associativity::NWay(8)); + assert_eq!(e.icache_size(), 32); +} + +#[test] +fn l2_l3_tlb_cache() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_l2_l3_cache_and_tlb_info() + .expect("Leaf is supported"); + + assert_eq!(e.itlb_2m_4m_associativity(), Associativity::NWay(8)); + assert_eq!(e.itlb_2m_4m_size(), 1024); + + assert_eq!(e.dtlb_2m_4m_associativity(), Associativity::NWay(4)); + assert_eq!(e.dtlb_2m_4m_size(), 2048); + + assert_eq!(e.itlb_4k_size(), 1024); + assert_eq!(e.itlb_4k_associativity(), Associativity::NWay(8)); + + assert_eq!(e.dtlb_4k_size(), 2048); + assert_eq!(e.dtlb_4k_associativity(), Associativity::NWay(8)); + + assert_eq!(e.l2cache_line_size(), 64); + assert_eq!(e.l2cache_lines_per_tag(), 1); + assert_eq!(e.l2cache_associativity(), Associativity::NWay(8)); + assert_eq!(e.l2cache_size(), 0x200); + + assert_eq!(e.l3cache_line_size(), 64); + assert_eq!(e.l3cache_lines_per_tag(), 1); + assert_eq!(e.l3cache_associativity(), Associativity::Unknown); + assert_eq!(e.l3cache_size(), 64); +} + +#[test] +fn apm() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_advanced_power_mgmt_info() + .expect("Leaf is supported"); + + assert_eq!(e.cpu_pwr_sample_time_ratio(), 0x0); + + assert!(e.has_mca_overflow_recovery()); + assert!(e.has_succor()); + assert!(!e.has_hwa()); + + assert!(e.has_ts()); + assert!(!e.has_freq_id_ctrl()); + assert!(!e.has_volt_id_ctrl()); + assert!(e.has_thermtrip()); + assert!(e.has_tm()); + assert!(!e.has_100mhz_steps()); + assert!(e.has_hw_pstate()); + assert!(e.has_invariant_tsc()); + assert!(e.has_cpb()); + assert!(e.has_ro_effective_freq_iface()); + assert!(!e.has_feedback_iface()); + assert!(!e.has_power_reporting_iface()); +} + +#[test] +fn processor_capcity_features() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_processor_capacity_feature_info() + .expect("Leaf is supported"); + + assert_eq!(e.physical_address_bits(), 48); + assert_eq!(e.linear_address_bits(), 48); + assert_eq!(e.guest_physical_address_bits(), 0); + + // These are hard to test if they are correct. I think the cpuid CLI tool + // displays bogus values here (see above) -- or I can't tell how they + // correspond to the AMD manual... + assert!(e.has_cl_zero()); + assert!(e.has_inst_ret_cntr_msr()); + assert!(e.has_restore_fp_error_ptrs()); + assert!(!e.has_invlpgb()); + assert!(e.has_rdpru()); + assert!(e.has_mcommit()); + assert!(e.has_wbnoinvd()); + assert!(e.has_int_wbinvd()); + assert!(!e.has_unsupported_efer_lmsle()); + assert!(!e.has_invlpgb_nested()); + + assert_eq!(e.invlpgb_max_pages(), 0x0); + assert_eq!(e.maximum_logical_processors(), 128); + assert_eq!(e.num_phys_threads(), 12); + assert_eq!(e.apic_id_size(), 7); + assert_eq!(e.perf_tsc_size(), 40); + assert_eq!(e.max_rdpru_id(), 0x1); +} + +#[test] +fn secure_encryption() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_memory_encryption_info() + .expect("Leaf is supported"); + + assert!(e.has_sme()); + assert!(e.has_sev()); + assert!(e.has_page_flush_msr()); + assert!(e.has_sev_es()); + assert!(!e.has_sev_snp()); + assert!(!e.has_vmpl()); + assert!(!e.has_hw_enforced_cache_coh()); + assert!(!e.has_64bit_mode()); + assert!(!e.has_restricted_injection()); + assert!(!e.has_alternate_injection()); + assert!(!e.has_debug_swap()); + assert!(!e.has_prevent_host_ibs()); + assert!(e.has_vte()); + + assert_eq!(e.c_bit_position(), 0x2f); + assert_eq!(e.physical_address_reduction(), 0x5); + assert_eq!(e.max_encrypted_guests(), 0x1fd); + assert_eq!(e.min_sev_no_es_asid(), 0x1); +} + +#[test] +fn svm() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_svm_info().expect("Leaf is supported"); + + assert_eq!(e.revision(), 0x1); + assert_eq!(e.supported_asids(), 0x8000); + + assert!(e.has_nested_paging()); + assert!(e.has_lbr_virtualization()); + assert!(e.has_svm_lock()); + assert!(e.has_nrip()); + assert!(e.has_tsc_rate_msr()); + assert!(e.has_vmcb_clean_bits()); + assert!(e.has_flush_by_asid()); + assert!(e.has_decode_assists()); + assert!(e.has_pause_filter()); + assert!(e.has_pause_filter_threshold()); + assert!(e.has_avic()); + assert!(e.has_vmsave_virtualization()); + assert!(e.has_gmet()); + assert!(!e.has_sss_check()); + assert!(e.has_spec_ctrl()); + assert!(!e.has_host_mce_override()); + assert!(!e.has_tlb_ctrl()); +} + +#[test] +fn tlb_1gb_page_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_tlb_1gb_page_info().expect("Leaf is supported"); + + assert!(e.dtlb_l1_1gb_associativity() == Associativity::FullyAssociative); + assert!(e.dtlb_l1_1gb_size() == 64); + assert!(e.itlb_l1_1gb_associativity() == Associativity::FullyAssociative); + assert!(e.itlb_l1_1gb_size() == 64); + assert!(e.dtlb_l2_1gb_associativity() == Associativity::Disabled); + assert!(e.dtlb_l2_1gb_size() == 0); + assert!(e.itlb_l2_1gb_associativity() == Associativity::Disabled); + assert!(e.itlb_l2_1gb_size() == 0); +} + +#[test] +fn performance_optimization_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_performance_optimization_info() + .expect("Leaf is supported"); + + assert!(!e.has_fp128()); + assert!(e.has_movu()); + assert!(e.has_fp256()); +} + +#[test] +fn processor_topology_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_processor_topology_info() + .expect("Leaf is supported"); + + assert!(e.x2apic_id() == 0); + assert!(e.core_id() == 0); + assert!(e.threads_per_core() == 2); + assert!(e.node_id() == 0); + assert!(e.nodes_per_processor() == 1); +} + +#[test] +fn remaining_unsupported_leafs() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + + assert!(cpuid.get_sgx_info().is_none()); + assert!(cpuid.get_processor_trace_info().is_none()); + assert!(cpuid.get_tsc_info().is_none()); + assert!(cpuid.get_processor_frequency_info().is_none()); + assert!(cpuid.get_deterministic_address_translation_info().is_none()); + assert!(cpuid.get_soc_vendor_info().is_none()); + assert!(cpuid.get_extended_topology_info_v2().is_none()); +} diff --git a/vendor/raw-cpuid-10.7.0/src/tests/xeon_gold_6252.rs b/vendor/raw-cpuid-10.7.0/src/tests/xeon_gold_6252.rs new file mode 100644 index 0000000000000..ce7d4929a7360 --- /dev/null +++ b/vendor/raw-cpuid-10.7.0/src/tests/xeon_gold_6252.rs @@ -0,0 +1,1205 @@ +use crate::{CpuId, CpuIdResult}; +use phf::phf_map; + +/// Raw dump of a cascade lake cpuid values. +/// +/// Key format is (eax << 32 | ecx) e.g., two 32 bit values packed in one 64 bit value +/// +/// +/// # Representation of Hex Values +/// +///```log +/// CPU: +/// vendor_id = "GenuineIntel" +/// version information (1/eax): +/// processor type = primary processor (0) +/// family = 0x6 (6) +/// model = 0x5 (5) +/// stepping id = 0x7 (7) +/// extended family = 0x0 (0) +/// extended model = 0x5 (5) +/// (family synth) = 0x6 (6) +/// (model synth) = 0x55 (85) +/// (simple synth) = Intel Core (unknown type) (Skylake / Skylake-X / Cascade Lake / Cascade Lake-X) {Skylake}, 14nm +/// miscellaneous (1/ebx): +/// process local APIC physical ID = 0xda (218) +/// cpu count = 0x40 (64) +/// CLFLUSH line size = 0x8 (8) +/// brand index = 0x0 (0) +/// brand id = 0x00 (0): unknown +/// feature information (1/edx): +/// x87 FPU on chip = true +/// VME: virtual-8086 mode enhancement = true +/// DE: debugging extensions = true +/// PSE: page size extensions = true +/// TSC: time stamp counter = true +/// RDMSR and WRMSR support = true +/// PAE: physical address extensions = true +/// MCE: machine check exception = true +/// CMPXCHG8B inst. = true +/// APIC on chip = true +/// SYSENTER and SYSEXIT = true +/// MTRR: memory type range registers = true +/// PTE global bit = true +/// MCA: machine check architecture = true +/// CMOV: conditional move/compare instr = true +/// PAT: page attribute table = true +/// PSE-36: page size extension = true +/// PSN: processor serial number = false +/// CLFLUSH instruction = true +/// DS: debug store = true +/// ACPI: thermal monitor and clock ctrl = true +/// MMX Technology = true +/// FXSAVE/FXRSTOR = true +/// SSE extensions = true +/// SSE2 extensions = true +/// SS: self snoop = true +/// hyper-threading / multi-core supported = true +/// TM: therm. monitor = true +/// IA64 = false +/// PBE: pending break event = true +/// feature information (1/ecx): +/// PNI/SSE3: Prescott New Instructions = true +/// PCLMULDQ instruction = true +/// DTES64: 64-bit debug store = true +/// MONITOR/MWAIT = true +/// CPL-qualified debug store = true +/// VMX: virtual machine extensions = true +/// SMX: safer mode extensions = true +/// Enhanced Intel SpeedStep Technology = true +/// TM2: thermal monitor 2 = true +/// SSSE3 extensions = true +/// context ID: adaptive or shared L1 data = false +/// SDBG: IA32_DEBUG_INTERFACE = true +/// FMA instruction = true +/// CMPXCHG16B instruction = true +/// xTPR disable = true +/// PDCM: perfmon and debug = true +/// PCID: process context identifiers = true +/// DCA: direct cache access = true +/// SSE4.1 extensions = true +/// SSE4.2 extensions = true +/// x2APIC: extended xAPIC support = true +/// MOVBE instruction = true +/// POPCNT instruction = true +/// time stamp counter deadline = true +/// AES instruction = true +/// XSAVE/XSTOR states = true +/// OS-enabled XSAVE/XSTOR = true +/// AVX: advanced vector extensions = true +/// F16C half-precision convert instruction = true +/// RDRAND instruction = true +/// hypervisor guest status = false +/// cache and TLB information (2): +/// 0x63: data TLB: 2M/4M pages, 4-way, 32 entries +/// data TLB: 1G pages, 4-way, 4 entries +/// 0x03: data TLB: 4K pages, 4-way, 64 entries +/// 0x76: instruction TLB: 2M/4M pages, fully, 8 entries +/// 0xff: cache data is in CPUID leaf 4 +/// 0xb5: instruction TLB: 4K, 8-way, 64 entries +/// 0xf0: 64 byte prefetching +/// 0xc3: L2 TLB: 4K/2M pages, 6-way, 1536 entries +/// processor serial number = 0005-0657-0000-0000-0000-0000 +/// deterministic cache parameters (4): +/// --- cache 0 --- +/// cache type = data cache (1) +/// cache level = 0x1 (1) +/// self-initializing cache level = true +/// fully associative cache = false +/// extra threads sharing this cache = 0x1 (1) +/// extra processor cores on this die = 0x1f (31) +/// system coherency line size = 0x40 (64) +/// physical line partitions = 0x1 (1) +/// ways of associativity = 0x8 (8) +/// number of sets = 0x40 (64) +/// WBINVD/INVD acts on lower caches = false +/// inclusive to lower caches = false +/// complex cache indexing = false +/// number of sets (s) = 64 +/// (size synth) = 32768 (32 KB) +/// --- cache 1 --- +/// cache type = instruction cache (2) +/// cache level = 0x1 (1) +/// self-initializing cache level = true +/// fully associative cache = false +/// extra threads sharing this cache = 0x1 (1) +/// extra processor cores on this die = 0x1f (31) +/// system coherency line size = 0x40 (64) +/// physical line partitions = 0x1 (1) +/// ways of associativity = 0x8 (8) +/// number of sets = 0x40 (64) +/// WBINVD/INVD acts on lower caches = false +/// inclusive to lower caches = false +/// complex cache indexing = false +/// number of sets (s) = 64 +/// (size synth) = 32768 (32 KB) +/// --- cache 2 --- +/// cache type = unified cache (3) +/// cache level = 0x2 (2) +/// self-initializing cache level = true +/// fully associative cache = false +/// extra threads sharing this cache = 0x1 (1) +/// extra processor cores on this die = 0x1f (31) +/// system coherency line size = 0x40 (64) +/// physical line partitions = 0x1 (1) +/// ways of associativity = 0x10 (16) +/// number of sets = 0x400 (1024) +/// WBINVD/INVD acts on lower caches = false +/// inclusive to lower caches = false +/// complex cache indexing = false +/// number of sets (s) = 1024 +/// (size synth) = 1048576 (1024 KB) +/// --- cache 3 --- +/// cache type = unified cache (3) +/// cache level = 0x3 (3) +/// self-initializing cache level = true +/// fully associative cache = false +/// extra threads sharing this cache = 0x3f (63) +/// extra processor cores on this die = 0x1f (31) +/// system coherency line size = 0x40 (64) +/// physical line partitions = 0x1 (1) +/// ways of associativity = 0xb (11) +/// number of sets = 0xd000 (53248) +/// WBINVD/INVD acts on lower caches = true +/// inclusive to lower caches = false +/// complex cache indexing = true +/// number of sets (s) = 53248 +/// (size synth) = 37486592 (35.8 MB) +/// MONITOR/MWAIT (5): +/// smallest monitor-line size (bytes) = 0x40 (64) +/// largest monitor-line size (bytes) = 0x40 (64) +/// enum of Monitor-MWAIT exts supported = true +/// supports intrs as break-event for MWAIT = true +/// number of C0 sub C-states using MWAIT = 0x0 (0) +/// number of C1 sub C-states using MWAIT = 0x2 (2) +/// number of C2 sub C-states using MWAIT = 0x0 (0) +/// number of C3 sub C-states using MWAIT = 0x2 (2) +/// number of C4 sub C-states using MWAIT = 0x0 (0) +/// number of C5 sub C-states using MWAIT = 0x0 (0) +/// number of C6 sub C-states using MWAIT = 0x0 (0) +/// number of C7 sub C-states using MWAIT = 0x0 (0) +/// Thermal and Power Management Features (6): +/// digital thermometer = true +/// Intel Turbo Boost Technology = true +/// ARAT always running APIC timer = true +/// PLN power limit notification = true +/// ECMD extended clock modulation duty = true +/// PTM package thermal management = true +/// HWP base registers = false +/// HWP notification = false +/// HWP activity window = false +/// HWP energy performance preference = false +/// HWP package level request = false +/// HDC base registers = false +/// Intel Turbo Boost Max Technology 3.0 = false +/// HWP capabilities = false +/// HWP PECI override = false +/// flexible HWP = false +/// IA32_HWP_REQUEST MSR fast access mode = false +/// HW_FEEDBACK = false +/// ignoring idle logical processor HWP req = false +/// digital thermometer thresholds = 0x2 (2) +/// hardware coordination feedback = true +/// ACNT2 available = false +/// performance-energy bias capability = true +/// performance capability reporting = false +/// energy efficiency capability reporting = false +/// size of feedback struct (4KB pages) = 0x0 (0) +/// index of CPU's row in feedback struct = 0x0 (0) +/// extended feature flags (7): +/// FSGSBASE instructions = true +/// IA32_TSC_ADJUST MSR supported = true +/// SGX: Software Guard Extensions supported = false +/// BMI1 instructions = true +/// HLE hardware lock elision = false +/// AVX2: advanced vector extensions 2 = true +/// FDP_EXCPTN_ONLY = true +/// SMEP supervisor mode exec protection = true +/// BMI2 instructions = true +/// enhanced REP MOVSB/STOSB = true +/// INVPCID instruction = true +/// RTM: restricted transactional memory = false +/// RDT-CMT/PQoS cache monitoring = true +/// deprecated FPU CS/DS = true +/// MPX: intel memory protection extensions = true +/// RDT-CAT/PQE cache allocation = true +/// AVX512F: AVX-512 foundation instructions = true +/// AVX512DQ: double & quadword instructions = true +/// RDSEED instruction = true +/// ADX instructions = true +/// SMAP: supervisor mode access prevention = true +/// AVX512IFMA: fused multiply add = false +/// PCOMMIT instruction = false +/// CLFLUSHOPT instruction = true +/// CLWB instruction = true +/// Intel processor trace = true +/// AVX512PF: prefetch instructions = false +/// AVX512ER: exponent & reciprocal instrs = false +/// AVX512CD: conflict detection instrs = true +/// SHA instructions = false +/// AVX512BW: byte & word instructions = true +/// AVX512VL: vector length = true +/// PREFETCHWT1 = false +/// AVX512VBMI: vector byte manipulation = false +/// UMIP: user-mode instruction prevention = false +/// PKU protection keys for user-mode = true +/// OSPKE CR4.PKE and RDPKRU/WRPKRU = true +/// WAITPKG instructions = false +/// AVX512_VBMI2: byte VPCOMPRESS, VPEXPAND = false +/// CET_SS: CET shadow stack = false +/// GFNI: Galois Field New Instructions = false +/// VAES instructions = false +/// VPCLMULQDQ instruction = false +/// AVX512_VNNI: neural network instructions = true +/// AVX512_BITALG: bit count/shiffle = false +/// TME: Total Memory Encryption = false +/// AVX512: VPOPCNTDQ instruction = false +/// 5-level paging = false +/// BNDLDX/BNDSTX MAWAU value in 64-bit mode = 0x0 (0) +/// RDPID: read processor D supported = false +/// CLDEMOTE supports cache line demote = false +/// MOVDIRI instruction = false +/// MOVDIR64B instruction = false +/// ENQCMD instruction = false +/// SGX_LC: SGX launch config supported = false +/// AVX512_4VNNIW: neural network instrs = false +/// AVX512_4FMAPS: multiply acc single prec = false +/// fast short REP MOV = false +/// AVX512_VP2INTERSECT: intersect mask regs = false +/// VERW md-clear microcode support = true +/// hybrid part = false +/// PCONFIG instruction = false +/// CET_IBT: CET indirect branch tracking = false +/// IBRS/IBPB: indirect branch restrictions = true +/// STIBP: 1 thr indirect branch predictor = true +/// L1D_FLUSH: IA32_FLUSH_CMD MSR = true +/// IA32_ARCH_CAPABILITIES MSR = true +/// IA32_CORE_CAPABILITIES MSR = false +/// SSBD: speculative store bypass disable = true +/// Direct Cache Access Parameters (9): +/// PLATFORM_DCA_CAP MSR bits = 0 +/// Architecture Performance Monitoring Features (0xa/eax): +/// version ID = 0x4 (4) +/// number of counters per logical processor = 0x4 (4) +/// bit width of counter = 0x30 (48) +/// length of EBX bit vector = 0x7 (7) +/// Architecture Performance Monitoring Features (0xa/ebx): +/// core cycle event not available = false +/// instruction retired event not available = false +/// reference cycles event not available = false +/// last-level cache ref event not available = false +/// last-level cache miss event not avail = false +/// branch inst retired event not available = false +/// branch mispred retired event not avail = false +/// Architecture Performance Monitoring Features (0xa/edx): +/// number of fixed counters = 0x3 (3) +/// bit width of fixed counters = 0x30 (48) +/// anythread deprecation = false +/// x2APIC features / processor topology (0xb): +/// extended APIC ID = 218 +/// --- level 0 --- +/// level number = 0x0 (0) +/// level type = thread (1) +/// bit width of level = 0x1 (1) +/// number of logical processors at level = 0x2 (2) +/// --- level 1 --- +/// level number = 0x1 (1) +/// level type = core (2) +/// bit width of level = 0x6 (6) +/// number of logical processors at level = 0x30 (48) +/// XSAVE features (0xd/0): +/// XCR0 lower 32 bits valid bit field mask = 0x000002ff +/// XCR0 upper 32 bits valid bit field mask = 0x00000000 +/// XCR0 supported: x87 state = true +/// XCR0 supported: SSE state = true +/// XCR0 supported: AVX state = true +/// XCR0 supported: MPX BNDREGS = true +/// XCR0 supported: MPX BNDCSR = true +/// XCR0 supported: AVX-512 opmask = true +/// XCR0 supported: AVX-512 ZMM_Hi256 = true +/// XCR0 supported: AVX-512 Hi16_ZMM = true +/// IA32_XSS supported: PT state = false +/// XCR0 supported: PKRU state = true +/// XCR0 supported: CET_U state = false +/// XCR0 supported: CET_S state = false +/// IA32_XSS supported: HDC state = false +/// bytes required by fields in XCR0 = 0x00000a88 (2696) +/// bytes required by XSAVE/XRSTOR area = 0x00000a88 (2696) +/// XSAVE features (0xd/1): +/// XSAVEOPT instruction = true +/// XSAVEC instruction = true +/// XGETBV instruction = true +/// XSAVES/XRSTORS instructions = true +/// SAVE area size in bytes = 0x00000a08 (2568) +/// IA32_XSS lower 32 bits valid bit field mask = 0x00000100 +/// IA32_XSS upper 32 bits valid bit field mask = 0x00000000 +/// AVX/YMM features (0xd/2): +/// AVX/YMM save state byte size = 0x00000100 (256) +/// AVX/YMM save state byte offset = 0x00000240 (576) +/// supported in IA32_XSS or XCR0 = XCR0 (user state) +/// 64-byte alignment in compacted XSAVE = false +/// MPX BNDREGS features (0xd/3): +/// MPX BNDREGS save state byte size = 0x00000040 (64) +/// MPX BNDREGS save state byte offset = 0x000003c0 (960) +/// supported in IA32_XSS or XCR0 = XCR0 (user state) +/// 64-byte alignment in compacted XSAVE = false +/// MPX BNDCSR features (0xd/4): +/// MPX BNDCSR save state byte size = 0x00000040 (64) +/// MPX BNDCSR save state byte offset = 0x00000400 (1024) +/// supported in IA32_XSS or XCR0 = XCR0 (user state) +/// 64-byte alignment in compacted XSAVE = false +/// AVX-512 opmask features (0xd/5): +/// AVX-512 opmask save state byte size = 0x00000040 (64) +/// AVX-512 opmask save state byte offset = 0x00000440 (1088) +/// supported in IA32_XSS or XCR0 = XCR0 (user state) +/// 64-byte alignment in compacted XSAVE = false +/// AVX-512 ZMM_Hi256 features (0xd/6): +/// AVX-512 ZMM_Hi256 save state byte size = 0x00000200 (512) +/// AVX-512 ZMM_Hi256 save state byte offset = 0x00000480 (1152) +/// supported in IA32_XSS or XCR0 = XCR0 (user state) +/// 64-byte alignment in compacted XSAVE = false +/// AVX-512 Hi16_ZMM features (0xd/7): +/// AVX-512 Hi16_ZMM save state byte size = 0x00000400 (1024) +/// AVX-512 Hi16_ZMM save state byte offset = 0x00000680 (1664) +/// supported in IA32_XSS or XCR0 = XCR0 (user state) +/// 64-byte alignment in compacted XSAVE = false +/// PT features (0xd/8): +/// PT save state byte size = 0x00000080 (128) +/// PT save state byte offset = 0x00000000 (0) +/// supported in IA32_XSS or XCR0 = IA32_XSS (supervisor state) +/// 64-byte alignment in compacted XSAVE = false +/// PKRU features (0xd/9): +/// PKRU save state byte size = 0x00000008 (8) +/// PKRU save state byte offset = 0x00000a80 (2688) +/// supported in IA32_XSS or XCR0 = XCR0 (user state) +/// 64-byte alignment in compacted XSAVE = false +/// Quality of Service Monitoring Resource Type (0xf/0): +/// Maximum range of RMID = 207 +/// supports L3 cache QoS monitoring = true +/// L3 Cache Quality of Service Monitoring (0xf/1): +/// Conversion factor from IA32_QM_CTR to bytes = 106496 +/// Maximum range of RMID = 207 +/// supports L3 occupancy monitoring = true +/// supports L3 total bandwidth monitoring = true +/// supports L3 local bandwidth monitoring = true +/// Resource Director Technology Allocation (0x10/0): +/// L3 cache allocation technology supported = true +/// L2 cache allocation technology supported = false +/// memory bandwidth allocation supported = true +/// L3 Cache Allocation Technology (0x10/1): +/// length of capacity bit mask = 0xb (11) +/// Bit-granular map of isolation/contention = 0x00000600 +/// infrequent updates of COS = false +/// code and data prioritization supported = true +/// highest COS number supported = 0xf (15) +/// Memory Bandwidth Allocation (0x10/3): +/// maximum throttling value = 0x5a (90) +/// delay values are linear = true +/// highest COS number supported = 0x7 (7) +/// 0x00000011 0x00: eax=0x00000000 ebx=0x00000000 ecx=0x00000000 edx=0x00000000 +/// Software Guard Extensions (SGX) capability (0x12/0): +/// SGX1 supported = false +/// SGX2 supported = false +/// SGX ENCLV E*VIRTCHILD, ESETCONTEXT = false +/// SGX ENCLS ETRACKC, ERDINFO, ELDBC, ELDUC = false +/// MISCSELECT.EXINFO supported: #PF & #GP = false +/// MISCSELECT.CPINFO supported: #CP = false +/// MaxEnclaveSize_Not64 (log2) = 0x0 (0) +/// MaxEnclaveSize_64 (log2) = 0x0 (0) +/// 0x00000013 0x00: eax=0x00000000 ebx=0x00000000 ecx=0x00000000 edx=0x00000000 +/// Intel Processor Trace (0x14): +/// IA32_RTIT_CR3_MATCH is accessible = true +/// configurable PSB & cycle-accurate = true +/// IP & TraceStop filtering; PT preserve = true +/// MTC timing packet; suppress COFI-based = true +/// PTWRITE support = false +/// power event trace support = false +/// ToPA output scheme support = true +/// ToPA can hold many output entries = true +/// single-range output scheme support = true +/// output to trace transport = false +/// IP payloads have LIP values & CS = false +/// configurable address ranges = 0x2 (2) +/// supported MTC periods bitmask = 0x249 (585) +/// supported cycle threshold bitmask = 0x3fff (16383) +/// supported config PSB freq bitmask = 0x3f (63) +/// Time Stamp Counter/Core Crystal Clock Information (0x15): +/// TSC/clock ratio = 168/2 +/// nominal core crystal clock = 0 Hz +/// Processor Frequency Information (0x16): +/// Core Base Frequency (MHz) = 0x834 (2100) +/// Core Maximum Frequency (MHz) = 0xe74 (3700) +/// Bus (Reference) Frequency (MHz) = 0x64 (100) +/// extended feature flags (0x80000001/edx): +/// SYSCALL and SYSRET instructions = true +/// execution disable = true +/// 1-GB large page support = true +/// RDTSCP = true +/// 64-bit extensions technology available = true +/// Intel feature flags (0x80000001/ecx): +/// LAHF/SAHF supported in 64-bit mode = true +/// LZCNT advanced bit manipulation = true +/// 3DNow! PREFETCH/PREFETCHW instructions = true +/// brand = "Intel(R) Xeon(R) Gold 6252 CPU @ 2.10GHz" +/// L1 TLB/cache information: 2M/4M pages & L1 TLB (0x80000005/eax): +/// instruction # entries = 0x0 (0) +/// instruction associativity = 0x0 (0) +/// data # entries = 0x0 (0) +/// data associativity = 0x0 (0) +/// L1 TLB/cache information: 4K pages & L1 TLB (0x80000005/ebx): +/// instruction # entries = 0x0 (0) +/// instruction associativity = 0x0 (0) +/// data # entries = 0x0 (0) +/// data associativity = 0x0 (0) +/// L1 data cache information (0x80000005/ecx): +/// line size (bytes) = 0x0 (0) +/// lines per tag = 0x0 (0) +/// associativity = 0x0 (0) +/// size (KB) = 0x0 (0) +/// L1 instruction cache information (0x80000005/edx): +/// line size (bytes) = 0x0 (0) +/// lines per tag = 0x0 (0) +/// associativity = 0x0 (0) +/// size (KB) = 0x0 (0) +/// L2 TLB/cache information: 2M/4M pages & L2 TLB (0x80000006/eax): +/// instruction # entries = 0x0 (0) +/// instruction associativity = L2 off (0) +/// data # entries = 0x0 (0) +/// data associativity = L2 off (0) +/// L2 TLB/cache information: 4K pages & L2 TLB (0x80000006/ebx): +/// instruction # entries = 0x0 (0) +/// instruction associativity = L2 off (0) +/// data # entries = 0x0 (0) +/// data associativity = L2 off (0) +/// L2 unified cache information (0x80000006/ecx): +/// line size (bytes) = 0x40 (64) +/// lines per tag = 0x0 (0) +/// associativity = 8-way (6) +/// size (KB) = 0x100 (256) +/// L3 cache information (0x80000006/edx): +/// line size (bytes) = 0x0 (0) +/// lines per tag = 0x0 (0) +/// associativity = L2 off (0) +/// size (in 512KB units) = 0x0 (0) +/// RAS Capability (0x80000007/ebx): +/// MCA overflow recovery support = false +/// SUCCOR support = false +/// HWA: hardware assert support = false +/// scalable MCA support = false +/// Advanced Power Management Features (0x80000007/ecx): +/// CmpUnitPwrSampleTimeRatio = 0x0 (0) +/// Advanced Power Management Features (0x80000007/edx): +/// TS: temperature sensing diode = false +/// FID: frequency ID control = false +/// VID: voltage ID control = false +/// TTP: thermal trip = false +/// TM: thermal monitor = false +/// STC: software thermal control = false +/// 100 MHz multiplier control = false +/// hardware P-State control = false +/// TscInvariant = true +/// CPB: core performance boost = false +/// read-only effective frequency interface = false +/// processor feedback interface = false +/// APM power reporting = false +/// connected standby = false +/// RAPL: running average power limit = false +/// Physical Address and Linear Address Size (0x80000008/eax): +/// maximum physical address bits = 0x2e (46) +/// maximum linear (virtual) address bits = 0x30 (48) +/// maximum guest physical address bits = 0x0 (0) +/// Extended Feature Extensions ID (0x80000008/ebx): +/// CLZERO instruction = false +/// instructions retired count support = false +/// always save/restore error pointers = false +/// RDPRU instruction = false +/// memory bandwidth enforcement = false +/// WBNOINVD instruction = false +/// IBPB: indirect branch prediction barrier = false +/// IBRS: indirect branch restr speculation = false +/// STIBP: 1 thr indirect branch predictor = false +/// STIBP always on preferred mode = false +/// ppin processor id number supported = false +/// SSBD: speculative store bypass disable = false +/// virtualized SSBD = false +/// SSBD fixed in hardware = false +/// Size Identifiers (0x80000008/ecx): +/// number of CPU cores = 0x1 (1) +/// ApicIdCoreIdSize = 0x0 (0) +/// performance time-stamp counter size = 0x0 (0) +/// Feature Extended Size (0x80000008/edx): +/// RDPRU instruction max input support = 0x0 (0) +/// (multi-processing synth) = multi-core (c=24), hyper-threaded (t=2) +/// (multi-processing method) = Intel leaf 0xb +/// (APIC widths synth): CORE_width=6 SMT_width=1 +/// (APIC synth): PKG_ID=1 CORE_ID=45 SMT_ID=0 +/// (uarch synth) = Intel Cascade Lake {Skylake}, 14nm +/// (synth) = Intel Scalable (2nd Gen) Bronze/Silver/Gold/Platinum (Cascade Lake B1/L1/R1) {Skylake}, 14nm +/// ``` +static CPUID_VALUE_MAP: phf::Map = phf_map! { + 0x00000000_00000000u64 => CpuIdResult { eax: 0x00000016, ebx: 0x756e6547, ecx: 0x6c65746e, edx: 0x49656e69 }, + 0x00000001_00000000u64 => CpuIdResult { eax: 0x00050657, ebx: 0xc7400800, ecx: 0x7ffefbff, edx: 0xbfebfbff }, + 0x00000002_00000000u64 => CpuIdResult { eax: 0x76036301, ebx: 0x00f0b5ff, ecx: 0x00000000, edx: 0x00c30000 }, + 0x00000003_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000004_00000000u64 => CpuIdResult { eax: 0x7c004121, ebx: 0x01c0003f, ecx: 0x0000003f, edx: 0x00000000 }, + 0x00000004_00000001u64 => CpuIdResult { eax: 0x7c004122, ebx: 0x01c0003f, ecx: 0x0000003f, edx: 0x00000000 }, + 0x00000004_00000002u64 => CpuIdResult { eax: 0x7c004143, ebx: 0x03c0003f, ecx: 0x000003ff, edx: 0x00000000 }, + 0x00000004_00000003u64 => CpuIdResult { eax: 0x7c0fc163, ebx: 0x0280003f, ecx: 0x0000cfff, edx: 0x00000005 }, + 0x00000005_00000000u64 => CpuIdResult { eax: 0x00000040, ebx: 0x00000040, ecx: 0x00000003, edx: 0x00002020 }, + 0x00000006_00000000u64 => CpuIdResult { eax: 0x00000077, ebx: 0x00000002, ecx: 0x00000009, edx: 0x00000000 }, + 0x00000007_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0xd39ff7eb, ecx: 0x00000818, edx: 0xbc000400 }, + 0x00000008_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000009_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000a_00000000u64 => CpuIdResult { eax: 0x07300404, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000603 }, + 0x0000000b_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x00000002, ecx: 0x00000100, edx: 0x000000c7 }, + 0x0000000b_00000001u64 => CpuIdResult { eax: 0x00000006, ebx: 0x00000030, ecx: 0x00000201, edx: 0x000000c7 }, + 0x0000000c_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000d_00000000u64 => CpuIdResult { eax: 0x000002ff, ebx: 0x00000a88, ecx: 0x00000a88, edx: 0x00000000 }, + 0x0000000d_00000001u64 => CpuIdResult { eax: 0x0000000f, ebx: 0x00000a08, ecx: 0x00000100, edx: 0x00000000 }, + 0x0000000d_00000002u64 => CpuIdResult { eax: 0x00000100, ebx: 0x00000240, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000d_00000003u64 => CpuIdResult { eax: 0x00000040, ebx: 0x000003c0, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000d_00000004u64 => CpuIdResult { eax: 0x00000040, ebx: 0x00000400, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000d_00000005u64 => CpuIdResult { eax: 0x00000040, ebx: 0x00000440, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000d_00000006u64 => CpuIdResult { eax: 0x00000200, ebx: 0x00000480, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000d_00000007u64 => CpuIdResult { eax: 0x00000400, ebx: 0x00000680, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000d_00000008u64 => CpuIdResult { eax: 0x00000080, ebx: 0x00000000, ecx: 0x00000001, edx: 0x00000000 }, + 0x0000000d_00000009u64 => CpuIdResult { eax: 0x00000008, ebx: 0x00000a80, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000e_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x0000000f_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x000000cf, ecx: 0x00000000, edx: 0x00000002 }, + 0x0000000f_00000001u64 => CpuIdResult { eax: 0x00000000, ebx: 0x0001a000, ecx: 0x000000cf, edx: 0x00000007 }, + 0x00000010_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x0000000a, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000010_00000001u64 => CpuIdResult { eax: 0x0000000a, ebx: 0x00000600, ecx: 0x00000004, edx: 0x0000000f }, + 0x00000010_00000003u64 => CpuIdResult { eax: 0x00000059, ebx: 0x00000000, ecx: 0x00000004, edx: 0x00000007 }, + 0x00000011_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000012_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000013_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000014_00000000u64 => CpuIdResult { eax: 0x00000001, ebx: 0x0000000f, ecx: 0x00000007, edx: 0x00000000 }, + 0x00000014_00000001u64 => CpuIdResult { eax: 0x02490002, ebx: 0x003f3fff, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000015_00000000u64 => CpuIdResult { eax: 0x00000002, ebx: 0x000000a8, ecx: 0x00000000, edx: 0x00000000 }, + 0x00000016_00000000u64 => CpuIdResult { eax: 0x00000834, ebx: 0x00000e74, ecx: 0x00000064, edx: 0x00000000 }, + 0x20000000_00000000u64 => CpuIdResult { eax: 0x00000834, ebx: 0x00000e74, ecx: 0x00000064, edx: 0x00000000 }, + 0x80000000_00000000u64 => CpuIdResult { eax: 0x80000008, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000001_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000121, edx: 0x2c100800 }, + 0x80000002_00000000u64 => CpuIdResult { eax: 0x65746e49, ebx: 0x2952286c, ecx: 0x6f655820, edx: 0x2952286e }, + 0x80000003_00000000u64 => CpuIdResult { eax: 0x6c6f4720, ebx: 0x32362064, ecx: 0x43203235, edx: 0x40205550 }, + 0x80000004_00000000u64 => CpuIdResult { eax: 0x312e3220, ebx: 0x7a484730, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000005_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80000006_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x01006040, edx: 0x00000000 }, + 0x80000007_00000000u64 => CpuIdResult { eax: 0x00000000, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000100 }, + 0x80000008_00000000u64 => CpuIdResult { eax: 0x0000302e, ebx: 0x00000000, ecx: 0x00000000, edx: 0x00000000 }, + 0x80860000_00000000u64 => CpuIdResult { eax: 0x00000834, ebx: 0x00000e74, ecx: 0x00000064, edx: 0x00000000 }, + 0xc0000000_00000000u64 => CpuIdResult { eax: 0x00000834, ebx: 0x00000e74, ecx: 0x00000064, edx: 0x00000000 }, +}; + +fn cpuid_reader(eax: u32, ecx: u32) -> CpuIdResult { + let key = (eax as u64) << u32::BITS | ecx as u64; + CPUID_VALUE_MAP[&key] +} + +/// Check that vendor is AuthenticAMD. +#[test] +fn vendor_check() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let v = cpuid.get_vendor_info().expect("Need to find vendor info"); + assert_eq!(v.as_str(), "GenuineIntel"); +} + +/// Check feature info gives correct values for CPU +#[test] +fn version_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let f = cpuid.get_feature_info().expect("Need to find feature info"); + + assert_eq!(f.base_family_id(), 6); + assert_eq!(f.base_model_id(), 5); + assert_eq!(f.stepping_id(), 7); + assert_eq!(f.extended_family_id(), 0); + assert_eq!(f.extended_model_id(), 5); + assert_eq!(f.family_id(), 6); + assert_eq!(f.model_id(), 85); + + assert_eq!(f.max_logical_processor_ids(), 64); + assert_eq!(f.initial_local_apic_id(), 199); // different from recorded output + assert_eq!(f.cflush_cache_line_size(), 0x8); + assert_eq!(f.brand_index(), 0x0); + + assert!(f.has_fpu()); + assert!(f.has_vme()); + assert!(f.has_de()); + assert!(f.has_pse()); + assert!(f.has_tsc()); + assert!(f.has_msr()); + assert!(f.has_pae()); + assert!(f.has_mce()); + assert!(f.has_cmpxchg8b()); + assert!(f.has_apic()); + assert!(f.has_sysenter_sysexit()); + assert!(f.has_mtrr()); + assert!(f.has_pge()); + assert!(f.has_mca()); + assert!(f.has_cmov()); + assert!(f.has_pat()); + assert!(f.has_pse36()); + assert!(!f.has_psn()); + assert!(f.has_clflush()); + assert!(f.has_ds()); + assert!(f.has_acpi()); + assert!(f.has_mmx()); + assert!(f.has_fxsave_fxstor()); + assert!(f.has_sse()); + assert!(f.has_sse2()); + assert!(f.has_ss()); + assert!(f.has_htt()); + assert!(f.has_tm()); + assert!(f.has_pbe()); + + assert!(f.has_sse3()); + assert!(f.has_pclmulqdq()); + assert!(f.has_ds_area()); + assert!(f.has_monitor_mwait()); + assert!(f.has_cpl()); + assert!(f.has_vmx()); + assert!(f.has_smx()); + assert!(f.has_eist()); + assert!(f.has_tm2()); + assert!(f.has_ssse3()); + assert!(!f.has_cnxtid()); + // has_SDBG + assert!(f.has_fma()); + assert!(f.has_cmpxchg16b()); + // xTPR + assert!(f.has_pdcm()); + assert!(f.has_pcid()); + assert!(f.has_dca()); + assert!(f.has_sse41()); + assert!(f.has_sse42()); + assert!(f.has_x2apic()); + assert!(f.has_movbe()); + assert!(f.has_popcnt()); + assert!(f.has_tsc_deadline()); + assert!(f.has_aesni()); + assert!(f.has_xsave()); + assert!(f.has_oxsave()); + assert!(f.has_avx()); + assert!(f.has_f16c()); + assert!(f.has_rdrand()); + assert!(!f.has_hypervisor()); +} + +#[test] +fn cache_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let ci = cpuid.get_cache_info().expect("Leaf is supported"); + + for (idx, cache) in ci.enumerate() { + match idx { + 0 => assert_eq!(cache.num, 0xff), + 1 => assert_eq!(cache.num, 0x63), + 2 => assert_eq!(cache.num, 0xb5), + 3 => assert_eq!(cache.num, 0x03), + 4 => assert_eq!(cache.num, 0xf0), + 5 => assert_eq!(cache.num, 0x76), + 6 => assert_eq!(cache.num, 0xc3), + _ => unreachable!(), + } + } +} + +#[test] +fn processor_serial() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let psn = cpuid.get_processor_serial().expect("Leaf is supported"); + assert_eq!(psn.serial_lower(), 0x0); + assert_eq!(psn.serial_middle(), 0x0); +} + +#[test] +fn monitor_mwait() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let mw = cpuid.get_monitor_mwait_info().expect("Leaf is supported"); + assert_eq!(mw.largest_monitor_line(), 64); + assert_eq!(mw.smallest_monitor_line(), 64); + assert!(mw.interrupts_as_break_event()); + assert!(mw.extensions_supported()); + + assert_eq!(mw.supported_c0_states(), 0x0); + assert_eq!(mw.supported_c1_states(), 0x2); + assert_eq!(mw.supported_c2_states(), 0x0); + assert_eq!(mw.supported_c3_states(), 0x2); + assert_eq!(mw.supported_c4_states(), 0x0); + assert_eq!(mw.supported_c5_states(), 0x0); + assert_eq!(mw.supported_c6_states(), 0x0); + assert_eq!(mw.supported_c7_states(), 0x0); +} + +#[test] +fn thermal_power() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let mw = cpuid.get_thermal_power_info().expect("Leaf is supported"); + + assert!(mw.has_dts()); + assert!(mw.has_turbo_boost()); + assert!(mw.has_arat()); + assert!(mw.has_pln()); + assert!(mw.has_ecmd()); + assert!(mw.has_ptm()); + assert!(!mw.has_hwp()); + assert!(!mw.has_hwp_notification()); + assert!(!mw.has_hwp_activity_window()); + assert!(!mw.has_hwp_energy_performance_preference()); + assert!(!mw.has_hwp_package_level_request()); + assert!(!mw.has_hdc()); + assert!(!mw.has_turbo_boost3()); + assert!(!mw.has_hwp_capabilities()); + assert!(!mw.has_hwp_peci_override()); + assert!(!mw.has_flexible_hwp()); + assert!(!mw.has_hwp_fast_access_mode()); + assert!(mw.has_hw_coord_feedback()); + assert!(!mw.has_ignore_idle_processor_hwp_request()); + // some missing + assert_eq!(mw.dts_irq_threshold(), 0x2); + // some missing + assert!(mw.has_energy_bias_pref()); +} + +#[test] +fn extended_features() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_extended_feature_info() + .expect("Leaf is supported"); + + assert!(e.has_fsgsbase()); + assert!(e.has_tsc_adjust_msr()); + assert!(!e.has_sgx()); + assert!(e.has_bmi1()); + assert!(!e.has_hle()); + assert!(e.has_avx2()); + assert!(e.has_fdp()); + assert!(e.has_smep()); + assert!(e.has_bmi2()); + assert!(e.has_rep_movsb_stosb()); + assert!(e.has_invpcid()); + assert!(!e.has_rtm()); + assert!(e.has_rdtm()); + assert!(e.has_fpu_cs_ds_deprecated()); + assert!(e.has_mpx()); + assert!(e.has_rdta()); + assert!(e.has_avx512f()); + assert!(e.has_avx512dq()); + assert!(e.has_rdseed()); + assert!(e.has_adx()); + assert!(e.has_smap()); + assert!(!e.has_avx512_ifma()); + assert!(e.has_clflushopt()); + assert!(e.has_clwb()); + assert!(e.has_processor_trace()); + assert!(!e.has_avx512pf()); + assert!(!e.has_avx512er()); + assert!(e.has_avx512cd()); + assert!(!e.has_sha()); + assert!(e.has_avx512bw()); + assert!(e.has_avx512vl()); + assert!(!e.has_prefetchwt1()); + // ... + assert!(!e.has_umip()); + assert!(e.has_pku()); + assert!(e.has_ospke()); + assert!(e.has_avx512vnni()); + assert!(!e.has_rdpid()); + assert!(!e.has_sgx_lc()); + assert_eq!(e.mawau_value(), 0x0); +} + +#[test] +fn direct_cache_access() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let dca = cpuid.get_direct_cache_access_info().expect("Leaf exists"); + assert_eq!(dca.get_dca_cap_value(), 0x0); +} + +#[test] +fn perfmon_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let pm = cpuid + .get_performance_monitoring_info() + .expect("Leaf exists"); + + assert_eq!(pm.version_id(), 0x4); + + assert_eq!(pm.number_of_counters(), 0x4); + assert_eq!(pm.counter_bit_width(), 0x30); + assert_eq!(pm.ebx_length(), 0x7); + + assert!(!pm.is_core_cyc_ev_unavailable()); + assert!(!pm.is_inst_ret_ev_unavailable()); + assert!(!pm.is_ref_cycle_ev_unavailable()); + assert!(!pm.is_cache_ref_ev_unavailable()); + assert!(!pm.is_ll_cache_miss_ev_unavailable()); + assert!(!pm.is_branch_inst_ret_ev_unavailable()); + assert!(!pm.is_branch_midpred_ev_unavailable()); + + assert_eq!(pm.fixed_function_counters(), 0x3); + assert_eq!(pm.fixed_function_counters_bit_width(), 0x30); + assert!(!pm.has_any_thread_deprecation()); +} + +#[test] +fn extended_topology_info() { + use crate::TopologyType; + + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let mut e = cpuid + .get_extended_topology_info() + .expect("Leaf is supported"); + + let t = e.next().expect("Have level 0"); + assert_eq!(t.x2apic_id(), 199); // different from doc, unpinned execution + assert_eq!(t.level_number(), 0); + assert_eq!(t.level_type(), TopologyType::SMT); + assert_eq!(t.shift_right_for_next_apic_id(), 0x1); + assert_eq!(t.processors(), 2); + + let t = e.next().expect("Have level 1"); + assert_eq!(t.level_number(), 1); + assert_eq!(t.level_type(), TopologyType::Core); + assert_eq!(t.shift_right_for_next_apic_id(), 0x6); + assert_eq!(t.processors(), 48); + assert_eq!(t.x2apic_id(), 199); // different from doc, unpinned execution +} + +#[test] +fn extended_state_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_extended_state_info().expect("Leaf is supported"); + + assert!(e.xcr0_supports_legacy_x87()); + assert!(e.xcr0_supports_sse_128()); + assert!(e.xcr0_supports_avx_256()); + assert!(e.xcr0_supports_mpx_bndregs()); + assert!(e.xcr0_supports_mpx_bndcsr()); + assert!(e.xcr0_supports_avx512_opmask()); + assert!(e.xcr0_supports_avx512_zmm_hi256()); + assert!(e.xcr0_supports_avx512_zmm_hi16()); + // cpuid binary says this isn't supported, I think it's a bug there and it's + // supposed to read from ecx1 like we do: + assert!(e.ia32_xss_supports_pt()); + assert!(e.xcr0_supports_pkru()); + // ... + assert!(!e.ia32_xss_supports_hdc()); + + assert_eq!(e.xsave_area_size_enabled_features(), 2696); + assert_eq!(e.xsave_area_size_supported_features(), 2696); + assert!(e.has_xsaveopt()); + assert!(e.has_xsavec()); + assert!(e.has_xgetbv()); + assert!(e.has_xsaves_xrstors()); + // ... + assert_eq!(e.xsave_size(), 2568); + // ... + + let mut e = e.iter(); + let ee = e.next().expect("Has level 2"); + assert_eq!(ee.size(), 256); + assert_eq!(ee.offset(), 576); + assert!(ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 3"); + assert_eq!(ee.size(), 64); + assert_eq!(ee.offset(), 960); + assert!(ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 4"); + assert_eq!(ee.size(), 64); + assert_eq!(ee.offset(), 1024); + assert!(ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 5"); + assert_eq!(ee.size(), 64); + assert_eq!(ee.offset(), 1088); + assert!(ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 6"); + assert_eq!(ee.size(), 512); + assert_eq!(ee.offset(), 1152); + assert!(ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 7"); + assert_eq!(ee.size(), 1024); + assert_eq!(ee.offset(), 1664); + assert!(ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 8"); + assert_eq!(ee.size(), 128); + assert_eq!(ee.offset(), 0); + assert!(!ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); + + let ee = e.next().expect("Has level 9"); + assert_eq!(ee.size(), 8); + assert_eq!(ee.offset(), 2688); + assert!(ee.is_in_xcr0()); + assert!(!ee.is_compacted_format()); +} + +#[test] +fn rdt_monitoring_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_rdt_monitoring_info().expect("Leaf is supported"); + + assert_eq!(e.rmid_range(), 207); + assert!(e.has_l3_monitoring()); + + let l3m = e.l3_monitoring().expect("Leaf is available"); + assert_eq!(l3m.conversion_factor(), 106496); + assert_eq!(l3m.maximum_rmid_range(), 207); + assert!(l3m.has_occupancy_monitoring()); + assert!(l3m.has_total_bandwidth_monitoring()); + assert!(l3m.has_local_bandwidth_monitoring()); +} + +#[test] +fn rdt_allocation_info() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_rdt_allocation_info().expect("Leaf is supported"); + + assert!(e.has_l3_cat()); + assert!(!e.has_l2_cat()); + assert!(e.has_memory_bandwidth_allocation()); + + assert!(e.l2_cat().is_none()); + + let l3c = e.l3_cat().expect("Leaf is available"); + assert_eq!(l3c.capacity_mask_length(), 0xb); + assert_eq!(l3c.isolation_bitmap(), 0x00000600); + assert_eq!(l3c.highest_cos(), 15); + assert!(l3c.has_code_data_prioritization()); + // infrequent updates of COS missing + + let mba = e.memory_bandwidth_allocation().expect("Leaf is available"); + assert_eq!(mba.max_hba_throttling(), 90); + assert!(mba.has_linear_response_delay()); + assert_eq!(mba.highest_cos(), 0x7); +} + +#[test] +fn sgx_test() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + assert!(cpuid.get_sgx_info().is_none()); +} + +#[test] +fn processor_trace() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let pt = cpuid.get_processor_trace_info().expect("Leaf is available"); + + assert!(pt.has_rtit_cr3_match()); + assert!(pt.has_configurable_psb_and_cycle_accurate_mode()); + assert!(pt.has_ip_tracestop_filtering()); + assert!(pt.has_mtc_timing_packet_coefi_suppression()); + assert!(!pt.has_ptwrite()); + assert!(!pt.has_power_event_trace()); + assert!(pt.has_topa()); + assert!(pt.has_topa_maximum_entries()); + assert!(pt.has_single_range_output_scheme()); + assert!(!pt.has_trace_transport_subsystem()); + assert!(!pt.has_lip_with_cs_base()); + + assert_eq!(pt.configurable_address_ranges(), 2); + assert_eq!(pt.supported_mtc_period_encodings(), 585); + assert_eq!(pt.supported_cycle_threshold_value_encodings(), 16383); + assert_eq!(pt.supported_psb_frequency_encodings(), 63); +} + +#[test] +fn tsc() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid.get_tsc_info().expect("Leaf is available"); + assert_eq!(e.denominator(), 2); + assert_eq!(e.numerator(), 168); + assert_eq!(e.nominal_frequency(), 0x0); + assert_eq!(e.tsc_frequency(), None); +} + +#[test] +fn processor_frequency() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_processor_frequency_info() + .expect("Leaf is supported"); + + assert_eq!(e.processor_base_frequency(), 2100); + assert_eq!(e.processor_max_frequency(), 3700); + assert_eq!(e.bus_frequency(), 100); +} + +#[test] +fn extended_processor_and_feature_identifiers() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_extended_processor_and_feature_identifiers() + .expect("Leaf is supported"); + + assert_eq!(e.pkg_type(), 0x0); // reserved on Intel + assert_eq!(e.brand_id(), 0x0); // reserved on Intel + + assert!(e.has_lahf_sahf()); + assert!(!e.has_cmp_legacy()); + assert!(!e.has_svm()); + assert!(!e.has_ext_apic_space()); + assert!(!e.has_alt_mov_cr8()); + assert!(e.has_lzcnt()); + assert!(!e.has_sse4a()); + assert!(!e.has_misaligned_sse_mode()); + assert!(e.has_prefetchw()); + assert!(!e.has_osvw()); + assert!(!e.has_ibs()); + assert!(!e.has_xop()); + assert!(!e.has_skinit()); + assert!(!e.has_wdt()); + assert!(!e.has_lwp()); + assert!(!e.has_fma4()); + assert!(!e.has_tbm()); + assert!(!e.has_topology_extensions()); + assert!(!e.has_perf_cntr_extensions()); + assert!(!e.has_nb_perf_cntr_extensions()); + assert!(!e.has_data_access_bkpt_extension()); + assert!(!e.has_perf_tsc()); + assert!(!e.has_perf_cntr_llc_extensions()); + assert!(!e.has_monitorx_mwaitx()); + assert!(!e.has_addr_mask_extension()); + assert!(e.has_syscall_sysret()); + assert!(e.has_execute_disable()); + assert!(!e.has_mmx_extensions()); + assert!(!e.has_fast_fxsave_fxstor()); + assert!(e.has_1gib_pages()); + assert!(e.has_rdtscp()); + assert!(e.has_64bit_mode()); + assert!(!e.has_amd_3dnow_extensions()); + assert!(!e.has_3dnow()); +} + +#[test] +fn brand_string() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_processor_brand_string() + .expect("Leaf is supported"); + + assert_eq!(e.as_str(), "Intel(R) Xeon(R) Gold 6252 CPU @ 2.10GHz"); +} + +#[test] +fn l1_tlb_cache() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + assert!(cpuid.get_l1_cache_and_tlb_info().is_none()); +} + +#[test] +fn l2_l3_tlb_cache() { + use crate::Associativity; + + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_l2_l3_cache_and_tlb_info() + .expect("Leaf is supported"); + + // Unsupported on Intel + assert_eq!(e.itlb_2m_4m_associativity(), Associativity::Disabled); + assert_eq!(e.itlb_2m_4m_size(), 0); + assert_eq!(e.dtlb_2m_4m_associativity(), Associativity::Disabled); + assert_eq!(e.dtlb_2m_4m_size(), 0); + assert_eq!(e.itlb_4k_size(), 0); + assert_eq!(e.itlb_4k_associativity(), Associativity::Disabled); + assert_eq!(e.dtlb_4k_size(), 0); + assert_eq!(e.dtlb_4k_associativity(), Associativity::Disabled); + + // Supported on Intel + assert_eq!(e.l2cache_line_size(), 64); + assert_eq!(e.l2cache_lines_per_tag(), 0); + assert_eq!(e.l2cache_associativity(), Associativity::NWay(8)); + assert_eq!(e.l2cache_size(), 256); + + // Unsupported on Intel + assert_eq!(e.l3cache_line_size(), 0); + assert_eq!(e.l3cache_lines_per_tag(), 0); + assert_eq!(e.l3cache_associativity(), Associativity::Disabled); + assert_eq!(e.l3cache_size(), 0); +} + +#[test] +fn apm() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_advanced_power_mgmt_info() + .expect("Leaf is supported"); + + assert!(!e.has_mca_overflow_recovery()); + assert!(!e.has_succor()); + assert!(!e.has_hwa()); + // ... + assert_eq!(e.cpu_pwr_sample_time_ratio(), 0x0); + + assert!(!e.has_ts()); + assert!(!e.has_freq_id_ctrl()); + assert!(!e.has_volt_id_ctrl()); + assert!(!e.has_thermtrip()); + assert!(!e.has_tm()); + assert!(!e.has_100mhz_steps()); + assert!(!e.has_hw_pstate()); + assert!(e.has_invariant_tsc()); // The only Intel supported feature here + assert!(!e.has_cpb()); + assert!(!e.has_ro_effective_freq_iface()); + assert!(!e.has_feedback_iface()); + assert!(!e.has_power_reporting_iface()); +} + +#[test] +fn processor_capcity_features() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + let e = cpuid + .get_processor_capacity_feature_info() + .expect("Leaf is supported"); + + assert_eq!(e.physical_address_bits(), 46); + assert_eq!(e.linear_address_bits(), 48); + assert_eq!(e.guest_physical_address_bits(), 0); + + assert!(!e.has_cl_zero()); + assert!(!e.has_inst_ret_cntr_msr()); + assert!(!e.has_restore_fp_error_ptrs()); + assert!(!e.has_invlpgb()); + assert!(!e.has_rdpru()); + assert!(!e.has_mcommit()); + assert!(!e.has_wbnoinvd()); + assert!(!e.has_int_wbinvd()); + assert!(!e.has_unsupported_efer_lmsle()); + assert!(!e.has_invlpgb_nested()); + + assert_eq!(e.invlpgb_max_pages(), 0x0); + + assert_eq!(e.maximum_logical_processors(), 1); // Not sure why this is set, it's reserved :( + assert_eq!(e.num_phys_threads(), 1); // Not sure why this is set, it's reserved :( + assert_eq!(e.apic_id_size(), 0); + assert_eq!(e.perf_tsc_size(), 40); // Not sure why this is set, it's reserved :( + assert_eq!(e.max_rdpru_id(), 0); +} + +#[test] +fn remaining_unsupported_leafs() { + let cpuid = CpuId::with_cpuid_fn(cpuid_reader); + + assert!(cpuid.get_deterministic_address_translation_info().is_none()); + assert!(cpuid.get_soc_vendor_info().is_none()); + assert!(cpuid.get_extended_topology_info_v2().is_none()); + assert!(cpuid.get_tlb_1gb_page_info().is_none()); + assert!(cpuid.get_performance_optimization_info().is_none()); + assert!(cpuid.get_processor_topology_info().is_none()); + assert!(cpuid.get_memory_encryption_info().is_none()); +} diff --git a/vendor/raw-window-handle/.cargo-checksum.json b/vendor/raw-window-handle/.cargo-checksum.json new file mode 100644 index 0000000000000..1dddf76596397 --- /dev/null +++ b/vendor/raw-window-handle/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"5e96b71c472c732833ad56a2a759c9cda1ff9379fc59f1e96490848e1ffdb440","Cargo.toml":"7534c93d571e5627b44571365ea93900d812d6232c66d46dc84ca8b3c621fddf","LICENSE-APACHE.md":"0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594","LICENSE-MIT.md":"9c5a80639a57c1c945570e7ebbca0706305849ce3c098021325cca9db2f7acc4","LICENSE-ZLIB.md":"ae895c8576e682f310fb70d93d9f99b1dd82872094c54a8f6cdfe2ca5c2d6ecb","README.md":"2633418eda2bfa891d64f813d59fbcd3915583b70b677d19490ce96146fab966","rustfmt.toml":"a60f9a6656083027a16746999197d72aa6fd7f906969597cb99ce162177f1700","src/android.rs":"ab71aac13da241d1fce139128ae0d6fc387241fdf6342a96656324ddf607e95a","src/appkit.rs":"32e168a0f0dda5564f2ef5c06da900faafaa32bf72da3cdcf4798f7f2221749f","src/borrowed.rs":"b142ee84724b67b72a5e51bcde65f3e8f2816a0c2c74bafb3515b6c1c1f82d92","src/haiku.rs":"a5af3a00b1ecba13a774271790756398017e35375a65be1942d8d50cb8a22ce3","src/lib.rs":"4760709043b847ef196e41a3e55c29bf554893ee797cdd6c61b143a698c21dd3","src/redox.rs":"7b1ad8f7ac8c098360b7536b753834817c7b985aa06f6336c950a3e48c7ddc12","src/uikit.rs":"e4ab89caaae6ab778ec82f7b8b17411372444d4dceb246c4303f3ddfca79e44e","src/unix.rs":"b0abe5252e8ae71794a693487de21c0b29a3157821cc4e2c4577bb51d04d8f0e","src/web.rs":"601f1f390f4f7155d3dc2c505c7851a919d5152839c93a983649a30ea1e68607","src/windows.rs":"ce5f0438875fcc0f8c6db95ceaf4cbea4d95c268fe92e82d92e3b7c913fe83d0"},"package":"f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"} \ No newline at end of file diff --git a/vendor/raw-window-handle/CHANGELOG.md b/vendor/raw-window-handle/CHANGELOG.md new file mode 100644 index 0000000000000..91e5a98bd0ddd --- /dev/null +++ b/vendor/raw-window-handle/CHANGELOG.md @@ -0,0 +1,90 @@ +# Changelog + +## Unreleased + +* Add several types for using raw window handles safely, including `HasWindowHandle`, `WindowHandle`, `HasDisplayHandle`, `DisplayHandle` and `Active`. + +## 0.5.1 (2023-03-07) + +* Add the `rust-version` field (`1.64`). +* Implemented `From` for `RawWindowHandle` and `RawDisplayHandle` + +## 0.5.0 (2022-07-14) + +* **Breaking:** The `RawWindowHandle` variants were split into `RawDisplayHandle` and `RawWindowHandle`. +* The X11 screen is now present in new `XlibDisplayHandle` and `XcbDisplayHandle`. +- Add GBM support. + +## 0.4.3 (2022-03-29) + +* [Add visual IDs to X11 handles](https://github.com/rust-windowing/raw-window-handle/pull/83) +* [Add a link to the MDN page for data attributes in the documentation for WebHandle](https://github.com/rust-windowing/raw-window-handle/pull/86) +* [add haiku support](https://github.com/rust-windowing/raw-window-handle/pull/88) + +## 0.4.2 (2021-11-24) + +* Also implement `HasRawWindowHandle` for `Rc`, and `Arc` where `T: ?Sized`. + +## 0.4.1 (2021-11-19) + +* Added an impl of `HasRawWindowHandle` for `&T`, `Rc`, and `Arc`. The impls for `Rc` and `Arc` require the `alloc` feature. + +## 0.4.0 (2021-11-15) + +* **Breaking:** Remove `_do_not_use` tags to use `#[non_exhaustive]` macro +* **Breaking:** `RawWindowHandle` variants are no longer cfg-guarded by platform. +* **Breaking:** Rename `IOS` to `UiKit`. +* **Breaking:** Rename `MacOS` to `AppKit`. +* **Breaking:** Rename `Windows` to `Win32`. +* **Breaking:** Rename `Redox` to `Orbital`. +* **Breaking:** Rename `Android` to `AndroidNdk`. +* **Breaking:** Inner window handle structs are now exported at crate root. +* Added Windows `WinRt` handle. + +# 0.3.4 (2021-11-27) + +* Add `HasRawWindowHandle` implementation for `HasRawWindowHandle` in the + newer `v0.4`. + This allows "provider" crates that implement `HasRawWindowHandle` (like + `winit`, `sdl2`, `glfw`, `fltk`, ...) to upgrade to `v0.4` without a + breaking change. + Afterwards "consumer" crates (like `gfx`, `wgpu`, `rfd`, ...) can start + upgrading with minimal breakage for their users. + +## 0.3.3 (2019-12-1) + +* Add missing `Hash` implementation for `AndroidHandle`. + +## 0.3.2 (2019-11-29) + +* Add `Hash` implementation for `RawWindowHandle`. + +## 0.3.1 (2019-10-27) + +* Remove `RawWindowHandle`'s `HasRawWindowHandle` implementation, as it was unsound (see [#35](https://github.com/rust-windowing/raw-window-handle/issues/35)) +* Explicitly require that handles within `RawWindowHandle` be valid for the lifetime of the `HasRawWindowHandle` implementation that provided them. + +## 0.3.0 (2019-10-5) + +* **Breaking:** Rename `XLib.surface` to `XLib.window`, as that more accurately represents the underlying type. +* Implement `HasRawWindowHandle` for `RawWindowHandle` +* Add `HINSTANCE` field to `WindowsHandle`. + +## 0.2.0 (2019-09-26) + +* **Breaking:** Rename `X11` to `XLib`. +* Add XCB support. +* Add Web support. +* Add Android support. + +## 0.1.2 (2019-08-13) + +* Fix use of private `_non_exhaustive` field in platform handle structs preventing structs from getting initialized. + +## 0.1.1 (2019-08-13) + +* Flesh out Cargo.toml, adding crates.io info rendering tags. + +## 0.1.0 (2019-08-13) + +* Initial release. diff --git a/vendor/raw-window-handle/Cargo.toml b/vendor/raw-window-handle/Cargo.toml new file mode 100644 index 0000000000000..0014b8fb6fe23 --- /dev/null +++ b/vendor/raw-window-handle/Cargo.toml @@ -0,0 +1,34 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.64" +name = "raw-window-handle" +version = "0.5.2" +authors = ["Osspial "] +description = "Interoperability library for Rust Windowing applications." +documentation = "https://docs.rs/raw-window-handle" +readme = "README.md" +keywords = ["windowing"] +license = "MIT OR Apache-2.0 OR Zlib" +repository = "https://github.com/rust-windowing/raw-window-handle" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[features] +alloc = [] +std = ["alloc"] diff --git a/vendor/raw-window-handle/LICENSE-APACHE.md b/vendor/raw-window-handle/LICENSE-APACHE.md new file mode 100644 index 0000000000000..f433b1a53f5b8 --- /dev/null +++ b/vendor/raw-window-handle/LICENSE-APACHE.md @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/vendor/raw-window-handle/LICENSE-MIT.md b/vendor/raw-window-handle/LICENSE-MIT.md new file mode 100644 index 0000000000000..be95e0b866f5f --- /dev/null +++ b/vendor/raw-window-handle/LICENSE-MIT.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Osspial + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/raw-window-handle/LICENSE-ZLIB.md b/vendor/raw-window-handle/LICENSE-ZLIB.md new file mode 100644 index 0000000000000..f3890311721ff --- /dev/null +++ b/vendor/raw-window-handle/LICENSE-ZLIB.md @@ -0,0 +1,11 @@ +Copyright (c) 2020 Osspial + +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. diff --git a/vendor/raw-window-handle/README.md b/vendor/raw-window-handle/README.md new file mode 100644 index 0000000000000..bee80616365cb --- /dev/null +++ b/vendor/raw-window-handle/README.md @@ -0,0 +1,11 @@ +# `raw-window-handle`: A common windowing interoperability library for Rust + +[![Crates.io](https://img.shields.io/crates/v/raw-window-handle.svg?maxAge=2592000)](https://crates.io/crates/raw-window-handle) +[![Docs](https://docs.rs/raw-window-handle/badge.svg)](https://docs.rs/raw-window-handle) +[![CI Status](https://github.com/rust-windowing/raw-window-handle/workflows/CI/badge.svg)](https://github.com/rust-windowing/raw-window-handle/actions) + +This library provides standard types for accessing a window's platform-specific +raw window handle and display's platform-specific raw display handle. This does +not provide any utilities for creating and managing windows; instead, it +provides a common interface that window creation libraries (e.g. Winit, SDL) +can use to easily talk with graphics libraries (e.g. gfx-hal). diff --git a/vendor/raw-window-handle/rustfmt.toml b/vendor/raw-window-handle/rustfmt.toml new file mode 100644 index 0000000000000..34503e88e1d07 --- /dev/null +++ b/vendor/raw-window-handle/rustfmt.toml @@ -0,0 +1 @@ +use_field_init_shorthand=true diff --git a/vendor/raw-window-handle/src/android.rs b/vendor/raw-window-handle/src/android.rs new file mode 100644 index 0000000000000..e4504cebf249a --- /dev/null +++ b/vendor/raw-window-handle/src/android.rs @@ -0,0 +1,43 @@ +use core::ffi::c_void; +use core::ptr; + +/// Raw display handle for Android. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::AndroidDisplayHandle; +/// let mut display_handle = AndroidDisplayHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct AndroidDisplayHandle; + +impl AndroidDisplayHandle { + pub fn empty() -> Self { + Self {} + } +} + +/// Raw window handle for Android NDK. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::AndroidNdkWindowHandle; +/// let mut window_handle = AndroidNdkWindowHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct AndroidNdkWindowHandle { + /// A pointer to an `ANativeWindow`. + pub a_native_window: *mut c_void, +} + +impl AndroidNdkWindowHandle { + pub fn empty() -> Self { + Self { + a_native_window: ptr::null_mut(), + } + } +} diff --git a/vendor/raw-window-handle/src/appkit.rs b/vendor/raw-window-handle/src/appkit.rs new file mode 100644 index 0000000000000..1023aa038b94a --- /dev/null +++ b/vendor/raw-window-handle/src/appkit.rs @@ -0,0 +1,47 @@ +use core::ffi::c_void; +use core::ptr; + +/// Raw display handle for AppKit. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::AppKitDisplayHandle; +/// let mut display_handle = AppKitDisplayHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct AppKitDisplayHandle; + +impl AppKitDisplayHandle { + pub fn empty() -> Self { + Self {} + } +} + +/// Raw window handle for AppKit. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::AppKitWindowHandle; +/// let mut window_handle = AppKitWindowHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct AppKitWindowHandle { + /// A pointer to an `NSWindow` object. + pub ns_window: *mut c_void, + /// A pointer to an `NSView` object. + pub ns_view: *mut c_void, + // TODO: WHAT ABOUT ns_window_controller and ns_view_controller? +} + +impl AppKitWindowHandle { + pub fn empty() -> Self { + Self { + ns_window: ptr::null_mut(), + ns_view: ptr::null_mut(), + } + } +} diff --git a/vendor/raw-window-handle/src/borrowed.rs b/vendor/raw-window-handle/src/borrowed.rs new file mode 100644 index 0000000000000..b38d3d80a6f6a --- /dev/null +++ b/vendor/raw-window-handle/src/borrowed.rs @@ -0,0 +1,615 @@ +//! Borrowable window handles based on the ones in this crate. +//! +//! These should be 100% safe to pass around and use, no possibility of dangling or invalidity. + +#[cfg(all(not(feature = "std"), target_os = "android"))] +compile_error!("Using borrowed handles on Android requires the `std` feature to be enabled."); + +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::marker::PhantomData; + +use crate::{HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle}; + +/// Keeps track of whether the application is currently active. +/// +/// On certain platforms (e.g. Android), it is possible for the application to enter a "suspended" +/// state. While in this state, all previously valid window handles become invalid. Therefore, in +/// order for window handles to be valid, the application must be active. +/// +/// On platforms where the graphical user interface is always active, this type is a ZST and all +/// of its methods are noops. On Android, this type acts as a reference counter that keeps track +/// of all currently active window handles. Before the application enters the suspended state, it +/// blocks until all of the currently active window handles are dropped. +/// +/// ## Explanation +/// +/// On Android, there is an [Activity]-global [`ANativeWindow`] object that is used for drawing. This +/// handle is used [within the `RawWindowHandle` type] for Android NDK, since it is necessary for GFX +/// APIs to draw to the screen. +/// +/// However, the [`ANativeWindow`] type can be arbitrarily invalidated by the underlying Android runtime. +/// The reasoning for this is complicated, but this idea is exposed to native code through the +/// [`onNativeWindowCreated`] and [`onNativeWindowDestroyed`] callbacks. To save you a click, the +/// conditions associated with these callbacks are: +/// +/// - [`onNativeWindowCreated`] provides a valid [`ANativeWindow`] pointer that can be used for drawing. +/// - [`onNativeWindowDestroyed`] indicates that the previous [`ANativeWindow`] pointer is no longer +/// valid. The documentation clarifies that, *once the function returns*, the [`ANativeWindow`] pointer +/// can no longer be used for drawing without resulting in undefined behavior. +/// +/// In [`winit`], these are exposed via the [`Resumed`] and [`Suspended`] events, respectively. Therefore, +/// between the last [`Suspended`] event and the next [`Resumed`] event, it is undefined behavior to use +/// the raw window handle. This condition makes it tricky to define an API that safely wraps the raw +/// window handles, since an existing window handle can be made invalid at any time. +/// +/// The Android docs specifies that the [`ANativeWindow`] pointer is still valid while the application +/// is still in the [`onNativeWindowDestroyed`] block, and suggests that synchronization needs to take +/// place to ensure that the pointer has been invalidated before the function returns. `Active` aims +/// to be the solution to this problem. It keeps track of all currently active window handles, and +/// blocks until all of them are dropped before allowing the application to enter the suspended state. +/// +/// [Activity]: https://developer.android.com/reference/android/app/Activity +/// [`ANativeWindow`]: https://developer.android.com/ndk/reference/group/a-native-window +/// [within the `RawWindowHandle` type]: struct.AndroidNdkWindowHandle.html#structfield.a_native_window +/// [`onNativeWindowCreated`]: https://developer.android.com/ndk/reference/struct/a-native-activity-callbacks#onnativewindowcreated +/// [`onNativeWindowDestroyed`]: https://developer.android.com/ndk/reference/struct/a-native-activity-callbacks#onnativewindowdestroyed +/// [`Resumed`]: https://docs.rs/winit/latest/winit/event/enum.Event.html#variant.Resumed +/// [`Suspended`]: https://docs.rs/winit/latest/winit/event/enum.Event.html#variant.Suspended +/// [`sdl2`]: https://crates.io/crates/sdl2 +/// [`RawWindowHandle`]: https://docs.rs/raw-window-handle/latest/raw_window_handle/enum.RawWindowHandle.html +/// [`HasRawWindowHandle`]: https://docs.rs/raw-window-handle/latest/raw_window_handle/trait.HasRawWindowHandle.html +/// [`winit`]: https://crates.io/crates/winit +pub struct Active(imp::Active); + +impl fmt::Debug for Active { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Active { .. }") + } +} + +/// Represents a live window handle. +/// +/// This is carried around by the [`Active`] type, and is used to ensure that the application doesn't +/// enter the suspended state while there are still live window handles. See documentation on the +/// [`Active`] type for more information. +/// +/// On non-Android platforms, this is a ZST. On Android, this is a reference counted handle that +/// keeps the application active while it is alive. +#[derive(Clone)] +pub struct ActiveHandle<'a>(imp::ActiveHandle<'a>); + +impl<'a> fmt::Debug for ActiveHandle<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("ActiveHandle { .. }") + } +} + +impl Active { + /// Create a new `Active` tracker. + /// + /// Only one of these should exist per display connection. + /// + /// # Example + /// + /// ``` + /// use raw_window_handle::Active; + /// let active = Active::new(); + /// ``` + pub const fn new() -> Self { + Self(imp::Active::new()) + } + + /// Get a live window handle. + /// + /// This function returns an active handle if the application is active, and `None` otherwise. + /// + /// # Example + /// + /// ``` + /// use raw_window_handle::Active; + /// + /// // Set the application to be active. + /// let active = Active::new(); + /// unsafe { active.set_active() }; + /// + /// // Get a live window handle. + /// let handle = active.handle(); + /// + /// // Drop it and set the application to be inactive. + /// drop(handle); + /// active.set_inactive(); + /// ``` + pub fn handle(&self) -> Option> { + self.0.handle().map(ActiveHandle) + } + + /// Set the application to be inactive. + /// + /// This function may block until there are no more active handles. + /// + /// # Example + /// + /// ``` + /// use raw_window_handle::Active; + /// + /// // Set the application to be active. + /// let active = Active::new(); + /// unsafe { active.set_active() }; + /// + /// // Set the application to be inactive. + /// active.set_inactive(); + /// ``` + pub fn set_inactive(&self) { + self.0.set_inactive() + } + + /// Set the application to be active. + /// + /// # Safety + /// + /// The application must actually be active. Setting to active when the application is not active + /// will result in undefined behavior. + /// + /// # Example + /// + /// ``` + /// use raw_window_handle::Active; + /// + /// // Set the application to be active. + /// let active = Active::new(); + /// unsafe { active.set_active() }; + /// + /// // Set the application to be inactive. + /// active.set_inactive(); + /// ``` + pub unsafe fn set_active(&self) { + self.0.set_active() + } +} + +impl ActiveHandle<'_> { + /// Create a new freestanding active handle. + /// + /// This function acts as an "escape hatch" to allow the user to create a live window handle + /// without having to go through the [`Active`] type. This is useful if the user *knows* that the + /// application is active, and wants to create a live window handle without having to go through + /// the [`Active`] type. + /// + /// # Safety + /// + /// The application must actually be active. + /// + /// # Example + /// + /// ``` + /// use raw_window_handle::ActiveHandle; + /// + /// // Create a freestanding active handle. + /// // SAFETY: The application must actually be active. + /// let handle = unsafe { ActiveHandle::new_unchecked() }; + /// ``` + pub unsafe fn new_unchecked() -> Self { + Self(imp::ActiveHandle::new_unchecked()) + } +} + +/// A display that acts as a wrapper around a display handle. +/// +/// Objects that implement this trait should be able to return a [`DisplayHandle`] for the display +/// that they are associated with. This handle should last for the lifetime of the object, and should +/// return an error if the application is inactive. +/// +/// Implementors of this trait will be windowing systems, like [`winit`] and [`sdl2`]. These windowing +/// systems should implement this trait on types that already implement [`HasRawDisplayHandle`]. It +/// should be implemented by tying the lifetime of the [`DisplayHandle`] to the lifetime of the +/// display object. +/// +/// Users of this trait will include graphics libraries, like [`wgpu`] and [`glutin`]. These APIs +/// should be generic over a type that implements `HasDisplayHandle`, and should use the +/// [`DisplayHandle`] type to access the display handle. +/// +/// # Safety +/// +/// The safety requirements of [`HasRawDisplayHandle`] apply here as well. To reiterate, the +/// [`DisplayHandle`] must contain a valid window handle for its lifetime. +/// +/// It is not possible to invalidate a [`DisplayHandle`] on any platform without additional unsafe code. +/// +/// Note that these requirements are not enforced on `HasDisplayHandle`, rather, they are enforced on the +/// constructors of [`DisplayHandle`]. This is because the `HasDisplayHandle` trait is safe to implement. +/// +/// [`HasRawDisplayHandle`]: crate::HasRawDisplayHandle +/// [`winit`]: https://crates.io/crates/winit +/// [`sdl2`]: https://crates.io/crates/sdl2 +/// [`wgpu`]: https://crates.io/crates/wgpu +/// [`glutin`]: https://crates.io/crates/glutin +pub trait HasDisplayHandle { + /// Get a handle to the display controller of the windowing system. + fn display_handle(&self) -> Result, HandleError>; +} + +impl HasDisplayHandle for &H { + fn display_handle(&self) -> Result, HandleError> { + (**self).display_handle() + } +} + +#[cfg(feature = "alloc")] +impl HasDisplayHandle for alloc::boxed::Box { + fn display_handle(&self) -> Result, HandleError> { + (**self).display_handle() + } +} + +#[cfg(feature = "alloc")] +impl HasDisplayHandle for alloc::rc::Rc { + fn display_handle(&self) -> Result, HandleError> { + (**self).display_handle() + } +} + +#[cfg(feature = "alloc")] +impl HasDisplayHandle for alloc::sync::Arc { + fn display_handle(&self) -> Result, HandleError> { + (**self).display_handle() + } +} + +/// The handle to the display controller of the windowing system. +/// +/// This is the primary return type of the [`HasDisplayHandle`] trait. It is guaranteed to contain +/// a valid platform-specific display handle for its lifetime. +/// +/// Get the underlying raw display handle with the [`HasRawDisplayHandle`] trait. +#[repr(transparent)] +#[derive(PartialEq, Eq, Hash)] +pub struct DisplayHandle<'a> { + raw: RawDisplayHandle, + _marker: PhantomData<&'a *const ()>, +} + +impl fmt::Debug for DisplayHandle<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("DisplayHandle").field(&self.raw).finish() + } +} + +impl<'a> Clone for DisplayHandle<'a> { + fn clone(&self) -> Self { + Self { + raw: self.raw, + _marker: PhantomData, + } + } +} + +impl<'a> DisplayHandle<'a> { + /// Create a `DisplayHandle` from a [`RawDisplayHandle`]. + /// + /// # Safety + /// + /// The `RawDisplayHandle` must be valid for the lifetime. + pub unsafe fn borrow_raw(raw: RawDisplayHandle) -> Self { + Self { + raw, + _marker: PhantomData, + } + } +} + +unsafe impl HasRawDisplayHandle for DisplayHandle<'_> { + fn raw_display_handle(&self) -> RawDisplayHandle { + self.raw + } +} + +impl<'a> HasDisplayHandle for DisplayHandle<'a> { + fn display_handle(&self) -> Result, HandleError> { + Ok(self.clone()) + } +} + +/// A handle to a window. +/// +/// Objects that implement this trait should be able to return a [`WindowHandle`] for the window +/// that they are associated with. This handle should last for the lifetime of the object, and should +/// return an error if the application is inactive. +/// +/// Implementors of this trait will be windowing systems, like [`winit`] and [`sdl2`]. These windowing +/// systems should implement this trait on types that already implement [`HasRawWindowHandle`]. First, +/// it should be made sure that the display type contains a unique [`Active`] ref-counted handle. +/// To create a [`WindowHandle`], the [`Active`] should be used to create an [`ActiveHandle`] that is +/// then used to create a [`WindowHandle`]. Finally, the raw window handle should be retrieved from +/// the type and used to create a [`WindowHandle`]. +/// +/// Users of this trait will include graphics libraries, like [`wgpu`] and [`glutin`]. These APIs +/// should be generic over a type that implements `HasWindowHandle`, and should use the +/// [`WindowHandle`] type to access the window handle. The window handle should be acquired and held +/// while the window is being used, in order to ensure that the window is not deleted while it is in +/// use. +/// +/// # Safety +/// +/// All pointers within the resulting [`WindowHandle`] must be valid and not dangling for the lifetime of +/// the handle. +/// +/// Note that this guarantee only applies to *pointers*, and not any window ID types in the handle. +/// This includes Window IDs (XIDs) from X11 and the window ID for web platforms. There is no way for +/// Rust to enforce any kind of invariant on these types, since: +/// +/// - For all three listed platforms, it is possible for safe code in the same process to delete +/// the window. +/// - For X11, it is possible for code in a different process to delete the window. In fact, it is +/// possible for code on a different *machine* to delete the window. +/// +/// It is *also* possible for the window to be replaced with another, valid-but-different window. User +/// code should be aware of this possibility, and should be ready to soundly handle the possible error +/// conditions that can arise from this. +/// +/// In addition, the window handle must not be invalidated for the duration of the [`ActiveHandle`] token. +/// +/// Note that these requirements are not enforced on `HasWindowHandle`, rather, they are enforced on the +/// constructors of [`WindowHandle`]. This is because the `HasWindowHandle` trait is safe to implement. +/// +/// [`winit`]: https://crates.io/crates/winit +/// [`sdl2`]: https://crates.io/crates/sdl2 +/// [`wgpu`]: https://crates.io/crates/wgpu +/// [`glutin`]: https://crates.io/crates/glutin +pub trait HasWindowHandle { + /// Get a handle to the window. + fn window_handle(&self) -> Result, HandleError>; +} + +impl HasWindowHandle for &H { + fn window_handle(&self) -> Result, HandleError> { + (**self).window_handle() + } +} + +#[cfg(feature = "alloc")] +impl HasWindowHandle for alloc::boxed::Box { + fn window_handle(&self) -> Result, HandleError> { + (**self).window_handle() + } +} + +#[cfg(feature = "alloc")] +impl HasWindowHandle for alloc::rc::Rc { + fn window_handle(&self) -> Result, HandleError> { + (**self).window_handle() + } +} + +#[cfg(feature = "alloc")] +impl HasWindowHandle for alloc::sync::Arc { + fn window_handle(&self) -> Result, HandleError> { + (**self).window_handle() + } +} + +/// The handle to a window. +/// +/// This is the primary return type of the [`HasWindowHandle`] trait. All *pointers* within this type +/// are guaranteed to be valid and not dangling for the lifetime of the handle. This excludes window IDs +/// like XIDs and the window ID for web platforms. See the documentation on the [`HasWindowHandle`] +/// trait for more information about these safety requirements. +/// +/// This handle is guaranteed to be safe and valid. Get the underlying raw window handle with the +/// [`HasRawWindowHandle`] trait. +#[derive(Clone)] +pub struct WindowHandle<'a> { + raw: RawWindowHandle, + _active: ActiveHandle<'a>, + _marker: PhantomData<&'a *const ()>, +} + +impl fmt::Debug for WindowHandle<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("WindowHandle").field(&self.raw).finish() + } +} + +impl PartialEq for WindowHandle<'_> { + fn eq(&self, other: &Self) -> bool { + self.raw == other.raw + } +} + +impl Eq for WindowHandle<'_> {} + +impl Hash for WindowHandle<'_> { + fn hash(&self, state: &mut H) { + self.raw.hash(state); + } +} + +impl<'a> WindowHandle<'a> { + /// Borrow a `WindowHandle` from a [`RawWindowHandle`]. + /// + /// # Safety + /// + /// The [`RawWindowHandle`] must be valid for the lifetime and the application must not be + /// suspended. The [`Active`] object that the [`ActiveHandle`] was created from must be + /// associated directly with the display that the window handle is associated with. + pub unsafe fn borrow_raw(raw: RawWindowHandle, active: ActiveHandle<'a>) -> Self { + Self { + raw, + _active: active, + _marker: PhantomData, + } + } +} + +unsafe impl HasRawWindowHandle for WindowHandle<'_> { + fn raw_window_handle(&self) -> RawWindowHandle { + self.raw + } +} + +impl HasWindowHandle for WindowHandle<'_> { + fn window_handle(&self) -> Result { + Ok(self.clone()) + } +} + +/// The error type returned when a handle cannot be obtained. +#[derive(Debug)] +#[non_exhaustive] +pub enum HandleError { + /// The handle is not currently active. + /// + /// See documentation on [`Active`] for more information. + Inactive, +} + +impl fmt::Display for HandleError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Inactive => write!(f, "the handle is not currently active"), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for HandleError {} + +/// ```compile_fail +/// use raw_window_handle::{Active, DisplayHandle, WindowHandle}; +/// fn _assert() {} +/// _assert::>(); +/// _assert::>(); +/// _assert::>(); +/// ``` +fn _not_send_or_sync() {} + +#[cfg(not(any(target_os = "android", raw_window_handle_force_refcount)))] +#[cfg_attr(docsrs, doc(cfg(not(target_os = "android"))))] +mod imp { + //! We don't need to refcount the handles, so we can just use no-ops. + + use core::cell::UnsafeCell; + use core::marker::PhantomData; + + pub(super) struct Active; + + #[derive(Clone)] + pub(super) struct ActiveHandle<'a> { + _marker: PhantomData<&'a UnsafeCell<()>>, + } + + impl Active { + pub(super) const fn new() -> Self { + Self + } + + pub(super) fn handle(&self) -> Option> { + // SAFETY: The handle is always active. + Some(unsafe { ActiveHandle::new_unchecked() }) + } + + pub(super) unsafe fn set_active(&self) {} + + pub(super) fn set_inactive(&self) {} + } + + impl ActiveHandle<'_> { + pub(super) unsafe fn new_unchecked() -> Self { + Self { + _marker: PhantomData, + } + } + } + + impl Drop for ActiveHandle<'_> { + fn drop(&mut self) { + // Done for consistency with the refcounted version. + } + } + + impl super::ActiveHandle<'_> { + /// Create a new `ActiveHandle`. + /// + /// This is safe because the handle is always active. + /// + /// # Example + /// + /// ``` + /// use raw_window_handle::ActiveHandle; + /// let handle = ActiveHandle::new(); + /// ``` + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + // SAFETY: The handle is always active. + unsafe { super::ActiveHandle::new_unchecked() } + } + } +} + +#[cfg(any(target_os = "android", raw_window_handle_force_refcount))] +#[cfg_attr(docsrs, doc(cfg(any(target_os = "android"))))] +mod imp { + //! We need to refcount the handles, so we use an `RwLock` to do so. + + use std::sync::{RwLock, RwLockReadGuard}; + + pub(super) struct Active { + active: RwLock, + } + + pub(super) struct ActiveHandle<'a> { + inner: Option>, + } + + struct Inner<'a> { + _read_guard: RwLockReadGuard<'a, bool>, + active: &'a Active, + } + + impl Clone for ActiveHandle<'_> { + fn clone(&self) -> Self { + Self { + inner: self.inner.as_ref().map(|inner| Inner { + _read_guard: inner.active.active.read().unwrap(), + active: inner.active, + }), + } + } + } + + impl Active { + pub(super) const fn new() -> Self { + Self { + active: RwLock::new(false), + } + } + + pub(super) fn handle(&self) -> Option> { + let active = self.active.read().ok()?; + if !*active { + return None; + } + + Some(ActiveHandle { + inner: Some(Inner { + _read_guard: active, + active: self, + }), + }) + } + + pub(super) unsafe fn set_active(&self) { + *self.active.write().unwrap() = true; + } + + pub(super) fn set_inactive(&self) { + *self.active.write().unwrap() = false; + } + } + + impl ActiveHandle<'_> { + pub(super) unsafe fn new_unchecked() -> Self { + Self { inner: None } + } + } +} diff --git a/vendor/raw-window-handle/src/haiku.rs b/vendor/raw-window-handle/src/haiku.rs new file mode 100644 index 0000000000000..d44e8c201741e --- /dev/null +++ b/vendor/raw-window-handle/src/haiku.rs @@ -0,0 +1,46 @@ +use core::ffi::c_void; +use core::ptr; + +/// Raw display handle for Haiku. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::HaikuDisplayHandle; +/// let mut display_handle = HaikuDisplayHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct HaikuDisplayHandle; + +impl HaikuDisplayHandle { + pub fn empty() -> Self { + Self {} + } +} + +/// Raw window handle for Haiku. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::HaikuWindowHandle; +/// let mut window_handle = HaikuWindowHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct HaikuWindowHandle { + /// A pointer to a BWindow object + pub b_window: *mut c_void, + /// A pointer to a BDirectWindow object that might be null + pub b_direct_window: *mut c_void, +} + +impl HaikuWindowHandle { + pub fn empty() -> Self { + Self { + b_window: ptr::null_mut(), + b_direct_window: ptr::null_mut(), + } + } +} diff --git a/vendor/raw-window-handle/src/lib.rs b/vendor/raw-window-handle/src/lib.rs new file mode 100644 index 0000000000000..2088271b1e26b --- /dev/null +++ b/vendor/raw-window-handle/src/lib.rs @@ -0,0 +1,381 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] + +//! Interoperability library for Rust Windowing applications. +//! +//! This library provides standard types for accessing a window's platform-specific raw window +//! handle and platforms display handle. This does not provide any utilities for creating and +//! managing windows; instead, it provides a common interface that window creation libraries (e.g. +//! Winit, SDL) can use to easily talk with graphics libraries (e.g. gfx-hal). +//! +//! ## Safety guarantees +//! +//! Please see the docs of [`HasRawWindowHandle`] and [`HasRawDisplayHandle`]. +//! +//! ## Platform handle initialization +//! +//! Each platform handle struct is purposefully non-exhaustive, so that additional fields may be +//! added without breaking backwards compatibility. Each struct provides an `empty` method that may +//! be used along with the struct update syntax to construct it. See each specific struct for +//! examples. +//! +//! ## Display Handles +//! +//! Some windowing systems use a separate display handle for some operations. The display usually +//! represents a connection to some display server, but it is not necessarily tied to a particular +//! window. See [`RawDisplayHandle`] for more details. + +#[cfg(feature = "alloc")] +extern crate alloc; + +#[cfg(feature = "std")] +extern crate std; + +mod android; +mod appkit; +#[cfg(any(feature = "std", not(target_os = "android")))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", not(target_os = "android")))))] +mod borrowed; +mod haiku; +mod redox; +mod uikit; +mod unix; +mod web; +mod windows; + +pub use android::{AndroidDisplayHandle, AndroidNdkWindowHandle}; +pub use appkit::{AppKitDisplayHandle, AppKitWindowHandle}; +#[cfg(any(feature = "std", not(target_os = "android")))] +pub use borrowed::{ + Active, ActiveHandle, DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, + WindowHandle, +}; +pub use haiku::{HaikuDisplayHandle, HaikuWindowHandle}; +pub use redox::{OrbitalDisplayHandle, OrbitalWindowHandle}; +pub use uikit::{UiKitDisplayHandle, UiKitWindowHandle}; +pub use unix::{ + DrmDisplayHandle, DrmWindowHandle, GbmDisplayHandle, GbmWindowHandle, WaylandDisplayHandle, + WaylandWindowHandle, XcbDisplayHandle, XcbWindowHandle, XlibDisplayHandle, XlibWindowHandle, +}; +pub use web::{WebDisplayHandle, WebWindowHandle}; +pub use windows::{Win32WindowHandle, WinRtWindowHandle, WindowsDisplayHandle}; + +/// Window that wraps around a raw window handle. +/// +/// # Safety +/// +/// Users can safely assume that non-`null`/`0` fields are valid handles, and it is up to the +/// implementer of this trait to ensure that condition is upheld. +/// +/// Despite that qualification, implementers should still make a best-effort attempt to fill in all +/// available fields. If an implementation doesn't, and a downstream user needs the field, it should +/// try to derive the field from other fields the implementer *does* provide via whatever methods the +/// platform provides. +/// +/// The exact handles returned by `raw_window_handle` must remain consistent between multiple calls +/// to `raw_window_handle` as long as not indicated otherwise by platform specific events. +pub unsafe trait HasRawWindowHandle { + fn raw_window_handle(&self) -> RawWindowHandle; +} + +unsafe impl<'a, T: HasRawWindowHandle + ?Sized> HasRawWindowHandle for &'a T { + fn raw_window_handle(&self) -> RawWindowHandle { + (*self).raw_window_handle() + } +} +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +unsafe impl HasRawWindowHandle for alloc::rc::Rc { + fn raw_window_handle(&self) -> RawWindowHandle { + (**self).raw_window_handle() + } +} +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +unsafe impl HasRawWindowHandle for alloc::sync::Arc { + fn raw_window_handle(&self) -> RawWindowHandle { + (**self).raw_window_handle() + } +} + +/// A window handle for a particular windowing system. +/// +/// Each variant contains a struct with fields specific to that windowing system +/// (e.g. [`Win32WindowHandle`] will include a [HWND], [`WaylandWindowHandle`] uses [wl_surface], +/// etc.) +/// +/// [HWND]: https://learn.microsoft.com/en-us/windows/win32/winmsg/about-windows#window-handle +/// [wl_surface]: https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_surface +/// +/// # Variant Availability +/// +/// Note that all variants are present on all targets (none are disabled behind +/// `#[cfg]`s), but see the "Availability Hints" section on each variant for +/// some hints on where this variant might be expected. +/// +/// Note that these "Availability Hints" are not normative. That is to say, a +/// [`HasRawWindowHandle`] implementor is completely allowed to return something +/// unexpected. (For example, it's legal for someone to return a +/// [`RawWindowHandle::Xlib`] on macOS, it would just be weird, and probably +/// requires something like XQuartz be used). +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum RawWindowHandle { + /// A raw window handle for UIKit (Apple's non-macOS windowing library). + /// + /// ## Availability Hints + /// This variant is likely to be used on iOS, tvOS, (in theory) watchOS, and + /// Mac Catalyst (`$arch-apple-ios-macabi` targets, which can notably use + /// UIKit *or* AppKit), as these are the targets that (currently) support + /// UIKit. + UiKit(UiKitWindowHandle), + /// A raw window handle for AppKit. + /// + /// ## Availability Hints + /// This variant is likely to be used on macOS, although Mac Catalyst + /// (`$arch-apple-ios-macabi` targets, which can notably use UIKit *or* + /// AppKit) can also use it despite being `target_os = "ios"`. + AppKit(AppKitWindowHandle), + /// A raw window handle for the Redox operating system. + /// + /// ## Availability Hints + /// This variant is used by the Orbital Windowing System in the Redox + /// operating system. + Orbital(OrbitalWindowHandle), + /// A raw window handle for Xlib. + /// + /// ## Availability Hints + /// This variant is likely to show up anywhere someone manages to get X11 + /// working that Xlib can be built for, which is to say, most (but not all) + /// Unix systems. + Xlib(XlibWindowHandle), + /// A raw window handle for Xcb. + /// + /// ## Availability Hints + /// This variant is likely to show up anywhere someone manages to get X11 + /// working that XCB can be built for, which is to say, most (but not all) + /// Unix systems. + Xcb(XcbWindowHandle), + /// A raw window handle for Wayland. + /// + /// ## Availability Hints + /// This variant should be expected anywhere Wayland works, which is + /// currently some subset of unix systems. + Wayland(WaylandWindowHandle), + /// A raw window handle for the Linux Kernel Mode Set/Direct Rendering Manager + /// + /// ## Availability Hints + /// This variant is used on Linux when neither X nor Wayland are available + Drm(DrmWindowHandle), + /// A raw window handle for the Linux Generic Buffer Manager. + /// + /// ## Availability Hints + /// This variant is present regardless of windowing backend and likely to be used with + /// EGL_MESA_platfrom_gbm or EGL_KHR_platfrom_gbm. + Gbm(GbmWindowHandle), + /// A raw window handle for Win32. + /// + /// ## Availability Hints + /// This variant is used on Windows systems. + Win32(Win32WindowHandle), + /// A raw window handle for WinRT. + /// + /// ## Availability Hints + /// This variant is used on Windows systems. + WinRt(WinRtWindowHandle), + /// A raw window handle for the Web. + /// + /// ## Availability Hints + /// This variant is used on Wasm or asm.js targets when targeting the Web/HTML5. + Web(WebWindowHandle), + /// A raw window handle for Android NDK. + /// + /// ## Availability Hints + /// This variant is used on Android targets. + AndroidNdk(AndroidNdkWindowHandle), + /// A raw window handle for Haiku. + /// + /// ## Availability Hints + /// This variant is used on HaikuOS. + Haiku(HaikuWindowHandle), +} + +/// Display that wraps around a raw display handle. +/// +/// # Safety +/// +/// Users can safely assume that non-`null`/`0` fields are valid handles, and it is up to the +/// implementer of this trait to ensure that condition is upheld. +/// +/// Despite that qualification, implementers should still make a best-effort attempt to fill in all +/// available fields. If an implementation doesn't, and a downstream user needs the field, it should +/// try to derive the field from other fields the implementer *does* provide via whatever methods the +/// platform provides. +/// +/// The exact handles returned by `raw_display_handle` must remain consistent between multiple calls +/// to `raw_display_handle` as long as not indicated otherwise by platform specific events. +pub unsafe trait HasRawDisplayHandle { + fn raw_display_handle(&self) -> RawDisplayHandle; +} + +unsafe impl<'a, T: HasRawDisplayHandle + ?Sized> HasRawDisplayHandle for &'a T { + fn raw_display_handle(&self) -> RawDisplayHandle { + (*self).raw_display_handle() + } +} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +unsafe impl HasRawDisplayHandle for alloc::rc::Rc { + fn raw_display_handle(&self) -> RawDisplayHandle { + (**self).raw_display_handle() + } +} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +unsafe impl HasRawDisplayHandle for alloc::sync::Arc { + fn raw_display_handle(&self) -> RawDisplayHandle { + (**self).raw_display_handle() + } +} + +/// A display server handle for a particular windowing system. +/// +/// The display usually represents a connection to some display server, but it is not necessarily +/// tied to a particular window. Some APIs can use the display handle without ever creating a window +/// handle (e.g. offscreen rendering, headless event handling). +/// +/// Each variant contains a struct with fields specific to that windowing system +/// (e.g. [`XlibDisplayHandle`] contains a [Display] connection to an X Server, +/// [`WaylandDisplayHandle`] uses [wl_display] to connect to a compositor). Not all windowing +/// systems have a separate display handle (or they haven't been implemented yet) and their variants +/// contain empty structs. +/// +/// [Display]: https://www.x.org/releases/current/doc/libX11/libX11/libX11.html#Display_Functions +/// [wl_display]: https://wayland.freedesktop.org/docs/html/apb.html#Client-classwl__display +/// +/// # Variant Availability +/// +/// Note that all variants are present on all targets (none are disabled behind +/// `#[cfg]`s), but see the "Availability Hints" section on each variant for +/// some hints on where this variant might be expected. +/// +/// Note that these "Availability Hints" are not normative. That is to say, a +/// [`HasRawDisplayHandle`] implementor is completely allowed to return something +/// unexpected. (For example, it's legal for someone to return a +/// [`RawDisplayHandle::Xlib`] on macOS, it would just be weird, and probably +/// requires something like XQuartz be used). +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum RawDisplayHandle { + /// A raw display handle for UIKit (Apple's non-macOS windowing library). + /// + /// ## Availability Hints + /// This variant is likely to be used on iOS, tvOS, (in theory) watchOS, and + /// Mac Catalyst (`$arch-apple-ios-macabi` targets, which can notably use + /// UIKit *or* AppKit), as these are the targets that (currently) support + /// UIKit. + UiKit(UiKitDisplayHandle), + /// A raw display handle for AppKit. + /// + /// ## Availability Hints + /// This variant is likely to be used on macOS, although Mac Catalyst + /// (`$arch-apple-ios-macabi` targets, which can notably use UIKit *or* + /// AppKit) can also use it despite being `target_os = "ios"`. + AppKit(AppKitDisplayHandle), + /// A raw display handle for the Redox operating system. + /// + /// ## Availability Hints + /// This variant is used by the Orbital Windowing System in the Redox + /// operating system. + Orbital(OrbitalDisplayHandle), + /// A raw display handle for Xlib. + /// + /// ## Availability Hints + /// This variant is likely to show up anywhere someone manages to get X11 + /// working that Xlib can be built for, which is to say, most (but not all) + /// Unix systems. + Xlib(XlibDisplayHandle), + /// A raw display handle for Xcb. + /// + /// ## Availability Hints + /// This variant is likely to show up anywhere someone manages to get X11 + /// working that XCB can be built for, which is to say, most (but not all) + /// Unix systems. + Xcb(XcbDisplayHandle), + /// A raw display handle for Wayland. + /// + /// ## Availability Hints + /// This variant should be expected anywhere Wayland works, which is + /// currently some subset of unix systems. + Wayland(WaylandDisplayHandle), + /// A raw display handle for the Linux Kernel Mode Set/Direct Rendering Manager + /// + /// ## Availability Hints + /// This variant is used on Linux when neither X nor Wayland are available + Drm(DrmDisplayHandle), + /// A raw display handle for the Linux Generic Buffer Manager. + /// + /// ## Availability Hints + /// This variant is present regardless of windowing backend and likely to be used with + /// EGL_MESA_platfrom_gbm or EGL_KHR_platfrom_gbm. + Gbm(GbmDisplayHandle), + /// A raw display handle for Win32. + /// + /// ## Availability Hints + /// This variant is used on Windows systems. + Windows(WindowsDisplayHandle), + /// A raw display handle for the Web. + /// + /// ## Availability Hints + /// This variant is used on Wasm or asm.js targets when targeting the Web/HTML5. + Web(WebDisplayHandle), + /// A raw display handle for Android NDK. + /// + /// ## Availability Hints + /// This variant is used on Android targets. + Android(AndroidDisplayHandle), + /// A raw display handle for Haiku. + /// + /// ## Availability Hints + /// This variant is used on HaikuOS. + Haiku(HaikuDisplayHandle), +} + +macro_rules! from_impl { + ($($to:ident, $enum:ident, $from:ty)*) => ($( + impl From<$from> for $to { + fn from(value: $from) -> Self { + $to::$enum(value) + } + } + )*) +} + +from_impl!(RawDisplayHandle, UiKit, UiKitDisplayHandle); +from_impl!(RawDisplayHandle, AppKit, AppKitDisplayHandle); +from_impl!(RawDisplayHandle, Orbital, OrbitalDisplayHandle); +from_impl!(RawDisplayHandle, Xlib, XlibDisplayHandle); +from_impl!(RawDisplayHandle, Xcb, XcbDisplayHandle); +from_impl!(RawDisplayHandle, Wayland, WaylandDisplayHandle); +from_impl!(RawDisplayHandle, Drm, DrmDisplayHandle); +from_impl!(RawDisplayHandle, Gbm, GbmDisplayHandle); +from_impl!(RawDisplayHandle, Windows, WindowsDisplayHandle); +from_impl!(RawDisplayHandle, Web, WebDisplayHandle); +from_impl!(RawDisplayHandle, Android, AndroidDisplayHandle); +from_impl!(RawDisplayHandle, Haiku, HaikuDisplayHandle); + +from_impl!(RawWindowHandle, UiKit, UiKitWindowHandle); +from_impl!(RawWindowHandle, AppKit, AppKitWindowHandle); +from_impl!(RawWindowHandle, Orbital, OrbitalWindowHandle); +from_impl!(RawWindowHandle, Xlib, XlibWindowHandle); +from_impl!(RawWindowHandle, Xcb, XcbWindowHandle); +from_impl!(RawWindowHandle, Wayland, WaylandWindowHandle); +from_impl!(RawWindowHandle, Drm, DrmWindowHandle); +from_impl!(RawWindowHandle, Gbm, GbmWindowHandle); +from_impl!(RawWindowHandle, Win32, Win32WindowHandle); +from_impl!(RawWindowHandle, WinRt, WinRtWindowHandle); +from_impl!(RawWindowHandle, Web, WebWindowHandle); +from_impl!(RawWindowHandle, AndroidNdk, AndroidNdkWindowHandle); +from_impl!(RawWindowHandle, Haiku, HaikuWindowHandle); diff --git a/vendor/raw-window-handle/src/redox.rs b/vendor/raw-window-handle/src/redox.rs new file mode 100644 index 0000000000000..5faa98501d15c --- /dev/null +++ b/vendor/raw-window-handle/src/redox.rs @@ -0,0 +1,43 @@ +use core::ffi::c_void; +use core::ptr; + +/// Raw display handle for the Redox operating system. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::OrbitalDisplayHandle; +/// let mut display_handle = OrbitalDisplayHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct OrbitalDisplayHandle; + +impl OrbitalDisplayHandle { + pub fn empty() -> Self { + Self {} + } +} + +/// Raw window handle for the Redox operating system. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::OrbitalWindowHandle; +/// let mut window_handle = OrbitalWindowHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct OrbitalWindowHandle { + /// A pointer to an orbclient window. + pub window: *mut c_void, +} + +impl OrbitalWindowHandle { + pub fn empty() -> Self { + Self { + window: ptr::null_mut(), + } + } +} diff --git a/vendor/raw-window-handle/src/uikit.rs b/vendor/raw-window-handle/src/uikit.rs new file mode 100644 index 0000000000000..bee3a9a71bd9b --- /dev/null +++ b/vendor/raw-window-handle/src/uikit.rs @@ -0,0 +1,49 @@ +use core::ffi::c_void; +use core::ptr; + +/// Raw display handle for UIKit. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::UiKitDisplayHandle; +/// let mut display_handle = UiKitDisplayHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct UiKitDisplayHandle; + +impl UiKitDisplayHandle { + pub fn empty() -> Self { + Self {} + } +} + +/// Raw window handle for UIKit. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::UiKitWindowHandle; +/// let mut window_handle = UiKitWindowHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct UiKitWindowHandle { + /// A pointer to an `UIWindow` object. + pub ui_window: *mut c_void, + /// A pointer to an `UIView` object. + pub ui_view: *mut c_void, + /// A pointer to an `UIViewController` object. + pub ui_view_controller: *mut c_void, +} + +impl UiKitWindowHandle { + pub fn empty() -> Self { + Self { + ui_window: ptr::null_mut(), + ui_view: ptr::null_mut(), + ui_view_controller: ptr::null_mut(), + } + } +} diff --git a/vendor/raw-window-handle/src/unix.rs b/vendor/raw-window-handle/src/unix.rs new file mode 100644 index 0000000000000..e220b2d72a933 --- /dev/null +++ b/vendor/raw-window-handle/src/unix.rs @@ -0,0 +1,250 @@ +use core::ffi::{c_int, c_ulong, c_void}; +use core::ptr; + +/// Raw display handle for Xlib. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::XlibDisplayHandle; +/// let display_handle = XlibDisplayHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct XlibDisplayHandle { + /// A pointer to an Xlib `Display`. + pub display: *mut c_void, + + /// An X11 screen to use with this display handle. + /// + /// Note, that X11 could have multiple screens, however + /// graphics APIs could work only with one screen at the time, + /// given that multiple screens usually reside on different GPUs. + pub screen: c_int, +} + +/// Raw window handle for Xlib. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::XlibWindowHandle; +/// let window_handle = XlibWindowHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct XlibWindowHandle { + /// An Xlib `Window`. + pub window: c_ulong, + /// An Xlib visual ID, or 0 if unknown. + pub visual_id: c_ulong, +} + +/// Raw display handle for Xcb. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::XcbDisplayHandle; +/// let display_handle = XcbDisplayHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct XcbDisplayHandle { + /// A pointer to an X server `xcb_connection_t`. + pub connection: *mut c_void, + + /// An X11 screen to use with this display handle. + /// + /// Note, that X11 could have multiple screens, however + /// graphics APIs could work only with one screen at the time, + /// given that multiple screens usually reside on different GPUs. + pub screen: c_int, +} + +/// Raw window handle for Xcb. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::XcbWindowHandle; +/// let window_handle = XcbWindowHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct XcbWindowHandle { + /// An X11 `xcb_window_t`. + pub window: u32, // Based on xproto.h + /// An X11 `xcb_visualid_t`, or 0 if unknown. + pub visual_id: u32, +} + +/// Raw display handle for Wayland. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::WaylandDisplayHandle; +/// let display_handle = WaylandDisplayHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct WaylandDisplayHandle { + /// A pointer to a `wl_display`. + pub display: *mut c_void, +} + +/// Raw window handle for Wayland. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::WaylandWindowHandle; +/// let window_handle = WaylandWindowHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct WaylandWindowHandle { + /// A pointer to a `wl_surface`. + pub surface: *mut c_void, +} + +/// Raw display handle for the Linux Kernel Mode Set/Direct Rendering Manager. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::DrmDisplayHandle; +/// let display_handle = DrmDisplayHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DrmDisplayHandle { + /// The drm file descriptor. + pub fd: i32, +} + +/// Raw window handle for the Linux Kernel Mode Set/Direct Rendering Manager. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::DrmWindowHandle; +/// let handle = DrmWindowHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DrmWindowHandle { + /// The primary drm plane handle. + pub plane: u32, +} + +/// Raw display handle for the Linux Generic Buffer Manager. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::GbmDisplayHandle; +/// let display_handle = GbmDisplayHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct GbmDisplayHandle { + /// The gbm device. + pub gbm_device: *mut c_void, +} + +/// Raw window handle for the Linux Generic Buffer Manager. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::GbmWindowHandle; +/// let handle = GbmWindowHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct GbmWindowHandle { + /// The gbm surface. + pub gbm_surface: *mut c_void, +} + +impl XlibDisplayHandle { + pub fn empty() -> Self { + Self { + display: ptr::null_mut(), + screen: 0, + } + } +} + +impl XlibWindowHandle { + pub fn empty() -> Self { + Self { + window: 0, + visual_id: 0, + } + } +} + +impl XcbDisplayHandle { + pub fn empty() -> Self { + Self { + connection: ptr::null_mut(), + screen: 0, + } + } +} + +impl XcbWindowHandle { + pub fn empty() -> Self { + Self { + window: 0, + visual_id: 0, + } + } +} + +impl WaylandDisplayHandle { + pub fn empty() -> Self { + Self { + display: ptr::null_mut(), + } + } +} + +impl WaylandWindowHandle { + pub fn empty() -> Self { + Self { + surface: ptr::null_mut(), + } + } +} + +impl DrmDisplayHandle { + pub fn empty() -> Self { + Self { fd: 0 } + } +} + +impl DrmWindowHandle { + pub fn empty() -> Self { + Self { plane: 0 } + } +} + +impl GbmDisplayHandle { + pub fn empty() -> Self { + Self { + gbm_device: ptr::null_mut(), + } + } +} + +impl GbmWindowHandle { + pub fn empty() -> Self { + Self { + gbm_surface: ptr::null_mut(), + } + } +} diff --git a/vendor/raw-window-handle/src/web.rs b/vendor/raw-window-handle/src/web.rs new file mode 100644 index 0000000000000..1e6908ffeafbb --- /dev/null +++ b/vendor/raw-window-handle/src/web.rs @@ -0,0 +1,45 @@ +/// Raw display handle for the Web. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::WebDisplayHandle; +/// let mut display_handle = WebDisplayHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct WebDisplayHandle; + +impl WebDisplayHandle { + pub fn empty() -> Self { + Self {} + } +} + +/// Raw window handle for the Web. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::WebWindowHandle; +/// let mut window_handle = WebWindowHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct WebWindowHandle { + /// An ID value inserted into the [data attributes] of the canvas element as '`raw-handle`'. + /// + /// When accessing from JS, the attribute will automatically be called `rawHandle`. + /// + /// Each canvas created by the windowing system should be assigned their own unique ID. + /// 0 should be reserved for invalid / null IDs. + /// + /// [data attributes]: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-* + pub id: u32, +} + +impl WebWindowHandle { + pub fn empty() -> Self { + Self { id: 0 } + } +} diff --git a/vendor/raw-window-handle/src/windows.rs b/vendor/raw-window-handle/src/windows.rs new file mode 100644 index 0000000000000..32b1a88af71a5 --- /dev/null +++ b/vendor/raw-window-handle/src/windows.rs @@ -0,0 +1,71 @@ +use core::ffi::c_void; +use core::ptr; + +/// Raw display handle for Windows. +/// +/// It could be used regardless of Windows window backend. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::WindowsDisplayHandle; +/// let mut display_handle = WindowsDisplayHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct WindowsDisplayHandle; + +impl WindowsDisplayHandle { + pub fn empty() -> Self { + Self + } +} + +/// Raw window handle for Win32. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::Win32WindowHandle; +/// let mut window_handle = Win32WindowHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Win32WindowHandle { + /// A Win32 `HWND` handle. + pub hwnd: *mut c_void, + /// The `HINSTANCE` associated with this type's `HWND`. + pub hinstance: *mut c_void, +} + +impl Win32WindowHandle { + pub fn empty() -> Self { + Self { + hwnd: ptr::null_mut(), + hinstance: ptr::null_mut(), + } + } +} + +/// Raw window handle for WinRT. +/// +/// ## Construction +/// ``` +/// # use raw_window_handle::WinRtWindowHandle; +/// let mut window_handle = WinRtWindowHandle::empty(); +/// /* set fields */ +/// ``` +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct WinRtWindowHandle { + /// A WinRT `CoreWindow` handle. + pub core_window: *mut c_void, +} + +impl WinRtWindowHandle { + pub fn empty() -> Self { + Self { + core_window: ptr::null_mut(), + } + } +} diff --git a/vendor/redox_syscall-0.2.16/.cargo-checksum.json b/vendor/redox_syscall-0.2.16/.cargo-checksum.json new file mode 100644 index 0000000000000..9c62b65217e90 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"0e92420005ca47c7854d02e9b637262cc13f800d48614aeef69be2f1119fc19b","LICENSE":"efcfee7981ff72431fffb06925cad00a23dce079ed4354f61030ad5abdb78829","README.md":"9161f18ba7f69b4ca51e844aee8ffb8237513a468c5c3b1f3a5f989044f895ac","src/arch/aarch64.rs":"61b5811b47a29257c3b5e15e7d9d15e7143bad99fbe29f0cb17ead9cbc17186f","src/arch/nonredox.rs":"9eac0fa2cf9eae07f0cafa2dd63c4a820791897a3de9ad1a933ab4f53458dbd8","src/arch/riscv64.rs":"20bf9a8db779059773b113643d0cb3737fbb5d57f45ee39b8ae9d3396b6ef636","src/arch/x86.rs":"7802186155c06638235e49e11f4c046b68f1d8145b2c849adec84497eb3cb70f","src/arch/x86_64.rs":"f40bad2680fd5e7f100ee1afaa805f33dd0e12ec8786b956d47204f66771801d","src/call.rs":"0d3e32e33ecdf75963e5d244f9e86e94047d155c5de5fa3c0085faf18ed97b33","src/daemon.rs":"11cd633298fe2eb89906a4d8c12ab34e4ee355f759e1216cee536f24c7c679b2","src/data.rs":"bd4545d4c2fcc59ff26ae52ad7f773a697d5ccf639a2ffc253cece6b31e94d51","src/error.rs":"ef20f3817f997a1aeb7114628407f19cb8bc13c555d4e093918f38a5d098f798","src/flag.rs":"f07d6a7aa6766d30d0a303c7b3bda5bb4c473dd9dd51687cf8e0631b1bf3ec9d","src/io/dma.rs":"fbc46e924d5913f5a3fb723751d7a9dd1b079ccf058500fde4957aaf9fa7dd1c","src/io/io.rs":"e1d454ff47efac70fdaa709251a5a9c1c5637f931994ba3bf6a38c6db9145822","src/io/mmio.rs":"12d0fb4d4f45097bf2c14f73cb1ce21325eae193b537e9f18af73ed5281b5e63","src/io/mod.rs":"79c2fce4fd6d75f3b9169df64b7a605feff31fab2e5ed81984ae085a1d07c0c4","src/io/pio.rs":"9ee6f2229b700d1c45b4c8c6242bd99fe69634e16dcd5843d9e8d1c958047406","src/lib.rs":"0bc9c8ca513dc6f0d9ef587bc53587114c31c1217d6b620399fc0fcbc54bf658","src/number.rs":"fe7b47b06566aa1f8a75f50b685801259df03a1a5c85b91817b4552583cd7862","src/scheme/generate.sh":"dde4e30f4e0223fb1a24ed486a6c36e624c854dbf890862cb6866f4fa3c7a6eb","src/scheme/mod.rs":"cb622405deb0aef4ab04499ea1adfd338c9c5dd9c31a1fe9989786dbf69b49d8","src/scheme/scheme.rs":"30263996f0b4930edd76dace5f5750e48229066bc888bc13365846688d0a870b","src/scheme/scheme_block.rs":"b7a761e4349eb87d106c8af14894e8c4272769b9eb235cd500b075ac1f823683","src/scheme/scheme_block_mut.rs":"4a4fc03bce14757b64006b9bc3fa2779e95382b2d99579870146ee0c3be3f46c","src/scheme/scheme_mut.rs":"e6f0671b77f1bf5263e497c69dec553352249b75d52af62ac19477ba5127f803","src/scheme/seek.rs":"94e044de47b0f00eb0c2aea3fb21001ac2b9aa1e4b20d73fd54163fe92fa63f7","src/tests.rs":"416a428ba6a9c5f0d8f4c3dbe91d9aa940a04472ec9a2d17bc5a66c455b4416f"},"package":"fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"} \ No newline at end of file diff --git a/vendor/redox_syscall-0.2.16/Cargo.toml b/vendor/redox_syscall-0.2.16/Cargo.toml new file mode 100644 index 0000000000000..74e23e8c9d3e3 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "redox_syscall" +version = "0.2.16" +authors = ["Jeremy Soller "] +description = "A Rust library to access raw Redox system calls" +documentation = "https://docs.rs/redox_syscall" +license = "MIT" +repository = "https://gitlab.redox-os.org/redox-os/syscall" + +[lib] +name = "syscall" + +[dependencies.bitflags] +version = "1.1.0" diff --git a/vendor/redox_syscall-0.2.16/LICENSE b/vendor/redox_syscall-0.2.16/LICENSE new file mode 100644 index 0000000000000..1292bb7fbdd1c --- /dev/null +++ b/vendor/redox_syscall-0.2.16/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2017 Redox OS Developers + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/redox_syscall-0.2.16/README.md b/vendor/redox_syscall-0.2.16/README.md new file mode 100644 index 0000000000000..244c90861a834 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/README.md @@ -0,0 +1,6 @@ +# syscall +[Redox OS](https://gitlab.redox-os.org/redox-os/redox)'s syscall API + +[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) +[![crates.io](http://meritbadge.herokuapp.com/redox_syscall)](https://crates.io/crates/redox_syscall) +[![docs.rs](https://docs.rs/redox_syscall/badge.svg)](https://docs.rs/redox_syscall) diff --git a/vendor/redox_syscall-0.2.16/src/arch/aarch64.rs b/vendor/redox_syscall-0.2.16/src/arch/aarch64.rs new file mode 100644 index 0000000000000..e771396e35624 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/arch/aarch64.rs @@ -0,0 +1,132 @@ +use core::{mem, slice}; +use core::ops::{Deref, DerefMut}; + +use super::error::{Error, Result}; + +macro_rules! syscall { + ($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => { + $( + pub unsafe fn $name($a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result { + let ret: usize; + + core::arch::asm!( + "svc 0", + in("x8") $a, + $( + in("x0") $b, + $( + in("x1") $c, + $( + in("x2") $d, + $( + in("x3") $e, + $( + in("x4") $f, + )? + )? + )? + )? + )? + lateout("x0") ret, + options(nostack), + ); + + Error::demux(ret) + } + )+ + }; +} + +syscall! { + syscall0(a,); + syscall1(a, b,); + syscall2(a, b, c,); + syscall3(a, b, c, d,); + syscall4(a, b, c, d, e,); + syscall5(a, b, c, d, e, f,); +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct IntRegisters { + pub elr_el1: usize, + pub tpidr_el0: usize, + pub tpidrro_el0: usize, + pub spsr_el1: usize, + pub esr_el1: usize, + pub sp_el0: usize, // Shouldn't be used if interrupt occurred at EL1 + pub padding: usize, // To keep the struct even number aligned + pub x30: usize, + pub x29: usize, + pub x28: usize, + pub x27: usize, + pub x26: usize, + pub x25: usize, + pub x24: usize, + pub x23: usize, + pub x22: usize, + pub x21: usize, + pub x20: usize, + pub x19: usize, + pub x18: usize, + pub x17: usize, + pub x16: usize, + pub x15: usize, + pub x14: usize, + pub x13: usize, + pub x12: usize, + pub x11: usize, + pub x10: usize, + pub x9: usize, + pub x8: usize, + pub x7: usize, + pub x6: usize, + pub x5: usize, + pub x4: usize, + pub x3: usize, + pub x2: usize, + pub x1: usize, + pub x0: usize +} + +impl Deref for IntRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const IntRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for IntRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut IntRegisters as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(packed)] +pub struct FloatRegisters { + pub fp_simd_regs: [u128; 32], + pub fpsr: u32, + pub fpcr: u32 +} + +impl Deref for FloatRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const FloatRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for FloatRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut FloatRegisters as *mut u8, mem::size_of::()) + } + } +} diff --git a/vendor/redox_syscall-0.2.16/src/arch/nonredox.rs b/vendor/redox_syscall-0.2.16/src/arch/nonredox.rs new file mode 100644 index 0000000000000..f99a7148cf021 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/arch/nonredox.rs @@ -0,0 +1,26 @@ +use super::error::{Error, Result, ENOSYS}; + +pub unsafe fn syscall0(_a: usize) -> Result { + Err(Error::new(ENOSYS)) +} + +pub unsafe fn syscall1(_a: usize, _b: usize) -> Result { + Err(Error::new(ENOSYS)) +} + +pub unsafe fn syscall2(_a: usize, _b: usize, _c: usize) -> Result { + Err(Error::new(ENOSYS)) +} + +pub unsafe fn syscall3(_a: usize, _b: usize, _c: usize, _d: usize) -> Result { + Err(Error::new(ENOSYS)) +} + +pub unsafe fn syscall4(_a: usize, _b: usize, _c: usize, _d: usize, _e: usize) -> Result { + Err(Error::new(ENOSYS)) +} + +pub unsafe fn syscall5(_a: usize, _b: usize, _c: usize, _d: usize, _e: usize, _f: usize) + -> Result { + Err(Error::new(ENOSYS)) +} diff --git a/vendor/redox_syscall-0.2.16/src/arch/riscv64.rs b/vendor/redox_syscall-0.2.16/src/arch/riscv64.rs new file mode 100644 index 0000000000000..2a90260da4e7c --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/arch/riscv64.rs @@ -0,0 +1,93 @@ +use core::{mem, slice}; +use core::ops::{Deref, DerefMut}; + +use super::error::{Error, Result}; + +macro_rules! syscall { + ($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => { + $( + pub unsafe fn $name($a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result { + let ret: usize; + + asm!( + "ecall", + in("a7") $a, + $( + in("a0") $b, + $( + in("a1") $c, + $( + in("a2") $d, + $( + in("a3") $e, + $( + in("a4") $f, + )? + )? + )? + )? + )? + lateout("a0") ret, + options(nostack), + ); + + Error::demux(ret) + } + )+ + }; +} + +syscall! { + syscall0(a,); + syscall1(a, b,); + syscall2(a, b, c,); + syscall3(a, b, c, d,); + syscall4(a, b, c, d, e,); + syscall5(a, b, c, d, e, f,); +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct IntRegisters { + //TODO +} + +impl Deref for IntRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const IntRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for IntRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut IntRegisters as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(packed)] +pub struct FloatRegisters { + //TODO +} + +impl Deref for FloatRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const FloatRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for FloatRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut FloatRegisters as *mut u8, mem::size_of::()) + } + } +} diff --git a/vendor/redox_syscall-0.2.16/src/arch/x86.rs b/vendor/redox_syscall-0.2.16/src/arch/x86.rs new file mode 100644 index 0000000000000..2f9301e0e078b --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/arch/x86.rs @@ -0,0 +1,105 @@ +use core::{mem, slice}; +use core::arch::asm; +use core::ops::{Deref, DerefMut}; + +use super::error::{Error, Result}; + +macro_rules! syscall { + ($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => { + $( + pub unsafe fn $name(mut $a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result { + asm!( + "int 0x80", + inout("eax") $a, + $( + in("ebx") $b, + $( + in("ecx") $c, + $( + in("edx") $d, + $( + in("esi") $e, + $( + in("edi") $f, + )? + )? + )? + )? + )? + options(nostack), + ); + + Error::demux($a) + } + )+ + }; +} + +syscall! { + syscall0(a,); + syscall1(a, b,); + syscall2(a, b, c,); + syscall3(a, b, c, d,); + // Must be done custom because LLVM reserves ESI + //syscall4(a, b, c, d, e,); + //syscall5(a, b, c, d, e, f,); +} + +pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) + -> Result { + asm!( + "xchg esi, {e} + int 0x80 + xchg esi, {e}", + e = in(reg) e, + inout("eax") a, + in("ebx") b, + in("ecx") c, + in("edx") d, + options(nostack), + ); + + Error::demux(a) +} + +pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) + -> Result { + asm!( + "xchg esi, {e} + int 0x80 + xchg esi, {e}", + e = in(reg) e, + inout("eax") a, + in("ebx") b, + in("ecx") c, + in("edx") d, + in("edi") f, + options(nostack), + ); + + Error::demux(a) +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(packed)] +pub struct EnvRegisters { + pub fsbase: u32, + pub gsbase: u32, +} + +impl Deref for EnvRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const EnvRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for EnvRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut EnvRegisters as *mut u8, mem::size_of::()) + } + } +} diff --git a/vendor/redox_syscall-0.2.16/src/arch/x86_64.rs b/vendor/redox_syscall-0.2.16/src/arch/x86_64.rs new file mode 100644 index 0000000000000..f71898e90c507 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/arch/x86_64.rs @@ -0,0 +1,155 @@ +use core::{mem, slice}; +use core::arch::asm; +use core::ops::{Deref, DerefMut}; + +use super::error::{Error, Result}; + +macro_rules! syscall { + ($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => { + $( + pub unsafe fn $name(mut $a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result { + asm!( + "syscall", + inout("rax") $a, + $( + in("rdi") $b, + $( + in("rsi") $c, + $( + in("rdx") $d, + $( + in("r10") $e, + $( + in("r8") $f, + )? + )? + )? + )? + )? + out("rcx") _, + out("r11") _, + options(nostack), + ); + + Error::demux($a) + } + )+ + }; +} + +syscall! { + syscall0(a,); + syscall1(a, b,); + syscall2(a, b, c,); + syscall3(a, b, c, d,); + syscall4(a, b, c, d, e,); + syscall5(a, b, c, d, e, f,); +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct IntRegisters { + // TODO: Some of these don't get set by Redox yet. Should they? + + pub r15: usize, + pub r14: usize, + pub r13: usize, + pub r12: usize, + pub rbp: usize, + pub rbx: usize, + pub r11: usize, + pub r10: usize, + pub r9: usize, + pub r8: usize, + pub rax: usize, + pub rcx: usize, + pub rdx: usize, + pub rsi: usize, + pub rdi: usize, + // pub orig_rax: usize, + pub rip: usize, + pub cs: usize, + pub rflags: usize, + pub rsp: usize, + pub ss: usize, + // pub fs_base: usize, + // pub gs_base: usize, + // pub ds: usize, + // pub es: usize, + pub fs: usize, + // pub gs: usize +} + +impl Deref for IntRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const IntRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for IntRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut IntRegisters as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(packed)] +pub struct FloatRegisters { + pub fcw: u16, + pub fsw: u16, + pub ftw: u8, + pub _reserved: u8, + pub fop: u16, + pub fip: u64, + pub fdp: u64, + pub mxcsr: u32, + pub mxcsr_mask: u32, + pub st_space: [u128; 8], + pub xmm_space: [u128; 16], + // TODO: YMM/ZMM +} + +impl Deref for FloatRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const FloatRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for FloatRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut FloatRegisters as *mut u8, mem::size_of::()) + } + } +} +#[derive(Clone, Copy, Debug, Default)] +#[repr(packed)] +pub struct EnvRegisters { + pub fsbase: u64, + pub gsbase: u64, + // TODO: PKRU? +} +impl Deref for EnvRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const EnvRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for EnvRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut EnvRegisters as *mut u8, mem::size_of::()) + } + } +} diff --git a/vendor/redox_syscall-0.2.16/src/call.rs b/vendor/redox_syscall-0.2.16/src/call.rs new file mode 100644 index 0000000000000..f6eb89c8c0d61 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/call.rs @@ -0,0 +1,420 @@ +use super::arch::*; +use super::data::{Map, SigAction, Stat, StatVfs, TimeSpec}; +use super::error::Result; +use super::flag::*; +use super::number::*; + +use core::{mem, ptr}; + +// Signal restorer +extern "C" fn restorer() -> ! { + sigreturn().unwrap(); + unreachable!(); +} + +/// Change the process's working directory +/// +/// This function will attempt to set the process's working directory to `path`, which can be +/// either a relative, scheme relative, or absolute path. +/// +/// On success, `Ok(0)` will be returned. On error, one of the following errors will be returned. +/// +/// # Errors +/// +/// * `EACCES` - permission is denied for one of the components of `path`, or `path` +/// * `EFAULT` - `path` does not point to the process's addressible memory +/// * `EIO` - an I/O error occurred +/// * `ENOENT` - `path` does not exit +/// * `ENOTDIR` - `path` is not a directory +pub fn chdir>(path: T) -> Result { + unsafe { syscall2(SYS_CHDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) } +} + +#[deprecated( + since = "0.1.55", + note = "use fchmod instead" +)] +pub fn chmod>(path: T, mode: usize) -> Result { + unsafe { syscall3(SYS_CHMOD, path.as_ref().as_ptr() as usize, path.as_ref().len(), mode) } +} + +/// Produce a fork of the current process, or a new process thread +pub unsafe fn clone(flags: CloneFlags) -> Result { + syscall1(SYS_CLONE, flags.bits()) +} + +/// Close a file +pub fn close(fd: usize) -> Result { + unsafe { syscall1(SYS_CLOSE, fd) } +} + +/// Get the current system time +pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result { + unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) } +} + +/// Copy and transform a file descriptor +pub fn dup(fd: usize, buf: &[u8]) -> Result { + unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) } +} + +/// Copy and transform a file descriptor +pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result { + unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) } +} + +/// Exit the current process +pub fn exit(status: usize) -> Result { + unsafe { syscall1(SYS_EXIT, status) } +} + +/// Change file permissions +pub fn fchmod(fd: usize, mode: u16) -> Result { + unsafe { syscall2(SYS_FCHMOD, fd, mode as usize) } + +} + +/// Change file ownership +pub fn fchown(fd: usize, uid: u32, gid: u32) -> Result { + unsafe { syscall3(SYS_FCHOWN, fd, uid as usize, gid as usize) } + +} + +/// Change file descriptor flags +pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result { + unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) } +} + +/// Replace the current process with a new executable +pub fn fexec(fd: usize, args: &[[usize; 2]], vars: &[[usize; 2]]) -> Result { + unsafe { syscall5(SYS_FEXEC, fd, args.as_ptr() as usize, args.len(), vars.as_ptr() as usize, vars.len()) } +} + +/// Map a file into memory, but with the ability to set the address to map into, either as a hint +/// or as a requirement of the map. +/// +/// # Errors +/// `EACCES` - the file descriptor was not open for reading +/// `EBADF` - if the file descriptor was invalid +/// `ENODEV` - mmapping was not supported +/// `EINVAL` - invalid combination of flags +/// `EEXIST` - if [`MapFlags::MAP_FIXED`] was set, and the address specified was already in use. +/// +pub unsafe fn fmap(fd: usize, map: &Map) -> Result { + syscall3(SYS_FMAP, fd, map as *const Map as usize, mem::size_of::()) +} + +/// Unmap whole (or partial) continous memory-mapped files +pub unsafe fn funmap(addr: usize, len: usize) -> Result { + syscall2(SYS_FUNMAP, addr, len) +} + +/// Retrieve the canonical path of a file +pub fn fpath(fd: usize, buf: &mut [u8]) -> Result { + unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) } +} + +/// Rename a file +pub fn frename>(fd: usize, path: T) -> Result { + unsafe { syscall3(SYS_FRENAME, fd, path.as_ref().as_ptr() as usize, path.as_ref().len()) } +} + +/// Get metadata about a file +pub fn fstat(fd: usize, stat: &mut Stat) -> Result { + unsafe { syscall3(SYS_FSTAT, fd, stat as *mut Stat as usize, mem::size_of::()) } +} + +/// Get metadata about a filesystem +pub fn fstatvfs(fd: usize, stat: &mut StatVfs) -> Result { + unsafe { syscall3(SYS_FSTATVFS, fd, stat as *mut StatVfs as usize, mem::size_of::()) } +} + +/// Sync a file descriptor to its underlying medium +pub fn fsync(fd: usize) -> Result { + unsafe { syscall1(SYS_FSYNC, fd) } +} + +/// Truncate or extend a file to a specified length +pub fn ftruncate(fd: usize, len: usize) -> Result { + unsafe { syscall2(SYS_FTRUNCATE, fd, len) } +} + +// Change modify and/or access times +pub fn futimens(fd: usize, times: &[TimeSpec]) -> Result { + unsafe { syscall3(SYS_FUTIMENS, fd, times.as_ptr() as usize, times.len() * mem::size_of::()) } +} + +/// Fast userspace mutex +pub unsafe fn futex(addr: *mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32) + -> Result { + syscall5(SYS_FUTEX, addr as usize, op, (val as isize) as usize, val2, addr2 as usize) +} + +/// Get the current working directory +pub fn getcwd(buf: &mut [u8]) -> Result { + unsafe { syscall2(SYS_GETCWD, buf.as_mut_ptr() as usize, buf.len()) } +} + +/// Get the effective group ID +pub fn getegid() -> Result { + unsafe { syscall0(SYS_GETEGID) } +} + +/// Get the effective namespace +pub fn getens() -> Result { + unsafe { syscall0(SYS_GETENS) } +} + +/// Get the effective user ID +pub fn geteuid() -> Result { + unsafe { syscall0(SYS_GETEUID) } +} + +/// Get the current group ID +pub fn getgid() -> Result { + unsafe { syscall0(SYS_GETGID) } +} + +/// Get the current namespace +pub fn getns() -> Result { + unsafe { syscall0(SYS_GETNS) } +} + +/// Get the current process ID +pub fn getpid() -> Result { + unsafe { syscall0(SYS_GETPID) } +} + +/// Get the process group ID +pub fn getpgid(pid: usize) -> Result { + unsafe { syscall1(SYS_GETPGID, pid) } +} + +/// Get the parent process ID +pub fn getppid() -> Result { + unsafe { syscall0(SYS_GETPPID) } +} + +/// Get the current user ID +pub fn getuid() -> Result { + unsafe { syscall0(SYS_GETUID) } +} + +/// Set the I/O privilege level +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +/// * `EINVAL` - `level > 3` +pub unsafe fn iopl(level: usize) -> Result { + syscall1(SYS_IOPL, level) +} + +/// Send a signal `sig` to the process identified by `pid` +pub fn kill(pid: usize, sig: usize) -> Result { + unsafe { syscall2(SYS_KILL, pid, sig) } +} + +/// Create a link to a file +pub unsafe fn link(old: *const u8, new: *const u8) -> Result { + syscall2(SYS_LINK, old as usize, new as usize) +} + +/// Seek to `offset` bytes in a file descriptor +pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result { + unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) } +} + +/// Make a new scheme namespace +pub fn mkns(schemes: &[[usize; 2]]) -> Result { + unsafe { syscall2(SYS_MKNS, schemes.as_ptr() as usize, schemes.len()) } +} + +/// Change mapping flags +pub unsafe fn mprotect(addr: usize, size: usize, flags: MapFlags) -> Result { + syscall3(SYS_MPROTECT, addr, size, flags.bits()) +} + +/// Sleep for the time specified in `req` +pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result { + unsafe { syscall2(SYS_NANOSLEEP, req as *const TimeSpec as usize, + rem as *mut TimeSpec as usize) } +} + +/// Open a file +pub fn open>(path: T, flags: usize) -> Result { + unsafe { syscall3(SYS_OPEN, path.as_ref().as_ptr() as usize, path.as_ref().len(), flags) } +} + +/// Allocate frames, linearly in physical memory. +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +/// * `ENOMEM` - the system has run out of available memory +pub unsafe fn physalloc(size: usize) -> Result { + syscall1(SYS_PHYSALLOC, size) +} + +/// Allocate frames, linearly in physical memory, with an extra set of flags. If the flags contain +/// [`PARTIAL_ALLOC`], this will result in `physalloc3` with `min = 1`. +/// +/// Refer to the simpler [`physalloc`] and the more complex [`physalloc3`], that this convenience +/// function is based on. +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +/// * `ENOMEM` - the system has run out of available memory +pub unsafe fn physalloc2(size: usize, flags: usize) -> Result { + let mut ret = 1usize; + physalloc3(size, flags, &mut ret) +} + +/// Allocate frames, linearly in physical memory, with an extra set of flags. If the flags contain +/// [`PARTIAL_ALLOC`], the `min` parameter specifies the number of frames that have to be allocated +/// for this operation to succeed. The return value is the offset of the first frame, and `min` is +/// overwritten with the number of frames actually allocated. +/// +/// Refer to the simpler [`physalloc`] and the simpler library function [`physalloc2`]. +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +/// * `ENOMEM` - the system has run out of available memory +/// * `EINVAL` - `min = 0` +pub unsafe fn physalloc3(size: usize, flags: usize, min: &mut usize) -> Result { + syscall3(SYS_PHYSALLOC3, size, flags, min as *mut usize as usize) +} + +/// Free physically allocated pages +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +pub unsafe fn physfree(physical_address: usize, size: usize) -> Result { + syscall2(SYS_PHYSFREE, physical_address, size) +} + +/// Map physical memory to virtual memory +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +pub unsafe fn physmap(physical_address: usize, size: usize, flags: PhysmapFlags) -> Result { + syscall3(SYS_PHYSMAP, physical_address, size, flags.bits()) +} + +/// Unmap previously mapped physical memory +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +/// * `EFAULT` - `virtual_address` has not been mapped +pub unsafe fn physunmap(virtual_address: usize) -> Result { + syscall1(SYS_PHYSUNMAP, virtual_address) +} + +/// Create a pair of file descriptors referencing the read and write ends of a pipe +pub fn pipe2(fds: &mut [usize; 2], flags: usize) -> Result { + unsafe { syscall2(SYS_PIPE2, fds.as_ptr() as usize, flags) } +} + +/// Read from a file descriptor into a buffer +pub fn read(fd: usize, buf: &mut [u8]) -> Result { + unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) } +} + +/// Remove a directory +pub fn rmdir>(path: T) -> Result { + unsafe { syscall2(SYS_RMDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) } +} + +/// Set the process group ID +pub fn setpgid(pid: usize, pgid: usize) -> Result { + unsafe { syscall2(SYS_SETPGID, pid, pgid) } +} + +/// Set the current process group IDs +pub fn setregid(rgid: usize, egid: usize) -> Result { + unsafe { syscall2(SYS_SETREGID, rgid, egid) } +} + +/// Make a new scheme namespace +pub fn setrens(rns: usize, ens: usize) -> Result { + unsafe { syscall2(SYS_SETRENS, rns, ens) } +} + +/// Set the current process user IDs +pub fn setreuid(ruid: usize, euid: usize) -> Result { + unsafe { syscall2(SYS_SETREUID, ruid, euid) } +} + +/// Set up a signal handler +pub fn sigaction(sig: usize, act: Option<&SigAction>, oldact: Option<&mut SigAction>) -> Result { + unsafe { syscall4(SYS_SIGACTION, sig, + act.map(|x| x as *const _).unwrap_or_else(ptr::null) as usize, + oldact.map(|x| x as *mut _).unwrap_or_else(ptr::null_mut) as usize, + restorer as usize) } +} + +/// Get and/or set signal masks +pub fn sigprocmask(how: usize, set: Option<&[u64; 2]>, oldset: Option<&mut [u64; 2]>) -> Result { + unsafe { syscall3(SYS_SIGPROCMASK, how, + set.map(|x| x as *const _).unwrap_or_else(ptr::null) as usize, + oldset.map(|x| x as *mut _).unwrap_or_else(ptr::null_mut) as usize) } +} + +// Return from signal handler +pub fn sigreturn() -> Result { + unsafe { syscall0(SYS_SIGRETURN) } +} + +/// Set the file mode creation mask +pub fn umask(mask: usize) -> Result { + unsafe { syscall1(SYS_UMASK, mask) } +} + +/// Remove a file +pub fn unlink>(path: T) -> Result { + unsafe { syscall2(SYS_UNLINK, path.as_ref().as_ptr() as usize, path.as_ref().len()) } +} + +/// Convert a virtual address to a physical one +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +pub unsafe fn virttophys(virtual_address: usize) -> Result { + syscall1(SYS_VIRTTOPHYS, virtual_address) +} + +/// Check if a child process has exited or received a signal +pub fn waitpid(pid: usize, status: &mut usize, options: WaitFlags) -> Result { + unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options.bits()) } +} + +/// Write a buffer to a file descriptor +/// +/// The kernel will attempt to write the bytes in `buf` to the file descriptor `fd`, returning +/// either an `Err`, explained below, or `Ok(count)` where `count` is the number of bytes which +/// were written. +/// +/// # Errors +/// +/// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block +/// * `EBADF` - the file descriptor is not valid or is not open for writing +/// * `EFAULT` - `buf` does not point to the process's addressible memory +/// * `EIO` - an I/O error occurred +/// * `ENOSPC` - the device containing the file descriptor has no room for data +/// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed +pub fn write(fd: usize, buf: &[u8]) -> Result { + unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) } +} + +/// Yield the process's time slice to the kernel +/// +/// This function will return Ok(0) on success +pub fn sched_yield() -> Result { + unsafe { syscall0(SYS_YIELD) } +} diff --git a/vendor/redox_syscall-0.2.16/src/daemon.rs b/vendor/redox_syscall-0.2.16/src/daemon.rs new file mode 100644 index 0000000000000..6433bcd7d25b4 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/daemon.rs @@ -0,0 +1,62 @@ +use core::convert::Infallible; + +use super::{ + clone, + CloneFlags, + close, + EIO, + Error, + exit, + pipe2, + read, + Result, + write, +}; + +#[must_use = "Daemon::ready must be called"] +pub struct Daemon { + write_pipe: usize, +} + +impl Daemon { + pub fn new Infallible>(f: F) -> Result { + let mut pipes = [0; 2]; + pipe2(&mut pipes, 0)?; + + let [read_pipe, write_pipe] = pipes; + + if unsafe { clone(CloneFlags::empty())? } == 0 { + let _ = close(read_pipe); + + f(Daemon { + write_pipe, + }); + // TODO: Replace Infallible with the never type once it is stabilized. + unreachable!(); + } else { + let _ = close(write_pipe); + + let mut data = [0]; + let res = read(read_pipe, &mut data); + let _ = close(read_pipe); + + if res? == 1 { + exit(data[0] as usize)?; + unreachable!(); + } else { + Err(Error::new(EIO)) + } + } + } + + pub fn ready(self) -> Result<()> { + let res = write(self.write_pipe, &[0]); + let _ = close(self.write_pipe); + + if res? == 1 { + Ok(()) + } else { + Err(Error::new(EIO)) + } + } +} diff --git a/vendor/redox_syscall-0.2.16/src/data.rs b/vendor/redox_syscall-0.2.16/src/data.rs new file mode 100644 index 0000000000000..45d2dd86253ed --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/data.rs @@ -0,0 +1,297 @@ +use core::ops::{Deref, DerefMut}; +use core::{mem, slice}; +use crate::flag::{EventFlags, MapFlags, PtraceFlags, SigActionFlags}; + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct Event { + pub id: usize, + pub flags: EventFlags, + pub data: usize +} + +impl Deref for Event { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Event as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for Event { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Event as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct ITimerSpec { + pub it_interval: TimeSpec, + pub it_value: TimeSpec, +} + +impl Deref for ITimerSpec { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const ITimerSpec as *const u8, + mem::size_of::()) + } + } +} + +impl DerefMut for ITimerSpec { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut ITimerSpec as *mut u8, + mem::size_of::()) + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct OldMap { + pub offset: usize, + pub size: usize, + pub flags: MapFlags, +} + +impl Deref for OldMap { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const OldMap as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for OldMap { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut OldMap as *mut u8, mem::size_of::()) + } + } +} +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct Map { + /// The offset inside the file that is being mapped. + pub offset: usize, + + /// The size of the memory map. + pub size: usize, + + /// Contains both prot and map flags. + pub flags: MapFlags, + + /// Functions as a hint to where in the virtual address space of the running process, to place + /// the memory map. If [`MapFlags::MAP_FIXED`] is set, then this address must be the address to + /// map to. + pub address: usize, +} + +impl Deref for Map { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Map as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for Map { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Map as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct Packet { + pub id: u64, + pub pid: usize, + pub uid: u32, + pub gid: u32, + pub a: usize, + pub b: usize, + pub c: usize, + pub d: usize +} + +impl Deref for Packet { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Packet as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for Packet { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Packet as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct SigAction { + pub sa_handler: Option, + pub sa_mask: [u64; 2], + pub sa_flags: SigActionFlags, +} + +#[allow(dead_code)] +unsafe fn _assert_size_of_function_is_sane() { + // Transmuting will complain *at compile time* if sizes differ. + // Rust forbids a fn-pointer from being 0 so to allow SIG_DFL to + // exist, we use Option which will mean 0 + // becomes None + let _ = mem::transmute::, usize>(None); +} + +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct Stat { + pub st_dev: u64, + pub st_ino: u64, + pub st_mode: u16, + pub st_nlink: u32, + pub st_uid: u32, + pub st_gid: u32, + pub st_size: u64, + pub st_blksize: u32, + pub st_blocks: u64, + pub st_mtime: u64, + pub st_mtime_nsec: u32, + pub st_atime: u64, + pub st_atime_nsec: u32, + pub st_ctime: u64, + pub st_ctime_nsec: u32, +} + +impl Deref for Stat { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Stat as *const u8, + mem::size_of::()) + } + } +} + +impl DerefMut for Stat { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Stat as *mut u8, + mem::size_of::()) + } + } +} + +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct StatVfs { + pub f_bsize: u32, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, +} + +impl Deref for StatVfs { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const StatVfs as *const u8, + mem::size_of::()) + } + } +} + +impl DerefMut for StatVfs { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut StatVfs as *mut u8, + mem::size_of::()) + } + } +} + +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct TimeSpec { + pub tv_sec: i64, + pub tv_nsec: i32, +} + +impl Deref for TimeSpec { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const TimeSpec as *const u8, + mem::size_of::()) + } + } +} + +impl DerefMut for TimeSpec { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut TimeSpec as *mut u8, + mem::size_of::()) + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(C)] +pub struct PtraceEvent { + pub cause: PtraceFlags, + pub a: usize, + pub b: usize, + pub c: usize, + pub d: usize, + pub e: usize, + pub f: usize +} + +impl Deref for PtraceEvent { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const PtraceEvent as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for PtraceEvent { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut PtraceEvent as *mut u8, mem::size_of::()) + } + } +} + +#[macro_export] +macro_rules! ptrace_event { + ($cause:expr $(, $a:expr $(, $b:expr $(, $c:expr)?)?)?) => { + $crate::data::PtraceEvent { + cause: $cause, + $(a: $a, + $(b: $b, + $(c: $c,)? + )? + )? + ..Default::default() + } + } +} diff --git a/vendor/redox_syscall-0.2.16/src/error.rs b/vendor/redox_syscall-0.2.16/src/error.rs new file mode 100644 index 0000000000000..9a4b0b5ad39ae --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/error.rs @@ -0,0 +1,311 @@ +use core::{fmt, result}; + +#[derive(Eq, PartialEq)] +pub struct Error { + pub errno: i32, +} + +pub type Result = result::Result; + +impl Error { + pub fn new(errno: i32) -> Error { + Error { errno: errno } + } + + pub fn mux(result: Result) -> usize { + match result { + Ok(value) => value, + Err(error) => -error.errno as usize, + } + } + + pub fn demux(value: usize) -> Result { + let errno = -(value as i32); + if errno >= 1 && errno < STR_ERROR.len() as i32 { + Err(Error::new(errno)) + } else { + Ok(value) + } + } + + pub fn text(&self) -> &'static str { + STR_ERROR.get(self.errno as usize).map(|&x| x).unwrap_or("Unknown Error") + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + f.write_str(self.text()) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + f.write_str(self.text()) + } +} + +pub const EPERM: i32 = 1; /* Operation not permitted */ +pub const ENOENT: i32 = 2; /* No such file or directory */ +pub const ESRCH: i32 = 3; /* No such process */ +pub const EINTR: i32 = 4; /* Interrupted system call */ +pub const EIO: i32 = 5; /* I/O error */ +pub const ENXIO: i32 = 6; /* No such device or address */ +pub const E2BIG: i32 = 7; /* Argument list too long */ +pub const ENOEXEC: i32 = 8; /* Exec format error */ +pub const EBADF: i32 = 9; /* Bad file number */ +pub const ECHILD: i32 = 10; /* No child processes */ +pub const EAGAIN: i32 = 11; /* Try again */ +pub const ENOMEM: i32 = 12; /* Out of memory */ +pub const EACCES: i32 = 13; /* Permission denied */ +pub const EFAULT: i32 = 14; /* Bad address */ +pub const ENOTBLK: i32 = 15; /* Block device required */ +pub const EBUSY: i32 = 16; /* Device or resource busy */ +pub const EEXIST: i32 = 17; /* File exists */ +pub const EXDEV: i32 = 18; /* Cross-device link */ +pub const ENODEV: i32 = 19; /* No such device */ +pub const ENOTDIR: i32 = 20; /* Not a directory */ +pub const EISDIR: i32 = 21; /* Is a directory */ +pub const EINVAL: i32 = 22; /* Invalid argument */ +pub const ENFILE: i32 = 23; /* File table overflow */ +pub const EMFILE: i32 = 24; /* Too many open files */ +pub const ENOTTY: i32 = 25; /* Not a typewriter */ +pub const ETXTBSY: i32 = 26; /* Text file busy */ +pub const EFBIG: i32 = 27; /* File too large */ +pub const ENOSPC: i32 = 28; /* No space left on device */ +pub const ESPIPE: i32 = 29; /* Illegal seek */ +pub const EROFS: i32 = 30; /* Read-only file system */ +pub const EMLINK: i32 = 31; /* Too many links */ +pub const EPIPE: i32 = 32; /* Broken pipe */ +pub const EDOM: i32 = 33; /* Math argument out of domain of func */ +pub const ERANGE: i32 = 34; /* Math result not representable */ +pub const EDEADLK: i32 = 35; /* Resource deadlock would occur */ +pub const ENAMETOOLONG: i32 = 36; /* File name too long */ +pub const ENOLCK: i32 = 37; /* No record locks available */ +pub const ENOSYS: i32 = 38; /* Function not implemented */ +pub const ENOTEMPTY: i32 = 39; /* Directory not empty */ +pub const ELOOP: i32 = 40; /* Too many symbolic links encountered */ +pub const EWOULDBLOCK: i32 = 41; /* Operation would block */ +pub const ENOMSG: i32 = 42; /* No message of desired type */ +pub const EIDRM: i32 = 43; /* Identifier removed */ +pub const ECHRNG: i32 = 44; /* Channel number out of range */ +pub const EL2NSYNC: i32 = 45; /* Level 2 not synchronized */ +pub const EL3HLT: i32 = 46; /* Level 3 halted */ +pub const EL3RST: i32 = 47; /* Level 3 reset */ +pub const ELNRNG: i32 = 48; /* Link number out of range */ +pub const EUNATCH: i32 = 49; /* Protocol driver not attached */ +pub const ENOCSI: i32 = 50; /* No CSI structure available */ +pub const EL2HLT: i32 = 51; /* Level 2 halted */ +pub const EBADE: i32 = 52; /* Invalid exchange */ +pub const EBADR: i32 = 53; /* Invalid request descriptor */ +pub const EXFULL: i32 = 54; /* Exchange full */ +pub const ENOANO: i32 = 55; /* No anode */ +pub const EBADRQC: i32 = 56; /* Invalid request code */ +pub const EBADSLT: i32 = 57; /* Invalid slot */ +pub const EDEADLOCK: i32 = 58; /* Resource deadlock would occur */ +pub const EBFONT: i32 = 59; /* Bad font file format */ +pub const ENOSTR: i32 = 60; /* Device not a stream */ +pub const ENODATA: i32 = 61; /* No data available */ +pub const ETIME: i32 = 62; /* Timer expired */ +pub const ENOSR: i32 = 63; /* Out of streams resources */ +pub const ENONET: i32 = 64; /* Machine is not on the network */ +pub const ENOPKG: i32 = 65; /* Package not installed */ +pub const EREMOTE: i32 = 66; /* Object is remote */ +pub const ENOLINK: i32 = 67; /* Link has been severed */ +pub const EADV: i32 = 68; /* Advertise error */ +pub const ESRMNT: i32 = 69; /* Srmount error */ +pub const ECOMM: i32 = 70; /* Communication error on send */ +pub const EPROTO: i32 = 71; /* Protocol error */ +pub const EMULTIHOP: i32 = 72; /* Multihop attempted */ +pub const EDOTDOT: i32 = 73; /* RFS specific error */ +pub const EBADMSG: i32 = 74; /* Not a data message */ +pub const EOVERFLOW: i32 = 75; /* Value too large for defined data type */ +pub const ENOTUNIQ: i32 = 76; /* Name not unique on network */ +pub const EBADFD: i32 = 77; /* File descriptor in bad state */ +pub const EREMCHG: i32 = 78; /* Remote address changed */ +pub const ELIBACC: i32 = 79; /* Can not access a needed shared library */ +pub const ELIBBAD: i32 = 80; /* Accessing a corrupted shared library */ +pub const ELIBSCN: i32 = 81; /* .lib section in a.out corrupted */ +pub const ELIBMAX: i32 = 82; /* Attempting to link in too many shared libraries */ +pub const ELIBEXEC: i32 = 83; /* Cannot exec a shared library directly */ +pub const EILSEQ: i32 = 84; /* Illegal byte sequence */ +pub const ERESTART: i32 = 85; /* Interrupted system call should be restarted */ +pub const ESTRPIPE: i32 = 86; /* Streams pipe error */ +pub const EUSERS: i32 = 87; /* Too many users */ +pub const ENOTSOCK: i32 = 88; /* Socket operation on non-socket */ +pub const EDESTADDRREQ: i32 = 89; /* Destination address required */ +pub const EMSGSIZE: i32 = 90; /* Message too long */ +pub const EPROTOTYPE: i32 = 91; /* Protocol wrong type for socket */ +pub const ENOPROTOOPT: i32 = 92; /* Protocol not available */ +pub const EPROTONOSUPPORT: i32 = 93; /* Protocol not supported */ +pub const ESOCKTNOSUPPORT: i32 = 94; /* Socket type not supported */ +pub const EOPNOTSUPP: i32 = 95; /* Operation not supported on transport endpoint */ +pub const EPFNOSUPPORT: i32 = 96; /* Protocol family not supported */ +pub const EAFNOSUPPORT: i32 = 97; /* Address family not supported by protocol */ +pub const EADDRINUSE: i32 = 98; /* Address already in use */ +pub const EADDRNOTAVAIL: i32 = 99; /* Cannot assign requested address */ +pub const ENETDOWN: i32 = 100; /* Network is down */ +pub const ENETUNREACH: i32 = 101; /* Network is unreachable */ +pub const ENETRESET: i32 = 102; /* Network dropped connection because of reset */ +pub const ECONNABORTED: i32 = 103; /* Software caused connection abort */ +pub const ECONNRESET: i32 = 104; /* Connection reset by peer */ +pub const ENOBUFS: i32 = 105; /* No buffer space available */ +pub const EISCONN: i32 = 106; /* Transport endpoint is already connected */ +pub const ENOTCONN: i32 = 107; /* Transport endpoint is not connected */ +pub const ESHUTDOWN: i32 = 108; /* Cannot send after transport endpoint shutdown */ +pub const ETOOMANYREFS: i32 = 109; /* Too many references: cannot splice */ +pub const ETIMEDOUT: i32 = 110; /* Connection timed out */ +pub const ECONNREFUSED: i32 = 111; /* Connection refused */ +pub const EHOSTDOWN: i32 = 112; /* Host is down */ +pub const EHOSTUNREACH: i32 = 113; /* No route to host */ +pub const EALREADY: i32 = 114; /* Operation already in progress */ +pub const EINPROGRESS: i32 = 115; /* Operation now in progress */ +pub const ESTALE: i32 = 116; /* Stale NFS file handle */ +pub const EUCLEAN: i32 = 117; /* Structure needs cleaning */ +pub const ENOTNAM: i32 = 118; /* Not a XENIX named type file */ +pub const ENAVAIL: i32 = 119; /* No XENIX semaphores available */ +pub const EISNAM: i32 = 120; /* Is a named type file */ +pub const EREMOTEIO: i32 = 121; /* Remote I/O error */ +pub const EDQUOT: i32 = 122; /* Quota exceeded */ +pub const ENOMEDIUM: i32 = 123; /* No medium found */ +pub const EMEDIUMTYPE: i32 = 124; /* Wrong medium type */ +pub const ECANCELED: i32 = 125; /* Operation Canceled */ +pub const ENOKEY: i32 = 126; /* Required key not available */ +pub const EKEYEXPIRED: i32 = 127; /* Key has expired */ +pub const EKEYREVOKED: i32 = 128; /* Key has been revoked */ +pub const EKEYREJECTED: i32 = 129; /* Key was rejected by service */ +pub const EOWNERDEAD: i32 = 130; /* Owner died */ +pub const ENOTRECOVERABLE: i32 = 131; /* State not recoverable */ + +pub static STR_ERROR: [&'static str; 132] = ["Success", + "Operation not permitted", + "No such file or directory", + "No such process", + "Interrupted system call", + "I/O error", + "No such device or address", + "Argument list too long", + "Exec format error", + "Bad file number", + "No child processes", + "Try again", + "Out of memory", + "Permission denied", + "Bad address", + "Block device required", + "Device or resource busy", + "File exists", + "Cross-device link", + "No such device", + "Not a directory", + "Is a directory", + "Invalid argument", + "File table overflow", + "Too many open files", + "Not a typewriter", + "Text file busy", + "File too large", + "No space left on device", + "Illegal seek", + "Read-only file system", + "Too many links", + "Broken pipe", + "Math argument out of domain of func", + "Math result not representable", + "Resource deadlock would occur", + "File name too long", + "No record locks available", + "Function not implemented", + "Directory not empty", + "Too many symbolic links encountered", + "Operation would block", + "No message of desired type", + "Identifier removed", + "Channel number out of range", + "Level 2 not synchronized", + "Level 3 halted", + "Level 3 reset", + "Link number out of range", + "Protocol driver not attached", + "No CSI structure available", + "Level 2 halted", + "Invalid exchange", + "Invalid request descriptor", + "Exchange full", + "No anode", + "Invalid request code", + "Invalid slot", + "Resource deadlock would occur", + "Bad font file format", + "Device not a stream", + "No data available", + "Timer expired", + "Out of streams resources", + "Machine is not on the network", + "Package not installed", + "Object is remote", + "Link has been severed", + "Advertise error", + "Srmount error", + "Communication error on send", + "Protocol error", + "Multihop attempted", + "RFS specific error", + "Not a data message", + "Value too large for defined data type", + "Name not unique on network", + "File descriptor in bad state", + "Remote address changed", + "Can not access a needed shared library", + "Accessing a corrupted shared library", + ".lib section in a.out corrupted", + "Attempting to link in too many shared libraries", + "Cannot exec a shared library directly", + "Illegal byte sequence", + "Interrupted system call should be restarted", + "Streams pipe error", + "Too many users", + "Socket operation on non-socket", + "Destination address required", + "Message too long", + "Protocol wrong type for socket", + "Protocol not available", + "Protocol not supported", + "Socket type not supported", + "Operation not supported on transport endpoint", + "Protocol family not supported", + "Address family not supported by protocol", + "Address already in use", + "Cannot assign requested address", + "Network is down", + "Network is unreachable", + "Network dropped connection because of reset", + "Software caused connection abort", + "Connection reset by peer", + "No buffer space available", + "Transport endpoint is already connected", + "Transport endpoint is not connected", + "Cannot send after transport endpoint shutdown", + "Too many references: cannot splice", + "Connection timed out", + "Connection refused", + "Host is down", + "No route to host", + "Operation already in progress", + "Operation now in progress", + "Stale NFS file handle", + "Structure needs cleaning", + "Not a XENIX named type file", + "No XENIX semaphores available", + "Is a named type file", + "Remote I/O error", + "Quota exceeded", + "No medium found", + "Wrong medium type", + "Operation Canceled", + "Required key not available", + "Key has expired", + "Key has been revoked", + "Key was rejected by service", + "Owner died", + "State not recoverable"]; diff --git a/vendor/redox_syscall-0.2.16/src/flag.rs b/vendor/redox_syscall-0.2.16/src/flag.rs new file mode 100644 index 0000000000000..9788884afa393 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/flag.rs @@ -0,0 +1,348 @@ +use bitflags::bitflags as inner_bitflags; +use core::{mem, ops::Deref, slice}; + +macro_rules! bitflags { + ( + $(#[$outer:meta])* + pub struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + // First, use the inner bitflags + inner_bitflags! { + #[derive(Default)] + $(#[$outer])* + pub struct $BitFlags: $T { + $( + $(#[$inner $($args)*])* + const $Flag = $value; + )+ + } + } + + // Secondly, re-export all inner constants + // (`pub use self::Struct::*` doesn't work) + $( + $(#[$inner $($args)*])* + pub const $Flag: $BitFlags = $BitFlags::$Flag; + )+ + } +} + +bitflags! { + pub struct CloneFlags: usize { + const CLONE_VM = 0x100; + const CLONE_FS = 0x200; + const CLONE_FILES = 0x400; + const CLONE_SIGHAND = 0x800; + const CLONE_VFORK = 0x4000; + const CLONE_THREAD = 0x10000; + const CLONE_STACK = 0x1000_0000; + } +} + +pub const CLOCK_REALTIME: usize = 1; +pub const CLOCK_MONOTONIC: usize = 4; + +bitflags! { + pub struct EventFlags: usize { + const EVENT_NONE = 0; + const EVENT_READ = 1; + const EVENT_WRITE = 2; + } +} + +pub const F_DUPFD: usize = 0; +pub const F_GETFD: usize = 1; +pub const F_SETFD: usize = 2; +pub const F_GETFL: usize = 3; +pub const F_SETFL: usize = 4; + +pub const FUTEX_WAIT: usize = 0; +pub const FUTEX_WAKE: usize = 1; +pub const FUTEX_REQUEUE: usize = 2; +pub const FUTEX_WAIT64: usize = 3; + +bitflags! { + pub struct MapFlags: usize { + const PROT_NONE = 0x0000_0000; + const PROT_EXEC = 0x0001_0000; + const PROT_WRITE = 0x0002_0000; + const PROT_READ = 0x0004_0000; + + const MAP_SHARED = 0x0001; + const MAP_PRIVATE = 0x0002; + + /// Only accepted for mmap2(2). + const MAP_FIXED = 0x0004; + const MAP_FIXED_NOREPLACE = 0x000C; + } +} + +pub const MODE_TYPE: u16 = 0xF000; +pub const MODE_DIR: u16 = 0x4000; +pub const MODE_FILE: u16 = 0x8000; +pub const MODE_SYMLINK: u16 = 0xA000; +pub const MODE_FIFO: u16 = 0x1000; +pub const MODE_CHR: u16 = 0x2000; + +pub const MODE_PERM: u16 = 0x0FFF; +pub const MODE_SETUID: u16 = 0o4000; +pub const MODE_SETGID: u16 = 0o2000; + +pub const O_RDONLY: usize = 0x0001_0000; +pub const O_WRONLY: usize = 0x0002_0000; +pub const O_RDWR: usize = 0x0003_0000; +pub const O_NONBLOCK: usize = 0x0004_0000; +pub const O_APPEND: usize = 0x0008_0000; +pub const O_SHLOCK: usize = 0x0010_0000; +pub const O_EXLOCK: usize = 0x0020_0000; +pub const O_ASYNC: usize = 0x0040_0000; +pub const O_FSYNC: usize = 0x0080_0000; +pub const O_CLOEXEC: usize = 0x0100_0000; +pub const O_CREAT: usize = 0x0200_0000; +pub const O_TRUNC: usize = 0x0400_0000; +pub const O_EXCL: usize = 0x0800_0000; +pub const O_DIRECTORY: usize = 0x1000_0000; +pub const O_STAT: usize = 0x2000_0000; +pub const O_SYMLINK: usize = 0x4000_0000; +pub const O_NOFOLLOW: usize = 0x8000_0000; +pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR; + +bitflags! { + pub struct PhysmapFlags: usize { + const PHYSMAP_WRITE = 0x0000_0001; + const PHYSMAP_WRITE_COMBINE = 0x0000_0002; + const PHYSMAP_NO_CACHE = 0x0000_0004; + } +} +bitflags! { + /// Extra flags for [`physalloc2`] or [`physalloc3`]. + /// + /// [`physalloc2`]: ../call/fn.physalloc2.html + /// [`physalloc3`]: ../call/fn.physalloc3.html + pub struct PhysallocFlags: usize { + /// Only allocate memory within the 32-bit physical memory space. This is necessary for + /// some devices may not support 64-bit memory. + const SPACE_32 = 0x0000_0001; + + /// The frame that will be allocated, is going to reside anywhere in 64-bit space. This + /// flag is redundant for the most part, except when overriding some other default. + const SPACE_64 = 0x0000_0002; + + /// Do a "partial allocation", which means that not all of the frames specified in the + /// frame count `size` actually have to be allocated. This means that if the allocator was + /// unable to find a physical memory range large enough, it can instead return whatever + /// range it decides is optimal. Thus, instead of letting one driver get an expensive + /// 128MiB physical memory range when the physical memory has become fragmented, and + /// failing, it can instead be given a more optimal range. If the device supports + /// scatter-gather lists, then the driver only has to allocate more ranges, and the device + /// will do vectored I/O. + /// + /// PARTIAL_ALLOC supports different allocation strategies, refer to + /// [`Optimal`], [`GreatestRange`]. + /// + /// [`Optimal`]: ./enum.PartialAllocStrategy.html + /// [`GreatestRange`]: ./enum.PartialAllocStrategy.html + const PARTIAL_ALLOC = 0x0000_0004; + } +} + +/// The bitmask of the partial allocation strategy. Currently four different strategies are +/// supported. If [`PARTIAL_ALLOC`] is not set, this bitmask is no longer reserved. +pub const PARTIAL_ALLOC_STRATEGY_MASK: usize = 0x0003_0000; + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(usize)] +pub enum PartialAllocStrategy { + /// The allocator decides itself the size of the memory range, based on e.g. free memory ranges + /// and other processes which require large physical memory chunks. + Optimal = 0x0001_0000, + + /// The allocator returns the absolute greatest range it can find. + GreatestRange = 0x0002_0000, + + /// The allocator returns the first range that fits the minimum count, without searching extra. + Greedy = 0x0003_0000, +} +impl Default for PartialAllocStrategy { + fn default() -> Self { + Self::Optimal + } +} + +impl PartialAllocStrategy { + pub fn from_raw(raw: usize) -> Option { + match raw { + 0x0001_0000 => Some(Self::Optimal), + 0x0002_0000 => Some(Self::GreatestRange), + 0x0003_0000 => Some(Self::Greedy), + _ => None, + } + } +} + +// The top 48 bits of PTRACE_* are reserved, for now + +bitflags! { + pub struct PtraceFlags: u64 { + /// Stop before a syscall is handled. Send PTRACE_FLAG_IGNORE to not + /// handle the syscall. + const PTRACE_STOP_PRE_SYSCALL = 0x0000_0000_0000_0001; + /// Stop after a syscall is handled. + const PTRACE_STOP_POST_SYSCALL = 0x0000_0000_0000_0002; + /// Stop after exactly one instruction. TODO: This may not handle + /// fexec/signal boundaries. Should it? + const PTRACE_STOP_SINGLESTEP = 0x0000_0000_0000_0004; + /// Stop before a signal is handled. Send PTRACE_FLAG_IGNORE to not + /// handle signal. + const PTRACE_STOP_SIGNAL = 0x0000_0000_0000_0008; + /// Stop on a software breakpoint, such as the int3 instruction for + /// x86_64. + const PTRACE_STOP_BREAKPOINT = 0x0000_0000_0000_0010; + /// Stop just before exiting for good. + const PTRACE_STOP_EXIT = 0x0000_0000_0000_0020; + + const PTRACE_STOP_MASK = 0x0000_0000_0000_00FF; + + + /// Sent when a child is cloned, giving you the opportunity to trace it. + /// If you don't catch this, the child is started as normal. + const PTRACE_EVENT_CLONE = 0x0000_0000_0000_0100; + + const PTRACE_EVENT_MASK = 0x0000_0000_0000_0F00; + + + /// Special meaning, depending on the event. Usually, when fired before + /// an action, it will skip performing that action. + const PTRACE_FLAG_IGNORE = 0x0000_0000_0000_1000; + + const PTRACE_FLAG_MASK = 0x0000_0000_0000_F000; + } +} +impl Deref for PtraceFlags { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + // Same as to_ne_bytes but in-place + unsafe { + slice::from_raw_parts( + &self.bits as *const _ as *const u8, + mem::size_of::() + ) + } + } +} + +pub const SEEK_SET: usize = 0; +pub const SEEK_CUR: usize = 1; +pub const SEEK_END: usize = 2; + +pub const SIGHUP: usize = 1; +pub const SIGINT: usize = 2; +pub const SIGQUIT: usize = 3; +pub const SIGILL: usize = 4; +pub const SIGTRAP: usize = 5; +pub const SIGABRT: usize = 6; +pub const SIGBUS: usize = 7; +pub const SIGFPE: usize = 8; +pub const SIGKILL: usize = 9; +pub const SIGUSR1: usize = 10; +pub const SIGSEGV: usize = 11; +pub const SIGUSR2: usize = 12; +pub const SIGPIPE: usize = 13; +pub const SIGALRM: usize = 14; +pub const SIGTERM: usize = 15; +pub const SIGSTKFLT: usize= 16; +pub const SIGCHLD: usize = 17; +pub const SIGCONT: usize = 18; +pub const SIGSTOP: usize = 19; +pub const SIGTSTP: usize = 20; +pub const SIGTTIN: usize = 21; +pub const SIGTTOU: usize = 22; +pub const SIGURG: usize = 23; +pub const SIGXCPU: usize = 24; +pub const SIGXFSZ: usize = 25; +pub const SIGVTALRM: usize= 26; +pub const SIGPROF: usize = 27; +pub const SIGWINCH: usize = 28; +pub const SIGIO: usize = 29; +pub const SIGPWR: usize = 30; +pub const SIGSYS: usize = 31; + +pub const SIG_DFL: usize = 0; +pub const SIG_IGN: usize = 1; + +pub const SIG_BLOCK: usize = 0; +pub const SIG_UNBLOCK: usize = 1; +pub const SIG_SETMASK: usize = 2; + +bitflags! { + pub struct SigActionFlags: usize { + const SA_NOCLDSTOP = 0x00000001; + const SA_NOCLDWAIT = 0x00000002; + const SA_SIGINFO = 0x00000004; + const SA_RESTORER = 0x04000000; + const SA_ONSTACK = 0x08000000; + const SA_RESTART = 0x10000000; + const SA_NODEFER = 0x40000000; + const SA_RESETHAND = 0x80000000; + } +} + +// Auxiliery vector types +pub const AT_NULL: usize = 0; +pub const AT_PHDR: usize = 3; +pub const AT_PHENT: usize = 4; +pub const AT_PHNUM: usize = 5; +pub const AT_ENTRY: usize = 9; + +bitflags! { + pub struct WaitFlags: usize { + const WNOHANG = 0x01; + const WUNTRACED = 0x02; + const WCONTINUED = 0x08; + } +} + +/// True if status indicates the child is stopped. +pub fn wifstopped(status: usize) -> bool { + (status & 0xff) == 0x7f +} + +/// If wifstopped(status), the signal that stopped the child. +pub fn wstopsig(status: usize) -> usize { + (status >> 8) & 0xff +} + +/// True if status indicates the child continued after a stop. +pub fn wifcontinued(status: usize) -> bool { + status == 0xffff +} + +/// True if STATUS indicates termination by a signal. +pub fn wifsignaled(status: usize) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 +} + +/// If wifsignaled(status), the terminating signal. +pub fn wtermsig(status: usize) -> usize { + status & 0x7f +} + +/// True if status indicates normal termination. +pub fn wifexited(status: usize) -> bool { + wtermsig(status) == 0 +} + +/// If wifexited(status), the exit status. +pub fn wexitstatus(status: usize) -> usize { + (status >> 8) & 0xff +} + +/// True if status indicates a core dump was created. +pub fn wcoredump(status: usize) -> bool { + (status & 0x80) != 0 +} diff --git a/vendor/redox_syscall-0.2.16/src/io/dma.rs b/vendor/redox_syscall-0.2.16/src/io/dma.rs new file mode 100644 index 0000000000000..b356c8abe9610 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/io/dma.rs @@ -0,0 +1,200 @@ +use core::mem::{self, MaybeUninit}; +use core::ops::{Deref, DerefMut}; +use core::{ptr, slice}; + +use crate::Result; +use crate::{PartialAllocStrategy, PhysallocFlags}; + +/// An RAII guard of a physical memory allocation. Currently all physically allocated memory are +/// page-aligned and take up at least 4k of space (on x86_64). +#[derive(Debug)] +pub struct PhysBox { + address: usize, + size: usize +} + +impl PhysBox { + /// Construct a PhysBox from an address and a size. + /// + /// # Safety + /// This function is unsafe because when dropping, Self has to a valid allocation. + pub unsafe fn from_raw_parts(address: usize, size: usize) -> Self { + Self { + address, + size, + } + } + + /// Retrieve the byte address in physical memory, of this allocation. + pub fn address(&self) -> usize { + self.address + } + + /// Retrieve the size in bytes of the alloc. + pub fn size(&self) -> usize { + self.size + } + + /// Allocate physical memory that must reside in 32-bit space. + pub fn new_in_32bit_space(size: usize) -> Result { + Self::new_with_flags(size, PhysallocFlags::SPACE_32) + } + + pub fn new_with_flags(size: usize, flags: PhysallocFlags) -> Result { + assert!(!flags.contains(PhysallocFlags::PARTIAL_ALLOC)); + + let address = unsafe { crate::physalloc2(size, flags.bits())? }; + Ok(Self { + address, + size, + }) + } + + /// "Partially" allocate physical memory, in the sense that the allocation may be smaller than + /// expected, but still with a minimum limit. This is particularly useful when the physical + /// memory space is fragmented, and a device supports scatter-gather I/O. In that case, the + /// driver can optimistically request e.g. 1 alloc of 1 MiB, with the minimum of 512 KiB. If + /// that first allocation only returns half the size, the driver can do another allocation + /// and then let the device use both buffers. + pub fn new_partial_allocation(size: usize, flags: PhysallocFlags, strategy: Option, mut min: usize) -> Result { + debug_assert!(!(flags.contains(PhysallocFlags::PARTIAL_ALLOC) && strategy.is_none())); + + let address = unsafe { crate::physalloc3(size, flags.bits() | strategy.map(|s| s as usize).unwrap_or(0), &mut min)? }; + Ok(Self { + address, + size: min, + }) + } + + pub fn new(size: usize) -> Result { + let address = unsafe { crate::physalloc(size)? }; + Ok(Self { + address, + size, + }) + } +} + +impl Drop for PhysBox { + fn drop(&mut self) { + let _ = unsafe { crate::physfree(self.address, self.size) }; + } +} + +pub struct Dma { + phys: PhysBox, + virt: *mut T, +} + +impl Dma { + pub fn from_physbox_uninit(phys: PhysBox) -> Result>> { + let virt = unsafe { crate::physmap(phys.address, phys.size, crate::PHYSMAP_WRITE)? } as *mut MaybeUninit; + + Ok(Dma { + phys, + virt, + }) + } + pub fn from_physbox_zeroed(phys: PhysBox) -> Result>> { + let this = Self::from_physbox_uninit(phys)?; + unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit, 0, this.phys.size) } + Ok(this) + } + + pub fn from_physbox(phys: PhysBox, value: T) -> Result { + let this = Self::from_physbox_uninit(phys)?; + + Ok(unsafe { + ptr::write(this.virt, MaybeUninit::new(value)); + this.assume_init() + }) + } + + pub fn new(value: T) -> Result { + let phys = PhysBox::new(mem::size_of::())?; + Self::from_physbox(phys, value) + } + pub fn zeroed() -> Result>> { + let phys = PhysBox::new(mem::size_of::())?; + Self::from_physbox_zeroed(phys) + } +} + +impl Dma> { + pub unsafe fn assume_init(self) -> Dma { + let &Dma { phys: PhysBox { address, size }, virt } = &self; + mem::forget(self); + + Dma { + phys: PhysBox { address, size }, + virt: virt as *mut T, + } + } +} +impl Dma { + pub fn physical(&self) -> usize { + self.phys.address() + } + pub fn size(&self) -> usize { + self.phys.size() + } + pub fn phys(&self) -> &PhysBox { + &self.phys + } +} + +impl Dma<[T]> { + pub fn from_physbox_uninit_unsized(phys: PhysBox, len: usize) -> Result]>> { + let max_len = phys.size() / mem::size_of::(); + assert!(len <= max_len); + + Ok(Dma { + virt: unsafe { slice::from_raw_parts_mut(crate::physmap(phys.address, phys.size, crate::PHYSMAP_WRITE)? as *mut MaybeUninit, len) } as *mut [MaybeUninit], + phys, + }) + } + pub fn from_physbox_zeroed_unsized(phys: PhysBox, len: usize) -> Result]>> { + let this = Self::from_physbox_uninit_unsized(phys, len)?; + unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit, 0, this.phys.size()) } + Ok(this) + } + /// Creates a new DMA buffer with a size only known at runtime. + /// ## Safety + /// * `T` must be properly aligned. + /// * `T` must be valid as zeroed (i.e. no NonNull pointers). + pub unsafe fn zeroed_unsized(count: usize) -> Result { + let phys = PhysBox::new(mem::size_of::() * count)?; + Ok(Self::from_physbox_zeroed_unsized(phys, count)?.assume_init()) + } +} +impl Dma<[MaybeUninit]> { + pub unsafe fn assume_init(self) -> Dma<[T]> { + let &Dma { phys: PhysBox { address, size }, virt } = &self; + mem::forget(self); + + Dma { + phys: PhysBox { address, size }, + virt: virt as *mut [T], + } + } +} + +impl Deref for Dma { + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.virt } + } +} + +impl DerefMut for Dma { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.virt } + } +} + +impl Drop for Dma { + fn drop(&mut self) { + unsafe { ptr::drop_in_place(self.virt) } + let _ = unsafe { crate::physunmap(self.virt as *mut u8 as usize) }; + } +} diff --git a/vendor/redox_syscall-0.2.16/src/io/io.rs b/vendor/redox_syscall-0.2.16/src/io/io.rs new file mode 100644 index 0000000000000..2c4acd3883f07 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/io/io.rs @@ -0,0 +1,71 @@ +use core::cmp::PartialEq; +use core::ops::{BitAnd, BitOr, Not}; + +pub trait Io { + type Value: Copy + PartialEq + BitAnd + BitOr + Not; + + fn read(&self) -> Self::Value; + fn write(&mut self, value: Self::Value); + + #[inline(always)] + fn readf(&self, flags: Self::Value) -> bool { + (self.read() & flags) as Self::Value == flags + } + + #[inline(always)] + fn writef(&mut self, flags: Self::Value, value: bool) { + let tmp: Self::Value = match value { + true => self.read() | flags, + false => self.read() & !flags, + }; + self.write(tmp); + } +} + +pub struct ReadOnly { + inner: I +} + +impl ReadOnly { + pub const fn new(inner: I) -> ReadOnly { + ReadOnly { + inner: inner + } + } +} + +impl ReadOnly { + #[inline(always)] + pub fn read(&self) -> I::Value { + self.inner.read() + } + + #[inline(always)] + pub fn readf(&self, flags: I::Value) -> bool { + self.inner.readf(flags) + } +} + +pub struct WriteOnly { + inner: I +} + +impl WriteOnly { + pub const fn new(inner: I) -> WriteOnly { + WriteOnly { + inner: inner + } + } +} + +impl WriteOnly { + #[inline(always)] + pub fn write(&mut self, value: I::Value) { + self.inner.write(value) + } + + #[inline(always)] + pub fn writef(&mut self, flags: I::Value, value: bool) { + self.inner.writef(flags, value) + } +} diff --git a/vendor/redox_syscall-0.2.16/src/io/mmio.rs b/vendor/redox_syscall-0.2.16/src/io/mmio.rs new file mode 100644 index 0000000000000..3966ab45467a1 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/io/mmio.rs @@ -0,0 +1,45 @@ +use core::ptr::{read_volatile, write_volatile, addr_of, addr_of_mut}; +use core::mem::MaybeUninit; +use core::ops::{BitAnd, BitOr, Not}; + +use super::io::Io; + +#[repr(packed)] +pub struct Mmio { + value: MaybeUninit, +} + +impl Mmio { + /// Create a new Mmio without initializing + #[deprecated = "unsound because it's possible to read even though it's uninitialized"] + pub fn new() -> Self { + unsafe { Self::uninit() } + } + pub unsafe fn zeroed() -> Self { + Self { + value: MaybeUninit::zeroed(), + } + } + pub unsafe fn uninit() -> Self { + Self { + value: MaybeUninit::uninit(), + } + } + pub const fn from(value: T) -> Self { + Self { + value: MaybeUninit::new(value), + } + } +} + +impl Io for Mmio where T: Copy + PartialEq + BitAnd + BitOr + Not { + type Value = T; + + fn read(&self) -> T { + unsafe { read_volatile(addr_of!(self.value).cast::()) } + } + + fn write(&mut self, value: T) { + unsafe { write_volatile(addr_of_mut!(self.value).cast::(), value) }; + } +} diff --git a/vendor/redox_syscall-0.2.16/src/io/mod.rs b/vendor/redox_syscall-0.2.16/src/io/mod.rs new file mode 100644 index 0000000000000..a225f0650b14e --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/io/mod.rs @@ -0,0 +1,15 @@ +//! I/O functions + +pub use self::dma::*; +pub use self::io::*; +pub use self::mmio::*; + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub use self::pio::*; + +mod dma; +mod io; +mod mmio; + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +mod pio; diff --git a/vendor/redox_syscall-0.2.16/src/io/pio.rs b/vendor/redox_syscall-0.2.16/src/io/pio.rs new file mode 100644 index 0000000000000..8b837bcdf1d80 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/io/pio.rs @@ -0,0 +1,90 @@ +use core::arch::asm; +use core::marker::PhantomData; + +use super::io::Io; + +/// Generic PIO +#[derive(Copy, Clone)] +pub struct Pio { + port: u16, + value: PhantomData, +} + +impl Pio { + /// Create a PIO from a given port + pub const fn new(port: u16) -> Self { + Pio:: { + port, + value: PhantomData, + } + } +} + +/// Read/Write for byte PIO +impl Io for Pio { + type Value = u8; + + /// Read + #[inline(always)] + fn read(&self) -> u8 { + let value: u8; + unsafe { + asm!("in al, dx", in("dx") self.port, out("al") value, options(nostack, nomem, preserves_flags)); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u8) { + unsafe { + asm!("out dx, al", in("dx") self.port, in("al") value, options(nostack, nomem, preserves_flags)); + } + } +} + +/// Read/Write for word PIO +impl Io for Pio { + type Value = u16; + + /// Read + #[inline(always)] + fn read(&self) -> u16 { + let value: u16; + unsafe { + asm!("in ax, dx", in("dx") self.port, out("ax") value, options(nostack, nomem, preserves_flags)); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u16) { + unsafe { + asm!("out dx, ax", in("dx") self.port, in("ax") value, options(nostack, nomem, preserves_flags)); + } + } +} + +/// Read/Write for doubleword PIO +impl Io for Pio { + type Value = u32; + + /// Read + #[inline(always)] + fn read(&self) -> u32 { + let value: u32; + unsafe { + asm!("in eax, dx", in("dx") self.port, out("eax") value, options(nostack, nomem, preserves_flags)); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u32) { + unsafe { + asm!("out dx, eax", in("dx") self.port, in("eax") value, options(nostack, nomem, preserves_flags)); + } + } +} diff --git a/vendor/redox_syscall-0.2.16/src/lib.rs b/vendor/redox_syscall-0.2.16/src/lib.rs new file mode 100644 index 0000000000000..9c59398302a3b --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/lib.rs @@ -0,0 +1,65 @@ +#![cfg_attr(not(test), no_std)] + +#[cfg(test)] +extern crate core; + +pub use self::arch::*; +pub use self::call::*; +pub use self::daemon::*; +pub use self::data::*; +pub use self::error::*; +pub use self::flag::*; +pub use self::io::*; +pub use self::number::*; +pub use self::scheme::*; + +#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "arm"))] +#[path="arch/nonredox.rs"] +mod arch; + +#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "aarch64"))] +#[path="arch/aarch64.rs"] +mod arch; + +#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "riscv64"))] +#[path="arch/riscv64.rs"] +mod arch; + +#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "x86"))] +#[path="arch/x86.rs"] +mod arch; + +#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "x86_64"))] +#[path="arch/x86_64.rs"] +mod arch; + +#[cfg(not(any(target_os = "none", target_os = "redox")))] +#[path="arch/nonredox.rs"] +mod arch; + +/// Function definitions +pub mod call; + +/// Complex structures that are used for some system calls +pub mod data; + +/// Wrapper to make daemons easier to write +pub mod daemon; + +/// All errors that can be generated by a system call +pub mod error; + +/// Flags used as an argument to many system calls +pub mod flag; + +/// Functions for low level hardware control +pub mod io; + +/// Call numbers used by each system call +pub mod number; + +/// A trait useful for scheme handlers +pub mod scheme; + +#[cfg(test)] +mod tests; diff --git a/vendor/redox_syscall-0.2.16/src/number.rs b/vendor/redox_syscall-0.2.16/src/number.rs new file mode 100644 index 0000000000000..1f037eb19bd80 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/number.rs @@ -0,0 +1,78 @@ +pub const SYS_CLASS: usize = 0xF000_0000; +pub const SYS_CLASS_PATH: usize=0x1000_0000; +pub const SYS_CLASS_FILE: usize=0x2000_0000; + +pub const SYS_ARG: usize = 0x0F00_0000; +pub const SYS_ARG_SLICE: usize =0x0100_0000; +pub const SYS_ARG_MSLICE: usize=0x0200_0000; +pub const SYS_ARG_PATH: usize = 0x0300_0000; + +pub const SYS_RET: usize = 0x00F0_0000; +pub const SYS_RET_FILE: usize = 0x0010_0000; + +pub const SYS_LINK: usize = SYS_CLASS_PATH | SYS_ARG_PATH | 9; +pub const SYS_OPEN: usize = SYS_CLASS_PATH | SYS_RET_FILE | 5; +pub const SYS_CHMOD: usize = SYS_CLASS_PATH | 15; +pub const SYS_RMDIR: usize = SYS_CLASS_PATH | 84; +pub const SYS_UNLINK: usize = SYS_CLASS_PATH | 10; + +pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6; +pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41; +pub const SYS_DUP2: usize = SYS_CLASS_FILE | SYS_RET_FILE | 63; +pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3; +pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4; +pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19; +pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94; +pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207; +pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55; +pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927; +pub const SYS_FEXEC: usize = SYS_CLASS_FILE | 11; +pub const SYS_FMAP_OLD: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 90; +pub const SYS_FMAP: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 900; +pub const SYS_FUNMAP_OLD: usize = SYS_CLASS_FILE | 91; +pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 92; +pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928; +pub const SYS_FRENAME: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 38; +pub const SYS_FSTAT: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 28; +pub const SYS_FSTATVFS: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 100; +pub const SYS_FSYNC: usize = SYS_CLASS_FILE | 118; +pub const SYS_FTRUNCATE: usize = SYS_CLASS_FILE | 93; +pub const SYS_FUTIMENS: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 320; + +pub const SYS_CHDIR: usize = 12; +pub const SYS_CLOCK_GETTIME: usize = 265; +pub const SYS_CLONE: usize = 120; +pub const SYS_EXIT: usize = 1; +pub const SYS_FUTEX: usize = 240; +pub const SYS_GETCWD: usize = 183; +pub const SYS_GETEGID: usize = 202; +pub const SYS_GETENS: usize = 951; +pub const SYS_GETEUID: usize = 201; +pub const SYS_GETGID: usize = 200; +pub const SYS_GETNS: usize = 950; +pub const SYS_GETPID: usize = 20; +pub const SYS_GETPGID: usize = 132; +pub const SYS_GETPPID: usize = 64; +pub const SYS_GETUID: usize = 199; +pub const SYS_IOPL: usize = 110; +pub const SYS_KILL: usize = 37; +pub const SYS_MPROTECT: usize = 125; +pub const SYS_MKNS: usize = 984; +pub const SYS_NANOSLEEP: usize =162; +pub const SYS_PHYSALLOC: usize =945; +pub const SYS_PHYSALLOC3: usize=9453; +pub const SYS_PHYSFREE: usize = 946; +pub const SYS_PHYSMAP: usize = 947; +pub const SYS_PHYSUNMAP: usize =948; +pub const SYS_VIRTTOPHYS: usize=949; +pub const SYS_PIPE2: usize = 331; +pub const SYS_SETPGID: usize = 57; +pub const SYS_SETREGID: usize = 204; +pub const SYS_SETRENS: usize = 952; +pub const SYS_SETREUID: usize = 203; +pub const SYS_SIGACTION: usize =67; +pub const SYS_SIGPROCMASK:usize=126; +pub const SYS_SIGRETURN: usize =119; +pub const SYS_UMASK: usize = 60; +pub const SYS_WAITPID: usize = 7; +pub const SYS_YIELD: usize = 158; diff --git a/vendor/redox_syscall-0.2.16/src/scheme/generate.sh b/vendor/redox_syscall-0.2.16/src/scheme/generate.sh new file mode 100755 index 0000000000000..a877cda921802 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/scheme/generate.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -e + +echo "Generating SchemeMut from Scheme" +sed 's/trait Scheme/trait SchemeMut/' scheme.rs \ +| sed 's/\&self/\&mut self/g' \ +> scheme_mut.rs + +echo "Generating SchemeBlock from Scheme" +sed 's/trait Scheme/trait SchemeBlock/' scheme.rs \ +| sed 's/fn handle(\&self, packet: \&mut Packet)/fn handle(\&self, packet: \&Packet) -> Option/' \ +| sed 's/packet.a = Error::mux(res);/res.transpose().map(Error::mux)/' \ +| sed 's/\.map(|f| f\.bits())/\.map(|f| f.map(|f| f.bits()))/' \ +| sed 's/\.map(|o| o as usize)/.map(|o| o.map(|o| o as usize))/' \ +| sed 's/Ok(0)/Ok(Some(0))/g' \ +| sed 's/Result<\([^>]\+\)>/Result>/g' \ +> scheme_block.rs + +echo "Generating SchemeBlockMut from SchemeBlock" +sed 's/trait SchemeBlock/trait SchemeBlockMut/' scheme_block.rs \ +| sed 's/\&self/\&mut self/g' \ +> scheme_block_mut.rs diff --git a/vendor/redox_syscall-0.2.16/src/scheme/mod.rs b/vendor/redox_syscall-0.2.16/src/scheme/mod.rs new file mode 100644 index 0000000000000..f65d1e2c06811 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/scheme/mod.rs @@ -0,0 +1,18 @@ +use core::{slice, str}; + +pub use self::scheme::Scheme; +pub use self::scheme_mut::SchemeMut; +pub use self::scheme_block::SchemeBlock; +pub use self::scheme_block_mut::SchemeBlockMut; +pub use self::seek::*; + +unsafe fn str_from_raw_parts(ptr: *const u8, len: usize) -> Option<&'static str> { + let slice = slice::from_raw_parts(ptr, len); + str::from_utf8(slice).ok() +} + +mod scheme; +mod scheme_mut; +mod scheme_block; +mod scheme_block_mut; +mod seek; diff --git a/vendor/redox_syscall-0.2.16/src/scheme/scheme.rs b/vendor/redox_syscall-0.2.16/src/scheme/scheme.rs new file mode 100644 index 0000000000000..249d28c6e2997 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/scheme/scheme.rs @@ -0,0 +1,211 @@ +use core::{mem, slice}; + +use crate::data::*; +use crate::error::*; +use crate::flag::*; +use crate::number::*; +use crate::scheme::str_from_raw_parts; + +pub trait Scheme { + fn handle(&self, packet: &mut Packet) { + let res = match packet.a { + SYS_OPEN => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.open(path, packet.d, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_CHMOD => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.chmod(path, packet.d as u16, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_RMDIR => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.rmdir(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_UNLINK => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.unlink(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + + SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o as usize), + SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), + SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), + SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.bits()), + SYS_FMAP_OLD => if packet.d >= mem::size_of::() { + self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FMAP => if packet.d >= mem::size_of::() { + self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FUNMAP_OLD => self.funmap_old(packet.b), + SYS_FUNMAP => self.funmap(packet.b, packet.c), + SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { + self.frename(packet.b, path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_FSTAT => if packet.d >= mem::size_of::() { + self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSTATVFS => if packet.d >= mem::size_of::() { + self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSYNC => self.fsync(packet.b), + SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), + SYS_FUTIMENS => if packet.d >= mem::size_of::() { + self.futimens(packet.b, unsafe { slice::from_raw_parts(packet.c as *const TimeSpec, packet.d / mem::size_of::()) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_CLOSE => self.close(packet.b), + _ => Err(Error::new(ENOSYS)) + }; + + packet.a = Error::mux(res); + } + + /* Scheme operations */ + + #[allow(unused_variables)] + fn open(&self, path: &str, flags: usize, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn chmod(&self, path: &str, mode: u16, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn rmdir(&self, path: &str, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn unlink(&self, path: &str, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + /* Resource operations */ + #[allow(unused_variables)] + fn dup(&self, old_id: usize, buf: &[u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn read(&self, id: usize, buf: &mut [u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn write(&self, id: usize, buf: &[u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn seek(&self, id: usize, pos: isize, whence: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchmod(&self, id: usize, mode: u16) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchown(&self, id: usize, uid: u32, gid: u32) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fevent(&self, id: usize, flags: EventFlags) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fmap_old(&self, id: usize, map: &OldMap) -> Result { + Err(Error::new(EBADF)) + } + #[allow(unused_variables)] + fn fmap(&self, id: usize, map: &Map) -> Result { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap_old(id, &OldMap { + offset: map.offset, + size: map.size, + flags: map.flags, + }) + } + + #[allow(unused_variables)] + fn funmap_old(&self, address: usize) -> Result { + Ok(0) + } + + #[allow(unused_variables)] + fn funmap(&self, address: usize, length: usize) -> Result { + Ok(0) + } + + #[allow(unused_variables)] + fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn frename(&self, id: usize, path: &str, uid: u32, gid: u32) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstat(&self, id: usize, stat: &mut Stat) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstatvfs(&self, id: usize, stat: &mut StatVfs) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fsync(&self, id: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn ftruncate(&self, id: usize, len: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn futimens(&self, id: usize, times: &[TimeSpec]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn close(&self, id: usize) -> Result { + Err(Error::new(EBADF)) + } +} diff --git a/vendor/redox_syscall-0.2.16/src/scheme/scheme_block.rs b/vendor/redox_syscall-0.2.16/src/scheme/scheme_block.rs new file mode 100644 index 0000000000000..e22535e0fd380 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/scheme/scheme_block.rs @@ -0,0 +1,211 @@ +use core::{mem, slice}; + +use crate::data::*; +use crate::error::*; +use crate::flag::*; +use crate::number::*; +use crate::scheme::str_from_raw_parts; + +pub trait SchemeBlock { + fn handle(&self, packet: &Packet) -> Option { + let res = match packet.a { + SYS_OPEN => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.open(path, packet.d, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_CHMOD => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.chmod(path, packet.d as u16, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_RMDIR => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.rmdir(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_UNLINK => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.unlink(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + + SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o.map(|o| o as usize)), + SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), + SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), + SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.map(|f| f.bits())), + SYS_FMAP_OLD => if packet.d >= mem::size_of::() { + self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FMAP => if packet.d >= mem::size_of::() { + self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FUNMAP_OLD => self.funmap_old(packet.b), + SYS_FUNMAP => self.funmap(packet.b, packet.c), + SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { + self.frename(packet.b, path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_FSTAT => if packet.d >= mem::size_of::() { + self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSTATVFS => if packet.d >= mem::size_of::() { + self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSYNC => self.fsync(packet.b), + SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), + SYS_FUTIMENS => if packet.d >= mem::size_of::() { + self.futimens(packet.b, unsafe { slice::from_raw_parts(packet.c as *const TimeSpec, packet.d / mem::size_of::()) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_CLOSE => self.close(packet.b), + _ => Err(Error::new(ENOSYS)) + }; + + res.transpose().map(Error::mux) + } + + /* Scheme operations */ + + #[allow(unused_variables)] + fn open(&self, path: &str, flags: usize, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn chmod(&self, path: &str, mode: u16, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn rmdir(&self, path: &str, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn unlink(&self, path: &str, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + /* Resource operations */ + #[allow(unused_variables)] + fn dup(&self, old_id: usize, buf: &[u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn read(&self, id: usize, buf: &mut [u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn write(&self, id: usize, buf: &[u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn seek(&self, id: usize, pos: isize, whence: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchmod(&self, id: usize, mode: u16) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchown(&self, id: usize, uid: u32, gid: u32) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fevent(&self, id: usize, flags: EventFlags) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fmap_old(&self, id: usize, map: &OldMap) -> Result> { + Err(Error::new(EBADF)) + } + #[allow(unused_variables)] + fn fmap(&self, id: usize, map: &Map) -> Result> { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap_old(id, &OldMap { + offset: map.offset, + size: map.size, + flags: map.flags, + }) + } + + #[allow(unused_variables)] + fn funmap_old(&self, address: usize) -> Result> { + Ok(Some(0)) + } + + #[allow(unused_variables)] + fn funmap(&self, address: usize, length: usize) -> Result> { + Ok(Some(0)) + } + + #[allow(unused_variables)] + fn fpath(&self, id: usize, buf: &mut [u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn frename(&self, id: usize, path: &str, uid: u32, gid: u32) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstat(&self, id: usize, stat: &mut Stat) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstatvfs(&self, id: usize, stat: &mut StatVfs) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fsync(&self, id: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn ftruncate(&self, id: usize, len: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn futimens(&self, id: usize, times: &[TimeSpec]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn close(&self, id: usize) -> Result> { + Err(Error::new(EBADF)) + } +} diff --git a/vendor/redox_syscall-0.2.16/src/scheme/scheme_block_mut.rs b/vendor/redox_syscall-0.2.16/src/scheme/scheme_block_mut.rs new file mode 100644 index 0000000000000..c1e54351a36a6 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/scheme/scheme_block_mut.rs @@ -0,0 +1,211 @@ +use core::{mem, slice}; + +use crate::data::*; +use crate::error::*; +use crate::flag::*; +use crate::number::*; +use crate::scheme::str_from_raw_parts; + +pub trait SchemeBlockMut { + fn handle(&mut self, packet: &Packet) -> Option { + let res = match packet.a { + SYS_OPEN => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.open(path, packet.d, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_CHMOD => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.chmod(path, packet.d as u16, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_RMDIR => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.rmdir(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_UNLINK => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.unlink(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + + SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o.map(|o| o as usize)), + SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), + SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), + SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.map(|f| f.bits())), + SYS_FMAP_OLD => if packet.d >= mem::size_of::() { + self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FMAP => if packet.d >= mem::size_of::() { + self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FUNMAP_OLD => self.funmap_old(packet.b), + SYS_FUNMAP => self.funmap(packet.b, packet.c), + SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { + self.frename(packet.b, path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_FSTAT => if packet.d >= mem::size_of::() { + self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSTATVFS => if packet.d >= mem::size_of::() { + self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSYNC => self.fsync(packet.b), + SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), + SYS_FUTIMENS => if packet.d >= mem::size_of::() { + self.futimens(packet.b, unsafe { slice::from_raw_parts(packet.c as *const TimeSpec, packet.d / mem::size_of::()) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_CLOSE => self.close(packet.b), + _ => Err(Error::new(ENOSYS)) + }; + + res.transpose().map(Error::mux) + } + + /* Scheme operations */ + + #[allow(unused_variables)] + fn open(&mut self, path: &str, flags: usize, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn chmod(&mut self, path: &str, mode: u16, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + /* Resource operations */ + #[allow(unused_variables)] + fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchmod(&mut self, id: usize, mode: u16) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fevent(&mut self, id: usize, flags: EventFlags) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fmap_old(&mut self, id: usize, map: &OldMap) -> Result> { + Err(Error::new(EBADF)) + } + #[allow(unused_variables)] + fn fmap(&mut self, id: usize, map: &Map) -> Result> { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap_old(id, &OldMap { + offset: map.offset, + size: map.size, + flags: map.flags, + }) + } + + #[allow(unused_variables)] + fn funmap_old(&mut self, address: usize) -> Result> { + Ok(Some(0)) + } + + #[allow(unused_variables)] + fn funmap(&mut self, address: usize, length: usize) -> Result> { + Ok(Some(0)) + } + + #[allow(unused_variables)] + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn frename(&mut self, id: usize, path: &str, uid: u32, gid: u32) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fsync(&mut self, id: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn ftruncate(&mut self, id: usize, len: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn futimens(&mut self, id: usize, times: &[TimeSpec]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn close(&mut self, id: usize) -> Result> { + Err(Error::new(EBADF)) + } +} diff --git a/vendor/redox_syscall-0.2.16/src/scheme/scheme_mut.rs b/vendor/redox_syscall-0.2.16/src/scheme/scheme_mut.rs new file mode 100644 index 0000000000000..deb1483664e00 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/scheme/scheme_mut.rs @@ -0,0 +1,211 @@ +use core::{mem, slice}; + +use crate::data::*; +use crate::error::*; +use crate::flag::*; +use crate::number::*; +use crate::scheme::str_from_raw_parts; + +pub trait SchemeMut { + fn handle(&mut self, packet: &mut Packet) { + let res = match packet.a { + SYS_OPEN => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.open(path, packet.d, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_CHMOD => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.chmod(path, packet.d as u16, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_RMDIR => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.rmdir(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_UNLINK => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.unlink(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + + SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o as usize), + SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), + SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), + SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.bits()), + SYS_FMAP_OLD => if packet.d >= mem::size_of::() { + self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FMAP => if packet.d >= mem::size_of::() { + self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FUNMAP_OLD => self.funmap_old(packet.b), + SYS_FUNMAP => self.funmap(packet.b, packet.c), + SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { + self.frename(packet.b, path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_FSTAT => if packet.d >= mem::size_of::() { + self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSTATVFS => if packet.d >= mem::size_of::() { + self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSYNC => self.fsync(packet.b), + SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), + SYS_FUTIMENS => if packet.d >= mem::size_of::() { + self.futimens(packet.b, unsafe { slice::from_raw_parts(packet.c as *const TimeSpec, packet.d / mem::size_of::()) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_CLOSE => self.close(packet.b), + _ => Err(Error::new(ENOSYS)) + }; + + packet.a = Error::mux(res); + } + + /* Scheme operations */ + + #[allow(unused_variables)] + fn open(&mut self, path: &str, flags: usize, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn chmod(&mut self, path: &str, mode: u16, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + /* Resource operations */ + #[allow(unused_variables)] + fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn write(&mut self, id: usize, buf: &[u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchmod(&mut self, id: usize, mode: u16) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fevent(&mut self, id: usize, flags: EventFlags) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fmap_old(&mut self, id: usize, map: &OldMap) -> Result { + Err(Error::new(EBADF)) + } + #[allow(unused_variables)] + fn fmap(&mut self, id: usize, map: &Map) -> Result { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap_old(id, &OldMap { + offset: map.offset, + size: map.size, + flags: map.flags, + }) + } + + #[allow(unused_variables)] + fn funmap_old(&mut self, address: usize) -> Result { + Ok(0) + } + + #[allow(unused_variables)] + fn funmap(&mut self, address: usize, length: usize) -> Result { + Ok(0) + } + + #[allow(unused_variables)] + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn frename(&mut self, id: usize, path: &str, uid: u32, gid: u32) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fsync(&mut self, id: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn ftruncate(&mut self, id: usize, len: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn futimens(&mut self, id: usize, times: &[TimeSpec]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn close(&mut self, id: usize) -> Result { + Err(Error::new(EBADF)) + } +} diff --git a/vendor/redox_syscall-0.2.16/src/scheme/seek.rs b/vendor/redox_syscall-0.2.16/src/scheme/seek.rs new file mode 100644 index 0000000000000..09a45186ac6c8 --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/scheme/seek.rs @@ -0,0 +1,33 @@ +use core::cmp; +use core::convert::TryFrom; +use crate::error::*; +use crate::flag::*; + +/// Helper for seek calls +/// In most cases it's easier to use a usize to track the offset and buffer size internally, +/// but the seek interface uses isize. This wrapper ensures EOVERFLOW errors are returned +/// as appropriate if the value in the usize can't fit in the isize. +pub fn calc_seek_offset_usize(cur_offset: usize, pos: isize, whence: usize, buf_len: usize) -> Result { + let cur_offset = isize::try_from(cur_offset).or_else(|_| Err(Error::new(EOVERFLOW)))?; + let buf_len = isize::try_from(buf_len).or_else(|_| Err(Error::new(EOVERFLOW)))?; + calc_seek_offset_isize(cur_offset, pos, whence, buf_len) +} + +/// Helper for seek calls +/// Result is guaranteed to be positive. +/// EOVERFLOW returned if the arguments would cause an overflow. +/// EINVAL returned if the new offset is out of bounds. +pub fn calc_seek_offset_isize(cur_offset: isize, pos: isize, whence: usize, buf_len: isize) -> Result { + let new_offset = match whence { + SEEK_CUR => pos.checked_add(cur_offset), + SEEK_END => pos.checked_add(buf_len), + SEEK_SET => Some(pos), + _ => None, + }; + + match new_offset { + Some(new_offset) if new_offset < 0 => Err(Error::new(EINVAL)), + Some(new_offset) => Ok(cmp::min(new_offset, buf_len)), + None => Err(Error::new(EOVERFLOW)) + } +} \ No newline at end of file diff --git a/vendor/redox_syscall-0.2.16/src/tests.rs b/vendor/redox_syscall-0.2.16/src/tests.rs new file mode 100644 index 0000000000000..c5e1f8df0778c --- /dev/null +++ b/vendor/redox_syscall-0.2.16/src/tests.rs @@ -0,0 +1,470 @@ +#[test] +fn chdir() { + use std::str; + + let mut current_buf = [0; 4096]; + let current_count = dbg!(crate::getcwd(&mut current_buf)).unwrap(); + let current = dbg!(str::from_utf8(¤t_buf[..current_count])).unwrap(); + + let new = "file:"; + assert_eq!(dbg!(crate::chdir(dbg!(new))), Ok(0)); + { + let mut buf = [0; 4096]; + let count = dbg!(crate::getcwd(&mut buf)).unwrap(); + assert_eq!(dbg!(str::from_utf8(&buf[..count])), Ok(new)); + } + + assert_eq!(dbg!(crate::chdir(current)), Ok(0)); + { + let mut buf = [0; 4096]; + let count = dbg!(crate::getcwd(&mut buf)).unwrap(); + assert_eq!(dbg!(str::from_utf8(&buf[..count])), Ok(current)); + } +} + +//TODO: chmod + +#[test] +fn clone() { + let expected_status = 42; + let pid_res = unsafe { crate::clone(crate::CloneFlags::empty()) }; + if pid_res == Ok(0) { + crate::exit(expected_status).unwrap(); + panic!("failed to exit"); + } else { + let pid = dbg!(pid_res).unwrap(); + let mut status = 0; + assert_eq!(dbg!(crate::waitpid(pid, &mut status, crate::WaitFlags::empty())), Ok(pid)); + assert_eq!(dbg!(crate::wifexited(status)), true); + assert_eq!(dbg!(crate::wexitstatus(status)), expected_status); + } +} + +//TODO: close + +#[test] +fn clock_gettime() { + let mut tp = crate::TimeSpec::default(); + assert_eq!(dbg!( + crate::clock_gettime(crate::CLOCK_MONOTONIC, &mut tp) + ), Ok(0)); + assert_ne!(dbg!(tp), crate::TimeSpec::default()); + + tp = crate::TimeSpec::default(); + assert_eq!(dbg!( + crate::clock_gettime(crate::CLOCK_REALTIME, &mut tp) + ), Ok(0)); + assert_ne!(dbg!(tp), crate::TimeSpec::default()); +} + +//TODO: dup + +//TODO: dup2 + +//TODO: exit (handled by clone?) + +//TODO: fchmod + +//TODO: fcntl + +#[test] +fn fexec() { + let name = "file:/bin/ls"; + + let fd = dbg!( + crate::open(name, crate::O_RDONLY | crate::O_CLOEXEC) + ).unwrap(); + + let args = &[ + [name.as_ptr() as usize, name.len()] + ]; + + let vars = &[]; + + let pid_res = unsafe { crate::clone(crate::CloneFlags::empty()) }; + if pid_res == Ok(0) { + crate::fexec(fd, args, vars).unwrap(); + panic!("failed to fexec"); + } else { + assert_eq!(dbg!(crate::close(fd)), Ok(0)); + + let pid = dbg!(pid_res).unwrap(); + let mut status = 0; + assert_eq!(dbg!(crate::waitpid(pid, &mut status, crate::WaitFlags::empty())), Ok(pid)); + assert_eq!(dbg!(crate::wifexited(status)), true); + assert_eq!(dbg!(crate::wexitstatus(status)), 0); + } +} + +#[test] +fn fmap() { + use std::slice; + + let fd = dbg!( + crate::open( + "file:/tmp/syscall-tests-fmap", + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + let size = 128; + + let map = unsafe { + slice::from_raw_parts_mut( + dbg!( + crate::fmap(fd, &crate::Map { + address: 0, + offset: 0, + size, + flags: crate::PROT_READ | crate::PROT_WRITE + }) + ).unwrap() as *mut u8, + 128 + ) + }; + + // Maps should be available after closing + assert_eq!(dbg!(crate::close(fd)), Ok(0)); + + for i in 0..128 { + map[i as usize] = i; + assert_eq!(map[i as usize], i); + } + + //TODO: add msync + unsafe { + assert_eq!(dbg!( + crate::funmap(map.as_mut_ptr() as usize, size) + ), Ok(0)); + } +} + +// funmap tested by fmap + +#[test] +fn fpath() { + use std::str; + + let path = "file:/tmp/syscall-tests-fpath"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + let mut buf = [0; 4096]; + let count = dbg!( + crate::fpath(fd, &mut buf) + ).unwrap(); + + assert_eq!(dbg!(str::from_utf8(&buf[..count])), Ok(path)); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); +} + +//TODO: frename + +#[test] +fn fstat() { + let path = "file:/tmp/syscall-tests-fstat"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + let mut stat = crate::Stat::default(); + assert_eq!(dbg!(crate::fstat(fd, &mut stat)), Ok(0)); + assert_ne!(dbg!(stat), crate::Stat::default()); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); +} + +#[test] +fn fstatvfs() { + let path = "file:/tmp/syscall-tests-fstatvfs"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + let mut statvfs = crate::StatVfs::default(); + assert_eq!(dbg!(crate::fstatvfs(fd, &mut statvfs)), Ok(0)); + assert_ne!(dbg!(statvfs), crate::StatVfs::default()); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); +} + +//TODO: fsync + +//TODO: ftruncate + +//TODO: futimens + +//TODO: futex + +// getcwd tested by chdir + +#[test] +fn getegid() { + assert_eq!(crate::getegid(), Ok(0)); +} + +#[test] +fn getens() { + assert_eq!(crate::getens(), Ok(1)); +} + +#[test] +fn geteuid() { + assert_eq!(crate::geteuid(), Ok(0)); +} + +#[test] +fn getgid() { + assert_eq!(crate::getgid(), Ok(0)); +} + +#[test] +fn getns() { + assert_eq!(crate::getns(), Ok(1)); +} + +//TODO: getpid + +//TODO: getpgid + +//TODO: getppid + +#[test] +fn getuid() { + assert_eq!(crate::getuid(), Ok(0)); +} + +//TODO: iopl + +//TODO: kill + +//TODO: link (probably will not work) + +#[test] +fn lseek() { + let path = "file:/tmp/syscall-tests-lseek"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + { + let mut buf = [0; 256]; + for i in 0..buf.len() { + buf[i] = i as u8; + } + assert_eq!(dbg!(crate::write(fd, &buf)), Ok(buf.len())); + + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_CUR)), Ok(buf.len())); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0)); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_END)), Ok(buf.len())); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0)); + } + + { + let mut buf = [0; 256]; + assert_eq!(dbg!(crate::read(fd, &mut buf)), Ok(buf.len())); + for i in 0..buf.len() { + assert_eq!(buf[i], i as u8); + } + + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_CUR)), Ok(buf.len())); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0)); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_END)), Ok(buf.len())); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0)); + } + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); +} + +//TODO: mkns + +//TODO: mprotect + +#[test] +fn nanosleep() { + let req = crate::TimeSpec { + tv_sec: 0, + tv_nsec: 0, + }; + let mut rem = crate::TimeSpec::default(); + assert_eq!(crate::nanosleep(&req, &mut rem), Ok(0)); + assert_eq!(rem, crate::TimeSpec::default()); +} + +//TODO: open + +//TODO: physalloc + +//TODO: physfree + +//TODO: physmap + +//TODO: physunmap + +#[test] +fn pipe2() { + let mut fds = [0, 0]; + assert_eq!(dbg!(crate::pipe2(&mut fds, crate::O_CLOEXEC)), Ok(0)); + assert_ne!(dbg!(fds), [0, 0]); + + { + let mut buf = [0; 256]; + for i in 0..buf.len() { + buf[i] = i as u8; + } + assert_eq!(dbg!(crate::write(fds[1], &buf)), Ok(buf.len())); + } + + { + let mut buf = [0; 256]; + assert_eq!(dbg!(crate::read(fds[0], &mut buf)), Ok(buf.len())); + for i in 0..buf.len() { + assert_eq!(buf[i], i as u8); + } + } + + assert_eq!(dbg!(crate::close(fds[0])), Ok(0)); + assert_eq!(dbg!(crate::close(fds[1])), Ok(0)); +} + +//TODO: read + +#[test] +fn rmdir() { + let path = "file:/tmp/syscall-tests-rmdir"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_DIRECTORY | crate::O_CLOEXEC + ) + ).unwrap(); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); + + assert_eq!(dbg!(crate::rmdir(path)), Ok(0)); +} + +//TODO: setpgid + +//TODO: setregid + +//TODO: setrens + +//TODO: setreuid + +//TODO: sigaction + +//TODO: sigprocmask + +//TODO: sigreturn + +#[test] +fn umask() { + let old = dbg!(crate::umask(0o244)).unwrap(); + assert_eq!(dbg!(crate::umask(old)), Ok(0o244)); +} + +#[test] +fn unlink() { + let path = "file:/tmp/syscall-tests-unlink"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); + + assert_eq!(dbg!(crate::unlink(path)), Ok(0)); +} + +//TODO: virttophys + +// waitpid tested by clone + +//TODO: write + +#[test] +fn sched_yield() { + assert_eq!(dbg!(crate::sched_yield()), Ok(0)); +} + +#[test] +fn sigaction() { + use std::{ + mem, + sync::atomic::{AtomicBool, Ordering} + }; + + static SA_HANDLER_WAS_RAN: AtomicBool = AtomicBool::new(false); + static SA_HANDLER_2_WAS_IGNORED: AtomicBool = AtomicBool::new(false); + + let child = unsafe { crate::clone(crate::CLONE_VM).unwrap() }; + + if child == 0 { + let pid = crate::getpid().unwrap(); + + extern "C" fn hello_im_a_signal_handler(signal: usize) { + assert_eq!(signal, crate::SIGUSR1); + SA_HANDLER_WAS_RAN.store(true, Ordering::SeqCst); + } + + let my_signal_handler = crate::SigAction { + sa_handler: Some(hello_im_a_signal_handler), + ..Default::default() + }; + crate::sigaction(crate::SIGUSR1, Some(&my_signal_handler), None).unwrap(); + + crate::kill(pid, crate::SIGUSR1).unwrap(); // calls handler + + let mut old_signal_handler = crate::SigAction::default(); + crate::sigaction( + crate::SIGUSR1, + Some(&crate::SigAction { + sa_handler: unsafe { mem::transmute::>(crate::SIG_IGN) }, + ..Default::default() + }), + Some(&mut old_signal_handler) + ).unwrap(); + assert_eq!(my_signal_handler, old_signal_handler); + + crate::kill(pid, crate::SIGUSR1).unwrap(); // does nothing + + SA_HANDLER_2_WAS_IGNORED.store(true, Ordering::SeqCst); + + crate::sigaction( + crate::SIGUSR1, + Some(&crate::SigAction { + sa_handler: unsafe { mem::transmute::>(crate::SIG_DFL) }, + ..Default::default() + }), + Some(&mut old_signal_handler) + ).unwrap(); + + crate::kill(pid, crate::SIGUSR1).unwrap(); // actually exits + } else { + let mut status = 0; + dbg!(crate::waitpid(child, &mut status, crate::WaitFlags::empty())).unwrap(); + + assert!(crate::wifsignaled(status)); + assert_eq!(crate::wtermsig(status), crate::SIGUSR1); + + assert!(SA_HANDLER_WAS_RAN.load(Ordering::SeqCst)); + assert!(SA_HANDLER_2_WAS_IGNORED.load(Ordering::SeqCst)); + } +} diff --git a/vendor/redox_syscall-0.3.5/.cargo-checksum.json b/vendor/redox_syscall-0.3.5/.cargo-checksum.json new file mode 100644 index 0000000000000..72e27feeba203 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"80db3d7e545f9b8a04804e634948c6e80c712f051680b2e7a39ddb848c200151","LICENSE":"efcfee7981ff72431fffb06925cad00a23dce079ed4354f61030ad5abdb78829","README.md":"9161f18ba7f69b4ca51e844aee8ffb8237513a468c5c3b1f3a5f989044f895ac","src/arch/aarch64.rs":"9b4cf7da1f001ce54bfd01b7a001dbc8043c1ef89823781a2a1070e2c096a9ce","src/arch/nonredox.rs":"1055cd441f4b95c9ec428222a7796c7fac953a8a500ca08173743ea95220aab3","src/arch/riscv64.rs":"20bf9a8db779059773b113643d0cb3737fbb5d57f45ee39b8ae9d3396b6ef636","src/arch/x86.rs":"cf01f4d798e8861ad5b9429714c947e2d7c53a3cb9a13d53dc7a38e4bdad4101","src/arch/x86_64.rs":"fd80c9a412d07c85f2b942f36de364edfff7cd49f6c00c043e69becb7c76119f","src/call.rs":"141bdb2cb64dc118beadf40fc8180cd32e41841c8d7db71aed646a5a8ab9fac3","src/data.rs":"bd4545d4c2fcc59ff26ae52ad7f773a697d5ccf639a2ffc253cece6b31e94d51","src/error.rs":"ef20f3817f997a1aeb7114628407f19cb8bc13c555d4e093918f38a5d098f798","src/flag.rs":"aad91126a0bb3413cd103fc38b457aa4d1f6b949605e3ae249aea0dfec8504ff","src/io/dma.rs":"85577342547afaac0dc46740dfeb9d2e4239d8809b86748c3fcaa12f922b1c9d","src/io/io.rs":"e1d454ff47efac70fdaa709251a5a9c1c5637f931994ba3bf6a38c6db9145822","src/io/mmio.rs":"12d0fb4d4f45097bf2c14f73cb1ce21325eae193b537e9f18af73ed5281b5e63","src/io/mod.rs":"79c2fce4fd6d75f3b9169df64b7a605feff31fab2e5ed81984ae085a1d07c0c4","src/io/pio.rs":"9ee6f2229b700d1c45b4c8c6242bd99fe69634e16dcd5843d9e8d1c958047406","src/lib.rs":"25c9f35cf709e7e50336ae12f0390f968cc11515f93b6d757825a7b7725eeadb","src/number.rs":"773d9f55a98c6ae5b4cb08b396568f05f8d9b187a7609b7a1c5dd940f6ee674a","src/scheme/generate.sh":"dde4e30f4e0223fb1a24ed486a6c36e624c854dbf890862cb6866f4fa3c7a6eb","src/scheme/mod.rs":"cb622405deb0aef4ab04499ea1adfd338c9c5dd9c31a1fe9989786dbf69b49d8","src/scheme/scheme.rs":"2e27e08e3b9005a5705fadd10a6160a570322c873d1b6477f269e0beae35f046","src/scheme/scheme_block.rs":"a8d0137e106dcb605367bfc6a22b83317142996b7e410c832de0f63a423d5305","src/scheme/scheme_block_mut.rs":"b6cea44a3e79dd6c30b4280b6913a215628918978451efe11f31b0d7eddd44a5","src/scheme/scheme_mut.rs":"e77da9d5208de101c126eca9fa685f2b78a5ddc4890ad5f5f4d79ded3bbd8fbd","src/scheme/seek.rs":"94e044de47b0f00eb0c2aea3fb21001ac2b9aa1e4b20d73fd54163fe92fa63f7","src/tests.rs":"b44de69251d6bcc1cb796147a1212fffd3ac7d5796d9a0d2265db0aac8a909df"},"package":"567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"} \ No newline at end of file diff --git a/vendor/redox_syscall-0.3.5/Cargo.toml b/vendor/redox_syscall-0.3.5/Cargo.toml new file mode 100644 index 0000000000000..ab14e3fe896b2 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/Cargo.toml @@ -0,0 +1,38 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "redox_syscall" +version = "0.3.5" +authors = ["Jeremy Soller "] +description = "A Rust library to access raw Redox system calls" +documentation = "https://docs.rs/redox_syscall" +readme = "README.md" +license = "MIT" +repository = "https://gitlab.redox-os.org/redox-os/syscall" + +[lib] +name = "syscall" + +[dependencies.bitflags] +version = "1.1.0" + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" + +[features] +rustc-dep-of-std = [ + "core", + "bitflags/rustc-dep-of-std", +] diff --git a/vendor/redox_syscall-0.3.5/LICENSE b/vendor/redox_syscall-0.3.5/LICENSE new file mode 100644 index 0000000000000..1292bb7fbdd1c --- /dev/null +++ b/vendor/redox_syscall-0.3.5/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2017 Redox OS Developers + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/redox_syscall-0.3.5/README.md b/vendor/redox_syscall-0.3.5/README.md new file mode 100644 index 0000000000000..244c90861a834 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/README.md @@ -0,0 +1,6 @@ +# syscall +[Redox OS](https://gitlab.redox-os.org/redox-os/redox)'s syscall API + +[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) +[![crates.io](http://meritbadge.herokuapp.com/redox_syscall)](https://crates.io/crates/redox_syscall) +[![docs.rs](https://docs.rs/redox_syscall/badge.svg)](https://docs.rs/redox_syscall) diff --git a/vendor/redox_syscall-0.3.5/src/arch/aarch64.rs b/vendor/redox_syscall-0.3.5/src/arch/aarch64.rs new file mode 100644 index 0000000000000..e792427cff6d3 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/arch/aarch64.rs @@ -0,0 +1,150 @@ +use core::{mem, slice}; +use core::ops::{Deref, DerefMut}; + +use super::error::{Error, Result}; + +pub const PAGE_SIZE: usize = 4096; + +macro_rules! syscall { + ($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => { + $( + pub unsafe fn $name($a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result { + let ret: usize; + + core::arch::asm!( + "svc 0", + in("x8") $a, + $( + in("x0") $b, + $( + in("x1") $c, + $( + in("x2") $d, + $( + in("x3") $e, + $( + in("x4") $f, + )? + )? + )? + )? + )? + lateout("x0") ret, + options(nostack), + ); + + Error::demux(ret) + } + )+ + }; +} + +syscall! { + syscall0(a,); + syscall1(a, b,); + syscall2(a, b, c,); + syscall3(a, b, c, d,); + syscall4(a, b, c, d, e,); + syscall5(a, b, c, d, e, f,); +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct IntRegisters { + pub x30: usize, + pub x29: usize, + pub x28: usize, + pub x27: usize, + pub x26: usize, + pub x25: usize, + pub x24: usize, + pub x23: usize, + pub x22: usize, + pub x21: usize, + pub x20: usize, + pub x19: usize, + pub x18: usize, + pub x17: usize, + pub x16: usize, + pub x15: usize, + pub x14: usize, + pub x13: usize, + pub x12: usize, + pub x11: usize, + pub x10: usize, + pub x9: usize, + pub x8: usize, + pub x7: usize, + pub x6: usize, + pub x5: usize, + pub x4: usize, + pub x3: usize, + pub x2: usize, + pub x1: usize, + pub x0: usize +} + +impl Deref for IntRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const IntRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for IntRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut IntRegisters as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(packed)] +pub struct FloatRegisters { + pub fp_simd_regs: [u128; 32], + pub fpsr: u32, + pub fpcr: u32 +} + +impl Deref for FloatRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const FloatRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for FloatRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut FloatRegisters as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(packed)] +pub struct EnvRegisters { + pub tpidr_el0: usize, + pub tpidrro_el0: usize, +} +impl Deref for EnvRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const EnvRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for EnvRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut EnvRegisters as *mut u8, mem::size_of::()) + } + } +} diff --git a/vendor/redox_syscall-0.3.5/src/arch/nonredox.rs b/vendor/redox_syscall-0.3.5/src/arch/nonredox.rs new file mode 100644 index 0000000000000..65c44fcd80f48 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/arch/nonredox.rs @@ -0,0 +1,29 @@ +use super::error::{Error, Result, ENOSYS}; + +// Doesn't really matter, but since we will most likely run on an x86_64 host, why not 4096? +pub const PAGE_SIZE: usize = 4096; + +pub unsafe fn syscall0(_a: usize) -> Result { + Err(Error::new(ENOSYS)) +} + +pub unsafe fn syscall1(_a: usize, _b: usize) -> Result { + Err(Error::new(ENOSYS)) +} + +pub unsafe fn syscall2(_a: usize, _b: usize, _c: usize) -> Result { + Err(Error::new(ENOSYS)) +} + +pub unsafe fn syscall3(_a: usize, _b: usize, _c: usize, _d: usize) -> Result { + Err(Error::new(ENOSYS)) +} + +pub unsafe fn syscall4(_a: usize, _b: usize, _c: usize, _d: usize, _e: usize) -> Result { + Err(Error::new(ENOSYS)) +} + +pub unsafe fn syscall5(_a: usize, _b: usize, _c: usize, _d: usize, _e: usize, _f: usize) + -> Result { + Err(Error::new(ENOSYS)) +} diff --git a/vendor/redox_syscall-0.3.5/src/arch/riscv64.rs b/vendor/redox_syscall-0.3.5/src/arch/riscv64.rs new file mode 100644 index 0000000000000..2a90260da4e7c --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/arch/riscv64.rs @@ -0,0 +1,93 @@ +use core::{mem, slice}; +use core::ops::{Deref, DerefMut}; + +use super::error::{Error, Result}; + +macro_rules! syscall { + ($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => { + $( + pub unsafe fn $name($a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result { + let ret: usize; + + asm!( + "ecall", + in("a7") $a, + $( + in("a0") $b, + $( + in("a1") $c, + $( + in("a2") $d, + $( + in("a3") $e, + $( + in("a4") $f, + )? + )? + )? + )? + )? + lateout("a0") ret, + options(nostack), + ); + + Error::demux(ret) + } + )+ + }; +} + +syscall! { + syscall0(a,); + syscall1(a, b,); + syscall2(a, b, c,); + syscall3(a, b, c, d,); + syscall4(a, b, c, d, e,); + syscall5(a, b, c, d, e, f,); +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct IntRegisters { + //TODO +} + +impl Deref for IntRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const IntRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for IntRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut IntRegisters as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(packed)] +pub struct FloatRegisters { + //TODO +} + +impl Deref for FloatRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const FloatRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for FloatRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut FloatRegisters as *mut u8, mem::size_of::()) + } + } +} diff --git a/vendor/redox_syscall-0.3.5/src/arch/x86.rs b/vendor/redox_syscall-0.3.5/src/arch/x86.rs new file mode 100644 index 0000000000000..54d8c0a93ee69 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/arch/x86.rs @@ -0,0 +1,184 @@ +use core::{mem, slice}; +use core::arch::asm; +use core::ops::{Deref, DerefMut}; + +use super::error::{Error, Result}; + +pub const PAGE_SIZE: usize = 4096; + +macro_rules! syscall { + ($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => { + $( + pub unsafe fn $name(mut $a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result { + asm!( + "int 0x80", + inout("eax") $a, + $( + in("ebx") $b, + $( + in("ecx") $c, + $( + in("edx") $d, + $( + in("esi") $e, + $( + in("edi") $f, + )? + )? + )? + )? + )? + options(nostack), + ); + + Error::demux($a) + } + )+ + }; +} + +syscall! { + syscall0(a,); + syscall1(a, b,); + syscall2(a, b, c,); + syscall3(a, b, c, d,); + // Must be done custom because LLVM reserves ESI + //syscall4(a, b, c, d, e,); + //syscall5(a, b, c, d, e, f,); +} + +pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) + -> Result { + asm!( + "xchg esi, {e} + int 0x80 + xchg esi, {e}", + e = in(reg) e, + inout("eax") a, + in("ebx") b, + in("ecx") c, + in("edx") d, + options(nostack), + ); + + Error::demux(a) +} + +pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) + -> Result { + asm!( + "xchg esi, {e} + int 0x80 + xchg esi, {e}", + e = in(reg) e, + inout("eax") a, + in("ebx") b, + in("ecx") c, + in("edx") d, + in("edi") f, + options(nostack), + ); + + Error::demux(a) +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct IntRegisters { + // TODO: Some of these don't get set by Redox yet. Should they? + + pub ebp: usize, + pub esi: usize, + pub edi: usize, + pub ebx: usize, + pub eax: usize, + pub ecx: usize, + pub edx: usize, + // pub orig_rax: usize, + pub eip: usize, + pub cs: usize, + pub eflags: usize, + pub esp: usize, + pub ss: usize, + // pub fs_base: usize, + // pub gs_base: usize, + // pub ds: usize, + // pub es: usize, + pub fs: usize, + // pub gs: usize +} + +impl Deref for IntRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const IntRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for IntRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut IntRegisters as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(packed)] +pub struct FloatRegisters { + pub fcw: u16, + pub fsw: u16, + pub ftw: u8, + pub _reserved: u8, + pub fop: u16, + pub fip: u64, + pub fdp: u64, + pub mxcsr: u32, + pub mxcsr_mask: u32, + pub st_space: [u128; 8], + pub xmm_space: [u128; 16], + // TODO: YMM/ZMM +} + +impl Deref for FloatRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const FloatRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for FloatRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut FloatRegisters as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(packed)] +pub struct EnvRegisters { + pub fsbase: u32, + pub gsbase: u32, +} + +impl Deref for EnvRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const EnvRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for EnvRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut EnvRegisters as *mut u8, mem::size_of::()) + } + } +} diff --git a/vendor/redox_syscall-0.3.5/src/arch/x86_64.rs b/vendor/redox_syscall-0.3.5/src/arch/x86_64.rs new file mode 100644 index 0000000000000..2ff57bb2d8202 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/arch/x86_64.rs @@ -0,0 +1,157 @@ +use core::{mem, slice}; +use core::arch::asm; +use core::ops::{Deref, DerefMut}; + +use super::error::{Error, Result}; + +pub const PAGE_SIZE: usize = 4096; + +macro_rules! syscall { + ($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => { + $( + pub unsafe fn $name(mut $a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result { + asm!( + "syscall", + inout("rax") $a, + $( + in("rdi") $b, + $( + in("rsi") $c, + $( + in("rdx") $d, + $( + in("r10") $e, + $( + in("r8") $f, + )? + )? + )? + )? + )? + out("rcx") _, + out("r11") _, + options(nostack), + ); + + Error::demux($a) + } + )+ + }; +} + +syscall! { + syscall0(a,); + syscall1(a, b,); + syscall2(a, b, c,); + syscall3(a, b, c, d,); + syscall4(a, b, c, d, e,); + syscall5(a, b, c, d, e, f,); +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct IntRegisters { + // TODO: Some of these don't get set by Redox yet. Should they? + + pub r15: usize, + pub r14: usize, + pub r13: usize, + pub r12: usize, + pub rbp: usize, + pub rbx: usize, + pub r11: usize, + pub r10: usize, + pub r9: usize, + pub r8: usize, + pub rax: usize, + pub rcx: usize, + pub rdx: usize, + pub rsi: usize, + pub rdi: usize, + // pub orig_rax: usize, + pub rip: usize, + pub cs: usize, + pub rflags: usize, + pub rsp: usize, + pub ss: usize, + // pub fs_base: usize, + // pub gs_base: usize, + // pub ds: usize, + // pub es: usize, + pub fs: usize, + // pub gs: usize +} + +impl Deref for IntRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const IntRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for IntRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut IntRegisters as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(packed)] +pub struct FloatRegisters { + pub fcw: u16, + pub fsw: u16, + pub ftw: u8, + pub _reserved: u8, + pub fop: u16, + pub fip: u64, + pub fdp: u64, + pub mxcsr: u32, + pub mxcsr_mask: u32, + pub st_space: [u128; 8], + pub xmm_space: [u128; 16], + // TODO: YMM/ZMM +} + +impl Deref for FloatRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const FloatRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for FloatRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut FloatRegisters as *mut u8, mem::size_of::()) + } + } +} +#[derive(Clone, Copy, Debug, Default)] +#[repr(packed)] +pub struct EnvRegisters { + pub fsbase: u64, + pub gsbase: u64, + // TODO: PKRU? +} +impl Deref for EnvRegisters { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const EnvRegisters as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for EnvRegisters { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut EnvRegisters as *mut u8, mem::size_of::()) + } + } +} diff --git a/vendor/redox_syscall-0.3.5/src/call.rs b/vendor/redox_syscall-0.3.5/src/call.rs new file mode 100644 index 0000000000000..bc1af0dc20de1 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/call.rs @@ -0,0 +1,379 @@ +use super::arch::*; +use super::data::{Map, SigAction, Stat, StatVfs, TimeSpec}; +use super::error::Result; +use super::flag::*; +use super::number::*; + +use core::{mem, ptr}; + +// Signal restorer +extern "C" fn restorer() -> ! { + sigreturn().unwrap(); + unreachable!(); +} + +/// Close a file +pub fn close(fd: usize) -> Result { + unsafe { syscall1(SYS_CLOSE, fd) } +} + +/// Get the current system time +pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result { + unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) } +} + +/// Copy and transform a file descriptor +pub fn dup(fd: usize, buf: &[u8]) -> Result { + unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) } +} + +/// Copy and transform a file descriptor +pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result { + unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) } +} + +/// Exit the current process +pub fn exit(status: usize) -> Result { + unsafe { syscall1(SYS_EXIT, status) } +} + +/// Change file permissions +pub fn fchmod(fd: usize, mode: u16) -> Result { + unsafe { syscall2(SYS_FCHMOD, fd, mode as usize) } + +} + +/// Change file ownership +pub fn fchown(fd: usize, uid: u32, gid: u32) -> Result { + unsafe { syscall3(SYS_FCHOWN, fd, uid as usize, gid as usize) } + +} + +/// Change file descriptor flags +pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result { + unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) } +} + +/// Map a file into memory, but with the ability to set the address to map into, either as a hint +/// or as a requirement of the map. +/// +/// # Errors +/// `EACCES` - the file descriptor was not open for reading +/// `EBADF` - if the file descriptor was invalid +/// `ENODEV` - mmapping was not supported +/// `EINVAL` - invalid combination of flags +/// `EEXIST` - if [`MapFlags::MAP_FIXED`] was set, and the address specified was already in use. +/// +pub unsafe fn fmap(fd: usize, map: &Map) -> Result { + syscall3(SYS_FMAP, fd, map as *const Map as usize, mem::size_of::()) +} + +/// Unmap whole (or partial) continous memory-mapped files +pub unsafe fn funmap(addr: usize, len: usize) -> Result { + syscall2(SYS_FUNMAP, addr, len) +} + +/// Retrieve the canonical path of a file +pub fn fpath(fd: usize, buf: &mut [u8]) -> Result { + unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) } +} + +/// Rename a file +pub fn frename>(fd: usize, path: T) -> Result { + unsafe { syscall3(SYS_FRENAME, fd, path.as_ref().as_ptr() as usize, path.as_ref().len()) } +} + +/// Get metadata about a file +pub fn fstat(fd: usize, stat: &mut Stat) -> Result { + unsafe { syscall3(SYS_FSTAT, fd, stat as *mut Stat as usize, mem::size_of::()) } +} + +/// Get metadata about a filesystem +pub fn fstatvfs(fd: usize, stat: &mut StatVfs) -> Result { + unsafe { syscall3(SYS_FSTATVFS, fd, stat as *mut StatVfs as usize, mem::size_of::()) } +} + +/// Sync a file descriptor to its underlying medium +pub fn fsync(fd: usize) -> Result { + unsafe { syscall1(SYS_FSYNC, fd) } +} + +/// Truncate or extend a file to a specified length +pub fn ftruncate(fd: usize, len: usize) -> Result { + unsafe { syscall2(SYS_FTRUNCATE, fd, len) } +} + +// Change modify and/or access times +pub fn futimens(fd: usize, times: &[TimeSpec]) -> Result { + unsafe { syscall3(SYS_FUTIMENS, fd, times.as_ptr() as usize, times.len() * mem::size_of::()) } +} + +/// Fast userspace mutex +pub unsafe fn futex(addr: *mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32) + -> Result { + syscall5(SYS_FUTEX, addr as usize, op, (val as isize) as usize, val2, addr2 as usize) +} + +/// Get the effective group ID +pub fn getegid() -> Result { + unsafe { syscall0(SYS_GETEGID) } +} + +/// Get the effective namespace +pub fn getens() -> Result { + unsafe { syscall0(SYS_GETENS) } +} + +/// Get the effective user ID +pub fn geteuid() -> Result { + unsafe { syscall0(SYS_GETEUID) } +} + +/// Get the current group ID +pub fn getgid() -> Result { + unsafe { syscall0(SYS_GETGID) } +} + +/// Get the current namespace +pub fn getns() -> Result { + unsafe { syscall0(SYS_GETNS) } +} + +/// Get the current process ID +pub fn getpid() -> Result { + unsafe { syscall0(SYS_GETPID) } +} + +/// Get the process group ID +pub fn getpgid(pid: usize) -> Result { + unsafe { syscall1(SYS_GETPGID, pid) } +} + +/// Get the parent process ID +pub fn getppid() -> Result { + unsafe { syscall0(SYS_GETPPID) } +} + +/// Get the current user ID +pub fn getuid() -> Result { + unsafe { syscall0(SYS_GETUID) } +} + +/// Set the I/O privilege level +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +/// * `EINVAL` - `level > 3` +pub unsafe fn iopl(level: usize) -> Result { + syscall1(SYS_IOPL, level) +} + +/// Send a signal `sig` to the process identified by `pid` +pub fn kill(pid: usize, sig: usize) -> Result { + unsafe { syscall2(SYS_KILL, pid, sig) } +} + +/// Create a link to a file +pub unsafe fn link(old: *const u8, new: *const u8) -> Result { + syscall2(SYS_LINK, old as usize, new as usize) +} + +/// Seek to `offset` bytes in a file descriptor +pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result { + unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) } +} + +/// Make a new scheme namespace +pub fn mkns(schemes: &[[usize; 2]]) -> Result { + unsafe { syscall2(SYS_MKNS, schemes.as_ptr() as usize, schemes.len()) } +} + +/// Change mapping flags +pub unsafe fn mprotect(addr: usize, size: usize, flags: MapFlags) -> Result { + syscall3(SYS_MPROTECT, addr, size, flags.bits()) +} + +/// Sleep for the time specified in `req` +pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result { + unsafe { syscall2(SYS_NANOSLEEP, req as *const TimeSpec as usize, + rem as *mut TimeSpec as usize) } +} + +/// Open a file +pub fn open>(path: T, flags: usize) -> Result { + unsafe { syscall3(SYS_OPEN, path.as_ref().as_ptr() as usize, path.as_ref().len(), flags) } +} + +/// Allocate frames, linearly in physical memory. +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +/// * `ENOMEM` - the system has run out of available memory +pub unsafe fn physalloc(size: usize) -> Result { + syscall1(SYS_PHYSALLOC, size) +} + +/// Allocate frames, linearly in physical memory, with an extra set of flags. If the flags contain +/// [`PARTIAL_ALLOC`], this will result in `physalloc3` with `min = 1`. +/// +/// Refer to the simpler [`physalloc`] and the more complex [`physalloc3`], that this convenience +/// function is based on. +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +/// * `ENOMEM` - the system has run out of available memory +pub unsafe fn physalloc2(size: usize, flags: usize) -> Result { + let mut ret = 1usize; + physalloc3(size, flags, &mut ret) +} + +/// Allocate frames, linearly in physical memory, with an extra set of flags. If the flags contain +/// [`PARTIAL_ALLOC`], the `min` parameter specifies the number of frames that have to be allocated +/// for this operation to succeed. The return value is the offset of the first frame, and `min` is +/// overwritten with the number of frames actually allocated. +/// +/// Refer to the simpler [`physalloc`] and the simpler library function [`physalloc2`]. +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +/// * `ENOMEM` - the system has run out of available memory +/// * `EINVAL` - `min = 0` +pub unsafe fn physalloc3(size: usize, flags: usize, min: &mut usize) -> Result { + syscall3(SYS_PHYSALLOC3, size, flags, min as *mut usize as usize) +} + +/// Free physically allocated pages +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +pub unsafe fn physfree(physical_address: usize, size: usize) -> Result { + syscall2(SYS_PHYSFREE, physical_address, size) +} + +/// Map physical memory to virtual memory +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +pub unsafe fn physmap(physical_address: usize, size: usize, flags: PhysmapFlags) -> Result { + syscall3(SYS_PHYSMAP, physical_address, size, flags.bits()) +} + +/// Unmap previously mapped physical memory +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +/// * `EFAULT` - `virtual_address` has not been mapped +pub unsafe fn physunmap(virtual_address: usize) -> Result { + syscall1(SYS_PHYSUNMAP, virtual_address) +} + +/// Create a pair of file descriptors referencing the read and write ends of a pipe +pub fn pipe2(fds: &mut [usize; 2], flags: usize) -> Result { + unsafe { syscall2(SYS_PIPE2, fds.as_ptr() as usize, flags) } +} + +/// Read from a file descriptor into a buffer +pub fn read(fd: usize, buf: &mut [u8]) -> Result { + unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) } +} + +/// Remove a directory +pub fn rmdir>(path: T) -> Result { + unsafe { syscall2(SYS_RMDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) } +} + +/// Set the process group ID +pub fn setpgid(pid: usize, pgid: usize) -> Result { + unsafe { syscall2(SYS_SETPGID, pid, pgid) } +} + +/// Set the current process group IDs +pub fn setregid(rgid: usize, egid: usize) -> Result { + unsafe { syscall2(SYS_SETREGID, rgid, egid) } +} + +/// Make a new scheme namespace +pub fn setrens(rns: usize, ens: usize) -> Result { + unsafe { syscall2(SYS_SETRENS, rns, ens) } +} + +/// Set the current process user IDs +pub fn setreuid(ruid: usize, euid: usize) -> Result { + unsafe { syscall2(SYS_SETREUID, ruid, euid) } +} + +/// Set up a signal handler +pub fn sigaction(sig: usize, act: Option<&SigAction>, oldact: Option<&mut SigAction>) -> Result { + unsafe { syscall4(SYS_SIGACTION, sig, + act.map(|x| x as *const _).unwrap_or_else(ptr::null) as usize, + oldact.map(|x| x as *mut _).unwrap_or_else(ptr::null_mut) as usize, + restorer as usize) } +} + +/// Get and/or set signal masks +pub fn sigprocmask(how: usize, set: Option<&[u64; 2]>, oldset: Option<&mut [u64; 2]>) -> Result { + unsafe { syscall3(SYS_SIGPROCMASK, how, + set.map(|x| x as *const _).unwrap_or_else(ptr::null) as usize, + oldset.map(|x| x as *mut _).unwrap_or_else(ptr::null_mut) as usize) } +} + +// Return from signal handler +pub fn sigreturn() -> Result { + unsafe { syscall0(SYS_SIGRETURN) } +} + +/// Set the file mode creation mask +pub fn umask(mask: usize) -> Result { + unsafe { syscall1(SYS_UMASK, mask) } +} + +/// Remove a file +pub fn unlink>(path: T) -> Result { + unsafe { syscall2(SYS_UNLINK, path.as_ref().as_ptr() as usize, path.as_ref().len()) } +} + +/// Convert a virtual address to a physical one +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +pub unsafe fn virttophys(virtual_address: usize) -> Result { + syscall1(SYS_VIRTTOPHYS, virtual_address) +} + +/// Check if a child process has exited or received a signal +pub fn waitpid(pid: usize, status: &mut usize, options: WaitFlags) -> Result { + unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options.bits()) } +} + +/// Write a buffer to a file descriptor +/// +/// The kernel will attempt to write the bytes in `buf` to the file descriptor `fd`, returning +/// either an `Err`, explained below, or `Ok(count)` where `count` is the number of bytes which +/// were written. +/// +/// # Errors +/// +/// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block +/// * `EBADF` - the file descriptor is not valid or is not open for writing +/// * `EFAULT` - `buf` does not point to the process's addressible memory +/// * `EIO` - an I/O error occurred +/// * `ENOSPC` - the device containing the file descriptor has no room for data +/// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed +pub fn write(fd: usize, buf: &[u8]) -> Result { + unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) } +} + +/// Yield the process's time slice to the kernel +/// +/// This function will return Ok(0) on success +pub fn sched_yield() -> Result { + unsafe { syscall0(SYS_YIELD) } +} diff --git a/vendor/redox_syscall-0.3.5/src/data.rs b/vendor/redox_syscall-0.3.5/src/data.rs new file mode 100644 index 0000000000000..45d2dd86253ed --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/data.rs @@ -0,0 +1,297 @@ +use core::ops::{Deref, DerefMut}; +use core::{mem, slice}; +use crate::flag::{EventFlags, MapFlags, PtraceFlags, SigActionFlags}; + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct Event { + pub id: usize, + pub flags: EventFlags, + pub data: usize +} + +impl Deref for Event { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Event as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for Event { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Event as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct ITimerSpec { + pub it_interval: TimeSpec, + pub it_value: TimeSpec, +} + +impl Deref for ITimerSpec { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const ITimerSpec as *const u8, + mem::size_of::()) + } + } +} + +impl DerefMut for ITimerSpec { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut ITimerSpec as *mut u8, + mem::size_of::()) + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct OldMap { + pub offset: usize, + pub size: usize, + pub flags: MapFlags, +} + +impl Deref for OldMap { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const OldMap as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for OldMap { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut OldMap as *mut u8, mem::size_of::()) + } + } +} +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct Map { + /// The offset inside the file that is being mapped. + pub offset: usize, + + /// The size of the memory map. + pub size: usize, + + /// Contains both prot and map flags. + pub flags: MapFlags, + + /// Functions as a hint to where in the virtual address space of the running process, to place + /// the memory map. If [`MapFlags::MAP_FIXED`] is set, then this address must be the address to + /// map to. + pub address: usize, +} + +impl Deref for Map { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Map as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for Map { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Map as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct Packet { + pub id: u64, + pub pid: usize, + pub uid: u32, + pub gid: u32, + pub a: usize, + pub b: usize, + pub c: usize, + pub d: usize +} + +impl Deref for Packet { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Packet as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for Packet { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Packet as *mut u8, mem::size_of::()) + } + } +} + +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct SigAction { + pub sa_handler: Option, + pub sa_mask: [u64; 2], + pub sa_flags: SigActionFlags, +} + +#[allow(dead_code)] +unsafe fn _assert_size_of_function_is_sane() { + // Transmuting will complain *at compile time* if sizes differ. + // Rust forbids a fn-pointer from being 0 so to allow SIG_DFL to + // exist, we use Option which will mean 0 + // becomes None + let _ = mem::transmute::, usize>(None); +} + +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct Stat { + pub st_dev: u64, + pub st_ino: u64, + pub st_mode: u16, + pub st_nlink: u32, + pub st_uid: u32, + pub st_gid: u32, + pub st_size: u64, + pub st_blksize: u32, + pub st_blocks: u64, + pub st_mtime: u64, + pub st_mtime_nsec: u32, + pub st_atime: u64, + pub st_atime_nsec: u32, + pub st_ctime: u64, + pub st_ctime_nsec: u32, +} + +impl Deref for Stat { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Stat as *const u8, + mem::size_of::()) + } + } +} + +impl DerefMut for Stat { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Stat as *mut u8, + mem::size_of::()) + } + } +} + +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct StatVfs { + pub f_bsize: u32, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, +} + +impl Deref for StatVfs { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const StatVfs as *const u8, + mem::size_of::()) + } + } +} + +impl DerefMut for StatVfs { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut StatVfs as *mut u8, + mem::size_of::()) + } + } +} + +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct TimeSpec { + pub tv_sec: i64, + pub tv_nsec: i32, +} + +impl Deref for TimeSpec { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const TimeSpec as *const u8, + mem::size_of::()) + } + } +} + +impl DerefMut for TimeSpec { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut TimeSpec as *mut u8, + mem::size_of::()) + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(C)] +pub struct PtraceEvent { + pub cause: PtraceFlags, + pub a: usize, + pub b: usize, + pub c: usize, + pub d: usize, + pub e: usize, + pub f: usize +} + +impl Deref for PtraceEvent { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const PtraceEvent as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for PtraceEvent { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut PtraceEvent as *mut u8, mem::size_of::()) + } + } +} + +#[macro_export] +macro_rules! ptrace_event { + ($cause:expr $(, $a:expr $(, $b:expr $(, $c:expr)?)?)?) => { + $crate::data::PtraceEvent { + cause: $cause, + $(a: $a, + $(b: $b, + $(c: $c,)? + )? + )? + ..Default::default() + } + } +} diff --git a/vendor/redox_syscall-0.3.5/src/error.rs b/vendor/redox_syscall-0.3.5/src/error.rs new file mode 100644 index 0000000000000..9a4b0b5ad39ae --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/error.rs @@ -0,0 +1,311 @@ +use core::{fmt, result}; + +#[derive(Eq, PartialEq)] +pub struct Error { + pub errno: i32, +} + +pub type Result = result::Result; + +impl Error { + pub fn new(errno: i32) -> Error { + Error { errno: errno } + } + + pub fn mux(result: Result) -> usize { + match result { + Ok(value) => value, + Err(error) => -error.errno as usize, + } + } + + pub fn demux(value: usize) -> Result { + let errno = -(value as i32); + if errno >= 1 && errno < STR_ERROR.len() as i32 { + Err(Error::new(errno)) + } else { + Ok(value) + } + } + + pub fn text(&self) -> &'static str { + STR_ERROR.get(self.errno as usize).map(|&x| x).unwrap_or("Unknown Error") + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + f.write_str(self.text()) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + f.write_str(self.text()) + } +} + +pub const EPERM: i32 = 1; /* Operation not permitted */ +pub const ENOENT: i32 = 2; /* No such file or directory */ +pub const ESRCH: i32 = 3; /* No such process */ +pub const EINTR: i32 = 4; /* Interrupted system call */ +pub const EIO: i32 = 5; /* I/O error */ +pub const ENXIO: i32 = 6; /* No such device or address */ +pub const E2BIG: i32 = 7; /* Argument list too long */ +pub const ENOEXEC: i32 = 8; /* Exec format error */ +pub const EBADF: i32 = 9; /* Bad file number */ +pub const ECHILD: i32 = 10; /* No child processes */ +pub const EAGAIN: i32 = 11; /* Try again */ +pub const ENOMEM: i32 = 12; /* Out of memory */ +pub const EACCES: i32 = 13; /* Permission denied */ +pub const EFAULT: i32 = 14; /* Bad address */ +pub const ENOTBLK: i32 = 15; /* Block device required */ +pub const EBUSY: i32 = 16; /* Device or resource busy */ +pub const EEXIST: i32 = 17; /* File exists */ +pub const EXDEV: i32 = 18; /* Cross-device link */ +pub const ENODEV: i32 = 19; /* No such device */ +pub const ENOTDIR: i32 = 20; /* Not a directory */ +pub const EISDIR: i32 = 21; /* Is a directory */ +pub const EINVAL: i32 = 22; /* Invalid argument */ +pub const ENFILE: i32 = 23; /* File table overflow */ +pub const EMFILE: i32 = 24; /* Too many open files */ +pub const ENOTTY: i32 = 25; /* Not a typewriter */ +pub const ETXTBSY: i32 = 26; /* Text file busy */ +pub const EFBIG: i32 = 27; /* File too large */ +pub const ENOSPC: i32 = 28; /* No space left on device */ +pub const ESPIPE: i32 = 29; /* Illegal seek */ +pub const EROFS: i32 = 30; /* Read-only file system */ +pub const EMLINK: i32 = 31; /* Too many links */ +pub const EPIPE: i32 = 32; /* Broken pipe */ +pub const EDOM: i32 = 33; /* Math argument out of domain of func */ +pub const ERANGE: i32 = 34; /* Math result not representable */ +pub const EDEADLK: i32 = 35; /* Resource deadlock would occur */ +pub const ENAMETOOLONG: i32 = 36; /* File name too long */ +pub const ENOLCK: i32 = 37; /* No record locks available */ +pub const ENOSYS: i32 = 38; /* Function not implemented */ +pub const ENOTEMPTY: i32 = 39; /* Directory not empty */ +pub const ELOOP: i32 = 40; /* Too many symbolic links encountered */ +pub const EWOULDBLOCK: i32 = 41; /* Operation would block */ +pub const ENOMSG: i32 = 42; /* No message of desired type */ +pub const EIDRM: i32 = 43; /* Identifier removed */ +pub const ECHRNG: i32 = 44; /* Channel number out of range */ +pub const EL2NSYNC: i32 = 45; /* Level 2 not synchronized */ +pub const EL3HLT: i32 = 46; /* Level 3 halted */ +pub const EL3RST: i32 = 47; /* Level 3 reset */ +pub const ELNRNG: i32 = 48; /* Link number out of range */ +pub const EUNATCH: i32 = 49; /* Protocol driver not attached */ +pub const ENOCSI: i32 = 50; /* No CSI structure available */ +pub const EL2HLT: i32 = 51; /* Level 2 halted */ +pub const EBADE: i32 = 52; /* Invalid exchange */ +pub const EBADR: i32 = 53; /* Invalid request descriptor */ +pub const EXFULL: i32 = 54; /* Exchange full */ +pub const ENOANO: i32 = 55; /* No anode */ +pub const EBADRQC: i32 = 56; /* Invalid request code */ +pub const EBADSLT: i32 = 57; /* Invalid slot */ +pub const EDEADLOCK: i32 = 58; /* Resource deadlock would occur */ +pub const EBFONT: i32 = 59; /* Bad font file format */ +pub const ENOSTR: i32 = 60; /* Device not a stream */ +pub const ENODATA: i32 = 61; /* No data available */ +pub const ETIME: i32 = 62; /* Timer expired */ +pub const ENOSR: i32 = 63; /* Out of streams resources */ +pub const ENONET: i32 = 64; /* Machine is not on the network */ +pub const ENOPKG: i32 = 65; /* Package not installed */ +pub const EREMOTE: i32 = 66; /* Object is remote */ +pub const ENOLINK: i32 = 67; /* Link has been severed */ +pub const EADV: i32 = 68; /* Advertise error */ +pub const ESRMNT: i32 = 69; /* Srmount error */ +pub const ECOMM: i32 = 70; /* Communication error on send */ +pub const EPROTO: i32 = 71; /* Protocol error */ +pub const EMULTIHOP: i32 = 72; /* Multihop attempted */ +pub const EDOTDOT: i32 = 73; /* RFS specific error */ +pub const EBADMSG: i32 = 74; /* Not a data message */ +pub const EOVERFLOW: i32 = 75; /* Value too large for defined data type */ +pub const ENOTUNIQ: i32 = 76; /* Name not unique on network */ +pub const EBADFD: i32 = 77; /* File descriptor in bad state */ +pub const EREMCHG: i32 = 78; /* Remote address changed */ +pub const ELIBACC: i32 = 79; /* Can not access a needed shared library */ +pub const ELIBBAD: i32 = 80; /* Accessing a corrupted shared library */ +pub const ELIBSCN: i32 = 81; /* .lib section in a.out corrupted */ +pub const ELIBMAX: i32 = 82; /* Attempting to link in too many shared libraries */ +pub const ELIBEXEC: i32 = 83; /* Cannot exec a shared library directly */ +pub const EILSEQ: i32 = 84; /* Illegal byte sequence */ +pub const ERESTART: i32 = 85; /* Interrupted system call should be restarted */ +pub const ESTRPIPE: i32 = 86; /* Streams pipe error */ +pub const EUSERS: i32 = 87; /* Too many users */ +pub const ENOTSOCK: i32 = 88; /* Socket operation on non-socket */ +pub const EDESTADDRREQ: i32 = 89; /* Destination address required */ +pub const EMSGSIZE: i32 = 90; /* Message too long */ +pub const EPROTOTYPE: i32 = 91; /* Protocol wrong type for socket */ +pub const ENOPROTOOPT: i32 = 92; /* Protocol not available */ +pub const EPROTONOSUPPORT: i32 = 93; /* Protocol not supported */ +pub const ESOCKTNOSUPPORT: i32 = 94; /* Socket type not supported */ +pub const EOPNOTSUPP: i32 = 95; /* Operation not supported on transport endpoint */ +pub const EPFNOSUPPORT: i32 = 96; /* Protocol family not supported */ +pub const EAFNOSUPPORT: i32 = 97; /* Address family not supported by protocol */ +pub const EADDRINUSE: i32 = 98; /* Address already in use */ +pub const EADDRNOTAVAIL: i32 = 99; /* Cannot assign requested address */ +pub const ENETDOWN: i32 = 100; /* Network is down */ +pub const ENETUNREACH: i32 = 101; /* Network is unreachable */ +pub const ENETRESET: i32 = 102; /* Network dropped connection because of reset */ +pub const ECONNABORTED: i32 = 103; /* Software caused connection abort */ +pub const ECONNRESET: i32 = 104; /* Connection reset by peer */ +pub const ENOBUFS: i32 = 105; /* No buffer space available */ +pub const EISCONN: i32 = 106; /* Transport endpoint is already connected */ +pub const ENOTCONN: i32 = 107; /* Transport endpoint is not connected */ +pub const ESHUTDOWN: i32 = 108; /* Cannot send after transport endpoint shutdown */ +pub const ETOOMANYREFS: i32 = 109; /* Too many references: cannot splice */ +pub const ETIMEDOUT: i32 = 110; /* Connection timed out */ +pub const ECONNREFUSED: i32 = 111; /* Connection refused */ +pub const EHOSTDOWN: i32 = 112; /* Host is down */ +pub const EHOSTUNREACH: i32 = 113; /* No route to host */ +pub const EALREADY: i32 = 114; /* Operation already in progress */ +pub const EINPROGRESS: i32 = 115; /* Operation now in progress */ +pub const ESTALE: i32 = 116; /* Stale NFS file handle */ +pub const EUCLEAN: i32 = 117; /* Structure needs cleaning */ +pub const ENOTNAM: i32 = 118; /* Not a XENIX named type file */ +pub const ENAVAIL: i32 = 119; /* No XENIX semaphores available */ +pub const EISNAM: i32 = 120; /* Is a named type file */ +pub const EREMOTEIO: i32 = 121; /* Remote I/O error */ +pub const EDQUOT: i32 = 122; /* Quota exceeded */ +pub const ENOMEDIUM: i32 = 123; /* No medium found */ +pub const EMEDIUMTYPE: i32 = 124; /* Wrong medium type */ +pub const ECANCELED: i32 = 125; /* Operation Canceled */ +pub const ENOKEY: i32 = 126; /* Required key not available */ +pub const EKEYEXPIRED: i32 = 127; /* Key has expired */ +pub const EKEYREVOKED: i32 = 128; /* Key has been revoked */ +pub const EKEYREJECTED: i32 = 129; /* Key was rejected by service */ +pub const EOWNERDEAD: i32 = 130; /* Owner died */ +pub const ENOTRECOVERABLE: i32 = 131; /* State not recoverable */ + +pub static STR_ERROR: [&'static str; 132] = ["Success", + "Operation not permitted", + "No such file or directory", + "No such process", + "Interrupted system call", + "I/O error", + "No such device or address", + "Argument list too long", + "Exec format error", + "Bad file number", + "No child processes", + "Try again", + "Out of memory", + "Permission denied", + "Bad address", + "Block device required", + "Device or resource busy", + "File exists", + "Cross-device link", + "No such device", + "Not a directory", + "Is a directory", + "Invalid argument", + "File table overflow", + "Too many open files", + "Not a typewriter", + "Text file busy", + "File too large", + "No space left on device", + "Illegal seek", + "Read-only file system", + "Too many links", + "Broken pipe", + "Math argument out of domain of func", + "Math result not representable", + "Resource deadlock would occur", + "File name too long", + "No record locks available", + "Function not implemented", + "Directory not empty", + "Too many symbolic links encountered", + "Operation would block", + "No message of desired type", + "Identifier removed", + "Channel number out of range", + "Level 2 not synchronized", + "Level 3 halted", + "Level 3 reset", + "Link number out of range", + "Protocol driver not attached", + "No CSI structure available", + "Level 2 halted", + "Invalid exchange", + "Invalid request descriptor", + "Exchange full", + "No anode", + "Invalid request code", + "Invalid slot", + "Resource deadlock would occur", + "Bad font file format", + "Device not a stream", + "No data available", + "Timer expired", + "Out of streams resources", + "Machine is not on the network", + "Package not installed", + "Object is remote", + "Link has been severed", + "Advertise error", + "Srmount error", + "Communication error on send", + "Protocol error", + "Multihop attempted", + "RFS specific error", + "Not a data message", + "Value too large for defined data type", + "Name not unique on network", + "File descriptor in bad state", + "Remote address changed", + "Can not access a needed shared library", + "Accessing a corrupted shared library", + ".lib section in a.out corrupted", + "Attempting to link in too many shared libraries", + "Cannot exec a shared library directly", + "Illegal byte sequence", + "Interrupted system call should be restarted", + "Streams pipe error", + "Too many users", + "Socket operation on non-socket", + "Destination address required", + "Message too long", + "Protocol wrong type for socket", + "Protocol not available", + "Protocol not supported", + "Socket type not supported", + "Operation not supported on transport endpoint", + "Protocol family not supported", + "Address family not supported by protocol", + "Address already in use", + "Cannot assign requested address", + "Network is down", + "Network is unreachable", + "Network dropped connection because of reset", + "Software caused connection abort", + "Connection reset by peer", + "No buffer space available", + "Transport endpoint is already connected", + "Transport endpoint is not connected", + "Cannot send after transport endpoint shutdown", + "Too many references: cannot splice", + "Connection timed out", + "Connection refused", + "Host is down", + "No route to host", + "Operation already in progress", + "Operation now in progress", + "Stale NFS file handle", + "Structure needs cleaning", + "Not a XENIX named type file", + "No XENIX semaphores available", + "Is a named type file", + "Remote I/O error", + "Quota exceeded", + "No medium found", + "Wrong medium type", + "Operation Canceled", + "Required key not available", + "Key has expired", + "Key has been revoked", + "Key was rejected by service", + "Owner died", + "State not recoverable"]; diff --git a/vendor/redox_syscall-0.3.5/src/flag.rs b/vendor/redox_syscall-0.3.5/src/flag.rs new file mode 100644 index 0000000000000..3411048562bc6 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/flag.rs @@ -0,0 +1,336 @@ +use bitflags::bitflags as inner_bitflags; +use core::{mem, ops::Deref, slice}; + +macro_rules! bitflags { + ( + $(#[$outer:meta])* + pub struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + // First, use the inner bitflags + inner_bitflags! { + #[derive(Default)] + $(#[$outer])* + pub struct $BitFlags: $T { + $( + $(#[$inner $($args)*])* + const $Flag = $value; + )+ + } + } + + // Secondly, re-export all inner constants + // (`pub use self::Struct::*` doesn't work) + $( + $(#[$inner $($args)*])* + pub const $Flag: $BitFlags = $BitFlags::$Flag; + )+ + } +} + +pub const CLOCK_REALTIME: usize = 1; +pub const CLOCK_MONOTONIC: usize = 4; + +bitflags! { + pub struct EventFlags: usize { + const EVENT_NONE = 0; + const EVENT_READ = 1; + const EVENT_WRITE = 2; + } +} + +pub const F_DUPFD: usize = 0; +pub const F_GETFD: usize = 1; +pub const F_SETFD: usize = 2; +pub const F_GETFL: usize = 3; +pub const F_SETFL: usize = 4; + +pub const FUTEX_WAIT: usize = 0; +pub const FUTEX_WAKE: usize = 1; +pub const FUTEX_REQUEUE: usize = 2; +pub const FUTEX_WAIT64: usize = 3; + +bitflags! { + pub struct MapFlags: usize { + const PROT_NONE = 0x0000_0000; + const PROT_EXEC = 0x0001_0000; + const PROT_WRITE = 0x0002_0000; + const PROT_READ = 0x0004_0000; + + const MAP_SHARED = 0x0001; + const MAP_PRIVATE = 0x0002; + + /// Only accepted for mmap2(2). + const MAP_FIXED = 0x0004; + const MAP_FIXED_NOREPLACE = 0x000C; + } +} + +pub const MODE_TYPE: u16 = 0xF000; +pub const MODE_DIR: u16 = 0x4000; +pub const MODE_FILE: u16 = 0x8000; +pub const MODE_SYMLINK: u16 = 0xA000; +pub const MODE_FIFO: u16 = 0x1000; +pub const MODE_CHR: u16 = 0x2000; + +pub const MODE_PERM: u16 = 0x0FFF; +pub const MODE_SETUID: u16 = 0o4000; +pub const MODE_SETGID: u16 = 0o2000; + +pub const O_RDONLY: usize = 0x0001_0000; +pub const O_WRONLY: usize = 0x0002_0000; +pub const O_RDWR: usize = 0x0003_0000; +pub const O_NONBLOCK: usize = 0x0004_0000; +pub const O_APPEND: usize = 0x0008_0000; +pub const O_SHLOCK: usize = 0x0010_0000; +pub const O_EXLOCK: usize = 0x0020_0000; +pub const O_ASYNC: usize = 0x0040_0000; +pub const O_FSYNC: usize = 0x0080_0000; +pub const O_CLOEXEC: usize = 0x0100_0000; +pub const O_CREAT: usize = 0x0200_0000; +pub const O_TRUNC: usize = 0x0400_0000; +pub const O_EXCL: usize = 0x0800_0000; +pub const O_DIRECTORY: usize = 0x1000_0000; +pub const O_STAT: usize = 0x2000_0000; +pub const O_SYMLINK: usize = 0x4000_0000; +pub const O_NOFOLLOW: usize = 0x8000_0000; +pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR; + +bitflags! { + pub struct PhysmapFlags: usize { + const PHYSMAP_WRITE = 0x0000_0001; + const PHYSMAP_WRITE_COMBINE = 0x0000_0002; + const PHYSMAP_NO_CACHE = 0x0000_0004; + } +} +bitflags! { + /// Extra flags for [`physalloc2`] or [`physalloc3`]. + /// + /// [`physalloc2`]: ../call/fn.physalloc2.html + /// [`physalloc3`]: ../call/fn.physalloc3.html + pub struct PhysallocFlags: usize { + /// Only allocate memory within the 32-bit physical memory space. This is necessary for + /// some devices may not support 64-bit memory. + const SPACE_32 = 0x0000_0001; + + /// The frame that will be allocated, is going to reside anywhere in 64-bit space. This + /// flag is redundant for the most part, except when overriding some other default. + const SPACE_64 = 0x0000_0002; + + /// Do a "partial allocation", which means that not all of the frames specified in the + /// frame count `size` actually have to be allocated. This means that if the allocator was + /// unable to find a physical memory range large enough, it can instead return whatever + /// range it decides is optimal. Thus, instead of letting one driver get an expensive + /// 128MiB physical memory range when the physical memory has become fragmented, and + /// failing, it can instead be given a more optimal range. If the device supports + /// scatter-gather lists, then the driver only has to allocate more ranges, and the device + /// will do vectored I/O. + /// + /// PARTIAL_ALLOC supports different allocation strategies, refer to + /// [`Optimal`], [`GreatestRange`]. + /// + /// [`Optimal`]: ./enum.PartialAllocStrategy.html + /// [`GreatestRange`]: ./enum.PartialAllocStrategy.html + const PARTIAL_ALLOC = 0x0000_0004; + } +} + +/// The bitmask of the partial allocation strategy. Currently four different strategies are +/// supported. If [`PARTIAL_ALLOC`] is not set, this bitmask is no longer reserved. +pub const PARTIAL_ALLOC_STRATEGY_MASK: usize = 0x0003_0000; + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(usize)] +pub enum PartialAllocStrategy { + /// The allocator decides itself the size of the memory range, based on e.g. free memory ranges + /// and other processes which require large physical memory chunks. + Optimal = 0x0001_0000, + + /// The allocator returns the absolute greatest range it can find. + GreatestRange = 0x0002_0000, + + /// The allocator returns the first range that fits the minimum count, without searching extra. + Greedy = 0x0003_0000, +} +impl Default for PartialAllocStrategy { + fn default() -> Self { + Self::Optimal + } +} + +impl PartialAllocStrategy { + pub fn from_raw(raw: usize) -> Option { + match raw { + 0x0001_0000 => Some(Self::Optimal), + 0x0002_0000 => Some(Self::GreatestRange), + 0x0003_0000 => Some(Self::Greedy), + _ => None, + } + } +} + +// The top 48 bits of PTRACE_* are reserved, for now + +bitflags! { + pub struct PtraceFlags: u64 { + /// Stop before a syscall is handled. Send PTRACE_FLAG_IGNORE to not + /// handle the syscall. + const PTRACE_STOP_PRE_SYSCALL = 0x0000_0000_0000_0001; + /// Stop after a syscall is handled. + const PTRACE_STOP_POST_SYSCALL = 0x0000_0000_0000_0002; + /// Stop after exactly one instruction. TODO: This may not handle + /// fexec/signal boundaries. Should it? + const PTRACE_STOP_SINGLESTEP = 0x0000_0000_0000_0004; + /// Stop before a signal is handled. Send PTRACE_FLAG_IGNORE to not + /// handle signal. + const PTRACE_STOP_SIGNAL = 0x0000_0000_0000_0008; + /// Stop on a software breakpoint, such as the int3 instruction for + /// x86_64. + const PTRACE_STOP_BREAKPOINT = 0x0000_0000_0000_0010; + /// Stop just before exiting for good. + const PTRACE_STOP_EXIT = 0x0000_0000_0000_0020; + + const PTRACE_STOP_MASK = 0x0000_0000_0000_00FF; + + + /// Sent when a child is cloned, giving you the opportunity to trace it. + /// If you don't catch this, the child is started as normal. + const PTRACE_EVENT_CLONE = 0x0000_0000_0000_0100; + + /// Sent when current-addrspace is changed, allowing the tracer to reopen the memory file. + const PTRACE_EVENT_ADDRSPACE_SWITCH = 0x0000_0000_0000_0200; + + const PTRACE_EVENT_MASK = 0x0000_0000_0000_0F00; + + /// Special meaning, depending on the event. Usually, when fired before + /// an action, it will skip performing that action. + const PTRACE_FLAG_IGNORE = 0x0000_0000_0000_1000; + + const PTRACE_FLAG_MASK = 0x0000_0000_0000_F000; + } +} +impl Deref for PtraceFlags { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + // Same as to_ne_bytes but in-place + unsafe { + slice::from_raw_parts( + &self.bits as *const _ as *const u8, + mem::size_of::() + ) + } + } +} + +pub const SEEK_SET: usize = 0; +pub const SEEK_CUR: usize = 1; +pub const SEEK_END: usize = 2; + +pub const SIGHUP: usize = 1; +pub const SIGINT: usize = 2; +pub const SIGQUIT: usize = 3; +pub const SIGILL: usize = 4; +pub const SIGTRAP: usize = 5; +pub const SIGABRT: usize = 6; +pub const SIGBUS: usize = 7; +pub const SIGFPE: usize = 8; +pub const SIGKILL: usize = 9; +pub const SIGUSR1: usize = 10; +pub const SIGSEGV: usize = 11; +pub const SIGUSR2: usize = 12; +pub const SIGPIPE: usize = 13; +pub const SIGALRM: usize = 14; +pub const SIGTERM: usize = 15; +pub const SIGSTKFLT: usize= 16; +pub const SIGCHLD: usize = 17; +pub const SIGCONT: usize = 18; +pub const SIGSTOP: usize = 19; +pub const SIGTSTP: usize = 20; +pub const SIGTTIN: usize = 21; +pub const SIGTTOU: usize = 22; +pub const SIGURG: usize = 23; +pub const SIGXCPU: usize = 24; +pub const SIGXFSZ: usize = 25; +pub const SIGVTALRM: usize= 26; +pub const SIGPROF: usize = 27; +pub const SIGWINCH: usize = 28; +pub const SIGIO: usize = 29; +pub const SIGPWR: usize = 30; +pub const SIGSYS: usize = 31; + +pub const SIG_DFL: usize = 0; +pub const SIG_IGN: usize = 1; + +pub const SIG_BLOCK: usize = 0; +pub const SIG_UNBLOCK: usize = 1; +pub const SIG_SETMASK: usize = 2; + +bitflags! { + pub struct SigActionFlags: usize { + const SA_NOCLDSTOP = 0x00000001; + const SA_NOCLDWAIT = 0x00000002; + const SA_SIGINFO = 0x00000004; + const SA_RESTORER = 0x04000000; + const SA_ONSTACK = 0x08000000; + const SA_RESTART = 0x10000000; + const SA_NODEFER = 0x40000000; + const SA_RESETHAND = 0x80000000; + } +} + +bitflags! { + pub struct WaitFlags: usize { + const WNOHANG = 0x01; + const WUNTRACED = 0x02; + const WCONTINUED = 0x08; + } +} + +pub const ADDRSPACE_OP_MMAP: usize = 0; +pub const ADDRSPACE_OP_MUNMAP: usize = 1; +pub const ADDRSPACE_OP_MPROTECT: usize = 2; +pub const ADDRSPACE_OP_TRANSFER: usize = 3; + +/// True if status indicates the child is stopped. +pub fn wifstopped(status: usize) -> bool { + (status & 0xff) == 0x7f +} + +/// If wifstopped(status), the signal that stopped the child. +pub fn wstopsig(status: usize) -> usize { + (status >> 8) & 0xff +} + +/// True if status indicates the child continued after a stop. +pub fn wifcontinued(status: usize) -> bool { + status == 0xffff +} + +/// True if STATUS indicates termination by a signal. +pub fn wifsignaled(status: usize) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 +} + +/// If wifsignaled(status), the terminating signal. +pub fn wtermsig(status: usize) -> usize { + status & 0x7f +} + +/// True if status indicates normal termination. +pub fn wifexited(status: usize) -> bool { + wtermsig(status) == 0 +} + +/// If wifexited(status), the exit status. +pub fn wexitstatus(status: usize) -> usize { + (status >> 8) & 0xff +} + +/// True if status indicates a core dump was created. +pub fn wcoredump(status: usize) -> bool { + (status & 0x80) != 0 +} diff --git a/vendor/redox_syscall-0.3.5/src/io/dma.rs b/vendor/redox_syscall-0.3.5/src/io/dma.rs new file mode 100644 index 0000000000000..0613fc9fc9b4c --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/io/dma.rs @@ -0,0 +1,219 @@ +use core::mem::{self, MaybeUninit}; +use core::ops::{Deref, DerefMut}; +use core::{ptr, slice}; + +use crate::Result; +use crate::{PartialAllocStrategy, PhysallocFlags, PhysmapFlags}; +use crate::arch::PAGE_SIZE; + +/// An RAII guard of a physical memory allocation. Currently all physically allocated memory are +/// page-aligned and take up at least 4k of space (on x86_64). +#[derive(Debug)] +pub struct PhysBox { + address: usize, + size: usize +} + +const fn round_up(x: usize) -> usize { + (x + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE +} +fn assert_aligned(x: usize) { + assert_eq!(x % PAGE_SIZE, 0); +} + +#[cfg(target_arch = "aarch64")] +fn physmap_flags() -> PhysmapFlags { + // aarch64 currently must map DMA memory without caching to ensure coherence + crate::PHYSMAP_NO_CACHE | crate::PHYSMAP_WRITE +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn physmap_flags() -> PhysmapFlags { + // x86 ensures cache coherence with DMA memory + crate::PHYSMAP_WRITE +} + +impl PhysBox { + /// Construct a PhysBox from an address and a size. The address must be page-aligned, and the + /// size must similarly be a multiple of the page size. + /// + /// # Safety + /// This function is unsafe because when dropping, Self has to a valid allocation. + pub unsafe fn from_raw_parts(address: usize, size: usize) -> Self { + assert_aligned(address); + assert_aligned(size); + + Self { + address, + size, + } + } + + /// Retrieve the byte address in physical memory, of this allocation. + pub fn address(&self) -> usize { + self.address + } + + /// Retrieve the size in bytes of the alloc. + pub fn size(&self) -> usize { + self.size + } + + /// Allocate physical memory that must reside in 32-bit space. + pub fn new_in_32bit_space(size: usize) -> Result { + Self::new_with_flags(size, PhysallocFlags::SPACE_32) + } + + pub fn new_with_flags(size: usize, flags: PhysallocFlags) -> Result { + assert!(!flags.contains(PhysallocFlags::PARTIAL_ALLOC)); + assert_aligned(size); + + let address = unsafe { crate::physalloc2(size, flags.bits())? }; + Ok(unsafe { Self::from_raw_parts(address, size) }) + } + + /// "Partially" allocate physical memory, in the sense that the allocation may be smaller than + /// expected, but still with a minimum limit. This is particularly useful when the physical + /// memory space is fragmented, and a device supports scatter-gather I/O. In that case, the + /// driver can optimistically request e.g. 1 alloc of 1 MiB, with the minimum of 512 KiB. If + /// that first allocation only returns half the size, the driver can do another allocation + /// and then let the device use both buffers. + pub fn new_partial_allocation(size: usize, flags: PhysallocFlags, strategy: Option, mut min: usize) -> Result { + assert_aligned(size); + debug_assert!(!(flags.contains(PhysallocFlags::PARTIAL_ALLOC) && strategy.is_none())); + + let address = unsafe { crate::physalloc3(size, flags.bits() | strategy.map_or(0, |s| s as usize), &mut min)? }; + Ok(unsafe { Self::from_raw_parts(address, size) }) + } + + pub fn new(size: usize) -> Result { + assert_aligned(size); + + let address = unsafe { crate::physalloc(size)? }; + Ok(unsafe { Self::from_raw_parts(address, size) }) + } +} + +impl Drop for PhysBox { + fn drop(&mut self) { + let _ = unsafe { crate::physfree(self.address, self.size) }; + } +} + +pub struct Dma { + phys: PhysBox, + virt: *mut T, +} + +impl Dma { + pub fn from_physbox_uninit(phys: PhysBox) -> Result>> { + let virt = unsafe { crate::physmap(phys.address, phys.size, physmap_flags())? } as *mut MaybeUninit; + + Ok(Dma { + phys, + virt, + }) + } + pub fn from_physbox_zeroed(phys: PhysBox) -> Result>> { + let this = Self::from_physbox_uninit(phys)?; + unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit, 0, this.phys.size) } + Ok(this) + } + + pub fn from_physbox(phys: PhysBox, value: T) -> Result { + let this = Self::from_physbox_uninit(phys)?; + + Ok(unsafe { + ptr::write(this.virt, MaybeUninit::new(value)); + this.assume_init() + }) + } + + pub fn new(value: T) -> Result { + let phys = PhysBox::new(round_up(mem::size_of::()))?; + Self::from_physbox(phys, value) + } + pub fn zeroed() -> Result>> { + let phys = PhysBox::new(round_up(mem::size_of::()))?; + Self::from_physbox_zeroed(phys) + } +} + +impl Dma> { + pub unsafe fn assume_init(self) -> Dma { + let &Dma { phys: PhysBox { address, size }, virt } = &self; + mem::forget(self); + + Dma { + phys: PhysBox { address, size }, + virt: virt as *mut T, + } + } +} +impl Dma { + pub fn physical(&self) -> usize { + self.phys.address() + } + pub fn size(&self) -> usize { + self.phys.size() + } + pub fn phys(&self) -> &PhysBox { + &self.phys + } +} + +impl Dma<[T]> { + pub fn from_physbox_uninit_unsized(phys: PhysBox, len: usize) -> Result]>> { + let max_len = phys.size() / mem::size_of::(); + assert!(len <= max_len); + + Ok(Dma { + virt: unsafe { slice::from_raw_parts_mut(crate::physmap(phys.address, phys.size, physmap_flags())? as *mut MaybeUninit, len) } as *mut [MaybeUninit], + phys, + }) + } + pub fn from_physbox_zeroed_unsized(phys: PhysBox, len: usize) -> Result]>> { + let this = Self::from_physbox_uninit_unsized(phys, len)?; + unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit, 0, this.phys.size()) } + Ok(this) + } + /// Creates a new DMA buffer with a size only known at runtime. + /// ## Safety + /// * `T` must be properly aligned. + /// * `T` must be valid as zeroed (i.e. no NonNull pointers). + pub unsafe fn zeroed_unsized(count: usize) -> Result { + let phys = PhysBox::new(round_up(mem::size_of::() * count))?; + Ok(Self::from_physbox_zeroed_unsized(phys, count)?.assume_init()) + } +} +impl Dma<[MaybeUninit]> { + pub unsafe fn assume_init(self) -> Dma<[T]> { + let &Dma { phys: PhysBox { address, size }, virt } = &self; + mem::forget(self); + + Dma { + phys: PhysBox { address, size }, + virt: virt as *mut [T], + } + } +} + +impl Deref for Dma { + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.virt } + } +} + +impl DerefMut for Dma { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.virt } + } +} + +impl Drop for Dma { + fn drop(&mut self) { + unsafe { ptr::drop_in_place(self.virt) } + let _ = unsafe { crate::funmap(self.virt as *mut u8 as usize, self.phys.size) }; + } +} diff --git a/vendor/redox_syscall-0.3.5/src/io/io.rs b/vendor/redox_syscall-0.3.5/src/io/io.rs new file mode 100644 index 0000000000000..2c4acd3883f07 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/io/io.rs @@ -0,0 +1,71 @@ +use core::cmp::PartialEq; +use core::ops::{BitAnd, BitOr, Not}; + +pub trait Io { + type Value: Copy + PartialEq + BitAnd + BitOr + Not; + + fn read(&self) -> Self::Value; + fn write(&mut self, value: Self::Value); + + #[inline(always)] + fn readf(&self, flags: Self::Value) -> bool { + (self.read() & flags) as Self::Value == flags + } + + #[inline(always)] + fn writef(&mut self, flags: Self::Value, value: bool) { + let tmp: Self::Value = match value { + true => self.read() | flags, + false => self.read() & !flags, + }; + self.write(tmp); + } +} + +pub struct ReadOnly { + inner: I +} + +impl ReadOnly { + pub const fn new(inner: I) -> ReadOnly { + ReadOnly { + inner: inner + } + } +} + +impl ReadOnly { + #[inline(always)] + pub fn read(&self) -> I::Value { + self.inner.read() + } + + #[inline(always)] + pub fn readf(&self, flags: I::Value) -> bool { + self.inner.readf(flags) + } +} + +pub struct WriteOnly { + inner: I +} + +impl WriteOnly { + pub const fn new(inner: I) -> WriteOnly { + WriteOnly { + inner: inner + } + } +} + +impl WriteOnly { + #[inline(always)] + pub fn write(&mut self, value: I::Value) { + self.inner.write(value) + } + + #[inline(always)] + pub fn writef(&mut self, flags: I::Value, value: bool) { + self.inner.writef(flags, value) + } +} diff --git a/vendor/redox_syscall-0.3.5/src/io/mmio.rs b/vendor/redox_syscall-0.3.5/src/io/mmio.rs new file mode 100644 index 0000000000000..3966ab45467a1 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/io/mmio.rs @@ -0,0 +1,45 @@ +use core::ptr::{read_volatile, write_volatile, addr_of, addr_of_mut}; +use core::mem::MaybeUninit; +use core::ops::{BitAnd, BitOr, Not}; + +use super::io::Io; + +#[repr(packed)] +pub struct Mmio { + value: MaybeUninit, +} + +impl Mmio { + /// Create a new Mmio without initializing + #[deprecated = "unsound because it's possible to read even though it's uninitialized"] + pub fn new() -> Self { + unsafe { Self::uninit() } + } + pub unsafe fn zeroed() -> Self { + Self { + value: MaybeUninit::zeroed(), + } + } + pub unsafe fn uninit() -> Self { + Self { + value: MaybeUninit::uninit(), + } + } + pub const fn from(value: T) -> Self { + Self { + value: MaybeUninit::new(value), + } + } +} + +impl Io for Mmio where T: Copy + PartialEq + BitAnd + BitOr + Not { + type Value = T; + + fn read(&self) -> T { + unsafe { read_volatile(addr_of!(self.value).cast::()) } + } + + fn write(&mut self, value: T) { + unsafe { write_volatile(addr_of_mut!(self.value).cast::(), value) }; + } +} diff --git a/vendor/redox_syscall-0.3.5/src/io/mod.rs b/vendor/redox_syscall-0.3.5/src/io/mod.rs new file mode 100644 index 0000000000000..a225f0650b14e --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/io/mod.rs @@ -0,0 +1,15 @@ +//! I/O functions + +pub use self::dma::*; +pub use self::io::*; +pub use self::mmio::*; + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub use self::pio::*; + +mod dma; +mod io; +mod mmio; + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +mod pio; diff --git a/vendor/redox_syscall-0.3.5/src/io/pio.rs b/vendor/redox_syscall-0.3.5/src/io/pio.rs new file mode 100644 index 0000000000000..8b837bcdf1d80 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/io/pio.rs @@ -0,0 +1,90 @@ +use core::arch::asm; +use core::marker::PhantomData; + +use super::io::Io; + +/// Generic PIO +#[derive(Copy, Clone)] +pub struct Pio { + port: u16, + value: PhantomData, +} + +impl Pio { + /// Create a PIO from a given port + pub const fn new(port: u16) -> Self { + Pio:: { + port, + value: PhantomData, + } + } +} + +/// Read/Write for byte PIO +impl Io for Pio { + type Value = u8; + + /// Read + #[inline(always)] + fn read(&self) -> u8 { + let value: u8; + unsafe { + asm!("in al, dx", in("dx") self.port, out("al") value, options(nostack, nomem, preserves_flags)); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u8) { + unsafe { + asm!("out dx, al", in("dx") self.port, in("al") value, options(nostack, nomem, preserves_flags)); + } + } +} + +/// Read/Write for word PIO +impl Io for Pio { + type Value = u16; + + /// Read + #[inline(always)] + fn read(&self) -> u16 { + let value: u16; + unsafe { + asm!("in ax, dx", in("dx") self.port, out("ax") value, options(nostack, nomem, preserves_flags)); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u16) { + unsafe { + asm!("out dx, ax", in("dx") self.port, in("ax") value, options(nostack, nomem, preserves_flags)); + } + } +} + +/// Read/Write for doubleword PIO +impl Io for Pio { + type Value = u32; + + /// Read + #[inline(always)] + fn read(&self) -> u32 { + let value: u32; + unsafe { + asm!("in eax, dx", in("dx") self.port, out("eax") value, options(nostack, nomem, preserves_flags)); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u32) { + unsafe { + asm!("out dx, eax", in("dx") self.port, in("eax") value, options(nostack, nomem, preserves_flags)); + } + } +} diff --git a/vendor/redox_syscall-0.3.5/src/lib.rs b/vendor/redox_syscall-0.3.5/src/lib.rs new file mode 100644 index 0000000000000..3f6d884797ace --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/lib.rs @@ -0,0 +1,61 @@ +#![cfg_attr(not(test), no_std)] + +#[cfg(test)] +extern crate core; + +pub use self::arch::*; +pub use self::call::*; +pub use self::data::*; +pub use self::error::*; +pub use self::flag::*; +pub use self::io::*; +pub use self::number::*; +pub use self::scheme::*; + +#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "arm"))] +#[path="arch/nonredox.rs"] +mod arch; + +#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "aarch64"))] +#[path="arch/aarch64.rs"] +mod arch; + +#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "riscv64"))] +#[path="arch/riscv64.rs"] +mod arch; + +#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "x86"))] +#[path="arch/x86.rs"] +mod arch; + +#[cfg(all(any(target_os = "none", target_os = "redox"), target_arch = "x86_64"))] +#[path="arch/x86_64.rs"] +mod arch; + +#[cfg(not(any(target_os = "none", target_os = "redox")))] +#[path="arch/nonredox.rs"] +mod arch; + +/// Function definitions +pub mod call; + +/// Complex structures that are used for some system calls +pub mod data; + +/// All errors that can be generated by a system call +pub mod error; + +/// Flags used as an argument to many system calls +pub mod flag; + +/// Functions for low level hardware control +pub mod io; + +/// Call numbers used by each system call +pub mod number; + +/// A trait useful for scheme handlers +pub mod scheme; + +#[cfg(test)] +mod tests; diff --git a/vendor/redox_syscall-0.3.5/src/number.rs b/vendor/redox_syscall-0.3.5/src/number.rs new file mode 100644 index 0000000000000..2b9205a269673 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/number.rs @@ -0,0 +1,73 @@ +pub const SYS_CLASS: usize = 0xF000_0000; +pub const SYS_CLASS_PATH: usize=0x1000_0000; +pub const SYS_CLASS_FILE: usize=0x2000_0000; + +pub const SYS_ARG: usize = 0x0F00_0000; +pub const SYS_ARG_SLICE: usize =0x0100_0000; +pub const SYS_ARG_MSLICE: usize=0x0200_0000; +pub const SYS_ARG_PATH: usize = 0x0300_0000; + +pub const SYS_RET: usize = 0x00F0_0000; +pub const SYS_RET_FILE: usize = 0x0010_0000; + +pub const SYS_LINK: usize = SYS_CLASS_PATH | SYS_ARG_PATH | 9; +pub const SYS_OPEN: usize = SYS_CLASS_PATH | SYS_RET_FILE | 5; +pub const SYS_RMDIR: usize = SYS_CLASS_PATH | 84; +pub const SYS_UNLINK: usize = SYS_CLASS_PATH | 10; + +pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6; +pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41; +pub const SYS_DUP2: usize = SYS_CLASS_FILE | SYS_RET_FILE | 63; +pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3; +pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4; +pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19; +pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94; +pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207; +pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55; +pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927; +pub const SYS_FMAP_OLD: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 90; +pub const SYS_FMAP: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 900; +pub const SYS_FUNMAP_OLD: usize = SYS_CLASS_FILE | 91; +pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 92; +pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928; +pub const SYS_FRENAME: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 38; +pub const SYS_FSTAT: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 28; +pub const SYS_FSTATVFS: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 100; +pub const SYS_FSYNC: usize = SYS_CLASS_FILE | 118; +pub const SYS_FTRUNCATE: usize = SYS_CLASS_FILE | 93; +pub const SYS_FUTIMENS: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 320; + +pub const SYS_CLOCK_GETTIME: usize = 265; +pub const SYS_EXIT: usize = 1; +pub const SYS_FUTEX: usize = 240; +pub const SYS_GETEGID: usize = 202; +pub const SYS_GETENS: usize = 951; +pub const SYS_GETEUID: usize = 201; +pub const SYS_GETGID: usize = 200; +pub const SYS_GETNS: usize = 950; +pub const SYS_GETPID: usize = 20; +pub const SYS_GETPGID: usize = 132; +pub const SYS_GETPPID: usize = 64; +pub const SYS_GETUID: usize = 199; +pub const SYS_IOPL: usize = 110; +pub const SYS_KILL: usize = 37; +pub const SYS_MPROTECT: usize = 125; +pub const SYS_MKNS: usize = 984; +pub const SYS_NANOSLEEP: usize =162; +pub const SYS_PHYSALLOC: usize =945; +pub const SYS_PHYSALLOC3: usize=9453; +pub const SYS_PHYSFREE: usize = 946; +pub const SYS_PHYSMAP: usize = 947; +pub const SYS_PHYSUNMAP: usize =948; +pub const SYS_VIRTTOPHYS: usize=949; +pub const SYS_PIPE2: usize = 331; +pub const SYS_SETPGID: usize = 57; +pub const SYS_SETREGID: usize = 204; +pub const SYS_SETRENS: usize = 952; +pub const SYS_SETREUID: usize = 203; +pub const SYS_SIGACTION: usize =67; +pub const SYS_SIGPROCMASK:usize=126; +pub const SYS_SIGRETURN: usize =119; +pub const SYS_UMASK: usize = 60; +pub const SYS_WAITPID: usize = 7; +pub const SYS_YIELD: usize = 158; diff --git a/vendor/redox_syscall-0.3.5/src/scheme/generate.sh b/vendor/redox_syscall-0.3.5/src/scheme/generate.sh new file mode 100755 index 0000000000000..a877cda921802 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/scheme/generate.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -e + +echo "Generating SchemeMut from Scheme" +sed 's/trait Scheme/trait SchemeMut/' scheme.rs \ +| sed 's/\&self/\&mut self/g' \ +> scheme_mut.rs + +echo "Generating SchemeBlock from Scheme" +sed 's/trait Scheme/trait SchemeBlock/' scheme.rs \ +| sed 's/fn handle(\&self, packet: \&mut Packet)/fn handle(\&self, packet: \&Packet) -> Option/' \ +| sed 's/packet.a = Error::mux(res);/res.transpose().map(Error::mux)/' \ +| sed 's/\.map(|f| f\.bits())/\.map(|f| f.map(|f| f.bits()))/' \ +| sed 's/\.map(|o| o as usize)/.map(|o| o.map(|o| o as usize))/' \ +| sed 's/Ok(0)/Ok(Some(0))/g' \ +| sed 's/Result<\([^>]\+\)>/Result>/g' \ +> scheme_block.rs + +echo "Generating SchemeBlockMut from SchemeBlock" +sed 's/trait SchemeBlock/trait SchemeBlockMut/' scheme_block.rs \ +| sed 's/\&self/\&mut self/g' \ +> scheme_block_mut.rs diff --git a/vendor/redox_syscall-0.3.5/src/scheme/mod.rs b/vendor/redox_syscall-0.3.5/src/scheme/mod.rs new file mode 100644 index 0000000000000..f65d1e2c06811 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/scheme/mod.rs @@ -0,0 +1,18 @@ +use core::{slice, str}; + +pub use self::scheme::Scheme; +pub use self::scheme_mut::SchemeMut; +pub use self::scheme_block::SchemeBlock; +pub use self::scheme_block_mut::SchemeBlockMut; +pub use self::seek::*; + +unsafe fn str_from_raw_parts(ptr: *const u8, len: usize) -> Option<&'static str> { + let slice = slice::from_raw_parts(ptr, len); + str::from_utf8(slice).ok() +} + +mod scheme; +mod scheme_mut; +mod scheme_block; +mod scheme_block_mut; +mod seek; diff --git a/vendor/redox_syscall-0.3.5/src/scheme/scheme.rs b/vendor/redox_syscall-0.3.5/src/scheme/scheme.rs new file mode 100644 index 0000000000000..6bf36172cd979 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/scheme/scheme.rs @@ -0,0 +1,206 @@ +use core::{mem, slice}; + +use crate::data::*; +use crate::error::*; +use crate::flag::*; +use crate::number::*; +use crate::scheme::str_from_raw_parts; + +pub trait Scheme { + fn handle(&self, packet: &mut Packet) { + let res = match packet.a { + SYS_OPEN => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.open(path, packet.d, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_RMDIR => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.rmdir(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_UNLINK => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.unlink(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + + SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o as usize), + SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), + SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), + SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.bits()), + SYS_FMAP_OLD => if packet.d >= mem::size_of::() { + self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FMAP => if packet.d >= mem::size_of::() { + self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FUNMAP_OLD => self.funmap_old(packet.b), + SYS_FUNMAP => self.funmap(packet.b, packet.c), + SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { + self.frename(packet.b, path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_FSTAT => if packet.d >= mem::size_of::() { + self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSTATVFS => if packet.d >= mem::size_of::() { + self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSYNC => self.fsync(packet.b), + SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), + SYS_FUTIMENS => if packet.d >= mem::size_of::() { + self.futimens(packet.b, unsafe { slice::from_raw_parts(packet.c as *const TimeSpec, packet.d / mem::size_of::()) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_CLOSE => self.close(packet.b), + _ => Err(Error::new(ENOSYS)) + }; + + packet.a = Error::mux(res); + } + + /* Scheme operations */ + + #[allow(unused_variables)] + fn open(&self, path: &str, flags: usize, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn chmod(&self, path: &str, mode: u16, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn rmdir(&self, path: &str, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn unlink(&self, path: &str, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + /* Resource operations */ + #[allow(unused_variables)] + fn dup(&self, old_id: usize, buf: &[u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn read(&self, id: usize, buf: &mut [u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn write(&self, id: usize, buf: &[u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn seek(&self, id: usize, pos: isize, whence: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchmod(&self, id: usize, mode: u16) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchown(&self, id: usize, uid: u32, gid: u32) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fevent(&self, id: usize, flags: EventFlags) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fmap_old(&self, id: usize, map: &OldMap) -> Result { + Err(Error::new(EBADF)) + } + #[allow(unused_variables)] + fn fmap(&self, id: usize, map: &Map) -> Result { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap_old(id, &OldMap { + offset: map.offset, + size: map.size, + flags: map.flags, + }) + } + + #[allow(unused_variables)] + fn funmap_old(&self, address: usize) -> Result { + Ok(0) + } + + #[allow(unused_variables)] + fn funmap(&self, address: usize, length: usize) -> Result { + Ok(0) + } + + #[allow(unused_variables)] + fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn frename(&self, id: usize, path: &str, uid: u32, gid: u32) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstat(&self, id: usize, stat: &mut Stat) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstatvfs(&self, id: usize, stat: &mut StatVfs) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fsync(&self, id: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn ftruncate(&self, id: usize, len: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn futimens(&self, id: usize, times: &[TimeSpec]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn close(&self, id: usize) -> Result { + Err(Error::new(EBADF)) + } +} diff --git a/vendor/redox_syscall-0.3.5/src/scheme/scheme_block.rs b/vendor/redox_syscall-0.3.5/src/scheme/scheme_block.rs new file mode 100644 index 0000000000000..3b3de4bc92291 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/scheme/scheme_block.rs @@ -0,0 +1,206 @@ +use core::{mem, slice}; + +use crate::data::*; +use crate::error::*; +use crate::flag::*; +use crate::number::*; +use crate::scheme::str_from_raw_parts; + +pub trait SchemeBlock { + fn handle(&self, packet: &Packet) -> Option { + let res = match packet.a { + SYS_OPEN => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.open(path, packet.d, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_RMDIR => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.rmdir(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_UNLINK => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.unlink(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + + SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o.map(|o| o as usize)), + SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), + SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), + SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.map(|f| f.bits())), + SYS_FMAP_OLD => if packet.d >= mem::size_of::() { + self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FMAP => if packet.d >= mem::size_of::() { + self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FUNMAP_OLD => self.funmap_old(packet.b), + SYS_FUNMAP => self.funmap(packet.b, packet.c), + SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { + self.frename(packet.b, path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_FSTAT => if packet.d >= mem::size_of::() { + self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSTATVFS => if packet.d >= mem::size_of::() { + self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSYNC => self.fsync(packet.b), + SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), + SYS_FUTIMENS => if packet.d >= mem::size_of::() { + self.futimens(packet.b, unsafe { slice::from_raw_parts(packet.c as *const TimeSpec, packet.d / mem::size_of::()) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_CLOSE => self.close(packet.b), + _ => Err(Error::new(ENOSYS)) + }; + + res.transpose().map(Error::mux) + } + + /* Scheme operations */ + + #[allow(unused_variables)] + fn open(&self, path: &str, flags: usize, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn chmod(&self, path: &str, mode: u16, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn rmdir(&self, path: &str, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn unlink(&self, path: &str, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + /* Resource operations */ + #[allow(unused_variables)] + fn dup(&self, old_id: usize, buf: &[u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn read(&self, id: usize, buf: &mut [u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn write(&self, id: usize, buf: &[u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn seek(&self, id: usize, pos: isize, whence: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchmod(&self, id: usize, mode: u16) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchown(&self, id: usize, uid: u32, gid: u32) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fevent(&self, id: usize, flags: EventFlags) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fmap_old(&self, id: usize, map: &OldMap) -> Result> { + Err(Error::new(EBADF)) + } + #[allow(unused_variables)] + fn fmap(&self, id: usize, map: &Map) -> Result> { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap_old(id, &OldMap { + offset: map.offset, + size: map.size, + flags: map.flags, + }) + } + + #[allow(unused_variables)] + fn funmap_old(&self, address: usize) -> Result> { + Ok(Some(0)) + } + + #[allow(unused_variables)] + fn funmap(&self, address: usize, length: usize) -> Result> { + Ok(Some(0)) + } + + #[allow(unused_variables)] + fn fpath(&self, id: usize, buf: &mut [u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn frename(&self, id: usize, path: &str, uid: u32, gid: u32) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstat(&self, id: usize, stat: &mut Stat) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstatvfs(&self, id: usize, stat: &mut StatVfs) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fsync(&self, id: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn ftruncate(&self, id: usize, len: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn futimens(&self, id: usize, times: &[TimeSpec]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn close(&self, id: usize) -> Result> { + Err(Error::new(EBADF)) + } +} diff --git a/vendor/redox_syscall-0.3.5/src/scheme/scheme_block_mut.rs b/vendor/redox_syscall-0.3.5/src/scheme/scheme_block_mut.rs new file mode 100644 index 0000000000000..1fae3a0e5ee6e --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/scheme/scheme_block_mut.rs @@ -0,0 +1,206 @@ +use core::{mem, slice}; + +use crate::data::*; +use crate::error::*; +use crate::flag::*; +use crate::number::*; +use crate::scheme::str_from_raw_parts; + +pub trait SchemeBlockMut { + fn handle(&mut self, packet: &Packet) -> Option { + let res = match packet.a { + SYS_OPEN => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.open(path, packet.d, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_RMDIR => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.rmdir(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_UNLINK => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.unlink(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + + SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o.map(|o| o as usize)), + SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), + SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), + SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.map(|f| f.bits())), + SYS_FMAP_OLD => if packet.d >= mem::size_of::() { + self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FMAP => if packet.d >= mem::size_of::() { + self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FUNMAP_OLD => self.funmap_old(packet.b), + SYS_FUNMAP => self.funmap(packet.b, packet.c), + SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { + self.frename(packet.b, path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_FSTAT => if packet.d >= mem::size_of::() { + self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSTATVFS => if packet.d >= mem::size_of::() { + self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSYNC => self.fsync(packet.b), + SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), + SYS_FUTIMENS => if packet.d >= mem::size_of::() { + self.futimens(packet.b, unsafe { slice::from_raw_parts(packet.c as *const TimeSpec, packet.d / mem::size_of::()) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_CLOSE => self.close(packet.b), + _ => Err(Error::new(ENOSYS)) + }; + + res.transpose().map(Error::mux) + } + + /* Scheme operations */ + + #[allow(unused_variables)] + fn open(&mut self, path: &str, flags: usize, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn chmod(&mut self, path: &str, mode: u16, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> Result> { + Err(Error::new(ENOENT)) + } + + /* Resource operations */ + #[allow(unused_variables)] + fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchmod(&mut self, id: usize, mode: u16) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fevent(&mut self, id: usize, flags: EventFlags) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fmap_old(&mut self, id: usize, map: &OldMap) -> Result> { + Err(Error::new(EBADF)) + } + #[allow(unused_variables)] + fn fmap(&mut self, id: usize, map: &Map) -> Result> { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap_old(id, &OldMap { + offset: map.offset, + size: map.size, + flags: map.flags, + }) + } + + #[allow(unused_variables)] + fn funmap_old(&mut self, address: usize) -> Result> { + Ok(Some(0)) + } + + #[allow(unused_variables)] + fn funmap(&mut self, address: usize, length: usize) -> Result> { + Ok(Some(0)) + } + + #[allow(unused_variables)] + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn frename(&mut self, id: usize, path: &str, uid: u32, gid: u32) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fsync(&mut self, id: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn ftruncate(&mut self, id: usize, len: usize) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn futimens(&mut self, id: usize, times: &[TimeSpec]) -> Result> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn close(&mut self, id: usize) -> Result> { + Err(Error::new(EBADF)) + } +} diff --git a/vendor/redox_syscall-0.3.5/src/scheme/scheme_mut.rs b/vendor/redox_syscall-0.3.5/src/scheme/scheme_mut.rs new file mode 100644 index 0000000000000..b364b62aaae77 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/scheme/scheme_mut.rs @@ -0,0 +1,206 @@ +use core::{mem, slice}; + +use crate::data::*; +use crate::error::*; +use crate::flag::*; +use crate::number::*; +use crate::scheme::str_from_raw_parts; + +pub trait SchemeMut { + fn handle(&mut self, packet: &mut Packet) { + let res = match packet.a { + SYS_OPEN => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.open(path, packet.d, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_RMDIR => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.rmdir(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_UNLINK => if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { + self.unlink(path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + + SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o as usize), + SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), + SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), + SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.bits()), + SYS_FMAP_OLD => if packet.d >= mem::size_of::() { + self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FMAP => if packet.d >= mem::size_of::() { + self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FUNMAP_OLD => self.funmap_old(packet.b), + SYS_FUNMAP => self.funmap(packet.b, packet.c), + SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { + self.frename(packet.b, path, packet.uid, packet.gid) + } else { + Err(Error::new(EINVAL)) + }, + SYS_FSTAT => if packet.d >= mem::size_of::() { + self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSTATVFS => if packet.d >= mem::size_of::() { + self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSYNC => self.fsync(packet.b), + SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), + SYS_FUTIMENS => if packet.d >= mem::size_of::() { + self.futimens(packet.b, unsafe { slice::from_raw_parts(packet.c as *const TimeSpec, packet.d / mem::size_of::()) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_CLOSE => self.close(packet.b), + _ => Err(Error::new(ENOSYS)) + }; + + packet.a = Error::mux(res); + } + + /* Scheme operations */ + + #[allow(unused_variables)] + fn open(&mut self, path: &str, flags: usize, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn chmod(&mut self, path: &str, mode: u16, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + + /* Resource operations */ + #[allow(unused_variables)] + fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn write(&mut self, id: usize, buf: &[u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchmod(&mut self, id: usize, mode: u16) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fevent(&mut self, id: usize, flags: EventFlags) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fmap_old(&mut self, id: usize, map: &OldMap) -> Result { + Err(Error::new(EBADF)) + } + #[allow(unused_variables)] + fn fmap(&mut self, id: usize, map: &Map) -> Result { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap_old(id, &OldMap { + offset: map.offset, + size: map.size, + flags: map.flags, + }) + } + + #[allow(unused_variables)] + fn funmap_old(&mut self, address: usize) -> Result { + Ok(0) + } + + #[allow(unused_variables)] + fn funmap(&mut self, address: usize, length: usize) -> Result { + Ok(0) + } + + #[allow(unused_variables)] + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn frename(&mut self, id: usize, path: &str, uid: u32, gid: u32) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fsync(&mut self, id: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn ftruncate(&mut self, id: usize, len: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn futimens(&mut self, id: usize, times: &[TimeSpec]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn close(&mut self, id: usize) -> Result { + Err(Error::new(EBADF)) + } +} diff --git a/vendor/redox_syscall-0.3.5/src/scheme/seek.rs b/vendor/redox_syscall-0.3.5/src/scheme/seek.rs new file mode 100644 index 0000000000000..09a45186ac6c8 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/scheme/seek.rs @@ -0,0 +1,33 @@ +use core::cmp; +use core::convert::TryFrom; +use crate::error::*; +use crate::flag::*; + +/// Helper for seek calls +/// In most cases it's easier to use a usize to track the offset and buffer size internally, +/// but the seek interface uses isize. This wrapper ensures EOVERFLOW errors are returned +/// as appropriate if the value in the usize can't fit in the isize. +pub fn calc_seek_offset_usize(cur_offset: usize, pos: isize, whence: usize, buf_len: usize) -> Result { + let cur_offset = isize::try_from(cur_offset).or_else(|_| Err(Error::new(EOVERFLOW)))?; + let buf_len = isize::try_from(buf_len).or_else(|_| Err(Error::new(EOVERFLOW)))?; + calc_seek_offset_isize(cur_offset, pos, whence, buf_len) +} + +/// Helper for seek calls +/// Result is guaranteed to be positive. +/// EOVERFLOW returned if the arguments would cause an overflow. +/// EINVAL returned if the new offset is out of bounds. +pub fn calc_seek_offset_isize(cur_offset: isize, pos: isize, whence: usize, buf_len: isize) -> Result { + let new_offset = match whence { + SEEK_CUR => pos.checked_add(cur_offset), + SEEK_END => pos.checked_add(buf_len), + SEEK_SET => Some(pos), + _ => None, + }; + + match new_offset { + Some(new_offset) if new_offset < 0 => Err(Error::new(EINVAL)), + Some(new_offset) => Ok(cmp::min(new_offset, buf_len)), + None => Err(Error::new(EOVERFLOW)) + } +} \ No newline at end of file diff --git a/vendor/redox_syscall-0.3.5/src/tests.rs b/vendor/redox_syscall-0.3.5/src/tests.rs new file mode 100644 index 0000000000000..fdff89b4b0cc4 --- /dev/null +++ b/vendor/redox_syscall-0.3.5/src/tests.rs @@ -0,0 +1,442 @@ +#[test] +fn clone() { + let expected_status = 42; + let pid_res = unsafe { crate::clone(crate::CloneFlags::empty()) }; + if pid_res == Ok(0) { + crate::exit(expected_status).unwrap(); + panic!("failed to exit"); + } else { + let pid = dbg!(pid_res).unwrap(); + let mut status = 0; + assert_eq!(dbg!(crate::waitpid(pid, &mut status, crate::WaitFlags::empty())), Ok(pid)); + assert_eq!(dbg!(crate::wifexited(status)), true); + assert_eq!(dbg!(crate::wexitstatus(status)), expected_status); + } +} + +//TODO: close + +#[test] +fn clock_gettime() { + let mut tp = crate::TimeSpec::default(); + assert_eq!(dbg!( + crate::clock_gettime(crate::CLOCK_MONOTONIC, &mut tp) + ), Ok(0)); + assert_ne!(dbg!(tp), crate::TimeSpec::default()); + + tp = crate::TimeSpec::default(); + assert_eq!(dbg!( + crate::clock_gettime(crate::CLOCK_REALTIME, &mut tp) + ), Ok(0)); + assert_ne!(dbg!(tp), crate::TimeSpec::default()); +} + +//TODO: dup + +//TODO: dup2 + +//TODO: exit (handled by clone?) + +//TODO: fchmod + +//TODO: fcntl + +#[test] +fn fexec() { + let name = "file:/bin/ls"; + + let fd = dbg!( + crate::open(name, crate::O_RDONLY | crate::O_CLOEXEC) + ).unwrap(); + + let args = &[ + [name.as_ptr() as usize, name.len()] + ]; + + let vars = &[]; + + let pid_res = unsafe { crate::clone(crate::CloneFlags::empty()) }; + if pid_res == Ok(0) { + crate::fexec(fd, args, vars).unwrap(); + panic!("failed to fexec"); + } else { + assert_eq!(dbg!(crate::close(fd)), Ok(0)); + + let pid = dbg!(pid_res).unwrap(); + let mut status = 0; + assert_eq!(dbg!(crate::waitpid(pid, &mut status, crate::WaitFlags::empty())), Ok(pid)); + assert_eq!(dbg!(crate::wifexited(status)), true); + assert_eq!(dbg!(crate::wexitstatus(status)), 0); + } +} + +#[test] +fn fmap() { + use std::slice; + + let fd = dbg!( + crate::open( + "file:/tmp/syscall-tests-fmap", + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + let size = 128; + + let map = unsafe { + slice::from_raw_parts_mut( + dbg!( + crate::fmap(fd, &crate::Map { + address: 0, + offset: 0, + size, + flags: crate::PROT_READ | crate::PROT_WRITE + }) + ).unwrap() as *mut u8, + 128 + ) + }; + + // Maps should be available after closing + assert_eq!(dbg!(crate::close(fd)), Ok(0)); + + for i in 0..128 { + map[i as usize] = i; + assert_eq!(map[i as usize], i); + } + + //TODO: add msync + unsafe { + assert_eq!(dbg!( + crate::funmap(map.as_mut_ptr() as usize, size) + ), Ok(0)); + } +} + +// funmap tested by fmap + +#[test] +fn fpath() { + use std::str; + + let path = "file:/tmp/syscall-tests-fpath"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + let mut buf = [0; 4096]; + let count = dbg!( + crate::fpath(fd, &mut buf) + ).unwrap(); + + assert_eq!(dbg!(str::from_utf8(&buf[..count])), Ok(path)); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); +} + +//TODO: frename + +#[test] +fn fstat() { + let path = "file:/tmp/syscall-tests-fstat"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + let mut stat = crate::Stat::default(); + assert_eq!(dbg!(crate::fstat(fd, &mut stat)), Ok(0)); + assert_ne!(dbg!(stat), crate::Stat::default()); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); +} + +#[test] +fn fstatvfs() { + let path = "file:/tmp/syscall-tests-fstatvfs"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + let mut statvfs = crate::StatVfs::default(); + assert_eq!(dbg!(crate::fstatvfs(fd, &mut statvfs)), Ok(0)); + assert_ne!(dbg!(statvfs), crate::StatVfs::default()); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); +} + +//TODO: fsync + +//TODO: ftruncate + +//TODO: futimens + +//TODO: futex + +#[test] +fn getegid() { + assert_eq!(crate::getegid(), Ok(0)); +} + +#[test] +fn getens() { + assert_eq!(crate::getens(), Ok(1)); +} + +#[test] +fn geteuid() { + assert_eq!(crate::geteuid(), Ok(0)); +} + +#[test] +fn getgid() { + assert_eq!(crate::getgid(), Ok(0)); +} + +#[test] +fn getns() { + assert_eq!(crate::getns(), Ok(1)); +} + +//TODO: getpid + +//TODO: getpgid + +//TODO: getppid + +#[test] +fn getuid() { + assert_eq!(crate::getuid(), Ok(0)); +} + +//TODO: iopl + +//TODO: kill + +//TODO: link (probably will not work) + +#[test] +fn lseek() { + let path = "file:/tmp/syscall-tests-lseek"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + { + let mut buf = [0; 256]; + for i in 0..buf.len() { + buf[i] = i as u8; + } + assert_eq!(dbg!(crate::write(fd, &buf)), Ok(buf.len())); + + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_CUR)), Ok(buf.len())); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0)); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_END)), Ok(buf.len())); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0)); + } + + { + let mut buf = [0; 256]; + assert_eq!(dbg!(crate::read(fd, &mut buf)), Ok(buf.len())); + for i in 0..buf.len() { + assert_eq!(buf[i], i as u8); + } + + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_CUR)), Ok(buf.len())); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0)); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_END)), Ok(buf.len())); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0)); + } + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); +} + +//TODO: mkns + +//TODO: mprotect + +#[test] +fn nanosleep() { + let req = crate::TimeSpec { + tv_sec: 0, + tv_nsec: 0, + }; + let mut rem = crate::TimeSpec::default(); + assert_eq!(crate::nanosleep(&req, &mut rem), Ok(0)); + assert_eq!(rem, crate::TimeSpec::default()); +} + +//TODO: open + +//TODO: physalloc + +//TODO: physfree + +//TODO: physmap + +//TODO: physunmap + +#[test] +fn pipe2() { + let mut fds = [0, 0]; + assert_eq!(dbg!(crate::pipe2(&mut fds, crate::O_CLOEXEC)), Ok(0)); + assert_ne!(dbg!(fds), [0, 0]); + + { + let mut buf = [0; 256]; + for i in 0..buf.len() { + buf[i] = i as u8; + } + assert_eq!(dbg!(crate::write(fds[1], &buf)), Ok(buf.len())); + } + + { + let mut buf = [0; 256]; + assert_eq!(dbg!(crate::read(fds[0], &mut buf)), Ok(buf.len())); + for i in 0..buf.len() { + assert_eq!(buf[i], i as u8); + } + } + + assert_eq!(dbg!(crate::close(fds[0])), Ok(0)); + assert_eq!(dbg!(crate::close(fds[1])), Ok(0)); +} + +//TODO: read + +#[test] +fn rmdir() { + let path = "file:/tmp/syscall-tests-rmdir"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_DIRECTORY | crate::O_CLOEXEC + ) + ).unwrap(); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); + + assert_eq!(dbg!(crate::rmdir(path)), Ok(0)); +} + +//TODO: setpgid + +//TODO: setregid + +//TODO: setrens + +//TODO: setreuid + +//TODO: sigaction + +//TODO: sigprocmask + +//TODO: sigreturn + +#[test] +fn umask() { + let old = dbg!(crate::umask(0o244)).unwrap(); + assert_eq!(dbg!(crate::umask(old)), Ok(0o244)); +} + +#[test] +fn unlink() { + let path = "file:/tmp/syscall-tests-unlink"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); + + assert_eq!(dbg!(crate::unlink(path)), Ok(0)); +} + +//TODO: virttophys + +// waitpid tested by clone + +//TODO: write + +#[test] +fn sched_yield() { + assert_eq!(dbg!(crate::sched_yield()), Ok(0)); +} + +#[test] +fn sigaction() { + use std::{ + mem, + sync::atomic::{AtomicBool, Ordering} + }; + + static SA_HANDLER_WAS_RAN: AtomicBool = AtomicBool::new(false); + static SA_HANDLER_2_WAS_IGNORED: AtomicBool = AtomicBool::new(false); + + let child = unsafe { crate::clone(crate::CLONE_VM).unwrap() }; + + if child == 0 { + let pid = crate::getpid().unwrap(); + + extern "C" fn hello_im_a_signal_handler(signal: usize) { + assert_eq!(signal, crate::SIGUSR1); + SA_HANDLER_WAS_RAN.store(true, Ordering::SeqCst); + } + + let my_signal_handler = crate::SigAction { + sa_handler: Some(hello_im_a_signal_handler), + ..Default::default() + }; + crate::sigaction(crate::SIGUSR1, Some(&my_signal_handler), None).unwrap(); + + crate::kill(pid, crate::SIGUSR1).unwrap(); // calls handler + + let mut old_signal_handler = crate::SigAction::default(); + crate::sigaction( + crate::SIGUSR1, + Some(&crate::SigAction { + sa_handler: unsafe { mem::transmute::>(crate::SIG_IGN) }, + ..Default::default() + }), + Some(&mut old_signal_handler) + ).unwrap(); + assert_eq!(my_signal_handler, old_signal_handler); + + crate::kill(pid, crate::SIGUSR1).unwrap(); // does nothing + + SA_HANDLER_2_WAS_IGNORED.store(true, Ordering::SeqCst); + + crate::sigaction( + crate::SIGUSR1, + Some(&crate::SigAction { + sa_handler: unsafe { mem::transmute::>(crate::SIG_DFL) }, + ..Default::default() + }), + Some(&mut old_signal_handler) + ).unwrap(); + + crate::kill(pid, crate::SIGUSR1).unwrap(); // actually exits + } else { + let mut status = 0; + dbg!(crate::waitpid(child, &mut status, crate::WaitFlags::empty())).unwrap(); + + assert!(crate::wifsignaled(status)); + assert_eq!(crate::wtermsig(status), crate::SIGUSR1); + + assert!(SA_HANDLER_WAS_RAN.load(Ordering::SeqCst)); + assert!(SA_HANDLER_2_WAS_IGNORED.load(Ordering::SeqCst)); + } +} diff --git a/vendor/redox_syscall/src/io/dma.rs b/vendor/redox_syscall/src/io/dma.rs new file mode 100644 index 0000000000000..0613fc9fc9b4c --- /dev/null +++ b/vendor/redox_syscall/src/io/dma.rs @@ -0,0 +1,219 @@ +use core::mem::{self, MaybeUninit}; +use core::ops::{Deref, DerefMut}; +use core::{ptr, slice}; + +use crate::Result; +use crate::{PartialAllocStrategy, PhysallocFlags, PhysmapFlags}; +use crate::arch::PAGE_SIZE; + +/// An RAII guard of a physical memory allocation. Currently all physically allocated memory are +/// page-aligned and take up at least 4k of space (on x86_64). +#[derive(Debug)] +pub struct PhysBox { + address: usize, + size: usize +} + +const fn round_up(x: usize) -> usize { + (x + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE +} +fn assert_aligned(x: usize) { + assert_eq!(x % PAGE_SIZE, 0); +} + +#[cfg(target_arch = "aarch64")] +fn physmap_flags() -> PhysmapFlags { + // aarch64 currently must map DMA memory without caching to ensure coherence + crate::PHYSMAP_NO_CACHE | crate::PHYSMAP_WRITE +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn physmap_flags() -> PhysmapFlags { + // x86 ensures cache coherence with DMA memory + crate::PHYSMAP_WRITE +} + +impl PhysBox { + /// Construct a PhysBox from an address and a size. The address must be page-aligned, and the + /// size must similarly be a multiple of the page size. + /// + /// # Safety + /// This function is unsafe because when dropping, Self has to a valid allocation. + pub unsafe fn from_raw_parts(address: usize, size: usize) -> Self { + assert_aligned(address); + assert_aligned(size); + + Self { + address, + size, + } + } + + /// Retrieve the byte address in physical memory, of this allocation. + pub fn address(&self) -> usize { + self.address + } + + /// Retrieve the size in bytes of the alloc. + pub fn size(&self) -> usize { + self.size + } + + /// Allocate physical memory that must reside in 32-bit space. + pub fn new_in_32bit_space(size: usize) -> Result { + Self::new_with_flags(size, PhysallocFlags::SPACE_32) + } + + pub fn new_with_flags(size: usize, flags: PhysallocFlags) -> Result { + assert!(!flags.contains(PhysallocFlags::PARTIAL_ALLOC)); + assert_aligned(size); + + let address = unsafe { crate::physalloc2(size, flags.bits())? }; + Ok(unsafe { Self::from_raw_parts(address, size) }) + } + + /// "Partially" allocate physical memory, in the sense that the allocation may be smaller than + /// expected, but still with a minimum limit. This is particularly useful when the physical + /// memory space is fragmented, and a device supports scatter-gather I/O. In that case, the + /// driver can optimistically request e.g. 1 alloc of 1 MiB, with the minimum of 512 KiB. If + /// that first allocation only returns half the size, the driver can do another allocation + /// and then let the device use both buffers. + pub fn new_partial_allocation(size: usize, flags: PhysallocFlags, strategy: Option, mut min: usize) -> Result { + assert_aligned(size); + debug_assert!(!(flags.contains(PhysallocFlags::PARTIAL_ALLOC) && strategy.is_none())); + + let address = unsafe { crate::physalloc3(size, flags.bits() | strategy.map_or(0, |s| s as usize), &mut min)? }; + Ok(unsafe { Self::from_raw_parts(address, size) }) + } + + pub fn new(size: usize) -> Result { + assert_aligned(size); + + let address = unsafe { crate::physalloc(size)? }; + Ok(unsafe { Self::from_raw_parts(address, size) }) + } +} + +impl Drop for PhysBox { + fn drop(&mut self) { + let _ = unsafe { crate::physfree(self.address, self.size) }; + } +} + +pub struct Dma { + phys: PhysBox, + virt: *mut T, +} + +impl Dma { + pub fn from_physbox_uninit(phys: PhysBox) -> Result>> { + let virt = unsafe { crate::physmap(phys.address, phys.size, physmap_flags())? } as *mut MaybeUninit; + + Ok(Dma { + phys, + virt, + }) + } + pub fn from_physbox_zeroed(phys: PhysBox) -> Result>> { + let this = Self::from_physbox_uninit(phys)?; + unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit, 0, this.phys.size) } + Ok(this) + } + + pub fn from_physbox(phys: PhysBox, value: T) -> Result { + let this = Self::from_physbox_uninit(phys)?; + + Ok(unsafe { + ptr::write(this.virt, MaybeUninit::new(value)); + this.assume_init() + }) + } + + pub fn new(value: T) -> Result { + let phys = PhysBox::new(round_up(mem::size_of::()))?; + Self::from_physbox(phys, value) + } + pub fn zeroed() -> Result>> { + let phys = PhysBox::new(round_up(mem::size_of::()))?; + Self::from_physbox_zeroed(phys) + } +} + +impl Dma> { + pub unsafe fn assume_init(self) -> Dma { + let &Dma { phys: PhysBox { address, size }, virt } = &self; + mem::forget(self); + + Dma { + phys: PhysBox { address, size }, + virt: virt as *mut T, + } + } +} +impl Dma { + pub fn physical(&self) -> usize { + self.phys.address() + } + pub fn size(&self) -> usize { + self.phys.size() + } + pub fn phys(&self) -> &PhysBox { + &self.phys + } +} + +impl Dma<[T]> { + pub fn from_physbox_uninit_unsized(phys: PhysBox, len: usize) -> Result]>> { + let max_len = phys.size() / mem::size_of::(); + assert!(len <= max_len); + + Ok(Dma { + virt: unsafe { slice::from_raw_parts_mut(crate::physmap(phys.address, phys.size, physmap_flags())? as *mut MaybeUninit, len) } as *mut [MaybeUninit], + phys, + }) + } + pub fn from_physbox_zeroed_unsized(phys: PhysBox, len: usize) -> Result]>> { + let this = Self::from_physbox_uninit_unsized(phys, len)?; + unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit, 0, this.phys.size()) } + Ok(this) + } + /// Creates a new DMA buffer with a size only known at runtime. + /// ## Safety + /// * `T` must be properly aligned. + /// * `T` must be valid as zeroed (i.e. no NonNull pointers). + pub unsafe fn zeroed_unsized(count: usize) -> Result { + let phys = PhysBox::new(round_up(mem::size_of::() * count))?; + Ok(Self::from_physbox_zeroed_unsized(phys, count)?.assume_init()) + } +} +impl Dma<[MaybeUninit]> { + pub unsafe fn assume_init(self) -> Dma<[T]> { + let &Dma { phys: PhysBox { address, size }, virt } = &self; + mem::forget(self); + + Dma { + phys: PhysBox { address, size }, + virt: virt as *mut [T], + } + } +} + +impl Deref for Dma { + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.virt } + } +} + +impl DerefMut for Dma { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.virt } + } +} + +impl Drop for Dma { + fn drop(&mut self) { + unsafe { ptr::drop_in_place(self.virt) } + let _ = unsafe { crate::funmap(self.virt as *mut u8 as usize, self.phys.size) }; + } +} diff --git a/vendor/redox_syscall/src/tests.rs b/vendor/redox_syscall/src/tests.rs new file mode 100644 index 0000000000000..06a3c011bcebd --- /dev/null +++ b/vendor/redox_syscall/src/tests.rs @@ -0,0 +1,416 @@ +#[test] +fn clone() { + let expected_status = 42; + let pid_res = unsafe { crate::clone(crate::CloneFlags::empty()) }; + if pid_res == Ok(0) { + crate::exit(expected_status).unwrap(); + panic!("failed to exit"); + } else { + let pid = dbg!(pid_res).unwrap(); + let mut status = 0; + assert_eq!(dbg!(crate::waitpid(pid, &mut status, crate::WaitFlags::empty())), Ok(pid)); + assert_eq!(dbg!(crate::wifexited(status)), true); + assert_eq!(dbg!(crate::wexitstatus(status)), expected_status); + } +} + +//TODO: close + +#[test] +fn clock_gettime() { + let mut tp = crate::TimeSpec::default(); + assert_eq!(dbg!( + crate::clock_gettime(crate::CLOCK_MONOTONIC, &mut tp) + ), Ok(0)); + assert_ne!(dbg!(tp), crate::TimeSpec::default()); + + tp = crate::TimeSpec::default(); + assert_eq!(dbg!( + crate::clock_gettime(crate::CLOCK_REALTIME, &mut tp) + ), Ok(0)); + assert_ne!(dbg!(tp), crate::TimeSpec::default()); +} + +//TODO: dup + +//TODO: dup2 + +//TODO: exit (handled by clone?) + +//TODO: fchmod + +//TODO: fcntl + +#[test] +fn fexec() { + let name = "file:/bin/ls"; + + let fd = dbg!( + crate::open(name, crate::O_RDONLY | crate::O_CLOEXEC) + ).unwrap(); + + let args = &[ + [name.as_ptr() as usize, name.len()] + ]; + + let vars = &[]; + + let pid_res = unsafe { crate::clone(crate::CloneFlags::empty()) }; + if pid_res == Ok(0) { + crate::fexec(fd, args, vars).unwrap(); + panic!("failed to fexec"); + } else { + assert_eq!(dbg!(crate::close(fd)), Ok(0)); + + let pid = dbg!(pid_res).unwrap(); + let mut status = 0; + assert_eq!(dbg!(crate::waitpid(pid, &mut status, crate::WaitFlags::empty())), Ok(pid)); + assert_eq!(dbg!(crate::wifexited(status)), true); + assert_eq!(dbg!(crate::wexitstatus(status)), 0); + } +} + +#[test] +fn fmap() { + use std::slice; + + let fd = dbg!( + crate::open( + "file:/tmp/syscall-tests-fmap", + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + let size = 128; + + let map = unsafe { + slice::from_raw_parts_mut( + dbg!( + crate::fmap(fd, &crate::Map { + address: 0, + offset: 0, + size, + flags: crate::PROT_READ | crate::PROT_WRITE + }) + ).unwrap() as *mut u8, + 128 + ) + }; + + // Maps should be available after closing + assert_eq!(dbg!(crate::close(fd)), Ok(0)); + + for i in 0..128 { + map[i as usize] = i; + assert_eq!(map[i as usize], i); + } + + //TODO: add msync + unsafe { + assert_eq!(dbg!( + crate::funmap(map.as_mut_ptr() as usize, size) + ), Ok(0)); + } +} + +// funmap tested by fmap + +#[test] +fn fpath() { + use std::str; + + let path = "file:/tmp/syscall-tests-fpath"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + let mut buf = [0; 4096]; + let count = dbg!( + crate::fpath(fd, &mut buf) + ).unwrap(); + + assert_eq!(dbg!(str::from_utf8(&buf[..count])), Ok(path)); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); +} + +//TODO: frename + +#[test] +fn fstat() { + let path = "file:/tmp/syscall-tests-fstat"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + let mut stat = crate::Stat::default(); + assert_eq!(dbg!(crate::fstat(fd, &mut stat)), Ok(0)); + assert_ne!(dbg!(stat), crate::Stat::default()); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); +} + +#[test] +fn fstatvfs() { + let path = "file:/tmp/syscall-tests-fstatvfs"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + let mut statvfs = crate::StatVfs::default(); + assert_eq!(dbg!(crate::fstatvfs(fd, &mut statvfs)), Ok(0)); + assert_ne!(dbg!(statvfs), crate::StatVfs::default()); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); +} + +//TODO: fsync + +//TODO: ftruncate + +//TODO: futimens + +//TODO: futex + +#[test] +fn getegid() { + assert_eq!(crate::getegid(), Ok(0)); +} + +#[test] +fn getens() { + assert_eq!(crate::getens(), Ok(1)); +} + +#[test] +fn geteuid() { + assert_eq!(crate::geteuid(), Ok(0)); +} + +#[test] +fn getgid() { + assert_eq!(crate::getgid(), Ok(0)); +} + +#[test] +fn getns() { + assert_eq!(crate::getns(), Ok(1)); +} + +//TODO: getpid + +//TODO: getpgid + +//TODO: getppid + +#[test] +fn getuid() { + assert_eq!(crate::getuid(), Ok(0)); +} + +//TODO: iopl + +//TODO: kill + +//TODO: link (probably will not work) + +#[test] +fn lseek() { + let path = "file:/tmp/syscall-tests-lseek"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + { + let mut buf = [0; 256]; + for i in 0..buf.len() { + buf[i] = i as u8; + } + assert_eq!(dbg!(crate::write(fd, &buf)), Ok(buf.len())); + + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_CUR)), Ok(buf.len())); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0)); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_END)), Ok(buf.len())); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0)); + } + + { + let mut buf = [0; 256]; + assert_eq!(dbg!(crate::read(fd, &mut buf)), Ok(buf.len())); + for i in 0..buf.len() { + assert_eq!(buf[i], i as u8); + } + + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_CUR)), Ok(buf.len())); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0)); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_END)), Ok(buf.len())); + assert_eq!(dbg!(crate::lseek(fd, 0, crate::SEEK_SET)), Ok(0)); + } + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); +} + +//TODO: mkns + +//TODO: mprotect + +#[test] +fn nanosleep() { + let req = crate::TimeSpec { + tv_sec: 0, + tv_nsec: 0, + }; + let mut rem = crate::TimeSpec::default(); + assert_eq!(crate::nanosleep(&req, &mut rem), Ok(0)); + assert_eq!(rem, crate::TimeSpec::default()); +} + +//TODO: open + +//TODO: physalloc + +//TODO: physfree + +//TODO: physmap + +//TODO: physunmap + +//TODO: read + +#[test] +fn rmdir() { + let path = "file:/tmp/syscall-tests-rmdir"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_DIRECTORY | crate::O_CLOEXEC + ) + ).unwrap(); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); + + assert_eq!(dbg!(crate::rmdir(path)), Ok(0)); +} + +//TODO: setpgid + +//TODO: setregid + +//TODO: setrens + +//TODO: setreuid + +//TODO: sigaction + +//TODO: sigprocmask + +//TODO: sigreturn + +#[test] +fn umask() { + let old = dbg!(crate::umask(0o244)).unwrap(); + assert_eq!(dbg!(crate::umask(old)), Ok(0o244)); +} + +#[test] +fn unlink() { + let path = "file:/tmp/syscall-tests-unlink"; + let fd = dbg!( + crate::open( + dbg!(path), + crate::O_CREAT | crate::O_RDWR | crate::O_CLOEXEC + ) + ).unwrap(); + + assert_eq!(dbg!(crate::close(fd)), Ok(0)); + + assert_eq!(dbg!(crate::unlink(path)), Ok(0)); +} + +//TODO: virttophys + +// waitpid tested by clone + +//TODO: write + +#[test] +fn sched_yield() { + assert_eq!(dbg!(crate::sched_yield()), Ok(0)); +} + +#[test] +fn sigaction() { + use std::{ + mem, + sync::atomic::{AtomicBool, Ordering} + }; + + static SA_HANDLER_WAS_RAN: AtomicBool = AtomicBool::new(false); + static SA_HANDLER_2_WAS_IGNORED: AtomicBool = AtomicBool::new(false); + + let child = unsafe { crate::clone(crate::CLONE_VM).unwrap() }; + + if child == 0 { + let pid = crate::getpid().unwrap(); + + extern "C" fn hello_im_a_signal_handler(signal: usize) { + assert_eq!(signal, crate::SIGUSR1); + SA_HANDLER_WAS_RAN.store(true, Ordering::SeqCst); + } + + let my_signal_handler = crate::SigAction { + sa_handler: Some(hello_im_a_signal_handler), + ..Default::default() + }; + crate::sigaction(crate::SIGUSR1, Some(&my_signal_handler), None).unwrap(); + + crate::kill(pid, crate::SIGUSR1).unwrap(); // calls handler + + let mut old_signal_handler = crate::SigAction::default(); + crate::sigaction( + crate::SIGUSR1, + Some(&crate::SigAction { + sa_handler: unsafe { mem::transmute::>(crate::SIG_IGN) }, + ..Default::default() + }), + Some(&mut old_signal_handler) + ).unwrap(); + assert_eq!(my_signal_handler, old_signal_handler); + + crate::kill(pid, crate::SIGUSR1).unwrap(); // does nothing + + SA_HANDLER_2_WAS_IGNORED.store(true, Ordering::SeqCst); + + crate::sigaction( + crate::SIGUSR1, + Some(&crate::SigAction { + sa_handler: unsafe { mem::transmute::>(crate::SIG_DFL) }, + ..Default::default() + }), + Some(&mut old_signal_handler) + ).unwrap(); + + crate::kill(pid, crate::SIGUSR1).unwrap(); // actually exits + } else { + let mut status = 0; + dbg!(crate::waitpid(child, &mut status, crate::WaitFlags::empty())).unwrap(); + + assert!(crate::wifsignaled(status)); + assert_eq!(crate::wtermsig(status), crate::SIGUSR1); + + assert!(SA_HANDLER_WAS_RAN.load(Ordering::SeqCst)); + assert!(SA_HANDLER_2_WAS_IGNORED.load(Ordering::SeqCst)); + } +} diff --git a/vendor/regex-syntax-0.7.5/.cargo-checksum.json b/vendor/regex-syntax-0.7.5/.cargo-checksum.json new file mode 100644 index 0000000000000..b37c799e88a06 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"cddce5fdfc6f46bbf659bda143f7b659487ed3912d66c86a1173735485316fbd","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"b2484aa7e66fb92d1378e9a7ce7605af18f77cb12c179866eaf92ba28cfec1d9","benches/bench.rs":"d2b6ae5b939abd6093064f144b981b7739d7f474ec0698a1268052fc92406635","src/ast/mod.rs":"f3412bf62ca9976079fffbb42784491dd69215e6fa0e14340e8ad2c7bef18184","src/ast/parse.rs":"27c666cc74931894a839ed4dd2191c4c33837320b24332d5c6c9564cf89f0afd","src/ast/print.rs":"62d319cd0b7e6f437dc8dcaf798046a44afa03e9aeb6a384d5cffa448383af53","src/ast/visitor.rs":"e97ca0a38aaa145dd928261e8e13d1ec7a6ae37534e92a24c93ea007b0c16a7d","src/debug.rs":"7a16cca02be9715fdc8c26a32279465774623cd12fab1ec59ac25a6e3047817f","src/either.rs":"1758e3edd056884eccadd995708d1e374ba9aa65846bd0e13b1aae852607c560","src/error.rs":"01a67e3407b0d0d869119363e47a94d92158834bfe5936366c2e3f6f4ed13f36","src/hir/interval.rs":"2358e74b4d4aabfa62f79df855fd5d183779b86c4e14aae4ee42d8695bb3d010","src/hir/literal.rs":"2c8066c18ee1783343bb06ced01ca32f6b8a581ac020378965a57375c4832e88","src/hir/mod.rs":"bf2bd12c4ab6d5420e131aee193c5885d465a15f1d91d67fcf773e6c9c2a23d8","src/hir/print.rs":"c24eab0e29db7547d3d7f86b8bf19239265d6b114244f5e71a9904e7ae9e9c67","src/hir/translate.rs":"c84d930e156883c5dbad3a0c4500e6659c1f3c55dd6e4caa28b157da681ddb7c","src/hir/visitor.rs":"71ca9c93aa48a5ed445399659fa6455093a1bbd9ef44b66bc7095c1b08b2ec1f","src/lib.rs":"d2891213d00edb99b26ab93bd53749a85f0a6b2a71a1addbed9d2c4969a7515f","src/parser.rs":"6b2f4f27e3331a01a25b87c89368dd2e54396bd425dac57941f9c1ebfd238ac8","src/rank.rs":"ff3d58b0cc5ffa69e2e8c56fc7d9ef41dd399d59a639a253a51551b858cb5bbd","src/unicode.rs":"9829458ef321b3bc22c21eae4b22805b33f8b5e67022928ffd9a9e0287bc7c31","src/unicode_tables/LICENSE-UNICODE":"74db5baf44a41b1000312c673544b3374e4198af5605c7f9080a402cec42cfa3","src/unicode_tables/age.rs":"2a2599a4e406fbbd0efd16aa6ce385c3f97b87c34820d6686a9f9113a5231c67","src/unicode_tables/case_folding_simple.rs":"9583803d4a10486da372b76979dbd26349b40766229467238eff972c1d78e47b","src/unicode_tables/general_category.rs":"36a93ba1cdeed96a00ff29a5ab5afd2c578a89541bf4dd8b18478146cebda0aa","src/unicode_tables/grapheme_cluster_break.rs":"39c388e9805a8391d3d3e69d74d831ce4fb99aa7e13e52c64dd2bd16d4765301","src/unicode_tables/mod.rs":"26c837099cd934c8062e24bc9a0aaecf15fe1de03f9c6da3f3e1e5ac3ca24bee","src/unicode_tables/perl_decimal.rs":"a98ea4afe71c2947023ae12bd25c46bf4c7de48eeb40979eca5c96ba62cee02e","src/unicode_tables/perl_space.rs":"ea2b3b84b4a48334082dadc6c37d9fcc9c9ded84b40e8f5c9c9314898638967e","src/unicode_tables/perl_word.rs":"6f1156bd6af32151ecffea4abe07a38fa04b1fc1b227ec1a8dac5d5f08d9d74b","src/unicode_tables/property_bool.rs":"0bd64f6e3228eaecf47824e238bdf1f8a9eef113ace6e790a57f045a8106701c","src/unicode_tables/property_names.rs":"5ca25437927eb70c62adf7d038e99a601cfb8a718677fd6de832589664d3c481","src/unicode_tables/property_values.rs":"5b4cc02392d382cf7af60455fc87b9980e97409b62a4b8d6c5843190d2e2d21d","src/unicode_tables/script.rs":"ea1d771b6d0a4b12d143f9bad2ea9342a0887878cbbe3c11262b6eabedaf2dd4","src/unicode_tables/script_extension.rs":"beeb8349703d903ff861beb8401bfd2599e457dc25df872e69d6ad1615f8b5e9","src/unicode_tables/sentence_break.rs":"2befe2a27cc4e8aecb624e310ef9f371462470dd3b2f572cec1f5873a5e30aa9","src/unicode_tables/word_break.rs":"94679177731b515f0c360eff394286a1f99b59527bdbc826cbf51d32f9666187","src/utf8.rs":"e9a13623a94295b81969c5483de17219ff74bb20768be13c527010351245acbd","test":"c7de5fbc0010d9b5b758cd49956375a64b88601c068167fd366808950257f108"},"package":"dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"} \ No newline at end of file diff --git a/vendor/regex-syntax-0.7.5/Cargo.toml b/vendor/regex-syntax-0.7.5/Cargo.toml new file mode 100644 index 0000000000000..638694f18a151 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/Cargo.toml @@ -0,0 +1,61 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.60.0" +name = "regex-syntax" +version = "0.7.5" +authors = [ + "The Rust Project Developers", + "Andrew Gallant ", +] +description = "A regular expression parser." +documentation = "https://docs.rs/regex-syntax" +readme = "README.md" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/regex/tree/master/regex-syntax" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.arbitrary] +version = "1.3.0" +features = ["derive"] +optional = true + +[features] +arbitrary = ["dep:arbitrary"] +default = [ + "std", + "unicode", +] +std = [] +unicode = [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment", +] +unicode-age = [] +unicode-bool = [] +unicode-case = [] +unicode-gencat = [] +unicode-perl = [] +unicode-script = [] +unicode-segment = [] diff --git a/vendor/regex-syntax-0.7.5/LICENSE-APACHE b/vendor/regex-syntax-0.7.5/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/regex-syntax-0.7.5/LICENSE-MIT b/vendor/regex-syntax-0.7.5/LICENSE-MIT new file mode 100644 index 0000000000000..39d4bdb5acd31 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/regex-syntax-0.7.5/README.md b/vendor/regex-syntax-0.7.5/README.md new file mode 100644 index 0000000000000..529513b0c8e97 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/README.md @@ -0,0 +1,96 @@ +regex-syntax +============ +This crate provides a robust regular expression parser. + +[![Build status](https://github.com/rust-lang/regex/workflows/ci/badge.svg)](https://github.com/rust-lang/regex/actions) +[![Crates.io](https://img.shields.io/crates/v/regex-syntax.svg)](https://crates.io/crates/regex-syntax) + + +### Documentation + +https://docs.rs/regex-syntax + + +### Overview + +There are two primary types exported by this crate: `Ast` and `Hir`. The former +is a faithful abstract syntax of a regular expression, and can convert regular +expressions back to their concrete syntax while mostly preserving its original +form. The latter type is a high level intermediate representation of a regular +expression that is amenable to analysis and compilation into byte codes or +automata. An `Hir` achieves this by drastically simplifying the syntactic +structure of the regular expression. While an `Hir` can be converted back to +its equivalent concrete syntax, the result is unlikely to resemble the original +concrete syntax that produced the `Hir`. + + +### Example + +This example shows how to parse a pattern string into its HIR: + +```rust +use regex_syntax::{hir::Hir, parse}; + +let hir = parse("a|b").unwrap(); +assert_eq!(hir, Hir::alternation(vec![ + Hir::literal("a".as_bytes()), + Hir::literal("b".as_bytes()), +])); +``` + + +### Safety + +This crate has no `unsafe` code and sets `forbid(unsafe_code)`. While it's +possible this crate could use `unsafe` code in the future, the standard +for doing so is extremely high. In general, most code in this crate is not +performance critical, since it tends to be dwarfed by the time it takes to +compile a regular expression into an automaton. Therefore, there is little need +for extreme optimization, and therefore, use of `unsafe`. + +The standard for using `unsafe` in this crate is extremely high because this +crate is intended to be reasonably safe to use with user supplied regular +expressions. Therefore, while there may be bugs in the regex parser itself, +they should _never_ result in memory unsafety unless there is either a bug +in the compiler or the standard library. (Since `regex-syntax` has zero +dependencies.) + + +### Crate features + +By default, this crate bundles a fairly large amount of Unicode data tables +(a source size of ~750KB). Because of their large size, one can disable some +or all of these data tables. If a regular expression attempts to use Unicode +data that is not available, then an error will occur when translating the `Ast` +to the `Hir`. + +The full set of features one can disable are +[in the "Crate features" section of the documentation](https://docs.rs/regex-syntax/*/#crate-features). + + +### Testing + +Simply running `cargo test` will give you very good coverage. However, because +of the large number of features exposed by this crate, a `test` script is +included in this directory which will test several feature combinations. This +is the same script that is run in CI. + + +### Motivation + +The primary purpose of this crate is to provide the parser used by `regex`. +Specifically, this crate is treated as an implementation detail of the `regex`, +and is primarily developed for the needs of `regex`. + +Since this crate is an implementation detail of `regex`, it may experience +breaking change releases at a different cadence from `regex`. This is only +possible because this crate is _not_ a public dependency of `regex`. + +Another consequence of this de-coupling is that there is no direct way to +compile a `regex::Regex` from a `regex_syntax::hir::Hir`. Instead, one must +first convert the `Hir` to a string (via its `std::fmt::Display`) and then +compile that via `Regex::new`. While this does repeat some work, compilation +typically takes much longer than parsing. + +Stated differently, the coupling between `regex` and `regex-syntax` exists only +at the level of the concrete syntax. diff --git a/vendor/regex-syntax-0.7.5/benches/bench.rs b/vendor/regex-syntax-0.7.5/benches/bench.rs new file mode 100644 index 0000000000000..d4703d4fc1ebf --- /dev/null +++ b/vendor/regex-syntax-0.7.5/benches/bench.rs @@ -0,0 +1,63 @@ +#![feature(test)] + +extern crate test; + +use regex_syntax::Parser; +use test::Bencher; + +#[bench] +fn parse_simple1(b: &mut Bencher) { + b.iter(|| { + let re = r"^bc(d|e)*$"; + Parser::new().parse(re).unwrap() + }); +} + +#[bench] +fn parse_simple2(b: &mut Bencher) { + b.iter(|| { + let re = r"'[a-zA-Z_][a-zA-Z0-9_]*(')\b"; + Parser::new().parse(re).unwrap() + }); +} + +#[bench] +fn parse_small1(b: &mut Bencher) { + b.iter(|| { + let re = r"\p{L}|\p{N}|\s|.|\d"; + Parser::new().parse(re).unwrap() + }); +} + +#[bench] +fn parse_medium1(b: &mut Bencher) { + b.iter(|| { + let re = r"\pL\p{Greek}\p{Hiragana}\p{Alphabetic}\p{Hebrew}\p{Arabic}"; + Parser::new().parse(re).unwrap() + }); +} + +#[bench] +fn parse_medium2(b: &mut Bencher) { + b.iter(|| { + let re = r"\s\S\w\W\d\D"; + Parser::new().parse(re).unwrap() + }); +} + +#[bench] +fn parse_medium3(b: &mut Bencher) { + b.iter(|| { + let re = + r"\p{age:3.2}\p{hira}\p{scx:hira}\p{alphabetic}\p{sc:Greek}\pL"; + Parser::new().parse(re).unwrap() + }); +} + +#[bench] +fn parse_huge(b: &mut Bencher) { + b.iter(|| { + let re = r"\p{L}{100}"; + Parser::new().parse(re).unwrap() + }); +} diff --git a/vendor/regex-syntax-0.7.5/src/ast/mod.rs b/vendor/regex-syntax-0.7.5/src/ast/mod.rs new file mode 100644 index 0000000000000..9e4284fee87e8 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/ast/mod.rs @@ -0,0 +1,1697 @@ +/*! +Defines an abstract syntax for regular expressions. +*/ + +use core::cmp::Ordering; + +use alloc::{boxed::Box, string::String, vec, vec::Vec}; + +pub use crate::ast::visitor::{visit, Visitor}; + +pub mod parse; +pub mod print; +mod visitor; + +/// An error that occurred while parsing a regular expression into an abstract +/// syntax tree. +/// +/// Note that not all ASTs represents a valid regular expression. For example, +/// an AST is constructed without error for `\p{Quux}`, but `Quux` is not a +/// valid Unicode property name. That particular error is reported when +/// translating an AST to the high-level intermediate representation (`HIR`). +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct Error { + /// The kind of error. + kind: ErrorKind, + /// The original pattern that the parser generated the error from. Every + /// span in an error is a valid range into this string. + pattern: String, + /// The span of this error. + span: Span, +} + +impl Error { + /// Return the type of this error. + pub fn kind(&self) -> &ErrorKind { + &self.kind + } + + /// The original pattern string in which this error occurred. + /// + /// Every span reported by this error is reported in terms of this string. + pub fn pattern(&self) -> &str { + &self.pattern + } + + /// Return the span at which this error occurred. + pub fn span(&self) -> &Span { + &self.span + } + + /// Return an auxiliary span. This span exists only for some errors that + /// benefit from being able to point to two locations in the original + /// regular expression. For example, "duplicate" errors will have the + /// main error position set to the duplicate occurrence while its + /// auxiliary span will be set to the initial occurrence. + pub fn auxiliary_span(&self) -> Option<&Span> { + use self::ErrorKind::*; + match self.kind { + FlagDuplicate { ref original } => Some(original), + FlagRepeatedNegation { ref original, .. } => Some(original), + GroupNameDuplicate { ref original, .. } => Some(original), + _ => None, + } + } +} + +/// The type of an error that occurred while building an AST. +/// +/// This error type is marked as `non_exhaustive`. This means that adding a +/// new variant is not considered a breaking change. +#[non_exhaustive] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum ErrorKind { + /// The capturing group limit was exceeded. + /// + /// Note that this represents a limit on the total number of capturing + /// groups in a regex and not necessarily the number of nested capturing + /// groups. That is, the nest limit can be low and it is still possible for + /// this error to occur. + CaptureLimitExceeded, + /// An invalid escape sequence was found in a character class set. + ClassEscapeInvalid, + /// An invalid character class range was found. An invalid range is any + /// range where the start is greater than the end. + ClassRangeInvalid, + /// An invalid range boundary was found in a character class. Range + /// boundaries must be a single literal codepoint, but this error indicates + /// that something else was found, such as a nested class. + ClassRangeLiteral, + /// An opening `[` was found with no corresponding closing `]`. + ClassUnclosed, + /// Note that this error variant is no longer used. Namely, a decimal + /// number can only appear as a repetition quantifier. When the number + /// in a repetition quantifier is empty, then it gets its own specialized + /// error, `RepetitionCountDecimalEmpty`. + DecimalEmpty, + /// An invalid decimal number was given where one was expected. + DecimalInvalid, + /// A bracketed hex literal was empty. + EscapeHexEmpty, + /// A bracketed hex literal did not correspond to a Unicode scalar value. + EscapeHexInvalid, + /// An invalid hexadecimal digit was found. + EscapeHexInvalidDigit, + /// EOF was found before an escape sequence was completed. + EscapeUnexpectedEof, + /// An unrecognized escape sequence. + EscapeUnrecognized, + /// A dangling negation was used when setting flags, e.g., `i-`. + FlagDanglingNegation, + /// A flag was used twice, e.g., `i-i`. + FlagDuplicate { + /// The position of the original flag. The error position + /// points to the duplicate flag. + original: Span, + }, + /// The negation operator was used twice, e.g., `-i-s`. + FlagRepeatedNegation { + /// The position of the original negation operator. The error position + /// points to the duplicate negation operator. + original: Span, + }, + /// Expected a flag but got EOF, e.g., `(?`. + FlagUnexpectedEof, + /// Unrecognized flag, e.g., `a`. + FlagUnrecognized, + /// A duplicate capture name was found. + GroupNameDuplicate { + /// The position of the initial occurrence of the capture name. The + /// error position itself points to the duplicate occurrence. + original: Span, + }, + /// A capture group name is empty, e.g., `(?P<>abc)`. + GroupNameEmpty, + /// An invalid character was seen for a capture group name. This includes + /// errors where the first character is a digit (even though subsequent + /// characters are allowed to be digits). + GroupNameInvalid, + /// A closing `>` could not be found for a capture group name. + GroupNameUnexpectedEof, + /// An unclosed group, e.g., `(ab`. + /// + /// The span of this error corresponds to the unclosed parenthesis. + GroupUnclosed, + /// An unopened group, e.g., `ab)`. + GroupUnopened, + /// The nest limit was exceeded. The limit stored here is the limit + /// configured in the parser. + NestLimitExceeded(u32), + /// The range provided in a counted repetition operator is invalid. The + /// range is invalid if the start is greater than the end. + RepetitionCountInvalid, + /// An opening `{` was not followed by a valid decimal value. + /// For example, `x{}` or `x{]}` would fail. + RepetitionCountDecimalEmpty, + /// An opening `{` was found with no corresponding closing `}`. + RepetitionCountUnclosed, + /// A repetition operator was applied to a missing sub-expression. This + /// occurs, for example, in the regex consisting of just a `*` or even + /// `(?i)*`. It is, however, possible to create a repetition operating on + /// an empty sub-expression. For example, `()*` is still considered valid. + RepetitionMissing, + /// The Unicode class is not valid. This typically occurs when a `\p` is + /// followed by something other than a `{`. + UnicodeClassInvalid, + /// When octal support is disabled, this error is produced when an octal + /// escape is used. The octal escape is assumed to be an invocation of + /// a backreference, which is the common case. + UnsupportedBackreference, + /// When syntax similar to PCRE's look-around is used, this error is + /// returned. Some example syntaxes that are rejected include, but are + /// not necessarily limited to, `(?=re)`, `(?!re)`, `(?<=re)` and + /// `(?) -> core::fmt::Result { + crate::error::Formatter::from(self).fmt(f) + } +} + +impl core::fmt::Display for ErrorKind { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use self::ErrorKind::*; + match *self { + CaptureLimitExceeded => write!( + f, + "exceeded the maximum number of \ + capturing groups ({})", + u32::MAX + ), + ClassEscapeInvalid => { + write!(f, "invalid escape sequence found in character class") + } + ClassRangeInvalid => write!( + f, + "invalid character class range, \ + the start must be <= the end" + ), + ClassRangeLiteral => { + write!(f, "invalid range boundary, must be a literal") + } + ClassUnclosed => write!(f, "unclosed character class"), + DecimalEmpty => write!(f, "decimal literal empty"), + DecimalInvalid => write!(f, "decimal literal invalid"), + EscapeHexEmpty => write!(f, "hexadecimal literal empty"), + EscapeHexInvalid => { + write!(f, "hexadecimal literal is not a Unicode scalar value") + } + EscapeHexInvalidDigit => write!(f, "invalid hexadecimal digit"), + EscapeUnexpectedEof => write!( + f, + "incomplete escape sequence, \ + reached end of pattern prematurely" + ), + EscapeUnrecognized => write!(f, "unrecognized escape sequence"), + FlagDanglingNegation => { + write!(f, "dangling flag negation operator") + } + FlagDuplicate { .. } => write!(f, "duplicate flag"), + FlagRepeatedNegation { .. } => { + write!(f, "flag negation operator repeated") + } + FlagUnexpectedEof => { + write!(f, "expected flag but got end of regex") + } + FlagUnrecognized => write!(f, "unrecognized flag"), + GroupNameDuplicate { .. } => { + write!(f, "duplicate capture group name") + } + GroupNameEmpty => write!(f, "empty capture group name"), + GroupNameInvalid => write!(f, "invalid capture group character"), + GroupNameUnexpectedEof => write!(f, "unclosed capture group name"), + GroupUnclosed => write!(f, "unclosed group"), + GroupUnopened => write!(f, "unopened group"), + NestLimitExceeded(limit) => write!( + f, + "exceed the maximum number of \ + nested parentheses/brackets ({})", + limit + ), + RepetitionCountInvalid => write!( + f, + "invalid repetition count range, \ + the start must be <= the end" + ), + RepetitionCountDecimalEmpty => { + write!(f, "repetition quantifier expects a valid decimal") + } + RepetitionCountUnclosed => { + write!(f, "unclosed counted repetition") + } + RepetitionMissing => { + write!(f, "repetition operator missing expression") + } + UnicodeClassInvalid => { + write!(f, "invalid Unicode character class") + } + UnsupportedBackreference => { + write!(f, "backreferences are not supported") + } + UnsupportedLookAround => write!( + f, + "look-around, including look-ahead and look-behind, \ + is not supported" + ), + } + } +} + +/// Span represents the position information of a single AST item. +/// +/// All span positions are absolute byte offsets that can be used on the +/// original regular expression that was parsed. +#[derive(Clone, Copy, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct Span { + /// The start byte offset. + pub start: Position, + /// The end byte offset. + pub end: Position, +} + +impl core::fmt::Debug for Span { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Span({:?}, {:?})", self.start, self.end) + } +} + +impl Ord for Span { + fn cmp(&self, other: &Span) -> Ordering { + (&self.start, &self.end).cmp(&(&other.start, &other.end)) + } +} + +impl PartialOrd for Span { + fn partial_cmp(&self, other: &Span) -> Option { + Some(self.cmp(other)) + } +} + +/// A single position in a regular expression. +/// +/// A position encodes one half of a span, and include the byte offset, line +/// number and column number. +#[derive(Clone, Copy, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct Position { + /// The absolute offset of this position, starting at `0` from the + /// beginning of the regular expression pattern string. + pub offset: usize, + /// The line number, starting at `1`. + pub line: usize, + /// The approximate column number, starting at `1`. + pub column: usize, +} + +impl core::fmt::Debug for Position { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "Position(o: {:?}, l: {:?}, c: {:?})", + self.offset, self.line, self.column + ) + } +} + +impl Ord for Position { + fn cmp(&self, other: &Position) -> Ordering { + self.offset.cmp(&other.offset) + } +} + +impl PartialOrd for Position { + fn partial_cmp(&self, other: &Position) -> Option { + Some(self.cmp(other)) + } +} + +impl Span { + /// Create a new span with the given positions. + pub fn new(start: Position, end: Position) -> Span { + Span { start, end } + } + + /// Create a new span using the given position as the start and end. + pub fn splat(pos: Position) -> Span { + Span::new(pos, pos) + } + + /// Create a new span by replacing the starting the position with the one + /// given. + pub fn with_start(self, pos: Position) -> Span { + Span { start: pos, ..self } + } + + /// Create a new span by replacing the ending the position with the one + /// given. + pub fn with_end(self, pos: Position) -> Span { + Span { end: pos, ..self } + } + + /// Returns true if and only if this span occurs on a single line. + pub fn is_one_line(&self) -> bool { + self.start.line == self.end.line + } + + /// Returns true if and only if this span is empty. That is, it points to + /// a single position in the concrete syntax of a regular expression. + pub fn is_empty(&self) -> bool { + self.start.offset == self.end.offset + } +} + +impl Position { + /// Create a new position with the given information. + /// + /// `offset` is the absolute offset of the position, starting at `0` from + /// the beginning of the regular expression pattern string. + /// + /// `line` is the line number, starting at `1`. + /// + /// `column` is the approximate column number, starting at `1`. + pub fn new(offset: usize, line: usize, column: usize) -> Position { + Position { offset, line, column } + } +} + +/// An abstract syntax tree for a singular expression along with comments +/// found. +/// +/// Comments are not stored in the tree itself to avoid complexity. Each +/// comment contains a span of precisely where it occurred in the original +/// regular expression. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct WithComments { + /// The actual ast. + pub ast: Ast, + /// All comments found in the original regular expression. + pub comments: Vec, +} + +/// A comment from a regular expression with an associated span. +/// +/// A regular expression can only contain comments when the `x` flag is +/// enabled. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct Comment { + /// The span of this comment, including the beginning `#` and ending `\n`. + pub span: Span, + /// The comment text, starting with the first character following the `#` + /// and ending with the last character preceding the `\n`. + pub comment: String, +} + +/// An abstract syntax tree for a single regular expression. +/// +/// An `Ast`'s `fmt::Display` implementation uses constant stack space and heap +/// space proportional to the size of the `Ast`. +/// +/// This type defines its own destructor that uses constant stack space and +/// heap space proportional to the size of the `Ast`. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum Ast { + /// An empty regex that matches everything. + Empty(Span), + /// A set of flags, e.g., `(?is)`. + Flags(SetFlags), + /// A single character literal, which includes escape sequences. + Literal(Literal), + /// The "any character" class. + Dot(Span), + /// A single zero-width assertion. + Assertion(Assertion), + /// A single character class. This includes all forms of character classes + /// except for `.`. e.g., `\d`, `\pN`, `[a-z]` and `[[:alpha:]]`. + Class(Class), + /// A repetition operator applied to an arbitrary regular expression. + Repetition(Repetition), + /// A grouped regular expression. + Group(Group), + /// An alternation of regular expressions. + Alternation(Alternation), + /// A concatenation of regular expressions. + Concat(Concat), +} + +impl Ast { + /// Return the span of this abstract syntax tree. + pub fn span(&self) -> &Span { + match *self { + Ast::Empty(ref span) => span, + Ast::Flags(ref x) => &x.span, + Ast::Literal(ref x) => &x.span, + Ast::Dot(ref span) => span, + Ast::Assertion(ref x) => &x.span, + Ast::Class(ref x) => x.span(), + Ast::Repetition(ref x) => &x.span, + Ast::Group(ref x) => &x.span, + Ast::Alternation(ref x) => &x.span, + Ast::Concat(ref x) => &x.span, + } + } + + /// Return true if and only if this Ast is empty. + pub fn is_empty(&self) -> bool { + match *self { + Ast::Empty(_) => true, + _ => false, + } + } + + /// Returns true if and only if this AST has any (including possibly empty) + /// subexpressions. + fn has_subexprs(&self) -> bool { + match *self { + Ast::Empty(_) + | Ast::Flags(_) + | Ast::Literal(_) + | Ast::Dot(_) + | Ast::Assertion(_) => false, + Ast::Class(_) + | Ast::Repetition(_) + | Ast::Group(_) + | Ast::Alternation(_) + | Ast::Concat(_) => true, + } + } +} + +/// Print a display representation of this Ast. +/// +/// This does not preserve any of the original whitespace formatting that may +/// have originally been present in the concrete syntax from which this Ast +/// was generated. +/// +/// This implementation uses constant stack space and heap space proportional +/// to the size of the `Ast`. +impl core::fmt::Display for Ast { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use crate::ast::print::Printer; + Printer::new().print(self, f) + } +} + +/// An alternation of regular expressions. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct Alternation { + /// The span of this alternation. + pub span: Span, + /// The alternate regular expressions. + pub asts: Vec, +} + +impl Alternation { + /// Return this alternation as an AST. + /// + /// If this alternation contains zero ASTs, then Ast::Empty is + /// returned. If this alternation contains exactly 1 AST, then the + /// corresponding AST is returned. Otherwise, Ast::Alternation is returned. + pub fn into_ast(mut self) -> Ast { + match self.asts.len() { + 0 => Ast::Empty(self.span), + 1 => self.asts.pop().unwrap(), + _ => Ast::Alternation(self), + } + } +} + +/// A concatenation of regular expressions. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct Concat { + /// The span of this concatenation. + pub span: Span, + /// The concatenation regular expressions. + pub asts: Vec, +} + +impl Concat { + /// Return this concatenation as an AST. + /// + /// If this concatenation contains zero ASTs, then Ast::Empty is + /// returned. If this concatenation contains exactly 1 AST, then the + /// corresponding AST is returned. Otherwise, Ast::Concat is returned. + pub fn into_ast(mut self) -> Ast { + match self.asts.len() { + 0 => Ast::Empty(self.span), + 1 => self.asts.pop().unwrap(), + _ => Ast::Concat(self), + } + } +} + +/// A single literal expression. +/// +/// A literal corresponds to a single Unicode scalar value. Literals may be +/// represented in their literal form, e.g., `a` or in their escaped form, +/// e.g., `\x61`. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct Literal { + /// The span of this literal. + pub span: Span, + /// The kind of this literal. + pub kind: LiteralKind, + /// The Unicode scalar value corresponding to this literal. + pub c: char, +} + +impl Literal { + /// If this literal was written as a `\x` hex escape, then this returns + /// the corresponding byte value. Otherwise, this returns `None`. + pub fn byte(&self) -> Option { + match self.kind { + LiteralKind::HexFixed(HexLiteralKind::X) => { + u8::try_from(self.c).ok() + } + _ => None, + } + } +} + +/// The kind of a single literal expression. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum LiteralKind { + /// The literal is written verbatim, e.g., `a` or `☃`. + Verbatim, + /// The literal is written as an escape because it is otherwise a special + /// regex meta character, e.g., `\*` or `\[`. + Meta, + /// The literal is written as an escape despite the fact that the escape is + /// unnecessary, e.g., `\%` or `\/`. + Superfluous, + /// The literal is written as an octal escape, e.g., `\141`. + Octal, + /// The literal is written as a hex code with a fixed number of digits + /// depending on the type of the escape, e.g., `\x61` or or `\u0061` or + /// `\U00000061`. + HexFixed(HexLiteralKind), + /// The literal is written as a hex code with a bracketed number of + /// digits. The only restriction is that the bracketed hex code must refer + /// to a valid Unicode scalar value. + HexBrace(HexLiteralKind), + /// The literal is written as a specially recognized escape, e.g., `\f` + /// or `\n`. + Special(SpecialLiteralKind), +} + +/// The type of a special literal. +/// +/// A special literal is a special escape sequence recognized by the regex +/// parser, e.g., `\f` or `\n`. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum SpecialLiteralKind { + /// Bell, spelled `\a` (`\x07`). + Bell, + /// Form feed, spelled `\f` (`\x0C`). + FormFeed, + /// Tab, spelled `\t` (`\x09`). + Tab, + /// Line feed, spelled `\n` (`\x0A`). + LineFeed, + /// Carriage return, spelled `\r` (`\x0D`). + CarriageReturn, + /// Vertical tab, spelled `\v` (`\x0B`). + VerticalTab, + /// Space, spelled `\ ` (`\x20`). Note that this can only appear when + /// parsing in verbose mode. + Space, +} + +/// The type of a Unicode hex literal. +/// +/// Note that all variants behave the same when used with brackets. They only +/// differ when used without brackets in the number of hex digits that must +/// follow. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum HexLiteralKind { + /// A `\x` prefix. When used without brackets, this form is limited to + /// two digits. + X, + /// A `\u` prefix. When used without brackets, this form is limited to + /// four digits. + UnicodeShort, + /// A `\U` prefix. When used without brackets, this form is limited to + /// eight digits. + UnicodeLong, +} + +impl HexLiteralKind { + /// The number of digits that must be used with this literal form when + /// used without brackets. When used with brackets, there is no + /// restriction on the number of digits. + pub fn digits(&self) -> u32 { + match *self { + HexLiteralKind::X => 2, + HexLiteralKind::UnicodeShort => 4, + HexLiteralKind::UnicodeLong => 8, + } + } +} + +/// A single character class expression. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum Class { + /// A Unicode character class, e.g., `\pL` or `\p{Greek}`. + Unicode(ClassUnicode), + /// A perl character class, e.g., `\d` or `\W`. + Perl(ClassPerl), + /// A bracketed character class set, which may contain zero or more + /// character ranges and/or zero or more nested classes. e.g., + /// `[a-zA-Z\pL]`. + Bracketed(ClassBracketed), +} + +impl Class { + /// Return the span of this character class. + pub fn span(&self) -> &Span { + match *self { + Class::Perl(ref x) => &x.span, + Class::Unicode(ref x) => &x.span, + Class::Bracketed(ref x) => &x.span, + } + } +} + +/// A Perl character class. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct ClassPerl { + /// The span of this class. + pub span: Span, + /// The kind of Perl class. + pub kind: ClassPerlKind, + /// Whether the class is negated or not. e.g., `\d` is not negated but + /// `\D` is. + pub negated: bool, +} + +/// The available Perl character classes. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum ClassPerlKind { + /// Decimal numbers. + Digit, + /// Whitespace. + Space, + /// Word characters. + Word, +} + +/// An ASCII character class. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct ClassAscii { + /// The span of this class. + pub span: Span, + /// The kind of ASCII class. + pub kind: ClassAsciiKind, + /// Whether the class is negated or not. e.g., `[[:alpha:]]` is not negated + /// but `[[:^alpha:]]` is. + pub negated: bool, +} + +/// The available ASCII character classes. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum ClassAsciiKind { + /// `[0-9A-Za-z]` + Alnum, + /// `[A-Za-z]` + Alpha, + /// `[\x00-\x7F]` + Ascii, + /// `[ \t]` + Blank, + /// `[\x00-\x1F\x7F]` + Cntrl, + /// `[0-9]` + Digit, + /// `[!-~]` + Graph, + /// `[a-z]` + Lower, + /// `[ -~]` + Print, + /// `[!-/:-@\[-`{-~]` + Punct, + /// `[\t\n\v\f\r ]` + Space, + /// `[A-Z]` + Upper, + /// `[0-9A-Za-z_]` + Word, + /// `[0-9A-Fa-f]` + Xdigit, +} + +impl ClassAsciiKind { + /// Return the corresponding ClassAsciiKind variant for the given name. + /// + /// The name given should correspond to the lowercase version of the + /// variant name. e.g., `cntrl` is the name for `ClassAsciiKind::Cntrl`. + /// + /// If no variant with the corresponding name exists, then `None` is + /// returned. + pub fn from_name(name: &str) -> Option { + use self::ClassAsciiKind::*; + match name { + "alnum" => Some(Alnum), + "alpha" => Some(Alpha), + "ascii" => Some(Ascii), + "blank" => Some(Blank), + "cntrl" => Some(Cntrl), + "digit" => Some(Digit), + "graph" => Some(Graph), + "lower" => Some(Lower), + "print" => Some(Print), + "punct" => Some(Punct), + "space" => Some(Space), + "upper" => Some(Upper), + "word" => Some(Word), + "xdigit" => Some(Xdigit), + _ => None, + } + } +} + +/// A Unicode character class. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct ClassUnicode { + /// The span of this class. + pub span: Span, + /// Whether this class is negated or not. + /// + /// Note: be careful when using this attribute. This specifically refers + /// to whether the class is written as `\p` or `\P`, where the latter + /// is `negated = true`. However, it also possible to write something like + /// `\P{scx!=Katakana}` which is actually equivalent to + /// `\p{scx=Katakana}` and is therefore not actually negated even though + /// `negated = true` here. To test whether this class is truly negated + /// or not, use the `is_negated` method. + pub negated: bool, + /// The kind of Unicode class. + pub kind: ClassUnicodeKind, +} + +impl ClassUnicode { + /// Returns true if this class has been negated. + /// + /// Note that this takes the Unicode op into account, if it's present. + /// e.g., `is_negated` for `\P{scx!=Katakana}` will return `false`. + pub fn is_negated(&self) -> bool { + match self.kind { + ClassUnicodeKind::NamedValue { + op: ClassUnicodeOpKind::NotEqual, + .. + } => !self.negated, + _ => self.negated, + } + } +} + +/// The available forms of Unicode character classes. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ClassUnicodeKind { + /// A one letter abbreviated class, e.g., `\pN`. + OneLetter(char), + /// A binary property, general category or script. The string may be + /// empty. + Named(String), + /// A property name and an associated value. + NamedValue { + /// The type of Unicode op used to associate `name` with `value`. + op: ClassUnicodeOpKind, + /// The property name (which may be empty). + name: String, + /// The property value (which may be empty). + value: String, + }, +} + +#[cfg(feature = "arbitrary")] +impl arbitrary::Arbitrary<'_> for ClassUnicodeKind { + fn arbitrary( + u: &mut arbitrary::Unstructured, + ) -> arbitrary::Result { + #[cfg(any( + feature = "unicode-age", + feature = "unicode-bool", + feature = "unicode-gencat", + feature = "unicode-perl", + feature = "unicode-script", + feature = "unicode-segment", + ))] + { + use alloc::string::ToString; + + use super::unicode_tables::{ + property_names::PROPERTY_NAMES, + property_values::PROPERTY_VALUES, + }; + + match u.choose_index(3)? { + 0 => { + let all = PROPERTY_VALUES + .iter() + .flat_map(|e| e.1.iter()) + .filter(|(name, _)| name.len() == 1) + .count(); + let idx = u.choose_index(all)?; + let value = PROPERTY_VALUES + .iter() + .flat_map(|e| e.1.iter()) + .take(idx + 1) + .last() + .unwrap() + .0 + .chars() + .next() + .unwrap(); + Ok(ClassUnicodeKind::OneLetter(value)) + } + 1 => { + let all = PROPERTY_VALUES + .iter() + .map(|e| e.1.len()) + .sum::() + + PROPERTY_NAMES.len(); + let idx = u.choose_index(all)?; + let name = PROPERTY_VALUES + .iter() + .flat_map(|e| e.1.iter()) + .chain(PROPERTY_NAMES) + .map(|(_, e)| e) + .take(idx + 1) + .last() + .unwrap(); + Ok(ClassUnicodeKind::Named(name.to_string())) + } + 2 => { + let all = PROPERTY_VALUES + .iter() + .map(|e| e.1.len()) + .sum::(); + let idx = u.choose_index(all)?; + let (prop, value) = PROPERTY_VALUES + .iter() + .flat_map(|e| { + e.1.iter().map(|(_, value)| (e.0, value)) + }) + .take(idx + 1) + .last() + .unwrap(); + Ok(ClassUnicodeKind::NamedValue { + op: u.arbitrary()?, + name: prop.to_string(), + value: value.to_string(), + }) + } + _ => unreachable!("index chosen is impossible"), + } + } + #[cfg(not(any( + feature = "unicode-age", + feature = "unicode-bool", + feature = "unicode-gencat", + feature = "unicode-perl", + feature = "unicode-script", + feature = "unicode-segment", + )))] + { + match u.choose_index(3)? { + 0 => Ok(ClassUnicodeKind::OneLetter(u.arbitrary()?)), + 1 => Ok(ClassUnicodeKind::Named(u.arbitrary()?)), + 2 => Ok(ClassUnicodeKind::NamedValue { + op: u.arbitrary()?, + name: u.arbitrary()?, + value: u.arbitrary()?, + }), + _ => unreachable!("index chosen is impossible"), + } + } + } + + fn size_hint(depth: usize) -> (usize, Option) { + #[cfg(any( + feature = "unicode-age", + feature = "unicode-bool", + feature = "unicode-gencat", + feature = "unicode-perl", + feature = "unicode-script", + feature = "unicode-segment", + ))] + { + arbitrary::size_hint::and_all(&[ + usize::size_hint(depth), + usize::size_hint(depth), + arbitrary::size_hint::or( + (0, Some(0)), + ClassUnicodeOpKind::size_hint(depth), + ), + ]) + } + #[cfg(not(any( + feature = "unicode-age", + feature = "unicode-bool", + feature = "unicode-gencat", + feature = "unicode-perl", + feature = "unicode-script", + feature = "unicode-segment", + )))] + { + arbitrary::size_hint::and( + usize::size_hint(depth), + arbitrary::size_hint::or_all(&[ + char::size_hint(depth), + String::size_hint(depth), + arbitrary::size_hint::and_all(&[ + String::size_hint(depth), + String::size_hint(depth), + ClassUnicodeOpKind::size_hint(depth), + ]), + ]), + ) + } + } +} + +/// The type of op used in a Unicode character class. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum ClassUnicodeOpKind { + /// A property set to a specific value, e.g., `\p{scx=Katakana}`. + Equal, + /// A property set to a specific value using a colon, e.g., + /// `\p{scx:Katakana}`. + Colon, + /// A property that isn't a particular value, e.g., `\p{scx!=Katakana}`. + NotEqual, +} + +impl ClassUnicodeOpKind { + /// Whether the op is an equality op or not. + pub fn is_equal(&self) -> bool { + match *self { + ClassUnicodeOpKind::Equal | ClassUnicodeOpKind::Colon => true, + _ => false, + } + } +} + +/// A bracketed character class, e.g., `[a-z0-9]`. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct ClassBracketed { + /// The span of this class. + pub span: Span, + /// Whether this class is negated or not. e.g., `[a]` is not negated but + /// `[^a]` is. + pub negated: bool, + /// The type of this set. A set is either a normal union of things, e.g., + /// `[abc]` or a result of applying set operations, e.g., `[\pL--c]`. + pub kind: ClassSet, +} + +/// A character class set. +/// +/// This type corresponds to the internal structure of a bracketed character +/// class. That is, every bracketed character is one of two types: a union of +/// items (literals, ranges, other bracketed classes) or a tree of binary set +/// operations. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum ClassSet { + /// An item, which can be a single literal, range, nested character class + /// or a union of items. + Item(ClassSetItem), + /// A single binary operation (i.e., &&, -- or ~~). + BinaryOp(ClassSetBinaryOp), +} + +impl ClassSet { + /// Build a set from a union. + pub fn union(ast: ClassSetUnion) -> ClassSet { + ClassSet::Item(ClassSetItem::Union(ast)) + } + + /// Return the span of this character class set. + pub fn span(&self) -> &Span { + match *self { + ClassSet::Item(ref x) => x.span(), + ClassSet::BinaryOp(ref x) => &x.span, + } + } + + /// Return true if and only if this class set is empty. + fn is_empty(&self) -> bool { + match *self { + ClassSet::Item(ClassSetItem::Empty(_)) => true, + _ => false, + } + } +} + +/// A single component of a character class set. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum ClassSetItem { + /// An empty item. + /// + /// Note that a bracketed character class cannot contain a single empty + /// item. Empty items can appear when using one of the binary operators. + /// For example, `[&&]` is the intersection of two empty classes. + Empty(Span), + /// A single literal. + Literal(Literal), + /// A range between two literals. + Range(ClassSetRange), + /// An ASCII character class, e.g., `[:alnum:]` or `[:punct:]`. + Ascii(ClassAscii), + /// A Unicode character class, e.g., `\pL` or `\p{Greek}`. + Unicode(ClassUnicode), + /// A perl character class, e.g., `\d` or `\W`. + Perl(ClassPerl), + /// A bracketed character class set, which may contain zero or more + /// character ranges and/or zero or more nested classes. e.g., + /// `[a-zA-Z\pL]`. + Bracketed(Box), + /// A union of items. + Union(ClassSetUnion), +} + +impl ClassSetItem { + /// Return the span of this character class set item. + pub fn span(&self) -> &Span { + match *self { + ClassSetItem::Empty(ref span) => span, + ClassSetItem::Literal(ref x) => &x.span, + ClassSetItem::Range(ref x) => &x.span, + ClassSetItem::Ascii(ref x) => &x.span, + ClassSetItem::Perl(ref x) => &x.span, + ClassSetItem::Unicode(ref x) => &x.span, + ClassSetItem::Bracketed(ref x) => &x.span, + ClassSetItem::Union(ref x) => &x.span, + } + } +} + +/// A single character class range in a set. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct ClassSetRange { + /// The span of this range. + pub span: Span, + /// The start of this range. + pub start: Literal, + /// The end of this range. + pub end: Literal, +} + +impl ClassSetRange { + /// Returns true if and only if this character class range is valid. + /// + /// The only case where a range is invalid is if its start is greater than + /// its end. + pub fn is_valid(&self) -> bool { + self.start.c <= self.end.c + } +} + +/// A union of items inside a character class set. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct ClassSetUnion { + /// The span of the items in this operation. e.g., the `a-z0-9` in + /// `[^a-z0-9]` + pub span: Span, + /// The sequence of items that make up this union. + pub items: Vec, +} + +impl ClassSetUnion { + /// Push a new item in this union. + /// + /// The ending position of this union's span is updated to the ending + /// position of the span of the item given. If the union is empty, then + /// the starting position of this union is set to the starting position + /// of this item. + /// + /// In other words, if you only use this method to add items to a union + /// and you set the spans on each item correctly, then you should never + /// need to adjust the span of the union directly. + pub fn push(&mut self, item: ClassSetItem) { + if self.items.is_empty() { + self.span.start = item.span().start; + } + self.span.end = item.span().end; + self.items.push(item); + } + + /// Return this union as a character class set item. + /// + /// If this union contains zero items, then an empty union is + /// returned. If this concatenation contains exactly 1 item, then the + /// corresponding item is returned. Otherwise, ClassSetItem::Union is + /// returned. + pub fn into_item(mut self) -> ClassSetItem { + match self.items.len() { + 0 => ClassSetItem::Empty(self.span), + 1 => self.items.pop().unwrap(), + _ => ClassSetItem::Union(self), + } + } +} + +/// A Unicode character class set operation. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct ClassSetBinaryOp { + /// The span of this operation. e.g., the `a-z--[h-p]` in `[a-z--h-p]`. + pub span: Span, + /// The type of this set operation. + pub kind: ClassSetBinaryOpKind, + /// The left hand side of the operation. + pub lhs: Box, + /// The right hand side of the operation. + pub rhs: Box, +} + +/// The type of a Unicode character class set operation. +/// +/// Note that this doesn't explicitly represent union since there is no +/// explicit union operator. Concatenation inside a character class corresponds +/// to the union operation. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum ClassSetBinaryOpKind { + /// The intersection of two sets, e.g., `\pN&&[a-z]`. + Intersection, + /// The difference of two sets, e.g., `\pN--[0-9]`. + Difference, + /// The symmetric difference of two sets. The symmetric difference is the + /// set of elements belonging to one but not both sets. + /// e.g., `[\pL~~[:ascii:]]`. + SymmetricDifference, +} + +/// A single zero-width assertion. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct Assertion { + /// The span of this assertion. + pub span: Span, + /// The assertion kind, e.g., `\b` or `^`. + pub kind: AssertionKind, +} + +/// An assertion kind. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum AssertionKind { + /// `^` + StartLine, + /// `$` + EndLine, + /// `\A` + StartText, + /// `\z` + EndText, + /// `\b` + WordBoundary, + /// `\B` + NotWordBoundary, +} + +/// A repetition operation applied to a regular expression. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct Repetition { + /// The span of this operation. + pub span: Span, + /// The actual operation. + pub op: RepetitionOp, + /// Whether this operation was applied greedily or not. + pub greedy: bool, + /// The regular expression under repetition. + pub ast: Box, +} + +/// The repetition operator itself. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct RepetitionOp { + /// The span of this operator. This includes things like `+`, `*?` and + /// `{m,n}`. + pub span: Span, + /// The type of operation. + pub kind: RepetitionKind, +} + +/// The kind of a repetition operator. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum RepetitionKind { + /// `?` + ZeroOrOne, + /// `*` + ZeroOrMore, + /// `+` + OneOrMore, + /// `{m,n}` + Range(RepetitionRange), +} + +/// A range repetition operator. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum RepetitionRange { + /// `{m}` + Exactly(u32), + /// `{m,}` + AtLeast(u32), + /// `{m,n}` + Bounded(u32, u32), +} + +impl RepetitionRange { + /// Returns true if and only if this repetition range is valid. + /// + /// The only case where a repetition range is invalid is if it is bounded + /// and its start is greater than its end. + pub fn is_valid(&self) -> bool { + match *self { + RepetitionRange::Bounded(s, e) if s > e => false, + _ => true, + } + } +} + +/// A grouped regular expression. +/// +/// This includes both capturing and non-capturing groups. This does **not** +/// include flag-only groups like `(?is)`, but does contain any group that +/// contains a sub-expression, e.g., `(a)`, `(?Pa)`, `(?:a)` and +/// `(?is:a)`. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct Group { + /// The span of this group. + pub span: Span, + /// The kind of this group. + pub kind: GroupKind, + /// The regular expression in this group. + pub ast: Box, +} + +impl Group { + /// If this group is non-capturing, then this returns the (possibly empty) + /// set of flags. Otherwise, `None` is returned. + pub fn flags(&self) -> Option<&Flags> { + match self.kind { + GroupKind::NonCapturing(ref flags) => Some(flags), + _ => None, + } + } + + /// Returns true if and only if this group is capturing. + pub fn is_capturing(&self) -> bool { + match self.kind { + GroupKind::CaptureIndex(_) | GroupKind::CaptureName { .. } => true, + GroupKind::NonCapturing(_) => false, + } + } + + /// Returns the capture index of this group, if this is a capturing group. + /// + /// This returns a capture index precisely when `is_capturing` is `true`. + pub fn capture_index(&self) -> Option { + match self.kind { + GroupKind::CaptureIndex(i) => Some(i), + GroupKind::CaptureName { ref name, .. } => Some(name.index), + GroupKind::NonCapturing(_) => None, + } + } +} + +/// The kind of a group. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum GroupKind { + /// `(a)` + CaptureIndex(u32), + /// `(?a)` or `(?Pa)` + CaptureName { + /// True if the `?P<` syntax is used and false if the `?<` syntax is used. + starts_with_p: bool, + /// The capture name. + name: CaptureName, + }, + /// `(?:a)` and `(?i:a)` + NonCapturing(Flags), +} + +/// A capture name. +/// +/// This corresponds to the name itself between the angle brackets in, e.g., +/// `(?Pexpr)`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CaptureName { + /// The span of this capture name. + pub span: Span, + /// The capture name. + pub name: String, + /// The capture index. + pub index: u32, +} + +#[cfg(feature = "arbitrary")] +impl arbitrary::Arbitrary<'_> for CaptureName { + fn arbitrary( + u: &mut arbitrary::Unstructured, + ) -> arbitrary::Result { + let len = u.arbitrary_len::()?; + if len == 0 { + return Err(arbitrary::Error::NotEnoughData); + } + let mut name: String = String::new(); + for _ in 0..len { + let ch: char = u.arbitrary()?; + let cp = u32::from(ch); + let ascii_letter_offset = u8::try_from(cp % 26).unwrap(); + let ascii_letter = b'a' + ascii_letter_offset; + name.push(char::from(ascii_letter)); + } + Ok(CaptureName { span: u.arbitrary()?, name, index: u.arbitrary()? }) + } + + fn size_hint(depth: usize) -> (usize, Option) { + arbitrary::size_hint::and_all(&[ + Span::size_hint(depth), + usize::size_hint(depth), + u32::size_hint(depth), + ]) + } +} + +/// A group of flags that is not applied to a particular regular expression. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct SetFlags { + /// The span of these flags, including the grouping parentheses. + pub span: Span, + /// The actual sequence of flags. + pub flags: Flags, +} + +/// A group of flags. +/// +/// This corresponds only to the sequence of flags themselves, e.g., `is-u`. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct Flags { + /// The span of this group of flags. + pub span: Span, + /// A sequence of flag items. Each item is either a flag or a negation + /// operator. + pub items: Vec, +} + +impl Flags { + /// Add the given item to this sequence of flags. + /// + /// If the item was added successfully, then `None` is returned. If the + /// given item is a duplicate, then `Some(i)` is returned, where + /// `items[i].kind == item.kind`. + pub fn add_item(&mut self, item: FlagsItem) -> Option { + for (i, x) in self.items.iter().enumerate() { + if x.kind == item.kind { + return Some(i); + } + } + self.items.push(item); + None + } + + /// Returns the state of the given flag in this set. + /// + /// If the given flag is in the set but is negated, then `Some(false)` is + /// returned. + /// + /// If the given flag is in the set and is not negated, then `Some(true)` + /// is returned. + /// + /// Otherwise, `None` is returned. + pub fn flag_state(&self, flag: Flag) -> Option { + let mut negated = false; + for x in &self.items { + match x.kind { + FlagsItemKind::Negation => { + negated = true; + } + FlagsItemKind::Flag(ref xflag) if xflag == &flag => { + return Some(!negated); + } + _ => {} + } + } + None + } +} + +/// A single item in a group of flags. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct FlagsItem { + /// The span of this item. + pub span: Span, + /// The kind of this item. + pub kind: FlagsItemKind, +} + +/// The kind of an item in a group of flags. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum FlagsItemKind { + /// A negation operator applied to all subsequent flags in the enclosing + /// group. + Negation, + /// A single flag in a group. + Flag(Flag), +} + +impl FlagsItemKind { + /// Returns true if and only if this item is a negation operator. + pub fn is_negation(&self) -> bool { + match *self { + FlagsItemKind::Negation => true, + _ => false, + } + } +} + +/// A single flag. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub enum Flag { + /// `i` + CaseInsensitive, + /// `m` + MultiLine, + /// `s` + DotMatchesNewLine, + /// `U` + SwapGreed, + /// `u` + Unicode, + /// `R` + CRLF, + /// `x` + IgnoreWhitespace, +} + +/// A custom `Drop` impl is used for `Ast` such that it uses constant stack +/// space but heap space proportional to the depth of the `Ast`. +impl Drop for Ast { + fn drop(&mut self) { + use core::mem; + + match *self { + Ast::Empty(_) + | Ast::Flags(_) + | Ast::Literal(_) + | Ast::Dot(_) + | Ast::Assertion(_) + // Classes are recursive, so they get their own Drop impl. + | Ast::Class(_) => return, + Ast::Repetition(ref x) if !x.ast.has_subexprs() => return, + Ast::Group(ref x) if !x.ast.has_subexprs() => return, + Ast::Alternation(ref x) if x.asts.is_empty() => return, + Ast::Concat(ref x) if x.asts.is_empty() => return, + _ => {} + } + + let empty_span = || Span::splat(Position::new(0, 0, 0)); + let empty_ast = || Ast::Empty(empty_span()); + let mut stack = vec![mem::replace(self, empty_ast())]; + while let Some(mut ast) = stack.pop() { + match ast { + Ast::Empty(_) + | Ast::Flags(_) + | Ast::Literal(_) + | Ast::Dot(_) + | Ast::Assertion(_) + // Classes are recursive, so they get their own Drop impl. + | Ast::Class(_) => {} + Ast::Repetition(ref mut x) => { + stack.push(mem::replace(&mut x.ast, empty_ast())); + } + Ast::Group(ref mut x) => { + stack.push(mem::replace(&mut x.ast, empty_ast())); + } + Ast::Alternation(ref mut x) => { + stack.extend(x.asts.drain(..)); + } + Ast::Concat(ref mut x) => { + stack.extend(x.asts.drain(..)); + } + } + } + } +} + +/// A custom `Drop` impl is used for `ClassSet` such that it uses constant +/// stack space but heap space proportional to the depth of the `ClassSet`. +impl Drop for ClassSet { + fn drop(&mut self) { + use core::mem; + + match *self { + ClassSet::Item(ref item) => match *item { + ClassSetItem::Empty(_) + | ClassSetItem::Literal(_) + | ClassSetItem::Range(_) + | ClassSetItem::Ascii(_) + | ClassSetItem::Unicode(_) + | ClassSetItem::Perl(_) => return, + ClassSetItem::Bracketed(ref x) => { + if x.kind.is_empty() { + return; + } + } + ClassSetItem::Union(ref x) => { + if x.items.is_empty() { + return; + } + } + }, + ClassSet::BinaryOp(ref op) => { + if op.lhs.is_empty() && op.rhs.is_empty() { + return; + } + } + } + + let empty_span = || Span::splat(Position::new(0, 0, 0)); + let empty_set = || ClassSet::Item(ClassSetItem::Empty(empty_span())); + let mut stack = vec![mem::replace(self, empty_set())]; + while let Some(mut set) = stack.pop() { + match set { + ClassSet::Item(ref mut item) => match *item { + ClassSetItem::Empty(_) + | ClassSetItem::Literal(_) + | ClassSetItem::Range(_) + | ClassSetItem::Ascii(_) + | ClassSetItem::Unicode(_) + | ClassSetItem::Perl(_) => {} + ClassSetItem::Bracketed(ref mut x) => { + stack.push(mem::replace(&mut x.kind, empty_set())); + } + ClassSetItem::Union(ref mut x) => { + stack.extend(x.items.drain(..).map(ClassSet::Item)); + } + }, + ClassSet::BinaryOp(ref mut op) => { + stack.push(mem::replace(&mut op.lhs, empty_set())); + stack.push(mem::replace(&mut op.rhs, empty_set())); + } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // We use a thread with an explicit stack size to test that our destructor + // for Ast can handle arbitrarily sized expressions in constant stack + // space. In case we run on a platform without threads (WASM?), we limit + // this test to Windows/Unix. + #[test] + #[cfg(any(unix, windows))] + fn no_stack_overflow_on_drop() { + use std::thread; + + let run = || { + let span = || Span::splat(Position::new(0, 0, 0)); + let mut ast = Ast::Empty(span()); + for i in 0..200 { + ast = Ast::Group(Group { + span: span(), + kind: GroupKind::CaptureIndex(i), + ast: Box::new(ast), + }); + } + assert!(!ast.is_empty()); + }; + + // We run our test on a thread with a small stack size so we can + // force the issue more easily. + // + // NOTE(2023-03-21): It turns out that some platforms (like FreeBSD) + // will just barf with very small stack sizes. So we bump this up a bit + // to give more room to breath. When I did this, I confirmed that if + // I remove the custom `Drop` impl for `Ast`, then this test does + // indeed still fail with a stack overflow. (At the time of writing, I + // had to bump it all the way up to 32K before the test would pass even + // without the custom `Drop` impl. So 16K seems like a safe number + // here.) + // + // See: https://github.com/rust-lang/regex/issues/967 + thread::Builder::new() + .stack_size(16 << 10) + .spawn(run) + .unwrap() + .join() + .unwrap(); + } +} diff --git a/vendor/regex-syntax-0.7.5/src/ast/parse.rs b/vendor/regex-syntax-0.7.5/src/ast/parse.rs new file mode 100644 index 0000000000000..47ea2586b4190 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/ast/parse.rs @@ -0,0 +1,6130 @@ +/*! +This module provides a regular expression parser. +*/ + +use core::{ + borrow::Borrow, + cell::{Cell, RefCell}, + mem, +}; + +use alloc::{ + boxed::Box, + string::{String, ToString}, + vec, + vec::Vec, +}; + +use crate::{ + ast::{self, Ast, Position, Span}, + either::Either, + is_escapeable_character, is_meta_character, +}; + +type Result = core::result::Result; + +/// A primitive is an expression with no sub-expressions. This includes +/// literals, assertions and non-set character classes. This representation +/// is used as intermediate state in the parser. +/// +/// This does not include ASCII character classes, since they can only appear +/// within a set character class. +#[derive(Clone, Debug, Eq, PartialEq)] +enum Primitive { + Literal(ast::Literal), + Assertion(ast::Assertion), + Dot(Span), + Perl(ast::ClassPerl), + Unicode(ast::ClassUnicode), +} + +impl Primitive { + /// Return the span of this primitive. + fn span(&self) -> &Span { + match *self { + Primitive::Literal(ref x) => &x.span, + Primitive::Assertion(ref x) => &x.span, + Primitive::Dot(ref span) => span, + Primitive::Perl(ref x) => &x.span, + Primitive::Unicode(ref x) => &x.span, + } + } + + /// Convert this primitive into a proper AST. + fn into_ast(self) -> Ast { + match self { + Primitive::Literal(lit) => Ast::Literal(lit), + Primitive::Assertion(assert) => Ast::Assertion(assert), + Primitive::Dot(span) => Ast::Dot(span), + Primitive::Perl(cls) => Ast::Class(ast::Class::Perl(cls)), + Primitive::Unicode(cls) => Ast::Class(ast::Class::Unicode(cls)), + } + } + + /// Convert this primitive into an item in a character class. + /// + /// If this primitive is not a legal item (i.e., an assertion or a dot), + /// then return an error. + fn into_class_set_item>( + self, + p: &ParserI<'_, P>, + ) -> Result { + use self::Primitive::*; + use crate::ast::ClassSetItem; + + match self { + Literal(lit) => Ok(ClassSetItem::Literal(lit)), + Perl(cls) => Ok(ClassSetItem::Perl(cls)), + Unicode(cls) => Ok(ClassSetItem::Unicode(cls)), + x => Err(p.error(*x.span(), ast::ErrorKind::ClassEscapeInvalid)), + } + } + + /// Convert this primitive into a literal in a character class. In + /// particular, literals are the only valid items that can appear in + /// ranges. + /// + /// If this primitive is not a legal item (i.e., a class, assertion or a + /// dot), then return an error. + fn into_class_literal>( + self, + p: &ParserI<'_, P>, + ) -> Result { + use self::Primitive::*; + + match self { + Literal(lit) => Ok(lit), + x => Err(p.error(*x.span(), ast::ErrorKind::ClassRangeLiteral)), + } + } +} + +/// Returns true if the given character is a hexadecimal digit. +fn is_hex(c: char) -> bool { + ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F') +} + +/// Returns true if the given character is a valid in a capture group name. +/// +/// If `first` is true, then `c` is treated as the first character in the +/// group name (which must be alphabetic or underscore). +fn is_capture_char(c: char, first: bool) -> bool { + if first { + c == '_' || c.is_alphabetic() + } else { + c == '_' || c == '.' || c == '[' || c == ']' || c.is_alphanumeric() + } +} + +/// A builder for a regular expression parser. +/// +/// This builder permits modifying configuration options for the parser. +#[derive(Clone, Debug)] +pub struct ParserBuilder { + ignore_whitespace: bool, + nest_limit: u32, + octal: bool, +} + +impl Default for ParserBuilder { + fn default() -> ParserBuilder { + ParserBuilder::new() + } +} + +impl ParserBuilder { + /// Create a new parser builder with a default configuration. + pub fn new() -> ParserBuilder { + ParserBuilder { + ignore_whitespace: false, + nest_limit: 250, + octal: false, + } + } + + /// Build a parser from this configuration with the given pattern. + pub fn build(&self) -> Parser { + Parser { + pos: Cell::new(Position { offset: 0, line: 1, column: 1 }), + capture_index: Cell::new(0), + nest_limit: self.nest_limit, + octal: self.octal, + initial_ignore_whitespace: self.ignore_whitespace, + ignore_whitespace: Cell::new(self.ignore_whitespace), + comments: RefCell::new(vec![]), + stack_group: RefCell::new(vec![]), + stack_class: RefCell::new(vec![]), + capture_names: RefCell::new(vec![]), + scratch: RefCell::new(String::new()), + } + } + + /// Set the nesting limit for this parser. + /// + /// The nesting limit controls how deep the abstract syntax tree is allowed + /// to be. If the AST exceeds the given limit (e.g., with too many nested + /// groups), then an error is returned by the parser. + /// + /// The purpose of this limit is to act as a heuristic to prevent stack + /// overflow for consumers that do structural induction on an `Ast` using + /// explicit recursion. While this crate never does this (instead using + /// constant stack space and moving the call stack to the heap), other + /// crates may. + /// + /// This limit is not checked until the entire AST is parsed. Therefore, + /// if callers want to put a limit on the amount of heap space used, then + /// they should impose a limit on the length, in bytes, of the concrete + /// pattern string. In particular, this is viable since this parser + /// implementation will limit itself to heap space proportional to the + /// length of the pattern string. + /// + /// Note that a nest limit of `0` will return a nest limit error for most + /// patterns but not all. For example, a nest limit of `0` permits `a` but + /// not `ab`, since `ab` requires a concatenation, which results in a nest + /// depth of `1`. In general, a nest limit is not something that manifests + /// in an obvious way in the concrete syntax, therefore, it should not be + /// used in a granular way. + pub fn nest_limit(&mut self, limit: u32) -> &mut ParserBuilder { + self.nest_limit = limit; + self + } + + /// Whether to support octal syntax or not. + /// + /// Octal syntax is a little-known way of uttering Unicode codepoints in + /// a regular expression. For example, `a`, `\x61`, `\u0061` and + /// `\141` are all equivalent regular expressions, where the last example + /// shows octal syntax. + /// + /// While supporting octal syntax isn't in and of itself a problem, it does + /// make good error messages harder. That is, in PCRE based regex engines, + /// syntax like `\0` invokes a backreference, which is explicitly + /// unsupported in Rust's regex engine. However, many users expect it to + /// be supported. Therefore, when octal support is disabled, the error + /// message will explicitly mention that backreferences aren't supported. + /// + /// Octal syntax is disabled by default. + pub fn octal(&mut self, yes: bool) -> &mut ParserBuilder { + self.octal = yes; + self + } + + /// Enable verbose mode in the regular expression. + /// + /// When enabled, verbose mode permits insignificant whitespace in many + /// places in the regular expression, as well as comments. Comments are + /// started using `#` and continue until the end of the line. + /// + /// By default, this is disabled. It may be selectively enabled in the + /// regular expression by using the `x` flag regardless of this setting. + pub fn ignore_whitespace(&mut self, yes: bool) -> &mut ParserBuilder { + self.ignore_whitespace = yes; + self + } +} + +/// A regular expression parser. +/// +/// This parses a string representation of a regular expression into an +/// abstract syntax tree. The size of the tree is proportional to the length +/// of the regular expression pattern. +/// +/// A `Parser` can be configured in more detail via a [`ParserBuilder`]. +#[derive(Clone, Debug)] +pub struct Parser { + /// The current position of the parser. + pos: Cell, + /// The current capture index. + capture_index: Cell, + /// The maximum number of open parens/brackets allowed. If the parser + /// exceeds this number, then an error is returned. + nest_limit: u32, + /// Whether to support octal syntax or not. When `false`, the parser will + /// return an error helpfully pointing out that backreferences are not + /// supported. + octal: bool, + /// The initial setting for `ignore_whitespace` as provided by + /// `ParserBuilder`. It is used when resetting the parser's state. + initial_ignore_whitespace: bool, + /// Whether whitespace should be ignored. When enabled, comments are + /// also permitted. + ignore_whitespace: Cell, + /// A list of comments, in order of appearance. + comments: RefCell>, + /// A stack of grouped sub-expressions, including alternations. + stack_group: RefCell>, + /// A stack of nested character classes. This is only non-empty when + /// parsing a class. + stack_class: RefCell>, + /// A sorted sequence of capture names. This is used to detect duplicate + /// capture names and report an error if one is detected. + capture_names: RefCell>, + /// A scratch buffer used in various places. Mostly this is used to + /// accumulate relevant characters from parts of a pattern. + scratch: RefCell, +} + +/// ParserI is the internal parser implementation. +/// +/// We use this separate type so that we can carry the provided pattern string +/// along with us. In particular, a `Parser` internal state is not tied to any +/// one pattern, but `ParserI` is. +/// +/// This type also lets us use `ParserI<&Parser>` in production code while +/// retaining the convenience of `ParserI` for tests, which sometimes +/// work against the internal interface of the parser. +#[derive(Clone, Debug)] +struct ParserI<'s, P> { + /// The parser state/configuration. + parser: P, + /// The full regular expression provided by the user. + pattern: &'s str, +} + +/// GroupState represents a single stack frame while parsing nested groups +/// and alternations. Each frame records the state up to an opening parenthesis +/// or a alternating bracket `|`. +#[derive(Clone, Debug)] +enum GroupState { + /// This state is pushed whenever an opening group is found. + Group { + /// The concatenation immediately preceding the opening group. + concat: ast::Concat, + /// The group that has been opened. Its sub-AST is always empty. + group: ast::Group, + /// Whether this group has the `x` flag enabled or not. + ignore_whitespace: bool, + }, + /// This state is pushed whenever a new alternation branch is found. If + /// an alternation branch is found and this state is at the top of the + /// stack, then this state should be modified to include the new + /// alternation. + Alternation(ast::Alternation), +} + +/// ClassState represents a single stack frame while parsing character classes. +/// Each frame records the state up to an intersection, difference, symmetric +/// difference or nested class. +/// +/// Note that a parser's character class stack is only non-empty when parsing +/// a character class. In all other cases, it is empty. +#[derive(Clone, Debug)] +enum ClassState { + /// This state is pushed whenever an opening bracket is found. + Open { + /// The union of class items immediately preceding this class. + union: ast::ClassSetUnion, + /// The class that has been opened. Typically this just corresponds + /// to the `[`, but it can also include `[^` since `^` indicates + /// negation of the class. + set: ast::ClassBracketed, + }, + /// This state is pushed when a operator is seen. When popped, the stored + /// set becomes the left hand side of the operator. + Op { + /// The type of the operation, i.e., &&, -- or ~~. + kind: ast::ClassSetBinaryOpKind, + /// The left-hand side of the operator. + lhs: ast::ClassSet, + }, +} + +impl Parser { + /// Create a new parser with a default configuration. + /// + /// The parser can be run with either the `parse` or `parse_with_comments` + /// methods. The parse methods return an abstract syntax tree. + /// + /// To set configuration options on the parser, use [`ParserBuilder`]. + pub fn new() -> Parser { + ParserBuilder::new().build() + } + + /// Parse the regular expression into an abstract syntax tree. + pub fn parse(&mut self, pattern: &str) -> Result { + ParserI::new(self, pattern).parse() + } + + /// Parse the regular expression and return an abstract syntax tree with + /// all of the comments found in the pattern. + pub fn parse_with_comments( + &mut self, + pattern: &str, + ) -> Result { + ParserI::new(self, pattern).parse_with_comments() + } + + /// Reset the internal state of a parser. + /// + /// This is called at the beginning of every parse. This prevents the + /// parser from running with inconsistent state (say, if a previous + /// invocation returned an error and the parser is reused). + fn reset(&self) { + // These settings should be in line with the construction + // in `ParserBuilder::build`. + self.pos.set(Position { offset: 0, line: 1, column: 1 }); + self.ignore_whitespace.set(self.initial_ignore_whitespace); + self.comments.borrow_mut().clear(); + self.stack_group.borrow_mut().clear(); + self.stack_class.borrow_mut().clear(); + } +} + +impl<'s, P: Borrow> ParserI<'s, P> { + /// Build an internal parser from a parser configuration and a pattern. + fn new(parser: P, pattern: &'s str) -> ParserI<'s, P> { + ParserI { parser, pattern } + } + + /// Return a reference to the parser state. + fn parser(&self) -> &Parser { + self.parser.borrow() + } + + /// Return a reference to the pattern being parsed. + fn pattern(&self) -> &str { + self.pattern + } + + /// Create a new error with the given span and error type. + fn error(&self, span: Span, kind: ast::ErrorKind) -> ast::Error { + ast::Error { kind, pattern: self.pattern().to_string(), span } + } + + /// Return the current offset of the parser. + /// + /// The offset starts at `0` from the beginning of the regular expression + /// pattern string. + fn offset(&self) -> usize { + self.parser().pos.get().offset + } + + /// Return the current line number of the parser. + /// + /// The line number starts at `1`. + fn line(&self) -> usize { + self.parser().pos.get().line + } + + /// Return the current column of the parser. + /// + /// The column number starts at `1` and is reset whenever a `\n` is seen. + fn column(&self) -> usize { + self.parser().pos.get().column + } + + /// Return the next capturing index. Each subsequent call increments the + /// internal index. + /// + /// The span given should correspond to the location of the opening + /// parenthesis. + /// + /// If the capture limit is exceeded, then an error is returned. + fn next_capture_index(&self, span: Span) -> Result { + let current = self.parser().capture_index.get(); + let i = current.checked_add(1).ok_or_else(|| { + self.error(span, ast::ErrorKind::CaptureLimitExceeded) + })?; + self.parser().capture_index.set(i); + Ok(i) + } + + /// Adds the given capture name to this parser. If this capture name has + /// already been used, then an error is returned. + fn add_capture_name(&self, cap: &ast::CaptureName) -> Result<()> { + let mut names = self.parser().capture_names.borrow_mut(); + match names + .binary_search_by_key(&cap.name.as_str(), |c| c.name.as_str()) + { + Err(i) => { + names.insert(i, cap.clone()); + Ok(()) + } + Ok(i) => Err(self.error( + cap.span, + ast::ErrorKind::GroupNameDuplicate { original: names[i].span }, + )), + } + } + + /// Return whether the parser should ignore whitespace or not. + fn ignore_whitespace(&self) -> bool { + self.parser().ignore_whitespace.get() + } + + /// Return the character at the current position of the parser. + /// + /// This panics if the current position does not point to a valid char. + fn char(&self) -> char { + self.char_at(self.offset()) + } + + /// Return the character at the given position. + /// + /// This panics if the given position does not point to a valid char. + fn char_at(&self, i: usize) -> char { + self.pattern()[i..] + .chars() + .next() + .unwrap_or_else(|| panic!("expected char at offset {}", i)) + } + + /// Bump the parser to the next Unicode scalar value. + /// + /// If the end of the input has been reached, then `false` is returned. + fn bump(&self) -> bool { + if self.is_eof() { + return false; + } + let Position { mut offset, mut line, mut column } = self.pos(); + if self.char() == '\n' { + line = line.checked_add(1).unwrap(); + column = 1; + } else { + column = column.checked_add(1).unwrap(); + } + offset += self.char().len_utf8(); + self.parser().pos.set(Position { offset, line, column }); + self.pattern()[self.offset()..].chars().next().is_some() + } + + /// If the substring starting at the current position of the parser has + /// the given prefix, then bump the parser to the character immediately + /// following the prefix and return true. Otherwise, don't bump the parser + /// and return false. + fn bump_if(&self, prefix: &str) -> bool { + if self.pattern()[self.offset()..].starts_with(prefix) { + for _ in 0..prefix.chars().count() { + self.bump(); + } + true + } else { + false + } + } + + /// Returns true if and only if the parser is positioned at a look-around + /// prefix. The conditions under which this returns true must always + /// correspond to a regular expression that would otherwise be consider + /// invalid. + /// + /// This should only be called immediately after parsing the opening of + /// a group or a set of flags. + fn is_lookaround_prefix(&self) -> bool { + self.bump_if("?=") + || self.bump_if("?!") + || self.bump_if("?<=") + || self.bump_if("? bool { + if !self.bump() { + return false; + } + self.bump_space(); + !self.is_eof() + } + + /// If the `x` flag is enabled (i.e., whitespace insensitivity with + /// comments), then this will advance the parser through all whitespace + /// and comments to the next non-whitespace non-comment byte. + /// + /// If the `x` flag is disabled, then this is a no-op. + /// + /// This should be used selectively throughout the parser where + /// arbitrary whitespace is permitted when the `x` flag is enabled. For + /// example, `{ 5 , 6}` is equivalent to `{5,6}`. + fn bump_space(&self) { + if !self.ignore_whitespace() { + return; + } + while !self.is_eof() { + if self.char().is_whitespace() { + self.bump(); + } else if self.char() == '#' { + let start = self.pos(); + let mut comment_text = String::new(); + self.bump(); + while !self.is_eof() { + let c = self.char(); + self.bump(); + if c == '\n' { + break; + } + comment_text.push(c); + } + let comment = ast::Comment { + span: Span::new(start, self.pos()), + comment: comment_text, + }; + self.parser().comments.borrow_mut().push(comment); + } else { + break; + } + } + } + + /// Peek at the next character in the input without advancing the parser. + /// + /// If the input has been exhausted, then this returns `None`. + fn peek(&self) -> Option { + if self.is_eof() { + return None; + } + self.pattern()[self.offset() + self.char().len_utf8()..].chars().next() + } + + /// Like peek, but will ignore spaces when the parser is in whitespace + /// insensitive mode. + fn peek_space(&self) -> Option { + if !self.ignore_whitespace() { + return self.peek(); + } + if self.is_eof() { + return None; + } + let mut start = self.offset() + self.char().len_utf8(); + let mut in_comment = false; + for (i, c) in self.pattern()[start..].char_indices() { + if c.is_whitespace() { + continue; + } else if !in_comment && c == '#' { + in_comment = true; + } else if in_comment && c == '\n' { + in_comment = false; + } else { + start += i; + break; + } + } + self.pattern()[start..].chars().next() + } + + /// Returns true if the next call to `bump` would return false. + fn is_eof(&self) -> bool { + self.offset() == self.pattern().len() + } + + /// Return the current position of the parser, which includes the offset, + /// line and column. + fn pos(&self) -> Position { + self.parser().pos.get() + } + + /// Create a span at the current position of the parser. Both the start + /// and end of the span are set. + fn span(&self) -> Span { + Span::splat(self.pos()) + } + + /// Create a span that covers the current character. + fn span_char(&self) -> Span { + let mut next = Position { + offset: self.offset().checked_add(self.char().len_utf8()).unwrap(), + line: self.line(), + column: self.column().checked_add(1).unwrap(), + }; + if self.char() == '\n' { + next.line += 1; + next.column = 1; + } + Span::new(self.pos(), next) + } + + /// Parse and push a single alternation on to the parser's internal stack. + /// If the top of the stack already has an alternation, then add to that + /// instead of pushing a new one. + /// + /// The concatenation given corresponds to a single alternation branch. + /// The concatenation returned starts the next branch and is empty. + /// + /// This assumes the parser is currently positioned at `|` and will advance + /// the parser to the character following `|`. + #[inline(never)] + fn push_alternate(&self, mut concat: ast::Concat) -> Result { + assert_eq!(self.char(), '|'); + concat.span.end = self.pos(); + self.push_or_add_alternation(concat); + self.bump(); + Ok(ast::Concat { span: self.span(), asts: vec![] }) + } + + /// Pushes or adds the given branch of an alternation to the parser's + /// internal stack of state. + fn push_or_add_alternation(&self, concat: ast::Concat) { + use self::GroupState::*; + + let mut stack = self.parser().stack_group.borrow_mut(); + if let Some(&mut Alternation(ref mut alts)) = stack.last_mut() { + alts.asts.push(concat.into_ast()); + return; + } + stack.push(Alternation(ast::Alternation { + span: Span::new(concat.span.start, self.pos()), + asts: vec![concat.into_ast()], + })); + } + + /// Parse and push a group AST (and its parent concatenation) on to the + /// parser's internal stack. Return a fresh concatenation corresponding + /// to the group's sub-AST. + /// + /// If a set of flags was found (with no group), then the concatenation + /// is returned with that set of flags added. + /// + /// This assumes that the parser is currently positioned on the opening + /// parenthesis. It advances the parser to the character at the start + /// of the sub-expression (or adjoining expression). + /// + /// If there was a problem parsing the start of the group, then an error + /// is returned. + #[inline(never)] + fn push_group(&self, mut concat: ast::Concat) -> Result { + assert_eq!(self.char(), '('); + match self.parse_group()? { + Either::Left(set) => { + let ignore = set.flags.flag_state(ast::Flag::IgnoreWhitespace); + if let Some(v) = ignore { + self.parser().ignore_whitespace.set(v); + } + + concat.asts.push(Ast::Flags(set)); + Ok(concat) + } + Either::Right(group) => { + let old_ignore_whitespace = self.ignore_whitespace(); + let new_ignore_whitespace = group + .flags() + .and_then(|f| f.flag_state(ast::Flag::IgnoreWhitespace)) + .unwrap_or(old_ignore_whitespace); + self.parser().stack_group.borrow_mut().push( + GroupState::Group { + concat, + group, + ignore_whitespace: old_ignore_whitespace, + }, + ); + self.parser().ignore_whitespace.set(new_ignore_whitespace); + Ok(ast::Concat { span: self.span(), asts: vec![] }) + } + } + } + + /// Pop a group AST from the parser's internal stack and set the group's + /// AST to the given concatenation. Return the concatenation containing + /// the group. + /// + /// This assumes that the parser is currently positioned on the closing + /// parenthesis and advances the parser to the character following the `)`. + /// + /// If no such group could be popped, then an unopened group error is + /// returned. + #[inline(never)] + fn pop_group(&self, mut group_concat: ast::Concat) -> Result { + use self::GroupState::*; + + assert_eq!(self.char(), ')'); + let mut stack = self.parser().stack_group.borrow_mut(); + let (mut prior_concat, mut group, ignore_whitespace, alt) = match stack + .pop() + { + Some(Group { concat, group, ignore_whitespace }) => { + (concat, group, ignore_whitespace, None) + } + Some(Alternation(alt)) => match stack.pop() { + Some(Group { concat, group, ignore_whitespace }) => { + (concat, group, ignore_whitespace, Some(alt)) + } + None | Some(Alternation(_)) => { + return Err(self.error( + self.span_char(), + ast::ErrorKind::GroupUnopened, + )); + } + }, + None => { + return Err(self + .error(self.span_char(), ast::ErrorKind::GroupUnopened)); + } + }; + self.parser().ignore_whitespace.set(ignore_whitespace); + group_concat.span.end = self.pos(); + self.bump(); + group.span.end = self.pos(); + match alt { + Some(mut alt) => { + alt.span.end = group_concat.span.end; + alt.asts.push(group_concat.into_ast()); + group.ast = Box::new(alt.into_ast()); + } + None => { + group.ast = Box::new(group_concat.into_ast()); + } + } + prior_concat.asts.push(Ast::Group(group)); + Ok(prior_concat) + } + + /// Pop the last state from the parser's internal stack, if it exists, and + /// add the given concatenation to it. There either must be no state or a + /// single alternation item on the stack. Any other scenario produces an + /// error. + /// + /// This assumes that the parser has advanced to the end. + #[inline(never)] + fn pop_group_end(&self, mut concat: ast::Concat) -> Result { + concat.span.end = self.pos(); + let mut stack = self.parser().stack_group.borrow_mut(); + let ast = match stack.pop() { + None => Ok(concat.into_ast()), + Some(GroupState::Alternation(mut alt)) => { + alt.span.end = self.pos(); + alt.asts.push(concat.into_ast()); + Ok(Ast::Alternation(alt)) + } + Some(GroupState::Group { group, .. }) => { + return Err( + self.error(group.span, ast::ErrorKind::GroupUnclosed) + ); + } + }; + // If we try to pop again, there should be nothing. + match stack.pop() { + None => ast, + Some(GroupState::Alternation(_)) => { + // This unreachable is unfortunate. This case can't happen + // because the only way we can be here is if there were two + // `GroupState::Alternation`s adjacent in the parser's stack, + // which we guarantee to never happen because we never push a + // `GroupState::Alternation` if one is already at the top of + // the stack. + unreachable!() + } + Some(GroupState::Group { group, .. }) => { + Err(self.error(group.span, ast::ErrorKind::GroupUnclosed)) + } + } + } + + /// Parse the opening of a character class and push the current class + /// parsing context onto the parser's stack. This assumes that the parser + /// is positioned at an opening `[`. The given union should correspond to + /// the union of set items built up before seeing the `[`. + /// + /// If there was a problem parsing the opening of the class, then an error + /// is returned. Otherwise, a new union of set items for the class is + /// returned (which may be populated with either a `]` or a `-`). + #[inline(never)] + fn push_class_open( + &self, + parent_union: ast::ClassSetUnion, + ) -> Result { + assert_eq!(self.char(), '['); + + let (nested_set, nested_union) = self.parse_set_class_open()?; + self.parser() + .stack_class + .borrow_mut() + .push(ClassState::Open { union: parent_union, set: nested_set }); + Ok(nested_union) + } + + /// Parse the end of a character class set and pop the character class + /// parser stack. The union given corresponds to the last union built + /// before seeing the closing `]`. The union returned corresponds to the + /// parent character class set with the nested class added to it. + /// + /// This assumes that the parser is positioned at a `]` and will advance + /// the parser to the byte immediately following the `]`. + /// + /// If the stack is empty after popping, then this returns the final + /// "top-level" character class AST (where a "top-level" character class + /// is one that is not nested inside any other character class). + /// + /// If there is no corresponding opening bracket on the parser's stack, + /// then an error is returned. + #[inline(never)] + fn pop_class( + &self, + nested_union: ast::ClassSetUnion, + ) -> Result> { + assert_eq!(self.char(), ']'); + + let item = ast::ClassSet::Item(nested_union.into_item()); + let prevset = self.pop_class_op(item); + let mut stack = self.parser().stack_class.borrow_mut(); + match stack.pop() { + None => { + // We can never observe an empty stack: + // + // 1) We are guaranteed to start with a non-empty stack since + // the character class parser is only initiated when it sees + // a `[`. + // 2) If we ever observe an empty stack while popping after + // seeing a `]`, then we signal the character class parser + // to terminate. + panic!("unexpected empty character class stack") + } + Some(ClassState::Op { .. }) => { + // This panic is unfortunate, but this case is impossible + // since we already popped the Op state if one exists above. + // Namely, every push to the class parser stack is guarded by + // whether an existing Op is already on the top of the stack. + // If it is, the existing Op is modified. That is, the stack + // can never have consecutive Op states. + panic!("unexpected ClassState::Op") + } + Some(ClassState::Open { mut union, mut set }) => { + self.bump(); + set.span.end = self.pos(); + set.kind = prevset; + if stack.is_empty() { + Ok(Either::Right(ast::Class::Bracketed(set))) + } else { + union.push(ast::ClassSetItem::Bracketed(Box::new(set))); + Ok(Either::Left(union)) + } + } + } + } + + /// Return an "unclosed class" error whose span points to the most + /// recently opened class. + /// + /// This should only be called while parsing a character class. + #[inline(never)] + fn unclosed_class_error(&self) -> ast::Error { + for state in self.parser().stack_class.borrow().iter().rev() { + if let ClassState::Open { ref set, .. } = *state { + return self.error(set.span, ast::ErrorKind::ClassUnclosed); + } + } + // We are guaranteed to have a non-empty stack with at least + // one open bracket, so we should never get here. + panic!("no open character class found") + } + + /// Push the current set of class items on to the class parser's stack as + /// the left hand side of the given operator. + /// + /// A fresh set union is returned, which should be used to build the right + /// hand side of this operator. + #[inline(never)] + fn push_class_op( + &self, + next_kind: ast::ClassSetBinaryOpKind, + next_union: ast::ClassSetUnion, + ) -> ast::ClassSetUnion { + let item = ast::ClassSet::Item(next_union.into_item()); + let new_lhs = self.pop_class_op(item); + self.parser() + .stack_class + .borrow_mut() + .push(ClassState::Op { kind: next_kind, lhs: new_lhs }); + ast::ClassSetUnion { span: self.span(), items: vec![] } + } + + /// Pop a character class set from the character class parser stack. If the + /// top of the stack is just an item (not an operation), then return the + /// given set unchanged. If the top of the stack is an operation, then the + /// given set will be used as the rhs of the operation on the top of the + /// stack. In that case, the binary operation is returned as a set. + #[inline(never)] + fn pop_class_op(&self, rhs: ast::ClassSet) -> ast::ClassSet { + let mut stack = self.parser().stack_class.borrow_mut(); + let (kind, lhs) = match stack.pop() { + Some(ClassState::Op { kind, lhs }) => (kind, lhs), + Some(state @ ClassState::Open { .. }) => { + stack.push(state); + return rhs; + } + None => unreachable!(), + }; + let span = Span::new(lhs.span().start, rhs.span().end); + ast::ClassSet::BinaryOp(ast::ClassSetBinaryOp { + span, + kind, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } +} + +impl<'s, P: Borrow> ParserI<'s, P> { + /// Parse the regular expression into an abstract syntax tree. + fn parse(&self) -> Result { + self.parse_with_comments().map(|astc| astc.ast) + } + + /// Parse the regular expression and return an abstract syntax tree with + /// all of the comments found in the pattern. + fn parse_with_comments(&self) -> Result { + assert_eq!(self.offset(), 0, "parser can only be used once"); + self.parser().reset(); + let mut concat = ast::Concat { span: self.span(), asts: vec![] }; + loop { + self.bump_space(); + if self.is_eof() { + break; + } + match self.char() { + '(' => concat = self.push_group(concat)?, + ')' => concat = self.pop_group(concat)?, + '|' => concat = self.push_alternate(concat)?, + '[' => { + let class = self.parse_set_class()?; + concat.asts.push(Ast::Class(class)); + } + '?' => { + concat = self.parse_uncounted_repetition( + concat, + ast::RepetitionKind::ZeroOrOne, + )?; + } + '*' => { + concat = self.parse_uncounted_repetition( + concat, + ast::RepetitionKind::ZeroOrMore, + )?; + } + '+' => { + concat = self.parse_uncounted_repetition( + concat, + ast::RepetitionKind::OneOrMore, + )?; + } + '{' => { + concat = self.parse_counted_repetition(concat)?; + } + _ => concat.asts.push(self.parse_primitive()?.into_ast()), + } + } + let ast = self.pop_group_end(concat)?; + NestLimiter::new(self).check(&ast)?; + Ok(ast::WithComments { + ast, + comments: mem::replace( + &mut *self.parser().comments.borrow_mut(), + vec![], + ), + }) + } + + /// Parses an uncounted repetition operation. An uncounted repetition + /// operator includes ?, * and +, but does not include the {m,n} syntax. + /// The given `kind` should correspond to the operator observed by the + /// caller. + /// + /// This assumes that the parser is currently positioned at the repetition + /// operator and advances the parser to the first character after the + /// operator. (Note that the operator may include a single additional `?`, + /// which makes the operator ungreedy.) + /// + /// The caller should include the concatenation that is being built. The + /// concatenation returned includes the repetition operator applied to the + /// last expression in the given concatenation. + #[inline(never)] + fn parse_uncounted_repetition( + &self, + mut concat: ast::Concat, + kind: ast::RepetitionKind, + ) -> Result { + assert!( + self.char() == '?' || self.char() == '*' || self.char() == '+' + ); + let op_start = self.pos(); + let ast = match concat.asts.pop() { + Some(ast) => ast, + None => { + return Err( + self.error(self.span(), ast::ErrorKind::RepetitionMissing) + ) + } + }; + match ast { + Ast::Empty(_) | Ast::Flags(_) => { + return Err( + self.error(self.span(), ast::ErrorKind::RepetitionMissing) + ) + } + _ => {} + } + let mut greedy = true; + if self.bump() && self.char() == '?' { + greedy = false; + self.bump(); + } + concat.asts.push(Ast::Repetition(ast::Repetition { + span: ast.span().with_end(self.pos()), + op: ast::RepetitionOp { + span: Span::new(op_start, self.pos()), + kind, + }, + greedy, + ast: Box::new(ast), + })); + Ok(concat) + } + + /// Parses a counted repetition operation. A counted repetition operator + /// corresponds to the {m,n} syntax, and does not include the ?, * or + + /// operators. + /// + /// This assumes that the parser is currently positioned at the opening `{` + /// and advances the parser to the first character after the operator. + /// (Note that the operator may include a single additional `?`, which + /// makes the operator ungreedy.) + /// + /// The caller should include the concatenation that is being built. The + /// concatenation returned includes the repetition operator applied to the + /// last expression in the given concatenation. + #[inline(never)] + fn parse_counted_repetition( + &self, + mut concat: ast::Concat, + ) -> Result { + assert!(self.char() == '{'); + let start = self.pos(); + let ast = match concat.asts.pop() { + Some(ast) => ast, + None => { + return Err( + self.error(self.span(), ast::ErrorKind::RepetitionMissing) + ) + } + }; + match ast { + Ast::Empty(_) | Ast::Flags(_) => { + return Err( + self.error(self.span(), ast::ErrorKind::RepetitionMissing) + ) + } + _ => {} + } + if !self.bump_and_bump_space() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::RepetitionCountUnclosed, + )); + } + let count_start = specialize_err( + self.parse_decimal(), + ast::ErrorKind::DecimalEmpty, + ast::ErrorKind::RepetitionCountDecimalEmpty, + )?; + let mut range = ast::RepetitionRange::Exactly(count_start); + if self.is_eof() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::RepetitionCountUnclosed, + )); + } + if self.char() == ',' { + if !self.bump_and_bump_space() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::RepetitionCountUnclosed, + )); + } + if self.char() != '}' { + let count_end = specialize_err( + self.parse_decimal(), + ast::ErrorKind::DecimalEmpty, + ast::ErrorKind::RepetitionCountDecimalEmpty, + )?; + range = ast::RepetitionRange::Bounded(count_start, count_end); + } else { + range = ast::RepetitionRange::AtLeast(count_start); + } + } + if self.is_eof() || self.char() != '}' { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::RepetitionCountUnclosed, + )); + } + + let mut greedy = true; + if self.bump_and_bump_space() && self.char() == '?' { + greedy = false; + self.bump(); + } + + let op_span = Span::new(start, self.pos()); + if !range.is_valid() { + return Err( + self.error(op_span, ast::ErrorKind::RepetitionCountInvalid) + ); + } + concat.asts.push(Ast::Repetition(ast::Repetition { + span: ast.span().with_end(self.pos()), + op: ast::RepetitionOp { + span: op_span, + kind: ast::RepetitionKind::Range(range), + }, + greedy, + ast: Box::new(ast), + })); + Ok(concat) + } + + /// Parse a group (which contains a sub-expression) or a set of flags. + /// + /// If a group was found, then it is returned with an empty AST. If a set + /// of flags is found, then that set is returned. + /// + /// The parser should be positioned at the opening parenthesis. + /// + /// This advances the parser to the character before the start of the + /// sub-expression (in the case of a group) or to the closing parenthesis + /// immediately following the set of flags. + /// + /// # Errors + /// + /// If flags are given and incorrectly specified, then a corresponding + /// error is returned. + /// + /// If a capture name is given and it is incorrectly specified, then a + /// corresponding error is returned. + #[inline(never)] + fn parse_group(&self) -> Result> { + assert_eq!(self.char(), '('); + let open_span = self.span_char(); + self.bump(); + self.bump_space(); + if self.is_lookaround_prefix() { + return Err(self.error( + Span::new(open_span.start, self.span().end), + ast::ErrorKind::UnsupportedLookAround, + )); + } + let inner_span = self.span(); + let mut starts_with_p = true; + if self.bump_if("?P<") || { + starts_with_p = false; + self.bump_if("?<") + } { + let capture_index = self.next_capture_index(open_span)?; + let name = self.parse_capture_name(capture_index)?; + Ok(Either::Right(ast::Group { + span: open_span, + kind: ast::GroupKind::CaptureName { starts_with_p, name }, + ast: Box::new(Ast::Empty(self.span())), + })) + } else if self.bump_if("?") { + if self.is_eof() { + return Err( + self.error(open_span, ast::ErrorKind::GroupUnclosed) + ); + } + let flags = self.parse_flags()?; + let char_end = self.char(); + self.bump(); + if char_end == ')' { + // We don't allow empty flags, e.g., `(?)`. We instead + // interpret it as a repetition operator missing its argument. + if flags.items.is_empty() { + return Err(self.error( + inner_span, + ast::ErrorKind::RepetitionMissing, + )); + } + Ok(Either::Left(ast::SetFlags { + span: Span { end: self.pos(), ..open_span }, + flags, + })) + } else { + assert_eq!(char_end, ':'); + Ok(Either::Right(ast::Group { + span: open_span, + kind: ast::GroupKind::NonCapturing(flags), + ast: Box::new(Ast::Empty(self.span())), + })) + } + } else { + let capture_index = self.next_capture_index(open_span)?; + Ok(Either::Right(ast::Group { + span: open_span, + kind: ast::GroupKind::CaptureIndex(capture_index), + ast: Box::new(Ast::Empty(self.span())), + })) + } + } + + /// Parses a capture group name. Assumes that the parser is positioned at + /// the first character in the name following the opening `<` (and may + /// possibly be EOF). This advances the parser to the first character + /// following the closing `>`. + /// + /// The caller must provide the capture index of the group for this name. + #[inline(never)] + fn parse_capture_name( + &self, + capture_index: u32, + ) -> Result { + if self.is_eof() { + return Err(self + .error(self.span(), ast::ErrorKind::GroupNameUnexpectedEof)); + } + let start = self.pos(); + loop { + if self.char() == '>' { + break; + } + if !is_capture_char(self.char(), self.pos() == start) { + return Err(self.error( + self.span_char(), + ast::ErrorKind::GroupNameInvalid, + )); + } + if !self.bump() { + break; + } + } + let end = self.pos(); + if self.is_eof() { + return Err(self + .error(self.span(), ast::ErrorKind::GroupNameUnexpectedEof)); + } + assert_eq!(self.char(), '>'); + self.bump(); + let name = &self.pattern()[start.offset..end.offset]; + if name.is_empty() { + return Err(self.error( + Span::new(start, start), + ast::ErrorKind::GroupNameEmpty, + )); + } + let capname = ast::CaptureName { + span: Span::new(start, end), + name: name.to_string(), + index: capture_index, + }; + self.add_capture_name(&capname)?; + Ok(capname) + } + + /// Parse a sequence of flags starting at the current character. + /// + /// This advances the parser to the character immediately following the + /// flags, which is guaranteed to be either `:` or `)`. + /// + /// # Errors + /// + /// If any flags are duplicated, then an error is returned. + /// + /// If the negation operator is used more than once, then an error is + /// returned. + /// + /// If no flags could be found or if the negation operation is not followed + /// by any flags, then an error is returned. + #[inline(never)] + fn parse_flags(&self) -> Result { + let mut flags = ast::Flags { span: self.span(), items: vec![] }; + let mut last_was_negation = None; + while self.char() != ':' && self.char() != ')' { + if self.char() == '-' { + last_was_negation = Some(self.span_char()); + let item = ast::FlagsItem { + span: self.span_char(), + kind: ast::FlagsItemKind::Negation, + }; + if let Some(i) = flags.add_item(item) { + return Err(self.error( + self.span_char(), + ast::ErrorKind::FlagRepeatedNegation { + original: flags.items[i].span, + }, + )); + } + } else { + last_was_negation = None; + let item = ast::FlagsItem { + span: self.span_char(), + kind: ast::FlagsItemKind::Flag(self.parse_flag()?), + }; + if let Some(i) = flags.add_item(item) { + return Err(self.error( + self.span_char(), + ast::ErrorKind::FlagDuplicate { + original: flags.items[i].span, + }, + )); + } + } + if !self.bump() { + return Err( + self.error(self.span(), ast::ErrorKind::FlagUnexpectedEof) + ); + } + } + if let Some(span) = last_was_negation { + return Err(self.error(span, ast::ErrorKind::FlagDanglingNegation)); + } + flags.span.end = self.pos(); + Ok(flags) + } + + /// Parse the current character as a flag. Do not advance the parser. + /// + /// # Errors + /// + /// If the flag is not recognized, then an error is returned. + #[inline(never)] + fn parse_flag(&self) -> Result { + match self.char() { + 'i' => Ok(ast::Flag::CaseInsensitive), + 'm' => Ok(ast::Flag::MultiLine), + 's' => Ok(ast::Flag::DotMatchesNewLine), + 'U' => Ok(ast::Flag::SwapGreed), + 'u' => Ok(ast::Flag::Unicode), + 'R' => Ok(ast::Flag::CRLF), + 'x' => Ok(ast::Flag::IgnoreWhitespace), + _ => { + Err(self + .error(self.span_char(), ast::ErrorKind::FlagUnrecognized)) + } + } + } + + /// Parse a primitive AST. e.g., A literal, non-set character class or + /// assertion. + /// + /// This assumes that the parser expects a primitive at the current + /// location. i.e., All other non-primitive cases have been handled. + /// For example, if the parser's position is at `|`, then `|` will be + /// treated as a literal (e.g., inside a character class). + /// + /// This advances the parser to the first character immediately following + /// the primitive. + fn parse_primitive(&self) -> Result { + match self.char() { + '\\' => self.parse_escape(), + '.' => { + let ast = Primitive::Dot(self.span_char()); + self.bump(); + Ok(ast) + } + '^' => { + let ast = Primitive::Assertion(ast::Assertion { + span: self.span_char(), + kind: ast::AssertionKind::StartLine, + }); + self.bump(); + Ok(ast) + } + '$' => { + let ast = Primitive::Assertion(ast::Assertion { + span: self.span_char(), + kind: ast::AssertionKind::EndLine, + }); + self.bump(); + Ok(ast) + } + c => { + let ast = Primitive::Literal(ast::Literal { + span: self.span_char(), + kind: ast::LiteralKind::Verbatim, + c, + }); + self.bump(); + Ok(ast) + } + } + } + + /// Parse an escape sequence as a primitive AST. + /// + /// This assumes the parser is positioned at the start of the escape + /// sequence, i.e., `\`. It advances the parser to the first position + /// immediately following the escape sequence. + #[inline(never)] + fn parse_escape(&self) -> Result { + assert_eq!(self.char(), '\\'); + let start = self.pos(); + if !self.bump() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::EscapeUnexpectedEof, + )); + } + let c = self.char(); + // Put some of the more complicated routines into helpers. + match c { + '0'..='7' => { + if !self.parser().octal { + return Err(self.error( + Span::new(start, self.span_char().end), + ast::ErrorKind::UnsupportedBackreference, + )); + } + let mut lit = self.parse_octal(); + lit.span.start = start; + return Ok(Primitive::Literal(lit)); + } + '8'..='9' if !self.parser().octal => { + return Err(self.error( + Span::new(start, self.span_char().end), + ast::ErrorKind::UnsupportedBackreference, + )); + } + 'x' | 'u' | 'U' => { + let mut lit = self.parse_hex()?; + lit.span.start = start; + return Ok(Primitive::Literal(lit)); + } + 'p' | 'P' => { + let mut cls = self.parse_unicode_class()?; + cls.span.start = start; + return Ok(Primitive::Unicode(cls)); + } + 'd' | 's' | 'w' | 'D' | 'S' | 'W' => { + let mut cls = self.parse_perl_class(); + cls.span.start = start; + return Ok(Primitive::Perl(cls)); + } + _ => {} + } + + // Handle all of the one letter sequences inline. + self.bump(); + let span = Span::new(start, self.pos()); + if is_meta_character(c) { + return Ok(Primitive::Literal(ast::Literal { + span, + kind: ast::LiteralKind::Meta, + c, + })); + } + if is_escapeable_character(c) { + return Ok(Primitive::Literal(ast::Literal { + span, + kind: ast::LiteralKind::Superfluous, + c, + })); + } + let special = |kind, c| { + Ok(Primitive::Literal(ast::Literal { + span, + kind: ast::LiteralKind::Special(kind), + c, + })) + }; + match c { + 'a' => special(ast::SpecialLiteralKind::Bell, '\x07'), + 'f' => special(ast::SpecialLiteralKind::FormFeed, '\x0C'), + 't' => special(ast::SpecialLiteralKind::Tab, '\t'), + 'n' => special(ast::SpecialLiteralKind::LineFeed, '\n'), + 'r' => special(ast::SpecialLiteralKind::CarriageReturn, '\r'), + 'v' => special(ast::SpecialLiteralKind::VerticalTab, '\x0B'), + 'A' => Ok(Primitive::Assertion(ast::Assertion { + span, + kind: ast::AssertionKind::StartText, + })), + 'z' => Ok(Primitive::Assertion(ast::Assertion { + span, + kind: ast::AssertionKind::EndText, + })), + 'b' => Ok(Primitive::Assertion(ast::Assertion { + span, + kind: ast::AssertionKind::WordBoundary, + })), + 'B' => Ok(Primitive::Assertion(ast::Assertion { + span, + kind: ast::AssertionKind::NotWordBoundary, + })), + _ => Err(self.error(span, ast::ErrorKind::EscapeUnrecognized)), + } + } + + /// Parse an octal representation of a Unicode codepoint up to 3 digits + /// long. This expects the parser to be positioned at the first octal + /// digit and advances the parser to the first character immediately + /// following the octal number. This also assumes that parsing octal + /// escapes is enabled. + /// + /// Assuming the preconditions are met, this routine can never fail. + #[inline(never)] + fn parse_octal(&self) -> ast::Literal { + assert!(self.parser().octal); + assert!('0' <= self.char() && self.char() <= '7'); + let start = self.pos(); + // Parse up to two more digits. + while self.bump() + && '0' <= self.char() + && self.char() <= '7' + && self.pos().offset - start.offset <= 2 + {} + let end = self.pos(); + let octal = &self.pattern()[start.offset..end.offset]; + // Parsing the octal should never fail since the above guarantees a + // valid number. + let codepoint = + u32::from_str_radix(octal, 8).expect("valid octal number"); + // The max value for 3 digit octal is 0777 = 511 and [0, 511] has no + // invalid Unicode scalar values. + let c = char::from_u32(codepoint).expect("Unicode scalar value"); + ast::Literal { + span: Span::new(start, end), + kind: ast::LiteralKind::Octal, + c, + } + } + + /// Parse a hex representation of a Unicode codepoint. This handles both + /// hex notations, i.e., `\xFF` and `\x{FFFF}`. This expects the parser to + /// be positioned at the `x`, `u` or `U` prefix. The parser is advanced to + /// the first character immediately following the hexadecimal literal. + #[inline(never)] + fn parse_hex(&self) -> Result { + assert!( + self.char() == 'x' || self.char() == 'u' || self.char() == 'U' + ); + + let hex_kind = match self.char() { + 'x' => ast::HexLiteralKind::X, + 'u' => ast::HexLiteralKind::UnicodeShort, + _ => ast::HexLiteralKind::UnicodeLong, + }; + if !self.bump_and_bump_space() { + return Err( + self.error(self.span(), ast::ErrorKind::EscapeUnexpectedEof) + ); + } + if self.char() == '{' { + self.parse_hex_brace(hex_kind) + } else { + self.parse_hex_digits(hex_kind) + } + } + + /// Parse an N-digit hex representation of a Unicode codepoint. This + /// expects the parser to be positioned at the first digit and will advance + /// the parser to the first character immediately following the escape + /// sequence. + /// + /// The number of digits given must be 2 (for `\xNN`), 4 (for `\uNNNN`) + /// or 8 (for `\UNNNNNNNN`). + #[inline(never)] + fn parse_hex_digits( + &self, + kind: ast::HexLiteralKind, + ) -> Result { + let mut scratch = self.parser().scratch.borrow_mut(); + scratch.clear(); + + let start = self.pos(); + for i in 0..kind.digits() { + if i > 0 && !self.bump_and_bump_space() { + return Err(self + .error(self.span(), ast::ErrorKind::EscapeUnexpectedEof)); + } + if !is_hex(self.char()) { + return Err(self.error( + self.span_char(), + ast::ErrorKind::EscapeHexInvalidDigit, + )); + } + scratch.push(self.char()); + } + // The final bump just moves the parser past the literal, which may + // be EOF. + self.bump_and_bump_space(); + let end = self.pos(); + let hex = scratch.as_str(); + match u32::from_str_radix(hex, 16).ok().and_then(char::from_u32) { + None => Err(self.error( + Span::new(start, end), + ast::ErrorKind::EscapeHexInvalid, + )), + Some(c) => Ok(ast::Literal { + span: Span::new(start, end), + kind: ast::LiteralKind::HexFixed(kind), + c, + }), + } + } + + /// Parse a hex representation of any Unicode scalar value. This expects + /// the parser to be positioned at the opening brace `{` and will advance + /// the parser to the first character following the closing brace `}`. + #[inline(never)] + fn parse_hex_brace( + &self, + kind: ast::HexLiteralKind, + ) -> Result { + let mut scratch = self.parser().scratch.borrow_mut(); + scratch.clear(); + + let brace_pos = self.pos(); + let start = self.span_char().end; + while self.bump_and_bump_space() && self.char() != '}' { + if !is_hex(self.char()) { + return Err(self.error( + self.span_char(), + ast::ErrorKind::EscapeHexInvalidDigit, + )); + } + scratch.push(self.char()); + } + if self.is_eof() { + return Err(self.error( + Span::new(brace_pos, self.pos()), + ast::ErrorKind::EscapeUnexpectedEof, + )); + } + let end = self.pos(); + let hex = scratch.as_str(); + assert_eq!(self.char(), '}'); + self.bump_and_bump_space(); + + if hex.is_empty() { + return Err(self.error( + Span::new(brace_pos, self.pos()), + ast::ErrorKind::EscapeHexEmpty, + )); + } + match u32::from_str_radix(hex, 16).ok().and_then(char::from_u32) { + None => Err(self.error( + Span::new(start, end), + ast::ErrorKind::EscapeHexInvalid, + )), + Some(c) => Ok(ast::Literal { + span: Span::new(start, self.pos()), + kind: ast::LiteralKind::HexBrace(kind), + c, + }), + } + } + + /// Parse a decimal number into a u32 while trimming leading and trailing + /// whitespace. + /// + /// This expects the parser to be positioned at the first position where + /// a decimal digit could occur. This will advance the parser to the byte + /// immediately following the last contiguous decimal digit. + /// + /// If no decimal digit could be found or if there was a problem parsing + /// the complete set of digits into a u32, then an error is returned. + fn parse_decimal(&self) -> Result { + let mut scratch = self.parser().scratch.borrow_mut(); + scratch.clear(); + + while !self.is_eof() && self.char().is_whitespace() { + self.bump(); + } + let start = self.pos(); + while !self.is_eof() && '0' <= self.char() && self.char() <= '9' { + scratch.push(self.char()); + self.bump_and_bump_space(); + } + let span = Span::new(start, self.pos()); + while !self.is_eof() && self.char().is_whitespace() { + self.bump_and_bump_space(); + } + let digits = scratch.as_str(); + if digits.is_empty() { + return Err(self.error(span, ast::ErrorKind::DecimalEmpty)); + } + match u32::from_str_radix(digits, 10).ok() { + Some(n) => Ok(n), + None => Err(self.error(span, ast::ErrorKind::DecimalInvalid)), + } + } + + /// Parse a standard character class consisting primarily of characters or + /// character ranges, but can also contain nested character classes of + /// any type (sans `.`). + /// + /// This assumes the parser is positioned at the opening `[`. If parsing + /// is successful, then the parser is advanced to the position immediately + /// following the closing `]`. + #[inline(never)] + fn parse_set_class(&self) -> Result { + assert_eq!(self.char(), '['); + + let mut union = + ast::ClassSetUnion { span: self.span(), items: vec![] }; + loop { + self.bump_space(); + if self.is_eof() { + return Err(self.unclosed_class_error()); + } + match self.char() { + '[' => { + // If we've already parsed the opening bracket, then + // attempt to treat this as the beginning of an ASCII + // class. If ASCII class parsing fails, then the parser + // backs up to `[`. + if !self.parser().stack_class.borrow().is_empty() { + if let Some(cls) = self.maybe_parse_ascii_class() { + union.push(ast::ClassSetItem::Ascii(cls)); + continue; + } + } + union = self.push_class_open(union)?; + } + ']' => match self.pop_class(union)? { + Either::Left(nested_union) => { + union = nested_union; + } + Either::Right(class) => return Ok(class), + }, + '&' if self.peek() == Some('&') => { + assert!(self.bump_if("&&")); + union = self.push_class_op( + ast::ClassSetBinaryOpKind::Intersection, + union, + ); + } + '-' if self.peek() == Some('-') => { + assert!(self.bump_if("--")); + union = self.push_class_op( + ast::ClassSetBinaryOpKind::Difference, + union, + ); + } + '~' if self.peek() == Some('~') => { + assert!(self.bump_if("~~")); + union = self.push_class_op( + ast::ClassSetBinaryOpKind::SymmetricDifference, + union, + ); + } + _ => { + union.push(self.parse_set_class_range()?); + } + } + } + } + + /// Parse a single primitive item in a character class set. The item to + /// be parsed can either be one of a simple literal character, a range + /// between two simple literal characters or a "primitive" character + /// class like \w or \p{Greek}. + /// + /// If an invalid escape is found, or if a character class is found where + /// a simple literal is expected (e.g., in a range), then an error is + /// returned. + #[inline(never)] + fn parse_set_class_range(&self) -> Result { + let prim1 = self.parse_set_class_item()?; + self.bump_space(); + if self.is_eof() { + return Err(self.unclosed_class_error()); + } + // If the next char isn't a `-`, then we don't have a range. + // There are two exceptions. If the char after a `-` is a `]`, then + // `-` is interpreted as a literal `-`. Alternatively, if the char + // after a `-` is a `-`, then `--` corresponds to a "difference" + // operation. + if self.char() != '-' + || self.peek_space() == Some(']') + || self.peek_space() == Some('-') + { + return prim1.into_class_set_item(self); + } + // OK, now we're parsing a range, so bump past the `-` and parse the + // second half of the range. + if !self.bump_and_bump_space() { + return Err(self.unclosed_class_error()); + } + let prim2 = self.parse_set_class_item()?; + let range = ast::ClassSetRange { + span: Span::new(prim1.span().start, prim2.span().end), + start: prim1.into_class_literal(self)?, + end: prim2.into_class_literal(self)?, + }; + if !range.is_valid() { + return Err( + self.error(range.span, ast::ErrorKind::ClassRangeInvalid) + ); + } + Ok(ast::ClassSetItem::Range(range)) + } + + /// Parse a single item in a character class as a primitive, where the + /// primitive either consists of a verbatim literal or a single escape + /// sequence. + /// + /// This assumes the parser is positioned at the beginning of a primitive, + /// and advances the parser to the first position after the primitive if + /// successful. + /// + /// Note that it is the caller's responsibility to report an error if an + /// illegal primitive was parsed. + #[inline(never)] + fn parse_set_class_item(&self) -> Result { + if self.char() == '\\' { + self.parse_escape() + } else { + let x = Primitive::Literal(ast::Literal { + span: self.span_char(), + kind: ast::LiteralKind::Verbatim, + c: self.char(), + }); + self.bump(); + Ok(x) + } + } + + /// Parses the opening of a character class set. This includes the opening + /// bracket along with `^` if present to indicate negation. This also + /// starts parsing the opening set of unioned items if applicable, since + /// there are special rules applied to certain characters in the opening + /// of a character class. For example, `[^]]` is the class of all + /// characters not equal to `]`. (`]` would need to be escaped in any other + /// position.) Similarly for `-`. + /// + /// In all cases, the op inside the returned `ast::ClassBracketed` is an + /// empty union. This empty union should be replaced with the actual item + /// when it is popped from the parser's stack. + /// + /// This assumes the parser is positioned at the opening `[` and advances + /// the parser to the first non-special byte of the character class. + /// + /// An error is returned if EOF is found. + #[inline(never)] + fn parse_set_class_open( + &self, + ) -> Result<(ast::ClassBracketed, ast::ClassSetUnion)> { + assert_eq!(self.char(), '['); + let start = self.pos(); + if !self.bump_and_bump_space() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::ClassUnclosed, + )); + } + + let negated = if self.char() != '^' { + false + } else { + if !self.bump_and_bump_space() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::ClassUnclosed, + )); + } + true + }; + // Accept any number of `-` as literal `-`. + let mut union = + ast::ClassSetUnion { span: self.span(), items: vec![] }; + while self.char() == '-' { + union.push(ast::ClassSetItem::Literal(ast::Literal { + span: self.span_char(), + kind: ast::LiteralKind::Verbatim, + c: '-', + })); + if !self.bump_and_bump_space() { + return Err(self.error( + Span::new(start, start), + ast::ErrorKind::ClassUnclosed, + )); + } + } + // If `]` is the *first* char in a set, then interpret it as a literal + // `]`. That is, an empty class is impossible to write. + if union.items.is_empty() && self.char() == ']' { + union.push(ast::ClassSetItem::Literal(ast::Literal { + span: self.span_char(), + kind: ast::LiteralKind::Verbatim, + c: ']', + })); + if !self.bump_and_bump_space() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::ClassUnclosed, + )); + } + } + let set = ast::ClassBracketed { + span: Span::new(start, self.pos()), + negated, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: Span::new(union.span.start, union.span.start), + items: vec![], + }), + }; + Ok((set, union)) + } + + /// Attempt to parse an ASCII character class, e.g., `[:alnum:]`. + /// + /// This assumes the parser is positioned at the opening `[`. + /// + /// If no valid ASCII character class could be found, then this does not + /// advance the parser and `None` is returned. Otherwise, the parser is + /// advanced to the first byte following the closing `]` and the + /// corresponding ASCII class is returned. + #[inline(never)] + fn maybe_parse_ascii_class(&self) -> Option { + // ASCII character classes are interesting from a parsing perspective + // because parsing cannot fail with any interesting error. For example, + // in order to use an ASCII character class, it must be enclosed in + // double brackets, e.g., `[[:alnum:]]`. Alternatively, you might think + // of it as "ASCII character characters have the syntax `[:NAME:]` + // which can only appear within character brackets." This means that + // things like `[[:lower:]A]` are legal constructs. + // + // However, if one types an incorrect ASCII character class, e.g., + // `[[:loower:]]`, then we treat that as a normal nested character + // class containing the characters `:elorw`. One might argue that we + // should return an error instead since the repeated colons give away + // the intent to write an ASCII class. But what if the user typed + // `[[:lower]]` instead? How can we tell that was intended to be an + // ASCII class and not just a normal nested class? + // + // Reasonable people can probably disagree over this, but for better + // or worse, we implement semantics that never fails at the expense + // of better failure modes. + assert_eq!(self.char(), '['); + // If parsing fails, then we back up the parser to this starting point. + let start = self.pos(); + let mut negated = false; + if !self.bump() || self.char() != ':' { + self.parser().pos.set(start); + return None; + } + if !self.bump() { + self.parser().pos.set(start); + return None; + } + if self.char() == '^' { + negated = true; + if !self.bump() { + self.parser().pos.set(start); + return None; + } + } + let name_start = self.offset(); + while self.char() != ':' && self.bump() {} + if self.is_eof() { + self.parser().pos.set(start); + return None; + } + let name = &self.pattern()[name_start..self.offset()]; + if !self.bump_if(":]") { + self.parser().pos.set(start); + return None; + } + let kind = match ast::ClassAsciiKind::from_name(name) { + Some(kind) => kind, + None => { + self.parser().pos.set(start); + return None; + } + }; + Some(ast::ClassAscii { + span: Span::new(start, self.pos()), + kind, + negated, + }) + } + + /// Parse a Unicode class in either the single character notation, `\pN` + /// or the multi-character bracketed notation, `\p{Greek}`. This assumes + /// the parser is positioned at the `p` (or `P` for negation) and will + /// advance the parser to the character immediately following the class. + /// + /// Note that this does not check whether the class name is valid or not. + #[inline(never)] + fn parse_unicode_class(&self) -> Result { + assert!(self.char() == 'p' || self.char() == 'P'); + + let mut scratch = self.parser().scratch.borrow_mut(); + scratch.clear(); + + let negated = self.char() == 'P'; + if !self.bump_and_bump_space() { + return Err( + self.error(self.span(), ast::ErrorKind::EscapeUnexpectedEof) + ); + } + let (start, kind) = if self.char() == '{' { + let start = self.span_char().end; + while self.bump_and_bump_space() && self.char() != '}' { + scratch.push(self.char()); + } + if self.is_eof() { + return Err(self + .error(self.span(), ast::ErrorKind::EscapeUnexpectedEof)); + } + assert_eq!(self.char(), '}'); + self.bump(); + + let name = scratch.as_str(); + if let Some(i) = name.find("!=") { + ( + start, + ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::NotEqual, + name: name[..i].to_string(), + value: name[i + 2..].to_string(), + }, + ) + } else if let Some(i) = name.find(':') { + ( + start, + ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::Colon, + name: name[..i].to_string(), + value: name[i + 1..].to_string(), + }, + ) + } else if let Some(i) = name.find('=') { + ( + start, + ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::Equal, + name: name[..i].to_string(), + value: name[i + 1..].to_string(), + }, + ) + } else { + (start, ast::ClassUnicodeKind::Named(name.to_string())) + } + } else { + let start = self.pos(); + let c = self.char(); + if c == '\\' { + return Err(self.error( + self.span_char(), + ast::ErrorKind::UnicodeClassInvalid, + )); + } + self.bump_and_bump_space(); + let kind = ast::ClassUnicodeKind::OneLetter(c); + (start, kind) + }; + Ok(ast::ClassUnicode { + span: Span::new(start, self.pos()), + negated, + kind, + }) + } + + /// Parse a Perl character class, e.g., `\d` or `\W`. This assumes the + /// parser is currently at a valid character class name and will be + /// advanced to the character immediately following the class. + #[inline(never)] + fn parse_perl_class(&self) -> ast::ClassPerl { + let c = self.char(); + let span = self.span_char(); + self.bump(); + let (negated, kind) = match c { + 'd' => (false, ast::ClassPerlKind::Digit), + 'D' => (true, ast::ClassPerlKind::Digit), + 's' => (false, ast::ClassPerlKind::Space), + 'S' => (true, ast::ClassPerlKind::Space), + 'w' => (false, ast::ClassPerlKind::Word), + 'W' => (true, ast::ClassPerlKind::Word), + c => panic!("expected valid Perl class but got '{}'", c), + }; + ast::ClassPerl { span, kind, negated } + } +} + +/// A type that traverses a fully parsed Ast and checks whether its depth +/// exceeds the specified nesting limit. If it does, then an error is returned. +#[derive(Debug)] +struct NestLimiter<'p, 's, P> { + /// The parser that is checking the nest limit. + p: &'p ParserI<'s, P>, + /// The current depth while walking an Ast. + depth: u32, +} + +impl<'p, 's, P: Borrow> NestLimiter<'p, 's, P> { + fn new(p: &'p ParserI<'s, P>) -> NestLimiter<'p, 's, P> { + NestLimiter { p, depth: 0 } + } + + #[inline(never)] + fn check(self, ast: &Ast) -> Result<()> { + ast::visit(ast, self) + } + + fn increment_depth(&mut self, span: &Span) -> Result<()> { + let new = self.depth.checked_add(1).ok_or_else(|| { + self.p.error( + span.clone(), + ast::ErrorKind::NestLimitExceeded(u32::MAX), + ) + })?; + let limit = self.p.parser().nest_limit; + if new > limit { + return Err(self.p.error( + span.clone(), + ast::ErrorKind::NestLimitExceeded(limit), + )); + } + self.depth = new; + Ok(()) + } + + fn decrement_depth(&mut self) { + // Assuming the correctness of the visitor, this should never drop + // below 0. + self.depth = self.depth.checked_sub(1).unwrap(); + } +} + +impl<'p, 's, P: Borrow> ast::Visitor for NestLimiter<'p, 's, P> { + type Output = (); + type Err = ast::Error; + + fn finish(self) -> Result<()> { + Ok(()) + } + + fn visit_pre(&mut self, ast: &Ast) -> Result<()> { + let span = match *ast { + Ast::Empty(_) + | Ast::Flags(_) + | Ast::Literal(_) + | Ast::Dot(_) + | Ast::Assertion(_) + | Ast::Class(ast::Class::Unicode(_)) + | Ast::Class(ast::Class::Perl(_)) => { + // These are all base cases, so we don't increment depth. + return Ok(()); + } + Ast::Class(ast::Class::Bracketed(ref x)) => &x.span, + Ast::Repetition(ref x) => &x.span, + Ast::Group(ref x) => &x.span, + Ast::Alternation(ref x) => &x.span, + Ast::Concat(ref x) => &x.span, + }; + self.increment_depth(span) + } + + fn visit_post(&mut self, ast: &Ast) -> Result<()> { + match *ast { + Ast::Empty(_) + | Ast::Flags(_) + | Ast::Literal(_) + | Ast::Dot(_) + | Ast::Assertion(_) + | Ast::Class(ast::Class::Unicode(_)) + | Ast::Class(ast::Class::Perl(_)) => { + // These are all base cases, so we don't decrement depth. + Ok(()) + } + Ast::Class(ast::Class::Bracketed(_)) + | Ast::Repetition(_) + | Ast::Group(_) + | Ast::Alternation(_) + | Ast::Concat(_) => { + self.decrement_depth(); + Ok(()) + } + } + } + + fn visit_class_set_item_pre( + &mut self, + ast: &ast::ClassSetItem, + ) -> Result<()> { + let span = match *ast { + ast::ClassSetItem::Empty(_) + | ast::ClassSetItem::Literal(_) + | ast::ClassSetItem::Range(_) + | ast::ClassSetItem::Ascii(_) + | ast::ClassSetItem::Unicode(_) + | ast::ClassSetItem::Perl(_) => { + // These are all base cases, so we don't increment depth. + return Ok(()); + } + ast::ClassSetItem::Bracketed(ref x) => &x.span, + ast::ClassSetItem::Union(ref x) => &x.span, + }; + self.increment_depth(span) + } + + fn visit_class_set_item_post( + &mut self, + ast: &ast::ClassSetItem, + ) -> Result<()> { + match *ast { + ast::ClassSetItem::Empty(_) + | ast::ClassSetItem::Literal(_) + | ast::ClassSetItem::Range(_) + | ast::ClassSetItem::Ascii(_) + | ast::ClassSetItem::Unicode(_) + | ast::ClassSetItem::Perl(_) => { + // These are all base cases, so we don't decrement depth. + Ok(()) + } + ast::ClassSetItem::Bracketed(_) | ast::ClassSetItem::Union(_) => { + self.decrement_depth(); + Ok(()) + } + } + } + + fn visit_class_set_binary_op_pre( + &mut self, + ast: &ast::ClassSetBinaryOp, + ) -> Result<()> { + self.increment_depth(&ast.span) + } + + fn visit_class_set_binary_op_post( + &mut self, + _ast: &ast::ClassSetBinaryOp, + ) -> Result<()> { + self.decrement_depth(); + Ok(()) + } +} + +/// When the result is an error, transforms the ast::ErrorKind from the source +/// Result into another one. This function is used to return clearer error +/// messages when possible. +fn specialize_err( + result: Result, + from: ast::ErrorKind, + to: ast::ErrorKind, +) -> Result { + if let Err(e) = result { + if e.kind == from { + Err(ast::Error { kind: to, pattern: e.pattern, span: e.span }) + } else { + Err(e) + } + } else { + result + } +} + +#[cfg(test)] +mod tests { + use core::ops::Range; + + use alloc::format; + + use crate::ast::{self, Ast, Position, Span}; + + use super::*; + + // Our own assert_eq, which has slightly better formatting (but honestly + // still kind of crappy). + macro_rules! assert_eq { + ($left:expr, $right:expr) => {{ + match (&$left, &$right) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + panic!( + "assertion failed: `(left == right)`\n\n\ + left: `{:?}`\nright: `{:?}`\n\n", + left_val, right_val + ) + } + } + } + }}; + } + + // We create these errors to compare with real ast::Errors in the tests. + // We define equality between TestError and ast::Error to disregard the + // pattern string in ast::Error, which is annoying to provide in tests. + #[derive(Clone, Debug)] + struct TestError { + span: Span, + kind: ast::ErrorKind, + } + + impl PartialEq for TestError { + fn eq(&self, other: &ast::Error) -> bool { + self.span == other.span && self.kind == other.kind + } + } + + impl PartialEq for ast::Error { + fn eq(&self, other: &TestError) -> bool { + self.span == other.span && self.kind == other.kind + } + } + + fn s(str: &str) -> String { + str.to_string() + } + + fn parser(pattern: &str) -> ParserI<'_, Parser> { + ParserI::new(Parser::new(), pattern) + } + + fn parser_octal(pattern: &str) -> ParserI<'_, Parser> { + let parser = ParserBuilder::new().octal(true).build(); + ParserI::new(parser, pattern) + } + + fn parser_nest_limit( + pattern: &str, + nest_limit: u32, + ) -> ParserI<'_, Parser> { + let p = ParserBuilder::new().nest_limit(nest_limit).build(); + ParserI::new(p, pattern) + } + + fn parser_ignore_whitespace(pattern: &str) -> ParserI<'_, Parser> { + let p = ParserBuilder::new().ignore_whitespace(true).build(); + ParserI::new(p, pattern) + } + + /// Short alias for creating a new span. + fn nspan(start: Position, end: Position) -> Span { + Span::new(start, end) + } + + /// Short alias for creating a new position. + fn npos(offset: usize, line: usize, column: usize) -> Position { + Position::new(offset, line, column) + } + + /// Create a new span from the given offset range. This assumes a single + /// line and sets the columns based on the offsets. i.e., This only works + /// out of the box for ASCII, which is fine for most tests. + fn span(range: Range) -> Span { + let start = Position::new(range.start, 1, range.start + 1); + let end = Position::new(range.end, 1, range.end + 1); + Span::new(start, end) + } + + /// Create a new span for the corresponding byte range in the given string. + fn span_range(subject: &str, range: Range) -> Span { + let start = Position { + offset: range.start, + line: 1 + subject[..range.start].matches('\n').count(), + column: 1 + subject[..range.start] + .chars() + .rev() + .position(|c| c == '\n') + .unwrap_or(subject[..range.start].chars().count()), + }; + let end = Position { + offset: range.end, + line: 1 + subject[..range.end].matches('\n').count(), + column: 1 + subject[..range.end] + .chars() + .rev() + .position(|c| c == '\n') + .unwrap_or(subject[..range.end].chars().count()), + }; + Span::new(start, end) + } + + /// Create a verbatim literal starting at the given position. + fn lit(c: char, start: usize) -> Ast { + lit_with(c, span(start..start + c.len_utf8())) + } + + /// Create a meta literal starting at the given position. + fn meta_lit(c: char, span: Span) -> Ast { + Ast::Literal(ast::Literal { span, kind: ast::LiteralKind::Meta, c }) + } + + /// Create a verbatim literal with the given span. + fn lit_with(c: char, span: Span) -> Ast { + Ast::Literal(ast::Literal { + span, + kind: ast::LiteralKind::Verbatim, + c, + }) + } + + /// Create a concatenation with the given range. + fn concat(range: Range, asts: Vec) -> Ast { + concat_with(span(range), asts) + } + + /// Create a concatenation with the given span. + fn concat_with(span: Span, asts: Vec) -> Ast { + Ast::Concat(ast::Concat { span, asts }) + } + + /// Create an alternation with the given span. + fn alt(range: Range, asts: Vec) -> Ast { + Ast::Alternation(ast::Alternation { span: span(range), asts }) + } + + /// Create a capturing group with the given span. + fn group(range: Range, index: u32, ast: Ast) -> Ast { + Ast::Group(ast::Group { + span: span(range), + kind: ast::GroupKind::CaptureIndex(index), + ast: Box::new(ast), + }) + } + + /// Create an ast::SetFlags. + /// + /// The given pattern should be the full pattern string. The range given + /// should correspond to the byte offsets where the flag set occurs. + /// + /// If negated is true, then the set is interpreted as beginning with a + /// negation. + fn flag_set( + pat: &str, + range: Range, + flag: ast::Flag, + negated: bool, + ) -> Ast { + let mut items = vec![ast::FlagsItem { + span: span_range(pat, (range.end - 2)..(range.end - 1)), + kind: ast::FlagsItemKind::Flag(flag), + }]; + if negated { + items.insert( + 0, + ast::FlagsItem { + span: span_range(pat, (range.start + 2)..(range.end - 2)), + kind: ast::FlagsItemKind::Negation, + }, + ); + } + Ast::Flags(ast::SetFlags { + span: span_range(pat, range.clone()), + flags: ast::Flags { + span: span_range(pat, (range.start + 2)..(range.end - 1)), + items, + }, + }) + } + + #[test] + fn parse_nest_limit() { + // A nest limit of 0 still allows some types of regexes. + assert_eq!( + parser_nest_limit("", 0).parse(), + Ok(Ast::Empty(span(0..0))) + ); + assert_eq!(parser_nest_limit("a", 0).parse(), Ok(lit('a', 0))); + + // Test repetition operations, which require one level of nesting. + assert_eq!( + parser_nest_limit("a+", 0).parse().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::NestLimitExceeded(0), + } + ); + assert_eq!( + parser_nest_limit("a+", 1).parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::OneOrMore, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + })) + ); + assert_eq!( + parser_nest_limit("(a)+", 1).parse().unwrap_err(), + TestError { + span: span(0..3), + kind: ast::ErrorKind::NestLimitExceeded(1), + } + ); + assert_eq!( + parser_nest_limit("a+*", 1).parse().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::NestLimitExceeded(1), + } + ); + assert_eq!( + parser_nest_limit("a+*", 2).parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..3), + op: ast::RepetitionOp { + span: span(2..3), + kind: ast::RepetitionKind::ZeroOrMore, + }, + greedy: true, + ast: Box::new(Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::OneOrMore, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + })), + })) + ); + + // Test concatenations. A concatenation requires one level of nesting. + assert_eq!( + parser_nest_limit("ab", 0).parse().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::NestLimitExceeded(0), + } + ); + assert_eq!( + parser_nest_limit("ab", 1).parse(), + Ok(concat(0..2, vec![lit('a', 0), lit('b', 1)])) + ); + assert_eq!( + parser_nest_limit("abc", 1).parse(), + Ok(concat(0..3, vec![lit('a', 0), lit('b', 1), lit('c', 2)])) + ); + + // Test alternations. An alternation requires one level of nesting. + assert_eq!( + parser_nest_limit("a|b", 0).parse().unwrap_err(), + TestError { + span: span(0..3), + kind: ast::ErrorKind::NestLimitExceeded(0), + } + ); + assert_eq!( + parser_nest_limit("a|b", 1).parse(), + Ok(alt(0..3, vec![lit('a', 0), lit('b', 2)])) + ); + assert_eq!( + parser_nest_limit("a|b|c", 1).parse(), + Ok(alt(0..5, vec![lit('a', 0), lit('b', 2), lit('c', 4)])) + ); + + // Test character classes. Classes form their own mini-recursive + // syntax! + assert_eq!( + parser_nest_limit("[a]", 0).parse().unwrap_err(), + TestError { + span: span(0..3), + kind: ast::ErrorKind::NestLimitExceeded(0), + } + ); + assert_eq!( + parser_nest_limit("[a]", 1).parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..3), + negated: false, + kind: ast::ClassSet::Item(ast::ClassSetItem::Literal( + ast::Literal { + span: span(1..2), + kind: ast::LiteralKind::Verbatim, + c: 'a', + } + )), + }))) + ); + assert_eq!( + parser_nest_limit("[ab]", 1).parse().unwrap_err(), + TestError { + span: span(1..3), + kind: ast::ErrorKind::NestLimitExceeded(1), + } + ); + assert_eq!( + parser_nest_limit("[ab[cd]]", 2).parse().unwrap_err(), + TestError { + span: span(3..7), + kind: ast::ErrorKind::NestLimitExceeded(2), + } + ); + assert_eq!( + parser_nest_limit("[ab[cd]]", 3).parse().unwrap_err(), + TestError { + span: span(4..6), + kind: ast::ErrorKind::NestLimitExceeded(3), + } + ); + assert_eq!( + parser_nest_limit("[a--b]", 1).parse().unwrap_err(), + TestError { + span: span(1..5), + kind: ast::ErrorKind::NestLimitExceeded(1), + } + ); + assert_eq!( + parser_nest_limit("[a--bc]", 2).parse().unwrap_err(), + TestError { + span: span(4..6), + kind: ast::ErrorKind::NestLimitExceeded(2), + } + ); + } + + #[test] + fn parse_comments() { + let pat = "(?x) +# This is comment 1. +foo # This is comment 2. + # This is comment 3. +bar +# This is comment 4."; + let astc = parser(pat).parse_with_comments().unwrap(); + assert_eq!( + astc.ast, + concat_with( + span_range(pat, 0..pat.len()), + vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + lit_with('f', span_range(pat, 26..27)), + lit_with('o', span_range(pat, 27..28)), + lit_with('o', span_range(pat, 28..29)), + lit_with('b', span_range(pat, 74..75)), + lit_with('a', span_range(pat, 75..76)), + lit_with('r', span_range(pat, 76..77)), + ] + ) + ); + assert_eq!( + astc.comments, + vec![ + ast::Comment { + span: span_range(pat, 5..26), + comment: s(" This is comment 1."), + }, + ast::Comment { + span: span_range(pat, 30..51), + comment: s(" This is comment 2."), + }, + ast::Comment { + span: span_range(pat, 53..74), + comment: s(" This is comment 3."), + }, + ast::Comment { + span: span_range(pat, 78..98), + comment: s(" This is comment 4."), + }, + ] + ); + } + + #[test] + fn parse_holistic() { + assert_eq!(parser("]").parse(), Ok(lit(']', 0))); + assert_eq!( + parser(r"\\\.\+\*\?\(\)\|\[\]\{\}\^\$\#\&\-\~").parse(), + Ok(concat( + 0..36, + vec![ + meta_lit('\\', span(0..2)), + meta_lit('.', span(2..4)), + meta_lit('+', span(4..6)), + meta_lit('*', span(6..8)), + meta_lit('?', span(8..10)), + meta_lit('(', span(10..12)), + meta_lit(')', span(12..14)), + meta_lit('|', span(14..16)), + meta_lit('[', span(16..18)), + meta_lit(']', span(18..20)), + meta_lit('{', span(20..22)), + meta_lit('}', span(22..24)), + meta_lit('^', span(24..26)), + meta_lit('$', span(26..28)), + meta_lit('#', span(28..30)), + meta_lit('&', span(30..32)), + meta_lit('-', span(32..34)), + meta_lit('~', span(34..36)), + ] + )) + ); + } + + #[test] + fn parse_ignore_whitespace() { + // Test that basic whitespace insensitivity works. + let pat = "(?x)a b"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with( + nspan(npos(0, 1, 1), npos(7, 1, 8)), + vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + lit_with('a', nspan(npos(4, 1, 5), npos(5, 1, 6))), + lit_with('b', nspan(npos(6, 1, 7), npos(7, 1, 8))), + ] + )) + ); + + // Test that we can toggle whitespace insensitivity. + let pat = "(?x)a b(?-x)a b"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with( + nspan(npos(0, 1, 1), npos(15, 1, 16)), + vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + lit_with('a', nspan(npos(4, 1, 5), npos(5, 1, 6))), + lit_with('b', nspan(npos(6, 1, 7), npos(7, 1, 8))), + flag_set(pat, 7..12, ast::Flag::IgnoreWhitespace, true), + lit_with('a', nspan(npos(12, 1, 13), npos(13, 1, 14))), + lit_with(' ', nspan(npos(13, 1, 14), npos(14, 1, 15))), + lit_with('b', nspan(npos(14, 1, 15), npos(15, 1, 16))), + ] + )) + ); + + // Test that nesting whitespace insensitive flags works. + let pat = "a (?x:a )a "; + assert_eq!( + parser(pat).parse(), + Ok(concat_with( + span_range(pat, 0..11), + vec![ + lit_with('a', span_range(pat, 0..1)), + lit_with(' ', span_range(pat, 1..2)), + Ast::Group(ast::Group { + span: span_range(pat, 2..9), + kind: ast::GroupKind::NonCapturing(ast::Flags { + span: span_range(pat, 4..5), + items: vec![ast::FlagsItem { + span: span_range(pat, 4..5), + kind: ast::FlagsItemKind::Flag( + ast::Flag::IgnoreWhitespace + ), + },], + }), + ast: Box::new(lit_with('a', span_range(pat, 6..7))), + }), + lit_with('a', span_range(pat, 9..10)), + lit_with(' ', span_range(pat, 10..11)), + ] + )) + ); + + // Test that whitespace after an opening paren is insignificant. + let pat = "(?x)( ?P a )"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with( + span_range(pat, 0..pat.len()), + vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + Ast::Group(ast::Group { + span: span_range(pat, 4..pat.len()), + kind: ast::GroupKind::CaptureName { + starts_with_p: true, + name: ast::CaptureName { + span: span_range(pat, 9..12), + name: s("foo"), + index: 1, + } + }, + ast: Box::new(lit_with('a', span_range(pat, 14..15))), + }), + ] + )) + ); + let pat = "(?x)( a )"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with( + span_range(pat, 0..pat.len()), + vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + Ast::Group(ast::Group { + span: span_range(pat, 4..pat.len()), + kind: ast::GroupKind::CaptureIndex(1), + ast: Box::new(lit_with('a', span_range(pat, 7..8))), + }), + ] + )) + ); + let pat = "(?x)( ?: a )"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with( + span_range(pat, 0..pat.len()), + vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + Ast::Group(ast::Group { + span: span_range(pat, 4..pat.len()), + kind: ast::GroupKind::NonCapturing(ast::Flags { + span: span_range(pat, 8..8), + items: vec![], + }), + ast: Box::new(lit_with('a', span_range(pat, 11..12))), + }), + ] + )) + ); + let pat = r"(?x)\x { 53 }"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with( + span_range(pat, 0..pat.len()), + vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + Ast::Literal(ast::Literal { + span: span(4..13), + kind: ast::LiteralKind::HexBrace( + ast::HexLiteralKind::X + ), + c: 'S', + }), + ] + )) + ); + + // Test that whitespace after an escape is OK. + let pat = r"(?x)\ "; + assert_eq!( + parser(pat).parse(), + Ok(concat_with( + span_range(pat, 0..pat.len()), + vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + Ast::Literal(ast::Literal { + span: span_range(pat, 4..6), + kind: ast::LiteralKind::Superfluous, + c: ' ', + }), + ] + )) + ); + } + + #[test] + fn parse_newlines() { + let pat = ".\n."; + assert_eq!( + parser(pat).parse(), + Ok(concat_with( + span_range(pat, 0..3), + vec![ + Ast::Dot(span_range(pat, 0..1)), + lit_with('\n', span_range(pat, 1..2)), + Ast::Dot(span_range(pat, 2..3)), + ] + )) + ); + + let pat = "foobar\nbaz\nquux\n"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with( + span_range(pat, 0..pat.len()), + vec![ + lit_with('f', nspan(npos(0, 1, 1), npos(1, 1, 2))), + lit_with('o', nspan(npos(1, 1, 2), npos(2, 1, 3))), + lit_with('o', nspan(npos(2, 1, 3), npos(3, 1, 4))), + lit_with('b', nspan(npos(3, 1, 4), npos(4, 1, 5))), + lit_with('a', nspan(npos(4, 1, 5), npos(5, 1, 6))), + lit_with('r', nspan(npos(5, 1, 6), npos(6, 1, 7))), + lit_with('\n', nspan(npos(6, 1, 7), npos(7, 2, 1))), + lit_with('b', nspan(npos(7, 2, 1), npos(8, 2, 2))), + lit_with('a', nspan(npos(8, 2, 2), npos(9, 2, 3))), + lit_with('z', nspan(npos(9, 2, 3), npos(10, 2, 4))), + lit_with('\n', nspan(npos(10, 2, 4), npos(11, 3, 1))), + lit_with('q', nspan(npos(11, 3, 1), npos(12, 3, 2))), + lit_with('u', nspan(npos(12, 3, 2), npos(13, 3, 3))), + lit_with('u', nspan(npos(13, 3, 3), npos(14, 3, 4))), + lit_with('x', nspan(npos(14, 3, 4), npos(15, 3, 5))), + lit_with('\n', nspan(npos(15, 3, 5), npos(16, 4, 1))), + ] + )) + ); + } + + #[test] + fn parse_uncounted_repetition() { + assert_eq!( + parser(r"a*").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::ZeroOrMore, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + })) + ); + assert_eq!( + parser(r"a+").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::OneOrMore, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + })) + ); + + assert_eq!( + parser(r"a?").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + })) + ); + assert_eq!( + parser(r"a??").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..3), + op: ast::RepetitionOp { + span: span(1..3), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: false, + ast: Box::new(lit('a', 0)), + })) + ); + assert_eq!( + parser(r"a?").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + })) + ); + assert_eq!( + parser(r"a?b").parse(), + Ok(concat( + 0..3, + vec![ + Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + }), + lit('b', 2), + ] + )) + ); + assert_eq!( + parser(r"a??b").parse(), + Ok(concat( + 0..4, + vec![ + Ast::Repetition(ast::Repetition { + span: span(0..3), + op: ast::RepetitionOp { + span: span(1..3), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: false, + ast: Box::new(lit('a', 0)), + }), + lit('b', 3), + ] + )) + ); + assert_eq!( + parser(r"ab?").parse(), + Ok(concat( + 0..3, + vec![ + lit('a', 0), + Ast::Repetition(ast::Repetition { + span: span(1..3), + op: ast::RepetitionOp { + span: span(2..3), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: true, + ast: Box::new(lit('b', 1)), + }), + ] + )) + ); + assert_eq!( + parser(r"(ab)?").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..5), + op: ast::RepetitionOp { + span: span(4..5), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: true, + ast: Box::new(group( + 0..4, + 1, + concat(1..3, vec![lit('a', 1), lit('b', 2),]) + )), + })) + ); + assert_eq!( + parser(r"|a?").parse(), + Ok(alt( + 0..3, + vec![ + Ast::Empty(span(0..0)), + Ast::Repetition(ast::Repetition { + span: span(1..3), + op: ast::RepetitionOp { + span: span(2..3), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: true, + ast: Box::new(lit('a', 1)), + }), + ] + )) + ); + + assert_eq!( + parser(r"*").parse().unwrap_err(), + TestError { + span: span(0..0), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + assert_eq!( + parser(r"(?i)*").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + assert_eq!( + parser(r"(*)").parse().unwrap_err(), + TestError { + span: span(1..1), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + assert_eq!( + parser(r"(?:?)").parse().unwrap_err(), + TestError { + span: span(3..3), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + assert_eq!( + parser(r"+").parse().unwrap_err(), + TestError { + span: span(0..0), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + assert_eq!( + parser(r"?").parse().unwrap_err(), + TestError { + span: span(0..0), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + assert_eq!( + parser(r"(?)").parse().unwrap_err(), + TestError { + span: span(1..1), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + assert_eq!( + parser(r"|*").parse().unwrap_err(), + TestError { + span: span(1..1), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + assert_eq!( + parser(r"|+").parse().unwrap_err(), + TestError { + span: span(1..1), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + assert_eq!( + parser(r"|?").parse().unwrap_err(), + TestError { + span: span(1..1), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + } + + #[test] + fn parse_counted_repetition() { + assert_eq!( + parser(r"a{5}").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..4), + op: ast::RepetitionOp { + span: span(1..4), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Exactly(5) + ), + }, + greedy: true, + ast: Box::new(lit('a', 0)), + })) + ); + assert_eq!( + parser(r"a{5,}").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..5), + op: ast::RepetitionOp { + span: span(1..5), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::AtLeast(5) + ), + }, + greedy: true, + ast: Box::new(lit('a', 0)), + })) + ); + assert_eq!( + parser(r"a{5,9}").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..6), + op: ast::RepetitionOp { + span: span(1..6), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Bounded(5, 9) + ), + }, + greedy: true, + ast: Box::new(lit('a', 0)), + })) + ); + assert_eq!( + parser(r"a{5}?").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..5), + op: ast::RepetitionOp { + span: span(1..5), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Exactly(5) + ), + }, + greedy: false, + ast: Box::new(lit('a', 0)), + })) + ); + assert_eq!( + parser(r"ab{5}").parse(), + Ok(concat( + 0..5, + vec![ + lit('a', 0), + Ast::Repetition(ast::Repetition { + span: span(1..5), + op: ast::RepetitionOp { + span: span(2..5), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Exactly(5) + ), + }, + greedy: true, + ast: Box::new(lit('b', 1)), + }), + ] + )) + ); + assert_eq!( + parser(r"ab{5}c").parse(), + Ok(concat( + 0..6, + vec![ + lit('a', 0), + Ast::Repetition(ast::Repetition { + span: span(1..5), + op: ast::RepetitionOp { + span: span(2..5), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Exactly(5) + ), + }, + greedy: true, + ast: Box::new(lit('b', 1)), + }), + lit('c', 5), + ] + )) + ); + + assert_eq!( + parser(r"a{ 5 }").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..6), + op: ast::RepetitionOp { + span: span(1..6), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Exactly(5) + ), + }, + greedy: true, + ast: Box::new(lit('a', 0)), + })) + ); + assert_eq!( + parser(r"a{ 5 , 9 }").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..10), + op: ast::RepetitionOp { + span: span(1..10), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Bounded(5, 9) + ), + }, + greedy: true, + ast: Box::new(lit('a', 0)), + })) + ); + assert_eq!( + parser_ignore_whitespace(r"a{5,9} ?").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..8), + op: ast::RepetitionOp { + span: span(1..8), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Bounded(5, 9) + ), + }, + greedy: false, + ast: Box::new(lit('a', 0)), + })) + ); + + assert_eq!( + parser(r"(?i){0}").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + assert_eq!( + parser(r"(?m){1,1}").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + assert_eq!( + parser(r"a{]}").parse().unwrap_err(), + TestError { + span: span(2..2), + kind: ast::ErrorKind::RepetitionCountDecimalEmpty, + } + ); + assert_eq!( + parser(r"a{1,]}").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::RepetitionCountDecimalEmpty, + } + ); + assert_eq!( + parser(r"a{").parse().unwrap_err(), + TestError { + span: span(1..2), + kind: ast::ErrorKind::RepetitionCountUnclosed, + } + ); + assert_eq!( + parser(r"a{}").parse().unwrap_err(), + TestError { + span: span(2..2), + kind: ast::ErrorKind::RepetitionCountDecimalEmpty, + } + ); + assert_eq!( + parser(r"a{a").parse().unwrap_err(), + TestError { + span: span(2..2), + kind: ast::ErrorKind::RepetitionCountDecimalEmpty, + } + ); + assert_eq!( + parser(r"a{9999999999}").parse().unwrap_err(), + TestError { + span: span(2..12), + kind: ast::ErrorKind::DecimalInvalid, + } + ); + assert_eq!( + parser(r"a{9").parse().unwrap_err(), + TestError { + span: span(1..3), + kind: ast::ErrorKind::RepetitionCountUnclosed, + } + ); + assert_eq!( + parser(r"a{9,a").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::RepetitionCountDecimalEmpty, + } + ); + assert_eq!( + parser(r"a{9,9999999999}").parse().unwrap_err(), + TestError { + span: span(4..14), + kind: ast::ErrorKind::DecimalInvalid, + } + ); + assert_eq!( + parser(r"a{9,").parse().unwrap_err(), + TestError { + span: span(1..4), + kind: ast::ErrorKind::RepetitionCountUnclosed, + } + ); + assert_eq!( + parser(r"a{9,11").parse().unwrap_err(), + TestError { + span: span(1..6), + kind: ast::ErrorKind::RepetitionCountUnclosed, + } + ); + assert_eq!( + parser(r"a{2,1}").parse().unwrap_err(), + TestError { + span: span(1..6), + kind: ast::ErrorKind::RepetitionCountInvalid, + } + ); + assert_eq!( + parser(r"{5}").parse().unwrap_err(), + TestError { + span: span(0..0), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + assert_eq!( + parser(r"|{5}").parse().unwrap_err(), + TestError { + span: span(1..1), + kind: ast::ErrorKind::RepetitionMissing, + } + ); + } + + #[test] + fn parse_alternate() { + assert_eq!( + parser(r"a|b").parse(), + Ok(Ast::Alternation(ast::Alternation { + span: span(0..3), + asts: vec![lit('a', 0), lit('b', 2)], + })) + ); + assert_eq!( + parser(r"(a|b)").parse(), + Ok(group( + 0..5, + 1, + Ast::Alternation(ast::Alternation { + span: span(1..4), + asts: vec![lit('a', 1), lit('b', 3)], + }) + )) + ); + + assert_eq!( + parser(r"a|b|c").parse(), + Ok(Ast::Alternation(ast::Alternation { + span: span(0..5), + asts: vec![lit('a', 0), lit('b', 2), lit('c', 4)], + })) + ); + assert_eq!( + parser(r"ax|by|cz").parse(), + Ok(Ast::Alternation(ast::Alternation { + span: span(0..8), + asts: vec![ + concat(0..2, vec![lit('a', 0), lit('x', 1)]), + concat(3..5, vec![lit('b', 3), lit('y', 4)]), + concat(6..8, vec![lit('c', 6), lit('z', 7)]), + ], + })) + ); + assert_eq!( + parser(r"(ax|by|cz)").parse(), + Ok(group( + 0..10, + 1, + Ast::Alternation(ast::Alternation { + span: span(1..9), + asts: vec![ + concat(1..3, vec![lit('a', 1), lit('x', 2)]), + concat(4..6, vec![lit('b', 4), lit('y', 5)]), + concat(7..9, vec![lit('c', 7), lit('z', 8)]), + ], + }) + )) + ); + assert_eq!( + parser(r"(ax|(by|(cz)))").parse(), + Ok(group( + 0..14, + 1, + alt( + 1..13, + vec![ + concat(1..3, vec![lit('a', 1), lit('x', 2)]), + group( + 4..13, + 2, + alt( + 5..12, + vec![ + concat( + 5..7, + vec![lit('b', 5), lit('y', 6)] + ), + group( + 8..12, + 3, + concat( + 9..11, + vec![lit('c', 9), lit('z', 10),] + ) + ), + ] + ) + ), + ] + ) + )) + ); + + assert_eq!( + parser(r"|").parse(), + Ok(alt( + 0..1, + vec![Ast::Empty(span(0..0)), Ast::Empty(span(1..1)),] + )) + ); + assert_eq!( + parser(r"||").parse(), + Ok(alt( + 0..2, + vec![ + Ast::Empty(span(0..0)), + Ast::Empty(span(1..1)), + Ast::Empty(span(2..2)), + ] + )) + ); + assert_eq!( + parser(r"a|").parse(), + Ok(alt(0..2, vec![lit('a', 0), Ast::Empty(span(2..2)),])) + ); + assert_eq!( + parser(r"|a").parse(), + Ok(alt(0..2, vec![Ast::Empty(span(0..0)), lit('a', 1),])) + ); + + assert_eq!( + parser(r"(|)").parse(), + Ok(group( + 0..3, + 1, + alt( + 1..2, + vec![Ast::Empty(span(1..1)), Ast::Empty(span(2..2)),] + ) + )) + ); + assert_eq!( + parser(r"(a|)").parse(), + Ok(group( + 0..4, + 1, + alt(1..3, vec![lit('a', 1), Ast::Empty(span(3..3)),]) + )) + ); + assert_eq!( + parser(r"(|a)").parse(), + Ok(group( + 0..4, + 1, + alt(1..3, vec![Ast::Empty(span(1..1)), lit('a', 2),]) + )) + ); + + assert_eq!( + parser(r"a|b)").parse().unwrap_err(), + TestError { + span: span(3..4), + kind: ast::ErrorKind::GroupUnopened, + } + ); + assert_eq!( + parser(r"(a|b").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::GroupUnclosed, + } + ); + } + + #[test] + fn parse_unsupported_lookaround() { + assert_eq!( + parser(r"(?=a)").parse().unwrap_err(), + TestError { + span: span(0..3), + kind: ast::ErrorKind::UnsupportedLookAround, + } + ); + assert_eq!( + parser(r"(?!a)").parse().unwrap_err(), + TestError { + span: span(0..3), + kind: ast::ErrorKind::UnsupportedLookAround, + } + ); + assert_eq!( + parser(r"(?<=a)").parse().unwrap_err(), + TestError { + span: span(0..4), + kind: ast::ErrorKind::UnsupportedLookAround, + } + ); + assert_eq!( + parser(r"(?z)").parse(), + Ok(Ast::Group(ast::Group { + span: span(0..7), + kind: ast::GroupKind::CaptureName { + starts_with_p: false, + name: ast::CaptureName { + span: span(3..4), + name: s("a"), + index: 1, + } + }, + ast: Box::new(lit('z', 5)), + })) + ); + assert_eq!( + parser("(?Pz)").parse(), + Ok(Ast::Group(ast::Group { + span: span(0..8), + kind: ast::GroupKind::CaptureName { + starts_with_p: true, + name: ast::CaptureName { + span: span(4..5), + name: s("a"), + index: 1, + } + }, + ast: Box::new(lit('z', 6)), + })) + ); + assert_eq!( + parser("(?Pz)").parse(), + Ok(Ast::Group(ast::Group { + span: span(0..10), + kind: ast::GroupKind::CaptureName { + starts_with_p: true, + name: ast::CaptureName { + span: span(4..7), + name: s("abc"), + index: 1, + } + }, + ast: Box::new(lit('z', 8)), + })) + ); + + assert_eq!( + parser("(?Pz)").parse(), + Ok(Ast::Group(ast::Group { + span: span(0..10), + kind: ast::GroupKind::CaptureName { + starts_with_p: true, + name: ast::CaptureName { + span: span(4..7), + name: s("a_1"), + index: 1, + } + }, + ast: Box::new(lit('z', 8)), + })) + ); + + assert_eq!( + parser("(?Pz)").parse(), + Ok(Ast::Group(ast::Group { + span: span(0..10), + kind: ast::GroupKind::CaptureName { + starts_with_p: true, + name: ast::CaptureName { + span: span(4..7), + name: s("a.1"), + index: 1, + } + }, + ast: Box::new(lit('z', 8)), + })) + ); + + assert_eq!( + parser("(?Pz)").parse(), + Ok(Ast::Group(ast::Group { + span: span(0..11), + kind: ast::GroupKind::CaptureName { + starts_with_p: true, + name: ast::CaptureName { + span: span(4..8), + name: s("a[1]"), + index: 1, + } + }, + ast: Box::new(lit('z', 9)), + })) + ); + + assert_eq!( + parser("(?P)").parse(), + Ok(Ast::Group(ast::Group { + span: Span::new( + Position::new(0, 1, 1), + Position::new(9, 1, 9), + ), + kind: ast::GroupKind::CaptureName { + starts_with_p: true, + name: ast::CaptureName { + span: Span::new( + Position::new(4, 1, 5), + Position::new(7, 1, 7), + ), + name: s("a¾"), + index: 1, + } + }, + ast: Box::new(Ast::Empty(Span::new( + Position::new(8, 1, 8), + Position::new(8, 1, 8), + ))), + })) + ); + assert_eq!( + parser("(?P<åå­—>)").parse(), + Ok(Ast::Group(ast::Group { + span: Span::new( + Position::new(0, 1, 1), + Position::new(12, 1, 9), + ), + kind: ast::GroupKind::CaptureName { + starts_with_p: true, + name: ast::CaptureName { + span: Span::new( + Position::new(4, 1, 5), + Position::new(10, 1, 7), + ), + name: s("åå­—"), + index: 1, + } + }, + ast: Box::new(Ast::Empty(Span::new( + Position::new(11, 1, 8), + Position::new(11, 1, 8), + ))), + })) + ); + + assert_eq!( + parser("(?P<").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::GroupNameUnexpectedEof, + } + ); + assert_eq!( + parser("(?P<>z)").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::GroupNameEmpty, + } + ); + assert_eq!( + parser("(?Py)(?Pz)").parse().unwrap_err(), + TestError { + span: span(12..13), + kind: ast::ErrorKind::GroupNameDuplicate { + original: span(4..5), + }, + } + ); + assert_eq!( + parser("(?P<5>)").parse().unwrap_err(), + TestError { + span: span(4..5), + kind: ast::ErrorKind::GroupNameInvalid, + } + ); + assert_eq!( + parser("(?P<5a>)").parse().unwrap_err(), + TestError { + span: span(4..5), + kind: ast::ErrorKind::GroupNameInvalid, + } + ); + assert_eq!( + parser("(?P<¾>)").parse().unwrap_err(), + TestError { + span: Span::new( + Position::new(4, 1, 5), + Position::new(6, 1, 6), + ), + kind: ast::ErrorKind::GroupNameInvalid, + } + ); + assert_eq!( + parser("(?P<¾a>)").parse().unwrap_err(), + TestError { + span: Span::new( + Position::new(4, 1, 5), + Position::new(6, 1, 6), + ), + kind: ast::ErrorKind::GroupNameInvalid, + } + ); + assert_eq!( + parser("(?P<☃>)").parse().unwrap_err(), + TestError { + span: Span::new( + Position::new(4, 1, 5), + Position::new(7, 1, 6), + ), + kind: ast::ErrorKind::GroupNameInvalid, + } + ); + assert_eq!( + parser("(?P)").parse().unwrap_err(), + TestError { + span: Span::new( + Position::new(5, 1, 6), + Position::new(8, 1, 7), + ), + kind: ast::ErrorKind::GroupNameInvalid, + } + ); + } + + #[test] + fn parse_flags() { + assert_eq!( + parser("i:").parse_flags(), + Ok(ast::Flags { + span: span(0..1), + items: vec![ast::FlagsItem { + span: span(0..1), + kind: ast::FlagsItemKind::Flag(ast::Flag::CaseInsensitive), + }], + }) + ); + assert_eq!( + parser("i)").parse_flags(), + Ok(ast::Flags { + span: span(0..1), + items: vec![ast::FlagsItem { + span: span(0..1), + kind: ast::FlagsItemKind::Flag(ast::Flag::CaseInsensitive), + }], + }) + ); + + assert_eq!( + parser("isU:").parse_flags(), + Ok(ast::Flags { + span: span(0..3), + items: vec![ + ast::FlagsItem { + span: span(0..1), + kind: ast::FlagsItemKind::Flag( + ast::Flag::CaseInsensitive + ), + }, + ast::FlagsItem { + span: span(1..2), + kind: ast::FlagsItemKind::Flag( + ast::Flag::DotMatchesNewLine + ), + }, + ast::FlagsItem { + span: span(2..3), + kind: ast::FlagsItemKind::Flag(ast::Flag::SwapGreed), + }, + ], + }) + ); + + assert_eq!( + parser("-isU:").parse_flags(), + Ok(ast::Flags { + span: span(0..4), + items: vec![ + ast::FlagsItem { + span: span(0..1), + kind: ast::FlagsItemKind::Negation, + }, + ast::FlagsItem { + span: span(1..2), + kind: ast::FlagsItemKind::Flag( + ast::Flag::CaseInsensitive + ), + }, + ast::FlagsItem { + span: span(2..3), + kind: ast::FlagsItemKind::Flag( + ast::Flag::DotMatchesNewLine + ), + }, + ast::FlagsItem { + span: span(3..4), + kind: ast::FlagsItemKind::Flag(ast::Flag::SwapGreed), + }, + ], + }) + ); + assert_eq!( + parser("i-sU:").parse_flags(), + Ok(ast::Flags { + span: span(0..4), + items: vec![ + ast::FlagsItem { + span: span(0..1), + kind: ast::FlagsItemKind::Flag( + ast::Flag::CaseInsensitive + ), + }, + ast::FlagsItem { + span: span(1..2), + kind: ast::FlagsItemKind::Negation, + }, + ast::FlagsItem { + span: span(2..3), + kind: ast::FlagsItemKind::Flag( + ast::Flag::DotMatchesNewLine + ), + }, + ast::FlagsItem { + span: span(3..4), + kind: ast::FlagsItemKind::Flag(ast::Flag::SwapGreed), + }, + ], + }) + ); + assert_eq!( + parser("i-sR:").parse_flags(), + Ok(ast::Flags { + span: span(0..4), + items: vec![ + ast::FlagsItem { + span: span(0..1), + kind: ast::FlagsItemKind::Flag( + ast::Flag::CaseInsensitive + ), + }, + ast::FlagsItem { + span: span(1..2), + kind: ast::FlagsItemKind::Negation, + }, + ast::FlagsItem { + span: span(2..3), + kind: ast::FlagsItemKind::Flag( + ast::Flag::DotMatchesNewLine + ), + }, + ast::FlagsItem { + span: span(3..4), + kind: ast::FlagsItemKind::Flag(ast::Flag::CRLF), + }, + ], + }) + ); + + assert_eq!( + parser("isU").parse_flags().unwrap_err(), + TestError { + span: span(3..3), + kind: ast::ErrorKind::FlagUnexpectedEof, + } + ); + assert_eq!( + parser("isUa:").parse_flags().unwrap_err(), + TestError { + span: span(3..4), + kind: ast::ErrorKind::FlagUnrecognized, + } + ); + assert_eq!( + parser("isUi:").parse_flags().unwrap_err(), + TestError { + span: span(3..4), + kind: ast::ErrorKind::FlagDuplicate { original: span(0..1) }, + } + ); + assert_eq!( + parser("i-sU-i:").parse_flags().unwrap_err(), + TestError { + span: span(4..5), + kind: ast::ErrorKind::FlagRepeatedNegation { + original: span(1..2), + }, + } + ); + assert_eq!( + parser("-)").parse_flags().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::FlagDanglingNegation, + } + ); + assert_eq!( + parser("i-)").parse_flags().unwrap_err(), + TestError { + span: span(1..2), + kind: ast::ErrorKind::FlagDanglingNegation, + } + ); + assert_eq!( + parser("iU-)").parse_flags().unwrap_err(), + TestError { + span: span(2..3), + kind: ast::ErrorKind::FlagDanglingNegation, + } + ); + } + + #[test] + fn parse_flag() { + assert_eq!(parser("i").parse_flag(), Ok(ast::Flag::CaseInsensitive)); + assert_eq!(parser("m").parse_flag(), Ok(ast::Flag::MultiLine)); + assert_eq!(parser("s").parse_flag(), Ok(ast::Flag::DotMatchesNewLine)); + assert_eq!(parser("U").parse_flag(), Ok(ast::Flag::SwapGreed)); + assert_eq!(parser("u").parse_flag(), Ok(ast::Flag::Unicode)); + assert_eq!(parser("R").parse_flag(), Ok(ast::Flag::CRLF)); + assert_eq!(parser("x").parse_flag(), Ok(ast::Flag::IgnoreWhitespace)); + + assert_eq!( + parser("a").parse_flag().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::FlagUnrecognized, + } + ); + assert_eq!( + parser("☃").parse_flag().unwrap_err(), + TestError { + span: span_range("☃", 0..3), + kind: ast::ErrorKind::FlagUnrecognized, + } + ); + } + + #[test] + fn parse_primitive_non_escape() { + assert_eq!( + parser(r".").parse_primitive(), + Ok(Primitive::Dot(span(0..1))) + ); + assert_eq!( + parser(r"^").parse_primitive(), + Ok(Primitive::Assertion(ast::Assertion { + span: span(0..1), + kind: ast::AssertionKind::StartLine, + })) + ); + assert_eq!( + parser(r"$").parse_primitive(), + Ok(Primitive::Assertion(ast::Assertion { + span: span(0..1), + kind: ast::AssertionKind::EndLine, + })) + ); + + assert_eq!( + parser(r"a").parse_primitive(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..1), + kind: ast::LiteralKind::Verbatim, + c: 'a', + })) + ); + assert_eq!( + parser(r"|").parse_primitive(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..1), + kind: ast::LiteralKind::Verbatim, + c: '|', + })) + ); + assert_eq!( + parser(r"☃").parse_primitive(), + Ok(Primitive::Literal(ast::Literal { + span: span_range("☃", 0..3), + kind: ast::LiteralKind::Verbatim, + c: '☃', + })) + ); + } + + #[test] + fn parse_escape() { + assert_eq!( + parser(r"\|").parse_primitive(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..2), + kind: ast::LiteralKind::Meta, + c: '|', + })) + ); + let specials = &[ + (r"\a", '\x07', ast::SpecialLiteralKind::Bell), + (r"\f", '\x0C', ast::SpecialLiteralKind::FormFeed), + (r"\t", '\t', ast::SpecialLiteralKind::Tab), + (r"\n", '\n', ast::SpecialLiteralKind::LineFeed), + (r"\r", '\r', ast::SpecialLiteralKind::CarriageReturn), + (r"\v", '\x0B', ast::SpecialLiteralKind::VerticalTab), + ]; + for &(pat, c, ref kind) in specials { + assert_eq!( + parser(pat).parse_primitive(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..2), + kind: ast::LiteralKind::Special(kind.clone()), + c, + })) + ); + } + assert_eq!( + parser(r"\A").parse_primitive(), + Ok(Primitive::Assertion(ast::Assertion { + span: span(0..2), + kind: ast::AssertionKind::StartText, + })) + ); + assert_eq!( + parser(r"\z").parse_primitive(), + Ok(Primitive::Assertion(ast::Assertion { + span: span(0..2), + kind: ast::AssertionKind::EndText, + })) + ); + assert_eq!( + parser(r"\b").parse_primitive(), + Ok(Primitive::Assertion(ast::Assertion { + span: span(0..2), + kind: ast::AssertionKind::WordBoundary, + })) + ); + assert_eq!( + parser(r"\B").parse_primitive(), + Ok(Primitive::Assertion(ast::Assertion { + span: span(0..2), + kind: ast::AssertionKind::NotWordBoundary, + })) + ); + + // We also support superfluous escapes in most cases now too. + for c in ['!', '@', '%', '"', '\'', '/', ' '] { + let pat = format!(r"\{}", c); + assert_eq!( + parser(&pat).parse_primitive(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..2), + kind: ast::LiteralKind::Superfluous, + c, + })) + ); + } + + // Some superfluous escapes, namely [0-9A-Za-z], are still banned. This + // gives flexibility for future evolution. + assert_eq!( + parser(r"\e").parse_escape().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::EscapeUnrecognized, + } + ); + assert_eq!( + parser(r"\y").parse_escape().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::EscapeUnrecognized, + } + ); + // But also, < and > are banned, so that we may evolve them into + // start/end word boundary assertions. (Not sure if we will...) + assert_eq!( + parser(r"\<").parse_escape().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::EscapeUnrecognized, + } + ); + assert_eq!( + parser(r"\>").parse_escape().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::EscapeUnrecognized, + } + ); + + // An unfinished escape is illegal. + assert_eq!( + parser(r"\").parse_escape().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::EscapeUnexpectedEof, + } + ); + } + + #[test] + fn parse_unsupported_backreference() { + assert_eq!( + parser(r"\0").parse_escape().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::UnsupportedBackreference, + } + ); + assert_eq!( + parser(r"\9").parse_escape().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::UnsupportedBackreference, + } + ); + } + + #[test] + fn parse_octal() { + for i in 0..511 { + let pat = format!(r"\{:o}", i); + assert_eq!( + parser_octal(&pat).parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..pat.len()), + kind: ast::LiteralKind::Octal, + c: char::from_u32(i).unwrap(), + })) + ); + } + assert_eq!( + parser_octal(r"\778").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..3), + kind: ast::LiteralKind::Octal, + c: '?', + })) + ); + assert_eq!( + parser_octal(r"\7777").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..4), + kind: ast::LiteralKind::Octal, + c: '\u{01FF}', + })) + ); + assert_eq!( + parser_octal(r"\778").parse(), + Ok(Ast::Concat(ast::Concat { + span: span(0..4), + asts: vec![ + Ast::Literal(ast::Literal { + span: span(0..3), + kind: ast::LiteralKind::Octal, + c: '?', + }), + Ast::Literal(ast::Literal { + span: span(3..4), + kind: ast::LiteralKind::Verbatim, + c: '8', + }), + ], + })) + ); + assert_eq!( + parser_octal(r"\7777").parse(), + Ok(Ast::Concat(ast::Concat { + span: span(0..5), + asts: vec![ + Ast::Literal(ast::Literal { + span: span(0..4), + kind: ast::LiteralKind::Octal, + c: '\u{01FF}', + }), + Ast::Literal(ast::Literal { + span: span(4..5), + kind: ast::LiteralKind::Verbatim, + c: '7', + }), + ], + })) + ); + + assert_eq!( + parser_octal(r"\8").parse_escape().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::EscapeUnrecognized, + } + ); + } + + #[test] + fn parse_hex_two() { + for i in 0..256 { + let pat = format!(r"\x{:02x}", i); + assert_eq!( + parser(&pat).parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..pat.len()), + kind: ast::LiteralKind::HexFixed(ast::HexLiteralKind::X), + c: char::from_u32(i).unwrap(), + })) + ); + } + + assert_eq!( + parser(r"\xF").parse_escape().unwrap_err(), + TestError { + span: span(3..3), + kind: ast::ErrorKind::EscapeUnexpectedEof, + } + ); + assert_eq!( + parser(r"\xG").parse_escape().unwrap_err(), + TestError { + span: span(2..3), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + assert_eq!( + parser(r"\xFG").parse_escape().unwrap_err(), + TestError { + span: span(3..4), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + } + + #[test] + fn parse_hex_four() { + for i in 0..65536 { + let c = match char::from_u32(i) { + None => continue, + Some(c) => c, + }; + let pat = format!(r"\u{:04x}", i); + assert_eq!( + parser(&pat).parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..pat.len()), + kind: ast::LiteralKind::HexFixed( + ast::HexLiteralKind::UnicodeShort + ), + c, + })) + ); + } + + assert_eq!( + parser(r"\uF").parse_escape().unwrap_err(), + TestError { + span: span(3..3), + kind: ast::ErrorKind::EscapeUnexpectedEof, + } + ); + assert_eq!( + parser(r"\uG").parse_escape().unwrap_err(), + TestError { + span: span(2..3), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + assert_eq!( + parser(r"\uFG").parse_escape().unwrap_err(), + TestError { + span: span(3..4), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + assert_eq!( + parser(r"\uFFG").parse_escape().unwrap_err(), + TestError { + span: span(4..5), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + assert_eq!( + parser(r"\uFFFG").parse_escape().unwrap_err(), + TestError { + span: span(5..6), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + assert_eq!( + parser(r"\uD800").parse_escape().unwrap_err(), + TestError { + span: span(2..6), + kind: ast::ErrorKind::EscapeHexInvalid, + } + ); + } + + #[test] + fn parse_hex_eight() { + for i in 0..65536 { + let c = match char::from_u32(i) { + None => continue, + Some(c) => c, + }; + let pat = format!(r"\U{:08x}", i); + assert_eq!( + parser(&pat).parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..pat.len()), + kind: ast::LiteralKind::HexFixed( + ast::HexLiteralKind::UnicodeLong + ), + c, + })) + ); + } + + assert_eq!( + parser(r"\UF").parse_escape().unwrap_err(), + TestError { + span: span(3..3), + kind: ast::ErrorKind::EscapeUnexpectedEof, + } + ); + assert_eq!( + parser(r"\UG").parse_escape().unwrap_err(), + TestError { + span: span(2..3), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + assert_eq!( + parser(r"\UFG").parse_escape().unwrap_err(), + TestError { + span: span(3..4), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + assert_eq!( + parser(r"\UFFG").parse_escape().unwrap_err(), + TestError { + span: span(4..5), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + assert_eq!( + parser(r"\UFFFG").parse_escape().unwrap_err(), + TestError { + span: span(5..6), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + assert_eq!( + parser(r"\UFFFFG").parse_escape().unwrap_err(), + TestError { + span: span(6..7), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + assert_eq!( + parser(r"\UFFFFFG").parse_escape().unwrap_err(), + TestError { + span: span(7..8), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + assert_eq!( + parser(r"\UFFFFFFG").parse_escape().unwrap_err(), + TestError { + span: span(8..9), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + assert_eq!( + parser(r"\UFFFFFFFG").parse_escape().unwrap_err(), + TestError { + span: span(9..10), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + } + + #[test] + fn parse_hex_brace() { + assert_eq!( + parser(r"\u{26c4}").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..8), + kind: ast::LiteralKind::HexBrace( + ast::HexLiteralKind::UnicodeShort + ), + c: '⛄', + })) + ); + assert_eq!( + parser(r"\U{26c4}").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..8), + kind: ast::LiteralKind::HexBrace( + ast::HexLiteralKind::UnicodeLong + ), + c: '⛄', + })) + ); + assert_eq!( + parser(r"\x{26c4}").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..8), + kind: ast::LiteralKind::HexBrace(ast::HexLiteralKind::X), + c: '⛄', + })) + ); + assert_eq!( + parser(r"\x{26C4}").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..8), + kind: ast::LiteralKind::HexBrace(ast::HexLiteralKind::X), + c: '⛄', + })) + ); + assert_eq!( + parser(r"\x{10fFfF}").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..10), + kind: ast::LiteralKind::HexBrace(ast::HexLiteralKind::X), + c: '\u{10FFFF}', + })) + ); + + assert_eq!( + parser(r"\x").parse_escape().unwrap_err(), + TestError { + span: span(2..2), + kind: ast::ErrorKind::EscapeUnexpectedEof, + } + ); + assert_eq!( + parser(r"\x{").parse_escape().unwrap_err(), + TestError { + span: span(2..3), + kind: ast::ErrorKind::EscapeUnexpectedEof, + } + ); + assert_eq!( + parser(r"\x{FF").parse_escape().unwrap_err(), + TestError { + span: span(2..5), + kind: ast::ErrorKind::EscapeUnexpectedEof, + } + ); + assert_eq!( + parser(r"\x{}").parse_escape().unwrap_err(), + TestError { + span: span(2..4), + kind: ast::ErrorKind::EscapeHexEmpty, + } + ); + assert_eq!( + parser(r"\x{FGF}").parse_escape().unwrap_err(), + TestError { + span: span(4..5), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + } + ); + assert_eq!( + parser(r"\x{FFFFFF}").parse_escape().unwrap_err(), + TestError { + span: span(3..9), + kind: ast::ErrorKind::EscapeHexInvalid, + } + ); + assert_eq!( + parser(r"\x{D800}").parse_escape().unwrap_err(), + TestError { + span: span(3..7), + kind: ast::ErrorKind::EscapeHexInvalid, + } + ); + assert_eq!( + parser(r"\x{FFFFFFFFF}").parse_escape().unwrap_err(), + TestError { + span: span(3..12), + kind: ast::ErrorKind::EscapeHexInvalid, + } + ); + } + + #[test] + fn parse_decimal() { + assert_eq!(parser("123").parse_decimal(), Ok(123)); + assert_eq!(parser("0").parse_decimal(), Ok(0)); + assert_eq!(parser("01").parse_decimal(), Ok(1)); + + assert_eq!( + parser("-1").parse_decimal().unwrap_err(), + TestError { span: span(0..0), kind: ast::ErrorKind::DecimalEmpty } + ); + assert_eq!( + parser("").parse_decimal().unwrap_err(), + TestError { span: span(0..0), kind: ast::ErrorKind::DecimalEmpty } + ); + assert_eq!( + parser("9999999999").parse_decimal().unwrap_err(), + TestError { + span: span(0..10), + kind: ast::ErrorKind::DecimalInvalid, + } + ); + } + + #[test] + fn parse_set_class() { + fn union(span: Span, items: Vec) -> ast::ClassSet { + ast::ClassSet::union(ast::ClassSetUnion { span, items }) + } + + fn intersection( + span: Span, + lhs: ast::ClassSet, + rhs: ast::ClassSet, + ) -> ast::ClassSet { + ast::ClassSet::BinaryOp(ast::ClassSetBinaryOp { + span, + kind: ast::ClassSetBinaryOpKind::Intersection, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } + + fn difference( + span: Span, + lhs: ast::ClassSet, + rhs: ast::ClassSet, + ) -> ast::ClassSet { + ast::ClassSet::BinaryOp(ast::ClassSetBinaryOp { + span, + kind: ast::ClassSetBinaryOpKind::Difference, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } + + fn symdifference( + span: Span, + lhs: ast::ClassSet, + rhs: ast::ClassSet, + ) -> ast::ClassSet { + ast::ClassSet::BinaryOp(ast::ClassSetBinaryOp { + span, + kind: ast::ClassSetBinaryOpKind::SymmetricDifference, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } + + fn itemset(item: ast::ClassSetItem) -> ast::ClassSet { + ast::ClassSet::Item(item) + } + + fn item_ascii(cls: ast::ClassAscii) -> ast::ClassSetItem { + ast::ClassSetItem::Ascii(cls) + } + + fn item_unicode(cls: ast::ClassUnicode) -> ast::ClassSetItem { + ast::ClassSetItem::Unicode(cls) + } + + fn item_perl(cls: ast::ClassPerl) -> ast::ClassSetItem { + ast::ClassSetItem::Perl(cls) + } + + fn item_bracket(cls: ast::ClassBracketed) -> ast::ClassSetItem { + ast::ClassSetItem::Bracketed(Box::new(cls)) + } + + fn lit(span: Span, c: char) -> ast::ClassSetItem { + ast::ClassSetItem::Literal(ast::Literal { + span, + kind: ast::LiteralKind::Verbatim, + c, + }) + } + + fn empty(span: Span) -> ast::ClassSetItem { + ast::ClassSetItem::Empty(span) + } + + fn range(span: Span, start: char, end: char) -> ast::ClassSetItem { + let pos1 = Position { + offset: span.start.offset + start.len_utf8(), + column: span.start.column + 1, + ..span.start + }; + let pos2 = Position { + offset: span.end.offset - end.len_utf8(), + column: span.end.column - 1, + ..span.end + }; + ast::ClassSetItem::Range(ast::ClassSetRange { + span, + start: ast::Literal { + span: Span { end: pos1, ..span }, + kind: ast::LiteralKind::Verbatim, + c: start, + }, + end: ast::Literal { + span: Span { start: pos2, ..span }, + kind: ast::LiteralKind::Verbatim, + c: end, + }, + }) + } + + fn alnum(span: Span, negated: bool) -> ast::ClassAscii { + ast::ClassAscii { span, kind: ast::ClassAsciiKind::Alnum, negated } + } + + fn lower(span: Span, negated: bool) -> ast::ClassAscii { + ast::ClassAscii { span, kind: ast::ClassAsciiKind::Lower, negated } + } + + assert_eq!( + parser("[[:alnum:]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..11), + negated: false, + kind: itemset(item_ascii(alnum(span(1..10), false))), + }))) + ); + assert_eq!( + parser("[[[:alnum:]]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..13), + negated: false, + kind: itemset(item_bracket(ast::ClassBracketed { + span: span(1..12), + negated: false, + kind: itemset(item_ascii(alnum(span(2..11), false))), + })), + }))) + ); + assert_eq!( + parser("[[:alnum:]&&[:lower:]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..22), + negated: false, + kind: intersection( + span(1..21), + itemset(item_ascii(alnum(span(1..10), false))), + itemset(item_ascii(lower(span(12..21), false))), + ), + }))) + ); + assert_eq!( + parser("[[:alnum:]--[:lower:]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..22), + negated: false, + kind: difference( + span(1..21), + itemset(item_ascii(alnum(span(1..10), false))), + itemset(item_ascii(lower(span(12..21), false))), + ), + }))) + ); + assert_eq!( + parser("[[:alnum:]~~[:lower:]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..22), + negated: false, + kind: symdifference( + span(1..21), + itemset(item_ascii(alnum(span(1..10), false))), + itemset(item_ascii(lower(span(12..21), false))), + ), + }))) + ); + + assert_eq!( + parser("[a]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..3), + negated: false, + kind: itemset(lit(span(1..2), 'a')), + }))) + ); + assert_eq!( + parser(r"[a\]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..5), + negated: false, + kind: union( + span(1..4), + vec![ + lit(span(1..2), 'a'), + ast::ClassSetItem::Literal(ast::Literal { + span: span(2..4), + kind: ast::LiteralKind::Meta, + c: ']', + }), + ] + ), + }))) + ); + assert_eq!( + parser(r"[a\-z]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..6), + negated: false, + kind: union( + span(1..5), + vec![ + lit(span(1..2), 'a'), + ast::ClassSetItem::Literal(ast::Literal { + span: span(2..4), + kind: ast::LiteralKind::Meta, + c: '-', + }), + lit(span(4..5), 'z'), + ] + ), + }))) + ); + assert_eq!( + parser("[ab]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: union( + span(1..3), + vec![lit(span(1..2), 'a'), lit(span(2..3), 'b'),] + ), + }))) + ); + assert_eq!( + parser("[a-]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: union( + span(1..3), + vec![lit(span(1..2), 'a'), lit(span(2..3), '-'),] + ), + }))) + ); + assert_eq!( + parser("[-a]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: union( + span(1..3), + vec![lit(span(1..2), '-'), lit(span(2..3), 'a'),] + ), + }))) + ); + assert_eq!( + parser(r"[\pL]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..5), + negated: false, + kind: itemset(item_unicode(ast::ClassUnicode { + span: span(1..4), + negated: false, + kind: ast::ClassUnicodeKind::OneLetter('L'), + })), + }))) + ); + assert_eq!( + parser(r"[\w]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: itemset(item_perl(ast::ClassPerl { + span: span(1..3), + kind: ast::ClassPerlKind::Word, + negated: false, + })), + }))) + ); + assert_eq!( + parser(r"[a\wz]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..6), + negated: false, + kind: union( + span(1..5), + vec![ + lit(span(1..2), 'a'), + item_perl(ast::ClassPerl { + span: span(2..4), + kind: ast::ClassPerlKind::Word, + negated: false, + }), + lit(span(4..5), 'z'), + ] + ), + }))) + ); + + assert_eq!( + parser("[a-z]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..5), + negated: false, + kind: itemset(range(span(1..4), 'a', 'z')), + }))) + ); + assert_eq!( + parser("[a-cx-z]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..8), + negated: false, + kind: union( + span(1..7), + vec![ + range(span(1..4), 'a', 'c'), + range(span(4..7), 'x', 'z'), + ] + ), + }))) + ); + assert_eq!( + parser(r"[\w&&a-cx-z]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..12), + negated: false, + kind: intersection( + span(1..11), + itemset(item_perl(ast::ClassPerl { + span: span(1..3), + kind: ast::ClassPerlKind::Word, + negated: false, + })), + union( + span(5..11), + vec![ + range(span(5..8), 'a', 'c'), + range(span(8..11), 'x', 'z'), + ] + ), + ), + }))) + ); + assert_eq!( + parser(r"[a-cx-z&&\w]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..12), + negated: false, + kind: intersection( + span(1..11), + union( + span(1..7), + vec![ + range(span(1..4), 'a', 'c'), + range(span(4..7), 'x', 'z'), + ] + ), + itemset(item_perl(ast::ClassPerl { + span: span(9..11), + kind: ast::ClassPerlKind::Word, + negated: false, + })), + ), + }))) + ); + assert_eq!( + parser(r"[a--b--c]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..9), + negated: false, + kind: difference( + span(1..8), + difference( + span(1..5), + itemset(lit(span(1..2), 'a')), + itemset(lit(span(4..5), 'b')), + ), + itemset(lit(span(7..8), 'c')), + ), + }))) + ); + assert_eq!( + parser(r"[a~~b~~c]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..9), + negated: false, + kind: symdifference( + span(1..8), + symdifference( + span(1..5), + itemset(lit(span(1..2), 'a')), + itemset(lit(span(4..5), 'b')), + ), + itemset(lit(span(7..8), 'c')), + ), + }))) + ); + assert_eq!( + parser(r"[\^&&^]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..7), + negated: false, + kind: intersection( + span(1..6), + itemset(ast::ClassSetItem::Literal(ast::Literal { + span: span(1..3), + kind: ast::LiteralKind::Meta, + c: '^', + })), + itemset(lit(span(5..6), '^')), + ), + }))) + ); + assert_eq!( + parser(r"[\&&&&]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..7), + negated: false, + kind: intersection( + span(1..6), + itemset(ast::ClassSetItem::Literal(ast::Literal { + span: span(1..3), + kind: ast::LiteralKind::Meta, + c: '&', + })), + itemset(lit(span(5..6), '&')), + ), + }))) + ); + assert_eq!( + parser(r"[&&&&]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..6), + negated: false, + kind: intersection( + span(1..5), + intersection( + span(1..3), + itemset(empty(span(1..1))), + itemset(empty(span(3..3))), + ), + itemset(empty(span(5..5))), + ), + }))) + ); + + let pat = "[☃-⛄]"; + assert_eq!( + parser(pat).parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span_range(pat, 0..9), + negated: false, + kind: itemset(ast::ClassSetItem::Range(ast::ClassSetRange { + span: span_range(pat, 1..8), + start: ast::Literal { + span: span_range(pat, 1..4), + kind: ast::LiteralKind::Verbatim, + c: '☃', + }, + end: ast::Literal { + span: span_range(pat, 5..8), + kind: ast::LiteralKind::Verbatim, + c: '⛄', + }, + })), + }))) + ); + + assert_eq!( + parser(r"[]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..3), + negated: false, + kind: itemset(lit(span(1..2), ']')), + }))) + ); + assert_eq!( + parser(r"[]\[]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..5), + negated: false, + kind: union( + span(1..4), + vec![ + lit(span(1..2), ']'), + ast::ClassSetItem::Literal(ast::Literal { + span: span(2..4), + kind: ast::LiteralKind::Meta, + c: '[', + }), + ] + ), + }))) + ); + assert_eq!( + parser(r"[\[]]").parse(), + Ok(concat( + 0..5, + vec![ + Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: itemset(ast::ClassSetItem::Literal( + ast::Literal { + span: span(1..3), + kind: ast::LiteralKind::Meta, + c: '[', + } + )), + })), + Ast::Literal(ast::Literal { + span: span(4..5), + kind: ast::LiteralKind::Verbatim, + c: ']', + }), + ] + )) + ); + + assert_eq!( + parser("[").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::ClassUnclosed, + } + ); + assert_eq!( + parser("[[").parse().unwrap_err(), + TestError { + span: span(1..2), + kind: ast::ErrorKind::ClassUnclosed, + } + ); + assert_eq!( + parser("[[-]").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::ClassUnclosed, + } + ); + assert_eq!( + parser("[[[:alnum:]").parse().unwrap_err(), + TestError { + span: span(1..2), + kind: ast::ErrorKind::ClassUnclosed, + } + ); + assert_eq!( + parser(r"[\b]").parse().unwrap_err(), + TestError { + span: span(1..3), + kind: ast::ErrorKind::ClassEscapeInvalid, + } + ); + assert_eq!( + parser(r"[\w-a]").parse().unwrap_err(), + TestError { + span: span(1..3), + kind: ast::ErrorKind::ClassRangeLiteral, + } + ); + assert_eq!( + parser(r"[a-\w]").parse().unwrap_err(), + TestError { + span: span(3..5), + kind: ast::ErrorKind::ClassRangeLiteral, + } + ); + assert_eq!( + parser(r"[z-a]").parse().unwrap_err(), + TestError { + span: span(1..4), + kind: ast::ErrorKind::ClassRangeInvalid, + } + ); + + assert_eq!( + parser_ignore_whitespace("[a ").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::ClassUnclosed, + } + ); + assert_eq!( + parser_ignore_whitespace("[a- ").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::ClassUnclosed, + } + ); + } + + #[test] + fn parse_set_class_open() { + assert_eq!(parser("[a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..1), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(1..1), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { span: span(1..1), items: vec![] }; + Ok((set, union)) + }); + assert_eq!( + parser_ignore_whitespace("[ a]").parse_set_class_open(), + { + let set = ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(4..4), + items: vec![], + }), + }; + let union = + ast::ClassSetUnion { span: span(4..4), items: vec![] }; + Ok((set, union)) + } + ); + assert_eq!(parser("[^a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..2), + negated: true, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(2..2), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { span: span(2..2), items: vec![] }; + Ok((set, union)) + }); + assert_eq!( + parser_ignore_whitespace("[ ^ a]").parse_set_class_open(), + { + let set = ast::ClassBracketed { + span: span(0..4), + negated: true, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(4..4), + items: vec![], + }), + }; + let union = + ast::ClassSetUnion { span: span(4..4), items: vec![] }; + Ok((set, union)) + } + ); + assert_eq!(parser("[-a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..2), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(1..1), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(1..2), + items: vec![ast::ClassSetItem::Literal(ast::Literal { + span: span(1..2), + kind: ast::LiteralKind::Verbatim, + c: '-', + })], + }; + Ok((set, union)) + }); + assert_eq!( + parser_ignore_whitespace("[ - a]").parse_set_class_open(), + { + let set = ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(2..2), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(2..3), + items: vec![ast::ClassSetItem::Literal(ast::Literal { + span: span(2..3), + kind: ast::LiteralKind::Verbatim, + c: '-', + })], + }; + Ok((set, union)) + } + ); + assert_eq!(parser("[^-a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..3), + negated: true, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(2..2), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(2..3), + items: vec![ast::ClassSetItem::Literal(ast::Literal { + span: span(2..3), + kind: ast::LiteralKind::Verbatim, + c: '-', + })], + }; + Ok((set, union)) + }); + assert_eq!(parser("[--a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..3), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(1..1), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(1..3), + items: vec![ + ast::ClassSetItem::Literal(ast::Literal { + span: span(1..2), + kind: ast::LiteralKind::Verbatim, + c: '-', + }), + ast::ClassSetItem::Literal(ast::Literal { + span: span(2..3), + kind: ast::LiteralKind::Verbatim, + c: '-', + }), + ], + }; + Ok((set, union)) + }); + assert_eq!(parser("[]a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..2), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(1..1), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(1..2), + items: vec![ast::ClassSetItem::Literal(ast::Literal { + span: span(1..2), + kind: ast::LiteralKind::Verbatim, + c: ']', + })], + }; + Ok((set, union)) + }); + assert_eq!( + parser_ignore_whitespace("[ ] a]").parse_set_class_open(), + { + let set = ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(2..2), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(2..3), + items: vec![ast::ClassSetItem::Literal(ast::Literal { + span: span(2..3), + kind: ast::LiteralKind::Verbatim, + c: ']', + })], + }; + Ok((set, union)) + } + ); + assert_eq!(parser("[^]a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..3), + negated: true, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(2..2), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(2..3), + items: vec![ast::ClassSetItem::Literal(ast::Literal { + span: span(2..3), + kind: ast::LiteralKind::Verbatim, + c: ']', + })], + }; + Ok((set, union)) + }); + assert_eq!(parser("[-]a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..2), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(1..1), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(1..2), + items: vec![ast::ClassSetItem::Literal(ast::Literal { + span: span(1..2), + kind: ast::LiteralKind::Verbatim, + c: '-', + })], + }; + Ok((set, union)) + }); + + assert_eq!( + parser("[").parse_set_class_open().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::ClassUnclosed, + } + ); + assert_eq!( + parser_ignore_whitespace("[ ") + .parse_set_class_open() + .unwrap_err(), + TestError { + span: span(0..5), + kind: ast::ErrorKind::ClassUnclosed, + } + ); + assert_eq!( + parser("[^").parse_set_class_open().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::ClassUnclosed, + } + ); + assert_eq!( + parser("[]").parse_set_class_open().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::ClassUnclosed, + } + ); + assert_eq!( + parser("[-").parse_set_class_open().unwrap_err(), + TestError { + span: span(0..0), + kind: ast::ErrorKind::ClassUnclosed, + } + ); + assert_eq!( + parser("[--").parse_set_class_open().unwrap_err(), + TestError { + span: span(0..0), + kind: ast::ErrorKind::ClassUnclosed, + } + ); + + // See: https://github.com/rust-lang/regex/issues/792 + assert_eq!( + parser("(?x)[-#]").parse_with_comments().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::ClassUnclosed, + } + ); + } + + #[test] + fn maybe_parse_ascii_class() { + assert_eq!( + parser(r"[:alnum:]").maybe_parse_ascii_class(), + Some(ast::ClassAscii { + span: span(0..9), + kind: ast::ClassAsciiKind::Alnum, + negated: false, + }) + ); + assert_eq!( + parser(r"[:alnum:]A").maybe_parse_ascii_class(), + Some(ast::ClassAscii { + span: span(0..9), + kind: ast::ClassAsciiKind::Alnum, + negated: false, + }) + ); + assert_eq!( + parser(r"[:^alnum:]").maybe_parse_ascii_class(), + Some(ast::ClassAscii { + span: span(0..10), + kind: ast::ClassAsciiKind::Alnum, + negated: true, + }) + ); + + let p = parser(r"[:"); + assert_eq!(p.maybe_parse_ascii_class(), None); + assert_eq!(p.offset(), 0); + + let p = parser(r"[:^"); + assert_eq!(p.maybe_parse_ascii_class(), None); + assert_eq!(p.offset(), 0); + + let p = parser(r"[^:alnum:]"); + assert_eq!(p.maybe_parse_ascii_class(), None); + assert_eq!(p.offset(), 0); + + let p = parser(r"[:alnnum:]"); + assert_eq!(p.maybe_parse_ascii_class(), None); + assert_eq!(p.offset(), 0); + + let p = parser(r"[:alnum]"); + assert_eq!(p.maybe_parse_ascii_class(), None); + assert_eq!(p.offset(), 0); + + let p = parser(r"[:alnum:"); + assert_eq!(p.maybe_parse_ascii_class(), None); + assert_eq!(p.offset(), 0); + } + + #[test] + fn parse_unicode_class() { + assert_eq!( + parser(r"\pN").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..3), + negated: false, + kind: ast::ClassUnicodeKind::OneLetter('N'), + })) + ); + assert_eq!( + parser(r"\PN").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..3), + negated: true, + kind: ast::ClassUnicodeKind::OneLetter('N'), + })) + ); + assert_eq!( + parser(r"\p{N}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..5), + negated: false, + kind: ast::ClassUnicodeKind::Named(s("N")), + })) + ); + assert_eq!( + parser(r"\P{N}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..5), + negated: true, + kind: ast::ClassUnicodeKind::Named(s("N")), + })) + ); + assert_eq!( + parser(r"\p{Greek}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..9), + negated: false, + kind: ast::ClassUnicodeKind::Named(s("Greek")), + })) + ); + + assert_eq!( + parser(r"\p{scx:Katakana}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..16), + negated: false, + kind: ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::Colon, + name: s("scx"), + value: s("Katakana"), + }, + })) + ); + assert_eq!( + parser(r"\p{scx=Katakana}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..16), + negated: false, + kind: ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::Equal, + name: s("scx"), + value: s("Katakana"), + }, + })) + ); + assert_eq!( + parser(r"\p{scx!=Katakana}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..17), + negated: false, + kind: ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::NotEqual, + name: s("scx"), + value: s("Katakana"), + }, + })) + ); + + assert_eq!( + parser(r"\p{:}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..5), + negated: false, + kind: ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::Colon, + name: s(""), + value: s(""), + }, + })) + ); + assert_eq!( + parser(r"\p{=}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..5), + negated: false, + kind: ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::Equal, + name: s(""), + value: s(""), + }, + })) + ); + assert_eq!( + parser(r"\p{!=}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..6), + negated: false, + kind: ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::NotEqual, + name: s(""), + value: s(""), + }, + })) + ); + + assert_eq!( + parser(r"\p").parse_escape().unwrap_err(), + TestError { + span: span(2..2), + kind: ast::ErrorKind::EscapeUnexpectedEof, + } + ); + assert_eq!( + parser(r"\p{").parse_escape().unwrap_err(), + TestError { + span: span(3..3), + kind: ast::ErrorKind::EscapeUnexpectedEof, + } + ); + assert_eq!( + parser(r"\p{N").parse_escape().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::EscapeUnexpectedEof, + } + ); + assert_eq!( + parser(r"\p{Greek").parse_escape().unwrap_err(), + TestError { + span: span(8..8), + kind: ast::ErrorKind::EscapeUnexpectedEof, + } + ); + + assert_eq!( + parser(r"\pNz").parse(), + Ok(Ast::Concat(ast::Concat { + span: span(0..4), + asts: vec![ + Ast::Class(ast::Class::Unicode(ast::ClassUnicode { + span: span(0..3), + negated: false, + kind: ast::ClassUnicodeKind::OneLetter('N'), + })), + Ast::Literal(ast::Literal { + span: span(3..4), + kind: ast::LiteralKind::Verbatim, + c: 'z', + }), + ], + })) + ); + assert_eq!( + parser(r"\p{Greek}z").parse(), + Ok(Ast::Concat(ast::Concat { + span: span(0..10), + asts: vec![ + Ast::Class(ast::Class::Unicode(ast::ClassUnicode { + span: span(0..9), + negated: false, + kind: ast::ClassUnicodeKind::Named(s("Greek")), + })), + Ast::Literal(ast::Literal { + span: span(9..10), + kind: ast::LiteralKind::Verbatim, + c: 'z', + }), + ], + })) + ); + assert_eq!( + parser(r"\p\{").parse().unwrap_err(), + TestError { + span: span(2..3), + kind: ast::ErrorKind::UnicodeClassInvalid, + } + ); + assert_eq!( + parser(r"\P\{").parse().unwrap_err(), + TestError { + span: span(2..3), + kind: ast::ErrorKind::UnicodeClassInvalid, + } + ); + } + + #[test] + fn parse_perl_class() { + assert_eq!( + parser(r"\d").parse_escape(), + Ok(Primitive::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Digit, + negated: false, + })) + ); + assert_eq!( + parser(r"\D").parse_escape(), + Ok(Primitive::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Digit, + negated: true, + })) + ); + assert_eq!( + parser(r"\s").parse_escape(), + Ok(Primitive::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Space, + negated: false, + })) + ); + assert_eq!( + parser(r"\S").parse_escape(), + Ok(Primitive::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Space, + negated: true, + })) + ); + assert_eq!( + parser(r"\w").parse_escape(), + Ok(Primitive::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Word, + negated: false, + })) + ); + assert_eq!( + parser(r"\W").parse_escape(), + Ok(Primitive::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Word, + negated: true, + })) + ); + + assert_eq!( + parser(r"\d").parse(), + Ok(Ast::Class(ast::Class::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Digit, + negated: false, + }))) + ); + assert_eq!( + parser(r"\dz").parse(), + Ok(Ast::Concat(ast::Concat { + span: span(0..3), + asts: vec![ + Ast::Class(ast::Class::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Digit, + negated: false, + })), + Ast::Literal(ast::Literal { + span: span(2..3), + kind: ast::LiteralKind::Verbatim, + c: 'z', + }), + ], + })) + ); + } + + // This tests a bug fix where the nest limit checker wasn't decrementing + // its depth during post-traversal, which causes long regexes to trip + // the default limit too aggressively. + #[test] + fn regression_454_nest_too_big() { + let pattern = r#" + 2(?: + [45]\d{3}| + 7(?: + 1[0-267]| + 2[0-289]| + 3[0-29]| + 4[01]| + 5[1-3]| + 6[013]| + 7[0178]| + 91 + )| + 8(?: + 0[125]| + [139][1-6]| + 2[0157-9]| + 41| + 6[1-35]| + 7[1-5]| + 8[1-8]| + 90 + )| + 9(?: + 0[0-2]| + 1[0-4]| + 2[568]| + 3[3-6]| + 5[5-7]| + 6[0167]| + 7[15]| + 8[0146-9] + ) + )\d{4} + "#; + assert!(parser_nest_limit(pattern, 50).parse().is_ok()); + } + + // This tests that we treat a trailing `-` in a character class as a + // literal `-` even when whitespace mode is enabled and there is whitespace + // after the trailing `-`. + #[test] + fn regression_455_trailing_dash_ignore_whitespace() { + assert!(parser("(?x)[ / - ]").parse().is_ok()); + assert!(parser("(?x)[ a - ]").parse().is_ok()); + assert!(parser( + "(?x)[ + a + - ] + " + ) + .parse() + .is_ok()); + assert!(parser( + "(?x)[ + a # wat + - ] + " + ) + .parse() + .is_ok()); + + assert!(parser("(?x)[ / -").parse().is_err()); + assert!(parser("(?x)[ / - ").parse().is_err()); + assert!(parser( + "(?x)[ + / - + " + ) + .parse() + .is_err()); + assert!(parser( + "(?x)[ + / - # wat + " + ) + .parse() + .is_err()); + } +} diff --git a/vendor/regex-syntax-0.7.5/src/ast/print.rs b/vendor/regex-syntax-0.7.5/src/ast/print.rs new file mode 100644 index 0000000000000..86a87e14396a8 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/ast/print.rs @@ -0,0 +1,577 @@ +/*! +This module provides a regular expression printer for `Ast`. +*/ + +use core::fmt; + +use crate::ast::{ + self, + visitor::{self, Visitor}, + Ast, +}; + +/// A builder for constructing a printer. +/// +/// Note that since a printer doesn't have any configuration knobs, this type +/// remains unexported. +#[derive(Clone, Debug)] +struct PrinterBuilder { + _priv: (), +} + +impl Default for PrinterBuilder { + fn default() -> PrinterBuilder { + PrinterBuilder::new() + } +} + +impl PrinterBuilder { + fn new() -> PrinterBuilder { + PrinterBuilder { _priv: () } + } + + fn build(&self) -> Printer { + Printer { _priv: () } + } +} + +/// A printer for a regular expression abstract syntax tree. +/// +/// A printer converts an abstract syntax tree (AST) to a regular expression +/// pattern string. This particular printer uses constant stack space and heap +/// space proportional to the size of the AST. +/// +/// This printer will not necessarily preserve the original formatting of the +/// regular expression pattern string. For example, all whitespace and comments +/// are ignored. +#[derive(Debug)] +pub struct Printer { + _priv: (), +} + +impl Printer { + /// Create a new printer. + pub fn new() -> Printer { + PrinterBuilder::new().build() + } + + /// Print the given `Ast` to the given writer. The writer must implement + /// `fmt::Write`. Typical implementations of `fmt::Write` that can be used + /// here are a `fmt::Formatter` (which is available in `fmt::Display` + /// implementations) or a `&mut String`. + pub fn print(&mut self, ast: &Ast, wtr: W) -> fmt::Result { + visitor::visit(ast, Writer { wtr }) + } +} + +#[derive(Debug)] +struct Writer { + wtr: W, +} + +impl Visitor for Writer { + type Output = (); + type Err = fmt::Error; + + fn finish(self) -> fmt::Result { + Ok(()) + } + + fn visit_pre(&mut self, ast: &Ast) -> fmt::Result { + match *ast { + Ast::Group(ref x) => self.fmt_group_pre(x), + Ast::Class(ast::Class::Bracketed(ref x)) => { + self.fmt_class_bracketed_pre(x) + } + _ => Ok(()), + } + } + + fn visit_post(&mut self, ast: &Ast) -> fmt::Result { + use crate::ast::Class; + + match *ast { + Ast::Empty(_) => Ok(()), + Ast::Flags(ref x) => self.fmt_set_flags(x), + Ast::Literal(ref x) => self.fmt_literal(x), + Ast::Dot(_) => self.wtr.write_str("."), + Ast::Assertion(ref x) => self.fmt_assertion(x), + Ast::Class(Class::Perl(ref x)) => self.fmt_class_perl(x), + Ast::Class(Class::Unicode(ref x)) => self.fmt_class_unicode(x), + Ast::Class(Class::Bracketed(ref x)) => { + self.fmt_class_bracketed_post(x) + } + Ast::Repetition(ref x) => self.fmt_repetition(x), + Ast::Group(ref x) => self.fmt_group_post(x), + Ast::Alternation(_) => Ok(()), + Ast::Concat(_) => Ok(()), + } + } + + fn visit_alternation_in(&mut self) -> fmt::Result { + self.wtr.write_str("|") + } + + fn visit_class_set_item_pre( + &mut self, + ast: &ast::ClassSetItem, + ) -> Result<(), Self::Err> { + match *ast { + ast::ClassSetItem::Bracketed(ref x) => { + self.fmt_class_bracketed_pre(x) + } + _ => Ok(()), + } + } + + fn visit_class_set_item_post( + &mut self, + ast: &ast::ClassSetItem, + ) -> Result<(), Self::Err> { + use crate::ast::ClassSetItem::*; + + match *ast { + Empty(_) => Ok(()), + Literal(ref x) => self.fmt_literal(x), + Range(ref x) => { + self.fmt_literal(&x.start)?; + self.wtr.write_str("-")?; + self.fmt_literal(&x.end)?; + Ok(()) + } + Ascii(ref x) => self.fmt_class_ascii(x), + Unicode(ref x) => self.fmt_class_unicode(x), + Perl(ref x) => self.fmt_class_perl(x), + Bracketed(ref x) => self.fmt_class_bracketed_post(x), + Union(_) => Ok(()), + } + } + + fn visit_class_set_binary_op_in( + &mut self, + ast: &ast::ClassSetBinaryOp, + ) -> Result<(), Self::Err> { + self.fmt_class_set_binary_op_kind(&ast.kind) + } +} + +impl Writer { + fn fmt_group_pre(&mut self, ast: &ast::Group) -> fmt::Result { + use crate::ast::GroupKind::*; + match ast.kind { + CaptureIndex(_) => self.wtr.write_str("("), + CaptureName { ref name, starts_with_p } => { + let start = if starts_with_p { "(?P<" } else { "(?<" }; + self.wtr.write_str(start)?; + self.wtr.write_str(&name.name)?; + self.wtr.write_str(">")?; + Ok(()) + } + NonCapturing(ref flags) => { + self.wtr.write_str("(?")?; + self.fmt_flags(flags)?; + self.wtr.write_str(":")?; + Ok(()) + } + } + } + + fn fmt_group_post(&mut self, _ast: &ast::Group) -> fmt::Result { + self.wtr.write_str(")") + } + + fn fmt_repetition(&mut self, ast: &ast::Repetition) -> fmt::Result { + use crate::ast::RepetitionKind::*; + match ast.op.kind { + ZeroOrOne if ast.greedy => self.wtr.write_str("?"), + ZeroOrOne => self.wtr.write_str("??"), + ZeroOrMore if ast.greedy => self.wtr.write_str("*"), + ZeroOrMore => self.wtr.write_str("*?"), + OneOrMore if ast.greedy => self.wtr.write_str("+"), + OneOrMore => self.wtr.write_str("+?"), + Range(ref x) => { + self.fmt_repetition_range(x)?; + if !ast.greedy { + self.wtr.write_str("?")?; + } + Ok(()) + } + } + } + + fn fmt_repetition_range( + &mut self, + ast: &ast::RepetitionRange, + ) -> fmt::Result { + use crate::ast::RepetitionRange::*; + match *ast { + Exactly(x) => write!(self.wtr, "{{{}}}", x), + AtLeast(x) => write!(self.wtr, "{{{},}}", x), + Bounded(x, y) => write!(self.wtr, "{{{},{}}}", x, y), + } + } + + fn fmt_literal(&mut self, ast: &ast::Literal) -> fmt::Result { + use crate::ast::LiteralKind::*; + + match ast.kind { + Verbatim => self.wtr.write_char(ast.c), + Meta | Superfluous => write!(self.wtr, r"\{}", ast.c), + Octal => write!(self.wtr, r"\{:o}", u32::from(ast.c)), + HexFixed(ast::HexLiteralKind::X) => { + write!(self.wtr, r"\x{:02X}", u32::from(ast.c)) + } + HexFixed(ast::HexLiteralKind::UnicodeShort) => { + write!(self.wtr, r"\u{:04X}", u32::from(ast.c)) + } + HexFixed(ast::HexLiteralKind::UnicodeLong) => { + write!(self.wtr, r"\U{:08X}", u32::from(ast.c)) + } + HexBrace(ast::HexLiteralKind::X) => { + write!(self.wtr, r"\x{{{:X}}}", u32::from(ast.c)) + } + HexBrace(ast::HexLiteralKind::UnicodeShort) => { + write!(self.wtr, r"\u{{{:X}}}", u32::from(ast.c)) + } + HexBrace(ast::HexLiteralKind::UnicodeLong) => { + write!(self.wtr, r"\U{{{:X}}}", u32::from(ast.c)) + } + Special(ast::SpecialLiteralKind::Bell) => { + self.wtr.write_str(r"\a") + } + Special(ast::SpecialLiteralKind::FormFeed) => { + self.wtr.write_str(r"\f") + } + Special(ast::SpecialLiteralKind::Tab) => self.wtr.write_str(r"\t"), + Special(ast::SpecialLiteralKind::LineFeed) => { + self.wtr.write_str(r"\n") + } + Special(ast::SpecialLiteralKind::CarriageReturn) => { + self.wtr.write_str(r"\r") + } + Special(ast::SpecialLiteralKind::VerticalTab) => { + self.wtr.write_str(r"\v") + } + Special(ast::SpecialLiteralKind::Space) => { + self.wtr.write_str(r"\ ") + } + } + } + + fn fmt_assertion(&mut self, ast: &ast::Assertion) -> fmt::Result { + use crate::ast::AssertionKind::*; + match ast.kind { + StartLine => self.wtr.write_str("^"), + EndLine => self.wtr.write_str("$"), + StartText => self.wtr.write_str(r"\A"), + EndText => self.wtr.write_str(r"\z"), + WordBoundary => self.wtr.write_str(r"\b"), + NotWordBoundary => self.wtr.write_str(r"\B"), + } + } + + fn fmt_set_flags(&mut self, ast: &ast::SetFlags) -> fmt::Result { + self.wtr.write_str("(?")?; + self.fmt_flags(&ast.flags)?; + self.wtr.write_str(")")?; + Ok(()) + } + + fn fmt_flags(&mut self, ast: &ast::Flags) -> fmt::Result { + use crate::ast::{Flag, FlagsItemKind}; + + for item in &ast.items { + match item.kind { + FlagsItemKind::Negation => self.wtr.write_str("-"), + FlagsItemKind::Flag(ref flag) => match *flag { + Flag::CaseInsensitive => self.wtr.write_str("i"), + Flag::MultiLine => self.wtr.write_str("m"), + Flag::DotMatchesNewLine => self.wtr.write_str("s"), + Flag::SwapGreed => self.wtr.write_str("U"), + Flag::Unicode => self.wtr.write_str("u"), + Flag::CRLF => self.wtr.write_str("R"), + Flag::IgnoreWhitespace => self.wtr.write_str("x"), + }, + }?; + } + Ok(()) + } + + fn fmt_class_bracketed_pre( + &mut self, + ast: &ast::ClassBracketed, + ) -> fmt::Result { + if ast.negated { + self.wtr.write_str("[^") + } else { + self.wtr.write_str("[") + } + } + + fn fmt_class_bracketed_post( + &mut self, + _ast: &ast::ClassBracketed, + ) -> fmt::Result { + self.wtr.write_str("]") + } + + fn fmt_class_set_binary_op_kind( + &mut self, + ast: &ast::ClassSetBinaryOpKind, + ) -> fmt::Result { + use crate::ast::ClassSetBinaryOpKind::*; + match *ast { + Intersection => self.wtr.write_str("&&"), + Difference => self.wtr.write_str("--"), + SymmetricDifference => self.wtr.write_str("~~"), + } + } + + fn fmt_class_perl(&mut self, ast: &ast::ClassPerl) -> fmt::Result { + use crate::ast::ClassPerlKind::*; + match ast.kind { + Digit if ast.negated => self.wtr.write_str(r"\D"), + Digit => self.wtr.write_str(r"\d"), + Space if ast.negated => self.wtr.write_str(r"\S"), + Space => self.wtr.write_str(r"\s"), + Word if ast.negated => self.wtr.write_str(r"\W"), + Word => self.wtr.write_str(r"\w"), + } + } + + fn fmt_class_ascii(&mut self, ast: &ast::ClassAscii) -> fmt::Result { + use crate::ast::ClassAsciiKind::*; + match ast.kind { + Alnum if ast.negated => self.wtr.write_str("[:^alnum:]"), + Alnum => self.wtr.write_str("[:alnum:]"), + Alpha if ast.negated => self.wtr.write_str("[:^alpha:]"), + Alpha => self.wtr.write_str("[:alpha:]"), + Ascii if ast.negated => self.wtr.write_str("[:^ascii:]"), + Ascii => self.wtr.write_str("[:ascii:]"), + Blank if ast.negated => self.wtr.write_str("[:^blank:]"), + Blank => self.wtr.write_str("[:blank:]"), + Cntrl if ast.negated => self.wtr.write_str("[:^cntrl:]"), + Cntrl => self.wtr.write_str("[:cntrl:]"), + Digit if ast.negated => self.wtr.write_str("[:^digit:]"), + Digit => self.wtr.write_str("[:digit:]"), + Graph if ast.negated => self.wtr.write_str("[:^graph:]"), + Graph => self.wtr.write_str("[:graph:]"), + Lower if ast.negated => self.wtr.write_str("[:^lower:]"), + Lower => self.wtr.write_str("[:lower:]"), + Print if ast.negated => self.wtr.write_str("[:^print:]"), + Print => self.wtr.write_str("[:print:]"), + Punct if ast.negated => self.wtr.write_str("[:^punct:]"), + Punct => self.wtr.write_str("[:punct:]"), + Space if ast.negated => self.wtr.write_str("[:^space:]"), + Space => self.wtr.write_str("[:space:]"), + Upper if ast.negated => self.wtr.write_str("[:^upper:]"), + Upper => self.wtr.write_str("[:upper:]"), + Word if ast.negated => self.wtr.write_str("[:^word:]"), + Word => self.wtr.write_str("[:word:]"), + Xdigit if ast.negated => self.wtr.write_str("[:^xdigit:]"), + Xdigit => self.wtr.write_str("[:xdigit:]"), + } + } + + fn fmt_class_unicode(&mut self, ast: &ast::ClassUnicode) -> fmt::Result { + use crate::ast::ClassUnicodeKind::*; + use crate::ast::ClassUnicodeOpKind::*; + + if ast.negated { + self.wtr.write_str(r"\P")?; + } else { + self.wtr.write_str(r"\p")?; + } + match ast.kind { + OneLetter(c) => self.wtr.write_char(c), + Named(ref x) => write!(self.wtr, "{{{}}}", x), + NamedValue { op: Equal, ref name, ref value } => { + write!(self.wtr, "{{{}={}}}", name, value) + } + NamedValue { op: Colon, ref name, ref value } => { + write!(self.wtr, "{{{}:{}}}", name, value) + } + NamedValue { op: NotEqual, ref name, ref value } => { + write!(self.wtr, "{{{}!={}}}", name, value) + } + } + } +} + +#[cfg(test)] +mod tests { + use alloc::string::String; + + use crate::ast::parse::ParserBuilder; + + use super::*; + + fn roundtrip(given: &str) { + roundtrip_with(|b| b, given); + } + + fn roundtrip_with(mut f: F, given: &str) + where + F: FnMut(&mut ParserBuilder) -> &mut ParserBuilder, + { + let mut builder = ParserBuilder::new(); + f(&mut builder); + let ast = builder.build().parse(given).unwrap(); + + let mut printer = Printer::new(); + let mut dst = String::new(); + printer.print(&ast, &mut dst).unwrap(); + assert_eq!(given, dst); + } + + #[test] + fn print_literal() { + roundtrip("a"); + roundtrip(r"\["); + roundtrip_with(|b| b.octal(true), r"\141"); + roundtrip(r"\x61"); + roundtrip(r"\x7F"); + roundtrip(r"\u0061"); + roundtrip(r"\U00000061"); + roundtrip(r"\x{61}"); + roundtrip(r"\x{7F}"); + roundtrip(r"\u{61}"); + roundtrip(r"\U{61}"); + + roundtrip(r"\a"); + roundtrip(r"\f"); + roundtrip(r"\t"); + roundtrip(r"\n"); + roundtrip(r"\r"); + roundtrip(r"\v"); + roundtrip(r"(?x)\ "); + } + + #[test] + fn print_dot() { + roundtrip("."); + } + + #[test] + fn print_concat() { + roundtrip("ab"); + roundtrip("abcde"); + roundtrip("a(bcd)ef"); + } + + #[test] + fn print_alternation() { + roundtrip("a|b"); + roundtrip("a|b|c|d|e"); + roundtrip("|a|b|c|d|e"); + roundtrip("|a|b|c|d|e|"); + roundtrip("a(b|c|d)|e|f"); + } + + #[test] + fn print_assertion() { + roundtrip(r"^"); + roundtrip(r"$"); + roundtrip(r"\A"); + roundtrip(r"\z"); + roundtrip(r"\b"); + roundtrip(r"\B"); + } + + #[test] + fn print_repetition() { + roundtrip("a?"); + roundtrip("a??"); + roundtrip("a*"); + roundtrip("a*?"); + roundtrip("a+"); + roundtrip("a+?"); + roundtrip("a{5}"); + roundtrip("a{5}?"); + roundtrip("a{5,}"); + roundtrip("a{5,}?"); + roundtrip("a{5,10}"); + roundtrip("a{5,10}?"); + } + + #[test] + fn print_flags() { + roundtrip("(?i)"); + roundtrip("(?-i)"); + roundtrip("(?s-i)"); + roundtrip("(?-si)"); + roundtrip("(?siUmux)"); + } + + #[test] + fn print_group() { + roundtrip("(?i:a)"); + roundtrip("(?Pa)"); + roundtrip("(?a)"); + roundtrip("(a)"); + } + + #[test] + fn print_class() { + roundtrip(r"[abc]"); + roundtrip(r"[a-z]"); + roundtrip(r"[^a-z]"); + roundtrip(r"[a-z0-9]"); + roundtrip(r"[-a-z0-9]"); + roundtrip(r"[-a-z0-9]"); + roundtrip(r"[a-z0-9---]"); + roundtrip(r"[a-z&&m-n]"); + roundtrip(r"[[a-z&&m-n]]"); + roundtrip(r"[a-z--m-n]"); + roundtrip(r"[a-z~~m-n]"); + roundtrip(r"[a-z[0-9]]"); + roundtrip(r"[a-z[^0-9]]"); + + roundtrip(r"\d"); + roundtrip(r"\D"); + roundtrip(r"\s"); + roundtrip(r"\S"); + roundtrip(r"\w"); + roundtrip(r"\W"); + + roundtrip(r"[[:alnum:]]"); + roundtrip(r"[[:^alnum:]]"); + roundtrip(r"[[:alpha:]]"); + roundtrip(r"[[:^alpha:]]"); + roundtrip(r"[[:ascii:]]"); + roundtrip(r"[[:^ascii:]]"); + roundtrip(r"[[:blank:]]"); + roundtrip(r"[[:^blank:]]"); + roundtrip(r"[[:cntrl:]]"); + roundtrip(r"[[:^cntrl:]]"); + roundtrip(r"[[:digit:]]"); + roundtrip(r"[[:^digit:]]"); + roundtrip(r"[[:graph:]]"); + roundtrip(r"[[:^graph:]]"); + roundtrip(r"[[:lower:]]"); + roundtrip(r"[[:^lower:]]"); + roundtrip(r"[[:print:]]"); + roundtrip(r"[[:^print:]]"); + roundtrip(r"[[:punct:]]"); + roundtrip(r"[[:^punct:]]"); + roundtrip(r"[[:space:]]"); + roundtrip(r"[[:^space:]]"); + roundtrip(r"[[:upper:]]"); + roundtrip(r"[[:^upper:]]"); + roundtrip(r"[[:word:]]"); + roundtrip(r"[[:^word:]]"); + roundtrip(r"[[:xdigit:]]"); + roundtrip(r"[[:^xdigit:]]"); + + roundtrip(r"\pL"); + roundtrip(r"\PL"); + roundtrip(r"\p{L}"); + roundtrip(r"\P{L}"); + roundtrip(r"\p{X=Y}"); + roundtrip(r"\P{X=Y}"); + roundtrip(r"\p{X:Y}"); + roundtrip(r"\P{X:Y}"); + roundtrip(r"\p{X!=Y}"); + roundtrip(r"\P{X!=Y}"); + } +} diff --git a/vendor/regex-syntax-0.7.5/src/ast/visitor.rs b/vendor/regex-syntax-0.7.5/src/ast/visitor.rs new file mode 100644 index 0000000000000..03d12a14dbcd3 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/ast/visitor.rs @@ -0,0 +1,522 @@ +use alloc::{vec, vec::Vec}; + +use crate::ast::{self, Ast}; + +/// A trait for visiting an abstract syntax tree (AST) in depth first order. +/// +/// The principle aim of this trait is to enable callers to perform case +/// analysis on an abstract syntax tree without necessarily using recursion. +/// In particular, this permits callers to do case analysis with constant stack +/// usage, which can be important since the size of an abstract syntax tree +/// may be proportional to end user input. +/// +/// Typical usage of this trait involves providing an implementation and then +/// running it using the [`visit`] function. +/// +/// Note that the abstract syntax tree for a regular expression is quite +/// complex. Unless you specifically need it, you might be able to use the much +/// simpler [high-level intermediate representation](crate::hir::Hir) and its +/// [corresponding `Visitor` trait](crate::hir::Visitor) instead. +pub trait Visitor { + /// The result of visiting an AST. + type Output; + /// An error that visiting an AST might return. + type Err; + + /// All implementors of `Visitor` must provide a `finish` method, which + /// yields the result of visiting the AST or an error. + fn finish(self) -> Result; + + /// This method is called before beginning traversal of the AST. + fn start(&mut self) {} + + /// This method is called on an `Ast` before descending into child `Ast` + /// nodes. + fn visit_pre(&mut self, _ast: &Ast) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called on an `Ast` after descending all of its child + /// `Ast` nodes. + fn visit_post(&mut self, _ast: &Ast) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called between child nodes of an + /// [`Alternation`](ast::Alternation). + fn visit_alternation_in(&mut self) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called between child nodes of a concatenation. + fn visit_concat_in(&mut self) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called on every [`ClassSetItem`](ast::ClassSetItem) + /// before descending into child nodes. + fn visit_class_set_item_pre( + &mut self, + _ast: &ast::ClassSetItem, + ) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called on every [`ClassSetItem`](ast::ClassSetItem) + /// after descending into child nodes. + fn visit_class_set_item_post( + &mut self, + _ast: &ast::ClassSetItem, + ) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called on every + /// [`ClassSetBinaryOp`](ast::ClassSetBinaryOp) before descending into + /// child nodes. + fn visit_class_set_binary_op_pre( + &mut self, + _ast: &ast::ClassSetBinaryOp, + ) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called on every + /// [`ClassSetBinaryOp`](ast::ClassSetBinaryOp) after descending into child + /// nodes. + fn visit_class_set_binary_op_post( + &mut self, + _ast: &ast::ClassSetBinaryOp, + ) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called between the left hand and right hand child nodes + /// of a [`ClassSetBinaryOp`](ast::ClassSetBinaryOp). + fn visit_class_set_binary_op_in( + &mut self, + _ast: &ast::ClassSetBinaryOp, + ) -> Result<(), Self::Err> { + Ok(()) + } +} + +/// Executes an implementation of `Visitor` in constant stack space. +/// +/// This function will visit every node in the given `Ast` while calling the +/// appropriate methods provided by the [`Visitor`] trait. +/// +/// The primary use case for this method is when one wants to perform case +/// analysis over an `Ast` without using a stack size proportional to the depth +/// of the `Ast`. Namely, this method will instead use constant stack size, but +/// will use heap space proportional to the size of the `Ast`. This may be +/// desirable in cases where the size of `Ast` is proportional to end user +/// input. +/// +/// If the visitor returns an error at any point, then visiting is stopped and +/// the error is returned. +pub fn visit(ast: &Ast, visitor: V) -> Result { + HeapVisitor::new().visit(ast, visitor) +} + +/// HeapVisitor visits every item in an `Ast` recursively using constant stack +/// size and a heap size proportional to the size of the `Ast`. +struct HeapVisitor<'a> { + /// A stack of `Ast` nodes. This is roughly analogous to the call stack + /// used in a typical recursive visitor. + stack: Vec<(&'a Ast, Frame<'a>)>, + /// Similar to the `Ast` stack above, but is used only for character + /// classes. In particular, character classes embed their own mini + /// recursive syntax. + stack_class: Vec<(ClassInduct<'a>, ClassFrame<'a>)>, +} + +/// Represents a single stack frame while performing structural induction over +/// an `Ast`. +enum Frame<'a> { + /// A stack frame allocated just before descending into a repetition + /// operator's child node. + Repetition(&'a ast::Repetition), + /// A stack frame allocated just before descending into a group's child + /// node. + Group(&'a ast::Group), + /// The stack frame used while visiting every child node of a concatenation + /// of expressions. + Concat { + /// The child node we are currently visiting. + head: &'a Ast, + /// The remaining child nodes to visit (which may be empty). + tail: &'a [Ast], + }, + /// The stack frame used while visiting every child node of an alternation + /// of expressions. + Alternation { + /// The child node we are currently visiting. + head: &'a Ast, + /// The remaining child nodes to visit (which may be empty). + tail: &'a [Ast], + }, +} + +/// Represents a single stack frame while performing structural induction over +/// a character class. +enum ClassFrame<'a> { + /// The stack frame used while visiting every child node of a union of + /// character class items. + Union { + /// The child node we are currently visiting. + head: &'a ast::ClassSetItem, + /// The remaining child nodes to visit (which may be empty). + tail: &'a [ast::ClassSetItem], + }, + /// The stack frame used while a binary class operation. + Binary { op: &'a ast::ClassSetBinaryOp }, + /// A stack frame allocated just before descending into a binary operator's + /// left hand child node. + BinaryLHS { + op: &'a ast::ClassSetBinaryOp, + lhs: &'a ast::ClassSet, + rhs: &'a ast::ClassSet, + }, + /// A stack frame allocated just before descending into a binary operator's + /// right hand child node. + BinaryRHS { op: &'a ast::ClassSetBinaryOp, rhs: &'a ast::ClassSet }, +} + +/// A representation of the inductive step when performing structural induction +/// over a character class. +/// +/// Note that there is no analogous explicit type for the inductive step for +/// `Ast` nodes because the inductive step is just an `Ast`. For character +/// classes, the inductive step can produce one of two possible child nodes: +/// an item or a binary operation. (An item cannot be a binary operation +/// because that would imply binary operations can be unioned in the concrete +/// syntax, which is not possible.) +enum ClassInduct<'a> { + Item(&'a ast::ClassSetItem), + BinaryOp(&'a ast::ClassSetBinaryOp), +} + +impl<'a> HeapVisitor<'a> { + fn new() -> HeapVisitor<'a> { + HeapVisitor { stack: vec![], stack_class: vec![] } + } + + fn visit( + &mut self, + mut ast: &'a Ast, + mut visitor: V, + ) -> Result { + self.stack.clear(); + self.stack_class.clear(); + + visitor.start(); + loop { + visitor.visit_pre(ast)?; + if let Some(x) = self.induct(ast, &mut visitor)? { + let child = x.child(); + self.stack.push((ast, x)); + ast = child; + continue; + } + // No induction means we have a base case, so we can post visit + // it now. + visitor.visit_post(ast)?; + + // At this point, we now try to pop our call stack until it is + // either empty or we hit another inductive case. + loop { + let (post_ast, frame) = match self.stack.pop() { + None => return visitor.finish(), + Some((post_ast, frame)) => (post_ast, frame), + }; + // If this is a concat/alternate, then we might have additional + // inductive steps to process. + if let Some(x) = self.pop(frame) { + match x { + Frame::Alternation { .. } => { + visitor.visit_alternation_in()?; + } + Frame::Concat { .. } => { + visitor.visit_concat_in()?; + } + _ => {} + } + ast = x.child(); + self.stack.push((post_ast, x)); + break; + } + // Otherwise, we've finished visiting all the child nodes for + // this AST, so we can post visit it now. + visitor.visit_post(post_ast)?; + } + } + } + + /// Build a stack frame for the given AST if one is needed (which occurs if + /// and only if there are child nodes in the AST). Otherwise, return None. + /// + /// If this visits a class, then the underlying visitor implementation may + /// return an error which will be passed on here. + fn induct( + &mut self, + ast: &'a Ast, + visitor: &mut V, + ) -> Result>, V::Err> { + Ok(match *ast { + Ast::Class(ast::Class::Bracketed(ref x)) => { + self.visit_class(x, visitor)?; + None + } + Ast::Repetition(ref x) => Some(Frame::Repetition(x)), + Ast::Group(ref x) => Some(Frame::Group(x)), + Ast::Concat(ref x) if x.asts.is_empty() => None, + Ast::Concat(ref x) => { + Some(Frame::Concat { head: &x.asts[0], tail: &x.asts[1..] }) + } + Ast::Alternation(ref x) if x.asts.is_empty() => None, + Ast::Alternation(ref x) => Some(Frame::Alternation { + head: &x.asts[0], + tail: &x.asts[1..], + }), + _ => None, + }) + } + + /// Pops the given frame. If the frame has an additional inductive step, + /// then return it, otherwise return `None`. + fn pop(&self, induct: Frame<'a>) -> Option> { + match induct { + Frame::Repetition(_) => None, + Frame::Group(_) => None, + Frame::Concat { tail, .. } => { + if tail.is_empty() { + None + } else { + Some(Frame::Concat { head: &tail[0], tail: &tail[1..] }) + } + } + Frame::Alternation { tail, .. } => { + if tail.is_empty() { + None + } else { + Some(Frame::Alternation { + head: &tail[0], + tail: &tail[1..], + }) + } + } + } + } + + fn visit_class( + &mut self, + ast: &'a ast::ClassBracketed, + visitor: &mut V, + ) -> Result<(), V::Err> { + let mut ast = ClassInduct::from_bracketed(ast); + loop { + self.visit_class_pre(&ast, visitor)?; + if let Some(x) = self.induct_class(&ast) { + let child = x.child(); + self.stack_class.push((ast, x)); + ast = child; + continue; + } + self.visit_class_post(&ast, visitor)?; + + // At this point, we now try to pop our call stack until it is + // either empty or we hit another inductive case. + loop { + let (post_ast, frame) = match self.stack_class.pop() { + None => return Ok(()), + Some((post_ast, frame)) => (post_ast, frame), + }; + // If this is a union or a binary op, then we might have + // additional inductive steps to process. + if let Some(x) = self.pop_class(frame) { + if let ClassFrame::BinaryRHS { ref op, .. } = x { + visitor.visit_class_set_binary_op_in(op)?; + } + ast = x.child(); + self.stack_class.push((post_ast, x)); + break; + } + // Otherwise, we've finished visiting all the child nodes for + // this class node, so we can post visit it now. + self.visit_class_post(&post_ast, visitor)?; + } + } + } + + /// Call the appropriate `Visitor` methods given an inductive step. + fn visit_class_pre( + &self, + ast: &ClassInduct<'a>, + visitor: &mut V, + ) -> Result<(), V::Err> { + match *ast { + ClassInduct::Item(item) => { + visitor.visit_class_set_item_pre(item)?; + } + ClassInduct::BinaryOp(op) => { + visitor.visit_class_set_binary_op_pre(op)?; + } + } + Ok(()) + } + + /// Call the appropriate `Visitor` methods given an inductive step. + fn visit_class_post( + &self, + ast: &ClassInduct<'a>, + visitor: &mut V, + ) -> Result<(), V::Err> { + match *ast { + ClassInduct::Item(item) => { + visitor.visit_class_set_item_post(item)?; + } + ClassInduct::BinaryOp(op) => { + visitor.visit_class_set_binary_op_post(op)?; + } + } + Ok(()) + } + + /// Build a stack frame for the given class node if one is needed (which + /// occurs if and only if there are child nodes). Otherwise, return None. + fn induct_class(&self, ast: &ClassInduct<'a>) -> Option> { + match *ast { + ClassInduct::Item(&ast::ClassSetItem::Bracketed(ref x)) => { + match x.kind { + ast::ClassSet::Item(ref item) => { + Some(ClassFrame::Union { head: item, tail: &[] }) + } + ast::ClassSet::BinaryOp(ref op) => { + Some(ClassFrame::Binary { op }) + } + } + } + ClassInduct::Item(&ast::ClassSetItem::Union(ref x)) => { + if x.items.is_empty() { + None + } else { + Some(ClassFrame::Union { + head: &x.items[0], + tail: &x.items[1..], + }) + } + } + ClassInduct::BinaryOp(op) => { + Some(ClassFrame::BinaryLHS { op, lhs: &op.lhs, rhs: &op.rhs }) + } + _ => None, + } + } + + /// Pops the given frame. If the frame has an additional inductive step, + /// then return it, otherwise return `None`. + fn pop_class(&self, induct: ClassFrame<'a>) -> Option> { + match induct { + ClassFrame::Union { tail, .. } => { + if tail.is_empty() { + None + } else { + Some(ClassFrame::Union { + head: &tail[0], + tail: &tail[1..], + }) + } + } + ClassFrame::Binary { .. } => None, + ClassFrame::BinaryLHS { op, rhs, .. } => { + Some(ClassFrame::BinaryRHS { op, rhs }) + } + ClassFrame::BinaryRHS { .. } => None, + } + } +} + +impl<'a> Frame<'a> { + /// Perform the next inductive step on this frame and return the next + /// child AST node to visit. + fn child(&self) -> &'a Ast { + match *self { + Frame::Repetition(rep) => &rep.ast, + Frame::Group(group) => &group.ast, + Frame::Concat { head, .. } => head, + Frame::Alternation { head, .. } => head, + } + } +} + +impl<'a> ClassFrame<'a> { + /// Perform the next inductive step on this frame and return the next + /// child class node to visit. + fn child(&self) -> ClassInduct<'a> { + match *self { + ClassFrame::Union { head, .. } => ClassInduct::Item(head), + ClassFrame::Binary { op, .. } => ClassInduct::BinaryOp(op), + ClassFrame::BinaryLHS { ref lhs, .. } => { + ClassInduct::from_set(lhs) + } + ClassFrame::BinaryRHS { ref rhs, .. } => { + ClassInduct::from_set(rhs) + } + } + } +} + +impl<'a> ClassInduct<'a> { + fn from_bracketed(ast: &'a ast::ClassBracketed) -> ClassInduct<'a> { + ClassInduct::from_set(&ast.kind) + } + + fn from_set(ast: &'a ast::ClassSet) -> ClassInduct<'a> { + match *ast { + ast::ClassSet::Item(ref item) => ClassInduct::Item(item), + ast::ClassSet::BinaryOp(ref op) => ClassInduct::BinaryOp(op), + } + } +} + +impl<'a> core::fmt::Debug for ClassFrame<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let x = match *self { + ClassFrame::Union { .. } => "Union", + ClassFrame::Binary { .. } => "Binary", + ClassFrame::BinaryLHS { .. } => "BinaryLHS", + ClassFrame::BinaryRHS { .. } => "BinaryRHS", + }; + write!(f, "{}", x) + } +} + +impl<'a> core::fmt::Debug for ClassInduct<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let x = match *self { + ClassInduct::Item(it) => match *it { + ast::ClassSetItem::Empty(_) => "Item(Empty)", + ast::ClassSetItem::Literal(_) => "Item(Literal)", + ast::ClassSetItem::Range(_) => "Item(Range)", + ast::ClassSetItem::Ascii(_) => "Item(Ascii)", + ast::ClassSetItem::Perl(_) => "Item(Perl)", + ast::ClassSetItem::Unicode(_) => "Item(Unicode)", + ast::ClassSetItem::Bracketed(_) => "Item(Bracketed)", + ast::ClassSetItem::Union(_) => "Item(Union)", + }, + ClassInduct::BinaryOp(it) => match it.kind { + ast::ClassSetBinaryOpKind::Intersection => { + "BinaryOp(Intersection)" + } + ast::ClassSetBinaryOpKind::Difference => { + "BinaryOp(Difference)" + } + ast::ClassSetBinaryOpKind::SymmetricDifference => { + "BinaryOp(SymmetricDifference)" + } + }, + }; + write!(f, "{}", x) + } +} diff --git a/vendor/regex-syntax-0.7.5/src/debug.rs b/vendor/regex-syntax-0.7.5/src/debug.rs new file mode 100644 index 0000000000000..a0b051b441427 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/debug.rs @@ -0,0 +1,107 @@ +/// A type that wraps a single byte with a convenient fmt::Debug impl that +/// escapes the byte. +pub(crate) struct Byte(pub(crate) u8); + +impl core::fmt::Debug for Byte { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + // Special case ASCII space. It's too hard to read otherwise, so + // put quotes around it. I sometimes wonder whether just '\x20' would + // be better... + if self.0 == b' ' { + return write!(f, "' '"); + } + // 10 bytes is enough to cover any output from ascii::escape_default. + let mut bytes = [0u8; 10]; + let mut len = 0; + for (i, mut b) in core::ascii::escape_default(self.0).enumerate() { + // capitalize \xab to \xAB + if i >= 2 && b'a' <= b && b <= b'f' { + b -= 32; + } + bytes[len] = b; + len += 1; + } + write!(f, "{}", core::str::from_utf8(&bytes[..len]).unwrap()) + } +} + +/// A type that provides a human readable debug impl for arbitrary bytes. +/// +/// This generally works best when the bytes are presumed to be mostly UTF-8, +/// but will work for anything. +/// +/// N.B. This is copied nearly verbatim from regex-automata. Sigh. +pub(crate) struct Bytes<'a>(pub(crate) &'a [u8]); + +impl<'a> core::fmt::Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "\"")?; + // This is a sad re-implementation of a similar impl found in bstr. + let mut bytes = self.0; + while let Some(result) = utf8_decode(bytes) { + let ch = match result { + Ok(ch) => ch, + Err(byte) => { + write!(f, r"\x{:02x}", byte)?; + bytes = &bytes[1..]; + continue; + } + }; + bytes = &bytes[ch.len_utf8()..]; + match ch { + '\0' => write!(f, "\\0")?, + // ASCII control characters except \0, \n, \r, \t + '\x01'..='\x08' + | '\x0b' + | '\x0c' + | '\x0e'..='\x19' + | '\x7f' => { + write!(f, "\\x{:02x}", u32::from(ch))?; + } + '\n' | '\r' | '\t' | _ => { + write!(f, "{}", ch.escape_debug())?; + } + } + } + write!(f, "\"")?; + Ok(()) + } +} + +/// Decodes the next UTF-8 encoded codepoint from the given byte slice. +/// +/// If no valid encoding of a codepoint exists at the beginning of the given +/// byte slice, then the first byte is returned instead. +/// +/// This returns `None` if and only if `bytes` is empty. +pub(crate) fn utf8_decode(bytes: &[u8]) -> Option> { + fn len(byte: u8) -> Option { + if byte <= 0x7F { + return Some(1); + } else if byte & 0b1100_0000 == 0b1000_0000 { + return None; + } else if byte <= 0b1101_1111 { + Some(2) + } else if byte <= 0b1110_1111 { + Some(3) + } else if byte <= 0b1111_0111 { + Some(4) + } else { + None + } + } + + if bytes.is_empty() { + return None; + } + let len = match len(bytes[0]) { + None => return Some(Err(bytes[0])), + Some(len) if len > bytes.len() => return Some(Err(bytes[0])), + Some(1) => return Some(Ok(char::from(bytes[0]))), + Some(len) => len, + }; + match core::str::from_utf8(&bytes[..len]) { + Ok(s) => Some(Ok(s.chars().next().unwrap())), + Err(_) => Some(Err(bytes[0])), + } +} diff --git a/vendor/regex-syntax-0.7.5/src/either.rs b/vendor/regex-syntax-0.7.5/src/either.rs new file mode 100644 index 0000000000000..7ae41e4ced746 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/either.rs @@ -0,0 +1,8 @@ +/// A simple binary sum type. +/// +/// This is occasionally useful in an ad hoc fashion. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Either { + Left(Left), + Right(Right), +} diff --git a/vendor/regex-syntax-0.7.5/src/error.rs b/vendor/regex-syntax-0.7.5/src/error.rs new file mode 100644 index 0000000000000..98869c4f79b30 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/error.rs @@ -0,0 +1,311 @@ +use alloc::{ + format, + string::{String, ToString}, + vec, + vec::Vec, +}; + +use crate::{ast, hir}; + +/// This error type encompasses any error that can be returned by this crate. +/// +/// This error type is marked as `non_exhaustive`. This means that adding a +/// new variant is not considered a breaking change. +#[non_exhaustive] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Error { + /// An error that occurred while translating concrete syntax into abstract + /// syntax (AST). + Parse(ast::Error), + /// An error that occurred while translating abstract syntax into a high + /// level intermediate representation (HIR). + Translate(hir::Error), +} + +impl From for Error { + fn from(err: ast::Error) -> Error { + Error::Parse(err) + } +} + +impl From for Error { + fn from(err: hir::Error) -> Error { + Error::Translate(err) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} + +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match *self { + Error::Parse(ref x) => x.fmt(f), + Error::Translate(ref x) => x.fmt(f), + } + } +} + +/// A helper type for formatting nice error messages. +/// +/// This type is responsible for reporting regex parse errors in a nice human +/// readable format. Most of its complexity is from interspersing notational +/// markers pointing out the position where an error occurred. +#[derive(Debug)] +pub struct Formatter<'e, E> { + /// The original regex pattern in which the error occurred. + pattern: &'e str, + /// The error kind. It must impl fmt::Display. + err: &'e E, + /// The primary span of the error. + span: &'e ast::Span, + /// An auxiliary and optional span, in case the error needs to point to + /// two locations (e.g., when reporting a duplicate capture group name). + aux_span: Option<&'e ast::Span>, +} + +impl<'e> From<&'e ast::Error> for Formatter<'e, ast::ErrorKind> { + fn from(err: &'e ast::Error) -> Self { + Formatter { + pattern: err.pattern(), + err: err.kind(), + span: err.span(), + aux_span: err.auxiliary_span(), + } + } +} + +impl<'e> From<&'e hir::Error> for Formatter<'e, hir::ErrorKind> { + fn from(err: &'e hir::Error) -> Self { + Formatter { + pattern: err.pattern(), + err: err.kind(), + span: err.span(), + aux_span: None, + } + } +} + +impl<'e, E: core::fmt::Display> core::fmt::Display for Formatter<'e, E> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let spans = Spans::from_formatter(self); + if self.pattern.contains('\n') { + let divider = repeat_char('~', 79); + + writeln!(f, "regex parse error:")?; + writeln!(f, "{}", divider)?; + let notated = spans.notate(); + write!(f, "{}", notated)?; + writeln!(f, "{}", divider)?; + // If we have error spans that cover multiple lines, then we just + // note the line numbers. + if !spans.multi_line.is_empty() { + let mut notes = vec![]; + for span in &spans.multi_line { + notes.push(format!( + "on line {} (column {}) through line {} (column {})", + span.start.line, + span.start.column, + span.end.line, + span.end.column - 1 + )); + } + writeln!(f, "{}", notes.join("\n"))?; + } + write!(f, "error: {}", self.err)?; + } else { + writeln!(f, "regex parse error:")?; + let notated = Spans::from_formatter(self).notate(); + write!(f, "{}", notated)?; + write!(f, "error: {}", self.err)?; + } + Ok(()) + } +} + +/// This type represents an arbitrary number of error spans in a way that makes +/// it convenient to notate the regex pattern. ("Notate" means "point out +/// exactly where the error occurred in the regex pattern.") +/// +/// Technically, we can only ever have two spans given our current error +/// structure. However, after toiling with a specific algorithm for handling +/// two spans, it became obvious that an algorithm to handle an arbitrary +/// number of spans was actually much simpler. +struct Spans<'p> { + /// The original regex pattern string. + pattern: &'p str, + /// The total width that should be used for line numbers. The width is + /// used for left padding the line numbers for alignment. + /// + /// A value of `0` means line numbers should not be displayed. That is, + /// the pattern is itself only one line. + line_number_width: usize, + /// All error spans that occur on a single line. This sequence always has + /// length equivalent to the number of lines in `pattern`, where the index + /// of the sequence represents a line number, starting at `0`. The spans + /// in each line are sorted in ascending order. + by_line: Vec>, + /// All error spans that occur over one or more lines. That is, the start + /// and end position of the span have different line numbers. The spans are + /// sorted in ascending order. + multi_line: Vec, +} + +impl<'p> Spans<'p> { + /// Build a sequence of spans from a formatter. + fn from_formatter<'e, E: core::fmt::Display>( + fmter: &'p Formatter<'e, E>, + ) -> Spans<'p> { + let mut line_count = fmter.pattern.lines().count(); + // If the pattern ends with a `\n` literal, then our line count is + // off by one, since a span can occur immediately after the last `\n`, + // which is consider to be an additional line. + if fmter.pattern.ends_with('\n') { + line_count += 1; + } + let line_number_width = + if line_count <= 1 { 0 } else { line_count.to_string().len() }; + let mut spans = Spans { + pattern: &fmter.pattern, + line_number_width, + by_line: vec![vec![]; line_count], + multi_line: vec![], + }; + spans.add(fmter.span.clone()); + if let Some(span) = fmter.aux_span { + spans.add(span.clone()); + } + spans + } + + /// Add the given span to this sequence, putting it in the right place. + fn add(&mut self, span: ast::Span) { + // This is grossly inefficient since we sort after each add, but right + // now, we only ever add two spans at most. + if span.is_one_line() { + let i = span.start.line - 1; // because lines are 1-indexed + self.by_line[i].push(span); + self.by_line[i].sort(); + } else { + self.multi_line.push(span); + self.multi_line.sort(); + } + } + + /// Notate the pattern string with carents (`^`) pointing at each span + /// location. This only applies to spans that occur within a single line. + fn notate(&self) -> String { + let mut notated = String::new(); + for (i, line) in self.pattern.lines().enumerate() { + if self.line_number_width > 0 { + notated.push_str(&self.left_pad_line_number(i + 1)); + notated.push_str(": "); + } else { + notated.push_str(" "); + } + notated.push_str(line); + notated.push('\n'); + if let Some(notes) = self.notate_line(i) { + notated.push_str(¬es); + notated.push('\n'); + } + } + notated + } + + /// Return notes for the line indexed at `i` (zero-based). If there are no + /// spans for the given line, then `None` is returned. Otherwise, an + /// appropriately space padded string with correctly positioned `^` is + /// returned, accounting for line numbers. + fn notate_line(&self, i: usize) -> Option { + let spans = &self.by_line[i]; + if spans.is_empty() { + return None; + } + let mut notes = String::new(); + for _ in 0..self.line_number_padding() { + notes.push(' '); + } + let mut pos = 0; + for span in spans { + for _ in pos..(span.start.column - 1) { + notes.push(' '); + pos += 1; + } + let note_len = span.end.column.saturating_sub(span.start.column); + for _ in 0..core::cmp::max(1, note_len) { + notes.push('^'); + pos += 1; + } + } + Some(notes) + } + + /// Left pad the given line number with spaces such that it is aligned with + /// other line numbers. + fn left_pad_line_number(&self, n: usize) -> String { + let n = n.to_string(); + let pad = self.line_number_width.checked_sub(n.len()).unwrap(); + let mut result = repeat_char(' ', pad); + result.push_str(&n); + result + } + + /// Return the line number padding beginning at the start of each line of + /// the pattern. + /// + /// If the pattern is only one line, then this returns a fixed padding + /// for visual indentation. + fn line_number_padding(&self) -> usize { + if self.line_number_width == 0 { + 4 + } else { + 2 + self.line_number_width + } + } +} + +fn repeat_char(c: char, count: usize) -> String { + core::iter::repeat(c).take(count).collect() +} + +#[cfg(test)] +mod tests { + use alloc::string::ToString; + + use crate::ast::parse::Parser; + + fn assert_panic_message(pattern: &str, expected_msg: &str) { + let result = Parser::new().parse(pattern); + match result { + Ok(_) => { + panic!("regex should not have parsed"); + } + Err(err) => { + assert_eq!(err.to_string(), expected_msg.trim()); + } + } + } + + // See: https://github.com/rust-lang/regex/issues/464 + #[test] + fn regression_464() { + let err = Parser::new().parse("a{\n").unwrap_err(); + // This test checks that the error formatter doesn't panic. + assert!(!err.to_string().is_empty()); + } + + // See: https://github.com/rust-lang/regex/issues/545 + #[test] + fn repetition_quantifier_expects_a_valid_decimal() { + assert_panic_message( + r"\\u{[^}]*}", + r#" +regex parse error: + \\u{[^}]*} + ^ +error: repetition quantifier expects a valid decimal +"#, + ); + } +} diff --git a/vendor/regex-syntax-0.7.5/src/hir/interval.rs b/vendor/regex-syntax-0.7.5/src/hir/interval.rs new file mode 100644 index 0000000000000..e063390a8ff59 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/hir/interval.rs @@ -0,0 +1,581 @@ +use core::{char, cmp, fmt::Debug, slice}; + +use alloc::vec::Vec; + +use crate::unicode; + +// This module contains an *internal* implementation of interval sets. +// +// The primary invariant that interval sets guards is canonical ordering. That +// is, every interval set contains an ordered sequence of intervals where +// no two intervals are overlapping or adjacent. While this invariant is +// occasionally broken within the implementation, it should be impossible for +// callers to observe it. +// +// Since case folding (as implemented below) breaks that invariant, we roll +// that into this API even though it is a little out of place in an otherwise +// generic interval set. (Hence the reason why the `unicode` module is imported +// here.) +// +// Some of the implementation complexity here is a result of me wanting to +// preserve the sequential representation without using additional memory. +// In many cases, we do use linear extra memory, but it is at most 2x and it +// is amortized. If we relaxed the memory requirements, this implementation +// could become much simpler. The extra memory is honestly probably OK, but +// character classes (especially of the Unicode variety) can become quite +// large, and it would be nice to keep regex compilation snappy even in debug +// builds. (In the past, I have been careless with this area of code and it has +// caused slow regex compilations in debug mode, so this isn't entirely +// unwarranted.) +// +// Tests on this are relegated to the public API of HIR in src/hir.rs. + +#[derive(Clone, Debug)] +pub struct IntervalSet { + /// A sorted set of non-overlapping ranges. + ranges: Vec, + /// While not required at all for correctness, we keep track of whether an + /// interval set has been case folded or not. This helps us avoid doing + /// redundant work if, for example, a set has already been cased folded. + /// And note that whether a set is folded or not is preserved through + /// all of the pairwise set operations. That is, if both interval sets + /// have been case folded, then any of difference, union, intersection or + /// symmetric difference all produce a case folded set. + /// + /// Note that when this is true, it *must* be the case that the set is case + /// folded. But when it's false, the set *may* be case folded. In other + /// words, we only set this to true when we know it to be case, but we're + /// okay with it being false if it would otherwise be costly to determine + /// whether it should be true. This means code cannot assume that a false + /// value necessarily indicates that the set is not case folded. + /// + /// Bottom line: this is a performance optimization. + folded: bool, +} + +impl Eq for IntervalSet {} + +// We implement PartialEq manually so that we don't consider the set's internal +// 'folded' property to be part of its identity. The 'folded' property is +// strictly an optimization. +impl PartialEq for IntervalSet { + fn eq(&self, other: &IntervalSet) -> bool { + self.ranges.eq(&other.ranges) + } +} + +impl IntervalSet { + /// Create a new set from a sequence of intervals. Each interval is + /// specified as a pair of bounds, where both bounds are inclusive. + /// + /// The given ranges do not need to be in any specific order, and ranges + /// may overlap. + pub fn new>(intervals: T) -> IntervalSet { + let ranges: Vec = intervals.into_iter().collect(); + // An empty set is case folded. + let folded = ranges.is_empty(); + let mut set = IntervalSet { ranges, folded }; + set.canonicalize(); + set + } + + /// Add a new interval to this set. + pub fn push(&mut self, interval: I) { + // TODO: This could be faster. e.g., Push the interval such that + // it preserves canonicalization. + self.ranges.push(interval); + self.canonicalize(); + // We don't know whether the new interval added here is considered + // case folded, so we conservatively assume that the entire set is + // no longer case folded if it was previously. + self.folded = false; + } + + /// Return an iterator over all intervals in this set. + /// + /// The iterator yields intervals in ascending order. + pub fn iter(&self) -> IntervalSetIter<'_, I> { + IntervalSetIter(self.ranges.iter()) + } + + /// Return an immutable slice of intervals in this set. + /// + /// The sequence returned is in canonical ordering. + pub fn intervals(&self) -> &[I] { + &self.ranges + } + + /// Expand this interval set such that it contains all case folded + /// characters. For example, if this class consists of the range `a-z`, + /// then applying case folding will result in the class containing both the + /// ranges `a-z` and `A-Z`. + /// + /// This returns an error if the necessary case mapping data is not + /// available. + pub fn case_fold_simple(&mut self) -> Result<(), unicode::CaseFoldError> { + if self.folded { + return Ok(()); + } + let len = self.ranges.len(); + for i in 0..len { + let range = self.ranges[i]; + if let Err(err) = range.case_fold_simple(&mut self.ranges) { + self.canonicalize(); + return Err(err); + } + } + self.canonicalize(); + self.folded = true; + Ok(()) + } + + /// Union this set with the given set, in place. + pub fn union(&mut self, other: &IntervalSet) { + if other.ranges.is_empty() || self.ranges == other.ranges { + return; + } + // This could almost certainly be done more efficiently. + self.ranges.extend(&other.ranges); + self.canonicalize(); + self.folded = self.folded && other.folded; + } + + /// Intersect this set with the given set, in place. + pub fn intersect(&mut self, other: &IntervalSet) { + if self.ranges.is_empty() { + return; + } + if other.ranges.is_empty() { + self.ranges.clear(); + // An empty set is case folded. + self.folded = true; + return; + } + + // There should be a way to do this in-place with constant memory, + // but I couldn't figure out a simple way to do it. So just append + // the intersection to the end of this range, and then drain it before + // we're done. + let drain_end = self.ranges.len(); + + let mut ita = 0..drain_end; + let mut itb = 0..other.ranges.len(); + let mut a = ita.next().unwrap(); + let mut b = itb.next().unwrap(); + loop { + if let Some(ab) = self.ranges[a].intersect(&other.ranges[b]) { + self.ranges.push(ab); + } + let (it, aorb) = + if self.ranges[a].upper() < other.ranges[b].upper() { + (&mut ita, &mut a) + } else { + (&mut itb, &mut b) + }; + match it.next() { + Some(v) => *aorb = v, + None => break, + } + } + self.ranges.drain(..drain_end); + self.folded = self.folded && other.folded; + } + + /// Subtract the given set from this set, in place. + pub fn difference(&mut self, other: &IntervalSet) { + if self.ranges.is_empty() || other.ranges.is_empty() { + return; + } + + // This algorithm is (to me) surprisingly complex. A search of the + // interwebs indicate that this is a potentially interesting problem. + // Folks seem to suggest interval or segment trees, but I'd like to + // avoid the overhead (both runtime and conceptual) of that. + // + // The following is basically my Shitty First Draft. Therefore, in + // order to grok it, you probably need to read each line carefully. + // Simplifications are most welcome! + // + // Remember, we can assume the canonical format invariant here, which + // says that all ranges are sorted, not overlapping and not adjacent in + // each class. + let drain_end = self.ranges.len(); + let (mut a, mut b) = (0, 0); + 'LOOP: while a < drain_end && b < other.ranges.len() { + // Basically, the easy cases are when neither range overlaps with + // each other. If the `b` range is less than our current `a` + // range, then we can skip it and move on. + if other.ranges[b].upper() < self.ranges[a].lower() { + b += 1; + continue; + } + // ... similarly for the `a` range. If it's less than the smallest + // `b` range, then we can add it as-is. + if self.ranges[a].upper() < other.ranges[b].lower() { + let range = self.ranges[a]; + self.ranges.push(range); + a += 1; + continue; + } + // Otherwise, we have overlapping ranges. + assert!(!self.ranges[a].is_intersection_empty(&other.ranges[b])); + + // This part is tricky and was non-obvious to me without looking + // at explicit examples (see the tests). The trickiness stems from + // two things: 1) subtracting a range from another range could + // yield two ranges and 2) after subtracting a range, it's possible + // that future ranges can have an impact. The loop below advances + // the `b` ranges until they can't possible impact the current + // range. + // + // For example, if our `a` range is `a-t` and our next three `b` + // ranges are `a-c`, `g-i`, `r-t` and `x-z`, then we need to apply + // subtraction three times before moving on to the next `a` range. + let mut range = self.ranges[a]; + while b < other.ranges.len() + && !range.is_intersection_empty(&other.ranges[b]) + { + let old_range = range; + range = match range.difference(&other.ranges[b]) { + (None, None) => { + // We lost the entire range, so move on to the next + // without adding this one. + a += 1; + continue 'LOOP; + } + (Some(range1), None) | (None, Some(range1)) => range1, + (Some(range1), Some(range2)) => { + self.ranges.push(range1); + range2 + } + }; + // It's possible that the `b` range has more to contribute + // here. In particular, if it is greater than the original + // range, then it might impact the next `a` range *and* it + // has impacted the current `a` range as much as possible, + // so we can quit. We don't bump `b` so that the next `a` + // range can apply it. + if other.ranges[b].upper() > old_range.upper() { + break; + } + // Otherwise, the next `b` range might apply to the current + // `a` range. + b += 1; + } + self.ranges.push(range); + a += 1; + } + while a < drain_end { + let range = self.ranges[a]; + self.ranges.push(range); + a += 1; + } + self.ranges.drain(..drain_end); + self.folded = self.folded && other.folded; + } + + /// Compute the symmetric difference of the two sets, in place. + /// + /// This computes the symmetric difference of two interval sets. This + /// removes all elements in this set that are also in the given set, + /// but also adds all elements from the given set that aren't in this + /// set. That is, the set will contain all elements in either set, + /// but will not contain any elements that are in both sets. + pub fn symmetric_difference(&mut self, other: &IntervalSet) { + // TODO(burntsushi): Fix this so that it amortizes allocation. + let mut intersection = self.clone(); + intersection.intersect(other); + self.union(other); + self.difference(&intersection); + } + + /// Negate this interval set. + /// + /// For all `x` where `x` is any element, if `x` was in this set, then it + /// will not be in this set after negation. + pub fn negate(&mut self) { + if self.ranges.is_empty() { + let (min, max) = (I::Bound::min_value(), I::Bound::max_value()); + self.ranges.push(I::create(min, max)); + // The set containing everything must case folded. + self.folded = true; + return; + } + + // There should be a way to do this in-place with constant memory, + // but I couldn't figure out a simple way to do it. So just append + // the negation to the end of this range, and then drain it before + // we're done. + let drain_end = self.ranges.len(); + + // We do checked arithmetic below because of the canonical ordering + // invariant. + if self.ranges[0].lower() > I::Bound::min_value() { + let upper = self.ranges[0].lower().decrement(); + self.ranges.push(I::create(I::Bound::min_value(), upper)); + } + for i in 1..drain_end { + let lower = self.ranges[i - 1].upper().increment(); + let upper = self.ranges[i].lower().decrement(); + self.ranges.push(I::create(lower, upper)); + } + if self.ranges[drain_end - 1].upper() < I::Bound::max_value() { + let lower = self.ranges[drain_end - 1].upper().increment(); + self.ranges.push(I::create(lower, I::Bound::max_value())); + } + self.ranges.drain(..drain_end); + // We don't need to update whether this set is folded or not, because + // it is conservatively preserved through negation. Namely, if a set + // is not folded, then it is possible that its negation is folded, for + // example, [^☃]. But we're fine with assuming that the set is not + // folded in that case. (`folded` permits false negatives but not false + // positives.) + // + // But what about when a set is folded, is its negation also + // necessarily folded? Yes. Because if a set is folded, then for every + // character in the set, it necessarily included its equivalence class + // of case folded characters. Negating it in turn means that all + // equivalence classes in the set are negated, and any equivalence + // class that was previously not in the set is now entirely in the set. + } + + /// Converts this set into a canonical ordering. + fn canonicalize(&mut self) { + if self.is_canonical() { + return; + } + self.ranges.sort(); + assert!(!self.ranges.is_empty()); + + // Is there a way to do this in-place with constant memory? I couldn't + // figure out a way to do it. So just append the canonicalization to + // the end of this range, and then drain it before we're done. + let drain_end = self.ranges.len(); + for oldi in 0..drain_end { + // If we've added at least one new range, then check if we can + // merge this range in the previously added range. + if self.ranges.len() > drain_end { + let (last, rest) = self.ranges.split_last_mut().unwrap(); + if let Some(union) = last.union(&rest[oldi]) { + *last = union; + continue; + } + } + let range = self.ranges[oldi]; + self.ranges.push(range); + } + self.ranges.drain(..drain_end); + } + + /// Returns true if and only if this class is in a canonical ordering. + fn is_canonical(&self) -> bool { + for pair in self.ranges.windows(2) { + if pair[0] >= pair[1] { + return false; + } + if pair[0].is_contiguous(&pair[1]) { + return false; + } + } + true + } +} + +/// An iterator over intervals. +#[derive(Debug)] +pub struct IntervalSetIter<'a, I>(slice::Iter<'a, I>); + +impl<'a, I> Iterator for IntervalSetIter<'a, I> { + type Item = &'a I; + + fn next(&mut self) -> Option<&'a I> { + self.0.next() + } +} + +pub trait Interval: + Clone + Copy + Debug + Default + Eq + PartialEq + PartialOrd + Ord +{ + type Bound: Bound; + + fn lower(&self) -> Self::Bound; + fn upper(&self) -> Self::Bound; + fn set_lower(&mut self, bound: Self::Bound); + fn set_upper(&mut self, bound: Self::Bound); + fn case_fold_simple( + &self, + intervals: &mut Vec, + ) -> Result<(), unicode::CaseFoldError>; + + /// Create a new interval. + fn create(lower: Self::Bound, upper: Self::Bound) -> Self { + let mut int = Self::default(); + if lower <= upper { + int.set_lower(lower); + int.set_upper(upper); + } else { + int.set_lower(upper); + int.set_upper(lower); + } + int + } + + /// Union the given overlapping range into this range. + /// + /// If the two ranges aren't contiguous, then this returns `None`. + fn union(&self, other: &Self) -> Option { + if !self.is_contiguous(other) { + return None; + } + let lower = cmp::min(self.lower(), other.lower()); + let upper = cmp::max(self.upper(), other.upper()); + Some(Self::create(lower, upper)) + } + + /// Intersect this range with the given range and return the result. + /// + /// If the intersection is empty, then this returns `None`. + fn intersect(&self, other: &Self) -> Option { + let lower = cmp::max(self.lower(), other.lower()); + let upper = cmp::min(self.upper(), other.upper()); + if lower <= upper { + Some(Self::create(lower, upper)) + } else { + None + } + } + + /// Subtract the given range from this range and return the resulting + /// ranges. + /// + /// If subtraction would result in an empty range, then no ranges are + /// returned. + fn difference(&self, other: &Self) -> (Option, Option) { + if self.is_subset(other) { + return (None, None); + } + if self.is_intersection_empty(other) { + return (Some(self.clone()), None); + } + let add_lower = other.lower() > self.lower(); + let add_upper = other.upper() < self.upper(); + // We know this because !self.is_subset(other) and the ranges have + // a non-empty intersection. + assert!(add_lower || add_upper); + let mut ret = (None, None); + if add_lower { + let upper = other.lower().decrement(); + ret.0 = Some(Self::create(self.lower(), upper)); + } + if add_upper { + let lower = other.upper().increment(); + let range = Self::create(lower, self.upper()); + if ret.0.is_none() { + ret.0 = Some(range); + } else { + ret.1 = Some(range); + } + } + ret + } + + /// Compute the symmetric difference the given range from this range. This + /// returns the union of the two ranges minus its intersection. + fn symmetric_difference( + &self, + other: &Self, + ) -> (Option, Option) { + let union = match self.union(other) { + None => return (Some(self.clone()), Some(other.clone())), + Some(union) => union, + }; + let intersection = match self.intersect(other) { + None => return (Some(self.clone()), Some(other.clone())), + Some(intersection) => intersection, + }; + union.difference(&intersection) + } + + /// Returns true if and only if the two ranges are contiguous. Two ranges + /// are contiguous if and only if the ranges are either overlapping or + /// adjacent. + fn is_contiguous(&self, other: &Self) -> bool { + let lower1 = self.lower().as_u32(); + let upper1 = self.upper().as_u32(); + let lower2 = other.lower().as_u32(); + let upper2 = other.upper().as_u32(); + cmp::max(lower1, lower2) <= cmp::min(upper1, upper2).saturating_add(1) + } + + /// Returns true if and only if the intersection of this range and the + /// other range is empty. + fn is_intersection_empty(&self, other: &Self) -> bool { + let (lower1, upper1) = (self.lower(), self.upper()); + let (lower2, upper2) = (other.lower(), other.upper()); + cmp::max(lower1, lower2) > cmp::min(upper1, upper2) + } + + /// Returns true if and only if this range is a subset of the other range. + fn is_subset(&self, other: &Self) -> bool { + let (lower1, upper1) = (self.lower(), self.upper()); + let (lower2, upper2) = (other.lower(), other.upper()); + (lower2 <= lower1 && lower1 <= upper2) + && (lower2 <= upper1 && upper1 <= upper2) + } +} + +pub trait Bound: + Copy + Clone + Debug + Eq + PartialEq + PartialOrd + Ord +{ + fn min_value() -> Self; + fn max_value() -> Self; + fn as_u32(self) -> u32; + fn increment(self) -> Self; + fn decrement(self) -> Self; +} + +impl Bound for u8 { + fn min_value() -> Self { + u8::MIN + } + fn max_value() -> Self { + u8::MAX + } + fn as_u32(self) -> u32 { + u32::from(self) + } + fn increment(self) -> Self { + self.checked_add(1).unwrap() + } + fn decrement(self) -> Self { + self.checked_sub(1).unwrap() + } +} + +impl Bound for char { + fn min_value() -> Self { + '\x00' + } + fn max_value() -> Self { + '\u{10FFFF}' + } + fn as_u32(self) -> u32 { + u32::from(self) + } + + fn increment(self) -> Self { + match self { + '\u{D7FF}' => '\u{E000}', + c => char::from_u32(u32::from(c).checked_add(1).unwrap()).unwrap(), + } + } + + fn decrement(self) -> Self { + match self { + '\u{E000}' => '\u{D7FF}', + c => char::from_u32(u32::from(c).checked_sub(1).unwrap()).unwrap(), + } + } +} + +// Tests for interval sets are written in src/hir.rs against the public API. diff --git a/vendor/regex-syntax-0.7.5/src/hir/literal.rs b/vendor/regex-syntax-0.7.5/src/hir/literal.rs new file mode 100644 index 0000000000000..afcd506e0c4a0 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/hir/literal.rs @@ -0,0 +1,3219 @@ +/*! +Provides literal extraction from `Hir` expressions. + +An [`Extractor`] pulls literals out of [`Hir`] expressions and returns a +[`Seq`] of [`Literal`]s. + +The purpose of literal extraction is generally to provide avenues for +optimizing regex searches. The main idea is that substring searches can be an +order of magnitude faster than a regex search. Therefore, if one can execute +a substring search to find candidate match locations and only run the regex +search at those locations, then it is possible for huge improvements in +performance to be realized. + +With that said, literal optimizations are generally a black art because even +though substring search is generally faster, if the number of candidates +produced is high, then it can create a lot of overhead by ping-ponging between +the substring search and the regex search. + +Here are some heuristics that might be used to help increase the chances of +effective literal optimizations: + +* Stick to small [`Seq`]s. If you search for too many literals, it's likely +to lead to substring search that is only a little faster than a regex search, +and thus the overhead of using literal optimizations in the first place might +make things slower overall. +* The literals in your [`Seq`] shouldn't be too short. In general, longer is +better. A sequence corresponding to single bytes that occur frequently in the +haystack, for example, is probably a bad literal optimization because it's +likely to produce many false positive candidates. Longer literals are less +likely to match, and thus probably produce fewer false positives. +* If it's possible to estimate the approximate frequency of each byte according +to some pre-computed background distribution, it is possible to compute a score +of how "good" a `Seq` is. If a `Seq` isn't good enough, you might consider +skipping the literal optimization and just use the regex engine. + +(It should be noted that there are always pathological cases that can make +any kind of literal optimization be a net slower result. This is why it +might be a good idea to be conservative, or to even provide a means for +literal optimizations to be dynamically disabled if they are determined to be +ineffective according to some measure.) + +You're encouraged to explore the methods on [`Seq`], which permit shrinking +the size of sequences in a preference-order preserving fashion. + +Finally, note that it isn't strictly necessary to use an [`Extractor`]. Namely, +an `Extractor` only uses public APIs of the [`Seq`] and [`Literal`] types, +so it is possible to implement your own extractor. For example, for n-grams +or "inner" literals (i.e., not prefix or suffix literals). The `Extractor` +is mostly responsible for the case analysis over `Hir` expressions. Much of +the "trickier" parts are how to combine literal sequences, and that is all +implemented on [`Seq`]. +*/ + +use core::{cmp, mem, num::NonZeroUsize}; + +use alloc::{vec, vec::Vec}; + +use crate::hir::{self, Hir}; + +/// Extracts prefix or suffix literal sequences from [`Hir`] expressions. +/// +/// Literal extraction is based on the following observations: +/// +/// * Many regexes start with one or a small number of literals. +/// * Substring search for literals is often much faster (sometimes by an order +/// of magnitude) than a regex search. +/// +/// Thus, in many cases, one can search for literals to find candidate starting +/// locations of a match, and then only run the full regex engine at each such +/// location instead of over the full haystack. +/// +/// The main downside of literal extraction is that it can wind up causing a +/// search to be slower overall. For example, if there are many matches or if +/// there are many candidates that don't ultimately lead to a match, then a +/// lot of overhead will be spent in shuffing back-and-forth between substring +/// search and the regex engine. This is the fundamental reason why literal +/// optimizations for regex patterns is sometimes considered a "black art." +/// +/// # Look-around assertions +/// +/// Literal extraction treats all look-around assertions as-if they match every +/// empty string. So for example, the regex `\bquux\b` will yield a sequence +/// containing a single exact literal `quux`. However, not all occurrences +/// of `quux` correspond to a match a of the regex. For example, `\bquux\b` +/// does not match `ZquuxZ` anywhere because `quux` does not fall on a word +/// boundary. +/// +/// In effect, if your regex contains look-around assertions, then a match of +/// an exact literal does not necessarily mean the regex overall matches. So +/// you may still need to run the regex engine in such cases to confirm the +/// match. +/// +/// The precise guarantee you get from a literal sequence is: if every literal +/// in the sequence is exact and the original regex contains zero look-around +/// assertions, then a preference-order multi-substring search of those +/// literals will precisely match a preference-order search of the original +/// regex. +/// +/// # Example +/// +/// This shows how to extract prefixes: +/// +/// ``` +/// use regex_syntax::{hir::literal::{Extractor, Literal, Seq}, parse}; +/// +/// let hir = parse(r"(a|b|c)(x|y|z)[A-Z]+foo")?; +/// let got = Extractor::new().extract(&hir); +/// // All literals returned are "inexact" because none of them reach the +/// // match state. +/// let expected = Seq::from_iter([ +/// Literal::inexact("ax"), +/// Literal::inexact("ay"), +/// Literal::inexact("az"), +/// Literal::inexact("bx"), +/// Literal::inexact("by"), +/// Literal::inexact("bz"), +/// Literal::inexact("cx"), +/// Literal::inexact("cy"), +/// Literal::inexact("cz"), +/// ]); +/// assert_eq!(expected, got); +/// +/// # Ok::<(), Box>(()) +/// ``` +/// +/// This shows how to extract suffixes: +/// +/// ``` +/// use regex_syntax::{ +/// hir::literal::{Extractor, ExtractKind, Literal, Seq}, +/// parse, +/// }; +/// +/// let hir = parse(r"foo|[A-Z]+bar")?; +/// let got = Extractor::new().kind(ExtractKind::Suffix).extract(&hir); +/// // Since 'foo' gets to a match state, it is considered exact. But 'bar' +/// // does not because of the '[A-Z]+', and thus is marked inexact. +/// let expected = Seq::from_iter([ +/// Literal::exact("foo"), +/// Literal::inexact("bar"), +/// ]); +/// assert_eq!(expected, got); +/// +/// # Ok::<(), Box>(()) +/// ``` +#[derive(Clone, Debug)] +pub struct Extractor { + kind: ExtractKind, + limit_class: usize, + limit_repeat: usize, + limit_literal_len: usize, + limit_total: usize, +} + +impl Extractor { + /// Create a new extractor with a default configuration. + /// + /// The extractor can be optionally configured before calling + /// [`Extractor::extract`] to get a literal sequence. + pub fn new() -> Extractor { + Extractor { + kind: ExtractKind::Prefix, + limit_class: 10, + limit_repeat: 10, + limit_literal_len: 100, + limit_total: 250, + } + } + + /// Execute the extractor and return a sequence of literals. + pub fn extract(&self, hir: &Hir) -> Seq { + use crate::hir::HirKind::*; + + match *hir.kind() { + Empty | Look(_) => Seq::singleton(self::Literal::exact(vec![])), + Literal(hir::Literal(ref bytes)) => { + let mut seq = + Seq::singleton(self::Literal::exact(bytes.to_vec())); + self.enforce_literal_len(&mut seq); + seq + } + Class(hir::Class::Unicode(ref cls)) => { + self.extract_class_unicode(cls) + } + Class(hir::Class::Bytes(ref cls)) => self.extract_class_bytes(cls), + Repetition(ref rep) => self.extract_repetition(rep), + Capture(hir::Capture { ref sub, .. }) => self.extract(sub), + Concat(ref hirs) => match self.kind { + ExtractKind::Prefix => self.extract_concat(hirs.iter()), + ExtractKind::Suffix => self.extract_concat(hirs.iter().rev()), + }, + Alternation(ref hirs) => { + // Unlike concat, we always union starting from the beginning, + // since the beginning corresponds to the highest preference, + // which doesn't change based on forwards vs reverse. + self.extract_alternation(hirs.iter()) + } + } + } + + /// Set the kind of literal sequence to extract from an [`Hir`] expression. + /// + /// The default is to extract prefixes, but suffixes can be selected + /// instead. The contract for prefixes is that every match of the + /// corresponding `Hir` must start with one of the literals in the sequence + /// returned. Moreover, the _order_ of the sequence returned corresponds to + /// the preference order. + /// + /// Suffixes satisfy a similar contract in that every match of the + /// corresponding `Hir` must end with one of the literals in the sequence + /// returned. However, there is no guarantee that the literals are in + /// preference order. + /// + /// Remember that a sequence can be infinite. For example, unless the + /// limits are configured to be impractically large, attempting to extract + /// prefixes (or suffixes) for the pattern `[A-Z]` will return an infinite + /// sequence. Generally speaking, if the sequence returned is infinite, + /// then it is presumed to be unwise to do prefix (or suffix) optimizations + /// for the pattern. + pub fn kind(&mut self, kind: ExtractKind) -> &mut Extractor { + self.kind = kind; + self + } + + /// Configure a limit on the length of the sequence that is permitted for + /// a character class. If a character class exceeds this limit, then the + /// sequence returned for it is infinite. + /// + /// This prevents classes like `[A-Z]` or `\pL` from getting turned into + /// huge and likely unproductive sequences of literals. + /// + /// # Example + /// + /// This example shows how this limit can be lowered to decrease the tolerance + /// for character classes being turned into literal sequences. + /// + /// ``` + /// use regex_syntax::{hir::literal::{Extractor, Seq}, parse}; + /// + /// let hir = parse(r"[0-9]")?; + /// + /// let got = Extractor::new().extract(&hir); + /// let expected = Seq::new([ + /// "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + /// ]); + /// assert_eq!(expected, got); + /// + /// // Now let's shrink the limit and see how that changes things. + /// let got = Extractor::new().limit_class(4).extract(&hir); + /// let expected = Seq::infinite(); + /// assert_eq!(expected, got); + /// + /// # Ok::<(), Box>(()) + /// ``` + pub fn limit_class(&mut self, limit: usize) -> &mut Extractor { + self.limit_class = limit; + self + } + + /// Configure a limit on the total number of repetitions that is permitted + /// before literal extraction is stopped. + /// + /// This is useful for limiting things like `(abcde){50}`, or more + /// insidiously, `(?:){1000000000}`. This limit prevents any one single + /// repetition from adding too much to a literal sequence. + /// + /// With this limit set, repetitions that exceed it will be stopped and any + /// literals extracted up to that point will be made inexact. + /// + /// # Example + /// + /// This shows how to decrease the limit and compares it with the default. + /// + /// ``` + /// use regex_syntax::{hir::literal::{Extractor, Literal, Seq}, parse}; + /// + /// let hir = parse(r"(abc){8}")?; + /// + /// let got = Extractor::new().extract(&hir); + /// let expected = Seq::new(["abcabcabcabcabcabcabcabc"]); + /// assert_eq!(expected, got); + /// + /// // Now let's shrink the limit and see how that changes things. + /// let got = Extractor::new().limit_repeat(4).extract(&hir); + /// let expected = Seq::from_iter([ + /// Literal::inexact("abcabcabcabc"), + /// ]); + /// assert_eq!(expected, got); + /// + /// # Ok::<(), Box>(()) + /// ``` + pub fn limit_repeat(&mut self, limit: usize) -> &mut Extractor { + self.limit_repeat = limit; + self + } + + /// Configure a limit on the maximum length of any literal in a sequence. + /// + /// This is useful for limiting things like `(abcde){5}{5}{5}{5}`. While + /// each repetition or literal in that regex is small, when all the + /// repetitions are applied, one ends up with a literal of length `5^4 = + /// 625`. + /// + /// With this limit set, literals that exceed it will be made inexact and + /// thus prevented from growing. + /// + /// # Example + /// + /// This shows how to decrease the limit and compares it with the default. + /// + /// ``` + /// use regex_syntax::{hir::literal::{Extractor, Literal, Seq}, parse}; + /// + /// let hir = parse(r"(abc){2}{2}{2}")?; + /// + /// let got = Extractor::new().extract(&hir); + /// let expected = Seq::new(["abcabcabcabcabcabcabcabc"]); + /// assert_eq!(expected, got); + /// + /// // Now let's shrink the limit and see how that changes things. + /// let got = Extractor::new().limit_literal_len(14).extract(&hir); + /// let expected = Seq::from_iter([ + /// Literal::inexact("abcabcabcabcab"), + /// ]); + /// assert_eq!(expected, got); + /// + /// # Ok::<(), Box>(()) + /// ``` + pub fn limit_literal_len(&mut self, limit: usize) -> &mut Extractor { + self.limit_literal_len = limit; + self + } + + /// Configure a limit on the total number of literals that will be + /// returned. + /// + /// This is useful as a practical measure for avoiding the creation of + /// large sequences of literals. While the extractor will automatically + /// handle local creations of large sequences (for example, `[A-Z]` yields + /// an infinite sequence by default), large sequences can be created + /// through non-local means as well. + /// + /// For example, `[ab]{3}{3}` would yield a sequence of length `512 = 2^9` + /// despite each of the repetitions being small on their own. This limit + /// thus represents a "catch all" for avoiding locally small sequences from + /// combining into large sequences. + /// + /// # Example + /// + /// This example shows how reducing the limit will change the literal + /// sequence returned. + /// + /// ``` + /// use regex_syntax::{hir::literal::{Extractor, Literal, Seq}, parse}; + /// + /// let hir = parse(r"[ab]{2}{2}")?; + /// + /// let got = Extractor::new().extract(&hir); + /// let expected = Seq::new([ + /// "aaaa", "aaab", "aaba", "aabb", + /// "abaa", "abab", "abba", "abbb", + /// "baaa", "baab", "baba", "babb", + /// "bbaa", "bbab", "bbba", "bbbb", + /// ]); + /// assert_eq!(expected, got); + /// + /// // The default limit is not too big, but big enough to extract all + /// // literals from '[ab]{2}{2}'. If we shrink the limit to less than 16, + /// // then we'll get a truncated set. Notice that it returns a sequence of + /// // length 4 even though our limit was 10. This is because the sequence + /// // is difficult to increase without blowing the limit. Notice also + /// // that every literal in the sequence is now inexact because they were + /// // stripped of some suffix. + /// let got = Extractor::new().limit_total(10).extract(&hir); + /// let expected = Seq::from_iter([ + /// Literal::inexact("aa"), + /// Literal::inexact("ab"), + /// Literal::inexact("ba"), + /// Literal::inexact("bb"), + /// ]); + /// assert_eq!(expected, got); + /// + /// # Ok::<(), Box>(()) + /// ``` + pub fn limit_total(&mut self, limit: usize) -> &mut Extractor { + self.limit_total = limit; + self + } + + /// Extract a sequence from the given concatenation. Sequences from each of + /// the child HIR expressions are combined via cross product. + /// + /// This short circuits once the cross product turns into a sequence + /// containing only inexact literals. + fn extract_concat<'a, I: Iterator>(&self, it: I) -> Seq { + let mut seq = Seq::singleton(self::Literal::exact(vec![])); + for hir in it { + // If every element in the sequence is inexact, then a cross + // product will always be a no-op. Thus, there is nothing else we + // can add to it and can quit early. Note that this also includes + // infinite sequences. + if seq.is_inexact() { + break; + } + // Note that 'cross' also dispatches based on whether we're + // extracting prefixes or suffixes. + seq = self.cross(seq, &mut self.extract(hir)); + } + seq + } + + /// Extract a sequence from the given alternation. + /// + /// This short circuits once the union turns into an infinite sequence. + fn extract_alternation<'a, I: Iterator>( + &self, + it: I, + ) -> Seq { + let mut seq = Seq::empty(); + for hir in it { + // Once our 'seq' is infinite, every subsequent union + // operation on it will itself always result in an + // infinite sequence. Thus, it can never change and we can + // short-circuit. + if !seq.is_finite() { + break; + } + seq = self.union(seq, &mut self.extract(hir)); + } + seq + } + + /// Extract a sequence of literals from the given repetition. We do our + /// best, Some examples: + /// + /// 'a*' => [inexact(a), exact("")] + /// 'a*?' => [exact(""), inexact(a)] + /// 'a+' => [inexact(a)] + /// 'a{3}' => [exact(aaa)] + /// 'a{3,5} => [inexact(aaa)] + /// + /// The key here really is making sure we get the 'inexact' vs 'exact' + /// attributes correct on each of the literals we add. For example, the + /// fact that 'a*' gives us an inexact 'a' and an exact empty string means + /// that a regex like 'ab*c' will result in [inexact(ab), exact(ac)] + /// literals being extracted, which might actually be a better prefilter + /// than just 'a'. + fn extract_repetition(&self, rep: &hir::Repetition) -> Seq { + let mut subseq = self.extract(&rep.sub); + match *rep { + hir::Repetition { min: 0, max, greedy, .. } => { + // When 'max=1', we can retain exactness, since 'a?' is + // equivalent to 'a|'. Similarly below, 'a??' is equivalent to + // '|a'. + if max != Some(1) { + subseq.make_inexact(); + } + let mut empty = Seq::singleton(Literal::exact(vec![])); + if !greedy { + mem::swap(&mut subseq, &mut empty); + } + self.union(subseq, &mut empty) + } + hir::Repetition { min, max: Some(max), .. } if min == max => { + assert!(min > 0); // handled above + let limit = + u32::try_from(self.limit_repeat).unwrap_or(u32::MAX); + let mut seq = Seq::singleton(Literal::exact(vec![])); + for _ in 0..cmp::min(min, limit) { + if seq.is_inexact() { + break; + } + seq = self.cross(seq, &mut subseq.clone()); + } + if usize::try_from(min).is_err() || min > limit { + seq.make_inexact(); + } + seq + } + hir::Repetition { min, .. } => { + assert!(min > 0); // handled above + let limit = + u32::try_from(self.limit_repeat).unwrap_or(u32::MAX); + let mut seq = Seq::singleton(Literal::exact(vec![])); + for _ in 0..cmp::min(min, limit) { + if seq.is_inexact() { + break; + } + seq = self.cross(seq, &mut subseq.clone()); + } + seq.make_inexact(); + seq + } + } + } + + /// Convert the given Unicode class into a sequence of literals if the + /// class is small enough. If the class is too big, return an infinite + /// sequence. + fn extract_class_unicode(&self, cls: &hir::ClassUnicode) -> Seq { + if self.class_over_limit_unicode(cls) { + return Seq::infinite(); + } + let mut seq = Seq::empty(); + for r in cls.iter() { + for ch in r.start()..=r.end() { + seq.push(Literal::from(ch)); + } + } + self.enforce_literal_len(&mut seq); + seq + } + + /// Convert the given byte class into a sequence of literals if the class + /// is small enough. If the class is too big, return an infinite sequence. + fn extract_class_bytes(&self, cls: &hir::ClassBytes) -> Seq { + if self.class_over_limit_bytes(cls) { + return Seq::infinite(); + } + let mut seq = Seq::empty(); + for r in cls.iter() { + for b in r.start()..=r.end() { + seq.push(Literal::from(b)); + } + } + self.enforce_literal_len(&mut seq); + seq + } + + /// Returns true if the given Unicode class exceeds the configured limits + /// on this extractor. + fn class_over_limit_unicode(&self, cls: &hir::ClassUnicode) -> bool { + let mut count = 0; + for r in cls.iter() { + if count > self.limit_class { + return true; + } + count += r.len(); + } + count > self.limit_class + } + + /// Returns true if the given byte class exceeds the configured limits on + /// this extractor. + fn class_over_limit_bytes(&self, cls: &hir::ClassBytes) -> bool { + let mut count = 0; + for r in cls.iter() { + if count > self.limit_class { + return true; + } + count += r.len(); + } + count > self.limit_class + } + + /// Compute the cross product of the two sequences if the result would be + /// within configured limits. Otherwise, make `seq2` infinite and cross the + /// infinite sequence with `seq1`. + fn cross(&self, mut seq1: Seq, seq2: &mut Seq) -> Seq { + if seq1.max_cross_len(seq2).map_or(false, |len| len > self.limit_total) + { + seq2.make_infinite(); + } + if let ExtractKind::Suffix = self.kind { + seq1.cross_reverse(seq2); + } else { + seq1.cross_forward(seq2); + } + assert!(seq1.len().map_or(true, |x| x <= self.limit_total)); + self.enforce_literal_len(&mut seq1); + seq1 + } + + /// Union the two sequences if the result would be within configured + /// limits. Otherwise, make `seq2` infinite and union the infinite sequence + /// with `seq1`. + fn union(&self, mut seq1: Seq, seq2: &mut Seq) -> Seq { + if seq1.max_union_len(seq2).map_or(false, |len| len > self.limit_total) + { + // We try to trim our literal sequences to see if we can make + // room for more literals. The idea is that we'd rather trim down + // literals already in our sequence if it means we can add a few + // more and retain a finite sequence. Otherwise, we'll union with + // an infinite sequence and that infects everything and effectively + // stops literal extraction in its tracks. + // + // We do we keep 4 bytes here? Well, it's a bit of an abstraction + // leakage. Downstream, the literals may wind up getting fed to + // the Teddy algorithm, which supports searching literals up to + // length 4. So that's why we pick that number here. Arguably this + // should be a tuneable parameter, but it seems a little tricky to + // describe. And I'm still unsure if this is the right way to go + // about culling literal sequences. + match self.kind { + ExtractKind::Prefix => { + seq1.keep_first_bytes(4); + seq2.keep_first_bytes(4); + } + ExtractKind::Suffix => { + seq1.keep_last_bytes(4); + seq2.keep_last_bytes(4); + } + } + seq1.dedup(); + seq2.dedup(); + if seq1 + .max_union_len(seq2) + .map_or(false, |len| len > self.limit_total) + { + seq2.make_infinite(); + } + } + seq1.union(seq2); + assert!(seq1.len().map_or(true, |x| x <= self.limit_total)); + seq1 + } + + /// Applies the literal length limit to the given sequence. If none of the + /// literals in the sequence exceed the limit, then this is a no-op. + fn enforce_literal_len(&self, seq: &mut Seq) { + let len = self.limit_literal_len; + match self.kind { + ExtractKind::Prefix => seq.keep_first_bytes(len), + ExtractKind::Suffix => seq.keep_last_bytes(len), + } + } +} + +impl Default for Extractor { + fn default() -> Extractor { + Extractor::new() + } +} + +/// The kind of literals to extract from an [`Hir`] expression. +/// +/// The default extraction kind is `Prefix`. +#[non_exhaustive] +#[derive(Clone, Debug)] +pub enum ExtractKind { + /// Extracts only prefix literals from a regex. + Prefix, + /// Extracts only suffix literals from a regex. + /// + /// Note that the sequence returned by suffix literals currently may + /// not correctly represent leftmost-first or "preference" order match + /// semantics. + Suffix, +} + +impl ExtractKind { + /// Returns true if this kind is the `Prefix` variant. + pub fn is_prefix(&self) -> bool { + matches!(*self, ExtractKind::Prefix) + } + + /// Returns true if this kind is the `Suffix` variant. + pub fn is_suffix(&self) -> bool { + matches!(*self, ExtractKind::Suffix) + } +} + +impl Default for ExtractKind { + fn default() -> ExtractKind { + ExtractKind::Prefix + } +} + +/// A sequence of literals. +/// +/// A `Seq` is very much like a set in that it represents a union of its +/// members. That is, it corresponds to a set of literals where at least one +/// must match in order for a particular [`Hir`] expression to match. (Whether +/// this corresponds to the entire `Hir` expression, a prefix of it or a suffix +/// of it depends on how the `Seq` was extracted from the `Hir`.) +/// +/// It is also unlike a set in that multiple identical literals may appear, +/// and that the order of the literals in the `Seq` matters. For example, if +/// the sequence is `[sam, samwise]` and leftmost-first matching is used, then +/// `samwise` can never match and the sequence is equivalent to `[sam]`. +/// +/// # States of a sequence +/// +/// A `Seq` has a few different logical states to consider: +/// +/// * The sequence can represent "any" literal. When this happens, the set does +/// not have a finite size. The purpose of this state is to inhibit callers +/// from making assumptions about what literals are required in order to match +/// a particular [`Hir`] expression. Generally speaking, when a set is in this +/// state, literal optimizations are inhibited. A good example of a regex that +/// will cause this sort of set to appear is `[A-Za-z]`. The character class +/// is just too big (and also too narrow) to be usefully expanded into 52 +/// different literals. (Note that the decision for when a seq should become +/// infinite is determined by the caller. A seq itself has no hard-coded +/// limits.) +/// * The sequence can be empty, in which case, it is an affirmative statement +/// that there are no literals that can match the corresponding `Hir`. +/// Consequently, the `Hir` never matches any input. For example, `[a&&b]`. +/// * The sequence can be non-empty, in which case, at least one of the +/// literals must match in order for the corresponding `Hir` to match. +/// +/// # Example +/// +/// This example shows how literal sequences can be simplified by stripping +/// suffixes and minimizing while maintaining preference order. +/// +/// ``` +/// use regex_syntax::hir::literal::{Literal, Seq}; +/// +/// let mut seq = Seq::new(&[ +/// "farm", +/// "appliance", +/// "faraway", +/// "apple", +/// "fare", +/// "gap", +/// "applicant", +/// "applaud", +/// ]); +/// seq.keep_first_bytes(3); +/// seq.minimize_by_preference(); +/// // Notice that 'far' comes before 'app', which matches the order in the +/// // original sequence. This guarantees that leftmost-first semantics are +/// // not altered by simplifying the set. +/// let expected = Seq::from_iter([ +/// Literal::inexact("far"), +/// Literal::inexact("app"), +/// Literal::exact("gap"), +/// ]); +/// assert_eq!(expected, seq); +/// ``` +#[derive(Clone, Eq, PartialEq)] +pub struct Seq { + /// The members of this seq. + /// + /// When `None`, the seq represents all possible literals. That is, it + /// prevents one from making assumptions about specific literals in the + /// seq, and forces one to treat it as if any literal might be in the seq. + /// + /// Note that `Some(vec![])` is valid and corresponds to the empty seq of + /// literals, i.e., a regex that can never match. For example, `[a&&b]`. + /// It is distinct from `Some(vec![""])`, which corresponds to the seq + /// containing an empty string, which matches at every position. + literals: Option>, +} + +impl Seq { + /// Returns an empty sequence. + /// + /// An empty sequence matches zero literals, and thus corresponds to a + /// regex that itself can never match. + #[inline] + pub fn empty() -> Seq { + Seq { literals: Some(vec![]) } + } + + /// Returns a sequence of literals without a finite size and may contain + /// any literal. + /// + /// A sequence without finite size does not reveal anything about the + /// characteristics of the literals in its set. There are no fixed prefixes + /// or suffixes, nor are lower or upper bounds on the length of the literals + /// in the set known. + /// + /// This is useful to represent constructs in a regex that are "too big" + /// to useful represent as a sequence of literals. For example, `[A-Za-z]`. + /// When sequences get too big, they lose their discriminating nature and + /// are more likely to produce false positives, which in turn makes them + /// less likely to speed up searches. + /// + /// More pragmatically, for many regexes, enumerating all possible literals + /// is itself not possible or might otherwise use too many resources. So + /// constraining the size of sets during extraction is a practical trade + /// off to make. + #[inline] + pub fn infinite() -> Seq { + Seq { literals: None } + } + + /// Returns a sequence containing a single literal. + #[inline] + pub fn singleton(lit: Literal) -> Seq { + Seq { literals: Some(vec![lit]) } + } + + /// Returns a sequence of exact literals from the given byte strings. + #[inline] + pub fn new(it: I) -> Seq + where + I: IntoIterator, + B: AsRef<[u8]>, + { + it.into_iter().map(|b| Literal::exact(b.as_ref())).collect() + } + + /// If this is a finite sequence, return its members as a slice of + /// literals. + /// + /// The slice returned may be empty, in which case, there are no literals + /// that can match this sequence. + #[inline] + pub fn literals(&self) -> Option<&[Literal]> { + self.literals.as_deref() + } + + /// Push a literal to the end of this sequence. + /// + /// If this sequence is not finite, then this is a no-op. + /// + /// Similarly, if the most recently added item of this sequence is + /// equivalent to the literal given, then it is not added. This reflects + /// a `Seq`'s "set like" behavior, and represents a practical trade off. + /// Namely, there is never any need to have two adjacent and equivalent + /// literals in the same sequence, _and_ it is easy to detect in some + /// cases. + #[inline] + pub fn push(&mut self, lit: Literal) { + let lits = match self.literals { + None => return, + Some(ref mut lits) => lits, + }; + if lits.last().map_or(false, |m| m == &lit) { + return; + } + lits.push(lit); + } + + /// Make all of the literals in this sequence inexact. + /// + /// This is a no-op if this sequence is not finite. + #[inline] + pub fn make_inexact(&mut self) { + let lits = match self.literals { + None => return, + Some(ref mut lits) => lits, + }; + for lit in lits.iter_mut() { + lit.make_inexact(); + } + } + + /// Converts this sequence to an infinite sequence. + /// + /// This is a no-op if the sequence is already infinite. + #[inline] + pub fn make_infinite(&mut self) { + self.literals = None; + } + + /// Modify this sequence to contain the cross product between it and the + /// sequence given. + /// + /// The cross product only considers literals in this sequence that are + /// exact. That is, inexact literals are not extended. + /// + /// The literals are always drained from `other`, even if none are used. + /// This permits callers to reuse the sequence allocation elsewhere. + /// + /// If this sequence is infinite, then this is a no-op, regardless of what + /// `other` contains (and in this case, the literals are still drained from + /// `other`). If `other` is infinite and this sequence is finite, then this + /// is a no-op, unless this sequence contains a zero-length literal. In + /// which case, the infiniteness of `other` infects this sequence, and this + /// sequence is itself made infinite. + /// + /// Like [`Seq::union`], this may attempt to deduplicate literals. See + /// [`Seq::dedup`] for how deduplication deals with exact and inexact + /// literals. + /// + /// # Example + /// + /// This example shows basic usage and how exact and inexact literals + /// interact. + /// + /// ``` + /// use regex_syntax::hir::literal::{Literal, Seq}; + /// + /// let mut seq1 = Seq::from_iter([ + /// Literal::exact("foo"), + /// Literal::inexact("bar"), + /// ]); + /// let mut seq2 = Seq::from_iter([ + /// Literal::inexact("quux"), + /// Literal::exact("baz"), + /// ]); + /// seq1.cross_forward(&mut seq2); + /// + /// // The literals are pulled out of seq2. + /// assert_eq!(Some(0), seq2.len()); + /// + /// let expected = Seq::from_iter([ + /// Literal::inexact("fooquux"), + /// Literal::exact("foobaz"), + /// Literal::inexact("bar"), + /// ]); + /// assert_eq!(expected, seq1); + /// ``` + /// + /// This example shows the behavior of when `other` is an infinite + /// sequence. + /// + /// ``` + /// use regex_syntax::hir::literal::{Literal, Seq}; + /// + /// let mut seq1 = Seq::from_iter([ + /// Literal::exact("foo"), + /// Literal::inexact("bar"), + /// ]); + /// let mut seq2 = Seq::infinite(); + /// seq1.cross_forward(&mut seq2); + /// + /// // When seq2 is infinite, cross product doesn't add anything, but + /// // ensures all members of seq1 are inexact. + /// let expected = Seq::from_iter([ + /// Literal::inexact("foo"), + /// Literal::inexact("bar"), + /// ]); + /// assert_eq!(expected, seq1); + /// ``` + /// + /// This example is like the one above, but shows what happens when this + /// sequence contains an empty string. In this case, an infinite `other` + /// sequence infects this sequence (because the empty string means that + /// there are no finite prefixes): + /// + /// ``` + /// use regex_syntax::hir::literal::{Literal, Seq}; + /// + /// let mut seq1 = Seq::from_iter([ + /// Literal::exact("foo"), + /// Literal::exact(""), // inexact provokes same behavior + /// Literal::inexact("bar"), + /// ]); + /// let mut seq2 = Seq::infinite(); + /// seq1.cross_forward(&mut seq2); + /// + /// // seq1 is now infinite! + /// assert!(!seq1.is_finite()); + /// ``` + /// + /// This example shows the behavior of this sequence is infinite. + /// + /// ``` + /// use regex_syntax::hir::literal::{Literal, Seq}; + /// + /// let mut seq1 = Seq::infinite(); + /// let mut seq2 = Seq::from_iter([ + /// Literal::exact("foo"), + /// Literal::inexact("bar"), + /// ]); + /// seq1.cross_forward(&mut seq2); + /// + /// // seq1 remains unchanged. + /// assert!(!seq1.is_finite()); + /// // Even though the literals in seq2 weren't used, it was still drained. + /// assert_eq!(Some(0), seq2.len()); + /// ``` + #[inline] + pub fn cross_forward(&mut self, other: &mut Seq) { + let (lits1, lits2) = match self.cross_preamble(other) { + None => return, + Some((lits1, lits2)) => (lits1, lits2), + }; + let newcap = lits1.len().saturating_mul(lits2.len()); + for selflit in mem::replace(lits1, Vec::with_capacity(newcap)) { + if !selflit.is_exact() { + lits1.push(selflit); + continue; + } + for otherlit in lits2.iter() { + let mut newlit = Literal::exact(Vec::with_capacity( + selflit.len() + otherlit.len(), + )); + newlit.extend(&selflit); + newlit.extend(&otherlit); + if !otherlit.is_exact() { + newlit.make_inexact(); + } + lits1.push(newlit); + } + } + lits2.drain(..); + self.dedup(); + } + + /// Modify this sequence to contain the cross product between it and + /// the sequence given, where the sequences are treated as suffixes + /// instead of prefixes. Namely, the sequence `other` is *prepended* + /// to `self` (as opposed to `other` being *appended* to `self` in + /// [`Seq::cross_forward`]). + /// + /// The cross product only considers literals in this sequence that are + /// exact. That is, inexact literals are not extended. + /// + /// The literals are always drained from `other`, even if none are used. + /// This permits callers to reuse the sequence allocation elsewhere. + /// + /// If this sequence is infinite, then this is a no-op, regardless of what + /// `other` contains (and in this case, the literals are still drained from + /// `other`). If `other` is infinite and this sequence is finite, then this + /// is a no-op, unless this sequence contains a zero-length literal. In + /// which case, the infiniteness of `other` infects this sequence, and this + /// sequence is itself made infinite. + /// + /// Like [`Seq::union`], this may attempt to deduplicate literals. See + /// [`Seq::dedup`] for how deduplication deals with exact and inexact + /// literals. + /// + /// # Example + /// + /// This example shows basic usage and how exact and inexact literals + /// interact. + /// + /// ``` + /// use regex_syntax::hir::literal::{Literal, Seq}; + /// + /// let mut seq1 = Seq::from_iter([ + /// Literal::exact("foo"), + /// Literal::inexact("bar"), + /// ]); + /// let mut seq2 = Seq::from_iter([ + /// Literal::inexact("quux"), + /// Literal::exact("baz"), + /// ]); + /// seq1.cross_reverse(&mut seq2); + /// + /// // The literals are pulled out of seq2. + /// assert_eq!(Some(0), seq2.len()); + /// + /// let expected = Seq::from_iter([ + /// Literal::inexact("quuxfoo"), + /// Literal::inexact("bar"), + /// Literal::exact("bazfoo"), + /// ]); + /// assert_eq!(expected, seq1); + /// ``` + /// + /// This example shows the behavior of when `other` is an infinite + /// sequence. + /// + /// ``` + /// use regex_syntax::hir::literal::{Literal, Seq}; + /// + /// let mut seq1 = Seq::from_iter([ + /// Literal::exact("foo"), + /// Literal::inexact("bar"), + /// ]); + /// let mut seq2 = Seq::infinite(); + /// seq1.cross_reverse(&mut seq2); + /// + /// // When seq2 is infinite, cross product doesn't add anything, but + /// // ensures all members of seq1 are inexact. + /// let expected = Seq::from_iter([ + /// Literal::inexact("foo"), + /// Literal::inexact("bar"), + /// ]); + /// assert_eq!(expected, seq1); + /// ``` + /// + /// This example is like the one above, but shows what happens when this + /// sequence contains an empty string. In this case, an infinite `other` + /// sequence infects this sequence (because the empty string means that + /// there are no finite suffixes): + /// + /// ``` + /// use regex_syntax::hir::literal::{Literal, Seq}; + /// + /// let mut seq1 = Seq::from_iter([ + /// Literal::exact("foo"), + /// Literal::exact(""), // inexact provokes same behavior + /// Literal::inexact("bar"), + /// ]); + /// let mut seq2 = Seq::infinite(); + /// seq1.cross_reverse(&mut seq2); + /// + /// // seq1 is now infinite! + /// assert!(!seq1.is_finite()); + /// ``` + /// + /// This example shows the behavior when this sequence is infinite. + /// + /// ``` + /// use regex_syntax::hir::literal::{Literal, Seq}; + /// + /// let mut seq1 = Seq::infinite(); + /// let mut seq2 = Seq::from_iter([ + /// Literal::exact("foo"), + /// Literal::inexact("bar"), + /// ]); + /// seq1.cross_reverse(&mut seq2); + /// + /// // seq1 remains unchanged. + /// assert!(!seq1.is_finite()); + /// // Even though the literals in seq2 weren't used, it was still drained. + /// assert_eq!(Some(0), seq2.len()); + /// ``` + #[inline] + pub fn cross_reverse(&mut self, other: &mut Seq) { + let (lits1, lits2) = match self.cross_preamble(other) { + None => return, + Some((lits1, lits2)) => (lits1, lits2), + }; + // We basically proceed as we do in 'cross_forward' at this point, + // except that the outer loop is now 'other' and the inner loop is now + // 'self'. That's because 'self' corresponds to suffixes and 'other' + // corresponds to the sequence we want to *prepend* to the suffixes. + let newcap = lits1.len().saturating_mul(lits2.len()); + let selflits = mem::replace(lits1, Vec::with_capacity(newcap)); + for (i, otherlit) in lits2.drain(..).enumerate() { + for selflit in selflits.iter() { + if !selflit.is_exact() { + // If the suffix isn't exact, then we can't prepend + // anything to it. However, we still want to keep it. But + // we only want to keep one of them, to avoid duplication. + // (The duplication is okay from a correctness perspective, + // but wasteful.) + if i == 0 { + lits1.push(selflit.clone()); + } + continue; + } + let mut newlit = Literal::exact(Vec::with_capacity( + otherlit.len() + selflit.len(), + )); + newlit.extend(&otherlit); + newlit.extend(&selflit); + if !otherlit.is_exact() { + newlit.make_inexact(); + } + lits1.push(newlit); + } + } + self.dedup(); + } + + /// A helper function the corresponds to the subtle preamble for both + /// `cross_forward` and `cross_reverse`. In effect, it handles the cases + /// of infinite sequences for both `self` and `other`, as well as ensuring + /// that literals from `other` are drained even if they aren't used. + fn cross_preamble<'a>( + &'a mut self, + other: &'a mut Seq, + ) -> Option<(&'a mut Vec, &'a mut Vec)> { + let lits2 = match other.literals { + None => { + // If our current seq contains the empty string and the seq + // we're adding matches any literal, then it follows that the + // current seq must now also match any literal. + // + // Otherwise, we just have to make sure everything in this + // sequence is inexact. + if self.min_literal_len() == Some(0) { + *self = Seq::infinite(); + } else { + self.make_inexact(); + } + return None; + } + Some(ref mut lits) => lits, + }; + let lits1 = match self.literals { + None => { + // If we aren't going to make it to the end of this routine + // where lits2 is drained, then we need to do it now. + lits2.drain(..); + return None; + } + Some(ref mut lits) => lits, + }; + Some((lits1, lits2)) + } + + /// Unions the `other` sequence into this one. + /// + /// The literals are always drained out of the given `other` sequence, + /// even if they are being unioned into an infinite sequence. This permits + /// the caller to reuse the `other` sequence in another context. + /// + /// Some literal deduping may be performed. If any deduping happens, + /// any leftmost-first or "preference" order match semantics will be + /// preserved. + /// + /// # Example + /// + /// This example shows basic usage. + /// + /// ``` + /// use regex_syntax::hir::literal::Seq; + /// + /// let mut seq1 = Seq::new(&["foo", "bar"]); + /// let mut seq2 = Seq::new(&["bar", "quux", "foo"]); + /// seq1.union(&mut seq2); + /// + /// // The literals are pulled out of seq2. + /// assert_eq!(Some(0), seq2.len()); + /// + /// // Adjacent literals are deduped, but non-adjacent literals may not be. + /// assert_eq!(Seq::new(&["foo", "bar", "quux", "foo"]), seq1); + /// ``` + /// + /// This example shows that literals are drained from `other` even when + /// they aren't necessarily used. + /// + /// ``` + /// use regex_syntax::hir::literal::Seq; + /// + /// let mut seq1 = Seq::infinite(); + /// // Infinite sequences have no finite length. + /// assert_eq!(None, seq1.len()); + /// + /// let mut seq2 = Seq::new(&["bar", "quux", "foo"]); + /// seq1.union(&mut seq2); + /// + /// // seq1 is still infinite and seq2 has been drained. + /// assert_eq!(None, seq1.len()); + /// assert_eq!(Some(0), seq2.len()); + /// ``` + #[inline] + pub fn union(&mut self, other: &mut Seq) { + let lits2 = match other.literals { + None => { + // Unioning with an infinite sequence always results in an + // infinite sequence. + self.make_infinite(); + return; + } + Some(ref mut lits) => lits.drain(..), + }; + let lits1 = match self.literals { + None => return, + Some(ref mut lits) => lits, + }; + lits1.extend(lits2); + self.dedup(); + } + + /// Unions the `other` sequence into this one by splice the `other` + /// sequence at the position of the first zero-length literal. + /// + /// This is useful for preserving preference order semantics when combining + /// two literal sequences. For example, in the regex `(a||f)+foo`, the + /// correct preference order prefix sequence is `[a, foo, f]`. + /// + /// The literals are always drained out of the given `other` sequence, + /// even if they are being unioned into an infinite sequence. This permits + /// the caller to reuse the `other` sequence in another context. Note that + /// the literals are drained even if no union is performed as well, i.e., + /// when this sequence does not contain a zero-length literal. + /// + /// Some literal deduping may be performed. If any deduping happens, + /// any leftmost-first or "preference" order match semantics will be + /// preserved. + /// + /// # Example + /// + /// This example shows basic usage. + /// + /// ``` + /// use regex_syntax::hir::literal::Seq; + /// + /// let mut seq1 = Seq::new(&["a", "", "f", ""]); + /// let mut seq2 = Seq::new(&["foo"]); + /// seq1.union_into_empty(&mut seq2); + /// + /// // The literals are pulled out of seq2. + /// assert_eq!(Some(0), seq2.len()); + /// // 'foo' gets spliced into seq1 where the first empty string occurs. + /// assert_eq!(Seq::new(&["a", "foo", "f"]), seq1); + /// ``` + /// + /// This example shows that literals are drained from `other` even when + /// they aren't necessarily used. + /// + /// ``` + /// use regex_syntax::hir::literal::Seq; + /// + /// let mut seq1 = Seq::new(&["foo", "bar"]); + /// let mut seq2 = Seq::new(&["bar", "quux", "foo"]); + /// seq1.union_into_empty(&mut seq2); + /// + /// // seq1 has no zero length literals, so no splicing happens. + /// assert_eq!(Seq::new(&["foo", "bar"]), seq1); + /// // Even though no splicing happens, seq2 is still drained. + /// assert_eq!(Some(0), seq2.len()); + /// ``` + #[inline] + pub fn union_into_empty(&mut self, other: &mut Seq) { + let lits2 = other.literals.as_mut().map(|lits| lits.drain(..)); + let lits1 = match self.literals { + None => return, + Some(ref mut lits) => lits, + }; + let first_empty = match lits1.iter().position(|m| m.is_empty()) { + None => return, + Some(i) => i, + }; + let lits2 = match lits2 { + None => { + // Note that we are only here if we've found an empty literal, + // which implies that an infinite sequence infects this seq and + // also turns it into an infinite sequence. + self.literals = None; + return; + } + Some(lits) => lits, + }; + // Clearing out the empties needs to come before the splice because + // the splice might add more empties that we don't want to get rid + // of. Since we're splicing into the position of the first empty, the + // 'first_empty' position computed above is still correct. + lits1.retain(|m| !m.is_empty()); + lits1.splice(first_empty..first_empty, lits2); + self.dedup(); + } + + /// Deduplicate adjacent equivalent literals in this sequence. + /// + /// If adjacent literals are equivalent strings but one is exact and the + /// other inexact, the inexact literal is kept and the exact one is + /// removed. + /// + /// Deduping an infinite sequence is a no-op. + /// + /// # Example + /// + /// This example shows how literals that are duplicate byte strings but + /// are not equivalent with respect to exactness are resolved. + /// + /// ``` + /// use regex_syntax::hir::literal::{Literal, Seq}; + /// + /// let mut seq = Seq::from_iter([ + /// Literal::exact("foo"), + /// Literal::inexact("foo"), + /// ]); + /// seq.dedup(); + /// + /// assert_eq!(Seq::from_iter([Literal::inexact("foo")]), seq); + /// ``` + #[inline] + pub fn dedup(&mut self) { + if let Some(ref mut lits) = self.literals { + lits.dedup_by(|lit1, lit2| { + if lit1.as_bytes() != lit2.as_bytes() { + return false; + } + if lit1.is_exact() != lit2.is_exact() { + lit1.make_inexact(); + lit2.make_inexact(); + } + true + }); + } + } + + /// Sorts this sequence of literals lexicographically. + /// + /// Note that if, before sorting, if a literal that is a prefix of another + /// literal appears after it, then after sorting, the sequence will not + /// represent the same preference order match semantics. For example, + /// sorting the sequence `[samwise, sam]` yields the sequence `[sam, + /// samwise]`. Under preference order semantics, the latter sequence will + /// never match `samwise` where as the first sequence can. + /// + /// # Example + /// + /// This example shows basic usage. + /// + /// ``` + /// use regex_syntax::hir::literal::Seq; + /// + /// let mut seq = Seq::new(&["foo", "quux", "bar"]); + /// seq.sort(); + /// + /// assert_eq!(Seq::new(&["bar", "foo", "quux"]), seq); + /// ``` + #[inline] + pub fn sort(&mut self) { + if let Some(ref mut lits) = self.literals { + lits.sort(); + } + } + + /// Reverses all of the literals in this sequence. + /// + /// The order of the sequence itself is preserved. + /// + /// # Example + /// + /// This example shows basic usage. + /// + /// ``` + /// use regex_syntax::hir::literal::Seq; + /// + /// let mut seq = Seq::new(&["oof", "rab"]); + /// seq.reverse_literals(); + /// assert_eq!(Seq::new(&["foo", "bar"]), seq); + /// ``` + #[inline] + pub fn reverse_literals(&mut self) { + if let Some(ref mut lits) = self.literals { + for lit in lits.iter_mut() { + lit.reverse(); + } + } + } + + /// Shrinks this seq to its minimal size while respecting the preference + /// order of its literals. + /// + /// While this routine will remove duplicate literals from this seq, it + /// will also remove literals that can never match in a leftmost-first or + /// "preference order" search. Similar to [`Seq::dedup`], if a literal is + /// deduped, then the one that remains is made inexact. + /// + /// This is a no-op on seqs that are empty or not finite. + /// + /// # Example + /// + /// This example shows the difference between `{sam, samwise}` and + /// `{samwise, sam}`. + /// + /// ``` + /// use regex_syntax::hir::literal::{Literal, Seq}; + /// + /// // If 'sam' comes before 'samwise' and a preference order search is + /// // executed, then 'samwise' can never match. + /// let mut seq = Seq::new(&["sam", "samwise"]); + /// seq.minimize_by_preference(); + /// assert_eq!(Seq::from_iter([Literal::inexact("sam")]), seq); + /// + /// // But if they are reversed, then it's possible for 'samwise' to match + /// // since it is given higher preference. + /// let mut seq = Seq::new(&["samwise", "sam"]); + /// seq.minimize_by_preference(); + /// assert_eq!(Seq::new(&["samwise", "sam"]), seq); + /// ``` + /// + /// This example shows that if an empty string is in this seq, then + /// anything that comes after it can never match. + /// + /// ``` + /// use regex_syntax::hir::literal::{Literal, Seq}; + /// + /// // An empty string is a prefix of all strings, so it automatically + /// // inhibits any subsequent strings from matching. + /// let mut seq = Seq::new(&["foo", "bar", "", "quux", "fox"]); + /// seq.minimize_by_preference(); + /// let expected = Seq::from_iter([ + /// Literal::exact("foo"), + /// Literal::exact("bar"), + /// Literal::inexact(""), + /// ]); + /// assert_eq!(expected, seq); + /// + /// // And of course, if it's at the beginning, then it makes it impossible + /// // for anything else to match. + /// let mut seq = Seq::new(&["", "foo", "quux", "fox"]); + /// seq.minimize_by_preference(); + /// assert_eq!(Seq::from_iter([Literal::inexact("")]), seq); + /// ``` + #[inline] + pub fn minimize_by_preference(&mut self) { + if let Some(ref mut lits) = self.literals { + PreferenceTrie::minimize(lits, false); + } + } + + /// Trims all literals in this seq such that only the first `len` bytes + /// remain. If a literal has less than or equal to `len` bytes, then it + /// remains unchanged. Otherwise, it is trimmed and made inexact. + /// + /// # Example + /// + /// ``` + /// use regex_syntax::hir::literal::{Literal, Seq}; + /// + /// let mut seq = Seq::new(&["a", "foo", "quux"]); + /// seq.keep_first_bytes(2); + /// + /// let expected = Seq::from_iter([ + /// Literal::exact("a"), + /// Literal::inexact("fo"), + /// Literal::inexact("qu"), + /// ]); + /// assert_eq!(expected, seq); + /// ``` + #[inline] + pub fn keep_first_bytes(&mut self, len: usize) { + if let Some(ref mut lits) = self.literals { + for m in lits.iter_mut() { + m.keep_first_bytes(len); + } + } + } + + /// Trims all literals in this seq such that only the last `len` bytes + /// remain. If a literal has less than or equal to `len` bytes, then it + /// remains unchanged. Otherwise, it is trimmed and made inexact. + /// + /// # Example + /// + /// ``` + /// use regex_syntax::hir::literal::{Literal, Seq}; + /// + /// let mut seq = Seq::new(&["a", "foo", "quux"]); + /// seq.keep_last_bytes(2); + /// + /// let expected = Seq::from_iter([ + /// Literal::exact("a"), + /// Literal::inexact("oo"), + /// Literal::inexact("ux"), + /// ]); + /// assert_eq!(expected, seq); + /// ``` + #[inline] + pub fn keep_last_bytes(&mut self, len: usize) { + if let Some(ref mut lits) = self.literals { + for m in lits.iter_mut() { + m.keep_last_bytes(len); + } + } + } + + /// Returns true if this sequence is finite. + /// + /// When false, this sequence is infinite and must be treated as if it + /// contains every possible literal. + #[inline] + pub fn is_finite(&self) -> bool { + self.literals.is_some() + } + + /// Returns true if and only if this sequence is finite and empty. + /// + /// An empty sequence never matches anything. It can only be produced by + /// literal extraction when the corresponding regex itself cannot match. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == Some(0) + } + + /// Returns the number of literals in this sequence if the sequence is + /// finite. If the sequence is infinite, then `None` is returned. + #[inline] + pub fn len(&self) -> Option { + self.literals.as_ref().map(|lits| lits.len()) + } + + /// Returns true if and only if all literals in this sequence are exact. + /// + /// This returns false if the sequence is infinite. + #[inline] + pub fn is_exact(&self) -> bool { + self.literals().map_or(false, |lits| lits.iter().all(|x| x.is_exact())) + } + + /// Returns true if and only if all literals in this sequence are inexact. + /// + /// This returns true if the sequence is infinite. + #[inline] + pub fn is_inexact(&self) -> bool { + self.literals().map_or(true, |lits| lits.iter().all(|x| !x.is_exact())) + } + + /// Return the maximum length of the sequence that would result from + /// unioning `self` with `other`. If either set is infinite, then this + /// returns `None`. + #[inline] + pub fn max_union_len(&self, other: &Seq) -> Option { + let len1 = self.len()?; + let len2 = other.len()?; + Some(len1.saturating_add(len2)) + } + + /// Return the maximum length of the sequence that would result from the + /// cross product of `self` with `other`. If either set is infinite, then + /// this returns `None`. + #[inline] + pub fn max_cross_len(&self, other: &Seq) -> Option { + let len1 = self.len()?; + let len2 = other.len()?; + Some(len1.saturating_mul(len2)) + } + + /// Returns the length of the shortest literal in this sequence. + /// + /// If the sequence is infinite or empty, then this returns `None`. + #[inline] + pub fn min_literal_len(&self) -> Option { + self.literals.as_ref()?.iter().map(|x| x.len()).min() + } + + /// Returns the length of the longest literal in this sequence. + /// + /// If the sequence is infinite or empty, then this returns `None`. + #[inline] + pub fn max_literal_len(&self) -> Option { + self.literals.as_ref()?.iter().map(|x| x.len()).max() + } + + /// Returns the longest common prefix from this seq. + /// + /// If the seq matches any literal or other contains no literals, then + /// there is no meaningful prefix and this returns `None`. + /// + /// # Example + /// + /// This shows some example seqs and their longest common prefix. + /// + /// ``` + /// use regex_syntax::hir::literal::Seq; + /// + /// let seq = Seq::new(&["foo", "foobar", "fo"]); + /// assert_eq!(Some(&b"fo"[..]), seq.longest_common_prefix()); + /// let seq = Seq::new(&["foo", "foo"]); + /// assert_eq!(Some(&b"foo"[..]), seq.longest_common_prefix()); + /// let seq = Seq::new(&["foo", "bar"]); + /// assert_eq!(Some(&b""[..]), seq.longest_common_prefix()); + /// let seq = Seq::new(&[""]); + /// assert_eq!(Some(&b""[..]), seq.longest_common_prefix()); + /// + /// let seq = Seq::infinite(); + /// assert_eq!(None, seq.longest_common_prefix()); + /// let seq = Seq::empty(); + /// assert_eq!(None, seq.longest_common_prefix()); + /// ``` + #[inline] + pub fn longest_common_prefix(&self) -> Option<&[u8]> { + // If we match everything or match nothing, then there's no meaningful + // longest common prefix. + let lits = match self.literals { + None => return None, + Some(ref lits) => lits, + }; + if lits.len() == 0 { + return None; + } + let base = lits[0].as_bytes(); + let mut len = base.len(); + for m in lits.iter().skip(1) { + len = m + .as_bytes() + .iter() + .zip(base[..len].iter()) + .take_while(|&(a, b)| a == b) + .count(); + if len == 0 { + return Some(&[]); + } + } + Some(&base[..len]) + } + + /// Returns the longest common suffix from this seq. + /// + /// If the seq matches any literal or other contains no literals, then + /// there is no meaningful suffix and this returns `None`. + /// + /// # Example + /// + /// This shows some example seqs and their longest common suffix. + /// + /// ``` + /// use regex_syntax::hir::literal::Seq; + /// + /// let seq = Seq::new(&["oof", "raboof", "of"]); + /// assert_eq!(Some(&b"of"[..]), seq.longest_common_suffix()); + /// let seq = Seq::new(&["foo", "foo"]); + /// assert_eq!(Some(&b"foo"[..]), seq.longest_common_suffix()); + /// let seq = Seq::new(&["foo", "bar"]); + /// assert_eq!(Some(&b""[..]), seq.longest_common_suffix()); + /// let seq = Seq::new(&[""]); + /// assert_eq!(Some(&b""[..]), seq.longest_common_suffix()); + /// + /// let seq = Seq::infinite(); + /// assert_eq!(None, seq.longest_common_suffix()); + /// let seq = Seq::empty(); + /// assert_eq!(None, seq.longest_common_suffix()); + /// ``` + #[inline] + pub fn longest_common_suffix(&self) -> Option<&[u8]> { + // If we match everything or match nothing, then there's no meaningful + // longest common suffix. + let lits = match self.literals { + None => return None, + Some(ref lits) => lits, + }; + if lits.len() == 0 { + return None; + } + let base = lits[0].as_bytes(); + let mut len = base.len(); + for m in lits.iter().skip(1) { + len = m + .as_bytes() + .iter() + .rev() + .zip(base[base.len() - len..].iter().rev()) + .take_while(|&(a, b)| a == b) + .count(); + if len == 0 { + return Some(&[]); + } + } + Some(&base[base.len() - len..]) + } + + /// Optimizes this seq while treating its literals as prefixes and + /// respecting the preference order of its literals. + /// + /// The specific way "optimization" works is meant to be an implementation + /// detail, as it essentially represents a set of heuristics. The goal + /// that optimization tries to accomplish is to make the literals in this + /// set reflect inputs that will result in a more effective prefilter. + /// Principally by reducing the false positive rate of candidates found by + /// the literals in this sequence. That is, when a match of a literal is + /// found, we would like it to be a strong predictor of the overall match + /// of the regex. If it isn't, then much time will be spent starting and + /// stopping the prefilter search and attempting to confirm the match only + /// to have it fail. + /// + /// Some of those heuristics might be: + /// + /// * Identifying a common prefix from a larger sequence of literals, and + /// shrinking the sequence down to that single common prefix. + /// * Rejecting the sequence entirely if it is believed to result in very + /// high false positive rate. When this happens, the sequence is made + /// infinite. + /// * Shrinking the sequence to a smaller number of literals representing + /// prefixes, but not shrinking it so much as to make literals too short. + /// (A sequence with very short literals, of 1 or 2 bytes, will typically + /// result in a higher false positive rate.) + /// + /// Optimization should only be run once extraction is complete. Namely, + /// optimization may make assumptions that do not compose with other + /// operations in the middle of extraction. For example, optimization will + /// reduce `[E(sam), E(samwise)]` to `[E(sam)]`, but such a transformation + /// is only valid if no other extraction will occur. If other extraction + /// may occur, then the correct transformation would be to `[I(sam)]`. + /// + /// The [`Seq::optimize_for_suffix_by_preference`] does the same thing, but + /// for suffixes. + /// + /// # Example + /// + /// This shows how optimization might transform a sequence. Note that + /// the specific behavior is not a documented guarantee. The heuristics + /// used are an implementation detail and may change over time in semver + /// compatible releases. + /// + /// ``` + /// use regex_syntax::hir::literal::{Seq, Literal}; + /// + /// let mut seq = Seq::new(&[ + /// "samantha", + /// "sam", + /// "samwise", + /// "frodo", + /// ]); + /// seq.optimize_for_prefix_by_preference(); + /// assert_eq!(Seq::from_iter([ + /// Literal::exact("samantha"), + /// // Kept exact even though 'samwise' got pruned + /// // because optimization assumes literal extraction + /// // has finished. + /// Literal::exact("sam"), + /// Literal::exact("frodo"), + /// ]), seq); + /// ``` + /// + /// # Example: optimization may make the sequence infinite + /// + /// If the heuristics deem that the sequence could cause a very high false + /// positive rate, then it may make the sequence infinite, effectively + /// disabling its use as a prefilter. + /// + /// ``` + /// use regex_syntax::hir::literal::{Seq, Literal}; + /// + /// let mut seq = Seq::new(&[ + /// "samantha", + /// // An empty string matches at every position, + /// // thus rendering the prefilter completely + /// // ineffective. + /// "", + /// "sam", + /// "samwise", + /// "frodo", + /// ]); + /// seq.optimize_for_prefix_by_preference(); + /// assert!(!seq.is_finite()); + /// ``` + /// + /// Do note that just because there is a `" "` in the sequence, that + /// doesn't mean the sequence will always be made infinite after it is + /// optimized. Namely, if the sequence is considered exact (any match + /// corresponds to an overall match of the original regex), then any match + /// is an overall match, and so the false positive rate is always `0`. + /// + /// To demonstrate this, we remove `samwise` from our sequence. This + /// results in no optimization happening and all literals remain exact. + /// Thus the entire sequence is exact, and it is kept as-is, even though + /// one is an ASCII space: + /// + /// ``` + /// use regex_syntax::hir::literal::{Seq, Literal}; + /// + /// let mut seq = Seq::new(&[ + /// "samantha", + /// " ", + /// "sam", + /// "frodo", + /// ]); + /// seq.optimize_for_prefix_by_preference(); + /// assert!(seq.is_finite()); + /// ``` + #[inline] + pub fn optimize_for_prefix_by_preference(&mut self) { + self.optimize_by_preference(true); + } + + /// Optimizes this seq while treating its literals as suffixes and + /// respecting the preference order of its literals. + /// + /// Optimization should only be run once extraction is complete. + /// + /// The [`Seq::optimize_for_prefix_by_preference`] does the same thing, but + /// for prefixes. See its documentation for more explanation. + #[inline] + pub fn optimize_for_suffix_by_preference(&mut self) { + self.optimize_by_preference(false); + } + + fn optimize_by_preference(&mut self, prefix: bool) { + let origlen = match self.len() { + None => return, + Some(len) => len, + }; + // Just give up now if our sequence contains an empty string. + if self.min_literal_len().map_or(false, |len| len == 0) { + // We squash the sequence so that nobody else gets any bright + // ideas to try and use it. An empty string implies a match at + // every position. A prefilter cannot help you here. + self.make_infinite(); + return; + } + // Make sure we start with the smallest sequence possible. We use a + // special version of preference minimization that retains exactness. + // This is legal because optimization is only expected to occur once + // extraction is complete. + if prefix { + if let Some(ref mut lits) = self.literals { + PreferenceTrie::minimize(lits, true); + } + } + + // Look for a common prefix (or suffix). If we found one of those and + // it's long enough, then it's a good bet that it will be our fastest + // possible prefilter since single-substring search is so fast. + let fix = if prefix { + self.longest_common_prefix() + } else { + self.longest_common_suffix() + }; + if let Some(fix) = fix { + // As a special case, if we have a common prefix and the leading + // byte of that prefix is one that we think probably occurs rarely, + // then strip everything down to just that single byte. This should + // promote the use of memchr. + // + // ... we only do this though if our sequence has more than one + // literal. Otherwise, we'd rather just stick with a single literal + // scan. That is, using memchr is probably better than looking + // for 2 or more literals, but probably not as good as a straight + // memmem search. + // + // ... and also only do this when the prefix is short and probably + // not too discriminatory anyway. If it's longer, then it's + // probably quite discriminatory and thus is likely to have a low + // false positive rate. + if prefix + && origlen > 1 + && fix.len() >= 1 + && fix.len() <= 3 + && rank(fix[0]) < 200 + { + self.keep_first_bytes(1); + self.dedup(); + return; + } + // We only strip down to the common prefix/suffix if we think + // the existing set of literals isn't great, or if the common + // prefix/suffix is expected to be particularly discriminatory. + let isfast = + self.is_exact() && self.len().map_or(false, |len| len <= 16); + let usefix = fix.len() > 4 || (fix.len() > 1 && !isfast); + if usefix { + // If we keep exactly the number of bytes equal to the length + // of the prefix (or suffix), then by the definition of a + // prefix, every literal in the sequence will be equivalent. + // Thus, 'dedup' will leave us with one literal. + // + // We do it this way to avoid an alloc, but also to make sure + // the exactness of literals is kept (or not). + if prefix { + self.keep_first_bytes(fix.len()); + } else { + self.keep_last_bytes(fix.len()); + } + self.dedup(); + assert_eq!(Some(1), self.len()); + // We still fall through here. In particular, we want our + // longest common prefix to be subject to the poison check. + } + } + // If we have an exact sequence, we *probably* just want to keep it + // as-is. But there are some cases where we don't. So we save a copy of + // the exact sequence now, and then try to do some more optimizations + // below. If those don't work out, we go back to this exact sequence. + // + // The specific motivation for this is that we sometimes wind up with + // an exact sequence with a hefty number of literals. Say, 100. If we + // stuck with that, it would be too big for Teddy and would result in + // using Aho-Corasick. Which is fine... but the lazy DFA is plenty + // suitable in such cases. The real issue is that we will wind up not + // using a fast prefilter at all. So in cases like this, even though + // we have an exact sequence, it would be better to try and shrink the + // sequence (which we do below) and use it as a prefilter that can + // produce false positive matches. + // + // But if the shrinking below results in a sequence that "sucks," then + // we don't want to use that because we already have an exact sequence + // in hand. + let exact: Option = + if self.is_exact() { Some(self.clone()) } else { None }; + // Now we attempt to shorten the sequence. The idea here is that we + // don't want to look for too many literals, but we want to shorten + // our sequence enough to improve our odds of using better algorithms + // downstream (such as Teddy). + // + // The pair of numbers in this list corresponds to the maximal prefix + // (in bytes) to keep for all literals and the length of the sequence + // at which to do it. + // + // So for example, the pair (3, 500) would mean, "if we have more than + // 500 literals in our sequence, then truncate all of our literals + // such that they are at most 3 bytes in length and the minimize the + // sequence." + const ATTEMPTS: [(usize, usize); 5] = + [(5, 10), (4, 10), (3, 64), (2, 64), (1, 10)]; + for (keep, limit) in ATTEMPTS { + let len = match self.len() { + None => break, + Some(len) => len, + }; + if len <= limit { + break; + } + if prefix { + self.keep_first_bytes(keep); + } else { + self.keep_last_bytes(keep); + } + if prefix { + if let Some(ref mut lits) = self.literals { + PreferenceTrie::minimize(lits, true); + } + } + } + // Check for a poison literal. A poison literal is one that is short + // and is believed to have a very high match count. These poisons + // generally lead to a prefilter with a very high false positive rate, + // and thus overall worse performance. + // + // We do this last because we could have gone from a non-poisonous + // sequence to a poisonous one. Perhaps we should add some code to + // prevent such transitions in the first place, but then again, we + // likely only made the transition in the first place if the sequence + // was itself huge. And huge sequences are themselves poisonous. So... + if let Some(lits) = self.literals() { + if lits.iter().any(|lit| lit.is_poisonous()) { + self.make_infinite(); + } + } + // OK, if we had an exact sequence before attempting more optimizations + // above and our post-optimized sequence sucks for some reason or + // another, then we go back to the exact sequence. + if let Some(exact) = exact { + // If optimizing resulted in dropping our literals, then certainly + // backup and use the exact sequence that we had. + if !self.is_finite() { + *self = exact; + return; + } + // If our optimized sequence contains a short literal, then it's + // *probably* not so great. So throw it away and revert to the + // exact sequence. + if self.min_literal_len().map_or(true, |len| len <= 2) { + *self = exact; + return; + } + // Finally, if our optimized sequence is "big" (i.e., can't use + // Teddy), then also don't use it and rely on the exact sequence. + if self.len().map_or(true, |len| len > 64) { + *self = exact; + return; + } + } + } +} + +impl core::fmt::Debug for Seq { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "Seq")?; + if let Some(lits) = self.literals() { + f.debug_list().entries(lits.iter()).finish() + } else { + write!(f, "[∞]") + } + } +} + +impl FromIterator for Seq { + fn from_iter>(it: T) -> Seq { + let mut seq = Seq::empty(); + for literal in it { + seq.push(literal); + } + seq + } +} + +/// A single literal extracted from an [`Hir`] expression. +/// +/// A literal is composed of two things: +/// +/// * A sequence of bytes. No guarantees with respect to UTF-8 are provided. +/// In particular, even if the regex a literal is extracted from is UTF-8, the +/// literal extracted may not be valid UTF-8. (For example, if an [`Extractor`] +/// limit resulted in trimming a literal in a way that splits a codepoint.) +/// * Whether the literal is "exact" or not. An "exact" literal means that it +/// has not been trimmed, and may continue to be extended. If a literal is +/// "exact" after visiting the entire `Hir` expression, then this implies that +/// the literal leads to a match state. (Although it doesn't necessarily imply +/// all occurrences of the literal correspond to a match of the regex, since +/// literal extraction ignores look-around assertions.) +#[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct Literal { + bytes: Vec, + exact: bool, +} + +impl Literal { + /// Returns a new exact literal containing the bytes given. + #[inline] + pub fn exact>>(bytes: B) -> Literal { + Literal { bytes: bytes.into(), exact: true } + } + + /// Returns a new inexact literal containing the bytes given. + #[inline] + pub fn inexact>>(bytes: B) -> Literal { + Literal { bytes: bytes.into(), exact: false } + } + + /// Returns the bytes in this literal. + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.bytes + } + + /// Yields ownership of the bytes inside this literal. + /// + /// Note that this throws away whether the literal is "exact" or not. + #[inline] + pub fn into_bytes(self) -> Vec { + self.bytes + } + + /// Returns the length of this literal in bytes. + #[inline] + pub fn len(&self) -> usize { + self.as_bytes().len() + } + + /// Returns true if and only if this literal has zero bytes. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns true if and only if this literal is exact. + #[inline] + pub fn is_exact(&self) -> bool { + self.exact + } + + /// Marks this literal as inexact. + /// + /// Inexact literals can never be extended. For example, + /// [`Seq::cross_forward`] will not extend inexact literals. + #[inline] + pub fn make_inexact(&mut self) { + self.exact = false; + } + + /// Reverse the bytes in this literal. + #[inline] + pub fn reverse(&mut self) { + self.bytes.reverse(); + } + + /// Extend this literal with the literal given. + /// + /// If this literal is inexact, then this is a no-op. + #[inline] + pub fn extend(&mut self, lit: &Literal) { + if !self.is_exact() { + return; + } + self.bytes.extend_from_slice(&lit.bytes); + } + + /// Trims this literal such that only the first `len` bytes remain. If + /// this literal has fewer than `len` bytes, then it remains unchanged. + /// Otherwise, the literal is marked as inexact. + #[inline] + pub fn keep_first_bytes(&mut self, len: usize) { + if len >= self.len() { + return; + } + self.make_inexact(); + self.bytes.truncate(len); + } + + /// Trims this literal such that only the last `len` bytes remain. If this + /// literal has fewer than `len` bytes, then it remains unchanged. + /// Otherwise, the literal is marked as inexact. + #[inline] + pub fn keep_last_bytes(&mut self, len: usize) { + if len >= self.len() { + return; + } + self.make_inexact(); + self.bytes.drain(..self.len() - len); + } + + /// Returns true if it is believe that this literal is likely to match very + /// frequently, and is thus not a good candidate for a prefilter. + fn is_poisonous(&self) -> bool { + self.is_empty() || (self.len() == 1 && rank(self.as_bytes()[0]) >= 250) + } +} + +impl From for Literal { + fn from(byte: u8) -> Literal { + Literal::exact(vec![byte]) + } +} + +impl From for Literal { + fn from(ch: char) -> Literal { + use alloc::string::ToString; + Literal::exact(ch.encode_utf8(&mut [0; 4]).to_string()) + } +} + +impl AsRef<[u8]> for Literal { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl core::fmt::Debug for Literal { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + let tag = if self.exact { "E" } else { "I" }; + f.debug_tuple(tag) + .field(&crate::debug::Bytes(self.as_bytes())) + .finish() + } +} + +/// A "preference" trie that rejects literals that will never match when +/// executing a leftmost first or "preference" search. +/// +/// For example, if 'sam' is inserted, then trying to insert 'samwise' will be +/// rejected because 'samwise' can never match since 'sam' will always take +/// priority. However, if 'samwise' is inserted first, then inserting 'sam' +/// after it is accepted. In this case, either 'samwise' or 'sam' can match in +/// a "preference" search. +/// +/// Note that we only use this trie as a "set." That is, given a sequence of +/// literals, we insert each one in order. An `insert` will reject a literal +/// if a prefix of that literal already exists in the trie. Thus, to rebuild +/// the "minimal" sequence, we simply only keep literals that were successfully +/// inserted. (Since we don't need traversal, one wonders whether we can make +/// some simplifications here, but I haven't given it a ton of thought and I've +/// never seen this show up on a profile. Because of the heuristic limits +/// imposed on literal extractions, the size of the inputs here is usually +/// very small.) +#[derive(Debug)] +struct PreferenceTrie { + /// The states in this trie. The index of a state in this vector is its ID. + states: Vec, + /// This vec indicates which states are match states. It always has + /// the same length as `states` and is indexed by the same state ID. + /// A state with identifier `sid` is a match state if and only if + /// `matches[sid].is_some()`. The option contains the index of the literal + /// corresponding to the match. The index is offset by 1 so that it fits in + /// a NonZeroUsize. + matches: Vec>, + /// The index to allocate to the next literal added to this trie. Starts at + /// 1 and increments by 1 for every literal successfully added to the trie. + next_literal_index: usize, +} + +/// A single state in a trie. Uses a sparse representation for its transitions. +#[derive(Debug, Default)] +struct State { + /// Sparse representation of the transitions out of this state. Transitions + /// are sorted by byte. There is at most one such transition for any + /// particular byte. + trans: Vec<(u8, usize)>, +} + +impl PreferenceTrie { + /// Minimizes the given sequence of literals while preserving preference + /// order semantics. + /// + /// When `keep_exact` is true, the exactness of every literal retained is + /// kept. This is useful when dealing with a fully extracted `Seq` that + /// only contains exact literals. In that case, we can keep all retained + /// literals as exact because we know we'll never need to match anything + /// after them and because any removed literals are guaranteed to never + /// match. + fn minimize(literals: &mut Vec, keep_exact: bool) { + use core::cell::RefCell; + + // MSRV(1.61): Use retain_mut here to avoid interior mutability. + let trie = RefCell::new(PreferenceTrie { + states: vec![], + matches: vec![], + next_literal_index: 1, + }); + let mut make_inexact = vec![]; + literals.retain(|lit| { + match trie.borrow_mut().insert(lit.as_bytes()) { + Ok(_) => true, + Err(i) => { + if !keep_exact { + make_inexact.push(i.checked_sub(1).unwrap()); + } + false + } + } + }); + for i in make_inexact { + literals[i].make_inexact(); + } + } + + /// Returns `Ok` if the given byte string is accepted into this trie and + /// `Err` otherwise. The index for the success case corresponds to the + /// index of the literal added. The index for the error case corresponds to + /// the index of the literal already in the trie that prevented the given + /// byte string from being added. (Which implies it is a prefix of the one + /// given.) + /// + /// In short, the byte string given is accepted into the trie if and only + /// if it is possible for it to match when executing a preference order + /// search. + fn insert(&mut self, bytes: &[u8]) -> Result { + let mut prev = self.root(); + if let Some(idx) = self.matches[prev] { + return Err(idx.get()); + } + for &b in bytes.iter() { + match self.states[prev].trans.binary_search_by_key(&b, |t| t.0) { + Ok(i) => { + prev = self.states[prev].trans[i].1; + if let Some(idx) = self.matches[prev] { + return Err(idx.get()); + } + } + Err(i) => { + let next = self.create_state(); + self.states[prev].trans.insert(i, (b, next)); + prev = next; + } + } + } + let idx = self.next_literal_index; + self.next_literal_index += 1; + self.matches[prev] = NonZeroUsize::new(idx); + Ok(idx) + } + + /// Returns the root state ID, and if it doesn't exist, creates it. + fn root(&mut self) -> usize { + if !self.states.is_empty() { + 0 + } else { + self.create_state() + } + } + + /// Creates a new empty state and returns its ID. + fn create_state(&mut self) -> usize { + let id = self.states.len(); + self.states.push(State::default()); + self.matches.push(None); + id + } +} + +/// Returns the "rank" of the given byte. +/// +/// The minimum rank value is `0` and the maximum rank value is `255`. +/// +/// The rank of a byte is derived from a heuristic background distribution of +/// relative frequencies of bytes. The heuristic says that lower the rank of a +/// byte, the less likely that byte is to appear in any arbitrary haystack. +pub fn rank(byte: u8) -> u8 { + crate::rank::BYTE_FREQUENCIES[usize::from(byte)] +} + +#[cfg(test)] +mod tests { + use super::*; + + fn parse(pattern: &str) -> Hir { + crate::ParserBuilder::new().utf8(false).build().parse(pattern).unwrap() + } + + fn prefixes(pattern: &str) -> Seq { + Extractor::new().kind(ExtractKind::Prefix).extract(&parse(pattern)) + } + + fn suffixes(pattern: &str) -> Seq { + Extractor::new().kind(ExtractKind::Suffix).extract(&parse(pattern)) + } + + fn e(pattern: &str) -> (Seq, Seq) { + (prefixes(pattern), suffixes(pattern)) + } + + #[allow(non_snake_case)] + fn E(x: &str) -> Literal { + Literal::exact(x.as_bytes()) + } + + #[allow(non_snake_case)] + fn I(x: &str) -> Literal { + Literal::inexact(x.as_bytes()) + } + + fn seq>(it: I) -> Seq { + Seq::from_iter(it) + } + + fn infinite() -> (Seq, Seq) { + (Seq::infinite(), Seq::infinite()) + } + + fn inexact(it1: I1, it2: I2) -> (Seq, Seq) + where + I1: IntoIterator, + I2: IntoIterator, + { + (Seq::from_iter(it1), Seq::from_iter(it2)) + } + + fn exact, I: IntoIterator>(it: I) -> (Seq, Seq) { + let s1 = Seq::new(it); + let s2 = s1.clone(); + (s1, s2) + } + + fn opt, I: IntoIterator>(it: I) -> (Seq, Seq) { + let (mut p, mut s) = exact(it); + p.optimize_for_prefix_by_preference(); + s.optimize_for_suffix_by_preference(); + (p, s) + } + + #[test] + fn literal() { + assert_eq!(exact(["a"]), e("a")); + assert_eq!(exact(["aaaaa"]), e("aaaaa")); + assert_eq!(exact(["A", "a"]), e("(?i-u)a")); + assert_eq!(exact(["AB", "Ab", "aB", "ab"]), e("(?i-u)ab")); + assert_eq!(exact(["abC", "abc"]), e("ab(?i-u)c")); + + assert_eq!(exact([b"\xFF"]), e(r"(?-u:\xFF)")); + + #[cfg(feature = "unicode-case")] + { + assert_eq!(exact(["☃"]), e("☃")); + assert_eq!(exact(["☃"]), e("(?i)☃")); + assert_eq!(exact(["☃☃☃☃☃"]), e("☃☃☃☃☃")); + + assert_eq!(exact(["Δ"]), e("Δ")); + assert_eq!(exact(["δ"]), e("δ")); + assert_eq!(exact(["Δ", "δ"]), e("(?i)Δ")); + assert_eq!(exact(["Δ", "δ"]), e("(?i)δ")); + + assert_eq!(exact(["S", "s", "Å¿"]), e("(?i)S")); + assert_eq!(exact(["S", "s", "Å¿"]), e("(?i)s")); + assert_eq!(exact(["S", "s", "Å¿"]), e("(?i)Å¿")); + } + + let letters = "ͱͳͷÎάέήίΰαβγδεζηθικλμνξοπÏςστυφχψωϊϋ"; + assert_eq!(exact([letters]), e(letters)); + } + + #[test] + fn class() { + assert_eq!(exact(["a", "b", "c"]), e("[abc]")); + assert_eq!(exact(["a1b", "a2b", "a3b"]), e("a[123]b")); + assert_eq!(exact(["δ", "ε"]), e("[εδ]")); + #[cfg(feature = "unicode-case")] + { + assert_eq!(exact(["Δ", "Ε", "δ", "ε", "ϵ"]), e(r"(?i)[εδ]")); + } + } + + #[test] + fn look() { + assert_eq!(exact(["ab"]), e(r"a\Ab")); + assert_eq!(exact(["ab"]), e(r"a\zb")); + assert_eq!(exact(["ab"]), e(r"a(?m:^)b")); + assert_eq!(exact(["ab"]), e(r"a(?m:$)b")); + assert_eq!(exact(["ab"]), e(r"a\bb")); + assert_eq!(exact(["ab"]), e(r"a\Bb")); + assert_eq!(exact(["ab"]), e(r"a(?-u:\b)b")); + assert_eq!(exact(["ab"]), e(r"a(?-u:\B)b")); + + assert_eq!(exact(["ab"]), e(r"^ab")); + assert_eq!(exact(["ab"]), e(r"$ab")); + assert_eq!(exact(["ab"]), e(r"(?m:^)ab")); + assert_eq!(exact(["ab"]), e(r"(?m:$)ab")); + assert_eq!(exact(["ab"]), e(r"\bab")); + assert_eq!(exact(["ab"]), e(r"\Bab")); + assert_eq!(exact(["ab"]), e(r"(?-u:\b)ab")); + assert_eq!(exact(["ab"]), e(r"(?-u:\B)ab")); + + assert_eq!(exact(["ab"]), e(r"ab^")); + assert_eq!(exact(["ab"]), e(r"ab$")); + assert_eq!(exact(["ab"]), e(r"ab(?m:^)")); + assert_eq!(exact(["ab"]), e(r"ab(?m:$)")); + assert_eq!(exact(["ab"]), e(r"ab\b")); + assert_eq!(exact(["ab"]), e(r"ab\B")); + assert_eq!(exact(["ab"]), e(r"ab(?-u:\b)")); + assert_eq!(exact(["ab"]), e(r"ab(?-u:\B)")); + + let expected = (seq([I("aZ"), E("ab")]), seq([I("Zb"), E("ab")])); + assert_eq!(expected, e(r"^aZ*b")); + } + + #[test] + fn repetition() { + assert_eq!(exact(["a", ""]), e(r"a?")); + assert_eq!(exact(["", "a"]), e(r"a??")); + assert_eq!(inexact([I("a"), E("")], [I("a"), E("")]), e(r"a*")); + assert_eq!(inexact([E(""), I("a")], [E(""), I("a")]), e(r"a*?")); + assert_eq!(inexact([I("a")], [I("a")]), e(r"a+")); + assert_eq!(inexact([I("a")], [I("a")]), e(r"(a+)+")); + + assert_eq!(exact(["ab"]), e(r"aZ{0}b")); + assert_eq!(exact(["aZb", "ab"]), e(r"aZ?b")); + assert_eq!(exact(["ab", "aZb"]), e(r"aZ??b")); + assert_eq!( + inexact([I("aZ"), E("ab")], [I("Zb"), E("ab")]), + e(r"aZ*b") + ); + assert_eq!( + inexact([E("ab"), I("aZ")], [E("ab"), I("Zb")]), + e(r"aZ*?b") + ); + assert_eq!(inexact([I("aZ")], [I("Zb")]), e(r"aZ+b")); + assert_eq!(inexact([I("aZ")], [I("Zb")]), e(r"aZ+?b")); + + assert_eq!(exact(["aZZb"]), e(r"aZ{2}b")); + assert_eq!(inexact([I("aZZ")], [I("ZZb")]), e(r"aZ{2,3}b")); + + assert_eq!(exact(["abc", ""]), e(r"(abc)?")); + assert_eq!(exact(["", "abc"]), e(r"(abc)??")); + + assert_eq!(inexact([I("a"), E("b")], [I("ab"), E("b")]), e(r"a*b")); + assert_eq!(inexact([E("b"), I("a")], [E("b"), I("ab")]), e(r"a*?b")); + assert_eq!(inexact([I("ab")], [I("b")]), e(r"ab+")); + assert_eq!(inexact([I("a"), I("b")], [I("b")]), e(r"a*b+")); + + // FIXME: The suffixes for this don't look quite right to me. I think + // the right suffixes would be: [I(ac), I(bc), E(c)]. The main issue I + // think is that suffixes are computed by iterating over concatenations + // in reverse, and then [bc, ac, c] ordering is indeed correct from + // that perspective. We also test a few more equivalent regexes, and + // we get the same result, so it is consistent at least I suppose. + // + // The reason why this isn't an issue is that it only messes up + // preference order, and currently, suffixes are never used in a + // context where preference order matters. For prefixes it matters + // because we sometimes want to use prefilters without confirmation + // when all of the literals are exact (and there's no look-around). But + // we never do that for suffixes. Any time we use suffixes, we always + // include a confirmation step. If that ever changes, then it's likely + // this bug will need to be fixed, but last time I looked, it appears + // hard to do so. + assert_eq!( + inexact([I("a"), I("b"), E("c")], [I("bc"), I("ac"), E("c")]), + e(r"a*b*c") + ); + assert_eq!( + inexact([I("a"), I("b"), E("c")], [I("bc"), I("ac"), E("c")]), + e(r"(a+)?(b+)?c") + ); + assert_eq!( + inexact([I("a"), I("b"), E("c")], [I("bc"), I("ac"), E("c")]), + e(r"(a+|)(b+|)c") + ); + // A few more similarish but not identical regexes. These may have a + // similar problem as above. + assert_eq!( + inexact( + [I("a"), I("b"), I("c"), E("")], + [I("c"), I("b"), I("a"), E("")] + ), + e(r"a*b*c*") + ); + assert_eq!(inexact([I("a"), I("b"), I("c")], [I("c")]), e(r"a*b*c+")); + assert_eq!(inexact([I("a"), I("b")], [I("bc")]), e(r"a*b+c")); + assert_eq!(inexact([I("a"), I("b")], [I("c"), I("b")]), e(r"a*b+c*")); + assert_eq!(inexact([I("ab"), E("a")], [I("b"), E("a")]), e(r"ab*")); + assert_eq!( + inexact([I("ab"), E("ac")], [I("bc"), E("ac")]), + e(r"ab*c") + ); + assert_eq!(inexact([I("ab")], [I("b")]), e(r"ab+")); + assert_eq!(inexact([I("ab")], [I("bc")]), e(r"ab+c")); + + assert_eq!( + inexact([I("z"), E("azb")], [I("zazb"), E("azb")]), + e(r"z*azb") + ); + + let expected = + exact(["aaa", "aab", "aba", "abb", "baa", "bab", "bba", "bbb"]); + assert_eq!(expected, e(r"[ab]{3}")); + let expected = inexact( + [ + I("aaa"), + I("aab"), + I("aba"), + I("abb"), + I("baa"), + I("bab"), + I("bba"), + I("bbb"), + ], + [ + I("aaa"), + I("aab"), + I("aba"), + I("abb"), + I("baa"), + I("bab"), + I("bba"), + I("bbb"), + ], + ); + assert_eq!(expected, e(r"[ab]{3,4}")); + } + + #[test] + fn concat() { + let empty: [&str; 0] = []; + + assert_eq!(exact(["abcxyz"]), e(r"abc()xyz")); + assert_eq!(exact(["abcxyz"]), e(r"(abc)(xyz)")); + assert_eq!(exact(["abcmnoxyz"]), e(r"abc()mno()xyz")); + assert_eq!(exact(empty), e(r"abc[a&&b]xyz")); + assert_eq!(exact(["abcxyz"]), e(r"abc[a&&b]*xyz")); + } + + #[test] + fn alternation() { + assert_eq!(exact(["abc", "mno", "xyz"]), e(r"abc|mno|xyz")); + assert_eq!( + inexact( + [E("abc"), I("mZ"), E("mo"), E("xyz")], + [E("abc"), I("Zo"), E("mo"), E("xyz")] + ), + e(r"abc|mZ*o|xyz") + ); + assert_eq!(exact(["abc", "xyz"]), e(r"abc|M[a&&b]N|xyz")); + assert_eq!(exact(["abc", "MN", "xyz"]), e(r"abc|M[a&&b]*N|xyz")); + + assert_eq!(exact(["aaa", "aaaaa"]), e(r"(?:|aa)aaa")); + assert_eq!( + inexact( + [I("aaa"), E(""), I("aaaaa"), E("aa")], + [I("aaa"), E(""), E("aa")] + ), + e(r"(?:|aa)(?:aaa)*") + ); + assert_eq!( + inexact( + [E(""), I("aaa"), E("aa"), I("aaaaa")], + [E(""), I("aaa"), E("aa")] + ), + e(r"(?:|aa)(?:aaa)*?") + ); + + assert_eq!( + inexact([E("a"), I("b"), E("")], [E("a"), I("b"), E("")]), + e(r"a|b*") + ); + assert_eq!(inexact([E("a"), I("b")], [E("a"), I("b")]), e(r"a|b+")); + + assert_eq!( + inexact([I("a"), E("b"), E("c")], [I("ab"), E("b"), E("c")]), + e(r"a*b|c") + ); + + assert_eq!( + inexact( + [E("a"), E("b"), I("c"), E("")], + [E("a"), E("b"), I("c"), E("")] + ), + e(r"a|(?:b|c*)") + ); + + assert_eq!( + inexact( + [I("a"), I("b"), E("c"), I("a"), I("ab"), E("c")], + [I("ac"), I("bc"), E("c"), I("ac"), I("abc"), E("c")], + ), + e(r"(a|b)*c|(a|ab)*c") + ); + + assert_eq!( + exact(["abef", "abgh", "cdef", "cdgh"]), + e(r"(ab|cd)(ef|gh)") + ); + assert_eq!( + exact([ + "abefij", "abefkl", "abghij", "abghkl", "cdefij", "cdefkl", + "cdghij", "cdghkl", + ]), + e(r"(ab|cd)(ef|gh)(ij|kl)") + ); + + assert_eq!(inexact([E("abab")], [E("abab")]), e(r"(ab){2}")); + + assert_eq!(inexact([I("abab")], [I("abab")]), e(r"(ab){2,3}")); + + assert_eq!(inexact([I("abab")], [I("abab")]), e(r"(ab){2,}")); + } + + #[test] + fn impossible() { + let empty: [&str; 0] = []; + + assert_eq!(exact(empty), e(r"[a&&b]")); + assert_eq!(exact(empty), e(r"a[a&&b]")); + assert_eq!(exact(empty), e(r"[a&&b]b")); + assert_eq!(exact(empty), e(r"a[a&&b]b")); + assert_eq!(exact(["a", "b"]), e(r"a|[a&&b]|b")); + assert_eq!(exact(["a", "b"]), e(r"a|c[a&&b]|b")); + assert_eq!(exact(["a", "b"]), e(r"a|[a&&b]d|b")); + assert_eq!(exact(["a", "b"]), e(r"a|c[a&&b]d|b")); + assert_eq!(exact([""]), e(r"[a&&b]*")); + assert_eq!(exact(["MN"]), e(r"M[a&&b]*N")); + } + + // This tests patterns that contain something that defeats literal + // detection, usually because it would blow some limit on the total number + // of literals that can be returned. + // + // The main idea is that when literal extraction sees something that + // it knows will blow a limit, it replaces it with a marker that says + // "any literal will match here." While not necessarily true, the + // over-estimation is just fine for the purposes of literal extraction, + // because the imprecision doesn't matter: too big is too big. + // + // This is one of the trickier parts of literal extraction, since we need + // to make sure all of our literal extraction operations correctly compose + // with the markers. + #[test] + fn anything() { + assert_eq!(infinite(), e(r".")); + assert_eq!(infinite(), e(r"(?s).")); + assert_eq!(infinite(), e(r"[A-Za-z]")); + assert_eq!(infinite(), e(r"[A-Z]")); + assert_eq!(exact([""]), e(r"[A-Z]{0}")); + assert_eq!(infinite(), e(r"[A-Z]?")); + assert_eq!(infinite(), e(r"[A-Z]*")); + assert_eq!(infinite(), e(r"[A-Z]+")); + assert_eq!((seq([I("1")]), Seq::infinite()), e(r"1[A-Z]")); + assert_eq!((seq([I("1")]), seq([I("2")])), e(r"1[A-Z]2")); + assert_eq!((Seq::infinite(), seq([I("123")])), e(r"[A-Z]+123")); + assert_eq!(infinite(), e(r"[A-Z]+123[A-Z]+")); + assert_eq!(infinite(), e(r"1|[A-Z]|3")); + assert_eq!( + (seq([E("1"), I("2"), E("3")]), Seq::infinite()), + e(r"1|2[A-Z]|3"), + ); + assert_eq!( + (Seq::infinite(), seq([E("1"), I("2"), E("3")])), + e(r"1|[A-Z]2|3"), + ); + assert_eq!( + (seq([E("1"), I("2"), E("4")]), seq([E("1"), I("3"), E("4")])), + e(r"1|2[A-Z]3|4"), + ); + assert_eq!((Seq::infinite(), seq([I("2")])), e(r"(?:|1)[A-Z]2")); + assert_eq!(inexact([I("a")], [I("z")]), e(r"a.z")); + } + + // Like the 'anything' test, but it uses smaller limits in order to test + // the logic for effectively aborting literal extraction when the seqs get + // too big. + #[test] + fn anything_small_limits() { + fn prefixes(pattern: &str) -> Seq { + Extractor::new() + .kind(ExtractKind::Prefix) + .limit_total(10) + .extract(&parse(pattern)) + } + + fn suffixes(pattern: &str) -> Seq { + Extractor::new() + .kind(ExtractKind::Suffix) + .limit_total(10) + .extract(&parse(pattern)) + } + + fn e(pattern: &str) -> (Seq, Seq) { + (prefixes(pattern), suffixes(pattern)) + } + + assert_eq!( + ( + seq([ + I("aaa"), + I("aab"), + I("aba"), + I("abb"), + I("baa"), + I("bab"), + I("bba"), + I("bbb") + ]), + seq([ + I("aaa"), + I("aab"), + I("aba"), + I("abb"), + I("baa"), + I("bab"), + I("bba"), + I("bbb") + ]) + ), + e(r"[ab]{3}{3}") + ); + + assert_eq!(infinite(), e(r"ab|cd|ef|gh|ij|kl|mn|op|qr|st|uv|wx|yz")); + } + + #[test] + fn empty() { + assert_eq!(exact([""]), e(r"")); + assert_eq!(exact([""]), e(r"^")); + assert_eq!(exact([""]), e(r"$")); + assert_eq!(exact([""]), e(r"(?m:^)")); + assert_eq!(exact([""]), e(r"(?m:$)")); + assert_eq!(exact([""]), e(r"\b")); + assert_eq!(exact([""]), e(r"\B")); + assert_eq!(exact([""]), e(r"(?-u:\b)")); + assert_eq!(exact([""]), e(r"(?-u:\B)")); + } + + #[test] + fn odds_and_ends() { + assert_eq!((Seq::infinite(), seq([I("a")])), e(r".a")); + assert_eq!((seq([I("a")]), Seq::infinite()), e(r"a.")); + assert_eq!(infinite(), e(r"a|.")); + assert_eq!(infinite(), e(r".|a")); + + let pat = r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]"; + let expected = inexact( + ["Mo'am", "Moam", "Mu'am", "Muam"].map(I), + [ + "ddafi", "ddafy", "dhafi", "dhafy", "dzafi", "dzafy", "dafi", + "dafy", "tdafi", "tdafy", "thafi", "thafy", "tzafi", "tzafy", + "tafi", "tafy", "zdafi", "zdafy", "zhafi", "zhafy", "zzafi", + "zzafy", "zafi", "zafy", + ] + .map(I), + ); + assert_eq!(expected, e(pat)); + + assert_eq!( + (seq(["fn is_", "fn as_"].map(I)), Seq::infinite()), + e(r"fn is_([A-Z]+)|fn as_([A-Z]+)"), + ); + assert_eq!( + inexact([I("foo")], [I("quux")]), + e(r"foo[A-Z]+bar[A-Z]+quux") + ); + assert_eq!(infinite(), e(r"[A-Z]+bar[A-Z]+")); + assert_eq!( + exact(["Sherlock Holmes"]), + e(r"(?m)^Sherlock Holmes|Sherlock Holmes$") + ); + + assert_eq!(exact(["sa", "sb"]), e(r"\bs(?:[ab])")); + } + + // This tests a specific regex along with some heuristic steps to reduce + // the sequences extracted. This is meant to roughly correspond to the + // types of heuristics used to shrink literal sets in practice. (Shrinking + // is done because you want to balance "spend too much work looking for + // too many literals" and "spend too much work processing false positive + // matches from short literals.") + #[test] + #[cfg(feature = "unicode-case")] + fn holmes() { + let expected = inexact( + ["HOL", "HOl", "HoL", "Hol", "hOL", "hOl", "hoL", "hol"].map(I), + [ + "MES", "MEs", "EÅ¿", "MeS", "Mes", "eÅ¿", "mES", "mEs", "meS", + "mes", + ] + .map(I), + ); + let (mut prefixes, mut suffixes) = e(r"(?i)Holmes"); + prefixes.keep_first_bytes(3); + suffixes.keep_last_bytes(3); + prefixes.minimize_by_preference(); + suffixes.minimize_by_preference(); + assert_eq!(expected, (prefixes, suffixes)); + } + + // This tests that we get some kind of literals extracted for a beefier + // alternation with case insensitive mode enabled. At one point during + // development, this returned nothing, and motivated some special case + // code in Extractor::union to try and trim down the literal sequences + // if the union would blow the limits set. + #[test] + #[cfg(feature = "unicode-case")] + fn holmes_alt() { + let mut pre = + prefixes(r"(?i)Sherlock|Holmes|Watson|Irene|Adler|John|Baker"); + assert!(pre.len().unwrap() > 0); + pre.optimize_for_prefix_by_preference(); + assert!(pre.len().unwrap() > 0); + } + + // See: https://github.com/rust-lang/regex/security/advisories/GHSA-m5pq-gvj9-9vr8 + // See: CVE-2022-24713 + // + // We test this here to ensure literal extraction completes in reasonable + // time and isn't materially impacted by these sorts of pathological + // repeats. + #[test] + fn crazy_repeats() { + assert_eq!(inexact([E("")], [E("")]), e(r"(?:){4294967295}")); + assert_eq!( + inexact([E("")], [E("")]), + e(r"(?:){64}{64}{64}{64}{64}{64}") + ); + assert_eq!(inexact([E("")], [E("")]), e(r"x{0}{4294967295}")); + assert_eq!(inexact([E("")], [E("")]), e(r"(?:|){4294967295}")); + + assert_eq!( + inexact([E("")], [E("")]), + e(r"(?:){8}{8}{8}{8}{8}{8}{8}{8}{8}{8}{8}{8}{8}{8}") + ); + let repa = "a".repeat(100); + assert_eq!( + inexact([I(&repa)], [I(&repa)]), + e(r"a{8}{8}{8}{8}{8}{8}{8}{8}{8}{8}{8}{8}{8}{8}") + ); + } + + #[test] + fn huge() { + let pat = r#"(?-u) + 2(?: + [45]\d{3}| + 7(?: + 1[0-267]| + 2[0-289]| + 3[0-29]| + 4[01]| + 5[1-3]| + 6[013]| + 7[0178]| + 91 + )| + 8(?: + 0[125]| + [139][1-6]| + 2[0157-9]| + 41| + 6[1-35]| + 7[1-5]| + 8[1-8]| + 90 + )| + 9(?: + 0[0-2]| + 1[0-4]| + 2[568]| + 3[3-6]| + 5[5-7]| + 6[0167]| + 7[15]| + 8[0146-9] + ) + )\d{4}| + 3(?: + 12?[5-7]\d{2}| + 0(?: + 2(?: + [025-79]\d| + [348]\d{1,2} + )| + 3(?: + [2-4]\d| + [56]\d? + ) + )| + 2(?: + 1\d{2}| + 2(?: + [12]\d| + [35]\d{1,2}| + 4\d? + ) + )| + 3(?: + 1\d{2}| + 2(?: + [2356]\d| + 4\d{1,2} + ) + )| + 4(?: + 1\d{2}| + 2(?: + 2\d{1,2}| + [47]| + 5\d{2} + ) + )| + 5(?: + 1\d{2}| + 29 + )| + [67]1\d{2}| + 8(?: + 1\d{2}| + 2(?: + 2\d{2}| + 3| + 4\d + ) + ) + )\d{3}| + 4(?: + 0(?: + 2(?: + [09]\d| + 7 + )| + 33\d{2} + )| + 1\d{3}| + 2(?: + 1\d{2}| + 2(?: + [25]\d?| + [348]\d| + [67]\d{1,2} + ) + )| + 3(?: + 1\d{2}(?: + \d{2} + )?| + 2(?: + [045]\d| + [236-9]\d{1,2} + )| + 32\d{2} + )| + 4(?: + [18]\d{2}| + 2(?: + [2-46]\d{2}| + 3 + )| + 5[25]\d{2} + )| + 5(?: + 1\d{2}| + 2(?: + 3\d| + 5 + ) + )| + 6(?: + [18]\d{2}| + 2(?: + 3(?: + \d{2} + )?| + [46]\d{1,2}| + 5\d{2}| + 7\d + )| + 5(?: + 3\d?| + 4\d| + [57]\d{1,2}| + 6\d{2}| + 8 + ) + )| + 71\d{2}| + 8(?: + [18]\d{2}| + 23\d{2}| + 54\d{2} + )| + 9(?: + [18]\d{2}| + 2[2-5]\d{2}| + 53\d{1,2} + ) + )\d{3}| + 5(?: + 02[03489]\d{2}| + 1\d{2}| + 2(?: + 1\d{2}| + 2(?: + 2(?: + \d{2} + )?| + [457]\d{2} + ) + )| + 3(?: + 1\d{2}| + 2(?: + [37](?: + \d{2} + )?| + [569]\d{2} + ) + )| + 4(?: + 1\d{2}| + 2[46]\d{2} + )| + 5(?: + 1\d{2}| + 26\d{1,2} + )| + 6(?: + [18]\d{2}| + 2| + 53\d{2} + )| + 7(?: + 1| + 24 + )\d{2}| + 8(?: + 1| + 26 + )\d{2}| + 91\d{2} + )\d{3}| + 6(?: + 0(?: + 1\d{2}| + 2(?: + 3\d{2}| + 4\d{1,2} + ) + )| + 2(?: + 2[2-5]\d{2}| + 5(?: + [3-5]\d{2}| + 7 + )| + 8\d{2} + )| + 3(?: + 1| + 2[3478] + )\d{2}| + 4(?: + 1| + 2[34] + )\d{2}| + 5(?: + 1| + 2[47] + )\d{2}| + 6(?: + [18]\d{2}| + 6(?: + 2(?: + 2\d| + [34]\d{2} + )| + 5(?: + [24]\d{2}| + 3\d| + 5\d{1,2} + ) + ) + )| + 72[2-5]\d{2}| + 8(?: + 1\d{2}| + 2[2-5]\d{2} + )| + 9(?: + 1\d{2}| + 2[2-6]\d{2} + ) + )\d{3}| + 7(?: + (?: + 02| + [3-589]1| + 6[12]| + 72[24] + )\d{2}| + 21\d{3}| + 32 + )\d{3}| + 8(?: + (?: + 4[12]| + [5-7]2| + 1\d? + )| + (?: + 0| + 3[12]| + [5-7]1| + 217 + )\d + )\d{4}| + 9(?: + [35]1| + (?: + [024]2| + 81 + )\d| + (?: + 1| + [24]1 + )\d{2} + )\d{3} + "#; + // TODO: This is a good candidate of a seq of literals that could be + // shrunk quite a bit and still be very productive with respect to + // literal optimizations. + let (prefixes, suffixes) = e(pat); + assert!(!suffixes.is_finite()); + assert_eq!(Some(243), prefixes.len()); + } + + #[test] + fn optimize() { + // This gets a common prefix that isn't too short. + let (p, s) = + opt(["foobarfoobar", "foobar", "foobarzfoobar", "foobarfoobar"]); + assert_eq!(seq([I("foobar")]), p); + assert_eq!(seq([I("foobar")]), s); + + // This also finds a common prefix, but since it's only one byte, it + // prefers the multiple literals. + let (p, s) = opt(["abba", "akka", "abccba"]); + assert_eq!(exact(["abba", "akka", "abccba"]), (p, s)); + + let (p, s) = opt(["sam", "samwise"]); + assert_eq!((seq([E("sam")]), seq([E("sam"), E("samwise")])), (p, s)); + + // The empty string is poisonous, so our seq becomes infinite, even + // though all literals are exact. + let (p, s) = opt(["foobarfoo", "foo", "", "foozfoo", "foofoo"]); + assert!(!p.is_finite()); + assert!(!s.is_finite()); + + // A space is also poisonous, so our seq becomes infinite. But this + // only gets triggered when we don't have a completely exact sequence. + // When the sequence is exact, spaces are okay, since we presume that + // any prefilter will match a space more quickly than the regex engine. + // (When the sequence is exact, there's a chance of the prefilter being + // used without needing the regex engine at all.) + let mut p = seq([E("foobarfoo"), I("foo"), E(" "), E("foofoo")]); + p.optimize_for_prefix_by_preference(); + assert!(!p.is_finite()); + } +} diff --git a/vendor/regex-syntax-0.7.5/src/hir/mod.rs b/vendor/regex-syntax-0.7.5/src/hir/mod.rs new file mode 100644 index 0000000000000..6c1d2745e023a --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/hir/mod.rs @@ -0,0 +1,3784 @@ +/*! +Defines a high-level intermediate (HIR) representation for regular expressions. + +The HIR is represented by the [`Hir`] type, and it principally constructed via +[translation](translate) from an [`Ast`](crate::ast::Ast). Alternatively, users +may use the smart constructors defined on `Hir` to build their own by hand. The +smart constructors simultaneously simplify and "optimize" the HIR, and are also +the same routines used by translation. + +Most regex engines only have an HIR like this, and usually construct it +directly from the concrete syntax. This crate however first parses the +concrete syntax into an `Ast`, and only then creates the HIR from the `Ast`, +as mentioned above. It's done this way to facilitate better error reporting, +and to have a structured representation of a regex that faithfully represents +its concrete syntax. Namely, while an `Hir` value can be converted back to an +equivalent regex pattern string, it is unlikely to look like the original due +to its simplified structure. +*/ + +use core::{char, cmp}; + +use alloc::{ + boxed::Box, + format, + string::{String, ToString}, + vec, + vec::Vec, +}; + +use crate::{ + ast::Span, + hir::interval::{Interval, IntervalSet, IntervalSetIter}, + unicode, +}; + +pub use crate::{ + hir::visitor::{visit, Visitor}, + unicode::CaseFoldError, +}; + +mod interval; +pub mod literal; +pub mod print; +pub mod translate; +mod visitor; + +/// An error that can occur while translating an `Ast` to a `Hir`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Error { + /// The kind of error. + kind: ErrorKind, + /// The original pattern that the translator's Ast was parsed from. Every + /// span in an error is a valid range into this string. + pattern: String, + /// The span of this error, derived from the Ast given to the translator. + span: Span, +} + +impl Error { + /// Return the type of this error. + pub fn kind(&self) -> &ErrorKind { + &self.kind + } + + /// The original pattern string in which this error occurred. + /// + /// Every span reported by this error is reported in terms of this string. + pub fn pattern(&self) -> &str { + &self.pattern + } + + /// Return the span at which this error occurred. + pub fn span(&self) -> &Span { + &self.span + } +} + +/// The type of an error that occurred while building an `Hir`. +/// +/// This error type is marked as `non_exhaustive`. This means that adding a +/// new variant is not considered a breaking change. +#[non_exhaustive] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ErrorKind { + /// This error occurs when a Unicode feature is used when Unicode + /// support is disabled. For example `(?-u:\pL)` would trigger this error. + UnicodeNotAllowed, + /// This error occurs when translating a pattern that could match a byte + /// sequence that isn't UTF-8 and `utf8` was enabled. + InvalidUtf8, + /// This error occurs when one uses a non-ASCII byte for a line terminator, + /// but where Unicode mode is enabled and UTF-8 mode is disabled. + InvalidLineTerminator, + /// This occurs when an unrecognized Unicode property name could not + /// be found. + UnicodePropertyNotFound, + /// This occurs when an unrecognized Unicode property value could not + /// be found. + UnicodePropertyValueNotFound, + /// This occurs when a Unicode-aware Perl character class (`\w`, `\s` or + /// `\d`) could not be found. This can occur when the `unicode-perl` + /// crate feature is not enabled. + UnicodePerlClassNotFound, + /// This occurs when the Unicode simple case mapping tables are not + /// available, and the regular expression required Unicode aware case + /// insensitivity. + UnicodeCaseUnavailable, +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} + +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + crate::error::Formatter::from(self).fmt(f) + } +} + +impl core::fmt::Display for ErrorKind { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use self::ErrorKind::*; + + let msg = match *self { + UnicodeNotAllowed => "Unicode not allowed here", + InvalidUtf8 => "pattern can match invalid UTF-8", + InvalidLineTerminator => "invalid line terminator, must be ASCII", + UnicodePropertyNotFound => "Unicode property not found", + UnicodePropertyValueNotFound => "Unicode property value not found", + UnicodePerlClassNotFound => { + "Unicode-aware Perl class not found \ + (make sure the unicode-perl feature is enabled)" + } + UnicodeCaseUnavailable => { + "Unicode-aware case insensitivity matching is not available \ + (make sure the unicode-case feature is enabled)" + } + }; + f.write_str(msg) + } +} + +/// A high-level intermediate representation (HIR) for a regular expression. +/// +/// An HIR value is a combination of a [`HirKind`] and a set of [`Properties`]. +/// An `HirKind` indicates what kind of regular expression it is (a literal, +/// a repetition, a look-around assertion, etc.), where as a `Properties` +/// describes various facts about the regular expression. For example, whether +/// it matches UTF-8 or if it matches the empty string. +/// +/// The HIR of a regular expression represents an intermediate step between +/// its abstract syntax (a structured description of the concrete syntax) and +/// an actual regex matcher. The purpose of HIR is to make regular expressions +/// easier to analyze. In particular, the AST is much more complex than the +/// HIR. For example, while an AST supports arbitrarily nested character +/// classes, the HIR will flatten all nested classes into a single set. The HIR +/// will also "compile away" every flag present in the concrete syntax. For +/// example, users of HIR expressions never need to worry about case folding; +/// it is handled automatically by the translator (e.g., by translating +/// `(?i:A)` to `[aA]`). +/// +/// The specific type of an HIR expression can be accessed via its `kind` +/// or `into_kind` methods. This extra level of indirection exists for two +/// reasons: +/// +/// 1. Construction of an HIR expression *must* use the constructor methods on +/// this `Hir` type instead of building the `HirKind` values directly. This +/// permits construction to enforce invariants like "concatenations always +/// consist of two or more sub-expressions." +/// 2. Every HIR expression contains attributes that are defined inductively, +/// and can be computed cheaply during the construction process. For example, +/// one such attribute is whether the expression must match at the beginning of +/// the haystack. +/// +/// In particular, if you have an `HirKind` value, then there is intentionally +/// no way to build an `Hir` value from it. You instead need to do case +/// analysis on the `HirKind` value and build the `Hir` value using its smart +/// constructors. +/// +/// # UTF-8 +/// +/// If the HIR was produced by a translator with +/// [`TranslatorBuilder::utf8`](translate::TranslatorBuilder::utf8) enabled, +/// then the HIR is guaranteed to match UTF-8 exclusively for all non-empty +/// matches. +/// +/// For empty matches, those can occur at any position. It is the +/// responsibility of the regex engine to determine whether empty matches are +/// permitted between the code units of a single codepoint. +/// +/// # Stack space +/// +/// This type defines its own destructor that uses constant stack space and +/// heap space proportional to the size of the HIR. +/// +/// Also, an `Hir`'s `fmt::Display` implementation prints an HIR as a regular +/// expression pattern string, and uses constant stack space and heap space +/// proportional to the size of the `Hir`. The regex it prints is guaranteed to +/// be _semantically_ equivalent to the original concrete syntax, but it may +/// look very different. (And potentially not practically readable by a human.) +/// +/// An `Hir`'s `fmt::Debug` implementation currently does not use constant +/// stack space. The implementation will also suppress some details (such as +/// the `Properties` inlined into every `Hir` value to make it less noisy). +#[derive(Clone, Eq, PartialEq)] +pub struct Hir { + /// The underlying HIR kind. + kind: HirKind, + /// Analysis info about this HIR, computed during construction. + props: Properties, +} + +/// Methods for accessing the underlying `HirKind` and `Properties`. +impl Hir { + /// Returns a reference to the underlying HIR kind. + pub fn kind(&self) -> &HirKind { + &self.kind + } + + /// Consumes ownership of this HIR expression and returns its underlying + /// `HirKind`. + pub fn into_kind(mut self) -> HirKind { + core::mem::replace(&mut self.kind, HirKind::Empty) + } + + /// Returns the properties computed for this `Hir`. + pub fn properties(&self) -> &Properties { + &self.props + } + + /// Splits this HIR into its constituent parts. + /// + /// This is useful because `let Hir { kind, props } = hir;` does not work + /// because of `Hir`'s custom `Drop` implementation. + fn into_parts(mut self) -> (HirKind, Properties) { + ( + core::mem::replace(&mut self.kind, HirKind::Empty), + core::mem::replace(&mut self.props, Properties::empty()), + ) + } +} + +/// Smart constructors for HIR values. +/// +/// These constructors are called "smart" because they do inductive work or +/// simplifications. For example, calling `Hir::repetition` with a repetition +/// like `a{0}` will actually return a `Hir` with a `HirKind::Empty` kind +/// since it is equivalent to an empty regex. Another example is calling +/// `Hir::concat(vec![expr])`. Instead of getting a `HirKind::Concat`, you'll +/// just get back the original `expr` since it's precisely equivalent. +/// +/// Smart constructors enable maintaining invariants about the HIR data type +/// while also simulanteously keeping the representation as simple as possible. +impl Hir { + /// Returns an empty HIR expression. + /// + /// An empty HIR expression always matches, including the empty string. + #[inline] + pub fn empty() -> Hir { + let props = Properties::empty(); + Hir { kind: HirKind::Empty, props } + } + + /// Returns an HIR expression that can never match anything. That is, + /// the size of the set of strings in the language described by the HIR + /// returned is `0`. + /// + /// This is distinct from [`Hir::empty`] in that the empty string matches + /// the HIR returned by `Hir::empty`. That is, the set of strings in the + /// language describe described by `Hir::empty` is non-empty. + /// + /// Note that currently, the HIR returned uses an empty character class to + /// indicate that nothing can match. An equivalent expression that cannot + /// match is an empty alternation, but all such "fail" expressions are + /// normalized (via smart constructors) to empty character classes. This is + /// because empty character classes can be spelled in the concrete syntax + /// of a regex (e.g., `\P{any}` or `(?-u:[^\x00-\xFF])` or `[a&&b]`), but + /// empty alternations cannot. + #[inline] + pub fn fail() -> Hir { + let class = Class::Bytes(ClassBytes::empty()); + let props = Properties::class(&class); + // We can't just call Hir::class here because it defers to Hir::fail + // in order to canonicalize the Hir value used to represent "cannot + // match." + Hir { kind: HirKind::Class(class), props } + } + + /// Creates a literal HIR expression. + /// + /// This accepts anything that can be converted into a `Box<[u8]>`. + /// + /// Note that there is no mechanism for storing a `char` or a `Box` + /// in an HIR. Everything is "just bytes." Whether a `Literal` (or + /// any HIR node) matches valid UTF-8 exclusively can be queried via + /// [`Properties::is_utf8`]. + /// + /// # Example + /// + /// This example shows that concatenations of `Literal` HIR values will + /// automatically get flattened and combined together. So for example, even + /// if you concat multiple `Literal` values that are themselves not valid + /// UTF-8, they might add up to valid UTF-8. This also demonstrates just + /// how "smart" Hir's smart constructors are. + /// + /// ``` + /// use regex_syntax::hir::{Hir, HirKind, Literal}; + /// + /// let literals = vec![ + /// Hir::literal([0xE2]), + /// Hir::literal([0x98]), + /// Hir::literal([0x83]), + /// ]; + /// // Each literal, on its own, is invalid UTF-8. + /// assert!(literals.iter().all(|hir| !hir.properties().is_utf8())); + /// + /// let concat = Hir::concat(literals); + /// // But the concatenation is valid UTF-8! + /// assert!(concat.properties().is_utf8()); + /// + /// // And also notice that the literals have been concatenated into a + /// // single `Literal`, to the point where there is no explicit `Concat`! + /// let expected = HirKind::Literal(Literal(Box::from("☃".as_bytes()))); + /// assert_eq!(&expected, concat.kind()); + /// ``` + #[inline] + pub fn literal>>(lit: B) -> Hir { + let bytes = lit.into(); + if bytes.is_empty() { + return Hir::empty(); + } + + let lit = Literal(bytes); + let props = Properties::literal(&lit); + Hir { kind: HirKind::Literal(lit), props } + } + + /// Creates a class HIR expression. The class may either be defined over + /// ranges of Unicode codepoints or ranges of raw byte values. + /// + /// Note that an empty class is permitted. An empty class is equivalent to + /// `Hir::fail()`. + #[inline] + pub fn class(class: Class) -> Hir { + if class.is_empty() { + return Hir::fail(); + } else if let Some(bytes) = class.literal() { + return Hir::literal(bytes); + } + let props = Properties::class(&class); + Hir { kind: HirKind::Class(class), props } + } + + /// Creates a look-around assertion HIR expression. + #[inline] + pub fn look(look: Look) -> Hir { + let props = Properties::look(look); + Hir { kind: HirKind::Look(look), props } + } + + /// Creates a repetition HIR expression. + #[inline] + pub fn repetition(mut rep: Repetition) -> Hir { + // If the sub-expression of a repetition can only match the empty + // string, then we force its maximum to be at most 1. + if rep.sub.properties().maximum_len() == Some(0) { + rep.min = cmp::min(rep.min, 1); + rep.max = rep.max.map(|n| cmp::min(n, 1)).or(Some(1)); + } + // The regex 'a{0}' is always equivalent to the empty regex. This is + // true even when 'a' is an expression that never matches anything + // (like '\P{any}'). + // + // Additionally, the regex 'a{1}' is always equivalent to 'a'. + if rep.min == 0 && rep.max == Some(0) { + return Hir::empty(); + } else if rep.min == 1 && rep.max == Some(1) { + return *rep.sub; + } + let props = Properties::repetition(&rep); + Hir { kind: HirKind::Repetition(rep), props } + } + + /// Creates a capture HIR expression. + /// + /// Note that there is no explicit HIR value for a non-capturing group. + /// Since a non-capturing group only exists to override precedence in the + /// concrete syntax and since an HIR already does its own grouping based on + /// what is parsed, there is no need to explicitly represent non-capturing + /// groups in the HIR. + #[inline] + pub fn capture(capture: Capture) -> Hir { + let props = Properties::capture(&capture); + Hir { kind: HirKind::Capture(capture), props } + } + + /// Returns the concatenation of the given expressions. + /// + /// This attempts to flatten and simplify the concatenation as appropriate. + /// + /// # Example + /// + /// This shows a simple example of basic flattening of both concatenations + /// and literals. + /// + /// ``` + /// use regex_syntax::hir::Hir; + /// + /// let hir = Hir::concat(vec![ + /// Hir::concat(vec![ + /// Hir::literal([b'a']), + /// Hir::literal([b'b']), + /// Hir::literal([b'c']), + /// ]), + /// Hir::concat(vec![ + /// Hir::literal([b'x']), + /// Hir::literal([b'y']), + /// Hir::literal([b'z']), + /// ]), + /// ]); + /// let expected = Hir::literal("abcxyz".as_bytes()); + /// assert_eq!(expected, hir); + /// ``` + pub fn concat(subs: Vec) -> Hir { + // We rebuild the concatenation by simplifying it. Would be nice to do + // it in place, but that seems a little tricky? + let mut new = vec![]; + // This gobbles up any adjacent literals in a concatenation and smushes + // them together. Basically, when we see a literal, we add its bytes + // to 'prior_lit', and whenever we see anything else, we first take + // any bytes in 'prior_lit' and add it to the 'new' concatenation. + let mut prior_lit: Option> = None; + for sub in subs { + let (kind, props) = sub.into_parts(); + match kind { + HirKind::Literal(Literal(bytes)) => { + if let Some(ref mut prior_bytes) = prior_lit { + prior_bytes.extend_from_slice(&bytes); + } else { + prior_lit = Some(bytes.to_vec()); + } + } + // We also flatten concats that are direct children of another + // concat. We only need to do this one level deep since + // Hir::concat is the only way to build concatenations, and so + // flattening happens inductively. + HirKind::Concat(subs2) => { + for sub2 in subs2 { + let (kind2, props2) = sub2.into_parts(); + match kind2 { + HirKind::Literal(Literal(bytes)) => { + if let Some(ref mut prior_bytes) = prior_lit { + prior_bytes.extend_from_slice(&bytes); + } else { + prior_lit = Some(bytes.to_vec()); + } + } + kind2 => { + if let Some(prior_bytes) = prior_lit.take() { + new.push(Hir::literal(prior_bytes)); + } + new.push(Hir { kind: kind2, props: props2 }); + } + } + } + } + // We can just skip empty HIRs. + HirKind::Empty => {} + kind => { + if let Some(prior_bytes) = prior_lit.take() { + new.push(Hir::literal(prior_bytes)); + } + new.push(Hir { kind, props }); + } + } + } + if let Some(prior_bytes) = prior_lit.take() { + new.push(Hir::literal(prior_bytes)); + } + if new.is_empty() { + return Hir::empty(); + } else if new.len() == 1 { + return new.pop().unwrap(); + } + let props = Properties::concat(&new); + Hir { kind: HirKind::Concat(new), props } + } + + /// Returns the alternation of the given expressions. + /// + /// This flattens and simplifies the alternation as appropriate. This may + /// include factoring out common prefixes or even rewriting the alternation + /// as a character class. + /// + /// Note that an empty alternation is equivalent to `Hir::fail()`. (It + /// is not possible for one to write an empty alternation, or even an + /// alternation with a single sub-expression, in the concrete syntax of a + /// regex.) + /// + /// # Example + /// + /// This is a simple example showing how an alternation might get + /// simplified. + /// + /// ``` + /// use regex_syntax::hir::{Hir, Class, ClassUnicode, ClassUnicodeRange}; + /// + /// let hir = Hir::alternation(vec![ + /// Hir::literal([b'a']), + /// Hir::literal([b'b']), + /// Hir::literal([b'c']), + /// Hir::literal([b'd']), + /// Hir::literal([b'e']), + /// Hir::literal([b'f']), + /// ]); + /// let expected = Hir::class(Class::Unicode(ClassUnicode::new([ + /// ClassUnicodeRange::new('a', 'f'), + /// ]))); + /// assert_eq!(expected, hir); + /// ``` + /// + /// And another example showing how common prefixes might get factored + /// out. + /// + /// ``` + /// use regex_syntax::hir::{Hir, Class, ClassUnicode, ClassUnicodeRange}; + /// + /// let hir = Hir::alternation(vec![ + /// Hir::concat(vec![ + /// Hir::literal("abc".as_bytes()), + /// Hir::class(Class::Unicode(ClassUnicode::new([ + /// ClassUnicodeRange::new('A', 'Z'), + /// ]))), + /// ]), + /// Hir::concat(vec![ + /// Hir::literal("abc".as_bytes()), + /// Hir::class(Class::Unicode(ClassUnicode::new([ + /// ClassUnicodeRange::new('a', 'z'), + /// ]))), + /// ]), + /// ]); + /// let expected = Hir::concat(vec![ + /// Hir::literal("abc".as_bytes()), + /// Hir::alternation(vec![ + /// Hir::class(Class::Unicode(ClassUnicode::new([ + /// ClassUnicodeRange::new('A', 'Z'), + /// ]))), + /// Hir::class(Class::Unicode(ClassUnicode::new([ + /// ClassUnicodeRange::new('a', 'z'), + /// ]))), + /// ]), + /// ]); + /// assert_eq!(expected, hir); + /// ``` + /// + /// Note that these sorts of simplifications are not guaranteed. + pub fn alternation(subs: Vec) -> Hir { + // We rebuild the alternation by simplifying it. We proceed similarly + // as the concatenation case. But in this case, there's no literal + // simplification happening. We're just flattening alternations. + let mut new = Vec::with_capacity(subs.len()); + for sub in subs { + let (kind, props) = sub.into_parts(); + match kind { + HirKind::Alternation(subs2) => { + new.extend(subs2); + } + kind => { + new.push(Hir { kind, props }); + } + } + } + if new.is_empty() { + return Hir::fail(); + } else if new.len() == 1 { + return new.pop().unwrap(); + } + // Now that it's completely flattened, look for the special case of + // 'char1|char2|...|charN' and collapse that into a class. Note that + // we look for 'char' first and then bytes. The issue here is that if + // we find both non-ASCII codepoints and non-ASCII singleton bytes, + // then it isn't actually possible to smush them into a single class. + // (Because classes are either "all codepoints" or "all bytes." You + // can have a class that both matches non-ASCII but valid UTF-8 and + // invalid UTF-8.) So we look for all chars and then all bytes, and + // don't handle anything else. + if let Some(singletons) = singleton_chars(&new) { + let it = singletons + .into_iter() + .map(|ch| ClassUnicodeRange { start: ch, end: ch }); + return Hir::class(Class::Unicode(ClassUnicode::new(it))); + } + if let Some(singletons) = singleton_bytes(&new) { + let it = singletons + .into_iter() + .map(|b| ClassBytesRange { start: b, end: b }); + return Hir::class(Class::Bytes(ClassBytes::new(it))); + } + // Similar to singleton chars, we can also look for alternations of + // classes. Those can be smushed into a single class. + if let Some(cls) = class_chars(&new) { + return Hir::class(cls); + } + if let Some(cls) = class_bytes(&new) { + return Hir::class(cls); + } + // Factor out a common prefix if we can, which might potentially + // simplify the expression and unlock other optimizations downstream. + // It also might generally make NFA matching and DFA construction + // faster by reducing the scope of branching in the regex. + new = match lift_common_prefix(new) { + Ok(hir) => return hir, + Err(unchanged) => unchanged, + }; + let props = Properties::alternation(&new); + Hir { kind: HirKind::Alternation(new), props } + } + + /// Returns an HIR expression for `.`. + /// + /// * [`Dot::AnyChar`] maps to `(?su-R:.)`. + /// * [`Dot::AnyByte`] maps to `(?s-Ru:.)`. + /// * [`Dot::AnyCharExceptLF`] maps to `(?u-Rs:.)`. + /// * [`Dot::AnyCharExceptCRLF`] maps to `(?Ru-s:.)`. + /// * [`Dot::AnyByteExceptLF`] maps to `(?-Rsu:.)`. + /// * [`Dot::AnyByteExceptCRLF`] maps to `(?R-su:.)`. + /// + /// # Example + /// + /// Note that this is a convenience routine for constructing the correct + /// character class based on the value of `Dot`. There is no explicit "dot" + /// HIR value. It is just an abbreviation for a common character class. + /// + /// ``` + /// use regex_syntax::hir::{Hir, Dot, Class, ClassBytes, ClassBytesRange}; + /// + /// let hir = Hir::dot(Dot::AnyByte); + /// let expected = Hir::class(Class::Bytes(ClassBytes::new([ + /// ClassBytesRange::new(0x00, 0xFF), + /// ]))); + /// assert_eq!(expected, hir); + /// ``` + #[inline] + pub fn dot(dot: Dot) -> Hir { + match dot { + Dot::AnyChar => { + let mut cls = ClassUnicode::empty(); + cls.push(ClassUnicodeRange::new('\0', '\u{10FFFF}')); + Hir::class(Class::Unicode(cls)) + } + Dot::AnyByte => { + let mut cls = ClassBytes::empty(); + cls.push(ClassBytesRange::new(b'\0', b'\xFF')); + Hir::class(Class::Bytes(cls)) + } + Dot::AnyCharExcept(ch) => { + let mut cls = + ClassUnicode::new([ClassUnicodeRange::new(ch, ch)]); + cls.negate(); + Hir::class(Class::Unicode(cls)) + } + Dot::AnyCharExceptLF => { + let mut cls = ClassUnicode::empty(); + cls.push(ClassUnicodeRange::new('\0', '\x09')); + cls.push(ClassUnicodeRange::new('\x0B', '\u{10FFFF}')); + Hir::class(Class::Unicode(cls)) + } + Dot::AnyCharExceptCRLF => { + let mut cls = ClassUnicode::empty(); + cls.push(ClassUnicodeRange::new('\0', '\x09')); + cls.push(ClassUnicodeRange::new('\x0B', '\x0C')); + cls.push(ClassUnicodeRange::new('\x0E', '\u{10FFFF}')); + Hir::class(Class::Unicode(cls)) + } + Dot::AnyByteExcept(byte) => { + let mut cls = + ClassBytes::new([ClassBytesRange::new(byte, byte)]); + cls.negate(); + Hir::class(Class::Bytes(cls)) + } + Dot::AnyByteExceptLF => { + let mut cls = ClassBytes::empty(); + cls.push(ClassBytesRange::new(b'\0', b'\x09')); + cls.push(ClassBytesRange::new(b'\x0B', b'\xFF')); + Hir::class(Class::Bytes(cls)) + } + Dot::AnyByteExceptCRLF => { + let mut cls = ClassBytes::empty(); + cls.push(ClassBytesRange::new(b'\0', b'\x09')); + cls.push(ClassBytesRange::new(b'\x0B', b'\x0C')); + cls.push(ClassBytesRange::new(b'\x0E', b'\xFF')); + Hir::class(Class::Bytes(cls)) + } + } + } +} + +/// The underlying kind of an arbitrary [`Hir`] expression. +/// +/// An `HirKind` is principally useful for doing case analysis on the type +/// of a regular expression. If you're looking to build new `Hir` values, +/// then you _must_ use the smart constructors defined on `Hir`, like +/// [`Hir::repetition`], to build new `Hir` values. The API intentionally does +/// not expose any way of building an `Hir` directly from an `HirKind`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum HirKind { + /// The empty regular expression, which matches everything, including the + /// empty string. + Empty, + /// A literalstring that matches exactly these bytes. + Literal(Literal), + /// A single character class that matches any of the characters in the + /// class. A class can either consist of Unicode scalar values as + /// characters, or it can use bytes. + /// + /// A class may be empty. In which case, it matches nothing. + Class(Class), + /// A look-around assertion. A look-around match always has zero length. + Look(Look), + /// A repetition operation applied to a sub-expression. + Repetition(Repetition), + /// A capturing group, which contains a sub-expression. + Capture(Capture), + /// A concatenation of expressions. + /// + /// A concatenation matches only if each of its sub-expressions match one + /// after the other. + /// + /// Concatenations are guaranteed by `Hir`'s smart constructors to always + /// have at least two sub-expressions. + Concat(Vec), + /// An alternation of expressions. + /// + /// An alternation matches only if at least one of its sub-expressions + /// match. If multiple sub-expressions match, then the leftmost is + /// preferred. + /// + /// Alternations are guaranteed by `Hir`'s smart constructors to always + /// have at least two sub-expressions. + Alternation(Vec), +} + +impl HirKind { + /// Returns a slice of this kind's sub-expressions, if any. + pub fn subs(&self) -> &[Hir] { + use core::slice::from_ref; + + match *self { + HirKind::Empty + | HirKind::Literal(_) + | HirKind::Class(_) + | HirKind::Look(_) => &[], + HirKind::Repetition(Repetition { ref sub, .. }) => from_ref(sub), + HirKind::Capture(Capture { ref sub, .. }) => from_ref(sub), + HirKind::Concat(ref subs) => subs, + HirKind::Alternation(ref subs) => subs, + } + } +} + +impl core::fmt::Debug for Hir { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.kind.fmt(f) + } +} + +/// Print a display representation of this Hir. +/// +/// The result of this is a valid regular expression pattern string. +/// +/// This implementation uses constant stack space and heap space proportional +/// to the size of the `Hir`. +impl core::fmt::Display for Hir { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + crate::hir::print::Printer::new().print(self, f) + } +} + +/// The high-level intermediate representation of a literal. +/// +/// A literal corresponds to `0` or more bytes that should be matched +/// literally. The smart constructors defined on `Hir` will automatically +/// concatenate adjacent literals into one literal, and will even automatically +/// replace empty literals with `Hir::empty()`. +/// +/// Note that despite a literal being represented by a sequence of bytes, its +/// `Debug` implementation will attempt to print it as a normal string. (That +/// is, not a sequence of decimal numbers.) +#[derive(Clone, Eq, PartialEq)] +pub struct Literal(pub Box<[u8]>); + +impl core::fmt::Debug for Literal { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + crate::debug::Bytes(&self.0).fmt(f) + } +} + +/// The high-level intermediate representation of a character class. +/// +/// A character class corresponds to a set of characters. A character is either +/// defined by a Unicode scalar value or a byte. Unicode characters are used +/// by default, while bytes are used when Unicode mode (via the `u` flag) is +/// disabled. +/// +/// A character class, regardless of its character type, is represented by a +/// sequence of non-overlapping non-adjacent ranges of characters. +/// +/// Note that `Bytes` variant may be produced even when it exclusively matches +/// valid UTF-8. This is because a `Bytes` variant represents an intention by +/// the author of the regular expression to disable Unicode mode, which in turn +/// impacts the semantics of case insensitive matching. For example, `(?i)k` +/// and `(?i-u)k` will not match the same set of strings. +#[derive(Clone, Eq, PartialEq)] +pub enum Class { + /// A set of characters represented by Unicode scalar values. + Unicode(ClassUnicode), + /// A set of characters represented by arbitrary bytes (one byte per + /// character). + Bytes(ClassBytes), +} + +impl Class { + /// Apply Unicode simple case folding to this character class, in place. + /// The character class will be expanded to include all simple case folded + /// character variants. + /// + /// If this is a byte oriented character class, then this will be limited + /// to the ASCII ranges `A-Z` and `a-z`. + /// + /// # Panics + /// + /// This routine panics when the case mapping data necessary for this + /// routine to complete is unavailable. This occurs when the `unicode-case` + /// feature is not enabled and the underlying class is Unicode oriented. + /// + /// Callers should prefer using `try_case_fold_simple` instead, which will + /// return an error instead of panicking. + pub fn case_fold_simple(&mut self) { + match *self { + Class::Unicode(ref mut x) => x.case_fold_simple(), + Class::Bytes(ref mut x) => x.case_fold_simple(), + } + } + + /// Apply Unicode simple case folding to this character class, in place. + /// The character class will be expanded to include all simple case folded + /// character variants. + /// + /// If this is a byte oriented character class, then this will be limited + /// to the ASCII ranges `A-Z` and `a-z`. + /// + /// # Error + /// + /// This routine returns an error when the case mapping data necessary + /// for this routine to complete is unavailable. This occurs when the + /// `unicode-case` feature is not enabled and the underlying class is + /// Unicode oriented. + pub fn try_case_fold_simple( + &mut self, + ) -> core::result::Result<(), CaseFoldError> { + match *self { + Class::Unicode(ref mut x) => x.try_case_fold_simple()?, + Class::Bytes(ref mut x) => x.case_fold_simple(), + } + Ok(()) + } + + /// Negate this character class in place. + /// + /// After completion, this character class will contain precisely the + /// characters that weren't previously in the class. + pub fn negate(&mut self) { + match *self { + Class::Unicode(ref mut x) => x.negate(), + Class::Bytes(ref mut x) => x.negate(), + } + } + + /// Returns true if and only if this character class will only ever match + /// valid UTF-8. + /// + /// A character class can match invalid UTF-8 only when the following + /// conditions are met: + /// + /// 1. The translator was configured to permit generating an expression + /// that can match invalid UTF-8. (By default, this is disabled.) + /// 2. Unicode mode (via the `u` flag) was disabled either in the concrete + /// syntax or in the parser builder. By default, Unicode mode is + /// enabled. + pub fn is_utf8(&self) -> bool { + match *self { + Class::Unicode(_) => true, + Class::Bytes(ref x) => x.is_ascii(), + } + } + + /// Returns the length, in bytes, of the smallest string matched by this + /// character class. + /// + /// For non-empty byte oriented classes, this always returns `1`. For + /// non-empty Unicode oriented classes, this can return `1`, `2`, `3` or + /// `4`. For empty classes, `None` is returned. It is impossible for `0` to + /// be returned. + /// + /// # Example + /// + /// This example shows some examples of regexes and their corresponding + /// minimum length, if any. + /// + /// ``` + /// use regex_syntax::{hir::Properties, parse}; + /// + /// // The empty string has a min length of 0. + /// let hir = parse(r"")?; + /// assert_eq!(Some(0), hir.properties().minimum_len()); + /// // As do other types of regexes that only match the empty string. + /// let hir = parse(r"^$\b\B")?; + /// assert_eq!(Some(0), hir.properties().minimum_len()); + /// // A regex that can match the empty string but match more is still 0. + /// let hir = parse(r"a*")?; + /// assert_eq!(Some(0), hir.properties().minimum_len()); + /// // A regex that matches nothing has no minimum defined. + /// let hir = parse(r"[a&&b]")?; + /// assert_eq!(None, hir.properties().minimum_len()); + /// // Character classes usually have a minimum length of 1. + /// let hir = parse(r"\w")?; + /// assert_eq!(Some(1), hir.properties().minimum_len()); + /// // But sometimes Unicode classes might be bigger! + /// let hir = parse(r"\p{Cyrillic}")?; + /// assert_eq!(Some(2), hir.properties().minimum_len()); + /// + /// # Ok::<(), Box>(()) + /// ``` + pub fn minimum_len(&self) -> Option { + match *self { + Class::Unicode(ref x) => x.minimum_len(), + Class::Bytes(ref x) => x.minimum_len(), + } + } + + /// Returns the length, in bytes, of the longest string matched by this + /// character class. + /// + /// For non-empty byte oriented classes, this always returns `1`. For + /// non-empty Unicode oriented classes, this can return `1`, `2`, `3` or + /// `4`. For empty classes, `None` is returned. It is impossible for `0` to + /// be returned. + /// + /// # Example + /// + /// This example shows some examples of regexes and their corresponding + /// maximum length, if any. + /// + /// ``` + /// use regex_syntax::{hir::Properties, parse}; + /// + /// // The empty string has a max length of 0. + /// let hir = parse(r"")?; + /// assert_eq!(Some(0), hir.properties().maximum_len()); + /// // As do other types of regexes that only match the empty string. + /// let hir = parse(r"^$\b\B")?; + /// assert_eq!(Some(0), hir.properties().maximum_len()); + /// // A regex that matches nothing has no maximum defined. + /// let hir = parse(r"[a&&b]")?; + /// assert_eq!(None, hir.properties().maximum_len()); + /// // Bounded repeats work as you expect. + /// let hir = parse(r"x{2,10}")?; + /// assert_eq!(Some(10), hir.properties().maximum_len()); + /// // An unbounded repeat means there is no maximum. + /// let hir = parse(r"x{2,}")?; + /// assert_eq!(None, hir.properties().maximum_len()); + /// // With Unicode enabled, \w can match up to 4 bytes! + /// let hir = parse(r"\w")?; + /// assert_eq!(Some(4), hir.properties().maximum_len()); + /// // Without Unicode enabled, \w matches at most 1 byte. + /// let hir = parse(r"(?-u)\w")?; + /// assert_eq!(Some(1), hir.properties().maximum_len()); + /// + /// # Ok::<(), Box>(()) + /// ``` + pub fn maximum_len(&self) -> Option { + match *self { + Class::Unicode(ref x) => x.maximum_len(), + Class::Bytes(ref x) => x.maximum_len(), + } + } + + /// Returns true if and only if this character class is empty. That is, + /// it has no elements. + /// + /// An empty character can never match anything, including an empty string. + pub fn is_empty(&self) -> bool { + match *self { + Class::Unicode(ref x) => x.ranges().is_empty(), + Class::Bytes(ref x) => x.ranges().is_empty(), + } + } + + /// If this class consists of exactly one element (whether a codepoint or a + /// byte), then return it as a literal byte string. + /// + /// If this class is empty or contains more than one element, then `None` + /// is returned. + pub fn literal(&self) -> Option> { + match *self { + Class::Unicode(ref x) => x.literal(), + Class::Bytes(ref x) => x.literal(), + } + } +} + +impl core::fmt::Debug for Class { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + use crate::debug::Byte; + + let mut fmter = f.debug_set(); + match *self { + Class::Unicode(ref cls) => { + for r in cls.ranges().iter() { + fmter.entry(&(r.start..=r.end)); + } + } + Class::Bytes(ref cls) => { + for r in cls.ranges().iter() { + fmter.entry(&(Byte(r.start)..=Byte(r.end))); + } + } + } + fmter.finish() + } +} + +/// A set of characters represented by Unicode scalar values. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ClassUnicode { + set: IntervalSet, +} + +impl ClassUnicode { + /// Create a new class from a sequence of ranges. + /// + /// The given ranges do not need to be in any specific order, and ranges + /// may overlap. Ranges will automatically be sorted into a canonical + /// non-overlapping order. + pub fn new(ranges: I) -> ClassUnicode + where + I: IntoIterator, + { + ClassUnicode { set: IntervalSet::new(ranges) } + } + + /// Create a new class with no ranges. + /// + /// An empty class matches nothing. That is, it is equivalent to + /// [`Hir::fail`]. + pub fn empty() -> ClassUnicode { + ClassUnicode::new(vec![]) + } + + /// Add a new range to this set. + pub fn push(&mut self, range: ClassUnicodeRange) { + self.set.push(range); + } + + /// Return an iterator over all ranges in this class. + /// + /// The iterator yields ranges in ascending order. + pub fn iter(&self) -> ClassUnicodeIter<'_> { + ClassUnicodeIter(self.set.iter()) + } + + /// Return the underlying ranges as a slice. + pub fn ranges(&self) -> &[ClassUnicodeRange] { + self.set.intervals() + } + + /// Expand this character class such that it contains all case folded + /// characters, according to Unicode's "simple" mapping. For example, if + /// this class consists of the range `a-z`, then applying case folding will + /// result in the class containing both the ranges `a-z` and `A-Z`. + /// + /// # Panics + /// + /// This routine panics when the case mapping data necessary for this + /// routine to complete is unavailable. This occurs when the `unicode-case` + /// feature is not enabled. + /// + /// Callers should prefer using `try_case_fold_simple` instead, which will + /// return an error instead of panicking. + pub fn case_fold_simple(&mut self) { + self.set + .case_fold_simple() + .expect("unicode-case feature must be enabled"); + } + + /// Expand this character class such that it contains all case folded + /// characters, according to Unicode's "simple" mapping. For example, if + /// this class consists of the range `a-z`, then applying case folding will + /// result in the class containing both the ranges `a-z` and `A-Z`. + /// + /// # Error + /// + /// This routine returns an error when the case mapping data necessary + /// for this routine to complete is unavailable. This occurs when the + /// `unicode-case` feature is not enabled. + pub fn try_case_fold_simple( + &mut self, + ) -> core::result::Result<(), CaseFoldError> { + self.set.case_fold_simple() + } + + /// Negate this character class. + /// + /// For all `c` where `c` is a Unicode scalar value, if `c` was in this + /// set, then it will not be in this set after negation. + pub fn negate(&mut self) { + self.set.negate(); + } + + /// Union this character class with the given character class, in place. + pub fn union(&mut self, other: &ClassUnicode) { + self.set.union(&other.set); + } + + /// Intersect this character class with the given character class, in + /// place. + pub fn intersect(&mut self, other: &ClassUnicode) { + self.set.intersect(&other.set); + } + + /// Subtract the given character class from this character class, in place. + pub fn difference(&mut self, other: &ClassUnicode) { + self.set.difference(&other.set); + } + + /// Compute the symmetric difference of the given character classes, in + /// place. + /// + /// This computes the symmetric difference of two character classes. This + /// removes all elements in this class that are also in the given class, + /// but all adds all elements from the given class that aren't in this + /// class. That is, the class will contain all elements in either class, + /// but will not contain any elements that are in both classes. + pub fn symmetric_difference(&mut self, other: &ClassUnicode) { + self.set.symmetric_difference(&other.set); + } + + /// Returns true if and only if this character class will either match + /// nothing or only ASCII bytes. Stated differently, this returns false + /// if and only if this class contains a non-ASCII codepoint. + pub fn is_ascii(&self) -> bool { + self.set.intervals().last().map_or(true, |r| r.end <= '\x7F') + } + + /// Returns the length, in bytes, of the smallest string matched by this + /// character class. + /// + /// Returns `None` when the class is empty. + pub fn minimum_len(&self) -> Option { + let first = self.ranges().get(0)?; + // Correct because c1 < c2 implies c1.len_utf8() < c2.len_utf8(). + Some(first.start.len_utf8()) + } + + /// Returns the length, in bytes, of the longest string matched by this + /// character class. + /// + /// Returns `None` when the class is empty. + pub fn maximum_len(&self) -> Option { + let last = self.ranges().last()?; + // Correct because c1 < c2 implies c1.len_utf8() < c2.len_utf8(). + Some(last.end.len_utf8()) + } + + /// If this class consists of exactly one codepoint, then return it as + /// a literal byte string. + /// + /// If this class is empty or contains more than one codepoint, then `None` + /// is returned. + pub fn literal(&self) -> Option> { + let rs = self.ranges(); + if rs.len() == 1 && rs[0].start == rs[0].end { + Some(rs[0].start.encode_utf8(&mut [0; 4]).to_string().into_bytes()) + } else { + None + } + } + + /// If this class consists of only ASCII ranges, then return its + /// corresponding and equivalent byte class. + pub fn to_byte_class(&self) -> Option { + if !self.is_ascii() { + return None; + } + Some(ClassBytes::new(self.ranges().iter().map(|r| { + // Since we are guaranteed that our codepoint range is ASCII, the + // 'u8::try_from' calls below are guaranteed to be correct. + ClassBytesRange { + start: u8::try_from(r.start).unwrap(), + end: u8::try_from(r.end).unwrap(), + } + }))) + } +} + +/// An iterator over all ranges in a Unicode character class. +/// +/// The lifetime `'a` refers to the lifetime of the underlying class. +#[derive(Debug)] +pub struct ClassUnicodeIter<'a>(IntervalSetIter<'a, ClassUnicodeRange>); + +impl<'a> Iterator for ClassUnicodeIter<'a> { + type Item = &'a ClassUnicodeRange; + + fn next(&mut self) -> Option<&'a ClassUnicodeRange> { + self.0.next() + } +} + +/// A single range of characters represented by Unicode scalar values. +/// +/// The range is closed. That is, the start and end of the range are included +/// in the range. +#[derive(Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct ClassUnicodeRange { + start: char, + end: char, +} + +impl core::fmt::Debug for ClassUnicodeRange { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let start = if !self.start.is_whitespace() && !self.start.is_control() + { + self.start.to_string() + } else { + format!("0x{:X}", u32::from(self.start)) + }; + let end = if !self.end.is_whitespace() && !self.end.is_control() { + self.end.to_string() + } else { + format!("0x{:X}", u32::from(self.end)) + }; + f.debug_struct("ClassUnicodeRange") + .field("start", &start) + .field("end", &end) + .finish() + } +} + +impl Interval for ClassUnicodeRange { + type Bound = char; + + #[inline] + fn lower(&self) -> char { + self.start + } + #[inline] + fn upper(&self) -> char { + self.end + } + #[inline] + fn set_lower(&mut self, bound: char) { + self.start = bound; + } + #[inline] + fn set_upper(&mut self, bound: char) { + self.end = bound; + } + + /// Apply simple case folding to this Unicode scalar value range. + /// + /// Additional ranges are appended to the given vector. Canonical ordering + /// is *not* maintained in the given vector. + fn case_fold_simple( + &self, + ranges: &mut Vec, + ) -> Result<(), unicode::CaseFoldError> { + let mut folder = unicode::SimpleCaseFolder::new()?; + if !folder.overlaps(self.start, self.end) { + return Ok(()); + } + let (start, end) = (u32::from(self.start), u32::from(self.end)); + for cp in (start..=end).filter_map(char::from_u32) { + for &cp_folded in folder.mapping(cp) { + ranges.push(ClassUnicodeRange::new(cp_folded, cp_folded)); + } + } + Ok(()) + } +} + +impl ClassUnicodeRange { + /// Create a new Unicode scalar value range for a character class. + /// + /// The returned range is always in a canonical form. That is, the range + /// returned always satisfies the invariant that `start <= end`. + pub fn new(start: char, end: char) -> ClassUnicodeRange { + ClassUnicodeRange::create(start, end) + } + + /// Return the start of this range. + /// + /// The start of a range is always less than or equal to the end of the + /// range. + pub fn start(&self) -> char { + self.start + } + + /// Return the end of this range. + /// + /// The end of a range is always greater than or equal to the start of the + /// range. + pub fn end(&self) -> char { + self.end + } + + /// Returns the number of codepoints in this range. + pub fn len(&self) -> usize { + let diff = 1 + u32::from(self.end) - u32::from(self.start); + // This is likely to panic in 16-bit targets since a usize can only fit + // 2^16. It's not clear what to do here, other than to return an error + // when building a Unicode class that contains a range whose length + // overflows usize. (Which, to be honest, is probably quite common on + // 16-bit targets. For example, this would imply that '.' and '\p{any}' + // would be impossible to build.) + usize::try_from(diff).expect("char class len fits in usize") + } +} + +/// A set of characters represented by arbitrary bytes (where one byte +/// corresponds to one character). +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ClassBytes { + set: IntervalSet, +} + +impl ClassBytes { + /// Create a new class from a sequence of ranges. + /// + /// The given ranges do not need to be in any specific order, and ranges + /// may overlap. Ranges will automatically be sorted into a canonical + /// non-overlapping order. + pub fn new(ranges: I) -> ClassBytes + where + I: IntoIterator, + { + ClassBytes { set: IntervalSet::new(ranges) } + } + + /// Create a new class with no ranges. + /// + /// An empty class matches nothing. That is, it is equivalent to + /// [`Hir::fail`]. + pub fn empty() -> ClassBytes { + ClassBytes::new(vec![]) + } + + /// Add a new range to this set. + pub fn push(&mut self, range: ClassBytesRange) { + self.set.push(range); + } + + /// Return an iterator over all ranges in this class. + /// + /// The iterator yields ranges in ascending order. + pub fn iter(&self) -> ClassBytesIter<'_> { + ClassBytesIter(self.set.iter()) + } + + /// Return the underlying ranges as a slice. + pub fn ranges(&self) -> &[ClassBytesRange] { + self.set.intervals() + } + + /// Expand this character class such that it contains all case folded + /// characters. For example, if this class consists of the range `a-z`, + /// then applying case folding will result in the class containing both the + /// ranges `a-z` and `A-Z`. + /// + /// Note that this only applies ASCII case folding, which is limited to the + /// characters `a-z` and `A-Z`. + pub fn case_fold_simple(&mut self) { + self.set.case_fold_simple().expect("ASCII case folding never fails"); + } + + /// Negate this byte class. + /// + /// For all `b` where `b` is a any byte, if `b` was in this set, then it + /// will not be in this set after negation. + pub fn negate(&mut self) { + self.set.negate(); + } + + /// Union this byte class with the given byte class, in place. + pub fn union(&mut self, other: &ClassBytes) { + self.set.union(&other.set); + } + + /// Intersect this byte class with the given byte class, in place. + pub fn intersect(&mut self, other: &ClassBytes) { + self.set.intersect(&other.set); + } + + /// Subtract the given byte class from this byte class, in place. + pub fn difference(&mut self, other: &ClassBytes) { + self.set.difference(&other.set); + } + + /// Compute the symmetric difference of the given byte classes, in place. + /// + /// This computes the symmetric difference of two byte classes. This + /// removes all elements in this class that are also in the given class, + /// but all adds all elements from the given class that aren't in this + /// class. That is, the class will contain all elements in either class, + /// but will not contain any elements that are in both classes. + pub fn symmetric_difference(&mut self, other: &ClassBytes) { + self.set.symmetric_difference(&other.set); + } + + /// Returns true if and only if this character class will either match + /// nothing or only ASCII bytes. Stated differently, this returns false + /// if and only if this class contains a non-ASCII byte. + pub fn is_ascii(&self) -> bool { + self.set.intervals().last().map_or(true, |r| r.end <= 0x7F) + } + + /// Returns the length, in bytes, of the smallest string matched by this + /// character class. + /// + /// Returns `None` when the class is empty. + pub fn minimum_len(&self) -> Option { + if self.ranges().is_empty() { + None + } else { + Some(1) + } + } + + /// Returns the length, in bytes, of the longest string matched by this + /// character class. + /// + /// Returns `None` when the class is empty. + pub fn maximum_len(&self) -> Option { + if self.ranges().is_empty() { + None + } else { + Some(1) + } + } + + /// If this class consists of exactly one byte, then return it as + /// a literal byte string. + /// + /// If this class is empty or contains more than one byte, then `None` + /// is returned. + pub fn literal(&self) -> Option> { + let rs = self.ranges(); + if rs.len() == 1 && rs[0].start == rs[0].end { + Some(vec![rs[0].start]) + } else { + None + } + } + + /// If this class consists of only ASCII ranges, then return its + /// corresponding and equivalent Unicode class. + pub fn to_unicode_class(&self) -> Option { + if !self.is_ascii() { + return None; + } + Some(ClassUnicode::new(self.ranges().iter().map(|r| { + // Since we are guaranteed that our byte range is ASCII, the + // 'char::from' calls below are correct and will not erroneously + // convert a raw byte value into its corresponding codepoint. + ClassUnicodeRange { + start: char::from(r.start), + end: char::from(r.end), + } + }))) + } +} + +/// An iterator over all ranges in a byte character class. +/// +/// The lifetime `'a` refers to the lifetime of the underlying class. +#[derive(Debug)] +pub struct ClassBytesIter<'a>(IntervalSetIter<'a, ClassBytesRange>); + +impl<'a> Iterator for ClassBytesIter<'a> { + type Item = &'a ClassBytesRange; + + fn next(&mut self) -> Option<&'a ClassBytesRange> { + self.0.next() + } +} + +/// A single range of characters represented by arbitrary bytes. +/// +/// The range is closed. That is, the start and end of the range are included +/// in the range. +#[derive(Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct ClassBytesRange { + start: u8, + end: u8, +} + +impl Interval for ClassBytesRange { + type Bound = u8; + + #[inline] + fn lower(&self) -> u8 { + self.start + } + #[inline] + fn upper(&self) -> u8 { + self.end + } + #[inline] + fn set_lower(&mut self, bound: u8) { + self.start = bound; + } + #[inline] + fn set_upper(&mut self, bound: u8) { + self.end = bound; + } + + /// Apply simple case folding to this byte range. Only ASCII case mappings + /// (for a-z) are applied. + /// + /// Additional ranges are appended to the given vector. Canonical ordering + /// is *not* maintained in the given vector. + fn case_fold_simple( + &self, + ranges: &mut Vec, + ) -> Result<(), unicode::CaseFoldError> { + if !ClassBytesRange::new(b'a', b'z').is_intersection_empty(self) { + let lower = cmp::max(self.start, b'a'); + let upper = cmp::min(self.end, b'z'); + ranges.push(ClassBytesRange::new(lower - 32, upper - 32)); + } + if !ClassBytesRange::new(b'A', b'Z').is_intersection_empty(self) { + let lower = cmp::max(self.start, b'A'); + let upper = cmp::min(self.end, b'Z'); + ranges.push(ClassBytesRange::new(lower + 32, upper + 32)); + } + Ok(()) + } +} + +impl ClassBytesRange { + /// Create a new byte range for a character class. + /// + /// The returned range is always in a canonical form. That is, the range + /// returned always satisfies the invariant that `start <= end`. + pub fn new(start: u8, end: u8) -> ClassBytesRange { + ClassBytesRange::create(start, end) + } + + /// Return the start of this range. + /// + /// The start of a range is always less than or equal to the end of the + /// range. + pub fn start(&self) -> u8 { + self.start + } + + /// Return the end of this range. + /// + /// The end of a range is always greater than or equal to the start of the + /// range. + pub fn end(&self) -> u8 { + self.end + } + + /// Returns the number of bytes in this range. + pub fn len(&self) -> usize { + usize::from(self.end.checked_sub(self.start).unwrap()) + .checked_add(1) + .unwrap() + } +} + +impl core::fmt::Debug for ClassBytesRange { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ClassBytesRange") + .field("start", &crate::debug::Byte(self.start)) + .field("end", &crate::debug::Byte(self.end)) + .finish() + } +} + +/// The high-level intermediate representation for a look-around assertion. +/// +/// An assertion match is always zero-length. Also called an "empty match." +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Look { + /// Match the beginning of text. Specifically, this matches at the starting + /// position of the input. + Start = 1 << 0, + /// Match the end of text. Specifically, this matches at the ending + /// position of the input. + End = 1 << 1, + /// Match the beginning of a line or the beginning of text. Specifically, + /// this matches at the starting position of the input, or at the position + /// immediately following a `\n` character. + StartLF = 1 << 2, + /// Match the end of a line or the end of text. Specifically, this matches + /// at the end position of the input, or at the position immediately + /// preceding a `\n` character. + EndLF = 1 << 3, + /// Match the beginning of a line or the beginning of text. Specifically, + /// this matches at the starting position of the input, or at the position + /// immediately following either a `\r` or `\n` character, but never after + /// a `\r` when a `\n` follows. + StartCRLF = 1 << 4, + /// Match the end of a line or the end of text. Specifically, this matches + /// at the end position of the input, or at the position immediately + /// preceding a `\r` or `\n` character, but never before a `\n` when a `\r` + /// precedes it. + EndCRLF = 1 << 5, + /// Match an ASCII-only word boundary. That is, this matches a position + /// where the left adjacent character and right adjacent character + /// correspond to a word and non-word or a non-word and word character. + WordAscii = 1 << 6, + /// Match an ASCII-only negation of a word boundary. + WordAsciiNegate = 1 << 7, + /// Match a Unicode-aware word boundary. That is, this matches a position + /// where the left adjacent character and right adjacent character + /// correspond to a word and non-word or a non-word and word character. + WordUnicode = 1 << 8, + /// Match a Unicode-aware negation of a word boundary. + WordUnicodeNegate = 1 << 9, +} + +impl Look { + /// Flip the look-around assertion to its equivalent for reverse searches. + /// For example, `StartLF` gets translated to `EndLF`. + /// + /// Some assertions, such as `WordUnicode`, remain the same since they + /// match the same positions regardless of the direction of the search. + #[inline] + pub const fn reversed(self) -> Look { + match self { + Look::Start => Look::End, + Look::End => Look::Start, + Look::StartLF => Look::EndLF, + Look::EndLF => Look::StartLF, + Look::StartCRLF => Look::EndCRLF, + Look::EndCRLF => Look::StartCRLF, + Look::WordAscii => Look::WordAscii, + Look::WordAsciiNegate => Look::WordAsciiNegate, + Look::WordUnicode => Look::WordUnicode, + Look::WordUnicodeNegate => Look::WordUnicodeNegate, + } + } + + /// Return the underlying representation of this look-around enumeration + /// as an integer. Giving the return value to the [`Look::from_repr`] + /// constructor is guaranteed to return the same look-around variant that + /// one started with within a semver compatible release of this crate. + #[inline] + pub const fn as_repr(self) -> u16 { + // AFAIK, 'as' is the only way to zero-cost convert an int enum to an + // actual int. + self as u16 + } + + /// Given the underlying representation of a `Look` value, return the + /// corresponding `Look` value if the representation is valid. Otherwise + /// `None` is returned. + #[inline] + pub const fn from_repr(repr: u16) -> Option { + match repr { + 0b00_0000_0001 => Some(Look::Start), + 0b00_0000_0010 => Some(Look::End), + 0b00_0000_0100 => Some(Look::StartLF), + 0b00_0000_1000 => Some(Look::EndLF), + 0b00_0001_0000 => Some(Look::StartCRLF), + 0b00_0010_0000 => Some(Look::EndCRLF), + 0b00_0100_0000 => Some(Look::WordAscii), + 0b00_1000_0000 => Some(Look::WordAsciiNegate), + 0b01_0000_0000 => Some(Look::WordUnicode), + 0b10_0000_0000 => Some(Look::WordUnicodeNegate), + _ => None, + } + } + + /// Returns a convenient single codepoint representation of this + /// look-around assertion. Each assertion is guaranteed to be represented + /// by a distinct character. + /// + /// This is useful for succinctly representing a look-around assertion in + /// human friendly but succinct output intended for a programmer working on + /// regex internals. + #[inline] + pub const fn as_char(self) -> char { + match self { + Look::Start => 'A', + Look::End => 'z', + Look::StartLF => '^', + Look::EndLF => '$', + Look::StartCRLF => 'r', + Look::EndCRLF => 'R', + Look::WordAscii => 'b', + Look::WordAsciiNegate => 'B', + Look::WordUnicode => 'ð›ƒ', + Look::WordUnicodeNegate => 'ðš©', + } + } +} + +/// The high-level intermediate representation for a capturing group. +/// +/// A capturing group always has an index and a child expression. It may +/// also have a name associated with it (e.g., `(?P\w)`), but it's not +/// necessary. +/// +/// Note that there is no explicit representation of a non-capturing group +/// in a `Hir`. Instead, non-capturing grouping is handled automatically by +/// the recursive structure of the `Hir` itself. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Capture { + /// The capture index of the capture. + pub index: u32, + /// The name of the capture, if it exists. + pub name: Option>, + /// The expression inside the capturing group, which may be empty. + pub sub: Box, +} + +/// The high-level intermediate representation of a repetition operator. +/// +/// A repetition operator permits the repetition of an arbitrary +/// sub-expression. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Repetition { + /// The minimum range of the repetition. + /// + /// Note that special cases like `?`, `+` and `*` all get translated into + /// the ranges `{0,1}`, `{1,}` and `{0,}`, respectively. + /// + /// When `min` is zero, this expression can match the empty string + /// regardless of what its sub-expression is. + pub min: u32, + /// The maximum range of the repetition. + /// + /// Note that when `max` is `None`, `min` acts as a lower bound but where + /// there is no upper bound. For something like `x{5}` where the min and + /// max are equivalent, `min` will be set to `5` and `max` will be set to + /// `Some(5)`. + pub max: Option, + /// Whether this repetition operator is greedy or not. A greedy operator + /// will match as much as it can. A non-greedy operator will match as + /// little as it can. + /// + /// Typically, operators are greedy by default and are only non-greedy when + /// a `?` suffix is used, e.g., `(expr)*` is greedy while `(expr)*?` is + /// not. However, this can be inverted via the `U` "ungreedy" flag. + pub greedy: bool, + /// The expression being repeated. + pub sub: Box, +} + +impl Repetition { + /// Returns a new repetition with the same `min`, `max` and `greedy` + /// values, but with its sub-expression replaced with the one given. + pub fn with(&self, sub: Hir) -> Repetition { + Repetition { + min: self.min, + max: self.max, + greedy: self.greedy, + sub: Box::new(sub), + } + } +} + +/// A type describing the different flavors of `.`. +/// +/// This type is meant to be used with [`Hir::dot`], which is a convenience +/// routine for building HIR values derived from the `.` regex. +#[non_exhaustive] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Dot { + /// Matches the UTF-8 encoding of any Unicode scalar value. + /// + /// This is equivalent to `(?su:.)` and also `\p{any}`. + AnyChar, + /// Matches any byte value. + /// + /// This is equivalent to `(?s-u:.)` and also `(?-u:[\x00-\xFF])`. + AnyByte, + /// Matches the UTF-8 encoding of any Unicode scalar value except for the + /// `char` given. + /// + /// This is equivalent to using `(?u-s:.)` with the line terminator set + /// to a particular ASCII byte. (Because of peculiarities in the regex + /// engines, a line terminator must be a single byte. It follows that when + /// UTF-8 mode is enabled, this single byte must also be a Unicode scalar + /// value. That is, ti must be ASCII.) + /// + /// (This and `AnyCharExceptLF` both exist because of legacy reasons. + /// `AnyCharExceptLF` will be dropped in the next breaking change release.) + AnyCharExcept(char), + /// Matches the UTF-8 encoding of any Unicode scalar value except for `\n`. + /// + /// This is equivalent to `(?u-s:.)` and also `[\p{any}--\n]`. + AnyCharExceptLF, + /// Matches the UTF-8 encoding of any Unicode scalar value except for `\r` + /// and `\n`. + /// + /// This is equivalent to `(?uR-s:.)` and also `[\p{any}--\r\n]`. + AnyCharExceptCRLF, + /// Matches any byte value except for the `u8` given. + /// + /// This is equivalent to using `(?-us:.)` with the line terminator set + /// to a particular ASCII byte. (Because of peculiarities in the regex + /// engines, a line terminator must be a single byte. It follows that when + /// UTF-8 mode is enabled, this single byte must also be a Unicode scalar + /// value. That is, ti must be ASCII.) + /// + /// (This and `AnyByteExceptLF` both exist because of legacy reasons. + /// `AnyByteExceptLF` will be dropped in the next breaking change release.) + AnyByteExcept(u8), + /// Matches any byte value except for `\n`. + /// + /// This is equivalent to `(?-su:.)` and also `(?-u:[[\x00-\xFF]--\n])`. + AnyByteExceptLF, + /// Matches any byte value except for `\r` and `\n`. + /// + /// This is equivalent to `(?R-su:.)` and also `(?-u:[[\x00-\xFF]--\r\n])`. + AnyByteExceptCRLF, +} + +/// A custom `Drop` impl is used for `HirKind` such that it uses constant stack +/// space but heap space proportional to the depth of the total `Hir`. +impl Drop for Hir { + fn drop(&mut self) { + use core::mem; + + match *self.kind() { + HirKind::Empty + | HirKind::Literal(_) + | HirKind::Class(_) + | HirKind::Look(_) => return, + HirKind::Capture(ref x) if x.sub.kind.subs().is_empty() => return, + HirKind::Repetition(ref x) if x.sub.kind.subs().is_empty() => { + return + } + HirKind::Concat(ref x) if x.is_empty() => return, + HirKind::Alternation(ref x) if x.is_empty() => return, + _ => {} + } + + let mut stack = vec![mem::replace(self, Hir::empty())]; + while let Some(mut expr) = stack.pop() { + match expr.kind { + HirKind::Empty + | HirKind::Literal(_) + | HirKind::Class(_) + | HirKind::Look(_) => {} + HirKind::Capture(ref mut x) => { + stack.push(mem::replace(&mut x.sub, Hir::empty())); + } + HirKind::Repetition(ref mut x) => { + stack.push(mem::replace(&mut x.sub, Hir::empty())); + } + HirKind::Concat(ref mut x) => { + stack.extend(x.drain(..)); + } + HirKind::Alternation(ref mut x) => { + stack.extend(x.drain(..)); + } + } + } + } +} + +/// A type that collects various properties of an HIR value. +/// +/// Properties are always scalar values and represent meta data that is +/// computed inductively on an HIR value. Properties are defined for all +/// HIR values. +/// +/// All methods on a `Properties` value take constant time and are meant to +/// be cheap to call. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Properties(Box); + +/// The property definition. It is split out so that we can box it, and +/// there by make `Properties` use less stack size. This is kind-of important +/// because every HIR value has a `Properties` attached to it. +/// +/// This does have the unfortunate consequence that creating any HIR value +/// always leads to at least one alloc for properties, but this is generally +/// true anyway (for pretty much all HirKinds except for look-arounds). +#[derive(Clone, Debug, Eq, PartialEq)] +struct PropertiesI { + minimum_len: Option, + maximum_len: Option, + look_set: LookSet, + look_set_prefix: LookSet, + look_set_suffix: LookSet, + look_set_prefix_any: LookSet, + look_set_suffix_any: LookSet, + utf8: bool, + explicit_captures_len: usize, + static_explicit_captures_len: Option, + literal: bool, + alternation_literal: bool, +} + +impl Properties { + /// Returns the length (in bytes) of the smallest string matched by this + /// HIR. + /// + /// A return value of `0` is possible and occurs when the HIR can match an + /// empty string. + /// + /// `None` is returned when there is no minimum length. This occurs in + /// precisely the cases where the HIR matches nothing. i.e., The language + /// the regex matches is empty. An example of such a regex is `\P{any}`. + #[inline] + pub fn minimum_len(&self) -> Option { + self.0.minimum_len + } + + /// Returns the length (in bytes) of the longest string matched by this + /// HIR. + /// + /// A return value of `0` is possible and occurs when nothing longer than + /// the empty string is in the language described by this HIR. + /// + /// `None` is returned when there is no longest matching string. This + /// occurs when the HIR matches nothing or when there is no upper bound on + /// the length of matching strings. Example of such regexes are `\P{any}` + /// (matches nothing) and `a+` (has no upper bound). + #[inline] + pub fn maximum_len(&self) -> Option { + self.0.maximum_len + } + + /// Returns a set of all look-around assertions that appear at least once + /// in this HIR value. + #[inline] + pub fn look_set(&self) -> LookSet { + self.0.look_set + } + + /// Returns a set of all look-around assertions that appear as a prefix for + /// this HIR value. That is, the set returned corresponds to the set of + /// assertions that must be passed before matching any bytes in a haystack. + /// + /// For example, `hir.look_set_prefix().contains(Look::Start)` returns true + /// if and only if the HIR is fully anchored at the start. + #[inline] + pub fn look_set_prefix(&self) -> LookSet { + self.0.look_set_prefix + } + + /// Returns a set of all look-around assertions that appear as a _possible_ + /// prefix for this HIR value. That is, the set returned corresponds to the + /// set of assertions that _may_ be passed before matching any bytes in a + /// haystack. + /// + /// For example, `hir.look_set_prefix_any().contains(Look::Start)` returns + /// true if and only if it's possible for the regex to match through a + /// anchored assertion before consuming any input. + #[inline] + pub fn look_set_prefix_any(&self) -> LookSet { + self.0.look_set_prefix_any + } + + /// Returns a set of all look-around assertions that appear as a suffix for + /// this HIR value. That is, the set returned corresponds to the set of + /// assertions that must be passed in order to be considered a match after + /// all other consuming HIR expressions. + /// + /// For example, `hir.look_set_suffix().contains(Look::End)` returns true + /// if and only if the HIR is fully anchored at the end. + #[inline] + pub fn look_set_suffix(&self) -> LookSet { + self.0.look_set_suffix + } + + /// Returns a set of all look-around assertions that appear as a _possible_ + /// suffix for this HIR value. That is, the set returned corresponds to the + /// set of assertions that _may_ be passed before matching any bytes in a + /// haystack. + /// + /// For example, `hir.look_set_suffix_any().contains(Look::End)` returns + /// true if and only if it's possible for the regex to match through a + /// anchored assertion at the end of a match without consuming any input. + #[inline] + pub fn look_set_suffix_any(&self) -> LookSet { + self.0.look_set_suffix_any + } + + /// Return true if and only if the corresponding HIR will always match + /// valid UTF-8. + /// + /// When this returns false, then it is possible for this HIR expression to + /// match invalid UTF-8, including by matching between the code units of + /// a single UTF-8 encoded codepoint. + /// + /// Note that this returns true even when the corresponding HIR can match + /// the empty string. Since an empty string can technically appear between + /// UTF-8 code units, it is possible for a match to be reported that splits + /// a codepoint which could in turn be considered matching invalid UTF-8. + /// However, it is generally assumed that such empty matches are handled + /// specially by the search routine if it is absolutely required that + /// matches not split a codepoint. + /// + /// # Example + /// + /// This code example shows the UTF-8 property of a variety of patterns. + /// + /// ``` + /// use regex_syntax::{ParserBuilder, parse}; + /// + /// // Examples of 'is_utf8() == true'. + /// assert!(parse(r"a")?.properties().is_utf8()); + /// assert!(parse(r"[^a]")?.properties().is_utf8()); + /// assert!(parse(r".")?.properties().is_utf8()); + /// assert!(parse(r"\W")?.properties().is_utf8()); + /// assert!(parse(r"\b")?.properties().is_utf8()); + /// assert!(parse(r"\B")?.properties().is_utf8()); + /// assert!(parse(r"(?-u)\b")?.properties().is_utf8()); + /// assert!(parse(r"(?-u)\B")?.properties().is_utf8()); + /// // Unicode mode is enabled by default, and in + /// // that mode, all \x hex escapes are treated as + /// // codepoints. So this actually matches the UTF-8 + /// // encoding of U+00FF. + /// assert!(parse(r"\xFF")?.properties().is_utf8()); + /// + /// // Now we show examples of 'is_utf8() == false'. + /// // The only way to do this is to force the parser + /// // to permit invalid UTF-8, otherwise all of these + /// // would fail to parse! + /// let parse = |pattern| { + /// ParserBuilder::new().utf8(false).build().parse(pattern) + /// }; + /// assert!(!parse(r"(?-u)[^a]")?.properties().is_utf8()); + /// assert!(!parse(r"(?-u).")?.properties().is_utf8()); + /// assert!(!parse(r"(?-u)\W")?.properties().is_utf8()); + /// // Conversely to the equivalent example above, + /// // when Unicode mode is disabled, \x hex escapes + /// // are treated as their raw byte values. + /// assert!(!parse(r"(?-u)\xFF")?.properties().is_utf8()); + /// // Note that just because we disabled UTF-8 in the + /// // parser doesn't mean we still can't use Unicode. + /// // It is enabled by default, so \xFF is still + /// // equivalent to matching the UTF-8 encoding of + /// // U+00FF by default. + /// assert!(parse(r"\xFF")?.properties().is_utf8()); + /// // Even though we use raw bytes that individually + /// // are not valid UTF-8, when combined together, the + /// // overall expression *does* match valid UTF-8! + /// assert!(parse(r"(?-u)\xE2\x98\x83")?.properties().is_utf8()); + /// + /// # Ok::<(), Box>(()) + /// ``` + #[inline] + pub fn is_utf8(&self) -> bool { + self.0.utf8 + } + + /// Returns the total number of explicit capturing groups in the + /// corresponding HIR. + /// + /// Note that this does not include the implicit capturing group + /// corresponding to the entire match that is typically included by regex + /// engines. + /// + /// # Example + /// + /// This method will return `0` for `a` and `1` for `(a)`: + /// + /// ``` + /// use regex_syntax::parse; + /// + /// assert_eq!(0, parse("a")?.properties().explicit_captures_len()); + /// assert_eq!(1, parse("(a)")?.properties().explicit_captures_len()); + /// + /// # Ok::<(), Box>(()) + /// ``` + #[inline] + pub fn explicit_captures_len(&self) -> usize { + self.0.explicit_captures_len + } + + /// Returns the total number of explicit capturing groups that appear in + /// every possible match. + /// + /// If the number of capture groups can vary depending on the match, then + /// this returns `None`. That is, a value is only returned when the number + /// of matching groups is invariant or "static." + /// + /// Note that this does not include the implicit capturing group + /// corresponding to the entire match. + /// + /// # Example + /// + /// This shows a few cases where a static number of capture groups is + /// available and a few cases where it is not. + /// + /// ``` + /// use regex_syntax::parse; + /// + /// let len = |pattern| { + /// parse(pattern).map(|h| { + /// h.properties().static_explicit_captures_len() + /// }) + /// }; + /// + /// assert_eq!(Some(0), len("a")?); + /// assert_eq!(Some(1), len("(a)")?); + /// assert_eq!(Some(1), len("(a)|(b)")?); + /// assert_eq!(Some(2), len("(a)(b)|(c)(d)")?); + /// assert_eq!(None, len("(a)|b")?); + /// assert_eq!(None, len("a|(b)")?); + /// assert_eq!(None, len("(b)*")?); + /// assert_eq!(Some(1), len("(b)+")?); + /// + /// # Ok::<(), Box>(()) + /// ``` + #[inline] + pub fn static_explicit_captures_len(&self) -> Option { + self.0.static_explicit_captures_len + } + + /// Return true if and only if this HIR is a simple literal. This is + /// only true when this HIR expression is either itself a `Literal` or a + /// concatenation of only `Literal`s. + /// + /// For example, `f` and `foo` are literals, but `f+`, `(foo)`, `foo()` and + /// the empty string are not (even though they contain sub-expressions that + /// are literals). + #[inline] + pub fn is_literal(&self) -> bool { + self.0.literal + } + + /// Return true if and only if this HIR is either a simple literal or an + /// alternation of simple literals. This is only + /// true when this HIR expression is either itself a `Literal` or a + /// concatenation of only `Literal`s or an alternation of only `Literal`s. + /// + /// For example, `f`, `foo`, `a|b|c`, and `foo|bar|baz` are alternation + /// literals, but `f+`, `(foo)`, `foo()`, and the empty pattern are not + /// (even though that contain sub-expressions that are literals). + #[inline] + pub fn is_alternation_literal(&self) -> bool { + self.0.alternation_literal + } + + /// Returns the total amount of heap memory usage, in bytes, used by this + /// `Properties` value. + #[inline] + pub fn memory_usage(&self) -> usize { + core::mem::size_of::() + } + + /// Returns a new set of properties that corresponds to the union of the + /// iterator of properties given. + /// + /// This is useful when one has multiple `Hir` expressions and wants + /// to combine them into a single alternation without constructing the + /// corresponding `Hir`. This routine provides a way of combining the + /// properties of each `Hir` expression into one set of properties + /// representing the union of those expressions. + /// + /// # Example: union with HIRs that never match + /// + /// This example shows that unioning properties together with one that + /// represents a regex that never matches will "poison" certain attributes, + /// like the minimum and maximum lengths. + /// + /// ``` + /// use regex_syntax::{hir::Properties, parse}; + /// + /// let hir1 = parse("ab?c?")?; + /// assert_eq!(Some(1), hir1.properties().minimum_len()); + /// assert_eq!(Some(3), hir1.properties().maximum_len()); + /// + /// let hir2 = parse(r"[a&&b]")?; + /// assert_eq!(None, hir2.properties().minimum_len()); + /// assert_eq!(None, hir2.properties().maximum_len()); + /// + /// let hir3 = parse(r"wxy?z?")?; + /// assert_eq!(Some(2), hir3.properties().minimum_len()); + /// assert_eq!(Some(4), hir3.properties().maximum_len()); + /// + /// let unioned = Properties::union([ + /// hir1.properties(), + /// hir2.properties(), + /// hir3.properties(), + /// ]); + /// assert_eq!(None, unioned.minimum_len()); + /// assert_eq!(None, unioned.maximum_len()); + /// + /// # Ok::<(), Box>(()) + /// ``` + /// + /// The maximum length can also be "poisoned" by a pattern that has no + /// upper bound on the length of a match. The minimum length remains + /// unaffected: + /// + /// ``` + /// use regex_syntax::{hir::Properties, parse}; + /// + /// let hir1 = parse("ab?c?")?; + /// assert_eq!(Some(1), hir1.properties().minimum_len()); + /// assert_eq!(Some(3), hir1.properties().maximum_len()); + /// + /// let hir2 = parse(r"a+")?; + /// assert_eq!(Some(1), hir2.properties().minimum_len()); + /// assert_eq!(None, hir2.properties().maximum_len()); + /// + /// let hir3 = parse(r"wxy?z?")?; + /// assert_eq!(Some(2), hir3.properties().minimum_len()); + /// assert_eq!(Some(4), hir3.properties().maximum_len()); + /// + /// let unioned = Properties::union([ + /// hir1.properties(), + /// hir2.properties(), + /// hir3.properties(), + /// ]); + /// assert_eq!(Some(1), unioned.minimum_len()); + /// assert_eq!(None, unioned.maximum_len()); + /// + /// # Ok::<(), Box>(()) + /// ``` + pub fn union(props: I) -> Properties + where + I: IntoIterator, + P: core::borrow::Borrow, + { + let mut it = props.into_iter().peekable(); + // While empty alternations aren't possible, we still behave as if they + // are. When we have an empty alternate, then clearly the look-around + // prefix and suffix is empty. Otherwise, it is the intersection of all + // prefixes and suffixes (respectively) of the branches. + let fix = if it.peek().is_none() { + LookSet::empty() + } else { + LookSet::full() + }; + // And also, an empty alternate means we have 0 static capture groups, + // but we otherwise start with the number corresponding to the first + // alternate. If any subsequent alternate has a different number of + // static capture groups, then we overall have a variation and not a + // static number of groups. + let static_explicit_captures_len = + it.peek().and_then(|p| p.borrow().static_explicit_captures_len()); + // The base case is an empty alternation, which matches nothing. + // Note though that empty alternations aren't possible, because the + // Hir::alternation smart constructor rewrites those as empty character + // classes. + let mut props = PropertiesI { + minimum_len: None, + maximum_len: None, + look_set: LookSet::empty(), + look_set_prefix: fix, + look_set_suffix: fix, + look_set_prefix_any: LookSet::empty(), + look_set_suffix_any: LookSet::empty(), + utf8: true, + explicit_captures_len: 0, + static_explicit_captures_len, + literal: false, + alternation_literal: true, + }; + let (mut min_poisoned, mut max_poisoned) = (false, false); + // Handle properties that need to visit every child hir. + for prop in it { + let p = prop.borrow(); + props.look_set.set_union(p.look_set()); + props.look_set_prefix.set_intersect(p.look_set_prefix()); + props.look_set_suffix.set_intersect(p.look_set_suffix()); + props.look_set_prefix_any.set_union(p.look_set_prefix_any()); + props.look_set_suffix_any.set_union(p.look_set_suffix_any()); + props.utf8 = props.utf8 && p.is_utf8(); + props.explicit_captures_len = props + .explicit_captures_len + .saturating_add(p.explicit_captures_len()); + if props.static_explicit_captures_len + != p.static_explicit_captures_len() + { + props.static_explicit_captures_len = None; + } + props.alternation_literal = + props.alternation_literal && p.is_literal(); + if !min_poisoned { + if let Some(xmin) = p.minimum_len() { + if props.minimum_len.map_or(true, |pmin| xmin < pmin) { + props.minimum_len = Some(xmin); + } + } else { + props.minimum_len = None; + min_poisoned = true; + } + } + if !max_poisoned { + if let Some(xmax) = p.maximum_len() { + if props.maximum_len.map_or(true, |pmax| xmax > pmax) { + props.maximum_len = Some(xmax); + } + } else { + props.maximum_len = None; + max_poisoned = true; + } + } + } + Properties(Box::new(props)) + } +} + +impl Properties { + /// Create a new set of HIR properties for an empty regex. + fn empty() -> Properties { + let inner = PropertiesI { + minimum_len: Some(0), + maximum_len: Some(0), + look_set: LookSet::empty(), + look_set_prefix: LookSet::empty(), + look_set_suffix: LookSet::empty(), + look_set_prefix_any: LookSet::empty(), + look_set_suffix_any: LookSet::empty(), + // It is debatable whether an empty regex always matches at valid + // UTF-8 boundaries. Strictly speaking, at a byte oriented view, + // it is clearly false. There are, for example, many empty strings + // between the bytes encoding a '☃'. + // + // However, when Unicode mode is enabled, the fundamental atom + // of matching is really a codepoint. And in that scenario, an + // empty regex is defined to only match at valid UTF-8 boundaries + // and to never split a codepoint. It just so happens that this + // enforcement is somewhat tricky to do for regexes that match + // the empty string inside regex engines themselves. It usually + // requires some layer above the regex engine to filter out such + // matches. + // + // In any case, 'true' is really the only coherent option. If it + // were false, for example, then 'a*' would also need to be false + // since it too can match the empty string. + utf8: true, + explicit_captures_len: 0, + static_explicit_captures_len: Some(0), + literal: false, + alternation_literal: false, + }; + Properties(Box::new(inner)) + } + + /// Create a new set of HIR properties for a literal regex. + fn literal(lit: &Literal) -> Properties { + let inner = PropertiesI { + minimum_len: Some(lit.0.len()), + maximum_len: Some(lit.0.len()), + look_set: LookSet::empty(), + look_set_prefix: LookSet::empty(), + look_set_suffix: LookSet::empty(), + look_set_prefix_any: LookSet::empty(), + look_set_suffix_any: LookSet::empty(), + utf8: core::str::from_utf8(&lit.0).is_ok(), + explicit_captures_len: 0, + static_explicit_captures_len: Some(0), + literal: true, + alternation_literal: true, + }; + Properties(Box::new(inner)) + } + + /// Create a new set of HIR properties for a character class. + fn class(class: &Class) -> Properties { + let inner = PropertiesI { + minimum_len: class.minimum_len(), + maximum_len: class.maximum_len(), + look_set: LookSet::empty(), + look_set_prefix: LookSet::empty(), + look_set_suffix: LookSet::empty(), + look_set_prefix_any: LookSet::empty(), + look_set_suffix_any: LookSet::empty(), + utf8: class.is_utf8(), + explicit_captures_len: 0, + static_explicit_captures_len: Some(0), + literal: false, + alternation_literal: false, + }; + Properties(Box::new(inner)) + } + + /// Create a new set of HIR properties for a look-around assertion. + fn look(look: Look) -> Properties { + let inner = PropertiesI { + minimum_len: Some(0), + maximum_len: Some(0), + look_set: LookSet::singleton(look), + look_set_prefix: LookSet::singleton(look), + look_set_suffix: LookSet::singleton(look), + look_set_prefix_any: LookSet::singleton(look), + look_set_suffix_any: LookSet::singleton(look), + // This requires a little explanation. Basically, we don't consider + // matching an empty string to be equivalent to matching invalid + // UTF-8, even though technically matching every empty string will + // split the UTF-8 encoding of a single codepoint when treating a + // UTF-8 encoded string as a sequence of bytes. Our defense here is + // that in such a case, a codepoint should logically be treated as + // the fundamental atom for matching, and thus the only valid match + // points are between codepoints and not bytes. + // + // More practically, this is true here because it's also true + // for 'Hir::empty()', otherwise something like 'a*' would be + // considered to match invalid UTF-8. That in turn makes this + // property borderline useless. + utf8: true, + explicit_captures_len: 0, + static_explicit_captures_len: Some(0), + literal: false, + alternation_literal: false, + }; + Properties(Box::new(inner)) + } + + /// Create a new set of HIR properties for a repetition. + fn repetition(rep: &Repetition) -> Properties { + let p = rep.sub.properties(); + let minimum_len = p.minimum_len().map(|child_min| { + let rep_min = usize::try_from(rep.min).unwrap_or(usize::MAX); + child_min.saturating_mul(rep_min) + }); + let maximum_len = rep.max.and_then(|rep_max| { + let rep_max = usize::try_from(rep_max).ok()?; + let child_max = p.maximum_len()?; + child_max.checked_mul(rep_max) + }); + + let mut inner = PropertiesI { + minimum_len, + maximum_len, + look_set: p.look_set(), + look_set_prefix: LookSet::empty(), + look_set_suffix: LookSet::empty(), + look_set_prefix_any: p.look_set_prefix_any(), + look_set_suffix_any: p.look_set_suffix_any(), + utf8: p.is_utf8(), + explicit_captures_len: p.explicit_captures_len(), + static_explicit_captures_len: p.static_explicit_captures_len(), + literal: false, + alternation_literal: false, + }; + // If the repetition operator can match the empty string, then its + // lookset prefix and suffixes themselves remain empty since they are + // no longer required to match. + if rep.min > 0 { + inner.look_set_prefix = p.look_set_prefix(); + inner.look_set_suffix = p.look_set_suffix(); + } + // If the static captures len of the sub-expression is not known or + // is greater than zero, then it automatically propagates to the + // repetition, regardless of the repetition. Otherwise, it might + // change, but only when the repetition can match 0 times. + if rep.min == 0 + && inner.static_explicit_captures_len.map_or(false, |len| len > 0) + { + // If we require a match 0 times, then our captures len is + // guaranteed to be zero. Otherwise, if we *can* match the empty + // string, then it's impossible to know how many captures will be + // in the resulting match. + if rep.max == Some(0) { + inner.static_explicit_captures_len = Some(0); + } else { + inner.static_explicit_captures_len = None; + } + } + Properties(Box::new(inner)) + } + + /// Create a new set of HIR properties for a capture. + fn capture(capture: &Capture) -> Properties { + let p = capture.sub.properties(); + Properties(Box::new(PropertiesI { + explicit_captures_len: p.explicit_captures_len().saturating_add(1), + static_explicit_captures_len: p + .static_explicit_captures_len() + .map(|len| len.saturating_add(1)), + literal: false, + alternation_literal: false, + ..*p.0.clone() + })) + } + + /// Create a new set of HIR properties for a concatenation. + fn concat(concat: &[Hir]) -> Properties { + // The base case is an empty concatenation, which matches the empty + // string. Note though that empty concatenations aren't possible, + // because the Hir::concat smart constructor rewrites those as + // Hir::empty. + let mut props = PropertiesI { + minimum_len: Some(0), + maximum_len: Some(0), + look_set: LookSet::empty(), + look_set_prefix: LookSet::empty(), + look_set_suffix: LookSet::empty(), + look_set_prefix_any: LookSet::empty(), + look_set_suffix_any: LookSet::empty(), + utf8: true, + explicit_captures_len: 0, + static_explicit_captures_len: Some(0), + literal: true, + alternation_literal: true, + }; + // Handle properties that need to visit every child hir. + for x in concat.iter() { + let p = x.properties(); + props.look_set.set_union(p.look_set()); + props.utf8 = props.utf8 && p.is_utf8(); + props.explicit_captures_len = props + .explicit_captures_len + .saturating_add(p.explicit_captures_len()); + props.static_explicit_captures_len = p + .static_explicit_captures_len() + .and_then(|len1| { + Some((len1, props.static_explicit_captures_len?)) + }) + .and_then(|(len1, len2)| Some(len1.saturating_add(len2))); + props.literal = props.literal && p.is_literal(); + props.alternation_literal = + props.alternation_literal && p.is_alternation_literal(); + if let Some(minimum_len) = props.minimum_len { + match p.minimum_len() { + None => props.minimum_len = None, + Some(len) => { + // We use saturating arithmetic here because the + // minimum is just a lower bound. We can't go any + // higher than what our number types permit. + props.minimum_len = + Some(minimum_len.saturating_add(len)); + } + } + } + if let Some(maximum_len) = props.maximum_len { + match p.maximum_len() { + None => props.maximum_len = None, + Some(len) => { + props.maximum_len = maximum_len.checked_add(len) + } + } + } + } + // Handle the prefix properties, which only requires visiting + // child exprs until one matches more than the empty string. + let mut it = concat.iter(); + while let Some(x) = it.next() { + props.look_set_prefix.set_union(x.properties().look_set_prefix()); + props + .look_set_prefix_any + .set_union(x.properties().look_set_prefix_any()); + if x.properties().maximum_len().map_or(true, |x| x > 0) { + break; + } + } + // Same thing for the suffix properties, but in reverse. + let mut it = concat.iter().rev(); + while let Some(x) = it.next() { + props.look_set_suffix.set_union(x.properties().look_set_suffix()); + props + .look_set_suffix_any + .set_union(x.properties().look_set_suffix_any()); + if x.properties().maximum_len().map_or(true, |x| x > 0) { + break; + } + } + Properties(Box::new(props)) + } + + /// Create a new set of HIR properties for a concatenation. + fn alternation(alts: &[Hir]) -> Properties { + Properties::union(alts.iter().map(|hir| hir.properties())) + } +} + +/// A set of look-around assertions. +/// +/// This is useful for efficiently tracking look-around assertions. For +/// example, an [`Hir`] provides properties that return `LookSet`s. +#[derive(Clone, Copy, Default, Eq, PartialEq)] +pub struct LookSet { + /// The underlying representation this set is exposed to make it possible + /// to store it somewhere efficiently. The representation is that + /// of a bitset, where each assertion occupies bit `i` where `i = + /// Look::as_repr()`. + /// + /// Note that users of this internal representation must permit the full + /// range of `u16` values to be represented. For example, even if the + /// current implementation only makes use of the 10 least significant bits, + /// it may use more bits in a future semver compatible release. + pub bits: u16, +} + +impl LookSet { + /// Create an empty set of look-around assertions. + #[inline] + pub fn empty() -> LookSet { + LookSet { bits: 0 } + } + + /// Create a full set of look-around assertions. + /// + /// This set contains all possible look-around assertions. + #[inline] + pub fn full() -> LookSet { + LookSet { bits: !0 } + } + + /// Create a look-around set containing the look-around assertion given. + /// + /// This is a convenience routine for creating an empty set and inserting + /// one look-around assertions. + #[inline] + pub fn singleton(look: Look) -> LookSet { + LookSet::empty().insert(look) + } + + /// Returns the total number of look-around assertions in this set. + #[inline] + pub fn len(self) -> usize { + // OK because max value always fits in a u8, which in turn always + // fits in a usize, regardless of target. + usize::try_from(self.bits.count_ones()).unwrap() + } + + /// Returns true if and only if this set is empty. + #[inline] + pub fn is_empty(self) -> bool { + self.len() == 0 + } + + /// Returns true if and only if the given look-around assertion is in this + /// set. + #[inline] + pub fn contains(self, look: Look) -> bool { + self.bits & look.as_repr() != 0 + } + + /// Returns true if and only if this set contains any anchor assertions. + /// This includes both "start/end of haystack" and "start/end of line." + #[inline] + pub fn contains_anchor(&self) -> bool { + self.contains_anchor_haystack() || self.contains_anchor_line() + } + + /// Returns true if and only if this set contains any "start/end of + /// haystack" anchors. This doesn't include "start/end of line" anchors. + #[inline] + pub fn contains_anchor_haystack(&self) -> bool { + self.contains(Look::Start) || self.contains(Look::End) + } + + /// Returns true if and only if this set contains any "start/end of line" + /// anchors. This doesn't include "start/end of haystack" anchors. This + /// includes both `\n` line anchors and CRLF (`\r\n`) aware line anchors. + #[inline] + pub fn contains_anchor_line(&self) -> bool { + self.contains(Look::StartLF) + || self.contains(Look::EndLF) + || self.contains(Look::StartCRLF) + || self.contains(Look::EndCRLF) + } + + /// Returns true if and only if this set contains any "start/end of line" + /// anchors that only treat `\n` as line terminators. This does not include + /// haystack anchors or CRLF aware line anchors. + #[inline] + pub fn contains_anchor_lf(&self) -> bool { + self.contains(Look::StartLF) || self.contains(Look::EndLF) + } + + /// Returns true if and only if this set contains any "start/end of line" + /// anchors that are CRLF-aware. This doesn't include "start/end of + /// haystack" or "start/end of line-feed" anchors. + #[inline] + pub fn contains_anchor_crlf(&self) -> bool { + self.contains(Look::StartCRLF) || self.contains(Look::EndCRLF) + } + + /// Returns true if and only if this set contains any word boundary or + /// negated word boundary assertions. This include both Unicode and ASCII + /// word boundaries. + #[inline] + pub fn contains_word(self) -> bool { + self.contains_word_unicode() || self.contains_word_ascii() + } + + /// Returns true if and only if this set contains any Unicode word boundary + /// or negated Unicode word boundary assertions. + #[inline] + pub fn contains_word_unicode(self) -> bool { + self.contains(Look::WordUnicode) + || self.contains(Look::WordUnicodeNegate) + } + + /// Returns true if and only if this set contains any ASCII word boundary + /// or negated ASCII word boundary assertions. + #[inline] + pub fn contains_word_ascii(self) -> bool { + self.contains(Look::WordAscii) || self.contains(Look::WordAsciiNegate) + } + + /// Returns an iterator over all of the look-around assertions in this set. + #[inline] + pub fn iter(self) -> LookSetIter { + LookSetIter { set: self } + } + + /// Return a new set that is equivalent to the original, but with the given + /// assertion added to it. If the assertion is already in the set, then the + /// returned set is equivalent to the original. + #[inline] + pub fn insert(self, look: Look) -> LookSet { + LookSet { bits: self.bits | look.as_repr() } + } + + /// Updates this set in place with the result of inserting the given + /// assertion into this set. + #[inline] + pub fn set_insert(&mut self, look: Look) { + *self = self.insert(look); + } + + /// Return a new set that is equivalent to the original, but with the given + /// assertion removed from it. If the assertion is not in the set, then the + /// returned set is equivalent to the original. + #[inline] + pub fn remove(self, look: Look) -> LookSet { + LookSet { bits: self.bits & !look.as_repr() } + } + + /// Updates this set in place with the result of removing the given + /// assertion from this set. + #[inline] + pub fn set_remove(&mut self, look: Look) { + *self = self.remove(look); + } + + /// Returns a new set that is the result of subtracting the given set from + /// this set. + #[inline] + pub fn subtract(self, other: LookSet) -> LookSet { + LookSet { bits: self.bits & !other.bits } + } + + /// Updates this set in place with the result of subtracting the given set + /// from this set. + #[inline] + pub fn set_subtract(&mut self, other: LookSet) { + *self = self.subtract(other); + } + + /// Returns a new set that is the union of this and the one given. + #[inline] + pub fn union(self, other: LookSet) -> LookSet { + LookSet { bits: self.bits | other.bits } + } + + /// Updates this set in place with the result of unioning it with the one + /// given. + #[inline] + pub fn set_union(&mut self, other: LookSet) { + *self = self.union(other); + } + + /// Returns a new set that is the intersection of this and the one given. + #[inline] + pub fn intersect(self, other: LookSet) -> LookSet { + LookSet { bits: self.bits & other.bits } + } + + /// Updates this set in place with the result of intersecting it with the + /// one given. + #[inline] + pub fn set_intersect(&mut self, other: LookSet) { + *self = self.intersect(other); + } + + /// Return a `LookSet` from the slice given as a native endian 16-bit + /// integer. + /// + /// # Panics + /// + /// This panics if `slice.len() < 2`. + #[inline] + pub fn read_repr(slice: &[u8]) -> LookSet { + let bits = u16::from_ne_bytes(slice[..2].try_into().unwrap()); + LookSet { bits } + } + + /// Write a `LookSet` as a native endian 16-bit integer to the beginning + /// of the slice given. + /// + /// # Panics + /// + /// This panics if `slice.len() < 2`. + #[inline] + pub fn write_repr(self, slice: &mut [u8]) { + let raw = self.bits.to_ne_bytes(); + slice[0] = raw[0]; + slice[1] = raw[1]; + } +} + +impl core::fmt::Debug for LookSet { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + if self.is_empty() { + return write!(f, "∅"); + } + for look in self.iter() { + write!(f, "{}", look.as_char())?; + } + Ok(()) + } +} + +/// An iterator over all look-around assertions in a [`LookSet`]. +/// +/// This iterator is created by [`LookSet::iter`]. +#[derive(Clone, Debug)] +pub struct LookSetIter { + set: LookSet, +} + +impl Iterator for LookSetIter { + type Item = Look; + + #[inline] + fn next(&mut self) -> Option { + if self.set.is_empty() { + return None; + } + // We'll never have more than u8::MAX distinct look-around assertions, + // so 'repr' will always fit into a u16. + let repr = u16::try_from(self.set.bits.trailing_zeros()).unwrap(); + let look = Look::from_repr(1 << repr)?; + self.set = self.set.remove(look); + Some(look) + } +} + +/// Given a sequence of HIR values where each value corresponds to a Unicode +/// class (or an all-ASCII byte class), return a single Unicode class +/// corresponding to the union of the classes found. +fn class_chars(hirs: &[Hir]) -> Option { + let mut cls = ClassUnicode::new(vec![]); + for hir in hirs.iter() { + match *hir.kind() { + HirKind::Class(Class::Unicode(ref cls2)) => { + cls.union(cls2); + } + HirKind::Class(Class::Bytes(ref cls2)) => { + cls.union(&cls2.to_unicode_class()?); + } + _ => return None, + }; + } + Some(Class::Unicode(cls)) +} + +/// Given a sequence of HIR values where each value corresponds to a byte class +/// (or an all-ASCII Unicode class), return a single byte class corresponding +/// to the union of the classes found. +fn class_bytes(hirs: &[Hir]) -> Option { + let mut cls = ClassBytes::new(vec![]); + for hir in hirs.iter() { + match *hir.kind() { + HirKind::Class(Class::Unicode(ref cls2)) => { + cls.union(&cls2.to_byte_class()?); + } + HirKind::Class(Class::Bytes(ref cls2)) => { + cls.union(cls2); + } + _ => return None, + }; + } + Some(Class::Bytes(cls)) +} + +/// Given a sequence of HIR values where each value corresponds to a literal +/// that is a single `char`, return that sequence of `char`s. Otherwise return +/// None. No deduplication is done. +fn singleton_chars(hirs: &[Hir]) -> Option> { + let mut singletons = vec![]; + for hir in hirs.iter() { + let literal = match *hir.kind() { + HirKind::Literal(Literal(ref bytes)) => bytes, + _ => return None, + }; + let ch = match crate::debug::utf8_decode(literal) { + None => return None, + Some(Err(_)) => return None, + Some(Ok(ch)) => ch, + }; + if literal.len() != ch.len_utf8() { + return None; + } + singletons.push(ch); + } + Some(singletons) +} + +/// Given a sequence of HIR values where each value corresponds to a literal +/// that is a single byte, return that sequence of bytes. Otherwise return +/// None. No deduplication is done. +fn singleton_bytes(hirs: &[Hir]) -> Option> { + let mut singletons = vec![]; + for hir in hirs.iter() { + let literal = match *hir.kind() { + HirKind::Literal(Literal(ref bytes)) => bytes, + _ => return None, + }; + if literal.len() != 1 { + return None; + } + singletons.push(literal[0]); + } + Some(singletons) +} + +/// Looks for a common prefix in the list of alternation branches given. If one +/// is found, then an equivalent but (hopefully) simplified Hir is returned. +/// Otherwise, the original given list of branches is returned unmodified. +/// +/// This is not quite as good as it could be. Right now, it requires that +/// all branches are 'Concat' expressions. It also doesn't do well with +/// literals. For example, given 'foofoo|foobar', it will not refactor it to +/// 'foo(?:foo|bar)' because literals are flattened into their own special +/// concatenation. (One wonders if perhaps 'Literal' should be a single atom +/// instead of a string of bytes because of this. Otherwise, handling the +/// current representation in this routine will be pretty gnarly. Sigh.) +fn lift_common_prefix(hirs: Vec) -> Result> { + if hirs.len() <= 1 { + return Err(hirs); + } + let mut prefix = match hirs[0].kind() { + HirKind::Concat(ref xs) => &**xs, + _ => return Err(hirs), + }; + if prefix.is_empty() { + return Err(hirs); + } + for h in hirs.iter().skip(1) { + let concat = match h.kind() { + HirKind::Concat(ref xs) => xs, + _ => return Err(hirs), + }; + let common_len = prefix + .iter() + .zip(concat.iter()) + .take_while(|(x, y)| x == y) + .count(); + prefix = &prefix[..common_len]; + if prefix.is_empty() { + return Err(hirs); + } + } + let len = prefix.len(); + assert_ne!(0, len); + let mut prefix_concat = vec![]; + let mut suffix_alts = vec![]; + for h in hirs { + let mut concat = match h.into_kind() { + HirKind::Concat(xs) => xs, + // We required all sub-expressions to be + // concats above, so we're only here if we + // have a concat. + _ => unreachable!(), + }; + suffix_alts.push(Hir::concat(concat.split_off(len))); + if prefix_concat.is_empty() { + prefix_concat = concat; + } + } + let mut concat = prefix_concat; + concat.push(Hir::alternation(suffix_alts)); + Ok(Hir::concat(concat)) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn uclass(ranges: &[(char, char)]) -> ClassUnicode { + let ranges: Vec = ranges + .iter() + .map(|&(s, e)| ClassUnicodeRange::new(s, e)) + .collect(); + ClassUnicode::new(ranges) + } + + fn bclass(ranges: &[(u8, u8)]) -> ClassBytes { + let ranges: Vec = + ranges.iter().map(|&(s, e)| ClassBytesRange::new(s, e)).collect(); + ClassBytes::new(ranges) + } + + fn uranges(cls: &ClassUnicode) -> Vec<(char, char)> { + cls.iter().map(|x| (x.start(), x.end())).collect() + } + + #[cfg(feature = "unicode-case")] + fn ucasefold(cls: &ClassUnicode) -> ClassUnicode { + let mut cls_ = cls.clone(); + cls_.case_fold_simple(); + cls_ + } + + fn uunion(cls1: &ClassUnicode, cls2: &ClassUnicode) -> ClassUnicode { + let mut cls_ = cls1.clone(); + cls_.union(cls2); + cls_ + } + + fn uintersect(cls1: &ClassUnicode, cls2: &ClassUnicode) -> ClassUnicode { + let mut cls_ = cls1.clone(); + cls_.intersect(cls2); + cls_ + } + + fn udifference(cls1: &ClassUnicode, cls2: &ClassUnicode) -> ClassUnicode { + let mut cls_ = cls1.clone(); + cls_.difference(cls2); + cls_ + } + + fn usymdifference( + cls1: &ClassUnicode, + cls2: &ClassUnicode, + ) -> ClassUnicode { + let mut cls_ = cls1.clone(); + cls_.symmetric_difference(cls2); + cls_ + } + + fn unegate(cls: &ClassUnicode) -> ClassUnicode { + let mut cls_ = cls.clone(); + cls_.negate(); + cls_ + } + + fn branges(cls: &ClassBytes) -> Vec<(u8, u8)> { + cls.iter().map(|x| (x.start(), x.end())).collect() + } + + fn bcasefold(cls: &ClassBytes) -> ClassBytes { + let mut cls_ = cls.clone(); + cls_.case_fold_simple(); + cls_ + } + + fn bunion(cls1: &ClassBytes, cls2: &ClassBytes) -> ClassBytes { + let mut cls_ = cls1.clone(); + cls_.union(cls2); + cls_ + } + + fn bintersect(cls1: &ClassBytes, cls2: &ClassBytes) -> ClassBytes { + let mut cls_ = cls1.clone(); + cls_.intersect(cls2); + cls_ + } + + fn bdifference(cls1: &ClassBytes, cls2: &ClassBytes) -> ClassBytes { + let mut cls_ = cls1.clone(); + cls_.difference(cls2); + cls_ + } + + fn bsymdifference(cls1: &ClassBytes, cls2: &ClassBytes) -> ClassBytes { + let mut cls_ = cls1.clone(); + cls_.symmetric_difference(cls2); + cls_ + } + + fn bnegate(cls: &ClassBytes) -> ClassBytes { + let mut cls_ = cls.clone(); + cls_.negate(); + cls_ + } + + #[test] + fn class_range_canonical_unicode() { + let range = ClassUnicodeRange::new('\u{00FF}', '\0'); + assert_eq!('\0', range.start()); + assert_eq!('\u{00FF}', range.end()); + } + + #[test] + fn class_range_canonical_bytes() { + let range = ClassBytesRange::new(b'\xFF', b'\0'); + assert_eq!(b'\0', range.start()); + assert_eq!(b'\xFF', range.end()); + } + + #[test] + fn class_canonicalize_unicode() { + let cls = uclass(&[('a', 'c'), ('x', 'z')]); + let expected = vec![('a', 'c'), ('x', 'z')]; + assert_eq!(expected, uranges(&cls)); + + let cls = uclass(&[('x', 'z'), ('a', 'c')]); + let expected = vec![('a', 'c'), ('x', 'z')]; + assert_eq!(expected, uranges(&cls)); + + let cls = uclass(&[('x', 'z'), ('w', 'y')]); + let expected = vec![('w', 'z')]; + assert_eq!(expected, uranges(&cls)); + + let cls = uclass(&[ + ('c', 'f'), + ('a', 'g'), + ('d', 'j'), + ('a', 'c'), + ('m', 'p'), + ('l', 's'), + ]); + let expected = vec![('a', 'j'), ('l', 's')]; + assert_eq!(expected, uranges(&cls)); + + let cls = uclass(&[('x', 'z'), ('u', 'w')]); + let expected = vec![('u', 'z')]; + assert_eq!(expected, uranges(&cls)); + + let cls = uclass(&[('\x00', '\u{10FFFF}'), ('\x00', '\u{10FFFF}')]); + let expected = vec![('\x00', '\u{10FFFF}')]; + assert_eq!(expected, uranges(&cls)); + + let cls = uclass(&[('a', 'a'), ('b', 'b')]); + let expected = vec![('a', 'b')]; + assert_eq!(expected, uranges(&cls)); + } + + #[test] + fn class_canonicalize_bytes() { + let cls = bclass(&[(b'a', b'c'), (b'x', b'z')]); + let expected = vec![(b'a', b'c'), (b'x', b'z')]; + assert_eq!(expected, branges(&cls)); + + let cls = bclass(&[(b'x', b'z'), (b'a', b'c')]); + let expected = vec![(b'a', b'c'), (b'x', b'z')]; + assert_eq!(expected, branges(&cls)); + + let cls = bclass(&[(b'x', b'z'), (b'w', b'y')]); + let expected = vec![(b'w', b'z')]; + assert_eq!(expected, branges(&cls)); + + let cls = bclass(&[ + (b'c', b'f'), + (b'a', b'g'), + (b'd', b'j'), + (b'a', b'c'), + (b'm', b'p'), + (b'l', b's'), + ]); + let expected = vec![(b'a', b'j'), (b'l', b's')]; + assert_eq!(expected, branges(&cls)); + + let cls = bclass(&[(b'x', b'z'), (b'u', b'w')]); + let expected = vec![(b'u', b'z')]; + assert_eq!(expected, branges(&cls)); + + let cls = bclass(&[(b'\x00', b'\xFF'), (b'\x00', b'\xFF')]); + let expected = vec![(b'\x00', b'\xFF')]; + assert_eq!(expected, branges(&cls)); + + let cls = bclass(&[(b'a', b'a'), (b'b', b'b')]); + let expected = vec![(b'a', b'b')]; + assert_eq!(expected, branges(&cls)); + } + + #[test] + #[cfg(feature = "unicode-case")] + fn class_case_fold_unicode() { + let cls = uclass(&[ + ('C', 'F'), + ('A', 'G'), + ('D', 'J'), + ('A', 'C'), + ('M', 'P'), + ('L', 'S'), + ('c', 'f'), + ]); + let expected = uclass(&[ + ('A', 'J'), + ('L', 'S'), + ('a', 'j'), + ('l', 's'), + ('\u{17F}', '\u{17F}'), + ]); + assert_eq!(expected, ucasefold(&cls)); + + let cls = uclass(&[('A', 'Z')]); + let expected = uclass(&[ + ('A', 'Z'), + ('a', 'z'), + ('\u{17F}', '\u{17F}'), + ('\u{212A}', '\u{212A}'), + ]); + assert_eq!(expected, ucasefold(&cls)); + + let cls = uclass(&[('a', 'z')]); + let expected = uclass(&[ + ('A', 'Z'), + ('a', 'z'), + ('\u{17F}', '\u{17F}'), + ('\u{212A}', '\u{212A}'), + ]); + assert_eq!(expected, ucasefold(&cls)); + + let cls = uclass(&[('A', 'A'), ('_', '_')]); + let expected = uclass(&[('A', 'A'), ('_', '_'), ('a', 'a')]); + assert_eq!(expected, ucasefold(&cls)); + + let cls = uclass(&[('A', 'A'), ('=', '=')]); + let expected = uclass(&[('=', '='), ('A', 'A'), ('a', 'a')]); + assert_eq!(expected, ucasefold(&cls)); + + let cls = uclass(&[('\x00', '\x10')]); + assert_eq!(cls, ucasefold(&cls)); + + let cls = uclass(&[('k', 'k')]); + let expected = + uclass(&[('K', 'K'), ('k', 'k'), ('\u{212A}', '\u{212A}')]); + assert_eq!(expected, ucasefold(&cls)); + + let cls = uclass(&[('@', '@')]); + assert_eq!(cls, ucasefold(&cls)); + } + + #[test] + #[cfg(not(feature = "unicode-case"))] + fn class_case_fold_unicode_disabled() { + let mut cls = uclass(&[ + ('C', 'F'), + ('A', 'G'), + ('D', 'J'), + ('A', 'C'), + ('M', 'P'), + ('L', 'S'), + ('c', 'f'), + ]); + assert!(cls.try_case_fold_simple().is_err()); + } + + #[test] + #[should_panic] + #[cfg(not(feature = "unicode-case"))] + fn class_case_fold_unicode_disabled_panics() { + let mut cls = uclass(&[ + ('C', 'F'), + ('A', 'G'), + ('D', 'J'), + ('A', 'C'), + ('M', 'P'), + ('L', 'S'), + ('c', 'f'), + ]); + cls.case_fold_simple(); + } + + #[test] + fn class_case_fold_bytes() { + let cls = bclass(&[ + (b'C', b'F'), + (b'A', b'G'), + (b'D', b'J'), + (b'A', b'C'), + (b'M', b'P'), + (b'L', b'S'), + (b'c', b'f'), + ]); + let expected = + bclass(&[(b'A', b'J'), (b'L', b'S'), (b'a', b'j'), (b'l', b's')]); + assert_eq!(expected, bcasefold(&cls)); + + let cls = bclass(&[(b'A', b'Z')]); + let expected = bclass(&[(b'A', b'Z'), (b'a', b'z')]); + assert_eq!(expected, bcasefold(&cls)); + + let cls = bclass(&[(b'a', b'z')]); + let expected = bclass(&[(b'A', b'Z'), (b'a', b'z')]); + assert_eq!(expected, bcasefold(&cls)); + + let cls = bclass(&[(b'A', b'A'), (b'_', b'_')]); + let expected = bclass(&[(b'A', b'A'), (b'_', b'_'), (b'a', b'a')]); + assert_eq!(expected, bcasefold(&cls)); + + let cls = bclass(&[(b'A', b'A'), (b'=', b'=')]); + let expected = bclass(&[(b'=', b'='), (b'A', b'A'), (b'a', b'a')]); + assert_eq!(expected, bcasefold(&cls)); + + let cls = bclass(&[(b'\x00', b'\x10')]); + assert_eq!(cls, bcasefold(&cls)); + + let cls = bclass(&[(b'k', b'k')]); + let expected = bclass(&[(b'K', b'K'), (b'k', b'k')]); + assert_eq!(expected, bcasefold(&cls)); + + let cls = bclass(&[(b'@', b'@')]); + assert_eq!(cls, bcasefold(&cls)); + } + + #[test] + fn class_negate_unicode() { + let cls = uclass(&[('a', 'a')]); + let expected = uclass(&[('\x00', '\x60'), ('\x62', '\u{10FFFF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('a', 'a'), ('b', 'b')]); + let expected = uclass(&[('\x00', '\x60'), ('\x63', '\u{10FFFF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('a', 'c'), ('x', 'z')]); + let expected = uclass(&[ + ('\x00', '\x60'), + ('\x64', '\x77'), + ('\x7B', '\u{10FFFF}'), + ]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('\x00', 'a')]); + let expected = uclass(&[('\x62', '\u{10FFFF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('a', '\u{10FFFF}')]); + let expected = uclass(&[('\x00', '\x60')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('\x00', '\u{10FFFF}')]); + let expected = uclass(&[]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[]); + let expected = uclass(&[('\x00', '\u{10FFFF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = + uclass(&[('\x00', '\u{10FFFD}'), ('\u{10FFFF}', '\u{10FFFF}')]); + let expected = uclass(&[('\u{10FFFE}', '\u{10FFFE}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('\x00', '\u{D7FF}')]); + let expected = uclass(&[('\u{E000}', '\u{10FFFF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('\x00', '\u{D7FE}')]); + let expected = uclass(&[('\u{D7FF}', '\u{10FFFF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('\u{E000}', '\u{10FFFF}')]); + let expected = uclass(&[('\x00', '\u{D7FF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('\u{E001}', '\u{10FFFF}')]); + let expected = uclass(&[('\x00', '\u{E000}')]); + assert_eq!(expected, unegate(&cls)); + } + + #[test] + fn class_negate_bytes() { + let cls = bclass(&[(b'a', b'a')]); + let expected = bclass(&[(b'\x00', b'\x60'), (b'\x62', b'\xFF')]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[(b'a', b'a'), (b'b', b'b')]); + let expected = bclass(&[(b'\x00', b'\x60'), (b'\x63', b'\xFF')]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[(b'a', b'c'), (b'x', b'z')]); + let expected = bclass(&[ + (b'\x00', b'\x60'), + (b'\x64', b'\x77'), + (b'\x7B', b'\xFF'), + ]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[(b'\x00', b'a')]); + let expected = bclass(&[(b'\x62', b'\xFF')]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[(b'a', b'\xFF')]); + let expected = bclass(&[(b'\x00', b'\x60')]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[(b'\x00', b'\xFF')]); + let expected = bclass(&[]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[]); + let expected = bclass(&[(b'\x00', b'\xFF')]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[(b'\x00', b'\xFD'), (b'\xFF', b'\xFF')]); + let expected = bclass(&[(b'\xFE', b'\xFE')]); + assert_eq!(expected, bnegate(&cls)); + } + + #[test] + fn class_union_unicode() { + let cls1 = uclass(&[('a', 'g'), ('m', 't'), ('A', 'C')]); + let cls2 = uclass(&[('a', 'z')]); + let expected = uclass(&[('a', 'z'), ('A', 'C')]); + assert_eq!(expected, uunion(&cls1, &cls2)); + } + + #[test] + fn class_union_bytes() { + let cls1 = bclass(&[(b'a', b'g'), (b'm', b't'), (b'A', b'C')]); + let cls2 = bclass(&[(b'a', b'z')]); + let expected = bclass(&[(b'a', b'z'), (b'A', b'C')]); + assert_eq!(expected, bunion(&cls1, &cls2)); + } + + #[test] + fn class_intersect_unicode() { + let cls1 = uclass(&[]); + let cls2 = uclass(&[('a', 'a')]); + let expected = uclass(&[]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'a')]); + let cls2 = uclass(&[('a', 'a')]); + let expected = uclass(&[('a', 'a')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'a')]); + let cls2 = uclass(&[('b', 'b')]); + let expected = uclass(&[]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'a')]); + let cls2 = uclass(&[('a', 'c')]); + let expected = uclass(&[('a', 'a')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b')]); + let cls2 = uclass(&[('a', 'c')]); + let expected = uclass(&[('a', 'b')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b')]); + let cls2 = uclass(&[('b', 'c')]); + let expected = uclass(&[('b', 'b')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b')]); + let cls2 = uclass(&[('c', 'd')]); + let expected = uclass(&[]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('b', 'c')]); + let cls2 = uclass(&[('a', 'd')]); + let expected = uclass(&[('b', 'c')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b'), ('d', 'e'), ('g', 'h')]); + let cls2 = uclass(&[('a', 'h')]); + let expected = uclass(&[('a', 'b'), ('d', 'e'), ('g', 'h')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b'), ('d', 'e'), ('g', 'h')]); + let cls2 = uclass(&[('a', 'b'), ('d', 'e'), ('g', 'h')]); + let expected = uclass(&[('a', 'b'), ('d', 'e'), ('g', 'h')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b'), ('g', 'h')]); + let cls2 = uclass(&[('d', 'e'), ('k', 'l')]); + let expected = uclass(&[]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b'), ('d', 'e'), ('g', 'h')]); + let cls2 = uclass(&[('h', 'h')]); + let expected = uclass(&[('h', 'h')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b'), ('e', 'f'), ('i', 'j')]); + let cls2 = uclass(&[('c', 'd'), ('g', 'h'), ('k', 'l')]); + let expected = uclass(&[]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b'), ('c', 'd'), ('e', 'f')]); + let cls2 = uclass(&[('b', 'c'), ('d', 'e'), ('f', 'g')]); + let expected = uclass(&[('b', 'f')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + } + + #[test] + fn class_intersect_bytes() { + let cls1 = bclass(&[]); + let cls2 = bclass(&[(b'a', b'a')]); + let expected = bclass(&[]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'a')]); + let cls2 = bclass(&[(b'a', b'a')]); + let expected = bclass(&[(b'a', b'a')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'a')]); + let cls2 = bclass(&[(b'b', b'b')]); + let expected = bclass(&[]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'a')]); + let cls2 = bclass(&[(b'a', b'c')]); + let expected = bclass(&[(b'a', b'a')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b')]); + let cls2 = bclass(&[(b'a', b'c')]); + let expected = bclass(&[(b'a', b'b')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b')]); + let cls2 = bclass(&[(b'b', b'c')]); + let expected = bclass(&[(b'b', b'b')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b')]); + let cls2 = bclass(&[(b'c', b'd')]); + let expected = bclass(&[]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'b', b'c')]); + let cls2 = bclass(&[(b'a', b'd')]); + let expected = bclass(&[(b'b', b'c')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b'), (b'd', b'e'), (b'g', b'h')]); + let cls2 = bclass(&[(b'a', b'h')]); + let expected = bclass(&[(b'a', b'b'), (b'd', b'e'), (b'g', b'h')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b'), (b'd', b'e'), (b'g', b'h')]); + let cls2 = bclass(&[(b'a', b'b'), (b'd', b'e'), (b'g', b'h')]); + let expected = bclass(&[(b'a', b'b'), (b'd', b'e'), (b'g', b'h')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b'), (b'g', b'h')]); + let cls2 = bclass(&[(b'd', b'e'), (b'k', b'l')]); + let expected = bclass(&[]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b'), (b'd', b'e'), (b'g', b'h')]); + let cls2 = bclass(&[(b'h', b'h')]); + let expected = bclass(&[(b'h', b'h')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b'), (b'e', b'f'), (b'i', b'j')]); + let cls2 = bclass(&[(b'c', b'd'), (b'g', b'h'), (b'k', b'l')]); + let expected = bclass(&[]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b'), (b'c', b'd'), (b'e', b'f')]); + let cls2 = bclass(&[(b'b', b'c'), (b'd', b'e'), (b'f', b'g')]); + let expected = bclass(&[(b'b', b'f')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + } + + #[test] + fn class_difference_unicode() { + let cls1 = uclass(&[('a', 'a')]); + let cls2 = uclass(&[('a', 'a')]); + let expected = uclass(&[]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'a')]); + let cls2 = uclass(&[]); + let expected = uclass(&[('a', 'a')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[]); + let cls2 = uclass(&[('a', 'a')]); + let expected = uclass(&[]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'z')]); + let cls2 = uclass(&[('a', 'a')]); + let expected = uclass(&[('b', 'z')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'z')]); + let cls2 = uclass(&[('z', 'z')]); + let expected = uclass(&[('a', 'y')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'z')]); + let cls2 = uclass(&[('m', 'm')]); + let expected = uclass(&[('a', 'l'), ('n', 'z')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'c'), ('g', 'i'), ('r', 't')]); + let cls2 = uclass(&[('a', 'z')]); + let expected = uclass(&[]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'c'), ('g', 'i'), ('r', 't')]); + let cls2 = uclass(&[('d', 'v')]); + let expected = uclass(&[('a', 'c')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'c'), ('g', 'i'), ('r', 't')]); + let cls2 = uclass(&[('b', 'g'), ('s', 'u')]); + let expected = uclass(&[('a', 'a'), ('h', 'i'), ('r', 'r')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'c'), ('g', 'i'), ('r', 't')]); + let cls2 = uclass(&[('b', 'd'), ('e', 'g'), ('s', 'u')]); + let expected = uclass(&[('a', 'a'), ('h', 'i'), ('r', 'r')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('x', 'z')]); + let cls2 = uclass(&[('a', 'c'), ('e', 'g'), ('s', 'u')]); + let expected = uclass(&[('x', 'z')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'z')]); + let cls2 = uclass(&[('a', 'c'), ('e', 'g'), ('s', 'u')]); + let expected = uclass(&[('d', 'd'), ('h', 'r'), ('v', 'z')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + } + + #[test] + fn class_difference_bytes() { + let cls1 = bclass(&[(b'a', b'a')]); + let cls2 = bclass(&[(b'a', b'a')]); + let expected = bclass(&[]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'a')]); + let cls2 = bclass(&[]); + let expected = bclass(&[(b'a', b'a')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[]); + let cls2 = bclass(&[(b'a', b'a')]); + let expected = bclass(&[]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'z')]); + let cls2 = bclass(&[(b'a', b'a')]); + let expected = bclass(&[(b'b', b'z')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'z')]); + let cls2 = bclass(&[(b'z', b'z')]); + let expected = bclass(&[(b'a', b'y')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'z')]); + let cls2 = bclass(&[(b'm', b'm')]); + let expected = bclass(&[(b'a', b'l'), (b'n', b'z')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'c'), (b'g', b'i'), (b'r', b't')]); + let cls2 = bclass(&[(b'a', b'z')]); + let expected = bclass(&[]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'c'), (b'g', b'i'), (b'r', b't')]); + let cls2 = bclass(&[(b'd', b'v')]); + let expected = bclass(&[(b'a', b'c')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'c'), (b'g', b'i'), (b'r', b't')]); + let cls2 = bclass(&[(b'b', b'g'), (b's', b'u')]); + let expected = bclass(&[(b'a', b'a'), (b'h', b'i'), (b'r', b'r')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'c'), (b'g', b'i'), (b'r', b't')]); + let cls2 = bclass(&[(b'b', b'd'), (b'e', b'g'), (b's', b'u')]); + let expected = bclass(&[(b'a', b'a'), (b'h', b'i'), (b'r', b'r')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'x', b'z')]); + let cls2 = bclass(&[(b'a', b'c'), (b'e', b'g'), (b's', b'u')]); + let expected = bclass(&[(b'x', b'z')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'z')]); + let cls2 = bclass(&[(b'a', b'c'), (b'e', b'g'), (b's', b'u')]); + let expected = bclass(&[(b'd', b'd'), (b'h', b'r'), (b'v', b'z')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + } + + #[test] + fn class_symmetric_difference_unicode() { + let cls1 = uclass(&[('a', 'm')]); + let cls2 = uclass(&[('g', 't')]); + let expected = uclass(&[('a', 'f'), ('n', 't')]); + assert_eq!(expected, usymdifference(&cls1, &cls2)); + } + + #[test] + fn class_symmetric_difference_bytes() { + let cls1 = bclass(&[(b'a', b'm')]); + let cls2 = bclass(&[(b'g', b't')]); + let expected = bclass(&[(b'a', b'f'), (b'n', b't')]); + assert_eq!(expected, bsymdifference(&cls1, &cls2)); + } + + // We use a thread with an explicit stack size to test that our destructor + // for Hir can handle arbitrarily sized expressions in constant stack + // space. In case we run on a platform without threads (WASM?), we limit + // this test to Windows/Unix. + #[test] + #[cfg(any(unix, windows))] + fn no_stack_overflow_on_drop() { + use std::thread; + + let run = || { + let mut expr = Hir::empty(); + for _ in 0..100 { + expr = Hir::capture(Capture { + index: 1, + name: None, + sub: Box::new(expr), + }); + expr = Hir::repetition(Repetition { + min: 0, + max: Some(1), + greedy: true, + sub: Box::new(expr), + }); + + expr = Hir { + kind: HirKind::Concat(vec![expr]), + props: Properties::empty(), + }; + expr = Hir { + kind: HirKind::Alternation(vec![expr]), + props: Properties::empty(), + }; + } + assert!(!matches!(*expr.kind(), HirKind::Empty)); + }; + + // We run our test on a thread with a small stack size so we can + // force the issue more easily. + // + // NOTE(2023-03-21): See the corresponding test in 'crate::ast::tests' + // for context on the specific stack size chosen here. + thread::Builder::new() + .stack_size(16 << 10) + .spawn(run) + .unwrap() + .join() + .unwrap(); + } + + #[test] + fn look_set_iter() { + let set = LookSet::empty(); + assert_eq!(0, set.iter().count()); + + let set = LookSet::full(); + assert_eq!(10, set.iter().count()); + + let set = + LookSet::empty().insert(Look::StartLF).insert(Look::WordUnicode); + assert_eq!(2, set.iter().count()); + + let set = LookSet::empty().insert(Look::StartLF); + assert_eq!(1, set.iter().count()); + + let set = LookSet::empty().insert(Look::WordAsciiNegate); + assert_eq!(1, set.iter().count()); + } + + #[test] + fn look_set_debug() { + let res = format!("{:?}", LookSet::empty()); + assert_eq!("∅", res); + let res = format!("{:?}", LookSet::full()); + assert_eq!("Az^$rRbBð›ƒðš©", res); + } +} diff --git a/vendor/regex-syntax-0.7.5/src/hir/print.rs b/vendor/regex-syntax-0.7.5/src/hir/print.rs new file mode 100644 index 0000000000000..aa737a092dbcd --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/hir/print.rs @@ -0,0 +1,584 @@ +/*! +This module provides a regular expression printer for `Hir`. +*/ + +use core::fmt; + +use crate::{ + hir::{ + self, + visitor::{self, Visitor}, + Hir, HirKind, + }, + is_meta_character, +}; + +/// A builder for constructing a printer. +/// +/// Note that since a printer doesn't have any configuration knobs, this type +/// remains unexported. +#[derive(Clone, Debug)] +struct PrinterBuilder { + _priv: (), +} + +impl Default for PrinterBuilder { + fn default() -> PrinterBuilder { + PrinterBuilder::new() + } +} + +impl PrinterBuilder { + fn new() -> PrinterBuilder { + PrinterBuilder { _priv: () } + } + + fn build(&self) -> Printer { + Printer { _priv: () } + } +} + +/// A printer for a regular expression's high-level intermediate +/// representation. +/// +/// A printer converts a high-level intermediate representation (HIR) to a +/// regular expression pattern string. This particular printer uses constant +/// stack space and heap space proportional to the size of the HIR. +/// +/// Since this printer is only using the HIR, the pattern it prints will likely +/// not resemble the original pattern at all. For example, a pattern like +/// `\pL` will have its entire class written out. +/// +/// The purpose of this printer is to provide a means to mutate an HIR and then +/// build a regular expression from the result of that mutation. (A regex +/// library could provide a constructor from this HIR explicitly, but that +/// creates an unnecessary public coupling between the regex library and this +/// specific HIR representation.) +#[derive(Debug)] +pub struct Printer { + _priv: (), +} + +impl Printer { + /// Create a new printer. + pub fn new() -> Printer { + PrinterBuilder::new().build() + } + + /// Print the given `Ast` to the given writer. The writer must implement + /// `fmt::Write`. Typical implementations of `fmt::Write` that can be used + /// here are a `fmt::Formatter` (which is available in `fmt::Display` + /// implementations) or a `&mut String`. + pub fn print(&mut self, hir: &Hir, wtr: W) -> fmt::Result { + visitor::visit(hir, Writer { wtr }) + } +} + +#[derive(Debug)] +struct Writer { + wtr: W, +} + +impl Visitor for Writer { + type Output = (); + type Err = fmt::Error; + + fn finish(self) -> fmt::Result { + Ok(()) + } + + fn visit_pre(&mut self, hir: &Hir) -> fmt::Result { + match *hir.kind() { + HirKind::Empty => { + // Technically an empty sub-expression could be "printed" by + // just ignoring it, but in practice, you could have a + // repetition operator attached to an empty expression, and you + // really need something in the concrete syntax to make that + // work as you'd expect. + self.wtr.write_str(r"(?:)")?; + } + // Repetition operators are strictly suffix oriented. + HirKind::Repetition(_) => {} + HirKind::Literal(hir::Literal(ref bytes)) => { + // See the comment on the 'Concat' and 'Alternation' case below + // for why we put parens here. Literals are, conceptually, + // a special case of concatenation where each element is a + // character. The HIR flattens this into a Box<[u8]>, but we + // still need to treat it like a concatenation for correct + // printing. As a special case, we don't write parens if there + // is only one character. One character means there is no + // concat so we don't need parens. Adding parens would still be + // correct, but we drop them here because it tends to create + // rather noisy regexes even in simple cases. + let result = core::str::from_utf8(bytes); + let len = result.map_or(bytes.len(), |s| s.chars().count()); + if len > 1 { + self.wtr.write_str(r"(?:")?; + } + match result { + Ok(string) => { + for c in string.chars() { + self.write_literal_char(c)?; + } + } + Err(_) => { + for &b in bytes.iter() { + self.write_literal_byte(b)?; + } + } + } + if len > 1 { + self.wtr.write_str(r")")?; + } + } + HirKind::Class(hir::Class::Unicode(ref cls)) => { + if cls.ranges().is_empty() { + return self.wtr.write_str("[a&&b]"); + } + self.wtr.write_str("[")?; + for range in cls.iter() { + if range.start() == range.end() { + self.write_literal_char(range.start())?; + } else if u32::from(range.start()) + 1 + == u32::from(range.end()) + { + self.write_literal_char(range.start())?; + self.write_literal_char(range.end())?; + } else { + self.write_literal_char(range.start())?; + self.wtr.write_str("-")?; + self.write_literal_char(range.end())?; + } + } + self.wtr.write_str("]")?; + } + HirKind::Class(hir::Class::Bytes(ref cls)) => { + if cls.ranges().is_empty() { + return self.wtr.write_str("[a&&b]"); + } + self.wtr.write_str("(?-u:[")?; + for range in cls.iter() { + if range.start() == range.end() { + self.write_literal_class_byte(range.start())?; + } else if range.start() + 1 == range.end() { + self.write_literal_class_byte(range.start())?; + self.write_literal_class_byte(range.end())?; + } else { + self.write_literal_class_byte(range.start())?; + self.wtr.write_str("-")?; + self.write_literal_class_byte(range.end())?; + } + } + self.wtr.write_str("])")?; + } + HirKind::Look(ref look) => match *look { + hir::Look::Start => { + self.wtr.write_str(r"\A")?; + } + hir::Look::End => { + self.wtr.write_str(r"\z")?; + } + hir::Look::StartLF => { + self.wtr.write_str("(?m:^)")?; + } + hir::Look::EndLF => { + self.wtr.write_str("(?m:$)")?; + } + hir::Look::StartCRLF => { + self.wtr.write_str("(?mR:^)")?; + } + hir::Look::EndCRLF => { + self.wtr.write_str("(?mR:$)")?; + } + hir::Look::WordAscii => { + self.wtr.write_str(r"(?-u:\b)")?; + } + hir::Look::WordAsciiNegate => { + self.wtr.write_str(r"(?-u:\B)")?; + } + hir::Look::WordUnicode => { + self.wtr.write_str(r"\b")?; + } + hir::Look::WordUnicodeNegate => { + self.wtr.write_str(r"\B")?; + } + }, + HirKind::Capture(hir::Capture { ref name, .. }) => { + self.wtr.write_str("(")?; + if let Some(ref name) = *name { + write!(self.wtr, "?P<{}>", name)?; + } + } + // Why do this? Wrapping concats and alts in non-capturing groups + // is not *always* necessary, but is sometimes necessary. For + // example, 'concat(a, alt(b, c))' should be written as 'a(?:b|c)' + // and not 'ab|c'. The former is clearly the intended meaning, but + // the latter is actually 'alt(concat(a, b), c)'. + // + // It would be possible to only group these things in cases where + // it's strictly necessary, but it requires knowing the parent + // expression. And since this technique is simpler and always + // correct, we take this route. More to the point, it is a non-goal + // of an HIR printer to show a nice easy-to-read regex. Indeed, + // its construction forbids it from doing so. Therefore, inserting + // extra groups where they aren't necessary is perfectly okay. + HirKind::Concat(_) | HirKind::Alternation(_) => { + self.wtr.write_str(r"(?:")?; + } + } + Ok(()) + } + + fn visit_post(&mut self, hir: &Hir) -> fmt::Result { + match *hir.kind() { + // Handled during visit_pre + HirKind::Empty + | HirKind::Literal(_) + | HirKind::Class(_) + | HirKind::Look(_) => {} + HirKind::Repetition(ref x) => { + match (x.min, x.max) { + (0, Some(1)) => { + self.wtr.write_str("?")?; + } + (0, None) => { + self.wtr.write_str("*")?; + } + (1, None) => { + self.wtr.write_str("+")?; + } + (1, Some(1)) => { + // 'a{1}' and 'a{1}?' are exactly equivalent to 'a'. + return Ok(()); + } + (m, None) => { + write!(self.wtr, "{{{},}}", m)?; + } + (m, Some(n)) if m == n => { + write!(self.wtr, "{{{}}}", m)?; + // a{m} and a{m}? are always exactly equivalent. + return Ok(()); + } + (m, Some(n)) => { + write!(self.wtr, "{{{},{}}}", m, n)?; + } + } + if !x.greedy { + self.wtr.write_str("?")?; + } + } + HirKind::Capture(_) + | HirKind::Concat(_) + | HirKind::Alternation(_) => { + self.wtr.write_str(r")")?; + } + } + Ok(()) + } + + fn visit_alternation_in(&mut self) -> fmt::Result { + self.wtr.write_str("|") + } +} + +impl Writer { + fn write_literal_char(&mut self, c: char) -> fmt::Result { + if is_meta_character(c) { + self.wtr.write_str("\\")?; + } + self.wtr.write_char(c) + } + + fn write_literal_byte(&mut self, b: u8) -> fmt::Result { + if b <= 0x7F && !b.is_ascii_control() && !b.is_ascii_whitespace() { + self.write_literal_char(char::try_from(b).unwrap()) + } else { + write!(self.wtr, "(?-u:\\x{:02X})", b) + } + } + + fn write_literal_class_byte(&mut self, b: u8) -> fmt::Result { + if b <= 0x7F && !b.is_ascii_control() && !b.is_ascii_whitespace() { + self.write_literal_char(char::try_from(b).unwrap()) + } else { + write!(self.wtr, "\\x{:02X}", b) + } + } +} + +#[cfg(test)] +mod tests { + use alloc::{ + boxed::Box, + string::{String, ToString}, + }; + + use crate::ParserBuilder; + + use super::*; + + fn roundtrip(given: &str, expected: &str) { + roundtrip_with(|b| b, given, expected); + } + + fn roundtrip_bytes(given: &str, expected: &str) { + roundtrip_with(|b| b.utf8(false), given, expected); + } + + fn roundtrip_with(mut f: F, given: &str, expected: &str) + where + F: FnMut(&mut ParserBuilder) -> &mut ParserBuilder, + { + let mut builder = ParserBuilder::new(); + f(&mut builder); + let hir = builder.build().parse(given).unwrap(); + + let mut printer = Printer::new(); + let mut dst = String::new(); + printer.print(&hir, &mut dst).unwrap(); + + // Check that the result is actually valid. + builder.build().parse(&dst).unwrap(); + + assert_eq!(expected, dst); + } + + #[test] + fn print_literal() { + roundtrip("a", "a"); + roundtrip(r"\xff", "\u{FF}"); + roundtrip_bytes(r"\xff", "\u{FF}"); + roundtrip_bytes(r"(?-u)\xff", r"(?-u:\xFF)"); + roundtrip("☃", "☃"); + } + + #[test] + fn print_class() { + roundtrip(r"[a]", r"a"); + roundtrip(r"[ab]", r"[ab]"); + roundtrip(r"[a-z]", r"[a-z]"); + roundtrip(r"[a-z--b-c--x-y]", r"[ad-wz]"); + roundtrip(r"[^\x01-\u{10FFFF}]", "\u{0}"); + roundtrip(r"[-]", r"\-"); + roundtrip(r"[☃-⛄]", r"[☃-⛄]"); + + roundtrip(r"(?-u)[a]", r"a"); + roundtrip(r"(?-u)[ab]", r"(?-u:[ab])"); + roundtrip(r"(?-u)[a-z]", r"(?-u:[a-z])"); + roundtrip_bytes(r"(?-u)[a-\xFF]", r"(?-u:[a-\xFF])"); + + // The following test that the printer escapes meta characters + // in character classes. + roundtrip(r"[\[]", r"\["); + roundtrip(r"[Z-_]", r"[Z-_]"); + roundtrip(r"[Z-_--Z]", r"[\[-_]"); + + // The following test that the printer escapes meta characters + // in byte oriented character classes. + roundtrip_bytes(r"(?-u)[\[]", r"\["); + roundtrip_bytes(r"(?-u)[Z-_]", r"(?-u:[Z-_])"); + roundtrip_bytes(r"(?-u)[Z-_--Z]", r"(?-u:[\[-_])"); + + // This tests that an empty character class is correctly roundtripped. + #[cfg(feature = "unicode-gencat")] + roundtrip(r"\P{any}", r"[a&&b]"); + roundtrip_bytes(r"(?-u)[^\x00-\xFF]", r"[a&&b]"); + } + + #[test] + fn print_anchor() { + roundtrip(r"^", r"\A"); + roundtrip(r"$", r"\z"); + roundtrip(r"(?m)^", r"(?m:^)"); + roundtrip(r"(?m)$", r"(?m:$)"); + } + + #[test] + fn print_word_boundary() { + roundtrip(r"\b", r"\b"); + roundtrip(r"\B", r"\B"); + roundtrip(r"(?-u)\b", r"(?-u:\b)"); + roundtrip_bytes(r"(?-u)\B", r"(?-u:\B)"); + } + + #[test] + fn print_repetition() { + roundtrip("a?", "a?"); + roundtrip("a??", "a??"); + roundtrip("(?U)a?", "a??"); + + roundtrip("a*", "a*"); + roundtrip("a*?", "a*?"); + roundtrip("(?U)a*", "a*?"); + + roundtrip("a+", "a+"); + roundtrip("a+?", "a+?"); + roundtrip("(?U)a+", "a+?"); + + roundtrip("a{1}", "a"); + roundtrip("a{2}", "a{2}"); + roundtrip("a{1,}", "a+"); + roundtrip("a{1,5}", "a{1,5}"); + roundtrip("a{1}?", "a"); + roundtrip("a{2}?", "a{2}"); + roundtrip("a{1,}?", "a+?"); + roundtrip("a{1,5}?", "a{1,5}?"); + roundtrip("(?U)a{1}", "a"); + roundtrip("(?U)a{2}", "a{2}"); + roundtrip("(?U)a{1,}", "a+?"); + roundtrip("(?U)a{1,5}", "a{1,5}?"); + + // Test that various zero-length repetitions always translate to an + // empty regex. This is more a property of HIR's smart constructors + // than the printer though. + roundtrip("a{0}", "(?:)"); + roundtrip("(?:ab){0}", "(?:)"); + #[cfg(feature = "unicode-gencat")] + { + roundtrip(r"\p{any}{0}", "(?:)"); + roundtrip(r"\P{any}{0}", "(?:)"); + } + } + + #[test] + fn print_group() { + roundtrip("()", "((?:))"); + roundtrip("(?P)", "(?P(?:))"); + roundtrip("(?:)", "(?:)"); + + roundtrip("(a)", "(a)"); + roundtrip("(?Pa)", "(?Pa)"); + roundtrip("(?:a)", "a"); + + roundtrip("((((a))))", "((((a))))"); + } + + #[test] + fn print_alternation() { + roundtrip("|", "(?:(?:)|(?:))"); + roundtrip("||", "(?:(?:)|(?:)|(?:))"); + + roundtrip("a|b", "[ab]"); + roundtrip("ab|cd", "(?:(?:ab)|(?:cd))"); + roundtrip("a|b|c", "[a-c]"); + roundtrip("ab|cd|ef", "(?:(?:ab)|(?:cd)|(?:ef))"); + roundtrip("foo|bar|quux", "(?:(?:foo)|(?:bar)|(?:quux))"); + } + + // This is a regression test that stresses a peculiarity of how the HIR + // is both constructed and printed. Namely, it is legal for a repetition + // to directly contain a concatenation. This particular construct isn't + // really possible to build from the concrete syntax directly, since you'd + // be forced to put the concatenation into (at least) a non-capturing + // group. Concurrently, the printer doesn't consider this case and just + // kind of naively prints the child expression and tacks on the repetition + // operator. + // + // As a result, if you attached '+' to a 'concat(a, b)', the printer gives + // you 'ab+', but clearly it really should be '(?:ab)+'. + // + // This bug isn't easy to surface because most ways of building an HIR + // come directly from the concrete syntax, and as mentioned above, it just + // isn't possible to build this kind of HIR from the concrete syntax. + // Nevertheless, this is definitely a bug. + // + // See: https://github.com/rust-lang/regex/issues/731 + #[test] + fn regression_repetition_concat() { + let expr = Hir::concat(alloc::vec![ + Hir::literal("x".as_bytes()), + Hir::repetition(hir::Repetition { + min: 1, + max: None, + greedy: true, + sub: Box::new(Hir::literal("ab".as_bytes())), + }), + Hir::literal("y".as_bytes()), + ]); + assert_eq!(r"(?:x(?:ab)+y)", expr.to_string()); + + let expr = Hir::concat(alloc::vec![ + Hir::look(hir::Look::Start), + Hir::repetition(hir::Repetition { + min: 1, + max: None, + greedy: true, + sub: Box::new(Hir::concat(alloc::vec![ + Hir::look(hir::Look::Start), + Hir::look(hir::Look::End), + ])), + }), + Hir::look(hir::Look::End), + ]); + assert_eq!(r"(?:\A\A\z\z)", expr.to_string()); + } + + // Just like regression_repetition_concat, but with the repetition using + // an alternation as a child expression instead. + // + // See: https://github.com/rust-lang/regex/issues/731 + #[test] + fn regression_repetition_alternation() { + let expr = Hir::concat(alloc::vec![ + Hir::literal("ab".as_bytes()), + Hir::repetition(hir::Repetition { + min: 1, + max: None, + greedy: true, + sub: Box::new(Hir::alternation(alloc::vec![ + Hir::literal("cd".as_bytes()), + Hir::literal("ef".as_bytes()), + ])), + }), + Hir::literal("gh".as_bytes()), + ]); + assert_eq!(r"(?:(?:ab)(?:(?:cd)|(?:ef))+(?:gh))", expr.to_string()); + + let expr = Hir::concat(alloc::vec![ + Hir::look(hir::Look::Start), + Hir::repetition(hir::Repetition { + min: 1, + max: None, + greedy: true, + sub: Box::new(Hir::alternation(alloc::vec![ + Hir::look(hir::Look::Start), + Hir::look(hir::Look::End), + ])), + }), + Hir::look(hir::Look::End), + ]); + assert_eq!(r"(?:\A(?:\A|\z)\z)", expr.to_string()); + } + + // This regression test is very similar in flavor to + // regression_repetition_concat in that the root of the issue lies in a + // peculiarity of how the HIR is represented and how the printer writes it + // out. Like the other regression, this one is also rooted in the fact that + // you can't produce the peculiar HIR from the concrete syntax. Namely, you + // just can't have a 'concat(a, alt(b, c))' because the 'alt' will normally + // be in (at least) a non-capturing group. Why? Because the '|' has very + // low precedence (lower that concatenation), and so something like 'ab|c' + // is actually 'alt(ab, c)'. + // + // See: https://github.com/rust-lang/regex/issues/516 + #[test] + fn regression_alternation_concat() { + let expr = Hir::concat(alloc::vec![ + Hir::literal("ab".as_bytes()), + Hir::alternation(alloc::vec![ + Hir::literal("mn".as_bytes()), + Hir::literal("xy".as_bytes()), + ]), + ]); + assert_eq!(r"(?:(?:ab)(?:(?:mn)|(?:xy)))", expr.to_string()); + + let expr = Hir::concat(alloc::vec![ + Hir::look(hir::Look::Start), + Hir::alternation(alloc::vec![ + Hir::look(hir::Look::Start), + Hir::look(hir::Look::End), + ]), + ]); + assert_eq!(r"(?:\A(?:\A|\z))", expr.to_string()); + } +} diff --git a/vendor/regex-syntax-0.7.5/src/hir/translate.rs b/vendor/regex-syntax-0.7.5/src/hir/translate.rs new file mode 100644 index 0000000000000..5430b51b27a51 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/hir/translate.rs @@ -0,0 +1,3629 @@ +/*! +Defines a translator that converts an `Ast` to an `Hir`. +*/ + +use core::cell::{Cell, RefCell}; + +use alloc::{boxed::Box, string::ToString, vec, vec::Vec}; + +use crate::{ + ast::{self, Ast, Span, Visitor}, + either::Either, + hir::{self, Error, ErrorKind, Hir, HirKind}, + unicode::{self, ClassQuery}, +}; + +type Result = core::result::Result; + +/// A builder for constructing an AST->HIR translator. +#[derive(Clone, Debug)] +pub struct TranslatorBuilder { + utf8: bool, + line_terminator: u8, + flags: Flags, +} + +impl Default for TranslatorBuilder { + fn default() -> TranslatorBuilder { + TranslatorBuilder::new() + } +} + +impl TranslatorBuilder { + /// Create a new translator builder with a default c onfiguration. + pub fn new() -> TranslatorBuilder { + TranslatorBuilder { + utf8: true, + line_terminator: b'\n', + flags: Flags::default(), + } + } + + /// Build a translator using the current configuration. + pub fn build(&self) -> Translator { + Translator { + stack: RefCell::new(vec![]), + flags: Cell::new(self.flags), + utf8: self.utf8, + line_terminator: self.line_terminator, + } + } + + /// When disabled, translation will permit the construction of a regular + /// expression that may match invalid UTF-8. + /// + /// When enabled (the default), the translator is guaranteed to produce an + /// expression that, for non-empty matches, will only ever produce spans + /// that are entirely valid UTF-8 (otherwise, the translator will return an + /// error). + /// + /// Perhaps surprisingly, when UTF-8 is enabled, an empty regex or even + /// a negated ASCII word boundary (uttered as `(?-u:\B)` in the concrete + /// syntax) will be allowed even though they can produce matches that split + /// a UTF-8 encoded codepoint. This only applies to zero-width or "empty" + /// matches, and it is expected that the regex engine itself must handle + /// these cases if necessary (perhaps by suppressing any zero-width matches + /// that split a codepoint). + pub fn utf8(&mut self, yes: bool) -> &mut TranslatorBuilder { + self.utf8 = yes; + self + } + + /// Sets the line terminator for use with `(?u-s:.)` and `(?-us:.)`. + /// + /// Namely, instead of `.` (by default) matching everything except for `\n`, + /// this will cause `.` to match everything except for the byte given. + /// + /// If `.` is used in a context where Unicode mode is enabled and this byte + /// isn't ASCII, then an error will be returned. When Unicode mode is + /// disabled, then any byte is permitted, but will return an error if UTF-8 + /// mode is enabled and it is a non-ASCII byte. + /// + /// In short, any ASCII value for a line terminator is always okay. But a + /// non-ASCII byte might result in an error depending on whether Unicode + /// mode or UTF-8 mode are enabled. + /// + /// Note that if `R` mode is enabled then it always takes precedence and + /// the line terminator will be treated as `\r` and `\n` simultaneously. + /// + /// Note also that this *doesn't* impact the look-around assertions + /// `(?m:^)` and `(?m:$)`. That's usually controlled by additional + /// configuration in the regex engine itself. + pub fn line_terminator(&mut self, byte: u8) -> &mut TranslatorBuilder { + self.line_terminator = byte; + self + } + + /// Enable or disable the case insensitive flag (`i`) by default. + pub fn case_insensitive(&mut self, yes: bool) -> &mut TranslatorBuilder { + self.flags.case_insensitive = if yes { Some(true) } else { None }; + self + } + + /// Enable or disable the multi-line matching flag (`m`) by default. + pub fn multi_line(&mut self, yes: bool) -> &mut TranslatorBuilder { + self.flags.multi_line = if yes { Some(true) } else { None }; + self + } + + /// Enable or disable the "dot matches any character" flag (`s`) by + /// default. + pub fn dot_matches_new_line( + &mut self, + yes: bool, + ) -> &mut TranslatorBuilder { + self.flags.dot_matches_new_line = if yes { Some(true) } else { None }; + self + } + + /// Enable or disable the CRLF mode flag (`R`) by default. + pub fn crlf(&mut self, yes: bool) -> &mut TranslatorBuilder { + self.flags.crlf = if yes { Some(true) } else { None }; + self + } + + /// Enable or disable the "swap greed" flag (`U`) by default. + pub fn swap_greed(&mut self, yes: bool) -> &mut TranslatorBuilder { + self.flags.swap_greed = if yes { Some(true) } else { None }; + self + } + + /// Enable or disable the Unicode flag (`u`) by default. + pub fn unicode(&mut self, yes: bool) -> &mut TranslatorBuilder { + self.flags.unicode = if yes { None } else { Some(false) }; + self + } +} + +/// A translator maps abstract syntax to a high level intermediate +/// representation. +/// +/// A translator may be benefit from reuse. That is, a translator can translate +/// many abstract syntax trees. +/// +/// A `Translator` can be configured in more detail via a +/// [`TranslatorBuilder`]. +#[derive(Clone, Debug)] +pub struct Translator { + /// Our call stack, but on the heap. + stack: RefCell>, + /// The current flag settings. + flags: Cell, + /// Whether we're allowed to produce HIR that can match arbitrary bytes. + utf8: bool, + /// The line terminator to use for `.`. + line_terminator: u8, +} + +impl Translator { + /// Create a new translator using the default configuration. + pub fn new() -> Translator { + TranslatorBuilder::new().build() + } + + /// Translate the given abstract syntax tree (AST) into a high level + /// intermediate representation (HIR). + /// + /// If there was a problem doing the translation, then an HIR-specific + /// error is returned. + /// + /// The original pattern string used to produce the `Ast` *must* also be + /// provided. The translator does not use the pattern string during any + /// correct translation, but is used for error reporting. + pub fn translate(&mut self, pattern: &str, ast: &Ast) -> Result { + ast::visit(ast, TranslatorI::new(self, pattern)) + } +} + +/// An HirFrame is a single stack frame, represented explicitly, which is +/// created for each item in the Ast that we traverse. +/// +/// Note that technically, this type doesn't represent our entire stack +/// frame. In particular, the Ast visitor represents any state associated with +/// traversing the Ast itself. +#[derive(Clone, Debug)] +enum HirFrame { + /// An arbitrary HIR expression. These get pushed whenever we hit a base + /// case in the Ast. They get popped after an inductive (i.e., recursive) + /// step is complete. + Expr(Hir), + /// A literal that is being constructed, character by character, from the + /// AST. We need this because the AST gives each individual character its + /// own node. So as we see characters, we peek at the top-most HirFrame. + /// If it's a literal, then we add to it. Otherwise, we push a new literal. + /// When it comes time to pop it, we convert it to an Hir via Hir::literal. + Literal(Vec), + /// A Unicode character class. This frame is mutated as we descend into + /// the Ast of a character class (which is itself its own mini recursive + /// structure). + ClassUnicode(hir::ClassUnicode), + /// A byte-oriented character class. This frame is mutated as we descend + /// into the Ast of a character class (which is itself its own mini + /// recursive structure). + /// + /// Byte character classes are created when Unicode mode (`u`) is disabled. + /// If `utf8` is enabled (the default), then a byte character is only + /// permitted to match ASCII text. + ClassBytes(hir::ClassBytes), + /// This is pushed whenever a repetition is observed. After visiting every + /// sub-expression in the repetition, the translator's stack is expected to + /// have this sentinel at the top. + /// + /// This sentinel only exists to stop other things (like flattening + /// literals) from reaching across repetition operators. + Repetition, + /// This is pushed on to the stack upon first seeing any kind of capture, + /// indicated by parentheses (including non-capturing groups). It is popped + /// upon leaving a group. + Group { + /// The old active flags when this group was opened. + /// + /// If this group sets flags, then the new active flags are set to the + /// result of merging the old flags with the flags introduced by this + /// group. If the group doesn't set any flags, then this is simply + /// equivalent to whatever flags were set when the group was opened. + /// + /// When this group is popped, the active flags should be restored to + /// the flags set here. + /// + /// The "active" flags correspond to whatever flags are set in the + /// Translator. + old_flags: Flags, + }, + /// This is pushed whenever a concatenation is observed. After visiting + /// every sub-expression in the concatenation, the translator's stack is + /// popped until it sees a Concat frame. + Concat, + /// This is pushed whenever an alternation is observed. After visiting + /// every sub-expression in the alternation, the translator's stack is + /// popped until it sees an Alternation frame. + Alternation, + /// This is pushed immediately before each sub-expression in an + /// alternation. This separates the branches of an alternation on the + /// stack and prevents literal flattening from reaching across alternation + /// branches. + /// + /// It is popped after each expression in a branch until an 'Alternation' + /// frame is observed when doing a post visit on an alternation. + AlternationBranch, +} + +impl HirFrame { + /// Assert that the current stack frame is an Hir expression and return it. + fn unwrap_expr(self) -> Hir { + match self { + HirFrame::Expr(expr) => expr, + HirFrame::Literal(lit) => Hir::literal(lit), + _ => panic!("tried to unwrap expr from HirFrame, got: {:?}", self), + } + } + + /// Assert that the current stack frame is a Unicode class expression and + /// return it. + fn unwrap_class_unicode(self) -> hir::ClassUnicode { + match self { + HirFrame::ClassUnicode(cls) => cls, + _ => panic!( + "tried to unwrap Unicode class \ + from HirFrame, got: {:?}", + self + ), + } + } + + /// Assert that the current stack frame is a byte class expression and + /// return it. + fn unwrap_class_bytes(self) -> hir::ClassBytes { + match self { + HirFrame::ClassBytes(cls) => cls, + _ => panic!( + "tried to unwrap byte class \ + from HirFrame, got: {:?}", + self + ), + } + } + + /// Assert that the current stack frame is a repetition sentinel. If it + /// isn't, then panic. + fn unwrap_repetition(self) { + match self { + HirFrame::Repetition => {} + _ => { + panic!( + "tried to unwrap repetition from HirFrame, got: {:?}", + self + ) + } + } + } + + /// Assert that the current stack frame is a group indicator and return + /// its corresponding flags (the flags that were active at the time the + /// group was entered). + fn unwrap_group(self) -> Flags { + match self { + HirFrame::Group { old_flags } => old_flags, + _ => { + panic!("tried to unwrap group from HirFrame, got: {:?}", self) + } + } + } + + /// Assert that the current stack frame is an alternation pipe sentinel. If + /// it isn't, then panic. + fn unwrap_alternation_pipe(self) { + match self { + HirFrame::AlternationBranch => {} + _ => { + panic!( + "tried to unwrap alt pipe from HirFrame, got: {:?}", + self + ) + } + } + } +} + +impl<'t, 'p> Visitor for TranslatorI<'t, 'p> { + type Output = Hir; + type Err = Error; + + fn finish(self) -> Result { + // ... otherwise, we should have exactly one HIR on the stack. + assert_eq!(self.trans().stack.borrow().len(), 1); + Ok(self.pop().unwrap().unwrap_expr()) + } + + fn visit_pre(&mut self, ast: &Ast) -> Result<()> { + match *ast { + Ast::Class(ast::Class::Bracketed(_)) => { + if self.flags().unicode() { + let cls = hir::ClassUnicode::empty(); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let cls = hir::ClassBytes::empty(); + self.push(HirFrame::ClassBytes(cls)); + } + } + Ast::Repetition(_) => self.push(HirFrame::Repetition), + Ast::Group(ref x) => { + let old_flags = x + .flags() + .map(|ast| self.set_flags(ast)) + .unwrap_or_else(|| self.flags()); + self.push(HirFrame::Group { old_flags }); + } + Ast::Concat(ref x) if x.asts.is_empty() => {} + Ast::Concat(_) => { + self.push(HirFrame::Concat); + } + Ast::Alternation(ref x) if x.asts.is_empty() => {} + Ast::Alternation(_) => { + self.push(HirFrame::Alternation); + self.push(HirFrame::AlternationBranch); + } + _ => {} + } + Ok(()) + } + + fn visit_post(&mut self, ast: &Ast) -> Result<()> { + match *ast { + Ast::Empty(_) => { + self.push(HirFrame::Expr(Hir::empty())); + } + Ast::Flags(ref x) => { + self.set_flags(&x.flags); + // Flags in the AST are generally considered directives and + // not actual sub-expressions. However, they can be used in + // the concrete syntax like `((?i))`, and we need some kind of + // indication of an expression there, and Empty is the correct + // choice. + // + // There can also be things like `(?i)+`, but we rule those out + // in the parser. In the future, we might allow them for + // consistency sake. + self.push(HirFrame::Expr(Hir::empty())); + } + Ast::Literal(ref x) => { + match self.ast_literal_to_scalar(x)? { + Either::Right(byte) => self.push_byte(byte), + Either::Left(ch) => { + if !self.flags().unicode() && ch.len_utf8() > 1 { + return Err(self + .error(x.span, ErrorKind::UnicodeNotAllowed)); + } + match self.case_fold_char(x.span, ch)? { + None => self.push_char(ch), + Some(expr) => self.push(HirFrame::Expr(expr)), + } + } + } + // self.push(HirFrame::Expr(self.hir_literal(x)?)); + } + Ast::Dot(span) => { + self.push(HirFrame::Expr(self.hir_dot(span)?)); + } + Ast::Assertion(ref x) => { + self.push(HirFrame::Expr(self.hir_assertion(x)?)); + } + Ast::Class(ast::Class::Perl(ref x)) => { + if self.flags().unicode() { + let cls = self.hir_perl_unicode_class(x)?; + let hcls = hir::Class::Unicode(cls); + self.push(HirFrame::Expr(Hir::class(hcls))); + } else { + let cls = self.hir_perl_byte_class(x)?; + let hcls = hir::Class::Bytes(cls); + self.push(HirFrame::Expr(Hir::class(hcls))); + } + } + Ast::Class(ast::Class::Unicode(ref x)) => { + let cls = hir::Class::Unicode(self.hir_unicode_class(x)?); + self.push(HirFrame::Expr(Hir::class(cls))); + } + Ast::Class(ast::Class::Bracketed(ref ast)) => { + if self.flags().unicode() { + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + self.unicode_fold_and_negate( + &ast.span, + ast.negated, + &mut cls, + )?; + let expr = Hir::class(hir::Class::Unicode(cls)); + self.push(HirFrame::Expr(expr)); + } else { + let mut cls = self.pop().unwrap().unwrap_class_bytes(); + self.bytes_fold_and_negate( + &ast.span, + ast.negated, + &mut cls, + )?; + let expr = Hir::class(hir::Class::Bytes(cls)); + self.push(HirFrame::Expr(expr)); + } + } + Ast::Repetition(ref x) => { + let expr = self.pop().unwrap().unwrap_expr(); + self.pop().unwrap().unwrap_repetition(); + self.push(HirFrame::Expr(self.hir_repetition(x, expr))); + } + Ast::Group(ref x) => { + let expr = self.pop().unwrap().unwrap_expr(); + let old_flags = self.pop().unwrap().unwrap_group(); + self.trans().flags.set(old_flags); + self.push(HirFrame::Expr(self.hir_capture(x, expr))); + } + Ast::Concat(_) => { + let mut exprs = vec![]; + while let Some(expr) = self.pop_concat_expr() { + if !matches!(*expr.kind(), HirKind::Empty) { + exprs.push(expr); + } + } + exprs.reverse(); + self.push(HirFrame::Expr(Hir::concat(exprs))); + } + Ast::Alternation(_) => { + let mut exprs = vec![]; + while let Some(expr) = self.pop_alt_expr() { + self.pop().unwrap().unwrap_alternation_pipe(); + exprs.push(expr); + } + exprs.reverse(); + self.push(HirFrame::Expr(Hir::alternation(exprs))); + } + } + Ok(()) + } + + fn visit_alternation_in(&mut self) -> Result<()> { + self.push(HirFrame::AlternationBranch); + Ok(()) + } + + fn visit_class_set_item_pre( + &mut self, + ast: &ast::ClassSetItem, + ) -> Result<()> { + match *ast { + ast::ClassSetItem::Bracketed(_) => { + if self.flags().unicode() { + let cls = hir::ClassUnicode::empty(); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let cls = hir::ClassBytes::empty(); + self.push(HirFrame::ClassBytes(cls)); + } + } + // We needn't handle the Union case here since the visitor will + // do it for us. + _ => {} + } + Ok(()) + } + + fn visit_class_set_item_post( + &mut self, + ast: &ast::ClassSetItem, + ) -> Result<()> { + match *ast { + ast::ClassSetItem::Empty(_) => {} + ast::ClassSetItem::Literal(ref x) => { + if self.flags().unicode() { + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + cls.push(hir::ClassUnicodeRange::new(x.c, x.c)); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let mut cls = self.pop().unwrap().unwrap_class_bytes(); + let byte = self.class_literal_byte(x)?; + cls.push(hir::ClassBytesRange::new(byte, byte)); + self.push(HirFrame::ClassBytes(cls)); + } + } + ast::ClassSetItem::Range(ref x) => { + if self.flags().unicode() { + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + cls.push(hir::ClassUnicodeRange::new(x.start.c, x.end.c)); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let mut cls = self.pop().unwrap().unwrap_class_bytes(); + let start = self.class_literal_byte(&x.start)?; + let end = self.class_literal_byte(&x.end)?; + cls.push(hir::ClassBytesRange::new(start, end)); + self.push(HirFrame::ClassBytes(cls)); + } + } + ast::ClassSetItem::Ascii(ref x) => { + if self.flags().unicode() { + let xcls = self.hir_ascii_unicode_class(x)?; + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + cls.union(&xcls); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let xcls = self.hir_ascii_byte_class(x)?; + let mut cls = self.pop().unwrap().unwrap_class_bytes(); + cls.union(&xcls); + self.push(HirFrame::ClassBytes(cls)); + } + } + ast::ClassSetItem::Unicode(ref x) => { + let xcls = self.hir_unicode_class(x)?; + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + cls.union(&xcls); + self.push(HirFrame::ClassUnicode(cls)); + } + ast::ClassSetItem::Perl(ref x) => { + if self.flags().unicode() { + let xcls = self.hir_perl_unicode_class(x)?; + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + cls.union(&xcls); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let xcls = self.hir_perl_byte_class(x)?; + let mut cls = self.pop().unwrap().unwrap_class_bytes(); + cls.union(&xcls); + self.push(HirFrame::ClassBytes(cls)); + } + } + ast::ClassSetItem::Bracketed(ref ast) => { + if self.flags().unicode() { + let mut cls1 = self.pop().unwrap().unwrap_class_unicode(); + self.unicode_fold_and_negate( + &ast.span, + ast.negated, + &mut cls1, + )?; + + let mut cls2 = self.pop().unwrap().unwrap_class_unicode(); + cls2.union(&cls1); + self.push(HirFrame::ClassUnicode(cls2)); + } else { + let mut cls1 = self.pop().unwrap().unwrap_class_bytes(); + self.bytes_fold_and_negate( + &ast.span, + ast.negated, + &mut cls1, + )?; + + let mut cls2 = self.pop().unwrap().unwrap_class_bytes(); + cls2.union(&cls1); + self.push(HirFrame::ClassBytes(cls2)); + } + } + // This is handled automatically by the visitor. + ast::ClassSetItem::Union(_) => {} + } + Ok(()) + } + + fn visit_class_set_binary_op_pre( + &mut self, + _op: &ast::ClassSetBinaryOp, + ) -> Result<()> { + if self.flags().unicode() { + let cls = hir::ClassUnicode::empty(); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let cls = hir::ClassBytes::empty(); + self.push(HirFrame::ClassBytes(cls)); + } + Ok(()) + } + + fn visit_class_set_binary_op_in( + &mut self, + _op: &ast::ClassSetBinaryOp, + ) -> Result<()> { + if self.flags().unicode() { + let cls = hir::ClassUnicode::empty(); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let cls = hir::ClassBytes::empty(); + self.push(HirFrame::ClassBytes(cls)); + } + Ok(()) + } + + fn visit_class_set_binary_op_post( + &mut self, + op: &ast::ClassSetBinaryOp, + ) -> Result<()> { + use crate::ast::ClassSetBinaryOpKind::*; + + if self.flags().unicode() { + let mut rhs = self.pop().unwrap().unwrap_class_unicode(); + let mut lhs = self.pop().unwrap().unwrap_class_unicode(); + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + if self.flags().case_insensitive() { + rhs.try_case_fold_simple().map_err(|_| { + self.error( + op.rhs.span().clone(), + ErrorKind::UnicodeCaseUnavailable, + ) + })?; + lhs.try_case_fold_simple().map_err(|_| { + self.error( + op.lhs.span().clone(), + ErrorKind::UnicodeCaseUnavailable, + ) + })?; + } + match op.kind { + Intersection => lhs.intersect(&rhs), + Difference => lhs.difference(&rhs), + SymmetricDifference => lhs.symmetric_difference(&rhs), + } + cls.union(&lhs); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let mut rhs = self.pop().unwrap().unwrap_class_bytes(); + let mut lhs = self.pop().unwrap().unwrap_class_bytes(); + let mut cls = self.pop().unwrap().unwrap_class_bytes(); + if self.flags().case_insensitive() { + rhs.case_fold_simple(); + lhs.case_fold_simple(); + } + match op.kind { + Intersection => lhs.intersect(&rhs), + Difference => lhs.difference(&rhs), + SymmetricDifference => lhs.symmetric_difference(&rhs), + } + cls.union(&lhs); + self.push(HirFrame::ClassBytes(cls)); + } + Ok(()) + } +} + +/// The internal implementation of a translator. +/// +/// This type is responsible for carrying around the original pattern string, +/// which is not tied to the internal state of a translator. +/// +/// A TranslatorI exists for the time it takes to translate a single Ast. +#[derive(Clone, Debug)] +struct TranslatorI<'t, 'p> { + trans: &'t Translator, + pattern: &'p str, +} + +impl<'t, 'p> TranslatorI<'t, 'p> { + /// Build a new internal translator. + fn new(trans: &'t Translator, pattern: &'p str) -> TranslatorI<'t, 'p> { + TranslatorI { trans, pattern } + } + + /// Return a reference to the underlying translator. + fn trans(&self) -> &Translator { + &self.trans + } + + /// Push the given frame on to the call stack. + fn push(&self, frame: HirFrame) { + self.trans().stack.borrow_mut().push(frame); + } + + /// Push the given literal char on to the call stack. + /// + /// If the top-most element of the stack is a literal, then the char + /// is appended to the end of that literal. Otherwise, a new literal + /// containing just the given char is pushed to the top of the stack. + fn push_char(&self, ch: char) { + let mut buf = [0; 4]; + let bytes = ch.encode_utf8(&mut buf).as_bytes(); + let mut stack = self.trans().stack.borrow_mut(); + if let Some(HirFrame::Literal(ref mut literal)) = stack.last_mut() { + literal.extend_from_slice(bytes); + } else { + stack.push(HirFrame::Literal(bytes.to_vec())); + } + } + + /// Push the given literal byte on to the call stack. + /// + /// If the top-most element of the stack is a literal, then the byte + /// is appended to the end of that literal. Otherwise, a new literal + /// containing just the given byte is pushed to the top of the stack. + fn push_byte(&self, byte: u8) { + let mut stack = self.trans().stack.borrow_mut(); + if let Some(HirFrame::Literal(ref mut literal)) = stack.last_mut() { + literal.push(byte); + } else { + stack.push(HirFrame::Literal(vec![byte])); + } + } + + /// Pop the top of the call stack. If the call stack is empty, return None. + fn pop(&self) -> Option { + self.trans().stack.borrow_mut().pop() + } + + /// Pop an HIR expression from the top of the stack for a concatenation. + /// + /// This returns None if the stack is empty or when a concat frame is seen. + /// Otherwise, it panics if it could not find an HIR expression. + fn pop_concat_expr(&self) -> Option { + let frame = self.pop()?; + match frame { + HirFrame::Concat => None, + HirFrame::Expr(expr) => Some(expr), + HirFrame::Literal(lit) => Some(Hir::literal(lit)), + HirFrame::ClassUnicode(_) => { + unreachable!("expected expr or concat, got Unicode class") + } + HirFrame::ClassBytes(_) => { + unreachable!("expected expr or concat, got byte class") + } + HirFrame::Repetition => { + unreachable!("expected expr or concat, got repetition") + } + HirFrame::Group { .. } => { + unreachable!("expected expr or concat, got group") + } + HirFrame::Alternation => { + unreachable!("expected expr or concat, got alt marker") + } + HirFrame::AlternationBranch => { + unreachable!("expected expr or concat, got alt branch marker") + } + } + } + + /// Pop an HIR expression from the top of the stack for an alternation. + /// + /// This returns None if the stack is empty or when an alternation frame is + /// seen. Otherwise, it panics if it could not find an HIR expression. + fn pop_alt_expr(&self) -> Option { + let frame = self.pop()?; + match frame { + HirFrame::Alternation => None, + HirFrame::Expr(expr) => Some(expr), + HirFrame::Literal(lit) => Some(Hir::literal(lit)), + HirFrame::ClassUnicode(_) => { + unreachable!("expected expr or alt, got Unicode class") + } + HirFrame::ClassBytes(_) => { + unreachable!("expected expr or alt, got byte class") + } + HirFrame::Repetition => { + unreachable!("expected expr or alt, got repetition") + } + HirFrame::Group { .. } => { + unreachable!("expected expr or alt, got group") + } + HirFrame::Concat => { + unreachable!("expected expr or alt, got concat marker") + } + HirFrame::AlternationBranch => { + unreachable!("expected expr or alt, got alt branch marker") + } + } + } + + /// Create a new error with the given span and error type. + fn error(&self, span: Span, kind: ErrorKind) -> Error { + Error { kind, pattern: self.pattern.to_string(), span } + } + + /// Return a copy of the active flags. + fn flags(&self) -> Flags { + self.trans().flags.get() + } + + /// Set the flags of this translator from the flags set in the given AST. + /// Then, return the old flags. + fn set_flags(&self, ast_flags: &ast::Flags) -> Flags { + let old_flags = self.flags(); + let mut new_flags = Flags::from_ast(ast_flags); + new_flags.merge(&old_flags); + self.trans().flags.set(new_flags); + old_flags + } + + /// Convert an Ast literal to its scalar representation. + /// + /// When Unicode mode is enabled, then this always succeeds and returns a + /// `char` (Unicode scalar value). + /// + /// When Unicode mode is disabled, then a `char` will still be returned + /// whenever possible. A byte is returned only when invalid UTF-8 is + /// allowed and when the byte is not ASCII. Otherwise, a non-ASCII byte + /// will result in an error when invalid UTF-8 is not allowed. + fn ast_literal_to_scalar( + &self, + lit: &ast::Literal, + ) -> Result> { + if self.flags().unicode() { + return Ok(Either::Left(lit.c)); + } + let byte = match lit.byte() { + None => return Ok(Either::Left(lit.c)), + Some(byte) => byte, + }; + if byte <= 0x7F { + return Ok(Either::Left(char::try_from(byte).unwrap())); + } + if self.trans().utf8 { + return Err(self.error(lit.span, ErrorKind::InvalidUtf8)); + } + Ok(Either::Right(byte)) + } + + fn case_fold_char(&self, span: Span, c: char) -> Result> { + if !self.flags().case_insensitive() { + return Ok(None); + } + if self.flags().unicode() { + // If case folding won't do anything, then don't bother trying. + let map = unicode::SimpleCaseFolder::new() + .map(|f| f.overlaps(c, c)) + .map_err(|_| { + self.error(span, ErrorKind::UnicodeCaseUnavailable) + })?; + if !map { + return Ok(None); + } + let mut cls = + hir::ClassUnicode::new(vec![hir::ClassUnicodeRange::new( + c, c, + )]); + cls.try_case_fold_simple().map_err(|_| { + self.error(span, ErrorKind::UnicodeCaseUnavailable) + })?; + Ok(Some(Hir::class(hir::Class::Unicode(cls)))) + } else { + if c.len_utf8() > 1 { + return Err(self.error(span, ErrorKind::UnicodeNotAllowed)); + } + // If case folding won't do anything, then don't bother trying. + match c { + 'A'..='Z' | 'a'..='z' => {} + _ => return Ok(None), + } + let mut cls = + hir::ClassBytes::new(vec![hir::ClassBytesRange::new( + // OK because 'c.len_utf8() == 1' which in turn implies + // that 'c' is ASCII. + u8::try_from(c).unwrap(), + u8::try_from(c).unwrap(), + )]); + cls.case_fold_simple(); + Ok(Some(Hir::class(hir::Class::Bytes(cls)))) + } + } + + fn hir_dot(&self, span: Span) -> Result { + let (utf8, lineterm, flags) = + (self.trans().utf8, self.trans().line_terminator, self.flags()); + if utf8 && (!flags.unicode() || !lineterm.is_ascii()) { + return Err(self.error(span, ErrorKind::InvalidUtf8)); + } + let dot = if flags.dot_matches_new_line() { + if flags.unicode() { + hir::Dot::AnyChar + } else { + hir::Dot::AnyByte + } + } else { + if flags.unicode() { + if flags.crlf() { + hir::Dot::AnyCharExceptCRLF + } else { + if !lineterm.is_ascii() { + return Err( + self.error(span, ErrorKind::InvalidLineTerminator) + ); + } + hir::Dot::AnyCharExcept(char::from(lineterm)) + } + } else { + if flags.crlf() { + hir::Dot::AnyByteExceptCRLF + } else { + hir::Dot::AnyByteExcept(lineterm) + } + } + }; + Ok(Hir::dot(dot)) + } + + fn hir_assertion(&self, asst: &ast::Assertion) -> Result { + let unicode = self.flags().unicode(); + let multi_line = self.flags().multi_line(); + let crlf = self.flags().crlf(); + Ok(match asst.kind { + ast::AssertionKind::StartLine => Hir::look(if multi_line { + if crlf { + hir::Look::StartCRLF + } else { + hir::Look::StartLF + } + } else { + hir::Look::Start + }), + ast::AssertionKind::EndLine => Hir::look(if multi_line { + if crlf { + hir::Look::EndCRLF + } else { + hir::Look::EndLF + } + } else { + hir::Look::End + }), + ast::AssertionKind::StartText => Hir::look(hir::Look::Start), + ast::AssertionKind::EndText => Hir::look(hir::Look::End), + ast::AssertionKind::WordBoundary => Hir::look(if unicode { + hir::Look::WordUnicode + } else { + hir::Look::WordAscii + }), + ast::AssertionKind::NotWordBoundary => Hir::look(if unicode { + hir::Look::WordUnicodeNegate + } else { + hir::Look::WordAsciiNegate + }), + }) + } + + fn hir_capture(&self, group: &ast::Group, expr: Hir) -> Hir { + let (index, name) = match group.kind { + ast::GroupKind::CaptureIndex(index) => (index, None), + ast::GroupKind::CaptureName { ref name, .. } => { + (name.index, Some(name.name.clone().into_boxed_str())) + } + // The HIR doesn't need to use non-capturing groups, since the way + // in which the data type is defined handles this automatically. + ast::GroupKind::NonCapturing(_) => return expr, + }; + Hir::capture(hir::Capture { index, name, sub: Box::new(expr) }) + } + + fn hir_repetition(&self, rep: &ast::Repetition, expr: Hir) -> Hir { + let (min, max) = match rep.op.kind { + ast::RepetitionKind::ZeroOrOne => (0, Some(1)), + ast::RepetitionKind::ZeroOrMore => (0, None), + ast::RepetitionKind::OneOrMore => (1, None), + ast::RepetitionKind::Range(ast::RepetitionRange::Exactly(m)) => { + (m, Some(m)) + } + ast::RepetitionKind::Range(ast::RepetitionRange::AtLeast(m)) => { + (m, None) + } + ast::RepetitionKind::Range(ast::RepetitionRange::Bounded( + m, + n, + )) => (m, Some(n)), + }; + let greedy = + if self.flags().swap_greed() { !rep.greedy } else { rep.greedy }; + Hir::repetition(hir::Repetition { + min, + max, + greedy, + sub: Box::new(expr), + }) + } + + fn hir_unicode_class( + &self, + ast_class: &ast::ClassUnicode, + ) -> Result { + use crate::ast::ClassUnicodeKind::*; + + if !self.flags().unicode() { + return Err( + self.error(ast_class.span, ErrorKind::UnicodeNotAllowed) + ); + } + let query = match ast_class.kind { + OneLetter(name) => ClassQuery::OneLetter(name), + Named(ref name) => ClassQuery::Binary(name), + NamedValue { ref name, ref value, .. } => ClassQuery::ByValue { + property_name: name, + property_value: value, + }, + }; + let mut result = self.convert_unicode_class_error( + &ast_class.span, + unicode::class(query), + ); + if let Ok(ref mut class) = result { + self.unicode_fold_and_negate( + &ast_class.span, + ast_class.negated, + class, + )?; + } + result + } + + fn hir_ascii_unicode_class( + &self, + ast: &ast::ClassAscii, + ) -> Result { + let mut cls = hir::ClassUnicode::new( + ascii_class_as_chars(&ast.kind) + .map(|(s, e)| hir::ClassUnicodeRange::new(s, e)), + ); + self.unicode_fold_and_negate(&ast.span, ast.negated, &mut cls)?; + Ok(cls) + } + + fn hir_ascii_byte_class( + &self, + ast: &ast::ClassAscii, + ) -> Result { + let mut cls = hir::ClassBytes::new( + ascii_class(&ast.kind) + .map(|(s, e)| hir::ClassBytesRange::new(s, e)), + ); + self.bytes_fold_and_negate(&ast.span, ast.negated, &mut cls)?; + Ok(cls) + } + + fn hir_perl_unicode_class( + &self, + ast_class: &ast::ClassPerl, + ) -> Result { + use crate::ast::ClassPerlKind::*; + + assert!(self.flags().unicode()); + let result = match ast_class.kind { + Digit => unicode::perl_digit(), + Space => unicode::perl_space(), + Word => unicode::perl_word(), + }; + let mut class = + self.convert_unicode_class_error(&ast_class.span, result)?; + // We needn't apply case folding here because the Perl Unicode classes + // are already closed under Unicode simple case folding. + if ast_class.negated { + class.negate(); + } + Ok(class) + } + + fn hir_perl_byte_class( + &self, + ast_class: &ast::ClassPerl, + ) -> Result { + use crate::ast::ClassPerlKind::*; + + assert!(!self.flags().unicode()); + let mut class = match ast_class.kind { + Digit => hir_ascii_class_bytes(&ast::ClassAsciiKind::Digit), + Space => hir_ascii_class_bytes(&ast::ClassAsciiKind::Space), + Word => hir_ascii_class_bytes(&ast::ClassAsciiKind::Word), + }; + // We needn't apply case folding here because the Perl ASCII classes + // are already closed (under ASCII case folding). + if ast_class.negated { + class.negate(); + } + // Negating a Perl byte class is likely to cause it to match invalid + // UTF-8. That's only OK if the translator is configured to allow such + // things. + if self.trans().utf8 && !class.is_ascii() { + return Err(self.error(ast_class.span, ErrorKind::InvalidUtf8)); + } + Ok(class) + } + + /// Converts the given Unicode specific error to an HIR translation error. + /// + /// The span given should approximate the position at which an error would + /// occur. + fn convert_unicode_class_error( + &self, + span: &Span, + result: core::result::Result, + ) -> Result { + result.map_err(|err| { + let sp = span.clone(); + match err { + unicode::Error::PropertyNotFound => { + self.error(sp, ErrorKind::UnicodePropertyNotFound) + } + unicode::Error::PropertyValueNotFound => { + self.error(sp, ErrorKind::UnicodePropertyValueNotFound) + } + unicode::Error::PerlClassNotFound => { + self.error(sp, ErrorKind::UnicodePerlClassNotFound) + } + } + }) + } + + fn unicode_fold_and_negate( + &self, + span: &Span, + negated: bool, + class: &mut hir::ClassUnicode, + ) -> Result<()> { + // Note that we must apply case folding before negation! + // Consider `(?i)[^x]`. If we applied negation first, then + // the result would be the character class that matched any + // Unicode scalar value. + if self.flags().case_insensitive() { + class.try_case_fold_simple().map_err(|_| { + self.error(span.clone(), ErrorKind::UnicodeCaseUnavailable) + })?; + } + if negated { + class.negate(); + } + Ok(()) + } + + fn bytes_fold_and_negate( + &self, + span: &Span, + negated: bool, + class: &mut hir::ClassBytes, + ) -> Result<()> { + // Note that we must apply case folding before negation! + // Consider `(?i)[^x]`. If we applied negation first, then + // the result would be the character class that matched any + // Unicode scalar value. + if self.flags().case_insensitive() { + class.case_fold_simple(); + } + if negated { + class.negate(); + } + if self.trans().utf8 && !class.is_ascii() { + return Err(self.error(span.clone(), ErrorKind::InvalidUtf8)); + } + Ok(()) + } + + /// Return a scalar byte value suitable for use as a literal in a byte + /// character class. + fn class_literal_byte(&self, ast: &ast::Literal) -> Result { + match self.ast_literal_to_scalar(ast)? { + Either::Right(byte) => Ok(byte), + Either::Left(ch) => { + let cp = u32::from(ch); + if cp <= 0x7F { + Ok(u8::try_from(cp).unwrap()) + } else { + // We can't feasibly support Unicode in + // byte oriented classes. Byte classes don't + // do Unicode case folding. + Err(self.error(ast.span, ErrorKind::UnicodeNotAllowed)) + } + } + } + } +} + +/// A translator's representation of a regular expression's flags at any given +/// moment in time. +/// +/// Each flag can be in one of three states: absent, present but disabled or +/// present but enabled. +#[derive(Clone, Copy, Debug, Default)] +struct Flags { + case_insensitive: Option, + multi_line: Option, + dot_matches_new_line: Option, + swap_greed: Option, + unicode: Option, + crlf: Option, + // Note that `ignore_whitespace` is omitted here because it is handled + // entirely in the parser. +} + +impl Flags { + fn from_ast(ast: &ast::Flags) -> Flags { + let mut flags = Flags::default(); + let mut enable = true; + for item in &ast.items { + match item.kind { + ast::FlagsItemKind::Negation => { + enable = false; + } + ast::FlagsItemKind::Flag(ast::Flag::CaseInsensitive) => { + flags.case_insensitive = Some(enable); + } + ast::FlagsItemKind::Flag(ast::Flag::MultiLine) => { + flags.multi_line = Some(enable); + } + ast::FlagsItemKind::Flag(ast::Flag::DotMatchesNewLine) => { + flags.dot_matches_new_line = Some(enable); + } + ast::FlagsItemKind::Flag(ast::Flag::SwapGreed) => { + flags.swap_greed = Some(enable); + } + ast::FlagsItemKind::Flag(ast::Flag::Unicode) => { + flags.unicode = Some(enable); + } + ast::FlagsItemKind::Flag(ast::Flag::CRLF) => { + flags.crlf = Some(enable); + } + ast::FlagsItemKind::Flag(ast::Flag::IgnoreWhitespace) => {} + } + } + flags + } + + fn merge(&mut self, previous: &Flags) { + if self.case_insensitive.is_none() { + self.case_insensitive = previous.case_insensitive; + } + if self.multi_line.is_none() { + self.multi_line = previous.multi_line; + } + if self.dot_matches_new_line.is_none() { + self.dot_matches_new_line = previous.dot_matches_new_line; + } + if self.swap_greed.is_none() { + self.swap_greed = previous.swap_greed; + } + if self.unicode.is_none() { + self.unicode = previous.unicode; + } + if self.crlf.is_none() { + self.crlf = previous.crlf; + } + } + + fn case_insensitive(&self) -> bool { + self.case_insensitive.unwrap_or(false) + } + + fn multi_line(&self) -> bool { + self.multi_line.unwrap_or(false) + } + + fn dot_matches_new_line(&self) -> bool { + self.dot_matches_new_line.unwrap_or(false) + } + + fn swap_greed(&self) -> bool { + self.swap_greed.unwrap_or(false) + } + + fn unicode(&self) -> bool { + self.unicode.unwrap_or(true) + } + + fn crlf(&self) -> bool { + self.crlf.unwrap_or(false) + } +} + +fn hir_ascii_class_bytes(kind: &ast::ClassAsciiKind) -> hir::ClassBytes { + let ranges: Vec<_> = ascii_class(kind) + .map(|(s, e)| hir::ClassBytesRange::new(s, e)) + .collect(); + hir::ClassBytes::new(ranges) +} + +fn ascii_class(kind: &ast::ClassAsciiKind) -> impl Iterator { + use crate::ast::ClassAsciiKind::*; + + let slice: &'static [(u8, u8)] = match *kind { + Alnum => &[(b'0', b'9'), (b'A', b'Z'), (b'a', b'z')], + Alpha => &[(b'A', b'Z'), (b'a', b'z')], + Ascii => &[(b'\x00', b'\x7F')], + Blank => &[(b'\t', b'\t'), (b' ', b' ')], + Cntrl => &[(b'\x00', b'\x1F'), (b'\x7F', b'\x7F')], + Digit => &[(b'0', b'9')], + Graph => &[(b'!', b'~')], + Lower => &[(b'a', b'z')], + Print => &[(b' ', b'~')], + Punct => &[(b'!', b'/'), (b':', b'@'), (b'[', b'`'), (b'{', b'~')], + Space => &[ + (b'\t', b'\t'), + (b'\n', b'\n'), + (b'\x0B', b'\x0B'), + (b'\x0C', b'\x0C'), + (b'\r', b'\r'), + (b' ', b' '), + ], + Upper => &[(b'A', b'Z')], + Word => &[(b'0', b'9'), (b'A', b'Z'), (b'_', b'_'), (b'a', b'z')], + Xdigit => &[(b'0', b'9'), (b'A', b'F'), (b'a', b'f')], + }; + slice.iter().copied() +} + +fn ascii_class_as_chars( + kind: &ast::ClassAsciiKind, +) -> impl Iterator { + ascii_class(kind).map(|(s, e)| (char::from(s), char::from(e))) +} + +#[cfg(test)] +mod tests { + use crate::{ + ast::{self, parse::ParserBuilder, Ast, Position, Span}, + hir::{self, Hir, HirKind, Look, Properties}, + unicode::{self, ClassQuery}, + }; + + use super::*; + + // We create these errors to compare with real hir::Errors in the tests. + // We define equality between TestError and hir::Error to disregard the + // pattern string in hir::Error, which is annoying to provide in tests. + #[derive(Clone, Debug)] + struct TestError { + span: Span, + kind: hir::ErrorKind, + } + + impl PartialEq for TestError { + fn eq(&self, other: &hir::Error) -> bool { + self.span == other.span && self.kind == other.kind + } + } + + impl PartialEq for hir::Error { + fn eq(&self, other: &TestError) -> bool { + self.span == other.span && self.kind == other.kind + } + } + + fn parse(pattern: &str) -> Ast { + ParserBuilder::new().octal(true).build().parse(pattern).unwrap() + } + + fn t(pattern: &str) -> Hir { + TranslatorBuilder::new() + .utf8(true) + .build() + .translate(pattern, &parse(pattern)) + .unwrap() + } + + fn t_err(pattern: &str) -> hir::Error { + TranslatorBuilder::new() + .utf8(true) + .build() + .translate(pattern, &parse(pattern)) + .unwrap_err() + } + + fn t_bytes(pattern: &str) -> Hir { + TranslatorBuilder::new() + .utf8(false) + .build() + .translate(pattern, &parse(pattern)) + .unwrap() + } + + fn props(pattern: &str) -> Properties { + t(pattern).properties().clone() + } + + fn props_bytes(pattern: &str) -> Properties { + t_bytes(pattern).properties().clone() + } + + fn hir_lit(s: &str) -> Hir { + hir_blit(s.as_bytes()) + } + + fn hir_blit(s: &[u8]) -> Hir { + Hir::literal(s) + } + + fn hir_capture(index: u32, expr: Hir) -> Hir { + Hir::capture(hir::Capture { index, name: None, sub: Box::new(expr) }) + } + + fn hir_capture_name(index: u32, name: &str, expr: Hir) -> Hir { + Hir::capture(hir::Capture { + index, + name: Some(name.into()), + sub: Box::new(expr), + }) + } + + fn hir_quest(greedy: bool, expr: Hir) -> Hir { + Hir::repetition(hir::Repetition { + min: 0, + max: Some(1), + greedy, + sub: Box::new(expr), + }) + } + + fn hir_star(greedy: bool, expr: Hir) -> Hir { + Hir::repetition(hir::Repetition { + min: 0, + max: None, + greedy, + sub: Box::new(expr), + }) + } + + fn hir_plus(greedy: bool, expr: Hir) -> Hir { + Hir::repetition(hir::Repetition { + min: 1, + max: None, + greedy, + sub: Box::new(expr), + }) + } + + fn hir_range(greedy: bool, min: u32, max: Option, expr: Hir) -> Hir { + Hir::repetition(hir::Repetition { + min, + max, + greedy, + sub: Box::new(expr), + }) + } + + fn hir_alt(alts: Vec) -> Hir { + Hir::alternation(alts) + } + + fn hir_cat(exprs: Vec) -> Hir { + Hir::concat(exprs) + } + + #[allow(dead_code)] + fn hir_uclass_query(query: ClassQuery<'_>) -> Hir { + Hir::class(hir::Class::Unicode(unicode::class(query).unwrap())) + } + + #[allow(dead_code)] + fn hir_uclass_perl_word() -> Hir { + Hir::class(hir::Class::Unicode(unicode::perl_word().unwrap())) + } + + fn hir_ascii_uclass(kind: &ast::ClassAsciiKind) -> Hir { + Hir::class(hir::Class::Unicode(hir::ClassUnicode::new( + ascii_class_as_chars(kind) + .map(|(s, e)| hir::ClassUnicodeRange::new(s, e)), + ))) + } + + fn hir_ascii_bclass(kind: &ast::ClassAsciiKind) -> Hir { + Hir::class(hir::Class::Bytes(hir::ClassBytes::new( + ascii_class(kind).map(|(s, e)| hir::ClassBytesRange::new(s, e)), + ))) + } + + fn hir_uclass(ranges: &[(char, char)]) -> Hir { + Hir::class(uclass(ranges)) + } + + fn hir_bclass(ranges: &[(u8, u8)]) -> Hir { + Hir::class(bclass(ranges)) + } + + fn hir_case_fold(expr: Hir) -> Hir { + match expr.into_kind() { + HirKind::Class(mut cls) => { + cls.case_fold_simple(); + Hir::class(cls) + } + _ => panic!("cannot case fold non-class Hir expr"), + } + } + + fn hir_negate(expr: Hir) -> Hir { + match expr.into_kind() { + HirKind::Class(mut cls) => { + cls.negate(); + Hir::class(cls) + } + _ => panic!("cannot negate non-class Hir expr"), + } + } + + fn uclass(ranges: &[(char, char)]) -> hir::Class { + let ranges: Vec = ranges + .iter() + .map(|&(s, e)| hir::ClassUnicodeRange::new(s, e)) + .collect(); + hir::Class::Unicode(hir::ClassUnicode::new(ranges)) + } + + fn bclass(ranges: &[(u8, u8)]) -> hir::Class { + let ranges: Vec = ranges + .iter() + .map(|&(s, e)| hir::ClassBytesRange::new(s, e)) + .collect(); + hir::Class::Bytes(hir::ClassBytes::new(ranges)) + } + + #[cfg(feature = "unicode-case")] + fn class_case_fold(mut cls: hir::Class) -> Hir { + cls.case_fold_simple(); + Hir::class(cls) + } + + fn class_negate(mut cls: hir::Class) -> Hir { + cls.negate(); + Hir::class(cls) + } + + #[allow(dead_code)] + fn hir_union(expr1: Hir, expr2: Hir) -> Hir { + use crate::hir::Class::{Bytes, Unicode}; + + match (expr1.into_kind(), expr2.into_kind()) { + (HirKind::Class(Unicode(mut c1)), HirKind::Class(Unicode(c2))) => { + c1.union(&c2); + Hir::class(hir::Class::Unicode(c1)) + } + (HirKind::Class(Bytes(mut c1)), HirKind::Class(Bytes(c2))) => { + c1.union(&c2); + Hir::class(hir::Class::Bytes(c1)) + } + _ => panic!("cannot union non-class Hir exprs"), + } + } + + #[allow(dead_code)] + fn hir_difference(expr1: Hir, expr2: Hir) -> Hir { + use crate::hir::Class::{Bytes, Unicode}; + + match (expr1.into_kind(), expr2.into_kind()) { + (HirKind::Class(Unicode(mut c1)), HirKind::Class(Unicode(c2))) => { + c1.difference(&c2); + Hir::class(hir::Class::Unicode(c1)) + } + (HirKind::Class(Bytes(mut c1)), HirKind::Class(Bytes(c2))) => { + c1.difference(&c2); + Hir::class(hir::Class::Bytes(c1)) + } + _ => panic!("cannot difference non-class Hir exprs"), + } + } + + fn hir_look(look: hir::Look) -> Hir { + Hir::look(look) + } + + #[test] + fn empty() { + assert_eq!(t(""), Hir::empty()); + assert_eq!(t("(?i)"), Hir::empty()); + assert_eq!(t("()"), hir_capture(1, Hir::empty())); + assert_eq!(t("(?:)"), Hir::empty()); + assert_eq!(t("(?P)"), hir_capture_name(1, "wat", Hir::empty())); + assert_eq!(t("|"), hir_alt(vec![Hir::empty(), Hir::empty()])); + assert_eq!( + t("()|()"), + hir_alt(vec![ + hir_capture(1, Hir::empty()), + hir_capture(2, Hir::empty()), + ]) + ); + assert_eq!( + t("(|b)"), + hir_capture(1, hir_alt(vec![Hir::empty(), hir_lit("b"),])) + ); + assert_eq!( + t("(a|)"), + hir_capture(1, hir_alt(vec![hir_lit("a"), Hir::empty(),])) + ); + assert_eq!( + t("(a||c)"), + hir_capture( + 1, + hir_alt(vec![hir_lit("a"), Hir::empty(), hir_lit("c"),]) + ) + ); + assert_eq!( + t("(||)"), + hir_capture( + 1, + hir_alt(vec![Hir::empty(), Hir::empty(), Hir::empty(),]) + ) + ); + } + + #[test] + fn literal() { + assert_eq!(t("a"), hir_lit("a")); + assert_eq!(t("(?-u)a"), hir_lit("a")); + assert_eq!(t("☃"), hir_lit("☃")); + assert_eq!(t("abcd"), hir_lit("abcd")); + + assert_eq!(t_bytes("(?-u)a"), hir_lit("a")); + assert_eq!(t_bytes("(?-u)\x61"), hir_lit("a")); + assert_eq!(t_bytes(r"(?-u)\x61"), hir_lit("a")); + assert_eq!(t_bytes(r"(?-u)\xFF"), hir_blit(b"\xFF")); + + assert_eq!( + t_err("(?-u)☃"), + TestError { + kind: hir::ErrorKind::UnicodeNotAllowed, + span: Span::new( + Position::new(5, 1, 6), + Position::new(8, 1, 7) + ), + } + ); + assert_eq!( + t_err(r"(?-u)\xFF"), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(5, 1, 6), + Position::new(9, 1, 10) + ), + } + ); + } + + #[test] + fn literal_case_insensitive() { + #[cfg(feature = "unicode-case")] + assert_eq!(t("(?i)a"), hir_uclass(&[('A', 'A'), ('a', 'a'),])); + #[cfg(feature = "unicode-case")] + assert_eq!(t("(?i:a)"), hir_uclass(&[('A', 'A'), ('a', 'a')])); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("a(?i)a(?-i)a"), + hir_cat(vec![ + hir_lit("a"), + hir_uclass(&[('A', 'A'), ('a', 'a')]), + hir_lit("a"), + ]) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i)ab@c"), + hir_cat(vec![ + hir_uclass(&[('A', 'A'), ('a', 'a')]), + hir_uclass(&[('B', 'B'), ('b', 'b')]), + hir_lit("@"), + hir_uclass(&[('C', 'C'), ('c', 'c')]), + ]) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i)β"), + hir_uclass(&[('Î’', 'Î’'), ('β', 'β'), ('Ï', 'Ï'),]) + ); + + assert_eq!(t("(?i-u)a"), hir_bclass(&[(b'A', b'A'), (b'a', b'a'),])); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?-u)a(?i)a(?-i)a"), + hir_cat(vec![ + hir_lit("a"), + hir_bclass(&[(b'A', b'A'), (b'a', b'a')]), + hir_lit("a"), + ]) + ); + assert_eq!( + t("(?i-u)ab@c"), + hir_cat(vec![ + hir_bclass(&[(b'A', b'A'), (b'a', b'a')]), + hir_bclass(&[(b'B', b'B'), (b'b', b'b')]), + hir_lit("@"), + hir_bclass(&[(b'C', b'C'), (b'c', b'c')]), + ]) + ); + + assert_eq!( + t_bytes("(?i-u)a"), + hir_bclass(&[(b'A', b'A'), (b'a', b'a'),]) + ); + assert_eq!( + t_bytes("(?i-u)\x61"), + hir_bclass(&[(b'A', b'A'), (b'a', b'a'),]) + ); + assert_eq!( + t_bytes(r"(?i-u)\x61"), + hir_bclass(&[(b'A', b'A'), (b'a', b'a'),]) + ); + assert_eq!(t_bytes(r"(?i-u)\xFF"), hir_blit(b"\xFF")); + + assert_eq!( + t_err("(?i-u)β"), + TestError { + kind: hir::ErrorKind::UnicodeNotAllowed, + span: Span::new( + Position::new(6, 1, 7), + Position::new(8, 1, 8), + ), + } + ); + } + + #[test] + fn dot() { + assert_eq!( + t("."), + hir_uclass(&[('\0', '\t'), ('\x0B', '\u{10FFFF}')]) + ); + assert_eq!( + t("(?R)."), + hir_uclass(&[ + ('\0', '\t'), + ('\x0B', '\x0C'), + ('\x0E', '\u{10FFFF}'), + ]) + ); + assert_eq!(t("(?s)."), hir_uclass(&[('\0', '\u{10FFFF}')])); + assert_eq!(t("(?Rs)."), hir_uclass(&[('\0', '\u{10FFFF}')])); + assert_eq!( + t_bytes("(?-u)."), + hir_bclass(&[(b'\0', b'\t'), (b'\x0B', b'\xFF')]) + ); + assert_eq!( + t_bytes("(?R-u)."), + hir_bclass(&[ + (b'\0', b'\t'), + (b'\x0B', b'\x0C'), + (b'\x0E', b'\xFF'), + ]) + ); + assert_eq!(t_bytes("(?s-u)."), hir_bclass(&[(b'\0', b'\xFF'),])); + assert_eq!(t_bytes("(?Rs-u)."), hir_bclass(&[(b'\0', b'\xFF'),])); + + // If invalid UTF-8 isn't allowed, then non-Unicode `.` isn't allowed. + assert_eq!( + t_err("(?-u)."), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(5, 1, 6), + Position::new(6, 1, 7) + ), + } + ); + assert_eq!( + t_err("(?R-u)."), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(6, 1, 7), + Position::new(7, 1, 8) + ), + } + ); + assert_eq!( + t_err("(?s-u)."), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(6, 1, 7), + Position::new(7, 1, 8) + ), + } + ); + assert_eq!( + t_err("(?Rs-u)."), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(7, 1, 8), + Position::new(8, 1, 9) + ), + } + ); + } + + #[test] + fn assertions() { + assert_eq!(t("^"), hir_look(hir::Look::Start)); + assert_eq!(t("$"), hir_look(hir::Look::End)); + assert_eq!(t(r"\A"), hir_look(hir::Look::Start)); + assert_eq!(t(r"\z"), hir_look(hir::Look::End)); + assert_eq!(t("(?m)^"), hir_look(hir::Look::StartLF)); + assert_eq!(t("(?m)$"), hir_look(hir::Look::EndLF)); + assert_eq!(t(r"(?m)\A"), hir_look(hir::Look::Start)); + assert_eq!(t(r"(?m)\z"), hir_look(hir::Look::End)); + + assert_eq!(t(r"\b"), hir_look(hir::Look::WordUnicode)); + assert_eq!(t(r"\B"), hir_look(hir::Look::WordUnicodeNegate)); + assert_eq!(t(r"(?-u)\b"), hir_look(hir::Look::WordAscii)); + assert_eq!(t(r"(?-u)\B"), hir_look(hir::Look::WordAsciiNegate)); + } + + #[test] + fn group() { + assert_eq!(t("(a)"), hir_capture(1, hir_lit("a"))); + assert_eq!( + t("(a)(b)"), + hir_cat(vec![ + hir_capture(1, hir_lit("a")), + hir_capture(2, hir_lit("b")), + ]) + ); + assert_eq!( + t("(a)|(b)"), + hir_alt(vec![ + hir_capture(1, hir_lit("a")), + hir_capture(2, hir_lit("b")), + ]) + ); + assert_eq!(t("(?P)"), hir_capture_name(1, "foo", Hir::empty())); + assert_eq!(t("(?Pa)"), hir_capture_name(1, "foo", hir_lit("a"))); + assert_eq!( + t("(?Pa)(?Pb)"), + hir_cat(vec![ + hir_capture_name(1, "foo", hir_lit("a")), + hir_capture_name(2, "bar", hir_lit("b")), + ]) + ); + assert_eq!(t("(?:)"), Hir::empty()); + assert_eq!(t("(?:a)"), hir_lit("a")); + assert_eq!( + t("(?:a)(b)"), + hir_cat(vec![hir_lit("a"), hir_capture(1, hir_lit("b")),]) + ); + assert_eq!( + t("(a)(?:b)(c)"), + hir_cat(vec![ + hir_capture(1, hir_lit("a")), + hir_lit("b"), + hir_capture(2, hir_lit("c")), + ]) + ); + assert_eq!( + t("(a)(?Pb)(c)"), + hir_cat(vec![ + hir_capture(1, hir_lit("a")), + hir_capture_name(2, "foo", hir_lit("b")), + hir_capture(3, hir_lit("c")), + ]) + ); + assert_eq!(t("()"), hir_capture(1, Hir::empty())); + assert_eq!(t("((?i))"), hir_capture(1, Hir::empty())); + assert_eq!(t("((?x))"), hir_capture(1, Hir::empty())); + assert_eq!( + t("(((?x)))"), + hir_capture(1, hir_capture(2, Hir::empty())) + ); + } + + #[test] + fn line_anchors() { + assert_eq!(t("^"), hir_look(hir::Look::Start)); + assert_eq!(t("$"), hir_look(hir::Look::End)); + assert_eq!(t(r"\A"), hir_look(hir::Look::Start)); + assert_eq!(t(r"\z"), hir_look(hir::Look::End)); + + assert_eq!(t(r"(?m)\A"), hir_look(hir::Look::Start)); + assert_eq!(t(r"(?m)\z"), hir_look(hir::Look::End)); + assert_eq!(t("(?m)^"), hir_look(hir::Look::StartLF)); + assert_eq!(t("(?m)$"), hir_look(hir::Look::EndLF)); + + assert_eq!(t(r"(?R)\A"), hir_look(hir::Look::Start)); + assert_eq!(t(r"(?R)\z"), hir_look(hir::Look::End)); + assert_eq!(t("(?R)^"), hir_look(hir::Look::Start)); + assert_eq!(t("(?R)$"), hir_look(hir::Look::End)); + + assert_eq!(t(r"(?Rm)\A"), hir_look(hir::Look::Start)); + assert_eq!(t(r"(?Rm)\z"), hir_look(hir::Look::End)); + assert_eq!(t("(?Rm)^"), hir_look(hir::Look::StartCRLF)); + assert_eq!(t("(?Rm)$"), hir_look(hir::Look::EndCRLF)); + } + + #[test] + fn flags() { + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i:a)a"), + hir_cat( + vec![hir_uclass(&[('A', 'A'), ('a', 'a')]), hir_lit("a"),] + ) + ); + assert_eq!( + t("(?i-u:a)β"), + hir_cat(vec![ + hir_bclass(&[(b'A', b'A'), (b'a', b'a')]), + hir_lit("β"), + ]) + ); + assert_eq!( + t("(?:(?i-u)a)b"), + hir_cat(vec![ + hir_bclass(&[(b'A', b'A'), (b'a', b'a')]), + hir_lit("b"), + ]) + ); + assert_eq!( + t("((?i-u)a)b"), + hir_cat(vec![ + hir_capture(1, hir_bclass(&[(b'A', b'A'), (b'a', b'a')])), + hir_lit("b"), + ]) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i)(?-i:a)a"), + hir_cat( + vec![hir_lit("a"), hir_uclass(&[('A', 'A'), ('a', 'a')]),] + ) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?im)a^"), + hir_cat(vec![ + hir_uclass(&[('A', 'A'), ('a', 'a')]), + hir_look(hir::Look::StartLF), + ]) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?im)a^(?i-m)a^"), + hir_cat(vec![ + hir_uclass(&[('A', 'A'), ('a', 'a')]), + hir_look(hir::Look::StartLF), + hir_uclass(&[('A', 'A'), ('a', 'a')]), + hir_look(hir::Look::Start), + ]) + ); + assert_eq!( + t("(?U)a*a*?(?-U)a*a*?"), + hir_cat(vec![ + hir_star(false, hir_lit("a")), + hir_star(true, hir_lit("a")), + hir_star(true, hir_lit("a")), + hir_star(false, hir_lit("a")), + ]) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?:a(?i)a)a"), + hir_cat(vec![ + hir_cat(vec![ + hir_lit("a"), + hir_uclass(&[('A', 'A'), ('a', 'a')]), + ]), + hir_lit("a"), + ]) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i)(?:a(?-i)a)a"), + hir_cat(vec![ + hir_cat(vec![ + hir_uclass(&[('A', 'A'), ('a', 'a')]), + hir_lit("a"), + ]), + hir_uclass(&[('A', 'A'), ('a', 'a')]), + ]) + ); + } + + #[test] + fn escape() { + assert_eq!( + t(r"\\\.\+\*\?\(\)\|\[\]\{\}\^\$\#"), + hir_lit(r"\.+*?()|[]{}^$#") + ); + } + + #[test] + fn repetition() { + assert_eq!(t("a?"), hir_quest(true, hir_lit("a"))); + assert_eq!(t("a*"), hir_star(true, hir_lit("a"))); + assert_eq!(t("a+"), hir_plus(true, hir_lit("a"))); + assert_eq!(t("a??"), hir_quest(false, hir_lit("a"))); + assert_eq!(t("a*?"), hir_star(false, hir_lit("a"))); + assert_eq!(t("a+?"), hir_plus(false, hir_lit("a"))); + + assert_eq!(t("a{1}"), hir_range(true, 1, Some(1), hir_lit("a"),)); + assert_eq!(t("a{1,}"), hir_range(true, 1, None, hir_lit("a"),)); + assert_eq!(t("a{1,2}"), hir_range(true, 1, Some(2), hir_lit("a"),)); + assert_eq!(t("a{1}?"), hir_range(false, 1, Some(1), hir_lit("a"),)); + assert_eq!(t("a{1,}?"), hir_range(false, 1, None, hir_lit("a"),)); + assert_eq!(t("a{1,2}?"), hir_range(false, 1, Some(2), hir_lit("a"),)); + + assert_eq!( + t("ab?"), + hir_cat(vec![hir_lit("a"), hir_quest(true, hir_lit("b")),]) + ); + assert_eq!(t("(ab)?"), hir_quest(true, hir_capture(1, hir_lit("ab")))); + assert_eq!( + t("a|b?"), + hir_alt(vec![hir_lit("a"), hir_quest(true, hir_lit("b")),]) + ); + } + + #[test] + fn cat_alt() { + let a = || hir_look(hir::Look::Start); + let b = || hir_look(hir::Look::End); + let c = || hir_look(hir::Look::WordUnicode); + let d = || hir_look(hir::Look::WordUnicodeNegate); + + assert_eq!(t("(^$)"), hir_capture(1, hir_cat(vec![a(), b()]))); + assert_eq!(t("^|$"), hir_alt(vec![a(), b()])); + assert_eq!(t(r"^|$|\b"), hir_alt(vec![a(), b(), c()])); + assert_eq!( + t(r"^$|$\b|\b\B"), + hir_alt(vec![ + hir_cat(vec![a(), b()]), + hir_cat(vec![b(), c()]), + hir_cat(vec![c(), d()]), + ]) + ); + assert_eq!(t("(^|$)"), hir_capture(1, hir_alt(vec![a(), b()]))); + assert_eq!( + t(r"(^|$|\b)"), + hir_capture(1, hir_alt(vec![a(), b(), c()])) + ); + assert_eq!( + t(r"(^$|$\b|\b\B)"), + hir_capture( + 1, + hir_alt(vec![ + hir_cat(vec![a(), b()]), + hir_cat(vec![b(), c()]), + hir_cat(vec![c(), d()]), + ]) + ) + ); + assert_eq!( + t(r"(^$|($\b|(\b\B)))"), + hir_capture( + 1, + hir_alt(vec![ + hir_cat(vec![a(), b()]), + hir_capture( + 2, + hir_alt(vec![ + hir_cat(vec![b(), c()]), + hir_capture(3, hir_cat(vec![c(), d()])), + ]) + ), + ]) + ) + ); + } + + // Tests the HIR transformation of things like '[a-z]|[A-Z]' into + // '[A-Za-z]'. In other words, an alternation of just classes is always + // equivalent to a single class corresponding to the union of the branches + // in that class. (Unless some branches match invalid UTF-8 and others + // match non-ASCII Unicode.) + #[test] + fn cat_class_flattened() { + assert_eq!(t(r"[a-z]|[A-Z]"), hir_uclass(&[('A', 'Z'), ('a', 'z')])); + // Combining all of the letter properties should give us the one giant + // letter property. + #[cfg(feature = "unicode-gencat")] + assert_eq!( + t(r"(?x) + \p{Lowercase_Letter} + |\p{Uppercase_Letter} + |\p{Titlecase_Letter} + |\p{Modifier_Letter} + |\p{Other_Letter} + "), + hir_uclass_query(ClassQuery::Binary("letter")) + ); + // Byte classes that can truly match invalid UTF-8 cannot be combined + // with Unicode classes. + assert_eq!( + t_bytes(r"[Δδ]|(?-u:[\x90-\xFF])|[Λλ]"), + hir_alt(vec![ + hir_uclass(&[('Δ', 'Δ'), ('δ', 'δ')]), + hir_bclass(&[(b'\x90', b'\xFF')]), + hir_uclass(&[('Λ', 'Λ'), ('λ', 'λ')]), + ]) + ); + // Byte classes on their own can be combined, even if some are ASCII + // and others are invalid UTF-8. + assert_eq!( + t_bytes(r"[a-z]|(?-u:[\x90-\xFF])|[A-Z]"), + hir_bclass(&[(b'A', b'Z'), (b'a', b'z'), (b'\x90', b'\xFF')]), + ); + } + + #[test] + fn class_ascii() { + assert_eq!( + t("[[:alnum:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Alnum) + ); + assert_eq!( + t("[[:alpha:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Alpha) + ); + assert_eq!( + t("[[:ascii:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Ascii) + ); + assert_eq!( + t("[[:blank:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Blank) + ); + assert_eq!( + t("[[:cntrl:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Cntrl) + ); + assert_eq!( + t("[[:digit:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Digit) + ); + assert_eq!( + t("[[:graph:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Graph) + ); + assert_eq!( + t("[[:lower:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Lower) + ); + assert_eq!( + t("[[:print:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Print) + ); + assert_eq!( + t("[[:punct:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Punct) + ); + assert_eq!( + t("[[:space:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Space) + ); + assert_eq!( + t("[[:upper:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Upper) + ); + assert_eq!( + t("[[:word:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Word) + ); + assert_eq!( + t("[[:xdigit:]]"), + hir_ascii_uclass(&ast::ClassAsciiKind::Xdigit) + ); + + assert_eq!( + t("[[:^lower:]]"), + hir_negate(hir_ascii_uclass(&ast::ClassAsciiKind::Lower)) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i)[[:lower:]]"), + hir_uclass(&[ + ('A', 'Z'), + ('a', 'z'), + ('\u{17F}', '\u{17F}'), + ('\u{212A}', '\u{212A}'), + ]) + ); + + assert_eq!( + t("(?-u)[[:lower:]]"), + hir_ascii_bclass(&ast::ClassAsciiKind::Lower) + ); + assert_eq!( + t("(?i-u)[[:lower:]]"), + hir_case_fold(hir_ascii_bclass(&ast::ClassAsciiKind::Lower)) + ); + + assert_eq!( + t_err("(?-u)[[:^lower:]]"), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(6, 1, 7), + Position::new(16, 1, 17) + ), + } + ); + assert_eq!( + t_err("(?i-u)[[:^lower:]]"), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(7, 1, 8), + Position::new(17, 1, 18) + ), + } + ); + } + + #[test] + fn class_ascii_multiple() { + // See: https://github.com/rust-lang/regex/issues/680 + assert_eq!( + t("[[:alnum:][:^ascii:]]"), + hir_union( + hir_ascii_uclass(&ast::ClassAsciiKind::Alnum), + hir_uclass(&[('\u{80}', '\u{10FFFF}')]), + ), + ); + assert_eq!( + t_bytes("(?-u)[[:alnum:][:^ascii:]]"), + hir_union( + hir_ascii_bclass(&ast::ClassAsciiKind::Alnum), + hir_bclass(&[(0x80, 0xFF)]), + ), + ); + } + + #[test] + #[cfg(feature = "unicode-perl")] + fn class_perl_unicode() { + // Unicode + assert_eq!(t(r"\d"), hir_uclass_query(ClassQuery::Binary("digit"))); + assert_eq!(t(r"\s"), hir_uclass_query(ClassQuery::Binary("space"))); + assert_eq!(t(r"\w"), hir_uclass_perl_word()); + #[cfg(feature = "unicode-case")] + assert_eq!( + t(r"(?i)\d"), + hir_uclass_query(ClassQuery::Binary("digit")) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t(r"(?i)\s"), + hir_uclass_query(ClassQuery::Binary("space")) + ); + #[cfg(feature = "unicode-case")] + assert_eq!(t(r"(?i)\w"), hir_uclass_perl_word()); + + // Unicode, negated + assert_eq!( + t(r"\D"), + hir_negate(hir_uclass_query(ClassQuery::Binary("digit"))) + ); + assert_eq!( + t(r"\S"), + hir_negate(hir_uclass_query(ClassQuery::Binary("space"))) + ); + assert_eq!(t(r"\W"), hir_negate(hir_uclass_perl_word())); + #[cfg(feature = "unicode-case")] + assert_eq!( + t(r"(?i)\D"), + hir_negate(hir_uclass_query(ClassQuery::Binary("digit"))) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t(r"(?i)\S"), + hir_negate(hir_uclass_query(ClassQuery::Binary("space"))) + ); + #[cfg(feature = "unicode-case")] + assert_eq!(t(r"(?i)\W"), hir_negate(hir_uclass_perl_word())); + } + + #[test] + fn class_perl_ascii() { + // ASCII only + assert_eq!( + t(r"(?-u)\d"), + hir_ascii_bclass(&ast::ClassAsciiKind::Digit) + ); + assert_eq!( + t(r"(?-u)\s"), + hir_ascii_bclass(&ast::ClassAsciiKind::Space) + ); + assert_eq!( + t(r"(?-u)\w"), + hir_ascii_bclass(&ast::ClassAsciiKind::Word) + ); + assert_eq!( + t(r"(?i-u)\d"), + hir_ascii_bclass(&ast::ClassAsciiKind::Digit) + ); + assert_eq!( + t(r"(?i-u)\s"), + hir_ascii_bclass(&ast::ClassAsciiKind::Space) + ); + assert_eq!( + t(r"(?i-u)\w"), + hir_ascii_bclass(&ast::ClassAsciiKind::Word) + ); + + // ASCII only, negated + assert_eq!( + t_bytes(r"(?-u)\D"), + hir_negate(hir_ascii_bclass(&ast::ClassAsciiKind::Digit)) + ); + assert_eq!( + t_bytes(r"(?-u)\S"), + hir_negate(hir_ascii_bclass(&ast::ClassAsciiKind::Space)) + ); + assert_eq!( + t_bytes(r"(?-u)\W"), + hir_negate(hir_ascii_bclass(&ast::ClassAsciiKind::Word)) + ); + assert_eq!( + t_bytes(r"(?i-u)\D"), + hir_negate(hir_ascii_bclass(&ast::ClassAsciiKind::Digit)) + ); + assert_eq!( + t_bytes(r"(?i-u)\S"), + hir_negate(hir_ascii_bclass(&ast::ClassAsciiKind::Space)) + ); + assert_eq!( + t_bytes(r"(?i-u)\W"), + hir_negate(hir_ascii_bclass(&ast::ClassAsciiKind::Word)) + ); + + // ASCII only, negated, with UTF-8 mode enabled. + // In this case, negating any Perl class results in an error because + // all such classes can match invalid UTF-8. + assert_eq!( + t_err(r"(?-u)\D"), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(5, 1, 6), + Position::new(7, 1, 8), + ), + }, + ); + assert_eq!( + t_err(r"(?-u)\S"), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(5, 1, 6), + Position::new(7, 1, 8), + ), + }, + ); + assert_eq!( + t_err(r"(?-u)\W"), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(5, 1, 6), + Position::new(7, 1, 8), + ), + }, + ); + assert_eq!( + t_err(r"(?i-u)\D"), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(6, 1, 7), + Position::new(8, 1, 9), + ), + }, + ); + assert_eq!( + t_err(r"(?i-u)\S"), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(6, 1, 7), + Position::new(8, 1, 9), + ), + }, + ); + assert_eq!( + t_err(r"(?i-u)\W"), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(6, 1, 7), + Position::new(8, 1, 9), + ), + }, + ); + } + + #[test] + #[cfg(not(feature = "unicode-perl"))] + fn class_perl_word_disabled() { + assert_eq!( + t_err(r"\w"), + TestError { + kind: hir::ErrorKind::UnicodePerlClassNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(2, 1, 3) + ), + } + ); + } + + #[test] + #[cfg(all(not(feature = "unicode-perl"), not(feature = "unicode-bool")))] + fn class_perl_space_disabled() { + assert_eq!( + t_err(r"\s"), + TestError { + kind: hir::ErrorKind::UnicodePerlClassNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(2, 1, 3) + ), + } + ); + } + + #[test] + #[cfg(all( + not(feature = "unicode-perl"), + not(feature = "unicode-gencat") + ))] + fn class_perl_digit_disabled() { + assert_eq!( + t_err(r"\d"), + TestError { + kind: hir::ErrorKind::UnicodePerlClassNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(2, 1, 3) + ), + } + ); + } + + #[test] + #[cfg(feature = "unicode-gencat")] + fn class_unicode_gencat() { + assert_eq!(t(r"\pZ"), hir_uclass_query(ClassQuery::Binary("Z"))); + assert_eq!(t(r"\pz"), hir_uclass_query(ClassQuery::Binary("Z"))); + assert_eq!( + t(r"\p{Separator}"), + hir_uclass_query(ClassQuery::Binary("Z")) + ); + assert_eq!( + t(r"\p{se PaRa ToR}"), + hir_uclass_query(ClassQuery::Binary("Z")) + ); + assert_eq!( + t(r"\p{gc:Separator}"), + hir_uclass_query(ClassQuery::Binary("Z")) + ); + assert_eq!( + t(r"\p{gc=Separator}"), + hir_uclass_query(ClassQuery::Binary("Z")) + ); + assert_eq!( + t(r"\p{Other}"), + hir_uclass_query(ClassQuery::Binary("Other")) + ); + assert_eq!(t(r"\pC"), hir_uclass_query(ClassQuery::Binary("Other"))); + + assert_eq!( + t(r"\PZ"), + hir_negate(hir_uclass_query(ClassQuery::Binary("Z"))) + ); + assert_eq!( + t(r"\P{separator}"), + hir_negate(hir_uclass_query(ClassQuery::Binary("Z"))) + ); + assert_eq!( + t(r"\P{gc!=separator}"), + hir_negate(hir_uclass_query(ClassQuery::Binary("Z"))) + ); + + assert_eq!(t(r"\p{any}"), hir_uclass_query(ClassQuery::Binary("Any"))); + assert_eq!( + t(r"\p{assigned}"), + hir_uclass_query(ClassQuery::Binary("Assigned")) + ); + assert_eq!( + t(r"\p{ascii}"), + hir_uclass_query(ClassQuery::Binary("ASCII")) + ); + assert_eq!( + t(r"\p{gc:any}"), + hir_uclass_query(ClassQuery::Binary("Any")) + ); + assert_eq!( + t(r"\p{gc:assigned}"), + hir_uclass_query(ClassQuery::Binary("Assigned")) + ); + assert_eq!( + t(r"\p{gc:ascii}"), + hir_uclass_query(ClassQuery::Binary("ASCII")) + ); + + assert_eq!( + t_err(r"(?-u)\pZ"), + TestError { + kind: hir::ErrorKind::UnicodeNotAllowed, + span: Span::new( + Position::new(5, 1, 6), + Position::new(8, 1, 9) + ), + } + ); + assert_eq!( + t_err(r"(?-u)\p{Separator}"), + TestError { + kind: hir::ErrorKind::UnicodeNotAllowed, + span: Span::new( + Position::new(5, 1, 6), + Position::new(18, 1, 19) + ), + } + ); + assert_eq!( + t_err(r"\pE"), + TestError { + kind: hir::ErrorKind::UnicodePropertyNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(3, 1, 4) + ), + } + ); + assert_eq!( + t_err(r"\p{Foo}"), + TestError { + kind: hir::ErrorKind::UnicodePropertyNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(7, 1, 8) + ), + } + ); + assert_eq!( + t_err(r"\p{gc:Foo}"), + TestError { + kind: hir::ErrorKind::UnicodePropertyValueNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(10, 1, 11) + ), + } + ); + } + + #[test] + #[cfg(not(feature = "unicode-gencat"))] + fn class_unicode_gencat_disabled() { + assert_eq!( + t_err(r"\p{Separator}"), + TestError { + kind: hir::ErrorKind::UnicodePropertyNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(13, 1, 14) + ), + } + ); + + assert_eq!( + t_err(r"\p{Any}"), + TestError { + kind: hir::ErrorKind::UnicodePropertyNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(7, 1, 8) + ), + } + ); + } + + #[test] + #[cfg(feature = "unicode-script")] + fn class_unicode_script() { + assert_eq!( + t(r"\p{Greek}"), + hir_uclass_query(ClassQuery::Binary("Greek")) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t(r"(?i)\p{Greek}"), + hir_case_fold(hir_uclass_query(ClassQuery::Binary("Greek"))) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t(r"(?i)\P{Greek}"), + hir_negate(hir_case_fold(hir_uclass_query(ClassQuery::Binary( + "Greek" + )))) + ); + + assert_eq!( + t_err(r"\p{sc:Foo}"), + TestError { + kind: hir::ErrorKind::UnicodePropertyValueNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(10, 1, 11) + ), + } + ); + assert_eq!( + t_err(r"\p{scx:Foo}"), + TestError { + kind: hir::ErrorKind::UnicodePropertyValueNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(11, 1, 12) + ), + } + ); + } + + #[test] + #[cfg(not(feature = "unicode-script"))] + fn class_unicode_script_disabled() { + assert_eq!( + t_err(r"\p{Greek}"), + TestError { + kind: hir::ErrorKind::UnicodePropertyNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(9, 1, 10) + ), + } + ); + + assert_eq!( + t_err(r"\p{scx:Greek}"), + TestError { + kind: hir::ErrorKind::UnicodePropertyNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(13, 1, 14) + ), + } + ); + } + + #[test] + #[cfg(feature = "unicode-age")] + fn class_unicode_age() { + assert_eq!( + t_err(r"\p{age:Foo}"), + TestError { + kind: hir::ErrorKind::UnicodePropertyValueNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(11, 1, 12) + ), + } + ); + } + + #[test] + #[cfg(feature = "unicode-gencat")] + fn class_unicode_any_empty() { + assert_eq!(t(r"\P{any}"), hir_uclass(&[]),); + } + + #[test] + #[cfg(not(feature = "unicode-age"))] + fn class_unicode_age_disabled() { + assert_eq!( + t_err(r"\p{age:3.0}"), + TestError { + kind: hir::ErrorKind::UnicodePropertyNotFound, + span: Span::new( + Position::new(0, 1, 1), + Position::new(11, 1, 12) + ), + } + ); + } + + #[test] + fn class_bracketed() { + assert_eq!(t("[a]"), hir_lit("a")); + assert_eq!(t("[ab]"), hir_uclass(&[('a', 'b')])); + assert_eq!(t("[^[a]]"), class_negate(uclass(&[('a', 'a')]))); + assert_eq!(t("[a-z]"), hir_uclass(&[('a', 'z')])); + assert_eq!(t("[a-fd-h]"), hir_uclass(&[('a', 'h')])); + assert_eq!(t("[a-fg-m]"), hir_uclass(&[('a', 'm')])); + assert_eq!(t(r"[\x00]"), hir_uclass(&[('\0', '\0')])); + assert_eq!(t(r"[\n]"), hir_uclass(&[('\n', '\n')])); + assert_eq!(t("[\n]"), hir_uclass(&[('\n', '\n')])); + #[cfg(any(feature = "unicode-perl", feature = "unicode-gencat"))] + assert_eq!(t(r"[\d]"), hir_uclass_query(ClassQuery::Binary("digit"))); + #[cfg(feature = "unicode-gencat")] + assert_eq!( + t(r"[\pZ]"), + hir_uclass_query(ClassQuery::Binary("separator")) + ); + #[cfg(feature = "unicode-gencat")] + assert_eq!( + t(r"[\p{separator}]"), + hir_uclass_query(ClassQuery::Binary("separator")) + ); + #[cfg(any(feature = "unicode-perl", feature = "unicode-gencat"))] + assert_eq!(t(r"[^\D]"), hir_uclass_query(ClassQuery::Binary("digit"))); + #[cfg(feature = "unicode-gencat")] + assert_eq!( + t(r"[^\PZ]"), + hir_uclass_query(ClassQuery::Binary("separator")) + ); + #[cfg(feature = "unicode-gencat")] + assert_eq!( + t(r"[^\P{separator}]"), + hir_uclass_query(ClassQuery::Binary("separator")) + ); + #[cfg(all( + feature = "unicode-case", + any(feature = "unicode-perl", feature = "unicode-gencat") + ))] + assert_eq!( + t(r"(?i)[^\D]"), + hir_uclass_query(ClassQuery::Binary("digit")) + ); + #[cfg(all(feature = "unicode-case", feature = "unicode-script"))] + assert_eq!( + t(r"(?i)[^\P{greek}]"), + hir_case_fold(hir_uclass_query(ClassQuery::Binary("greek"))) + ); + + assert_eq!(t("(?-u)[a]"), hir_bclass(&[(b'a', b'a')])); + assert_eq!(t(r"(?-u)[\x00]"), hir_bclass(&[(b'\0', b'\0')])); + assert_eq!(t_bytes(r"(?-u)[\xFF]"), hir_bclass(&[(b'\xFF', b'\xFF')])); + + #[cfg(feature = "unicode-case")] + assert_eq!(t("(?i)[a]"), hir_uclass(&[('A', 'A'), ('a', 'a')])); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i)[k]"), + hir_uclass(&[('K', 'K'), ('k', 'k'), ('\u{212A}', '\u{212A}'),]) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i)[β]"), + hir_uclass(&[('Î’', 'Î’'), ('β', 'β'), ('Ï', 'Ï'),]) + ); + assert_eq!(t("(?i-u)[k]"), hir_bclass(&[(b'K', b'K'), (b'k', b'k'),])); + + assert_eq!(t("[^a]"), class_negate(uclass(&[('a', 'a')]))); + assert_eq!(t(r"[^\x00]"), class_negate(uclass(&[('\0', '\0')]))); + assert_eq!( + t_bytes("(?-u)[^a]"), + class_negate(bclass(&[(b'a', b'a')])) + ); + #[cfg(any(feature = "unicode-perl", feature = "unicode-gencat"))] + assert_eq!( + t(r"[^\d]"), + hir_negate(hir_uclass_query(ClassQuery::Binary("digit"))) + ); + #[cfg(feature = "unicode-gencat")] + assert_eq!( + t(r"[^\pZ]"), + hir_negate(hir_uclass_query(ClassQuery::Binary("separator"))) + ); + #[cfg(feature = "unicode-gencat")] + assert_eq!( + t(r"[^\p{separator}]"), + hir_negate(hir_uclass_query(ClassQuery::Binary("separator"))) + ); + #[cfg(all(feature = "unicode-case", feature = "unicode-script"))] + assert_eq!( + t(r"(?i)[^\p{greek}]"), + hir_negate(hir_case_fold(hir_uclass_query(ClassQuery::Binary( + "greek" + )))) + ); + #[cfg(all(feature = "unicode-case", feature = "unicode-script"))] + assert_eq!( + t(r"(?i)[\P{greek}]"), + hir_negate(hir_case_fold(hir_uclass_query(ClassQuery::Binary( + "greek" + )))) + ); + + // Test some weird cases. + assert_eq!(t(r"[\[]"), hir_uclass(&[('[', '[')])); + + assert_eq!(t(r"[&]"), hir_uclass(&[('&', '&')])); + assert_eq!(t(r"[\&]"), hir_uclass(&[('&', '&')])); + assert_eq!(t(r"[\&\&]"), hir_uclass(&[('&', '&')])); + assert_eq!(t(r"[\x00-&]"), hir_uclass(&[('\0', '&')])); + assert_eq!(t(r"[&-\xFF]"), hir_uclass(&[('&', '\u{FF}')])); + + assert_eq!(t(r"[~]"), hir_uclass(&[('~', '~')])); + assert_eq!(t(r"[\~]"), hir_uclass(&[('~', '~')])); + assert_eq!(t(r"[\~\~]"), hir_uclass(&[('~', '~')])); + assert_eq!(t(r"[\x00-~]"), hir_uclass(&[('\0', '~')])); + assert_eq!(t(r"[~-\xFF]"), hir_uclass(&[('~', '\u{FF}')])); + + assert_eq!(t(r"[-]"), hir_uclass(&[('-', '-')])); + assert_eq!(t(r"[\-]"), hir_uclass(&[('-', '-')])); + assert_eq!(t(r"[\-\-]"), hir_uclass(&[('-', '-')])); + assert_eq!(t(r"[\x00-\-]"), hir_uclass(&[('\0', '-')])); + assert_eq!(t(r"[\--\xFF]"), hir_uclass(&[('-', '\u{FF}')])); + + assert_eq!( + t_err("(?-u)[^a]"), + TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new( + Position::new(5, 1, 6), + Position::new(9, 1, 10) + ), + } + ); + #[cfg(any(feature = "unicode-perl", feature = "unicode-bool"))] + assert_eq!(t(r"[^\s\S]"), hir_uclass(&[]),); + #[cfg(any(feature = "unicode-perl", feature = "unicode-bool"))] + assert_eq!(t_bytes(r"(?-u)[^\s\S]"), hir_bclass(&[]),); + } + + #[test] + fn class_bracketed_union() { + assert_eq!(t("[a-zA-Z]"), hir_uclass(&[('A', 'Z'), ('a', 'z')])); + #[cfg(feature = "unicode-gencat")] + assert_eq!( + t(r"[a\pZb]"), + hir_union( + hir_uclass(&[('a', 'b')]), + hir_uclass_query(ClassQuery::Binary("separator")) + ) + ); + #[cfg(all(feature = "unicode-gencat", feature = "unicode-script"))] + assert_eq!( + t(r"[\pZ\p{Greek}]"), + hir_union( + hir_uclass_query(ClassQuery::Binary("greek")), + hir_uclass_query(ClassQuery::Binary("separator")) + ) + ); + #[cfg(all( + feature = "unicode-age", + feature = "unicode-gencat", + feature = "unicode-script" + ))] + assert_eq!( + t(r"[\p{age:3.0}\pZ\p{Greek}]"), + hir_union( + hir_uclass_query(ClassQuery::ByValue { + property_name: "age", + property_value: "3.0", + }), + hir_union( + hir_uclass_query(ClassQuery::Binary("greek")), + hir_uclass_query(ClassQuery::Binary("separator")) + ) + ) + ); + #[cfg(all( + feature = "unicode-age", + feature = "unicode-gencat", + feature = "unicode-script" + ))] + assert_eq!( + t(r"[[[\p{age:3.0}\pZ]\p{Greek}][\p{Cyrillic}]]"), + hir_union( + hir_uclass_query(ClassQuery::ByValue { + property_name: "age", + property_value: "3.0", + }), + hir_union( + hir_uclass_query(ClassQuery::Binary("cyrillic")), + hir_union( + hir_uclass_query(ClassQuery::Binary("greek")), + hir_uclass_query(ClassQuery::Binary("separator")) + ) + ) + ) + ); + + #[cfg(all( + feature = "unicode-age", + feature = "unicode-case", + feature = "unicode-gencat", + feature = "unicode-script" + ))] + assert_eq!( + t(r"(?i)[\p{age:3.0}\pZ\p{Greek}]"), + hir_case_fold(hir_union( + hir_uclass_query(ClassQuery::ByValue { + property_name: "age", + property_value: "3.0", + }), + hir_union( + hir_uclass_query(ClassQuery::Binary("greek")), + hir_uclass_query(ClassQuery::Binary("separator")) + ) + )) + ); + #[cfg(all( + feature = "unicode-age", + feature = "unicode-gencat", + feature = "unicode-script" + ))] + assert_eq!( + t(r"[^\p{age:3.0}\pZ\p{Greek}]"), + hir_negate(hir_union( + hir_uclass_query(ClassQuery::ByValue { + property_name: "age", + property_value: "3.0", + }), + hir_union( + hir_uclass_query(ClassQuery::Binary("greek")), + hir_uclass_query(ClassQuery::Binary("separator")) + ) + )) + ); + #[cfg(all( + feature = "unicode-age", + feature = "unicode-case", + feature = "unicode-gencat", + feature = "unicode-script" + ))] + assert_eq!( + t(r"(?i)[^\p{age:3.0}\pZ\p{Greek}]"), + hir_negate(hir_case_fold(hir_union( + hir_uclass_query(ClassQuery::ByValue { + property_name: "age", + property_value: "3.0", + }), + hir_union( + hir_uclass_query(ClassQuery::Binary("greek")), + hir_uclass_query(ClassQuery::Binary("separator")) + ) + ))) + ); + } + + #[test] + fn class_bracketed_nested() { + assert_eq!(t(r"[a[^c]]"), class_negate(uclass(&[('c', 'c')]))); + assert_eq!(t(r"[a-b[^c]]"), class_negate(uclass(&[('c', 'c')]))); + assert_eq!(t(r"[a-c[^c]]"), class_negate(uclass(&[]))); + + assert_eq!(t(r"[^a[^c]]"), hir_uclass(&[('c', 'c')])); + assert_eq!(t(r"[^a-b[^c]]"), hir_uclass(&[('c', 'c')])); + + #[cfg(feature = "unicode-case")] + assert_eq!( + t(r"(?i)[a[^c]]"), + hir_negate(class_case_fold(uclass(&[('c', 'c')]))) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t(r"(?i)[a-b[^c]]"), + hir_negate(class_case_fold(uclass(&[('c', 'c')]))) + ); + + #[cfg(feature = "unicode-case")] + assert_eq!(t(r"(?i)[^a[^c]]"), hir_uclass(&[('C', 'C'), ('c', 'c')])); + #[cfg(feature = "unicode-case")] + assert_eq!( + t(r"(?i)[^a-b[^c]]"), + hir_uclass(&[('C', 'C'), ('c', 'c')]) + ); + + assert_eq!(t(r"[^a-c[^c]]"), hir_uclass(&[]),); + #[cfg(feature = "unicode-case")] + assert_eq!(t(r"(?i)[^a-c[^c]]"), hir_uclass(&[]),); + } + + #[test] + fn class_bracketed_intersect() { + assert_eq!(t("[abc&&b-c]"), hir_uclass(&[('b', 'c')])); + assert_eq!(t("[abc&&[b-c]]"), hir_uclass(&[('b', 'c')])); + assert_eq!(t("[[abc]&&[b-c]]"), hir_uclass(&[('b', 'c')])); + assert_eq!(t("[a-z&&b-y&&c-x]"), hir_uclass(&[('c', 'x')])); + assert_eq!(t("[c-da-b&&a-d]"), hir_uclass(&[('a', 'd')])); + assert_eq!(t("[a-d&&c-da-b]"), hir_uclass(&[('a', 'd')])); + assert_eq!(t(r"[a-z&&a-c]"), hir_uclass(&[('a', 'c')])); + assert_eq!(t(r"[[a-z&&a-c]]"), hir_uclass(&[('a', 'c')])); + assert_eq!(t(r"[^[a-z&&a-c]]"), hir_negate(hir_uclass(&[('a', 'c')]))); + + assert_eq!(t("(?-u)[abc&&b-c]"), hir_bclass(&[(b'b', b'c')])); + assert_eq!(t("(?-u)[abc&&[b-c]]"), hir_bclass(&[(b'b', b'c')])); + assert_eq!(t("(?-u)[[abc]&&[b-c]]"), hir_bclass(&[(b'b', b'c')])); + assert_eq!(t("(?-u)[a-z&&b-y&&c-x]"), hir_bclass(&[(b'c', b'x')])); + assert_eq!(t("(?-u)[c-da-b&&a-d]"), hir_bclass(&[(b'a', b'd')])); + assert_eq!(t("(?-u)[a-d&&c-da-b]"), hir_bclass(&[(b'a', b'd')])); + + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i)[abc&&b-c]"), + hir_case_fold(hir_uclass(&[('b', 'c')])) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i)[abc&&[b-c]]"), + hir_case_fold(hir_uclass(&[('b', 'c')])) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i)[[abc]&&[b-c]]"), + hir_case_fold(hir_uclass(&[('b', 'c')])) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i)[a-z&&b-y&&c-x]"), + hir_case_fold(hir_uclass(&[('c', 'x')])) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i)[c-da-b&&a-d]"), + hir_case_fold(hir_uclass(&[('a', 'd')])) + ); + #[cfg(feature = "unicode-case")] + assert_eq!( + t("(?i)[a-d&&c-da-b]"), + hir_case_fold(hir_uclass(&[('a', 'd')])) + ); + + assert_eq!( + t("(?i-u)[abc&&b-c]"), + hir_case_fold(hir_bclass(&[(b'b', b'c')])) + ); + assert_eq!( + t("(?i-u)[abc&&[b-c]]"), + hir_case_fold(hir_bclass(&[(b'b', b'c')])) + ); + assert_eq!( + t("(?i-u)[[abc]&&[b-c]]"), + hir_case_fold(hir_bclass(&[(b'b', b'c')])) + ); + assert_eq!( + t("(?i-u)[a-z&&b-y&&c-x]"), + hir_case_fold(hir_bclass(&[(b'c', b'x')])) + ); + assert_eq!( + t("(?i-u)[c-da-b&&a-d]"), + hir_case_fold(hir_bclass(&[(b'a', b'd')])) + ); + assert_eq!( + t("(?i-u)[a-d&&c-da-b]"), + hir_case_fold(hir_bclass(&[(b'a', b'd')])) + ); + + // In `[a^]`, `^` does not need to be escaped, so it makes sense that + // `^` is also allowed to be unescaped after `&&`. + assert_eq!(t(r"[\^&&^]"), hir_uclass(&[('^', '^')])); + // `]` needs to be escaped after `&&` since it's not at start of class. + assert_eq!(t(r"[]&&\]]"), hir_uclass(&[(']', ']')])); + assert_eq!(t(r"[-&&-]"), hir_uclass(&[('-', '-')])); + assert_eq!(t(r"[\&&&&]"), hir_uclass(&[('&', '&')])); + assert_eq!(t(r"[\&&&\&]"), hir_uclass(&[('&', '&')])); + // Test precedence. + assert_eq!( + t(r"[a-w&&[^c-g]z]"), + hir_uclass(&[('a', 'b'), ('h', 'w')]) + ); + } + + #[test] + fn class_bracketed_intersect_negate() { + #[cfg(feature = "unicode-perl")] + assert_eq!( + t(r"[^\w&&\d]"), + hir_negate(hir_uclass_query(ClassQuery::Binary("digit"))) + ); + assert_eq!(t(r"[^[a-z&&a-c]]"), hir_negate(hir_uclass(&[('a', 'c')]))); + #[cfg(feature = "unicode-perl")] + assert_eq!( + t(r"[^[\w&&\d]]"), + hir_negate(hir_uclass_query(ClassQuery::Binary("digit"))) + ); + #[cfg(feature = "unicode-perl")] + assert_eq!( + t(r"[^[^\w&&\d]]"), + hir_uclass_query(ClassQuery::Binary("digit")) + ); + #[cfg(feature = "unicode-perl")] + assert_eq!(t(r"[[[^\w]&&[^\d]]]"), hir_negate(hir_uclass_perl_word())); + + #[cfg(feature = "unicode-perl")] + assert_eq!( + t_bytes(r"(?-u)[^\w&&\d]"), + hir_negate(hir_ascii_bclass(&ast::ClassAsciiKind::Digit)) + ); + assert_eq!( + t_bytes(r"(?-u)[^[a-z&&a-c]]"), + hir_negate(hir_bclass(&[(b'a', b'c')])) + ); + assert_eq!( + t_bytes(r"(?-u)[^[\w&&\d]]"), + hir_negate(hir_ascii_bclass(&ast::ClassAsciiKind::Digit)) + ); + assert_eq!( + t_bytes(r"(?-u)[^[^\w&&\d]]"), + hir_ascii_bclass(&ast::ClassAsciiKind::Digit) + ); + assert_eq!( + t_bytes(r"(?-u)[[[^\w]&&[^\d]]]"), + hir_negate(hir_ascii_bclass(&ast::ClassAsciiKind::Word)) + ); + } + + #[test] + fn class_bracketed_difference() { + #[cfg(feature = "unicode-gencat")] + assert_eq!( + t(r"[\pL--[:ascii:]]"), + hir_difference( + hir_uclass_query(ClassQuery::Binary("letter")), + hir_uclass(&[('\0', '\x7F')]) + ) + ); + + assert_eq!( + t(r"(?-u)[[:alpha:]--[:lower:]]"), + hir_bclass(&[(b'A', b'Z')]) + ); + } + + #[test] + fn class_bracketed_symmetric_difference() { + #[cfg(feature = "unicode-script")] + assert_eq!( + t(r"[\p{sc:Greek}~~\p{scx:Greek}]"), + hir_uclass(&[ + ('\u{0342}', '\u{0342}'), + ('\u{0345}', '\u{0345}'), + ('\u{1DC0}', '\u{1DC1}'), + ]) + ); + assert_eq!(t(r"[a-g~~c-j]"), hir_uclass(&[('a', 'b'), ('h', 'j')])); + + assert_eq!( + t(r"(?-u)[a-g~~c-j]"), + hir_bclass(&[(b'a', b'b'), (b'h', b'j')]) + ); + } + + #[test] + fn ignore_whitespace() { + assert_eq!(t(r"(?x)\12 3"), hir_lit("\n3")); + assert_eq!(t(r"(?x)\x { 53 }"), hir_lit("S")); + assert_eq!( + t(r"(?x)\x # comment +{ # comment + 53 # comment +} #comment"), + hir_lit("S") + ); + + assert_eq!(t(r"(?x)\x 53"), hir_lit("S")); + assert_eq!( + t(r"(?x)\x # comment + 53 # comment"), + hir_lit("S") + ); + assert_eq!(t(r"(?x)\x5 3"), hir_lit("S")); + + #[cfg(feature = "unicode-gencat")] + assert_eq!( + t(r"(?x)\p # comment +{ # comment + Separator # comment +} # comment"), + hir_uclass_query(ClassQuery::Binary("separator")) + ); + + assert_eq!( + t(r"(?x)a # comment +{ # comment + 5 # comment + , # comment + 10 # comment +} # comment"), + hir_range(true, 5, Some(10), hir_lit("a")) + ); + + assert_eq!(t(r"(?x)a\ # hi there"), hir_lit("a ")); + } + + #[test] + fn analysis_is_utf8() { + // Positive examples. + assert!(props_bytes(r"a").is_utf8()); + assert!(props_bytes(r"ab").is_utf8()); + assert!(props_bytes(r"(?-u)a").is_utf8()); + assert!(props_bytes(r"(?-u)ab").is_utf8()); + assert!(props_bytes(r"\xFF").is_utf8()); + assert!(props_bytes(r"\xFF\xFF").is_utf8()); + assert!(props_bytes(r"[^a]").is_utf8()); + assert!(props_bytes(r"[^a][^a]").is_utf8()); + assert!(props_bytes(r"\b").is_utf8()); + assert!(props_bytes(r"\B").is_utf8()); + assert!(props_bytes(r"(?-u)\b").is_utf8()); + assert!(props_bytes(r"(?-u)\B").is_utf8()); + + // Negative examples. + assert!(!props_bytes(r"(?-u)\xFF").is_utf8()); + assert!(!props_bytes(r"(?-u)\xFF\xFF").is_utf8()); + assert!(!props_bytes(r"(?-u)[^a]").is_utf8()); + assert!(!props_bytes(r"(?-u)[^a][^a]").is_utf8()); + } + + #[test] + fn analysis_captures_len() { + assert_eq!(0, props(r"a").explicit_captures_len()); + assert_eq!(0, props(r"(?:a)").explicit_captures_len()); + assert_eq!(0, props(r"(?i-u:a)").explicit_captures_len()); + assert_eq!(0, props(r"(?i-u)a").explicit_captures_len()); + assert_eq!(1, props(r"(a)").explicit_captures_len()); + assert_eq!(1, props(r"(?Pa)").explicit_captures_len()); + assert_eq!(1, props(r"()").explicit_captures_len()); + assert_eq!(1, props(r"()a").explicit_captures_len()); + assert_eq!(1, props(r"(a)+").explicit_captures_len()); + assert_eq!(2, props(r"(a)(b)").explicit_captures_len()); + assert_eq!(2, props(r"(a)|(b)").explicit_captures_len()); + assert_eq!(2, props(r"((a))").explicit_captures_len()); + assert_eq!(1, props(r"([a&&b])").explicit_captures_len()); + } + + #[test] + fn analysis_static_captures_len() { + let len = |pattern| props(pattern).static_explicit_captures_len(); + assert_eq!(Some(0), len(r"")); + assert_eq!(Some(0), len(r"foo|bar")); + assert_eq!(None, len(r"(foo)|bar")); + assert_eq!(None, len(r"foo|(bar)")); + assert_eq!(Some(1), len(r"(foo|bar)")); + assert_eq!(Some(1), len(r"(a|b|c|d|e|f)")); + assert_eq!(Some(1), len(r"(a)|(b)|(c)|(d)|(e)|(f)")); + assert_eq!(Some(2), len(r"(a)(b)|(c)(d)|(e)(f)")); + assert_eq!(Some(6), len(r"(a)(b)(c)(d)(e)(f)")); + assert_eq!(Some(3), len(r"(a)(b)(extra)|(a)(b)()")); + assert_eq!(Some(3), len(r"(a)(b)((?:extra)?)")); + assert_eq!(None, len(r"(a)(b)(extra)?")); + assert_eq!(Some(1), len(r"(foo)|(bar)")); + assert_eq!(Some(2), len(r"(foo)(bar)")); + assert_eq!(Some(2), len(r"(foo)+(bar)")); + assert_eq!(None, len(r"(foo)*(bar)")); + assert_eq!(Some(0), len(r"(foo)?{0}")); + assert_eq!(None, len(r"(foo)?{1}")); + assert_eq!(Some(1), len(r"(foo){1}")); + assert_eq!(Some(1), len(r"(foo){1,}")); + assert_eq!(Some(1), len(r"(foo){1,}?")); + assert_eq!(None, len(r"(foo){1,}??")); + assert_eq!(None, len(r"(foo){0,}")); + assert_eq!(Some(1), len(r"(foo)(?:bar)")); + assert_eq!(Some(2), len(r"(foo(?:bar)+)(?:baz(boo))")); + assert_eq!(Some(2), len(r"(?Pfoo)(?:bar)(bal|loon)")); + assert_eq!( + Some(2), + len(r#"<(a)[^>]+href="([^"]+)"|<(img)[^>]+src="([^"]+)""#) + ); + } + + #[test] + fn analysis_is_all_assertions() { + // Positive examples. + let p = props(r"\b"); + assert!(!p.look_set().is_empty()); + assert_eq!(p.minimum_len(), Some(0)); + + let p = props(r"\B"); + assert!(!p.look_set().is_empty()); + assert_eq!(p.minimum_len(), Some(0)); + + let p = props(r"^"); + assert!(!p.look_set().is_empty()); + assert_eq!(p.minimum_len(), Some(0)); + + let p = props(r"$"); + assert!(!p.look_set().is_empty()); + assert_eq!(p.minimum_len(), Some(0)); + + let p = props(r"\A"); + assert!(!p.look_set().is_empty()); + assert_eq!(p.minimum_len(), Some(0)); + + let p = props(r"\z"); + assert!(!p.look_set().is_empty()); + assert_eq!(p.minimum_len(), Some(0)); + + let p = props(r"$^\z\A\b\B"); + assert!(!p.look_set().is_empty()); + assert_eq!(p.minimum_len(), Some(0)); + + let p = props(r"$|^|\z|\A|\b|\B"); + assert!(!p.look_set().is_empty()); + assert_eq!(p.minimum_len(), Some(0)); + + let p = props(r"^$|$^"); + assert!(!p.look_set().is_empty()); + assert_eq!(p.minimum_len(), Some(0)); + + let p = props(r"((\b)+())*^"); + assert!(!p.look_set().is_empty()); + assert_eq!(p.minimum_len(), Some(0)); + + // Negative examples. + let p = props(r"^a"); + assert!(!p.look_set().is_empty()); + assert_eq!(p.minimum_len(), Some(1)); + } + + #[test] + fn analysis_look_set_prefix_any() { + let p = props(r"(?-u)(?i:(?:\b|_)win(?:32|64|dows)?(?:\b|_))"); + assert!(p.look_set_prefix_any().contains(Look::WordAscii)); + } + + #[test] + fn analysis_is_anchored() { + let is_start = |p| props(p).look_set_prefix().contains(Look::Start); + let is_end = |p| props(p).look_set_suffix().contains(Look::End); + + // Positive examples. + assert!(is_start(r"^")); + assert!(is_end(r"$")); + + assert!(is_start(r"^^")); + assert!(props(r"$$").look_set_suffix().contains(Look::End)); + + assert!(is_start(r"^$")); + assert!(is_end(r"^$")); + + assert!(is_start(r"^foo")); + assert!(is_end(r"foo$")); + + assert!(is_start(r"^foo|^bar")); + assert!(is_end(r"foo$|bar$")); + + assert!(is_start(r"^(foo|bar)")); + assert!(is_end(r"(foo|bar)$")); + + assert!(is_start(r"^+")); + assert!(is_end(r"$+")); + assert!(is_start(r"^++")); + assert!(is_end(r"$++")); + assert!(is_start(r"(^)+")); + assert!(is_end(r"($)+")); + + assert!(is_start(r"$^")); + assert!(is_start(r"$^")); + assert!(is_start(r"$^|^$")); + assert!(is_end(r"$^|^$")); + + assert!(is_start(r"\b^")); + assert!(is_end(r"$\b")); + assert!(is_start(r"^(?m:^)")); + assert!(is_end(r"(?m:$)$")); + assert!(is_start(r"(?m:^)^")); + assert!(is_end(r"$(?m:$)")); + + // Negative examples. + assert!(!is_start(r"(?m)^")); + assert!(!is_end(r"(?m)$")); + assert!(!is_start(r"(?m:^$)|$^")); + assert!(!is_end(r"(?m:^$)|$^")); + assert!(!is_start(r"$^|(?m:^$)")); + assert!(!is_end(r"$^|(?m:^$)")); + + assert!(!is_start(r"a^")); + assert!(!is_start(r"$a")); + + assert!(!is_end(r"a^")); + assert!(!is_end(r"$a")); + + assert!(!is_start(r"^foo|bar")); + assert!(!is_end(r"foo|bar$")); + + assert!(!is_start(r"^*")); + assert!(!is_end(r"$*")); + assert!(!is_start(r"^*+")); + assert!(!is_end(r"$*+")); + assert!(!is_start(r"^+*")); + assert!(!is_end(r"$+*")); + assert!(!is_start(r"(^)*")); + assert!(!is_end(r"($)*")); + } + + #[test] + fn analysis_is_any_anchored() { + let is_start = |p| props(p).look_set().contains(Look::Start); + let is_end = |p| props(p).look_set().contains(Look::End); + + // Positive examples. + assert!(is_start(r"^")); + assert!(is_end(r"$")); + assert!(is_start(r"\A")); + assert!(is_end(r"\z")); + + // Negative examples. + assert!(!is_start(r"(?m)^")); + assert!(!is_end(r"(?m)$")); + assert!(!is_start(r"$")); + assert!(!is_end(r"^")); + } + + #[test] + fn analysis_can_empty() { + // Positive examples. + let assert_empty = + |p| assert_eq!(Some(0), props_bytes(p).minimum_len()); + assert_empty(r""); + assert_empty(r"()"); + assert_empty(r"()*"); + assert_empty(r"()+"); + assert_empty(r"()?"); + assert_empty(r"a*"); + assert_empty(r"a?"); + assert_empty(r"a{0}"); + assert_empty(r"a{0,}"); + assert_empty(r"a{0,1}"); + assert_empty(r"a{0,10}"); + #[cfg(feature = "unicode-gencat")] + assert_empty(r"\pL*"); + assert_empty(r"a*|b"); + assert_empty(r"b|a*"); + assert_empty(r"a|"); + assert_empty(r"|a"); + assert_empty(r"a||b"); + assert_empty(r"a*a?(abcd)*"); + assert_empty(r"^"); + assert_empty(r"$"); + assert_empty(r"(?m)^"); + assert_empty(r"(?m)$"); + assert_empty(r"\A"); + assert_empty(r"\z"); + assert_empty(r"\B"); + assert_empty(r"(?-u)\B"); + assert_empty(r"\b"); + assert_empty(r"(?-u)\b"); + + // Negative examples. + let assert_non_empty = + |p| assert_ne!(Some(0), props_bytes(p).minimum_len()); + assert_non_empty(r"a+"); + assert_non_empty(r"a{1}"); + assert_non_empty(r"a{1,}"); + assert_non_empty(r"a{1,2}"); + assert_non_empty(r"a{1,10}"); + assert_non_empty(r"b|a"); + assert_non_empty(r"a*a+(abcd)*"); + #[cfg(feature = "unicode-gencat")] + assert_non_empty(r"\P{any}"); + assert_non_empty(r"[a--a]"); + assert_non_empty(r"[a&&b]"); + } + + #[test] + fn analysis_is_literal() { + // Positive examples. + assert!(props(r"a").is_literal()); + assert!(props(r"ab").is_literal()); + assert!(props(r"abc").is_literal()); + assert!(props(r"(?m)abc").is_literal()); + assert!(props(r"(?:a)").is_literal()); + assert!(props(r"foo(?:a)").is_literal()); + assert!(props(r"(?:a)foo").is_literal()); + assert!(props(r"[a]").is_literal()); + + // Negative examples. + assert!(!props(r"").is_literal()); + assert!(!props(r"^").is_literal()); + assert!(!props(r"a|b").is_literal()); + assert!(!props(r"(a)").is_literal()); + assert!(!props(r"a+").is_literal()); + assert!(!props(r"foo(a)").is_literal()); + assert!(!props(r"(a)foo").is_literal()); + assert!(!props(r"[ab]").is_literal()); + } + + #[test] + fn analysis_is_alternation_literal() { + // Positive examples. + assert!(props(r"a").is_alternation_literal()); + assert!(props(r"ab").is_alternation_literal()); + assert!(props(r"abc").is_alternation_literal()); + assert!(props(r"(?m)abc").is_alternation_literal()); + assert!(props(r"foo|bar").is_alternation_literal()); + assert!(props(r"foo|bar|baz").is_alternation_literal()); + assert!(props(r"[a]").is_alternation_literal()); + assert!(props(r"(?:ab)|cd").is_alternation_literal()); + assert!(props(r"ab|(?:cd)").is_alternation_literal()); + + // Negative examples. + assert!(!props(r"").is_alternation_literal()); + assert!(!props(r"^").is_alternation_literal()); + assert!(!props(r"(a)").is_alternation_literal()); + assert!(!props(r"a+").is_alternation_literal()); + assert!(!props(r"foo(a)").is_alternation_literal()); + assert!(!props(r"(a)foo").is_alternation_literal()); + assert!(!props(r"[ab]").is_alternation_literal()); + assert!(!props(r"[ab]|b").is_alternation_literal()); + assert!(!props(r"a|[ab]").is_alternation_literal()); + assert!(!props(r"(a)|b").is_alternation_literal()); + assert!(!props(r"a|(b)").is_alternation_literal()); + assert!(!props(r"a|b").is_alternation_literal()); + assert!(!props(r"a|b|c").is_alternation_literal()); + assert!(!props(r"[a]|b").is_alternation_literal()); + assert!(!props(r"a|[b]").is_alternation_literal()); + assert!(!props(r"(?:a)|b").is_alternation_literal()); + assert!(!props(r"a|(?:b)").is_alternation_literal()); + assert!(!props(r"(?:z|xx)@|xx").is_alternation_literal()); + } + + // This tests that the smart Hir::repetition constructors does some basic + // simplifications. + #[test] + fn smart_repetition() { + assert_eq!(t(r"a{0}"), Hir::empty()); + assert_eq!(t(r"a{1}"), hir_lit("a")); + assert_eq!(t(r"\B{32111}"), hir_look(hir::Look::WordUnicodeNegate)); + } + + // This tests that the smart Hir::concat constructor simplifies the given + // exprs in a way we expect. + #[test] + fn smart_concat() { + assert_eq!(t(""), Hir::empty()); + assert_eq!(t("(?:)"), Hir::empty()); + assert_eq!(t("abc"), hir_lit("abc")); + assert_eq!(t("(?:foo)(?:bar)"), hir_lit("foobar")); + assert_eq!(t("quux(?:foo)(?:bar)baz"), hir_lit("quuxfoobarbaz")); + assert_eq!( + t("foo(?:bar^baz)quux"), + hir_cat(vec![ + hir_lit("foobar"), + hir_look(hir::Look::Start), + hir_lit("bazquux"), + ]) + ); + assert_eq!( + t("foo(?:ba(?:r^b)az)quux"), + hir_cat(vec![ + hir_lit("foobar"), + hir_look(hir::Look::Start), + hir_lit("bazquux"), + ]) + ); + } + + // This tests that the smart Hir::alternation constructor simplifies the + // given exprs in a way we expect. + #[test] + fn smart_alternation() { + assert_eq!( + t("(?:foo)|(?:bar)"), + hir_alt(vec![hir_lit("foo"), hir_lit("bar")]) + ); + assert_eq!( + t("quux|(?:abc|def|xyz)|baz"), + hir_alt(vec![ + hir_lit("quux"), + hir_lit("abc"), + hir_lit("def"), + hir_lit("xyz"), + hir_lit("baz"), + ]) + ); + assert_eq!( + t("quux|(?:abc|(?:def|mno)|xyz)|baz"), + hir_alt(vec![ + hir_lit("quux"), + hir_lit("abc"), + hir_lit("def"), + hir_lit("mno"), + hir_lit("xyz"), + hir_lit("baz"), + ]) + ); + assert_eq!( + t("a|b|c|d|e|f|x|y|z"), + hir_uclass(&[('a', 'f'), ('x', 'z')]), + ); + // Tests that we lift common prefixes out of an alternation. + assert_eq!( + t("[A-Z]foo|[A-Z]quux"), + hir_cat(vec![ + hir_uclass(&[('A', 'Z')]), + hir_alt(vec![hir_lit("foo"), hir_lit("quux")]), + ]), + ); + assert_eq!( + t("[A-Z][A-Z]|[A-Z]quux"), + hir_cat(vec![ + hir_uclass(&[('A', 'Z')]), + hir_alt(vec![hir_uclass(&[('A', 'Z')]), hir_lit("quux")]), + ]), + ); + assert_eq!( + t("[A-Z][A-Z]|[A-Z][A-Z]quux"), + hir_cat(vec![ + hir_uclass(&[('A', 'Z')]), + hir_uclass(&[('A', 'Z')]), + hir_alt(vec![Hir::empty(), hir_lit("quux")]), + ]), + ); + assert_eq!( + t("[A-Z]foo|[A-Z]foobar"), + hir_cat(vec![ + hir_uclass(&[('A', 'Z')]), + hir_alt(vec![hir_lit("foo"), hir_lit("foobar")]), + ]), + ); + } +} diff --git a/vendor/regex-syntax-0.7.5/src/hir/visitor.rs b/vendor/regex-syntax-0.7.5/src/hir/visitor.rs new file mode 100644 index 0000000000000..f30f0a163e46b --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/hir/visitor.rs @@ -0,0 +1,215 @@ +use alloc::{vec, vec::Vec}; + +use crate::hir::{self, Hir, HirKind}; + +/// A trait for visiting the high-level IR (HIR) in depth first order. +/// +/// The principle aim of this trait is to enable callers to perform case +/// analysis on a high-level intermediate representation of a regular +/// expression without necessarily using recursion. In particular, this permits +/// callers to do case analysis with constant stack usage, which can be +/// important since the size of an HIR may be proportional to end user input. +/// +/// Typical usage of this trait involves providing an implementation and then +/// running it using the [`visit`] function. +pub trait Visitor { + /// The result of visiting an HIR. + type Output; + /// An error that visiting an HIR might return. + type Err; + + /// All implementors of `Visitor` must provide a `finish` method, which + /// yields the result of visiting the HIR or an error. + fn finish(self) -> Result; + + /// This method is called before beginning traversal of the HIR. + fn start(&mut self) {} + + /// This method is called on an `Hir` before descending into child `Hir` + /// nodes. + fn visit_pre(&mut self, _hir: &Hir) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called on an `Hir` after descending all of its child + /// `Hir` nodes. + fn visit_post(&mut self, _hir: &Hir) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called between child nodes of an alternation. + fn visit_alternation_in(&mut self) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called between child nodes of a concatenation. + fn visit_concat_in(&mut self) -> Result<(), Self::Err> { + Ok(()) + } +} + +/// Executes an implementation of `Visitor` in constant stack space. +/// +/// This function will visit every node in the given `Hir` while calling +/// appropriate methods provided by the [`Visitor`] trait. +/// +/// The primary use case for this method is when one wants to perform case +/// analysis over an `Hir` without using a stack size proportional to the depth +/// of the `Hir`. Namely, this method will instead use constant stack space, +/// but will use heap space proportional to the size of the `Hir`. This may be +/// desirable in cases where the size of `Hir` is proportional to end user +/// input. +/// +/// If the visitor returns an error at any point, then visiting is stopped and +/// the error is returned. +pub fn visit(hir: &Hir, visitor: V) -> Result { + HeapVisitor::new().visit(hir, visitor) +} + +/// HeapVisitor visits every item in an `Hir` recursively using constant stack +/// size and a heap size proportional to the size of the `Hir`. +struct HeapVisitor<'a> { + /// A stack of `Hir` nodes. This is roughly analogous to the call stack + /// used in a typical recursive visitor. + stack: Vec<(&'a Hir, Frame<'a>)>, +} + +/// Represents a single stack frame while performing structural induction over +/// an `Hir`. +enum Frame<'a> { + /// A stack frame allocated just before descending into a repetition + /// operator's child node. + Repetition(&'a hir::Repetition), + /// A stack frame allocated just before descending into a capture's child + /// node. + Capture(&'a hir::Capture), + /// The stack frame used while visiting every child node of a concatenation + /// of expressions. + Concat { + /// The child node we are currently visiting. + head: &'a Hir, + /// The remaining child nodes to visit (which may be empty). + tail: &'a [Hir], + }, + /// The stack frame used while visiting every child node of an alternation + /// of expressions. + Alternation { + /// The child node we are currently visiting. + head: &'a Hir, + /// The remaining child nodes to visit (which may be empty). + tail: &'a [Hir], + }, +} + +impl<'a> HeapVisitor<'a> { + fn new() -> HeapVisitor<'a> { + HeapVisitor { stack: vec![] } + } + + fn visit( + &mut self, + mut hir: &'a Hir, + mut visitor: V, + ) -> Result { + self.stack.clear(); + + visitor.start(); + loop { + visitor.visit_pre(hir)?; + if let Some(x) = self.induct(hir) { + let child = x.child(); + self.stack.push((hir, x)); + hir = child; + continue; + } + // No induction means we have a base case, so we can post visit + // it now. + visitor.visit_post(hir)?; + + // At this point, we now try to pop our call stack until it is + // either empty or we hit another inductive case. + loop { + let (post_hir, frame) = match self.stack.pop() { + None => return visitor.finish(), + Some((post_hir, frame)) => (post_hir, frame), + }; + // If this is a concat/alternate, then we might have additional + // inductive steps to process. + if let Some(x) = self.pop(frame) { + match x { + Frame::Alternation { .. } => { + visitor.visit_alternation_in()?; + } + Frame::Concat { .. } => { + visitor.visit_concat_in()?; + } + _ => {} + } + hir = x.child(); + self.stack.push((post_hir, x)); + break; + } + // Otherwise, we've finished visiting all the child nodes for + // this HIR, so we can post visit it now. + visitor.visit_post(post_hir)?; + } + } + } + + /// Build a stack frame for the given HIR if one is needed (which occurs if + /// and only if there are child nodes in the HIR). Otherwise, return None. + fn induct(&mut self, hir: &'a Hir) -> Option> { + match *hir.kind() { + HirKind::Repetition(ref x) => Some(Frame::Repetition(x)), + HirKind::Capture(ref x) => Some(Frame::Capture(x)), + HirKind::Concat(ref x) if x.is_empty() => None, + HirKind::Concat(ref x) => { + Some(Frame::Concat { head: &x[0], tail: &x[1..] }) + } + HirKind::Alternation(ref x) if x.is_empty() => None, + HirKind::Alternation(ref x) => { + Some(Frame::Alternation { head: &x[0], tail: &x[1..] }) + } + _ => None, + } + } + + /// Pops the given frame. If the frame has an additional inductive step, + /// then return it, otherwise return `None`. + fn pop(&self, induct: Frame<'a>) -> Option> { + match induct { + Frame::Repetition(_) => None, + Frame::Capture(_) => None, + Frame::Concat { tail, .. } => { + if tail.is_empty() { + None + } else { + Some(Frame::Concat { head: &tail[0], tail: &tail[1..] }) + } + } + Frame::Alternation { tail, .. } => { + if tail.is_empty() { + None + } else { + Some(Frame::Alternation { + head: &tail[0], + tail: &tail[1..], + }) + } + } + } + } +} + +impl<'a> Frame<'a> { + /// Perform the next inductive step on this frame and return the next + /// child HIR node to visit. + fn child(&self) -> &'a Hir { + match *self { + Frame::Repetition(rep) => &rep.sub, + Frame::Capture(capture) => &capture.sub, + Frame::Concat { head, .. } => head, + Frame::Alternation { head, .. } => head, + } + } +} diff --git a/vendor/regex-syntax-0.7.5/src/lib.rs b/vendor/regex-syntax-0.7.5/src/lib.rs new file mode 100644 index 0000000000000..47d818a17fb88 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/lib.rs @@ -0,0 +1,440 @@ +/*! +This crate provides a robust regular expression parser. + +This crate defines two primary types: + +* [`Ast`](ast::Ast) is the abstract syntax of a regular expression. + An abstract syntax corresponds to a *structured representation* of the + concrete syntax of a regular expression, where the concrete syntax is the + pattern string itself (e.g., `foo(bar)+`). Given some abstract syntax, it + can be converted back to the original concrete syntax (modulo some details, + like whitespace). To a first approximation, the abstract syntax is complex + and difficult to analyze. +* [`Hir`](hir::Hir) is the high-level intermediate representation + ("HIR" or "high-level IR" for short) of regular expression. It corresponds to + an intermediate state of a regular expression that sits between the abstract + syntax and the low level compiled opcodes that are eventually responsible for + executing a regular expression search. Given some high-level IR, it is not + possible to produce the original concrete syntax (although it is possible to + produce an equivalent concrete syntax, but it will likely scarcely resemble + the original pattern). To a first approximation, the high-level IR is simple + and easy to analyze. + +These two types come with conversion routines: + +* An [`ast::parse::Parser`] converts concrete syntax (a `&str`) to an +[`Ast`](ast::Ast). +* A [`hir::translate::Translator`] converts an [`Ast`](ast::Ast) to a +[`Hir`](hir::Hir). + +As a convenience, the above two conversion routines are combined into one via +the top-level [`Parser`] type. This `Parser` will first convert your pattern to +an `Ast` and then convert the `Ast` to an `Hir`. It's also exposed as top-level +[`parse`] free function. + + +# Example + +This example shows how to parse a pattern string into its HIR: + +``` +use regex_syntax::{hir::Hir, parse}; + +let hir = parse("a|b")?; +assert_eq!(hir, Hir::alternation(vec![ + Hir::literal("a".as_bytes()), + Hir::literal("b".as_bytes()), +])); +# Ok::<(), Box>(()) +``` + + +# Concrete syntax supported + +The concrete syntax is documented as part of the public API of the +[`regex` crate](https://docs.rs/regex/%2A/regex/#syntax). + + +# Input safety + +A key feature of this library is that it is safe to use with end user facing +input. This plays a significant role in the internal implementation. In +particular: + +1. Parsers provide a `nest_limit` option that permits callers to control how + deeply nested a regular expression is allowed to be. This makes it possible + to do case analysis over an `Ast` or an `Hir` using recursion without + worrying about stack overflow. +2. Since relying on a particular stack size is brittle, this crate goes to + great lengths to ensure that all interactions with both the `Ast` and the + `Hir` do not use recursion. Namely, they use constant stack space and heap + space proportional to the size of the original pattern string (in bytes). + This includes the type's corresponding destructors. (One exception to this + is literal extraction, but this will eventually get fixed.) + + +# Error reporting + +The `Display` implementations on all `Error` types exposed in this library +provide nice human readable errors that are suitable for showing to end users +in a monospace font. + + +# Literal extraction + +This crate provides limited support for [literal extraction from `Hir` +values](hir::literal). Be warned that literal extraction uses recursion, and +therefore, stack size proportional to the size of the `Hir`. + +The purpose of literal extraction is to speed up searches. That is, if you +know a regular expression must match a prefix or suffix literal, then it is +often quicker to search for instances of that literal, and then confirm or deny +the match using the full regular expression engine. These optimizations are +done automatically in the `regex` crate. + + +# Crate features + +An important feature provided by this crate is its Unicode support. This +includes things like case folding, boolean properties, general categories, +scripts and Unicode-aware support for the Perl classes `\w`, `\s` and `\d`. +However, a downside of this support is that it requires bundling several +Unicode data tables that are substantial in size. + +A fair number of use cases do not require full Unicode support. For this +reason, this crate exposes a number of features to control which Unicode +data is available. + +If a regular expression attempts to use a Unicode feature that is not available +because the corresponding crate feature was disabled, then translating that +regular expression to an `Hir` will return an error. (It is still possible +construct an `Ast` for such a regular expression, since Unicode data is not +used until translation to an `Hir`.) Stated differently, enabling or disabling +any of the features below can only add or subtract from the total set of valid +regular expressions. Enabling or disabling a feature will never modify the +match semantics of a regular expression. + +The following features are available: + +* **std** - + Enables support for the standard library. This feature is enabled by default. + When disabled, only `core` and `alloc` are used. Otherwise, enabling `std` + generally just enables `std::error::Error` trait impls for the various error + types. +* **unicode** - + Enables all Unicode features. This feature is enabled by default, and will + always cover all Unicode features, even if more are added in the future. +* **unicode-age** - + Provide the data for the + [Unicode `Age` property](https://www.unicode.org/reports/tr44/tr44-24.html#Character_Age). + This makes it possible to use classes like `\p{Age:6.0}` to refer to all + codepoints first introduced in Unicode 6.0 +* **unicode-bool** - + Provide the data for numerous Unicode boolean properties. The full list + is not included here, but contains properties like `Alphabetic`, `Emoji`, + `Lowercase`, `Math`, `Uppercase` and `White_Space`. +* **unicode-case** - + Provide the data for case insensitive matching using + [Unicode's "simple loose matches" specification](https://www.unicode.org/reports/tr18/#Simple_Loose_Matches). +* **unicode-gencat** - + Provide the data for + [Unicode general categories](https://www.unicode.org/reports/tr44/tr44-24.html#General_Category_Values). + This includes, but is not limited to, `Decimal_Number`, `Letter`, + `Math_Symbol`, `Number` and `Punctuation`. +* **unicode-perl** - + Provide the data for supporting the Unicode-aware Perl character classes, + corresponding to `\w`, `\s` and `\d`. This is also necessary for using + Unicode-aware word boundary assertions. Note that if this feature is + disabled, the `\s` and `\d` character classes are still available if the + `unicode-bool` and `unicode-gencat` features are enabled, respectively. +* **unicode-script** - + Provide the data for + [Unicode scripts and script extensions](https://www.unicode.org/reports/tr24/). + This includes, but is not limited to, `Arabic`, `Cyrillic`, `Hebrew`, + `Latin` and `Thai`. +* **unicode-segment** - + Provide the data necessary to provide the properties used to implement the + [Unicode text segmentation algorithms](https://www.unicode.org/reports/tr29/). + This enables using classes like `\p{gcb=Extend}`, `\p{wb=Katakana}` and + `\p{sb=ATerm}`. +* **arbitrary** - + Enabling this feature introduces a public dependency on the + [`arbitrary`](https://crates.io/crates/arbitrary) + crate. Namely, it implements the `Arbitrary` trait from that crate for the + [`Ast`](crate::ast::Ast) type. This feature is disabled by default. +*/ + +#![no_std] +#![forbid(unsafe_code)] +#![deny(missing_docs, rustdoc::broken_intra_doc_links)] +#![warn(missing_debug_implementations)] +// MSRV(1.62): Allow unused warnings. Needed for the 'allow' below, +// since the warning is no longer triggered in newer Rust releases. +// Once the 'allow(mutable_borrow_reservation_conflict)' can be +// removed, we can remove the 'allow(renamed_and_removed_lints)' too. +#![allow(renamed_and_removed_lints)] +// MSRV(1.62): This gets triggered on Rust <1.62, and since our MSRV +// is Rust 1.60 at the time of writing, a warning is displayed. But +// the lang team decided the code pattern flagged by this warning is +// OK, so the warning is innocuous. We can remove this explicit allow +// once we get to a Rust release where the warning is no longer +// triggered. I believe that's Rust 1.62. +#![allow(mutable_borrow_reservation_conflict)] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] + +#[cfg(any(test, feature = "std"))] +extern crate std; + +extern crate alloc; + +pub use crate::{ + error::Error, + parser::{parse, Parser, ParserBuilder}, + unicode::UnicodeWordError, +}; + +use alloc::string::String; + +pub mod ast; +mod debug; +mod either; +mod error; +pub mod hir; +mod parser; +mod rank; +mod unicode; +mod unicode_tables; +pub mod utf8; + +/// Escapes all regular expression meta characters in `text`. +/// +/// The string returned may be safely used as a literal in a regular +/// expression. +pub fn escape(text: &str) -> String { + let mut quoted = String::new(); + escape_into(text, &mut quoted); + quoted +} + +/// Escapes all meta characters in `text` and writes the result into `buf`. +/// +/// This will append escape characters into the given buffer. The characters +/// that are appended are safe to use as a literal in a regular expression. +pub fn escape_into(text: &str, buf: &mut String) { + buf.reserve(text.len()); + for c in text.chars() { + if is_meta_character(c) { + buf.push('\\'); + } + buf.push(c); + } +} + +/// Returns true if the given character has significance in a regex. +/// +/// Generally speaking, these are the only characters which _must_ be escaped +/// in order to match their literal meaning. For example, to match a literal +/// `|`, one could write `\|`. Sometimes escaping isn't always necessary. For +/// example, `-` is treated as a meta character because of its significance +/// for writing ranges inside of character classes, but the regex `-` will +/// match a literal `-` because `-` has no special meaning outside of character +/// classes. +/// +/// In order to determine whether a character may be escaped at all, the +/// [`is_escapeable_character`] routine should be used. The difference between +/// `is_meta_character` and `is_escapeable_character` is that the latter will +/// return true for some characters that are _not_ meta characters. For +/// example, `%` and `\%` both match a literal `%` in all contexts. In other +/// words, `is_escapeable_character` includes "superfluous" escapes. +/// +/// Note that the set of characters for which this function returns `true` or +/// `false` is fixed and won't change in a semver compatible release. (In this +/// case, "semver compatible release" actually refers to the `regex` crate +/// itself, since reducing or expanding the set of meta characters would be a +/// breaking change for not just `regex-syntax` but also `regex` itself.) +/// +/// # Example +/// +/// ``` +/// use regex_syntax::is_meta_character; +/// +/// assert!(is_meta_character('?')); +/// assert!(is_meta_character('-')); +/// assert!(is_meta_character('&')); +/// assert!(is_meta_character('#')); +/// +/// assert!(!is_meta_character('%')); +/// assert!(!is_meta_character('/')); +/// assert!(!is_meta_character('!')); +/// assert!(!is_meta_character('"')); +/// assert!(!is_meta_character('e')); +/// ``` +pub fn is_meta_character(c: char) -> bool { + match c { + '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' + | '}' | '^' | '$' | '#' | '&' | '-' | '~' => true, + _ => false, + } +} + +/// Returns true if the given character can be escaped in a regex. +/// +/// This returns true in all cases that `is_meta_character` returns true, but +/// also returns true in some cases where `is_meta_character` returns false. +/// For example, `%` is not a meta character, but it is escapeable. That is, +/// `%` and `\%` both match a literal `%` in all contexts. +/// +/// The purpose of this routine is to provide knowledge about what characters +/// may be escaped. Namely, most regex engines permit "superfluous" escapes +/// where characters without any special significance may be escaped even +/// though there is no actual _need_ to do so. +/// +/// This will return false for some characters. For example, `e` is not +/// escapeable. Therefore, `\e` will either result in a parse error (which is +/// true today), or it could backwards compatibly evolve into a new construct +/// with its own meaning. Indeed, that is the purpose of banning _some_ +/// superfluous escapes: it provides a way to evolve the syntax in a compatible +/// manner. +/// +/// # Example +/// +/// ``` +/// use regex_syntax::is_escapeable_character; +/// +/// assert!(is_escapeable_character('?')); +/// assert!(is_escapeable_character('-')); +/// assert!(is_escapeable_character('&')); +/// assert!(is_escapeable_character('#')); +/// assert!(is_escapeable_character('%')); +/// assert!(is_escapeable_character('/')); +/// assert!(is_escapeable_character('!')); +/// assert!(is_escapeable_character('"')); +/// +/// assert!(!is_escapeable_character('e')); +/// ``` +pub fn is_escapeable_character(c: char) -> bool { + // Certainly escapeable if it's a meta character. + if is_meta_character(c) { + return true; + } + // Any character that isn't ASCII is definitely not escapeable. There's + // no real need to allow things like \☃ right? + if !c.is_ascii() { + return false; + } + // Otherwise, we basically say that everything is escapeable unless it's a + // letter or digit. Things like \3 are either octal (when enabled) or an + // error, and we should keep it that way. Otherwise, letters are reserved + // for adding new syntax in a backwards compatible way. + match c { + '0'..='9' | 'A'..='Z' | 'a'..='z' => false, + // While not currently supported, we keep these as not escapeable to + // give us some flexibility with respect to supporting the \< and + // \> word boundary assertions in the future. By rejecting them as + // escapeable, \< and \> will result in a parse error. Thus, we can + // turn them into something else in the future without it being a + // backwards incompatible change. + '<' | '>' => false, + _ => true, + } +} + +/// Returns true if and only if the given character is a Unicode word +/// character. +/// +/// A Unicode word character is defined by +/// [UTS#18 Annex C](https://unicode.org/reports/tr18/#Compatibility_Properties). +/// In particular, a character +/// is considered a word character if it is in either of the `Alphabetic` or +/// `Join_Control` properties, or is in one of the `Decimal_Number`, `Mark` +/// or `Connector_Punctuation` general categories. +/// +/// # Panics +/// +/// If the `unicode-perl` feature is not enabled, then this function +/// panics. For this reason, it is recommended that callers use +/// [`try_is_word_character`] instead. +pub fn is_word_character(c: char) -> bool { + try_is_word_character(c).expect("unicode-perl feature must be enabled") +} + +/// Returns true if and only if the given character is a Unicode word +/// character. +/// +/// A Unicode word character is defined by +/// [UTS#18 Annex C](https://unicode.org/reports/tr18/#Compatibility_Properties). +/// In particular, a character +/// is considered a word character if it is in either of the `Alphabetic` or +/// `Join_Control` properties, or is in one of the `Decimal_Number`, `Mark` +/// or `Connector_Punctuation` general categories. +/// +/// # Errors +/// +/// If the `unicode-perl` feature is not enabled, then this function always +/// returns an error. +pub fn try_is_word_character( + c: char, +) -> core::result::Result { + unicode::is_word_character(c) +} + +/// Returns true if and only if the given character is an ASCII word character. +/// +/// An ASCII word character is defined by the following character class: +/// `[_0-9a-zA-Z]'. +pub fn is_word_byte(c: u8) -> bool { + match c { + b'_' | b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' => true, + _ => false, + } +} + +#[cfg(test)] +mod tests { + use alloc::string::ToString; + + use super::*; + + #[test] + fn escape_meta() { + assert_eq!( + escape(r"\.+*?()|[]{}^$#&-~"), + r"\\\.\+\*\?\(\)\|\[\]\{\}\^\$\#\&\-\~".to_string() + ); + } + + #[test] + fn word_byte() { + assert!(is_word_byte(b'a')); + assert!(!is_word_byte(b'-')); + } + + #[test] + #[cfg(feature = "unicode-perl")] + fn word_char() { + assert!(is_word_character('a'), "ASCII"); + assert!(is_word_character('à'), "Latin-1"); + assert!(is_word_character('β'), "Greek"); + assert!(is_word_character('\u{11011}'), "Brahmi (Unicode 6.0)"); + assert!(is_word_character('\u{11611}'), "Modi (Unicode 7.0)"); + assert!(is_word_character('\u{11711}'), "Ahom (Unicode 8.0)"); + assert!(is_word_character('\u{17828}'), "Tangut (Unicode 9.0)"); + assert!(is_word_character('\u{1B1B1}'), "Nushu (Unicode 10.0)"); + assert!(is_word_character('\u{16E40}'), "Medefaidrin (Unicode 11.0)"); + assert!(!is_word_character('-')); + assert!(!is_word_character('☃')); + } + + #[test] + #[should_panic] + #[cfg(not(feature = "unicode-perl"))] + fn word_char_disabled_panic() { + assert!(is_word_character('a')); + } + + #[test] + #[cfg(not(feature = "unicode-perl"))] + fn word_char_disabled_error() { + assert!(try_is_word_character('a').is_err()); + } +} diff --git a/vendor/regex-syntax-0.7.5/src/parser.rs b/vendor/regex-syntax-0.7.5/src/parser.rs new file mode 100644 index 0000000000000..f482b84667a7a --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/parser.rs @@ -0,0 +1,254 @@ +use crate::{ast, hir, Error}; + +/// A convenience routine for parsing a regex using default options. +/// +/// This is equivalent to `Parser::new().parse(pattern)`. +/// +/// If you need to set non-default options, then use a [`ParserBuilder`]. +/// +/// This routine returns an [`Hir`](hir::Hir) value. Namely, it automatically +/// parses the pattern as an [`Ast`](ast::Ast) and then invokes the translator +/// to convert the `Ast` into an `Hir`. If you need access to the `Ast`, then +/// you should use a [`ast::parse::Parser`]. +pub fn parse(pattern: &str) -> Result { + Parser::new().parse(pattern) +} + +/// A builder for a regular expression parser. +/// +/// This builder permits modifying configuration options for the parser. +/// +/// This type combines the builder options for both the [AST +/// `ParserBuilder`](ast::parse::ParserBuilder) and the [HIR +/// `TranslatorBuilder`](hir::translate::TranslatorBuilder). +#[derive(Clone, Debug, Default)] +pub struct ParserBuilder { + ast: ast::parse::ParserBuilder, + hir: hir::translate::TranslatorBuilder, +} + +impl ParserBuilder { + /// Create a new parser builder with a default configuration. + pub fn new() -> ParserBuilder { + ParserBuilder::default() + } + + /// Build a parser from this configuration with the given pattern. + pub fn build(&self) -> Parser { + Parser { ast: self.ast.build(), hir: self.hir.build() } + } + + /// Set the nesting limit for this parser. + /// + /// The nesting limit controls how deep the abstract syntax tree is allowed + /// to be. If the AST exceeds the given limit (e.g., with too many nested + /// groups), then an error is returned by the parser. + /// + /// The purpose of this limit is to act as a heuristic to prevent stack + /// overflow for consumers that do structural induction on an `Ast` using + /// explicit recursion. While this crate never does this (instead using + /// constant stack space and moving the call stack to the heap), other + /// crates may. + /// + /// This limit is not checked until the entire Ast is parsed. Therefore, + /// if callers want to put a limit on the amount of heap space used, then + /// they should impose a limit on the length, in bytes, of the concrete + /// pattern string. In particular, this is viable since this parser + /// implementation will limit itself to heap space proportional to the + /// length of the pattern string. + /// + /// Note that a nest limit of `0` will return a nest limit error for most + /// patterns but not all. For example, a nest limit of `0` permits `a` but + /// not `ab`, since `ab` requires a concatenation, which results in a nest + /// depth of `1`. In general, a nest limit is not something that manifests + /// in an obvious way in the concrete syntax, therefore, it should not be + /// used in a granular way. + pub fn nest_limit(&mut self, limit: u32) -> &mut ParserBuilder { + self.ast.nest_limit(limit); + self + } + + /// Whether to support octal syntax or not. + /// + /// Octal syntax is a little-known way of uttering Unicode codepoints in + /// a regular expression. For example, `a`, `\x61`, `\u0061` and + /// `\141` are all equivalent regular expressions, where the last example + /// shows octal syntax. + /// + /// While supporting octal syntax isn't in and of itself a problem, it does + /// make good error messages harder. That is, in PCRE based regex engines, + /// syntax like `\0` invokes a backreference, which is explicitly + /// unsupported in Rust's regex engine. However, many users expect it to + /// be supported. Therefore, when octal support is disabled, the error + /// message will explicitly mention that backreferences aren't supported. + /// + /// Octal syntax is disabled by default. + pub fn octal(&mut self, yes: bool) -> &mut ParserBuilder { + self.ast.octal(yes); + self + } + + /// When disabled, translation will permit the construction of a regular + /// expression that may match invalid UTF-8. + /// + /// When enabled (the default), the translator is guaranteed to produce an + /// expression that, for non-empty matches, will only ever produce spans + /// that are entirely valid UTF-8 (otherwise, the translator will return an + /// error). + /// + /// Perhaps surprisingly, when UTF-8 is enabled, an empty regex or even + /// a negated ASCII word boundary (uttered as `(?-u:\B)` in the concrete + /// syntax) will be allowed even though they can produce matches that split + /// a UTF-8 encoded codepoint. This only applies to zero-width or "empty" + /// matches, and it is expected that the regex engine itself must handle + /// these cases if necessary (perhaps by suppressing any zero-width matches + /// that split a codepoint). + pub fn utf8(&mut self, yes: bool) -> &mut ParserBuilder { + self.hir.utf8(yes); + self + } + + /// Enable verbose mode in the regular expression. + /// + /// When enabled, verbose mode permits insignificant whitespace in many + /// places in the regular expression, as well as comments. Comments are + /// started using `#` and continue until the end of the line. + /// + /// By default, this is disabled. It may be selectively enabled in the + /// regular expression by using the `x` flag regardless of this setting. + pub fn ignore_whitespace(&mut self, yes: bool) -> &mut ParserBuilder { + self.ast.ignore_whitespace(yes); + self + } + + /// Enable or disable the case insensitive flag by default. + /// + /// By default this is disabled. It may alternatively be selectively + /// enabled in the regular expression itself via the `i` flag. + pub fn case_insensitive(&mut self, yes: bool) -> &mut ParserBuilder { + self.hir.case_insensitive(yes); + self + } + + /// Enable or disable the multi-line matching flag by default. + /// + /// By default this is disabled. It may alternatively be selectively + /// enabled in the regular expression itself via the `m` flag. + pub fn multi_line(&mut self, yes: bool) -> &mut ParserBuilder { + self.hir.multi_line(yes); + self + } + + /// Enable or disable the "dot matches any character" flag by default. + /// + /// By default this is disabled. It may alternatively be selectively + /// enabled in the regular expression itself via the `s` flag. + pub fn dot_matches_new_line(&mut self, yes: bool) -> &mut ParserBuilder { + self.hir.dot_matches_new_line(yes); + self + } + + /// Enable or disable the CRLF mode flag by default. + /// + /// By default this is disabled. It may alternatively be selectively + /// enabled in the regular expression itself via the `R` flag. + /// + /// When CRLF mode is enabled, the following happens: + /// + /// * Unless `dot_matches_new_line` is enabled, `.` will match any character + /// except for `\r` and `\n`. + /// * When `multi_line` mode is enabled, `^` and `$` will treat `\r\n`, + /// `\r` and `\n` as line terminators. And in particular, neither will + /// match between a `\r` and a `\n`. + pub fn crlf(&mut self, yes: bool) -> &mut ParserBuilder { + self.hir.crlf(yes); + self + } + + /// Sets the line terminator for use with `(?u-s:.)` and `(?-us:.)`. + /// + /// Namely, instead of `.` (by default) matching everything except for `\n`, + /// this will cause `.` to match everything except for the byte given. + /// + /// If `.` is used in a context where Unicode mode is enabled and this byte + /// isn't ASCII, then an error will be returned. When Unicode mode is + /// disabled, then any byte is permitted, but will return an error if UTF-8 + /// mode is enabled and it is a non-ASCII byte. + /// + /// In short, any ASCII value for a line terminator is always okay. But a + /// non-ASCII byte might result in an error depending on whether Unicode + /// mode or UTF-8 mode are enabled. + /// + /// Note that if `R` mode is enabled then it always takes precedence and + /// the line terminator will be treated as `\r` and `\n` simultaneously. + /// + /// Note also that this *doesn't* impact the look-around assertions + /// `(?m:^)` and `(?m:$)`. That's usually controlled by additional + /// configuration in the regex engine itself. + pub fn line_terminator(&mut self, byte: u8) -> &mut ParserBuilder { + self.hir.line_terminator(byte); + self + } + + /// Enable or disable the "swap greed" flag by default. + /// + /// By default this is disabled. It may alternatively be selectively + /// enabled in the regular expression itself via the `U` flag. + pub fn swap_greed(&mut self, yes: bool) -> &mut ParserBuilder { + self.hir.swap_greed(yes); + self + } + + /// Enable or disable the Unicode flag (`u`) by default. + /// + /// By default this is **enabled**. It may alternatively be selectively + /// disabled in the regular expression itself via the `u` flag. + /// + /// Note that unless `utf8` is disabled (it's enabled by default), a + /// regular expression will fail to parse if Unicode mode is disabled and a + /// sub-expression could possibly match invalid UTF-8. + pub fn unicode(&mut self, yes: bool) -> &mut ParserBuilder { + self.hir.unicode(yes); + self + } +} + +/// A convenience parser for regular expressions. +/// +/// This parser takes as input a regular expression pattern string (the +/// "concrete syntax") and returns a high-level intermediate representation +/// (the HIR) suitable for most types of analysis. In particular, this parser +/// hides the intermediate state of producing an AST (the "abstract syntax"). +/// The AST is itself far more complex than the HIR, so this parser serves as a +/// convenience for never having to deal with it at all. +/// +/// If callers have more fine grained use cases that need an AST, then please +/// see the [`ast::parse`] module. +/// +/// A `Parser` can be configured in more detail via a [`ParserBuilder`]. +#[derive(Clone, Debug)] +pub struct Parser { + ast: ast::parse::Parser, + hir: hir::translate::Translator, +} + +impl Parser { + /// Create a new parser with a default configuration. + /// + /// The parser can be run with `parse` method. The parse method returns + /// a high level intermediate representation of the given regular + /// expression. + /// + /// To set configuration options on the parser, use [`ParserBuilder`]. + pub fn new() -> Parser { + ParserBuilder::new().build() + } + + /// Parse the regular expression into a high level intermediate + /// representation. + pub fn parse(&mut self, pattern: &str) -> Result { + let ast = self.ast.parse(pattern)?; + let hir = self.hir.translate(pattern, &ast)?; + Ok(hir) + } +} diff --git a/vendor/regex-syntax-0.7.5/src/rank.rs b/vendor/regex-syntax-0.7.5/src/rank.rs new file mode 100644 index 0000000000000..ccb25a20aedcd --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/rank.rs @@ -0,0 +1,258 @@ +pub(crate) const BYTE_FREQUENCIES: [u8; 256] = [ + 55, // '\x00' + 52, // '\x01' + 51, // '\x02' + 50, // '\x03' + 49, // '\x04' + 48, // '\x05' + 47, // '\x06' + 46, // '\x07' + 45, // '\x08' + 103, // '\t' + 242, // '\n' + 66, // '\x0b' + 67, // '\x0c' + 229, // '\r' + 44, // '\x0e' + 43, // '\x0f' + 42, // '\x10' + 41, // '\x11' + 40, // '\x12' + 39, // '\x13' + 38, // '\x14' + 37, // '\x15' + 36, // '\x16' + 35, // '\x17' + 34, // '\x18' + 33, // '\x19' + 56, // '\x1a' + 32, // '\x1b' + 31, // '\x1c' + 30, // '\x1d' + 29, // '\x1e' + 28, // '\x1f' + 255, // ' ' + 148, // '!' + 164, // '"' + 149, // '#' + 136, // '$' + 160, // '%' + 155, // '&' + 173, // "'" + 221, // '(' + 222, // ')' + 134, // '*' + 122, // '+' + 232, // ',' + 202, // '-' + 215, // '.' + 224, // '/' + 208, // '0' + 220, // '1' + 204, // '2' + 187, // '3' + 183, // '4' + 179, // '5' + 177, // '6' + 168, // '7' + 178, // '8' + 200, // '9' + 226, // ':' + 195, // ';' + 154, // '<' + 184, // '=' + 174, // '>' + 126, // '?' + 120, // '@' + 191, // 'A' + 157, // 'B' + 194, // 'C' + 170, // 'D' + 189, // 'E' + 162, // 'F' + 161, // 'G' + 150, // 'H' + 193, // 'I' + 142, // 'J' + 137, // 'K' + 171, // 'L' + 176, // 'M' + 185, // 'N' + 167, // 'O' + 186, // 'P' + 112, // 'Q' + 175, // 'R' + 192, // 'S' + 188, // 'T' + 156, // 'U' + 140, // 'V' + 143, // 'W' + 123, // 'X' + 133, // 'Y' + 128, // 'Z' + 147, // '[' + 138, // '\\' + 146, // ']' + 114, // '^' + 223, // '_' + 151, // '`' + 249, // 'a' + 216, // 'b' + 238, // 'c' + 236, // 'd' + 253, // 'e' + 227, // 'f' + 218, // 'g' + 230, // 'h' + 247, // 'i' + 135, // 'j' + 180, // 'k' + 241, // 'l' + 233, // 'm' + 246, // 'n' + 244, // 'o' + 231, // 'p' + 139, // 'q' + 245, // 'r' + 243, // 's' + 251, // 't' + 235, // 'u' + 201, // 'v' + 196, // 'w' + 240, // 'x' + 214, // 'y' + 152, // 'z' + 182, // '{' + 205, // '|' + 181, // '}' + 127, // '~' + 27, // '\x7f' + 212, // '\x80' + 211, // '\x81' + 210, // '\x82' + 213, // '\x83' + 228, // '\x84' + 197, // '\x85' + 169, // '\x86' + 159, // '\x87' + 131, // '\x88' + 172, // '\x89' + 105, // '\x8a' + 80, // '\x8b' + 98, // '\x8c' + 96, // '\x8d' + 97, // '\x8e' + 81, // '\x8f' + 207, // '\x90' + 145, // '\x91' + 116, // '\x92' + 115, // '\x93' + 144, // '\x94' + 130, // '\x95' + 153, // '\x96' + 121, // '\x97' + 107, // '\x98' + 132, // '\x99' + 109, // '\x9a' + 110, // '\x9b' + 124, // '\x9c' + 111, // '\x9d' + 82, // '\x9e' + 108, // '\x9f' + 118, // '\xa0' + 141, // '¡' + 113, // '¢' + 129, // '£' + 119, // '¤' + 125, // 'Â¥' + 165, // '¦' + 117, // '§' + 92, // '¨' + 106, // '©' + 83, // 'ª' + 72, // '«' + 99, // '¬' + 93, // '\xad' + 65, // '®' + 79, // '¯' + 166, // '°' + 237, // '±' + 163, // '²' + 199, // '³' + 190, // '´' + 225, // 'µ' + 209, // '¶' + 203, // '·' + 198, // '¸' + 217, // '¹' + 219, // 'º' + 206, // '»' + 234, // '¼' + 248, // '½' + 158, // '¾' + 239, // '¿' + 255, // 'À' + 255, // 'Ã' + 255, // 'Â' + 255, // 'Ã' + 255, // 'Ä' + 255, // 'Ã…' + 255, // 'Æ' + 255, // 'Ç' + 255, // 'È' + 255, // 'É' + 255, // 'Ê' + 255, // 'Ë' + 255, // 'ÃŒ' + 255, // 'Ã' + 255, // 'ÃŽ' + 255, // 'Ã' + 255, // 'Ã' + 255, // 'Ñ' + 255, // 'Ã’' + 255, // 'Ó' + 255, // 'Ô' + 255, // 'Õ' + 255, // 'Ö' + 255, // '×' + 255, // 'Ø' + 255, // 'Ù' + 255, // 'Ú' + 255, // 'Û' + 255, // 'Ãœ' + 255, // 'Ã' + 255, // 'Þ' + 255, // 'ß' + 255, // 'à' + 255, // 'á' + 255, // 'â' + 255, // 'ã' + 255, // 'ä' + 255, // 'Ã¥' + 255, // 'æ' + 255, // 'ç' + 255, // 'è' + 255, // 'é' + 255, // 'ê' + 255, // 'ë' + 255, // 'ì' + 255, // 'í' + 255, // 'î' + 255, // 'ï' + 255, // 'ð' + 255, // 'ñ' + 255, // 'ò' + 255, // 'ó' + 255, // 'ô' + 255, // 'õ' + 255, // 'ö' + 255, // '÷' + 255, // 'ø' + 255, // 'ù' + 255, // 'ú' + 255, // 'û' + 255, // 'ü' + 255, // 'ý' + 255, // 'þ' + 255, // 'ÿ' +]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode.rs b/vendor/regex-syntax-0.7.5/src/unicode.rs new file mode 100644 index 0000000000000..393a4c018ac7e --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode.rs @@ -0,0 +1,1039 @@ +use alloc::{ + string::{String, ToString}, + vec::Vec, +}; + +use crate::hir; + +/// An inclusive range of codepoints from a generated file (hence the static +/// lifetime). +type Range = &'static [(char, char)]; + +/// An error that occurs when dealing with Unicode. +/// +/// We don't impl the Error trait here because these always get converted +/// into other public errors. (This error type isn't exported.) +#[derive(Debug)] +pub enum Error { + PropertyNotFound, + PropertyValueNotFound, + // Not used when unicode-perl is enabled. + #[allow(dead_code)] + PerlClassNotFound, +} + +/// An error that occurs when Unicode-aware simple case folding fails. +/// +/// This error can occur when the case mapping tables necessary for Unicode +/// aware case folding are unavailable. This only occurs when the +/// `unicode-case` feature is disabled. (The feature is enabled by default.) +#[derive(Debug)] +pub struct CaseFoldError(()); + +#[cfg(feature = "std")] +impl std::error::Error for CaseFoldError {} + +impl core::fmt::Display for CaseFoldError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "Unicode-aware case folding is not available \ + (probably because the unicode-case feature is not enabled)" + ) + } +} + +/// An error that occurs when the Unicode-aware `\w` class is unavailable. +/// +/// This error can occur when the data tables necessary for the Unicode aware +/// Perl character class `\w` are unavailable. This only occurs when the +/// `unicode-perl` feature is disabled. (The feature is enabled by default.) +#[derive(Debug)] +pub struct UnicodeWordError(()); + +#[cfg(feature = "std")] +impl std::error::Error for UnicodeWordError {} + +impl core::fmt::Display for UnicodeWordError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "Unicode-aware \\w class is not available \ + (probably because the unicode-perl feature is not enabled)" + ) + } +} + +/// A state oriented traverser of the simple case folding table. +/// +/// A case folder can be constructed via `SimpleCaseFolder::new()`, which will +/// return an error if the underlying case folding table is unavailable. +/// +/// After construction, it is expected that callers will use +/// `SimpleCaseFolder::mapping` by calling it with codepoints in strictly +/// increasing order. For example, calling it on `b` and then on `a` is illegal +/// and will result in a panic. +/// +/// The main idea of this type is that it tries hard to make mapping lookups +/// fast by exploiting the structure of the underlying table, and the ordering +/// assumption enables this. +#[derive(Debug)] +pub struct SimpleCaseFolder { + /// The simple case fold table. It's a sorted association list, where the + /// keys are Unicode scalar values and the values are the corresponding + /// equivalence class (not including the key) of the "simple" case folded + /// Unicode scalar values. + table: &'static [(char, &'static [char])], + /// The last codepoint that was used for a lookup. + last: Option, + /// The index to the entry in `table` corresponding to the smallest key `k` + /// such that `k > k0`, where `k0` is the most recent key lookup. Note that + /// in particular, `k0` may not be in the table! + next: usize, +} + +impl SimpleCaseFolder { + /// Create a new simple case folder, returning an error if the underlying + /// case folding table is unavailable. + pub fn new() -> Result { + #[cfg(not(feature = "unicode-case"))] + { + Err(CaseFoldError(())) + } + #[cfg(feature = "unicode-case")] + { + Ok(SimpleCaseFolder { + table: crate::unicode_tables::case_folding_simple::CASE_FOLDING_SIMPLE, + last: None, + next: 0, + }) + } + } + + /// Return the equivalence class of case folded codepoints for the given + /// codepoint. The equivalence class returned never includes the codepoint + /// given. If the given codepoint has no case folded codepoints (i.e., + /// no entry in the underlying case folding table), then this returns an + /// empty slice. + /// + /// # Panics + /// + /// This panics when called with a `c` that is less than or equal to the + /// previous call. In other words, callers need to use this method with + /// strictly increasing values of `c`. + pub fn mapping(&mut self, c: char) -> &'static [char] { + if let Some(last) = self.last { + assert!( + last < c, + "got codepoint U+{:X} which occurs before \ + last codepoint U+{:X}", + u32::from(c), + u32::from(last), + ); + } + self.last = Some(c); + if self.next >= self.table.len() { + return &[]; + } + let (k, v) = self.table[self.next]; + if k == c { + self.next += 1; + return v; + } + match self.get(c) { + Err(i) => { + self.next = i; + &[] + } + Ok(i) => { + // Since we require lookups to proceed + // in order, anything we find should be + // after whatever we thought might be + // next. Otherwise, the caller is either + // going out of order or we would have + // found our next key at 'self.next'. + assert!(i > self.next); + self.next = i + 1; + self.table[i].1 + } + } + } + + /// Returns true if and only if the given range overlaps with any region + /// of the underlying case folding table. That is, when true, there exists + /// at least one codepoint in the inclusive range `[start, end]` that has + /// a non-trivial equivalence class of case folded codepoints. Conversely, + /// when this returns false, all codepoints in the range `[start, end]` + /// correspond to the trivial equivalence class of case folded codepoints, + /// i.e., itself. + /// + /// This is useful to call before iterating over the codepoints in the + /// range and looking up the mapping for each. If you know none of the + /// mappings will return anything, then you might be able to skip doing it + /// altogether. + /// + /// # Panics + /// + /// This panics when `end < start`. + pub fn overlaps(&self, start: char, end: char) -> bool { + use core::cmp::Ordering; + + assert!(start <= end); + self.table + .binary_search_by(|&(c, _)| { + if start <= c && c <= end { + Ordering::Equal + } else if c > end { + Ordering::Greater + } else { + Ordering::Less + } + }) + .is_ok() + } + + /// Returns the index at which `c` occurs in the simple case fold table. If + /// `c` does not occur, then this returns an `i` such that `table[i-1].0 < + /// c` and `table[i].0 > c`. + fn get(&self, c: char) -> Result { + self.table.binary_search_by_key(&c, |&(c1, _)| c1) + } +} + +/// A query for finding a character class defined by Unicode. This supports +/// either use of a property name directly, or lookup by property value. The +/// former generally refers to Binary properties (see UTS#44, Table 8), but +/// as a special exception (see UTS#18, Section 1.2) both general categories +/// (an enumeration) and scripts (a catalog) are supported as if each of their +/// possible values were a binary property. +/// +/// In all circumstances, property names and values are normalized and +/// canonicalized. That is, `GC == gc == GeneralCategory == general_category`. +/// +/// The lifetime `'a` refers to the shorter of the lifetimes of property name +/// and property value. +#[derive(Debug)] +pub enum ClassQuery<'a> { + /// Return a class corresponding to a Unicode binary property, named by + /// a single letter. + OneLetter(char), + /// Return a class corresponding to a Unicode binary property. + /// + /// Note that, by special exception (see UTS#18, Section 1.2), both + /// general category values and script values are permitted here as if + /// they were a binary property. + Binary(&'a str), + /// Return a class corresponding to all codepoints whose property + /// (identified by `property_name`) corresponds to the given value + /// (identified by `property_value`). + ByValue { + /// A property name. + property_name: &'a str, + /// A property value. + property_value: &'a str, + }, +} + +impl<'a> ClassQuery<'a> { + fn canonicalize(&self) -> Result { + match *self { + ClassQuery::OneLetter(c) => self.canonical_binary(&c.to_string()), + ClassQuery::Binary(name) => self.canonical_binary(name), + ClassQuery::ByValue { property_name, property_value } => { + let property_name = symbolic_name_normalize(property_name); + let property_value = symbolic_name_normalize(property_value); + + let canon_name = match canonical_prop(&property_name)? { + None => return Err(Error::PropertyNotFound), + Some(canon_name) => canon_name, + }; + Ok(match canon_name { + "General_Category" => { + let canon = match canonical_gencat(&property_value)? { + None => return Err(Error::PropertyValueNotFound), + Some(canon) => canon, + }; + CanonicalClassQuery::GeneralCategory(canon) + } + "Script" => { + let canon = match canonical_script(&property_value)? { + None => return Err(Error::PropertyValueNotFound), + Some(canon) => canon, + }; + CanonicalClassQuery::Script(canon) + } + _ => { + let vals = match property_values(canon_name)? { + None => return Err(Error::PropertyValueNotFound), + Some(vals) => vals, + }; + let canon_val = + match canonical_value(vals, &property_value) { + None => { + return Err(Error::PropertyValueNotFound) + } + Some(canon_val) => canon_val, + }; + CanonicalClassQuery::ByValue { + property_name: canon_name, + property_value: canon_val, + } + } + }) + } + } + } + + fn canonical_binary( + &self, + name: &str, + ) -> Result { + let norm = symbolic_name_normalize(name); + + // This is a special case where 'cf' refers to the 'Format' general + // category, but where the 'cf' abbreviation is also an abbreviation + // for the 'Case_Folding' property. But we want to treat it as + // a general category. (Currently, we don't even support the + // 'Case_Folding' property. But if we do in the future, users will be + // required to spell it out.) + // + // Also 'sc' refers to the 'Currency_Symbol' general category, but is + // also the abbreviation for the 'Script' property. So we avoid calling + // 'canonical_prop' for it too, which would erroneously normalize it + // to 'Script'. + // + // Another case: 'lc' is an abbreviation for the 'Cased_Letter' + // general category, but is also an abbreviation for the 'Lowercase_Mapping' + // property. We don't currently support the latter, so as with 'cf' + // above, we treat 'lc' as 'Cased_Letter'. + if norm != "cf" && norm != "sc" && norm != "lc" { + if let Some(canon) = canonical_prop(&norm)? { + return Ok(CanonicalClassQuery::Binary(canon)); + } + } + if let Some(canon) = canonical_gencat(&norm)? { + return Ok(CanonicalClassQuery::GeneralCategory(canon)); + } + if let Some(canon) = canonical_script(&norm)? { + return Ok(CanonicalClassQuery::Script(canon)); + } + Err(Error::PropertyNotFound) + } +} + +/// Like ClassQuery, but its parameters have been canonicalized. This also +/// differentiates binary properties from flattened general categories and +/// scripts. +#[derive(Debug, Eq, PartialEq)] +enum CanonicalClassQuery { + /// The canonical binary property name. + Binary(&'static str), + /// The canonical general category name. + GeneralCategory(&'static str), + /// The canonical script name. + Script(&'static str), + /// An arbitrary association between property and value, both of which + /// have been canonicalized. + /// + /// Note that by construction, the property name of ByValue will never + /// be General_Category or Script. Those two cases are subsumed by the + /// eponymous variants. + ByValue { + /// The canonical property name. + property_name: &'static str, + /// The canonical property value. + property_value: &'static str, + }, +} + +/// Looks up a Unicode class given a query. If one doesn't exist, then +/// `None` is returned. +pub fn class(query: ClassQuery<'_>) -> Result { + use self::CanonicalClassQuery::*; + + match query.canonicalize()? { + Binary(name) => bool_property(name), + GeneralCategory(name) => gencat(name), + Script(name) => script(name), + ByValue { property_name: "Age", property_value } => { + let mut class = hir::ClassUnicode::empty(); + for set in ages(property_value)? { + class.union(&hir_class(set)); + } + Ok(class) + } + ByValue { property_name: "Script_Extensions", property_value } => { + script_extension(property_value) + } + ByValue { + property_name: "Grapheme_Cluster_Break", + property_value, + } => gcb(property_value), + ByValue { property_name: "Sentence_Break", property_value } => { + sb(property_value) + } + ByValue { property_name: "Word_Break", property_value } => { + wb(property_value) + } + _ => { + // What else should we support? + Err(Error::PropertyNotFound) + } + } +} + +/// Returns a Unicode aware class for \w. +/// +/// This returns an error if the data is not available for \w. +pub fn perl_word() -> Result { + #[cfg(not(feature = "unicode-perl"))] + fn imp() -> Result { + Err(Error::PerlClassNotFound) + } + + #[cfg(feature = "unicode-perl")] + fn imp() -> Result { + use crate::unicode_tables::perl_word::PERL_WORD; + Ok(hir_class(PERL_WORD)) + } + + imp() +} + +/// Returns a Unicode aware class for \s. +/// +/// This returns an error if the data is not available for \s. +pub fn perl_space() -> Result { + #[cfg(not(any(feature = "unicode-perl", feature = "unicode-bool")))] + fn imp() -> Result { + Err(Error::PerlClassNotFound) + } + + #[cfg(all(feature = "unicode-perl", not(feature = "unicode-bool")))] + fn imp() -> Result { + use crate::unicode_tables::perl_space::WHITE_SPACE; + Ok(hir_class(WHITE_SPACE)) + } + + #[cfg(feature = "unicode-bool")] + fn imp() -> Result { + use crate::unicode_tables::property_bool::WHITE_SPACE; + Ok(hir_class(WHITE_SPACE)) + } + + imp() +} + +/// Returns a Unicode aware class for \d. +/// +/// This returns an error if the data is not available for \d. +pub fn perl_digit() -> Result { + #[cfg(not(any(feature = "unicode-perl", feature = "unicode-gencat")))] + fn imp() -> Result { + Err(Error::PerlClassNotFound) + } + + #[cfg(all(feature = "unicode-perl", not(feature = "unicode-gencat")))] + fn imp() -> Result { + use crate::unicode_tables::perl_decimal::DECIMAL_NUMBER; + Ok(hir_class(DECIMAL_NUMBER)) + } + + #[cfg(feature = "unicode-gencat")] + fn imp() -> Result { + use crate::unicode_tables::general_category::DECIMAL_NUMBER; + Ok(hir_class(DECIMAL_NUMBER)) + } + + imp() +} + +/// Build a Unicode HIR class from a sequence of Unicode scalar value ranges. +pub fn hir_class(ranges: &[(char, char)]) -> hir::ClassUnicode { + let hir_ranges: Vec = ranges + .iter() + .map(|&(s, e)| hir::ClassUnicodeRange::new(s, e)) + .collect(); + hir::ClassUnicode::new(hir_ranges) +} + +/// Returns true only if the given codepoint is in the `\w` character class. +/// +/// If the `unicode-perl` feature is not enabled, then this returns an error. +pub fn is_word_character(c: char) -> Result { + #[cfg(not(feature = "unicode-perl"))] + fn imp(_: char) -> Result { + Err(UnicodeWordError(())) + } + + #[cfg(feature = "unicode-perl")] + fn imp(c: char) -> Result { + use crate::{is_word_byte, unicode_tables::perl_word::PERL_WORD}; + + if u8::try_from(c).map_or(false, is_word_byte) { + return Ok(true); + } + Ok(PERL_WORD + .binary_search_by(|&(start, end)| { + use core::cmp::Ordering; + + if start <= c && c <= end { + Ordering::Equal + } else if start > c { + Ordering::Greater + } else { + Ordering::Less + } + }) + .is_ok()) + } + + imp(c) +} + +/// A mapping of property values for a specific property. +/// +/// The first element of each tuple is a normalized property value while the +/// second element of each tuple is the corresponding canonical property +/// value. +type PropertyValues = &'static [(&'static str, &'static str)]; + +fn canonical_gencat( + normalized_value: &str, +) -> Result, Error> { + Ok(match normalized_value { + "any" => Some("Any"), + "assigned" => Some("Assigned"), + "ascii" => Some("ASCII"), + _ => { + let gencats = property_values("General_Category")?.unwrap(); + canonical_value(gencats, normalized_value) + } + }) +} + +fn canonical_script( + normalized_value: &str, +) -> Result, Error> { + let scripts = property_values("Script")?.unwrap(); + Ok(canonical_value(scripts, normalized_value)) +} + +/// Find the canonical property name for the given normalized property name. +/// +/// If no such property exists, then `None` is returned. +/// +/// The normalized property name must have been normalized according to +/// UAX44 LM3, which can be done using `symbolic_name_normalize`. +/// +/// If the property names data is not available, then an error is returned. +fn canonical_prop( + normalized_name: &str, +) -> Result, Error> { + #[cfg(not(any( + feature = "unicode-age", + feature = "unicode-bool", + feature = "unicode-gencat", + feature = "unicode-perl", + feature = "unicode-script", + feature = "unicode-segment", + )))] + fn imp(_: &str) -> Result, Error> { + Err(Error::PropertyNotFound) + } + + #[cfg(any( + feature = "unicode-age", + feature = "unicode-bool", + feature = "unicode-gencat", + feature = "unicode-perl", + feature = "unicode-script", + feature = "unicode-segment", + ))] + fn imp(name: &str) -> Result, Error> { + use crate::unicode_tables::property_names::PROPERTY_NAMES; + + Ok(PROPERTY_NAMES + .binary_search_by_key(&name, |&(n, _)| n) + .ok() + .map(|i| PROPERTY_NAMES[i].1)) + } + + imp(normalized_name) +} + +/// Find the canonical property value for the given normalized property +/// value. +/// +/// The given property values should correspond to the values for the property +/// under question, which can be found using `property_values`. +/// +/// If no such property value exists, then `None` is returned. +/// +/// The normalized property value must have been normalized according to +/// UAX44 LM3, which can be done using `symbolic_name_normalize`. +fn canonical_value( + vals: PropertyValues, + normalized_value: &str, +) -> Option<&'static str> { + vals.binary_search_by_key(&normalized_value, |&(n, _)| n) + .ok() + .map(|i| vals[i].1) +} + +/// Return the table of property values for the given property name. +/// +/// If the property values data is not available, then an error is returned. +fn property_values( + canonical_property_name: &'static str, +) -> Result, Error> { + #[cfg(not(any( + feature = "unicode-age", + feature = "unicode-bool", + feature = "unicode-gencat", + feature = "unicode-perl", + feature = "unicode-script", + feature = "unicode-segment", + )))] + fn imp(_: &'static str) -> Result, Error> { + Err(Error::PropertyValueNotFound) + } + + #[cfg(any( + feature = "unicode-age", + feature = "unicode-bool", + feature = "unicode-gencat", + feature = "unicode-perl", + feature = "unicode-script", + feature = "unicode-segment", + ))] + fn imp(name: &'static str) -> Result, Error> { + use crate::unicode_tables::property_values::PROPERTY_VALUES; + + Ok(PROPERTY_VALUES + .binary_search_by_key(&name, |&(n, _)| n) + .ok() + .map(|i| PROPERTY_VALUES[i].1)) + } + + imp(canonical_property_name) +} + +// This is only used in some cases, but small enough to just let it be dead +// instead of figuring out (and maintaining) the right set of features. +#[allow(dead_code)] +fn property_set( + name_map: &'static [(&'static str, Range)], + canonical: &'static str, +) -> Option { + name_map + .binary_search_by_key(&canonical, |x| x.0) + .ok() + .map(|i| name_map[i].1) +} + +/// Returns an iterator over Unicode Age sets. Each item corresponds to a set +/// of codepoints that were added in a particular revision of Unicode. The +/// iterator yields items in chronological order. +/// +/// If the given age value isn't valid or if the data isn't available, then an +/// error is returned instead. +fn ages(canonical_age: &str) -> Result, Error> { + #[cfg(not(feature = "unicode-age"))] + fn imp(_: &str) -> Result, Error> { + use core::option::IntoIter; + Err::, _>(Error::PropertyNotFound) + } + + #[cfg(feature = "unicode-age")] + fn imp(canonical_age: &str) -> Result, Error> { + use crate::unicode_tables::age; + + const AGES: &[(&str, Range)] = &[ + ("V1_1", age::V1_1), + ("V2_0", age::V2_0), + ("V2_1", age::V2_1), + ("V3_0", age::V3_0), + ("V3_1", age::V3_1), + ("V3_2", age::V3_2), + ("V4_0", age::V4_0), + ("V4_1", age::V4_1), + ("V5_0", age::V5_0), + ("V5_1", age::V5_1), + ("V5_2", age::V5_2), + ("V6_0", age::V6_0), + ("V6_1", age::V6_1), + ("V6_2", age::V6_2), + ("V6_3", age::V6_3), + ("V7_0", age::V7_0), + ("V8_0", age::V8_0), + ("V9_0", age::V9_0), + ("V10_0", age::V10_0), + ("V11_0", age::V11_0), + ("V12_0", age::V12_0), + ("V12_1", age::V12_1), + ("V13_0", age::V13_0), + ("V14_0", age::V14_0), + ("V15_0", age::V15_0), + ]; + assert_eq!(AGES.len(), age::BY_NAME.len(), "ages are out of sync"); + + let pos = AGES.iter().position(|&(age, _)| canonical_age == age); + match pos { + None => Err(Error::PropertyValueNotFound), + Some(i) => Ok(AGES[..=i].iter().map(|&(_, classes)| classes)), + } + } + + imp(canonical_age) +} + +/// Returns the Unicode HIR class corresponding to the given general category. +/// +/// Name canonicalization is assumed to be performed by the caller. +/// +/// If the given general category could not be found, or if the general +/// category data is not available, then an error is returned. +fn gencat(canonical_name: &'static str) -> Result { + #[cfg(not(feature = "unicode-gencat"))] + fn imp(_: &'static str) -> Result { + Err(Error::PropertyNotFound) + } + + #[cfg(feature = "unicode-gencat")] + fn imp(name: &'static str) -> Result { + use crate::unicode_tables::general_category::BY_NAME; + match name { + "ASCII" => Ok(hir_class(&[('\0', '\x7F')])), + "Any" => Ok(hir_class(&[('\0', '\u{10FFFF}')])), + "Assigned" => { + let mut cls = gencat("Unassigned")?; + cls.negate(); + Ok(cls) + } + name => property_set(BY_NAME, name) + .map(hir_class) + .ok_or(Error::PropertyValueNotFound), + } + } + + match canonical_name { + "Decimal_Number" => perl_digit(), + name => imp(name), + } +} + +/// Returns the Unicode HIR class corresponding to the given script. +/// +/// Name canonicalization is assumed to be performed by the caller. +/// +/// If the given script could not be found, or if the script data is not +/// available, then an error is returned. +fn script(canonical_name: &'static str) -> Result { + #[cfg(not(feature = "unicode-script"))] + fn imp(_: &'static str) -> Result { + Err(Error::PropertyNotFound) + } + + #[cfg(feature = "unicode-script")] + fn imp(name: &'static str) -> Result { + use crate::unicode_tables::script::BY_NAME; + property_set(BY_NAME, name) + .map(hir_class) + .ok_or(Error::PropertyValueNotFound) + } + + imp(canonical_name) +} + +/// Returns the Unicode HIR class corresponding to the given script extension. +/// +/// Name canonicalization is assumed to be performed by the caller. +/// +/// If the given script extension could not be found, or if the script data is +/// not available, then an error is returned. +fn script_extension( + canonical_name: &'static str, +) -> Result { + #[cfg(not(feature = "unicode-script"))] + fn imp(_: &'static str) -> Result { + Err(Error::PropertyNotFound) + } + + #[cfg(feature = "unicode-script")] + fn imp(name: &'static str) -> Result { + use crate::unicode_tables::script_extension::BY_NAME; + property_set(BY_NAME, name) + .map(hir_class) + .ok_or(Error::PropertyValueNotFound) + } + + imp(canonical_name) +} + +/// Returns the Unicode HIR class corresponding to the given Unicode boolean +/// property. +/// +/// Name canonicalization is assumed to be performed by the caller. +/// +/// If the given boolean property could not be found, or if the boolean +/// property data is not available, then an error is returned. +fn bool_property( + canonical_name: &'static str, +) -> Result { + #[cfg(not(feature = "unicode-bool"))] + fn imp(_: &'static str) -> Result { + Err(Error::PropertyNotFound) + } + + #[cfg(feature = "unicode-bool")] + fn imp(name: &'static str) -> Result { + use crate::unicode_tables::property_bool::BY_NAME; + property_set(BY_NAME, name) + .map(hir_class) + .ok_or(Error::PropertyNotFound) + } + + match canonical_name { + "Decimal_Number" => perl_digit(), + "White_Space" => perl_space(), + name => imp(name), + } +} + +/// Returns the Unicode HIR class corresponding to the given grapheme cluster +/// break property. +/// +/// Name canonicalization is assumed to be performed by the caller. +/// +/// If the given property could not be found, or if the corresponding data is +/// not available, then an error is returned. +fn gcb(canonical_name: &'static str) -> Result { + #[cfg(not(feature = "unicode-segment"))] + fn imp(_: &'static str) -> Result { + Err(Error::PropertyNotFound) + } + + #[cfg(feature = "unicode-segment")] + fn imp(name: &'static str) -> Result { + use crate::unicode_tables::grapheme_cluster_break::BY_NAME; + property_set(BY_NAME, name) + .map(hir_class) + .ok_or(Error::PropertyValueNotFound) + } + + imp(canonical_name) +} + +/// Returns the Unicode HIR class corresponding to the given word break +/// property. +/// +/// Name canonicalization is assumed to be performed by the caller. +/// +/// If the given property could not be found, or if the corresponding data is +/// not available, then an error is returned. +fn wb(canonical_name: &'static str) -> Result { + #[cfg(not(feature = "unicode-segment"))] + fn imp(_: &'static str) -> Result { + Err(Error::PropertyNotFound) + } + + #[cfg(feature = "unicode-segment")] + fn imp(name: &'static str) -> Result { + use crate::unicode_tables::word_break::BY_NAME; + property_set(BY_NAME, name) + .map(hir_class) + .ok_or(Error::PropertyValueNotFound) + } + + imp(canonical_name) +} + +/// Returns the Unicode HIR class corresponding to the given sentence +/// break property. +/// +/// Name canonicalization is assumed to be performed by the caller. +/// +/// If the given property could not be found, or if the corresponding data is +/// not available, then an error is returned. +fn sb(canonical_name: &'static str) -> Result { + #[cfg(not(feature = "unicode-segment"))] + fn imp(_: &'static str) -> Result { + Err(Error::PropertyNotFound) + } + + #[cfg(feature = "unicode-segment")] + fn imp(name: &'static str) -> Result { + use crate::unicode_tables::sentence_break::BY_NAME; + property_set(BY_NAME, name) + .map(hir_class) + .ok_or(Error::PropertyValueNotFound) + } + + imp(canonical_name) +} + +/// Like symbolic_name_normalize_bytes, but operates on a string. +fn symbolic_name_normalize(x: &str) -> String { + let mut tmp = x.as_bytes().to_vec(); + let len = symbolic_name_normalize_bytes(&mut tmp).len(); + tmp.truncate(len); + // This should always succeed because `symbolic_name_normalize_bytes` + // guarantees that `&tmp[..len]` is always valid UTF-8. + // + // N.B. We could avoid the additional UTF-8 check here, but it's unlikely + // to be worth skipping the additional safety check. A benchmark must + // justify it first. + String::from_utf8(tmp).unwrap() +} + +/// Normalize the given symbolic name in place according to UAX44-LM3. +/// +/// A "symbolic name" typically corresponds to property names and property +/// value aliases. Note, though, that it should not be applied to property +/// string values. +/// +/// The slice returned is guaranteed to be valid UTF-8 for all possible values +/// of `slice`. +/// +/// See: https://unicode.org/reports/tr44/#UAX44-LM3 +fn symbolic_name_normalize_bytes(slice: &mut [u8]) -> &mut [u8] { + // I couldn't find a place in the standard that specified that property + // names/aliases had a particular structure (unlike character names), but + // we assume that it's ASCII only and drop anything that isn't ASCII. + let mut start = 0; + let mut starts_with_is = false; + if slice.len() >= 2 { + // Ignore any "is" prefix. + starts_with_is = slice[0..2] == b"is"[..] + || slice[0..2] == b"IS"[..] + || slice[0..2] == b"iS"[..] + || slice[0..2] == b"Is"[..]; + if starts_with_is { + start = 2; + } + } + let mut next_write = 0; + for i in start..slice.len() { + // VALIDITY ARGUMENT: To guarantee that the resulting slice is valid + // UTF-8, we ensure that the slice contains only ASCII bytes. In + // particular, we drop every non-ASCII byte from the normalized string. + let b = slice[i]; + if b == b' ' || b == b'_' || b == b'-' { + continue; + } else if b'A' <= b && b <= b'Z' { + slice[next_write] = b + (b'a' - b'A'); + next_write += 1; + } else if b <= 0x7F { + slice[next_write] = b; + next_write += 1; + } + } + // Special case: ISO_Comment has a 'isc' abbreviation. Since we generally + // ignore 'is' prefixes, the 'isc' abbreviation gets caught in the cross + // fire and ends up creating an alias for 'c' to 'ISO_Comment', but it + // is actually an alias for the 'Other' general category. + if starts_with_is && next_write == 1 && slice[0] == b'c' { + slice[0] = b'i'; + slice[1] = b's'; + slice[2] = b'c'; + next_write = 3; + } + &mut slice[..next_write] +} + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(feature = "unicode-case")] + fn simple_fold_ok(c: char) -> impl Iterator { + SimpleCaseFolder::new().unwrap().mapping(c).iter().copied() + } + + #[cfg(feature = "unicode-case")] + fn contains_case_map(start: char, end: char) -> bool { + SimpleCaseFolder::new().unwrap().overlaps(start, end) + } + + #[test] + #[cfg(feature = "unicode-case")] + fn simple_fold_k() { + let xs: Vec = simple_fold_ok('k').collect(); + assert_eq!(xs, alloc::vec!['K', 'K']); + + let xs: Vec = simple_fold_ok('K').collect(); + assert_eq!(xs, alloc::vec!['k', 'K']); + + let xs: Vec = simple_fold_ok('K').collect(); + assert_eq!(xs, alloc::vec!['K', 'k']); + } + + #[test] + #[cfg(feature = "unicode-case")] + fn simple_fold_a() { + let xs: Vec = simple_fold_ok('a').collect(); + assert_eq!(xs, alloc::vec!['A']); + + let xs: Vec = simple_fold_ok('A').collect(); + assert_eq!(xs, alloc::vec!['a']); + } + + #[test] + #[cfg(not(feature = "unicode-case"))] + fn simple_fold_disabled() { + assert!(SimpleCaseFolder::new().is_err()); + } + + #[test] + #[cfg(feature = "unicode-case")] + fn range_contains() { + assert!(contains_case_map('A', 'A')); + assert!(contains_case_map('Z', 'Z')); + assert!(contains_case_map('A', 'Z')); + assert!(contains_case_map('@', 'A')); + assert!(contains_case_map('Z', '[')); + assert!(contains_case_map('☃', 'â°€')); + + assert!(!contains_case_map('[', '[')); + assert!(!contains_case_map('[', '`')); + + assert!(!contains_case_map('☃', '☃')); + } + + #[test] + #[cfg(feature = "unicode-gencat")] + fn regression_466() { + use super::{CanonicalClassQuery, ClassQuery}; + + let q = ClassQuery::OneLetter('C'); + assert_eq!( + q.canonicalize().unwrap(), + CanonicalClassQuery::GeneralCategory("Other") + ); + } + + #[test] + fn sym_normalize() { + let sym_norm = symbolic_name_normalize; + + assert_eq!(sym_norm("Line_Break"), "linebreak"); + assert_eq!(sym_norm("Line-break"), "linebreak"); + assert_eq!(sym_norm("linebreak"), "linebreak"); + assert_eq!(sym_norm("BA"), "ba"); + assert_eq!(sym_norm("ba"), "ba"); + assert_eq!(sym_norm("Greek"), "greek"); + assert_eq!(sym_norm("isGreek"), "greek"); + assert_eq!(sym_norm("IS_Greek"), "greek"); + assert_eq!(sym_norm("isc"), "isc"); + assert_eq!(sym_norm("is c"), "isc"); + assert_eq!(sym_norm("is_c"), "isc"); + } + + #[test] + fn valid_utf8_symbolic() { + let mut x = b"abc\xFFxyz".to_vec(); + let y = symbolic_name_normalize_bytes(&mut x); + assert_eq!(y, b"abcxyz"); + } +} diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/LICENSE-UNICODE b/vendor/regex-syntax-0.7.5/src/unicode_tables/LICENSE-UNICODE new file mode 100644 index 0000000000000..b82826bdbdd2c --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/LICENSE-UNICODE @@ -0,0 +1,57 @@ +UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE + +Unicode Data Files include all data files under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, +http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and +http://www.unicode.org/utility/trac/browser/. + +Unicode Data Files do not include PDF online code charts under the +directory http://www.unicode.org/Public/. + +Software includes any source code published in the Unicode Standard +or under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, +http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and +http://www.unicode.org/utility/trac/browser/. + +NOTICE TO USER: Carefully read the following legal agreement. +BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. +IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +THE DATA FILES OR SOFTWARE. + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2018 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in http://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/age.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/age.rs new file mode 100644 index 0000000000000..71f4861e075a2 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/age.rs @@ -0,0 +1,1791 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate age ucd-15.0.0 --chars +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("V10_0", V10_0), + ("V11_0", V11_0), + ("V12_0", V12_0), + ("V12_1", V12_1), + ("V13_0", V13_0), + ("V14_0", V14_0), + ("V15_0", V15_0), + ("V1_1", V1_1), + ("V2_0", V2_0), + ("V2_1", V2_1), + ("V3_0", V3_0), + ("V3_1", V3_1), + ("V3_2", V3_2), + ("V4_0", V4_0), + ("V4_1", V4_1), + ("V5_0", V5_0), + ("V5_1", V5_1), + ("V5_2", V5_2), + ("V6_0", V6_0), + ("V6_1", V6_1), + ("V6_2", V6_2), + ("V6_3", V6_3), + ("V7_0", V7_0), + ("V8_0", V8_0), + ("V9_0", V9_0), +]; + +pub const V10_0: &'static [(char, char)] = &[ + ('à¡ ', 'ࡪ'), + ('ৼ', '৽'), + ('\u{afa}', '\u{aff}'), + ('\u{d00}', '\u{d00}'), + ('\u{d3b}', '\u{d3c}'), + ('á³·', 'á³·'), + ('\u{1df6}', '\u{1df9}'), + ('â‚¿', 'â‚¿'), + ('â¿', 'â¿'), + ('⯒', '⯒'), + ('â¹…', '⹉'), + ('ã„®', 'ã„®'), + ('é¿–', '鿪'), + ('ðŒ­', 'ðŒ¯'), + ('𑨀', '\u{11a47}'), + ('ð‘©', '𑪃'), + ('𑪆', '𑪜'), + ('𑪞', '𑪢'), + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d47}'), + ('ð‘µ', '𑵙'), + ('ð–¿¡', 'ð–¿¡'), + ('𛀂', '𛄞'), + ('ð›…°', '𛋻'), + ('🉠', '🉥'), + ('🛓', '🛔'), + ('🛷', '🛸'), + ('🤀', '🤋'), + ('🤟', '🤟'), + ('🤨', '🤯'), + ('🤱', '🤲'), + ('🥌', '🥌'), + ('🥟', '🥫'), + ('🦒', '🦗'), + ('ðŸ§', '🧦'), + ('𬺰', '𮯠'), +]; + +pub const V11_0: &'static [(char, char)] = &[ + ('Õ ', 'Õ '), + ('Öˆ', 'Öˆ'), + ('ׯ', 'ׯ'), + ('\u{7fd}', 'ß¿'), + ('\u{8d3}', '\u{8d3}'), + ('\u{9fe}', '\u{9fe}'), + ('੶', '੶'), + ('\u{c04}', '\u{c04}'), + ('಄', '಄'), + ('ᡸ', 'ᡸ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('⮺', '⮼'), + ('⯓', '⯫'), + ('⯰', '⯾'), + ('⹊', '⹎'), + ('ㄯ', 'ㄯ'), + ('é¿«', '鿯'), + ('ꞯ', 'ꞯ'), + ('Ꞹ', 'êž¹'), + ('ꣾ', '\u{a8ff}'), + ('ð¨´', 'ð¨µ'), + ('ð©ˆ', 'ð©ˆ'), + ('ð´€', '\u{10d27}'), + ('ð´°', 'ð´¹'), + ('ð¼€', 'ð¼§'), + ('ð¼°', 'ð½™'), + ('\u{110cd}', '\u{110cd}'), + ('ð‘…„', 'ð‘…†'), + ('\u{1133b}', '\u{1133b}'), + ('\u{1145e}', '\u{1145e}'), + ('𑜚', '𑜚'), + ('ð‘ €', 'ð‘ »'), + ('ð‘ª', 'ð‘ª'), + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶎'), + ('\u{11d90}', '\u{11d91}'), + ('𑶓', '𑶘'), + ('𑶠', '𑶩'), + ('ð‘» ', '𑻸'), + ('ð–¹€', '𖺚'), + ('𘟭', '𘟱'), + ('ð‹ ', 'ð‹³'), + ('ð²', 'ð¸'), + ('ðž±±', 'ðž²´'), + ('🄯', '🄯'), + ('🛹', '🛹'), + ('🟕', '🟘'), + ('ðŸ¥', 'ðŸ¥'), + ('🥬', '🥰'), + ('🥳', '🥶'), + ('🥺', '🥺'), + ('🥼', '🥿'), + ('🦘', '🦢'), + ('🦰', '🦹'), + ('ðŸ§', '🧂'), + ('🧧', '🧿'), + ('🩠', '🩭'), +]; + +pub const V12_0: &'static [(char, char)] = &[ + ('à±·', 'à±·'), + ('ຆ', 'ຆ'), + ('ຉ', 'ຉ'), + ('ຌ', 'ຌ'), + ('ຎ', 'ຓ'), + ('ຘ', 'ຘ'), + ('ຠ', 'ຠ'), + ('ຨ', 'ຩ'), + ('ຬ', 'ຬ'), + ('\u{eba}', '\u{eba}'), + ('ᳺ', 'ᳺ'), + ('⯉', '⯉'), + ('⯿', '⯿'), + ('â¹', 'â¹'), + ('Ꞻ', 'êž¿'), + ('Ꟃ', 'Ᶎ'), + ('ê­¦', 'ê­§'), + ('ð¿ ', 'ð¿¶'), + ('ð‘‘Ÿ', 'ð‘‘Ÿ'), + ('𑚸', '𑚸'), + ('𑦠', '𑦧'), + ('𑦪', '\u{119d7}'), + ('\u{119da}', '𑧤'), + ('𑪄', '𑪅'), + ('ð‘¿€', 'ð‘¿±'), + ('ð‘¿¿', 'ð‘¿¿'), + ('\u{13430}', '\u{13438}'), + ('ð–½…', '𖽊'), + ('\u{16f4f}', '\u{16f4f}'), + ('𖽿', '𖾇'), + ('ð–¿¢', 'ð–¿£'), + ('𘟲', '𘟷'), + ('ð›…', 'ð›…’'), + ('ð›…¤', 'ð›…§'), + ('ðž„€', '𞄬'), + ('\u{1e130}', '𞄽'), + ('ðž…€', 'ðž…‰'), + ('ðž…Ž', 'ðž…'), + ('ðž‹€', '𞋹'), + ('ðž‹¿', 'ðž‹¿'), + ('𞥋', '𞥋'), + ('ðž´', 'ðž´½'), + ('🅬', '🅬'), + ('🛕', '🛕'), + ('🛺', '🛺'), + ('🟠', '🟫'), + ('ðŸ¤', 'ðŸ¤'), + ('🤿', '🤿'), + ('🥱', '🥱'), + ('🥻', '🥻'), + ('🦥', '🦪'), + ('🦮', '🦯'), + ('🦺', '🦿'), + ('🧃', '🧊'), + ('ðŸ§', 'ðŸ§'), + ('🨀', '🩓'), + ('🩰', '🩳'), + ('🩸', '🩺'), + ('🪀', '🪂'), + ('ðŸª', '🪕'), +]; + +pub const V12_1: &'static [(char, char)] = &[('ã‹¿', 'ã‹¿')]; + +pub const V13_0: &'static [(char, char)] = &[ + ('ࢾ', 'ࣇ'), + ('\u{b55}', '\u{b55}'), + ('à´„', 'à´„'), + ('\u{d81}', '\u{d81}'), + ('\u{1abf}', '\u{1ac0}'), + ('â®—', 'â®—'), + ('â¹', 'â¹’'), + ('ㆻ', 'ㆿ'), + ('䶶', '䶿'), + ('é¿°', '鿼'), + ('Ꟈ', 'ꟊ'), + ('Ꟶ', 'ꟶ'), + ('\u{a82c}', '\u{a82c}'), + ('ê­¨', 'ê­«'), + ('ð†œ', 'ð†œ'), + ('ðº€', 'ðº©'), + ('\u{10eab}', 'ðº­'), + ('ðº°', 'ðº±'), + ('ð¾°', 'ð¿‹'), + ('ð‘…‡', 'ð‘…‡'), + ('𑇎', '\u{111cf}'), + ('ð‘‘š', 'ð‘‘š'), + ('ð‘‘ ', 'ð‘‘¡'), + ('𑤀', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤵'), + ('𑤷', '𑤸'), + ('\u{1193b}', '𑥆'), + ('ð‘¥', 'ð‘¥™'), + ('𑾰', '𑾰'), + ('\u{16fe4}', '\u{16fe4}'), + ('ð–¿°', 'ð–¿±'), + ('𘫳', '𘳕'), + ('𘴀', '𘴈'), + ('ðŸ„', 'ðŸ„'), + ('🅭', '🅯'), + ('🆭', '🆭'), + ('🛖', '🛗'), + ('🛻', '🛼'), + ('🢰', '🢱'), + ('🤌', '🤌'), + ('🥲', '🥲'), + ('🥷', '🥸'), + ('🦣', '🦤'), + ('🦫', '🦭'), + ('🧋', '🧋'), + ('🩴', '🩴'), + ('🪃', '🪆'), + ('🪖', '🪨'), + ('🪰', '🪶'), + ('🫀', '🫂'), + ('ðŸ«', '🫖'), + ('🬀', '🮒'), + ('🮔', '🯊'), + ('🯰', '🯹'), + ('𪛗', 'ðª›'), + ('ð°€€', 'ð±Š'), +]; + +pub const V14_0: &'static [(char, char)] = &[ + ('Ø', 'Ø'), + ('à¡°', 'ࢎ'), + ('\u{890}', '\u{891}'), + ('\u{898}', '\u{89f}'), + ('ࢵ', 'ࢵ'), + ('ࣈ', '\u{8d2}'), + ('\u{c3c}', '\u{c3c}'), + ('à±', 'à±'), + ('à³', 'à³'), + ('áœ', 'áœ'), + ('᜕', '᜕'), + ('ᜟ', 'ᜟ'), + ('\u{180f}', '\u{180f}'), + ('\u{1ac1}', '\u{1ace}'), + ('á­Œ', 'á­Œ'), + ('á­½', 'á­¾'), + ('\u{1dfa}', '\u{1dfa}'), + ('⃀', '⃀'), + ('â°¯', 'â°¯'), + ('ⱟ', 'ⱟ'), + ('⹓', 'â¹'), + ('鿽', 'é¿¿'), + ('Ꟁ', 'êŸ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('ꟲ', 'ꟴ'), + ('﯂', '﯂'), + ('ïµ€', 'ïµ'), + ('ï·', 'ï·'), + ('ï·¾', 'ï·¿'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð½°', 'ð¾‰'), + ('\u{11070}', 'ð‘µ'), + ('\u{110c2}', '\u{110c2}'), + ('ð‘š¹', 'ð‘š¹'), + ('ð‘€', 'ð‘†'), + ('𑪰', '𑪿'), + ('ð’¾', 'ð’¿²'), + ('ð–©°', '𖪾'), + ('ð–«€', '𖫉'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𛄟', '𛄢'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('ðœ½', '𜿃'), + ('ð‡©', 'ð‡ª'), + ('ð¼€', 'ð¼ž'), + ('ðžŠ', '\u{1e2ae}'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), + ('ðŸ›', '🛟'), + ('🟰', '🟰'), + ('🥹', '🥹'), + ('🧌', '🧌'), + ('🩻', '🩼'), + ('🪩', '🪬'), + ('🪷', '🪺'), + ('🫃', '🫅'), + ('🫗', '🫙'), + ('🫠', '🫧'), + ('🫰', '🫶'), + ('𪛞', '𪛟'), + ('𫜵', '𫜸'), +]; + +pub const V15_0: &'static [(char, char)] = &[ + ('à³³', 'à³³'), + ('\u{ece}', '\u{ece}'), + ('\u{10efd}', '\u{10eff}'), + ('𑈿', '\u{11241}'), + ('𑬀', '𑬉'), + ('\u{11f00}', 'ð‘¼'), + ('𑼒', '\u{11f3a}'), + ('𑼾', '𑽙'), + ('ð“¯', 'ð“¯'), + ('\u{13439}', '\u{13455}'), + ('𛄲', '𛄲'), + ('ð›…•', 'ð›…•'), + ('ð‹€', 'ð‹“'), + ('ð¼¥', 'ð¼ª'), + ('𞀰', 'ðž­'), + ('\u{1e08f}', '\u{1e08f}'), + ('ðž“', '𞓹'), + ('🛜', '🛜'), + ('ðŸ´', 'ðŸ¶'), + ('ðŸ»', 'ðŸ¿'), + ('🟙', '🟙'), + ('🩵', '🩷'), + ('🪇', '🪈'), + ('🪭', '🪯'), + ('🪻', '🪽'), + ('🪿', '🪿'), + ('🫎', 'ðŸ«'), + ('🫚', '🫛'), + ('🫨', '🫨'), + ('🫷', '🫸'), + ('𫜹', '𫜹'), + ('ð±', '𲎯'), +]; + +pub const V1_1: &'static [(char, char)] = &[ + ('\0', 'ǵ'), + ('Ǻ', 'È—'), + ('É', 'ʨ'), + ('Ê°', 'Ëž'), + ('Ë ', 'Ë©'), + ('\u{300}', '\u{345}'), + ('\u{360}', '\u{361}'), + ('Í´', '͵'), + ('ͺ', 'ͺ'), + (';', ';'), + ('΄', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'ÏŽ'), + ('Ï', 'Ï–'), + ('Ïš', 'Ïš'), + ('Ïœ', 'Ïœ'), + ('Ïž', 'Ïž'), + ('Ï ', 'Ï '), + ('Ï¢', 'ϳ'), + ('Ð', 'ÐŒ'), + ('ÐŽ', 'Ñ'), + ('Ñ‘', 'Ñœ'), + ('Ñž', '\u{486}'), + ('Ò', 'Ó„'), + ('Ó‡', 'Óˆ'), + ('Ó‹', 'ÓŒ'), + ('Ó', 'Ó«'), + ('Ó®', 'Óµ'), + ('Ó¸', 'Ó¹'), + ('Ô±', 'Õ–'), + ('Õ™', 'ÕŸ'), + ('Õ¡', 'Ö‡'), + ('Ö‰', 'Ö‰'), + ('\u{5b0}', '\u{5b9}'), + ('\u{5bb}', '׃'), + ('×', 'ת'), + ('×°', '×´'), + ('ØŒ', 'ØŒ'), + ('Ø›', 'Ø›'), + ('ØŸ', 'ØŸ'), + ('Ø¡', 'غ'), + ('Ù€', '\u{652}'), + ('Ù ', 'Ù­'), + ('\u{670}', 'Ú·'), + ('Úº', 'Ú¾'), + ('Û€', 'ÛŽ'), + ('Û', '\u{6ed}'), + ('Û°', 'Û¹'), + ('\u{901}', 'ः'), + ('अ', 'ह'), + ('\u{93c}', '\u{94d}'), + ('à¥', '\u{954}'), + ('क़', '॰'), + ('\u{981}', 'ঃ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('\u{9bc}', '\u{9bc}'), + ('\u{9be}', '\u{9c4}'), + ('ে', 'ৈ'), + ('ো', '\u{9cd}'), + ('\u{9d7}', '\u{9d7}'), + ('ড়', 'à§'), + ('য়', '\u{9e3}'), + ('০', '৺'), + ('\u{a02}', '\u{a02}'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('\u{a3c}', '\u{a3c}'), + ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('੦', 'à©´'), + ('\u{a81}', 'ઃ'), + ('અ', 'ઋ'), + ('àª', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('\u{abc}', '\u{ac5}'), + ('\u{ac7}', 'ૉ'), + ('à«‹', '\u{acd}'), + ('à«', 'à«'), + ('à« ', 'à« '), + ('૦', '૯'), + ('\u{b01}', 'ଃ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଶ', 'ହ'), + ('\u{b3c}', '\u{b43}'), + ('à­‡', 'à­ˆ'), + ('à­‹', '\u{b4d}'), + ('\u{b56}', '\u{b57}'), + ('à­œ', 'à­'), + ('à­Ÿ', 'à­¡'), + ('à­¦', 'à­°'), + ('\u{b82}', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'வ'), + ('à®·', 'ஹ'), + ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), + ('ொ', '\u{bcd}'), + ('\u{bd7}', '\u{bd7}'), + ('௧', '௲'), + ('à°', 'à°ƒ'), + ('à°…', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°³'), + ('à°µ', 'à°¹'), + ('\u{c3e}', 'ౄ'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('à± ', 'ౡ'), + ('౦', '౯'), + ('ಂ', 'ಃ'), + ('ಅ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('ಾ', 'ೄ'), + ('\u{cc6}', 'ೈ'), + ('ೊ', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), + ('ೞ', 'ೞ'), + ('à³ ', 'ೡ'), + ('೦', '೯'), + ('à´‚', 'à´ƒ'), + ('à´…', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', 'à´¨'), + ('à´ª', 'à´¹'), + ('\u{d3e}', '\u{d43}'), + ('െ', 'ൈ'), + ('ൊ', '\u{d4d}'), + ('\u{d57}', '\u{d57}'), + ('ൠ', 'ൡ'), + ('൦', '൯'), + ('à¸', '\u{e3a}'), + ('฿', '๛'), + ('àº', 'ຂ'), + ('ຄ', 'ຄ'), + ('ງ', 'ຈ'), + ('ຊ', 'ຊ'), + ('àº', 'àº'), + ('ດ', 'ທ'), + ('ນ', 'ຟ'), + ('ມ', 'ຣ'), + ('ລ', 'ລ'), + ('ວ', 'ວ'), + ('ສ', 'ຫ'), + ('ອ', '\u{eb9}'), + ('\u{ebb}', 'ຽ'), + ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), + ('\u{ec8}', '\u{ecd}'), + ('à»', 'à»™'), + ('ໜ', 'à»'), + ('á‚ ', 'Ⴥ'), + ('áƒ', 'ჶ'), + ('჻', '჻'), + ('á„€', 'á…™'), + ('á…Ÿ', 'ᆢ'), + ('ᆨ', 'ᇹ'), + ('Ḁ', 'ẚ'), + ('Ạ', 'ỹ'), + ('á¼€', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¿„'), + ('ῆ', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿', '`'), + ('ῲ', 'á¿´'), + ('ῶ', '῾'), + ('\u{2000}', '\u{202e}'), + ('‰', 'â†'), + ('\u{206a}', 'â°'), + ('â´', 'â‚Ž'), + ('â‚ ', '₪'), + ('\u{20d0}', '\u{20e1}'), + ('â„€', 'ℸ'), + ('â…“', 'ↂ'), + ('â†', '⇪'), + ('∀', '⋱'), + ('⌀', '⌀'), + ('⌂', 'âº'), + ('â€', 'â¤'), + ('â‘€', 'â‘Š'), + ('â‘ ', '⓪'), + ('─', 'â–•'), + ('â– ', 'â—¯'), + ('☀', '☓'), + ('☚', '♯'), + ('âœ', '✄'), + ('✆', '✉'), + ('✌', '✧'), + ('✩', 'â‹'), + ('â', 'â'), + ('â', 'â’'), + ('â–', 'â–'), + ('â˜', 'âž'), + ('â¡', 'â§'), + ('â¶', 'âž”'), + ('➘', '➯'), + ('âž±', 'âž¾'), + ('\u{3000}', '〷'), + ('〿', '〿'), + ('ã', 'ã‚”'), + ('\u{3099}', 'ã‚ž'), + ('ã‚¡', 'ヾ'), + ('ã„…', 'ㄬ'), + ('ㄱ', 'ㆎ'), + ('ã†', '㆟'), + ('㈀', '㈜'), + ('㈠', '㉃'), + ('㉠', '㉻'), + ('㉿', '㊰'), + ('ã‹€', 'ã‹‹'), + ('ã‹', '㋾'), + ('㌀', 'ã¶'), + ('ã»', 'ã'), + ('ã ', 'ã¾'), + ('一', 'é¾¥'), + ('\u{e000}', '鶴'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('\u{fb1e}', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', 'ï®±'), + ('ﯓ', 'ï´¿'), + ('ïµ', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·°', 'ï·»'), + ('\u{fe20}', '\u{fe23}'), + ('︰', '﹄'), + ('﹉', 'ï¹’'), + ('ï¹”', '﹦'), + ('﹨', '﹫'), + ('ï¹°', 'ï¹²'), + ('ï¹´', 'ï¹´'), + ('ﹶ', 'ﻼ'), + ('\u{feff}', '\u{feff}'), + ('ï¼', '~'), + ('。', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), + ('ï¿ ', '₩'), + ('│', 'ï¿®'), + ('�', '\u{ffff}'), +]; + +pub const V2_0: &'static [(char, char)] = &[ + ('\u{591}', '\u{5a1}'), + ('\u{5a3}', '\u{5af}'), + ('\u{5c4}', '\u{5c4}'), + ('ༀ', 'ཇ'), + ('ཉ', 'ཀྵ'), + ('\u{f71}', 'ྋ'), + ('\u{f90}', '\u{f95}'), + ('\u{f97}', '\u{f97}'), + ('\u{f99}', '\u{fad}'), + ('\u{fb1}', '\u{fb7}'), + ('\u{fb9}', '\u{fb9}'), + ('ẛ', 'ẛ'), + ('â‚«', 'â‚«'), + ('ê°€', '힣'), + ('\u{1fffe}', '\u{1ffff}'), + ('\u{2fffe}', '\u{2ffff}'), + ('\u{3fffe}', '\u{3ffff}'), + ('\u{4fffe}', '\u{4ffff}'), + ('\u{5fffe}', '\u{5ffff}'), + ('\u{6fffe}', '\u{6ffff}'), + ('\u{7fffe}', '\u{7ffff}'), + ('\u{8fffe}', '\u{8ffff}'), + ('\u{9fffe}', '\u{9ffff}'), + ('\u{afffe}', '\u{affff}'), + ('\u{bfffe}', '\u{bffff}'), + ('\u{cfffe}', '\u{cffff}'), + ('\u{dfffe}', '\u{dffff}'), + ('\u{efffe}', '\u{10ffff}'), +]; + +pub const V2_1: &'static [(char, char)] = &[('€', '€'), ('', '')]; + +pub const V3_0: &'static [(char, char)] = &[ + ('Ƕ', 'ǹ'), + ('Ș', 'ÈŸ'), + ('È¢', 'ȳ'), + ('Ê©', 'Ê­'), + ('ËŸ', 'ËŸ'), + ('˪', 'Ë®'), + ('\u{346}', '\u{34e}'), + ('\u{362}', '\u{362}'), + ('Ï—', 'Ï—'), + ('Ï›', 'Ï›'), + ('Ï', 'Ï'), + ('ÏŸ', 'ÏŸ'), + ('Ï¡', 'Ï¡'), + ('Ѐ', 'Ѐ'), + ('Ð', 'Ð'), + ('Ñ', 'Ñ'), + ('Ñ', 'Ñ'), + ('\u{488}', '\u{489}'), + ('ÒŒ', 'Ò'), + ('Ó¬', 'Ó­'), + ('ÖŠ', 'ÖŠ'), + ('\u{653}', '\u{655}'), + ('Ú¸', 'Ú¹'), + ('Ú¿', 'Ú¿'), + ('Û', 'Û'), + ('Ûº', 'Û¾'), + ('Ü€', 'Ü'), + ('\u{70f}', 'ܬ'), + ('\u{730}', '\u{74a}'), + ('Þ€', '\u{7b0}'), + ('ං', 'ඃ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('à·˜', '\u{ddf}'), + ('à·²', 'à·´'), + ('ཪ', 'ཪ'), + ('\u{f96}', '\u{f96}'), + ('\u{fae}', '\u{fb0}'), + ('\u{fb8}', '\u{fb8}'), + ('\u{fba}', '\u{fbc}'), + ('྾', 'à¿Œ'), + ('à¿', 'à¿'), + ('က', 'အ'), + ('ဣ', 'ဧ'), + ('ဩ', 'ဪ'), + ('ာ', '\u{1032}'), + ('\u{1036}', '\u{1039}'), + ('á€', '\u{1059}'), + ('ሀ', 'ሆ'), + ('ለ', 'ቆ'), + ('ቈ', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኆ'), + ('ኈ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኮ'), + ('ኰ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹Ž'), + ('á‹', 'á‹–'), + ('ዘ', 'á‹®'), + ('á‹°', 'ጎ'), + ('áŒ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'ጞ'), + ('ጠ', 'á†'), + ('áˆ', 'áš'), + ('á¡', 'á¼'), + ('Ꭰ', 'á´'), + ('á', 'ᙶ'), + ('\u{1680}', 'ášœ'), + ('áš ', 'á›°'), + ('ក', 'ៜ'), + ('០', '៩'), + ('á €', '\u{180e}'), + ('á ', 'á ™'), + ('á  ', 'á¡·'), + ('ᢀ', '\u{18a9}'), + ('\u{202f}', '\u{202f}'), + ('âˆ', 'â'), + ('â‚­', '₯'), + ('\u{20e2}', '\u{20e3}'), + ('ℹ', '℺'), + ('Ↄ', 'Ↄ'), + ('⇫', '⇳'), + ('âŒ', 'âŒ'), + ('â»', 'â»'), + ('â½', '⎚'), + ('â¥', 'â¦'), + ('â—°', 'â—·'), + ('☙', '☙'), + ('â™°', 'â™±'), + ('â €', '⣿'), + ('⺀', '⺙'), + ('⺛', '⻳'), + ('â¼€', 'â¿•'), + ('â¿°', 'â¿»'), + ('〸', '〺'), + ('〾', '〾'), + ('ㆠ', 'ㆷ'), + ('ã€', '䶵'), + ('ꀀ', 'ê’Œ'), + ('ê’', 'ê’¡'), + ('ê’¤', 'ê’³'), + ('ê’µ', 'ê“€'), + ('ê“‚', 'ê“„'), + ('꓆', '꓆'), + ('ï¬', 'ï¬'), + ('\u{fff9}', '\u{fffb}'), +]; + +pub const V3_1: &'static [(char, char)] = &[ + ('Ï´', 'ϵ'), + ('\u{fdd0}', '\u{fdef}'), + ('ðŒ€', 'ðŒž'), + ('ðŒ ', 'ðŒ£'), + ('ðŒ°', 'ðŠ'), + ('ð€', 'ð¥'), + ('ð¨', 'ð‘'), + ('ð€€', 'ðƒµ'), + ('ð„€', 'ð„¦'), + ('ð„ª', 'ð‡'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“€'), + ('ð“‚', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš£'), + ('ðš¨', 'ðŸ‰'), + ('ðŸŽ', 'ðŸ¿'), + ('ð €€', '𪛖'), + ('丽', 'ð¯¨'), + ('\u{e0001}', '\u{e0001}'), + ('\u{e0020}', '\u{e007f}'), +]; + +pub const V3_2: &'static [(char, char)] = &[ + ('È ', 'È '), + ('\u{34f}', '\u{34f}'), + ('\u{363}', '\u{36f}'), + ('Ϙ', 'Ï™'), + ('϶', '϶'), + ('ÒŠ', 'Ò‹'), + ('Ó…', 'Ó†'), + ('Ó‰', 'ÓŠ'), + ('Ó', 'ÓŽ'), + ('Ô€', 'Ô'), + ('Ù®', 'Ù¯'), + ('Þ±', 'Þ±'), + ('ჷ', 'ჸ'), + ('ᜀ', 'ᜌ'), + ('ᜎ', '\u{1714}'), + ('ᜠ', '᜶'), + ('á€', '\u{1753}'), + ('á ', 'á¬'), + ('á®', 'á°'), + ('\u{1772}', '\u{1773}'), + ('â‡', 'â‡'), + ('âŽ', 'â’'), + ('â—', 'â—'), + ('\u{205f}', '\u{2063}'), + ('â±', 'â±'), + ('â‚°', '₱'), + ('\u{20e4}', '\u{20ea}'), + ('ℽ', 'â…‹'), + ('⇴', '⇿'), + ('⋲', 'â‹¿'), + ('â¼', 'â¼'), + ('⎛', 'âŽ'), + ('â“«', '⓾'), + ('â––', 'â–Ÿ'), + ('â—¸', 'â—¿'), + ('☖', '☗'), + ('♲', '♽'), + ('⚀', '⚉'), + ('â¨', 'âµ'), + ('âŸ', '⟫'), + ('⟰', '⟿'), + ('⤀', 'â«¿'), + ('〻', '〽'), + ('ã‚•', 'ã‚–'), + ('ã‚Ÿ', 'ã‚ '), + ('ヿ', 'ヿ'), + ('ㇰ', 'ㇿ'), + ('㉑', '㉟'), + ('㊱', '㊿'), + ('ê’¢', 'ê’£'), + ('ê’´', 'ê’´'), + ('ê“', 'ê“'), + ('ê“…', 'ê“…'), + ('侮', '頻'), + ('ï·¼', 'ï·¼'), + ('\u{fe00}', '\u{fe0f}'), + ('ï¹…', '﹆'), + ('ï¹³', 'ï¹³'), + ('⦅', 'ï½ '), +]; + +pub const V4_0: &'static [(char, char)] = &[ + ('È¡', 'È¡'), + ('È´', 'ȶ'), + ('Ê®', 'ʯ'), + ('˯', 'Ë¿'), + ('\u{350}', '\u{357}'), + ('\u{35d}', '\u{35f}'), + ('Ï·', 'Ï»'), + ('\u{600}', '\u{603}'), + ('Ø', '\u{615}'), + ('\u{656}', '\u{658}'), + ('Û®', 'Û¯'), + ('Û¿', 'Û¿'), + ('Ü­', 'ܯ'), + ('Ý', 'Ý'), + ('ऄ', 'ऄ'), + ('ঽ', 'ঽ'), + ('\u{a01}', '\u{a01}'), + ('ਃ', 'ਃ'), + ('ઌ', 'ઌ'), + ('à«¡', '\u{ae3}'), + ('૱', '૱'), + ('ଵ', 'ଵ'), + ('à­±', 'à­±'), + ('௳', '௺'), + ('\u{cbc}', 'ಽ'), + ('\u{17dd}', '\u{17dd}'), + ('៰', '៹'), + ('ᤀ', 'ᤜ'), + ('\u{1920}', 'ᤫ'), + ('ᤰ', '\u{193b}'), + ('᥀', '᥀'), + ('᥄', 'ᥭ'), + ('ᥰ', 'ᥴ'), + ('᧠', '᧿'), + ('á´€', 'ᵫ'), + ('â“', 'â”'), + ('â„»', 'â„»'), + ('â', 'â'), + ('â“¿', 'â“¿'), + ('☔', '☕'), + ('⚊', 'âš‘'), + ('âš ', 'âš¡'), + ('⬀', 'â¬'), + ('ãˆ', '㈞'), + ('ã‰', 'ã‰'), + ('㉼', '㉽'), + ('ã‹Œ', 'ã‹'), + ('ã·', 'ãº'), + ('ãž', 'ãŸ'), + ('ã¿', 'ã¿'), + ('ä·€', 'ä·¿'), + ('ï·½', 'ï·½'), + ('﹇', '﹈'), + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), + ('ð„€', 'ð„‚'), + ('ð„‡', 'ð„³'), + ('ð„·', 'ð„¿'), + ('ðŽ€', 'ðŽ'), + ('ðŽŸ', 'ðŽŸ'), + ('ð¦', 'ð§'), + ('ð‘Ž', 'ð’'), + ('ð’ ', 'ð’©'), + ('ð €', 'ð …'), + ('ð ˆ', 'ð ˆ'), + ('ð Š', 'ð µ'), + ('ð ·', 'ð ¸'), + ('ð ¼', 'ð ¼'), + ('ð ¿', 'ð ¿'), + ('ðŒ€', 'ð–'), + ('ð“', 'ð“'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const V4_1: &'static [(char, char)] = &[ + ('È·', 'É'), + ('\u{358}', '\u{35c}'), + ('ϼ', 'Ï¿'), + ('Ó¶', 'Ó·'), + ('\u{5a2}', '\u{5a2}'), + ('\u{5c5}', '\u{5c7}'), + ('Ø‹', 'Ø‹'), + ('Øž', 'Øž'), + ('\u{659}', '\u{65e}'), + ('Ý', 'Ý­'), + ('ॽ', 'ॽ'), + ('ৎ', 'ৎ'), + ('ஶ', 'ஶ'), + ('௦', '௦'), + ('à¿', 'à¿‘'), + ('ჹ', 'ჺ'), + ('ჼ', 'ჼ'), + ('ሇ', 'ሇ'), + ('ቇ', 'ቇ'), + ('ኇ', 'ኇ'), + ('ኯ', 'ኯ'), + ('á‹', 'á‹'), + ('ዯ', 'ዯ'), + ('áŒ', 'áŒ'), + ('ጟ', 'ጟ'), + ('á‡', 'á‡'), + ('\u{135f}', 'á '), + ('ᎀ', '᎙'), + ('ᦀ', 'ᦩ'), + ('ᦰ', 'ᧉ'), + ('á§', '᧙'), + ('᧞', '᧟'), + ('ᨀ', '\u{1a1b}'), + ('᨞', '᨟'), + ('ᵬ', '\u{1dc3}'), + ('â•', 'â–'), + ('â˜', 'âž'), + ('â‚', 'â‚”'), + ('₲', '₵'), + ('\u{20eb}', '\u{20eb}'), + ('ℼ', 'ℼ'), + ('â…Œ', 'â…Œ'), + ('â‘', 'â›'), + ('☘', '☘'), + ('♾', '♿'), + ('âš’', 'âšœ'), + ('⚢', 'âš±'), + ('⟀', '⟆'), + ('⬎', '⬓'), + ('â°€', 'â°®'), + ('â°°', 'ⱞ'), + ('â²€', '⳪'), + ('â³¹', 'â´¥'), + ('â´°', 'âµ¥'), + ('ⵯ', 'ⵯ'), + ('ⶀ', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('⸀', '⸗'), + ('⸜', 'â¸'), + ('㇀', 'ã‡'), + ('㉾', '㉾'), + ('龦', 'é¾»'), + ('꜀', '꜖'), + ('ê €', 'ê «'), + ('ï©°', 'ï«™'), + ('ï¸', '︙'), + ('ð…€', 'ð†Š'), + ('ðŽ ', 'ðƒ'), + ('ðˆ', 'ð•'), + ('ð¨€', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨³'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', 'ð©‡'), + ('ð©', 'ð©˜'), + ('ðˆ€', 'ð‰…'), + ('ðš¤', 'ðš¥'), +]; + +pub const V5_0: &'static [(char, char)] = &[ + ('É‚', 'É'), + ('Í»', 'ͽ'), + ('Ó', 'Ó'), + ('Óº', 'Ó¿'), + ('Ô', 'Ô“'), + ('\u{5ba}', '\u{5ba}'), + ('߀', 'ߺ'), + ('ॻ', 'ॼ'), + ('ॾ', 'ॿ'), + ('\u{ce2}', '\u{ce3}'), + ('à³±', 'à³²'), + ('\u{1b00}', 'á­‹'), + ('á­', 'á­¼'), + ('\u{1dc4}', '\u{1dca}'), + ('\u{1dfe}', '\u{1dff}'), + ('\u{20ec}', '\u{20ef}'), + ('â…', 'â…Ž'), + ('ↄ', 'ↄ'), + ('âœ', 'â§'), + ('âš²', 'âš²'), + ('⟇', '⟊'), + ('⬔', '⬚'), + ('⬠', '⬣'), + ('â± ', 'ⱬ'), + ('â±´', 'â±·'), + ('ꜗ', 'ꜚ'), + ('꜠', '꜡'), + ('ê¡€', 'ê¡·'), + ('ð¤€', 'ð¤™'), + ('ð¤Ÿ', 'ð¤Ÿ'), + ('ð’€€', 'ð’®'), + ('ð’€', 'ð’‘¢'), + ('ð’‘°', 'ð’‘³'), + ('ð ', 'ð±'), + ('ðŸŠ', 'ðŸ‹'), +]; + +pub const V5_1: &'static [(char, char)] = &[ + ('Í°', 'ͳ'), + ('Ͷ', 'Í·'), + ('Ï', 'Ï'), + ('\u{487}', '\u{487}'), + ('Ô”', 'Ô£'), + ('؆', 'ØŠ'), + ('\u{616}', '\u{61a}'), + ('Ø»', 'Ø¿'), + ('Ý®', 'Ý¿'), + ('ॱ', 'ॲ'), + ('\u{a51}', '\u{a51}'), + ('\u{a75}', '\u{a75}'), + ('\u{b44}', '\u{b44}'), + ('\u{b62}', '\u{b63}'), + ('à¯', 'à¯'), + ('à°½', 'à°½'), + ('ౘ', 'à±™'), + ('\u{c62}', '\u{c63}'), + ('౸', '౿'), + ('à´½', 'à´½'), + ('\u{d44}', '\u{d44}'), + ('\u{d62}', '\u{d63}'), + ('൰', '൵'), + ('൹', 'ൿ'), + ('ཫ', 'ཬ'), + ('à¿Ž', 'à¿Ž'), + ('à¿’', 'à¿”'), + ('ဢ', 'ဢ'), + ('ဨ', 'ဨ'), + ('ါ', 'ါ'), + ('\u{1033}', '\u{1035}'), + ('\u{103a}', 'ဿ'), + ('áš', 'á‚™'), + ('á‚ž', 'á‚Ÿ'), + ('ᢪ', 'ᢪ'), + ('\u{1b80}', '᮪'), + ('á®®', '᮹'), + ('á°€', '\u{1c37}'), + ('á°»', '᱉'), + ('á±', '᱿'), + ('\u{1dcb}', '\u{1de6}'), + ('ẜ', 'ẟ'), + ('Ỻ', 'ỿ'), + ('\u{2064}', '\u{2064}'), + ('\u{20f0}', '\u{20f0}'), + ('â…', 'â…'), + ('ↅ', 'ↈ'), + ('âš', 'âš'), + ('âš³', 'âš¼'), + ('⛀', '⛃'), + ('⟌', '⟌'), + ('⟬', '⟯'), + ('⬛', '⬟'), + ('⬤', 'â­Œ'), + ('â­', 'â­”'), + ('â±­', 'Ɐ'), + ('â±±', 'â±³'), + ('ⱸ', 'â±½'), + ('\u{2de0}', '\u{2dff}'), + ('⸘', '⸛'), + ('⸞', '⸰'), + ('ã„­', 'ã„­'), + ('ã‡', '㇣'), + ('é¾¼', '鿃'), + ('ꔀ', 'ꘫ'), + ('Ꙁ', 'ꙟ'), + ('Ꙣ', '꙳'), + ('\u{a67c}', 'êš—'), + ('ꜛ', 'ꜟ'), + ('Ꜣ', 'ꞌ'), + ('ꟻ', 'ꟿ'), + ('ꢀ', '\u{a8c4}'), + ('꣎', '꣙'), + ('꤀', '꥓'), + ('꥟', '꥟'), + ('ꨀ', '\u{aa36}'), + ('ê©€', 'ê©'), + ('ê©', 'ê©™'), + ('ê©œ', 'ê©Ÿ'), + ('\u{fe24}', '\u{fe26}'), + ('ð†', 'ð†›'), + ('ð‡', '\u{101fd}'), + ('ðŠ€', 'ðŠœ'), + ('ðŠ ', 'ð‹'), + ('ð¤ ', 'ð¤¹'), + ('ð¤¿', 'ð¤¿'), + ('ð„©', 'ð„©'), + ('🀀', '🀫'), + ('🀰', '🂓'), +]; + +pub const V5_2: &'static [(char, char)] = &[ + ('Ô¤', 'Ô¥'), + ('à €', '\u{82d}'), + ('à °', 'à ¾'), + ('\u{900}', '\u{900}'), + ('ॎ', 'ॎ'), + ('\u{955}', '\u{955}'), + ('ॹ', 'ॺ'), + ('৻', '৻'), + ('à¿•', '࿘'), + ('á‚š', '\u{109d}'), + ('á…š', 'á…ž'), + ('ᆣ', 'ᆧ'), + ('ᇺ', 'ᇿ'), + ('á€', 'á€'), + ('á™·', 'ᙿ'), + ('ᢰ', 'ᣵ'), + ('ᦪ', 'ᦫ'), + ('᧚', '᧚'), + ('ᨠ', '\u{1a5e}'), + ('\u{1a60}', '\u{1a7c}'), + ('\u{1a7f}', '᪉'), + ('áª', '᪙'), + ('᪠', '᪭'), + ('\u{1cd0}', 'á³²'), + ('\u{1dfd}', '\u{1dfd}'), + ('₶', '₸'), + ('â…', 'â…’'), + ('↉', '↉'), + ('â¨', 'â¨'), + ('âšž', '⚟'), + ('âš½', 'âš¿'), + ('⛄', 'â›'), + ('â›', '⛡'), + ('⛣', '⛣'), + ('⛨', '⛿'), + ('â—', 'â—'), + ('â­•', 'â­™'), + ('â±°', 'â±°'), + ('â±¾', 'Ɀ'), + ('Ⳬ', '\u{2cf1}'), + ('⸱', '⸱'), + ('㉄', 'ã‰'), + ('é¿„', 'é¿‹'), + ('ê“', 'ê“¿'), + ('êš ', 'ê›·'), + ('ê °', 'ê ¹'), + ('\u{a8e0}', 'ꣻ'), + ('ꥠ', 'ꥼ'), + ('\u{a980}', 'ê§'), + ('ê§', '꧙'), + ('꧞', '꧟'), + ('ê© ', 'ê©»'), + ('ꪀ', 'ê«‚'), + ('ê«›', 'ê«Ÿ'), + ('ꯀ', '\u{abed}'), + ('꯰', '꯹'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('ï©«', 'ï©­'), + ('ð¡€', 'ð¡•'), + ('ð¡—', 'ð¡Ÿ'), + ('ð¤š', 'ð¤›'), + ('ð© ', 'ð©¿'), + ('ð¬€', 'ð¬µ'), + ('ð¬¹', 'ð­•'), + ('ð­˜', 'ð­²'), + ('ð­¸', 'ð­¿'), + ('ð°€', 'ð±ˆ'), + ('ð¹ ', 'ð¹¾'), + ('\u{11080}', 'ð‘ƒ'), + ('ð“€€', 'ð“®'), + ('🄀', '🄊'), + ('ðŸ„', '🄮'), + ('🄱', '🄱'), + ('🄽', '🄽'), + ('🄿', '🄿'), + ('🅂', '🅂'), + ('🅆', '🅆'), + ('🅊', '🅎'), + ('🅗', '🅗'), + ('🅟', '🅟'), + ('🅹', '🅹'), + ('🅻', '🅼'), + ('🅿', '🅿'), + ('🆊', 'ðŸ†'), + ('ðŸ†', 'ðŸ†'), + ('🈀', '🈀'), + ('ðŸˆ', '🈱'), + ('🉀', '🉈'), + ('𪜀', '𫜴'), +]; + +pub const V6_0: &'static [(char, char)] = &[ + ('Ô¦', 'Ô§'), + ('Ø ', 'Ø '), + ('\u{65f}', '\u{65f}'), + ('à¡€', '\u{85b}'), + ('à¡ž', 'à¡ž'), + ('\u{93a}', 'ऻ'), + ('à¥', 'à¥'), + ('\u{956}', '\u{957}'), + ('ॳ', 'ॷ'), + ('à­²', 'à­·'), + ('à´©', 'à´©'), + ('à´º', 'à´º'), + ('ൎ', 'ൎ'), + ('ྌ', '\u{f8f}'), + ('à¿™', 'à¿š'), + ('\u{135d}', '\u{135e}'), + ('ᯀ', '᯳'), + ('᯼', '᯿'), + ('\u{1dfc}', '\u{1dfc}'), + ('â‚•', 'â‚œ'), + ('₹', '₹'), + ('â©', 'â³'), + ('⛎', '⛎'), + ('⛢', '⛢'), + ('⛤', '⛧'), + ('✅', '✅'), + ('✊', '✋'), + ('✨', '✨'), + ('âŒ', 'âŒ'), + ('âŽ', 'âŽ'), + ('â“', 'â•'), + ('âŸ', 'â '), + ('âž•', 'âž—'), + ('âž°', 'âž°'), + ('âž¿', 'âž¿'), + ('⟎', 'âŸ'), + ('âµ°', 'âµ°'), + ('\u{2d7f}', '\u{2d7f}'), + ('ㆸ', 'ㆺ'), + ('ê™ ', 'ꙡ'), + ('êž', 'ꞎ'), + ('êž', 'êž‘'), + ('êž ', 'êž©'), + ('ꟺ', 'ꟺ'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('﮲', 'ï¯'), + ('ð‘€€', 'ð‘'), + ('ð‘’', 'ð‘¯'), + ('ð– €', '𖨸'), + ('𛀀', 'ð›€'), + ('🂠', '🂮'), + ('🂱', '🂾'), + ('ðŸƒ', 'ðŸƒ'), + ('🃑', '🃟'), + ('🄰', '🄰'), + ('🄲', '🄼'), + ('🄾', '🄾'), + ('🅀', 'ðŸ…'), + ('🅃', '🅅'), + ('🅇', '🅉'), + ('ðŸ…', '🅖'), + ('🅘', '🅞'), + ('🅠', '🅩'), + ('🅰', '🅸'), + ('🅺', '🅺'), + ('🅽', '🅾'), + ('🆀', '🆉'), + ('🆎', 'ðŸ†'), + ('🆑', '🆚'), + ('🇦', '🇿'), + ('ðŸˆ', '🈂'), + ('🈲', '🈺'), + ('ðŸ‰', '🉑'), + ('🌀', '🌠'), + ('🌰', '🌵'), + ('🌷', 'ðŸ¼'), + ('🎀', '🎓'), + ('🎠', 'ðŸ„'), + ('ðŸ†', 'ðŸŠ'), + ('ðŸ ', 'ðŸ°'), + ('ðŸ€', 'ðŸ¾'), + ('👀', '👀'), + ('👂', '📷'), + ('📹', '📼'), + ('🔀', '🔽'), + ('ðŸ•', '🕧'), + ('🗻', '🗿'), + ('ðŸ˜', 'ðŸ˜'), + ('😒', '😔'), + ('😖', '😖'), + ('😘', '😘'), + ('😚', '😚'), + ('😜', '😞'), + ('😠', '😥'), + ('😨', '😫'), + ('😭', '😭'), + ('😰', '😳'), + ('😵', '🙀'), + ('🙅', 'ðŸ™'), + ('🚀', '🛅'), + ('🜀', 'ðŸ³'), + ('ð«€', 'ð« '), +]; + +pub const V6_1: &'static [(char, char)] = &[ + ('Ö', 'Ö'), + ('\u{604}', '\u{604}'), + ('ࢠ', 'ࢠ'), + ('ࢢ', 'ࢬ'), + ('\u{8e4}', '\u{8fe}'), + ('à«°', 'à«°'), + ('ໞ', 'ໟ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('ჽ', 'ჿ'), + ('\u{1bab}', '\u{1bad}'), + ('ᮺ', 'ᮿ'), + ('á³€', '᳇'), + ('á³³', 'ᳶ'), + ('⟋', '⟋'), + ('âŸ', 'âŸ'), + ('â³²', 'â³³'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('ⵦ', 'ⵧ'), + ('⸲', '⸻'), + ('é¿Œ', 'é¿Œ'), + ('\u{a674}', '\u{a67b}'), + ('\u{a69f}', '\u{a69f}'), + ('êž’', 'êž“'), + ('Ɦ', 'Ɦ'), + ('ꟸ', 'ꟹ'), + ('ê« ', '\u{aaf6}'), + ('郞', '隷'), + ('ð¦€', 'ð¦·'), + ('ð¦¾', 'ð¦¿'), + ('ð‘ƒ', '𑃨'), + ('𑃰', '𑃹'), + ('\u{11100}', '\u{11134}'), + ('𑄶', 'ð‘…ƒ'), + ('\u{11180}', '𑇈'), + ('ð‘‡', '𑇙'), + ('𑚀', '\u{116b7}'), + ('𑛀', '𑛉'), + ('ð–¼€', '𖽄'), + ('ð–½', 'ð–½¾'), + ('\u{16f8f}', '𖾟'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('ðž»°', 'ðž»±'), + ('🅪', '🅫'), + ('🕀', '🕃'), + ('😀', '😀'), + ('😑', '😑'), + ('😕', '😕'), + ('😗', '😗'), + ('😙', '😙'), + ('😛', '😛'), + ('😟', '😟'), + ('😦', '😧'), + ('😬', '😬'), + ('😮', '😯'), + ('😴', '😴'), +]; + +pub const V6_2: &'static [(char, char)] = &[('₺', '₺')]; + +pub const V6_3: &'static [(char, char)] = + &[('\u{61c}', '\u{61c}'), ('\u{2066}', '\u{2069}')]; + +pub const V7_0: &'static [(char, char)] = &[ + ('Í¿', 'Í¿'), + ('Ô¨', 'Ô¯'), + ('Ö', 'ÖŽ'), + ('\u{605}', '\u{605}'), + ('ࢡ', 'ࢡ'), + ('ࢭ', 'ࢲ'), + ('\u{8ff}', '\u{8ff}'), + ('ॸ', 'ॸ'), + ('ঀ', 'ঀ'), + ('\u{c00}', '\u{c00}'), + ('à°´', 'à°´'), + ('\u{c81}', '\u{c81}'), + ('\u{d01}', '\u{d01}'), + ('à·¦', 'à·¯'), + ('á›±', 'ᛸ'), + ('á¤', 'ᤞ'), + ('\u{1ab0}', '\u{1abe}'), + ('\u{1cf8}', '\u{1cf9}'), + ('\u{1de7}', '\u{1df5}'), + ('â‚»', '₽'), + ('â´', 'âº'), + ('✀', '✀'), + ('â­', 'â­'), + ('â­š', 'â­³'), + ('â­¶', '⮕'), + ('⮘', '⮹'), + ('⮽', '⯈'), + ('⯊', '⯑'), + ('⸼', '⹂'), + ('Ꚙ', 'êš'), + ('êž”', 'ꞟ'), + ('êž«', 'êž­'), + ('êž°', 'êž±'), + ('ꟷ', 'ꟷ'), + ('ꧠ', 'ꧾ'), + ('\u{aa7c}', 'ê©¿'), + ('ꬰ', 'ê­Ÿ'), + ('ê­¤', 'ê­¥'), + ('\u{fe27}', '\u{fe2d}'), + ('ð†‹', 'ð†Œ'), + ('ð† ', 'ð† '), + ('\u{102e0}', 'ð‹»'), + ('ðŒŸ', 'ðŒŸ'), + ('ð', '\u{1037a}'), + ('ð”€', 'ð”§'), + ('ð”°', 'ð•£'), + ('ð•¯', 'ð•¯'), + ('ð˜€', 'ðœ¶'), + ('ð€', 'ð•'), + ('ð ', 'ð§'), + ('ð¡ ', 'ð¢ž'), + ('ð¢§', 'ð¢¯'), + ('ðª€', 'ðªŸ'), + ('ð«€', '\u{10ae6}'), + ('ð««', 'ð«¶'), + ('ð®€', 'ð®‘'), + ('ð®™', 'ð®œ'), + ('ð®©', 'ð®¯'), + ('\u{1107f}', '\u{1107f}'), + ('ð‘…', 'ð‘…¶'), + ('ð‘‡', 'ð‘‡'), + ('𑇚', '𑇚'), + ('𑇡', '𑇴'), + ('𑈀', '𑈑'), + ('𑈓', '𑈽'), + ('ð‘Š°', '\u{112ea}'), + ('ð‘‹°', 'ð‘‹¹'), + ('\u{11301}', '𑌃'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('\u{1133c}', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘'), + ('\u{11357}', '\u{11357}'), + ('ð‘', 'ð‘£'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('ð‘’€', '𑓇'), + ('ð‘“', 'ð‘“™'), + ('ð‘–€', '\u{115b5}'), + ('ð‘–¸', 'ð‘—‰'), + ('𑘀', 'ð‘™„'), + ('ð‘™', 'ð‘™™'), + ('ð‘¢ ', 'ð‘£²'), + ('𑣿', '𑣿'), + ('ð‘«€', '𑫸'), + ('ð’¯', '𒎘'), + ('ð’‘£', 'ð’‘®'), + ('ð’‘´', 'ð’‘´'), + ('ð–©€', 'ð–©ž'), + ('ð–© ', 'ð–©©'), + ('ð–©®', '𖩯'), + ('ð–«', 'ð–«­'), + ('\u{16af0}', 'ð–«µ'), + ('𖬀', 'ð–­…'), + ('ð–­', 'ð–­™'), + ('ð–­›', 'ð–­¡'), + ('ð–­£', 'ð–­·'), + ('ð–­½', 'ð–®'), + ('ð›°€', '𛱪'), + ('ð›±°', 'ð›±¼'), + ('𛲀', '𛲈'), + ('ð›²', '𛲙'), + ('𛲜', '\u{1bca3}'), + ('ðž €', '𞣄'), + ('𞣇', '\u{1e8d6}'), + ('🂿', '🂿'), + ('🃠', '🃵'), + ('🄋', '🄌'), + ('🌡', '🌬'), + ('🌶', '🌶'), + ('ðŸ½', 'ðŸ½'), + ('🎔', '🎟'), + ('ðŸ…', 'ðŸ…'), + ('ðŸ‹', 'ðŸŽ'), + ('ðŸ”', 'ðŸŸ'), + ('ðŸ±', 'ðŸ·'), + ('ðŸ¿', 'ðŸ¿'), + ('ðŸ‘', 'ðŸ‘'), + ('📸', '📸'), + ('📽', '📾'), + ('🔾', '🔿'), + ('🕄', '🕊'), + ('🕨', '🕹'), + ('🕻', '🖣'), + ('🖥', '🗺'), + ('ðŸ™', '🙂'), + ('ðŸ™', '🙿'), + ('🛆', 'ðŸ›'), + ('🛠', '🛬'), + ('🛰', '🛳'), + ('🞀', '🟔'), + ('🠀', '🠋'), + ('ðŸ ', '🡇'), + ('ðŸ¡', '🡙'), + ('🡠', '🢇'), + ('ðŸ¢', '🢭'), +]; + +pub const V8_0: &'static [(char, char)] = &[ + ('ࢳ', 'ࢴ'), + ('\u{8e3}', '\u{8e3}'), + ('ૹ', 'ૹ'), + ('ౚ', 'ౚ'), + ('ൟ', 'ൟ'), + ('áµ', 'áµ'), + ('á¸', 'á½'), + ('₾', '₾'), + ('↊', '↋'), + ('⯬', '⯯'), + ('é¿', 'é¿•'), + ('\u{a69e}', '\u{a69e}'), + ('êž', 'êž'), + ('êž²', 'êž·'), + ('꣼', 'ꣽ'), + ('ê­ ', 'ê­£'), + ('ê­°', 'ꮿ'), + ('\u{fe2e}', '\u{fe2f}'), + ('ð£ ', 'ð£²'), + ('ð£´', 'ð£µ'), + ('ð£»', 'ð£¿'), + ('ð¦¼', 'ð¦½'), + ('ð§€', 'ð§'), + ('ð§’', 'ð§¿'), + ('ð²€', 'ð²²'), + ('ð³€', 'ð³²'), + ('ð³º', 'ð³¿'), + ('\u{111c9}', '\u{111cc}'), + ('𑇛', '𑇟'), + ('ð‘Š€', '𑊆'), + ('𑊈', '𑊈'), + ('ð‘ŠŠ', 'ð‘Š'), + ('ð‘Š', 'ð‘Š'), + ('ð‘ŠŸ', 'ð‘Š©'), + ('\u{11300}', '\u{11300}'), + ('ð‘', 'ð‘'), + ('ð‘—Š', '\u{115dd}'), + ('𑜀', '𑜙'), + ('\u{1171d}', '\u{1172b}'), + ('𑜰', '𑜿'), + ('ð’Ž™', 'ð’Ž™'), + ('ð’’€', '𒕃'), + ('ð”€', '𔙆'), + ('ð‡ž', 'ð‡¨'), + ('ð €', 'ðª‹'), + ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), + ('🌭', '🌯'), + ('ðŸ¾', 'ðŸ¿'), + ('ðŸ', 'ðŸ“'), + ('ðŸ¸', 'ðŸ¿'), + ('📿', '📿'), + ('🕋', 'ðŸ•'), + ('🙃', '🙄'), + ('ðŸ›', 'ðŸ›'), + ('ðŸ¤', '🤘'), + ('🦀', '🦄'), + ('🧀', '🧀'), + ('ð«  ', '𬺡'), +]; + +pub const V9_0: &'static [(char, char)] = &[ + ('ࢶ', 'ࢽ'), + ('\u{8d4}', '\u{8e2}'), + ('ಀ', 'ಀ'), + ('àµ', 'àµ'), + ('ൔ', 'ൖ'), + ('൘', '൞'), + ('൶', '൸'), + ('á²€', 'ᲈ'), + ('\u{1dfb}', '\u{1dfb}'), + ('â»', 'â¾'), + ('⹃', '⹄'), + ('êž®', 'êž®'), + ('\u{a8c5}', '\u{a8c5}'), + ('ð†', 'ð†Ž'), + ('ð’°', 'ð““'), + ('ð“˜', 'ð“»'), + ('\u{1123e}', '\u{1123e}'), + ('ð‘€', 'ð‘‘™'), + ('ð‘‘›', 'ð‘‘›'), + ('ð‘‘', 'ð‘‘'), + ('ð‘™ ', '𑙬'), + ('ð‘°€', 'ð‘°ˆ'), + ('ð‘°Š', '\u{11c36}'), + ('\u{11c38}', '𑱅'), + ('ð‘±', '𑱬'), + ('𑱰', 'ð‘²'), + ('\u{11c92}', '\u{11ca7}'), + ('𑲩', '\u{11cb6}'), + ('ð–¿ ', 'ð–¿ '), + ('ð—€€', '𘟬'), + ('𘠀', '𘫲'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('𞤀', '\u{1e94a}'), + ('ðž¥', '𞥙'), + ('𞥞', '𞥟'), + ('🆛', '🆬'), + ('🈻', '🈻'), + ('🕺', '🕺'), + ('🖤', '🖤'), + ('🛑', '🛒'), + ('🛴', '🛶'), + ('🤙', '🤞'), + ('🤠', '🤧'), + ('🤰', '🤰'), + ('🤳', '🤾'), + ('🥀', '🥋'), + ('ðŸ¥', '🥞'), + ('🦅', '🦑'), +]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/case_folding_simple.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/case_folding_simple.rs new file mode 100644 index 0000000000000..23f9364ce9c43 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/case_folding_simple.rs @@ -0,0 +1,2888 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate case-folding-simple ucd-15.0.0 --chars --all-pairs +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const CASE_FOLDING_SIMPLE: &'static [(char, &'static [char])] = &[ + ('A', &['a']), + ('B', &['b']), + ('C', &['c']), + ('D', &['d']), + ('E', &['e']), + ('F', &['f']), + ('G', &['g']), + ('H', &['h']), + ('I', &['i']), + ('J', &['j']), + ('K', &['k', 'K']), + ('L', &['l']), + ('M', &['m']), + ('N', &['n']), + ('O', &['o']), + ('P', &['p']), + ('Q', &['q']), + ('R', &['r']), + ('S', &['s', 'Å¿']), + ('T', &['t']), + ('U', &['u']), + ('V', &['v']), + ('W', &['w']), + ('X', &['x']), + ('Y', &['y']), + ('Z', &['z']), + ('a', &['A']), + ('b', &['B']), + ('c', &['C']), + ('d', &['D']), + ('e', &['E']), + ('f', &['F']), + ('g', &['G']), + ('h', &['H']), + ('i', &['I']), + ('j', &['J']), + ('k', &['K', 'K']), + ('l', &['L']), + ('m', &['M']), + ('n', &['N']), + ('o', &['O']), + ('p', &['P']), + ('q', &['Q']), + ('r', &['R']), + ('s', &['S', 'Å¿']), + ('t', &['T']), + ('u', &['U']), + ('v', &['V']), + ('w', &['W']), + ('x', &['X']), + ('y', &['Y']), + ('z', &['Z']), + ('µ', &['Îœ', 'μ']), + ('À', &['à']), + ('Ã', &['á']), + ('Â', &['â']), + ('Ã', &['ã']), + ('Ä', &['ä']), + ('Ã…', &['Ã¥', 'â„«']), + ('Æ', &['æ']), + ('Ç', &['ç']), + ('È', &['è']), + ('É', &['é']), + ('Ê', &['ê']), + ('Ë', &['ë']), + ('ÃŒ', &['ì']), + ('Ã', &['í']), + ('ÃŽ', &['î']), + ('Ã', &['ï']), + ('Ã', &['ð']), + ('Ñ', &['ñ']), + ('Ã’', &['ò']), + ('Ó', &['ó']), + ('Ô', &['ô']), + ('Õ', &['õ']), + ('Ö', &['ö']), + ('Ø', &['ø']), + ('Ù', &['ù']), + ('Ú', &['ú']), + ('Û', &['û']), + ('Ãœ', &['ü']), + ('Ã', &['ý']), + ('Þ', &['þ']), + ('ß', &['ẞ']), + ('à', &['À']), + ('á', &['Ã']), + ('â', &['Â']), + ('ã', &['Ã']), + ('ä', &['Ä']), + ('Ã¥', &['Ã…', 'â„«']), + ('æ', &['Æ']), + ('ç', &['Ç']), + ('è', &['È']), + ('é', &['É']), + ('ê', &['Ê']), + ('ë', &['Ë']), + ('ì', &['ÃŒ']), + ('í', &['Ã']), + ('î', &['ÃŽ']), + ('ï', &['Ã']), + ('ð', &['Ã']), + ('ñ', &['Ñ']), + ('ò', &['Ã’']), + ('ó', &['Ó']), + ('ô', &['Ô']), + ('õ', &['Õ']), + ('ö', &['Ö']), + ('ø', &['Ø']), + ('ù', &['Ù']), + ('ú', &['Ú']), + ('û', &['Û']), + ('ü', &['Ãœ']), + ('ý', &['Ã']), + ('þ', &['Þ']), + ('ÿ', &['Ÿ']), + ('Ä€', &['Ä']), + ('Ä', &['Ä€']), + ('Ä‚', &['ă']), + ('ă', &['Ä‚']), + ('Ä„', &['Ä…']), + ('Ä…', &['Ä„']), + ('Ć', &['ć']), + ('ć', &['Ć']), + ('Ĉ', &['ĉ']), + ('ĉ', &['Ĉ']), + ('ÄŠ', &['Ä‹']), + ('Ä‹', &['ÄŠ']), + ('ÄŒ', &['Ä']), + ('Ä', &['ÄŒ']), + ('ÄŽ', &['Ä']), + ('Ä', &['ÄŽ']), + ('Ä', &['Ä‘']), + ('Ä‘', &['Ä']), + ('Ä’', &['Ä“']), + ('Ä“', &['Ä’']), + ('Ä”', &['Ä•']), + ('Ä•', &['Ä”']), + ('Ä–', &['Ä—']), + ('Ä—', &['Ä–']), + ('Ę', &['Ä™']), + ('Ä™', &['Ę']), + ('Äš', &['Ä›']), + ('Ä›', &['Äš']), + ('Äœ', &['Ä']), + ('Ä', &['Äœ']), + ('Äž', &['ÄŸ']), + ('ÄŸ', &['Äž']), + ('Ä ', &['Ä¡']), + ('Ä¡', &['Ä ']), + ('Ä¢', &['Ä£']), + ('Ä£', &['Ä¢']), + ('Ĥ', &['Ä¥']), + ('Ä¥', &['Ĥ']), + ('Ħ', &['ħ']), + ('ħ', &['Ħ']), + ('Ĩ', &['Ä©']), + ('Ä©', &['Ĩ']), + ('Ī', &['Ä«']), + ('Ä«', &['Ī']), + ('Ĭ', &['Ä­']), + ('Ä­', &['Ĭ']), + ('Ä®', &['į']), + ('į', &['Ä®']), + ('IJ', &['ij']), + ('ij', &['IJ']), + ('Ä´', &['ĵ']), + ('ĵ', &['Ä´']), + ('Ķ', &['Ä·']), + ('Ä·', &['Ķ']), + ('Ĺ', &['ĺ']), + ('ĺ', &['Ĺ']), + ('Ä»', &['ļ']), + ('ļ', &['Ä»']), + ('Ľ', &['ľ']), + ('ľ', &['Ľ']), + ('Ä¿', &['Å€']), + ('Å€', &['Ä¿']), + ('Å', &['Å‚']), + ('Å‚', &['Å']), + ('Ń', &['Å„']), + ('Å„', &['Ń']), + ('Å…', &['ņ']), + ('ņ', &['Å…']), + ('Ň', &['ň']), + ('ň', &['Ň']), + ('ÅŠ', &['Å‹']), + ('Å‹', &['ÅŠ']), + ('ÅŒ', &['Å']), + ('Å', &['ÅŒ']), + ('ÅŽ', &['Å']), + ('Å', &['ÅŽ']), + ('Å', &['Å‘']), + ('Å‘', &['Å']), + ('Å’', &['Å“']), + ('Å“', &['Å’']), + ('Å”', &['Å•']), + ('Å•', &['Å”']), + ('Å–', &['Å—']), + ('Å—', &['Å–']), + ('Ř', &['Å™']), + ('Å™', &['Ř']), + ('Åš', &['Å›']), + ('Å›', &['Åš']), + ('Åœ', &['Å']), + ('Å', &['Åœ']), + ('Åž', &['ÅŸ']), + ('ÅŸ', &['Åž']), + ('Å ', &['Å¡']), + ('Å¡', &['Å ']), + ('Å¢', &['Å£']), + ('Å£', &['Å¢']), + ('Ť', &['Å¥']), + ('Å¥', &['Ť']), + ('Ŧ', &['ŧ']), + ('ŧ', &['Ŧ']), + ('Ũ', &['Å©']), + ('Å©', &['Ũ']), + ('Ū', &['Å«']), + ('Å«', &['Ū']), + ('Ŭ', &['Å­']), + ('Å­', &['Ŭ']), + ('Å®', &['ů']), + ('ů', &['Å®']), + ('Å°', &['ű']), + ('ű', &['Å°']), + ('Ų', &['ų']), + ('ų', &['Ų']), + ('Å´', &['ŵ']), + ('ŵ', &['Å´']), + ('Ŷ', &['Å·']), + ('Å·', &['Ŷ']), + ('Ÿ', &['ÿ']), + ('Ź', &['ź']), + ('ź', &['Ź']), + ('Å»', &['ż']), + ('ż', &['Å»']), + ('Ž', &['ž']), + ('ž', &['Ž']), + ('Å¿', &['S', 's']), + ('Æ€', &['Ƀ']), + ('Æ', &['É“']), + ('Æ‚', &['ƃ']), + ('ƃ', &['Æ‚']), + ('Æ„', &['Æ…']), + ('Æ…', &['Æ„']), + ('Ɔ', &['É”']), + ('Ƈ', &['ƈ']), + ('ƈ', &['Ƈ']), + ('Ɖ', &['É–']), + ('ÆŠ', &['É—']), + ('Æ‹', &['ÆŒ']), + ('ÆŒ', &['Æ‹']), + ('ÆŽ', &['Ç']), + ('Æ', &['É™']), + ('Æ', &['É›']), + ('Æ‘', &['Æ’']), + ('Æ’', &['Æ‘']), + ('Æ“', &['É ']), + ('Æ”', &['É£']), + ('Æ•', &['Ƕ']), + ('Æ–', &['É©']), + ('Æ—', &['ɨ']), + ('Ƙ', &['Æ™']), + ('Æ™', &['Ƙ']), + ('Æš', &['Ƚ']), + ('Æœ', &['ɯ']), + ('Æ', &['ɲ']), + ('Æž', &['È ']), + ('ÆŸ', &['ɵ']), + ('Æ ', &['Æ¡']), + ('Æ¡', &['Æ ']), + ('Æ¢', &['Æ£']), + ('Æ£', &['Æ¢']), + ('Ƥ', &['Æ¥']), + ('Æ¥', &['Ƥ']), + ('Ʀ', &['Ê€']), + ('Ƨ', &['ƨ']), + ('ƨ', &['Ƨ']), + ('Æ©', &['ʃ']), + ('Ƭ', &['Æ­']), + ('Æ­', &['Ƭ']), + ('Æ®', &['ʈ']), + ('Ư', &['Æ°']), + ('Æ°', &['Ư']), + ('Ʊ', &['ÊŠ']), + ('Ʋ', &['Ê‹']), + ('Ƴ', &['Æ´']), + ('Æ´', &['Ƴ']), + ('Ƶ', &['ƶ']), + ('ƶ', &['Ƶ']), + ('Æ·', &['Ê’']), + ('Ƹ', &['ƹ']), + ('ƹ', &['Ƹ']), + ('Ƽ', &['ƽ']), + ('ƽ', &['Ƽ']), + ('Æ¿', &['Ç·']), + ('Ç„', &['Ç…', 'dž']), + ('Ç…', &['Ç„', 'dž']), + ('dž', &['Ç„', 'Ç…']), + ('LJ', &['Lj', 'lj']), + ('Lj', &['LJ', 'lj']), + ('lj', &['LJ', 'Lj']), + ('ÇŠ', &['Ç‹', 'ÇŒ']), + ('Ç‹', &['ÇŠ', 'ÇŒ']), + ('ÇŒ', &['ÇŠ', 'Ç‹']), + ('Ç', &['ÇŽ']), + ('ÇŽ', &['Ç']), + ('Ç', &['Ç']), + ('Ç', &['Ç']), + ('Ç‘', &['Ç’']), + ('Ç’', &['Ç‘']), + ('Ç“', &['Ç”']), + ('Ç”', &['Ç“']), + ('Ç•', &['Ç–']), + ('Ç–', &['Ç•']), + ('Ç—', &['ǘ']), + ('ǘ', &['Ç—']), + ('Ç™', &['Çš']), + ('Çš', &['Ç™']), + ('Ç›', &['Çœ']), + ('Çœ', &['Ç›']), + ('Ç', &['ÆŽ']), + ('Çž', &['ÇŸ']), + ('ÇŸ', &['Çž']), + ('Ç ', &['Ç¡']), + ('Ç¡', &['Ç ']), + ('Ç¢', &['Ç£']), + ('Ç£', &['Ç¢']), + ('Ǥ', &['Ç¥']), + ('Ç¥', &['Ǥ']), + ('Ǧ', &['ǧ']), + ('ǧ', &['Ǧ']), + ('Ǩ', &['Ç©']), + ('Ç©', &['Ǩ']), + ('Ǫ', &['Ç«']), + ('Ç«', &['Ǫ']), + ('Ǭ', &['Ç­']), + ('Ç­', &['Ǭ']), + ('Ç®', &['ǯ']), + ('ǯ', &['Ç®']), + ('DZ', &['Dz', 'dz']), + ('Dz', &['DZ', 'dz']), + ('dz', &['DZ', 'Dz']), + ('Ç´', &['ǵ']), + ('ǵ', &['Ç´']), + ('Ƕ', &['Æ•']), + ('Ç·', &['Æ¿']), + ('Ǹ', &['ǹ']), + ('ǹ', &['Ǹ']), + ('Ǻ', &['Ç»']), + ('Ç»', &['Ǻ']), + ('Ǽ', &['ǽ']), + ('ǽ', &['Ǽ']), + ('Ǿ', &['Ç¿']), + ('Ç¿', &['Ǿ']), + ('È€', &['È']), + ('È', &['È€']), + ('È‚', &['ȃ']), + ('ȃ', &['È‚']), + ('È„', &['È…']), + ('È…', &['È„']), + ('Ȇ', &['ȇ']), + ('ȇ', &['Ȇ']), + ('Ȉ', &['ȉ']), + ('ȉ', &['Ȉ']), + ('ÈŠ', &['È‹']), + ('È‹', &['ÈŠ']), + ('ÈŒ', &['È']), + ('È', &['ÈŒ']), + ('ÈŽ', &['È']), + ('È', &['ÈŽ']), + ('È', &['È‘']), + ('È‘', &['È']), + ('È’', &['È“']), + ('È“', &['È’']), + ('È”', &['È•']), + ('È•', &['È”']), + ('È–', &['È—']), + ('È—', &['È–']), + ('Ș', &['È™']), + ('È™', &['Ș']), + ('Èš', &['È›']), + ('È›', &['Èš']), + ('Èœ', &['È']), + ('È', &['Èœ']), + ('Èž', &['ÈŸ']), + ('ÈŸ', &['Èž']), + ('È ', &['Æž']), + ('È¢', &['È£']), + ('È£', &['È¢']), + ('Ȥ', &['È¥']), + ('È¥', &['Ȥ']), + ('Ȧ', &['ȧ']), + ('ȧ', &['Ȧ']), + ('Ȩ', &['È©']), + ('È©', &['Ȩ']), + ('Ȫ', &['È«']), + ('È«', &['Ȫ']), + ('Ȭ', &['È­']), + ('È­', &['Ȭ']), + ('È®', &['ȯ']), + ('ȯ', &['È®']), + ('È°', &['ȱ']), + ('ȱ', &['È°']), + ('Ȳ', &['ȳ']), + ('ȳ', &['Ȳ']), + ('Ⱥ', &['â±¥']), + ('È»', &['ȼ']), + ('ȼ', &['È»']), + ('Ƚ', &['Æš']), + ('Ⱦ', &['ⱦ']), + ('È¿', &['â±¾']), + ('É€', &['Ɀ']), + ('É', &['É‚']), + ('É‚', &['É']), + ('Ƀ', &['Æ€']), + ('É„', &['ʉ']), + ('É…', &['ÊŒ']), + ('Ɇ', &['ɇ']), + ('ɇ', &['Ɇ']), + ('Ɉ', &['ɉ']), + ('ɉ', &['Ɉ']), + ('ÉŠ', &['É‹']), + ('É‹', &['ÉŠ']), + ('ÉŒ', &['É']), + ('É', &['ÉŒ']), + ('ÉŽ', &['É']), + ('É', &['ÉŽ']), + ('É', &['Ɐ']), + ('É‘', &['â±­']), + ('É’', &['â±°']), + ('É“', &['Æ']), + ('É”', &['Ɔ']), + ('É–', &['Ɖ']), + ('É—', &['ÆŠ']), + ('É™', &['Æ']), + ('É›', &['Æ']), + ('Éœ', &['êž«']), + ('É ', &['Æ“']), + ('É¡', &['Ɡ']), + ('É£', &['Æ”']), + ('É¥', &['êž']), + ('ɦ', &['Ɦ']), + ('ɨ', &['Æ—']), + ('É©', &['Æ–']), + ('ɪ', &['êž®']), + ('É«', &['â±¢']), + ('ɬ', &['êž­']), + ('ɯ', &['Æœ']), + ('ɱ', &['â±®']), + ('ɲ', &['Æ']), + ('ɵ', &['ÆŸ']), + ('ɽ', &['Ɽ']), + ('Ê€', &['Ʀ']), + ('Ê‚', &['Ʂ']), + ('ʃ', &['Æ©']), + ('ʇ', &['êž±']), + ('ʈ', &['Æ®']), + ('ʉ', &['É„']), + ('ÊŠ', &['Ʊ']), + ('Ê‹', &['Ʋ']), + ('ÊŒ', &['É…']), + ('Ê’', &['Æ·']), + ('Ê', &['êž²']), + ('Êž', &['êž°']), + ('\u{345}', &['Ι', 'ι', 'á¾¾']), + ('Í°', &['ͱ']), + ('ͱ', &['Í°']), + ('Ͳ', &['ͳ']), + ('ͳ', &['Ͳ']), + ('Ͷ', &['Í·']), + ('Í·', &['Ͷ']), + ('Í»', &['Ͻ']), + ('ͼ', &['Ͼ']), + ('ͽ', &['Ï¿']), + ('Í¿', &['ϳ']), + ('Ά', &['ά']), + ('Έ', &['έ']), + ('Ή', &['ή']), + ('Ί', &['ί']), + ('ÎŒ', &['ÏŒ']), + ('ÎŽ', &['Ï']), + ('Î', &['ÏŽ']), + ('Α', &['α']), + ('Î’', &['β', 'Ï']), + ('Γ', &['γ']), + ('Δ', &['δ']), + ('Ε', &['ε', 'ϵ']), + ('Ζ', &['ζ']), + ('Η', &['η']), + ('Θ', &['θ', 'Ï‘', 'Ï´']), + ('Ι', &['\u{345}', 'ι', 'á¾¾']), + ('Κ', &['κ', 'Ï°']), + ('Λ', &['λ']), + ('Îœ', &['µ', 'μ']), + ('Î', &['ν']), + ('Ξ', &['ξ']), + ('Ο', &['ο']), + ('Π', &['Ï€', 'Ï–']), + ('Ρ', &['Ï', 'ϱ']), + ('Σ', &['Ï‚', 'σ']), + ('Τ', &['Ï„']), + ('Î¥', &['Ï…']), + ('Φ', &['φ', 'Ï•']), + ('Χ', &['χ']), + ('Ψ', &['ψ']), + ('Ω', &['ω', 'Ω']), + ('Ϊ', &['ÏŠ']), + ('Ϋ', &['Ï‹']), + ('ά', &['Ά']), + ('έ', &['Έ']), + ('ή', &['Ή']), + ('ί', &['Ί']), + ('α', &['Α']), + ('β', &['Î’', 'Ï']), + ('γ', &['Γ']), + ('δ', &['Δ']), + ('ε', &['Ε', 'ϵ']), + ('ζ', &['Ζ']), + ('η', &['Η']), + ('θ', &['Θ', 'Ï‘', 'Ï´']), + ('ι', &['\u{345}', 'Ι', 'á¾¾']), + ('κ', &['Κ', 'Ï°']), + ('λ', &['Λ']), + ('μ', &['µ', 'Îœ']), + ('ν', &['Î']), + ('ξ', &['Ξ']), + ('ο', &['Ο']), + ('Ï€', &['Π', 'Ï–']), + ('Ï', &['Ρ', 'ϱ']), + ('Ï‚', &['Σ', 'σ']), + ('σ', &['Σ', 'Ï‚']), + ('Ï„', &['Τ']), + ('Ï…', &['Î¥']), + ('φ', &['Φ', 'Ï•']), + ('χ', &['Χ']), + ('ψ', &['Ψ']), + ('ω', &['Ω', 'Ω']), + ('ÏŠ', &['Ϊ']), + ('Ï‹', &['Ϋ']), + ('ÏŒ', &['ÎŒ']), + ('Ï', &['ÎŽ']), + ('ÏŽ', &['Î']), + ('Ï', &['Ï—']), + ('Ï', &['Î’', 'β']), + ('Ï‘', &['Θ', 'θ', 'Ï´']), + ('Ï•', &['Φ', 'φ']), + ('Ï–', &['Π', 'Ï€']), + ('Ï—', &['Ï']), + ('Ϙ', &['Ï™']), + ('Ï™', &['Ϙ']), + ('Ïš', &['Ï›']), + ('Ï›', &['Ïš']), + ('Ïœ', &['Ï']), + ('Ï', &['Ïœ']), + ('Ïž', &['ÏŸ']), + ('ÏŸ', &['Ïž']), + ('Ï ', &['Ï¡']), + ('Ï¡', &['Ï ']), + ('Ï¢', &['Ï£']), + ('Ï£', &['Ï¢']), + ('Ϥ', &['Ï¥']), + ('Ï¥', &['Ϥ']), + ('Ϧ', &['ϧ']), + ('ϧ', &['Ϧ']), + ('Ϩ', &['Ï©']), + ('Ï©', &['Ϩ']), + ('Ϫ', &['Ï«']), + ('Ï«', &['Ϫ']), + ('Ϭ', &['Ï­']), + ('Ï­', &['Ϭ']), + ('Ï®', &['ϯ']), + ('ϯ', &['Ï®']), + ('Ï°', &['Κ', 'κ']), + ('ϱ', &['Ρ', 'Ï']), + ('ϲ', &['Ϲ']), + ('ϳ', &['Í¿']), + ('Ï´', &['Θ', 'θ', 'Ï‘']), + ('ϵ', &['Ε', 'ε']), + ('Ï·', &['ϸ']), + ('ϸ', &['Ï·']), + ('Ϲ', &['ϲ']), + ('Ϻ', &['Ï»']), + ('Ï»', &['Ϻ']), + ('Ͻ', &['Í»']), + ('Ͼ', &['ͼ']), + ('Ï¿', &['ͽ']), + ('Ѐ', &['Ñ']), + ('Ð', &['Ñ‘']), + ('Ђ', &['Ñ’']), + ('Ѓ', &['Ñ“']), + ('Є', &['Ñ”']), + ('Ð…', &['Ñ•']), + ('І', &['Ñ–']), + ('Ї', &['Ñ—']), + ('Ј', &['ј']), + ('Љ', &['Ñ™']), + ('Њ', &['Ñš']), + ('Ћ', &['Ñ›']), + ('ÐŒ', &['Ñœ']), + ('Ð', &['Ñ']), + ('ÐŽ', &['Ñž']), + ('Ð', &['ÑŸ']), + ('Ð', &['а']), + ('Б', &['б']), + ('Ð’', &['в', 'á²€']), + ('Г', &['г']), + ('Д', &['д', 'á²']), + ('Е', &['е']), + ('Ж', &['ж']), + ('З', &['з']), + ('И', &['и']), + ('Й', &['й']), + ('К', &['к']), + ('Л', &['л']), + ('Ðœ', &['м']), + ('Ð', &['н']), + ('О', &['о', 'ᲂ']), + ('П', &['п']), + ('Р', &['Ñ€']), + ('С', &['Ñ', 'ᲃ']), + ('Т', &['Ñ‚', 'ᲄ', 'á²…']), + ('У', &['у']), + ('Ф', &['Ñ„']), + ('Ð¥', &['Ñ…']), + ('Ц', &['ц']), + ('Ч', &['ч']), + ('Ш', &['ш']), + ('Щ', &['щ']), + ('Ъ', &['ÑŠ', 'ᲆ']), + ('Ы', &['Ñ‹']), + ('Ь', &['ÑŒ']), + ('Э', &['Ñ']), + ('Ю', &['ÑŽ']), + ('Я', &['Ñ']), + ('а', &['Ð']), + ('б', &['Б']), + ('в', &['Ð’', 'á²€']), + ('г', &['Г']), + ('д', &['Д', 'á²']), + ('е', &['Е']), + ('ж', &['Ж']), + ('з', &['З']), + ('и', &['И']), + ('й', &['Й']), + ('к', &['К']), + ('л', &['Л']), + ('м', &['Ðœ']), + ('н', &['Ð']), + ('о', &['О', 'ᲂ']), + ('п', &['П']), + ('Ñ€', &['Р']), + ('Ñ', &['С', 'ᲃ']), + ('Ñ‚', &['Т', 'ᲄ', 'á²…']), + ('у', &['У']), + ('Ñ„', &['Ф']), + ('Ñ…', &['Ð¥']), + ('ц', &['Ц']), + ('ч', &['Ч']), + ('ш', &['Ш']), + ('щ', &['Щ']), + ('ÑŠ', &['Ъ', 'ᲆ']), + ('Ñ‹', &['Ы']), + ('ÑŒ', &['Ь']), + ('Ñ', &['Э']), + ('ÑŽ', &['Ю']), + ('Ñ', &['Я']), + ('Ñ', &['Ѐ']), + ('Ñ‘', &['Ð']), + ('Ñ’', &['Ђ']), + ('Ñ“', &['Ѓ']), + ('Ñ”', &['Є']), + ('Ñ•', &['Ð…']), + ('Ñ–', &['І']), + ('Ñ—', &['Ї']), + ('ј', &['Ј']), + ('Ñ™', &['Љ']), + ('Ñš', &['Њ']), + ('Ñ›', &['Ћ']), + ('Ñœ', &['ÐŒ']), + ('Ñ', &['Ð']), + ('Ñž', &['ÐŽ']), + ('ÑŸ', &['Ð']), + ('Ñ ', &['Ñ¡']), + ('Ñ¡', &['Ñ ']), + ('Ñ¢', &['Ñ£', 'ᲇ']), + ('Ñ£', &['Ñ¢', 'ᲇ']), + ('Ѥ', &['Ñ¥']), + ('Ñ¥', &['Ѥ']), + ('Ѧ', &['ѧ']), + ('ѧ', &['Ѧ']), + ('Ѩ', &['Ñ©']), + ('Ñ©', &['Ѩ']), + ('Ѫ', &['Ñ«']), + ('Ñ«', &['Ѫ']), + ('Ѭ', &['Ñ­']), + ('Ñ­', &['Ѭ']), + ('Ñ®', &['ѯ']), + ('ѯ', &['Ñ®']), + ('Ñ°', &['ѱ']), + ('ѱ', &['Ñ°']), + ('Ѳ', &['ѳ']), + ('ѳ', &['Ѳ']), + ('Ñ´', &['ѵ']), + ('ѵ', &['Ñ´']), + ('Ѷ', &['Ñ·']), + ('Ñ·', &['Ѷ']), + ('Ѹ', &['ѹ']), + ('ѹ', &['Ѹ']), + ('Ѻ', &['Ñ»']), + ('Ñ»', &['Ѻ']), + ('Ѽ', &['ѽ']), + ('ѽ', &['Ѽ']), + ('Ѿ', &['Ñ¿']), + ('Ñ¿', &['Ѿ']), + ('Ò€', &['Ò']), + ('Ò', &['Ò€']), + ('ÒŠ', &['Ò‹']), + ('Ò‹', &['ÒŠ']), + ('ÒŒ', &['Ò']), + ('Ò', &['ÒŒ']), + ('ÒŽ', &['Ò']), + ('Ò', &['ÒŽ']), + ('Ò', &['Ò‘']), + ('Ò‘', &['Ò']), + ('Ò’', &['Ò“']), + ('Ò“', &['Ò’']), + ('Ò”', &['Ò•']), + ('Ò•', &['Ò”']), + ('Ò–', &['Ò—']), + ('Ò—', &['Ò–']), + ('Ò˜', &['Ò™']), + ('Ò™', &['Ò˜']), + ('Òš', &['Ò›']), + ('Ò›', &['Òš']), + ('Òœ', &['Ò']), + ('Ò', &['Òœ']), + ('Òž', &['ÒŸ']), + ('ÒŸ', &['Òž']), + ('Ò ', &['Ò¡']), + ('Ò¡', &['Ò ']), + ('Ò¢', &['Ò£']), + ('Ò£', &['Ò¢']), + ('Ò¤', &['Ò¥']), + ('Ò¥', &['Ò¤']), + ('Ò¦', &['Ò§']), + ('Ò§', &['Ò¦']), + ('Ò¨', &['Ò©']), + ('Ò©', &['Ò¨']), + ('Òª', &['Ò«']), + ('Ò«', &['Òª']), + ('Ò¬', &['Ò­']), + ('Ò­', &['Ò¬']), + ('Ò®', &['Ò¯']), + ('Ò¯', &['Ò®']), + ('Ò°', &['Ò±']), + ('Ò±', &['Ò°']), + ('Ò²', &['Ò³']), + ('Ò³', &['Ò²']), + ('Ò´', &['Òµ']), + ('Òµ', &['Ò´']), + ('Ò¶', &['Ò·']), + ('Ò·', &['Ò¶']), + ('Ò¸', &['Ò¹']), + ('Ò¹', &['Ò¸']), + ('Òº', &['Ò»']), + ('Ò»', &['Òº']), + ('Ò¼', &['Ò½']), + ('Ò½', &['Ò¼']), + ('Ò¾', &['Ò¿']), + ('Ò¿', &['Ò¾']), + ('Ó€', &['Ó']), + ('Ó', &['Ó‚']), + ('Ó‚', &['Ó']), + ('Óƒ', &['Ó„']), + ('Ó„', &['Óƒ']), + ('Ó…', &['Ó†']), + ('Ó†', &['Ó…']), + ('Ó‡', &['Óˆ']), + ('Óˆ', &['Ó‡']), + ('Ó‰', &['ÓŠ']), + ('ÓŠ', &['Ó‰']), + ('Ó‹', &['ÓŒ']), + ('ÓŒ', &['Ó‹']), + ('Ó', &['ÓŽ']), + ('ÓŽ', &['Ó']), + ('Ó', &['Ó€']), + ('Ó', &['Ó‘']), + ('Ó‘', &['Ó']), + ('Ó’', &['Ó“']), + ('Ó“', &['Ó’']), + ('Ó”', &['Ó•']), + ('Ó•', &['Ó”']), + ('Ó–', &['Ó—']), + ('Ó—', &['Ó–']), + ('Ó˜', &['Ó™']), + ('Ó™', &['Ó˜']), + ('Óš', &['Ó›']), + ('Ó›', &['Óš']), + ('Óœ', &['Ó']), + ('Ó', &['Óœ']), + ('Óž', &['ÓŸ']), + ('ÓŸ', &['Óž']), + ('Ó ', &['Ó¡']), + ('Ó¡', &['Ó ']), + ('Ó¢', &['Ó£']), + ('Ó£', &['Ó¢']), + ('Ó¤', &['Ó¥']), + ('Ó¥', &['Ó¤']), + ('Ó¦', &['Ó§']), + ('Ó§', &['Ó¦']), + ('Ó¨', &['Ó©']), + ('Ó©', &['Ó¨']), + ('Óª', &['Ó«']), + ('Ó«', &['Óª']), + ('Ó¬', &['Ó­']), + ('Ó­', &['Ó¬']), + ('Ó®', &['Ó¯']), + ('Ó¯', &['Ó®']), + ('Ó°', &['Ó±']), + ('Ó±', &['Ó°']), + ('Ó²', &['Ó³']), + ('Ó³', &['Ó²']), + ('Ó´', &['Óµ']), + ('Óµ', &['Ó´']), + ('Ó¶', &['Ó·']), + ('Ó·', &['Ó¶']), + ('Ó¸', &['Ó¹']), + ('Ó¹', &['Ó¸']), + ('Óº', &['Ó»']), + ('Ó»', &['Óº']), + ('Ó¼', &['Ó½']), + ('Ó½', &['Ó¼']), + ('Ó¾', &['Ó¿']), + ('Ó¿', &['Ó¾']), + ('Ô€', &['Ô']), + ('Ô', &['Ô€']), + ('Ô‚', &['Ôƒ']), + ('Ôƒ', &['Ô‚']), + ('Ô„', &['Ô…']), + ('Ô…', &['Ô„']), + ('Ô†', &['Ô‡']), + ('Ô‡', &['Ô†']), + ('Ôˆ', &['Ô‰']), + ('Ô‰', &['Ôˆ']), + ('ÔŠ', &['Ô‹']), + ('Ô‹', &['ÔŠ']), + ('ÔŒ', &['Ô']), + ('Ô', &['ÔŒ']), + ('ÔŽ', &['Ô']), + ('Ô', &['ÔŽ']), + ('Ô', &['Ô‘']), + ('Ô‘', &['Ô']), + ('Ô’', &['Ô“']), + ('Ô“', &['Ô’']), + ('Ô”', &['Ô•']), + ('Ô•', &['Ô”']), + ('Ô–', &['Ô—']), + ('Ô—', &['Ô–']), + ('Ô˜', &['Ô™']), + ('Ô™', &['Ô˜']), + ('Ôš', &['Ô›']), + ('Ô›', &['Ôš']), + ('Ôœ', &['Ô']), + ('Ô', &['Ôœ']), + ('Ôž', &['ÔŸ']), + ('ÔŸ', &['Ôž']), + ('Ô ', &['Ô¡']), + ('Ô¡', &['Ô ']), + ('Ô¢', &['Ô£']), + ('Ô£', &['Ô¢']), + ('Ô¤', &['Ô¥']), + ('Ô¥', &['Ô¤']), + ('Ô¦', &['Ô§']), + ('Ô§', &['Ô¦']), + ('Ô¨', &['Ô©']), + ('Ô©', &['Ô¨']), + ('Ôª', &['Ô«']), + ('Ô«', &['Ôª']), + ('Ô¬', &['Ô­']), + ('Ô­', &['Ô¬']), + ('Ô®', &['Ô¯']), + ('Ô¯', &['Ô®']), + ('Ô±', &['Õ¡']), + ('Ô²', &['Õ¢']), + ('Ô³', &['Õ£']), + ('Ô´', &['Õ¤']), + ('Ôµ', &['Õ¥']), + ('Ô¶', &['Õ¦']), + ('Ô·', &['Õ§']), + ('Ô¸', &['Õ¨']), + ('Ô¹', &['Õ©']), + ('Ôº', &['Õª']), + ('Ô»', &['Õ«']), + ('Ô¼', &['Õ¬']), + ('Ô½', &['Õ­']), + ('Ô¾', &['Õ®']), + ('Ô¿', &['Õ¯']), + ('Õ€', &['Õ°']), + ('Õ', &['Õ±']), + ('Õ‚', &['Õ²']), + ('Õƒ', &['Õ³']), + ('Õ„', &['Õ´']), + ('Õ…', &['Õµ']), + ('Õ†', &['Õ¶']), + ('Õ‡', &['Õ·']), + ('Õˆ', &['Õ¸']), + ('Õ‰', &['Õ¹']), + ('ÕŠ', &['Õº']), + ('Õ‹', &['Õ»']), + ('ÕŒ', &['Õ¼']), + ('Õ', &['Õ½']), + ('ÕŽ', &['Õ¾']), + ('Õ', &['Õ¿']), + ('Õ', &['Ö€']), + ('Õ‘', &['Ö']), + ('Õ’', &['Ö‚']), + ('Õ“', &['Öƒ']), + ('Õ”', &['Ö„']), + ('Õ•', &['Ö…']), + ('Õ–', &['Ö†']), + ('Õ¡', &['Ô±']), + ('Õ¢', &['Ô²']), + ('Õ£', &['Ô³']), + ('Õ¤', &['Ô´']), + ('Õ¥', &['Ôµ']), + ('Õ¦', &['Ô¶']), + ('Õ§', &['Ô·']), + ('Õ¨', &['Ô¸']), + ('Õ©', &['Ô¹']), + ('Õª', &['Ôº']), + ('Õ«', &['Ô»']), + ('Õ¬', &['Ô¼']), + ('Õ­', &['Ô½']), + ('Õ®', &['Ô¾']), + ('Õ¯', &['Ô¿']), + ('Õ°', &['Õ€']), + ('Õ±', &['Õ']), + ('Õ²', &['Õ‚']), + ('Õ³', &['Õƒ']), + ('Õ´', &['Õ„']), + ('Õµ', &['Õ…']), + ('Õ¶', &['Õ†']), + ('Õ·', &['Õ‡']), + ('Õ¸', &['Õˆ']), + ('Õ¹', &['Õ‰']), + ('Õº', &['ÕŠ']), + ('Õ»', &['Õ‹']), + ('Õ¼', &['ÕŒ']), + ('Õ½', &['Õ']), + ('Õ¾', &['ÕŽ']), + ('Õ¿', &['Õ']), + ('Ö€', &['Õ']), + ('Ö', &['Õ‘']), + ('Ö‚', &['Õ’']), + ('Öƒ', &['Õ“']), + ('Ö„', &['Õ”']), + ('Ö…', &['Õ•']), + ('Ö†', &['Õ–']), + ('á‚ ', &['â´€']), + ('á‚¡', &['â´']), + ('á‚¢', &['â´‚']), + ('á‚£', &['â´ƒ']), + ('Ⴄ', &['â´„']), + ('á‚¥', &['â´…']), + ('Ⴆ', &['â´†']), + ('Ⴇ', &['â´‡']), + ('Ⴈ', &['â´ˆ']), + ('á‚©', &['â´‰']), + ('Ⴊ', &['â´Š']), + ('á‚«', &['â´‹']), + ('Ⴌ', &['â´Œ']), + ('á‚­', &['â´']), + ('á‚®', &['â´Ž']), + ('Ⴏ', &['â´']), + ('á‚°', &['â´']), + ('Ⴑ', &['â´‘']), + ('Ⴒ', &['â´’']), + ('Ⴓ', &['â´“']), + ('á‚´', &['â´”']), + ('Ⴕ', &['â´•']), + ('Ⴖ', &['â´–']), + ('á‚·', &['â´—']), + ('Ⴘ', &['â´˜']), + ('Ⴙ', &['â´™']), + ('Ⴚ', &['â´š']), + ('á‚»', &['â´›']), + ('Ⴜ', &['â´œ']), + ('Ⴝ', &['â´']), + ('Ⴞ', &['â´ž']), + ('á‚¿', &['â´Ÿ']), + ('Ⴠ', &['â´ ']), + ('áƒ', &['â´¡']), + ('Ⴢ', &['â´¢']), + ('Ⴣ', &['â´£']), + ('Ⴤ', &['â´¤']), + ('Ⴥ', &['â´¥']), + ('Ⴧ', &['â´§']), + ('áƒ', &['â´­']), + ('áƒ', &['á²']), + ('ბ', &['Ბ']), + ('გ', &['á²’']), + ('დ', &['Დ']), + ('ე', &['á²”']), + ('ვ', &['Ვ']), + ('ზ', &['á²–']), + ('თ', &['á²—']), + ('ი', &['Ი']), + ('კ', &['á²™']), + ('ლ', &['Ლ']), + ('მ', &['á²›']), + ('ნ', &['Ნ']), + ('áƒ', &['á²']), + ('პ', &['Პ']), + ('ჟ', &['Ჟ']), + ('რ', &['á² ']), + ('ს', &['Ს']), + ('ტ', &['á²¢']), + ('უ', &['á²£']), + ('ფ', &['Ფ']), + ('ქ', &['á²¥']), + ('ღ', &['Ღ']), + ('ყ', &['Ყ']), + ('შ', &['Შ']), + ('ჩ', &['Ჩ']), + ('ც', &['Ც']), + ('ძ', &['Ძ']), + ('წ', &['Წ']), + ('ჭ', &['á²­']), + ('ხ', &['á²®']), + ('ჯ', &['Ჯ']), + ('ჰ', &['á²°']), + ('ჱ', &['á²±']), + ('ჲ', &['á²²']), + ('ჳ', &['á²³']), + ('ჴ', &['á²´']), + ('ჵ', &['á²µ']), + ('ჶ', &['Ჶ']), + ('ჷ', &['á²·']), + ('ჸ', &['Ჸ']), + ('ჹ', &['á²¹']), + ('ჺ', &['Ჺ']), + ('ჽ', &['á²½']), + ('ჾ', &['á²¾']), + ('ჿ', &['Ჿ']), + ('Ꭰ', &['ê­°']), + ('Ꭱ', &['ê­±']), + ('Ꭲ', &['ê­²']), + ('Ꭳ', &['ê­³']), + ('Ꭴ', &['ê­´']), + ('Ꭵ', &['ê­µ']), + ('Ꭶ', &['ê­¶']), + ('Ꭷ', &['ê­·']), + ('Ꭸ', &['ê­¸']), + ('Ꭹ', &['ê­¹']), + ('Ꭺ', &['ê­º']), + ('Ꭻ', &['ê­»']), + ('Ꭼ', &['ê­¼']), + ('Ꭽ', &['ê­½']), + ('Ꭾ', &['ê­¾']), + ('Ꭿ', &['ê­¿']), + ('Ꮀ', &['ꮀ']), + ('Ꮁ', &['ê®']), + ('Ꮂ', &['ꮂ']), + ('Ꮃ', &['ꮃ']), + ('Ꮄ', &['ꮄ']), + ('Ꮅ', &['ê®…']), + ('Ꮆ', &['ꮆ']), + ('Ꮇ', &['ꮇ']), + ('Ꮈ', &['ꮈ']), + ('Ꮉ', &['ꮉ']), + ('Ꮊ', &['ꮊ']), + ('Ꮋ', &['ꮋ']), + ('Ꮌ', &['ꮌ']), + ('Ꮍ', &['ê®']), + ('Ꮎ', &['ꮎ']), + ('Ꮏ', &['ê®']), + ('á€', &['ê®']), + ('á', &['ꮑ']), + ('á‚', &['ê®’']), + ('áƒ', &['ꮓ']), + ('á„', &['ê®”']), + ('á…', &['ꮕ']), + ('á†', &['ê®–']), + ('á‡', &['ê®—']), + ('áˆ', &['ꮘ']), + ('á‰', &['ê®™']), + ('áŠ', &['ꮚ']), + ('á‹', &['ê®›']), + ('áŒ', &['ꮜ']), + ('á', &['ê®']), + ('áŽ', &['ꮞ']), + ('á', &['ꮟ']), + ('á', &['ê® ']), + ('á‘', &['ꮡ']), + ('á’', &['ꮢ']), + ('á“', &['ꮣ']), + ('á”', &['ꮤ']), + ('á•', &['ꮥ']), + ('á–', &['ꮦ']), + ('á—', &['ꮧ']), + ('á˜', &['ꮨ']), + ('á™', &['ꮩ']), + ('áš', &['ꮪ']), + ('á›', &['ꮫ']), + ('áœ', &['ꮬ']), + ('á', &['ê®­']), + ('áž', &['ê®®']), + ('áŸ', &['ꮯ']), + ('á ', &['ê®°']), + ('á¡', &['ê®±']), + ('á¢', &['ꮲ']), + ('á£', &['ꮳ']), + ('á¤', &['ê®´']), + ('á¥', &['ꮵ']), + ('á¦', &['ꮶ']), + ('á§', &['ê®·']), + ('á¨', &['ꮸ']), + ('á©', &['ꮹ']), + ('áª', &['ꮺ']), + ('á«', &['ê®»']), + ('á¬', &['ꮼ']), + ('á­', &['ꮽ']), + ('á®', &['ꮾ']), + ('á¯', &['ꮿ']), + ('á°', &['á¸']), + ('á±', &['á¹']), + ('á²', &['áº']), + ('á³', &['á»']), + ('á´', &['á¼']), + ('áµ', &['á½']), + ('á¸', &['á°']), + ('á¹', &['á±']), + ('áº', &['á²']), + ('á»', &['á³']), + ('á¼', &['á´']), + ('á½', &['áµ']), + ('á²€', &['Ð’', 'в']), + ('á²', &['Д', 'д']), + ('ᲂ', &['О', 'о']), + ('ᲃ', &['С', 'Ñ']), + ('ᲄ', &['Т', 'Ñ‚', 'á²…']), + ('á²…', &['Т', 'Ñ‚', 'ᲄ']), + ('ᲆ', &['Ъ', 'ÑŠ']), + ('ᲇ', &['Ñ¢', 'Ñ£']), + ('ᲈ', &['Ꙋ', 'ꙋ']), + ('á²', &['áƒ']), + ('Ბ', &['ბ']), + ('á²’', &['გ']), + ('Დ', &['დ']), + ('á²”', &['ე']), + ('Ვ', &['ვ']), + ('á²–', &['ზ']), + ('á²—', &['თ']), + ('Ი', &['ი']), + ('á²™', &['კ']), + ('Ლ', &['ლ']), + ('á²›', &['მ']), + ('Ნ', &['ნ']), + ('á²', &['áƒ']), + ('Პ', &['პ']), + ('Ჟ', &['ჟ']), + ('á² ', &['რ']), + ('Ს', &['ს']), + ('á²¢', &['ტ']), + ('á²£', &['უ']), + ('Ფ', &['ფ']), + ('á²¥', &['ქ']), + ('Ღ', &['ღ']), + ('Ყ', &['ყ']), + ('Შ', &['შ']), + ('Ჩ', &['ჩ']), + ('Ც', &['ც']), + ('Ძ', &['ძ']), + ('Წ', &['წ']), + ('á²­', &['ჭ']), + ('á²®', &['ხ']), + ('Ჯ', &['ჯ']), + ('á²°', &['ჰ']), + ('á²±', &['ჱ']), + ('á²²', &['ჲ']), + ('á²³', &['ჳ']), + ('á²´', &['ჴ']), + ('á²µ', &['ჵ']), + ('Ჶ', &['ჶ']), + ('á²·', &['ჷ']), + ('Ჸ', &['ჸ']), + ('á²¹', &['ჹ']), + ('Ჺ', &['ჺ']), + ('á²½', &['ჽ']), + ('á²¾', &['ჾ']), + ('Ჿ', &['ჿ']), + ('áµ¹', &['ê½']), + ('áµ½', &['â±£']), + ('ᶎ', &['Ᶎ']), + ('Ḁ', &['á¸']), + ('á¸', &['Ḁ']), + ('Ḃ', &['ḃ']), + ('ḃ', &['Ḃ']), + ('Ḅ', &['ḅ']), + ('ḅ', &['Ḅ']), + ('Ḇ', &['ḇ']), + ('ḇ', &['Ḇ']), + ('Ḉ', &['ḉ']), + ('ḉ', &['Ḉ']), + ('Ḋ', &['ḋ']), + ('ḋ', &['Ḋ']), + ('Ḍ', &['á¸']), + ('á¸', &['Ḍ']), + ('Ḏ', &['á¸']), + ('á¸', &['Ḏ']), + ('á¸', &['ḑ']), + ('ḑ', &['á¸']), + ('Ḓ', &['ḓ']), + ('ḓ', &['Ḓ']), + ('Ḕ', &['ḕ']), + ('ḕ', &['Ḕ']), + ('Ḗ', &['ḗ']), + ('ḗ', &['Ḗ']), + ('Ḙ', &['ḙ']), + ('ḙ', &['Ḙ']), + ('Ḛ', &['ḛ']), + ('ḛ', &['Ḛ']), + ('Ḝ', &['á¸']), + ('á¸', &['Ḝ']), + ('Ḟ', &['ḟ']), + ('ḟ', &['Ḟ']), + ('Ḡ', &['ḡ']), + ('ḡ', &['Ḡ']), + ('Ḣ', &['ḣ']), + ('ḣ', &['Ḣ']), + ('Ḥ', &['ḥ']), + ('ḥ', &['Ḥ']), + ('Ḧ', &['ḧ']), + ('ḧ', &['Ḧ']), + ('Ḩ', &['ḩ']), + ('ḩ', &['Ḩ']), + ('Ḫ', &['ḫ']), + ('ḫ', &['Ḫ']), + ('Ḭ', &['ḭ']), + ('ḭ', &['Ḭ']), + ('Ḯ', &['ḯ']), + ('ḯ', &['Ḯ']), + ('Ḱ', &['ḱ']), + ('ḱ', &['Ḱ']), + ('Ḳ', &['ḳ']), + ('ḳ', &['Ḳ']), + ('Ḵ', &['ḵ']), + ('ḵ', &['Ḵ']), + ('Ḷ', &['ḷ']), + ('ḷ', &['Ḷ']), + ('Ḹ', &['ḹ']), + ('ḹ', &['Ḹ']), + ('Ḻ', &['ḻ']), + ('ḻ', &['Ḻ']), + ('Ḽ', &['ḽ']), + ('ḽ', &['Ḽ']), + ('Ḿ', &['ḿ']), + ('ḿ', &['Ḿ']), + ('á¹€', &['á¹']), + ('á¹', &['á¹€']), + ('Ṃ', &['ṃ']), + ('ṃ', &['Ṃ']), + ('Ṅ', &['á¹…']), + ('á¹…', &['Ṅ']), + ('Ṇ', &['ṇ']), + ('ṇ', &['Ṇ']), + ('Ṉ', &['ṉ']), + ('ṉ', &['Ṉ']), + ('Ṋ', &['ṋ']), + ('ṋ', &['Ṋ']), + ('Ṍ', &['á¹']), + ('á¹', &['Ṍ']), + ('Ṏ', &['á¹']), + ('á¹', &['Ṏ']), + ('á¹', &['ṑ']), + ('ṑ', &['á¹']), + ('á¹’', &['ṓ']), + ('ṓ', &['á¹’']), + ('á¹”', &['ṕ']), + ('ṕ', &['á¹”']), + ('á¹–', &['á¹—']), + ('á¹—', &['á¹–']), + ('Ṙ', &['á¹™']), + ('á¹™', &['Ṙ']), + ('Ṛ', &['á¹›']), + ('á¹›', &['Ṛ']), + ('Ṝ', &['á¹']), + ('á¹', &['Ṝ']), + ('Ṟ', &['ṟ']), + ('ṟ', &['Ṟ']), + ('á¹ ', &['ṡ', 'ẛ']), + ('ṡ', &['á¹ ', 'ẛ']), + ('á¹¢', &['á¹£']), + ('á¹£', &['á¹¢']), + ('Ṥ', &['á¹¥']), + ('á¹¥', &['Ṥ']), + ('Ṧ', &['ṧ']), + ('ṧ', &['Ṧ']), + ('Ṩ', &['ṩ']), + ('ṩ', &['Ṩ']), + ('Ṫ', &['ṫ']), + ('ṫ', &['Ṫ']), + ('Ṭ', &['á¹­']), + ('á¹­', &['Ṭ']), + ('á¹®', &['ṯ']), + ('ṯ', &['á¹®']), + ('á¹°', &['á¹±']), + ('á¹±', &['á¹°']), + ('á¹²', &['á¹³']), + ('á¹³', &['á¹²']), + ('á¹´', &['á¹µ']), + ('á¹µ', &['á¹´']), + ('Ṷ', &['á¹·']), + ('á¹·', &['Ṷ']), + ('Ṹ', &['á¹¹']), + ('á¹¹', &['Ṹ']), + ('Ṻ', &['á¹»']), + ('á¹»', &['Ṻ']), + ('á¹¼', &['á¹½']), + ('á¹½', &['á¹¼']), + ('á¹¾', &['ṿ']), + ('ṿ', &['á¹¾']), + ('Ẁ', &['áº']), + ('áº', &['Ẁ']), + ('Ẃ', &['ẃ']), + ('ẃ', &['Ẃ']), + ('Ẅ', &['ẅ']), + ('ẅ', &['Ẅ']), + ('Ẇ', &['ẇ']), + ('ẇ', &['Ẇ']), + ('Ẉ', &['ẉ']), + ('ẉ', &['Ẉ']), + ('Ẋ', &['ẋ']), + ('ẋ', &['Ẋ']), + ('Ẍ', &['áº']), + ('áº', &['Ẍ']), + ('Ẏ', &['áº']), + ('áº', &['Ẏ']), + ('áº', &['ẑ']), + ('ẑ', &['áº']), + ('Ẓ', &['ẓ']), + ('ẓ', &['Ẓ']), + ('Ẕ', &['ẕ']), + ('ẕ', &['Ẕ']), + ('ẛ', &['á¹ ', 'ṡ']), + ('ẞ', &['ß']), + ('Ạ', &['ạ']), + ('ạ', &['Ạ']), + ('Ả', &['ả']), + ('ả', &['Ả']), + ('Ấ', &['ấ']), + ('ấ', &['Ấ']), + ('Ầ', &['ầ']), + ('ầ', &['Ầ']), + ('Ẩ', &['ẩ']), + ('ẩ', &['Ẩ']), + ('Ẫ', &['ẫ']), + ('ẫ', &['Ẫ']), + ('Ậ', &['ậ']), + ('ậ', &['Ậ']), + ('Ắ', &['ắ']), + ('ắ', &['Ắ']), + ('Ằ', &['ằ']), + ('ằ', &['Ằ']), + ('Ẳ', &['ẳ']), + ('ẳ', &['Ẳ']), + ('Ẵ', &['ẵ']), + ('ẵ', &['Ẵ']), + ('Ặ', &['ặ']), + ('ặ', &['Ặ']), + ('Ẹ', &['ẹ']), + ('ẹ', &['Ẹ']), + ('Ẻ', &['ẻ']), + ('ẻ', &['Ẻ']), + ('Ẽ', &['ẽ']), + ('ẽ', &['Ẽ']), + ('Ế', &['ế']), + ('ế', &['Ế']), + ('Ề', &['á»']), + ('á»', &['Ề']), + ('Ể', &['ể']), + ('ể', &['Ể']), + ('Ễ', &['á»…']), + ('á»…', &['Ễ']), + ('Ệ', &['ệ']), + ('ệ', &['Ệ']), + ('Ỉ', &['ỉ']), + ('ỉ', &['Ỉ']), + ('Ị', &['ị']), + ('ị', &['Ị']), + ('Ọ', &['á»']), + ('á»', &['Ọ']), + ('Ỏ', &['á»']), + ('á»', &['Ỏ']), + ('á»', &['ố']), + ('ố', &['á»']), + ('á»’', &['ồ']), + ('ồ', &['á»’']), + ('á»”', &['ổ']), + ('ổ', &['á»”']), + ('á»–', &['á»—']), + ('á»—', &['á»–']), + ('Ộ', &['á»™']), + ('á»™', &['Ộ']), + ('Ớ', &['á»›']), + ('á»›', &['Ớ']), + ('Ờ', &['á»']), + ('á»', &['Ờ']), + ('Ở', &['ở']), + ('ở', &['Ở']), + ('á» ', &['ỡ']), + ('ỡ', &['á» ']), + ('Ợ', &['ợ']), + ('ợ', &['Ợ']), + ('Ụ', &['ụ']), + ('ụ', &['Ụ']), + ('Ủ', &['ủ']), + ('ủ', &['Ủ']), + ('Ứ', &['ứ']), + ('ứ', &['Ứ']), + ('Ừ', &['ừ']), + ('ừ', &['Ừ']), + ('Ử', &['á»­']), + ('á»­', &['Ử']), + ('á»®', &['ữ']), + ('ữ', &['á»®']), + ('á»°', &['á»±']), + ('á»±', &['á»°']), + ('Ỳ', &['ỳ']), + ('ỳ', &['Ỳ']), + ('á»´', &['ỵ']), + ('ỵ', &['á»´']), + ('Ỷ', &['á»·']), + ('á»·', &['Ỷ']), + ('Ỹ', &['ỹ']), + ('ỹ', &['Ỹ']), + ('Ỻ', &['á»»']), + ('á»»', &['Ỻ']), + ('Ỽ', &['ỽ']), + ('ỽ', &['Ỽ']), + ('Ỿ', &['ỿ']), + ('ỿ', &['Ỿ']), + ('á¼€', &['Ἀ']), + ('á¼', &['Ἁ']), + ('ἂ', &['Ἂ']), + ('ἃ', &['Ἃ']), + ('ἄ', &['Ἄ']), + ('á¼…', &['á¼']), + ('ἆ', &['Ἆ']), + ('ἇ', &['á¼']), + ('Ἀ', &['á¼€']), + ('Ἁ', &['á¼']), + ('Ἂ', &['ἂ']), + ('Ἃ', &['ἃ']), + ('Ἄ', &['ἄ']), + ('á¼', &['á¼…']), + ('Ἆ', &['ἆ']), + ('á¼', &['ἇ']), + ('á¼', &['Ἐ']), + ('ἑ', &['á¼™']), + ('á¼’', &['Ἒ']), + ('ἓ', &['á¼›']), + ('á¼”', &['Ἔ']), + ('ἕ', &['á¼']), + ('Ἐ', &['á¼']), + ('á¼™', &['ἑ']), + ('Ἒ', &['á¼’']), + ('á¼›', &['ἓ']), + ('Ἔ', &['á¼”']), + ('á¼', &['ἕ']), + ('á¼ ', &['Ἠ']), + ('ἡ', &['Ἡ']), + ('á¼¢', &['Ἢ']), + ('á¼£', &['Ἣ']), + ('ἤ', &['Ἤ']), + ('á¼¥', &['á¼­']), + ('ἦ', &['á¼®']), + ('ἧ', &['Ἧ']), + ('Ἠ', &['á¼ ']), + ('Ἡ', &['ἡ']), + ('Ἢ', &['á¼¢']), + ('Ἣ', &['á¼£']), + ('Ἤ', &['ἤ']), + ('á¼­', &['á¼¥']), + ('á¼®', &['ἦ']), + ('Ἧ', &['ἧ']), + ('á¼°', &['Ἰ']), + ('á¼±', &['á¼¹']), + ('á¼²', &['Ἲ']), + ('á¼³', &['á¼»']), + ('á¼´', &['á¼¼']), + ('á¼µ', &['á¼½']), + ('ἶ', &['á¼¾']), + ('á¼·', &['Ἷ']), + ('Ἰ', &['á¼°']), + ('á¼¹', &['á¼±']), + ('Ἲ', &['á¼²']), + ('á¼»', &['á¼³']), + ('á¼¼', &['á¼´']), + ('á¼½', &['á¼µ']), + ('á¼¾', &['ἶ']), + ('Ἷ', &['á¼·']), + ('á½€', &['Ὀ']), + ('á½', &['Ὁ']), + ('ὂ', &['Ὂ']), + ('ὃ', &['Ὃ']), + ('ὄ', &['Ὄ']), + ('á½…', &['á½']), + ('Ὀ', &['á½€']), + ('Ὁ', &['á½']), + ('Ὂ', &['ὂ']), + ('Ὃ', &['ὃ']), + ('Ὄ', &['ὄ']), + ('á½', &['á½…']), + ('ὑ', &['á½™']), + ('ὓ', &['á½›']), + ('ὕ', &['á½']), + ('á½—', &['Ὗ']), + ('á½™', &['ὑ']), + ('á½›', &['ὓ']), + ('á½', &['ὕ']), + ('Ὗ', &['á½—']), + ('á½ ', &['Ὠ']), + ('ὡ', &['Ὡ']), + ('á½¢', &['Ὢ']), + ('á½£', &['Ὣ']), + ('ὤ', &['Ὤ']), + ('á½¥', &['á½­']), + ('ὦ', &['á½®']), + ('ὧ', &['Ὧ']), + ('Ὠ', &['á½ ']), + ('Ὡ', &['ὡ']), + ('Ὢ', &['á½¢']), + ('Ὣ', &['á½£']), + ('Ὤ', &['ὤ']), + ('á½­', &['á½¥']), + ('á½®', &['ὦ']), + ('Ὧ', &['ὧ']), + ('á½°', &['Ὰ']), + ('á½±', &['á¾»']), + ('á½²', &['Ὲ']), + ('á½³', &['Έ']), + ('á½´', &['á¿Š']), + ('á½µ', &['á¿‹']), + ('ὶ', &['á¿š']), + ('á½·', &['á¿›']), + ('ὸ', &['Ὸ']), + ('á½¹', &['Ό']), + ('ὺ', &['Ὺ']), + ('á½»', &['á¿«']), + ('á½¼', &['Ὼ']), + ('á½½', &['á¿»']), + ('á¾€', &['ᾈ']), + ('á¾', &['ᾉ']), + ('ᾂ', &['ᾊ']), + ('ᾃ', &['ᾋ']), + ('ᾄ', &['ᾌ']), + ('á¾…', &['á¾']), + ('ᾆ', &['ᾎ']), + ('ᾇ', &['á¾']), + ('ᾈ', &['á¾€']), + ('ᾉ', &['á¾']), + ('ᾊ', &['ᾂ']), + ('ᾋ', &['ᾃ']), + ('ᾌ', &['ᾄ']), + ('á¾', &['á¾…']), + ('ᾎ', &['ᾆ']), + ('á¾', &['ᾇ']), + ('á¾', &['ᾘ']), + ('ᾑ', &['á¾™']), + ('á¾’', &['ᾚ']), + ('ᾓ', &['á¾›']), + ('á¾”', &['ᾜ']), + ('ᾕ', &['á¾']), + ('á¾–', &['ᾞ']), + ('á¾—', &['ᾟ']), + ('ᾘ', &['á¾']), + ('á¾™', &['ᾑ']), + ('ᾚ', &['á¾’']), + ('á¾›', &['ᾓ']), + ('ᾜ', &['á¾”']), + ('á¾', &['ᾕ']), + ('ᾞ', &['á¾–']), + ('ᾟ', &['á¾—']), + ('á¾ ', &['ᾨ']), + ('ᾡ', &['ᾩ']), + ('á¾¢', &['ᾪ']), + ('á¾£', &['ᾫ']), + ('ᾤ', &['ᾬ']), + ('á¾¥', &['á¾­']), + ('ᾦ', &['á¾®']), + ('ᾧ', &['ᾯ']), + ('ᾨ', &['á¾ ']), + ('ᾩ', &['ᾡ']), + ('ᾪ', &['á¾¢']), + ('ᾫ', &['á¾£']), + ('ᾬ', &['ᾤ']), + ('á¾­', &['á¾¥']), + ('á¾®', &['ᾦ']), + ('ᾯ', &['ᾧ']), + ('á¾°', &['Ᾰ']), + ('á¾±', &['á¾¹']), + ('á¾³', &['á¾¼']), + ('Ᾰ', &['á¾°']), + ('á¾¹', &['á¾±']), + ('Ὰ', &['á½°']), + ('á¾»', &['á½±']), + ('á¾¼', &['á¾³']), + ('á¾¾', &['\u{345}', 'Ι', 'ι']), + ('ῃ', &['á¿Œ']), + ('Ὲ', &['á½²']), + ('Έ', &['á½³']), + ('á¿Š', &['á½´']), + ('á¿‹', &['á½µ']), + ('á¿Œ', &['ῃ']), + ('á¿', &['Ῐ']), + ('á¿‘', &['á¿™']), + ('Ῐ', &['á¿']), + ('á¿™', &['á¿‘']), + ('á¿š', &['ὶ']), + ('á¿›', &['á½·']), + ('á¿ ', &['Ῠ']), + ('á¿¡', &['á¿©']), + ('á¿¥', &['Ῥ']), + ('Ῠ', &['á¿ ']), + ('á¿©', &['á¿¡']), + ('Ὺ', &['ὺ']), + ('á¿«', &['á½»']), + ('Ῥ', &['á¿¥']), + ('ῳ', &['ῼ']), + ('Ὸ', &['ὸ']), + ('Ό', &['á½¹']), + ('Ὼ', &['á½¼']), + ('á¿»', &['á½½']), + ('ῼ', &['ῳ']), + ('Ω', &['Ω', 'ω']), + ('K', &['K', 'k']), + ('â„«', &['Ã…', 'Ã¥']), + ('Ⅎ', &['â…Ž']), + ('â…Ž', &['Ⅎ']), + ('â… ', &['â…°']), + ('â…¡', &['â…±']), + ('â…¢', &['â…²']), + ('â…£', &['â…³']), + ('â…¤', &['â…´']), + ('â…¥', &['â…µ']), + ('â…¦', &['â…¶']), + ('â…§', &['â…·']), + ('â…¨', &['â…¸']), + ('â…©', &['â…¹']), + ('â…ª', &['â…º']), + ('â…«', &['â…»']), + ('â…¬', &['â…¼']), + ('â…­', &['â…½']), + ('â…®', &['â…¾']), + ('â…¯', &['â…¿']), + ('â…°', &['â… ']), + ('â…±', &['â…¡']), + ('â…²', &['â…¢']), + ('â…³', &['â…£']), + ('â…´', &['â…¤']), + ('â…µ', &['â…¥']), + ('â…¶', &['â…¦']), + ('â…·', &['â…§']), + ('â…¸', &['â…¨']), + ('â…¹', &['â…©']), + ('â…º', &['â…ª']), + ('â…»', &['â…«']), + ('â…¼', &['â…¬']), + ('â…½', &['â…­']), + ('â…¾', &['â…®']), + ('â…¿', &['â…¯']), + ('Ↄ', &['ↄ']), + ('ↄ', &['Ↄ']), + ('â’¶', &['â“']), + ('â’·', &['â“‘']), + ('â’¸', &['â“’']), + ('â’¹', &['â““']), + ('â’º', &['â“”']), + ('â’»', &['â“•']), + ('â’¼', &['â“–']), + ('â’½', &['â“—']), + ('â’¾', &['ⓘ']), + ('â’¿', &['â“™']), + ('â“€', &['â“š']), + ('â“', &['â“›']), + ('â“‚', &['â“œ']), + ('Ⓝ', &['â“']), + ('â“„', &['â“ž']), + ('â“…', &['â“Ÿ']), + ('Ⓠ', &['â“ ']), + ('Ⓡ', &['â“¡']), + ('Ⓢ', &['â“¢']), + ('Ⓣ', &['â“£']), + ('â“Š', &['ⓤ']), + ('â“‹', &['â“¥']), + ('â“Œ', &['ⓦ']), + ('â“', &['ⓧ']), + ('â“Ž', &['ⓨ']), + ('â“', &['â“©']), + ('â“', &['â’¶']), + ('â“‘', &['â’·']), + ('â“’', &['â’¸']), + ('â““', &['â’¹']), + ('â“”', &['â’º']), + ('â“•', &['â’»']), + ('â“–', &['â’¼']), + ('â“—', &['â’½']), + ('ⓘ', &['â’¾']), + ('â“™', &['â’¿']), + ('â“š', &['â“€']), + ('â“›', &['â“']), + ('â“œ', &['â“‚']), + ('â“', &['Ⓝ']), + ('â“ž', &['â“„']), + ('â“Ÿ', &['â“…']), + ('â“ ', &['Ⓠ']), + ('â“¡', &['Ⓡ']), + ('â“¢', &['Ⓢ']), + ('â“£', &['Ⓣ']), + ('ⓤ', &['â“Š']), + ('â“¥', &['â“‹']), + ('ⓦ', &['â“Œ']), + ('ⓧ', &['â“']), + ('ⓨ', &['â“Ž']), + ('â“©', &['â“']), + ('â°€', &['â°°']), + ('â°', &['â°±']), + ('â°‚', &['â°²']), + ('â°ƒ', &['â°³']), + ('â°„', &['â°´']), + ('â°…', &['â°µ']), + ('â°†', &['â°¶']), + ('â°‡', &['â°·']), + ('â°ˆ', &['â°¸']), + ('â°‰', &['â°¹']), + ('â°Š', &['â°º']), + ('â°‹', &['â°»']), + ('â°Œ', &['â°¼']), + ('â°', &['â°½']), + ('â°Ž', &['â°¾']), + ('â°', &['â°¿']), + ('â°', &['â±€']), + ('â°‘', &['â±']), + ('â°’', &['ⱂ']), + ('â°“', &['ⱃ']), + ('â°”', &['ⱄ']), + ('â°•', &['â±…']), + ('â°–', &['ⱆ']), + ('â°—', &['ⱇ']), + ('â°˜', &['ⱈ']), + ('â°™', &['ⱉ']), + ('â°š', &['ⱊ']), + ('â°›', &['ⱋ']), + ('â°œ', &['ⱌ']), + ('â°', &['â±']), + ('â°ž', &['ⱎ']), + ('â°Ÿ', &['â±']), + ('â° ', &['â±']), + ('â°¡', &['ⱑ']), + ('â°¢', &['â±’']), + ('â°£', &['ⱓ']), + ('â°¤', &['â±”']), + ('â°¥', &['ⱕ']), + ('â°¦', &['â±–']), + ('â°§', &['â±—']), + ('â°¨', &['ⱘ']), + ('â°©', &['â±™']), + ('â°ª', &['ⱚ']), + ('â°«', &['â±›']), + ('â°¬', &['ⱜ']), + ('â°­', &['â±']), + ('â°®', &['ⱞ']), + ('â°¯', &['ⱟ']), + ('â°°', &['â°€']), + ('â°±', &['â°']), + ('â°²', &['â°‚']), + ('â°³', &['â°ƒ']), + ('â°´', &['â°„']), + ('â°µ', &['â°…']), + ('â°¶', &['â°†']), + ('â°·', &['â°‡']), + ('â°¸', &['â°ˆ']), + ('â°¹', &['â°‰']), + ('â°º', &['â°Š']), + ('â°»', &['â°‹']), + ('â°¼', &['â°Œ']), + ('â°½', &['â°']), + ('â°¾', &['â°Ž']), + ('â°¿', &['â°']), + ('â±€', &['â°']), + ('â±', &['â°‘']), + ('ⱂ', &['â°’']), + ('ⱃ', &['â°“']), + ('ⱄ', &['â°”']), + ('â±…', &['â°•']), + ('ⱆ', &['â°–']), + ('ⱇ', &['â°—']), + ('ⱈ', &['â°˜']), + ('ⱉ', &['â°™']), + ('ⱊ', &['â°š']), + ('ⱋ', &['â°›']), + ('ⱌ', &['â°œ']), + ('â±', &['â°']), + ('ⱎ', &['â°ž']), + ('â±', &['â°Ÿ']), + ('â±', &['â° ']), + ('ⱑ', &['â°¡']), + ('â±’', &['â°¢']), + ('ⱓ', &['â°£']), + ('â±”', &['â°¤']), + ('ⱕ', &['â°¥']), + ('â±–', &['â°¦']), + ('â±—', &['â°§']), + ('ⱘ', &['â°¨']), + ('â±™', &['â°©']), + ('ⱚ', &['â°ª']), + ('â±›', &['â°«']), + ('ⱜ', &['â°¬']), + ('â±', &['â°­']), + ('ⱞ', &['â°®']), + ('ⱟ', &['â°¯']), + ('â± ', &['ⱡ']), + ('ⱡ', &['â± ']), + ('â±¢', &['É«']), + ('â±£', &['áµ½']), + ('Ɽ', &['ɽ']), + ('â±¥', &['Ⱥ']), + ('ⱦ', &['Ⱦ']), + ('Ⱨ', &['ⱨ']), + ('ⱨ', &['Ⱨ']), + ('Ⱪ', &['ⱪ']), + ('ⱪ', &['Ⱪ']), + ('Ⱬ', &['ⱬ']), + ('ⱬ', &['Ⱬ']), + ('â±­', &['É‘']), + ('â±®', &['ɱ']), + ('Ɐ', &['É']), + ('â±°', &['É’']), + ('â±²', &['â±³']), + ('â±³', &['â±²']), + ('â±µ', &['ⱶ']), + ('ⱶ', &['â±µ']), + ('â±¾', &['È¿']), + ('Ɀ', &['É€']), + ('â²€', &['â²']), + ('â²', &['â²€']), + ('Ⲃ', &['ⲃ']), + ('ⲃ', &['Ⲃ']), + ('Ⲅ', &['â²…']), + ('â²…', &['Ⲅ']), + ('Ⲇ', &['ⲇ']), + ('ⲇ', &['Ⲇ']), + ('Ⲉ', &['ⲉ']), + ('ⲉ', &['Ⲉ']), + ('Ⲋ', &['ⲋ']), + ('ⲋ', &['Ⲋ']), + ('Ⲍ', &['â²']), + ('â²', &['Ⲍ']), + ('Ⲏ', &['â²']), + ('â²', &['Ⲏ']), + ('â²', &['ⲑ']), + ('ⲑ', &['â²']), + ('â²’', &['ⲓ']), + ('ⲓ', &['â²’']), + ('â²”', &['ⲕ']), + ('ⲕ', &['â²”']), + ('â²–', &['â²—']), + ('â²—', &['â²–']), + ('Ⲙ', &['â²™']), + ('â²™', &['Ⲙ']), + ('Ⲛ', &['â²›']), + ('â²›', &['Ⲛ']), + ('Ⲝ', &['â²']), + ('â²', &['Ⲝ']), + ('Ⲟ', &['ⲟ']), + ('ⲟ', &['Ⲟ']), + ('â² ', &['ⲡ']), + ('ⲡ', &['â² ']), + ('â²¢', &['â²£']), + ('â²£', &['â²¢']), + ('Ⲥ', &['â²¥']), + ('â²¥', &['Ⲥ']), + ('Ⲧ', &['ⲧ']), + ('ⲧ', &['Ⲧ']), + ('Ⲩ', &['ⲩ']), + ('ⲩ', &['Ⲩ']), + ('Ⲫ', &['ⲫ']), + ('ⲫ', &['Ⲫ']), + ('Ⲭ', &['â²­']), + ('â²­', &['Ⲭ']), + ('â²®', &['ⲯ']), + ('ⲯ', &['â²®']), + ('â²°', &['â²±']), + ('â²±', &['â²°']), + ('â²²', &['â²³']), + ('â²³', &['â²²']), + ('â²´', &['â²µ']), + ('â²µ', &['â²´']), + ('Ⲷ', &['â²·']), + ('â²·', &['Ⲷ']), + ('Ⲹ', &['â²¹']), + ('â²¹', &['Ⲹ']), + ('Ⲻ', &['â²»']), + ('â²»', &['Ⲻ']), + ('â²¼', &['â²½']), + ('â²½', &['â²¼']), + ('â²¾', &['ⲿ']), + ('ⲿ', &['â²¾']), + ('â³€', &['â³']), + ('â³', &['â³€']), + ('Ⳃ', &['ⳃ']), + ('ⳃ', &['Ⳃ']), + ('Ⳅ', &['â³…']), + ('â³…', &['Ⳅ']), + ('Ⳇ', &['ⳇ']), + ('ⳇ', &['Ⳇ']), + ('Ⳉ', &['ⳉ']), + ('ⳉ', &['Ⳉ']), + ('Ⳋ', &['ⳋ']), + ('ⳋ', &['Ⳋ']), + ('Ⳍ', &['â³']), + ('â³', &['Ⳍ']), + ('Ⳏ', &['â³']), + ('â³', &['Ⳏ']), + ('â³', &['ⳑ']), + ('ⳑ', &['â³']), + ('â³’', &['ⳓ']), + ('ⳓ', &['â³’']), + ('â³”', &['ⳕ']), + ('ⳕ', &['â³”']), + ('â³–', &['â³—']), + ('â³—', &['â³–']), + ('Ⳙ', &['â³™']), + ('â³™', &['Ⳙ']), + ('Ⳛ', &['â³›']), + ('â³›', &['Ⳛ']), + ('Ⳝ', &['â³']), + ('â³', &['Ⳝ']), + ('Ⳟ', &['ⳟ']), + ('ⳟ', &['Ⳟ']), + ('â³ ', &['ⳡ']), + ('ⳡ', &['â³ ']), + ('â³¢', &['â³£']), + ('â³£', &['â³¢']), + ('Ⳬ', &['ⳬ']), + ('ⳬ', &['Ⳬ']), + ('â³­', &['â³®']), + ('â³®', &['â³­']), + ('â³²', &['â³³']), + ('â³³', &['â³²']), + ('â´€', &['á‚ ']), + ('â´', &['á‚¡']), + ('â´‚', &['á‚¢']), + ('â´ƒ', &['á‚£']), + ('â´„', &['Ⴄ']), + ('â´…', &['á‚¥']), + ('â´†', &['Ⴆ']), + ('â´‡', &['Ⴇ']), + ('â´ˆ', &['Ⴈ']), + ('â´‰', &['á‚©']), + ('â´Š', &['Ⴊ']), + ('â´‹', &['á‚«']), + ('â´Œ', &['Ⴌ']), + ('â´', &['á‚­']), + ('â´Ž', &['á‚®']), + ('â´', &['Ⴏ']), + ('â´', &['á‚°']), + ('â´‘', &['Ⴑ']), + ('â´’', &['Ⴒ']), + ('â´“', &['Ⴓ']), + ('â´”', &['á‚´']), + ('â´•', &['Ⴕ']), + ('â´–', &['Ⴖ']), + ('â´—', &['á‚·']), + ('â´˜', &['Ⴘ']), + ('â´™', &['Ⴙ']), + ('â´š', &['Ⴚ']), + ('â´›', &['á‚»']), + ('â´œ', &['Ⴜ']), + ('â´', &['Ⴝ']), + ('â´ž', &['Ⴞ']), + ('â´Ÿ', &['á‚¿']), + ('â´ ', &['Ⴠ']), + ('â´¡', &['áƒ']), + ('â´¢', &['Ⴢ']), + ('â´£', &['Ⴣ']), + ('â´¤', &['Ⴤ']), + ('â´¥', &['Ⴥ']), + ('â´§', &['Ⴧ']), + ('â´­', &['áƒ']), + ('Ꙁ', &['ê™']), + ('ê™', &['Ꙁ']), + ('Ꙃ', &['ꙃ']), + ('ꙃ', &['Ꙃ']), + ('Ꙅ', &['ê™…']), + ('ê™…', &['Ꙅ']), + ('Ꙇ', &['ꙇ']), + ('ꙇ', &['Ꙇ']), + ('Ꙉ', &['ꙉ']), + ('ꙉ', &['Ꙉ']), + ('Ꙋ', &['ᲈ', 'ꙋ']), + ('ꙋ', &['ᲈ', 'Ꙋ']), + ('Ꙍ', &['ê™']), + ('ê™', &['Ꙍ']), + ('Ꙏ', &['ê™']), + ('ê™', &['Ꙏ']), + ('ê™', &['ꙑ']), + ('ꙑ', &['ê™']), + ('ê™’', &['ꙓ']), + ('ꙓ', &['ê™’']), + ('ê™”', &['ꙕ']), + ('ꙕ', &['ê™”']), + ('ê™–', &['ê™—']), + ('ê™—', &['ê™–']), + ('Ꙙ', &['ê™™']), + ('ê™™', &['Ꙙ']), + ('Ꙛ', &['ê™›']), + ('ê™›', &['Ꙛ']), + ('Ꙝ', &['ê™']), + ('ê™', &['Ꙝ']), + ('Ꙟ', &['ꙟ']), + ('ꙟ', &['Ꙟ']), + ('ê™ ', &['ꙡ']), + ('ꙡ', &['ê™ ']), + ('Ꙣ', &['ꙣ']), + ('ꙣ', &['Ꙣ']), + ('Ꙥ', &['ꙥ']), + ('ꙥ', &['Ꙥ']), + ('Ꙧ', &['ꙧ']), + ('ꙧ', &['Ꙧ']), + ('Ꙩ', &['ꙩ']), + ('ꙩ', &['Ꙩ']), + ('Ꙫ', &['ꙫ']), + ('ꙫ', &['Ꙫ']), + ('Ꙭ', &['ê™­']), + ('ê™­', &['Ꙭ']), + ('Ꚁ', &['êš']), + ('êš', &['Ꚁ']), + ('êš‚', &['ꚃ']), + ('ꚃ', &['êš‚']), + ('êš„', &['êš…']), + ('êš…', &['êš„']), + ('Ꚇ', &['ꚇ']), + ('ꚇ', &['Ꚇ']), + ('Ꚉ', &['ꚉ']), + ('ꚉ', &['Ꚉ']), + ('Ꚋ', &['êš‹']), + ('êš‹', &['Ꚋ']), + ('Ꚍ', &['êš']), + ('êš', &['Ꚍ']), + ('Ꚏ', &['êš']), + ('êš', &['Ꚏ']), + ('êš', &['êš‘']), + ('êš‘', &['êš']), + ('êš’', &['êš“']), + ('êš“', &['êš’']), + ('êš”', &['êš•']), + ('êš•', &['êš”']), + ('êš–', &['êš—']), + ('êš—', &['êš–']), + ('Ꚙ', &['êš™']), + ('êš™', &['Ꚙ']), + ('êšš', &['êš›']), + ('êš›', &['êšš']), + ('Ꜣ', &['ꜣ']), + ('ꜣ', &['Ꜣ']), + ('Ꜥ', &['ꜥ']), + ('ꜥ', &['Ꜥ']), + ('Ꜧ', &['ꜧ']), + ('ꜧ', &['Ꜧ']), + ('Ꜩ', &['ꜩ']), + ('ꜩ', &['Ꜩ']), + ('Ꜫ', &['ꜫ']), + ('ꜫ', &['Ꜫ']), + ('Ꜭ', &['ꜭ']), + ('ꜭ', &['Ꜭ']), + ('Ꜯ', &['ꜯ']), + ('ꜯ', &['Ꜯ']), + ('Ꜳ', &['ꜳ']), + ('ꜳ', &['Ꜳ']), + ('Ꜵ', &['ꜵ']), + ('ꜵ', &['Ꜵ']), + ('Ꜷ', &['ꜷ']), + ('ꜷ', &['Ꜷ']), + ('Ꜹ', &['ꜹ']), + ('ꜹ', &['Ꜹ']), + ('Ꜻ', &['ꜻ']), + ('ꜻ', &['Ꜻ']), + ('Ꜽ', &['ꜽ']), + ('ꜽ', &['Ꜽ']), + ('Ꜿ', &['ꜿ']), + ('ꜿ', &['Ꜿ']), + ('ê€', &['ê']), + ('ê', &['ê€']), + ('ê‚', &['êƒ']), + ('êƒ', &['ê‚']), + ('ê„', &['ê…']), + ('ê…', &['ê„']), + ('ê†', &['ê‡']), + ('ê‡', &['ê†']), + ('êˆ', &['ê‰']), + ('ê‰', &['êˆ']), + ('êŠ', &['ê‹']), + ('ê‹', &['êŠ']), + ('êŒ', &['ê']), + ('ê', &['êŒ']), + ('êŽ', &['ê']), + ('ê', &['êŽ']), + ('ê', &['ê‘']), + ('ê‘', &['ê']), + ('ê’', &['ê“']), + ('ê“', &['ê’']), + ('ê”', &['ê•']), + ('ê•', &['ê”']), + ('ê–', &['ê—']), + ('ê—', &['ê–']), + ('ê˜', &['ê™']), + ('ê™', &['ê˜']), + ('êš', &['ê›']), + ('ê›', &['êš']), + ('êœ', &['ê']), + ('ê', &['êœ']), + ('êž', &['êŸ']), + ('êŸ', &['êž']), + ('ê ', &['ê¡']), + ('ê¡', &['ê ']), + ('ê¢', &['ê£']), + ('ê£', &['ê¢']), + ('ê¤', &['ê¥']), + ('ê¥', &['ê¤']), + ('ê¦', &['ê§']), + ('ê§', &['ê¦']), + ('ê¨', &['ê©']), + ('ê©', &['ê¨']), + ('êª', &['ê«']), + ('ê«', &['êª']), + ('ê¬', &['ê­']), + ('ê­', &['ê¬']), + ('ê®', &['ê¯']), + ('ê¯', &['ê®']), + ('ê¹', &['êº']), + ('êº', &['ê¹']), + ('ê»', &['ê¼']), + ('ê¼', &['ê»']), + ('ê½', &['áµ¹']), + ('ê¾', &['ê¿']), + ('ê¿', &['ê¾']), + ('Ꞁ', &['êž']), + ('êž', &['Ꞁ']), + ('êž‚', &['ꞃ']), + ('ꞃ', &['êž‚']), + ('êž„', &['êž…']), + ('êž…', &['êž„']), + ('Ꞇ', &['ꞇ']), + ('ꞇ', &['Ꞇ']), + ('êž‹', &['ꞌ']), + ('ꞌ', &['êž‹']), + ('êž', &['É¥']), + ('êž', &['êž‘']), + ('êž‘', &['êž']), + ('êž’', &['êž“']), + ('êž“', &['êž’']), + ('êž”', &['Ꞔ']), + ('êž–', &['êž—']), + ('êž—', &['êž–']), + ('Ꞙ', &['êž™']), + ('êž™', &['Ꞙ']), + ('êžš', &['êž›']), + ('êž›', &['êžš']), + ('êžœ', &['êž']), + ('êž', &['êžœ']), + ('êžž', &['ꞟ']), + ('ꞟ', &['êžž']), + ('êž ', &['êž¡']), + ('êž¡', &['êž ']), + ('Ꞣ', &['ꞣ']), + ('ꞣ', &['Ꞣ']), + ('Ꞥ', &['ꞥ']), + ('ꞥ', &['Ꞥ']), + ('Ꞧ', &['ꞧ']), + ('ꞧ', &['Ꞧ']), + ('Ꞩ', &['êž©']), + ('êž©', &['Ꞩ']), + ('Ɦ', &['ɦ']), + ('êž«', &['Éœ']), + ('Ɡ', &['É¡']), + ('êž­', &['ɬ']), + ('êž®', &['ɪ']), + ('êž°', &['Êž']), + ('êž±', &['ʇ']), + ('êž²', &['Ê']), + ('êž³', &['ê­“']), + ('êž´', &['êžµ']), + ('êžµ', &['êž´']), + ('Ꞷ', &['êž·']), + ('êž·', &['Ꞷ']), + ('Ꞹ', &['êž¹']), + ('êž¹', &['Ꞹ']), + ('Ꞻ', &['êž»']), + ('êž»', &['Ꞻ']), + ('êž¼', &['êž½']), + ('êž½', &['êž¼']), + ('êž¾', &['êž¿']), + ('êž¿', &['êž¾']), + ('Ꟁ', &['êŸ']), + ('êŸ', &['Ꟁ']), + ('Ꟃ', &['ꟃ']), + ('ꟃ', &['Ꟃ']), + ('Ꞔ', &['êž”']), + ('Ʂ', &['Ê‚']), + ('Ᶎ', &['ᶎ']), + ('Ꟈ', &['ꟈ']), + ('ꟈ', &['Ꟈ']), + ('Ꟊ', &['ꟊ']), + ('ꟊ', &['Ꟊ']), + ('êŸ', &['ꟑ']), + ('ꟑ', &['êŸ']), + ('Ꟗ', &['ꟗ']), + ('ꟗ', &['Ꟗ']), + ('Ꟙ', &['ꟙ']), + ('ꟙ', &['Ꟙ']), + ('Ꟶ', &['ꟶ']), + ('ꟶ', &['Ꟶ']), + ('ê­“', &['êž³']), + ('ê­°', &['Ꭰ']), + ('ê­±', &['Ꭱ']), + ('ê­²', &['Ꭲ']), + ('ê­³', &['Ꭳ']), + ('ê­´', &['Ꭴ']), + ('ê­µ', &['Ꭵ']), + ('ê­¶', &['Ꭶ']), + ('ê­·', &['Ꭷ']), + ('ê­¸', &['Ꭸ']), + ('ê­¹', &['Ꭹ']), + ('ê­º', &['Ꭺ']), + ('ê­»', &['Ꭻ']), + ('ê­¼', &['Ꭼ']), + ('ê­½', &['Ꭽ']), + ('ê­¾', &['Ꭾ']), + ('ê­¿', &['Ꭿ']), + ('ꮀ', &['Ꮀ']), + ('ê®', &['Ꮁ']), + ('ꮂ', &['Ꮂ']), + ('ꮃ', &['Ꮃ']), + ('ꮄ', &['Ꮄ']), + ('ê®…', &['Ꮅ']), + ('ꮆ', &['Ꮆ']), + ('ꮇ', &['Ꮇ']), + ('ꮈ', &['Ꮈ']), + ('ꮉ', &['Ꮉ']), + ('ꮊ', &['Ꮊ']), + ('ꮋ', &['Ꮋ']), + ('ꮌ', &['Ꮌ']), + ('ê®', &['Ꮍ']), + ('ꮎ', &['Ꮎ']), + ('ê®', &['Ꮏ']), + ('ê®', &['á€']), + ('ꮑ', &['á']), + ('ê®’', &['á‚']), + ('ꮓ', &['áƒ']), + ('ê®”', &['á„']), + ('ꮕ', &['á…']), + ('ê®–', &['á†']), + ('ê®—', &['á‡']), + ('ꮘ', &['áˆ']), + ('ê®™', &['á‰']), + ('ꮚ', &['áŠ']), + ('ê®›', &['á‹']), + ('ꮜ', &['áŒ']), + ('ê®', &['á']), + ('ꮞ', &['áŽ']), + ('ꮟ', &['á']), + ('ê® ', &['á']), + ('ꮡ', &['á‘']), + ('ꮢ', &['á’']), + ('ꮣ', &['á“']), + ('ꮤ', &['á”']), + ('ꮥ', &['á•']), + ('ꮦ', &['á–']), + ('ꮧ', &['á—']), + ('ꮨ', &['á˜']), + ('ꮩ', &['á™']), + ('ꮪ', &['áš']), + ('ꮫ', &['á›']), + ('ꮬ', &['áœ']), + ('ê®­', &['á']), + ('ê®®', &['áž']), + ('ꮯ', &['áŸ']), + ('ê®°', &['á ']), + ('ê®±', &['á¡']), + ('ꮲ', &['á¢']), + ('ꮳ', &['á£']), + ('ê®´', &['á¤']), + ('ꮵ', &['á¥']), + ('ꮶ', &['á¦']), + ('ê®·', &['á§']), + ('ꮸ', &['á¨']), + ('ꮹ', &['á©']), + ('ꮺ', &['áª']), + ('ê®»', &['á«']), + ('ꮼ', &['á¬']), + ('ꮽ', &['á­']), + ('ꮾ', &['á®']), + ('ꮿ', &['á¯']), + ('A', &['ï½']), + ('ï¼¢', &['b']), + ('ï¼£', &['c']), + ('D', &['d']), + ('ï¼¥', &['ï½…']), + ('F', &['f']), + ('G', &['g']), + ('H', &['h']), + ('I', &['i']), + ('J', &['j']), + ('K', &['k']), + ('L', &['l']), + ('ï¼­', &['ï½']), + ('ï¼®', &['n']), + ('O', &['ï½']), + ('ï¼°', &['ï½']), + ('ï¼±', &['q']), + ('ï¼²', &['ï½’']), + ('ï¼³', &['s']), + ('ï¼´', &['ï½”']), + ('ï¼µ', &['u']), + ('V', &['ï½–']), + ('ï¼·', &['ï½—']), + ('X', &['x']), + ('ï¼¹', &['ï½™']), + ('Z', &['z']), + ('ï½', &['A']), + ('b', &['ï¼¢']), + ('c', &['ï¼£']), + ('d', &['D']), + ('ï½…', &['ï¼¥']), + ('f', &['F']), + ('g', &['G']), + ('h', &['H']), + ('i', &['I']), + ('j', &['J']), + ('k', &['K']), + ('l', &['L']), + ('ï½', &['ï¼­']), + ('n', &['ï¼®']), + ('ï½', &['O']), + ('ï½', &['ï¼°']), + ('q', &['ï¼±']), + ('ï½’', &['ï¼²']), + ('s', &['ï¼³']), + ('ï½”', &['ï¼´']), + ('u', &['ï¼µ']), + ('ï½–', &['V']), + ('ï½—', &['ï¼·']), + ('x', &['X']), + ('ï½™', &['ï¼¹']), + ('z', &['Z']), + ('ð€', &['ð¨']), + ('ð', &['ð©']), + ('ð‚', &['ðª']), + ('ðƒ', &['ð«']), + ('ð„', &['ð¬']), + ('ð…', &['ð­']), + ('ð†', &['ð®']), + ('ð‡', &['ð¯']), + ('ðˆ', &['ð°']), + ('ð‰', &['ð±']), + ('ðŠ', &['ð²']), + ('ð‹', &['ð³']), + ('ðŒ', &['ð´']), + ('ð', &['ðµ']), + ('ðŽ', &['ð¶']), + ('ð', &['ð·']), + ('ð', &['ð¸']), + ('ð‘', &['ð¹']), + ('ð’', &['ðº']), + ('ð“', &['ð»']), + ('ð”', &['ð¼']), + ('ð•', &['ð½']), + ('ð–', &['ð¾']), + ('ð—', &['ð¿']), + ('ð˜', &['ð‘€']), + ('ð™', &['ð‘']), + ('ðš', &['ð‘‚']), + ('ð›', &['ð‘ƒ']), + ('ðœ', &['ð‘„']), + ('ð', &['ð‘…']), + ('ðž', &['ð‘†']), + ('ðŸ', &['ð‘‡']), + ('ð ', &['ð‘ˆ']), + ('ð¡', &['ð‘‰']), + ('ð¢', &['ð‘Š']), + ('ð£', &['ð‘‹']), + ('ð¤', &['ð‘Œ']), + ('ð¥', &['ð‘']), + ('ð¦', &['ð‘Ž']), + ('ð§', &['ð‘']), + ('ð¨', &['ð€']), + ('ð©', &['ð']), + ('ðª', &['ð‚']), + ('ð«', &['ðƒ']), + ('ð¬', &['ð„']), + ('ð­', &['ð…']), + ('ð®', &['ð†']), + ('ð¯', &['ð‡']), + ('ð°', &['ðˆ']), + ('ð±', &['ð‰']), + ('ð²', &['ðŠ']), + ('ð³', &['ð‹']), + ('ð´', &['ðŒ']), + ('ðµ', &['ð']), + ('ð¶', &['ðŽ']), + ('ð·', &['ð']), + ('ð¸', &['ð']), + ('ð¹', &['ð‘']), + ('ðº', &['ð’']), + ('ð»', &['ð“']), + ('ð¼', &['ð”']), + ('ð½', &['ð•']), + ('ð¾', &['ð–']), + ('ð¿', &['ð—']), + ('ð‘€', &['ð˜']), + ('ð‘', &['ð™']), + ('ð‘‚', &['ðš']), + ('ð‘ƒ', &['ð›']), + ('ð‘„', &['ðœ']), + ('ð‘…', &['ð']), + ('ð‘†', &['ðž']), + ('ð‘‡', &['ðŸ']), + ('ð‘ˆ', &['ð ']), + ('ð‘‰', &['ð¡']), + ('ð‘Š', &['ð¢']), + ('ð‘‹', &['ð£']), + ('ð‘Œ', &['ð¤']), + ('ð‘', &['ð¥']), + ('ð‘Ž', &['ð¦']), + ('ð‘', &['ð§']), + ('ð’°', &['ð“˜']), + ('ð’±', &['ð“™']), + ('ð’²', &['ð“š']), + ('ð’³', &['ð“›']), + ('ð’´', &['ð“œ']), + ('ð’µ', &['ð“']), + ('ð’¶', &['ð“ž']), + ('ð’·', &['ð“Ÿ']), + ('ð’¸', &['ð“ ']), + ('ð’¹', &['ð“¡']), + ('ð’º', &['ð“¢']), + ('ð’»', &['ð“£']), + ('ð’¼', &['ð“¤']), + ('ð’½', &['ð“¥']), + ('ð’¾', &['ð“¦']), + ('ð’¿', &['ð“§']), + ('ð“€', &['ð“¨']), + ('ð“', &['ð“©']), + ('ð“‚', &['ð“ª']), + ('ð“ƒ', &['ð“«']), + ('ð“„', &['ð“¬']), + ('ð“…', &['ð“­']), + ('ð“†', &['ð“®']), + ('ð“‡', &['ð“¯']), + ('ð“ˆ', &['ð“°']), + ('ð“‰', &['ð“±']), + ('ð“Š', &['ð“²']), + ('ð“‹', &['ð“³']), + ('ð“Œ', &['ð“´']), + ('ð“', &['ð“µ']), + ('ð“Ž', &['ð“¶']), + ('ð“', &['ð“·']), + ('ð“', &['ð“¸']), + ('ð“‘', &['ð“¹']), + ('ð“’', &['ð“º']), + ('ð““', &['ð“»']), + ('ð“˜', &['ð’°']), + ('ð“™', &['ð’±']), + ('ð“š', &['ð’²']), + ('ð“›', &['ð’³']), + ('ð“œ', &['ð’´']), + ('ð“', &['ð’µ']), + ('ð“ž', &['ð’¶']), + ('ð“Ÿ', &['ð’·']), + ('ð“ ', &['ð’¸']), + ('ð“¡', &['ð’¹']), + ('ð“¢', &['ð’º']), + ('ð“£', &['ð’»']), + ('ð“¤', &['ð’¼']), + ('ð“¥', &['ð’½']), + ('ð“¦', &['ð’¾']), + ('ð“§', &['ð’¿']), + ('ð“¨', &['ð“€']), + ('ð“©', &['ð“']), + ('ð“ª', &['ð“‚']), + ('ð“«', &['ð“ƒ']), + ('ð“¬', &['ð“„']), + ('ð“­', &['ð“…']), + ('ð“®', &['ð“†']), + ('ð“¯', &['ð“‡']), + ('ð“°', &['ð“ˆ']), + ('ð“±', &['ð“‰']), + ('ð“²', &['ð“Š']), + ('ð“³', &['ð“‹']), + ('ð“´', &['ð“Œ']), + ('ð“µ', &['ð“']), + ('ð“¶', &['ð“Ž']), + ('ð“·', &['ð“']), + ('ð“¸', &['ð“']), + ('ð“¹', &['ð“‘']), + ('ð“º', &['ð“’']), + ('ð“»', &['ð““']), + ('ð•°', &['ð–—']), + ('ð•±', &['ð–˜']), + ('ð•²', &['ð–™']), + ('ð•³', &['ð–š']), + ('ð•´', &['ð–›']), + ('ð•µ', &['ð–œ']), + ('ð•¶', &['ð–']), + ('ð•·', &['ð–ž']), + ('ð•¸', &['ð–Ÿ']), + ('ð•¹', &['ð– ']), + ('ð•º', &['ð–¡']), + ('ð•¼', &['ð–£']), + ('ð•½', &['ð–¤']), + ('ð•¾', &['ð–¥']), + ('ð•¿', &['ð–¦']), + ('ð–€', &['ð–§']), + ('ð–', &['ð–¨']), + ('ð–‚', &['ð–©']), + ('ð–ƒ', &['ð–ª']), + ('ð–„', &['ð–«']), + ('ð–…', &['ð–¬']), + ('ð–†', &['ð–­']), + ('ð–‡', &['ð–®']), + ('ð–ˆ', &['ð–¯']), + ('ð–‰', &['ð–°']), + ('ð–Š', &['ð–±']), + ('ð–Œ', &['ð–³']), + ('ð–', &['ð–´']), + ('ð–Ž', &['ð–µ']), + ('ð–', &['ð–¶']), + ('ð–', &['ð–·']), + ('ð–‘', &['ð–¸']), + ('ð–’', &['ð–¹']), + ('ð–”', &['ð–»']), + ('ð–•', &['ð–¼']), + ('ð–—', &['ð•°']), + ('ð–˜', &['ð•±']), + ('ð–™', &['ð•²']), + ('ð–š', &['ð•³']), + ('ð–›', &['ð•´']), + ('ð–œ', &['ð•µ']), + ('ð–', &['ð•¶']), + ('ð–ž', &['ð•·']), + ('ð–Ÿ', &['ð•¸']), + ('ð– ', &['ð•¹']), + ('ð–¡', &['ð•º']), + ('ð–£', &['ð•¼']), + ('ð–¤', &['ð•½']), + ('ð–¥', &['ð•¾']), + ('ð–¦', &['ð•¿']), + ('ð–§', &['ð–€']), + ('ð–¨', &['ð–']), + ('ð–©', &['ð–‚']), + ('ð–ª', &['ð–ƒ']), + ('ð–«', &['ð–„']), + ('ð–¬', &['ð–…']), + ('ð–­', &['ð–†']), + ('ð–®', &['ð–‡']), + ('ð–¯', &['ð–ˆ']), + ('ð–°', &['ð–‰']), + ('ð–±', &['ð–Š']), + ('ð–³', &['ð–Œ']), + ('ð–´', &['ð–']), + ('ð–µ', &['ð–Ž']), + ('ð–¶', &['ð–']), + ('ð–·', &['ð–']), + ('ð–¸', &['ð–‘']), + ('ð–¹', &['ð–’']), + ('ð–»', &['ð–”']), + ('ð–¼', &['ð–•']), + ('ð²€', &['ð³€']), + ('ð²', &['ð³']), + ('ð²‚', &['ð³‚']), + ('ð²ƒ', &['ð³ƒ']), + ('ð²„', &['ð³„']), + ('ð²…', &['ð³…']), + ('ð²†', &['ð³†']), + ('ð²‡', &['ð³‡']), + ('ð²ˆ', &['ð³ˆ']), + ('ð²‰', &['ð³‰']), + ('ð²Š', &['ð³Š']), + ('ð²‹', &['ð³‹']), + ('ð²Œ', &['ð³Œ']), + ('ð²', &['ð³']), + ('ð²Ž', &['ð³Ž']), + ('ð²', &['ð³']), + ('ð²', &['ð³']), + ('ð²‘', &['ð³‘']), + ('ð²’', &['ð³’']), + ('ð²“', &['ð³“']), + ('ð²”', &['ð³”']), + ('ð²•', &['ð³•']), + ('ð²–', &['ð³–']), + ('ð²—', &['ð³—']), + ('ð²˜', &['ð³˜']), + ('ð²™', &['ð³™']), + ('ð²š', &['ð³š']), + ('ð²›', &['ð³›']), + ('ð²œ', &['ð³œ']), + ('ð²', &['ð³']), + ('ð²ž', &['ð³ž']), + ('ð²Ÿ', &['ð³Ÿ']), + ('ð² ', &['ð³ ']), + ('ð²¡', &['ð³¡']), + ('ð²¢', &['ð³¢']), + ('ð²£', &['ð³£']), + ('ð²¤', &['ð³¤']), + ('ð²¥', &['ð³¥']), + ('ð²¦', &['ð³¦']), + ('ð²§', &['ð³§']), + ('ð²¨', &['ð³¨']), + ('ð²©', &['ð³©']), + ('ð²ª', &['ð³ª']), + ('ð²«', &['ð³«']), + ('ð²¬', &['ð³¬']), + ('ð²­', &['ð³­']), + ('ð²®', &['ð³®']), + ('ð²¯', &['ð³¯']), + ('ð²°', &['ð³°']), + ('ð²±', &['ð³±']), + ('ð²²', &['ð³²']), + ('ð³€', &['ð²€']), + ('ð³', &['ð²']), + ('ð³‚', &['ð²‚']), + ('ð³ƒ', &['ð²ƒ']), + ('ð³„', &['ð²„']), + ('ð³…', &['ð²…']), + ('ð³†', &['ð²†']), + ('ð³‡', &['ð²‡']), + ('ð³ˆ', &['ð²ˆ']), + ('ð³‰', &['ð²‰']), + ('ð³Š', &['ð²Š']), + ('ð³‹', &['ð²‹']), + ('ð³Œ', &['ð²Œ']), + ('ð³', &['ð²']), + ('ð³Ž', &['ð²Ž']), + ('ð³', &['ð²']), + ('ð³', &['ð²']), + ('ð³‘', &['ð²‘']), + ('ð³’', &['ð²’']), + ('ð³“', &['ð²“']), + ('ð³”', &['ð²”']), + ('ð³•', &['ð²•']), + ('ð³–', &['ð²–']), + ('ð³—', &['ð²—']), + ('ð³˜', &['ð²˜']), + ('ð³™', &['ð²™']), + ('ð³š', &['ð²š']), + ('ð³›', &['ð²›']), + ('ð³œ', &['ð²œ']), + ('ð³', &['ð²']), + ('ð³ž', &['ð²ž']), + ('ð³Ÿ', &['ð²Ÿ']), + ('ð³ ', &['ð² ']), + ('ð³¡', &['ð²¡']), + ('ð³¢', &['ð²¢']), + ('ð³£', &['ð²£']), + ('ð³¤', &['ð²¤']), + ('ð³¥', &['ð²¥']), + ('ð³¦', &['ð²¦']), + ('ð³§', &['ð²§']), + ('ð³¨', &['ð²¨']), + ('ð³©', &['ð²©']), + ('ð³ª', &['ð²ª']), + ('ð³«', &['ð²«']), + ('ð³¬', &['ð²¬']), + ('ð³­', &['ð²­']), + ('ð³®', &['ð²®']), + ('ð³¯', &['ð²¯']), + ('ð³°', &['ð²°']), + ('ð³±', &['ð²±']), + ('ð³²', &['ð²²']), + ('ð‘¢ ', &['ð‘£€']), + ('𑢡', &['ð‘£']), + ('ð‘¢¢', &['𑣂']), + ('ð‘¢£', &['𑣃']), + ('𑢤', &['𑣄']), + ('ð‘¢¥', &['ð‘£…']), + ('𑢦', &['𑣆']), + ('𑢧', &['𑣇']), + ('𑢨', &['𑣈']), + ('𑢩', &['𑣉']), + ('𑢪', &['𑣊']), + ('𑢫', &['𑣋']), + ('𑢬', &['𑣌']), + ('ð‘¢­', &['ð‘£']), + ('ð‘¢®', &['𑣎']), + ('𑢯', &['ð‘£']), + ('ð‘¢°', &['ð‘£']), + ('ð‘¢±', &['𑣑']), + ('ð‘¢²', &['ð‘£’']), + ('ð‘¢³', &['𑣓']), + ('ð‘¢´', &['ð‘£”']), + ('ð‘¢µ', &['𑣕']), + ('𑢶', &['ð‘£–']), + ('ð‘¢·', &['ð‘£—']), + ('𑢸', &['𑣘']), + ('ð‘¢¹', &['ð‘£™']), + ('𑢺', &['𑣚']), + ('ð‘¢»', &['ð‘£›']), + ('ð‘¢¼', &['𑣜']), + ('ð‘¢½', &['ð‘£']), + ('ð‘¢¾', &['𑣞']), + ('𑢿', &['𑣟']), + ('ð‘£€', &['ð‘¢ ']), + ('ð‘£', &['𑢡']), + ('𑣂', &['ð‘¢¢']), + ('𑣃', &['ð‘¢£']), + ('𑣄', &['𑢤']), + ('ð‘£…', &['ð‘¢¥']), + ('𑣆', &['𑢦']), + ('𑣇', &['𑢧']), + ('𑣈', &['𑢨']), + ('𑣉', &['𑢩']), + ('𑣊', &['𑢪']), + ('𑣋', &['𑢫']), + ('𑣌', &['𑢬']), + ('ð‘£', &['ð‘¢­']), + ('𑣎', &['ð‘¢®']), + ('ð‘£', &['𑢯']), + ('ð‘£', &['ð‘¢°']), + ('𑣑', &['ð‘¢±']), + ('ð‘£’', &['ð‘¢²']), + ('𑣓', &['ð‘¢³']), + ('ð‘£”', &['ð‘¢´']), + ('𑣕', &['ð‘¢µ']), + ('ð‘£–', &['𑢶']), + ('ð‘£—', &['ð‘¢·']), + ('𑣘', &['𑢸']), + ('ð‘£™', &['ð‘¢¹']), + ('𑣚', &['𑢺']), + ('ð‘£›', &['ð‘¢»']), + ('𑣜', &['ð‘¢¼']), + ('ð‘£', &['ð‘¢½']), + ('𑣞', &['ð‘¢¾']), + ('𑣟', &['𑢿']), + ('ð–¹€', &['ð–¹ ']), + ('ð–¹', &['𖹡']), + ('𖹂', &['ð–¹¢']), + ('𖹃', &['ð–¹£']), + ('𖹄', &['𖹤']), + ('ð–¹…', &['ð–¹¥']), + ('𖹆', &['𖹦']), + ('𖹇', &['𖹧']), + ('𖹈', &['𖹨']), + ('𖹉', &['𖹩']), + ('𖹊', &['𖹪']), + ('𖹋', &['𖹫']), + ('𖹌', &['𖹬']), + ('ð–¹', &['ð–¹­']), + ('𖹎', &['ð–¹®']), + ('ð–¹', &['𖹯']), + ('ð–¹', &['ð–¹°']), + ('𖹑', &['ð–¹±']), + ('ð–¹’', &['ð–¹²']), + ('𖹓', &['ð–¹³']), + ('ð–¹”', &['ð–¹´']), + ('𖹕', &['ð–¹µ']), + ('ð–¹–', &['𖹶']), + ('ð–¹—', &['ð–¹·']), + ('𖹘', &['𖹸']), + ('ð–¹™', &['ð–¹¹']), + ('𖹚', &['𖹺']), + ('ð–¹›', &['ð–¹»']), + ('𖹜', &['ð–¹¼']), + ('ð–¹', &['ð–¹½']), + ('𖹞', &['ð–¹¾']), + ('𖹟', &['𖹿']), + ('ð–¹ ', &['ð–¹€']), + ('𖹡', &['ð–¹']), + ('ð–¹¢', &['𖹂']), + ('ð–¹£', &['𖹃']), + ('𖹤', &['𖹄']), + ('ð–¹¥', &['ð–¹…']), + ('𖹦', &['𖹆']), + ('𖹧', &['𖹇']), + ('𖹨', &['𖹈']), + ('𖹩', &['𖹉']), + ('𖹪', &['𖹊']), + ('𖹫', &['𖹋']), + ('𖹬', &['𖹌']), + ('ð–¹­', &['ð–¹']), + ('ð–¹®', &['𖹎']), + ('𖹯', &['ð–¹']), + ('ð–¹°', &['ð–¹']), + ('ð–¹±', &['𖹑']), + ('ð–¹²', &['ð–¹’']), + ('ð–¹³', &['𖹓']), + ('ð–¹´', &['ð–¹”']), + ('ð–¹µ', &['𖹕']), + ('𖹶', &['ð–¹–']), + ('ð–¹·', &['ð–¹—']), + ('𖹸', &['𖹘']), + ('ð–¹¹', &['ð–¹™']), + ('𖹺', &['𖹚']), + ('ð–¹»', &['ð–¹›']), + ('ð–¹¼', &['𖹜']), + ('ð–¹½', &['ð–¹']), + ('ð–¹¾', &['𖹞']), + ('𖹿', &['𖹟']), + ('𞤀', &['𞤢']), + ('ðž¤', &['𞤣']), + ('𞤂', &['𞤤']), + ('𞤃', &['𞤥']), + ('𞤄', &['𞤦']), + ('𞤅', &['𞤧']), + ('𞤆', &['𞤨']), + ('𞤇', &['𞤩']), + ('𞤈', &['𞤪']), + ('𞤉', &['𞤫']), + ('𞤊', &['𞤬']), + ('𞤋', &['𞤭']), + ('𞤌', &['𞤮']), + ('ðž¤', &['𞤯']), + ('𞤎', &['𞤰']), + ('ðž¤', &['𞤱']), + ('ðž¤', &['𞤲']), + ('𞤑', &['𞤳']), + ('𞤒', &['𞤴']), + ('𞤓', &['𞤵']), + ('𞤔', &['𞤶']), + ('𞤕', &['𞤷']), + ('𞤖', &['𞤸']), + ('𞤗', &['𞤹']), + ('𞤘', &['𞤺']), + ('𞤙', &['𞤻']), + ('𞤚', &['𞤼']), + ('𞤛', &['𞤽']), + ('𞤜', &['𞤾']), + ('ðž¤', &['𞤿']), + ('𞤞', &['𞥀']), + ('𞤟', &['ðž¥']), + ('𞤠', &['𞥂']), + ('𞤡', &['𞥃']), + ('𞤢', &['𞤀']), + ('𞤣', &['ðž¤']), + ('𞤤', &['𞤂']), + ('𞤥', &['𞤃']), + ('𞤦', &['𞤄']), + ('𞤧', &['𞤅']), + ('𞤨', &['𞤆']), + ('𞤩', &['𞤇']), + ('𞤪', &['𞤈']), + ('𞤫', &['𞤉']), + ('𞤬', &['𞤊']), + ('𞤭', &['𞤋']), + ('𞤮', &['𞤌']), + ('𞤯', &['ðž¤']), + ('𞤰', &['𞤎']), + ('𞤱', &['ðž¤']), + ('𞤲', &['ðž¤']), + ('𞤳', &['𞤑']), + ('𞤴', &['𞤒']), + ('𞤵', &['𞤓']), + ('𞤶', &['𞤔']), + ('𞤷', &['𞤕']), + ('𞤸', &['𞤖']), + ('𞤹', &['𞤗']), + ('𞤺', &['𞤘']), + ('𞤻', &['𞤙']), + ('𞤼', &['𞤚']), + ('𞤽', &['𞤛']), + ('𞤾', &['𞤜']), + ('𞤿', &['ðž¤']), + ('𞥀', &['𞤞']), + ('ðž¥', &['𞤟']), + ('𞥂', &['𞤠']), + ('𞥃', &['𞤡']), +]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/general_category.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/general_category.rs new file mode 100644 index 0000000000000..8fc92891279aa --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/general_category.rs @@ -0,0 +1,6552 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate general-category ucd-15.0.0 --chars --exclude surrogate +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("Cased_Letter", CASED_LETTER), + ("Close_Punctuation", CLOSE_PUNCTUATION), + ("Connector_Punctuation", CONNECTOR_PUNCTUATION), + ("Control", CONTROL), + ("Currency_Symbol", CURRENCY_SYMBOL), + ("Dash_Punctuation", DASH_PUNCTUATION), + ("Decimal_Number", DECIMAL_NUMBER), + ("Enclosing_Mark", ENCLOSING_MARK), + ("Final_Punctuation", FINAL_PUNCTUATION), + ("Format", FORMAT), + ("Initial_Punctuation", INITIAL_PUNCTUATION), + ("Letter", LETTER), + ("Letter_Number", LETTER_NUMBER), + ("Line_Separator", LINE_SEPARATOR), + ("Lowercase_Letter", LOWERCASE_LETTER), + ("Mark", MARK), + ("Math_Symbol", MATH_SYMBOL), + ("Modifier_Letter", MODIFIER_LETTER), + ("Modifier_Symbol", MODIFIER_SYMBOL), + ("Nonspacing_Mark", NONSPACING_MARK), + ("Number", NUMBER), + ("Open_Punctuation", OPEN_PUNCTUATION), + ("Other", OTHER), + ("Other_Letter", OTHER_LETTER), + ("Other_Number", OTHER_NUMBER), + ("Other_Punctuation", OTHER_PUNCTUATION), + ("Other_Symbol", OTHER_SYMBOL), + ("Paragraph_Separator", PARAGRAPH_SEPARATOR), + ("Private_Use", PRIVATE_USE), + ("Punctuation", PUNCTUATION), + ("Separator", SEPARATOR), + ("Space_Separator", SPACE_SEPARATOR), + ("Spacing_Mark", SPACING_MARK), + ("Symbol", SYMBOL), + ("Titlecase_Letter", TITLECASE_LETTER), + ("Unassigned", UNASSIGNED), + ("Uppercase_Letter", UPPERCASE_LETTER), +]; + +pub const CASED_LETTER: &'static [(char, char)] = &[ + ('A', 'Z'), + ('a', 'z'), + ('µ', 'µ'), + ('À', 'Ö'), + ('Ø', 'ö'), + ('ø', 'ƺ'), + ('Ƽ', 'Æ¿'), + ('Ç„', 'Ê“'), + ('Ê•', 'ʯ'), + ('Í°', 'ͳ'), + ('Ͷ', 'Í·'), + ('Í»', 'ͽ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'ϵ'), + ('Ï·', 'Ò'), + ('ÒŠ', 'Ô¯'), + ('Ô±', 'Õ–'), + ('Õ ', 'Öˆ'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ჺ'), + ('ჽ', 'ჿ'), + ('Ꭰ', 'áµ'), + ('á¸', 'á½'), + ('á²€', 'ᲈ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('á´€', 'á´«'), + ('ᵫ', 'áµ·'), + ('áµ¹', 'ᶚ'), + ('Ḁ', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¾¼'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'á¿Œ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), + ('ῶ', 'ῼ'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„Š', 'â„“'), + ('â„•', 'â„•'), + ('â„™', 'â„'), + ('ℤ', 'ℤ'), + ('Ω', 'Ω'), + ('ℨ', 'ℨ'), + ('K', 'â„­'), + ('ℯ', 'â„´'), + ('ℹ', 'ℹ'), + ('ℼ', 'â„¿'), + ('â……', 'â…‰'), + ('â…Ž', 'â…Ž'), + ('Ↄ', 'ↄ'), + ('â°€', 'â±»'), + ('â±¾', 'ⳤ'), + ('Ⳬ', 'â³®'), + ('â³²', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('Ꙁ', 'ê™­'), + ('Ꚁ', 'êš›'), + ('Ꜣ', 'ê¯'), + ('ê±', 'ꞇ'), + ('êž‹', 'ꞎ'), + ('êž', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('Ꟶ', 'ꟶ'), + ('ꟺ', 'ꟺ'), + ('ꬰ', 'ê­š'), + ('ê­ ', 'ê­¨'), + ('ê­°', 'ꮿ'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('A', 'Z'), + ('ï½', 'z'), + ('ð€', 'ð‘'), + ('ð’°', 'ð““'), + ('ð“˜', 'ð“»'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð²€', 'ð²²'), + ('ð³€', 'ð³²'), + ('ð‘¢ ', '𑣟'), + ('ð–¹€', '𖹿'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ð›€'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›º'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ´'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð®'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž¨'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‹'), + ('ð¼€', 'ð¼‰'), + ('ð¼‹', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('𞤀', '𞥃'), +]; + +pub const CLOSE_PUNCTUATION: &'static [(char, char)] = &[ + (')', ')'), + (']', ']'), + ('}', '}'), + ('༻', '༻'), + ('༽', '༽'), + ('ášœ', 'ášœ'), + ('â†', 'â†'), + ('â¾', 'â¾'), + ('â‚Ž', 'â‚Ž'), + ('⌉', '⌉'), + ('⌋', '⌋'), + ('〉', '〉'), + ('â©', 'â©'), + ('â«', 'â«'), + ('â­', 'â­'), + ('â¯', 'â¯'), + ('â±', 'â±'), + ('â³', 'â³'), + ('âµ', 'âµ'), + ('⟆', '⟆'), + ('⟧', '⟧'), + ('⟩', '⟩'), + ('⟫', '⟫'), + ('⟭', '⟭'), + ('⟯', '⟯'), + ('⦄', '⦄'), + ('⦆', '⦆'), + ('⦈', '⦈'), + ('⦊', '⦊'), + ('⦌', '⦌'), + ('⦎', '⦎'), + ('â¦', 'â¦'), + ('⦒', '⦒'), + ('⦔', '⦔'), + ('⦖', '⦖'), + ('⦘', '⦘'), + ('⧙', '⧙'), + ('⧛', '⧛'), + ('⧽', '⧽'), + ('⸣', '⸣'), + ('⸥', '⸥'), + ('⸧', '⸧'), + ('⸩', '⸩'), + ('â¹–', 'â¹–'), + ('⹘', '⹘'), + ('⹚', '⹚'), + ('⹜', '⹜'), + ('〉', '〉'), + ('》', '》'), + ('ã€', 'ã€'), + ('ã€', 'ã€'), + ('】', '】'), + ('〕', '〕'), + ('〗', '〗'), + ('〙', '〙'), + ('〛', '〛'), + ('〞', '〟'), + ('ï´¾', 'ï´¾'), + ('︘', '︘'), + ('︶', '︶'), + ('︸', '︸'), + ('︺', '︺'), + ('︼', '︼'), + ('︾', '︾'), + ('ï¹€', 'ï¹€'), + ('﹂', '﹂'), + ('﹄', '﹄'), + ('﹈', '﹈'), + ('﹚', '﹚'), + ('﹜', '﹜'), + ('﹞', '﹞'), + (')', ')'), + ('ï¼½', 'ï¼½'), + ('ï½', 'ï½'), + ('ï½ ', 'ï½ '), + ('ï½£', 'ï½£'), +]; + +pub const CONNECTOR_PUNCTUATION: &'static [(char, char)] = &[ + ('_', '_'), + ('‿', 'â€'), + ('â”', 'â”'), + ('︳', '︴'), + ('ï¹', 'ï¹'), + ('_', '_'), +]; + +pub const CONTROL: &'static [(char, char)] = + &[('\0', '\u{1f}'), ('\u{7f}', '\u{9f}')]; + +pub const CURRENCY_SYMBOL: &'static [(char, char)] = &[ + ('$', '$'), + ('¢', 'Â¥'), + ('Ö', 'Ö'), + ('Ø‹', 'Ø‹'), + ('ß¾', 'ß¿'), + ('৲', '৳'), + ('৻', '৻'), + ('૱', '૱'), + ('௹', '௹'), + ('฿', '฿'), + ('៛', '៛'), + ('â‚ ', '⃀'), + ('ê ¸', 'ê ¸'), + ('ï·¼', 'ï·¼'), + ('﹩', '﹩'), + ('$', '$'), + ('ï¿ ', 'ï¿¡'), + ('ï¿¥', '₩'), + ('ð‘¿', 'ð‘¿ '), + ('ðž‹¿', 'ðž‹¿'), + ('ðž²°', 'ðž²°'), +]; + +pub const DASH_PUNCTUATION: &'static [(char, char)] = &[ + ('-', '-'), + ('ÖŠ', 'ÖŠ'), + ('Ö¾', 'Ö¾'), + ('á€', 'á€'), + ('á †', 'á †'), + ('â€', '―'), + ('⸗', '⸗'), + ('⸚', '⸚'), + ('⸺', '⸻'), + ('â¹€', 'â¹€'), + ('â¹', 'â¹'), + ('〜', '〜'), + ('〰', '〰'), + ('ã‚ ', 'ã‚ '), + ('︱', '︲'), + ('﹘', '﹘'), + ('ï¹£', 'ï¹£'), + ('ï¼', 'ï¼'), + ('ðº­', 'ðº­'), +]; + +pub const DECIMAL_NUMBER: &'static [(char, char)] = &[ + ('0', '9'), + ('Ù ', 'Ù©'), + ('Û°', 'Û¹'), + ('߀', '߉'), + ('०', '९'), + ('০', '৯'), + ('੦', '੯'), + ('૦', '૯'), + ('à­¦', 'à­¯'), + ('௦', '௯'), + ('౦', '౯'), + ('೦', '೯'), + ('൦', '൯'), + ('à·¦', 'à·¯'), + ('à¹', '๙'), + ('à»', 'à»™'), + ('༠', '༩'), + ('á€', 'á‰'), + ('á‚', 'á‚™'), + ('០', '៩'), + ('á ', 'á ™'), + ('᥆', 'á¥'), + ('á§', '᧙'), + ('᪀', '᪉'), + ('áª', '᪙'), + ('á­', 'á­™'), + ('á®°', '᮹'), + ('á±€', '᱉'), + ('á±', 'á±™'), + ('꘠', '꘩'), + ('ê£', '꣙'), + ('꤀', '꤉'), + ('ê§', '꧙'), + ('꧰', '꧹'), + ('ê©', 'ê©™'), + ('꯰', '꯹'), + ('ï¼', 'ï¼™'), + ('ð’ ', 'ð’©'), + ('ð´°', 'ð´¹'), + ('ð‘¦', 'ð‘¯'), + ('𑃰', '𑃹'), + ('𑄶', 'ð‘„¿'), + ('ð‘‡', '𑇙'), + ('ð‘‹°', 'ð‘‹¹'), + ('ð‘‘', 'ð‘‘™'), + ('ð‘“', 'ð‘“™'), + ('ð‘™', 'ð‘™™'), + ('𑛀', '𑛉'), + ('𑜰', '𑜹'), + ('ð‘£ ', '𑣩'), + ('ð‘¥', 'ð‘¥™'), + ('ð‘±', '𑱙'), + ('ð‘µ', '𑵙'), + ('𑶠', '𑶩'), + ('ð‘½', '𑽙'), + ('ð–© ', 'ð–©©'), + ('ð–«€', '𖫉'), + ('ð–­', 'ð–­™'), + ('ðŸŽ', 'ðŸ¿'), + ('ðž…€', 'ðž…‰'), + ('ðž‹°', '𞋹'), + ('ðž“°', '𞓹'), + ('ðž¥', '𞥙'), + ('🯰', '🯹'), +]; + +pub const ENCLOSING_MARK: &'static [(char, char)] = &[ + ('\u{488}', '\u{489}'), + ('\u{1abe}', '\u{1abe}'), + ('\u{20dd}', '\u{20e0}'), + ('\u{20e2}', '\u{20e4}'), + ('\u{a670}', '\u{a672}'), +]; + +pub const FINAL_PUNCTUATION: &'static [(char, char)] = &[ + ('»', '»'), + ('’', '’'), + ('â€', 'â€'), + ('›', '›'), + ('⸃', '⸃'), + ('⸅', '⸅'), + ('⸊', '⸊'), + ('â¸', 'â¸'), + ('â¸', 'â¸'), + ('⸡', '⸡'), +]; + +pub const FORMAT: &'static [(char, char)] = &[ + ('\u{ad}', '\u{ad}'), + ('\u{600}', '\u{605}'), + ('\u{61c}', '\u{61c}'), + ('\u{6dd}', '\u{6dd}'), + ('\u{70f}', '\u{70f}'), + ('\u{890}', '\u{891}'), + ('\u{8e2}', '\u{8e2}'), + ('\u{180e}', '\u{180e}'), + ('\u{200b}', '\u{200f}'), + ('\u{202a}', '\u{202e}'), + ('\u{2060}', '\u{2064}'), + ('\u{2066}', '\u{206f}'), + ('\u{feff}', '\u{feff}'), + ('\u{fff9}', '\u{fffb}'), + ('\u{110bd}', '\u{110bd}'), + ('\u{110cd}', '\u{110cd}'), + ('\u{13430}', '\u{1343f}'), + ('\u{1bca0}', '\u{1bca3}'), + ('\u{1d173}', '\u{1d17a}'), + ('\u{e0001}', '\u{e0001}'), + ('\u{e0020}', '\u{e007f}'), +]; + +pub const INITIAL_PUNCTUATION: &'static [(char, char)] = &[ + ('«', '«'), + ('‘', '‘'), + ('‛', '“'), + ('‟', '‟'), + ('‹', '‹'), + ('⸂', '⸂'), + ('⸄', '⸄'), + ('⸉', '⸉'), + ('⸌', '⸌'), + ('⸜', '⸜'), + ('⸠', '⸠'), +]; + +pub const LETTER: &'static [(char, char)] = &[ + ('A', 'Z'), + ('a', 'z'), + ('ª', 'ª'), + ('µ', 'µ'), + ('º', 'º'), + ('À', 'Ö'), + ('Ø', 'ö'), + ('ø', 'Ë'), + ('ˆ', 'Ë‘'), + ('Ë ', 'ˤ'), + ('ˬ', 'ˬ'), + ('Ë®', 'Ë®'), + ('Í°', 'Í´'), + ('Ͷ', 'Í·'), + ('ͺ', 'ͽ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'ϵ'), + ('Ï·', 'Ò'), + ('ÒŠ', 'Ô¯'), + ('Ô±', 'Õ–'), + ('Õ™', 'Õ™'), + ('Õ ', 'Öˆ'), + ('×', 'ת'), + ('ׯ', 'ײ'), + ('Ø ', 'ÙŠ'), + ('Ù®', 'Ù¯'), + ('Ù±', 'Û“'), + ('Û•', 'Û•'), + ('Û¥', 'Û¦'), + ('Û®', 'Û¯'), + ('Ûº', 'Û¼'), + ('Û¿', 'Û¿'), + ('Ü', 'Ü'), + ('Ü’', 'ܯ'), + ('Ý', 'Þ¥'), + ('Þ±', 'Þ±'), + ('ߊ', 'ߪ'), + ('ß´', 'ßµ'), + ('ߺ', 'ߺ'), + ('à €', 'à •'), + ('à š', 'à š'), + ('à ¤', 'à ¤'), + ('à ¨', 'à ¨'), + ('à¡€', 'ࡘ'), + ('à¡ ', 'ࡪ'), + ('à¡°', 'ࢇ'), + ('ࢉ', 'ࢎ'), + ('ࢠ', 'ࣉ'), + ('ऄ', 'ह'), + ('ऽ', 'ऽ'), + ('à¥', 'à¥'), + ('क़', 'ॡ'), + ('ॱ', 'ঀ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('ঽ', 'ঽ'), + ('ৎ', 'ৎ'), + ('ড়', 'à§'), + ('য়', 'ৡ'), + ('ৰ', 'ৱ'), + ('ৼ', 'ৼ'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('ੲ', 'à©´'), + ('અ', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('ઽ', 'ઽ'), + ('à«', 'à«'), + ('à« ', 'à«¡'), + ('ૹ', 'ૹ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), + ('ଽ', 'ଽ'), + ('à­œ', 'à­'), + ('à­Ÿ', 'à­¡'), + ('à­±', 'à­±'), + ('ஃ', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'ஹ'), + ('à¯', 'à¯'), + ('à°…', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°¹'), + ('à°½', 'à°½'), + ('ౘ', 'ౚ'), + ('à±', 'à±'), + ('à± ', 'ౡ'), + ('ಀ', 'ಀ'), + ('ಅ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('ಽ', 'ಽ'), + ('à³', 'ೞ'), + ('à³ ', 'ೡ'), + ('à³±', 'à³²'), + ('à´„', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', 'à´º'), + ('à´½', 'à´½'), + ('ൎ', 'ൎ'), + ('ൔ', 'ൖ'), + ('ൟ', 'ൡ'), + ('ൺ', 'ൿ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('à¸', 'ะ'), + ('า', 'ำ'), + ('เ', 'ๆ'), + ('àº', 'ຂ'), + ('ຄ', 'ຄ'), + ('ຆ', 'ຊ'), + ('ຌ', 'ຣ'), + ('ລ', 'ລ'), + ('ວ', 'ະ'), + ('າ', 'ຳ'), + ('ຽ', 'ຽ'), + ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), + ('ໜ', 'ໟ'), + ('ༀ', 'ༀ'), + ('ཀ', 'ཇ'), + ('ཉ', 'ཬ'), + ('ྈ', 'ྌ'), + ('က', 'ဪ'), + ('ဿ', 'ဿ'), + ('á', 'á•'), + ('áš', 'á'), + ('á¡', 'á¡'), + ('á¥', 'á¦'), + ('á®', 'á°'), + ('áµ', 'á‚'), + ('á‚Ž', 'á‚Ž'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ჺ'), + ('ჼ', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹–'), + ('ዘ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'áš'), + ('ᎀ', 'áŽ'), + ('Ꭰ', 'áµ'), + ('á¸', 'á½'), + ('á', 'ᙬ'), + ('ᙯ', 'ᙿ'), + ('áš', 'ášš'), + ('áš ', 'ᛪ'), + ('á›±', 'ᛸ'), + ('ᜀ', 'ᜑ'), + ('ᜟ', 'ᜱ'), + ('á€', 'á‘'), + ('á ', 'á¬'), + ('á®', 'á°'), + ('ក', 'áž³'), + ('ៗ', 'ៗ'), + ('ៜ', 'ៜ'), + ('á  ', 'ᡸ'), + ('ᢀ', 'ᢄ'), + ('ᢇ', 'ᢨ'), + ('ᢪ', 'ᢪ'), + ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), + ('á¥', 'ᥭ'), + ('ᥰ', 'ᥴ'), + ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), + ('ᨀ', 'ᨖ'), + ('ᨠ', 'á©”'), + ('ᪧ', 'ᪧ'), + ('ᬅ', 'ᬳ'), + ('á­…', 'á­Œ'), + ('ᮃ', 'á® '), + ('á®®', 'ᮯ'), + ('ᮺ', 'ᯥ'), + ('á°€', 'á°£'), + ('á±', 'á±'), + ('ᱚ', 'á±½'), + ('á²€', 'ᲈ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('ᳩ', 'ᳬ'), + ('á³®', 'á³³'), + ('á³µ', 'ᳶ'), + ('ᳺ', 'ᳺ'), + ('á´€', 'ᶿ'), + ('Ḁ', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¾¼'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'á¿Œ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), + ('ῶ', 'ῼ'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„Š', 'â„“'), + ('â„•', 'â„•'), + ('â„™', 'â„'), + ('ℤ', 'ℤ'), + ('Ω', 'Ω'), + ('ℨ', 'ℨ'), + ('K', 'â„­'), + ('ℯ', 'ℹ'), + ('ℼ', 'â„¿'), + ('â……', 'â…‰'), + ('â…Ž', 'â…Ž'), + ('Ↄ', 'ↄ'), + ('â°€', 'ⳤ'), + ('Ⳬ', 'â³®'), + ('â³²', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('â´°', 'ⵧ'), + ('ⵯ', 'ⵯ'), + ('ⶀ', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('ⸯ', 'ⸯ'), + ('々', '〆'), + ('〱', '〵'), + ('〻', '〼'), + ('ã', 'ã‚–'), + ('ã‚', 'ã‚Ÿ'), + ('ã‚¡', 'ヺ'), + ('ー', 'ヿ'), + ('ã„…', 'ㄯ'), + ('ㄱ', 'ㆎ'), + ('ㆠ', 'ㆿ'), + ('ㇰ', 'ㇿ'), + ('ã€', '䶿'), + ('一', 'ê’Œ'), + ('ê“', 'ꓽ'), + ('ꔀ', 'ꘌ'), + ('ê˜', 'ꘟ'), + ('ꘪ', 'ꘫ'), + ('Ꙁ', 'ê™®'), + ('ꙿ', 'êš'), + ('êš ', 'ꛥ'), + ('ꜗ', 'ꜟ'), + ('Ꜣ', 'ꞈ'), + ('êž‹', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('ꟲ', 'ê '), + ('ê ƒ', 'ê …'), + ('ê ‡', 'ê Š'), + ('ê Œ', 'ê ¢'), + ('ê¡€', 'ꡳ'), + ('ꢂ', 'ꢳ'), + ('ꣲ', 'ꣷ'), + ('ꣻ', 'ꣻ'), + ('ꣽ', 'ꣾ'), + ('ꤊ', 'ꤥ'), + ('ꤰ', 'ꥆ'), + ('ꥠ', 'ꥼ'), + ('ꦄ', 'ꦲ'), + ('ê§', 'ê§'), + ('ꧠ', 'ꧤ'), + ('ꧦ', 'ꧯ'), + ('ꧺ', 'ꧾ'), + ('ꨀ', 'ꨨ'), + ('ê©€', 'ê©‚'), + ('ê©„', 'ê©‹'), + ('ê© ', 'ꩶ'), + ('ꩺ', 'ꩺ'), + ('ꩾ', 'ꪯ'), + ('ꪱ', 'ꪱ'), + ('ꪵ', 'ꪶ'), + ('ꪹ', 'ꪽ'), + ('ê«€', 'ê«€'), + ('ê«‚', 'ê«‚'), + ('ê«›', 'ê«'), + ('ê« ', 'ꫪ'), + ('ꫲ', 'ê«´'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('ꬰ', 'ê­š'), + ('ê­œ', 'ê­©'), + ('ê­°', 'ꯢ'), + ('ê°€', '힣'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), + ('ï©°', 'ï«™'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï¬', 'ï¬'), + ('ײַ', 'ﬨ'), + ('שׁ', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', 'ï®±'), + ('ﯓ', 'ï´½'), + ('ïµ', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·°', 'ï·»'), + ('ï¹°', 'ï¹´'), + ('ﹶ', 'ﻼ'), + ('A', 'Z'), + ('ï½', 'z'), + ('ヲ', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), + ('ðŠ€', 'ðŠœ'), + ('ðŠ ', 'ð‹'), + ('ðŒ€', 'ðŒŸ'), + ('ðŒ­', 'ð€'), + ('ð‚', 'ð‰'), + ('ð', 'ðµ'), + ('ðŽ€', 'ðŽ'), + ('ðŽ ', 'ðƒ'), + ('ðˆ', 'ð'), + ('ð€', 'ð’'), + ('ð’°', 'ð““'), + ('ð“˜', 'ð“»'), + ('ð”€', 'ð”§'), + ('ð”°', 'ð•£'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð˜€', 'ðœ¶'), + ('ð€', 'ð•'), + ('ð ', 'ð§'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð €', 'ð …'), + ('ð ˆ', 'ð ˆ'), + ('ð Š', 'ð µ'), + ('ð ·', 'ð ¸'), + ('ð ¼', 'ð ¼'), + ('ð ¿', 'ð¡•'), + ('ð¡ ', 'ð¡¶'), + ('ð¢€', 'ð¢ž'), + ('ð£ ', 'ð£²'), + ('ð£´', 'ð£µ'), + ('ð¤€', 'ð¤•'), + ('ð¤ ', 'ð¤¹'), + ('ð¦€', 'ð¦·'), + ('ð¦¾', 'ð¦¿'), + ('ð¨€', 'ð¨€'), + ('ð¨', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨µ'), + ('ð© ', 'ð©¼'), + ('ðª€', 'ðªœ'), + ('ð«€', 'ð«‡'), + ('ð«‰', 'ð«¤'), + ('ð¬€', 'ð¬µ'), + ('ð­€', 'ð­•'), + ('ð­ ', 'ð­²'), + ('ð®€', 'ð®‘'), + ('ð°€', 'ð±ˆ'), + ('ð²€', 'ð²²'), + ('ð³€', 'ð³²'), + ('ð´€', 'ð´£'), + ('ðº€', 'ðº©'), + ('ðº°', 'ðº±'), + ('ð¼€', 'ð¼œ'), + ('ð¼§', 'ð¼§'), + ('ð¼°', 'ð½…'), + ('ð½°', 'ð¾'), + ('ð¾°', 'ð¿„'), + ('ð¿ ', 'ð¿¶'), + ('𑀃', 'ð‘€·'), + ('ð‘±', 'ð‘²'), + ('ð‘µ', 'ð‘µ'), + ('𑂃', '𑂯'), + ('ð‘ƒ', '𑃨'), + ('𑄃', '𑄦'), + ('ð‘…„', 'ð‘…„'), + ('ð‘…‡', 'ð‘…‡'), + ('ð‘…', 'ð‘…²'), + ('ð‘…¶', 'ð‘…¶'), + ('𑆃', '𑆲'), + ('ð‘‡', '𑇄'), + ('𑇚', '𑇚'), + ('𑇜', '𑇜'), + ('𑈀', '𑈑'), + ('𑈓', '𑈫'), + ('𑈿', '𑉀'), + ('ð‘Š€', '𑊆'), + ('𑊈', '𑊈'), + ('ð‘ŠŠ', 'ð‘Š'), + ('ð‘Š', 'ð‘Š'), + ('ð‘ŠŸ', '𑊨'), + ('ð‘Š°', 'ð‘‹ž'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('𑌽', '𑌽'), + ('ð‘', 'ð‘'), + ('ð‘', 'ð‘¡'), + ('ð‘€', 'ð‘´'), + ('𑑇', 'ð‘‘Š'), + ('ð‘‘Ÿ', 'ð‘‘¡'), + ('ð‘’€', 'ð‘’¯'), + ('ð‘“„', 'ð‘“…'), + ('𑓇', '𑓇'), + ('ð‘–€', 'ð‘–®'), + ('ð‘—˜', 'ð‘—›'), + ('𑘀', '𑘯'), + ('ð‘™„', 'ð‘™„'), + ('𑚀', '𑚪'), + ('𑚸', '𑚸'), + ('𑜀', '𑜚'), + ('ð‘€', 'ð‘†'), + ('ð‘ €', 'ð‘ «'), + ('ð‘¢ ', '𑣟'), + ('𑣿', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤯'), + ('𑤿', '𑤿'), + ('ð‘¥', 'ð‘¥'), + ('𑦠', '𑦧'), + ('𑦪', 'ð‘§'), + ('𑧡', '𑧡'), + ('𑧣', '𑧣'), + ('𑨀', '𑨀'), + ('𑨋', '𑨲'), + ('𑨺', '𑨺'), + ('ð‘©', 'ð‘©'), + ('ð‘©œ', '𑪉'), + ('ð‘ª', 'ð‘ª'), + ('𑪰', '𑫸'), + ('ð‘°€', 'ð‘°ˆ'), + ('ð‘°Š', 'ð‘°®'), + ('𑱀', '𑱀'), + ('𑱲', 'ð‘²'), + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', 'ð‘´°'), + ('𑵆', '𑵆'), + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶉'), + ('𑶘', '𑶘'), + ('ð‘» ', 'ð‘»²'), + ('𑼂', '𑼂'), + ('𑼄', 'ð‘¼'), + ('𑼒', '𑼳'), + ('𑾰', '𑾰'), + ('ð’€€', 'ð’Ž™'), + ('ð’’€', '𒕃'), + ('ð’¾', 'ð’¿°'), + ('ð“€€', 'ð“¯'), + ('ð“‘', '𓑆'), + ('ð”€', '𔙆'), + ('ð– €', '𖨸'), + ('ð–©€', 'ð–©ž'), + ('ð–©°', '𖪾'), + ('ð–«', 'ð–«­'), + ('𖬀', '𖬯'), + ('ð–­€', 'ð–­ƒ'), + ('ð–­£', 'ð–­·'), + ('ð–­½', 'ð–®'), + ('ð–¹€', '𖹿'), + ('ð–¼€', '𖽊'), + ('ð–½', 'ð–½'), + ('𖾓', '𖾟'), + ('ð–¿ ', 'ð–¿¡'), + ('ð–¿£', 'ð–¿£'), + ('ð—€€', '𘟷'), + ('𘠀', '𘳕'), + ('𘴀', '𘴈'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𛀀', '𛄢'), + ('𛄲', '𛄲'), + ('ð›…', 'ð›…’'), + ('ð›…•', 'ð›…•'), + ('ð›…¤', 'ð›…§'), + ('ð›…°', '𛋻'), + ('ð›°€', '𛱪'), + ('ð›±°', 'ð›±¼'), + ('𛲀', '𛲈'), + ('ð›²', '𛲙'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ð›€'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›º'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ´'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð®'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž¨'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‹'), + ('ð¼€', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('𞀰', 'ðž­'), + ('ðž„€', '𞄬'), + ('ðž„·', '𞄽'), + ('ðž…Ž', 'ðž…Ž'), + ('ðžŠ', '𞊭'), + ('ðž‹€', 'ðž‹«'), + ('ðž“', 'ðž“«'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), + ('ðž €', '𞣄'), + ('𞤀', '𞥃'), + ('𞥋', '𞥋'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('丽', 'ð¯¨'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), +]; + +pub const LETTER_NUMBER: &'static [(char, char)] = &[ + ('á›®', 'á›°'), + ('â… ', 'ↂ'), + ('ↅ', 'ↈ'), + ('〇', '〇'), + ('〡', '〩'), + ('〸', '〺'), + ('ꛦ', 'ꛯ'), + ('ð…€', 'ð…´'), + ('ð', 'ð'), + ('ðŠ', 'ðŠ'), + ('ð‘', 'ð•'), + ('ð’€', 'ð’‘®'), +]; + +pub const LINE_SEPARATOR: &'static [(char, char)] = + &[('\u{2028}', '\u{2028}')]; + +pub const LOWERCASE_LETTER: &'static [(char, char)] = &[ + ('a', 'z'), + ('µ', 'µ'), + ('ß', 'ö'), + ('ø', 'ÿ'), + ('Ä', 'Ä'), + ('ă', 'ă'), + ('Ä…', 'Ä…'), + ('ć', 'ć'), + ('ĉ', 'ĉ'), + ('Ä‹', 'Ä‹'), + ('Ä', 'Ä'), + ('Ä', 'Ä'), + ('Ä‘', 'Ä‘'), + ('Ä“', 'Ä“'), + ('Ä•', 'Ä•'), + ('Ä—', 'Ä—'), + ('Ä™', 'Ä™'), + ('Ä›', 'Ä›'), + ('Ä', 'Ä'), + ('ÄŸ', 'ÄŸ'), + ('Ä¡', 'Ä¡'), + ('Ä£', 'Ä£'), + ('Ä¥', 'Ä¥'), + ('ħ', 'ħ'), + ('Ä©', 'Ä©'), + ('Ä«', 'Ä«'), + ('Ä­', 'Ä­'), + ('į', 'į'), + ('ı', 'ı'), + ('ij', 'ij'), + ('ĵ', 'ĵ'), + ('Ä·', 'ĸ'), + ('ĺ', 'ĺ'), + ('ļ', 'ļ'), + ('ľ', 'ľ'), + ('Å€', 'Å€'), + ('Å‚', 'Å‚'), + ('Å„', 'Å„'), + ('ņ', 'ņ'), + ('ň', 'ʼn'), + ('Å‹', 'Å‹'), + ('Å', 'Å'), + ('Å', 'Å'), + ('Å‘', 'Å‘'), + ('Å“', 'Å“'), + ('Å•', 'Å•'), + ('Å—', 'Å—'), + ('Å™', 'Å™'), + ('Å›', 'Å›'), + ('Å', 'Å'), + ('ÅŸ', 'ÅŸ'), + ('Å¡', 'Å¡'), + ('Å£', 'Å£'), + ('Å¥', 'Å¥'), + ('ŧ', 'ŧ'), + ('Å©', 'Å©'), + ('Å«', 'Å«'), + ('Å­', 'Å­'), + ('ů', 'ů'), + ('ű', 'ű'), + ('ų', 'ų'), + ('ŵ', 'ŵ'), + ('Å·', 'Å·'), + ('ź', 'ź'), + ('ż', 'ż'), + ('ž', 'Æ€'), + ('ƃ', 'ƃ'), + ('Æ…', 'Æ…'), + ('ƈ', 'ƈ'), + ('ÆŒ', 'Æ'), + ('Æ’', 'Æ’'), + ('Æ•', 'Æ•'), + ('Æ™', 'Æ›'), + ('Æž', 'Æž'), + ('Æ¡', 'Æ¡'), + ('Æ£', 'Æ£'), + ('Æ¥', 'Æ¥'), + ('ƨ', 'ƨ'), + ('ƪ', 'Æ«'), + ('Æ­', 'Æ­'), + ('Æ°', 'Æ°'), + ('Æ´', 'Æ´'), + ('ƶ', 'ƶ'), + ('ƹ', 'ƺ'), + ('ƽ', 'Æ¿'), + ('dž', 'dž'), + ('lj', 'lj'), + ('ÇŒ', 'ÇŒ'), + ('ÇŽ', 'ÇŽ'), + ('Ç', 'Ç'), + ('Ç’', 'Ç’'), + ('Ç”', 'Ç”'), + ('Ç–', 'Ç–'), + ('ǘ', 'ǘ'), + ('Çš', 'Çš'), + ('Çœ', 'Ç'), + ('ÇŸ', 'ÇŸ'), + ('Ç¡', 'Ç¡'), + ('Ç£', 'Ç£'), + ('Ç¥', 'Ç¥'), + ('ǧ', 'ǧ'), + ('Ç©', 'Ç©'), + ('Ç«', 'Ç«'), + ('Ç­', 'Ç­'), + ('ǯ', 'Ç°'), + ('dz', 'dz'), + ('ǵ', 'ǵ'), + ('ǹ', 'ǹ'), + ('Ç»', 'Ç»'), + ('ǽ', 'ǽ'), + ('Ç¿', 'Ç¿'), + ('È', 'È'), + ('ȃ', 'ȃ'), + ('È…', 'È…'), + ('ȇ', 'ȇ'), + ('ȉ', 'ȉ'), + ('È‹', 'È‹'), + ('È', 'È'), + ('È', 'È'), + ('È‘', 'È‘'), + ('È“', 'È“'), + ('È•', 'È•'), + ('È—', 'È—'), + ('È™', 'È™'), + ('È›', 'È›'), + ('È', 'È'), + ('ÈŸ', 'ÈŸ'), + ('È¡', 'È¡'), + ('È£', 'È£'), + ('È¥', 'È¥'), + ('ȧ', 'ȧ'), + ('È©', 'È©'), + ('È«', 'È«'), + ('È­', 'È­'), + ('ȯ', 'ȯ'), + ('ȱ', 'ȱ'), + ('ȳ', 'ȹ'), + ('ȼ', 'ȼ'), + ('È¿', 'É€'), + ('É‚', 'É‚'), + ('ɇ', 'ɇ'), + ('ɉ', 'ɉ'), + ('É‹', 'É‹'), + ('É', 'É'), + ('É', 'Ê“'), + ('Ê•', 'ʯ'), + ('ͱ', 'ͱ'), + ('ͳ', 'ͳ'), + ('Í·', 'Í·'), + ('Í»', 'ͽ'), + ('Î', 'Î'), + ('ά', 'ÏŽ'), + ('Ï', 'Ï‘'), + ('Ï•', 'Ï—'), + ('Ï™', 'Ï™'), + ('Ï›', 'Ï›'), + ('Ï', 'Ï'), + ('ÏŸ', 'ÏŸ'), + ('Ï¡', 'Ï¡'), + ('Ï£', 'Ï£'), + ('Ï¥', 'Ï¥'), + ('ϧ', 'ϧ'), + ('Ï©', 'Ï©'), + ('Ï«', 'Ï«'), + ('Ï­', 'Ï­'), + ('ϯ', 'ϳ'), + ('ϵ', 'ϵ'), + ('ϸ', 'ϸ'), + ('Ï»', 'ϼ'), + ('а', 'ÑŸ'), + ('Ñ¡', 'Ñ¡'), + ('Ñ£', 'Ñ£'), + ('Ñ¥', 'Ñ¥'), + ('ѧ', 'ѧ'), + ('Ñ©', 'Ñ©'), + ('Ñ«', 'Ñ«'), + ('Ñ­', 'Ñ­'), + ('ѯ', 'ѯ'), + ('ѱ', 'ѱ'), + ('ѳ', 'ѳ'), + ('ѵ', 'ѵ'), + ('Ñ·', 'Ñ·'), + ('ѹ', 'ѹ'), + ('Ñ»', 'Ñ»'), + ('ѽ', 'ѽ'), + ('Ñ¿', 'Ñ¿'), + ('Ò', 'Ò'), + ('Ò‹', 'Ò‹'), + ('Ò', 'Ò'), + ('Ò', 'Ò'), + ('Ò‘', 'Ò‘'), + ('Ò“', 'Ò“'), + ('Ò•', 'Ò•'), + ('Ò—', 'Ò—'), + ('Ò™', 'Ò™'), + ('Ò›', 'Ò›'), + ('Ò', 'Ò'), + ('ÒŸ', 'ÒŸ'), + ('Ò¡', 'Ò¡'), + ('Ò£', 'Ò£'), + ('Ò¥', 'Ò¥'), + ('Ò§', 'Ò§'), + ('Ò©', 'Ò©'), + ('Ò«', 'Ò«'), + ('Ò­', 'Ò­'), + ('Ò¯', 'Ò¯'), + ('Ò±', 'Ò±'), + ('Ò³', 'Ò³'), + ('Òµ', 'Òµ'), + ('Ò·', 'Ò·'), + ('Ò¹', 'Ò¹'), + ('Ò»', 'Ò»'), + ('Ò½', 'Ò½'), + ('Ò¿', 'Ò¿'), + ('Ó‚', 'Ó‚'), + ('Ó„', 'Ó„'), + ('Ó†', 'Ó†'), + ('Óˆ', 'Óˆ'), + ('ÓŠ', 'ÓŠ'), + ('ÓŒ', 'ÓŒ'), + ('ÓŽ', 'Ó'), + ('Ó‘', 'Ó‘'), + ('Ó“', 'Ó“'), + ('Ó•', 'Ó•'), + ('Ó—', 'Ó—'), + ('Ó™', 'Ó™'), + ('Ó›', 'Ó›'), + ('Ó', 'Ó'), + ('ÓŸ', 'ÓŸ'), + ('Ó¡', 'Ó¡'), + ('Ó£', 'Ó£'), + ('Ó¥', 'Ó¥'), + ('Ó§', 'Ó§'), + ('Ó©', 'Ó©'), + ('Ó«', 'Ó«'), + ('Ó­', 'Ó­'), + ('Ó¯', 'Ó¯'), + ('Ó±', 'Ó±'), + ('Ó³', 'Ó³'), + ('Óµ', 'Óµ'), + ('Ó·', 'Ó·'), + ('Ó¹', 'Ó¹'), + ('Ó»', 'Ó»'), + ('Ó½', 'Ó½'), + ('Ó¿', 'Ó¿'), + ('Ô', 'Ô'), + ('Ôƒ', 'Ôƒ'), + ('Ô…', 'Ô…'), + ('Ô‡', 'Ô‡'), + ('Ô‰', 'Ô‰'), + ('Ô‹', 'Ô‹'), + ('Ô', 'Ô'), + ('Ô', 'Ô'), + ('Ô‘', 'Ô‘'), + ('Ô“', 'Ô“'), + ('Ô•', 'Ô•'), + ('Ô—', 'Ô—'), + ('Ô™', 'Ô™'), + ('Ô›', 'Ô›'), + ('Ô', 'Ô'), + ('ÔŸ', 'ÔŸ'), + ('Ô¡', 'Ô¡'), + ('Ô£', 'Ô£'), + ('Ô¥', 'Ô¥'), + ('Ô§', 'Ô§'), + ('Ô©', 'Ô©'), + ('Ô«', 'Ô«'), + ('Ô­', 'Ô­'), + ('Ô¯', 'Ô¯'), + ('Õ ', 'Öˆ'), + ('áƒ', 'ჺ'), + ('ჽ', 'ჿ'), + ('á¸', 'á½'), + ('á²€', 'ᲈ'), + ('á´€', 'á´«'), + ('ᵫ', 'áµ·'), + ('áµ¹', 'ᶚ'), + ('á¸', 'á¸'), + ('ḃ', 'ḃ'), + ('ḅ', 'ḅ'), + ('ḇ', 'ḇ'), + ('ḉ', 'ḉ'), + ('ḋ', 'ḋ'), + ('á¸', 'á¸'), + ('á¸', 'á¸'), + ('ḑ', 'ḑ'), + ('ḓ', 'ḓ'), + ('ḕ', 'ḕ'), + ('ḗ', 'ḗ'), + ('ḙ', 'ḙ'), + ('ḛ', 'ḛ'), + ('á¸', 'á¸'), + ('ḟ', 'ḟ'), + ('ḡ', 'ḡ'), + ('ḣ', 'ḣ'), + ('ḥ', 'ḥ'), + ('ḧ', 'ḧ'), + ('ḩ', 'ḩ'), + ('ḫ', 'ḫ'), + ('ḭ', 'ḭ'), + ('ḯ', 'ḯ'), + ('ḱ', 'ḱ'), + ('ḳ', 'ḳ'), + ('ḵ', 'ḵ'), + ('ḷ', 'ḷ'), + ('ḹ', 'ḹ'), + ('ḻ', 'ḻ'), + ('ḽ', 'ḽ'), + ('ḿ', 'ḿ'), + ('á¹', 'á¹'), + ('ṃ', 'ṃ'), + ('á¹…', 'á¹…'), + ('ṇ', 'ṇ'), + ('ṉ', 'ṉ'), + ('ṋ', 'ṋ'), + ('á¹', 'á¹'), + ('á¹', 'á¹'), + ('ṑ', 'ṑ'), + ('ṓ', 'ṓ'), + ('ṕ', 'ṕ'), + ('á¹—', 'á¹—'), + ('á¹™', 'á¹™'), + ('á¹›', 'á¹›'), + ('á¹', 'á¹'), + ('ṟ', 'ṟ'), + ('ṡ', 'ṡ'), + ('á¹£', 'á¹£'), + ('á¹¥', 'á¹¥'), + ('ṧ', 'ṧ'), + ('ṩ', 'ṩ'), + ('ṫ', 'ṫ'), + ('á¹­', 'á¹­'), + ('ṯ', 'ṯ'), + ('á¹±', 'á¹±'), + ('á¹³', 'á¹³'), + ('á¹µ', 'á¹µ'), + ('á¹·', 'á¹·'), + ('á¹¹', 'á¹¹'), + ('á¹»', 'á¹»'), + ('á¹½', 'á¹½'), + ('ṿ', 'ṿ'), + ('áº', 'áº'), + ('ẃ', 'ẃ'), + ('ẅ', 'ẅ'), + ('ẇ', 'ẇ'), + ('ẉ', 'ẉ'), + ('ẋ', 'ẋ'), + ('áº', 'áº'), + ('áº', 'áº'), + ('ẑ', 'ẑ'), + ('ẓ', 'ẓ'), + ('ẕ', 'áº'), + ('ẟ', 'ẟ'), + ('ạ', 'ạ'), + ('ả', 'ả'), + ('ấ', 'ấ'), + ('ầ', 'ầ'), + ('ẩ', 'ẩ'), + ('ẫ', 'ẫ'), + ('ậ', 'ậ'), + ('ắ', 'ắ'), + ('ằ', 'ằ'), + ('ẳ', 'ẳ'), + ('ẵ', 'ẵ'), + ('ặ', 'ặ'), + ('ẹ', 'ẹ'), + ('ẻ', 'ẻ'), + ('ẽ', 'ẽ'), + ('ế', 'ế'), + ('á»', 'á»'), + ('ể', 'ể'), + ('á»…', 'á»…'), + ('ệ', 'ệ'), + ('ỉ', 'ỉ'), + ('ị', 'ị'), + ('á»', 'á»'), + ('á»', 'á»'), + ('ố', 'ố'), + ('ồ', 'ồ'), + ('ổ', 'ổ'), + ('á»—', 'á»—'), + ('á»™', 'á»™'), + ('á»›', 'á»›'), + ('á»', 'á»'), + ('ở', 'ở'), + ('ỡ', 'ỡ'), + ('ợ', 'ợ'), + ('ụ', 'ụ'), + ('ủ', 'ủ'), + ('ứ', 'ứ'), + ('ừ', 'ừ'), + ('á»­', 'á»­'), + ('ữ', 'ữ'), + ('á»±', 'á»±'), + ('ỳ', 'ỳ'), + ('ỵ', 'ỵ'), + ('á»·', 'á»·'), + ('ỹ', 'ỹ'), + ('á»»', 'á»»'), + ('ỽ', 'ỽ'), + ('ỿ', 'ἇ'), + ('á¼', 'ἕ'), + ('á¼ ', 'ἧ'), + ('á¼°', 'á¼·'), + ('á½€', 'á½…'), + ('á½', 'á½—'), + ('á½ ', 'ὧ'), + ('á½°', 'á½½'), + ('á¾€', 'ᾇ'), + ('á¾', 'á¾—'), + ('á¾ ', 'ᾧ'), + ('á¾°', 'á¾´'), + ('ᾶ', 'á¾·'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'ῇ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿—'), + ('á¿ ', 'ῧ'), + ('ῲ', 'á¿´'), + ('ῶ', 'á¿·'), + ('â„Š', 'â„Š'), + ('â„Ž', 'â„'), + ('â„“', 'â„“'), + ('ℯ', 'ℯ'), + ('â„´', 'â„´'), + ('ℹ', 'ℹ'), + ('ℼ', 'ℽ'), + ('â…†', 'â…‰'), + ('â…Ž', 'â…Ž'), + ('ↄ', 'ↄ'), + ('â°°', 'ⱟ'), + ('ⱡ', 'ⱡ'), + ('â±¥', 'ⱦ'), + ('ⱨ', 'ⱨ'), + ('ⱪ', 'ⱪ'), + ('ⱬ', 'ⱬ'), + ('â±±', 'â±±'), + ('â±³', 'â±´'), + ('ⱶ', 'â±»'), + ('â²', 'â²'), + ('ⲃ', 'ⲃ'), + ('â²…', 'â²…'), + ('ⲇ', 'ⲇ'), + ('ⲉ', 'ⲉ'), + ('ⲋ', 'ⲋ'), + ('â²', 'â²'), + ('â²', 'â²'), + ('ⲑ', 'ⲑ'), + ('ⲓ', 'ⲓ'), + ('ⲕ', 'ⲕ'), + ('â²—', 'â²—'), + ('â²™', 'â²™'), + ('â²›', 'â²›'), + ('â²', 'â²'), + ('ⲟ', 'ⲟ'), + ('ⲡ', 'ⲡ'), + ('â²£', 'â²£'), + ('â²¥', 'â²¥'), + ('ⲧ', 'ⲧ'), + ('ⲩ', 'ⲩ'), + ('ⲫ', 'ⲫ'), + ('â²­', 'â²­'), + ('ⲯ', 'ⲯ'), + ('â²±', 'â²±'), + ('â²³', 'â²³'), + ('â²µ', 'â²µ'), + ('â²·', 'â²·'), + ('â²¹', 'â²¹'), + ('â²»', 'â²»'), + ('â²½', 'â²½'), + ('ⲿ', 'ⲿ'), + ('â³', 'â³'), + ('ⳃ', 'ⳃ'), + ('â³…', 'â³…'), + ('ⳇ', 'ⳇ'), + ('ⳉ', 'ⳉ'), + ('ⳋ', 'ⳋ'), + ('â³', 'â³'), + ('â³', 'â³'), + ('ⳑ', 'ⳑ'), + ('ⳓ', 'ⳓ'), + ('ⳕ', 'ⳕ'), + ('â³—', 'â³—'), + ('â³™', 'â³™'), + ('â³›', 'â³›'), + ('â³', 'â³'), + ('ⳟ', 'ⳟ'), + ('ⳡ', 'ⳡ'), + ('â³£', 'ⳤ'), + ('ⳬ', 'ⳬ'), + ('â³®', 'â³®'), + ('â³³', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('ê™', 'ê™'), + ('ꙃ', 'ꙃ'), + ('ê™…', 'ê™…'), + ('ꙇ', 'ꙇ'), + ('ꙉ', 'ꙉ'), + ('ꙋ', 'ꙋ'), + ('ê™', 'ê™'), + ('ê™', 'ê™'), + ('ꙑ', 'ꙑ'), + ('ꙓ', 'ꙓ'), + ('ꙕ', 'ꙕ'), + ('ê™—', 'ê™—'), + ('ê™™', 'ê™™'), + ('ê™›', 'ê™›'), + ('ê™', 'ê™'), + ('ꙟ', 'ꙟ'), + ('ꙡ', 'ꙡ'), + ('ꙣ', 'ꙣ'), + ('ꙥ', 'ꙥ'), + ('ꙧ', 'ꙧ'), + ('ꙩ', 'ꙩ'), + ('ꙫ', 'ꙫ'), + ('ê™­', 'ê™­'), + ('êš', 'êš'), + ('ꚃ', 'ꚃ'), + ('êš…', 'êš…'), + ('ꚇ', 'ꚇ'), + ('ꚉ', 'ꚉ'), + ('êš‹', 'êš‹'), + ('êš', 'êš'), + ('êš', 'êš'), + ('êš‘', 'êš‘'), + ('êš“', 'êš“'), + ('êš•', 'êš•'), + ('êš—', 'êš—'), + ('êš™', 'êš™'), + ('êš›', 'êš›'), + ('ꜣ', 'ꜣ'), + ('ꜥ', 'ꜥ'), + ('ꜧ', 'ꜧ'), + ('ꜩ', 'ꜩ'), + ('ꜫ', 'ꜫ'), + ('ꜭ', 'ꜭ'), + ('ꜯ', 'ꜱ'), + ('ꜳ', 'ꜳ'), + ('ꜵ', 'ꜵ'), + ('ꜷ', 'ꜷ'), + ('ꜹ', 'ꜹ'), + ('ꜻ', 'ꜻ'), + ('ꜽ', 'ꜽ'), + ('ꜿ', 'ꜿ'), + ('ê', 'ê'), + ('êƒ', 'êƒ'), + ('ê…', 'ê…'), + ('ê‡', 'ê‡'), + ('ê‰', 'ê‰'), + ('ê‹', 'ê‹'), + ('ê', 'ê'), + ('ê', 'ê'), + ('ê‘', 'ê‘'), + ('ê“', 'ê“'), + ('ê•', 'ê•'), + ('ê—', 'ê—'), + ('ê™', 'ê™'), + ('ê›', 'ê›'), + ('ê', 'ê'), + ('êŸ', 'êŸ'), + ('ê¡', 'ê¡'), + ('ê£', 'ê£'), + ('ê¥', 'ê¥'), + ('ê§', 'ê§'), + ('ê©', 'ê©'), + ('ê«', 'ê«'), + ('ê­', 'ê­'), + ('ê¯', 'ê¯'), + ('ê±', 'ê¸'), + ('êº', 'êº'), + ('ê¼', 'ê¼'), + ('ê¿', 'ê¿'), + ('êž', 'êž'), + ('ꞃ', 'ꞃ'), + ('êž…', 'êž…'), + ('ꞇ', 'ꞇ'), + ('ꞌ', 'ꞌ'), + ('ꞎ', 'ꞎ'), + ('êž‘', 'êž‘'), + ('êž“', 'êž•'), + ('êž—', 'êž—'), + ('êž™', 'êž™'), + ('êž›', 'êž›'), + ('êž', 'êž'), + ('ꞟ', 'ꞟ'), + ('êž¡', 'êž¡'), + ('ꞣ', 'ꞣ'), + ('ꞥ', 'ꞥ'), + ('ꞧ', 'ꞧ'), + ('êž©', 'êž©'), + ('ꞯ', 'ꞯ'), + ('êžµ', 'êžµ'), + ('êž·', 'êž·'), + ('êž¹', 'êž¹'), + ('êž»', 'êž»'), + ('êž½', 'êž½'), + ('êž¿', 'êž¿'), + ('êŸ', 'êŸ'), + ('ꟃ', 'ꟃ'), + ('ꟈ', 'ꟈ'), + ('ꟊ', 'ꟊ'), + ('ꟑ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟕ'), + ('ꟗ', 'ꟗ'), + ('ꟙ', 'ꟙ'), + ('ꟶ', 'ꟶ'), + ('ꟺ', 'ꟺ'), + ('ꬰ', 'ê­š'), + ('ê­ ', 'ê­¨'), + ('ê­°', 'ꮿ'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï½', 'z'), + ('ð¨', 'ð‘'), + ('ð“˜', 'ð“»'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð³€', 'ð³²'), + ('ð‘£€', '𑣟'), + ('ð–¹ ', '𖹿'), + ('ðš', 'ð³'), + ('ð‘Ž', 'ð‘”'), + ('ð‘–', 'ð‘§'), + ('ð’‚', 'ð’›'), + ('ð’¶', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð“'), + ('ð“ª', 'ð”ƒ'), + ('ð”ž', 'ð”·'), + ('ð•’', 'ð•«'), + ('ð–†', 'ð–Ÿ'), + ('ð–º', 'ð—“'), + ('ð—®', 'ð˜‡'), + ('ð˜¢', 'ð˜»'), + ('ð™–', 'ð™¯'), + ('ðšŠ', 'ðš¥'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›¡'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ›'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð•'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‰'), + ('ðŸ‹', 'ðŸ‹'), + ('ð¼€', 'ð¼‰'), + ('ð¼‹', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('𞤢', '𞥃'), +]; + +pub const MARK: &'static [(char, char)] = &[ + ('\u{300}', '\u{36f}'), + ('\u{483}', '\u{489}'), + ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), + ('\u{610}', '\u{61a}'), + ('\u{64b}', '\u{65f}'), + ('\u{670}', '\u{670}'), + ('\u{6d6}', '\u{6dc}'), + ('\u{6df}', '\u{6e4}'), + ('\u{6e7}', '\u{6e8}'), + ('\u{6ea}', '\u{6ed}'), + ('\u{711}', '\u{711}'), + ('\u{730}', '\u{74a}'), + ('\u{7a6}', '\u{7b0}'), + ('\u{7eb}', '\u{7f3}'), + ('\u{7fd}', '\u{7fd}'), + ('\u{816}', '\u{819}'), + ('\u{81b}', '\u{823}'), + ('\u{825}', '\u{827}'), + ('\u{829}', '\u{82d}'), + ('\u{859}', '\u{85b}'), + ('\u{898}', '\u{89f}'), + ('\u{8ca}', '\u{8e1}'), + ('\u{8e3}', 'ः'), + ('\u{93a}', '\u{93c}'), + ('ा', 'à¥'), + ('\u{951}', '\u{957}'), + ('\u{962}', '\u{963}'), + ('\u{981}', 'ঃ'), + ('\u{9bc}', '\u{9bc}'), + ('\u{9be}', '\u{9c4}'), + ('ে', 'ৈ'), + ('ো', '\u{9cd}'), + ('\u{9d7}', '\u{9d7}'), + ('\u{9e2}', '\u{9e3}'), + ('\u{9fe}', '\u{9fe}'), + ('\u{a01}', 'ਃ'), + ('\u{a3c}', '\u{a3c}'), + ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), + ('\u{a70}', '\u{a71}'), + ('\u{a75}', '\u{a75}'), + ('\u{a81}', 'ઃ'), + ('\u{abc}', '\u{abc}'), + ('ા', '\u{ac5}'), + ('\u{ac7}', 'ૉ'), + ('à«‹', '\u{acd}'), + ('\u{ae2}', '\u{ae3}'), + ('\u{afa}', '\u{aff}'), + ('\u{b01}', 'ଃ'), + ('\u{b3c}', '\u{b3c}'), + ('\u{b3e}', '\u{b44}'), + ('à­‡', 'à­ˆ'), + ('à­‹', '\u{b4d}'), + ('\u{b55}', '\u{b57}'), + ('\u{b62}', '\u{b63}'), + ('\u{b82}', '\u{b82}'), + ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), + ('ொ', '\u{bcd}'), + ('\u{bd7}', '\u{bd7}'), + ('\u{c00}', '\u{c04}'), + ('\u{c3c}', '\u{c3c}'), + ('\u{c3e}', 'ౄ'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('\u{c62}', '\u{c63}'), + ('\u{c81}', 'ಃ'), + ('\u{cbc}', '\u{cbc}'), + ('ಾ', 'ೄ'), + ('\u{cc6}', 'ೈ'), + ('ೊ', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), + ('\u{ce2}', '\u{ce3}'), + ('à³³', 'à³³'), + ('\u{d00}', 'à´ƒ'), + ('\u{d3b}', '\u{d3c}'), + ('\u{d3e}', '\u{d44}'), + ('െ', 'ൈ'), + ('ൊ', '\u{d4d}'), + ('\u{d57}', '\u{d57}'), + ('\u{d62}', '\u{d63}'), + ('\u{d81}', 'ඃ'), + ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('à·˜', '\u{ddf}'), + ('à·²', 'à·³'), + ('\u{e31}', '\u{e31}'), + ('\u{e34}', '\u{e3a}'), + ('\u{e47}', '\u{e4e}'), + ('\u{eb1}', '\u{eb1}'), + ('\u{eb4}', '\u{ebc}'), + ('\u{ec8}', '\u{ece}'), + ('\u{f18}', '\u{f19}'), + ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), + ('\u{f39}', '\u{f39}'), + ('༾', '༿'), + ('\u{f71}', '\u{f84}'), + ('\u{f86}', '\u{f87}'), + ('\u{f8d}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('\u{fc6}', '\u{fc6}'), + ('ါ', '\u{103e}'), + ('á–', '\u{1059}'), + ('\u{105e}', '\u{1060}'), + ('á¢', 'á¤'), + ('á§', 'á­'), + ('\u{1071}', '\u{1074}'), + ('\u{1082}', '\u{108d}'), + ('á‚', 'á‚'), + ('á‚š', '\u{109d}'), + ('\u{135d}', '\u{135f}'), + ('\u{1712}', '᜕'), + ('\u{1732}', '᜴'), + ('\u{1752}', '\u{1753}'), + ('\u{1772}', '\u{1773}'), + ('\u{17b4}', '\u{17d3}'), + ('\u{17dd}', '\u{17dd}'), + ('\u{180b}', '\u{180d}'), + ('\u{180f}', '\u{180f}'), + ('\u{1885}', '\u{1886}'), + ('\u{18a9}', '\u{18a9}'), + ('\u{1920}', 'ᤫ'), + ('ᤰ', '\u{193b}'), + ('\u{1a17}', '\u{1a1b}'), + ('á©•', '\u{1a5e}'), + ('\u{1a60}', '\u{1a7c}'), + ('\u{1a7f}', '\u{1a7f}'), + ('\u{1ab0}', '\u{1ace}'), + ('\u{1b00}', 'ᬄ'), + ('\u{1b34}', 'á­„'), + ('\u{1b6b}', '\u{1b73}'), + ('\u{1b80}', 'ᮂ'), + ('ᮡ', '\u{1bad}'), + ('\u{1be6}', '᯳'), + ('á°¤', '\u{1c37}'), + ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', '\u{1ce8}'), + ('\u{1ced}', '\u{1ced}'), + ('\u{1cf4}', '\u{1cf4}'), + ('á³·', '\u{1cf9}'), + ('\u{1dc0}', '\u{1dff}'), + ('\u{20d0}', '\u{20f0}'), + ('\u{2cef}', '\u{2cf1}'), + ('\u{2d7f}', '\u{2d7f}'), + ('\u{2de0}', '\u{2dff}'), + ('\u{302a}', '\u{302f}'), + ('\u{3099}', '\u{309a}'), + ('\u{a66f}', '\u{a672}'), + ('\u{a674}', '\u{a67d}'), + ('\u{a69e}', '\u{a69f}'), + ('\u{a6f0}', '\u{a6f1}'), + ('\u{a802}', '\u{a802}'), + ('\u{a806}', '\u{a806}'), + ('\u{a80b}', '\u{a80b}'), + ('ê £', 'ê §'), + ('\u{a82c}', '\u{a82c}'), + ('ꢀ', 'ê¢'), + ('ꢴ', '\u{a8c5}'), + ('\u{a8e0}', '\u{a8f1}'), + ('\u{a8ff}', '\u{a8ff}'), + ('\u{a926}', '\u{a92d}'), + ('\u{a947}', '꥓'), + ('\u{a980}', 'ꦃ'), + ('\u{a9b3}', '꧀'), + ('\u{a9e5}', '\u{a9e5}'), + ('\u{aa29}', '\u{aa36}'), + ('\u{aa43}', '\u{aa43}'), + ('\u{aa4c}', 'ê©'), + ('ê©»', 'ꩽ'), + ('\u{aab0}', '\u{aab0}'), + ('\u{aab2}', '\u{aab4}'), + ('\u{aab7}', '\u{aab8}'), + ('\u{aabe}', '\u{aabf}'), + ('\u{aac1}', '\u{aac1}'), + ('ê««', 'ꫯ'), + ('ꫵ', '\u{aaf6}'), + ('ꯣ', 'ꯪ'), + ('꯬', '\u{abed}'), + ('\u{fb1e}', '\u{fb1e}'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{fe20}', '\u{fe2f}'), + ('\u{101fd}', '\u{101fd}'), + ('\u{102e0}', '\u{102e0}'), + ('\u{10376}', '\u{1037a}'), + ('\u{10a01}', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), + ('\u{10ae5}', '\u{10ae6}'), + ('\u{10d24}', '\u{10d27}'), + ('\u{10eab}', '\u{10eac}'), + ('\u{10efd}', '\u{10eff}'), + ('\u{10f46}', '\u{10f50}'), + ('\u{10f82}', '\u{10f85}'), + ('ð‘€€', '𑀂'), + ('\u{11038}', '\u{11046}'), + ('\u{11070}', '\u{11070}'), + ('\u{11073}', '\u{11074}'), + ('\u{1107f}', 'ð‘‚‚'), + ('ð‘‚°', '\u{110ba}'), + ('\u{110c2}', '\u{110c2}'), + ('\u{11100}', '\u{11102}'), + ('\u{11127}', '\u{11134}'), + ('ð‘……', 'ð‘…†'), + ('\u{11173}', '\u{11173}'), + ('\u{11180}', '𑆂'), + ('𑆳', '𑇀'), + ('\u{111c9}', '\u{111cc}'), + ('𑇎', '\u{111cf}'), + ('𑈬', '\u{11237}'), + ('\u{1123e}', '\u{1123e}'), + ('\u{11241}', '\u{11241}'), + ('\u{112df}', '\u{112ea}'), + ('\u{11300}', '𑌃'), + ('\u{1133b}', '\u{1133c}'), + ('\u{1133e}', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘'), + ('\u{11357}', '\u{11357}'), + ('ð‘¢', 'ð‘£'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('ð‘µ', '\u{11446}'), + ('\u{1145e}', '\u{1145e}'), + ('\u{114b0}', '\u{114c3}'), + ('\u{115af}', '\u{115b5}'), + ('ð‘–¸', '\u{115c0}'), + ('\u{115dc}', '\u{115dd}'), + ('𑘰', '\u{11640}'), + ('\u{116ab}', '\u{116b7}'), + ('\u{1171d}', '\u{1172b}'), + ('ð‘ ¬', '\u{1183a}'), + ('\u{11930}', '𑤵'), + ('𑤷', '𑤸'), + ('\u{1193b}', '\u{1193e}'), + ('ð‘¥€', 'ð‘¥€'), + ('𑥂', '\u{11943}'), + ('𑧑', '\u{119d7}'), + ('\u{119da}', '\u{119e0}'), + ('𑧤', '𑧤'), + ('\u{11a01}', '\u{11a0a}'), + ('\u{11a33}', '𑨹'), + ('\u{11a3b}', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), + ('\u{11a51}', '\u{11a5b}'), + ('\u{11a8a}', '\u{11a99}'), + ('ð‘°¯', '\u{11c36}'), + ('\u{11c38}', '\u{11c3f}'), + ('\u{11c92}', '\u{11ca7}'), + ('𑲩', '\u{11cb6}'), + ('\u{11d31}', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d45}'), + ('\u{11d47}', '\u{11d47}'), + ('𑶊', '𑶎'), + ('\u{11d90}', '\u{11d91}'), + ('𑶓', '\u{11d97}'), + ('\u{11ef3}', '𑻶'), + ('\u{11f00}', '\u{11f01}'), + ('𑼃', '𑼃'), + ('𑼴', '\u{11f3a}'), + ('𑼾', '\u{11f42}'), + ('\u{13440}', '\u{13440}'), + ('\u{13447}', '\u{13455}'), + ('\u{16af0}', '\u{16af4}'), + ('\u{16b30}', '\u{16b36}'), + ('\u{16f4f}', '\u{16f4f}'), + ('𖽑', '𖾇'), + ('\u{16f8f}', '\u{16f92}'), + ('\u{16fe4}', '\u{16fe4}'), + ('ð–¿°', 'ð–¿±'), + ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('\u{1d165}', '\u{1d169}'), + ('ð…­', '\u{1d172}'), + ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), + ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), + ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), + ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('\u{1e08f}', '\u{1e08f}'), + ('\u{1e130}', '\u{1e136}'), + ('\u{1e2ae}', '\u{1e2ae}'), + ('\u{1e2ec}', '\u{1e2ef}'), + ('\u{1e4ec}', '\u{1e4ef}'), + ('\u{1e8d0}', '\u{1e8d6}'), + ('\u{1e944}', '\u{1e94a}'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const MATH_SYMBOL: &'static [(char, char)] = &[ + ('+', '+'), + ('<', '>'), + ('|', '|'), + ('~', '~'), + ('¬', '¬'), + ('±', '±'), + ('×', '×'), + ('÷', '÷'), + ('϶', '϶'), + ('؆', '؈'), + ('â„', 'â„'), + ('â’', 'â’'), + ('âº', 'â¼'), + ('â‚Š', 'â‚Œ'), + ('℘', '℘'), + ('â…€', 'â…„'), + ('â…‹', 'â…‹'), + ('â†', '↔'), + ('↚', '↛'), + ('↠', '↠'), + ('↣', '↣'), + ('↦', '↦'), + ('↮', '↮'), + ('⇎', 'â‡'), + ('⇒', '⇒'), + ('⇔', '⇔'), + ('⇴', 'â‹¿'), + ('⌠', '⌡'), + ('â¼', 'â¼'), + ('⎛', '⎳'), + ('âœ', 'â¡'), + ('â–·', 'â–·'), + ('â—', 'â—'), + ('â—¸', 'â—¿'), + ('♯', '♯'), + ('⟀', '⟄'), + ('⟇', '⟥'), + ('⟰', '⟿'), + ('⤀', '⦂'), + ('⦙', '⧗'), + ('⧜', '⧻'), + ('⧾', 'â«¿'), + ('⬰', 'â­„'), + ('â­‡', 'â­Œ'), + ('﬩', '﬩'), + ('ï¹¢', 'ï¹¢'), + ('﹤', '﹦'), + ('+', '+'), + ('<', '>'), + ('|', '|'), + ('~', '~'), + ('ï¿¢', 'ï¿¢'), + ('ï¿©', '↓'), + ('ð›', 'ð›'), + ('ð››', 'ð››'), + ('ð›»', 'ð›»'), + ('ðœ•', 'ðœ•'), + ('ðœµ', 'ðœµ'), + ('ð', 'ð'), + ('ð¯', 'ð¯'), + ('ðž‰', 'ðž‰'), + ('ðž©', 'ðž©'), + ('ðŸƒ', 'ðŸƒ'), + ('ðž»°', 'ðž»±'), +]; + +pub const MODIFIER_LETTER: &'static [(char, char)] = &[ + ('Ê°', 'Ë'), + ('ˆ', 'Ë‘'), + ('Ë ', 'ˤ'), + ('ˬ', 'ˬ'), + ('Ë®', 'Ë®'), + ('Í´', 'Í´'), + ('ͺ', 'ͺ'), + ('Õ™', 'Õ™'), + ('Ù€', 'Ù€'), + ('Û¥', 'Û¦'), + ('ß´', 'ßµ'), + ('ߺ', 'ߺ'), + ('à š', 'à š'), + ('à ¤', 'à ¤'), + ('à ¨', 'à ¨'), + ('ࣉ', 'ࣉ'), + ('ॱ', 'ॱ'), + ('ๆ', 'ๆ'), + ('ໆ', 'ໆ'), + ('ჼ', 'ჼ'), + ('ៗ', 'ៗ'), + ('ᡃ', 'ᡃ'), + ('ᪧ', 'ᪧ'), + ('ᱸ', 'á±½'), + ('á´¬', 'ᵪ'), + ('ᵸ', 'ᵸ'), + ('ᶛ', 'ᶿ'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('â±¼', 'â±½'), + ('ⵯ', 'ⵯ'), + ('ⸯ', 'ⸯ'), + ('々', '々'), + ('〱', '〵'), + ('〻', '〻'), + ('ã‚', 'ã‚ž'), + ('ー', 'ヾ'), + ('ꀕ', 'ꀕ'), + ('ꓸ', 'ꓽ'), + ('ꘌ', 'ꘌ'), + ('ꙿ', 'ꙿ'), + ('êšœ', 'êš'), + ('ꜗ', 'ꜟ'), + ('ê°', 'ê°'), + ('ꞈ', 'ꞈ'), + ('ꟲ', 'ꟴ'), + ('ꟸ', 'ꟹ'), + ('ê§', 'ê§'), + ('ꧦ', 'ꧦ'), + ('ê©°', 'ê©°'), + ('ê«', 'ê«'), + ('ꫳ', 'ê«´'), + ('ê­œ', 'ê­Ÿ'), + ('ê­©', 'ê­©'), + ('ï½°', 'ï½°'), + ('\u{ff9e}', '\u{ff9f}'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð–­€', 'ð–­ƒ'), + ('𖾓', '𖾟'), + ('ð–¿ ', 'ð–¿¡'), + ('ð–¿£', 'ð–¿£'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𞀰', 'ðž­'), + ('ðž„·', '𞄽'), + ('ðž“«', 'ðž“«'), + ('𞥋', '𞥋'), +]; + +pub const MODIFIER_SYMBOL: &'static [(char, char)] = &[ + ('^', '^'), + ('`', '`'), + ('¨', '¨'), + ('¯', '¯'), + ('´', '´'), + ('¸', '¸'), + ('Ë‚', 'Ë…'), + ('Ë’', 'ËŸ'), + ('Ë¥', 'Ë«'), + ('Ë­', 'Ë­'), + ('˯', 'Ë¿'), + ('͵', '͵'), + ('΄', 'Î…'), + ('࢈', '࢈'), + ('á¾½', 'á¾½'), + ('᾿', 'á¿'), + ('á¿', 'á¿'), + ('á¿', 'á¿Ÿ'), + ('á¿­', '`'), + ('´', '῾'), + ('ã‚›', 'ã‚œ'), + ('꜀', '꜖'), + ('꜠', '꜡'), + ('꞉', '꞊'), + ('ê­›', 'ê­›'), + ('ê­ª', 'ê­«'), + ('﮲', '﯂'), + ('ï¼¾', 'ï¼¾'), + ('ï½€', 'ï½€'), + ('ï¿£', 'ï¿£'), + ('ðŸ»', 'ðŸ¿'), +]; + +pub const NONSPACING_MARK: &'static [(char, char)] = &[ + ('\u{300}', '\u{36f}'), + ('\u{483}', '\u{487}'), + ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), + ('\u{610}', '\u{61a}'), + ('\u{64b}', '\u{65f}'), + ('\u{670}', '\u{670}'), + ('\u{6d6}', '\u{6dc}'), + ('\u{6df}', '\u{6e4}'), + ('\u{6e7}', '\u{6e8}'), + ('\u{6ea}', '\u{6ed}'), + ('\u{711}', '\u{711}'), + ('\u{730}', '\u{74a}'), + ('\u{7a6}', '\u{7b0}'), + ('\u{7eb}', '\u{7f3}'), + ('\u{7fd}', '\u{7fd}'), + ('\u{816}', '\u{819}'), + ('\u{81b}', '\u{823}'), + ('\u{825}', '\u{827}'), + ('\u{829}', '\u{82d}'), + ('\u{859}', '\u{85b}'), + ('\u{898}', '\u{89f}'), + ('\u{8ca}', '\u{8e1}'), + ('\u{8e3}', '\u{902}'), + ('\u{93a}', '\u{93a}'), + ('\u{93c}', '\u{93c}'), + ('\u{941}', '\u{948}'), + ('\u{94d}', '\u{94d}'), + ('\u{951}', '\u{957}'), + ('\u{962}', '\u{963}'), + ('\u{981}', '\u{981}'), + ('\u{9bc}', '\u{9bc}'), + ('\u{9c1}', '\u{9c4}'), + ('\u{9cd}', '\u{9cd}'), + ('\u{9e2}', '\u{9e3}'), + ('\u{9fe}', '\u{9fe}'), + ('\u{a01}', '\u{a02}'), + ('\u{a3c}', '\u{a3c}'), + ('\u{a41}', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), + ('\u{a70}', '\u{a71}'), + ('\u{a75}', '\u{a75}'), + ('\u{a81}', '\u{a82}'), + ('\u{abc}', '\u{abc}'), + ('\u{ac1}', '\u{ac5}'), + ('\u{ac7}', '\u{ac8}'), + ('\u{acd}', '\u{acd}'), + ('\u{ae2}', '\u{ae3}'), + ('\u{afa}', '\u{aff}'), + ('\u{b01}', '\u{b01}'), + ('\u{b3c}', '\u{b3c}'), + ('\u{b3f}', '\u{b3f}'), + ('\u{b41}', '\u{b44}'), + ('\u{b4d}', '\u{b4d}'), + ('\u{b55}', '\u{b56}'), + ('\u{b62}', '\u{b63}'), + ('\u{b82}', '\u{b82}'), + ('\u{bc0}', '\u{bc0}'), + ('\u{bcd}', '\u{bcd}'), + ('\u{c00}', '\u{c00}'), + ('\u{c04}', '\u{c04}'), + ('\u{c3c}', '\u{c3c}'), + ('\u{c3e}', '\u{c40}'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('\u{c62}', '\u{c63}'), + ('\u{c81}', '\u{c81}'), + ('\u{cbc}', '\u{cbc}'), + ('\u{cbf}', '\u{cbf}'), + ('\u{cc6}', '\u{cc6}'), + ('\u{ccc}', '\u{ccd}'), + ('\u{ce2}', '\u{ce3}'), + ('\u{d00}', '\u{d01}'), + ('\u{d3b}', '\u{d3c}'), + ('\u{d41}', '\u{d44}'), + ('\u{d4d}', '\u{d4d}'), + ('\u{d62}', '\u{d63}'), + ('\u{d81}', '\u{d81}'), + ('\u{dca}', '\u{dca}'), + ('\u{dd2}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('\u{e31}', '\u{e31}'), + ('\u{e34}', '\u{e3a}'), + ('\u{e47}', '\u{e4e}'), + ('\u{eb1}', '\u{eb1}'), + ('\u{eb4}', '\u{ebc}'), + ('\u{ec8}', '\u{ece}'), + ('\u{f18}', '\u{f19}'), + ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), + ('\u{f39}', '\u{f39}'), + ('\u{f71}', '\u{f7e}'), + ('\u{f80}', '\u{f84}'), + ('\u{f86}', '\u{f87}'), + ('\u{f8d}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('\u{fc6}', '\u{fc6}'), + ('\u{102d}', '\u{1030}'), + ('\u{1032}', '\u{1037}'), + ('\u{1039}', '\u{103a}'), + ('\u{103d}', '\u{103e}'), + ('\u{1058}', '\u{1059}'), + ('\u{105e}', '\u{1060}'), + ('\u{1071}', '\u{1074}'), + ('\u{1082}', '\u{1082}'), + ('\u{1085}', '\u{1086}'), + ('\u{108d}', '\u{108d}'), + ('\u{109d}', '\u{109d}'), + ('\u{135d}', '\u{135f}'), + ('\u{1712}', '\u{1714}'), + ('\u{1732}', '\u{1733}'), + ('\u{1752}', '\u{1753}'), + ('\u{1772}', '\u{1773}'), + ('\u{17b4}', '\u{17b5}'), + ('\u{17b7}', '\u{17bd}'), + ('\u{17c6}', '\u{17c6}'), + ('\u{17c9}', '\u{17d3}'), + ('\u{17dd}', '\u{17dd}'), + ('\u{180b}', '\u{180d}'), + ('\u{180f}', '\u{180f}'), + ('\u{1885}', '\u{1886}'), + ('\u{18a9}', '\u{18a9}'), + ('\u{1920}', '\u{1922}'), + ('\u{1927}', '\u{1928}'), + ('\u{1932}', '\u{1932}'), + ('\u{1939}', '\u{193b}'), + ('\u{1a17}', '\u{1a18}'), + ('\u{1a1b}', '\u{1a1b}'), + ('\u{1a56}', '\u{1a56}'), + ('\u{1a58}', '\u{1a5e}'), + ('\u{1a60}', '\u{1a60}'), + ('\u{1a62}', '\u{1a62}'), + ('\u{1a65}', '\u{1a6c}'), + ('\u{1a73}', '\u{1a7c}'), + ('\u{1a7f}', '\u{1a7f}'), + ('\u{1ab0}', '\u{1abd}'), + ('\u{1abf}', '\u{1ace}'), + ('\u{1b00}', '\u{1b03}'), + ('\u{1b34}', '\u{1b34}'), + ('\u{1b36}', '\u{1b3a}'), + ('\u{1b3c}', '\u{1b3c}'), + ('\u{1b42}', '\u{1b42}'), + ('\u{1b6b}', '\u{1b73}'), + ('\u{1b80}', '\u{1b81}'), + ('\u{1ba2}', '\u{1ba5}'), + ('\u{1ba8}', '\u{1ba9}'), + ('\u{1bab}', '\u{1bad}'), + ('\u{1be6}', '\u{1be6}'), + ('\u{1be8}', '\u{1be9}'), + ('\u{1bed}', '\u{1bed}'), + ('\u{1bef}', '\u{1bf1}'), + ('\u{1c2c}', '\u{1c33}'), + ('\u{1c36}', '\u{1c37}'), + ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', '\u{1ce0}'), + ('\u{1ce2}', '\u{1ce8}'), + ('\u{1ced}', '\u{1ced}'), + ('\u{1cf4}', '\u{1cf4}'), + ('\u{1cf8}', '\u{1cf9}'), + ('\u{1dc0}', '\u{1dff}'), + ('\u{20d0}', '\u{20dc}'), + ('\u{20e1}', '\u{20e1}'), + ('\u{20e5}', '\u{20f0}'), + ('\u{2cef}', '\u{2cf1}'), + ('\u{2d7f}', '\u{2d7f}'), + ('\u{2de0}', '\u{2dff}'), + ('\u{302a}', '\u{302d}'), + ('\u{3099}', '\u{309a}'), + ('\u{a66f}', '\u{a66f}'), + ('\u{a674}', '\u{a67d}'), + ('\u{a69e}', '\u{a69f}'), + ('\u{a6f0}', '\u{a6f1}'), + ('\u{a802}', '\u{a802}'), + ('\u{a806}', '\u{a806}'), + ('\u{a80b}', '\u{a80b}'), + ('\u{a825}', '\u{a826}'), + ('\u{a82c}', '\u{a82c}'), + ('\u{a8c4}', '\u{a8c5}'), + ('\u{a8e0}', '\u{a8f1}'), + ('\u{a8ff}', '\u{a8ff}'), + ('\u{a926}', '\u{a92d}'), + ('\u{a947}', '\u{a951}'), + ('\u{a980}', '\u{a982}'), + ('\u{a9b3}', '\u{a9b3}'), + ('\u{a9b6}', '\u{a9b9}'), + ('\u{a9bc}', '\u{a9bd}'), + ('\u{a9e5}', '\u{a9e5}'), + ('\u{aa29}', '\u{aa2e}'), + ('\u{aa31}', '\u{aa32}'), + ('\u{aa35}', '\u{aa36}'), + ('\u{aa43}', '\u{aa43}'), + ('\u{aa4c}', '\u{aa4c}'), + ('\u{aa7c}', '\u{aa7c}'), + ('\u{aab0}', '\u{aab0}'), + ('\u{aab2}', '\u{aab4}'), + ('\u{aab7}', '\u{aab8}'), + ('\u{aabe}', '\u{aabf}'), + ('\u{aac1}', '\u{aac1}'), + ('\u{aaec}', '\u{aaed}'), + ('\u{aaf6}', '\u{aaf6}'), + ('\u{abe5}', '\u{abe5}'), + ('\u{abe8}', '\u{abe8}'), + ('\u{abed}', '\u{abed}'), + ('\u{fb1e}', '\u{fb1e}'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{fe20}', '\u{fe2f}'), + ('\u{101fd}', '\u{101fd}'), + ('\u{102e0}', '\u{102e0}'), + ('\u{10376}', '\u{1037a}'), + ('\u{10a01}', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), + ('\u{10ae5}', '\u{10ae6}'), + ('\u{10d24}', '\u{10d27}'), + ('\u{10eab}', '\u{10eac}'), + ('\u{10efd}', '\u{10eff}'), + ('\u{10f46}', '\u{10f50}'), + ('\u{10f82}', '\u{10f85}'), + ('\u{11001}', '\u{11001}'), + ('\u{11038}', '\u{11046}'), + ('\u{11070}', '\u{11070}'), + ('\u{11073}', '\u{11074}'), + ('\u{1107f}', '\u{11081}'), + ('\u{110b3}', '\u{110b6}'), + ('\u{110b9}', '\u{110ba}'), + ('\u{110c2}', '\u{110c2}'), + ('\u{11100}', '\u{11102}'), + ('\u{11127}', '\u{1112b}'), + ('\u{1112d}', '\u{11134}'), + ('\u{11173}', '\u{11173}'), + ('\u{11180}', '\u{11181}'), + ('\u{111b6}', '\u{111be}'), + ('\u{111c9}', '\u{111cc}'), + ('\u{111cf}', '\u{111cf}'), + ('\u{1122f}', '\u{11231}'), + ('\u{11234}', '\u{11234}'), + ('\u{11236}', '\u{11237}'), + ('\u{1123e}', '\u{1123e}'), + ('\u{11241}', '\u{11241}'), + ('\u{112df}', '\u{112df}'), + ('\u{112e3}', '\u{112ea}'), + ('\u{11300}', '\u{11301}'), + ('\u{1133b}', '\u{1133c}'), + ('\u{11340}', '\u{11340}'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('\u{11438}', '\u{1143f}'), + ('\u{11442}', '\u{11444}'), + ('\u{11446}', '\u{11446}'), + ('\u{1145e}', '\u{1145e}'), + ('\u{114b3}', '\u{114b8}'), + ('\u{114ba}', '\u{114ba}'), + ('\u{114bf}', '\u{114c0}'), + ('\u{114c2}', '\u{114c3}'), + ('\u{115b2}', '\u{115b5}'), + ('\u{115bc}', '\u{115bd}'), + ('\u{115bf}', '\u{115c0}'), + ('\u{115dc}', '\u{115dd}'), + ('\u{11633}', '\u{1163a}'), + ('\u{1163d}', '\u{1163d}'), + ('\u{1163f}', '\u{11640}'), + ('\u{116ab}', '\u{116ab}'), + ('\u{116ad}', '\u{116ad}'), + ('\u{116b0}', '\u{116b5}'), + ('\u{116b7}', '\u{116b7}'), + ('\u{1171d}', '\u{1171f}'), + ('\u{11722}', '\u{11725}'), + ('\u{11727}', '\u{1172b}'), + ('\u{1182f}', '\u{11837}'), + ('\u{11839}', '\u{1183a}'), + ('\u{1193b}', '\u{1193c}'), + ('\u{1193e}', '\u{1193e}'), + ('\u{11943}', '\u{11943}'), + ('\u{119d4}', '\u{119d7}'), + ('\u{119da}', '\u{119db}'), + ('\u{119e0}', '\u{119e0}'), + ('\u{11a01}', '\u{11a0a}'), + ('\u{11a33}', '\u{11a38}'), + ('\u{11a3b}', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), + ('\u{11a51}', '\u{11a56}'), + ('\u{11a59}', '\u{11a5b}'), + ('\u{11a8a}', '\u{11a96}'), + ('\u{11a98}', '\u{11a99}'), + ('\u{11c30}', '\u{11c36}'), + ('\u{11c38}', '\u{11c3d}'), + ('\u{11c3f}', '\u{11c3f}'), + ('\u{11c92}', '\u{11ca7}'), + ('\u{11caa}', '\u{11cb0}'), + ('\u{11cb2}', '\u{11cb3}'), + ('\u{11cb5}', '\u{11cb6}'), + ('\u{11d31}', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d45}'), + ('\u{11d47}', '\u{11d47}'), + ('\u{11d90}', '\u{11d91}'), + ('\u{11d95}', '\u{11d95}'), + ('\u{11d97}', '\u{11d97}'), + ('\u{11ef3}', '\u{11ef4}'), + ('\u{11f00}', '\u{11f01}'), + ('\u{11f36}', '\u{11f3a}'), + ('\u{11f40}', '\u{11f40}'), + ('\u{11f42}', '\u{11f42}'), + ('\u{13440}', '\u{13440}'), + ('\u{13447}', '\u{13455}'), + ('\u{16af0}', '\u{16af4}'), + ('\u{16b30}', '\u{16b36}'), + ('\u{16f4f}', '\u{16f4f}'), + ('\u{16f8f}', '\u{16f92}'), + ('\u{16fe4}', '\u{16fe4}'), + ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('\u{1d167}', '\u{1d169}'), + ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), + ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), + ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), + ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('\u{1e08f}', '\u{1e08f}'), + ('\u{1e130}', '\u{1e136}'), + ('\u{1e2ae}', '\u{1e2ae}'), + ('\u{1e2ec}', '\u{1e2ef}'), + ('\u{1e4ec}', '\u{1e4ef}'), + ('\u{1e8d0}', '\u{1e8d6}'), + ('\u{1e944}', '\u{1e94a}'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const NUMBER: &'static [(char, char)] = &[ + ('0', '9'), + ('²', '³'), + ('¹', '¹'), + ('¼', '¾'), + ('Ù ', 'Ù©'), + ('Û°', 'Û¹'), + ('߀', '߉'), + ('०', '९'), + ('০', '৯'), + ('৴', '৹'), + ('੦', '੯'), + ('૦', '૯'), + ('à­¦', 'à­¯'), + ('à­²', 'à­·'), + ('௦', '௲'), + ('౦', '౯'), + ('౸', 'à±¾'), + ('೦', '೯'), + ('൘', '൞'), + ('൦', '൸'), + ('à·¦', 'à·¯'), + ('à¹', '๙'), + ('à»', 'à»™'), + ('༠', '༳'), + ('á€', 'á‰'), + ('á‚', 'á‚™'), + ('á©', 'á¼'), + ('á›®', 'á›°'), + ('០', '៩'), + ('៰', '៹'), + ('á ', 'á ™'), + ('᥆', 'á¥'), + ('á§', '᧚'), + ('᪀', '᪉'), + ('áª', '᪙'), + ('á­', 'á­™'), + ('á®°', '᮹'), + ('á±€', '᱉'), + ('á±', 'á±™'), + ('â°', 'â°'), + ('â´', 'â¹'), + ('â‚€', '₉'), + ('â…', 'ↂ'), + ('ↅ', '↉'), + ('â‘ ', 'â’›'), + ('⓪', 'â“¿'), + ('â¶', 'âž“'), + ('â³½', 'â³½'), + ('〇', '〇'), + ('〡', '〩'), + ('〸', '〺'), + ('㆒', '㆕'), + ('㈠', '㈩'), + ('㉈', 'ã‰'), + ('㉑', '㉟'), + ('㊀', '㊉'), + ('㊱', '㊿'), + ('꘠', '꘩'), + ('ꛦ', 'ꛯ'), + ('ê °', 'ê µ'), + ('ê£', '꣙'), + ('꤀', '꤉'), + ('ê§', '꧙'), + ('꧰', '꧹'), + ('ê©', 'ê©™'), + ('꯰', '꯹'), + ('ï¼', 'ï¼™'), + ('ð„‡', 'ð„³'), + ('ð…€', 'ð…¸'), + ('ð†Š', 'ð†‹'), + ('ð‹¡', 'ð‹»'), + ('ðŒ ', 'ðŒ£'), + ('ð', 'ð'), + ('ðŠ', 'ðŠ'), + ('ð‘', 'ð•'), + ('ð’ ', 'ð’©'), + ('ð¡˜', 'ð¡Ÿ'), + ('ð¡¹', 'ð¡¿'), + ('ð¢§', 'ð¢¯'), + ('ð£»', 'ð£¿'), + ('ð¤–', 'ð¤›'), + ('ð¦¼', 'ð¦½'), + ('ð§€', 'ð§'), + ('ð§’', 'ð§¿'), + ('ð©€', 'ð©ˆ'), + ('ð©½', 'ð©¾'), + ('ðª', 'ðªŸ'), + ('ð««', 'ð«¯'), + ('ð­˜', 'ð­Ÿ'), + ('ð­¸', 'ð­¿'), + ('ð®©', 'ð®¯'), + ('ð³º', 'ð³¿'), + ('ð´°', 'ð´¹'), + ('ð¹ ', 'ð¹¾'), + ('ð¼', 'ð¼¦'), + ('ð½‘', 'ð½”'), + ('ð¿…', 'ð¿‹'), + ('ð‘’', 'ð‘¯'), + ('𑃰', '𑃹'), + ('𑄶', 'ð‘„¿'), + ('ð‘‡', '𑇙'), + ('𑇡', '𑇴'), + ('ð‘‹°', 'ð‘‹¹'), + ('ð‘‘', 'ð‘‘™'), + ('ð‘“', 'ð‘“™'), + ('ð‘™', 'ð‘™™'), + ('𑛀', '𑛉'), + ('𑜰', '𑜻'), + ('ð‘£ ', 'ð‘£²'), + ('ð‘¥', 'ð‘¥™'), + ('ð‘±', '𑱬'), + ('ð‘µ', '𑵙'), + ('𑶠', '𑶩'), + ('ð‘½', '𑽙'), + ('ð‘¿€', 'ð‘¿”'), + ('ð’€', 'ð’‘®'), + ('ð–© ', 'ð–©©'), + ('ð–«€', '𖫉'), + ('ð–­', 'ð–­™'), + ('ð–­›', 'ð–­¡'), + ('𖺀', 'ð–º–'), + ('ð‹€', 'ð‹“'), + ('ð‹ ', 'ð‹³'), + ('ð ', 'ð¸'), + ('ðŸŽ', 'ðŸ¿'), + ('ðž…€', 'ðž…‰'), + ('ðž‹°', '𞋹'), + ('ðž“°', '𞓹'), + ('𞣇', 'ðž£'), + ('ðž¥', '𞥙'), + ('ðž±±', '𞲫'), + ('ðž²­', '𞲯'), + ('ðž²±', 'ðž²´'), + ('ðž´', 'ðž´­'), + ('ðž´¯', 'ðž´½'), + ('🄀', '🄌'), + ('🯰', '🯹'), +]; + +pub const OPEN_PUNCTUATION: &'static [(char, char)] = &[ + ('(', '('), + ('[', '['), + ('{', '{'), + ('༺', '༺'), + ('༼', '༼'), + ('áš›', 'áš›'), + ('‚', '‚'), + ('„', '„'), + ('â…', 'â…'), + ('â½', 'â½'), + ('â‚', 'â‚'), + ('⌈', '⌈'), + ('⌊', '⌊'), + ('〈', '〈'), + ('â¨', 'â¨'), + ('âª', 'âª'), + ('â¬', 'â¬'), + ('â®', 'â®'), + ('â°', 'â°'), + ('â²', 'â²'), + ('â´', 'â´'), + ('⟅', '⟅'), + ('⟦', '⟦'), + ('⟨', '⟨'), + ('⟪', '⟪'), + ('⟬', '⟬'), + ('⟮', '⟮'), + ('⦃', '⦃'), + ('⦅', '⦅'), + ('⦇', '⦇'), + ('⦉', '⦉'), + ('⦋', '⦋'), + ('â¦', 'â¦'), + ('â¦', 'â¦'), + ('⦑', '⦑'), + ('⦓', '⦓'), + ('⦕', '⦕'), + ('⦗', '⦗'), + ('⧘', '⧘'), + ('⧚', '⧚'), + ('⧼', '⧼'), + ('⸢', '⸢'), + ('⸤', '⸤'), + ('⸦', '⸦'), + ('⸨', '⸨'), + ('⹂', '⹂'), + ('⹕', '⹕'), + ('â¹—', 'â¹—'), + ('â¹™', 'â¹™'), + ('â¹›', 'â¹›'), + ('〈', '〈'), + ('《', '《'), + ('「', '「'), + ('『', '『'), + ('ã€', 'ã€'), + ('〔', '〔'), + ('〖', '〖'), + ('〘', '〘'), + ('〚', '〚'), + ('ã€', 'ã€'), + ('ï´¿', 'ï´¿'), + ('︗', '︗'), + ('︵', '︵'), + ('︷', '︷'), + ('︹', '︹'), + ('︻', '︻'), + ('︽', '︽'), + ('︿', '︿'), + ('ï¹', 'ï¹'), + ('﹃', '﹃'), + ('﹇', '﹇'), + ('ï¹™', 'ï¹™'), + ('ï¹›', 'ï¹›'), + ('ï¹', 'ï¹'), + ('(', '('), + ('ï¼»', 'ï¼»'), + ('ï½›', 'ï½›'), + ('⦅', '⦅'), + ('ï½¢', 'ï½¢'), +]; + +pub const OTHER: &'static [(char, char)] = &[ + ('\0', '\u{1f}'), + ('\u{7f}', '\u{9f}'), + ('\u{ad}', '\u{ad}'), + ('\u{378}', '\u{379}'), + ('\u{380}', '\u{383}'), + ('\u{38b}', '\u{38b}'), + ('\u{38d}', '\u{38d}'), + ('\u{3a2}', '\u{3a2}'), + ('\u{530}', '\u{530}'), + ('\u{557}', '\u{558}'), + ('\u{58b}', '\u{58c}'), + ('\u{590}', '\u{590}'), + ('\u{5c8}', '\u{5cf}'), + ('\u{5eb}', '\u{5ee}'), + ('\u{5f5}', '\u{605}'), + ('\u{61c}', '\u{61c}'), + ('\u{6dd}', '\u{6dd}'), + ('\u{70e}', '\u{70f}'), + ('\u{74b}', '\u{74c}'), + ('\u{7b2}', '\u{7bf}'), + ('\u{7fb}', '\u{7fc}'), + ('\u{82e}', '\u{82f}'), + ('\u{83f}', '\u{83f}'), + ('\u{85c}', '\u{85d}'), + ('\u{85f}', '\u{85f}'), + ('\u{86b}', '\u{86f}'), + ('\u{88f}', '\u{897}'), + ('\u{8e2}', '\u{8e2}'), + ('\u{984}', '\u{984}'), + ('\u{98d}', '\u{98e}'), + ('\u{991}', '\u{992}'), + ('\u{9a9}', '\u{9a9}'), + ('\u{9b1}', '\u{9b1}'), + ('\u{9b3}', '\u{9b5}'), + ('\u{9ba}', '\u{9bb}'), + ('\u{9c5}', '\u{9c6}'), + ('\u{9c9}', '\u{9ca}'), + ('\u{9cf}', '\u{9d6}'), + ('\u{9d8}', '\u{9db}'), + ('\u{9de}', '\u{9de}'), + ('\u{9e4}', '\u{9e5}'), + ('\u{9ff}', '\u{a00}'), + ('\u{a04}', '\u{a04}'), + ('\u{a0b}', '\u{a0e}'), + ('\u{a11}', '\u{a12}'), + ('\u{a29}', '\u{a29}'), + ('\u{a31}', '\u{a31}'), + ('\u{a34}', '\u{a34}'), + ('\u{a37}', '\u{a37}'), + ('\u{a3a}', '\u{a3b}'), + ('\u{a3d}', '\u{a3d}'), + ('\u{a43}', '\u{a46}'), + ('\u{a49}', '\u{a4a}'), + ('\u{a4e}', '\u{a50}'), + ('\u{a52}', '\u{a58}'), + ('\u{a5d}', '\u{a5d}'), + ('\u{a5f}', '\u{a65}'), + ('\u{a77}', '\u{a80}'), + ('\u{a84}', '\u{a84}'), + ('\u{a8e}', '\u{a8e}'), + ('\u{a92}', '\u{a92}'), + ('\u{aa9}', '\u{aa9}'), + ('\u{ab1}', '\u{ab1}'), + ('\u{ab4}', '\u{ab4}'), + ('\u{aba}', '\u{abb}'), + ('\u{ac6}', '\u{ac6}'), + ('\u{aca}', '\u{aca}'), + ('\u{ace}', '\u{acf}'), + ('\u{ad1}', '\u{adf}'), + ('\u{ae4}', '\u{ae5}'), + ('\u{af2}', '\u{af8}'), + ('\u{b00}', '\u{b00}'), + ('\u{b04}', '\u{b04}'), + ('\u{b0d}', '\u{b0e}'), + ('\u{b11}', '\u{b12}'), + ('\u{b29}', '\u{b29}'), + ('\u{b31}', '\u{b31}'), + ('\u{b34}', '\u{b34}'), + ('\u{b3a}', '\u{b3b}'), + ('\u{b45}', '\u{b46}'), + ('\u{b49}', '\u{b4a}'), + ('\u{b4e}', '\u{b54}'), + ('\u{b58}', '\u{b5b}'), + ('\u{b5e}', '\u{b5e}'), + ('\u{b64}', '\u{b65}'), + ('\u{b78}', '\u{b81}'), + ('\u{b84}', '\u{b84}'), + ('\u{b8b}', '\u{b8d}'), + ('\u{b91}', '\u{b91}'), + ('\u{b96}', '\u{b98}'), + ('\u{b9b}', '\u{b9b}'), + ('\u{b9d}', '\u{b9d}'), + ('\u{ba0}', '\u{ba2}'), + ('\u{ba5}', '\u{ba7}'), + ('\u{bab}', '\u{bad}'), + ('\u{bba}', '\u{bbd}'), + ('\u{bc3}', '\u{bc5}'), + ('\u{bc9}', '\u{bc9}'), + ('\u{bce}', '\u{bcf}'), + ('\u{bd1}', '\u{bd6}'), + ('\u{bd8}', '\u{be5}'), + ('\u{bfb}', '\u{bff}'), + ('\u{c0d}', '\u{c0d}'), + ('\u{c11}', '\u{c11}'), + ('\u{c29}', '\u{c29}'), + ('\u{c3a}', '\u{c3b}'), + ('\u{c45}', '\u{c45}'), + ('\u{c49}', '\u{c49}'), + ('\u{c4e}', '\u{c54}'), + ('\u{c57}', '\u{c57}'), + ('\u{c5b}', '\u{c5c}'), + ('\u{c5e}', '\u{c5f}'), + ('\u{c64}', '\u{c65}'), + ('\u{c70}', '\u{c76}'), + ('\u{c8d}', '\u{c8d}'), + ('\u{c91}', '\u{c91}'), + ('\u{ca9}', '\u{ca9}'), + ('\u{cb4}', '\u{cb4}'), + ('\u{cba}', '\u{cbb}'), + ('\u{cc5}', '\u{cc5}'), + ('\u{cc9}', '\u{cc9}'), + ('\u{cce}', '\u{cd4}'), + ('\u{cd7}', '\u{cdc}'), + ('\u{cdf}', '\u{cdf}'), + ('\u{ce4}', '\u{ce5}'), + ('\u{cf0}', '\u{cf0}'), + ('\u{cf4}', '\u{cff}'), + ('\u{d0d}', '\u{d0d}'), + ('\u{d11}', '\u{d11}'), + ('\u{d45}', '\u{d45}'), + ('\u{d49}', '\u{d49}'), + ('\u{d50}', '\u{d53}'), + ('\u{d64}', '\u{d65}'), + ('\u{d80}', '\u{d80}'), + ('\u{d84}', '\u{d84}'), + ('\u{d97}', '\u{d99}'), + ('\u{db2}', '\u{db2}'), + ('\u{dbc}', '\u{dbc}'), + ('\u{dbe}', '\u{dbf}'), + ('\u{dc7}', '\u{dc9}'), + ('\u{dcb}', '\u{dce}'), + ('\u{dd5}', '\u{dd5}'), + ('\u{dd7}', '\u{dd7}'), + ('\u{de0}', '\u{de5}'), + ('\u{df0}', '\u{df1}'), + ('\u{df5}', '\u{e00}'), + ('\u{e3b}', '\u{e3e}'), + ('\u{e5c}', '\u{e80}'), + ('\u{e83}', '\u{e83}'), + ('\u{e85}', '\u{e85}'), + ('\u{e8b}', '\u{e8b}'), + ('\u{ea4}', '\u{ea4}'), + ('\u{ea6}', '\u{ea6}'), + ('\u{ebe}', '\u{ebf}'), + ('\u{ec5}', '\u{ec5}'), + ('\u{ec7}', '\u{ec7}'), + ('\u{ecf}', '\u{ecf}'), + ('\u{eda}', '\u{edb}'), + ('\u{ee0}', '\u{eff}'), + ('\u{f48}', '\u{f48}'), + ('\u{f6d}', '\u{f70}'), + ('\u{f98}', '\u{f98}'), + ('\u{fbd}', '\u{fbd}'), + ('\u{fcd}', '\u{fcd}'), + ('\u{fdb}', '\u{fff}'), + ('\u{10c6}', '\u{10c6}'), + ('\u{10c8}', '\u{10cc}'), + ('\u{10ce}', '\u{10cf}'), + ('\u{1249}', '\u{1249}'), + ('\u{124e}', '\u{124f}'), + ('\u{1257}', '\u{1257}'), + ('\u{1259}', '\u{1259}'), + ('\u{125e}', '\u{125f}'), + ('\u{1289}', '\u{1289}'), + ('\u{128e}', '\u{128f}'), + ('\u{12b1}', '\u{12b1}'), + ('\u{12b6}', '\u{12b7}'), + ('\u{12bf}', '\u{12bf}'), + ('\u{12c1}', '\u{12c1}'), + ('\u{12c6}', '\u{12c7}'), + ('\u{12d7}', '\u{12d7}'), + ('\u{1311}', '\u{1311}'), + ('\u{1316}', '\u{1317}'), + ('\u{135b}', '\u{135c}'), + ('\u{137d}', '\u{137f}'), + ('\u{139a}', '\u{139f}'), + ('\u{13f6}', '\u{13f7}'), + ('\u{13fe}', '\u{13ff}'), + ('\u{169d}', '\u{169f}'), + ('\u{16f9}', '\u{16ff}'), + ('\u{1716}', '\u{171e}'), + ('\u{1737}', '\u{173f}'), + ('\u{1754}', '\u{175f}'), + ('\u{176d}', '\u{176d}'), + ('\u{1771}', '\u{1771}'), + ('\u{1774}', '\u{177f}'), + ('\u{17de}', '\u{17df}'), + ('\u{17ea}', '\u{17ef}'), + ('\u{17fa}', '\u{17ff}'), + ('\u{180e}', '\u{180e}'), + ('\u{181a}', '\u{181f}'), + ('\u{1879}', '\u{187f}'), + ('\u{18ab}', '\u{18af}'), + ('\u{18f6}', '\u{18ff}'), + ('\u{191f}', '\u{191f}'), + ('\u{192c}', '\u{192f}'), + ('\u{193c}', '\u{193f}'), + ('\u{1941}', '\u{1943}'), + ('\u{196e}', '\u{196f}'), + ('\u{1975}', '\u{197f}'), + ('\u{19ac}', '\u{19af}'), + ('\u{19ca}', '\u{19cf}'), + ('\u{19db}', '\u{19dd}'), + ('\u{1a1c}', '\u{1a1d}'), + ('\u{1a5f}', '\u{1a5f}'), + ('\u{1a7d}', '\u{1a7e}'), + ('\u{1a8a}', '\u{1a8f}'), + ('\u{1a9a}', '\u{1a9f}'), + ('\u{1aae}', '\u{1aaf}'), + ('\u{1acf}', '\u{1aff}'), + ('\u{1b4d}', '\u{1b4f}'), + ('\u{1b7f}', '\u{1b7f}'), + ('\u{1bf4}', '\u{1bfb}'), + ('\u{1c38}', '\u{1c3a}'), + ('\u{1c4a}', '\u{1c4c}'), + ('\u{1c89}', '\u{1c8f}'), + ('\u{1cbb}', '\u{1cbc}'), + ('\u{1cc8}', '\u{1ccf}'), + ('\u{1cfb}', '\u{1cff}'), + ('\u{1f16}', '\u{1f17}'), + ('\u{1f1e}', '\u{1f1f}'), + ('\u{1f46}', '\u{1f47}'), + ('\u{1f4e}', '\u{1f4f}'), + ('\u{1f58}', '\u{1f58}'), + ('\u{1f5a}', '\u{1f5a}'), + ('\u{1f5c}', '\u{1f5c}'), + ('\u{1f5e}', '\u{1f5e}'), + ('\u{1f7e}', '\u{1f7f}'), + ('\u{1fb5}', '\u{1fb5}'), + ('\u{1fc5}', '\u{1fc5}'), + ('\u{1fd4}', '\u{1fd5}'), + ('\u{1fdc}', '\u{1fdc}'), + ('\u{1ff0}', '\u{1ff1}'), + ('\u{1ff5}', '\u{1ff5}'), + ('\u{1fff}', '\u{1fff}'), + ('\u{200b}', '\u{200f}'), + ('\u{202a}', '\u{202e}'), + ('\u{2060}', '\u{206f}'), + ('\u{2072}', '\u{2073}'), + ('\u{208f}', '\u{208f}'), + ('\u{209d}', '\u{209f}'), + ('\u{20c1}', '\u{20cf}'), + ('\u{20f1}', '\u{20ff}'), + ('\u{218c}', '\u{218f}'), + ('\u{2427}', '\u{243f}'), + ('\u{244b}', '\u{245f}'), + ('\u{2b74}', '\u{2b75}'), + ('\u{2b96}', '\u{2b96}'), + ('\u{2cf4}', '\u{2cf8}'), + ('\u{2d26}', '\u{2d26}'), + ('\u{2d28}', '\u{2d2c}'), + ('\u{2d2e}', '\u{2d2f}'), + ('\u{2d68}', '\u{2d6e}'), + ('\u{2d71}', '\u{2d7e}'), + ('\u{2d97}', '\u{2d9f}'), + ('\u{2da7}', '\u{2da7}'), + ('\u{2daf}', '\u{2daf}'), + ('\u{2db7}', '\u{2db7}'), + ('\u{2dbf}', '\u{2dbf}'), + ('\u{2dc7}', '\u{2dc7}'), + ('\u{2dcf}', '\u{2dcf}'), + ('\u{2dd7}', '\u{2dd7}'), + ('\u{2ddf}', '\u{2ddf}'), + ('\u{2e5e}', '\u{2e7f}'), + ('\u{2e9a}', '\u{2e9a}'), + ('\u{2ef4}', '\u{2eff}'), + ('\u{2fd6}', '\u{2fef}'), + ('\u{2ffc}', '\u{2fff}'), + ('\u{3040}', '\u{3040}'), + ('\u{3097}', '\u{3098}'), + ('\u{3100}', '\u{3104}'), + ('\u{3130}', '\u{3130}'), + ('\u{318f}', '\u{318f}'), + ('\u{31e4}', '\u{31ef}'), + ('\u{321f}', '\u{321f}'), + ('\u{a48d}', '\u{a48f}'), + ('\u{a4c7}', '\u{a4cf}'), + ('\u{a62c}', '\u{a63f}'), + ('\u{a6f8}', '\u{a6ff}'), + ('\u{a7cb}', '\u{a7cf}'), + ('\u{a7d2}', '\u{a7d2}'), + ('\u{a7d4}', '\u{a7d4}'), + ('\u{a7da}', '\u{a7f1}'), + ('\u{a82d}', '\u{a82f}'), + ('\u{a83a}', '\u{a83f}'), + ('\u{a878}', '\u{a87f}'), + ('\u{a8c6}', '\u{a8cd}'), + ('\u{a8da}', '\u{a8df}'), + ('\u{a954}', '\u{a95e}'), + ('\u{a97d}', '\u{a97f}'), + ('\u{a9ce}', '\u{a9ce}'), + ('\u{a9da}', '\u{a9dd}'), + ('\u{a9ff}', '\u{a9ff}'), + ('\u{aa37}', '\u{aa3f}'), + ('\u{aa4e}', '\u{aa4f}'), + ('\u{aa5a}', '\u{aa5b}'), + ('\u{aac3}', '\u{aada}'), + ('\u{aaf7}', '\u{ab00}'), + ('\u{ab07}', '\u{ab08}'), + ('\u{ab0f}', '\u{ab10}'), + ('\u{ab17}', '\u{ab1f}'), + ('\u{ab27}', '\u{ab27}'), + ('\u{ab2f}', '\u{ab2f}'), + ('\u{ab6c}', '\u{ab6f}'), + ('\u{abee}', '\u{abef}'), + ('\u{abfa}', '\u{abff}'), + ('\u{d7a4}', '\u{d7af}'), + ('\u{d7c7}', '\u{d7ca}'), + ('\u{d7fc}', '\u{f8ff}'), + ('\u{fa6e}', '\u{fa6f}'), + ('\u{fada}', '\u{faff}'), + ('\u{fb07}', '\u{fb12}'), + ('\u{fb18}', '\u{fb1c}'), + ('\u{fb37}', '\u{fb37}'), + ('\u{fb3d}', '\u{fb3d}'), + ('\u{fb3f}', '\u{fb3f}'), + ('\u{fb42}', '\u{fb42}'), + ('\u{fb45}', '\u{fb45}'), + ('\u{fbc3}', '\u{fbd2}'), + ('\u{fd90}', '\u{fd91}'), + ('\u{fdc8}', '\u{fdce}'), + ('\u{fdd0}', '\u{fdef}'), + ('\u{fe1a}', '\u{fe1f}'), + ('\u{fe53}', '\u{fe53}'), + ('\u{fe67}', '\u{fe67}'), + ('\u{fe6c}', '\u{fe6f}'), + ('\u{fe75}', '\u{fe75}'), + ('\u{fefd}', '\u{ff00}'), + ('\u{ffbf}', '\u{ffc1}'), + ('\u{ffc8}', '\u{ffc9}'), + ('\u{ffd0}', '\u{ffd1}'), + ('\u{ffd8}', '\u{ffd9}'), + ('\u{ffdd}', '\u{ffdf}'), + ('\u{ffe7}', '\u{ffe7}'), + ('\u{ffef}', '\u{fffb}'), + ('\u{fffe}', '\u{ffff}'), + ('\u{1000c}', '\u{1000c}'), + ('\u{10027}', '\u{10027}'), + ('\u{1003b}', '\u{1003b}'), + ('\u{1003e}', '\u{1003e}'), + ('\u{1004e}', '\u{1004f}'), + ('\u{1005e}', '\u{1007f}'), + ('\u{100fb}', '\u{100ff}'), + ('\u{10103}', '\u{10106}'), + ('\u{10134}', '\u{10136}'), + ('\u{1018f}', '\u{1018f}'), + ('\u{1019d}', '\u{1019f}'), + ('\u{101a1}', '\u{101cf}'), + ('\u{101fe}', '\u{1027f}'), + ('\u{1029d}', '\u{1029f}'), + ('\u{102d1}', '\u{102df}'), + ('\u{102fc}', '\u{102ff}'), + ('\u{10324}', '\u{1032c}'), + ('\u{1034b}', '\u{1034f}'), + ('\u{1037b}', '\u{1037f}'), + ('\u{1039e}', '\u{1039e}'), + ('\u{103c4}', '\u{103c7}'), + ('\u{103d6}', '\u{103ff}'), + ('\u{1049e}', '\u{1049f}'), + ('\u{104aa}', '\u{104af}'), + ('\u{104d4}', '\u{104d7}'), + ('\u{104fc}', '\u{104ff}'), + ('\u{10528}', '\u{1052f}'), + ('\u{10564}', '\u{1056e}'), + ('\u{1057b}', '\u{1057b}'), + ('\u{1058b}', '\u{1058b}'), + ('\u{10593}', '\u{10593}'), + ('\u{10596}', '\u{10596}'), + ('\u{105a2}', '\u{105a2}'), + ('\u{105b2}', '\u{105b2}'), + ('\u{105ba}', '\u{105ba}'), + ('\u{105bd}', '\u{105ff}'), + ('\u{10737}', '\u{1073f}'), + ('\u{10756}', '\u{1075f}'), + ('\u{10768}', '\u{1077f}'), + ('\u{10786}', '\u{10786}'), + ('\u{107b1}', '\u{107b1}'), + ('\u{107bb}', '\u{107ff}'), + ('\u{10806}', '\u{10807}'), + ('\u{10809}', '\u{10809}'), + ('\u{10836}', '\u{10836}'), + ('\u{10839}', '\u{1083b}'), + ('\u{1083d}', '\u{1083e}'), + ('\u{10856}', '\u{10856}'), + ('\u{1089f}', '\u{108a6}'), + ('\u{108b0}', '\u{108df}'), + ('\u{108f3}', '\u{108f3}'), + ('\u{108f6}', '\u{108fa}'), + ('\u{1091c}', '\u{1091e}'), + ('\u{1093a}', '\u{1093e}'), + ('\u{10940}', '\u{1097f}'), + ('\u{109b8}', '\u{109bb}'), + ('\u{109d0}', '\u{109d1}'), + ('\u{10a04}', '\u{10a04}'), + ('\u{10a07}', '\u{10a0b}'), + ('\u{10a14}', '\u{10a14}'), + ('\u{10a18}', '\u{10a18}'), + ('\u{10a36}', '\u{10a37}'), + ('\u{10a3b}', '\u{10a3e}'), + ('\u{10a49}', '\u{10a4f}'), + ('\u{10a59}', '\u{10a5f}'), + ('\u{10aa0}', '\u{10abf}'), + ('\u{10ae7}', '\u{10aea}'), + ('\u{10af7}', '\u{10aff}'), + ('\u{10b36}', '\u{10b38}'), + ('\u{10b56}', '\u{10b57}'), + ('\u{10b73}', '\u{10b77}'), + ('\u{10b92}', '\u{10b98}'), + ('\u{10b9d}', '\u{10ba8}'), + ('\u{10bb0}', '\u{10bff}'), + ('\u{10c49}', '\u{10c7f}'), + ('\u{10cb3}', '\u{10cbf}'), + ('\u{10cf3}', '\u{10cf9}'), + ('\u{10d28}', '\u{10d2f}'), + ('\u{10d3a}', '\u{10e5f}'), + ('\u{10e7f}', '\u{10e7f}'), + ('\u{10eaa}', '\u{10eaa}'), + ('\u{10eae}', '\u{10eaf}'), + ('\u{10eb2}', '\u{10efc}'), + ('\u{10f28}', '\u{10f2f}'), + ('\u{10f5a}', '\u{10f6f}'), + ('\u{10f8a}', '\u{10faf}'), + ('\u{10fcc}', '\u{10fdf}'), + ('\u{10ff7}', '\u{10fff}'), + ('\u{1104e}', '\u{11051}'), + ('\u{11076}', '\u{1107e}'), + ('\u{110bd}', '\u{110bd}'), + ('\u{110c3}', '\u{110cf}'), + ('\u{110e9}', '\u{110ef}'), + ('\u{110fa}', '\u{110ff}'), + ('\u{11135}', '\u{11135}'), + ('\u{11148}', '\u{1114f}'), + ('\u{11177}', '\u{1117f}'), + ('\u{111e0}', '\u{111e0}'), + ('\u{111f5}', '\u{111ff}'), + ('\u{11212}', '\u{11212}'), + ('\u{11242}', '\u{1127f}'), + ('\u{11287}', '\u{11287}'), + ('\u{11289}', '\u{11289}'), + ('\u{1128e}', '\u{1128e}'), + ('\u{1129e}', '\u{1129e}'), + ('\u{112aa}', '\u{112af}'), + ('\u{112eb}', '\u{112ef}'), + ('\u{112fa}', '\u{112ff}'), + ('\u{11304}', '\u{11304}'), + ('\u{1130d}', '\u{1130e}'), + ('\u{11311}', '\u{11312}'), + ('\u{11329}', '\u{11329}'), + ('\u{11331}', '\u{11331}'), + ('\u{11334}', '\u{11334}'), + ('\u{1133a}', '\u{1133a}'), + ('\u{11345}', '\u{11346}'), + ('\u{11349}', '\u{1134a}'), + ('\u{1134e}', '\u{1134f}'), + ('\u{11351}', '\u{11356}'), + ('\u{11358}', '\u{1135c}'), + ('\u{11364}', '\u{11365}'), + ('\u{1136d}', '\u{1136f}'), + ('\u{11375}', '\u{113ff}'), + ('\u{1145c}', '\u{1145c}'), + ('\u{11462}', '\u{1147f}'), + ('\u{114c8}', '\u{114cf}'), + ('\u{114da}', '\u{1157f}'), + ('\u{115b6}', '\u{115b7}'), + ('\u{115de}', '\u{115ff}'), + ('\u{11645}', '\u{1164f}'), + ('\u{1165a}', '\u{1165f}'), + ('\u{1166d}', '\u{1167f}'), + ('\u{116ba}', '\u{116bf}'), + ('\u{116ca}', '\u{116ff}'), + ('\u{1171b}', '\u{1171c}'), + ('\u{1172c}', '\u{1172f}'), + ('\u{11747}', '\u{117ff}'), + ('\u{1183c}', '\u{1189f}'), + ('\u{118f3}', '\u{118fe}'), + ('\u{11907}', '\u{11908}'), + ('\u{1190a}', '\u{1190b}'), + ('\u{11914}', '\u{11914}'), + ('\u{11917}', '\u{11917}'), + ('\u{11936}', '\u{11936}'), + ('\u{11939}', '\u{1193a}'), + ('\u{11947}', '\u{1194f}'), + ('\u{1195a}', '\u{1199f}'), + ('\u{119a8}', '\u{119a9}'), + ('\u{119d8}', '\u{119d9}'), + ('\u{119e5}', '\u{119ff}'), + ('\u{11a48}', '\u{11a4f}'), + ('\u{11aa3}', '\u{11aaf}'), + ('\u{11af9}', '\u{11aff}'), + ('\u{11b0a}', '\u{11bff}'), + ('\u{11c09}', '\u{11c09}'), + ('\u{11c37}', '\u{11c37}'), + ('\u{11c46}', '\u{11c4f}'), + ('\u{11c6d}', '\u{11c6f}'), + ('\u{11c90}', '\u{11c91}'), + ('\u{11ca8}', '\u{11ca8}'), + ('\u{11cb7}', '\u{11cff}'), + ('\u{11d07}', '\u{11d07}'), + ('\u{11d0a}', '\u{11d0a}'), + ('\u{11d37}', '\u{11d39}'), + ('\u{11d3b}', '\u{11d3b}'), + ('\u{11d3e}', '\u{11d3e}'), + ('\u{11d48}', '\u{11d4f}'), + ('\u{11d5a}', '\u{11d5f}'), + ('\u{11d66}', '\u{11d66}'), + ('\u{11d69}', '\u{11d69}'), + ('\u{11d8f}', '\u{11d8f}'), + ('\u{11d92}', '\u{11d92}'), + ('\u{11d99}', '\u{11d9f}'), + ('\u{11daa}', '\u{11edf}'), + ('\u{11ef9}', '\u{11eff}'), + ('\u{11f11}', '\u{11f11}'), + ('\u{11f3b}', '\u{11f3d}'), + ('\u{11f5a}', '\u{11faf}'), + ('\u{11fb1}', '\u{11fbf}'), + ('\u{11ff2}', '\u{11ffe}'), + ('\u{1239a}', '\u{123ff}'), + ('\u{1246f}', '\u{1246f}'), + ('\u{12475}', '\u{1247f}'), + ('\u{12544}', '\u{12f8f}'), + ('\u{12ff3}', '\u{12fff}'), + ('\u{13430}', '\u{1343f}'), + ('\u{13456}', '\u{143ff}'), + ('\u{14647}', '\u{167ff}'), + ('\u{16a39}', '\u{16a3f}'), + ('\u{16a5f}', '\u{16a5f}'), + ('\u{16a6a}', '\u{16a6d}'), + ('\u{16abf}', '\u{16abf}'), + ('\u{16aca}', '\u{16acf}'), + ('\u{16aee}', '\u{16aef}'), + ('\u{16af6}', '\u{16aff}'), + ('\u{16b46}', '\u{16b4f}'), + ('\u{16b5a}', '\u{16b5a}'), + ('\u{16b62}', '\u{16b62}'), + ('\u{16b78}', '\u{16b7c}'), + ('\u{16b90}', '\u{16e3f}'), + ('\u{16e9b}', '\u{16eff}'), + ('\u{16f4b}', '\u{16f4e}'), + ('\u{16f88}', '\u{16f8e}'), + ('\u{16fa0}', '\u{16fdf}'), + ('\u{16fe5}', '\u{16fef}'), + ('\u{16ff2}', '\u{16fff}'), + ('\u{187f8}', '\u{187ff}'), + ('\u{18cd6}', '\u{18cff}'), + ('\u{18d09}', '\u{1afef}'), + ('\u{1aff4}', '\u{1aff4}'), + ('\u{1affc}', '\u{1affc}'), + ('\u{1afff}', '\u{1afff}'), + ('\u{1b123}', '\u{1b131}'), + ('\u{1b133}', '\u{1b14f}'), + ('\u{1b153}', '\u{1b154}'), + ('\u{1b156}', '\u{1b163}'), + ('\u{1b168}', '\u{1b16f}'), + ('\u{1b2fc}', '\u{1bbff}'), + ('\u{1bc6b}', '\u{1bc6f}'), + ('\u{1bc7d}', '\u{1bc7f}'), + ('\u{1bc89}', '\u{1bc8f}'), + ('\u{1bc9a}', '\u{1bc9b}'), + ('\u{1bca0}', '\u{1ceff}'), + ('\u{1cf2e}', '\u{1cf2f}'), + ('\u{1cf47}', '\u{1cf4f}'), + ('\u{1cfc4}', '\u{1cfff}'), + ('\u{1d0f6}', '\u{1d0ff}'), + ('\u{1d127}', '\u{1d128}'), + ('\u{1d173}', '\u{1d17a}'), + ('\u{1d1eb}', '\u{1d1ff}'), + ('\u{1d246}', '\u{1d2bf}'), + ('\u{1d2d4}', '\u{1d2df}'), + ('\u{1d2f4}', '\u{1d2ff}'), + ('\u{1d357}', '\u{1d35f}'), + ('\u{1d379}', '\u{1d3ff}'), + ('\u{1d455}', '\u{1d455}'), + ('\u{1d49d}', '\u{1d49d}'), + ('\u{1d4a0}', '\u{1d4a1}'), + ('\u{1d4a3}', '\u{1d4a4}'), + ('\u{1d4a7}', '\u{1d4a8}'), + ('\u{1d4ad}', '\u{1d4ad}'), + ('\u{1d4ba}', '\u{1d4ba}'), + ('\u{1d4bc}', '\u{1d4bc}'), + ('\u{1d4c4}', '\u{1d4c4}'), + ('\u{1d506}', '\u{1d506}'), + ('\u{1d50b}', '\u{1d50c}'), + ('\u{1d515}', '\u{1d515}'), + ('\u{1d51d}', '\u{1d51d}'), + ('\u{1d53a}', '\u{1d53a}'), + ('\u{1d53f}', '\u{1d53f}'), + ('\u{1d545}', '\u{1d545}'), + ('\u{1d547}', '\u{1d549}'), + ('\u{1d551}', '\u{1d551}'), + ('\u{1d6a6}', '\u{1d6a7}'), + ('\u{1d7cc}', '\u{1d7cd}'), + ('\u{1da8c}', '\u{1da9a}'), + ('\u{1daa0}', '\u{1daa0}'), + ('\u{1dab0}', '\u{1deff}'), + ('\u{1df1f}', '\u{1df24}'), + ('\u{1df2b}', '\u{1dfff}'), + ('\u{1e007}', '\u{1e007}'), + ('\u{1e019}', '\u{1e01a}'), + ('\u{1e022}', '\u{1e022}'), + ('\u{1e025}', '\u{1e025}'), + ('\u{1e02b}', '\u{1e02f}'), + ('\u{1e06e}', '\u{1e08e}'), + ('\u{1e090}', '\u{1e0ff}'), + ('\u{1e12d}', '\u{1e12f}'), + ('\u{1e13e}', '\u{1e13f}'), + ('\u{1e14a}', '\u{1e14d}'), + ('\u{1e150}', '\u{1e28f}'), + ('\u{1e2af}', '\u{1e2bf}'), + ('\u{1e2fa}', '\u{1e2fe}'), + ('\u{1e300}', '\u{1e4cf}'), + ('\u{1e4fa}', '\u{1e7df}'), + ('\u{1e7e7}', '\u{1e7e7}'), + ('\u{1e7ec}', '\u{1e7ec}'), + ('\u{1e7ef}', '\u{1e7ef}'), + ('\u{1e7ff}', '\u{1e7ff}'), + ('\u{1e8c5}', '\u{1e8c6}'), + ('\u{1e8d7}', '\u{1e8ff}'), + ('\u{1e94c}', '\u{1e94f}'), + ('\u{1e95a}', '\u{1e95d}'), + ('\u{1e960}', '\u{1ec70}'), + ('\u{1ecb5}', '\u{1ed00}'), + ('\u{1ed3e}', '\u{1edff}'), + ('\u{1ee04}', '\u{1ee04}'), + ('\u{1ee20}', '\u{1ee20}'), + ('\u{1ee23}', '\u{1ee23}'), + ('\u{1ee25}', '\u{1ee26}'), + ('\u{1ee28}', '\u{1ee28}'), + ('\u{1ee33}', '\u{1ee33}'), + ('\u{1ee38}', '\u{1ee38}'), + ('\u{1ee3a}', '\u{1ee3a}'), + ('\u{1ee3c}', '\u{1ee41}'), + ('\u{1ee43}', '\u{1ee46}'), + ('\u{1ee48}', '\u{1ee48}'), + ('\u{1ee4a}', '\u{1ee4a}'), + ('\u{1ee4c}', '\u{1ee4c}'), + ('\u{1ee50}', '\u{1ee50}'), + ('\u{1ee53}', '\u{1ee53}'), + ('\u{1ee55}', '\u{1ee56}'), + ('\u{1ee58}', '\u{1ee58}'), + ('\u{1ee5a}', '\u{1ee5a}'), + ('\u{1ee5c}', '\u{1ee5c}'), + ('\u{1ee5e}', '\u{1ee5e}'), + ('\u{1ee60}', '\u{1ee60}'), + ('\u{1ee63}', '\u{1ee63}'), + ('\u{1ee65}', '\u{1ee66}'), + ('\u{1ee6b}', '\u{1ee6b}'), + ('\u{1ee73}', '\u{1ee73}'), + ('\u{1ee78}', '\u{1ee78}'), + ('\u{1ee7d}', '\u{1ee7d}'), + ('\u{1ee7f}', '\u{1ee7f}'), + ('\u{1ee8a}', '\u{1ee8a}'), + ('\u{1ee9c}', '\u{1eea0}'), + ('\u{1eea4}', '\u{1eea4}'), + ('\u{1eeaa}', '\u{1eeaa}'), + ('\u{1eebc}', '\u{1eeef}'), + ('\u{1eef2}', '\u{1efff}'), + ('\u{1f02c}', '\u{1f02f}'), + ('\u{1f094}', '\u{1f09f}'), + ('\u{1f0af}', '\u{1f0b0}'), + ('\u{1f0c0}', '\u{1f0c0}'), + ('\u{1f0d0}', '\u{1f0d0}'), + ('\u{1f0f6}', '\u{1f0ff}'), + ('\u{1f1ae}', '\u{1f1e5}'), + ('\u{1f203}', '\u{1f20f}'), + ('\u{1f23c}', '\u{1f23f}'), + ('\u{1f249}', '\u{1f24f}'), + ('\u{1f252}', '\u{1f25f}'), + ('\u{1f266}', '\u{1f2ff}'), + ('\u{1f6d8}', '\u{1f6db}'), + ('\u{1f6ed}', '\u{1f6ef}'), + ('\u{1f6fd}', '\u{1f6ff}'), + ('\u{1f777}', '\u{1f77a}'), + ('\u{1f7da}', '\u{1f7df}'), + ('\u{1f7ec}', '\u{1f7ef}'), + ('\u{1f7f1}', '\u{1f7ff}'), + ('\u{1f80c}', '\u{1f80f}'), + ('\u{1f848}', '\u{1f84f}'), + ('\u{1f85a}', '\u{1f85f}'), + ('\u{1f888}', '\u{1f88f}'), + ('\u{1f8ae}', '\u{1f8af}'), + ('\u{1f8b2}', '\u{1f8ff}'), + ('\u{1fa54}', '\u{1fa5f}'), + ('\u{1fa6e}', '\u{1fa6f}'), + ('\u{1fa7d}', '\u{1fa7f}'), + ('\u{1fa89}', '\u{1fa8f}'), + ('\u{1fabe}', '\u{1fabe}'), + ('\u{1fac6}', '\u{1facd}'), + ('\u{1fadc}', '\u{1fadf}'), + ('\u{1fae9}', '\u{1faef}'), + ('\u{1faf9}', '\u{1faff}'), + ('\u{1fb93}', '\u{1fb93}'), + ('\u{1fbcb}', '\u{1fbef}'), + ('\u{1fbfa}', '\u{1ffff}'), + ('\u{2a6e0}', '\u{2a6ff}'), + ('\u{2b73a}', '\u{2b73f}'), + ('\u{2b81e}', '\u{2b81f}'), + ('\u{2cea2}', '\u{2ceaf}'), + ('\u{2ebe1}', '\u{2f7ff}'), + ('\u{2fa1e}', '\u{2ffff}'), + ('\u{3134b}', '\u{3134f}'), + ('\u{323b0}', '\u{e00ff}'), + ('\u{e01f0}', '\u{10ffff}'), +]; + +pub const OTHER_LETTER: &'static [(char, char)] = &[ + ('ª', 'ª'), + ('º', 'º'), + ('Æ»', 'Æ»'), + ('Ç€', 'ǃ'), + ('Ê”', 'Ê”'), + ('×', 'ת'), + ('ׯ', 'ײ'), + ('Ø ', 'Ø¿'), + ('Ù', 'ÙŠ'), + ('Ù®', 'Ù¯'), + ('Ù±', 'Û“'), + ('Û•', 'Û•'), + ('Û®', 'Û¯'), + ('Ûº', 'Û¼'), + ('Û¿', 'Û¿'), + ('Ü', 'Ü'), + ('Ü’', 'ܯ'), + ('Ý', 'Þ¥'), + ('Þ±', 'Þ±'), + ('ߊ', 'ߪ'), + ('à €', 'à •'), + ('à¡€', 'ࡘ'), + ('à¡ ', 'ࡪ'), + ('à¡°', 'ࢇ'), + ('ࢉ', 'ࢎ'), + ('ࢠ', 'ࣈ'), + ('ऄ', 'ह'), + ('ऽ', 'ऽ'), + ('à¥', 'à¥'), + ('क़', 'ॡ'), + ('ॲ', 'ঀ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('ঽ', 'ঽ'), + ('ৎ', 'ৎ'), + ('ড়', 'à§'), + ('য়', 'ৡ'), + ('ৰ', 'ৱ'), + ('ৼ', 'ৼ'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('ੲ', 'à©´'), + ('અ', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('ઽ', 'ઽ'), + ('à«', 'à«'), + ('à« ', 'à«¡'), + ('ૹ', 'ૹ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), + ('ଽ', 'ଽ'), + ('à­œ', 'à­'), + ('à­Ÿ', 'à­¡'), + ('à­±', 'à­±'), + ('ஃ', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'ஹ'), + ('à¯', 'à¯'), + ('à°…', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°¹'), + ('à°½', 'à°½'), + ('ౘ', 'ౚ'), + ('à±', 'à±'), + ('à± ', 'ౡ'), + ('ಀ', 'ಀ'), + ('ಅ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('ಽ', 'ಽ'), + ('à³', 'ೞ'), + ('à³ ', 'ೡ'), + ('à³±', 'à³²'), + ('à´„', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', 'à´º'), + ('à´½', 'à´½'), + ('ൎ', 'ൎ'), + ('ൔ', 'ൖ'), + ('ൟ', 'ൡ'), + ('ൺ', 'ൿ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('à¸', 'ะ'), + ('า', 'ำ'), + ('เ', 'ๅ'), + ('àº', 'ຂ'), + ('ຄ', 'ຄ'), + ('ຆ', 'ຊ'), + ('ຌ', 'ຣ'), + ('ລ', 'ລ'), + ('ວ', 'ະ'), + ('າ', 'ຳ'), + ('ຽ', 'ຽ'), + ('ເ', 'ໄ'), + ('ໜ', 'ໟ'), + ('ༀ', 'ༀ'), + ('ཀ', 'ཇ'), + ('ཉ', 'ཬ'), + ('ྈ', 'ྌ'), + ('က', 'ဪ'), + ('ဿ', 'ဿ'), + ('á', 'á•'), + ('áš', 'á'), + ('á¡', 'á¡'), + ('á¥', 'á¦'), + ('á®', 'á°'), + ('áµ', 'á‚'), + ('á‚Ž', 'á‚Ž'), + ('á„€', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹–'), + ('ዘ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'áš'), + ('ᎀ', 'áŽ'), + ('á', 'ᙬ'), + ('ᙯ', 'ᙿ'), + ('áš', 'ášš'), + ('áš ', 'ᛪ'), + ('á›±', 'ᛸ'), + ('ᜀ', 'ᜑ'), + ('ᜟ', 'ᜱ'), + ('á€', 'á‘'), + ('á ', 'á¬'), + ('á®', 'á°'), + ('ក', 'áž³'), + ('ៜ', 'ៜ'), + ('á  ', 'á¡‚'), + ('á¡„', 'ᡸ'), + ('ᢀ', 'ᢄ'), + ('ᢇ', 'ᢨ'), + ('ᢪ', 'ᢪ'), + ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), + ('á¥', 'ᥭ'), + ('ᥰ', 'ᥴ'), + ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), + ('ᨀ', 'ᨖ'), + ('ᨠ', 'á©”'), + ('ᬅ', 'ᬳ'), + ('á­…', 'á­Œ'), + ('ᮃ', 'á® '), + ('á®®', 'ᮯ'), + ('ᮺ', 'ᯥ'), + ('á°€', 'á°£'), + ('á±', 'á±'), + ('ᱚ', 'á±·'), + ('ᳩ', 'ᳬ'), + ('á³®', 'á³³'), + ('á³µ', 'ᳶ'), + ('ᳺ', 'ᳺ'), + ('ℵ', 'ℸ'), + ('â´°', 'ⵧ'), + ('ⶀ', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('〆', '〆'), + ('〼', '〼'), + ('ã', 'ã‚–'), + ('ã‚Ÿ', 'ã‚Ÿ'), + ('ã‚¡', 'ヺ'), + ('ヿ', 'ヿ'), + ('ã„…', 'ㄯ'), + ('ㄱ', 'ㆎ'), + ('ㆠ', 'ㆿ'), + ('ㇰ', 'ㇿ'), + ('ã€', '䶿'), + ('一', 'ꀔ'), + ('ꀖ', 'ê’Œ'), + ('ê“', 'ê“·'), + ('ꔀ', 'ꘋ'), + ('ê˜', 'ꘟ'), + ('ꘪ', 'ꘫ'), + ('ê™®', 'ê™®'), + ('êš ', 'ꛥ'), + ('êž', 'êž'), + ('ꟷ', 'ꟷ'), + ('ꟻ', 'ê '), + ('ê ƒ', 'ê …'), + ('ê ‡', 'ê Š'), + ('ê Œ', 'ê ¢'), + ('ê¡€', 'ꡳ'), + ('ꢂ', 'ꢳ'), + ('ꣲ', 'ꣷ'), + ('ꣻ', 'ꣻ'), + ('ꣽ', 'ꣾ'), + ('ꤊ', 'ꤥ'), + ('ꤰ', 'ꥆ'), + ('ꥠ', 'ꥼ'), + ('ꦄ', 'ꦲ'), + ('ꧠ', 'ꧤ'), + ('ꧧ', 'ꧯ'), + ('ꧺ', 'ꧾ'), + ('ꨀ', 'ꨨ'), + ('ê©€', 'ê©‚'), + ('ê©„', 'ê©‹'), + ('ê© ', 'ꩯ'), + ('ꩱ', 'ꩶ'), + ('ꩺ', 'ꩺ'), + ('ꩾ', 'ꪯ'), + ('ꪱ', 'ꪱ'), + ('ꪵ', 'ꪶ'), + ('ꪹ', 'ꪽ'), + ('ê«€', 'ê«€'), + ('ê«‚', 'ê«‚'), + ('ê«›', 'ê«œ'), + ('ê« ', 'ꫪ'), + ('ꫲ', 'ꫲ'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('ꯀ', 'ꯢ'), + ('ê°€', '힣'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), + ('ï©°', 'ï«™'), + ('ï¬', 'ï¬'), + ('ײַ', 'ﬨ'), + ('שׁ', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', 'ï®±'), + ('ﯓ', 'ï´½'), + ('ïµ', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·°', 'ï·»'), + ('ï¹°', 'ï¹´'), + ('ﹶ', 'ﻼ'), + ('ヲ', 'ッ'), + ('ï½±', 'ï¾'), + ('ï¾ ', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), + ('ðŠ€', 'ðŠœ'), + ('ðŠ ', 'ð‹'), + ('ðŒ€', 'ðŒŸ'), + ('ðŒ­', 'ð€'), + ('ð‚', 'ð‰'), + ('ð', 'ðµ'), + ('ðŽ€', 'ðŽ'), + ('ðŽ ', 'ðƒ'), + ('ðˆ', 'ð'), + ('ð‘', 'ð’'), + ('ð”€', 'ð”§'), + ('ð”°', 'ð•£'), + ('ð˜€', 'ðœ¶'), + ('ð€', 'ð•'), + ('ð ', 'ð§'), + ('ð €', 'ð …'), + ('ð ˆ', 'ð ˆ'), + ('ð Š', 'ð µ'), + ('ð ·', 'ð ¸'), + ('ð ¼', 'ð ¼'), + ('ð ¿', 'ð¡•'), + ('ð¡ ', 'ð¡¶'), + ('ð¢€', 'ð¢ž'), + ('ð£ ', 'ð£²'), + ('ð£´', 'ð£µ'), + ('ð¤€', 'ð¤•'), + ('ð¤ ', 'ð¤¹'), + ('ð¦€', 'ð¦·'), + ('ð¦¾', 'ð¦¿'), + ('ð¨€', 'ð¨€'), + ('ð¨', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨µ'), + ('ð© ', 'ð©¼'), + ('ðª€', 'ðªœ'), + ('ð«€', 'ð«‡'), + ('ð«‰', 'ð«¤'), + ('ð¬€', 'ð¬µ'), + ('ð­€', 'ð­•'), + ('ð­ ', 'ð­²'), + ('ð®€', 'ð®‘'), + ('ð°€', 'ð±ˆ'), + ('ð´€', 'ð´£'), + ('ðº€', 'ðº©'), + ('ðº°', 'ðº±'), + ('ð¼€', 'ð¼œ'), + ('ð¼§', 'ð¼§'), + ('ð¼°', 'ð½…'), + ('ð½°', 'ð¾'), + ('ð¾°', 'ð¿„'), + ('ð¿ ', 'ð¿¶'), + ('𑀃', 'ð‘€·'), + ('ð‘±', 'ð‘²'), + ('ð‘µ', 'ð‘µ'), + ('𑂃', '𑂯'), + ('ð‘ƒ', '𑃨'), + ('𑄃', '𑄦'), + ('ð‘…„', 'ð‘…„'), + ('ð‘…‡', 'ð‘…‡'), + ('ð‘…', 'ð‘…²'), + ('ð‘…¶', 'ð‘…¶'), + ('𑆃', '𑆲'), + ('ð‘‡', '𑇄'), + ('𑇚', '𑇚'), + ('𑇜', '𑇜'), + ('𑈀', '𑈑'), + ('𑈓', '𑈫'), + ('𑈿', '𑉀'), + ('ð‘Š€', '𑊆'), + ('𑊈', '𑊈'), + ('ð‘ŠŠ', 'ð‘Š'), + ('ð‘Š', 'ð‘Š'), + ('ð‘ŠŸ', '𑊨'), + ('ð‘Š°', 'ð‘‹ž'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('𑌽', '𑌽'), + ('ð‘', 'ð‘'), + ('ð‘', 'ð‘¡'), + ('ð‘€', 'ð‘´'), + ('𑑇', 'ð‘‘Š'), + ('ð‘‘Ÿ', 'ð‘‘¡'), + ('ð‘’€', 'ð‘’¯'), + ('ð‘“„', 'ð‘“…'), + ('𑓇', '𑓇'), + ('ð‘–€', 'ð‘–®'), + ('ð‘—˜', 'ð‘—›'), + ('𑘀', '𑘯'), + ('ð‘™„', 'ð‘™„'), + ('𑚀', '𑚪'), + ('𑚸', '𑚸'), + ('𑜀', '𑜚'), + ('ð‘€', 'ð‘†'), + ('ð‘ €', 'ð‘ «'), + ('𑣿', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤯'), + ('𑤿', '𑤿'), + ('ð‘¥', 'ð‘¥'), + ('𑦠', '𑦧'), + ('𑦪', 'ð‘§'), + ('𑧡', '𑧡'), + ('𑧣', '𑧣'), + ('𑨀', '𑨀'), + ('𑨋', '𑨲'), + ('𑨺', '𑨺'), + ('ð‘©', 'ð‘©'), + ('ð‘©œ', '𑪉'), + ('ð‘ª', 'ð‘ª'), + ('𑪰', '𑫸'), + ('ð‘°€', 'ð‘°ˆ'), + ('ð‘°Š', 'ð‘°®'), + ('𑱀', '𑱀'), + ('𑱲', 'ð‘²'), + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', 'ð‘´°'), + ('𑵆', '𑵆'), + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶉'), + ('𑶘', '𑶘'), + ('ð‘» ', 'ð‘»²'), + ('𑼂', '𑼂'), + ('𑼄', 'ð‘¼'), + ('𑼒', '𑼳'), + ('𑾰', '𑾰'), + ('ð’€€', 'ð’Ž™'), + ('ð’’€', '𒕃'), + ('ð’¾', 'ð’¿°'), + ('ð“€€', 'ð“¯'), + ('ð“‘', '𓑆'), + ('ð”€', '𔙆'), + ('ð– €', '𖨸'), + ('ð–©€', 'ð–©ž'), + ('ð–©°', '𖪾'), + ('ð–«', 'ð–«­'), + ('𖬀', '𖬯'), + ('ð–­£', 'ð–­·'), + ('ð–­½', 'ð–®'), + ('ð–¼€', '𖽊'), + ('ð–½', 'ð–½'), + ('ð—€€', '𘟷'), + ('𘠀', '𘳕'), + ('𘴀', '𘴈'), + ('𛀀', '𛄢'), + ('𛄲', '𛄲'), + ('ð›…', 'ð›…’'), + ('ð›…•', 'ð›…•'), + ('ð›…¤', 'ð›…§'), + ('ð›…°', '𛋻'), + ('ð›°€', '𛱪'), + ('ð›±°', 'ð›±¼'), + ('𛲀', '𛲈'), + ('ð›²', '𛲙'), + ('ð¼Š', 'ð¼Š'), + ('ðž„€', '𞄬'), + ('ðž…Ž', 'ðž…Ž'), + ('ðžŠ', '𞊭'), + ('ðž‹€', 'ðž‹«'), + ('ðž“', '𞓪'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), + ('ðž €', '𞣄'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('丽', 'ð¯¨'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), +]; + +pub const OTHER_NUMBER: &'static [(char, char)] = &[ + ('²', '³'), + ('¹', '¹'), + ('¼', '¾'), + ('৴', '৹'), + ('à­²', 'à­·'), + ('௰', '௲'), + ('౸', 'à±¾'), + ('൘', '൞'), + ('൰', '൸'), + ('༪', '༳'), + ('á©', 'á¼'), + ('៰', '៹'), + ('᧚', '᧚'), + ('â°', 'â°'), + ('â´', 'â¹'), + ('â‚€', '₉'), + ('â…', 'â…Ÿ'), + ('↉', '↉'), + ('â‘ ', 'â’›'), + ('⓪', 'â“¿'), + ('â¶', 'âž“'), + ('â³½', 'â³½'), + ('㆒', '㆕'), + ('㈠', '㈩'), + ('㉈', 'ã‰'), + ('㉑', '㉟'), + ('㊀', '㊉'), + ('㊱', '㊿'), + ('ê °', 'ê µ'), + ('ð„‡', 'ð„³'), + ('ð…µ', 'ð…¸'), + ('ð†Š', 'ð†‹'), + ('ð‹¡', 'ð‹»'), + ('ðŒ ', 'ðŒ£'), + ('ð¡˜', 'ð¡Ÿ'), + ('ð¡¹', 'ð¡¿'), + ('ð¢§', 'ð¢¯'), + ('ð£»', 'ð£¿'), + ('ð¤–', 'ð¤›'), + ('ð¦¼', 'ð¦½'), + ('ð§€', 'ð§'), + ('ð§’', 'ð§¿'), + ('ð©€', 'ð©ˆ'), + ('ð©½', 'ð©¾'), + ('ðª', 'ðªŸ'), + ('ð««', 'ð«¯'), + ('ð­˜', 'ð­Ÿ'), + ('ð­¸', 'ð­¿'), + ('ð®©', 'ð®¯'), + ('ð³º', 'ð³¿'), + ('ð¹ ', 'ð¹¾'), + ('ð¼', 'ð¼¦'), + ('ð½‘', 'ð½”'), + ('ð¿…', 'ð¿‹'), + ('ð‘’', 'ð‘¥'), + ('𑇡', '𑇴'), + ('𑜺', '𑜻'), + ('𑣪', 'ð‘£²'), + ('𑱚', '𑱬'), + ('ð‘¿€', 'ð‘¿”'), + ('ð–­›', 'ð–­¡'), + ('𖺀', 'ð–º–'), + ('ð‹€', 'ð‹“'), + ('ð‹ ', 'ð‹³'), + ('ð ', 'ð¸'), + ('𞣇', 'ðž£'), + ('ðž±±', '𞲫'), + ('ðž²­', '𞲯'), + ('ðž²±', 'ðž²´'), + ('ðž´', 'ðž´­'), + ('ðž´¯', 'ðž´½'), + ('🄀', '🄌'), +]; + +pub const OTHER_PUNCTUATION: &'static [(char, char)] = &[ + ('!', '#'), + ('%', '\''), + ('*', '*'), + (',', ','), + ('.', '/'), + (':', ';'), + ('?', '@'), + ('\\', '\\'), + ('¡', '¡'), + ('§', '§'), + ('¶', '·'), + ('¿', '¿'), + (';', ';'), + ('·', '·'), + ('Õš', 'ÕŸ'), + ('Ö‰', 'Ö‰'), + ('×€', '×€'), + ('׃', '׃'), + ('׆', '׆'), + ('׳', '×´'), + ('؉', 'ØŠ'), + ('ØŒ', 'Ø'), + ('Ø›', 'Ø›'), + ('Ø', 'ØŸ'), + ('Ùª', 'Ù­'), + ('Û”', 'Û”'), + ('Ü€', 'Ü'), + ('ß·', 'ß¹'), + ('à °', 'à ¾'), + ('à¡ž', 'à¡ž'), + ('।', '॥'), + ('॰', '॰'), + ('৽', '৽'), + ('੶', '੶'), + ('à«°', 'à«°'), + ('à±·', 'à±·'), + ('಄', '಄'), + ('à·´', 'à·´'), + ('à¹', 'à¹'), + ('๚', '๛'), + ('༄', '༒'), + ('༔', '༔'), + ('྅', '྅'), + ('à¿', 'à¿”'), + ('à¿™', 'à¿š'), + ('áŠ', 'á'), + ('჻', '჻'), + ('á ', 'á¨'), + ('á™®', 'á™®'), + ('᛫', 'á›­'), + ('᜵', '᜶'), + ('។', '៖'), + ('៘', '៚'), + ('á €', 'á …'), + ('á ‡', 'á Š'), + ('᥄', '᥅'), + ('᨞', '᨟'), + ('᪠', '᪦'), + ('᪨', '᪭'), + ('á­š', 'á­ '), + ('á­½', 'á­¾'), + ('᯼', '᯿'), + ('á°»', 'á°¿'), + ('á±¾', '᱿'), + ('á³€', '᳇'), + ('᳓', '᳓'), + ('‖', '‗'), + ('†', '‧'), + ('‰', '‸'), + ('※', '‾'), + ('â', 'âƒ'), + ('â‡', 'â‘'), + ('â“', 'â“'), + ('â•', 'âž'), + ('â³¹', 'â³¼'), + ('â³¾', '⳿'), + ('âµ°', 'âµ°'), + ('⸀', 'â¸'), + ('⸆', '⸈'), + ('⸋', '⸋'), + ('⸎', '⸖'), + ('⸘', '⸙'), + ('⸛', '⸛'), + ('⸞', '⸟'), + ('⸪', '⸮'), + ('⸰', '⸹'), + ('⸼', '⸿'), + ('â¹', 'â¹'), + ('⹃', 'â¹'), + ('â¹’', 'â¹”'), + ('ã€', '〃'), + ('〽', '〽'), + ('・', '・'), + ('꓾', 'ê“¿'), + ('ê˜', 'ê˜'), + ('꙳', '꙳'), + ('꙾', '꙾'), + ('꛲', 'ê›·'), + ('ê¡´', 'ê¡·'), + ('꣎', 'ê£'), + ('꣸', '꣺'), + ('꣼', '꣼'), + ('꤮', '꤯'), + ('꥟', '꥟'), + ('ê§', 'ê§'), + ('꧞', '꧟'), + ('ê©œ', 'ê©Ÿ'), + ('ê«ž', 'ê«Ÿ'), + ('ê«°', '꫱'), + ('꯫', '꯫'), + ('ï¸', '︖'), + ('︙', '︙'), + ('︰', '︰'), + ('ï¹…', '﹆'), + ('﹉', '﹌'), + ('ï¹', 'ï¹’'), + ('ï¹”', 'ï¹—'), + ('﹟', '﹡'), + ('﹨', '﹨'), + ('﹪', '﹫'), + ('ï¼', '#'), + ('ï¼…', '''), + ('*', '*'), + (',', ','), + ('.', 'ï¼'), + (':', 'ï¼›'), + ('?', 'ï¼ '), + ('ï¼¼', 'ï¼¼'), + ('。', '。'), + ('、', 'ï½¥'), + ('ð„€', 'ð„‚'), + ('ðŽŸ', 'ðŽŸ'), + ('ð', 'ð'), + ('ð•¯', 'ð•¯'), + ('ð¡—', 'ð¡—'), + ('ð¤Ÿ', 'ð¤Ÿ'), + ('ð¤¿', 'ð¤¿'), + ('ð©', 'ð©˜'), + ('ð©¿', 'ð©¿'), + ('ð«°', 'ð«¶'), + ('ð¬¹', 'ð¬¿'), + ('ð®™', 'ð®œ'), + ('ð½•', 'ð½™'), + ('ð¾†', 'ð¾‰'), + ('ð‘‡', 'ð‘'), + ('ð‘‚»', 'ð‘‚¼'), + ('ð‘‚¾', 'ð‘ƒ'), + ('ð‘…€', 'ð‘…ƒ'), + ('ð‘…´', 'ð‘…µ'), + ('𑇅', '𑇈'), + ('ð‘‡', 'ð‘‡'), + ('𑇛', '𑇛'), + ('ð‘‡', '𑇟'), + ('𑈸', '𑈽'), + ('ð‘Š©', 'ð‘Š©'), + ('ð‘‘‹', 'ð‘‘'), + ('ð‘‘š', 'ð‘‘›'), + ('ð‘‘', 'ð‘‘'), + ('𑓆', '𑓆'), + ('ð‘—', 'ð‘——'), + ('ð‘™', '𑙃'), + ('ð‘™ ', '𑙬'), + ('ð‘š¹', 'ð‘š¹'), + ('𑜼', '𑜾'), + ('ð‘ »', 'ð‘ »'), + ('𑥄', '𑥆'), + ('𑧢', '𑧢'), + ('𑨿', '𑩆'), + ('𑪚', '𑪜'), + ('𑪞', '𑪢'), + ('𑬀', '𑬉'), + ('ð‘±', '𑱅'), + ('𑱰', '𑱱'), + ('ð‘»·', '𑻸'), + ('𑽃', 'ð‘½'), + ('ð‘¿¿', 'ð‘¿¿'), + ('ð’‘°', 'ð’‘´'), + ('ð’¿±', 'ð’¿²'), + ('ð–©®', '𖩯'), + ('ð–«µ', 'ð–«µ'), + ('ð–¬·', '𖬻'), + ('ð–­„', 'ð–­„'), + ('ð–º—', '𖺚'), + ('ð–¿¢', 'ð–¿¢'), + ('𛲟', '𛲟'), + ('ðª‡', 'ðª‹'), + ('𞥞', '𞥟'), +]; + +pub const OTHER_SYMBOL: &'static [(char, char)] = &[ + ('¦', '¦'), + ('©', '©'), + ('®', '®'), + ('°', '°'), + ('Ò‚', 'Ò‚'), + ('Ö', 'ÖŽ'), + ('ØŽ', 'Ø'), + ('Ûž', 'Ûž'), + ('Û©', 'Û©'), + ('Û½', 'Û¾'), + ('߶', '߶'), + ('৺', '৺'), + ('à­°', 'à­°'), + ('௳', '௸'), + ('௺', '௺'), + ('౿', '౿'), + ('àµ', 'àµ'), + ('൹', '൹'), + ('à¼', '༃'), + ('༓', '༓'), + ('༕', '༗'), + ('༚', '༟'), + ('༴', '༴'), + ('༶', '༶'), + ('༸', '༸'), + ('྾', 'à¿…'), + ('࿇', 'à¿Œ'), + ('à¿Ž', 'à¿'), + ('à¿•', '࿘'), + ('á‚ž', 'á‚Ÿ'), + ('áŽ', '᎙'), + ('á™­', 'á™­'), + ('᥀', '᥀'), + ('᧞', '᧿'), + ('á­¡', 'á­ª'), + ('á­´', 'á­¼'), + ('â„€', 'â„'), + ('℃', '℆'), + ('℈', '℉'), + ('â„”', 'â„”'), + ('â„–', 'â„—'), + ('â„ž', 'â„£'), + ('â„¥', 'â„¥'), + ('℧', '℧'), + ('â„©', 'â„©'), + ('â„®', 'â„®'), + ('℺', 'â„»'), + ('â…Š', 'â…Š'), + ('â…Œ', 'â…'), + ('â…', 'â…'), + ('↊', '↋'), + ('↕', '↙'), + ('↜', '↟'), + ('↡', '↢'), + ('↤', '↥'), + ('↧', '↭'), + ('↯', 'â‡'), + ('â‡', '⇑'), + ('⇓', '⇓'), + ('⇕', '⇳'), + ('⌀', '⌇'), + ('⌌', '⌟'), + ('⌢', '⌨'), + ('⌫', 'â»'), + ('â½', '⎚'), + ('⎴', 'â›'), + ('â¢', 'â¦'), + ('â‘€', 'â‘Š'), + ('â’œ', 'â“©'), + ('─', 'â–¶'), + ('â–¸', 'â—€'), + ('â—‚', 'â—·'), + ('☀', 'â™®'), + ('â™°', 'â§'), + ('âž”', 'âž¿'), + ('â €', '⣿'), + ('⬀', '⬯'), + ('â­…', 'â­†'), + ('â­', 'â­³'), + ('â­¶', '⮕'), + ('â®—', '⯿'), + ('â³¥', '⳪'), + ('â¹', '⹑'), + ('⺀', '⺙'), + ('⺛', '⻳'), + ('â¼€', 'â¿•'), + ('â¿°', 'â¿»'), + ('〄', '〄'), + ('〒', '〓'), + ('〠', '〠'), + ('〶', '〷'), + ('〾', '〿'), + ('ã†', '㆑'), + ('㆖', '㆟'), + ('㇀', '㇣'), + ('㈀', '㈞'), + ('㈪', '㉇'), + ('ã‰', 'ã‰'), + ('㉠', '㉿'), + ('㊊', '㊰'), + ('ã‹€', 'ã¿'), + ('ä·€', 'ä·¿'), + ('ê’', '꓆'), + ('ê ¨', 'ê «'), + ('ê ¶', 'ê ·'), + ('ê ¹', 'ê ¹'), + ('ê©·', '꩹'), + ('ïµ€', 'ïµ'), + ('ï·', 'ï·'), + ('ï·½', 'ï·¿'), + ('¦', '¦'), + ('│', '│'), + ('ï¿­', 'ï¿®'), + ('', '�'), + ('ð„·', 'ð„¿'), + ('ð…¹', 'ð†‰'), + ('ð†Œ', 'ð†Ž'), + ('ð†', 'ð†œ'), + ('ð† ', 'ð† '), + ('ð‡', 'ð‡¼'), + ('ð¡·', 'ð¡¸'), + ('ð«ˆ', 'ð«ˆ'), + ('𑜿', '𑜿'), + ('ð‘¿•', 'ð‘¿œ'), + ('ð‘¿¡', 'ð‘¿±'), + ('𖬼', '𖬿'), + ('ð–­…', 'ð–­…'), + ('𛲜', '𛲜'), + ('ðœ½', '𜿃'), + ('ð€€', 'ðƒµ'), + ('ð„€', 'ð„¦'), + ('ð„©', 'ð…¤'), + ('ð…ª', 'ð…¬'), + ('ð†ƒ', 'ð†„'), + ('ð†Œ', 'ð†©'), + ('ð†®', 'ð‡ª'), + ('ðˆ€', 'ð‰'), + ('ð‰…', 'ð‰…'), + ('ðŒ€', 'ð–'), + ('ð €', 'ð§¿'), + ('ð¨·', 'ð¨º'), + ('ð©­', 'ð©´'), + ('ð©¶', 'ðªƒ'), + ('ðª…', 'ðª†'), + ('ðž…', 'ðž…'), + ('𞲬', '𞲬'), + ('ðž´®', 'ðž´®'), + ('🀀', '🀫'), + ('🀰', '🂓'), + ('🂠', '🂮'), + ('🂱', '🂿'), + ('ðŸƒ', 'ðŸƒ'), + ('🃑', '🃵'), + ('ðŸ„', '🆭'), + ('🇦', '🈂'), + ('ðŸˆ', '🈻'), + ('🉀', '🉈'), + ('ðŸ‰', '🉑'), + ('🉠', '🉥'), + ('🌀', 'ðŸº'), + ('ðŸ€', '🛗'), + ('🛜', '🛬'), + ('🛰', '🛼'), + ('🜀', 'ðŸ¶'), + ('ðŸ»', '🟙'), + ('🟠', '🟫'), + ('🟰', '🟰'), + ('🠀', '🠋'), + ('ðŸ ', '🡇'), + ('ðŸ¡', '🡙'), + ('🡠', '🢇'), + ('ðŸ¢', '🢭'), + ('🢰', '🢱'), + ('🤀', '🩓'), + ('🩠', '🩭'), + ('🩰', '🩼'), + ('🪀', '🪈'), + ('ðŸª', '🪽'), + ('🪿', '🫅'), + ('🫎', '🫛'), + ('🫠', '🫨'), + ('🫰', '🫸'), + ('🬀', '🮒'), + ('🮔', '🯊'), +]; + +pub const PARAGRAPH_SEPARATOR: &'static [(char, char)] = + &[('\u{2029}', '\u{2029}')]; + +pub const PRIVATE_USE: &'static [(char, char)] = &[ + ('\u{e000}', '\u{f8ff}'), + ('\u{f0000}', '\u{ffffd}'), + ('\u{100000}', '\u{10fffd}'), +]; + +pub const PUNCTUATION: &'static [(char, char)] = &[ + ('!', '#'), + ('%', '*'), + (',', '/'), + (':', ';'), + ('?', '@'), + ('[', ']'), + ('_', '_'), + ('{', '{'), + ('}', '}'), + ('¡', '¡'), + ('§', '§'), + ('«', '«'), + ('¶', '·'), + ('»', '»'), + ('¿', '¿'), + (';', ';'), + ('·', '·'), + ('Õš', 'ÕŸ'), + ('Ö‰', 'ÖŠ'), + ('Ö¾', 'Ö¾'), + ('×€', '×€'), + ('׃', '׃'), + ('׆', '׆'), + ('׳', '×´'), + ('؉', 'ØŠ'), + ('ØŒ', 'Ø'), + ('Ø›', 'Ø›'), + ('Ø', 'ØŸ'), + ('Ùª', 'Ù­'), + ('Û”', 'Û”'), + ('Ü€', 'Ü'), + ('ß·', 'ß¹'), + ('à °', 'à ¾'), + ('à¡ž', 'à¡ž'), + ('।', '॥'), + ('॰', '॰'), + ('৽', '৽'), + ('੶', '੶'), + ('à«°', 'à«°'), + ('à±·', 'à±·'), + ('಄', '಄'), + ('à·´', 'à·´'), + ('à¹', 'à¹'), + ('๚', '๛'), + ('༄', '༒'), + ('༔', '༔'), + ('༺', '༽'), + ('྅', '྅'), + ('à¿', 'à¿”'), + ('à¿™', 'à¿š'), + ('áŠ', 'á'), + ('჻', '჻'), + ('á ', 'á¨'), + ('á€', 'á€'), + ('á™®', 'á™®'), + ('áš›', 'ášœ'), + ('᛫', 'á›­'), + ('᜵', '᜶'), + ('។', '៖'), + ('៘', '៚'), + ('á €', 'á Š'), + ('᥄', '᥅'), + ('᨞', '᨟'), + ('᪠', '᪦'), + ('᪨', '᪭'), + ('á­š', 'á­ '), + ('á­½', 'á­¾'), + ('᯼', '᯿'), + ('á°»', 'á°¿'), + ('á±¾', '᱿'), + ('á³€', '᳇'), + ('᳓', '᳓'), + ('â€', '‧'), + ('‰', 'âƒ'), + ('â…', 'â‘'), + ('â“', 'âž'), + ('â½', 'â¾'), + ('â‚', 'â‚Ž'), + ('⌈', '⌋'), + ('〈', '〉'), + ('â¨', 'âµ'), + ('⟅', '⟆'), + ('⟦', '⟯'), + ('⦃', '⦘'), + ('⧘', '⧛'), + ('⧼', '⧽'), + ('â³¹', 'â³¼'), + ('â³¾', '⳿'), + ('âµ°', 'âµ°'), + ('⸀', '⸮'), + ('⸰', 'â¹'), + ('â¹’', 'â¹'), + ('ã€', '〃'), + ('〈', '】'), + ('〔', '〟'), + ('〰', '〰'), + ('〽', '〽'), + ('ã‚ ', 'ã‚ '), + ('・', '・'), + ('꓾', 'ê“¿'), + ('ê˜', 'ê˜'), + ('꙳', '꙳'), + ('꙾', '꙾'), + ('꛲', 'ê›·'), + ('ê¡´', 'ê¡·'), + ('꣎', 'ê£'), + ('꣸', '꣺'), + ('꣼', '꣼'), + ('꤮', '꤯'), + ('꥟', '꥟'), + ('ê§', 'ê§'), + ('꧞', '꧟'), + ('ê©œ', 'ê©Ÿ'), + ('ê«ž', 'ê«Ÿ'), + ('ê«°', '꫱'), + ('꯫', '꯫'), + ('ï´¾', 'ï´¿'), + ('ï¸', '︙'), + ('︰', 'ï¹’'), + ('ï¹”', '﹡'), + ('ï¹£', 'ï¹£'), + ('﹨', '﹨'), + ('﹪', '﹫'), + ('ï¼', '#'), + ('ï¼…', '*'), + (',', 'ï¼'), + (':', 'ï¼›'), + ('?', 'ï¼ '), + ('ï¼»', 'ï¼½'), + ('_', '_'), + ('ï½›', 'ï½›'), + ('ï½', 'ï½'), + ('⦅', 'ï½¥'), + ('ð„€', 'ð„‚'), + ('ðŽŸ', 'ðŽŸ'), + ('ð', 'ð'), + ('ð•¯', 'ð•¯'), + ('ð¡—', 'ð¡—'), + ('ð¤Ÿ', 'ð¤Ÿ'), + ('ð¤¿', 'ð¤¿'), + ('ð©', 'ð©˜'), + ('ð©¿', 'ð©¿'), + ('ð«°', 'ð«¶'), + ('ð¬¹', 'ð¬¿'), + ('ð®™', 'ð®œ'), + ('ðº­', 'ðº­'), + ('ð½•', 'ð½™'), + ('ð¾†', 'ð¾‰'), + ('ð‘‡', 'ð‘'), + ('ð‘‚»', 'ð‘‚¼'), + ('ð‘‚¾', 'ð‘ƒ'), + ('ð‘…€', 'ð‘…ƒ'), + ('ð‘…´', 'ð‘…µ'), + ('𑇅', '𑇈'), + ('ð‘‡', 'ð‘‡'), + ('𑇛', '𑇛'), + ('ð‘‡', '𑇟'), + ('𑈸', '𑈽'), + ('ð‘Š©', 'ð‘Š©'), + ('ð‘‘‹', 'ð‘‘'), + ('ð‘‘š', 'ð‘‘›'), + ('ð‘‘', 'ð‘‘'), + ('𑓆', '𑓆'), + ('ð‘—', 'ð‘——'), + ('ð‘™', '𑙃'), + ('ð‘™ ', '𑙬'), + ('ð‘š¹', 'ð‘š¹'), + ('𑜼', '𑜾'), + ('ð‘ »', 'ð‘ »'), + ('𑥄', '𑥆'), + ('𑧢', '𑧢'), + ('𑨿', '𑩆'), + ('𑪚', '𑪜'), + ('𑪞', '𑪢'), + ('𑬀', '𑬉'), + ('ð‘±', '𑱅'), + ('𑱰', '𑱱'), + ('ð‘»·', '𑻸'), + ('𑽃', 'ð‘½'), + ('ð‘¿¿', 'ð‘¿¿'), + ('ð’‘°', 'ð’‘´'), + ('ð’¿±', 'ð’¿²'), + ('ð–©®', '𖩯'), + ('ð–«µ', 'ð–«µ'), + ('ð–¬·', '𖬻'), + ('ð–­„', 'ð–­„'), + ('ð–º—', '𖺚'), + ('ð–¿¢', 'ð–¿¢'), + ('𛲟', '𛲟'), + ('ðª‡', 'ðª‹'), + ('𞥞', '𞥟'), +]; + +pub const SEPARATOR: &'static [(char, char)] = &[ + (' ', ' '), + ('\u{a0}', '\u{a0}'), + ('\u{1680}', '\u{1680}'), + ('\u{2000}', '\u{200a}'), + ('\u{2028}', '\u{2029}'), + ('\u{202f}', '\u{202f}'), + ('\u{205f}', '\u{205f}'), + ('\u{3000}', '\u{3000}'), +]; + +pub const SPACE_SEPARATOR: &'static [(char, char)] = &[ + (' ', ' '), + ('\u{a0}', '\u{a0}'), + ('\u{1680}', '\u{1680}'), + ('\u{2000}', '\u{200a}'), + ('\u{202f}', '\u{202f}'), + ('\u{205f}', '\u{205f}'), + ('\u{3000}', '\u{3000}'), +]; + +pub const SPACING_MARK: &'static [(char, char)] = &[ + ('ः', 'ः'), + ('ऻ', 'ऻ'), + ('ा', 'ी'), + ('ॉ', 'ौ'), + ('ॎ', 'à¥'), + ('ং', 'ঃ'), + ('\u{9be}', 'ী'), + ('ে', 'ৈ'), + ('ো', 'ৌ'), + ('\u{9d7}', '\u{9d7}'), + ('ਃ', 'ਃ'), + ('ਾ', 'à©€'), + ('ઃ', 'ઃ'), + ('ા', 'à«€'), + ('ૉ', 'ૉ'), + ('à«‹', 'à«Œ'), + ('ଂ', 'ଃ'), + ('\u{b3e}', '\u{b3e}'), + ('à­€', 'à­€'), + ('à­‡', 'à­ˆ'), + ('à­‹', 'à­Œ'), + ('\u{b57}', '\u{b57}'), + ('\u{bbe}', 'ி'), + ('à¯', 'ூ'), + ('ெ', 'ை'), + ('ொ', 'ௌ'), + ('\u{bd7}', '\u{bd7}'), + ('à°', 'à°ƒ'), + ('à±', 'ౄ'), + ('ಂ', 'ಃ'), + ('ಾ', 'ಾ'), + ('à³€', 'ೄ'), + ('ೇ', 'ೈ'), + ('ೊ', 'ೋ'), + ('\u{cd5}', '\u{cd6}'), + ('à³³', 'à³³'), + ('à´‚', 'à´ƒ'), + ('\u{d3e}', 'ീ'), + ('െ', 'ൈ'), + ('ൊ', 'ൌ'), + ('\u{d57}', '\u{d57}'), + ('ං', 'ඃ'), + ('\u{dcf}', 'à·‘'), + ('à·˜', '\u{ddf}'), + ('à·²', 'à·³'), + ('༾', '༿'), + ('ཿ', 'ཿ'), + ('ါ', 'ာ'), + ('ေ', 'ေ'), + ('း', 'း'), + ('ျ', 'ြ'), + ('á–', 'á—'), + ('á¢', 'á¤'), + ('á§', 'á­'), + ('ႃ', 'á‚„'), + ('ႇ', 'á‚Œ'), + ('á‚', 'á‚'), + ('á‚š', 'á‚œ'), + ('᜕', '᜕'), + ('᜴', '᜴'), + ('ា', 'ា'), + ('áž¾', 'ៅ'), + ('ះ', 'ៈ'), + ('ᤣ', 'ᤦ'), + ('ᤩ', 'ᤫ'), + ('ᤰ', 'ᤱ'), + ('ᤳ', 'ᤸ'), + ('ᨙ', 'ᨚ'), + ('á©•', 'á©•'), + ('á©—', 'á©—'), + ('á©¡', 'á©¡'), + ('á©£', 'ᩤ'), + ('á©­', 'ᩲ'), + ('ᬄ', 'ᬄ'), + ('\u{1b35}', '\u{1b35}'), + ('ᬻ', 'ᬻ'), + ('ᬽ', 'á­'), + ('á­ƒ', 'á­„'), + ('ᮂ', 'ᮂ'), + ('ᮡ', 'ᮡ'), + ('ᮦ', 'ᮧ'), + ('᮪', '᮪'), + ('ᯧ', 'ᯧ'), + ('ᯪ', 'ᯬ'), + ('ᯮ', 'ᯮ'), + ('᯲', '᯳'), + ('á°¤', 'á°«'), + ('á°´', 'á°µ'), + ('᳡', '᳡'), + ('á³·', 'á³·'), + ('\u{302e}', '\u{302f}'), + ('ê £', 'ê ¤'), + ('ê §', 'ê §'), + ('ꢀ', 'ê¢'), + ('ꢴ', 'ꣃ'), + ('ꥒ', '꥓'), + ('ꦃ', 'ꦃ'), + ('ꦴ', 'ꦵ'), + ('ꦺ', 'ꦻ'), + ('ꦾ', '꧀'), + ('ꨯ', 'ꨰ'), + ('ꨳ', 'ꨴ'), + ('ê©', 'ê©'), + ('ê©»', 'ê©»'), + ('ꩽ', 'ꩽ'), + ('ê««', 'ê««'), + ('ê«®', 'ꫯ'), + ('ꫵ', 'ꫵ'), + ('ꯣ', 'ꯤ'), + ('ꯦ', 'ꯧ'), + ('ꯩ', 'ꯪ'), + ('꯬', '꯬'), + ('ð‘€€', 'ð‘€€'), + ('𑀂', '𑀂'), + ('ð‘‚‚', 'ð‘‚‚'), + ('ð‘‚°', 'ð‘‚²'), + ('ð‘‚·', '𑂸'), + ('𑄬', '𑄬'), + ('ð‘……', 'ð‘…†'), + ('𑆂', '𑆂'), + ('𑆳', '𑆵'), + ('𑆿', '𑇀'), + ('𑇎', '𑇎'), + ('𑈬', '𑈮'), + ('𑈲', '𑈳'), + ('𑈵', '𑈵'), + ('ð‘‹ ', 'ð‘‹¢'), + ('𑌂', '𑌃'), + ('\u{1133e}', '𑌿'), + ('ð‘', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘'), + ('\u{11357}', '\u{11357}'), + ('ð‘¢', 'ð‘£'), + ('ð‘µ', 'ð‘·'), + ('ð‘‘€', 'ð‘‘'), + ('ð‘‘…', 'ð‘‘…'), + ('\u{114b0}', 'ð‘’²'), + ('ð‘’¹', 'ð‘’¹'), + ('ð‘’»', 'ð‘’¾'), + ('ð‘“', 'ð‘“'), + ('\u{115af}', 'ð‘–±'), + ('ð‘–¸', 'ð‘–»'), + ('ð‘–¾', 'ð‘–¾'), + ('𑘰', '𑘲'), + ('𑘻', '𑘼'), + ('𑘾', '𑘾'), + ('𑚬', '𑚬'), + ('ð‘š®', '𑚯'), + ('𑚶', '𑚶'), + ('𑜠', '𑜡'), + ('𑜦', '𑜦'), + ('ð‘ ¬', 'ð‘ ®'), + ('ð‘ ¸', 'ð‘ ¸'), + ('\u{11930}', '𑤵'), + ('𑤷', '𑤸'), + ('𑤽', '𑤽'), + ('ð‘¥€', 'ð‘¥€'), + ('𑥂', '𑥂'), + ('𑧑', '𑧓'), + ('𑧜', '𑧟'), + ('𑧤', '𑧤'), + ('𑨹', '𑨹'), + ('ð‘©—', '𑩘'), + ('𑪗', '𑪗'), + ('ð‘°¯', 'ð‘°¯'), + ('ð‘°¾', 'ð‘°¾'), + ('𑲩', '𑲩'), + ('𑲱', '𑲱'), + ('𑲴', '𑲴'), + ('𑶊', '𑶎'), + ('𑶓', '𑶔'), + ('𑶖', '𑶖'), + ('ð‘»µ', '𑻶'), + ('𑼃', '𑼃'), + ('𑼴', '𑼵'), + ('𑼾', '𑼿'), + ('ð‘½', 'ð‘½'), + ('𖽑', '𖾇'), + ('ð–¿°', 'ð–¿±'), + ('\u{1d165}', 'ð…¦'), + ('ð…­', '\u{1d172}'), +]; + +pub const SYMBOL: &'static [(char, char)] = &[ + ('$', '$'), + ('+', '+'), + ('<', '>'), + ('^', '^'), + ('`', '`'), + ('|', '|'), + ('~', '~'), + ('¢', '¦'), + ('¨', '©'), + ('¬', '¬'), + ('®', '±'), + ('´', '´'), + ('¸', '¸'), + ('×', '×'), + ('÷', '÷'), + ('Ë‚', 'Ë…'), + ('Ë’', 'ËŸ'), + ('Ë¥', 'Ë«'), + ('Ë­', 'Ë­'), + ('˯', 'Ë¿'), + ('͵', '͵'), + ('΄', 'Î…'), + ('϶', '϶'), + ('Ò‚', 'Ò‚'), + ('Ö', 'Ö'), + ('؆', '؈'), + ('Ø‹', 'Ø‹'), + ('ØŽ', 'Ø'), + ('Ûž', 'Ûž'), + ('Û©', 'Û©'), + ('Û½', 'Û¾'), + ('߶', '߶'), + ('ß¾', 'ß¿'), + ('࢈', '࢈'), + ('৲', '৳'), + ('৺', '৻'), + ('૱', '૱'), + ('à­°', 'à­°'), + ('௳', '௺'), + ('౿', '౿'), + ('àµ', 'àµ'), + ('൹', '൹'), + ('฿', '฿'), + ('à¼', '༃'), + ('༓', '༓'), + ('༕', '༗'), + ('༚', '༟'), + ('༴', '༴'), + ('༶', '༶'), + ('༸', '༸'), + ('྾', 'à¿…'), + ('࿇', 'à¿Œ'), + ('à¿Ž', 'à¿'), + ('à¿•', '࿘'), + ('á‚ž', 'á‚Ÿ'), + ('áŽ', '᎙'), + ('á™­', 'á™­'), + ('៛', '៛'), + ('᥀', '᥀'), + ('᧞', '᧿'), + ('á­¡', 'á­ª'), + ('á­´', 'á­¼'), + ('á¾½', 'á¾½'), + ('᾿', 'á¿'), + ('á¿', 'á¿'), + ('á¿', 'á¿Ÿ'), + ('á¿­', '`'), + ('´', '῾'), + ('â„', 'â„'), + ('â’', 'â’'), + ('âº', 'â¼'), + ('â‚Š', 'â‚Œ'), + ('â‚ ', '⃀'), + ('â„€', 'â„'), + ('℃', '℆'), + ('℈', '℉'), + ('â„”', 'â„”'), + ('â„–', '℘'), + ('â„ž', 'â„£'), + ('â„¥', 'â„¥'), + ('℧', '℧'), + ('â„©', 'â„©'), + ('â„®', 'â„®'), + ('℺', 'â„»'), + ('â…€', 'â…„'), + ('â…Š', 'â…'), + ('â…', 'â…'), + ('↊', '↋'), + ('â†', '⌇'), + ('⌌', '⌨'), + ('⌫', 'â¦'), + ('â‘€', 'â‘Š'), + ('â’œ', 'â“©'), + ('─', 'â§'), + ('âž”', '⟄'), + ('⟇', '⟥'), + ('⟰', '⦂'), + ('⦙', '⧗'), + ('⧜', '⧻'), + ('⧾', 'â­³'), + ('â­¶', '⮕'), + ('â®—', '⯿'), + ('â³¥', '⳪'), + ('â¹', '⹑'), + ('⺀', '⺙'), + ('⺛', '⻳'), + ('â¼€', 'â¿•'), + ('â¿°', 'â¿»'), + ('〄', '〄'), + ('〒', '〓'), + ('〠', '〠'), + ('〶', '〷'), + ('〾', '〿'), + ('ã‚›', 'ã‚œ'), + ('ã†', '㆑'), + ('㆖', '㆟'), + ('㇀', '㇣'), + ('㈀', '㈞'), + ('㈪', '㉇'), + ('ã‰', 'ã‰'), + ('㉠', '㉿'), + ('㊊', '㊰'), + ('ã‹€', 'ã¿'), + ('ä·€', 'ä·¿'), + ('ê’', '꓆'), + ('꜀', '꜖'), + ('꜠', '꜡'), + ('꞉', '꞊'), + ('ê ¨', 'ê «'), + ('ê ¶', 'ê ¹'), + ('ê©·', '꩹'), + ('ê­›', 'ê­›'), + ('ê­ª', 'ê­«'), + ('﬩', '﬩'), + ('﮲', '﯂'), + ('ïµ€', 'ïµ'), + ('ï·', 'ï·'), + ('ï·¼', 'ï·¿'), + ('ï¹¢', 'ï¹¢'), + ('﹤', '﹦'), + ('﹩', '﹩'), + ('$', '$'), + ('+', '+'), + ('<', '>'), + ('ï¼¾', 'ï¼¾'), + ('ï½€', 'ï½€'), + ('|', '|'), + ('~', '~'), + ('ï¿ ', '₩'), + ('│', 'ï¿®'), + ('', '�'), + ('ð„·', 'ð„¿'), + ('ð…¹', 'ð†‰'), + ('ð†Œ', 'ð†Ž'), + ('ð†', 'ð†œ'), + ('ð† ', 'ð† '), + ('ð‡', 'ð‡¼'), + ('ð¡·', 'ð¡¸'), + ('ð«ˆ', 'ð«ˆ'), + ('𑜿', '𑜿'), + ('ð‘¿•', 'ð‘¿±'), + ('𖬼', '𖬿'), + ('ð–­…', 'ð–­…'), + ('𛲜', '𛲜'), + ('ðœ½', '𜿃'), + ('ð€€', 'ðƒµ'), + ('ð„€', 'ð„¦'), + ('ð„©', 'ð…¤'), + ('ð…ª', 'ð…¬'), + ('ð†ƒ', 'ð†„'), + ('ð†Œ', 'ð†©'), + ('ð†®', 'ð‡ª'), + ('ðˆ€', 'ð‰'), + ('ð‰…', 'ð‰…'), + ('ðŒ€', 'ð–'), + ('ð›', 'ð›'), + ('ð››', 'ð››'), + ('ð›»', 'ð›»'), + ('ðœ•', 'ðœ•'), + ('ðœµ', 'ðœµ'), + ('ð', 'ð'), + ('ð¯', 'ð¯'), + ('ðž‰', 'ðž‰'), + ('ðž©', 'ðž©'), + ('ðŸƒ', 'ðŸƒ'), + ('ð €', 'ð§¿'), + ('ð¨·', 'ð¨º'), + ('ð©­', 'ð©´'), + ('ð©¶', 'ðªƒ'), + ('ðª…', 'ðª†'), + ('ðž…', 'ðž…'), + ('ðž‹¿', 'ðž‹¿'), + ('𞲬', '𞲬'), + ('ðž²°', 'ðž²°'), + ('ðž´®', 'ðž´®'), + ('ðž»°', 'ðž»±'), + ('🀀', '🀫'), + ('🀰', '🂓'), + ('🂠', '🂮'), + ('🂱', '🂿'), + ('ðŸƒ', 'ðŸƒ'), + ('🃑', '🃵'), + ('ðŸ„', '🆭'), + ('🇦', '🈂'), + ('ðŸˆ', '🈻'), + ('🉀', '🉈'), + ('ðŸ‰', '🉑'), + ('🉠', '🉥'), + ('🌀', '🛗'), + ('🛜', '🛬'), + ('🛰', '🛼'), + ('🜀', 'ðŸ¶'), + ('ðŸ»', '🟙'), + ('🟠', '🟫'), + ('🟰', '🟰'), + ('🠀', '🠋'), + ('ðŸ ', '🡇'), + ('ðŸ¡', '🡙'), + ('🡠', '🢇'), + ('ðŸ¢', '🢭'), + ('🢰', '🢱'), + ('🤀', '🩓'), + ('🩠', '🩭'), + ('🩰', '🩼'), + ('🪀', '🪈'), + ('ðŸª', '🪽'), + ('🪿', '🫅'), + ('🫎', '🫛'), + ('🫠', '🫨'), + ('🫰', '🫸'), + ('🬀', '🮒'), + ('🮔', '🯊'), +]; + +pub const TITLECASE_LETTER: &'static [(char, char)] = &[ + ('Ç…', 'Ç…'), + ('Lj', 'Lj'), + ('Ç‹', 'Ç‹'), + ('Dz', 'Dz'), + ('ᾈ', 'á¾'), + ('ᾘ', 'ᾟ'), + ('ᾨ', 'ᾯ'), + ('á¾¼', 'á¾¼'), + ('á¿Œ', 'á¿Œ'), + ('ῼ', 'ῼ'), +]; + +pub const UNASSIGNED: &'static [(char, char)] = &[ + ('\u{378}', '\u{379}'), + ('\u{380}', '\u{383}'), + ('\u{38b}', '\u{38b}'), + ('\u{38d}', '\u{38d}'), + ('\u{3a2}', '\u{3a2}'), + ('\u{530}', '\u{530}'), + ('\u{557}', '\u{558}'), + ('\u{58b}', '\u{58c}'), + ('\u{590}', '\u{590}'), + ('\u{5c8}', '\u{5cf}'), + ('\u{5eb}', '\u{5ee}'), + ('\u{5f5}', '\u{5ff}'), + ('\u{70e}', '\u{70e}'), + ('\u{74b}', '\u{74c}'), + ('\u{7b2}', '\u{7bf}'), + ('\u{7fb}', '\u{7fc}'), + ('\u{82e}', '\u{82f}'), + ('\u{83f}', '\u{83f}'), + ('\u{85c}', '\u{85d}'), + ('\u{85f}', '\u{85f}'), + ('\u{86b}', '\u{86f}'), + ('\u{88f}', '\u{88f}'), + ('\u{892}', '\u{897}'), + ('\u{984}', '\u{984}'), + ('\u{98d}', '\u{98e}'), + ('\u{991}', '\u{992}'), + ('\u{9a9}', '\u{9a9}'), + ('\u{9b1}', '\u{9b1}'), + ('\u{9b3}', '\u{9b5}'), + ('\u{9ba}', '\u{9bb}'), + ('\u{9c5}', '\u{9c6}'), + ('\u{9c9}', '\u{9ca}'), + ('\u{9cf}', '\u{9d6}'), + ('\u{9d8}', '\u{9db}'), + ('\u{9de}', '\u{9de}'), + ('\u{9e4}', '\u{9e5}'), + ('\u{9ff}', '\u{a00}'), + ('\u{a04}', '\u{a04}'), + ('\u{a0b}', '\u{a0e}'), + ('\u{a11}', '\u{a12}'), + ('\u{a29}', '\u{a29}'), + ('\u{a31}', '\u{a31}'), + ('\u{a34}', '\u{a34}'), + ('\u{a37}', '\u{a37}'), + ('\u{a3a}', '\u{a3b}'), + ('\u{a3d}', '\u{a3d}'), + ('\u{a43}', '\u{a46}'), + ('\u{a49}', '\u{a4a}'), + ('\u{a4e}', '\u{a50}'), + ('\u{a52}', '\u{a58}'), + ('\u{a5d}', '\u{a5d}'), + ('\u{a5f}', '\u{a65}'), + ('\u{a77}', '\u{a80}'), + ('\u{a84}', '\u{a84}'), + ('\u{a8e}', '\u{a8e}'), + ('\u{a92}', '\u{a92}'), + ('\u{aa9}', '\u{aa9}'), + ('\u{ab1}', '\u{ab1}'), + ('\u{ab4}', '\u{ab4}'), + ('\u{aba}', '\u{abb}'), + ('\u{ac6}', '\u{ac6}'), + ('\u{aca}', '\u{aca}'), + ('\u{ace}', '\u{acf}'), + ('\u{ad1}', '\u{adf}'), + ('\u{ae4}', '\u{ae5}'), + ('\u{af2}', '\u{af8}'), + ('\u{b00}', '\u{b00}'), + ('\u{b04}', '\u{b04}'), + ('\u{b0d}', '\u{b0e}'), + ('\u{b11}', '\u{b12}'), + ('\u{b29}', '\u{b29}'), + ('\u{b31}', '\u{b31}'), + ('\u{b34}', '\u{b34}'), + ('\u{b3a}', '\u{b3b}'), + ('\u{b45}', '\u{b46}'), + ('\u{b49}', '\u{b4a}'), + ('\u{b4e}', '\u{b54}'), + ('\u{b58}', '\u{b5b}'), + ('\u{b5e}', '\u{b5e}'), + ('\u{b64}', '\u{b65}'), + ('\u{b78}', '\u{b81}'), + ('\u{b84}', '\u{b84}'), + ('\u{b8b}', '\u{b8d}'), + ('\u{b91}', '\u{b91}'), + ('\u{b96}', '\u{b98}'), + ('\u{b9b}', '\u{b9b}'), + ('\u{b9d}', '\u{b9d}'), + ('\u{ba0}', '\u{ba2}'), + ('\u{ba5}', '\u{ba7}'), + ('\u{bab}', '\u{bad}'), + ('\u{bba}', '\u{bbd}'), + ('\u{bc3}', '\u{bc5}'), + ('\u{bc9}', '\u{bc9}'), + ('\u{bce}', '\u{bcf}'), + ('\u{bd1}', '\u{bd6}'), + ('\u{bd8}', '\u{be5}'), + ('\u{bfb}', '\u{bff}'), + ('\u{c0d}', '\u{c0d}'), + ('\u{c11}', '\u{c11}'), + ('\u{c29}', '\u{c29}'), + ('\u{c3a}', '\u{c3b}'), + ('\u{c45}', '\u{c45}'), + ('\u{c49}', '\u{c49}'), + ('\u{c4e}', '\u{c54}'), + ('\u{c57}', '\u{c57}'), + ('\u{c5b}', '\u{c5c}'), + ('\u{c5e}', '\u{c5f}'), + ('\u{c64}', '\u{c65}'), + ('\u{c70}', '\u{c76}'), + ('\u{c8d}', '\u{c8d}'), + ('\u{c91}', '\u{c91}'), + ('\u{ca9}', '\u{ca9}'), + ('\u{cb4}', '\u{cb4}'), + ('\u{cba}', '\u{cbb}'), + ('\u{cc5}', '\u{cc5}'), + ('\u{cc9}', '\u{cc9}'), + ('\u{cce}', '\u{cd4}'), + ('\u{cd7}', '\u{cdc}'), + ('\u{cdf}', '\u{cdf}'), + ('\u{ce4}', '\u{ce5}'), + ('\u{cf0}', '\u{cf0}'), + ('\u{cf4}', '\u{cff}'), + ('\u{d0d}', '\u{d0d}'), + ('\u{d11}', '\u{d11}'), + ('\u{d45}', '\u{d45}'), + ('\u{d49}', '\u{d49}'), + ('\u{d50}', '\u{d53}'), + ('\u{d64}', '\u{d65}'), + ('\u{d80}', '\u{d80}'), + ('\u{d84}', '\u{d84}'), + ('\u{d97}', '\u{d99}'), + ('\u{db2}', '\u{db2}'), + ('\u{dbc}', '\u{dbc}'), + ('\u{dbe}', '\u{dbf}'), + ('\u{dc7}', '\u{dc9}'), + ('\u{dcb}', '\u{dce}'), + ('\u{dd5}', '\u{dd5}'), + ('\u{dd7}', '\u{dd7}'), + ('\u{de0}', '\u{de5}'), + ('\u{df0}', '\u{df1}'), + ('\u{df5}', '\u{e00}'), + ('\u{e3b}', '\u{e3e}'), + ('\u{e5c}', '\u{e80}'), + ('\u{e83}', '\u{e83}'), + ('\u{e85}', '\u{e85}'), + ('\u{e8b}', '\u{e8b}'), + ('\u{ea4}', '\u{ea4}'), + ('\u{ea6}', '\u{ea6}'), + ('\u{ebe}', '\u{ebf}'), + ('\u{ec5}', '\u{ec5}'), + ('\u{ec7}', '\u{ec7}'), + ('\u{ecf}', '\u{ecf}'), + ('\u{eda}', '\u{edb}'), + ('\u{ee0}', '\u{eff}'), + ('\u{f48}', '\u{f48}'), + ('\u{f6d}', '\u{f70}'), + ('\u{f98}', '\u{f98}'), + ('\u{fbd}', '\u{fbd}'), + ('\u{fcd}', '\u{fcd}'), + ('\u{fdb}', '\u{fff}'), + ('\u{10c6}', '\u{10c6}'), + ('\u{10c8}', '\u{10cc}'), + ('\u{10ce}', '\u{10cf}'), + ('\u{1249}', '\u{1249}'), + ('\u{124e}', '\u{124f}'), + ('\u{1257}', '\u{1257}'), + ('\u{1259}', '\u{1259}'), + ('\u{125e}', '\u{125f}'), + ('\u{1289}', '\u{1289}'), + ('\u{128e}', '\u{128f}'), + ('\u{12b1}', '\u{12b1}'), + ('\u{12b6}', '\u{12b7}'), + ('\u{12bf}', '\u{12bf}'), + ('\u{12c1}', '\u{12c1}'), + ('\u{12c6}', '\u{12c7}'), + ('\u{12d7}', '\u{12d7}'), + ('\u{1311}', '\u{1311}'), + ('\u{1316}', '\u{1317}'), + ('\u{135b}', '\u{135c}'), + ('\u{137d}', '\u{137f}'), + ('\u{139a}', '\u{139f}'), + ('\u{13f6}', '\u{13f7}'), + ('\u{13fe}', '\u{13ff}'), + ('\u{169d}', '\u{169f}'), + ('\u{16f9}', '\u{16ff}'), + ('\u{1716}', '\u{171e}'), + ('\u{1737}', '\u{173f}'), + ('\u{1754}', '\u{175f}'), + ('\u{176d}', '\u{176d}'), + ('\u{1771}', '\u{1771}'), + ('\u{1774}', '\u{177f}'), + ('\u{17de}', '\u{17df}'), + ('\u{17ea}', '\u{17ef}'), + ('\u{17fa}', '\u{17ff}'), + ('\u{181a}', '\u{181f}'), + ('\u{1879}', '\u{187f}'), + ('\u{18ab}', '\u{18af}'), + ('\u{18f6}', '\u{18ff}'), + ('\u{191f}', '\u{191f}'), + ('\u{192c}', '\u{192f}'), + ('\u{193c}', '\u{193f}'), + ('\u{1941}', '\u{1943}'), + ('\u{196e}', '\u{196f}'), + ('\u{1975}', '\u{197f}'), + ('\u{19ac}', '\u{19af}'), + ('\u{19ca}', '\u{19cf}'), + ('\u{19db}', '\u{19dd}'), + ('\u{1a1c}', '\u{1a1d}'), + ('\u{1a5f}', '\u{1a5f}'), + ('\u{1a7d}', '\u{1a7e}'), + ('\u{1a8a}', '\u{1a8f}'), + ('\u{1a9a}', '\u{1a9f}'), + ('\u{1aae}', '\u{1aaf}'), + ('\u{1acf}', '\u{1aff}'), + ('\u{1b4d}', '\u{1b4f}'), + ('\u{1b7f}', '\u{1b7f}'), + ('\u{1bf4}', '\u{1bfb}'), + ('\u{1c38}', '\u{1c3a}'), + ('\u{1c4a}', '\u{1c4c}'), + ('\u{1c89}', '\u{1c8f}'), + ('\u{1cbb}', '\u{1cbc}'), + ('\u{1cc8}', '\u{1ccf}'), + ('\u{1cfb}', '\u{1cff}'), + ('\u{1f16}', '\u{1f17}'), + ('\u{1f1e}', '\u{1f1f}'), + ('\u{1f46}', '\u{1f47}'), + ('\u{1f4e}', '\u{1f4f}'), + ('\u{1f58}', '\u{1f58}'), + ('\u{1f5a}', '\u{1f5a}'), + ('\u{1f5c}', '\u{1f5c}'), + ('\u{1f5e}', '\u{1f5e}'), + ('\u{1f7e}', '\u{1f7f}'), + ('\u{1fb5}', '\u{1fb5}'), + ('\u{1fc5}', '\u{1fc5}'), + ('\u{1fd4}', '\u{1fd5}'), + ('\u{1fdc}', '\u{1fdc}'), + ('\u{1ff0}', '\u{1ff1}'), + ('\u{1ff5}', '\u{1ff5}'), + ('\u{1fff}', '\u{1fff}'), + ('\u{2065}', '\u{2065}'), + ('\u{2072}', '\u{2073}'), + ('\u{208f}', '\u{208f}'), + ('\u{209d}', '\u{209f}'), + ('\u{20c1}', '\u{20cf}'), + ('\u{20f1}', '\u{20ff}'), + ('\u{218c}', '\u{218f}'), + ('\u{2427}', '\u{243f}'), + ('\u{244b}', '\u{245f}'), + ('\u{2b74}', '\u{2b75}'), + ('\u{2b96}', '\u{2b96}'), + ('\u{2cf4}', '\u{2cf8}'), + ('\u{2d26}', '\u{2d26}'), + ('\u{2d28}', '\u{2d2c}'), + ('\u{2d2e}', '\u{2d2f}'), + ('\u{2d68}', '\u{2d6e}'), + ('\u{2d71}', '\u{2d7e}'), + ('\u{2d97}', '\u{2d9f}'), + ('\u{2da7}', '\u{2da7}'), + ('\u{2daf}', '\u{2daf}'), + ('\u{2db7}', '\u{2db7}'), + ('\u{2dbf}', '\u{2dbf}'), + ('\u{2dc7}', '\u{2dc7}'), + ('\u{2dcf}', '\u{2dcf}'), + ('\u{2dd7}', '\u{2dd7}'), + ('\u{2ddf}', '\u{2ddf}'), + ('\u{2e5e}', '\u{2e7f}'), + ('\u{2e9a}', '\u{2e9a}'), + ('\u{2ef4}', '\u{2eff}'), + ('\u{2fd6}', '\u{2fef}'), + ('\u{2ffc}', '\u{2fff}'), + ('\u{3040}', '\u{3040}'), + ('\u{3097}', '\u{3098}'), + ('\u{3100}', '\u{3104}'), + ('\u{3130}', '\u{3130}'), + ('\u{318f}', '\u{318f}'), + ('\u{31e4}', '\u{31ef}'), + ('\u{321f}', '\u{321f}'), + ('\u{a48d}', '\u{a48f}'), + ('\u{a4c7}', '\u{a4cf}'), + ('\u{a62c}', '\u{a63f}'), + ('\u{a6f8}', '\u{a6ff}'), + ('\u{a7cb}', '\u{a7cf}'), + ('\u{a7d2}', '\u{a7d2}'), + ('\u{a7d4}', '\u{a7d4}'), + ('\u{a7da}', '\u{a7f1}'), + ('\u{a82d}', '\u{a82f}'), + ('\u{a83a}', '\u{a83f}'), + ('\u{a878}', '\u{a87f}'), + ('\u{a8c6}', '\u{a8cd}'), + ('\u{a8da}', '\u{a8df}'), + ('\u{a954}', '\u{a95e}'), + ('\u{a97d}', '\u{a97f}'), + ('\u{a9ce}', '\u{a9ce}'), + ('\u{a9da}', '\u{a9dd}'), + ('\u{a9ff}', '\u{a9ff}'), + ('\u{aa37}', '\u{aa3f}'), + ('\u{aa4e}', '\u{aa4f}'), + ('\u{aa5a}', '\u{aa5b}'), + ('\u{aac3}', '\u{aada}'), + ('\u{aaf7}', '\u{ab00}'), + ('\u{ab07}', '\u{ab08}'), + ('\u{ab0f}', '\u{ab10}'), + ('\u{ab17}', '\u{ab1f}'), + ('\u{ab27}', '\u{ab27}'), + ('\u{ab2f}', '\u{ab2f}'), + ('\u{ab6c}', '\u{ab6f}'), + ('\u{abee}', '\u{abef}'), + ('\u{abfa}', '\u{abff}'), + ('\u{d7a4}', '\u{d7af}'), + ('\u{d7c7}', '\u{d7ca}'), + ('\u{d7fc}', '\u{d7ff}'), + ('\u{fa6e}', '\u{fa6f}'), + ('\u{fada}', '\u{faff}'), + ('\u{fb07}', '\u{fb12}'), + ('\u{fb18}', '\u{fb1c}'), + ('\u{fb37}', '\u{fb37}'), + ('\u{fb3d}', '\u{fb3d}'), + ('\u{fb3f}', '\u{fb3f}'), + ('\u{fb42}', '\u{fb42}'), + ('\u{fb45}', '\u{fb45}'), + ('\u{fbc3}', '\u{fbd2}'), + ('\u{fd90}', '\u{fd91}'), + ('\u{fdc8}', '\u{fdce}'), + ('\u{fdd0}', '\u{fdef}'), + ('\u{fe1a}', '\u{fe1f}'), + ('\u{fe53}', '\u{fe53}'), + ('\u{fe67}', '\u{fe67}'), + ('\u{fe6c}', '\u{fe6f}'), + ('\u{fe75}', '\u{fe75}'), + ('\u{fefd}', '\u{fefe}'), + ('\u{ff00}', '\u{ff00}'), + ('\u{ffbf}', '\u{ffc1}'), + ('\u{ffc8}', '\u{ffc9}'), + ('\u{ffd0}', '\u{ffd1}'), + ('\u{ffd8}', '\u{ffd9}'), + ('\u{ffdd}', '\u{ffdf}'), + ('\u{ffe7}', '\u{ffe7}'), + ('\u{ffef}', '\u{fff8}'), + ('\u{fffe}', '\u{ffff}'), + ('\u{1000c}', '\u{1000c}'), + ('\u{10027}', '\u{10027}'), + ('\u{1003b}', '\u{1003b}'), + ('\u{1003e}', '\u{1003e}'), + ('\u{1004e}', '\u{1004f}'), + ('\u{1005e}', '\u{1007f}'), + ('\u{100fb}', '\u{100ff}'), + ('\u{10103}', '\u{10106}'), + ('\u{10134}', '\u{10136}'), + ('\u{1018f}', '\u{1018f}'), + ('\u{1019d}', '\u{1019f}'), + ('\u{101a1}', '\u{101cf}'), + ('\u{101fe}', '\u{1027f}'), + ('\u{1029d}', '\u{1029f}'), + ('\u{102d1}', '\u{102df}'), + ('\u{102fc}', '\u{102ff}'), + ('\u{10324}', '\u{1032c}'), + ('\u{1034b}', '\u{1034f}'), + ('\u{1037b}', '\u{1037f}'), + ('\u{1039e}', '\u{1039e}'), + ('\u{103c4}', '\u{103c7}'), + ('\u{103d6}', '\u{103ff}'), + ('\u{1049e}', '\u{1049f}'), + ('\u{104aa}', '\u{104af}'), + ('\u{104d4}', '\u{104d7}'), + ('\u{104fc}', '\u{104ff}'), + ('\u{10528}', '\u{1052f}'), + ('\u{10564}', '\u{1056e}'), + ('\u{1057b}', '\u{1057b}'), + ('\u{1058b}', '\u{1058b}'), + ('\u{10593}', '\u{10593}'), + ('\u{10596}', '\u{10596}'), + ('\u{105a2}', '\u{105a2}'), + ('\u{105b2}', '\u{105b2}'), + ('\u{105ba}', '\u{105ba}'), + ('\u{105bd}', '\u{105ff}'), + ('\u{10737}', '\u{1073f}'), + ('\u{10756}', '\u{1075f}'), + ('\u{10768}', '\u{1077f}'), + ('\u{10786}', '\u{10786}'), + ('\u{107b1}', '\u{107b1}'), + ('\u{107bb}', '\u{107ff}'), + ('\u{10806}', '\u{10807}'), + ('\u{10809}', '\u{10809}'), + ('\u{10836}', '\u{10836}'), + ('\u{10839}', '\u{1083b}'), + ('\u{1083d}', '\u{1083e}'), + ('\u{10856}', '\u{10856}'), + ('\u{1089f}', '\u{108a6}'), + ('\u{108b0}', '\u{108df}'), + ('\u{108f3}', '\u{108f3}'), + ('\u{108f6}', '\u{108fa}'), + ('\u{1091c}', '\u{1091e}'), + ('\u{1093a}', '\u{1093e}'), + ('\u{10940}', '\u{1097f}'), + ('\u{109b8}', '\u{109bb}'), + ('\u{109d0}', '\u{109d1}'), + ('\u{10a04}', '\u{10a04}'), + ('\u{10a07}', '\u{10a0b}'), + ('\u{10a14}', '\u{10a14}'), + ('\u{10a18}', '\u{10a18}'), + ('\u{10a36}', '\u{10a37}'), + ('\u{10a3b}', '\u{10a3e}'), + ('\u{10a49}', '\u{10a4f}'), + ('\u{10a59}', '\u{10a5f}'), + ('\u{10aa0}', '\u{10abf}'), + ('\u{10ae7}', '\u{10aea}'), + ('\u{10af7}', '\u{10aff}'), + ('\u{10b36}', '\u{10b38}'), + ('\u{10b56}', '\u{10b57}'), + ('\u{10b73}', '\u{10b77}'), + ('\u{10b92}', '\u{10b98}'), + ('\u{10b9d}', '\u{10ba8}'), + ('\u{10bb0}', '\u{10bff}'), + ('\u{10c49}', '\u{10c7f}'), + ('\u{10cb3}', '\u{10cbf}'), + ('\u{10cf3}', '\u{10cf9}'), + ('\u{10d28}', '\u{10d2f}'), + ('\u{10d3a}', '\u{10e5f}'), + ('\u{10e7f}', '\u{10e7f}'), + ('\u{10eaa}', '\u{10eaa}'), + ('\u{10eae}', '\u{10eaf}'), + ('\u{10eb2}', '\u{10efc}'), + ('\u{10f28}', '\u{10f2f}'), + ('\u{10f5a}', '\u{10f6f}'), + ('\u{10f8a}', '\u{10faf}'), + ('\u{10fcc}', '\u{10fdf}'), + ('\u{10ff7}', '\u{10fff}'), + ('\u{1104e}', '\u{11051}'), + ('\u{11076}', '\u{1107e}'), + ('\u{110c3}', '\u{110cc}'), + ('\u{110ce}', '\u{110cf}'), + ('\u{110e9}', '\u{110ef}'), + ('\u{110fa}', '\u{110ff}'), + ('\u{11135}', '\u{11135}'), + ('\u{11148}', '\u{1114f}'), + ('\u{11177}', '\u{1117f}'), + ('\u{111e0}', '\u{111e0}'), + ('\u{111f5}', '\u{111ff}'), + ('\u{11212}', '\u{11212}'), + ('\u{11242}', '\u{1127f}'), + ('\u{11287}', '\u{11287}'), + ('\u{11289}', '\u{11289}'), + ('\u{1128e}', '\u{1128e}'), + ('\u{1129e}', '\u{1129e}'), + ('\u{112aa}', '\u{112af}'), + ('\u{112eb}', '\u{112ef}'), + ('\u{112fa}', '\u{112ff}'), + ('\u{11304}', '\u{11304}'), + ('\u{1130d}', '\u{1130e}'), + ('\u{11311}', '\u{11312}'), + ('\u{11329}', '\u{11329}'), + ('\u{11331}', '\u{11331}'), + ('\u{11334}', '\u{11334}'), + ('\u{1133a}', '\u{1133a}'), + ('\u{11345}', '\u{11346}'), + ('\u{11349}', '\u{1134a}'), + ('\u{1134e}', '\u{1134f}'), + ('\u{11351}', '\u{11356}'), + ('\u{11358}', '\u{1135c}'), + ('\u{11364}', '\u{11365}'), + ('\u{1136d}', '\u{1136f}'), + ('\u{11375}', '\u{113ff}'), + ('\u{1145c}', '\u{1145c}'), + ('\u{11462}', '\u{1147f}'), + ('\u{114c8}', '\u{114cf}'), + ('\u{114da}', '\u{1157f}'), + ('\u{115b6}', '\u{115b7}'), + ('\u{115de}', '\u{115ff}'), + ('\u{11645}', '\u{1164f}'), + ('\u{1165a}', '\u{1165f}'), + ('\u{1166d}', '\u{1167f}'), + ('\u{116ba}', '\u{116bf}'), + ('\u{116ca}', '\u{116ff}'), + ('\u{1171b}', '\u{1171c}'), + ('\u{1172c}', '\u{1172f}'), + ('\u{11747}', '\u{117ff}'), + ('\u{1183c}', '\u{1189f}'), + ('\u{118f3}', '\u{118fe}'), + ('\u{11907}', '\u{11908}'), + ('\u{1190a}', '\u{1190b}'), + ('\u{11914}', '\u{11914}'), + ('\u{11917}', '\u{11917}'), + ('\u{11936}', '\u{11936}'), + ('\u{11939}', '\u{1193a}'), + ('\u{11947}', '\u{1194f}'), + ('\u{1195a}', '\u{1199f}'), + ('\u{119a8}', '\u{119a9}'), + ('\u{119d8}', '\u{119d9}'), + ('\u{119e5}', '\u{119ff}'), + ('\u{11a48}', '\u{11a4f}'), + ('\u{11aa3}', '\u{11aaf}'), + ('\u{11af9}', '\u{11aff}'), + ('\u{11b0a}', '\u{11bff}'), + ('\u{11c09}', '\u{11c09}'), + ('\u{11c37}', '\u{11c37}'), + ('\u{11c46}', '\u{11c4f}'), + ('\u{11c6d}', '\u{11c6f}'), + ('\u{11c90}', '\u{11c91}'), + ('\u{11ca8}', '\u{11ca8}'), + ('\u{11cb7}', '\u{11cff}'), + ('\u{11d07}', '\u{11d07}'), + ('\u{11d0a}', '\u{11d0a}'), + ('\u{11d37}', '\u{11d39}'), + ('\u{11d3b}', '\u{11d3b}'), + ('\u{11d3e}', '\u{11d3e}'), + ('\u{11d48}', '\u{11d4f}'), + ('\u{11d5a}', '\u{11d5f}'), + ('\u{11d66}', '\u{11d66}'), + ('\u{11d69}', '\u{11d69}'), + ('\u{11d8f}', '\u{11d8f}'), + ('\u{11d92}', '\u{11d92}'), + ('\u{11d99}', '\u{11d9f}'), + ('\u{11daa}', '\u{11edf}'), + ('\u{11ef9}', '\u{11eff}'), + ('\u{11f11}', '\u{11f11}'), + ('\u{11f3b}', '\u{11f3d}'), + ('\u{11f5a}', '\u{11faf}'), + ('\u{11fb1}', '\u{11fbf}'), + ('\u{11ff2}', '\u{11ffe}'), + ('\u{1239a}', '\u{123ff}'), + ('\u{1246f}', '\u{1246f}'), + ('\u{12475}', '\u{1247f}'), + ('\u{12544}', '\u{12f8f}'), + ('\u{12ff3}', '\u{12fff}'), + ('\u{13456}', '\u{143ff}'), + ('\u{14647}', '\u{167ff}'), + ('\u{16a39}', '\u{16a3f}'), + ('\u{16a5f}', '\u{16a5f}'), + ('\u{16a6a}', '\u{16a6d}'), + ('\u{16abf}', '\u{16abf}'), + ('\u{16aca}', '\u{16acf}'), + ('\u{16aee}', '\u{16aef}'), + ('\u{16af6}', '\u{16aff}'), + ('\u{16b46}', '\u{16b4f}'), + ('\u{16b5a}', '\u{16b5a}'), + ('\u{16b62}', '\u{16b62}'), + ('\u{16b78}', '\u{16b7c}'), + ('\u{16b90}', '\u{16e3f}'), + ('\u{16e9b}', '\u{16eff}'), + ('\u{16f4b}', '\u{16f4e}'), + ('\u{16f88}', '\u{16f8e}'), + ('\u{16fa0}', '\u{16fdf}'), + ('\u{16fe5}', '\u{16fef}'), + ('\u{16ff2}', '\u{16fff}'), + ('\u{187f8}', '\u{187ff}'), + ('\u{18cd6}', '\u{18cff}'), + ('\u{18d09}', '\u{1afef}'), + ('\u{1aff4}', '\u{1aff4}'), + ('\u{1affc}', '\u{1affc}'), + ('\u{1afff}', '\u{1afff}'), + ('\u{1b123}', '\u{1b131}'), + ('\u{1b133}', '\u{1b14f}'), + ('\u{1b153}', '\u{1b154}'), + ('\u{1b156}', '\u{1b163}'), + ('\u{1b168}', '\u{1b16f}'), + ('\u{1b2fc}', '\u{1bbff}'), + ('\u{1bc6b}', '\u{1bc6f}'), + ('\u{1bc7d}', '\u{1bc7f}'), + ('\u{1bc89}', '\u{1bc8f}'), + ('\u{1bc9a}', '\u{1bc9b}'), + ('\u{1bca4}', '\u{1ceff}'), + ('\u{1cf2e}', '\u{1cf2f}'), + ('\u{1cf47}', '\u{1cf4f}'), + ('\u{1cfc4}', '\u{1cfff}'), + ('\u{1d0f6}', '\u{1d0ff}'), + ('\u{1d127}', '\u{1d128}'), + ('\u{1d1eb}', '\u{1d1ff}'), + ('\u{1d246}', '\u{1d2bf}'), + ('\u{1d2d4}', '\u{1d2df}'), + ('\u{1d2f4}', '\u{1d2ff}'), + ('\u{1d357}', '\u{1d35f}'), + ('\u{1d379}', '\u{1d3ff}'), + ('\u{1d455}', '\u{1d455}'), + ('\u{1d49d}', '\u{1d49d}'), + ('\u{1d4a0}', '\u{1d4a1}'), + ('\u{1d4a3}', '\u{1d4a4}'), + ('\u{1d4a7}', '\u{1d4a8}'), + ('\u{1d4ad}', '\u{1d4ad}'), + ('\u{1d4ba}', '\u{1d4ba}'), + ('\u{1d4bc}', '\u{1d4bc}'), + ('\u{1d4c4}', '\u{1d4c4}'), + ('\u{1d506}', '\u{1d506}'), + ('\u{1d50b}', '\u{1d50c}'), + ('\u{1d515}', '\u{1d515}'), + ('\u{1d51d}', '\u{1d51d}'), + ('\u{1d53a}', '\u{1d53a}'), + ('\u{1d53f}', '\u{1d53f}'), + ('\u{1d545}', '\u{1d545}'), + ('\u{1d547}', '\u{1d549}'), + ('\u{1d551}', '\u{1d551}'), + ('\u{1d6a6}', '\u{1d6a7}'), + ('\u{1d7cc}', '\u{1d7cd}'), + ('\u{1da8c}', '\u{1da9a}'), + ('\u{1daa0}', '\u{1daa0}'), + ('\u{1dab0}', '\u{1deff}'), + ('\u{1df1f}', '\u{1df24}'), + ('\u{1df2b}', '\u{1dfff}'), + ('\u{1e007}', '\u{1e007}'), + ('\u{1e019}', '\u{1e01a}'), + ('\u{1e022}', '\u{1e022}'), + ('\u{1e025}', '\u{1e025}'), + ('\u{1e02b}', '\u{1e02f}'), + ('\u{1e06e}', '\u{1e08e}'), + ('\u{1e090}', '\u{1e0ff}'), + ('\u{1e12d}', '\u{1e12f}'), + ('\u{1e13e}', '\u{1e13f}'), + ('\u{1e14a}', '\u{1e14d}'), + ('\u{1e150}', '\u{1e28f}'), + ('\u{1e2af}', '\u{1e2bf}'), + ('\u{1e2fa}', '\u{1e2fe}'), + ('\u{1e300}', '\u{1e4cf}'), + ('\u{1e4fa}', '\u{1e7df}'), + ('\u{1e7e7}', '\u{1e7e7}'), + ('\u{1e7ec}', '\u{1e7ec}'), + ('\u{1e7ef}', '\u{1e7ef}'), + ('\u{1e7ff}', '\u{1e7ff}'), + ('\u{1e8c5}', '\u{1e8c6}'), + ('\u{1e8d7}', '\u{1e8ff}'), + ('\u{1e94c}', '\u{1e94f}'), + ('\u{1e95a}', '\u{1e95d}'), + ('\u{1e960}', '\u{1ec70}'), + ('\u{1ecb5}', '\u{1ed00}'), + ('\u{1ed3e}', '\u{1edff}'), + ('\u{1ee04}', '\u{1ee04}'), + ('\u{1ee20}', '\u{1ee20}'), + ('\u{1ee23}', '\u{1ee23}'), + ('\u{1ee25}', '\u{1ee26}'), + ('\u{1ee28}', '\u{1ee28}'), + ('\u{1ee33}', '\u{1ee33}'), + ('\u{1ee38}', '\u{1ee38}'), + ('\u{1ee3a}', '\u{1ee3a}'), + ('\u{1ee3c}', '\u{1ee41}'), + ('\u{1ee43}', '\u{1ee46}'), + ('\u{1ee48}', '\u{1ee48}'), + ('\u{1ee4a}', '\u{1ee4a}'), + ('\u{1ee4c}', '\u{1ee4c}'), + ('\u{1ee50}', '\u{1ee50}'), + ('\u{1ee53}', '\u{1ee53}'), + ('\u{1ee55}', '\u{1ee56}'), + ('\u{1ee58}', '\u{1ee58}'), + ('\u{1ee5a}', '\u{1ee5a}'), + ('\u{1ee5c}', '\u{1ee5c}'), + ('\u{1ee5e}', '\u{1ee5e}'), + ('\u{1ee60}', '\u{1ee60}'), + ('\u{1ee63}', '\u{1ee63}'), + ('\u{1ee65}', '\u{1ee66}'), + ('\u{1ee6b}', '\u{1ee6b}'), + ('\u{1ee73}', '\u{1ee73}'), + ('\u{1ee78}', '\u{1ee78}'), + ('\u{1ee7d}', '\u{1ee7d}'), + ('\u{1ee7f}', '\u{1ee7f}'), + ('\u{1ee8a}', '\u{1ee8a}'), + ('\u{1ee9c}', '\u{1eea0}'), + ('\u{1eea4}', '\u{1eea4}'), + ('\u{1eeaa}', '\u{1eeaa}'), + ('\u{1eebc}', '\u{1eeef}'), + ('\u{1eef2}', '\u{1efff}'), + ('\u{1f02c}', '\u{1f02f}'), + ('\u{1f094}', '\u{1f09f}'), + ('\u{1f0af}', '\u{1f0b0}'), + ('\u{1f0c0}', '\u{1f0c0}'), + ('\u{1f0d0}', '\u{1f0d0}'), + ('\u{1f0f6}', '\u{1f0ff}'), + ('\u{1f1ae}', '\u{1f1e5}'), + ('\u{1f203}', '\u{1f20f}'), + ('\u{1f23c}', '\u{1f23f}'), + ('\u{1f249}', '\u{1f24f}'), + ('\u{1f252}', '\u{1f25f}'), + ('\u{1f266}', '\u{1f2ff}'), + ('\u{1f6d8}', '\u{1f6db}'), + ('\u{1f6ed}', '\u{1f6ef}'), + ('\u{1f6fd}', '\u{1f6ff}'), + ('\u{1f777}', '\u{1f77a}'), + ('\u{1f7da}', '\u{1f7df}'), + ('\u{1f7ec}', '\u{1f7ef}'), + ('\u{1f7f1}', '\u{1f7ff}'), + ('\u{1f80c}', '\u{1f80f}'), + ('\u{1f848}', '\u{1f84f}'), + ('\u{1f85a}', '\u{1f85f}'), + ('\u{1f888}', '\u{1f88f}'), + ('\u{1f8ae}', '\u{1f8af}'), + ('\u{1f8b2}', '\u{1f8ff}'), + ('\u{1fa54}', '\u{1fa5f}'), + ('\u{1fa6e}', '\u{1fa6f}'), + ('\u{1fa7d}', '\u{1fa7f}'), + ('\u{1fa89}', '\u{1fa8f}'), + ('\u{1fabe}', '\u{1fabe}'), + ('\u{1fac6}', '\u{1facd}'), + ('\u{1fadc}', '\u{1fadf}'), + ('\u{1fae9}', '\u{1faef}'), + ('\u{1faf9}', '\u{1faff}'), + ('\u{1fb93}', '\u{1fb93}'), + ('\u{1fbcb}', '\u{1fbef}'), + ('\u{1fbfa}', '\u{1ffff}'), + ('\u{2a6e0}', '\u{2a6ff}'), + ('\u{2b73a}', '\u{2b73f}'), + ('\u{2b81e}', '\u{2b81f}'), + ('\u{2cea2}', '\u{2ceaf}'), + ('\u{2ebe1}', '\u{2f7ff}'), + ('\u{2fa1e}', '\u{2ffff}'), + ('\u{3134b}', '\u{3134f}'), + ('\u{323b0}', '\u{e0000}'), + ('\u{e0002}', '\u{e001f}'), + ('\u{e0080}', '\u{e00ff}'), + ('\u{e01f0}', '\u{effff}'), + ('\u{ffffe}', '\u{fffff}'), + ('\u{10fffe}', '\u{10ffff}'), +]; + +pub const UPPERCASE_LETTER: &'static [(char, char)] = &[ + ('A', 'Z'), + ('À', 'Ö'), + ('Ø', 'Þ'), + ('Ä€', 'Ä€'), + ('Ä‚', 'Ä‚'), + ('Ä„', 'Ä„'), + ('Ć', 'Ć'), + ('Ĉ', 'Ĉ'), + ('ÄŠ', 'ÄŠ'), + ('ÄŒ', 'ÄŒ'), + ('ÄŽ', 'ÄŽ'), + ('Ä', 'Ä'), + ('Ä’', 'Ä’'), + ('Ä”', 'Ä”'), + ('Ä–', 'Ä–'), + ('Ę', 'Ę'), + ('Äš', 'Äš'), + ('Äœ', 'Äœ'), + ('Äž', 'Äž'), + ('Ä ', 'Ä '), + ('Ä¢', 'Ä¢'), + ('Ĥ', 'Ĥ'), + ('Ħ', 'Ħ'), + ('Ĩ', 'Ĩ'), + ('Ī', 'Ī'), + ('Ĭ', 'Ĭ'), + ('Ä®', 'Ä®'), + ('Ä°', 'Ä°'), + ('IJ', 'IJ'), + ('Ä´', 'Ä´'), + ('Ķ', 'Ķ'), + ('Ĺ', 'Ĺ'), + ('Ä»', 'Ä»'), + ('Ľ', 'Ľ'), + ('Ä¿', 'Ä¿'), + ('Å', 'Å'), + ('Ń', 'Ń'), + ('Å…', 'Å…'), + ('Ň', 'Ň'), + ('ÅŠ', 'ÅŠ'), + ('ÅŒ', 'ÅŒ'), + ('ÅŽ', 'ÅŽ'), + ('Å', 'Å'), + ('Å’', 'Å’'), + ('Å”', 'Å”'), + ('Å–', 'Å–'), + ('Ř', 'Ř'), + ('Åš', 'Åš'), + ('Åœ', 'Åœ'), + ('Åž', 'Åž'), + ('Å ', 'Å '), + ('Å¢', 'Å¢'), + ('Ť', 'Ť'), + ('Ŧ', 'Ŧ'), + ('Ũ', 'Ũ'), + ('Ū', 'Ū'), + ('Ŭ', 'Ŭ'), + ('Å®', 'Å®'), + ('Å°', 'Å°'), + ('Ų', 'Ų'), + ('Å´', 'Å´'), + ('Ŷ', 'Ŷ'), + ('Ÿ', 'Ź'), + ('Å»', 'Å»'), + ('Ž', 'Ž'), + ('Æ', 'Æ‚'), + ('Æ„', 'Æ„'), + ('Ɔ', 'Ƈ'), + ('Ɖ', 'Æ‹'), + ('ÆŽ', 'Æ‘'), + ('Æ“', 'Æ”'), + ('Æ–', 'Ƙ'), + ('Æœ', 'Æ'), + ('ÆŸ', 'Æ '), + ('Æ¢', 'Æ¢'), + ('Ƥ', 'Ƥ'), + ('Ʀ', 'Ƨ'), + ('Æ©', 'Æ©'), + ('Ƭ', 'Ƭ'), + ('Æ®', 'Ư'), + ('Ʊ', 'Ƴ'), + ('Ƶ', 'Ƶ'), + ('Æ·', 'Ƹ'), + ('Ƽ', 'Ƽ'), + ('Ç„', 'Ç„'), + ('LJ', 'LJ'), + ('ÇŠ', 'ÇŠ'), + ('Ç', 'Ç'), + ('Ç', 'Ç'), + ('Ç‘', 'Ç‘'), + ('Ç“', 'Ç“'), + ('Ç•', 'Ç•'), + ('Ç—', 'Ç—'), + ('Ç™', 'Ç™'), + ('Ç›', 'Ç›'), + ('Çž', 'Çž'), + ('Ç ', 'Ç '), + ('Ç¢', 'Ç¢'), + ('Ǥ', 'Ǥ'), + ('Ǧ', 'Ǧ'), + ('Ǩ', 'Ǩ'), + ('Ǫ', 'Ǫ'), + ('Ǭ', 'Ǭ'), + ('Ç®', 'Ç®'), + ('DZ', 'DZ'), + ('Ç´', 'Ç´'), + ('Ƕ', 'Ǹ'), + ('Ǻ', 'Ǻ'), + ('Ǽ', 'Ǽ'), + ('Ǿ', 'Ǿ'), + ('È€', 'È€'), + ('È‚', 'È‚'), + ('È„', 'È„'), + ('Ȇ', 'Ȇ'), + ('Ȉ', 'Ȉ'), + ('ÈŠ', 'ÈŠ'), + ('ÈŒ', 'ÈŒ'), + ('ÈŽ', 'ÈŽ'), + ('È', 'È'), + ('È’', 'È’'), + ('È”', 'È”'), + ('È–', 'È–'), + ('Ș', 'Ș'), + ('Èš', 'Èš'), + ('Èœ', 'Èœ'), + ('Èž', 'Èž'), + ('È ', 'È '), + ('È¢', 'È¢'), + ('Ȥ', 'Ȥ'), + ('Ȧ', 'Ȧ'), + ('Ȩ', 'Ȩ'), + ('Ȫ', 'Ȫ'), + ('Ȭ', 'Ȭ'), + ('È®', 'È®'), + ('È°', 'È°'), + ('Ȳ', 'Ȳ'), + ('Ⱥ', 'È»'), + ('Ƚ', 'Ⱦ'), + ('É', 'É'), + ('Ƀ', 'Ɇ'), + ('Ɉ', 'Ɉ'), + ('ÉŠ', 'ÉŠ'), + ('ÉŒ', 'ÉŒ'), + ('ÉŽ', 'ÉŽ'), + ('Í°', 'Í°'), + ('Ͳ', 'Ͳ'), + ('Ͷ', 'Ͷ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Î'), + ('Α', 'Ρ'), + ('Σ', 'Ϋ'), + ('Ï', 'Ï'), + ('Ï’', 'Ï”'), + ('Ϙ', 'Ϙ'), + ('Ïš', 'Ïš'), + ('Ïœ', 'Ïœ'), + ('Ïž', 'Ïž'), + ('Ï ', 'Ï '), + ('Ï¢', 'Ï¢'), + ('Ϥ', 'Ϥ'), + ('Ϧ', 'Ϧ'), + ('Ϩ', 'Ϩ'), + ('Ϫ', 'Ϫ'), + ('Ϭ', 'Ϭ'), + ('Ï®', 'Ï®'), + ('Ï´', 'Ï´'), + ('Ï·', 'Ï·'), + ('Ϲ', 'Ϻ'), + ('Ͻ', 'Я'), + ('Ñ ', 'Ñ '), + ('Ñ¢', 'Ñ¢'), + ('Ѥ', 'Ѥ'), + ('Ѧ', 'Ѧ'), + ('Ѩ', 'Ѩ'), + ('Ѫ', 'Ѫ'), + ('Ѭ', 'Ѭ'), + ('Ñ®', 'Ñ®'), + ('Ñ°', 'Ñ°'), + ('Ѳ', 'Ѳ'), + ('Ñ´', 'Ñ´'), + ('Ѷ', 'Ѷ'), + ('Ѹ', 'Ѹ'), + ('Ѻ', 'Ѻ'), + ('Ѽ', 'Ѽ'), + ('Ѿ', 'Ѿ'), + ('Ò€', 'Ò€'), + ('ÒŠ', 'ÒŠ'), + ('ÒŒ', 'ÒŒ'), + ('ÒŽ', 'ÒŽ'), + ('Ò', 'Ò'), + ('Ò’', 'Ò’'), + ('Ò”', 'Ò”'), + ('Ò–', 'Ò–'), + ('Ò˜', 'Ò˜'), + ('Òš', 'Òš'), + ('Òœ', 'Òœ'), + ('Òž', 'Òž'), + ('Ò ', 'Ò '), + ('Ò¢', 'Ò¢'), + ('Ò¤', 'Ò¤'), + ('Ò¦', 'Ò¦'), + ('Ò¨', 'Ò¨'), + ('Òª', 'Òª'), + ('Ò¬', 'Ò¬'), + ('Ò®', 'Ò®'), + ('Ò°', 'Ò°'), + ('Ò²', 'Ò²'), + ('Ò´', 'Ò´'), + ('Ò¶', 'Ò¶'), + ('Ò¸', 'Ò¸'), + ('Òº', 'Òº'), + ('Ò¼', 'Ò¼'), + ('Ò¾', 'Ò¾'), + ('Ó€', 'Ó'), + ('Óƒ', 'Óƒ'), + ('Ó…', 'Ó…'), + ('Ó‡', 'Ó‡'), + ('Ó‰', 'Ó‰'), + ('Ó‹', 'Ó‹'), + ('Ó', 'Ó'), + ('Ó', 'Ó'), + ('Ó’', 'Ó’'), + ('Ó”', 'Ó”'), + ('Ó–', 'Ó–'), + ('Ó˜', 'Ó˜'), + ('Óš', 'Óš'), + ('Óœ', 'Óœ'), + ('Óž', 'Óž'), + ('Ó ', 'Ó '), + ('Ó¢', 'Ó¢'), + ('Ó¤', 'Ó¤'), + ('Ó¦', 'Ó¦'), + ('Ó¨', 'Ó¨'), + ('Óª', 'Óª'), + ('Ó¬', 'Ó¬'), + ('Ó®', 'Ó®'), + ('Ó°', 'Ó°'), + ('Ó²', 'Ó²'), + ('Ó´', 'Ó´'), + ('Ó¶', 'Ó¶'), + ('Ó¸', 'Ó¸'), + ('Óº', 'Óº'), + ('Ó¼', 'Ó¼'), + ('Ó¾', 'Ó¾'), + ('Ô€', 'Ô€'), + ('Ô‚', 'Ô‚'), + ('Ô„', 'Ô„'), + ('Ô†', 'Ô†'), + ('Ôˆ', 'Ôˆ'), + ('ÔŠ', 'ÔŠ'), + ('ÔŒ', 'ÔŒ'), + ('ÔŽ', 'ÔŽ'), + ('Ô', 'Ô'), + ('Ô’', 'Ô’'), + ('Ô”', 'Ô”'), + ('Ô–', 'Ô–'), + ('Ô˜', 'Ô˜'), + ('Ôš', 'Ôš'), + ('Ôœ', 'Ôœ'), + ('Ôž', 'Ôž'), + ('Ô ', 'Ô '), + ('Ô¢', 'Ô¢'), + ('Ô¤', 'Ô¤'), + ('Ô¦', 'Ô¦'), + ('Ô¨', 'Ô¨'), + ('Ôª', 'Ôª'), + ('Ô¬', 'Ô¬'), + ('Ô®', 'Ô®'), + ('Ô±', 'Õ–'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('Ꭰ', 'áµ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('Ḁ', 'Ḁ'), + ('Ḃ', 'Ḃ'), + ('Ḅ', 'Ḅ'), + ('Ḇ', 'Ḇ'), + ('Ḉ', 'Ḉ'), + ('Ḋ', 'Ḋ'), + ('Ḍ', 'Ḍ'), + ('Ḏ', 'Ḏ'), + ('á¸', 'á¸'), + ('Ḓ', 'Ḓ'), + ('Ḕ', 'Ḕ'), + ('Ḗ', 'Ḗ'), + ('Ḙ', 'Ḙ'), + ('Ḛ', 'Ḛ'), + ('Ḝ', 'Ḝ'), + ('Ḟ', 'Ḟ'), + ('Ḡ', 'Ḡ'), + ('Ḣ', 'Ḣ'), + ('Ḥ', 'Ḥ'), + ('Ḧ', 'Ḧ'), + ('Ḩ', 'Ḩ'), + ('Ḫ', 'Ḫ'), + ('Ḭ', 'Ḭ'), + ('Ḯ', 'Ḯ'), + ('Ḱ', 'Ḱ'), + ('Ḳ', 'Ḳ'), + ('Ḵ', 'Ḵ'), + ('Ḷ', 'Ḷ'), + ('Ḹ', 'Ḹ'), + ('Ḻ', 'Ḻ'), + ('Ḽ', 'Ḽ'), + ('Ḿ', 'Ḿ'), + ('á¹€', 'á¹€'), + ('Ṃ', 'Ṃ'), + ('Ṅ', 'Ṅ'), + ('Ṇ', 'Ṇ'), + ('Ṉ', 'Ṉ'), + ('Ṋ', 'Ṋ'), + ('Ṍ', 'Ṍ'), + ('Ṏ', 'Ṏ'), + ('á¹', 'á¹'), + ('á¹’', 'á¹’'), + ('á¹”', 'á¹”'), + ('á¹–', 'á¹–'), + ('Ṙ', 'Ṙ'), + ('Ṛ', 'Ṛ'), + ('Ṝ', 'Ṝ'), + ('Ṟ', 'Ṟ'), + ('á¹ ', 'á¹ '), + ('á¹¢', 'á¹¢'), + ('Ṥ', 'Ṥ'), + ('Ṧ', 'Ṧ'), + ('Ṩ', 'Ṩ'), + ('Ṫ', 'Ṫ'), + ('Ṭ', 'Ṭ'), + ('á¹®', 'á¹®'), + ('á¹°', 'á¹°'), + ('á¹²', 'á¹²'), + ('á¹´', 'á¹´'), + ('Ṷ', 'Ṷ'), + ('Ṹ', 'Ṹ'), + ('Ṻ', 'Ṻ'), + ('á¹¼', 'á¹¼'), + ('á¹¾', 'á¹¾'), + ('Ẁ', 'Ẁ'), + ('Ẃ', 'Ẃ'), + ('Ẅ', 'Ẅ'), + ('Ẇ', 'Ẇ'), + ('Ẉ', 'Ẉ'), + ('Ẋ', 'Ẋ'), + ('Ẍ', 'Ẍ'), + ('Ẏ', 'Ẏ'), + ('áº', 'áº'), + ('Ẓ', 'Ẓ'), + ('Ẕ', 'Ẕ'), + ('ẞ', 'ẞ'), + ('Ạ', 'Ạ'), + ('Ả', 'Ả'), + ('Ấ', 'Ấ'), + ('Ầ', 'Ầ'), + ('Ẩ', 'Ẩ'), + ('Ẫ', 'Ẫ'), + ('Ậ', 'Ậ'), + ('Ắ', 'Ắ'), + ('Ằ', 'Ằ'), + ('Ẳ', 'Ẳ'), + ('Ẵ', 'Ẵ'), + ('Ặ', 'Ặ'), + ('Ẹ', 'Ẹ'), + ('Ẻ', 'Ẻ'), + ('Ẽ', 'Ẽ'), + ('Ế', 'Ế'), + ('Ề', 'Ề'), + ('Ể', 'Ể'), + ('Ễ', 'Ễ'), + ('Ệ', 'Ệ'), + ('Ỉ', 'Ỉ'), + ('Ị', 'Ị'), + ('Ọ', 'Ọ'), + ('Ỏ', 'Ỏ'), + ('á»', 'á»'), + ('á»’', 'á»’'), + ('á»”', 'á»”'), + ('á»–', 'á»–'), + ('Ộ', 'Ộ'), + ('Ớ', 'Ớ'), + ('Ờ', 'Ờ'), + ('Ở', 'Ở'), + ('á» ', 'á» '), + ('Ợ', 'Ợ'), + ('Ụ', 'Ụ'), + ('Ủ', 'Ủ'), + ('Ứ', 'Ứ'), + ('Ừ', 'Ừ'), + ('Ử', 'Ử'), + ('á»®', 'á»®'), + ('á»°', 'á»°'), + ('Ỳ', 'Ỳ'), + ('á»´', 'á»´'), + ('Ỷ', 'Ỷ'), + ('Ỹ', 'Ỹ'), + ('Ỻ', 'Ỻ'), + ('Ỽ', 'Ỽ'), + ('Ỿ', 'Ỿ'), + ('Ἀ', 'á¼'), + ('Ἐ', 'á¼'), + ('Ἠ', 'Ἧ'), + ('Ἰ', 'Ἷ'), + ('Ὀ', 'á½'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'Ὗ'), + ('Ὠ', 'Ὧ'), + ('Ᾰ', 'á¾»'), + ('Ὲ', 'á¿‹'), + ('Ῐ', 'á¿›'), + ('Ῠ', 'Ῥ'), + ('Ὸ', 'á¿»'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„‹', 'â„'), + ('â„', 'â„’'), + ('â„•', 'â„•'), + ('â„™', 'â„'), + ('ℤ', 'ℤ'), + ('Ω', 'Ω'), + ('ℨ', 'ℨ'), + ('K', 'â„­'), + ('â„°', 'ℳ'), + ('ℾ', 'â„¿'), + ('â……', 'â……'), + ('Ↄ', 'Ↄ'), + ('â°€', 'â°¯'), + ('â± ', 'â± '), + ('â±¢', 'Ɽ'), + ('Ⱨ', 'Ⱨ'), + ('Ⱪ', 'Ⱪ'), + ('Ⱬ', 'Ⱬ'), + ('â±­', 'â±°'), + ('â±²', 'â±²'), + ('â±µ', 'â±µ'), + ('â±¾', 'â²€'), + ('Ⲃ', 'Ⲃ'), + ('Ⲅ', 'Ⲅ'), + ('Ⲇ', 'Ⲇ'), + ('Ⲉ', 'Ⲉ'), + ('Ⲋ', 'Ⲋ'), + ('Ⲍ', 'Ⲍ'), + ('Ⲏ', 'Ⲏ'), + ('â²', 'â²'), + ('â²’', 'â²’'), + ('â²”', 'â²”'), + ('â²–', 'â²–'), + ('Ⲙ', 'Ⲙ'), + ('Ⲛ', 'Ⲛ'), + ('Ⲝ', 'Ⲝ'), + ('Ⲟ', 'Ⲟ'), + ('â² ', 'â² '), + ('â²¢', 'â²¢'), + ('Ⲥ', 'Ⲥ'), + ('Ⲧ', 'Ⲧ'), + ('Ⲩ', 'Ⲩ'), + ('Ⲫ', 'Ⲫ'), + ('Ⲭ', 'Ⲭ'), + ('â²®', 'â²®'), + ('â²°', 'â²°'), + ('â²²', 'â²²'), + ('â²´', 'â²´'), + ('Ⲷ', 'Ⲷ'), + ('Ⲹ', 'Ⲹ'), + ('Ⲻ', 'Ⲻ'), + ('â²¼', 'â²¼'), + ('â²¾', 'â²¾'), + ('â³€', 'â³€'), + ('Ⳃ', 'Ⳃ'), + ('Ⳅ', 'Ⳅ'), + ('Ⳇ', 'Ⳇ'), + ('Ⳉ', 'Ⳉ'), + ('Ⳋ', 'Ⳋ'), + ('Ⳍ', 'Ⳍ'), + ('Ⳏ', 'Ⳏ'), + ('â³', 'â³'), + ('â³’', 'â³’'), + ('â³”', 'â³”'), + ('â³–', 'â³–'), + ('Ⳙ', 'Ⳙ'), + ('Ⳛ', 'Ⳛ'), + ('Ⳝ', 'Ⳝ'), + ('Ⳟ', 'Ⳟ'), + ('â³ ', 'â³ '), + ('â³¢', 'â³¢'), + ('Ⳬ', 'Ⳬ'), + ('â³­', 'â³­'), + ('â³²', 'â³²'), + ('Ꙁ', 'Ꙁ'), + ('Ꙃ', 'Ꙃ'), + ('Ꙅ', 'Ꙅ'), + ('Ꙇ', 'Ꙇ'), + ('Ꙉ', 'Ꙉ'), + ('Ꙋ', 'Ꙋ'), + ('Ꙍ', 'Ꙍ'), + ('Ꙏ', 'Ꙏ'), + ('ê™', 'ê™'), + ('ê™’', 'ê™’'), + ('ê™”', 'ê™”'), + ('ê™–', 'ê™–'), + ('Ꙙ', 'Ꙙ'), + ('Ꙛ', 'Ꙛ'), + ('Ꙝ', 'Ꙝ'), + ('Ꙟ', 'Ꙟ'), + ('ê™ ', 'ê™ '), + ('Ꙣ', 'Ꙣ'), + ('Ꙥ', 'Ꙥ'), + ('Ꙧ', 'Ꙧ'), + ('Ꙩ', 'Ꙩ'), + ('Ꙫ', 'Ꙫ'), + ('Ꙭ', 'Ꙭ'), + ('Ꚁ', 'Ꚁ'), + ('êš‚', 'êš‚'), + ('êš„', 'êš„'), + ('Ꚇ', 'Ꚇ'), + ('Ꚉ', 'Ꚉ'), + ('Ꚋ', 'Ꚋ'), + ('Ꚍ', 'Ꚍ'), + ('Ꚏ', 'Ꚏ'), + ('êš', 'êš'), + ('êš’', 'êš’'), + ('êš”', 'êš”'), + ('êš–', 'êš–'), + ('Ꚙ', 'Ꚙ'), + ('êšš', 'êšš'), + ('Ꜣ', 'Ꜣ'), + ('Ꜥ', 'Ꜥ'), + ('Ꜧ', 'Ꜧ'), + ('Ꜩ', 'Ꜩ'), + ('Ꜫ', 'Ꜫ'), + ('Ꜭ', 'Ꜭ'), + ('Ꜯ', 'Ꜯ'), + ('Ꜳ', 'Ꜳ'), + ('Ꜵ', 'Ꜵ'), + ('Ꜷ', 'Ꜷ'), + ('Ꜹ', 'Ꜹ'), + ('Ꜻ', 'Ꜻ'), + ('Ꜽ', 'Ꜽ'), + ('Ꜿ', 'Ꜿ'), + ('ê€', 'ê€'), + ('ê‚', 'ê‚'), + ('ê„', 'ê„'), + ('ê†', 'ê†'), + ('êˆ', 'êˆ'), + ('êŠ', 'êŠ'), + ('êŒ', 'êŒ'), + ('êŽ', 'êŽ'), + ('ê', 'ê'), + ('ê’', 'ê’'), + ('ê”', 'ê”'), + ('ê–', 'ê–'), + ('ê˜', 'ê˜'), + ('êš', 'êš'), + ('êœ', 'êœ'), + ('êž', 'êž'), + ('ê ', 'ê '), + ('ê¢', 'ê¢'), + ('ê¤', 'ê¤'), + ('ê¦', 'ê¦'), + ('ê¨', 'ê¨'), + ('êª', 'êª'), + ('ê¬', 'ê¬'), + ('ê®', 'ê®'), + ('ê¹', 'ê¹'), + ('ê»', 'ê»'), + ('ê½', 'ê¾'), + ('Ꞁ', 'Ꞁ'), + ('êž‚', 'êž‚'), + ('êž„', 'êž„'), + ('Ꞇ', 'Ꞇ'), + ('êž‹', 'êž‹'), + ('êž', 'êž'), + ('êž', 'êž'), + ('êž’', 'êž’'), + ('êž–', 'êž–'), + ('Ꞙ', 'Ꞙ'), + ('êžš', 'êžš'), + ('êžœ', 'êžœ'), + ('êžž', 'êžž'), + ('êž ', 'êž '), + ('Ꞣ', 'Ꞣ'), + ('Ꞥ', 'Ꞥ'), + ('Ꞧ', 'Ꞧ'), + ('Ꞩ', 'Ꞩ'), + ('Ɦ', 'êž®'), + ('êž°', 'êž´'), + ('Ꞷ', 'Ꞷ'), + ('Ꞹ', 'Ꞹ'), + ('Ꞻ', 'Ꞻ'), + ('êž¼', 'êž¼'), + ('êž¾', 'êž¾'), + ('Ꟁ', 'Ꟁ'), + ('Ꟃ', 'Ꟃ'), + ('Ꞔ', 'Ꟈ'), + ('Ꟊ', 'Ꟊ'), + ('êŸ', 'êŸ'), + ('Ꟗ', 'Ꟗ'), + ('Ꟙ', 'Ꟙ'), + ('Ꟶ', 'Ꟶ'), + ('A', 'Z'), + ('ð€', 'ð§'), + ('ð’°', 'ð““'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð²€', 'ð²²'), + ('ð‘¢ ', '𑢿'), + ('ð–¹€', '𖹟'), + ('ð€', 'ð™'), + ('ð´', 'ð‘'), + ('ð‘¨', 'ð’'), + ('ð’œ', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’µ'), + ('ð“', 'ð“©'), + ('ð”„', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”¸', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•¬', 'ð–…'), + ('ð– ', 'ð–¹'), + ('ð—”', 'ð—­'), + ('ð˜ˆ', 'ð˜¡'), + ('ð˜¼', 'ð™•'), + ('ð™°', 'ðš‰'), + ('ðš¨', 'ð›€'), + ('ð›¢', 'ð›º'), + ('ðœœ', 'ðœ´'), + ('ð–', 'ð®'), + ('ðž', 'ðž¨'), + ('ðŸŠ', 'ðŸŠ'), + ('𞤀', '𞤡'), +]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/grapheme_cluster_break.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/grapheme_cluster_break.rs new file mode 100644 index 0000000000000..294dfbdcc00bb --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/grapheme_cluster_break.rs @@ -0,0 +1,1416 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate grapheme-cluster-break ucd-15.0.0 --chars +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("CR", CR), + ("Control", CONTROL), + ("Extend", EXTEND), + ("L", L), + ("LF", LF), + ("LV", LV), + ("LVT", LVT), + ("Prepend", PREPEND), + ("Regional_Indicator", REGIONAL_INDICATOR), + ("SpacingMark", SPACINGMARK), + ("T", T), + ("V", V), + ("ZWJ", ZWJ), +]; + +pub const CR: &'static [(char, char)] = &[('\r', '\r')]; + +pub const CONTROL: &'static [(char, char)] = &[ + ('\0', '\t'), + ('\u{b}', '\u{c}'), + ('\u{e}', '\u{1f}'), + ('\u{7f}', '\u{9f}'), + ('\u{ad}', '\u{ad}'), + ('\u{61c}', '\u{61c}'), + ('\u{180e}', '\u{180e}'), + ('\u{200b}', '\u{200b}'), + ('\u{200e}', '\u{200f}'), + ('\u{2028}', '\u{202e}'), + ('\u{2060}', '\u{206f}'), + ('\u{feff}', '\u{feff}'), + ('\u{fff0}', '\u{fffb}'), + ('\u{13430}', '\u{1343f}'), + ('\u{1bca0}', '\u{1bca3}'), + ('\u{1d173}', '\u{1d17a}'), + ('\u{e0000}', '\u{e001f}'), + ('\u{e0080}', '\u{e00ff}'), + ('\u{e01f0}', '\u{e0fff}'), +]; + +pub const EXTEND: &'static [(char, char)] = &[ + ('\u{300}', '\u{36f}'), + ('\u{483}', '\u{489}'), + ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), + ('\u{610}', '\u{61a}'), + ('\u{64b}', '\u{65f}'), + ('\u{670}', '\u{670}'), + ('\u{6d6}', '\u{6dc}'), + ('\u{6df}', '\u{6e4}'), + ('\u{6e7}', '\u{6e8}'), + ('\u{6ea}', '\u{6ed}'), + ('\u{711}', '\u{711}'), + ('\u{730}', '\u{74a}'), + ('\u{7a6}', '\u{7b0}'), + ('\u{7eb}', '\u{7f3}'), + ('\u{7fd}', '\u{7fd}'), + ('\u{816}', '\u{819}'), + ('\u{81b}', '\u{823}'), + ('\u{825}', '\u{827}'), + ('\u{829}', '\u{82d}'), + ('\u{859}', '\u{85b}'), + ('\u{898}', '\u{89f}'), + ('\u{8ca}', '\u{8e1}'), + ('\u{8e3}', '\u{902}'), + ('\u{93a}', '\u{93a}'), + ('\u{93c}', '\u{93c}'), + ('\u{941}', '\u{948}'), + ('\u{94d}', '\u{94d}'), + ('\u{951}', '\u{957}'), + ('\u{962}', '\u{963}'), + ('\u{981}', '\u{981}'), + ('\u{9bc}', '\u{9bc}'), + ('\u{9be}', '\u{9be}'), + ('\u{9c1}', '\u{9c4}'), + ('\u{9cd}', '\u{9cd}'), + ('\u{9d7}', '\u{9d7}'), + ('\u{9e2}', '\u{9e3}'), + ('\u{9fe}', '\u{9fe}'), + ('\u{a01}', '\u{a02}'), + ('\u{a3c}', '\u{a3c}'), + ('\u{a41}', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), + ('\u{a70}', '\u{a71}'), + ('\u{a75}', '\u{a75}'), + ('\u{a81}', '\u{a82}'), + ('\u{abc}', '\u{abc}'), + ('\u{ac1}', '\u{ac5}'), + ('\u{ac7}', '\u{ac8}'), + ('\u{acd}', '\u{acd}'), + ('\u{ae2}', '\u{ae3}'), + ('\u{afa}', '\u{aff}'), + ('\u{b01}', '\u{b01}'), + ('\u{b3c}', '\u{b3c}'), + ('\u{b3e}', '\u{b3f}'), + ('\u{b41}', '\u{b44}'), + ('\u{b4d}', '\u{b4d}'), + ('\u{b55}', '\u{b57}'), + ('\u{b62}', '\u{b63}'), + ('\u{b82}', '\u{b82}'), + ('\u{bbe}', '\u{bbe}'), + ('\u{bc0}', '\u{bc0}'), + ('\u{bcd}', '\u{bcd}'), + ('\u{bd7}', '\u{bd7}'), + ('\u{c00}', '\u{c00}'), + ('\u{c04}', '\u{c04}'), + ('\u{c3c}', '\u{c3c}'), + ('\u{c3e}', '\u{c40}'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('\u{c62}', '\u{c63}'), + ('\u{c81}', '\u{c81}'), + ('\u{cbc}', '\u{cbc}'), + ('\u{cbf}', '\u{cbf}'), + ('\u{cc2}', '\u{cc2}'), + ('\u{cc6}', '\u{cc6}'), + ('\u{ccc}', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), + ('\u{ce2}', '\u{ce3}'), + ('\u{d00}', '\u{d01}'), + ('\u{d3b}', '\u{d3c}'), + ('\u{d3e}', '\u{d3e}'), + ('\u{d41}', '\u{d44}'), + ('\u{d4d}', '\u{d4d}'), + ('\u{d57}', '\u{d57}'), + ('\u{d62}', '\u{d63}'), + ('\u{d81}', '\u{d81}'), + ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dcf}'), + ('\u{dd2}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('\u{ddf}', '\u{ddf}'), + ('\u{e31}', '\u{e31}'), + ('\u{e34}', '\u{e3a}'), + ('\u{e47}', '\u{e4e}'), + ('\u{eb1}', '\u{eb1}'), + ('\u{eb4}', '\u{ebc}'), + ('\u{ec8}', '\u{ece}'), + ('\u{f18}', '\u{f19}'), + ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), + ('\u{f39}', '\u{f39}'), + ('\u{f71}', '\u{f7e}'), + ('\u{f80}', '\u{f84}'), + ('\u{f86}', '\u{f87}'), + ('\u{f8d}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('\u{fc6}', '\u{fc6}'), + ('\u{102d}', '\u{1030}'), + ('\u{1032}', '\u{1037}'), + ('\u{1039}', '\u{103a}'), + ('\u{103d}', '\u{103e}'), + ('\u{1058}', '\u{1059}'), + ('\u{105e}', '\u{1060}'), + ('\u{1071}', '\u{1074}'), + ('\u{1082}', '\u{1082}'), + ('\u{1085}', '\u{1086}'), + ('\u{108d}', '\u{108d}'), + ('\u{109d}', '\u{109d}'), + ('\u{135d}', '\u{135f}'), + ('\u{1712}', '\u{1714}'), + ('\u{1732}', '\u{1733}'), + ('\u{1752}', '\u{1753}'), + ('\u{1772}', '\u{1773}'), + ('\u{17b4}', '\u{17b5}'), + ('\u{17b7}', '\u{17bd}'), + ('\u{17c6}', '\u{17c6}'), + ('\u{17c9}', '\u{17d3}'), + ('\u{17dd}', '\u{17dd}'), + ('\u{180b}', '\u{180d}'), + ('\u{180f}', '\u{180f}'), + ('\u{1885}', '\u{1886}'), + ('\u{18a9}', '\u{18a9}'), + ('\u{1920}', '\u{1922}'), + ('\u{1927}', '\u{1928}'), + ('\u{1932}', '\u{1932}'), + ('\u{1939}', '\u{193b}'), + ('\u{1a17}', '\u{1a18}'), + ('\u{1a1b}', '\u{1a1b}'), + ('\u{1a56}', '\u{1a56}'), + ('\u{1a58}', '\u{1a5e}'), + ('\u{1a60}', '\u{1a60}'), + ('\u{1a62}', '\u{1a62}'), + ('\u{1a65}', '\u{1a6c}'), + ('\u{1a73}', '\u{1a7c}'), + ('\u{1a7f}', '\u{1a7f}'), + ('\u{1ab0}', '\u{1ace}'), + ('\u{1b00}', '\u{1b03}'), + ('\u{1b34}', '\u{1b3a}'), + ('\u{1b3c}', '\u{1b3c}'), + ('\u{1b42}', '\u{1b42}'), + ('\u{1b6b}', '\u{1b73}'), + ('\u{1b80}', '\u{1b81}'), + ('\u{1ba2}', '\u{1ba5}'), + ('\u{1ba8}', '\u{1ba9}'), + ('\u{1bab}', '\u{1bad}'), + ('\u{1be6}', '\u{1be6}'), + ('\u{1be8}', '\u{1be9}'), + ('\u{1bed}', '\u{1bed}'), + ('\u{1bef}', '\u{1bf1}'), + ('\u{1c2c}', '\u{1c33}'), + ('\u{1c36}', '\u{1c37}'), + ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', '\u{1ce0}'), + ('\u{1ce2}', '\u{1ce8}'), + ('\u{1ced}', '\u{1ced}'), + ('\u{1cf4}', '\u{1cf4}'), + ('\u{1cf8}', '\u{1cf9}'), + ('\u{1dc0}', '\u{1dff}'), + ('\u{200c}', '\u{200c}'), + ('\u{20d0}', '\u{20f0}'), + ('\u{2cef}', '\u{2cf1}'), + ('\u{2d7f}', '\u{2d7f}'), + ('\u{2de0}', '\u{2dff}'), + ('\u{302a}', '\u{302f}'), + ('\u{3099}', '\u{309a}'), + ('\u{a66f}', '\u{a672}'), + ('\u{a674}', '\u{a67d}'), + ('\u{a69e}', '\u{a69f}'), + ('\u{a6f0}', '\u{a6f1}'), + ('\u{a802}', '\u{a802}'), + ('\u{a806}', '\u{a806}'), + ('\u{a80b}', '\u{a80b}'), + ('\u{a825}', '\u{a826}'), + ('\u{a82c}', '\u{a82c}'), + ('\u{a8c4}', '\u{a8c5}'), + ('\u{a8e0}', '\u{a8f1}'), + ('\u{a8ff}', '\u{a8ff}'), + ('\u{a926}', '\u{a92d}'), + ('\u{a947}', '\u{a951}'), + ('\u{a980}', '\u{a982}'), + ('\u{a9b3}', '\u{a9b3}'), + ('\u{a9b6}', '\u{a9b9}'), + ('\u{a9bc}', '\u{a9bd}'), + ('\u{a9e5}', '\u{a9e5}'), + ('\u{aa29}', '\u{aa2e}'), + ('\u{aa31}', '\u{aa32}'), + ('\u{aa35}', '\u{aa36}'), + ('\u{aa43}', '\u{aa43}'), + ('\u{aa4c}', '\u{aa4c}'), + ('\u{aa7c}', '\u{aa7c}'), + ('\u{aab0}', '\u{aab0}'), + ('\u{aab2}', '\u{aab4}'), + ('\u{aab7}', '\u{aab8}'), + ('\u{aabe}', '\u{aabf}'), + ('\u{aac1}', '\u{aac1}'), + ('\u{aaec}', '\u{aaed}'), + ('\u{aaf6}', '\u{aaf6}'), + ('\u{abe5}', '\u{abe5}'), + ('\u{abe8}', '\u{abe8}'), + ('\u{abed}', '\u{abed}'), + ('\u{fb1e}', '\u{fb1e}'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{fe20}', '\u{fe2f}'), + ('\u{ff9e}', '\u{ff9f}'), + ('\u{101fd}', '\u{101fd}'), + ('\u{102e0}', '\u{102e0}'), + ('\u{10376}', '\u{1037a}'), + ('\u{10a01}', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), + ('\u{10ae5}', '\u{10ae6}'), + ('\u{10d24}', '\u{10d27}'), + ('\u{10eab}', '\u{10eac}'), + ('\u{10efd}', '\u{10eff}'), + ('\u{10f46}', '\u{10f50}'), + ('\u{10f82}', '\u{10f85}'), + ('\u{11001}', '\u{11001}'), + ('\u{11038}', '\u{11046}'), + ('\u{11070}', '\u{11070}'), + ('\u{11073}', '\u{11074}'), + ('\u{1107f}', '\u{11081}'), + ('\u{110b3}', '\u{110b6}'), + ('\u{110b9}', '\u{110ba}'), + ('\u{110c2}', '\u{110c2}'), + ('\u{11100}', '\u{11102}'), + ('\u{11127}', '\u{1112b}'), + ('\u{1112d}', '\u{11134}'), + ('\u{11173}', '\u{11173}'), + ('\u{11180}', '\u{11181}'), + ('\u{111b6}', '\u{111be}'), + ('\u{111c9}', '\u{111cc}'), + ('\u{111cf}', '\u{111cf}'), + ('\u{1122f}', '\u{11231}'), + ('\u{11234}', '\u{11234}'), + ('\u{11236}', '\u{11237}'), + ('\u{1123e}', '\u{1123e}'), + ('\u{11241}', '\u{11241}'), + ('\u{112df}', '\u{112df}'), + ('\u{112e3}', '\u{112ea}'), + ('\u{11300}', '\u{11301}'), + ('\u{1133b}', '\u{1133c}'), + ('\u{1133e}', '\u{1133e}'), + ('\u{11340}', '\u{11340}'), + ('\u{11357}', '\u{11357}'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('\u{11438}', '\u{1143f}'), + ('\u{11442}', '\u{11444}'), + ('\u{11446}', '\u{11446}'), + ('\u{1145e}', '\u{1145e}'), + ('\u{114b0}', '\u{114b0}'), + ('\u{114b3}', '\u{114b8}'), + ('\u{114ba}', '\u{114ba}'), + ('\u{114bd}', '\u{114bd}'), + ('\u{114bf}', '\u{114c0}'), + ('\u{114c2}', '\u{114c3}'), + ('\u{115af}', '\u{115af}'), + ('\u{115b2}', '\u{115b5}'), + ('\u{115bc}', '\u{115bd}'), + ('\u{115bf}', '\u{115c0}'), + ('\u{115dc}', '\u{115dd}'), + ('\u{11633}', '\u{1163a}'), + ('\u{1163d}', '\u{1163d}'), + ('\u{1163f}', '\u{11640}'), + ('\u{116ab}', '\u{116ab}'), + ('\u{116ad}', '\u{116ad}'), + ('\u{116b0}', '\u{116b5}'), + ('\u{116b7}', '\u{116b7}'), + ('\u{1171d}', '\u{1171f}'), + ('\u{11722}', '\u{11725}'), + ('\u{11727}', '\u{1172b}'), + ('\u{1182f}', '\u{11837}'), + ('\u{11839}', '\u{1183a}'), + ('\u{11930}', '\u{11930}'), + ('\u{1193b}', '\u{1193c}'), + ('\u{1193e}', '\u{1193e}'), + ('\u{11943}', '\u{11943}'), + ('\u{119d4}', '\u{119d7}'), + ('\u{119da}', '\u{119db}'), + ('\u{119e0}', '\u{119e0}'), + ('\u{11a01}', '\u{11a0a}'), + ('\u{11a33}', '\u{11a38}'), + ('\u{11a3b}', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), + ('\u{11a51}', '\u{11a56}'), + ('\u{11a59}', '\u{11a5b}'), + ('\u{11a8a}', '\u{11a96}'), + ('\u{11a98}', '\u{11a99}'), + ('\u{11c30}', '\u{11c36}'), + ('\u{11c38}', '\u{11c3d}'), + ('\u{11c3f}', '\u{11c3f}'), + ('\u{11c92}', '\u{11ca7}'), + ('\u{11caa}', '\u{11cb0}'), + ('\u{11cb2}', '\u{11cb3}'), + ('\u{11cb5}', '\u{11cb6}'), + ('\u{11d31}', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d45}'), + ('\u{11d47}', '\u{11d47}'), + ('\u{11d90}', '\u{11d91}'), + ('\u{11d95}', '\u{11d95}'), + ('\u{11d97}', '\u{11d97}'), + ('\u{11ef3}', '\u{11ef4}'), + ('\u{11f00}', '\u{11f01}'), + ('\u{11f36}', '\u{11f3a}'), + ('\u{11f40}', '\u{11f40}'), + ('\u{11f42}', '\u{11f42}'), + ('\u{13440}', '\u{13440}'), + ('\u{13447}', '\u{13455}'), + ('\u{16af0}', '\u{16af4}'), + ('\u{16b30}', '\u{16b36}'), + ('\u{16f4f}', '\u{16f4f}'), + ('\u{16f8f}', '\u{16f92}'), + ('\u{16fe4}', '\u{16fe4}'), + ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('\u{1d165}', '\u{1d165}'), + ('\u{1d167}', '\u{1d169}'), + ('\u{1d16e}', '\u{1d172}'), + ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), + ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), + ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), + ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('\u{1e08f}', '\u{1e08f}'), + ('\u{1e130}', '\u{1e136}'), + ('\u{1e2ae}', '\u{1e2ae}'), + ('\u{1e2ec}', '\u{1e2ef}'), + ('\u{1e4ec}', '\u{1e4ef}'), + ('\u{1e8d0}', '\u{1e8d6}'), + ('\u{1e944}', '\u{1e94a}'), + ('ðŸ»', 'ðŸ¿'), + ('\u{e0020}', '\u{e007f}'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const L: &'static [(char, char)] = &[('á„€', 'á…Ÿ'), ('ꥠ', 'ꥼ')]; + +pub const LF: &'static [(char, char)] = &[('\n', '\n')]; + +pub const LV: &'static [(char, char)] = &[ + ('ê°€', 'ê°€'), + ('ê°œ', 'ê°œ'), + ('ê°¸', 'ê°¸'), + ('ê±”', 'ê±”'), + ('ê±°', 'ê±°'), + ('게', '게'), + ('겨', '겨'), + ('계', '계'), + ('ê³ ', 'ê³ '), + ('ê³¼', 'ê³¼'), + ('ê´˜', 'ê´˜'), + ('ê´´', 'ê´´'), + ('êµ', 'êµ'), + ('구', '구'), + ('궈', '궈'), + ('궤', '궤'), + ('ê·€', 'ê·€'), + ('ê·œ', 'ê·œ'), + ('ê·¸', 'ê·¸'), + ('긔', '긔'), + ('기', '기'), + ('까', '까'), + ('깨', '깨'), + ('꺄', '꺄'), + ('꺠', '꺠'), + ('꺼', '꺼'), + ('께', '께'), + ('ê»´', 'ê»´'), + ('ê¼', 'ê¼'), + ('꼬', '꼬'), + ('꽈', '꽈'), + ('꽤', '꽤'), + ('ê¾€', 'ê¾€'), + ('꾜', '꾜'), + ('꾸', '꾸'), + ('ê¿”', 'ê¿”'), + ('ê¿°', 'ê¿°'), + ('뀌', '뀌'), + ('뀨', '뀨'), + ('ë„', 'ë„'), + ('ë ', 'ë '), + ('ë¼', 'ë¼'), + ('나', '나'), + ('ë‚´', 'ë‚´'), + ('ëƒ', 'ëƒ'), + ('냬', '냬'), + ('너', '너'), + ('네', '네'), + ('ë…€', 'ë…€'), + ('ë…œ', 'ë…œ'), + ('ë…¸', 'ë…¸'), + ('놔', '놔'), + ('놰', '놰'), + ('뇌', '뇌'), + ('뇨', '뇨'), + ('누', '누'), + ('눠', '눠'), + ('눼', '눼'), + ('뉘', '뉘'), + ('뉴', '뉴'), + ('ëŠ', 'ëŠ'), + ('늬', '늬'), + ('니', '니'), + ('다', '다'), + ('대', '대'), + ('댜', '댜'), + ('댸', '댸'), + ('ë”', 'ë”'), + ('ë°', 'ë°'), + ('뎌', '뎌'), + ('뎨', '뎨'), + ('ë„', 'ë„'), + ('ë ', 'ë '), + ('ë¼', 'ë¼'), + ('ë˜', 'ë˜'), + ('ë´', 'ë´'), + ('ë‘', 'ë‘'), + ('둬', '둬'), + ('ë’ˆ', 'ë’ˆ'), + ('ë’¤', 'ë’¤'), + ('ë“€', 'ë“€'), + ('ë“œ', 'ë“œ'), + ('듸', '듸'), + ('ë””', 'ë””'), + ('ë”°', 'ë”°'), + ('ë•Œ', 'ë•Œ'), + ('땨', '땨'), + ('ë–„', 'ë–„'), + ('ë– ', 'ë– '), + ('ë–¼', 'ë–¼'), + ('ë—˜', 'ë—˜'), + ('ë—´', 'ë—´'), + ('ë˜', 'ë˜'), + ('똬', '똬'), + ('뙈', '뙈'), + ('뙤', '뙤'), + ('뚀', '뚀'), + ('ëšœ', 'ëšœ'), + ('뚸', '뚸'), + ('ë›”', 'ë›”'), + ('ë›°', 'ë›°'), + ('뜌', '뜌'), + ('뜨', '뜨'), + ('ë„', 'ë„'), + ('ë ', 'ë '), + ('ë¼', 'ë¼'), + ('래', '래'), + ('ëž´', 'ëž´'), + ('ëŸ', 'ëŸ'), + ('러', '러'), + ('ë ˆ', 'ë ˆ'), + ('ë ¤', 'ë ¤'), + ('ë¡€', 'ë¡€'), + ('ë¡œ', 'ë¡œ'), + ('롸', '롸'), + ('뢔', '뢔'), + ('뢰', '뢰'), + ('료', '료'), + ('루', '루'), + ('뤄', '뤄'), + ('뤠', '뤠'), + ('뤼', '뤼'), + ('류', '류'), + ('르', '르'), + ('ë¦', 'ë¦'), + ('리', '리'), + ('마', '마'), + ('매', '매'), + ('먀', '먀'), + ('먜', '먜'), + ('머', '머'), + ('ë©”', 'ë©”'), + ('ë©°', 'ë©°'), + ('몌', '몌'), + ('모', '모'), + ('ë«„', 'ë«„'), + ('ë« ', 'ë« '), + ('뫼', '뫼'), + ('묘', '묘'), + ('무', '무'), + ('ë­', 'ë­'), + ('ë­¬', 'ë­¬'), + ('뮈', '뮈'), + ('뮤', '뮤'), + ('므', '므'), + ('믜', '믜'), + ('미', '미'), + ('ë°”', 'ë°”'), + ('ë°°', 'ë°°'), + ('뱌', '뱌'), + ('뱨', '뱨'), + ('버', '버'), + ('ë² ', 'ë² '), + ('ë²¼', 'ë²¼'), + ('볘', '볘'), + ('ë³´', 'ë³´'), + ('ë´', 'ë´'), + ('ë´¬', 'ë´¬'), + ('뵈', '뵈'), + ('뵤', '뵤'), + ('부', '부'), + ('붜', '붜'), + ('붸', '붸'), + ('ë·”', 'ë·”'), + ('ë·°', 'ë·°'), + ('브', '브'), + ('븨', '븨'), + ('비', '비'), + ('ë¹ ', 'ë¹ '), + ('ë¹¼', 'ë¹¼'), + ('뺘', '뺘'), + ('뺴', '뺴'), + ('ë»', 'ë»'), + ('뻬', '뻬'), + ('뼈', '뼈'), + ('뼤', '뼤'), + ('ë½€', 'ë½€'), + ('뽜', '뽜'), + ('뽸', '뽸'), + ('ë¾”', 'ë¾”'), + ('ë¾°', 'ë¾°'), + ('ë¿Œ', 'ë¿Œ'), + ('뿨', '뿨'), + ('쀄', '쀄'), + ('쀠', '쀠'), + ('쀼', '쀼'), + ('ì˜', 'ì˜'), + ('ì´', 'ì´'), + ('ì‚', 'ì‚'), + ('사', '사'), + ('새', '새'), + ('샤', '샤'), + ('ì„€', 'ì„€'), + ('ì„œ', 'ì„œ'), + ('세', '세'), + ('ì…”', 'ì…”'), + ('ì…°', 'ì…°'), + ('소', '소'), + ('솨', '솨'), + ('쇄', '쇄'), + ('쇠', '쇠'), + ('쇼', '쇼'), + ('수', '수'), + ('숴', '숴'), + ('ì‰', 'ì‰'), + ('쉬', '쉬'), + ('슈', '슈'), + ('스', '스'), + ('ì‹€', 'ì‹€'), + ('ì‹œ', 'ì‹œ'), + ('싸', '싸'), + ('쌔', '쌔'), + ('쌰', '쌰'), + ('ìŒ', 'ìŒ'), + ('ì¨', 'ì¨'), + ('쎄', '쎄'), + ('쎠', '쎠'), + ('쎼', '쎼'), + ('ì˜', 'ì˜'), + ('ì´', 'ì´'), + ('ì', 'ì'), + ('ì¬', 'ì¬'), + ('쑈', '쑈'), + ('쑤', '쑤'), + ('ì’€', 'ì’€'), + ('ì’œ', 'ì’œ'), + ('ì’¸', 'ì’¸'), + ('ì“”', 'ì“”'), + ('ì“°', 'ì“°'), + ('씌', '씌'), + ('씨', '씨'), + ('ì•„', 'ì•„'), + ('ì• ', 'ì• '), + ('야', '야'), + ('ì–˜', 'ì–˜'), + ('ì–´', 'ì–´'), + ('ì—', 'ì—'), + ('ì—¬', 'ì—¬'), + ('예', '예'), + ('오', '오'), + ('와', '와'), + ('왜', '왜'), + ('외', '외'), + ('ìš”', 'ìš”'), + ('ìš°', 'ìš°'), + ('워', '워'), + ('웨', '웨'), + ('위', '위'), + ('유', '유'), + ('으', '으'), + ('ì˜', 'ì˜'), + ('ì´', 'ì´'), + ('ìž', 'ìž'), + ('재', '재'), + ('쟈', '쟈'), + ('쟤', '쟤'), + ('ì €', 'ì €'), + ('ì œ', 'ì œ'), + ('ì ¸', 'ì ¸'), + ('ì¡”', 'ì¡”'), + ('ì¡°', 'ì¡°'), + ('좌', '좌'), + ('좨', '좨'), + ('죄', '죄'), + ('죠', '죠'), + ('주', '주'), + ('줘', '줘'), + ('줴', '줴'), + ('ì¥', 'ì¥'), + ('쥬', '쥬'), + ('즈', '즈'), + ('즤', '즤'), + ('지', '지'), + ('짜', '짜'), + ('째', '째'), + ('쨔', '쨔'), + ('쨰', '쨰'), + ('ì©Œ', 'ì©Œ'), + ('쩨', '쩨'), + ('쪄', '쪄'), + ('쪠', '쪠'), + ('쪼', '쪼'), + ('쫘', '쫘'), + ('ì«´', 'ì«´'), + ('ì¬', 'ì¬'), + ('쬬', '쬬'), + ('ì­ˆ', 'ì­ˆ'), + ('ì­¤', 'ì­¤'), + ('쮀', '쮀'), + ('쮜', '쮜'), + ('쮸', '쮸'), + ('쯔', '쯔'), + ('쯰', '쯰'), + ('ì°Œ', 'ì°Œ'), + ('ì°¨', 'ì°¨'), + ('채', '채'), + ('ì± ', 'ì± '), + ('ì±¼', 'ì±¼'), + ('처', '처'), + ('ì²´', 'ì²´'), + ('ì³', 'ì³'), + ('쳬', '쳬'), + ('ì´ˆ', 'ì´ˆ'), + ('ì´¤', 'ì´¤'), + ('ìµ€', 'ìµ€'), + ('최', '최'), + ('쵸', '쵸'), + ('추', '추'), + ('춰', '춰'), + ('ì·Œ', 'ì·Œ'), + ('ì·¨', 'ì·¨'), + ('츄', '츄'), + ('츠', '츠'), + ('츼', '츼'), + ('치', '치'), + ('ì¹´', 'ì¹´'), + ('ìº', 'ìº'), + ('캬', '캬'), + ('컈', '컈'), + ('커', '커'), + ('ì¼€', 'ì¼€'), + ('켜', '켜'), + ('켸', '켸'), + ('ì½”', 'ì½”'), + ('ì½°', 'ì½°'), + ('쾌', '쾌'), + ('쾨', '쾨'), + ('ì¿„', 'ì¿„'), + ('ì¿ ', 'ì¿ '), + ('쿼', '쿼'), + ('퀘', '퀘'), + ('퀴', '퀴'), + ('í', 'í'), + ('í¬', 'í¬'), + ('킈', '킈'), + ('키', '키'), + ('타', '타'), + ('태', '태'), + ('탸', '탸'), + ('í„”', 'í„”'), + ('í„°', 'í„°'), + ('í…Œ', 'í…Œ'), + ('í…¨', 'í…¨'), + ('톄', '톄'), + ('토', '토'), + ('톼', '톼'), + ('퇘', '퇘'), + ('퇴', '퇴'), + ('íˆ', 'íˆ'), + ('투', '투'), + ('퉈', '퉈'), + ('퉤', '퉤'), + ('튀', '튀'), + ('튜', '튜'), + ('트', '트'), + ('í‹”', 'í‹”'), + ('í‹°', 'í‹°'), + ('파', '파'), + ('패', '패'), + ('í„', 'í„'), + ('í ', 'í '), + ('í¼', 'í¼'), + ('페', '페'), + ('펴', '펴'), + ('í', 'í'), + ('í¬', 'í¬'), + ('íˆ', 'íˆ'), + ('í¤', 'í¤'), + ('í‘€', 'í‘€'), + ('í‘œ', 'í‘œ'), + ('푸', '푸'), + ('í’”', 'í’”'), + ('í’°', 'í’°'), + ('í“Œ', 'í“Œ'), + ('퓨', '퓨'), + ('프', '프'), + ('í” ', 'í” '), + ('피', '피'), + ('하', '하'), + ('í•´', 'í•´'), + ('í–', 'í–'), + ('í–¬', 'í–¬'), + ('í—ˆ', 'í—ˆ'), + ('í—¤', 'í—¤'), + ('혀', '혀'), + ('혜', '혜'), + ('호', '호'), + ('í™”', 'í™”'), + ('í™°', 'í™°'), + ('회', '회'), + ('효', '효'), + ('후', '후'), + ('í› ', 'í› '), + ('훼', '훼'), + ('휘', '휘'), + ('휴', '휴'), + ('í', 'í'), + ('í¬', 'í¬'), + ('히', '히'), +]; + +pub const LVT: &'static [(char, char)] = &[ + ('ê°', 'ê°›'), + ('ê°', 'ê°·'), + ('ê°¹', '걓'), + ('걕', '걯'), + ('ê±±', '겋'), + ('ê²', '겧'), + ('격', '곃'), + ('ê³…', '곟'), + ('곡', 'ê³»'), + ('ê³½', 'ê´—'), + ('ê´™', 'ê´³'), + ('ê´µ', 'êµ'), + ('굑', '굫'), + ('êµ­', '궇'), + ('궉', '궣'), + ('궥', '궿'), + ('ê·', 'ê·›'), + ('ê·', 'ê··'), + ('ê·¹', '긓'), + ('긕', '긯'), + ('긱', '깋'), + ('ê¹', '깧'), + ('깩', '꺃'), + ('꺅', '꺟'), + ('꺡', '꺻'), + ('꺽', 'ê»—'), + ('ê»™', '껳'), + ('껵', 'ê¼'), + ('꼑', '꼫'), + ('ê¼­', '꽇'), + ('꽉', 'ê½£'), + ('ê½¥', '꽿'), + ('ê¾', 'ê¾›'), + ('ê¾', 'ê¾·'), + ('ê¾¹', 'ê¿“'), + ('ê¿•', '꿯'), + ('꿱', '뀋'), + ('ë€', '뀧'), + ('뀩', 'ëƒ'), + ('ë…', 'ëŸ'), + ('ë¡', 'ë»'), + ('ë½', 'ë‚—'), + ('ë‚™', '낳'), + ('낵', 'ëƒ'), + ('냑', '냫'), + ('냭', '넇'), + ('넉', 'ë„£'), + ('ë„¥', 'ë„¿'), + ('ë…', 'ë…›'), + ('ë…', 'ë…·'), + ('ë…¹', '놓'), + ('놕', '놯'), + ('놱', '뇋'), + ('ë‡', '뇧'), + ('뇩', '눃'), + ('눅', '눟'), + ('눡', '눻'), + ('눽', '뉗'), + ('뉙', '뉳'), + ('뉵', 'ëŠ'), + ('늑', '늫'), + ('늭', '닇'), + ('닉', 'ë‹£'), + ('ë‹¥', 'ë‹¿'), + ('ëŒ', '댛'), + ('ëŒ', '댷'), + ('댹', 'ë“'), + ('ë•', 'ë¯'), + ('ë±', '뎋'), + ('ëŽ', '뎧'), + ('뎩', 'ëƒ'), + ('ë…', 'ëŸ'), + ('ë¡', 'ë»'), + ('ë½', 'ë—'), + ('ë™', 'ë³'), + ('ëµ', 'ë‘'), + ('ë‘‘', 'ë‘«'), + ('ë‘­', 'ë’‡'), + ('ë’‰', 'ë’£'), + ('ë’¥', 'ë’¿'), + ('ë“', 'ë“›'), + ('ë“', 'ë“·'), + ('듹', '딓'), + ('딕', '딯'), + ('ë”±', 'ë•‹'), + ('ë•', '땧'), + ('ë•©', 'ë–ƒ'), + ('ë–…', 'ë–Ÿ'), + ('ë–¡', 'ë–»'), + ('ë–½', 'ë——'), + ('ë—™', 'ë—³'), + ('ë—µ', 'ë˜'), + ('똑', '똫'), + ('똭', '뙇'), + ('뙉', '뙣'), + ('뙥', '뙿'), + ('ëš', 'ëš›'), + ('ëš', 'ëš·'), + ('ëš¹', '뛓'), + ('뛕', '뛯'), + ('ë›±', '뜋'), + ('ëœ', '뜧'), + ('뜩', 'ëƒ'), + ('ë…', 'ëŸ'), + ('ë¡', 'ë»'), + ('ë½', 'ëž—'), + ('ëž™', 'ëž³'), + ('ëžµ', 'ëŸ'), + ('럑', '럫'), + ('럭', 'ë ‡'), + ('ë ‰', 'ë £'), + ('ë ¥', 'ë ¿'), + ('ë¡', 'ë¡›'), + ('ë¡', 'ë¡·'), + ('롹', '뢓'), + ('뢕', '뢯'), + ('뢱', '룋'), + ('ë£', '룧'), + ('룩', '뤃'), + ('뤅', '뤟'), + ('뤡', '뤻'), + ('뤽', '륗'), + ('륙', '륳'), + ('륵', 'ë¦'), + ('릑', '릫'), + ('릭', '맇'), + ('막', '맣'), + ('맥', '맿'), + ('ë¨', '먛'), + ('ë¨', '먷'), + ('먹', 'ë©“'), + ('ë©•', '멯'), + ('멱', '몋'), + ('ëª', '몧'), + ('목', '뫃'), + ('ë«…', 'ë«Ÿ'), + ('ë«¡', 'ë«»'), + ('뫽', '묗'), + ('묙', '묳'), + ('묵', 'ë­'), + ('ë­‘', 'ë­«'), + ('ë­­', '뮇'), + ('뮉', '뮣'), + ('뮥', '뮿'), + ('ë¯', '믛'), + ('ë¯', '믷'), + ('믹', 'ë°“'), + ('ë°•', 'ë°¯'), + ('ë°±', '뱋'), + ('ë±', '뱧'), + ('뱩', '벃'), + ('ë²…', '벟'), + ('벡', 'ë²»'), + ('ë²½', 'ë³—'), + ('ë³™', 'ë³³'), + ('ë³µ', 'ë´'), + ('ë´‘', 'ë´«'), + ('ë´­', '뵇'), + ('뵉', 'ëµ£'), + ('ëµ¥', '뵿'), + ('ë¶', '붛'), + ('ë¶', '붷'), + ('붹', 'ë·“'), + ('ë·•', 'ë·¯'), + ('ë·±', '븋'), + ('ë¸', '븧'), + ('븩', '빃'), + ('ë¹…', '빟'), + ('빡', 'ë¹»'), + ('ë¹½', '뺗'), + ('뺙', '뺳'), + ('뺵', 'ë»'), + ('뻑', '뻫'), + ('ë»­', '뼇'), + ('뼉', 'ë¼£'), + ('ë¼¥', '뼿'), + ('ë½', 'ë½›'), + ('ë½', 'ë½·'), + ('ë½¹', '뾓'), + ('뾕', '뾯'), + ('ë¾±', 'ë¿‹'), + ('ë¿', '뿧'), + ('ë¿©', '쀃'), + ('쀅', '쀟'), + ('쀡', '쀻'), + ('쀽', 'ì—'), + ('ì™', 'ì³'), + ('ìµ', 'ì‚'), + ('ì‚‘', 'ì‚«'), + ('ì‚­', '샇'), + ('색', '샣'), + ('샥', '샿'), + ('ì„', 'ì„›'), + ('ì„', 'ì„·'), + ('섹', 'ì…“'), + ('ì…•', 'ì…¯'), + ('ì…±', '솋'), + ('ì†', '솧'), + ('솩', '쇃'), + ('쇅', '쇟'), + ('쇡', '쇻'), + ('쇽', '숗'), + ('숙', '숳'), + ('숵', 'ì‰'), + ('쉑', '쉫'), + ('쉭', '슇'), + ('슉', '슣'), + ('슥', '슿'), + ('ì‹', 'ì‹›'), + ('ì‹', 'ì‹·'), + ('싹', '쌓'), + ('쌕', '쌯'), + ('쌱', 'ì‹'), + ('ì', 'ì§'), + ('ì©', '쎃'), + ('쎅', '쎟'), + ('쎡', '쎻'), + ('쎽', 'ì—'), + ('ì™', 'ì³'), + ('ìµ', 'ì'), + ('ì‘', 'ì«'), + ('ì­', '쑇'), + ('쑉', 'ì‘£'), + ('ì‘¥', 'ì‘¿'), + ('ì’', 'ì’›'), + ('ì’', 'ì’·'), + ('ì’¹', 'ì““'), + ('ì“•', '쓯'), + ('쓱', '씋'), + ('ì”', '씧'), + ('씩', '앃'), + ('ì•…', 'ì•Ÿ'), + ('ì•¡', 'ì•»'), + ('약', 'ì–—'), + ('ì–™', 'ì–³'), + ('ì–µ', 'ì—'), + ('ì—‘', 'ì—«'), + ('ì—­', '옇'), + ('옉', '옣'), + ('옥', '옿'), + ('ì™', 'ì™›'), + ('ì™', 'ì™·'), + ('왹', 'ìš“'), + ('ìš•', '욯'), + ('ìš±', '웋'), + ('ì›', '웧'), + ('웩', '윃'), + ('윅', '윟'), + ('육', '윻'), + ('윽', 'ì—'), + ('ì™', 'ì³'), + ('ìµ', 'ìž'), + ('ìž‘', 'ìž«'), + ('ìž­', '쟇'), + ('쟉', '쟣'), + ('쟥', '쟿'), + ('ì ', 'ì ›'), + ('ì ', 'ì ·'), + ('ì ¹', 'ì¡“'), + ('ì¡•', '졯'), + ('족', '좋'), + ('ì¢', '좧'), + ('좩', '죃'), + ('죅', '죟'), + ('죡', '죻'), + ('죽', '줗'), + ('줙', '줳'), + ('줵', 'ì¥'), + ('쥑', '쥫'), + ('쥭', '즇'), + ('즉', '즣'), + ('즥', '즿'), + ('ì§', '짛'), + ('ì§', '짷'), + ('짹', '쨓'), + ('쨕', '쨯'), + ('쨱', 'ì©‹'), + ('ì©', '쩧'), + ('ì©©', '쪃'), + ('쪅', '쪟'), + ('쪡', '쪻'), + ('쪽', 'ì«—'), + ('ì«™', '쫳'), + ('쫵', 'ì¬'), + ('쬑', '쬫'), + ('쬭', 'ì­‡'), + ('ì­‰', 'ì­£'), + ('ì­¥', 'ì­¿'), + ('ì®', 'ì®›'), + ('ì®', 'ì®·'), + ('쮹', '쯓'), + ('쯕', '쯯'), + ('쯱', 'ì°‹'), + ('ì°', 'ì°§'), + ('ì°©', '챃'), + ('ì±…', '챟'), + ('챡', 'ì±»'), + ('ì±½', 'ì²—'), + ('ì²™', 'ì²³'), + ('ì²µ', 'ì³'), + ('쳑', '쳫'), + ('ì³­', 'ì´‡'), + ('ì´‰', 'ì´£'), + ('ì´¥', 'ì´¿'), + ('ìµ', 'ìµ›'), + ('ìµ', 'ìµ·'), + ('ìµ¹', '춓'), + ('축', '춯'), + ('춱', 'ì·‹'), + ('ì·', 'ì·§'), + ('ì·©', '츃'), + ('츅', '츟'), + ('측', '츻'), + ('츽', 'ì¹—'), + ('ì¹™', 'ì¹³'), + ('ì¹µ', 'ìº'), + ('캑', '캫'), + ('캭', '컇'), + ('컉', '컣'), + ('컥', '컿'), + ('ì¼', 'ì¼›'), + ('ì¼', 'ì¼·'), + ('ì¼¹', '콓'), + ('콕', '콯'), + ('ì½±', '쾋'), + ('ì¾', '쾧'), + ('쾩', '쿃'), + ('ì¿…', 'ì¿Ÿ'), + ('ì¿¡', 'ì¿»'), + ('쿽', '퀗'), + ('퀙', '퀳'), + ('퀵', 'í'), + ('í‘', 'í«'), + ('í­', '킇'), + ('킉', 'í‚£'), + ('í‚¥', 'í‚¿'), + ('íƒ', '탛'), + ('íƒ', '탷'), + ('탹', 'í„“'), + ('í„•', '턯'), + ('턱', 'í…‹'), + ('í…', 'í…§'), + ('í…©', '톃'), + ('톅', '톟'), + ('톡', '톻'), + ('톽', '퇗'), + ('퇙', '퇳'), + ('퇵', 'íˆ'), + ('툑', '툫'), + ('툭', '퉇'), + ('퉉', '퉣'), + ('퉥', '퉿'), + ('íŠ', '튛'), + ('íŠ', '튷'), + ('특', 'í‹“'), + ('í‹•', '틯'), + ('틱', '팋'), + ('íŒ', '팧'), + ('팩', 'íƒ'), + ('í…', 'íŸ'), + ('í¡', 'í»'), + ('í½', '펗'), + ('펙', '펳'), + ('펵', 'í'), + ('í‘', 'í«'), + ('í­', 'í‡'), + ('í‰', 'í£'), + ('í¥', 'í¿'), + ('í‘', 'í‘›'), + ('í‘', 'í‘·'), + ('푹', 'í’“'), + ('í’•', 'í’¯'), + ('í’±', 'í“‹'), + ('í“', '퓧'), + ('í“©', '픃'), + ('í”…', '픟'), + ('픡', 'í”»'), + ('픽', 'í•—'), + ('í•™', '핳'), + ('핵', 'í–'), + ('í–‘', 'í–«'), + ('í–­', 'í—‡'), + ('í—‰', 'í—£'), + ('í—¥', 'í—¿'), + ('í˜', '혛'), + ('í˜', '혷'), + ('혹', '홓'), + ('확', '홯'), + ('í™±', 'íš‹'), + ('íš', '횧'), + ('íš©', '훃'), + ('í›…', '훟'), + ('훡', 'í›»'), + ('훽', '휗'), + ('휙', '휳'), + ('휵', 'í'), + ('í‘', 'í«'), + ('í­', '힇'), + ('힉', '힣'), +]; + +pub const PREPEND: &'static [(char, char)] = &[ + ('\u{600}', '\u{605}'), + ('\u{6dd}', '\u{6dd}'), + ('\u{70f}', '\u{70f}'), + ('\u{890}', '\u{891}'), + ('\u{8e2}', '\u{8e2}'), + ('ൎ', 'ൎ'), + ('\u{110bd}', '\u{110bd}'), + ('\u{110cd}', '\u{110cd}'), + ('𑇂', '𑇃'), + ('𑤿', '𑤿'), + ('ð‘¥', 'ð‘¥'), + ('𑨺', '𑨺'), + ('𑪄', '𑪉'), + ('𑵆', '𑵆'), + ('𑼂', '𑼂'), +]; + +pub const REGIONAL_INDICATOR: &'static [(char, char)] = &[('🇦', '🇿')]; + +pub const SPACINGMARK: &'static [(char, char)] = &[ + ('ः', 'ः'), + ('ऻ', 'ऻ'), + ('ा', 'ी'), + ('ॉ', 'ौ'), + ('ॎ', 'à¥'), + ('ং', 'ঃ'), + ('ি', 'ী'), + ('ে', 'ৈ'), + ('ো', 'ৌ'), + ('ਃ', 'ਃ'), + ('ਾ', 'à©€'), + ('ઃ', 'ઃ'), + ('ા', 'à«€'), + ('ૉ', 'ૉ'), + ('à«‹', 'à«Œ'), + ('ଂ', 'ଃ'), + ('à­€', 'à­€'), + ('à­‡', 'à­ˆ'), + ('à­‹', 'à­Œ'), + ('ி', 'ி'), + ('à¯', 'ூ'), + ('ெ', 'ை'), + ('ொ', 'ௌ'), + ('à°', 'à°ƒ'), + ('à±', 'ౄ'), + ('ಂ', 'ಃ'), + ('ಾ', 'ಾ'), + ('à³€', 'à³'), + ('ೃ', 'ೄ'), + ('ೇ', 'ೈ'), + ('ೊ', 'ೋ'), + ('à³³', 'à³³'), + ('à´‚', 'à´ƒ'), + ('à´¿', 'ീ'), + ('െ', 'ൈ'), + ('ൊ', 'ൌ'), + ('ං', 'ඃ'), + ('à·', 'à·‘'), + ('à·˜', 'à·ž'), + ('à·²', 'à·³'), + ('ำ', 'ำ'), + ('ຳ', 'ຳ'), + ('༾', '༿'), + ('ཿ', 'ཿ'), + ('ေ', 'ေ'), + ('ျ', 'ြ'), + ('á–', 'á—'), + ('á‚„', 'á‚„'), + ('᜕', '᜕'), + ('᜴', '᜴'), + ('ា', 'ា'), + ('áž¾', 'ៅ'), + ('ះ', 'ៈ'), + ('ᤣ', 'ᤦ'), + ('ᤩ', 'ᤫ'), + ('ᤰ', 'ᤱ'), + ('ᤳ', 'ᤸ'), + ('ᨙ', 'ᨚ'), + ('á©•', 'á©•'), + ('á©—', 'á©—'), + ('á©­', 'ᩲ'), + ('ᬄ', 'ᬄ'), + ('ᬻ', 'ᬻ'), + ('ᬽ', 'á­'), + ('á­ƒ', 'á­„'), + ('ᮂ', 'ᮂ'), + ('ᮡ', 'ᮡ'), + ('ᮦ', 'ᮧ'), + ('᮪', '᮪'), + ('ᯧ', 'ᯧ'), + ('ᯪ', 'ᯬ'), + ('ᯮ', 'ᯮ'), + ('᯲', '᯳'), + ('á°¤', 'á°«'), + ('á°´', 'á°µ'), + ('᳡', '᳡'), + ('á³·', 'á³·'), + ('ê £', 'ê ¤'), + ('ê §', 'ê §'), + ('ꢀ', 'ê¢'), + ('ꢴ', 'ꣃ'), + ('ꥒ', '꥓'), + ('ꦃ', 'ꦃ'), + ('ꦴ', 'ꦵ'), + ('ꦺ', 'ꦻ'), + ('ꦾ', '꧀'), + ('ꨯ', 'ꨰ'), + ('ꨳ', 'ꨴ'), + ('ê©', 'ê©'), + ('ê««', 'ê««'), + ('ê«®', 'ꫯ'), + ('ꫵ', 'ꫵ'), + ('ꯣ', 'ꯤ'), + ('ꯦ', 'ꯧ'), + ('ꯩ', 'ꯪ'), + ('꯬', '꯬'), + ('ð‘€€', 'ð‘€€'), + ('𑀂', '𑀂'), + ('ð‘‚‚', 'ð‘‚‚'), + ('ð‘‚°', 'ð‘‚²'), + ('ð‘‚·', '𑂸'), + ('𑄬', '𑄬'), + ('ð‘……', 'ð‘…†'), + ('𑆂', '𑆂'), + ('𑆳', '𑆵'), + ('𑆿', '𑇀'), + ('𑇎', '𑇎'), + ('𑈬', '𑈮'), + ('𑈲', '𑈳'), + ('𑈵', '𑈵'), + ('ð‘‹ ', 'ð‘‹¢'), + ('𑌂', '𑌃'), + ('𑌿', '𑌿'), + ('ð‘', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘'), + ('ð‘¢', 'ð‘£'), + ('ð‘µ', 'ð‘·'), + ('ð‘‘€', 'ð‘‘'), + ('ð‘‘…', 'ð‘‘…'), + ('ð‘’±', 'ð‘’²'), + ('ð‘’¹', 'ð‘’¹'), + ('ð‘’»', 'ð‘’¼'), + ('ð‘’¾', 'ð‘’¾'), + ('ð‘“', 'ð‘“'), + ('ð‘–°', 'ð‘–±'), + ('ð‘–¸', 'ð‘–»'), + ('ð‘–¾', 'ð‘–¾'), + ('𑘰', '𑘲'), + ('𑘻', '𑘼'), + ('𑘾', '𑘾'), + ('𑚬', '𑚬'), + ('ð‘š®', '𑚯'), + ('𑚶', '𑚶'), + ('𑜦', '𑜦'), + ('ð‘ ¬', 'ð‘ ®'), + ('ð‘ ¸', 'ð‘ ¸'), + ('𑤱', '𑤵'), + ('𑤷', '𑤸'), + ('𑤽', '𑤽'), + ('ð‘¥€', 'ð‘¥€'), + ('𑥂', '𑥂'), + ('𑧑', '𑧓'), + ('𑧜', '𑧟'), + ('𑧤', '𑧤'), + ('𑨹', '𑨹'), + ('ð‘©—', '𑩘'), + ('𑪗', '𑪗'), + ('ð‘°¯', 'ð‘°¯'), + ('ð‘°¾', 'ð‘°¾'), + ('𑲩', '𑲩'), + ('𑲱', '𑲱'), + ('𑲴', '𑲴'), + ('𑶊', '𑶎'), + ('𑶓', '𑶔'), + ('𑶖', '𑶖'), + ('ð‘»µ', '𑻶'), + ('𑼃', '𑼃'), + ('𑼴', '𑼵'), + ('𑼾', '𑼿'), + ('ð‘½', 'ð‘½'), + ('𖽑', '𖾇'), + ('ð–¿°', 'ð–¿±'), + ('ð…¦', 'ð…¦'), + ('ð…­', 'ð…­'), +]; + +pub const T: &'static [(char, char)] = &[('ᆨ', 'ᇿ'), ('ퟋ', 'ퟻ')]; + +pub const V: &'static [(char, char)] = &[('á… ', 'ᆧ'), ('íž°', 'ퟆ')]; + +pub const ZWJ: &'static [(char, char)] = &[('\u{200d}', '\u{200d}')]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/mod.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/mod.rs new file mode 100644 index 0000000000000..20736c7ac813e --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/mod.rs @@ -0,0 +1,57 @@ +#[cfg(feature = "unicode-age")] +pub mod age; + +#[cfg(feature = "unicode-case")] +pub mod case_folding_simple; + +#[cfg(feature = "unicode-gencat")] +pub mod general_category; + +#[cfg(feature = "unicode-segment")] +pub mod grapheme_cluster_break; + +#[cfg(all(feature = "unicode-perl", not(feature = "unicode-gencat")))] +#[allow(dead_code)] +pub mod perl_decimal; + +#[cfg(all(feature = "unicode-perl", not(feature = "unicode-bool")))] +#[allow(dead_code)] +pub mod perl_space; + +#[cfg(feature = "unicode-perl")] +pub mod perl_word; + +#[cfg(feature = "unicode-bool")] +pub mod property_bool; + +#[cfg(any( + feature = "unicode-age", + feature = "unicode-bool", + feature = "unicode-gencat", + feature = "unicode-perl", + feature = "unicode-script", + feature = "unicode-segment", +))] +pub mod property_names; + +#[cfg(any( + feature = "unicode-age", + feature = "unicode-bool", + feature = "unicode-gencat", + feature = "unicode-perl", + feature = "unicode-script", + feature = "unicode-segment", +))] +pub mod property_values; + +#[cfg(feature = "unicode-script")] +pub mod script; + +#[cfg(feature = "unicode-script")] +pub mod script_extension; + +#[cfg(feature = "unicode-segment")] +pub mod sentence_break; + +#[cfg(feature = "unicode-segment")] +pub mod word_break; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/perl_decimal.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/perl_decimal.rs new file mode 100644 index 0000000000000..4f4c08a128d2b --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/perl_decimal.rs @@ -0,0 +1,77 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate general-category ucd-15.0.0 --chars --include decimalnumber +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = + &[("Decimal_Number", DECIMAL_NUMBER)]; + +pub const DECIMAL_NUMBER: &'static [(char, char)] = &[ + ('0', '9'), + ('Ù ', 'Ù©'), + ('Û°', 'Û¹'), + ('߀', '߉'), + ('०', '९'), + ('০', '৯'), + ('੦', '੯'), + ('૦', '૯'), + ('à­¦', 'à­¯'), + ('௦', '௯'), + ('౦', '౯'), + ('೦', '೯'), + ('൦', '൯'), + ('à·¦', 'à·¯'), + ('à¹', '๙'), + ('à»', 'à»™'), + ('༠', '༩'), + ('á€', 'á‰'), + ('á‚', 'á‚™'), + ('០', '៩'), + ('á ', 'á ™'), + ('᥆', 'á¥'), + ('á§', '᧙'), + ('᪀', '᪉'), + ('áª', '᪙'), + ('á­', 'á­™'), + ('á®°', '᮹'), + ('á±€', '᱉'), + ('á±', 'á±™'), + ('꘠', '꘩'), + ('ê£', '꣙'), + ('꤀', '꤉'), + ('ê§', '꧙'), + ('꧰', '꧹'), + ('ê©', 'ê©™'), + ('꯰', '꯹'), + ('ï¼', 'ï¼™'), + ('ð’ ', 'ð’©'), + ('ð´°', 'ð´¹'), + ('ð‘¦', 'ð‘¯'), + ('𑃰', '𑃹'), + ('𑄶', 'ð‘„¿'), + ('ð‘‡', '𑇙'), + ('ð‘‹°', 'ð‘‹¹'), + ('ð‘‘', 'ð‘‘™'), + ('ð‘“', 'ð‘“™'), + ('ð‘™', 'ð‘™™'), + ('𑛀', '𑛉'), + ('𑜰', '𑜹'), + ('ð‘£ ', '𑣩'), + ('ð‘¥', 'ð‘¥™'), + ('ð‘±', '𑱙'), + ('ð‘µ', '𑵙'), + ('𑶠', '𑶩'), + ('ð‘½', '𑽙'), + ('ð–© ', 'ð–©©'), + ('ð–«€', '𖫉'), + ('ð–­', 'ð–­™'), + ('ðŸŽ', 'ðŸ¿'), + ('ðž…€', 'ðž…‰'), + ('ðž‹°', '𞋹'), + ('ðž“°', '𞓹'), + ('ðž¥', '𞥙'), + ('🯰', '🯹'), +]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/perl_space.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/perl_space.rs new file mode 100644 index 0000000000000..174169579530d --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/perl_space.rs @@ -0,0 +1,23 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate property-bool ucd-15.0.0 --chars --include whitespace +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = + &[("White_Space", WHITE_SPACE)]; + +pub const WHITE_SPACE: &'static [(char, char)] = &[ + ('\t', '\r'), + (' ', ' '), + ('\u{85}', '\u{85}'), + ('\u{a0}', '\u{a0}'), + ('\u{1680}', '\u{1680}'), + ('\u{2000}', '\u{200a}'), + ('\u{2028}', '\u{2029}'), + ('\u{202f}', '\u{202f}'), + ('\u{205f}', '\u{205f}'), + ('\u{3000}', '\u{3000}'), +]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/perl_word.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/perl_word.rs new file mode 100644 index 0000000000000..c1b66bd9ab934 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/perl_word.rs @@ -0,0 +1,781 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate perl-word ucd-15.0.0 --chars +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const PERL_WORD: &'static [(char, char)] = &[ + ('0', '9'), + ('A', 'Z'), + ('_', '_'), + ('a', 'z'), + ('ª', 'ª'), + ('µ', 'µ'), + ('º', 'º'), + ('À', 'Ö'), + ('Ø', 'ö'), + ('ø', 'Ë'), + ('ˆ', 'Ë‘'), + ('Ë ', 'ˤ'), + ('ˬ', 'ˬ'), + ('Ë®', 'Ë®'), + ('\u{300}', 'Í´'), + ('Ͷ', 'Í·'), + ('ͺ', 'ͽ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'ϵ'), + ('Ï·', 'Ò'), + ('\u{483}', 'Ô¯'), + ('Ô±', 'Õ–'), + ('Õ™', 'Õ™'), + ('Õ ', 'Öˆ'), + ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), + ('×', 'ת'), + ('ׯ', 'ײ'), + ('\u{610}', '\u{61a}'), + ('Ø ', 'Ù©'), + ('Ù®', 'Û“'), + ('Û•', '\u{6dc}'), + ('\u{6df}', '\u{6e8}'), + ('\u{6ea}', 'Û¼'), + ('Û¿', 'Û¿'), + ('Ü', '\u{74a}'), + ('Ý', 'Þ±'), + ('߀', 'ßµ'), + ('ߺ', 'ߺ'), + ('\u{7fd}', '\u{7fd}'), + ('à €', '\u{82d}'), + ('à¡€', '\u{85b}'), + ('à¡ ', 'ࡪ'), + ('à¡°', 'ࢇ'), + ('ࢉ', 'ࢎ'), + ('\u{898}', '\u{8e1}'), + ('\u{8e3}', '\u{963}'), + ('०', '९'), + ('ॱ', 'ঃ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('\u{9bc}', '\u{9c4}'), + ('ে', 'ৈ'), + ('ো', 'ৎ'), + ('\u{9d7}', '\u{9d7}'), + ('ড়', 'à§'), + ('য়', '\u{9e3}'), + ('০', 'ৱ'), + ('ৼ', 'ৼ'), + ('\u{9fe}', '\u{9fe}'), + ('\u{a01}', 'ਃ'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('\u{a3c}', '\u{a3c}'), + ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('੦', '\u{a75}'), + ('\u{a81}', 'ઃ'), + ('અ', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('\u{abc}', '\u{ac5}'), + ('\u{ac7}', 'ૉ'), + ('à«‹', '\u{acd}'), + ('à«', 'à«'), + ('à« ', '\u{ae3}'), + ('૦', '૯'), + ('ૹ', '\u{aff}'), + ('\u{b01}', 'ଃ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), + ('\u{b3c}', '\u{b44}'), + ('à­‡', 'à­ˆ'), + ('à­‹', '\u{b4d}'), + ('\u{b55}', '\u{b57}'), + ('à­œ', 'à­'), + ('à­Ÿ', '\u{b63}'), + ('à­¦', 'à­¯'), + ('à­±', 'à­±'), + ('\u{b82}', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'ஹ'), + ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), + ('ொ', '\u{bcd}'), + ('à¯', 'à¯'), + ('\u{bd7}', '\u{bd7}'), + ('௦', '௯'), + ('\u{c00}', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°¹'), + ('\u{c3c}', 'ౄ'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('ౘ', 'ౚ'), + ('à±', 'à±'), + ('à± ', '\u{c63}'), + ('౦', '౯'), + ('ಀ', 'ಃ'), + ('ಅ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('\u{cbc}', 'ೄ'), + ('\u{cc6}', 'ೈ'), + ('ೊ', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), + ('à³', 'ೞ'), + ('à³ ', '\u{ce3}'), + ('೦', '೯'), + ('à³±', 'à³³'), + ('\u{d00}', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', '\u{d44}'), + ('െ', 'ൈ'), + ('ൊ', 'ൎ'), + ('ൔ', '\u{d57}'), + ('ൟ', '\u{d63}'), + ('൦', '൯'), + ('ൺ', 'ൿ'), + ('\u{d81}', 'ඃ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('à·˜', '\u{ddf}'), + ('à·¦', 'à·¯'), + ('à·²', 'à·³'), + ('à¸', '\u{e3a}'), + ('เ', '\u{e4e}'), + ('à¹', '๙'), + ('àº', 'ຂ'), + ('ຄ', 'ຄ'), + ('ຆ', 'ຊ'), + ('ຌ', 'ຣ'), + ('ລ', 'ລ'), + ('ວ', 'ຽ'), + ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), + ('\u{ec8}', '\u{ece}'), + ('à»', 'à»™'), + ('ໜ', 'ໟ'), + ('ༀ', 'ༀ'), + ('\u{f18}', '\u{f19}'), + ('༠', '༩'), + ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), + ('\u{f39}', '\u{f39}'), + ('༾', 'ཇ'), + ('ཉ', 'ཬ'), + ('\u{f71}', '\u{f84}'), + ('\u{f86}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('\u{fc6}', '\u{fc6}'), + ('က', 'á‰'), + ('á', '\u{109d}'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ჺ'), + ('ჼ', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹–'), + ('ዘ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'áš'), + ('\u{135d}', '\u{135f}'), + ('ᎀ', 'áŽ'), + ('Ꭰ', 'áµ'), + ('á¸', 'á½'), + ('á', 'ᙬ'), + ('ᙯ', 'ᙿ'), + ('áš', 'ášš'), + ('áš ', 'ᛪ'), + ('á›®', 'ᛸ'), + ('ᜀ', '᜕'), + ('ᜟ', '᜴'), + ('á€', '\u{1753}'), + ('á ', 'á¬'), + ('á®', 'á°'), + ('\u{1772}', '\u{1773}'), + ('ក', '\u{17d3}'), + ('ៗ', 'ៗ'), + ('ៜ', '\u{17dd}'), + ('០', '៩'), + ('\u{180b}', '\u{180d}'), + ('\u{180f}', 'á ™'), + ('á  ', 'ᡸ'), + ('ᢀ', 'ᢪ'), + ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), + ('\u{1920}', 'ᤫ'), + ('ᤰ', '\u{193b}'), + ('᥆', 'ᥭ'), + ('ᥰ', 'ᥴ'), + ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), + ('á§', '᧙'), + ('ᨀ', '\u{1a1b}'), + ('ᨠ', '\u{1a5e}'), + ('\u{1a60}', '\u{1a7c}'), + ('\u{1a7f}', '᪉'), + ('áª', '᪙'), + ('ᪧ', 'ᪧ'), + ('\u{1ab0}', '\u{1ace}'), + ('\u{1b00}', 'á­Œ'), + ('á­', 'á­™'), + ('\u{1b6b}', '\u{1b73}'), + ('\u{1b80}', '᯳'), + ('á°€', '\u{1c37}'), + ('á±€', '᱉'), + ('á±', 'á±½'), + ('á²€', 'ᲈ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', 'ᳺ'), + ('á´€', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¾¼'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'á¿Œ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), + ('ῶ', 'ῼ'), + ('\u{200c}', '\u{200d}'), + ('‿', 'â€'), + ('â”', 'â”'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('\u{20d0}', '\u{20f0}'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„Š', 'â„“'), + ('â„•', 'â„•'), + ('â„™', 'â„'), + ('ℤ', 'ℤ'), + ('Ω', 'Ω'), + ('ℨ', 'ℨ'), + ('K', 'â„­'), + ('ℯ', 'ℹ'), + ('ℼ', 'â„¿'), + ('â……', 'â…‰'), + ('â…Ž', 'â…Ž'), + ('â… ', 'ↈ'), + ('â’¶', 'â“©'), + ('â°€', 'ⳤ'), + ('Ⳬ', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('â´°', 'ⵧ'), + ('ⵯ', 'ⵯ'), + ('\u{2d7f}', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('\u{2de0}', '\u{2dff}'), + ('ⸯ', 'ⸯ'), + ('々', '〇'), + ('〡', '\u{302f}'), + ('〱', '〵'), + ('〸', '〼'), + ('ã', 'ã‚–'), + ('\u{3099}', '\u{309a}'), + ('ã‚', 'ã‚Ÿ'), + ('ã‚¡', 'ヺ'), + ('ー', 'ヿ'), + ('ã„…', 'ㄯ'), + ('ㄱ', 'ㆎ'), + ('ㆠ', 'ㆿ'), + ('ㇰ', 'ㇿ'), + ('ã€', '䶿'), + ('一', 'ê’Œ'), + ('ê“', 'ꓽ'), + ('ꔀ', 'ꘌ'), + ('ê˜', 'ꘫ'), + ('Ꙁ', '\u{a672}'), + ('\u{a674}', '\u{a67d}'), + ('ꙿ', '\u{a6f1}'), + ('ꜗ', 'ꜟ'), + ('Ꜣ', 'ꞈ'), + ('êž‹', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('ꟲ', 'ê §'), + ('\u{a82c}', '\u{a82c}'), + ('ê¡€', 'ꡳ'), + ('ꢀ', '\u{a8c5}'), + ('ê£', '꣙'), + ('\u{a8e0}', 'ꣷ'), + ('ꣻ', 'ꣻ'), + ('ꣽ', '\u{a92d}'), + ('ꤰ', '꥓'), + ('ꥠ', 'ꥼ'), + ('\u{a980}', '꧀'), + ('ê§', '꧙'), + ('ꧠ', 'ꧾ'), + ('ꨀ', '\u{aa36}'), + ('ê©€', 'ê©'), + ('ê©', 'ê©™'), + ('ê© ', 'ꩶ'), + ('ꩺ', 'ê«‚'), + ('ê«›', 'ê«'), + ('ê« ', 'ꫯ'), + ('ꫲ', '\u{aaf6}'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('ꬰ', 'ê­š'), + ('ê­œ', 'ê­©'), + ('ê­°', 'ꯪ'), + ('꯬', '\u{abed}'), + ('꯰', '꯹'), + ('ê°€', '힣'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), + ('ï©°', 'ï«™'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï¬', 'ﬨ'), + ('שׁ', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', 'ï®±'), + ('ﯓ', 'ï´½'), + ('ïµ', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·°', 'ï·»'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{fe20}', '\u{fe2f}'), + ('︳', '︴'), + ('ï¹', 'ï¹'), + ('ï¹°', 'ï¹´'), + ('ﹶ', 'ﻼ'), + ('ï¼', 'ï¼™'), + ('A', 'Z'), + ('_', '_'), + ('ï½', 'z'), + ('ヲ', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), + ('ð…€', 'ð…´'), + ('\u{101fd}', '\u{101fd}'), + ('ðŠ€', 'ðŠœ'), + ('ðŠ ', 'ð‹'), + ('\u{102e0}', '\u{102e0}'), + ('ðŒ€', 'ðŒŸ'), + ('ðŒ­', 'ðŠ'), + ('ð', '\u{1037a}'), + ('ðŽ€', 'ðŽ'), + ('ðŽ ', 'ðƒ'), + ('ðˆ', 'ð'), + ('ð‘', 'ð•'), + ('ð€', 'ð’'), + ('ð’ ', 'ð’©'), + ('ð’°', 'ð““'), + ('ð“˜', 'ð“»'), + ('ð”€', 'ð”§'), + ('ð”°', 'ð•£'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð˜€', 'ðœ¶'), + ('ð€', 'ð•'), + ('ð ', 'ð§'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð €', 'ð …'), + ('ð ˆ', 'ð ˆ'), + ('ð Š', 'ð µ'), + ('ð ·', 'ð ¸'), + ('ð ¼', 'ð ¼'), + ('ð ¿', 'ð¡•'), + ('ð¡ ', 'ð¡¶'), + ('ð¢€', 'ð¢ž'), + ('ð£ ', 'ð£²'), + ('ð£´', 'ð£µ'), + ('ð¤€', 'ð¤•'), + ('ð¤ ', 'ð¤¹'), + ('ð¦€', 'ð¦·'), + ('ð¦¾', 'ð¦¿'), + ('ð¨€', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨µ'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), + ('ð© ', 'ð©¼'), + ('ðª€', 'ðªœ'), + ('ð«€', 'ð«‡'), + ('ð«‰', '\u{10ae6}'), + ('ð¬€', 'ð¬µ'), + ('ð­€', 'ð­•'), + ('ð­ ', 'ð­²'), + ('ð®€', 'ð®‘'), + ('ð°€', 'ð±ˆ'), + ('ð²€', 'ð²²'), + ('ð³€', 'ð³²'), + ('ð´€', '\u{10d27}'), + ('ð´°', 'ð´¹'), + ('ðº€', 'ðº©'), + ('\u{10eab}', '\u{10eac}'), + ('ðº°', 'ðº±'), + ('\u{10efd}', 'ð¼œ'), + ('ð¼§', 'ð¼§'), + ('ð¼°', '\u{10f50}'), + ('ð½°', '\u{10f85}'), + ('ð¾°', 'ð¿„'), + ('ð¿ ', 'ð¿¶'), + ('ð‘€€', '\u{11046}'), + ('ð‘¦', 'ð‘µ'), + ('\u{1107f}', '\u{110ba}'), + ('\u{110c2}', '\u{110c2}'), + ('ð‘ƒ', '𑃨'), + ('𑃰', '𑃹'), + ('\u{11100}', '\u{11134}'), + ('𑄶', 'ð‘„¿'), + ('ð‘…„', 'ð‘…‡'), + ('ð‘…', '\u{11173}'), + ('ð‘…¶', 'ð‘…¶'), + ('\u{11180}', '𑇄'), + ('\u{111c9}', '\u{111cc}'), + ('𑇎', '𑇚'), + ('𑇜', '𑇜'), + ('𑈀', '𑈑'), + ('𑈓', '\u{11237}'), + ('\u{1123e}', '\u{11241}'), + ('ð‘Š€', '𑊆'), + ('𑊈', '𑊈'), + ('ð‘ŠŠ', 'ð‘Š'), + ('ð‘Š', 'ð‘Š'), + ('ð‘ŠŸ', '𑊨'), + ('ð‘Š°', '\u{112ea}'), + ('ð‘‹°', 'ð‘‹¹'), + ('\u{11300}', '𑌃'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('\u{1133b}', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘'), + ('ð‘', 'ð‘'), + ('\u{11357}', '\u{11357}'), + ('ð‘', 'ð‘£'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('ð‘€', 'ð‘‘Š'), + ('ð‘‘', 'ð‘‘™'), + ('\u{1145e}', 'ð‘‘¡'), + ('ð‘’€', 'ð‘“…'), + ('𑓇', '𑓇'), + ('ð‘“', 'ð‘“™'), + ('ð‘–€', '\u{115b5}'), + ('ð‘–¸', '\u{115c0}'), + ('ð‘—˜', '\u{115dd}'), + ('𑘀', '\u{11640}'), + ('ð‘™„', 'ð‘™„'), + ('ð‘™', 'ð‘™™'), + ('𑚀', '𑚸'), + ('𑛀', '𑛉'), + ('𑜀', '𑜚'), + ('\u{1171d}', '\u{1172b}'), + ('𑜰', '𑜹'), + ('ð‘€', 'ð‘†'), + ('ð‘ €', '\u{1183a}'), + ('ð‘¢ ', '𑣩'), + ('𑣿', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤵'), + ('𑤷', '𑤸'), + ('\u{1193b}', '\u{11943}'), + ('ð‘¥', 'ð‘¥™'), + ('𑦠', '𑦧'), + ('𑦪', '\u{119d7}'), + ('\u{119da}', '𑧡'), + ('𑧣', '𑧤'), + ('𑨀', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), + ('ð‘©', '\u{11a99}'), + ('ð‘ª', 'ð‘ª'), + ('𑪰', '𑫸'), + ('ð‘°€', 'ð‘°ˆ'), + ('ð‘°Š', '\u{11c36}'), + ('\u{11c38}', '𑱀'), + ('ð‘±', '𑱙'), + ('𑱲', 'ð‘²'), + ('\u{11c92}', '\u{11ca7}'), + ('𑲩', '\u{11cb6}'), + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d47}'), + ('ð‘µ', '𑵙'), + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶎'), + ('\u{11d90}', '\u{11d91}'), + ('𑶓', '𑶘'), + ('𑶠', '𑶩'), + ('ð‘» ', '𑻶'), + ('\u{11f00}', 'ð‘¼'), + ('𑼒', '\u{11f3a}'), + ('𑼾', '\u{11f42}'), + ('ð‘½', '𑽙'), + ('𑾰', '𑾰'), + ('ð’€€', 'ð’Ž™'), + ('ð’€', 'ð’‘®'), + ('ð’’€', '𒕃'), + ('ð’¾', 'ð’¿°'), + ('ð“€€', 'ð“¯'), + ('\u{13440}', '\u{13455}'), + ('ð”€', '𔙆'), + ('ð– €', '𖨸'), + ('ð–©€', 'ð–©ž'), + ('ð–© ', 'ð–©©'), + ('ð–©°', '𖪾'), + ('ð–«€', '𖫉'), + ('ð–«', 'ð–«­'), + ('\u{16af0}', '\u{16af4}'), + ('𖬀', '\u{16b36}'), + ('ð–­€', 'ð–­ƒ'), + ('ð–­', 'ð–­™'), + ('ð–­£', 'ð–­·'), + ('ð–­½', 'ð–®'), + ('ð–¹€', '𖹿'), + ('ð–¼€', '𖽊'), + ('\u{16f4f}', '𖾇'), + ('\u{16f8f}', '𖾟'), + ('ð–¿ ', 'ð–¿¡'), + ('ð–¿£', '\u{16fe4}'), + ('ð–¿°', 'ð–¿±'), + ('ð—€€', '𘟷'), + ('𘠀', '𘳕'), + ('𘴀', '𘴈'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𛀀', '𛄢'), + ('𛄲', '𛄲'), + ('ð›…', 'ð›…’'), + ('ð›…•', 'ð›…•'), + ('ð›…¤', 'ð›…§'), + ('ð›…°', '𛋻'), + ('ð›°€', '𛱪'), + ('ð›±°', 'ð›±¼'), + ('𛲀', '𛲈'), + ('ð›²', '𛲙'), + ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('\u{1d165}', '\u{1d169}'), + ('ð…­', '\u{1d172}'), + ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ð›€'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›º'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ´'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð®'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž¨'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‹'), + ('ðŸŽ', 'ðŸ¿'), + ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), + ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), + ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), + ('ð¼€', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('𞀰', 'ðž­'), + ('\u{1e08f}', '\u{1e08f}'), + ('ðž„€', '𞄬'), + ('\u{1e130}', '𞄽'), + ('ðž…€', 'ðž…‰'), + ('ðž…Ž', 'ðž…Ž'), + ('ðžŠ', '\u{1e2ae}'), + ('ðž‹€', '𞋹'), + ('ðž“', '𞓹'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), + ('ðž €', '𞣄'), + ('\u{1e8d0}', '\u{1e8d6}'), + ('𞤀', '𞥋'), + ('ðž¥', '𞥙'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('🄰', '🅉'), + ('ðŸ…', '🅩'), + ('🅰', '🆉'), + ('🯰', '🯹'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('丽', 'ð¯¨'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), + ('\u{e0100}', '\u{e01ef}'), +]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/property_bool.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/property_bool.rs new file mode 100644 index 0000000000000..a3e84b519c1a4 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/property_bool.rs @@ -0,0 +1,11367 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate property-bool ucd-15.0.0 --chars +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("ASCII_Hex_Digit", ASCII_HEX_DIGIT), + ("Alphabetic", ALPHABETIC), + ("Bidi_Control", BIDI_CONTROL), + ("Bidi_Mirrored", BIDI_MIRRORED), + ("Case_Ignorable", CASE_IGNORABLE), + ("Cased", CASED), + ("Changes_When_Casefolded", CHANGES_WHEN_CASEFOLDED), + ("Changes_When_Casemapped", CHANGES_WHEN_CASEMAPPED), + ("Changes_When_Lowercased", CHANGES_WHEN_LOWERCASED), + ("Changes_When_Titlecased", CHANGES_WHEN_TITLECASED), + ("Changes_When_Uppercased", CHANGES_WHEN_UPPERCASED), + ("Dash", DASH), + ("Default_Ignorable_Code_Point", DEFAULT_IGNORABLE_CODE_POINT), + ("Deprecated", DEPRECATED), + ("Diacritic", DIACRITIC), + ("Emoji", EMOJI), + ("Emoji_Component", EMOJI_COMPONENT), + ("Emoji_Modifier", EMOJI_MODIFIER), + ("Emoji_Modifier_Base", EMOJI_MODIFIER_BASE), + ("Emoji_Presentation", EMOJI_PRESENTATION), + ("Extended_Pictographic", EXTENDED_PICTOGRAPHIC), + ("Extender", EXTENDER), + ("Grapheme_Base", GRAPHEME_BASE), + ("Grapheme_Extend", GRAPHEME_EXTEND), + ("Grapheme_Link", GRAPHEME_LINK), + ("Hex_Digit", HEX_DIGIT), + ("Hyphen", HYPHEN), + ("IDS_Binary_Operator", IDS_BINARY_OPERATOR), + ("IDS_Trinary_Operator", IDS_TRINARY_OPERATOR), + ("ID_Continue", ID_CONTINUE), + ("ID_Start", ID_START), + ("Ideographic", IDEOGRAPHIC), + ("Join_Control", JOIN_CONTROL), + ("Logical_Order_Exception", LOGICAL_ORDER_EXCEPTION), + ("Lowercase", LOWERCASE), + ("Math", MATH), + ("Noncharacter_Code_Point", NONCHARACTER_CODE_POINT), + ("Other_Alphabetic", OTHER_ALPHABETIC), + ("Other_Default_Ignorable_Code_Point", OTHER_DEFAULT_IGNORABLE_CODE_POINT), + ("Other_Grapheme_Extend", OTHER_GRAPHEME_EXTEND), + ("Other_ID_Continue", OTHER_ID_CONTINUE), + ("Other_ID_Start", OTHER_ID_START), + ("Other_Lowercase", OTHER_LOWERCASE), + ("Other_Math", OTHER_MATH), + ("Other_Uppercase", OTHER_UPPERCASE), + ("Pattern_Syntax", PATTERN_SYNTAX), + ("Pattern_White_Space", PATTERN_WHITE_SPACE), + ("Prepended_Concatenation_Mark", PREPENDED_CONCATENATION_MARK), + ("Quotation_Mark", QUOTATION_MARK), + ("Radical", RADICAL), + ("Regional_Indicator", REGIONAL_INDICATOR), + ("Sentence_Terminal", SENTENCE_TERMINAL), + ("Soft_Dotted", SOFT_DOTTED), + ("Terminal_Punctuation", TERMINAL_PUNCTUATION), + ("Unified_Ideograph", UNIFIED_IDEOGRAPH), + ("Uppercase", UPPERCASE), + ("Variation_Selector", VARIATION_SELECTOR), + ("White_Space", WHITE_SPACE), + ("XID_Continue", XID_CONTINUE), + ("XID_Start", XID_START), +]; + +pub const ASCII_HEX_DIGIT: &'static [(char, char)] = + &[('0', '9'), ('A', 'F'), ('a', 'f')]; + +pub const ALPHABETIC: &'static [(char, char)] = &[ + ('A', 'Z'), + ('a', 'z'), + ('ª', 'ª'), + ('µ', 'µ'), + ('º', 'º'), + ('À', 'Ö'), + ('Ø', 'ö'), + ('ø', 'Ë'), + ('ˆ', 'Ë‘'), + ('Ë ', 'ˤ'), + ('ˬ', 'ˬ'), + ('Ë®', 'Ë®'), + ('\u{345}', '\u{345}'), + ('Í°', 'Í´'), + ('Ͷ', 'Í·'), + ('ͺ', 'ͽ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'ϵ'), + ('Ï·', 'Ò'), + ('ÒŠ', 'Ô¯'), + ('Ô±', 'Õ–'), + ('Õ™', 'Õ™'), + ('Õ ', 'Öˆ'), + ('\u{5b0}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), + ('×', 'ת'), + ('ׯ', 'ײ'), + ('\u{610}', '\u{61a}'), + ('Ø ', '\u{657}'), + ('\u{659}', '\u{65f}'), + ('Ù®', 'Û“'), + ('Û•', '\u{6dc}'), + ('\u{6e1}', '\u{6e8}'), + ('\u{6ed}', 'Û¯'), + ('Ûº', 'Û¼'), + ('Û¿', 'Û¿'), + ('Ü', '\u{73f}'), + ('Ý', 'Þ±'), + ('ߊ', 'ߪ'), + ('ß´', 'ßµ'), + ('ߺ', 'ߺ'), + ('à €', '\u{817}'), + ('à š', '\u{82c}'), + ('à¡€', 'ࡘ'), + ('à¡ ', 'ࡪ'), + ('à¡°', 'ࢇ'), + ('ࢉ', 'ࢎ'), + ('ࢠ', 'ࣉ'), + ('\u{8d4}', '\u{8df}'), + ('\u{8e3}', '\u{8e9}'), + ('\u{8f0}', 'ऻ'), + ('ऽ', 'ौ'), + ('ॎ', 'à¥'), + ('\u{955}', '\u{963}'), + ('ॱ', 'ঃ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('ঽ', '\u{9c4}'), + ('ে', 'ৈ'), + ('ো', 'ৌ'), + ('ৎ', 'ৎ'), + ('\u{9d7}', '\u{9d7}'), + ('ড়', 'à§'), + ('য়', '\u{9e3}'), + ('ৰ', 'ৱ'), + ('ৼ', 'ৼ'), + ('\u{a01}', 'ਃ'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4c}'), + ('\u{a51}', '\u{a51}'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('\u{a70}', '\u{a75}'), + ('\u{a81}', 'ઃ'), + ('અ', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('ઽ', '\u{ac5}'), + ('\u{ac7}', 'ૉ'), + ('à«‹', 'à«Œ'), + ('à«', 'à«'), + ('à« ', '\u{ae3}'), + ('ૹ', '\u{afc}'), + ('\u{b01}', 'ଃ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), + ('ଽ', '\u{b44}'), + ('à­‡', 'à­ˆ'), + ('à­‹', 'à­Œ'), + ('\u{b56}', '\u{b57}'), + ('à­œ', 'à­'), + ('à­Ÿ', '\u{b63}'), + ('à­±', 'à­±'), + ('\u{b82}', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'ஹ'), + ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), + ('ொ', 'ௌ'), + ('à¯', 'à¯'), + ('\u{bd7}', '\u{bd7}'), + ('\u{c00}', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°¹'), + ('à°½', 'ౄ'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4c}'), + ('\u{c55}', '\u{c56}'), + ('ౘ', 'ౚ'), + ('à±', 'à±'), + ('à± ', '\u{c63}'), + ('ಀ', 'ಃ'), + ('ಅ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('ಽ', 'ೄ'), + ('\u{cc6}', 'ೈ'), + ('ೊ', '\u{ccc}'), + ('\u{cd5}', '\u{cd6}'), + ('à³', 'ೞ'), + ('à³ ', '\u{ce3}'), + ('à³±', 'à³³'), + ('\u{d00}', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', 'à´º'), + ('à´½', '\u{d44}'), + ('െ', 'ൈ'), + ('ൊ', 'ൌ'), + ('ൎ', 'ൎ'), + ('ൔ', '\u{d57}'), + ('ൟ', '\u{d63}'), + ('ൺ', 'ൿ'), + ('\u{d81}', 'ඃ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('à·˜', '\u{ddf}'), + ('à·²', 'à·³'), + ('à¸', '\u{e3a}'), + ('เ', 'ๆ'), + ('\u{e4d}', '\u{e4d}'), + ('àº', 'ຂ'), + ('ຄ', 'ຄ'), + ('ຆ', 'ຊ'), + ('ຌ', 'ຣ'), + ('ລ', 'ລ'), + ('ວ', '\u{eb9}'), + ('\u{ebb}', 'ຽ'), + ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), + ('\u{ecd}', '\u{ecd}'), + ('ໜ', 'ໟ'), + ('ༀ', 'ༀ'), + ('ཀ', 'ཇ'), + ('ཉ', 'ཬ'), + ('\u{f71}', '\u{f83}'), + ('ྈ', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('က', '\u{1036}'), + ('း', 'း'), + ('ျ', 'ဿ'), + ('á', 'á‚'), + ('á‚š', '\u{109d}'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ჺ'), + ('ჼ', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹–'), + ('ዘ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'áš'), + ('ᎀ', 'áŽ'), + ('Ꭰ', 'áµ'), + ('á¸', 'á½'), + ('á', 'ᙬ'), + ('ᙯ', 'ᙿ'), + ('áš', 'ášš'), + ('áš ', 'ᛪ'), + ('á›®', 'ᛸ'), + ('ᜀ', '\u{1713}'), + ('ᜟ', '\u{1733}'), + ('á€', '\u{1753}'), + ('á ', 'á¬'), + ('á®', 'á°'), + ('\u{1772}', '\u{1773}'), + ('ក', 'áž³'), + ('ា', 'ៈ'), + ('ៗ', 'ៗ'), + ('ៜ', 'ៜ'), + ('á  ', 'ᡸ'), + ('ᢀ', 'ᢪ'), + ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), + ('\u{1920}', 'ᤫ'), + ('ᤰ', 'ᤸ'), + ('á¥', 'ᥭ'), + ('ᥰ', 'ᥴ'), + ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), + ('ᨀ', '\u{1a1b}'), + ('ᨠ', '\u{1a5e}'), + ('á©¡', '\u{1a74}'), + ('ᪧ', 'ᪧ'), + ('\u{1abf}', '\u{1ac0}'), + ('\u{1acc}', '\u{1ace}'), + ('\u{1b00}', 'ᬳ'), + ('\u{1b35}', 'á­ƒ'), + ('á­…', 'á­Œ'), + ('\u{1b80}', '\u{1ba9}'), + ('\u{1bac}', 'ᮯ'), + ('ᮺ', 'ᯥ'), + ('ᯧ', '\u{1bf1}'), + ('á°€', '\u{1c36}'), + ('á±', 'á±'), + ('ᱚ', 'á±½'), + ('á²€', 'ᲈ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('ᳩ', 'ᳬ'), + ('á³®', 'á³³'), + ('á³µ', 'ᳶ'), + ('ᳺ', 'ᳺ'), + ('á´€', 'ᶿ'), + ('\u{1de7}', '\u{1df4}'), + ('Ḁ', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¾¼'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'á¿Œ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), + ('ῶ', 'ῼ'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„Š', 'â„“'), + ('â„•', 'â„•'), + ('â„™', 'â„'), + ('ℤ', 'ℤ'), + ('Ω', 'Ω'), + ('ℨ', 'ℨ'), + ('K', 'â„­'), + ('ℯ', 'ℹ'), + ('ℼ', 'â„¿'), + ('â……', 'â…‰'), + ('â…Ž', 'â…Ž'), + ('â… ', 'ↈ'), + ('â’¶', 'â“©'), + ('â°€', 'ⳤ'), + ('Ⳬ', 'â³®'), + ('â³²', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('â´°', 'ⵧ'), + ('ⵯ', 'ⵯ'), + ('ⶀ', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('\u{2de0}', '\u{2dff}'), + ('ⸯ', 'ⸯ'), + ('々', '〇'), + ('〡', '〩'), + ('〱', '〵'), + ('〸', '〼'), + ('ã', 'ã‚–'), + ('ã‚', 'ã‚Ÿ'), + ('ã‚¡', 'ヺ'), + ('ー', 'ヿ'), + ('ã„…', 'ㄯ'), + ('ㄱ', 'ㆎ'), + ('ㆠ', 'ㆿ'), + ('ㇰ', 'ㇿ'), + ('ã€', '䶿'), + ('一', 'ê’Œ'), + ('ê“', 'ꓽ'), + ('ꔀ', 'ꘌ'), + ('ê˜', 'ꘟ'), + ('ꘪ', 'ꘫ'), + ('Ꙁ', 'ê™®'), + ('\u{a674}', '\u{a67b}'), + ('ꙿ', 'ꛯ'), + ('ꜗ', 'ꜟ'), + ('Ꜣ', 'ꞈ'), + ('êž‹', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('ꟲ', 'ê …'), + ('ê ‡', 'ê §'), + ('ê¡€', 'ꡳ'), + ('ꢀ', 'ꣃ'), + ('\u{a8c5}', '\u{a8c5}'), + ('ꣲ', 'ꣷ'), + ('ꣻ', 'ꣻ'), + ('ꣽ', '\u{a8ff}'), + ('ꤊ', '\u{a92a}'), + ('ꤰ', 'ꥒ'), + ('ꥠ', 'ꥼ'), + ('\u{a980}', 'ꦲ'), + ('ꦴ', 'ꦿ'), + ('ê§', 'ê§'), + ('ꧠ', 'ꧯ'), + ('ꧺ', 'ꧾ'), + ('ꨀ', '\u{aa36}'), + ('ê©€', 'ê©'), + ('ê© ', 'ꩶ'), + ('ꩺ', '\u{aabe}'), + ('ê«€', 'ê«€'), + ('ê«‚', 'ê«‚'), + ('ê«›', 'ê«'), + ('ê« ', 'ꫯ'), + ('ꫲ', 'ꫵ'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('ꬰ', 'ê­š'), + ('ê­œ', 'ê­©'), + ('ê­°', 'ꯪ'), + ('ê°€', '힣'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), + ('ï©°', 'ï«™'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï¬', 'ﬨ'), + ('שׁ', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', 'ï®±'), + ('ﯓ', 'ï´½'), + ('ïµ', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·°', 'ï·»'), + ('ï¹°', 'ï¹´'), + ('ﹶ', 'ﻼ'), + ('A', 'Z'), + ('ï½', 'z'), + ('ヲ', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), + ('ð…€', 'ð…´'), + ('ðŠ€', 'ðŠœ'), + ('ðŠ ', 'ð‹'), + ('ðŒ€', 'ðŒŸ'), + ('ðŒ­', 'ðŠ'), + ('ð', '\u{1037a}'), + ('ðŽ€', 'ðŽ'), + ('ðŽ ', 'ðƒ'), + ('ðˆ', 'ð'), + ('ð‘', 'ð•'), + ('ð€', 'ð’'), + ('ð’°', 'ð““'), + ('ð“˜', 'ð“»'), + ('ð”€', 'ð”§'), + ('ð”°', 'ð•£'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð˜€', 'ðœ¶'), + ('ð€', 'ð•'), + ('ð ', 'ð§'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð €', 'ð …'), + ('ð ˆ', 'ð ˆ'), + ('ð Š', 'ð µ'), + ('ð ·', 'ð ¸'), + ('ð ¼', 'ð ¼'), + ('ð ¿', 'ð¡•'), + ('ð¡ ', 'ð¡¶'), + ('ð¢€', 'ð¢ž'), + ('ð£ ', 'ð£²'), + ('ð£´', 'ð£µ'), + ('ð¤€', 'ð¤•'), + ('ð¤ ', 'ð¤¹'), + ('ð¦€', 'ð¦·'), + ('ð¦¾', 'ð¦¿'), + ('ð¨€', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨µ'), + ('ð© ', 'ð©¼'), + ('ðª€', 'ðªœ'), + ('ð«€', 'ð«‡'), + ('ð«‰', 'ð«¤'), + ('ð¬€', 'ð¬µ'), + ('ð­€', 'ð­•'), + ('ð­ ', 'ð­²'), + ('ð®€', 'ð®‘'), + ('ð°€', 'ð±ˆ'), + ('ð²€', 'ð²²'), + ('ð³€', 'ð³²'), + ('ð´€', '\u{10d27}'), + ('ðº€', 'ðº©'), + ('\u{10eab}', '\u{10eac}'), + ('ðº°', 'ðº±'), + ('ð¼€', 'ð¼œ'), + ('ð¼§', 'ð¼§'), + ('ð¼°', 'ð½…'), + ('ð½°', 'ð¾'), + ('ð¾°', 'ð¿„'), + ('ð¿ ', 'ð¿¶'), + ('ð‘€€', '\u{11045}'), + ('ð‘±', 'ð‘µ'), + ('\u{11080}', '𑂸'), + ('\u{110c2}', '\u{110c2}'), + ('ð‘ƒ', '𑃨'), + ('\u{11100}', '\u{11132}'), + ('ð‘…„', 'ð‘…‡'), + ('ð‘…', 'ð‘…²'), + ('ð‘…¶', 'ð‘…¶'), + ('\u{11180}', '𑆿'), + ('ð‘‡', '𑇄'), + ('𑇎', '\u{111cf}'), + ('𑇚', '𑇚'), + ('𑇜', '𑇜'), + ('𑈀', '𑈑'), + ('𑈓', '\u{11234}'), + ('\u{11237}', '\u{11237}'), + ('\u{1123e}', '\u{11241}'), + ('ð‘Š€', '𑊆'), + ('𑊈', '𑊈'), + ('ð‘ŠŠ', 'ð‘Š'), + ('ð‘Š', 'ð‘Š'), + ('ð‘ŠŸ', '𑊨'), + ('ð‘Š°', '\u{112e8}'), + ('\u{11300}', '𑌃'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('𑌽', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘Œ'), + ('ð‘', 'ð‘'), + ('\u{11357}', '\u{11357}'), + ('ð‘', 'ð‘£'), + ('ð‘€', 'ð‘‘'), + ('\u{11443}', 'ð‘‘…'), + ('𑑇', 'ð‘‘Š'), + ('ð‘‘Ÿ', 'ð‘‘¡'), + ('ð‘’€', 'ð‘“'), + ('ð‘“„', 'ð‘“…'), + ('𑓇', '𑓇'), + ('ð‘–€', '\u{115b5}'), + ('ð‘–¸', 'ð‘–¾'), + ('ð‘—˜', '\u{115dd}'), + ('𑘀', '𑘾'), + ('\u{11640}', '\u{11640}'), + ('ð‘™„', 'ð‘™„'), + ('𑚀', '\u{116b5}'), + ('𑚸', '𑚸'), + ('𑜀', '𑜚'), + ('\u{1171d}', '\u{1172a}'), + ('ð‘€', 'ð‘†'), + ('ð‘ €', 'ð‘ ¸'), + ('ð‘¢ ', '𑣟'), + ('𑣿', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤵'), + ('𑤷', '𑤸'), + ('\u{1193b}', '\u{1193c}'), + ('𑤿', '𑥂'), + ('𑦠', '𑦧'), + ('𑦪', '\u{119d7}'), + ('\u{119da}', '𑧟'), + ('𑧡', '𑧡'), + ('𑧣', '𑧤'), + ('𑨀', '𑨲'), + ('\u{11a35}', '\u{11a3e}'), + ('ð‘©', '𑪗'), + ('ð‘ª', 'ð‘ª'), + ('𑪰', '𑫸'), + ('ð‘°€', 'ð‘°ˆ'), + ('ð‘°Š', '\u{11c36}'), + ('\u{11c38}', 'ð‘°¾'), + ('𑱀', '𑱀'), + ('𑱲', 'ð‘²'), + ('\u{11c92}', '\u{11ca7}'), + ('𑲩', '\u{11cb6}'), + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d41}'), + ('\u{11d43}', '\u{11d43}'), + ('𑵆', '\u{11d47}'), + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶎'), + ('\u{11d90}', '\u{11d91}'), + ('𑶓', '𑶖'), + ('𑶘', '𑶘'), + ('ð‘» ', '𑻶'), + ('\u{11f00}', 'ð‘¼'), + ('𑼒', '\u{11f3a}'), + ('𑼾', '\u{11f40}'), + ('𑾰', '𑾰'), + ('ð’€€', 'ð’Ž™'), + ('ð’€', 'ð’‘®'), + ('ð’’€', '𒕃'), + ('ð’¾', 'ð’¿°'), + ('ð“€€', 'ð“¯'), + ('ð“‘', '𓑆'), + ('ð”€', '𔙆'), + ('ð– €', '𖨸'), + ('ð–©€', 'ð–©ž'), + ('ð–©°', '𖪾'), + ('ð–«', 'ð–«­'), + ('𖬀', '𖬯'), + ('ð–­€', 'ð–­ƒ'), + ('ð–­£', 'ð–­·'), + ('ð–­½', 'ð–®'), + ('ð–¹€', '𖹿'), + ('ð–¼€', '𖽊'), + ('\u{16f4f}', '𖾇'), + ('\u{16f8f}', '𖾟'), + ('ð–¿ ', 'ð–¿¡'), + ('ð–¿£', 'ð–¿£'), + ('ð–¿°', 'ð–¿±'), + ('ð—€€', '𘟷'), + ('𘠀', '𘳕'), + ('𘴀', '𘴈'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𛀀', '𛄢'), + ('𛄲', '𛄲'), + ('ð›…', 'ð›…’'), + ('ð›…•', 'ð›…•'), + ('ð›…¤', 'ð›…§'), + ('ð›…°', '𛋻'), + ('ð›°€', '𛱪'), + ('ð›±°', 'ð›±¼'), + ('𛲀', '𛲈'), + ('ð›²', '𛲙'), + ('\u{1bc9e}', '\u{1bc9e}'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ð›€'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›º'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ´'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð®'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž¨'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‹'), + ('ð¼€', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('𞀰', 'ðž­'), + ('\u{1e08f}', '\u{1e08f}'), + ('ðž„€', '𞄬'), + ('ðž„·', '𞄽'), + ('ðž…Ž', 'ðž…Ž'), + ('ðžŠ', '𞊭'), + ('ðž‹€', 'ðž‹«'), + ('ðž“', 'ðž“«'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), + ('ðž €', '𞣄'), + ('𞤀', '𞥃'), + ('\u{1e947}', '\u{1e947}'), + ('𞥋', '𞥋'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('🄰', '🅉'), + ('ðŸ…', '🅩'), + ('🅰', '🆉'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('丽', 'ð¯¨'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), +]; + +pub const BIDI_CONTROL: &'static [(char, char)] = &[ + ('\u{61c}', '\u{61c}'), + ('\u{200e}', '\u{200f}'), + ('\u{202a}', '\u{202e}'), + ('\u{2066}', '\u{2069}'), +]; + +pub const BIDI_MIRRORED: &'static [(char, char)] = &[ + ('(', ')'), + ('<', '<'), + ('>', '>'), + ('[', '['), + (']', ']'), + ('{', '{'), + ('}', '}'), + ('«', '«'), + ('»', '»'), + ('༺', '༽'), + ('áš›', 'ášœ'), + ('‹', '›'), + ('â…', 'â†'), + ('â½', 'â¾'), + ('â‚', 'â‚Ž'), + ('â…€', 'â…€'), + ('âˆ', '∄'), + ('∈', 'âˆ'), + ('∑', '∑'), + ('∕', '∖'), + ('√', 'âˆ'), + ('∟', '∢'), + ('∤', '∤'), + ('∦', '∦'), + ('∫', '∳'), + ('∹', '∹'), + ('∻', '≌'), + ('≒', '≕'), + ('≟', '≠'), + ('≢', '≢'), + ('≤', '≫'), + ('≮', '⊌'), + ('âŠ', '⊒'), + ('⊘', '⊘'), + ('⊢', '⊣'), + ('⊦', '⊸'), + ('⊾', '⊿'), + ('⋉', 'â‹'), + ('â‹', 'â‹‘'), + ('â‹–', 'â‹­'), + ('â‹°', 'â‹¿'), + ('⌈', '⌋'), + ('⌠', '⌡'), + ('〈', '〉'), + ('â¨', 'âµ'), + ('⟀', '⟀'), + ('⟃', '⟆'), + ('⟈', '⟉'), + ('⟋', 'âŸ'), + ('⟓', '⟖'), + ('⟜', '⟞'), + ('⟢', '⟯'), + ('⦃', '⦘'), + ('⦛', '⦠'), + ('⦢', '⦯'), + ('⦸', '⦸'), + ('⧀', '⧅'), + ('⧉', '⧉'), + ('⧎', '⧒'), + ('⧔', '⧕'), + ('⧘', '⧜'), + ('⧡', '⧡'), + ('⧣', '⧥'), + ('⧨', '⧩'), + ('⧴', '⧹'), + ('⧼', '⧽'), + ('⨊', '⨜'), + ('⨞', '⨡'), + ('⨤', '⨤'), + ('⨦', '⨦'), + ('⨩', '⨩'), + ('⨫', '⨮'), + ('⨴', '⨵'), + ('⨼', '⨾'), + ('â©—', '⩘'), + ('⩤', 'â©¥'), + ('⩪', 'â©­'), + ('⩯', 'â©°'), + ('⩳', 'â©´'), + ('⩹', '⪣'), + ('⪦', '⪭'), + ('⪯', 'â«–'), + ('â«œ', 'â«œ'), + ('â«ž', 'â«ž'), + ('â«¢', '⫦'), + ('⫬', 'â«®'), + ('⫳', '⫳'), + ('â«·', 'â«»'), + ('⫽', '⫽'), + ('⯾', '⯾'), + ('⸂', '⸅'), + ('⸉', '⸊'), + ('⸌', 'â¸'), + ('⸜', 'â¸'), + ('⸠', '⸩'), + ('⹕', '⹜'), + ('〈', '】'), + ('〔', '〛'), + ('ï¹™', '﹞'), + ('﹤', 'ï¹¥'), + ('(', ')'), + ('<', '<'), + ('>', '>'), + ('ï¼»', 'ï¼»'), + ('ï¼½', 'ï¼½'), + ('ï½›', 'ï½›'), + ('ï½', 'ï½'), + ('⦅', 'ï½ '), + ('ï½¢', 'ï½£'), + ('ð››', 'ð››'), + ('ðœ•', 'ðœ•'), + ('ð', 'ð'), + ('ðž‰', 'ðž‰'), + ('ðŸƒ', 'ðŸƒ'), +]; + +pub const CASE_IGNORABLE: &'static [(char, char)] = &[ + ('\'', '\''), + ('.', '.'), + (':', ':'), + ('^', '^'), + ('`', '`'), + ('¨', '¨'), + ('\u{ad}', '\u{ad}'), + ('¯', '¯'), + ('´', '´'), + ('·', '¸'), + ('Ê°', '\u{36f}'), + ('Í´', '͵'), + ('ͺ', 'ͺ'), + ('΄', 'Î…'), + ('·', '·'), + ('\u{483}', '\u{489}'), + ('Õ™', 'Õ™'), + ('ÕŸ', 'ÕŸ'), + ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), + ('×´', '×´'), + ('\u{600}', '\u{605}'), + ('\u{610}', '\u{61a}'), + ('\u{61c}', '\u{61c}'), + ('Ù€', 'Ù€'), + ('\u{64b}', '\u{65f}'), + ('\u{670}', '\u{670}'), + ('\u{6d6}', '\u{6dd}'), + ('\u{6df}', '\u{6e8}'), + ('\u{6ea}', '\u{6ed}'), + ('\u{70f}', '\u{70f}'), + ('\u{711}', '\u{711}'), + ('\u{730}', '\u{74a}'), + ('\u{7a6}', '\u{7b0}'), + ('\u{7eb}', 'ßµ'), + ('ߺ', 'ߺ'), + ('\u{7fd}', '\u{7fd}'), + ('\u{816}', '\u{82d}'), + ('\u{859}', '\u{85b}'), + ('࢈', '࢈'), + ('\u{890}', '\u{891}'), + ('\u{898}', '\u{89f}'), + ('ࣉ', '\u{902}'), + ('\u{93a}', '\u{93a}'), + ('\u{93c}', '\u{93c}'), + ('\u{941}', '\u{948}'), + ('\u{94d}', '\u{94d}'), + ('\u{951}', '\u{957}'), + ('\u{962}', '\u{963}'), + ('ॱ', 'ॱ'), + ('\u{981}', '\u{981}'), + ('\u{9bc}', '\u{9bc}'), + ('\u{9c1}', '\u{9c4}'), + ('\u{9cd}', '\u{9cd}'), + ('\u{9e2}', '\u{9e3}'), + ('\u{9fe}', '\u{9fe}'), + ('\u{a01}', '\u{a02}'), + ('\u{a3c}', '\u{a3c}'), + ('\u{a41}', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), + ('\u{a70}', '\u{a71}'), + ('\u{a75}', '\u{a75}'), + ('\u{a81}', '\u{a82}'), + ('\u{abc}', '\u{abc}'), + ('\u{ac1}', '\u{ac5}'), + ('\u{ac7}', '\u{ac8}'), + ('\u{acd}', '\u{acd}'), + ('\u{ae2}', '\u{ae3}'), + ('\u{afa}', '\u{aff}'), + ('\u{b01}', '\u{b01}'), + ('\u{b3c}', '\u{b3c}'), + ('\u{b3f}', '\u{b3f}'), + ('\u{b41}', '\u{b44}'), + ('\u{b4d}', '\u{b4d}'), + ('\u{b55}', '\u{b56}'), + ('\u{b62}', '\u{b63}'), + ('\u{b82}', '\u{b82}'), + ('\u{bc0}', '\u{bc0}'), + ('\u{bcd}', '\u{bcd}'), + ('\u{c00}', '\u{c00}'), + ('\u{c04}', '\u{c04}'), + ('\u{c3c}', '\u{c3c}'), + ('\u{c3e}', '\u{c40}'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('\u{c62}', '\u{c63}'), + ('\u{c81}', '\u{c81}'), + ('\u{cbc}', '\u{cbc}'), + ('\u{cbf}', '\u{cbf}'), + ('\u{cc6}', '\u{cc6}'), + ('\u{ccc}', '\u{ccd}'), + ('\u{ce2}', '\u{ce3}'), + ('\u{d00}', '\u{d01}'), + ('\u{d3b}', '\u{d3c}'), + ('\u{d41}', '\u{d44}'), + ('\u{d4d}', '\u{d4d}'), + ('\u{d62}', '\u{d63}'), + ('\u{d81}', '\u{d81}'), + ('\u{dca}', '\u{dca}'), + ('\u{dd2}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('\u{e31}', '\u{e31}'), + ('\u{e34}', '\u{e3a}'), + ('ๆ', '\u{e4e}'), + ('\u{eb1}', '\u{eb1}'), + ('\u{eb4}', '\u{ebc}'), + ('ໆ', 'ໆ'), + ('\u{ec8}', '\u{ece}'), + ('\u{f18}', '\u{f19}'), + ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), + ('\u{f39}', '\u{f39}'), + ('\u{f71}', '\u{f7e}'), + ('\u{f80}', '\u{f84}'), + ('\u{f86}', '\u{f87}'), + ('\u{f8d}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('\u{fc6}', '\u{fc6}'), + ('\u{102d}', '\u{1030}'), + ('\u{1032}', '\u{1037}'), + ('\u{1039}', '\u{103a}'), + ('\u{103d}', '\u{103e}'), + ('\u{1058}', '\u{1059}'), + ('\u{105e}', '\u{1060}'), + ('\u{1071}', '\u{1074}'), + ('\u{1082}', '\u{1082}'), + ('\u{1085}', '\u{1086}'), + ('\u{108d}', '\u{108d}'), + ('\u{109d}', '\u{109d}'), + ('ჼ', 'ჼ'), + ('\u{135d}', '\u{135f}'), + ('\u{1712}', '\u{1714}'), + ('\u{1732}', '\u{1733}'), + ('\u{1752}', '\u{1753}'), + ('\u{1772}', '\u{1773}'), + ('\u{17b4}', '\u{17b5}'), + ('\u{17b7}', '\u{17bd}'), + ('\u{17c6}', '\u{17c6}'), + ('\u{17c9}', '\u{17d3}'), + ('ៗ', 'ៗ'), + ('\u{17dd}', '\u{17dd}'), + ('\u{180b}', '\u{180f}'), + ('ᡃ', 'ᡃ'), + ('\u{1885}', '\u{1886}'), + ('\u{18a9}', '\u{18a9}'), + ('\u{1920}', '\u{1922}'), + ('\u{1927}', '\u{1928}'), + ('\u{1932}', '\u{1932}'), + ('\u{1939}', '\u{193b}'), + ('\u{1a17}', '\u{1a18}'), + ('\u{1a1b}', '\u{1a1b}'), + ('\u{1a56}', '\u{1a56}'), + ('\u{1a58}', '\u{1a5e}'), + ('\u{1a60}', '\u{1a60}'), + ('\u{1a62}', '\u{1a62}'), + ('\u{1a65}', '\u{1a6c}'), + ('\u{1a73}', '\u{1a7c}'), + ('\u{1a7f}', '\u{1a7f}'), + ('ᪧ', 'ᪧ'), + ('\u{1ab0}', '\u{1ace}'), + ('\u{1b00}', '\u{1b03}'), + ('\u{1b34}', '\u{1b34}'), + ('\u{1b36}', '\u{1b3a}'), + ('\u{1b3c}', '\u{1b3c}'), + ('\u{1b42}', '\u{1b42}'), + ('\u{1b6b}', '\u{1b73}'), + ('\u{1b80}', '\u{1b81}'), + ('\u{1ba2}', '\u{1ba5}'), + ('\u{1ba8}', '\u{1ba9}'), + ('\u{1bab}', '\u{1bad}'), + ('\u{1be6}', '\u{1be6}'), + ('\u{1be8}', '\u{1be9}'), + ('\u{1bed}', '\u{1bed}'), + ('\u{1bef}', '\u{1bf1}'), + ('\u{1c2c}', '\u{1c33}'), + ('\u{1c36}', '\u{1c37}'), + ('ᱸ', 'á±½'), + ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', '\u{1ce0}'), + ('\u{1ce2}', '\u{1ce8}'), + ('\u{1ced}', '\u{1ced}'), + ('\u{1cf4}', '\u{1cf4}'), + ('\u{1cf8}', '\u{1cf9}'), + ('á´¬', 'ᵪ'), + ('ᵸ', 'ᵸ'), + ('ᶛ', '\u{1dff}'), + ('á¾½', 'á¾½'), + ('᾿', 'á¿'), + ('á¿', 'á¿'), + ('á¿', 'á¿Ÿ'), + ('á¿­', '`'), + ('´', '῾'), + ('\u{200b}', '\u{200f}'), + ('‘', '’'), + ('․', '․'), + ('‧', '‧'), + ('\u{202a}', '\u{202e}'), + ('\u{2060}', '\u{2064}'), + ('\u{2066}', '\u{206f}'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('\u{20d0}', '\u{20f0}'), + ('â±¼', 'â±½'), + ('\u{2cef}', '\u{2cf1}'), + ('ⵯ', 'ⵯ'), + ('\u{2d7f}', '\u{2d7f}'), + ('\u{2de0}', '\u{2dff}'), + ('ⸯ', 'ⸯ'), + ('々', '々'), + ('\u{302a}', '\u{302d}'), + ('〱', '〵'), + ('〻', '〻'), + ('\u{3099}', 'ã‚ž'), + ('ー', 'ヾ'), + ('ꀕ', 'ꀕ'), + ('ꓸ', 'ꓽ'), + ('ꘌ', 'ꘌ'), + ('\u{a66f}', '\u{a672}'), + ('\u{a674}', '\u{a67d}'), + ('ꙿ', 'ꙿ'), + ('êšœ', '\u{a69f}'), + ('\u{a6f0}', '\u{a6f1}'), + ('꜀', '꜡'), + ('ê°', 'ê°'), + ('ꞈ', '꞊'), + ('ꟲ', 'ꟴ'), + ('ꟸ', 'ꟹ'), + ('\u{a802}', '\u{a802}'), + ('\u{a806}', '\u{a806}'), + ('\u{a80b}', '\u{a80b}'), + ('\u{a825}', '\u{a826}'), + ('\u{a82c}', '\u{a82c}'), + ('\u{a8c4}', '\u{a8c5}'), + ('\u{a8e0}', '\u{a8f1}'), + ('\u{a8ff}', '\u{a8ff}'), + ('\u{a926}', '\u{a92d}'), + ('\u{a947}', '\u{a951}'), + ('\u{a980}', '\u{a982}'), + ('\u{a9b3}', '\u{a9b3}'), + ('\u{a9b6}', '\u{a9b9}'), + ('\u{a9bc}', '\u{a9bd}'), + ('ê§', 'ê§'), + ('\u{a9e5}', 'ꧦ'), + ('\u{aa29}', '\u{aa2e}'), + ('\u{aa31}', '\u{aa32}'), + ('\u{aa35}', '\u{aa36}'), + ('\u{aa43}', '\u{aa43}'), + ('\u{aa4c}', '\u{aa4c}'), + ('ê©°', 'ê©°'), + ('\u{aa7c}', '\u{aa7c}'), + ('\u{aab0}', '\u{aab0}'), + ('\u{aab2}', '\u{aab4}'), + ('\u{aab7}', '\u{aab8}'), + ('\u{aabe}', '\u{aabf}'), + ('\u{aac1}', '\u{aac1}'), + ('ê«', 'ê«'), + ('\u{aaec}', '\u{aaed}'), + ('ꫳ', 'ê«´'), + ('\u{aaf6}', '\u{aaf6}'), + ('ê­›', 'ê­Ÿ'), + ('ê­©', 'ê­«'), + ('\u{abe5}', '\u{abe5}'), + ('\u{abe8}', '\u{abe8}'), + ('\u{abed}', '\u{abed}'), + ('\u{fb1e}', '\u{fb1e}'), + ('﮲', '﯂'), + ('\u{fe00}', '\u{fe0f}'), + ('︓', '︓'), + ('\u{fe20}', '\u{fe2f}'), + ('ï¹’', 'ï¹’'), + ('﹕', '﹕'), + ('\u{feff}', '\u{feff}'), + (''', '''), + ('.', '.'), + (':', ':'), + ('ï¼¾', 'ï¼¾'), + ('ï½€', 'ï½€'), + ('ï½°', 'ï½°'), + ('\u{ff9e}', '\u{ff9f}'), + ('ï¿£', 'ï¿£'), + ('\u{fff9}', '\u{fffb}'), + ('\u{101fd}', '\u{101fd}'), + ('\u{102e0}', '\u{102e0}'), + ('\u{10376}', '\u{1037a}'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('\u{10a01}', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), + ('\u{10ae5}', '\u{10ae6}'), + ('\u{10d24}', '\u{10d27}'), + ('\u{10eab}', '\u{10eac}'), + ('\u{10efd}', '\u{10eff}'), + ('\u{10f46}', '\u{10f50}'), + ('\u{10f82}', '\u{10f85}'), + ('\u{11001}', '\u{11001}'), + ('\u{11038}', '\u{11046}'), + ('\u{11070}', '\u{11070}'), + ('\u{11073}', '\u{11074}'), + ('\u{1107f}', '\u{11081}'), + ('\u{110b3}', '\u{110b6}'), + ('\u{110b9}', '\u{110ba}'), + ('\u{110bd}', '\u{110bd}'), + ('\u{110c2}', '\u{110c2}'), + ('\u{110cd}', '\u{110cd}'), + ('\u{11100}', '\u{11102}'), + ('\u{11127}', '\u{1112b}'), + ('\u{1112d}', '\u{11134}'), + ('\u{11173}', '\u{11173}'), + ('\u{11180}', '\u{11181}'), + ('\u{111b6}', '\u{111be}'), + ('\u{111c9}', '\u{111cc}'), + ('\u{111cf}', '\u{111cf}'), + ('\u{1122f}', '\u{11231}'), + ('\u{11234}', '\u{11234}'), + ('\u{11236}', '\u{11237}'), + ('\u{1123e}', '\u{1123e}'), + ('\u{11241}', '\u{11241}'), + ('\u{112df}', '\u{112df}'), + ('\u{112e3}', '\u{112ea}'), + ('\u{11300}', '\u{11301}'), + ('\u{1133b}', '\u{1133c}'), + ('\u{11340}', '\u{11340}'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('\u{11438}', '\u{1143f}'), + ('\u{11442}', '\u{11444}'), + ('\u{11446}', '\u{11446}'), + ('\u{1145e}', '\u{1145e}'), + ('\u{114b3}', '\u{114b8}'), + ('\u{114ba}', '\u{114ba}'), + ('\u{114bf}', '\u{114c0}'), + ('\u{114c2}', '\u{114c3}'), + ('\u{115b2}', '\u{115b5}'), + ('\u{115bc}', '\u{115bd}'), + ('\u{115bf}', '\u{115c0}'), + ('\u{115dc}', '\u{115dd}'), + ('\u{11633}', '\u{1163a}'), + ('\u{1163d}', '\u{1163d}'), + ('\u{1163f}', '\u{11640}'), + ('\u{116ab}', '\u{116ab}'), + ('\u{116ad}', '\u{116ad}'), + ('\u{116b0}', '\u{116b5}'), + ('\u{116b7}', '\u{116b7}'), + ('\u{1171d}', '\u{1171f}'), + ('\u{11722}', '\u{11725}'), + ('\u{11727}', '\u{1172b}'), + ('\u{1182f}', '\u{11837}'), + ('\u{11839}', '\u{1183a}'), + ('\u{1193b}', '\u{1193c}'), + ('\u{1193e}', '\u{1193e}'), + ('\u{11943}', '\u{11943}'), + ('\u{119d4}', '\u{119d7}'), + ('\u{119da}', '\u{119db}'), + ('\u{119e0}', '\u{119e0}'), + ('\u{11a01}', '\u{11a0a}'), + ('\u{11a33}', '\u{11a38}'), + ('\u{11a3b}', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), + ('\u{11a51}', '\u{11a56}'), + ('\u{11a59}', '\u{11a5b}'), + ('\u{11a8a}', '\u{11a96}'), + ('\u{11a98}', '\u{11a99}'), + ('\u{11c30}', '\u{11c36}'), + ('\u{11c38}', '\u{11c3d}'), + ('\u{11c3f}', '\u{11c3f}'), + ('\u{11c92}', '\u{11ca7}'), + ('\u{11caa}', '\u{11cb0}'), + ('\u{11cb2}', '\u{11cb3}'), + ('\u{11cb5}', '\u{11cb6}'), + ('\u{11d31}', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d45}'), + ('\u{11d47}', '\u{11d47}'), + ('\u{11d90}', '\u{11d91}'), + ('\u{11d95}', '\u{11d95}'), + ('\u{11d97}', '\u{11d97}'), + ('\u{11ef3}', '\u{11ef4}'), + ('\u{11f00}', '\u{11f01}'), + ('\u{11f36}', '\u{11f3a}'), + ('\u{11f40}', '\u{11f40}'), + ('\u{11f42}', '\u{11f42}'), + ('\u{13430}', '\u{13440}'), + ('\u{13447}', '\u{13455}'), + ('\u{16af0}', '\u{16af4}'), + ('\u{16b30}', '\u{16b36}'), + ('ð–­€', 'ð–­ƒ'), + ('\u{16f4f}', '\u{16f4f}'), + ('\u{16f8f}', '𖾟'), + ('ð–¿ ', 'ð–¿¡'), + ('ð–¿£', '\u{16fe4}'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1bca0}', '\u{1bca3}'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('\u{1d167}', '\u{1d169}'), + ('\u{1d173}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), + ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), + ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), + ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('𞀰', 'ðž­'), + ('\u{1e08f}', '\u{1e08f}'), + ('\u{1e130}', '𞄽'), + ('\u{1e2ae}', '\u{1e2ae}'), + ('\u{1e2ec}', '\u{1e2ef}'), + ('ðž“«', '\u{1e4ef}'), + ('\u{1e8d0}', '\u{1e8d6}'), + ('\u{1e944}', '𞥋'), + ('ðŸ»', 'ðŸ¿'), + ('\u{e0001}', '\u{e0001}'), + ('\u{e0020}', '\u{e007f}'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const CASED: &'static [(char, char)] = &[ + ('A', 'Z'), + ('a', 'z'), + ('ª', 'ª'), + ('µ', 'µ'), + ('º', 'º'), + ('À', 'Ö'), + ('Ø', 'ö'), + ('ø', 'ƺ'), + ('Ƽ', 'Æ¿'), + ('Ç„', 'Ê“'), + ('Ê•', 'ʸ'), + ('Ë€', 'Ë'), + ('Ë ', 'ˤ'), + ('\u{345}', '\u{345}'), + ('Í°', 'ͳ'), + ('Ͷ', 'Í·'), + ('ͺ', 'ͽ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'ϵ'), + ('Ï·', 'Ò'), + ('ÒŠ', 'Ô¯'), + ('Ô±', 'Õ–'), + ('Õ ', 'Öˆ'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ჺ'), + ('ჼ', 'ჿ'), + ('Ꭰ', 'áµ'), + ('á¸', 'á½'), + ('á²€', 'ᲈ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('á´€', 'ᶿ'), + ('Ḁ', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¾¼'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'á¿Œ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), + ('ῶ', 'ῼ'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„Š', 'â„“'), + ('â„•', 'â„•'), + ('â„™', 'â„'), + ('ℤ', 'ℤ'), + ('Ω', 'Ω'), + ('ℨ', 'ℨ'), + ('K', 'â„­'), + ('ℯ', 'â„´'), + ('ℹ', 'ℹ'), + ('ℼ', 'â„¿'), + ('â……', 'â…‰'), + ('â…Ž', 'â…Ž'), + ('â… ', 'â…¿'), + ('Ↄ', 'ↄ'), + ('â’¶', 'â“©'), + ('â°€', 'ⳤ'), + ('Ⳬ', 'â³®'), + ('â³²', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('Ꙁ', 'ê™­'), + ('Ꚁ', 'êš'), + ('Ꜣ', 'ꞇ'), + ('êž‹', 'ꞎ'), + ('êž', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('ꟲ', 'ꟶ'), + ('ꟸ', 'ꟺ'), + ('ꬰ', 'ê­š'), + ('ê­œ', 'ê­©'), + ('ê­°', 'ꮿ'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('A', 'Z'), + ('ï½', 'z'), + ('ð€', 'ð‘'), + ('ð’°', 'ð““'), + ('ð“˜', 'ð“»'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ðž€', 'ðž€'), + ('ðžƒ', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð²€', 'ð²²'), + ('ð³€', 'ð³²'), + ('ð‘¢ ', '𑣟'), + ('ð–¹€', '𖹿'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ð›€'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›º'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ´'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð®'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž¨'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‹'), + ('ð¼€', 'ð¼‰'), + ('ð¼‹', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('𞀰', 'ðž­'), + ('𞤀', '𞥃'), + ('🄰', '🅉'), + ('ðŸ…', '🅩'), + ('🅰', '🆉'), +]; + +pub const CHANGES_WHEN_CASEFOLDED: &'static [(char, char)] = &[ + ('A', 'Z'), + ('µ', 'µ'), + ('À', 'Ö'), + ('Ø', 'ß'), + ('Ä€', 'Ä€'), + ('Ä‚', 'Ä‚'), + ('Ä„', 'Ä„'), + ('Ć', 'Ć'), + ('Ĉ', 'Ĉ'), + ('ÄŠ', 'ÄŠ'), + ('ÄŒ', 'ÄŒ'), + ('ÄŽ', 'ÄŽ'), + ('Ä', 'Ä'), + ('Ä’', 'Ä’'), + ('Ä”', 'Ä”'), + ('Ä–', 'Ä–'), + ('Ę', 'Ę'), + ('Äš', 'Äš'), + ('Äœ', 'Äœ'), + ('Äž', 'Äž'), + ('Ä ', 'Ä '), + ('Ä¢', 'Ä¢'), + ('Ĥ', 'Ĥ'), + ('Ħ', 'Ħ'), + ('Ĩ', 'Ĩ'), + ('Ī', 'Ī'), + ('Ĭ', 'Ĭ'), + ('Ä®', 'Ä®'), + ('Ä°', 'Ä°'), + ('IJ', 'IJ'), + ('Ä´', 'Ä´'), + ('Ķ', 'Ķ'), + ('Ĺ', 'Ĺ'), + ('Ä»', 'Ä»'), + ('Ľ', 'Ľ'), + ('Ä¿', 'Ä¿'), + ('Å', 'Å'), + ('Ń', 'Ń'), + ('Å…', 'Å…'), + ('Ň', 'Ň'), + ('ʼn', 'ÅŠ'), + ('ÅŒ', 'ÅŒ'), + ('ÅŽ', 'ÅŽ'), + ('Å', 'Å'), + ('Å’', 'Å’'), + ('Å”', 'Å”'), + ('Å–', 'Å–'), + ('Ř', 'Ř'), + ('Åš', 'Åš'), + ('Åœ', 'Åœ'), + ('Åž', 'Åž'), + ('Å ', 'Å '), + ('Å¢', 'Å¢'), + ('Ť', 'Ť'), + ('Ŧ', 'Ŧ'), + ('Ũ', 'Ũ'), + ('Ū', 'Ū'), + ('Ŭ', 'Ŭ'), + ('Å®', 'Å®'), + ('Å°', 'Å°'), + ('Ų', 'Ų'), + ('Å´', 'Å´'), + ('Ŷ', 'Ŷ'), + ('Ÿ', 'Ź'), + ('Å»', 'Å»'), + ('Ž', 'Ž'), + ('Å¿', 'Å¿'), + ('Æ', 'Æ‚'), + ('Æ„', 'Æ„'), + ('Ɔ', 'Ƈ'), + ('Ɖ', 'Æ‹'), + ('ÆŽ', 'Æ‘'), + ('Æ“', 'Æ”'), + ('Æ–', 'Ƙ'), + ('Æœ', 'Æ'), + ('ÆŸ', 'Æ '), + ('Æ¢', 'Æ¢'), + ('Ƥ', 'Ƥ'), + ('Ʀ', 'Ƨ'), + ('Æ©', 'Æ©'), + ('Ƭ', 'Ƭ'), + ('Æ®', 'Ư'), + ('Ʊ', 'Ƴ'), + ('Ƶ', 'Ƶ'), + ('Æ·', 'Ƹ'), + ('Ƽ', 'Ƽ'), + ('Ç„', 'Ç…'), + ('LJ', 'Lj'), + ('ÇŠ', 'Ç‹'), + ('Ç', 'Ç'), + ('Ç', 'Ç'), + ('Ç‘', 'Ç‘'), + ('Ç“', 'Ç“'), + ('Ç•', 'Ç•'), + ('Ç—', 'Ç—'), + ('Ç™', 'Ç™'), + ('Ç›', 'Ç›'), + ('Çž', 'Çž'), + ('Ç ', 'Ç '), + ('Ç¢', 'Ç¢'), + ('Ǥ', 'Ǥ'), + ('Ǧ', 'Ǧ'), + ('Ǩ', 'Ǩ'), + ('Ǫ', 'Ǫ'), + ('Ǭ', 'Ǭ'), + ('Ç®', 'Ç®'), + ('DZ', 'Dz'), + ('Ç´', 'Ç´'), + ('Ƕ', 'Ǹ'), + ('Ǻ', 'Ǻ'), + ('Ǽ', 'Ǽ'), + ('Ǿ', 'Ǿ'), + ('È€', 'È€'), + ('È‚', 'È‚'), + ('È„', 'È„'), + ('Ȇ', 'Ȇ'), + ('Ȉ', 'Ȉ'), + ('ÈŠ', 'ÈŠ'), + ('ÈŒ', 'ÈŒ'), + ('ÈŽ', 'ÈŽ'), + ('È', 'È'), + ('È’', 'È’'), + ('È”', 'È”'), + ('È–', 'È–'), + ('Ș', 'Ș'), + ('Èš', 'Èš'), + ('Èœ', 'Èœ'), + ('Èž', 'Èž'), + ('È ', 'È '), + ('È¢', 'È¢'), + ('Ȥ', 'Ȥ'), + ('Ȧ', 'Ȧ'), + ('Ȩ', 'Ȩ'), + ('Ȫ', 'Ȫ'), + ('Ȭ', 'Ȭ'), + ('È®', 'È®'), + ('È°', 'È°'), + ('Ȳ', 'Ȳ'), + ('Ⱥ', 'È»'), + ('Ƚ', 'Ⱦ'), + ('É', 'É'), + ('Ƀ', 'Ɇ'), + ('Ɉ', 'Ɉ'), + ('ÉŠ', 'ÉŠ'), + ('ÉŒ', 'ÉŒ'), + ('ÉŽ', 'ÉŽ'), + ('\u{345}', '\u{345}'), + ('Í°', 'Í°'), + ('Ͳ', 'Ͳ'), + ('Ͷ', 'Ͷ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Î'), + ('Α', 'Ρ'), + ('Σ', 'Ϋ'), + ('Ï‚', 'Ï‚'), + ('Ï', 'Ï‘'), + ('Ï•', 'Ï–'), + ('Ϙ', 'Ϙ'), + ('Ïš', 'Ïš'), + ('Ïœ', 'Ïœ'), + ('Ïž', 'Ïž'), + ('Ï ', 'Ï '), + ('Ï¢', 'Ï¢'), + ('Ϥ', 'Ϥ'), + ('Ϧ', 'Ϧ'), + ('Ϩ', 'Ϩ'), + ('Ϫ', 'Ϫ'), + ('Ϭ', 'Ϭ'), + ('Ï®', 'Ï®'), + ('Ï°', 'ϱ'), + ('Ï´', 'ϵ'), + ('Ï·', 'Ï·'), + ('Ϲ', 'Ϻ'), + ('Ͻ', 'Я'), + ('Ñ ', 'Ñ '), + ('Ñ¢', 'Ñ¢'), + ('Ѥ', 'Ѥ'), + ('Ѧ', 'Ѧ'), + ('Ѩ', 'Ѩ'), + ('Ѫ', 'Ѫ'), + ('Ѭ', 'Ѭ'), + ('Ñ®', 'Ñ®'), + ('Ñ°', 'Ñ°'), + ('Ѳ', 'Ѳ'), + ('Ñ´', 'Ñ´'), + ('Ѷ', 'Ѷ'), + ('Ѹ', 'Ѹ'), + ('Ѻ', 'Ѻ'), + ('Ѽ', 'Ѽ'), + ('Ѿ', 'Ѿ'), + ('Ò€', 'Ò€'), + ('ÒŠ', 'ÒŠ'), + ('ÒŒ', 'ÒŒ'), + ('ÒŽ', 'ÒŽ'), + ('Ò', 'Ò'), + ('Ò’', 'Ò’'), + ('Ò”', 'Ò”'), + ('Ò–', 'Ò–'), + ('Ò˜', 'Ò˜'), + ('Òš', 'Òš'), + ('Òœ', 'Òœ'), + ('Òž', 'Òž'), + ('Ò ', 'Ò '), + ('Ò¢', 'Ò¢'), + ('Ò¤', 'Ò¤'), + ('Ò¦', 'Ò¦'), + ('Ò¨', 'Ò¨'), + ('Òª', 'Òª'), + ('Ò¬', 'Ò¬'), + ('Ò®', 'Ò®'), + ('Ò°', 'Ò°'), + ('Ò²', 'Ò²'), + ('Ò´', 'Ò´'), + ('Ò¶', 'Ò¶'), + ('Ò¸', 'Ò¸'), + ('Òº', 'Òº'), + ('Ò¼', 'Ò¼'), + ('Ò¾', 'Ò¾'), + ('Ó€', 'Ó'), + ('Óƒ', 'Óƒ'), + ('Ó…', 'Ó…'), + ('Ó‡', 'Ó‡'), + ('Ó‰', 'Ó‰'), + ('Ó‹', 'Ó‹'), + ('Ó', 'Ó'), + ('Ó', 'Ó'), + ('Ó’', 'Ó’'), + ('Ó”', 'Ó”'), + ('Ó–', 'Ó–'), + ('Ó˜', 'Ó˜'), + ('Óš', 'Óš'), + ('Óœ', 'Óœ'), + ('Óž', 'Óž'), + ('Ó ', 'Ó '), + ('Ó¢', 'Ó¢'), + ('Ó¤', 'Ó¤'), + ('Ó¦', 'Ó¦'), + ('Ó¨', 'Ó¨'), + ('Óª', 'Óª'), + ('Ó¬', 'Ó¬'), + ('Ó®', 'Ó®'), + ('Ó°', 'Ó°'), + ('Ó²', 'Ó²'), + ('Ó´', 'Ó´'), + ('Ó¶', 'Ó¶'), + ('Ó¸', 'Ó¸'), + ('Óº', 'Óº'), + ('Ó¼', 'Ó¼'), + ('Ó¾', 'Ó¾'), + ('Ô€', 'Ô€'), + ('Ô‚', 'Ô‚'), + ('Ô„', 'Ô„'), + ('Ô†', 'Ô†'), + ('Ôˆ', 'Ôˆ'), + ('ÔŠ', 'ÔŠ'), + ('ÔŒ', 'ÔŒ'), + ('ÔŽ', 'ÔŽ'), + ('Ô', 'Ô'), + ('Ô’', 'Ô’'), + ('Ô”', 'Ô”'), + ('Ô–', 'Ô–'), + ('Ô˜', 'Ô˜'), + ('Ôš', 'Ôš'), + ('Ôœ', 'Ôœ'), + ('Ôž', 'Ôž'), + ('Ô ', 'Ô '), + ('Ô¢', 'Ô¢'), + ('Ô¤', 'Ô¤'), + ('Ô¦', 'Ô¦'), + ('Ô¨', 'Ô¨'), + ('Ôª', 'Ôª'), + ('Ô¬', 'Ô¬'), + ('Ô®', 'Ô®'), + ('Ô±', 'Õ–'), + ('Ö‡', 'Ö‡'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('á¸', 'á½'), + ('á²€', 'ᲈ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('Ḁ', 'Ḁ'), + ('Ḃ', 'Ḃ'), + ('Ḅ', 'Ḅ'), + ('Ḇ', 'Ḇ'), + ('Ḉ', 'Ḉ'), + ('Ḋ', 'Ḋ'), + ('Ḍ', 'Ḍ'), + ('Ḏ', 'Ḏ'), + ('á¸', 'á¸'), + ('Ḓ', 'Ḓ'), + ('Ḕ', 'Ḕ'), + ('Ḗ', 'Ḗ'), + ('Ḙ', 'Ḙ'), + ('Ḛ', 'Ḛ'), + ('Ḝ', 'Ḝ'), + ('Ḟ', 'Ḟ'), + ('Ḡ', 'Ḡ'), + ('Ḣ', 'Ḣ'), + ('Ḥ', 'Ḥ'), + ('Ḧ', 'Ḧ'), + ('Ḩ', 'Ḩ'), + ('Ḫ', 'Ḫ'), + ('Ḭ', 'Ḭ'), + ('Ḯ', 'Ḯ'), + ('Ḱ', 'Ḱ'), + ('Ḳ', 'Ḳ'), + ('Ḵ', 'Ḵ'), + ('Ḷ', 'Ḷ'), + ('Ḹ', 'Ḹ'), + ('Ḻ', 'Ḻ'), + ('Ḽ', 'Ḽ'), + ('Ḿ', 'Ḿ'), + ('á¹€', 'á¹€'), + ('Ṃ', 'Ṃ'), + ('Ṅ', 'Ṅ'), + ('Ṇ', 'Ṇ'), + ('Ṉ', 'Ṉ'), + ('Ṋ', 'Ṋ'), + ('Ṍ', 'Ṍ'), + ('Ṏ', 'Ṏ'), + ('á¹', 'á¹'), + ('á¹’', 'á¹’'), + ('á¹”', 'á¹”'), + ('á¹–', 'á¹–'), + ('Ṙ', 'Ṙ'), + ('Ṛ', 'Ṛ'), + ('Ṝ', 'Ṝ'), + ('Ṟ', 'Ṟ'), + ('á¹ ', 'á¹ '), + ('á¹¢', 'á¹¢'), + ('Ṥ', 'Ṥ'), + ('Ṧ', 'Ṧ'), + ('Ṩ', 'Ṩ'), + ('Ṫ', 'Ṫ'), + ('Ṭ', 'Ṭ'), + ('á¹®', 'á¹®'), + ('á¹°', 'á¹°'), + ('á¹²', 'á¹²'), + ('á¹´', 'á¹´'), + ('Ṷ', 'Ṷ'), + ('Ṹ', 'Ṹ'), + ('Ṻ', 'Ṻ'), + ('á¹¼', 'á¹¼'), + ('á¹¾', 'á¹¾'), + ('Ẁ', 'Ẁ'), + ('Ẃ', 'Ẃ'), + ('Ẅ', 'Ẅ'), + ('Ẇ', 'Ẇ'), + ('Ẉ', 'Ẉ'), + ('Ẋ', 'Ẋ'), + ('Ẍ', 'Ẍ'), + ('Ẏ', 'Ẏ'), + ('áº', 'áº'), + ('Ẓ', 'Ẓ'), + ('Ẕ', 'Ẕ'), + ('ẚ', 'ẛ'), + ('ẞ', 'ẞ'), + ('Ạ', 'Ạ'), + ('Ả', 'Ả'), + ('Ấ', 'Ấ'), + ('Ầ', 'Ầ'), + ('Ẩ', 'Ẩ'), + ('Ẫ', 'Ẫ'), + ('Ậ', 'Ậ'), + ('Ắ', 'Ắ'), + ('Ằ', 'Ằ'), + ('Ẳ', 'Ẳ'), + ('Ẵ', 'Ẵ'), + ('Ặ', 'Ặ'), + ('Ẹ', 'Ẹ'), + ('Ẻ', 'Ẻ'), + ('Ẽ', 'Ẽ'), + ('Ế', 'Ế'), + ('Ề', 'Ề'), + ('Ể', 'Ể'), + ('Ễ', 'Ễ'), + ('Ệ', 'Ệ'), + ('Ỉ', 'Ỉ'), + ('Ị', 'Ị'), + ('Ọ', 'Ọ'), + ('Ỏ', 'Ỏ'), + ('á»', 'á»'), + ('á»’', 'á»’'), + ('á»”', 'á»”'), + ('á»–', 'á»–'), + ('Ộ', 'Ộ'), + ('Ớ', 'Ớ'), + ('Ờ', 'Ờ'), + ('Ở', 'Ở'), + ('á» ', 'á» '), + ('Ợ', 'Ợ'), + ('Ụ', 'Ụ'), + ('Ủ', 'Ủ'), + ('Ứ', 'Ứ'), + ('Ừ', 'Ừ'), + ('Ử', 'Ử'), + ('á»®', 'á»®'), + ('á»°', 'á»°'), + ('Ỳ', 'Ỳ'), + ('á»´', 'á»´'), + ('Ỷ', 'Ỷ'), + ('Ỹ', 'Ỹ'), + ('Ỻ', 'Ỻ'), + ('Ỽ', 'Ỽ'), + ('Ỿ', 'Ỿ'), + ('Ἀ', 'á¼'), + ('Ἐ', 'á¼'), + ('Ἠ', 'Ἧ'), + ('Ἰ', 'Ἷ'), + ('Ὀ', 'á½'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'Ὗ'), + ('Ὠ', 'Ὧ'), + ('á¾€', 'ᾯ'), + ('á¾²', 'á¾´'), + ('á¾·', 'á¾¼'), + ('á¿‚', 'á¿„'), + ('ῇ', 'á¿Œ'), + ('Ῐ', 'á¿›'), + ('Ῠ', 'Ῥ'), + ('ῲ', 'á¿´'), + ('á¿·', 'ῼ'), + ('Ω', 'Ω'), + ('K', 'â„«'), + ('Ⅎ', 'Ⅎ'), + ('â… ', 'â…¯'), + ('Ↄ', 'Ↄ'), + ('â’¶', 'â“'), + ('â°€', 'â°¯'), + ('â± ', 'â± '), + ('â±¢', 'Ɽ'), + ('Ⱨ', 'Ⱨ'), + ('Ⱪ', 'Ⱪ'), + ('Ⱬ', 'Ⱬ'), + ('â±­', 'â±°'), + ('â±²', 'â±²'), + ('â±µ', 'â±µ'), + ('â±¾', 'â²€'), + ('Ⲃ', 'Ⲃ'), + ('Ⲅ', 'Ⲅ'), + ('Ⲇ', 'Ⲇ'), + ('Ⲉ', 'Ⲉ'), + ('Ⲋ', 'Ⲋ'), + ('Ⲍ', 'Ⲍ'), + ('Ⲏ', 'Ⲏ'), + ('â²', 'â²'), + ('â²’', 'â²’'), + ('â²”', 'â²”'), + ('â²–', 'â²–'), + ('Ⲙ', 'Ⲙ'), + ('Ⲛ', 'Ⲛ'), + ('Ⲝ', 'Ⲝ'), + ('Ⲟ', 'Ⲟ'), + ('â² ', 'â² '), + ('â²¢', 'â²¢'), + ('Ⲥ', 'Ⲥ'), + ('Ⲧ', 'Ⲧ'), + ('Ⲩ', 'Ⲩ'), + ('Ⲫ', 'Ⲫ'), + ('Ⲭ', 'Ⲭ'), + ('â²®', 'â²®'), + ('â²°', 'â²°'), + ('â²²', 'â²²'), + ('â²´', 'â²´'), + ('Ⲷ', 'Ⲷ'), + ('Ⲹ', 'Ⲹ'), + ('Ⲻ', 'Ⲻ'), + ('â²¼', 'â²¼'), + ('â²¾', 'â²¾'), + ('â³€', 'â³€'), + ('Ⳃ', 'Ⳃ'), + ('Ⳅ', 'Ⳅ'), + ('Ⳇ', 'Ⳇ'), + ('Ⳉ', 'Ⳉ'), + ('Ⳋ', 'Ⳋ'), + ('Ⳍ', 'Ⳍ'), + ('Ⳏ', 'Ⳏ'), + ('â³', 'â³'), + ('â³’', 'â³’'), + ('â³”', 'â³”'), + ('â³–', 'â³–'), + ('Ⳙ', 'Ⳙ'), + ('Ⳛ', 'Ⳛ'), + ('Ⳝ', 'Ⳝ'), + ('Ⳟ', 'Ⳟ'), + ('â³ ', 'â³ '), + ('â³¢', 'â³¢'), + ('Ⳬ', 'Ⳬ'), + ('â³­', 'â³­'), + ('â³²', 'â³²'), + ('Ꙁ', 'Ꙁ'), + ('Ꙃ', 'Ꙃ'), + ('Ꙅ', 'Ꙅ'), + ('Ꙇ', 'Ꙇ'), + ('Ꙉ', 'Ꙉ'), + ('Ꙋ', 'Ꙋ'), + ('Ꙍ', 'Ꙍ'), + ('Ꙏ', 'Ꙏ'), + ('ê™', 'ê™'), + ('ê™’', 'ê™’'), + ('ê™”', 'ê™”'), + ('ê™–', 'ê™–'), + ('Ꙙ', 'Ꙙ'), + ('Ꙛ', 'Ꙛ'), + ('Ꙝ', 'Ꙝ'), + ('Ꙟ', 'Ꙟ'), + ('ê™ ', 'ê™ '), + ('Ꙣ', 'Ꙣ'), + ('Ꙥ', 'Ꙥ'), + ('Ꙧ', 'Ꙧ'), + ('Ꙩ', 'Ꙩ'), + ('Ꙫ', 'Ꙫ'), + ('Ꙭ', 'Ꙭ'), + ('Ꚁ', 'Ꚁ'), + ('êš‚', 'êš‚'), + ('êš„', 'êš„'), + ('Ꚇ', 'Ꚇ'), + ('Ꚉ', 'Ꚉ'), + ('Ꚋ', 'Ꚋ'), + ('Ꚍ', 'Ꚍ'), + ('Ꚏ', 'Ꚏ'), + ('êš', 'êš'), + ('êš’', 'êš’'), + ('êš”', 'êš”'), + ('êš–', 'êš–'), + ('Ꚙ', 'Ꚙ'), + ('êšš', 'êšš'), + ('Ꜣ', 'Ꜣ'), + ('Ꜥ', 'Ꜥ'), + ('Ꜧ', 'Ꜧ'), + ('Ꜩ', 'Ꜩ'), + ('Ꜫ', 'Ꜫ'), + ('Ꜭ', 'Ꜭ'), + ('Ꜯ', 'Ꜯ'), + ('Ꜳ', 'Ꜳ'), + ('Ꜵ', 'Ꜵ'), + ('Ꜷ', 'Ꜷ'), + ('Ꜹ', 'Ꜹ'), + ('Ꜻ', 'Ꜻ'), + ('Ꜽ', 'Ꜽ'), + ('Ꜿ', 'Ꜿ'), + ('ê€', 'ê€'), + ('ê‚', 'ê‚'), + ('ê„', 'ê„'), + ('ê†', 'ê†'), + ('êˆ', 'êˆ'), + ('êŠ', 'êŠ'), + ('êŒ', 'êŒ'), + ('êŽ', 'êŽ'), + ('ê', 'ê'), + ('ê’', 'ê’'), + ('ê”', 'ê”'), + ('ê–', 'ê–'), + ('ê˜', 'ê˜'), + ('êš', 'êš'), + ('êœ', 'êœ'), + ('êž', 'êž'), + ('ê ', 'ê '), + ('ê¢', 'ê¢'), + ('ê¤', 'ê¤'), + ('ê¦', 'ê¦'), + ('ê¨', 'ê¨'), + ('êª', 'êª'), + ('ê¬', 'ê¬'), + ('ê®', 'ê®'), + ('ê¹', 'ê¹'), + ('ê»', 'ê»'), + ('ê½', 'ê¾'), + ('Ꞁ', 'Ꞁ'), + ('êž‚', 'êž‚'), + ('êž„', 'êž„'), + ('Ꞇ', 'Ꞇ'), + ('êž‹', 'êž‹'), + ('êž', 'êž'), + ('êž', 'êž'), + ('êž’', 'êž’'), + ('êž–', 'êž–'), + ('Ꞙ', 'Ꞙ'), + ('êžš', 'êžš'), + ('êžœ', 'êžœ'), + ('êžž', 'êžž'), + ('êž ', 'êž '), + ('Ꞣ', 'Ꞣ'), + ('Ꞥ', 'Ꞥ'), + ('Ꞧ', 'Ꞧ'), + ('Ꞩ', 'Ꞩ'), + ('Ɦ', 'êž®'), + ('êž°', 'êž´'), + ('Ꞷ', 'Ꞷ'), + ('Ꞹ', 'Ꞹ'), + ('Ꞻ', 'Ꞻ'), + ('êž¼', 'êž¼'), + ('êž¾', 'êž¾'), + ('Ꟁ', 'Ꟁ'), + ('Ꟃ', 'Ꟃ'), + ('Ꞔ', 'Ꟈ'), + ('Ꟊ', 'Ꟊ'), + ('êŸ', 'êŸ'), + ('Ꟗ', 'Ꟗ'), + ('Ꟙ', 'Ꟙ'), + ('Ꟶ', 'Ꟶ'), + ('ê­°', 'ꮿ'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('A', 'Z'), + ('ð€', 'ð§'), + ('ð’°', 'ð““'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð²€', 'ð²²'), + ('ð‘¢ ', '𑢿'), + ('ð–¹€', '𖹟'), + ('𞤀', '𞤡'), +]; + +pub const CHANGES_WHEN_CASEMAPPED: &'static [(char, char)] = &[ + ('A', 'Z'), + ('a', 'z'), + ('µ', 'µ'), + ('À', 'Ö'), + ('Ø', 'ö'), + ('ø', 'Ä·'), + ('Ĺ', 'ÆŒ'), + ('ÆŽ', 'Æš'), + ('Æœ', 'Æ©'), + ('Ƭ', 'ƹ'), + ('Ƽ', 'ƽ'), + ('Æ¿', 'Æ¿'), + ('Ç„', 'È '), + ('È¢', 'ȳ'), + ('Ⱥ', 'É”'), + ('É–', 'É—'), + ('É™', 'É™'), + ('É›', 'Éœ'), + ('É ', 'É¡'), + ('É£', 'É£'), + ('É¥', 'ɦ'), + ('ɨ', 'ɬ'), + ('ɯ', 'ɯ'), + ('ɱ', 'ɲ'), + ('ɵ', 'ɵ'), + ('ɽ', 'ɽ'), + ('Ê€', 'Ê€'), + ('Ê‚', 'ʃ'), + ('ʇ', 'ÊŒ'), + ('Ê’', 'Ê’'), + ('Ê', 'Êž'), + ('\u{345}', '\u{345}'), + ('Í°', 'ͳ'), + ('Ͷ', 'Í·'), + ('Í»', 'ͽ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'Ï‘'), + ('Ï•', 'ϵ'), + ('Ï·', 'Ï»'), + ('Ͻ', 'Ò'), + ('ÒŠ', 'Ô¯'), + ('Ô±', 'Õ–'), + ('Õ¡', 'Ö‡'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ჺ'), + ('ჽ', 'ჿ'), + ('Ꭰ', 'áµ'), + ('á¸', 'á½'), + ('á²€', 'ᲈ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('áµ¹', 'áµ¹'), + ('áµ½', 'áµ½'), + ('ᶎ', 'ᶎ'), + ('Ḁ', 'ẛ'), + ('ẞ', 'ẞ'), + ('Ạ', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¾¼'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'á¿Œ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), + ('ῶ', 'ῼ'), + ('Ω', 'Ω'), + ('K', 'â„«'), + ('Ⅎ', 'Ⅎ'), + ('â…Ž', 'â…Ž'), + ('â… ', 'â…¿'), + ('Ↄ', 'ↄ'), + ('â’¶', 'â“©'), + ('â°€', 'â±°'), + ('â±²', 'â±³'), + ('â±µ', 'ⱶ'), + ('â±¾', 'â³£'), + ('Ⳬ', 'â³®'), + ('â³²', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('Ꙁ', 'ê™­'), + ('Ꚁ', 'êš›'), + ('Ꜣ', 'ꜯ'), + ('Ꜳ', 'ê¯'), + ('ê¹', 'ꞇ'), + ('êž‹', 'êž'), + ('êž', 'êž”'), + ('êž–', 'êž®'), + ('êž°', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('Ꟗ', 'ꟙ'), + ('Ꟶ', 'ꟶ'), + ('ê­“', 'ê­“'), + ('ê­°', 'ꮿ'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('A', 'Z'), + ('ï½', 'z'), + ('ð€', 'ð‘'), + ('ð’°', 'ð““'), + ('ð“˜', 'ð“»'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð²€', 'ð²²'), + ('ð³€', 'ð³²'), + ('ð‘¢ ', '𑣟'), + ('ð–¹€', '𖹿'), + ('𞤀', '𞥃'), +]; + +pub const CHANGES_WHEN_LOWERCASED: &'static [(char, char)] = &[ + ('A', 'Z'), + ('À', 'Ö'), + ('Ø', 'Þ'), + ('Ä€', 'Ä€'), + ('Ä‚', 'Ä‚'), + ('Ä„', 'Ä„'), + ('Ć', 'Ć'), + ('Ĉ', 'Ĉ'), + ('ÄŠ', 'ÄŠ'), + ('ÄŒ', 'ÄŒ'), + ('ÄŽ', 'ÄŽ'), + ('Ä', 'Ä'), + ('Ä’', 'Ä’'), + ('Ä”', 'Ä”'), + ('Ä–', 'Ä–'), + ('Ę', 'Ę'), + ('Äš', 'Äš'), + ('Äœ', 'Äœ'), + ('Äž', 'Äž'), + ('Ä ', 'Ä '), + ('Ä¢', 'Ä¢'), + ('Ĥ', 'Ĥ'), + ('Ħ', 'Ħ'), + ('Ĩ', 'Ĩ'), + ('Ī', 'Ī'), + ('Ĭ', 'Ĭ'), + ('Ä®', 'Ä®'), + ('Ä°', 'Ä°'), + ('IJ', 'IJ'), + ('Ä´', 'Ä´'), + ('Ķ', 'Ķ'), + ('Ĺ', 'Ĺ'), + ('Ä»', 'Ä»'), + ('Ľ', 'Ľ'), + ('Ä¿', 'Ä¿'), + ('Å', 'Å'), + ('Ń', 'Ń'), + ('Å…', 'Å…'), + ('Ň', 'Ň'), + ('ÅŠ', 'ÅŠ'), + ('ÅŒ', 'ÅŒ'), + ('ÅŽ', 'ÅŽ'), + ('Å', 'Å'), + ('Å’', 'Å’'), + ('Å”', 'Å”'), + ('Å–', 'Å–'), + ('Ř', 'Ř'), + ('Åš', 'Åš'), + ('Åœ', 'Åœ'), + ('Åž', 'Åž'), + ('Å ', 'Å '), + ('Å¢', 'Å¢'), + ('Ť', 'Ť'), + ('Ŧ', 'Ŧ'), + ('Ũ', 'Ũ'), + ('Ū', 'Ū'), + ('Ŭ', 'Ŭ'), + ('Å®', 'Å®'), + ('Å°', 'Å°'), + ('Ų', 'Ų'), + ('Å´', 'Å´'), + ('Ŷ', 'Ŷ'), + ('Ÿ', 'Ź'), + ('Å»', 'Å»'), + ('Ž', 'Ž'), + ('Æ', 'Æ‚'), + ('Æ„', 'Æ„'), + ('Ɔ', 'Ƈ'), + ('Ɖ', 'Æ‹'), + ('ÆŽ', 'Æ‘'), + ('Æ“', 'Æ”'), + ('Æ–', 'Ƙ'), + ('Æœ', 'Æ'), + ('ÆŸ', 'Æ '), + ('Æ¢', 'Æ¢'), + ('Ƥ', 'Ƥ'), + ('Ʀ', 'Ƨ'), + ('Æ©', 'Æ©'), + ('Ƭ', 'Ƭ'), + ('Æ®', 'Ư'), + ('Ʊ', 'Ƴ'), + ('Ƶ', 'Ƶ'), + ('Æ·', 'Ƹ'), + ('Ƽ', 'Ƽ'), + ('Ç„', 'Ç…'), + ('LJ', 'Lj'), + ('ÇŠ', 'Ç‹'), + ('Ç', 'Ç'), + ('Ç', 'Ç'), + ('Ç‘', 'Ç‘'), + ('Ç“', 'Ç“'), + ('Ç•', 'Ç•'), + ('Ç—', 'Ç—'), + ('Ç™', 'Ç™'), + ('Ç›', 'Ç›'), + ('Çž', 'Çž'), + ('Ç ', 'Ç '), + ('Ç¢', 'Ç¢'), + ('Ǥ', 'Ǥ'), + ('Ǧ', 'Ǧ'), + ('Ǩ', 'Ǩ'), + ('Ǫ', 'Ǫ'), + ('Ǭ', 'Ǭ'), + ('Ç®', 'Ç®'), + ('DZ', 'Dz'), + ('Ç´', 'Ç´'), + ('Ƕ', 'Ǹ'), + ('Ǻ', 'Ǻ'), + ('Ǽ', 'Ǽ'), + ('Ǿ', 'Ǿ'), + ('È€', 'È€'), + ('È‚', 'È‚'), + ('È„', 'È„'), + ('Ȇ', 'Ȇ'), + ('Ȉ', 'Ȉ'), + ('ÈŠ', 'ÈŠ'), + ('ÈŒ', 'ÈŒ'), + ('ÈŽ', 'ÈŽ'), + ('È', 'È'), + ('È’', 'È’'), + ('È”', 'È”'), + ('È–', 'È–'), + ('Ș', 'Ș'), + ('Èš', 'Èš'), + ('Èœ', 'Èœ'), + ('Èž', 'Èž'), + ('È ', 'È '), + ('È¢', 'È¢'), + ('Ȥ', 'Ȥ'), + ('Ȧ', 'Ȧ'), + ('Ȩ', 'Ȩ'), + ('Ȫ', 'Ȫ'), + ('Ȭ', 'Ȭ'), + ('È®', 'È®'), + ('È°', 'È°'), + ('Ȳ', 'Ȳ'), + ('Ⱥ', 'È»'), + ('Ƚ', 'Ⱦ'), + ('É', 'É'), + ('Ƀ', 'Ɇ'), + ('Ɉ', 'Ɉ'), + ('ÉŠ', 'ÉŠ'), + ('ÉŒ', 'ÉŒ'), + ('ÉŽ', 'ÉŽ'), + ('Í°', 'Í°'), + ('Ͳ', 'Ͳ'), + ('Ͷ', 'Ͷ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Î'), + ('Α', 'Ρ'), + ('Σ', 'Ϋ'), + ('Ï', 'Ï'), + ('Ϙ', 'Ϙ'), + ('Ïš', 'Ïš'), + ('Ïœ', 'Ïœ'), + ('Ïž', 'Ïž'), + ('Ï ', 'Ï '), + ('Ï¢', 'Ï¢'), + ('Ϥ', 'Ϥ'), + ('Ϧ', 'Ϧ'), + ('Ϩ', 'Ϩ'), + ('Ϫ', 'Ϫ'), + ('Ϭ', 'Ϭ'), + ('Ï®', 'Ï®'), + ('Ï´', 'Ï´'), + ('Ï·', 'Ï·'), + ('Ϲ', 'Ϻ'), + ('Ͻ', 'Я'), + ('Ñ ', 'Ñ '), + ('Ñ¢', 'Ñ¢'), + ('Ѥ', 'Ѥ'), + ('Ѧ', 'Ѧ'), + ('Ѩ', 'Ѩ'), + ('Ѫ', 'Ѫ'), + ('Ѭ', 'Ѭ'), + ('Ñ®', 'Ñ®'), + ('Ñ°', 'Ñ°'), + ('Ѳ', 'Ѳ'), + ('Ñ´', 'Ñ´'), + ('Ѷ', 'Ѷ'), + ('Ѹ', 'Ѹ'), + ('Ѻ', 'Ѻ'), + ('Ѽ', 'Ѽ'), + ('Ѿ', 'Ѿ'), + ('Ò€', 'Ò€'), + ('ÒŠ', 'ÒŠ'), + ('ÒŒ', 'ÒŒ'), + ('ÒŽ', 'ÒŽ'), + ('Ò', 'Ò'), + ('Ò’', 'Ò’'), + ('Ò”', 'Ò”'), + ('Ò–', 'Ò–'), + ('Ò˜', 'Ò˜'), + ('Òš', 'Òš'), + ('Òœ', 'Òœ'), + ('Òž', 'Òž'), + ('Ò ', 'Ò '), + ('Ò¢', 'Ò¢'), + ('Ò¤', 'Ò¤'), + ('Ò¦', 'Ò¦'), + ('Ò¨', 'Ò¨'), + ('Òª', 'Òª'), + ('Ò¬', 'Ò¬'), + ('Ò®', 'Ò®'), + ('Ò°', 'Ò°'), + ('Ò²', 'Ò²'), + ('Ò´', 'Ò´'), + ('Ò¶', 'Ò¶'), + ('Ò¸', 'Ò¸'), + ('Òº', 'Òº'), + ('Ò¼', 'Ò¼'), + ('Ò¾', 'Ò¾'), + ('Ó€', 'Ó'), + ('Óƒ', 'Óƒ'), + ('Ó…', 'Ó…'), + ('Ó‡', 'Ó‡'), + ('Ó‰', 'Ó‰'), + ('Ó‹', 'Ó‹'), + ('Ó', 'Ó'), + ('Ó', 'Ó'), + ('Ó’', 'Ó’'), + ('Ó”', 'Ó”'), + ('Ó–', 'Ó–'), + ('Ó˜', 'Ó˜'), + ('Óš', 'Óš'), + ('Óœ', 'Óœ'), + ('Óž', 'Óž'), + ('Ó ', 'Ó '), + ('Ó¢', 'Ó¢'), + ('Ó¤', 'Ó¤'), + ('Ó¦', 'Ó¦'), + ('Ó¨', 'Ó¨'), + ('Óª', 'Óª'), + ('Ó¬', 'Ó¬'), + ('Ó®', 'Ó®'), + ('Ó°', 'Ó°'), + ('Ó²', 'Ó²'), + ('Ó´', 'Ó´'), + ('Ó¶', 'Ó¶'), + ('Ó¸', 'Ó¸'), + ('Óº', 'Óº'), + ('Ó¼', 'Ó¼'), + ('Ó¾', 'Ó¾'), + ('Ô€', 'Ô€'), + ('Ô‚', 'Ô‚'), + ('Ô„', 'Ô„'), + ('Ô†', 'Ô†'), + ('Ôˆ', 'Ôˆ'), + ('ÔŠ', 'ÔŠ'), + ('ÔŒ', 'ÔŒ'), + ('ÔŽ', 'ÔŽ'), + ('Ô', 'Ô'), + ('Ô’', 'Ô’'), + ('Ô”', 'Ô”'), + ('Ô–', 'Ô–'), + ('Ô˜', 'Ô˜'), + ('Ôš', 'Ôš'), + ('Ôœ', 'Ôœ'), + ('Ôž', 'Ôž'), + ('Ô ', 'Ô '), + ('Ô¢', 'Ô¢'), + ('Ô¤', 'Ô¤'), + ('Ô¦', 'Ô¦'), + ('Ô¨', 'Ô¨'), + ('Ôª', 'Ôª'), + ('Ô¬', 'Ô¬'), + ('Ô®', 'Ô®'), + ('Ô±', 'Õ–'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('Ꭰ', 'áµ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('Ḁ', 'Ḁ'), + ('Ḃ', 'Ḃ'), + ('Ḅ', 'Ḅ'), + ('Ḇ', 'Ḇ'), + ('Ḉ', 'Ḉ'), + ('Ḋ', 'Ḋ'), + ('Ḍ', 'Ḍ'), + ('Ḏ', 'Ḏ'), + ('á¸', 'á¸'), + ('Ḓ', 'Ḓ'), + ('Ḕ', 'Ḕ'), + ('Ḗ', 'Ḗ'), + ('Ḙ', 'Ḙ'), + ('Ḛ', 'Ḛ'), + ('Ḝ', 'Ḝ'), + ('Ḟ', 'Ḟ'), + ('Ḡ', 'Ḡ'), + ('Ḣ', 'Ḣ'), + ('Ḥ', 'Ḥ'), + ('Ḧ', 'Ḧ'), + ('Ḩ', 'Ḩ'), + ('Ḫ', 'Ḫ'), + ('Ḭ', 'Ḭ'), + ('Ḯ', 'Ḯ'), + ('Ḱ', 'Ḱ'), + ('Ḳ', 'Ḳ'), + ('Ḵ', 'Ḵ'), + ('Ḷ', 'Ḷ'), + ('Ḹ', 'Ḹ'), + ('Ḻ', 'Ḻ'), + ('Ḽ', 'Ḽ'), + ('Ḿ', 'Ḿ'), + ('á¹€', 'á¹€'), + ('Ṃ', 'Ṃ'), + ('Ṅ', 'Ṅ'), + ('Ṇ', 'Ṇ'), + ('Ṉ', 'Ṉ'), + ('Ṋ', 'Ṋ'), + ('Ṍ', 'Ṍ'), + ('Ṏ', 'Ṏ'), + ('á¹', 'á¹'), + ('á¹’', 'á¹’'), + ('á¹”', 'á¹”'), + ('á¹–', 'á¹–'), + ('Ṙ', 'Ṙ'), + ('Ṛ', 'Ṛ'), + ('Ṝ', 'Ṝ'), + ('Ṟ', 'Ṟ'), + ('á¹ ', 'á¹ '), + ('á¹¢', 'á¹¢'), + ('Ṥ', 'Ṥ'), + ('Ṧ', 'Ṧ'), + ('Ṩ', 'Ṩ'), + ('Ṫ', 'Ṫ'), + ('Ṭ', 'Ṭ'), + ('á¹®', 'á¹®'), + ('á¹°', 'á¹°'), + ('á¹²', 'á¹²'), + ('á¹´', 'á¹´'), + ('Ṷ', 'Ṷ'), + ('Ṹ', 'Ṹ'), + ('Ṻ', 'Ṻ'), + ('á¹¼', 'á¹¼'), + ('á¹¾', 'á¹¾'), + ('Ẁ', 'Ẁ'), + ('Ẃ', 'Ẃ'), + ('Ẅ', 'Ẅ'), + ('Ẇ', 'Ẇ'), + ('Ẉ', 'Ẉ'), + ('Ẋ', 'Ẋ'), + ('Ẍ', 'Ẍ'), + ('Ẏ', 'Ẏ'), + ('áº', 'áº'), + ('Ẓ', 'Ẓ'), + ('Ẕ', 'Ẕ'), + ('ẞ', 'ẞ'), + ('Ạ', 'Ạ'), + ('Ả', 'Ả'), + ('Ấ', 'Ấ'), + ('Ầ', 'Ầ'), + ('Ẩ', 'Ẩ'), + ('Ẫ', 'Ẫ'), + ('Ậ', 'Ậ'), + ('Ắ', 'Ắ'), + ('Ằ', 'Ằ'), + ('Ẳ', 'Ẳ'), + ('Ẵ', 'Ẵ'), + ('Ặ', 'Ặ'), + ('Ẹ', 'Ẹ'), + ('Ẻ', 'Ẻ'), + ('Ẽ', 'Ẽ'), + ('Ế', 'Ế'), + ('Ề', 'Ề'), + ('Ể', 'Ể'), + ('Ễ', 'Ễ'), + ('Ệ', 'Ệ'), + ('Ỉ', 'Ỉ'), + ('Ị', 'Ị'), + ('Ọ', 'Ọ'), + ('Ỏ', 'Ỏ'), + ('á»', 'á»'), + ('á»’', 'á»’'), + ('á»”', 'á»”'), + ('á»–', 'á»–'), + ('Ộ', 'Ộ'), + ('Ớ', 'Ớ'), + ('Ờ', 'Ờ'), + ('Ở', 'Ở'), + ('á» ', 'á» '), + ('Ợ', 'Ợ'), + ('Ụ', 'Ụ'), + ('Ủ', 'Ủ'), + ('Ứ', 'Ứ'), + ('Ừ', 'Ừ'), + ('Ử', 'Ử'), + ('á»®', 'á»®'), + ('á»°', 'á»°'), + ('Ỳ', 'Ỳ'), + ('á»´', 'á»´'), + ('Ỷ', 'Ỷ'), + ('Ỹ', 'Ỹ'), + ('Ỻ', 'Ỻ'), + ('Ỽ', 'Ỽ'), + ('Ỿ', 'Ỿ'), + ('Ἀ', 'á¼'), + ('Ἐ', 'á¼'), + ('Ἠ', 'Ἧ'), + ('Ἰ', 'Ἷ'), + ('Ὀ', 'á½'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'Ὗ'), + ('Ὠ', 'Ὧ'), + ('ᾈ', 'á¾'), + ('ᾘ', 'ᾟ'), + ('ᾨ', 'ᾯ'), + ('Ᾰ', 'á¾¼'), + ('Ὲ', 'á¿Œ'), + ('Ῐ', 'á¿›'), + ('Ῠ', 'Ῥ'), + ('Ὸ', 'ῼ'), + ('Ω', 'Ω'), + ('K', 'â„«'), + ('Ⅎ', 'Ⅎ'), + ('â… ', 'â…¯'), + ('Ↄ', 'Ↄ'), + ('â’¶', 'â“'), + ('â°€', 'â°¯'), + ('â± ', 'â± '), + ('â±¢', 'Ɽ'), + ('Ⱨ', 'Ⱨ'), + ('Ⱪ', 'Ⱪ'), + ('Ⱬ', 'Ⱬ'), + ('â±­', 'â±°'), + ('â±²', 'â±²'), + ('â±µ', 'â±µ'), + ('â±¾', 'â²€'), + ('Ⲃ', 'Ⲃ'), + ('Ⲅ', 'Ⲅ'), + ('Ⲇ', 'Ⲇ'), + ('Ⲉ', 'Ⲉ'), + ('Ⲋ', 'Ⲋ'), + ('Ⲍ', 'Ⲍ'), + ('Ⲏ', 'Ⲏ'), + ('â²', 'â²'), + ('â²’', 'â²’'), + ('â²”', 'â²”'), + ('â²–', 'â²–'), + ('Ⲙ', 'Ⲙ'), + ('Ⲛ', 'Ⲛ'), + ('Ⲝ', 'Ⲝ'), + ('Ⲟ', 'Ⲟ'), + ('â² ', 'â² '), + ('â²¢', 'â²¢'), + ('Ⲥ', 'Ⲥ'), + ('Ⲧ', 'Ⲧ'), + ('Ⲩ', 'Ⲩ'), + ('Ⲫ', 'Ⲫ'), + ('Ⲭ', 'Ⲭ'), + ('â²®', 'â²®'), + ('â²°', 'â²°'), + ('â²²', 'â²²'), + ('â²´', 'â²´'), + ('Ⲷ', 'Ⲷ'), + ('Ⲹ', 'Ⲹ'), + ('Ⲻ', 'Ⲻ'), + ('â²¼', 'â²¼'), + ('â²¾', 'â²¾'), + ('â³€', 'â³€'), + ('Ⳃ', 'Ⳃ'), + ('Ⳅ', 'Ⳅ'), + ('Ⳇ', 'Ⳇ'), + ('Ⳉ', 'Ⳉ'), + ('Ⳋ', 'Ⳋ'), + ('Ⳍ', 'Ⳍ'), + ('Ⳏ', 'Ⳏ'), + ('â³', 'â³'), + ('â³’', 'â³’'), + ('â³”', 'â³”'), + ('â³–', 'â³–'), + ('Ⳙ', 'Ⳙ'), + ('Ⳛ', 'Ⳛ'), + ('Ⳝ', 'Ⳝ'), + ('Ⳟ', 'Ⳟ'), + ('â³ ', 'â³ '), + ('â³¢', 'â³¢'), + ('Ⳬ', 'Ⳬ'), + ('â³­', 'â³­'), + ('â³²', 'â³²'), + ('Ꙁ', 'Ꙁ'), + ('Ꙃ', 'Ꙃ'), + ('Ꙅ', 'Ꙅ'), + ('Ꙇ', 'Ꙇ'), + ('Ꙉ', 'Ꙉ'), + ('Ꙋ', 'Ꙋ'), + ('Ꙍ', 'Ꙍ'), + ('Ꙏ', 'Ꙏ'), + ('ê™', 'ê™'), + ('ê™’', 'ê™’'), + ('ê™”', 'ê™”'), + ('ê™–', 'ê™–'), + ('Ꙙ', 'Ꙙ'), + ('Ꙛ', 'Ꙛ'), + ('Ꙝ', 'Ꙝ'), + ('Ꙟ', 'Ꙟ'), + ('ê™ ', 'ê™ '), + ('Ꙣ', 'Ꙣ'), + ('Ꙥ', 'Ꙥ'), + ('Ꙧ', 'Ꙧ'), + ('Ꙩ', 'Ꙩ'), + ('Ꙫ', 'Ꙫ'), + ('Ꙭ', 'Ꙭ'), + ('Ꚁ', 'Ꚁ'), + ('êš‚', 'êš‚'), + ('êš„', 'êš„'), + ('Ꚇ', 'Ꚇ'), + ('Ꚉ', 'Ꚉ'), + ('Ꚋ', 'Ꚋ'), + ('Ꚍ', 'Ꚍ'), + ('Ꚏ', 'Ꚏ'), + ('êš', 'êš'), + ('êš’', 'êš’'), + ('êš”', 'êš”'), + ('êš–', 'êš–'), + ('Ꚙ', 'Ꚙ'), + ('êšš', 'êšš'), + ('Ꜣ', 'Ꜣ'), + ('Ꜥ', 'Ꜥ'), + ('Ꜧ', 'Ꜧ'), + ('Ꜩ', 'Ꜩ'), + ('Ꜫ', 'Ꜫ'), + ('Ꜭ', 'Ꜭ'), + ('Ꜯ', 'Ꜯ'), + ('Ꜳ', 'Ꜳ'), + ('Ꜵ', 'Ꜵ'), + ('Ꜷ', 'Ꜷ'), + ('Ꜹ', 'Ꜹ'), + ('Ꜻ', 'Ꜻ'), + ('Ꜽ', 'Ꜽ'), + ('Ꜿ', 'Ꜿ'), + ('ê€', 'ê€'), + ('ê‚', 'ê‚'), + ('ê„', 'ê„'), + ('ê†', 'ê†'), + ('êˆ', 'êˆ'), + ('êŠ', 'êŠ'), + ('êŒ', 'êŒ'), + ('êŽ', 'êŽ'), + ('ê', 'ê'), + ('ê’', 'ê’'), + ('ê”', 'ê”'), + ('ê–', 'ê–'), + ('ê˜', 'ê˜'), + ('êš', 'êš'), + ('êœ', 'êœ'), + ('êž', 'êž'), + ('ê ', 'ê '), + ('ê¢', 'ê¢'), + ('ê¤', 'ê¤'), + ('ê¦', 'ê¦'), + ('ê¨', 'ê¨'), + ('êª', 'êª'), + ('ê¬', 'ê¬'), + ('ê®', 'ê®'), + ('ê¹', 'ê¹'), + ('ê»', 'ê»'), + ('ê½', 'ê¾'), + ('Ꞁ', 'Ꞁ'), + ('êž‚', 'êž‚'), + ('êž„', 'êž„'), + ('Ꞇ', 'Ꞇ'), + ('êž‹', 'êž‹'), + ('êž', 'êž'), + ('êž', 'êž'), + ('êž’', 'êž’'), + ('êž–', 'êž–'), + ('Ꞙ', 'Ꞙ'), + ('êžš', 'êžš'), + ('êžœ', 'êžœ'), + ('êžž', 'êžž'), + ('êž ', 'êž '), + ('Ꞣ', 'Ꞣ'), + ('Ꞥ', 'Ꞥ'), + ('Ꞧ', 'Ꞧ'), + ('Ꞩ', 'Ꞩ'), + ('Ɦ', 'êž®'), + ('êž°', 'êž´'), + ('Ꞷ', 'Ꞷ'), + ('Ꞹ', 'Ꞹ'), + ('Ꞻ', 'Ꞻ'), + ('êž¼', 'êž¼'), + ('êž¾', 'êž¾'), + ('Ꟁ', 'Ꟁ'), + ('Ꟃ', 'Ꟃ'), + ('Ꞔ', 'Ꟈ'), + ('Ꟊ', 'Ꟊ'), + ('êŸ', 'êŸ'), + ('Ꟗ', 'Ꟗ'), + ('Ꟙ', 'Ꟙ'), + ('Ꟶ', 'Ꟶ'), + ('A', 'Z'), + ('ð€', 'ð§'), + ('ð’°', 'ð““'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð²€', 'ð²²'), + ('ð‘¢ ', '𑢿'), + ('ð–¹€', '𖹟'), + ('𞤀', '𞤡'), +]; + +pub const CHANGES_WHEN_TITLECASED: &'static [(char, char)] = &[ + ('a', 'z'), + ('µ', 'µ'), + ('ß', 'ö'), + ('ø', 'ÿ'), + ('Ä', 'Ä'), + ('ă', 'ă'), + ('Ä…', 'Ä…'), + ('ć', 'ć'), + ('ĉ', 'ĉ'), + ('Ä‹', 'Ä‹'), + ('Ä', 'Ä'), + ('Ä', 'Ä'), + ('Ä‘', 'Ä‘'), + ('Ä“', 'Ä“'), + ('Ä•', 'Ä•'), + ('Ä—', 'Ä—'), + ('Ä™', 'Ä™'), + ('Ä›', 'Ä›'), + ('Ä', 'Ä'), + ('ÄŸ', 'ÄŸ'), + ('Ä¡', 'Ä¡'), + ('Ä£', 'Ä£'), + ('Ä¥', 'Ä¥'), + ('ħ', 'ħ'), + ('Ä©', 'Ä©'), + ('Ä«', 'Ä«'), + ('Ä­', 'Ä­'), + ('į', 'į'), + ('ı', 'ı'), + ('ij', 'ij'), + ('ĵ', 'ĵ'), + ('Ä·', 'Ä·'), + ('ĺ', 'ĺ'), + ('ļ', 'ļ'), + ('ľ', 'ľ'), + ('Å€', 'Å€'), + ('Å‚', 'Å‚'), + ('Å„', 'Å„'), + ('ņ', 'ņ'), + ('ň', 'ʼn'), + ('Å‹', 'Å‹'), + ('Å', 'Å'), + ('Å', 'Å'), + ('Å‘', 'Å‘'), + ('Å“', 'Å“'), + ('Å•', 'Å•'), + ('Å—', 'Å—'), + ('Å™', 'Å™'), + ('Å›', 'Å›'), + ('Å', 'Å'), + ('ÅŸ', 'ÅŸ'), + ('Å¡', 'Å¡'), + ('Å£', 'Å£'), + ('Å¥', 'Å¥'), + ('ŧ', 'ŧ'), + ('Å©', 'Å©'), + ('Å«', 'Å«'), + ('Å­', 'Å­'), + ('ů', 'ů'), + ('ű', 'ű'), + ('ų', 'ų'), + ('ŵ', 'ŵ'), + ('Å·', 'Å·'), + ('ź', 'ź'), + ('ż', 'ż'), + ('ž', 'Æ€'), + ('ƃ', 'ƃ'), + ('Æ…', 'Æ…'), + ('ƈ', 'ƈ'), + ('ÆŒ', 'ÆŒ'), + ('Æ’', 'Æ’'), + ('Æ•', 'Æ•'), + ('Æ™', 'Æš'), + ('Æž', 'Æž'), + ('Æ¡', 'Æ¡'), + ('Æ£', 'Æ£'), + ('Æ¥', 'Æ¥'), + ('ƨ', 'ƨ'), + ('Æ­', 'Æ­'), + ('Æ°', 'Æ°'), + ('Æ´', 'Æ´'), + ('ƶ', 'ƶ'), + ('ƹ', 'ƹ'), + ('ƽ', 'ƽ'), + ('Æ¿', 'Æ¿'), + ('Ç„', 'Ç„'), + ('dž', 'LJ'), + ('lj', 'ÇŠ'), + ('ÇŒ', 'ÇŒ'), + ('ÇŽ', 'ÇŽ'), + ('Ç', 'Ç'), + ('Ç’', 'Ç’'), + ('Ç”', 'Ç”'), + ('Ç–', 'Ç–'), + ('ǘ', 'ǘ'), + ('Çš', 'Çš'), + ('Çœ', 'Ç'), + ('ÇŸ', 'ÇŸ'), + ('Ç¡', 'Ç¡'), + ('Ç£', 'Ç£'), + ('Ç¥', 'Ç¥'), + ('ǧ', 'ǧ'), + ('Ç©', 'Ç©'), + ('Ç«', 'Ç«'), + ('Ç­', 'Ç­'), + ('ǯ', 'DZ'), + ('dz', 'dz'), + ('ǵ', 'ǵ'), + ('ǹ', 'ǹ'), + ('Ç»', 'Ç»'), + ('ǽ', 'ǽ'), + ('Ç¿', 'Ç¿'), + ('È', 'È'), + ('ȃ', 'ȃ'), + ('È…', 'È…'), + ('ȇ', 'ȇ'), + ('ȉ', 'ȉ'), + ('È‹', 'È‹'), + ('È', 'È'), + ('È', 'È'), + ('È‘', 'È‘'), + ('È“', 'È“'), + ('È•', 'È•'), + ('È—', 'È—'), + ('È™', 'È™'), + ('È›', 'È›'), + ('È', 'È'), + ('ÈŸ', 'ÈŸ'), + ('È£', 'È£'), + ('È¥', 'È¥'), + ('ȧ', 'ȧ'), + ('È©', 'È©'), + ('È«', 'È«'), + ('È­', 'È­'), + ('ȯ', 'ȯ'), + ('ȱ', 'ȱ'), + ('ȳ', 'ȳ'), + ('ȼ', 'ȼ'), + ('È¿', 'É€'), + ('É‚', 'É‚'), + ('ɇ', 'ɇ'), + ('ɉ', 'ɉ'), + ('É‹', 'É‹'), + ('É', 'É'), + ('É', 'É”'), + ('É–', 'É—'), + ('É™', 'É™'), + ('É›', 'Éœ'), + ('É ', 'É¡'), + ('É£', 'É£'), + ('É¥', 'ɦ'), + ('ɨ', 'ɬ'), + ('ɯ', 'ɯ'), + ('ɱ', 'ɲ'), + ('ɵ', 'ɵ'), + ('ɽ', 'ɽ'), + ('Ê€', 'Ê€'), + ('Ê‚', 'ʃ'), + ('ʇ', 'ÊŒ'), + ('Ê’', 'Ê’'), + ('Ê', 'Êž'), + ('\u{345}', '\u{345}'), + ('ͱ', 'ͱ'), + ('ͳ', 'ͳ'), + ('Í·', 'Í·'), + ('Í»', 'ͽ'), + ('Î', 'Î'), + ('ά', 'ÏŽ'), + ('Ï', 'Ï‘'), + ('Ï•', 'Ï—'), + ('Ï™', 'Ï™'), + ('Ï›', 'Ï›'), + ('Ï', 'Ï'), + ('ÏŸ', 'ÏŸ'), + ('Ï¡', 'Ï¡'), + ('Ï£', 'Ï£'), + ('Ï¥', 'Ï¥'), + ('ϧ', 'ϧ'), + ('Ï©', 'Ï©'), + ('Ï«', 'Ï«'), + ('Ï­', 'Ï­'), + ('ϯ', 'ϳ'), + ('ϵ', 'ϵ'), + ('ϸ', 'ϸ'), + ('Ï»', 'Ï»'), + ('а', 'ÑŸ'), + ('Ñ¡', 'Ñ¡'), + ('Ñ£', 'Ñ£'), + ('Ñ¥', 'Ñ¥'), + ('ѧ', 'ѧ'), + ('Ñ©', 'Ñ©'), + ('Ñ«', 'Ñ«'), + ('Ñ­', 'Ñ­'), + ('ѯ', 'ѯ'), + ('ѱ', 'ѱ'), + ('ѳ', 'ѳ'), + ('ѵ', 'ѵ'), + ('Ñ·', 'Ñ·'), + ('ѹ', 'ѹ'), + ('Ñ»', 'Ñ»'), + ('ѽ', 'ѽ'), + ('Ñ¿', 'Ñ¿'), + ('Ò', 'Ò'), + ('Ò‹', 'Ò‹'), + ('Ò', 'Ò'), + ('Ò', 'Ò'), + ('Ò‘', 'Ò‘'), + ('Ò“', 'Ò“'), + ('Ò•', 'Ò•'), + ('Ò—', 'Ò—'), + ('Ò™', 'Ò™'), + ('Ò›', 'Ò›'), + ('Ò', 'Ò'), + ('ÒŸ', 'ÒŸ'), + ('Ò¡', 'Ò¡'), + ('Ò£', 'Ò£'), + ('Ò¥', 'Ò¥'), + ('Ò§', 'Ò§'), + ('Ò©', 'Ò©'), + ('Ò«', 'Ò«'), + ('Ò­', 'Ò­'), + ('Ò¯', 'Ò¯'), + ('Ò±', 'Ò±'), + ('Ò³', 'Ò³'), + ('Òµ', 'Òµ'), + ('Ò·', 'Ò·'), + ('Ò¹', 'Ò¹'), + ('Ò»', 'Ò»'), + ('Ò½', 'Ò½'), + ('Ò¿', 'Ò¿'), + ('Ó‚', 'Ó‚'), + ('Ó„', 'Ó„'), + ('Ó†', 'Ó†'), + ('Óˆ', 'Óˆ'), + ('ÓŠ', 'ÓŠ'), + ('ÓŒ', 'ÓŒ'), + ('ÓŽ', 'Ó'), + ('Ó‘', 'Ó‘'), + ('Ó“', 'Ó“'), + ('Ó•', 'Ó•'), + ('Ó—', 'Ó—'), + ('Ó™', 'Ó™'), + ('Ó›', 'Ó›'), + ('Ó', 'Ó'), + ('ÓŸ', 'ÓŸ'), + ('Ó¡', 'Ó¡'), + ('Ó£', 'Ó£'), + ('Ó¥', 'Ó¥'), + ('Ó§', 'Ó§'), + ('Ó©', 'Ó©'), + ('Ó«', 'Ó«'), + ('Ó­', 'Ó­'), + ('Ó¯', 'Ó¯'), + ('Ó±', 'Ó±'), + ('Ó³', 'Ó³'), + ('Óµ', 'Óµ'), + ('Ó·', 'Ó·'), + ('Ó¹', 'Ó¹'), + ('Ó»', 'Ó»'), + ('Ó½', 'Ó½'), + ('Ó¿', 'Ó¿'), + ('Ô', 'Ô'), + ('Ôƒ', 'Ôƒ'), + ('Ô…', 'Ô…'), + ('Ô‡', 'Ô‡'), + ('Ô‰', 'Ô‰'), + ('Ô‹', 'Ô‹'), + ('Ô', 'Ô'), + ('Ô', 'Ô'), + ('Ô‘', 'Ô‘'), + ('Ô“', 'Ô“'), + ('Ô•', 'Ô•'), + ('Ô—', 'Ô—'), + ('Ô™', 'Ô™'), + ('Ô›', 'Ô›'), + ('Ô', 'Ô'), + ('ÔŸ', 'ÔŸ'), + ('Ô¡', 'Ô¡'), + ('Ô£', 'Ô£'), + ('Ô¥', 'Ô¥'), + ('Ô§', 'Ô§'), + ('Ô©', 'Ô©'), + ('Ô«', 'Ô«'), + ('Ô­', 'Ô­'), + ('Ô¯', 'Ô¯'), + ('Õ¡', 'Ö‡'), + ('á¸', 'á½'), + ('á²€', 'ᲈ'), + ('áµ¹', 'áµ¹'), + ('áµ½', 'áµ½'), + ('ᶎ', 'ᶎ'), + ('á¸', 'á¸'), + ('ḃ', 'ḃ'), + ('ḅ', 'ḅ'), + ('ḇ', 'ḇ'), + ('ḉ', 'ḉ'), + ('ḋ', 'ḋ'), + ('á¸', 'á¸'), + ('á¸', 'á¸'), + ('ḑ', 'ḑ'), + ('ḓ', 'ḓ'), + ('ḕ', 'ḕ'), + ('ḗ', 'ḗ'), + ('ḙ', 'ḙ'), + ('ḛ', 'ḛ'), + ('á¸', 'á¸'), + ('ḟ', 'ḟ'), + ('ḡ', 'ḡ'), + ('ḣ', 'ḣ'), + ('ḥ', 'ḥ'), + ('ḧ', 'ḧ'), + ('ḩ', 'ḩ'), + ('ḫ', 'ḫ'), + ('ḭ', 'ḭ'), + ('ḯ', 'ḯ'), + ('ḱ', 'ḱ'), + ('ḳ', 'ḳ'), + ('ḵ', 'ḵ'), + ('ḷ', 'ḷ'), + ('ḹ', 'ḹ'), + ('ḻ', 'ḻ'), + ('ḽ', 'ḽ'), + ('ḿ', 'ḿ'), + ('á¹', 'á¹'), + ('ṃ', 'ṃ'), + ('á¹…', 'á¹…'), + ('ṇ', 'ṇ'), + ('ṉ', 'ṉ'), + ('ṋ', 'ṋ'), + ('á¹', 'á¹'), + ('á¹', 'á¹'), + ('ṑ', 'ṑ'), + ('ṓ', 'ṓ'), + ('ṕ', 'ṕ'), + ('á¹—', 'á¹—'), + ('á¹™', 'á¹™'), + ('á¹›', 'á¹›'), + ('á¹', 'á¹'), + ('ṟ', 'ṟ'), + ('ṡ', 'ṡ'), + ('á¹£', 'á¹£'), + ('á¹¥', 'á¹¥'), + ('ṧ', 'ṧ'), + ('ṩ', 'ṩ'), + ('ṫ', 'ṫ'), + ('á¹­', 'á¹­'), + ('ṯ', 'ṯ'), + ('á¹±', 'á¹±'), + ('á¹³', 'á¹³'), + ('á¹µ', 'á¹µ'), + ('á¹·', 'á¹·'), + ('á¹¹', 'á¹¹'), + ('á¹»', 'á¹»'), + ('á¹½', 'á¹½'), + ('ṿ', 'ṿ'), + ('áº', 'áº'), + ('ẃ', 'ẃ'), + ('ẅ', 'ẅ'), + ('ẇ', 'ẇ'), + ('ẉ', 'ẉ'), + ('ẋ', 'ẋ'), + ('áº', 'áº'), + ('áº', 'áº'), + ('ẑ', 'ẑ'), + ('ẓ', 'ẓ'), + ('ẕ', 'ẛ'), + ('ạ', 'ạ'), + ('ả', 'ả'), + ('ấ', 'ấ'), + ('ầ', 'ầ'), + ('ẩ', 'ẩ'), + ('ẫ', 'ẫ'), + ('ậ', 'ậ'), + ('ắ', 'ắ'), + ('ằ', 'ằ'), + ('ẳ', 'ẳ'), + ('ẵ', 'ẵ'), + ('ặ', 'ặ'), + ('ẹ', 'ẹ'), + ('ẻ', 'ẻ'), + ('ẽ', 'ẽ'), + ('ế', 'ế'), + ('á»', 'á»'), + ('ể', 'ể'), + ('á»…', 'á»…'), + ('ệ', 'ệ'), + ('ỉ', 'ỉ'), + ('ị', 'ị'), + ('á»', 'á»'), + ('á»', 'á»'), + ('ố', 'ố'), + ('ồ', 'ồ'), + ('ổ', 'ổ'), + ('á»—', 'á»—'), + ('á»™', 'á»™'), + ('á»›', 'á»›'), + ('á»', 'á»'), + ('ở', 'ở'), + ('ỡ', 'ỡ'), + ('ợ', 'ợ'), + ('ụ', 'ụ'), + ('ủ', 'ủ'), + ('ứ', 'ứ'), + ('ừ', 'ừ'), + ('á»­', 'á»­'), + ('ữ', 'ữ'), + ('á»±', 'á»±'), + ('ỳ', 'ỳ'), + ('ỵ', 'ỵ'), + ('á»·', 'á»·'), + ('ỹ', 'ỹ'), + ('á»»', 'á»»'), + ('ỽ', 'ỽ'), + ('ỿ', 'ἇ'), + ('á¼', 'ἕ'), + ('á¼ ', 'ἧ'), + ('á¼°', 'á¼·'), + ('á½€', 'á½…'), + ('á½', 'á½—'), + ('á½ ', 'ὧ'), + ('á½°', 'á½½'), + ('á¾€', 'ᾇ'), + ('á¾', 'á¾—'), + ('á¾ ', 'ᾧ'), + ('á¾°', 'á¾´'), + ('ᾶ', 'á¾·'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'ῇ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿—'), + ('á¿ ', 'ῧ'), + ('ῲ', 'á¿´'), + ('ῶ', 'á¿·'), + ('â…Ž', 'â…Ž'), + ('â…°', 'â…¿'), + ('ↄ', 'ↄ'), + ('â“', 'â“©'), + ('â°°', 'ⱟ'), + ('ⱡ', 'ⱡ'), + ('â±¥', 'ⱦ'), + ('ⱨ', 'ⱨ'), + ('ⱪ', 'ⱪ'), + ('ⱬ', 'ⱬ'), + ('â±³', 'â±³'), + ('ⱶ', 'ⱶ'), + ('â²', 'â²'), + ('ⲃ', 'ⲃ'), + ('â²…', 'â²…'), + ('ⲇ', 'ⲇ'), + ('ⲉ', 'ⲉ'), + ('ⲋ', 'ⲋ'), + ('â²', 'â²'), + ('â²', 'â²'), + ('ⲑ', 'ⲑ'), + ('ⲓ', 'ⲓ'), + ('ⲕ', 'ⲕ'), + ('â²—', 'â²—'), + ('â²™', 'â²™'), + ('â²›', 'â²›'), + ('â²', 'â²'), + ('ⲟ', 'ⲟ'), + ('ⲡ', 'ⲡ'), + ('â²£', 'â²£'), + ('â²¥', 'â²¥'), + ('ⲧ', 'ⲧ'), + ('ⲩ', 'ⲩ'), + ('ⲫ', 'ⲫ'), + ('â²­', 'â²­'), + ('ⲯ', 'ⲯ'), + ('â²±', 'â²±'), + ('â²³', 'â²³'), + ('â²µ', 'â²µ'), + ('â²·', 'â²·'), + ('â²¹', 'â²¹'), + ('â²»', 'â²»'), + ('â²½', 'â²½'), + ('ⲿ', 'ⲿ'), + ('â³', 'â³'), + ('ⳃ', 'ⳃ'), + ('â³…', 'â³…'), + ('ⳇ', 'ⳇ'), + ('ⳉ', 'ⳉ'), + ('ⳋ', 'ⳋ'), + ('â³', 'â³'), + ('â³', 'â³'), + ('ⳑ', 'ⳑ'), + ('ⳓ', 'ⳓ'), + ('ⳕ', 'ⳕ'), + ('â³—', 'â³—'), + ('â³™', 'â³™'), + ('â³›', 'â³›'), + ('â³', 'â³'), + ('ⳟ', 'ⳟ'), + ('ⳡ', 'ⳡ'), + ('â³£', 'â³£'), + ('ⳬ', 'ⳬ'), + ('â³®', 'â³®'), + ('â³³', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('ê™', 'ê™'), + ('ꙃ', 'ꙃ'), + ('ê™…', 'ê™…'), + ('ꙇ', 'ꙇ'), + ('ꙉ', 'ꙉ'), + ('ꙋ', 'ꙋ'), + ('ê™', 'ê™'), + ('ê™', 'ê™'), + ('ꙑ', 'ꙑ'), + ('ꙓ', 'ꙓ'), + ('ꙕ', 'ꙕ'), + ('ê™—', 'ê™—'), + ('ê™™', 'ê™™'), + ('ê™›', 'ê™›'), + ('ê™', 'ê™'), + ('ꙟ', 'ꙟ'), + ('ꙡ', 'ꙡ'), + ('ꙣ', 'ꙣ'), + ('ꙥ', 'ꙥ'), + ('ꙧ', 'ꙧ'), + ('ꙩ', 'ꙩ'), + ('ꙫ', 'ꙫ'), + ('ê™­', 'ê™­'), + ('êš', 'êš'), + ('ꚃ', 'ꚃ'), + ('êš…', 'êš…'), + ('ꚇ', 'ꚇ'), + ('ꚉ', 'ꚉ'), + ('êš‹', 'êš‹'), + ('êš', 'êš'), + ('êš', 'êš'), + ('êš‘', 'êš‘'), + ('êš“', 'êš“'), + ('êš•', 'êš•'), + ('êš—', 'êš—'), + ('êš™', 'êš™'), + ('êš›', 'êš›'), + ('ꜣ', 'ꜣ'), + ('ꜥ', 'ꜥ'), + ('ꜧ', 'ꜧ'), + ('ꜩ', 'ꜩ'), + ('ꜫ', 'ꜫ'), + ('ꜭ', 'ꜭ'), + ('ꜯ', 'ꜯ'), + ('ꜳ', 'ꜳ'), + ('ꜵ', 'ꜵ'), + ('ꜷ', 'ꜷ'), + ('ꜹ', 'ꜹ'), + ('ꜻ', 'ꜻ'), + ('ꜽ', 'ꜽ'), + ('ꜿ', 'ꜿ'), + ('ê', 'ê'), + ('êƒ', 'êƒ'), + ('ê…', 'ê…'), + ('ê‡', 'ê‡'), + ('ê‰', 'ê‰'), + ('ê‹', 'ê‹'), + ('ê', 'ê'), + ('ê', 'ê'), + ('ê‘', 'ê‘'), + ('ê“', 'ê“'), + ('ê•', 'ê•'), + ('ê—', 'ê—'), + ('ê™', 'ê™'), + ('ê›', 'ê›'), + ('ê', 'ê'), + ('êŸ', 'êŸ'), + ('ê¡', 'ê¡'), + ('ê£', 'ê£'), + ('ê¥', 'ê¥'), + ('ê§', 'ê§'), + ('ê©', 'ê©'), + ('ê«', 'ê«'), + ('ê­', 'ê­'), + ('ê¯', 'ê¯'), + ('êº', 'êº'), + ('ê¼', 'ê¼'), + ('ê¿', 'ê¿'), + ('êž', 'êž'), + ('ꞃ', 'ꞃ'), + ('êž…', 'êž…'), + ('ꞇ', 'ꞇ'), + ('ꞌ', 'ꞌ'), + ('êž‘', 'êž‘'), + ('êž“', 'êž”'), + ('êž—', 'êž—'), + ('êž™', 'êž™'), + ('êž›', 'êž›'), + ('êž', 'êž'), + ('ꞟ', 'ꞟ'), + ('êž¡', 'êž¡'), + ('ꞣ', 'ꞣ'), + ('ꞥ', 'ꞥ'), + ('ꞧ', 'ꞧ'), + ('êž©', 'êž©'), + ('êžµ', 'êžµ'), + ('êž·', 'êž·'), + ('êž¹', 'êž¹'), + ('êž»', 'êž»'), + ('êž½', 'êž½'), + ('êž¿', 'êž¿'), + ('êŸ', 'êŸ'), + ('ꟃ', 'ꟃ'), + ('ꟈ', 'ꟈ'), + ('ꟊ', 'ꟊ'), + ('ꟑ', 'ꟑ'), + ('ꟗ', 'ꟗ'), + ('ꟙ', 'ꟙ'), + ('ꟶ', 'ꟶ'), + ('ê­“', 'ê­“'), + ('ê­°', 'ꮿ'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï½', 'z'), + ('ð¨', 'ð‘'), + ('ð“˜', 'ð“»'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð³€', 'ð³²'), + ('ð‘£€', '𑣟'), + ('ð–¹ ', '𖹿'), + ('𞤢', '𞥃'), +]; + +pub const CHANGES_WHEN_UPPERCASED: &'static [(char, char)] = &[ + ('a', 'z'), + ('µ', 'µ'), + ('ß', 'ö'), + ('ø', 'ÿ'), + ('Ä', 'Ä'), + ('ă', 'ă'), + ('Ä…', 'Ä…'), + ('ć', 'ć'), + ('ĉ', 'ĉ'), + ('Ä‹', 'Ä‹'), + ('Ä', 'Ä'), + ('Ä', 'Ä'), + ('Ä‘', 'Ä‘'), + ('Ä“', 'Ä“'), + ('Ä•', 'Ä•'), + ('Ä—', 'Ä—'), + ('Ä™', 'Ä™'), + ('Ä›', 'Ä›'), + ('Ä', 'Ä'), + ('ÄŸ', 'ÄŸ'), + ('Ä¡', 'Ä¡'), + ('Ä£', 'Ä£'), + ('Ä¥', 'Ä¥'), + ('ħ', 'ħ'), + ('Ä©', 'Ä©'), + ('Ä«', 'Ä«'), + ('Ä­', 'Ä­'), + ('į', 'į'), + ('ı', 'ı'), + ('ij', 'ij'), + ('ĵ', 'ĵ'), + ('Ä·', 'Ä·'), + ('ĺ', 'ĺ'), + ('ļ', 'ļ'), + ('ľ', 'ľ'), + ('Å€', 'Å€'), + ('Å‚', 'Å‚'), + ('Å„', 'Å„'), + ('ņ', 'ņ'), + ('ň', 'ʼn'), + ('Å‹', 'Å‹'), + ('Å', 'Å'), + ('Å', 'Å'), + ('Å‘', 'Å‘'), + ('Å“', 'Å“'), + ('Å•', 'Å•'), + ('Å—', 'Å—'), + ('Å™', 'Å™'), + ('Å›', 'Å›'), + ('Å', 'Å'), + ('ÅŸ', 'ÅŸ'), + ('Å¡', 'Å¡'), + ('Å£', 'Å£'), + ('Å¥', 'Å¥'), + ('ŧ', 'ŧ'), + ('Å©', 'Å©'), + ('Å«', 'Å«'), + ('Å­', 'Å­'), + ('ů', 'ů'), + ('ű', 'ű'), + ('ų', 'ų'), + ('ŵ', 'ŵ'), + ('Å·', 'Å·'), + ('ź', 'ź'), + ('ż', 'ż'), + ('ž', 'Æ€'), + ('ƃ', 'ƃ'), + ('Æ…', 'Æ…'), + ('ƈ', 'ƈ'), + ('ÆŒ', 'ÆŒ'), + ('Æ’', 'Æ’'), + ('Æ•', 'Æ•'), + ('Æ™', 'Æš'), + ('Æž', 'Æž'), + ('Æ¡', 'Æ¡'), + ('Æ£', 'Æ£'), + ('Æ¥', 'Æ¥'), + ('ƨ', 'ƨ'), + ('Æ­', 'Æ­'), + ('Æ°', 'Æ°'), + ('Æ´', 'Æ´'), + ('ƶ', 'ƶ'), + ('ƹ', 'ƹ'), + ('ƽ', 'ƽ'), + ('Æ¿', 'Æ¿'), + ('Ç…', 'dž'), + ('Lj', 'lj'), + ('Ç‹', 'ÇŒ'), + ('ÇŽ', 'ÇŽ'), + ('Ç', 'Ç'), + ('Ç’', 'Ç’'), + ('Ç”', 'Ç”'), + ('Ç–', 'Ç–'), + ('ǘ', 'ǘ'), + ('Çš', 'Çš'), + ('Çœ', 'Ç'), + ('ÇŸ', 'ÇŸ'), + ('Ç¡', 'Ç¡'), + ('Ç£', 'Ç£'), + ('Ç¥', 'Ç¥'), + ('ǧ', 'ǧ'), + ('Ç©', 'Ç©'), + ('Ç«', 'Ç«'), + ('Ç­', 'Ç­'), + ('ǯ', 'Ç°'), + ('Dz', 'dz'), + ('ǵ', 'ǵ'), + ('ǹ', 'ǹ'), + ('Ç»', 'Ç»'), + ('ǽ', 'ǽ'), + ('Ç¿', 'Ç¿'), + ('È', 'È'), + ('ȃ', 'ȃ'), + ('È…', 'È…'), + ('ȇ', 'ȇ'), + ('ȉ', 'ȉ'), + ('È‹', 'È‹'), + ('È', 'È'), + ('È', 'È'), + ('È‘', 'È‘'), + ('È“', 'È“'), + ('È•', 'È•'), + ('È—', 'È—'), + ('È™', 'È™'), + ('È›', 'È›'), + ('È', 'È'), + ('ÈŸ', 'ÈŸ'), + ('È£', 'È£'), + ('È¥', 'È¥'), + ('ȧ', 'ȧ'), + ('È©', 'È©'), + ('È«', 'È«'), + ('È­', 'È­'), + ('ȯ', 'ȯ'), + ('ȱ', 'ȱ'), + ('ȳ', 'ȳ'), + ('ȼ', 'ȼ'), + ('È¿', 'É€'), + ('É‚', 'É‚'), + ('ɇ', 'ɇ'), + ('ɉ', 'ɉ'), + ('É‹', 'É‹'), + ('É', 'É'), + ('É', 'É”'), + ('É–', 'É—'), + ('É™', 'É™'), + ('É›', 'Éœ'), + ('É ', 'É¡'), + ('É£', 'É£'), + ('É¥', 'ɦ'), + ('ɨ', 'ɬ'), + ('ɯ', 'ɯ'), + ('ɱ', 'ɲ'), + ('ɵ', 'ɵ'), + ('ɽ', 'ɽ'), + ('Ê€', 'Ê€'), + ('Ê‚', 'ʃ'), + ('ʇ', 'ÊŒ'), + ('Ê’', 'Ê’'), + ('Ê', 'Êž'), + ('\u{345}', '\u{345}'), + ('ͱ', 'ͱ'), + ('ͳ', 'ͳ'), + ('Í·', 'Í·'), + ('Í»', 'ͽ'), + ('Î', 'Î'), + ('ά', 'ÏŽ'), + ('Ï', 'Ï‘'), + ('Ï•', 'Ï—'), + ('Ï™', 'Ï™'), + ('Ï›', 'Ï›'), + ('Ï', 'Ï'), + ('ÏŸ', 'ÏŸ'), + ('Ï¡', 'Ï¡'), + ('Ï£', 'Ï£'), + ('Ï¥', 'Ï¥'), + ('ϧ', 'ϧ'), + ('Ï©', 'Ï©'), + ('Ï«', 'Ï«'), + ('Ï­', 'Ï­'), + ('ϯ', 'ϳ'), + ('ϵ', 'ϵ'), + ('ϸ', 'ϸ'), + ('Ï»', 'Ï»'), + ('а', 'ÑŸ'), + ('Ñ¡', 'Ñ¡'), + ('Ñ£', 'Ñ£'), + ('Ñ¥', 'Ñ¥'), + ('ѧ', 'ѧ'), + ('Ñ©', 'Ñ©'), + ('Ñ«', 'Ñ«'), + ('Ñ­', 'Ñ­'), + ('ѯ', 'ѯ'), + ('ѱ', 'ѱ'), + ('ѳ', 'ѳ'), + ('ѵ', 'ѵ'), + ('Ñ·', 'Ñ·'), + ('ѹ', 'ѹ'), + ('Ñ»', 'Ñ»'), + ('ѽ', 'ѽ'), + ('Ñ¿', 'Ñ¿'), + ('Ò', 'Ò'), + ('Ò‹', 'Ò‹'), + ('Ò', 'Ò'), + ('Ò', 'Ò'), + ('Ò‘', 'Ò‘'), + ('Ò“', 'Ò“'), + ('Ò•', 'Ò•'), + ('Ò—', 'Ò—'), + ('Ò™', 'Ò™'), + ('Ò›', 'Ò›'), + ('Ò', 'Ò'), + ('ÒŸ', 'ÒŸ'), + ('Ò¡', 'Ò¡'), + ('Ò£', 'Ò£'), + ('Ò¥', 'Ò¥'), + ('Ò§', 'Ò§'), + ('Ò©', 'Ò©'), + ('Ò«', 'Ò«'), + ('Ò­', 'Ò­'), + ('Ò¯', 'Ò¯'), + ('Ò±', 'Ò±'), + ('Ò³', 'Ò³'), + ('Òµ', 'Òµ'), + ('Ò·', 'Ò·'), + ('Ò¹', 'Ò¹'), + ('Ò»', 'Ò»'), + ('Ò½', 'Ò½'), + ('Ò¿', 'Ò¿'), + ('Ó‚', 'Ó‚'), + ('Ó„', 'Ó„'), + ('Ó†', 'Ó†'), + ('Óˆ', 'Óˆ'), + ('ÓŠ', 'ÓŠ'), + ('ÓŒ', 'ÓŒ'), + ('ÓŽ', 'Ó'), + ('Ó‘', 'Ó‘'), + ('Ó“', 'Ó“'), + ('Ó•', 'Ó•'), + ('Ó—', 'Ó—'), + ('Ó™', 'Ó™'), + ('Ó›', 'Ó›'), + ('Ó', 'Ó'), + ('ÓŸ', 'ÓŸ'), + ('Ó¡', 'Ó¡'), + ('Ó£', 'Ó£'), + ('Ó¥', 'Ó¥'), + ('Ó§', 'Ó§'), + ('Ó©', 'Ó©'), + ('Ó«', 'Ó«'), + ('Ó­', 'Ó­'), + ('Ó¯', 'Ó¯'), + ('Ó±', 'Ó±'), + ('Ó³', 'Ó³'), + ('Óµ', 'Óµ'), + ('Ó·', 'Ó·'), + ('Ó¹', 'Ó¹'), + ('Ó»', 'Ó»'), + ('Ó½', 'Ó½'), + ('Ó¿', 'Ó¿'), + ('Ô', 'Ô'), + ('Ôƒ', 'Ôƒ'), + ('Ô…', 'Ô…'), + ('Ô‡', 'Ô‡'), + ('Ô‰', 'Ô‰'), + ('Ô‹', 'Ô‹'), + ('Ô', 'Ô'), + ('Ô', 'Ô'), + ('Ô‘', 'Ô‘'), + ('Ô“', 'Ô“'), + ('Ô•', 'Ô•'), + ('Ô—', 'Ô—'), + ('Ô™', 'Ô™'), + ('Ô›', 'Ô›'), + ('Ô', 'Ô'), + ('ÔŸ', 'ÔŸ'), + ('Ô¡', 'Ô¡'), + ('Ô£', 'Ô£'), + ('Ô¥', 'Ô¥'), + ('Ô§', 'Ô§'), + ('Ô©', 'Ô©'), + ('Ô«', 'Ô«'), + ('Ô­', 'Ô­'), + ('Ô¯', 'Ô¯'), + ('Õ¡', 'Ö‡'), + ('áƒ', 'ჺ'), + ('ჽ', 'ჿ'), + ('á¸', 'á½'), + ('á²€', 'ᲈ'), + ('áµ¹', 'áµ¹'), + ('áµ½', 'áµ½'), + ('ᶎ', 'ᶎ'), + ('á¸', 'á¸'), + ('ḃ', 'ḃ'), + ('ḅ', 'ḅ'), + ('ḇ', 'ḇ'), + ('ḉ', 'ḉ'), + ('ḋ', 'ḋ'), + ('á¸', 'á¸'), + ('á¸', 'á¸'), + ('ḑ', 'ḑ'), + ('ḓ', 'ḓ'), + ('ḕ', 'ḕ'), + ('ḗ', 'ḗ'), + ('ḙ', 'ḙ'), + ('ḛ', 'ḛ'), + ('á¸', 'á¸'), + ('ḟ', 'ḟ'), + ('ḡ', 'ḡ'), + ('ḣ', 'ḣ'), + ('ḥ', 'ḥ'), + ('ḧ', 'ḧ'), + ('ḩ', 'ḩ'), + ('ḫ', 'ḫ'), + ('ḭ', 'ḭ'), + ('ḯ', 'ḯ'), + ('ḱ', 'ḱ'), + ('ḳ', 'ḳ'), + ('ḵ', 'ḵ'), + ('ḷ', 'ḷ'), + ('ḹ', 'ḹ'), + ('ḻ', 'ḻ'), + ('ḽ', 'ḽ'), + ('ḿ', 'ḿ'), + ('á¹', 'á¹'), + ('ṃ', 'ṃ'), + ('á¹…', 'á¹…'), + ('ṇ', 'ṇ'), + ('ṉ', 'ṉ'), + ('ṋ', 'ṋ'), + ('á¹', 'á¹'), + ('á¹', 'á¹'), + ('ṑ', 'ṑ'), + ('ṓ', 'ṓ'), + ('ṕ', 'ṕ'), + ('á¹—', 'á¹—'), + ('á¹™', 'á¹™'), + ('á¹›', 'á¹›'), + ('á¹', 'á¹'), + ('ṟ', 'ṟ'), + ('ṡ', 'ṡ'), + ('á¹£', 'á¹£'), + ('á¹¥', 'á¹¥'), + ('ṧ', 'ṧ'), + ('ṩ', 'ṩ'), + ('ṫ', 'ṫ'), + ('á¹­', 'á¹­'), + ('ṯ', 'ṯ'), + ('á¹±', 'á¹±'), + ('á¹³', 'á¹³'), + ('á¹µ', 'á¹µ'), + ('á¹·', 'á¹·'), + ('á¹¹', 'á¹¹'), + ('á¹»', 'á¹»'), + ('á¹½', 'á¹½'), + ('ṿ', 'ṿ'), + ('áº', 'áº'), + ('ẃ', 'ẃ'), + ('ẅ', 'ẅ'), + ('ẇ', 'ẇ'), + ('ẉ', 'ẉ'), + ('ẋ', 'ẋ'), + ('áº', 'áº'), + ('áº', 'áº'), + ('ẑ', 'ẑ'), + ('ẓ', 'ẓ'), + ('ẕ', 'ẛ'), + ('ạ', 'ạ'), + ('ả', 'ả'), + ('ấ', 'ấ'), + ('ầ', 'ầ'), + ('ẩ', 'ẩ'), + ('ẫ', 'ẫ'), + ('ậ', 'ậ'), + ('ắ', 'ắ'), + ('ằ', 'ằ'), + ('ẳ', 'ẳ'), + ('ẵ', 'ẵ'), + ('ặ', 'ặ'), + ('ẹ', 'ẹ'), + ('ẻ', 'ẻ'), + ('ẽ', 'ẽ'), + ('ế', 'ế'), + ('á»', 'á»'), + ('ể', 'ể'), + ('á»…', 'á»…'), + ('ệ', 'ệ'), + ('ỉ', 'ỉ'), + ('ị', 'ị'), + ('á»', 'á»'), + ('á»', 'á»'), + ('ố', 'ố'), + ('ồ', 'ồ'), + ('ổ', 'ổ'), + ('á»—', 'á»—'), + ('á»™', 'á»™'), + ('á»›', 'á»›'), + ('á»', 'á»'), + ('ở', 'ở'), + ('ỡ', 'ỡ'), + ('ợ', 'ợ'), + ('ụ', 'ụ'), + ('ủ', 'ủ'), + ('ứ', 'ứ'), + ('ừ', 'ừ'), + ('á»­', 'á»­'), + ('ữ', 'ữ'), + ('á»±', 'á»±'), + ('ỳ', 'ỳ'), + ('ỵ', 'ỵ'), + ('á»·', 'á»·'), + ('ỹ', 'ỹ'), + ('á»»', 'á»»'), + ('ỽ', 'ỽ'), + ('ỿ', 'ἇ'), + ('á¼', 'ἕ'), + ('á¼ ', 'ἧ'), + ('á¼°', 'á¼·'), + ('á½€', 'á½…'), + ('á½', 'á½—'), + ('á½ ', 'ὧ'), + ('á½°', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¾·'), + ('á¾¼', 'á¾¼'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'ῇ'), + ('á¿Œ', 'á¿Œ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿—'), + ('á¿ ', 'ῧ'), + ('ῲ', 'á¿´'), + ('ῶ', 'á¿·'), + ('ῼ', 'ῼ'), + ('â…Ž', 'â…Ž'), + ('â…°', 'â…¿'), + ('ↄ', 'ↄ'), + ('â“', 'â“©'), + ('â°°', 'ⱟ'), + ('ⱡ', 'ⱡ'), + ('â±¥', 'ⱦ'), + ('ⱨ', 'ⱨ'), + ('ⱪ', 'ⱪ'), + ('ⱬ', 'ⱬ'), + ('â±³', 'â±³'), + ('ⱶ', 'ⱶ'), + ('â²', 'â²'), + ('ⲃ', 'ⲃ'), + ('â²…', 'â²…'), + ('ⲇ', 'ⲇ'), + ('ⲉ', 'ⲉ'), + ('ⲋ', 'ⲋ'), + ('â²', 'â²'), + ('â²', 'â²'), + ('ⲑ', 'ⲑ'), + ('ⲓ', 'ⲓ'), + ('ⲕ', 'ⲕ'), + ('â²—', 'â²—'), + ('â²™', 'â²™'), + ('â²›', 'â²›'), + ('â²', 'â²'), + ('ⲟ', 'ⲟ'), + ('ⲡ', 'ⲡ'), + ('â²£', 'â²£'), + ('â²¥', 'â²¥'), + ('ⲧ', 'ⲧ'), + ('ⲩ', 'ⲩ'), + ('ⲫ', 'ⲫ'), + ('â²­', 'â²­'), + ('ⲯ', 'ⲯ'), + ('â²±', 'â²±'), + ('â²³', 'â²³'), + ('â²µ', 'â²µ'), + ('â²·', 'â²·'), + ('â²¹', 'â²¹'), + ('â²»', 'â²»'), + ('â²½', 'â²½'), + ('ⲿ', 'ⲿ'), + ('â³', 'â³'), + ('ⳃ', 'ⳃ'), + ('â³…', 'â³…'), + ('ⳇ', 'ⳇ'), + ('ⳉ', 'ⳉ'), + ('ⳋ', 'ⳋ'), + ('â³', 'â³'), + ('â³', 'â³'), + ('ⳑ', 'ⳑ'), + ('ⳓ', 'ⳓ'), + ('ⳕ', 'ⳕ'), + ('â³—', 'â³—'), + ('â³™', 'â³™'), + ('â³›', 'â³›'), + ('â³', 'â³'), + ('ⳟ', 'ⳟ'), + ('ⳡ', 'ⳡ'), + ('â³£', 'â³£'), + ('ⳬ', 'ⳬ'), + ('â³®', 'â³®'), + ('â³³', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('ê™', 'ê™'), + ('ꙃ', 'ꙃ'), + ('ê™…', 'ê™…'), + ('ꙇ', 'ꙇ'), + ('ꙉ', 'ꙉ'), + ('ꙋ', 'ꙋ'), + ('ê™', 'ê™'), + ('ê™', 'ê™'), + ('ꙑ', 'ꙑ'), + ('ꙓ', 'ꙓ'), + ('ꙕ', 'ꙕ'), + ('ê™—', 'ê™—'), + ('ê™™', 'ê™™'), + ('ê™›', 'ê™›'), + ('ê™', 'ê™'), + ('ꙟ', 'ꙟ'), + ('ꙡ', 'ꙡ'), + ('ꙣ', 'ꙣ'), + ('ꙥ', 'ꙥ'), + ('ꙧ', 'ꙧ'), + ('ꙩ', 'ꙩ'), + ('ꙫ', 'ꙫ'), + ('ê™­', 'ê™­'), + ('êš', 'êš'), + ('ꚃ', 'ꚃ'), + ('êš…', 'êš…'), + ('ꚇ', 'ꚇ'), + ('ꚉ', 'ꚉ'), + ('êš‹', 'êš‹'), + ('êš', 'êš'), + ('êš', 'êš'), + ('êš‘', 'êš‘'), + ('êš“', 'êš“'), + ('êš•', 'êš•'), + ('êš—', 'êš—'), + ('êš™', 'êš™'), + ('êš›', 'êš›'), + ('ꜣ', 'ꜣ'), + ('ꜥ', 'ꜥ'), + ('ꜧ', 'ꜧ'), + ('ꜩ', 'ꜩ'), + ('ꜫ', 'ꜫ'), + ('ꜭ', 'ꜭ'), + ('ꜯ', 'ꜯ'), + ('ꜳ', 'ꜳ'), + ('ꜵ', 'ꜵ'), + ('ꜷ', 'ꜷ'), + ('ꜹ', 'ꜹ'), + ('ꜻ', 'ꜻ'), + ('ꜽ', 'ꜽ'), + ('ꜿ', 'ꜿ'), + ('ê', 'ê'), + ('êƒ', 'êƒ'), + ('ê…', 'ê…'), + ('ê‡', 'ê‡'), + ('ê‰', 'ê‰'), + ('ê‹', 'ê‹'), + ('ê', 'ê'), + ('ê', 'ê'), + ('ê‘', 'ê‘'), + ('ê“', 'ê“'), + ('ê•', 'ê•'), + ('ê—', 'ê—'), + ('ê™', 'ê™'), + ('ê›', 'ê›'), + ('ê', 'ê'), + ('êŸ', 'êŸ'), + ('ê¡', 'ê¡'), + ('ê£', 'ê£'), + ('ê¥', 'ê¥'), + ('ê§', 'ê§'), + ('ê©', 'ê©'), + ('ê«', 'ê«'), + ('ê­', 'ê­'), + ('ê¯', 'ê¯'), + ('êº', 'êº'), + ('ê¼', 'ê¼'), + ('ê¿', 'ê¿'), + ('êž', 'êž'), + ('ꞃ', 'ꞃ'), + ('êž…', 'êž…'), + ('ꞇ', 'ꞇ'), + ('ꞌ', 'ꞌ'), + ('êž‘', 'êž‘'), + ('êž“', 'êž”'), + ('êž—', 'êž—'), + ('êž™', 'êž™'), + ('êž›', 'êž›'), + ('êž', 'êž'), + ('ꞟ', 'ꞟ'), + ('êž¡', 'êž¡'), + ('ꞣ', 'ꞣ'), + ('ꞥ', 'ꞥ'), + ('ꞧ', 'ꞧ'), + ('êž©', 'êž©'), + ('êžµ', 'êžµ'), + ('êž·', 'êž·'), + ('êž¹', 'êž¹'), + ('êž»', 'êž»'), + ('êž½', 'êž½'), + ('êž¿', 'êž¿'), + ('êŸ', 'êŸ'), + ('ꟃ', 'ꟃ'), + ('ꟈ', 'ꟈ'), + ('ꟊ', 'ꟊ'), + ('ꟑ', 'ꟑ'), + ('ꟗ', 'ꟗ'), + ('ꟙ', 'ꟙ'), + ('ꟶ', 'ꟶ'), + ('ê­“', 'ê­“'), + ('ê­°', 'ꮿ'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï½', 'z'), + ('ð¨', 'ð‘'), + ('ð“˜', 'ð“»'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð³€', 'ð³²'), + ('ð‘£€', '𑣟'), + ('ð–¹ ', '𖹿'), + ('𞤢', '𞥃'), +]; + +pub const DASH: &'static [(char, char)] = &[ + ('-', '-'), + ('ÖŠ', 'ÖŠ'), + ('Ö¾', 'Ö¾'), + ('á€', 'á€'), + ('á †', 'á †'), + ('â€', '―'), + ('â“', 'â“'), + ('â»', 'â»'), + ('â‚‹', 'â‚‹'), + ('−', '−'), + ('⸗', '⸗'), + ('⸚', '⸚'), + ('⸺', '⸻'), + ('â¹€', 'â¹€'), + ('â¹', 'â¹'), + ('〜', '〜'), + ('〰', '〰'), + ('ã‚ ', 'ã‚ '), + ('︱', '︲'), + ('﹘', '﹘'), + ('ï¹£', 'ï¹£'), + ('ï¼', 'ï¼'), + ('ðº­', 'ðº­'), +]; + +pub const DEFAULT_IGNORABLE_CODE_POINT: &'static [(char, char)] = &[ + ('\u{ad}', '\u{ad}'), + ('\u{34f}', '\u{34f}'), + ('\u{61c}', '\u{61c}'), + ('á…Ÿ', 'á… '), + ('\u{17b4}', '\u{17b5}'), + ('\u{180b}', '\u{180f}'), + ('\u{200b}', '\u{200f}'), + ('\u{202a}', '\u{202e}'), + ('\u{2060}', '\u{206f}'), + ('ã…¤', 'ã…¤'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{feff}', '\u{feff}'), + ('ï¾ ', 'ï¾ '), + ('\u{fff0}', '\u{fff8}'), + ('\u{1bca0}', '\u{1bca3}'), + ('\u{1d173}', '\u{1d17a}'), + ('\u{e0000}', '\u{e0fff}'), +]; + +pub const DEPRECATED: &'static [(char, char)] = &[ + ('ʼn', 'ʼn'), + ('Ù³', 'Ù³'), + ('\u{f77}', '\u{f77}'), + ('\u{f79}', '\u{f79}'), + ('ឣ', 'ឤ'), + ('\u{206a}', '\u{206f}'), + ('〈', '〉'), + ('\u{e0001}', '\u{e0001}'), +]; + +pub const DIACRITIC: &'static [(char, char)] = &[ + ('^', '^'), + ('`', '`'), + ('¨', '¨'), + ('¯', '¯'), + ('´', '´'), + ('·', '¸'), + ('Ê°', '\u{34e}'), + ('\u{350}', '\u{357}'), + ('\u{35d}', '\u{362}'), + ('Í´', '͵'), + ('ͺ', 'ͺ'), + ('΄', 'Î…'), + ('\u{483}', '\u{487}'), + ('Õ™', 'Õ™'), + ('\u{591}', '\u{5a1}'), + ('\u{5a3}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c4}'), + ('\u{64b}', '\u{652}'), + ('\u{657}', '\u{658}'), + ('\u{6df}', '\u{6e0}'), + ('Û¥', 'Û¦'), + ('\u{6ea}', '\u{6ec}'), + ('\u{730}', '\u{74a}'), + ('\u{7a6}', '\u{7b0}'), + ('\u{7eb}', 'ßµ'), + ('\u{818}', '\u{819}'), + ('\u{898}', '\u{89f}'), + ('ࣉ', '\u{8d2}'), + ('\u{8e3}', '\u{8fe}'), + ('\u{93c}', '\u{93c}'), + ('\u{94d}', '\u{94d}'), + ('\u{951}', '\u{954}'), + ('ॱ', 'ॱ'), + ('\u{9bc}', '\u{9bc}'), + ('\u{9cd}', '\u{9cd}'), + ('\u{a3c}', '\u{a3c}'), + ('\u{a4d}', '\u{a4d}'), + ('\u{abc}', '\u{abc}'), + ('\u{acd}', '\u{acd}'), + ('\u{afd}', '\u{aff}'), + ('\u{b3c}', '\u{b3c}'), + ('\u{b4d}', '\u{b4d}'), + ('\u{b55}', '\u{b55}'), + ('\u{bcd}', '\u{bcd}'), + ('\u{c3c}', '\u{c3c}'), + ('\u{c4d}', '\u{c4d}'), + ('\u{cbc}', '\u{cbc}'), + ('\u{ccd}', '\u{ccd}'), + ('\u{d3b}', '\u{d3c}'), + ('\u{d4d}', '\u{d4d}'), + ('\u{dca}', '\u{dca}'), + ('\u{e47}', '\u{e4c}'), + ('\u{e4e}', '\u{e4e}'), + ('\u{eba}', '\u{eba}'), + ('\u{ec8}', '\u{ecc}'), + ('\u{f18}', '\u{f19}'), + ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), + ('\u{f39}', '\u{f39}'), + ('༾', '༿'), + ('\u{f82}', '\u{f84}'), + ('\u{f86}', '\u{f87}'), + ('\u{fc6}', '\u{fc6}'), + ('\u{1037}', '\u{1037}'), + ('\u{1039}', '\u{103a}'), + ('á£', 'á¤'), + ('á©', 'á­'), + ('ႇ', '\u{108d}'), + ('á‚', 'á‚'), + ('á‚š', 'á‚›'), + ('\u{135d}', '\u{135f}'), + ('\u{1714}', '᜕'), + ('\u{17c9}', '\u{17d3}'), + ('\u{17dd}', '\u{17dd}'), + ('\u{1939}', '\u{193b}'), + ('\u{1a75}', '\u{1a7c}'), + ('\u{1a7f}', '\u{1a7f}'), + ('\u{1ab0}', '\u{1abe}'), + ('\u{1ac1}', '\u{1acb}'), + ('\u{1b34}', '\u{1b34}'), + ('á­„', 'á­„'), + ('\u{1b6b}', '\u{1b73}'), + ('᮪', '\u{1bab}'), + ('\u{1c36}', '\u{1c37}'), + ('ᱸ', 'á±½'), + ('\u{1cd0}', '\u{1ce8}'), + ('\u{1ced}', '\u{1ced}'), + ('\u{1cf4}', '\u{1cf4}'), + ('á³·', '\u{1cf9}'), + ('á´¬', 'ᵪ'), + ('\u{1dc4}', '\u{1dcf}'), + ('\u{1df5}', '\u{1dff}'), + ('á¾½', 'á¾½'), + ('᾿', 'á¿'), + ('á¿', 'á¿'), + ('á¿', 'á¿Ÿ'), + ('á¿­', '`'), + ('´', '῾'), + ('\u{2cef}', '\u{2cf1}'), + ('ⸯ', 'ⸯ'), + ('\u{302a}', '\u{302f}'), + ('\u{3099}', 'ã‚œ'), + ('ー', 'ー'), + ('\u{a66f}', '\u{a66f}'), + ('\u{a67c}', '\u{a67d}'), + ('ꙿ', 'ꙿ'), + ('êšœ', 'êš'), + ('\u{a6f0}', '\u{a6f1}'), + ('꜀', '꜡'), + ('ꞈ', '꞊'), + ('ꟸ', 'ꟹ'), + ('\u{a8c4}', '\u{a8c4}'), + ('\u{a8e0}', '\u{a8f1}'), + ('\u{a92b}', '꤮'), + ('꥓', '꥓'), + ('\u{a9b3}', '\u{a9b3}'), + ('꧀', '꧀'), + ('\u{a9e5}', '\u{a9e5}'), + ('ê©»', 'ꩽ'), + ('\u{aabf}', 'ê«‚'), + ('\u{aaf6}', '\u{aaf6}'), + ('ê­›', 'ê­Ÿ'), + ('ê­©', 'ê­«'), + ('꯬', '\u{abed}'), + ('\u{fb1e}', '\u{fb1e}'), + ('\u{fe20}', '\u{fe2f}'), + ('ï¼¾', 'ï¼¾'), + ('ï½€', 'ï½€'), + ('ï½°', 'ï½°'), + ('\u{ff9e}', '\u{ff9f}'), + ('ï¿£', 'ï¿£'), + ('\u{102e0}', '\u{102e0}'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('\u{10ae5}', '\u{10ae6}'), + ('ð´¢', '\u{10d27}'), + ('\u{10efd}', '\u{10eff}'), + ('\u{10f46}', '\u{10f50}'), + ('\u{10f82}', '\u{10f85}'), + ('\u{11046}', '\u{11046}'), + ('\u{11070}', '\u{11070}'), + ('\u{110b9}', '\u{110ba}'), + ('\u{11133}', '\u{11134}'), + ('\u{11173}', '\u{11173}'), + ('𑇀', '𑇀'), + ('\u{111ca}', '\u{111cc}'), + ('𑈵', '\u{11236}'), + ('\u{112e9}', '\u{112ea}'), + ('\u{1133c}', '\u{1133c}'), + ('ð‘', 'ð‘'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('\u{11442}', '\u{11442}'), + ('\u{11446}', '\u{11446}'), + ('\u{114c2}', '\u{114c3}'), + ('\u{115bf}', '\u{115c0}'), + ('\u{1163f}', '\u{1163f}'), + ('𑚶', '\u{116b7}'), + ('\u{1172b}', '\u{1172b}'), + ('\u{11839}', '\u{1183a}'), + ('𑤽', '\u{1193e}'), + ('\u{11943}', '\u{11943}'), + ('\u{119e0}', '\u{119e0}'), + ('\u{11a34}', '\u{11a34}'), + ('\u{11a47}', '\u{11a47}'), + ('\u{11a99}', '\u{11a99}'), + ('\u{11c3f}', '\u{11c3f}'), + ('\u{11d42}', '\u{11d42}'), + ('\u{11d44}', '\u{11d45}'), + ('\u{11d97}', '\u{11d97}'), + ('\u{13447}', '\u{13455}'), + ('\u{16af0}', '\u{16af4}'), + ('\u{16b30}', '\u{16b36}'), + ('\u{16f8f}', '𖾟'), + ('ð–¿°', 'ð–¿±'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('\u{1d167}', '\u{1d169}'), + ('ð…­', '\u{1d172}'), + ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('𞀰', 'ðž­'), + ('\u{1e130}', '\u{1e136}'), + ('\u{1e2ae}', '\u{1e2ae}'), + ('\u{1e2ec}', '\u{1e2ef}'), + ('\u{1e8d0}', '\u{1e8d6}'), + ('\u{1e944}', '\u{1e946}'), + ('\u{1e948}', '\u{1e94a}'), +]; + +pub const EMOJI: &'static [(char, char)] = &[ + ('#', '#'), + ('*', '*'), + ('0', '9'), + ('©', '©'), + ('®', '®'), + ('‼', '‼'), + ('â‰', 'â‰'), + ('â„¢', 'â„¢'), + ('ℹ', 'ℹ'), + ('↔', '↙'), + ('↩', '↪'), + ('⌚', '⌛'), + ('⌨', '⌨'), + ('â', 'â'), + ('â©', 'â³'), + ('â¸', 'âº'), + ('â“‚', 'â“‚'), + ('â–ª', 'â–«'), + ('â–¶', 'â–¶'), + ('â—€', 'â—€'), + ('â—»', 'â—¾'), + ('☀', '☄'), + ('☎', '☎'), + ('☑', '☑'), + ('☔', '☕'), + ('☘', '☘'), + ('â˜', 'â˜'), + ('☠', '☠'), + ('☢', '☣'), + ('☦', '☦'), + ('☪', '☪'), + ('☮', '☯'), + ('☸', '☺'), + ('♀', '♀'), + ('♂', '♂'), + ('♈', '♓'), + ('♟', 'â™ '), + ('♣', '♣'), + ('♥', '♦'), + ('♨', '♨'), + ('â™»', 'â™»'), + ('♾', '♿'), + ('âš’', 'âš—'), + ('âš™', 'âš™'), + ('âš›', 'âšœ'), + ('âš ', 'âš¡'), + ('⚧', '⚧'), + ('⚪', 'âš«'), + ('âš°', 'âš±'), + ('âš½', 'âš¾'), + ('⛄', 'â›…'), + ('⛈', '⛈'), + ('⛎', 'â›'), + ('⛑', '⛑'), + ('⛓', 'â›”'), + ('⛩', '⛪'), + ('â›°', '⛵'), + ('â›·', '⛺'), + ('⛽', '⛽'), + ('✂', '✂'), + ('✅', '✅'), + ('✈', 'âœ'), + ('âœ', 'âœ'), + ('✒', '✒'), + ('✔', '✔'), + ('✖', '✖'), + ('âœ', 'âœ'), + ('✡', '✡'), + ('✨', '✨'), + ('✳', '✴'), + ('â„', 'â„'), + ('â‡', 'â‡'), + ('âŒ', 'âŒ'), + ('âŽ', 'âŽ'), + ('â“', 'â•'), + ('â—', 'â—'), + ('â£', 'â¤'), + ('âž•', 'âž—'), + ('âž¡', 'âž¡'), + ('âž°', 'âž°'), + ('âž¿', 'âž¿'), + ('⤴', '⤵'), + ('⬅', '⬇'), + ('⬛', '⬜'), + ('â­', 'â­'), + ('â­•', 'â­•'), + ('〰', '〰'), + ('〽', '〽'), + ('㊗', '㊗'), + ('㊙', '㊙'), + ('🀄', '🀄'), + ('ðŸƒ', 'ðŸƒ'), + ('🅰', '🅱'), + ('🅾', '🅿'), + ('🆎', '🆎'), + ('🆑', '🆚'), + ('🇦', '🇿'), + ('ðŸˆ', '🈂'), + ('🈚', '🈚'), + ('🈯', '🈯'), + ('🈲', '🈺'), + ('ðŸ‰', '🉑'), + ('🌀', '🌡'), + ('🌤', '🎓'), + ('🎖', '🎗'), + ('🎙', '🎛'), + ('🎞', 'ðŸ°'), + ('ðŸ³', 'ðŸµ'), + ('ðŸ·', '📽'), + ('📿', '🔽'), + ('🕉', '🕎'), + ('ðŸ•', '🕧'), + ('🕯', '🕰'), + ('🕳', '🕺'), + ('🖇', '🖇'), + ('🖊', 'ðŸ–'), + ('ðŸ–', 'ðŸ–'), + ('🖕', '🖖'), + ('🖤', '🖥'), + ('🖨', '🖨'), + ('🖱', '🖲'), + ('🖼', '🖼'), + ('🗂', '🗄'), + ('🗑', '🗓'), + ('🗜', '🗞'), + ('🗡', '🗡'), + ('🗣', '🗣'), + ('🗨', '🗨'), + ('🗯', '🗯'), + ('🗳', '🗳'), + ('🗺', 'ðŸ™'), + ('🚀', '🛅'), + ('🛋', '🛒'), + ('🛕', '🛗'), + ('🛜', '🛥'), + ('🛩', '🛩'), + ('🛫', '🛬'), + ('🛰', '🛰'), + ('🛳', '🛼'), + ('🟠', '🟫'), + ('🟰', '🟰'), + ('🤌', '🤺'), + ('🤼', '🥅'), + ('🥇', '🧿'), + ('🩰', '🩼'), + ('🪀', '🪈'), + ('ðŸª', '🪽'), + ('🪿', '🫅'), + ('🫎', '🫛'), + ('🫠', '🫨'), + ('🫰', '🫸'), +]; + +pub const EMOJI_COMPONENT: &'static [(char, char)] = &[ + ('#', '#'), + ('*', '*'), + ('0', '9'), + ('\u{200d}', '\u{200d}'), + ('\u{20e3}', '\u{20e3}'), + ('\u{fe0f}', '\u{fe0f}'), + ('🇦', '🇿'), + ('ðŸ»', 'ðŸ¿'), + ('🦰', '🦳'), + ('\u{e0020}', '\u{e007f}'), +]; + +pub const EMOJI_MODIFIER: &'static [(char, char)] = &[('ðŸ»', 'ðŸ¿')]; + +pub const EMOJI_MODIFIER_BASE: &'static [(char, char)] = &[ + ('â˜', 'â˜'), + ('⛹', '⛹'), + ('✊', 'âœ'), + ('🎅', '🎅'), + ('ðŸ‚', 'ðŸ„'), + ('ðŸ‡', 'ðŸ‡'), + ('ðŸŠ', 'ðŸŒ'), + ('👂', '👃'), + ('👆', 'ðŸ‘'), + ('👦', '👸'), + ('👼', '👼'), + ('ðŸ’', '💃'), + ('💅', '💇'), + ('ðŸ’', 'ðŸ’'), + ('💑', '💑'), + ('💪', '💪'), + ('🕴', '🕵'), + ('🕺', '🕺'), + ('ðŸ–', 'ðŸ–'), + ('🖕', '🖖'), + ('🙅', '🙇'), + ('🙋', 'ðŸ™'), + ('🚣', '🚣'), + ('🚴', '🚶'), + ('🛀', '🛀'), + ('🛌', '🛌'), + ('🤌', '🤌'), + ('ðŸ¤', 'ðŸ¤'), + ('🤘', '🤟'), + ('🤦', '🤦'), + ('🤰', '🤹'), + ('🤼', '🤾'), + ('🥷', '🥷'), + ('🦵', '🦶'), + ('🦸', '🦹'), + ('🦻', '🦻'), + ('ðŸ§', 'ðŸ§'), + ('🧑', 'ðŸ§'), + ('🫃', '🫅'), + ('🫰', '🫸'), +]; + +pub const EMOJI_PRESENTATION: &'static [(char, char)] = &[ + ('⌚', '⌛'), + ('â©', 'â¬'), + ('â°', 'â°'), + ('â³', 'â³'), + ('â—½', 'â—¾'), + ('☔', '☕'), + ('♈', '♓'), + ('♿', '♿'), + ('âš“', 'âš“'), + ('âš¡', 'âš¡'), + ('⚪', 'âš«'), + ('âš½', 'âš¾'), + ('⛄', 'â›…'), + ('⛎', '⛎'), + ('â›”', 'â›”'), + ('⛪', '⛪'), + ('⛲', '⛳'), + ('⛵', '⛵'), + ('⛺', '⛺'), + ('⛽', '⛽'), + ('✅', '✅'), + ('✊', '✋'), + ('✨', '✨'), + ('âŒ', 'âŒ'), + ('âŽ', 'âŽ'), + ('â“', 'â•'), + ('â—', 'â—'), + ('âž•', 'âž—'), + ('âž°', 'âž°'), + ('âž¿', 'âž¿'), + ('⬛', '⬜'), + ('â­', 'â­'), + ('â­•', 'â­•'), + ('🀄', '🀄'), + ('ðŸƒ', 'ðŸƒ'), + ('🆎', '🆎'), + ('🆑', '🆚'), + ('🇦', '🇿'), + ('ðŸˆ', 'ðŸˆ'), + ('🈚', '🈚'), + ('🈯', '🈯'), + ('🈲', '🈶'), + ('🈸', '🈺'), + ('ðŸ‰', '🉑'), + ('🌀', '🌠'), + ('🌭', '🌵'), + ('🌷', 'ðŸ¼'), + ('ðŸ¾', '🎓'), + ('🎠', 'ðŸŠ'), + ('ðŸ', 'ðŸ“'), + ('ðŸ ', 'ðŸ°'), + ('ðŸ´', 'ðŸ´'), + ('ðŸ¸', 'ðŸ¾'), + ('👀', '👀'), + ('👂', '📼'), + ('📿', '🔽'), + ('🕋', '🕎'), + ('ðŸ•', '🕧'), + ('🕺', '🕺'), + ('🖕', '🖖'), + ('🖤', '🖤'), + ('🗻', 'ðŸ™'), + ('🚀', '🛅'), + ('🛌', '🛌'), + ('ðŸ›', '🛒'), + ('🛕', '🛗'), + ('🛜', '🛟'), + ('🛫', '🛬'), + ('🛴', '🛼'), + ('🟠', '🟫'), + ('🟰', '🟰'), + ('🤌', '🤺'), + ('🤼', '🥅'), + ('🥇', '🧿'), + ('🩰', '🩼'), + ('🪀', '🪈'), + ('ðŸª', '🪽'), + ('🪿', '🫅'), + ('🫎', '🫛'), + ('🫠', '🫨'), + ('🫰', '🫸'), +]; + +pub const EXTENDED_PICTOGRAPHIC: &'static [(char, char)] = &[ + ('©', '©'), + ('®', '®'), + ('‼', '‼'), + ('â‰', 'â‰'), + ('â„¢', 'â„¢'), + ('ℹ', 'ℹ'), + ('↔', '↙'), + ('↩', '↪'), + ('⌚', '⌛'), + ('⌨', '⌨'), + ('⎈', '⎈'), + ('â', 'â'), + ('â©', 'â³'), + ('â¸', 'âº'), + ('â“‚', 'â“‚'), + ('â–ª', 'â–«'), + ('â–¶', 'â–¶'), + ('â—€', 'â—€'), + ('â—»', 'â—¾'), + ('☀', '★'), + ('☇', '☒'), + ('☔', 'âš…'), + ('âš', '✅'), + ('✈', '✒'), + ('✔', '✔'), + ('✖', '✖'), + ('âœ', 'âœ'), + ('✡', '✡'), + ('✨', '✨'), + ('✳', '✴'), + ('â„', 'â„'), + ('â‡', 'â‡'), + ('âŒ', 'âŒ'), + ('âŽ', 'âŽ'), + ('â“', 'â•'), + ('â—', 'â—'), + ('â£', 'â§'), + ('âž•', 'âž—'), + ('âž¡', 'âž¡'), + ('âž°', 'âž°'), + ('âž¿', 'âž¿'), + ('⤴', '⤵'), + ('⬅', '⬇'), + ('⬛', '⬜'), + ('â­', 'â­'), + ('â­•', 'â­•'), + ('〰', '〰'), + ('〽', '〽'), + ('㊗', '㊗'), + ('㊙', '㊙'), + ('🀀', '\u{1f0ff}'), + ('ðŸ„', 'ðŸ„'), + ('🄯', '🄯'), + ('🅬', '🅱'), + ('🅾', '🅿'), + ('🆎', '🆎'), + ('🆑', '🆚'), + ('🆭', '\u{1f1e5}'), + ('ðŸˆ', '\u{1f20f}'), + ('🈚', '🈚'), + ('🈯', '🈯'), + ('🈲', '🈺'), + ('\u{1f23c}', '\u{1f23f}'), + ('\u{1f249}', 'ðŸº'), + ('ðŸ€', '🔽'), + ('🕆', 'ðŸ™'), + ('🚀', '\u{1f6ff}'), + ('ðŸ´', 'ðŸ¿'), + ('🟕', '\u{1f7ff}'), + ('\u{1f80c}', '\u{1f80f}'), + ('\u{1f848}', '\u{1f84f}'), + ('\u{1f85a}', '\u{1f85f}'), + ('\u{1f888}', '\u{1f88f}'), + ('\u{1f8ae}', '\u{1f8ff}'), + ('🤌', '🤺'), + ('🤼', '🥅'), + ('🥇', '\u{1faff}'), + ('\u{1fc00}', '\u{1fffd}'), +]; + +pub const EXTENDER: &'static [(char, char)] = &[ + ('·', '·'), + ('Ë', 'Ë‘'), + ('Ù€', 'Ù€'), + ('ߺ', 'ߺ'), + ('\u{b55}', '\u{b55}'), + ('ๆ', 'ๆ'), + ('ໆ', 'ໆ'), + ('á Š', 'á Š'), + ('ᡃ', 'ᡃ'), + ('ᪧ', 'ᪧ'), + ('\u{1c36}', '\u{1c36}'), + ('á±»', 'á±»'), + ('々', '々'), + ('〱', '〵'), + ('ã‚', 'ã‚ž'), + ('ー', 'ヾ'), + ('ꀕ', 'ꀕ'), + ('ꘌ', 'ꘌ'), + ('ê§', 'ê§'), + ('ꧦ', 'ꧦ'), + ('ê©°', 'ê©°'), + ('ê«', 'ê«'), + ('ꫳ', 'ê«´'), + ('ï½°', 'ï½°'), + ('ðž', 'ðž‚'), + ('ð‘', 'ð‘'), + ('ð‘—†', 'ð‘—ˆ'), + ('\u{11a98}', '\u{11a98}'), + ('ð–­‚', 'ð–­ƒ'), + ('ð–¿ ', 'ð–¿¡'), + ('ð–¿£', 'ð–¿£'), + ('𞄼', '𞄽'), + ('\u{1e944}', '\u{1e946}'), +]; + +pub const GRAPHEME_BASE: &'static [(char, char)] = &[ + (' ', '~'), + ('\u{a0}', '¬'), + ('®', 'Ë¿'), + ('Í°', 'Í·'), + ('ͺ', 'Í¿'), + ('΄', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'Ò‚'), + ('ÒŠ', 'Ô¯'), + ('Ô±', 'Õ–'), + ('Õ™', 'ÖŠ'), + ('Ö', 'Ö'), + ('Ö¾', 'Ö¾'), + ('×€', '×€'), + ('׃', '׃'), + ('׆', '׆'), + ('×', 'ת'), + ('ׯ', '×´'), + ('؆', 'Ø'), + ('Ø›', 'Ø›'), + ('Ø', 'ÙŠ'), + ('Ù ', 'Ù¯'), + ('Ù±', 'Û•'), + ('Ûž', 'Ûž'), + ('Û¥', 'Û¦'), + ('Û©', 'Û©'), + ('Û®', 'Ü'), + ('Ü', 'Ü'), + ('Ü’', 'ܯ'), + ('Ý', 'Þ¥'), + ('Þ±', 'Þ±'), + ('߀', 'ߪ'), + ('ß´', 'ߺ'), + ('ß¾', 'à •'), + ('à š', 'à š'), + ('à ¤', 'à ¤'), + ('à ¨', 'à ¨'), + ('à °', 'à ¾'), + ('à¡€', 'ࡘ'), + ('à¡ž', 'à¡ž'), + ('à¡ ', 'ࡪ'), + ('à¡°', 'ࢎ'), + ('ࢠ', 'ࣉ'), + ('ः', 'ह'), + ('ऻ', 'ऻ'), + ('ऽ', 'ी'), + ('ॉ', 'ौ'), + ('ॎ', 'à¥'), + ('क़', 'ॡ'), + ('।', 'ঀ'), + ('ং', 'ঃ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('ঽ', 'ঽ'), + ('ি', 'ী'), + ('ে', 'ৈ'), + ('ো', 'ৌ'), + ('ৎ', 'ৎ'), + ('ড়', 'à§'), + ('য়', 'ৡ'), + ('০', '৽'), + ('ਃ', 'ਃ'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('ਾ', 'à©€'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('੦', '੯'), + ('ੲ', 'à©´'), + ('੶', '੶'), + ('ઃ', 'ઃ'), + ('અ', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('ઽ', 'à«€'), + ('ૉ', 'ૉ'), + ('à«‹', 'à«Œ'), + ('à«', 'à«'), + ('à« ', 'à«¡'), + ('૦', '૱'), + ('ૹ', 'ૹ'), + ('ଂ', 'ଃ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), + ('ଽ', 'ଽ'), + ('à­€', 'à­€'), + ('à­‡', 'à­ˆ'), + ('à­‹', 'à­Œ'), + ('à­œ', 'à­'), + ('à­Ÿ', 'à­¡'), + ('à­¦', 'à­·'), + ('ஃ', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'ஹ'), + ('ி', 'ி'), + ('à¯', 'ூ'), + ('ெ', 'ை'), + ('ொ', 'ௌ'), + ('à¯', 'à¯'), + ('௦', '௺'), + ('à°', 'à°ƒ'), + ('à°…', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°¹'), + ('à°½', 'à°½'), + ('à±', 'ౄ'), + ('ౘ', 'ౚ'), + ('à±', 'à±'), + ('à± ', 'ౡ'), + ('౦', '౯'), + ('à±·', 'ಀ'), + ('ಂ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('ಽ', 'ಾ'), + ('à³€', 'à³'), + ('ೃ', 'ೄ'), + ('ೇ', 'ೈ'), + ('ೊ', 'ೋ'), + ('à³', 'ೞ'), + ('à³ ', 'ೡ'), + ('೦', '೯'), + ('à³±', 'à³³'), + ('à´‚', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', 'à´º'), + ('à´½', 'à´½'), + ('à´¿', 'ീ'), + ('െ', 'ൈ'), + ('ൊ', 'ൌ'), + ('ൎ', 'àµ'), + ('ൔ', 'ൖ'), + ('൘', 'ൡ'), + ('൦', 'ൿ'), + ('ං', 'ඃ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('à·', 'à·‘'), + ('à·˜', 'à·ž'), + ('à·¦', 'à·¯'), + ('à·²', 'à·´'), + ('à¸', 'ะ'), + ('า', 'ำ'), + ('฿', 'ๆ'), + ('à¹', '๛'), + ('àº', 'ຂ'), + ('ຄ', 'ຄ'), + ('ຆ', 'ຊ'), + ('ຌ', 'ຣ'), + ('ລ', 'ລ'), + ('ວ', 'ະ'), + ('າ', 'ຳ'), + ('ຽ', 'ຽ'), + ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), + ('à»', 'à»™'), + ('ໜ', 'ໟ'), + ('ༀ', '༗'), + ('༚', '༴'), + ('༶', '༶'), + ('༸', '༸'), + ('༺', 'ཇ'), + ('ཉ', 'ཬ'), + ('ཿ', 'ཿ'), + ('྅', '྅'), + ('ྈ', 'ྌ'), + ('྾', 'à¿…'), + ('࿇', 'à¿Œ'), + ('à¿Ž', 'à¿š'), + ('က', 'ာ'), + ('ေ', 'ေ'), + ('း', 'း'), + ('ျ', 'ြ'), + ('ဿ', 'á—'), + ('áš', 'á'), + ('á¡', 'á°'), + ('áµ', 'á‚'), + ('ႃ', 'á‚„'), + ('ႇ', 'á‚Œ'), + ('á‚Ž', 'á‚œ'), + ('á‚ž', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹–'), + ('ዘ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'áš'), + ('á ', 'á¼'), + ('ᎀ', '᎙'), + ('Ꭰ', 'áµ'), + ('á¸', 'á½'), + ('á€', 'ášœ'), + ('áš ', 'ᛸ'), + ('ᜀ', 'ᜑ'), + ('᜕', '᜕'), + ('ᜟ', 'ᜱ'), + ('᜴', '᜶'), + ('á€', 'á‘'), + ('á ', 'á¬'), + ('á®', 'á°'), + ('ក', 'áž³'), + ('ា', 'ា'), + ('áž¾', 'ៅ'), + ('ះ', 'ៈ'), + ('។', 'ៜ'), + ('០', '៩'), + ('៰', '៹'), + ('á €', 'á Š'), + ('á ', 'á ™'), + ('á  ', 'ᡸ'), + ('ᢀ', 'ᢄ'), + ('ᢇ', 'ᢨ'), + ('ᢪ', 'ᢪ'), + ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), + ('ᤣ', 'ᤦ'), + ('ᤩ', 'ᤫ'), + ('ᤰ', 'ᤱ'), + ('ᤳ', 'ᤸ'), + ('᥀', '᥀'), + ('᥄', 'ᥭ'), + ('ᥰ', 'ᥴ'), + ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), + ('á§', '᧚'), + ('᧞', 'ᨖ'), + ('ᨙ', 'ᨚ'), + ('᨞', 'á©•'), + ('á©—', 'á©—'), + ('á©¡', 'á©¡'), + ('á©£', 'ᩤ'), + ('á©­', 'ᩲ'), + ('᪀', '᪉'), + ('áª', '᪙'), + ('᪠', '᪭'), + ('ᬄ', 'ᬳ'), + ('ᬻ', 'ᬻ'), + ('ᬽ', 'á­'), + ('á­ƒ', 'á­Œ'), + ('á­', 'á­ª'), + ('á­´', 'á­¾'), + ('ᮂ', 'ᮡ'), + ('ᮦ', 'ᮧ'), + ('᮪', '᮪'), + ('á®®', 'ᯥ'), + ('ᯧ', 'ᯧ'), + ('ᯪ', 'ᯬ'), + ('ᯮ', 'ᯮ'), + ('᯲', '᯳'), + ('᯼', 'á°«'), + ('á°´', 'á°µ'), + ('á°»', '᱉'), + ('á±', 'ᲈ'), + ('á²', 'Ჺ'), + ('á²½', '᳇'), + ('᳓', '᳓'), + ('᳡', '᳡'), + ('ᳩ', 'ᳬ'), + ('á³®', 'á³³'), + ('á³µ', 'á³·'), + ('ᳺ', 'ᳺ'), + ('á´€', 'ᶿ'), + ('Ḁ', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¿„'), + ('ῆ', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿', '`'), + ('ῲ', 'á¿´'), + ('ῶ', '῾'), + ('\u{2000}', '\u{200a}'), + ('â€', '‧'), + ('\u{202f}', '\u{205f}'), + ('â°', 'â±'), + ('â´', 'â‚Ž'), + ('â‚', 'â‚œ'), + ('â‚ ', '⃀'), + ('â„€', '↋'), + ('â†', 'â¦'), + ('â‘€', 'â‘Š'), + ('â‘ ', 'â­³'), + ('â­¶', '⮕'), + ('â®—', 'â³®'), + ('â³²', 'â³³'), + ('â³¹', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('â´°', 'ⵧ'), + ('ⵯ', 'âµ°'), + ('ⶀ', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('⸀', 'â¹'), + ('⺀', '⺙'), + ('⺛', '⻳'), + ('â¼€', 'â¿•'), + ('â¿°', 'â¿»'), + ('\u{3000}', '〩'), + ('〰', '〿'), + ('ã', 'ã‚–'), + ('ã‚›', 'ヿ'), + ('ã„…', 'ㄯ'), + ('ㄱ', 'ㆎ'), + ('ã†', '㇣'), + ('ㇰ', '㈞'), + ('㈠', 'ê’Œ'), + ('ê’', '꓆'), + ('ê“', 'ꘫ'), + ('Ꙁ', 'ê™®'), + ('꙳', '꙳'), + ('꙾', 'êš'), + ('êš ', 'ꛯ'), + ('꛲', 'ê›·'), + ('꜀', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('ꟲ', 'ê '), + ('ê ƒ', 'ê …'), + ('ê ‡', 'ê Š'), + ('ê Œ', 'ê ¤'), + ('ê §', 'ê «'), + ('ê °', 'ê ¹'), + ('ê¡€', 'ê¡·'), + ('ꢀ', 'ꣃ'), + ('꣎', '꣙'), + ('ꣲ', 'ꣾ'), + ('꤀', 'ꤥ'), + ('꤮', 'ꥆ'), + ('ꥒ', '꥓'), + ('꥟', 'ꥼ'), + ('ꦃ', 'ꦲ'), + ('ꦴ', 'ꦵ'), + ('ꦺ', 'ꦻ'), + ('ꦾ', 'ê§'), + ('ê§', '꧙'), + ('꧞', 'ꧤ'), + ('ꧦ', 'ꧾ'), + ('ꨀ', 'ꨨ'), + ('ꨯ', 'ꨰ'), + ('ꨳ', 'ꨴ'), + ('ê©€', 'ê©‚'), + ('ê©„', 'ê©‹'), + ('ê©', 'ê©'), + ('ê©', 'ê©™'), + ('ê©œ', 'ê©»'), + ('ꩽ', 'ꪯ'), + ('ꪱ', 'ꪱ'), + ('ꪵ', 'ꪶ'), + ('ꪹ', 'ꪽ'), + ('ê«€', 'ê«€'), + ('ê«‚', 'ê«‚'), + ('ê«›', 'ê««'), + ('ê«®', 'ꫵ'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('ꬰ', 'ê­«'), + ('ê­°', 'ꯤ'), + ('ꯦ', 'ꯧ'), + ('ꯩ', '꯬'), + ('꯰', '꯹'), + ('ê°€', '힣'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), + ('ï©°', 'ï«™'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï¬', 'ï¬'), + ('ײַ', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', '﯂'), + ('ﯓ', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·', 'ï·'), + ('ï·°', 'ï·¿'), + ('ï¸', '︙'), + ('︰', 'ï¹’'), + ('ï¹”', '﹦'), + ('﹨', '﹫'), + ('ï¹°', 'ï¹´'), + ('ﹶ', 'ﻼ'), + ('ï¼', 'ï¾'), + ('ï¾ ', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), + ('ï¿ ', '₩'), + ('│', 'ï¿®'), + ('', '�'), + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), + ('ð„€', 'ð„‚'), + ('ð„‡', 'ð„³'), + ('ð„·', 'ð†Ž'), + ('ð†', 'ð†œ'), + ('ð† ', 'ð† '), + ('ð‡', 'ð‡¼'), + ('ðŠ€', 'ðŠœ'), + ('ðŠ ', 'ð‹'), + ('ð‹¡', 'ð‹»'), + ('ðŒ€', 'ðŒ£'), + ('ðŒ­', 'ðŠ'), + ('ð', 'ðµ'), + ('ðŽ€', 'ðŽ'), + ('ðŽŸ', 'ðƒ'), + ('ðˆ', 'ð•'), + ('ð€', 'ð’'), + ('ð’ ', 'ð’©'), + ('ð’°', 'ð““'), + ('ð“˜', 'ð“»'), + ('ð”€', 'ð”§'), + ('ð”°', 'ð•£'), + ('ð•¯', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð˜€', 'ðœ¶'), + ('ð€', 'ð•'), + ('ð ', 'ð§'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð €', 'ð …'), + ('ð ˆ', 'ð ˆ'), + ('ð Š', 'ð µ'), + ('ð ·', 'ð ¸'), + ('ð ¼', 'ð ¼'), + ('ð ¿', 'ð¡•'), + ('ð¡—', 'ð¢ž'), + ('ð¢§', 'ð¢¯'), + ('ð£ ', 'ð£²'), + ('ð£´', 'ð£µ'), + ('ð£»', 'ð¤›'), + ('ð¤Ÿ', 'ð¤¹'), + ('ð¤¿', 'ð¤¿'), + ('ð¦€', 'ð¦·'), + ('ð¦¼', 'ð§'), + ('ð§’', 'ð¨€'), + ('ð¨', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨µ'), + ('ð©€', 'ð©ˆ'), + ('ð©', 'ð©˜'), + ('ð© ', 'ðªŸ'), + ('ð«€', 'ð«¤'), + ('ð««', 'ð«¶'), + ('ð¬€', 'ð¬µ'), + ('ð¬¹', 'ð­•'), + ('ð­˜', 'ð­²'), + ('ð­¸', 'ð®‘'), + ('ð®™', 'ð®œ'), + ('ð®©', 'ð®¯'), + ('ð°€', 'ð±ˆ'), + ('ð²€', 'ð²²'), + ('ð³€', 'ð³²'), + ('ð³º', 'ð´£'), + ('ð´°', 'ð´¹'), + ('ð¹ ', 'ð¹¾'), + ('ðº€', 'ðº©'), + ('ðº­', 'ðº­'), + ('ðº°', 'ðº±'), + ('ð¼€', 'ð¼§'), + ('ð¼°', 'ð½…'), + ('ð½‘', 'ð½™'), + ('ð½°', 'ð¾'), + ('ð¾†', 'ð¾‰'), + ('ð¾°', 'ð¿‹'), + ('ð¿ ', 'ð¿¶'), + ('ð‘€€', 'ð‘€€'), + ('𑀂', 'ð‘€·'), + ('ð‘‡', 'ð‘'), + ('ð‘’', 'ð‘¯'), + ('ð‘±', 'ð‘²'), + ('ð‘µ', 'ð‘µ'), + ('ð‘‚‚', 'ð‘‚²'), + ('ð‘‚·', '𑂸'), + ('ð‘‚»', 'ð‘‚¼'), + ('ð‘‚¾', 'ð‘ƒ'), + ('ð‘ƒ', '𑃨'), + ('𑃰', '𑃹'), + ('𑄃', '𑄦'), + ('𑄬', '𑄬'), + ('𑄶', 'ð‘…‡'), + ('ð‘…', 'ð‘…²'), + ('ð‘…´', 'ð‘…¶'), + ('𑆂', '𑆵'), + ('𑆿', '𑇈'), + ('ð‘‡', '𑇎'), + ('ð‘‡', '𑇟'), + ('𑇡', '𑇴'), + ('𑈀', '𑈑'), + ('𑈓', '𑈮'), + ('𑈲', '𑈳'), + ('𑈵', '𑈵'), + ('𑈸', '𑈽'), + ('𑈿', '𑉀'), + ('ð‘Š€', '𑊆'), + ('𑊈', '𑊈'), + ('ð‘ŠŠ', 'ð‘Š'), + ('ð‘Š', 'ð‘Š'), + ('ð‘ŠŸ', 'ð‘Š©'), + ('ð‘Š°', 'ð‘‹ž'), + ('ð‘‹ ', 'ð‘‹¢'), + ('ð‘‹°', 'ð‘‹¹'), + ('𑌂', '𑌃'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('𑌽', '𑌽'), + ('𑌿', '𑌿'), + ('ð‘', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘'), + ('ð‘', 'ð‘'), + ('ð‘', 'ð‘£'), + ('ð‘€', 'ð‘·'), + ('ð‘‘€', 'ð‘‘'), + ('ð‘‘…', 'ð‘‘…'), + ('𑑇', 'ð‘‘›'), + ('ð‘‘', 'ð‘‘'), + ('ð‘‘Ÿ', 'ð‘‘¡'), + ('ð‘’€', 'ð‘’¯'), + ('ð‘’±', 'ð‘’²'), + ('ð‘’¹', 'ð‘’¹'), + ('ð‘’»', 'ð‘’¼'), + ('ð‘’¾', 'ð‘’¾'), + ('ð‘“', 'ð‘“'), + ('ð‘“„', '𑓇'), + ('ð‘“', 'ð‘“™'), + ('ð‘–€', 'ð‘–®'), + ('ð‘–°', 'ð‘–±'), + ('ð‘–¸', 'ð‘–»'), + ('ð‘–¾', 'ð‘–¾'), + ('ð‘—', 'ð‘—›'), + ('𑘀', '𑘲'), + ('𑘻', '𑘼'), + ('𑘾', '𑘾'), + ('ð‘™', 'ð‘™„'), + ('ð‘™', 'ð‘™™'), + ('ð‘™ ', '𑙬'), + ('𑚀', '𑚪'), + ('𑚬', '𑚬'), + ('ð‘š®', '𑚯'), + ('𑚶', '𑚶'), + ('𑚸', 'ð‘š¹'), + ('𑛀', '𑛉'), + ('𑜀', '𑜚'), + ('𑜠', '𑜡'), + ('𑜦', '𑜦'), + ('𑜰', 'ð‘†'), + ('ð‘ €', 'ð‘ ®'), + ('ð‘ ¸', 'ð‘ ¸'), + ('ð‘ »', 'ð‘ »'), + ('ð‘¢ ', 'ð‘£²'), + ('𑣿', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤯'), + ('𑤱', '𑤵'), + ('𑤷', '𑤸'), + ('𑤽', '𑤽'), + ('𑤿', '𑥂'), + ('𑥄', '𑥆'), + ('ð‘¥', 'ð‘¥™'), + ('𑦠', '𑦧'), + ('𑦪', '𑧓'), + ('𑧜', '𑧟'), + ('𑧡', '𑧤'), + ('𑨀', '𑨀'), + ('𑨋', '𑨲'), + ('𑨹', '𑨺'), + ('𑨿', '𑩆'), + ('ð‘©', 'ð‘©'), + ('ð‘©—', '𑩘'), + ('ð‘©œ', '𑪉'), + ('𑪗', '𑪗'), + ('𑪚', '𑪢'), + ('𑪰', '𑫸'), + ('𑬀', '𑬉'), + ('ð‘°€', 'ð‘°ˆ'), + ('ð‘°Š', 'ð‘°¯'), + ('ð‘°¾', 'ð‘°¾'), + ('𑱀', '𑱅'), + ('ð‘±', '𑱬'), + ('𑱰', 'ð‘²'), + ('𑲩', '𑲩'), + ('𑲱', '𑲱'), + ('𑲴', '𑲴'), + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', 'ð‘´°'), + ('𑵆', '𑵆'), + ('ð‘µ', '𑵙'), + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶎'), + ('𑶓', '𑶔'), + ('𑶖', '𑶖'), + ('𑶘', '𑶘'), + ('𑶠', '𑶩'), + ('ð‘» ', 'ð‘»²'), + ('ð‘»µ', '𑻸'), + ('𑼂', 'ð‘¼'), + ('𑼒', '𑼵'), + ('𑼾', '𑼿'), + ('ð‘½', 'ð‘½'), + ('𑽃', '𑽙'), + ('𑾰', '𑾰'), + ('ð‘¿€', 'ð‘¿±'), + ('ð‘¿¿', 'ð’Ž™'), + ('ð’€', 'ð’‘®'), + ('ð’‘°', 'ð’‘´'), + ('ð’’€', '𒕃'), + ('ð’¾', 'ð’¿²'), + ('ð“€€', 'ð“¯'), + ('ð“‘', '𓑆'), + ('ð”€', '𔙆'), + ('ð– €', '𖨸'), + ('ð–©€', 'ð–©ž'), + ('ð–© ', 'ð–©©'), + ('ð–©®', '𖪾'), + ('ð–«€', '𖫉'), + ('ð–«', 'ð–«­'), + ('ð–«µ', 'ð–«µ'), + ('𖬀', '𖬯'), + ('ð–¬·', 'ð–­…'), + ('ð–­', 'ð–­™'), + ('ð–­›', 'ð–­¡'), + ('ð–­£', 'ð–­·'), + ('ð–­½', 'ð–®'), + ('ð–¹€', '𖺚'), + ('ð–¼€', '𖽊'), + ('ð–½', '𖾇'), + ('𖾓', '𖾟'), + ('ð–¿ ', 'ð–¿£'), + ('ð–¿°', 'ð–¿±'), + ('ð—€€', '𘟷'), + ('𘠀', '𘳕'), + ('𘴀', '𘴈'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𛀀', '𛄢'), + ('𛄲', '𛄲'), + ('ð›…', 'ð›…’'), + ('ð›…•', 'ð›…•'), + ('ð›…¤', 'ð›…§'), + ('ð›…°', '𛋻'), + ('ð›°€', '𛱪'), + ('ð›±°', 'ð›±¼'), + ('𛲀', '𛲈'), + ('ð›²', '𛲙'), + ('𛲜', '𛲜'), + ('𛲟', '𛲟'), + ('ðœ½', '𜿃'), + ('ð€€', 'ðƒµ'), + ('ð„€', 'ð„¦'), + ('ð„©', 'ð…¤'), + ('ð…¦', 'ð…¦'), + ('ð…ª', 'ð…­'), + ('ð†ƒ', 'ð†„'), + ('ð†Œ', 'ð†©'), + ('ð†®', 'ð‡ª'), + ('ðˆ€', 'ð‰'), + ('ð‰…', 'ð‰…'), + ('ð‹€', 'ð‹“'), + ('ð‹ ', 'ð‹³'), + ('ðŒ€', 'ð–'), + ('ð ', 'ð¸'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ðŸ‹'), + ('ðŸŽ', 'ð§¿'), + ('ð¨·', 'ð¨º'), + ('ð©­', 'ð©´'), + ('ð©¶', 'ðªƒ'), + ('ðª…', 'ðª‹'), + ('ð¼€', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('𞀰', 'ðž­'), + ('ðž„€', '𞄬'), + ('ðž„·', '𞄽'), + ('ðž…€', 'ðž…‰'), + ('ðž…Ž', 'ðž…'), + ('ðžŠ', '𞊭'), + ('ðž‹€', 'ðž‹«'), + ('ðž‹°', '𞋹'), + ('ðž‹¿', 'ðž‹¿'), + ('ðž“', 'ðž“«'), + ('ðž“°', '𞓹'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), + ('ðž €', '𞣄'), + ('𞣇', 'ðž£'), + ('𞤀', '𞥃'), + ('𞥋', '𞥋'), + ('ðž¥', '𞥙'), + ('𞥞', '𞥟'), + ('ðž±±', 'ðž²´'), + ('ðž´', 'ðž´½'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('ðž»°', 'ðž»±'), + ('🀀', '🀫'), + ('🀰', '🂓'), + ('🂠', '🂮'), + ('🂱', '🂿'), + ('ðŸƒ', 'ðŸƒ'), + ('🃑', '🃵'), + ('🄀', '🆭'), + ('🇦', '🈂'), + ('ðŸˆ', '🈻'), + ('🉀', '🉈'), + ('ðŸ‰', '🉑'), + ('🉠', '🉥'), + ('🌀', '🛗'), + ('🛜', '🛬'), + ('🛰', '🛼'), + ('🜀', 'ðŸ¶'), + ('ðŸ»', '🟙'), + ('🟠', '🟫'), + ('🟰', '🟰'), + ('🠀', '🠋'), + ('ðŸ ', '🡇'), + ('ðŸ¡', '🡙'), + ('🡠', '🢇'), + ('ðŸ¢', '🢭'), + ('🢰', '🢱'), + ('🤀', '🩓'), + ('🩠', '🩭'), + ('🩰', '🩼'), + ('🪀', '🪈'), + ('ðŸª', '🪽'), + ('🪿', '🫅'), + ('🫎', '🫛'), + ('🫠', '🫨'), + ('🫰', '🫸'), + ('🬀', '🮒'), + ('🮔', '🯊'), + ('🯰', '🯹'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('丽', 'ð¯¨'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), +]; + +pub const GRAPHEME_EXTEND: &'static [(char, char)] = &[ + ('\u{300}', '\u{36f}'), + ('\u{483}', '\u{489}'), + ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), + ('\u{610}', '\u{61a}'), + ('\u{64b}', '\u{65f}'), + ('\u{670}', '\u{670}'), + ('\u{6d6}', '\u{6dc}'), + ('\u{6df}', '\u{6e4}'), + ('\u{6e7}', '\u{6e8}'), + ('\u{6ea}', '\u{6ed}'), + ('\u{711}', '\u{711}'), + ('\u{730}', '\u{74a}'), + ('\u{7a6}', '\u{7b0}'), + ('\u{7eb}', '\u{7f3}'), + ('\u{7fd}', '\u{7fd}'), + ('\u{816}', '\u{819}'), + ('\u{81b}', '\u{823}'), + ('\u{825}', '\u{827}'), + ('\u{829}', '\u{82d}'), + ('\u{859}', '\u{85b}'), + ('\u{898}', '\u{89f}'), + ('\u{8ca}', '\u{8e1}'), + ('\u{8e3}', '\u{902}'), + ('\u{93a}', '\u{93a}'), + ('\u{93c}', '\u{93c}'), + ('\u{941}', '\u{948}'), + ('\u{94d}', '\u{94d}'), + ('\u{951}', '\u{957}'), + ('\u{962}', '\u{963}'), + ('\u{981}', '\u{981}'), + ('\u{9bc}', '\u{9bc}'), + ('\u{9be}', '\u{9be}'), + ('\u{9c1}', '\u{9c4}'), + ('\u{9cd}', '\u{9cd}'), + ('\u{9d7}', '\u{9d7}'), + ('\u{9e2}', '\u{9e3}'), + ('\u{9fe}', '\u{9fe}'), + ('\u{a01}', '\u{a02}'), + ('\u{a3c}', '\u{a3c}'), + ('\u{a41}', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), + ('\u{a70}', '\u{a71}'), + ('\u{a75}', '\u{a75}'), + ('\u{a81}', '\u{a82}'), + ('\u{abc}', '\u{abc}'), + ('\u{ac1}', '\u{ac5}'), + ('\u{ac7}', '\u{ac8}'), + ('\u{acd}', '\u{acd}'), + ('\u{ae2}', '\u{ae3}'), + ('\u{afa}', '\u{aff}'), + ('\u{b01}', '\u{b01}'), + ('\u{b3c}', '\u{b3c}'), + ('\u{b3e}', '\u{b3f}'), + ('\u{b41}', '\u{b44}'), + ('\u{b4d}', '\u{b4d}'), + ('\u{b55}', '\u{b57}'), + ('\u{b62}', '\u{b63}'), + ('\u{b82}', '\u{b82}'), + ('\u{bbe}', '\u{bbe}'), + ('\u{bc0}', '\u{bc0}'), + ('\u{bcd}', '\u{bcd}'), + ('\u{bd7}', '\u{bd7}'), + ('\u{c00}', '\u{c00}'), + ('\u{c04}', '\u{c04}'), + ('\u{c3c}', '\u{c3c}'), + ('\u{c3e}', '\u{c40}'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('\u{c62}', '\u{c63}'), + ('\u{c81}', '\u{c81}'), + ('\u{cbc}', '\u{cbc}'), + ('\u{cbf}', '\u{cbf}'), + ('\u{cc2}', '\u{cc2}'), + ('\u{cc6}', '\u{cc6}'), + ('\u{ccc}', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), + ('\u{ce2}', '\u{ce3}'), + ('\u{d00}', '\u{d01}'), + ('\u{d3b}', '\u{d3c}'), + ('\u{d3e}', '\u{d3e}'), + ('\u{d41}', '\u{d44}'), + ('\u{d4d}', '\u{d4d}'), + ('\u{d57}', '\u{d57}'), + ('\u{d62}', '\u{d63}'), + ('\u{d81}', '\u{d81}'), + ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dcf}'), + ('\u{dd2}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('\u{ddf}', '\u{ddf}'), + ('\u{e31}', '\u{e31}'), + ('\u{e34}', '\u{e3a}'), + ('\u{e47}', '\u{e4e}'), + ('\u{eb1}', '\u{eb1}'), + ('\u{eb4}', '\u{ebc}'), + ('\u{ec8}', '\u{ece}'), + ('\u{f18}', '\u{f19}'), + ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), + ('\u{f39}', '\u{f39}'), + ('\u{f71}', '\u{f7e}'), + ('\u{f80}', '\u{f84}'), + ('\u{f86}', '\u{f87}'), + ('\u{f8d}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('\u{fc6}', '\u{fc6}'), + ('\u{102d}', '\u{1030}'), + ('\u{1032}', '\u{1037}'), + ('\u{1039}', '\u{103a}'), + ('\u{103d}', '\u{103e}'), + ('\u{1058}', '\u{1059}'), + ('\u{105e}', '\u{1060}'), + ('\u{1071}', '\u{1074}'), + ('\u{1082}', '\u{1082}'), + ('\u{1085}', '\u{1086}'), + ('\u{108d}', '\u{108d}'), + ('\u{109d}', '\u{109d}'), + ('\u{135d}', '\u{135f}'), + ('\u{1712}', '\u{1714}'), + ('\u{1732}', '\u{1733}'), + ('\u{1752}', '\u{1753}'), + ('\u{1772}', '\u{1773}'), + ('\u{17b4}', '\u{17b5}'), + ('\u{17b7}', '\u{17bd}'), + ('\u{17c6}', '\u{17c6}'), + ('\u{17c9}', '\u{17d3}'), + ('\u{17dd}', '\u{17dd}'), + ('\u{180b}', '\u{180d}'), + ('\u{180f}', '\u{180f}'), + ('\u{1885}', '\u{1886}'), + ('\u{18a9}', '\u{18a9}'), + ('\u{1920}', '\u{1922}'), + ('\u{1927}', '\u{1928}'), + ('\u{1932}', '\u{1932}'), + ('\u{1939}', '\u{193b}'), + ('\u{1a17}', '\u{1a18}'), + ('\u{1a1b}', '\u{1a1b}'), + ('\u{1a56}', '\u{1a56}'), + ('\u{1a58}', '\u{1a5e}'), + ('\u{1a60}', '\u{1a60}'), + ('\u{1a62}', '\u{1a62}'), + ('\u{1a65}', '\u{1a6c}'), + ('\u{1a73}', '\u{1a7c}'), + ('\u{1a7f}', '\u{1a7f}'), + ('\u{1ab0}', '\u{1ace}'), + ('\u{1b00}', '\u{1b03}'), + ('\u{1b34}', '\u{1b3a}'), + ('\u{1b3c}', '\u{1b3c}'), + ('\u{1b42}', '\u{1b42}'), + ('\u{1b6b}', '\u{1b73}'), + ('\u{1b80}', '\u{1b81}'), + ('\u{1ba2}', '\u{1ba5}'), + ('\u{1ba8}', '\u{1ba9}'), + ('\u{1bab}', '\u{1bad}'), + ('\u{1be6}', '\u{1be6}'), + ('\u{1be8}', '\u{1be9}'), + ('\u{1bed}', '\u{1bed}'), + ('\u{1bef}', '\u{1bf1}'), + ('\u{1c2c}', '\u{1c33}'), + ('\u{1c36}', '\u{1c37}'), + ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', '\u{1ce0}'), + ('\u{1ce2}', '\u{1ce8}'), + ('\u{1ced}', '\u{1ced}'), + ('\u{1cf4}', '\u{1cf4}'), + ('\u{1cf8}', '\u{1cf9}'), + ('\u{1dc0}', '\u{1dff}'), + ('\u{200c}', '\u{200c}'), + ('\u{20d0}', '\u{20f0}'), + ('\u{2cef}', '\u{2cf1}'), + ('\u{2d7f}', '\u{2d7f}'), + ('\u{2de0}', '\u{2dff}'), + ('\u{302a}', '\u{302f}'), + ('\u{3099}', '\u{309a}'), + ('\u{a66f}', '\u{a672}'), + ('\u{a674}', '\u{a67d}'), + ('\u{a69e}', '\u{a69f}'), + ('\u{a6f0}', '\u{a6f1}'), + ('\u{a802}', '\u{a802}'), + ('\u{a806}', '\u{a806}'), + ('\u{a80b}', '\u{a80b}'), + ('\u{a825}', '\u{a826}'), + ('\u{a82c}', '\u{a82c}'), + ('\u{a8c4}', '\u{a8c5}'), + ('\u{a8e0}', '\u{a8f1}'), + ('\u{a8ff}', '\u{a8ff}'), + ('\u{a926}', '\u{a92d}'), + ('\u{a947}', '\u{a951}'), + ('\u{a980}', '\u{a982}'), + ('\u{a9b3}', '\u{a9b3}'), + ('\u{a9b6}', '\u{a9b9}'), + ('\u{a9bc}', '\u{a9bd}'), + ('\u{a9e5}', '\u{a9e5}'), + ('\u{aa29}', '\u{aa2e}'), + ('\u{aa31}', '\u{aa32}'), + ('\u{aa35}', '\u{aa36}'), + ('\u{aa43}', '\u{aa43}'), + ('\u{aa4c}', '\u{aa4c}'), + ('\u{aa7c}', '\u{aa7c}'), + ('\u{aab0}', '\u{aab0}'), + ('\u{aab2}', '\u{aab4}'), + ('\u{aab7}', '\u{aab8}'), + ('\u{aabe}', '\u{aabf}'), + ('\u{aac1}', '\u{aac1}'), + ('\u{aaec}', '\u{aaed}'), + ('\u{aaf6}', '\u{aaf6}'), + ('\u{abe5}', '\u{abe5}'), + ('\u{abe8}', '\u{abe8}'), + ('\u{abed}', '\u{abed}'), + ('\u{fb1e}', '\u{fb1e}'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{fe20}', '\u{fe2f}'), + ('\u{ff9e}', '\u{ff9f}'), + ('\u{101fd}', '\u{101fd}'), + ('\u{102e0}', '\u{102e0}'), + ('\u{10376}', '\u{1037a}'), + ('\u{10a01}', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), + ('\u{10ae5}', '\u{10ae6}'), + ('\u{10d24}', '\u{10d27}'), + ('\u{10eab}', '\u{10eac}'), + ('\u{10efd}', '\u{10eff}'), + ('\u{10f46}', '\u{10f50}'), + ('\u{10f82}', '\u{10f85}'), + ('\u{11001}', '\u{11001}'), + ('\u{11038}', '\u{11046}'), + ('\u{11070}', '\u{11070}'), + ('\u{11073}', '\u{11074}'), + ('\u{1107f}', '\u{11081}'), + ('\u{110b3}', '\u{110b6}'), + ('\u{110b9}', '\u{110ba}'), + ('\u{110c2}', '\u{110c2}'), + ('\u{11100}', '\u{11102}'), + ('\u{11127}', '\u{1112b}'), + ('\u{1112d}', '\u{11134}'), + ('\u{11173}', '\u{11173}'), + ('\u{11180}', '\u{11181}'), + ('\u{111b6}', '\u{111be}'), + ('\u{111c9}', '\u{111cc}'), + ('\u{111cf}', '\u{111cf}'), + ('\u{1122f}', '\u{11231}'), + ('\u{11234}', '\u{11234}'), + ('\u{11236}', '\u{11237}'), + ('\u{1123e}', '\u{1123e}'), + ('\u{11241}', '\u{11241}'), + ('\u{112df}', '\u{112df}'), + ('\u{112e3}', '\u{112ea}'), + ('\u{11300}', '\u{11301}'), + ('\u{1133b}', '\u{1133c}'), + ('\u{1133e}', '\u{1133e}'), + ('\u{11340}', '\u{11340}'), + ('\u{11357}', '\u{11357}'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('\u{11438}', '\u{1143f}'), + ('\u{11442}', '\u{11444}'), + ('\u{11446}', '\u{11446}'), + ('\u{1145e}', '\u{1145e}'), + ('\u{114b0}', '\u{114b0}'), + ('\u{114b3}', '\u{114b8}'), + ('\u{114ba}', '\u{114ba}'), + ('\u{114bd}', '\u{114bd}'), + ('\u{114bf}', '\u{114c0}'), + ('\u{114c2}', '\u{114c3}'), + ('\u{115af}', '\u{115af}'), + ('\u{115b2}', '\u{115b5}'), + ('\u{115bc}', '\u{115bd}'), + ('\u{115bf}', '\u{115c0}'), + ('\u{115dc}', '\u{115dd}'), + ('\u{11633}', '\u{1163a}'), + ('\u{1163d}', '\u{1163d}'), + ('\u{1163f}', '\u{11640}'), + ('\u{116ab}', '\u{116ab}'), + ('\u{116ad}', '\u{116ad}'), + ('\u{116b0}', '\u{116b5}'), + ('\u{116b7}', '\u{116b7}'), + ('\u{1171d}', '\u{1171f}'), + ('\u{11722}', '\u{11725}'), + ('\u{11727}', '\u{1172b}'), + ('\u{1182f}', '\u{11837}'), + ('\u{11839}', '\u{1183a}'), + ('\u{11930}', '\u{11930}'), + ('\u{1193b}', '\u{1193c}'), + ('\u{1193e}', '\u{1193e}'), + ('\u{11943}', '\u{11943}'), + ('\u{119d4}', '\u{119d7}'), + ('\u{119da}', '\u{119db}'), + ('\u{119e0}', '\u{119e0}'), + ('\u{11a01}', '\u{11a0a}'), + ('\u{11a33}', '\u{11a38}'), + ('\u{11a3b}', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), + ('\u{11a51}', '\u{11a56}'), + ('\u{11a59}', '\u{11a5b}'), + ('\u{11a8a}', '\u{11a96}'), + ('\u{11a98}', '\u{11a99}'), + ('\u{11c30}', '\u{11c36}'), + ('\u{11c38}', '\u{11c3d}'), + ('\u{11c3f}', '\u{11c3f}'), + ('\u{11c92}', '\u{11ca7}'), + ('\u{11caa}', '\u{11cb0}'), + ('\u{11cb2}', '\u{11cb3}'), + ('\u{11cb5}', '\u{11cb6}'), + ('\u{11d31}', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d45}'), + ('\u{11d47}', '\u{11d47}'), + ('\u{11d90}', '\u{11d91}'), + ('\u{11d95}', '\u{11d95}'), + ('\u{11d97}', '\u{11d97}'), + ('\u{11ef3}', '\u{11ef4}'), + ('\u{11f00}', '\u{11f01}'), + ('\u{11f36}', '\u{11f3a}'), + ('\u{11f40}', '\u{11f40}'), + ('\u{11f42}', '\u{11f42}'), + ('\u{13440}', '\u{13440}'), + ('\u{13447}', '\u{13455}'), + ('\u{16af0}', '\u{16af4}'), + ('\u{16b30}', '\u{16b36}'), + ('\u{16f4f}', '\u{16f4f}'), + ('\u{16f8f}', '\u{16f92}'), + ('\u{16fe4}', '\u{16fe4}'), + ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('\u{1d165}', '\u{1d165}'), + ('\u{1d167}', '\u{1d169}'), + ('\u{1d16e}', '\u{1d172}'), + ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), + ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), + ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), + ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('\u{1e08f}', '\u{1e08f}'), + ('\u{1e130}', '\u{1e136}'), + ('\u{1e2ae}', '\u{1e2ae}'), + ('\u{1e2ec}', '\u{1e2ef}'), + ('\u{1e4ec}', '\u{1e4ef}'), + ('\u{1e8d0}', '\u{1e8d6}'), + ('\u{1e944}', '\u{1e94a}'), + ('\u{e0020}', '\u{e007f}'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const GRAPHEME_LINK: &'static [(char, char)] = &[ + ('\u{94d}', '\u{94d}'), + ('\u{9cd}', '\u{9cd}'), + ('\u{a4d}', '\u{a4d}'), + ('\u{acd}', '\u{acd}'), + ('\u{b4d}', '\u{b4d}'), + ('\u{bcd}', '\u{bcd}'), + ('\u{c4d}', '\u{c4d}'), + ('\u{ccd}', '\u{ccd}'), + ('\u{d3b}', '\u{d3c}'), + ('\u{d4d}', '\u{d4d}'), + ('\u{dca}', '\u{dca}'), + ('\u{e3a}', '\u{e3a}'), + ('\u{eba}', '\u{eba}'), + ('\u{f84}', '\u{f84}'), + ('\u{1039}', '\u{103a}'), + ('\u{1714}', '᜕'), + ('᜴', '᜴'), + ('\u{17d2}', '\u{17d2}'), + ('\u{1a60}', '\u{1a60}'), + ('á­„', 'á­„'), + ('᮪', '\u{1bab}'), + ('᯲', '᯳'), + ('\u{2d7f}', '\u{2d7f}'), + ('\u{a806}', '\u{a806}'), + ('\u{a82c}', '\u{a82c}'), + ('\u{a8c4}', '\u{a8c4}'), + ('꥓', '꥓'), + ('꧀', '꧀'), + ('\u{aaf6}', '\u{aaf6}'), + ('\u{abed}', '\u{abed}'), + ('\u{10a3f}', '\u{10a3f}'), + ('\u{11046}', '\u{11046}'), + ('\u{11070}', '\u{11070}'), + ('\u{1107f}', '\u{1107f}'), + ('\u{110b9}', '\u{110b9}'), + ('\u{11133}', '\u{11134}'), + ('𑇀', '𑇀'), + ('𑈵', '𑈵'), + ('\u{112ea}', '\u{112ea}'), + ('ð‘', 'ð‘'), + ('\u{11442}', '\u{11442}'), + ('\u{114c2}', '\u{114c2}'), + ('\u{115bf}', '\u{115bf}'), + ('\u{1163f}', '\u{1163f}'), + ('𑚶', '𑚶'), + ('\u{1172b}', '\u{1172b}'), + ('\u{11839}', '\u{11839}'), + ('𑤽', '\u{1193e}'), + ('\u{119e0}', '\u{119e0}'), + ('\u{11a34}', '\u{11a34}'), + ('\u{11a47}', '\u{11a47}'), + ('\u{11a99}', '\u{11a99}'), + ('\u{11c3f}', '\u{11c3f}'), + ('\u{11d44}', '\u{11d45}'), + ('\u{11d97}', '\u{11d97}'), + ('ð‘½', '\u{11f42}'), +]; + +pub const HEX_DIGIT: &'static [(char, char)] = &[ + ('0', '9'), + ('A', 'F'), + ('a', 'f'), + ('ï¼', 'ï¼™'), + ('A', 'F'), + ('ï½', 'f'), +]; + +pub const HYPHEN: &'static [(char, char)] = &[ + ('-', '-'), + ('\u{ad}', '\u{ad}'), + ('ÖŠ', 'ÖŠ'), + ('á †', 'á †'), + ('â€', '‑'), + ('⸗', '⸗'), + ('・', '・'), + ('ï¹£', 'ï¹£'), + ('ï¼', 'ï¼'), + ('ï½¥', 'ï½¥'), +]; + +pub const IDS_BINARY_OPERATOR: &'static [(char, char)] = + &[('â¿°', '⿱'), ('â¿´', 'â¿»')]; + +pub const IDS_TRINARY_OPERATOR: &'static [(char, char)] = &[('⿲', '⿳')]; + +pub const ID_CONTINUE: &'static [(char, char)] = &[ + ('0', '9'), + ('A', 'Z'), + ('_', '_'), + ('a', 'z'), + ('ª', 'ª'), + ('µ', 'µ'), + ('·', '·'), + ('º', 'º'), + ('À', 'Ö'), + ('Ø', 'ö'), + ('ø', 'Ë'), + ('ˆ', 'Ë‘'), + ('Ë ', 'ˤ'), + ('ˬ', 'ˬ'), + ('Ë®', 'Ë®'), + ('\u{300}', 'Í´'), + ('Ͷ', 'Í·'), + ('ͺ', 'ͽ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'ϵ'), + ('Ï·', 'Ò'), + ('\u{483}', '\u{487}'), + ('ÒŠ', 'Ô¯'), + ('Ô±', 'Õ–'), + ('Õ™', 'Õ™'), + ('Õ ', 'Öˆ'), + ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), + ('×', 'ת'), + ('ׯ', 'ײ'), + ('\u{610}', '\u{61a}'), + ('Ø ', 'Ù©'), + ('Ù®', 'Û“'), + ('Û•', '\u{6dc}'), + ('\u{6df}', '\u{6e8}'), + ('\u{6ea}', 'Û¼'), + ('Û¿', 'Û¿'), + ('Ü', '\u{74a}'), + ('Ý', 'Þ±'), + ('߀', 'ßµ'), + ('ߺ', 'ߺ'), + ('\u{7fd}', '\u{7fd}'), + ('à €', '\u{82d}'), + ('à¡€', '\u{85b}'), + ('à¡ ', 'ࡪ'), + ('à¡°', 'ࢇ'), + ('ࢉ', 'ࢎ'), + ('\u{898}', '\u{8e1}'), + ('\u{8e3}', '\u{963}'), + ('०', '९'), + ('ॱ', 'ঃ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('\u{9bc}', '\u{9c4}'), + ('ে', 'ৈ'), + ('ো', 'ৎ'), + ('\u{9d7}', '\u{9d7}'), + ('ড়', 'à§'), + ('য়', '\u{9e3}'), + ('০', 'ৱ'), + ('ৼ', 'ৼ'), + ('\u{9fe}', '\u{9fe}'), + ('\u{a01}', 'ਃ'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('\u{a3c}', '\u{a3c}'), + ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('੦', '\u{a75}'), + ('\u{a81}', 'ઃ'), + ('અ', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('\u{abc}', '\u{ac5}'), + ('\u{ac7}', 'ૉ'), + ('à«‹', '\u{acd}'), + ('à«', 'à«'), + ('à« ', '\u{ae3}'), + ('૦', '૯'), + ('ૹ', '\u{aff}'), + ('\u{b01}', 'ଃ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), + ('\u{b3c}', '\u{b44}'), + ('à­‡', 'à­ˆ'), + ('à­‹', '\u{b4d}'), + ('\u{b55}', '\u{b57}'), + ('à­œ', 'à­'), + ('à­Ÿ', '\u{b63}'), + ('à­¦', 'à­¯'), + ('à­±', 'à­±'), + ('\u{b82}', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'ஹ'), + ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), + ('ொ', '\u{bcd}'), + ('à¯', 'à¯'), + ('\u{bd7}', '\u{bd7}'), + ('௦', '௯'), + ('\u{c00}', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°¹'), + ('\u{c3c}', 'ౄ'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('ౘ', 'ౚ'), + ('à±', 'à±'), + ('à± ', '\u{c63}'), + ('౦', '౯'), + ('ಀ', 'ಃ'), + ('ಅ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('\u{cbc}', 'ೄ'), + ('\u{cc6}', 'ೈ'), + ('ೊ', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), + ('à³', 'ೞ'), + ('à³ ', '\u{ce3}'), + ('೦', '೯'), + ('à³±', 'à³³'), + ('\u{d00}', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', '\u{d44}'), + ('െ', 'ൈ'), + ('ൊ', 'ൎ'), + ('ൔ', '\u{d57}'), + ('ൟ', '\u{d63}'), + ('൦', '൯'), + ('ൺ', 'ൿ'), + ('\u{d81}', 'ඃ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('à·˜', '\u{ddf}'), + ('à·¦', 'à·¯'), + ('à·²', 'à·³'), + ('à¸', '\u{e3a}'), + ('เ', '\u{e4e}'), + ('à¹', '๙'), + ('àº', 'ຂ'), + ('ຄ', 'ຄ'), + ('ຆ', 'ຊ'), + ('ຌ', 'ຣ'), + ('ລ', 'ລ'), + ('ວ', 'ຽ'), + ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), + ('\u{ec8}', '\u{ece}'), + ('à»', 'à»™'), + ('ໜ', 'ໟ'), + ('ༀ', 'ༀ'), + ('\u{f18}', '\u{f19}'), + ('༠', '༩'), + ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), + ('\u{f39}', '\u{f39}'), + ('༾', 'ཇ'), + ('ཉ', 'ཬ'), + ('\u{f71}', '\u{f84}'), + ('\u{f86}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('\u{fc6}', '\u{fc6}'), + ('က', 'á‰'), + ('á', '\u{109d}'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ჺ'), + ('ჼ', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹–'), + ('ዘ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'áš'), + ('\u{135d}', '\u{135f}'), + ('á©', 'á±'), + ('ᎀ', 'áŽ'), + ('Ꭰ', 'áµ'), + ('á¸', 'á½'), + ('á', 'ᙬ'), + ('ᙯ', 'ᙿ'), + ('áš', 'ášš'), + ('áš ', 'ᛪ'), + ('á›®', 'ᛸ'), + ('ᜀ', '᜕'), + ('ᜟ', '᜴'), + ('á€', '\u{1753}'), + ('á ', 'á¬'), + ('á®', 'á°'), + ('\u{1772}', '\u{1773}'), + ('ក', '\u{17d3}'), + ('ៗ', 'ៗ'), + ('ៜ', '\u{17dd}'), + ('០', '៩'), + ('\u{180b}', '\u{180d}'), + ('\u{180f}', 'á ™'), + ('á  ', 'ᡸ'), + ('ᢀ', 'ᢪ'), + ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), + ('\u{1920}', 'ᤫ'), + ('ᤰ', '\u{193b}'), + ('᥆', 'ᥭ'), + ('ᥰ', 'ᥴ'), + ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), + ('á§', '᧚'), + ('ᨀ', '\u{1a1b}'), + ('ᨠ', '\u{1a5e}'), + ('\u{1a60}', '\u{1a7c}'), + ('\u{1a7f}', '᪉'), + ('áª', '᪙'), + ('ᪧ', 'ᪧ'), + ('\u{1ab0}', '\u{1abd}'), + ('\u{1abf}', '\u{1ace}'), + ('\u{1b00}', 'á­Œ'), + ('á­', 'á­™'), + ('\u{1b6b}', '\u{1b73}'), + ('\u{1b80}', '᯳'), + ('á°€', '\u{1c37}'), + ('á±€', '᱉'), + ('á±', 'á±½'), + ('á²€', 'ᲈ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', 'ᳺ'), + ('á´€', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¾¼'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'á¿Œ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), + ('ῶ', 'ῼ'), + ('‿', 'â€'), + ('â”', 'â”'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('\u{20d0}', '\u{20dc}'), + ('\u{20e1}', '\u{20e1}'), + ('\u{20e5}', '\u{20f0}'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„Š', 'â„“'), + ('â„•', 'â„•'), + ('℘', 'â„'), + ('ℤ', 'ℤ'), + ('Ω', 'Ω'), + ('ℨ', 'ℨ'), + ('K', 'ℹ'), + ('ℼ', 'â„¿'), + ('â……', 'â…‰'), + ('â…Ž', 'â…Ž'), + ('â… ', 'ↈ'), + ('â°€', 'ⳤ'), + ('Ⳬ', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('â´°', 'ⵧ'), + ('ⵯ', 'ⵯ'), + ('\u{2d7f}', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('\u{2de0}', '\u{2dff}'), + ('々', '〇'), + ('〡', '\u{302f}'), + ('〱', '〵'), + ('〸', '〼'), + ('ã', 'ã‚–'), + ('\u{3099}', 'ã‚Ÿ'), + ('ã‚¡', 'ヺ'), + ('ー', 'ヿ'), + ('ã„…', 'ㄯ'), + ('ㄱ', 'ㆎ'), + ('ㆠ', 'ㆿ'), + ('ㇰ', 'ㇿ'), + ('ã€', '䶿'), + ('一', 'ê’Œ'), + ('ê“', 'ꓽ'), + ('ꔀ', 'ꘌ'), + ('ê˜', 'ꘫ'), + ('Ꙁ', '\u{a66f}'), + ('\u{a674}', '\u{a67d}'), + ('ꙿ', '\u{a6f1}'), + ('ꜗ', 'ꜟ'), + ('Ꜣ', 'ꞈ'), + ('êž‹', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('ꟲ', 'ê §'), + ('\u{a82c}', '\u{a82c}'), + ('ê¡€', 'ꡳ'), + ('ꢀ', '\u{a8c5}'), + ('ê£', '꣙'), + ('\u{a8e0}', 'ꣷ'), + ('ꣻ', 'ꣻ'), + ('ꣽ', '\u{a92d}'), + ('ꤰ', '꥓'), + ('ꥠ', 'ꥼ'), + ('\u{a980}', '꧀'), + ('ê§', '꧙'), + ('ꧠ', 'ꧾ'), + ('ꨀ', '\u{aa36}'), + ('ê©€', 'ê©'), + ('ê©', 'ê©™'), + ('ê© ', 'ꩶ'), + ('ꩺ', 'ê«‚'), + ('ê«›', 'ê«'), + ('ê« ', 'ꫯ'), + ('ꫲ', '\u{aaf6}'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('ꬰ', 'ê­š'), + ('ê­œ', 'ê­©'), + ('ê­°', 'ꯪ'), + ('꯬', '\u{abed}'), + ('꯰', '꯹'), + ('ê°€', '힣'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), + ('ï©°', 'ï«™'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï¬', 'ﬨ'), + ('שׁ', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', 'ï®±'), + ('ﯓ', 'ï´½'), + ('ïµ', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·°', 'ï·»'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{fe20}', '\u{fe2f}'), + ('︳', '︴'), + ('ï¹', 'ï¹'), + ('ï¹°', 'ï¹´'), + ('ﹶ', 'ﻼ'), + ('ï¼', 'ï¼™'), + ('A', 'Z'), + ('_', '_'), + ('ï½', 'z'), + ('ヲ', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), + ('ð…€', 'ð…´'), + ('\u{101fd}', '\u{101fd}'), + ('ðŠ€', 'ðŠœ'), + ('ðŠ ', 'ð‹'), + ('\u{102e0}', '\u{102e0}'), + ('ðŒ€', 'ðŒŸ'), + ('ðŒ­', 'ðŠ'), + ('ð', '\u{1037a}'), + ('ðŽ€', 'ðŽ'), + ('ðŽ ', 'ðƒ'), + ('ðˆ', 'ð'), + ('ð‘', 'ð•'), + ('ð€', 'ð’'), + ('ð’ ', 'ð’©'), + ('ð’°', 'ð““'), + ('ð“˜', 'ð“»'), + ('ð”€', 'ð”§'), + ('ð”°', 'ð•£'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð˜€', 'ðœ¶'), + ('ð€', 'ð•'), + ('ð ', 'ð§'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð €', 'ð …'), + ('ð ˆ', 'ð ˆ'), + ('ð Š', 'ð µ'), + ('ð ·', 'ð ¸'), + ('ð ¼', 'ð ¼'), + ('ð ¿', 'ð¡•'), + ('ð¡ ', 'ð¡¶'), + ('ð¢€', 'ð¢ž'), + ('ð£ ', 'ð£²'), + ('ð£´', 'ð£µ'), + ('ð¤€', 'ð¤•'), + ('ð¤ ', 'ð¤¹'), + ('ð¦€', 'ð¦·'), + ('ð¦¾', 'ð¦¿'), + ('ð¨€', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨µ'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), + ('ð© ', 'ð©¼'), + ('ðª€', 'ðªœ'), + ('ð«€', 'ð«‡'), + ('ð«‰', '\u{10ae6}'), + ('ð¬€', 'ð¬µ'), + ('ð­€', 'ð­•'), + ('ð­ ', 'ð­²'), + ('ð®€', 'ð®‘'), + ('ð°€', 'ð±ˆ'), + ('ð²€', 'ð²²'), + ('ð³€', 'ð³²'), + ('ð´€', '\u{10d27}'), + ('ð´°', 'ð´¹'), + ('ðº€', 'ðº©'), + ('\u{10eab}', '\u{10eac}'), + ('ðº°', 'ðº±'), + ('\u{10efd}', 'ð¼œ'), + ('ð¼§', 'ð¼§'), + ('ð¼°', '\u{10f50}'), + ('ð½°', '\u{10f85}'), + ('ð¾°', 'ð¿„'), + ('ð¿ ', 'ð¿¶'), + ('ð‘€€', '\u{11046}'), + ('ð‘¦', 'ð‘µ'), + ('\u{1107f}', '\u{110ba}'), + ('\u{110c2}', '\u{110c2}'), + ('ð‘ƒ', '𑃨'), + ('𑃰', '𑃹'), + ('\u{11100}', '\u{11134}'), + ('𑄶', 'ð‘„¿'), + ('ð‘…„', 'ð‘…‡'), + ('ð‘…', '\u{11173}'), + ('ð‘…¶', 'ð‘…¶'), + ('\u{11180}', '𑇄'), + ('\u{111c9}', '\u{111cc}'), + ('𑇎', '𑇚'), + ('𑇜', '𑇜'), + ('𑈀', '𑈑'), + ('𑈓', '\u{11237}'), + ('\u{1123e}', '\u{11241}'), + ('ð‘Š€', '𑊆'), + ('𑊈', '𑊈'), + ('ð‘ŠŠ', 'ð‘Š'), + ('ð‘Š', 'ð‘Š'), + ('ð‘ŠŸ', '𑊨'), + ('ð‘Š°', '\u{112ea}'), + ('ð‘‹°', 'ð‘‹¹'), + ('\u{11300}', '𑌃'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('\u{1133b}', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘'), + ('ð‘', 'ð‘'), + ('\u{11357}', '\u{11357}'), + ('ð‘', 'ð‘£'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('ð‘€', 'ð‘‘Š'), + ('ð‘‘', 'ð‘‘™'), + ('\u{1145e}', 'ð‘‘¡'), + ('ð‘’€', 'ð‘“…'), + ('𑓇', '𑓇'), + ('ð‘“', 'ð‘“™'), + ('ð‘–€', '\u{115b5}'), + ('ð‘–¸', '\u{115c0}'), + ('ð‘—˜', '\u{115dd}'), + ('𑘀', '\u{11640}'), + ('ð‘™„', 'ð‘™„'), + ('ð‘™', 'ð‘™™'), + ('𑚀', '𑚸'), + ('𑛀', '𑛉'), + ('𑜀', '𑜚'), + ('\u{1171d}', '\u{1172b}'), + ('𑜰', '𑜹'), + ('ð‘€', 'ð‘†'), + ('ð‘ €', '\u{1183a}'), + ('ð‘¢ ', '𑣩'), + ('𑣿', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤵'), + ('𑤷', '𑤸'), + ('\u{1193b}', '\u{11943}'), + ('ð‘¥', 'ð‘¥™'), + ('𑦠', '𑦧'), + ('𑦪', '\u{119d7}'), + ('\u{119da}', '𑧡'), + ('𑧣', '𑧤'), + ('𑨀', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), + ('ð‘©', '\u{11a99}'), + ('ð‘ª', 'ð‘ª'), + ('𑪰', '𑫸'), + ('ð‘°€', 'ð‘°ˆ'), + ('ð‘°Š', '\u{11c36}'), + ('\u{11c38}', '𑱀'), + ('ð‘±', '𑱙'), + ('𑱲', 'ð‘²'), + ('\u{11c92}', '\u{11ca7}'), + ('𑲩', '\u{11cb6}'), + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d47}'), + ('ð‘µ', '𑵙'), + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶎'), + ('\u{11d90}', '\u{11d91}'), + ('𑶓', '𑶘'), + ('𑶠', '𑶩'), + ('ð‘» ', '𑻶'), + ('\u{11f00}', 'ð‘¼'), + ('𑼒', '\u{11f3a}'), + ('𑼾', '\u{11f42}'), + ('ð‘½', '𑽙'), + ('𑾰', '𑾰'), + ('ð’€€', 'ð’Ž™'), + ('ð’€', 'ð’‘®'), + ('ð’’€', '𒕃'), + ('ð’¾', 'ð’¿°'), + ('ð“€€', 'ð“¯'), + ('\u{13440}', '\u{13455}'), + ('ð”€', '𔙆'), + ('ð– €', '𖨸'), + ('ð–©€', 'ð–©ž'), + ('ð–© ', 'ð–©©'), + ('ð–©°', '𖪾'), + ('ð–«€', '𖫉'), + ('ð–«', 'ð–«­'), + ('\u{16af0}', '\u{16af4}'), + ('𖬀', '\u{16b36}'), + ('ð–­€', 'ð–­ƒ'), + ('ð–­', 'ð–­™'), + ('ð–­£', 'ð–­·'), + ('ð–­½', 'ð–®'), + ('ð–¹€', '𖹿'), + ('ð–¼€', '𖽊'), + ('\u{16f4f}', '𖾇'), + ('\u{16f8f}', '𖾟'), + ('ð–¿ ', 'ð–¿¡'), + ('ð–¿£', '\u{16fe4}'), + ('ð–¿°', 'ð–¿±'), + ('ð—€€', '𘟷'), + ('𘠀', '𘳕'), + ('𘴀', '𘴈'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𛀀', '𛄢'), + ('𛄲', '𛄲'), + ('ð›…', 'ð›…’'), + ('ð›…•', 'ð›…•'), + ('ð›…¤', 'ð›…§'), + ('ð›…°', '𛋻'), + ('ð›°€', '𛱪'), + ('ð›±°', 'ð›±¼'), + ('𛲀', '𛲈'), + ('ð›²', '𛲙'), + ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('\u{1d165}', '\u{1d169}'), + ('ð…­', '\u{1d172}'), + ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ð›€'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›º'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ´'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð®'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž¨'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‹'), + ('ðŸŽ', 'ðŸ¿'), + ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), + ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), + ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), + ('ð¼€', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('𞀰', 'ðž­'), + ('\u{1e08f}', '\u{1e08f}'), + ('ðž„€', '𞄬'), + ('\u{1e130}', '𞄽'), + ('ðž…€', 'ðž…‰'), + ('ðž…Ž', 'ðž…Ž'), + ('ðžŠ', '\u{1e2ae}'), + ('ðž‹€', '𞋹'), + ('ðž“', '𞓹'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), + ('ðž €', '𞣄'), + ('\u{1e8d0}', '\u{1e8d6}'), + ('𞤀', '𞥋'), + ('ðž¥', '𞥙'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('🯰', '🯹'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('丽', 'ð¯¨'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const ID_START: &'static [(char, char)] = &[ + ('A', 'Z'), + ('a', 'z'), + ('ª', 'ª'), + ('µ', 'µ'), + ('º', 'º'), + ('À', 'Ö'), + ('Ø', 'ö'), + ('ø', 'Ë'), + ('ˆ', 'Ë‘'), + ('Ë ', 'ˤ'), + ('ˬ', 'ˬ'), + ('Ë®', 'Ë®'), + ('Í°', 'Í´'), + ('Ͷ', 'Í·'), + ('ͺ', 'ͽ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'ϵ'), + ('Ï·', 'Ò'), + ('ÒŠ', 'Ô¯'), + ('Ô±', 'Õ–'), + ('Õ™', 'Õ™'), + ('Õ ', 'Öˆ'), + ('×', 'ת'), + ('ׯ', 'ײ'), + ('Ø ', 'ÙŠ'), + ('Ù®', 'Ù¯'), + ('Ù±', 'Û“'), + ('Û•', 'Û•'), + ('Û¥', 'Û¦'), + ('Û®', 'Û¯'), + ('Ûº', 'Û¼'), + ('Û¿', 'Û¿'), + ('Ü', 'Ü'), + ('Ü’', 'ܯ'), + ('Ý', 'Þ¥'), + ('Þ±', 'Þ±'), + ('ߊ', 'ߪ'), + ('ß´', 'ßµ'), + ('ߺ', 'ߺ'), + ('à €', 'à •'), + ('à š', 'à š'), + ('à ¤', 'à ¤'), + ('à ¨', 'à ¨'), + ('à¡€', 'ࡘ'), + ('à¡ ', 'ࡪ'), + ('à¡°', 'ࢇ'), + ('ࢉ', 'ࢎ'), + ('ࢠ', 'ࣉ'), + ('ऄ', 'ह'), + ('ऽ', 'ऽ'), + ('à¥', 'à¥'), + ('क़', 'ॡ'), + ('ॱ', 'ঀ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('ঽ', 'ঽ'), + ('ৎ', 'ৎ'), + ('ড়', 'à§'), + ('য়', 'ৡ'), + ('ৰ', 'ৱ'), + ('ৼ', 'ৼ'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('ੲ', 'à©´'), + ('અ', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('ઽ', 'ઽ'), + ('à«', 'à«'), + ('à« ', 'à«¡'), + ('ૹ', 'ૹ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), + ('ଽ', 'ଽ'), + ('à­œ', 'à­'), + ('à­Ÿ', 'à­¡'), + ('à­±', 'à­±'), + ('ஃ', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'ஹ'), + ('à¯', 'à¯'), + ('à°…', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°¹'), + ('à°½', 'à°½'), + ('ౘ', 'ౚ'), + ('à±', 'à±'), + ('à± ', 'ౡ'), + ('ಀ', 'ಀ'), + ('ಅ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('ಽ', 'ಽ'), + ('à³', 'ೞ'), + ('à³ ', 'ೡ'), + ('à³±', 'à³²'), + ('à´„', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', 'à´º'), + ('à´½', 'à´½'), + ('ൎ', 'ൎ'), + ('ൔ', 'ൖ'), + ('ൟ', 'ൡ'), + ('ൺ', 'ൿ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('à¸', 'ะ'), + ('า', 'ำ'), + ('เ', 'ๆ'), + ('àº', 'ຂ'), + ('ຄ', 'ຄ'), + ('ຆ', 'ຊ'), + ('ຌ', 'ຣ'), + ('ລ', 'ລ'), + ('ວ', 'ະ'), + ('າ', 'ຳ'), + ('ຽ', 'ຽ'), + ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), + ('ໜ', 'ໟ'), + ('ༀ', 'ༀ'), + ('ཀ', 'ཇ'), + ('ཉ', 'ཬ'), + ('ྈ', 'ྌ'), + ('က', 'ဪ'), + ('ဿ', 'ဿ'), + ('á', 'á•'), + ('áš', 'á'), + ('á¡', 'á¡'), + ('á¥', 'á¦'), + ('á®', 'á°'), + ('áµ', 'á‚'), + ('á‚Ž', 'á‚Ž'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ჺ'), + ('ჼ', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹–'), + ('ዘ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'áš'), + ('ᎀ', 'áŽ'), + ('Ꭰ', 'áµ'), + ('á¸', 'á½'), + ('á', 'ᙬ'), + ('ᙯ', 'ᙿ'), + ('áš', 'ášš'), + ('áš ', 'ᛪ'), + ('á›®', 'ᛸ'), + ('ᜀ', 'ᜑ'), + ('ᜟ', 'ᜱ'), + ('á€', 'á‘'), + ('á ', 'á¬'), + ('á®', 'á°'), + ('ក', 'áž³'), + ('ៗ', 'ៗ'), + ('ៜ', 'ៜ'), + ('á  ', 'ᡸ'), + ('ᢀ', 'ᢨ'), + ('ᢪ', 'ᢪ'), + ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), + ('á¥', 'ᥭ'), + ('ᥰ', 'ᥴ'), + ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), + ('ᨀ', 'ᨖ'), + ('ᨠ', 'á©”'), + ('ᪧ', 'ᪧ'), + ('ᬅ', 'ᬳ'), + ('á­…', 'á­Œ'), + ('ᮃ', 'á® '), + ('á®®', 'ᮯ'), + ('ᮺ', 'ᯥ'), + ('á°€', 'á°£'), + ('á±', 'á±'), + ('ᱚ', 'á±½'), + ('á²€', 'ᲈ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('ᳩ', 'ᳬ'), + ('á³®', 'á³³'), + ('á³µ', 'ᳶ'), + ('ᳺ', 'ᳺ'), + ('á´€', 'ᶿ'), + ('Ḁ', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¾¼'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'á¿Œ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), + ('ῶ', 'ῼ'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„Š', 'â„“'), + ('â„•', 'â„•'), + ('℘', 'â„'), + ('ℤ', 'ℤ'), + ('Ω', 'Ω'), + ('ℨ', 'ℨ'), + ('K', 'ℹ'), + ('ℼ', 'â„¿'), + ('â……', 'â…‰'), + ('â…Ž', 'â…Ž'), + ('â… ', 'ↈ'), + ('â°€', 'ⳤ'), + ('Ⳬ', 'â³®'), + ('â³²', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('â´°', 'ⵧ'), + ('ⵯ', 'ⵯ'), + ('ⶀ', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('々', '〇'), + ('〡', '〩'), + ('〱', '〵'), + ('〸', '〼'), + ('ã', 'ã‚–'), + ('ã‚›', 'ã‚Ÿ'), + ('ã‚¡', 'ヺ'), + ('ー', 'ヿ'), + ('ã„…', 'ㄯ'), + ('ㄱ', 'ㆎ'), + ('ㆠ', 'ㆿ'), + ('ㇰ', 'ㇿ'), + ('ã€', '䶿'), + ('一', 'ê’Œ'), + ('ê“', 'ꓽ'), + ('ꔀ', 'ꘌ'), + ('ê˜', 'ꘟ'), + ('ꘪ', 'ꘫ'), + ('Ꙁ', 'ê™®'), + ('ꙿ', 'êš'), + ('êš ', 'ꛯ'), + ('ꜗ', 'ꜟ'), + ('Ꜣ', 'ꞈ'), + ('êž‹', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('ꟲ', 'ê '), + ('ê ƒ', 'ê …'), + ('ê ‡', 'ê Š'), + ('ê Œ', 'ê ¢'), + ('ê¡€', 'ꡳ'), + ('ꢂ', 'ꢳ'), + ('ꣲ', 'ꣷ'), + ('ꣻ', 'ꣻ'), + ('ꣽ', 'ꣾ'), + ('ꤊ', 'ꤥ'), + ('ꤰ', 'ꥆ'), + ('ꥠ', 'ꥼ'), + ('ꦄ', 'ꦲ'), + ('ê§', 'ê§'), + ('ꧠ', 'ꧤ'), + ('ꧦ', 'ꧯ'), + ('ꧺ', 'ꧾ'), + ('ꨀ', 'ꨨ'), + ('ê©€', 'ê©‚'), + ('ê©„', 'ê©‹'), + ('ê© ', 'ꩶ'), + ('ꩺ', 'ꩺ'), + ('ꩾ', 'ꪯ'), + ('ꪱ', 'ꪱ'), + ('ꪵ', 'ꪶ'), + ('ꪹ', 'ꪽ'), + ('ê«€', 'ê«€'), + ('ê«‚', 'ê«‚'), + ('ê«›', 'ê«'), + ('ê« ', 'ꫪ'), + ('ꫲ', 'ê«´'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('ꬰ', 'ê­š'), + ('ê­œ', 'ê­©'), + ('ê­°', 'ꯢ'), + ('ê°€', '힣'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), + ('ï©°', 'ï«™'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï¬', 'ï¬'), + ('ײַ', 'ﬨ'), + ('שׁ', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', 'ï®±'), + ('ﯓ', 'ï´½'), + ('ïµ', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·°', 'ï·»'), + ('ï¹°', 'ï¹´'), + ('ﹶ', 'ﻼ'), + ('A', 'Z'), + ('ï½', 'z'), + ('ヲ', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), + ('ð…€', 'ð…´'), + ('ðŠ€', 'ðŠœ'), + ('ðŠ ', 'ð‹'), + ('ðŒ€', 'ðŒŸ'), + ('ðŒ­', 'ðŠ'), + ('ð', 'ðµ'), + ('ðŽ€', 'ðŽ'), + ('ðŽ ', 'ðƒ'), + ('ðˆ', 'ð'), + ('ð‘', 'ð•'), + ('ð€', 'ð’'), + ('ð’°', 'ð““'), + ('ð“˜', 'ð“»'), + ('ð”€', 'ð”§'), + ('ð”°', 'ð•£'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð˜€', 'ðœ¶'), + ('ð€', 'ð•'), + ('ð ', 'ð§'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð €', 'ð …'), + ('ð ˆ', 'ð ˆ'), + ('ð Š', 'ð µ'), + ('ð ·', 'ð ¸'), + ('ð ¼', 'ð ¼'), + ('ð ¿', 'ð¡•'), + ('ð¡ ', 'ð¡¶'), + ('ð¢€', 'ð¢ž'), + ('ð£ ', 'ð£²'), + ('ð£´', 'ð£µ'), + ('ð¤€', 'ð¤•'), + ('ð¤ ', 'ð¤¹'), + ('ð¦€', 'ð¦·'), + ('ð¦¾', 'ð¦¿'), + ('ð¨€', 'ð¨€'), + ('ð¨', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨µ'), + ('ð© ', 'ð©¼'), + ('ðª€', 'ðªœ'), + ('ð«€', 'ð«‡'), + ('ð«‰', 'ð«¤'), + ('ð¬€', 'ð¬µ'), + ('ð­€', 'ð­•'), + ('ð­ ', 'ð­²'), + ('ð®€', 'ð®‘'), + ('ð°€', 'ð±ˆ'), + ('ð²€', 'ð²²'), + ('ð³€', 'ð³²'), + ('ð´€', 'ð´£'), + ('ðº€', 'ðº©'), + ('ðº°', 'ðº±'), + ('ð¼€', 'ð¼œ'), + ('ð¼§', 'ð¼§'), + ('ð¼°', 'ð½…'), + ('ð½°', 'ð¾'), + ('ð¾°', 'ð¿„'), + ('ð¿ ', 'ð¿¶'), + ('𑀃', 'ð‘€·'), + ('ð‘±', 'ð‘²'), + ('ð‘µ', 'ð‘µ'), + ('𑂃', '𑂯'), + ('ð‘ƒ', '𑃨'), + ('𑄃', '𑄦'), + ('ð‘…„', 'ð‘…„'), + ('ð‘…‡', 'ð‘…‡'), + ('ð‘…', 'ð‘…²'), + ('ð‘…¶', 'ð‘…¶'), + ('𑆃', '𑆲'), + ('ð‘‡', '𑇄'), + ('𑇚', '𑇚'), + ('𑇜', '𑇜'), + ('𑈀', '𑈑'), + ('𑈓', '𑈫'), + ('𑈿', '𑉀'), + ('ð‘Š€', '𑊆'), + ('𑊈', '𑊈'), + ('ð‘ŠŠ', 'ð‘Š'), + ('ð‘Š', 'ð‘Š'), + ('ð‘ŠŸ', '𑊨'), + ('ð‘Š°', 'ð‘‹ž'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('𑌽', '𑌽'), + ('ð‘', 'ð‘'), + ('ð‘', 'ð‘¡'), + ('ð‘€', 'ð‘´'), + ('𑑇', 'ð‘‘Š'), + ('ð‘‘Ÿ', 'ð‘‘¡'), + ('ð‘’€', 'ð‘’¯'), + ('ð‘“„', 'ð‘“…'), + ('𑓇', '𑓇'), + ('ð‘–€', 'ð‘–®'), + ('ð‘—˜', 'ð‘—›'), + ('𑘀', '𑘯'), + ('ð‘™„', 'ð‘™„'), + ('𑚀', '𑚪'), + ('𑚸', '𑚸'), + ('𑜀', '𑜚'), + ('ð‘€', 'ð‘†'), + ('ð‘ €', 'ð‘ «'), + ('ð‘¢ ', '𑣟'), + ('𑣿', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤯'), + ('𑤿', '𑤿'), + ('ð‘¥', 'ð‘¥'), + ('𑦠', '𑦧'), + ('𑦪', 'ð‘§'), + ('𑧡', '𑧡'), + ('𑧣', '𑧣'), + ('𑨀', '𑨀'), + ('𑨋', '𑨲'), + ('𑨺', '𑨺'), + ('ð‘©', 'ð‘©'), + ('ð‘©œ', '𑪉'), + ('ð‘ª', 'ð‘ª'), + ('𑪰', '𑫸'), + ('ð‘°€', 'ð‘°ˆ'), + ('ð‘°Š', 'ð‘°®'), + ('𑱀', '𑱀'), + ('𑱲', 'ð‘²'), + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', 'ð‘´°'), + ('𑵆', '𑵆'), + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶉'), + ('𑶘', '𑶘'), + ('ð‘» ', 'ð‘»²'), + ('𑼂', '𑼂'), + ('𑼄', 'ð‘¼'), + ('𑼒', '𑼳'), + ('𑾰', '𑾰'), + ('ð’€€', 'ð’Ž™'), + ('ð’€', 'ð’‘®'), + ('ð’’€', '𒕃'), + ('ð’¾', 'ð’¿°'), + ('ð“€€', 'ð“¯'), + ('ð“‘', '𓑆'), + ('ð”€', '𔙆'), + ('ð– €', '𖨸'), + ('ð–©€', 'ð–©ž'), + ('ð–©°', '𖪾'), + ('ð–«', 'ð–«­'), + ('𖬀', '𖬯'), + ('ð–­€', 'ð–­ƒ'), + ('ð–­£', 'ð–­·'), + ('ð–­½', 'ð–®'), + ('ð–¹€', '𖹿'), + ('ð–¼€', '𖽊'), + ('ð–½', 'ð–½'), + ('𖾓', '𖾟'), + ('ð–¿ ', 'ð–¿¡'), + ('ð–¿£', 'ð–¿£'), + ('ð—€€', '𘟷'), + ('𘠀', '𘳕'), + ('𘴀', '𘴈'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𛀀', '𛄢'), + ('𛄲', '𛄲'), + ('ð›…', 'ð›…’'), + ('ð›…•', 'ð›…•'), + ('ð›…¤', 'ð›…§'), + ('ð›…°', '𛋻'), + ('ð›°€', '𛱪'), + ('ð›±°', 'ð›±¼'), + ('𛲀', '𛲈'), + ('ð›²', '𛲙'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ð›€'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›º'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ´'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð®'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž¨'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‹'), + ('ð¼€', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('𞀰', 'ðž­'), + ('ðž„€', '𞄬'), + ('ðž„·', '𞄽'), + ('ðž…Ž', 'ðž…Ž'), + ('ðžŠ', '𞊭'), + ('ðž‹€', 'ðž‹«'), + ('ðž“', 'ðž“«'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), + ('ðž €', '𞣄'), + ('𞤀', '𞥃'), + ('𞥋', '𞥋'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('丽', 'ð¯¨'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), +]; + +pub const IDEOGRAPHIC: &'static [(char, char)] = &[ + ('〆', '〇'), + ('〡', '〩'), + ('〸', '〺'), + ('ã€', '䶿'), + ('一', 'é¿¿'), + ('豈', 'ï©­'), + ('ï©°', 'ï«™'), + ('\u{16fe4}', '\u{16fe4}'), + ('ð—€€', '𘟷'), + ('𘠀', '𘳕'), + ('𘴀', '𘴈'), + ('ð›…°', '𛋻'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('丽', 'ð¯¨'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), +]; + +pub const JOIN_CONTROL: &'static [(char, char)] = &[('\u{200c}', '\u{200d}')]; + +pub const LOGICAL_ORDER_EXCEPTION: &'static [(char, char)] = &[ + ('เ', 'ไ'), + ('ເ', 'ໄ'), + ('ᦵ', 'ᦷ'), + ('ᦺ', 'ᦺ'), + ('ꪵ', 'ꪶ'), + ('ꪹ', 'ꪹ'), + ('ꪻ', 'ꪼ'), +]; + +pub const LOWERCASE: &'static [(char, char)] = &[ + ('a', 'z'), + ('ª', 'ª'), + ('µ', 'µ'), + ('º', 'º'), + ('ß', 'ö'), + ('ø', 'ÿ'), + ('Ä', 'Ä'), + ('ă', 'ă'), + ('Ä…', 'Ä…'), + ('ć', 'ć'), + ('ĉ', 'ĉ'), + ('Ä‹', 'Ä‹'), + ('Ä', 'Ä'), + ('Ä', 'Ä'), + ('Ä‘', 'Ä‘'), + ('Ä“', 'Ä“'), + ('Ä•', 'Ä•'), + ('Ä—', 'Ä—'), + ('Ä™', 'Ä™'), + ('Ä›', 'Ä›'), + ('Ä', 'Ä'), + ('ÄŸ', 'ÄŸ'), + ('Ä¡', 'Ä¡'), + ('Ä£', 'Ä£'), + ('Ä¥', 'Ä¥'), + ('ħ', 'ħ'), + ('Ä©', 'Ä©'), + ('Ä«', 'Ä«'), + ('Ä­', 'Ä­'), + ('į', 'į'), + ('ı', 'ı'), + ('ij', 'ij'), + ('ĵ', 'ĵ'), + ('Ä·', 'ĸ'), + ('ĺ', 'ĺ'), + ('ļ', 'ļ'), + ('ľ', 'ľ'), + ('Å€', 'Å€'), + ('Å‚', 'Å‚'), + ('Å„', 'Å„'), + ('ņ', 'ņ'), + ('ň', 'ʼn'), + ('Å‹', 'Å‹'), + ('Å', 'Å'), + ('Å', 'Å'), + ('Å‘', 'Å‘'), + ('Å“', 'Å“'), + ('Å•', 'Å•'), + ('Å—', 'Å—'), + ('Å™', 'Å™'), + ('Å›', 'Å›'), + ('Å', 'Å'), + ('ÅŸ', 'ÅŸ'), + ('Å¡', 'Å¡'), + ('Å£', 'Å£'), + ('Å¥', 'Å¥'), + ('ŧ', 'ŧ'), + ('Å©', 'Å©'), + ('Å«', 'Å«'), + ('Å­', 'Å­'), + ('ů', 'ů'), + ('ű', 'ű'), + ('ų', 'ų'), + ('ŵ', 'ŵ'), + ('Å·', 'Å·'), + ('ź', 'ź'), + ('ż', 'ż'), + ('ž', 'Æ€'), + ('ƃ', 'ƃ'), + ('Æ…', 'Æ…'), + ('ƈ', 'ƈ'), + ('ÆŒ', 'Æ'), + ('Æ’', 'Æ’'), + ('Æ•', 'Æ•'), + ('Æ™', 'Æ›'), + ('Æž', 'Æž'), + ('Æ¡', 'Æ¡'), + ('Æ£', 'Æ£'), + ('Æ¥', 'Æ¥'), + ('ƨ', 'ƨ'), + ('ƪ', 'Æ«'), + ('Æ­', 'Æ­'), + ('Æ°', 'Æ°'), + ('Æ´', 'Æ´'), + ('ƶ', 'ƶ'), + ('ƹ', 'ƺ'), + ('ƽ', 'Æ¿'), + ('dž', 'dž'), + ('lj', 'lj'), + ('ÇŒ', 'ÇŒ'), + ('ÇŽ', 'ÇŽ'), + ('Ç', 'Ç'), + ('Ç’', 'Ç’'), + ('Ç”', 'Ç”'), + ('Ç–', 'Ç–'), + ('ǘ', 'ǘ'), + ('Çš', 'Çš'), + ('Çœ', 'Ç'), + ('ÇŸ', 'ÇŸ'), + ('Ç¡', 'Ç¡'), + ('Ç£', 'Ç£'), + ('Ç¥', 'Ç¥'), + ('ǧ', 'ǧ'), + ('Ç©', 'Ç©'), + ('Ç«', 'Ç«'), + ('Ç­', 'Ç­'), + ('ǯ', 'Ç°'), + ('dz', 'dz'), + ('ǵ', 'ǵ'), + ('ǹ', 'ǹ'), + ('Ç»', 'Ç»'), + ('ǽ', 'ǽ'), + ('Ç¿', 'Ç¿'), + ('È', 'È'), + ('ȃ', 'ȃ'), + ('È…', 'È…'), + ('ȇ', 'ȇ'), + ('ȉ', 'ȉ'), + ('È‹', 'È‹'), + ('È', 'È'), + ('È', 'È'), + ('È‘', 'È‘'), + ('È“', 'È“'), + ('È•', 'È•'), + ('È—', 'È—'), + ('È™', 'È™'), + ('È›', 'È›'), + ('È', 'È'), + ('ÈŸ', 'ÈŸ'), + ('È¡', 'È¡'), + ('È£', 'È£'), + ('È¥', 'È¥'), + ('ȧ', 'ȧ'), + ('È©', 'È©'), + ('È«', 'È«'), + ('È­', 'È­'), + ('ȯ', 'ȯ'), + ('ȱ', 'ȱ'), + ('ȳ', 'ȹ'), + ('ȼ', 'ȼ'), + ('È¿', 'É€'), + ('É‚', 'É‚'), + ('ɇ', 'ɇ'), + ('ɉ', 'ɉ'), + ('É‹', 'É‹'), + ('É', 'É'), + ('É', 'Ê“'), + ('Ê•', 'ʸ'), + ('Ë€', 'Ë'), + ('Ë ', 'ˤ'), + ('\u{345}', '\u{345}'), + ('ͱ', 'ͱ'), + ('ͳ', 'ͳ'), + ('Í·', 'Í·'), + ('ͺ', 'ͽ'), + ('Î', 'Î'), + ('ά', 'ÏŽ'), + ('Ï', 'Ï‘'), + ('Ï•', 'Ï—'), + ('Ï™', 'Ï™'), + ('Ï›', 'Ï›'), + ('Ï', 'Ï'), + ('ÏŸ', 'ÏŸ'), + ('Ï¡', 'Ï¡'), + ('Ï£', 'Ï£'), + ('Ï¥', 'Ï¥'), + ('ϧ', 'ϧ'), + ('Ï©', 'Ï©'), + ('Ï«', 'Ï«'), + ('Ï­', 'Ï­'), + ('ϯ', 'ϳ'), + ('ϵ', 'ϵ'), + ('ϸ', 'ϸ'), + ('Ï»', 'ϼ'), + ('а', 'ÑŸ'), + ('Ñ¡', 'Ñ¡'), + ('Ñ£', 'Ñ£'), + ('Ñ¥', 'Ñ¥'), + ('ѧ', 'ѧ'), + ('Ñ©', 'Ñ©'), + ('Ñ«', 'Ñ«'), + ('Ñ­', 'Ñ­'), + ('ѯ', 'ѯ'), + ('ѱ', 'ѱ'), + ('ѳ', 'ѳ'), + ('ѵ', 'ѵ'), + ('Ñ·', 'Ñ·'), + ('ѹ', 'ѹ'), + ('Ñ»', 'Ñ»'), + ('ѽ', 'ѽ'), + ('Ñ¿', 'Ñ¿'), + ('Ò', 'Ò'), + ('Ò‹', 'Ò‹'), + ('Ò', 'Ò'), + ('Ò', 'Ò'), + ('Ò‘', 'Ò‘'), + ('Ò“', 'Ò“'), + ('Ò•', 'Ò•'), + ('Ò—', 'Ò—'), + ('Ò™', 'Ò™'), + ('Ò›', 'Ò›'), + ('Ò', 'Ò'), + ('ÒŸ', 'ÒŸ'), + ('Ò¡', 'Ò¡'), + ('Ò£', 'Ò£'), + ('Ò¥', 'Ò¥'), + ('Ò§', 'Ò§'), + ('Ò©', 'Ò©'), + ('Ò«', 'Ò«'), + ('Ò­', 'Ò­'), + ('Ò¯', 'Ò¯'), + ('Ò±', 'Ò±'), + ('Ò³', 'Ò³'), + ('Òµ', 'Òµ'), + ('Ò·', 'Ò·'), + ('Ò¹', 'Ò¹'), + ('Ò»', 'Ò»'), + ('Ò½', 'Ò½'), + ('Ò¿', 'Ò¿'), + ('Ó‚', 'Ó‚'), + ('Ó„', 'Ó„'), + ('Ó†', 'Ó†'), + ('Óˆ', 'Óˆ'), + ('ÓŠ', 'ÓŠ'), + ('ÓŒ', 'ÓŒ'), + ('ÓŽ', 'Ó'), + ('Ó‘', 'Ó‘'), + ('Ó“', 'Ó“'), + ('Ó•', 'Ó•'), + ('Ó—', 'Ó—'), + ('Ó™', 'Ó™'), + ('Ó›', 'Ó›'), + ('Ó', 'Ó'), + ('ÓŸ', 'ÓŸ'), + ('Ó¡', 'Ó¡'), + ('Ó£', 'Ó£'), + ('Ó¥', 'Ó¥'), + ('Ó§', 'Ó§'), + ('Ó©', 'Ó©'), + ('Ó«', 'Ó«'), + ('Ó­', 'Ó­'), + ('Ó¯', 'Ó¯'), + ('Ó±', 'Ó±'), + ('Ó³', 'Ó³'), + ('Óµ', 'Óµ'), + ('Ó·', 'Ó·'), + ('Ó¹', 'Ó¹'), + ('Ó»', 'Ó»'), + ('Ó½', 'Ó½'), + ('Ó¿', 'Ó¿'), + ('Ô', 'Ô'), + ('Ôƒ', 'Ôƒ'), + ('Ô…', 'Ô…'), + ('Ô‡', 'Ô‡'), + ('Ô‰', 'Ô‰'), + ('Ô‹', 'Ô‹'), + ('Ô', 'Ô'), + ('Ô', 'Ô'), + ('Ô‘', 'Ô‘'), + ('Ô“', 'Ô“'), + ('Ô•', 'Ô•'), + ('Ô—', 'Ô—'), + ('Ô™', 'Ô™'), + ('Ô›', 'Ô›'), + ('Ô', 'Ô'), + ('ÔŸ', 'ÔŸ'), + ('Ô¡', 'Ô¡'), + ('Ô£', 'Ô£'), + ('Ô¥', 'Ô¥'), + ('Ô§', 'Ô§'), + ('Ô©', 'Ô©'), + ('Ô«', 'Ô«'), + ('Ô­', 'Ô­'), + ('Ô¯', 'Ô¯'), + ('Õ ', 'Öˆ'), + ('áƒ', 'ჺ'), + ('ჼ', 'ჿ'), + ('á¸', 'á½'), + ('á²€', 'ᲈ'), + ('á´€', 'ᶿ'), + ('á¸', 'á¸'), + ('ḃ', 'ḃ'), + ('ḅ', 'ḅ'), + ('ḇ', 'ḇ'), + ('ḉ', 'ḉ'), + ('ḋ', 'ḋ'), + ('á¸', 'á¸'), + ('á¸', 'á¸'), + ('ḑ', 'ḑ'), + ('ḓ', 'ḓ'), + ('ḕ', 'ḕ'), + ('ḗ', 'ḗ'), + ('ḙ', 'ḙ'), + ('ḛ', 'ḛ'), + ('á¸', 'á¸'), + ('ḟ', 'ḟ'), + ('ḡ', 'ḡ'), + ('ḣ', 'ḣ'), + ('ḥ', 'ḥ'), + ('ḧ', 'ḧ'), + ('ḩ', 'ḩ'), + ('ḫ', 'ḫ'), + ('ḭ', 'ḭ'), + ('ḯ', 'ḯ'), + ('ḱ', 'ḱ'), + ('ḳ', 'ḳ'), + ('ḵ', 'ḵ'), + ('ḷ', 'ḷ'), + ('ḹ', 'ḹ'), + ('ḻ', 'ḻ'), + ('ḽ', 'ḽ'), + ('ḿ', 'ḿ'), + ('á¹', 'á¹'), + ('ṃ', 'ṃ'), + ('á¹…', 'á¹…'), + ('ṇ', 'ṇ'), + ('ṉ', 'ṉ'), + ('ṋ', 'ṋ'), + ('á¹', 'á¹'), + ('á¹', 'á¹'), + ('ṑ', 'ṑ'), + ('ṓ', 'ṓ'), + ('ṕ', 'ṕ'), + ('á¹—', 'á¹—'), + ('á¹™', 'á¹™'), + ('á¹›', 'á¹›'), + ('á¹', 'á¹'), + ('ṟ', 'ṟ'), + ('ṡ', 'ṡ'), + ('á¹£', 'á¹£'), + ('á¹¥', 'á¹¥'), + ('ṧ', 'ṧ'), + ('ṩ', 'ṩ'), + ('ṫ', 'ṫ'), + ('á¹­', 'á¹­'), + ('ṯ', 'ṯ'), + ('á¹±', 'á¹±'), + ('á¹³', 'á¹³'), + ('á¹µ', 'á¹µ'), + ('á¹·', 'á¹·'), + ('á¹¹', 'á¹¹'), + ('á¹»', 'á¹»'), + ('á¹½', 'á¹½'), + ('ṿ', 'ṿ'), + ('áº', 'áº'), + ('ẃ', 'ẃ'), + ('ẅ', 'ẅ'), + ('ẇ', 'ẇ'), + ('ẉ', 'ẉ'), + ('ẋ', 'ẋ'), + ('áº', 'áº'), + ('áº', 'áº'), + ('ẑ', 'ẑ'), + ('ẓ', 'ẓ'), + ('ẕ', 'áº'), + ('ẟ', 'ẟ'), + ('ạ', 'ạ'), + ('ả', 'ả'), + ('ấ', 'ấ'), + ('ầ', 'ầ'), + ('ẩ', 'ẩ'), + ('ẫ', 'ẫ'), + ('ậ', 'ậ'), + ('ắ', 'ắ'), + ('ằ', 'ằ'), + ('ẳ', 'ẳ'), + ('ẵ', 'ẵ'), + ('ặ', 'ặ'), + ('ẹ', 'ẹ'), + ('ẻ', 'ẻ'), + ('ẽ', 'ẽ'), + ('ế', 'ế'), + ('á»', 'á»'), + ('ể', 'ể'), + ('á»…', 'á»…'), + ('ệ', 'ệ'), + ('ỉ', 'ỉ'), + ('ị', 'ị'), + ('á»', 'á»'), + ('á»', 'á»'), + ('ố', 'ố'), + ('ồ', 'ồ'), + ('ổ', 'ổ'), + ('á»—', 'á»—'), + ('á»™', 'á»™'), + ('á»›', 'á»›'), + ('á»', 'á»'), + ('ở', 'ở'), + ('ỡ', 'ỡ'), + ('ợ', 'ợ'), + ('ụ', 'ụ'), + ('ủ', 'ủ'), + ('ứ', 'ứ'), + ('ừ', 'ừ'), + ('á»­', 'á»­'), + ('ữ', 'ữ'), + ('á»±', 'á»±'), + ('ỳ', 'ỳ'), + ('ỵ', 'ỵ'), + ('á»·', 'á»·'), + ('ỹ', 'ỹ'), + ('á»»', 'á»»'), + ('ỽ', 'ỽ'), + ('ỿ', 'ἇ'), + ('á¼', 'ἕ'), + ('á¼ ', 'ἧ'), + ('á¼°', 'á¼·'), + ('á½€', 'á½…'), + ('á½', 'á½—'), + ('á½ ', 'ὧ'), + ('á½°', 'á½½'), + ('á¾€', 'ᾇ'), + ('á¾', 'á¾—'), + ('á¾ ', 'ᾧ'), + ('á¾°', 'á¾´'), + ('ᾶ', 'á¾·'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'ῇ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿—'), + ('á¿ ', 'ῧ'), + ('ῲ', 'á¿´'), + ('ῶ', 'á¿·'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('â„Š', 'â„Š'), + ('â„Ž', 'â„'), + ('â„“', 'â„“'), + ('ℯ', 'ℯ'), + ('â„´', 'â„´'), + ('ℹ', 'ℹ'), + ('ℼ', 'ℽ'), + ('â…†', 'â…‰'), + ('â…Ž', 'â…Ž'), + ('â…°', 'â…¿'), + ('ↄ', 'ↄ'), + ('â“', 'â“©'), + ('â°°', 'ⱟ'), + ('ⱡ', 'ⱡ'), + ('â±¥', 'ⱦ'), + ('ⱨ', 'ⱨ'), + ('ⱪ', 'ⱪ'), + ('ⱬ', 'ⱬ'), + ('â±±', 'â±±'), + ('â±³', 'â±´'), + ('ⱶ', 'â±½'), + ('â²', 'â²'), + ('ⲃ', 'ⲃ'), + ('â²…', 'â²…'), + ('ⲇ', 'ⲇ'), + ('ⲉ', 'ⲉ'), + ('ⲋ', 'ⲋ'), + ('â²', 'â²'), + ('â²', 'â²'), + ('ⲑ', 'ⲑ'), + ('ⲓ', 'ⲓ'), + ('ⲕ', 'ⲕ'), + ('â²—', 'â²—'), + ('â²™', 'â²™'), + ('â²›', 'â²›'), + ('â²', 'â²'), + ('ⲟ', 'ⲟ'), + ('ⲡ', 'ⲡ'), + ('â²£', 'â²£'), + ('â²¥', 'â²¥'), + ('ⲧ', 'ⲧ'), + ('ⲩ', 'ⲩ'), + ('ⲫ', 'ⲫ'), + ('â²­', 'â²­'), + ('ⲯ', 'ⲯ'), + ('â²±', 'â²±'), + ('â²³', 'â²³'), + ('â²µ', 'â²µ'), + ('â²·', 'â²·'), + ('â²¹', 'â²¹'), + ('â²»', 'â²»'), + ('â²½', 'â²½'), + ('ⲿ', 'ⲿ'), + ('â³', 'â³'), + ('ⳃ', 'ⳃ'), + ('â³…', 'â³…'), + ('ⳇ', 'ⳇ'), + ('ⳉ', 'ⳉ'), + ('ⳋ', 'ⳋ'), + ('â³', 'â³'), + ('â³', 'â³'), + ('ⳑ', 'ⳑ'), + ('ⳓ', 'ⳓ'), + ('ⳕ', 'ⳕ'), + ('â³—', 'â³—'), + ('â³™', 'â³™'), + ('â³›', 'â³›'), + ('â³', 'â³'), + ('ⳟ', 'ⳟ'), + ('ⳡ', 'ⳡ'), + ('â³£', 'ⳤ'), + ('ⳬ', 'ⳬ'), + ('â³®', 'â³®'), + ('â³³', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('ê™', 'ê™'), + ('ꙃ', 'ꙃ'), + ('ê™…', 'ê™…'), + ('ꙇ', 'ꙇ'), + ('ꙉ', 'ꙉ'), + ('ꙋ', 'ꙋ'), + ('ê™', 'ê™'), + ('ê™', 'ê™'), + ('ꙑ', 'ꙑ'), + ('ꙓ', 'ꙓ'), + ('ꙕ', 'ꙕ'), + ('ê™—', 'ê™—'), + ('ê™™', 'ê™™'), + ('ê™›', 'ê™›'), + ('ê™', 'ê™'), + ('ꙟ', 'ꙟ'), + ('ꙡ', 'ꙡ'), + ('ꙣ', 'ꙣ'), + ('ꙥ', 'ꙥ'), + ('ꙧ', 'ꙧ'), + ('ꙩ', 'ꙩ'), + ('ꙫ', 'ꙫ'), + ('ê™­', 'ê™­'), + ('êš', 'êš'), + ('ꚃ', 'ꚃ'), + ('êš…', 'êš…'), + ('ꚇ', 'ꚇ'), + ('ꚉ', 'ꚉ'), + ('êš‹', 'êš‹'), + ('êš', 'êš'), + ('êš', 'êš'), + ('êš‘', 'êš‘'), + ('êš“', 'êš“'), + ('êš•', 'êš•'), + ('êš—', 'êš—'), + ('êš™', 'êš™'), + ('êš›', 'êš'), + ('ꜣ', 'ꜣ'), + ('ꜥ', 'ꜥ'), + ('ꜧ', 'ꜧ'), + ('ꜩ', 'ꜩ'), + ('ꜫ', 'ꜫ'), + ('ꜭ', 'ꜭ'), + ('ꜯ', 'ꜱ'), + ('ꜳ', 'ꜳ'), + ('ꜵ', 'ꜵ'), + ('ꜷ', 'ꜷ'), + ('ꜹ', 'ꜹ'), + ('ꜻ', 'ꜻ'), + ('ꜽ', 'ꜽ'), + ('ꜿ', 'ꜿ'), + ('ê', 'ê'), + ('êƒ', 'êƒ'), + ('ê…', 'ê…'), + ('ê‡', 'ê‡'), + ('ê‰', 'ê‰'), + ('ê‹', 'ê‹'), + ('ê', 'ê'), + ('ê', 'ê'), + ('ê‘', 'ê‘'), + ('ê“', 'ê“'), + ('ê•', 'ê•'), + ('ê—', 'ê—'), + ('ê™', 'ê™'), + ('ê›', 'ê›'), + ('ê', 'ê'), + ('êŸ', 'êŸ'), + ('ê¡', 'ê¡'), + ('ê£', 'ê£'), + ('ê¥', 'ê¥'), + ('ê§', 'ê§'), + ('ê©', 'ê©'), + ('ê«', 'ê«'), + ('ê­', 'ê­'), + ('ê¯', 'ê¸'), + ('êº', 'êº'), + ('ê¼', 'ê¼'), + ('ê¿', 'ê¿'), + ('êž', 'êž'), + ('ꞃ', 'ꞃ'), + ('êž…', 'êž…'), + ('ꞇ', 'ꞇ'), + ('ꞌ', 'ꞌ'), + ('ꞎ', 'ꞎ'), + ('êž‘', 'êž‘'), + ('êž“', 'êž•'), + ('êž—', 'êž—'), + ('êž™', 'êž™'), + ('êž›', 'êž›'), + ('êž', 'êž'), + ('ꞟ', 'ꞟ'), + ('êž¡', 'êž¡'), + ('ꞣ', 'ꞣ'), + ('ꞥ', 'ꞥ'), + ('ꞧ', 'ꞧ'), + ('êž©', 'êž©'), + ('ꞯ', 'ꞯ'), + ('êžµ', 'êžµ'), + ('êž·', 'êž·'), + ('êž¹', 'êž¹'), + ('êž»', 'êž»'), + ('êž½', 'êž½'), + ('êž¿', 'êž¿'), + ('êŸ', 'êŸ'), + ('ꟃ', 'ꟃ'), + ('ꟈ', 'ꟈ'), + ('ꟊ', 'ꟊ'), + ('ꟑ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟕ'), + ('ꟗ', 'ꟗ'), + ('ꟙ', 'ꟙ'), + ('ꟲ', 'ꟴ'), + ('ꟶ', 'ꟶ'), + ('ꟸ', 'ꟺ'), + ('ꬰ', 'ê­š'), + ('ê­œ', 'ê­©'), + ('ê­°', 'ꮿ'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï½', 'z'), + ('ð¨', 'ð‘'), + ('ð“˜', 'ð“»'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ðž€', 'ðž€'), + ('ðžƒ', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð³€', 'ð³²'), + ('ð‘£€', '𑣟'), + ('ð–¹ ', '𖹿'), + ('ðš', 'ð³'), + ('ð‘Ž', 'ð‘”'), + ('ð‘–', 'ð‘§'), + ('ð’‚', 'ð’›'), + ('ð’¶', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð“'), + ('ð“ª', 'ð”ƒ'), + ('ð”ž', 'ð”·'), + ('ð•’', 'ð•«'), + ('ð–†', 'ð–Ÿ'), + ('ð–º', 'ð—“'), + ('ð—®', 'ð˜‡'), + ('ð˜¢', 'ð˜»'), + ('ð™–', 'ð™¯'), + ('ðšŠ', 'ðš¥'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›¡'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ›'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð•'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‰'), + ('ðŸ‹', 'ðŸ‹'), + ('ð¼€', 'ð¼‰'), + ('ð¼‹', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('𞀰', 'ðž­'), + ('𞤢', '𞥃'), +]; + +pub const MATH: &'static [(char, char)] = &[ + ('+', '+'), + ('<', '>'), + ('^', '^'), + ('|', '|'), + ('~', '~'), + ('¬', '¬'), + ('±', '±'), + ('×', '×'), + ('÷', '÷'), + ('Ï', 'Ï’'), + ('Ï•', 'Ï•'), + ('Ï°', 'ϱ'), + ('Ï´', '϶'), + ('؆', '؈'), + ('‖', '‖'), + ('′', '‴'), + ('â€', 'â€'), + ('â„', 'â„'), + ('â’', 'â’'), + ('\u{2061}', '\u{2064}'), + ('âº', 'â¾'), + ('â‚Š', 'â‚Ž'), + ('\u{20d0}', '\u{20dc}'), + ('\u{20e1}', '\u{20e1}'), + ('\u{20e5}', '\u{20e6}'), + ('\u{20eb}', '\u{20ef}'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„Š', 'â„“'), + ('â„•', 'â„•'), + ('℘', 'â„'), + ('ℤ', 'ℤ'), + ('ℨ', 'â„©'), + ('ℬ', 'â„­'), + ('ℯ', 'ℱ'), + ('ℳ', 'ℸ'), + ('ℼ', 'â…‰'), + ('â…‹', 'â…‹'), + ('â†', '↧'), + ('↩', '↮'), + ('↰', '↱'), + ('↶', '↷'), + ('↼', '⇛'), + ('â‡', 'â‡'), + ('⇤', '⇥'), + ('⇴', 'â‹¿'), + ('⌈', '⌋'), + ('⌠', '⌡'), + ('â¼', 'â¼'), + ('⎛', '⎵'), + ('⎷', '⎷'), + ('â', 'â'), + ('âœ', 'â¢'), + ('â– ', 'â–¡'), + ('â–®', 'â–·'), + ('â–¼', 'â—'), + ('â—†', 'â—‡'), + ('â—Š', 'â—‹'), + ('â—', 'â—“'), + ('â—¢', 'â—¢'), + ('â—¤', 'â—¤'), + ('â—§', 'â—¬'), + ('â—¸', 'â—¿'), + ('★', '☆'), + ('♀', '♀'), + ('♂', '♂'), + ('â™ ', '♣'), + ('â™­', '♯'), + ('⟀', '⟿'), + ('⤀', 'â«¿'), + ('⬰', 'â­„'), + ('â­‡', 'â­Œ'), + ('﬩', '﬩'), + ('﹡', '﹦'), + ('﹨', '﹨'), + ('+', '+'), + ('<', '>'), + ('ï¼¼', 'ï¼¼'), + ('ï¼¾', 'ï¼¾'), + ('|', '|'), + ('~', '~'), + ('ï¿¢', 'ï¿¢'), + ('ï¿©', '↓'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ðŸ‹'), + ('ðŸŽ', 'ðŸ¿'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('ðž»°', 'ðž»±'), +]; + +pub const NONCHARACTER_CODE_POINT: &'static [(char, char)] = &[ + ('\u{fdd0}', '\u{fdef}'), + ('\u{fffe}', '\u{ffff}'), + ('\u{1fffe}', '\u{1ffff}'), + ('\u{2fffe}', '\u{2ffff}'), + ('\u{3fffe}', '\u{3ffff}'), + ('\u{4fffe}', '\u{4ffff}'), + ('\u{5fffe}', '\u{5ffff}'), + ('\u{6fffe}', '\u{6ffff}'), + ('\u{7fffe}', '\u{7ffff}'), + ('\u{8fffe}', '\u{8ffff}'), + ('\u{9fffe}', '\u{9ffff}'), + ('\u{afffe}', '\u{affff}'), + ('\u{bfffe}', '\u{bffff}'), + ('\u{cfffe}', '\u{cffff}'), + ('\u{dfffe}', '\u{dffff}'), + ('\u{efffe}', '\u{effff}'), + ('\u{ffffe}', '\u{fffff}'), + ('\u{10fffe}', '\u{10ffff}'), +]; + +pub const OTHER_ALPHABETIC: &'static [(char, char)] = &[ + ('\u{345}', '\u{345}'), + ('\u{5b0}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), + ('\u{610}', '\u{61a}'), + ('\u{64b}', '\u{657}'), + ('\u{659}', '\u{65f}'), + ('\u{670}', '\u{670}'), + ('\u{6d6}', '\u{6dc}'), + ('\u{6e1}', '\u{6e4}'), + ('\u{6e7}', '\u{6e8}'), + ('\u{6ed}', '\u{6ed}'), + ('\u{711}', '\u{711}'), + ('\u{730}', '\u{73f}'), + ('\u{7a6}', '\u{7b0}'), + ('\u{816}', '\u{817}'), + ('\u{81b}', '\u{823}'), + ('\u{825}', '\u{827}'), + ('\u{829}', '\u{82c}'), + ('\u{8d4}', '\u{8df}'), + ('\u{8e3}', '\u{8e9}'), + ('\u{8f0}', 'ः'), + ('\u{93a}', 'ऻ'), + ('ा', 'ौ'), + ('ॎ', 'à¥'), + ('\u{955}', '\u{957}'), + ('\u{962}', '\u{963}'), + ('\u{981}', 'ঃ'), + ('\u{9be}', '\u{9c4}'), + ('ে', 'ৈ'), + ('ো', 'ৌ'), + ('\u{9d7}', '\u{9d7}'), + ('\u{9e2}', '\u{9e3}'), + ('\u{a01}', 'ਃ'), + ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4c}'), + ('\u{a51}', '\u{a51}'), + ('\u{a70}', '\u{a71}'), + ('\u{a75}', '\u{a75}'), + ('\u{a81}', 'ઃ'), + ('ા', '\u{ac5}'), + ('\u{ac7}', 'ૉ'), + ('à«‹', 'à«Œ'), + ('\u{ae2}', '\u{ae3}'), + ('\u{afa}', '\u{afc}'), + ('\u{b01}', 'ଃ'), + ('\u{b3e}', '\u{b44}'), + ('à­‡', 'à­ˆ'), + ('à­‹', 'à­Œ'), + ('\u{b56}', '\u{b57}'), + ('\u{b62}', '\u{b63}'), + ('\u{b82}', '\u{b82}'), + ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), + ('ொ', 'ௌ'), + ('\u{bd7}', '\u{bd7}'), + ('\u{c00}', '\u{c04}'), + ('\u{c3e}', 'ౄ'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4c}'), + ('\u{c55}', '\u{c56}'), + ('\u{c62}', '\u{c63}'), + ('\u{c81}', 'ಃ'), + ('ಾ', 'ೄ'), + ('\u{cc6}', 'ೈ'), + ('ೊ', '\u{ccc}'), + ('\u{cd5}', '\u{cd6}'), + ('\u{ce2}', '\u{ce3}'), + ('à³³', 'à³³'), + ('\u{d00}', 'à´ƒ'), + ('\u{d3e}', '\u{d44}'), + ('െ', 'ൈ'), + ('ൊ', 'ൌ'), + ('\u{d57}', '\u{d57}'), + ('\u{d62}', '\u{d63}'), + ('\u{d81}', 'ඃ'), + ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('à·˜', '\u{ddf}'), + ('à·²', 'à·³'), + ('\u{e31}', '\u{e31}'), + ('\u{e34}', '\u{e3a}'), + ('\u{e4d}', '\u{e4d}'), + ('\u{eb1}', '\u{eb1}'), + ('\u{eb4}', '\u{eb9}'), + ('\u{ebb}', '\u{ebc}'), + ('\u{ecd}', '\u{ecd}'), + ('\u{f71}', '\u{f83}'), + ('\u{f8d}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('ါ', '\u{1036}'), + ('း', 'း'), + ('ျ', '\u{103e}'), + ('á–', '\u{1059}'), + ('\u{105e}', '\u{1060}'), + ('á¢', 'á¤'), + ('á§', 'á­'), + ('\u{1071}', '\u{1074}'), + ('\u{1082}', '\u{108d}'), + ('á‚', 'á‚'), + ('á‚š', '\u{109d}'), + ('\u{1712}', '\u{1713}'), + ('\u{1732}', '\u{1733}'), + ('\u{1752}', '\u{1753}'), + ('\u{1772}', '\u{1773}'), + ('ា', 'ៈ'), + ('\u{1885}', '\u{1886}'), + ('\u{18a9}', '\u{18a9}'), + ('\u{1920}', 'ᤫ'), + ('ᤰ', 'ᤸ'), + ('\u{1a17}', '\u{1a1b}'), + ('á©•', '\u{1a5e}'), + ('á©¡', '\u{1a74}'), + ('\u{1abf}', '\u{1ac0}'), + ('\u{1acc}', '\u{1ace}'), + ('\u{1b00}', 'ᬄ'), + ('\u{1b35}', 'á­ƒ'), + ('\u{1b80}', 'ᮂ'), + ('ᮡ', '\u{1ba9}'), + ('\u{1bac}', '\u{1bad}'), + ('ᯧ', '\u{1bf1}'), + ('á°¤', '\u{1c36}'), + ('\u{1de7}', '\u{1df4}'), + ('â’¶', 'â“©'), + ('\u{2de0}', '\u{2dff}'), + ('\u{a674}', '\u{a67b}'), + ('\u{a69e}', '\u{a69f}'), + ('\u{a802}', '\u{a802}'), + ('\u{a80b}', '\u{a80b}'), + ('ê £', 'ê §'), + ('ꢀ', 'ê¢'), + ('ꢴ', 'ꣃ'), + ('\u{a8c5}', '\u{a8c5}'), + ('\u{a8ff}', '\u{a8ff}'), + ('\u{a926}', '\u{a92a}'), + ('\u{a947}', 'ꥒ'), + ('\u{a980}', 'ꦃ'), + ('ꦴ', 'ꦿ'), + ('\u{a9e5}', '\u{a9e5}'), + ('\u{aa29}', '\u{aa36}'), + ('\u{aa43}', '\u{aa43}'), + ('\u{aa4c}', 'ê©'), + ('ê©»', 'ꩽ'), + ('\u{aab0}', '\u{aab0}'), + ('\u{aab2}', '\u{aab4}'), + ('\u{aab7}', '\u{aab8}'), + ('\u{aabe}', '\u{aabe}'), + ('ê««', 'ꫯ'), + ('ꫵ', 'ꫵ'), + ('ꯣ', 'ꯪ'), + ('\u{fb1e}', '\u{fb1e}'), + ('\u{10376}', '\u{1037a}'), + ('\u{10a01}', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), + ('\u{10d24}', '\u{10d27}'), + ('\u{10eab}', '\u{10eac}'), + ('ð‘€€', '𑀂'), + ('\u{11038}', '\u{11045}'), + ('\u{11073}', '\u{11074}'), + ('\u{11080}', 'ð‘‚‚'), + ('ð‘‚°', '𑂸'), + ('\u{110c2}', '\u{110c2}'), + ('\u{11100}', '\u{11102}'), + ('\u{11127}', '\u{11132}'), + ('ð‘……', 'ð‘…†'), + ('\u{11180}', '𑆂'), + ('𑆳', '𑆿'), + ('𑇎', '\u{111cf}'), + ('𑈬', '\u{11234}'), + ('\u{11237}', '\u{11237}'), + ('\u{1123e}', '\u{1123e}'), + ('\u{11241}', '\u{11241}'), + ('\u{112df}', '\u{112e8}'), + ('\u{11300}', '𑌃'), + ('\u{1133e}', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘Œ'), + ('\u{11357}', '\u{11357}'), + ('ð‘¢', 'ð‘£'), + ('ð‘µ', 'ð‘‘'), + ('\u{11443}', 'ð‘‘…'), + ('\u{114b0}', 'ð‘“'), + ('\u{115af}', '\u{115b5}'), + ('ð‘–¸', 'ð‘–¾'), + ('\u{115dc}', '\u{115dd}'), + ('𑘰', '𑘾'), + ('\u{11640}', '\u{11640}'), + ('\u{116ab}', '\u{116b5}'), + ('\u{1171d}', '\u{1172a}'), + ('ð‘ ¬', 'ð‘ ¸'), + ('\u{11930}', '𑤵'), + ('𑤷', '𑤸'), + ('\u{1193b}', '\u{1193c}'), + ('ð‘¥€', 'ð‘¥€'), + ('𑥂', '𑥂'), + ('𑧑', '\u{119d7}'), + ('\u{119da}', '𑧟'), + ('𑧤', '𑧤'), + ('\u{11a01}', '\u{11a0a}'), + ('\u{11a35}', '𑨹'), + ('\u{11a3b}', '\u{11a3e}'), + ('\u{11a51}', '\u{11a5b}'), + ('\u{11a8a}', '𑪗'), + ('ð‘°¯', '\u{11c36}'), + ('\u{11c38}', 'ð‘°¾'), + ('\u{11c92}', '\u{11ca7}'), + ('𑲩', '\u{11cb6}'), + ('\u{11d31}', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d41}'), + ('\u{11d43}', '\u{11d43}'), + ('\u{11d47}', '\u{11d47}'), + ('𑶊', '𑶎'), + ('\u{11d90}', '\u{11d91}'), + ('𑶓', '𑶖'), + ('\u{11ef3}', '𑻶'), + ('\u{11f00}', '\u{11f01}'), + ('𑼃', '𑼃'), + ('𑼴', '\u{11f3a}'), + ('𑼾', '\u{11f40}'), + ('\u{16f4f}', '\u{16f4f}'), + ('𖽑', '𖾇'), + ('\u{16f8f}', '\u{16f92}'), + ('ð–¿°', 'ð–¿±'), + ('\u{1bc9e}', '\u{1bc9e}'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('\u{1e08f}', '\u{1e08f}'), + ('\u{1e947}', '\u{1e947}'), + ('🄰', '🅉'), + ('ðŸ…', '🅩'), + ('🅰', '🆉'), +]; + +pub const OTHER_DEFAULT_IGNORABLE_CODE_POINT: &'static [(char, char)] = &[ + ('\u{34f}', '\u{34f}'), + ('á…Ÿ', 'á… '), + ('\u{17b4}', '\u{17b5}'), + ('\u{2065}', '\u{2065}'), + ('ã…¤', 'ã…¤'), + ('ï¾ ', 'ï¾ '), + ('\u{fff0}', '\u{fff8}'), + ('\u{e0000}', '\u{e0000}'), + ('\u{e0002}', '\u{e001f}'), + ('\u{e0080}', '\u{e00ff}'), + ('\u{e01f0}', '\u{e0fff}'), +]; + +pub const OTHER_GRAPHEME_EXTEND: &'static [(char, char)] = &[ + ('\u{9be}', '\u{9be}'), + ('\u{9d7}', '\u{9d7}'), + ('\u{b3e}', '\u{b3e}'), + ('\u{b57}', '\u{b57}'), + ('\u{bbe}', '\u{bbe}'), + ('\u{bd7}', '\u{bd7}'), + ('\u{cc2}', '\u{cc2}'), + ('\u{cd5}', '\u{cd6}'), + ('\u{d3e}', '\u{d3e}'), + ('\u{d57}', '\u{d57}'), + ('\u{dcf}', '\u{dcf}'), + ('\u{ddf}', '\u{ddf}'), + ('\u{1b35}', '\u{1b35}'), + ('\u{200c}', '\u{200c}'), + ('\u{302e}', '\u{302f}'), + ('\u{ff9e}', '\u{ff9f}'), + ('\u{1133e}', '\u{1133e}'), + ('\u{11357}', '\u{11357}'), + ('\u{114b0}', '\u{114b0}'), + ('\u{114bd}', '\u{114bd}'), + ('\u{115af}', '\u{115af}'), + ('\u{11930}', '\u{11930}'), + ('\u{1d165}', '\u{1d165}'), + ('\u{1d16e}', '\u{1d172}'), + ('\u{e0020}', '\u{e007f}'), +]; + +pub const OTHER_ID_CONTINUE: &'static [(char, char)] = + &[('·', '·'), ('·', '·'), ('á©', 'á±'), ('᧚', '᧚')]; + +pub const OTHER_ID_START: &'static [(char, char)] = + &[('\u{1885}', '\u{1886}'), ('℘', '℘'), ('â„®', 'â„®'), ('ã‚›', 'ã‚œ')]; + +pub const OTHER_LOWERCASE: &'static [(char, char)] = &[ + ('ª', 'ª'), + ('º', 'º'), + ('Ê°', 'ʸ'), + ('Ë€', 'Ë'), + ('Ë ', 'ˤ'), + ('\u{345}', '\u{345}'), + ('ͺ', 'ͺ'), + ('ჼ', 'ჼ'), + ('á´¬', 'ᵪ'), + ('ᵸ', 'ᵸ'), + ('ᶛ', 'ᶿ'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('â…°', 'â…¿'), + ('â“', 'â“©'), + ('â±¼', 'â±½'), + ('êšœ', 'êš'), + ('ê°', 'ê°'), + ('ꟲ', 'ꟴ'), + ('ꟸ', 'ꟹ'), + ('ê­œ', 'ê­Ÿ'), + ('ê­©', 'ê­©'), + ('ðž€', 'ðž€'), + ('ðžƒ', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('𞀰', 'ðž­'), +]; + +pub const OTHER_MATH: &'static [(char, char)] = &[ + ('^', '^'), + ('Ï', 'Ï’'), + ('Ï•', 'Ï•'), + ('Ï°', 'ϱ'), + ('Ï´', 'ϵ'), + ('‖', '‖'), + ('′', '‴'), + ('â€', 'â€'), + ('\u{2061}', '\u{2064}'), + ('â½', 'â¾'), + ('â‚', 'â‚Ž'), + ('\u{20d0}', '\u{20dc}'), + ('\u{20e1}', '\u{20e1}'), + ('\u{20e5}', '\u{20e6}'), + ('\u{20eb}', '\u{20ef}'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„Š', 'â„“'), + ('â„•', 'â„•'), + ('â„™', 'â„'), + ('ℤ', 'ℤ'), + ('ℨ', 'â„©'), + ('ℬ', 'â„­'), + ('ℯ', 'ℱ'), + ('ℳ', 'ℸ'), + ('ℼ', 'â„¿'), + ('â……', 'â…‰'), + ('↕', '↙'), + ('↜', '↟'), + ('↡', '↢'), + ('↤', '↥'), + ('↧', '↧'), + ('↩', '↭'), + ('↰', '↱'), + ('↶', '↷'), + ('↼', 'â‡'), + ('â‡', '⇑'), + ('⇓', '⇓'), + ('⇕', '⇛'), + ('â‡', 'â‡'), + ('⇤', '⇥'), + ('⌈', '⌋'), + ('⎴', '⎵'), + ('⎷', '⎷'), + ('â', 'â'), + ('â¢', 'â¢'), + ('â– ', 'â–¡'), + ('â–®', 'â–¶'), + ('â–¼', 'â—€'), + ('â—†', 'â—‡'), + ('â—Š', 'â—‹'), + ('â—', 'â—“'), + ('â—¢', 'â—¢'), + ('â—¤', 'â—¤'), + ('â—§', 'â—¬'), + ('★', '☆'), + ('♀', '♀'), + ('♂', '♂'), + ('â™ ', '♣'), + ('â™­', 'â™®'), + ('⟅', '⟆'), + ('⟦', '⟯'), + ('⦃', '⦘'), + ('⧘', '⧛'), + ('⧼', '⧽'), + ('﹡', '﹡'), + ('ï¹£', 'ï¹£'), + ('﹨', '﹨'), + ('ï¼¼', 'ï¼¼'), + ('ï¼¾', 'ï¼¾'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ð›€'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›º'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ´'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð®'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž¨'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‹'), + ('ðŸŽ', 'ðŸ¿'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), +]; + +pub const OTHER_UPPERCASE: &'static [(char, char)] = + &[('â… ', 'â…¯'), ('â’¶', 'â“'), ('🄰', '🅉'), ('ðŸ…', '🅩'), ('🅰', '🆉')]; + +pub const PATTERN_SYNTAX: &'static [(char, char)] = &[ + ('!', '/'), + (':', '@'), + ('[', '^'), + ('`', '`'), + ('{', '~'), + ('¡', '§'), + ('©', '©'), + ('«', '¬'), + ('®', '®'), + ('°', '±'), + ('¶', '¶'), + ('»', '»'), + ('¿', '¿'), + ('×', '×'), + ('÷', '÷'), + ('â€', '‧'), + ('‰', '‾'), + ('â', 'â“'), + ('â•', 'âž'), + ('â†', '\u{245f}'), + ('─', 'âµ'), + ('âž”', '⯿'), + ('⸀', '\u{2e7f}'), + ('ã€', '〃'), + ('〈', '〠'), + ('〰', '〰'), + ('ï´¾', 'ï´¿'), + ('ï¹…', '﹆'), +]; + +pub const PATTERN_WHITE_SPACE: &'static [(char, char)] = &[ + ('\t', '\r'), + (' ', ' '), + ('\u{85}', '\u{85}'), + ('\u{200e}', '\u{200f}'), + ('\u{2028}', '\u{2029}'), +]; + +pub const PREPENDED_CONCATENATION_MARK: &'static [(char, char)] = &[ + ('\u{600}', '\u{605}'), + ('\u{6dd}', '\u{6dd}'), + ('\u{70f}', '\u{70f}'), + ('\u{890}', '\u{891}'), + ('\u{8e2}', '\u{8e2}'), + ('\u{110bd}', '\u{110bd}'), + ('\u{110cd}', '\u{110cd}'), +]; + +pub const QUOTATION_MARK: &'static [(char, char)] = &[ + ('"', '"'), + ('\'', '\''), + ('«', '«'), + ('»', '»'), + ('‘', '‟'), + ('‹', '›'), + ('⹂', '⹂'), + ('「', 'ã€'), + ('ã€', '〟'), + ('ï¹', '﹄'), + ('"', '"'), + (''', '''), + ('ï½¢', 'ï½£'), +]; + +pub const RADICAL: &'static [(char, char)] = + &[('⺀', '⺙'), ('⺛', '⻳'), ('â¼€', 'â¿•')]; + +pub const REGIONAL_INDICATOR: &'static [(char, char)] = &[('🇦', '🇿')]; + +pub const SENTENCE_TERMINAL: &'static [(char, char)] = &[ + ('!', '!'), + ('.', '.'), + ('?', '?'), + ('Ö‰', 'Ö‰'), + ('Ø', 'ØŸ'), + ('Û”', 'Û”'), + ('Ü€', 'Ü‚'), + ('ß¹', 'ß¹'), + ('à ·', 'à ·'), + ('à ¹', 'à ¹'), + ('à ½', 'à ¾'), + ('।', '॥'), + ('áŠ', 'á‹'), + ('á¢', 'á¢'), + ('á§', 'á¨'), + ('á™®', 'á™®'), + ('᜵', '᜶'), + ('á ƒ', 'á ƒ'), + ('á ‰', 'á ‰'), + ('᥄', '᥅'), + ('᪨', '᪫'), + ('á­š', 'á­›'), + ('á­ž', 'á­Ÿ'), + ('á­½', 'á­¾'), + ('á°»', 'á°¼'), + ('á±¾', '᱿'), + ('‼', '‽'), + ('â‡', 'â‰'), + ('⸮', '⸮'), + ('⸼', '⸼'), + ('⹓', 'â¹”'), + ('。', '。'), + ('ê“¿', 'ê“¿'), + ('꘎', 'ê˜'), + ('꛳', '꛳'), + ('ê›·', 'ê›·'), + ('꡶', 'ê¡·'), + ('꣎', 'ê£'), + ('꤯', '꤯'), + ('꧈', '꧉'), + ('ê©', 'ê©Ÿ'), + ('ê«°', '꫱'), + ('꯫', '꯫'), + ('ï¹’', 'ï¹’'), + ('ï¹–', 'ï¹—'), + ('ï¼', 'ï¼'), + ('.', '.'), + ('?', '?'), + ('。', '。'), + ('ð©–', 'ð©—'), + ('ð½•', 'ð½™'), + ('ð¾†', 'ð¾‰'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‚¾', 'ð‘ƒ'), + ('ð‘…', 'ð‘…ƒ'), + ('𑇅', '𑇆'), + ('ð‘‡', 'ð‘‡'), + ('𑇞', '𑇟'), + ('𑈸', '𑈹'), + ('𑈻', '𑈼'), + ('ð‘Š©', 'ð‘Š©'), + ('ð‘‘‹', 'ð‘‘Œ'), + ('ð‘—‚', 'ð‘—ƒ'), + ('ð‘—‰', 'ð‘——'), + ('ð‘™', 'ð‘™‚'), + ('𑜼', '𑜾'), + ('𑥄', '𑥄'), + ('𑥆', '𑥆'), + ('ð‘©‚', '𑩃'), + ('𑪛', '𑪜'), + ('ð‘±', '𑱂'), + ('ð‘»·', '𑻸'), + ('𑽃', '𑽄'), + ('ð–©®', '𖩯'), + ('ð–«µ', 'ð–«µ'), + ('ð–¬·', '𖬸'), + ('ð–­„', 'ð–­„'), + ('𖺘', '𖺘'), + ('𛲟', '𛲟'), + ('ðªˆ', 'ðªˆ'), +]; + +pub const SOFT_DOTTED: &'static [(char, char)] = &[ + ('i', 'j'), + ('į', 'į'), + ('ɉ', 'ɉ'), + ('ɨ', 'ɨ'), + ('Ê', 'Ê'), + ('ʲ', 'ʲ'), + ('ϳ', 'ϳ'), + ('Ñ–', 'Ñ–'), + ('ј', 'ј'), + ('áµ¢', 'áµ¢'), + ('ᶖ', 'ᶖ'), + ('ᶤ', 'ᶤ'), + ('ᶨ', 'ᶨ'), + ('ḭ', 'ḭ'), + ('ị', 'ị'), + ('â±', 'â±'), + ('â…ˆ', 'â…‰'), + ('â±¼', 'â±¼'), + ('ð¢', 'ð£'), + ('ð‘–', 'ð‘—'), + ('ð’Š', 'ð’‹'), + ('ð’¾', 'ð’¿'), + ('ð“²', 'ð“³'), + ('ð”¦', 'ð”§'), + ('ð•š', 'ð•›'), + ('ð–Ž', 'ð–'), + ('ð—‚', 'ð—ƒ'), + ('ð—¶', 'ð—·'), + ('ð˜ª', 'ð˜«'), + ('ð™ž', 'ð™Ÿ'), + ('ðš’', 'ðš“'), + ('ð¼š', 'ð¼š'), + ('ðžŒ', 'ðž'), + ('ðž¨', 'ðž¨'), +]; + +pub const TERMINAL_PUNCTUATION: &'static [(char, char)] = &[ + ('!', '!'), + (',', ','), + ('.', '.'), + (':', ';'), + ('?', '?'), + (';', ';'), + ('·', '·'), + ('Ö‰', 'Ö‰'), + ('׃', '׃'), + ('ØŒ', 'ØŒ'), + ('Ø›', 'Ø›'), + ('Ø', 'ØŸ'), + ('Û”', 'Û”'), + ('Ü€', 'ÜŠ'), + ('ÜŒ', 'ÜŒ'), + ('߸', 'ß¹'), + ('à °', 'à ¾'), + ('à¡ž', 'à¡ž'), + ('।', '॥'), + ('๚', '๛'), + ('༈', '༈'), + ('à¼', '༒'), + ('áŠ', 'á‹'), + ('á¡', 'á¨'), + ('á™®', 'á™®'), + ('᛫', 'á›­'), + ('᜵', '᜶'), + ('។', '៖'), + ('៚', '៚'), + ('á ‚', 'á …'), + ('á ˆ', 'á ‰'), + ('᥄', '᥅'), + ('᪨', '᪫'), + ('á­š', 'á­›'), + ('á­', 'á­Ÿ'), + ('á­½', 'á­¾'), + ('á°»', 'á°¿'), + ('á±¾', '᱿'), + ('‼', '‽'), + ('â‡', 'â‰'), + ('⸮', '⸮'), + ('⸼', '⸼'), + ('â¹', 'â¹'), + ('⹌', '⹌'), + ('⹎', 'â¹'), + ('⹓', 'â¹”'), + ('ã€', '。'), + ('꓾', 'ê“¿'), + ('ê˜', 'ê˜'), + ('꛳', 'ê›·'), + ('꡶', 'ê¡·'), + ('꣎', 'ê£'), + ('꤯', '꤯'), + ('꧇', '꧉'), + ('ê©', 'ê©Ÿ'), + ('ê«Ÿ', 'ê«Ÿ'), + ('ê«°', '꫱'), + ('꯫', '꯫'), + ('ï¹', 'ï¹’'), + ('ï¹”', 'ï¹—'), + ('ï¼', 'ï¼'), + (',', ','), + ('.', '.'), + (':', 'ï¼›'), + ('?', '?'), + ('。', '。'), + ('、', '、'), + ('ðŽŸ', 'ðŽŸ'), + ('ð', 'ð'), + ('ð¡—', 'ð¡—'), + ('ð¤Ÿ', 'ð¤Ÿ'), + ('ð©–', 'ð©—'), + ('ð«°', 'ð«µ'), + ('ð¬º', 'ð¬¿'), + ('ð®™', 'ð®œ'), + ('ð½•', 'ð½™'), + ('ð¾†', 'ð¾‰'), + ('ð‘‡', 'ð‘'), + ('ð‘‚¾', 'ð‘ƒ'), + ('ð‘…', 'ð‘…ƒ'), + ('𑇅', '𑇆'), + ('ð‘‡', 'ð‘‡'), + ('𑇞', '𑇟'), + ('𑈸', '𑈼'), + ('ð‘Š©', 'ð‘Š©'), + ('ð‘‘‹', 'ð‘‘'), + ('ð‘‘š', 'ð‘‘›'), + ('ð‘—‚', 'ð‘—…'), + ('ð‘—‰', 'ð‘——'), + ('ð‘™', 'ð‘™‚'), + ('𑜼', '𑜾'), + ('𑥄', '𑥄'), + ('𑥆', '𑥆'), + ('ð‘©‚', '𑩃'), + ('𑪛', '𑪜'), + ('𑪡', '𑪢'), + ('ð‘±', '𑱃'), + ('𑱱', '𑱱'), + ('ð‘»·', '𑻸'), + ('𑽃', '𑽄'), + ('ð’‘°', 'ð’‘´'), + ('ð–©®', '𖩯'), + ('ð–«µ', 'ð–«µ'), + ('ð–¬·', '𖬹'), + ('ð–­„', 'ð–­„'), + ('ð–º—', '𖺘'), + ('𛲟', '𛲟'), + ('ðª‡', 'ðªŠ'), +]; + +pub const UNIFIED_IDEOGRAPH: &'static [(char, char)] = &[ + ('ã€', '䶿'), + ('一', 'é¿¿'), + ('﨎', 'ï¨'), + ('﨑', '﨑'), + ('﨓', '﨔'), + ('﨟', '﨟'), + ('﨡', '﨡'), + ('﨣', '﨤'), + ('﨧', '﨩'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), +]; + +pub const UPPERCASE: &'static [(char, char)] = &[ + ('A', 'Z'), + ('À', 'Ö'), + ('Ø', 'Þ'), + ('Ä€', 'Ä€'), + ('Ä‚', 'Ä‚'), + ('Ä„', 'Ä„'), + ('Ć', 'Ć'), + ('Ĉ', 'Ĉ'), + ('ÄŠ', 'ÄŠ'), + ('ÄŒ', 'ÄŒ'), + ('ÄŽ', 'ÄŽ'), + ('Ä', 'Ä'), + ('Ä’', 'Ä’'), + ('Ä”', 'Ä”'), + ('Ä–', 'Ä–'), + ('Ę', 'Ę'), + ('Äš', 'Äš'), + ('Äœ', 'Äœ'), + ('Äž', 'Äž'), + ('Ä ', 'Ä '), + ('Ä¢', 'Ä¢'), + ('Ĥ', 'Ĥ'), + ('Ħ', 'Ħ'), + ('Ĩ', 'Ĩ'), + ('Ī', 'Ī'), + ('Ĭ', 'Ĭ'), + ('Ä®', 'Ä®'), + ('Ä°', 'Ä°'), + ('IJ', 'IJ'), + ('Ä´', 'Ä´'), + ('Ķ', 'Ķ'), + ('Ĺ', 'Ĺ'), + ('Ä»', 'Ä»'), + ('Ľ', 'Ľ'), + ('Ä¿', 'Ä¿'), + ('Å', 'Å'), + ('Ń', 'Ń'), + ('Å…', 'Å…'), + ('Ň', 'Ň'), + ('ÅŠ', 'ÅŠ'), + ('ÅŒ', 'ÅŒ'), + ('ÅŽ', 'ÅŽ'), + ('Å', 'Å'), + ('Å’', 'Å’'), + ('Å”', 'Å”'), + ('Å–', 'Å–'), + ('Ř', 'Ř'), + ('Åš', 'Åš'), + ('Åœ', 'Åœ'), + ('Åž', 'Åž'), + ('Å ', 'Å '), + ('Å¢', 'Å¢'), + ('Ť', 'Ť'), + ('Ŧ', 'Ŧ'), + ('Ũ', 'Ũ'), + ('Ū', 'Ū'), + ('Ŭ', 'Ŭ'), + ('Å®', 'Å®'), + ('Å°', 'Å°'), + ('Ų', 'Ų'), + ('Å´', 'Å´'), + ('Ŷ', 'Ŷ'), + ('Ÿ', 'Ź'), + ('Å»', 'Å»'), + ('Ž', 'Ž'), + ('Æ', 'Æ‚'), + ('Æ„', 'Æ„'), + ('Ɔ', 'Ƈ'), + ('Ɖ', 'Æ‹'), + ('ÆŽ', 'Æ‘'), + ('Æ“', 'Æ”'), + ('Æ–', 'Ƙ'), + ('Æœ', 'Æ'), + ('ÆŸ', 'Æ '), + ('Æ¢', 'Æ¢'), + ('Ƥ', 'Ƥ'), + ('Ʀ', 'Ƨ'), + ('Æ©', 'Æ©'), + ('Ƭ', 'Ƭ'), + ('Æ®', 'Ư'), + ('Ʊ', 'Ƴ'), + ('Ƶ', 'Ƶ'), + ('Æ·', 'Ƹ'), + ('Ƽ', 'Ƽ'), + ('Ç„', 'Ç„'), + ('LJ', 'LJ'), + ('ÇŠ', 'ÇŠ'), + ('Ç', 'Ç'), + ('Ç', 'Ç'), + ('Ç‘', 'Ç‘'), + ('Ç“', 'Ç“'), + ('Ç•', 'Ç•'), + ('Ç—', 'Ç—'), + ('Ç™', 'Ç™'), + ('Ç›', 'Ç›'), + ('Çž', 'Çž'), + ('Ç ', 'Ç '), + ('Ç¢', 'Ç¢'), + ('Ǥ', 'Ǥ'), + ('Ǧ', 'Ǧ'), + ('Ǩ', 'Ǩ'), + ('Ǫ', 'Ǫ'), + ('Ǭ', 'Ǭ'), + ('Ç®', 'Ç®'), + ('DZ', 'DZ'), + ('Ç´', 'Ç´'), + ('Ƕ', 'Ǹ'), + ('Ǻ', 'Ǻ'), + ('Ǽ', 'Ǽ'), + ('Ǿ', 'Ǿ'), + ('È€', 'È€'), + ('È‚', 'È‚'), + ('È„', 'È„'), + ('Ȇ', 'Ȇ'), + ('Ȉ', 'Ȉ'), + ('ÈŠ', 'ÈŠ'), + ('ÈŒ', 'ÈŒ'), + ('ÈŽ', 'ÈŽ'), + ('È', 'È'), + ('È’', 'È’'), + ('È”', 'È”'), + ('È–', 'È–'), + ('Ș', 'Ș'), + ('Èš', 'Èš'), + ('Èœ', 'Èœ'), + ('Èž', 'Èž'), + ('È ', 'È '), + ('È¢', 'È¢'), + ('Ȥ', 'Ȥ'), + ('Ȧ', 'Ȧ'), + ('Ȩ', 'Ȩ'), + ('Ȫ', 'Ȫ'), + ('Ȭ', 'Ȭ'), + ('È®', 'È®'), + ('È°', 'È°'), + ('Ȳ', 'Ȳ'), + ('Ⱥ', 'È»'), + ('Ƚ', 'Ⱦ'), + ('É', 'É'), + ('Ƀ', 'Ɇ'), + ('Ɉ', 'Ɉ'), + ('ÉŠ', 'ÉŠ'), + ('ÉŒ', 'ÉŒ'), + ('ÉŽ', 'ÉŽ'), + ('Í°', 'Í°'), + ('Ͳ', 'Ͳ'), + ('Ͷ', 'Ͷ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Î'), + ('Α', 'Ρ'), + ('Σ', 'Ϋ'), + ('Ï', 'Ï'), + ('Ï’', 'Ï”'), + ('Ϙ', 'Ϙ'), + ('Ïš', 'Ïš'), + ('Ïœ', 'Ïœ'), + ('Ïž', 'Ïž'), + ('Ï ', 'Ï '), + ('Ï¢', 'Ï¢'), + ('Ϥ', 'Ϥ'), + ('Ϧ', 'Ϧ'), + ('Ϩ', 'Ϩ'), + ('Ϫ', 'Ϫ'), + ('Ϭ', 'Ϭ'), + ('Ï®', 'Ï®'), + ('Ï´', 'Ï´'), + ('Ï·', 'Ï·'), + ('Ϲ', 'Ϻ'), + ('Ͻ', 'Я'), + ('Ñ ', 'Ñ '), + ('Ñ¢', 'Ñ¢'), + ('Ѥ', 'Ѥ'), + ('Ѧ', 'Ѧ'), + ('Ѩ', 'Ѩ'), + ('Ѫ', 'Ѫ'), + ('Ѭ', 'Ѭ'), + ('Ñ®', 'Ñ®'), + ('Ñ°', 'Ñ°'), + ('Ѳ', 'Ѳ'), + ('Ñ´', 'Ñ´'), + ('Ѷ', 'Ѷ'), + ('Ѹ', 'Ѹ'), + ('Ѻ', 'Ѻ'), + ('Ѽ', 'Ѽ'), + ('Ѿ', 'Ѿ'), + ('Ò€', 'Ò€'), + ('ÒŠ', 'ÒŠ'), + ('ÒŒ', 'ÒŒ'), + ('ÒŽ', 'ÒŽ'), + ('Ò', 'Ò'), + ('Ò’', 'Ò’'), + ('Ò”', 'Ò”'), + ('Ò–', 'Ò–'), + ('Ò˜', 'Ò˜'), + ('Òš', 'Òš'), + ('Òœ', 'Òœ'), + ('Òž', 'Òž'), + ('Ò ', 'Ò '), + ('Ò¢', 'Ò¢'), + ('Ò¤', 'Ò¤'), + ('Ò¦', 'Ò¦'), + ('Ò¨', 'Ò¨'), + ('Òª', 'Òª'), + ('Ò¬', 'Ò¬'), + ('Ò®', 'Ò®'), + ('Ò°', 'Ò°'), + ('Ò²', 'Ò²'), + ('Ò´', 'Ò´'), + ('Ò¶', 'Ò¶'), + ('Ò¸', 'Ò¸'), + ('Òº', 'Òº'), + ('Ò¼', 'Ò¼'), + ('Ò¾', 'Ò¾'), + ('Ó€', 'Ó'), + ('Óƒ', 'Óƒ'), + ('Ó…', 'Ó…'), + ('Ó‡', 'Ó‡'), + ('Ó‰', 'Ó‰'), + ('Ó‹', 'Ó‹'), + ('Ó', 'Ó'), + ('Ó', 'Ó'), + ('Ó’', 'Ó’'), + ('Ó”', 'Ó”'), + ('Ó–', 'Ó–'), + ('Ó˜', 'Ó˜'), + ('Óš', 'Óš'), + ('Óœ', 'Óœ'), + ('Óž', 'Óž'), + ('Ó ', 'Ó '), + ('Ó¢', 'Ó¢'), + ('Ó¤', 'Ó¤'), + ('Ó¦', 'Ó¦'), + ('Ó¨', 'Ó¨'), + ('Óª', 'Óª'), + ('Ó¬', 'Ó¬'), + ('Ó®', 'Ó®'), + ('Ó°', 'Ó°'), + ('Ó²', 'Ó²'), + ('Ó´', 'Ó´'), + ('Ó¶', 'Ó¶'), + ('Ó¸', 'Ó¸'), + ('Óº', 'Óº'), + ('Ó¼', 'Ó¼'), + ('Ó¾', 'Ó¾'), + ('Ô€', 'Ô€'), + ('Ô‚', 'Ô‚'), + ('Ô„', 'Ô„'), + ('Ô†', 'Ô†'), + ('Ôˆ', 'Ôˆ'), + ('ÔŠ', 'ÔŠ'), + ('ÔŒ', 'ÔŒ'), + ('ÔŽ', 'ÔŽ'), + ('Ô', 'Ô'), + ('Ô’', 'Ô’'), + ('Ô”', 'Ô”'), + ('Ô–', 'Ô–'), + ('Ô˜', 'Ô˜'), + ('Ôš', 'Ôš'), + ('Ôœ', 'Ôœ'), + ('Ôž', 'Ôž'), + ('Ô ', 'Ô '), + ('Ô¢', 'Ô¢'), + ('Ô¤', 'Ô¤'), + ('Ô¦', 'Ô¦'), + ('Ô¨', 'Ô¨'), + ('Ôª', 'Ôª'), + ('Ô¬', 'Ô¬'), + ('Ô®', 'Ô®'), + ('Ô±', 'Õ–'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('Ꭰ', 'áµ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('Ḁ', 'Ḁ'), + ('Ḃ', 'Ḃ'), + ('Ḅ', 'Ḅ'), + ('Ḇ', 'Ḇ'), + ('Ḉ', 'Ḉ'), + ('Ḋ', 'Ḋ'), + ('Ḍ', 'Ḍ'), + ('Ḏ', 'Ḏ'), + ('á¸', 'á¸'), + ('Ḓ', 'Ḓ'), + ('Ḕ', 'Ḕ'), + ('Ḗ', 'Ḗ'), + ('Ḙ', 'Ḙ'), + ('Ḛ', 'Ḛ'), + ('Ḝ', 'Ḝ'), + ('Ḟ', 'Ḟ'), + ('Ḡ', 'Ḡ'), + ('Ḣ', 'Ḣ'), + ('Ḥ', 'Ḥ'), + ('Ḧ', 'Ḧ'), + ('Ḩ', 'Ḩ'), + ('Ḫ', 'Ḫ'), + ('Ḭ', 'Ḭ'), + ('Ḯ', 'Ḯ'), + ('Ḱ', 'Ḱ'), + ('Ḳ', 'Ḳ'), + ('Ḵ', 'Ḵ'), + ('Ḷ', 'Ḷ'), + ('Ḹ', 'Ḹ'), + ('Ḻ', 'Ḻ'), + ('Ḽ', 'Ḽ'), + ('Ḿ', 'Ḿ'), + ('á¹€', 'á¹€'), + ('Ṃ', 'Ṃ'), + ('Ṅ', 'Ṅ'), + ('Ṇ', 'Ṇ'), + ('Ṉ', 'Ṉ'), + ('Ṋ', 'Ṋ'), + ('Ṍ', 'Ṍ'), + ('Ṏ', 'Ṏ'), + ('á¹', 'á¹'), + ('á¹’', 'á¹’'), + ('á¹”', 'á¹”'), + ('á¹–', 'á¹–'), + ('Ṙ', 'Ṙ'), + ('Ṛ', 'Ṛ'), + ('Ṝ', 'Ṝ'), + ('Ṟ', 'Ṟ'), + ('á¹ ', 'á¹ '), + ('á¹¢', 'á¹¢'), + ('Ṥ', 'Ṥ'), + ('Ṧ', 'Ṧ'), + ('Ṩ', 'Ṩ'), + ('Ṫ', 'Ṫ'), + ('Ṭ', 'Ṭ'), + ('á¹®', 'á¹®'), + ('á¹°', 'á¹°'), + ('á¹²', 'á¹²'), + ('á¹´', 'á¹´'), + ('Ṷ', 'Ṷ'), + ('Ṹ', 'Ṹ'), + ('Ṻ', 'Ṻ'), + ('á¹¼', 'á¹¼'), + ('á¹¾', 'á¹¾'), + ('Ẁ', 'Ẁ'), + ('Ẃ', 'Ẃ'), + ('Ẅ', 'Ẅ'), + ('Ẇ', 'Ẇ'), + ('Ẉ', 'Ẉ'), + ('Ẋ', 'Ẋ'), + ('Ẍ', 'Ẍ'), + ('Ẏ', 'Ẏ'), + ('áº', 'áº'), + ('Ẓ', 'Ẓ'), + ('Ẕ', 'Ẕ'), + ('ẞ', 'ẞ'), + ('Ạ', 'Ạ'), + ('Ả', 'Ả'), + ('Ấ', 'Ấ'), + ('Ầ', 'Ầ'), + ('Ẩ', 'Ẩ'), + ('Ẫ', 'Ẫ'), + ('Ậ', 'Ậ'), + ('Ắ', 'Ắ'), + ('Ằ', 'Ằ'), + ('Ẳ', 'Ẳ'), + ('Ẵ', 'Ẵ'), + ('Ặ', 'Ặ'), + ('Ẹ', 'Ẹ'), + ('Ẻ', 'Ẻ'), + ('Ẽ', 'Ẽ'), + ('Ế', 'Ế'), + ('Ề', 'Ề'), + ('Ể', 'Ể'), + ('Ễ', 'Ễ'), + ('Ệ', 'Ệ'), + ('Ỉ', 'Ỉ'), + ('Ị', 'Ị'), + ('Ọ', 'Ọ'), + ('Ỏ', 'Ỏ'), + ('á»', 'á»'), + ('á»’', 'á»’'), + ('á»”', 'á»”'), + ('á»–', 'á»–'), + ('Ộ', 'Ộ'), + ('Ớ', 'Ớ'), + ('Ờ', 'Ờ'), + ('Ở', 'Ở'), + ('á» ', 'á» '), + ('Ợ', 'Ợ'), + ('Ụ', 'Ụ'), + ('Ủ', 'Ủ'), + ('Ứ', 'Ứ'), + ('Ừ', 'Ừ'), + ('Ử', 'Ử'), + ('á»®', 'á»®'), + ('á»°', 'á»°'), + ('Ỳ', 'Ỳ'), + ('á»´', 'á»´'), + ('Ỷ', 'Ỷ'), + ('Ỹ', 'Ỹ'), + ('Ỻ', 'Ỻ'), + ('Ỽ', 'Ỽ'), + ('Ỿ', 'Ỿ'), + ('Ἀ', 'á¼'), + ('Ἐ', 'á¼'), + ('Ἠ', 'Ἧ'), + ('Ἰ', 'Ἷ'), + ('Ὀ', 'á½'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'Ὗ'), + ('Ὠ', 'Ὧ'), + ('Ᾰ', 'á¾»'), + ('Ὲ', 'á¿‹'), + ('Ῐ', 'á¿›'), + ('Ῠ', 'Ῥ'), + ('Ὸ', 'á¿»'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„‹', 'â„'), + ('â„', 'â„’'), + ('â„•', 'â„•'), + ('â„™', 'â„'), + ('ℤ', 'ℤ'), + ('Ω', 'Ω'), + ('ℨ', 'ℨ'), + ('K', 'â„­'), + ('â„°', 'ℳ'), + ('ℾ', 'â„¿'), + ('â……', 'â……'), + ('â… ', 'â…¯'), + ('Ↄ', 'Ↄ'), + ('â’¶', 'â“'), + ('â°€', 'â°¯'), + ('â± ', 'â± '), + ('â±¢', 'Ɽ'), + ('Ⱨ', 'Ⱨ'), + ('Ⱪ', 'Ⱪ'), + ('Ⱬ', 'Ⱬ'), + ('â±­', 'â±°'), + ('â±²', 'â±²'), + ('â±µ', 'â±µ'), + ('â±¾', 'â²€'), + ('Ⲃ', 'Ⲃ'), + ('Ⲅ', 'Ⲅ'), + ('Ⲇ', 'Ⲇ'), + ('Ⲉ', 'Ⲉ'), + ('Ⲋ', 'Ⲋ'), + ('Ⲍ', 'Ⲍ'), + ('Ⲏ', 'Ⲏ'), + ('â²', 'â²'), + ('â²’', 'â²’'), + ('â²”', 'â²”'), + ('â²–', 'â²–'), + ('Ⲙ', 'Ⲙ'), + ('Ⲛ', 'Ⲛ'), + ('Ⲝ', 'Ⲝ'), + ('Ⲟ', 'Ⲟ'), + ('â² ', 'â² '), + ('â²¢', 'â²¢'), + ('Ⲥ', 'Ⲥ'), + ('Ⲧ', 'Ⲧ'), + ('Ⲩ', 'Ⲩ'), + ('Ⲫ', 'Ⲫ'), + ('Ⲭ', 'Ⲭ'), + ('â²®', 'â²®'), + ('â²°', 'â²°'), + ('â²²', 'â²²'), + ('â²´', 'â²´'), + ('Ⲷ', 'Ⲷ'), + ('Ⲹ', 'Ⲹ'), + ('Ⲻ', 'Ⲻ'), + ('â²¼', 'â²¼'), + ('â²¾', 'â²¾'), + ('â³€', 'â³€'), + ('Ⳃ', 'Ⳃ'), + ('Ⳅ', 'Ⳅ'), + ('Ⳇ', 'Ⳇ'), + ('Ⳉ', 'Ⳉ'), + ('Ⳋ', 'Ⳋ'), + ('Ⳍ', 'Ⳍ'), + ('Ⳏ', 'Ⳏ'), + ('â³', 'â³'), + ('â³’', 'â³’'), + ('â³”', 'â³”'), + ('â³–', 'â³–'), + ('Ⳙ', 'Ⳙ'), + ('Ⳛ', 'Ⳛ'), + ('Ⳝ', 'Ⳝ'), + ('Ⳟ', 'Ⳟ'), + ('â³ ', 'â³ '), + ('â³¢', 'â³¢'), + ('Ⳬ', 'Ⳬ'), + ('â³­', 'â³­'), + ('â³²', 'â³²'), + ('Ꙁ', 'Ꙁ'), + ('Ꙃ', 'Ꙃ'), + ('Ꙅ', 'Ꙅ'), + ('Ꙇ', 'Ꙇ'), + ('Ꙉ', 'Ꙉ'), + ('Ꙋ', 'Ꙋ'), + ('Ꙍ', 'Ꙍ'), + ('Ꙏ', 'Ꙏ'), + ('ê™', 'ê™'), + ('ê™’', 'ê™’'), + ('ê™”', 'ê™”'), + ('ê™–', 'ê™–'), + ('Ꙙ', 'Ꙙ'), + ('Ꙛ', 'Ꙛ'), + ('Ꙝ', 'Ꙝ'), + ('Ꙟ', 'Ꙟ'), + ('ê™ ', 'ê™ '), + ('Ꙣ', 'Ꙣ'), + ('Ꙥ', 'Ꙥ'), + ('Ꙧ', 'Ꙧ'), + ('Ꙩ', 'Ꙩ'), + ('Ꙫ', 'Ꙫ'), + ('Ꙭ', 'Ꙭ'), + ('Ꚁ', 'Ꚁ'), + ('êš‚', 'êš‚'), + ('êš„', 'êš„'), + ('Ꚇ', 'Ꚇ'), + ('Ꚉ', 'Ꚉ'), + ('Ꚋ', 'Ꚋ'), + ('Ꚍ', 'Ꚍ'), + ('Ꚏ', 'Ꚏ'), + ('êš', 'êš'), + ('êš’', 'êš’'), + ('êš”', 'êš”'), + ('êš–', 'êš–'), + ('Ꚙ', 'Ꚙ'), + ('êšš', 'êšš'), + ('Ꜣ', 'Ꜣ'), + ('Ꜥ', 'Ꜥ'), + ('Ꜧ', 'Ꜧ'), + ('Ꜩ', 'Ꜩ'), + ('Ꜫ', 'Ꜫ'), + ('Ꜭ', 'Ꜭ'), + ('Ꜯ', 'Ꜯ'), + ('Ꜳ', 'Ꜳ'), + ('Ꜵ', 'Ꜵ'), + ('Ꜷ', 'Ꜷ'), + ('Ꜹ', 'Ꜹ'), + ('Ꜻ', 'Ꜻ'), + ('Ꜽ', 'Ꜽ'), + ('Ꜿ', 'Ꜿ'), + ('ê€', 'ê€'), + ('ê‚', 'ê‚'), + ('ê„', 'ê„'), + ('ê†', 'ê†'), + ('êˆ', 'êˆ'), + ('êŠ', 'êŠ'), + ('êŒ', 'êŒ'), + ('êŽ', 'êŽ'), + ('ê', 'ê'), + ('ê’', 'ê’'), + ('ê”', 'ê”'), + ('ê–', 'ê–'), + ('ê˜', 'ê˜'), + ('êš', 'êš'), + ('êœ', 'êœ'), + ('êž', 'êž'), + ('ê ', 'ê '), + ('ê¢', 'ê¢'), + ('ê¤', 'ê¤'), + ('ê¦', 'ê¦'), + ('ê¨', 'ê¨'), + ('êª', 'êª'), + ('ê¬', 'ê¬'), + ('ê®', 'ê®'), + ('ê¹', 'ê¹'), + ('ê»', 'ê»'), + ('ê½', 'ê¾'), + ('Ꞁ', 'Ꞁ'), + ('êž‚', 'êž‚'), + ('êž„', 'êž„'), + ('Ꞇ', 'Ꞇ'), + ('êž‹', 'êž‹'), + ('êž', 'êž'), + ('êž', 'êž'), + ('êž’', 'êž’'), + ('êž–', 'êž–'), + ('Ꞙ', 'Ꞙ'), + ('êžš', 'êžš'), + ('êžœ', 'êžœ'), + ('êžž', 'êžž'), + ('êž ', 'êž '), + ('Ꞣ', 'Ꞣ'), + ('Ꞥ', 'Ꞥ'), + ('Ꞧ', 'Ꞧ'), + ('Ꞩ', 'Ꞩ'), + ('Ɦ', 'êž®'), + ('êž°', 'êž´'), + ('Ꞷ', 'Ꞷ'), + ('Ꞹ', 'Ꞹ'), + ('Ꞻ', 'Ꞻ'), + ('êž¼', 'êž¼'), + ('êž¾', 'êž¾'), + ('Ꟁ', 'Ꟁ'), + ('Ꟃ', 'Ꟃ'), + ('Ꞔ', 'Ꟈ'), + ('Ꟊ', 'Ꟊ'), + ('êŸ', 'êŸ'), + ('Ꟗ', 'Ꟗ'), + ('Ꟙ', 'Ꟙ'), + ('Ꟶ', 'Ꟶ'), + ('A', 'Z'), + ('ð€', 'ð§'), + ('ð’°', 'ð““'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð²€', 'ð²²'), + ('ð‘¢ ', '𑢿'), + ('ð–¹€', '𖹟'), + ('ð€', 'ð™'), + ('ð´', 'ð‘'), + ('ð‘¨', 'ð’'), + ('ð’œ', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’µ'), + ('ð“', 'ð“©'), + ('ð”„', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”¸', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•¬', 'ð–…'), + ('ð– ', 'ð–¹'), + ('ð—”', 'ð—­'), + ('ð˜ˆ', 'ð˜¡'), + ('ð˜¼', 'ð™•'), + ('ð™°', 'ðš‰'), + ('ðš¨', 'ð›€'), + ('ð›¢', 'ð›º'), + ('ðœœ', 'ðœ´'), + ('ð–', 'ð®'), + ('ðž', 'ðž¨'), + ('ðŸŠ', 'ðŸŠ'), + ('𞤀', '𞤡'), + ('🄰', '🅉'), + ('ðŸ…', '🅩'), + ('🅰', '🆉'), +]; + +pub const VARIATION_SELECTOR: &'static [(char, char)] = &[ + ('\u{180b}', '\u{180d}'), + ('\u{180f}', '\u{180f}'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const WHITE_SPACE: &'static [(char, char)] = &[ + ('\t', '\r'), + (' ', ' '), + ('\u{85}', '\u{85}'), + ('\u{a0}', '\u{a0}'), + ('\u{1680}', '\u{1680}'), + ('\u{2000}', '\u{200a}'), + ('\u{2028}', '\u{2029}'), + ('\u{202f}', '\u{202f}'), + ('\u{205f}', '\u{205f}'), + ('\u{3000}', '\u{3000}'), +]; + +pub const XID_CONTINUE: &'static [(char, char)] = &[ + ('0', '9'), + ('A', 'Z'), + ('_', '_'), + ('a', 'z'), + ('ª', 'ª'), + ('µ', 'µ'), + ('·', '·'), + ('º', 'º'), + ('À', 'Ö'), + ('Ø', 'ö'), + ('ø', 'Ë'), + ('ˆ', 'Ë‘'), + ('Ë ', 'ˤ'), + ('ˬ', 'ˬ'), + ('Ë®', 'Ë®'), + ('\u{300}', 'Í´'), + ('Ͷ', 'Í·'), + ('Í»', 'ͽ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'ϵ'), + ('Ï·', 'Ò'), + ('\u{483}', '\u{487}'), + ('ÒŠ', 'Ô¯'), + ('Ô±', 'Õ–'), + ('Õ™', 'Õ™'), + ('Õ ', 'Öˆ'), + ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), + ('×', 'ת'), + ('ׯ', 'ײ'), + ('\u{610}', '\u{61a}'), + ('Ø ', 'Ù©'), + ('Ù®', 'Û“'), + ('Û•', '\u{6dc}'), + ('\u{6df}', '\u{6e8}'), + ('\u{6ea}', 'Û¼'), + ('Û¿', 'Û¿'), + ('Ü', '\u{74a}'), + ('Ý', 'Þ±'), + ('߀', 'ßµ'), + ('ߺ', 'ߺ'), + ('\u{7fd}', '\u{7fd}'), + ('à €', '\u{82d}'), + ('à¡€', '\u{85b}'), + ('à¡ ', 'ࡪ'), + ('à¡°', 'ࢇ'), + ('ࢉ', 'ࢎ'), + ('\u{898}', '\u{8e1}'), + ('\u{8e3}', '\u{963}'), + ('०', '९'), + ('ॱ', 'ঃ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('\u{9bc}', '\u{9c4}'), + ('ে', 'ৈ'), + ('ো', 'ৎ'), + ('\u{9d7}', '\u{9d7}'), + ('ড়', 'à§'), + ('য়', '\u{9e3}'), + ('০', 'ৱ'), + ('ৼ', 'ৼ'), + ('\u{9fe}', '\u{9fe}'), + ('\u{a01}', 'ਃ'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('\u{a3c}', '\u{a3c}'), + ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('੦', '\u{a75}'), + ('\u{a81}', 'ઃ'), + ('અ', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('\u{abc}', '\u{ac5}'), + ('\u{ac7}', 'ૉ'), + ('à«‹', '\u{acd}'), + ('à«', 'à«'), + ('à« ', '\u{ae3}'), + ('૦', '૯'), + ('ૹ', '\u{aff}'), + ('\u{b01}', 'ଃ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), + ('\u{b3c}', '\u{b44}'), + ('à­‡', 'à­ˆ'), + ('à­‹', '\u{b4d}'), + ('\u{b55}', '\u{b57}'), + ('à­œ', 'à­'), + ('à­Ÿ', '\u{b63}'), + ('à­¦', 'à­¯'), + ('à­±', 'à­±'), + ('\u{b82}', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'ஹ'), + ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), + ('ொ', '\u{bcd}'), + ('à¯', 'à¯'), + ('\u{bd7}', '\u{bd7}'), + ('௦', '௯'), + ('\u{c00}', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°¹'), + ('\u{c3c}', 'ౄ'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('ౘ', 'ౚ'), + ('à±', 'à±'), + ('à± ', '\u{c63}'), + ('౦', '౯'), + ('ಀ', 'ಃ'), + ('ಅ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('\u{cbc}', 'ೄ'), + ('\u{cc6}', 'ೈ'), + ('ೊ', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), + ('à³', 'ೞ'), + ('à³ ', '\u{ce3}'), + ('೦', '೯'), + ('à³±', 'à³³'), + ('\u{d00}', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', '\u{d44}'), + ('െ', 'ൈ'), + ('ൊ', 'ൎ'), + ('ൔ', '\u{d57}'), + ('ൟ', '\u{d63}'), + ('൦', '൯'), + ('ൺ', 'ൿ'), + ('\u{d81}', 'ඃ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('à·˜', '\u{ddf}'), + ('à·¦', 'à·¯'), + ('à·²', 'à·³'), + ('à¸', '\u{e3a}'), + ('เ', '\u{e4e}'), + ('à¹', '๙'), + ('àº', 'ຂ'), + ('ຄ', 'ຄ'), + ('ຆ', 'ຊ'), + ('ຌ', 'ຣ'), + ('ລ', 'ລ'), + ('ວ', 'ຽ'), + ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), + ('\u{ec8}', '\u{ece}'), + ('à»', 'à»™'), + ('ໜ', 'ໟ'), + ('ༀ', 'ༀ'), + ('\u{f18}', '\u{f19}'), + ('༠', '༩'), + ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), + ('\u{f39}', '\u{f39}'), + ('༾', 'ཇ'), + ('ཉ', 'ཬ'), + ('\u{f71}', '\u{f84}'), + ('\u{f86}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('\u{fc6}', '\u{fc6}'), + ('က', 'á‰'), + ('á', '\u{109d}'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ჺ'), + ('ჼ', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹–'), + ('ዘ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'áš'), + ('\u{135d}', '\u{135f}'), + ('á©', 'á±'), + ('ᎀ', 'áŽ'), + ('Ꭰ', 'áµ'), + ('á¸', 'á½'), + ('á', 'ᙬ'), + ('ᙯ', 'ᙿ'), + ('áš', 'ášš'), + ('áš ', 'ᛪ'), + ('á›®', 'ᛸ'), + ('ᜀ', '᜕'), + ('ᜟ', '᜴'), + ('á€', '\u{1753}'), + ('á ', 'á¬'), + ('á®', 'á°'), + ('\u{1772}', '\u{1773}'), + ('ក', '\u{17d3}'), + ('ៗ', 'ៗ'), + ('ៜ', '\u{17dd}'), + ('០', '៩'), + ('\u{180b}', '\u{180d}'), + ('\u{180f}', 'á ™'), + ('á  ', 'ᡸ'), + ('ᢀ', 'ᢪ'), + ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), + ('\u{1920}', 'ᤫ'), + ('ᤰ', '\u{193b}'), + ('᥆', 'ᥭ'), + ('ᥰ', 'ᥴ'), + ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), + ('á§', '᧚'), + ('ᨀ', '\u{1a1b}'), + ('ᨠ', '\u{1a5e}'), + ('\u{1a60}', '\u{1a7c}'), + ('\u{1a7f}', '᪉'), + ('áª', '᪙'), + ('ᪧ', 'ᪧ'), + ('\u{1ab0}', '\u{1abd}'), + ('\u{1abf}', '\u{1ace}'), + ('\u{1b00}', 'á­Œ'), + ('á­', 'á­™'), + ('\u{1b6b}', '\u{1b73}'), + ('\u{1b80}', '᯳'), + ('á°€', '\u{1c37}'), + ('á±€', '᱉'), + ('á±', 'á±½'), + ('á²€', 'ᲈ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', 'ᳺ'), + ('á´€', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¾¼'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'á¿Œ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), + ('ῶ', 'ῼ'), + ('‿', 'â€'), + ('â”', 'â”'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('\u{20d0}', '\u{20dc}'), + ('\u{20e1}', '\u{20e1}'), + ('\u{20e5}', '\u{20f0}'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„Š', 'â„“'), + ('â„•', 'â„•'), + ('℘', 'â„'), + ('ℤ', 'ℤ'), + ('Ω', 'Ω'), + ('ℨ', 'ℨ'), + ('K', 'ℹ'), + ('ℼ', 'â„¿'), + ('â……', 'â…‰'), + ('â…Ž', 'â…Ž'), + ('â… ', 'ↈ'), + ('â°€', 'ⳤ'), + ('Ⳬ', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('â´°', 'ⵧ'), + ('ⵯ', 'ⵯ'), + ('\u{2d7f}', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('\u{2de0}', '\u{2dff}'), + ('々', '〇'), + ('〡', '\u{302f}'), + ('〱', '〵'), + ('〸', '〼'), + ('ã', 'ã‚–'), + ('\u{3099}', '\u{309a}'), + ('ã‚', 'ã‚Ÿ'), + ('ã‚¡', 'ヺ'), + ('ー', 'ヿ'), + ('ã„…', 'ㄯ'), + ('ㄱ', 'ㆎ'), + ('ㆠ', 'ㆿ'), + ('ㇰ', 'ㇿ'), + ('ã€', '䶿'), + ('一', 'ê’Œ'), + ('ê“', 'ꓽ'), + ('ꔀ', 'ꘌ'), + ('ê˜', 'ꘫ'), + ('Ꙁ', '\u{a66f}'), + ('\u{a674}', '\u{a67d}'), + ('ꙿ', '\u{a6f1}'), + ('ꜗ', 'ꜟ'), + ('Ꜣ', 'ꞈ'), + ('êž‹', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('ꟲ', 'ê §'), + ('\u{a82c}', '\u{a82c}'), + ('ê¡€', 'ꡳ'), + ('ꢀ', '\u{a8c5}'), + ('ê£', '꣙'), + ('\u{a8e0}', 'ꣷ'), + ('ꣻ', 'ꣻ'), + ('ꣽ', '\u{a92d}'), + ('ꤰ', '꥓'), + ('ꥠ', 'ꥼ'), + ('\u{a980}', '꧀'), + ('ê§', '꧙'), + ('ꧠ', 'ꧾ'), + ('ꨀ', '\u{aa36}'), + ('ê©€', 'ê©'), + ('ê©', 'ê©™'), + ('ê© ', 'ꩶ'), + ('ꩺ', 'ê«‚'), + ('ê«›', 'ê«'), + ('ê« ', 'ꫯ'), + ('ꫲ', '\u{aaf6}'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('ꬰ', 'ê­š'), + ('ê­œ', 'ê­©'), + ('ê­°', 'ꯪ'), + ('꯬', '\u{abed}'), + ('꯰', '꯹'), + ('ê°€', '힣'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), + ('ï©°', 'ï«™'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï¬', 'ﬨ'), + ('שׁ', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', 'ï®±'), + ('ﯓ', 'ï±'), + ('ﱤ', 'ï´½'), + ('ïµ', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·°', 'ï·¹'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{fe20}', '\u{fe2f}'), + ('︳', '︴'), + ('ï¹', 'ï¹'), + ('ï¹±', 'ï¹±'), + ('ï¹³', 'ï¹³'), + ('ï¹·', 'ï¹·'), + ('ï¹¹', 'ï¹¹'), + ('ï¹»', 'ï¹»'), + ('ï¹½', 'ï¹½'), + ('ﹿ', 'ﻼ'), + ('ï¼', 'ï¼™'), + ('A', 'Z'), + ('_', '_'), + ('ï½', 'z'), + ('ヲ', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), + ('ð…€', 'ð…´'), + ('\u{101fd}', '\u{101fd}'), + ('ðŠ€', 'ðŠœ'), + ('ðŠ ', 'ð‹'), + ('\u{102e0}', '\u{102e0}'), + ('ðŒ€', 'ðŒŸ'), + ('ðŒ­', 'ðŠ'), + ('ð', '\u{1037a}'), + ('ðŽ€', 'ðŽ'), + ('ðŽ ', 'ðƒ'), + ('ðˆ', 'ð'), + ('ð‘', 'ð•'), + ('ð€', 'ð’'), + ('ð’ ', 'ð’©'), + ('ð’°', 'ð““'), + ('ð“˜', 'ð“»'), + ('ð”€', 'ð”§'), + ('ð”°', 'ð•£'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð˜€', 'ðœ¶'), + ('ð€', 'ð•'), + ('ð ', 'ð§'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð €', 'ð …'), + ('ð ˆ', 'ð ˆ'), + ('ð Š', 'ð µ'), + ('ð ·', 'ð ¸'), + ('ð ¼', 'ð ¼'), + ('ð ¿', 'ð¡•'), + ('ð¡ ', 'ð¡¶'), + ('ð¢€', 'ð¢ž'), + ('ð£ ', 'ð£²'), + ('ð£´', 'ð£µ'), + ('ð¤€', 'ð¤•'), + ('ð¤ ', 'ð¤¹'), + ('ð¦€', 'ð¦·'), + ('ð¦¾', 'ð¦¿'), + ('ð¨€', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨µ'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), + ('ð© ', 'ð©¼'), + ('ðª€', 'ðªœ'), + ('ð«€', 'ð«‡'), + ('ð«‰', '\u{10ae6}'), + ('ð¬€', 'ð¬µ'), + ('ð­€', 'ð­•'), + ('ð­ ', 'ð­²'), + ('ð®€', 'ð®‘'), + ('ð°€', 'ð±ˆ'), + ('ð²€', 'ð²²'), + ('ð³€', 'ð³²'), + ('ð´€', '\u{10d27}'), + ('ð´°', 'ð´¹'), + ('ðº€', 'ðº©'), + ('\u{10eab}', '\u{10eac}'), + ('ðº°', 'ðº±'), + ('\u{10efd}', 'ð¼œ'), + ('ð¼§', 'ð¼§'), + ('ð¼°', '\u{10f50}'), + ('ð½°', '\u{10f85}'), + ('ð¾°', 'ð¿„'), + ('ð¿ ', 'ð¿¶'), + ('ð‘€€', '\u{11046}'), + ('ð‘¦', 'ð‘µ'), + ('\u{1107f}', '\u{110ba}'), + ('\u{110c2}', '\u{110c2}'), + ('ð‘ƒ', '𑃨'), + ('𑃰', '𑃹'), + ('\u{11100}', '\u{11134}'), + ('𑄶', 'ð‘„¿'), + ('ð‘…„', 'ð‘…‡'), + ('ð‘…', '\u{11173}'), + ('ð‘…¶', 'ð‘…¶'), + ('\u{11180}', '𑇄'), + ('\u{111c9}', '\u{111cc}'), + ('𑇎', '𑇚'), + ('𑇜', '𑇜'), + ('𑈀', '𑈑'), + ('𑈓', '\u{11237}'), + ('\u{1123e}', '\u{11241}'), + ('ð‘Š€', '𑊆'), + ('𑊈', '𑊈'), + ('ð‘ŠŠ', 'ð‘Š'), + ('ð‘Š', 'ð‘Š'), + ('ð‘ŠŸ', '𑊨'), + ('ð‘Š°', '\u{112ea}'), + ('ð‘‹°', 'ð‘‹¹'), + ('\u{11300}', '𑌃'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('\u{1133b}', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘'), + ('ð‘', 'ð‘'), + ('\u{11357}', '\u{11357}'), + ('ð‘', 'ð‘£'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('ð‘€', 'ð‘‘Š'), + ('ð‘‘', 'ð‘‘™'), + ('\u{1145e}', 'ð‘‘¡'), + ('ð‘’€', 'ð‘“…'), + ('𑓇', '𑓇'), + ('ð‘“', 'ð‘“™'), + ('ð‘–€', '\u{115b5}'), + ('ð‘–¸', '\u{115c0}'), + ('ð‘—˜', '\u{115dd}'), + ('𑘀', '\u{11640}'), + ('ð‘™„', 'ð‘™„'), + ('ð‘™', 'ð‘™™'), + ('𑚀', '𑚸'), + ('𑛀', '𑛉'), + ('𑜀', '𑜚'), + ('\u{1171d}', '\u{1172b}'), + ('𑜰', '𑜹'), + ('ð‘€', 'ð‘†'), + ('ð‘ €', '\u{1183a}'), + ('ð‘¢ ', '𑣩'), + ('𑣿', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤵'), + ('𑤷', '𑤸'), + ('\u{1193b}', '\u{11943}'), + ('ð‘¥', 'ð‘¥™'), + ('𑦠', '𑦧'), + ('𑦪', '\u{119d7}'), + ('\u{119da}', '𑧡'), + ('𑧣', '𑧤'), + ('𑨀', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), + ('ð‘©', '\u{11a99}'), + ('ð‘ª', 'ð‘ª'), + ('𑪰', '𑫸'), + ('ð‘°€', 'ð‘°ˆ'), + ('ð‘°Š', '\u{11c36}'), + ('\u{11c38}', '𑱀'), + ('ð‘±', '𑱙'), + ('𑱲', 'ð‘²'), + ('\u{11c92}', '\u{11ca7}'), + ('𑲩', '\u{11cb6}'), + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d47}'), + ('ð‘µ', '𑵙'), + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶎'), + ('\u{11d90}', '\u{11d91}'), + ('𑶓', '𑶘'), + ('𑶠', '𑶩'), + ('ð‘» ', '𑻶'), + ('\u{11f00}', 'ð‘¼'), + ('𑼒', '\u{11f3a}'), + ('𑼾', '\u{11f42}'), + ('ð‘½', '𑽙'), + ('𑾰', '𑾰'), + ('ð’€€', 'ð’Ž™'), + ('ð’€', 'ð’‘®'), + ('ð’’€', '𒕃'), + ('ð’¾', 'ð’¿°'), + ('ð“€€', 'ð“¯'), + ('\u{13440}', '\u{13455}'), + ('ð”€', '𔙆'), + ('ð– €', '𖨸'), + ('ð–©€', 'ð–©ž'), + ('ð–© ', 'ð–©©'), + ('ð–©°', '𖪾'), + ('ð–«€', '𖫉'), + ('ð–«', 'ð–«­'), + ('\u{16af0}', '\u{16af4}'), + ('𖬀', '\u{16b36}'), + ('ð–­€', 'ð–­ƒ'), + ('ð–­', 'ð–­™'), + ('ð–­£', 'ð–­·'), + ('ð–­½', 'ð–®'), + ('ð–¹€', '𖹿'), + ('ð–¼€', '𖽊'), + ('\u{16f4f}', '𖾇'), + ('\u{16f8f}', '𖾟'), + ('ð–¿ ', 'ð–¿¡'), + ('ð–¿£', '\u{16fe4}'), + ('ð–¿°', 'ð–¿±'), + ('ð—€€', '𘟷'), + ('𘠀', '𘳕'), + ('𘴀', '𘴈'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𛀀', '𛄢'), + ('𛄲', '𛄲'), + ('ð›…', 'ð›…’'), + ('ð›…•', 'ð›…•'), + ('ð›…¤', 'ð›…§'), + ('ð›…°', '𛋻'), + ('ð›°€', '𛱪'), + ('ð›±°', 'ð›±¼'), + ('𛲀', '𛲈'), + ('ð›²', '𛲙'), + ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('\u{1d165}', '\u{1d169}'), + ('ð…­', '\u{1d172}'), + ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ð›€'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›º'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ´'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð®'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž¨'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‹'), + ('ðŸŽ', 'ðŸ¿'), + ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), + ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), + ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), + ('ð¼€', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('𞀰', 'ðž­'), + ('\u{1e08f}', '\u{1e08f}'), + ('ðž„€', '𞄬'), + ('\u{1e130}', '𞄽'), + ('ðž…€', 'ðž…‰'), + ('ðž…Ž', 'ðž…Ž'), + ('ðžŠ', '\u{1e2ae}'), + ('ðž‹€', '𞋹'), + ('ðž“', '𞓹'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), + ('ðž €', '𞣄'), + ('\u{1e8d0}', '\u{1e8d6}'), + ('𞤀', '𞥋'), + ('ðž¥', '𞥙'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('🯰', '🯹'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('丽', 'ð¯¨'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const XID_START: &'static [(char, char)] = &[ + ('A', 'Z'), + ('a', 'z'), + ('ª', 'ª'), + ('µ', 'µ'), + ('º', 'º'), + ('À', 'Ö'), + ('Ø', 'ö'), + ('ø', 'Ë'), + ('ˆ', 'Ë‘'), + ('Ë ', 'ˤ'), + ('ˬ', 'ˬ'), + ('Ë®', 'Ë®'), + ('Í°', 'Í´'), + ('Ͷ', 'Í·'), + ('Í»', 'ͽ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'ϵ'), + ('Ï·', 'Ò'), + ('ÒŠ', 'Ô¯'), + ('Ô±', 'Õ–'), + ('Õ™', 'Õ™'), + ('Õ ', 'Öˆ'), + ('×', 'ת'), + ('ׯ', 'ײ'), + ('Ø ', 'ÙŠ'), + ('Ù®', 'Ù¯'), + ('Ù±', 'Û“'), + ('Û•', 'Û•'), + ('Û¥', 'Û¦'), + ('Û®', 'Û¯'), + ('Ûº', 'Û¼'), + ('Û¿', 'Û¿'), + ('Ü', 'Ü'), + ('Ü’', 'ܯ'), + ('Ý', 'Þ¥'), + ('Þ±', 'Þ±'), + ('ߊ', 'ߪ'), + ('ß´', 'ßµ'), + ('ߺ', 'ߺ'), + ('à €', 'à •'), + ('à š', 'à š'), + ('à ¤', 'à ¤'), + ('à ¨', 'à ¨'), + ('à¡€', 'ࡘ'), + ('à¡ ', 'ࡪ'), + ('à¡°', 'ࢇ'), + ('ࢉ', 'ࢎ'), + ('ࢠ', 'ࣉ'), + ('ऄ', 'ह'), + ('ऽ', 'ऽ'), + ('à¥', 'à¥'), + ('क़', 'ॡ'), + ('ॱ', 'ঀ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('ঽ', 'ঽ'), + ('ৎ', 'ৎ'), + ('ড়', 'à§'), + ('য়', 'ৡ'), + ('ৰ', 'ৱ'), + ('ৼ', 'ৼ'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('ੲ', 'à©´'), + ('અ', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('ઽ', 'ઽ'), + ('à«', 'à«'), + ('à« ', 'à«¡'), + ('ૹ', 'ૹ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), + ('ଽ', 'ଽ'), + ('à­œ', 'à­'), + ('à­Ÿ', 'à­¡'), + ('à­±', 'à­±'), + ('ஃ', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'ஹ'), + ('à¯', 'à¯'), + ('à°…', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°¹'), + ('à°½', 'à°½'), + ('ౘ', 'ౚ'), + ('à±', 'à±'), + ('à± ', 'ౡ'), + ('ಀ', 'ಀ'), + ('ಅ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('ಽ', 'ಽ'), + ('à³', 'ೞ'), + ('à³ ', 'ೡ'), + ('à³±', 'à³²'), + ('à´„', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', 'à´º'), + ('à´½', 'à´½'), + ('ൎ', 'ൎ'), + ('ൔ', 'ൖ'), + ('ൟ', 'ൡ'), + ('ൺ', 'ൿ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('à¸', 'ะ'), + ('า', 'า'), + ('เ', 'ๆ'), + ('àº', 'ຂ'), + ('ຄ', 'ຄ'), + ('ຆ', 'ຊ'), + ('ຌ', 'ຣ'), + ('ລ', 'ລ'), + ('ວ', 'ະ'), + ('າ', 'າ'), + ('ຽ', 'ຽ'), + ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), + ('ໜ', 'ໟ'), + ('ༀ', 'ༀ'), + ('ཀ', 'ཇ'), + ('ཉ', 'ཬ'), + ('ྈ', 'ྌ'), + ('က', 'ဪ'), + ('ဿ', 'ဿ'), + ('á', 'á•'), + ('áš', 'á'), + ('á¡', 'á¡'), + ('á¥', 'á¦'), + ('á®', 'á°'), + ('áµ', 'á‚'), + ('á‚Ž', 'á‚Ž'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ჺ'), + ('ჼ', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹–'), + ('ዘ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'áš'), + ('ᎀ', 'áŽ'), + ('Ꭰ', 'áµ'), + ('á¸', 'á½'), + ('á', 'ᙬ'), + ('ᙯ', 'ᙿ'), + ('áš', 'ášš'), + ('áš ', 'ᛪ'), + ('á›®', 'ᛸ'), + ('ᜀ', 'ᜑ'), + ('ᜟ', 'ᜱ'), + ('á€', 'á‘'), + ('á ', 'á¬'), + ('á®', 'á°'), + ('ក', 'áž³'), + ('ៗ', 'ៗ'), + ('ៜ', 'ៜ'), + ('á  ', 'ᡸ'), + ('ᢀ', 'ᢨ'), + ('ᢪ', 'ᢪ'), + ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), + ('á¥', 'ᥭ'), + ('ᥰ', 'ᥴ'), + ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), + ('ᨀ', 'ᨖ'), + ('ᨠ', 'á©”'), + ('ᪧ', 'ᪧ'), + ('ᬅ', 'ᬳ'), + ('á­…', 'á­Œ'), + ('ᮃ', 'á® '), + ('á®®', 'ᮯ'), + ('ᮺ', 'ᯥ'), + ('á°€', 'á°£'), + ('á±', 'á±'), + ('ᱚ', 'á±½'), + ('á²€', 'ᲈ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('ᳩ', 'ᳬ'), + ('á³®', 'á³³'), + ('á³µ', 'ᳶ'), + ('ᳺ', 'ᳺ'), + ('á´€', 'ᶿ'), + ('Ḁ', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¾¼'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'á¿Œ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), + ('ῶ', 'ῼ'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„Š', 'â„“'), + ('â„•', 'â„•'), + ('℘', 'â„'), + ('ℤ', 'ℤ'), + ('Ω', 'Ω'), + ('ℨ', 'ℨ'), + ('K', 'ℹ'), + ('ℼ', 'â„¿'), + ('â……', 'â…‰'), + ('â…Ž', 'â…Ž'), + ('â… ', 'ↈ'), + ('â°€', 'ⳤ'), + ('Ⳬ', 'â³®'), + ('â³²', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('â´°', 'ⵧ'), + ('ⵯ', 'ⵯ'), + ('ⶀ', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('々', '〇'), + ('〡', '〩'), + ('〱', '〵'), + ('〸', '〼'), + ('ã', 'ã‚–'), + ('ã‚', 'ã‚Ÿ'), + ('ã‚¡', 'ヺ'), + ('ー', 'ヿ'), + ('ã„…', 'ㄯ'), + ('ㄱ', 'ㆎ'), + ('ㆠ', 'ㆿ'), + ('ㇰ', 'ㇿ'), + ('ã€', '䶿'), + ('一', 'ê’Œ'), + ('ê“', 'ꓽ'), + ('ꔀ', 'ꘌ'), + ('ê˜', 'ꘟ'), + ('ꘪ', 'ꘫ'), + ('Ꙁ', 'ê™®'), + ('ꙿ', 'êš'), + ('êš ', 'ꛯ'), + ('ꜗ', 'ꜟ'), + ('Ꜣ', 'ꞈ'), + ('êž‹', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('ꟲ', 'ê '), + ('ê ƒ', 'ê …'), + ('ê ‡', 'ê Š'), + ('ê Œ', 'ê ¢'), + ('ê¡€', 'ꡳ'), + ('ꢂ', 'ꢳ'), + ('ꣲ', 'ꣷ'), + ('ꣻ', 'ꣻ'), + ('ꣽ', 'ꣾ'), + ('ꤊ', 'ꤥ'), + ('ꤰ', 'ꥆ'), + ('ꥠ', 'ꥼ'), + ('ꦄ', 'ꦲ'), + ('ê§', 'ê§'), + ('ꧠ', 'ꧤ'), + ('ꧦ', 'ꧯ'), + ('ꧺ', 'ꧾ'), + ('ꨀ', 'ꨨ'), + ('ê©€', 'ê©‚'), + ('ê©„', 'ê©‹'), + ('ê© ', 'ꩶ'), + ('ꩺ', 'ꩺ'), + ('ꩾ', 'ꪯ'), + ('ꪱ', 'ꪱ'), + ('ꪵ', 'ꪶ'), + ('ꪹ', 'ꪽ'), + ('ê«€', 'ê«€'), + ('ê«‚', 'ê«‚'), + ('ê«›', 'ê«'), + ('ê« ', 'ꫪ'), + ('ꫲ', 'ê«´'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('ꬰ', 'ê­š'), + ('ê­œ', 'ê­©'), + ('ê­°', 'ꯢ'), + ('ê°€', '힣'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), + ('ï©°', 'ï«™'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï¬', 'ï¬'), + ('ײַ', 'ﬨ'), + ('שׁ', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', 'ï®±'), + ('ﯓ', 'ï±'), + ('ﱤ', 'ï´½'), + ('ïµ', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·°', 'ï·¹'), + ('ï¹±', 'ï¹±'), + ('ï¹³', 'ï¹³'), + ('ï¹·', 'ï¹·'), + ('ï¹¹', 'ï¹¹'), + ('ï¹»', 'ï¹»'), + ('ï¹½', 'ï¹½'), + ('ﹿ', 'ﻼ'), + ('A', 'Z'), + ('ï½', 'z'), + ('ヲ', 'ï¾'), + ('ï¾ ', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), + ('ð…€', 'ð…´'), + ('ðŠ€', 'ðŠœ'), + ('ðŠ ', 'ð‹'), + ('ðŒ€', 'ðŒŸ'), + ('ðŒ­', 'ðŠ'), + ('ð', 'ðµ'), + ('ðŽ€', 'ðŽ'), + ('ðŽ ', 'ðƒ'), + ('ðˆ', 'ð'), + ('ð‘', 'ð•'), + ('ð€', 'ð’'), + ('ð’°', 'ð““'), + ('ð“˜', 'ð“»'), + ('ð”€', 'ð”§'), + ('ð”°', 'ð•£'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð˜€', 'ðœ¶'), + ('ð€', 'ð•'), + ('ð ', 'ð§'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð €', 'ð …'), + ('ð ˆ', 'ð ˆ'), + ('ð Š', 'ð µ'), + ('ð ·', 'ð ¸'), + ('ð ¼', 'ð ¼'), + ('ð ¿', 'ð¡•'), + ('ð¡ ', 'ð¡¶'), + ('ð¢€', 'ð¢ž'), + ('ð£ ', 'ð£²'), + ('ð£´', 'ð£µ'), + ('ð¤€', 'ð¤•'), + ('ð¤ ', 'ð¤¹'), + ('ð¦€', 'ð¦·'), + ('ð¦¾', 'ð¦¿'), + ('ð¨€', 'ð¨€'), + ('ð¨', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨µ'), + ('ð© ', 'ð©¼'), + ('ðª€', 'ðªœ'), + ('ð«€', 'ð«‡'), + ('ð«‰', 'ð«¤'), + ('ð¬€', 'ð¬µ'), + ('ð­€', 'ð­•'), + ('ð­ ', 'ð­²'), + ('ð®€', 'ð®‘'), + ('ð°€', 'ð±ˆ'), + ('ð²€', 'ð²²'), + ('ð³€', 'ð³²'), + ('ð´€', 'ð´£'), + ('ðº€', 'ðº©'), + ('ðº°', 'ðº±'), + ('ð¼€', 'ð¼œ'), + ('ð¼§', 'ð¼§'), + ('ð¼°', 'ð½…'), + ('ð½°', 'ð¾'), + ('ð¾°', 'ð¿„'), + ('ð¿ ', 'ð¿¶'), + ('𑀃', 'ð‘€·'), + ('ð‘±', 'ð‘²'), + ('ð‘µ', 'ð‘µ'), + ('𑂃', '𑂯'), + ('ð‘ƒ', '𑃨'), + ('𑄃', '𑄦'), + ('ð‘…„', 'ð‘…„'), + ('ð‘…‡', 'ð‘…‡'), + ('ð‘…', 'ð‘…²'), + ('ð‘…¶', 'ð‘…¶'), + ('𑆃', '𑆲'), + ('ð‘‡', '𑇄'), + ('𑇚', '𑇚'), + ('𑇜', '𑇜'), + ('𑈀', '𑈑'), + ('𑈓', '𑈫'), + ('𑈿', '𑉀'), + ('ð‘Š€', '𑊆'), + ('𑊈', '𑊈'), + ('ð‘ŠŠ', 'ð‘Š'), + ('ð‘Š', 'ð‘Š'), + ('ð‘ŠŸ', '𑊨'), + ('ð‘Š°', 'ð‘‹ž'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('𑌽', '𑌽'), + ('ð‘', 'ð‘'), + ('ð‘', 'ð‘¡'), + ('ð‘€', 'ð‘´'), + ('𑑇', 'ð‘‘Š'), + ('ð‘‘Ÿ', 'ð‘‘¡'), + ('ð‘’€', 'ð‘’¯'), + ('ð‘“„', 'ð‘“…'), + ('𑓇', '𑓇'), + ('ð‘–€', 'ð‘–®'), + ('ð‘—˜', 'ð‘—›'), + ('𑘀', '𑘯'), + ('ð‘™„', 'ð‘™„'), + ('𑚀', '𑚪'), + ('𑚸', '𑚸'), + ('𑜀', '𑜚'), + ('ð‘€', 'ð‘†'), + ('ð‘ €', 'ð‘ «'), + ('ð‘¢ ', '𑣟'), + ('𑣿', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤯'), + ('𑤿', '𑤿'), + ('ð‘¥', 'ð‘¥'), + ('𑦠', '𑦧'), + ('𑦪', 'ð‘§'), + ('𑧡', '𑧡'), + ('𑧣', '𑧣'), + ('𑨀', '𑨀'), + ('𑨋', '𑨲'), + ('𑨺', '𑨺'), + ('ð‘©', 'ð‘©'), + ('ð‘©œ', '𑪉'), + ('ð‘ª', 'ð‘ª'), + ('𑪰', '𑫸'), + ('ð‘°€', 'ð‘°ˆ'), + ('ð‘°Š', 'ð‘°®'), + ('𑱀', '𑱀'), + ('𑱲', 'ð‘²'), + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', 'ð‘´°'), + ('𑵆', '𑵆'), + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶉'), + ('𑶘', '𑶘'), + ('ð‘» ', 'ð‘»²'), + ('𑼂', '𑼂'), + ('𑼄', 'ð‘¼'), + ('𑼒', '𑼳'), + ('𑾰', '𑾰'), + ('ð’€€', 'ð’Ž™'), + ('ð’€', 'ð’‘®'), + ('ð’’€', '𒕃'), + ('ð’¾', 'ð’¿°'), + ('ð“€€', 'ð“¯'), + ('ð“‘', '𓑆'), + ('ð”€', '𔙆'), + ('ð– €', '𖨸'), + ('ð–©€', 'ð–©ž'), + ('ð–©°', '𖪾'), + ('ð–«', 'ð–«­'), + ('𖬀', '𖬯'), + ('ð–­€', 'ð–­ƒ'), + ('ð–­£', 'ð–­·'), + ('ð–­½', 'ð–®'), + ('ð–¹€', '𖹿'), + ('ð–¼€', '𖽊'), + ('ð–½', 'ð–½'), + ('𖾓', '𖾟'), + ('ð–¿ ', 'ð–¿¡'), + ('ð–¿£', 'ð–¿£'), + ('ð—€€', '𘟷'), + ('𘠀', '𘳕'), + ('𘴀', '𘴈'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𛀀', '𛄢'), + ('𛄲', '𛄲'), + ('ð›…', 'ð›…’'), + ('ð›…•', 'ð›…•'), + ('ð›…¤', 'ð›…§'), + ('ð›…°', '𛋻'), + ('ð›°€', '𛱪'), + ('ð›±°', 'ð›±¼'), + ('𛲀', '𛲈'), + ('ð›²', '𛲙'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ð›€'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›º'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ´'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð®'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž¨'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‹'), + ('ð¼€', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('𞀰', 'ðž­'), + ('ðž„€', '𞄬'), + ('ðž„·', '𞄽'), + ('ðž…Ž', 'ðž…Ž'), + ('ðžŠ', '𞊭'), + ('ðž‹€', 'ðž‹«'), + ('ðž“', 'ðž“«'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), + ('ðž €', '𞣄'), + ('𞤀', '𞥃'), + ('𞥋', '𞥋'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('丽', 'ð¯¨'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), +]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/property_names.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/property_names.rs new file mode 100644 index 0000000000000..599a123ae58a4 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/property_names.rs @@ -0,0 +1,264 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate property-names ucd-15.0.0 +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const PROPERTY_NAMES: &'static [(&'static str, &'static str)] = &[ + ("age", "Age"), + ("ahex", "ASCII_Hex_Digit"), + ("alpha", "Alphabetic"), + ("alphabetic", "Alphabetic"), + ("asciihexdigit", "ASCII_Hex_Digit"), + ("bc", "Bidi_Class"), + ("bidic", "Bidi_Control"), + ("bidiclass", "Bidi_Class"), + ("bidicontrol", "Bidi_Control"), + ("bidim", "Bidi_Mirrored"), + ("bidimirrored", "Bidi_Mirrored"), + ("bidimirroringglyph", "Bidi_Mirroring_Glyph"), + ("bidipairedbracket", "Bidi_Paired_Bracket"), + ("bidipairedbrackettype", "Bidi_Paired_Bracket_Type"), + ("blk", "Block"), + ("block", "Block"), + ("bmg", "Bidi_Mirroring_Glyph"), + ("bpb", "Bidi_Paired_Bracket"), + ("bpt", "Bidi_Paired_Bracket_Type"), + ("canonicalcombiningclass", "Canonical_Combining_Class"), + ("cased", "Cased"), + ("casefolding", "Case_Folding"), + ("caseignorable", "Case_Ignorable"), + ("ccc", "Canonical_Combining_Class"), + ("ce", "Composition_Exclusion"), + ("cf", "Case_Folding"), + ("changeswhencasefolded", "Changes_When_Casefolded"), + ("changeswhencasemapped", "Changes_When_Casemapped"), + ("changeswhenlowercased", "Changes_When_Lowercased"), + ("changeswhennfkccasefolded", "Changes_When_NFKC_Casefolded"), + ("changeswhentitlecased", "Changes_When_Titlecased"), + ("changeswhenuppercased", "Changes_When_Uppercased"), + ("ci", "Case_Ignorable"), + ("cjkaccountingnumeric", "kAccountingNumeric"), + ("cjkcompatibilityvariant", "kCompatibilityVariant"), + ("cjkiicore", "kIICore"), + ("cjkirggsource", "kIRG_GSource"), + ("cjkirghsource", "kIRG_HSource"), + ("cjkirgjsource", "kIRG_JSource"), + ("cjkirgkpsource", "kIRG_KPSource"), + ("cjkirgksource", "kIRG_KSource"), + ("cjkirgmsource", "kIRG_MSource"), + ("cjkirgssource", "kIRG_SSource"), + ("cjkirgtsource", "kIRG_TSource"), + ("cjkirguksource", "kIRG_UKSource"), + ("cjkirgusource", "kIRG_USource"), + ("cjkirgvsource", "kIRG_VSource"), + ("cjkothernumeric", "kOtherNumeric"), + ("cjkprimarynumeric", "kPrimaryNumeric"), + ("cjkrsunicode", "kRSUnicode"), + ("compex", "Full_Composition_Exclusion"), + ("compositionexclusion", "Composition_Exclusion"), + ("cwcf", "Changes_When_Casefolded"), + ("cwcm", "Changes_When_Casemapped"), + ("cwkcf", "Changes_When_NFKC_Casefolded"), + ("cwl", "Changes_When_Lowercased"), + ("cwt", "Changes_When_Titlecased"), + ("cwu", "Changes_When_Uppercased"), + ("dash", "Dash"), + ("decompositionmapping", "Decomposition_Mapping"), + ("decompositiontype", "Decomposition_Type"), + ("defaultignorablecodepoint", "Default_Ignorable_Code_Point"), + ("dep", "Deprecated"), + ("deprecated", "Deprecated"), + ("di", "Default_Ignorable_Code_Point"), + ("dia", "Diacritic"), + ("diacritic", "Diacritic"), + ("dm", "Decomposition_Mapping"), + ("dt", "Decomposition_Type"), + ("ea", "East_Asian_Width"), + ("eastasianwidth", "East_Asian_Width"), + ("ebase", "Emoji_Modifier_Base"), + ("ecomp", "Emoji_Component"), + ("emod", "Emoji_Modifier"), + ("emoji", "Emoji"), + ("emojicomponent", "Emoji_Component"), + ("emojimodifier", "Emoji_Modifier"), + ("emojimodifierbase", "Emoji_Modifier_Base"), + ("emojipresentation", "Emoji_Presentation"), + ("epres", "Emoji_Presentation"), + ("equideo", "Equivalent_Unified_Ideograph"), + ("equivalentunifiedideograph", "Equivalent_Unified_Ideograph"), + ("expandsonnfc", "Expands_On_NFC"), + ("expandsonnfd", "Expands_On_NFD"), + ("expandsonnfkc", "Expands_On_NFKC"), + ("expandsonnfkd", "Expands_On_NFKD"), + ("ext", "Extender"), + ("extendedpictographic", "Extended_Pictographic"), + ("extender", "Extender"), + ("extpict", "Extended_Pictographic"), + ("fcnfkc", "FC_NFKC_Closure"), + ("fcnfkcclosure", "FC_NFKC_Closure"), + ("fullcompositionexclusion", "Full_Composition_Exclusion"), + ("gc", "General_Category"), + ("gcb", "Grapheme_Cluster_Break"), + ("generalcategory", "General_Category"), + ("graphemebase", "Grapheme_Base"), + ("graphemeclusterbreak", "Grapheme_Cluster_Break"), + ("graphemeextend", "Grapheme_Extend"), + ("graphemelink", "Grapheme_Link"), + ("grbase", "Grapheme_Base"), + ("grext", "Grapheme_Extend"), + ("grlink", "Grapheme_Link"), + ("hangulsyllabletype", "Hangul_Syllable_Type"), + ("hex", "Hex_Digit"), + ("hexdigit", "Hex_Digit"), + ("hst", "Hangul_Syllable_Type"), + ("hyphen", "Hyphen"), + ("idc", "ID_Continue"), + ("idcontinue", "ID_Continue"), + ("ideo", "Ideographic"), + ("ideographic", "Ideographic"), + ("ids", "ID_Start"), + ("idsb", "IDS_Binary_Operator"), + ("idsbinaryoperator", "IDS_Binary_Operator"), + ("idst", "IDS_Trinary_Operator"), + ("idstart", "ID_Start"), + ("idstrinaryoperator", "IDS_Trinary_Operator"), + ("indicpositionalcategory", "Indic_Positional_Category"), + ("indicsyllabiccategory", "Indic_Syllabic_Category"), + ("inpc", "Indic_Positional_Category"), + ("insc", "Indic_Syllabic_Category"), + ("isc", "ISO_Comment"), + ("jamoshortname", "Jamo_Short_Name"), + ("jg", "Joining_Group"), + ("joinc", "Join_Control"), + ("joincontrol", "Join_Control"), + ("joininggroup", "Joining_Group"), + ("joiningtype", "Joining_Type"), + ("jsn", "Jamo_Short_Name"), + ("jt", "Joining_Type"), + ("kaccountingnumeric", "kAccountingNumeric"), + ("kcompatibilityvariant", "kCompatibilityVariant"), + ("kiicore", "kIICore"), + ("kirggsource", "kIRG_GSource"), + ("kirghsource", "kIRG_HSource"), + ("kirgjsource", "kIRG_JSource"), + ("kirgkpsource", "kIRG_KPSource"), + ("kirgksource", "kIRG_KSource"), + ("kirgmsource", "kIRG_MSource"), + ("kirgssource", "kIRG_SSource"), + ("kirgtsource", "kIRG_TSource"), + ("kirguksource", "kIRG_UKSource"), + ("kirgusource", "kIRG_USource"), + ("kirgvsource", "kIRG_VSource"), + ("kothernumeric", "kOtherNumeric"), + ("kprimarynumeric", "kPrimaryNumeric"), + ("krsunicode", "kRSUnicode"), + ("lb", "Line_Break"), + ("lc", "Lowercase_Mapping"), + ("linebreak", "Line_Break"), + ("loe", "Logical_Order_Exception"), + ("logicalorderexception", "Logical_Order_Exception"), + ("lower", "Lowercase"), + ("lowercase", "Lowercase"), + ("lowercasemapping", "Lowercase_Mapping"), + ("math", "Math"), + ("na", "Name"), + ("na1", "Unicode_1_Name"), + ("name", "Name"), + ("namealias", "Name_Alias"), + ("nchar", "Noncharacter_Code_Point"), + ("nfcqc", "NFC_Quick_Check"), + ("nfcquickcheck", "NFC_Quick_Check"), + ("nfdqc", "NFD_Quick_Check"), + ("nfdquickcheck", "NFD_Quick_Check"), + ("nfkccasefold", "NFKC_Casefold"), + ("nfkccf", "NFKC_Casefold"), + ("nfkcqc", "NFKC_Quick_Check"), + ("nfkcquickcheck", "NFKC_Quick_Check"), + ("nfkdqc", "NFKD_Quick_Check"), + ("nfkdquickcheck", "NFKD_Quick_Check"), + ("noncharactercodepoint", "Noncharacter_Code_Point"), + ("nt", "Numeric_Type"), + ("numerictype", "Numeric_Type"), + ("numericvalue", "Numeric_Value"), + ("nv", "Numeric_Value"), + ("oalpha", "Other_Alphabetic"), + ("ocomment", "ISO_Comment"), + ("odi", "Other_Default_Ignorable_Code_Point"), + ("ogrext", "Other_Grapheme_Extend"), + ("oidc", "Other_ID_Continue"), + ("oids", "Other_ID_Start"), + ("olower", "Other_Lowercase"), + ("omath", "Other_Math"), + ("otheralphabetic", "Other_Alphabetic"), + ("otherdefaultignorablecodepoint", "Other_Default_Ignorable_Code_Point"), + ("othergraphemeextend", "Other_Grapheme_Extend"), + ("otheridcontinue", "Other_ID_Continue"), + ("otheridstart", "Other_ID_Start"), + ("otherlowercase", "Other_Lowercase"), + ("othermath", "Other_Math"), + ("otheruppercase", "Other_Uppercase"), + ("oupper", "Other_Uppercase"), + ("patsyn", "Pattern_Syntax"), + ("patternsyntax", "Pattern_Syntax"), + ("patternwhitespace", "Pattern_White_Space"), + ("patws", "Pattern_White_Space"), + ("pcm", "Prepended_Concatenation_Mark"), + ("prependedconcatenationmark", "Prepended_Concatenation_Mark"), + ("qmark", "Quotation_Mark"), + ("quotationmark", "Quotation_Mark"), + ("radical", "Radical"), + ("regionalindicator", "Regional_Indicator"), + ("ri", "Regional_Indicator"), + ("sb", "Sentence_Break"), + ("sc", "Script"), + ("scf", "Simple_Case_Folding"), + ("script", "Script"), + ("scriptextensions", "Script_Extensions"), + ("scx", "Script_Extensions"), + ("sd", "Soft_Dotted"), + ("sentencebreak", "Sentence_Break"), + ("sentenceterminal", "Sentence_Terminal"), + ("sfc", "Simple_Case_Folding"), + ("simplecasefolding", "Simple_Case_Folding"), + ("simplelowercasemapping", "Simple_Lowercase_Mapping"), + ("simpletitlecasemapping", "Simple_Titlecase_Mapping"), + ("simpleuppercasemapping", "Simple_Uppercase_Mapping"), + ("slc", "Simple_Lowercase_Mapping"), + ("softdotted", "Soft_Dotted"), + ("space", "White_Space"), + ("stc", "Simple_Titlecase_Mapping"), + ("sterm", "Sentence_Terminal"), + ("suc", "Simple_Uppercase_Mapping"), + ("tc", "Titlecase_Mapping"), + ("term", "Terminal_Punctuation"), + ("terminalpunctuation", "Terminal_Punctuation"), + ("titlecasemapping", "Titlecase_Mapping"), + ("uc", "Uppercase_Mapping"), + ("uideo", "Unified_Ideograph"), + ("unicode1name", "Unicode_1_Name"), + ("unicoderadicalstroke", "kRSUnicode"), + ("unifiedideograph", "Unified_Ideograph"), + ("upper", "Uppercase"), + ("uppercase", "Uppercase"), + ("uppercasemapping", "Uppercase_Mapping"), + ("urs", "kRSUnicode"), + ("variationselector", "Variation_Selector"), + ("verticalorientation", "Vertical_Orientation"), + ("vo", "Vertical_Orientation"), + ("vs", "Variation_Selector"), + ("wb", "Word_Break"), + ("whitespace", "White_Space"), + ("wordbreak", "Word_Break"), + ("wspace", "White_Space"), + ("xidc", "XID_Continue"), + ("xidcontinue", "XID_Continue"), + ("xids", "XID_Start"), + ("xidstart", "XID_Start"), + ("xonfc", "Expands_On_NFC"), + ("xonfd", "Expands_On_NFD"), + ("xonfkc", "Expands_On_NFKC"), + ("xonfkd", "Expands_On_NFKD"), +]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/property_values.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/property_values.rs new file mode 100644 index 0000000000000..cb2d32fb707d2 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/property_values.rs @@ -0,0 +1,924 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate property-values ucd-15.0.0 --include gc,script,scx,age,gcb,wb,sb +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const PROPERTY_VALUES: &'static [( + &'static str, + &'static [(&'static str, &'static str)], +)] = &[ + ( + "Age", + &[ + ("1.1", "V1_1"), + ("10.0", "V10_0"), + ("11.0", "V11_0"), + ("12.0", "V12_0"), + ("12.1", "V12_1"), + ("13.0", "V13_0"), + ("14.0", "V14_0"), + ("15.0", "V15_0"), + ("2.0", "V2_0"), + ("2.1", "V2_1"), + ("3.0", "V3_0"), + ("3.1", "V3_1"), + ("3.2", "V3_2"), + ("4.0", "V4_0"), + ("4.1", "V4_1"), + ("5.0", "V5_0"), + ("5.1", "V5_1"), + ("5.2", "V5_2"), + ("6.0", "V6_0"), + ("6.1", "V6_1"), + ("6.2", "V6_2"), + ("6.3", "V6_3"), + ("7.0", "V7_0"), + ("8.0", "V8_0"), + ("9.0", "V9_0"), + ("na", "Unassigned"), + ("unassigned", "Unassigned"), + ("v100", "V10_0"), + ("v11", "V1_1"), + ("v110", "V11_0"), + ("v120", "V12_0"), + ("v121", "V12_1"), + ("v130", "V13_0"), + ("v140", "V14_0"), + ("v150", "V15_0"), + ("v20", "V2_0"), + ("v21", "V2_1"), + ("v30", "V3_0"), + ("v31", "V3_1"), + ("v32", "V3_2"), + ("v40", "V4_0"), + ("v41", "V4_1"), + ("v50", "V5_0"), + ("v51", "V5_1"), + ("v52", "V5_2"), + ("v60", "V6_0"), + ("v61", "V6_1"), + ("v62", "V6_2"), + ("v63", "V6_3"), + ("v70", "V7_0"), + ("v80", "V8_0"), + ("v90", "V9_0"), + ], + ), + ( + "General_Category", + &[ + ("c", "Other"), + ("casedletter", "Cased_Letter"), + ("cc", "Control"), + ("cf", "Format"), + ("closepunctuation", "Close_Punctuation"), + ("cn", "Unassigned"), + ("cntrl", "Control"), + ("co", "Private_Use"), + ("combiningmark", "Mark"), + ("connectorpunctuation", "Connector_Punctuation"), + ("control", "Control"), + ("cs", "Surrogate"), + ("currencysymbol", "Currency_Symbol"), + ("dashpunctuation", "Dash_Punctuation"), + ("decimalnumber", "Decimal_Number"), + ("digit", "Decimal_Number"), + ("enclosingmark", "Enclosing_Mark"), + ("finalpunctuation", "Final_Punctuation"), + ("format", "Format"), + ("initialpunctuation", "Initial_Punctuation"), + ("l", "Letter"), + ("lc", "Cased_Letter"), + ("letter", "Letter"), + ("letternumber", "Letter_Number"), + ("lineseparator", "Line_Separator"), + ("ll", "Lowercase_Letter"), + ("lm", "Modifier_Letter"), + ("lo", "Other_Letter"), + ("lowercaseletter", "Lowercase_Letter"), + ("lt", "Titlecase_Letter"), + ("lu", "Uppercase_Letter"), + ("m", "Mark"), + ("mark", "Mark"), + ("mathsymbol", "Math_Symbol"), + ("mc", "Spacing_Mark"), + ("me", "Enclosing_Mark"), + ("mn", "Nonspacing_Mark"), + ("modifierletter", "Modifier_Letter"), + ("modifiersymbol", "Modifier_Symbol"), + ("n", "Number"), + ("nd", "Decimal_Number"), + ("nl", "Letter_Number"), + ("no", "Other_Number"), + ("nonspacingmark", "Nonspacing_Mark"), + ("number", "Number"), + ("openpunctuation", "Open_Punctuation"), + ("other", "Other"), + ("otherletter", "Other_Letter"), + ("othernumber", "Other_Number"), + ("otherpunctuation", "Other_Punctuation"), + ("othersymbol", "Other_Symbol"), + ("p", "Punctuation"), + ("paragraphseparator", "Paragraph_Separator"), + ("pc", "Connector_Punctuation"), + ("pd", "Dash_Punctuation"), + ("pe", "Close_Punctuation"), + ("pf", "Final_Punctuation"), + ("pi", "Initial_Punctuation"), + ("po", "Other_Punctuation"), + ("privateuse", "Private_Use"), + ("ps", "Open_Punctuation"), + ("punct", "Punctuation"), + ("punctuation", "Punctuation"), + ("s", "Symbol"), + ("sc", "Currency_Symbol"), + ("separator", "Separator"), + ("sk", "Modifier_Symbol"), + ("sm", "Math_Symbol"), + ("so", "Other_Symbol"), + ("spaceseparator", "Space_Separator"), + ("spacingmark", "Spacing_Mark"), + ("surrogate", "Surrogate"), + ("symbol", "Symbol"), + ("titlecaseletter", "Titlecase_Letter"), + ("unassigned", "Unassigned"), + ("uppercaseletter", "Uppercase_Letter"), + ("z", "Separator"), + ("zl", "Line_Separator"), + ("zp", "Paragraph_Separator"), + ("zs", "Space_Separator"), + ], + ), + ( + "Grapheme_Cluster_Break", + &[ + ("cn", "Control"), + ("control", "Control"), + ("cr", "CR"), + ("eb", "E_Base"), + ("ebase", "E_Base"), + ("ebasegaz", "E_Base_GAZ"), + ("ebg", "E_Base_GAZ"), + ("em", "E_Modifier"), + ("emodifier", "E_Modifier"), + ("ex", "Extend"), + ("extend", "Extend"), + ("gaz", "Glue_After_Zwj"), + ("glueafterzwj", "Glue_After_Zwj"), + ("l", "L"), + ("lf", "LF"), + ("lv", "LV"), + ("lvt", "LVT"), + ("other", "Other"), + ("pp", "Prepend"), + ("prepend", "Prepend"), + ("regionalindicator", "Regional_Indicator"), + ("ri", "Regional_Indicator"), + ("sm", "SpacingMark"), + ("spacingmark", "SpacingMark"), + ("t", "T"), + ("v", "V"), + ("xx", "Other"), + ("zwj", "ZWJ"), + ], + ), + ( + "Script", + &[ + ("adlam", "Adlam"), + ("adlm", "Adlam"), + ("aghb", "Caucasian_Albanian"), + ("ahom", "Ahom"), + ("anatolianhieroglyphs", "Anatolian_Hieroglyphs"), + ("arab", "Arabic"), + ("arabic", "Arabic"), + ("armenian", "Armenian"), + ("armi", "Imperial_Aramaic"), + ("armn", "Armenian"), + ("avestan", "Avestan"), + ("avst", "Avestan"), + ("bali", "Balinese"), + ("balinese", "Balinese"), + ("bamu", "Bamum"), + ("bamum", "Bamum"), + ("bass", "Bassa_Vah"), + ("bassavah", "Bassa_Vah"), + ("batak", "Batak"), + ("batk", "Batak"), + ("beng", "Bengali"), + ("bengali", "Bengali"), + ("bhaiksuki", "Bhaiksuki"), + ("bhks", "Bhaiksuki"), + ("bopo", "Bopomofo"), + ("bopomofo", "Bopomofo"), + ("brah", "Brahmi"), + ("brahmi", "Brahmi"), + ("brai", "Braille"), + ("braille", "Braille"), + ("bugi", "Buginese"), + ("buginese", "Buginese"), + ("buhd", "Buhid"), + ("buhid", "Buhid"), + ("cakm", "Chakma"), + ("canadianaboriginal", "Canadian_Aboriginal"), + ("cans", "Canadian_Aboriginal"), + ("cari", "Carian"), + ("carian", "Carian"), + ("caucasianalbanian", "Caucasian_Albanian"), + ("chakma", "Chakma"), + ("cham", "Cham"), + ("cher", "Cherokee"), + ("cherokee", "Cherokee"), + ("chorasmian", "Chorasmian"), + ("chrs", "Chorasmian"), + ("common", "Common"), + ("copt", "Coptic"), + ("coptic", "Coptic"), + ("cpmn", "Cypro_Minoan"), + ("cprt", "Cypriot"), + ("cuneiform", "Cuneiform"), + ("cypriot", "Cypriot"), + ("cyprominoan", "Cypro_Minoan"), + ("cyrillic", "Cyrillic"), + ("cyrl", "Cyrillic"), + ("deseret", "Deseret"), + ("deva", "Devanagari"), + ("devanagari", "Devanagari"), + ("diak", "Dives_Akuru"), + ("divesakuru", "Dives_Akuru"), + ("dogr", "Dogra"), + ("dogra", "Dogra"), + ("dsrt", "Deseret"), + ("dupl", "Duployan"), + ("duployan", "Duployan"), + ("egyp", "Egyptian_Hieroglyphs"), + ("egyptianhieroglyphs", "Egyptian_Hieroglyphs"), + ("elba", "Elbasan"), + ("elbasan", "Elbasan"), + ("elym", "Elymaic"), + ("elymaic", "Elymaic"), + ("ethi", "Ethiopic"), + ("ethiopic", "Ethiopic"), + ("geor", "Georgian"), + ("georgian", "Georgian"), + ("glag", "Glagolitic"), + ("glagolitic", "Glagolitic"), + ("gong", "Gunjala_Gondi"), + ("gonm", "Masaram_Gondi"), + ("goth", "Gothic"), + ("gothic", "Gothic"), + ("gran", "Grantha"), + ("grantha", "Grantha"), + ("greek", "Greek"), + ("grek", "Greek"), + ("gujarati", "Gujarati"), + ("gujr", "Gujarati"), + ("gunjalagondi", "Gunjala_Gondi"), + ("gurmukhi", "Gurmukhi"), + ("guru", "Gurmukhi"), + ("han", "Han"), + ("hang", "Hangul"), + ("hangul", "Hangul"), + ("hani", "Han"), + ("hanifirohingya", "Hanifi_Rohingya"), + ("hano", "Hanunoo"), + ("hanunoo", "Hanunoo"), + ("hatr", "Hatran"), + ("hatran", "Hatran"), + ("hebr", "Hebrew"), + ("hebrew", "Hebrew"), + ("hira", "Hiragana"), + ("hiragana", "Hiragana"), + ("hluw", "Anatolian_Hieroglyphs"), + ("hmng", "Pahawh_Hmong"), + ("hmnp", "Nyiakeng_Puachue_Hmong"), + ("hrkt", "Katakana_Or_Hiragana"), + ("hung", "Old_Hungarian"), + ("imperialaramaic", "Imperial_Aramaic"), + ("inherited", "Inherited"), + ("inscriptionalpahlavi", "Inscriptional_Pahlavi"), + ("inscriptionalparthian", "Inscriptional_Parthian"), + ("ital", "Old_Italic"), + ("java", "Javanese"), + ("javanese", "Javanese"), + ("kaithi", "Kaithi"), + ("kali", "Kayah_Li"), + ("kana", "Katakana"), + ("kannada", "Kannada"), + ("katakana", "Katakana"), + ("katakanaorhiragana", "Katakana_Or_Hiragana"), + ("kawi", "Kawi"), + ("kayahli", "Kayah_Li"), + ("khar", "Kharoshthi"), + ("kharoshthi", "Kharoshthi"), + ("khitansmallscript", "Khitan_Small_Script"), + ("khmer", "Khmer"), + ("khmr", "Khmer"), + ("khoj", "Khojki"), + ("khojki", "Khojki"), + ("khudawadi", "Khudawadi"), + ("kits", "Khitan_Small_Script"), + ("knda", "Kannada"), + ("kthi", "Kaithi"), + ("lana", "Tai_Tham"), + ("lao", "Lao"), + ("laoo", "Lao"), + ("latin", "Latin"), + ("latn", "Latin"), + ("lepc", "Lepcha"), + ("lepcha", "Lepcha"), + ("limb", "Limbu"), + ("limbu", "Limbu"), + ("lina", "Linear_A"), + ("linb", "Linear_B"), + ("lineara", "Linear_A"), + ("linearb", "Linear_B"), + ("lisu", "Lisu"), + ("lyci", "Lycian"), + ("lycian", "Lycian"), + ("lydi", "Lydian"), + ("lydian", "Lydian"), + ("mahajani", "Mahajani"), + ("mahj", "Mahajani"), + ("maka", "Makasar"), + ("makasar", "Makasar"), + ("malayalam", "Malayalam"), + ("mand", "Mandaic"), + ("mandaic", "Mandaic"), + ("mani", "Manichaean"), + ("manichaean", "Manichaean"), + ("marc", "Marchen"), + ("marchen", "Marchen"), + ("masaramgondi", "Masaram_Gondi"), + ("medefaidrin", "Medefaidrin"), + ("medf", "Medefaidrin"), + ("meeteimayek", "Meetei_Mayek"), + ("mend", "Mende_Kikakui"), + ("mendekikakui", "Mende_Kikakui"), + ("merc", "Meroitic_Cursive"), + ("mero", "Meroitic_Hieroglyphs"), + ("meroiticcursive", "Meroitic_Cursive"), + ("meroitichieroglyphs", "Meroitic_Hieroglyphs"), + ("miao", "Miao"), + ("mlym", "Malayalam"), + ("modi", "Modi"), + ("mong", "Mongolian"), + ("mongolian", "Mongolian"), + ("mro", "Mro"), + ("mroo", "Mro"), + ("mtei", "Meetei_Mayek"), + ("mult", "Multani"), + ("multani", "Multani"), + ("myanmar", "Myanmar"), + ("mymr", "Myanmar"), + ("nabataean", "Nabataean"), + ("nagm", "Nag_Mundari"), + ("nagmundari", "Nag_Mundari"), + ("nand", "Nandinagari"), + ("nandinagari", "Nandinagari"), + ("narb", "Old_North_Arabian"), + ("nbat", "Nabataean"), + ("newa", "Newa"), + ("newtailue", "New_Tai_Lue"), + ("nko", "Nko"), + ("nkoo", "Nko"), + ("nshu", "Nushu"), + ("nushu", "Nushu"), + ("nyiakengpuachuehmong", "Nyiakeng_Puachue_Hmong"), + ("ogam", "Ogham"), + ("ogham", "Ogham"), + ("olchiki", "Ol_Chiki"), + ("olck", "Ol_Chiki"), + ("oldhungarian", "Old_Hungarian"), + ("olditalic", "Old_Italic"), + ("oldnortharabian", "Old_North_Arabian"), + ("oldpermic", "Old_Permic"), + ("oldpersian", "Old_Persian"), + ("oldsogdian", "Old_Sogdian"), + ("oldsoutharabian", "Old_South_Arabian"), + ("oldturkic", "Old_Turkic"), + ("olduyghur", "Old_Uyghur"), + ("oriya", "Oriya"), + ("orkh", "Old_Turkic"), + ("orya", "Oriya"), + ("osage", "Osage"), + ("osge", "Osage"), + ("osma", "Osmanya"), + ("osmanya", "Osmanya"), + ("ougr", "Old_Uyghur"), + ("pahawhhmong", "Pahawh_Hmong"), + ("palm", "Palmyrene"), + ("palmyrene", "Palmyrene"), + ("pauc", "Pau_Cin_Hau"), + ("paucinhau", "Pau_Cin_Hau"), + ("perm", "Old_Permic"), + ("phag", "Phags_Pa"), + ("phagspa", "Phags_Pa"), + ("phli", "Inscriptional_Pahlavi"), + ("phlp", "Psalter_Pahlavi"), + ("phnx", "Phoenician"), + ("phoenician", "Phoenician"), + ("plrd", "Miao"), + ("prti", "Inscriptional_Parthian"), + ("psalterpahlavi", "Psalter_Pahlavi"), + ("qaac", "Coptic"), + ("qaai", "Inherited"), + ("rejang", "Rejang"), + ("rjng", "Rejang"), + ("rohg", "Hanifi_Rohingya"), + ("runic", "Runic"), + ("runr", "Runic"), + ("samaritan", "Samaritan"), + ("samr", "Samaritan"), + ("sarb", "Old_South_Arabian"), + ("saur", "Saurashtra"), + ("saurashtra", "Saurashtra"), + ("sgnw", "SignWriting"), + ("sharada", "Sharada"), + ("shavian", "Shavian"), + ("shaw", "Shavian"), + ("shrd", "Sharada"), + ("sidd", "Siddham"), + ("siddham", "Siddham"), + ("signwriting", "SignWriting"), + ("sind", "Khudawadi"), + ("sinh", "Sinhala"), + ("sinhala", "Sinhala"), + ("sogd", "Sogdian"), + ("sogdian", "Sogdian"), + ("sogo", "Old_Sogdian"), + ("sora", "Sora_Sompeng"), + ("sorasompeng", "Sora_Sompeng"), + ("soyo", "Soyombo"), + ("soyombo", "Soyombo"), + ("sund", "Sundanese"), + ("sundanese", "Sundanese"), + ("sylo", "Syloti_Nagri"), + ("sylotinagri", "Syloti_Nagri"), + ("syrc", "Syriac"), + ("syriac", "Syriac"), + ("tagalog", "Tagalog"), + ("tagb", "Tagbanwa"), + ("tagbanwa", "Tagbanwa"), + ("taile", "Tai_Le"), + ("taitham", "Tai_Tham"), + ("taiviet", "Tai_Viet"), + ("takr", "Takri"), + ("takri", "Takri"), + ("tale", "Tai_Le"), + ("talu", "New_Tai_Lue"), + ("tamil", "Tamil"), + ("taml", "Tamil"), + ("tang", "Tangut"), + ("tangsa", "Tangsa"), + ("tangut", "Tangut"), + ("tavt", "Tai_Viet"), + ("telu", "Telugu"), + ("telugu", "Telugu"), + ("tfng", "Tifinagh"), + ("tglg", "Tagalog"), + ("thaa", "Thaana"), + ("thaana", "Thaana"), + ("thai", "Thai"), + ("tibetan", "Tibetan"), + ("tibt", "Tibetan"), + ("tifinagh", "Tifinagh"), + ("tirh", "Tirhuta"), + ("tirhuta", "Tirhuta"), + ("tnsa", "Tangsa"), + ("toto", "Toto"), + ("ugar", "Ugaritic"), + ("ugaritic", "Ugaritic"), + ("unknown", "Unknown"), + ("vai", "Vai"), + ("vaii", "Vai"), + ("vith", "Vithkuqi"), + ("vithkuqi", "Vithkuqi"), + ("wancho", "Wancho"), + ("wara", "Warang_Citi"), + ("warangciti", "Warang_Citi"), + ("wcho", "Wancho"), + ("xpeo", "Old_Persian"), + ("xsux", "Cuneiform"), + ("yezi", "Yezidi"), + ("yezidi", "Yezidi"), + ("yi", "Yi"), + ("yiii", "Yi"), + ("zanabazarsquare", "Zanabazar_Square"), + ("zanb", "Zanabazar_Square"), + ("zinh", "Inherited"), + ("zyyy", "Common"), + ("zzzz", "Unknown"), + ], + ), + ( + "Script_Extensions", + &[ + ("adlam", "Adlam"), + ("adlm", "Adlam"), + ("aghb", "Caucasian_Albanian"), + ("ahom", "Ahom"), + ("anatolianhieroglyphs", "Anatolian_Hieroglyphs"), + ("arab", "Arabic"), + ("arabic", "Arabic"), + ("armenian", "Armenian"), + ("armi", "Imperial_Aramaic"), + ("armn", "Armenian"), + ("avestan", "Avestan"), + ("avst", "Avestan"), + ("bali", "Balinese"), + ("balinese", "Balinese"), + ("bamu", "Bamum"), + ("bamum", "Bamum"), + ("bass", "Bassa_Vah"), + ("bassavah", "Bassa_Vah"), + ("batak", "Batak"), + ("batk", "Batak"), + ("beng", "Bengali"), + ("bengali", "Bengali"), + ("bhaiksuki", "Bhaiksuki"), + ("bhks", "Bhaiksuki"), + ("bopo", "Bopomofo"), + ("bopomofo", "Bopomofo"), + ("brah", "Brahmi"), + ("brahmi", "Brahmi"), + ("brai", "Braille"), + ("braille", "Braille"), + ("bugi", "Buginese"), + ("buginese", "Buginese"), + ("buhd", "Buhid"), + ("buhid", "Buhid"), + ("cakm", "Chakma"), + ("canadianaboriginal", "Canadian_Aboriginal"), + ("cans", "Canadian_Aboriginal"), + ("cari", "Carian"), + ("carian", "Carian"), + ("caucasianalbanian", "Caucasian_Albanian"), + ("chakma", "Chakma"), + ("cham", "Cham"), + ("cher", "Cherokee"), + ("cherokee", "Cherokee"), + ("chorasmian", "Chorasmian"), + ("chrs", "Chorasmian"), + ("common", "Common"), + ("copt", "Coptic"), + ("coptic", "Coptic"), + ("cpmn", "Cypro_Minoan"), + ("cprt", "Cypriot"), + ("cuneiform", "Cuneiform"), + ("cypriot", "Cypriot"), + ("cyprominoan", "Cypro_Minoan"), + ("cyrillic", "Cyrillic"), + ("cyrl", "Cyrillic"), + ("deseret", "Deseret"), + ("deva", "Devanagari"), + ("devanagari", "Devanagari"), + ("diak", "Dives_Akuru"), + ("divesakuru", "Dives_Akuru"), + ("dogr", "Dogra"), + ("dogra", "Dogra"), + ("dsrt", "Deseret"), + ("dupl", "Duployan"), + ("duployan", "Duployan"), + ("egyp", "Egyptian_Hieroglyphs"), + ("egyptianhieroglyphs", "Egyptian_Hieroglyphs"), + ("elba", "Elbasan"), + ("elbasan", "Elbasan"), + ("elym", "Elymaic"), + ("elymaic", "Elymaic"), + ("ethi", "Ethiopic"), + ("ethiopic", "Ethiopic"), + ("geor", "Georgian"), + ("georgian", "Georgian"), + ("glag", "Glagolitic"), + ("glagolitic", "Glagolitic"), + ("gong", "Gunjala_Gondi"), + ("gonm", "Masaram_Gondi"), + ("goth", "Gothic"), + ("gothic", "Gothic"), + ("gran", "Grantha"), + ("grantha", "Grantha"), + ("greek", "Greek"), + ("grek", "Greek"), + ("gujarati", "Gujarati"), + ("gujr", "Gujarati"), + ("gunjalagondi", "Gunjala_Gondi"), + ("gurmukhi", "Gurmukhi"), + ("guru", "Gurmukhi"), + ("han", "Han"), + ("hang", "Hangul"), + ("hangul", "Hangul"), + ("hani", "Han"), + ("hanifirohingya", "Hanifi_Rohingya"), + ("hano", "Hanunoo"), + ("hanunoo", "Hanunoo"), + ("hatr", "Hatran"), + ("hatran", "Hatran"), + ("hebr", "Hebrew"), + ("hebrew", "Hebrew"), + ("hira", "Hiragana"), + ("hiragana", "Hiragana"), + ("hluw", "Anatolian_Hieroglyphs"), + ("hmng", "Pahawh_Hmong"), + ("hmnp", "Nyiakeng_Puachue_Hmong"), + ("hrkt", "Katakana_Or_Hiragana"), + ("hung", "Old_Hungarian"), + ("imperialaramaic", "Imperial_Aramaic"), + ("inherited", "Inherited"), + ("inscriptionalpahlavi", "Inscriptional_Pahlavi"), + ("inscriptionalparthian", "Inscriptional_Parthian"), + ("ital", "Old_Italic"), + ("java", "Javanese"), + ("javanese", "Javanese"), + ("kaithi", "Kaithi"), + ("kali", "Kayah_Li"), + ("kana", "Katakana"), + ("kannada", "Kannada"), + ("katakana", "Katakana"), + ("katakanaorhiragana", "Katakana_Or_Hiragana"), + ("kawi", "Kawi"), + ("kayahli", "Kayah_Li"), + ("khar", "Kharoshthi"), + ("kharoshthi", "Kharoshthi"), + ("khitansmallscript", "Khitan_Small_Script"), + ("khmer", "Khmer"), + ("khmr", "Khmer"), + ("khoj", "Khojki"), + ("khojki", "Khojki"), + ("khudawadi", "Khudawadi"), + ("kits", "Khitan_Small_Script"), + ("knda", "Kannada"), + ("kthi", "Kaithi"), + ("lana", "Tai_Tham"), + ("lao", "Lao"), + ("laoo", "Lao"), + ("latin", "Latin"), + ("latn", "Latin"), + ("lepc", "Lepcha"), + ("lepcha", "Lepcha"), + ("limb", "Limbu"), + ("limbu", "Limbu"), + ("lina", "Linear_A"), + ("linb", "Linear_B"), + ("lineara", "Linear_A"), + ("linearb", "Linear_B"), + ("lisu", "Lisu"), + ("lyci", "Lycian"), + ("lycian", "Lycian"), + ("lydi", "Lydian"), + ("lydian", "Lydian"), + ("mahajani", "Mahajani"), + ("mahj", "Mahajani"), + ("maka", "Makasar"), + ("makasar", "Makasar"), + ("malayalam", "Malayalam"), + ("mand", "Mandaic"), + ("mandaic", "Mandaic"), + ("mani", "Manichaean"), + ("manichaean", "Manichaean"), + ("marc", "Marchen"), + ("marchen", "Marchen"), + ("masaramgondi", "Masaram_Gondi"), + ("medefaidrin", "Medefaidrin"), + ("medf", "Medefaidrin"), + ("meeteimayek", "Meetei_Mayek"), + ("mend", "Mende_Kikakui"), + ("mendekikakui", "Mende_Kikakui"), + ("merc", "Meroitic_Cursive"), + ("mero", "Meroitic_Hieroglyphs"), + ("meroiticcursive", "Meroitic_Cursive"), + ("meroitichieroglyphs", "Meroitic_Hieroglyphs"), + ("miao", "Miao"), + ("mlym", "Malayalam"), + ("modi", "Modi"), + ("mong", "Mongolian"), + ("mongolian", "Mongolian"), + ("mro", "Mro"), + ("mroo", "Mro"), + ("mtei", "Meetei_Mayek"), + ("mult", "Multani"), + ("multani", "Multani"), + ("myanmar", "Myanmar"), + ("mymr", "Myanmar"), + ("nabataean", "Nabataean"), + ("nagm", "Nag_Mundari"), + ("nagmundari", "Nag_Mundari"), + ("nand", "Nandinagari"), + ("nandinagari", "Nandinagari"), + ("narb", "Old_North_Arabian"), + ("nbat", "Nabataean"), + ("newa", "Newa"), + ("newtailue", "New_Tai_Lue"), + ("nko", "Nko"), + ("nkoo", "Nko"), + ("nshu", "Nushu"), + ("nushu", "Nushu"), + ("nyiakengpuachuehmong", "Nyiakeng_Puachue_Hmong"), + ("ogam", "Ogham"), + ("ogham", "Ogham"), + ("olchiki", "Ol_Chiki"), + ("olck", "Ol_Chiki"), + ("oldhungarian", "Old_Hungarian"), + ("olditalic", "Old_Italic"), + ("oldnortharabian", "Old_North_Arabian"), + ("oldpermic", "Old_Permic"), + ("oldpersian", "Old_Persian"), + ("oldsogdian", "Old_Sogdian"), + ("oldsoutharabian", "Old_South_Arabian"), + ("oldturkic", "Old_Turkic"), + ("olduyghur", "Old_Uyghur"), + ("oriya", "Oriya"), + ("orkh", "Old_Turkic"), + ("orya", "Oriya"), + ("osage", "Osage"), + ("osge", "Osage"), + ("osma", "Osmanya"), + ("osmanya", "Osmanya"), + ("ougr", "Old_Uyghur"), + ("pahawhhmong", "Pahawh_Hmong"), + ("palm", "Palmyrene"), + ("palmyrene", "Palmyrene"), + ("pauc", "Pau_Cin_Hau"), + ("paucinhau", "Pau_Cin_Hau"), + ("perm", "Old_Permic"), + ("phag", "Phags_Pa"), + ("phagspa", "Phags_Pa"), + ("phli", "Inscriptional_Pahlavi"), + ("phlp", "Psalter_Pahlavi"), + ("phnx", "Phoenician"), + ("phoenician", "Phoenician"), + ("plrd", "Miao"), + ("prti", "Inscriptional_Parthian"), + ("psalterpahlavi", "Psalter_Pahlavi"), + ("qaac", "Coptic"), + ("qaai", "Inherited"), + ("rejang", "Rejang"), + ("rjng", "Rejang"), + ("rohg", "Hanifi_Rohingya"), + ("runic", "Runic"), + ("runr", "Runic"), + ("samaritan", "Samaritan"), + ("samr", "Samaritan"), + ("sarb", "Old_South_Arabian"), + ("saur", "Saurashtra"), + ("saurashtra", "Saurashtra"), + ("sgnw", "SignWriting"), + ("sharada", "Sharada"), + ("shavian", "Shavian"), + ("shaw", "Shavian"), + ("shrd", "Sharada"), + ("sidd", "Siddham"), + ("siddham", "Siddham"), + ("signwriting", "SignWriting"), + ("sind", "Khudawadi"), + ("sinh", "Sinhala"), + ("sinhala", "Sinhala"), + ("sogd", "Sogdian"), + ("sogdian", "Sogdian"), + ("sogo", "Old_Sogdian"), + ("sora", "Sora_Sompeng"), + ("sorasompeng", "Sora_Sompeng"), + ("soyo", "Soyombo"), + ("soyombo", "Soyombo"), + ("sund", "Sundanese"), + ("sundanese", "Sundanese"), + ("sylo", "Syloti_Nagri"), + ("sylotinagri", "Syloti_Nagri"), + ("syrc", "Syriac"), + ("syriac", "Syriac"), + ("tagalog", "Tagalog"), + ("tagb", "Tagbanwa"), + ("tagbanwa", "Tagbanwa"), + ("taile", "Tai_Le"), + ("taitham", "Tai_Tham"), + ("taiviet", "Tai_Viet"), + ("takr", "Takri"), + ("takri", "Takri"), + ("tale", "Tai_Le"), + ("talu", "New_Tai_Lue"), + ("tamil", "Tamil"), + ("taml", "Tamil"), + ("tang", "Tangut"), + ("tangsa", "Tangsa"), + ("tangut", "Tangut"), + ("tavt", "Tai_Viet"), + ("telu", "Telugu"), + ("telugu", "Telugu"), + ("tfng", "Tifinagh"), + ("tglg", "Tagalog"), + ("thaa", "Thaana"), + ("thaana", "Thaana"), + ("thai", "Thai"), + ("tibetan", "Tibetan"), + ("tibt", "Tibetan"), + ("tifinagh", "Tifinagh"), + ("tirh", "Tirhuta"), + ("tirhuta", "Tirhuta"), + ("tnsa", "Tangsa"), + ("toto", "Toto"), + ("ugar", "Ugaritic"), + ("ugaritic", "Ugaritic"), + ("unknown", "Unknown"), + ("vai", "Vai"), + ("vaii", "Vai"), + ("vith", "Vithkuqi"), + ("vithkuqi", "Vithkuqi"), + ("wancho", "Wancho"), + ("wara", "Warang_Citi"), + ("warangciti", "Warang_Citi"), + ("wcho", "Wancho"), + ("xpeo", "Old_Persian"), + ("xsux", "Cuneiform"), + ("yezi", "Yezidi"), + ("yezidi", "Yezidi"), + ("yi", "Yi"), + ("yiii", "Yi"), + ("zanabazarsquare", "Zanabazar_Square"), + ("zanb", "Zanabazar_Square"), + ("zinh", "Inherited"), + ("zyyy", "Common"), + ("zzzz", "Unknown"), + ], + ), + ( + "Sentence_Break", + &[ + ("at", "ATerm"), + ("aterm", "ATerm"), + ("cl", "Close"), + ("close", "Close"), + ("cr", "CR"), + ("ex", "Extend"), + ("extend", "Extend"), + ("fo", "Format"), + ("format", "Format"), + ("le", "OLetter"), + ("lf", "LF"), + ("lo", "Lower"), + ("lower", "Lower"), + ("nu", "Numeric"), + ("numeric", "Numeric"), + ("oletter", "OLetter"), + ("other", "Other"), + ("sc", "SContinue"), + ("scontinue", "SContinue"), + ("se", "Sep"), + ("sep", "Sep"), + ("sp", "Sp"), + ("st", "STerm"), + ("sterm", "STerm"), + ("up", "Upper"), + ("upper", "Upper"), + ("xx", "Other"), + ], + ), + ( + "Word_Break", + &[ + ("aletter", "ALetter"), + ("cr", "CR"), + ("doublequote", "Double_Quote"), + ("dq", "Double_Quote"), + ("eb", "E_Base"), + ("ebase", "E_Base"), + ("ebasegaz", "E_Base_GAZ"), + ("ebg", "E_Base_GAZ"), + ("em", "E_Modifier"), + ("emodifier", "E_Modifier"), + ("ex", "ExtendNumLet"), + ("extend", "Extend"), + ("extendnumlet", "ExtendNumLet"), + ("fo", "Format"), + ("format", "Format"), + ("gaz", "Glue_After_Zwj"), + ("glueafterzwj", "Glue_After_Zwj"), + ("hebrewletter", "Hebrew_Letter"), + ("hl", "Hebrew_Letter"), + ("ka", "Katakana"), + ("katakana", "Katakana"), + ("le", "ALetter"), + ("lf", "LF"), + ("mb", "MidNumLet"), + ("midletter", "MidLetter"), + ("midnum", "MidNum"), + ("midnumlet", "MidNumLet"), + ("ml", "MidLetter"), + ("mn", "MidNum"), + ("newline", "Newline"), + ("nl", "Newline"), + ("nu", "Numeric"), + ("numeric", "Numeric"), + ("other", "Other"), + ("regionalindicator", "Regional_Indicator"), + ("ri", "Regional_Indicator"), + ("singlequote", "Single_Quote"), + ("sq", "Single_Quote"), + ("wsegspace", "WSegSpace"), + ("xx", "Other"), + ("zwj", "ZWJ"), + ], + ), +]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/script.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/script.rs new file mode 100644 index 0000000000000..cc5c400ddb84d --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/script.rs @@ -0,0 +1,1263 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate script ucd-15.0.0 --chars +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("Adlam", ADLAM), + ("Ahom", AHOM), + ("Anatolian_Hieroglyphs", ANATOLIAN_HIEROGLYPHS), + ("Arabic", ARABIC), + ("Armenian", ARMENIAN), + ("Avestan", AVESTAN), + ("Balinese", BALINESE), + ("Bamum", BAMUM), + ("Bassa_Vah", BASSA_VAH), + ("Batak", BATAK), + ("Bengali", BENGALI), + ("Bhaiksuki", BHAIKSUKI), + ("Bopomofo", BOPOMOFO), + ("Brahmi", BRAHMI), + ("Braille", BRAILLE), + ("Buginese", BUGINESE), + ("Buhid", BUHID), + ("Canadian_Aboriginal", CANADIAN_ABORIGINAL), + ("Carian", CARIAN), + ("Caucasian_Albanian", CAUCASIAN_ALBANIAN), + ("Chakma", CHAKMA), + ("Cham", CHAM), + ("Cherokee", CHEROKEE), + ("Chorasmian", CHORASMIAN), + ("Common", COMMON), + ("Coptic", COPTIC), + ("Cuneiform", CUNEIFORM), + ("Cypriot", CYPRIOT), + ("Cypro_Minoan", CYPRO_MINOAN), + ("Cyrillic", CYRILLIC), + ("Deseret", DESERET), + ("Devanagari", DEVANAGARI), + ("Dives_Akuru", DIVES_AKURU), + ("Dogra", DOGRA), + ("Duployan", DUPLOYAN), + ("Egyptian_Hieroglyphs", EGYPTIAN_HIEROGLYPHS), + ("Elbasan", ELBASAN), + ("Elymaic", ELYMAIC), + ("Ethiopic", ETHIOPIC), + ("Georgian", GEORGIAN), + ("Glagolitic", GLAGOLITIC), + ("Gothic", GOTHIC), + ("Grantha", GRANTHA), + ("Greek", GREEK), + ("Gujarati", GUJARATI), + ("Gunjala_Gondi", GUNJALA_GONDI), + ("Gurmukhi", GURMUKHI), + ("Han", HAN), + ("Hangul", HANGUL), + ("Hanifi_Rohingya", HANIFI_ROHINGYA), + ("Hanunoo", HANUNOO), + ("Hatran", HATRAN), + ("Hebrew", HEBREW), + ("Hiragana", HIRAGANA), + ("Imperial_Aramaic", IMPERIAL_ARAMAIC), + ("Inherited", INHERITED), + ("Inscriptional_Pahlavi", INSCRIPTIONAL_PAHLAVI), + ("Inscriptional_Parthian", INSCRIPTIONAL_PARTHIAN), + ("Javanese", JAVANESE), + ("Kaithi", KAITHI), + ("Kannada", KANNADA), + ("Katakana", KATAKANA), + ("Kawi", KAWI), + ("Kayah_Li", KAYAH_LI), + ("Kharoshthi", KHAROSHTHI), + ("Khitan_Small_Script", KHITAN_SMALL_SCRIPT), + ("Khmer", KHMER), + ("Khojki", KHOJKI), + ("Khudawadi", KHUDAWADI), + ("Lao", LAO), + ("Latin", LATIN), + ("Lepcha", LEPCHA), + ("Limbu", LIMBU), + ("Linear_A", LINEAR_A), + ("Linear_B", LINEAR_B), + ("Lisu", LISU), + ("Lycian", LYCIAN), + ("Lydian", LYDIAN), + ("Mahajani", MAHAJANI), + ("Makasar", MAKASAR), + ("Malayalam", MALAYALAM), + ("Mandaic", MANDAIC), + ("Manichaean", MANICHAEAN), + ("Marchen", MARCHEN), + ("Masaram_Gondi", MASARAM_GONDI), + ("Medefaidrin", MEDEFAIDRIN), + ("Meetei_Mayek", MEETEI_MAYEK), + ("Mende_Kikakui", MENDE_KIKAKUI), + ("Meroitic_Cursive", MEROITIC_CURSIVE), + ("Meroitic_Hieroglyphs", MEROITIC_HIEROGLYPHS), + ("Miao", MIAO), + ("Modi", MODI), + ("Mongolian", MONGOLIAN), + ("Mro", MRO), + ("Multani", MULTANI), + ("Myanmar", MYANMAR), + ("Nabataean", NABATAEAN), + ("Nag_Mundari", NAG_MUNDARI), + ("Nandinagari", NANDINAGARI), + ("New_Tai_Lue", NEW_TAI_LUE), + ("Newa", NEWA), + ("Nko", NKO), + ("Nushu", NUSHU), + ("Nyiakeng_Puachue_Hmong", NYIAKENG_PUACHUE_HMONG), + ("Ogham", OGHAM), + ("Ol_Chiki", OL_CHIKI), + ("Old_Hungarian", OLD_HUNGARIAN), + ("Old_Italic", OLD_ITALIC), + ("Old_North_Arabian", OLD_NORTH_ARABIAN), + ("Old_Permic", OLD_PERMIC), + ("Old_Persian", OLD_PERSIAN), + ("Old_Sogdian", OLD_SOGDIAN), + ("Old_South_Arabian", OLD_SOUTH_ARABIAN), + ("Old_Turkic", OLD_TURKIC), + ("Old_Uyghur", OLD_UYGHUR), + ("Oriya", ORIYA), + ("Osage", OSAGE), + ("Osmanya", OSMANYA), + ("Pahawh_Hmong", PAHAWH_HMONG), + ("Palmyrene", PALMYRENE), + ("Pau_Cin_Hau", PAU_CIN_HAU), + ("Phags_Pa", PHAGS_PA), + ("Phoenician", PHOENICIAN), + ("Psalter_Pahlavi", PSALTER_PAHLAVI), + ("Rejang", REJANG), + ("Runic", RUNIC), + ("Samaritan", SAMARITAN), + ("Saurashtra", SAURASHTRA), + ("Sharada", SHARADA), + ("Shavian", SHAVIAN), + ("Siddham", SIDDHAM), + ("SignWriting", SIGNWRITING), + ("Sinhala", SINHALA), + ("Sogdian", SOGDIAN), + ("Sora_Sompeng", SORA_SOMPENG), + ("Soyombo", SOYOMBO), + ("Sundanese", SUNDANESE), + ("Syloti_Nagri", SYLOTI_NAGRI), + ("Syriac", SYRIAC), + ("Tagalog", TAGALOG), + ("Tagbanwa", TAGBANWA), + ("Tai_Le", TAI_LE), + ("Tai_Tham", TAI_THAM), + ("Tai_Viet", TAI_VIET), + ("Takri", TAKRI), + ("Tamil", TAMIL), + ("Tangsa", TANGSA), + ("Tangut", TANGUT), + ("Telugu", TELUGU), + ("Thaana", THAANA), + ("Thai", THAI), + ("Tibetan", TIBETAN), + ("Tifinagh", TIFINAGH), + ("Tirhuta", TIRHUTA), + ("Toto", TOTO), + ("Ugaritic", UGARITIC), + ("Vai", VAI), + ("Vithkuqi", VITHKUQI), + ("Wancho", WANCHO), + ("Warang_Citi", WARANG_CITI), + ("Yezidi", YEZIDI), + ("Yi", YI), + ("Zanabazar_Square", ZANABAZAR_SQUARE), +]; + +pub const ADLAM: &'static [(char, char)] = + &[('𞤀', '𞥋'), ('ðž¥', '𞥙'), ('𞥞', '𞥟')]; + +pub const AHOM: &'static [(char, char)] = + &[('𑜀', '𑜚'), ('\u{1171d}', '\u{1172b}'), ('𑜰', 'ð‘†')]; + +pub const ANATOLIAN_HIEROGLYPHS: &'static [(char, char)] = &[('ð”€', '𔙆')]; + +pub const ARABIC: &'static [(char, char)] = &[ + ('\u{600}', '\u{604}'), + ('؆', 'Ø‹'), + ('Ø', '\u{61a}'), + ('\u{61c}', 'Øž'), + ('Ø ', 'Ø¿'), + ('Ù', 'ÙŠ'), + ('\u{656}', 'Ù¯'), + ('Ù±', '\u{6dc}'), + ('Ûž', 'Û¿'), + ('Ý', 'Ý¿'), + ('à¡°', 'ࢎ'), + ('\u{890}', '\u{891}'), + ('\u{898}', '\u{8e1}'), + ('\u{8e3}', '\u{8ff}'), + ('ï­', '﯂'), + ('ﯓ', 'ï´½'), + ('ïµ€', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·', 'ï·'), + ('ï·°', 'ï·¿'), + ('ï¹°', 'ï¹´'), + ('ﹶ', 'ﻼ'), + ('ð¹ ', 'ð¹¾'), + ('\u{10efd}', '\u{10eff}'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('ðž»°', 'ðž»±'), +]; + +pub const ARMENIAN: &'static [(char, char)] = + &[('Ô±', 'Õ–'), ('Õ™', 'ÖŠ'), ('Ö', 'Ö'), ('ﬓ', 'ﬗ')]; + +pub const AVESTAN: &'static [(char, char)] = &[('ð¬€', 'ð¬µ'), ('ð¬¹', 'ð¬¿')]; + +pub const BALINESE: &'static [(char, char)] = &[('\u{1b00}', 'á­Œ'), ('á­', 'á­¾')]; + +pub const BAMUM: &'static [(char, char)] = &[('êš ', 'ê›·'), ('ð– €', '𖨸')]; + +pub const BASSA_VAH: &'static [(char, char)] = + &[('ð–«', 'ð–«­'), ('\u{16af0}', 'ð–«µ')]; + +pub const BATAK: &'static [(char, char)] = &[('ᯀ', '᯳'), ('᯼', '᯿')]; + +pub const BENGALI: &'static [(char, char)] = &[ + ('ঀ', 'ঃ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('\u{9bc}', '\u{9c4}'), + ('ে', 'ৈ'), + ('ো', 'ৎ'), + ('\u{9d7}', '\u{9d7}'), + ('ড়', 'à§'), + ('য়', '\u{9e3}'), + ('০', '\u{9fe}'), +]; + +pub const BHAIKSUKI: &'static [(char, char)] = + &[('ð‘°€', 'ð‘°ˆ'), ('ð‘°Š', '\u{11c36}'), ('\u{11c38}', '𑱅'), ('ð‘±', '𑱬')]; + +pub const BOPOMOFO: &'static [(char, char)] = + &[('˪', 'Ë«'), ('ã„…', 'ㄯ'), ('ㆠ', 'ㆿ')]; + +pub const BRAHMI: &'static [(char, char)] = + &[('ð‘€€', 'ð‘'), ('ð‘’', 'ð‘µ'), ('\u{1107f}', '\u{1107f}')]; + +pub const BRAILLE: &'static [(char, char)] = &[('â €', '⣿')]; + +pub const BUGINESE: &'static [(char, char)] = &[('ᨀ', '\u{1a1b}'), ('᨞', '᨟')]; + +pub const BUHID: &'static [(char, char)] = &[('á€', '\u{1753}')]; + +pub const CANADIAN_ABORIGINAL: &'static [(char, char)] = + &[('á€', 'ᙿ'), ('ᢰ', 'ᣵ'), ('𑪰', '𑪿')]; + +pub const CARIAN: &'static [(char, char)] = &[('ðŠ ', 'ð‹')]; + +pub const CAUCASIAN_ALBANIAN: &'static [(char, char)] = + &[('ð”°', 'ð•£'), ('ð•¯', 'ð•¯')]; + +pub const CHAKMA: &'static [(char, char)] = + &[('\u{11100}', '\u{11134}'), ('𑄶', 'ð‘…‡')]; + +pub const CHAM: &'static [(char, char)] = + &[('ꨀ', '\u{aa36}'), ('ê©€', 'ê©'), ('ê©', 'ê©™'), ('ê©œ', 'ê©Ÿ')]; + +pub const CHEROKEE: &'static [(char, char)] = + &[('Ꭰ', 'áµ'), ('á¸', 'á½'), ('ê­°', 'ꮿ')]; + +pub const CHORASMIAN: &'static [(char, char)] = &[('ð¾°', 'ð¿‹')]; + +pub const COMMON: &'static [(char, char)] = &[ + ('\0', '@'), + ('[', '`'), + ('{', '©'), + ('«', '¹'), + ('»', '¿'), + ('×', '×'), + ('÷', '÷'), + ('ʹ', 'ËŸ'), + ('Ë¥', 'Ë©'), + ('ˬ', 'Ë¿'), + ('Í´', 'Í´'), + (';', ';'), + ('Î…', 'Î…'), + ('·', '·'), + ('\u{605}', '\u{605}'), + ('ØŒ', 'ØŒ'), + ('Ø›', 'Ø›'), + ('ØŸ', 'ØŸ'), + ('Ù€', 'Ù€'), + ('\u{6dd}', '\u{6dd}'), + ('\u{8e2}', '\u{8e2}'), + ('।', '॥'), + ('฿', '฿'), + ('à¿•', '࿘'), + ('჻', '჻'), + ('᛫', 'á›­'), + ('᜵', '᜶'), + ('á ‚', 'á ƒ'), + ('á …', 'á …'), + ('᳓', '᳓'), + ('᳡', '᳡'), + ('ᳩ', 'ᳬ'), + ('á³®', 'á³³'), + ('á³µ', 'á³·'), + ('ᳺ', 'ᳺ'), + ('\u{2000}', '\u{200b}'), + ('\u{200e}', '\u{2064}'), + ('\u{2066}', 'â°'), + ('â´', 'â¾'), + ('â‚€', 'â‚Ž'), + ('â‚ ', '⃀'), + ('â„€', 'â„¥'), + ('℧', 'â„©'), + ('ℬ', 'ℱ'), + ('ℳ', 'â…'), + ('â…', 'â…Ÿ'), + ('↉', '↋'), + ('â†', 'â¦'), + ('â‘€', 'â‘Š'), + ('â‘ ', '⟿'), + ('⤀', 'â­³'), + ('â­¶', '⮕'), + ('â®—', '⯿'), + ('⸀', 'â¹'), + ('â¿°', 'â¿»'), + ('\u{3000}', '〄'), + ('〆', '〆'), + ('〈', '〠'), + ('〰', '〷'), + ('〼', '〿'), + ('ã‚›', 'ã‚œ'), + ('ã‚ ', 'ã‚ '), + ('・', 'ー'), + ('ã†', '㆟'), + ('㇀', '㇣'), + ('㈠', '㉟'), + ('㉿', 'ã‹'), + ('ã‹¿', 'ã‹¿'), + ('ã˜', 'ã¿'), + ('ä·€', 'ä·¿'), + ('꜀', '꜡'), + ('ꞈ', '꞊'), + ('ê °', 'ê ¹'), + ('꤮', '꤮'), + ('ê§', 'ê§'), + ('ê­›', 'ê­›'), + ('ê­ª', 'ê­«'), + ('ï´¾', 'ï´¿'), + ('ï¸', '︙'), + ('︰', 'ï¹’'), + ('ï¹”', '﹦'), + ('﹨', '﹫'), + ('\u{feff}', '\u{feff}'), + ('ï¼', 'ï¼ '), + ('ï¼»', 'ï½€'), + ('ï½›', 'ï½¥'), + ('ï½°', 'ï½°'), + ('\u{ff9e}', '\u{ff9f}'), + ('ï¿ ', '₩'), + ('│', 'ï¿®'), + ('\u{fff9}', '�'), + ('ð„€', 'ð„‚'), + ('ð„‡', 'ð„³'), + ('ð„·', 'ð„¿'), + ('ð†', 'ð†œ'), + ('ð‡', 'ð‡¼'), + ('ð‹¡', 'ð‹»'), + ('\u{1bca0}', '\u{1bca3}'), + ('ðœ½', '𜿃'), + ('ð€€', 'ðƒµ'), + ('ð„€', 'ð„¦'), + ('ð„©', 'ð…¦'), + ('ð…ª', '\u{1d17a}'), + ('ð†ƒ', 'ð†„'), + ('ð†Œ', 'ð†©'), + ('ð†®', 'ð‡ª'), + ('ð‹€', 'ð‹“'), + ('ð‹ ', 'ð‹³'), + ('ðŒ€', 'ð–'), + ('ð ', 'ð¸'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ðŸ‹'), + ('ðŸŽ', 'ðŸ¿'), + ('ðž±±', 'ðž²´'), + ('ðž´', 'ðž´½'), + ('🀀', '🀫'), + ('🀰', '🂓'), + ('🂠', '🂮'), + ('🂱', '🂿'), + ('ðŸƒ', 'ðŸƒ'), + ('🃑', '🃵'), + ('🄀', '🆭'), + ('🇦', '🇿'), + ('ðŸˆ', '🈂'), + ('ðŸˆ', '🈻'), + ('🉀', '🉈'), + ('ðŸ‰', '🉑'), + ('🉠', '🉥'), + ('🌀', '🛗'), + ('🛜', '🛬'), + ('🛰', '🛼'), + ('🜀', 'ðŸ¶'), + ('ðŸ»', '🟙'), + ('🟠', '🟫'), + ('🟰', '🟰'), + ('🠀', '🠋'), + ('ðŸ ', '🡇'), + ('ðŸ¡', '🡙'), + ('🡠', '🢇'), + ('ðŸ¢', '🢭'), + ('🢰', '🢱'), + ('🤀', '🩓'), + ('🩠', '🩭'), + ('🩰', '🩼'), + ('🪀', '🪈'), + ('ðŸª', '🪽'), + ('🪿', '🫅'), + ('🫎', '🫛'), + ('🫠', '🫨'), + ('🫰', '🫸'), + ('🬀', '🮒'), + ('🮔', '🯊'), + ('🯰', '🯹'), + ('\u{e0001}', '\u{e0001}'), + ('\u{e0020}', '\u{e007f}'), +]; + +pub const COPTIC: &'static [(char, char)] = + &[('Ï¢', 'ϯ'), ('â²€', 'â³³'), ('â³¹', '⳿')]; + +pub const CUNEIFORM: &'static [(char, char)] = + &[('ð’€€', 'ð’Ž™'), ('ð’€', 'ð’‘®'), ('ð’‘°', 'ð’‘´'), ('ð’’€', '𒕃')]; + +pub const CYPRIOT: &'static [(char, char)] = + &[('ð €', 'ð …'), ('ð ˆ', 'ð ˆ'), ('ð Š', 'ð µ'), ('ð ·', 'ð ¸'), ('ð ¼', 'ð ¼'), ('ð ¿', 'ð ¿')]; + +pub const CYPRO_MINOAN: &'static [(char, char)] = &[('ð’¾', 'ð’¿²')]; + +pub const CYRILLIC: &'static [(char, char)] = &[ + ('Ѐ', '\u{484}'), + ('\u{487}', 'Ô¯'), + ('á²€', 'ᲈ'), + ('á´«', 'á´«'), + ('ᵸ', 'ᵸ'), + ('\u{2de0}', '\u{2dff}'), + ('Ꙁ', '\u{a69f}'), + ('\u{fe2e}', '\u{fe2f}'), + ('𞀰', 'ðž­'), + ('\u{1e08f}', '\u{1e08f}'), +]; + +pub const DESERET: &'static [(char, char)] = &[('ð€', 'ð‘')]; + +pub const DEVANAGARI: &'static [(char, char)] = &[ + ('\u{900}', 'à¥'), + ('\u{955}', '\u{963}'), + ('०', 'ॿ'), + ('\u{a8e0}', '\u{a8ff}'), + ('𑬀', '𑬉'), +]; + +pub const DIVES_AKURU: &'static [(char, char)] = &[ + ('𑤀', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤵'), + ('𑤷', '𑤸'), + ('\u{1193b}', '𑥆'), + ('ð‘¥', 'ð‘¥™'), +]; + +pub const DOGRA: &'static [(char, char)] = &[('ð‘ €', 'ð‘ »')]; + +pub const DUPLOYAN: &'static [(char, char)] = + &[('ð›°€', '𛱪'), ('ð›±°', 'ð›±¼'), ('𛲀', '𛲈'), ('ð›²', '𛲙'), ('𛲜', '𛲟')]; + +pub const EGYPTIAN_HIEROGLYPHS: &'static [(char, char)] = + &[('ð“€€', '\u{13455}')]; + +pub const ELBASAN: &'static [(char, char)] = &[('ð”€', 'ð”§')]; + +pub const ELYMAIC: &'static [(char, char)] = &[('ð¿ ', 'ð¿¶')]; + +pub const ETHIOPIC: &'static [(char, char)] = &[ + ('ሀ', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹–'), + ('ዘ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'áš'), + ('\u{135d}', 'á¼'), + ('ᎀ', '᎙'), + ('ⶀ', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), +]; + +pub const GEORGIAN: &'static [(char, char)] = &[ + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ჺ'), + ('ჼ', 'ჿ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), +]; + +pub const GLAGOLITIC: &'static [(char, char)] = &[ + ('â°€', 'ⱟ'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), +]; + +pub const GOTHIC: &'static [(char, char)] = &[('ðŒ°', 'ðŠ')]; + +pub const GRANTHA: &'static [(char, char)] = &[ + ('\u{11300}', '𑌃'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('\u{1133c}', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘'), + ('ð‘', 'ð‘'), + ('\u{11357}', '\u{11357}'), + ('ð‘', 'ð‘£'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), +]; + +pub const GREEK: &'static [(char, char)] = &[ + ('Í°', 'ͳ'), + ('͵', 'Í·'), + ('ͺ', 'ͽ'), + ('Í¿', 'Í¿'), + ('΄', '΄'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'Ï¡'), + ('Ï°', 'Ï¿'), + ('á´¦', 'á´ª'), + ('áµ', 'ᵡ'), + ('ᵦ', 'ᵪ'), + ('ᶿ', 'ᶿ'), + ('á¼€', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¿„'), + ('ῆ', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿', '`'), + ('ῲ', 'á¿´'), + ('ῶ', '῾'), + ('Ω', 'Ω'), + ('ê­¥', 'ê­¥'), + ('ð…€', 'ð†Ž'), + ('ð† ', 'ð† '), + ('ðˆ€', 'ð‰…'), +]; + +pub const GUJARATI: &'static [(char, char)] = &[ + ('\u{a81}', 'ઃ'), + ('અ', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('\u{abc}', '\u{ac5}'), + ('\u{ac7}', 'ૉ'), + ('à«‹', '\u{acd}'), + ('à«', 'à«'), + ('à« ', '\u{ae3}'), + ('૦', '૱'), + ('ૹ', '\u{aff}'), +]; + +pub const GUNJALA_GONDI: &'static [(char, char)] = &[ + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶎'), + ('\u{11d90}', '\u{11d91}'), + ('𑶓', '𑶘'), + ('𑶠', '𑶩'), +]; + +pub const GURMUKHI: &'static [(char, char)] = &[ + ('\u{a01}', 'ਃ'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('\u{a3c}', '\u{a3c}'), + ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('੦', '੶'), +]; + +pub const HAN: &'static [(char, char)] = &[ + ('⺀', '⺙'), + ('⺛', '⻳'), + ('â¼€', 'â¿•'), + ('々', '々'), + ('〇', '〇'), + ('〡', '〩'), + ('〸', '〻'), + ('ã€', '䶿'), + ('一', 'é¿¿'), + ('豈', 'ï©­'), + ('ï©°', 'ï«™'), + ('ð–¿¢', 'ð–¿£'), + ('ð–¿°', 'ð–¿±'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('丽', 'ð¯¨'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), +]; + +pub const HANGUL: &'static [(char, char)] = &[ + ('á„€', 'ᇿ'), + ('\u{302e}', '\u{302f}'), + ('ㄱ', 'ㆎ'), + ('㈀', '㈞'), + ('㉠', '㉾'), + ('ꥠ', 'ꥼ'), + ('ê°€', '힣'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('ï¾ ', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), +]; + +pub const HANIFI_ROHINGYA: &'static [(char, char)] = + &[('ð´€', '\u{10d27}'), ('ð´°', 'ð´¹')]; + +pub const HANUNOO: &'static [(char, char)] = &[('ᜠ', '᜴')]; + +pub const HATRAN: &'static [(char, char)] = + &[('ð£ ', 'ð£²'), ('ð£´', 'ð£µ'), ('ð£»', 'ð£¿')]; + +pub const HEBREW: &'static [(char, char)] = &[ + ('\u{591}', '\u{5c7}'), + ('×', 'ת'), + ('ׯ', '×´'), + ('ï¬', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', 'ï­'), +]; + +pub const HIRAGANA: &'static [(char, char)] = &[ + ('ã', 'ã‚–'), + ('ã‚', 'ã‚Ÿ'), + ('ð›€', '𛄟'), + ('𛄲', '𛄲'), + ('ð›…', 'ð›…’'), + ('🈀', '🈀'), +]; + +pub const IMPERIAL_ARAMAIC: &'static [(char, char)] = + &[('ð¡€', 'ð¡•'), ('ð¡—', 'ð¡Ÿ')]; + +pub const INHERITED: &'static [(char, char)] = &[ + ('\u{300}', '\u{36f}'), + ('\u{485}', '\u{486}'), + ('\u{64b}', '\u{655}'), + ('\u{670}', '\u{670}'), + ('\u{951}', '\u{954}'), + ('\u{1ab0}', '\u{1ace}'), + ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', '\u{1ce0}'), + ('\u{1ce2}', '\u{1ce8}'), + ('\u{1ced}', '\u{1ced}'), + ('\u{1cf4}', '\u{1cf4}'), + ('\u{1cf8}', '\u{1cf9}'), + ('\u{1dc0}', '\u{1dff}'), + ('\u{200c}', '\u{200d}'), + ('\u{20d0}', '\u{20f0}'), + ('\u{302a}', '\u{302d}'), + ('\u{3099}', '\u{309a}'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{fe20}', '\u{fe2d}'), + ('\u{101fd}', '\u{101fd}'), + ('\u{102e0}', '\u{102e0}'), + ('\u{1133b}', '\u{1133b}'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('\u{1d167}', '\u{1d169}'), + ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const INSCRIPTIONAL_PAHLAVI: &'static [(char, char)] = + &[('ð­ ', 'ð­²'), ('ð­¸', 'ð­¿')]; + +pub const INSCRIPTIONAL_PARTHIAN: &'static [(char, char)] = + &[('ð­€', 'ð­•'), ('ð­˜', 'ð­Ÿ')]; + +pub const JAVANESE: &'static [(char, char)] = + &[('\u{a980}', 'ê§'), ('ê§', '꧙'), ('꧞', '꧟')]; + +pub const KAITHI: &'static [(char, char)] = + &[('\u{11080}', '\u{110c2}'), ('\u{110cd}', '\u{110cd}')]; + +pub const KANNADA: &'static [(char, char)] = &[ + ('ಀ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('\u{cbc}', 'ೄ'), + ('\u{cc6}', 'ೈ'), + ('ೊ', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), + ('à³', 'ೞ'), + ('à³ ', '\u{ce3}'), + ('೦', '೯'), + ('à³±', 'à³³'), +]; + +pub const KATAKANA: &'static [(char, char)] = &[ + ('ã‚¡', 'ヺ'), + ('ヽ', 'ヿ'), + ('ㇰ', 'ㇿ'), + ('ã‹', '㋾'), + ('㌀', 'ã—'), + ('ヲ', 'ッ'), + ('ï½±', 'ï¾'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𛀀', '𛀀'), + ('𛄠', '𛄢'), + ('ð›…•', 'ð›…•'), + ('ð›…¤', 'ð›…§'), +]; + +pub const KAWI: &'static [(char, char)] = + &[('\u{11f00}', 'ð‘¼'), ('𑼒', '\u{11f3a}'), ('𑼾', '𑽙')]; + +pub const KAYAH_LI: &'static [(char, char)] = &[('꤀', '\u{a92d}'), ('꤯', '꤯')]; + +pub const KHAROSHTHI: &'static [(char, char)] = &[ + ('ð¨€', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨µ'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', 'ð©ˆ'), + ('ð©', 'ð©˜'), +]; + +pub const KHITAN_SMALL_SCRIPT: &'static [(char, char)] = + &[('\u{16fe4}', '\u{16fe4}'), ('𘬀', '𘳕')]; + +pub const KHMER: &'static [(char, char)] = + &[('ក', '\u{17dd}'), ('០', '៩'), ('៰', '៹'), ('᧠', '᧿')]; + +pub const KHOJKI: &'static [(char, char)] = &[('𑈀', '𑈑'), ('𑈓', '\u{11241}')]; + +pub const KHUDAWADI: &'static [(char, char)] = + &[('ð‘Š°', '\u{112ea}'), ('ð‘‹°', 'ð‘‹¹')]; + +pub const LAO: &'static [(char, char)] = &[ + ('àº', 'ຂ'), + ('ຄ', 'ຄ'), + ('ຆ', 'ຊ'), + ('ຌ', 'ຣ'), + ('ລ', 'ລ'), + ('ວ', 'ຽ'), + ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), + ('\u{ec8}', '\u{ece}'), + ('à»', 'à»™'), + ('ໜ', 'ໟ'), +]; + +pub const LATIN: &'static [(char, char)] = &[ + ('A', 'Z'), + ('a', 'z'), + ('ª', 'ª'), + ('º', 'º'), + ('À', 'Ö'), + ('Ø', 'ö'), + ('ø', 'ʸ'), + ('Ë ', 'ˤ'), + ('á´€', 'á´¥'), + ('á´¬', 'ᵜ'), + ('áµ¢', 'áµ¥'), + ('ᵫ', 'áµ·'), + ('áµ¹', 'ᶾ'), + ('Ḁ', 'ỿ'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('K', 'â„«'), + ('Ⅎ', 'Ⅎ'), + ('â…Ž', 'â…Ž'), + ('â… ', 'ↈ'), + ('â± ', 'Ɀ'), + ('Ꜣ', 'ꞇ'), + ('êž‹', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('ꟲ', 'ꟿ'), + ('ꬰ', 'ê­š'), + ('ê­œ', 'ê­¤'), + ('ê­¦', 'ê­©'), + ('ff', 'st'), + ('A', 'Z'), + ('ï½', 'z'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð¼€', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), +]; + +pub const LEPCHA: &'static [(char, char)] = + &[('á°€', '\u{1c37}'), ('á°»', '᱉'), ('á±', 'á±')]; + +pub const LIMBU: &'static [(char, char)] = &[ + ('ᤀ', 'ᤞ'), + ('\u{1920}', 'ᤫ'), + ('ᤰ', '\u{193b}'), + ('᥀', '᥀'), + ('᥄', 'á¥'), +]; + +pub const LINEAR_A: &'static [(char, char)] = + &[('ð˜€', 'ðœ¶'), ('ð€', 'ð•'), ('ð ', 'ð§')]; + +pub const LINEAR_B: &'static [(char, char)] = &[ + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), +]; + +pub const LISU: &'static [(char, char)] = &[('ê“', 'ê“¿'), ('𑾰', '𑾰')]; + +pub const LYCIAN: &'static [(char, char)] = &[('ðŠ€', 'ðŠœ')]; + +pub const LYDIAN: &'static [(char, char)] = &[('ð¤ ', 'ð¤¹'), ('ð¤¿', 'ð¤¿')]; + +pub const MAHAJANI: &'static [(char, char)] = &[('ð‘…', 'ð‘…¶')]; + +pub const MAKASAR: &'static [(char, char)] = &[('ð‘» ', '𑻸')]; + +pub const MALAYALAM: &'static [(char, char)] = &[ + ('\u{d00}', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', '\u{d44}'), + ('െ', 'ൈ'), + ('ൊ', 'àµ'), + ('ൔ', '\u{d63}'), + ('൦', 'ൿ'), +]; + +pub const MANDAIC: &'static [(char, char)] = &[('à¡€', '\u{85b}'), ('à¡ž', 'à¡ž')]; + +pub const MANICHAEAN: &'static [(char, char)] = + &[('ð«€', '\u{10ae6}'), ('ð««', 'ð«¶')]; + +pub const MARCHEN: &'static [(char, char)] = + &[('𑱰', 'ð‘²'), ('\u{11c92}', '\u{11ca7}'), ('𑲩', '\u{11cb6}')]; + +pub const MASARAM_GONDI: &'static [(char, char)] = &[ + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d47}'), + ('ð‘µ', '𑵙'), +]; + +pub const MEDEFAIDRIN: &'static [(char, char)] = &[('ð–¹€', '𖺚')]; + +pub const MEETEI_MAYEK: &'static [(char, char)] = + &[('ê« ', '\u{aaf6}'), ('ꯀ', '\u{abed}'), ('꯰', '꯹')]; + +pub const MENDE_KIKAKUI: &'static [(char, char)] = + &[('ðž €', '𞣄'), ('𞣇', '\u{1e8d6}')]; + +pub const MEROITIC_CURSIVE: &'static [(char, char)] = + &[('ð¦ ', 'ð¦·'), ('ð¦¼', 'ð§'), ('ð§’', 'ð§¿')]; + +pub const MEROITIC_HIEROGLYPHS: &'static [(char, char)] = &[('ð¦€', 'ð¦Ÿ')]; + +pub const MIAO: &'static [(char, char)] = + &[('ð–¼€', '𖽊'), ('\u{16f4f}', '𖾇'), ('\u{16f8f}', '𖾟')]; + +pub const MODI: &'static [(char, char)] = &[('𑘀', 'ð‘™„'), ('ð‘™', 'ð‘™™')]; + +pub const MONGOLIAN: &'static [(char, char)] = + &[('á €', 'á '), ('á „', 'á „'), ('á †', 'á ™'), ('á  ', 'ᡸ'), ('ᢀ', 'ᢪ'), ('ð‘™ ', '𑙬')]; + +pub const MRO: &'static [(char, char)] = &[('ð–©€', 'ð–©ž'), ('ð–© ', 'ð–©©'), ('ð–©®', '𖩯')]; + +pub const MULTANI: &'static [(char, char)] = + &[('ð‘Š€', '𑊆'), ('𑊈', '𑊈'), ('ð‘ŠŠ', 'ð‘Š'), ('ð‘Š', 'ð‘Š'), ('ð‘ŠŸ', 'ð‘Š©')]; + +pub const MYANMAR: &'static [(char, char)] = + &[('က', 'á‚Ÿ'), ('ꧠ', 'ꧾ'), ('ê© ', 'ê©¿')]; + +pub const NABATAEAN: &'static [(char, char)] = &[('ð¢€', 'ð¢ž'), ('ð¢§', 'ð¢¯')]; + +pub const NAG_MUNDARI: &'static [(char, char)] = &[('ðž“', '𞓹')]; + +pub const NANDINAGARI: &'static [(char, char)] = + &[('𑦠', '𑦧'), ('𑦪', '\u{119d7}'), ('\u{119da}', '𑧤')]; + +pub const NEW_TAI_LUE: &'static [(char, char)] = + &[('ᦀ', 'ᦫ'), ('ᦰ', 'ᧉ'), ('á§', '᧚'), ('᧞', '᧟')]; + +pub const NEWA: &'static [(char, char)] = &[('ð‘€', 'ð‘‘›'), ('ð‘‘', 'ð‘‘¡')]; + +pub const NKO: &'static [(char, char)] = &[('߀', 'ߺ'), ('\u{7fd}', 'ß¿')]; + +pub const NUSHU: &'static [(char, char)] = &[('ð–¿¡', 'ð–¿¡'), ('ð›…°', '𛋻')]; + +pub const NYIAKENG_PUACHUE_HMONG: &'static [(char, char)] = + &[('ðž„€', '𞄬'), ('\u{1e130}', '𞄽'), ('ðž…€', 'ðž…‰'), ('ðž…Ž', 'ðž…')]; + +pub const OGHAM: &'static [(char, char)] = &[('\u{1680}', 'ášœ')]; + +pub const OL_CHIKI: &'static [(char, char)] = &[('á±', '᱿')]; + +pub const OLD_HUNGARIAN: &'static [(char, char)] = + &[('ð²€', 'ð²²'), ('ð³€', 'ð³²'), ('ð³º', 'ð³¿')]; + +pub const OLD_ITALIC: &'static [(char, char)] = &[('ðŒ€', 'ðŒ£'), ('ðŒ­', 'ðŒ¯')]; + +pub const OLD_NORTH_ARABIAN: &'static [(char, char)] = &[('ðª€', 'ðªŸ')]; + +pub const OLD_PERMIC: &'static [(char, char)] = &[('ð', '\u{1037a}')]; + +pub const OLD_PERSIAN: &'static [(char, char)] = &[('ðŽ ', 'ðƒ'), ('ðˆ', 'ð•')]; + +pub const OLD_SOGDIAN: &'static [(char, char)] = &[('ð¼€', 'ð¼§')]; + +pub const OLD_SOUTH_ARABIAN: &'static [(char, char)] = &[('ð© ', 'ð©¿')]; + +pub const OLD_TURKIC: &'static [(char, char)] = &[('ð°€', 'ð±ˆ')]; + +pub const OLD_UYGHUR: &'static [(char, char)] = &[('ð½°', 'ð¾‰')]; + +pub const ORIYA: &'static [(char, char)] = &[ + ('\u{b01}', 'ଃ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), + ('\u{b3c}', '\u{b44}'), + ('à­‡', 'à­ˆ'), + ('à­‹', '\u{b4d}'), + ('\u{b55}', '\u{b57}'), + ('à­œ', 'à­'), + ('à­Ÿ', '\u{b63}'), + ('à­¦', 'à­·'), +]; + +pub const OSAGE: &'static [(char, char)] = &[('ð’°', 'ð““'), ('ð“˜', 'ð“»')]; + +pub const OSMANYA: &'static [(char, char)] = &[('ð’€', 'ð’'), ('ð’ ', 'ð’©')]; + +pub const PAHAWH_HMONG: &'static [(char, char)] = + &[('𖬀', 'ð–­…'), ('ð–­', 'ð–­™'), ('ð–­›', 'ð–­¡'), ('ð–­£', 'ð–­·'), ('ð–­½', 'ð–®')]; + +pub const PALMYRENE: &'static [(char, char)] = &[('ð¡ ', 'ð¡¿')]; + +pub const PAU_CIN_HAU: &'static [(char, char)] = &[('ð‘«€', '𑫸')]; + +pub const PHAGS_PA: &'static [(char, char)] = &[('ê¡€', 'ê¡·')]; + +pub const PHOENICIAN: &'static [(char, char)] = &[('ð¤€', 'ð¤›'), ('ð¤Ÿ', 'ð¤Ÿ')]; + +pub const PSALTER_PAHLAVI: &'static [(char, char)] = + &[('ð®€', 'ð®‘'), ('ð®™', 'ð®œ'), ('ð®©', 'ð®¯')]; + +pub const REJANG: &'static [(char, char)] = &[('ꤰ', '꥓'), ('꥟', '꥟')]; + +pub const RUNIC: &'static [(char, char)] = &[('áš ', 'ᛪ'), ('á›®', 'ᛸ')]; + +pub const SAMARITAN: &'static [(char, char)] = &[('à €', '\u{82d}'), ('à °', 'à ¾')]; + +pub const SAURASHTRA: &'static [(char, char)] = + &[('ꢀ', '\u{a8c5}'), ('꣎', '꣙')]; + +pub const SHARADA: &'static [(char, char)] = &[('\u{11180}', '𑇟')]; + +pub const SHAVIAN: &'static [(char, char)] = &[('ð‘', 'ð‘¿')]; + +pub const SIDDHAM: &'static [(char, char)] = + &[('ð‘–€', '\u{115b5}'), ('ð‘–¸', '\u{115dd}')]; + +pub const SIGNWRITING: &'static [(char, char)] = + &[('ð €', 'ðª‹'), ('\u{1da9b}', '\u{1da9f}'), ('\u{1daa1}', '\u{1daaf}')]; + +pub const SINHALA: &'static [(char, char)] = &[ + ('\u{d81}', 'ඃ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('à·˜', '\u{ddf}'), + ('à·¦', 'à·¯'), + ('à·²', 'à·´'), + ('𑇡', '𑇴'), +]; + +pub const SOGDIAN: &'static [(char, char)] = &[('ð¼°', 'ð½™')]; + +pub const SORA_SOMPENG: &'static [(char, char)] = &[('ð‘ƒ', '𑃨'), ('𑃰', '𑃹')]; + +pub const SOYOMBO: &'static [(char, char)] = &[('ð‘©', '𑪢')]; + +pub const SUNDANESE: &'static [(char, char)] = + &[('\u{1b80}', 'ᮿ'), ('á³€', '᳇')]; + +pub const SYLOTI_NAGRI: &'static [(char, char)] = &[('ê €', '\u{a82c}')]; + +pub const SYRIAC: &'static [(char, char)] = + &[('Ü€', 'Ü'), ('\u{70f}', '\u{74a}'), ('Ý', 'Ý'), ('à¡ ', 'ࡪ')]; + +pub const TAGALOG: &'static [(char, char)] = &[('ᜀ', '᜕'), ('ᜟ', 'ᜟ')]; + +pub const TAGBANWA: &'static [(char, char)] = + &[('á ', 'á¬'), ('á®', 'á°'), ('\u{1772}', '\u{1773}')]; + +pub const TAI_LE: &'static [(char, char)] = &[('á¥', 'ᥭ'), ('ᥰ', 'ᥴ')]; + +pub const TAI_THAM: &'static [(char, char)] = &[ + ('ᨠ', '\u{1a5e}'), + ('\u{1a60}', '\u{1a7c}'), + ('\u{1a7f}', '᪉'), + ('áª', '᪙'), + ('᪠', '᪭'), +]; + +pub const TAI_VIET: &'static [(char, char)] = &[('ꪀ', 'ê«‚'), ('ê«›', 'ê«Ÿ')]; + +pub const TAKRI: &'static [(char, char)] = &[('𑚀', 'ð‘š¹'), ('𑛀', '𑛉')]; + +pub const TAMIL: &'static [(char, char)] = &[ + ('\u{b82}', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'ஹ'), + ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), + ('ொ', '\u{bcd}'), + ('à¯', 'à¯'), + ('\u{bd7}', '\u{bd7}'), + ('௦', '௺'), + ('ð‘¿€', 'ð‘¿±'), + ('ð‘¿¿', 'ð‘¿¿'), +]; + +pub const TANGSA: &'static [(char, char)] = &[('ð–©°', '𖪾'), ('ð–«€', '𖫉')]; + +pub const TANGUT: &'static [(char, char)] = + &[('ð–¿ ', 'ð–¿ '), ('ð—€€', '𘟷'), ('𘠀', '𘫿'), ('𘴀', '𘴈')]; + +pub const TELUGU: &'static [(char, char)] = &[ + ('\u{c00}', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°¹'), + ('\u{c3c}', 'ౄ'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('ౘ', 'ౚ'), + ('à±', 'à±'), + ('à± ', '\u{c63}'), + ('౦', '౯'), + ('à±·', '౿'), +]; + +pub const THAANA: &'static [(char, char)] = &[('Þ€', 'Þ±')]; + +pub const THAI: &'static [(char, char)] = &[('à¸', '\u{e3a}'), ('เ', '๛')]; + +pub const TIBETAN: &'static [(char, char)] = &[ + ('ༀ', 'ཇ'), + ('ཉ', 'ཬ'), + ('\u{f71}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('྾', 'à¿Œ'), + ('à¿Ž', 'à¿”'), + ('à¿™', 'à¿š'), +]; + +pub const TIFINAGH: &'static [(char, char)] = + &[('â´°', 'ⵧ'), ('ⵯ', 'âµ°'), ('\u{2d7f}', '\u{2d7f}')]; + +pub const TIRHUTA: &'static [(char, char)] = &[('ð‘’€', '𑓇'), ('ð‘“', 'ð‘“™')]; + +pub const TOTO: &'static [(char, char)] = &[('ðžŠ', '\u{1e2ae}')]; + +pub const UGARITIC: &'static [(char, char)] = &[('ðŽ€', 'ðŽ'), ('ðŽŸ', 'ðŽŸ')]; + +pub const VAI: &'static [(char, char)] = &[('ꔀ', 'ꘫ')]; + +pub const VITHKUQI: &'static [(char, char)] = &[ + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), +]; + +pub const WANCHO: &'static [(char, char)] = &[('ðž‹€', '𞋹'), ('ðž‹¿', 'ðž‹¿')]; + +pub const WARANG_CITI: &'static [(char, char)] = &[('ð‘¢ ', 'ð‘£²'), ('𑣿', '𑣿')]; + +pub const YEZIDI: &'static [(char, char)] = + &[('ðº€', 'ðº©'), ('\u{10eab}', 'ðº­'), ('ðº°', 'ðº±')]; + +pub const YI: &'static [(char, char)] = &[('ꀀ', 'ê’Œ'), ('ê’', '꓆')]; + +pub const ZANABAZAR_SQUARE: &'static [(char, char)] = &[('𑨀', '\u{11a47}')]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/script_extension.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/script_extension.rs new file mode 100644 index 0000000000000..42625e21b9e7c --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/script_extension.rs @@ -0,0 +1,1457 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate script-extension ucd-15.0.0 --chars +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("Adlam", ADLAM), + ("Ahom", AHOM), + ("Anatolian_Hieroglyphs", ANATOLIAN_HIEROGLYPHS), + ("Arabic", ARABIC), + ("Armenian", ARMENIAN), + ("Avestan", AVESTAN), + ("Balinese", BALINESE), + ("Bamum", BAMUM), + ("Bassa_Vah", BASSA_VAH), + ("Batak", BATAK), + ("Bengali", BENGALI), + ("Bhaiksuki", BHAIKSUKI), + ("Bopomofo", BOPOMOFO), + ("Brahmi", BRAHMI), + ("Braille", BRAILLE), + ("Buginese", BUGINESE), + ("Buhid", BUHID), + ("Canadian_Aboriginal", CANADIAN_ABORIGINAL), + ("Carian", CARIAN), + ("Caucasian_Albanian", CAUCASIAN_ALBANIAN), + ("Chakma", CHAKMA), + ("Cham", CHAM), + ("Cherokee", CHEROKEE), + ("Chorasmian", CHORASMIAN), + ("Common", COMMON), + ("Coptic", COPTIC), + ("Cuneiform", CUNEIFORM), + ("Cypriot", CYPRIOT), + ("Cypro_Minoan", CYPRO_MINOAN), + ("Cyrillic", CYRILLIC), + ("Deseret", DESERET), + ("Devanagari", DEVANAGARI), + ("Dives_Akuru", DIVES_AKURU), + ("Dogra", DOGRA), + ("Duployan", DUPLOYAN), + ("Egyptian_Hieroglyphs", EGYPTIAN_HIEROGLYPHS), + ("Elbasan", ELBASAN), + ("Elymaic", ELYMAIC), + ("Ethiopic", ETHIOPIC), + ("Georgian", GEORGIAN), + ("Glagolitic", GLAGOLITIC), + ("Gothic", GOTHIC), + ("Grantha", GRANTHA), + ("Greek", GREEK), + ("Gujarati", GUJARATI), + ("Gunjala_Gondi", GUNJALA_GONDI), + ("Gurmukhi", GURMUKHI), + ("Han", HAN), + ("Hangul", HANGUL), + ("Hanifi_Rohingya", HANIFI_ROHINGYA), + ("Hanunoo", HANUNOO), + ("Hatran", HATRAN), + ("Hebrew", HEBREW), + ("Hiragana", HIRAGANA), + ("Imperial_Aramaic", IMPERIAL_ARAMAIC), + ("Inherited", INHERITED), + ("Inscriptional_Pahlavi", INSCRIPTIONAL_PAHLAVI), + ("Inscriptional_Parthian", INSCRIPTIONAL_PARTHIAN), + ("Javanese", JAVANESE), + ("Kaithi", KAITHI), + ("Kannada", KANNADA), + ("Katakana", KATAKANA), + ("Kawi", KAWI), + ("Kayah_Li", KAYAH_LI), + ("Kharoshthi", KHAROSHTHI), + ("Khitan_Small_Script", KHITAN_SMALL_SCRIPT), + ("Khmer", KHMER), + ("Khojki", KHOJKI), + ("Khudawadi", KHUDAWADI), + ("Lao", LAO), + ("Latin", LATIN), + ("Lepcha", LEPCHA), + ("Limbu", LIMBU), + ("Linear_A", LINEAR_A), + ("Linear_B", LINEAR_B), + ("Lisu", LISU), + ("Lycian", LYCIAN), + ("Lydian", LYDIAN), + ("Mahajani", MAHAJANI), + ("Makasar", MAKASAR), + ("Malayalam", MALAYALAM), + ("Mandaic", MANDAIC), + ("Manichaean", MANICHAEAN), + ("Marchen", MARCHEN), + ("Masaram_Gondi", MASARAM_GONDI), + ("Medefaidrin", MEDEFAIDRIN), + ("Meetei_Mayek", MEETEI_MAYEK), + ("Mende_Kikakui", MENDE_KIKAKUI), + ("Meroitic_Cursive", MEROITIC_CURSIVE), + ("Meroitic_Hieroglyphs", MEROITIC_HIEROGLYPHS), + ("Miao", MIAO), + ("Modi", MODI), + ("Mongolian", MONGOLIAN), + ("Mro", MRO), + ("Multani", MULTANI), + ("Myanmar", MYANMAR), + ("Nabataean", NABATAEAN), + ("Nag_Mundari", NAG_MUNDARI), + ("Nandinagari", NANDINAGARI), + ("New_Tai_Lue", NEW_TAI_LUE), + ("Newa", NEWA), + ("Nko", NKO), + ("Nushu", NUSHU), + ("Nyiakeng_Puachue_Hmong", NYIAKENG_PUACHUE_HMONG), + ("Ogham", OGHAM), + ("Ol_Chiki", OL_CHIKI), + ("Old_Hungarian", OLD_HUNGARIAN), + ("Old_Italic", OLD_ITALIC), + ("Old_North_Arabian", OLD_NORTH_ARABIAN), + ("Old_Permic", OLD_PERMIC), + ("Old_Persian", OLD_PERSIAN), + ("Old_Sogdian", OLD_SOGDIAN), + ("Old_South_Arabian", OLD_SOUTH_ARABIAN), + ("Old_Turkic", OLD_TURKIC), + ("Old_Uyghur", OLD_UYGHUR), + ("Oriya", ORIYA), + ("Osage", OSAGE), + ("Osmanya", OSMANYA), + ("Pahawh_Hmong", PAHAWH_HMONG), + ("Palmyrene", PALMYRENE), + ("Pau_Cin_Hau", PAU_CIN_HAU), + ("Phags_Pa", PHAGS_PA), + ("Phoenician", PHOENICIAN), + ("Psalter_Pahlavi", PSALTER_PAHLAVI), + ("Rejang", REJANG), + ("Runic", RUNIC), + ("Samaritan", SAMARITAN), + ("Saurashtra", SAURASHTRA), + ("Sharada", SHARADA), + ("Shavian", SHAVIAN), + ("Siddham", SIDDHAM), + ("SignWriting", SIGNWRITING), + ("Sinhala", SINHALA), + ("Sogdian", SOGDIAN), + ("Sora_Sompeng", SORA_SOMPENG), + ("Soyombo", SOYOMBO), + ("Sundanese", SUNDANESE), + ("Syloti_Nagri", SYLOTI_NAGRI), + ("Syriac", SYRIAC), + ("Tagalog", TAGALOG), + ("Tagbanwa", TAGBANWA), + ("Tai_Le", TAI_LE), + ("Tai_Tham", TAI_THAM), + ("Tai_Viet", TAI_VIET), + ("Takri", TAKRI), + ("Tamil", TAMIL), + ("Tangsa", TANGSA), + ("Tangut", TANGUT), + ("Telugu", TELUGU), + ("Thaana", THAANA), + ("Thai", THAI), + ("Tibetan", TIBETAN), + ("Tifinagh", TIFINAGH), + ("Tirhuta", TIRHUTA), + ("Toto", TOTO), + ("Ugaritic", UGARITIC), + ("Vai", VAI), + ("Vithkuqi", VITHKUQI), + ("Wancho", WANCHO), + ("Warang_Citi", WARANG_CITI), + ("Yezidi", YEZIDI), + ("Yi", YI), + ("Zanabazar_Square", ZANABAZAR_SQUARE), +]; + +pub const ADLAM: &'static [(char, char)] = + &[('ØŸ', 'ØŸ'), ('Ù€', 'Ù€'), ('𞤀', '𞥋'), ('ðž¥', '𞥙'), ('𞥞', '𞥟')]; + +pub const AHOM: &'static [(char, char)] = + &[('𑜀', '𑜚'), ('\u{1171d}', '\u{1172b}'), ('𑜰', 'ð‘†')]; + +pub const ANATOLIAN_HIEROGLYPHS: &'static [(char, char)] = &[('ð”€', '𔙆')]; + +pub const ARABIC: &'static [(char, char)] = &[ + ('\u{600}', '\u{604}'), + ('؆', '\u{6dc}'), + ('Ûž', 'Û¿'), + ('Ý', 'Ý¿'), + ('à¡°', 'ࢎ'), + ('\u{890}', '\u{891}'), + ('\u{898}', '\u{8e1}'), + ('\u{8e3}', '\u{8ff}'), + ('ï­', '﯂'), + ('ﯓ', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·', 'ï·'), + ('ï·°', 'ï·¿'), + ('ï¹°', 'ï¹´'), + ('ﹶ', 'ﻼ'), + ('\u{102e0}', 'ð‹»'), + ('ð¹ ', 'ð¹¾'), + ('\u{10efd}', '\u{10eff}'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('ðž»°', 'ðž»±'), +]; + +pub const ARMENIAN: &'static [(char, char)] = + &[('Ô±', 'Õ–'), ('Õ™', 'ÖŠ'), ('Ö', 'Ö'), ('ﬓ', 'ﬗ')]; + +pub const AVESTAN: &'static [(char, char)] = &[('ð¬€', 'ð¬µ'), ('ð¬¹', 'ð¬¿')]; + +pub const BALINESE: &'static [(char, char)] = &[('\u{1b00}', 'á­Œ'), ('á­', 'á­¾')]; + +pub const BAMUM: &'static [(char, char)] = &[('êš ', 'ê›·'), ('ð– €', '𖨸')]; + +pub const BASSA_VAH: &'static [(char, char)] = + &[('ð–«', 'ð–«­'), ('\u{16af0}', 'ð–«µ')]; + +pub const BATAK: &'static [(char, char)] = &[('ᯀ', '᯳'), ('᯼', '᯿')]; + +pub const BENGALI: &'static [(char, char)] = &[ + ('\u{951}', '\u{952}'), + ('।', '॥'), + ('ঀ', 'ঃ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('\u{9bc}', '\u{9c4}'), + ('ে', 'ৈ'), + ('ো', 'ৎ'), + ('\u{9d7}', '\u{9d7}'), + ('ড়', 'à§'), + ('য়', '\u{9e3}'), + ('০', '\u{9fe}'), + ('\u{1cd0}', '\u{1cd0}'), + ('\u{1cd2}', '\u{1cd2}'), + ('\u{1cd5}', '\u{1cd6}'), + ('\u{1cd8}', '\u{1cd8}'), + ('᳡', '᳡'), + ('ᳪ', 'ᳪ'), + ('\u{1ced}', '\u{1ced}'), + ('á³²', 'á³²'), + ('á³µ', 'á³·'), + ('\u{a8f1}', '\u{a8f1}'), +]; + +pub const BHAIKSUKI: &'static [(char, char)] = + &[('ð‘°€', 'ð‘°ˆ'), ('ð‘°Š', '\u{11c36}'), ('\u{11c38}', '𑱅'), ('ð‘±', '𑱬')]; + +pub const BOPOMOFO: &'static [(char, char)] = &[ + ('˪', 'Ë«'), + ('ã€', '〃'), + ('〈', '】'), + ('〓', '〟'), + ('\u{302a}', '\u{302d}'), + ('〰', '〰'), + ('〷', '〷'), + ('・', '・'), + ('ã„…', 'ㄯ'), + ('ㆠ', 'ㆿ'), + ('ï¹…', '﹆'), + ('。', 'ï½¥'), +]; + +pub const BRAHMI: &'static [(char, char)] = + &[('ð‘€€', 'ð‘'), ('ð‘’', 'ð‘µ'), ('\u{1107f}', '\u{1107f}')]; + +pub const BRAILLE: &'static [(char, char)] = &[('â €', '⣿')]; + +pub const BUGINESE: &'static [(char, char)] = + &[('ᨀ', '\u{1a1b}'), ('᨞', '᨟'), ('ê§', 'ê§')]; + +pub const BUHID: &'static [(char, char)] = &[('᜵', '᜶'), ('á€', '\u{1753}')]; + +pub const CANADIAN_ABORIGINAL: &'static [(char, char)] = + &[('á€', 'ᙿ'), ('ᢰ', 'ᣵ'), ('𑪰', '𑪿')]; + +pub const CARIAN: &'static [(char, char)] = &[('ðŠ ', 'ð‹')]; + +pub const CAUCASIAN_ALBANIAN: &'static [(char, char)] = + &[('ð”°', 'ð•£'), ('ð•¯', 'ð•¯')]; + +pub const CHAKMA: &'static [(char, char)] = + &[('০', '৯'), ('á€', 'á‰'), ('\u{11100}', '\u{11134}'), ('𑄶', 'ð‘…‡')]; + +pub const CHAM: &'static [(char, char)] = + &[('ꨀ', '\u{aa36}'), ('ê©€', 'ê©'), ('ê©', 'ê©™'), ('ê©œ', 'ê©Ÿ')]; + +pub const CHEROKEE: &'static [(char, char)] = + &[('Ꭰ', 'áµ'), ('á¸', 'á½'), ('ê­°', 'ꮿ')]; + +pub const CHORASMIAN: &'static [(char, char)] = &[('ð¾°', 'ð¿‹')]; + +pub const COMMON: &'static [(char, char)] = &[ + ('\0', '@'), + ('[', '`'), + ('{', '©'), + ('«', '¹'), + ('»', '¿'), + ('×', '×'), + ('÷', '÷'), + ('ʹ', 'ËŸ'), + ('Ë¥', 'Ë©'), + ('ˬ', 'Ë¿'), + ('Í´', 'Í´'), + (';', ';'), + ('Î…', 'Î…'), + ('·', '·'), + ('\u{605}', '\u{605}'), + ('\u{6dd}', '\u{6dd}'), + ('\u{8e2}', '\u{8e2}'), + ('฿', '฿'), + ('à¿•', '࿘'), + ('᛫', 'á›­'), + ('\u{2000}', '\u{200b}'), + ('\u{200e}', '\u{202e}'), + ('‰', '\u{2064}'), + ('\u{2066}', 'â°'), + ('â´', 'â¾'), + ('â‚€', 'â‚Ž'), + ('â‚ ', '⃀'), + ('â„€', 'â„¥'), + ('℧', 'â„©'), + ('ℬ', 'ℱ'), + ('ℳ', 'â…'), + ('â…', 'â…Ÿ'), + ('↉', '↋'), + ('â†', 'â¦'), + ('â‘€', 'â‘Š'), + ('â‘ ', '⟿'), + ('⤀', 'â­³'), + ('â­¶', '⮕'), + ('â®—', '⯿'), + ('⸀', '⹂'), + ('⹄', 'â¹'), + ('â¿°', 'â¿»'), + ('\u{3000}', '\u{3000}'), + ('〄', '〄'), + ('〒', '〒'), + ('〠', '〠'), + ('〶', '〶'), + ('㉈', '㉟'), + ('㉿', '㉿'), + ('㊱', '㊿'), + ('ã‹Œ', 'ã‹'), + ('ã±', 'ãº'), + ('㎀', 'ãŸ'), + ('ã¿', 'ã¿'), + ('ä·€', 'ä·¿'), + ('꜈', '꜡'), + ('ꞈ', '꞊'), + ('ê­›', 'ê­›'), + ('ê­ª', 'ê­«'), + ('ï¸', '︙'), + ('︰', '﹄'), + ('﹇', 'ï¹’'), + ('ï¹”', '﹦'), + ('﹨', '﹫'), + ('\u{feff}', '\u{feff}'), + ('ï¼', 'ï¼ '), + ('ï¼»', 'ï½€'), + ('ï½›', 'ï½ '), + ('ï¿ ', '₩'), + ('│', 'ï¿®'), + ('\u{fff9}', '�'), + ('ð†', 'ð†œ'), + ('ð‡', 'ð‡¼'), + ('ðœ½', '𜿃'), + ('ð€€', 'ðƒµ'), + ('ð„€', 'ð„¦'), + ('ð„©', 'ð…¦'), + ('ð…ª', '\u{1d17a}'), + ('ð†ƒ', 'ð†„'), + ('ð†Œ', 'ð†©'), + ('ð†®', 'ð‡ª'), + ('ð‹€', 'ð‹“'), + ('ð‹ ', 'ð‹³'), + ('ðŒ€', 'ð–'), + ('ð²', 'ð¸'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ðŸ‹'), + ('ðŸŽ', 'ðŸ¿'), + ('ðž±±', 'ðž²´'), + ('ðž´', 'ðž´½'), + ('🀀', '🀫'), + ('🀰', '🂓'), + ('🂠', '🂮'), + ('🂱', '🂿'), + ('ðŸƒ', 'ðŸƒ'), + ('🃑', '🃵'), + ('🄀', '🆭'), + ('🇦', '🇿'), + ('ðŸˆ', '🈂'), + ('ðŸˆ', '🈻'), + ('🉀', '🉈'), + ('🉠', '🉥'), + ('🌀', '🛗'), + ('🛜', '🛬'), + ('🛰', '🛼'), + ('🜀', 'ðŸ¶'), + ('ðŸ»', '🟙'), + ('🟠', '🟫'), + ('🟰', '🟰'), + ('🠀', '🠋'), + ('ðŸ ', '🡇'), + ('ðŸ¡', '🡙'), + ('🡠', '🢇'), + ('ðŸ¢', '🢭'), + ('🢰', '🢱'), + ('🤀', '🩓'), + ('🩠', '🩭'), + ('🩰', '🩼'), + ('🪀', '🪈'), + ('ðŸª', '🪽'), + ('🪿', '🫅'), + ('🫎', '🫛'), + ('🫠', '🫨'), + ('🫰', '🫸'), + ('🬀', '🮒'), + ('🮔', '🯊'), + ('🯰', '🯹'), + ('\u{e0001}', '\u{e0001}'), + ('\u{e0020}', '\u{e007f}'), +]; + +pub const COPTIC: &'static [(char, char)] = + &[('Ï¢', 'ϯ'), ('â²€', 'â³³'), ('â³¹', '⳿'), ('\u{102e0}', 'ð‹»')]; + +pub const CUNEIFORM: &'static [(char, char)] = + &[('ð’€€', 'ð’Ž™'), ('ð’€', 'ð’‘®'), ('ð’‘°', 'ð’‘´'), ('ð’’€', '𒕃')]; + +pub const CYPRIOT: &'static [(char, char)] = &[ + ('ð„€', 'ð„‚'), + ('ð„‡', 'ð„³'), + ('ð„·', 'ð„¿'), + ('ð €', 'ð …'), + ('ð ˆ', 'ð ˆ'), + ('ð Š', 'ð µ'), + ('ð ·', 'ð ¸'), + ('ð ¼', 'ð ¼'), + ('ð ¿', 'ð ¿'), +]; + +pub const CYPRO_MINOAN: &'static [(char, char)] = &[('ð„€', 'ð„'), ('ð’¾', 'ð’¿²')]; + +pub const CYRILLIC: &'static [(char, char)] = &[ + ('Ѐ', 'Ô¯'), + ('á²€', 'ᲈ'), + ('á´«', 'á´«'), + ('ᵸ', 'ᵸ'), + ('\u{1df8}', '\u{1df8}'), + ('\u{2de0}', '\u{2dff}'), + ('⹃', '⹃'), + ('Ꙁ', '\u{a69f}'), + ('\u{fe2e}', '\u{fe2f}'), + ('𞀰', 'ðž­'), + ('\u{1e08f}', '\u{1e08f}'), +]; + +pub const DESERET: &'static [(char, char)] = &[('ð€', 'ð‘')]; + +pub const DEVANAGARI: &'static [(char, char)] = &[ + ('\u{900}', '\u{952}'), + ('\u{955}', 'ॿ'), + ('\u{1cd0}', 'ᳶ'), + ('\u{1cf8}', '\u{1cf9}'), + ('\u{20f0}', '\u{20f0}'), + ('ê °', 'ê ¹'), + ('\u{a8e0}', '\u{a8ff}'), + ('𑬀', '𑬉'), +]; + +pub const DIVES_AKURU: &'static [(char, char)] = &[ + ('𑤀', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤵'), + ('𑤷', '𑤸'), + ('\u{1193b}', '𑥆'), + ('ð‘¥', 'ð‘¥™'), +]; + +pub const DOGRA: &'static [(char, char)] = + &[('।', '९'), ('ê °', 'ê ¹'), ('ð‘ €', 'ð‘ »')]; + +pub const DUPLOYAN: &'static [(char, char)] = + &[('ð›°€', '𛱪'), ('ð›±°', 'ð›±¼'), ('𛲀', '𛲈'), ('ð›²', '𛲙'), ('𛲜', '\u{1bca3}')]; + +pub const EGYPTIAN_HIEROGLYPHS: &'static [(char, char)] = + &[('ð“€€', '\u{13455}')]; + +pub const ELBASAN: &'static [(char, char)] = &[('ð”€', 'ð”§')]; + +pub const ELYMAIC: &'static [(char, char)] = &[('ð¿ ', 'ð¿¶')]; + +pub const ETHIOPIC: &'static [(char, char)] = &[ + ('ሀ', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹–'), + ('ዘ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'áš'), + ('\u{135d}', 'á¼'), + ('ᎀ', '᎙'), + ('ⶀ', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), +]; + +pub const GEORGIAN: &'static [(char, char)] = &[ + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ჿ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), +]; + +pub const GLAGOLITIC: &'static [(char, char)] = &[ + ('\u{484}', '\u{484}'), + ('\u{487}', '\u{487}'), + ('â°€', 'ⱟ'), + ('⹃', '⹃'), + ('\u{a66f}', '\u{a66f}'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), +]; + +pub const GOTHIC: &'static [(char, char)] = &[('ðŒ°', 'ðŠ')]; + +pub const GRANTHA: &'static [(char, char)] = &[ + ('\u{951}', '\u{952}'), + ('।', '॥'), + ('௦', '௳'), + ('\u{1cd0}', '\u{1cd0}'), + ('\u{1cd2}', '᳓'), + ('á³²', '\u{1cf4}'), + ('\u{1cf8}', '\u{1cf9}'), + ('\u{20f0}', '\u{20f0}'), + ('\u{11300}', '𑌃'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('\u{1133b}', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘'), + ('ð‘', 'ð‘'), + ('\u{11357}', '\u{11357}'), + ('ð‘', 'ð‘£'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('ð‘¿', 'ð‘¿‘'), + ('ð‘¿“', 'ð‘¿“'), +]; + +pub const GREEK: &'static [(char, char)] = &[ + ('\u{342}', '\u{342}'), + ('\u{345}', '\u{345}'), + ('Í°', 'ͳ'), + ('͵', 'Í·'), + ('ͺ', 'ͽ'), + ('Í¿', 'Í¿'), + ('΄', '΄'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'Ï¡'), + ('Ï°', 'Ï¿'), + ('á´¦', 'á´ª'), + ('áµ', 'ᵡ'), + ('ᵦ', 'ᵪ'), + ('ᶿ', '\u{1dc1}'), + ('á¼€', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¿„'), + ('ῆ', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿', '`'), + ('ῲ', 'á¿´'), + ('ῶ', '῾'), + ('Ω', 'Ω'), + ('ê­¥', 'ê­¥'), + ('ð…€', 'ð†Ž'), + ('ð† ', 'ð† '), + ('ðˆ€', 'ð‰…'), +]; + +pub const GUJARATI: &'static [(char, char)] = &[ + ('\u{951}', '\u{952}'), + ('।', '॥'), + ('\u{a81}', 'ઃ'), + ('અ', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('\u{abc}', '\u{ac5}'), + ('\u{ac7}', 'ૉ'), + ('à«‹', '\u{acd}'), + ('à«', 'à«'), + ('à« ', '\u{ae3}'), + ('૦', '૱'), + ('ૹ', '\u{aff}'), + ('ê °', 'ê ¹'), +]; + +pub const GUNJALA_GONDI: &'static [(char, char)] = &[ + ('।', '॥'), + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶎'), + ('\u{11d90}', '\u{11d91}'), + ('𑶓', '𑶘'), + ('𑶠', '𑶩'), +]; + +pub const GURMUKHI: &'static [(char, char)] = &[ + ('\u{951}', '\u{952}'), + ('।', '॥'), + ('\u{a01}', 'ਃ'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('\u{a3c}', '\u{a3c}'), + ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('੦', '੶'), + ('ê °', 'ê ¹'), +]; + +pub const HAN: &'static [(char, char)] = &[ + ('⺀', '⺙'), + ('⺛', '⻳'), + ('â¼€', 'â¿•'), + ('ã€', '〃'), + ('々', '】'), + ('〓', '〟'), + ('〡', '\u{302d}'), + ('〰', '〰'), + ('〷', '〿'), + ('・', '・'), + ('ã†', '㆟'), + ('㇀', '㇣'), + ('㈠', '㉇'), + ('㊀', '㊰'), + ('ã‹€', 'ã‹‹'), + ('ã‹¿', 'ã‹¿'), + ('ã˜', 'ã°'), + ('ã»', 'ã¿'), + ('ã ', 'ã¾'), + ('ã€', '䶿'), + ('一', 'é¿¿'), + ('꜀', '꜇'), + ('豈', 'ï©­'), + ('ï©°', 'ï«™'), + ('ï¹…', '﹆'), + ('。', 'ï½¥'), + ('ð–¿¢', 'ð–¿£'), + ('ð–¿°', 'ð–¿±'), + ('ð ', 'ð±'), + ('ðŸ‰', '🉑'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('丽', 'ð¯¨'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), +]; + +pub const HANGUL: &'static [(char, char)] = &[ + ('á„€', 'ᇿ'), + ('ã€', '〃'), + ('〈', '】'), + ('〓', '〟'), + ('\u{302e}', '〰'), + ('〷', '〷'), + ('・', '・'), + ('ㄱ', 'ㆎ'), + ('㈀', '㈞'), + ('㉠', '㉾'), + ('ꥠ', 'ꥼ'), + ('ê°€', '힣'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('ï¹…', '﹆'), + ('。', 'ï½¥'), + ('ï¾ ', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), +]; + +pub const HANIFI_ROHINGYA: &'static [(char, char)] = &[ + ('ØŒ', 'ØŒ'), + ('Ø›', 'Ø›'), + ('ØŸ', 'ØŸ'), + ('Ù€', 'Ù€'), + ('Û”', 'Û”'), + ('ð´€', '\u{10d27}'), + ('ð´°', 'ð´¹'), +]; + +pub const HANUNOO: &'static [(char, char)] = &[('ᜠ', '᜶')]; + +pub const HATRAN: &'static [(char, char)] = + &[('ð£ ', 'ð£²'), ('ð£´', 'ð£µ'), ('ð£»', 'ð£¿')]; + +pub const HEBREW: &'static [(char, char)] = &[ + ('\u{591}', '\u{5c7}'), + ('×', 'ת'), + ('ׯ', '×´'), + ('ï¬', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', 'ï­'), +]; + +pub const HIRAGANA: &'static [(char, char)] = &[ + ('ã€', '〃'), + ('〈', '】'), + ('〓', '〟'), + ('〰', '〵'), + ('〷', '〷'), + ('〼', '〽'), + ('ã', 'ã‚–'), + ('\u{3099}', 'ã‚ '), + ('・', 'ー'), + ('ï¹…', '﹆'), + ('。', 'ï½¥'), + ('ï½°', 'ï½°'), + ('\u{ff9e}', '\u{ff9f}'), + ('ð›€', '𛄟'), + ('𛄲', '𛄲'), + ('ð›…', 'ð›…’'), + ('🈀', '🈀'), +]; + +pub const IMPERIAL_ARAMAIC: &'static [(char, char)] = + &[('ð¡€', 'ð¡•'), ('ð¡—', 'ð¡Ÿ')]; + +pub const INHERITED: &'static [(char, char)] = &[ + ('\u{300}', '\u{341}'), + ('\u{343}', '\u{344}'), + ('\u{346}', '\u{362}'), + ('\u{953}', '\u{954}'), + ('\u{1ab0}', '\u{1ace}'), + ('\u{1dc2}', '\u{1df7}'), + ('\u{1df9}', '\u{1df9}'), + ('\u{1dfb}', '\u{1dff}'), + ('\u{200c}', '\u{200d}'), + ('\u{20d0}', '\u{20ef}'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{fe20}', '\u{fe2d}'), + ('\u{101fd}', '\u{101fd}'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('\u{1d167}', '\u{1d169}'), + ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const INSCRIPTIONAL_PAHLAVI: &'static [(char, char)] = + &[('ð­ ', 'ð­²'), ('ð­¸', 'ð­¿')]; + +pub const INSCRIPTIONAL_PARTHIAN: &'static [(char, char)] = + &[('ð­€', 'ð­•'), ('ð­˜', 'ð­Ÿ')]; + +pub const JAVANESE: &'static [(char, char)] = + &[('\u{a980}', 'ê§'), ('ê§', '꧙'), ('꧞', '꧟')]; + +pub const KAITHI: &'static [(char, char)] = &[ + ('०', '९'), + ('ê °', 'ê ¹'), + ('\u{11080}', '\u{110c2}'), + ('\u{110cd}', '\u{110cd}'), +]; + +pub const KANNADA: &'static [(char, char)] = &[ + ('\u{951}', '\u{952}'), + ('।', '॥'), + ('ಀ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('\u{cbc}', 'ೄ'), + ('\u{cc6}', 'ೈ'), + ('ೊ', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), + ('à³', 'ೞ'), + ('à³ ', '\u{ce3}'), + ('೦', '೯'), + ('à³±', 'à³³'), + ('\u{1cd0}', '\u{1cd0}'), + ('\u{1cd2}', '\u{1cd2}'), + ('\u{1cda}', '\u{1cda}'), + ('á³²', 'á³²'), + ('\u{1cf4}', '\u{1cf4}'), + ('ê °', 'ê µ'), +]; + +pub const KATAKANA: &'static [(char, char)] = &[ + ('ã€', '〃'), + ('〈', '】'), + ('〓', '〟'), + ('〰', '〵'), + ('〷', '〷'), + ('〼', '〽'), + ('\u{3099}', 'ã‚œ'), + ('ã‚ ', 'ヿ'), + ('ㇰ', 'ㇿ'), + ('ã‹', '㋾'), + ('㌀', 'ã—'), + ('ï¹…', '﹆'), + ('。', '\u{ff9f}'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𛀀', '𛀀'), + ('𛄠', '𛄢'), + ('ð›…•', 'ð›…•'), + ('ð›…¤', 'ð›…§'), +]; + +pub const KAWI: &'static [(char, char)] = + &[('\u{11f00}', 'ð‘¼'), ('𑼒', '\u{11f3a}'), ('𑼾', '𑽙')]; + +pub const KAYAH_LI: &'static [(char, char)] = &[('꤀', '꤯')]; + +pub const KHAROSHTHI: &'static [(char, char)] = &[ + ('ð¨€', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨µ'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', 'ð©ˆ'), + ('ð©', 'ð©˜'), +]; + +pub const KHITAN_SMALL_SCRIPT: &'static [(char, char)] = + &[('\u{16fe4}', '\u{16fe4}'), ('𘬀', '𘳕')]; + +pub const KHMER: &'static [(char, char)] = + &[('ក', '\u{17dd}'), ('០', '៩'), ('៰', '៹'), ('᧠', '᧿')]; + +pub const KHOJKI: &'static [(char, char)] = + &[('૦', '૯'), ('ê °', 'ê ¹'), ('𑈀', '𑈑'), ('𑈓', '\u{11241}')]; + +pub const KHUDAWADI: &'static [(char, char)] = + &[('।', '॥'), ('ê °', 'ê ¹'), ('ð‘Š°', '\u{112ea}'), ('ð‘‹°', 'ð‘‹¹')]; + +pub const LAO: &'static [(char, char)] = &[ + ('àº', 'ຂ'), + ('ຄ', 'ຄ'), + ('ຆ', 'ຊ'), + ('ຌ', 'ຣ'), + ('ລ', 'ລ'), + ('ວ', 'ຽ'), + ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), + ('\u{ec8}', '\u{ece}'), + ('à»', 'à»™'), + ('ໜ', 'ໟ'), +]; + +pub const LATIN: &'static [(char, char)] = &[ + ('A', 'Z'), + ('a', 'z'), + ('ª', 'ª'), + ('º', 'º'), + ('À', 'Ö'), + ('Ø', 'ö'), + ('ø', 'ʸ'), + ('Ë ', 'ˤ'), + ('\u{363}', '\u{36f}'), + ('\u{485}', '\u{486}'), + ('\u{951}', '\u{952}'), + ('჻', '჻'), + ('á´€', 'á´¥'), + ('á´¬', 'ᵜ'), + ('áµ¢', 'áµ¥'), + ('ᵫ', 'áµ·'), + ('áµ¹', 'ᶾ'), + ('Ḁ', 'ỿ'), + ('\u{202f}', '\u{202f}'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('\u{20f0}', '\u{20f0}'), + ('K', 'â„«'), + ('Ⅎ', 'Ⅎ'), + ('â…Ž', 'â…Ž'), + ('â… ', 'ↈ'), + ('â± ', 'Ɀ'), + ('꜀', '꜇'), + ('Ꜣ', 'ꞇ'), + ('êž‹', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('ꟲ', 'ꟿ'), + ('꤮', '꤮'), + ('ꬰ', 'ê­š'), + ('ê­œ', 'ê­¤'), + ('ê­¦', 'ê­©'), + ('ff', 'st'), + ('A', 'Z'), + ('ï½', 'z'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð¼€', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), +]; + +pub const LEPCHA: &'static [(char, char)] = + &[('á°€', '\u{1c37}'), ('á°»', '᱉'), ('á±', 'á±')]; + +pub const LIMBU: &'static [(char, char)] = &[ + ('॥', '॥'), + ('ᤀ', 'ᤞ'), + ('\u{1920}', 'ᤫ'), + ('ᤰ', '\u{193b}'), + ('᥀', '᥀'), + ('᥄', 'á¥'), +]; + +pub const LINEAR_A: &'static [(char, char)] = + &[('ð„‡', 'ð„³'), ('ð˜€', 'ðœ¶'), ('ð€', 'ð•'), ('ð ', 'ð§')]; + +pub const LINEAR_B: &'static [(char, char)] = &[ + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), + ('ð„€', 'ð„‚'), + ('ð„‡', 'ð„³'), + ('ð„·', 'ð„¿'), +]; + +pub const LISU: &'static [(char, char)] = &[('ê“', 'ê“¿'), ('𑾰', '𑾰')]; + +pub const LYCIAN: &'static [(char, char)] = &[('ðŠ€', 'ðŠœ')]; + +pub const LYDIAN: &'static [(char, char)] = &[('ð¤ ', 'ð¤¹'), ('ð¤¿', 'ð¤¿')]; + +pub const MAHAJANI: &'static [(char, char)] = + &[('।', '९'), ('ê °', 'ê ¹'), ('ð‘…', 'ð‘…¶')]; + +pub const MAKASAR: &'static [(char, char)] = &[('ð‘» ', '𑻸')]; + +pub const MALAYALAM: &'static [(char, char)] = &[ + ('\u{951}', '\u{952}'), + ('।', '॥'), + ('\u{d00}', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', '\u{d44}'), + ('െ', 'ൈ'), + ('ൊ', 'àµ'), + ('ൔ', '\u{d63}'), + ('൦', 'ൿ'), + ('\u{1cda}', '\u{1cda}'), + ('ê °', 'ê ²'), +]; + +pub const MANDAIC: &'static [(char, char)] = + &[('Ù€', 'Ù€'), ('à¡€', '\u{85b}'), ('à¡ž', 'à¡ž')]; + +pub const MANICHAEAN: &'static [(char, char)] = + &[('Ù€', 'Ù€'), ('ð«€', '\u{10ae6}'), ('ð««', 'ð«¶')]; + +pub const MARCHEN: &'static [(char, char)] = + &[('𑱰', 'ð‘²'), ('\u{11c92}', '\u{11ca7}'), ('𑲩', '\u{11cb6}')]; + +pub const MASARAM_GONDI: &'static [(char, char)] = &[ + ('।', '॥'), + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d47}'), + ('ð‘µ', '𑵙'), +]; + +pub const MEDEFAIDRIN: &'static [(char, char)] = &[('ð–¹€', '𖺚')]; + +pub const MEETEI_MAYEK: &'static [(char, char)] = + &[('ê« ', '\u{aaf6}'), ('ꯀ', '\u{abed}'), ('꯰', '꯹')]; + +pub const MENDE_KIKAKUI: &'static [(char, char)] = + &[('ðž €', '𞣄'), ('𞣇', '\u{1e8d6}')]; + +pub const MEROITIC_CURSIVE: &'static [(char, char)] = + &[('ð¦ ', 'ð¦·'), ('ð¦¼', 'ð§'), ('ð§’', 'ð§¿')]; + +pub const MEROITIC_HIEROGLYPHS: &'static [(char, char)] = &[('ð¦€', 'ð¦Ÿ')]; + +pub const MIAO: &'static [(char, char)] = + &[('ð–¼€', '𖽊'), ('\u{16f4f}', '𖾇'), ('\u{16f8f}', '𖾟')]; + +pub const MODI: &'static [(char, char)] = + &[('ê °', 'ê ¹'), ('𑘀', 'ð‘™„'), ('ð‘™', 'ð‘™™')]; + +pub const MONGOLIAN: &'static [(char, char)] = &[ + ('á €', 'á ™'), + ('á  ', 'ᡸ'), + ('ᢀ', 'ᢪ'), + ('\u{202f}', '\u{202f}'), + ('ð‘™ ', '𑙬'), +]; + +pub const MRO: &'static [(char, char)] = &[('ð–©€', 'ð–©ž'), ('ð–© ', 'ð–©©'), ('ð–©®', '𖩯')]; + +pub const MULTANI: &'static [(char, char)] = + &[('੦', '੯'), ('ð‘Š€', '𑊆'), ('𑊈', '𑊈'), ('ð‘ŠŠ', 'ð‘Š'), ('ð‘Š', 'ð‘Š'), ('ð‘ŠŸ', 'ð‘Š©')]; + +pub const MYANMAR: &'static [(char, char)] = + &[('က', 'á‚Ÿ'), ('꤮', '꤮'), ('ꧠ', 'ꧾ'), ('ê© ', 'ê©¿')]; + +pub const NABATAEAN: &'static [(char, char)] = &[('ð¢€', 'ð¢ž'), ('ð¢§', 'ð¢¯')]; + +pub const NAG_MUNDARI: &'static [(char, char)] = &[('ðž“', '𞓹')]; + +pub const NANDINAGARI: &'static [(char, char)] = &[ + ('।', '॥'), + ('೦', '೯'), + ('ᳩ', 'ᳩ'), + ('á³²', 'á³²'), + ('ᳺ', 'ᳺ'), + ('ê °', 'ê µ'), + ('𑦠', '𑦧'), + ('𑦪', '\u{119d7}'), + ('\u{119da}', '𑧤'), +]; + +pub const NEW_TAI_LUE: &'static [(char, char)] = + &[('ᦀ', 'ᦫ'), ('ᦰ', 'ᧉ'), ('á§', '᧚'), ('᧞', '᧟')]; + +pub const NEWA: &'static [(char, char)] = &[('ð‘€', 'ð‘‘›'), ('ð‘‘', 'ð‘‘¡')]; + +pub const NKO: &'static [(char, char)] = &[ + ('ØŒ', 'ØŒ'), + ('Ø›', 'Ø›'), + ('ØŸ', 'ØŸ'), + ('߀', 'ߺ'), + ('\u{7fd}', 'ß¿'), + ('ï´¾', 'ï´¿'), +]; + +pub const NUSHU: &'static [(char, char)] = &[('ð–¿¡', 'ð–¿¡'), ('ð›…°', '𛋻')]; + +pub const NYIAKENG_PUACHUE_HMONG: &'static [(char, char)] = + &[('ðž„€', '𞄬'), ('\u{1e130}', '𞄽'), ('ðž…€', 'ðž…‰'), ('ðž…Ž', 'ðž…')]; + +pub const OGHAM: &'static [(char, char)] = &[('\u{1680}', 'ášœ')]; + +pub const OL_CHIKI: &'static [(char, char)] = &[('á±', '᱿')]; + +pub const OLD_HUNGARIAN: &'static [(char, char)] = + &[('ð²€', 'ð²²'), ('ð³€', 'ð³²'), ('ð³º', 'ð³¿')]; + +pub const OLD_ITALIC: &'static [(char, char)] = &[('ðŒ€', 'ðŒ£'), ('ðŒ­', 'ðŒ¯')]; + +pub const OLD_NORTH_ARABIAN: &'static [(char, char)] = &[('ðª€', 'ðªŸ')]; + +pub const OLD_PERMIC: &'static [(char, char)] = + &[('\u{483}', '\u{483}'), ('ð', '\u{1037a}')]; + +pub const OLD_PERSIAN: &'static [(char, char)] = &[('ðŽ ', 'ðƒ'), ('ðˆ', 'ð•')]; + +pub const OLD_SOGDIAN: &'static [(char, char)] = &[('ð¼€', 'ð¼§')]; + +pub const OLD_SOUTH_ARABIAN: &'static [(char, char)] = &[('ð© ', 'ð©¿')]; + +pub const OLD_TURKIC: &'static [(char, char)] = &[('ð°€', 'ð±ˆ')]; + +pub const OLD_UYGHUR: &'static [(char, char)] = + &[('Ù€', 'Ù€'), ('ð«²', 'ð«²'), ('ð½°', 'ð¾‰')]; + +pub const ORIYA: &'static [(char, char)] = &[ + ('\u{951}', '\u{952}'), + ('।', '॥'), + ('\u{b01}', 'ଃ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), + ('\u{b3c}', '\u{b44}'), + ('à­‡', 'à­ˆ'), + ('à­‹', '\u{b4d}'), + ('\u{b55}', '\u{b57}'), + ('à­œ', 'à­'), + ('à­Ÿ', '\u{b63}'), + ('à­¦', 'à­·'), + ('\u{1cda}', '\u{1cda}'), + ('á³²', 'á³²'), +]; + +pub const OSAGE: &'static [(char, char)] = &[('ð’°', 'ð““'), ('ð“˜', 'ð“»')]; + +pub const OSMANYA: &'static [(char, char)] = &[('ð’€', 'ð’'), ('ð’ ', 'ð’©')]; + +pub const PAHAWH_HMONG: &'static [(char, char)] = + &[('𖬀', 'ð–­…'), ('ð–­', 'ð–­™'), ('ð–­›', 'ð–­¡'), ('ð–­£', 'ð–­·'), ('ð–­½', 'ð–®')]; + +pub const PALMYRENE: &'static [(char, char)] = &[('ð¡ ', 'ð¡¿')]; + +pub const PAU_CIN_HAU: &'static [(char, char)] = &[('ð‘«€', '𑫸')]; + +pub const PHAGS_PA: &'static [(char, char)] = + &[('á ‚', 'á ƒ'), ('á …', 'á …'), ('ê¡€', 'ê¡·')]; + +pub const PHOENICIAN: &'static [(char, char)] = &[('ð¤€', 'ð¤›'), ('ð¤Ÿ', 'ð¤Ÿ')]; + +pub const PSALTER_PAHLAVI: &'static [(char, char)] = + &[('Ù€', 'Ù€'), ('ð®€', 'ð®‘'), ('ð®™', 'ð®œ'), ('ð®©', 'ð®¯')]; + +pub const REJANG: &'static [(char, char)] = &[('ꤰ', '꥓'), ('꥟', '꥟')]; + +pub const RUNIC: &'static [(char, char)] = &[('áš ', 'ᛪ'), ('á›®', 'ᛸ')]; + +pub const SAMARITAN: &'static [(char, char)] = &[('à €', '\u{82d}'), ('à °', 'à ¾')]; + +pub const SAURASHTRA: &'static [(char, char)] = + &[('ꢀ', '\u{a8c5}'), ('꣎', '꣙')]; + +pub const SHARADA: &'static [(char, char)] = &[ + ('\u{951}', '\u{951}'), + ('\u{1cd7}', '\u{1cd7}'), + ('\u{1cd9}', '\u{1cd9}'), + ('\u{1cdc}', '\u{1cdd}'), + ('\u{1ce0}', '\u{1ce0}'), + ('\u{11180}', '𑇟'), +]; + +pub const SHAVIAN: &'static [(char, char)] = &[('ð‘', 'ð‘¿')]; + +pub const SIDDHAM: &'static [(char, char)] = + &[('ð‘–€', '\u{115b5}'), ('ð‘–¸', '\u{115dd}')]; + +pub const SIGNWRITING: &'static [(char, char)] = + &[('ð €', 'ðª‹'), ('\u{1da9b}', '\u{1da9f}'), ('\u{1daa1}', '\u{1daaf}')]; + +pub const SINHALA: &'static [(char, char)] = &[ + ('।', '॥'), + ('\u{d81}', 'ඃ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('à·˜', '\u{ddf}'), + ('à·¦', 'à·¯'), + ('à·²', 'à·´'), + ('𑇡', '𑇴'), +]; + +pub const SOGDIAN: &'static [(char, char)] = &[('Ù€', 'Ù€'), ('ð¼°', 'ð½™')]; + +pub const SORA_SOMPENG: &'static [(char, char)] = &[('ð‘ƒ', '𑃨'), ('𑃰', '𑃹')]; + +pub const SOYOMBO: &'static [(char, char)] = &[('ð‘©', '𑪢')]; + +pub const SUNDANESE: &'static [(char, char)] = + &[('\u{1b80}', 'ᮿ'), ('á³€', '᳇')]; + +pub const SYLOTI_NAGRI: &'static [(char, char)] = + &[('।', '॥'), ('০', '৯'), ('ê €', '\u{a82c}')]; + +pub const SYRIAC: &'static [(char, char)] = &[ + ('ØŒ', 'ØŒ'), + ('Ø›', '\u{61c}'), + ('ØŸ', 'ØŸ'), + ('Ù€', 'Ù€'), + ('\u{64b}', '\u{655}'), + ('\u{670}', '\u{670}'), + ('Ü€', 'Ü'), + ('\u{70f}', '\u{74a}'), + ('Ý', 'Ý'), + ('à¡ ', 'ࡪ'), + ('\u{1df8}', '\u{1df8}'), + ('\u{1dfa}', '\u{1dfa}'), +]; + +pub const TAGALOG: &'static [(char, char)] = + &[('ᜀ', '᜕'), ('ᜟ', 'ᜟ'), ('᜵', '᜶')]; + +pub const TAGBANWA: &'static [(char, char)] = + &[('᜵', '᜶'), ('á ', 'á¬'), ('á®', 'á°'), ('\u{1772}', '\u{1773}')]; + +pub const TAI_LE: &'static [(char, char)] = + &[('á€', 'á‰'), ('á¥', 'ᥭ'), ('ᥰ', 'ᥴ')]; + +pub const TAI_THAM: &'static [(char, char)] = &[ + ('ᨠ', '\u{1a5e}'), + ('\u{1a60}', '\u{1a7c}'), + ('\u{1a7f}', '᪉'), + ('áª', '᪙'), + ('᪠', '᪭'), +]; + +pub const TAI_VIET: &'static [(char, char)] = &[('ꪀ', 'ê«‚'), ('ê«›', 'ê«Ÿ')]; + +pub const TAKRI: &'static [(char, char)] = + &[('।', '॥'), ('ê °', 'ê ¹'), ('𑚀', 'ð‘š¹'), ('𑛀', '𑛉')]; + +pub const TAMIL: &'static [(char, char)] = &[ + ('\u{951}', '\u{952}'), + ('।', '॥'), + ('\u{b82}', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'ஹ'), + ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), + ('ொ', '\u{bcd}'), + ('à¯', 'à¯'), + ('\u{bd7}', '\u{bd7}'), + ('௦', '௺'), + ('\u{1cda}', '\u{1cda}'), + ('ꣳ', 'ꣳ'), + ('\u{11301}', '\u{11301}'), + ('𑌃', '𑌃'), + ('\u{1133b}', '\u{1133c}'), + ('ð‘¿€', 'ð‘¿±'), + ('ð‘¿¿', 'ð‘¿¿'), +]; + +pub const TANGSA: &'static [(char, char)] = &[('ð–©°', '𖪾'), ('ð–«€', '𖫉')]; + +pub const TANGUT: &'static [(char, char)] = + &[('ð–¿ ', 'ð–¿ '), ('ð—€€', '𘟷'), ('𘠀', '𘫿'), ('𘴀', '𘴈')]; + +pub const TELUGU: &'static [(char, char)] = &[ + ('\u{951}', '\u{952}'), + ('।', '॥'), + ('\u{c00}', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°¹'), + ('\u{c3c}', 'ౄ'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('ౘ', 'ౚ'), + ('à±', 'à±'), + ('à± ', '\u{c63}'), + ('౦', '౯'), + ('à±·', '౿'), + ('\u{1cda}', '\u{1cda}'), + ('á³²', 'á³²'), +]; + +pub const THAANA: &'static [(char, char)] = &[ + ('ØŒ', 'ØŒ'), + ('Ø›', '\u{61c}'), + ('ØŸ', 'ØŸ'), + ('Ù ', 'Ù©'), + ('Þ€', 'Þ±'), + ('ï·²', 'ï·²'), + ('ï·½', 'ï·½'), +]; + +pub const THAI: &'static [(char, char)] = &[('à¸', '\u{e3a}'), ('เ', '๛')]; + +pub const TIBETAN: &'static [(char, char)] = &[ + ('ༀ', 'ཇ'), + ('ཉ', 'ཬ'), + ('\u{f71}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('྾', 'à¿Œ'), + ('à¿Ž', 'à¿”'), + ('à¿™', 'à¿š'), +]; + +pub const TIFINAGH: &'static [(char, char)] = + &[('â´°', 'ⵧ'), ('ⵯ', 'âµ°'), ('\u{2d7f}', '\u{2d7f}')]; + +pub const TIRHUTA: &'static [(char, char)] = &[ + ('\u{951}', '\u{952}'), + ('।', '॥'), + ('á³²', 'á³²'), + ('ê °', 'ê ¹'), + ('ð‘’€', '𑓇'), + ('ð‘“', 'ð‘“™'), +]; + +pub const TOTO: &'static [(char, char)] = &[('ðžŠ', '\u{1e2ae}')]; + +pub const UGARITIC: &'static [(char, char)] = &[('ðŽ€', 'ðŽ'), ('ðŽŸ', 'ðŽŸ')]; + +pub const VAI: &'static [(char, char)] = &[('ꔀ', 'ꘫ')]; + +pub const VITHKUQI: &'static [(char, char)] = &[ + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), +]; + +pub const WANCHO: &'static [(char, char)] = &[('ðž‹€', '𞋹'), ('ðž‹¿', 'ðž‹¿')]; + +pub const WARANG_CITI: &'static [(char, char)] = &[('ð‘¢ ', 'ð‘£²'), ('𑣿', '𑣿')]; + +pub const YEZIDI: &'static [(char, char)] = &[ + ('ØŒ', 'ØŒ'), + ('Ø›', 'Ø›'), + ('ØŸ', 'ØŸ'), + ('Ù ', 'Ù©'), + ('ðº€', 'ðº©'), + ('\u{10eab}', 'ðº­'), + ('ðº°', 'ðº±'), +]; + +pub const YI: &'static [(char, char)] = &[ + ('ã€', '。'), + ('〈', '】'), + ('〔', '〛'), + ('・', '・'), + ('ꀀ', 'ê’Œ'), + ('ê’', '꓆'), + ('。', 'ï½¥'), +]; + +pub const ZANABAZAR_SQUARE: &'static [(char, char)] = &[('𑨀', '\u{11a47}')]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/sentence_break.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/sentence_break.rs new file mode 100644 index 0000000000000..24348736f21cf --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/sentence_break.rs @@ -0,0 +1,2477 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate sentence-break ucd-15.0.0 --chars +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("ATerm", ATERM), + ("CR", CR), + ("Close", CLOSE), + ("Extend", EXTEND), + ("Format", FORMAT), + ("LF", LF), + ("Lower", LOWER), + ("Numeric", NUMERIC), + ("OLetter", OLETTER), + ("SContinue", SCONTINUE), + ("STerm", STERM), + ("Sep", SEP), + ("Sp", SP), + ("Upper", UPPER), +]; + +pub const ATERM: &'static [(char, char)] = + &[('.', '.'), ('․', '․'), ('ï¹’', 'ï¹’'), ('.', '.')]; + +pub const CR: &'static [(char, char)] = &[('\r', '\r')]; + +pub const CLOSE: &'static [(char, char)] = &[ + ('"', '"'), + ('\'', ')'), + ('[', '['), + (']', ']'), + ('{', '{'), + ('}', '}'), + ('«', '«'), + ('»', '»'), + ('༺', '༽'), + ('áš›', 'ášœ'), + ('‘', '‟'), + ('‹', '›'), + ('â…', 'â†'), + ('â½', 'â¾'), + ('â‚', 'â‚Ž'), + ('⌈', '⌋'), + ('〈', '〉'), + ('â›', 'â '), + ('â¨', 'âµ'), + ('⟅', '⟆'), + ('⟦', '⟯'), + ('⦃', '⦘'), + ('⧘', '⧛'), + ('⧼', '⧽'), + ('⸀', 'â¸'), + ('⸜', 'â¸'), + ('⸠', '⸩'), + ('⹂', '⹂'), + ('⹕', '⹜'), + ('〈', '】'), + ('〔', '〛'), + ('ã€', '〟'), + ('ï´¾', 'ï´¿'), + ('︗', '︘'), + ('︵', '﹄'), + ('﹇', '﹈'), + ('ï¹™', '﹞'), + ('(', ')'), + ('ï¼»', 'ï¼»'), + ('ï¼½', 'ï¼½'), + ('ï½›', 'ï½›'), + ('ï½', 'ï½'), + ('⦅', 'ï½ '), + ('ï½¢', 'ï½£'), + ('🙶', '🙸'), +]; + +pub const EXTEND: &'static [(char, char)] = &[ + ('\u{300}', '\u{36f}'), + ('\u{483}', '\u{489}'), + ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), + ('\u{610}', '\u{61a}'), + ('\u{64b}', '\u{65f}'), + ('\u{670}', '\u{670}'), + ('\u{6d6}', '\u{6dc}'), + ('\u{6df}', '\u{6e4}'), + ('\u{6e7}', '\u{6e8}'), + ('\u{6ea}', '\u{6ed}'), + ('\u{711}', '\u{711}'), + ('\u{730}', '\u{74a}'), + ('\u{7a6}', '\u{7b0}'), + ('\u{7eb}', '\u{7f3}'), + ('\u{7fd}', '\u{7fd}'), + ('\u{816}', '\u{819}'), + ('\u{81b}', '\u{823}'), + ('\u{825}', '\u{827}'), + ('\u{829}', '\u{82d}'), + ('\u{859}', '\u{85b}'), + ('\u{898}', '\u{89f}'), + ('\u{8ca}', '\u{8e1}'), + ('\u{8e3}', 'ः'), + ('\u{93a}', '\u{93c}'), + ('ा', 'à¥'), + ('\u{951}', '\u{957}'), + ('\u{962}', '\u{963}'), + ('\u{981}', 'ঃ'), + ('\u{9bc}', '\u{9bc}'), + ('\u{9be}', '\u{9c4}'), + ('ে', 'ৈ'), + ('ো', '\u{9cd}'), + ('\u{9d7}', '\u{9d7}'), + ('\u{9e2}', '\u{9e3}'), + ('\u{9fe}', '\u{9fe}'), + ('\u{a01}', 'ਃ'), + ('\u{a3c}', '\u{a3c}'), + ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), + ('\u{a70}', '\u{a71}'), + ('\u{a75}', '\u{a75}'), + ('\u{a81}', 'ઃ'), + ('\u{abc}', '\u{abc}'), + ('ા', '\u{ac5}'), + ('\u{ac7}', 'ૉ'), + ('à«‹', '\u{acd}'), + ('\u{ae2}', '\u{ae3}'), + ('\u{afa}', '\u{aff}'), + ('\u{b01}', 'ଃ'), + ('\u{b3c}', '\u{b3c}'), + ('\u{b3e}', '\u{b44}'), + ('à­‡', 'à­ˆ'), + ('à­‹', '\u{b4d}'), + ('\u{b55}', '\u{b57}'), + ('\u{b62}', '\u{b63}'), + ('\u{b82}', '\u{b82}'), + ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), + ('ொ', '\u{bcd}'), + ('\u{bd7}', '\u{bd7}'), + ('\u{c00}', '\u{c04}'), + ('\u{c3c}', '\u{c3c}'), + ('\u{c3e}', 'ౄ'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('\u{c62}', '\u{c63}'), + ('\u{c81}', 'ಃ'), + ('\u{cbc}', '\u{cbc}'), + ('ಾ', 'ೄ'), + ('\u{cc6}', 'ೈ'), + ('ೊ', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), + ('\u{ce2}', '\u{ce3}'), + ('à³³', 'à³³'), + ('\u{d00}', 'à´ƒ'), + ('\u{d3b}', '\u{d3c}'), + ('\u{d3e}', '\u{d44}'), + ('െ', 'ൈ'), + ('ൊ', '\u{d4d}'), + ('\u{d57}', '\u{d57}'), + ('\u{d62}', '\u{d63}'), + ('\u{d81}', 'ඃ'), + ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('à·˜', '\u{ddf}'), + ('à·²', 'à·³'), + ('\u{e31}', '\u{e31}'), + ('\u{e34}', '\u{e3a}'), + ('\u{e47}', '\u{e4e}'), + ('\u{eb1}', '\u{eb1}'), + ('\u{eb4}', '\u{ebc}'), + ('\u{ec8}', '\u{ece}'), + ('\u{f18}', '\u{f19}'), + ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), + ('\u{f39}', '\u{f39}'), + ('༾', '༿'), + ('\u{f71}', '\u{f84}'), + ('\u{f86}', '\u{f87}'), + ('\u{f8d}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('\u{fc6}', '\u{fc6}'), + ('ါ', '\u{103e}'), + ('á–', '\u{1059}'), + ('\u{105e}', '\u{1060}'), + ('á¢', 'á¤'), + ('á§', 'á­'), + ('\u{1071}', '\u{1074}'), + ('\u{1082}', '\u{108d}'), + ('á‚', 'á‚'), + ('á‚š', '\u{109d}'), + ('\u{135d}', '\u{135f}'), + ('\u{1712}', '᜕'), + ('\u{1732}', '᜴'), + ('\u{1752}', '\u{1753}'), + ('\u{1772}', '\u{1773}'), + ('\u{17b4}', '\u{17d3}'), + ('\u{17dd}', '\u{17dd}'), + ('\u{180b}', '\u{180d}'), + ('\u{180f}', '\u{180f}'), + ('\u{1885}', '\u{1886}'), + ('\u{18a9}', '\u{18a9}'), + ('\u{1920}', 'ᤫ'), + ('ᤰ', '\u{193b}'), + ('\u{1a17}', '\u{1a1b}'), + ('á©•', '\u{1a5e}'), + ('\u{1a60}', '\u{1a7c}'), + ('\u{1a7f}', '\u{1a7f}'), + ('\u{1ab0}', '\u{1ace}'), + ('\u{1b00}', 'ᬄ'), + ('\u{1b34}', 'á­„'), + ('\u{1b6b}', '\u{1b73}'), + ('\u{1b80}', 'ᮂ'), + ('ᮡ', '\u{1bad}'), + ('\u{1be6}', '᯳'), + ('á°¤', '\u{1c37}'), + ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', '\u{1ce8}'), + ('\u{1ced}', '\u{1ced}'), + ('\u{1cf4}', '\u{1cf4}'), + ('á³·', '\u{1cf9}'), + ('\u{1dc0}', '\u{1dff}'), + ('\u{200c}', '\u{200d}'), + ('\u{20d0}', '\u{20f0}'), + ('\u{2cef}', '\u{2cf1}'), + ('\u{2d7f}', '\u{2d7f}'), + ('\u{2de0}', '\u{2dff}'), + ('\u{302a}', '\u{302f}'), + ('\u{3099}', '\u{309a}'), + ('\u{a66f}', '\u{a672}'), + ('\u{a674}', '\u{a67d}'), + ('\u{a69e}', '\u{a69f}'), + ('\u{a6f0}', '\u{a6f1}'), + ('\u{a802}', '\u{a802}'), + ('\u{a806}', '\u{a806}'), + ('\u{a80b}', '\u{a80b}'), + ('ê £', 'ê §'), + ('\u{a82c}', '\u{a82c}'), + ('ꢀ', 'ê¢'), + ('ꢴ', '\u{a8c5}'), + ('\u{a8e0}', '\u{a8f1}'), + ('\u{a8ff}', '\u{a8ff}'), + ('\u{a926}', '\u{a92d}'), + ('\u{a947}', '꥓'), + ('\u{a980}', 'ꦃ'), + ('\u{a9b3}', '꧀'), + ('\u{a9e5}', '\u{a9e5}'), + ('\u{aa29}', '\u{aa36}'), + ('\u{aa43}', '\u{aa43}'), + ('\u{aa4c}', 'ê©'), + ('ê©»', 'ꩽ'), + ('\u{aab0}', '\u{aab0}'), + ('\u{aab2}', '\u{aab4}'), + ('\u{aab7}', '\u{aab8}'), + ('\u{aabe}', '\u{aabf}'), + ('\u{aac1}', '\u{aac1}'), + ('ê««', 'ꫯ'), + ('ꫵ', '\u{aaf6}'), + ('ꯣ', 'ꯪ'), + ('꯬', '\u{abed}'), + ('\u{fb1e}', '\u{fb1e}'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{fe20}', '\u{fe2f}'), + ('\u{ff9e}', '\u{ff9f}'), + ('\u{101fd}', '\u{101fd}'), + ('\u{102e0}', '\u{102e0}'), + ('\u{10376}', '\u{1037a}'), + ('\u{10a01}', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), + ('\u{10ae5}', '\u{10ae6}'), + ('\u{10d24}', '\u{10d27}'), + ('\u{10eab}', '\u{10eac}'), + ('\u{10efd}', '\u{10eff}'), + ('\u{10f46}', '\u{10f50}'), + ('\u{10f82}', '\u{10f85}'), + ('ð‘€€', '𑀂'), + ('\u{11038}', '\u{11046}'), + ('\u{11070}', '\u{11070}'), + ('\u{11073}', '\u{11074}'), + ('\u{1107f}', 'ð‘‚‚'), + ('ð‘‚°', '\u{110ba}'), + ('\u{110c2}', '\u{110c2}'), + ('\u{11100}', '\u{11102}'), + ('\u{11127}', '\u{11134}'), + ('ð‘……', 'ð‘…†'), + ('\u{11173}', '\u{11173}'), + ('\u{11180}', '𑆂'), + ('𑆳', '𑇀'), + ('\u{111c9}', '\u{111cc}'), + ('𑇎', '\u{111cf}'), + ('𑈬', '\u{11237}'), + ('\u{1123e}', '\u{1123e}'), + ('\u{11241}', '\u{11241}'), + ('\u{112df}', '\u{112ea}'), + ('\u{11300}', '𑌃'), + ('\u{1133b}', '\u{1133c}'), + ('\u{1133e}', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘'), + ('\u{11357}', '\u{11357}'), + ('ð‘¢', 'ð‘£'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('ð‘µ', '\u{11446}'), + ('\u{1145e}', '\u{1145e}'), + ('\u{114b0}', '\u{114c3}'), + ('\u{115af}', '\u{115b5}'), + ('ð‘–¸', '\u{115c0}'), + ('\u{115dc}', '\u{115dd}'), + ('𑘰', '\u{11640}'), + ('\u{116ab}', '\u{116b7}'), + ('\u{1171d}', '\u{1172b}'), + ('ð‘ ¬', '\u{1183a}'), + ('\u{11930}', '𑤵'), + ('𑤷', '𑤸'), + ('\u{1193b}', '\u{1193e}'), + ('ð‘¥€', 'ð‘¥€'), + ('𑥂', '\u{11943}'), + ('𑧑', '\u{119d7}'), + ('\u{119da}', '\u{119e0}'), + ('𑧤', '𑧤'), + ('\u{11a01}', '\u{11a0a}'), + ('\u{11a33}', '𑨹'), + ('\u{11a3b}', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), + ('\u{11a51}', '\u{11a5b}'), + ('\u{11a8a}', '\u{11a99}'), + ('ð‘°¯', '\u{11c36}'), + ('\u{11c38}', '\u{11c3f}'), + ('\u{11c92}', '\u{11ca7}'), + ('𑲩', '\u{11cb6}'), + ('\u{11d31}', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d45}'), + ('\u{11d47}', '\u{11d47}'), + ('𑶊', '𑶎'), + ('\u{11d90}', '\u{11d91}'), + ('𑶓', '\u{11d97}'), + ('\u{11ef3}', '𑻶'), + ('\u{11f00}', '\u{11f01}'), + ('𑼃', '𑼃'), + ('𑼴', '\u{11f3a}'), + ('𑼾', '\u{11f42}'), + ('\u{13440}', '\u{13440}'), + ('\u{13447}', '\u{13455}'), + ('\u{16af0}', '\u{16af4}'), + ('\u{16b30}', '\u{16b36}'), + ('\u{16f4f}', '\u{16f4f}'), + ('𖽑', '𖾇'), + ('\u{16f8f}', '\u{16f92}'), + ('\u{16fe4}', '\u{16fe4}'), + ('ð–¿°', 'ð–¿±'), + ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('\u{1d165}', '\u{1d169}'), + ('ð…­', '\u{1d172}'), + ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), + ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), + ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), + ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('\u{1e08f}', '\u{1e08f}'), + ('\u{1e130}', '\u{1e136}'), + ('\u{1e2ae}', '\u{1e2ae}'), + ('\u{1e2ec}', '\u{1e2ef}'), + ('\u{1e4ec}', '\u{1e4ef}'), + ('\u{1e8d0}', '\u{1e8d6}'), + ('\u{1e944}', '\u{1e94a}'), + ('\u{e0020}', '\u{e007f}'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const FORMAT: &'static [(char, char)] = &[ + ('\u{ad}', '\u{ad}'), + ('\u{600}', '\u{605}'), + ('\u{61c}', '\u{61c}'), + ('\u{6dd}', '\u{6dd}'), + ('\u{70f}', '\u{70f}'), + ('\u{890}', '\u{891}'), + ('\u{8e2}', '\u{8e2}'), + ('\u{180e}', '\u{180e}'), + ('\u{200b}', '\u{200b}'), + ('\u{200e}', '\u{200f}'), + ('\u{202a}', '\u{202e}'), + ('\u{2060}', '\u{2064}'), + ('\u{2066}', '\u{206f}'), + ('\u{feff}', '\u{feff}'), + ('\u{fff9}', '\u{fffb}'), + ('\u{110bd}', '\u{110bd}'), + ('\u{110cd}', '\u{110cd}'), + ('\u{13430}', '\u{1343f}'), + ('\u{1bca0}', '\u{1bca3}'), + ('\u{1d173}', '\u{1d17a}'), + ('\u{e0001}', '\u{e0001}'), +]; + +pub const LF: &'static [(char, char)] = &[('\n', '\n')]; + +pub const LOWER: &'static [(char, char)] = &[ + ('a', 'z'), + ('ª', 'ª'), + ('µ', 'µ'), + ('º', 'º'), + ('ß', 'ö'), + ('ø', 'ÿ'), + ('Ä', 'Ä'), + ('ă', 'ă'), + ('Ä…', 'Ä…'), + ('ć', 'ć'), + ('ĉ', 'ĉ'), + ('Ä‹', 'Ä‹'), + ('Ä', 'Ä'), + ('Ä', 'Ä'), + ('Ä‘', 'Ä‘'), + ('Ä“', 'Ä“'), + ('Ä•', 'Ä•'), + ('Ä—', 'Ä—'), + ('Ä™', 'Ä™'), + ('Ä›', 'Ä›'), + ('Ä', 'Ä'), + ('ÄŸ', 'ÄŸ'), + ('Ä¡', 'Ä¡'), + ('Ä£', 'Ä£'), + ('Ä¥', 'Ä¥'), + ('ħ', 'ħ'), + ('Ä©', 'Ä©'), + ('Ä«', 'Ä«'), + ('Ä­', 'Ä­'), + ('į', 'į'), + ('ı', 'ı'), + ('ij', 'ij'), + ('ĵ', 'ĵ'), + ('Ä·', 'ĸ'), + ('ĺ', 'ĺ'), + ('ļ', 'ļ'), + ('ľ', 'ľ'), + ('Å€', 'Å€'), + ('Å‚', 'Å‚'), + ('Å„', 'Å„'), + ('ņ', 'ņ'), + ('ň', 'ʼn'), + ('Å‹', 'Å‹'), + ('Å', 'Å'), + ('Å', 'Å'), + ('Å‘', 'Å‘'), + ('Å“', 'Å“'), + ('Å•', 'Å•'), + ('Å—', 'Å—'), + ('Å™', 'Å™'), + ('Å›', 'Å›'), + ('Å', 'Å'), + ('ÅŸ', 'ÅŸ'), + ('Å¡', 'Å¡'), + ('Å£', 'Å£'), + ('Å¥', 'Å¥'), + ('ŧ', 'ŧ'), + ('Å©', 'Å©'), + ('Å«', 'Å«'), + ('Å­', 'Å­'), + ('ů', 'ů'), + ('ű', 'ű'), + ('ų', 'ų'), + ('ŵ', 'ŵ'), + ('Å·', 'Å·'), + ('ź', 'ź'), + ('ż', 'ż'), + ('ž', 'Æ€'), + ('ƃ', 'ƃ'), + ('Æ…', 'Æ…'), + ('ƈ', 'ƈ'), + ('ÆŒ', 'Æ'), + ('Æ’', 'Æ’'), + ('Æ•', 'Æ•'), + ('Æ™', 'Æ›'), + ('Æž', 'Æž'), + ('Æ¡', 'Æ¡'), + ('Æ£', 'Æ£'), + ('Æ¥', 'Æ¥'), + ('ƨ', 'ƨ'), + ('ƪ', 'Æ«'), + ('Æ­', 'Æ­'), + ('Æ°', 'Æ°'), + ('Æ´', 'Æ´'), + ('ƶ', 'ƶ'), + ('ƹ', 'ƺ'), + ('ƽ', 'Æ¿'), + ('dž', 'dž'), + ('lj', 'lj'), + ('ÇŒ', 'ÇŒ'), + ('ÇŽ', 'ÇŽ'), + ('Ç', 'Ç'), + ('Ç’', 'Ç’'), + ('Ç”', 'Ç”'), + ('Ç–', 'Ç–'), + ('ǘ', 'ǘ'), + ('Çš', 'Çš'), + ('Çœ', 'Ç'), + ('ÇŸ', 'ÇŸ'), + ('Ç¡', 'Ç¡'), + ('Ç£', 'Ç£'), + ('Ç¥', 'Ç¥'), + ('ǧ', 'ǧ'), + ('Ç©', 'Ç©'), + ('Ç«', 'Ç«'), + ('Ç­', 'Ç­'), + ('ǯ', 'Ç°'), + ('dz', 'dz'), + ('ǵ', 'ǵ'), + ('ǹ', 'ǹ'), + ('Ç»', 'Ç»'), + ('ǽ', 'ǽ'), + ('Ç¿', 'Ç¿'), + ('È', 'È'), + ('ȃ', 'ȃ'), + ('È…', 'È…'), + ('ȇ', 'ȇ'), + ('ȉ', 'ȉ'), + ('È‹', 'È‹'), + ('È', 'È'), + ('È', 'È'), + ('È‘', 'È‘'), + ('È“', 'È“'), + ('È•', 'È•'), + ('È—', 'È—'), + ('È™', 'È™'), + ('È›', 'È›'), + ('È', 'È'), + ('ÈŸ', 'ÈŸ'), + ('È¡', 'È¡'), + ('È£', 'È£'), + ('È¥', 'È¥'), + ('ȧ', 'ȧ'), + ('È©', 'È©'), + ('È«', 'È«'), + ('È­', 'È­'), + ('ȯ', 'ȯ'), + ('ȱ', 'ȱ'), + ('ȳ', 'ȹ'), + ('ȼ', 'ȼ'), + ('È¿', 'É€'), + ('É‚', 'É‚'), + ('ɇ', 'ɇ'), + ('ɉ', 'ɉ'), + ('É‹', 'É‹'), + ('É', 'É'), + ('É', 'Ê“'), + ('Ê•', 'ʸ'), + ('Ë€', 'Ë'), + ('Ë ', 'ˤ'), + ('ͱ', 'ͱ'), + ('ͳ', 'ͳ'), + ('Í·', 'Í·'), + ('ͺ', 'ͽ'), + ('Î', 'Î'), + ('ά', 'ÏŽ'), + ('Ï', 'Ï‘'), + ('Ï•', 'Ï—'), + ('Ï™', 'Ï™'), + ('Ï›', 'Ï›'), + ('Ï', 'Ï'), + ('ÏŸ', 'ÏŸ'), + ('Ï¡', 'Ï¡'), + ('Ï£', 'Ï£'), + ('Ï¥', 'Ï¥'), + ('ϧ', 'ϧ'), + ('Ï©', 'Ï©'), + ('Ï«', 'Ï«'), + ('Ï­', 'Ï­'), + ('ϯ', 'ϳ'), + ('ϵ', 'ϵ'), + ('ϸ', 'ϸ'), + ('Ï»', 'ϼ'), + ('а', 'ÑŸ'), + ('Ñ¡', 'Ñ¡'), + ('Ñ£', 'Ñ£'), + ('Ñ¥', 'Ñ¥'), + ('ѧ', 'ѧ'), + ('Ñ©', 'Ñ©'), + ('Ñ«', 'Ñ«'), + ('Ñ­', 'Ñ­'), + ('ѯ', 'ѯ'), + ('ѱ', 'ѱ'), + ('ѳ', 'ѳ'), + ('ѵ', 'ѵ'), + ('Ñ·', 'Ñ·'), + ('ѹ', 'ѹ'), + ('Ñ»', 'Ñ»'), + ('ѽ', 'ѽ'), + ('Ñ¿', 'Ñ¿'), + ('Ò', 'Ò'), + ('Ò‹', 'Ò‹'), + ('Ò', 'Ò'), + ('Ò', 'Ò'), + ('Ò‘', 'Ò‘'), + ('Ò“', 'Ò“'), + ('Ò•', 'Ò•'), + ('Ò—', 'Ò—'), + ('Ò™', 'Ò™'), + ('Ò›', 'Ò›'), + ('Ò', 'Ò'), + ('ÒŸ', 'ÒŸ'), + ('Ò¡', 'Ò¡'), + ('Ò£', 'Ò£'), + ('Ò¥', 'Ò¥'), + ('Ò§', 'Ò§'), + ('Ò©', 'Ò©'), + ('Ò«', 'Ò«'), + ('Ò­', 'Ò­'), + ('Ò¯', 'Ò¯'), + ('Ò±', 'Ò±'), + ('Ò³', 'Ò³'), + ('Òµ', 'Òµ'), + ('Ò·', 'Ò·'), + ('Ò¹', 'Ò¹'), + ('Ò»', 'Ò»'), + ('Ò½', 'Ò½'), + ('Ò¿', 'Ò¿'), + ('Ó‚', 'Ó‚'), + ('Ó„', 'Ó„'), + ('Ó†', 'Ó†'), + ('Óˆ', 'Óˆ'), + ('ÓŠ', 'ÓŠ'), + ('ÓŒ', 'ÓŒ'), + ('ÓŽ', 'Ó'), + ('Ó‘', 'Ó‘'), + ('Ó“', 'Ó“'), + ('Ó•', 'Ó•'), + ('Ó—', 'Ó—'), + ('Ó™', 'Ó™'), + ('Ó›', 'Ó›'), + ('Ó', 'Ó'), + ('ÓŸ', 'ÓŸ'), + ('Ó¡', 'Ó¡'), + ('Ó£', 'Ó£'), + ('Ó¥', 'Ó¥'), + ('Ó§', 'Ó§'), + ('Ó©', 'Ó©'), + ('Ó«', 'Ó«'), + ('Ó­', 'Ó­'), + ('Ó¯', 'Ó¯'), + ('Ó±', 'Ó±'), + ('Ó³', 'Ó³'), + ('Óµ', 'Óµ'), + ('Ó·', 'Ó·'), + ('Ó¹', 'Ó¹'), + ('Ó»', 'Ó»'), + ('Ó½', 'Ó½'), + ('Ó¿', 'Ó¿'), + ('Ô', 'Ô'), + ('Ôƒ', 'Ôƒ'), + ('Ô…', 'Ô…'), + ('Ô‡', 'Ô‡'), + ('Ô‰', 'Ô‰'), + ('Ô‹', 'Ô‹'), + ('Ô', 'Ô'), + ('Ô', 'Ô'), + ('Ô‘', 'Ô‘'), + ('Ô“', 'Ô“'), + ('Ô•', 'Ô•'), + ('Ô—', 'Ô—'), + ('Ô™', 'Ô™'), + ('Ô›', 'Ô›'), + ('Ô', 'Ô'), + ('ÔŸ', 'ÔŸ'), + ('Ô¡', 'Ô¡'), + ('Ô£', 'Ô£'), + ('Ô¥', 'Ô¥'), + ('Ô§', 'Ô§'), + ('Ô©', 'Ô©'), + ('Ô«', 'Ô«'), + ('Ô­', 'Ô­'), + ('Ô¯', 'Ô¯'), + ('Õ ', 'Öˆ'), + ('ჼ', 'ჼ'), + ('á¸', 'á½'), + ('á²€', 'ᲈ'), + ('á´€', 'ᶿ'), + ('á¸', 'á¸'), + ('ḃ', 'ḃ'), + ('ḅ', 'ḅ'), + ('ḇ', 'ḇ'), + ('ḉ', 'ḉ'), + ('ḋ', 'ḋ'), + ('á¸', 'á¸'), + ('á¸', 'á¸'), + ('ḑ', 'ḑ'), + ('ḓ', 'ḓ'), + ('ḕ', 'ḕ'), + ('ḗ', 'ḗ'), + ('ḙ', 'ḙ'), + ('ḛ', 'ḛ'), + ('á¸', 'á¸'), + ('ḟ', 'ḟ'), + ('ḡ', 'ḡ'), + ('ḣ', 'ḣ'), + ('ḥ', 'ḥ'), + ('ḧ', 'ḧ'), + ('ḩ', 'ḩ'), + ('ḫ', 'ḫ'), + ('ḭ', 'ḭ'), + ('ḯ', 'ḯ'), + ('ḱ', 'ḱ'), + ('ḳ', 'ḳ'), + ('ḵ', 'ḵ'), + ('ḷ', 'ḷ'), + ('ḹ', 'ḹ'), + ('ḻ', 'ḻ'), + ('ḽ', 'ḽ'), + ('ḿ', 'ḿ'), + ('á¹', 'á¹'), + ('ṃ', 'ṃ'), + ('á¹…', 'á¹…'), + ('ṇ', 'ṇ'), + ('ṉ', 'ṉ'), + ('ṋ', 'ṋ'), + ('á¹', 'á¹'), + ('á¹', 'á¹'), + ('ṑ', 'ṑ'), + ('ṓ', 'ṓ'), + ('ṕ', 'ṕ'), + ('á¹—', 'á¹—'), + ('á¹™', 'á¹™'), + ('á¹›', 'á¹›'), + ('á¹', 'á¹'), + ('ṟ', 'ṟ'), + ('ṡ', 'ṡ'), + ('á¹£', 'á¹£'), + ('á¹¥', 'á¹¥'), + ('ṧ', 'ṧ'), + ('ṩ', 'ṩ'), + ('ṫ', 'ṫ'), + ('á¹­', 'á¹­'), + ('ṯ', 'ṯ'), + ('á¹±', 'á¹±'), + ('á¹³', 'á¹³'), + ('á¹µ', 'á¹µ'), + ('á¹·', 'á¹·'), + ('á¹¹', 'á¹¹'), + ('á¹»', 'á¹»'), + ('á¹½', 'á¹½'), + ('ṿ', 'ṿ'), + ('áº', 'áº'), + ('ẃ', 'ẃ'), + ('ẅ', 'ẅ'), + ('ẇ', 'ẇ'), + ('ẉ', 'ẉ'), + ('ẋ', 'ẋ'), + ('áº', 'áº'), + ('áº', 'áº'), + ('ẑ', 'ẑ'), + ('ẓ', 'ẓ'), + ('ẕ', 'áº'), + ('ẟ', 'ẟ'), + ('ạ', 'ạ'), + ('ả', 'ả'), + ('ấ', 'ấ'), + ('ầ', 'ầ'), + ('ẩ', 'ẩ'), + ('ẫ', 'ẫ'), + ('ậ', 'ậ'), + ('ắ', 'ắ'), + ('ằ', 'ằ'), + ('ẳ', 'ẳ'), + ('ẵ', 'ẵ'), + ('ặ', 'ặ'), + ('ẹ', 'ẹ'), + ('ẻ', 'ẻ'), + ('ẽ', 'ẽ'), + ('ế', 'ế'), + ('á»', 'á»'), + ('ể', 'ể'), + ('á»…', 'á»…'), + ('ệ', 'ệ'), + ('ỉ', 'ỉ'), + ('ị', 'ị'), + ('á»', 'á»'), + ('á»', 'á»'), + ('ố', 'ố'), + ('ồ', 'ồ'), + ('ổ', 'ổ'), + ('á»—', 'á»—'), + ('á»™', 'á»™'), + ('á»›', 'á»›'), + ('á»', 'á»'), + ('ở', 'ở'), + ('ỡ', 'ỡ'), + ('ợ', 'ợ'), + ('ụ', 'ụ'), + ('ủ', 'ủ'), + ('ứ', 'ứ'), + ('ừ', 'ừ'), + ('á»­', 'á»­'), + ('ữ', 'ữ'), + ('á»±', 'á»±'), + ('ỳ', 'ỳ'), + ('ỵ', 'ỵ'), + ('á»·', 'á»·'), + ('ỹ', 'ỹ'), + ('á»»', 'á»»'), + ('ỽ', 'ỽ'), + ('ỿ', 'ἇ'), + ('á¼', 'ἕ'), + ('á¼ ', 'ἧ'), + ('á¼°', 'á¼·'), + ('á½€', 'á½…'), + ('á½', 'á½—'), + ('á½ ', 'ὧ'), + ('á½°', 'á½½'), + ('á¾€', 'ᾇ'), + ('á¾', 'á¾—'), + ('á¾ ', 'ᾧ'), + ('á¾°', 'á¾´'), + ('ᾶ', 'á¾·'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'ῇ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿—'), + ('á¿ ', 'ῧ'), + ('ῲ', 'á¿´'), + ('ῶ', 'á¿·'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('â„Š', 'â„Š'), + ('â„Ž', 'â„'), + ('â„“', 'â„“'), + ('ℯ', 'ℯ'), + ('â„´', 'â„´'), + ('ℹ', 'ℹ'), + ('ℼ', 'ℽ'), + ('â…†', 'â…‰'), + ('â…Ž', 'â…Ž'), + ('â…°', 'â…¿'), + ('ↄ', 'ↄ'), + ('â“', 'â“©'), + ('â°°', 'ⱟ'), + ('ⱡ', 'ⱡ'), + ('â±¥', 'ⱦ'), + ('ⱨ', 'ⱨ'), + ('ⱪ', 'ⱪ'), + ('ⱬ', 'ⱬ'), + ('â±±', 'â±±'), + ('â±³', 'â±´'), + ('ⱶ', 'â±½'), + ('â²', 'â²'), + ('ⲃ', 'ⲃ'), + ('â²…', 'â²…'), + ('ⲇ', 'ⲇ'), + ('ⲉ', 'ⲉ'), + ('ⲋ', 'ⲋ'), + ('â²', 'â²'), + ('â²', 'â²'), + ('ⲑ', 'ⲑ'), + ('ⲓ', 'ⲓ'), + ('ⲕ', 'ⲕ'), + ('â²—', 'â²—'), + ('â²™', 'â²™'), + ('â²›', 'â²›'), + ('â²', 'â²'), + ('ⲟ', 'ⲟ'), + ('ⲡ', 'ⲡ'), + ('â²£', 'â²£'), + ('â²¥', 'â²¥'), + ('ⲧ', 'ⲧ'), + ('ⲩ', 'ⲩ'), + ('ⲫ', 'ⲫ'), + ('â²­', 'â²­'), + ('ⲯ', 'ⲯ'), + ('â²±', 'â²±'), + ('â²³', 'â²³'), + ('â²µ', 'â²µ'), + ('â²·', 'â²·'), + ('â²¹', 'â²¹'), + ('â²»', 'â²»'), + ('â²½', 'â²½'), + ('ⲿ', 'ⲿ'), + ('â³', 'â³'), + ('ⳃ', 'ⳃ'), + ('â³…', 'â³…'), + ('ⳇ', 'ⳇ'), + ('ⳉ', 'ⳉ'), + ('ⳋ', 'ⳋ'), + ('â³', 'â³'), + ('â³', 'â³'), + ('ⳑ', 'ⳑ'), + ('ⳓ', 'ⳓ'), + ('ⳕ', 'ⳕ'), + ('â³—', 'â³—'), + ('â³™', 'â³™'), + ('â³›', 'â³›'), + ('â³', 'â³'), + ('ⳟ', 'ⳟ'), + ('ⳡ', 'ⳡ'), + ('â³£', 'ⳤ'), + ('ⳬ', 'ⳬ'), + ('â³®', 'â³®'), + ('â³³', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('ê™', 'ê™'), + ('ꙃ', 'ꙃ'), + ('ê™…', 'ê™…'), + ('ꙇ', 'ꙇ'), + ('ꙉ', 'ꙉ'), + ('ꙋ', 'ꙋ'), + ('ê™', 'ê™'), + ('ê™', 'ê™'), + ('ꙑ', 'ꙑ'), + ('ꙓ', 'ꙓ'), + ('ꙕ', 'ꙕ'), + ('ê™—', 'ê™—'), + ('ê™™', 'ê™™'), + ('ê™›', 'ê™›'), + ('ê™', 'ê™'), + ('ꙟ', 'ꙟ'), + ('ꙡ', 'ꙡ'), + ('ꙣ', 'ꙣ'), + ('ꙥ', 'ꙥ'), + ('ꙧ', 'ꙧ'), + ('ꙩ', 'ꙩ'), + ('ꙫ', 'ꙫ'), + ('ê™­', 'ê™­'), + ('êš', 'êš'), + ('ꚃ', 'ꚃ'), + ('êš…', 'êš…'), + ('ꚇ', 'ꚇ'), + ('ꚉ', 'ꚉ'), + ('êš‹', 'êš‹'), + ('êš', 'êš'), + ('êš', 'êš'), + ('êš‘', 'êš‘'), + ('êš“', 'êš“'), + ('êš•', 'êš•'), + ('êš—', 'êš—'), + ('êš™', 'êš™'), + ('êš›', 'êš'), + ('ꜣ', 'ꜣ'), + ('ꜥ', 'ꜥ'), + ('ꜧ', 'ꜧ'), + ('ꜩ', 'ꜩ'), + ('ꜫ', 'ꜫ'), + ('ꜭ', 'ꜭ'), + ('ꜯ', 'ꜱ'), + ('ꜳ', 'ꜳ'), + ('ꜵ', 'ꜵ'), + ('ꜷ', 'ꜷ'), + ('ꜹ', 'ꜹ'), + ('ꜻ', 'ꜻ'), + ('ꜽ', 'ꜽ'), + ('ꜿ', 'ꜿ'), + ('ê', 'ê'), + ('êƒ', 'êƒ'), + ('ê…', 'ê…'), + ('ê‡', 'ê‡'), + ('ê‰', 'ê‰'), + ('ê‹', 'ê‹'), + ('ê', 'ê'), + ('ê', 'ê'), + ('ê‘', 'ê‘'), + ('ê“', 'ê“'), + ('ê•', 'ê•'), + ('ê—', 'ê—'), + ('ê™', 'ê™'), + ('ê›', 'ê›'), + ('ê', 'ê'), + ('êŸ', 'êŸ'), + ('ê¡', 'ê¡'), + ('ê£', 'ê£'), + ('ê¥', 'ê¥'), + ('ê§', 'ê§'), + ('ê©', 'ê©'), + ('ê«', 'ê«'), + ('ê­', 'ê­'), + ('ê¯', 'ê¸'), + ('êº', 'êº'), + ('ê¼', 'ê¼'), + ('ê¿', 'ê¿'), + ('êž', 'êž'), + ('ꞃ', 'ꞃ'), + ('êž…', 'êž…'), + ('ꞇ', 'ꞇ'), + ('ꞌ', 'ꞌ'), + ('ꞎ', 'ꞎ'), + ('êž‘', 'êž‘'), + ('êž“', 'êž•'), + ('êž—', 'êž—'), + ('êž™', 'êž™'), + ('êž›', 'êž›'), + ('êž', 'êž'), + ('ꞟ', 'ꞟ'), + ('êž¡', 'êž¡'), + ('ꞣ', 'ꞣ'), + ('ꞥ', 'ꞥ'), + ('ꞧ', 'ꞧ'), + ('êž©', 'êž©'), + ('ꞯ', 'ꞯ'), + ('êžµ', 'êžµ'), + ('êž·', 'êž·'), + ('êž¹', 'êž¹'), + ('êž»', 'êž»'), + ('êž½', 'êž½'), + ('êž¿', 'êž¿'), + ('êŸ', 'êŸ'), + ('ꟃ', 'ꟃ'), + ('ꟈ', 'ꟈ'), + ('ꟊ', 'ꟊ'), + ('ꟑ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟕ'), + ('ꟗ', 'ꟗ'), + ('ꟙ', 'ꟙ'), + ('ꟲ', 'ꟴ'), + ('ꟶ', 'ꟶ'), + ('ꟸ', 'ꟺ'), + ('ꬰ', 'ê­š'), + ('ê­œ', 'ê­©'), + ('ê­°', 'ꮿ'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï½', 'z'), + ('ð¨', 'ð‘'), + ('ð“˜', 'ð“»'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ðž€', 'ðž€'), + ('ðžƒ', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð³€', 'ð³²'), + ('ð‘£€', '𑣟'), + ('ð–¹ ', '𖹿'), + ('ðš', 'ð³'), + ('ð‘Ž', 'ð‘”'), + ('ð‘–', 'ð‘§'), + ('ð’‚', 'ð’›'), + ('ð’¶', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð“'), + ('ð“ª', 'ð”ƒ'), + ('ð”ž', 'ð”·'), + ('ð•’', 'ð•«'), + ('ð–†', 'ð–Ÿ'), + ('ð–º', 'ð—“'), + ('ð—®', 'ð˜‡'), + ('ð˜¢', 'ð˜»'), + ('ð™–', 'ð™¯'), + ('ðšŠ', 'ðš¥'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›¡'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ›'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð•'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‰'), + ('ðŸ‹', 'ðŸ‹'), + ('ð¼€', 'ð¼‰'), + ('ð¼‹', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('𞀰', 'ðž­'), + ('𞤢', '𞥃'), +]; + +pub const NUMERIC: &'static [(char, char)] = &[ + ('0', '9'), + ('Ù ', 'Ù©'), + ('Ù«', 'Ù¬'), + ('Û°', 'Û¹'), + ('߀', '߉'), + ('०', '९'), + ('০', '৯'), + ('੦', '੯'), + ('૦', '૯'), + ('à­¦', 'à­¯'), + ('௦', '௯'), + ('౦', '౯'), + ('೦', '೯'), + ('൦', '൯'), + ('à·¦', 'à·¯'), + ('à¹', '๙'), + ('à»', 'à»™'), + ('༠', '༩'), + ('á€', 'á‰'), + ('á‚', 'á‚™'), + ('០', '៩'), + ('á ', 'á ™'), + ('᥆', 'á¥'), + ('á§', '᧙'), + ('᪀', '᪉'), + ('áª', '᪙'), + ('á­', 'á­™'), + ('á®°', '᮹'), + ('á±€', '᱉'), + ('á±', 'á±™'), + ('꘠', '꘩'), + ('ê£', '꣙'), + ('꤀', '꤉'), + ('ê§', '꧙'), + ('꧰', '꧹'), + ('ê©', 'ê©™'), + ('꯰', '꯹'), + ('ï¼', 'ï¼™'), + ('ð’ ', 'ð’©'), + ('ð´°', 'ð´¹'), + ('ð‘¦', 'ð‘¯'), + ('𑃰', '𑃹'), + ('𑄶', 'ð‘„¿'), + ('ð‘‡', '𑇙'), + ('ð‘‹°', 'ð‘‹¹'), + ('ð‘‘', 'ð‘‘™'), + ('ð‘“', 'ð‘“™'), + ('ð‘™', 'ð‘™™'), + ('𑛀', '𑛉'), + ('𑜰', '𑜹'), + ('ð‘£ ', '𑣩'), + ('ð‘¥', 'ð‘¥™'), + ('ð‘±', '𑱙'), + ('ð‘µ', '𑵙'), + ('𑶠', '𑶩'), + ('ð‘½', '𑽙'), + ('ð–© ', 'ð–©©'), + ('ð–«€', '𖫉'), + ('ð–­', 'ð–­™'), + ('ðŸŽ', 'ðŸ¿'), + ('ðž…€', 'ðž…‰'), + ('ðž‹°', '𞋹'), + ('ðž“°', '𞓹'), + ('ðž¥', '𞥙'), + ('🯰', '🯹'), +]; + +pub const OLETTER: &'static [(char, char)] = &[ + ('Æ»', 'Æ»'), + ('Ç€', 'ǃ'), + ('Ê”', 'Ê”'), + ('ʹ', 'Ê¿'), + ('ˆ', 'Ë‘'), + ('ˬ', 'ˬ'), + ('Ë®', 'Ë®'), + ('Í´', 'Í´'), + ('Õ™', 'Õ™'), + ('×', 'ת'), + ('ׯ', '׳'), + ('Ø ', 'ÙŠ'), + ('Ù®', 'Ù¯'), + ('Ù±', 'Û“'), + ('Û•', 'Û•'), + ('Û¥', 'Û¦'), + ('Û®', 'Û¯'), + ('Ûº', 'Û¼'), + ('Û¿', 'Û¿'), + ('Ü', 'Ü'), + ('Ü’', 'ܯ'), + ('Ý', 'Þ¥'), + ('Þ±', 'Þ±'), + ('ߊ', 'ߪ'), + ('ß´', 'ßµ'), + ('ߺ', 'ߺ'), + ('à €', 'à •'), + ('à š', 'à š'), + ('à ¤', 'à ¤'), + ('à ¨', 'à ¨'), + ('à¡€', 'ࡘ'), + ('à¡ ', 'ࡪ'), + ('à¡°', 'ࢇ'), + ('ࢉ', 'ࢎ'), + ('ࢠ', 'ࣉ'), + ('ऄ', 'ह'), + ('ऽ', 'ऽ'), + ('à¥', 'à¥'), + ('क़', 'ॡ'), + ('ॱ', 'ঀ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('ঽ', 'ঽ'), + ('ৎ', 'ৎ'), + ('ড়', 'à§'), + ('য়', 'ৡ'), + ('ৰ', 'ৱ'), + ('ৼ', 'ৼ'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('ੲ', 'à©´'), + ('અ', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('ઽ', 'ઽ'), + ('à«', 'à«'), + ('à« ', 'à«¡'), + ('ૹ', 'ૹ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), + ('ଽ', 'ଽ'), + ('à­œ', 'à­'), + ('à­Ÿ', 'à­¡'), + ('à­±', 'à­±'), + ('ஃ', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'ஹ'), + ('à¯', 'à¯'), + ('à°…', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°¹'), + ('à°½', 'à°½'), + ('ౘ', 'ౚ'), + ('à±', 'à±'), + ('à± ', 'ౡ'), + ('ಀ', 'ಀ'), + ('ಅ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('ಽ', 'ಽ'), + ('à³', 'ೞ'), + ('à³ ', 'ೡ'), + ('à³±', 'à³²'), + ('à´„', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', 'à´º'), + ('à´½', 'à´½'), + ('ൎ', 'ൎ'), + ('ൔ', 'ൖ'), + ('ൟ', 'ൡ'), + ('ൺ', 'ൿ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('à¸', 'ะ'), + ('า', 'ำ'), + ('เ', 'ๆ'), + ('àº', 'ຂ'), + ('ຄ', 'ຄ'), + ('ຆ', 'ຊ'), + ('ຌ', 'ຣ'), + ('ລ', 'ລ'), + ('ວ', 'ະ'), + ('າ', 'ຳ'), + ('ຽ', 'ຽ'), + ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), + ('ໜ', 'ໟ'), + ('ༀ', 'ༀ'), + ('ཀ', 'ཇ'), + ('ཉ', 'ཬ'), + ('ྈ', 'ྌ'), + ('က', 'ဪ'), + ('ဿ', 'ဿ'), + ('á', 'á•'), + ('áš', 'á'), + ('á¡', 'á¡'), + ('á¥', 'á¦'), + ('á®', 'á°'), + ('áµ', 'á‚'), + ('á‚Ž', 'á‚Ž'), + ('áƒ', 'ჺ'), + ('ჽ', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹–'), + ('ዘ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'áš'), + ('ᎀ', 'áŽ'), + ('á', 'ᙬ'), + ('ᙯ', 'ᙿ'), + ('áš', 'ášš'), + ('áš ', 'ᛪ'), + ('á›®', 'ᛸ'), + ('ᜀ', 'ᜑ'), + ('ᜟ', 'ᜱ'), + ('á€', 'á‘'), + ('á ', 'á¬'), + ('á®', 'á°'), + ('ក', 'áž³'), + ('ៗ', 'ៗ'), + ('ៜ', 'ៜ'), + ('á  ', 'ᡸ'), + ('ᢀ', 'ᢄ'), + ('ᢇ', 'ᢨ'), + ('ᢪ', 'ᢪ'), + ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), + ('á¥', 'ᥭ'), + ('ᥰ', 'ᥴ'), + ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), + ('ᨀ', 'ᨖ'), + ('ᨠ', 'á©”'), + ('ᪧ', 'ᪧ'), + ('ᬅ', 'ᬳ'), + ('á­…', 'á­Œ'), + ('ᮃ', 'á® '), + ('á®®', 'ᮯ'), + ('ᮺ', 'ᯥ'), + ('á°€', 'á°£'), + ('á±', 'á±'), + ('ᱚ', 'á±½'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('ᳩ', 'ᳬ'), + ('á³®', 'á³³'), + ('á³µ', 'ᳶ'), + ('ᳺ', 'ᳺ'), + ('ℵ', 'ℸ'), + ('ↀ', 'ↂ'), + ('ↅ', 'ↈ'), + ('â´°', 'ⵧ'), + ('ⵯ', 'ⵯ'), + ('ⶀ', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('ⸯ', 'ⸯ'), + ('々', '〇'), + ('〡', '〩'), + ('〱', '〵'), + ('〸', '〼'), + ('ã', 'ã‚–'), + ('ã‚', 'ã‚Ÿ'), + ('ã‚¡', 'ヺ'), + ('ー', 'ヿ'), + ('ã„…', 'ㄯ'), + ('ㄱ', 'ㆎ'), + ('ㆠ', 'ㆿ'), + ('ㇰ', 'ㇿ'), + ('ã€', '䶿'), + ('一', 'ê’Œ'), + ('ê“', 'ꓽ'), + ('ꔀ', 'ꘌ'), + ('ê˜', 'ꘟ'), + ('ꘪ', 'ꘫ'), + ('ê™®', 'ê™®'), + ('ꙿ', 'ꙿ'), + ('êš ', 'ꛯ'), + ('ꜗ', 'ꜟ'), + ('ꞈ', 'ꞈ'), + ('êž', 'êž'), + ('ꟷ', 'ꟷ'), + ('ꟻ', 'ê '), + ('ê ƒ', 'ê …'), + ('ê ‡', 'ê Š'), + ('ê Œ', 'ê ¢'), + ('ê¡€', 'ꡳ'), + ('ꢂ', 'ꢳ'), + ('ꣲ', 'ꣷ'), + ('ꣻ', 'ꣻ'), + ('ꣽ', 'ꣾ'), + ('ꤊ', 'ꤥ'), + ('ꤰ', 'ꥆ'), + ('ꥠ', 'ꥼ'), + ('ꦄ', 'ꦲ'), + ('ê§', 'ê§'), + ('ꧠ', 'ꧤ'), + ('ꧦ', 'ꧯ'), + ('ꧺ', 'ꧾ'), + ('ꨀ', 'ꨨ'), + ('ê©€', 'ê©‚'), + ('ê©„', 'ê©‹'), + ('ê© ', 'ꩶ'), + ('ꩺ', 'ꩺ'), + ('ꩾ', 'ꪯ'), + ('ꪱ', 'ꪱ'), + ('ꪵ', 'ꪶ'), + ('ꪹ', 'ꪽ'), + ('ê«€', 'ê«€'), + ('ê«‚', 'ê«‚'), + ('ê«›', 'ê«'), + ('ê« ', 'ꫪ'), + ('ꫲ', 'ê«´'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('ꯀ', 'ꯢ'), + ('ê°€', '힣'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), + ('ï©°', 'ï«™'), + ('ï¬', 'ï¬'), + ('ײַ', 'ﬨ'), + ('שׁ', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', 'ï®±'), + ('ﯓ', 'ï´½'), + ('ïµ', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·°', 'ï·»'), + ('ï¹°', 'ï¹´'), + ('ﹶ', 'ﻼ'), + ('ヲ', 'ï¾'), + ('ï¾ ', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), + ('ð…€', 'ð…´'), + ('ðŠ€', 'ðŠœ'), + ('ðŠ ', 'ð‹'), + ('ðŒ€', 'ðŒŸ'), + ('ðŒ­', 'ðŠ'), + ('ð', 'ðµ'), + ('ðŽ€', 'ðŽ'), + ('ðŽ ', 'ðƒ'), + ('ðˆ', 'ð'), + ('ð‘', 'ð•'), + ('ð‘', 'ð’'), + ('ð”€', 'ð”§'), + ('ð”°', 'ð•£'), + ('ð˜€', 'ðœ¶'), + ('ð€', 'ð•'), + ('ð ', 'ð§'), + ('ðž', 'ðž‚'), + ('ð €', 'ð …'), + ('ð ˆ', 'ð ˆ'), + ('ð Š', 'ð µ'), + ('ð ·', 'ð ¸'), + ('ð ¼', 'ð ¼'), + ('ð ¿', 'ð¡•'), + ('ð¡ ', 'ð¡¶'), + ('ð¢€', 'ð¢ž'), + ('ð£ ', 'ð£²'), + ('ð£´', 'ð£µ'), + ('ð¤€', 'ð¤•'), + ('ð¤ ', 'ð¤¹'), + ('ð¦€', 'ð¦·'), + ('ð¦¾', 'ð¦¿'), + ('ð¨€', 'ð¨€'), + ('ð¨', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨µ'), + ('ð© ', 'ð©¼'), + ('ðª€', 'ðªœ'), + ('ð«€', 'ð«‡'), + ('ð«‰', 'ð«¤'), + ('ð¬€', 'ð¬µ'), + ('ð­€', 'ð­•'), + ('ð­ ', 'ð­²'), + ('ð®€', 'ð®‘'), + ('ð°€', 'ð±ˆ'), + ('ð´€', 'ð´£'), + ('ðº€', 'ðº©'), + ('ðº°', 'ðº±'), + ('ð¼€', 'ð¼œ'), + ('ð¼§', 'ð¼§'), + ('ð¼°', 'ð½…'), + ('ð½°', 'ð¾'), + ('ð¾°', 'ð¿„'), + ('ð¿ ', 'ð¿¶'), + ('𑀃', 'ð‘€·'), + ('ð‘±', 'ð‘²'), + ('ð‘µ', 'ð‘µ'), + ('𑂃', '𑂯'), + ('ð‘ƒ', '𑃨'), + ('𑄃', '𑄦'), + ('ð‘…„', 'ð‘…„'), + ('ð‘…‡', 'ð‘…‡'), + ('ð‘…', 'ð‘…²'), + ('ð‘…¶', 'ð‘…¶'), + ('𑆃', '𑆲'), + ('ð‘‡', '𑇄'), + ('𑇚', '𑇚'), + ('𑇜', '𑇜'), + ('𑈀', '𑈑'), + ('𑈓', '𑈫'), + ('𑈿', '𑉀'), + ('ð‘Š€', '𑊆'), + ('𑊈', '𑊈'), + ('ð‘ŠŠ', 'ð‘Š'), + ('ð‘Š', 'ð‘Š'), + ('ð‘ŠŸ', '𑊨'), + ('ð‘Š°', 'ð‘‹ž'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('𑌽', '𑌽'), + ('ð‘', 'ð‘'), + ('ð‘', 'ð‘¡'), + ('ð‘€', 'ð‘´'), + ('𑑇', 'ð‘‘Š'), + ('ð‘‘Ÿ', 'ð‘‘¡'), + ('ð‘’€', 'ð‘’¯'), + ('ð‘“„', 'ð‘“…'), + ('𑓇', '𑓇'), + ('ð‘–€', 'ð‘–®'), + ('ð‘—˜', 'ð‘—›'), + ('𑘀', '𑘯'), + ('ð‘™„', 'ð‘™„'), + ('𑚀', '𑚪'), + ('𑚸', '𑚸'), + ('𑜀', '𑜚'), + ('ð‘€', 'ð‘†'), + ('ð‘ €', 'ð‘ «'), + ('𑣿', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤯'), + ('𑤿', '𑤿'), + ('ð‘¥', 'ð‘¥'), + ('𑦠', '𑦧'), + ('𑦪', 'ð‘§'), + ('𑧡', '𑧡'), + ('𑧣', '𑧣'), + ('𑨀', '𑨀'), + ('𑨋', '𑨲'), + ('𑨺', '𑨺'), + ('ð‘©', 'ð‘©'), + ('ð‘©œ', '𑪉'), + ('ð‘ª', 'ð‘ª'), + ('𑪰', '𑫸'), + ('ð‘°€', 'ð‘°ˆ'), + ('ð‘°Š', 'ð‘°®'), + ('𑱀', '𑱀'), + ('𑱲', 'ð‘²'), + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', 'ð‘´°'), + ('𑵆', '𑵆'), + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶉'), + ('𑶘', '𑶘'), + ('ð‘» ', 'ð‘»²'), + ('𑼂', '𑼂'), + ('𑼄', 'ð‘¼'), + ('𑼒', '𑼳'), + ('𑾰', '𑾰'), + ('ð’€€', 'ð’Ž™'), + ('ð’€', 'ð’‘®'), + ('ð’’€', '𒕃'), + ('ð’¾', 'ð’¿°'), + ('ð“€€', 'ð“¯'), + ('ð“‘', '𓑆'), + ('ð”€', '𔙆'), + ('ð– €', '𖨸'), + ('ð–©€', 'ð–©ž'), + ('ð–©°', '𖪾'), + ('ð–«', 'ð–«­'), + ('𖬀', '𖬯'), + ('ð–­€', 'ð–­ƒ'), + ('ð–­£', 'ð–­·'), + ('ð–­½', 'ð–®'), + ('ð–¼€', '𖽊'), + ('ð–½', 'ð–½'), + ('𖾓', '𖾟'), + ('ð–¿ ', 'ð–¿¡'), + ('ð–¿£', 'ð–¿£'), + ('ð—€€', '𘟷'), + ('𘠀', '𘳕'), + ('𘴀', '𘴈'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𛀀', '𛄢'), + ('𛄲', '𛄲'), + ('ð›…', 'ð›…’'), + ('ð›…•', 'ð›…•'), + ('ð›…¤', 'ð›…§'), + ('ð›…°', '𛋻'), + ('ð›°€', '𛱪'), + ('ð›±°', 'ð›±¼'), + ('𛲀', '𛲈'), + ('ð›²', '𛲙'), + ('ð¼Š', 'ð¼Š'), + ('ðž„€', '𞄬'), + ('ðž„·', '𞄽'), + ('ðž…Ž', 'ðž…Ž'), + ('ðžŠ', '𞊭'), + ('ðž‹€', 'ðž‹«'), + ('ðž“', 'ðž“«'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), + ('ðž €', '𞣄'), + ('𞥋', '𞥋'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('ð €€', '𪛟'), + ('𪜀', '𫜹'), + ('ð«€', 'ð« '), + ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), + ('丽', 'ð¯¨'), + ('ð°€€', 'ð±Š'), + ('ð±', '𲎯'), +]; + +pub const SCONTINUE: &'static [(char, char)] = &[ + (',', '-'), + (':', ':'), + ('Õ', 'Õ'), + ('ØŒ', 'Ø'), + ('߸', '߸'), + ('á ‚', 'á ‚'), + ('á ˆ', 'á ˆ'), + ('–', '—'), + ('ã€', 'ã€'), + ('ï¸', '︑'), + ('︓', '︓'), + ('︱', '︲'), + ('ï¹', '﹑'), + ('﹕', '﹕'), + ('﹘', '﹘'), + ('ï¹£', 'ï¹£'), + (',', 'ï¼'), + (':', ':'), + ('、', '、'), +]; + +pub const STERM: &'static [(char, char)] = &[ + ('!', '!'), + ('?', '?'), + ('Ö‰', 'Ö‰'), + ('Ø', 'ØŸ'), + ('Û”', 'Û”'), + ('Ü€', 'Ü‚'), + ('ß¹', 'ß¹'), + ('à ·', 'à ·'), + ('à ¹', 'à ¹'), + ('à ½', 'à ¾'), + ('।', '॥'), + ('áŠ', 'á‹'), + ('á¢', 'á¢'), + ('á§', 'á¨'), + ('á™®', 'á™®'), + ('᜵', '᜶'), + ('á ƒ', 'á ƒ'), + ('á ‰', 'á ‰'), + ('᥄', '᥅'), + ('᪨', '᪫'), + ('á­š', 'á­›'), + ('á­ž', 'á­Ÿ'), + ('á­½', 'á­¾'), + ('á°»', 'á°¼'), + ('á±¾', '᱿'), + ('‼', '‽'), + ('â‡', 'â‰'), + ('⸮', '⸮'), + ('⸼', '⸼'), + ('⹓', 'â¹”'), + ('。', '。'), + ('ê“¿', 'ê“¿'), + ('꘎', 'ê˜'), + ('꛳', '꛳'), + ('ê›·', 'ê›·'), + ('꡶', 'ê¡·'), + ('꣎', 'ê£'), + ('꤯', '꤯'), + ('꧈', '꧉'), + ('ê©', 'ê©Ÿ'), + ('ê«°', '꫱'), + ('꯫', '꯫'), + ('ï¹–', 'ï¹—'), + ('ï¼', 'ï¼'), + ('?', '?'), + ('。', '。'), + ('ð©–', 'ð©—'), + ('ð½•', 'ð½™'), + ('ð¾†', 'ð¾‰'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‚¾', 'ð‘ƒ'), + ('ð‘…', 'ð‘…ƒ'), + ('𑇅', '𑇆'), + ('ð‘‡', 'ð‘‡'), + ('𑇞', '𑇟'), + ('𑈸', '𑈹'), + ('𑈻', '𑈼'), + ('ð‘Š©', 'ð‘Š©'), + ('ð‘‘‹', 'ð‘‘Œ'), + ('ð‘—‚', 'ð‘—ƒ'), + ('ð‘—‰', 'ð‘——'), + ('ð‘™', 'ð‘™‚'), + ('𑜼', '𑜾'), + ('𑥄', '𑥄'), + ('𑥆', '𑥆'), + ('ð‘©‚', '𑩃'), + ('𑪛', '𑪜'), + ('ð‘±', '𑱂'), + ('ð‘»·', '𑻸'), + ('𑽃', '𑽄'), + ('ð–©®', '𖩯'), + ('ð–«µ', 'ð–«µ'), + ('ð–¬·', '𖬸'), + ('ð–­„', 'ð–­„'), + ('𖺘', '𖺘'), + ('𛲟', '𛲟'), + ('ðªˆ', 'ðªˆ'), +]; + +pub const SEP: &'static [(char, char)] = + &[('\u{85}', '\u{85}'), ('\u{2028}', '\u{2029}')]; + +pub const SP: &'static [(char, char)] = &[ + ('\t', '\t'), + ('\u{b}', '\u{c}'), + (' ', ' '), + ('\u{a0}', '\u{a0}'), + ('\u{1680}', '\u{1680}'), + ('\u{2000}', '\u{200a}'), + ('\u{202f}', '\u{202f}'), + ('\u{205f}', '\u{205f}'), + ('\u{3000}', '\u{3000}'), +]; + +pub const UPPER: &'static [(char, char)] = &[ + ('A', 'Z'), + ('À', 'Ö'), + ('Ø', 'Þ'), + ('Ä€', 'Ä€'), + ('Ä‚', 'Ä‚'), + ('Ä„', 'Ä„'), + ('Ć', 'Ć'), + ('Ĉ', 'Ĉ'), + ('ÄŠ', 'ÄŠ'), + ('ÄŒ', 'ÄŒ'), + ('ÄŽ', 'ÄŽ'), + ('Ä', 'Ä'), + ('Ä’', 'Ä’'), + ('Ä”', 'Ä”'), + ('Ä–', 'Ä–'), + ('Ę', 'Ę'), + ('Äš', 'Äš'), + ('Äœ', 'Äœ'), + ('Äž', 'Äž'), + ('Ä ', 'Ä '), + ('Ä¢', 'Ä¢'), + ('Ĥ', 'Ĥ'), + ('Ħ', 'Ħ'), + ('Ĩ', 'Ĩ'), + ('Ī', 'Ī'), + ('Ĭ', 'Ĭ'), + ('Ä®', 'Ä®'), + ('Ä°', 'Ä°'), + ('IJ', 'IJ'), + ('Ä´', 'Ä´'), + ('Ķ', 'Ķ'), + ('Ĺ', 'Ĺ'), + ('Ä»', 'Ä»'), + ('Ľ', 'Ľ'), + ('Ä¿', 'Ä¿'), + ('Å', 'Å'), + ('Ń', 'Ń'), + ('Å…', 'Å…'), + ('Ň', 'Ň'), + ('ÅŠ', 'ÅŠ'), + ('ÅŒ', 'ÅŒ'), + ('ÅŽ', 'ÅŽ'), + ('Å', 'Å'), + ('Å’', 'Å’'), + ('Å”', 'Å”'), + ('Å–', 'Å–'), + ('Ř', 'Ř'), + ('Åš', 'Åš'), + ('Åœ', 'Åœ'), + ('Åž', 'Åž'), + ('Å ', 'Å '), + ('Å¢', 'Å¢'), + ('Ť', 'Ť'), + ('Ŧ', 'Ŧ'), + ('Ũ', 'Ũ'), + ('Ū', 'Ū'), + ('Ŭ', 'Ŭ'), + ('Å®', 'Å®'), + ('Å°', 'Å°'), + ('Ų', 'Ų'), + ('Å´', 'Å´'), + ('Ŷ', 'Ŷ'), + ('Ÿ', 'Ź'), + ('Å»', 'Å»'), + ('Ž', 'Ž'), + ('Æ', 'Æ‚'), + ('Æ„', 'Æ„'), + ('Ɔ', 'Ƈ'), + ('Ɖ', 'Æ‹'), + ('ÆŽ', 'Æ‘'), + ('Æ“', 'Æ”'), + ('Æ–', 'Ƙ'), + ('Æœ', 'Æ'), + ('ÆŸ', 'Æ '), + ('Æ¢', 'Æ¢'), + ('Ƥ', 'Ƥ'), + ('Ʀ', 'Ƨ'), + ('Æ©', 'Æ©'), + ('Ƭ', 'Ƭ'), + ('Æ®', 'Ư'), + ('Ʊ', 'Ƴ'), + ('Ƶ', 'Ƶ'), + ('Æ·', 'Ƹ'), + ('Ƽ', 'Ƽ'), + ('Ç„', 'Ç…'), + ('LJ', 'Lj'), + ('ÇŠ', 'Ç‹'), + ('Ç', 'Ç'), + ('Ç', 'Ç'), + ('Ç‘', 'Ç‘'), + ('Ç“', 'Ç“'), + ('Ç•', 'Ç•'), + ('Ç—', 'Ç—'), + ('Ç™', 'Ç™'), + ('Ç›', 'Ç›'), + ('Çž', 'Çž'), + ('Ç ', 'Ç '), + ('Ç¢', 'Ç¢'), + ('Ǥ', 'Ǥ'), + ('Ǧ', 'Ǧ'), + ('Ǩ', 'Ǩ'), + ('Ǫ', 'Ǫ'), + ('Ǭ', 'Ǭ'), + ('Ç®', 'Ç®'), + ('DZ', 'Dz'), + ('Ç´', 'Ç´'), + ('Ƕ', 'Ǹ'), + ('Ǻ', 'Ǻ'), + ('Ǽ', 'Ǽ'), + ('Ǿ', 'Ǿ'), + ('È€', 'È€'), + ('È‚', 'È‚'), + ('È„', 'È„'), + ('Ȇ', 'Ȇ'), + ('Ȉ', 'Ȉ'), + ('ÈŠ', 'ÈŠ'), + ('ÈŒ', 'ÈŒ'), + ('ÈŽ', 'ÈŽ'), + ('È', 'È'), + ('È’', 'È’'), + ('È”', 'È”'), + ('È–', 'È–'), + ('Ș', 'Ș'), + ('Èš', 'Èš'), + ('Èœ', 'Èœ'), + ('Èž', 'Èž'), + ('È ', 'È '), + ('È¢', 'È¢'), + ('Ȥ', 'Ȥ'), + ('Ȧ', 'Ȧ'), + ('Ȩ', 'Ȩ'), + ('Ȫ', 'Ȫ'), + ('Ȭ', 'Ȭ'), + ('È®', 'È®'), + ('È°', 'È°'), + ('Ȳ', 'Ȳ'), + ('Ⱥ', 'È»'), + ('Ƚ', 'Ⱦ'), + ('É', 'É'), + ('Ƀ', 'Ɇ'), + ('Ɉ', 'Ɉ'), + ('ÉŠ', 'ÉŠ'), + ('ÉŒ', 'ÉŒ'), + ('ÉŽ', 'ÉŽ'), + ('Í°', 'Í°'), + ('Ͳ', 'Ͳ'), + ('Ͷ', 'Ͷ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Î'), + ('Α', 'Ρ'), + ('Σ', 'Ϋ'), + ('Ï', 'Ï'), + ('Ï’', 'Ï”'), + ('Ϙ', 'Ϙ'), + ('Ïš', 'Ïš'), + ('Ïœ', 'Ïœ'), + ('Ïž', 'Ïž'), + ('Ï ', 'Ï '), + ('Ï¢', 'Ï¢'), + ('Ϥ', 'Ϥ'), + ('Ϧ', 'Ϧ'), + ('Ϩ', 'Ϩ'), + ('Ϫ', 'Ϫ'), + ('Ϭ', 'Ϭ'), + ('Ï®', 'Ï®'), + ('Ï´', 'Ï´'), + ('Ï·', 'Ï·'), + ('Ϲ', 'Ϻ'), + ('Ͻ', 'Я'), + ('Ñ ', 'Ñ '), + ('Ñ¢', 'Ñ¢'), + ('Ѥ', 'Ѥ'), + ('Ѧ', 'Ѧ'), + ('Ѩ', 'Ѩ'), + ('Ѫ', 'Ѫ'), + ('Ѭ', 'Ѭ'), + ('Ñ®', 'Ñ®'), + ('Ñ°', 'Ñ°'), + ('Ѳ', 'Ѳ'), + ('Ñ´', 'Ñ´'), + ('Ѷ', 'Ѷ'), + ('Ѹ', 'Ѹ'), + ('Ѻ', 'Ѻ'), + ('Ѽ', 'Ѽ'), + ('Ѿ', 'Ѿ'), + ('Ò€', 'Ò€'), + ('ÒŠ', 'ÒŠ'), + ('ÒŒ', 'ÒŒ'), + ('ÒŽ', 'ÒŽ'), + ('Ò', 'Ò'), + ('Ò’', 'Ò’'), + ('Ò”', 'Ò”'), + ('Ò–', 'Ò–'), + ('Ò˜', 'Ò˜'), + ('Òš', 'Òš'), + ('Òœ', 'Òœ'), + ('Òž', 'Òž'), + ('Ò ', 'Ò '), + ('Ò¢', 'Ò¢'), + ('Ò¤', 'Ò¤'), + ('Ò¦', 'Ò¦'), + ('Ò¨', 'Ò¨'), + ('Òª', 'Òª'), + ('Ò¬', 'Ò¬'), + ('Ò®', 'Ò®'), + ('Ò°', 'Ò°'), + ('Ò²', 'Ò²'), + ('Ò´', 'Ò´'), + ('Ò¶', 'Ò¶'), + ('Ò¸', 'Ò¸'), + ('Òº', 'Òº'), + ('Ò¼', 'Ò¼'), + ('Ò¾', 'Ò¾'), + ('Ó€', 'Ó'), + ('Óƒ', 'Óƒ'), + ('Ó…', 'Ó…'), + ('Ó‡', 'Ó‡'), + ('Ó‰', 'Ó‰'), + ('Ó‹', 'Ó‹'), + ('Ó', 'Ó'), + ('Ó', 'Ó'), + ('Ó’', 'Ó’'), + ('Ó”', 'Ó”'), + ('Ó–', 'Ó–'), + ('Ó˜', 'Ó˜'), + ('Óš', 'Óš'), + ('Óœ', 'Óœ'), + ('Óž', 'Óž'), + ('Ó ', 'Ó '), + ('Ó¢', 'Ó¢'), + ('Ó¤', 'Ó¤'), + ('Ó¦', 'Ó¦'), + ('Ó¨', 'Ó¨'), + ('Óª', 'Óª'), + ('Ó¬', 'Ó¬'), + ('Ó®', 'Ó®'), + ('Ó°', 'Ó°'), + ('Ó²', 'Ó²'), + ('Ó´', 'Ó´'), + ('Ó¶', 'Ó¶'), + ('Ó¸', 'Ó¸'), + ('Óº', 'Óº'), + ('Ó¼', 'Ó¼'), + ('Ó¾', 'Ó¾'), + ('Ô€', 'Ô€'), + ('Ô‚', 'Ô‚'), + ('Ô„', 'Ô„'), + ('Ô†', 'Ô†'), + ('Ôˆ', 'Ôˆ'), + ('ÔŠ', 'ÔŠ'), + ('ÔŒ', 'ÔŒ'), + ('ÔŽ', 'ÔŽ'), + ('Ô', 'Ô'), + ('Ô’', 'Ô’'), + ('Ô”', 'Ô”'), + ('Ô–', 'Ô–'), + ('Ô˜', 'Ô˜'), + ('Ôš', 'Ôš'), + ('Ôœ', 'Ôœ'), + ('Ôž', 'Ôž'), + ('Ô ', 'Ô '), + ('Ô¢', 'Ô¢'), + ('Ô¤', 'Ô¤'), + ('Ô¦', 'Ô¦'), + ('Ô¨', 'Ô¨'), + ('Ôª', 'Ôª'), + ('Ô¬', 'Ô¬'), + ('Ô®', 'Ô®'), + ('Ô±', 'Õ–'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('Ꭰ', 'áµ'), + ('Ḁ', 'Ḁ'), + ('Ḃ', 'Ḃ'), + ('Ḅ', 'Ḅ'), + ('Ḇ', 'Ḇ'), + ('Ḉ', 'Ḉ'), + ('Ḋ', 'Ḋ'), + ('Ḍ', 'Ḍ'), + ('Ḏ', 'Ḏ'), + ('á¸', 'á¸'), + ('Ḓ', 'Ḓ'), + ('Ḕ', 'Ḕ'), + ('Ḗ', 'Ḗ'), + ('Ḙ', 'Ḙ'), + ('Ḛ', 'Ḛ'), + ('Ḝ', 'Ḝ'), + ('Ḟ', 'Ḟ'), + ('Ḡ', 'Ḡ'), + ('Ḣ', 'Ḣ'), + ('Ḥ', 'Ḥ'), + ('Ḧ', 'Ḧ'), + ('Ḩ', 'Ḩ'), + ('Ḫ', 'Ḫ'), + ('Ḭ', 'Ḭ'), + ('Ḯ', 'Ḯ'), + ('Ḱ', 'Ḱ'), + ('Ḳ', 'Ḳ'), + ('Ḵ', 'Ḵ'), + ('Ḷ', 'Ḷ'), + ('Ḹ', 'Ḹ'), + ('Ḻ', 'Ḻ'), + ('Ḽ', 'Ḽ'), + ('Ḿ', 'Ḿ'), + ('á¹€', 'á¹€'), + ('Ṃ', 'Ṃ'), + ('Ṅ', 'Ṅ'), + ('Ṇ', 'Ṇ'), + ('Ṉ', 'Ṉ'), + ('Ṋ', 'Ṋ'), + ('Ṍ', 'Ṍ'), + ('Ṏ', 'Ṏ'), + ('á¹', 'á¹'), + ('á¹’', 'á¹’'), + ('á¹”', 'á¹”'), + ('á¹–', 'á¹–'), + ('Ṙ', 'Ṙ'), + ('Ṛ', 'Ṛ'), + ('Ṝ', 'Ṝ'), + ('Ṟ', 'Ṟ'), + ('á¹ ', 'á¹ '), + ('á¹¢', 'á¹¢'), + ('Ṥ', 'Ṥ'), + ('Ṧ', 'Ṧ'), + ('Ṩ', 'Ṩ'), + ('Ṫ', 'Ṫ'), + ('Ṭ', 'Ṭ'), + ('á¹®', 'á¹®'), + ('á¹°', 'á¹°'), + ('á¹²', 'á¹²'), + ('á¹´', 'á¹´'), + ('Ṷ', 'Ṷ'), + ('Ṹ', 'Ṹ'), + ('Ṻ', 'Ṻ'), + ('á¹¼', 'á¹¼'), + ('á¹¾', 'á¹¾'), + ('Ẁ', 'Ẁ'), + ('Ẃ', 'Ẃ'), + ('Ẅ', 'Ẅ'), + ('Ẇ', 'Ẇ'), + ('Ẉ', 'Ẉ'), + ('Ẋ', 'Ẋ'), + ('Ẍ', 'Ẍ'), + ('Ẏ', 'Ẏ'), + ('áº', 'áº'), + ('Ẓ', 'Ẓ'), + ('Ẕ', 'Ẕ'), + ('ẞ', 'ẞ'), + ('Ạ', 'Ạ'), + ('Ả', 'Ả'), + ('Ấ', 'Ấ'), + ('Ầ', 'Ầ'), + ('Ẩ', 'Ẩ'), + ('Ẫ', 'Ẫ'), + ('Ậ', 'Ậ'), + ('Ắ', 'Ắ'), + ('Ằ', 'Ằ'), + ('Ẳ', 'Ẳ'), + ('Ẵ', 'Ẵ'), + ('Ặ', 'Ặ'), + ('Ẹ', 'Ẹ'), + ('Ẻ', 'Ẻ'), + ('Ẽ', 'Ẽ'), + ('Ế', 'Ế'), + ('Ề', 'Ề'), + ('Ể', 'Ể'), + ('Ễ', 'Ễ'), + ('Ệ', 'Ệ'), + ('Ỉ', 'Ỉ'), + ('Ị', 'Ị'), + ('Ọ', 'Ọ'), + ('Ỏ', 'Ỏ'), + ('á»', 'á»'), + ('á»’', 'á»’'), + ('á»”', 'á»”'), + ('á»–', 'á»–'), + ('Ộ', 'Ộ'), + ('Ớ', 'Ớ'), + ('Ờ', 'Ờ'), + ('Ở', 'Ở'), + ('á» ', 'á» '), + ('Ợ', 'Ợ'), + ('Ụ', 'Ụ'), + ('Ủ', 'Ủ'), + ('Ứ', 'Ứ'), + ('Ừ', 'Ừ'), + ('Ử', 'Ử'), + ('á»®', 'á»®'), + ('á»°', 'á»°'), + ('Ỳ', 'Ỳ'), + ('á»´', 'á»´'), + ('Ỷ', 'Ỷ'), + ('Ỹ', 'Ỹ'), + ('Ỻ', 'Ỻ'), + ('Ỽ', 'Ỽ'), + ('Ỿ', 'Ỿ'), + ('Ἀ', 'á¼'), + ('Ἐ', 'á¼'), + ('Ἠ', 'Ἧ'), + ('Ἰ', 'Ἷ'), + ('Ὀ', 'á½'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'Ὗ'), + ('Ὠ', 'Ὧ'), + ('ᾈ', 'á¾'), + ('ᾘ', 'ᾟ'), + ('ᾨ', 'ᾯ'), + ('Ᾰ', 'á¾¼'), + ('Ὲ', 'á¿Œ'), + ('Ῐ', 'á¿›'), + ('Ῠ', 'Ῥ'), + ('Ὸ', 'ῼ'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„‹', 'â„'), + ('â„', 'â„’'), + ('â„•', 'â„•'), + ('â„™', 'â„'), + ('ℤ', 'ℤ'), + ('Ω', 'Ω'), + ('ℨ', 'ℨ'), + ('K', 'â„­'), + ('â„°', 'ℳ'), + ('ℾ', 'â„¿'), + ('â……', 'â……'), + ('â… ', 'â…¯'), + ('Ↄ', 'Ↄ'), + ('â’¶', 'â“'), + ('â°€', 'â°¯'), + ('â± ', 'â± '), + ('â±¢', 'Ɽ'), + ('Ⱨ', 'Ⱨ'), + ('Ⱪ', 'Ⱪ'), + ('Ⱬ', 'Ⱬ'), + ('â±­', 'â±°'), + ('â±²', 'â±²'), + ('â±µ', 'â±µ'), + ('â±¾', 'â²€'), + ('Ⲃ', 'Ⲃ'), + ('Ⲅ', 'Ⲅ'), + ('Ⲇ', 'Ⲇ'), + ('Ⲉ', 'Ⲉ'), + ('Ⲋ', 'Ⲋ'), + ('Ⲍ', 'Ⲍ'), + ('Ⲏ', 'Ⲏ'), + ('â²', 'â²'), + ('â²’', 'â²’'), + ('â²”', 'â²”'), + ('â²–', 'â²–'), + ('Ⲙ', 'Ⲙ'), + ('Ⲛ', 'Ⲛ'), + ('Ⲝ', 'Ⲝ'), + ('Ⲟ', 'Ⲟ'), + ('â² ', 'â² '), + ('â²¢', 'â²¢'), + ('Ⲥ', 'Ⲥ'), + ('Ⲧ', 'Ⲧ'), + ('Ⲩ', 'Ⲩ'), + ('Ⲫ', 'Ⲫ'), + ('Ⲭ', 'Ⲭ'), + ('â²®', 'â²®'), + ('â²°', 'â²°'), + ('â²²', 'â²²'), + ('â²´', 'â²´'), + ('Ⲷ', 'Ⲷ'), + ('Ⲹ', 'Ⲹ'), + ('Ⲻ', 'Ⲻ'), + ('â²¼', 'â²¼'), + ('â²¾', 'â²¾'), + ('â³€', 'â³€'), + ('Ⳃ', 'Ⳃ'), + ('Ⳅ', 'Ⳅ'), + ('Ⳇ', 'Ⳇ'), + ('Ⳉ', 'Ⳉ'), + ('Ⳋ', 'Ⳋ'), + ('Ⳍ', 'Ⳍ'), + ('Ⳏ', 'Ⳏ'), + ('â³', 'â³'), + ('â³’', 'â³’'), + ('â³”', 'â³”'), + ('â³–', 'â³–'), + ('Ⳙ', 'Ⳙ'), + ('Ⳛ', 'Ⳛ'), + ('Ⳝ', 'Ⳝ'), + ('Ⳟ', 'Ⳟ'), + ('â³ ', 'â³ '), + ('â³¢', 'â³¢'), + ('Ⳬ', 'Ⳬ'), + ('â³­', 'â³­'), + ('â³²', 'â³²'), + ('Ꙁ', 'Ꙁ'), + ('Ꙃ', 'Ꙃ'), + ('Ꙅ', 'Ꙅ'), + ('Ꙇ', 'Ꙇ'), + ('Ꙉ', 'Ꙉ'), + ('Ꙋ', 'Ꙋ'), + ('Ꙍ', 'Ꙍ'), + ('Ꙏ', 'Ꙏ'), + ('ê™', 'ê™'), + ('ê™’', 'ê™’'), + ('ê™”', 'ê™”'), + ('ê™–', 'ê™–'), + ('Ꙙ', 'Ꙙ'), + ('Ꙛ', 'Ꙛ'), + ('Ꙝ', 'Ꙝ'), + ('Ꙟ', 'Ꙟ'), + ('ê™ ', 'ê™ '), + ('Ꙣ', 'Ꙣ'), + ('Ꙥ', 'Ꙥ'), + ('Ꙧ', 'Ꙧ'), + ('Ꙩ', 'Ꙩ'), + ('Ꙫ', 'Ꙫ'), + ('Ꙭ', 'Ꙭ'), + ('Ꚁ', 'Ꚁ'), + ('êš‚', 'êš‚'), + ('êš„', 'êš„'), + ('Ꚇ', 'Ꚇ'), + ('Ꚉ', 'Ꚉ'), + ('Ꚋ', 'Ꚋ'), + ('Ꚍ', 'Ꚍ'), + ('Ꚏ', 'Ꚏ'), + ('êš', 'êš'), + ('êš’', 'êš’'), + ('êš”', 'êš”'), + ('êš–', 'êš–'), + ('Ꚙ', 'Ꚙ'), + ('êšš', 'êšš'), + ('Ꜣ', 'Ꜣ'), + ('Ꜥ', 'Ꜥ'), + ('Ꜧ', 'Ꜧ'), + ('Ꜩ', 'Ꜩ'), + ('Ꜫ', 'Ꜫ'), + ('Ꜭ', 'Ꜭ'), + ('Ꜯ', 'Ꜯ'), + ('Ꜳ', 'Ꜳ'), + ('Ꜵ', 'Ꜵ'), + ('Ꜷ', 'Ꜷ'), + ('Ꜹ', 'Ꜹ'), + ('Ꜻ', 'Ꜻ'), + ('Ꜽ', 'Ꜽ'), + ('Ꜿ', 'Ꜿ'), + ('ê€', 'ê€'), + ('ê‚', 'ê‚'), + ('ê„', 'ê„'), + ('ê†', 'ê†'), + ('êˆ', 'êˆ'), + ('êŠ', 'êŠ'), + ('êŒ', 'êŒ'), + ('êŽ', 'êŽ'), + ('ê', 'ê'), + ('ê’', 'ê’'), + ('ê”', 'ê”'), + ('ê–', 'ê–'), + ('ê˜', 'ê˜'), + ('êš', 'êš'), + ('êœ', 'êœ'), + ('êž', 'êž'), + ('ê ', 'ê '), + ('ê¢', 'ê¢'), + ('ê¤', 'ê¤'), + ('ê¦', 'ê¦'), + ('ê¨', 'ê¨'), + ('êª', 'êª'), + ('ê¬', 'ê¬'), + ('ê®', 'ê®'), + ('ê¹', 'ê¹'), + ('ê»', 'ê»'), + ('ê½', 'ê¾'), + ('Ꞁ', 'Ꞁ'), + ('êž‚', 'êž‚'), + ('êž„', 'êž„'), + ('Ꞇ', 'Ꞇ'), + ('êž‹', 'êž‹'), + ('êž', 'êž'), + ('êž', 'êž'), + ('êž’', 'êž’'), + ('êž–', 'êž–'), + ('Ꞙ', 'Ꞙ'), + ('êžš', 'êžš'), + ('êžœ', 'êžœ'), + ('êžž', 'êžž'), + ('êž ', 'êž '), + ('Ꞣ', 'Ꞣ'), + ('Ꞥ', 'Ꞥ'), + ('Ꞧ', 'Ꞧ'), + ('Ꞩ', 'Ꞩ'), + ('Ɦ', 'êž®'), + ('êž°', 'êž´'), + ('Ꞷ', 'Ꞷ'), + ('Ꞹ', 'Ꞹ'), + ('Ꞻ', 'Ꞻ'), + ('êž¼', 'êž¼'), + ('êž¾', 'êž¾'), + ('Ꟁ', 'Ꟁ'), + ('Ꟃ', 'Ꟃ'), + ('Ꞔ', 'Ꟈ'), + ('Ꟊ', 'Ꟊ'), + ('êŸ', 'êŸ'), + ('Ꟗ', 'Ꟗ'), + ('Ꟙ', 'Ꟙ'), + ('Ꟶ', 'Ꟶ'), + ('A', 'Z'), + ('ð€', 'ð§'), + ('ð’°', 'ð““'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð²€', 'ð²²'), + ('ð‘¢ ', '𑢿'), + ('ð–¹€', '𖹟'), + ('ð€', 'ð™'), + ('ð´', 'ð‘'), + ('ð‘¨', 'ð’'), + ('ð’œ', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’µ'), + ('ð“', 'ð“©'), + ('ð”„', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”¸', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•¬', 'ð–…'), + ('ð– ', 'ð–¹'), + ('ð—”', 'ð—­'), + ('ð˜ˆ', 'ð˜¡'), + ('ð˜¼', 'ð™•'), + ('ð™°', 'ðš‰'), + ('ðš¨', 'ð›€'), + ('ð›¢', 'ð›º'), + ('ðœœ', 'ðœ´'), + ('ð–', 'ð®'), + ('ðž', 'ðž¨'), + ('ðŸŠ', 'ðŸŠ'), + ('𞤀', '𞤡'), + ('🄰', '🅉'), + ('ðŸ…', '🅩'), + ('🅰', '🆉'), +]; diff --git a/vendor/regex-syntax-0.7.5/src/unicode_tables/word_break.rs b/vendor/regex-syntax-0.7.5/src/unicode_tables/word_break.rs new file mode 100644 index 0000000000000..c0714956feacb --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/unicode_tables/word_break.rs @@ -0,0 +1,1120 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate word-break ucd-15.0.0 --chars +// +// Unicode version: 15.0.0. +// +// ucd-generate 0.2.14 is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("ALetter", ALETTER), + ("CR", CR), + ("Double_Quote", DOUBLE_QUOTE), + ("Extend", EXTEND), + ("ExtendNumLet", EXTENDNUMLET), + ("Format", FORMAT), + ("Hebrew_Letter", HEBREW_LETTER), + ("Katakana", KATAKANA), + ("LF", LF), + ("MidLetter", MIDLETTER), + ("MidNum", MIDNUM), + ("MidNumLet", MIDNUMLET), + ("Newline", NEWLINE), + ("Numeric", NUMERIC), + ("Regional_Indicator", REGIONAL_INDICATOR), + ("Single_Quote", SINGLE_QUOTE), + ("WSegSpace", WSEGSPACE), + ("ZWJ", ZWJ), +]; + +pub const ALETTER: &'static [(char, char)] = &[ + ('A', 'Z'), + ('a', 'z'), + ('ª', 'ª'), + ('µ', 'µ'), + ('º', 'º'), + ('À', 'Ö'), + ('Ø', 'ö'), + ('ø', 'Ë—'), + ('Ëž', 'Ë¿'), + ('Í°', 'Í´'), + ('Ͷ', 'Í·'), + ('ͺ', 'ͽ'), + ('Í¿', 'Í¿'), + ('Ά', 'Ά'), + ('Έ', 'Ί'), + ('ÎŒ', 'ÎŒ'), + ('ÎŽ', 'Ρ'), + ('Σ', 'ϵ'), + ('Ï·', 'Ò'), + ('ÒŠ', 'Ô¯'), + ('Ô±', 'Õ–'), + ('Õ™', 'Õœ'), + ('Õž', 'Õž'), + ('Õ ', 'Öˆ'), + ('ÖŠ', 'ÖŠ'), + ('׳', '׳'), + ('Ø ', 'ÙŠ'), + ('Ù®', 'Ù¯'), + ('Ù±', 'Û“'), + ('Û•', 'Û•'), + ('Û¥', 'Û¦'), + ('Û®', 'Û¯'), + ('Ûº', 'Û¼'), + ('Û¿', 'Û¿'), + ('Ü', 'Ü'), + ('Ü’', 'ܯ'), + ('Ý', 'Þ¥'), + ('Þ±', 'Þ±'), + ('ߊ', 'ߪ'), + ('ß´', 'ßµ'), + ('ߺ', 'ߺ'), + ('à €', 'à •'), + ('à š', 'à š'), + ('à ¤', 'à ¤'), + ('à ¨', 'à ¨'), + ('à¡€', 'ࡘ'), + ('à¡ ', 'ࡪ'), + ('à¡°', 'ࢇ'), + ('ࢉ', 'ࢎ'), + ('ࢠ', 'ࣉ'), + ('ऄ', 'ह'), + ('ऽ', 'ऽ'), + ('à¥', 'à¥'), + ('क़', 'ॡ'), + ('ॱ', 'ঀ'), + ('অ', 'ঌ'), + ('à¦', 'à¦'), + ('ও', 'ন'), + ('প', 'র'), + ('ল', 'ল'), + ('শ', 'হ'), + ('ঽ', 'ঽ'), + ('ৎ', 'ৎ'), + ('ড়', 'à§'), + ('য়', 'ৡ'), + ('ৰ', 'ৱ'), + ('ৼ', 'ৼ'), + ('ਅ', 'ਊ'), + ('à¨', 'à¨'), + ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), + ('à©™', 'à©œ'), + ('à©ž', 'à©ž'), + ('ੲ', 'à©´'), + ('અ', 'àª'), + ('àª', 'ઑ'), + ('ઓ', 'ન'), + ('પ', 'ર'), + ('લ', 'ળ'), + ('વ', 'હ'), + ('ઽ', 'ઽ'), + ('à«', 'à«'), + ('à« ', 'à«¡'), + ('ૹ', 'ૹ'), + ('ଅ', 'ଌ'), + ('à¬', 'à¬'), + ('ଓ', 'ନ'), + ('ପ', 'ର'), + ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), + ('ଽ', 'ଽ'), + ('à­œ', 'à­'), + ('à­Ÿ', 'à­¡'), + ('à­±', 'à­±'), + ('ஃ', 'ஃ'), + ('à®…', 'ஊ'), + ('எ', 'à®'), + ('à®’', 'க'), + ('à®™', 'ச'), + ('ஜ', 'ஜ'), + ('ஞ', 'ட'), + ('ண', 'த'), + ('ந', 'ப'), + ('à®®', 'ஹ'), + ('à¯', 'à¯'), + ('à°…', 'à°Œ'), + ('à°Ž', 'à°'), + ('à°’', 'à°¨'), + ('à°ª', 'à°¹'), + ('à°½', 'à°½'), + ('ౘ', 'ౚ'), + ('à±', 'à±'), + ('à± ', 'ౡ'), + ('ಀ', 'ಀ'), + ('ಅ', 'ಌ'), + ('ಎ', 'à²'), + ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), + ('ಽ', 'ಽ'), + ('à³', 'ೞ'), + ('à³ ', 'ೡ'), + ('à³±', 'à³²'), + ('à´„', 'à´Œ'), + ('à´Ž', 'à´'), + ('à´’', 'à´º'), + ('à´½', 'à´½'), + ('ൎ', 'ൎ'), + ('ൔ', 'ൖ'), + ('ൟ', 'ൡ'), + ('ൺ', 'ൿ'), + ('අ', 'ඖ'), + ('ක', 'න'), + ('ඳ', 'ර'), + ('ල', 'ල'), + ('à·€', 'à·†'), + ('ༀ', 'ༀ'), + ('ཀ', 'ཇ'), + ('ཉ', 'ཬ'), + ('ྈ', 'ྌ'), + ('á‚ ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), + ('áƒ', 'áƒ'), + ('áƒ', 'ჺ'), + ('ჼ', 'ቈ'), + ('ቊ', 'á‰'), + ('á‰', 'ቖ'), + ('ቘ', 'ቘ'), + ('ቚ', 'á‰'), + ('በ', 'ኈ'), + ('ኊ', 'áŠ'), + ('áŠ', 'ኰ'), + ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), + ('á‹€', 'á‹€'), + ('á‹‚', 'á‹…'), + ('ወ', 'á‹–'), + ('ዘ', 'áŒ'), + ('ጒ', 'ጕ'), + ('ጘ', 'áš'), + ('ᎀ', 'áŽ'), + ('Ꭰ', 'áµ'), + ('á¸', 'á½'), + ('á', 'ᙬ'), + ('ᙯ', 'ᙿ'), + ('áš', 'ášš'), + ('áš ', 'ᛪ'), + ('á›®', 'ᛸ'), + ('ᜀ', 'ᜑ'), + ('ᜟ', 'ᜱ'), + ('á€', 'á‘'), + ('á ', 'á¬'), + ('á®', 'á°'), + ('á  ', 'ᡸ'), + ('ᢀ', 'ᢄ'), + ('ᢇ', 'ᢨ'), + ('ᢪ', 'ᢪ'), + ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), + ('ᨀ', 'ᨖ'), + ('ᬅ', 'ᬳ'), + ('á­…', 'á­Œ'), + ('ᮃ', 'á® '), + ('á®®', 'ᮯ'), + ('ᮺ', 'ᯥ'), + ('á°€', 'á°£'), + ('á±', 'á±'), + ('ᱚ', 'á±½'), + ('á²€', 'ᲈ'), + ('á²', 'Ჺ'), + ('á²½', 'Ჿ'), + ('ᳩ', 'ᳬ'), + ('á³®', 'á³³'), + ('á³µ', 'ᳶ'), + ('ᳺ', 'ᳺ'), + ('á´€', 'ᶿ'), + ('Ḁ', 'ἕ'), + ('Ἐ', 'á¼'), + ('á¼ ', 'á½…'), + ('Ὀ', 'á½'), + ('á½', 'á½—'), + ('á½™', 'á½™'), + ('á½›', 'á½›'), + ('á½', 'á½'), + ('Ὗ', 'á½½'), + ('á¾€', 'á¾´'), + ('ᾶ', 'á¾¼'), + ('á¾¾', 'á¾¾'), + ('á¿‚', 'á¿„'), + ('ῆ', 'á¿Œ'), + ('á¿', 'á¿“'), + ('á¿–', 'á¿›'), + ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), + ('ῶ', 'ῼ'), + ('â±', 'â±'), + ('â¿', 'â¿'), + ('â‚', 'â‚œ'), + ('â„‚', 'â„‚'), + ('ℇ', 'ℇ'), + ('â„Š', 'â„“'), + ('â„•', 'â„•'), + ('â„™', 'â„'), + ('ℤ', 'ℤ'), + ('Ω', 'Ω'), + ('ℨ', 'ℨ'), + ('K', 'â„­'), + ('ℯ', 'ℹ'), + ('ℼ', 'â„¿'), + ('â……', 'â…‰'), + ('â…Ž', 'â…Ž'), + ('â… ', 'ↈ'), + ('â’¶', 'â“©'), + ('â°€', 'ⳤ'), + ('Ⳬ', 'â³®'), + ('â³²', 'â³³'), + ('â´€', 'â´¥'), + ('â´§', 'â´§'), + ('â´­', 'â´­'), + ('â´°', 'ⵧ'), + ('ⵯ', 'ⵯ'), + ('ⶀ', 'ⶖ'), + ('ⶠ', 'ⶦ'), + ('ⶨ', 'ⶮ'), + ('ⶰ', 'ⶶ'), + ('ⶸ', 'ⶾ'), + ('â·€', 'â·†'), + ('â·ˆ', 'â·Ž'), + ('â·', 'â·–'), + ('â·˜', 'â·ž'), + ('ⸯ', 'ⸯ'), + ('々', '々'), + ('〻', '〼'), + ('ã„…', 'ㄯ'), + ('ㄱ', 'ㆎ'), + ('ㆠ', 'ㆿ'), + ('ꀀ', 'ê’Œ'), + ('ê“', 'ꓽ'), + ('ꔀ', 'ꘌ'), + ('ê˜', 'ꘟ'), + ('ꘪ', 'ꘫ'), + ('Ꙁ', 'ê™®'), + ('ꙿ', 'êš'), + ('êš ', 'ꛯ'), + ('꜈', 'ꟊ'), + ('êŸ', 'ꟑ'), + ('ꟓ', 'ꟓ'), + ('ꟕ', 'ꟙ'), + ('ꟲ', 'ê '), + ('ê ƒ', 'ê …'), + ('ê ‡', 'ê Š'), + ('ê Œ', 'ê ¢'), + ('ê¡€', 'ꡳ'), + ('ꢂ', 'ꢳ'), + ('ꣲ', 'ꣷ'), + ('ꣻ', 'ꣻ'), + ('ꣽ', 'ꣾ'), + ('ꤊ', 'ꤥ'), + ('ꤰ', 'ꥆ'), + ('ꥠ', 'ꥼ'), + ('ꦄ', 'ꦲ'), + ('ê§', 'ê§'), + ('ꨀ', 'ꨨ'), + ('ê©€', 'ê©‚'), + ('ê©„', 'ê©‹'), + ('ê« ', 'ꫪ'), + ('ꫲ', 'ê«´'), + ('ê¬', 'ꬆ'), + ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), + ('ꬰ', 'ê­©'), + ('ê­°', 'ꯢ'), + ('ê°€', '힣'), + ('íž°', 'ퟆ'), + ('ퟋ', 'ퟻ'), + ('ff', 'st'), + ('ﬓ', 'ﬗ'), + ('ï­', 'ï®±'), + ('ﯓ', 'ï´½'), + ('ïµ', 'ï¶'), + ('ﶒ', 'ï·‡'), + ('ï·°', 'ï·»'), + ('ï¹°', 'ï¹´'), + ('ﹶ', 'ﻼ'), + ('A', 'Z'), + ('ï½', 'z'), + ('ï¾ ', 'ï¾¾'), + ('ï¿‚', 'ᅦ'), + ('ï¿Š', 'ï¿'), + ('ï¿’', 'ï¿—'), + ('ï¿š', 'ï¿œ'), + ('ð€€', 'ð€‹'), + ('ð€', 'ð€¦'), + ('ð€¨', 'ð€º'), + ('ð€¼', 'ð€½'), + ('ð€¿', 'ð'), + ('ð', 'ð'), + ('ð‚€', 'ðƒº'), + ('ð…€', 'ð…´'), + ('ðŠ€', 'ðŠœ'), + ('ðŠ ', 'ð‹'), + ('ðŒ€', 'ðŒŸ'), + ('ðŒ­', 'ðŠ'), + ('ð', 'ðµ'), + ('ðŽ€', 'ðŽ'), + ('ðŽ ', 'ðƒ'), + ('ðˆ', 'ð'), + ('ð‘', 'ð•'), + ('ð€', 'ð’'), + ('ð’°', 'ð““'), + ('ð“˜', 'ð“»'), + ('ð”€', 'ð”§'), + ('ð”°', 'ð•£'), + ('ð•°', 'ð•º'), + ('ð•¼', 'ð–Š'), + ('ð–Œ', 'ð–’'), + ('ð–”', 'ð–•'), + ('ð–—', 'ð–¡'), + ('ð–£', 'ð–±'), + ('ð–³', 'ð–¹'), + ('ð–»', 'ð–¼'), + ('ð˜€', 'ðœ¶'), + ('ð€', 'ð•'), + ('ð ', 'ð§'), + ('ðž€', 'ðž…'), + ('ðž‡', 'ðž°'), + ('ðž²', 'ðžº'), + ('ð €', 'ð …'), + ('ð ˆ', 'ð ˆ'), + ('ð Š', 'ð µ'), + ('ð ·', 'ð ¸'), + ('ð ¼', 'ð ¼'), + ('ð ¿', 'ð¡•'), + ('ð¡ ', 'ð¡¶'), + ('ð¢€', 'ð¢ž'), + ('ð£ ', 'ð£²'), + ('ð£´', 'ð£µ'), + ('ð¤€', 'ð¤•'), + ('ð¤ ', 'ð¤¹'), + ('ð¦€', 'ð¦·'), + ('ð¦¾', 'ð¦¿'), + ('ð¨€', 'ð¨€'), + ('ð¨', 'ð¨“'), + ('ð¨•', 'ð¨—'), + ('ð¨™', 'ð¨µ'), + ('ð© ', 'ð©¼'), + ('ðª€', 'ðªœ'), + ('ð«€', 'ð«‡'), + ('ð«‰', 'ð«¤'), + ('ð¬€', 'ð¬µ'), + ('ð­€', 'ð­•'), + ('ð­ ', 'ð­²'), + ('ð®€', 'ð®‘'), + ('ð°€', 'ð±ˆ'), + ('ð²€', 'ð²²'), + ('ð³€', 'ð³²'), + ('ð´€', 'ð´£'), + ('ðº€', 'ðº©'), + ('ðº°', 'ðº±'), + ('ð¼€', 'ð¼œ'), + ('ð¼§', 'ð¼§'), + ('ð¼°', 'ð½…'), + ('ð½°', 'ð¾'), + ('ð¾°', 'ð¿„'), + ('ð¿ ', 'ð¿¶'), + ('𑀃', 'ð‘€·'), + ('ð‘±', 'ð‘²'), + ('ð‘µ', 'ð‘µ'), + ('𑂃', '𑂯'), + ('ð‘ƒ', '𑃨'), + ('𑄃', '𑄦'), + ('ð‘…„', 'ð‘…„'), + ('ð‘…‡', 'ð‘…‡'), + ('ð‘…', 'ð‘…²'), + ('ð‘…¶', 'ð‘…¶'), + ('𑆃', '𑆲'), + ('ð‘‡', '𑇄'), + ('𑇚', '𑇚'), + ('𑇜', '𑇜'), + ('𑈀', '𑈑'), + ('𑈓', '𑈫'), + ('𑈿', '𑉀'), + ('ð‘Š€', '𑊆'), + ('𑊈', '𑊈'), + ('ð‘ŠŠ', 'ð‘Š'), + ('ð‘Š', 'ð‘Š'), + ('ð‘ŠŸ', '𑊨'), + ('ð‘Š°', 'ð‘‹ž'), + ('𑌅', '𑌌'), + ('ð‘Œ', 'ð‘Œ'), + ('𑌓', '𑌨'), + ('𑌪', '𑌰'), + ('𑌲', '𑌳'), + ('𑌵', '𑌹'), + ('𑌽', '𑌽'), + ('ð‘', 'ð‘'), + ('ð‘', 'ð‘¡'), + ('ð‘€', 'ð‘´'), + ('𑑇', 'ð‘‘Š'), + ('ð‘‘Ÿ', 'ð‘‘¡'), + ('ð‘’€', 'ð‘’¯'), + ('ð‘“„', 'ð‘“…'), + ('𑓇', '𑓇'), + ('ð‘–€', 'ð‘–®'), + ('ð‘—˜', 'ð‘—›'), + ('𑘀', '𑘯'), + ('ð‘™„', 'ð‘™„'), + ('𑚀', '𑚪'), + ('𑚸', '𑚸'), + ('ð‘ €', 'ð‘ «'), + ('ð‘¢ ', '𑣟'), + ('𑣿', '𑤆'), + ('𑤉', '𑤉'), + ('𑤌', '𑤓'), + ('𑤕', '𑤖'), + ('𑤘', '𑤯'), + ('𑤿', '𑤿'), + ('ð‘¥', 'ð‘¥'), + ('𑦠', '𑦧'), + ('𑦪', 'ð‘§'), + ('𑧡', '𑧡'), + ('𑧣', '𑧣'), + ('𑨀', '𑨀'), + ('𑨋', '𑨲'), + ('𑨺', '𑨺'), + ('ð‘©', 'ð‘©'), + ('ð‘©œ', '𑪉'), + ('ð‘ª', 'ð‘ª'), + ('𑪰', '𑫸'), + ('ð‘°€', 'ð‘°ˆ'), + ('ð‘°Š', 'ð‘°®'), + ('𑱀', '𑱀'), + ('𑱲', 'ð‘²'), + ('ð‘´€', 'ð‘´†'), + ('ð‘´ˆ', 'ð‘´‰'), + ('ð‘´‹', 'ð‘´°'), + ('𑵆', '𑵆'), + ('𑵠', '𑵥'), + ('𑵧', '𑵨'), + ('𑵪', '𑶉'), + ('𑶘', '𑶘'), + ('ð‘» ', 'ð‘»²'), + ('𑼂', '𑼂'), + ('𑼄', 'ð‘¼'), + ('𑼒', '𑼳'), + ('𑾰', '𑾰'), + ('ð’€€', 'ð’Ž™'), + ('ð’€', 'ð’‘®'), + ('ð’’€', '𒕃'), + ('ð’¾', 'ð’¿°'), + ('ð“€€', 'ð“¯'), + ('ð“‘', '𓑆'), + ('ð”€', '𔙆'), + ('ð– €', '𖨸'), + ('ð–©€', 'ð–©ž'), + ('ð–©°', '𖪾'), + ('ð–«', 'ð–«­'), + ('𖬀', '𖬯'), + ('ð–­€', 'ð–­ƒ'), + ('ð–­£', 'ð–­·'), + ('ð–­½', 'ð–®'), + ('ð–¹€', '𖹿'), + ('ð–¼€', '𖽊'), + ('ð–½', 'ð–½'), + ('𖾓', '𖾟'), + ('ð–¿ ', 'ð–¿¡'), + ('ð–¿£', 'ð–¿£'), + ('ð›°€', '𛱪'), + ('ð›±°', 'ð›±¼'), + ('𛲀', '𛲈'), + ('ð›²', '𛲙'), + ('ð€', 'ð‘”'), + ('ð‘–', 'ð’œ'), + ('ð’ž', 'ð’Ÿ'), + ('ð’¢', 'ð’¢'), + ('ð’¥', 'ð’¦'), + ('ð’©', 'ð’¬'), + ('ð’®', 'ð’¹'), + ('ð’»', 'ð’»'), + ('ð’½', 'ð“ƒ'), + ('ð“…', 'ð”…'), + ('ð”‡', 'ð”Š'), + ('ð”', 'ð””'), + ('ð”–', 'ð”œ'), + ('ð”ž', 'ð”¹'), + ('ð”»', 'ð”¾'), + ('ð•€', 'ð•„'), + ('ð•†', 'ð•†'), + ('ð•Š', 'ð•'), + ('ð•’', 'ðš¥'), + ('ðš¨', 'ð›€'), + ('ð›‚', 'ð›š'), + ('ð›œ', 'ð›º'), + ('ð›¼', 'ðœ”'), + ('ðœ–', 'ðœ´'), + ('ðœ¶', 'ðŽ'), + ('ð', 'ð®'), + ('ð°', 'ðžˆ'), + ('ðžŠ', 'ðž¨'), + ('ðžª', 'ðŸ‚'), + ('ðŸ„', 'ðŸ‹'), + ('ð¼€', 'ð¼ž'), + ('ð¼¥', 'ð¼ª'), + ('𞀰', 'ðž­'), + ('ðž„€', '𞄬'), + ('ðž„·', '𞄽'), + ('ðž…Ž', 'ðž…Ž'), + ('ðžŠ', '𞊭'), + ('ðž‹€', 'ðž‹«'), + ('ðž“', 'ðž“«'), + ('𞟠', '𞟦'), + ('𞟨', '𞟫'), + ('𞟭', '𞟮'), + ('𞟰', '𞟾'), + ('ðž €', '𞣄'), + ('𞤀', '𞥃'), + ('𞥋', '𞥋'), + ('𞸀', '𞸃'), + ('𞸅', '𞸟'), + ('𞸡', '𞸢'), + ('𞸤', '𞸤'), + ('𞸧', '𞸧'), + ('𞸩', '𞸲'), + ('𞸴', '𞸷'), + ('𞸹', '𞸹'), + ('𞸻', '𞸻'), + ('𞹂', '𞹂'), + ('𞹇', '𞹇'), + ('𞹉', '𞹉'), + ('𞹋', '𞹋'), + ('ðž¹', 'ðž¹'), + ('𞹑', 'ðž¹’'), + ('ðž¹”', 'ðž¹”'), + ('ðž¹—', 'ðž¹—'), + ('ðž¹™', 'ðž¹™'), + ('ðž¹›', 'ðž¹›'), + ('ðž¹', 'ðž¹'), + ('𞹟', '𞹟'), + ('𞹡', 'ðž¹¢'), + ('𞹤', '𞹤'), + ('𞹧', '𞹪'), + ('𞹬', 'ðž¹²'), + ('ðž¹´', 'ðž¹·'), + ('ðž¹¹', 'ðž¹¼'), + ('ðž¹¾', 'ðž¹¾'), + ('𞺀', '𞺉'), + ('𞺋', '𞺛'), + ('𞺡', '𞺣'), + ('𞺥', '𞺩'), + ('𞺫', '𞺻'), + ('🄰', '🅉'), + ('ðŸ…', '🅩'), + ('🅰', '🆉'), +]; + +pub const CR: &'static [(char, char)] = &[('\r', '\r')]; + +pub const DOUBLE_QUOTE: &'static [(char, char)] = &[('"', '"')]; + +pub const EXTEND: &'static [(char, char)] = &[ + ('\u{300}', '\u{36f}'), + ('\u{483}', '\u{489}'), + ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), + ('\u{610}', '\u{61a}'), + ('\u{64b}', '\u{65f}'), + ('\u{670}', '\u{670}'), + ('\u{6d6}', '\u{6dc}'), + ('\u{6df}', '\u{6e4}'), + ('\u{6e7}', '\u{6e8}'), + ('\u{6ea}', '\u{6ed}'), + ('\u{711}', '\u{711}'), + ('\u{730}', '\u{74a}'), + ('\u{7a6}', '\u{7b0}'), + ('\u{7eb}', '\u{7f3}'), + ('\u{7fd}', '\u{7fd}'), + ('\u{816}', '\u{819}'), + ('\u{81b}', '\u{823}'), + ('\u{825}', '\u{827}'), + ('\u{829}', '\u{82d}'), + ('\u{859}', '\u{85b}'), + ('\u{898}', '\u{89f}'), + ('\u{8ca}', '\u{8e1}'), + ('\u{8e3}', 'ः'), + ('\u{93a}', '\u{93c}'), + ('ा', 'à¥'), + ('\u{951}', '\u{957}'), + ('\u{962}', '\u{963}'), + ('\u{981}', 'ঃ'), + ('\u{9bc}', '\u{9bc}'), + ('\u{9be}', '\u{9c4}'), + ('ে', 'ৈ'), + ('ো', '\u{9cd}'), + ('\u{9d7}', '\u{9d7}'), + ('\u{9e2}', '\u{9e3}'), + ('\u{9fe}', '\u{9fe}'), + ('\u{a01}', 'ਃ'), + ('\u{a3c}', '\u{a3c}'), + ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), + ('\u{a70}', '\u{a71}'), + ('\u{a75}', '\u{a75}'), + ('\u{a81}', 'ઃ'), + ('\u{abc}', '\u{abc}'), + ('ા', '\u{ac5}'), + ('\u{ac7}', 'ૉ'), + ('à«‹', '\u{acd}'), + ('\u{ae2}', '\u{ae3}'), + ('\u{afa}', '\u{aff}'), + ('\u{b01}', 'ଃ'), + ('\u{b3c}', '\u{b3c}'), + ('\u{b3e}', '\u{b44}'), + ('à­‡', 'à­ˆ'), + ('à­‹', '\u{b4d}'), + ('\u{b55}', '\u{b57}'), + ('\u{b62}', '\u{b63}'), + ('\u{b82}', '\u{b82}'), + ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), + ('ொ', '\u{bcd}'), + ('\u{bd7}', '\u{bd7}'), + ('\u{c00}', '\u{c04}'), + ('\u{c3c}', '\u{c3c}'), + ('\u{c3e}', 'ౄ'), + ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), + ('\u{c62}', '\u{c63}'), + ('\u{c81}', 'ಃ'), + ('\u{cbc}', '\u{cbc}'), + ('ಾ', 'ೄ'), + ('\u{cc6}', 'ೈ'), + ('ೊ', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), + ('\u{ce2}', '\u{ce3}'), + ('à³³', 'à³³'), + ('\u{d00}', 'à´ƒ'), + ('\u{d3b}', '\u{d3c}'), + ('\u{d3e}', '\u{d44}'), + ('െ', 'ൈ'), + ('ൊ', '\u{d4d}'), + ('\u{d57}', '\u{d57}'), + ('\u{d62}', '\u{d63}'), + ('\u{d81}', 'ඃ'), + ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), + ('à·˜', '\u{ddf}'), + ('à·²', 'à·³'), + ('\u{e31}', '\u{e31}'), + ('\u{e34}', '\u{e3a}'), + ('\u{e47}', '\u{e4e}'), + ('\u{eb1}', '\u{eb1}'), + ('\u{eb4}', '\u{ebc}'), + ('\u{ec8}', '\u{ece}'), + ('\u{f18}', '\u{f19}'), + ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), + ('\u{f39}', '\u{f39}'), + ('༾', '༿'), + ('\u{f71}', '\u{f84}'), + ('\u{f86}', '\u{f87}'), + ('\u{f8d}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), + ('\u{fc6}', '\u{fc6}'), + ('ါ', '\u{103e}'), + ('á–', '\u{1059}'), + ('\u{105e}', '\u{1060}'), + ('á¢', 'á¤'), + ('á§', 'á­'), + ('\u{1071}', '\u{1074}'), + ('\u{1082}', '\u{108d}'), + ('á‚', 'á‚'), + ('á‚š', '\u{109d}'), + ('\u{135d}', '\u{135f}'), + ('\u{1712}', '᜕'), + ('\u{1732}', '᜴'), + ('\u{1752}', '\u{1753}'), + ('\u{1772}', '\u{1773}'), + ('\u{17b4}', '\u{17d3}'), + ('\u{17dd}', '\u{17dd}'), + ('\u{180b}', '\u{180d}'), + ('\u{180f}', '\u{180f}'), + ('\u{1885}', '\u{1886}'), + ('\u{18a9}', '\u{18a9}'), + ('\u{1920}', 'ᤫ'), + ('ᤰ', '\u{193b}'), + ('\u{1a17}', '\u{1a1b}'), + ('á©•', '\u{1a5e}'), + ('\u{1a60}', '\u{1a7c}'), + ('\u{1a7f}', '\u{1a7f}'), + ('\u{1ab0}', '\u{1ace}'), + ('\u{1b00}', 'ᬄ'), + ('\u{1b34}', 'á­„'), + ('\u{1b6b}', '\u{1b73}'), + ('\u{1b80}', 'ᮂ'), + ('ᮡ', '\u{1bad}'), + ('\u{1be6}', '᯳'), + ('á°¤', '\u{1c37}'), + ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', '\u{1ce8}'), + ('\u{1ced}', '\u{1ced}'), + ('\u{1cf4}', '\u{1cf4}'), + ('á³·', '\u{1cf9}'), + ('\u{1dc0}', '\u{1dff}'), + ('\u{200c}', '\u{200c}'), + ('\u{20d0}', '\u{20f0}'), + ('\u{2cef}', '\u{2cf1}'), + ('\u{2d7f}', '\u{2d7f}'), + ('\u{2de0}', '\u{2dff}'), + ('\u{302a}', '\u{302f}'), + ('\u{3099}', '\u{309a}'), + ('\u{a66f}', '\u{a672}'), + ('\u{a674}', '\u{a67d}'), + ('\u{a69e}', '\u{a69f}'), + ('\u{a6f0}', '\u{a6f1}'), + ('\u{a802}', '\u{a802}'), + ('\u{a806}', '\u{a806}'), + ('\u{a80b}', '\u{a80b}'), + ('ê £', 'ê §'), + ('\u{a82c}', '\u{a82c}'), + ('ꢀ', 'ê¢'), + ('ꢴ', '\u{a8c5}'), + ('\u{a8e0}', '\u{a8f1}'), + ('\u{a8ff}', '\u{a8ff}'), + ('\u{a926}', '\u{a92d}'), + ('\u{a947}', '꥓'), + ('\u{a980}', 'ꦃ'), + ('\u{a9b3}', '꧀'), + ('\u{a9e5}', '\u{a9e5}'), + ('\u{aa29}', '\u{aa36}'), + ('\u{aa43}', '\u{aa43}'), + ('\u{aa4c}', 'ê©'), + ('ê©»', 'ꩽ'), + ('\u{aab0}', '\u{aab0}'), + ('\u{aab2}', '\u{aab4}'), + ('\u{aab7}', '\u{aab8}'), + ('\u{aabe}', '\u{aabf}'), + ('\u{aac1}', '\u{aac1}'), + ('ê««', 'ꫯ'), + ('ꫵ', '\u{aaf6}'), + ('ꯣ', 'ꯪ'), + ('꯬', '\u{abed}'), + ('\u{fb1e}', '\u{fb1e}'), + ('\u{fe00}', '\u{fe0f}'), + ('\u{fe20}', '\u{fe2f}'), + ('\u{ff9e}', '\u{ff9f}'), + ('\u{101fd}', '\u{101fd}'), + ('\u{102e0}', '\u{102e0}'), + ('\u{10376}', '\u{1037a}'), + ('\u{10a01}', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), + ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), + ('\u{10ae5}', '\u{10ae6}'), + ('\u{10d24}', '\u{10d27}'), + ('\u{10eab}', '\u{10eac}'), + ('\u{10efd}', '\u{10eff}'), + ('\u{10f46}', '\u{10f50}'), + ('\u{10f82}', '\u{10f85}'), + ('ð‘€€', '𑀂'), + ('\u{11038}', '\u{11046}'), + ('\u{11070}', '\u{11070}'), + ('\u{11073}', '\u{11074}'), + ('\u{1107f}', 'ð‘‚‚'), + ('ð‘‚°', '\u{110ba}'), + ('\u{110c2}', '\u{110c2}'), + ('\u{11100}', '\u{11102}'), + ('\u{11127}', '\u{11134}'), + ('ð‘……', 'ð‘…†'), + ('\u{11173}', '\u{11173}'), + ('\u{11180}', '𑆂'), + ('𑆳', '𑇀'), + ('\u{111c9}', '\u{111cc}'), + ('𑇎', '\u{111cf}'), + ('𑈬', '\u{11237}'), + ('\u{1123e}', '\u{1123e}'), + ('\u{11241}', '\u{11241}'), + ('\u{112df}', '\u{112ea}'), + ('\u{11300}', '𑌃'), + ('\u{1133b}', '\u{1133c}'), + ('\u{1133e}', 'ð‘„'), + ('ð‘‡', 'ð‘ˆ'), + ('ð‘‹', 'ð‘'), + ('\u{11357}', '\u{11357}'), + ('ð‘¢', 'ð‘£'), + ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), + ('ð‘µ', '\u{11446}'), + ('\u{1145e}', '\u{1145e}'), + ('\u{114b0}', '\u{114c3}'), + ('\u{115af}', '\u{115b5}'), + ('ð‘–¸', '\u{115c0}'), + ('\u{115dc}', '\u{115dd}'), + ('𑘰', '\u{11640}'), + ('\u{116ab}', '\u{116b7}'), + ('\u{1171d}', '\u{1172b}'), + ('ð‘ ¬', '\u{1183a}'), + ('\u{11930}', '𑤵'), + ('𑤷', '𑤸'), + ('\u{1193b}', '\u{1193e}'), + ('ð‘¥€', 'ð‘¥€'), + ('𑥂', '\u{11943}'), + ('𑧑', '\u{119d7}'), + ('\u{119da}', '\u{119e0}'), + ('𑧤', '𑧤'), + ('\u{11a01}', '\u{11a0a}'), + ('\u{11a33}', '𑨹'), + ('\u{11a3b}', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), + ('\u{11a51}', '\u{11a5b}'), + ('\u{11a8a}', '\u{11a99}'), + ('ð‘°¯', '\u{11c36}'), + ('\u{11c38}', '\u{11c3f}'), + ('\u{11c92}', '\u{11ca7}'), + ('𑲩', '\u{11cb6}'), + ('\u{11d31}', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d45}'), + ('\u{11d47}', '\u{11d47}'), + ('𑶊', '𑶎'), + ('\u{11d90}', '\u{11d91}'), + ('𑶓', '\u{11d97}'), + ('\u{11ef3}', '𑻶'), + ('\u{11f00}', '\u{11f01}'), + ('𑼃', '𑼃'), + ('𑼴', '\u{11f3a}'), + ('𑼾', '\u{11f42}'), + ('\u{13440}', '\u{13440}'), + ('\u{13447}', '\u{13455}'), + ('\u{16af0}', '\u{16af4}'), + ('\u{16b30}', '\u{16b36}'), + ('\u{16f4f}', '\u{16f4f}'), + ('𖽑', '𖾇'), + ('\u{16f8f}', '\u{16f92}'), + ('\u{16fe4}', '\u{16fe4}'), + ('ð–¿°', 'ð–¿±'), + ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1cf00}', '\u{1cf2d}'), + ('\u{1cf30}', '\u{1cf46}'), + ('\u{1d165}', '\u{1d169}'), + ('ð…­', '\u{1d172}'), + ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), + ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), + ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), + ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), + ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), + ('\u{1e08f}', '\u{1e08f}'), + ('\u{1e130}', '\u{1e136}'), + ('\u{1e2ae}', '\u{1e2ae}'), + ('\u{1e2ec}', '\u{1e2ef}'), + ('\u{1e4ec}', '\u{1e4ef}'), + ('\u{1e8d0}', '\u{1e8d6}'), + ('\u{1e944}', '\u{1e94a}'), + ('ðŸ»', 'ðŸ¿'), + ('\u{e0020}', '\u{e007f}'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const EXTENDNUMLET: &'static [(char, char)] = &[ + ('_', '_'), + ('\u{202f}', '\u{202f}'), + ('‿', 'â€'), + ('â”', 'â”'), + ('︳', '︴'), + ('ï¹', 'ï¹'), + ('_', '_'), +]; + +pub const FORMAT: &'static [(char, char)] = &[ + ('\u{ad}', '\u{ad}'), + ('\u{600}', '\u{605}'), + ('\u{61c}', '\u{61c}'), + ('\u{6dd}', '\u{6dd}'), + ('\u{70f}', '\u{70f}'), + ('\u{890}', '\u{891}'), + ('\u{8e2}', '\u{8e2}'), + ('\u{180e}', '\u{180e}'), + ('\u{200e}', '\u{200f}'), + ('\u{202a}', '\u{202e}'), + ('\u{2060}', '\u{2064}'), + ('\u{2066}', '\u{206f}'), + ('\u{feff}', '\u{feff}'), + ('\u{fff9}', '\u{fffb}'), + ('\u{110bd}', '\u{110bd}'), + ('\u{110cd}', '\u{110cd}'), + ('\u{13430}', '\u{1343f}'), + ('\u{1bca0}', '\u{1bca3}'), + ('\u{1d173}', '\u{1d17a}'), + ('\u{e0001}', '\u{e0001}'), +]; + +pub const HEBREW_LETTER: &'static [(char, char)] = &[ + ('×', 'ת'), + ('ׯ', 'ײ'), + ('ï¬', 'ï¬'), + ('ײַ', 'ﬨ'), + ('שׁ', 'זּ'), + ('טּ', 'לּ'), + ('מּ', 'מּ'), + ('ï­€', 'ï­'), + ('ï­ƒ', 'ï­„'), + ('ï­†', 'ï­'), +]; + +pub const KATAKANA: &'static [(char, char)] = &[ + ('〱', '〵'), + ('ã‚›', 'ã‚œ'), + ('ã‚ ', 'ヺ'), + ('ー', 'ヿ'), + ('ㇰ', 'ㇿ'), + ('ã‹', '㋾'), + ('㌀', 'ã—'), + ('ヲ', 'ï¾'), + ('ðš¿°', '𚿳'), + ('𚿵', 'ðš¿»'), + ('𚿽', '𚿾'), + ('𛀀', '𛀀'), + ('𛄠', '𛄢'), + ('ð›…•', 'ð›…•'), + ('ð›…¤', 'ð›…§'), +]; + +pub const LF: &'static [(char, char)] = &[('\n', '\n')]; + +pub const MIDLETTER: &'static [(char, char)] = &[ + (':', ':'), + ('·', '·'), + ('·', '·'), + ('ÕŸ', 'ÕŸ'), + ('×´', '×´'), + ('‧', '‧'), + ('︓', '︓'), + ('﹕', '﹕'), + (':', ':'), +]; + +pub const MIDNUM: &'static [(char, char)] = &[ + (',', ','), + (';', ';'), + (';', ';'), + ('Ö‰', 'Ö‰'), + ('ØŒ', 'Ø'), + ('Ù¬', 'Ù¬'), + ('߸', '߸'), + ('â„', 'â„'), + ('ï¸', 'ï¸'), + ('︔', '︔'), + ('ï¹', 'ï¹'), + ('ï¹”', 'ï¹”'), + (',', ','), + ('ï¼›', 'ï¼›'), +]; + +pub const MIDNUMLET: &'static [(char, char)] = &[ + ('.', '.'), + ('‘', '’'), + ('․', '․'), + ('ï¹’', 'ï¹’'), + (''', '''), + ('.', '.'), +]; + +pub const NEWLINE: &'static [(char, char)] = + &[('\u{b}', '\u{c}'), ('\u{85}', '\u{85}'), ('\u{2028}', '\u{2029}')]; + +pub const NUMERIC: &'static [(char, char)] = &[ + ('0', '9'), + ('Ù ', 'Ù©'), + ('Ù«', 'Ù«'), + ('Û°', 'Û¹'), + ('߀', '߉'), + ('०', '९'), + ('০', '৯'), + ('੦', '੯'), + ('૦', '૯'), + ('à­¦', 'à­¯'), + ('௦', '௯'), + ('౦', '౯'), + ('೦', '೯'), + ('൦', '൯'), + ('à·¦', 'à·¯'), + ('à¹', '๙'), + ('à»', 'à»™'), + ('༠', '༩'), + ('á€', 'á‰'), + ('á‚', 'á‚™'), + ('០', '៩'), + ('á ', 'á ™'), + ('᥆', 'á¥'), + ('á§', '᧙'), + ('᪀', '᪉'), + ('áª', '᪙'), + ('á­', 'á­™'), + ('á®°', '᮹'), + ('á±€', '᱉'), + ('á±', 'á±™'), + ('꘠', '꘩'), + ('ê£', '꣙'), + ('꤀', '꤉'), + ('ê§', '꧙'), + ('꧰', '꧹'), + ('ê©', 'ê©™'), + ('꯰', '꯹'), + ('ï¼', 'ï¼™'), + ('ð’ ', 'ð’©'), + ('ð´°', 'ð´¹'), + ('ð‘¦', 'ð‘¯'), + ('𑃰', '𑃹'), + ('𑄶', 'ð‘„¿'), + ('ð‘‡', '𑇙'), + ('ð‘‹°', 'ð‘‹¹'), + ('ð‘‘', 'ð‘‘™'), + ('ð‘“', 'ð‘“™'), + ('ð‘™', 'ð‘™™'), + ('𑛀', '𑛉'), + ('𑜰', '𑜹'), + ('ð‘£ ', '𑣩'), + ('ð‘¥', 'ð‘¥™'), + ('ð‘±', '𑱙'), + ('ð‘µ', '𑵙'), + ('𑶠', '𑶩'), + ('ð‘½', '𑽙'), + ('ð–© ', 'ð–©©'), + ('ð–«€', '𖫉'), + ('ð–­', 'ð–­™'), + ('ðŸŽ', 'ðŸ¿'), + ('ðž…€', 'ðž…‰'), + ('ðž‹°', '𞋹'), + ('ðž“°', '𞓹'), + ('ðž¥', '𞥙'), + ('🯰', '🯹'), +]; + +pub const REGIONAL_INDICATOR: &'static [(char, char)] = &[('🇦', '🇿')]; + +pub const SINGLE_QUOTE: &'static [(char, char)] = &[('\'', '\'')]; + +pub const WSEGSPACE: &'static [(char, char)] = &[ + (' ', ' '), + ('\u{1680}', '\u{1680}'), + ('\u{2000}', '\u{2006}'), + ('\u{2008}', '\u{200a}'), + ('\u{205f}', '\u{205f}'), + ('\u{3000}', '\u{3000}'), +]; + +pub const ZWJ: &'static [(char, char)] = &[('\u{200d}', '\u{200d}')]; diff --git a/vendor/regex-syntax-0.7.5/src/utf8.rs b/vendor/regex-syntax-0.7.5/src/utf8.rs new file mode 100644 index 0000000000000..e13b55abf0436 --- /dev/null +++ b/vendor/regex-syntax-0.7.5/src/utf8.rs @@ -0,0 +1,592 @@ +/*! +Converts ranges of Unicode scalar values to equivalent ranges of UTF-8 bytes. + +This is sub-module is useful for constructing byte based automatons that need +to embed UTF-8 decoding. The most common use of this module is in conjunction +with the [`hir::ClassUnicodeRange`](crate::hir::ClassUnicodeRange) type. + +See the documentation on the `Utf8Sequences` iterator for more details and +an example. + +# Wait, what is this? + +This is simplest to explain with an example. Let's say you wanted to test +whether a particular byte sequence was a Cyrillic character. One possible +scalar value range is `[0400-04FF]`. The set of allowed bytes for this +range can be expressed as a sequence of byte ranges: + +```text +[D0-D3][80-BF] +``` + +This is simple enough: simply encode the boundaries, `0400` encodes to +`D0 80` and `04FF` encodes to `D3 BF`, and create ranges from each +corresponding pair of bytes: `D0` to `D3` and `80` to `BF`. + +However, what if you wanted to add the Cyrillic Supplementary characters to +your range? Your range might then become `[0400-052F]`. The same procedure +as above doesn't quite work because `052F` encodes to `D4 AF`. The byte ranges +you'd get from the previous transformation would be `[D0-D4][80-AF]`. However, +this isn't quite correct because this range doesn't capture many characters, +for example, `04FF` (because its last byte, `BF` isn't in the range `80-AF`). + +Instead, you need multiple sequences of byte ranges: + +```text +[D0-D3][80-BF] # matches codepoints 0400-04FF +[D4][80-AF] # matches codepoints 0500-052F +``` + +This gets even more complicated if you want bigger ranges, particularly if +they naively contain surrogate codepoints. For example, the sequence of byte +ranges for the basic multilingual plane (`[0000-FFFF]`) look like this: + +```text +[0-7F] +[C2-DF][80-BF] +[E0][A0-BF][80-BF] +[E1-EC][80-BF][80-BF] +[ED][80-9F][80-BF] +[EE-EF][80-BF][80-BF] +``` + +Note that the byte ranges above will *not* match any erroneous encoding of +UTF-8, including encodings of surrogate codepoints. + +And, of course, for all of Unicode (`[000000-10FFFF]`): + +```text +[0-7F] +[C2-DF][80-BF] +[E0][A0-BF][80-BF] +[E1-EC][80-BF][80-BF] +[ED][80-9F][80-BF] +[EE-EF][80-BF][80-BF] +[F0][90-BF][80-BF][80-BF] +[F1-F3][80-BF][80-BF][80-BF] +[F4][80-8F][80-BF][80-BF] +``` + +This module automates the process of creating these byte ranges from ranges of +Unicode scalar values. + +# Lineage + +I got the idea and general implementation strategy from Russ Cox in his +[article on regexps](https://web.archive.org/web/20160404141123/https://swtch.com/~rsc/regexp/regexp3.html) and RE2. +Russ Cox got it from Ken Thompson's `grep` (no source, folk lore?). +I also got the idea from +[Lucene](https://github.com/apache/lucene-solr/blob/ae93f4e7ac6a3908046391de35d4f50a0d3c59ca/lucene/core/src/java/org/apache/lucene/util/automaton/UTF32ToUTF8.java), +which uses it for executing automata on their term index. +*/ + +use core::{char, fmt, iter::FusedIterator, slice}; + +use alloc::{vec, vec::Vec}; + +const MAX_UTF8_BYTES: usize = 4; + +/// Utf8Sequence represents a sequence of byte ranges. +/// +/// To match a Utf8Sequence, a candidate byte sequence must match each +/// successive range. +/// +/// For example, if there are two ranges, `[C2-DF][80-BF]`, then the byte +/// sequence `\xDD\x61` would not match because `0x61 < 0x80`. +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] +pub enum Utf8Sequence { + /// One byte range. + One(Utf8Range), + /// Two successive byte ranges. + Two([Utf8Range; 2]), + /// Three successive byte ranges. + Three([Utf8Range; 3]), + /// Four successive byte ranges. + Four([Utf8Range; 4]), +} + +impl Utf8Sequence { + /// Creates a new UTF-8 sequence from the encoded bytes of a scalar value + /// range. + /// + /// This assumes that `start` and `end` have the same length. + fn from_encoded_range(start: &[u8], end: &[u8]) -> Self { + assert_eq!(start.len(), end.len()); + match start.len() { + 2 => Utf8Sequence::Two([ + Utf8Range::new(start[0], end[0]), + Utf8Range::new(start[1], end[1]), + ]), + 3 => Utf8Sequence::Three([ + Utf8Range::new(start[0], end[0]), + Utf8Range::new(start[1], end[1]), + Utf8Range::new(start[2], end[2]), + ]), + 4 => Utf8Sequence::Four([ + Utf8Range::new(start[0], end[0]), + Utf8Range::new(start[1], end[1]), + Utf8Range::new(start[2], end[2]), + Utf8Range::new(start[3], end[3]), + ]), + n => unreachable!("invalid encoded length: {}", n), + } + } + + /// Returns the underlying sequence of byte ranges as a slice. + pub fn as_slice(&self) -> &[Utf8Range] { + use self::Utf8Sequence::*; + match *self { + One(ref r) => slice::from_ref(r), + Two(ref r) => &r[..], + Three(ref r) => &r[..], + Four(ref r) => &r[..], + } + } + + /// Returns the number of byte ranges in this sequence. + /// + /// The length is guaranteed to be in the closed interval `[1, 4]`. + pub fn len(&self) -> usize { + self.as_slice().len() + } + + /// Reverses the ranges in this sequence. + /// + /// For example, if this corresponds to the following sequence: + /// + /// ```text + /// [D0-D3][80-BF] + /// ``` + /// + /// Then after reversal, it will be + /// + /// ```text + /// [80-BF][D0-D3] + /// ``` + /// + /// This is useful when one is constructing a UTF-8 automaton to match + /// character classes in reverse. + pub fn reverse(&mut self) { + match *self { + Utf8Sequence::One(_) => {} + Utf8Sequence::Two(ref mut x) => x.reverse(), + Utf8Sequence::Three(ref mut x) => x.reverse(), + Utf8Sequence::Four(ref mut x) => x.reverse(), + } + } + + /// Returns true if and only if a prefix of `bytes` matches this sequence + /// of byte ranges. + pub fn matches(&self, bytes: &[u8]) -> bool { + if bytes.len() < self.len() { + return false; + } + for (&b, r) in bytes.iter().zip(self) { + if !r.matches(b) { + return false; + } + } + true + } +} + +impl<'a> IntoIterator for &'a Utf8Sequence { + type IntoIter = slice::Iter<'a, Utf8Range>; + type Item = &'a Utf8Range; + + fn into_iter(self) -> Self::IntoIter { + self.as_slice().iter() + } +} + +impl fmt::Debug for Utf8Sequence { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use self::Utf8Sequence::*; + match *self { + One(ref r) => write!(f, "{:?}", r), + Two(ref r) => write!(f, "{:?}{:?}", r[0], r[1]), + Three(ref r) => write!(f, "{:?}{:?}{:?}", r[0], r[1], r[2]), + Four(ref r) => { + write!(f, "{:?}{:?}{:?}{:?}", r[0], r[1], r[2], r[3]) + } + } + } +} + +/// A single inclusive range of UTF-8 bytes. +#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord)] +pub struct Utf8Range { + /// Start of byte range (inclusive). + pub start: u8, + /// End of byte range (inclusive). + pub end: u8, +} + +impl Utf8Range { + fn new(start: u8, end: u8) -> Self { + Utf8Range { start, end } + } + + /// Returns true if and only if the given byte is in this range. + pub fn matches(&self, b: u8) -> bool { + self.start <= b && b <= self.end + } +} + +impl fmt::Debug for Utf8Range { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.start == self.end { + write!(f, "[{:X}]", self.start) + } else { + write!(f, "[{:X}-{:X}]", self.start, self.end) + } + } +} + +/// An iterator over ranges of matching UTF-8 byte sequences. +/// +/// The iteration represents an alternation of comprehensive byte sequences +/// that match precisely the set of UTF-8 encoded scalar values. +/// +/// A byte sequence corresponds to one of the scalar values in the range given +/// if and only if it completely matches exactly one of the sequences of byte +/// ranges produced by this iterator. +/// +/// Each sequence of byte ranges matches a unique set of bytes. That is, no two +/// sequences will match the same bytes. +/// +/// # Example +/// +/// This shows how to match an arbitrary byte sequence against a range of +/// scalar values. +/// +/// ```rust +/// use regex_syntax::utf8::{Utf8Sequences, Utf8Sequence}; +/// +/// fn matches(seqs: &[Utf8Sequence], bytes: &[u8]) -> bool { +/// for range in seqs { +/// if range.matches(bytes) { +/// return true; +/// } +/// } +/// false +/// } +/// +/// // Test the basic multilingual plane. +/// let seqs: Vec<_> = Utf8Sequences::new('\u{0}', '\u{FFFF}').collect(); +/// +/// // UTF-8 encoding of 'a'. +/// assert!(matches(&seqs, &[0x61])); +/// // UTF-8 encoding of '☃' (`\u{2603}`). +/// assert!(matches(&seqs, &[0xE2, 0x98, 0x83])); +/// // UTF-8 encoding of `\u{10348}` (outside the BMP). +/// assert!(!matches(&seqs, &[0xF0, 0x90, 0x8D, 0x88])); +/// // Tries to match against a UTF-8 encoding of a surrogate codepoint, +/// // which is invalid UTF-8, and therefore fails, despite the fact that +/// // the corresponding codepoint (0xD800) falls in the range given. +/// assert!(!matches(&seqs, &[0xED, 0xA0, 0x80])); +/// // And fails against plain old invalid UTF-8. +/// assert!(!matches(&seqs, &[0xFF, 0xFF])); +/// ``` +/// +/// If this example seems circuitous, that's because it is! It's meant to be +/// illustrative. In practice, you could just try to decode your byte sequence +/// and compare it with the scalar value range directly. However, this is not +/// always possible (for example, in a byte based automaton). +#[derive(Debug)] +pub struct Utf8Sequences { + range_stack: Vec, +} + +impl Utf8Sequences { + /// Create a new iterator over UTF-8 byte ranges for the scalar value range + /// given. + pub fn new(start: char, end: char) -> Self { + let mut it = Utf8Sequences { range_stack: vec![] }; + it.push(u32::from(start), u32::from(end)); + it + } + + /// reset resets the scalar value range. + /// Any existing state is cleared, but resources may be reused. + /// + /// N.B. Benchmarks say that this method is dubious. + #[doc(hidden)] + pub fn reset(&mut self, start: char, end: char) { + self.range_stack.clear(); + self.push(u32::from(start), u32::from(end)); + } + + fn push(&mut self, start: u32, end: u32) { + self.range_stack.push(ScalarRange { start, end }); + } +} + +struct ScalarRange { + start: u32, + end: u32, +} + +impl fmt::Debug for ScalarRange { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ScalarRange({:X}, {:X})", self.start, self.end) + } +} + +impl Iterator for Utf8Sequences { + type Item = Utf8Sequence; + + fn next(&mut self) -> Option { + 'TOP: while let Some(mut r) = self.range_stack.pop() { + 'INNER: loop { + if let Some((r1, r2)) = r.split() { + self.push(r2.start, r2.end); + r.start = r1.start; + r.end = r1.end; + continue 'INNER; + } + if !r.is_valid() { + continue 'TOP; + } + for i in 1..MAX_UTF8_BYTES { + let max = max_scalar_value(i); + if r.start <= max && max < r.end { + self.push(max + 1, r.end); + r.end = max; + continue 'INNER; + } + } + if let Some(ascii_range) = r.as_ascii() { + return Some(Utf8Sequence::One(ascii_range)); + } + for i in 1..MAX_UTF8_BYTES { + let m = (1 << (6 * i)) - 1; + if (r.start & !m) != (r.end & !m) { + if (r.start & m) != 0 { + self.push((r.start | m) + 1, r.end); + r.end = r.start | m; + continue 'INNER; + } + if (r.end & m) != m { + self.push(r.end & !m, r.end); + r.end = (r.end & !m) - 1; + continue 'INNER; + } + } + } + let mut start = [0; MAX_UTF8_BYTES]; + let mut end = [0; MAX_UTF8_BYTES]; + let n = r.encode(&mut start, &mut end); + return Some(Utf8Sequence::from_encoded_range( + &start[0..n], + &end[0..n], + )); + } + } + None + } +} + +impl FusedIterator for Utf8Sequences {} + +impl ScalarRange { + /// split splits this range if it overlaps with a surrogate codepoint. + /// + /// Either or both ranges may be invalid. + fn split(&self) -> Option<(ScalarRange, ScalarRange)> { + if self.start < 0xE000 && self.end > 0xD7FF { + Some(( + ScalarRange { start: self.start, end: 0xD7FF }, + ScalarRange { start: 0xE000, end: self.end }, + )) + } else { + None + } + } + + /// is_valid returns true if and only if start <= end. + fn is_valid(&self) -> bool { + self.start <= self.end + } + + /// as_ascii returns this range as a Utf8Range if and only if all scalar + /// values in this range can be encoded as a single byte. + fn as_ascii(&self) -> Option { + if self.is_ascii() { + let start = u8::try_from(self.start).unwrap(); + let end = u8::try_from(self.end).unwrap(); + Some(Utf8Range::new(start, end)) + } else { + None + } + } + + /// is_ascii returns true if the range is ASCII only (i.e., takes a single + /// byte to encode any scalar value). + fn is_ascii(&self) -> bool { + self.is_valid() && self.end <= 0x7f + } + + /// encode writes the UTF-8 encoding of the start and end of this range + /// to the corresponding destination slices, and returns the number of + /// bytes written. + /// + /// The slices should have room for at least `MAX_UTF8_BYTES`. + fn encode(&self, start: &mut [u8], end: &mut [u8]) -> usize { + let cs = char::from_u32(self.start).unwrap(); + let ce = char::from_u32(self.end).unwrap(); + let ss = cs.encode_utf8(start); + let se = ce.encode_utf8(end); + assert_eq!(ss.len(), se.len()); + ss.len() + } +} + +fn max_scalar_value(nbytes: usize) -> u32 { + match nbytes { + 1 => 0x007F, + 2 => 0x07FF, + 3 => 0xFFFF, + 4 => 0x0010_FFFF, + _ => unreachable!("invalid UTF-8 byte sequence size"), + } +} + +#[cfg(test)] +mod tests { + use core::char; + + use alloc::{vec, vec::Vec}; + + use crate::utf8::{Utf8Range, Utf8Sequences}; + + fn rutf8(s: u8, e: u8) -> Utf8Range { + Utf8Range::new(s, e) + } + + fn never_accepts_surrogate_codepoints(start: char, end: char) { + for cp in 0xD800..0xE000 { + let buf = encode_surrogate(cp); + for r in Utf8Sequences::new(start, end) { + if r.matches(&buf) { + panic!( + "Sequence ({:X}, {:X}) contains range {:?}, \ + which matches surrogate code point {:X} \ + with encoded bytes {:?}", + u32::from(start), + u32::from(end), + r, + cp, + buf, + ); + } + } + } + } + + #[test] + fn codepoints_no_surrogates() { + never_accepts_surrogate_codepoints('\u{0}', '\u{FFFF}'); + never_accepts_surrogate_codepoints('\u{0}', '\u{10FFFF}'); + never_accepts_surrogate_codepoints('\u{0}', '\u{10FFFE}'); + never_accepts_surrogate_codepoints('\u{80}', '\u{10FFFF}'); + never_accepts_surrogate_codepoints('\u{D7FF}', '\u{E000}'); + } + + #[test] + fn single_codepoint_one_sequence() { + // Tests that every range of scalar values that contains a single + // scalar value is recognized by one sequence of byte ranges. + for i in 0x0..=0x0010_FFFF { + let c = match char::from_u32(i) { + None => continue, + Some(c) => c, + }; + let seqs: Vec<_> = Utf8Sequences::new(c, c).collect(); + assert_eq!(seqs.len(), 1); + } + } + + #[test] + fn bmp() { + use crate::utf8::Utf8Sequence::*; + + let seqs = Utf8Sequences::new('\u{0}', '\u{FFFF}').collect::>(); + assert_eq!( + seqs, + vec![ + One(rutf8(0x0, 0x7F)), + Two([rutf8(0xC2, 0xDF), rutf8(0x80, 0xBF)]), + Three([ + rutf8(0xE0, 0xE0), + rutf8(0xA0, 0xBF), + rutf8(0x80, 0xBF) + ]), + Three([ + rutf8(0xE1, 0xEC), + rutf8(0x80, 0xBF), + rutf8(0x80, 0xBF) + ]), + Three([ + rutf8(0xED, 0xED), + rutf8(0x80, 0x9F), + rutf8(0x80, 0xBF) + ]), + Three([ + rutf8(0xEE, 0xEF), + rutf8(0x80, 0xBF), + rutf8(0x80, 0xBF) + ]), + ] + ); + } + + #[test] + fn reverse() { + use crate::utf8::Utf8Sequence::*; + + let mut s = One(rutf8(0xA, 0xB)); + s.reverse(); + assert_eq!(s.as_slice(), &[rutf8(0xA, 0xB)]); + + let mut s = Two([rutf8(0xA, 0xB), rutf8(0xB, 0xC)]); + s.reverse(); + assert_eq!(s.as_slice(), &[rutf8(0xB, 0xC), rutf8(0xA, 0xB)]); + + let mut s = Three([rutf8(0xA, 0xB), rutf8(0xB, 0xC), rutf8(0xC, 0xD)]); + s.reverse(); + assert_eq!( + s.as_slice(), + &[rutf8(0xC, 0xD), rutf8(0xB, 0xC), rutf8(0xA, 0xB)] + ); + + let mut s = Four([ + rutf8(0xA, 0xB), + rutf8(0xB, 0xC), + rutf8(0xC, 0xD), + rutf8(0xD, 0xE), + ]); + s.reverse(); + assert_eq!( + s.as_slice(), + &[ + rutf8(0xD, 0xE), + rutf8(0xC, 0xD), + rutf8(0xB, 0xC), + rutf8(0xA, 0xB) + ] + ); + } + + fn encode_surrogate(cp: u32) -> [u8; 3] { + const TAG_CONT: u8 = 0b1000_0000; + const TAG_THREE_B: u8 = 0b1110_0000; + + assert!(0xD800 <= cp && cp < 0xE000); + let mut dst = [0; 3]; + dst[0] = u8::try_from(cp >> 12 & 0x0F).unwrap() | TAG_THREE_B; + dst[1] = u8::try_from(cp >> 6 & 0x3F).unwrap() | TAG_CONT; + dst[2] = u8::try_from(cp & 0x3F).unwrap() | TAG_CONT; + dst + } +} diff --git a/vendor/regex-syntax-0.7.5/test b/vendor/regex-syntax-0.7.5/test new file mode 100755 index 0000000000000..8626c3bfccbab --- /dev/null +++ b/vendor/regex-syntax-0.7.5/test @@ -0,0 +1,30 @@ +#!/bin/bash + +set -e + +# cd to the directory containing this crate's Cargo.toml so that we don't need +# to pass --manifest-path to every `cargo` command. +cd "$(dirname "$0")" + +# This is a convenience script for running a broad swath of the syntax tests. +echo "===== DEFAULT FEATURES ===" +cargo test + +features=( + std + unicode + unicode-age + unicode-bool + unicode-case + unicode-gencat + unicode-perl + unicode-script + unicode-segment +) +for f in "${features[@]}"; do + echo "=== FEATURE: $f ===" + # We only run library tests because I couldn't figure out how to easily + # make doc tests run in 'no_std' mode. In particular, without the Error + # trait, using '?' in doc tests seems tricky. + cargo test --no-default-features --lib --features "$f" +done diff --git a/vendor/relative-path/CHANGELOG.md b/vendor/relative-path/CHANGELOG.md new file mode 100644 index 0000000000000..60d942586f00b --- /dev/null +++ b/vendor/relative-path/CHANGELOG.md @@ -0,0 +1,133 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.8.0] - 2023-03-05 + +### Added +* Deserialize implementation and conversions for `Box`. +* `From<&str>`, `From>`, for `Box`. +* Added tests for most trait implementations. +* Add `Deserialize` implementation for `&RelativePath` (#19). +* Add `AsRef` for `Component` (#24). + +## [1.7.3] - 2023-01-02 + +### Changed +* Fixed build badge in repo. + +## [1.7.1] - 2022-07-10 + +### Changed +* Updated documentation to be easier to follow. + +## [1.7.0] - 2022-03-22 + +### Added +* Added `Clone` implementation for `Box` with `RelativePathBuf::into_boxed_relative_path` ([#37]). + +[#37]: https://github.com/udoprog/relative-path/pull/37 + +## [1.6.1] - 2022-02-07 + +### Changed +* Updated documentation. + +## [1.6.0] - 2021-12-03 + +### Added +* Added `RelativePath::is_normalized` to check for normalization ([#28]). +* Added `impl From<&RelativePath> for Box` ([#26]). +* Added `impl From for Box` ([#26]). +* Added `impl From<&RelativePath> for Arc` ([#26]). +* Added `impl From for Arc` ([#26]). +* Added `impl From<&RelativePath> for Rc` ([#26]). +* Added `impl From for Rc` ([#26]). + +### Fixed +* Changed `to_path` and `to_logical_path` to treat empty paths better ([#29]). + +[#29]: https://github.com/udoprog/relative-path/pull/29 +[#28]: https://github.com/udoprog/relative-path/pull/28 +[#26]: https://github.com/udoprog/relative-path/pull/26 + +## [1.5.0] - 2021-07-29 + +### Added +* Implement Extend and FromIterator for RelativePathBuf ([#25]). + +[#25]: https://github.com/udoprog/relative-path/pull/25 + +## [1.4.0] - 2021-05-04 + +### Added +* `to_logical_path` as an alternative method of converting into a path. + +### Changed +* `set_extension` no longer needs to allocate. +* `set_file_name` implementation to more closely match + `std::path::PathBuf::set_file_name`. + +## [1.3.1], [1.3.2] - 2020-07-12 + +### Changed +* Minor documentation fixes. + +## [1.3.0] - 2020-07-12 + +### Fixed +* Changed `to_path` to ignore platform-specific absolute components ([#18]). + +[#18]: https://github.com/udoprog/relative-path/pull/18 + +## [1.2.1] - 2020-06-16 + +### Changed +* Change signature of `RelativePath::strip_prefix` to be the same as `std::path::Path` ([#16]). + +## [1.2.0] - 2020-06-13 + +### Added +* Added `FromPathError::kind` to get more detailed error information ([#15]). + +### Changed +* Marked `FromPathErrorKind` `#[non_exhaustive]` which technically is a breaking + change. But since it was not accessible from API code of this library, anyone + who used it outside are on their own. + +## [1.1.1] - 2020-06-13 + +### Changed +* Deprecated use of `std::error::Error::description` in favor of just having a `std::fmt::Display` impl. + +## [1.1.0] - 2020-06-13 + +### Added +* Added `RelativePath::relative` to render a path relative from one path to another ([#14]). + +[#16]: https://github.com/udoprog/relative-path/pull/16 +[#15]: https://github.com/udoprog/relative-path/pull/15 +[#14]: https://github.com/udoprog/relative-path/pull/14 + +[Unreleased]: https://github.com/udoprog/relative-path/compare/1.8.0...master +[1.8.0]: https://github.com/udoprog/relative-path/compare/1.7.3...1.8.0 +[1.7.3]: https://github.com/udoprog/relative-path/compare/1.7.2...1.7.3 +[1.7.2]: https://github.com/udoprog/relative-path/compare/1.7.1...1.7.2 +[1.7.1]: https://github.com/udoprog/relative-path/compare/1.7.0...1.7.1 +[1.7.0]: https://github.com/udoprog/relative-path/compare/1.6.1...1.7.0 +[1.6.1]: https://github.com/udoprog/relative-path/compare/1.6.0...1.6.1 +[1.6.0]: https://github.com/udoprog/relative-path/compare/1.5.0...1.6.0 +[1.5.0]: https://github.com/udoprog/relative-path/compare/1.4.0...1.5.0 +[1.4.0]: https://github.com/udoprog/relative-path/compare/1.3.2...1.4.0 +[1.3.2]: https://github.com/udoprog/relative-path/compare/1.3.1...1.3.2 +[1.3.1]: https://github.com/udoprog/relative-path/compare/1.3.0...1.3.1 +[1.3.0]: https://github.com/udoprog/relative-path/compare/1.2.1...1.3.0 +[1.2.1]: https://github.com/udoprog/relative-path/compare/1.2.0...1.2.1 +[1.2.0]: https://github.com/udoprog/relative-path/compare/1.1.1...1.2.0 +[1.1.1]: https://github.com/udoprog/relative-path/compare/1.1.0...1.1.1 +[1.1.0]: https://github.com/udoprog/relative-path/compare/1.0.0...1.1.0 diff --git a/vendor/relative-path/LICENSE-APACHE b/vendor/relative-path/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/vendor/relative-path/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/relative-path/LICENSE-MIT b/vendor/relative-path/LICENSE-MIT new file mode 100644 index 0000000000000..39d4bdb5acd31 --- /dev/null +++ b/vendor/relative-path/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/reqwest/src/dns/trust_dns.rs b/vendor/reqwest/src/dns/trust_dns.rs new file mode 100644 index 0000000000000..a25326085c8b0 --- /dev/null +++ b/vendor/reqwest/src/dns/trust_dns.rs @@ -0,0 +1,59 @@ +//! DNS resolution via the [trust_dns_resolver](https://github.com/bluejekyll/trust-dns) crate + +use hyper::client::connect::dns::Name; +use once_cell::sync::OnceCell; +use trust_dns_resolver::{lookup_ip::LookupIpIntoIter, system_conf, TokioAsyncResolver}; + +use std::io; +use std::net::SocketAddr; +use std::sync::Arc; + +use super::{Addrs, Resolve, Resolving}; + +/// Wrapper around an `AsyncResolver`, which implements the `Resolve` trait. +#[derive(Debug, Default, Clone)] +pub(crate) struct TrustDnsResolver { + /// Since we might not have been called in the context of a + /// Tokio Runtime in initialization, so we must delay the actual + /// construction of the resolver. + state: Arc>, +} + +struct SocketAddrs { + iter: LookupIpIntoIter, +} + +impl Resolve for TrustDnsResolver { + fn resolve(&self, name: Name) -> Resolving { + let resolver = self.clone(); + Box::pin(async move { + let resolver = resolver.state.get_or_try_init(new_resolver)?; + + let lookup = resolver.lookup_ip(name.as_str()).await?; + let addrs: Addrs = Box::new(SocketAddrs { + iter: lookup.into_iter(), + }); + Ok(addrs) + }) + } +} + +impl Iterator for SocketAddrs { + type Item = SocketAddr; + + fn next(&mut self) -> Option { + self.iter.next().map(|ip_addr| SocketAddr::new(ip_addr, 0)) + } +} + +/// Create a new resolver with the default configuration, +/// which reads from `/etc/resolve.conf`. +fn new_resolver() -> io::Result { + let (config, opts) = system_conf::read_system_conf().map_err(|e| { + io::Error::new( + io::ErrorKind::Other, + format!("error reading DNS system conf: {e}"), + ) + })?; + Ok(TokioAsyncResolver::tokio(config, opts)) +} diff --git a/vendor/retain_mut/.cargo-checksum.json b/vendor/retain_mut/.cargo-checksum.json new file mode 100644 index 0000000000000..3b8bd38743bc7 --- /dev/null +++ b/vendor/retain_mut/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"b107e68253afdbdfaafc533c4e338c124a2737874bdf71f76d9693cd8148a521","LICENSE":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"df547dda0d4ff750771c5f2a5a06648a26119f6a64fe039b2e33cbf894cd5184","src/lib.rs":"8d701f4c4244ea0b4ad9491f92aea57c4363c499aefd6186470e0045f5a345cb"},"package":"8c31b5c4033f8fdde8700e4657be2c497e7288f01515be52168c631e2e4d4086"} \ No newline at end of file diff --git a/vendor/retain_mut/Cargo.toml b/vendor/retain_mut/Cargo.toml new file mode 100644 index 0000000000000..cae7e10f54a0a --- /dev/null +++ b/vendor/retain_mut/Cargo.toml @@ -0,0 +1,23 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +name = "retain_mut" +version = "0.1.7" +authors = ["Xidorn Quan "] +description = "Provide retain_mut method that has the same functionality as retain but gives mutable borrow to the predicate." +readme = "README.md" +keywords = ["retain", "no_std"] +categories = ["rust-patterns"] +license = "MIT" +repository = "https://github.com/upsuper/retain_mut" + +[dependencies] diff --git a/vendor/retain_mut/LICENSE b/vendor/retain_mut/LICENSE new file mode 100644 index 0000000000000..31aa79387f27e --- /dev/null +++ b/vendor/retain_mut/LICENSE @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/retain_mut/README.md b/vendor/retain_mut/README.md new file mode 100644 index 0000000000000..8934cb3a47a85 --- /dev/null +++ b/vendor/retain_mut/README.md @@ -0,0 +1,42 @@ +# RetainMut + + + +This crate provides trait `RetainMut` which +provides `retain_mut` method for `Vec` and `VecDeque`. + +`retain_mut` is basically the same as `retain` except that +it gives mutable reference of items to the predicate function. + +Since there is no reason `retain` couldn't have been designed this way, +this crate basically just copies the code from std with minor changes +to hand out mutable reference. +The code these impls are based on can be found in code comments of this crate. + +This was probably a historical mistake in Rust library, +that `retain` should do this at the very beginning. +See [rust-lang/rust#25477](https://github.com/rust-lang/rust/issues/25477). + +From Rust 1.58, an unstable `retain_mut` method has been added to the std, see +[rust-lang/rust#90829](https://github.com/rust-lang/rust/issues/90829). +Once it gets stabilized, you can simply remove this crate. + +## Examples + +### `Vec` + +```rust +let mut vec = vec![1, 2, 3, 4]; +vec.retain_mut(|x| { *x *= 3; *x % 2 == 0 }); +assert_eq!(vec, [6, 12]); +``` + +### `VecDeque` + +```rust +let mut deque = VecDeque::from(vec![1, 2, 3, 4]); +deque.retain_mut(|x| { *x *= 3; *x % 2 == 0 }); +assert_eq!(deque, [6, 12]); +``` + + diff --git a/vendor/retain_mut/src/lib.rs b/vendor/retain_mut/src/lib.rs new file mode 100644 index 0000000000000..0697d1c5b50e0 --- /dev/null +++ b/vendor/retain_mut/src/lib.rs @@ -0,0 +1,201 @@ +//! This crate provides trait `RetainMut` which +//! provides `retain_mut` method for `Vec` and `VecDeque`. +//! +//! `retain_mut` is basically the same as `retain` except that +//! it gives mutable reference of items to the predicate function. +//! +//! Since there is no reason `retain` couldn't have been designed this way, +//! this crate basically just copies the code from std with minor changes +//! to hand out mutable reference. +//! The code these impls are based on can be found in code comments of this crate. +//! +//! This was probably a historical mistake in Rust library, +//! that `retain` should do this at the very beginning. +//! See [rust-lang/rust#25477](https://github.com/rust-lang/rust/issues/25477). +//! +//! From Rust 1.58, an unstable `retain_mut` method has been added to the std, see +//! [rust-lang/rust#90829](https://github.com/rust-lang/rust/issues/90829). +//! Once it gets stabilized, you can simply remove this crate. +//! +//! ## Examples +//! +//! ### `Vec` +//! +//! ``` +//! # use retain_mut::RetainMut; +//! let mut vec = vec![1, 2, 3, 4]; +//! vec.retain_mut(|x| { *x *= 3; *x % 2 == 0 }); +//! assert_eq!(vec, [6, 12]); +//! ``` +//! +//! ### `VecDeque` +//! +//! ``` +//! # use retain_mut::RetainMut; +//! # use std::collections::VecDeque; +//! let mut deque = VecDeque::from(vec![1, 2, 3, 4]); +//! deque.retain_mut(|x| { *x *= 3; *x % 2 == 0 }); +//! assert_eq!(deque, [6, 12]); +//! ``` + +#![no_std] + +extern crate alloc; + +use alloc::collections::vec_deque::VecDeque; +use alloc::vec::Vec; +use core::ptr; + +/// Trait that provides `retain_mut` method. +pub trait RetainMut { + /// Retains only the elements specified by the predicate, passing a mutable reference to it. + /// + /// In other words, remove all elements `e` such that `f(&mut e)` returns `false`. + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. + fn retain_mut(&mut self, f: F) + where + F: FnMut(&mut T) -> bool; +} + +impl RetainMut for Vec { + // The implementation is based on + // https://github.com/rust-lang/rust/blob/03c8ffaacb040a8753ef8e1accea701bc9f5be85/library/alloc/src/vec/mod.rs#L1478-L1569 + fn retain_mut(&mut self, mut f: F) + where + F: FnMut(&mut T) -> bool, + { + let original_len = self.len(); + // Avoid double drop if the drop guard is not executed, + // since we may make some holes during the process. + unsafe { self.set_len(0) }; + + // Vec: [Kept, Kept, Hole, Hole, Hole, Hole, Unchecked, Unchecked] + // |<- processed len ->| ^- next to check + // |<- deleted cnt ->| + // |<- original_len ->| + // Kept: Elements which predicate returns true on. + // Hole: Moved or dropped element slot. + // Unchecked: Unchecked valid elements. + // + // This drop guard will be invoked when predicate or `drop` of element panicked. + // It shifts unchecked elements to cover holes and `set_len` to the correct length. + // In cases when predicate and `drop` never panick, it will be optimized out. + struct BackshiftOnDrop<'a, T> { + v: &'a mut Vec, + processed_len: usize, + deleted_cnt: usize, + original_len: usize, + } + + impl Drop for BackshiftOnDrop<'_, T> { + fn drop(&mut self) { + if self.deleted_cnt > 0 { + // SAFETY: Trailing unchecked items must be valid since we never touch them. + unsafe { + ptr::copy( + self.v.as_ptr().add(self.processed_len), + self.v + .as_mut_ptr() + .add(self.processed_len - self.deleted_cnt), + self.original_len - self.processed_len, + ); + } + } + // SAFETY: After filling holes, all items are in contiguous memory. + unsafe { + self.v.set_len(self.original_len - self.deleted_cnt); + } + } + } + + let mut g = BackshiftOnDrop { + v: self, + processed_len: 0, + deleted_cnt: 0, + original_len, + }; + + fn process_loop( + original_len: usize, + f: &mut F, + g: &mut BackshiftOnDrop<'_, T>, + ) where + F: FnMut(&mut T) -> bool, + { + while g.processed_len != original_len { + // SAFETY: Unchecked element must be valid. + let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) }; + if !f(cur) { + // Advance early to avoid double drop if `drop_in_place` panicked. + g.processed_len += 1; + g.deleted_cnt += 1; + // SAFETY: We never touch this element again after dropped. + unsafe { ptr::drop_in_place(cur) }; + // We already advanced the counter. + if DELETED { + continue; + } else { + break; + } + } + if DELETED { + // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element. + // We use copy for move, and never touch this element again. + unsafe { + let hole_slot = g.v.as_mut_ptr().add(g.processed_len - g.deleted_cnt); + ptr::copy_nonoverlapping(cur, hole_slot, 1); + } + } + g.processed_len += 1; + } + } + + // Stage 1: Nothing was deleted. + process_loop::(original_len, &mut f, &mut g); + + // Stage 2: Some elements were deleted. + process_loop::(original_len, &mut f, &mut g); + + // All item are processed. This can be optimized to `set_len` by LLVM. + drop(g); + } +} + +impl RetainMut for VecDeque { + // The implementation is based on + // https://github.com/rust-lang/rust/blob/3e21768a0a3fc84befd1cbe825ae6849e9941b73/library/alloc/src/collections/vec_deque/mod.rs#L2148-L2180 + fn retain_mut(&mut self, mut f: F) + where + F: FnMut(&mut T) -> bool, + { + let len = self.len(); + let mut idx = 0; + let mut cur = 0; + + // Stage 1: All values are retained. + while cur < len { + if !f(&mut self[cur]) { + cur += 1; + break; + } + cur += 1; + idx += 1; + } + // Stage 2: Swap retained value into current idx. + while cur < len { + if !f(&mut self[cur]) { + cur += 1; + continue; + } + + self.swap(idx, cur); + cur += 1; + idx += 1; + } + // Stage 3: Trancate all values after idx. + if cur != idx { + self.truncate(idx); + } + } +} diff --git a/vendor/ring/src/arithmetic/nonnegative.rs b/vendor/ring/src/arithmetic/nonnegative.rs new file mode 100644 index 0000000000000..836f088756ccb --- /dev/null +++ b/vendor/ring/src/arithmetic/nonnegative.rs @@ -0,0 +1,70 @@ +// Copyright 2015-2023 Brian Smith. +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use crate::{ + bits, error, + limb::{self, Limb, LimbMask, LIMB_BYTES}, +}; +use alloc::{boxed::Box, vec, vec::Vec}; + +/// Nonnegative integers. +pub(crate) struct Nonnegative { + limbs: Vec, +} + +impl Nonnegative { + pub fn from_be_bytes_with_bit_length( + input: untrusted::Input, + ) -> Result<(Self, bits::BitLength), error::Unspecified> { + let mut limbs = vec![0; (input.len() + LIMB_BYTES - 1) / LIMB_BYTES]; + // Rejects empty inputs. + limb::parse_big_endian_and_pad_consttime(input, &mut limbs)?; + while limbs.last() == Some(&0) { + let _ = limbs.pop(); + } + let r_bits = limb::limbs_minimal_bits(&limbs); + Ok((Self { limbs }, r_bits)) + } + + #[inline] + pub fn is_odd(&self) -> bool { + limb::limbs_are_even_constant_time(&self.limbs) != LimbMask::True + } + + pub fn verify_less_than(&self, other: &Self) -> Result<(), error::Unspecified> { + if !greater_than(other, self) { + return Err(error::Unspecified); + } + Ok(()) + } + + #[inline] + pub fn limbs(&self) -> &[Limb] { + &self.limbs + } + + #[inline] + pub fn into_limbs(self) -> Box<[Limb]> { + self.limbs.into_boxed_slice() + } +} + +// Returns a > b. +fn greater_than(a: &Nonnegative, b: &Nonnegative) -> bool { + if a.limbs.len() == b.limbs.len() { + limb::limbs_less_than_limbs_vartime(&b.limbs, &a.limbs) + } else { + a.limbs.len() > b.limbs.len() + } +} diff --git a/vendor/ring/src/polyfill/chunks_fixed.rs b/vendor/ring/src/polyfill/chunks_fixed.rs new file mode 100644 index 0000000000000..ac6f18064034a --- /dev/null +++ b/vendor/ring/src/polyfill/chunks_fixed.rs @@ -0,0 +1,31 @@ +/// Allows splitting a reference to an array type into fixed-length chunks. +pub trait ChunksFixed<'a, Chunks> +where + Chunks: 'a, +{ + fn chunks_fixed(self) -> Chunks; +} + +/// `$unchuncked_len` must be divisible by `$chunk_len`. +macro_rules! define_chunks_fixed { + ( $unchuncked_len:expr, $chunk_len:expr ) => { + define_chunks_fixed!($unchuncked_len, $chunk_len, $unchuncked_len / $chunk_len); + }; + + ( $unchuncked_len:expr, $chunk_len:expr, $chunked_len:expr ) => { + impl<'a, T> ChunksFixed<'a, &'a [[T; $chunk_len]; $chunked_len]> + for &'a [T; $unchuncked_len] + { + #[inline(always)] + fn chunks_fixed(self) -> &'a [[T; $chunk_len]; $chunked_len] { + let as_ptr: *const [T; $chunk_len] = self.as_ptr() as *const [T; $chunk_len]; + let as_ptr = as_ptr as *const [[T; $chunk_len]; $chunked_len]; + unsafe { &*as_ptr } + } + } + }; +} + +// Sorted by the first value, then the second value. +define_chunks_fixed!(64, 32); +define_chunks_fixed!(80, 20); diff --git a/vendor/rmp/tests/func/mod.rs b/vendor/rmp/tests/func/mod.rs new file mode 100644 index 0000000000000..5d450e6cc3884 --- /dev/null +++ b/vendor/rmp/tests/func/mod.rs @@ -0,0 +1,3 @@ +mod decode; +mod encode; +mod mirror; diff --git a/vendor/rstest/LICENCE-MIT b/vendor/rstest/LICENCE-MIT new file mode 100644 index 0000000000000..b1d8b47414c99 --- /dev/null +++ b/vendor/rstest/LICENCE-MIT @@ -0,0 +1,18 @@ +Copyright 2018-19 Michele d'Amico + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/rstest_macros/LICENCE-MIT b/vendor/rstest_macros/LICENCE-MIT new file mode 100644 index 0000000000000..b1d8b47414c99 --- /dev/null +++ b/vendor/rstest_macros/LICENCE-MIT @@ -0,0 +1,18 @@ +Copyright 2018-19 Michele d'Amico + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/rustix/src/maybe_polyfill/no_std/net/ip_addr.rs b/vendor/rustix/src/maybe_polyfill/no_std/net/ip_addr.rs new file mode 100644 index 0000000000000..81415e960f9a8 --- /dev/null +++ b/vendor/rustix/src/maybe_polyfill/no_std/net/ip_addr.rs @@ -0,0 +1,2068 @@ +//! The following is derived from Rust's +//! library/std/src/net/ip_addr.rs at revision +//! bd20fc1fd657b32f7aa1d70d8723f04c87f21606. +//! +//! All code in this file is licensed MIT or Apache 2.0 at your option. +//! +//! This defines `IpAddr`, `Ipv4Addr`, and `Ipv6Addr`. Ideally, these should be +//! defined in `core`. See [RFC 2832]. +//! +//! [RFC 2832]: https://github.com/rust-lang/rfcs/pull/2832 + +#![allow(unsafe_code)] + +use core::cmp::Ordering; +use core::mem::transmute; + +/// An IP address, either IPv4 or IPv6. +/// +/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their +/// respective documentation for more details. +/// +/// # Examples +/// +/// ``` +/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +/// +/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); +/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); +/// +/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4)); +/// assert_eq!("::1".parse(), Ok(localhost_v6)); +/// +/// assert_eq!(localhost_v4.is_ipv6(), false); +/// assert_eq!(localhost_v4.is_ipv4(), true); +/// ``` +#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] +#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub enum IpAddr { + /// An IPv4 address. + #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] + V4(#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] Ipv4Addr), + /// An IPv6 address. + #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] + V6(#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] Ipv6Addr), +} + +/// An IPv4 address. +/// +/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. +/// They are usually represented as four octets. +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 +/// +/// # Textual representation +/// +/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal +/// notation, divided by `.` (this is called "dot-decimal notation"). +/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which +/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943]. +/// +/// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1 +/// [`FromStr`]: core::str::FromStr +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv4Addr; +/// +/// let localhost = Ipv4Addr::new(127, 0, 0, 1); +/// assert_eq!("127.0.0.1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); +/// assert!("012.004.002.000".parse::().is_err()); // all octets are in octal +/// assert!("0000000.0.0.0".parse::().is_err()); // first octet is a zero in octal +/// assert!("0xcb.0x0.0x71.0x00".parse::().is_err()); // all octets are in hex +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub struct Ipv4Addr { + octets: [u8; 4], +} + +/// An IPv6 address. +/// +/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. +/// They are usually represented as eight 16-bit segments. +/// +/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 +/// +/// # Embedding IPv4 Addresses +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined: +/// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated. +/// +/// Both types of addresses are not assigned any special meaning by this implementation, +/// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`, +/// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is. +/// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address. +/// +/// ### IPv4-Compatible IPv6 Addresses +/// +/// IPv4-compatible IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.1], and have been officially deprecated. +/// The RFC describes the format of an "IPv4-Compatible IPv6 address" as follows: +/// +/// ```text +/// | 80 bits | 16 | 32 bits | +/// +--------------------------------------+--------------------------+ +/// |0000..............................0000|0000| IPv4 address | +/// +--------------------------------------+----+---------------------+ +/// ``` +/// So `::a.b.c.d` would be an IPv4-compatible IPv6 address representing the IPv4 address `a.b.c.d`. +/// +/// To convert from an IPv4 address to an IPv4-compatible IPv6 address, use [`Ipv4Addr::to_ipv6_compatible`]. +/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-compatible IPv6 address to the canonical IPv4 address. +/// +/// [IETF RFC 4291 Section 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1 +/// +/// ### IPv4-Mapped IPv6 Addresses +/// +/// IPv4-mapped IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.2]. +/// The RFC describes the format of an "IPv4-Mapped IPv6 address" as follows: +/// +/// ```text +/// | 80 bits | 16 | 32 bits | +/// +--------------------------------------+--------------------------+ +/// |0000..............................0000|FFFF| IPv4 address | +/// +--------------------------------------+----+---------------------+ +/// ``` +/// So `::ffff:a.b.c.d` would be an IPv4-mapped IPv6 address representing the IPv4 address `a.b.c.d`. +/// +/// To convert from an IPv4 address to an IPv4-mapped IPv6 address, use [`Ipv4Addr::to_ipv6_mapped`]. +/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-mapped IPv6 address to the canonical IPv4 address. +/// Note that this will also convert the IPv6 loopback address `::1` to `0.0.0.1`. Use +/// [`Ipv6Addr::to_ipv4_mapped`] to avoid this. +/// +/// [IETF RFC 4291 Section 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2 +/// +/// # Textual representation +/// +/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent +/// an IPv6 address in text, but in general, each segments is written in hexadecimal +/// notation, and segments are separated by `:`. For more information, see +/// [IETF RFC 5952]. +/// +/// [`FromStr`]: core::str::FromStr +/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv6Addr; +/// +/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); +/// assert_eq!("::1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub struct Ipv6Addr { + octets: [u8; 16], +} + +/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2]. +/// +/// # Stability Guarantees +/// +/// Not all possible values for a multicast scope have been assigned. +/// Future RFCs may introduce new scopes, which will be added as variants to this enum; +/// because of this the enum is marked as `#[non_exhaustive]`. +/// +/// # Examples +/// ``` +/// #![feature(ip)] +/// +/// use std::net::Ipv6Addr; +/// use std::net::Ipv6MulticastScope::*; +/// +/// // An IPv6 multicast address with global scope (`ff0e::`). +/// let address = Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0); +/// +/// // Will print "Global scope". +/// match address.multicast_scope() { +/// Some(InterfaceLocal) => println!("Interface-Local scope"), +/// Some(LinkLocal) => println!("Link-Local scope"), +/// Some(RealmLocal) => println!("Realm-Local scope"), +/// Some(AdminLocal) => println!("Admin-Local scope"), +/// Some(SiteLocal) => println!("Site-Local scope"), +/// Some(OrganizationLocal) => println!("Organization-Local scope"), +/// Some(Global) => println!("Global scope"), +/// Some(_) => println!("Unknown scope"), +/// None => println!("Not a multicast address!") +/// } +/// +/// ``` +/// +/// [IPv6 multicast address]: Ipv6Addr +/// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2 +#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] +#[non_exhaustive] +pub enum Ipv6MulticastScope { + /// Interface-Local scope. + InterfaceLocal, + /// Link-Local scope. + LinkLocal, + /// Realm-Local scope. + RealmLocal, + /// Admin-Local scope. + AdminLocal, + /// Site-Local scope. + SiteLocal, + /// Organization-Local scope. + OrganizationLocal, + /// Global scope. + Global, +} + +impl IpAddr { + /// Returns [`true`] for the special 'unspecified' address. + /// + /// See the documentation for [`Ipv4Addr::is_unspecified()`] and + /// [`Ipv6Addr::is_unspecified()`] for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] + #[must_use] + #[inline] + pub const fn is_unspecified(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_unspecified(), + IpAddr::V6(ip) => ip.is_unspecified(), + } + } + + /// Returns [`true`] if this is a loopback address. + /// + /// See the documentation for [`Ipv4Addr::is_loopback()`] and + /// [`Ipv6Addr::is_loopback()`] for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] + #[must_use] + #[inline] + pub const fn is_loopback(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_loopback(), + IpAddr::V6(ip) => ip.is_loopback(), + } + } + + /// Returns [`true`] if the address appears to be globally routable. + /// + /// See the documentation for [`Ipv4Addr::is_global()`] and + /// [`Ipv6Addr::is_global()`] for more details. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ip", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_global(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_global(), + IpAddr::V6(ip) => ip.is_global(), + } + } + + /// Returns [`true`] if this is a multicast address. + /// + /// See the documentation for [`Ipv4Addr::is_multicast()`] and + /// [`Ipv6Addr::is_multicast()`] for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] + #[must_use] + #[inline] + pub const fn is_multicast(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_multicast(), + IpAddr::V6(ip) => ip.is_multicast(), + } + } + + /// Returns [`true`] if this address is in a range designated for documentation. + /// + /// See the documentation for [`Ipv4Addr::is_documentation()`] and + /// [`Ipv6Addr::is_documentation()`] for more details. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(), + /// true + /// ); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ip", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_documentation(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_documentation(), + IpAddr::V6(ip) => ip.is_documentation(), + } + } + + /// Returns [`true`] if this address is in a range designated for benchmarking. + /// + /// See the documentation for [`Ipv4Addr::is_benchmarking()`] and + /// [`Ipv6Addr::is_benchmarking()`] for more details. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255)).is_benchmarking(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true); + /// ``` + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_benchmarking(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_benchmarking(), + IpAddr::V6(ip) => ip.is_benchmarking(), + } + } + + /// Returns [`true`] if this address is an [`IPv4` address], and [`false`] + /// otherwise. + /// + /// [`IPv4` address]: IpAddr::V4 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "ipaddr_checker", since = "1.16.0"))] + #[must_use] + #[inline] + pub const fn is_ipv4(&self) -> bool { + matches!(self, IpAddr::V4(_)) + } + + /// Returns [`true`] if this address is an [`IPv6` address], and [`false`] + /// otherwise. + /// + /// [`IPv6` address]: IpAddr::V6 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "ipaddr_checker", since = "1.16.0"))] + #[must_use] + #[inline] + pub const fn is_ipv6(&self) -> bool { + matches!(self, IpAddr::V6(_)) + } + + /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped IPv6 addresses, otherwise it + /// return `self` as-is. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true); + /// ``` + #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ip", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + pub const fn to_canonical(&self) -> IpAddr { + match self { + &v4 @ IpAddr::V4(_) => v4, + IpAddr::V6(v6) => v6.to_canonical(), + } + } +} + +impl Ipv4Addr { + /// Creates a new IPv4 address from four eight-bit octets. + /// + /// The result will represent the IP address `a`.`b`.`c`.`d`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_32", since = "1.32.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use] + #[inline] + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + Ipv4Addr { + octets: [a, b, c, d], + } + } + + /// An IPv4 address with the address pointing to localhost: `127.0.0.1` + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::LOCALHOST; + /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); + /// ``` + #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] + pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); + + /// An IPv4 address representing an unspecified address: `0.0.0.0` + /// + /// This corresponds to the constant `INADDR_ANY` in other languages. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::UNSPECIFIED; + /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); + /// ``` + #[doc(alias = "INADDR_ANY")] + #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] + pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); + + /// An IPv4 address representing the broadcast address: `255.255.255.255` + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::BROADCAST; + /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255)); + /// ``` + #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] + pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); + + /// Returns the four eight-bit integers that make up this address. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// assert_eq!(addr.octets(), [127, 0, 0, 1]); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use] + #[inline] + pub const fn octets(&self) -> [u8; 4] { + self.octets + } + + /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`). + /// + /// This property is defined in _UNIX Network Programming, Second Edition_, + /// W. Richard Stevens, p. 891; see also [ip7]. + /// + /// [ip7]: https://man7.org/linux/man-pages/man7/ip.7.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); + /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_32", since = "1.32.0") + )] + #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] + #[must_use] + #[inline] + pub const fn is_unspecified(&self) -> bool { + u32::from_be_bytes(self.octets) == 0 + } + + /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`). + /// + /// This property is defined by [IETF RFC 1122]. + /// + /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); + /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_loopback(&self) -> bool { + self.octets()[0] == 127 + } + + /// Returns [`true`] if this is a private address. + /// + /// The private address ranges are defined in [IETF RFC 1918] and include: + /// + /// - `10.0.0.0/8` + /// - `172.16.0.0/12` + /// - `192.168.0.0/16` + /// + /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true); + /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); + /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_private(&self) -> bool { + match self.octets() { + [10, ..] => true, + [172, b, ..] if b >= 16 && b <= 31 => true, + [192, 168, ..] => true, + _ => false, + } + } + + /// Returns [`true`] if the address is link-local (`169.254.0.0/16`). + /// + /// This property is defined by [IETF RFC 3927]. + /// + /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true); + /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); + /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_link_local(&self) -> bool { + matches!(self.octets(), [169, 254, ..]) + } + + /// Returns [`true`] if the address appears to be globally reachable + /// as specified by the [IANA IPv4 Special-Purpose Address Registry]. + /// Whether or not an address is practically reachable will depend on your network configuration. + /// + /// Most IPv4 addresses are globally reachable; + /// unless they are specifically defined as *not* globally reachable. + /// + /// Non-exhaustive list of notable addresses that are not globally reachable: + /// + /// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified)) + /// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private)) + /// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared)) + /// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback)) + /// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local)) + /// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation)) + /// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking)) + /// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved)) + /// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast)) + /// + /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv4 Special-Purpose Address Registry]. + /// + /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml + /// [unspecified address]: Ipv4Addr::UNSPECIFIED + /// [broadcast address]: Ipv4Addr::BROADCAST + + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv4Addr; + /// + /// // Most IPv4 addresses are globally reachable: + /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); + /// + /// // However some addresses have been assigned a special meaning + /// // that makes them not globally reachable. Some examples are: + /// + /// // The unspecified address (`0.0.0.0`) + /// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false); + /// + /// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16) + /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); + /// + /// // Addresses in the shared address space (`100.64.0.0/10`) + /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); + /// + /// // The loopback addresses (`127.0.0.0/8`) + /// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false); + /// + /// // Link-local addresses (`169.254.0.0/16`) + /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); + /// + /// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`) + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); + /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); + /// + /// // Addresses reserved for benchmarking (`198.18.0.0/15`) + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); + /// + /// // Reserved addresses (`240.0.0.0/4`) + /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); + /// + /// // The broadcast address (`255.255.255.255`) + /// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false); + /// + /// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry. + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv4", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_global(&self) -> bool { + !(self.octets()[0] == 0 // "This network" + || self.is_private() + || self.is_shared() + || self.is_loopback() + || self.is_link_local() + // addresses reserved for future protocols (`192.0.0.0/24`) + ||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0) + || self.is_documentation() + || self.is_benchmarking() + || self.is_reserved() + || self.is_broadcast()) + } + + /// Returns [`true`] if this address is part of the Shared Address Space defined in + /// [IETF RFC 6598] (`100.64.0.0/10`). + /// + /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv4", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_shared(&self) -> bool { + self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) + } + + /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for + /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` + /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. + /// + /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544 + /// [errata 423]: https://www.rfc-editor.org/errata/eid423 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv4", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_benchmarking(&self) -> bool { + self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 + } + + /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] + /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the + /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since + /// it is obviously not reserved for future use. + /// + /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 + /// + /// # Warning + /// + /// As IANA assigns new addresses, this method will be + /// updated. This may result in non-reserved addresses being + /// treated as reserved in code that relies on an outdated version + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); + /// + /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); + /// // The broadcast address is not considered as reserved for future use by this implementation + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv4", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_reserved(&self) -> bool { + self.octets()[0] & 240 == 240 && !self.is_broadcast() + } + + /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`). + /// + /// Multicast addresses have a most significant octet between `224` and `239`, + /// and is defined by [IETF RFC 5771]. + /// + /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true); + /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_multicast(&self) -> bool { + self.octets()[0] >= 224 && self.octets()[0] <= 239 + } + + /// Returns [`true`] if this is a broadcast address (`255.255.255.255`). + /// + /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919]. + /// + /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); + /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_broadcast(&self) -> bool { + u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) + } + + /// Returns [`true`] if this address is in a range designated for documentation. + /// + /// This is defined in [IETF RFC 5737]: + /// + /// - `192.0.2.0/24` (TEST-NET-1) + /// - `198.51.100.0/24` (TEST-NET-2) + /// - `203.0.113.0/24` (TEST-NET-3) + /// + /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_documentation(&self) -> bool { + matches!( + self.octets(), + [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _] + ) + } + + /// Converts this address to an [IPv4-compatible] [`IPv6` address]. + /// + /// `a.b.c.d` becomes `::a.b.c.d` + /// + /// Note that IPv4-compatible addresses have been officially deprecated. + /// If you don't explicitly need an IPv4-compatible address for legacy reasons, consider using `to_ipv6_mapped` instead. + /// + /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses + /// [`IPv6` address]: Ipv6Addr + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!( + /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff) + /// ); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { + let [a, b, c, d] = self.octets(); + Ipv6Addr { + octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d], + } + } + + /// Converts this address to an [IPv4-mapped] [`IPv6` address]. + /// + /// `a.b.c.d` becomes `::ffff:a.b.c.d` + /// + /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses + /// [`IPv6` address]: Ipv6Addr + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff)); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { + let [a, b, c, d] = self.octets(); + Ipv6Addr { + octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d], + } + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))] +impl From for IpAddr { + /// Copies this address to a new `IpAddr::V4`. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr}; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// + /// assert_eq!( + /// IpAddr::V4(addr), + /// IpAddr::from(addr) + /// ) + /// ``` + #[inline] + fn from(ipv4: Ipv4Addr) -> IpAddr { + IpAddr::V4(ipv4) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))] +impl From for IpAddr { + /// Copies this address to a new `IpAddr::V6`. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); + /// + /// assert_eq!( + /// IpAddr::V6(addr), + /// IpAddr::from(addr) + /// ); + /// ``` + #[inline] + fn from(ipv6: Ipv6Addr) -> IpAddr { + IpAddr::V6(ipv6) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialEq for IpAddr { + #[inline] + fn eq(&self, other: &Ipv4Addr) -> bool { + match self { + IpAddr::V4(v4) => v4 == other, + IpAddr::V6(_) => false, + } + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialEq for Ipv4Addr { + #[inline] + fn eq(&self, other: &IpAddr) -> bool { + match other { + IpAddr::V4(v4) => self == v4, + IpAddr::V6(_) => false, + } + } +} + +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +impl PartialOrd for Ipv4Addr { + #[inline] + fn partial_cmp(&self, other: &Ipv4Addr) -> Option { + Some(self.cmp(other)) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialOrd for IpAddr { + #[inline] + fn partial_cmp(&self, other: &Ipv4Addr) -> Option { + match self { + IpAddr::V4(v4) => v4.partial_cmp(other), + IpAddr::V6(_) => Some(Ordering::Greater), + } + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialOrd for Ipv4Addr { + #[inline] + fn partial_cmp(&self, other: &IpAddr) -> Option { + match other { + IpAddr::V4(v4) => self.partial_cmp(v4), + IpAddr::V6(_) => Some(Ordering::Less), + } + } +} + +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +impl Ord for Ipv4Addr { + #[inline] + fn cmp(&self, other: &Ipv4Addr) -> Ordering { + self.octets.cmp(&other.octets) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_u32", since = "1.1.0"))] +impl From for u32 { + /// Converts an `Ipv4Addr` into a host byte order `u32`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78); + /// assert_eq!(0x12345678, u32::from(addr)); + /// ``` + #[inline] + fn from(ip: Ipv4Addr) -> u32 { + u32::from_be_bytes(ip.octets) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_u32", since = "1.1.0"))] +impl From for Ipv4Addr { + /// Converts a host byte order `u32` into an `Ipv4Addr`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::from(0x12345678); + /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr); + /// ``` + #[inline] + fn from(ip: u32) -> Ipv4Addr { + Ipv4Addr { + octets: ip.to_be_bytes(), + } + } +} + +#[cfg_attr(staged_api, stable(feature = "from_slice_v4", since = "1.9.0"))] +impl From<[u8; 4]> for Ipv4Addr { + /// Creates an `Ipv4Addr` from a four element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]); + /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); + /// ``` + #[inline] + fn from(octets: [u8; 4]) -> Ipv4Addr { + Ipv4Addr { octets } + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))] +impl From<[u8; 4]> for IpAddr { + /// Creates an `IpAddr::V4` from a four element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr}; + /// + /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]); + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr); + /// ``` + #[inline] + fn from(octets: [u8; 4]) -> IpAddr { + IpAddr::V4(Ipv4Addr::from(octets)) + } +} + +impl Ipv6Addr { + /// Creates a new IPv6 address from eight 16-bit segments. + /// + /// The result will represent the IP address `a:b:c:d:e:f:g:h`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_32", since = "1.32.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[allow(clippy::too_many_arguments)] + #[must_use] + #[inline] + pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { + let addr16 = [ + a.to_be(), + b.to_be(), + c.to_be(), + d.to_be(), + e.to_be(), + f.to_be(), + g.to_be(), + h.to_be(), + ]; + Ipv6Addr { + // All elements in `addr16` are big endian. + // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`. + octets: unsafe { transmute::<_, [u8; 16]>(addr16) }, + } + } + + /// An IPv6 address representing localhost: `::1`. + /// + /// This corresponds to constant `IN6ADDR_LOOPBACK_INIT` or `in6addr_loopback` in other + /// languages. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::LOCALHOST; + /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + /// ``` + #[doc(alias = "IN6ADDR_LOOPBACK_INIT")] + #[doc(alias = "in6addr_loopback")] + #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] + pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + + /// An IPv6 address representing the unspecified address: `::` + /// + /// This corresponds to constant `IN6ADDR_ANY_INIT` or `in6addr_any` in other languages. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::UNSPECIFIED; + /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + /// ``` + #[doc(alias = "IN6ADDR_ANY_INIT")] + #[doc(alias = "in6addr_any")] + #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] + pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + + /// Returns the eight 16-bit segments that make up this address. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), + /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use] + #[inline] + pub const fn segments(&self) -> [u16; 8] { + // All elements in `self.octets` must be big endian. + // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`. + let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.octets) }; + // We want native endian u16 + [ + u16::from_be(a), + u16::from_be(b), + u16::from_be(c), + u16::from_be(d), + u16::from_be(e), + u16::from_be(f), + u16::from_be(g), + u16::from_be(h), + ] + } + + /// Returns [`true`] for the special 'unspecified' address (`::`). + /// + /// This property is defined in [IETF RFC 4291]. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_unspecified(&self) -> bool { + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) + } + + /// Returns [`true`] if this is the [loopback address] (`::1`), + /// as defined in [IETF RFC 4291 section 2.5.3]. + /// + /// Contrary to IPv4, in IPv6 there is only one loopback address. + /// + /// [loopback address]: Ipv6Addr::LOCALHOST + /// [IETF RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_loopback(&self) -> bool { + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) + } + + /// Returns [`true`] if the address appears to be globally reachable + /// as specified by the [IANA IPv6 Special-Purpose Address Registry]. + /// Whether or not an address is practically reachable will depend on your network configuration. + /// + /// Most IPv6 addresses are globally reachable; + /// unless they are specifically defined as *not* globally reachable. + /// + /// Non-exhaustive list of notable addresses that are not globally reachable: + /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified)) + /// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback)) + /// - IPv4-mapped addresses + /// - Addresses reserved for benchmarking + /// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation)) + /// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local)) + /// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local)) + /// + /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry]. + /// + /// Note that an address having global scope is not the same as being globally reachable, + /// and there is no direct relation between the two concepts: There exist addresses with global scope + /// that are not globally reachable (for example unique local addresses), + /// and addresses that are globally reachable without having global scope + /// (multicast addresses with non-global scope). + /// + /// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml + /// [unspecified address]: Ipv6Addr::UNSPECIFIED + /// [loopback address]: Ipv6Addr::LOCALHOST + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// // Most IPv6 addresses are globally reachable: + /// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true); + /// + /// // However some addresses have been assigned a special meaning + /// // that makes them not globally reachable. Some examples are: + /// + /// // The unspecified address (`::`) + /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false); + /// + /// // The loopback address (`::1`) + /// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false); + /// + /// // IPv4-mapped addresses (`::ffff:0:0/96`) + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false); + /// + /// // Addresses reserved for benchmarking (`2001:2::/48`) + /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false); + /// + /// // Addresses reserved for documentation (`2001:db8::/32`) + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false); + /// + /// // Unique local addresses (`fc00::/7`) + /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false); + /// + /// // Unicast addresses with link-local scope (`fe80::/10`) + /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false); + /// + /// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry. + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_global(&self) -> bool { + !(self.is_unspecified() + || self.is_loopback() + // IPv4-mapped Address (`::ffff:0:0/96`) + || matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _]) + // IPv4-IPv6 Translat. (`64:ff9b:1::/48`) + || matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _]) + // Discard-Only Address Block (`100::/64`) + || matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _]) + // IETF Protocol Assignments (`2001::/23`) + || (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200) + && !( + // Port Control Protocol Anycast (`2001:1::1`) + u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001 + // Traversal Using Relays around NAT Anycast (`2001:1::2`) + || u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002 + // AMT (`2001:3::/32`) + || matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _]) + // AS112-v6 (`2001:4:112::/48`) + || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _]) + // ORCHIDv2 (`2001:20::/28`) + || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F) + )) + || self.is_documentation() + || self.is_unique_local() + || self.is_unicast_link_local()) + } + + /// Returns [`true`] if this is a unique local address (`fc00::/7`). + /// + /// This property is defined in [IETF RFC 4193]. + /// + /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); + /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_unique_local(&self) -> bool { + (self.segments()[0] & 0xfe00) == 0xfc00 + } + + /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291]. + /// Any address that is not a [multicast address] (`ff00::/8`) is unicast. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [multicast address]: Ipv6Addr::is_multicast + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// // The unspecified and loopback addresses are unicast. + /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true); + /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true); + /// + /// // Any address that is not a multicast address (`ff00::/8`) is unicast. + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true); + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_unicast(&self) -> bool { + !self.is_multicast() + } + + /// Returns `true` if the address is a unicast address with link-local scope, + /// as defined in [RFC 4291]. + /// + /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4]. + /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6], + /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format: + /// + /// ```text + /// | 10 bits | 54 bits | 64 bits | + /// +----------+-------------------------+----------------------------+ + /// |1111111010| 0 | interface ID | + /// +----------+-------------------------+----------------------------+ + /// ``` + /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`, + /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated, + /// and those addresses will have link-local scope. + /// + /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope", + /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it. + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 + /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 + /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 + /// [loopback address]: Ipv6Addr::LOCALHOST + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// // The loopback address (`::1`) does not actually have link-local scope. + /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false); + /// + /// // Only addresses in `fe80::/10` have link-local scope. + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false); + /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); + /// + /// // Addresses outside the stricter `fe80::/64` also have link-local scope. + /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true); + /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_unicast_link_local(&self) -> bool { + (self.segments()[0] & 0xffc0) == 0xfe80 + } + + /// Returns [`true`] if this is an address reserved for documentation + /// (`2001:db8::/32`). + /// + /// This property is defined in [IETF RFC 3849]. + /// + /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_documentation(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) + } + + /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`). + /// + /// This property is defined in [IETF RFC 5180], where it is mistakenly specified as covering the range `2001:0200::/48`. + /// This is corrected in [IETF RFC Errata 1752] to `2001:0002::/48`. + /// + /// [IETF RFC 5180]: https://tools.ietf.org/html/rfc5180 + /// [IETF RFC Errata 1752]: https://www.rfc-editor.org/errata_search.php?eid=1752 + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc613, 0x0).is_benchmarking(), false); + /// assert_eq!(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0).is_benchmarking(), true); + /// ``` + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_benchmarking(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0) + } + + /// Returns [`true`] if the address is a globally routable unicast address. + /// + /// The following return false: + /// + /// - the loopback address + /// - the link-local addresses + /// - unique local addresses + /// - the unspecified address + /// - the address range reserved for documentation + /// + /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7] + /// + /// ```no_rust + /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer + /// be supported in new implementations (i.e., new implementations must treat this prefix as + /// Global Unicast). + /// ``` + /// + /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn is_unicast_global(&self) -> bool { + self.is_unicast() + && !self.is_loopback() + && !self.is_unicast_link_local() + && !self.is_unique_local() + && !self.is_unspecified() + && !self.is_documentation() + && !self.is_benchmarking() + } + + /// Returns the address' multicast scope if the address is multicast. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; + /// + /// assert_eq!( + /// Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), + /// Some(Ipv6MulticastScope::Global) + /// ); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use] + #[inline] + pub const fn multicast_scope(&self) -> Option { + if self.is_multicast() { + match self.segments()[0] & 0x000f { + 1 => Some(Ipv6MulticastScope::InterfaceLocal), + 2 => Some(Ipv6MulticastScope::LinkLocal), + 3 => Some(Ipv6MulticastScope::RealmLocal), + 4 => Some(Ipv6MulticastScope::AdminLocal), + 5 => Some(Ipv6MulticastScope::SiteLocal), + 8 => Some(Ipv6MulticastScope::OrganizationLocal), + 14 => Some(Ipv6MulticastScope::Global), + _ => None, + } + } else { + None + } + } + + /// Returns [`true`] if this is a multicast address (`ff00::/8`). + /// + /// This property is defined by [IETF RFC 4291]. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] + #[must_use] + #[inline] + pub const fn is_multicast(&self) -> bool { + (self.segments()[0] & 0xff00) == 0xff00 + } + + /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address, + /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`]. + /// + /// `::ffff:a.b.c.d` becomes `a.b.c.d`. + /// All addresses *not* starting with `::ffff` will return `None`. + /// + /// [`IPv4` address]: Ipv4Addr + /// [IPv4-mapped]: Ipv6Addr + /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(), + /// Some(Ipv4Addr::new(192, 10, 2, 255))); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0"))] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_ipv4_mapped(&self) -> Option { + match self.octets() { + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => { + Some(Ipv4Addr::new(a, b, c, d)) + } + _ => None, + } + } + + /// Converts this address to an [`IPv4` address] if it is either + /// an [IPv4-compatible] address as defined in [IETF RFC 4291 section 2.5.5.1], + /// or an [IPv4-mapped] address as defined in [IETF RFC 4291 section 2.5.5.2], + /// otherwise returns [`None`]. + /// + /// Note that this will return an [`IPv4` address] for the IPv6 loopback address `::1`. Use + /// [`Ipv6Addr::to_ipv4_mapped`] to avoid this. + /// + /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`. `::1` becomes `0.0.0.1`. + /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`. + /// + /// [`IPv4` address]: Ipv4Addr + /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses + /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses + /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1 + /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), + /// Some(Ipv4Addr::new(192, 10, 2, 255))); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), + /// Some(Ipv4Addr::new(0, 0, 0, 1))); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_50", since = "1.50.0") + )] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_ipv4(&self) -> Option { + if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { + let [a, b] = ab.to_be_bytes(); + let [c, d] = cd.to_be_bytes(); + Some(Ipv4Addr::new(a, b, c, d)) + } else { + None + } + } + + /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped addresses, otherwise it + /// returns self wrapped in an `IpAddr::V6`. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_ipv6", issue = "76205") + )] + #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_canonical(&self) -> IpAddr { + if let Some(mapped) = self.to_ipv4_mapped() { + return IpAddr::V4(mapped); + } + IpAddr::V6(*self) + } + + /// Returns the sixteen eight-bit integers the IPv6 address consists of. + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), + /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// ``` + #[cfg_attr( + staged_api, + rustc_const_stable(feature = "const_ip_32", since = "1.32.0") + )] + #[cfg_attr(staged_api, stable(feature = "ipv6_to_octets", since = "1.12.0"))] + #[must_use] + #[inline] + pub const fn octets(&self) -> [u8; 16] { + self.octets + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialEq for Ipv6Addr { + #[inline] + fn eq(&self, other: &IpAddr) -> bool { + match other { + IpAddr::V4(_) => false, + IpAddr::V6(v6) => self == v6, + } + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialEq for IpAddr { + #[inline] + fn eq(&self, other: &Ipv6Addr) -> bool { + match self { + IpAddr::V4(_) => false, + IpAddr::V6(v6) => v6 == other, + } + } +} + +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +impl PartialOrd for Ipv6Addr { + #[inline] + fn partial_cmp(&self, other: &Ipv6Addr) -> Option { + Some(self.cmp(other)) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialOrd for IpAddr { + #[inline] + fn partial_cmp(&self, other: &Ipv6Addr) -> Option { + match self { + IpAddr::V4(_) => Some(Ordering::Less), + IpAddr::V6(v6) => v6.partial_cmp(other), + } + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] +impl PartialOrd for Ipv6Addr { + #[inline] + fn partial_cmp(&self, other: &IpAddr) -> Option { + match other { + IpAddr::V4(_) => Some(Ordering::Greater), + IpAddr::V6(v6) => self.partial_cmp(v6), + } + } +} + +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +impl Ord for Ipv6Addr { + #[inline] + fn cmp(&self, other: &Ipv6Addr) -> Ordering { + self.segments().cmp(&other.segments()) + } +} + +#[cfg_attr(staged_api, stable(feature = "i128", since = "1.26.0"))] +impl From for u128 { + /// Convert an `Ipv6Addr` into a host byte order `u128`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::new( + /// 0x1020, 0x3040, 0x5060, 0x7080, + /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, + /// ); + /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr)); + /// ``` + #[inline] + fn from(ip: Ipv6Addr) -> u128 { + u128::from_be_bytes(ip.octets) + } +} +#[cfg_attr(staged_api, stable(feature = "i128", since = "1.26.0"))] +impl From for Ipv6Addr { + /// Convert a host byte order `u128` into an `Ipv6Addr`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128); + /// assert_eq!( + /// Ipv6Addr::new( + /// 0x1020, 0x3040, 0x5060, 0x7080, + /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, + /// ), + /// addr); + /// ``` + #[inline] + fn from(ip: u128) -> Ipv6Addr { + Ipv6Addr::from(ip.to_be_bytes()) + } +} + +#[cfg_attr(staged_api, stable(feature = "ipv6_from_octets", since = "1.9.0"))] +impl From<[u8; 16]> for Ipv6Addr { + /// Creates an `Ipv6Addr` from a sixteen element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::from([ + /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, + /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, + /// ]); + /// assert_eq!( + /// Ipv6Addr::new( + /// 0x1918, 0x1716, + /// 0x1514, 0x1312, + /// 0x1110, 0x0f0e, + /// 0x0d0c, 0x0b0a + /// ), + /// addr + /// ); + /// ``` + #[inline] + fn from(octets: [u8; 16]) -> Ipv6Addr { + Ipv6Addr { octets } + } +} + +#[cfg_attr(staged_api, stable(feature = "ipv6_from_segments", since = "1.16.0"))] +impl From<[u16; 8]> for Ipv6Addr { + /// Creates an `Ipv6Addr` from an eight element 16-bit array. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::from([ + /// 525u16, 524u16, 523u16, 522u16, + /// 521u16, 520u16, 519u16, 518u16, + /// ]); + /// assert_eq!( + /// Ipv6Addr::new( + /// 0x20d, 0x20c, + /// 0x20b, 0x20a, + /// 0x209, 0x208, + /// 0x207, 0x206 + /// ), + /// addr + /// ); + /// ``` + #[inline] + fn from(segments: [u16; 8]) -> Ipv6Addr { + let [a, b, c, d, e, f, g, h] = segments; + Ipv6Addr::new(a, b, c, d, e, f, g, h) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))] +impl From<[u8; 16]> for IpAddr { + /// Creates an `IpAddr::V6` from a sixteen element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = IpAddr::from([ + /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, + /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, + /// ]); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new( + /// 0x1918, 0x1716, + /// 0x1514, 0x1312, + /// 0x1110, 0x0f0e, + /// 0x0d0c, 0x0b0a + /// )), + /// addr + /// ); + /// ``` + #[inline] + fn from(octets: [u8; 16]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(octets)) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))] +impl From<[u16; 8]> for IpAddr { + /// Creates an `IpAddr::V6` from an eight element 16-bit array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = IpAddr::from([ + /// 525u16, 524u16, 523u16, 522u16, + /// 521u16, 520u16, 519u16, 518u16, + /// ]); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new( + /// 0x20d, 0x20c, + /// 0x20b, 0x20a, + /// 0x209, 0x208, + /// 0x207, 0x206 + /// )), + /// addr + /// ); + /// ``` + #[inline] + fn from(segments: [u16; 8]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(segments)) + } +} diff --git a/vendor/rustix/src/maybe_polyfill/no_std/net/socket_addr.rs b/vendor/rustix/src/maybe_polyfill/no_std/net/socket_addr.rs new file mode 100644 index 0000000000000..053d8f670b53f --- /dev/null +++ b/vendor/rustix/src/maybe_polyfill/no_std/net/socket_addr.rs @@ -0,0 +1,641 @@ +//! The following is derived from Rust's +//! library/std/src/net/socket_addr.rs at revision +//! bd20fc1fd657b32f7aa1d70d8723f04c87f21606. +//! +//! All code in this file is licensed MIT or Apache 2.0 at your option. +//! +//! This defines `SocketAddr`, `SocketAddrV4`, and `SocketAddrV6` in a +//! platform-independent way. It is not the native representation. + +use super::ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr}; +use core::cmp::Ordering; +use core::hash; + +/// An internet socket address, either IPv4 or IPv6. +/// +/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well +/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and +/// [`SocketAddrV6`]'s respective documentation for more details. +/// +/// The size of a `SocketAddr` instance may vary depending on the target operating +/// system. +/// +/// [IP address]: IpAddr +/// +/// # Examples +/// +/// ``` +/// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +/// +/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); +/// +/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); +/// assert_eq!(socket.port(), 8080); +/// assert_eq!(socket.is_ipv4(), true); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub enum SocketAddr { + /// An IPv4 socket address. + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + V4(#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] SocketAddrV4), + /// An IPv6 socket address. + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + V6(#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] SocketAddrV6), +} + +/// An IPv4 socket address. +/// +/// IPv4 socket addresses consist of an [`IPv4` address] and a 16-bit port number, as +/// stated in [IETF RFC 793]. +/// +/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. +/// +/// The size of a `SocketAddrV4` struct may vary depending on the target operating +/// system. Do not assume that this type has the same memory layout as the underlying +/// system representation. +/// +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [`IPv4` address]: Ipv4Addr +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv4Addr, SocketAddrV4}; +/// +/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); +/// +/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); +/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); +/// assert_eq!(socket.port(), 8080); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq)] +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub struct SocketAddrV4 { + ip: Ipv4Addr, + port: u16, +} + +/// An IPv6 socket address. +/// +/// IPv6 socket addresses consist of an [`IPv6` address], a 16-bit port number, as well +/// as fields containing the traffic class, the flow label, and a scope identifier +/// (see [IETF RFC 2553, Section 3.3] for more details). +/// +/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. +/// +/// The size of a `SocketAddrV6` struct may vary depending on the target operating +/// system. Do not assume that this type has the same memory layout as the underlying +/// system representation. +/// +/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 +/// [`IPv6` address]: Ipv6Addr +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv6Addr, SocketAddrV6}; +/// +/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0); +/// +/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket)); +/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); +/// assert_eq!(socket.port(), 8080); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq)] +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub struct SocketAddrV6 { + ip: Ipv6Addr, + port: u16, + flowinfo: u32, + scope_id: u32, +} + +impl SocketAddr { + /// Creates a new socket address from an [IP address] and a port number. + /// + /// [IP address]: IpAddr + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] + #[must_use] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn new(ip: IpAddr, port: u16) -> SocketAddr { + match ip { + IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)), + IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)), + } + } + + /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn ip(&self) -> IpAddr { + match *self { + SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()), + SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()), + } + } + + /// Changes the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); + /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_ip(&mut self, new_ip: IpAddr) { + // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away. + match (self, new_ip) { + (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip), + (&mut SocketAddr::V6(ref mut a), IpAddr::V6(new_ip)) => a.set_ip(new_ip), + (self_, new_ip) => *self_ = Self::new(new_ip, self_.port()), + } + } + + /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn port(&self) -> u16 { + match *self { + SocketAddr::V4(ref a) => a.port(), + SocketAddr::V6(ref a) => a.port(), + } + } + + /// Changes the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// socket.set_port(1025); + /// assert_eq!(socket.port(), 1025); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_port(&mut self, new_port: u16) { + match *self { + SocketAddr::V4(ref mut a) => a.set_port(new_port), + SocketAddr::V6(ref mut a) => a.set_port(new_port), + } + } + + /// Returns [`true`] if the [IP address] in this `SocketAddr` is an + /// [`IPv4` address], and [`false`] otherwise. + /// + /// [IP address]: IpAddr + /// [`IPv4` address]: IpAddr::V4 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.is_ipv4(), true); + /// assert_eq!(socket.is_ipv6(), false); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "sockaddr_checker", since = "1.16.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn is_ipv4(&self) -> bool { + matches!(*self, SocketAddr::V4(_)) + } + + /// Returns [`true`] if the [IP address] in this `SocketAddr` is an + /// [`IPv6` address], and [`false`] otherwise. + /// + /// [IP address]: IpAddr + /// [`IPv6` address]: IpAddr::V6 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080); + /// assert_eq!(socket.is_ipv4(), false); + /// assert_eq!(socket.is_ipv6(), true); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "sockaddr_checker", since = "1.16.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn is_ipv6(&self) -> bool { + matches!(*self, SocketAddr::V6(_)) + } +} + +impl SocketAddrV4 { + /// Creates a new socket address from an [`IPv4` address] and a port number. + /// + /// [`IPv4` address]: Ipv4Addr + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// ``` + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { + SocketAddrV4 { ip, port } + } + + /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn ip(&self) -> &Ipv4Addr { + &self.ip + } + + /// Changes the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1)); + /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1)); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_ip(&mut self, new_ip: Ipv4Addr) { + self.ip = new_ip; + } + + /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn port(&self) -> u16 { + self.port + } + + /// Changes the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// socket.set_port(4242); + /// assert_eq!(socket.port(), 4242); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_port(&mut self, new_port: u16) { + self.port = new_port; + } +} + +impl SocketAddrV6 { + /// Creates a new socket address from an [`IPv6` address], a 16-bit port number, + /// and the `flowinfo` and `scope_id` fields. + /// + /// For more information on the meaning and layout of the `flowinfo` and `scope_id` + /// parameters, see [IETF RFC 2553, Section 3.3]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// [`IPv6` address]: Ipv6Addr + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// ``` + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[must_use] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 { + SocketAddrV6 { + ip, + port, + flowinfo, + scope_id, + } + } + + /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn ip(&self) -> &Ipv6Addr { + &self.ip + } + + /// Changes the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); + /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_ip(&mut self, new_ip: Ipv6Addr) { + self.ip = new_ip; + } + + /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn port(&self) -> u16 { + self.port + } + + /// Changes the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// socket.set_port(4242); + /// assert_eq!(socket.port(), 4242); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_port(&mut self, new_port: u16) { + self.port = new_port; + } + + /// Returns the flow information associated with this address. + /// + /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`, + /// as specified in [IETF RFC 2553, Section 3.3]. + /// It combines information about the flow label and the traffic class as specified + /// in [IETF RFC 2460], respectively [Section 6] and [Section 7]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460 + /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6 + /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7 + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); + /// assert_eq!(socket.flowinfo(), 10); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn flowinfo(&self) -> u32 { + self.flowinfo + } + + /// Changes the flow information associated with this socket address. + /// + /// See [`SocketAddrV6::flowinfo`]'s documentation for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); + /// socket.set_flowinfo(56); + /// assert_eq!(socket.flowinfo(), 56); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_flowinfo(&mut self, new_flowinfo: u32) { + self.flowinfo = new_flowinfo; + } + + /// Returns the scope ID associated with this address. + /// + /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`, + /// as specified in [IETF RFC 2553, Section 3.3]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); + /// assert_eq!(socket.scope_id(), 78); + /// ``` + #[must_use] + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr( + staged_api, + rustc_const_unstable(feature = "const_socketaddr", issue = "82485") + )] + pub const fn scope_id(&self) -> u32 { + self.scope_id + } + + /// Changes the scope ID associated with this socket address. + /// + /// See [`SocketAddrV6::scope_id`]'s documentation for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); + /// socket.set_scope_id(42); + /// assert_eq!(socket.scope_id(), 42); + /// ``` + #[cfg_attr(staged_api, stable(feature = "sockaddr_setters", since = "1.9.0"))] + pub fn set_scope_id(&mut self, new_scope_id: u32) { + self.scope_id = new_scope_id; + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))] +impl From for SocketAddr { + /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`]. + fn from(sock4: SocketAddrV4) -> SocketAddr { + SocketAddr::V4(sock4) + } +} + +#[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))] +impl From for SocketAddr { + /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`]. + fn from(sock6: SocketAddrV6) -> SocketAddr { + SocketAddr::V6(sock6) + } +} + +#[cfg_attr(staged_api, stable(feature = "addr_from_into_ip", since = "1.17.0"))] +impl> From<(I, u16)> for SocketAddr { + /// Converts a tuple struct (Into<[`IpAddr`]>, `u16`) into a [`SocketAddr`]. + /// + /// This conversion creates a [`SocketAddr::V4`] for an [`IpAddr::V4`] + /// and creates a [`SocketAddr::V6`] for an [`IpAddr::V6`]. + /// + /// `u16` is treated as port of the newly created [`SocketAddr`]. + fn from(pieces: (I, u16)) -> SocketAddr { + SocketAddr::new(pieces.0.into(), pieces.1) + } +} + +#[cfg_attr(staged_api, stable(feature = "socketaddr_ordering", since = "1.45.0"))] +impl PartialOrd for SocketAddrV4 { + fn partial_cmp(&self, other: &SocketAddrV4) -> Option { + Some(self.cmp(other)) + } +} + +#[cfg_attr(staged_api, stable(feature = "socketaddr_ordering", since = "1.45.0"))] +impl PartialOrd for SocketAddrV6 { + fn partial_cmp(&self, other: &SocketAddrV6) -> Option { + Some(self.cmp(other)) + } +} + +#[cfg_attr(staged_api, stable(feature = "socketaddr_ordering", since = "1.45.0"))] +impl Ord for SocketAddrV4 { + fn cmp(&self, other: &SocketAddrV4) -> Ordering { + self.ip() + .cmp(other.ip()) + .then(self.port().cmp(&other.port())) + } +} + +#[cfg_attr(staged_api, stable(feature = "socketaddr_ordering", since = "1.45.0"))] +impl Ord for SocketAddrV6 { + fn cmp(&self, other: &SocketAddrV6) -> Ordering { + self.ip() + .cmp(other.ip()) + .then(self.port().cmp(&other.port())) + } +} + +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +impl hash::Hash for SocketAddrV4 { + fn hash(&self, s: &mut H) { + (self.port, self.ip).hash(s) + } +} +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +impl hash::Hash for SocketAddrV6 { + fn hash(&self, s: &mut H) { + (self.port, &self.ip, self.flowinfo, self.scope_id).hash(s) + } +} diff --git a/vendor/rustls-0.21.8/.cargo-checksum.json b/vendor/rustls-0.21.8/.cargo-checksum.json new file mode 100644 index 0000000000000..92634d7705c0e --- /dev/null +++ b/vendor/rustls-0.21.8/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"15901aaf1c07a653d9de91084bfb07d207432d3563b849adac8d8c301c35f773","Cargo.toml":"a7837bc1b27060df2bb509cdeeca2d577438f709c84b0bd29230051311e64e1c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-ISC":"7cfafc877eccc46c0e346ccbaa5c51bb6b894d2b818e617d970211e232785ad4","LICENSE-MIT":"709e3175b4212f7b13aa93971c9f62ff8c69ec45ad8c6532a7e0c41d7a7d6f8c","README.md":"d266ea49e83b7cc6c0e8326fff39eb227fe6cefd851e302a03a8311e16bf37c9","benches/benchmarks.rs":"2fd0c1535ba25d700318a8a032a7b646b8c426867f0dbb993b3d450f42995956","build.rs":"83af94fa10c4be7653b2b69e1a4656239ecf6fbdfc225341f10e1ec7121b383e","examples/internal/bench.rs":"5f6dcfa4ae2926a26f81dabff0e5ad2a6dd01b9eba79bc7d32de6063433821a9","examples/internal/bogo_shim.rs":"e1923dfa779da50a20bef2623073045dfe37cbaadad4cc1529ab65a95a51ac27","src/anchors.rs":"bff9f3d6bae9ebe5247efa2f8528853541642d56cd19794e2f12e902d767941a","src/bs_debug.rs":"6a209655cea0ced94f4fc6341bf654a05ca1aa162c67361b3b2c8e28d179b156","src/builder.rs":"64964e17fa77cb1eaf9f81ac481115f8c26134bb828adde349db786a8083462d","src/check.rs":"a22af9344a7b884c271370625f0498de6f99521348ab87e9c1184d993bea1b30","src/cipher.rs":"b98ae327ad0e957587d59fb6e1888a66dc5e2e1e33d20cca267e3a4d24010986","src/client/builder.rs":"f7d89cb3d1bc966573e213ed08f4abb2e76af63b5d80f767f99afb0670cb40eb","src/client/client_conn.rs":"6c773faca8c92d01690f06f967150aa496fad96d998fe605f79ea4513b7ed936","src/client/common.rs":"c03ceb060bb3e157f1615722321bc4f3956f406b65a4a619c7cefe5ee87cec70","src/client/handy.rs":"6c578a5927efb77134a03cee331f369bc9de42f24850b2a2595e4ec7f577e193","src/client/hs.rs":"2da9e773f5b39b59471ffb8c1a429fa52515f63e40dac32c6ba010ea5751dee2","src/client/tls12.rs":"5ce1295e641deac2579bdfd6dae36da2823063ee8c36fdd8c3a18cc6701ff810","src/client/tls13.rs":"ea2251c8caba27b6af254ae8cb2fe32fb689f70741fd9bf9792935c402bb0199","src/common_state.rs":"0a07a75871d967f34cb85c496ccc90dc726e7c40de289b6c34e1230f722f6831","src/conn.rs":"ac3470327b406c1e67c86a081caef4e32f1bb977ccb6189bb571f1701a823fc8","src/dns_name.rs":"de1da7a79e454f76ee434984213217a335dfa725def7bcdb0c479d0cbd43c29d","src/enums.rs":"c8ce03d80d080fc7c00dc1b4a4714efcbae7ac3db659bf1e0c3dc5516cfca839","src/error.rs":"d41042e72c3b16192131f1dbfed87f7ad8b87dea52986a4960279f4537a92a35","src/hash_hs.rs":"4adfdc3caadf97dfa49c33cede24f92e0a51e9dd4e56f7bc78c5c48f1e4fe1da","src/key.rs":"ec9242bead53ea83e48c7e8a62b82c9c67660674c846d94325dc37eb788e5d11","src/key_log.rs":"781a86f2e9e07d82288f3c130ce3cfe36f3c17743c28bd5d8036d7b5afa1d5f7","src/key_log_file.rs":"d9f68aa1d30af89e22986ac9e0b3d619e511ae254d12600cf0f22865592ed889","src/kx.rs":"386bc27a852325f8c1185527d4eb6d4f41fcdcd66d4d19caf1c7188a3568d860","src/lib.rs":"d844e78e7eab018d0111f0af962d869bbb86728c560b66884b2a018aec0b1d72","src/limited_cache.rs":"38b045abde34c532d8cbf7d781b33b4ca87d5ec7233933071f651f90bd90f474","src/manual/defaults.rs":"d4d44d094c8dee1e595988674c1f7e19c3d73ae51b8c7aa9921fd8a1a33ad015","src/manual/features.rs":"5aef65271e980cef6ab3be21cd2bfcf18eb4fcb8e7bca1c46788d4fdbd951a22","src/manual/howto.rs":"cded032780c8f7eb48620bf9bfd5f02482f720da9146b2c87c6e4d926d29234a","src/manual/implvulns.rs":"d023ad1183f57bc9bfa20f1fa3c5048f4378548cbb23cbe5bf238fcba598a1ef","src/manual/mod.rs":"8348373cb7d6f21da000ceeba4e39f79e2e81a3a8d01841847d8e54e3a7b6dba","src/manual/tlsvulns.rs":"e9b756bbc9c880a1c754365f361cfc334bfcbc0d457b4c7e50147a0ca181d686","src/msgs/alert.rs":"41f96e4bcb061e4c6eff6cd814b259c2778006c523155f5875eba55abdaf858b","src/msgs/base.rs":"f85c33ab3c24eff00f3496c752ba00af0ae8bc9808362d99244485a3a2164f6b","src/msgs/ccs.rs":"29fc4288688c99699a4b879aff908d8aef704a1de36b8cf1dcef571168bd32dd","src/msgs/codec.rs":"5e562c282623416d6b6bdf63e4d253780c0c6c0a2209cb341c1c74e0832b7402","src/msgs/deframer.rs":"0b5660157b3d6f71704df86ecbaa5dba8985dd590b69daba0bf81d24fe4b72ee","src/msgs/enums.rs":"d4c7614bb6683ef9c0f0401bcb76824021dafc6906cde73e496a38ed280bb4f3","src/msgs/fragmenter.rs":"e820d8e7f33f411d8cbd2ca57e1eed6aca828b83da8877f2d9660ed7634a6819","src/msgs/handshake-test.1.bin":"dfc0687f3b9902e7a0dfd2ebf59d73745b23b103e1d2b337ff555dfe42c5d1dd","src/msgs/handshake.rs":"9b9c574fbd779d90fc50d4abec62105045e01e5393fdd723e3bdf7861037712f","src/msgs/handshake_test.rs":"19ba44038446303938572103a560dd98c23a288044bdef34d225516a23cf08d0","src/msgs/hello-api.devicecheck.apple.com.bin":"2bc3d61745598bf03d412fbcf482152d6810f674f6f6e7dab4fca90b71797c93","src/msgs/macros.rs":"c273ea05c5d31933b03dc1411a8fc2534dee5026f8c7d211e683b7bd49848367","src/msgs/message.rs":"3334d82edb38f65e674bf9d8a7c7da50c06fbd832a2921571de1bc79c409c825","src/msgs/message_test.rs":"379fcb0b8e2aba4c55a40c641965149e7803b00c609b549a88523bc38004ca17","src/msgs/mod.rs":"278efbfe4cf25557d495f48f457e504a4ad70998cd7f435f90fe8be2b74eca53","src/msgs/persist.rs":"ec825deae9529d8aaf763f376b611cd1710f1aac9fe4f2ebb257097561345cad","src/quic.rs":"d07c084e19187bdc1428da1f6f7acb65880823abf68b92036bafd201360aa170","src/rand.rs":"a573eff543d11f5a9009dc7929d426e7e87a5680bd03beb86666588b3301dd88","src/record_layer.rs":"451e2f82ce0242597876fd8a642519e607c28d0a0fb48f324709970dca184a84","src/server/builder.rs":"c1b3e51856190e092b902f28053bc7e3fba14e82e9f7abe5eb136f8f4eb6b7ac","src/server/common.rs":"41d15562492bbe402960fac598f5c9f48702bb18c6038b3649eb398f620b5e89","src/server/handy.rs":"499be48e074e9e3d72fd5bf0df0b15552bc5e7a89f83de9cd1fb224e191badee","src/server/hs.rs":"95ece66642b0f0fbbf8c9b6c0a19e63f5230da48e7897b8c7a0529e4a7febd70","src/server/server_conn.rs":"71d7cd1091ada4b2db6fa2d4e1cdecd74650774010aee6431af1eee61660a5d8","src/server/tls12.rs":"8c11a4066214f64944c09067f4887b55aded6569bce9ec75c6a5a9d6204a234f","src/server/tls13.rs":"47553a8b77899f18a902718aac8183e394c4ce5559db1cf2f51b2ac711fcd0ce","src/sign.rs":"c6fa6d0f70874f0cfe9243203d39cceb9918ca93b3c6dcb8abf2b4d76aad554a","src/stream.rs":"57b86f568c8f479e59c3f5d1bac94308290aa7a8e61ff6e5dc82b047ad7aac83","src/suites.rs":"76c2b1804a02493e495986a238d3b74d704eaf791eb544f3968c210b87833181","src/testdata/cert-arstechnica.0.der":"46aabc708067403be19c801e364b3d74d142fa34f0d236bd5ebb78b6ea92ee09","src/testdata/cert-arstechnica.1.der":"f55f9ffcb83c73453261601c7e044db15a0f034b93c05830f28635ef889cf670","src/testdata/cert-arstechnica.2.der":"87dcd4dc74640a322cd205552506d1be64f12596258096544986b4850bc72706","src/testdata/cert-arstechnica.3.der":"28689b30e4c306aab53b027b29e36ad6dd1dcf4b953994482ca84bdc1ecac996","src/testdata/cert-duckduckgo.0.der":"a5d67800ebb234db3814a0fa562d57ddc6f3d55fe999012d67ccce96eedec9d5","src/testdata/cert-duckduckgo.1.der":"52274c57ce4dee3b49db7a7ff708c040f771898b3be88725a86fb4430182fe14","src/testdata/cert-github.0.der":"0ae384bfd4dde9d13e50c5857c05a442c93f8e01445ee4b34540d22bd1e37f1b","src/testdata/cert-github.1.der":"74eab573da7db195097be0e90f334934c7a4c89e8083759db4333a00edd243d9","src/testdata/cert-google.0.der":"41204cc6d81b76f1ec47cc3ec42dd8beca364cfc3d60eef23426aba6d2fb527f","src/testdata/cert-google.1.der":"23ecb03eec17338c4e33a6b48a41dc3cda12281bbc3ff813c0589d6cc2387522","src/testdata/cert-google.2.der":"3ee0278df71fa3c125c4cd487f01d774694e6fc57e0cd94c24efd769133918e5","src/testdata/cert-hn.0.der":"34556ed249da9c079c6ab4394a7ec0faeb58802ade1131a21952655e2f9c601e","src/testdata/cert-hn.1.der":"52274c57ce4dee3b49db7a7ff708c040f771898b3be88725a86fb4430182fe14","src/testdata/cert-reddit.0.der":"c6691fc719fb3afe21ee36ff30c34270a26bec774cde6c5359de960b95efb542","src/testdata/cert-reddit.1.der":"52274c57ce4dee3b49db7a7ff708c040f771898b3be88725a86fb4430182fe14","src/testdata/cert-rustlang.0.der":"8b9884fd898113bcc1158665b8799dcc916b0439154bdb1fb1a34aac90f70740","src/testdata/cert-rustlang.1.der":"f55f9ffcb83c73453261601c7e044db15a0f034b93c05830f28635ef889cf670","src/testdata/cert-rustlang.2.der":"87dcd4dc74640a322cd205552506d1be64f12596258096544986b4850bc72706","src/testdata/cert-rustlang.3.der":"28689b30e4c306aab53b027b29e36ad6dd1dcf4b953994482ca84bdc1ecac996","src/testdata/cert-servo.0.der":"eb197f28ce58d8d0fa3d92e2e2d7be5b98de354410aa66ddd3016e3f24a7250a","src/testdata/cert-servo.1.der":"3abbe63daf756c5016b6b85f52015fd8e8acbe277c5087b127a60563a841ed8a","src/testdata/cert-stackoverflow.0.der":"f4abeb331e28cceb20da7fc18ca95590c0ed1f4e63f52b637b23b9bc06665e64","src/testdata/cert-stackoverflow.1.der":"67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd","src/testdata/cert-stackoverflow.2.der":"6d99fb265eb1c5b3744765fcbc648f3cd8e1bffafdc4c2f99b9d47cf7ff1c24f","src/testdata/cert-twitter.0.der":"fe7c6283d9f01487f3637a9d3f51dbe89c12ae6a8ba072bb39392045d403c770","src/testdata/cert-twitter.1.der":"25768713d3b459f9382d2a594f85f34709fd2a8930731542a4146ffb246bec69","src/testdata/cert-wapo.0.der":"babb936bd25e338826c345561b93f8acf15c643a7d6ef07a2168bcc10ad99bb3","src/testdata/cert-wapo.1.der":"75c5b3f01fd1f51a2c447ab7c785d72e69fa9c472c08571e7eadf3b8eabae70c","src/testdata/cert-wikipedia.0.der":"570a5629103e749596336c7ba750d385ed124db5ddbdd6461546500fe81653f2","src/testdata/cert-wikipedia.1.der":"f7a9a1b2fd964a3f2670bd668d561fb7c55d3aa9ab8391e7e169702db8a3dbcf","src/testdata/deframer-empty-applicationdata.bin":"b86ffa54a7c45e93a27d6255cb5037a3d51c6714077883601f06b619892aa0bb","src/testdata/deframer-invalid-contenttype.bin":"5b7e3b73fd67dcd7de3853ba6c1bdc91d5c46936845520744d610254b68b4826","src/testdata/deframer-invalid-empty.bin":"1d4a7cb76d38591ca1d062056e6bb4e409097663d2bf4866e91094e4e317a7a3","src/testdata/deframer-invalid-length.bin":"400f1998d0f76b4e40c030508e779dfbcb3e3359b79704737c9cf36f67221b8b","src/testdata/deframer-invalid-version.bin":"7e9f00a1ada82bbd42c3482e7d0245f657beeaaa2d297342d3a8fbeb58db5ebe","src/testdata/deframer-test.1.bin":"33e15a17ebdee1f2c2c7918f114791492058df12c8c9fc497876ff9d6f7ebb55","src/testdata/deframer-test.2.bin":"a850ca71fdd1cb5a26324bd204d7179aa320ac5324e2b02d1499c87bc8f9689e","src/testdata/eddsakey.der":"606bc208c72f30d11ce19e3d2b93365f6d3e12ccaf87055589f349f390c26a03","src/testdata/nistp256key.der":"02147f779ac9234e561753715383cff4339d142a674a456071b40a63f657673a","src/testdata/nistp256key.pkcs8.der":"8ac0d1f37d827866d4396497b4016c1cdadfb740248bfe1eea24f73a9f1d4d86","src/testdata/nistp384key.der":"ed67accafd2fc24881f9200fd438c10ddd586f9a7d672981c42eb5f7f17abfeb","src/testdata/nistp384key.pkcs8.der":"469e695487cc8aaf5109907b1d201be54f0ee768ce8c0e90b9d63bde98a27980","src/testdata/prf-result.1.bin":"ba86827dfe61b8dd2037e4e8f094d15f1bb574850ae205c8b412814f8ec1284e","src/testdata/prf-result.2.bin":"b46941b6e44dfe3e6b49fef860bc976b1cd6f8829d784991928f1b7ba119716f","src/testdata/rsa2048key.pkcs1.der":"1ba5d98f8477176468664b7b2120566dc3b7e955119cba6c56f7a19a31267bcb","src/testdata/rsa2048key.pkcs8.der":"2e2a42e8e9bfed26a7836244a89cd5fc440b612ae08655b21c8e4b126440d873","src/ticketer.rs":"93c8ed2256ad1520eb8fad01f427e2f811f44efa88cc4ace63e0fe46859bfab0","src/tls12/cipher.rs":"34da69091e5729e12547ba157aba9262c70589b091515f8069fd3885e4d4d11f","src/tls12/mod.rs":"258d7a7c6845f58384733856740932d66ad7e3e88ba72fe03a671bce3d160183","src/tls12/prf.rs":"28703996f07d480aef0a29ad892eb0112b6ac1742fa4eeb5e6b16768e6aa990e","src/tls13/key_schedule.rs":"69289a057852db7dcb43427b329473adfee6ac9e4cba6f434defb95eb52c823d","src/tls13/mod.rs":"3e0ca6f44d79d979f89a0f367a05da7771c301b8923abc2786edb314971dd93d","src/vecbuf.rs":"af52479b29390779d77f59a9f5b60863988ab1610d33a4b87a577f1934d478f6","src/verify.rs":"04bbd5f181b4fa6e0f963f86350baf283c99f086ea9f49964766e6de4af14202","src/verifybench.rs":"a2f46c6cf319a64a66f8928eca08edf2802c07b9166564416d669478454be954","src/versions.rs":"e1aa0ff42f0026b11450d03cf82dae70b9507447165ca8a30988ebd0b19b0a1e","src/x509.rs":"99230c9042731f4be98a7d07a89229dd675840aed30165e6dc8b191949b71079","tests/api.rs":"028827aeb507a2da046413cc166461669826dc92de59ef5fd41af5399dbe13aa","tests/bogo.rs":"34b9ce193d93b69a40ec3c529b3a225f2de40fc666f69c26df483fca453f0dd6","tests/client_cert_verifier.rs":"8a3df319c7e44922553abee3cdfc67ccf6647d8643e397150744ea7ba08c455a","tests/common/mod.rs":"bd8132a83e204eb122ae2e1a7fa23ebf74ba91075de6441a5d5825f5e6066dfd","tests/key_log_file_env.rs":"e2823c2e31c769c0ada203cf4415a8bd3f71176ee60cb00153537d51f2537278","tests/server_cert_verifier.rs":"78fc9542797713304b5a3a5c9644fc0e8856b15a3de191949633ce5b47d81b7a"},"package":"446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c"} \ No newline at end of file diff --git a/vendor/rustls-0.21.8/Cargo.lock b/vendor/rustls-0.21.8/Cargo.lock new file mode 100644 index 0000000000000..ed114f6877119 --- /dev/null +++ b/vendor/rustls-0.21.8/Cargo.lock @@ -0,0 +1,510 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "bencher" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys", +] + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + +[[package]] +name = "linux-raw-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys", +] + +[[package]] +name = "rustix" +version = "0.38.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustls" +version = "0.21.8" +dependencies = [ + "base64", + "bencher", + "env_logger", + "log", + "ring 0.17.5", + "rustls-pemfile", + "rustls-webpki", + "rustversion", + "sct", + "webpki-roots", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.5", + "untrusted 0.9.0", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring 0.16.20", + "untrusted 0.7.1", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "syn" +version = "2.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/vendor/rustls-0.21.8/Cargo.toml b/vendor/rustls-0.21.8/Cargo.toml new file mode 100644 index 0000000000000..e17590ccc81d9 --- /dev/null +++ b/vendor/rustls-0.21.8/Cargo.toml @@ -0,0 +1,103 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.61" +name = "rustls" +version = "0.21.8" +build = "build.rs" +autobenches = false +description = "Rustls is a modern TLS library written in Rust." +homepage = "https://github.com/rustls/rustls" +readme = "README.md" +categories = [ + "network-programming", + "cryptography", +] +license = "Apache-2.0 OR ISC OR MIT" +repository = "https://github.com/rustls/rustls" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[[example]] +name = "bogo_shim" +path = "examples/internal/bogo_shim.rs" +required-features = [ + "dangerous_configuration", + "quic", +] + +[[example]] +name = "bench" +path = "examples/internal/bench.rs" + +[[bench]] +name = "benchmarks" +path = "benches/benchmarks.rs" +harness = false + +[dependencies.log] +version = "0.4.4" +optional = true + +[dependencies.ring] +version = "0.17" + +[dependencies.sct] +version = "0.7.0" + +[dependencies.webpki] +version = "0.101.7" +features = [ + "alloc", + "std", +] +package = "rustls-webpki" + +[dev-dependencies.base64] +version = "0.21" + +[dev-dependencies.bencher] +version = "0.1.5" + +[dev-dependencies.env_logger] +version = "0.10" + +[dev-dependencies.log] +version = "0.4.4" + +[dev-dependencies.rustls-pemfile] +version = "1.0.3" + +[dev-dependencies.webpki-roots] +version = "0.25.0" + +[build-dependencies.rustversion] +version = "1.0.6" +optional = true + +[features] +dangerous_configuration = [] +default = [ + "logging", + "tls12", +] +logging = ["log"] +quic = [] +read_buf = ["rustversion"] +secret_extraction = [] +tls12 = [] diff --git a/vendor/rustls-0.21.8/LICENSE-APACHE b/vendor/rustls-0.21.8/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/vendor/rustls-0.21.8/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/rustls-0.21.8/LICENSE-ISC b/vendor/rustls-0.21.8/LICENSE-ISC new file mode 100644 index 0000000000000..03acf1bd2c44c --- /dev/null +++ b/vendor/rustls-0.21.8/LICENSE-ISC @@ -0,0 +1,15 @@ +ISC License (ISC) +Copyright (c) 2016, Joseph Birr-Pixton + +Permission to use, copy, modify, and/or distribute this software for +any purpose with or without fee is hereby granted, provided that the +above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/vendor/rustls-0.21.8/LICENSE-MIT b/vendor/rustls-0.21.8/LICENSE-MIT new file mode 100644 index 0000000000000..ef480e6f0936e --- /dev/null +++ b/vendor/rustls-0.21.8/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Joseph Birr-Pixton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/rustls-0.21.8/README.md b/vendor/rustls-0.21.8/README.md new file mode 100644 index 0000000000000..fc34e369f210a --- /dev/null +++ b/vendor/rustls-0.21.8/README.md @@ -0,0 +1,244 @@ +

+ +

+ +
+ +# Status +Rustls is mature and widely used. While most of the API surface is stable, we expect the next +few releases will make further changes as needed to accomodate new features or performance improvements. + +If you'd like to help out, please see [CONTRIBUTING.md](CONTRIBUTING.md). + +[![Build Status](https://github.com/rustls/rustls/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/rustls/rustls/actions/workflows/build.yml?query=branch%3Amain) +[![Coverage Status (codecov.io)](https://codecov.io/gh/rustls/rustls/branch/main/graph/badge.svg)](https://codecov.io/gh/rustls/rustls/) +[![Documentation](https://docs.rs/rustls/badge.svg)](https://docs.rs/rustls/) +[![Chat](https://img.shields.io/discord/976380008299917365?logo=discord)](https://discord.gg/MCSB76RU96) + +## Release history + +Release history can be found [on GitHub](https://github.com/rustls/rustls/releases). + +# Documentation +Lives here: https://docs.rs/rustls/ + +# Approach +Rustls is a TLS library that aims to provide a good level of cryptographic security, +requires no configuration to achieve that security, and provides no unsafe features or +obsolete cryptography. + +## Current features + +* TLS1.2 and TLS1.3. +* ECDSA, Ed25519 or RSA server authentication by clients. +* ECDSA, Ed25519 or RSA server authentication by servers. +* Forward secrecy using ECDHE; with curve25519, nistp256 or nistp384 curves. +* AES128-GCM and AES256-GCM bulk encryption, with safe nonces. +* ChaCha20-Poly1305 bulk encryption ([RFC7905](https://tools.ietf.org/html/rfc7905)). +* ALPN support. +* SNI support. +* Tunable fragment size to make TLS messages match size of underlying transport. +* Optional use of vectored IO to minimise system calls. +* TLS1.2 session resumption. +* TLS1.2 resumption via tickets ([RFC5077](https://tools.ietf.org/html/rfc5077)). +* TLS1.3 resumption via tickets or session storage. +* TLS1.3 0-RTT data for clients. +* TLS1.3 0-RTT data for servers. +* Client authentication by clients. +* Client authentication by servers. +* Extended master secret support ([RFC7627](https://tools.ietf.org/html/rfc7627)). +* Exporters ([RFC5705](https://tools.ietf.org/html/rfc5705)). +* OCSP stapling by servers. +* SCT stapling by servers. +* SCT verification by clients. + +## Possible future features + +* PSK support. +* OCSP verification by clients. +* Certificate pinning. + +## Non-features + +For reasons [explained in the manual](https://docs.rs/rustls/latest/rustls/manual/_02_tls_vulnerabilities/index.html), +rustls does not and will not support: + +* SSL1, SSL2, SSL3, TLS1 or TLS1.1. +* RC4. +* DES or triple DES. +* EXPORT ciphersuites. +* MAC-then-encrypt ciphersuites. +* Ciphersuites without forward secrecy. +* Renegotiation. +* Kerberos. +* Compression. +* Discrete-log Diffie-Hellman. +* Automatic protocol version downgrade. + +There are plenty of other libraries that provide these features should you +need them. + +### Platform support + +While Rustls itself is platform independent it uses +[`ring`](https://crates.io/crates/ring) for implementing the cryptography in +TLS. As a result, rustls only runs on platforms +supported by `ring`. At the time of writing, this means 32-bit ARM, Aarch64 (64-bit ARM), +x86, x86-64, LoongArch64, 32-bit & 64-bit Little Endian MIPS, 32-bit PowerPC (Big Endian), +64-bit PowerPC (Big and Little Endian), 64-bit RISC-V, and s390x. We do not presently +support WebAssembly. +For more information, see [the supported `ring` target platforms][ring-target-platforms]. + +Rustls requires Rust 1.61 or later. + +[ring-target-platforms]: https://github.com/briansmith/ring/blob/2e8363b433fa3b3962c877d9ed2e9145612f3160/include/ring-core/target.h#L18-L64 + +# Example code +There are two example programs which use +[mio](https://github.com/carllerche/mio) to do asynchronous IO. + +## Client example program +The client example program is named `tlsclient-mio`. The interface looks like: + +```tlsclient-mio +Connects to the TLS server at hostname:PORT. The default PORT +is 443. By default, this reads a request from stdin (to EOF) +before making the connection. --http replaces this with a +basic HTTP GET request for /. + +If --cafile is not supplied, a built-in set of CA certificates +are used from the webpki-roots crate. + +Usage: + tlsclient-mio [options] [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] + tlsclient-mio (--version | -v) + tlsclient-mio (--help | -h) + +Options: + -p, --port PORT Connect to PORT [default: 443]. + --http Send a basic HTTP GET request for /. + --cafile CAFILE Read root certificates from CAFILE. + --auth-key KEY Read client authentication key from KEY. + --auth-certs CERTS Read client authentication certificates from CERTS. + CERTS must match up with KEY. + --protover VERSION Disable default TLS version list, and use + VERSION instead. May be used multiple times. + --suite SUITE Disable default cipher suite list, and use + SUITE instead. May be used multiple times. + --proto PROTOCOL Send ALPN extension containing PROTOCOL. + May be used multiple times to offer several protocols. + --no-tickets Disable session ticket support. + --no-sni Disable server name indication support. + --insecure Disable certificate verification. + --verbose Emit log output. + --max-frag-size M Limit outgoing messages to M bytes. + --version, -v Show tool version. + --help, -h Show this screen. +``` + +Some sample runs: + +``` +$ cargo run --bin tlsclient-mio -- --http mozilla-modern.badssl.com +HTTP/1.1 200 OK +Server: nginx/1.6.2 (Ubuntu) +Date: Wed, 01 Jun 2016 18:44:00 GMT +Content-Type: text/html +Content-Length: 644 +(...) +``` + +or + +``` +$ cargo run --bin tlsclient-mio -- --http expired.badssl.com +TLS error: InvalidCertificate(Expired) +Connection closed +``` + +## Server example program +The server example program is named `tlsserver-mio`. The interface looks like: + +```tlsserver-mio +Runs a TLS server on :PORT. The default PORT is 443. + +`echo' mode means the server echoes received data on each connection. + +`http' mode means the server blindly sends a HTTP response on each +connection. + +`forward' means the server forwards plaintext to a connection made to +localhost:fport. + +`--certs' names the full certificate chain, `--key' provides the +RSA private key. + +Usage: + tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] [options] echo + tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] [options] http + tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] [options] forward + tlsserver-mio (--version | -v) + tlsserver-mio (--help | -h) + +Options: + -p, --port PORT Listen on PORT [default: 443]. + --certs CERTFILE Read server certificates from CERTFILE. + This should contain PEM-format certificates + in the right order (the first certificate should + certify KEYFILE, the last should be a root CA). + --key KEYFILE Read private key from KEYFILE. This should be a RSA + private key or PKCS8-encoded private key, in PEM format. + --ocsp OCSPFILE Read DER-encoded OCSP response from OCSPFILE and staple + to certificate. Optional. + --auth CERTFILE Enable client authentication, and accept certificates + signed by those roots provided in CERTFILE. + --require-auth Send a fatal alert if the client does not complete client + authentication. + --resumption Support session resumption. + --tickets Support tickets. + --protover VERSION Disable default TLS version list, and use + VERSION instead. May be used multiple times. + --suite SUITE Disable default cipher suite list, and use + SUITE instead. May be used multiple times. + --proto PROTOCOL Negotiate PROTOCOL using ALPN. + May be used multiple times. + --verbose Emit log output. + --version, -v Show tool version. + --help, -h Show this screen. +``` + +Here's a sample run; we start a TLS echo server, then connect to it with +`openssl` and `tlsclient-mio`: + +``` +$ cargo run --bin tlsserver-mio -- --certs test-ca/rsa/end.fullchain --key test-ca/rsa/end.rsa -p 8443 echo & +$ echo hello world | openssl s_client -ign_eof -quiet -connect localhost:8443 +depth=2 CN = ponytown RSA CA +verify error:num=19:self signed certificate in certificate chain +hello world +^C +$ echo hello world | cargo run --bin tlsclient-mio -- --cafile test-ca/rsa/ca.cert -p 8443 localhost +hello world +^C +``` + +# License + +Rustls is distributed under the following three licenses: + +- Apache License version 2.0. +- MIT license. +- ISC license. + +These are included as LICENSE-APACHE, LICENSE-MIT and LICENSE-ISC +respectively. You may use this software under the terms of any +of these licenses, at your option. + +# Code of conduct + +This project adopts the [Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct). +Please email rustls-mod@googlegroups.com to report any instance of misconduct, or if you +have any comments or questions on the Code of Conduct. diff --git a/vendor/rustls-0.21.8/benches/benchmarks.rs b/vendor/rustls-0.21.8/benches/benchmarks.rs new file mode 100644 index 0000000000000..c0f64d8c80002 --- /dev/null +++ b/vendor/rustls-0.21.8/benches/benchmarks.rs @@ -0,0 +1,20 @@ +use bencher::{benchmark_group, benchmark_main, Bencher}; + +#[path = "../tests/common/mod.rs"] +mod test_utils; +use test_utils::*; + +use rustls::ServerConnection; + +use std::io; +use std::sync::Arc; + +fn bench_ewouldblock(c: &mut Bencher) { + let server_config = make_server_config(KeyType::Rsa); + let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); + let mut read_ewouldblock = FailsReads::new(io::ErrorKind::WouldBlock); + c.iter(|| server.read_tls(&mut read_ewouldblock)); +} + +benchmark_group!(benches, bench_ewouldblock); +benchmark_main!(benches); diff --git a/vendor/rustls-0.21.8/build.rs b/vendor/rustls-0.21.8/build.rs new file mode 100644 index 0000000000000..9c73252a655fa --- /dev/null +++ b/vendor/rustls-0.21.8/build.rs @@ -0,0 +1,13 @@ +/// This build script allows us to enable the `read_buf` language feature only +/// for Rust Nightly. +/// +/// See the comment in lib.rs to understand why we need this. + +#[cfg_attr(feature = "read_buf", rustversion::not(nightly))] +fn main() {} + +#[cfg(feature = "read_buf")] +#[rustversion::nightly] +fn main() { + println!("cargo:rustc-cfg=read_buf"); +} diff --git a/vendor/rustls-0.21.8/examples/internal/bench.rs b/vendor/rustls-0.21.8/examples/internal/bench.rs new file mode 100644 index 0000000000000..19e97fa25a354 --- /dev/null +++ b/vendor/rustls-0.21.8/examples/internal/bench.rs @@ -0,0 +1,675 @@ +// This program does assorted benchmarking of rustls. +// +// Note: we don't use any of the standard 'cargo bench', 'test::Bencher', +// etc. because it's unstable at the time of writing. + +use std::env; +use std::fs; +use std::io::{self, Read, Write}; +use std::ops::Deref; +use std::ops::DerefMut; +use std::sync::Arc; +use std::time::{Duration, Instant}; + +use rustls::client::Resumption; +use rustls::server::{ + AllowAnyAuthenticatedClient, NoClientAuth, NoServerSessionStorage, ServerSessionMemoryCache, +}; +use rustls::RootCertStore; +use rustls::Ticketer; +use rustls::{ClientConfig, ClientConnection}; +use rustls::{ConnectionCommon, SideData}; +use rustls::{ServerConfig, ServerConnection}; + +fn duration_nanos(d: Duration) -> f64 { + (d.as_secs() as f64) + f64::from(d.subsec_nanos()) / 1e9 +} + +fn _bench(count: usize, name: &'static str, f_setup: Fsetup, f_test: Ftest) +where + Fsetup: Fn() -> S, + Ftest: Fn(S), +{ + let mut times = Vec::new(); + + for _ in 0..count { + let state = f_setup(); + let start = Instant::now(); + f_test(state); + times.push(duration_nanos(Instant::now().duration_since(start))); + } + + println!("{}", name); + println!("{:?}", times); +} + +fn time(mut f: F) -> f64 +where + F: FnMut(), +{ + let start = Instant::now(); + f(); + let end = Instant::now(); + duration_nanos(end.duration_since(start)) +} + +fn transfer(left: &mut L, right: &mut R, expect_data: Option) -> f64 +where + L: DerefMut + Deref>, + R: DerefMut + Deref>, + LS: SideData, + RS: SideData, +{ + let mut tls_buf = [0u8; 262144]; + let mut read_time = 0f64; + let mut data_left = expect_data; + let mut data_buf = [0u8; 8192]; + + loop { + let mut sz = 0; + + while left.wants_write() { + let written = left + .write_tls(&mut tls_buf[sz..].as_mut()) + .unwrap(); + if written == 0 { + break; + } + + sz += written; + } + + if sz == 0 { + return read_time; + } + + let mut offs = 0; + loop { + let start = Instant::now(); + match right.read_tls(&mut tls_buf[offs..sz].as_ref()) { + Ok(read) => { + right.process_new_packets().unwrap(); + offs += read; + } + Err(err) => { + panic!("error on transfer {}..{}: {}", offs, sz, err); + } + } + + if let Some(left) = &mut data_left { + loop { + let sz = match right.reader().read(&mut data_buf) { + Ok(sz) => sz, + Err(err) if err.kind() == io::ErrorKind::WouldBlock => break, + Err(err) => panic!("failed to read data: {}", err), + }; + + *left -= sz; + if *left == 0 { + break; + } + } + } + + let end = Instant::now(); + read_time += duration_nanos(end.duration_since(start)); + if sz == offs { + break; + } + } + } +} + +#[derive(PartialEq, Clone, Copy)] +enum ClientAuth { + No, + Yes, +} + +#[derive(PartialEq, Clone, Copy)] +enum ResumptionParam { + No, + SessionID, + Tickets, +} + +impl ResumptionParam { + fn label(&self) -> &'static str { + match *self { + Self::No => "no-resume", + Self::SessionID => "sessionid", + Self::Tickets => "tickets", + } + } +} + +// copied from tests/api.rs +#[derive(PartialEq, Clone, Copy, Debug)] +enum KeyType { + Rsa, + Ecdsa, + Ed25519, +} + +struct BenchmarkParam { + key_type: KeyType, + ciphersuite: rustls::SupportedCipherSuite, + version: &'static rustls::SupportedProtocolVersion, +} + +impl BenchmarkParam { + const fn new( + key_type: KeyType, + ciphersuite: rustls::SupportedCipherSuite, + version: &'static rustls::SupportedProtocolVersion, + ) -> Self { + Self { + key_type, + ciphersuite, + version, + } + } +} + +static ALL_BENCHMARKS: &[BenchmarkParam] = &[ + #[cfg(feature = "tls12")] + BenchmarkParam::new( + KeyType::Rsa, + rustls::cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + &rustls::version::TLS12, + ), + #[cfg(feature = "tls12")] + BenchmarkParam::new( + KeyType::Ecdsa, + rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + &rustls::version::TLS12, + ), + #[cfg(feature = "tls12")] + BenchmarkParam::new( + KeyType::Rsa, + rustls::cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + &rustls::version::TLS12, + ), + #[cfg(feature = "tls12")] + BenchmarkParam::new( + KeyType::Rsa, + rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + &rustls::version::TLS12, + ), + #[cfg(feature = "tls12")] + BenchmarkParam::new( + KeyType::Rsa, + rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + &rustls::version::TLS12, + ), + #[cfg(feature = "tls12")] + BenchmarkParam::new( + KeyType::Ecdsa, + rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + &rustls::version::TLS12, + ), + #[cfg(feature = "tls12")] + BenchmarkParam::new( + KeyType::Ecdsa, + rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + &rustls::version::TLS12, + ), + BenchmarkParam::new( + KeyType::Rsa, + rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256, + &rustls::version::TLS13, + ), + BenchmarkParam::new( + KeyType::Rsa, + rustls::cipher_suite::TLS13_AES_256_GCM_SHA384, + &rustls::version::TLS13, + ), + BenchmarkParam::new( + KeyType::Rsa, + rustls::cipher_suite::TLS13_AES_128_GCM_SHA256, + &rustls::version::TLS13, + ), + BenchmarkParam::new( + KeyType::Ecdsa, + rustls::cipher_suite::TLS13_AES_128_GCM_SHA256, + &rustls::version::TLS13, + ), + BenchmarkParam::new( + KeyType::Ed25519, + rustls::cipher_suite::TLS13_AES_128_GCM_SHA256, + &rustls::version::TLS13, + ), +]; + +impl KeyType { + fn path_for(&self, part: &str) -> String { + match self { + Self::Rsa => format!("test-ca/rsa/{}", part), + Self::Ecdsa => format!("test-ca/ecdsa/{}", part), + Self::Ed25519 => format!("test-ca/eddsa/{}", part), + } + } + + fn get_chain(&self) -> Vec { + rustls_pemfile::certs(&mut io::BufReader::new( + fs::File::open(self.path_for("end.fullchain")).unwrap(), + )) + .unwrap() + .iter() + .map(|v| rustls::Certificate(v.clone())) + .collect() + } + + fn get_key(&self) -> rustls::PrivateKey { + rustls::PrivateKey( + rustls_pemfile::pkcs8_private_keys(&mut io::BufReader::new( + fs::File::open(self.path_for("end.key")).unwrap(), + )) + .unwrap()[0] + .clone(), + ) + } + + fn get_client_chain(&self) -> Vec { + rustls_pemfile::certs(&mut io::BufReader::new( + fs::File::open(self.path_for("client.fullchain")).unwrap(), + )) + .unwrap() + .iter() + .map(|v| rustls::Certificate(v.clone())) + .collect() + } + + fn get_client_key(&self) -> rustls::PrivateKey { + rustls::PrivateKey( + rustls_pemfile::pkcs8_private_keys(&mut io::BufReader::new( + fs::File::open(self.path_for("client.key")).unwrap(), + )) + .unwrap()[0] + .clone(), + ) + } +} + +fn make_server_config( + params: &BenchmarkParam, + client_auth: ClientAuth, + resume: ResumptionParam, + max_fragment_size: Option, +) -> ServerConfig { + let client_auth = match client_auth { + ClientAuth::Yes => { + let roots = params.key_type.get_chain(); + let mut client_auth_roots = RootCertStore::empty(); + for root in roots { + client_auth_roots.add(&root).unwrap(); + } + Arc::new(AllowAnyAuthenticatedClient::new(client_auth_roots)) + } + ClientAuth::No => NoClientAuth::boxed(), + }; + + let mut cfg = ServerConfig::builder() + .with_safe_default_cipher_suites() + .with_safe_default_kx_groups() + .with_protocol_versions(&[params.version]) + .unwrap() + .with_client_cert_verifier(client_auth) + .with_single_cert(params.key_type.get_chain(), params.key_type.get_key()) + .expect("bad certs/private key?"); + + if resume == ResumptionParam::SessionID { + cfg.session_storage = ServerSessionMemoryCache::new(128); + } else if resume == ResumptionParam::Tickets { + cfg.ticketer = Ticketer::new().unwrap(); + } else { + cfg.session_storage = Arc::new(NoServerSessionStorage {}); + } + + cfg.max_fragment_size = max_fragment_size; + cfg +} + +fn make_client_config( + params: &BenchmarkParam, + clientauth: ClientAuth, + resume: ResumptionParam, +) -> ClientConfig { + let mut root_store = RootCertStore::empty(); + let mut rootbuf = + io::BufReader::new(fs::File::open(params.key_type.path_for("ca.cert")).unwrap()); + root_store.add_parsable_certificates(&rustls_pemfile::certs(&mut rootbuf).unwrap()); + + let cfg = ClientConfig::builder() + .with_cipher_suites(&[params.ciphersuite]) + .with_safe_default_kx_groups() + .with_protocol_versions(&[params.version]) + .unwrap() + .with_root_certificates(root_store); + + let mut cfg = if clientauth == ClientAuth::Yes { + cfg.with_client_auth_cert( + params.key_type.get_client_chain(), + params.key_type.get_client_key(), + ) + .unwrap() + } else { + cfg.with_no_client_auth() + }; + + if resume != ResumptionParam::No { + cfg.resumption = Resumption::in_memory_sessions(128); + } else { + cfg.resumption = Resumption::disabled(); + } + + cfg +} + +fn apply_work_multiplier(work: u64) -> u64 { + let mul = match env::var("BENCH_MULTIPLIER") { + Ok(val) => val + .parse::() + .expect("invalid BENCH_MULTIPLIER value"), + Err(_) => 1., + }; + + ((work as f64) * mul).round() as u64 +} + +fn bench_handshake(params: &BenchmarkParam, clientauth: ClientAuth, resume: ResumptionParam) { + let client_config = Arc::new(make_client_config(params, clientauth, resume)); + let server_config = Arc::new(make_server_config(params, clientauth, resume, None)); + + assert!(params.ciphersuite.version() == params.version); + + let rounds = apply_work_multiplier(if resume == ResumptionParam::No { + 512 + } else { + 4096 + }); + let mut client_time = 0f64; + let mut server_time = 0f64; + + for _ in 0..rounds { + let server_name = "localhost".try_into().unwrap(); + let mut client = ClientConnection::new(Arc::clone(&client_config), server_name).unwrap(); + let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); + + server_time += time(|| { + transfer(&mut client, &mut server, None); + }); + client_time += time(|| { + transfer(&mut server, &mut client, None); + }); + server_time += time(|| { + transfer(&mut client, &mut server, None); + }); + client_time += time(|| { + transfer(&mut server, &mut client, None); + }); + } + + println!( + "handshakes\t{:?}\t{:?}\t{:?}\tclient\t{}\t{}\t{:.2}\thandshake/s", + params.version, + params.key_type, + params.ciphersuite.suite(), + if clientauth == ClientAuth::Yes { + "mutual" + } else { + "server-auth" + }, + resume.label(), + (rounds as f64) / client_time + ); + println!( + "handshakes\t{:?}\t{:?}\t{:?}\tserver\t{}\t{}\t{:.2}\thandshake/s", + params.version, + params.key_type, + params.ciphersuite.suite(), + if clientauth == ClientAuth::Yes { + "mutual" + } else { + "server-auth" + }, + resume.label(), + (rounds as f64) / server_time + ); +} + +fn do_handshake_step(client: &mut ClientConnection, server: &mut ServerConnection) -> bool { + if server.is_handshaking() || client.is_handshaking() { + transfer(client, server, None); + transfer(server, client, None); + true + } else { + false + } +} + +fn do_handshake(client: &mut ClientConnection, server: &mut ServerConnection) { + while do_handshake_step(client, server) {} +} + +fn bench_bulk(params: &BenchmarkParam, plaintext_size: u64, max_fragment_size: Option) { + let client_config = Arc::new(make_client_config( + params, + ClientAuth::No, + ResumptionParam::No, + )); + let server_config = Arc::new(make_server_config( + params, + ClientAuth::No, + ResumptionParam::No, + max_fragment_size, + )); + + let server_name = "localhost".try_into().unwrap(); + let mut client = ClientConnection::new(client_config, server_name).unwrap(); + client.set_buffer_limit(None); + let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); + server.set_buffer_limit(None); + + do_handshake(&mut client, &mut server); + + let mut buf = Vec::new(); + buf.resize(plaintext_size as usize, 0u8); + + let total_data = apply_work_multiplier(if plaintext_size < 8192 { + 64 * 1024 * 1024 + } else { + 1024 * 1024 * 1024 + }); + let rounds = total_data / plaintext_size; + let mut time_send = 0f64; + let mut time_recv = 0f64; + + for _ in 0..rounds { + time_send += time(|| { + server.writer().write_all(&buf).unwrap(); + }); + + time_recv += transfer(&mut server, &mut client, Some(buf.len())); + } + + let mfs_str = format!( + "max_fragment_size:{}", + max_fragment_size + .map(|v| v.to_string()) + .unwrap_or_else(|| "default".to_string()) + ); + let total_mbs = ((plaintext_size * rounds) as f64) / (1024. * 1024.); + println!( + "bulk\t{:?}\t{:?}\t{}\tsend\t{:.2}\tMB/s", + params.version, + params.ciphersuite.suite(), + mfs_str, + total_mbs / time_send + ); + println!( + "bulk\t{:?}\t{:?}\t{}\trecv\t{:.2}\tMB/s", + params.version, + params.ciphersuite.suite(), + mfs_str, + total_mbs / time_recv + ); +} + +fn bench_memory(params: &BenchmarkParam, conn_count: u64) { + let client_config = Arc::new(make_client_config( + params, + ClientAuth::No, + ResumptionParam::No, + )); + let server_config = Arc::new(make_server_config( + params, + ClientAuth::No, + ResumptionParam::No, + None, + )); + + // The target here is to end up with conn_count post-handshake + // server and client sessions. + let conn_count = (conn_count / 2) as usize; + let mut servers = Vec::with_capacity(conn_count); + let mut clients = Vec::with_capacity(conn_count); + + for _i in 0..conn_count { + servers.push(ServerConnection::new(Arc::clone(&server_config)).unwrap()); + let server_name = "localhost".try_into().unwrap(); + clients.push(ClientConnection::new(Arc::clone(&client_config), server_name).unwrap()); + } + + for _step in 0..5 { + for (client, server) in clients + .iter_mut() + .zip(servers.iter_mut()) + { + do_handshake_step(client, server); + } + } + + for client in clients.iter_mut() { + client + .writer() + .write_all(&[0u8; 1024]) + .unwrap(); + } + + for (client, server) in clients + .iter_mut() + .zip(servers.iter_mut()) + { + transfer(client, server, Some(1024)); + } +} + +fn lookup_matching_benches(name: &str) -> Vec<&BenchmarkParam> { + let r: Vec<&BenchmarkParam> = ALL_BENCHMARKS + .iter() + .filter(|params| { + format!("{:?}", params.ciphersuite.suite()).to_lowercase() == name.to_lowercase() + }) + .collect(); + + if r.is_empty() { + panic!("unknown suite {:?}", name); + } + + r +} + +fn selected_tests(mut args: env::Args) { + let mode = args + .next() + .expect("first argument must be mode"); + + match mode.as_ref() { + "bulk" => match args.next() { + Some(suite) => { + let len = args + .next() + .map(|arg| { + arg.parse::() + .expect("3rd arg must be plaintext size integer") + }) + .unwrap_or(1048576); + let mfs = args.next().map(|arg| { + arg.parse::() + .expect("4th arg must be max_fragment_size integer") + }); + for param in lookup_matching_benches(&suite).iter() { + bench_bulk(param, len, mfs); + } + } + None => { + panic!("bulk needs ciphersuite argument"); + } + }, + + "handshake" | "handshake-resume" | "handshake-ticket" => match args.next() { + Some(suite) => { + let resume = if mode == "handshake" { + ResumptionParam::No + } else if mode == "handshake-resume" { + ResumptionParam::SessionID + } else { + ResumptionParam::Tickets + }; + + for param in lookup_matching_benches(&suite).iter() { + bench_handshake(param, ClientAuth::No, resume); + } + } + None => { + panic!("handshake* needs ciphersuite argument"); + } + }, + + "memory" => match args.next() { + Some(suite) => { + let count = args + .next() + .map(|arg| { + arg.parse::() + .expect("3rd arg must be connection count integer") + }) + .unwrap_or(1000000); + for param in lookup_matching_benches(&suite).iter() { + bench_memory(param, count); + } + } + None => { + panic!("memory needs ciphersuite argument"); + } + }, + + _ => { + panic!("unsupported mode {:?}", mode); + } + } +} + +fn all_tests() { + for test in ALL_BENCHMARKS.iter() { + bench_bulk(test, 1024 * 1024, None); + bench_bulk(test, 1024 * 1024, Some(10000)); + bench_handshake(test, ClientAuth::No, ResumptionParam::No); + bench_handshake(test, ClientAuth::Yes, ResumptionParam::No); + bench_handshake(test, ClientAuth::No, ResumptionParam::SessionID); + bench_handshake(test, ClientAuth::Yes, ResumptionParam::SessionID); + bench_handshake(test, ClientAuth::No, ResumptionParam::Tickets); + bench_handshake(test, ClientAuth::Yes, ResumptionParam::Tickets); + } +} + +fn main() { + let mut args = env::args(); + if args.len() > 1 { + args.next(); + selected_tests(args); + } else { + all_tests(); + } +} diff --git a/vendor/rustls-0.21.8/examples/internal/bogo_shim.rs b/vendor/rustls-0.21.8/examples/internal/bogo_shim.rs new file mode 100644 index 0000000000000..7ce3e1668bb25 --- /dev/null +++ b/vendor/rustls-0.21.8/examples/internal/bogo_shim.rs @@ -0,0 +1,1260 @@ +// This is a test shim for the BoringSSL-Go ('bogo') TLS +// test suite. See bogo/ for this in action. +// +// https://boringssl.googlesource.com/boringssl/+/master/ssl/test +// + +use rustls::client::{ClientConfig, ClientConnection, Resumption}; +use rustls::internal::msgs::codec::Codec; +use rustls::internal::msgs::persist; +use rustls::server::{ClientHello, ServerConfig, ServerConnection}; +use rustls::{ + self, client, kx_group, server, sign, version, AlertDescription, Certificate, CertificateError, + Connection, DistinguishedName, Error, InvalidMessage, NamedGroup, PeerIncompatible, + PeerMisbehaved, PrivateKey, ProtocolVersion, ServerName, Side, SignatureAlgorithm, + SignatureScheme, SupportedKxGroup, SupportedProtocolVersion, Ticketer, ALL_KX_GROUPS, +}; + +use base64::prelude::{Engine, BASE64_STANDARD}; +use env_logger; + +use std::io::{self, BufReader, Read, Write}; +use std::sync::Arc; +use std::time::{self, SystemTime}; +use std::{env, fs, net, process, thread}; + +static BOGO_NACK: i32 = 89; + +macro_rules! println_err( + ($($arg:tt)*) => { { + writeln!(&mut ::std::io::stderr(), $($arg)*).unwrap(); + } } +); + +#[derive(Debug)] +struct Options { + port: u16, + side: Side, + max_fragment: Option, + resumes: usize, + verify_peer: bool, + require_any_client_cert: bool, + offer_no_client_cas: bool, + tickets: bool, + resume_with_tickets_disabled: bool, + queue_data: bool, + queue_data_on_resume: bool, + only_write_one_byte_after_handshake: bool, + only_write_one_byte_after_handshake_on_resume: bool, + shut_down_after_handshake: bool, + check_close_notify: bool, + host_name: String, + use_sni: bool, + send_sct: bool, + key_file: String, + cert_file: String, + protocols: Vec, + reject_alpn: bool, + support_tls13: bool, + support_tls12: bool, + min_version: Option, + max_version: Option, + server_ocsp_response: Vec, + server_sct_list: Vec, + use_signing_scheme: u16, + curves: Option>, + export_keying_material: usize, + export_keying_material_label: String, + export_keying_material_context: String, + export_keying_material_context_used: bool, + read_size: usize, + quic_transport_params: Vec, + expect_quic_transport_params: Vec, + enable_early_data: bool, + expect_ticket_supports_early_data: bool, + expect_accept_early_data: bool, + expect_reject_early_data: bool, + expect_version: u16, + resumption_delay: u32, + queue_early_data_after_received_messages: Vec, +} + +impl Options { + fn new() -> Self { + Options { + port: 0, + side: Side::Client, + max_fragment: None, + resumes: 0, + verify_peer: false, + tickets: true, + resume_with_tickets_disabled: false, + host_name: "example.com".to_string(), + use_sni: false, + send_sct: false, + queue_data: false, + queue_data_on_resume: false, + only_write_one_byte_after_handshake: false, + only_write_one_byte_after_handshake_on_resume: false, + shut_down_after_handshake: false, + check_close_notify: false, + require_any_client_cert: false, + offer_no_client_cas: false, + key_file: "".to_string(), + cert_file: "".to_string(), + protocols: vec![], + reject_alpn: false, + support_tls13: true, + support_tls12: true, + min_version: None, + max_version: None, + server_ocsp_response: vec![], + server_sct_list: vec![], + use_signing_scheme: 0, + curves: None, + export_keying_material: 0, + export_keying_material_label: "".to_string(), + export_keying_material_context: "".to_string(), + export_keying_material_context_used: false, + read_size: 512, + quic_transport_params: vec![], + expect_quic_transport_params: vec![], + enable_early_data: false, + expect_ticket_supports_early_data: false, + expect_accept_early_data: false, + expect_reject_early_data: false, + expect_version: 0, + resumption_delay: 0, + queue_early_data_after_received_messages: vec![], + } + } + + fn version_allowed(&self, vers: ProtocolVersion) -> bool { + (self.min_version.is_none() || vers.get_u16() >= self.min_version.unwrap().get_u16()) + && (self.max_version.is_none() || vers.get_u16() <= self.max_version.unwrap().get_u16()) + } + + fn tls13_supported(&self) -> bool { + self.support_tls13 && self.version_allowed(ProtocolVersion::TLSv1_3) + } + + fn tls12_supported(&self) -> bool { + self.support_tls12 && self.version_allowed(ProtocolVersion::TLSv1_2) + } + + fn supported_versions(&self) -> Vec<&'static SupportedProtocolVersion> { + let mut versions = vec![]; + + if self.tls12_supported() { + versions.push(&version::TLS12); + } + + if self.tls13_supported() { + versions.push(&version::TLS13); + } + versions + } +} + +fn load_cert(filename: &str) -> Vec { + let certfile = fs::File::open(filename).expect("cannot open certificate file"); + let mut reader = BufReader::new(certfile); + rustls_pemfile::certs(&mut reader) + .unwrap() + .iter() + .map(|v| Certificate(v.clone())) + .collect() +} + +fn load_key(filename: &str) -> PrivateKey { + let keyfile = fs::File::open(filename).expect("cannot open private key file"); + let mut reader = BufReader::new(keyfile); + let keys = rustls_pemfile::pkcs8_private_keys(&mut reader).unwrap(); + assert!(keys.len() == 1); + PrivateKey(keys[0].clone()) +} + +fn split_protocols(protos: &str) -> Vec { + let mut ret = Vec::new(); + + let mut offs = 0; + while offs < protos.len() { + let len = protos.as_bytes()[offs] as usize; + let item = protos[offs + 1..offs + 1 + len].to_string(); + ret.push(item); + offs += 1 + len; + } + + ret +} + +struct DummyClientAuth { + mandatory: bool, +} + +impl server::ClientCertVerifier for DummyClientAuth { + fn offer_client_auth(&self) -> bool { + true + } + + fn client_auth_mandatory(&self) -> bool { + self.mandatory + } + + fn client_auth_root_subjects(&self) -> &[DistinguishedName] { + &[] + } + + fn verify_client_cert( + &self, + _end_entity: &Certificate, + _intermediates: &[Certificate], + _now: SystemTime, + ) -> Result { + Ok(server::ClientCertVerified::assertion()) + } +} + +struct DummyServerAuth { + send_sct: bool, +} + +impl client::ServerCertVerifier for DummyServerAuth { + fn verify_server_cert( + &self, + _end_entity: &Certificate, + _certs: &[Certificate], + _hostname: &ServerName, + _scts: &mut dyn Iterator, + _ocsp: &[u8], + _now: SystemTime, + ) -> Result { + Ok(client::ServerCertVerified::assertion()) + } + + fn request_scts(&self) -> bool { + self.send_sct + } +} + +struct FixedSignatureSchemeSigningKey { + key: Arc, + scheme: SignatureScheme, +} + +impl sign::SigningKey for FixedSignatureSchemeSigningKey { + fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option> { + if offered.contains(&self.scheme) { + self.key.choose_scheme(&[self.scheme]) + } else { + self.key.choose_scheme(&[]) + } + } + fn algorithm(&self) -> SignatureAlgorithm { + self.key.algorithm() + } +} + +struct FixedSignatureSchemeServerCertResolver { + resolver: Arc, + scheme: SignatureScheme, +} + +impl server::ResolvesServerCert for FixedSignatureSchemeServerCertResolver { + fn resolve(&self, client_hello: ClientHello) -> Option> { + let mut certkey = self.resolver.resolve(client_hello)?; + Arc::make_mut(&mut certkey).key = Arc::new(FixedSignatureSchemeSigningKey { + key: certkey.key.clone(), + scheme: self.scheme, + }); + Some(certkey) + } +} + +struct FixedSignatureSchemeClientCertResolver { + resolver: Arc, + scheme: SignatureScheme, +} + +impl client::ResolvesClientCert for FixedSignatureSchemeClientCertResolver { + fn resolve( + &self, + acceptable_issuers: &[&[u8]], + sigschemes: &[SignatureScheme], + ) -> Option> { + if !sigschemes.contains(&self.scheme) { + quit(":NO_COMMON_SIGNATURE_ALGORITHMS:"); + } + let mut certkey = self + .resolver + .resolve(acceptable_issuers, sigschemes)?; + Arc::make_mut(&mut certkey).key = Arc::new(FixedSignatureSchemeSigningKey { + key: certkey.key.clone(), + scheme: self.scheme, + }); + Some(certkey) + } + + fn has_certs(&self) -> bool { + self.resolver.has_certs() + } +} + +fn lookup_scheme(scheme: u16) -> SignatureScheme { + match scheme { + 0x0401 => SignatureScheme::RSA_PKCS1_SHA256, + 0x0501 => SignatureScheme::RSA_PKCS1_SHA384, + 0x0601 => SignatureScheme::RSA_PKCS1_SHA512, + 0x0403 => SignatureScheme::ECDSA_NISTP256_SHA256, + 0x0503 => SignatureScheme::ECDSA_NISTP384_SHA384, + 0x0804 => SignatureScheme::RSA_PSS_SHA256, + 0x0805 => SignatureScheme::RSA_PSS_SHA384, + 0x0806 => SignatureScheme::RSA_PSS_SHA512, + 0x0807 => SignatureScheme::ED25519, + // TODO: add support for Ed448 + // 0x0808 => SignatureScheme::ED448, + _ => { + println_err!("Unsupported signature scheme {:04x}", scheme); + process::exit(BOGO_NACK); + } + } +} + +fn lookup_kx_group(group: u16) -> &'static SupportedKxGroup { + match group { + 0x001d => &kx_group::X25519, + 0x0017 => &kx_group::SECP256R1, + 0x0018 => &kx_group::SECP384R1, + _ => { + println_err!("Unsupported kx group {:04x}", group); + process::exit(BOGO_NACK); + } + } +} + +struct ServerCacheWithResumptionDelay { + delay: u32, + storage: Arc, +} + +impl ServerCacheWithResumptionDelay { + fn new(delay: u32) -> Arc { + Arc::new(Self { + delay, + storage: server::ServerSessionMemoryCache::new(32), + }) + } +} + +fn align_time() { + /* we don't have an injectable clock source in rustls' public api, and + * resumption timing is in seconds resolution, so tests that use + * resumption_delay tend to be flickery if the seconds time ticks + * during this. + * + * this function delays until a fresh second ticks, which alleviates + * this. gross! + */ + fn sample() -> u64 { + time::SystemTime::now() + .duration_since(time::SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs() + } + + let start_secs = sample(); + while start_secs == sample() { + thread::sleep(time::Duration::from_millis(20)); + } +} + +impl server::StoresServerSessions for ServerCacheWithResumptionDelay { + fn put(&self, key: Vec, value: Vec) -> bool { + let mut ssv = persist::ServerSessionValue::read_bytes(&value).unwrap(); + ssv.creation_time_sec -= self.delay as u64; + + self.storage + .put(key, ssv.get_encoding()) + } + + fn get(&self, key: &[u8]) -> Option> { + self.storage.get(key) + } + + fn take(&self, key: &[u8]) -> Option> { + self.storage.take(key) + } + + fn can_cache(&self) -> bool { + self.storage.can_cache() + } +} + +fn make_server_cfg(opts: &Options) -> Arc { + let client_auth = + if opts.verify_peer || opts.offer_no_client_cas || opts.require_any_client_cert { + Arc::new(DummyClientAuth { + mandatory: opts.require_any_client_cert, + }) + } else { + server::NoClientAuth::boxed() + }; + + let cert = load_cert(&opts.cert_file); + let key = load_key(&opts.key_file); + + let kx_groups = if let Some(curves) = &opts.curves { + curves + .iter() + .map(|curveid| lookup_kx_group(*curveid)) + .collect() + } else { + ALL_KX_GROUPS.to_vec() + }; + + let mut cfg = ServerConfig::builder() + .with_safe_default_cipher_suites() + .with_kx_groups(&kx_groups) + .with_protocol_versions(&opts.supported_versions()) + .unwrap() + .with_client_cert_verifier(client_auth) + .with_single_cert_with_ocsp_and_sct( + cert.clone(), + key, + opts.server_ocsp_response.clone(), + opts.server_sct_list.clone(), + ) + .unwrap(); + + cfg.session_storage = ServerCacheWithResumptionDelay::new(opts.resumption_delay); + cfg.max_fragment_size = opts.max_fragment; + cfg.send_tls13_tickets = 1; + + if opts.use_signing_scheme > 0 { + let scheme = lookup_scheme(opts.use_signing_scheme); + cfg.cert_resolver = Arc::new(FixedSignatureSchemeServerCertResolver { + resolver: cfg.cert_resolver.clone(), + scheme, + }); + } + + if opts.tickets { + cfg.ticketer = Ticketer::new().unwrap(); + } else if opts.resumes == 0 { + cfg.session_storage = Arc::new(server::NoServerSessionStorage {}); + } + + if !opts.protocols.is_empty() { + cfg.alpn_protocols = opts + .protocols + .iter() + .map(|proto| proto.as_bytes().to_vec()) + .collect::>(); + } + + if opts.reject_alpn { + cfg.alpn_protocols = vec![b"invalid".to_vec()]; + } + + if opts.enable_early_data { + // see kMaxEarlyDataAccepted in boringssl, which bogo validates + cfg.max_early_data_size = 14336; + cfg.send_half_rtt_data = true; + } + + Arc::new(cfg) +} + +struct ClientCacheWithoutKxHints { + delay: u32, + storage: Arc, +} + +impl ClientCacheWithoutKxHints { + fn new(delay: u32) -> Arc { + Arc::new(ClientCacheWithoutKxHints { + delay, + storage: Arc::new(client::ClientSessionMemoryCache::new(32)), + }) + } +} + +impl client::ClientSessionStore for ClientCacheWithoutKxHints { + fn set_kx_hint(&self, _: &ServerName, _: NamedGroup) {} + fn kx_hint(&self, _: &ServerName) -> Option { + None + } + + fn set_tls12_session( + &self, + server_name: &ServerName, + mut value: client::Tls12ClientSessionValue, + ) { + value.rewind_epoch(self.delay); + self.storage + .set_tls12_session(server_name, value); + } + + fn tls12_session(&self, server_name: &ServerName) -> Option { + self.storage.tls12_session(server_name) + } + + fn remove_tls12_session(&self, server_name: &ServerName) { + self.storage + .remove_tls12_session(server_name); + } + + fn insert_tls13_ticket( + &self, + server_name: &ServerName, + mut value: client::Tls13ClientSessionValue, + ) { + value.rewind_epoch(self.delay); + self.storage + .insert_tls13_ticket(server_name, value) + } + + fn take_tls13_ticket( + &self, + server_name: &ServerName, + ) -> Option { + self.storage + .take_tls13_ticket(server_name) + } +} + +fn make_client_cfg(opts: &Options) -> Arc { + let kx_groups = if let Some(curves) = &opts.curves { + curves + .iter() + .map(|curveid| lookup_kx_group(*curveid)) + .collect() + } else { + ALL_KX_GROUPS.to_vec() + }; + + let cfg = ClientConfig::builder() + .with_safe_default_cipher_suites() + .with_kx_groups(&kx_groups) + .with_protocol_versions(&opts.supported_versions()) + .expect("inconsistent settings") + .with_custom_certificate_verifier(Arc::new(DummyServerAuth { + send_sct: opts.send_sct, + })); + + let mut cfg = if !opts.cert_file.is_empty() && !opts.key_file.is_empty() { + let cert = load_cert(&opts.cert_file); + let key = load_key(&opts.key_file); + cfg.with_client_auth_cert(cert, key) + .unwrap() + } else { + cfg.with_no_client_auth() + }; + + if !opts.cert_file.is_empty() && opts.use_signing_scheme > 0 { + let scheme = lookup_scheme(opts.use_signing_scheme); + cfg.client_auth_cert_resolver = Arc::new(FixedSignatureSchemeClientCertResolver { + resolver: cfg.client_auth_cert_resolver.clone(), + scheme, + }); + } + + cfg.resumption = Resumption::store(ClientCacheWithoutKxHints::new(opts.resumption_delay)); + cfg.enable_sni = opts.use_sni; + cfg.max_fragment_size = opts.max_fragment; + + if !opts.protocols.is_empty() { + cfg.alpn_protocols = opts + .protocols + .iter() + .map(|proto| proto.as_bytes().to_vec()) + .collect(); + } + + if opts.enable_early_data { + cfg.enable_early_data = true; + } + + Arc::new(cfg) +} + +fn quit(why: &str) -> ! { + println_err!("{}", why); + process::exit(0) +} + +fn quit_err(why: &str) -> ! { + println_err!("{}", why); + process::exit(1) +} + +fn handle_err(err: Error) -> ! { + println!("TLS error: {:?}", err); + thread::sleep(time::Duration::from_millis(100)); + + match err { + Error::InappropriateHandshakeMessage { .. } | Error::InappropriateMessage { .. } => { + quit(":UNEXPECTED_MESSAGE:") + } + Error::AlertReceived(AlertDescription::RecordOverflow) => { + quit(":TLSV1_ALERT_RECORD_OVERFLOW:") + } + Error::AlertReceived(AlertDescription::HandshakeFailure) => quit(":HANDSHAKE_FAILURE:"), + Error::AlertReceived(AlertDescription::ProtocolVersion) => quit(":WRONG_VERSION:"), + Error::AlertReceived(AlertDescription::InternalError) => { + quit(":PEER_ALERT_INTERNAL_ERROR:") + } + Error::InvalidMessage( + InvalidMessage::MissingData("AlertDescription") + | InvalidMessage::TrailingData("AlertMessagePayload"), + ) => quit(":BAD_ALERT:"), + Error::InvalidMessage( + InvalidMessage::TrailingData("ChangeCipherSpecPayload") | InvalidMessage::InvalidCcs, + ) => quit(":BAD_CHANGE_CIPHER_SPEC:"), + Error::InvalidMessage( + InvalidMessage::InvalidKeyUpdate + | InvalidMessage::MissingData(_) + | InvalidMessage::TrailingData(_) + | InvalidMessage::UnexpectedMessage("HelloRetryRequest") + | InvalidMessage::NoSignatureSchemes + | InvalidMessage::UnsupportedCompression, + ) => quit(":BAD_HANDSHAKE_MSG:"), + Error::InvalidMessage(InvalidMessage::InvalidCertRequest) + | Error::InvalidMessage(InvalidMessage::InvalidDhParams) + | Error::InvalidMessage(InvalidMessage::MissingKeyExchange) => quit(":BAD_HANDSHAKE_MSG:"), + Error::InvalidMessage(InvalidMessage::InvalidContentType) + | Error::InvalidMessage(InvalidMessage::InvalidEmptyPayload) + | Error::InvalidMessage(InvalidMessage::UnknownProtocolVersion) + | Error::InvalidMessage(InvalidMessage::MessageTooLarge) => quit(":GARBAGE:"), + Error::InvalidMessage(InvalidMessage::UnexpectedMessage(_)) => quit(":GARBAGE:"), + Error::DecryptError => quit(":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:"), + Error::NoApplicationProtocol => quit(":NO_APPLICATION_PROTOCOL:"), + Error::PeerIncompatible( + PeerIncompatible::ServerSentHelloRetryRequestWithUnknownExtension, + ) => quit(":UNEXPECTED_EXTENSION:"), + Error::PeerIncompatible(_) => quit(":INCOMPATIBLE:"), + Error::PeerMisbehaved(PeerMisbehaved::MissingPskModesExtension) => { + quit(":MISSING_EXTENSION:") + } + Error::PeerMisbehaved(PeerMisbehaved::TooMuchEarlyDataReceived) => { + quit(":TOO_MUCH_READ_EARLY_DATA:") + } + Error::PeerMisbehaved(_) => quit(":PEER_MISBEHAVIOUR:"), + Error::NoCertificatesPresented => quit(":NO_CERTS:"), + Error::AlertReceived(AlertDescription::UnexpectedMessage) => quit(":BAD_ALERT:"), + Error::AlertReceived(AlertDescription::DecompressionFailure) => { + quit_err(":SSLV3_ALERT_DECOMPRESSION_FAILURE:") + } + Error::InvalidCertificate(CertificateError::BadEncoding) => { + quit(":CANNOT_PARSE_LEAF_CERT:") + } + Error::InvalidCertificate(CertificateError::BadSignature) => quit(":BAD_SIGNATURE:"), + Error::InvalidCertificate(e) => quit(&format!(":BAD_CERT: ({:?})", e)), + Error::PeerSentOversizedRecord => quit(":DATA_LENGTH_TOO_LONG:"), + _ => { + println_err!("unhandled error: {:?}", err); + quit(":FIXME:") + } + } +} + +fn flush(sess: &mut Connection, conn: &mut net::TcpStream) { + while sess.wants_write() { + match sess.write_tls(conn) { + Err(err) => { + println!("IO error: {:?}", err); + process::exit(0); + } + Ok(_) => {} + } + } + conn.flush().unwrap(); +} + +fn client(conn: &mut Connection) -> &mut ClientConnection { + conn.try_into().unwrap() +} + +fn server(conn: &mut Connection) -> &mut ServerConnection { + match conn { + Connection::Server(s) => s, + _ => panic!("Connection is not a ServerConnection"), + } +} + +const MAX_MESSAGE_SIZE: usize = 0xffff + 5; + +fn after_read(sess: &mut Connection, conn: &mut net::TcpStream) { + if let Err(err) = sess.process_new_packets() { + flush(sess, conn); /* send any alerts before exiting */ + handle_err(err); + } +} + +fn read_n_bytes(sess: &mut Connection, conn: &mut net::TcpStream, n: usize) { + let mut bytes = [0u8; MAX_MESSAGE_SIZE]; + match conn.read(&mut bytes[..n]) { + Ok(count) => { + println!("read {:?} bytes", count); + sess.read_tls(&mut io::Cursor::new(&mut bytes[..count])) + .expect("read_tls not expected to fail reading from buffer"); + } + Err(ref err) if err.kind() == io::ErrorKind::ConnectionReset => {} + Err(err) => panic!("invalid read: {}", err), + }; + + after_read(sess, conn); +} + +fn read_all_bytes(sess: &mut Connection, conn: &mut net::TcpStream) { + match sess.read_tls(conn) { + Ok(_) => {} + Err(ref err) if err.kind() == io::ErrorKind::ConnectionReset => {} + Err(err) => panic!("invalid read: {}", err), + }; + + after_read(sess, conn); +} + +fn exec(opts: &Options, mut sess: Connection, count: usize) { + let mut sent_message = false; + + let addrs = [ + net::SocketAddr::from((net::Ipv6Addr::LOCALHOST, opts.port)), + net::SocketAddr::from((net::Ipv4Addr::LOCALHOST, opts.port)), + ]; + let mut conn = net::TcpStream::connect(&addrs[..]).expect("cannot connect"); + let mut sent_shutdown = false; + let mut sent_exporter = false; + let mut quench_writes = false; + + loop { + if !sent_message && (opts.queue_data || (opts.queue_data_on_resume && count > 0)) { + if !opts + .queue_early_data_after_received_messages + .is_empty() + { + flush(&mut sess, &mut conn); + for message_size_estimate in &opts.queue_early_data_after_received_messages { + read_n_bytes(&mut sess, &mut conn, *message_size_estimate); + } + println!("now ready for early data"); + } + + if count > 0 && opts.enable_early_data { + let len = client(&mut sess) + .early_data() + .expect("0rtt not available") + .write(b"hello") + .expect("0rtt write failed"); + sess.writer() + .write_all(&b"hello"[len..]) + .unwrap(); + sent_message = true; + } else if !opts.only_write_one_byte_after_handshake { + let _ = sess.writer().write_all(b"hello"); + sent_message = true; + } + } + + if !quench_writes { + flush(&mut sess, &mut conn); + } + + if sess.wants_read() { + read_all_bytes(&mut sess, &mut conn); + } + + if opts.side == Side::Server && opts.enable_early_data { + if let Some(ref mut ed) = server(&mut sess).early_data() { + let mut data = Vec::new(); + let data_len = ed + .read_to_end(&mut data) + .expect("cannot read early_data"); + + for b in data.iter_mut() { + *b ^= 0xff; + } + + sess.writer() + .write_all(&data[..data_len]) + .expect("cannot echo early_data in 1rtt data"); + } + } + + if !sess.is_handshaking() && opts.export_keying_material > 0 && !sent_exporter { + let mut export = Vec::new(); + export.resize(opts.export_keying_material, 0u8); + sess.export_keying_material( + &mut export, + opts.export_keying_material_label + .as_bytes(), + if opts.export_keying_material_context_used { + Some( + opts.export_keying_material_context + .as_bytes(), + ) + } else { + None + }, + ) + .unwrap(); + sess.writer() + .write_all(&export) + .unwrap(); + sent_exporter = true; + } + + if !sess.is_handshaking() && opts.only_write_one_byte_after_handshake && !sent_message { + println!("writing message and then only one byte of its tls frame"); + flush(&mut sess, &mut conn); + + sess.writer() + .write_all(b"hello") + .unwrap(); + sent_message = true; + + let mut one_byte = [0u8]; + let mut cursor = io::Cursor::new(&mut one_byte[..]); + sess.write_tls(&mut cursor).unwrap(); + conn.write_all(&one_byte) + .expect("IO error"); + + quench_writes = true; + } + + if opts.enable_early_data + && opts.side == Side::Client + && !sess.is_handshaking() + && count > 0 + { + if opts.expect_accept_early_data && !client(&mut sess).is_early_data_accepted() { + quit_err("Early data was not accepted, but we expect the opposite"); + } else if opts.expect_reject_early_data && client(&mut sess).is_early_data_accepted() { + quit_err("Early data was accepted, but we expect the opposite"); + } + if opts.expect_version == 0x0304 { + match sess.protocol_version() { + Some(ProtocolVersion::TLSv1_3) | Some(ProtocolVersion::Unknown(0x7f17)) => {} + _ => quit_err("wrong protocol version"), + } + } + } + + let mut buf = [0u8; 1024]; + let len = match sess + .reader() + .read(&mut buf[..opts.read_size]) + { + Ok(0) => { + if opts.check_close_notify { + println!("close notify ok"); + } + println!("EOF (tls)"); + return; + } + Ok(len) => len, + Err(err) if err.kind() == io::ErrorKind::WouldBlock => 0, + Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => { + if opts.check_close_notify { + quit_err(":CLOSE_WITHOUT_CLOSE_NOTIFY:"); + } + println!("EOF (tcp)"); + return; + } + Err(err) => panic!("unhandled read error {:?}", err), + }; + + if opts.shut_down_after_handshake && !sent_shutdown && !sess.is_handshaking() { + sess.send_close_notify(); + sent_shutdown = true; + } + + if quench_writes && len > 0 { + println!("unquenching writes after {:?}", len); + quench_writes = false; + } + + for b in buf.iter_mut() { + *b ^= 0xff; + } + + sess.writer() + .write_all(&buf[..len]) + .unwrap(); + } +} + +fn main() { + let mut args: Vec<_> = env::args().collect(); + env_logger::init(); + + args.remove(0); + + if !args.is_empty() && args[0] == "-is-handshaker-supported" { + println!("No"); + process::exit(0); + } + println!("options: {:?}", args); + + let mut opts = Options::new(); + + while !args.is_empty() { + let arg = args.remove(0); + match arg.as_ref() { + "-port" => { + opts.port = args.remove(0).parse::().unwrap(); + } + "-server" => { + opts.side = Side::Server; + } + "-key-file" => { + opts.key_file = args.remove(0); + } + "-cert-file" => { + opts.cert_file = args.remove(0); + } + "-resume-count" => { + opts.resumes = args.remove(0).parse::().unwrap(); + } + "-no-tls13" => { + opts.support_tls13 = false; + } + "-no-tls12" => { + opts.support_tls12 = false; + } + "-min-version" => { + let min = args.remove(0).parse::().unwrap(); + opts.min_version = Some(ProtocolVersion::Unknown(min)); + } + "-max-version" => { + let max = args.remove(0).parse::().unwrap(); + opts.max_version = Some(ProtocolVersion::Unknown(max)); + } + "-max-send-fragment" => { + let max_fragment = args.remove(0).parse::().unwrap(); + opts.max_fragment = Some(max_fragment + 5); // ours includes header + } + "-read-size" => { + let rdsz = args.remove(0).parse::().unwrap(); + opts.read_size = rdsz; + } + "-tls13-variant" => { + let variant = args.remove(0).parse::().unwrap(); + if variant != 1 { + println!("NYI TLS1.3 variant selection: {:?} {:?}", arg, variant); + process::exit(BOGO_NACK); + } + } + "-no-ticket" => { + opts.tickets = false; + } + "-on-resume-no-ticket" => { + opts.resume_with_tickets_disabled = true; + } + "-signing-prefs" => { + let alg = args.remove(0).parse::().unwrap(); + opts.use_signing_scheme = alg; + } + "-max-cert-list" | + "-expect-curve-id" | + "-expect-resume-curve-id" | + "-expect-peer-signature-algorithm" | + "-expect-peer-verify-pref" | + "-expect-advertised-alpn" | + "-expect-alpn" | + "-on-initial-expect-alpn" | + "-on-resume-expect-alpn" | + "-on-retry-expect-alpn" | + "-expect-server-name" | + "-expect-ocsp-response" | + "-expect-signed-cert-timestamps" | + "-expect-certificate-types" | + "-expect-client-ca-list" | + "-on-retry-expect-early-data-reason" | + "-on-resume-expect-early-data-reason" | + "-on-initial-expect-early-data-reason" | + "-on-initial-expect-cipher" | + "-on-resume-expect-cipher" | + "-on-retry-expect-cipher" | + "-expect-ticket-age-skew" | + "-handshaker-path" | + "-application-settings" | + "-expect-msg-callback" => { + println!("not checking {} {}; NYI", arg, args.remove(0)); + } + + "-expect-secure-renegotiation" | + "-expect-no-session-id" | + "-enable-ed25519" | + "-expect-hrr" | + "-expect-no-hrr" | + "-on-resume-expect-no-offer-early-data" | + "-key-update" | //< we could implement an API for this + "-expect-tls13-downgrade" | + "-expect-session-id" => { + println!("not checking {}; NYI", arg); + } + + "-export-keying-material" => { + opts.export_keying_material = args.remove(0).parse::().unwrap(); + } + "-export-label" => { + opts.export_keying_material_label = args.remove(0); + } + "-export-context" => { + opts.export_keying_material_context = args.remove(0); + } + "-use-export-context" => { + opts.export_keying_material_context_used = true; + } + "-quic-transport-params" => { + opts.quic_transport_params = BASE64_STANDARD.decode(args.remove(0).as_bytes()) + .expect("invalid base64"); + } + "-expect-quic-transport-params" => { + opts.expect_quic_transport_params = BASE64_STANDARD.decode(args.remove(0).as_bytes()) + .expect("invalid base64"); + } + + "-ocsp-response" => { + opts.server_ocsp_response = BASE64_STANDARD.decode(args.remove(0).as_bytes()) + .expect("invalid base64"); + } + "-signed-cert-timestamps" => { + opts.server_sct_list = BASE64_STANDARD.decode(args.remove(0).as_bytes()) + .expect("invalid base64"); + + if opts.server_sct_list.len() == 2 && + opts.server_sct_list[0] == 0x00 && + opts.server_sct_list[1] == 0x00 { + quit(":INVALID_SCT_LIST:"); + } + } + "-select-alpn" => { + opts.protocols.push(args.remove(0)); + } + "-require-any-client-certificate" => { + opts.require_any_client_cert = true; + } + "-verify-peer" => { + opts.verify_peer = true; + } + "-shim-writes-first" => { + opts.queue_data = true; + } + "-read-with-unfinished-write" => { + opts.queue_data = true; + opts.only_write_one_byte_after_handshake = true; + } + "-shim-shuts-down" => { + opts.shut_down_after_handshake = true; + } + "-check-close-notify" => { + opts.check_close_notify = true; + } + "-host-name" => { + opts.host_name = args.remove(0); + opts.use_sni = true; + } + "-advertise-alpn" => { + opts.protocols = split_protocols(&args.remove(0)); + } + "-reject-alpn" => { + opts.reject_alpn = true; + } + "-use-null-client-ca-list" => { + opts.offer_no_client_cas = true; + } + "-enable-signed-cert-timestamps" => { + opts.send_sct = true; + } + "-enable-early-data" => { + opts.tickets = false; + opts.enable_early_data = true; + } + "-on-resume-shim-writes-first" => { + opts.queue_data_on_resume = true; + } + "-on-resume-read-with-unfinished-write" => { + opts.queue_data_on_resume = true; + opts.only_write_one_byte_after_handshake_on_resume = true; + } + "-on-resume-early-write-after-message" => { + opts.queue_early_data_after_received_messages= match args.remove(0).parse::().unwrap() { + // estimate where these messages appear in the server's first flight. + 2 => vec![5 + 128 + 5 + 32], + 8 => vec![5 + 128 + 5 + 32, 5 + 64], + _ => { + panic!("unhandled -on-resume-early-write-after-message"); + } + }; + opts.queue_data_on_resume = true; + } + "-expect-ticket-supports-early-data" => { + opts.expect_ticket_supports_early_data = true; + } + "-expect-accept-early-data" | + "-on-resume-expect-accept-early-data" => { + opts.expect_accept_early_data = true; + } + "-expect-early-data-reason" | + "-on-resume-expect-reject-early-data-reason" => { + let reason = args.remove(0); + match reason.as_str() { + "disabled" | "protocol_version" => { + opts.expect_reject_early_data = true; + } + _ => { + println!("NYI early data reason: {}", reason); + process::exit(1); + } + } + } + "-expect-reject-early-data" | + "-on-resume-expect-reject-early-data" => { + opts.expect_reject_early_data = true; + } + "-expect-version" => { + opts.expect_version = args.remove(0).parse::().unwrap(); + } + "-curves" => { + let curve = args.remove(0).parse::().unwrap(); + if let Some(mut curves) = opts.curves.take() { + curves.push(curve); + } else { + opts.curves = Some(vec![ curve ]); + } + } + "-resumption-delay" => { + opts.resumption_delay = args.remove(0).parse::().unwrap(); + align_time(); + } + + // defaults: + "-enable-all-curves" | + "-renegotiate-ignore" | + "-no-tls11" | + "-no-tls1" | + "-no-ssl3" | + "-handoff" | + "-decline-alpn" | + "-expect-no-session" | + "-expect-session-miss" | + "-expect-extended-master-secret" | + "-expect-ticket-renewal" | + "-enable-ocsp-stapling" | + // internal openssl details: + "-async" | + "-implicit-handshake" | + "-use-old-client-cert-callback" | + "-use-early-callback" => {} + + // Not implemented things + "-dtls" | + "-cipher" | + "-psk" | + "-renegotiate-freely" | + "-false-start" | + "-fallback-scsv" | + "-fail-early-callback" | + "-fail-cert-callback" | + "-install-ddos-callback" | + "-advertise-npn" | + "-verify-fail" | + "-expect-channel-id" | + "-send-channel-id" | + "-select-next-proto" | + "-expect-verify-result" | + "-send-alert" | + "-digest-prefs" | + "-use-exporter-between-reads" | + "-ticket-key" | + "-tls-unique" | + "-enable-server-custom-extension" | + "-enable-client-custom-extension" | + "-expect-dhe-group-size" | + "-use-ticket-callback" | + "-enable-grease" | + "-enable-channel-id" | + "-expect-early-data-info" | + "-expect-cipher-aes" | + "-retain-only-sha256-client-cert-initial" | + "-use-client-ca-list" | + "-expect-draft-downgrade" | + "-allow-unknown-alpn-protos" | + "-on-initial-tls13-variant" | + "-on-initial-expect-curve-id" | + "-on-resume-export-early-keying-material" | + "-on-resume-enable-early-data" | + "-export-early-keying-material" | + "-handshake-twice" | + "-on-resume-verify-fail" | + "-reverify-on-resume" | + "-verify-prefs" | + "-no-op-extra-handshake" | + "-expect-peer-cert-file" | + "-no-rsa-pss-rsae-certs" | + "-ignore-tls13-downgrade" | + "-allow-hint-mismatch" | + "-fips-202205" | + "-wpa-202304" | + "-srtp-profiles" | + "-permute-extensions" | + "-on-initial-expect-peer-cert-file" => { + println!("NYI option {:?}", arg); + process::exit(BOGO_NACK); + } + + _ => { + println!("unhandled option {:?}", arg); + process::exit(1); + } + } + } + + println!("opts {:?}", opts); + + let (client_cfg, mut server_cfg) = match opts.side { + Side::Client => (Some(make_client_cfg(&opts)), None), + Side::Server => (None, Some(make_server_cfg(&opts))), + }; + + fn make_session( + opts: &Options, + scfg: &Option>, + ccfg: &Option>, + ) -> Connection { + assert!(opts.quic_transport_params.is_empty()); + assert!(opts + .expect_quic_transport_params + .is_empty()); + + if opts.side == Side::Server { + let scfg = Arc::clone(scfg.as_ref().unwrap()); + ServerConnection::new(scfg) + .unwrap() + .into() + } else { + let server_name = opts + .host_name + .as_str() + .try_into() + .unwrap(); + let ccfg = Arc::clone(ccfg.as_ref().unwrap()); + + ClientConnection::new(ccfg, server_name) + .unwrap() + .into() + } + } + + for i in 0..opts.resumes + 1 { + let sess = make_session(&opts, &server_cfg, &client_cfg); + exec(&opts, sess, i); + if opts.resume_with_tickets_disabled { + opts.tickets = false; + server_cfg = Some(make_server_cfg(&opts)); + } + } +} diff --git a/vendor/rustls-0.21.8/src/anchors.rs b/vendor/rustls-0.21.8/src/anchors.rs new file mode 100644 index 0000000000000..b5e182f73550e --- /dev/null +++ b/vendor/rustls-0.21.8/src/anchors.rs @@ -0,0 +1,186 @@ +#[cfg(feature = "logging")] +use crate::log::{debug, trace}; +use crate::x509; +use crate::{key, DistinguishedName}; +use crate::{CertificateError, Error}; + +/// A trust anchor, commonly known as a "Root Certificate." +#[derive(Debug, Clone)] +pub struct OwnedTrustAnchor { + subject_dn_header_len: usize, + subject_dn: DistinguishedName, + spki: Vec, + name_constraints: Option>, +} + +impl OwnedTrustAnchor { + /// Get a `webpki::TrustAnchor` by borrowing the owned elements. + pub(crate) fn to_trust_anchor(&self) -> webpki::TrustAnchor { + webpki::TrustAnchor { + subject: &self.subject_dn.as_ref()[self.subject_dn_header_len..], + spki: &self.spki, + name_constraints: self.name_constraints.as_deref(), + } + } + + /// Constructs an `OwnedTrustAnchor` from its components. + /// + /// All inputs are DER-encoded. + /// + /// `subject` is the [Subject] field of the trust anchor *without* the outer SEQUENCE + /// encoding. + /// + /// `spki` is the [SubjectPublicKeyInfo] field of the trust anchor. + /// + /// `name_constraints` is the [Name Constraints] to + /// apply for this trust anchor, if any. + /// + /// [Subject]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 + /// [SubjectPublicKeyInfo]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.7 + /// [Name Constraints]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 + pub fn from_subject_spki_name_constraints( + subject: impl Into>, + spki: impl Into>, + name_constraints: Option>>, + ) -> Self { + let (subject_dn, subject_dn_header_len) = { + let mut subject = subject.into(); + let before_len = subject.len(); + x509::wrap_in_sequence(&mut subject); + let header_len = subject.len().saturating_sub(before_len); + (DistinguishedName::from(subject), header_len) + }; + Self { + subject_dn_header_len, + subject_dn, + spki: spki.into(), + name_constraints: name_constraints.map(|x| x.into()), + } + } + + /// Return the subject field including its outer SEQUENCE encoding. + /// + /// This can be decoded using [x509-parser's FromDer trait](https://docs.rs/x509-parser/latest/x509_parser/prelude/trait.FromDer.html). + /// + /// ```ignore + /// use x509_parser::prelude::FromDer; + /// println!("{}", x509_parser::x509::X509Name::from_der(anchor.subject())?.1); + /// ``` + pub fn subject(&self) -> &DistinguishedName { + &self.subject_dn + } +} + +/// A container for root certificates able to provide a root-of-trust +/// for connection authentication. +#[derive(Debug, Clone)] +pub struct RootCertStore { + /// The list of roots. + pub roots: Vec, +} + +impl RootCertStore { + /// Make a new, empty `RootCertStore`. + pub fn empty() -> Self { + Self { roots: Vec::new() } + } + + /// Return true if there are no certificates. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Say how many certificates are in the container. + pub fn len(&self) -> usize { + self.roots.len() + } + + /// Add a single DER-encoded certificate to the store. + /// + /// This is suitable for a small set of root certificates that are expected to parse + /// successfully. For large collections of roots (for example from a system store) it + /// is expected that some of them might not be valid according to the rules rustls + /// implements. As long as a relatively limited number of certificates are affected, + /// this should not be a cause for concern. Use [`RootCertStore::add_parsable_certificates`] + /// in order to add as many valid roots as possible and to understand how many certificates + /// have been diagnosed as malformed. + pub fn add(&mut self, der: &key::Certificate) -> Result<(), Error> { + self.add_internal(&der.0) + } + + /// Adds all the given TrustAnchors `anchors`. This does not + /// fail. + pub fn add_trust_anchors(&mut self, trust_anchors: impl Iterator) { + self.roots.extend(trust_anchors); + } + + /// Adds all the given TrustAnchors `anchors`. This does not + /// fail. + #[deprecated(since = "0.21.6", note = "Please use `add_trust_anchors` instead")] + pub fn add_server_trust_anchors( + &mut self, + trust_anchors: impl Iterator, + ) { + self.add_trust_anchors(trust_anchors); + } + + /// Parse the given DER-encoded certificates and add all that can be parsed + /// in a best-effort fashion. + /// + /// This is because large collections of root certificates often + /// include ancient or syntactically invalid certificates. + /// + /// Returns the number of certificates added, and the number that were ignored. + pub fn add_parsable_certificates(&mut self, der_certs: &[impl AsRef<[u8]>]) -> (usize, usize) { + let mut valid_count = 0; + let mut invalid_count = 0; + + for der_cert in der_certs { + #[cfg_attr(not(feature = "logging"), allow(unused_variables))] + match self.add_internal(der_cert.as_ref()) { + Ok(_) => valid_count += 1, + Err(err) => { + trace!("invalid cert der {:?}", der_cert.as_ref()); + debug!("certificate parsing failed: {:?}", err); + invalid_count += 1; + } + } + } + + debug!( + "add_parsable_certificates processed {} valid and {} invalid certs", + valid_count, invalid_count + ); + + (valid_count, invalid_count) + } + + fn add_internal(&mut self, der: &[u8]) -> Result<(), Error> { + let ta = webpki::TrustAnchor::try_from_cert_der(der) + .map_err(|_| Error::InvalidCertificate(CertificateError::BadEncoding))?; + self.roots + .push(OwnedTrustAnchor::from_subject_spki_name_constraints( + ta.subject, + ta.spki, + ta.name_constraints, + )); + Ok(()) + } +} + +mod tests { + #[test] + fn ownedtrustanchor_subject_is_correctly_encoding_dn() { + let subject = b"subject".to_owned(); + let ota = super::OwnedTrustAnchor::from_subject_spki_name_constraints( + subject, + b"".to_owned(), + None::>, + ); + let expected_prefix = vec![ring::io::der::Tag::Sequence as u8, subject.len() as u8]; + assert_eq!( + ota.subject().as_ref(), + [expected_prefix, subject.to_vec()].concat() + ); + } +} diff --git a/vendor/rustls-0.21.8/src/bs_debug.rs b/vendor/rustls-0.21.8/src/bs_debug.rs new file mode 100644 index 0000000000000..ad73ee6b3ca8a --- /dev/null +++ b/vendor/rustls-0.21.8/src/bs_debug.rs @@ -0,0 +1,77 @@ +use std::fmt; + +/// Alternative implementation of `fmt::Debug` for byte slice. +/// +/// Standard `Debug` implementation for `[u8]` is comma separated +/// list of numbers. Since large amount of byte strings are in fact +/// ASCII strings or contain a lot of ASCII strings (e. g. HTTP), +/// it is convenient to print strings as ASCII when possible. +/// +/// This struct wraps `&[u8]` just to override `fmt::Debug`. +/// +/// `BsDebug` is not a part of public API of bytes crate. +pub(crate) struct BsDebug<'a>(pub(crate) &'a [u8]); + +impl<'a> fmt::Debug for BsDebug<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(fmt, "b\"")?; + for &c in self.0 { + // https://doc.rust-lang.org/reference.html#byte-escapes + if c == b'\n' { + write!(fmt, "\\n")?; + } else if c == b'\r' { + write!(fmt, "\\r")?; + } else if c == b'\t' { + write!(fmt, "\\t")?; + } else if c == b'\\' || c == b'"' { + write!(fmt, "\\{}", c as char)?; + } else if c == b'\0' { + write!(fmt, "\\0")?; + // ASCII printable + } else if (0x20..0x7f).contains(&c) { + write!(fmt, "{}", c as char)?; + } else { + write!(fmt, "\\x{:02x}", c)?; + } + } + write!(fmt, "\"")?; + Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::BsDebug; + + #[test] + fn debug() { + let vec: Vec<_> = (0..0x100).map(|b| b as u8).collect(); + + let expected = "b\"\ + \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\ + \\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\ + \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\ + \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f\ + \x20!\\\"#$%&'()*+,-./0123456789:;<=>?\ + @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_\ + `abcdefghijklmnopqrstuvwxyz{|}~\\x7f\ + \\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\ + \\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\ + \\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\ + \\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\ + \\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\ + \\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\ + \\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\ + \\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\ + \\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\ + \\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\ + \\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\ + \\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\ + \\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\ + \\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\ + \\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\ + \\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff\""; + + assert_eq!(expected, format!("{:?}", BsDebug(&vec))); + } +} diff --git a/vendor/rustls-0.21.8/src/builder.rs b/vendor/rustls-0.21.8/src/builder.rs new file mode 100644 index 0000000000000..5c32977fb8a8f --- /dev/null +++ b/vendor/rustls-0.21.8/src/builder.rs @@ -0,0 +1,268 @@ +use crate::error::Error; +use crate::kx::{SupportedKxGroup, ALL_KX_GROUPS}; +use crate::suites::{SupportedCipherSuite, DEFAULT_CIPHER_SUITES}; +use crate::versions; + +use std::fmt; +use std::marker::PhantomData; + +/// Building a [`ServerConfig`] or [`ClientConfig`] in a linker-friendly and +/// complete way. +/// +/// Linker-friendly: meaning unused cipher suites, protocol +/// versions, key exchange mechanisms, etc. can be discarded +/// by the linker as they'll be unreferenced. +/// +/// Complete: the type system ensures all decisions required to run a +/// server or client have been made by the time the process finishes. +/// +/// Example, to make a [`ServerConfig`]: +/// +/// ```no_run +/// # use rustls::ServerConfig; +/// # let certs = vec![]; +/// # let private_key = rustls::PrivateKey(vec![]); +/// ServerConfig::builder() +/// .with_safe_default_cipher_suites() +/// .with_safe_default_kx_groups() +/// .with_safe_default_protocol_versions() +/// .unwrap() +/// .with_no_client_auth() +/// .with_single_cert(certs, private_key) +/// .expect("bad certificate/key"); +/// ``` +/// +/// This may be shortened to: +/// +/// ```no_run +/// # use rustls::ServerConfig; +/// # let certs = vec![]; +/// # let private_key = rustls::PrivateKey(vec![]); +/// ServerConfig::builder() +/// .with_safe_defaults() +/// .with_no_client_auth() +/// .with_single_cert(certs, private_key) +/// .expect("bad certificate/key"); +/// ``` +/// +/// To make a [`ClientConfig`]: +/// +/// ```no_run +/// # use rustls::ClientConfig; +/// # let root_certs = rustls::RootCertStore::empty(); +/// # let certs = vec![]; +/// # let private_key = rustls::PrivateKey(vec![]); +/// ClientConfig::builder() +/// .with_safe_default_cipher_suites() +/// .with_safe_default_kx_groups() +/// .with_safe_default_protocol_versions() +/// .unwrap() +/// .with_root_certificates(root_certs) +/// .with_client_auth_cert(certs, private_key) +/// .expect("bad certificate/key"); +/// ``` +/// +/// This may be shortened to: +/// +/// ``` +/// # use rustls::ClientConfig; +/// # let root_certs = rustls::RootCertStore::empty(); +/// ClientConfig::builder() +/// .with_safe_defaults() +/// .with_root_certificates(root_certs) +/// .with_no_client_auth(); +/// ``` +/// +/// The types used here fit together like this: +/// +/// 1. Call [`ClientConfig::builder()`] or [`ServerConfig::builder()`] to initialize a builder. +/// 1. You must make a decision on which cipher suites to use, typically +/// by calling [`ConfigBuilder::with_safe_default_cipher_suites()`]. +/// 2. Now you must make a decision +/// on key exchange groups: typically by calling +/// [`ConfigBuilder::with_safe_default_kx_groups()`]. +/// 3. Now you must make +/// a decision on which protocol versions to support, typically by calling +/// [`ConfigBuilder::with_safe_default_protocol_versions()`]. +/// 5. Now see [`ConfigBuilder`] or +/// [`ConfigBuilder`] for further steps. +/// +/// [`ServerConfig`]: crate::ServerConfig +/// [`ClientConfig`]: crate::ClientConfig +/// [`ClientConfig::builder()`]: crate::ClientConfig::builder() +/// [`ServerConfig::builder()`]: crate::ServerConfig::builder() +/// [`ConfigBuilder`]: struct.ConfigBuilder.html#impl-3 +/// [`ConfigBuilder`]: struct.ConfigBuilder.html#impl-6 +#[derive(Clone)] +pub struct ConfigBuilder { + pub(crate) state: State, + pub(crate) side: PhantomData, +} + +impl fmt::Debug for ConfigBuilder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let side_name = std::any::type_name::(); + let side_name = side_name + .split("::") + .last() + .unwrap_or(side_name); + f.debug_struct(&format!("ConfigBuilder<{}, _>", side_name)) + .field("state", &self.state) + .finish() + } +} + +/// Config builder state where the caller must supply cipher suites. +/// +/// For more information, see the [`ConfigBuilder`] documentation. +#[derive(Clone, Debug)] +pub struct WantsCipherSuites(pub(crate) ()); + +impl ConfigBuilder { + /// Start side-specific config with defaults for underlying cryptography. + /// + /// If used, this will enable all safe supported cipher suites ([`DEFAULT_CIPHER_SUITES`]), all + /// safe supported key exchange groups ([`ALL_KX_GROUPS`]) and all safe supported protocol + /// versions ([`DEFAULT_VERSIONS`]). + /// + /// These are safe defaults, useful for 99% of applications. + /// + /// [`DEFAULT_VERSIONS`]: versions::DEFAULT_VERSIONS + pub fn with_safe_defaults(self) -> ConfigBuilder { + ConfigBuilder { + state: WantsVerifier { + cipher_suites: DEFAULT_CIPHER_SUITES.to_vec(), + kx_groups: ALL_KX_GROUPS.to_vec(), + versions: versions::EnabledVersions::new(versions::DEFAULT_VERSIONS), + }, + side: self.side, + } + } + + /// Choose a specific set of cipher suites. + pub fn with_cipher_suites( + self, + cipher_suites: &[SupportedCipherSuite], + ) -> ConfigBuilder { + ConfigBuilder { + state: WantsKxGroups { + cipher_suites: cipher_suites.to_vec(), + }, + side: self.side, + } + } + + /// Choose the default set of cipher suites ([`DEFAULT_CIPHER_SUITES`]). + /// + /// Note that this default provides only high-quality suites: there is no need + /// to filter out low-, export- or NULL-strength cipher suites: rustls does not + /// implement these. + pub fn with_safe_default_cipher_suites(self) -> ConfigBuilder { + self.with_cipher_suites(DEFAULT_CIPHER_SUITES) + } +} + +/// Config builder state where the caller must supply key exchange groups. +/// +/// For more information, see the [`ConfigBuilder`] documentation. +#[derive(Clone, Debug)] +pub struct WantsKxGroups { + cipher_suites: Vec, +} + +impl ConfigBuilder { + /// Choose a specific set of key exchange groups. + pub fn with_kx_groups( + self, + kx_groups: &[&'static SupportedKxGroup], + ) -> ConfigBuilder { + ConfigBuilder { + state: WantsVersions { + cipher_suites: self.state.cipher_suites, + kx_groups: kx_groups.to_vec(), + }, + side: self.side, + } + } + + /// Choose the default set of key exchange groups ([`ALL_KX_GROUPS`]). + /// + /// This is a safe default: rustls doesn't implement any poor-quality groups. + pub fn with_safe_default_kx_groups(self) -> ConfigBuilder { + self.with_kx_groups(&ALL_KX_GROUPS) + } +} + +/// Config builder state where the caller must supply TLS protocol versions. +/// +/// For more information, see the [`ConfigBuilder`] documentation. +#[derive(Clone, Debug)] +pub struct WantsVersions { + cipher_suites: Vec, + kx_groups: Vec<&'static SupportedKxGroup>, +} + +impl ConfigBuilder { + /// Accept the default protocol versions: both TLS1.2 and TLS1.3 are enabled. + pub fn with_safe_default_protocol_versions( + self, + ) -> Result, Error> { + self.with_protocol_versions(versions::DEFAULT_VERSIONS) + } + + /// Use a specific set of protocol versions. + pub fn with_protocol_versions( + self, + versions: &[&'static versions::SupportedProtocolVersion], + ) -> Result, Error> { + let mut any_usable_suite = false; + for suite in &self.state.cipher_suites { + if versions.contains(&suite.version()) { + any_usable_suite = true; + break; + } + } + + if !any_usable_suite { + return Err(Error::General("no usable cipher suites configured".into())); + } + + if self.state.kx_groups.is_empty() { + return Err(Error::General("no kx groups configured".into())); + } + + Ok(ConfigBuilder { + state: WantsVerifier { + cipher_suites: self.state.cipher_suites, + kx_groups: self.state.kx_groups, + versions: versions::EnabledVersions::new(versions), + }, + side: self.side, + }) + } +} + +/// Config builder state where the caller must supply a verifier. +/// +/// For more information, see the [`ConfigBuilder`] documentation. +#[derive(Clone, Debug)] +pub struct WantsVerifier { + pub(crate) cipher_suites: Vec, + pub(crate) kx_groups: Vec<&'static SupportedKxGroup>, + pub(crate) versions: versions::EnabledVersions, +} + +/// Helper trait to abstract [`ConfigBuilder`] over building a [`ClientConfig`] or [`ServerConfig`]. +/// +/// [`ClientConfig`]: crate::ClientConfig +/// [`ServerConfig`]: crate::ServerConfig +pub trait ConfigSide: sealed::Sealed {} + +impl ConfigSide for crate::ClientConfig {} +impl ConfigSide for crate::ServerConfig {} + +mod sealed { + pub trait Sealed {} + impl Sealed for crate::ClientConfig {} + impl Sealed for crate::ServerConfig {} +} diff --git a/vendor/rustls-0.21.8/src/check.rs b/vendor/rustls-0.21.8/src/check.rs new file mode 100644 index 0000000000000..e61a42a3d45bf --- /dev/null +++ b/vendor/rustls-0.21.8/src/check.rs @@ -0,0 +1,77 @@ +use crate::enums::{ContentType, HandshakeType}; +use crate::error::Error; +#[cfg(feature = "logging")] +use crate::log::warn; +use crate::msgs::message::MessagePayload; + +/// For a Message $m, and a HandshakePayload enum member $payload_type, +/// return Ok(payload) if $m is both a handshake message and one that +/// has the given $payload_type. If not, return Err(rustls::Error) quoting +/// $handshake_type as the expected handshake type. +macro_rules! require_handshake_msg( + ( $m:expr, $handshake_type:path, $payload_type:path ) => ( + match &$m.payload { + MessagePayload::Handshake { parsed: $crate::msgs::handshake::HandshakeMessagePayload { + payload: $payload_type(hm), + .. + }, .. } => Ok(hm), + payload => Err($crate::check::inappropriate_handshake_message( + payload, + &[$crate::ContentType::Handshake], + &[$handshake_type])) + } + ) +); + +/// Like require_handshake_msg, but moves the payload out of $m. +#[cfg(feature = "tls12")] +macro_rules! require_handshake_msg_move( + ( $m:expr, $handshake_type:path, $payload_type:path ) => ( + match $m.payload { + MessagePayload::Handshake { parsed: $crate::msgs::handshake::HandshakeMessagePayload { + payload: $payload_type(hm), + .. + }, .. } => Ok(hm), + payload => + Err($crate::check::inappropriate_handshake_message( + &payload, + &[$crate::ContentType::Handshake], + &[$handshake_type])) + } + ) +); + +pub(crate) fn inappropriate_message( + payload: &MessagePayload, + content_types: &[ContentType], +) -> Error { + warn!( + "Received a {:?} message while expecting {:?}", + payload.content_type(), + content_types + ); + Error::InappropriateMessage { + expect_types: content_types.to_vec(), + got_type: payload.content_type(), + } +} + +pub(crate) fn inappropriate_handshake_message( + payload: &MessagePayload, + content_types: &[ContentType], + handshake_types: &[HandshakeType], +) -> Error { + match payload { + MessagePayload::Handshake { parsed, .. } => { + warn!( + "Received a {:?} handshake message while expecting {:?}", + parsed.typ, handshake_types + ); + Error::InappropriateHandshakeMessage { + expect_types: handshake_types.to_vec(), + got_type: parsed.typ, + } + } + payload => inappropriate_message(payload, content_types), + } +} diff --git a/vendor/rustls-0.21.8/src/cipher.rs b/vendor/rustls-0.21.8/src/cipher.rs new file mode 100644 index 0000000000000..b4cde3b9bb315 --- /dev/null +++ b/vendor/rustls-0.21.8/src/cipher.rs @@ -0,0 +1,101 @@ +use crate::error::Error; +use crate::msgs::codec; +use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage}; + +use ring::{aead, hkdf}; + +/// Objects with this trait can decrypt TLS messages. +pub trait MessageDecrypter: Send + Sync { + /// Perform the decryption over the concerned TLS message. + + fn decrypt(&self, m: OpaqueMessage, seq: u64) -> Result; +} + +/// Objects with this trait can encrypt TLS messages. +pub(crate) trait MessageEncrypter: Send + Sync { + fn encrypt(&self, m: BorrowedPlainMessage, seq: u64) -> Result; +} + +impl dyn MessageEncrypter { + pub(crate) fn invalid() -> Box { + Box::new(InvalidMessageEncrypter {}) + } +} + +impl dyn MessageDecrypter { + pub(crate) fn invalid() -> Box { + Box::new(InvalidMessageDecrypter {}) + } +} + +/// A write or read IV. +#[derive(Default)] +pub(crate) struct Iv(pub(crate) [u8; ring::aead::NONCE_LEN]); + +impl Iv { + #[cfg(feature = "tls12")] + fn new(value: [u8; ring::aead::NONCE_LEN]) -> Self { + Self(value) + } + + #[cfg(feature = "tls12")] + pub(crate) fn copy(value: &[u8]) -> Self { + debug_assert_eq!(value.len(), ring::aead::NONCE_LEN); + let mut iv = Self::new(Default::default()); + iv.0.copy_from_slice(value); + iv + } + + #[cfg(test)] + pub(crate) fn value(&self) -> &[u8; 12] { + &self.0 + } +} + +pub(crate) struct IvLen; + +impl hkdf::KeyType for IvLen { + fn len(&self) -> usize { + aead::NONCE_LEN + } +} + +impl From> for Iv { + fn from(okm: hkdf::Okm) -> Self { + let mut r = Self(Default::default()); + okm.fill(&mut r.0[..]).unwrap(); + r + } +} + +pub(crate) fn make_nonce(iv: &Iv, seq: u64) -> ring::aead::Nonce { + let mut nonce = [0u8; ring::aead::NONCE_LEN]; + codec::put_u64(seq, &mut nonce[4..]); + + nonce + .iter_mut() + .zip(iv.0.iter()) + .for_each(|(nonce, iv)| { + *nonce ^= *iv; + }); + + aead::Nonce::assume_unique_for_key(nonce) +} + +/// A `MessageEncrypter` which doesn't work. +struct InvalidMessageEncrypter {} + +impl MessageEncrypter for InvalidMessageEncrypter { + fn encrypt(&self, _m: BorrowedPlainMessage, _seq: u64) -> Result { + Err(Error::EncryptError) + } +} + +/// A `MessageDecrypter` which doesn't work. +struct InvalidMessageDecrypter {} + +impl MessageDecrypter for InvalidMessageDecrypter { + fn decrypt(&self, _m: OpaqueMessage, _seq: u64) -> Result { + Err(Error::DecryptError) + } +} diff --git a/vendor/rustls-0.21.8/src/client/builder.rs b/vendor/rustls-0.21.8/src/client/builder.rs new file mode 100644 index 0000000000000..aaf4e489e128c --- /dev/null +++ b/vendor/rustls-0.21.8/src/client/builder.rs @@ -0,0 +1,222 @@ +use crate::builder::{ConfigBuilder, WantsVerifier}; +use crate::client::{handy, ClientConfig, ResolvesClientCert}; +use crate::error::Error; +use crate::key_log::NoKeyLog; +use crate::kx::SupportedKxGroup; +use crate::suites::SupportedCipherSuite; +use crate::verify::{self, CertificateTransparencyPolicy}; +use crate::{anchors, key, versions}; + +use super::client_conn::Resumption; + +use std::marker::PhantomData; +use std::sync::Arc; +use std::time::SystemTime; + +impl ConfigBuilder { + /// Choose how to verify server certificates. + pub fn with_root_certificates( + self, + root_store: impl Into>, + ) -> ConfigBuilder { + ConfigBuilder { + state: WantsTransparencyPolicyOrClientCert { + cipher_suites: self.state.cipher_suites, + kx_groups: self.state.kx_groups, + versions: self.state.versions, + root_store: root_store.into(), + }, + side: PhantomData, + } + } + + #[cfg(feature = "dangerous_configuration")] + /// Set a custom certificate verifier. + pub fn with_custom_certificate_verifier( + self, + verifier: Arc, + ) -> ConfigBuilder { + ConfigBuilder { + state: WantsClientCert { + cipher_suites: self.state.cipher_suites, + kx_groups: self.state.kx_groups, + versions: self.state.versions, + verifier, + }, + side: PhantomData, + } + } +} + +/// A config builder state where the caller needs to supply a certificate transparency policy or +/// client certificate resolver. +/// +/// In this state, the caller can optionally enable certificate transparency, or ignore CT and +/// invoke one of the methods related to client certificates (as in the [`WantsClientCert`] state). +/// +/// For more information, see the [`ConfigBuilder`] documentation. +#[derive(Clone, Debug)] +pub struct WantsTransparencyPolicyOrClientCert { + cipher_suites: Vec, + kx_groups: Vec<&'static SupportedKxGroup>, + versions: versions::EnabledVersions, + root_store: Arc, +} + +impl ConfigBuilder { + /// Set Certificate Transparency logs to use for server certificate validation. + /// + /// Because Certificate Transparency logs are sharded on a per-year basis and can be trusted or + /// distrusted relatively quickly, rustls stores a validation deadline. Server certificates will + /// be validated against the configured CT logs until the deadline expires. After the deadline, + /// certificates will no longer be validated, and a warning message will be logged. The deadline + /// may vary depending on how often you deploy builds with updated dependencies. + pub fn with_certificate_transparency_logs( + self, + logs: &'static [&'static sct::Log], + validation_deadline: SystemTime, + ) -> ConfigBuilder { + self.with_logs(Some(CertificateTransparencyPolicy::new( + logs, + validation_deadline, + ))) + } + + /// Sets a single certificate chain and matching private key for use + /// in client authentication. + /// + /// `cert_chain` is a vector of DER-encoded certificates. + /// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key. + /// + /// This function fails if `key_der` is invalid. + pub fn with_client_auth_cert( + self, + cert_chain: Vec, + key_der: key::PrivateKey, + ) -> Result { + self.with_logs(None) + .with_client_auth_cert(cert_chain, key_der) + } + + /// Sets a single certificate chain and matching private key for use + /// in client authentication. + /// + /// `cert_chain` is a vector of DER-encoded certificates. + /// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key. + /// + /// This function fails if `key_der` is invalid. + #[deprecated(since = "0.21.4", note = "Use `with_client_auth_cert` instead")] + pub fn with_single_cert( + self, + cert_chain: Vec, + key_der: key::PrivateKey, + ) -> Result { + self.with_client_auth_cert(cert_chain, key_der) + } + + /// Do not support client auth. + pub fn with_no_client_auth(self) -> ClientConfig { + self.with_logs(None) + .with_client_cert_resolver(Arc::new(handy::FailResolveClientCert {})) + } + + /// Sets a custom [`ResolvesClientCert`]. + pub fn with_client_cert_resolver( + self, + client_auth_cert_resolver: Arc, + ) -> ClientConfig { + self.with_logs(None) + .with_client_cert_resolver(client_auth_cert_resolver) + } + + fn with_logs( + self, + ct_policy: Option, + ) -> ConfigBuilder { + ConfigBuilder { + state: WantsClientCert { + cipher_suites: self.state.cipher_suites, + kx_groups: self.state.kx_groups, + versions: self.state.versions, + verifier: Arc::new(verify::WebPkiVerifier::new( + self.state.root_store, + ct_policy, + )), + }, + side: PhantomData, + } + } +} + +/// A config builder state where the caller needs to supply whether and how to provide a client +/// certificate. +/// +/// For more information, see the [`ConfigBuilder`] documentation. +#[derive(Clone, Debug)] +pub struct WantsClientCert { + cipher_suites: Vec, + kx_groups: Vec<&'static SupportedKxGroup>, + versions: versions::EnabledVersions, + verifier: Arc, +} + +impl ConfigBuilder { + /// Sets a single certificate chain and matching private key for use + /// in client authentication. + /// + /// `cert_chain` is a vector of DER-encoded certificates. + /// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key. + /// + /// This function fails if `key_der` is invalid. + pub fn with_client_auth_cert( + self, + cert_chain: Vec, + key_der: key::PrivateKey, + ) -> Result { + let resolver = handy::AlwaysResolvesClientCert::new(cert_chain, &key_der)?; + Ok(self.with_client_cert_resolver(Arc::new(resolver))) + } + + /// Sets a single certificate chain and matching private key for use + /// in client authentication. + /// + /// `cert_chain` is a vector of DER-encoded certificates. + /// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key. + /// + /// This function fails if `key_der` is invalid. + #[deprecated(since = "0.21.4", note = "Use `with_client_auth_cert` instead")] + pub fn with_single_cert( + self, + cert_chain: Vec, + key_der: key::PrivateKey, + ) -> Result { + self.with_client_auth_cert(cert_chain, key_der) + } + + /// Do not support client auth. + pub fn with_no_client_auth(self) -> ClientConfig { + self.with_client_cert_resolver(Arc::new(handy::FailResolveClientCert {})) + } + + /// Sets a custom [`ResolvesClientCert`]. + pub fn with_client_cert_resolver( + self, + client_auth_cert_resolver: Arc, + ) -> ClientConfig { + ClientConfig { + cipher_suites: self.state.cipher_suites, + kx_groups: self.state.kx_groups, + alpn_protocols: Vec::new(), + resumption: Resumption::default(), + max_fragment_size: None, + client_auth_cert_resolver, + versions: self.state.versions, + enable_sni: true, + verifier: self.state.verifier, + key_log: Arc::new(NoKeyLog {}), + #[cfg(feature = "secret_extraction")] + enable_secret_extraction: false, + enable_early_data: false, + } + } +} diff --git a/vendor/rustls-0.21.8/src/client/client_conn.rs b/vendor/rustls-0.21.8/src/client/client_conn.rs new file mode 100644 index 0000000000000..b84219f27a6c0 --- /dev/null +++ b/vendor/rustls-0.21.8/src/client/client_conn.rs @@ -0,0 +1,693 @@ +use crate::builder::{ConfigBuilder, WantsCipherSuites}; +use crate::common_state::{CommonState, Protocol, Side}; +use crate::conn::{ConnectionCommon, ConnectionCore}; +use crate::dns_name::{DnsName, DnsNameRef, InvalidDnsNameError}; +use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme}; +use crate::error::Error; +use crate::kx::SupportedKxGroup; +#[cfg(feature = "logging")] +use crate::log::trace; +use crate::msgs::enums::NamedGroup; +use crate::msgs::handshake::ClientExtension; +use crate::msgs::persist; +use crate::sign; +use crate::suites::SupportedCipherSuite; +use crate::verify; +use crate::versions; +#[cfg(feature = "secret_extraction")] +use crate::ExtractedSecrets; +use crate::KeyLog; + +use super::handy::{ClientSessionMemoryCache, NoClientSessionStorage}; +use super::hs; + +use std::marker::PhantomData; +use std::net::IpAddr; +use std::ops::{Deref, DerefMut}; +use std::sync::Arc; +use std::{fmt, io, mem}; + +/// A trait for the ability to store client session data, so that sessions +/// can be resumed in future connections. +/// +/// Generally all data in this interface should be treated as +/// **highly sensitive**, containing enough key material to break all security +/// of the corresponding session. +/// +/// `set_`, `insert_`, `remove_` and `take_` operations are mutating; this isn't +/// expressed in the type system to allow implementations freedom in +/// how to achieve interior mutability. `Mutex` is a common choice. +pub trait ClientSessionStore: Send + Sync { + /// Remember what `NamedGroup` the given server chose. + fn set_kx_hint(&self, server_name: &ServerName, group: NamedGroup); + + /// This should return the value most recently passed to `set_kx_hint` + /// for the given `server_name`. + /// + /// If `None` is returned, the caller chooses the first configured group, + /// and an extra round trip might happen if that choice is unsatisfactory + /// to the server. + fn kx_hint(&self, server_name: &ServerName) -> Option; + + /// Remember a TLS1.2 session. + /// + /// At most one of these can be remembered at a time, per `server_name`. + fn set_tls12_session(&self, server_name: &ServerName, value: persist::Tls12ClientSessionValue); + + /// Get the most recently saved TLS1.2 session for `server_name` provided to `set_tls12_session`. + fn tls12_session(&self, server_name: &ServerName) -> Option; + + /// Remove and forget any saved TLS1.2 session for `server_name`. + fn remove_tls12_session(&self, server_name: &ServerName); + + /// Remember a TLS1.3 ticket that might be retrieved later from `take_tls13_ticket`, allowing + /// resumption of this session. + /// + /// This can be called multiple times for a given session, allowing multiple independent tickets + /// to be valid at once. The number of times this is called is controlled by the server, so + /// implementations of this trait should apply a reasonable bound of how many items are stored + /// simultaneously. + fn insert_tls13_ticket( + &self, + server_name: &ServerName, + value: persist::Tls13ClientSessionValue, + ); + + /// Return a TLS1.3 ticket previously provided to `add_tls13_ticket`. + /// + /// Implementations of this trait must return each value provided to `add_tls13_ticket` _at most once_. + fn take_tls13_ticket( + &self, + server_name: &ServerName, + ) -> Option; +} + +/// A trait for the ability to choose a certificate chain and +/// private key for the purposes of client authentication. +pub trait ResolvesClientCert: Send + Sync { + /// With the server-supplied acceptable issuers in `acceptable_issuers`, + /// the server's supported signature schemes in `sigschemes`, + /// return a certificate chain and signing key to authenticate. + /// + /// `acceptable_issuers` is undecoded and unverified by the rustls + /// library, but it should be expected to contain a DER encodings + /// of X501 NAMEs. + /// + /// Return None to continue the handshake without any client + /// authentication. The server may reject the handshake later + /// if it requires authentication. + fn resolve( + &self, + acceptable_issuers: &[&[u8]], + sigschemes: &[SignatureScheme], + ) -> Option>; + + /// Return true if any certificates at all are available. + fn has_certs(&self) -> bool; +} + +/// Common configuration for (typically) all connections made by a program. +/// +/// Making one of these is cheap, though one of the inputs may be expensive: gathering trust roots +/// from the operating system to add to the [`RootCertStore`] passed to `with_root_certificates()` +/// (the rustls-native-certs crate is often used for this) may take on the order of a few hundred +/// milliseconds. +/// +/// These must be created via the [`ClientConfig::builder()`] function. +/// +/// # Defaults +/// +/// * [`ClientConfig::max_fragment_size`]: the default is `None`: TLS packets are not fragmented to a specific size. +/// * [`ClientConfig::resumption`]: supports resumption with up to 256 server names, using session +/// ids or tickets, with a max of eight tickets per server. +/// * [`ClientConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated. +/// * [`ClientConfig::key_log`]: key material is not logged. +/// +/// [`RootCertStore`]: crate::RootCertStore +#[derive(Clone)] +pub struct ClientConfig { + /// List of ciphersuites, in preference order. + pub(super) cipher_suites: Vec, + + /// List of supported key exchange algorithms, in preference order -- the + /// first element is the highest priority. + /// + /// The first element in this list is the _default key share algorithm_, + /// and in TLS1.3 a key share for it is sent in the client hello. + pub(super) kx_groups: Vec<&'static SupportedKxGroup>, + + /// Which ALPN protocols we include in our client hello. + /// If empty, no ALPN extension is sent. + pub alpn_protocols: Vec>, + + /// How and when the client can resume a previous session. + pub resumption: Resumption, + + /// The maximum size of TLS message we'll emit. If None, we don't limit TLS + /// message lengths except to the 2**16 limit specified in the standard. + /// + /// rustls enforces an arbitrary minimum of 32 bytes for this field. + /// Out of range values are reported as errors from ClientConnection::new. + /// + /// Setting this value to the TCP MSS may improve latency for stream-y workloads. + pub max_fragment_size: Option, + + /// How to decide what client auth certificate/keys to use. + pub client_auth_cert_resolver: Arc, + + /// Supported versions, in no particular order. The default + /// is all supported versions. + pub(super) versions: versions::EnabledVersions, + + /// Whether to send the Server Name Indication (SNI) extension + /// during the client handshake. + /// + /// The default is true. + pub enable_sni: bool, + + /// How to verify the server certificate chain. + pub(super) verifier: Arc, + + /// How to output key material for debugging. The default + /// does nothing. + pub key_log: Arc, + + /// Allows traffic secrets to be extracted after the handshake, + /// e.g. for kTLS setup. + #[cfg(feature = "secret_extraction")] + #[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] + pub enable_secret_extraction: bool, + + /// Whether to send data on the first flight ("early data") in + /// TLS 1.3 handshakes. + /// + /// The default is false. + pub enable_early_data: bool, +} + +/// What mechanisms to support for resuming a TLS 1.2 session. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Tls12Resumption { + /// Disable 1.2 resumption. + Disabled, + /// Support 1.2 resumption using session ids only. + SessionIdOnly, + /// Support 1.2 resumption using session ids or RFC 5077 tickets. + /// + /// See[^1] for why you might like to disable RFC 5077 by instead choosing the `SessionIdOnly` + /// option. Note that TLS 1.3 tickets do not have those issues. + /// + /// [^1]: + SessionIdOrTickets, +} + +impl fmt::Debug for ClientConfig { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ClientConfig") + .field("alpn_protocols", &self.alpn_protocols) + .field("resumption", &self.resumption) + .field("max_fragment_size", &self.max_fragment_size) + .field("enable_sni", &self.enable_sni) + .field("enable_early_data", &self.enable_early_data) + .finish_non_exhaustive() + } +} + +impl ClientConfig { + /// Create a builder to build up the client configuration. + /// + /// For more information, see the [`ConfigBuilder`] documentation. + pub fn builder() -> ConfigBuilder { + ConfigBuilder { + state: WantsCipherSuites(()), + side: PhantomData, + } + } + + /// We support a given TLS version if it's quoted in the configured + /// versions *and* at least one ciphersuite for this version is + /// also configured. + pub(crate) fn supports_version(&self, v: ProtocolVersion) -> bool { + self.versions.contains(v) + && self + .cipher_suites + .iter() + .any(|cs| cs.version().version == v) + } + + /// Access configuration options whose use is dangerous and requires + /// extra care. + #[cfg(feature = "dangerous_configuration")] + pub fn dangerous(&mut self) -> danger::DangerousClientConfig { + danger::DangerousClientConfig { cfg: self } + } + + pub(super) fn find_cipher_suite(&self, suite: CipherSuite) -> Option { + self.cipher_suites + .iter() + .copied() + .find(|&scs| scs.suite() == suite) + } +} + +/// Configuration for how/when a client is allowed to resume a previous session. +#[derive(Clone)] +pub struct Resumption { + /// How we store session data or tickets. The default is to use an in-memory + /// [ClientSessionMemoryCache]. + pub(super) store: Arc, + + /// What mechanism is used for resuming a TLS 1.2 session. + pub(super) tls12_resumption: Tls12Resumption, +} + +impl Resumption { + /// Create a new `Resumption` that stores data for the given number of sessions in memory. + /// + /// This is the default `Resumption` choice, and enables resuming a TLS 1.2 session with + /// a session id or RFC 5077 ticket. + pub fn in_memory_sessions(num: usize) -> Self { + Self { + store: Arc::new(ClientSessionMemoryCache::new(num)), + tls12_resumption: Tls12Resumption::SessionIdOrTickets, + } + } + + /// Use a custom [`ClientSessionStore`] implementation to store sessions. + /// + /// By default, enables resuming a TLS 1.2 session with a session id or RFC 5077 ticket. + pub fn store(store: Arc) -> Self { + Self { + store, + tls12_resumption: Tls12Resumption::SessionIdOrTickets, + } + } + + /// Disable all use of session resumption. + pub fn disabled() -> Self { + Self { + store: Arc::new(NoClientSessionStorage), + tls12_resumption: Tls12Resumption::Disabled, + } + } + + /// Configure whether TLS 1.2 sessions may be resumed, and by what mechanism. + /// + /// This is meaningless if you've disabled resumption entirely. + pub fn tls12_resumption(mut self, tls12: Tls12Resumption) -> Self { + self.tls12_resumption = tls12; + self + } +} + +impl fmt::Debug for Resumption { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Resumption") + .field("tls12_resumption", &self.tls12_resumption) + .finish() + } +} + +impl Default for Resumption { + /// Create an in-memory session store resumption with up to 256 server names, allowing + /// a TLS 1.2 session to resume with a session id or RFC 5077 ticket. + fn default() -> Self { + Self::in_memory_sessions(256) + } +} + +/// Encodes ways a client can know the expected name of the server. +/// +/// This currently covers knowing the DNS name of the server, but +/// will be extended in the future to supporting privacy-preserving names +/// for the server ("ECH"). For this reason this enum is `non_exhaustive`. +/// +/// # Making one +/// +/// If you have a DNS name as a `&str`, this type implements `TryFrom<&str>`, +/// so you can do: +/// +/// ``` +/// # use rustls::ServerName; +/// ServerName::try_from("example.com").expect("invalid DNS name"); +/// +/// // or, alternatively... +/// +/// let x = "example.com".try_into().expect("invalid DNS name"); +/// # let _: ServerName = x; +/// ``` +#[non_exhaustive] +#[derive(Clone, Eq, Hash, PartialEq)] +pub enum ServerName { + /// The server is identified by a DNS name. The name + /// is sent in the TLS Server Name Indication (SNI) + /// extension. + DnsName(DnsName), + + /// The server is identified by an IP address. SNI is not + /// done. + IpAddress(IpAddr), +} + +impl fmt::Debug for ServerName { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::DnsName(d) => f + .debug_tuple("DnsName") + .field(&d.as_ref()) + .finish(), + Self::IpAddress(i) => f + .debug_tuple("IpAddress") + .field(i) + .finish(), + } + } +} + +impl ServerName { + /// Return the name that should go in the SNI extension. + /// If [`None`] is returned, the SNI extension is not included + /// in the handshake. + pub(crate) fn for_sni(&self) -> Option { + match self { + Self::DnsName(dns_name) => Some(dns_name.borrow()), + Self::IpAddress(_) => None, + } + } +} + +/// Attempt to make a ServerName from a string by parsing +/// it as a DNS name. +impl TryFrom<&str> for ServerName { + type Error = InvalidDnsNameError; + fn try_from(s: &str) -> Result { + match DnsNameRef::try_from(s) { + Ok(dns) => Ok(Self::DnsName(dns.to_owned())), + Err(InvalidDnsNameError) => match s.parse() { + Ok(ip) => Ok(Self::IpAddress(ip)), + Err(_) => Err(InvalidDnsNameError), + }, + } + } +} + +/// Container for unsafe APIs +#[cfg(feature = "dangerous_configuration")] +pub(super) mod danger { + use std::sync::Arc; + + use super::verify::ServerCertVerifier; + use super::ClientConfig; + + /// Accessor for dangerous configuration options. + #[derive(Debug)] + #[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] + pub struct DangerousClientConfig<'a> { + /// The underlying ClientConfig + pub cfg: &'a mut ClientConfig, + } + + impl<'a> DangerousClientConfig<'a> { + /// Overrides the default `ServerCertVerifier` with something else. + pub fn set_certificate_verifier(&mut self, verifier: Arc) { + self.cfg.verifier = verifier; + } + } +} + +#[derive(Debug, PartialEq)] +enum EarlyDataState { + Disabled, + Ready, + Accepted, + AcceptedFinished, + Rejected, +} + +pub(super) struct EarlyData { + state: EarlyDataState, + left: usize, +} + +impl EarlyData { + fn new() -> Self { + Self { + left: 0, + state: EarlyDataState::Disabled, + } + } + + pub(super) fn is_enabled(&self) -> bool { + matches!(self.state, EarlyDataState::Ready | EarlyDataState::Accepted) + } + + fn is_accepted(&self) -> bool { + matches!( + self.state, + EarlyDataState::Accepted | EarlyDataState::AcceptedFinished + ) + } + + pub(super) fn enable(&mut self, max_data: usize) { + assert_eq!(self.state, EarlyDataState::Disabled); + self.state = EarlyDataState::Ready; + self.left = max_data; + } + + pub(super) fn rejected(&mut self) { + trace!("EarlyData rejected"); + self.state = EarlyDataState::Rejected; + } + + pub(super) fn accepted(&mut self) { + trace!("EarlyData accepted"); + assert_eq!(self.state, EarlyDataState::Ready); + self.state = EarlyDataState::Accepted; + } + + pub(super) fn finished(&mut self) { + trace!("EarlyData finished"); + self.state = match self.state { + EarlyDataState::Accepted => EarlyDataState::AcceptedFinished, + _ => panic!("bad EarlyData state"), + } + } + + fn check_write(&mut self, sz: usize) -> io::Result { + match self.state { + EarlyDataState::Disabled => unreachable!(), + EarlyDataState::Ready | EarlyDataState::Accepted => { + let take = if self.left < sz { + mem::replace(&mut self.left, 0) + } else { + self.left -= sz; + sz + }; + + Ok(take) + } + EarlyDataState::Rejected | EarlyDataState::AcceptedFinished => { + Err(io::Error::from(io::ErrorKind::InvalidInput)) + } + } + } + + fn bytes_left(&self) -> usize { + self.left + } +} + +/// Stub that implements io::Write and dispatches to `write_early_data`. +pub struct WriteEarlyData<'a> { + sess: &'a mut ClientConnection, +} + +impl<'a> WriteEarlyData<'a> { + fn new(sess: &'a mut ClientConnection) -> WriteEarlyData<'a> { + WriteEarlyData { sess } + } + + /// How many bytes you may send. Writes will become short + /// once this reaches zero. + pub fn bytes_left(&self) -> usize { + self.sess + .inner + .core + .data + .early_data + .bytes_left() + } +} + +impl<'a> io::Write for WriteEarlyData<'a> { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.sess.write_early_data(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +/// This represents a single TLS client connection. +pub struct ClientConnection { + inner: ConnectionCommon, +} + +impl fmt::Debug for ClientConnection { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ClientConnection") + .finish() + } +} + +impl ClientConnection { + /// Make a new ClientConnection. `config` controls how + /// we behave in the TLS protocol, `name` is the + /// name of the server we want to talk to. + pub fn new(config: Arc, name: ServerName) -> Result { + Ok(Self { + inner: ConnectionCore::for_client(config, name, Vec::new(), Protocol::Tcp)?.into(), + }) + } + + /// Returns an `io::Write` implementer you can write bytes to + /// to send TLS1.3 early data (a.k.a. "0-RTT data") to the server. + /// + /// This returns None in many circumstances when the capability to + /// send early data is not available, including but not limited to: + /// + /// - The server hasn't been talked to previously. + /// - The server does not support resumption. + /// - The server does not support early data. + /// - The resumption data for the server has expired. + /// + /// The server specifies a maximum amount of early data. You can + /// learn this limit through the returned object, and writes through + /// it will process only this many bytes. + /// + /// The server can choose not to accept any sent early data -- + /// in this case the data is lost but the connection continues. You + /// can tell this happened using `is_early_data_accepted`. + pub fn early_data(&mut self) -> Option { + if self + .inner + .core + .data + .early_data + .is_enabled() + { + Some(WriteEarlyData::new(self)) + } else { + None + } + } + + /// Returns True if the server signalled it will process early data. + /// + /// If you sent early data and this returns false at the end of the + /// handshake then the server will not process the data. This + /// is not an error, but you may wish to resend the data. + pub fn is_early_data_accepted(&self) -> bool { + self.inner.core.is_early_data_accepted() + } + + fn write_early_data(&mut self, data: &[u8]) -> io::Result { + self.inner + .core + .data + .early_data + .check_write(data.len()) + .map(|sz| { + self.inner + .send_early_plaintext(&data[..sz]) + }) + } + + /// Extract secrets, so they can be used when configuring kTLS, for example. + #[cfg(feature = "secret_extraction")] + #[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] + pub fn extract_secrets(self) -> Result { + self.inner.extract_secrets() + } +} + +impl Deref for ClientConnection { + type Target = ConnectionCommon; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for ClientConnection { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +#[doc(hidden)] +impl<'a> TryFrom<&'a mut crate::Connection> for &'a mut ClientConnection { + type Error = (); + + fn try_from(value: &'a mut crate::Connection) -> Result { + use crate::Connection::*; + match value { + Client(conn) => Ok(conn), + Server(_) => Err(()), + } + } +} + +impl From for crate::Connection { + fn from(conn: ClientConnection) -> Self { + Self::Client(conn) + } +} + +impl ConnectionCore { + pub(crate) fn for_client( + config: Arc, + name: ServerName, + extra_exts: Vec, + proto: Protocol, + ) -> Result { + let mut common_state = CommonState::new(Side::Client); + common_state.set_max_fragment_size(config.max_fragment_size)?; + common_state.protocol = proto; + #[cfg(feature = "secret_extraction")] + { + common_state.enable_secret_extraction = config.enable_secret_extraction; + } + let mut data = ClientConnectionData::new(); + + let mut cx = hs::ClientContext { + common: &mut common_state, + data: &mut data, + }; + + let state = hs::start_handshake(name, extra_exts, config, &mut cx)?; + Ok(Self::new(state, data, common_state)) + } + + pub(crate) fn is_early_data_accepted(&self) -> bool { + self.data.early_data.is_accepted() + } +} + +/// State associated with a client connection. +pub struct ClientConnectionData { + pub(super) early_data: EarlyData, + pub(super) resumption_ciphersuite: Option, +} + +impl ClientConnectionData { + fn new() -> Self { + Self { + early_data: EarlyData::new(), + resumption_ciphersuite: None, + } + } +} + +impl crate::conn::SideData for ClientConnectionData {} diff --git a/vendor/rustls-0.21.8/src/client/common.rs b/vendor/rustls-0.21.8/src/client/common.rs new file mode 100644 index 0000000000000..3816e40f428f1 --- /dev/null +++ b/vendor/rustls-0.21.8/src/client/common.rs @@ -0,0 +1,112 @@ +use super::ResolvesClientCert; +#[cfg(feature = "logging")] +use crate::log::{debug, trace}; +use crate::msgs::enums::ExtensionType; +use crate::msgs::handshake::{CertificatePayload, DistinguishedName}; +use crate::msgs::handshake::{Sct, ServerExtension}; +use crate::{sign, SignatureScheme}; + +use std::sync::Arc; + +#[derive(Debug)] +pub(super) struct ServerCertDetails { + pub(super) cert_chain: CertificatePayload, + pub(super) ocsp_response: Vec, + pub(super) scts: Option>, +} + +impl ServerCertDetails { + pub(super) fn new( + cert_chain: CertificatePayload, + ocsp_response: Vec, + scts: Option>, + ) -> Self { + Self { + cert_chain, + ocsp_response, + scts, + } + } + + pub(super) fn scts(&self) -> impl Iterator { + self.scts + .as_deref() + .unwrap_or(&[]) + .iter() + .map(|payload| payload.as_ref()) + } +} + +pub(super) struct ClientHelloDetails { + pub(super) sent_extensions: Vec, +} + +impl ClientHelloDetails { + pub(super) fn new() -> Self { + Self { + sent_extensions: Vec::new(), + } + } + + pub(super) fn server_may_send_sct_list(&self) -> bool { + self.sent_extensions + .contains(&ExtensionType::SCT) + } + + pub(super) fn server_sent_unsolicited_extensions( + &self, + received_exts: &[ServerExtension], + allowed_unsolicited: &[ExtensionType], + ) -> bool { + for ext in received_exts { + let ext_type = ext.get_type(); + if !self.sent_extensions.contains(&ext_type) && !allowed_unsolicited.contains(&ext_type) + { + trace!("Unsolicited extension {:?}", ext_type); + return true; + } + } + + false + } +} + +pub(super) enum ClientAuthDetails { + /// Send an empty `Certificate` and no `CertificateVerify`. + Empty { auth_context_tls13: Option> }, + /// Send a non-empty `Certificate` and a `CertificateVerify`. + Verify { + certkey: Arc, + signer: Box, + auth_context_tls13: Option>, + }, +} + +impl ClientAuthDetails { + pub(super) fn resolve( + resolver: &dyn ResolvesClientCert, + canames: Option<&[DistinguishedName]>, + sigschemes: &[SignatureScheme], + auth_context_tls13: Option>, + ) -> Self { + let acceptable_issuers = canames + .unwrap_or_default() + .iter() + .map(|p| p.as_ref()) + .collect::>(); + + if let Some(certkey) = resolver.resolve(&acceptable_issuers, sigschemes) { + if let Some(signer) = certkey.key.choose_scheme(sigschemes) { + debug!("Attempting client auth"); + return Self::Verify { + certkey, + signer, + auth_context_tls13, + }; + } + } + + debug!("Client auth requested but no cert/sigscheme available"); + Self::Empty { auth_context_tls13 } + } +} diff --git a/vendor/rustls-0.21.8/src/client/handy.rs b/vendor/rustls-0.21.8/src/client/handy.rs new file mode 100644 index 0000000000000..963572fd2f0c4 --- /dev/null +++ b/vendor/rustls-0.21.8/src/client/handy.rs @@ -0,0 +1,268 @@ +use crate::client; +use crate::enums::SignatureScheme; +use crate::error::Error; +use crate::key; +use crate::limited_cache; +use crate::msgs::persist; +use crate::sign; +use crate::NamedGroup; +use crate::ServerName; + +use std::collections::VecDeque; +use std::sync::{Arc, Mutex}; + +/// An implementer of `ClientSessionStore` which does nothing. +pub(super) struct NoClientSessionStorage; + +impl client::ClientSessionStore for NoClientSessionStorage { + fn set_kx_hint(&self, _: &ServerName, _: NamedGroup) {} + + fn kx_hint(&self, _: &ServerName) -> Option { + None + } + + fn set_tls12_session(&self, _: &ServerName, _: persist::Tls12ClientSessionValue) {} + + fn tls12_session(&self, _: &ServerName) -> Option { + None + } + + fn remove_tls12_session(&self, _: &ServerName) {} + + fn insert_tls13_ticket(&self, _: &ServerName, _: persist::Tls13ClientSessionValue) {} + + fn take_tls13_ticket(&self, _: &ServerName) -> Option { + None + } +} + +const MAX_TLS13_TICKETS_PER_SERVER: usize = 8; + +struct ServerData { + kx_hint: Option, + + // Zero or one TLS1.2 sessions. + #[cfg(feature = "tls12")] + tls12: Option, + + // Up to MAX_TLS13_TICKETS_PER_SERVER TLS1.3 tickets, oldest first. + tls13: VecDeque, +} + +impl Default for ServerData { + fn default() -> Self { + Self { + kx_hint: None, + #[cfg(feature = "tls12")] + tls12: None, + tls13: VecDeque::with_capacity(MAX_TLS13_TICKETS_PER_SERVER), + } + } +} + +/// An implementer of `ClientSessionStore` that stores everything +/// in memory. +/// +/// It enforces a limit on the number of entries to bound memory usage. +pub struct ClientSessionMemoryCache { + servers: Mutex>, +} + +impl ClientSessionMemoryCache { + /// Make a new ClientSessionMemoryCache. `size` is the + /// maximum number of stored sessions. + pub fn new(size: usize) -> Self { + let max_servers = + size.saturating_add(MAX_TLS13_TICKETS_PER_SERVER - 1) / MAX_TLS13_TICKETS_PER_SERVER; + Self { + servers: Mutex::new(limited_cache::LimitedCache::new(max_servers)), + } + } +} + +impl client::ClientSessionStore for ClientSessionMemoryCache { + fn set_kx_hint(&self, server_name: &ServerName, group: NamedGroup) { + self.servers + .lock() + .unwrap() + .get_or_insert_default_and_edit(server_name.clone(), |data| data.kx_hint = Some(group)); + } + + fn kx_hint(&self, server_name: &ServerName) -> Option { + self.servers + .lock() + .unwrap() + .get(server_name) + .and_then(|sd| sd.kx_hint) + } + + fn set_tls12_session( + &self, + _server_name: &ServerName, + _value: persist::Tls12ClientSessionValue, + ) { + #[cfg(feature = "tls12")] + self.servers + .lock() + .unwrap() + .get_or_insert_default_and_edit(_server_name.clone(), |data| data.tls12 = Some(_value)); + } + + fn tls12_session(&self, _server_name: &ServerName) -> Option { + #[cfg(not(feature = "tls12"))] + return None; + + #[cfg(feature = "tls12")] + self.servers + .lock() + .unwrap() + .get(_server_name) + .and_then(|sd| sd.tls12.as_ref().cloned()) + } + + fn remove_tls12_session(&self, _server_name: &ServerName) { + #[cfg(feature = "tls12")] + self.servers + .lock() + .unwrap() + .get_mut(_server_name) + .and_then(|data| data.tls12.take()); + } + + fn insert_tls13_ticket( + &self, + server_name: &ServerName, + value: persist::Tls13ClientSessionValue, + ) { + self.servers + .lock() + .unwrap() + .get_or_insert_default_and_edit(server_name.clone(), |data| { + if data.tls13.len() == data.tls13.capacity() { + data.tls13.pop_front(); + } + data.tls13.push_back(value); + }); + } + + fn take_tls13_ticket( + &self, + server_name: &ServerName, + ) -> Option { + self.servers + .lock() + .unwrap() + .get_mut(server_name) + .and_then(|data| data.tls13.pop_back()) + } +} + +pub(super) struct FailResolveClientCert {} + +impl client::ResolvesClientCert for FailResolveClientCert { + fn resolve( + &self, + _acceptable_issuers: &[&[u8]], + _sigschemes: &[SignatureScheme], + ) -> Option> { + None + } + + fn has_certs(&self) -> bool { + false + } +} + +pub(super) struct AlwaysResolvesClientCert(Arc); + +impl AlwaysResolvesClientCert { + pub(super) fn new( + chain: Vec, + priv_key: &key::PrivateKey, + ) -> Result { + let key = sign::any_supported_type(priv_key) + .map_err(|_| Error::General("invalid private key".into()))?; + Ok(Self(Arc::new(sign::CertifiedKey::new(chain, key)))) + } +} + +impl client::ResolvesClientCert for AlwaysResolvesClientCert { + fn resolve( + &self, + _acceptable_issuers: &[&[u8]], + _sigschemes: &[SignatureScheme], + ) -> Option> { + Some(Arc::clone(&self.0)) + } + + fn has_certs(&self) -> bool { + true + } +} + +#[cfg(test)] +mod test { + use super::NoClientSessionStorage; + use crate::client::ClientSessionStore; + use crate::msgs::enums::NamedGroup; + #[cfg(feature = "tls12")] + use crate::msgs::handshake::SessionId; + use crate::msgs::persist::Tls13ClientSessionValue; + use crate::suites::SupportedCipherSuite; + use std::convert::TryInto; + + #[test] + fn test_noclientsessionstorage_does_nothing() { + let c = NoClientSessionStorage {}; + let name = "example.com".try_into().unwrap(); + let now = crate::ticketer::TimeBase::now().unwrap(); + + c.set_kx_hint(&name, NamedGroup::X25519); + assert_eq!(None, c.kx_hint(&name)); + + #[cfg(feature = "tls12")] + { + use crate::msgs::persist::Tls12ClientSessionValue; + let tls12_suite = match crate::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 { + SupportedCipherSuite::Tls12(inner) => inner, + _ => unreachable!(), + }; + + c.set_tls12_session( + &name, + Tls12ClientSessionValue::new( + tls12_suite, + SessionId::empty(), + Vec::new(), + Vec::new(), + Vec::new(), + now, + 0, + true, + ), + ); + assert!(c.tls12_session(&name).is_none()); + c.remove_tls12_session(&name); + } + + let tls13_suite = match crate::cipher_suite::TLS13_AES_256_GCM_SHA384 { + SupportedCipherSuite::Tls13(inner) => inner, + #[cfg(feature = "tls12")] + _ => unreachable!(), + }; + c.insert_tls13_ticket( + &name, + Tls13ClientSessionValue::new( + tls13_suite, + Vec::new(), + Vec::new(), + Vec::new(), + now, + 0, + 0, + 0, + ), + ); + assert!(c.take_tls13_ticket(&name).is_none()); + } +} diff --git a/vendor/rustls-0.21.8/src/client/hs.rs b/vendor/rustls-0.21.8/src/client/hs.rs new file mode 100644 index 0000000000000..1bef101bf04f8 --- /dev/null +++ b/vendor/rustls-0.21.8/src/client/hs.rs @@ -0,0 +1,917 @@ +#[cfg(feature = "logging")] +use crate::bs_debug; +use crate::check::inappropriate_handshake_message; +use crate::common_state::{CommonState, State}; +use crate::conn::ConnectionRandoms; +use crate::enums::{AlertDescription, CipherSuite, ContentType, HandshakeType, ProtocolVersion}; +use crate::error::{Error, PeerIncompatible, PeerMisbehaved}; +use crate::hash_hs::HandshakeHashBuffer; +use crate::kx; +#[cfg(feature = "logging")] +use crate::log::{debug, trace}; +use crate::msgs::base::Payload; +use crate::msgs::enums::{Compression, ExtensionType}; +use crate::msgs::enums::{ECPointFormat, PSKKeyExchangeMode}; +use crate::msgs::handshake::ConvertProtocolNameList; +use crate::msgs::handshake::{CertificateStatusRequest, ClientSessionTicket, Sct}; +use crate::msgs::handshake::{ClientExtension, HasServerExtensions}; +use crate::msgs::handshake::{ClientHelloPayload, HandshakeMessagePayload, HandshakePayload}; +use crate::msgs::handshake::{HelloRetryRequest, KeyShareEntry}; +use crate::msgs::handshake::{Random, SessionId}; +use crate::msgs::message::{Message, MessagePayload}; +use crate::msgs::persist; +use crate::ticketer::TimeBase; +use crate::tls13::key_schedule::KeyScheduleEarly; +use crate::SupportedCipherSuite; + +#[cfg(feature = "tls12")] +use super::tls12; +use super::Tls12Resumption; +use crate::client::client_conn::ClientConnectionData; +use crate::client::common::ClientHelloDetails; +use crate::client::{tls13, ClientConfig, ServerName}; + +use std::ops::Deref; +use std::sync::Arc; + +pub(super) type NextState = Box>; +pub(super) type NextStateOrError = Result; +pub(super) type ClientContext<'a> = crate::common_state::Context<'a, ClientConnectionData>; + +fn find_session( + server_name: &ServerName, + config: &ClientConfig, + #[cfg(feature = "quic")] cx: &mut ClientContext<'_>, +) -> Option> { + #[allow(clippy::let_and_return, clippy::unnecessary_lazy_evaluations)] + let found = config + .resumption + .store + .take_tls13_ticket(server_name) + .map(ClientSessionValue::Tls13) + .or_else(|| { + #[cfg(feature = "tls12")] + { + config + .resumption + .store + .tls12_session(server_name) + .map(ClientSessionValue::Tls12) + } + + #[cfg(not(feature = "tls12"))] + None + }) + .and_then(|resuming| { + let retrieved = persist::Retrieved::new(resuming, TimeBase::now().ok()?); + match retrieved.has_expired() { + false => Some(retrieved), + true => None, + } + }) + .or_else(|| { + debug!("No cached session for {:?}", server_name); + None + }); + + #[cfg(feature = "quic")] + if let Some(resuming) = &found { + if cx.common.is_quic() { + cx.common.quic.params = resuming + .tls13() + .map(|v| v.quic_params()); + } + } + + found +} + +pub(super) fn start_handshake( + server_name: ServerName, + extra_exts: Vec, + config: Arc, + cx: &mut ClientContext<'_>, +) -> NextStateOrError { + let mut transcript_buffer = HandshakeHashBuffer::new(); + if config + .client_auth_cert_resolver + .has_certs() + { + transcript_buffer.set_client_auth_enabled(); + } + + let mut resuming = find_session( + &server_name, + &config, + #[cfg(feature = "quic")] + cx, + ); + + let key_share = if config.supports_version(ProtocolVersion::TLSv1_3) { + Some(tls13::initial_key_share(&config, &server_name)?) + } else { + None + }; + + #[cfg_attr(not(feature = "tls12"), allow(unused_mut))] + let mut session_id = None; + if let Some(_resuming) = &mut resuming { + #[cfg(feature = "tls12")] + if let ClientSessionValue::Tls12(inner) = &mut _resuming.value { + // If we have a ticket, we use the sessionid as a signal that + // we're doing an abbreviated handshake. See section 3.4 in + // RFC5077. + if !inner.ticket().is_empty() { + inner.session_id = SessionId::random()?; + } + session_id = Some(inner.session_id); + } + + debug!("Resuming session"); + } else { + debug!("Not resuming any session"); + } + + // https://tools.ietf.org/html/rfc8446#appendix-D.4 + // https://tools.ietf.org/html/draft-ietf-quic-tls-34#section-8.4 + let session_id = match session_id { + Some(session_id) => session_id, + None if cx.common.is_quic() => SessionId::empty(), + None if !config.supports_version(ProtocolVersion::TLSv1_3) => SessionId::empty(), + None => SessionId::random()?, + }; + + let may_send_sct_list = config.verifier.request_scts(); + Ok(emit_client_hello_for_retry( + transcript_buffer, + None, + key_share, + extra_exts, + may_send_sct_list, + None, + ClientHelloInput { + config, + resuming, + random: Random::new()?, + #[cfg(feature = "tls12")] + using_ems: false, + sent_tls13_fake_ccs: false, + hello: ClientHelloDetails::new(), + session_id, + server_name, + }, + cx, + )) +} + +struct ExpectServerHello { + input: ClientHelloInput, + transcript_buffer: HandshakeHashBuffer, + early_key_schedule: Option, + offered_key_share: Option, + suite: Option, +} + +struct ExpectServerHelloOrHelloRetryRequest { + next: ExpectServerHello, + extra_exts: Vec, +} + +struct ClientHelloInput { + config: Arc, + resuming: Option>, + random: Random, + #[cfg(feature = "tls12")] + using_ems: bool, + sent_tls13_fake_ccs: bool, + hello: ClientHelloDetails, + session_id: SessionId, + server_name: ServerName, +} + +fn emit_client_hello_for_retry( + mut transcript_buffer: HandshakeHashBuffer, + retryreq: Option<&HelloRetryRequest>, + key_share: Option, + extra_exts: Vec, + may_send_sct_list: bool, + suite: Option, + mut input: ClientHelloInput, + cx: &mut ClientContext<'_>, +) -> NextState { + let config = &input.config; + let support_tls12 = config.supports_version(ProtocolVersion::TLSv1_2) && !cx.common.is_quic(); + let support_tls13 = config.supports_version(ProtocolVersion::TLSv1_3); + + let mut supported_versions = Vec::new(); + if support_tls13 { + supported_versions.push(ProtocolVersion::TLSv1_3); + } + + if support_tls12 { + supported_versions.push(ProtocolVersion::TLSv1_2); + } + + // should be unreachable thanks to config builder + assert!(!supported_versions.is_empty()); + + let mut exts = vec![ + ClientExtension::SupportedVersions(supported_versions), + ClientExtension::ECPointFormats(ECPointFormat::SUPPORTED.to_vec()), + ClientExtension::NamedGroups( + config + .kx_groups + .iter() + .map(|skxg| skxg.name) + .collect(), + ), + ClientExtension::SignatureAlgorithms( + config + .verifier + .supported_verify_schemes(), + ), + ClientExtension::ExtendedMasterSecretRequest, + ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()), + ]; + + if let (Some(sni_name), true) = (input.server_name.for_sni(), config.enable_sni) { + exts.push(ClientExtension::make_sni(sni_name)); + } + + if may_send_sct_list { + exts.push(ClientExtension::SignedCertificateTimestampRequest); + } + + if let Some(key_share) = &key_share { + debug_assert!(support_tls13); + let key_share = KeyShareEntry::new(key_share.group(), key_share.pubkey.as_ref()); + exts.push(ClientExtension::KeyShare(vec![key_share])); + } + + if let Some(cookie) = retryreq.and_then(HelloRetryRequest::get_cookie) { + exts.push(ClientExtension::Cookie(cookie.clone())); + } + + if support_tls13 { + // We could support PSK_KE here too. Such connections don't + // have forward secrecy, and are similar to TLS1.2 resumption. + let psk_modes = vec![PSKKeyExchangeMode::PSK_DHE_KE]; + exts.push(ClientExtension::PresharedKeyModes(psk_modes)); + } + + if !config.alpn_protocols.is_empty() { + exts.push(ClientExtension::Protocols(Vec::from_slices( + &config + .alpn_protocols + .iter() + .map(|proto| &proto[..]) + .collect::>(), + ))); + } + + // Extra extensions must be placed before the PSK extension + exts.extend(extra_exts.iter().cloned()); + + // Do we have a SessionID or ticket cached for this host? + let tls13_session = prepare_resumption(&input.resuming, &mut exts, suite, cx, config); + + // Note what extensions we sent. + input.hello.sent_extensions = exts + .iter() + .map(ClientExtension::get_type) + .collect(); + + let mut cipher_suites: Vec<_> = config + .cipher_suites + .iter() + .map(|cs| cs.suite()) + .collect(); + // We don't do renegotiation at all, in fact. + cipher_suites.push(CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV); + + let mut chp = HandshakeMessagePayload { + typ: HandshakeType::ClientHello, + payload: HandshakePayload::ClientHello(ClientHelloPayload { + client_version: ProtocolVersion::TLSv1_2, + random: input.random, + session_id: input.session_id, + cipher_suites, + compression_methods: vec![Compression::Null], + extensions: exts, + }), + }; + + let early_key_schedule = if let Some(resuming) = tls13_session { + let schedule = tls13::fill_in_psk_binder(&resuming, &transcript_buffer, &mut chp); + Some((resuming.suite(), schedule)) + } else { + None + }; + + let ch = Message { + // "This value MUST be set to 0x0303 for all records generated + // by a TLS 1.3 implementation other than an initial ClientHello + // (i.e., one not generated after a HelloRetryRequest)" + version: if retryreq.is_some() { + ProtocolVersion::TLSv1_2 + } else { + ProtocolVersion::TLSv1_0 + }, + payload: MessagePayload::handshake(chp), + }; + + if retryreq.is_some() { + // send dummy CCS to fool middleboxes prior + // to second client hello + tls13::emit_fake_ccs(&mut input.sent_tls13_fake_ccs, cx.common); + } + + trace!("Sending ClientHello {:#?}", ch); + + transcript_buffer.add_message(&ch); + cx.common.send_msg(ch, false); + + // Calculate the hash of ClientHello and use it to derive EarlyTrafficSecret + let early_key_schedule = early_key_schedule.map(|(resuming_suite, schedule)| { + if !cx.data.early_data.is_enabled() { + return schedule; + } + + tls13::derive_early_traffic_secret( + &*config.key_log, + cx, + resuming_suite, + &schedule, + &mut input.sent_tls13_fake_ccs, + &transcript_buffer, + &input.random.0, + ); + schedule + }); + + let next = ExpectServerHello { + input, + transcript_buffer, + early_key_schedule, + offered_key_share: key_share, + suite, + }; + + if support_tls13 && retryreq.is_none() { + Box::new(ExpectServerHelloOrHelloRetryRequest { next, extra_exts }) + } else { + Box::new(next) + } +} + +/// Prepare resumption with the session state retrieved from storage. +/// +/// This function will push onto `exts` to +/// +/// (a) request a new ticket if we don't have one, +/// (b) send our TLS 1.2 ticket after retrieving an 1.2 session, +/// (c) send a request for 1.3 early data if allowed and +/// (d) send a 1.3 preshared key if we have one. +/// +/// For resumption to work, the currently negotiated cipher suite (if available) must be +/// able to resume from the resuming session's cipher suite. +/// +/// If 1.3 resumption can continue, returns the 1.3 session value for further processing. +fn prepare_resumption<'a>( + resuming: &'a Option>, + exts: &mut Vec, + suite: Option, + cx: &mut ClientContext<'_>, + config: &ClientConfig, +) -> Option> { + // Check whether we're resuming with a non-empty ticket. + let resuming = match resuming { + Some(resuming) if !resuming.ticket().is_empty() => resuming, + _ => { + if config.supports_version(ProtocolVersion::TLSv1_3) + || config.resumption.tls12_resumption == Tls12Resumption::SessionIdOrTickets + { + // If we don't have a ticket, request one. + exts.push(ClientExtension::SessionTicket(ClientSessionTicket::Request)); + } + return None; + } + }; + + let tls13 = match resuming.map(|csv| csv.tls13()) { + Some(tls13) => tls13, + None => { + // TLS 1.2; send the ticket if we have support this protocol version + if config.supports_version(ProtocolVersion::TLSv1_2) + && config.resumption.tls12_resumption == Tls12Resumption::SessionIdOrTickets + { + exts.push(ClientExtension::SessionTicket(ClientSessionTicket::Offer( + Payload::new(resuming.ticket()), + ))); + } + return None; // TLS 1.2, so nothing to return here + } + }; + + if !config.supports_version(ProtocolVersion::TLSv1_3) { + return None; + } + + // If the server selected TLS 1.2, we can't resume. + let suite = match suite { + Some(SupportedCipherSuite::Tls13(suite)) => Some(suite), + #[cfg(feature = "tls12")] + Some(SupportedCipherSuite::Tls12(_)) => return None, + None => None, + }; + + // If the selected cipher suite can't select from the session's, we can't resume. + if let Some(suite) = suite { + suite.can_resume_from(tls13.suite())?; + } + + tls13::prepare_resumption(config, cx, &tls13, exts, suite.is_some()); + Some(tls13) +} + +pub(super) fn process_alpn_protocol( + common: &mut CommonState, + config: &ClientConfig, + proto: Option<&[u8]>, +) -> Result<(), Error> { + common.alpn_protocol = proto.map(ToOwned::to_owned); + + if let Some(alpn_protocol) = &common.alpn_protocol { + if !config + .alpn_protocols + .contains(alpn_protocol) + { + return Err(common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::SelectedUnofferedApplicationProtocol, + )); + } + } + + #[cfg(feature = "quic")] + { + // RFC 9001 says: "While ALPN only specifies that servers use this alert, QUIC clients MUST + // use error 0x0178 to terminate a connection when ALPN negotiation fails." We judge that + // the user intended to use ALPN (rather than some out-of-band protocol negotiation + // mechanism) iff any ALPN protocols were configured. This defends against badly-behaved + // servers which accept a connection that requires an application-layer protocol they do not + // understand. + if common.is_quic() && common.alpn_protocol.is_none() && !config.alpn_protocols.is_empty() { + return Err(common.send_fatal_alert( + AlertDescription::NoApplicationProtocol, + Error::NoApplicationProtocol, + )); + } + } + + debug!( + "ALPN protocol is {:?}", + common + .alpn_protocol + .as_ref() + .map(|v| bs_debug::BsDebug(v)) + ); + Ok(()) +} + +pub(super) fn sct_list_is_invalid(scts: &[Sct]) -> bool { + scts.is_empty() + || scts + .iter() + .any(|sct| sct.as_ref().is_empty()) +} + +impl State for ExpectServerHello { + fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> NextStateOrError { + let server_hello = + require_handshake_msg!(m, HandshakeType::ServerHello, HandshakePayload::ServerHello)?; + trace!("We got ServerHello {:#?}", server_hello); + + use crate::ProtocolVersion::{TLSv1_2, TLSv1_3}; + let config = &self.input.config; + let tls13_supported = config.supports_version(TLSv1_3); + + let server_version = if server_hello.legacy_version == TLSv1_2 { + server_hello + .get_supported_versions() + .unwrap_or(server_hello.legacy_version) + } else { + server_hello.legacy_version + }; + + let version = match server_version { + TLSv1_3 if tls13_supported => TLSv1_3, + TLSv1_2 if config.supports_version(TLSv1_2) => { + if cx.data.early_data.is_enabled() && cx.common.early_traffic { + // The client must fail with a dedicated error code if the server + // responds with TLS 1.2 when offering 0-RTT. + return Err(PeerMisbehaved::OfferedEarlyDataWithOldProtocolVersion.into()); + } + + if server_hello + .get_supported_versions() + .is_some() + { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::SelectedTls12UsingTls13VersionExtension, + ) + }); + } + + TLSv1_2 + } + _ => { + let reason = match server_version { + TLSv1_2 | TLSv1_3 => PeerIncompatible::ServerTlsVersionIsDisabledByOurConfig, + _ => PeerIncompatible::ServerDoesNotSupportTls12Or13, + }; + return Err(cx + .common + .send_fatal_alert(AlertDescription::ProtocolVersion, reason)); + } + }; + + if server_hello.compression_method != Compression::Null { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::SelectedUnofferedCompression, + ) + }); + } + + if server_hello.has_duplicate_extension() { + return Err(cx.common.send_fatal_alert( + AlertDescription::DecodeError, + PeerMisbehaved::DuplicateServerHelloExtensions, + )); + } + + let allowed_unsolicited = [ExtensionType::RenegotiationInfo]; + if self + .input + .hello + .server_sent_unsolicited_extensions(&server_hello.extensions, &allowed_unsolicited) + { + return Err(cx.common.send_fatal_alert( + AlertDescription::UnsupportedExtension, + PeerMisbehaved::UnsolicitedServerHelloExtension, + )); + } + + cx.common.negotiated_version = Some(version); + + // Extract ALPN protocol + if !cx.common.is_tls13() { + process_alpn_protocol(cx.common, config, server_hello.get_alpn_protocol())?; + } + + // If ECPointFormats extension is supplied by the server, it must contain + // Uncompressed. But it's allowed to be omitted. + if let Some(point_fmts) = server_hello.get_ecpoints_extension() { + if !point_fmts.contains(&ECPointFormat::Uncompressed) { + return Err(cx.common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerMisbehaved::ServerHelloMustOfferUncompressedEcPoints, + )); + } + } + + let suite = config + .find_cipher_suite(server_hello.cipher_suite) + .ok_or_else(|| { + cx.common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerMisbehaved::SelectedUnofferedCipherSuite, + ) + })?; + + if version != suite.version().version { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::SelectedUnusableCipherSuiteForVersion, + ) + }); + } + + match self.suite { + Some(prev_suite) if prev_suite != suite => { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::SelectedDifferentCipherSuiteAfterRetry, + ) + }); + } + _ => { + debug!("Using ciphersuite {:?}", suite); + self.suite = Some(suite); + cx.common.suite = Some(suite); + } + } + + // Start our handshake hash, and input the server-hello. + let mut transcript = self + .transcript_buffer + .start_hash(suite.hash_algorithm()); + transcript.add_message(&m); + + let randoms = ConnectionRandoms::new(self.input.random, server_hello.random); + // For TLS1.3, start message encryption using + // handshake_traffic_secret. + match suite { + SupportedCipherSuite::Tls13(suite) => { + #[allow(clippy::bind_instead_of_map)] + let resuming_session = self + .input + .resuming + .and_then(|resuming| match resuming.value { + ClientSessionValue::Tls13(inner) => Some(inner), + #[cfg(feature = "tls12")] + ClientSessionValue::Tls12(_) => None, + }); + + tls13::handle_server_hello( + self.input.config, + cx, + server_hello, + resuming_session, + self.input.server_name, + randoms, + suite, + transcript, + self.early_key_schedule, + self.input.hello, + // We always send a key share when TLS 1.3 is enabled. + self.offered_key_share.unwrap(), + self.input.sent_tls13_fake_ccs, + ) + } + #[cfg(feature = "tls12")] + SupportedCipherSuite::Tls12(suite) => { + let resuming_session = self + .input + .resuming + .and_then(|resuming| match resuming.value { + ClientSessionValue::Tls12(inner) => Some(inner), + ClientSessionValue::Tls13(_) => None, + }); + + tls12::CompleteServerHelloHandling { + config: self.input.config, + resuming_session, + server_name: self.input.server_name, + randoms, + using_ems: self.input.using_ems, + transcript, + } + .handle_server_hello(cx, suite, server_hello, tls13_supported) + } + } + } +} + +impl ExpectServerHelloOrHelloRetryRequest { + fn into_expect_server_hello(self) -> NextState { + Box::new(self.next) + } + + fn handle_hello_retry_request( + self, + cx: &mut ClientContext<'_>, + m: Message, + ) -> NextStateOrError { + let hrr = require_handshake_msg!( + m, + HandshakeType::HelloRetryRequest, + HandshakePayload::HelloRetryRequest + )?; + trace!("Got HRR {:?}", hrr); + + cx.common.check_aligned_handshake()?; + + let cookie = hrr.get_cookie(); + let req_group = hrr.get_requested_key_share_group(); + + // We always send a key share when TLS 1.3 is enabled. + let offered_key_share = self.next.offered_key_share.unwrap(); + + // A retry request is illegal if it contains no cookie and asks for + // retry of a group we already sent. + if cookie.is_none() && req_group == Some(offered_key_share.group()) { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::IllegalHelloRetryRequestWithOfferedGroup, + ) + }); + } + + // Or has an empty cookie. + if let Some(cookie) = cookie { + if cookie.0.is_empty() { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::IllegalHelloRetryRequestWithEmptyCookie, + ) + }); + } + } + + // Or has something unrecognised + if hrr.has_unknown_extension() { + return Err(cx.common.send_fatal_alert( + AlertDescription::UnsupportedExtension, + PeerIncompatible::ServerSentHelloRetryRequestWithUnknownExtension, + )); + } + + // Or has the same extensions more than once + if hrr.has_duplicate_extension() { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::DuplicateHelloRetryRequestExtensions, + ) + }); + } + + // Or asks us to change nothing. + if cookie.is_none() && req_group.is_none() { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::IllegalHelloRetryRequestWithNoChanges, + ) + }); + } + + // Or does not echo the session_id from our ClientHello: + // + // > the HelloRetryRequest has the same format as a ServerHello message, + // > and the legacy_version, legacy_session_id_echo, cipher_suite, and + // > legacy_compression_method fields have the same meaning + // + // + // and + // + // > A client which receives a legacy_session_id_echo field that does not + // > match what it sent in the ClientHello MUST abort the handshake with an + // > "illegal_parameter" alert. + // + if hrr.session_id != self.next.input.session_id { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::IllegalHelloRetryRequestWithWrongSessionId, + ) + }); + } + + // Or asks us to talk a protocol we didn't offer, or doesn't support HRR at all. + match hrr.get_supported_versions() { + Some(ProtocolVersion::TLSv1_3) => { + cx.common.negotiated_version = Some(ProtocolVersion::TLSv1_3); + } + _ => { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::IllegalHelloRetryRequestWithUnsupportedVersion, + ) + }); + } + } + + // Or asks us to use a ciphersuite we didn't offer. + let config = &self.next.input.config; + let cs = match config.find_cipher_suite(hrr.cipher_suite) { + Some(cs) => cs, + None => { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::IllegalHelloRetryRequestWithUnofferedCipherSuite, + ) + }); + } + }; + + // HRR selects the ciphersuite. + cx.common.suite = Some(cs); + + // This is the draft19 change where the transcript became a tree + let transcript = self + .next + .transcript_buffer + .start_hash(cs.hash_algorithm()); + let mut transcript_buffer = transcript.into_hrr_buffer(); + transcript_buffer.add_message(&m); + + // Early data is not allowed after HelloRetryrequest + if cx.data.early_data.is_enabled() { + cx.data.early_data.rejected(); + } + + let may_send_sct_list = self + .next + .input + .hello + .server_may_send_sct_list(); + + let key_share = match req_group { + Some(group) if group != offered_key_share.group() => { + let group = kx::KeyExchange::choose(group, &config.kx_groups).ok_or_else(|| { + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::IllegalHelloRetryRequestWithUnofferedNamedGroup, + ) + })?; + kx::KeyExchange::start(group).ok_or(Error::FailedToGetRandomBytes)? + } + _ => offered_key_share, + }; + + Ok(emit_client_hello_for_retry( + transcript_buffer, + Some(hrr), + Some(key_share), + self.extra_exts, + may_send_sct_list, + Some(cs), + self.next.input, + cx, + )) + } +} + +impl State for ExpectServerHelloOrHelloRetryRequest { + fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> NextStateOrError { + match m.payload { + MessagePayload::Handshake { + parsed: + HandshakeMessagePayload { + payload: HandshakePayload::ServerHello(..), + .. + }, + .. + } => self + .into_expect_server_hello() + .handle(cx, m), + MessagePayload::Handshake { + parsed: + HandshakeMessagePayload { + payload: HandshakePayload::HelloRetryRequest(..), + .. + }, + .. + } => self.handle_hello_retry_request(cx, m), + payload => Err(inappropriate_handshake_message( + &payload, + &[ContentType::Handshake], + &[HandshakeType::ServerHello, HandshakeType::HelloRetryRequest], + )), + } + } +} + +enum ClientSessionValue { + Tls13(persist::Tls13ClientSessionValue), + #[cfg(feature = "tls12")] + Tls12(persist::Tls12ClientSessionValue), +} + +impl ClientSessionValue { + fn common(&self) -> &persist::ClientSessionCommon { + match self { + Self::Tls13(inner) => &inner.common, + #[cfg(feature = "tls12")] + Self::Tls12(inner) => &inner.common, + } + } + + fn tls13(&self) -> Option<&persist::Tls13ClientSessionValue> { + match self { + Self::Tls13(v) => Some(v), + #[cfg(feature = "tls12")] + Self::Tls12(_) => None, + } + } +} + +impl Deref for ClientSessionValue { + type Target = persist::ClientSessionCommon; + + fn deref(&self) -> &Self::Target { + self.common() + } +} diff --git a/vendor/rustls-0.21.8/src/client/tls12.rs b/vendor/rustls-0.21.8/src/client/tls12.rs new file mode 100644 index 0000000000000..150f051bb43f0 --- /dev/null +++ b/vendor/rustls-0.21.8/src/client/tls12.rs @@ -0,0 +1,1117 @@ +use crate::check::{inappropriate_handshake_message, inappropriate_message}; +use crate::common_state::{CommonState, Side, State}; +use crate::conn::ConnectionRandoms; +use crate::enums::ProtocolVersion; +use crate::enums::{AlertDescription, ContentType, HandshakeType}; +use crate::error::{Error, InvalidMessage, PeerMisbehaved}; +use crate::hash_hs::HandshakeHash; +use crate::kx; +#[cfg(feature = "logging")] +use crate::log::{debug, trace, warn}; +use crate::msgs::base::{Payload, PayloadU8}; +use crate::msgs::ccs::ChangeCipherSpecPayload; +use crate::msgs::codec::Codec; +use crate::msgs::handshake::{ + CertificatePayload, HandshakeMessagePayload, HandshakePayload, NewSessionTicketPayload, Sct, + ServerECDHParams, SessionId, +}; +use crate::msgs::message::{Message, MessagePayload}; +use crate::msgs::persist; +use crate::sign::Signer; +#[cfg(feature = "secret_extraction")] +use crate::suites::PartiallyExtractedSecrets; +use crate::suites::SupportedCipherSuite; +use crate::ticketer::TimeBase; +use crate::tls12::{self, ConnectionSecrets, Tls12CipherSuite}; +use crate::verify::{self, DigitallySignedStruct}; + +use super::client_conn::ClientConnectionData; +use super::hs::ClientContext; +use crate::client::common::ClientAuthDetails; +use crate::client::common::ServerCertDetails; +use crate::client::{hs, ClientConfig, ServerName}; + +use ring::agreement::PublicKey; +use ring::constant_time; + +use std::sync::Arc; + +pub(super) use server_hello::CompleteServerHelloHandling; + +mod server_hello { + use crate::msgs::enums::ExtensionType; + use crate::msgs::handshake::HasServerExtensions; + use crate::msgs::handshake::ServerHelloPayload; + + use super::*; + + pub(in crate::client) struct CompleteServerHelloHandling { + pub(in crate::client) config: Arc, + pub(in crate::client) resuming_session: Option, + pub(in crate::client) server_name: ServerName, + pub(in crate::client) randoms: ConnectionRandoms, + pub(in crate::client) using_ems: bool, + pub(in crate::client) transcript: HandshakeHash, + } + + impl CompleteServerHelloHandling { + pub(in crate::client) fn handle_server_hello( + mut self, + cx: &mut ClientContext, + suite: &'static Tls12CipherSuite, + server_hello: &ServerHelloPayload, + tls13_supported: bool, + ) -> hs::NextStateOrError { + server_hello + .random + .write_slice(&mut self.randoms.server); + + // Look for TLS1.3 downgrade signal in server random + // both the server random and TLS12_DOWNGRADE_SENTINEL are + // public values and don't require constant time comparison + let has_downgrade_marker = self.randoms.server[24..] == tls12::DOWNGRADE_SENTINEL; + if tls13_supported && has_downgrade_marker { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::AttemptedDowngradeToTls12WhenTls13IsSupported, + ) + }); + } + + // Doing EMS? + self.using_ems = server_hello.ems_support_acked(); + + // Might the server send a ticket? + let must_issue_new_ticket = if server_hello + .find_extension(ExtensionType::SessionTicket) + .is_some() + { + debug!("Server supports tickets"); + true + } else { + false + }; + + // Might the server send a CertificateStatus between Certificate and + // ServerKeyExchange? + let may_send_cert_status = server_hello + .find_extension(ExtensionType::StatusRequest) + .is_some(); + if may_send_cert_status { + debug!("Server may staple OCSP response"); + } + + // Save any sent SCTs for verification against the certificate. + let server_cert_sct_list = if let Some(sct_list) = server_hello.get_sct_list() { + debug!("Server sent {:?} SCTs", sct_list.len()); + + if hs::sct_list_is_invalid(sct_list) { + return Err(PeerMisbehaved::InvalidSctList.into()); + } + Some(sct_list.to_owned()) + } else { + None + }; + + // See if we're successfully resuming. + if let Some(ref resuming) = self.resuming_session { + if resuming.session_id == server_hello.session_id { + debug!("Server agreed to resume"); + + // Is the server telling lies about the ciphersuite? + if resuming.suite() != suite { + return Err(PeerMisbehaved::ResumptionOfferedWithVariedCipherSuite.into()); + } + + // And about EMS support? + if resuming.extended_ms() != self.using_ems { + return Err(PeerMisbehaved::ResumptionOfferedWithVariedEms.into()); + } + + let secrets = + ConnectionSecrets::new_resume(self.randoms, suite, resuming.secret()); + self.config.key_log.log( + "CLIENT_RANDOM", + &secrets.randoms.client, + &secrets.master_secret, + ); + cx.common + .start_encryption_tls12(&secrets, Side::Client); + + // Since we're resuming, we verified the certificate and + // proof of possession in the prior session. + cx.common.peer_certificates = Some(resuming.server_cert_chain().to_vec()); + let cert_verified = verify::ServerCertVerified::assertion(); + let sig_verified = verify::HandshakeSignatureValid::assertion(); + + return if must_issue_new_ticket { + Ok(Box::new(ExpectNewTicket { + config: self.config, + secrets, + resuming_session: self.resuming_session, + session_id: server_hello.session_id, + server_name: self.server_name, + using_ems: self.using_ems, + transcript: self.transcript, + resuming: true, + cert_verified, + sig_verified, + })) + } else { + Ok(Box::new(ExpectCcs { + config: self.config, + secrets, + resuming_session: self.resuming_session, + session_id: server_hello.session_id, + server_name: self.server_name, + using_ems: self.using_ems, + transcript: self.transcript, + ticket: None, + resuming: true, + cert_verified, + sig_verified, + })) + }; + } + } + + Ok(Box::new(ExpectCertificate { + config: self.config, + resuming_session: self.resuming_session, + session_id: server_hello.session_id, + server_name: self.server_name, + randoms: self.randoms, + using_ems: self.using_ems, + transcript: self.transcript, + suite, + may_send_cert_status, + must_issue_new_ticket, + server_cert_sct_list, + })) + } + } +} + +struct ExpectCertificate { + config: Arc, + resuming_session: Option, + session_id: SessionId, + server_name: ServerName, + randoms: ConnectionRandoms, + using_ems: bool, + transcript: HandshakeHash, + pub(super) suite: &'static Tls12CipherSuite, + may_send_cert_status: bool, + must_issue_new_ticket: bool, + server_cert_sct_list: Option>, +} + +impl State for ExpectCertificate { + fn handle( + mut self: Box, + _cx: &mut ClientContext<'_>, + m: Message, + ) -> hs::NextStateOrError { + self.transcript.add_message(&m); + let server_cert_chain = require_handshake_msg_move!( + m, + HandshakeType::Certificate, + HandshakePayload::Certificate + )?; + + if self.may_send_cert_status { + Ok(Box::new(ExpectCertificateStatusOrServerKx { + config: self.config, + resuming_session: self.resuming_session, + session_id: self.session_id, + server_name: self.server_name, + randoms: self.randoms, + using_ems: self.using_ems, + transcript: self.transcript, + suite: self.suite, + server_cert_sct_list: self.server_cert_sct_list, + server_cert_chain, + must_issue_new_ticket: self.must_issue_new_ticket, + })) + } else { + let server_cert = + ServerCertDetails::new(server_cert_chain, vec![], self.server_cert_sct_list); + + Ok(Box::new(ExpectServerKx { + config: self.config, + resuming_session: self.resuming_session, + session_id: self.session_id, + server_name: self.server_name, + randoms: self.randoms, + using_ems: self.using_ems, + transcript: self.transcript, + suite: self.suite, + server_cert, + must_issue_new_ticket: self.must_issue_new_ticket, + })) + } + } +} + +struct ExpectCertificateStatusOrServerKx { + config: Arc, + resuming_session: Option, + session_id: SessionId, + server_name: ServerName, + randoms: ConnectionRandoms, + using_ems: bool, + transcript: HandshakeHash, + suite: &'static Tls12CipherSuite, + server_cert_sct_list: Option>, + server_cert_chain: CertificatePayload, + must_issue_new_ticket: bool, +} + +impl State for ExpectCertificateStatusOrServerKx { + fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + match m.payload { + MessagePayload::Handshake { + parsed: + HandshakeMessagePayload { + payload: HandshakePayload::ServerKeyExchange(..), + .. + }, + .. + } => Box::new(ExpectServerKx { + config: self.config, + resuming_session: self.resuming_session, + session_id: self.session_id, + server_name: self.server_name, + randoms: self.randoms, + using_ems: self.using_ems, + transcript: self.transcript, + suite: self.suite, + server_cert: ServerCertDetails::new( + self.server_cert_chain, + vec![], + self.server_cert_sct_list, + ), + must_issue_new_ticket: self.must_issue_new_ticket, + }) + .handle(cx, m), + MessagePayload::Handshake { + parsed: + HandshakeMessagePayload { + payload: HandshakePayload::CertificateStatus(..), + .. + }, + .. + } => Box::new(ExpectCertificateStatus { + config: self.config, + resuming_session: self.resuming_session, + session_id: self.session_id, + server_name: self.server_name, + randoms: self.randoms, + using_ems: self.using_ems, + transcript: self.transcript, + suite: self.suite, + server_cert_sct_list: self.server_cert_sct_list, + server_cert_chain: self.server_cert_chain, + must_issue_new_ticket: self.must_issue_new_ticket, + }) + .handle(cx, m), + payload => Err(inappropriate_handshake_message( + &payload, + &[ContentType::Handshake], + &[ + HandshakeType::ServerKeyExchange, + HandshakeType::CertificateStatus, + ], + )), + } + } +} + +struct ExpectCertificateStatus { + config: Arc, + resuming_session: Option, + session_id: SessionId, + server_name: ServerName, + randoms: ConnectionRandoms, + using_ems: bool, + transcript: HandshakeHash, + suite: &'static Tls12CipherSuite, + server_cert_sct_list: Option>, + server_cert_chain: CertificatePayload, + must_issue_new_ticket: bool, +} + +impl State for ExpectCertificateStatus { + fn handle( + mut self: Box, + _cx: &mut ClientContext<'_>, + m: Message, + ) -> hs::NextStateOrError { + self.transcript.add_message(&m); + let server_cert_ocsp_response = require_handshake_msg_move!( + m, + HandshakeType::CertificateStatus, + HandshakePayload::CertificateStatus + )? + .into_inner(); + + trace!( + "Server stapled OCSP response is {:?}", + &server_cert_ocsp_response + ); + + let server_cert = ServerCertDetails::new( + self.server_cert_chain, + server_cert_ocsp_response, + self.server_cert_sct_list, + ); + + Ok(Box::new(ExpectServerKx { + config: self.config, + resuming_session: self.resuming_session, + session_id: self.session_id, + server_name: self.server_name, + randoms: self.randoms, + using_ems: self.using_ems, + transcript: self.transcript, + suite: self.suite, + server_cert, + must_issue_new_ticket: self.must_issue_new_ticket, + })) + } +} + +struct ExpectServerKx { + config: Arc, + resuming_session: Option, + session_id: SessionId, + server_name: ServerName, + randoms: ConnectionRandoms, + using_ems: bool, + transcript: HandshakeHash, + suite: &'static Tls12CipherSuite, + server_cert: ServerCertDetails, + must_issue_new_ticket: bool, +} + +impl State for ExpectServerKx { + fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + let opaque_kx = require_handshake_msg!( + m, + HandshakeType::ServerKeyExchange, + HandshakePayload::ServerKeyExchange + )?; + self.transcript.add_message(&m); + + let ecdhe = opaque_kx + .unwrap_given_kxa(self.suite.kx) + .ok_or_else(|| { + cx.common.send_fatal_alert( + AlertDescription::DecodeError, + InvalidMessage::MissingKeyExchange, + ) + })?; + + // Save the signature and signed parameters for later verification. + let mut kx_params = Vec::new(); + ecdhe.params.encode(&mut kx_params); + let server_kx = ServerKxDetails::new(kx_params, ecdhe.dss); + + #[cfg_attr(not(feature = "logging"), allow(unused_variables))] + { + debug!("ECDHE curve is {:?}", ecdhe.params.curve_params); + } + + Ok(Box::new(ExpectServerDoneOrCertReq { + config: self.config, + resuming_session: self.resuming_session, + session_id: self.session_id, + server_name: self.server_name, + randoms: self.randoms, + using_ems: self.using_ems, + transcript: self.transcript, + suite: self.suite, + server_cert: self.server_cert, + server_kx, + must_issue_new_ticket: self.must_issue_new_ticket, + })) + } +} + +fn emit_certificate( + transcript: &mut HandshakeHash, + cert_chain: CertificatePayload, + common: &mut CommonState, +) { + let cert = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::Certificate, + payload: HandshakePayload::Certificate(cert_chain), + }), + }; + + transcript.add_message(&cert); + common.send_msg(cert, false); +} + +fn emit_clientkx(transcript: &mut HandshakeHash, common: &mut CommonState, pubkey: &PublicKey) { + let mut buf = Vec::new(); + let ecpoint = PayloadU8::new(Vec::from(pubkey.as_ref())); + ecpoint.encode(&mut buf); + let pubkey = Payload::new(buf); + + let ckx = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::ClientKeyExchange, + payload: HandshakePayload::ClientKeyExchange(pubkey), + }), + }; + + transcript.add_message(&ckx); + common.send_msg(ckx, false); +} + +fn emit_certverify( + transcript: &mut HandshakeHash, + signer: &dyn Signer, + common: &mut CommonState, +) -> Result<(), Error> { + let message = transcript + .take_handshake_buf() + .ok_or_else(|| Error::General("Expected transcript".to_owned()))?; + + let scheme = signer.scheme(); + let sig = signer.sign(&message)?; + let body = DigitallySignedStruct::new(scheme, sig); + + let m = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::CertificateVerify, + payload: HandshakePayload::CertificateVerify(body), + }), + }; + + transcript.add_message(&m); + common.send_msg(m, false); + Ok(()) +} + +fn emit_ccs(common: &mut CommonState) { + let ccs = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}), + }; + + common.send_msg(ccs, false); +} + +fn emit_finished( + secrets: &ConnectionSecrets, + transcript: &mut HandshakeHash, + common: &mut CommonState, +) { + let vh = transcript.get_current_hash(); + let verify_data = secrets.client_verify_data(&vh); + let verify_data_payload = Payload::new(verify_data); + + let f = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::Finished, + payload: HandshakePayload::Finished(verify_data_payload), + }), + }; + + transcript.add_message(&f); + common.send_msg(f, true); +} + +struct ServerKxDetails { + kx_params: Vec, + kx_sig: DigitallySignedStruct, +} + +impl ServerKxDetails { + fn new(params: Vec, sig: DigitallySignedStruct) -> Self { + Self { + kx_params: params, + kx_sig: sig, + } + } +} + +// --- Either a CertificateRequest, or a ServerHelloDone. --- +// Existence of the CertificateRequest tells us the server is asking for +// client auth. Otherwise we go straight to ServerHelloDone. +struct ExpectServerDoneOrCertReq { + config: Arc, + resuming_session: Option, + session_id: SessionId, + server_name: ServerName, + randoms: ConnectionRandoms, + using_ems: bool, + transcript: HandshakeHash, + suite: &'static Tls12CipherSuite, + server_cert: ServerCertDetails, + server_kx: ServerKxDetails, + must_issue_new_ticket: bool, +} + +impl State for ExpectServerDoneOrCertReq { + fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + if matches!( + m.payload, + MessagePayload::Handshake { + parsed: HandshakeMessagePayload { + payload: HandshakePayload::CertificateRequest(_), + .. + }, + .. + } + ) { + Box::new(ExpectCertificateRequest { + config: self.config, + resuming_session: self.resuming_session, + session_id: self.session_id, + server_name: self.server_name, + randoms: self.randoms, + using_ems: self.using_ems, + transcript: self.transcript, + suite: self.suite, + server_cert: self.server_cert, + server_kx: self.server_kx, + must_issue_new_ticket: self.must_issue_new_ticket, + }) + .handle(cx, m) + } else { + self.transcript.abandon_client_auth(); + + Box::new(ExpectServerDone { + config: self.config, + resuming_session: self.resuming_session, + session_id: self.session_id, + server_name: self.server_name, + randoms: self.randoms, + using_ems: self.using_ems, + transcript: self.transcript, + suite: self.suite, + server_cert: self.server_cert, + server_kx: self.server_kx, + client_auth: None, + must_issue_new_ticket: self.must_issue_new_ticket, + }) + .handle(cx, m) + } + } +} + +struct ExpectCertificateRequest { + config: Arc, + resuming_session: Option, + session_id: SessionId, + server_name: ServerName, + randoms: ConnectionRandoms, + using_ems: bool, + transcript: HandshakeHash, + suite: &'static Tls12CipherSuite, + server_cert: ServerCertDetails, + server_kx: ServerKxDetails, + must_issue_new_ticket: bool, +} + +impl State for ExpectCertificateRequest { + fn handle( + mut self: Box, + _cx: &mut ClientContext<'_>, + m: Message, + ) -> hs::NextStateOrError { + let certreq = require_handshake_msg!( + m, + HandshakeType::CertificateRequest, + HandshakePayload::CertificateRequest + )?; + self.transcript.add_message(&m); + debug!("Got CertificateRequest {:?}", certreq); + + // The RFC jovially describes the design here as 'somewhat complicated' + // and 'somewhat underspecified'. So thanks for that. + // + // We ignore certreq.certtypes as a result, since the information it contains + // is entirely duplicated in certreq.sigschemes. + + const NO_CONTEXT: Option> = None; // TLS 1.2 doesn't use a context. + let client_auth = ClientAuthDetails::resolve( + self.config + .client_auth_cert_resolver + .as_ref(), + Some(&certreq.canames), + &certreq.sigschemes, + NO_CONTEXT, + ); + + Ok(Box::new(ExpectServerDone { + config: self.config, + resuming_session: self.resuming_session, + session_id: self.session_id, + server_name: self.server_name, + randoms: self.randoms, + using_ems: self.using_ems, + transcript: self.transcript, + suite: self.suite, + server_cert: self.server_cert, + server_kx: self.server_kx, + client_auth: Some(client_auth), + must_issue_new_ticket: self.must_issue_new_ticket, + })) + } +} + +struct ExpectServerDone { + config: Arc, + resuming_session: Option, + session_id: SessionId, + server_name: ServerName, + randoms: ConnectionRandoms, + using_ems: bool, + transcript: HandshakeHash, + suite: &'static Tls12CipherSuite, + server_cert: ServerCertDetails, + server_kx: ServerKxDetails, + client_auth: Option, + must_issue_new_ticket: bool, +} + +impl State for ExpectServerDone { + fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + match m.payload { + MessagePayload::Handshake { + parsed: + HandshakeMessagePayload { + payload: HandshakePayload::ServerHelloDone, + .. + }, + .. + } => {} + payload => { + return Err(inappropriate_handshake_message( + &payload, + &[ContentType::Handshake], + &[HandshakeType::ServerHelloDone], + )); + } + } + + let mut st = *self; + st.transcript.add_message(&m); + + cx.common.check_aligned_handshake()?; + + trace!("Server cert is {:?}", st.server_cert.cert_chain); + debug!("Server DNS name is {:?}", st.server_name); + + let suite = st.suite; + + // 1. Verify the cert chain. + // 2. Verify any SCTs provided with the certificate. + // 3. Verify that the top certificate signed their kx. + // 4. If doing client auth, send our Certificate. + // 5. Complete the key exchange: + // a) generate our kx pair + // b) emit a ClientKeyExchange containing it + // c) if doing client auth, emit a CertificateVerify + // d) emit a CCS + // e) derive the shared keys, and start encryption + // 6. emit a Finished, our first encrypted message under the new keys. + + // 1. + let (end_entity, intermediates) = st + .server_cert + .cert_chain + .split_first() + .ok_or(Error::NoCertificatesPresented)?; + let now = std::time::SystemTime::now(); + let cert_verified = st + .config + .verifier + .verify_server_cert( + end_entity, + intermediates, + &st.server_name, + &mut st.server_cert.scts(), + &st.server_cert.ocsp_response, + now, + ) + .map_err(|err| { + cx.common + .send_cert_verify_error_alert(err) + })?; + + // 3. + // Build up the contents of the signed message. + // It's ClientHello.random || ServerHello.random || ServerKeyExchange.params + let sig_verified = { + let mut message = Vec::new(); + message.extend_from_slice(&st.randoms.client); + message.extend_from_slice(&st.randoms.server); + message.extend_from_slice(&st.server_kx.kx_params); + + // Check the signature is compatible with the ciphersuite. + let sig = &st.server_kx.kx_sig; + if !SupportedCipherSuite::from(suite).usable_for_signature_algorithm(sig.scheme.sign()) + { + warn!( + "peer signed kx with wrong algorithm (got {:?} expect {:?})", + sig.scheme.sign(), + suite.sign + ); + return Err(PeerMisbehaved::SignedKxWithWrongAlgorithm.into()); + } + + st.config + .verifier + .verify_tls12_signature(&message, &st.server_cert.cert_chain[0], sig) + .map_err(|err| { + cx.common + .send_cert_verify_error_alert(err) + })? + }; + cx.common.peer_certificates = Some(st.server_cert.cert_chain); + + // 4. + if let Some(client_auth) = &st.client_auth { + let certs = match client_auth { + ClientAuthDetails::Empty { .. } => Vec::new(), + ClientAuthDetails::Verify { certkey, .. } => certkey.cert.clone(), + }; + emit_certificate(&mut st.transcript, certs, cx.common); + } + + // 5a. + let ecdh_params = + tls12::decode_ecdh_params::(cx.common, &st.server_kx.kx_params)?; + let group = + kx::KeyExchange::choose(ecdh_params.curve_params.named_group, &st.config.kx_groups) + .ok_or(Error::PeerMisbehaved( + PeerMisbehaved::SelectedUnofferedKxGroup, + ))?; + let kx = kx::KeyExchange::start(group).ok_or(Error::FailedToGetRandomBytes)?; + + // 5b. + let mut transcript = st.transcript; + emit_clientkx(&mut transcript, cx.common, &kx.pubkey); + // nb. EMS handshake hash only runs up to ClientKeyExchange. + let ems_seed = st + .using_ems + .then(|| transcript.get_current_hash()); + + // 5c. + if let Some(ClientAuthDetails::Verify { signer, .. }) = &st.client_auth { + emit_certverify(&mut transcript, signer.as_ref(), cx.common)?; + } + + // 5d. + emit_ccs(cx.common); + + // 5e. Now commit secrets. + let secrets = ConnectionSecrets::from_key_exchange( + kx, + &ecdh_params.public.0, + ems_seed, + st.randoms, + suite, + )?; + + st.config.key_log.log( + "CLIENT_RANDOM", + &secrets.randoms.client, + &secrets.master_secret, + ); + cx.common + .start_encryption_tls12(&secrets, Side::Client); + cx.common + .record_layer + .start_encrypting(); + + // 6. + emit_finished(&secrets, &mut transcript, cx.common); + + if st.must_issue_new_ticket { + Ok(Box::new(ExpectNewTicket { + config: st.config, + secrets, + resuming_session: st.resuming_session, + session_id: st.session_id, + server_name: st.server_name, + using_ems: st.using_ems, + transcript, + resuming: false, + cert_verified, + sig_verified, + })) + } else { + Ok(Box::new(ExpectCcs { + config: st.config, + secrets, + resuming_session: st.resuming_session, + session_id: st.session_id, + server_name: st.server_name, + using_ems: st.using_ems, + transcript, + ticket: None, + resuming: false, + cert_verified, + sig_verified, + })) + } + } +} + +struct ExpectNewTicket { + config: Arc, + secrets: ConnectionSecrets, + resuming_session: Option, + session_id: SessionId, + server_name: ServerName, + using_ems: bool, + transcript: HandshakeHash, + resuming: bool, + cert_verified: verify::ServerCertVerified, + sig_verified: verify::HandshakeSignatureValid, +} + +impl State for ExpectNewTicket { + fn handle( + mut self: Box, + _cx: &mut ClientContext<'_>, + m: Message, + ) -> hs::NextStateOrError { + self.transcript.add_message(&m); + + let nst = require_handshake_msg_move!( + m, + HandshakeType::NewSessionTicket, + HandshakePayload::NewSessionTicket + )?; + + Ok(Box::new(ExpectCcs { + config: self.config, + secrets: self.secrets, + resuming_session: self.resuming_session, + session_id: self.session_id, + server_name: self.server_name, + using_ems: self.using_ems, + transcript: self.transcript, + ticket: Some(nst), + resuming: self.resuming, + cert_verified: self.cert_verified, + sig_verified: self.sig_verified, + })) + } +} + +// -- Waiting for their CCS -- +struct ExpectCcs { + config: Arc, + secrets: ConnectionSecrets, + resuming_session: Option, + session_id: SessionId, + server_name: ServerName, + using_ems: bool, + transcript: HandshakeHash, + ticket: Option, + resuming: bool, + cert_verified: verify::ServerCertVerified, + sig_verified: verify::HandshakeSignatureValid, +} + +impl State for ExpectCcs { + fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + match m.payload { + MessagePayload::ChangeCipherSpec(..) => {} + payload => { + return Err(inappropriate_message( + &payload, + &[ContentType::ChangeCipherSpec], + )); + } + } + // CCS should not be received interleaved with fragmented handshake-level + // message. + cx.common.check_aligned_handshake()?; + + // nb. msgs layer validates trivial contents of CCS + cx.common + .record_layer + .start_decrypting(); + + Ok(Box::new(ExpectFinished { + config: self.config, + secrets: self.secrets, + resuming_session: self.resuming_session, + session_id: self.session_id, + server_name: self.server_name, + using_ems: self.using_ems, + transcript: self.transcript, + ticket: self.ticket, + resuming: self.resuming, + cert_verified: self.cert_verified, + sig_verified: self.sig_verified, + })) + } +} + +struct ExpectFinished { + config: Arc, + resuming_session: Option, + session_id: SessionId, + server_name: ServerName, + using_ems: bool, + transcript: HandshakeHash, + ticket: Option, + secrets: ConnectionSecrets, + resuming: bool, + cert_verified: verify::ServerCertVerified, + sig_verified: verify::HandshakeSignatureValid, +} + +impl ExpectFinished { + // -- Waiting for their finished -- + fn save_session(&mut self, cx: &ClientContext<'_>) { + // Save a ticket. If we got a new ticket, save that. Otherwise, save the + // original ticket again. + let (mut ticket, lifetime) = match self.ticket.take() { + Some(nst) => (nst.ticket.0, nst.lifetime_hint), + None => (Vec::new(), 0), + }; + + if ticket.is_empty() { + if let Some(resuming_session) = &mut self.resuming_session { + ticket = resuming_session.take_ticket(); + } + } + + if self.session_id.is_empty() && ticket.is_empty() { + debug!("Session not saved: server didn't allocate id or ticket"); + return; + } + + let time_now = match TimeBase::now() { + Ok(time_now) => time_now, + #[allow(unused_variables)] + Err(e) => { + debug!("Session not saved: {}", e); + return; + } + }; + + let session_value = persist::Tls12ClientSessionValue::new( + self.secrets.suite(), + self.session_id, + ticket, + self.secrets.get_master_secret(), + cx.common + .peer_certificates + .clone() + .unwrap_or_default(), + time_now, + lifetime, + self.using_ems, + ); + + self.config + .resumption + .store + .set_tls12_session(&self.server_name, session_value); + } +} + +impl State for ExpectFinished { + fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + let mut st = *self; + let finished = + require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; + + cx.common.check_aligned_handshake()?; + + // Work out what verify_data we expect. + let vh = st.transcript.get_current_hash(); + let expect_verify_data = st.secrets.server_verify_data(&vh); + + // Constant-time verification of this is relatively unimportant: they only + // get one chance. But it can't hurt. + let _fin_verified = + constant_time::verify_slices_are_equal(&expect_verify_data, &finished.0) + .map_err(|_| { + cx.common + .send_fatal_alert(AlertDescription::DecryptError, Error::DecryptError) + }) + .map(|_| verify::FinishedMessageVerified::assertion())?; + + // Hash this message too. + st.transcript.add_message(&m); + + st.save_session(cx); + + if st.resuming { + emit_ccs(cx.common); + cx.common + .record_layer + .start_encrypting(); + emit_finished(&st.secrets, &mut st.transcript, cx.common); + } + + cx.common.start_traffic(); + Ok(Box::new(ExpectTraffic { + secrets: st.secrets, + _cert_verified: st.cert_verified, + _sig_verified: st.sig_verified, + _fin_verified, + })) + } +} + +// -- Traffic transit state -- +struct ExpectTraffic { + secrets: ConnectionSecrets, + _cert_verified: verify::ServerCertVerified, + _sig_verified: verify::HandshakeSignatureValid, + _fin_verified: verify::FinishedMessageVerified, +} + +impl State for ExpectTraffic { + fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + match m.payload { + MessagePayload::ApplicationData(payload) => cx + .common + .take_received_plaintext(payload), + payload => { + return Err(inappropriate_message( + &payload, + &[ContentType::ApplicationData], + )); + } + } + Ok(self) + } + + fn export_keying_material( + &self, + output: &mut [u8], + label: &[u8], + context: Option<&[u8]>, + ) -> Result<(), Error> { + self.secrets + .export_keying_material(output, label, context); + Ok(()) + } + + #[cfg(feature = "secret_extraction")] + fn extract_secrets(&self) -> Result { + self.secrets + .extract_secrets(Side::Client) + } +} diff --git a/vendor/rustls-0.21.8/src/client/tls13.rs b/vendor/rustls-0.21.8/src/client/tls13.rs new file mode 100644 index 0000000000000..2d9674585602d --- /dev/null +++ b/vendor/rustls-0.21.8/src/client/tls13.rs @@ -0,0 +1,1121 @@ +use crate::check::inappropriate_handshake_message; +#[cfg(feature = "quic")] +use crate::common_state::Protocol; +#[cfg(feature = "secret_extraction")] +use crate::common_state::Side; +use crate::common_state::{CommonState, State}; +use crate::conn::ConnectionRandoms; +use crate::enums::{ + AlertDescription, ContentType, HandshakeType, ProtocolVersion, SignatureScheme, +}; +use crate::error::{Error, InvalidMessage, PeerIncompatible, PeerMisbehaved}; +use crate::hash_hs::{HandshakeHash, HandshakeHashBuffer}; +use crate::kx; +#[cfg(feature = "logging")] +use crate::log::{debug, trace, warn}; +use crate::msgs::base::{Payload, PayloadU8}; +use crate::msgs::ccs::ChangeCipherSpecPayload; +use crate::msgs::enums::ExtensionType; +use crate::msgs::enums::KeyUpdateRequest; +use crate::msgs::handshake::NewSessionTicketPayloadTLS13; +use crate::msgs::handshake::{CertificateEntry, CertificatePayloadTLS13}; +use crate::msgs::handshake::{ClientExtension, ServerExtension}; +use crate::msgs::handshake::{HandshakeMessagePayload, HandshakePayload}; +use crate::msgs::handshake::{HasServerExtensions, ServerHelloPayload}; +use crate::msgs::handshake::{PresharedKeyIdentity, PresharedKeyOffer}; +use crate::msgs::message::{Message, MessagePayload}; +use crate::msgs::persist; +#[cfg(feature = "secret_extraction")] +use crate::suites::PartiallyExtractedSecrets; +use crate::tls13::key_schedule::{ + KeyScheduleEarly, KeyScheduleHandshake, KeySchedulePreHandshake, KeyScheduleTraffic, +}; +use crate::tls13::Tls13CipherSuite; +use crate::verify::{self, DigitallySignedStruct}; +use crate::{sign, KeyLog}; + +use super::client_conn::ClientConnectionData; +use super::hs::ClientContext; +use crate::client::common::ServerCertDetails; +use crate::client::common::{ClientAuthDetails, ClientHelloDetails}; +use crate::client::{hs, ClientConfig, ClientSessionStore, ServerName}; + +use crate::ticketer::TimeBase; +use ring::constant_time; + +use crate::sign::{CertifiedKey, Signer}; +use std::sync::Arc; + +// Extensions we expect in plaintext in the ServerHello. +static ALLOWED_PLAINTEXT_EXTS: &[ExtensionType] = &[ + ExtensionType::KeyShare, + ExtensionType::PreSharedKey, + ExtensionType::SupportedVersions, +]; + +// Only the intersection of things we offer, and those disallowed +// in TLS1.3 +static DISALLOWED_TLS13_EXTS: &[ExtensionType] = &[ + ExtensionType::ECPointFormats, + ExtensionType::SessionTicket, + ExtensionType::RenegotiationInfo, + ExtensionType::ExtendedMasterSecret, +]; + +pub(super) fn handle_server_hello( + config: Arc, + cx: &mut ClientContext, + server_hello: &ServerHelloPayload, + mut resuming_session: Option, + server_name: ServerName, + randoms: ConnectionRandoms, + suite: &'static Tls13CipherSuite, + transcript: HandshakeHash, + early_key_schedule: Option, + hello: ClientHelloDetails, + our_key_share: kx::KeyExchange, + mut sent_tls13_fake_ccs: bool, +) -> hs::NextStateOrError { + validate_server_hello(cx.common, server_hello)?; + + let their_key_share = server_hello + .get_key_share() + .ok_or_else(|| { + cx.common.send_fatal_alert( + AlertDescription::MissingExtension, + PeerMisbehaved::MissingKeyShare, + ) + })?; + + if our_key_share.group() != their_key_share.group { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::WrongGroupForKeyShare, + ) + }); + } + + let key_schedule_pre_handshake = if let (Some(selected_psk), Some(early_key_schedule)) = + (server_hello.get_psk_index(), early_key_schedule) + { + if let Some(ref resuming) = resuming_session { + let resuming_suite = match suite.can_resume_from(resuming.suite()) { + Some(resuming) => resuming, + None => { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::ResumptionOfferedWithIncompatibleCipherSuite, + ) + }); + } + }; + + // If the server varies the suite here, we will have encrypted early data with + // the wrong suite. + if cx.data.early_data.is_enabled() && resuming_suite != suite { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::EarlyDataOfferedWithVariedCipherSuite, + ) + }); + } + + if selected_psk != 0 { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::SelectedInvalidPsk, + ) + }); + } + + debug!("Resuming using PSK"); + // The key schedule has been initialized and set in fill_in_psk_binder() + } else { + return Err(PeerMisbehaved::SelectedUnofferedPsk.into()); + } + KeySchedulePreHandshake::from(early_key_schedule) + } else { + debug!("Not resuming"); + // Discard the early data key schedule. + cx.data.early_data.rejected(); + cx.common.early_traffic = false; + resuming_session.take(); + KeySchedulePreHandshake::new(suite) + }; + + let key_schedule = our_key_share.complete(&their_key_share.payload.0, |secret| { + key_schedule_pre_handshake.into_handshake(secret) + })?; + + // Remember what KX group the server liked for next time. + config + .resumption + .store + .set_kx_hint(&server_name, their_key_share.group); + + // If we change keying when a subsequent handshake message is being joined, + // the two halves will have different record layer protections. Disallow this. + cx.common.check_aligned_handshake()?; + + let hash_at_client_recvd_server_hello = transcript.get_current_hash(); + let key_schedule = key_schedule.derive_client_handshake_secrets( + cx.data.early_data.is_enabled(), + hash_at_client_recvd_server_hello, + suite, + &*config.key_log, + &randoms.client, + cx.common, + ); + + emit_fake_ccs(&mut sent_tls13_fake_ccs, cx.common); + + Ok(Box::new(ExpectEncryptedExtensions { + config, + resuming_session, + server_name, + randoms, + suite, + transcript, + key_schedule, + hello, + })) +} + +fn validate_server_hello( + common: &mut CommonState, + server_hello: &ServerHelloPayload, +) -> Result<(), Error> { + for ext in &server_hello.extensions { + if !ALLOWED_PLAINTEXT_EXTS.contains(&ext.get_type()) { + return Err(common.send_fatal_alert( + AlertDescription::UnsupportedExtension, + PeerMisbehaved::UnexpectedCleartextExtension, + )); + } + } + + Ok(()) +} + +pub(super) fn initial_key_share( + config: &ClientConfig, + server_name: &ServerName, +) -> Result { + let group = config + .resumption + .store + .kx_hint(server_name) + .and_then(|group| kx::KeyExchange::choose(group, &config.kx_groups)) + .unwrap_or_else(|| { + config + .kx_groups + .first() + .expect("No kx groups configured") + }); + + kx::KeyExchange::start(group).ok_or(Error::FailedToGetRandomBytes) +} + +/// This implements the horrifying TLS1.3 hack where PSK binders have a +/// data dependency on the message they are contained within. +pub(super) fn fill_in_psk_binder( + resuming: &persist::Tls13ClientSessionValue, + transcript: &HandshakeHashBuffer, + hmp: &mut HandshakeMessagePayload, +) -> KeyScheduleEarly { + // We need to know the hash function of the suite we're trying to resume into. + let suite = resuming.suite(); + let suite_hash = suite.hash_algorithm(); + + // The binder is calculated over the clienthello, but doesn't include itself or its + // length, or the length of its container. + let binder_plaintext = hmp.get_encoding_for_binder_signing(); + let handshake_hash = transcript.get_hash_given(suite_hash, &binder_plaintext); + + // Run a fake key_schedule to simulate what the server will do if it chooses + // to resume. + let key_schedule = KeyScheduleEarly::new(suite, resuming.secret()); + let real_binder = key_schedule.resumption_psk_binder_key_and_sign_verify_data(&handshake_hash); + + if let HandshakePayload::ClientHello(ref mut ch) = hmp.payload { + ch.set_psk_binder(real_binder.as_ref()); + }; + + key_schedule +} + +pub(super) fn prepare_resumption( + config: &ClientConfig, + cx: &mut ClientContext<'_>, + resuming_session: &persist::Retrieved<&persist::Tls13ClientSessionValue>, + exts: &mut Vec, + doing_retry: bool, +) { + let resuming_suite = resuming_session.suite(); + cx.common.suite = Some(resuming_suite.into()); + cx.data.resumption_ciphersuite = Some(resuming_suite.into()); + // The EarlyData extension MUST be supplied together with the + // PreSharedKey extension. + let max_early_data_size = resuming_session.max_early_data_size(); + if config.enable_early_data && max_early_data_size > 0 && !doing_retry { + cx.data + .early_data + .enable(max_early_data_size as usize); + exts.push(ClientExtension::EarlyData); + } + + // Finally, and only for TLS1.3 with a ticket resumption, include a binder + // for our ticket. This must go last. + // + // Include an empty binder. It gets filled in below because it depends on + // the message it's contained in (!!!). + let obfuscated_ticket_age = resuming_session.obfuscated_ticket_age(); + + let binder_len = resuming_suite + .hash_algorithm() + .output_len(); + let binder = vec![0u8; binder_len]; + + let psk_identity = + PresharedKeyIdentity::new(resuming_session.ticket().to_vec(), obfuscated_ticket_age); + let psk_ext = PresharedKeyOffer::new(psk_identity, binder); + exts.push(ClientExtension::PresharedKey(psk_ext)); +} + +pub(super) fn derive_early_traffic_secret( + key_log: &dyn KeyLog, + cx: &mut ClientContext<'_>, + resuming_suite: &'static Tls13CipherSuite, + early_key_schedule: &KeyScheduleEarly, + sent_tls13_fake_ccs: &mut bool, + transcript_buffer: &HandshakeHashBuffer, + client_random: &[u8; 32], +) { + // For middlebox compatibility + emit_fake_ccs(sent_tls13_fake_ccs, cx.common); + + let client_hello_hash = transcript_buffer.get_hash_given(resuming_suite.hash_algorithm(), &[]); + early_key_schedule.client_early_traffic_secret( + &client_hello_hash, + key_log, + client_random, + cx.common, + ); + + // Now the client can send encrypted early data + cx.common.early_traffic = true; + trace!("Starting early data traffic"); +} + +pub(super) fn emit_fake_ccs(sent_tls13_fake_ccs: &mut bool, common: &mut CommonState) { + if common.is_quic() { + return; + } + + if std::mem::replace(sent_tls13_fake_ccs, true) { + return; + } + + let m = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}), + }; + common.send_msg(m, false); +} + +fn validate_encrypted_extensions( + common: &mut CommonState, + hello: &ClientHelloDetails, + exts: &Vec, +) -> Result<(), Error> { + if exts.has_duplicate_extension() { + return Err(common.send_fatal_alert( + AlertDescription::DecodeError, + PeerMisbehaved::DuplicateEncryptedExtensions, + )); + } + + if hello.server_sent_unsolicited_extensions(exts, &[]) { + return Err(common.send_fatal_alert( + AlertDescription::UnsupportedExtension, + PeerMisbehaved::UnsolicitedEncryptedExtension, + )); + } + + for ext in exts { + if ALLOWED_PLAINTEXT_EXTS.contains(&ext.get_type()) + || DISALLOWED_TLS13_EXTS.contains(&ext.get_type()) + { + return Err(common.send_fatal_alert( + AlertDescription::UnsupportedExtension, + PeerMisbehaved::DisallowedEncryptedExtension, + )); + } + } + + Ok(()) +} + +struct ExpectEncryptedExtensions { + config: Arc, + resuming_session: Option, + server_name: ServerName, + randoms: ConnectionRandoms, + suite: &'static Tls13CipherSuite, + transcript: HandshakeHash, + key_schedule: KeyScheduleHandshake, + hello: ClientHelloDetails, +} + +impl State for ExpectEncryptedExtensions { + fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + let exts = require_handshake_msg!( + m, + HandshakeType::EncryptedExtensions, + HandshakePayload::EncryptedExtensions + )?; + debug!("TLS1.3 encrypted extensions: {:?}", exts); + self.transcript.add_message(&m); + + validate_encrypted_extensions(cx.common, &self.hello, exts)?; + hs::process_alpn_protocol(cx.common, &self.config, exts.get_alpn_protocol())?; + + #[cfg(feature = "quic")] + { + // QUIC transport parameters + if cx.common.is_quic() { + match exts.get_quic_params_extension() { + Some(params) => cx.common.quic.params = Some(params), + None => { + return Err(cx + .common + .missing_extension(PeerMisbehaved::MissingQuicTransportParameters)); + } + } + } + } + + if let Some(resuming_session) = self.resuming_session { + let was_early_traffic = cx.common.early_traffic; + if was_early_traffic { + if exts.early_data_extension_offered() { + cx.data.early_data.accepted(); + } else { + cx.data.early_data.rejected(); + cx.common.early_traffic = false; + } + } + + if was_early_traffic && !cx.common.early_traffic { + // If no early traffic, set the encryption key for handshakes + self.key_schedule + .set_handshake_encrypter(cx.common); + } + + cx.common.peer_certificates = Some( + resuming_session + .server_cert_chain() + .to_vec(), + ); + + // We *don't* reverify the certificate chain here: resumption is a + // continuation of the previous session in terms of security policy. + let cert_verified = verify::ServerCertVerified::assertion(); + let sig_verified = verify::HandshakeSignatureValid::assertion(); + Ok(Box::new(ExpectFinished { + config: self.config, + server_name: self.server_name, + randoms: self.randoms, + suite: self.suite, + transcript: self.transcript, + key_schedule: self.key_schedule, + client_auth: None, + cert_verified, + sig_verified, + })) + } else { + if exts.early_data_extension_offered() { + return Err(PeerMisbehaved::EarlyDataExtensionWithoutResumption.into()); + } + Ok(Box::new(ExpectCertificateOrCertReq { + config: self.config, + server_name: self.server_name, + randoms: self.randoms, + suite: self.suite, + transcript: self.transcript, + key_schedule: self.key_schedule, + may_send_sct_list: self.hello.server_may_send_sct_list(), + })) + } + } +} + +struct ExpectCertificateOrCertReq { + config: Arc, + server_name: ServerName, + randoms: ConnectionRandoms, + suite: &'static Tls13CipherSuite, + transcript: HandshakeHash, + key_schedule: KeyScheduleHandshake, + may_send_sct_list: bool, +} + +impl State for ExpectCertificateOrCertReq { + fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + match m.payload { + MessagePayload::Handshake { + parsed: + HandshakeMessagePayload { + payload: HandshakePayload::CertificateTLS13(..), + .. + }, + .. + } => Box::new(ExpectCertificate { + config: self.config, + server_name: self.server_name, + randoms: self.randoms, + suite: self.suite, + transcript: self.transcript, + key_schedule: self.key_schedule, + may_send_sct_list: self.may_send_sct_list, + client_auth: None, + }) + .handle(cx, m), + MessagePayload::Handshake { + parsed: + HandshakeMessagePayload { + payload: HandshakePayload::CertificateRequestTLS13(..), + .. + }, + .. + } => Box::new(ExpectCertificateRequest { + config: self.config, + server_name: self.server_name, + randoms: self.randoms, + suite: self.suite, + transcript: self.transcript, + key_schedule: self.key_schedule, + may_send_sct_list: self.may_send_sct_list, + }) + .handle(cx, m), + payload => Err(inappropriate_handshake_message( + &payload, + &[ContentType::Handshake], + &[ + HandshakeType::Certificate, + HandshakeType::CertificateRequest, + ], + )), + } + } +} + +// TLS1.3 version of CertificateRequest handling. We then move to expecting the server +// Certificate. Unfortunately the CertificateRequest type changed in an annoying way +// in TLS1.3. +struct ExpectCertificateRequest { + config: Arc, + server_name: ServerName, + randoms: ConnectionRandoms, + suite: &'static Tls13CipherSuite, + transcript: HandshakeHash, + key_schedule: KeyScheduleHandshake, + may_send_sct_list: bool, +} + +impl State for ExpectCertificateRequest { + fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + let certreq = &require_handshake_msg!( + m, + HandshakeType::CertificateRequest, + HandshakePayload::CertificateRequestTLS13 + )?; + self.transcript.add_message(&m); + debug!("Got CertificateRequest {:?}", certreq); + + // Fortunately the problems here in TLS1.2 and prior are corrected in + // TLS1.3. + + // Must be empty during handshake. + if !certreq.context.0.is_empty() { + warn!("Server sent non-empty certreq context"); + return Err(cx.common.send_fatal_alert( + AlertDescription::DecodeError, + InvalidMessage::InvalidCertRequest, + )); + } + + let tls13_sign_schemes = sign::supported_sign_tls13(); + let no_sigschemes = Vec::new(); + let compat_sigschemes = certreq + .get_sigalgs_extension() + .unwrap_or(&no_sigschemes) + .iter() + .cloned() + .filter(|scheme| tls13_sign_schemes.contains(scheme)) + .collect::>(); + + if compat_sigschemes.is_empty() { + return Err(cx.common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerIncompatible::NoCertificateRequestSignatureSchemesInCommon, + )); + } + + let client_auth = ClientAuthDetails::resolve( + self.config + .client_auth_cert_resolver + .as_ref(), + certreq.get_authorities_extension(), + &compat_sigschemes, + Some(certreq.context.0.clone()), + ); + + Ok(Box::new(ExpectCertificate { + config: self.config, + server_name: self.server_name, + randoms: self.randoms, + suite: self.suite, + transcript: self.transcript, + key_schedule: self.key_schedule, + may_send_sct_list: self.may_send_sct_list, + client_auth: Some(client_auth), + })) + } +} + +struct ExpectCertificate { + config: Arc, + server_name: ServerName, + randoms: ConnectionRandoms, + suite: &'static Tls13CipherSuite, + transcript: HandshakeHash, + key_schedule: KeyScheduleHandshake, + may_send_sct_list: bool, + client_auth: Option, +} + +impl State for ExpectCertificate { + fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + let cert_chain = require_handshake_msg!( + m, + HandshakeType::Certificate, + HandshakePayload::CertificateTLS13 + )?; + self.transcript.add_message(&m); + + // This is only non-empty for client auth. + if !cert_chain.context.0.is_empty() { + return Err(cx.common.send_fatal_alert( + AlertDescription::DecodeError, + InvalidMessage::InvalidCertRequest, + )); + } + + if cert_chain.any_entry_has_duplicate_extension() + || cert_chain.any_entry_has_unknown_extension() + { + return Err(cx.common.send_fatal_alert( + AlertDescription::UnsupportedExtension, + PeerMisbehaved::BadCertChainExtensions, + )); + } + + let server_cert = ServerCertDetails::new( + cert_chain.convert(), + cert_chain.get_end_entity_ocsp(), + cert_chain + .get_end_entity_scts() + .map(|scts| scts.to_vec()), + ); + + if let Some(sct_list) = server_cert.scts.as_ref() { + if hs::sct_list_is_invalid(sct_list) { + return Err(PeerMisbehaved::InvalidSctList.into()); + } + + if !self.may_send_sct_list { + return Err(PeerMisbehaved::UnsolicitedSctList.into()); + } + } + + Ok(Box::new(ExpectCertificateVerify { + config: self.config, + server_name: self.server_name, + randoms: self.randoms, + suite: self.suite, + transcript: self.transcript, + key_schedule: self.key_schedule, + server_cert, + client_auth: self.client_auth, + })) + } +} + +// --- TLS1.3 CertificateVerify --- +struct ExpectCertificateVerify { + config: Arc, + server_name: ServerName, + randoms: ConnectionRandoms, + suite: &'static Tls13CipherSuite, + transcript: HandshakeHash, + key_schedule: KeyScheduleHandshake, + server_cert: ServerCertDetails, + client_auth: Option, +} + +impl State for ExpectCertificateVerify { + fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + let cert_verify = require_handshake_msg!( + m, + HandshakeType::CertificateVerify, + HandshakePayload::CertificateVerify + )?; + + trace!("Server cert is {:?}", self.server_cert.cert_chain); + + // 1. Verify the certificate chain. + let (end_entity, intermediates) = self + .server_cert + .cert_chain + .split_first() + .ok_or(Error::NoCertificatesPresented)?; + let now = std::time::SystemTime::now(); + let cert_verified = self + .config + .verifier + .verify_server_cert( + end_entity, + intermediates, + &self.server_name, + &mut self.server_cert.scts(), + &self.server_cert.ocsp_response, + now, + ) + .map_err(|err| { + cx.common + .send_cert_verify_error_alert(err) + })?; + + // 2. Verify their signature on the handshake. + let handshake_hash = self.transcript.get_current_hash(); + let sig_verified = self + .config + .verifier + .verify_tls13_signature( + &verify::construct_tls13_server_verify_message(&handshake_hash), + &self.server_cert.cert_chain[0], + cert_verify, + ) + .map_err(|err| { + cx.common + .send_cert_verify_error_alert(err) + })?; + + cx.common.peer_certificates = Some(self.server_cert.cert_chain); + self.transcript.add_message(&m); + + Ok(Box::new(ExpectFinished { + config: self.config, + server_name: self.server_name, + randoms: self.randoms, + suite: self.suite, + transcript: self.transcript, + key_schedule: self.key_schedule, + client_auth: self.client_auth, + cert_verified, + sig_verified, + })) + } +} + +fn emit_certificate_tls13( + transcript: &mut HandshakeHash, + certkey: Option<&CertifiedKey>, + auth_context: Option>, + common: &mut CommonState, +) { + let context = auth_context.unwrap_or_default(); + + let mut cert_payload = CertificatePayloadTLS13 { + context: PayloadU8::new(context), + entries: Vec::new(), + }; + + if let Some(certkey) = certkey { + for cert in &certkey.cert { + cert_payload + .entries + .push(CertificateEntry::new(cert.clone())); + } + } + + let m = Message { + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::Certificate, + payload: HandshakePayload::CertificateTLS13(cert_payload), + }), + }; + transcript.add_message(&m); + common.send_msg(m, true); +} + +fn emit_certverify_tls13( + transcript: &mut HandshakeHash, + signer: &dyn Signer, + common: &mut CommonState, +) -> Result<(), Error> { + let message = verify::construct_tls13_client_verify_message(&transcript.get_current_hash()); + + let scheme = signer.scheme(); + let sig = signer.sign(&message)?; + let dss = DigitallySignedStruct::new(scheme, sig); + + let m = Message { + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::CertificateVerify, + payload: HandshakePayload::CertificateVerify(dss), + }), + }; + + transcript.add_message(&m); + common.send_msg(m, true); + Ok(()) +} + +fn emit_finished_tls13( + transcript: &mut HandshakeHash, + verify_data: ring::hmac::Tag, + common: &mut CommonState, +) { + let verify_data_payload = Payload::new(verify_data.as_ref()); + + let m = Message { + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::Finished, + payload: HandshakePayload::Finished(verify_data_payload), + }), + }; + + transcript.add_message(&m); + common.send_msg(m, true); +} + +fn emit_end_of_early_data_tls13(transcript: &mut HandshakeHash, common: &mut CommonState) { + if common.is_quic() { + return; + } + + let m = Message { + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::EndOfEarlyData, + payload: HandshakePayload::EndOfEarlyData, + }), + }; + + transcript.add_message(&m); + common.send_msg(m, true); +} + +struct ExpectFinished { + config: Arc, + server_name: ServerName, + randoms: ConnectionRandoms, + suite: &'static Tls13CipherSuite, + transcript: HandshakeHash, + key_schedule: KeyScheduleHandshake, + client_auth: Option, + cert_verified: verify::ServerCertVerified, + sig_verified: verify::HandshakeSignatureValid, +} + +impl State for ExpectFinished { + fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + let mut st = *self; + let finished = + require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; + + let handshake_hash = st.transcript.get_current_hash(); + let expect_verify_data = st + .key_schedule + .sign_server_finish(&handshake_hash); + + let fin = constant_time::verify_slices_are_equal(expect_verify_data.as_ref(), &finished.0) + .map_err(|_| { + cx.common + .send_fatal_alert(AlertDescription::DecryptError, Error::DecryptError) + }) + .map(|_| verify::FinishedMessageVerified::assertion())?; + + st.transcript.add_message(&m); + + let hash_after_handshake = st.transcript.get_current_hash(); + /* The EndOfEarlyData message to server is still encrypted with early data keys, + * but appears in the transcript after the server Finished. */ + if cx.common.early_traffic { + emit_end_of_early_data_tls13(&mut st.transcript, cx.common); + cx.common.early_traffic = false; + cx.data.early_data.finished(); + st.key_schedule + .set_handshake_encrypter(cx.common); + } + + /* Send our authentication/finished messages. These are still encrypted + * with our handshake keys. */ + if let Some(client_auth) = st.client_auth { + match client_auth { + ClientAuthDetails::Empty { + auth_context_tls13: auth_context, + } => { + emit_certificate_tls13(&mut st.transcript, None, auth_context, cx.common); + } + ClientAuthDetails::Verify { + certkey, + signer, + auth_context_tls13: auth_context, + } => { + emit_certificate_tls13( + &mut st.transcript, + Some(&certkey), + auth_context, + cx.common, + ); + emit_certverify_tls13(&mut st.transcript, signer.as_ref(), cx.common)?; + } + } + } + + let (key_schedule_pre_finished, verify_data) = st + .key_schedule + .into_pre_finished_client_traffic( + hash_after_handshake, + st.transcript.get_current_hash(), + &*st.config.key_log, + &st.randoms.client, + ); + + emit_finished_tls13(&mut st.transcript, verify_data, cx.common); + + /* We're now sure this server supports TLS1.3. But if we run out of TLS1.3 tickets + * when connecting to it again, we definitely don't want to attempt a TLS1.2 resumption. */ + st.config + .resumption + .store + .remove_tls12_session(&st.server_name); + + /* Now move to our application traffic keys. */ + cx.common.check_aligned_handshake()?; + let key_schedule_traffic = key_schedule_pre_finished.into_traffic(cx.common); + cx.common.start_traffic(); + + let st = ExpectTraffic { + session_storage: Arc::clone(&st.config.resumption.store), + server_name: st.server_name, + suite: st.suite, + transcript: st.transcript, + key_schedule: key_schedule_traffic, + _cert_verified: st.cert_verified, + _sig_verified: st.sig_verified, + _fin_verified: fin, + }; + + #[cfg(feature = "quic")] + if cx.common.is_quic() { + return Ok(Box::new(ExpectQuicTraffic(st))); + } + + Ok(Box::new(st)) + } +} + +// -- Traffic transit state (TLS1.3) -- +// In this state we can be sent tickets, key updates, +// and application data. +struct ExpectTraffic { + session_storage: Arc, + server_name: ServerName, + suite: &'static Tls13CipherSuite, + transcript: HandshakeHash, + key_schedule: KeyScheduleTraffic, + _cert_verified: verify::ServerCertVerified, + _sig_verified: verify::HandshakeSignatureValid, + _fin_verified: verify::FinishedMessageVerified, +} + +impl ExpectTraffic { + #[allow(clippy::unnecessary_wraps)] // returns Err for #[cfg(feature = "quic")] + fn handle_new_ticket_tls13( + &mut self, + cx: &mut ClientContext<'_>, + nst: &NewSessionTicketPayloadTLS13, + ) -> Result<(), Error> { + if nst.has_duplicate_extension() { + return Err(cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::DuplicateNewSessionTicketExtensions, + )); + } + + let handshake_hash = self.transcript.get_current_hash(); + let secret = self + .key_schedule + .resumption_master_secret_and_derive_ticket_psk(&handshake_hash, &nst.nonce.0); + + let time_now = match TimeBase::now() { + Ok(t) => t, + #[allow(unused_variables)] + Err(e) => { + debug!("Session not saved: {}", e); + return Ok(()); + } + }; + + #[allow(unused_mut)] + let mut value = persist::Tls13ClientSessionValue::new( + self.suite, + nst.ticket.0.clone(), + secret, + cx.common + .peer_certificates + .clone() + .unwrap_or_default(), + time_now, + nst.lifetime, + nst.age_add, + nst.get_max_early_data_size() + .unwrap_or_default(), + ); + + #[cfg(feature = "quic")] + if cx.common.is_quic() { + if let Some(sz) = nst.get_max_early_data_size() { + if sz != 0 && sz != 0xffff_ffff { + return Err(PeerMisbehaved::InvalidMaxEarlyDataSize.into()); + } + } + + if let Some(ref quic_params) = &cx.common.quic.params { + value.set_quic_params(quic_params); + } + } + + self.session_storage + .insert_tls13_ticket(&self.server_name, value); + Ok(()) + } + + fn handle_key_update( + &mut self, + common: &mut CommonState, + key_update_request: &KeyUpdateRequest, + ) -> Result<(), Error> { + #[cfg(feature = "quic")] + { + if let Protocol::Quic = common.protocol { + return Err(common.send_fatal_alert( + AlertDescription::UnexpectedMessage, + PeerMisbehaved::KeyUpdateReceivedInQuicConnection, + )); + } + } + + // Mustn't be interleaved with other handshake messages. + common.check_aligned_handshake()?; + + if common.should_update_key(key_update_request)? { + self.key_schedule + .update_encrypter_and_notify(common); + } + + // Update our read-side keys. + self.key_schedule + .update_decrypter(common); + Ok(()) + } +} + +impl State for ExpectTraffic { + fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + match m.payload { + MessagePayload::ApplicationData(payload) => cx + .common + .take_received_plaintext(payload), + MessagePayload::Handshake { + parsed: + HandshakeMessagePayload { + payload: HandshakePayload::NewSessionTicketTLS13(ref new_ticket), + .. + }, + .. + } => self.handle_new_ticket_tls13(cx, new_ticket)?, + MessagePayload::Handshake { + parsed: + HandshakeMessagePayload { + payload: HandshakePayload::KeyUpdate(ref key_update), + .. + }, + .. + } => self.handle_key_update(cx.common, key_update)?, + payload => { + return Err(inappropriate_handshake_message( + &payload, + &[ContentType::ApplicationData, ContentType::Handshake], + &[HandshakeType::NewSessionTicket, HandshakeType::KeyUpdate], + )); + } + } + + Ok(self) + } + + fn export_keying_material( + &self, + output: &mut [u8], + label: &[u8], + context: Option<&[u8]>, + ) -> Result<(), Error> { + self.key_schedule + .export_keying_material(output, label, context) + } + + #[cfg(feature = "secret_extraction")] + fn extract_secrets(&self) -> Result { + self.key_schedule + .extract_secrets(Side::Client) + } +} + +#[cfg(feature = "quic")] +struct ExpectQuicTraffic(ExpectTraffic); + +#[cfg(feature = "quic")] +impl State for ExpectQuicTraffic { + fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { + let nst = require_handshake_msg!( + m, + HandshakeType::NewSessionTicket, + HandshakePayload::NewSessionTicketTLS13 + )?; + self.0 + .handle_new_ticket_tls13(cx, nst)?; + Ok(self) + } + + fn export_keying_material( + &self, + output: &mut [u8], + label: &[u8], + context: Option<&[u8]>, + ) -> Result<(), Error> { + self.0 + .export_keying_material(output, label, context) + } +} diff --git a/vendor/rustls-0.21.8/src/common_state.rs b/vendor/rustls-0.21.8/src/common_state.rs new file mode 100644 index 0000000000000..27ba9b68afb9f --- /dev/null +++ b/vendor/rustls-0.21.8/src/common_state.rs @@ -0,0 +1,683 @@ +use crate::enums::{AlertDescription, ContentType, HandshakeType, ProtocolVersion}; +use crate::error::{Error, InvalidMessage, PeerMisbehaved}; +use crate::key; +#[cfg(feature = "logging")] +use crate::log::{debug, warn}; +use crate::msgs::alert::AlertMessagePayload; +use crate::msgs::base::Payload; +use crate::msgs::enums::{AlertLevel, KeyUpdateRequest}; +use crate::msgs::fragmenter::MessageFragmenter; +#[cfg(feature = "quic")] +use crate::msgs::message::MessagePayload; +use crate::msgs::message::{BorrowedPlainMessage, Message, OpaqueMessage, PlainMessage}; +#[cfg(feature = "quic")] +use crate::quic; +use crate::record_layer; +#[cfg(feature = "secret_extraction")] +use crate::suites::PartiallyExtractedSecrets; +use crate::suites::SupportedCipherSuite; +#[cfg(feature = "tls12")] +use crate::tls12::ConnectionSecrets; +use crate::vecbuf::ChunkVecBuffer; + +/// Connection state common to both client and server connections. +pub struct CommonState { + pub(crate) negotiated_version: Option, + pub(crate) side: Side, + pub(crate) record_layer: record_layer::RecordLayer, + pub(crate) suite: Option, + pub(crate) alpn_protocol: Option>, + pub(crate) aligned_handshake: bool, + pub(crate) may_send_application_data: bool, + pub(crate) may_receive_application_data: bool, + pub(crate) early_traffic: bool, + sent_fatal_alert: bool, + /// If the peer has signaled end of stream. + pub(crate) has_received_close_notify: bool, + pub(crate) has_seen_eof: bool, + pub(crate) received_middlebox_ccs: u8, + pub(crate) peer_certificates: Option>, + message_fragmenter: MessageFragmenter, + pub(crate) received_plaintext: ChunkVecBuffer, + sendable_plaintext: ChunkVecBuffer, + pub(crate) sendable_tls: ChunkVecBuffer, + queued_key_update_message: Option>, + + #[allow(dead_code)] // only read for QUIC + /// Protocol whose key schedule should be used. Unused for TLS < 1.3. + pub(crate) protocol: Protocol, + #[cfg(feature = "quic")] + pub(crate) quic: quic::Quic, + #[cfg(feature = "secret_extraction")] + pub(crate) enable_secret_extraction: bool, +} + +impl CommonState { + pub(crate) fn new(side: Side) -> Self { + Self { + negotiated_version: None, + side, + record_layer: record_layer::RecordLayer::new(), + suite: None, + alpn_protocol: None, + aligned_handshake: true, + may_send_application_data: false, + may_receive_application_data: false, + early_traffic: false, + sent_fatal_alert: false, + has_received_close_notify: false, + has_seen_eof: false, + received_middlebox_ccs: 0, + peer_certificates: None, + message_fragmenter: MessageFragmenter::default(), + received_plaintext: ChunkVecBuffer::new(Some(DEFAULT_RECEIVED_PLAINTEXT_LIMIT)), + sendable_plaintext: ChunkVecBuffer::new(Some(DEFAULT_BUFFER_LIMIT)), + sendable_tls: ChunkVecBuffer::new(Some(DEFAULT_BUFFER_LIMIT)), + queued_key_update_message: None, + + protocol: Protocol::Tcp, + #[cfg(feature = "quic")] + quic: quic::Quic::default(), + #[cfg(feature = "secret_extraction")] + enable_secret_extraction: false, + } + } + + /// Returns true if the caller should call [`Connection::write_tls`] as soon as possible. + /// + /// [`Connection::write_tls`]: crate::Connection::write_tls + pub fn wants_write(&self) -> bool { + !self.sendable_tls.is_empty() + } + + /// Returns true if the connection is currently performing the TLS handshake. + /// + /// During this time plaintext written to the connection is buffered in memory. After + /// [`Connection::process_new_packets()`] has been called, this might start to return `false` + /// while the final handshake packets still need to be extracted from the connection's buffers. + /// + /// [`Connection::process_new_packets()`]: crate::Connection::process_new_packets + pub fn is_handshaking(&self) -> bool { + !(self.may_send_application_data && self.may_receive_application_data) + } + + /// Retrieves the certificate chain used by the peer to authenticate. + /// + /// The order of the certificate chain is as it appears in the TLS + /// protocol: the first certificate relates to the peer, the + /// second certifies the first, the third certifies the second, and + /// so on. + /// + /// This is made available for both full and resumed handshakes. + /// + /// For clients, this is the certificate chain of the server. + /// + /// For servers, this is the certificate chain of the client, + /// if client authentication was completed. + /// + /// The return value is None until this value is available. + pub fn peer_certificates(&self) -> Option<&[key::Certificate]> { + self.peer_certificates.as_deref() + } + + /// Retrieves the protocol agreed with the peer via ALPN. + /// + /// A return value of `None` after handshake completion + /// means no protocol was agreed (because no protocols + /// were offered or accepted by the peer). + pub fn alpn_protocol(&self) -> Option<&[u8]> { + self.get_alpn_protocol() + } + + /// Retrieves the ciphersuite agreed with the peer. + /// + /// This returns None until the ciphersuite is agreed. + pub fn negotiated_cipher_suite(&self) -> Option { + self.suite + } + + /// Retrieves the protocol version agreed with the peer. + /// + /// This returns `None` until the version is agreed. + pub fn protocol_version(&self) -> Option { + self.negotiated_version + } + + pub(crate) fn is_tls13(&self) -> bool { + matches!(self.negotiated_version, Some(ProtocolVersion::TLSv1_3)) + } + + pub(crate) fn process_main_protocol( + &mut self, + msg: Message, + mut state: Box>, + data: &mut Data, + ) -> Result>, Error> { + // For TLS1.2, outside of the handshake, send rejection alerts for + // renegotiation requests. These can occur any time. + if self.may_receive_application_data && !self.is_tls13() { + let reject_ty = match self.side { + Side::Client => HandshakeType::HelloRequest, + Side::Server => HandshakeType::ClientHello, + }; + if msg.is_handshake_type(reject_ty) { + self.send_warning_alert(AlertDescription::NoRenegotiation); + return Ok(state); + } + } + + let mut cx = Context { common: self, data }; + match state.handle(&mut cx, msg) { + Ok(next) => { + state = next; + Ok(state) + } + Err(e @ Error::InappropriateMessage { .. }) + | Err(e @ Error::InappropriateHandshakeMessage { .. }) => { + Err(self.send_fatal_alert(AlertDescription::UnexpectedMessage, e)) + } + Err(e) => Err(e), + } + } + + /// Send plaintext application data, fragmenting and + /// encrypting it as it goes out. + /// + /// If internal buffers are too small, this function will not accept + /// all the data. + pub(crate) fn send_some_plaintext(&mut self, data: &[u8]) -> usize { + self.perhaps_write_key_update(); + self.send_plain(data, Limit::Yes) + } + + pub(crate) fn send_early_plaintext(&mut self, data: &[u8]) -> usize { + debug_assert!(self.early_traffic); + debug_assert!(self.record_layer.is_encrypting()); + + if data.is_empty() { + // Don't send empty fragments. + return 0; + } + + self.send_appdata_encrypt(data, Limit::Yes) + } + + // Changing the keys must not span any fragmented handshake + // messages. Otherwise the defragmented messages will have + // been protected with two different record layer protections, + // which is illegal. Not mentioned in RFC. + pub(crate) fn check_aligned_handshake(&mut self) -> Result<(), Error> { + if !self.aligned_handshake { + Err(self.send_fatal_alert( + AlertDescription::UnexpectedMessage, + PeerMisbehaved::KeyEpochWithPendingFragment, + )) + } else { + Ok(()) + } + } + + /// Fragment `m`, encrypt the fragments, and then queue + /// the encrypted fragments for sending. + pub(crate) fn send_msg_encrypt(&mut self, m: PlainMessage) { + let iter = self + .message_fragmenter + .fragment_message(&m); + for m in iter { + self.send_single_fragment(m); + } + } + + /// Like send_msg_encrypt, but operate on an appdata directly. + fn send_appdata_encrypt(&mut self, payload: &[u8], limit: Limit) -> usize { + // Here, the limit on sendable_tls applies to encrypted data, + // but we're respecting it for plaintext data -- so we'll + // be out by whatever the cipher+record overhead is. That's a + // constant and predictable amount, so it's not a terrible issue. + let len = match limit { + Limit::Yes => self + .sendable_tls + .apply_limit(payload.len()), + Limit::No => payload.len(), + }; + + let iter = self.message_fragmenter.fragment_slice( + ContentType::ApplicationData, + ProtocolVersion::TLSv1_2, + &payload[..len], + ); + for m in iter { + self.send_single_fragment(m); + } + + len + } + + fn send_single_fragment(&mut self, m: BorrowedPlainMessage) { + // Close connection once we start to run out of + // sequence space. + if self + .record_layer + .wants_close_before_encrypt() + { + self.send_close_notify(); + } + + // Refuse to wrap counter at all costs. This + // is basically untestable unfortunately. + if self.record_layer.encrypt_exhausted() { + return; + } + + let em = self.record_layer.encrypt_outgoing(m); + self.queue_tls_message(em); + } + + /// Encrypt and send some plaintext `data`. `limit` controls + /// whether the per-connection buffer limits apply. + /// + /// Returns the number of bytes written from `data`: this might + /// be less than `data.len()` if buffer limits were exceeded. + fn send_plain(&mut self, data: &[u8], limit: Limit) -> usize { + if !self.may_send_application_data { + // If we haven't completed handshaking, buffer + // plaintext to send once we do. + let len = match limit { + Limit::Yes => self + .sendable_plaintext + .append_limited_copy(data), + Limit::No => self + .sendable_plaintext + .append(data.to_vec()), + }; + return len; + } + + debug_assert!(self.record_layer.is_encrypting()); + + if data.is_empty() { + // Don't send empty fragments. + return 0; + } + + self.send_appdata_encrypt(data, limit) + } + + pub(crate) fn start_outgoing_traffic(&mut self) { + self.may_send_application_data = true; + self.flush_plaintext(); + } + + pub(crate) fn start_traffic(&mut self) { + self.may_receive_application_data = true; + self.start_outgoing_traffic(); + } + + /// Sets a limit on the internal buffers used to buffer + /// unsent plaintext (prior to completing the TLS handshake) + /// and unsent TLS records. This limit acts only on application + /// data written through [`Connection::writer`]. + /// + /// By default the limit is 64KB. The limit can be set + /// at any time, even if the current buffer use is higher. + /// + /// [`None`] means no limit applies, and will mean that written + /// data is buffered without bound -- it is up to the application + /// to appropriately schedule its plaintext and TLS writes to bound + /// memory usage. + /// + /// For illustration: `Some(1)` means a limit of one byte applies: + /// [`Connection::writer`] will accept only one byte, encrypt it and + /// add a TLS header. Once this is sent via [`Connection::write_tls`], + /// another byte may be sent. + /// + /// # Internal write-direction buffering + /// rustls has two buffers whose size are bounded by this setting: + /// + /// ## Buffering of unsent plaintext data prior to handshake completion + /// + /// Calls to [`Connection::writer`] before or during the handshake + /// are buffered (up to the limit specified here). Once the + /// handshake completes this data is encrypted and the resulting + /// TLS records are added to the outgoing buffer. + /// + /// ## Buffering of outgoing TLS records + /// + /// This buffer is used to store TLS records that rustls needs to + /// send to the peer. It is used in these two circumstances: + /// + /// - by [`Connection::process_new_packets`] when a handshake or alert + /// TLS record needs to be sent. + /// - by [`Connection::writer`] post-handshake: the plaintext is + /// encrypted and the resulting TLS record is buffered. + /// + /// This buffer is emptied by [`Connection::write_tls`]. + /// + /// [`Connection::writer`]: crate::Connection::writer + /// [`Connection::write_tls`]: crate::Connection::write_tls + /// [`Connection::process_new_packets`]: crate::Connection::process_new_packets + pub fn set_buffer_limit(&mut self, limit: Option) { + self.sendable_plaintext.set_limit(limit); + self.sendable_tls.set_limit(limit); + } + + /// Send any buffered plaintext. Plaintext is buffered if + /// written during handshake. + fn flush_plaintext(&mut self) { + if !self.may_send_application_data { + return; + } + + while let Some(buf) = self.sendable_plaintext.pop() { + self.send_plain(&buf, Limit::No); + } + } + + // Put m into sendable_tls for writing. + fn queue_tls_message(&mut self, m: OpaqueMessage) { + self.sendable_tls.append(m.encode()); + } + + /// Send a raw TLS message, fragmenting it if needed. + pub(crate) fn send_msg(&mut self, m: Message, must_encrypt: bool) { + #[cfg(feature = "quic")] + { + if let Protocol::Quic = self.protocol { + if let MessagePayload::Alert(alert) = m.payload { + self.quic.alert = Some(alert.description); + } else { + debug_assert!( + matches!(m.payload, MessagePayload::Handshake { .. }), + "QUIC uses TLS for the cryptographic handshake only" + ); + let mut bytes = Vec::new(); + m.payload.encode(&mut bytes); + self.quic + .hs_queue + .push_back((must_encrypt, bytes)); + } + return; + } + } + if !must_encrypt { + let msg = &m.into(); + let iter = self + .message_fragmenter + .fragment_message(msg); + for m in iter { + self.queue_tls_message(m.to_unencrypted_opaque()); + } + } else { + self.send_msg_encrypt(m.into()); + } + } + + pub(crate) fn take_received_plaintext(&mut self, bytes: Payload) { + self.received_plaintext.append(bytes.0); + } + + #[cfg(feature = "tls12")] + pub(crate) fn start_encryption_tls12(&mut self, secrets: &ConnectionSecrets, side: Side) { + let (dec, enc) = secrets.make_cipher_pair(side); + self.record_layer + .prepare_message_encrypter(enc); + self.record_layer + .prepare_message_decrypter(dec); + } + + #[cfg(feature = "quic")] + pub(crate) fn missing_extension(&mut self, why: PeerMisbehaved) -> Error { + self.send_fatal_alert(AlertDescription::MissingExtension, why) + } + + fn send_warning_alert(&mut self, desc: AlertDescription) { + warn!("Sending warning alert {:?}", desc); + self.send_warning_alert_no_log(desc); + } + + pub(crate) fn process_alert(&mut self, alert: &AlertMessagePayload) -> Result<(), Error> { + // Reject unknown AlertLevels. + if let AlertLevel::Unknown(_) = alert.level { + return Err(self.send_fatal_alert( + AlertDescription::IllegalParameter, + Error::AlertReceived(alert.description), + )); + } + + // If we get a CloseNotify, make a note to declare EOF to our + // caller. + if alert.description == AlertDescription::CloseNotify { + self.has_received_close_notify = true; + return Ok(()); + } + + // Warnings are nonfatal for TLS1.2, but outlawed in TLS1.3 + // (except, for no good reason, user_cancelled). + let err = Error::AlertReceived(alert.description); + if alert.level == AlertLevel::Warning { + if self.is_tls13() && alert.description != AlertDescription::UserCanceled { + return Err(self.send_fatal_alert(AlertDescription::DecodeError, err)); + } else { + warn!("TLS alert warning received: {:#?}", alert); + return Ok(()); + } + } + + Err(err) + } + + pub(crate) fn send_cert_verify_error_alert(&mut self, err: Error) -> Error { + self.send_fatal_alert( + match &err { + Error::InvalidCertificate(e) => e.clone().into(), + Error::PeerMisbehaved(_) => AlertDescription::IllegalParameter, + _ => AlertDescription::HandshakeFailure, + }, + err, + ) + } + + pub(crate) fn send_fatal_alert( + &mut self, + desc: AlertDescription, + err: impl Into, + ) -> Error { + debug_assert!(!self.sent_fatal_alert); + let m = Message::build_alert(AlertLevel::Fatal, desc); + self.send_msg(m, self.record_layer.is_encrypting()); + self.sent_fatal_alert = true; + err.into() + } + + /// Queues a close_notify warning alert to be sent in the next + /// [`Connection::write_tls`] call. This informs the peer that the + /// connection is being closed. + /// + /// [`Connection::write_tls`]: crate::Connection::write_tls + pub fn send_close_notify(&mut self) { + debug!("Sending warning alert {:?}", AlertDescription::CloseNotify); + self.send_warning_alert_no_log(AlertDescription::CloseNotify); + } + + fn send_warning_alert_no_log(&mut self, desc: AlertDescription) { + let m = Message::build_alert(AlertLevel::Warning, desc); + self.send_msg(m, self.record_layer.is_encrypting()); + } + + pub(crate) fn set_max_fragment_size(&mut self, new: Option) -> Result<(), Error> { + self.message_fragmenter + .set_max_fragment_size(new) + } + + pub(crate) fn get_alpn_protocol(&self) -> Option<&[u8]> { + self.alpn_protocol + .as_ref() + .map(AsRef::as_ref) + } + + /// Returns true if the caller should call [`Connection::read_tls`] as soon + /// as possible. + /// + /// If there is pending plaintext data to read with [`Connection::reader`], + /// this returns false. If your application respects this mechanism, + /// only one full TLS message will be buffered by rustls. + /// + /// [`Connection::reader`]: crate::Connection::reader + /// [`Connection::read_tls`]: crate::Connection::read_tls + pub fn wants_read(&self) -> bool { + // We want to read more data all the time, except when we have unprocessed plaintext. + // This provides back-pressure to the TCP buffers. We also don't want to read more after + // the peer has sent us a close notification. + // + // In the handshake case we don't have readable plaintext before the handshake has + // completed, but also don't want to read if we still have sendable tls. + self.received_plaintext.is_empty() + && !self.has_received_close_notify + && (self.may_send_application_data || self.sendable_tls.is_empty()) + } + + pub(crate) fn current_io_state(&self) -> IoState { + IoState { + tls_bytes_to_write: self.sendable_tls.len(), + plaintext_bytes_to_read: self.received_plaintext.len(), + peer_has_closed: self.has_received_close_notify, + } + } + + pub(crate) fn is_quic(&self) -> bool { + #[cfg(feature = "quic")] + { + self.protocol == Protocol::Quic + } + #[cfg(not(feature = "quic"))] + false + } + + pub(crate) fn should_update_key( + &mut self, + key_update_request: &KeyUpdateRequest, + ) -> Result { + match key_update_request { + KeyUpdateRequest::UpdateNotRequested => Ok(false), + KeyUpdateRequest::UpdateRequested => Ok(self.queued_key_update_message.is_none()), + _ => Err(self.send_fatal_alert( + AlertDescription::IllegalParameter, + InvalidMessage::InvalidKeyUpdate, + )), + } + } + + pub(crate) fn enqueue_key_update_notification(&mut self) { + let message = PlainMessage::from(Message::build_key_update_notify()); + self.queued_key_update_message = Some( + self.record_layer + .encrypt_outgoing(message.borrow()) + .encode(), + ); + } + + pub(crate) fn perhaps_write_key_update(&mut self) { + if let Some(message) = self.queued_key_update_message.take() { + self.sendable_tls.append(message); + } + } +} + +/// Values of this structure are returned from [`Connection::process_new_packets`] +/// and tell the caller the current I/O state of the TLS connection. +/// +/// [`Connection::process_new_packets`]: crate::Connection::process_new_packets +#[derive(Debug, Eq, PartialEq)] +pub struct IoState { + tls_bytes_to_write: usize, + plaintext_bytes_to_read: usize, + peer_has_closed: bool, +} + +impl IoState { + /// How many bytes could be written by [`Connection::write_tls`] if called + /// right now. A non-zero value implies [`CommonState::wants_write`]. + /// + /// [`Connection::write_tls`]: crate::Connection::write_tls + pub fn tls_bytes_to_write(&self) -> usize { + self.tls_bytes_to_write + } + + /// How many plaintext bytes could be obtained via [`std::io::Read`] + /// without further I/O. + pub fn plaintext_bytes_to_read(&self) -> usize { + self.plaintext_bytes_to_read + } + + /// True if the peer has sent us a close_notify alert. This is + /// the TLS mechanism to securely half-close a TLS connection, + /// and signifies that the peer will not send any further data + /// on this connection. + /// + /// This is also signalled via returning `Ok(0)` from + /// [`std::io::Read`], after all the received bytes have been + /// retrieved. + pub fn peer_has_closed(&self) -> bool { + self.peer_has_closed + } +} + +pub(crate) trait State: Send + Sync { + fn handle( + self: Box, + cx: &mut Context<'_, Data>, + message: Message, + ) -> Result>, Error>; + + fn export_keying_material( + &self, + _output: &mut [u8], + _label: &[u8], + _context: Option<&[u8]>, + ) -> Result<(), Error> { + Err(Error::HandshakeNotComplete) + } + + #[cfg(feature = "secret_extraction")] + fn extract_secrets(&self) -> Result { + Err(Error::HandshakeNotComplete) + } +} + +pub(crate) struct Context<'a, Data> { + pub(crate) common: &'a mut CommonState, + pub(crate) data: &'a mut Data, +} + +/// Side of the connection. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Side { + /// A client initiates the connection. + Client, + /// A server waits for a client to connect. + Server, +} + +impl Side { + pub(crate) fn peer(&self) -> Self { + match self { + Self::Client => Self::Server, + Self::Server => Self::Client, + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub(crate) enum Protocol { + Tcp, + #[cfg(feature = "quic")] + Quic, +} + +enum Limit { + Yes, + No, +} + +const DEFAULT_RECEIVED_PLAINTEXT_LIMIT: usize = 16 * 1024; +const DEFAULT_BUFFER_LIMIT: usize = 64 * 1024; diff --git a/vendor/rustls-0.21.8/src/conn.rs b/vendor/rustls-0.21.8/src/conn.rs new file mode 100644 index 0000000000000..b2f5c760e9ed9 --- /dev/null +++ b/vendor/rustls-0.21.8/src/conn.rs @@ -0,0 +1,753 @@ +use crate::common_state::{CommonState, Context, IoState, State}; +use crate::enums::{AlertDescription, ContentType}; +use crate::error::{Error, PeerMisbehaved}; +#[cfg(feature = "logging")] +use crate::log::trace; +use crate::msgs::deframer::{Deframed, MessageDeframer}; +use crate::msgs::handshake::Random; +use crate::msgs::message::{Message, MessagePayload, PlainMessage}; +#[cfg(feature = "secret_extraction")] +use crate::suites::{ExtractedSecrets, PartiallyExtractedSecrets}; +use crate::vecbuf::ChunkVecBuffer; + +use std::fmt::Debug; +use std::io; +use std::mem; +use std::ops::{Deref, DerefMut}; + +/// A client or server connection. +#[derive(Debug)] +pub enum Connection { + /// A client connection + Client(crate::client::ClientConnection), + /// A server connection + Server(crate::server::ServerConnection), +} + +impl Connection { + /// Read TLS content from `rd`. + /// + /// See [`ConnectionCommon::read_tls()`] for more information. + pub fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result { + match self { + Self::Client(conn) => conn.read_tls(rd), + Self::Server(conn) => conn.read_tls(rd), + } + } + + /// Writes TLS messages to `wr`. + /// + /// See [`ConnectionCommon::write_tls()`] for more information. + pub fn write_tls(&mut self, wr: &mut dyn io::Write) -> Result { + self.sendable_tls.write_to(wr) + } + + /// Returns an object that allows reading plaintext. + pub fn reader(&mut self) -> Reader { + match self { + Self::Client(conn) => conn.reader(), + Self::Server(conn) => conn.reader(), + } + } + + /// Returns an object that allows writing plaintext. + pub fn writer(&mut self) -> Writer { + match self { + Self::Client(conn) => Writer::new(&mut **conn), + Self::Server(conn) => Writer::new(&mut **conn), + } + } + + /// Processes any new packets read by a previous call to [`Connection::read_tls`]. + /// + /// See [`ConnectionCommon::process_new_packets()`] for more information. + pub fn process_new_packets(&mut self) -> Result { + match self { + Self::Client(conn) => conn.process_new_packets(), + Self::Server(conn) => conn.process_new_packets(), + } + } + + /// Derives key material from the agreed connection secrets. + /// + /// See [`ConnectionCommon::export_keying_material()`] for more information. + pub fn export_keying_material>( + &self, + output: T, + label: &[u8], + context: Option<&[u8]>, + ) -> Result { + match self { + Self::Client(conn) => conn.export_keying_material(output, label, context), + Self::Server(conn) => conn.export_keying_material(output, label, context), + } + } + + /// Extract secrets, to set up kTLS for example + #[cfg(feature = "secret_extraction")] + #[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] + pub fn extract_secrets(self) -> Result { + match self { + Self::Client(conn) => conn.extract_secrets(), + Self::Server(conn) => conn.extract_secrets(), + } + } + + /// This function uses `io` to complete any outstanding IO for this connection. + /// + /// See [`ConnectionCommon::complete_io()`] for more information. + pub fn complete_io(&mut self, io: &mut T) -> Result<(usize, usize), io::Error> + where + Self: Sized, + T: io::Read + io::Write, + { + match self { + Self::Client(conn) => conn.complete_io(io), + Self::Server(conn) => conn.complete_io(io), + } + } +} + +impl Deref for Connection { + type Target = CommonState; + + fn deref(&self) -> &Self::Target { + match self { + Self::Client(conn) => &conn.core.common_state, + Self::Server(conn) => &conn.core.common_state, + } + } +} + +impl DerefMut for Connection { + fn deref_mut(&mut self) -> &mut Self::Target { + match self { + Self::Client(conn) => &mut conn.core.common_state, + Self::Server(conn) => &mut conn.core.common_state, + } + } +} + +/// A structure that implements [`std::io::Read`] for reading plaintext. +pub struct Reader<'a> { + received_plaintext: &'a mut ChunkVecBuffer, + peer_cleanly_closed: bool, + has_seen_eof: bool, +} + +impl<'a> io::Read for Reader<'a> { + /// Obtain plaintext data received from the peer over this TLS connection. + /// + /// If the peer closes the TLS session cleanly, this returns `Ok(0)` once all + /// the pending data has been read. No further data can be received on that + /// connection, so the underlying TCP connection should be half-closed too. + /// + /// If the peer closes the TLS session uncleanly (a TCP EOF without sending a + /// `close_notify` alert) this function returns `Err(ErrorKind::UnexpectedEof.into())` + /// once any pending data has been read. + /// + /// Note that support for `close_notify` varies in peer TLS libraries: many do not + /// support it and uncleanly close the TCP connection (this might be + /// vulnerable to truncation attacks depending on the application protocol). + /// This means applications using rustls must both handle EOF + /// from this function, *and* unexpected EOF of the underlying TCP connection. + /// + /// If there are no bytes to read, this returns `Err(ErrorKind::WouldBlock.into())`. + /// + /// You may learn the number of bytes available at any time by inspecting + /// the return of [`Connection::process_new_packets`]. + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let len = self.received_plaintext.read(buf)?; + + if len == 0 && !buf.is_empty() { + // No bytes available: + match (self.peer_cleanly_closed, self.has_seen_eof) { + // cleanly closed; don't care about TCP EOF: express this as Ok(0) + (true, _) => {} + // unclean closure + (false, true) => return Err(io::ErrorKind::UnexpectedEof.into()), + // connection still going, but need more data: signal `WouldBlock` so that + // the caller knows this + (false, false) => return Err(io::ErrorKind::WouldBlock.into()), + } + } + + Ok(len) + } + + /// Obtain plaintext data received from the peer over this TLS connection. + /// + /// If the peer closes the TLS session, this returns `Ok(())` without filling + /// any more of the buffer once all the pending data has been read. No further + /// data can be received on that connection, so the underlying TCP connection + /// should be half-closed too. + /// + /// If the peer closes the TLS session uncleanly (a TCP EOF without sending a + /// `close_notify` alert) this function returns `Err(ErrorKind::UnexpectedEof.into())` + /// once any pending data has been read. + /// + /// Note that support for `close_notify` varies in peer TLS libraries: many do not + /// support it and uncleanly close the TCP connection (this might be + /// vulnerable to truncation attacks depending on the application protocol). + /// This means applications using rustls must both handle EOF + /// from this function, *and* unexpected EOF of the underlying TCP connection. + /// + /// If there are no bytes to read, this returns `Err(ErrorKind::WouldBlock.into())`. + /// + /// You may learn the number of bytes available at any time by inspecting + /// the return of [`Connection::process_new_packets`]. + #[cfg(read_buf)] + fn read_buf(&mut self, mut cursor: io::BorrowedCursor<'_>) -> io::Result<()> { + let before = cursor.written(); + self.received_plaintext + .read_buf(cursor.reborrow())?; + let len = cursor.written() - before; + + if len == 0 && cursor.capacity() > 0 { + // No bytes available: + match (self.peer_cleanly_closed, self.has_seen_eof) { + // cleanly closed; don't care about TCP EOF: express this as Ok(0) + (true, _) => {} + // unclean closure + (false, true) => return Err(io::ErrorKind::UnexpectedEof.into()), + // connection still going, but need more data: signal `WouldBlock` so that + // the caller knows this + (false, false) => return Err(io::ErrorKind::WouldBlock.into()), + } + } + + Ok(()) + } +} + +/// Internal trait implemented by the [`ServerConnection`]/[`ClientConnection`] +/// allowing them to be the subject of a [`Writer`]. +pub(crate) trait PlaintextSink { + fn write(&mut self, buf: &[u8]) -> io::Result; + fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result; + fn flush(&mut self) -> io::Result<()>; +} + +impl PlaintextSink for ConnectionCommon { + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(self.send_some_plaintext(buf)) + } + + fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + let mut sz = 0; + for buf in bufs { + sz += self.send_some_plaintext(buf); + } + Ok(sz) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +/// A structure that implements [`std::io::Write`] for writing plaintext. +pub struct Writer<'a> { + sink: &'a mut dyn PlaintextSink, +} + +impl<'a> Writer<'a> { + /// Create a new Writer. + /// + /// This is not an external interface. Get one of these objects + /// from [`Connection::writer`]. + pub(crate) fn new(sink: &'a mut dyn PlaintextSink) -> Writer<'a> { + Writer { sink } + } +} + +impl<'a> io::Write for Writer<'a> { + /// Send the plaintext `buf` to the peer, encrypting + /// and authenticating it. Once this function succeeds + /// you should call [`Connection::write_tls`] which will output the + /// corresponding TLS records. + /// + /// This function buffers plaintext sent before the + /// TLS handshake completes, and sends it as soon + /// as it can. See [`CommonState::set_buffer_limit`] to control + /// the size of this buffer. + fn write(&mut self, buf: &[u8]) -> io::Result { + self.sink.write(buf) + } + + fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + self.sink.write_vectored(bufs) + } + + fn flush(&mut self) -> io::Result<()> { + self.sink.flush() + } +} + +#[derive(Debug)] +pub(crate) struct ConnectionRandoms { + pub(crate) client: [u8; 32], + pub(crate) server: [u8; 32], +} + +/// How many ChangeCipherSpec messages we accept and drop in TLS1.3 handshakes. +/// The spec says 1, but implementations (namely the boringssl test suite) get +/// this wrong. BoringSSL itself accepts up to 32. +static TLS13_MAX_DROPPED_CCS: u8 = 2u8; + +impl ConnectionRandoms { + pub(crate) fn new(client: Random, server: Random) -> Self { + Self { + client: client.0, + server: server.0, + } + } +} + +// --- Common (to client and server) connection functions --- + +fn is_valid_ccs(msg: &PlainMessage) -> bool { + // We passthrough ChangeCipherSpec messages in the deframer without decrypting them. + // nb. this is prior to the record layer, so is unencrypted. see + // third paragraph of section 5 in RFC8446. + msg.typ == ContentType::ChangeCipherSpec && msg.payload.0 == [0x01] +} + +/// Interface shared by client and server connections. +pub struct ConnectionCommon { + pub(crate) core: ConnectionCore, +} + +impl ConnectionCommon { + /// Returns an object that allows reading plaintext. + pub fn reader(&mut self) -> Reader { + let common = &mut self.core.common_state; + Reader { + received_plaintext: &mut common.received_plaintext, + // Are we done? i.e., have we processed all received messages, and received a + // close_notify to indicate that no new messages will arrive? + peer_cleanly_closed: common.has_received_close_notify + && !self.core.message_deframer.has_pending(), + has_seen_eof: common.has_seen_eof, + } + } + + /// Returns an object that allows writing plaintext. + pub fn writer(&mut self) -> Writer { + Writer::new(self) + } + + /// This function uses `io` to complete any outstanding IO for + /// this connection. + /// + /// This is a convenience function which solely uses other parts + /// of the public API. + /// + /// What this means depends on the connection state: + /// + /// - If the connection [`is_handshaking`], then IO is performed until + /// the handshake is complete. + /// - Otherwise, if [`wants_write`] is true, [`write_tls`] is invoked + /// until it is all written. + /// - Otherwise, if [`wants_read`] is true, [`read_tls`] is invoked + /// once. + /// + /// The return value is the number of bytes read from and written + /// to `io`, respectively. + /// + /// This function will block if `io` blocks. + /// + /// Errors from TLS record handling (i.e., from [`process_new_packets`]) + /// are wrapped in an `io::ErrorKind::InvalidData`-kind error. + /// + /// [`is_handshaking`]: CommonState::is_handshaking + /// [`wants_read`]: CommonState::wants_read + /// [`wants_write`]: CommonState::wants_write + /// [`write_tls`]: ConnectionCommon::write_tls + /// [`read_tls`]: ConnectionCommon::read_tls + /// [`process_new_packets`]: ConnectionCommon::process_new_packets + pub fn complete_io(&mut self, io: &mut T) -> Result<(usize, usize), io::Error> + where + Self: Sized, + T: io::Read + io::Write, + { + let mut eof = false; + let mut wrlen = 0; + let mut rdlen = 0; + + loop { + let until_handshaked = self.is_handshaking(); + + while self.wants_write() { + wrlen += self.write_tls(io)?; + } + io.flush()?; + + if !until_handshaked && wrlen > 0 { + return Ok((rdlen, wrlen)); + } + + while !eof && self.wants_read() { + let read_size = match self.read_tls(io) { + Ok(0) => { + eof = true; + Some(0) + } + Ok(n) => { + rdlen += n; + Some(n) + } + Err(ref err) if err.kind() == io::ErrorKind::Interrupted => None, // nothing to do + Err(err) => return Err(err), + }; + if read_size.is_some() { + break; + } + } + + match self.process_new_packets() { + Ok(_) => {} + Err(e) => { + // In case we have an alert to send describing this error, + // try a last-gasp write -- but don't predate the primary + // error. + let _ignored = self.write_tls(io); + let _ignored = io.flush(); + + return Err(io::Error::new(io::ErrorKind::InvalidData, e)); + } + }; + + // if we're doing IO until handshaked, and we believe we've finished handshaking, + // but process_new_packets() has queued TLS data to send, loop around again to write + // the queued messages. + if until_handshaked && !self.is_handshaking() && self.wants_write() { + continue; + } + + match (eof, until_handshaked, self.is_handshaking()) { + (_, true, false) => return Ok((rdlen, wrlen)), + (_, false, _) => return Ok((rdlen, wrlen)), + (true, true, true) => return Err(io::Error::from(io::ErrorKind::UnexpectedEof)), + (..) => {} + } + } + } + + /// Extract the first handshake message. + /// + /// This is a shortcut to the `process_new_packets()` -> `process_msg()` -> + /// `process_handshake_messages()` path, specialized for the first handshake message. + pub(crate) fn first_handshake_message(&mut self) -> Result, Error> { + match self + .core + .deframe()? + .map(Message::try_from) + { + Some(Ok(msg)) => Ok(Some(msg)), + Some(Err(err)) => Err(self.send_fatal_alert(AlertDescription::DecodeError, err)), + None => Ok(None), + } + } + + pub(crate) fn replace_state(&mut self, new: Box>) { + self.core.state = Ok(new); + } + + /// Processes any new packets read by a previous call to + /// [`Connection::read_tls`]. + /// + /// Errors from this function relate to TLS protocol errors, and + /// are fatal to the connection. Future calls after an error will do + /// no new work and will return the same error. After an error is + /// received from [`process_new_packets`], you should not call [`read_tls`] + /// any more (it will fill up buffers to no purpose). However, you + /// may call the other methods on the connection, including `write`, + /// `send_close_notify`, and `write_tls`. Most likely you will want to + /// call `write_tls` to send any alerts queued by the error and then + /// close the underlying connection. + /// + /// Success from this function comes with some sundry state data + /// about the connection. + /// + /// [`read_tls`]: Connection::read_tls + /// [`process_new_packets`]: Connection::process_new_packets + #[inline] + pub fn process_new_packets(&mut self) -> Result { + self.core.process_new_packets() + } + + /// Read TLS content from `rd` into the internal buffer. + /// + /// Due to the internal buffering, `rd` can supply TLS messages in arbitrary-sized chunks (like + /// a socket or pipe might). + /// + /// You should call [`process_new_packets()`] each time a call to this function succeeds in order + /// to empty the incoming TLS data buffer. + /// + /// This function returns `Ok(0)` when the underlying `rd` does so. This typically happens when + /// a socket is cleanly closed, or a file is at EOF. Errors may result from the IO done through + /// `rd`; additionally, errors of `ErrorKind::Other` are emitted to signal backpressure: + /// + /// * In order to empty the incoming TLS data buffer, you should call [`process_new_packets()`] + /// each time a call to this function succeeds. + /// * In order to empty the incoming plaintext data buffer, you should empty it through + /// the [`reader()`] after the call to [`process_new_packets()`]. + /// + /// [`process_new_packets()`]: ConnectionCommon::process_new_packets + /// [`reader()`]: ConnectionCommon::reader + pub fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result { + if self.received_plaintext.is_full() { + return Err(io::Error::new( + io::ErrorKind::Other, + "received plaintext buffer full", + )); + } + + let res = self.core.message_deframer.read(rd); + if let Ok(0) = res { + self.has_seen_eof = true; + } + res + } + + /// Writes TLS messages to `wr`. + /// + /// On success, this function returns `Ok(n)` where `n` is a number of bytes written to `wr` + /// (after encoding and encryption). + /// + /// After this function returns, the connection buffer may not yet be fully flushed. The + /// [`CommonState::wants_write`] function can be used to check if the output buffer is empty. + pub fn write_tls(&mut self, wr: &mut dyn io::Write) -> Result { + self.sendable_tls.write_to(wr) + } + + /// Derives key material from the agreed connection secrets. + /// + /// This function fills in `output` with `output.len()` bytes of key + /// material derived from the master session secret using `label` + /// and `context` for diversification. Ownership of the buffer is taken + /// by the function and returned via the Ok result to ensure no key + /// material leaks if the function fails. + /// + /// See RFC5705 for more details on what this does and is for. + /// + /// For TLS1.3 connections, this function does not use the + /// "early" exporter at any point. + /// + /// This function fails if called prior to the handshake completing; + /// check with [`CommonState::is_handshaking`] first. + #[inline] + pub fn export_keying_material>( + &self, + output: T, + label: &[u8], + context: Option<&[u8]>, + ) -> Result { + self.core + .export_keying_material(output, label, context) + } + + /// Extract secrets, so they can be used when configuring kTLS, for example. + #[cfg(feature = "secret_extraction")] + #[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] + pub fn extract_secrets(self) -> Result { + if !self.enable_secret_extraction { + return Err(Error::General("Secret extraction is disabled".into())); + } + + let st = self.core.state?; + + let record_layer = self.core.common_state.record_layer; + let PartiallyExtractedSecrets { tx, rx } = st.extract_secrets()?; + Ok(ExtractedSecrets { + tx: (record_layer.write_seq(), tx), + rx: (record_layer.read_seq(), rx), + }) + } +} + +impl<'a, Data> From<&'a mut ConnectionCommon> for Context<'a, Data> { + fn from(conn: &'a mut ConnectionCommon) -> Self { + Self { + common: &mut conn.core.common_state, + data: &mut conn.core.data, + } + } +} + +impl Deref for ConnectionCommon { + type Target = CommonState; + + fn deref(&self) -> &Self::Target { + &self.core.common_state + } +} + +impl DerefMut for ConnectionCommon { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.core.common_state + } +} + +impl From> for ConnectionCommon { + fn from(core: ConnectionCore) -> Self { + Self { core } + } +} + +pub(crate) struct ConnectionCore { + pub(crate) state: Result>, Error>, + pub(crate) data: Data, + pub(crate) common_state: CommonState, + pub(crate) message_deframer: MessageDeframer, +} + +impl ConnectionCore { + pub(crate) fn new(state: Box>, data: Data, common_state: CommonState) -> Self { + Self { + state: Ok(state), + data, + common_state, + message_deframer: MessageDeframer::default(), + } + } + + pub(crate) fn process_new_packets(&mut self) -> Result { + let mut state = match mem::replace(&mut self.state, Err(Error::HandshakeNotComplete)) { + Ok(state) => state, + Err(e) => { + self.state = Err(e.clone()); + return Err(e); + } + }; + + while let Some(msg) = self.deframe()? { + match self.process_msg(msg, state) { + Ok(new) => state = new, + Err(e) => { + self.state = Err(e.clone()); + return Err(e); + } + } + } + + self.state = Ok(state); + Ok(self.common_state.current_io_state()) + } + + /// Pull a message out of the deframer and send any messages that need to be sent as a result. + fn deframe(&mut self) -> Result, Error> { + match self + .message_deframer + .pop(&mut self.common_state.record_layer) + { + Ok(Some(Deframed { + want_close_before_decrypt, + aligned, + trial_decryption_finished, + message, + })) => { + if want_close_before_decrypt { + self.common_state.send_close_notify(); + } + + if trial_decryption_finished { + self.common_state + .record_layer + .finish_trial_decryption(); + } + + self.common_state.aligned_handshake = aligned; + Ok(Some(message)) + } + Ok(None) => Ok(None), + Err(err @ Error::InvalidMessage(_)) => { + #[cfg(feature = "quic")] + if self.common_state.is_quic() { + self.common_state.quic.alert = Some(AlertDescription::DecodeError); + } + + Err(if !self.common_state.is_quic() { + self.common_state + .send_fatal_alert(AlertDescription::DecodeError, err) + } else { + err + }) + } + Err(err @ Error::PeerSentOversizedRecord) => Err(self + .common_state + .send_fatal_alert(AlertDescription::RecordOverflow, err)), + Err(err @ Error::DecryptError) => Err(self + .common_state + .send_fatal_alert(AlertDescription::BadRecordMac, err)), + Err(e) => Err(e), + } + } + + fn process_msg( + &mut self, + msg: PlainMessage, + state: Box>, + ) -> Result>, Error> { + // Drop CCS messages during handshake in TLS1.3 + if msg.typ == ContentType::ChangeCipherSpec + && !self + .common_state + .may_receive_application_data + && self.common_state.is_tls13() + { + if !is_valid_ccs(&msg) + || self.common_state.received_middlebox_ccs > TLS13_MAX_DROPPED_CCS + { + // "An implementation which receives any other change_cipher_spec value or + // which receives a protected change_cipher_spec record MUST abort the + // handshake with an "unexpected_message" alert." + return Err(self.common_state.send_fatal_alert( + AlertDescription::UnexpectedMessage, + PeerMisbehaved::IllegalMiddleboxChangeCipherSpec, + )); + } else { + self.common_state.received_middlebox_ccs += 1; + trace!("Dropping CCS"); + return Ok(state); + } + } + + // Now we can fully parse the message payload. + let msg = match Message::try_from(msg) { + Ok(msg) => msg, + Err(err) => { + return Err(self + .common_state + .send_fatal_alert(AlertDescription::DecodeError, err)); + } + }; + + // For alerts, we have separate logic. + if let MessagePayload::Alert(alert) = &msg.payload { + self.common_state.process_alert(alert)?; + return Ok(state); + } + + self.common_state + .process_main_protocol(msg, state, &mut self.data) + } + + pub(crate) fn export_keying_material>( + &self, + mut output: T, + label: &[u8], + context: Option<&[u8]>, + ) -> Result { + match self.state.as_ref() { + Ok(st) => st + .export_keying_material(output.as_mut(), label, context) + .map(|_| output), + Err(e) => Err(e.clone()), + } + } +} + +/// Data specific to the peer's side (client or server). +pub trait SideData {} diff --git a/vendor/rustls-0.21.8/src/dns_name.rs b/vendor/rustls-0.21.8/src/dns_name.rs new file mode 100644 index 0000000000000..473d652cb7d8c --- /dev/null +++ b/vendor/rustls-0.21.8/src/dns_name.rs @@ -0,0 +1,272 @@ +/// DNS name validation according to RFC1035, but with underscores allowed. +use std::error::Error as StdError; +use std::fmt; + +/// A type which encapsulates an owned string that is a syntactically valid DNS name. +#[derive(Clone, Eq, Hash, PartialEq, Debug)] +pub struct DnsName(String); + +impl<'a> DnsName { + /// Produce a borrowed `DnsNameRef` from this owned `DnsName`. + pub fn borrow(&'a self) -> DnsNameRef<'a> { + DnsNameRef(self.as_ref()) + } + + /// Validate the given bytes are a DNS name if they are viewed as ASCII. + pub fn try_from_ascii(bytes: &[u8]) -> Result { + // nb. a sequence of bytes that is accepted by `validate()` is both + // valid UTF-8, and valid ASCII. + String::from_utf8(bytes.to_vec()) + .map_err(|_| InvalidDnsNameError) + .and_then(Self::try_from) + } +} + +impl TryFrom for DnsName { + type Error = InvalidDnsNameError; + + fn try_from(value: String) -> Result { + validate(value.as_bytes())?; + Ok(Self(value)) + } +} + +impl AsRef for DnsName { + fn as_ref(&self) -> &str { + AsRef::::as_ref(&self.0) + } +} + +/// A type which encapsulates a borrowed string that is a syntactically valid DNS name. +#[derive(Eq, Hash, PartialEq, Debug)] +pub struct DnsNameRef<'a>(&'a str); + +impl<'a> DnsNameRef<'a> { + /// Copy this object to produce an owned `DnsName`. + pub fn to_owned(&'a self) -> DnsName { + DnsName(self.0.to_string()) + } + + /// Copy this object to produce an owned `DnsName`, smashing the case to lowercase + /// in one operation. + pub fn to_lowercase_owned(&'a self) -> DnsName { + DnsName(self.0.to_lowercase()) + } +} + +impl<'a> TryFrom<&'a str> for DnsNameRef<'a> { + type Error = InvalidDnsNameError; + + fn try_from(value: &'a str) -> Result, Self::Error> { + validate(value.as_bytes())?; + Ok(DnsNameRef(value)) + } +} + +impl<'a> AsRef for DnsNameRef<'a> { + fn as_ref(&self) -> &str { + self.0 + } +} + +/// The provided input could not be parsed because +/// it is not a syntactically-valid DNS Name. +#[derive(Debug)] +pub struct InvalidDnsNameError; + +impl fmt::Display for InvalidDnsNameError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("invalid dns name") + } +} + +impl StdError for InvalidDnsNameError {} + +fn validate(input: &[u8]) -> Result<(), InvalidDnsNameError> { + use State::*; + let mut state = Start; + + /// "Labels must be 63 characters or less." + const MAX_LABEL_LENGTH: usize = 63; + + /// https://devblogs.microsoft.com/oldnewthing/20120412-00/?p=7873 + const MAX_NAME_LENGTH: usize = 253; + + if input.len() > MAX_NAME_LENGTH { + return Err(InvalidDnsNameError); + } + + for ch in input { + state = match (state, ch) { + (Start | Next | NextAfterNumericOnly | Hyphen { .. }, b'.') => { + return Err(InvalidDnsNameError) + } + (Subsequent { .. }, b'.') => Next, + (NumericOnly { .. }, b'.') => NextAfterNumericOnly, + (Subsequent { len } | NumericOnly { len } | Hyphen { len }, _) + if len >= MAX_LABEL_LENGTH => + { + return Err(InvalidDnsNameError) + } + (Start | Next | NextAfterNumericOnly, b'0'..=b'9') => NumericOnly { len: 1 }, + (NumericOnly { len }, b'0'..=b'9') => NumericOnly { len: len + 1 }, + (Start | Next | NextAfterNumericOnly, b'a'..=b'z' | b'A'..=b'Z' | b'_') => { + Subsequent { len: 1 } + } + (Subsequent { len } | NumericOnly { len } | Hyphen { len }, b'-') => { + Hyphen { len: len + 1 } + } + ( + Subsequent { len } | NumericOnly { len } | Hyphen { len }, + b'a'..=b'z' | b'A'..=b'Z' | b'_' | b'0'..=b'9', + ) => Subsequent { len: len + 1 }, + _ => return Err(InvalidDnsNameError), + }; + } + + if matches!( + state, + Start | Hyphen { .. } | NumericOnly { .. } | NextAfterNumericOnly + ) { + return Err(InvalidDnsNameError); + } + + Ok(()) +} + +enum State { + Start, + Next, + NumericOnly { len: usize }, + NextAfterNumericOnly, + Subsequent { len: usize }, + Hyphen { len: usize }, +} + +#[cfg(test)] +mod test { + static TESTS: &[(&'static str, bool)] = &[ + ("", false), + ("localhost", true), + ("LOCALHOST", true), + (".localhost", false), + ("..localhost", false), + ("1.2.3.4", false), + ("127.0.0.1", false), + ("absolute.", true), + ("absolute..", false), + ("multiple.labels.absolute.", true), + ("foo.bar.com", true), + ("infix-hyphen-allowed.com", true), + ("-prefixhypheninvalid.com", false), + ("suffixhypheninvalid--", false), + ("suffixhypheninvalid-.com", false), + ("foo.lastlabelendswithhyphen-", false), + ("infix_underscore_allowed.com", true), + ("_prefixunderscorevalid.com", true), + ("labelendswithnumber1.bar.com", true), + ("xn--bcher-kva.example", true), + ( + "sixtythreesixtythreesixtythreesixtythreesixtythreesixtythreesix.com", + true, + ), + ( + "sixtyfoursixtyfoursixtyfoursixtyfoursixtyfoursixtyfoursixtyfours.com", + false, + ), + ( + "012345678901234567890123456789012345678901234567890123456789012.com", + true, + ), + ( + "0123456789012345678901234567890123456789012345678901234567890123.com", + false, + ), + ( + "01234567890123456789012345678901234567890123456789012345678901-.com", + false, + ), + ( + "012345678901234567890123456789012345678901234567890123456789012-.com", + false, + ), + ("numeric-only-final-label.1", false), + ("numeric-only-final-label.absolute.1.", false), + ("1starts-with-number.com", true), + ("1Starts-with-number.com", true), + ("1.2.3.4.com", true), + ("123.numeric-only-first-label", true), + ("a123b.com", true), + ("numeric-only-middle-label.4.com", true), + ("1000-sans.badssl.com", true), + ("twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfi", true), + ("twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourc", false), + ]; + + #[test] + fn test_validation() { + for (input, expected) in TESTS { + println!("test: {:?} expected valid? {:?}", input, expected); + let name_ref = super::DnsNameRef::try_from(*input); + assert_eq!(*expected, name_ref.is_ok()); + let name = super::DnsName::try_from(input.to_string()); + assert_eq!(*expected, name.is_ok()); + } + } + + #[test] + fn error_is_debug() { + assert_eq!( + format!("{:?}", super::InvalidDnsNameError), + "InvalidDnsNameError" + ); + } + + #[test] + fn error_is_display() { + assert_eq!( + format!("{}", super::InvalidDnsNameError), + "invalid dns name" + ); + } + + #[test] + fn dns_name_is_debug() { + let example = super::DnsName::try_from("example.com".to_string()).unwrap(); + assert_eq!(format!("{:?}", example), "DnsName(\"example.com\")"); + } + + #[test] + fn dns_name_traits() { + let example = super::DnsName::try_from("example.com".to_string()).unwrap(); + assert_eq!(example, example); // PartialEq + + use std::collections::HashSet; + let mut h = HashSet::::new(); + h.insert(example); + } + + #[test] + fn try_from_ascii_rejects_bad_utf8() { + assert_eq!( + format!("{:?}", super::DnsName::try_from_ascii(b"\x80")), + "Err(InvalidDnsNameError)" + ); + } + + #[test] + fn dns_name_ref_is_debug() { + let example = super::DnsNameRef::try_from("example.com").unwrap(); + assert_eq!(format!("{:?}", example), "DnsNameRef(\"example.com\")"); + } + + #[test] + fn dns_name_ref_traits() { + let example = super::DnsNameRef::try_from("example.com").unwrap(); + assert_eq!(example, example); // PartialEq + + use std::collections::HashSet; + let mut h = HashSet::::new(); + h.insert(example); + } +} diff --git a/vendor/rustls-0.21.8/src/enums.rs b/vendor/rustls-0.21.8/src/enums.rs new file mode 100644 index 0000000000000..592f7ad239eb1 --- /dev/null +++ b/vendor/rustls-0.21.8/src/enums.rs @@ -0,0 +1,570 @@ +#![allow(non_camel_case_types)] +#![allow(missing_docs)] +use crate::msgs::codec::{Codec, Reader}; + +enum_builder! { + /// The `AlertDescription` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: AlertDescription; + EnumVal{ + CloseNotify => 0x00, + UnexpectedMessage => 0x0a, + BadRecordMac => 0x14, + DecryptionFailed => 0x15, + RecordOverflow => 0x16, + DecompressionFailure => 0x1e, + HandshakeFailure => 0x28, + NoCertificate => 0x29, + BadCertificate => 0x2a, + UnsupportedCertificate => 0x2b, + CertificateRevoked => 0x2c, + CertificateExpired => 0x2d, + CertificateUnknown => 0x2e, + IllegalParameter => 0x2f, + UnknownCA => 0x30, + AccessDenied => 0x31, + DecodeError => 0x32, + DecryptError => 0x33, + ExportRestriction => 0x3c, + ProtocolVersion => 0x46, + InsufficientSecurity => 0x47, + InternalError => 0x50, + InappropriateFallback => 0x56, + UserCanceled => 0x5a, + NoRenegotiation => 0x64, + MissingExtension => 0x6d, + UnsupportedExtension => 0x6e, + CertificateUnobtainable => 0x6f, + UnrecognisedName => 0x70, + BadCertificateStatusResponse => 0x71, + BadCertificateHashValue => 0x72, + UnknownPSKIdentity => 0x73, + CertificateRequired => 0x74, + NoApplicationProtocol => 0x78 + } +} + +enum_builder! { + /// The `HandshakeType` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: HandshakeType; + EnumVal{ + HelloRequest => 0x00, + ClientHello => 0x01, + ServerHello => 0x02, + HelloVerifyRequest => 0x03, + NewSessionTicket => 0x04, + EndOfEarlyData => 0x05, + HelloRetryRequest => 0x06, + EncryptedExtensions => 0x08, + Certificate => 0x0b, + ServerKeyExchange => 0x0c, + CertificateRequest => 0x0d, + ServerHelloDone => 0x0e, + CertificateVerify => 0x0f, + ClientKeyExchange => 0x10, + Finished => 0x14, + CertificateURL => 0x15, + CertificateStatus => 0x16, + KeyUpdate => 0x18, + MessageHash => 0xfe + } +} + +enum_builder! { + /// The `ContentType` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: ContentType; + EnumVal{ + ChangeCipherSpec => 0x14, + Alert => 0x15, + Handshake => 0x16, + ApplicationData => 0x17, + Heartbeat => 0x18 + } +} + +enum_builder! { + /// The `ProtocolVersion` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U16 + EnumName: ProtocolVersion; + EnumVal{ + SSLv2 => 0x0200, + SSLv3 => 0x0300, + TLSv1_0 => 0x0301, + TLSv1_1 => 0x0302, + TLSv1_2 => 0x0303, + TLSv1_3 => 0x0304, + DTLSv1_0 => 0xFEFF, + DTLSv1_2 => 0xFEFD, + DTLSv1_3 => 0xFEFC + } +} + +enum_builder! { + /// The `CipherSuite` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U16 + EnumName: CipherSuite; + EnumVal{ + TLS_NULL_WITH_NULL_NULL => 0x0000, + TLS_RSA_WITH_NULL_MD5 => 0x0001, + TLS_RSA_WITH_NULL_SHA => 0x0002, + TLS_RSA_EXPORT_WITH_RC4_40_MD5 => 0x0003, + TLS_RSA_WITH_RC4_128_MD5 => 0x0004, + TLS_RSA_WITH_RC4_128_SHA => 0x0005, + TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 => 0x0006, + TLS_RSA_WITH_IDEA_CBC_SHA => 0x0007, + TLS_RSA_EXPORT_WITH_DES40_CBC_SHA => 0x0008, + TLS_RSA_WITH_DES_CBC_SHA => 0x0009, + TLS_RSA_WITH_3DES_EDE_CBC_SHA => 0x000a, + TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA => 0x000b, + TLS_DH_DSS_WITH_DES_CBC_SHA => 0x000c, + TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA => 0x000d, + TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA => 0x000e, + TLS_DH_RSA_WITH_DES_CBC_SHA => 0x000f, + TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA => 0x0010, + TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA => 0x0011, + TLS_DHE_DSS_WITH_DES_CBC_SHA => 0x0012, + TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA => 0x0013, + TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA => 0x0014, + TLS_DHE_RSA_WITH_DES_CBC_SHA => 0x0015, + TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA => 0x0016, + TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 => 0x0017, + TLS_DH_anon_WITH_RC4_128_MD5 => 0x0018, + TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA => 0x0019, + TLS_DH_anon_WITH_DES_CBC_SHA => 0x001a, + TLS_DH_anon_WITH_3DES_EDE_CBC_SHA => 0x001b, + SSL_FORTEZZA_KEA_WITH_NULL_SHA => 0x001c, + SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA => 0x001d, + TLS_KRB5_WITH_DES_CBC_SHA_or_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA => 0x001e, + TLS_KRB5_WITH_3DES_EDE_CBC_SHA => 0x001f, + TLS_KRB5_WITH_RC4_128_SHA => 0x0020, + TLS_KRB5_WITH_IDEA_CBC_SHA => 0x0021, + TLS_KRB5_WITH_DES_CBC_MD5 => 0x0022, + TLS_KRB5_WITH_3DES_EDE_CBC_MD5 => 0x0023, + TLS_KRB5_WITH_RC4_128_MD5 => 0x0024, + TLS_KRB5_WITH_IDEA_CBC_MD5 => 0x0025, + TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA => 0x0026, + TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA => 0x0027, + TLS_KRB5_EXPORT_WITH_RC4_40_SHA => 0x0028, + TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 => 0x0029, + TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 => 0x002a, + TLS_KRB5_EXPORT_WITH_RC4_40_MD5 => 0x002b, + TLS_PSK_WITH_NULL_SHA => 0x002c, + TLS_DHE_PSK_WITH_NULL_SHA => 0x002d, + TLS_RSA_PSK_WITH_NULL_SHA => 0x002e, + TLS_RSA_WITH_AES_128_CBC_SHA => 0x002f, + TLS_DH_DSS_WITH_AES_128_CBC_SHA => 0x0030, + TLS_DH_RSA_WITH_AES_128_CBC_SHA => 0x0031, + TLS_DHE_DSS_WITH_AES_128_CBC_SHA => 0x0032, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA => 0x0033, + TLS_DH_anon_WITH_AES_128_CBC_SHA => 0x0034, + TLS_RSA_WITH_AES_256_CBC_SHA => 0x0035, + TLS_DH_DSS_WITH_AES_256_CBC_SHA => 0x0036, + TLS_DH_RSA_WITH_AES_256_CBC_SHA => 0x0037, + TLS_DHE_DSS_WITH_AES_256_CBC_SHA => 0x0038, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA => 0x0039, + TLS_DH_anon_WITH_AES_256_CBC_SHA => 0x003a, + TLS_RSA_WITH_NULL_SHA256 => 0x003b, + TLS_RSA_WITH_AES_128_CBC_SHA256 => 0x003c, + TLS_RSA_WITH_AES_256_CBC_SHA256 => 0x003d, + TLS_DH_DSS_WITH_AES_128_CBC_SHA256 => 0x003e, + TLS_DH_RSA_WITH_AES_128_CBC_SHA256 => 0x003f, + TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 => 0x0040, + TLS_RSA_WITH_CAMELLIA_128_CBC_SHA => 0x0041, + TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA => 0x0042, + TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA => 0x0043, + TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA => 0x0044, + TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA => 0x0045, + TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA => 0x0046, + TLS_ECDH_ECDSA_WITH_NULL_SHA_draft => 0x0047, + TLS_ECDH_ECDSA_WITH_RC4_128_SHA_draft => 0x0048, + TLS_ECDH_ECDSA_WITH_DES_CBC_SHA_draft => 0x0049, + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA_draft => 0x004a, + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA_draft => 0x004b, + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA_draft => 0x004c, + TLS_ECDH_ECNRA_WITH_DES_CBC_SHA_draft => 0x004d, + TLS_ECDH_ECNRA_WITH_3DES_EDE_CBC_SHA_draft => 0x004e, + TLS_ECMQV_ECDSA_NULL_SHA_draft => 0x004f, + TLS_ECMQV_ECDSA_WITH_RC4_128_SHA_draft => 0x0050, + TLS_ECMQV_ECDSA_WITH_DES_CBC_SHA_draft => 0x0051, + TLS_ECMQV_ECDSA_WITH_3DES_EDE_CBC_SHA_draft => 0x0052, + TLS_ECMQV_ECNRA_NULL_SHA_draft => 0x0053, + TLS_ECMQV_ECNRA_WITH_RC4_128_SHA_draft => 0x0054, + TLS_ECMQV_ECNRA_WITH_DES_CBC_SHA_draft => 0x0055, + TLS_ECMQV_ECNRA_WITH_3DES_EDE_CBC_SHA_draft => 0x0056, + TLS_ECDH_anon_NULL_WITH_SHA_draft => 0x0057, + TLS_ECDH_anon_WITH_RC4_128_SHA_draft => 0x0058, + TLS_ECDH_anon_WITH_DES_CBC_SHA_draft => 0x0059, + TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA_draft => 0x005a, + TLS_ECDH_anon_EXPORT_WITH_DES40_CBC_SHA_draft => 0x005b, + TLS_ECDH_anon_EXPORT_WITH_RC4_40_SHA_draft => 0x005c, + TLS_RSA_EXPORT1024_WITH_RC4_56_MD5 => 0x0060, + TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 => 0x0061, + TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA => 0x0062, + TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA => 0x0063, + TLS_RSA_EXPORT1024_WITH_RC4_56_SHA => 0x0064, + TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA => 0x0065, + TLS_DHE_DSS_WITH_RC4_128_SHA => 0x0066, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 => 0x0067, + TLS_DH_DSS_WITH_AES_256_CBC_SHA256 => 0x0068, + TLS_DH_RSA_WITH_AES_256_CBC_SHA256 => 0x0069, + TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 => 0x006a, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 => 0x006b, + TLS_DH_anon_WITH_AES_128_CBC_SHA256 => 0x006c, + TLS_DH_anon_WITH_AES_256_CBC_SHA256 => 0x006d, + TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD => 0x0072, + TLS_DHE_DSS_WITH_AES_128_CBC_RMD => 0x0073, + TLS_DHE_DSS_WITH_AES_256_CBC_RMD => 0x0074, + TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD => 0x0077, + TLS_DHE_RSA_WITH_AES_128_CBC_RMD => 0x0078, + TLS_DHE_RSA_WITH_AES_256_CBC_RMD => 0x0079, + TLS_RSA_WITH_3DES_EDE_CBC_RMD => 0x007c, + TLS_RSA_WITH_AES_128_CBC_RMD => 0x007d, + TLS_RSA_WITH_AES_256_CBC_RMD => 0x007e, + TLS_GOSTR341094_WITH_28147_CNT_IMIT => 0x0080, + TLS_GOSTR341001_WITH_28147_CNT_IMIT => 0x0081, + TLS_GOSTR341094_WITH_NULL_GOSTR3411 => 0x0082, + TLS_GOSTR341001_WITH_NULL_GOSTR3411 => 0x0083, + TLS_RSA_WITH_CAMELLIA_256_CBC_SHA => 0x0084, + TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA => 0x0085, + TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA => 0x0086, + TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA => 0x0087, + TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA => 0x0088, + TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA => 0x0089, + TLS_PSK_WITH_RC4_128_SHA => 0x008a, + TLS_PSK_WITH_3DES_EDE_CBC_SHA => 0x008b, + TLS_PSK_WITH_AES_128_CBC_SHA => 0x008c, + TLS_PSK_WITH_AES_256_CBC_SHA => 0x008d, + TLS_DHE_PSK_WITH_RC4_128_SHA => 0x008e, + TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA => 0x008f, + TLS_DHE_PSK_WITH_AES_128_CBC_SHA => 0x0090, + TLS_DHE_PSK_WITH_AES_256_CBC_SHA => 0x0091, + TLS_RSA_PSK_WITH_RC4_128_SHA => 0x0092, + TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA => 0x0093, + TLS_RSA_PSK_WITH_AES_128_CBC_SHA => 0x0094, + TLS_RSA_PSK_WITH_AES_256_CBC_SHA => 0x0095, + TLS_RSA_WITH_SEED_CBC_SHA => 0x0096, + TLS_DH_DSS_WITH_SEED_CBC_SHA => 0x0097, + TLS_DH_RSA_WITH_SEED_CBC_SHA => 0x0098, + TLS_DHE_DSS_WITH_SEED_CBC_SHA => 0x0099, + TLS_DHE_RSA_WITH_SEED_CBC_SHA => 0x009a, + TLS_DH_anon_WITH_SEED_CBC_SHA => 0x009b, + TLS_RSA_WITH_AES_128_GCM_SHA256 => 0x009c, + TLS_RSA_WITH_AES_256_GCM_SHA384 => 0x009d, + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 => 0x009e, + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 => 0x009f, + TLS_DH_RSA_WITH_AES_128_GCM_SHA256 => 0x00a0, + TLS_DH_RSA_WITH_AES_256_GCM_SHA384 => 0x00a1, + TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 => 0x00a2, + TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 => 0x00a3, + TLS_DH_DSS_WITH_AES_128_GCM_SHA256 => 0x00a4, + TLS_DH_DSS_WITH_AES_256_GCM_SHA384 => 0x00a5, + TLS_DH_anon_WITH_AES_128_GCM_SHA256 => 0x00a6, + TLS_DH_anon_WITH_AES_256_GCM_SHA384 => 0x00a7, + TLS_PSK_WITH_AES_128_GCM_SHA256 => 0x00a8, + TLS_PSK_WITH_AES_256_GCM_SHA384 => 0x00a9, + TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 => 0x00aa, + TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 => 0x00ab, + TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 => 0x00ac, + TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 => 0x00ad, + TLS_PSK_WITH_AES_128_CBC_SHA256 => 0x00ae, + TLS_PSK_WITH_AES_256_CBC_SHA384 => 0x00af, + TLS_PSK_WITH_NULL_SHA256 => 0x00b0, + TLS_PSK_WITH_NULL_SHA384 => 0x00b1, + TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 => 0x00b2, + TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 => 0x00b3, + TLS_DHE_PSK_WITH_NULL_SHA256 => 0x00b4, + TLS_DHE_PSK_WITH_NULL_SHA384 => 0x00b5, + TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 => 0x00b6, + TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 => 0x00b7, + TLS_RSA_PSK_WITH_NULL_SHA256 => 0x00b8, + TLS_RSA_PSK_WITH_NULL_SHA384 => 0x00b9, + TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0x00ba, + TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 => 0x00bb, + TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0x00bc, + TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 => 0x00bd, + TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0x00be, + TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 => 0x00bf, + TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c0, + TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c1, + TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c2, + TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c3, + TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c4, + TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c5, + TLS_EMPTY_RENEGOTIATION_INFO_SCSV => 0x00ff, + TLS13_AES_128_GCM_SHA256 => 0x1301, + TLS13_AES_256_GCM_SHA384 => 0x1302, + TLS13_CHACHA20_POLY1305_SHA256 => 0x1303, + TLS13_AES_128_CCM_SHA256 => 0x1304, + TLS13_AES_128_CCM_8_SHA256 => 0x1305, + TLS_ECDH_ECDSA_WITH_NULL_SHA => 0xc001, + TLS_ECDH_ECDSA_WITH_RC4_128_SHA => 0xc002, + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA => 0xc003, + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA => 0xc004, + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA => 0xc005, + TLS_ECDHE_ECDSA_WITH_NULL_SHA => 0xc006, + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA => 0xc007, + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA => 0xc008, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA => 0xc009, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA => 0xc00a, + TLS_ECDH_RSA_WITH_NULL_SHA => 0xc00b, + TLS_ECDH_RSA_WITH_RC4_128_SHA => 0xc00c, + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA => 0xc00d, + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA => 0xc00e, + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA => 0xc00f, + TLS_ECDHE_RSA_WITH_NULL_SHA => 0xc010, + TLS_ECDHE_RSA_WITH_RC4_128_SHA => 0xc011, + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA => 0xc012, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA => 0xc013, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA => 0xc014, + TLS_ECDH_anon_WITH_NULL_SHA => 0xc015, + TLS_ECDH_anon_WITH_RC4_128_SHA => 0xc016, + TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA => 0xc017, + TLS_ECDH_anon_WITH_AES_128_CBC_SHA => 0xc018, + TLS_ECDH_anon_WITH_AES_256_CBC_SHA => 0xc019, + TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA => 0xc01a, + TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA => 0xc01b, + TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA => 0xc01c, + TLS_SRP_SHA_WITH_AES_128_CBC_SHA => 0xc01d, + TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA => 0xc01e, + TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA => 0xc01f, + TLS_SRP_SHA_WITH_AES_256_CBC_SHA => 0xc020, + TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA => 0xc021, + TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA => 0xc022, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 => 0xc023, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 => 0xc024, + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 => 0xc025, + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 => 0xc026, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 => 0xc027, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 => 0xc028, + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 => 0xc029, + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 => 0xc02a, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 => 0xc02b, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 => 0xc02c, + TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 => 0xc02d, + TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 => 0xc02e, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 => 0xc02f, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 => 0xc030, + TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 => 0xc031, + TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 => 0xc032, + TLS_ECDHE_PSK_WITH_RC4_128_SHA => 0xc033, + TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA => 0xc034, + TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA => 0xc035, + TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA => 0xc036, + TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 => 0xc037, + TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 => 0xc038, + TLS_ECDHE_PSK_WITH_NULL_SHA => 0xc039, + TLS_ECDHE_PSK_WITH_NULL_SHA256 => 0xc03a, + TLS_ECDHE_PSK_WITH_NULL_SHA384 => 0xc03b, + TLS_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc03c, + TLS_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc03d, + TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 => 0xc03e, + TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 => 0xc03f, + TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc040, + TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc041, + TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 => 0xc042, + TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 => 0xc043, + TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc044, + TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc045, + TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 => 0xc046, + TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 => 0xc047, + TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 => 0xc048, + TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 => 0xc049, + TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 => 0xc04a, + TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 => 0xc04b, + TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc04c, + TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc04d, + TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc04e, + TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc04f, + TLS_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc050, + TLS_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc051, + TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc052, + TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc053, + TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc054, + TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc055, + TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 => 0xc056, + TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 => 0xc057, + TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 => 0xc058, + TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 => 0xc059, + TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 => 0xc05a, + TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 => 0xc05b, + TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 => 0xc05c, + TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 => 0xc05d, + TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 => 0xc05e, + TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 => 0xc05f, + TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc060, + TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc061, + TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc062, + TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc063, + TLS_PSK_WITH_ARIA_128_CBC_SHA256 => 0xc064, + TLS_PSK_WITH_ARIA_256_CBC_SHA384 => 0xc065, + TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 => 0xc066, + TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 => 0xc067, + TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 => 0xc068, + TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 => 0xc069, + TLS_PSK_WITH_ARIA_128_GCM_SHA256 => 0xc06a, + TLS_PSK_WITH_ARIA_256_GCM_SHA384 => 0xc06b, + TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 => 0xc06c, + TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 => 0xc06d, + TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 => 0xc06e, + TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 => 0xc06f, + TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 => 0xc070, + TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 => 0xc071, + TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 => 0xc072, + TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 => 0xc073, + TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 => 0xc074, + TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 => 0xc075, + TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0xc076, + TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 => 0xc077, + TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0xc078, + TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 => 0xc079, + TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc07a, + TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc07b, + TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc07c, + TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc07d, + TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc07e, + TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc07f, + TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 => 0xc080, + TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 => 0xc081, + TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 => 0xc082, + TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 => 0xc083, + TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 => 0xc084, + TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 => 0xc085, + TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc086, + TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc087, + TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc088, + TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc089, + TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc08a, + TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc08b, + TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc08c, + TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc08d, + TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 => 0xc08e, + TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 => 0xc08f, + TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 => 0xc090, + TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 => 0xc091, + TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 => 0xc092, + TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 => 0xc093, + TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 => 0xc094, + TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 => 0xc095, + TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 => 0xc096, + TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 => 0xc097, + TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 => 0xc098, + TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 => 0xc099, + TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 => 0xc09a, + TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 => 0xc09b, + TLS_RSA_WITH_AES_128_CCM => 0xc09c, + TLS_RSA_WITH_AES_256_CCM => 0xc09d, + TLS_DHE_RSA_WITH_AES_128_CCM => 0xc09e, + TLS_DHE_RSA_WITH_AES_256_CCM => 0xc09f, + TLS_RSA_WITH_AES_128_CCM_8 => 0xc0a0, + TLS_RSA_WITH_AES_256_CCM_8 => 0xc0a1, + TLS_DHE_RSA_WITH_AES_128_CCM_8 => 0xc0a2, + TLS_DHE_RSA_WITH_AES_256_CCM_8 => 0xc0a3, + TLS_PSK_WITH_AES_128_CCM => 0xc0a4, + TLS_PSK_WITH_AES_256_CCM => 0xc0a5, + TLS_DHE_PSK_WITH_AES_128_CCM => 0xc0a6, + TLS_DHE_PSK_WITH_AES_256_CCM => 0xc0a7, + TLS_PSK_WITH_AES_128_CCM_8 => 0xc0a8, + TLS_PSK_WITH_AES_256_CCM_8 => 0xc0a9, + TLS_PSK_DHE_WITH_AES_128_CCM_8 => 0xc0aa, + TLS_PSK_DHE_WITH_AES_256_CCM_8 => 0xc0ab, + TLS_ECDHE_ECDSA_WITH_AES_128_CCM => 0xc0ac, + TLS_ECDHE_ECDSA_WITH_AES_256_CCM => 0xc0ad, + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 => 0xc0ae, + TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 => 0xc0af, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 => 0xcca8, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 => 0xcca9, + TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 => 0xccaa, + TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 => 0xccab, + TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 => 0xccac, + TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 => 0xccad, + TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 => 0xccae, + SSL_RSA_FIPS_WITH_DES_CBC_SHA => 0xfefe, + SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA => 0xfeff + } +} + +enum_builder! { + /// The `SignatureScheme` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U16 + EnumName: SignatureScheme; + EnumVal{ + RSA_PKCS1_SHA1 => 0x0201, + ECDSA_SHA1_Legacy => 0x0203, + RSA_PKCS1_SHA256 => 0x0401, + ECDSA_NISTP256_SHA256 => 0x0403, + RSA_PKCS1_SHA384 => 0x0501, + ECDSA_NISTP384_SHA384 => 0x0503, + RSA_PKCS1_SHA512 => 0x0601, + ECDSA_NISTP521_SHA512 => 0x0603, + RSA_PSS_SHA256 => 0x0804, + RSA_PSS_SHA384 => 0x0805, + RSA_PSS_SHA512 => 0x0806, + ED25519 => 0x0807, + ED448 => 0x0808 + } +} + +impl SignatureScheme { + pub(crate) fn sign(&self) -> SignatureAlgorithm { + match *self { + Self::RSA_PKCS1_SHA1 + | Self::RSA_PKCS1_SHA256 + | Self::RSA_PKCS1_SHA384 + | Self::RSA_PKCS1_SHA512 + | Self::RSA_PSS_SHA256 + | Self::RSA_PSS_SHA384 + | Self::RSA_PSS_SHA512 => SignatureAlgorithm::RSA, + Self::ECDSA_NISTP256_SHA256 + | Self::ECDSA_NISTP384_SHA384 + | Self::ECDSA_NISTP521_SHA512 => SignatureAlgorithm::ECDSA, + _ => SignatureAlgorithm::Unknown(0), + } + } +} + +enum_builder! { + /// The `SignatureAlgorithm` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: SignatureAlgorithm; + EnumVal{ + Anonymous => 0x00, + RSA => 0x01, + DSA => 0x02, + ECDSA => 0x03, + ED25519 => 0x07, + ED448 => 0x08 + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::msgs::enums::tests::test_enum8; + + #[test] + fn test_enums() { + test_enum8::(SignatureAlgorithm::Anonymous, SignatureAlgorithm::ECDSA); + test_enum8::(ContentType::ChangeCipherSpec, ContentType::Heartbeat); + test_enum8::(HandshakeType::HelloRequest, HandshakeType::MessageHash); + test_enum8::( + AlertDescription::CloseNotify, + AlertDescription::NoApplicationProtocol, + ); + } +} diff --git a/vendor/rustls-0.21.8/src/error.rs b/vendor/rustls-0.21.8/src/error.rs new file mode 100644 index 0000000000000..90b74d0e262fa --- /dev/null +++ b/vendor/rustls-0.21.8/src/error.rs @@ -0,0 +1,709 @@ +use crate::enums::{AlertDescription, ContentType, HandshakeType}; +use crate::msgs::handshake::KeyExchangeAlgorithm; +use crate::rand; + +use std::error::Error as StdError; +use std::fmt; +use std::sync::Arc; +use std::time::SystemTimeError; + +/// rustls reports protocol errors using this type. +#[non_exhaustive] +#[derive(Debug, PartialEq, Clone)] +pub enum Error { + /// We received a TLS message that isn't valid right now. + /// `expect_types` lists the message types we can expect right now. + /// `got_type` is the type we found. This error is typically + /// caused by a buggy TLS stack (the peer or this one), a broken + /// network, or an attack. + InappropriateMessage { + /// Which types we expected + expect_types: Vec, + /// What type we received + got_type: ContentType, + }, + + /// We received a TLS handshake message that isn't valid right now. + /// `expect_types` lists the handshake message types we can expect + /// right now. `got_type` is the type we found. + InappropriateHandshakeMessage { + /// Which handshake type we expected + expect_types: Vec, + /// What handshake type we received + got_type: HandshakeType, + }, + + /// The peer sent us a TLS message with invalid contents. + InvalidMessage(InvalidMessage), + + /// The peer didn't give us any certificates. + NoCertificatesPresented, + + /// The certificate verifier doesn't support the given type of name. + UnsupportedNameType, + + /// We couldn't decrypt a message. This is invariably fatal. + DecryptError, + + /// We couldn't encrypt a message because it was larger than the allowed message size. + /// This should never happen if the application is using valid record sizes. + EncryptError, + + /// The peer doesn't support a protocol version/feature we require. + /// The parameter gives a hint as to what version/feature it is. + PeerIncompatible(PeerIncompatible), + + /// The peer deviated from the standard TLS protocol. + /// The parameter gives a hint where. + PeerMisbehaved(PeerMisbehaved), + + /// We received a fatal alert. This means the peer is unhappy. + AlertReceived(AlertDescription), + + /// We saw an invalid certificate. + /// + /// The contained error is from the certificate validation trait + /// implementation. + InvalidCertificate(CertificateError), + + /// The presented SCT(s) were invalid. + InvalidSct(sct::Error), + + /// A provided certificate revocation list (CRL) was invalid. + InvalidCertRevocationList(CertRevocationListError), + + /// A catch-all error for unlikely errors. + General(String), + + /// We failed to figure out what time it currently is. + FailedToGetCurrentTime, + + /// We failed to acquire random bytes from the system. + FailedToGetRandomBytes, + + /// This function doesn't work until the TLS handshake + /// is complete. + HandshakeNotComplete, + + /// The peer sent an oversized record/fragment. + PeerSentOversizedRecord, + + /// An incoming connection did not support any known application protocol. + NoApplicationProtocol, + + /// The `max_fragment_size` value supplied in configuration was too small, + /// or too large. + BadMaxFragmentSize, +} + +/// A corrupt TLS message payload that resulted in an error. +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq)] + +pub enum InvalidMessage { + /// An advertised message was larger then expected. + HandshakePayloadTooLarge, + /// The peer sent us a syntactically incorrect ChangeCipherSpec payload. + InvalidCcs, + /// An unknown content type was encountered during message decoding. + InvalidContentType, + /// A peer sent an invalid certificate status type + InvalidCertificateStatusType, + /// Context was incorrectly attached to a certificate request during a handshake. + InvalidCertRequest, + /// A peer's DH params could not be decoded + InvalidDhParams, + /// A message was zero-length when its record kind forbids it. + InvalidEmptyPayload, + /// A peer sent an unexpected key update request. + InvalidKeyUpdate, + /// A peer's server name could not be decoded + InvalidServerName, + /// A TLS message payload was larger then allowed by the specification. + MessageTooLarge, + /// Message is shorter than the expected length + MessageTooShort, + /// Missing data for the named handshake payload value + MissingData(&'static str), + /// A peer did not advertise its supported key exchange groups. + MissingKeyExchange, + /// A peer sent an empty list of signature schemes + NoSignatureSchemes, + /// Trailing data found for the named handshake payload value + TrailingData(&'static str), + /// A peer sent an unexpected message type. + UnexpectedMessage(&'static str), + /// An unknown TLS protocol was encountered during message decoding. + UnknownProtocolVersion, + /// A peer sent a non-null compression method. + UnsupportedCompression, + /// A peer sent an unknown elliptic curve type. + UnsupportedCurveType, + /// A peer sent an unsupported key exchange algorithm. + UnsupportedKeyExchangeAlgorithm(KeyExchangeAlgorithm), +} + +impl From for Error { + #[inline] + fn from(e: InvalidMessage) -> Self { + Self::InvalidMessage(e) + } +} + +#[non_exhaustive] +#[allow(missing_docs)] +#[derive(Debug, PartialEq, Clone)] +/// The set of cases where we failed to make a connection because we thought +/// the peer was misbehaving. +/// +/// This is `non_exhaustive`: we might add or stop using items here in minor +/// versions. We also don't document what they mean. Generally a user of +/// rustls shouldn't vary its behaviour on these error codes, and there is +/// nothing it can do to improve matters. +/// +/// Please file a bug against rustls if you see `Error::PeerMisbehaved` in +/// the wild. +pub enum PeerMisbehaved { + AttemptedDowngradeToTls12WhenTls13IsSupported, + BadCertChainExtensions, + DisallowedEncryptedExtension, + DuplicateClientHelloExtensions, + DuplicateEncryptedExtensions, + DuplicateHelloRetryRequestExtensions, + DuplicateNewSessionTicketExtensions, + DuplicateServerHelloExtensions, + DuplicateServerNameTypes, + EarlyDataAttemptedInSecondClientHello, + EarlyDataExtensionWithoutResumption, + EarlyDataOfferedWithVariedCipherSuite, + HandshakeHashVariedAfterRetry, + IllegalHelloRetryRequestWithEmptyCookie, + IllegalHelloRetryRequestWithNoChanges, + IllegalHelloRetryRequestWithOfferedGroup, + IllegalHelloRetryRequestWithUnofferedCipherSuite, + IllegalHelloRetryRequestWithUnofferedNamedGroup, + IllegalHelloRetryRequestWithUnsupportedVersion, + IllegalHelloRetryRequestWithWrongSessionId, + IllegalMiddleboxChangeCipherSpec, + IllegalTlsInnerPlaintext, + IncorrectBinder, + InvalidMaxEarlyDataSize, + InvalidKeyShare, + InvalidSctList, + KeyEpochWithPendingFragment, + KeyUpdateReceivedInQuicConnection, + MessageInterleavedWithHandshakeMessage, + MissingBinderInPskExtension, + MissingKeyShare, + MissingPskModesExtension, + MissingQuicTransportParameters, + OfferedDuplicateKeyShares, + OfferedEarlyDataWithOldProtocolVersion, + OfferedEmptyApplicationProtocol, + OfferedIncorrectCompressions, + PskExtensionMustBeLast, + PskExtensionWithMismatchedIdsAndBinders, + RefusedToFollowHelloRetryRequest, + RejectedEarlyDataInterleavedWithHandshakeMessage, + ResumptionAttemptedWithVariedEms, + ResumptionOfferedWithVariedCipherSuite, + ResumptionOfferedWithVariedEms, + ResumptionOfferedWithIncompatibleCipherSuite, + SelectedDifferentCipherSuiteAfterRetry, + SelectedInvalidPsk, + SelectedTls12UsingTls13VersionExtension, + SelectedUnofferedApplicationProtocol, + SelectedUnofferedCipherSuite, + SelectedUnofferedCompression, + SelectedUnofferedKxGroup, + SelectedUnofferedPsk, + SelectedUnusableCipherSuiteForVersion, + ServerHelloMustOfferUncompressedEcPoints, + ServerNameDifferedOnRetry, + ServerNameMustContainOneHostName, + SignedKxWithWrongAlgorithm, + SignedHandshakeWithUnadvertisedSigScheme, + TooMuchEarlyDataReceived, + UnexpectedCleartextExtension, + UnsolicitedCertExtension, + UnsolicitedEncryptedExtension, + UnsolicitedSctList, + UnsolicitedServerHelloExtension, + WrongGroupForKeyShare, +} + +impl From for Error { + #[inline] + fn from(e: PeerMisbehaved) -> Self { + Self::PeerMisbehaved(e) + } +} + +#[non_exhaustive] +#[allow(missing_docs)] +#[derive(Debug, PartialEq, Clone)] +/// The set of cases where we failed to make a connection because a peer +/// doesn't support a TLS version/feature we require. +/// +/// This is `non_exhaustive`: we might add or stop using items here in minor +/// versions. +pub enum PeerIncompatible { + EcPointsExtensionRequired, + KeyShareExtensionRequired, + NamedGroupsExtensionRequired, + NoCertificateRequestSignatureSchemesInCommon, + NoCipherSuitesInCommon, + NoEcPointFormatsInCommon, + NoKxGroupsInCommon, + NoSignatureSchemesInCommon, + NullCompressionRequired, + ServerDoesNotSupportTls12Or13, + ServerSentHelloRetryRequestWithUnknownExtension, + ServerTlsVersionIsDisabledByOurConfig, + SignatureAlgorithmsExtensionRequired, + SupportedVersionsExtensionRequired, + Tls12NotOffered, + Tls12NotOfferedOrEnabled, + Tls13RequiredForQuic, + UncompressedEcPointsRequired, +} + +impl From for Error { + #[inline] + fn from(e: PeerIncompatible) -> Self { + Self::PeerIncompatible(e) + } +} + +#[non_exhaustive] +#[derive(Debug, Clone)] +/// The ways in which certificate validators can express errors. +/// +/// Note that the rustls TLS protocol code interprets specifically these +/// error codes to send specific TLS alerts. Therefore, if a +/// custom certificate validator uses incorrect errors the library as +/// a whole will send alerts that do not match the standard (this is usually +/// a minor issue, but could be misleading). +pub enum CertificateError { + /// The certificate is not correctly encoded. + BadEncoding, + + /// The current time is after the `notAfter` time in the certificate. + Expired, + + /// The current time is before the `notBefore` time in the certificate. + NotValidYet, + + /// The certificate has been revoked. + Revoked, + + /// The certificate contains an extension marked critical, but it was + /// not processed by the certificate validator. + UnhandledCriticalExtension, + + /// The certificate chain is not issued by a known root certificate. + UnknownIssuer, + + /// A certificate is not correctly signed by the key of its alleged + /// issuer. + BadSignature, + + /// The subject names in an end-entity certificate do not include + /// the expected name. + NotValidForName, + + /// The certificate is being used for a different purpose than allowed. + InvalidPurpose, + + /// The certificate is valid, but the handshake is rejected for other + /// reasons. + ApplicationVerificationFailure, + + /// Any other error. + /// + /// This can be used by custom verifiers to expose the underlying error + /// (where they are not better described by the more specific errors + /// above). + /// + /// It is also used by the default verifier in case its error is + /// not covered by the above common cases. + /// + /// Enums holding this variant will never compare equal to each other. + Other(Arc), +} + +impl PartialEq for CertificateError { + fn eq(&self, other: &Self) -> bool { + use CertificateError::*; + #[allow(clippy::match_like_matches_macro)] + match (self, other) { + (BadEncoding, BadEncoding) => true, + (Expired, Expired) => true, + (NotValidYet, NotValidYet) => true, + (Revoked, Revoked) => true, + (UnhandledCriticalExtension, UnhandledCriticalExtension) => true, + (UnknownIssuer, UnknownIssuer) => true, + (BadSignature, BadSignature) => true, + (NotValidForName, NotValidForName) => true, + (InvalidPurpose, InvalidPurpose) => true, + (ApplicationVerificationFailure, ApplicationVerificationFailure) => true, + _ => false, + } + } +} + +// The following mapping are heavily referenced in: +// * [OpenSSL Implementation](https://github.com/openssl/openssl/blob/45bb98bfa223efd3258f445ad443f878011450f0/ssl/statem/statem_lib.c#L1434) +// * [BoringSSL Implementation](https://github.com/google/boringssl/blob/583c60bd4bf76d61b2634a58bcda99a92de106cb/ssl/ssl_x509.cc#L1323) +impl From for AlertDescription { + fn from(e: CertificateError) -> Self { + use CertificateError::*; + match e { + BadEncoding | UnhandledCriticalExtension | NotValidForName => Self::BadCertificate, + // RFC 5246/RFC 8446 + // certificate_expired + // A certificate has expired or **is not currently valid**. + Expired | NotValidYet => Self::CertificateExpired, + Revoked => Self::CertificateRevoked, + UnknownIssuer => Self::UnknownCA, + BadSignature => Self::DecryptError, + InvalidPurpose => Self::UnsupportedCertificate, + ApplicationVerificationFailure => Self::AccessDenied, + // RFC 5246/RFC 8446 + // certificate_unknown + // Some other (unspecified) issue arose in processing the + // certificate, rendering it unacceptable. + Other(_) => Self::CertificateUnknown, + } + } +} + +impl From for Error { + #[inline] + fn from(e: CertificateError) -> Self { + Self::InvalidCertificate(e) + } +} + +#[non_exhaustive] +#[derive(Debug, Clone)] +/// The ways in which a certificate revocation list (CRL) can be invalid. +pub enum CertRevocationListError { + /// The CRL had a bad, or unsupported signature from its issuer. + BadSignature, + + /// The CRL contained an invalid CRL number. + InvalidCrlNumber, + + /// The CRL contained a revoked certificate with an invalid serial number. + InvalidRevokedCertSerialNumber, + + /// The CRL issuer does not specify the cRLSign key usage. + IssuerInvalidForCrl, + + /// The CRL is invalid for some other reason. + /// + /// Enums holding this variant will never compare equal to each other. + Other(Arc), + + /// The CRL is not correctly encoded. + ParseError, + + /// The CRL is not a v2 X.509 CRL. + UnsupportedCrlVersion, + + /// The CRL, or a revoked certificate in the CRL, contained an unsupported critical extension. + UnsupportedCriticalExtension, + + /// The CRL is an unsupported delta CRL, containing only changes relative to another CRL. + UnsupportedDeltaCrl, + + /// The CRL is an unsupported indirect CRL, containing revoked certificates issued by a CA + /// other than the issuer of the CRL. + UnsupportedIndirectCrl, + + /// The CRL contained a revoked certificate with an unsupported revocation reason. + /// See RFC 5280 Section 5.3.1[^1] for a list of supported revocation reasons. + /// + /// [^1]: + UnsupportedRevocationReason, +} + +impl PartialEq for CertRevocationListError { + fn eq(&self, other: &Self) -> bool { + use CertRevocationListError::*; + #[allow(clippy::match_like_matches_macro)] + match (self, other) { + (BadSignature, BadSignature) => true, + (InvalidCrlNumber, InvalidCrlNumber) => true, + (InvalidRevokedCertSerialNumber, InvalidRevokedCertSerialNumber) => true, + (IssuerInvalidForCrl, IssuerInvalidForCrl) => true, + (ParseError, ParseError) => true, + (UnsupportedCrlVersion, UnsupportedCrlVersion) => true, + (UnsupportedCriticalExtension, UnsupportedCriticalExtension) => true, + (UnsupportedDeltaCrl, UnsupportedDeltaCrl) => true, + (UnsupportedIndirectCrl, UnsupportedIndirectCrl) => true, + (UnsupportedRevocationReason, UnsupportedRevocationReason) => true, + _ => false, + } + } +} + +impl From for CertRevocationListError { + fn from(e: webpki::Error) -> Self { + use webpki::Error::*; + match e { + InvalidCrlSignatureForPublicKey + | UnsupportedCrlSignatureAlgorithm + | UnsupportedCrlSignatureAlgorithmForPublicKey => Self::BadSignature, + InvalidCrlNumber => Self::InvalidCrlNumber, + InvalidSerialNumber => Self::InvalidRevokedCertSerialNumber, + IssuerNotCrlSigner => Self::IssuerInvalidForCrl, + MalformedExtensions | BadDer | BadDerTime => Self::ParseError, + UnsupportedCriticalExtension => Self::UnsupportedCriticalExtension, + UnsupportedCrlVersion => Self::UnsupportedCrlVersion, + UnsupportedDeltaCrl => Self::UnsupportedDeltaCrl, + UnsupportedIndirectCrl => Self::UnsupportedIndirectCrl, + UnsupportedRevocationReason => Self::UnsupportedRevocationReason, + + _ => Self::Other(Arc::new(e)), + } + } +} + +impl From for Error { + #[inline] + fn from(e: CertRevocationListError) -> Self { + Self::InvalidCertRevocationList(e) + } +} + +fn join(items: &[T]) -> String { + items + .iter() + .map(|x| format!("{:?}", x)) + .collect::>() + .join(" or ") +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::InappropriateMessage { + ref expect_types, + ref got_type, + } => write!( + f, + "received unexpected message: got {:?} when expecting {}", + got_type, + join::(expect_types) + ), + Self::InappropriateHandshakeMessage { + ref expect_types, + ref got_type, + } => write!( + f, + "received unexpected handshake message: got {:?} when expecting {}", + got_type, + join::(expect_types) + ), + Self::InvalidMessage(ref typ) => { + write!(f, "received corrupt message of type {:?}", typ) + } + Self::PeerIncompatible(ref why) => write!(f, "peer is incompatible: {:?}", why), + Self::PeerMisbehaved(ref why) => write!(f, "peer misbehaved: {:?}", why), + Self::AlertReceived(ref alert) => write!(f, "received fatal alert: {:?}", alert), + Self::InvalidCertificate(ref err) => { + write!(f, "invalid peer certificate: {:?}", err) + } + Self::InvalidCertRevocationList(ref err) => { + write!(f, "invalid certificate revocation list: {:?}", err) + } + Self::NoCertificatesPresented => write!(f, "peer sent no certificates"), + Self::UnsupportedNameType => write!(f, "presented server name type wasn't supported"), + Self::DecryptError => write!(f, "cannot decrypt peer's message"), + Self::EncryptError => write!(f, "cannot encrypt message"), + Self::PeerSentOversizedRecord => write!(f, "peer sent excess record size"), + Self::HandshakeNotComplete => write!(f, "handshake not complete"), + Self::NoApplicationProtocol => write!(f, "peer doesn't support any known protocol"), + Self::InvalidSct(ref err) => write!(f, "invalid certificate timestamp: {:?}", err), + Self::FailedToGetCurrentTime => write!(f, "failed to get current time"), + Self::FailedToGetRandomBytes => write!(f, "failed to get random bytes"), + Self::BadMaxFragmentSize => { + write!(f, "the supplied max_fragment_size was too small or large") + } + Self::General(ref err) => write!(f, "unexpected error: {}", err), + } + } +} + +impl From for Error { + #[inline] + fn from(_: SystemTimeError) -> Self { + Self::FailedToGetCurrentTime + } +} + +impl StdError for Error {} + +impl From for Error { + fn from(_: rand::GetRandomFailed) -> Self { + Self::FailedToGetRandomBytes + } +} + +#[cfg(test)] +mod tests { + use super::{Error, InvalidMessage}; + use crate::error::CertRevocationListError; + + #[test] + fn certificate_error_equality() { + use super::CertificateError::*; + assert_eq!(BadEncoding, BadEncoding); + assert_eq!(Expired, Expired); + assert_eq!(NotValidYet, NotValidYet); + assert_eq!(Revoked, Revoked); + assert_eq!(UnhandledCriticalExtension, UnhandledCriticalExtension); + assert_eq!(UnknownIssuer, UnknownIssuer); + assert_eq!(BadSignature, BadSignature); + assert_eq!(NotValidForName, NotValidForName); + assert_eq!(InvalidPurpose, InvalidPurpose); + assert_eq!( + ApplicationVerificationFailure, + ApplicationVerificationFailure + ); + let other = Other(std::sync::Arc::from(Box::from(""))); + assert_ne!(other, other); + assert_ne!(BadEncoding, Expired); + } + + #[test] + fn crl_error_equality() { + use super::CertRevocationListError::*; + assert_eq!(BadSignature, BadSignature); + assert_eq!(InvalidCrlNumber, InvalidCrlNumber); + assert_eq!( + InvalidRevokedCertSerialNumber, + InvalidRevokedCertSerialNumber + ); + assert_eq!(IssuerInvalidForCrl, IssuerInvalidForCrl); + assert_eq!(ParseError, ParseError); + assert_eq!(UnsupportedCriticalExtension, UnsupportedCriticalExtension); + assert_eq!(UnsupportedCrlVersion, UnsupportedCrlVersion); + assert_eq!(UnsupportedDeltaCrl, UnsupportedDeltaCrl); + assert_eq!(UnsupportedIndirectCrl, UnsupportedIndirectCrl); + assert_eq!(UnsupportedRevocationReason, UnsupportedRevocationReason); + let other = Other(std::sync::Arc::from(Box::from(""))); + assert_ne!(other, other); + assert_ne!(BadSignature, InvalidCrlNumber); + } + + #[test] + fn crl_error_from_webpki() { + use super::CertRevocationListError::*; + let testcases = &[ + (webpki::Error::InvalidCrlSignatureForPublicKey, BadSignature), + ( + webpki::Error::UnsupportedCrlSignatureAlgorithm, + BadSignature, + ), + ( + webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey, + BadSignature, + ), + (webpki::Error::InvalidCrlNumber, InvalidCrlNumber), + ( + webpki::Error::InvalidSerialNumber, + InvalidRevokedCertSerialNumber, + ), + (webpki::Error::IssuerNotCrlSigner, IssuerInvalidForCrl), + (webpki::Error::MalformedExtensions, ParseError), + (webpki::Error::BadDer, ParseError), + (webpki::Error::BadDerTime, ParseError), + ( + webpki::Error::UnsupportedCriticalExtension, + UnsupportedCriticalExtension, + ), + (webpki::Error::UnsupportedCrlVersion, UnsupportedCrlVersion), + (webpki::Error::UnsupportedDeltaCrl, UnsupportedDeltaCrl), + ( + webpki::Error::UnsupportedIndirectCrl, + UnsupportedIndirectCrl, + ), + ( + webpki::Error::UnsupportedRevocationReason, + UnsupportedRevocationReason, + ), + ]; + for t in testcases { + assert_eq!( + >::into(t.0), + t.1 + ); + } + + assert!(matches!( + >::into( + webpki::Error::NameConstraintViolation + ), + Other(_) + )); + } + + #[test] + fn smoke() { + use crate::enums::{AlertDescription, ContentType, HandshakeType}; + use sct; + + let all = vec![ + Error::InappropriateMessage { + expect_types: vec![ContentType::Alert], + got_type: ContentType::Handshake, + }, + Error::InappropriateHandshakeMessage { + expect_types: vec![HandshakeType::ClientHello, HandshakeType::Finished], + got_type: HandshakeType::ServerHello, + }, + Error::InvalidMessage(InvalidMessage::InvalidCcs), + Error::NoCertificatesPresented, + Error::DecryptError, + super::PeerIncompatible::Tls12NotOffered.into(), + super::PeerMisbehaved::UnsolicitedCertExtension.into(), + Error::AlertReceived(AlertDescription::ExportRestriction), + super::CertificateError::Expired.into(), + Error::InvalidSct(sct::Error::MalformedSct), + Error::General("undocumented error".to_string()), + Error::FailedToGetCurrentTime, + Error::FailedToGetRandomBytes, + Error::HandshakeNotComplete, + Error::PeerSentOversizedRecord, + Error::NoApplicationProtocol, + Error::BadMaxFragmentSize, + Error::InvalidCertRevocationList(CertRevocationListError::BadSignature), + ]; + + for err in all { + println!("{:?}:", err); + println!(" fmt '{}'", err); + } + } + + #[test] + fn rand_error_mapping() { + use super::rand; + let err: Error = rand::GetRandomFailed.into(); + assert_eq!(err, Error::FailedToGetRandomBytes); + } + + #[test] + fn time_error_mapping() { + use std::time::SystemTime; + + let time_error = SystemTime::UNIX_EPOCH + .duration_since(SystemTime::now()) + .unwrap_err(); + let err: Error = time_error.into(); + assert_eq!(err, Error::FailedToGetCurrentTime); + } +} diff --git a/vendor/rustls-0.21.8/src/hash_hs.rs b/vendor/rustls-0.21.8/src/hash_hs.rs new file mode 100644 index 0000000000000..3dd66b118c000 --- /dev/null +++ b/vendor/rustls-0.21.8/src/hash_hs.rs @@ -0,0 +1,240 @@ +use crate::msgs::codec::Codec; +use crate::msgs::handshake::HandshakeMessagePayload; +use crate::msgs::message::{Message, MessagePayload}; +use ring::digest; +use std::mem; + +/// Early stage buffering of handshake payloads. +/// +/// Before we know the hash algorithm to use to verify the handshake, we just buffer the messages. +/// During the handshake, we may restart the transcript due to a HelloRetryRequest, reverting +/// from the `HandshakeHash` to a `HandshakeHashBuffer` again. +pub(crate) struct HandshakeHashBuffer { + buffer: Vec, + client_auth_enabled: bool, +} + +impl HandshakeHashBuffer { + pub(crate) fn new() -> Self { + Self { + buffer: Vec::new(), + client_auth_enabled: false, + } + } + + /// We might be doing client auth, so need to keep a full + /// log of the handshake. + pub(crate) fn set_client_auth_enabled(&mut self) { + self.client_auth_enabled = true; + } + + /// Hash/buffer a handshake message. + pub(crate) fn add_message(&mut self, m: &Message) { + if let MessagePayload::Handshake { encoded, .. } = &m.payload { + self.buffer + .extend_from_slice(&encoded.0); + } + } + + /// Hash or buffer a byte slice. + #[cfg(test)] + fn update_raw(&mut self, buf: &[u8]) { + self.buffer.extend_from_slice(buf); + } + + /// Get the hash value if we were to hash `extra` too. + pub(crate) fn get_hash_given( + &self, + hash: &'static digest::Algorithm, + extra: &[u8], + ) -> digest::Digest { + let mut ctx = digest::Context::new(hash); + ctx.update(&self.buffer); + ctx.update(extra); + ctx.finish() + } + + /// We now know what hash function the verify_data will use. + pub(crate) fn start_hash(self, alg: &'static digest::Algorithm) -> HandshakeHash { + let mut ctx = digest::Context::new(alg); + ctx.update(&self.buffer); + HandshakeHash { + ctx, + client_auth: match self.client_auth_enabled { + true => Some(self.buffer), + false => None, + }, + } + } +} + +/// This deals with keeping a running hash of the handshake +/// payloads. This is computed by buffering initially. Once +/// we know what hash function we need to use we switch to +/// incremental hashing. +/// +/// For client auth, we also need to buffer all the messages. +/// This is disabled in cases where client auth is not possible. +pub(crate) struct HandshakeHash { + /// None before we know what hash function we're using + ctx: digest::Context, + + /// buffer for client-auth. + client_auth: Option>, +} + +impl HandshakeHash { + /// We decided not to do client auth after all, so discard + /// the transcript. + pub(crate) fn abandon_client_auth(&mut self) { + self.client_auth = None; + } + + /// Hash/buffer a handshake message. + pub(crate) fn add_message(&mut self, m: &Message) -> &mut Self { + if let MessagePayload::Handshake { encoded, .. } = &m.payload { + self.update_raw(&encoded.0); + } + self + } + + /// Hash or buffer a byte slice. + fn update_raw(&mut self, buf: &[u8]) -> &mut Self { + self.ctx.update(buf); + + if let Some(buffer) = &mut self.client_auth { + buffer.extend_from_slice(buf); + } + + self + } + + /// Get the hash value if we were to hash `extra` too, + /// using hash function `hash`. + pub(crate) fn get_hash_given(&self, extra: &[u8]) -> digest::Digest { + let mut ctx = self.ctx.clone(); + ctx.update(extra); + ctx.finish() + } + + pub(crate) fn into_hrr_buffer(self) -> HandshakeHashBuffer { + let old_hash = self.ctx.finish(); + let old_handshake_hash_msg = + HandshakeMessagePayload::build_handshake_hash(old_hash.as_ref()); + + HandshakeHashBuffer { + client_auth_enabled: self.client_auth.is_some(), + buffer: old_handshake_hash_msg.get_encoding(), + } + } + + /// Take the current hash value, and encapsulate it in a + /// 'handshake_hash' handshake message. Start this hash + /// again, with that message at the front. + pub(crate) fn rollup_for_hrr(&mut self) { + let ctx = &mut self.ctx; + + let old_ctx = mem::replace(ctx, digest::Context::new(ctx.algorithm())); + let old_hash = old_ctx.finish(); + let old_handshake_hash_msg = + HandshakeMessagePayload::build_handshake_hash(old_hash.as_ref()); + + self.update_raw(&old_handshake_hash_msg.get_encoding()); + } + + /// Get the current hash value. + pub(crate) fn get_current_hash(&self) -> digest::Digest { + self.ctx.clone().finish() + } + + /// Takes this object's buffer containing all handshake messages + /// so far. This method only works once; it resets the buffer + /// to empty. + #[cfg(feature = "tls12")] + pub(crate) fn take_handshake_buf(&mut self) -> Option> { + self.client_auth.take() + } + + /// The digest algorithm + pub(crate) fn algorithm(&self) -> &'static digest::Algorithm { + self.ctx.algorithm() + } +} + +#[cfg(test)] +mod test { + use super::HandshakeHashBuffer; + use ring::digest; + + #[test] + fn hashes_correctly() { + let mut hhb = HandshakeHashBuffer::new(); + hhb.update_raw(b"hello"); + assert_eq!(hhb.buffer.len(), 5); + let mut hh = hhb.start_hash(&digest::SHA256); + assert!(hh.client_auth.is_none()); + hh.update_raw(b"world"); + let h = hh.get_current_hash(); + let h = h.as_ref(); + assert_eq!(h[0], 0x93); + assert_eq!(h[1], 0x6a); + assert_eq!(h[2], 0x18); + assert_eq!(h[3], 0x5c); + } + + #[cfg(feature = "tls12")] + #[test] + fn buffers_correctly() { + let mut hhb = HandshakeHashBuffer::new(); + hhb.set_client_auth_enabled(); + hhb.update_raw(b"hello"); + assert_eq!(hhb.buffer.len(), 5); + let mut hh = hhb.start_hash(&digest::SHA256); + assert_eq!( + hh.client_auth + .as_ref() + .map(|buf| buf.len()), + Some(5) + ); + hh.update_raw(b"world"); + assert_eq!( + hh.client_auth + .as_ref() + .map(|buf| buf.len()), + Some(10) + ); + let h = hh.get_current_hash(); + let h = h.as_ref(); + assert_eq!(h[0], 0x93); + assert_eq!(h[1], 0x6a); + assert_eq!(h[2], 0x18); + assert_eq!(h[3], 0x5c); + let buf = hh.take_handshake_buf(); + assert_eq!(Some(b"helloworld".to_vec()), buf); + } + + #[test] + fn abandon() { + let mut hhb = HandshakeHashBuffer::new(); + hhb.set_client_auth_enabled(); + hhb.update_raw(b"hello"); + assert_eq!(hhb.buffer.len(), 5); + let mut hh = hhb.start_hash(&digest::SHA256); + assert_eq!( + hh.client_auth + .as_ref() + .map(|buf| buf.len()), + Some(5) + ); + hh.abandon_client_auth(); + assert_eq!(hh.client_auth, None); + hh.update_raw(b"world"); + assert_eq!(hh.client_auth, None); + let h = hh.get_current_hash(); + let h = h.as_ref(); + assert_eq!(h[0], 0x93); + assert_eq!(h[1], 0x6a); + assert_eq!(h[2], 0x18); + assert_eq!(h[3], 0x5c); + } +} diff --git a/vendor/rustls-0.21.8/src/key.rs b/vendor/rustls-0.21.8/src/key.rs new file mode 100644 index 0000000000000..1efe50cb74c3a --- /dev/null +++ b/vendor/rustls-0.21.8/src/key.rs @@ -0,0 +1,127 @@ +use std::fmt; + +use crate::Error; + +/// This type contains a private key by value. +/// +/// The private key must be DER-encoded ASN.1 in either +/// PKCS#8, PKCS#1, or Sec1 format. +/// +/// A common format for storing private keys is +/// [PEM](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail). +/// PEM private keys are commonly stored in files with a `.pem` or `.key` suffix, and look like this: +/// +/// ```txt +/// -----BEGIN PRIVATE KEY----- +/// +/// -----END PRIVATE KEY----- +/// ``` +/// +/// The [`rustls-pemfile`](https://docs.rs/rustls-pemfile/latest/rustls_pemfile/) crate can be used +/// to parse PEM files. The [`rcgen`](https://docs.rs/rcgen/latest/rcgen/) can be used to generate +/// certificates and private keys. +/// +/// ## Examples +/// +/// Creating a `PrivateKey` from a PEM file containing a PKCS8-encoded private key using the `rustls_pemfile` crate: +/// +/// ```rust +/// use std::fs::File; +/// use std::io::BufReader; +/// use rustls::PrivateKey; +/// +/// fn load_private_key_from_file(path: &str) -> Result> { +/// let file = File::open(&path)?; +/// let mut reader = BufReader::new(file); +/// let mut keys = rustls_pemfile::pkcs8_private_keys(&mut reader)?; +/// +/// match keys.len() { +/// 0 => Err(format!("No PKCS8-encoded private key found in {path}").into()), +/// 1 => Ok(PrivateKey(keys.remove(0))), +/// _ => Err(format!("More than one PKCS8-encoded private key found in {path}").into()), +/// } +/// } +/// ``` +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct PrivateKey(pub Vec); + +/// This type contains a single certificate by value. +/// +/// The certificate must be in DER-encoded X.509 format. +/// +/// A common format for storing certificates is +/// [PEM](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail). +/// PEM certificates are commonly stored in files with a `.pem`, `.cer` or `.crt` suffix, and look +/// like this: +/// +/// ```txt +/// -----BEGIN CERTIFICATE----- +/// +/// -----END CERTIFICATE----- +/// ``` +/// +/// The [`rustls-pemfile`](https://docs.rs/rustls-pemfile/latest/rustls_pemfile/) crate can be used +/// to parse PEM files. The [`rcgen`](https://docs.rs/rcgen/latest/rcgen/) crate can be used to +/// generate certificates and private keys. +/// +/// ## Examples +/// +/// Parsing a PEM file to extract DER-encoded certificates: +/// +/// ```rust +/// use std::fs::File; +/// use std::io::BufReader; +/// use rustls::Certificate; +/// +/// fn load_certificates_from_pem(path: &str) -> std::io::Result> { +/// let file = File::open(path)?; +/// let mut reader = BufReader::new(file); +/// let certs = rustls_pemfile::certs(&mut reader)?; +/// +/// Ok(certs.into_iter().map(Certificate).collect()) +/// } +/// ``` +#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Certificate(pub Vec); + +impl AsRef<[u8]> for Certificate { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl fmt::Debug for Certificate { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use super::bs_debug::BsDebug; + f.debug_tuple("Certificate") + .field(&BsDebug(&self.0)) + .finish() + } +} + +/// wrapper around internal representation of a parsed certificate. This is used in order to avoid parsing twice when specifying custom verification +#[cfg_attr(not(feature = "dangerous_configuration"), allow(unreachable_pub))] +#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] +pub struct ParsedCertificate<'a>(pub(crate) webpki::EndEntityCert<'a>); + +impl<'a> TryFrom<&'a Certificate> for ParsedCertificate<'a> { + type Error = Error; + fn try_from(value: &'a Certificate) -> Result, Self::Error> { + webpki::EndEntityCert::try_from(value.0.as_ref()) + .map_err(crate::verify::pki_error) + .map(ParsedCertificate) + } +} + +#[cfg(test)] +mod test { + use super::Certificate; + + #[test] + fn certificate_debug() { + assert_eq!( + "Certificate(b\"ab\")", + format!("{:?}", Certificate(b"ab".to_vec())) + ); + } +} diff --git a/vendor/rustls-0.21.8/src/key_log.rs b/vendor/rustls-0.21.8/src/key_log.rs new file mode 100644 index 0000000000000..1b6b3fec709dd --- /dev/null +++ b/vendor/rustls-0.21.8/src/key_log.rs @@ -0,0 +1,55 @@ +/// This trait represents the ability to do something useful +/// with key material, such as logging it to a file for debugging. +/// +/// Naturally, secrets passed over the interface are *extremely* +/// sensitive and can break the security of past, present and +/// future sessions. +/// +/// You'll likely want some interior mutability in your +/// implementation to make this useful. +/// +/// See [`KeyLogFile`](crate::KeyLogFile) that implements the standard +/// `SSLKEYLOGFILE` environment variable behaviour. +pub trait KeyLog: Send + Sync { + /// Log the given `secret`. `client_random` is provided for + /// session identification. `label` describes precisely what + /// `secret` means: + /// + /// - `CLIENT_RANDOM`: `secret` is the master secret for a TLSv1.2 session. + /// - `CLIENT_EARLY_TRAFFIC_SECRET`: `secret` encrypts early data + /// transmitted by a client + /// - `SERVER_HANDSHAKE_TRAFFIC_SECRET`: `secret` encrypts + /// handshake messages from the server during a TLSv1.3 handshake. + /// - `CLIENT_HANDSHAKE_TRAFFIC_SECRET`: `secret` encrypts + /// handshake messages from the client during a TLSv1.3 handshake. + /// - `SERVER_TRAFFIC_SECRET_0`: `secret` encrypts post-handshake data + /// from the server in a TLSv1.3 session. + /// - `CLIENT_TRAFFIC_SECRET_0`: `secret` encrypts post-handshake data + /// from the client in a TLSv1.3 session. + /// - `EXPORTER_SECRET`: `secret` is the post-handshake exporter secret + /// in a TLSv1.3 session. + /// + /// These strings are selected to match the NSS key log format: + /// + fn log(&self, label: &str, client_random: &[u8], secret: &[u8]); + + /// Indicates whether the secret with label `label` will be logged. + /// + /// If `will_log` returns true then `log` will be called with the secret. + /// Otherwise, `log` will not be called for the secret. This is a + /// performance optimization. + fn will_log(&self, _label: &str) -> bool { + true + } +} + +/// KeyLog that does exactly nothing. +pub struct NoKeyLog; + +impl KeyLog for NoKeyLog { + fn log(&self, _: &str, _: &[u8], _: &[u8]) {} + #[inline] + fn will_log(&self, _label: &str) -> bool { + false + } +} diff --git a/vendor/rustls-0.21.8/src/key_log_file.rs b/vendor/rustls-0.21.8/src/key_log_file.rs new file mode 100644 index 0000000000000..79071131bcf69 --- /dev/null +++ b/vendor/rustls-0.21.8/src/key_log_file.rs @@ -0,0 +1,154 @@ +#[cfg(feature = "logging")] +use crate::log::warn; +use crate::KeyLog; +use std::env; +use std::fs::{File, OpenOptions}; +use std::io; +use std::io::Write; +use std::path::Path; +use std::sync::Mutex; + +// Internal mutable state for KeyLogFile +struct KeyLogFileInner { + file: Option, + buf: Vec, +} + +impl KeyLogFileInner { + fn new(var: Result) -> Self { + let path = match var { + Ok(ref s) => Path::new(s), + Err(env::VarError::NotUnicode(ref s)) => Path::new(s), + Err(env::VarError::NotPresent) => { + return Self { + file: None, + buf: Vec::new(), + }; + } + }; + + #[cfg_attr(not(feature = "logging"), allow(unused_variables))] + let file = match OpenOptions::new() + .append(true) + .create(true) + .open(path) + { + Ok(f) => Some(f), + Err(e) => { + warn!("unable to create key log file {:?}: {}", path, e); + None + } + }; + + Self { + file, + buf: Vec::new(), + } + } + + fn try_write(&mut self, label: &str, client_random: &[u8], secret: &[u8]) -> io::Result<()> { + let mut file = match self.file { + None => { + return Ok(()); + } + Some(ref f) => f, + }; + + self.buf.truncate(0); + write!(self.buf, "{} ", label)?; + for b in client_random.iter() { + write!(self.buf, "{:02x}", b)?; + } + write!(self.buf, " ")?; + for b in secret.iter() { + write!(self.buf, "{:02x}", b)?; + } + writeln!(self.buf)?; + file.write_all(&self.buf) + } +} + +/// [`KeyLog`] implementation that opens a file whose name is +/// given by the `SSLKEYLOGFILE` environment variable, and writes +/// keys into it. +/// +/// If `SSLKEYLOGFILE` is not set, this does nothing. +/// +/// If such a file cannot be opened, or cannot be written then +/// this does nothing but logs errors at warning-level. +pub struct KeyLogFile(Mutex); + +impl KeyLogFile { + /// Makes a new `KeyLogFile`. The environment variable is + /// inspected and the named file is opened during this call. + pub fn new() -> Self { + let var = env::var("SSLKEYLOGFILE"); + Self(Mutex::new(KeyLogFileInner::new(var))) + } +} + +impl KeyLog for KeyLogFile { + fn log(&self, label: &str, client_random: &[u8], secret: &[u8]) { + #[cfg_attr(not(feature = "logging"), allow(unused_variables))] + match self + .0 + .lock() + .unwrap() + .try_write(label, client_random, secret) + { + Ok(()) => {} + Err(e) => { + warn!("error writing to key log file: {}", e); + } + } + } +} + +#[cfg(all(test, target_os = "linux"))] +mod test { + use super::*; + + fn init() { + let _ = env_logger::builder() + .is_test(true) + .try_init(); + } + + #[test] + fn test_env_var_is_not_unicode() { + init(); + let mut inner = KeyLogFileInner::new(Err(env::VarError::NotUnicode( + "/tmp/keylogfileinnertest".into(), + ))); + assert!(inner + .try_write("label", b"random", b"secret") + .is_ok()); + } + + #[test] + fn test_env_var_is_not_set() { + init(); + let mut inner = KeyLogFileInner::new(Err(env::VarError::NotPresent)); + assert!(inner + .try_write("label", b"random", b"secret") + .is_ok()); + } + + #[test] + fn test_env_var_cannot_be_opened() { + init(); + let mut inner = KeyLogFileInner::new(Ok("/dev/does-not-exist".into())); + assert!(inner + .try_write("label", b"random", b"secret") + .is_ok()); + } + + #[test] + fn test_env_var_cannot_be_written() { + init(); + let mut inner = KeyLogFileInner::new(Ok("/dev/full".into())); + assert!(inner + .try_write("label", b"random", b"secret") + .is_err()); + } +} diff --git a/vendor/rustls-0.21.8/src/kx.rs b/vendor/rustls-0.21.8/src/kx.rs new file mode 100644 index 0000000000000..e16a49d02ff9d --- /dev/null +++ b/vendor/rustls-0.21.8/src/kx.rs @@ -0,0 +1,96 @@ +use std::fmt; + +use crate::error::{Error, PeerMisbehaved}; +use crate::msgs::enums::NamedGroup; + +/// An in-progress key exchange. This has the algorithm, +/// our private key, and our public key. +pub(crate) struct KeyExchange { + skxg: &'static SupportedKxGroup, + privkey: ring::agreement::EphemeralPrivateKey, + pub(crate) pubkey: ring::agreement::PublicKey, +} + +impl KeyExchange { + /// Choose a SupportedKxGroup by name, from a list of supported groups. + pub(crate) fn choose( + name: NamedGroup, + supported: &[&'static SupportedKxGroup], + ) -> Option<&'static SupportedKxGroup> { + supported + .iter() + .find(|skxg| skxg.name == name) + .cloned() + } + + /// Start a key exchange, using the given SupportedKxGroup. + /// + /// This generates an ephemeral key pair and stores it in the returned KeyExchange object. + pub(crate) fn start(skxg: &'static SupportedKxGroup) -> Option { + let rng = ring::rand::SystemRandom::new(); + let ours = + ring::agreement::EphemeralPrivateKey::generate(skxg.agreement_algorithm, &rng).ok()?; + + let pubkey = ours.compute_public_key().ok()?; + + Some(Self { + skxg, + privkey: ours, + pubkey, + }) + } + + /// Return the group being used. + pub(crate) fn group(&self) -> NamedGroup { + self.skxg.name + } + + /// Completes the key exchange, given the peer's public key. + /// + /// The shared secret is passed into the closure passed down in `f`, and the result of calling + /// `f` is returned to the caller. + pub(crate) fn complete(self, peer: &[u8], f: impl FnOnce(&[u8]) -> T) -> Result { + let peer_key = ring::agreement::UnparsedPublicKey::new(self.skxg.agreement_algorithm, peer); + ring::agreement::agree_ephemeral(self.privkey, &peer_key, f) + .map_err(|_| PeerMisbehaved::InvalidKeyShare.into()) + } +} + +/// A key-exchange group supported by rustls. +/// +/// All possible instances of this class are provided by the library in +/// the `ALL_KX_GROUPS` array. +pub struct SupportedKxGroup { + /// The IANA "TLS Supported Groups" name of the group + pub name: NamedGroup, + + /// The corresponding ring agreement::Algorithm + agreement_algorithm: &'static ring::agreement::Algorithm, +} + +impl fmt::Debug for SupportedKxGroup { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.name.fmt(f) + } +} + +/// Ephemeral ECDH on curve25519 (see RFC7748) +pub static X25519: SupportedKxGroup = SupportedKxGroup { + name: NamedGroup::X25519, + agreement_algorithm: &ring::agreement::X25519, +}; + +/// Ephemeral ECDH on secp256r1 (aka NIST-P256) +pub static SECP256R1: SupportedKxGroup = SupportedKxGroup { + name: NamedGroup::secp256r1, + agreement_algorithm: &ring::agreement::ECDH_P256, +}; + +/// Ephemeral ECDH on secp384r1 (aka NIST-P384) +pub static SECP384R1: SupportedKxGroup = SupportedKxGroup { + name: NamedGroup::secp384r1, + agreement_algorithm: &ring::agreement::ECDH_P384, +}; + +/// A list of all the key exchange groups supported by rustls. +pub static ALL_KX_GROUPS: [&SupportedKxGroup; 3] = [&X25519, &SECP256R1, &SECP384R1]; diff --git a/vendor/rustls-0.21.8/src/lib.rs b/vendor/rustls-0.21.8/src/lib.rs new file mode 100644 index 0000000000000..6e4749aa6bfa0 --- /dev/null +++ b/vendor/rustls-0.21.8/src/lib.rs @@ -0,0 +1,530 @@ +//! # Rustls - a modern TLS library +//! Rustls is a TLS library that aims to provide a good level of cryptographic security, +//! requires no configuration to achieve that security, and provides no unsafe features or +//! obsolete cryptography. +//! +//! ## Current features +//! +//! * TLS1.2 and TLS1.3. +//! * ECDSA, Ed25519 or RSA server authentication by clients. +//! * ECDSA, Ed25519 or RSA server authentication by servers. +//! * Forward secrecy using ECDHE; with curve25519, nistp256 or nistp384 curves. +//! * AES128-GCM and AES256-GCM bulk encryption, with safe nonces. +//! * ChaCha20-Poly1305 bulk encryption ([RFC7905](https://tools.ietf.org/html/rfc7905)). +//! * ALPN support. +//! * SNI support. +//! * Tunable fragment size to make TLS messages match size of underlying transport. +//! * Optional use of vectored IO to minimise system calls. +//! * TLS1.2 session resumption. +//! * TLS1.2 resumption via tickets ([RFC5077](https://tools.ietf.org/html/rfc5077)). +//! * TLS1.3 resumption via tickets or session storage. +//! * TLS1.3 0-RTT data for clients. +//! * TLS1.3 0-RTT data for servers. +//! * Client authentication by clients. +//! * Client authentication by servers. +//! * Extended master secret support ([RFC7627](https://tools.ietf.org/html/rfc7627)). +//! * Exporters ([RFC5705](https://tools.ietf.org/html/rfc5705)). +//! * OCSP stapling by servers. +//! * SCT stapling by servers. +//! * SCT verification by clients. +//! +//! ## Possible future features +//! +//! * PSK support. +//! * OCSP verification by clients. +//! * Certificate pinning. +//! +//! ## Non-features +//! +//! For reasons [explained in the manual](manual), +//! rustls does not and will not support: +//! +//! * SSL1, SSL2, SSL3, TLS1 or TLS1.1. +//! * RC4. +//! * DES or triple DES. +//! * EXPORT ciphersuites. +//! * MAC-then-encrypt ciphersuites. +//! * Ciphersuites without forward secrecy. +//! * Renegotiation. +//! * Kerberos. +//! * Compression. +//! * Discrete-log Diffie-Hellman. +//! * Automatic protocol version downgrade. +//! +//! There are plenty of other libraries that provide these features should you +//! need them. +//! +//! ### Platform support +//! +//! While Rustls itself is platform independent it uses +//! [`ring`](https://crates.io/crates/ring) for implementing the cryptography in +//! TLS. As a result, rustls only runs on platforms +//! supported by `ring`. At the time of writing, this means 32-bit ARM, Aarch64 (64-bit ARM), +//! x86, x86-64, LoongArch64, 32-bit & 64-bit Little Endian MIPS, 32-bit PowerPC (Big Endian), +//! 64-bit PowerPC (Big and Little Endian), 64-bit RISC-V, and s390x. We do not presently +//! support WebAssembly. +//! For more information, see [the supported `ring` target platforms][ring-target-platforms]. +//! +//! Rustls requires Rust 1.61 or later. +//! +//! [ring-target-platforms]: https://github.com/briansmith/ring/blob/2e8363b433fa3b3962c877d9ed2e9145612f3160/include/ring-core/target.h#L18-L64 +//! +//! ## Design Overview +//! ### Rustls does not take care of network IO +//! It doesn't make or accept TCP connections, or do DNS, or read or write files. +//! +//! There's example client and server code which uses mio to do all needed network +//! IO. +//! +//! ### Rustls provides encrypted pipes +//! These are the [`ServerConnection`] and [`ClientConnection`] types. You supply raw TLS traffic +//! on the left (via the [`read_tls()`] and [`write_tls()`] methods) and then read/write the +//! plaintext on the right: +//! +//! [`read_tls()`]: Connection::read_tls +//! [`write_tls()`]: Connection::read_tls +//! +//! ```text +//! TLS Plaintext +//! === ========= +//! read_tls() +-----------------------+ reader() as io::Read +//! | | +//! +---------> ClientConnection +---------> +//! | or | +//! <---------+ ServerConnection <---------+ +//! | | +//! write_tls() +-----------------------+ writer() as io::Write +//! ``` +//! +//! ### Rustls takes care of server certificate verification +//! You do not need to provide anything other than a set of root certificates to trust. +//! Certificate verification cannot be turned off or disabled in the main API. +//! +//! ## Getting started +//! This is the minimum you need to do to make a TLS client connection. +//! +//! First we load some root certificates. These are used to authenticate the server. +//! The recommended way is to depend on the `webpki_roots` crate which contains +//! the Mozilla set of root certificates. +//! +//! ```rust,no_run +//! let mut root_store = rustls::RootCertStore::empty(); +//! root_store.add_trust_anchors( +//! webpki_roots::TLS_SERVER_ROOTS +//! .iter() +//! .map(|ta| { +//! rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( +//! ta.subject, +//! ta.spki, +//! ta.name_constraints, +//! ) +//! }) +//! ); +//! ``` +//! +//! Next, we make a `ClientConfig`. You're likely to make one of these per process, +//! and use it for all connections made by that process. +//! +//! ```rust,no_run +//! # let root_store: rustls::RootCertStore = panic!(); +//! let config = rustls::ClientConfig::builder() +//! .with_safe_defaults() +//! .with_root_certificates(root_store) +//! .with_no_client_auth(); +//! ``` +//! +//! Now we can make a connection. You need to provide the server's hostname so we +//! know what to expect to find in the server's certificate. +//! +//! ```rust +//! # use rustls; +//! # use webpki; +//! # use std::sync::Arc; +//! # let mut root_store = rustls::RootCertStore::empty(); +//! # root_store.add_trust_anchors( +//! # webpki_roots::TLS_SERVER_ROOTS +//! # .iter() +//! # .map(|ta| { +//! # rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( +//! # ta.subject, +//! # ta.spki, +//! # ta.name_constraints, +//! # ) +//! # }) +//! # ); +//! # let config = rustls::ClientConfig::builder() +//! # .with_safe_defaults() +//! # .with_root_certificates(root_store) +//! # .with_no_client_auth(); +//! let rc_config = Arc::new(config); +//! let example_com = "example.com".try_into().unwrap(); +//! let mut client = rustls::ClientConnection::new(rc_config, example_com); +//! ``` +//! +//! Now you should do appropriate IO for the `client` object. If `client.wants_read()` yields +//! true, you should call `client.read_tls()` when the underlying connection has data. +//! Likewise, if `client.wants_write()` yields true, you should call `client.write_tls()` +//! when the underlying connection is able to send data. You should continue doing this +//! as long as the connection is valid. +//! +//! The return types of `read_tls()` and `write_tls()` only tell you if the IO worked. No +//! parsing or processing of the TLS messages is done. After each `read_tls()` you should +//! therefore call `client.process_new_packets()` which parses and processes the messages. +//! Any error returned from `process_new_packets` is fatal to the connection, and will tell you +//! why. For example, if the server's certificate is expired `process_new_packets` will +//! return `Err(InvalidCertificate(Expired))`. From this point on, +//! `process_new_packets` will not do any new work and will return that error continually. +//! +//! You can extract newly received data by calling `client.reader()` (which implements the +//! `io::Read` trait). You can send data to the peer by calling `client.writer()` (which +//! implements `io::Write` trait). Note that `client.writer().write()` buffers data you +//! send if the TLS connection is not yet established: this is useful for writing (say) a +//! HTTP request, but this is buffered so avoid large amounts of data. +//! +//! The following code uses a fictional socket IO API for illustration, and does not handle +//! errors. +//! +//! ```rust,no_run +//! # let mut client = rustls::ClientConnection::new(panic!(), panic!()).unwrap(); +//! # struct Socket { } +//! # impl Socket { +//! # fn ready_for_write(&self) -> bool { false } +//! # fn ready_for_read(&self) -> bool { false } +//! # fn wait_for_something_to_happen(&self) { } +//! # } +//! # +//! # use std::io::{Read, Write, Result}; +//! # impl Read for Socket { +//! # fn read(&mut self, buf: &mut [u8]) -> Result { panic!() } +//! # } +//! # impl Write for Socket { +//! # fn write(&mut self, buf: &[u8]) -> Result { panic!() } +//! # fn flush(&mut self) -> Result<()> { panic!() } +//! # } +//! # +//! # fn connect(_address: &str, _port: u16) -> Socket { +//! # panic!(); +//! # } +//! use std::io; +//! use rustls::Connection; +//! +//! client.writer().write(b"GET / HTTP/1.0\r\n\r\n").unwrap(); +//! let mut socket = connect("example.com", 443); +//! loop { +//! if client.wants_read() && socket.ready_for_read() { +//! client.read_tls(&mut socket).unwrap(); +//! client.process_new_packets().unwrap(); +//! +//! let mut plaintext = Vec::new(); +//! client.reader().read_to_end(&mut plaintext).unwrap(); +//! io::stdout().write(&plaintext).unwrap(); +//! } +//! +//! if client.wants_write() && socket.ready_for_write() { +//! client.write_tls(&mut socket).unwrap(); +//! } +//! +//! socket.wait_for_something_to_happen(); +//! } +//! ``` +//! +//! # Examples +//! [`tlsserver`](https://github.com/rustls/rustls/blob/main/examples/src/bin/tlsserver-mio.rs) +//! and [`tlsclient`](https://github.com/rustls/rustls/blob/main/examples/src/bin/tlsclient-mio.rs) +//! are full worked examples. These both use mio. +//! +//! # Crate features +//! Here's a list of what features are exposed by the rustls crate and what +//! they mean. +//! +//! - `logging`: this makes the rustls crate depend on the `log` crate. +//! rustls outputs interesting protocol-level messages at `trace!` and `debug!` +//! level, and protocol-level errors at `warn!` and `error!` level. The log +//! messages do not contain secret key data, and so are safe to archive without +//! affecting session security. This feature is in the default set. +//! +//! - `dangerous_configuration`: this feature enables a `dangerous()` method on +//! `ClientConfig` and `ServerConfig` that allows setting inadvisable options, +//! such as replacing the certificate verification process. Applications +//! requesting this feature should be reviewed carefully. +//! +//! - `quic`: this feature exposes additional constructors and functions +//! for using rustls as a TLS library for QUIC. See the `quic` module for +//! details of these. You will only need this if you're writing a QUIC +//! implementation. +//! +//! - `tls12`: enables support for TLS version 1.2. This feature is in the default +//! set. Note that, due to the additive nature of Cargo features and because it +//! is enabled by default, other crates in your dependency graph could re-enable +//! it for your application. If you want to disable TLS 1.2 for security reasons, +//! consider explicitly enabling TLS 1.3 only in the config builder API. +//! +//! - `read_buf`: When building with Rust Nightly, adds support for the unstable +//! `std::io::ReadBuf` and related APIs. This reduces costs from initializing +//! buffers. Will do nothing on non-Nightly releases. + +// Require docs for public APIs, deny unsafe code, etc. +#![forbid(unsafe_code, unused_must_use)] +#![cfg_attr(not(any(read_buf, bench)), forbid(unstable_features))] +#![deny( + clippy::clone_on_ref_ptr, + clippy::use_self, + trivial_casts, + trivial_numeric_casts, + missing_docs, + unreachable_pub, + unused_import_braces, + unused_extern_crates, + unused_qualifications +)] +// Relax these clippy lints: +// - ptr_arg: this triggers on references to type aliases that are Vec +// underneath. +// - too_many_arguments: some things just need a lot of state, wrapping it +// doesn't necessarily make it easier to follow what's going on +// - new_ret_no_self: we sometimes return `Arc`, which seems fine +// - single_component_path_imports: our top-level `use log` import causes +// a false positive, https://github.com/rust-lang/rust-clippy/issues/5210 +// - new_without_default: for internal constructors, the indirection is not +// helpful +#![allow( + clippy::too_many_arguments, + clippy::new_ret_no_self, + clippy::ptr_arg, + clippy::single_component_path_imports, + clippy::new_without_default +)] +// Enable documentation for all features on docs.rs +#![cfg_attr(docsrs, feature(doc_cfg))] +// XXX: Because of https://github.com/rust-lang/rust/issues/54726, we cannot +// write `#![rustversion::attr(nightly, feature(read_buf))]` here. Instead, +// build.rs set `read_buf` for (only) Rust Nightly to get the same effect. +// +// All the other conditional logic in the crate could use +// `#[rustversion::nightly]` instead of `#[cfg(read_buf)]`; `#[cfg(read_buf)]` +// is used to avoid needing `rustversion` to be compiled twice during +// cross-compiling. +#![cfg_attr(read_buf, feature(read_buf))] +#![cfg_attr(bench, feature(test))] + +// Import `test` sysroot crate for `Bencher` definitions. +#[cfg(bench)] +#[allow(unused_extern_crates)] +extern crate test; + +// log for logging (optional). +#[cfg(feature = "logging")] +use log; + +#[cfg(not(feature = "logging"))] +#[macro_use] +mod log { + macro_rules! trace ( ($($tt:tt)*) => {{}} ); + macro_rules! debug ( ($($tt:tt)*) => {{}} ); + macro_rules! warn ( ($($tt:tt)*) => {{}} ); +} + +#[macro_use] +mod msgs; +mod anchors; +mod cipher; +mod common_state; +mod conn; +mod dns_name; +mod error; +mod hash_hs; +mod limited_cache; +mod rand; +mod record_layer; +mod stream; +#[cfg(feature = "tls12")] +mod tls12; +mod tls13; +mod vecbuf; +mod verify; +#[cfg(test)] +mod verifybench; +mod x509; +#[macro_use] +mod check; +mod bs_debug; +mod builder; +mod enums; +mod key; +mod key_log; +mod key_log_file; +mod kx; +mod suites; +mod ticketer; +mod versions; + +/// Internal classes which may be useful outside the library. +/// The contents of this section DO NOT form part of the stable interface. +pub mod internal { + /// Low-level TLS message parsing and encoding functions. + pub mod msgs { + pub use crate::msgs::*; + } + /// Low-level TLS message decryption functions. + pub mod cipher { + pub use crate::cipher::MessageDecrypter; + } + /// Low-level TLS record layer functions. + pub mod record_layer { + pub use crate::record_layer::{Decrypted, RecordLayer}; + } +} + +// The public interface is: +pub use crate::anchors::{OwnedTrustAnchor, RootCertStore}; +pub use crate::builder::{ + ConfigBuilder, ConfigSide, WantsCipherSuites, WantsKxGroups, WantsVerifier, WantsVersions, +}; +pub use crate::common_state::{CommonState, IoState, Side}; +pub use crate::conn::{Connection, ConnectionCommon, Reader, SideData, Writer}; +pub use crate::enums::{ + AlertDescription, CipherSuite, ContentType, HandshakeType, ProtocolVersion, SignatureAlgorithm, + SignatureScheme, +}; +pub use crate::error::{ + CertRevocationListError, CertificateError, Error, InvalidMessage, PeerIncompatible, + PeerMisbehaved, +}; +pub use crate::key::{Certificate, PrivateKey}; +pub use crate::key_log::{KeyLog, NoKeyLog}; +pub use crate::key_log_file::KeyLogFile; +pub use crate::kx::{SupportedKxGroup, ALL_KX_GROUPS}; +pub use crate::msgs::enums::NamedGroup; +pub use crate::msgs::handshake::DistinguishedName; +pub use crate::stream::{Stream, StreamOwned}; +pub use crate::suites::{ + BulkAlgorithm, SupportedCipherSuite, ALL_CIPHER_SUITES, DEFAULT_CIPHER_SUITES, +}; +#[cfg(feature = "secret_extraction")] +#[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] +pub use crate::suites::{ConnectionTrafficSecrets, ExtractedSecrets}; +pub use crate::ticketer::Ticketer; +#[cfg(feature = "tls12")] +pub use crate::tls12::Tls12CipherSuite; +pub use crate::tls13::Tls13CipherSuite; +pub use crate::verify::DigitallySignedStruct; +pub use crate::versions::{SupportedProtocolVersion, ALL_VERSIONS, DEFAULT_VERSIONS}; + +/// Items for use in a client. +pub mod client { + pub(super) mod builder; + mod client_conn; + mod common; + pub(super) mod handy; + mod hs; + #[cfg(feature = "tls12")] + mod tls12; + mod tls13; + + pub use crate::dns_name::InvalidDnsNameError; + pub use builder::{WantsClientCert, WantsTransparencyPolicyOrClientCert}; + pub use client_conn::{ + ClientConfig, ClientConnection, ClientConnectionData, ClientSessionStore, + ResolvesClientCert, Resumption, ServerName, Tls12Resumption, WriteEarlyData, + }; + pub use handy::ClientSessionMemoryCache; + + #[cfg(feature = "dangerous_configuration")] + pub use crate::verify::{ + verify_server_cert_signed_by_trust_anchor, verify_server_name, + CertificateTransparencyPolicy, HandshakeSignatureValid, ServerCertVerified, + ServerCertVerifier, WebPkiVerifier, + }; + #[cfg(feature = "dangerous_configuration")] + pub use client_conn::danger::DangerousClientConfig; + + pub use crate::msgs::persist::Tls12ClientSessionValue; + pub use crate::msgs::persist::Tls13ClientSessionValue; +} + +pub use client::{ClientConfig, ClientConnection, ServerName}; + +/// Items for use in a server. +pub mod server { + pub(crate) mod builder; + mod common; + pub(crate) mod handy; + mod hs; + mod server_conn; + #[cfg(feature = "tls12")] + mod tls12; + mod tls13; + + pub use crate::verify::{ + AllowAnyAnonymousOrAuthenticatedClient, AllowAnyAuthenticatedClient, NoClientAuth, + UnparsedCertRevocationList, + }; + pub use builder::WantsServerCert; + pub use handy::ResolvesServerCertUsingSni; + pub use handy::{NoServerSessionStorage, ServerSessionMemoryCache}; + pub use server_conn::StoresServerSessions; + pub use server_conn::{ + Accepted, Acceptor, ReadEarlyData, ServerConfig, ServerConnection, ServerConnectionData, + }; + pub use server_conn::{ClientHello, ProducesTickets, ResolvesServerCert}; + + #[cfg(feature = "dangerous_configuration")] + pub use crate::dns_name::DnsName; + #[cfg(feature = "dangerous_configuration")] + pub use crate::key::ParsedCertificate; + #[cfg(feature = "dangerous_configuration")] + pub use crate::verify::{ClientCertVerified, ClientCertVerifier}; +} + +pub use server::{ServerConfig, ServerConnection}; + +/// All defined ciphersuites appear in this module. +/// +/// [`ALL_CIPHER_SUITES`] is provided as an array of all of these values. +pub mod cipher_suite { + pub use crate::suites::CipherSuiteCommon; + #[cfg(feature = "tls12")] + pub use crate::tls12::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; + #[cfg(feature = "tls12")] + pub use crate::tls12::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; + #[cfg(feature = "tls12")] + pub use crate::tls12::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256; + #[cfg(feature = "tls12")] + pub use crate::tls12::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; + #[cfg(feature = "tls12")] + pub use crate::tls12::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384; + #[cfg(feature = "tls12")] + pub use crate::tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256; + pub use crate::tls13::TLS13_AES_128_GCM_SHA256; + pub use crate::tls13::TLS13_AES_256_GCM_SHA384; + pub use crate::tls13::TLS13_CHACHA20_POLY1305_SHA256; +} + +/// All defined protocol versions appear in this module. +/// +/// ALL_VERSIONS is a provided as an array of all of these values. +pub mod version { + #[cfg(feature = "tls12")] + pub use crate::versions::TLS12; + pub use crate::versions::TLS13; +} + +/// All defined key exchange groups appear in this module. +/// +/// ALL_KX_GROUPS is provided as an array of all of these values. +pub mod kx_group { + pub use crate::kx::SECP256R1; + pub use crate::kx::SECP384R1; + pub use crate::kx::X25519; +} + +/// Message signing interfaces and implementations. +pub mod sign; + +#[cfg(feature = "quic")] +#[cfg_attr(docsrs, doc(cfg(feature = "quic")))] +/// APIs for implementing QUIC TLS +pub mod quic; + +/// This is the rustls manual. +pub mod manual; diff --git a/vendor/rustls-0.21.8/src/limited_cache.rs b/vendor/rustls-0.21.8/src/limited_cache.rs new file mode 100644 index 0000000000000..6bb99f954dc41 --- /dev/null +++ b/vendor/rustls-0.21.8/src/limited_cache.rs @@ -0,0 +1,245 @@ +use std::borrow::Borrow; +use std::collections::hash_map::Entry; +use std::collections::{HashMap, VecDeque}; +use std::hash::Hash; + +/// A HashMap-alike, which never gets larger than a specified +/// capacity, and evicts the oldest insertion to maintain this. +/// +/// The requested capacity may be rounded up by the underlying +/// collections. This implementation uses all the allocated +/// storage. +/// +/// This is inefficient: it stores keys twice. +pub(crate) struct LimitedCache { + map: HashMap, + + // first item is the oldest key + oldest: VecDeque, +} + +impl LimitedCache +where + K: Eq + Hash + Clone + std::fmt::Debug, + V: Default, +{ + /// Create a new LimitedCache with the given rough capacity. + pub(crate) fn new(capacity_order_of_magnitude: usize) -> Self { + Self { + map: HashMap::with_capacity(capacity_order_of_magnitude), + oldest: VecDeque::with_capacity(capacity_order_of_magnitude), + } + } + + pub(crate) fn get_or_insert_default_and_edit(&mut self, k: K, edit: impl FnOnce(&mut V)) { + let inserted_new_item = match self.map.entry(k) { + Entry::Occupied(value) => { + edit(value.into_mut()); + false + } + entry @ Entry::Vacant(_) => { + self.oldest + .push_back(entry.key().clone()); + edit(entry.or_insert_with(V::default)); + true + } + }; + + // ensure next insertion does not require a realloc + if inserted_new_item && self.oldest.capacity() == self.oldest.len() { + if let Some(oldest_key) = self.oldest.pop_front() { + self.map.remove(&oldest_key); + } + } + } + + pub(crate) fn insert(&mut self, k: K, v: V) { + let inserted_new_item = match self.map.entry(k) { + Entry::Occupied(mut old) => { + // nb. does not freshen entry in `oldest` + old.insert(v); + false + } + + entry @ Entry::Vacant(_) => { + self.oldest + .push_back(entry.key().clone()); + entry.or_insert(v); + true + } + }; + + // ensure next insertion does not require a realloc + if inserted_new_item && self.oldest.capacity() == self.oldest.len() { + if let Some(oldest_key) = self.oldest.pop_front() { + self.map.remove(&oldest_key); + } + } + } + + pub(crate) fn get(&self, k: &Q) -> Option<&V> + where + K: Borrow, + Q: Hash + Eq, + { + self.map.get(k) + } + + pub(crate) fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: Borrow, + Q: Hash + Eq, + { + self.map.get_mut(k) + } + + pub(crate) fn remove(&mut self, k: &Q) -> Option + where + K: Borrow, + Q: Hash + Eq, + { + if let Some(value) = self.map.remove(k) { + // O(N) search, followed by O(N) removal + if let Some(index) = self + .oldest + .iter() + .position(|item| item.borrow() == k) + { + self.oldest.remove(index); + } + Some(value) + } else { + None + } + } +} + +#[cfg(test)] +mod test { + type Test = super::LimitedCache; + + #[test] + fn test_updates_existing_item() { + let mut t = Test::new(3); + t.insert("abc".into(), 1); + t.insert("abc".into(), 2); + assert_eq!(t.get("abc"), Some(&2)); + } + + #[test] + fn test_evicts_oldest_item() { + let mut t = Test::new(3); + t.insert("abc".into(), 1); + t.insert("def".into(), 2); + t.insert("ghi".into(), 3); + + assert_eq!(t.get("abc"), None); + assert_eq!(t.get("def"), Some(&2)); + assert_eq!(t.get("ghi"), Some(&3)); + } + + #[test] + fn test_evicts_second_oldest_item_if_first_removed() { + let mut t = Test::new(3); + t.insert("abc".into(), 1); + t.insert("def".into(), 2); + + assert_eq!(t.remove("abc"), Some(1)); + + t.insert("ghi".into(), 3); + t.insert("jkl".into(), 4); + + assert_eq!(t.get("abc"), None); + assert_eq!(t.get("def"), None); + assert_eq!(t.get("ghi"), Some(&3)); + assert_eq!(t.get("jkl"), Some(&4)); + } + + #[test] + fn test_evicts_after_second_oldest_item_removed() { + let mut t = Test::new(3); + t.insert("abc".into(), 1); + t.insert("def".into(), 2); + + assert_eq!(t.remove("def"), Some(2)); + assert_eq!(t.get("abc"), Some(&1)); + + t.insert("ghi".into(), 3); + t.insert("jkl".into(), 4); + + assert_eq!(t.get("abc"), None); + assert_eq!(t.get("def"), None); + assert_eq!(t.get("ghi"), Some(&3)); + assert_eq!(t.get("jkl"), Some(&4)); + } + + #[test] + fn test_removes_all_items() { + let mut t = Test::new(3); + t.insert("abc".into(), 1); + t.insert("def".into(), 2); + + assert_eq!(t.remove("def"), Some(2)); + assert_eq!(t.remove("abc"), Some(1)); + + t.insert("ghi".into(), 3); + t.insert("jkl".into(), 4); + t.insert("mno".into(), 5); + + assert_eq!(t.get("abc"), None); + assert_eq!(t.get("def"), None); + assert_eq!(t.get("ghi"), None); + assert_eq!(t.get("jkl"), Some(&4)); + assert_eq!(t.get("mno"), Some(&5)); + } + + #[test] + fn test_inserts_many_items() { + let mut t = Test::new(3); + + for _ in 0..10000 { + t.insert("abc".into(), 1); + t.insert("def".into(), 2); + t.insert("ghi".into(), 3); + } + } + + #[test] + fn test_get_or_insert_default_and_edit_evicts_old_items_to_meet_capacity() { + let mut t = Test::new(3); + + t.get_or_insert_default_and_edit("abc".into(), |v| *v += 1); + t.get_or_insert_default_and_edit("def".into(), |v| *v += 2); + + // evicts "abc" + t.get_or_insert_default_and_edit("ghi".into(), |v| *v += 3); + assert_eq!(t.get("abc"), None); + + // evicts "def" + t.get_or_insert_default_and_edit("jkl".into(), |v| *v += 4); + assert_eq!(t.get("def"), None); + + // evicts "ghi" + t.get_or_insert_default_and_edit("abc".into(), |v| *v += 5); + assert_eq!(t.get("ghi"), None); + + // evicts "jkl" + t.get_or_insert_default_and_edit("def".into(), |v| *v += 6); + + assert_eq!(t.get("abc"), Some(&5)); + assert_eq!(t.get("def"), Some(&6)); + assert_eq!(t.get("ghi"), None); + assert_eq!(t.get("jkl"), None); + } + + #[test] + fn test_get_or_insert_default_and_edit_edits_existing_item() { + let mut t = Test::new(3); + + t.get_or_insert_default_and_edit("abc".into(), |v| *v += 1); + t.get_or_insert_default_and_edit("abc".into(), |v| *v += 2); + t.get_or_insert_default_and_edit("abc".into(), |v| *v += 3); + + assert_eq!(t.get("abc"), Some(&6)); + } +} diff --git a/vendor/rustls-0.21.8/src/manual/defaults.rs b/vendor/rustls-0.21.8/src/manual/defaults.rs new file mode 100644 index 0000000000000..aa15863c16305 --- /dev/null +++ b/vendor/rustls-0.21.8/src/manual/defaults.rs @@ -0,0 +1,29 @@ +/*! + +## Rationale for defaults + +### Why is AES-256 preferred over AES-128? + +This is a trade-off between: + +1. classical security level: searching a 2^128 key space is as implausible as 2^256. +2. post-quantum security level: the difference is more meaningful, and AES-256 seems like the conservative choice. +3. performance: AES-256 is around 40% slower than AES-128, though hardware acceleration typically narrows this gap. + +The choice is frankly quite marginal. + +### Why is AES-GCM preferred over chacha20-poly1305? + +Hardware support for accelerating AES-GCM is widespread, and hardware-accelerated AES-GCM +is quicker than un-accelerated chacha20-poly1305. + +However, if you know your application will run on a platform without that, you should +_definitely_ change the default order to prefer chacha20-poly1305: both the performance and +the implementation security will be improved. We think this is an uncommon case. + +### Why is x25519 preferred for key exchange over nistp256? + +Both provide roughly the same classical security level, but x25519 has better performance and +it's _much_ more likely that both peers will have good quality implementations. + +*/ diff --git a/vendor/rustls-0.21.8/src/manual/features.rs b/vendor/rustls-0.21.8/src/manual/features.rs new file mode 100644 index 0000000000000..639a23184c9bd --- /dev/null +++ b/vendor/rustls-0.21.8/src/manual/features.rs @@ -0,0 +1,50 @@ +/*! + +## Current features + +* TLS1.2 and TLS1.3. +* ECDSA, Ed25519 or RSA server authentication by clients. +* ECDSA, Ed25519 or RSA server authentication by servers. +* Forward secrecy using ECDHE; with curve25519, nistp256 or nistp384 curves. +* AES128-GCM and AES256-GCM bulk encryption, with safe nonces. +* ChaCha20-Poly1305 bulk encryption ([RFC7905](https://tools.ietf.org/html/rfc7905)). +* ALPN support. +* SNI support. +* Tunable MTU to make TLS messages match size of underlying transport. +* Optional use of vectored IO to minimise system calls. +* TLS1.2 session resumption. +* TLS1.2 resumption via tickets (RFC5077). +* TLS1.3 resumption via tickets or session storage. +* TLS1.3 0-RTT data for clients. +* Client authentication by clients. +* Client authentication by servers. +* Extended master secret support (RFC7627). +* Exporters (RFC5705). +* OCSP stapling by servers. +* SCT stapling by servers. +* SCT verification by clients. + +## Possible future features + +* PSK support. +* OCSP verification by clients. +* Certificate pinning. + +## Non-features + +For reasons explained in the other sections of this manual, rustls does not +and will not support: + +* SSL1, SSL2, SSL3, TLS1 or TLS1.1. +* RC4. +* DES or triple DES. +* EXPORT ciphersuites. +* MAC-then-encrypt ciphersuites. +* Ciphersuites without forward secrecy. +* Renegotiation. +* Kerberos. +* Compression. +* Discrete-log Diffie-Hellman. +* Automatic protocol version downgrade. + +*/ diff --git a/vendor/rustls-0.21.8/src/manual/howto.rs b/vendor/rustls-0.21.8/src/manual/howto.rs new file mode 100644 index 0000000000000..aa68a1e390bc5 --- /dev/null +++ b/vendor/rustls-0.21.8/src/manual/howto.rs @@ -0,0 +1,36 @@ +/*! # Customising private key usage + +By default rustls supports PKCS#8-format[^1] RSA or ECDSA keys, plus PKCS#1-format RSA keys. + +However, if your private key resides in a HSM, or in another process, or perhaps +another machine, rustls has some extension points to support this: + +The main trait you must implement is [`sign::SigningKey`][signing_key]. The primary method here +is [`choose_scheme`][choose_scheme] where you are given a set of [`SignatureScheme`s][sig_scheme] the client says +it supports: you must choose one (or return `None` -- this aborts the handshake). Having +done that, you return an implementation of the [`sign::Signer`][signer] trait. +The [`sign()`][sign_method] performs the signature and returns it. + +(Unfortunately this is currently designed for keys with low latency access, like in a +PKCS#11 provider, Microsoft CryptoAPI, etc. so is blocking rather than asynchronous. +It's a TODO to make these and other extension points async.) + +Once you have these two pieces, configuring a server to use them involves, briefly: + +- packaging your `sign::SigningKey` with the matching certificate chain into a [`sign::CertifiedKey`][certified_key] +- making a [`ResolvesServerCertUsingSni`][cert_using_sni] and feeding in your `sign::CertifiedKey` for all SNI hostnames you want to use it for, +- setting that as your `ServerConfig`'s [`cert_resolver`][cert_resolver] + +[signing_key]: ../../sign/trait.SigningKey.html +[choose_scheme]: ../../sign/trait.SigningKey.html#tymethod.choose_scheme +[sig_scheme]: ../../enum.SignatureScheme.html +[signer]: ../../sign/trait.Signer.html +[sign_method]: ../../sign/trait.Signer.html#tymethod.sign +[certified_key]: ../../sign/struct.CertifiedKey.html +[cert_using_sni]: ../../struct.ResolvesServerCertUsingSni.html +[cert_resolver]: ../../struct.ServerConfig.html#structfield.cert_resolver + +[^1]: For PKCS#8 it does not support password encryption -- there's not a meaningful threat + model addressed by this, and the encryption supported is typically extremely poor. + +*/ diff --git a/vendor/rustls-0.21.8/src/manual/implvulns.rs b/vendor/rustls-0.21.8/src/manual/implvulns.rs new file mode 100644 index 0000000000000..d08e1100aeda0 --- /dev/null +++ b/vendor/rustls-0.21.8/src/manual/implvulns.rs @@ -0,0 +1,104 @@ +/*! # A review of TLS Implementation Vulnerabilities + +An important part of engineering involves studying and learning from the mistakes of the past. +It would be tremendously unfortunate to spend effort re-discovering and re-fixing the same +vulnerabilities that were discovered in the past. + +## Memory safety + +Being written entirely in the safe-subset of Rust immediately offers us freedom from the entire +class of memory safety vulnerabilities. There are too many to exhaustively list, and there will +certainly be more in the future. + +Examples: + +- Heartbleed [CVE-2014-0160](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160) (OpenSSL) +- Memory corruption in ASN.1 decoder [CVE-2016-2108](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2108) (OpenSSL) +- Buffer overflow in read_server_hello [CVE-2014-3466](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3466) (GnuTLS) + +## `goto fail` + +This is the name of a vulnerability in Apple Secure Transport [CVE-2014-1266](https://nvd.nist.gov/vuln/detail/CVE-2014-1266). +This boiled down to the following code, which validates the server's signature on the key exchange: + +```c + if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) + goto fail; + if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) + goto fail; +> goto fail; + if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) + goto fail; +``` + +The marked line was duplicated, likely accidentally during a merge. This meant +the remaining part of the function (including the actual signature validation) +was unconditionally skipped. + +Ultimately the one countermeasure to this type of bug is basic testing: that a +valid signature returns success, and that an invalid one does not. rustls +has such testing, but this is really table stakes for security code. + +Further than this, though, we could consider that the *lack* of an error from +this function is a poor indicator that the signature was valid. rustls, instead, +has zero-size and non-copyable types that indicate a particular signature validation +has been performed. These types can be thought of as *capabilities* originated only +by designated signature verification functions -- such functions can then be a focus +of manual code review. Like capabilities, values of these types are otherwise unforgeable, +and are communicable only by Rust's move semantics. + +Values of these types are threaded through the protocol state machine, leading to terminal +states that look like: + +```ignore +struct ExpectTraffic { + (...) + _cert_verified: verify::ServerCertVerified, + _sig_verified: verify::HandshakeSignatureValid, + _fin_verified: verify::FinishedMessageVerified, +} +``` + +Since this state requires a value of these types, it will be a compile-time error to +reach that state without performing the requisite security-critical operations. + +This approach is not infallible, but it has zero runtime cost. + +## State machine attacks: EarlyCCS and SMACK/SKIP/FREAK + +EarlyCCS [CVE-2014-0224](https://nvd.nist.gov/vuln/detail/CVE-2014-0224) was a vulnerability in OpenSSL +found in 2014. The TLS `ChangeCipherSpec` message would be processed at inappropriate times, leading +to data being encrypted with the wrong keys (specifically, keys which were not secret). This resulted +from OpenSSL taking a *reactive* strategy to incoming messages ("when I get a message X, I should do Y") +which allows it to diverge from the proper state machine under attacker control. + +[SMACK](https://mitls.org/pages/attacks/SMACK) is a similar suite of vulnerabilities found in JSSE, +CyaSSL, OpenSSL, Mono and axTLS. "SKIP-TLS" demonstrated that some implementations allowed handshake +messages (and in one case, the entire handshake!) to be skipped leading to breaks in security. "FREAK" +found that some implementations incorrectly allowed export-only state transitions (i.e., transitions that +were only valid when an export ciphersuite was in use). + +rustls represents its protocol state machine carefully to avoid these defects. We model the handshake, +CCS and application data subprotocols in the same single state machine. Each state in this machine is +represented with a single struct, and transitions are modelled as functions that consume the current state +plus one TLS message[^1] and return a struct representing the next state. These functions fully validate +the message type before further operations. + +A sample sequence for a full TLSv1.2 handshake by a client looks like: + +- `hs::ExpectServerHello` (nb. ClientHello is logically sent before this state); transition to `tls12::ExpectCertificate` +- `tls12::ExpectCertificate`; transition to `tls12::ExpectServerKX` +- `tls12::ExpectServerKX`; transition to `tls12::ExpectServerDoneOrCertReq` +- `tls12::ExpectServerDoneOrCertReq`; delegates to `tls12::ExpectCertificateRequest` or `tls12::ExpectServerDone` depending on incoming message. + - `tls12::ExpectServerDone`; transition to `tls12::ExpectCCS` +- `tls12::ExpectCCS`; transition to `tls12::ExpectFinished` +- `tls12::ExpectFinished`; transition to `tls12::ExpectTraffic` +- `tls12::ExpectTraffic`; terminal state; transitions to `tls12::ExpectTraffic` + +In the future we plan to formally prove that all possible transitions modelled in this system of types +are correct with respect to the standard(s). At the moment we rely merely on exhaustive testing. + +[^1]: a logical TLS message: post-decryption, post-fragmentation. + + +*/ diff --git a/vendor/rustls-0.21.8/src/manual/mod.rs b/vendor/rustls-0.21.8/src/manual/mod.rs new file mode 100644 index 0000000000000..778d24b280448 --- /dev/null +++ b/vendor/rustls-0.21.8/src/manual/mod.rs @@ -0,0 +1,30 @@ +/*! + +This documentation primarily aims to explain design decisions taken in rustls. + +It does this from a few aspects: how rustls attempts to avoid construction errors +that occurred in other TLS libraries, how rustls attempts to avoid past TLS +protocol vulnerabilities, and assorted advice for achieving common tasks with rustls. +*/ +#![allow(non_snake_case)] + +/// This section discusses vulnerabilities in other TLS implementations, theorising their +/// root cause and how we aim to avoid them in rustls. +#[path = "implvulns.rs"] +pub mod _01_impl_vulnerabilities; + +/// This section discusses vulnerabilities and design errors in the TLS protocol. +#[path = "tlsvulns.rs"] +pub mod _02_tls_vulnerabilities; + +/// This section collects together goal-oriented documentation. +#[path = "howto.rs"] +pub mod _03_howto; + +/// This section documents rustls itself: what protocol features are and are not implemented. +#[path = "features.rs"] +pub mod _04_features; + +/// This section provides rationale for the defaults in rustls. +#[path = "defaults.rs"] +pub mod _05_defaults; diff --git a/vendor/rustls-0.21.8/src/manual/tlsvulns.rs b/vendor/rustls-0.21.8/src/manual/tlsvulns.rs new file mode 100644 index 0000000000000..77d5510270af9 --- /dev/null +++ b/vendor/rustls-0.21.8/src/manual/tlsvulns.rs @@ -0,0 +1,173 @@ +/*! # A review of protocol vulnerabilities + +## CBC MAC-then-encrypt ciphersuites + +Back in 2000 [Bellare and Namprempre](https://eprint.iacr.org/2000/025) discussed how to make authenticated +encryption by composing separate encryption and authentication primitives. That paper included this table: + +| Composition Method | Privacy || Integrity || +|--------------------|---------||-----------|| +|| IND-CPA | IND-CCA | NM-CPA | INT-PTXT | INT-CTXT | +| Encrypt-and-MAC | insecure | insecure | insecure | secure | insecure | +| MAC-then-encrypt | secure | insecure | insecure | secure | insecure | +| Encrypt-then-MAC | secure | secure | secure | secure | secure | + +One may assume from this fairly clear result that encrypt-and-MAC and MAC-then-encrypt compositions would be quickly abandoned +in favour of the remaining proven-secure option. But that didn't happen, not in TLSv1.1 (2006) nor in TLSv1.2 (2008). Worse, +both RFCs included incorrect advice on countermeasures for implementers, suggesting that the flaw was "not believed to be large +enough to be exploitable". + +[Lucky 13](http://www.isg.rhul.ac.uk/tls/Lucky13.html) (2013) exploited this flaw and affected all implementations, including +those written [after discovery](https://aws.amazon.com/blogs/security/s2n-and-lucky-13/). OpenSSL even had a +[memory safety vulnerability in the fix for Lucky 13](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2107), which +gives a flavour of the kind of complexity required to remove the side channel. + +rustls does not implement CBC MAC-then-encrypt ciphersuites for these reasons. TLSv1.3 removed support for these +ciphersuites in 2018. + +There are some further rejected options worth mentioning: [RFC7366](https://tools.ietf.org/html/rfc7366) defines +Encrypt-then-MAC for TLS, but unfortunately cannot be negotiated without also supporting MAC-then-encrypt +(clients cannot express "I offer CBC, but only EtM and not MtE"). + +## RSA PKCS#1 encryption + +"RSA key exchange" in TLS involves the client choosing a large random value and encrypting it using the server's +public key. This has two overall problems: + +1. It provides no _forward secrecy_: later compromise of the server's private key breaks confidentiality of + *all* past sessions using that key. This is a crucial property in the presence of software that is often + [poor at keeping a secret](http://heartbleed.com/). +2. The padding used in practice in TLS ("PKCS#1", or fully "RSAES-PKCS1-v1_5") has been known to be broken since + [1998](http://archiv.infsec.ethz.ch/education/fs08/secsem/bleichenbacher98.pdf). + +In a similar pattern to the MAC-then-encrypt problem discussed above, TLSv1.0 (1999), TLSv1.1 (2006) and TLSv1.2 (2008) +continued to specify use of PKCS#1 encryption, again with incrementally more complex and incorrect advice on countermeasures. + +[ROBOT](https://robotattack.org/) (2018) showed that implementations were still vulnerable to these attacks twenty years later. + +rustls does not support RSA key exchange. TLSv1.3 also removed support. + +## BEAST + +[BEAST](https://vnhacker.blogspot.com/2011/09/beast.html) ([CVE-2011-3389](https://nvd.nist.gov/vuln/detail/CVE-2011-3389)) +was demonstrated in 2011 by Thai Duong and Juliano Rizzo, +and was another vulnerability in CBC-based ciphersuites in SSLv3.0 and TLSv1.0. CBC mode is vulnerable to adaptive +chosen-plaintext attacks if the IV is predictable. In the case of these protocol versions, the IV was the previous +block of ciphertext (as if the entire TLS session was one CBC ciphertext, albeit revealed incrementally). This was +obviously predictable, since it was published on the wire. + +OpenSSL contained a countermeasure for this problem from 2002 onwards: it encrypts an empty message before each real +one, so that the IV used in the real message is unpredictable. This was turned off by default due to bugs in IE6. + +TLSv1.1 fix this vulnerability, but not any of the other deficiencies of CBC mode (see above). + +rustls does not support these ciphersuites. + +## CRIME + +In 2002 [John Kelsey](https://www.iacr.org/cryptodb/archive/2002/FSE/3091/3091.pdf) discussed the length side channel +as applied to compression of combined secret and attacker-chosen strings. + +Compression continued to be an option in TLSv1.1 (2006) and in TLSv1.2 (2008). Support in libraries was widespread. + +[CRIME](http://netifera.com/research/crime/CRIME_ekoparty2012.pdf) ([CVE-2012-4929](https://nvd.nist.gov/vuln/detail/CVE-2012-4929)) +was demonstrated in 2012, again by Thai Duong and Juliano Rizzo. It attacked several protocols offering transparent +compression of application data, allowing quick adaptive chosen-plaintext attacks against secret values like cookies. + +rustls does not implement compression. TLSv1.3 also removed support. + +## Logjam / FREAK + +Way back when SSL was first being born, circa 1995, the US government considered cryptography a munition requiring +export control. SSL contained specific ciphersuites with dramatically small key sizes that were not subject +to export control. These controls were dropped in 2000. + +Since the "export-grade" ciphersuites no longer fulfilled any purpose, and because they were actively harmful to users, +one may have expected software support to disappear quickly. This did not happen. + +In 2015 [the FREAK attack](https://mitls.org/pages/attacks/SMACK#freak) ([CVE-2015-0204](https://nvd.nist.gov/vuln/detail/CVE-2015-0204)) +and [the Logjam attack](https://weakdh.org/) ([CVE-2015-4000](https://nvd.nist.gov/vuln/detail/CVE-2015-4000)) both +demonstrated total breaks of security in the presence of servers that accepted export ciphersuites. FREAK factored +512-bit RSA keys, while Logjam optimised solving discrete logs in the 512-bit group used by many different servers. + +Naturally, rustls does not implement any of these ciphersuites. + +## SWEET32 + +Block ciphers are vulnerable to birthday attacks, where the probability of repeating a block increases dramatically +once a particular key has been used for many blocks. For block ciphers with 64-bit blocks, this becomes probable +once a given key encrypts the order of 32GB of data. + +[Sweet32](https://sweet32.info/) ([CVE-2016-2183](https://nvd.nist.gov/vuln/detail/CVE-2016-2183)) attacked this fact +in the context of TLS support for 3DES, breaking confidentiality by analysing a large amount of attacker-induced traffic +in one session. + +rustls does not support any 64-bit block ciphers. + +## DROWN + +[DROWN](https://drownattack.com/) ([CVE-2016-0800](https://nvd.nist.gov/vuln/detail/CVE-2016-0800)) is a cross-protocol +attack that breaks the security of TLSv1.2 and earlier (when used with RSA key exchange) by using SSLv2. It is required +that the server uses the same key for both protocol versions. + +rustls naturally does not support SSLv2, but most importantly does not support RSA key exchange for TLSv1.2. + +## Poodle + +[POODLE](https://www.openssl.org/~bodo/ssl-poodle.pdf) ([CVE-2014-3566](https://nvd.nist.gov/vuln/detail/CVE-2014-3566)) +is an attack against CBC mode ciphersuites in SSLv3. This was possible in most cases because some clients willingly +downgraded to SSLv3 after failed handshakes for later versions. + +rustls does not support CBC mode ciphersuites, or SSLv3. Note that rustls does not need to implement `TLS_FALLBACK_SCSV` +introduced as a countermeasure because it contains no ability to downgrade to earlier protocol versions. + +## GCM nonces + +[RFC5288](https://tools.ietf.org/html/rfc5288) introduced GCM-based ciphersuites for use in TLS. Unfortunately +the design was poor; it reused design for an unrelated security setting proposed in RFC5116. + +GCM is a typical nonce-based AEAD: it requires a unique (but not necessarily unpredictable) 96-bit nonce for each encryption +with a given key. The design specified by RFC5288 left two-thirds of the nonce construction up to implementations: + +- wasting 8 bytes per TLS ciphertext, +- meaning correct operation cannot be tested for (e.g., in protocol-level test vectors). + +There were no trade-offs here: TLS has a 64-bit sequence number that is not allowed to wrap and would make an ideal nonce. + +As a result, a [2016 study](https://eprint.iacr.org/2016/475.pdf) found: + +- implementations from IBM, A10 and Citrix used randomly-chosen nonces, which are unlikely to be unique over long connections, +- an implementation from Radware used the same nonce for the first two messages. + +rustls uses a counter from a random starting point for GCM nonces. TLSv1.3 and the Chacha20-Poly1305 TLSv1.2 ciphersuite +standardise this method. + +## Renegotiation + +In 2009 Marsh Ray and Steve Dispensa [discovered](https://kryptera.se/Renegotiating%20TLS.pdf) that the renegotiation +feature of all versions of TLS allows a MitM to splice a request of their choice onto the front of the client's real HTTP +request. A countermeasure was proposed and widely implemented to bind renegotiations to their previous negotiations; +unfortunately this was insufficient. + +rustls does not support renegotiation in TLSv1.2. TLSv1.3 also no longer supports renegotiation. + +## 3SHAKE + +[3SHAKE](https://www.mitls.org/pages/attacks/3SHAKE) (2014) described a complex attack that broke the "Secure Renegotiation" extension +introduced as a countermeasure to the previous protocol flaw. + +rustls does not support renegotiation for TLSv1.2 connections, or RSA key exchange, and both are required for this attack +to work. rustls implements the "Extended Master Secret" (RFC7627) extension for TLSv1.2 which was standardised as a countermeasure. + +TLSv1.3 no longer supports renegotiation and RSA key exchange. It also effectively incorporates the improvements made in RFC7627. + +## KCI + +[This vulnerability](https://kcitls.org/) makes use of TLS ciphersuites (those offering static DH) which were standardised +yet not widely used. However, they were implemented by libraries, and as a result enabled for various clients. It coupled +this with misconfigured certificates (on services including facebook.com) which allowed their misuse to MitM connections. + +rustls does not support static DH/EC-DH ciphersuites. We assert that it is misissuance to sign an EC certificate +with the keyUsage extension allowing both signatures and key exchange. That it isn't is probably a failure +of CAB Forum baseline requirements. +*/ diff --git a/vendor/rustls-0.21.8/src/msgs/alert.rs b/vendor/rustls-0.21.8/src/msgs/alert.rs new file mode 100644 index 0000000000000..ca673647c6122 --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/alert.rs @@ -0,0 +1,24 @@ +use crate::enums::AlertDescription; +use crate::error::InvalidMessage; +use crate::msgs::codec::{Codec, Reader}; +use crate::msgs::enums::AlertLevel; + +#[derive(Debug)] +pub struct AlertMessagePayload { + pub level: AlertLevel, + pub description: AlertDescription, +} + +impl Codec for AlertMessagePayload { + fn encode(&self, bytes: &mut Vec) { + self.level.encode(bytes); + self.description.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let level = AlertLevel::read(r)?; + let description = AlertDescription::read(r)?; + r.expect_empty("AlertMessagePayload") + .map(|_| Self { level, description }) + } +} diff --git a/vendor/rustls-0.21.8/src/msgs/base.rs b/vendor/rustls-0.21.8/src/msgs/base.rs new file mode 100644 index 0000000000000..139ffa7249db6 --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/base.rs @@ -0,0 +1,171 @@ +use std::fmt; + +use crate::error::InvalidMessage; +use crate::key; +use crate::msgs::codec; +use crate::msgs::codec::{Codec, Reader}; + +/// An externally length'd payload +#[derive(Clone, Eq, PartialEq)] +pub struct Payload(pub Vec); + +impl Codec for Payload { + fn encode(&self, bytes: &mut Vec) { + bytes.extend_from_slice(&self.0); + } + + fn read(r: &mut Reader) -> Result { + Ok(Self::read(r)) + } +} + +impl Payload { + pub fn new(bytes: impl Into>) -> Self { + Self(bytes.into()) + } + + pub fn empty() -> Self { + Self::new(Vec::new()) + } + + pub fn read(r: &mut Reader) -> Self { + Self(r.rest().to_vec()) + } +} + +impl Codec for key::Certificate { + fn encode(&self, bytes: &mut Vec) { + codec::u24(self.0.len() as u32).encode(bytes); + bytes.extend_from_slice(&self.0); + } + + fn read(r: &mut Reader) -> Result { + let len = codec::u24::read(r)?.0 as usize; + let mut sub = r.sub(len)?; + let body = sub.rest().to_vec(); + Ok(Self(body)) + } +} + +impl fmt::Debug for Payload { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + hex(f, &self.0) + } +} + +/// An arbitrary, unknown-content, u24-length-prefixed payload +#[derive(Clone, Eq, PartialEq)] +pub struct PayloadU24(pub Vec); + +impl PayloadU24 { + pub fn new(bytes: Vec) -> Self { + Self(bytes) + } +} + +impl Codec for PayloadU24 { + fn encode(&self, bytes: &mut Vec) { + codec::u24(self.0.len() as u32).encode(bytes); + bytes.extend_from_slice(&self.0); + } + + fn read(r: &mut Reader) -> Result { + let len = codec::u24::read(r)?.0 as usize; + let mut sub = r.sub(len)?; + let body = sub.rest().to_vec(); + Ok(Self(body)) + } +} + +impl fmt::Debug for PayloadU24 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + hex(f, &self.0) + } +} + +/// An arbitrary, unknown-content, u16-length-prefixed payload +#[derive(Clone, Eq, PartialEq)] +pub struct PayloadU16(pub Vec); + +impl PayloadU16 { + pub fn new(bytes: Vec) -> Self { + Self(bytes) + } + + pub fn empty() -> Self { + Self::new(Vec::new()) + } + + pub fn encode_slice(slice: &[u8], bytes: &mut Vec) { + (slice.len() as u16).encode(bytes); + bytes.extend_from_slice(slice); + } +} + +impl Codec for PayloadU16 { + fn encode(&self, bytes: &mut Vec) { + Self::encode_slice(&self.0, bytes); + } + + fn read(r: &mut Reader) -> Result { + let len = u16::read(r)? as usize; + let mut sub = r.sub(len)?; + let body = sub.rest().to_vec(); + Ok(Self(body)) + } +} + +impl fmt::Debug for PayloadU16 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + hex(f, &self.0) + } +} + +/// An arbitrary, unknown-content, u8-length-prefixed payload +#[derive(Clone, Eq, PartialEq)] +pub struct PayloadU8(pub Vec); + +impl PayloadU8 { + pub fn new(bytes: Vec) -> Self { + Self(bytes) + } + + pub fn empty() -> Self { + Self(Vec::new()) + } + + pub fn into_inner(self) -> Vec { + self.0 + } +} + +impl Codec for PayloadU8 { + fn encode(&self, bytes: &mut Vec) { + (self.0.len() as u8).encode(bytes); + bytes.extend_from_slice(&self.0); + } + + fn read(r: &mut Reader) -> Result { + let len = u8::read(r)? as usize; + let mut sub = r.sub(len)?; + let body = sub.rest().to_vec(); + Ok(Self(body)) + } +} + +impl fmt::Debug for PayloadU8 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + hex(f, &self.0) + } +} + +// Format an iterator of u8 into a hex string +pub(super) fn hex<'a>( + f: &mut fmt::Formatter<'_>, + payload: impl IntoIterator, +) -> fmt::Result { + for b in payload { + write!(f, "{:02x}", b)?; + } + Ok(()) +} diff --git a/vendor/rustls-0.21.8/src/msgs/ccs.rs b/vendor/rustls-0.21.8/src/msgs/ccs.rs new file mode 100644 index 0000000000000..b9fb624eb8121 --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/ccs.rs @@ -0,0 +1,21 @@ +use crate::error::InvalidMessage; +use crate::msgs::codec::{Codec, Reader}; + +#[derive(Debug)] +pub struct ChangeCipherSpecPayload; + +impl Codec for ChangeCipherSpecPayload { + fn encode(&self, bytes: &mut Vec) { + 1u8.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let typ = u8::read(r)?; + if typ != 1 { + return Err(InvalidMessage::InvalidCcs); + } + + r.expect_empty("ChangeCipherSpecPayload") + .map(|_| Self {}) + } +} diff --git a/vendor/rustls-0.21.8/src/msgs/codec.rs b/vendor/rustls-0.21.8/src/msgs/codec.rs new file mode 100644 index 0000000000000..9316e4fc478e6 --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/codec.rs @@ -0,0 +1,290 @@ +use std::fmt::Debug; + +use crate::error::InvalidMessage; + +/// Wrapper over a slice of bytes that allows reading chunks from +/// with the current position state held using a cursor. +/// +/// A new reader for a sub section of the the buffer can be created +/// using the `sub` function or a section of a certain length can +/// be obtained using the `take` function +pub struct Reader<'a> { + /// The underlying buffer storing the readers content + buffer: &'a [u8], + /// Stores the current reading position for the buffer + cursor: usize, +} + +impl<'a> Reader<'a> { + /// Creates a new Reader of the provided `bytes` slice with + /// the initial cursor position of zero. + pub fn init(bytes: &[u8]) -> Reader { + Reader { + buffer: bytes, + cursor: 0, + } + } + + /// Attempts to create a new Reader on a sub section of this + /// readers bytes by taking a slice of the provided `length` + /// will return None if there is not enough bytes + pub fn sub(&mut self, length: usize) -> Result { + match self.take(length) { + Some(bytes) => Ok(Reader::init(bytes)), + None => Err(InvalidMessage::MessageTooShort), + } + } + + /// Borrows a slice of all the remaining bytes + /// that appear after the cursor position. + /// + /// Moves the cursor to the end of the buffer length. + pub fn rest(&mut self) -> &[u8] { + let rest = &self.buffer[self.cursor..]; + self.cursor = self.buffer.len(); + rest + } + + /// Attempts to borrow a slice of bytes from the current + /// cursor position of `length` if there is not enough + /// bytes remaining after the cursor to take the length + /// then None is returned instead. + pub fn take(&mut self, length: usize) -> Option<&[u8]> { + if self.left() < length { + return None; + } + let current = self.cursor; + self.cursor += length; + Some(&self.buffer[current..current + length]) + } + + /// Used to check whether the reader has any content left + /// after the cursor (cursor has not reached end of buffer) + pub fn any_left(&self) -> bool { + self.cursor < self.buffer.len() + } + + pub fn expect_empty(&self, name: &'static str) -> Result<(), InvalidMessage> { + match self.any_left() { + true => Err(InvalidMessage::TrailingData(name)), + false => Ok(()), + } + } + + /// Returns the cursor position which is also the number + /// of bytes that have been read from the buffer. + pub fn used(&self) -> usize { + self.cursor + } + + /// Returns the number of bytes that are still able to be + /// read (The number of remaining takes) + pub fn left(&self) -> usize { + self.buffer.len() - self.cursor + } +} + +/// Trait for implementing encoding and decoding functionality +/// on something. +pub trait Codec: Debug + Sized { + /// Function for encoding itself by appending itself to + /// the provided vec of bytes. + fn encode(&self, bytes: &mut Vec); + + /// Function for decoding itself from the provided reader + /// will return Some if the decoding was successful or + /// None if it was not. + fn read(_: &mut Reader) -> Result; + + /// Convenience function for encoding the implementation + /// into a vec and returning it + fn get_encoding(&self) -> Vec { + let mut bytes = Vec::new(); + self.encode(&mut bytes); + bytes + } + + /// Function for wrapping a call to the read function in + /// a Reader for the slice of bytes provided + fn read_bytes(bytes: &[u8]) -> Result { + let mut reader = Reader::init(bytes); + Self::read(&mut reader) + } +} + +impl Codec for u8 { + fn encode(&self, bytes: &mut Vec) { + bytes.push(*self); + } + + fn read(r: &mut Reader) -> Result { + match r.take(1) { + Some(&[byte]) => Ok(byte), + _ => Err(InvalidMessage::MissingData("u8")), + } + } +} + +pub fn put_u16(v: u16, out: &mut [u8]) { + let out: &mut [u8; 2] = (&mut out[..2]).try_into().unwrap(); + *out = u16::to_be_bytes(v); +} + +impl Codec for u16 { + fn encode(&self, bytes: &mut Vec) { + let mut b16 = [0u8; 2]; + put_u16(*self, &mut b16); + bytes.extend_from_slice(&b16); + } + + fn read(r: &mut Reader) -> Result { + match r.take(2) { + Some(&[b1, b2]) => Ok(Self::from_be_bytes([b1, b2])), + _ => Err(InvalidMessage::MissingData("u8")), + } + } +} + +// Make a distinct type for u24, even though it's a u32 underneath +#[allow(non_camel_case_types)] +#[derive(Debug, Copy, Clone)] +pub struct u24(pub u32); + +#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] +impl From for usize { + #[inline] + fn from(v: u24) -> Self { + v.0 as Self + } +} + +impl Codec for u24 { + fn encode(&self, bytes: &mut Vec) { + let be_bytes = u32::to_be_bytes(self.0); + bytes.extend_from_slice(&be_bytes[1..]); + } + + fn read(r: &mut Reader) -> Result { + match r.take(3) { + Some(&[a, b, c]) => Ok(Self(u32::from_be_bytes([0, a, b, c]))), + _ => Err(InvalidMessage::MissingData("u24")), + } + } +} + +impl Codec for u32 { + fn encode(&self, bytes: &mut Vec) { + bytes.extend(Self::to_be_bytes(*self)); + } + + fn read(r: &mut Reader) -> Result { + match r.take(4) { + Some(&[a, b, c, d]) => Ok(Self::from_be_bytes([a, b, c, d])), + _ => Err(InvalidMessage::MissingData("u32")), + } + } +} + +pub fn put_u64(v: u64, bytes: &mut [u8]) { + let bytes: &mut [u8; 8] = (&mut bytes[..8]).try_into().unwrap(); + *bytes = u64::to_be_bytes(v); +} + +impl Codec for u64 { + fn encode(&self, bytes: &mut Vec) { + let mut b64 = [0u8; 8]; + put_u64(*self, &mut b64); + bytes.extend_from_slice(&b64); + } + + fn read(r: &mut Reader) -> Result { + match r.take(8) { + Some(&[a, b, c, d, e, f, g, h]) => Ok(Self::from_be_bytes([a, b, c, d, e, f, g, h])), + _ => Err(InvalidMessage::MissingData("u64")), + } + } +} + +/// Implement `Codec` for lists of elements that implement `TlsListElement`. +/// +/// `TlsListElement` provides the size of the length prefix for the list. +impl Codec for Vec { + fn encode(&self, bytes: &mut Vec) { + let len_offset = bytes.len(); + bytes.extend(match T::SIZE_LEN { + ListLength::U8 => &[0][..], + ListLength::U16 => &[0, 0], + ListLength::U24 { .. } => &[0, 0, 0], + }); + + for i in self { + i.encode(bytes); + } + + match T::SIZE_LEN { + ListLength::U8 => { + let len = bytes.len() - len_offset - 1; + debug_assert!(len <= 0xff); + bytes[len_offset] = len as u8; + } + ListLength::U16 => { + let len = bytes.len() - len_offset - 2; + debug_assert!(len <= 0xffff); + let out: &mut [u8; 2] = (&mut bytes[len_offset..len_offset + 2]) + .try_into() + .unwrap(); + *out = u16::to_be_bytes(len as u16); + } + ListLength::U24 { .. } => { + let len = bytes.len() - len_offset - 3; + debug_assert!(len <= 0xff_ffff); + let len_bytes = u32::to_be_bytes(len as u32); + let out: &mut [u8; 3] = (&mut bytes[len_offset..len_offset + 3]) + .try_into() + .unwrap(); + out.copy_from_slice(&len_bytes[1..]); + } + } + } + + fn read(r: &mut Reader) -> Result { + let len = match T::SIZE_LEN { + ListLength::U8 => usize::from(u8::read(r)?), + ListLength::U16 => usize::from(u16::read(r)?), + ListLength::U24 { max } => Ord::min(usize::from(u24::read(r)?), max), + }; + + let mut sub = r.sub(len)?; + let mut ret = Self::new(); + while sub.any_left() { + ret.push(T::read(&mut sub)?); + } + + Ok(ret) + } +} + +/// A trait for types that can be encoded and decoded in a list. +/// +/// This trait is used to implement `Codec` for `Vec`. Lists in the TLS wire format are +/// prefixed with a length, the size of which depends on the type of the list elements. +/// As such, the `Codec` implementation for `Vec` requires an implementation of this trait +/// for its element type `T`. +/// +// TODO: make this `pub(crate)` once our MSRV allows it? +pub trait TlsListElement { + const SIZE_LEN: ListLength; +} + +/// The length of the length prefix for a list. +/// +/// The types that appear in lists are limited to three kinds of length prefixes: +/// 1, 2, and 3 bytes. For the latter kind, we require a `TlsListElement` implementer +/// to specify a maximum length. +/// +// TODO: make this `pub(crate)` once our MSRV allows it? +pub enum ListLength { + U8, + U16, + U24 { max: usize }, +} diff --git a/vendor/rustls-0.21.8/src/msgs/deframer.rs b/vendor/rustls-0.21.8/src/msgs/deframer.rs new file mode 100644 index 0000000000000..b06117656a75d --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/deframer.rs @@ -0,0 +1,735 @@ +use std::io; +use std::ops::Range; + +use super::base::Payload; +use super::codec::Codec; +use super::message::PlainMessage; +use crate::enums::{ContentType, ProtocolVersion}; +use crate::error::{Error, InvalidMessage, PeerMisbehaved}; +use crate::msgs::codec; +use crate::msgs::message::{MessageError, OpaqueMessage}; +use crate::record_layer::{Decrypted, RecordLayer}; + +/// This deframer works to reconstruct TLS messages from a stream of arbitrary-sized reads. +/// +/// It buffers incoming data into a `Vec` through `read()`, and returns messages through `pop()`. +/// QUIC connections will call `push()` to append handshake payload data directly. +#[derive(Default)] +pub struct MessageDeframer { + /// Set if the peer is not talking TLS, but some other + /// protocol. The caller should abort the connection, because + /// the deframer cannot recover. + last_error: Option, + + /// Buffer of data read from the socket, in the process of being parsed into messages. + /// + /// For buffer size management, checkout out the `read()` method. + buf: Vec, + + /// If we're in the middle of joining a handshake payload, this is the metadata. + joining_hs: Option, + + /// What size prefix of `buf` is used. + used: usize, +} + +impl MessageDeframer { + /// Return any decrypted messages that the deframer has been able to parse. + /// + /// Returns an `Error` if the deframer failed to parse some message contents or if decryption + /// failed, `Ok(None)` if no full message is buffered or if trial decryption failed, and + /// `Ok(Some(_))` if a valid message was found and decrypted successfully. + pub fn pop(&mut self, record_layer: &mut RecordLayer) -> Result, Error> { + if let Some(last_err) = self.last_error.clone() { + return Err(last_err); + } else if self.used == 0 { + return Ok(None); + } + + // We loop over records we've received but not processed yet. + // For records that decrypt as `Handshake`, we keep the current state of the joined + // handshake message payload in `self.joining_hs`, appending to it as we see records. + let expected_len = loop { + let start = match &self.joining_hs { + Some(meta) => { + match meta.expected_len { + // We're joining a handshake payload, and we've seen the full payload. + Some(len) if len <= meta.payload.len() => break len, + // Not enough data, and we can't parse any more out of the buffer (QUIC). + _ if meta.quic => return Ok(None), + // Try parsing some more of the encrypted buffered data. + _ => meta.message.end, + } + } + None => 0, + }; + + // Does our `buf` contain a full message? It does if it is big enough to + // contain a header, and that header has a length which falls within `buf`. + // If so, deframe it and place the message onto the frames output queue. + let mut rd = codec::Reader::init(&self.buf[start..self.used]); + let m = match OpaqueMessage::read(&mut rd) { + Ok(m) => m, + Err(msg_err) => { + let err_kind = match msg_err { + MessageError::TooShortForHeader | MessageError::TooShortForLength => { + return Ok(None) + } + MessageError::InvalidEmptyPayload => InvalidMessage::InvalidEmptyPayload, + MessageError::MessageTooLarge => InvalidMessage::MessageTooLarge, + MessageError::InvalidContentType => InvalidMessage::InvalidContentType, + MessageError::UnknownProtocolVersion => { + InvalidMessage::UnknownProtocolVersion + } + }; + + return Err(self.set_err(err_kind)); + } + }; + + // If we're in the middle of joining a handshake payload and the next message is not of + // type handshake, yield an error. Return CCS messages immediately without decrypting. + let end = start + rd.used(); + if m.typ == ContentType::ChangeCipherSpec && self.joining_hs.is_none() { + // This is unencrypted. We check the contents later. + self.discard(end); + return Ok(Some(Deframed { + want_close_before_decrypt: false, + aligned: true, + trial_decryption_finished: false, + message: m.into_plain_message(), + })); + } + + // Decrypt the encrypted message (if necessary). + let msg = match record_layer.decrypt_incoming(m) { + Ok(Some(decrypted)) => { + let Decrypted { + want_close_before_decrypt, + plaintext, + } = decrypted; + debug_assert!(!want_close_before_decrypt); + plaintext + } + // This was rejected early data, discard it. If we currently have a handshake + // payload in progress, this counts as interleaved, so we error out. + Ok(None) if self.joining_hs.is_some() => { + return Err(self.set_err( + PeerMisbehaved::RejectedEarlyDataInterleavedWithHandshakeMessage, + )); + } + Ok(None) => { + self.discard(end); + continue; + } + Err(e) => return Err(e), + }; + + if self.joining_hs.is_some() && msg.typ != ContentType::Handshake { + // "Handshake messages MUST NOT be interleaved with other record + // types. That is, if a handshake message is split over two or more + // records, there MUST NOT be any other records between them." + // https://www.rfc-editor.org/rfc/rfc8446#section-5.1 + return Err(self.set_err(PeerMisbehaved::MessageInterleavedWithHandshakeMessage)); + } + + // If it's not a handshake message, just return it -- no joining necessary. + if msg.typ != ContentType::Handshake { + let end = start + rd.used(); + self.discard(end); + return Ok(Some(Deframed { + want_close_before_decrypt: false, + aligned: true, + trial_decryption_finished: false, + message: msg, + })); + } + + // If we don't know the payload size yet or if the payload size is larger + // than the currently buffered payload, we need to wait for more data. + match self.append_hs(msg.version, &msg.payload.0, end, false)? { + HandshakePayloadState::Blocked => return Ok(None), + HandshakePayloadState::Complete(len) => break len, + HandshakePayloadState::Continue => continue, + } + }; + + let meta = self.joining_hs.as_mut().unwrap(); // safe after calling `append_hs()` + + // We can now wrap the complete handshake payload in a `PlainMessage`, to be returned. + let message = PlainMessage { + typ: ContentType::Handshake, + version: meta.version, + payload: Payload::new(&self.buf[meta.payload.start..meta.payload.start + expected_len]), + }; + + // But before we return, update the `joining_hs` state to skip past this payload. + if meta.payload.len() > expected_len { + // If we have another (beginning of) a handshake payload left in the buffer, update + // the payload start to point past the payload we're about to yield, and update the + // `expected_len` to match the state of that remaining payload. + meta.payload.start += expected_len; + meta.expected_len = payload_size(&self.buf[meta.payload.start..meta.payload.end])?; + } else { + // Otherwise, we've yielded the last handshake payload in the buffer, so we can + // discard all of the bytes that we're previously buffered as handshake data. + let end = meta.message.end; + self.joining_hs = None; + self.discard(end); + } + + Ok(Some(Deframed { + want_close_before_decrypt: false, + aligned: self.joining_hs.is_none(), + trial_decryption_finished: true, + message, + })) + } + + /// Fuses this deframer's error and returns the set value. + /// + /// Any future calls to `pop` will return `err` again. + fn set_err(&mut self, err: impl Into) -> Error { + let err = err.into(); + self.last_error = Some(err.clone()); + err + } + + /// Allow pushing handshake messages directly into the buffer. + #[cfg(feature = "quic")] + pub fn push(&mut self, version: ProtocolVersion, payload: &[u8]) -> Result<(), Error> { + if self.used > 0 && self.joining_hs.is_none() { + return Err(Error::General( + "cannot push QUIC messages into unrelated connection".into(), + )); + } else if let Err(err) = self.prepare_read() { + return Err(Error::General(err.into())); + } + + let end = self.used + payload.len(); + self.append_hs(version, payload, end, true)?; + self.used = end; + Ok(()) + } + + /// Write the handshake message contents into the buffer and update the metadata. + /// + /// Returns true if a complete message is found. + fn append_hs( + &mut self, + version: ProtocolVersion, + payload: &[u8], + end: usize, + quic: bool, + ) -> Result { + let meta = match &mut self.joining_hs { + Some(meta) => { + debug_assert_eq!(meta.quic, quic); + + // We're joining a handshake message to the previous one here. + // Write it into the buffer and update the metadata. + + let dst = &mut self.buf[meta.payload.end..meta.payload.end + payload.len()]; + dst.copy_from_slice(payload); + meta.message.end = end; + meta.payload.end += payload.len(); + + // If we haven't parsed the payload size yet, try to do so now. + if meta.expected_len.is_none() { + meta.expected_len = + payload_size(&self.buf[meta.payload.start..meta.payload.end])?; + } + + meta + } + None => { + // We've found a new handshake message here. + // Write it into the buffer and create the metadata. + + let expected_len = payload_size(payload)?; + let dst = &mut self.buf[..payload.len()]; + dst.copy_from_slice(payload); + self.joining_hs + .insert(HandshakePayloadMeta { + message: Range { start: 0, end }, + payload: Range { + start: 0, + end: payload.len(), + }, + version, + expected_len, + quic, + }) + } + }; + + Ok(match meta.expected_len { + Some(len) if len <= meta.payload.len() => HandshakePayloadState::Complete(len), + _ => match self.used > meta.message.end { + true => HandshakePayloadState::Continue, + false => HandshakePayloadState::Blocked, + }, + }) + } + + /// Read some bytes from `rd`, and add them to our internal buffer. + #[allow(clippy::comparison_chain)] + pub fn read(&mut self, rd: &mut dyn io::Read) -> io::Result { + if let Err(err) = self.prepare_read() { + return Err(io::Error::new(io::ErrorKind::InvalidData, err)); + } + + // Try to do the largest reads possible. Note that if + // we get a message with a length field out of range here, + // we do a zero length read. That looks like an EOF to + // the next layer up, which is fine. + let new_bytes = rd.read(&mut self.buf[self.used..])?; + self.used += new_bytes; + Ok(new_bytes) + } + + /// Resize the internal `buf` if necessary for reading more bytes. + fn prepare_read(&mut self) -> Result<(), &'static str> { + // We allow a maximum of 64k of buffered data for handshake messages only. Enforce this + // by varying the maximum allowed buffer size here based on whether a prefix of a + // handshake payload is currently being buffered. Given that the first read of such a + // payload will only ever be 4k bytes, the next time we come around here we allow a + // larger buffer size. Once the large message and any following handshake messages in + // the same flight have been consumed, `pop()` will call `discard()` to reset `used`. + // At this point, the buffer resizing logic below should reduce the buffer size. + let allow_max = match self.joining_hs { + Some(_) => MAX_HANDSHAKE_SIZE as usize, + None => OpaqueMessage::MAX_WIRE_SIZE, + }; + + if self.used >= allow_max { + return Err("message buffer full"); + } + + // If we can and need to increase the buffer size to allow a 4k read, do so. After + // dealing with a large handshake message (exceeding `OpaqueMessage::MAX_WIRE_SIZE`), + // make sure to reduce the buffer size again (large messages should be rare). + // Also, reduce the buffer size if there are neither full nor partial messages in it, + // which usually means that the other side suspended sending data. + let need_capacity = Ord::min(allow_max, self.used + READ_SIZE); + if need_capacity > self.buf.len() { + self.buf.resize(need_capacity, 0); + } else if self.used == 0 || self.buf.len() > allow_max { + self.buf.resize(need_capacity, 0); + self.buf.shrink_to(need_capacity); + } + + Ok(()) + } + + /// Returns true if we have messages for the caller + /// to process, either whole messages in our output + /// queue or partial messages in our buffer. + pub fn has_pending(&self) -> bool { + self.used > 0 + } + + /// Discard `taken` bytes from the start of our buffer. + fn discard(&mut self, taken: usize) { + #[allow(clippy::comparison_chain)] + if taken < self.used { + /* Before: + * +----------+----------+----------+ + * | taken | pending |xxxxxxxxxx| + * +----------+----------+----------+ + * 0 ^ taken ^ self.used + * + * After: + * +----------+----------+----------+ + * | pending |xxxxxxxxxxxxxxxxxxxxx| + * +----------+----------+----------+ + * 0 ^ self.used + */ + + self.buf + .copy_within(taken..self.used, 0); + self.used -= taken; + } else if taken == self.used { + self.used = 0; + } + } +} + +enum HandshakePayloadState { + /// Waiting for more data. + Blocked, + /// We have a complete handshake message. + Complete(usize), + /// More records available for processing. + Continue, +} + +struct HandshakePayloadMeta { + /// The range of bytes from the deframer buffer that contains data processed so far. + /// + /// This will need to be discarded as the last of the handshake message is `pop()`ped. + message: Range, + /// The range of bytes from the deframer buffer that contains payload. + payload: Range, + /// The protocol version as found in the decrypted handshake message. + version: ProtocolVersion, + /// The expected size of the handshake payload, if available. + /// + /// If the received payload exceeds 4 bytes (the handshake payload header), we update + /// `expected_len` to contain the payload length as advertised (at most 16_777_215 bytes). + expected_len: Option, + /// True if this is a QUIC handshake message. + /// + /// In the case of QUIC, we get a plaintext handshake data directly from the CRYPTO stream, + /// so there's no need to unwrap and decrypt the outer TLS record. This is implemented + /// by directly calling `MessageDeframer::push()` from the connection. + quic: bool, +} + +/// Determine the expected length of the payload as advertised in the header. +/// +/// Returns `Err` if the advertised length is larger than what we want to accept +/// (`MAX_HANDSHAKE_SIZE`), `Ok(None)` if the buffer is too small to contain a complete header, +/// and `Ok(Some(len))` otherwise. +fn payload_size(buf: &[u8]) -> Result, Error> { + if buf.len() < HEADER_SIZE { + return Ok(None); + } + + let (header, _) = buf.split_at(HEADER_SIZE); + match codec::u24::read_bytes(&header[1..]) { + Ok(len) if len.0 > MAX_HANDSHAKE_SIZE => Err(Error::InvalidMessage( + InvalidMessage::HandshakePayloadTooLarge, + )), + Ok(len) => Ok(Some(HEADER_SIZE + usize::from(len))), + _ => Ok(None), + } +} + +#[derive(Debug)] +pub struct Deframed { + pub want_close_before_decrypt: bool, + pub aligned: bool, + pub trial_decryption_finished: bool, + pub message: PlainMessage, +} + +#[derive(Debug)] +pub enum DeframerError { + HandshakePayloadSizeTooLarge, +} + +const HEADER_SIZE: usize = 1 + 3; + +/// TLS allows for handshake messages of up to 16MB. We +/// restrict that to 64KB to limit potential for denial-of- +/// service. +const MAX_HANDSHAKE_SIZE: u32 = 0xffff; + +const READ_SIZE: usize = 4096; + +#[cfg(test)] +mod tests { + use super::MessageDeframer; + use crate::msgs::message::{Message, OpaqueMessage}; + use crate::record_layer::RecordLayer; + use crate::{ContentType, Error, InvalidMessage}; + + use std::io; + + const FIRST_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-test.1.bin"); + const SECOND_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-test.2.bin"); + + const EMPTY_APPLICATIONDATA_MESSAGE: &[u8] = + include_bytes!("../testdata/deframer-empty-applicationdata.bin"); + + const INVALID_EMPTY_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-invalid-empty.bin"); + const INVALID_CONTENTTYPE_MESSAGE: &[u8] = + include_bytes!("../testdata/deframer-invalid-contenttype.bin"); + const INVALID_VERSION_MESSAGE: &[u8] = + include_bytes!("../testdata/deframer-invalid-version.bin"); + const INVALID_LENGTH_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-invalid-length.bin"); + + fn input_bytes(d: &mut MessageDeframer, bytes: &[u8]) -> io::Result { + let mut rd = io::Cursor::new(bytes); + d.read(&mut rd) + } + + fn input_bytes_concat( + d: &mut MessageDeframer, + bytes1: &[u8], + bytes2: &[u8], + ) -> io::Result { + let mut bytes = vec![0u8; bytes1.len() + bytes2.len()]; + bytes[..bytes1.len()].clone_from_slice(bytes1); + bytes[bytes1.len()..].clone_from_slice(bytes2); + let mut rd = io::Cursor::new(&bytes); + d.read(&mut rd) + } + + struct ErrorRead { + error: Option, + } + + impl ErrorRead { + fn new(error: io::Error) -> Self { + Self { error: Some(error) } + } + } + + impl io::Read for ErrorRead { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + for (i, b) in buf.iter_mut().enumerate() { + *b = i as u8; + } + + let error = self.error.take().unwrap(); + Err(error) + } + } + + fn input_error(d: &mut MessageDeframer) { + let error = io::Error::from(io::ErrorKind::TimedOut); + let mut rd = ErrorRead::new(error); + d.read(&mut rd) + .expect_err("error not propagated"); + } + + fn input_whole_incremental(d: &mut MessageDeframer, bytes: &[u8]) { + let before = d.used; + + for i in 0..bytes.len() { + assert_len(1, input_bytes(d, &bytes[i..i + 1])); + assert!(d.has_pending()); + } + + assert_eq!(before + bytes.len(), d.used); + } + + fn assert_len(want: usize, got: io::Result) { + if let Ok(gotval) = got { + assert_eq!(gotval, want); + } else { + panic!("read failed, expected {:?} bytes", want); + } + } + + fn pop_first(d: &mut MessageDeframer, rl: &mut RecordLayer) { + let m = d.pop(rl).unwrap().unwrap().message; + assert_eq!(m.typ, ContentType::Handshake); + Message::try_from(m).unwrap(); + } + + fn pop_second(d: &mut MessageDeframer, rl: &mut RecordLayer) { + let m = d.pop(rl).unwrap().unwrap().message; + assert_eq!(m.typ, ContentType::Alert); + Message::try_from(m).unwrap(); + } + + #[test] + fn check_incremental() { + let mut d = MessageDeframer::default(); + assert!(!d.has_pending()); + input_whole_incremental(&mut d, FIRST_MESSAGE); + assert!(d.has_pending()); + + let mut rl = RecordLayer::new(); + pop_first(&mut d, &mut rl); + assert!(!d.has_pending()); + assert!(d.last_error.is_none()); + } + + #[test] + fn check_incremental_2() { + let mut d = MessageDeframer::default(); + assert!(!d.has_pending()); + input_whole_incremental(&mut d, FIRST_MESSAGE); + assert!(d.has_pending()); + input_whole_incremental(&mut d, SECOND_MESSAGE); + assert!(d.has_pending()); + + let mut rl = RecordLayer::new(); + pop_first(&mut d, &mut rl); + assert!(d.has_pending()); + pop_second(&mut d, &mut rl); + assert!(!d.has_pending()); + assert!(d.last_error.is_none()); + } + + #[test] + fn check_whole() { + let mut d = MessageDeframer::default(); + assert!(!d.has_pending()); + assert_len(FIRST_MESSAGE.len(), input_bytes(&mut d, FIRST_MESSAGE)); + assert!(d.has_pending()); + + let mut rl = RecordLayer::new(); + pop_first(&mut d, &mut rl); + assert!(!d.has_pending()); + assert!(d.last_error.is_none()); + } + + #[test] + fn check_whole_2() { + let mut d = MessageDeframer::default(); + assert!(!d.has_pending()); + assert_len(FIRST_MESSAGE.len(), input_bytes(&mut d, FIRST_MESSAGE)); + assert_len(SECOND_MESSAGE.len(), input_bytes(&mut d, SECOND_MESSAGE)); + + let mut rl = RecordLayer::new(); + pop_first(&mut d, &mut rl); + pop_second(&mut d, &mut rl); + assert!(!d.has_pending()); + assert!(d.last_error.is_none()); + } + + #[test] + fn test_two_in_one_read() { + let mut d = MessageDeframer::default(); + assert!(!d.has_pending()); + assert_len( + FIRST_MESSAGE.len() + SECOND_MESSAGE.len(), + input_bytes_concat(&mut d, FIRST_MESSAGE, SECOND_MESSAGE), + ); + + let mut rl = RecordLayer::new(); + pop_first(&mut d, &mut rl); + pop_second(&mut d, &mut rl); + assert!(!d.has_pending()); + assert!(d.last_error.is_none()); + } + + #[test] + fn test_two_in_one_read_shortest_first() { + let mut d = MessageDeframer::default(); + assert!(!d.has_pending()); + assert_len( + FIRST_MESSAGE.len() + SECOND_MESSAGE.len(), + input_bytes_concat(&mut d, SECOND_MESSAGE, FIRST_MESSAGE), + ); + + let mut rl = RecordLayer::new(); + pop_second(&mut d, &mut rl); + pop_first(&mut d, &mut rl); + assert!(!d.has_pending()); + assert!(d.last_error.is_none()); + } + + #[test] + fn test_incremental_with_nonfatal_read_error() { + let mut d = MessageDeframer::default(); + assert_len(3, input_bytes(&mut d, &FIRST_MESSAGE[..3])); + input_error(&mut d); + assert_len( + FIRST_MESSAGE.len() - 3, + input_bytes(&mut d, &FIRST_MESSAGE[3..]), + ); + + let mut rl = RecordLayer::new(); + pop_first(&mut d, &mut rl); + assert!(!d.has_pending()); + assert!(d.last_error.is_none()); + } + + #[test] + fn test_invalid_contenttype_errors() { + let mut d = MessageDeframer::default(); + assert_len( + INVALID_CONTENTTYPE_MESSAGE.len(), + input_bytes(&mut d, INVALID_CONTENTTYPE_MESSAGE), + ); + + let mut rl = RecordLayer::new(); + assert_eq!( + d.pop(&mut rl).unwrap_err(), + Error::InvalidMessage(InvalidMessage::InvalidContentType) + ); + } + + #[test] + fn test_invalid_version_errors() { + let mut d = MessageDeframer::default(); + assert_len( + INVALID_VERSION_MESSAGE.len(), + input_bytes(&mut d, INVALID_VERSION_MESSAGE), + ); + + let mut rl = RecordLayer::new(); + assert_eq!( + d.pop(&mut rl).unwrap_err(), + Error::InvalidMessage(InvalidMessage::UnknownProtocolVersion) + ); + } + + #[test] + fn test_invalid_length_errors() { + let mut d = MessageDeframer::default(); + assert_len( + INVALID_LENGTH_MESSAGE.len(), + input_bytes(&mut d, INVALID_LENGTH_MESSAGE), + ); + + let mut rl = RecordLayer::new(); + assert_eq!( + d.pop(&mut rl).unwrap_err(), + Error::InvalidMessage(InvalidMessage::MessageTooLarge) + ); + } + + #[test] + fn test_empty_applicationdata() { + let mut d = MessageDeframer::default(); + assert_len( + EMPTY_APPLICATIONDATA_MESSAGE.len(), + input_bytes(&mut d, EMPTY_APPLICATIONDATA_MESSAGE), + ); + + let mut rl = RecordLayer::new(); + let m = d.pop(&mut rl).unwrap().unwrap().message; + assert_eq!(m.typ, ContentType::ApplicationData); + assert_eq!(m.payload.0.len(), 0); + assert!(!d.has_pending()); + assert!(d.last_error.is_none()); + } + + #[test] + fn test_invalid_empty_errors() { + let mut d = MessageDeframer::default(); + assert_len( + INVALID_EMPTY_MESSAGE.len(), + input_bytes(&mut d, INVALID_EMPTY_MESSAGE), + ); + + let mut rl = RecordLayer::new(); + assert_eq!( + d.pop(&mut rl).unwrap_err(), + Error::InvalidMessage(InvalidMessage::InvalidEmptyPayload) + ); + // CorruptMessage has been fused + assert_eq!( + d.pop(&mut rl).unwrap_err(), + Error::InvalidMessage(InvalidMessage::InvalidEmptyPayload) + ); + } + + #[test] + fn test_limited_buffer() { + const PAYLOAD_LEN: usize = 16_384; + let mut message = Vec::with_capacity(16_389); + message.push(0x17); // ApplicationData + message.extend(&[0x03, 0x04]); // ProtocolVersion + message.extend((PAYLOAD_LEN as u16).to_be_bytes()); // payload length + message.extend(&[0; PAYLOAD_LEN]); + + let mut d = MessageDeframer::default(); + assert_len(4096, input_bytes(&mut d, &message)); + assert_len(4096, input_bytes(&mut d, &message)); + assert_len(4096, input_bytes(&mut d, &message)); + assert_len(4096, input_bytes(&mut d, &message)); + assert_len( + OpaqueMessage::MAX_WIRE_SIZE - 16_384, + input_bytes(&mut d, &message), + ); + assert!(input_bytes(&mut d, &message).is_err()); + } +} diff --git a/vendor/rustls-0.21.8/src/msgs/enums.rs b/vendor/rustls-0.21.8/src/msgs/enums.rs new file mode 100644 index 0000000000000..3861722001f91 --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/enums.rs @@ -0,0 +1,372 @@ +#![allow(clippy::upper_case_acronyms)] +#![allow(non_camel_case_types)] +/// This file is autogenerated. See https://github.com/ctz/tls-hacking/ +use crate::msgs::codec::{Codec, Reader}; + +enum_builder! { + /// The `HashAlgorithm` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: HashAlgorithm; + EnumVal{ + NONE => 0x00, + MD5 => 0x01, + SHA1 => 0x02, + SHA224 => 0x03, + SHA256 => 0x04, + SHA384 => 0x05, + SHA512 => 0x06 + } +} + +enum_builder! { + /// The `ClientCertificateType` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: ClientCertificateType; + EnumVal{ + RSASign => 0x01, + DSSSign => 0x02, + RSAFixedDH => 0x03, + DSSFixedDH => 0x04, + RSAEphemeralDH => 0x05, + DSSEphemeralDH => 0x06, + FortezzaDMS => 0x14, + ECDSASign => 0x40, + RSAFixedECDH => 0x41, + ECDSAFixedECDH => 0x42 + } +} + +enum_builder! { + /// The `Compression` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: Compression; + EnumVal{ + Null => 0x00, + Deflate => 0x01, + LSZ => 0x40 + } +} + +enum_builder! { + /// The `AlertLevel` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: AlertLevel; + EnumVal{ + Warning => 0x01, + Fatal => 0x02 + } +} + +enum_builder! { + /// The `HeartbeatMessageType` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: HeartbeatMessageType; + EnumVal{ + Request => 0x01, + Response => 0x02 + } +} + +enum_builder! { + /// The `ExtensionType` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U16 + EnumName: ExtensionType; + EnumVal{ + ServerName => 0x0000, + MaxFragmentLength => 0x0001, + ClientCertificateUrl => 0x0002, + TrustedCAKeys => 0x0003, + TruncatedHMAC => 0x0004, + StatusRequest => 0x0005, + UserMapping => 0x0006, + ClientAuthz => 0x0007, + ServerAuthz => 0x0008, + CertificateType => 0x0009, + EllipticCurves => 0x000a, + ECPointFormats => 0x000b, + SRP => 0x000c, + SignatureAlgorithms => 0x000d, + UseSRTP => 0x000e, + Heartbeat => 0x000f, + ALProtocolNegotiation => 0x0010, + SCT => 0x0012, + Padding => 0x0015, + ExtendedMasterSecret => 0x0017, + SessionTicket => 0x0023, + PreSharedKey => 0x0029, + EarlyData => 0x002a, + SupportedVersions => 0x002b, + Cookie => 0x002c, + PSKKeyExchangeModes => 0x002d, + TicketEarlyDataInfo => 0x002e, + CertificateAuthorities => 0x002f, + OIDFilters => 0x0030, + PostHandshakeAuth => 0x0031, + SignatureAlgorithmsCert => 0x0032, + KeyShare => 0x0033, + TransportParameters => 0x0039, + NextProtocolNegotiation => 0x3374, + ChannelId => 0x754f, + RenegotiationInfo => 0xff01, + TransportParametersDraft => 0xffa5 + } +} + +enum_builder! { + /// The `ServerNameType` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: ServerNameType; + EnumVal{ + HostName => 0x00 + } +} + +enum_builder! { + /// The `NamedCurve` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + /// + /// This enum is used for recognizing elliptic curve parameters advertised + /// by a peer during a TLS handshake. It is **not** a list of curves that + /// Rustls supports. See [`crate::kx_group`] for the list of supported + /// elliptic curve groups. + @U16 + EnumName: NamedCurve; + EnumVal{ + sect163k1 => 0x0001, + sect163r1 => 0x0002, + sect163r2 => 0x0003, + sect193r1 => 0x0004, + sect193r2 => 0x0005, + sect233k1 => 0x0006, + sect233r1 => 0x0007, + sect239k1 => 0x0008, + sect283k1 => 0x0009, + sect283r1 => 0x000a, + sect409k1 => 0x000b, + sect409r1 => 0x000c, + sect571k1 => 0x000d, + sect571r1 => 0x000e, + secp160k1 => 0x000f, + secp160r1 => 0x0010, + secp160r2 => 0x0011, + secp192k1 => 0x0012, + secp192r1 => 0x0013, + secp224k1 => 0x0014, + secp224r1 => 0x0015, + secp256k1 => 0x0016, + secp256r1 => 0x0017, + secp384r1 => 0x0018, + secp521r1 => 0x0019, + brainpoolp256r1 => 0x001a, + brainpoolp384r1 => 0x001b, + brainpoolp512r1 => 0x001c, + X25519 => 0x001d, + X448 => 0x001e, + arbitrary_explicit_prime_curves => 0xff01, + arbitrary_explicit_char2_curves => 0xff02 + } +} + +enum_builder! { + /// The `NamedGroup` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U16 + EnumName: NamedGroup; + EnumVal{ + secp256r1 => 0x0017, + secp384r1 => 0x0018, + secp521r1 => 0x0019, + X25519 => 0x001d, + X448 => 0x001e, + FFDHE2048 => 0x0100, + FFDHE3072 => 0x0101, + FFDHE4096 => 0x0102, + FFDHE6144 => 0x0103, + FFDHE8192 => 0x0104 + } +} + +enum_builder! { + /// The `ECPointFormat` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: ECPointFormat; + EnumVal{ + Uncompressed => 0x00, + ANSIX962CompressedPrime => 0x01, + ANSIX962CompressedChar2 => 0x02 + } +} + +impl ECPointFormat { + pub const SUPPORTED: [Self; 1] = [Self::Uncompressed]; +} + +enum_builder! { + /// The `HeartbeatMode` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: HeartbeatMode; + EnumVal{ + PeerAllowedToSend => 0x01, + PeerNotAllowedToSend => 0x02 + } +} + +enum_builder! { + /// The `ECCurveType` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: ECCurveType; + EnumVal{ + ExplicitPrime => 0x01, + ExplicitChar2 => 0x02, + NamedCurve => 0x03 + } +} + +enum_builder! { + /// The `PSKKeyExchangeMode` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: PSKKeyExchangeMode; + EnumVal{ + PSK_KE => 0x00, + PSK_DHE_KE => 0x01 + } +} + +enum_builder! { + /// The `KeyUpdateRequest` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: KeyUpdateRequest; + EnumVal{ + UpdateNotRequested => 0x00, + UpdateRequested => 0x01 + } +} + +enum_builder! { + /// The `CertificateStatusType` TLS protocol enum. Values in this enum are taken + /// from the various RFCs covering TLS, and are listed by IANA. + /// The `Unknown` item is used when processing unrecognised ordinals. + @U8 + EnumName: CertificateStatusType; + EnumVal{ + OCSP => 0x01 + } +} + +#[cfg(test)] +pub(crate) mod tests { + //! These tests are intended to provide coverage and + //! check panic-safety of relatively unused values. + + use super::*; + use crate::msgs::codec::Codec; + + #[test] + fn test_enums() { + test_enum8::(HashAlgorithm::NONE, HashAlgorithm::SHA512); + test_enum8::( + ClientCertificateType::RSASign, + ClientCertificateType::ECDSAFixedECDH, + ); + test_enum8::(Compression::Null, Compression::LSZ); + test_enum8::(AlertLevel::Warning, AlertLevel::Fatal); + test_enum8::( + HeartbeatMessageType::Request, + HeartbeatMessageType::Response, + ); + test_enum16::(ExtensionType::ServerName, ExtensionType::RenegotiationInfo); + test_enum8::(ServerNameType::HostName, ServerNameType::HostName); + test_enum16::( + NamedCurve::sect163k1, + NamedCurve::arbitrary_explicit_char2_curves, + ); + test_enum16::(NamedGroup::secp256r1, NamedGroup::FFDHE8192); + test_enum8::( + ECPointFormat::Uncompressed, + ECPointFormat::ANSIX962CompressedChar2, + ); + test_enum8::( + HeartbeatMode::PeerAllowedToSend, + HeartbeatMode::PeerNotAllowedToSend, + ); + test_enum8::(ECCurveType::ExplicitPrime, ECCurveType::NamedCurve); + test_enum8::( + PSKKeyExchangeMode::PSK_KE, + PSKKeyExchangeMode::PSK_DHE_KE, + ); + test_enum8::( + KeyUpdateRequest::UpdateNotRequested, + KeyUpdateRequest::UpdateRequested, + ); + test_enum8::( + CertificateStatusType::OCSP, + CertificateStatusType::OCSP, + ); + } + + pub(crate) fn test_enum8(first: T, last: T) { + let first_v = get8(&first); + let last_v = get8(&last); + + for val in first_v..last_v + 1 { + let mut buf = Vec::new(); + val.encode(&mut buf); + assert_eq!(buf.len(), 1); + + let t = T::read_bytes(&buf).unwrap(); + assert_eq!(val, get8(&t)); + } + } + + pub(crate) fn test_enum16(first: T, last: T) { + let first_v = get16(&first); + let last_v = get16(&last); + + for val in first_v..last_v + 1 { + let mut buf = Vec::new(); + val.encode(&mut buf); + assert_eq!(buf.len(), 2); + + let t = T::read_bytes(&buf).unwrap(); + assert_eq!(val, get16(&t)); + } + } + + fn get8(enum_value: &T) -> u8 { + let enc = enum_value.get_encoding(); + assert_eq!(enc.len(), 1); + enc[0] + } + + fn get16(enum_value: &T) -> u16 { + let enc = enum_value.get_encoding(); + assert_eq!(enc.len(), 2); + (enc[0] as u16 >> 8) | (enc[1] as u16) + } +} diff --git a/vendor/rustls-0.21.8/src/msgs/fragmenter.rs b/vendor/rustls-0.21.8/src/msgs/fragmenter.rs new file mode 100644 index 0000000000000..ac930b1ea7756 --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/fragmenter.rs @@ -0,0 +1,162 @@ +use crate::enums::ContentType; +use crate::enums::ProtocolVersion; +use crate::msgs::message::{BorrowedPlainMessage, PlainMessage}; +use crate::Error; +pub const MAX_FRAGMENT_LEN: usize = 16384; +pub const PACKET_OVERHEAD: usize = 1 + 2 + 2; +pub const MAX_FRAGMENT_SIZE: usize = MAX_FRAGMENT_LEN + PACKET_OVERHEAD; + +pub struct MessageFragmenter { + max_frag: usize, +} + +impl Default for MessageFragmenter { + fn default() -> Self { + Self { + max_frag: MAX_FRAGMENT_LEN, + } + } +} + +impl MessageFragmenter { + /// Take the Message `msg` and re-fragment it into new + /// messages whose fragment is no more than max_frag. + /// Return an iterator across those messages. + /// Payloads are borrowed. + pub fn fragment_message<'a>( + &self, + msg: &'a PlainMessage, + ) -> impl Iterator> + 'a { + self.fragment_slice(msg.typ, msg.version, &msg.payload.0) + } + + /// Enqueue borrowed fragments of (version, typ, payload) which + /// are no longer than max_frag onto the `out` deque. + pub fn fragment_slice<'a>( + &self, + typ: ContentType, + version: ProtocolVersion, + payload: &'a [u8], + ) -> impl Iterator> + 'a { + payload + .chunks(self.max_frag) + .map(move |c| BorrowedPlainMessage { + typ, + version, + payload: c, + }) + } + + /// Set the maximum fragment size that will be produced. + /// + /// This includes overhead. A `max_fragment_size` of 10 will produce TLS fragments + /// up to 10 bytes long. + /// + /// A `max_fragment_size` of `None` sets the highest allowable fragment size. + /// + /// Returns BadMaxFragmentSize if the size is smaller than 32 or larger than 16389. + pub fn set_max_fragment_size(&mut self, max_fragment_size: Option) -> Result<(), Error> { + self.max_frag = match max_fragment_size { + Some(sz @ 32..=MAX_FRAGMENT_SIZE) => sz - PACKET_OVERHEAD, + None => MAX_FRAGMENT_LEN, + _ => return Err(Error::BadMaxFragmentSize), + }; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::{MessageFragmenter, PACKET_OVERHEAD}; + use crate::enums::ContentType; + use crate::enums::ProtocolVersion; + use crate::msgs::base::Payload; + use crate::msgs::message::{BorrowedPlainMessage, PlainMessage}; + + fn msg_eq( + m: &BorrowedPlainMessage, + total_len: usize, + typ: &ContentType, + version: &ProtocolVersion, + bytes: &[u8], + ) { + assert_eq!(&m.typ, typ); + assert_eq!(&m.version, version); + assert_eq!(m.payload, bytes); + + let buf = m.to_unencrypted_opaque().encode(); + + assert_eq!(total_len, buf.len()); + } + + #[test] + fn smoke() { + let typ = ContentType::Handshake; + let version = ProtocolVersion::TLSv1_2; + let data: Vec = (1..70u8).collect(); + let m = PlainMessage { + typ, + version, + payload: Payload::new(data), + }; + + let mut frag = MessageFragmenter::default(); + frag.set_max_fragment_size(Some(32)) + .unwrap(); + let q = frag + .fragment_message(&m) + .collect::>(); + assert_eq!(q.len(), 3); + msg_eq( + &q[0], + 32, + &typ, + &version, + &[ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, + ], + ); + msg_eq( + &q[1], + 32, + &typ, + &version, + &[ + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, + ], + ); + msg_eq( + &q[2], + 20, + &typ, + &version, + &[55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69], + ); + } + + #[test] + fn non_fragment() { + let m = PlainMessage { + typ: ContentType::Handshake, + version: ProtocolVersion::TLSv1_2, + payload: Payload::new(b"\x01\x02\x03\x04\x05\x06\x07\x08".to_vec()), + }; + + let mut frag = MessageFragmenter::default(); + frag.set_max_fragment_size(Some(32)) + .unwrap(); + let q = frag + .fragment_message(&m) + .collect::>(); + assert_eq!(q.len(), 1); + msg_eq( + &q[0], + PACKET_OVERHEAD + 8, + &ContentType::Handshake, + &ProtocolVersion::TLSv1_2, + b"\x01\x02\x03\x04\x05\x06\x07\x08", + ); + } +} diff --git a/vendor/rustls-0.21.8/src/msgs/handshake-test.1.bin b/vendor/rustls-0.21.8/src/msgs/handshake-test.1.bin new file mode 100644 index 0000000000000..5c04f3f6064a5 Binary files /dev/null and b/vendor/rustls-0.21.8/src/msgs/handshake-test.1.bin differ diff --git a/vendor/rustls-0.21.8/src/msgs/handshake.rs b/vendor/rustls-0.21.8/src/msgs/handshake.rs new file mode 100644 index 0000000000000..f8be007ed5c3d --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/handshake.rs @@ -0,0 +1,2299 @@ +#![allow(non_camel_case_types)] +use crate::dns_name::{DnsName, DnsNameRef}; +use crate::enums::{CipherSuite, HandshakeType, ProtocolVersion, SignatureScheme}; +use crate::error::InvalidMessage; +use crate::key; +#[cfg(feature = "logging")] +use crate::log::warn; +use crate::msgs::base::{Payload, PayloadU16, PayloadU24, PayloadU8}; +use crate::msgs::codec::{self, Codec, ListLength, Reader, TlsListElement}; +use crate::msgs::enums::{ + CertificateStatusType, ClientCertificateType, Compression, ECCurveType, ECPointFormat, + ExtensionType, KeyUpdateRequest, NamedGroup, PSKKeyExchangeMode, ServerNameType, +}; +use crate::rand; +use crate::verify::DigitallySignedStruct; + +use std::collections; +use std::fmt; + +/// Create a newtype wrapper around a given type. +/// +/// This is used to create newtypes for the various TLS message types which is used to wrap +/// the `PayloadU8` or `PayloadU16` types. This is typically used for types where we don't need +/// anything other than access to the underlying bytes. +macro_rules! wrapped_payload( + ($(#[$comment:meta])* $name:ident, $inner:ident,) => { + $(#[$comment])* + #[derive(Clone, Debug)] + pub struct $name($inner); + + impl From> for $name { + fn from(v: Vec) -> Self { + Self($inner::new(v)) + } + } + + impl AsRef<[u8]> for $name { + fn as_ref(&self) -> &[u8] { + self.0.0.as_slice() + } + } + + impl Codec for $name { + fn encode(&self, bytes: &mut Vec) { + self.0.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + Ok(Self($inner::read(r)?)) + } + } + } +); + +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Random(pub [u8; 32]); + +impl fmt::Debug for Random { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + super::base::hex(f, &self.0) + } +} + +static HELLO_RETRY_REQUEST_RANDOM: Random = Random([ + 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91, + 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c, +]); + +static ZERO_RANDOM: Random = Random([0u8; 32]); + +impl Codec for Random { + fn encode(&self, bytes: &mut Vec) { + bytes.extend_from_slice(&self.0); + } + + fn read(r: &mut Reader) -> Result { + let bytes = match r.take(32) { + Some(bytes) => bytes, + None => return Err(InvalidMessage::MissingData("Random")), + }; + + let mut opaque = [0; 32]; + opaque.clone_from_slice(bytes); + Ok(Self(opaque)) + } +} + +impl Random { + pub fn new() -> Result { + let mut data = [0u8; 32]; + rand::fill_random(&mut data)?; + Ok(Self(data)) + } + + pub fn write_slice(&self, bytes: &mut [u8]) { + let buf = self.get_encoding(); + bytes.copy_from_slice(&buf); + } +} + +impl From<[u8; 32]> for Random { + #[inline] + fn from(bytes: [u8; 32]) -> Self { + Self(bytes) + } +} + +#[derive(Copy, Clone)] +pub struct SessionId { + len: usize, + data: [u8; 32], +} + +impl fmt::Debug for SessionId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + super::base::hex(f, &self.data[..self.len]) + } +} + +impl PartialEq for SessionId { + fn eq(&self, other: &Self) -> bool { + if self.len != other.len { + return false; + } + + let mut diff = 0u8; + for i in 0..self.len { + diff |= self.data[i] ^ other.data[i]; + } + + diff == 0u8 + } +} + +impl Codec for SessionId { + fn encode(&self, bytes: &mut Vec) { + debug_assert!(self.len <= 32); + bytes.push(self.len as u8); + bytes.extend_from_slice(&self.data[..self.len]); + } + + fn read(r: &mut Reader) -> Result { + let len = u8::read(r)? as usize; + if len > 32 { + return Err(InvalidMessage::TrailingData("SessionID")); + } + + let bytes = match r.take(len) { + Some(bytes) => bytes, + None => return Err(InvalidMessage::MissingData("SessionID")), + }; + + let mut out = [0u8; 32]; + out[..len].clone_from_slice(&bytes[..len]); + Ok(Self { data: out, len }) + } +} + +impl SessionId { + pub fn random() -> Result { + let mut data = [0u8; 32]; + rand::fill_random(&mut data)?; + Ok(Self { data, len: 32 }) + } + + pub fn empty() -> Self { + Self { + data: [0u8; 32], + len: 0, + } + } + + pub fn len(&self) -> usize { + self.len + } + + pub fn is_empty(&self) -> bool { + self.len == 0 + } +} + +#[derive(Clone, Debug)] +pub struct UnknownExtension { + pub typ: ExtensionType, + pub payload: Payload, +} + +impl UnknownExtension { + fn encode(&self, bytes: &mut Vec) { + self.payload.encode(bytes); + } + + fn read(typ: ExtensionType, r: &mut Reader) -> Self { + let payload = Payload::read(r); + Self { typ, payload } + } +} + +impl TlsListElement for ECPointFormat { + const SIZE_LEN: ListLength = ListLength::U8; +} + +impl TlsListElement for NamedGroup { + const SIZE_LEN: ListLength = ListLength::U16; +} + +impl TlsListElement for SignatureScheme { + const SIZE_LEN: ListLength = ListLength::U16; +} + +#[derive(Clone, Debug)] +pub enum ServerNamePayload { + HostName(DnsName), + Unknown(Payload), +} + +impl ServerNamePayload { + pub fn new_hostname(hostname: DnsName) -> Self { + Self::HostName(hostname) + } + + fn read_hostname(r: &mut Reader) -> Result { + let raw = PayloadU16::read(r)?; + + match DnsName::try_from_ascii(&raw.0) { + Ok(dns_name) => Ok(Self::HostName(dns_name)), + Err(_) => { + warn!( + "Illegal SNI hostname received {:?}", + String::from_utf8_lossy(&raw.0) + ); + Err(InvalidMessage::InvalidServerName) + } + } + } + + fn encode(&self, bytes: &mut Vec) { + match *self { + Self::HostName(ref name) => { + (name.as_ref().len() as u16).encode(bytes); + bytes.extend_from_slice(name.as_ref().as_bytes()); + } + Self::Unknown(ref r) => r.encode(bytes), + } + } +} + +#[derive(Clone, Debug)] +pub struct ServerName { + pub typ: ServerNameType, + pub payload: ServerNamePayload, +} + +impl Codec for ServerName { + fn encode(&self, bytes: &mut Vec) { + self.typ.encode(bytes); + self.payload.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let typ = ServerNameType::read(r)?; + + let payload = match typ { + ServerNameType::HostName => ServerNamePayload::read_hostname(r)?, + _ => ServerNamePayload::Unknown(Payload::read(r)), + }; + + Ok(Self { typ, payload }) + } +} + +impl TlsListElement for ServerName { + const SIZE_LEN: ListLength = ListLength::U16; +} + +pub trait ConvertServerNameList { + fn has_duplicate_names_for_type(&self) -> bool; + fn get_single_hostname(&self) -> Option; +} + +impl ConvertServerNameList for [ServerName] { + /// RFC6066: "The ServerNameList MUST NOT contain more than one name of the same name_type." + fn has_duplicate_names_for_type(&self) -> bool { + let mut seen = collections::HashSet::new(); + + for name in self { + if !seen.insert(name.typ.get_u8()) { + return true; + } + } + + false + } + + fn get_single_hostname(&self) -> Option { + fn only_dns_hostnames(name: &ServerName) -> Option { + if let ServerNamePayload::HostName(ref dns) = name.payload { + Some(dns.borrow()) + } else { + None + } + } + + self.iter() + .filter_map(only_dns_hostnames) + .next() + } +} + +wrapped_payload!(ProtocolName, PayloadU8,); + +impl TlsListElement for ProtocolName { + const SIZE_LEN: ListLength = ListLength::U16; +} + +pub trait ConvertProtocolNameList { + fn from_slices(names: &[&[u8]]) -> Self; + fn to_slices(&self) -> Vec<&[u8]>; + fn as_single_slice(&self) -> Option<&[u8]>; +} + +impl ConvertProtocolNameList for Vec { + fn from_slices(names: &[&[u8]]) -> Self { + let mut ret = Self::new(); + + for name in names { + ret.push(ProtocolName::from(name.to_vec())); + } + + ret + } + + fn to_slices(&self) -> Vec<&[u8]> { + self.iter() + .map(|proto| proto.as_ref()) + .collect::>() + } + + fn as_single_slice(&self) -> Option<&[u8]> { + if self.len() == 1 { + Some(self[0].as_ref()) + } else { + None + } + } +} + +// --- TLS 1.3 Key shares --- +#[derive(Clone, Debug)] +pub struct KeyShareEntry { + pub group: NamedGroup, + pub payload: PayloadU16, +} + +impl KeyShareEntry { + pub fn new(group: NamedGroup, payload: &[u8]) -> Self { + Self { + group, + payload: PayloadU16::new(payload.to_vec()), + } + } +} + +impl Codec for KeyShareEntry { + fn encode(&self, bytes: &mut Vec) { + self.group.encode(bytes); + self.payload.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let group = NamedGroup::read(r)?; + let payload = PayloadU16::read(r)?; + + Ok(Self { group, payload }) + } +} + +// --- TLS 1.3 PresharedKey offers --- +#[derive(Clone, Debug)] +pub struct PresharedKeyIdentity { + pub identity: PayloadU16, + pub obfuscated_ticket_age: u32, +} + +impl PresharedKeyIdentity { + pub fn new(id: Vec, age: u32) -> Self { + Self { + identity: PayloadU16::new(id), + obfuscated_ticket_age: age, + } + } +} + +impl Codec for PresharedKeyIdentity { + fn encode(&self, bytes: &mut Vec) { + self.identity.encode(bytes); + self.obfuscated_ticket_age.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + Ok(Self { + identity: PayloadU16::read(r)?, + obfuscated_ticket_age: u32::read(r)?, + }) + } +} + +impl TlsListElement for PresharedKeyIdentity { + const SIZE_LEN: ListLength = ListLength::U16; +} + +wrapped_payload!(PresharedKeyBinder, PayloadU8,); + +impl TlsListElement for PresharedKeyBinder { + const SIZE_LEN: ListLength = ListLength::U16; +} + +#[derive(Clone, Debug)] +pub struct PresharedKeyOffer { + pub identities: Vec, + pub binders: Vec, +} + +impl PresharedKeyOffer { + /// Make a new one with one entry. + pub fn new(id: PresharedKeyIdentity, binder: Vec) -> Self { + Self { + identities: vec![id], + binders: vec![PresharedKeyBinder::from(binder)], + } + } +} + +impl Codec for PresharedKeyOffer { + fn encode(&self, bytes: &mut Vec) { + self.identities.encode(bytes); + self.binders.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + Ok(Self { + identities: Vec::read(r)?, + binders: Vec::read(r)?, + }) + } +} + +// --- RFC6066 certificate status request --- +wrapped_payload!(ResponderId, PayloadU16,); + +impl TlsListElement for ResponderId { + const SIZE_LEN: ListLength = ListLength::U16; +} + +#[derive(Clone, Debug)] +pub struct OCSPCertificateStatusRequest { + pub responder_ids: Vec, + pub extensions: PayloadU16, +} + +impl Codec for OCSPCertificateStatusRequest { + fn encode(&self, bytes: &mut Vec) { + CertificateStatusType::OCSP.encode(bytes); + self.responder_ids.encode(bytes); + self.extensions.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + Ok(Self { + responder_ids: Vec::read(r)?, + extensions: PayloadU16::read(r)?, + }) + } +} + +#[derive(Clone, Debug)] +pub enum CertificateStatusRequest { + OCSP(OCSPCertificateStatusRequest), + Unknown((CertificateStatusType, Payload)), +} + +impl Codec for CertificateStatusRequest { + fn encode(&self, bytes: &mut Vec) { + match self { + Self::OCSP(ref r) => r.encode(bytes), + Self::Unknown((typ, payload)) => { + typ.encode(bytes); + payload.encode(bytes); + } + } + } + + fn read(r: &mut Reader) -> Result { + let typ = CertificateStatusType::read(r)?; + + match typ { + CertificateStatusType::OCSP => { + let ocsp_req = OCSPCertificateStatusRequest::read(r)?; + Ok(Self::OCSP(ocsp_req)) + } + _ => { + let data = Payload::read(r); + Ok(Self::Unknown((typ, data))) + } + } + } +} + +impl CertificateStatusRequest { + pub fn build_ocsp() -> Self { + let ocsp = OCSPCertificateStatusRequest { + responder_ids: Vec::new(), + extensions: PayloadU16::empty(), + }; + Self::OCSP(ocsp) + } +} + +// --- +// SCTs + +wrapped_payload!(Sct, PayloadU16,); + +impl TlsListElement for Sct { + const SIZE_LEN: ListLength = ListLength::U16; +} + +// --- + +impl TlsListElement for PSKKeyExchangeMode { + const SIZE_LEN: ListLength = ListLength::U8; +} + +impl TlsListElement for KeyShareEntry { + const SIZE_LEN: ListLength = ListLength::U16; +} + +impl TlsListElement for ProtocolVersion { + const SIZE_LEN: ListLength = ListLength::U8; +} + +#[derive(Clone, Debug)] +pub enum ClientExtension { + ECPointFormats(Vec), + NamedGroups(Vec), + SignatureAlgorithms(Vec), + ServerName(Vec), + SessionTicket(ClientSessionTicket), + Protocols(Vec), + SupportedVersions(Vec), + KeyShare(Vec), + PresharedKeyModes(Vec), + PresharedKey(PresharedKeyOffer), + Cookie(PayloadU16), + ExtendedMasterSecretRequest, + CertificateStatusRequest(CertificateStatusRequest), + SignedCertificateTimestampRequest, + TransportParameters(Vec), + TransportParametersDraft(Vec), + EarlyData, + Unknown(UnknownExtension), +} + +impl ClientExtension { + pub fn get_type(&self) -> ExtensionType { + match *self { + Self::ECPointFormats(_) => ExtensionType::ECPointFormats, + Self::NamedGroups(_) => ExtensionType::EllipticCurves, + Self::SignatureAlgorithms(_) => ExtensionType::SignatureAlgorithms, + Self::ServerName(_) => ExtensionType::ServerName, + Self::SessionTicket(_) => ExtensionType::SessionTicket, + Self::Protocols(_) => ExtensionType::ALProtocolNegotiation, + Self::SupportedVersions(_) => ExtensionType::SupportedVersions, + Self::KeyShare(_) => ExtensionType::KeyShare, + Self::PresharedKeyModes(_) => ExtensionType::PSKKeyExchangeModes, + Self::PresharedKey(_) => ExtensionType::PreSharedKey, + Self::Cookie(_) => ExtensionType::Cookie, + Self::ExtendedMasterSecretRequest => ExtensionType::ExtendedMasterSecret, + Self::CertificateStatusRequest(_) => ExtensionType::StatusRequest, + Self::SignedCertificateTimestampRequest => ExtensionType::SCT, + Self::TransportParameters(_) => ExtensionType::TransportParameters, + Self::TransportParametersDraft(_) => ExtensionType::TransportParametersDraft, + Self::EarlyData => ExtensionType::EarlyData, + Self::Unknown(ref r) => r.typ, + } + } +} + +impl Codec for ClientExtension { + fn encode(&self, bytes: &mut Vec) { + self.get_type().encode(bytes); + + let mut sub: Vec = Vec::new(); + match *self { + Self::ECPointFormats(ref r) => r.encode(&mut sub), + Self::NamedGroups(ref r) => r.encode(&mut sub), + Self::SignatureAlgorithms(ref r) => r.encode(&mut sub), + Self::ServerName(ref r) => r.encode(&mut sub), + Self::SessionTicket(ClientSessionTicket::Request) + | Self::ExtendedMasterSecretRequest + | Self::SignedCertificateTimestampRequest + | Self::EarlyData => {} + Self::SessionTicket(ClientSessionTicket::Offer(ref r)) => r.encode(&mut sub), + Self::Protocols(ref r) => r.encode(&mut sub), + Self::SupportedVersions(ref r) => r.encode(&mut sub), + Self::KeyShare(ref r) => r.encode(&mut sub), + Self::PresharedKeyModes(ref r) => r.encode(&mut sub), + Self::PresharedKey(ref r) => r.encode(&mut sub), + Self::Cookie(ref r) => r.encode(&mut sub), + Self::CertificateStatusRequest(ref r) => r.encode(&mut sub), + Self::TransportParameters(ref r) | Self::TransportParametersDraft(ref r) => { + sub.extend_from_slice(r); + } + Self::Unknown(ref r) => r.encode(&mut sub), + } + + (sub.len() as u16).encode(bytes); + bytes.append(&mut sub); + } + + fn read(r: &mut Reader) -> Result { + let typ = ExtensionType::read(r)?; + let len = u16::read(r)? as usize; + let mut sub = r.sub(len)?; + + let ext = match typ { + ExtensionType::ECPointFormats => Self::ECPointFormats(Vec::read(&mut sub)?), + ExtensionType::EllipticCurves => Self::NamedGroups(Vec::read(&mut sub)?), + ExtensionType::SignatureAlgorithms => Self::SignatureAlgorithms(Vec::read(&mut sub)?), + ExtensionType::ServerName => Self::ServerName(Vec::read(&mut sub)?), + ExtensionType::SessionTicket => { + if sub.any_left() { + let contents = Payload::read(&mut sub); + Self::SessionTicket(ClientSessionTicket::Offer(contents)) + } else { + Self::SessionTicket(ClientSessionTicket::Request) + } + } + ExtensionType::ALProtocolNegotiation => Self::Protocols(Vec::read(&mut sub)?), + ExtensionType::SupportedVersions => Self::SupportedVersions(Vec::read(&mut sub)?), + ExtensionType::KeyShare => Self::KeyShare(Vec::read(&mut sub)?), + ExtensionType::PSKKeyExchangeModes => Self::PresharedKeyModes(Vec::read(&mut sub)?), + ExtensionType::PreSharedKey => Self::PresharedKey(PresharedKeyOffer::read(&mut sub)?), + ExtensionType::Cookie => Self::Cookie(PayloadU16::read(&mut sub)?), + ExtensionType::ExtendedMasterSecret if !sub.any_left() => { + Self::ExtendedMasterSecretRequest + } + ExtensionType::StatusRequest => { + let csr = CertificateStatusRequest::read(&mut sub)?; + Self::CertificateStatusRequest(csr) + } + ExtensionType::SCT if !sub.any_left() => Self::SignedCertificateTimestampRequest, + ExtensionType::TransportParameters => Self::TransportParameters(sub.rest().to_vec()), + ExtensionType::TransportParametersDraft => { + Self::TransportParametersDraft(sub.rest().to_vec()) + } + ExtensionType::EarlyData if !sub.any_left() => Self::EarlyData, + _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), + }; + + sub.expect_empty("ClientExtension") + .map(|_| ext) + } +} + +fn trim_hostname_trailing_dot_for_sni(dns_name: DnsNameRef) -> DnsName { + let dns_name_str: &str = dns_name.as_ref(); + + // RFC6066: "The hostname is represented as a byte string using + // ASCII encoding without a trailing dot" + if dns_name_str.ends_with('.') { + let trimmed = &dns_name_str[0..dns_name_str.len() - 1]; + DnsNameRef::try_from(trimmed) + .unwrap() + .to_owned() + } else { + dns_name.to_owned() + } +} + +impl ClientExtension { + /// Make a basic SNI ServerNameRequest quoting `hostname`. + pub fn make_sni(dns_name: DnsNameRef) -> Self { + let name = ServerName { + typ: ServerNameType::HostName, + payload: ServerNamePayload::new_hostname(trim_hostname_trailing_dot_for_sni(dns_name)), + }; + + Self::ServerName(vec![name]) + } +} + +#[derive(Clone, Debug)] +pub enum ClientSessionTicket { + Request, + Offer(Payload), +} + +#[derive(Clone, Debug)] +pub enum ServerExtension { + ECPointFormats(Vec), + ServerNameAck, + SessionTicketAck, + RenegotiationInfo(PayloadU8), + Protocols(Vec), + KeyShare(KeyShareEntry), + PresharedKey(u16), + ExtendedMasterSecretAck, + CertificateStatusAck, + SignedCertificateTimestamp(Vec), + SupportedVersions(ProtocolVersion), + TransportParameters(Vec), + TransportParametersDraft(Vec), + EarlyData, + Unknown(UnknownExtension), +} + +impl ServerExtension { + pub fn get_type(&self) -> ExtensionType { + match *self { + Self::ECPointFormats(_) => ExtensionType::ECPointFormats, + Self::ServerNameAck => ExtensionType::ServerName, + Self::SessionTicketAck => ExtensionType::SessionTicket, + Self::RenegotiationInfo(_) => ExtensionType::RenegotiationInfo, + Self::Protocols(_) => ExtensionType::ALProtocolNegotiation, + Self::KeyShare(_) => ExtensionType::KeyShare, + Self::PresharedKey(_) => ExtensionType::PreSharedKey, + Self::ExtendedMasterSecretAck => ExtensionType::ExtendedMasterSecret, + Self::CertificateStatusAck => ExtensionType::StatusRequest, + Self::SignedCertificateTimestamp(_) => ExtensionType::SCT, + Self::SupportedVersions(_) => ExtensionType::SupportedVersions, + Self::TransportParameters(_) => ExtensionType::TransportParameters, + Self::TransportParametersDraft(_) => ExtensionType::TransportParametersDraft, + Self::EarlyData => ExtensionType::EarlyData, + Self::Unknown(ref r) => r.typ, + } + } +} + +impl Codec for ServerExtension { + fn encode(&self, bytes: &mut Vec) { + self.get_type().encode(bytes); + + let mut sub: Vec = Vec::new(); + match *self { + Self::ECPointFormats(ref r) => r.encode(&mut sub), + Self::ServerNameAck + | Self::SessionTicketAck + | Self::ExtendedMasterSecretAck + | Self::CertificateStatusAck + | Self::EarlyData => {} + Self::RenegotiationInfo(ref r) => r.encode(&mut sub), + Self::Protocols(ref r) => r.encode(&mut sub), + Self::KeyShare(ref r) => r.encode(&mut sub), + Self::PresharedKey(r) => r.encode(&mut sub), + Self::SignedCertificateTimestamp(ref r) => r.encode(&mut sub), + Self::SupportedVersions(ref r) => r.encode(&mut sub), + Self::TransportParameters(ref r) | Self::TransportParametersDraft(ref r) => { + sub.extend_from_slice(r); + } + Self::Unknown(ref r) => r.encode(&mut sub), + } + + (sub.len() as u16).encode(bytes); + bytes.append(&mut sub); + } + + fn read(r: &mut Reader) -> Result { + let typ = ExtensionType::read(r)?; + let len = u16::read(r)? as usize; + let mut sub = r.sub(len)?; + + let ext = match typ { + ExtensionType::ECPointFormats => Self::ECPointFormats(Vec::read(&mut sub)?), + ExtensionType::ServerName => Self::ServerNameAck, + ExtensionType::SessionTicket => Self::SessionTicketAck, + ExtensionType::StatusRequest => Self::CertificateStatusAck, + ExtensionType::RenegotiationInfo => Self::RenegotiationInfo(PayloadU8::read(&mut sub)?), + ExtensionType::ALProtocolNegotiation => Self::Protocols(Vec::read(&mut sub)?), + ExtensionType::KeyShare => Self::KeyShare(KeyShareEntry::read(&mut sub)?), + ExtensionType::PreSharedKey => Self::PresharedKey(u16::read(&mut sub)?), + ExtensionType::ExtendedMasterSecret => Self::ExtendedMasterSecretAck, + ExtensionType::SCT => Self::SignedCertificateTimestamp(Vec::read(&mut sub)?), + ExtensionType::SupportedVersions => { + Self::SupportedVersions(ProtocolVersion::read(&mut sub)?) + } + ExtensionType::TransportParameters => Self::TransportParameters(sub.rest().to_vec()), + ExtensionType::TransportParametersDraft => { + Self::TransportParametersDraft(sub.rest().to_vec()) + } + ExtensionType::EarlyData => Self::EarlyData, + _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), + }; + + sub.expect_empty("ServerExtension") + .map(|_| ext) + } +} + +impl ServerExtension { + pub fn make_alpn(proto: &[&[u8]]) -> Self { + Self::Protocols(Vec::from_slices(proto)) + } + + pub fn make_empty_renegotiation_info() -> Self { + let empty = Vec::new(); + Self::RenegotiationInfo(PayloadU8::new(empty)) + } + + pub fn make_sct(sctl: Vec) -> Self { + let scts = Vec::read_bytes(&sctl).expect("invalid SCT list"); + Self::SignedCertificateTimestamp(scts) + } +} + +#[derive(Debug)] +pub struct ClientHelloPayload { + pub client_version: ProtocolVersion, + pub random: Random, + pub session_id: SessionId, + pub cipher_suites: Vec, + pub compression_methods: Vec, + pub extensions: Vec, +} + +impl Codec for ClientHelloPayload { + fn encode(&self, bytes: &mut Vec) { + self.client_version.encode(bytes); + self.random.encode(bytes); + self.session_id.encode(bytes); + self.cipher_suites.encode(bytes); + self.compression_methods.encode(bytes); + + if !self.extensions.is_empty() { + self.extensions.encode(bytes); + } + } + + fn read(r: &mut Reader) -> Result { + let mut ret = Self { + client_version: ProtocolVersion::read(r)?, + random: Random::read(r)?, + session_id: SessionId::read(r)?, + cipher_suites: Vec::read(r)?, + compression_methods: Vec::read(r)?, + extensions: Vec::new(), + }; + + if r.any_left() { + ret.extensions = Vec::read(r)?; + } + + match (r.any_left(), ret.extensions.is_empty()) { + (true, _) => Err(InvalidMessage::TrailingData("ClientHelloPayload")), + (_, true) => Err(InvalidMessage::MissingData("ClientHelloPayload")), + _ => Ok(ret), + } + } +} + +impl TlsListElement for CipherSuite { + const SIZE_LEN: ListLength = ListLength::U16; +} + +impl TlsListElement for Compression { + const SIZE_LEN: ListLength = ListLength::U8; +} + +impl TlsListElement for ClientExtension { + const SIZE_LEN: ListLength = ListLength::U16; +} + +impl ClientHelloPayload { + /// Returns true if there is more than one extension of a given + /// type. + pub fn has_duplicate_extension(&self) -> bool { + let mut seen = collections::HashSet::new(); + + for ext in &self.extensions { + let typ = ext.get_type().get_u16(); + + if seen.contains(&typ) { + return true; + } + seen.insert(typ); + } + + false + } + + pub fn find_extension(&self, ext: ExtensionType) -> Option<&ClientExtension> { + self.extensions + .iter() + .find(|x| x.get_type() == ext) + } + + pub fn get_sni_extension(&self) -> Option<&[ServerName]> { + let ext = self.find_extension(ExtensionType::ServerName)?; + match *ext { + ClientExtension::ServerName(ref req) => Some(req), + _ => None, + } + } + + pub fn get_sigalgs_extension(&self) -> Option<&[SignatureScheme]> { + let ext = self.find_extension(ExtensionType::SignatureAlgorithms)?; + match *ext { + ClientExtension::SignatureAlgorithms(ref req) => Some(req), + _ => None, + } + } + + pub fn get_namedgroups_extension(&self) -> Option<&[NamedGroup]> { + let ext = self.find_extension(ExtensionType::EllipticCurves)?; + match *ext { + ClientExtension::NamedGroups(ref req) => Some(req), + _ => None, + } + } + + pub fn get_ecpoints_extension(&self) -> Option<&[ECPointFormat]> { + let ext = self.find_extension(ExtensionType::ECPointFormats)?; + match *ext { + ClientExtension::ECPointFormats(ref req) => Some(req), + _ => None, + } + } + + pub fn get_alpn_extension(&self) -> Option<&Vec> { + let ext = self.find_extension(ExtensionType::ALProtocolNegotiation)?; + match *ext { + ClientExtension::Protocols(ref req) => Some(req), + _ => None, + } + } + + pub fn get_quic_params_extension(&self) -> Option> { + let ext = self + .find_extension(ExtensionType::TransportParameters) + .or_else(|| self.find_extension(ExtensionType::TransportParametersDraft))?; + match *ext { + ClientExtension::TransportParameters(ref bytes) + | ClientExtension::TransportParametersDraft(ref bytes) => Some(bytes.to_vec()), + _ => None, + } + } + + pub fn get_ticket_extension(&self) -> Option<&ClientExtension> { + self.find_extension(ExtensionType::SessionTicket) + } + + pub fn get_versions_extension(&self) -> Option<&[ProtocolVersion]> { + let ext = self.find_extension(ExtensionType::SupportedVersions)?; + match *ext { + ClientExtension::SupportedVersions(ref vers) => Some(vers), + _ => None, + } + } + + pub fn get_keyshare_extension(&self) -> Option<&[KeyShareEntry]> { + let ext = self.find_extension(ExtensionType::KeyShare)?; + match *ext { + ClientExtension::KeyShare(ref shares) => Some(shares), + _ => None, + } + } + + pub fn has_keyshare_extension_with_duplicates(&self) -> bool { + if let Some(entries) = self.get_keyshare_extension() { + let mut seen = collections::HashSet::new(); + + for kse in entries { + let grp = kse.group.get_u16(); + + if !seen.insert(grp) { + return true; + } + } + } + + false + } + + pub fn get_psk(&self) -> Option<&PresharedKeyOffer> { + let ext = self.find_extension(ExtensionType::PreSharedKey)?; + match *ext { + ClientExtension::PresharedKey(ref psk) => Some(psk), + _ => None, + } + } + + pub fn check_psk_ext_is_last(&self) -> bool { + self.extensions + .last() + .map_or(false, |ext| ext.get_type() == ExtensionType::PreSharedKey) + } + + pub fn get_psk_modes(&self) -> Option<&[PSKKeyExchangeMode]> { + let ext = self.find_extension(ExtensionType::PSKKeyExchangeModes)?; + match *ext { + ClientExtension::PresharedKeyModes(ref psk_modes) => Some(psk_modes), + _ => None, + } + } + + pub fn psk_mode_offered(&self, mode: PSKKeyExchangeMode) -> bool { + self.get_psk_modes() + .map(|modes| modes.contains(&mode)) + .unwrap_or(false) + } + + pub fn set_psk_binder(&mut self, binder: impl Into>) { + let last_extension = self.extensions.last_mut(); + if let Some(ClientExtension::PresharedKey(ref mut offer)) = last_extension { + offer.binders[0] = PresharedKeyBinder::from(binder.into()); + } + } + + pub fn ems_support_offered(&self) -> bool { + self.find_extension(ExtensionType::ExtendedMasterSecret) + .is_some() + } + + pub fn early_data_extension_offered(&self) -> bool { + self.find_extension(ExtensionType::EarlyData) + .is_some() + } +} + +#[derive(Debug)] +pub enum HelloRetryExtension { + KeyShare(NamedGroup), + Cookie(PayloadU16), + SupportedVersions(ProtocolVersion), + Unknown(UnknownExtension), +} + +impl HelloRetryExtension { + pub fn get_type(&self) -> ExtensionType { + match *self { + Self::KeyShare(_) => ExtensionType::KeyShare, + Self::Cookie(_) => ExtensionType::Cookie, + Self::SupportedVersions(_) => ExtensionType::SupportedVersions, + Self::Unknown(ref r) => r.typ, + } + } +} + +impl Codec for HelloRetryExtension { + fn encode(&self, bytes: &mut Vec) { + self.get_type().encode(bytes); + + let mut sub: Vec = Vec::new(); + match *self { + Self::KeyShare(ref r) => r.encode(&mut sub), + Self::Cookie(ref r) => r.encode(&mut sub), + Self::SupportedVersions(ref r) => r.encode(&mut sub), + Self::Unknown(ref r) => r.encode(&mut sub), + } + + (sub.len() as u16).encode(bytes); + bytes.append(&mut sub); + } + + fn read(r: &mut Reader) -> Result { + let typ = ExtensionType::read(r)?; + let len = u16::read(r)? as usize; + let mut sub = r.sub(len)?; + + let ext = match typ { + ExtensionType::KeyShare => Self::KeyShare(NamedGroup::read(&mut sub)?), + ExtensionType::Cookie => Self::Cookie(PayloadU16::read(&mut sub)?), + ExtensionType::SupportedVersions => { + Self::SupportedVersions(ProtocolVersion::read(&mut sub)?) + } + _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), + }; + + sub.expect_empty("HelloRetryExtension") + .map(|_| ext) + } +} + +impl TlsListElement for HelloRetryExtension { + const SIZE_LEN: ListLength = ListLength::U16; +} + +#[derive(Debug)] +pub struct HelloRetryRequest { + pub legacy_version: ProtocolVersion, + pub session_id: SessionId, + pub cipher_suite: CipherSuite, + pub extensions: Vec, +} + +impl Codec for HelloRetryRequest { + fn encode(&self, bytes: &mut Vec) { + self.legacy_version.encode(bytes); + HELLO_RETRY_REQUEST_RANDOM.encode(bytes); + self.session_id.encode(bytes); + self.cipher_suite.encode(bytes); + Compression::Null.encode(bytes); + self.extensions.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let session_id = SessionId::read(r)?; + let cipher_suite = CipherSuite::read(r)?; + let compression = Compression::read(r)?; + + if compression != Compression::Null { + return Err(InvalidMessage::UnsupportedCompression); + } + + Ok(Self { + legacy_version: ProtocolVersion::Unknown(0), + session_id, + cipher_suite, + extensions: Vec::read(r)?, + }) + } +} + +impl HelloRetryRequest { + /// Returns true if there is more than one extension of a given + /// type. + pub fn has_duplicate_extension(&self) -> bool { + let mut seen = collections::HashSet::new(); + + for ext in &self.extensions { + let typ = ext.get_type().get_u16(); + + if seen.contains(&typ) { + return true; + } + seen.insert(typ); + } + + false + } + + pub fn has_unknown_extension(&self) -> bool { + self.extensions.iter().any(|ext| { + ext.get_type() != ExtensionType::KeyShare + && ext.get_type() != ExtensionType::SupportedVersions + && ext.get_type() != ExtensionType::Cookie + }) + } + + fn find_extension(&self, ext: ExtensionType) -> Option<&HelloRetryExtension> { + self.extensions + .iter() + .find(|x| x.get_type() == ext) + } + + pub fn get_requested_key_share_group(&self) -> Option { + let ext = self.find_extension(ExtensionType::KeyShare)?; + match *ext { + HelloRetryExtension::KeyShare(grp) => Some(grp), + _ => None, + } + } + + pub fn get_cookie(&self) -> Option<&PayloadU16> { + let ext = self.find_extension(ExtensionType::Cookie)?; + match *ext { + HelloRetryExtension::Cookie(ref ck) => Some(ck), + _ => None, + } + } + + pub fn get_supported_versions(&self) -> Option { + let ext = self.find_extension(ExtensionType::SupportedVersions)?; + match *ext { + HelloRetryExtension::SupportedVersions(ver) => Some(ver), + _ => None, + } + } +} + +#[derive(Debug)] +pub struct ServerHelloPayload { + pub legacy_version: ProtocolVersion, + pub random: Random, + pub session_id: SessionId, + pub cipher_suite: CipherSuite, + pub compression_method: Compression, + pub extensions: Vec, +} + +impl Codec for ServerHelloPayload { + fn encode(&self, bytes: &mut Vec) { + self.legacy_version.encode(bytes); + self.random.encode(bytes); + + self.session_id.encode(bytes); + self.cipher_suite.encode(bytes); + self.compression_method.encode(bytes); + + if !self.extensions.is_empty() { + self.extensions.encode(bytes); + } + } + + // minus version and random, which have already been read. + fn read(r: &mut Reader) -> Result { + let session_id = SessionId::read(r)?; + let suite = CipherSuite::read(r)?; + let compression = Compression::read(r)?; + + // RFC5246: + // "The presence of extensions can be detected by determining whether + // there are bytes following the compression_method field at the end of + // the ServerHello." + let extensions = if r.any_left() { Vec::read(r)? } else { vec![] }; + + let ret = Self { + legacy_version: ProtocolVersion::Unknown(0), + random: ZERO_RANDOM, + session_id, + cipher_suite: suite, + compression_method: compression, + extensions, + }; + + r.expect_empty("ServerHelloPayload") + .map(|_| ret) + } +} + +impl HasServerExtensions for ServerHelloPayload { + fn get_extensions(&self) -> &[ServerExtension] { + &self.extensions + } +} + +impl ServerHelloPayload { + pub fn get_key_share(&self) -> Option<&KeyShareEntry> { + let ext = self.find_extension(ExtensionType::KeyShare)?; + match *ext { + ServerExtension::KeyShare(ref share) => Some(share), + _ => None, + } + } + + pub fn get_psk_index(&self) -> Option { + let ext = self.find_extension(ExtensionType::PreSharedKey)?; + match *ext { + ServerExtension::PresharedKey(ref index) => Some(*index), + _ => None, + } + } + + pub fn get_ecpoints_extension(&self) -> Option<&[ECPointFormat]> { + let ext = self.find_extension(ExtensionType::ECPointFormats)?; + match *ext { + ServerExtension::ECPointFormats(ref fmts) => Some(fmts), + _ => None, + } + } + + pub fn ems_support_acked(&self) -> bool { + self.find_extension(ExtensionType::ExtendedMasterSecret) + .is_some() + } + + pub fn get_sct_list(&self) -> Option<&[Sct]> { + let ext = self.find_extension(ExtensionType::SCT)?; + match *ext { + ServerExtension::SignedCertificateTimestamp(ref sctl) => Some(sctl), + _ => None, + } + } + + pub fn get_supported_versions(&self) -> Option { + let ext = self.find_extension(ExtensionType::SupportedVersions)?; + match *ext { + ServerExtension::SupportedVersions(vers) => Some(vers), + _ => None, + } + } +} + +pub type CertificatePayload = Vec; + +impl TlsListElement for key::Certificate { + const SIZE_LEN: ListLength = ListLength::U24 { max: 0x1_0000 }; +} + +// TLS1.3 changes the Certificate payload encoding. +// That's annoying. It means the parsing is not +// context-free any more. + +#[derive(Debug)] +pub enum CertificateExtension { + CertificateStatus(CertificateStatus), + SignedCertificateTimestamp(Vec), + Unknown(UnknownExtension), +} + +impl CertificateExtension { + pub fn get_type(&self) -> ExtensionType { + match *self { + Self::CertificateStatus(_) => ExtensionType::StatusRequest, + Self::SignedCertificateTimestamp(_) => ExtensionType::SCT, + Self::Unknown(ref r) => r.typ, + } + } + + pub fn make_sct(sct_list: Vec) -> Self { + let sctl = Vec::read_bytes(&sct_list).expect("invalid SCT list"); + Self::SignedCertificateTimestamp(sctl) + } + + pub fn get_cert_status(&self) -> Option<&Vec> { + match *self { + Self::CertificateStatus(ref cs) => Some(&cs.ocsp_response.0), + _ => None, + } + } + + pub fn get_sct_list(&self) -> Option<&[Sct]> { + match *self { + Self::SignedCertificateTimestamp(ref sctl) => Some(sctl), + _ => None, + } + } +} + +impl Codec for CertificateExtension { + fn encode(&self, bytes: &mut Vec) { + self.get_type().encode(bytes); + + let mut sub: Vec = Vec::new(); + match *self { + Self::CertificateStatus(ref r) => r.encode(&mut sub), + Self::SignedCertificateTimestamp(ref r) => r.encode(&mut sub), + Self::Unknown(ref r) => r.encode(&mut sub), + } + + (sub.len() as u16).encode(bytes); + bytes.append(&mut sub); + } + + fn read(r: &mut Reader) -> Result { + let typ = ExtensionType::read(r)?; + let len = u16::read(r)? as usize; + let mut sub = r.sub(len)?; + + let ext = match typ { + ExtensionType::StatusRequest => { + let st = CertificateStatus::read(&mut sub)?; + Self::CertificateStatus(st) + } + ExtensionType::SCT => Self::SignedCertificateTimestamp(Vec::read(&mut sub)?), + _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), + }; + + sub.expect_empty("CertificateExtension") + .map(|_| ext) + } +} + +impl TlsListElement for CertificateExtension { + const SIZE_LEN: ListLength = ListLength::U16; +} + +#[derive(Debug)] +pub struct CertificateEntry { + pub cert: key::Certificate, + pub exts: Vec, +} + +impl Codec for CertificateEntry { + fn encode(&self, bytes: &mut Vec) { + self.cert.encode(bytes); + self.exts.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + Ok(Self { + cert: key::Certificate::read(r)?, + exts: Vec::read(r)?, + }) + } +} + +impl CertificateEntry { + pub fn new(cert: key::Certificate) -> Self { + Self { + cert, + exts: Vec::new(), + } + } + + pub fn has_duplicate_extension(&self) -> bool { + let mut seen = collections::HashSet::new(); + + for ext in &self.exts { + let typ = ext.get_type().get_u16(); + + if seen.contains(&typ) { + return true; + } + seen.insert(typ); + } + + false + } + + pub fn has_unknown_extension(&self) -> bool { + self.exts.iter().any(|ext| { + ext.get_type() != ExtensionType::StatusRequest && ext.get_type() != ExtensionType::SCT + }) + } + + pub fn get_ocsp_response(&self) -> Option<&Vec> { + self.exts + .iter() + .find(|ext| ext.get_type() == ExtensionType::StatusRequest) + .and_then(CertificateExtension::get_cert_status) + } + + pub fn get_scts(&self) -> Option<&[Sct]> { + self.exts + .iter() + .find(|ext| ext.get_type() == ExtensionType::SCT) + .and_then(CertificateExtension::get_sct_list) + } +} + +impl TlsListElement for CertificateEntry { + const SIZE_LEN: ListLength = ListLength::U24 { max: 0x1_0000 }; +} + +#[derive(Debug)] +pub struct CertificatePayloadTLS13 { + pub context: PayloadU8, + pub entries: Vec, +} + +impl Codec for CertificatePayloadTLS13 { + fn encode(&self, bytes: &mut Vec) { + self.context.encode(bytes); + self.entries.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + Ok(Self { + context: PayloadU8::read(r)?, + entries: Vec::read(r)?, + }) + } +} + +impl CertificatePayloadTLS13 { + pub fn new(entries: Vec) -> Self { + Self { + context: PayloadU8::empty(), + entries, + } + } + + pub fn any_entry_has_duplicate_extension(&self) -> bool { + for entry in &self.entries { + if entry.has_duplicate_extension() { + return true; + } + } + + false + } + + pub fn any_entry_has_unknown_extension(&self) -> bool { + for entry in &self.entries { + if entry.has_unknown_extension() { + return true; + } + } + + false + } + + pub fn any_entry_has_extension(&self) -> bool { + for entry in &self.entries { + if !entry.exts.is_empty() { + return true; + } + } + + false + } + + pub fn get_end_entity_ocsp(&self) -> Vec { + self.entries + .first() + .and_then(CertificateEntry::get_ocsp_response) + .cloned() + .unwrap_or_default() + } + + pub fn get_end_entity_scts(&self) -> Option<&[Sct]> { + self.entries + .first() + .and_then(CertificateEntry::get_scts) + } + + pub fn convert(&self) -> CertificatePayload { + let mut ret = Vec::new(); + for entry in &self.entries { + ret.push(entry.cert.clone()); + } + ret + } +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum KeyExchangeAlgorithm { + BulkOnly, + DH, + DHE, + RSA, + ECDH, + ECDHE, +} + +// We don't support arbitrary curves. It's a terrible +// idea and unnecessary attack surface. Please, +// get a grip. +#[derive(Debug)] +pub struct ECParameters { + pub curve_type: ECCurveType, + pub named_group: NamedGroup, +} + +impl Codec for ECParameters { + fn encode(&self, bytes: &mut Vec) { + self.curve_type.encode(bytes); + self.named_group.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let ct = ECCurveType::read(r)?; + if ct != ECCurveType::NamedCurve { + return Err(InvalidMessage::UnsupportedCurveType); + } + + let grp = NamedGroup::read(r)?; + + Ok(Self { + curve_type: ct, + named_group: grp, + }) + } +} + +#[derive(Debug)] +pub struct ClientECDHParams { + pub public: PayloadU8, +} + +impl Codec for ClientECDHParams { + fn encode(&self, bytes: &mut Vec) { + self.public.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let pb = PayloadU8::read(r)?; + Ok(Self { public: pb }) + } +} + +#[derive(Debug)] +pub struct ServerECDHParams { + pub curve_params: ECParameters, + pub public: PayloadU8, +} + +impl ServerECDHParams { + pub fn new(named_group: NamedGroup, pubkey: &[u8]) -> Self { + Self { + curve_params: ECParameters { + curve_type: ECCurveType::NamedCurve, + named_group, + }, + public: PayloadU8::new(pubkey.to_vec()), + } + } +} + +impl Codec for ServerECDHParams { + fn encode(&self, bytes: &mut Vec) { + self.curve_params.encode(bytes); + self.public.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let cp = ECParameters::read(r)?; + let pb = PayloadU8::read(r)?; + + Ok(Self { + curve_params: cp, + public: pb, + }) + } +} + +#[derive(Debug)] +pub struct ECDHEServerKeyExchange { + pub params: ServerECDHParams, + pub dss: DigitallySignedStruct, +} + +impl Codec for ECDHEServerKeyExchange { + fn encode(&self, bytes: &mut Vec) { + self.params.encode(bytes); + self.dss.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let params = ServerECDHParams::read(r)?; + let dss = DigitallySignedStruct::read(r)?; + + Ok(Self { params, dss }) + } +} + +#[derive(Debug)] +pub enum ServerKeyExchangePayload { + ECDHE(ECDHEServerKeyExchange), + Unknown(Payload), +} + +impl Codec for ServerKeyExchangePayload { + fn encode(&self, bytes: &mut Vec) { + match *self { + Self::ECDHE(ref x) => x.encode(bytes), + Self::Unknown(ref x) => x.encode(bytes), + } + } + + fn read(r: &mut Reader) -> Result { + // read as Unknown, fully parse when we know the + // KeyExchangeAlgorithm + Ok(Self::Unknown(Payload::read(r))) + } +} + +impl ServerKeyExchangePayload { + pub fn unwrap_given_kxa(&self, kxa: KeyExchangeAlgorithm) -> Option { + if let Self::Unknown(ref unk) = *self { + let mut rd = Reader::init(&unk.0); + + let result = match kxa { + KeyExchangeAlgorithm::ECDHE => ECDHEServerKeyExchange::read(&mut rd), + _ => return None, + }; + + if !rd.any_left() { + return result.ok(); + }; + } + + None + } +} + +// -- EncryptedExtensions (TLS1.3 only) -- + +impl TlsListElement for ServerExtension { + const SIZE_LEN: ListLength = ListLength::U16; +} + +pub trait HasServerExtensions { + fn get_extensions(&self) -> &[ServerExtension]; + + /// Returns true if there is more than one extension of a given + /// type. + fn has_duplicate_extension(&self) -> bool { + let mut seen = collections::HashSet::new(); + + for ext in self.get_extensions() { + let typ = ext.get_type().get_u16(); + + if seen.contains(&typ) { + return true; + } + seen.insert(typ); + } + + false + } + + fn find_extension(&self, ext: ExtensionType) -> Option<&ServerExtension> { + self.get_extensions() + .iter() + .find(|x| x.get_type() == ext) + } + + fn get_alpn_protocol(&self) -> Option<&[u8]> { + let ext = self.find_extension(ExtensionType::ALProtocolNegotiation)?; + match *ext { + ServerExtension::Protocols(ref protos) => protos.as_single_slice(), + _ => None, + } + } + + fn get_quic_params_extension(&self) -> Option> { + let ext = self + .find_extension(ExtensionType::TransportParameters) + .or_else(|| self.find_extension(ExtensionType::TransportParametersDraft))?; + match *ext { + ServerExtension::TransportParameters(ref bytes) + | ServerExtension::TransportParametersDraft(ref bytes) => Some(bytes.to_vec()), + _ => None, + } + } + + fn early_data_extension_offered(&self) -> bool { + self.find_extension(ExtensionType::EarlyData) + .is_some() + } +} + +impl HasServerExtensions for Vec { + fn get_extensions(&self) -> &[ServerExtension] { + self + } +} + +impl TlsListElement for ClientCertificateType { + const SIZE_LEN: ListLength = ListLength::U8; +} + +wrapped_payload!( + /// A `DistinguishedName` is a `Vec` wrapped in internal types. + /// + /// It contains the DER or BER encoded [`Subject` field from RFC 5280](https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6) + /// for a single certificate. The Subject field is [encoded as an RFC 5280 `Name`](https://datatracker.ietf.org/doc/html/rfc5280#page-116). + /// It can be decoded using [x509-parser's FromDer trait](https://docs.rs/x509-parser/latest/x509_parser/prelude/trait.FromDer.html). + /// + /// ```ignore + /// for name in distinguished_names { + /// use x509_parser::prelude::FromDer; + /// println!("{}", x509_parser::x509::X509Name::from_der(&name.0)?.1); + /// } + /// ``` + DistinguishedName, + PayloadU16, +); + +impl TlsListElement for DistinguishedName { + const SIZE_LEN: ListLength = ListLength::U16; +} + +#[derive(Debug)] +pub struct CertificateRequestPayload { + pub certtypes: Vec, + pub sigschemes: Vec, + pub canames: Vec, +} + +impl Codec for CertificateRequestPayload { + fn encode(&self, bytes: &mut Vec) { + self.certtypes.encode(bytes); + self.sigschemes.encode(bytes); + self.canames.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let certtypes = Vec::read(r)?; + let sigschemes = Vec::read(r)?; + let canames = Vec::read(r)?; + + if sigschemes.is_empty() { + warn!("meaningless CertificateRequest message"); + Err(InvalidMessage::NoSignatureSchemes) + } else { + Ok(Self { + certtypes, + sigschemes, + canames, + }) + } + } +} + +#[derive(Debug)] +pub enum CertReqExtension { + SignatureAlgorithms(Vec), + AuthorityNames(Vec), + Unknown(UnknownExtension), +} + +impl CertReqExtension { + pub fn get_type(&self) -> ExtensionType { + match *self { + Self::SignatureAlgorithms(_) => ExtensionType::SignatureAlgorithms, + Self::AuthorityNames(_) => ExtensionType::CertificateAuthorities, + Self::Unknown(ref r) => r.typ, + } + } +} + +impl Codec for CertReqExtension { + fn encode(&self, bytes: &mut Vec) { + self.get_type().encode(bytes); + + let mut sub: Vec = Vec::new(); + match *self { + Self::SignatureAlgorithms(ref r) => r.encode(&mut sub), + Self::AuthorityNames(ref r) => r.encode(&mut sub), + Self::Unknown(ref r) => r.encode(&mut sub), + } + + (sub.len() as u16).encode(bytes); + bytes.append(&mut sub); + } + + fn read(r: &mut Reader) -> Result { + let typ = ExtensionType::read(r)?; + let len = u16::read(r)? as usize; + let mut sub = r.sub(len)?; + + let ext = match typ { + ExtensionType::SignatureAlgorithms => { + let schemes = Vec::read(&mut sub)?; + if schemes.is_empty() { + return Err(InvalidMessage::NoSignatureSchemes); + } + Self::SignatureAlgorithms(schemes) + } + ExtensionType::CertificateAuthorities => { + let cas = Vec::read(&mut sub)?; + Self::AuthorityNames(cas) + } + _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), + }; + + sub.expect_empty("CertReqExtension") + .map(|_| ext) + } +} + +impl TlsListElement for CertReqExtension { + const SIZE_LEN: ListLength = ListLength::U16; +} + +#[derive(Debug)] +pub struct CertificateRequestPayloadTLS13 { + pub context: PayloadU8, + pub extensions: Vec, +} + +impl Codec for CertificateRequestPayloadTLS13 { + fn encode(&self, bytes: &mut Vec) { + self.context.encode(bytes); + self.extensions.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let context = PayloadU8::read(r)?; + let extensions = Vec::read(r)?; + + Ok(Self { + context, + extensions, + }) + } +} + +impl CertificateRequestPayloadTLS13 { + pub fn find_extension(&self, ext: ExtensionType) -> Option<&CertReqExtension> { + self.extensions + .iter() + .find(|x| x.get_type() == ext) + } + + pub fn get_sigalgs_extension(&self) -> Option<&[SignatureScheme]> { + let ext = self.find_extension(ExtensionType::SignatureAlgorithms)?; + match *ext { + CertReqExtension::SignatureAlgorithms(ref sa) => Some(sa), + _ => None, + } + } + + pub fn get_authorities_extension(&self) -> Option<&[DistinguishedName]> { + let ext = self.find_extension(ExtensionType::CertificateAuthorities)?; + match *ext { + CertReqExtension::AuthorityNames(ref an) => Some(an), + _ => None, + } + } +} + +// -- NewSessionTicket -- +#[derive(Debug)] +pub struct NewSessionTicketPayload { + pub lifetime_hint: u32, + pub ticket: PayloadU16, +} + +impl NewSessionTicketPayload { + pub fn new(lifetime_hint: u32, ticket: Vec) -> Self { + Self { + lifetime_hint, + ticket: PayloadU16::new(ticket), + } + } +} + +impl Codec for NewSessionTicketPayload { + fn encode(&self, bytes: &mut Vec) { + self.lifetime_hint.encode(bytes); + self.ticket.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let lifetime = u32::read(r)?; + let ticket = PayloadU16::read(r)?; + + Ok(Self { + lifetime_hint: lifetime, + ticket, + }) + } +} + +// -- NewSessionTicket electric boogaloo -- +#[derive(Debug)] +pub enum NewSessionTicketExtension { + EarlyData(u32), + Unknown(UnknownExtension), +} + +impl NewSessionTicketExtension { + pub fn get_type(&self) -> ExtensionType { + match *self { + Self::EarlyData(_) => ExtensionType::EarlyData, + Self::Unknown(ref r) => r.typ, + } + } +} + +impl Codec for NewSessionTicketExtension { + fn encode(&self, bytes: &mut Vec) { + self.get_type().encode(bytes); + + let mut sub: Vec = Vec::new(); + match *self { + Self::EarlyData(r) => r.encode(&mut sub), + Self::Unknown(ref r) => r.encode(&mut sub), + } + + (sub.len() as u16).encode(bytes); + bytes.append(&mut sub); + } + + fn read(r: &mut Reader) -> Result { + let typ = ExtensionType::read(r)?; + let len = u16::read(r)? as usize; + let mut sub = r.sub(len)?; + + let ext = match typ { + ExtensionType::EarlyData => Self::EarlyData(u32::read(&mut sub)?), + _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), + }; + + sub.expect_empty("NewSessionTicketExtension") + .map(|_| ext) + } +} + +impl TlsListElement for NewSessionTicketExtension { + const SIZE_LEN: ListLength = ListLength::U16; +} + +#[derive(Debug)] +pub struct NewSessionTicketPayloadTLS13 { + pub lifetime: u32, + pub age_add: u32, + pub nonce: PayloadU8, + pub ticket: PayloadU16, + pub exts: Vec, +} + +impl NewSessionTicketPayloadTLS13 { + pub fn new(lifetime: u32, age_add: u32, nonce: Vec, ticket: Vec) -> Self { + Self { + lifetime, + age_add, + nonce: PayloadU8::new(nonce), + ticket: PayloadU16::new(ticket), + exts: vec![], + } + } + + pub fn has_duplicate_extension(&self) -> bool { + let mut seen = collections::HashSet::new(); + + for ext in &self.exts { + let typ = ext.get_type().get_u16(); + + if seen.contains(&typ) { + return true; + } + seen.insert(typ); + } + + false + } + + pub fn find_extension(&self, ext: ExtensionType) -> Option<&NewSessionTicketExtension> { + self.exts + .iter() + .find(|x| x.get_type() == ext) + } + + pub fn get_max_early_data_size(&self) -> Option { + let ext = self.find_extension(ExtensionType::EarlyData)?; + match *ext { + NewSessionTicketExtension::EarlyData(ref sz) => Some(*sz), + _ => None, + } + } +} + +impl Codec for NewSessionTicketPayloadTLS13 { + fn encode(&self, bytes: &mut Vec) { + self.lifetime.encode(bytes); + self.age_add.encode(bytes); + self.nonce.encode(bytes); + self.ticket.encode(bytes); + self.exts.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let lifetime = u32::read(r)?; + let age_add = u32::read(r)?; + let nonce = PayloadU8::read(r)?; + let ticket = PayloadU16::read(r)?; + let exts = Vec::read(r)?; + + Ok(Self { + lifetime, + age_add, + nonce, + ticket, + exts, + }) + } +} + +// -- RFC6066 certificate status types + +/// Only supports OCSP +#[derive(Debug)] +pub struct CertificateStatus { + pub ocsp_response: PayloadU24, +} + +impl Codec for CertificateStatus { + fn encode(&self, bytes: &mut Vec) { + CertificateStatusType::OCSP.encode(bytes); + self.ocsp_response.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let typ = CertificateStatusType::read(r)?; + + match typ { + CertificateStatusType::OCSP => Ok(Self { + ocsp_response: PayloadU24::read(r)?, + }), + _ => Err(InvalidMessage::InvalidCertificateStatusType), + } + } +} + +impl CertificateStatus { + pub fn new(ocsp: Vec) -> Self { + Self { + ocsp_response: PayloadU24::new(ocsp), + } + } + + pub fn into_inner(self) -> Vec { + self.ocsp_response.0 + } +} + +#[derive(Debug)] +pub enum HandshakePayload { + HelloRequest, + ClientHello(ClientHelloPayload), + ServerHello(ServerHelloPayload), + HelloRetryRequest(HelloRetryRequest), + Certificate(CertificatePayload), + CertificateTLS13(CertificatePayloadTLS13), + ServerKeyExchange(ServerKeyExchangePayload), + CertificateRequest(CertificateRequestPayload), + CertificateRequestTLS13(CertificateRequestPayloadTLS13), + CertificateVerify(DigitallySignedStruct), + ServerHelloDone, + EndOfEarlyData, + ClientKeyExchange(Payload), + NewSessionTicket(NewSessionTicketPayload), + NewSessionTicketTLS13(NewSessionTicketPayloadTLS13), + EncryptedExtensions(Vec), + KeyUpdate(KeyUpdateRequest), + Finished(Payload), + CertificateStatus(CertificateStatus), + MessageHash(Payload), + Unknown(Payload), +} + +impl HandshakePayload { + fn encode(&self, bytes: &mut Vec) { + use self::HandshakePayload::*; + match *self { + HelloRequest | ServerHelloDone | EndOfEarlyData => {} + ClientHello(ref x) => x.encode(bytes), + ServerHello(ref x) => x.encode(bytes), + HelloRetryRequest(ref x) => x.encode(bytes), + Certificate(ref x) => x.encode(bytes), + CertificateTLS13(ref x) => x.encode(bytes), + ServerKeyExchange(ref x) => x.encode(bytes), + ClientKeyExchange(ref x) => x.encode(bytes), + CertificateRequest(ref x) => x.encode(bytes), + CertificateRequestTLS13(ref x) => x.encode(bytes), + CertificateVerify(ref x) => x.encode(bytes), + NewSessionTicket(ref x) => x.encode(bytes), + NewSessionTicketTLS13(ref x) => x.encode(bytes), + EncryptedExtensions(ref x) => x.encode(bytes), + KeyUpdate(ref x) => x.encode(bytes), + Finished(ref x) => x.encode(bytes), + CertificateStatus(ref x) => x.encode(bytes), + MessageHash(ref x) => x.encode(bytes), + Unknown(ref x) => x.encode(bytes), + } + } +} + +#[derive(Debug)] +pub struct HandshakeMessagePayload { + pub typ: HandshakeType, + pub payload: HandshakePayload, +} + +impl Codec for HandshakeMessagePayload { + fn encode(&self, bytes: &mut Vec) { + // encode payload to learn length + let mut sub: Vec = Vec::new(); + self.payload.encode(&mut sub); + + // output type, length, and encoded payload + match self.typ { + HandshakeType::HelloRetryRequest => HandshakeType::ServerHello, + _ => self.typ, + } + .encode(bytes); + codec::u24(sub.len() as u32).encode(bytes); + bytes.append(&mut sub); + } + + fn read(r: &mut Reader) -> Result { + Self::read_version(r, ProtocolVersion::TLSv1_2) + } +} + +impl HandshakeMessagePayload { + pub fn read_version(r: &mut Reader, vers: ProtocolVersion) -> Result { + let mut typ = HandshakeType::read(r)?; + let len = codec::u24::read(r)?.0 as usize; + let mut sub = r.sub(len)?; + + let payload = match typ { + HandshakeType::HelloRequest if sub.left() == 0 => HandshakePayload::HelloRequest, + HandshakeType::ClientHello => { + HandshakePayload::ClientHello(ClientHelloPayload::read(&mut sub)?) + } + HandshakeType::ServerHello => { + let version = ProtocolVersion::read(&mut sub)?; + let random = Random::read(&mut sub)?; + + if random == HELLO_RETRY_REQUEST_RANDOM { + let mut hrr = HelloRetryRequest::read(&mut sub)?; + hrr.legacy_version = version; + typ = HandshakeType::HelloRetryRequest; + HandshakePayload::HelloRetryRequest(hrr) + } else { + let mut shp = ServerHelloPayload::read(&mut sub)?; + shp.legacy_version = version; + shp.random = random; + HandshakePayload::ServerHello(shp) + } + } + HandshakeType::Certificate if vers == ProtocolVersion::TLSv1_3 => { + let p = CertificatePayloadTLS13::read(&mut sub)?; + HandshakePayload::CertificateTLS13(p) + } + HandshakeType::Certificate => { + HandshakePayload::Certificate(CertificatePayload::read(&mut sub)?) + } + HandshakeType::ServerKeyExchange => { + let p = ServerKeyExchangePayload::read(&mut sub)?; + HandshakePayload::ServerKeyExchange(p) + } + HandshakeType::ServerHelloDone => { + sub.expect_empty("ServerHelloDone")?; + HandshakePayload::ServerHelloDone + } + HandshakeType::ClientKeyExchange => { + HandshakePayload::ClientKeyExchange(Payload::read(&mut sub)) + } + HandshakeType::CertificateRequest if vers == ProtocolVersion::TLSv1_3 => { + let p = CertificateRequestPayloadTLS13::read(&mut sub)?; + HandshakePayload::CertificateRequestTLS13(p) + } + HandshakeType::CertificateRequest => { + let p = CertificateRequestPayload::read(&mut sub)?; + HandshakePayload::CertificateRequest(p) + } + HandshakeType::CertificateVerify => { + HandshakePayload::CertificateVerify(DigitallySignedStruct::read(&mut sub)?) + } + HandshakeType::NewSessionTicket if vers == ProtocolVersion::TLSv1_3 => { + let p = NewSessionTicketPayloadTLS13::read(&mut sub)?; + HandshakePayload::NewSessionTicketTLS13(p) + } + HandshakeType::NewSessionTicket => { + let p = NewSessionTicketPayload::read(&mut sub)?; + HandshakePayload::NewSessionTicket(p) + } + HandshakeType::EncryptedExtensions => { + HandshakePayload::EncryptedExtensions(Vec::read(&mut sub)?) + } + HandshakeType::KeyUpdate => { + HandshakePayload::KeyUpdate(KeyUpdateRequest::read(&mut sub)?) + } + HandshakeType::EndOfEarlyData => { + sub.expect_empty("EndOfEarlyData")?; + HandshakePayload::EndOfEarlyData + } + HandshakeType::Finished => HandshakePayload::Finished(Payload::read(&mut sub)), + HandshakeType::CertificateStatus => { + HandshakePayload::CertificateStatus(CertificateStatus::read(&mut sub)?) + } + HandshakeType::MessageHash => { + // does not appear on the wire + return Err(InvalidMessage::UnexpectedMessage("MessageHash")); + } + HandshakeType::HelloRetryRequest => { + // not legal on wire + return Err(InvalidMessage::UnexpectedMessage("HelloRetryRequest")); + } + _ => HandshakePayload::Unknown(Payload::read(&mut sub)), + }; + + sub.expect_empty("HandshakeMessagePayload") + .map(|_| Self { typ, payload }) + } + + pub fn build_key_update_notify() -> Self { + Self { + typ: HandshakeType::KeyUpdate, + payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateNotRequested), + } + } + + pub fn get_encoding_for_binder_signing(&self) -> Vec { + let mut ret = self.get_encoding(); + + let binder_len = match self.payload { + HandshakePayload::ClientHello(ref ch) => match ch.extensions.last() { + Some(ClientExtension::PresharedKey(ref offer)) => { + let mut binders_encoding = Vec::new(); + offer + .binders + .encode(&mut binders_encoding); + binders_encoding.len() + } + _ => 0, + }, + _ => 0, + }; + + let ret_len = ret.len() - binder_len; + ret.truncate(ret_len); + ret + } + + pub fn build_handshake_hash(hash: &[u8]) -> Self { + Self { + typ: HandshakeType::MessageHash, + payload: HandshakePayload::MessageHash(Payload::new(hash.to_vec())), + } + } +} diff --git a/vendor/rustls-0.21.8/src/msgs/handshake_test.rs b/vendor/rustls-0.21.8/src/msgs/handshake_test.rs new file mode 100644 index 0000000000000..ee960557233f9 --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/handshake_test.rs @@ -0,0 +1,1210 @@ +use crate::dns_name::DnsNameRef; +use crate::enums::{CipherSuite, HandshakeType, ProtocolVersion, SignatureScheme}; +use crate::key::Certificate; +use crate::msgs::base::{Payload, PayloadU16, PayloadU24, PayloadU8}; +use crate::msgs::codec::{put_u16, Codec, Reader}; +use crate::msgs::enums::{ + ClientCertificateType, Compression, ECCurveType, ECPointFormat, ExtensionType, + KeyUpdateRequest, NamedGroup, PSKKeyExchangeMode, ServerNameType, +}; +use crate::msgs::handshake::{ + CertReqExtension, CertificateEntry, CertificateExtension, CertificatePayloadTLS13, + CertificateRequestPayload, CertificateRequestPayloadTLS13, CertificateStatus, + CertificateStatusRequest, ClientExtension, ClientHelloPayload, ClientSessionTicket, + ConvertProtocolNameList, ConvertServerNameList, DistinguishedName, ECDHEServerKeyExchange, + ECParameters, HandshakeMessagePayload, HandshakePayload, HasServerExtensions, + HelloRetryExtension, HelloRetryRequest, KeyShareEntry, NewSessionTicketExtension, + NewSessionTicketPayload, NewSessionTicketPayloadTLS13, PresharedKeyBinder, + PresharedKeyIdentity, PresharedKeyOffer, ProtocolName, Random, Sct, ServerECDHParams, + ServerExtension, ServerHelloPayload, ServerKeyExchangePayload, SessionId, UnknownExtension, +}; +use crate::verify::DigitallySignedStruct; + +#[test] +fn rejects_short_random() { + let bytes = [0x01; 31]; + let mut rd = Reader::init(&bytes); + assert!(Random::read(&mut rd).is_err()); +} + +#[test] +fn reads_random() { + let bytes = [0x01; 32]; + let mut rd = Reader::init(&bytes); + let rnd = Random::read(&mut rd).unwrap(); + println!("{:?}", rnd); + + assert!(!rd.any_left()); +} + +#[test] +fn debug_random() { + assert_eq!( + "0101010101010101010101010101010101010101010101010101010101010101", + format!("{:?}", Random::from([1; 32])) + ); +} + +#[test] +fn rejects_truncated_sessionid() { + let bytes = [32; 32]; + let mut rd = Reader::init(&bytes); + assert!(SessionId::read(&mut rd).is_err()); +} + +#[test] +fn rejects_sessionid_with_bad_length() { + let bytes = [33; 33]; + let mut rd = Reader::init(&bytes); + assert!(SessionId::read(&mut rd).is_err()); +} + +#[test] +fn sessionid_with_different_lengths_are_unequal() { + let a = SessionId::read(&mut Reader::init(&[1u8, 1])).unwrap(); + let b = SessionId::read(&mut Reader::init(&[2u8, 1, 2])).unwrap(); + assert_ne!(a, b); +} + +#[test] +fn accepts_short_sessionid() { + let bytes = [1; 2]; + let mut rd = Reader::init(&bytes); + let sess = SessionId::read(&mut rd).unwrap(); + println!("{:?}", sess); + + assert!(!sess.is_empty()); + assert_eq!(sess.len(), 1); + assert!(!rd.any_left()); +} + +#[test] +fn accepts_empty_sessionid() { + let bytes = [0; 1]; + let mut rd = Reader::init(&bytes); + let sess = SessionId::read(&mut rd).unwrap(); + println!("{:?}", sess); + + assert!(sess.is_empty()); + assert_eq!(sess.len(), 0); + assert!(!rd.any_left()); +} + +#[test] +fn debug_sessionid() { + let bytes = [ + 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, + ]; + let mut rd = Reader::init(&bytes); + let sess = SessionId::read(&mut rd).unwrap(); + assert_eq!( + "0101010101010101010101010101010101010101010101010101010101010101", + format!("{:?}", sess) + ); +} + +#[test] +fn can_roundtrip_unknown_client_ext() { + let bytes = [0x12u8, 0x34u8, 0, 3, 1, 2, 3]; + let mut rd = Reader::init(&bytes); + let ext = ClientExtension::read(&mut rd).unwrap(); + + println!("{:?}", ext); + assert_eq!(ext.get_type(), ExtensionType::Unknown(0x1234)); + assert_eq!(bytes.to_vec(), ext.get_encoding()); +} + +#[test] +fn refuses_client_ext_with_unparsed_bytes() { + let bytes = [0x00u8, 0x0b, 0x00, 0x04, 0x02, 0xf8, 0x01, 0x02]; + let mut rd = Reader::init(&bytes); + assert!(ClientExtension::read(&mut rd).is_err()); +} + +#[test] +fn refuses_server_ext_with_unparsed_bytes() { + let bytes = [0x00u8, 0x0b, 0x00, 0x04, 0x02, 0xf8, 0x01, 0x02]; + let mut rd = Reader::init(&bytes); + assert!(ServerExtension::read(&mut rd).is_err()); +} + +#[test] +fn refuses_certificate_ext_with_unparsed_bytes() { + let bytes = [0x00u8, 0x12, 0x00, 0x03, 0x00, 0x00, 0x01]; + let mut rd = Reader::init(&bytes); + assert!(CertificateExtension::read(&mut rd).is_err()); +} + +#[test] +fn refuses_certificate_req_ext_with_unparsed_bytes() { + let bytes = [0x00u8, 0x0d, 0x00, 0x05, 0x00, 0x02, 0x01, 0x02, 0xff]; + let mut rd = Reader::init(&bytes); + assert!(CertReqExtension::read(&mut rd).is_err()); +} + +#[test] +fn refuses_helloreq_ext_with_unparsed_bytes() { + let bytes = [0x00u8, 0x2b, 0x00, 0x03, 0x00, 0x00, 0x01]; + let mut rd = Reader::init(&bytes); + assert!(HelloRetryExtension::read(&mut rd).is_err()); +} + +#[test] +fn refuses_newsessionticket_ext_with_unparsed_bytes() { + let bytes = [0x00u8, 0x2a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01]; + let mut rd = Reader::init(&bytes); + assert!(NewSessionTicketExtension::read(&mut rd).is_err()); +} + +#[test] +fn can_roundtrip_single_sni() { + let bytes = [0, 0, 0, 7, 0, 5, 0, 0, 2, 0x6c, 0x6f]; + let mut rd = Reader::init(&bytes); + let ext = ClientExtension::read(&mut rd).unwrap(); + println!("{:?}", ext); + + assert_eq!(ext.get_type(), ExtensionType::ServerName); + assert_eq!(bytes.to_vec(), ext.get_encoding()); +} + +#[test] +fn can_round_trip_mixed_case_sni() { + let bytes = [0, 0, 0, 7, 0, 5, 0, 0, 2, 0x4c, 0x6f]; + let mut rd = Reader::init(&bytes); + let ext = ClientExtension::read(&mut rd).unwrap(); + println!("{:?}", ext); + + assert_eq!(ext.get_type(), ExtensionType::ServerName); + assert_eq!(bytes.to_vec(), ext.get_encoding()); +} + +#[test] +fn can_roundtrip_other_sni_name_types() { + let bytes = [0, 0, 0, 7, 0, 5, 1, 0, 2, 0x6c, 0x6f]; + let mut rd = Reader::init(&bytes); + let ext = ClientExtension::read(&mut rd).unwrap(); + println!("{:?}", ext); + + assert_eq!(ext.get_type(), ExtensionType::ServerName); + assert_eq!(bytes.to_vec(), ext.get_encoding()); +} + +#[test] +fn get_single_hostname_returns_none_for_other_sni_name_types() { + let bytes = [0, 0, 0, 7, 0, 5, 1, 0, 2, 0x6c, 0x6f]; + let mut rd = Reader::init(&bytes); + let ext = ClientExtension::read(&mut rd).unwrap(); + println!("{:?}", ext); + + assert_eq!(ext.get_type(), ExtensionType::ServerName); + if let ClientExtension::ServerName(snr) = ext { + assert!(!snr.has_duplicate_names_for_type()); + assert!(snr.get_single_hostname().is_none()); + } else { + unreachable!(); + } +} + +#[test] +fn can_roundtrip_multiname_sni() { + let bytes = [0, 0, 0, 12, 0, 10, 0, 0, 2, 0x68, 0x69, 0, 0, 2, 0x6c, 0x6f]; + let mut rd = Reader::init(&bytes); + let ext = ClientExtension::read(&mut rd).unwrap(); + println!("{:?}", ext); + + assert_eq!(ext.get_type(), ExtensionType::ServerName); + assert_eq!(bytes.to_vec(), ext.get_encoding()); + match ext { + ClientExtension::ServerName(req) => { + assert_eq!(2, req.len()); + + assert!(req.has_duplicate_names_for_type()); + + let dns_name = req.get_single_hostname().unwrap(); + assert_eq!(dns_name.as_ref(), "hi"); + + assert_eq!(req[0].typ, ServerNameType::HostName); + assert_eq!(req[1].typ, ServerNameType::HostName); + } + _ => unreachable!(), + } +} + +#[test] +fn rejects_truncated_sni() { + let bytes = [0, 0, 0, 1, 0]; + assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); + + let bytes = [0, 0, 0, 2, 0, 1]; + assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); + + let bytes = [0, 0, 0, 3, 0, 1, 0]; + assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); + + let bytes = [0, 0, 0, 4, 0, 2, 0, 0]; + assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); + + let bytes = [0, 0, 0, 5, 0, 3, 0, 0, 0]; + assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); + + let bytes = [0, 0, 0, 5, 0, 3, 0, 0, 1]; + assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); + + let bytes = [0, 0, 0, 6, 0, 4, 0, 0, 2, 0x68]; + assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); +} + +#[test] +fn can_roundtrip_psk_identity() { + let bytes = [0, 0, 0x11, 0x22, 0x33, 0x44]; + let psk_id = PresharedKeyIdentity::read(&mut Reader::init(&bytes)).unwrap(); + println!("{:?}", psk_id); + assert_eq!(psk_id.obfuscated_ticket_age, 0x11223344); + assert_eq!(psk_id.get_encoding(), bytes.to_vec()); + + let bytes = [0, 5, 0x1, 0x2, 0x3, 0x4, 0x5, 0x11, 0x22, 0x33, 0x44]; + let psk_id = PresharedKeyIdentity::read(&mut Reader::init(&bytes)).unwrap(); + println!("{:?}", psk_id); + assert_eq!(psk_id.identity.0, vec![0x1, 0x2, 0x3, 0x4, 0x5]); + assert_eq!(psk_id.obfuscated_ticket_age, 0x11223344); + assert_eq!(psk_id.get_encoding(), bytes.to_vec()); +} + +#[test] +fn can_roundtrip_psk_offer() { + let bytes = [ + 0, 7, 0, 1, 0x99, 0x11, 0x22, 0x33, 0x44, 0, 4, 3, 0x01, 0x02, 0x3, + ]; + let psko = PresharedKeyOffer::read(&mut Reader::init(&bytes)).unwrap(); + println!("{:?}", psko); + + assert_eq!(psko.identities.len(), 1); + assert_eq!(psko.identities[0].identity.0, vec![0x99]); + assert_eq!(psko.identities[0].obfuscated_ticket_age, 0x11223344); + assert_eq!(psko.binders.len(), 1); + assert_eq!(psko.binders[0].as_ref(), &[1, 2, 3]); + assert_eq!(psko.get_encoding(), bytes.to_vec()); +} + +#[test] +fn can_roundtrip_certstatusreq_for_ocsp() { + let ext = ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()); + println!("{:?}", ext); + + let bytes = [ + 0, 5, // CertificateStatusRequest + 0, 11, 1, // OCSP + 0, 5, 0, 3, 0, 1, 1, 0, 1, 2, + ]; + + let csr = ClientExtension::read(&mut Reader::init(&bytes)).unwrap(); + println!("{:?}", csr); + assert_eq!(csr.get_encoding(), bytes.to_vec()); +} + +#[test] +fn can_roundtrip_certstatusreq_for_other() { + let bytes = [ + 0, 5, // CertificateStatusRequest + 0, 5, 2, // !OCSP + 1, 2, 3, 4, + ]; + + let csr = ClientExtension::read(&mut Reader::init(&bytes)).unwrap(); + println!("{:?}", csr); + assert_eq!(csr.get_encoding(), bytes.to_vec()); +} + +#[test] +fn can_roundtrip_multi_proto() { + let bytes = [0, 16, 0, 8, 0, 6, 2, 0x68, 0x69, 2, 0x6c, 0x6f]; + let mut rd = Reader::init(&bytes); + let ext = ClientExtension::read(&mut rd).unwrap(); + println!("{:?}", ext); + + assert_eq!(ext.get_type(), ExtensionType::ALProtocolNegotiation); + assert_eq!(ext.get_encoding(), bytes.to_vec()); + match ext { + ClientExtension::Protocols(prot) => { + assert_eq!(2, prot.len()); + assert_eq!(vec![b"hi", b"lo"], prot.to_slices()); + assert_eq!(prot.as_single_slice(), None); + } + _ => unreachable!(), + } +} + +#[test] +fn can_roundtrip_single_proto() { + let bytes = [0, 16, 0, 5, 0, 3, 2, 0x68, 0x69]; + let mut rd = Reader::init(&bytes); + let ext = ClientExtension::read(&mut rd).unwrap(); + println!("{:?}", ext); + + assert_eq!(ext.get_type(), ExtensionType::ALProtocolNegotiation); + assert_eq!(bytes.to_vec(), ext.get_encoding()); + match ext { + ClientExtension::Protocols(prot) => { + assert_eq!(1, prot.len()); + assert_eq!(vec![b"hi"], prot.to_slices()); + assert_eq!(prot.as_single_slice(), Some(&b"hi"[..])); + } + _ => unreachable!(), + } +} + +fn get_sample_clienthellopayload() -> ClientHelloPayload { + ClientHelloPayload { + client_version: ProtocolVersion::TLSv1_2, + random: Random::from([0; 32]), + session_id: SessionId::empty(), + cipher_suites: vec![CipherSuite::TLS_NULL_WITH_NULL_NULL], + compression_methods: vec![Compression::Null], + extensions: vec![ + ClientExtension::ECPointFormats(ECPointFormat::SUPPORTED.to_vec()), + ClientExtension::NamedGroups(vec![NamedGroup::X25519]), + ClientExtension::SignatureAlgorithms(vec![SignatureScheme::ECDSA_NISTP256_SHA256]), + ClientExtension::make_sni(DnsNameRef::try_from("hello").unwrap()), + ClientExtension::SessionTicket(ClientSessionTicket::Request), + ClientExtension::SessionTicket(ClientSessionTicket::Offer(Payload(vec![]))), + ClientExtension::Protocols(vec![ProtocolName::from(vec![0])]), + ClientExtension::SupportedVersions(vec![ProtocolVersion::TLSv1_3]), + ClientExtension::KeyShare(vec![KeyShareEntry::new(NamedGroup::X25519, &[1, 2, 3])]), + ClientExtension::PresharedKeyModes(vec![PSKKeyExchangeMode::PSK_DHE_KE]), + ClientExtension::PresharedKey(PresharedKeyOffer { + identities: vec![ + PresharedKeyIdentity::new(vec![3, 4, 5], 123456), + PresharedKeyIdentity::new(vec![6, 7, 8], 7891011), + ], + binders: vec![ + PresharedKeyBinder::from(vec![1, 2, 3]), + PresharedKeyBinder::from(vec![3, 4, 5]), + ], + }), + ClientExtension::Cookie(PayloadU16(vec![1, 2, 3])), + ClientExtension::ExtendedMasterSecretRequest, + ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()), + ClientExtension::SignedCertificateTimestampRequest, + ClientExtension::TransportParameters(vec![1, 2, 3]), + ClientExtension::Unknown(UnknownExtension { + typ: ExtensionType::Unknown(12345), + payload: Payload(vec![1, 2, 3]), + }), + ], + } +} + +#[test] +fn can_print_all_clientextensions() { + println!("client hello {:?}", get_sample_clienthellopayload()); +} + +#[test] +fn can_clone_all_clientextensions() { + let _ = get_sample_serverhellopayload().extensions; +} + +#[test] +fn client_has_duplicate_extensions_works() { + let mut chp = get_sample_clienthellopayload(); + assert!(chp.has_duplicate_extension()); // due to SessionTicketRequest/SessionTicketOffer + + chp.extensions.drain(1..); + assert!(!chp.has_duplicate_extension()); + + chp.extensions = vec![]; + assert!(!chp.has_duplicate_extension()); +} + +#[test] +fn test_truncated_psk_offer() { + let ext = ClientExtension::PresharedKey(PresharedKeyOffer { + identities: vec![PresharedKeyIdentity::new(vec![3, 4, 5], 123456)], + binders: vec![PresharedKeyBinder::from(vec![1, 2, 3])], + }); + + let mut enc = ext.get_encoding(); + println!("testing {:?} enc {:?}", ext, enc); + for l in 0..enc.len() { + if l == 9 { + continue; + } + put_u16(l as u16, &mut enc[4..]); + let rc = ClientExtension::read_bytes(&enc); + assert!(rc.is_err()); + } +} + +#[test] +fn test_truncated_client_hello_is_detected() { + let ch = get_sample_clienthellopayload(); + let enc = ch.get_encoding(); + println!("testing {:?} enc {:?}", ch, enc); + + for l in 0..enc.len() { + println!("len {:?} enc {:?}", l, &enc[..l]); + if l == 41 { + continue; // where extensions are empty + } + assert!(ClientHelloPayload::read_bytes(&enc[..l]).is_err()); + } +} + +#[test] +fn test_truncated_client_extension_is_detected() { + let chp = get_sample_clienthellopayload(); + + for ext in &chp.extensions { + let mut enc = ext.get_encoding(); + println!("testing {:?} enc {:?}", ext, enc); + + // "outer" truncation, i.e., where the extension-level length is longer than + // the input + for l in 0..enc.len() { + assert!(ClientExtension::read_bytes(&enc[..l]).is_err()); + } + + // these extension types don't have any internal encoding that rustls validates: + match ext.get_type() { + ExtensionType::TransportParameters | ExtensionType::Unknown(_) => { + continue; + } + _ => {} + }; + + // "inner" truncation, where the extension-level length agrees with the input + // length, but isn't long enough for the type of extension + for l in 0..(enc.len() - 4) { + put_u16(l as u16, &mut enc[2..]); + println!(" encoding {:?} len {:?}", enc, l); + assert!(ClientExtension::read_bytes(&enc).is_err()); + } + } +} + +fn test_client_extension_getter(typ: ExtensionType, getter: fn(&ClientHelloPayload) -> bool) { + let mut chp = get_sample_clienthellopayload(); + let ext = chp.find_extension(typ).unwrap().clone(); + + chp.extensions = vec![]; + assert!(!getter(&chp)); + + chp.extensions = vec![ext]; + assert!(getter(&chp)); + + chp.extensions = vec![ClientExtension::Unknown(UnknownExtension { + typ, + payload: Payload(vec![]), + })]; + assert!(!getter(&chp)); +} + +#[test] +fn client_get_sni_extension() { + test_client_extension_getter(ExtensionType::ServerName, |chp| { + chp.get_sni_extension().is_some() + }); +} + +#[test] +fn client_get_sigalgs_extension() { + test_client_extension_getter(ExtensionType::SignatureAlgorithms, |chp| { + chp.get_sigalgs_extension().is_some() + }); +} + +#[test] +fn client_get_namedgroups_extension() { + test_client_extension_getter(ExtensionType::EllipticCurves, |chp| { + chp.get_namedgroups_extension() + .is_some() + }); +} + +#[test] +fn client_get_ecpoints_extension() { + test_client_extension_getter(ExtensionType::ECPointFormats, |chp| { + chp.get_ecpoints_extension().is_some() + }); +} + +#[test] +fn client_get_alpn_extension() { + test_client_extension_getter(ExtensionType::ALProtocolNegotiation, |chp| { + chp.get_alpn_extension().is_some() + }); +} + +#[test] +fn client_get_quic_params_extension() { + test_client_extension_getter(ExtensionType::TransportParameters, |chp| { + chp.get_quic_params_extension() + .is_some() + }); +} + +#[test] +fn client_get_versions_extension() { + test_client_extension_getter(ExtensionType::SupportedVersions, |chp| { + chp.get_versions_extension().is_some() + }); +} + +#[test] +fn client_get_keyshare_extension() { + test_client_extension_getter(ExtensionType::KeyShare, |chp| { + chp.get_keyshare_extension().is_some() + }); +} + +#[test] +fn client_get_psk() { + test_client_extension_getter(ExtensionType::PreSharedKey, |chp| chp.get_psk().is_some()); +} + +#[test] +fn client_get_psk_modes() { + test_client_extension_getter(ExtensionType::PSKKeyExchangeModes, |chp| { + chp.get_psk_modes().is_some() + }); +} + +#[test] +fn test_truncated_helloretry_extension_is_detected() { + let hrr = get_sample_helloretryrequest(); + + for ext in &hrr.extensions { + let mut enc = ext.get_encoding(); + println!("testing {:?} enc {:?}", ext, enc); + + // "outer" truncation, i.e., where the extension-level length is longer than + // the input + for l in 0..enc.len() { + assert!(HelloRetryExtension::read_bytes(&enc[..l]).is_err()); + } + + // these extension types don't have any internal encoding that rustls validates: + if let ExtensionType::Unknown(_) = ext.get_type() { + continue; + } + + // "inner" truncation, where the extension-level length agrees with the input + // length, but isn't long enough for the type of extension + for l in 0..(enc.len() - 4) { + put_u16(l as u16, &mut enc[2..]); + println!(" encoding {:?} len {:?}", enc, l); + assert!(HelloRetryExtension::read_bytes(&enc).is_err()); + } + } +} + +fn test_helloretry_extension_getter(typ: ExtensionType, getter: fn(&HelloRetryRequest) -> bool) { + let mut hrr = get_sample_helloretryrequest(); + let mut exts = std::mem::take(&mut hrr.extensions); + exts.retain(|ext| ext.get_type() == typ); + + assert!(!getter(&hrr)); + + hrr.extensions = exts; + assert!(getter(&hrr)); + + hrr.extensions = vec![HelloRetryExtension::Unknown(UnknownExtension { + typ, + payload: Payload(vec![]), + })]; + assert!(!getter(&hrr)); +} + +#[test] +fn helloretry_get_requested_key_share_group() { + test_helloretry_extension_getter(ExtensionType::KeyShare, |hrr| { + hrr.get_requested_key_share_group() + .is_some() + }); +} + +#[test] +fn helloretry_get_cookie() { + test_helloretry_extension_getter(ExtensionType::Cookie, |hrr| hrr.get_cookie().is_some()); +} + +#[test] +fn helloretry_get_supported_versions() { + test_helloretry_extension_getter(ExtensionType::SupportedVersions, |hrr| { + hrr.get_supported_versions().is_some() + }); +} + +#[test] +fn test_truncated_server_extension_is_detected() { + let shp = get_sample_serverhellopayload(); + + for ext in &shp.extensions { + let mut enc = ext.get_encoding(); + println!("testing {:?} enc {:?}", ext, enc); + + // "outer" truncation, i.e., where the extension-level length is longer than + // the input + for l in 0..enc.len() { + assert!(ServerExtension::read_bytes(&enc[..l]).is_err()); + } + + // these extension types don't have any internal encoding that rustls validates: + match ext.get_type() { + ExtensionType::TransportParameters | ExtensionType::Unknown(_) => { + continue; + } + _ => {} + }; + + // "inner" truncation, where the extension-level length agrees with the input + // length, but isn't long enough for the type of extension + for l in 0..(enc.len() - 4) { + put_u16(l as u16, &mut enc[2..]); + println!(" encoding {:?} len {:?}", enc, l); + assert!(ServerExtension::read_bytes(&enc).is_err()); + } + } +} + +fn test_server_extension_getter(typ: ExtensionType, getter: fn(&ServerHelloPayload) -> bool) { + let mut shp = get_sample_serverhellopayload(); + let ext = shp.find_extension(typ).unwrap().clone(); + + shp.extensions = vec![]; + assert!(!getter(&shp)); + + shp.extensions = vec![ext]; + assert!(getter(&shp)); + + shp.extensions = vec![ServerExtension::Unknown(UnknownExtension { + typ, + payload: Payload(vec![]), + })]; + assert!(!getter(&shp)); +} + +#[test] +fn server_get_key_share() { + test_server_extension_getter(ExtensionType::KeyShare, |shp| shp.get_key_share().is_some()); +} + +#[test] +fn server_get_psk_index() { + test_server_extension_getter(ExtensionType::PreSharedKey, |shp| { + shp.get_psk_index().is_some() + }); +} + +#[test] +fn server_get_ecpoints_extension() { + test_server_extension_getter(ExtensionType::ECPointFormats, |shp| { + shp.get_ecpoints_extension().is_some() + }); +} + +#[test] +fn server_get_sct_list() { + test_server_extension_getter(ExtensionType::SCT, |shp| shp.get_sct_list().is_some()); +} + +#[test] +fn server_get_supported_versions() { + test_server_extension_getter(ExtensionType::SupportedVersions, |shp| { + shp.get_supported_versions().is_some() + }); +} + +fn test_cert_extension_getter(typ: ExtensionType, getter: fn(&CertificateEntry) -> bool) { + let mut ce = get_sample_certificatepayloadtls13() + .entries + .remove(0); + let mut exts = std::mem::take(&mut ce.exts); + exts.retain(|ext| ext.get_type() == typ); + + assert!(!getter(&ce)); + + ce.exts = exts; + assert!(getter(&ce)); + + ce.exts = vec![CertificateExtension::Unknown(UnknownExtension { + typ, + payload: Payload(vec![]), + })]; + assert!(!getter(&ce)); +} + +#[test] +fn certentry_get_ocsp_response() { + test_cert_extension_getter(ExtensionType::StatusRequest, |ce| { + ce.get_ocsp_response().is_some() + }); +} + +#[test] +fn certentry_get_scts() { + test_cert_extension_getter(ExtensionType::SCT, |ce| ce.get_scts().is_some()); +} + +fn get_sample_serverhellopayload() -> ServerHelloPayload { + ServerHelloPayload { + legacy_version: ProtocolVersion::TLSv1_2, + random: Random::from([0; 32]), + session_id: SessionId::empty(), + cipher_suite: CipherSuite::TLS_NULL_WITH_NULL_NULL, + compression_method: Compression::Null, + extensions: vec![ + ServerExtension::ECPointFormats(ECPointFormat::SUPPORTED.to_vec()), + ServerExtension::ServerNameAck, + ServerExtension::SessionTicketAck, + ServerExtension::RenegotiationInfo(PayloadU8(vec![0])), + ServerExtension::Protocols(vec![ProtocolName::from(vec![0])]), + ServerExtension::KeyShare(KeyShareEntry::new(NamedGroup::X25519, &[1, 2, 3])), + ServerExtension::PresharedKey(3), + ServerExtension::ExtendedMasterSecretAck, + ServerExtension::CertificateStatusAck, + ServerExtension::SignedCertificateTimestamp(vec![Sct::from(vec![0])]), + ServerExtension::SupportedVersions(ProtocolVersion::TLSv1_2), + ServerExtension::TransportParameters(vec![1, 2, 3]), + ServerExtension::Unknown(UnknownExtension { + typ: ExtensionType::Unknown(12345), + payload: Payload(vec![1, 2, 3]), + }), + ], + } +} + +#[test] +fn can_print_all_serverextensions() { + println!("server hello {:?}", get_sample_serverhellopayload()); +} + +#[test] +fn can_clone_all_serverextensions() { + let _ = get_sample_serverhellopayload().extensions; +} + +fn get_sample_helloretryrequest() -> HelloRetryRequest { + HelloRetryRequest { + legacy_version: ProtocolVersion::TLSv1_2, + session_id: SessionId::empty(), + cipher_suite: CipherSuite::TLS_NULL_WITH_NULL_NULL, + extensions: vec![ + HelloRetryExtension::KeyShare(NamedGroup::X25519), + HelloRetryExtension::Cookie(PayloadU16(vec![0])), + HelloRetryExtension::SupportedVersions(ProtocolVersion::TLSv1_2), + HelloRetryExtension::Unknown(UnknownExtension { + typ: ExtensionType::Unknown(12345), + payload: Payload(vec![1, 2, 3]), + }), + ], + } +} + +fn get_sample_certificatepayloadtls13() -> CertificatePayloadTLS13 { + CertificatePayloadTLS13 { + context: PayloadU8(vec![1, 2, 3]), + entries: vec![CertificateEntry { + cert: Certificate(vec![3, 4, 5]), + exts: vec![ + CertificateExtension::CertificateStatus(CertificateStatus { + ocsp_response: PayloadU24(vec![1, 2, 3]), + }), + CertificateExtension::SignedCertificateTimestamp(vec![Sct::from(vec![0])]), + CertificateExtension::Unknown(UnknownExtension { + typ: ExtensionType::Unknown(12345), + payload: Payload(vec![1, 2, 3]), + }), + ], + }], + } +} + +fn get_sample_serverkeyexchangepayload_ecdhe() -> ServerKeyExchangePayload { + ServerKeyExchangePayload::ECDHE(ECDHEServerKeyExchange { + params: ServerECDHParams { + curve_params: ECParameters { + curve_type: ECCurveType::NamedCurve, + named_group: NamedGroup::X25519, + }, + public: PayloadU8(vec![1, 2, 3]), + }, + dss: DigitallySignedStruct::new(SignatureScheme::RSA_PSS_SHA256, vec![1, 2, 3]), + }) +} + +fn get_sample_serverkeyexchangepayload_unknown() -> ServerKeyExchangePayload { + ServerKeyExchangePayload::Unknown(Payload(vec![1, 2, 3])) +} + +fn get_sample_certificaterequestpayload() -> CertificateRequestPayload { + CertificateRequestPayload { + certtypes: vec![ClientCertificateType::RSASign], + sigschemes: vec![SignatureScheme::ECDSA_NISTP256_SHA256], + canames: vec![DistinguishedName::from(vec![1, 2, 3])], + } +} + +fn get_sample_certificaterequestpayloadtls13() -> CertificateRequestPayloadTLS13 { + CertificateRequestPayloadTLS13 { + context: PayloadU8(vec![1, 2, 3]), + extensions: vec![ + CertReqExtension::SignatureAlgorithms(vec![SignatureScheme::ECDSA_NISTP256_SHA256]), + CertReqExtension::AuthorityNames(vec![DistinguishedName::from(vec![1, 2, 3])]), + CertReqExtension::Unknown(UnknownExtension { + typ: ExtensionType::Unknown(12345), + payload: Payload(vec![1, 2, 3]), + }), + ], + } +} + +fn get_sample_newsessionticketpayload() -> NewSessionTicketPayload { + NewSessionTicketPayload { + lifetime_hint: 1234, + ticket: PayloadU16(vec![1, 2, 3]), + } +} + +fn get_sample_newsessionticketpayloadtls13() -> NewSessionTicketPayloadTLS13 { + NewSessionTicketPayloadTLS13 { + lifetime: 123, + age_add: 1234, + nonce: PayloadU8(vec![1, 2, 3]), + ticket: PayloadU16(vec![4, 5, 6]), + exts: vec![NewSessionTicketExtension::Unknown(UnknownExtension { + typ: ExtensionType::Unknown(12345), + payload: Payload(vec![1, 2, 3]), + })], + } +} + +fn get_sample_encryptedextensions() -> Vec { + get_sample_serverhellopayload().extensions +} + +fn get_sample_certificatestatus() -> CertificateStatus { + CertificateStatus { + ocsp_response: PayloadU24(vec![1, 2, 3]), + } +} + +fn get_all_tls12_handshake_payloads() -> Vec { + vec![ + HandshakeMessagePayload { + typ: HandshakeType::HelloRequest, + payload: HandshakePayload::HelloRequest, + }, + HandshakeMessagePayload { + typ: HandshakeType::ClientHello, + payload: HandshakePayload::ClientHello(get_sample_clienthellopayload()), + }, + HandshakeMessagePayload { + typ: HandshakeType::ServerHello, + payload: HandshakePayload::ServerHello(get_sample_serverhellopayload()), + }, + HandshakeMessagePayload { + typ: HandshakeType::HelloRetryRequest, + payload: HandshakePayload::HelloRetryRequest(get_sample_helloretryrequest()), + }, + HandshakeMessagePayload { + typ: HandshakeType::Certificate, + payload: HandshakePayload::Certificate(vec![Certificate(vec![1, 2, 3])]), + }, + HandshakeMessagePayload { + typ: HandshakeType::ServerKeyExchange, + payload: HandshakePayload::ServerKeyExchange( + get_sample_serverkeyexchangepayload_ecdhe(), + ), + }, + HandshakeMessagePayload { + typ: HandshakeType::ServerKeyExchange, + payload: HandshakePayload::ServerKeyExchange( + get_sample_serverkeyexchangepayload_unknown(), + ), + }, + HandshakeMessagePayload { + typ: HandshakeType::CertificateRequest, + payload: HandshakePayload::CertificateRequest(get_sample_certificaterequestpayload()), + }, + HandshakeMessagePayload { + typ: HandshakeType::ServerHelloDone, + payload: HandshakePayload::ServerHelloDone, + }, + HandshakeMessagePayload { + typ: HandshakeType::ClientKeyExchange, + payload: HandshakePayload::ClientKeyExchange(Payload(vec![1, 2, 3])), + }, + HandshakeMessagePayload { + typ: HandshakeType::NewSessionTicket, + payload: HandshakePayload::NewSessionTicket(get_sample_newsessionticketpayload()), + }, + HandshakeMessagePayload { + typ: HandshakeType::EncryptedExtensions, + payload: HandshakePayload::EncryptedExtensions(get_sample_encryptedextensions()), + }, + HandshakeMessagePayload { + typ: HandshakeType::KeyUpdate, + payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateRequested), + }, + HandshakeMessagePayload { + typ: HandshakeType::KeyUpdate, + payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateNotRequested), + }, + HandshakeMessagePayload { + typ: HandshakeType::Finished, + payload: HandshakePayload::Finished(Payload(vec![1, 2, 3])), + }, + HandshakeMessagePayload { + typ: HandshakeType::CertificateStatus, + payload: HandshakePayload::CertificateStatus(get_sample_certificatestatus()), + }, + HandshakeMessagePayload { + typ: HandshakeType::Unknown(99), + payload: HandshakePayload::Unknown(Payload(vec![1, 2, 3])), + }, + ] +} + +#[test] +fn can_roundtrip_all_tls12_handshake_payloads() { + for ref hm in get_all_tls12_handshake_payloads().iter() { + println!("{:?}", hm.typ); + let bytes = hm.get_encoding(); + let mut rd = Reader::init(&bytes); + let other = HandshakeMessagePayload::read(&mut rd).unwrap(); + assert!(!rd.any_left()); + assert_eq!(hm.get_encoding(), other.get_encoding()); + + println!("{:?}", hm); + println!("{:?}", other); + } +} + +#[test] +fn can_detect_truncation_of_all_tls12_handshake_payloads() { + for hm in get_all_tls12_handshake_payloads().iter() { + let mut enc = hm.get_encoding(); + println!("test {:?} enc {:?}", hm, enc); + + // outer truncation + for l in 0..enc.len() { + assert!(HandshakeMessagePayload::read_bytes(&enc[..l]).is_err()) + } + + // inner truncation + for l in 0..enc.len() - 4 { + put_u24(l as u32, &mut enc[1..]); + println!(" check len {:?} enc {:?}", l, enc); + + match (hm.typ, l) { + (HandshakeType::ClientHello, 41) + | (HandshakeType::ServerHello, 38) + | (HandshakeType::ServerKeyExchange, _) + | (HandshakeType::ClientKeyExchange, _) + | (HandshakeType::Finished, _) + | (HandshakeType::Unknown(_), _) => continue, + _ => {} + }; + + assert!(HandshakeMessagePayload::read_version( + &mut Reader::init(&enc), + ProtocolVersion::TLSv1_2 + ) + .is_err()); + assert!(HandshakeMessagePayload::read_bytes(&enc).is_err()); + } + } +} + +fn get_all_tls13_handshake_payloads() -> Vec { + vec![ + HandshakeMessagePayload { + typ: HandshakeType::HelloRequest, + payload: HandshakePayload::HelloRequest, + }, + HandshakeMessagePayload { + typ: HandshakeType::ClientHello, + payload: HandshakePayload::ClientHello(get_sample_clienthellopayload()), + }, + HandshakeMessagePayload { + typ: HandshakeType::ServerHello, + payload: HandshakePayload::ServerHello(get_sample_serverhellopayload()), + }, + HandshakeMessagePayload { + typ: HandshakeType::HelloRetryRequest, + payload: HandshakePayload::HelloRetryRequest(get_sample_helloretryrequest()), + }, + HandshakeMessagePayload { + typ: HandshakeType::Certificate, + payload: HandshakePayload::CertificateTLS13(get_sample_certificatepayloadtls13()), + }, + HandshakeMessagePayload { + typ: HandshakeType::ServerKeyExchange, + payload: HandshakePayload::ServerKeyExchange( + get_sample_serverkeyexchangepayload_ecdhe(), + ), + }, + HandshakeMessagePayload { + typ: HandshakeType::ServerKeyExchange, + payload: HandshakePayload::ServerKeyExchange( + get_sample_serverkeyexchangepayload_unknown(), + ), + }, + HandshakeMessagePayload { + typ: HandshakeType::CertificateRequest, + payload: HandshakePayload::CertificateRequestTLS13( + get_sample_certificaterequestpayloadtls13(), + ), + }, + HandshakeMessagePayload { + typ: HandshakeType::CertificateVerify, + payload: HandshakePayload::CertificateVerify(DigitallySignedStruct::new( + SignatureScheme::ECDSA_NISTP256_SHA256, + vec![1, 2, 3], + )), + }, + HandshakeMessagePayload { + typ: HandshakeType::ServerHelloDone, + payload: HandshakePayload::ServerHelloDone, + }, + HandshakeMessagePayload { + typ: HandshakeType::ClientKeyExchange, + payload: HandshakePayload::ClientKeyExchange(Payload(vec![1, 2, 3])), + }, + HandshakeMessagePayload { + typ: HandshakeType::NewSessionTicket, + payload: HandshakePayload::NewSessionTicketTLS13( + get_sample_newsessionticketpayloadtls13(), + ), + }, + HandshakeMessagePayload { + typ: HandshakeType::EncryptedExtensions, + payload: HandshakePayload::EncryptedExtensions(get_sample_encryptedextensions()), + }, + HandshakeMessagePayload { + typ: HandshakeType::KeyUpdate, + payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateRequested), + }, + HandshakeMessagePayload { + typ: HandshakeType::KeyUpdate, + payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateNotRequested), + }, + HandshakeMessagePayload { + typ: HandshakeType::Finished, + payload: HandshakePayload::Finished(Payload(vec![1, 2, 3])), + }, + HandshakeMessagePayload { + typ: HandshakeType::CertificateStatus, + payload: HandshakePayload::CertificateStatus(get_sample_certificatestatus()), + }, + HandshakeMessagePayload { + typ: HandshakeType::Unknown(99), + payload: HandshakePayload::Unknown(Payload(vec![1, 2, 3])), + }, + ] +} + +#[test] +fn can_roundtrip_all_tls13_handshake_payloads() { + for ref hm in get_all_tls13_handshake_payloads().iter() { + println!("{:?}", hm.typ); + let bytes = hm.get_encoding(); + let mut rd = Reader::init(&bytes); + + let other = + HandshakeMessagePayload::read_version(&mut rd, ProtocolVersion::TLSv1_3).unwrap(); + assert!(!rd.any_left()); + assert_eq!(hm.get_encoding(), other.get_encoding()); + + println!("{:?}", hm); + println!("{:?}", other); + } +} + +fn put_u24(u: u32, b: &mut [u8]) { + b[0] = (u >> 16) as u8; + b[1] = (u >> 8) as u8; + b[2] = u as u8; +} + +#[test] +fn can_detect_truncation_of_all_tls13_handshake_payloads() { + for hm in get_all_tls13_handshake_payloads().iter() { + let mut enc = hm.get_encoding(); + println!("test {:?} enc {:?}", hm, enc); + + // outer truncation + for l in 0..enc.len() { + assert!(HandshakeMessagePayload::read_bytes(&enc[..l]).is_err()) + } + + // inner truncation + for l in 0..enc.len() - 4 { + put_u24(l as u32, &mut enc[1..]); + println!(" check len {:?} enc {:?}", l, enc); + + match (hm.typ, l) { + (HandshakeType::ClientHello, 41) + | (HandshakeType::ServerHello, 38) + | (HandshakeType::ServerKeyExchange, _) + | (HandshakeType::ClientKeyExchange, _) + | (HandshakeType::Finished, _) + | (HandshakeType::Unknown(_), _) => continue, + _ => {} + }; + + assert!(HandshakeMessagePayload::read_version( + &mut Reader::init(&enc), + ProtocolVersion::TLSv1_3 + ) + .is_err()); + } + } +} + +#[test] +fn cannot_read_messagehash_from_network() { + let mh = HandshakeMessagePayload { + typ: HandshakeType::MessageHash, + payload: HandshakePayload::MessageHash(Payload::new(vec![1, 2, 3])), + }; + println!("mh {:?}", mh); + let enc = mh.get_encoding(); + assert!(HandshakeMessagePayload::read_bytes(&enc).is_err()); +} + +#[test] +fn cannot_decode_huge_certificate() { + let mut buf = [0u8; 65 * 1024]; + // exactly 64KB decodes fine + buf[0] = 0x0b; + buf[1] = 0x01; + buf[2] = 0x00; + buf[3] = 0x03; + buf[4] = 0x01; + buf[5] = 0x00; + buf[6] = 0x00; + buf[7] = 0x00; + buf[8] = 0xff; + buf[9] = 0xfd; + HandshakeMessagePayload::read_bytes(&buf).unwrap(); + + // however 64KB + 1 byte does not + buf[1] = 0x01; + buf[2] = 0x00; + buf[3] = 0x04; + buf[4] = 0x01; + buf[5] = 0x00; + buf[6] = 0x01; + assert!(HandshakeMessagePayload::read_bytes(&buf).is_err()); +} + +#[test] +fn can_decode_server_hello_from_api_devicecheck_apple_com() { + let data = include_bytes!("hello-api.devicecheck.apple.com.bin"); + let mut r = Reader::init(data); + let hm = HandshakeMessagePayload::read(&mut r).unwrap(); + println!("msg: {:?}", hm); +} diff --git a/vendor/rustls-0.21.8/src/msgs/hello-api.devicecheck.apple.com.bin b/vendor/rustls-0.21.8/src/msgs/hello-api.devicecheck.apple.com.bin new file mode 100644 index 0000000000000..fcbaaadee7193 Binary files /dev/null and b/vendor/rustls-0.21.8/src/msgs/hello-api.devicecheck.apple.com.bin differ diff --git a/vendor/rustls-0.21.8/src/msgs/macros.rs b/vendor/rustls-0.21.8/src/msgs/macros.rs new file mode 100644 index 0000000000000..ba47e9b34c818 --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/macros.rs @@ -0,0 +1,96 @@ +/// A macro which defines an enum type. +macro_rules! enum_builder { + ( + $(#[$comment:meta])* + @U8 + EnumName: $enum_name: ident; + EnumVal { $( $enum_var: ident => $enum_val: expr ),* } + ) => { + $(#[$comment])* + #[non_exhaustive] + #[derive(Debug, PartialEq, Eq, Clone, Copy)] + pub enum $enum_name { + $( $enum_var),* + ,Unknown(u8) + } + impl $enum_name { + pub fn get_u8(&self) -> u8 { + let x = self.clone(); + match x { + $( $enum_name::$enum_var => $enum_val),* + ,$enum_name::Unknown(x) => x + } + } + } + impl Codec for $enum_name { + fn encode(&self, bytes: &mut Vec) { + self.get_u8().encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + match u8::read(r) { + Ok(x) => Ok($enum_name::from(x)), + Err(_) => Err(crate::error::InvalidMessage::MissingData(stringify!($enum_name))), + } + } + } + impl From for $enum_name { + fn from(x: u8) -> Self { + match x { + $($enum_val => $enum_name::$enum_var),* + , x => $enum_name::Unknown(x), + } + } + } + }; + ( + $(#[$comment:meta])* + @U16 + EnumName: $enum_name: ident; + EnumVal { $( $enum_var: ident => $enum_val: expr ),* } + ) => { + $(#[$comment])* + #[non_exhaustive] + #[derive(Debug, PartialEq, Eq, Clone, Copy)] + pub enum $enum_name { + $( $enum_var),* + ,Unknown(u16) + } + impl $enum_name { + pub fn get_u16(&self) -> u16 { + let x = self.clone(); + match x { + $( $enum_name::$enum_var => $enum_val),* + ,$enum_name::Unknown(x) => x + } + } + + pub fn as_str(&self) -> Option<&'static str> { + match self { + $( $enum_name::$enum_var => Some(stringify!($enum_var))),* + ,$enum_name::Unknown(_) => None, + } + } + } + impl Codec for $enum_name { + fn encode(&self, bytes: &mut Vec) { + self.get_u16().encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + match u16::read(r) { + Ok(x) => Ok($enum_name::from(x)), + Err(_) => Err(crate::error::InvalidMessage::MissingData(stringify!($enum_name))), + } + } + } + impl From for $enum_name { + fn from(x: u16) -> Self { + match x { + $($enum_val => $enum_name::$enum_var),* + , x => $enum_name::Unknown(x), + } + } + } + }; +} diff --git a/vendor/rustls-0.21.8/src/msgs/message.rs b/vendor/rustls-0.21.8/src/msgs/message.rs new file mode 100644 index 0000000000000..5915ab5edeea7 --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/message.rs @@ -0,0 +1,292 @@ +use crate::enums::ProtocolVersion; +use crate::enums::{AlertDescription, ContentType, HandshakeType}; +use crate::error::{Error, InvalidMessage}; +use crate::msgs::alert::AlertMessagePayload; +use crate::msgs::base::Payload; +use crate::msgs::ccs::ChangeCipherSpecPayload; +use crate::msgs::codec::{Codec, Reader}; +use crate::msgs::enums::AlertLevel; +use crate::msgs::handshake::HandshakeMessagePayload; + +#[derive(Debug)] +pub enum MessagePayload { + Alert(AlertMessagePayload), + Handshake { + parsed: HandshakeMessagePayload, + encoded: Payload, + }, + ChangeCipherSpec(ChangeCipherSpecPayload), + ApplicationData(Payload), +} + +impl MessagePayload { + pub fn encode(&self, bytes: &mut Vec) { + match self { + Self::Alert(x) => x.encode(bytes), + Self::Handshake { encoded, .. } => bytes.extend(&encoded.0), + Self::ChangeCipherSpec(x) => x.encode(bytes), + Self::ApplicationData(x) => x.encode(bytes), + } + } + + pub fn handshake(parsed: HandshakeMessagePayload) -> Self { + Self::Handshake { + encoded: Payload::new(parsed.get_encoding()), + parsed, + } + } + + pub fn new( + typ: ContentType, + vers: ProtocolVersion, + payload: Payload, + ) -> Result { + let mut r = Reader::init(&payload.0); + match typ { + ContentType::ApplicationData => Ok(Self::ApplicationData(payload)), + ContentType::Alert => AlertMessagePayload::read(&mut r).map(MessagePayload::Alert), + ContentType::Handshake => { + HandshakeMessagePayload::read_version(&mut r, vers).map(|parsed| Self::Handshake { + parsed, + encoded: payload, + }) + } + ContentType::ChangeCipherSpec => { + ChangeCipherSpecPayload::read(&mut r).map(MessagePayload::ChangeCipherSpec) + } + _ => Err(InvalidMessage::InvalidContentType), + } + } + + pub fn content_type(&self) -> ContentType { + match self { + Self::Alert(_) => ContentType::Alert, + Self::Handshake { .. } => ContentType::Handshake, + Self::ChangeCipherSpec(_) => ContentType::ChangeCipherSpec, + Self::ApplicationData(_) => ContentType::ApplicationData, + } + } +} + +/// A TLS frame, named TLSPlaintext in the standard. +/// +/// This type owns all memory for its interior parts. It is used to read/write from/to I/O +/// buffers as well as for fragmenting, joining and encryption/decryption. It can be converted +/// into a `Message` by decoding the payload. +#[derive(Clone, Debug)] +pub struct OpaqueMessage { + pub typ: ContentType, + pub version: ProtocolVersion, + pub payload: Payload, +} + +impl OpaqueMessage { + /// `MessageError` allows callers to distinguish between valid prefixes (might + /// become valid if we read more data) and invalid data. + pub fn read(r: &mut Reader) -> Result { + let typ = ContentType::read(r).map_err(|_| MessageError::TooShortForHeader)?; + // Don't accept any new content-types. + if let ContentType::Unknown(_) = typ { + return Err(MessageError::InvalidContentType); + } + + let version = ProtocolVersion::read(r).map_err(|_| MessageError::TooShortForHeader)?; + // Accept only versions 0x03XX for any XX. + match version { + ProtocolVersion::Unknown(ref v) if (v & 0xff00) != 0x0300 => { + return Err(MessageError::UnknownProtocolVersion); + } + _ => {} + }; + + let len = u16::read(r).map_err(|_| MessageError::TooShortForHeader)?; + + // Reject undersize messages + // implemented per section 5.1 of RFC8446 (TLSv1.3) + // per section 6.2.1 of RFC5246 (TLSv1.2) + if typ != ContentType::ApplicationData && len == 0 { + return Err(MessageError::InvalidEmptyPayload); + } + + // Reject oversize messages + if len >= Self::MAX_PAYLOAD { + return Err(MessageError::MessageTooLarge); + } + + let mut sub = r + .sub(len as usize) + .map_err(|_| MessageError::TooShortForLength)?; + let payload = Payload::read(&mut sub); + + Ok(Self { + typ, + version, + payload, + }) + } + + pub fn encode(self) -> Vec { + let mut buf = Vec::new(); + self.typ.encode(&mut buf); + self.version.encode(&mut buf); + (self.payload.0.len() as u16).encode(&mut buf); + self.payload.encode(&mut buf); + buf + } + + /// Force conversion into a plaintext message. + /// + /// This should only be used for messages that are known to be in plaintext. Otherwise, the + /// `OpaqueMessage` should be decrypted into a `PlainMessage` using a `MessageDecrypter`. + pub fn into_plain_message(self) -> PlainMessage { + PlainMessage { + version: self.version, + typ: self.typ, + payload: self.payload, + } + } + + /// This is the maximum on-the-wire size of a TLSCiphertext. + /// That's 2^14 payload bytes, a header, and a 2KB allowance + /// for ciphertext overheads. + const MAX_PAYLOAD: u16 = 16384 + 2048; + + /// Content type, version and size. + const HEADER_SIZE: u16 = 1 + 2 + 2; + + /// Maximum on-wire message size. + pub const MAX_WIRE_SIZE: usize = (Self::MAX_PAYLOAD + Self::HEADER_SIZE) as usize; +} + +impl From for PlainMessage { + fn from(msg: Message) -> Self { + let typ = msg.payload.content_type(); + let payload = match msg.payload { + MessagePayload::ApplicationData(payload) => payload, + _ => { + let mut buf = Vec::new(); + msg.payload.encode(&mut buf); + Payload(buf) + } + }; + + Self { + typ, + version: msg.version, + payload, + } + } +} + +/// A decrypted TLS frame +/// +/// This type owns all memory for its interior parts. It can be decrypted from an OpaqueMessage +/// or encrypted into an OpaqueMessage, and it is also used for joining and fragmenting. +#[derive(Clone, Debug)] +pub struct PlainMessage { + pub typ: ContentType, + pub version: ProtocolVersion, + pub payload: Payload, +} + +impl PlainMessage { + pub fn into_unencrypted_opaque(self) -> OpaqueMessage { + OpaqueMessage { + version: self.version, + typ: self.typ, + payload: self.payload, + } + } + + pub fn borrow(&self) -> BorrowedPlainMessage<'_> { + BorrowedPlainMessage { + version: self.version, + typ: self.typ, + payload: &self.payload.0, + } + } +} + +/// A message with decoded payload +#[derive(Debug)] +pub struct Message { + pub version: ProtocolVersion, + pub payload: MessagePayload, +} + +impl Message { + pub fn is_handshake_type(&self, hstyp: HandshakeType) -> bool { + // Bit of a layering violation, but OK. + if let MessagePayload::Handshake { parsed, .. } = &self.payload { + parsed.typ == hstyp + } else { + false + } + } + + pub fn build_alert(level: AlertLevel, desc: AlertDescription) -> Self { + Self { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::Alert(AlertMessagePayload { + level, + description: desc, + }), + } + } + + pub fn build_key_update_notify() -> Self { + Self { + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::handshake(HandshakeMessagePayload::build_key_update_notify()), + } + } +} + +/// Parses a plaintext message into a well-typed [`Message`]. +/// +/// A [`PlainMessage`] must contain plaintext content. Encrypted content should be stored in an +/// [`OpaqueMessage`] and decrypted before being stored into a [`PlainMessage`]. +impl TryFrom for Message { + type Error = Error; + + fn try_from(plain: PlainMessage) -> Result { + Ok(Self { + version: plain.version, + payload: MessagePayload::new(plain.typ, plain.version, plain.payload)?, + }) + } +} + +/// A TLS frame, named TLSPlaintext in the standard. +/// +/// This type differs from `OpaqueMessage` because it borrows +/// its payload. You can make a `OpaqueMessage` from an +/// `BorrowMessage`, but this involves a copy. +/// +/// This type also cannot decode its internals and +/// cannot be read/encoded; only `OpaqueMessage` can do that. +pub struct BorrowedPlainMessage<'a> { + pub typ: ContentType, + pub version: ProtocolVersion, + pub payload: &'a [u8], +} + +impl<'a> BorrowedPlainMessage<'a> { + pub fn to_unencrypted_opaque(&self) -> OpaqueMessage { + OpaqueMessage { + version: self.version, + typ: self.typ, + payload: Payload(self.payload.to_vec()), + } + } +} + +#[derive(Debug)] +pub enum MessageError { + TooShortForHeader, + TooShortForLength, + InvalidEmptyPayload, + MessageTooLarge, + InvalidContentType, + UnknownProtocolVersion, +} diff --git a/vendor/rustls-0.21.8/src/msgs/message_test.rs b/vendor/rustls-0.21.8/src/msgs/message_test.rs new file mode 100644 index 0000000000000..010f93cd61bdf --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/message_test.rs @@ -0,0 +1,113 @@ +use crate::enums::{AlertDescription, HandshakeType}; +use crate::msgs::base::{PayloadU16, PayloadU24, PayloadU8}; + +use super::base::Payload; +use super::codec::Reader; +use super::enums::AlertLevel; +use super::message::{Message, OpaqueMessage, PlainMessage}; + +use std::fs; +use std::io::Read; +use std::path::{Path, PathBuf}; + +#[test] +fn test_read_fuzz_corpus() { + fn corpus_dir() -> PathBuf { + let from_subcrate = Path::new("../fuzz/corpus/message"); + let from_root = Path::new("fuzz/corpus/message"); + + if from_root.is_dir() { + from_root.to_path_buf() + } else { + from_subcrate.to_path_buf() + } + } + + for file in fs::read_dir(corpus_dir()).unwrap() { + let mut f = fs::File::open(file.unwrap().path()).unwrap(); + let mut bytes = Vec::new(); + f.read_to_end(&mut bytes).unwrap(); + + let mut rd = Reader::init(&bytes); + let msg = OpaqueMessage::read(&mut rd) + .unwrap() + .into_plain_message(); + println!("{:?}", msg); + + let msg = match Message::try_from(msg) { + Ok(msg) => msg, + Err(_) => continue, + }; + + let enc = PlainMessage::from(msg) + .into_unencrypted_opaque() + .encode(); + assert_eq!(bytes.to_vec(), enc); + assert_eq!(bytes[..rd.used()].to_vec(), enc); + } +} + +#[test] +fn can_read_safari_client_hello() { + let _ = env_logger::Builder::new() + .filter(None, log::LevelFilter::Trace) + .try_init(); + + let bytes = b"\ + \x16\x03\x01\x00\xeb\x01\x00\x00\xe7\x03\x03\xb6\x1f\xe4\x3a\x55\ + \x90\x3e\xc0\x28\x9c\x12\xe0\x5c\x84\xea\x90\x1b\xfb\x11\xfc\xbd\ + \x25\x55\xda\x9f\x51\x93\x1b\x8d\x92\x66\xfd\x00\x00\x2e\xc0\x2c\ + \xc0\x2b\xc0\x24\xc0\x23\xc0\x0a\xc0\x09\xcc\xa9\xc0\x30\xc0\x2f\ + \xc0\x28\xc0\x27\xc0\x14\xc0\x13\xcc\xa8\x00\x9d\x00\x9c\x00\x3d\ + \x00\x3c\x00\x35\x00\x2f\xc0\x08\xc0\x12\x00\x0a\x01\x00\x00\x90\ + \xff\x01\x00\x01\x00\x00\x00\x00\x0e\x00\x0c\x00\x00\x09\x31\x32\ + \x37\x2e\x30\x2e\x30\x2e\x31\x00\x17\x00\x00\x00\x0d\x00\x18\x00\ + \x16\x04\x03\x08\x04\x04\x01\x05\x03\x02\x03\x08\x05\x08\x05\x05\ + \x01\x08\x06\x06\x01\x02\x01\x00\x05\x00\x05\x01\x00\x00\x00\x00\ + \x33\x74\x00\x00\x00\x12\x00\x00\x00\x10\x00\x30\x00\x2e\x02\x68\ + \x32\x05\x68\x32\x2d\x31\x36\x05\x68\x32\x2d\x31\x35\x05\x68\x32\ + \x2d\x31\x34\x08\x73\x70\x64\x79\x2f\x33\x2e\x31\x06\x73\x70\x64\ + \x79\x2f\x33\x08\x68\x74\x74\x70\x2f\x31\x2e\x31\x00\x0b\x00\x02\ + \x01\x00\x00\x0a\x00\x0a\x00\x08\x00\x1d\x00\x17\x00\x18\x00\x19"; + let mut rd = Reader::init(bytes); + let m = OpaqueMessage::read(&mut rd).unwrap(); + println!("m = {:?}", m); + assert!(Message::try_from(m.into_plain_message()).is_err()); +} + +#[test] +fn alert_is_not_handshake() { + let m = Message::build_alert(AlertLevel::Fatal, AlertDescription::DecodeError); + assert!(!m.is_handshake_type(HandshakeType::ClientHello)); +} + +#[test] +fn alert_is_not_opaque() { + let m = Message::build_alert(AlertLevel::Fatal, AlertDescription::DecodeError); + assert!(Message::try_from(m).is_ok()); +} + +#[test] +fn construct_all_types() { + let samples = [ + &b"\x14\x03\x04\x00\x01\x01"[..], + &b"\x15\x03\x04\x00\x02\x01\x16"[..], + &b"\x16\x03\x04\x00\x05\x18\x00\x00\x01\x00"[..], + &b"\x17\x03\x04\x00\x04\x11\x22\x33\x44"[..], + &b"\x18\x03\x04\x00\x04\x11\x22\x33\x44"[..], + ]; + for &bytes in samples.iter() { + let m = OpaqueMessage::read(&mut Reader::init(bytes)).unwrap(); + println!("m = {:?}", m); + let m = Message::try_from(m.into_plain_message()); + println!("m' = {:?}", m); + } +} + +#[test] +fn debug_payload() { + assert_eq!("01020304", format!("{:?}", Payload(vec![1, 2, 3, 4]))); + assert_eq!("01020304", format!("{:?}", PayloadU8(vec![1, 2, 3, 4]))); + assert_eq!("01020304", format!("{:?}", PayloadU16(vec![1, 2, 3, 4]))); + assert_eq!("01020304", format!("{:?}", PayloadU24(vec![1, 2, 3, 4]))); +} diff --git a/vendor/rustls-0.21.8/src/msgs/mod.rs b/vendor/rustls-0.21.8/src/msgs/mod.rs new file mode 100644 index 0000000000000..f6411f60684c7 --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/mod.rs @@ -0,0 +1,42 @@ +#![allow(clippy::upper_case_acronyms)] +#![allow(missing_docs)] + +#[macro_use] +mod macros; + +pub mod alert; +pub mod base; +pub mod ccs; +pub mod codec; +pub mod deframer; +pub mod enums; +pub mod fragmenter; +pub mod handshake; +pub mod message; +pub mod persist; + +#[cfg(test)] +mod handshake_test; + +#[cfg(test)] +mod message_test; + +#[cfg(test)] +mod test { + #[test] + fn smoketest() { + use super::codec::Reader; + use super::message::{Message, OpaqueMessage}; + let bytes = include_bytes!("handshake-test.1.bin"); + let mut r = Reader::init(bytes); + + while r.any_left() { + let m = OpaqueMessage::read(&mut r).unwrap(); + + let out = m.clone().encode(); + assert!(!out.is_empty()); + + Message::try_from(m.into_plain_message()).unwrap(); + } + } +} diff --git a/vendor/rustls-0.21.8/src/msgs/persist.rs b/vendor/rustls-0.21.8/src/msgs/persist.rs new file mode 100644 index 0000000000000..1ca73820e73f2 --- /dev/null +++ b/vendor/rustls-0.21.8/src/msgs/persist.rs @@ -0,0 +1,449 @@ +use crate::dns_name::DnsName; +use crate::enums::{CipherSuite, ProtocolVersion}; +use crate::error::InvalidMessage; +use crate::key; +use crate::msgs::base::{PayloadU16, PayloadU8}; +use crate::msgs::codec::{Codec, Reader}; +use crate::msgs::handshake::CertificatePayload; +use crate::msgs::handshake::SessionId; +use crate::ticketer::TimeBase; +#[cfg(feature = "tls12")] +use crate::tls12::Tls12CipherSuite; +use crate::tls13::Tls13CipherSuite; + +use std::cmp; +#[cfg(feature = "tls12")] +use std::mem; + +pub struct Retrieved { + pub value: T, + retrieved_at: TimeBase, +} + +impl Retrieved { + pub fn new(value: T, retrieved_at: TimeBase) -> Self { + Self { + value, + retrieved_at, + } + } + + pub fn map(&self, f: impl FnOnce(&T) -> Option<&M>) -> Option> { + Some(Retrieved { + value: f(&self.value)?, + retrieved_at: self.retrieved_at, + }) + } +} + +impl Retrieved<&Tls13ClientSessionValue> { + pub fn obfuscated_ticket_age(&self) -> u32 { + let age_secs = self + .retrieved_at + .as_secs() + .saturating_sub(self.value.common.epoch); + let age_millis = age_secs as u32 * 1000; + age_millis.wrapping_add(self.value.age_add) + } +} + +impl> Retrieved { + pub fn has_expired(&self) -> bool { + let common = &*self.value; + common.lifetime_secs != 0 + && common + .epoch + .saturating_add(u64::from(common.lifetime_secs)) + < self.retrieved_at.as_secs() + } +} + +impl std::ops::Deref for Retrieved { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +#[derive(Debug)] +pub struct Tls13ClientSessionValue { + suite: &'static Tls13CipherSuite, + age_add: u32, + max_early_data_size: u32, + pub(crate) common: ClientSessionCommon, + #[cfg(feature = "quic")] + quic_params: PayloadU16, +} + +impl Tls13ClientSessionValue { + pub(crate) fn new( + suite: &'static Tls13CipherSuite, + ticket: Vec, + secret: Vec, + server_cert_chain: Vec, + time_now: TimeBase, + lifetime_secs: u32, + age_add: u32, + max_early_data_size: u32, + ) -> Self { + Self { + suite, + age_add, + max_early_data_size, + common: ClientSessionCommon::new( + ticket, + secret, + time_now, + lifetime_secs, + server_cert_chain, + ), + #[cfg(feature = "quic")] + quic_params: PayloadU16(Vec::new()), + } + } + + pub fn max_early_data_size(&self) -> u32 { + self.max_early_data_size + } + + pub fn suite(&self) -> &'static Tls13CipherSuite { + self.suite + } + + #[doc(hidden)] + /// Test only: rewind epoch by `delta` seconds. + pub fn rewind_epoch(&mut self, delta: u32) { + self.common.epoch -= delta as u64; + } + + #[cfg(feature = "quic")] + pub fn set_quic_params(&mut self, quic_params: &[u8]) { + self.quic_params = PayloadU16(quic_params.to_vec()); + } + + #[cfg(feature = "quic")] + pub fn quic_params(&self) -> Vec { + self.quic_params.0.clone() + } +} + +impl std::ops::Deref for Tls13ClientSessionValue { + type Target = ClientSessionCommon; + + fn deref(&self) -> &Self::Target { + &self.common + } +} + +#[derive(Debug, Clone)] +pub struct Tls12ClientSessionValue { + #[cfg(feature = "tls12")] + suite: &'static Tls12CipherSuite, + #[cfg(feature = "tls12")] + pub(crate) session_id: SessionId, + #[cfg(feature = "tls12")] + extended_ms: bool, + #[doc(hidden)] + #[cfg(feature = "tls12")] + pub(crate) common: ClientSessionCommon, +} + +#[cfg(feature = "tls12")] +impl Tls12ClientSessionValue { + pub(crate) fn new( + suite: &'static Tls12CipherSuite, + session_id: SessionId, + ticket: Vec, + master_secret: Vec, + server_cert_chain: Vec, + time_now: TimeBase, + lifetime_secs: u32, + extended_ms: bool, + ) -> Self { + Self { + suite, + session_id, + extended_ms, + common: ClientSessionCommon::new( + ticket, + master_secret, + time_now, + lifetime_secs, + server_cert_chain, + ), + } + } + + pub(crate) fn take_ticket(&mut self) -> Vec { + mem::take(&mut self.common.ticket.0) + } + + pub(crate) fn extended_ms(&self) -> bool { + self.extended_ms + } + + pub(crate) fn suite(&self) -> &'static Tls12CipherSuite { + self.suite + } + + #[doc(hidden)] + /// Test only: rewind epoch by `delta` seconds. + pub fn rewind_epoch(&mut self, delta: u32) { + self.common.epoch -= delta as u64; + } +} + +#[cfg(feature = "tls12")] +impl std::ops::Deref for Tls12ClientSessionValue { + type Target = ClientSessionCommon; + + fn deref(&self) -> &Self::Target { + &self.common + } +} + +#[derive(Debug, Clone)] +pub struct ClientSessionCommon { + ticket: PayloadU16, + secret: PayloadU8, + epoch: u64, + lifetime_secs: u32, + server_cert_chain: CertificatePayload, +} + +impl ClientSessionCommon { + fn new( + ticket: Vec, + secret: Vec, + time_now: TimeBase, + lifetime_secs: u32, + server_cert_chain: Vec, + ) -> Self { + Self { + ticket: PayloadU16(ticket), + secret: PayloadU8(secret), + epoch: time_now.as_secs(), + lifetime_secs: cmp::min(lifetime_secs, MAX_TICKET_LIFETIME), + server_cert_chain, + } + } + + pub(crate) fn server_cert_chain(&self) -> &[key::Certificate] { + self.server_cert_chain.as_ref() + } + + pub(crate) fn secret(&self) -> &[u8] { + self.secret.0.as_ref() + } + + pub(crate) fn ticket(&self) -> &[u8] { + self.ticket.0.as_ref() + } +} + +static MAX_TICKET_LIFETIME: u32 = 7 * 24 * 60 * 60; + +/// This is the maximum allowed skew between server and client clocks, over +/// the maximum ticket lifetime period. This encompasses TCP retransmission +/// times in case packet loss occurs when the client sends the ClientHello +/// or receives the NewSessionTicket, _and_ actual clock skew over this period. +static MAX_FRESHNESS_SKEW_MS: u32 = 60 * 1000; + +// --- Server types --- +pub type ServerSessionKey = SessionId; + +#[derive(Debug)] +pub struct ServerSessionValue { + pub sni: Option, + pub version: ProtocolVersion, + pub cipher_suite: CipherSuite, + pub master_secret: PayloadU8, + pub extended_ms: bool, + pub client_cert_chain: Option, + pub alpn: Option, + pub application_data: PayloadU16, + pub creation_time_sec: u64, + pub age_obfuscation_offset: u32, + freshness: Option, +} + +impl Codec for ServerSessionValue { + fn encode(&self, bytes: &mut Vec) { + if let Some(ref sni) = self.sni { + 1u8.encode(bytes); + let sni_bytes: &str = sni.as_ref(); + PayloadU8::new(Vec::from(sni_bytes)).encode(bytes); + } else { + 0u8.encode(bytes); + } + self.version.encode(bytes); + self.cipher_suite.encode(bytes); + self.master_secret.encode(bytes); + (u8::from(self.extended_ms)).encode(bytes); + if let Some(ref chain) = self.client_cert_chain { + 1u8.encode(bytes); + chain.encode(bytes); + } else { + 0u8.encode(bytes); + } + if let Some(ref alpn) = self.alpn { + 1u8.encode(bytes); + alpn.encode(bytes); + } else { + 0u8.encode(bytes); + } + self.application_data.encode(bytes); + self.creation_time_sec.encode(bytes); + self.age_obfuscation_offset + .encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let has_sni = u8::read(r)?; + let sni = if has_sni == 1 { + let dns_name = PayloadU8::read(r)?; + let dns_name = match DnsName::try_from_ascii(&dns_name.0) { + Ok(dns_name) => dns_name, + Err(_) => return Err(InvalidMessage::InvalidServerName), + }; + + Some(dns_name) + } else { + None + }; + + let v = ProtocolVersion::read(r)?; + let cs = CipherSuite::read(r)?; + let ms = PayloadU8::read(r)?; + let ems = u8::read(r)?; + let has_ccert = u8::read(r)? == 1; + let ccert = if has_ccert { + Some(CertificatePayload::read(r)?) + } else { + None + }; + let has_alpn = u8::read(r)? == 1; + let alpn = if has_alpn { + Some(PayloadU8::read(r)?) + } else { + None + }; + let application_data = PayloadU16::read(r)?; + let creation_time_sec = u64::read(r)?; + let age_obfuscation_offset = u32::read(r)?; + + Ok(Self { + sni, + version: v, + cipher_suite: cs, + master_secret: ms, + extended_ms: ems == 1u8, + client_cert_chain: ccert, + alpn, + application_data, + creation_time_sec, + age_obfuscation_offset, + freshness: None, + }) + } +} + +impl ServerSessionValue { + pub fn new( + sni: Option<&DnsName>, + v: ProtocolVersion, + cs: CipherSuite, + ms: Vec, + client_cert_chain: Option, + alpn: Option>, + application_data: Vec, + creation_time: TimeBase, + age_obfuscation_offset: u32, + ) -> Self { + Self { + sni: sni.cloned(), + version: v, + cipher_suite: cs, + master_secret: PayloadU8::new(ms), + extended_ms: false, + client_cert_chain, + alpn: alpn.map(PayloadU8::new), + application_data: PayloadU16::new(application_data), + creation_time_sec: creation_time.as_secs(), + age_obfuscation_offset, + freshness: None, + } + } + + pub fn set_extended_ms_used(&mut self) { + self.extended_ms = true; + } + + pub fn set_freshness(mut self, obfuscated_client_age_ms: u32, time_now: TimeBase) -> Self { + let client_age_ms = obfuscated_client_age_ms.wrapping_sub(self.age_obfuscation_offset); + let server_age_ms = (time_now + .as_secs() + .saturating_sub(self.creation_time_sec) as u32) + .saturating_mul(1000); + + let age_difference = if client_age_ms < server_age_ms { + server_age_ms - client_age_ms + } else { + client_age_ms - server_age_ms + }; + + self.freshness = Some(age_difference <= MAX_FRESHNESS_SKEW_MS); + self + } + + pub fn is_fresh(&self) -> bool { + self.freshness.unwrap_or_default() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::enums::*; + use crate::msgs::codec::{Codec, Reader}; + use crate::ticketer::TimeBase; + + #[test] + fn serversessionvalue_is_debug() { + let ssv = ServerSessionValue::new( + None, + ProtocolVersion::TLSv1_3, + CipherSuite::TLS13_AES_128_GCM_SHA256, + vec![1, 2, 3], + None, + None, + vec![4, 5, 6], + TimeBase::now().unwrap(), + 0x12345678, + ); + println!("{:?}", ssv); + } + + #[test] + fn serversessionvalue_no_sni() { + let bytes = [ + 0x00, 0x03, 0x03, 0xc0, 0x23, 0x03, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0xfe, 0xed, 0xf0, 0x0d, + ]; + let mut rd = Reader::init(&bytes); + let ssv = ServerSessionValue::read(&mut rd).unwrap(); + assert_eq!(ssv.get_encoding(), bytes); + } + + #[test] + fn serversessionvalue_with_cert() { + let bytes = [ + 0x00, 0x03, 0x03, 0xc0, 0x23, 0x03, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0xfe, 0xed, 0xf0, 0x0d, + ]; + let mut rd = Reader::init(&bytes); + let ssv = ServerSessionValue::read(&mut rd).unwrap(); + assert_eq!(ssv.get_encoding(), bytes); + } +} diff --git a/vendor/rustls-0.21.8/src/quic.rs b/vendor/rustls-0.21.8/src/quic.rs new file mode 100644 index 0000000000000..1c893bb86521a --- /dev/null +++ b/vendor/rustls-0.21.8/src/quic.rs @@ -0,0 +1,1093 @@ +/// This module contains optional APIs for implementing QUIC TLS. +use crate::cipher::{Iv, IvLen}; +use crate::client::{ClientConfig, ClientConnectionData, ServerName}; +use crate::common_state::{CommonState, Protocol, Side}; +use crate::conn::{ConnectionCore, SideData}; +use crate::enums::{AlertDescription, ProtocolVersion}; +use crate::error::Error; +use crate::msgs::handshake::{ClientExtension, ServerExtension}; +use crate::server::{ServerConfig, ServerConnectionData}; +use crate::suites::BulkAlgorithm; +use crate::tls13::key_schedule::hkdf_expand; +use crate::tls13::{Tls13CipherSuite, TLS13_AES_128_GCM_SHA256_INTERNAL}; + +use ring::{aead, hkdf}; + +use std::collections::VecDeque; +use std::fmt::{self, Debug}; +use std::ops::{Deref, DerefMut}; +use std::sync::Arc; + +/// A QUIC client or server connection. +#[derive(Debug)] +pub enum Connection { + /// A client connection + Client(ClientConnection), + /// A server connection + Server(ServerConnection), +} + +impl Connection { + /// Return the TLS-encoded transport parameters for the session's peer. + /// + /// See [`ConnectionCommon::quic_transport_parameters()`] for more details. + pub fn quic_transport_parameters(&self) -> Option<&[u8]> { + match self { + Self::Client(conn) => conn.quic_transport_parameters(), + Self::Server(conn) => conn.quic_transport_parameters(), + } + } + + /// Compute the keys for encrypting/decrypting 0-RTT packets, if available + pub fn zero_rtt_keys(&self) -> Option { + match self { + Self::Client(conn) => conn.zero_rtt_keys(), + Self::Server(conn) => conn.zero_rtt_keys(), + } + } + + /// Consume unencrypted TLS handshake data. + /// + /// Handshake data obtained from separate encryption levels should be supplied in separate calls. + pub fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> { + match self { + Self::Client(conn) => conn.read_hs(plaintext), + Self::Server(conn) => conn.read_hs(plaintext), + } + } + + /// Emit unencrypted TLS handshake data. + /// + /// When this returns `Some(_)`, the new keys must be used for future handshake data. + pub fn write_hs(&mut self, buf: &mut Vec) -> Option { + match self { + Self::Client(conn) => conn.write_hs(buf), + Self::Server(conn) => conn.write_hs(buf), + } + } + + /// Emit the TLS description code of a fatal alert, if one has arisen. + /// + /// Check after `read_hs` returns `Err(_)`. + pub fn alert(&self) -> Option { + match self { + Self::Client(conn) => conn.alert(), + Self::Server(conn) => conn.alert(), + } + } + + /// Derives key material from the agreed connection secrets. + /// + /// This function fills in `output` with `output.len()` bytes of key + /// material derived from the master session secret using `label` + /// and `context` for diversification. Ownership of the buffer is taken + /// by the function and returned via the Ok result to ensure no key + /// material leaks if the function fails. + /// + /// See RFC5705 for more details on what this does and is for. + /// + /// For TLS1.3 connections, this function does not use the + /// "early" exporter at any point. + /// + /// This function fails if called prior to the handshake completing; + /// check with [`CommonState::is_handshaking`] first. + #[inline] + pub fn export_keying_material>( + &self, + output: T, + label: &[u8], + context: Option<&[u8]>, + ) -> Result { + match self { + Self::Client(conn) => conn + .core + .export_keying_material(output, label, context), + Self::Server(conn) => conn + .core + .export_keying_material(output, label, context), + } + } +} + +impl Deref for Connection { + type Target = CommonState; + + fn deref(&self) -> &Self::Target { + match self { + Self::Client(conn) => &conn.core.common_state, + Self::Server(conn) => &conn.core.common_state, + } + } +} + +impl DerefMut for Connection { + fn deref_mut(&mut self) -> &mut Self::Target { + match self { + Self::Client(conn) => &mut conn.core.common_state, + Self::Server(conn) => &mut conn.core.common_state, + } + } +} + +/// A QUIC client connection. +pub struct ClientConnection { + inner: ConnectionCommon, +} + +impl ClientConnection { + /// Make a new QUIC ClientConnection. This differs from `ClientConnection::new()` + /// in that it takes an extra argument, `params`, which contains the + /// TLS-encoded transport parameters to send. + pub fn new( + config: Arc, + quic_version: Version, + name: ServerName, + params: Vec, + ) -> Result { + if !config.supports_version(ProtocolVersion::TLSv1_3) { + return Err(Error::General( + "TLS 1.3 support is required for QUIC".into(), + )); + } + + let ext = match quic_version { + Version::V1Draft => ClientExtension::TransportParametersDraft(params), + Version::V1 | Version::V2 => ClientExtension::TransportParameters(params), + }; + + let mut inner = ConnectionCore::for_client(config, name, vec![ext], Protocol::Quic)?; + inner.common_state.quic.version = quic_version; + Ok(Self { + inner: inner.into(), + }) + } + + /// Returns True if the server signalled it will process early data. + /// + /// If you sent early data and this returns false at the end of the + /// handshake then the server will not process the data. This + /// is not an error, but you may wish to resend the data. + pub fn is_early_data_accepted(&self) -> bool { + self.inner.core.is_early_data_accepted() + } +} + +impl Deref for ClientConnection { + type Target = ConnectionCommon; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for ClientConnection { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl Debug for ClientConnection { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("quic::ClientConnection") + .finish() + } +} + +impl From for Connection { + fn from(c: ClientConnection) -> Self { + Self::Client(c) + } +} + +/// A QUIC server connection. +pub struct ServerConnection { + inner: ConnectionCommon, +} + +impl ServerConnection { + /// Make a new QUIC ServerConnection. This differs from `ServerConnection::new()` + /// in that it takes an extra argument, `params`, which contains the + /// TLS-encoded transport parameters to send. + pub fn new( + config: Arc, + quic_version: Version, + params: Vec, + ) -> Result { + if !config.supports_version(ProtocolVersion::TLSv1_3) { + return Err(Error::General( + "TLS 1.3 support is required for QUIC".into(), + )); + } + + if config.max_early_data_size != 0 && config.max_early_data_size != 0xffff_ffff { + return Err(Error::General( + "QUIC sessions must set a max early data of 0 or 2^32-1".into(), + )); + } + + let ext = match quic_version { + Version::V1Draft => ServerExtension::TransportParametersDraft(params), + Version::V1 | Version::V2 => ServerExtension::TransportParameters(params), + }; + + let mut core = ConnectionCore::for_server(config, vec![ext])?; + core.common_state.protocol = Protocol::Quic; + core.common_state.quic.version = quic_version; + Ok(Self { inner: core.into() }) + } + + /// Explicitly discard early data, notifying the client + /// + /// Useful if invariants encoded in `received_resumption_data()` cannot be respected. + /// + /// Must be called while `is_handshaking` is true. + pub fn reject_early_data(&mut self) { + self.inner.core.reject_early_data() + } + + /// Retrieves the server name, if any, used to select the certificate and + /// private key. + /// + /// This returns `None` until some time after the client's server name indication + /// (SNI) extension value is processed during the handshake. It will never be + /// `None` when the connection is ready to send or process application data, + /// unless the client does not support SNI. + /// + /// This is useful for application protocols that need to enforce that the + /// server name matches an application layer protocol hostname. For + /// example, HTTP/1.1 servers commonly expect the `Host:` header field of + /// every request on a connection to match the hostname in the SNI extension + /// when the client provides the SNI extension. + /// + /// The server name is also used to match sessions during session resumption. + pub fn server_name(&self) -> Option<&str> { + self.inner.core.get_sni_str() + } +} + +impl Deref for ServerConnection { + type Target = ConnectionCommon; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for ServerConnection { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl Debug for ServerConnection { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("quic::ServerConnection") + .finish() + } +} + +impl From for Connection { + fn from(c: ServerConnection) -> Self { + Self::Server(c) + } +} + +/// A shared interface for QUIC connections. +pub struct ConnectionCommon { + core: ConnectionCore, +} + +impl ConnectionCommon { + /// Return the TLS-encoded transport parameters for the session's peer. + /// + /// While the transport parameters are technically available prior to the + /// completion of the handshake, they cannot be fully trusted until the + /// handshake completes, and reliance on them should be minimized. + /// However, any tampering with the parameters will cause the handshake + /// to fail. + pub fn quic_transport_parameters(&self) -> Option<&[u8]> { + self.core + .common_state + .quic + .params + .as_ref() + .map(|v| v.as_ref()) + } + + /// Compute the keys for encrypting/decrypting 0-RTT packets, if available + pub fn zero_rtt_keys(&self) -> Option { + Some(DirectionalKeys::new( + self.core + .common_state + .suite + .and_then(|suite| suite.tls13())?, + self.core + .common_state + .quic + .early_secret + .as_ref()?, + self.core.common_state.quic.version, + )) + } + + /// Consume unencrypted TLS handshake data. + /// + /// Handshake data obtained from separate encryption levels should be supplied in separate calls. + pub fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> { + self.core + .message_deframer + .push(ProtocolVersion::TLSv1_3, plaintext)?; + self.core.process_new_packets()?; + Ok(()) + } + + /// Emit unencrypted TLS handshake data. + /// + /// When this returns `Some(_)`, the new keys must be used for future handshake data. + pub fn write_hs(&mut self, buf: &mut Vec) -> Option { + self.core + .common_state + .quic + .write_hs(buf) + } + + /// Emit the TLS description code of a fatal alert, if one has arisen. + /// + /// Check after `read_hs` returns `Err(_)`. + pub fn alert(&self) -> Option { + self.core.common_state.quic.alert + } +} + +impl Deref for ConnectionCommon { + type Target = CommonState; + + fn deref(&self) -> &Self::Target { + &self.core.common_state + } +} + +impl DerefMut for ConnectionCommon { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.core.common_state + } +} + +impl From> for ConnectionCommon { + fn from(core: ConnectionCore) -> Self { + Self { core } + } +} + +#[cfg(feature = "quic")] +#[derive(Default)] +pub(crate) struct Quic { + /// QUIC transport parameters received from the peer during the handshake + pub(crate) params: Option>, + pub(crate) alert: Option, + pub(crate) hs_queue: VecDeque<(bool, Vec)>, + pub(crate) early_secret: Option, + pub(crate) hs_secrets: Option, + pub(crate) traffic_secrets: Option, + /// Whether keys derived from traffic_secrets have been passed to the QUIC implementation + pub(crate) returned_traffic_keys: bool, + pub(crate) version: Version, +} + +impl Quic { + pub(crate) fn write_hs(&mut self, buf: &mut Vec) -> Option { + while let Some((_, msg)) = self.hs_queue.pop_front() { + buf.extend_from_slice(&msg); + if let Some(&(true, _)) = self.hs_queue.front() { + if self.hs_secrets.is_some() { + // Allow the caller to switch keys before proceeding. + break; + } + } + } + + if let Some(secrets) = self.hs_secrets.take() { + return Some(KeyChange::Handshake { + keys: Keys::new(&secrets), + }); + } + + if let Some(mut secrets) = self.traffic_secrets.take() { + if !self.returned_traffic_keys { + self.returned_traffic_keys = true; + let keys = Keys::new(&secrets); + secrets.update(); + return Some(KeyChange::OneRtt { + keys, + next: secrets, + }); + } + } + + None + } +} + +/// Secrets used to encrypt/decrypt traffic +#[derive(Clone, Debug)] +pub struct Secrets { + /// Secret used to encrypt packets transmitted by the client + client: hkdf::Prk, + /// Secret used to encrypt packets transmitted by the server + server: hkdf::Prk, + /// Cipher suite used with these secrets + suite: &'static Tls13CipherSuite, + side: Side, + version: Version, +} + +impl Secrets { + pub(crate) fn new( + client: hkdf::Prk, + server: hkdf::Prk, + suite: &'static Tls13CipherSuite, + side: Side, + version: Version, + ) -> Self { + Self { + client, + server, + suite, + side, + version, + } + } + + /// Derive the next set of packet keys + pub fn next_packet_keys(&mut self) -> PacketKeySet { + let keys = PacketKeySet::new(self); + self.update(); + keys + } + + fn update(&mut self) { + let hkdf_alg = self.suite.hkdf_algorithm; + self.client = hkdf_expand(&self.client, hkdf_alg, self.version.key_update_label(), &[]); + self.server = hkdf_expand(&self.server, hkdf_alg, self.version.key_update_label(), &[]); + } + + fn local_remote(&self) -> (&hkdf::Prk, &hkdf::Prk) { + match self.side { + Side::Client => (&self.client, &self.server), + Side::Server => (&self.server, &self.client), + } + } +} + +/// Keys used to communicate in a single direction +pub struct DirectionalKeys { + /// Encrypts or decrypts a packet's headers + pub header: HeaderProtectionKey, + /// Encrypts or decrypts the payload of a packet + pub packet: PacketKey, +} + +impl DirectionalKeys { + pub(crate) fn new( + suite: &'static Tls13CipherSuite, + secret: &hkdf::Prk, + version: Version, + ) -> Self { + Self { + header: HeaderProtectionKey::new(suite, secret, version), + packet: PacketKey::new(suite, secret, version), + } + } +} + +/// A QUIC header protection key +pub struct HeaderProtectionKey(aead::quic::HeaderProtectionKey); + +impl HeaderProtectionKey { + fn new(suite: &'static Tls13CipherSuite, secret: &hkdf::Prk, version: Version) -> Self { + let alg = match suite.common.bulk { + BulkAlgorithm::Aes128Gcm => &aead::quic::AES_128, + BulkAlgorithm::Aes256Gcm => &aead::quic::AES_256, + BulkAlgorithm::Chacha20Poly1305 => &aead::quic::CHACHA20, + }; + + Self(hkdf_expand(secret, alg, version.header_key_label(), &[])) + } + + /// Adds QUIC Header Protection. + /// + /// `sample` must contain the sample of encrypted payload; see + /// [Header Protection Sample]. + /// + /// `first` must reference the first byte of the header, referred to as + /// `packet[0]` in [Header Protection Application]. + /// + /// `packet_number` must reference the Packet Number field; this is + /// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application]. + /// + /// Returns an error without modifying anything if `sample` is not + /// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]), + /// or `packet_number` is longer than allowed (see [Packet Number Encoding and Decoding]). + /// + /// Otherwise, `first` and `packet_number` will have the header protection added. + /// + /// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1 + /// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2 + /// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1 + #[inline] + pub fn encrypt_in_place( + &self, + sample: &[u8], + first: &mut u8, + packet_number: &mut [u8], + ) -> Result<(), Error> { + self.xor_in_place(sample, first, packet_number, false) + } + + /// Removes QUIC Header Protection. + /// + /// `sample` must contain the sample of encrypted payload; see + /// [Header Protection Sample]. + /// + /// `first` must reference the first byte of the header, referred to as + /// `packet[0]` in [Header Protection Application]. + /// + /// `packet_number` must reference the Packet Number field; this is + /// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application]. + /// + /// Returns an error without modifying anything if `sample` is not + /// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]), + /// or `packet_number` is longer than allowed (see + /// [Packet Number Encoding and Decoding]). + /// + /// Otherwise, `first` and `packet_number` will have the header protection removed. + /// + /// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1 + /// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2 + /// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1 + #[inline] + pub fn decrypt_in_place( + &self, + sample: &[u8], + first: &mut u8, + packet_number: &mut [u8], + ) -> Result<(), Error> { + self.xor_in_place(sample, first, packet_number, true) + } + + fn xor_in_place( + &self, + sample: &[u8], + first: &mut u8, + packet_number: &mut [u8], + masked: bool, + ) -> Result<(), Error> { + // This implements [Header Protection Application] almost verbatim. + + let mask = self + .0 + .new_mask(sample) + .map_err(|_| Error::General("sample of invalid length".into()))?; + + // The `unwrap()` will not panic because `new_mask` returns a + // non-empty result. + let (first_mask, pn_mask) = mask.split_first().unwrap(); + + // It is OK for the `mask` to be longer than `packet_number`, + // but a valid `packet_number` will never be longer than `mask`. + if packet_number.len() > pn_mask.len() { + return Err(Error::General("packet number too long".into())); + } + + // Infallible from this point on. Before this point, `first` and + // `packet_number` are unchanged. + + const LONG_HEADER_FORM: u8 = 0x80; + let bits = match *first & LONG_HEADER_FORM == LONG_HEADER_FORM { + true => 0x0f, // Long header: 4 bits masked + false => 0x1f, // Short header: 5 bits masked + }; + + let first_plain = match masked { + // When unmasking, use the packet length bits after unmasking + true => *first ^ (first_mask & bits), + // When masking, use the packet length bits before masking + false => *first, + }; + let pn_len = (first_plain & 0x03) as usize + 1; + + *first ^= first_mask & bits; + for (dst, m) in packet_number + .iter_mut() + .zip(pn_mask) + .take(pn_len) + { + *dst ^= m; + } + + Ok(()) + } + + /// Expected sample length for the key's algorithm + #[inline] + pub fn sample_len(&self) -> usize { + self.0.algorithm().sample_len() + } +} + +/// Keys to encrypt or decrypt the payload of a packet +pub struct PacketKey { + /// Encrypts or decrypts a packet's payload + key: aead::LessSafeKey, + /// Computes unique nonces for each packet + iv: Iv, + /// The cipher suite used for this packet key + suite: &'static Tls13CipherSuite, +} + +impl PacketKey { + fn new(suite: &'static Tls13CipherSuite, secret: &hkdf::Prk, version: Version) -> Self { + Self { + key: aead::LessSafeKey::new(hkdf_expand( + secret, + suite.common.aead_algorithm, + version.packet_key_label(), + &[], + )), + iv: hkdf_expand(secret, IvLen, version.packet_iv_label(), &[]), + suite, + } + } + + /// Encrypt a QUIC packet + /// + /// Takes a `packet_number`, used to derive the nonce; the packet `header`, which is used as + /// the additional authenticated data; and the `payload`. The authentication tag is returned if + /// encryption succeeds. + /// + /// Fails iff the payload is longer than allowed by the cipher suite's AEAD algorithm. + pub fn encrypt_in_place( + &self, + packet_number: u64, + header: &[u8], + payload: &mut [u8], + ) -> Result { + let aad = aead::Aad::from(header); + let nonce = nonce_for(packet_number, &self.iv); + let tag = self + .key + .seal_in_place_separate_tag(nonce, aad, payload) + .map_err(|_| Error::EncryptError)?; + Ok(Tag(tag)) + } + + /// Decrypt a QUIC packet + /// + /// Takes the packet `header`, which is used as the additional authenticated data, and the + /// `payload`, which includes the authentication tag. + /// + /// If the return value is `Ok`, the decrypted payload can be found in `payload`, up to the + /// length found in the return value. + pub fn decrypt_in_place<'a>( + &self, + packet_number: u64, + header: &[u8], + payload: &'a mut [u8], + ) -> Result<&'a [u8], Error> { + let payload_len = payload.len(); + let aad = aead::Aad::from(header); + let nonce = nonce_for(packet_number, &self.iv); + self.key + .open_in_place(nonce, aad, payload) + .map_err(|_| Error::DecryptError)?; + + let plain_len = payload_len - self.key.algorithm().tag_len(); + Ok(&payload[..plain_len]) + } + + /// Number of times the packet key can be used without sacrificing confidentiality + /// + /// See . + #[inline] + pub fn confidentiality_limit(&self) -> u64 { + self.suite.confidentiality_limit + } + + /// Number of times the packet key can be used without sacrificing integrity + /// + /// See . + #[inline] + pub fn integrity_limit(&self) -> u64 { + self.suite.integrity_limit + } + + /// Tag length for the underlying AEAD algorithm + #[inline] + pub fn tag_len(&self) -> usize { + self.key.algorithm().tag_len() + } +} + +/// AEAD tag, must be appended to encrypted cipher text +pub struct Tag(aead::Tag); + +impl AsRef<[u8]> for Tag { + #[inline] + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +/// Packet protection keys for bidirectional 1-RTT communication +pub struct PacketKeySet { + /// Encrypts outgoing packets + pub local: PacketKey, + /// Decrypts incoming packets + pub remote: PacketKey, +} + +impl PacketKeySet { + fn new(secrets: &Secrets) -> Self { + let (local, remote) = secrets.local_remote(); + Self { + local: PacketKey::new(secrets.suite, local, secrets.version), + remote: PacketKey::new(secrets.suite, remote, secrets.version), + } + } +} + +/// Complete set of keys used to communicate with the peer +pub struct Keys { + /// Encrypts outgoing packets + pub local: DirectionalKeys, + /// Decrypts incoming packets + pub remote: DirectionalKeys, +} + +impl Keys { + /// Construct keys for use with initial packets + pub fn initial(version: Version, client_dst_connection_id: &[u8], side: Side) -> Self { + const CLIENT_LABEL: &[u8] = b"client in"; + const SERVER_LABEL: &[u8] = b"server in"; + let salt = version.initial_salt(); + let hs_secret = hkdf::Salt::new(hkdf::HKDF_SHA256, salt).extract(client_dst_connection_id); + + let secrets = Secrets { + version, + client: hkdf_expand(&hs_secret, hkdf::HKDF_SHA256, CLIENT_LABEL, &[]), + server: hkdf_expand(&hs_secret, hkdf::HKDF_SHA256, SERVER_LABEL, &[]), + suite: TLS13_AES_128_GCM_SHA256_INTERNAL, + side, + }; + Self::new(&secrets) + } + + fn new(secrets: &Secrets) -> Self { + let (local, remote) = secrets.local_remote(); + Self { + local: DirectionalKeys::new(secrets.suite, local, secrets.version), + remote: DirectionalKeys::new(secrets.suite, remote, secrets.version), + } + } +} + +/// Key material for use in QUIC packet spaces +/// +/// QUIC uses 4 different sets of keys (and progressive key updates for long-running connections): +/// +/// * Initial: these can be created from [`Keys::initial()`] +/// * 0-RTT keys: can be retrieved from [`ConnectionCommon::zero_rtt_keys()`] +/// * Handshake: these are returned from [`ConnectionCommon::write_hs()`] after `ClientHello` and +/// `ServerHello` messages have been exchanged +/// * 1-RTT keys: these are returned from [`ConnectionCommon::write_hs()`] after the handshake is done +/// +/// Once the 1-RTT keys have been exchanged, either side may initiate a key update. Progressive +/// update keys can be obtained from the [`Secrets`] returned in [`KeyChange::OneRtt`]. Note that +/// only packet keys are updated by key updates; header protection keys remain the same. +#[allow(clippy::large_enum_variant)] +pub enum KeyChange { + /// Keys for the handshake space + Handshake { + /// Header and packet keys for the handshake space + keys: Keys, + }, + /// Keys for 1-RTT data + OneRtt { + /// Header and packet keys for 1-RTT data + keys: Keys, + /// Secrets to derive updated keys from + next: Secrets, + }, +} + +/// Compute the nonce to use for encrypting or decrypting `packet_number` +fn nonce_for(packet_number: u64, iv: &Iv) -> ring::aead::Nonce { + let mut out = [0; aead::NONCE_LEN]; + out[4..].copy_from_slice(&packet_number.to_be_bytes()); + for (out, inp) in out.iter_mut().zip(iv.0.iter()) { + *out ^= inp; + } + aead::Nonce::assume_unique_for_key(out) +} + +/// QUIC protocol version +/// +/// Governs version-specific behavior in the TLS layer +#[non_exhaustive] +#[derive(Clone, Copy, Debug)] +pub enum Version { + /// Draft versions 29, 30, 31 and 32 + V1Draft, + /// First stable RFC + V1, + /// Anti-ossification variant of V1 + V2, +} + +impl Version { + fn initial_salt(self) -> &'static [u8; 20] { + match self { + Self::V1Draft => &[ + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-32#section-5.2 + 0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, + 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99, + ], + Self::V1 => &[ + // https://www.rfc-editor.org/rfc/rfc9001.html#name-initial-secrets + 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, + 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a, + ], + Self::V2 => &[ + // https://www.ietf.org/archive/id/draft-ietf-quic-v2-10.html#name-initial-salt-2 + 0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26, + 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9, + ], + } + } + + fn packet_key_label(&self) -> &'static [u8] { + match self { + Self::V1Draft | Self::V1 => b"quic key", + Self::V2 => b"quicv2 key", + } + } + + fn packet_iv_label(&self) -> &'static [u8] { + match self { + Self::V1Draft | Self::V1 => b"quic iv", + Self::V2 => b"quicv2 iv", + } + } + + fn header_key_label(&self) -> &'static [u8] { + match self { + Self::V1Draft | Self::V1 => b"quic hp", + Self::V2 => b"quicv2 hp", + } + } + + fn key_update_label(&self) -> &'static [u8] { + match self { + Self::V1Draft | Self::V1 => b"quic ku", + Self::V2 => b"quicv2 ku", + } + } +} + +impl Default for Version { + fn default() -> Self { + Self::V1 + } +} + +#[cfg(test)] +mod test { + use super::*; + + fn test_short_packet(version: Version, expected: &[u8]) { + const PN: u64 = 654360564; + const SECRET: &[u8] = &[ + 0x9a, 0xc3, 0x12, 0xa7, 0xf8, 0x77, 0x46, 0x8e, 0xbe, 0x69, 0x42, 0x27, 0x48, 0xad, + 0x00, 0xa1, 0x54, 0x43, 0xf1, 0x82, 0x03, 0xa0, 0x7d, 0x60, 0x60, 0xf6, 0x88, 0xf3, + 0x0f, 0x21, 0x63, 0x2b, + ]; + + let secret = hkdf::Prk::new_less_safe(hkdf::HKDF_SHA256, SECRET); + use crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL; + let hpk = + HeaderProtectionKey::new(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL, &secret, version); + let packet = PacketKey::new(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL, &secret, version); + + const PLAIN: &[u8] = &[0x42, 0x00, 0xbf, 0xf4, 0x01]; + + let mut buf = PLAIN.to_vec(); + let (header, payload) = buf.split_at_mut(4); + let tag = packet + .encrypt_in_place(PN, &*header, payload) + .unwrap(); + buf.extend(tag.as_ref()); + + let pn_offset = 1; + let (header, sample) = buf.split_at_mut(pn_offset + 4); + let (first, rest) = header.split_at_mut(1); + let sample = &sample[..hpk.sample_len()]; + hpk.encrypt_in_place(sample, &mut first[0], dbg!(rest)) + .unwrap(); + + assert_eq!(&buf, expected); + + let (header, sample) = buf.split_at_mut(pn_offset + 4); + let (first, rest) = header.split_at_mut(1); + let sample = &sample[..hpk.sample_len()]; + hpk.decrypt_in_place(sample, &mut first[0], rest) + .unwrap(); + + let (header, payload_tag) = buf.split_at_mut(4); + let plain = packet + .decrypt_in_place(PN, &*header, payload_tag) + .unwrap(); + + assert_eq!(plain, &PLAIN[4..]); + } + + #[test] + fn short_packet_header_protection() { + // https://www.rfc-editor.org/rfc/rfc9001.html#name-chacha20-poly1305-short-hea + test_short_packet( + Version::V1, + &[ + 0x4c, 0xfe, 0x41, 0x89, 0x65, 0x5e, 0x5c, 0xd5, 0x5c, 0x41, 0xf6, 0x90, 0x80, 0x57, + 0x5d, 0x79, 0x99, 0xc2, 0x5a, 0x5b, 0xfb, + ], + ); + } + + #[test] + fn key_update_test_vector() { + fn equal_prk(x: &hkdf::Prk, y: &hkdf::Prk) -> bool { + let mut x_data = [0; 16]; + let mut y_data = [0; 16]; + let x_okm = x + .expand(&[b"info"], &aead::quic::AES_128) + .unwrap(); + x_okm.fill(&mut x_data[..]).unwrap(); + let y_okm = y + .expand(&[b"info"], &aead::quic::AES_128) + .unwrap(); + y_okm.fill(&mut y_data[..]).unwrap(); + x_data == y_data + } + + let mut secrets = Secrets { + // Constant dummy values for reproducibility + client: hkdf::Prk::new_less_safe( + hkdf::HKDF_SHA256, + &[ + 0xb8, 0x76, 0x77, 0x08, 0xf8, 0x77, 0x23, 0x58, 0xa6, 0xea, 0x9f, 0xc4, 0x3e, + 0x4a, 0xdd, 0x2c, 0x96, 0x1b, 0x3f, 0x52, 0x87, 0xa6, 0xd1, 0x46, 0x7e, 0xe0, + 0xae, 0xab, 0x33, 0x72, 0x4d, 0xbf, + ], + ), + server: hkdf::Prk::new_less_safe( + hkdf::HKDF_SHA256, + &[ + 0x42, 0xdc, 0x97, 0x21, 0x40, 0xe0, 0xf2, 0xe3, 0x98, 0x45, 0xb7, 0x67, 0x61, + 0x34, 0x39, 0xdc, 0x67, 0x58, 0xca, 0x43, 0x25, 0x9b, 0x87, 0x85, 0x06, 0x82, + 0x4e, 0xb1, 0xe4, 0x38, 0xd8, 0x55, + ], + ), + suite: TLS13_AES_128_GCM_SHA256_INTERNAL, + side: Side::Client, + version: Version::V1, + }; + secrets.update(); + + assert!(equal_prk( + &secrets.client, + &hkdf::Prk::new_less_safe( + hkdf::HKDF_SHA256, + &[ + 0x42, 0xca, 0xc8, 0xc9, 0x1c, 0xd5, 0xeb, 0x40, 0x68, 0x2e, 0x43, 0x2e, 0xdf, + 0x2d, 0x2b, 0xe9, 0xf4, 0x1a, 0x52, 0xca, 0x6b, 0x22, 0xd8, 0xe6, 0xcd, 0xb1, + 0xe8, 0xac, 0xa9, 0x6, 0x1f, 0xce + ] + ) + )); + assert!(equal_prk( + &secrets.server, + &hkdf::Prk::new_less_safe( + hkdf::HKDF_SHA256, + &[ + 0xeb, 0x7f, 0x5e, 0x2a, 0x12, 0x3f, 0x40, 0x7d, 0xb4, 0x99, 0xe3, 0x61, 0xca, + 0xe5, 0x90, 0xd4, 0xd9, 0x92, 0xe1, 0x4b, 0x7a, 0xce, 0x3, 0xc2, 0x44, 0xe0, + 0x42, 0x21, 0x15, 0xb6, 0xd3, 0x8a + ] + ) + )); + } + + #[test] + fn short_packet_header_protection_v2() { + // https://www.ietf.org/archive/id/draft-ietf-quic-v2-10.html#name-chacha20-poly1305-short-head + test_short_packet( + Version::V2, + &[ + 0x55, 0x58, 0xb1, 0xc6, 0x0a, 0xe7, 0xb6, 0xb9, 0x32, 0xbc, 0x27, 0xd7, 0x86, 0xf4, + 0xbc, 0x2b, 0xb2, 0x0f, 0x21, 0x62, 0xba, + ], + ); + } + + #[test] + fn initial_test_vector_v2() { + // https://www.ietf.org/archive/id/draft-ietf-quic-v2-10.html#name-sample-packet-protection-2 + let icid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08]; + let server = Keys::initial(Version::V2, &icid, Side::Server); + let mut server_payload = [ + 0x02, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x40, 0x5a, 0x02, 0x00, 0x00, 0x56, 0x03, + 0x03, 0xee, 0xfc, 0xe7, 0xf7, 0xb3, 0x7b, 0xa1, 0xd1, 0x63, 0x2e, 0x96, 0x67, 0x78, + 0x25, 0xdd, 0xf7, 0x39, 0x88, 0xcf, 0xc7, 0x98, 0x25, 0xdf, 0x56, 0x6d, 0xc5, 0x43, + 0x0b, 0x9a, 0x04, 0x5a, 0x12, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00, + 0x24, 0x00, 0x1d, 0x00, 0x20, 0x9d, 0x3c, 0x94, 0x0d, 0x89, 0x69, 0x0b, 0x84, 0xd0, + 0x8a, 0x60, 0x99, 0x3c, 0x14, 0x4e, 0xca, 0x68, 0x4d, 0x10, 0x81, 0x28, 0x7c, 0x83, + 0x4d, 0x53, 0x11, 0xbc, 0xf3, 0x2b, 0xb9, 0xda, 0x1a, 0x00, 0x2b, 0x00, 0x02, 0x03, + 0x04, + ]; + let mut server_header = [ + 0xd1, 0x6b, 0x33, 0x43, 0xcf, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, + 0xb5, 0x00, 0x40, 0x75, 0x00, 0x01, + ]; + let tag = server + .local + .packet + .encrypt_in_place(1, &server_header, &mut server_payload) + .unwrap(); + let (first, rest) = server_header.split_at_mut(1); + let rest_len = rest.len(); + server + .local + .header + .encrypt_in_place( + &server_payload[2..18], + &mut first[0], + &mut rest[rest_len - 2..], + ) + .unwrap(); + let mut server_packet = server_header.to_vec(); + server_packet.extend(server_payload); + server_packet.extend(tag.as_ref()); + let expected_server_packet = [ + 0xdc, 0x6b, 0x33, 0x43, 0xcf, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, + 0xb5, 0x00, 0x40, 0x75, 0xd9, 0x2f, 0xaa, 0xf1, 0x6f, 0x05, 0xd8, 0xa4, 0x39, 0x8c, + 0x47, 0x08, 0x96, 0x98, 0xba, 0xee, 0xa2, 0x6b, 0x91, 0xeb, 0x76, 0x1d, 0x9b, 0x89, + 0x23, 0x7b, 0xbf, 0x87, 0x26, 0x30, 0x17, 0x91, 0x53, 0x58, 0x23, 0x00, 0x35, 0xf7, + 0xfd, 0x39, 0x45, 0xd8, 0x89, 0x65, 0xcf, 0x17, 0xf9, 0xaf, 0x6e, 0x16, 0x88, 0x6c, + 0x61, 0xbf, 0xc7, 0x03, 0x10, 0x6f, 0xba, 0xf3, 0xcb, 0x4c, 0xfa, 0x52, 0x38, 0x2d, + 0xd1, 0x6a, 0x39, 0x3e, 0x42, 0x75, 0x75, 0x07, 0x69, 0x80, 0x75, 0xb2, 0xc9, 0x84, + 0xc7, 0x07, 0xf0, 0xa0, 0x81, 0x2d, 0x8c, 0xd5, 0xa6, 0x88, 0x1e, 0xaf, 0x21, 0xce, + 0xda, 0x98, 0xf4, 0xbd, 0x23, 0xf6, 0xfe, 0x1a, 0x3e, 0x2c, 0x43, 0xed, 0xd9, 0xce, + 0x7c, 0xa8, 0x4b, 0xed, 0x85, 0x21, 0xe2, 0xe1, 0x40, + ]; + assert_eq!(server_packet[..], expected_server_packet[..]); + } +} diff --git a/vendor/rustls-0.21.8/src/rand.rs b/vendor/rustls-0.21.8/src/rand.rs new file mode 100644 index 0000000000000..d82221002693d --- /dev/null +++ b/vendor/rustls-0.21.8/src/rand.rs @@ -0,0 +1,28 @@ +//! The single place where we generate random material for our own use. + +use ring::rand::{SecureRandom, SystemRandom}; + +/// Fill the whole slice with random material. +pub(crate) fn fill_random(bytes: &mut [u8]) -> Result<(), GetRandomFailed> { + SystemRandom::new() + .fill(bytes) + .map_err(|_| GetRandomFailed) +} + +/// Make a Vec of the given size +/// containing random material. +pub(crate) fn random_vec(len: usize) -> Result, GetRandomFailed> { + let mut v = vec![0; len]; + fill_random(&mut v)?; + Ok(v) +} + +/// Return a uniformly random u32. +pub(crate) fn random_u32() -> Result { + let mut buf = [0u8; 4]; + fill_random(&mut buf)?; + Ok(u32::from_be_bytes(buf)) +} + +#[derive(Debug)] +pub struct GetRandomFailed; diff --git a/vendor/rustls-0.21.8/src/record_layer.rs b/vendor/rustls-0.21.8/src/record_layer.rs new file mode 100644 index 0000000000000..c05a34720ccdd --- /dev/null +++ b/vendor/rustls-0.21.8/src/record_layer.rs @@ -0,0 +1,221 @@ +use crate::cipher::{MessageDecrypter, MessageEncrypter}; +use crate::error::Error; +use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage}; + +#[cfg(feature = "logging")] +use crate::log::trace; + +static SEQ_SOFT_LIMIT: u64 = 0xffff_ffff_ffff_0000u64; +static SEQ_HARD_LIMIT: u64 = 0xffff_ffff_ffff_fffeu64; + +#[derive(PartialEq)] +enum DirectionState { + /// No keying material. + Invalid, + + /// Keying material present, but not yet in use. + Prepared, + + /// Keying material in use. + Active, +} + +/// Record layer that tracks decryption and encryption keys. +pub struct RecordLayer { + message_encrypter: Box, + message_decrypter: Box, + write_seq: u64, + read_seq: u64, + encrypt_state: DirectionState, + decrypt_state: DirectionState, + + // Message encrypted with other keys may be encountered, so failures + // should be swallowed by the caller. This struct tracks the amount + // of message size this is allowed for. + trial_decryption_len: Option, +} + +impl RecordLayer { + /// Create new record layer with no keys. + pub fn new() -> Self { + Self { + message_encrypter: ::invalid(), + message_decrypter: ::invalid(), + write_seq: 0, + read_seq: 0, + encrypt_state: DirectionState::Invalid, + decrypt_state: DirectionState::Invalid, + trial_decryption_len: None, + } + } + + pub(crate) fn is_encrypting(&self) -> bool { + self.encrypt_state == DirectionState::Active + } + + #[cfg(feature = "secret_extraction")] + pub(crate) fn write_seq(&self) -> u64 { + self.write_seq + } + + #[cfg(feature = "secret_extraction")] + pub(crate) fn read_seq(&self) -> u64 { + self.read_seq + } + + fn doing_trial_decryption(&mut self, requested: usize) -> bool { + match self + .trial_decryption_len + .and_then(|value| value.checked_sub(requested)) + { + Some(remaining) => { + self.trial_decryption_len = Some(remaining); + true + } + _ => false, + } + } + + /// Prepare to use the given `MessageEncrypter` for future message encryption. + /// It is not used until you call `start_encrypting`. + pub(crate) fn prepare_message_encrypter(&mut self, cipher: Box) { + self.message_encrypter = cipher; + self.write_seq = 0; + self.encrypt_state = DirectionState::Prepared; + } + + /// Prepare to use the given `MessageDecrypter` for future message decryption. + /// It is not used until you call `start_decrypting`. + pub(crate) fn prepare_message_decrypter(&mut self, cipher: Box) { + self.message_decrypter = cipher; + self.read_seq = 0; + self.decrypt_state = DirectionState::Prepared; + } + + /// Start using the `MessageEncrypter` previously provided to the previous + /// call to `prepare_message_encrypter`. + pub(crate) fn start_encrypting(&mut self) { + debug_assert!(self.encrypt_state == DirectionState::Prepared); + self.encrypt_state = DirectionState::Active; + } + + /// Start using the `MessageDecrypter` previously provided to the previous + /// call to `prepare_message_decrypter`. + pub(crate) fn start_decrypting(&mut self) { + debug_assert!(self.decrypt_state == DirectionState::Prepared); + self.decrypt_state = DirectionState::Active; + } + + /// Set and start using the given `MessageEncrypter` for future outgoing + /// message encryption. + pub(crate) fn set_message_encrypter(&mut self, cipher: Box) { + self.prepare_message_encrypter(cipher); + self.start_encrypting(); + } + + /// Set and start using the given `MessageDecrypter` for future incoming + /// message decryption. + pub(crate) fn set_message_decrypter(&mut self, cipher: Box) { + self.prepare_message_decrypter(cipher); + self.start_decrypting(); + self.trial_decryption_len = None; + } + + /// Set and start using the given `MessageDecrypter` for future incoming + /// message decryption, and enable "trial decryption" mode for when TLS1.3 + /// 0-RTT is attempted but rejected by the server. + pub(crate) fn set_message_decrypter_with_trial_decryption( + &mut self, + cipher: Box, + max_length: usize, + ) { + self.prepare_message_decrypter(cipher); + self.start_decrypting(); + self.trial_decryption_len = Some(max_length); + } + + pub(crate) fn finish_trial_decryption(&mut self) { + self.trial_decryption_len = None; + } + + /// Return true if we are getting close to encrypting too many + /// messages with our encryption key. + pub(crate) fn wants_close_before_encrypt(&self) -> bool { + self.write_seq == SEQ_SOFT_LIMIT + } + + /// Return true if we outright refuse to do anything with the + /// encryption key. + pub(crate) fn encrypt_exhausted(&self) -> bool { + self.write_seq >= SEQ_HARD_LIMIT + } + + /// Decrypt a TLS message. + /// + /// `encr` is a decoded message allegedly received from the peer. + /// If it can be decrypted, its decryption is returned. Otherwise, + /// an error is returned. + pub(crate) fn decrypt_incoming( + &mut self, + encr: OpaqueMessage, + ) -> Result, Error> { + if self.decrypt_state != DirectionState::Active { + return Ok(Some(Decrypted { + want_close_before_decrypt: false, + plaintext: encr.into_plain_message(), + })); + } + + // Set to `true` if the peer appears to getting close to encrypting + // too many messages with this key. + // + // Perhaps if we send an alert well before their counter wraps, a + // buggy peer won't make a terrible mistake here? + // + // Note that there's no reason to refuse to decrypt: the security + // failure has already happened. + let want_close_before_decrypt = self.read_seq == SEQ_SOFT_LIMIT; + + let encrypted_len = encr.payload.0.len(); + match self + .message_decrypter + .decrypt(encr, self.read_seq) + { + Ok(plaintext) => { + self.read_seq += 1; + Ok(Some(Decrypted { + want_close_before_decrypt, + plaintext, + })) + } + Err(Error::DecryptError) if self.doing_trial_decryption(encrypted_len) => { + trace!("Dropping undecryptable message after aborted early_data"); + Ok(None) + } + Err(err) => Err(err), + } + } + + /// Encrypt a TLS message. + /// + /// `plain` is a TLS message we'd like to send. This function + /// panics if the requisite keying material hasn't been established yet. + pub(crate) fn encrypt_outgoing(&mut self, plain: BorrowedPlainMessage) -> OpaqueMessage { + debug_assert!(self.encrypt_state == DirectionState::Active); + assert!(!self.encrypt_exhausted()); + let seq = self.write_seq; + self.write_seq += 1; + self.message_encrypter + .encrypt(plain, seq) + .unwrap() + } +} + +/// Result of decryption. +#[derive(Debug)] +pub struct Decrypted { + /// Whether the peer appears to be getting close to encrypting too many messages with this key. + pub want_close_before_decrypt: bool, + /// The decrypted message. + pub plaintext: PlainMessage, +} diff --git a/vendor/rustls-0.21.8/src/server/builder.rs b/vendor/rustls-0.21.8/src/server/builder.rs new file mode 100644 index 0000000000000..56e636fd0ee51 --- /dev/null +++ b/vendor/rustls-0.21.8/src/server/builder.rs @@ -0,0 +1,117 @@ +use crate::builder::{ConfigBuilder, WantsVerifier}; +use crate::error::Error; +use crate::key; +use crate::kx::SupportedKxGroup; +use crate::server::handy; +use crate::server::{ResolvesServerCert, ServerConfig}; +use crate::suites::SupportedCipherSuite; +use crate::verify; +use crate::versions; +use crate::NoKeyLog; + +use std::marker::PhantomData; +use std::sync::Arc; + +impl ConfigBuilder { + /// Choose how to verify client certificates. + pub fn with_client_cert_verifier( + self, + client_cert_verifier: Arc, + ) -> ConfigBuilder { + ConfigBuilder { + state: WantsServerCert { + cipher_suites: self.state.cipher_suites, + kx_groups: self.state.kx_groups, + versions: self.state.versions, + verifier: client_cert_verifier, + }, + side: PhantomData, + } + } + + /// Disable client authentication. + pub fn with_no_client_auth(self) -> ConfigBuilder { + self.with_client_cert_verifier(verify::NoClientAuth::boxed()) + } +} + +/// A config builder state where the caller must supply how to provide a server certificate to +/// the connecting peer. +/// +/// For more information, see the [`ConfigBuilder`] documentation. +#[derive(Clone, Debug)] +pub struct WantsServerCert { + cipher_suites: Vec, + kx_groups: Vec<&'static SupportedKxGroup>, + versions: versions::EnabledVersions, + verifier: Arc, +} + +impl ConfigBuilder { + /// Sets a single certificate chain and matching private key. This + /// certificate and key is used for all subsequent connections, + /// irrespective of things like SNI hostname. + /// + /// Note that the end-entity certificate must have the + /// [Subject Alternative Name](https://tools.ietf.org/html/rfc6125#section-4.1) + /// extension to describe, e.g., the valid DNS name. The `commonName` field is + /// disregarded. + /// + /// `cert_chain` is a vector of DER-encoded certificates. + /// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key. + /// + /// This function fails if `key_der` is invalid. + pub fn with_single_cert( + self, + cert_chain: Vec, + key_der: key::PrivateKey, + ) -> Result { + let resolver = handy::AlwaysResolvesChain::new(cert_chain, &key_der)?; + Ok(self.with_cert_resolver(Arc::new(resolver))) + } + + /// Sets a single certificate chain, matching private key, OCSP + /// response and SCTs. This certificate and key is used for all + /// subsequent connections, irrespective of things like SNI hostname. + /// + /// `cert_chain` is a vector of DER-encoded certificates. + /// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key. + /// `ocsp` is a DER-encoded OCSP response. Ignored if zero length. + /// `scts` is an `SignedCertificateTimestampList` encoding (see RFC6962) + /// and is ignored if empty. + /// + /// This function fails if `key_der` is invalid. + pub fn with_single_cert_with_ocsp_and_sct( + self, + cert_chain: Vec, + key_der: key::PrivateKey, + ocsp: Vec, + scts: Vec, + ) -> Result { + let resolver = + handy::AlwaysResolvesChain::new_with_extras(cert_chain, &key_der, ocsp, scts)?; + Ok(self.with_cert_resolver(Arc::new(resolver))) + } + + /// Sets a custom [`ResolvesServerCert`]. + pub fn with_cert_resolver(self, cert_resolver: Arc) -> ServerConfig { + ServerConfig { + cipher_suites: self.state.cipher_suites, + kx_groups: self.state.kx_groups, + verifier: self.state.verifier, + cert_resolver, + ignore_client_order: false, + max_fragment_size: None, + session_storage: handy::ServerSessionMemoryCache::new(256), + ticketer: Arc::new(handy::NeverProducesTickets {}), + alpn_protocols: Vec::new(), + versions: self.state.versions, + key_log: Arc::new(NoKeyLog {}), + #[cfg(feature = "secret_extraction")] + enable_secret_extraction: false, + max_early_data_size: 0, + send_half_rtt_data: false, + send_tls13_tickets: 4, + } + } +} diff --git a/vendor/rustls-0.21.8/src/server/common.rs b/vendor/rustls-0.21.8/src/server/common.rs new file mode 100644 index 0000000000000..2e3420c2f5d23 --- /dev/null +++ b/vendor/rustls-0.21.8/src/server/common.rs @@ -0,0 +1,41 @@ +use crate::{key, sign}; + +/// ActiveCertifiedKey wraps CertifiedKey and tracks OSCP and SCT state +/// in a single handshake. +pub(super) struct ActiveCertifiedKey<'a> { + key: &'a sign::CertifiedKey, + ocsp: Option<&'a [u8]>, + sct_list: Option<&'a [u8]>, +} + +impl<'a> ActiveCertifiedKey<'a> { + pub(super) fn from_certified_key(key: &sign::CertifiedKey) -> ActiveCertifiedKey { + ActiveCertifiedKey { + key, + ocsp: key.ocsp.as_deref(), + sct_list: key.sct_list.as_deref(), + } + } + + /// Get the certificate chain + #[inline] + pub(super) fn get_cert(&self) -> &[key::Certificate] { + &self.key.cert + } + + /// Get the signing key + #[inline] + pub(super) fn get_key(&self) -> &dyn sign::SigningKey { + &*self.key.key + } + + #[inline] + pub(super) fn get_ocsp(&self) -> Option<&[u8]> { + self.ocsp + } + + #[inline] + pub(super) fn get_sct_list(&self) -> Option<&[u8]> { + self.sct_list + } +} diff --git a/vendor/rustls-0.21.8/src/server/handy.rs b/vendor/rustls-0.21.8/src/server/handy.rs new file mode 100644 index 0000000000000..5fcaaaebf5c2e --- /dev/null +++ b/vendor/rustls-0.21.8/src/server/handy.rs @@ -0,0 +1,314 @@ +use crate::dns_name::DnsNameRef; +use crate::error::Error; +use crate::key; +use crate::limited_cache; +use crate::server; +use crate::server::ClientHello; +use crate::sign; + +use std::collections; +use std::sync::{Arc, Mutex}; + +/// Something which never stores sessions. +pub struct NoServerSessionStorage {} + +impl server::StoresServerSessions for NoServerSessionStorage { + fn put(&self, _id: Vec, _sec: Vec) -> bool { + false + } + fn get(&self, _id: &[u8]) -> Option> { + None + } + fn take(&self, _id: &[u8]) -> Option> { + None + } + fn can_cache(&self) -> bool { + false + } +} + +/// An implementer of `StoresServerSessions` that stores everything +/// in memory. If enforces a limit on the number of stored sessions +/// to bound memory usage. +pub struct ServerSessionMemoryCache { + cache: Mutex, Vec>>, +} + +impl ServerSessionMemoryCache { + /// Make a new ServerSessionMemoryCache. `size` is the maximum + /// number of stored sessions, and may be rounded-up for + /// efficiency. + pub fn new(size: usize) -> Arc { + Arc::new(Self { + cache: Mutex::new(limited_cache::LimitedCache::new(size)), + }) + } +} + +impl server::StoresServerSessions for ServerSessionMemoryCache { + fn put(&self, key: Vec, value: Vec) -> bool { + self.cache + .lock() + .unwrap() + .insert(key, value); + true + } + + fn get(&self, key: &[u8]) -> Option> { + self.cache + .lock() + .unwrap() + .get(key) + .cloned() + } + + fn take(&self, key: &[u8]) -> Option> { + self.cache.lock().unwrap().remove(key) + } + + fn can_cache(&self) -> bool { + true + } +} + +/// Something which never produces tickets. +pub(super) struct NeverProducesTickets {} + +impl server::ProducesTickets for NeverProducesTickets { + fn enabled(&self) -> bool { + false + } + fn lifetime(&self) -> u32 { + 0 + } + fn encrypt(&self, _bytes: &[u8]) -> Option> { + None + } + fn decrypt(&self, _bytes: &[u8]) -> Option> { + None + } +} + +/// Something which always resolves to the same cert chain. +pub(super) struct AlwaysResolvesChain(Arc); + +impl AlwaysResolvesChain { + /// Creates an `AlwaysResolvesChain`, auto-detecting the underlying private + /// key type and encoding. + pub(super) fn new( + chain: Vec, + priv_key: &key::PrivateKey, + ) -> Result { + let key = sign::any_supported_type(priv_key) + .map_err(|_| Error::General("invalid private key".into()))?; + Ok(Self(Arc::new(sign::CertifiedKey::new(chain, key)))) + } + + /// Creates an `AlwaysResolvesChain`, auto-detecting the underlying private + /// key type and encoding. + /// + /// If non-empty, the given OCSP response and SCTs are attached. + pub(super) fn new_with_extras( + chain: Vec, + priv_key: &key::PrivateKey, + ocsp: Vec, + scts: Vec, + ) -> Result { + let mut r = Self::new(chain, priv_key)?; + + { + let cert = Arc::make_mut(&mut r.0); + if !ocsp.is_empty() { + cert.ocsp = Some(ocsp); + } + if !scts.is_empty() { + cert.sct_list = Some(scts); + } + } + + Ok(r) + } +} + +impl server::ResolvesServerCert for AlwaysResolvesChain { + fn resolve(&self, _client_hello: ClientHello) -> Option> { + Some(Arc::clone(&self.0)) + } +} + +/// Something that resolves do different cert chains/keys based +/// on client-supplied server name (via SNI). +pub struct ResolvesServerCertUsingSni { + by_name: collections::HashMap>, +} + +impl ResolvesServerCertUsingSni { + /// Create a new and empty (i.e., knows no certificates) resolver. + pub fn new() -> Self { + Self { + by_name: collections::HashMap::new(), + } + } + + /// Add a new `sign::CertifiedKey` to be used for the given SNI `name`. + /// + /// This function fails if `name` is not a valid DNS name, or if + /// it's not valid for the supplied certificate, or if the certificate + /// chain is syntactically faulty. + pub fn add(&mut self, name: &str, ck: sign::CertifiedKey) -> Result<(), Error> { + let checked_name = DnsNameRef::try_from(name) + .map_err(|_| Error::General("Bad DNS name".into())) + .map(|dns| dns.to_lowercase_owned())?; + + // Check the certificate chain for validity: + // - it should be non-empty list + // - the first certificate should be parsable as a x509v3, + // - the first certificate should quote the given server name + // (if provided) + // + // These checks are not security-sensitive. They are the + // *server* attempting to detect accidental misconfiguration. + + // Always reject an empty certificate chain. + let end_entity_cert = ck.end_entity_cert().map_err(|_| { + Error::General("No end-entity certificate in certificate chain".to_string()) + })?; + + // Reject syntactically-invalid end-entity certificates. + let end_entity_cert = + webpki::EndEntityCert::try_from(end_entity_cert.as_ref()).map_err(|_| { + Error::General( + "End-entity certificate in certificate chain is syntactically invalid" + .to_string(), + ) + })?; + + // Note that this doesn't fully validate that the certificate is valid; it only validates that the name is one + // that the certificate is valid for, if the certificate is + // valid. + let general_error = + || Error::General("The server certificate is not valid for the given name".to_string()); + + let name = webpki::DnsNameRef::try_from_ascii(checked_name.as_ref().as_bytes()) + .map_err(|_| general_error())?; + + end_entity_cert + .verify_is_valid_for_subject_name(webpki::SubjectNameRef::DnsName(name)) + .map_err(|_| general_error())?; + + let as_str: &str = checked_name.as_ref(); + self.by_name + .insert(as_str.to_string(), Arc::new(ck)); + Ok(()) + } +} + +impl server::ResolvesServerCert for ResolvesServerCertUsingSni { + fn resolve(&self, client_hello: ClientHello) -> Option> { + if let Some(name) = client_hello.server_name() { + self.by_name.get(name).map(Arc::clone) + } else { + // This kind of resolver requires SNI + None + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::server::ProducesTickets; + use crate::server::ResolvesServerCert; + use crate::server::StoresServerSessions; + + #[test] + fn test_noserversessionstorage_drops_put() { + let c = NoServerSessionStorage {}; + assert!(!c.put(vec![0x01], vec![0x02])); + } + + #[test] + fn test_noserversessionstorage_denies_gets() { + let c = NoServerSessionStorage {}; + c.put(vec![0x01], vec![0x02]); + assert_eq!(c.get(&[]), None); + assert_eq!(c.get(&[0x01]), None); + assert_eq!(c.get(&[0x02]), None); + } + + #[test] + fn test_noserversessionstorage_denies_takes() { + let c = NoServerSessionStorage {}; + assert_eq!(c.take(&[]), None); + assert_eq!(c.take(&[0x01]), None); + assert_eq!(c.take(&[0x02]), None); + } + + #[test] + fn test_serversessionmemorycache_accepts_put() { + let c = ServerSessionMemoryCache::new(4); + assert!(c.put(vec![0x01], vec![0x02])); + } + + #[test] + fn test_serversessionmemorycache_persists_put() { + let c = ServerSessionMemoryCache::new(4); + assert!(c.put(vec![0x01], vec![0x02])); + assert_eq!(c.get(&[0x01]), Some(vec![0x02])); + assert_eq!(c.get(&[0x01]), Some(vec![0x02])); + } + + #[test] + fn test_serversessionmemorycache_overwrites_put() { + let c = ServerSessionMemoryCache::new(4); + assert!(c.put(vec![0x01], vec![0x02])); + assert!(c.put(vec![0x01], vec![0x04])); + assert_eq!(c.get(&[0x01]), Some(vec![0x04])); + } + + #[test] + fn test_serversessionmemorycache_drops_to_maintain_size_invariant() { + let c = ServerSessionMemoryCache::new(2); + assert!(c.put(vec![0x01], vec![0x02])); + assert!(c.put(vec![0x03], vec![0x04])); + assert!(c.put(vec![0x05], vec![0x06])); + assert!(c.put(vec![0x07], vec![0x08])); + assert!(c.put(vec![0x09], vec![0x0a])); + + let count = c.get(&[0x01]).iter().count() + + c.get(&[0x03]).iter().count() + + c.get(&[0x05]).iter().count() + + c.get(&[0x07]).iter().count() + + c.get(&[0x09]).iter().count(); + + assert!(count < 5); + } + + #[test] + fn test_neverproducestickets_does_nothing() { + let npt = NeverProducesTickets {}; + assert!(!npt.enabled()); + assert_eq!(0, npt.lifetime()); + assert_eq!(None, npt.encrypt(&[])); + assert_eq!(None, npt.decrypt(&[])); + } + + #[test] + fn test_resolvesservercertusingsni_requires_sni() { + let rscsni = ResolvesServerCertUsingSni::new(); + assert!(rscsni + .resolve(ClientHello::new(&None, &[], None, &[])) + .is_none()); + } + + #[test] + fn test_resolvesservercertusingsni_handles_unknown_name() { + let rscsni = ResolvesServerCertUsingSni::new(); + let name = DnsNameRef::try_from("hello.com") + .unwrap() + .to_owned(); + assert!(rscsni + .resolve(ClientHello::new(&Some(name), &[], None, &[])) + .is_none()); + } +} diff --git a/vendor/rustls-0.21.8/src/server/hs.rs b/vendor/rustls-0.21.8/src/server/hs.rs new file mode 100644 index 0000000000000..8d3077458d34b --- /dev/null +++ b/vendor/rustls-0.21.8/src/server/hs.rs @@ -0,0 +1,527 @@ +use crate::common_state::State; +use crate::conn::ConnectionRandoms; +use crate::dns_name::DnsName; +#[cfg(feature = "tls12")] +use crate::enums::CipherSuite; +use crate::enums::{AlertDescription, HandshakeType, ProtocolVersion, SignatureScheme}; +use crate::error::{Error, PeerIncompatible, PeerMisbehaved}; +use crate::hash_hs::{HandshakeHash, HandshakeHashBuffer}; +#[cfg(feature = "logging")] +use crate::log::{debug, trace}; +use crate::msgs::enums::{Compression, ExtensionType}; +#[cfg(feature = "tls12")] +use crate::msgs::handshake::SessionId; +use crate::msgs::handshake::{ClientHelloPayload, Random, ServerExtension}; +use crate::msgs::handshake::{ConvertProtocolNameList, ConvertServerNameList, HandshakePayload}; +use crate::msgs::message::{Message, MessagePayload}; +use crate::msgs::persist; +use crate::server::{ClientHello, ServerConfig}; +use crate::suites; +use crate::SupportedCipherSuite; + +use super::server_conn::ServerConnectionData; +#[cfg(feature = "tls12")] +use super::tls12; +use crate::server::common::ActiveCertifiedKey; +use crate::server::tls13; + +use std::sync::Arc; + +pub(super) type NextState = Box>; +pub(super) type NextStateOrError = Result; +pub(super) type ServerContext<'a> = crate::common_state::Context<'a, ServerConnectionData>; + +pub(super) fn can_resume( + suite: SupportedCipherSuite, + sni: &Option, + using_ems: bool, + resumedata: &persist::ServerSessionValue, +) -> bool { + // The RFCs underspecify what happens if we try to resume to + // an unoffered/varying suite. We merely don't resume in weird cases. + // + // RFC 6066 says "A server that implements this extension MUST NOT accept + // the request to resume the session if the server_name extension contains + // a different name. Instead, it proceeds with a full handshake to + // establish a new session." + resumedata.cipher_suite == suite.suite() + && (resumedata.extended_ms == using_ems || (resumedata.extended_ms && !using_ems)) + && &resumedata.sni == sni +} + +#[derive(Default)] +pub(super) struct ExtensionProcessing { + // extensions to reply with + pub(super) exts: Vec, + #[cfg(feature = "tls12")] + pub(super) send_ticket: bool, +} + +impl ExtensionProcessing { + pub(super) fn new() -> Self { + Default::default() + } + + pub(super) fn process_common( + &mut self, + config: &ServerConfig, + cx: &mut ServerContext<'_>, + ocsp_response: &mut Option<&[u8]>, + sct_list: &mut Option<&[u8]>, + hello: &ClientHelloPayload, + resumedata: Option<&persist::ServerSessionValue>, + extra_exts: Vec, + ) -> Result<(), Error> { + // ALPN + let our_protocols = &config.alpn_protocols; + let maybe_their_protocols = hello.get_alpn_extension(); + if let Some(their_protocols) = maybe_their_protocols { + let their_protocols = their_protocols.to_slices(); + + if their_protocols + .iter() + .any(|protocol| protocol.is_empty()) + { + return Err(PeerMisbehaved::OfferedEmptyApplicationProtocol.into()); + } + + cx.common.alpn_protocol = our_protocols + .iter() + .find(|protocol| their_protocols.contains(&protocol.as_slice())) + .cloned(); + if let Some(ref selected_protocol) = cx.common.alpn_protocol { + debug!("Chosen ALPN protocol {:?}", selected_protocol); + self.exts + .push(ServerExtension::make_alpn(&[selected_protocol])); + } else if !our_protocols.is_empty() { + return Err(cx.common.send_fatal_alert( + AlertDescription::NoApplicationProtocol, + Error::NoApplicationProtocol, + )); + } + } + + #[cfg(feature = "quic")] + { + if cx.common.is_quic() { + // QUIC has strict ALPN, unlike TLS's more backwards-compatible behavior. RFC 9001 + // says: "The server MUST treat the inability to select a compatible application + // protocol as a connection error of type 0x0178". We judge that ALPN was desired + // (rather than some out-of-band protocol negotiation mechanism) iff any ALPN + // protocols were configured locally or offered by the client. This helps prevent + // successful establishment of connections between peers that can't understand + // each other. + if cx.common.alpn_protocol.is_none() + && (!our_protocols.is_empty() || maybe_their_protocols.is_some()) + { + return Err(cx.common.send_fatal_alert( + AlertDescription::NoApplicationProtocol, + Error::NoApplicationProtocol, + )); + } + + match hello.get_quic_params_extension() { + Some(params) => cx.common.quic.params = Some(params), + None => { + return Err(cx + .common + .missing_extension(PeerMisbehaved::MissingQuicTransportParameters)); + } + } + } + } + + let for_resume = resumedata.is_some(); + // SNI + if !for_resume && hello.get_sni_extension().is_some() { + self.exts + .push(ServerExtension::ServerNameAck); + } + + // Send status_request response if we have one. This is not allowed + // if we're resuming, and is only triggered if we have an OCSP response + // to send. + if !for_resume + && hello + .find_extension(ExtensionType::StatusRequest) + .is_some() + { + if ocsp_response.is_some() && !cx.common.is_tls13() { + // Only TLS1.2 sends confirmation in ServerHello + self.exts + .push(ServerExtension::CertificateStatusAck); + } + } else { + // Throw away any OCSP response so we don't try to send it later. + ocsp_response.take(); + } + + if !for_resume + && hello + .find_extension(ExtensionType::SCT) + .is_some() + { + if !cx.common.is_tls13() { + // Take the SCT list, if any, so we don't send it later, + // and put it in the legacy extension. + if let Some(sct_list) = sct_list.take() { + self.exts + .push(ServerExtension::make_sct(sct_list.to_vec())); + } + } + } else { + // Throw away any SCT list so we don't send it later. + sct_list.take(); + } + + self.exts.extend(extra_exts); + + Ok(()) + } + + #[cfg(feature = "tls12")] + pub(super) fn process_tls12( + &mut self, + config: &ServerConfig, + hello: &ClientHelloPayload, + using_ems: bool, + ) { + // Renegotiation. + // (We don't do reneg at all, but would support the secure version if we did.) + let secure_reneg_offered = hello + .find_extension(ExtensionType::RenegotiationInfo) + .is_some() + || hello + .cipher_suites + .contains(&CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV); + + if secure_reneg_offered { + self.exts + .push(ServerExtension::make_empty_renegotiation_info()); + } + + // Tickets: + // If we get any SessionTicket extension and have tickets enabled, + // we send an ack. + if hello + .find_extension(ExtensionType::SessionTicket) + .is_some() + && config.ticketer.enabled() + { + self.send_ticket = true; + self.exts + .push(ServerExtension::SessionTicketAck); + } + + // Confirm use of EMS if offered. + if using_ems { + self.exts + .push(ServerExtension::ExtendedMasterSecretAck); + } + } +} + +pub(super) struct ExpectClientHello { + pub(super) config: Arc, + pub(super) extra_exts: Vec, + pub(super) transcript: HandshakeHashOrBuffer, + #[cfg(feature = "tls12")] + pub(super) session_id: SessionId, + #[cfg(feature = "tls12")] + pub(super) using_ems: bool, + pub(super) done_retry: bool, + pub(super) send_tickets: usize, +} + +impl ExpectClientHello { + pub(super) fn new(config: Arc, extra_exts: Vec) -> Self { + let mut transcript_buffer = HandshakeHashBuffer::new(); + + if config.verifier.offer_client_auth() { + transcript_buffer.set_client_auth_enabled(); + } + + Self { + config, + extra_exts, + transcript: HandshakeHashOrBuffer::Buffer(transcript_buffer), + #[cfg(feature = "tls12")] + session_id: SessionId::empty(), + #[cfg(feature = "tls12")] + using_ems: false, + done_retry: false, + send_tickets: 0, + } + } + + /// Continues handling of a `ClientHello` message once config and certificate are available. + pub(super) fn with_certified_key( + self, + mut sig_schemes: Vec, + client_hello: &ClientHelloPayload, + m: &Message, + cx: &mut ServerContext<'_>, + ) -> NextStateOrError { + let tls13_enabled = self + .config + .supports_version(ProtocolVersion::TLSv1_3); + let tls12_enabled = self + .config + .supports_version(ProtocolVersion::TLSv1_2); + + // Are we doing TLS1.3? + let maybe_versions_ext = client_hello.get_versions_extension(); + let version = if let Some(versions) = maybe_versions_ext { + if versions.contains(&ProtocolVersion::TLSv1_3) && tls13_enabled { + ProtocolVersion::TLSv1_3 + } else if !versions.contains(&ProtocolVersion::TLSv1_2) || !tls12_enabled { + return Err(cx.common.send_fatal_alert( + AlertDescription::ProtocolVersion, + PeerIncompatible::Tls12NotOfferedOrEnabled, + )); + } else if cx.common.is_quic() { + return Err(cx.common.send_fatal_alert( + AlertDescription::ProtocolVersion, + PeerIncompatible::Tls13RequiredForQuic, + )); + } else { + ProtocolVersion::TLSv1_2 + } + } else if client_hello.client_version.get_u16() < ProtocolVersion::TLSv1_2.get_u16() { + return Err(cx.common.send_fatal_alert( + AlertDescription::ProtocolVersion, + PeerIncompatible::Tls12NotOffered, + )); + } else if !tls12_enabled && tls13_enabled { + return Err(cx.common.send_fatal_alert( + AlertDescription::ProtocolVersion, + PeerIncompatible::SupportedVersionsExtensionRequired, + )); + } else if cx.common.is_quic() { + return Err(cx.common.send_fatal_alert( + AlertDescription::ProtocolVersion, + PeerIncompatible::Tls13RequiredForQuic, + )); + } else { + ProtocolVersion::TLSv1_2 + }; + + cx.common.negotiated_version = Some(version); + + // We communicate to the upper layer what kind of key they should choose + // via the sigschemes value. Clients tend to treat this extension + // orthogonally to offered ciphersuites (even though, in TLS1.2 it is not). + // So: reduce the offered sigschemes to those compatible with the + // intersection of ciphersuites. + let client_suites = self + .config + .cipher_suites + .iter() + .copied() + .filter(|scs| { + client_hello + .cipher_suites + .contains(&scs.suite()) + }) + .collect::>(); + + sig_schemes + .retain(|scheme| suites::compatible_sigscheme_for_suites(*scheme, &client_suites)); + + // Choose a certificate. + let certkey = { + let client_hello = ClientHello::new( + &cx.data.sni, + &sig_schemes, + client_hello.get_alpn_extension(), + &client_hello.cipher_suites, + ); + + let certkey = self + .config + .cert_resolver + .resolve(client_hello); + + certkey.ok_or_else(|| { + cx.common.send_fatal_alert( + AlertDescription::AccessDenied, + Error::General("no server certificate chain resolved".to_owned()), + ) + })? + }; + let certkey = ActiveCertifiedKey::from_certified_key(&certkey); + + // Reduce our supported ciphersuites by the certificate. + // (no-op for TLS1.3) + let suitable_suites = + suites::reduce_given_sigalg(&self.config.cipher_suites, certkey.get_key().algorithm()); + + // And version + let suitable_suites = suites::reduce_given_version(&suitable_suites, version); + + let suite = if self.config.ignore_client_order { + suites::choose_ciphersuite_preferring_server( + &client_hello.cipher_suites, + &suitable_suites, + ) + } else { + suites::choose_ciphersuite_preferring_client( + &client_hello.cipher_suites, + &suitable_suites, + ) + } + .ok_or_else(|| { + cx.common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerIncompatible::NoCipherSuitesInCommon, + ) + })?; + + debug!("decided upon suite {:?}", suite); + cx.common.suite = Some(suite); + + // Start handshake hash. + let starting_hash = suite.hash_algorithm(); + let transcript = match self.transcript { + HandshakeHashOrBuffer::Buffer(inner) => inner.start_hash(starting_hash), + HandshakeHashOrBuffer::Hash(inner) if inner.algorithm() == starting_hash => inner, + _ => { + return Err(cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::HandshakeHashVariedAfterRetry, + )); + } + }; + + // Save their Random. + let randoms = ConnectionRandoms::new(client_hello.random, Random::new()?); + match suite { + SupportedCipherSuite::Tls13(suite) => tls13::CompleteClientHelloHandling { + config: self.config, + transcript, + suite, + randoms, + done_retry: self.done_retry, + send_tickets: self.send_tickets, + extra_exts: self.extra_exts, + } + .handle_client_hello(cx, certkey, m, client_hello, sig_schemes), + #[cfg(feature = "tls12")] + SupportedCipherSuite::Tls12(suite) => tls12::CompleteClientHelloHandling { + config: self.config, + transcript, + session_id: self.session_id, + suite, + using_ems: self.using_ems, + randoms, + send_ticket: self.send_tickets > 0, + extra_exts: self.extra_exts, + } + .handle_client_hello( + cx, + certkey, + m, + client_hello, + sig_schemes, + tls13_enabled, + ), + } + } +} + +impl State for ExpectClientHello { + fn handle(self: Box, cx: &mut ServerContext<'_>, m: Message) -> NextStateOrError { + let (client_hello, sig_schemes) = process_client_hello(&m, self.done_retry, cx)?; + self.with_certified_key(sig_schemes, client_hello, &m, cx) + } +} + +/// Configuration-independent validation of a `ClientHello` message. +/// +/// This represents the first part of the `ClientHello` handling, where we do all validation that +/// doesn't depend on a `ServerConfig` being available and extract everything needed to build a +/// [`ClientHello`] value for a [`ResolvesServerConfig`]/`ResolvesServerCert`]. +/// +/// Note that this will modify `data.sni` even if config or certificate resolution fail. +pub(super) fn process_client_hello<'a>( + m: &'a Message, + done_retry: bool, + cx: &mut ServerContext, +) -> Result<(&'a ClientHelloPayload, Vec), Error> { + let client_hello = + require_handshake_msg!(m, HandshakeType::ClientHello, HandshakePayload::ClientHello)?; + trace!("we got a clienthello {:?}", client_hello); + + if !client_hello + .compression_methods + .contains(&Compression::Null) + { + return Err(cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerIncompatible::NullCompressionRequired, + )); + } + + if client_hello.has_duplicate_extension() { + return Err(cx.common.send_fatal_alert( + AlertDescription::DecodeError, + PeerMisbehaved::DuplicateClientHelloExtensions, + )); + } + + // No handshake messages should follow this one in this flight. + cx.common.check_aligned_handshake()?; + + // Extract and validate the SNI DNS name, if any, before giving it to + // the cert resolver. In particular, if it is invalid then we should + // send an Illegal Parameter alert instead of the Internal Error alert + // (or whatever) that we'd send if this were checked later or in a + // different way. + let sni: Option = match client_hello.get_sni_extension() { + Some(sni) => { + if sni.has_duplicate_names_for_type() { + return Err(cx.common.send_fatal_alert( + AlertDescription::DecodeError, + PeerMisbehaved::DuplicateServerNameTypes, + )); + } + + if let Some(hostname) = sni.get_single_hostname() { + Some(hostname.to_lowercase_owned()) + } else { + return Err(cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::ServerNameMustContainOneHostName, + )); + } + } + None => None, + }; + + // save only the first SNI + if let (Some(sni), false) = (&sni, done_retry) { + // Save the SNI into the session. + // The SNI hostname is immutable once set. + assert!(cx.data.sni.is_none()); + cx.data.sni = Some(sni.clone()); + } else if cx.data.sni != sni { + return Err(PeerMisbehaved::ServerNameDifferedOnRetry.into()); + } + + let sig_schemes = client_hello + .get_sigalgs_extension() + .ok_or_else(|| { + cx.common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerIncompatible::SignatureAlgorithmsExtensionRequired, + ) + })?; + + Ok((client_hello, sig_schemes.to_owned())) +} + +#[allow(clippy::large_enum_variant)] +pub(crate) enum HandshakeHashOrBuffer { + Buffer(HandshakeHashBuffer), + Hash(HandshakeHash), +} diff --git a/vendor/rustls-0.21.8/src/server/server_conn.rs b/vendor/rustls-0.21.8/src/server/server_conn.rs new file mode 100644 index 0000000000000..b0fc80c78cf4d --- /dev/null +++ b/vendor/rustls-0.21.8/src/server/server_conn.rs @@ -0,0 +1,808 @@ +use crate::builder::{ConfigBuilder, WantsCipherSuites}; +use crate::common_state::{CommonState, Context, Side, State}; +use crate::conn::{ConnectionCommon, ConnectionCore}; +use crate::dns_name::DnsName; +use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme}; +use crate::error::Error; +use crate::kx::SupportedKxGroup; +#[cfg(feature = "logging")] +use crate::log::trace; +use crate::msgs::base::Payload; +use crate::msgs::handshake::{ClientHelloPayload, ProtocolName, ServerExtension}; +use crate::msgs::message::Message; +use crate::sign; +use crate::suites::SupportedCipherSuite; +use crate::vecbuf::ChunkVecBuffer; +use crate::verify; +#[cfg(feature = "secret_extraction")] +use crate::ExtractedSecrets; +use crate::KeyLog; + +use super::hs; + +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; +use std::sync::Arc; +use std::{fmt, io}; + +/// A trait for the ability to store server session data. +/// +/// The keys and values are opaque. +/// +/// Both the keys and values should be treated as +/// **highly sensitive data**, containing enough key material +/// to break all security of the corresponding sessions. +/// +/// Implementations can be lossy (in other words, forgetting +/// key/value pairs) without any negative security consequences. +/// +/// However, note that `take` **must** reliably delete a returned +/// value. If it does not, there may be security consequences. +/// +/// `put` and `take` are mutating operations; this isn't expressed +/// in the type system to allow implementations freedom in +/// how to achieve interior mutability. `Mutex` is a common +/// choice. +pub trait StoresServerSessions: Send + Sync { + /// Store session secrets encoded in `value` against `key`, + /// overwrites any existing value against `key`. Returns `true` + /// if the value was stored. + fn put(&self, key: Vec, value: Vec) -> bool; + + /// Find a value with the given `key`. Return it, or None + /// if it doesn't exist. + fn get(&self, key: &[u8]) -> Option>; + + /// Find a value with the given `key`. Return it and delete it; + /// or None if it doesn't exist. + fn take(&self, key: &[u8]) -> Option>; + + /// Whether the store can cache another session. This is used to indicate to clients + /// whether their session can be resumed; the implementation is not required to remember + /// a session even if it returns `true` here. + fn can_cache(&self) -> bool; +} + +/// A trait for the ability to encrypt and decrypt tickets. +pub trait ProducesTickets: Send + Sync { + /// Returns true if this implementation will encrypt/decrypt + /// tickets. Should return false if this is a dummy + /// implementation: the server will not send the SessionTicket + /// extension and will not call the other functions. + fn enabled(&self) -> bool; + + /// Returns the lifetime in seconds of tickets produced now. + /// The lifetime is provided as a hint to clients that the + /// ticket will not be useful after the given time. + /// + /// This lifetime must be implemented by key rolling and + /// erasure, *not* by storing a lifetime in the ticket. + /// + /// The objective is to limit damage to forward secrecy caused + /// by tickets, not just limiting their lifetime. + fn lifetime(&self) -> u32; + + /// Encrypt and authenticate `plain`, returning the resulting + /// ticket. Return None if `plain` cannot be encrypted for + /// some reason: an empty ticket will be sent and the connection + /// will continue. + fn encrypt(&self, plain: &[u8]) -> Option>; + + /// Decrypt `cipher`, validating its authenticity protection + /// and recovering the plaintext. `cipher` is fully attacker + /// controlled, so this decryption must be side-channel free, + /// panic-proof, and otherwise bullet-proof. If the decryption + /// fails, return None. + fn decrypt(&self, cipher: &[u8]) -> Option>; +} + +/// How to choose a certificate chain and signing key for use +/// in server authentication. +pub trait ResolvesServerCert: Send + Sync { + /// Choose a certificate chain and matching key given simplified + /// ClientHello information. + /// + /// Return `None` to abort the handshake. + fn resolve(&self, client_hello: ClientHello) -> Option>; +} + +/// A struct representing the received Client Hello +pub struct ClientHello<'a> { + server_name: &'a Option, + signature_schemes: &'a [SignatureScheme], + alpn: Option<&'a Vec>, + cipher_suites: &'a [CipherSuite], +} + +impl<'a> ClientHello<'a> { + /// Creates a new ClientHello + pub(super) fn new( + server_name: &'a Option, + signature_schemes: &'a [SignatureScheme], + alpn: Option<&'a Vec>, + cipher_suites: &'a [CipherSuite], + ) -> Self { + trace!("sni {:?}", server_name); + trace!("sig schemes {:?}", signature_schemes); + trace!("alpn protocols {:?}", alpn); + trace!("cipher suites {:?}", cipher_suites); + + ClientHello { + server_name, + signature_schemes, + alpn, + cipher_suites, + } + } + + /// Get the server name indicator. + /// + /// Returns `None` if the client did not supply a SNI. + pub fn server_name(&self) -> Option<&str> { + self.server_name + .as_ref() + .map(>::as_ref) + } + + /// Get the compatible signature schemes. + /// + /// Returns standard-specified default if the client omitted this extension. + pub fn signature_schemes(&self) -> &[SignatureScheme] { + self.signature_schemes + } + + /// Get the ALPN protocol identifiers submitted by the client. + /// + /// Returns `None` if the client did not include an ALPN extension. + /// + /// Application Layer Protocol Negotiation (ALPN) is a TLS extension that lets a client + /// submit a set of identifiers that each a represent an application-layer protocol. + /// The server will then pick its preferred protocol from the set submitted by the client. + /// Each identifier is represented as a byte array, although common values are often ASCII-encoded. + /// See the official RFC-7301 specifications at + /// for more information on ALPN. + /// + /// For example, a HTTP client might specify "http/1.1" and/or "h2". Other well-known values + /// are listed in the at IANA registry at + /// . + /// + /// The server can specify supported ALPN protocols by setting [`ServerConfig::alpn_protocols`]. + /// During the handshake, the server will select the first protocol configured that the client supports. + pub fn alpn(&self) -> Option> { + self.alpn.map(|protocols| { + protocols + .iter() + .map(|proto| proto.as_ref()) + }) + } + + /// Get cipher suites. + pub fn cipher_suites(&self) -> &[CipherSuite] { + self.cipher_suites + } +} + +/// Common configuration for a set of server sessions. +/// +/// Making one of these is cheap, though one of the inputs may be expensive: gathering trust roots +/// from the operating system to add to the [`RootCertStore`] passed to a `ClientCertVerifier` +/// builder may take on the order of a few hundred milliseconds. +/// +/// These must be created via the [`ServerConfig::builder()`] function. +/// +/// # Defaults +/// +/// * [`ServerConfig::max_fragment_size`]: the default is `None`: TLS packets are not fragmented to a specific size. +/// * [`ServerConfig::session_storage`]: the default stores 256 sessions in memory. +/// * [`ServerConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated. +/// * [`ServerConfig::key_log`]: key material is not logged. +/// * [`ServerConfig::send_tls13_tickets`]: 4 tickets are sent. +/// +/// [`RootCertStore`]: crate::RootCertStore +#[derive(Clone)] +pub struct ServerConfig { + /// List of ciphersuites, in preference order. + pub(super) cipher_suites: Vec, + + /// List of supported key exchange groups. + /// + /// The first is the highest priority: they will be + /// offered to the client in this order. + pub(super) kx_groups: Vec<&'static SupportedKxGroup>, + + /// Ignore the client's ciphersuite order. Instead, + /// choose the top ciphersuite in the server list + /// which is supported by the client. + pub ignore_client_order: bool, + + /// The maximum size of TLS message we'll emit. If None, we don't limit TLS + /// message lengths except to the 2**16 limit specified in the standard. + /// + /// rustls enforces an arbitrary minimum of 32 bytes for this field. + /// Out of range values are reported as errors from ServerConnection::new. + /// + /// Setting this value to the TCP MSS may improve latency for stream-y workloads. + pub max_fragment_size: Option, + + /// How to store client sessions. + pub session_storage: Arc, + + /// How to produce tickets. + pub ticketer: Arc, + + /// How to choose a server cert and key. + pub cert_resolver: Arc, + + /// Protocol names we support, most preferred first. + /// If empty we don't do ALPN at all. + pub alpn_protocols: Vec>, + + /// Supported protocol versions, in no particular order. + /// The default is all supported versions. + pub(super) versions: crate::versions::EnabledVersions, + + /// How to verify client certificates. + pub(super) verifier: Arc, + + /// How to output key material for debugging. The default + /// does nothing. + pub key_log: Arc, + + /// Allows traffic secrets to be extracted after the handshake, + /// e.g. for kTLS setup. + #[cfg(feature = "secret_extraction")] + #[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] + pub enable_secret_extraction: bool, + + /// Amount of early data to accept for sessions created by + /// this config. Specify 0 to disable early data. The + /// default is 0. + /// + /// Read the early data via [`ServerConnection::early_data`]. + /// + /// The units for this are _both_ plaintext bytes, _and_ ciphertext + /// bytes, depending on whether the server accepts a client's early_data + /// or not. It is therefore recommended to include some slop in + /// this value to account for the unknown amount of ciphertext + /// expansion in the latter case. + pub max_early_data_size: u32, + + /// Whether the server should send "0.5RTT" data. This means the server + /// sends data after its first flight of handshake messages, without + /// waiting for the client to complete the handshake. + /// + /// This can improve TTFB latency for either server-speaks-first protocols, + /// or client-speaks-first protocols when paired with "0RTT" data. This + /// comes at the cost of a subtle weakening of the normal handshake + /// integrity guarantees that TLS provides. Note that the initial + /// `ClientHello` is indirectly authenticated because it is included + /// in the transcript used to derive the keys used to encrypt the data. + /// + /// This only applies to TLS1.3 connections. TLS1.2 connections cannot + /// do this optimisation and this setting is ignored for them. It is + /// also ignored for TLS1.3 connections that even attempt client + /// authentication. + /// + /// This defaults to false. This means the first application data + /// sent by the server comes after receiving and validating the client's + /// handshake up to the `Finished` message. This is the safest option. + pub send_half_rtt_data: bool, + + /// How many TLS1.3 tickets to send immediately after a successful + /// handshake. + /// + /// Because TLS1.3 tickets are single-use, this allows + /// a client to perform multiple resumptions. + /// + /// The default is 4. + /// + /// If this is 0, no tickets are sent and clients will not be able to + /// do any resumption. + pub send_tls13_tickets: usize, +} + +impl fmt::Debug for ServerConfig { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ServerConfig") + .field("ignore_client_order", &self.ignore_client_order) + .field("max_fragment_size", &self.max_fragment_size) + .field("alpn_protocols", &self.alpn_protocols) + .field("max_early_data_size", &self.max_early_data_size) + .field("send_half_rtt_data", &self.send_half_rtt_data) + .field("send_tls13_tickets", &self.send_tls13_tickets) + .finish_non_exhaustive() + } +} + +impl ServerConfig { + /// Create builder to build up the server configuration. + /// + /// For more information, see the [`ConfigBuilder`] documentation. + pub fn builder() -> ConfigBuilder { + ConfigBuilder { + state: WantsCipherSuites(()), + side: PhantomData, + } + } + + /// We support a given TLS version if it's quoted in the configured + /// versions *and* at least one ciphersuite for this version is + /// also configured. + pub(crate) fn supports_version(&self, v: ProtocolVersion) -> bool { + self.versions.contains(v) + && self + .cipher_suites + .iter() + .any(|cs| cs.version().version == v) + } +} + +/// Allows reading of early data in resumed TLS1.3 connections. +/// +/// "Early data" is also known as "0-RTT data". +/// +/// This structure implements [`std::io::Read`]. +pub struct ReadEarlyData<'a> { + early_data: &'a mut EarlyDataState, +} + +impl<'a> ReadEarlyData<'a> { + fn new(early_data: &'a mut EarlyDataState) -> Self { + ReadEarlyData { early_data } + } +} + +impl<'a> std::io::Read for ReadEarlyData<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.early_data.read(buf) + } + + #[cfg(read_buf)] + fn read_buf(&mut self, cursor: io::BorrowedCursor<'_>) -> io::Result<()> { + self.early_data.read_buf(cursor) + } +} + +/// This represents a single TLS server connection. +/// +/// Send TLS-protected data to the peer using the `io::Write` trait implementation. +/// Read data from the peer using the `io::Read` trait implementation. +pub struct ServerConnection { + inner: ConnectionCommon, +} + +impl ServerConnection { + /// Make a new ServerConnection. `config` controls how + /// we behave in the TLS protocol. + pub fn new(config: Arc) -> Result { + Ok(Self { + inner: ConnectionCommon::from(ConnectionCore::for_server(config, Vec::new())?), + }) + } + + /// Retrieves the server name, if any, used to select the certificate and + /// private key. + /// + /// This returns `None` until some time after the client's server name indication + /// (SNI) extension value is processed during the handshake. It will never be + /// `None` when the connection is ready to send or process application data, + /// unless the client does not support SNI. + /// + /// This is useful for application protocols that need to enforce that the + /// server name matches an application layer protocol hostname. For + /// example, HTTP/1.1 servers commonly expect the `Host:` header field of + /// every request on a connection to match the hostname in the SNI extension + /// when the client provides the SNI extension. + /// + /// The server name is also used to match sessions during session resumption. + pub fn server_name(&self) -> Option<&str> { + self.inner.core.get_sni_str() + } + + /// Application-controlled portion of the resumption ticket supplied by the client, if any. + /// + /// Recovered from the prior session's `set_resumption_data`. Integrity is guaranteed by rustls. + /// + /// Returns `Some` iff a valid resumption ticket has been received from the client. + pub fn received_resumption_data(&self) -> Option<&[u8]> { + self.inner + .core + .data + .received_resumption_data + .as_ref() + .map(|x| &x[..]) + } + + /// Set the resumption data to embed in future resumption tickets supplied to the client. + /// + /// Defaults to the empty byte string. Must be less than 2^15 bytes to allow room for other + /// data. Should be called while `is_handshaking` returns true to ensure all transmitted + /// resumption tickets are affected. + /// + /// Integrity will be assured by rustls, but the data will be visible to the client. If secrecy + /// from the client is desired, encrypt the data separately. + pub fn set_resumption_data(&mut self, data: &[u8]) { + assert!(data.len() < 2usize.pow(15)); + self.inner.core.data.resumption_data = data.into(); + } + + /// Explicitly discard early data, notifying the client + /// + /// Useful if invariants encoded in `received_resumption_data()` cannot be respected. + /// + /// Must be called while `is_handshaking` is true. + pub fn reject_early_data(&mut self) { + self.inner.core.reject_early_data() + } + + /// Returns an `io::Read` implementer you can read bytes from that are + /// received from a client as TLS1.3 0RTT/"early" data, during the handshake. + /// + /// This returns `None` in many circumstances, such as : + /// + /// - Early data is disabled if [`ServerConfig::max_early_data_size`] is zero (the default). + /// - The session negotiated with the client is not TLS1.3. + /// - The client just doesn't support early data. + /// - The connection doesn't resume an existing session. + /// - The client hasn't sent a full ClientHello yet. + pub fn early_data(&mut self) -> Option { + let data = &mut self.inner.core.data; + if data.early_data.was_accepted() { + Some(ReadEarlyData::new(&mut data.early_data)) + } else { + None + } + } + + /// Extract secrets, so they can be used when configuring kTLS, for example. + #[cfg(feature = "secret_extraction")] + #[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] + pub fn extract_secrets(self) -> Result { + self.inner.extract_secrets() + } +} + +impl fmt::Debug for ServerConnection { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ServerConnection") + .finish() + } +} + +impl Deref for ServerConnection { + type Target = ConnectionCommon; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for ServerConnection { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl From for crate::Connection { + fn from(conn: ServerConnection) -> Self { + Self::Server(conn) + } +} + +/// Handle on a server-side connection before configuration is available. +/// +/// `Acceptor` allows the caller to choose a [`ServerConfig`] after reading +/// the [`ClientHello`] of an incoming connection. This is useful for servers +/// that choose different certificates or cipher suites based on the +/// characteristics of the `ClientHello`. In particular it is useful for +/// servers that need to do some I/O to load a certificate and its private key +/// and don't want to use the blocking interface provided by +/// [`ResolvesServerCert`]. +/// +/// Create an Acceptor with [`Acceptor::default()`]. +/// +/// # Example +/// +/// ```no_run +/// # fn choose_server_config( +/// # _: rustls::server::ClientHello, +/// # ) -> std::sync::Arc { +/// # unimplemented!(); +/// # } +/// # #[allow(unused_variables)] +/// # fn main() { +/// use rustls::server::{Acceptor, ServerConfig}; +/// let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); +/// for stream in listener.incoming() { +/// let mut stream = stream.unwrap(); +/// let mut acceptor = Acceptor::default(); +/// let accepted = loop { +/// acceptor.read_tls(&mut stream).unwrap(); +/// if let Some(accepted) = acceptor.accept().unwrap() { +/// break accepted; +/// } +/// }; +/// +/// // For some user-defined choose_server_config: +/// let config = choose_server_config(accepted.client_hello()); +/// let conn = accepted +/// .into_connection(config) +/// .unwrap(); + +/// // Proceed with handling the ServerConnection. +/// } +/// # } +/// ``` +pub struct Acceptor { + inner: Option>, +} + +impl Default for Acceptor { + /// Return an empty Acceptor, ready to receive bytes from a new client connection. + fn default() -> Self { + Self { + inner: Some( + ConnectionCore::new( + Box::new(Accepting), + ServerConnectionData::default(), + CommonState::new(Side::Server), + ) + .into(), + ), + } + } +} + +impl Acceptor { + /// Read TLS content from `rd`. + /// + /// Returns an error if this `Acceptor` has already yielded an [`Accepted`]. For more details, + /// refer to [`Connection::read_tls()`]. + /// + /// [`Connection::read_tls()`]: crate::Connection::read_tls + pub fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result { + match &mut self.inner { + Some(conn) => conn.read_tls(rd), + None => Err(io::Error::new( + io::ErrorKind::Other, + "acceptor cannot read after successful acceptance", + )), + } + } + + /// Check if a `ClientHello` message has been received. + /// + /// Returns `Ok(None)` if the complete `ClientHello` has not yet been received. + /// Do more I/O and then call this function again. + /// + /// Returns `Ok(Some(accepted))` if the connection has been accepted. Call + /// `accepted.into_connection()` to continue. Do not call this function again. + /// + /// Returns `Err(err)` if an error occurred. Do not call this function again. + pub fn accept(&mut self) -> Result, Error> { + let mut connection = match self.inner.take() { + Some(conn) => conn, + None => { + return Err(Error::General("Acceptor polled after completion".into())); + } + }; + + let message = match connection.first_handshake_message()? { + Some(msg) => msg, + None => { + self.inner = Some(connection); + return Ok(None); + } + }; + + let (_, sig_schemes) = + hs::process_client_hello(&message, false, &mut Context::from(&mut connection))?; + + Ok(Some(Accepted { + connection, + message, + sig_schemes, + })) + } +} + +/// Represents a `ClientHello` message received through the [`Acceptor`]. +/// +/// Contains the state required to resume the connection through [`Accepted::into_connection()`]. +pub struct Accepted { + connection: ConnectionCommon, + message: Message, + sig_schemes: Vec, +} + +impl Accepted { + /// Get the [`ClientHello`] for this connection. + pub fn client_hello(&self) -> ClientHello<'_> { + let payload = Self::client_hello_payload(&self.message); + ClientHello::new( + &self.connection.core.data.sni, + &self.sig_schemes, + payload.get_alpn_extension(), + &payload.cipher_suites, + ) + } + + /// Convert the [`Accepted`] into a [`ServerConnection`]. + /// + /// Takes the state returned from [`Acceptor::accept()`] as well as the [`ServerConfig`] and + /// [`sign::CertifiedKey`] that should be used for the session. Returns an error if + /// configuration-dependent validation of the received `ClientHello` message fails. + pub fn into_connection(mut self, config: Arc) -> Result { + self.connection + .set_max_fragment_size(config.max_fragment_size)?; + + #[cfg(feature = "secret_extraction")] + { + self.connection.enable_secret_extraction = config.enable_secret_extraction; + } + + let state = hs::ExpectClientHello::new(config, Vec::new()); + let mut cx = hs::ServerContext::from(&mut self.connection); + + let new = state.with_certified_key( + self.sig_schemes, + Self::client_hello_payload(&self.message), + &self.message, + &mut cx, + )?; + + self.connection.replace_state(new); + Ok(ServerConnection { + inner: self.connection, + }) + } + + fn client_hello_payload(message: &Message) -> &ClientHelloPayload { + match &message.payload { + crate::msgs::message::MessagePayload::Handshake { parsed, .. } => match &parsed.payload + { + crate::msgs::handshake::HandshakePayload::ClientHello(ch) => ch, + _ => unreachable!(), + }, + _ => unreachable!(), + } + } +} + +struct Accepting; + +impl State for Accepting { + fn handle( + self: Box, + _cx: &mut hs::ServerContext<'_>, + _m: Message, + ) -> Result>, Error> { + Err(Error::General("unreachable state".into())) + } +} + +pub(super) enum EarlyDataState { + New, + Accepted(ChunkVecBuffer), + Rejected, +} + +impl Default for EarlyDataState { + fn default() -> Self { + Self::New + } +} + +impl EarlyDataState { + pub(super) fn reject(&mut self) { + *self = Self::Rejected; + } + + pub(super) fn accept(&mut self, max_size: usize) { + *self = Self::Accepted(ChunkVecBuffer::new(Some(max_size))); + } + + fn was_accepted(&self) -> bool { + matches!(self, Self::Accepted(_)) + } + + pub(super) fn was_rejected(&self) -> bool { + matches!(self, Self::Rejected) + } + + fn read(&mut self, buf: &mut [u8]) -> io::Result { + match self { + Self::Accepted(ref mut received) => received.read(buf), + _ => Err(io::Error::from(io::ErrorKind::BrokenPipe)), + } + } + + #[cfg(read_buf)] + fn read_buf(&mut self, cursor: io::BorrowedCursor<'_>) -> io::Result<()> { + match self { + Self::Accepted(ref mut received) => received.read_buf(cursor), + _ => Err(io::Error::from(io::ErrorKind::BrokenPipe)), + } + } + + pub(super) fn take_received_plaintext(&mut self, bytes: Payload) -> bool { + let available = bytes.0.len(); + match self { + Self::Accepted(ref mut received) if received.apply_limit(available) == available => { + received.append(bytes.0); + true + } + _ => false, + } + } +} + +// these branches not reachable externally, unless something else goes wrong. +#[test] +fn test_read_in_new_state() { + assert_eq!( + format!("{:?}", EarlyDataState::default().read(&mut [0u8; 5])), + "Err(Kind(BrokenPipe))" + ); +} + +#[cfg(read_buf)] +#[test] +fn test_read_buf_in_new_state() { + use std::io::BorrowedBuf; + + let mut buf = [0u8; 5]; + let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); + assert_eq!( + format!("{:?}", EarlyDataState::default().read_buf(buf.unfilled())), + "Err(Kind(BrokenPipe))" + ); +} + +impl ConnectionCore { + pub(crate) fn for_server( + config: Arc, + extra_exts: Vec, + ) -> Result { + let mut common = CommonState::new(Side::Server); + common.set_max_fragment_size(config.max_fragment_size)?; + #[cfg(feature = "secret_extraction")] + { + common.enable_secret_extraction = config.enable_secret_extraction; + } + Ok(Self::new( + Box::new(hs::ExpectClientHello::new(config, extra_exts)), + ServerConnectionData::default(), + common, + )) + } + + pub(crate) fn reject_early_data(&mut self) { + assert!( + self.common_state.is_handshaking(), + "cannot retroactively reject early data" + ); + self.data.early_data.reject(); + } + + pub(crate) fn get_sni_str(&self) -> Option<&str> { + self.data.get_sni_str() + } +} + +/// State associated with a server connection. +#[derive(Default)] +pub struct ServerConnectionData { + pub(super) sni: Option, + pub(super) received_resumption_data: Option>, + pub(super) resumption_data: Vec, + pub(super) early_data: EarlyDataState, +} + +impl ServerConnectionData { + pub(super) fn get_sni_str(&self) -> Option<&str> { + self.sni.as_ref().map(AsRef::as_ref) + } +} + +impl crate::conn::SideData for ServerConnectionData {} diff --git a/vendor/rustls-0.21.8/src/server/tls12.rs b/vendor/rustls-0.21.8/src/server/tls12.rs new file mode 100644 index 0000000000000..b55b961272b29 --- /dev/null +++ b/vendor/rustls-0.21.8/src/server/tls12.rs @@ -0,0 +1,955 @@ +use crate::check::inappropriate_message; +use crate::common_state::{CommonState, Side, State}; +use crate::conn::ConnectionRandoms; +use crate::enums::ProtocolVersion; +use crate::enums::{AlertDescription, ContentType, HandshakeType}; +use crate::error::{Error, PeerIncompatible, PeerMisbehaved}; +use crate::hash_hs::HandshakeHash; +use crate::key::Certificate; +#[cfg(feature = "logging")] +use crate::log::{debug, trace}; +use crate::msgs::base::Payload; +use crate::msgs::ccs::ChangeCipherSpecPayload; +use crate::msgs::codec::Codec; +use crate::msgs::handshake::{ClientECDHParams, HandshakeMessagePayload, HandshakePayload}; +use crate::msgs::handshake::{NewSessionTicketPayload, SessionId}; +use crate::msgs::message::{Message, MessagePayload}; +use crate::msgs::persist; +#[cfg(feature = "secret_extraction")] +use crate::suites::PartiallyExtractedSecrets; +use crate::tls12::{self, ConnectionSecrets, Tls12CipherSuite}; +use crate::{kx, ticketer, verify}; + +use super::common::ActiveCertifiedKey; +use super::hs::{self, ServerContext}; +use super::server_conn::{ProducesTickets, ServerConfig, ServerConnectionData}; + +use ring::constant_time; + +use std::sync::Arc; + +pub(super) use client_hello::CompleteClientHelloHandling; + +mod client_hello { + use crate::enums::SignatureScheme; + use crate::msgs::enums::ECPointFormat; + use crate::msgs::enums::{ClientCertificateType, Compression}; + use crate::msgs::handshake::ServerECDHParams; + use crate::msgs::handshake::{CertificateRequestPayload, ClientSessionTicket, Random}; + use crate::msgs::handshake::{CertificateStatus, ECDHEServerKeyExchange}; + use crate::msgs::handshake::{ClientExtension, SessionId}; + use crate::msgs::handshake::{ClientHelloPayload, ServerHelloPayload}; + use crate::msgs::handshake::{ServerExtension, ServerKeyExchangePayload}; + use crate::sign; + use crate::verify::DigitallySignedStruct; + + use super::*; + + pub(in crate::server) struct CompleteClientHelloHandling { + pub(in crate::server) config: Arc, + pub(in crate::server) transcript: HandshakeHash, + pub(in crate::server) session_id: SessionId, + pub(in crate::server) suite: &'static Tls12CipherSuite, + pub(in crate::server) using_ems: bool, + pub(in crate::server) randoms: ConnectionRandoms, + pub(in crate::server) send_ticket: bool, + pub(in crate::server) extra_exts: Vec, + } + + impl CompleteClientHelloHandling { + pub(in crate::server) fn handle_client_hello( + mut self, + cx: &mut ServerContext<'_>, + server_key: ActiveCertifiedKey, + chm: &Message, + client_hello: &ClientHelloPayload, + sigschemes_ext: Vec, + tls13_enabled: bool, + ) -> hs::NextStateOrError { + // -- TLS1.2 only from hereon in -- + self.transcript.add_message(chm); + + if client_hello.ems_support_offered() { + self.using_ems = true; + } + + let groups_ext = client_hello + .get_namedgroups_extension() + .ok_or_else(|| { + cx.common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerIncompatible::NamedGroupsExtensionRequired, + ) + })?; + let ecpoints_ext = client_hello + .get_ecpoints_extension() + .ok_or_else(|| { + cx.common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerIncompatible::EcPointsExtensionRequired, + ) + })?; + + trace!("namedgroups {:?}", groups_ext); + trace!("ecpoints {:?}", ecpoints_ext); + + if !ecpoints_ext.contains(&ECPointFormat::Uncompressed) { + return Err(cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerIncompatible::UncompressedEcPointsRequired, + )); + } + + // -- If TLS1.3 is enabled, signal the downgrade in the server random + if tls13_enabled { + self.randoms.server[24..].copy_from_slice(&tls12::DOWNGRADE_SENTINEL); + } + + // -- Check for resumption -- + // We can do this either by (in order of preference): + // 1. receiving a ticket that decrypts + // 2. receiving a sessionid that is in our cache + // + // If we receive a ticket, the sessionid won't be in our + // cache, so don't check. + // + // If either works, we end up with a ServerConnectionValue + // which is passed to start_resumption and concludes + // our handling of the ClientHello. + // + let mut ticket_received = false; + let resume_data = client_hello + .get_ticket_extension() + .and_then(|ticket_ext| match ticket_ext { + ClientExtension::SessionTicket(ClientSessionTicket::Offer(ticket)) => { + Some(ticket) + } + _ => None, + }) + .and_then(|ticket| { + ticket_received = true; + debug!("Ticket received"); + let data = self.config.ticketer.decrypt(&ticket.0); + if data.is_none() { + debug!("Ticket didn't decrypt"); + } + data + }) + .or_else(|| { + // Perhaps resume? If we received a ticket, the sessionid + // does not correspond to a real session. + if client_hello.session_id.is_empty() || ticket_received { + return None; + } + + self.config + .session_storage + .get(&client_hello.session_id.get_encoding()) + }) + .and_then(|x| persist::ServerSessionValue::read_bytes(&x).ok()) + .filter(|resumedata| { + hs::can_resume(self.suite.into(), &cx.data.sni, self.using_ems, resumedata) + }); + + if let Some(data) = resume_data { + return self.start_resumption(cx, client_hello, &client_hello.session_id, data); + } + + // Now we have chosen a ciphersuite, we can make kx decisions. + let sigschemes = self + .suite + .resolve_sig_schemes(&sigschemes_ext); + + if sigschemes.is_empty() { + return Err(cx.common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerIncompatible::NoSignatureSchemesInCommon, + )); + } + + let group = self + .config + .kx_groups + .iter() + .find(|skxg| groups_ext.contains(&skxg.name)) + .cloned() + .ok_or_else(|| { + cx.common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerIncompatible::NoKxGroupsInCommon, + ) + })?; + + let ecpoint = ECPointFormat::SUPPORTED + .iter() + .find(|format| ecpoints_ext.contains(format)) + .cloned() + .ok_or_else(|| { + cx.common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerIncompatible::NoEcPointFormatsInCommon, + ) + })?; + + debug_assert_eq!(ecpoint, ECPointFormat::Uncompressed); + + let (mut ocsp_response, mut sct_list) = + (server_key.get_ocsp(), server_key.get_sct_list()); + + // If we're not offered a ticket or a potential session ID, allocate a session ID. + if !self.config.session_storage.can_cache() { + self.session_id = SessionId::empty(); + } else if self.session_id.is_empty() && !ticket_received { + self.session_id = SessionId::random()?; + } + + self.send_ticket = emit_server_hello( + &self.config, + &mut self.transcript, + cx, + self.session_id, + self.suite, + self.using_ems, + &mut ocsp_response, + &mut sct_list, + client_hello, + None, + &self.randoms, + self.extra_exts, + )?; + emit_certificate(&mut self.transcript, cx.common, server_key.get_cert()); + if let Some(ocsp_response) = ocsp_response { + emit_cert_status(&mut self.transcript, cx.common, ocsp_response); + } + let server_kx = emit_server_kx( + &mut self.transcript, + cx.common, + sigschemes, + group, + server_key.get_key(), + &self.randoms, + )?; + let doing_client_auth = emit_certificate_req(&self.config, &mut self.transcript, cx)?; + emit_server_hello_done(&mut self.transcript, cx.common); + + if doing_client_auth { + Ok(Box::new(ExpectCertificate { + config: self.config, + transcript: self.transcript, + randoms: self.randoms, + session_id: self.session_id, + suite: self.suite, + using_ems: self.using_ems, + server_kx, + send_ticket: self.send_ticket, + })) + } else { + Ok(Box::new(ExpectClientKx { + config: self.config, + transcript: self.transcript, + randoms: self.randoms, + session_id: self.session_id, + suite: self.suite, + using_ems: self.using_ems, + server_kx, + client_cert: None, + send_ticket: self.send_ticket, + })) + } + } + + fn start_resumption( + mut self, + cx: &mut ServerContext<'_>, + client_hello: &ClientHelloPayload, + id: &SessionId, + resumedata: persist::ServerSessionValue, + ) -> hs::NextStateOrError { + debug!("Resuming connection"); + + if resumedata.extended_ms && !self.using_ems { + return Err(cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::ResumptionAttemptedWithVariedEms, + )); + } + + self.session_id = *id; + self.send_ticket = emit_server_hello( + &self.config, + &mut self.transcript, + cx, + self.session_id, + self.suite, + self.using_ems, + &mut None, + &mut None, + client_hello, + Some(&resumedata), + &self.randoms, + self.extra_exts, + )?; + + let secrets = ConnectionSecrets::new_resume( + self.randoms, + self.suite, + &resumedata.master_secret.0, + ); + self.config.key_log.log( + "CLIENT_RANDOM", + &secrets.randoms.client, + &secrets.master_secret, + ); + cx.common + .start_encryption_tls12(&secrets, Side::Server); + cx.common.peer_certificates = resumedata.client_cert_chain; + + if self.send_ticket { + emit_ticket( + &secrets, + &mut self.transcript, + self.using_ems, + cx, + &*self.config.ticketer, + )?; + } + emit_ccs(cx.common); + cx.common + .record_layer + .start_encrypting(); + emit_finished(&secrets, &mut self.transcript, cx.common); + + Ok(Box::new(ExpectCcs { + config: self.config, + secrets, + transcript: self.transcript, + session_id: self.session_id, + using_ems: self.using_ems, + resuming: true, + send_ticket: self.send_ticket, + })) + } + } + + fn emit_server_hello( + config: &ServerConfig, + transcript: &mut HandshakeHash, + cx: &mut ServerContext<'_>, + session_id: SessionId, + suite: &'static Tls12CipherSuite, + using_ems: bool, + ocsp_response: &mut Option<&[u8]>, + sct_list: &mut Option<&[u8]>, + hello: &ClientHelloPayload, + resumedata: Option<&persist::ServerSessionValue>, + randoms: &ConnectionRandoms, + extra_exts: Vec, + ) -> Result { + let mut ep = hs::ExtensionProcessing::new(); + ep.process_common( + config, + cx, + ocsp_response, + sct_list, + hello, + resumedata, + extra_exts, + )?; + ep.process_tls12(config, hello, using_ems); + + let sh = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::ServerHello, + payload: HandshakePayload::ServerHello(ServerHelloPayload { + legacy_version: ProtocolVersion::TLSv1_2, + random: Random::from(randoms.server), + session_id, + cipher_suite: suite.common.suite, + compression_method: Compression::Null, + extensions: ep.exts, + }), + }), + }; + + trace!("sending server hello {:?}", sh); + transcript.add_message(&sh); + cx.common.send_msg(sh, false); + Ok(ep.send_ticket) + } + + fn emit_certificate( + transcript: &mut HandshakeHash, + common: &mut CommonState, + cert_chain: &[Certificate], + ) { + let c = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::Certificate, + payload: HandshakePayload::Certificate(cert_chain.to_owned()), + }), + }; + + transcript.add_message(&c); + common.send_msg(c, false); + } + + fn emit_cert_status(transcript: &mut HandshakeHash, common: &mut CommonState, ocsp: &[u8]) { + let st = CertificateStatus::new(ocsp.to_owned()); + + let c = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::CertificateStatus, + payload: HandshakePayload::CertificateStatus(st), + }), + }; + + transcript.add_message(&c); + common.send_msg(c, false); + } + + fn emit_server_kx( + transcript: &mut HandshakeHash, + common: &mut CommonState, + sigschemes: Vec, + skxg: &'static kx::SupportedKxGroup, + signing_key: &dyn sign::SigningKey, + randoms: &ConnectionRandoms, + ) -> Result { + let kx = kx::KeyExchange::start(skxg).ok_or(Error::FailedToGetRandomBytes)?; + let secdh = ServerECDHParams::new(skxg.name, kx.pubkey.as_ref()); + + let mut msg = Vec::new(); + msg.extend(randoms.client); + msg.extend(randoms.server); + secdh.encode(&mut msg); + + let signer = signing_key + .choose_scheme(&sigschemes) + .ok_or_else(|| Error::General("incompatible signing key".to_string()))?; + let sigscheme = signer.scheme(); + let sig = signer.sign(&msg)?; + + let skx = ServerKeyExchangePayload::ECDHE(ECDHEServerKeyExchange { + params: secdh, + dss: DigitallySignedStruct::new(sigscheme, sig), + }); + + let m = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::ServerKeyExchange, + payload: HandshakePayload::ServerKeyExchange(skx), + }), + }; + + transcript.add_message(&m); + common.send_msg(m, false); + Ok(kx) + } + + fn emit_certificate_req( + config: &ServerConfig, + transcript: &mut HandshakeHash, + cx: &mut ServerContext<'_>, + ) -> Result { + let client_auth = &config.verifier; + + if !client_auth.offer_client_auth() { + return Ok(false); + } + + let verify_schemes = client_auth.supported_verify_schemes(); + + let names = config + .verifier + .client_auth_root_subjects() + .to_vec(); + + let cr = CertificateRequestPayload { + certtypes: vec![ + ClientCertificateType::RSASign, + ClientCertificateType::ECDSASign, + ], + sigschemes: verify_schemes, + canames: names, + }; + + let m = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::CertificateRequest, + payload: HandshakePayload::CertificateRequest(cr), + }), + }; + + trace!("Sending CertificateRequest {:?}", m); + transcript.add_message(&m); + cx.common.send_msg(m, false); + Ok(true) + } + + fn emit_server_hello_done(transcript: &mut HandshakeHash, common: &mut CommonState) { + let m = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::ServerHelloDone, + payload: HandshakePayload::ServerHelloDone, + }), + }; + + transcript.add_message(&m); + common.send_msg(m, false); + } +} + +// --- Process client's Certificate for client auth --- +struct ExpectCertificate { + config: Arc, + transcript: HandshakeHash, + randoms: ConnectionRandoms, + session_id: SessionId, + suite: &'static Tls12CipherSuite, + using_ems: bool, + server_kx: kx::KeyExchange, + send_ticket: bool, +} + +impl State for ExpectCertificate { + fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { + self.transcript.add_message(&m); + let cert_chain = require_handshake_msg_move!( + m, + HandshakeType::Certificate, + HandshakePayload::Certificate + )?; + + // If we can't determine if the auth is mandatory, abort + let mandatory = self + .config + .verifier + .client_auth_mandatory(); + + trace!("certs {:?}", cert_chain); + + let client_cert = match cert_chain.split_first() { + None if mandatory => { + return Err(cx.common.send_fatal_alert( + AlertDescription::CertificateRequired, + Error::NoCertificatesPresented, + )); + } + None => { + debug!("client auth requested but no certificate supplied"); + self.transcript.abandon_client_auth(); + None + } + Some((end_entity, intermediates)) => { + let now = std::time::SystemTime::now(); + self.config + .verifier + .verify_client_cert(end_entity, intermediates, now) + .map_err(|err| { + cx.common + .send_cert_verify_error_alert(err) + })?; + + Some(cert_chain) + } + }; + + Ok(Box::new(ExpectClientKx { + config: self.config, + transcript: self.transcript, + randoms: self.randoms, + session_id: self.session_id, + suite: self.suite, + using_ems: self.using_ems, + server_kx: self.server_kx, + client_cert, + send_ticket: self.send_ticket, + })) + } +} + +// --- Process client's KeyExchange --- +struct ExpectClientKx { + config: Arc, + transcript: HandshakeHash, + randoms: ConnectionRandoms, + session_id: SessionId, + suite: &'static Tls12CipherSuite, + using_ems: bool, + server_kx: kx::KeyExchange, + client_cert: Option>, + send_ticket: bool, +} + +impl State for ExpectClientKx { + fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { + let client_kx = require_handshake_msg!( + m, + HandshakeType::ClientKeyExchange, + HandshakePayload::ClientKeyExchange + )?; + self.transcript.add_message(&m); + let ems_seed = self + .using_ems + .then(|| self.transcript.get_current_hash()); + + // Complete key agreement, and set up encryption with the + // resulting premaster secret. + let peer_kx_params = + tls12::decode_ecdh_params::(cx.common, &client_kx.0)?; + let secrets = ConnectionSecrets::from_key_exchange( + self.server_kx, + &peer_kx_params.public.0, + ems_seed, + self.randoms, + self.suite, + )?; + + self.config.key_log.log( + "CLIENT_RANDOM", + &secrets.randoms.client, + &secrets.master_secret, + ); + cx.common + .start_encryption_tls12(&secrets, Side::Server); + + if let Some(client_cert) = self.client_cert { + Ok(Box::new(ExpectCertificateVerify { + config: self.config, + secrets, + transcript: self.transcript, + session_id: self.session_id, + using_ems: self.using_ems, + client_cert, + send_ticket: self.send_ticket, + })) + } else { + Ok(Box::new(ExpectCcs { + config: self.config, + secrets, + transcript: self.transcript, + session_id: self.session_id, + using_ems: self.using_ems, + resuming: false, + send_ticket: self.send_ticket, + })) + } + } +} + +// --- Process client's certificate proof --- +struct ExpectCertificateVerify { + config: Arc, + secrets: ConnectionSecrets, + transcript: HandshakeHash, + session_id: SessionId, + using_ems: bool, + client_cert: Vec, + send_ticket: bool, +} + +impl State for ExpectCertificateVerify { + fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { + let rc = { + let sig = require_handshake_msg!( + m, + HandshakeType::CertificateVerify, + HandshakePayload::CertificateVerify + )?; + + match self.transcript.take_handshake_buf() { + Some(msgs) => { + let certs = &self.client_cert; + self.config + .verifier + .verify_tls12_signature(&msgs, &certs[0], sig) + } + None => { + // This should be unreachable; the handshake buffer was initialized with + // client authentication if the verifier wants to offer it. + // `transcript.abandon_client_auth()` can extract it, but its only caller in + // this flow will also set `ExpectClientKx::client_cert` to `None`, making it + // impossible to reach this state. + return Err(cx.common.send_fatal_alert( + AlertDescription::AccessDenied, + Error::General("client authentication not set up".into()), + )); + } + } + }; + + if let Err(e) = rc { + return Err(cx + .common + .send_cert_verify_error_alert(e)); + } + + trace!("client CertificateVerify OK"); + cx.common.peer_certificates = Some(self.client_cert); + + self.transcript.add_message(&m); + Ok(Box::new(ExpectCcs { + config: self.config, + secrets: self.secrets, + transcript: self.transcript, + session_id: self.session_id, + using_ems: self.using_ems, + resuming: false, + send_ticket: self.send_ticket, + })) + } +} + +// --- Process client's ChangeCipherSpec --- +struct ExpectCcs { + config: Arc, + secrets: ConnectionSecrets, + transcript: HandshakeHash, + session_id: SessionId, + using_ems: bool, + resuming: bool, + send_ticket: bool, +} + +impl State for ExpectCcs { + fn handle(self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { + match m.payload { + MessagePayload::ChangeCipherSpec(..) => {} + payload => { + return Err(inappropriate_message( + &payload, + &[ContentType::ChangeCipherSpec], + )) + } + } + + // CCS should not be received interleaved with fragmented handshake-level + // message. + cx.common.check_aligned_handshake()?; + + cx.common + .record_layer + .start_decrypting(); + Ok(Box::new(ExpectFinished { + config: self.config, + secrets: self.secrets, + transcript: self.transcript, + session_id: self.session_id, + using_ems: self.using_ems, + resuming: self.resuming, + send_ticket: self.send_ticket, + })) + } +} + +// --- Process client's Finished --- +fn get_server_connection_value_tls12( + secrets: &ConnectionSecrets, + using_ems: bool, + cx: &ServerContext<'_>, + time_now: ticketer::TimeBase, +) -> persist::ServerSessionValue { + let version = ProtocolVersion::TLSv1_2; + let secret = secrets.get_master_secret(); + + let mut v = persist::ServerSessionValue::new( + cx.data.sni.as_ref(), + version, + secrets.suite().common.suite, + secret, + cx.common.peer_certificates.clone(), + cx.common.alpn_protocol.clone(), + cx.data.resumption_data.clone(), + time_now, + 0, + ); + + if using_ems { + v.set_extended_ms_used(); + } + + v +} + +fn emit_ticket( + secrets: &ConnectionSecrets, + transcript: &mut HandshakeHash, + using_ems: bool, + cx: &mut ServerContext<'_>, + ticketer: &dyn ProducesTickets, +) -> Result<(), Error> { + let time_now = ticketer::TimeBase::now()?; + let plain = get_server_connection_value_tls12(secrets, using_ems, cx, time_now).get_encoding(); + + // If we can't produce a ticket for some reason, we can't + // report an error. Send an empty one. + let ticket = ticketer + .encrypt(&plain) + .unwrap_or_default(); + let ticket_lifetime = ticketer.lifetime(); + + let m = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::NewSessionTicket, + payload: HandshakePayload::NewSessionTicket(NewSessionTicketPayload::new( + ticket_lifetime, + ticket, + )), + }), + }; + + transcript.add_message(&m); + cx.common.send_msg(m, false); + Ok(()) +} + +fn emit_ccs(common: &mut CommonState) { + let m = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}), + }; + + common.send_msg(m, false); +} + +fn emit_finished( + secrets: &ConnectionSecrets, + transcript: &mut HandshakeHash, + common: &mut CommonState, +) { + let vh = transcript.get_current_hash(); + let verify_data = secrets.server_verify_data(&vh); + let verify_data_payload = Payload::new(verify_data); + + let f = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::Finished, + payload: HandshakePayload::Finished(verify_data_payload), + }), + }; + + transcript.add_message(&f); + common.send_msg(f, true); +} + +struct ExpectFinished { + config: Arc, + secrets: ConnectionSecrets, + transcript: HandshakeHash, + session_id: SessionId, + using_ems: bool, + resuming: bool, + send_ticket: bool, +} + +impl State for ExpectFinished { + fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { + let finished = + require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; + + cx.common.check_aligned_handshake()?; + + let vh = self.transcript.get_current_hash(); + let expect_verify_data = self.secrets.client_verify_data(&vh); + + let _fin_verified = + constant_time::verify_slices_are_equal(&expect_verify_data, &finished.0) + .map_err(|_| { + cx.common + .send_fatal_alert(AlertDescription::DecryptError, Error::DecryptError) + }) + .map(|_| verify::FinishedMessageVerified::assertion())?; + + // Save connection, perhaps + if !self.resuming && !self.session_id.is_empty() { + let time_now = ticketer::TimeBase::now()?; + let value = + get_server_connection_value_tls12(&self.secrets, self.using_ems, cx, time_now); + + let worked = self + .config + .session_storage + .put(self.session_id.get_encoding(), value.get_encoding()); + if worked { + debug!("Session saved"); + } else { + debug!("Session not saved"); + } + } + + // Send our CCS and Finished. + self.transcript.add_message(&m); + if !self.resuming { + if self.send_ticket { + emit_ticket( + &self.secrets, + &mut self.transcript, + self.using_ems, + cx, + &*self.config.ticketer, + )?; + } + emit_ccs(cx.common); + cx.common + .record_layer + .start_encrypting(); + emit_finished(&self.secrets, &mut self.transcript, cx.common); + } + + cx.common.start_traffic(); + Ok(Box::new(ExpectTraffic { + secrets: self.secrets, + _fin_verified, + })) + } +} + +// --- Process traffic --- +struct ExpectTraffic { + secrets: ConnectionSecrets, + _fin_verified: verify::FinishedMessageVerified, +} + +impl ExpectTraffic {} + +impl State for ExpectTraffic { + fn handle(self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { + match m.payload { + MessagePayload::ApplicationData(payload) => cx + .common + .take_received_plaintext(payload), + payload => { + return Err(inappropriate_message( + &payload, + &[ContentType::ApplicationData], + )); + } + } + Ok(self) + } + + fn export_keying_material( + &self, + output: &mut [u8], + label: &[u8], + context: Option<&[u8]>, + ) -> Result<(), Error> { + self.secrets + .export_keying_material(output, label, context); + Ok(()) + } + + #[cfg(feature = "secret_extraction")] + fn extract_secrets(&self) -> Result { + self.secrets + .extract_secrets(Side::Server) + } +} diff --git a/vendor/rustls-0.21.8/src/server/tls13.rs b/vendor/rustls-0.21.8/src/server/tls13.rs new file mode 100644 index 0000000000000..7ce4d0ba7bea7 --- /dev/null +++ b/vendor/rustls-0.21.8/src/server/tls13.rs @@ -0,0 +1,1325 @@ +use crate::check::inappropriate_handshake_message; +#[cfg(feature = "quic")] +use crate::check::inappropriate_message; +#[cfg(feature = "quic")] +use crate::common_state::Protocol; +#[cfg(feature = "secret_extraction")] +use crate::common_state::Side; +use crate::common_state::{CommonState, State}; +use crate::conn::ConnectionRandoms; +use crate::enums::ProtocolVersion; +use crate::enums::{AlertDescription, ContentType, HandshakeType}; +use crate::error::{Error, PeerIncompatible, PeerMisbehaved}; +use crate::hash_hs::HandshakeHash; +use crate::key::Certificate; +#[cfg(feature = "logging")] +use crate::log::{debug, trace, warn}; +use crate::msgs::codec::Codec; +use crate::msgs::enums::KeyUpdateRequest; +use crate::msgs::handshake::HandshakeMessagePayload; +use crate::msgs::handshake::HandshakePayload; +use crate::msgs::handshake::{NewSessionTicketExtension, NewSessionTicketPayloadTLS13}; +use crate::msgs::message::{Message, MessagePayload}; +use crate::msgs::persist; +use crate::rand; +use crate::server::ServerConfig; +#[cfg(feature = "secret_extraction")] +use crate::suites::PartiallyExtractedSecrets; +use crate::ticketer; +use crate::tls13::key_schedule::{KeyScheduleTraffic, KeyScheduleTrafficWithClientFinishedPending}; +use crate::tls13::Tls13CipherSuite; +use crate::verify; + +use super::hs::{self, HandshakeHashOrBuffer, ServerContext}; +use super::server_conn::ServerConnectionData; + +use std::sync::Arc; + +use ring::constant_time; + +pub(super) use client_hello::CompleteClientHelloHandling; + +mod client_hello { + use crate::enums::SignatureScheme; + use crate::kx; + use crate::msgs::base::{Payload, PayloadU8}; + use crate::msgs::ccs::ChangeCipherSpecPayload; + use crate::msgs::enums::NamedGroup; + use crate::msgs::enums::{Compression, PSKKeyExchangeMode}; + use crate::msgs::handshake::CertReqExtension; + use crate::msgs::handshake::CertificateEntry; + use crate::msgs::handshake::CertificateExtension; + use crate::msgs::handshake::CertificatePayloadTLS13; + use crate::msgs::handshake::CertificateRequestPayloadTLS13; + use crate::msgs::handshake::CertificateStatus; + use crate::msgs::handshake::ClientHelloPayload; + use crate::msgs::handshake::HelloRetryExtension; + use crate::msgs::handshake::HelloRetryRequest; + use crate::msgs::handshake::KeyShareEntry; + use crate::msgs::handshake::Random; + use crate::msgs::handshake::ServerExtension; + use crate::msgs::handshake::ServerHelloPayload; + use crate::msgs::handshake::SessionId; + use crate::server::common::ActiveCertifiedKey; + use crate::sign; + use crate::tls13::key_schedule::{ + KeyScheduleEarly, KeyScheduleHandshake, KeySchedulePreHandshake, + }; + use crate::verify::DigitallySignedStruct; + + use super::*; + + #[derive(PartialEq)] + pub(super) enum EarlyDataDecision { + Disabled, + RequestedButRejected, + Accepted, + } + + pub(in crate::server) struct CompleteClientHelloHandling { + pub(in crate::server) config: Arc, + pub(in crate::server) transcript: HandshakeHash, + pub(in crate::server) suite: &'static Tls13CipherSuite, + pub(in crate::server) randoms: ConnectionRandoms, + pub(in crate::server) done_retry: bool, + pub(in crate::server) send_tickets: usize, + pub(in crate::server) extra_exts: Vec, + } + + fn max_early_data_size(configured: u32) -> usize { + if configured != 0 { + configured as usize + } else { + // The relevant max_early_data_size may in fact be unknowable: if + // we (the server) have turned off early_data but the client has + // a stale ticket from when we allowed early_data: we'll naturally + // reject early_data but need an upper bound on the amount of data + // to drop. + // + // Use a single maximum-sized message. + 16384 + } + } + + impl CompleteClientHelloHandling { + fn check_binder( + &self, + suite: &'static Tls13CipherSuite, + client_hello: &Message, + psk: &[u8], + binder: &[u8], + ) -> bool { + let binder_plaintext = match &client_hello.payload { + MessagePayload::Handshake { parsed, .. } => { + parsed.get_encoding_for_binder_signing() + } + _ => unreachable!(), + }; + + let handshake_hash = self + .transcript + .get_hash_given(&binder_plaintext); + + let key_schedule = KeyScheduleEarly::new(suite, psk); + let real_binder = + key_schedule.resumption_psk_binder_key_and_sign_verify_data(&handshake_hash); + + constant_time::verify_slices_are_equal(real_binder.as_ref(), binder).is_ok() + } + + fn attempt_tls13_ticket_decryption( + &mut self, + ticket: &[u8], + ) -> Option { + if self.config.ticketer.enabled() { + self.config + .ticketer + .decrypt(ticket) + .and_then(|plain| persist::ServerSessionValue::read_bytes(&plain).ok()) + } else { + self.config + .session_storage + .take(ticket) + .and_then(|plain| persist::ServerSessionValue::read_bytes(&plain).ok()) + } + } + + pub(in crate::server) fn handle_client_hello( + mut self, + cx: &mut ServerContext<'_>, + server_key: ActiveCertifiedKey, + chm: &Message, + client_hello: &ClientHelloPayload, + mut sigschemes_ext: Vec, + ) -> hs::NextStateOrError { + if client_hello.compression_methods.len() != 1 { + return Err(cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::OfferedIncorrectCompressions, + )); + } + + let groups_ext = client_hello + .get_namedgroups_extension() + .ok_or_else(|| { + cx.common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerIncompatible::NamedGroupsExtensionRequired, + ) + })?; + + let tls13_schemes = sign::supported_sign_tls13(); + sigschemes_ext.retain(|scheme| tls13_schemes.contains(scheme)); + + let shares_ext = client_hello + .get_keyshare_extension() + .ok_or_else(|| { + cx.common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerIncompatible::KeyShareExtensionRequired, + ) + })?; + + if client_hello.has_keyshare_extension_with_duplicates() { + return Err(cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::OfferedDuplicateKeyShares, + )); + } + + let early_data_requested = client_hello.early_data_extension_offered(); + + // EarlyData extension is illegal in second ClientHello + if self.done_retry && early_data_requested { + return Err({ + cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::EarlyDataAttemptedInSecondClientHello, + ) + }); + } + + // choose a share that we support + let chosen_share = self + .config + .kx_groups + .iter() + .find_map(|group| { + shares_ext + .iter() + .find(|share| share.group == group.name) + }); + + let chosen_share = match chosen_share { + Some(s) => s, + None => { + // We don't have a suitable key share. Choose a suitable group and + // send a HelloRetryRequest. + let retry_group_maybe = self + .config + .kx_groups + .iter() + .find(|group| groups_ext.contains(&group.name)) + .cloned(); + + self.transcript.add_message(chm); + + if let Some(group) = retry_group_maybe { + if self.done_retry { + return Err(cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::RefusedToFollowHelloRetryRequest, + )); + } + + emit_hello_retry_request( + &mut self.transcript, + self.suite, + client_hello.session_id, + cx.common, + group.name, + ); + emit_fake_ccs(cx.common); + + let skip_early_data = max_early_data_size(self.config.max_early_data_size); + + let next = Box::new(hs::ExpectClientHello { + config: self.config, + transcript: HandshakeHashOrBuffer::Hash(self.transcript), + #[cfg(feature = "tls12")] + session_id: SessionId::empty(), + #[cfg(feature = "tls12")] + using_ems: false, + done_retry: true, + send_tickets: self.send_tickets, + extra_exts: self.extra_exts, + }); + + return if early_data_requested { + Ok(Box::new(ExpectAndSkipRejectedEarlyData { + skip_data_left: skip_early_data, + next, + })) + } else { + Ok(next) + }; + } + + return Err(cx.common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerIncompatible::NoKxGroupsInCommon, + )); + } + }; + + let mut chosen_psk_index = None; + let mut resumedata = None; + let time_now = ticketer::TimeBase::now()?; + + if let Some(psk_offer) = client_hello.get_psk() { + if !client_hello.check_psk_ext_is_last() { + return Err(cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::PskExtensionMustBeLast, + )); + } + + // "A client MUST provide a "psk_key_exchange_modes" extension if it + // offers a "pre_shared_key" extension. If clients offer + // "pre_shared_key" without a "psk_key_exchange_modes" extension, + // servers MUST abort the handshake." - RFC8446 4.2.9 + if client_hello.get_psk_modes().is_none() { + return Err(cx.common.send_fatal_alert( + AlertDescription::MissingExtension, + PeerMisbehaved::MissingPskModesExtension, + )); + } + + if psk_offer.binders.is_empty() { + return Err(cx.common.send_fatal_alert( + AlertDescription::DecodeError, + PeerMisbehaved::MissingBinderInPskExtension, + )); + } + + if psk_offer.binders.len() != psk_offer.identities.len() { + return Err(cx.common.send_fatal_alert( + AlertDescription::IllegalParameter, + PeerMisbehaved::PskExtensionWithMismatchedIdsAndBinders, + )); + } + + for (i, psk_id) in psk_offer.identities.iter().enumerate() { + let resume = match self + .attempt_tls13_ticket_decryption(&psk_id.identity.0) + .map(|resumedata| { + resumedata.set_freshness(psk_id.obfuscated_ticket_age, time_now) + }) + .filter(|resumedata| { + hs::can_resume(self.suite.into(), &cx.data.sni, false, resumedata) + }) { + Some(resume) => resume, + None => continue, + }; + + if !self.check_binder( + self.suite, + chm, + &resume.master_secret.0, + psk_offer.binders[i].as_ref(), + ) { + return Err(cx.common.send_fatal_alert( + AlertDescription::DecryptError, + PeerMisbehaved::IncorrectBinder, + )); + } + + chosen_psk_index = Some(i); + resumedata = Some(resume); + break; + } + } + + if !client_hello.psk_mode_offered(PSKKeyExchangeMode::PSK_DHE_KE) { + debug!("Client unwilling to resume, DHE_KE not offered"); + self.send_tickets = 0; + chosen_psk_index = None; + resumedata = None; + } else { + self.send_tickets = self.config.send_tls13_tickets; + } + + if let Some(ref resume) = resumedata { + cx.data.received_resumption_data = Some(resume.application_data.0.clone()); + cx.common.peer_certificates = resume.client_cert_chain.clone(); + } + + let full_handshake = resumedata.is_none(); + self.transcript.add_message(chm); + let key_schedule = emit_server_hello( + &mut self.transcript, + &self.randoms, + self.suite, + cx, + &client_hello.session_id, + chosen_share, + chosen_psk_index, + resumedata + .as_ref() + .map(|x| &x.master_secret.0[..]), + &self.config, + )?; + if !self.done_retry { + emit_fake_ccs(cx.common); + } + + let (mut ocsp_response, mut sct_list) = + (server_key.get_ocsp(), server_key.get_sct_list()); + let doing_early_data = emit_encrypted_extensions( + &mut self.transcript, + self.suite, + cx, + &mut ocsp_response, + &mut sct_list, + client_hello, + resumedata.as_ref(), + self.extra_exts, + &self.config, + )?; + + let doing_client_auth = if full_handshake { + let client_auth = + emit_certificate_req_tls13(&mut self.transcript, cx, &self.config)?; + emit_certificate_tls13( + &mut self.transcript, + cx.common, + server_key.get_cert(), + ocsp_response, + sct_list, + ); + emit_certificate_verify_tls13( + &mut self.transcript, + cx.common, + server_key.get_key(), + &sigschemes_ext, + )?; + client_auth + } else { + false + }; + + // If we're not doing early data, then the next messages we receive + // are encrypted with the handshake keys. + match doing_early_data { + EarlyDataDecision::Disabled => { + key_schedule.set_handshake_decrypter(None, cx.common); + cx.data.early_data.reject(); + } + EarlyDataDecision::RequestedButRejected => { + debug!("Client requested early_data, but not accepted: switching to handshake keys with trial decryption"); + key_schedule.set_handshake_decrypter( + Some(max_early_data_size(self.config.max_early_data_size)), + cx.common, + ); + cx.data.early_data.reject(); + } + EarlyDataDecision::Accepted => { + cx.data + .early_data + .accept(self.config.max_early_data_size as usize); + } + } + + cx.common.check_aligned_handshake()?; + let key_schedule_traffic = emit_finished_tls13( + &mut self.transcript, + &self.randoms, + cx, + key_schedule, + &self.config, + ); + + if !doing_client_auth && self.config.send_half_rtt_data { + // Application data can be sent immediately after Finished, in one + // flight. However, if client auth is enabled, we don't want to send + // application data to an unauthenticated peer. + cx.common.start_outgoing_traffic(); + } + + if doing_client_auth { + Ok(Box::new(ExpectCertificate { + config: self.config, + transcript: self.transcript, + suite: self.suite, + key_schedule: key_schedule_traffic, + send_tickets: self.send_tickets, + })) + } else if doing_early_data == EarlyDataDecision::Accepted && !cx.common.is_quic() { + // Not used for QUIC: RFC 9001 §8.3: Clients MUST NOT send the EndOfEarlyData + // message. A server MUST treat receipt of a CRYPTO frame in a 0-RTT packet as a + // connection error of type PROTOCOL_VIOLATION. + Ok(Box::new(ExpectEarlyData { + config: self.config, + transcript: self.transcript, + suite: self.suite, + key_schedule: key_schedule_traffic, + send_tickets: self.send_tickets, + })) + } else { + Ok(Box::new(ExpectFinished { + config: self.config, + transcript: self.transcript, + suite: self.suite, + key_schedule: key_schedule_traffic, + send_tickets: self.send_tickets, + })) + } + } + } + + fn emit_server_hello( + transcript: &mut HandshakeHash, + randoms: &ConnectionRandoms, + suite: &'static Tls13CipherSuite, + cx: &mut ServerContext<'_>, + session_id: &SessionId, + share: &KeyShareEntry, + chosen_psk_idx: Option, + resuming_psk: Option<&[u8]>, + config: &ServerConfig, + ) -> Result { + let mut extensions = Vec::new(); + + // Prepare key exchange + let kx = kx::KeyExchange::choose(share.group, &config.kx_groups) + .and_then(kx::KeyExchange::start) + .ok_or(Error::FailedToGetRandomBytes)?; + + let kse = KeyShareEntry::new(share.group, kx.pubkey.as_ref()); + extensions.push(ServerExtension::KeyShare(kse)); + extensions.push(ServerExtension::SupportedVersions(ProtocolVersion::TLSv1_3)); + + if let Some(psk_idx) = chosen_psk_idx { + extensions.push(ServerExtension::PresharedKey(psk_idx as u16)); + } + + let sh = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::ServerHello, + payload: HandshakePayload::ServerHello(ServerHelloPayload { + legacy_version: ProtocolVersion::TLSv1_2, + random: Random::from(randoms.server), + session_id: *session_id, + cipher_suite: suite.common.suite, + compression_method: Compression::Null, + extensions, + }), + }), + }; + + cx.common.check_aligned_handshake()?; + + let client_hello_hash = transcript.get_hash_given(&[]); + + trace!("sending server hello {:?}", sh); + transcript.add_message(&sh); + cx.common.send_msg(sh, false); + + // Start key schedule + let key_schedule_pre_handshake = if let Some(psk) = resuming_psk { + let early_key_schedule = KeyScheduleEarly::new(suite, psk); + early_key_schedule.client_early_traffic_secret( + &client_hello_hash, + &*config.key_log, + &randoms.client, + cx.common, + ); + + KeySchedulePreHandshake::from(early_key_schedule) + } else { + KeySchedulePreHandshake::new(suite) + }; + + // Do key exchange + let key_schedule = kx.complete(&share.payload.0, |secret| { + key_schedule_pre_handshake.into_handshake(secret) + })?; + + let handshake_hash = transcript.get_current_hash(); + let key_schedule = key_schedule.derive_server_handshake_secrets( + handshake_hash, + &*config.key_log, + &randoms.client, + cx.common, + ); + + Ok(key_schedule) + } + + fn emit_fake_ccs(common: &mut CommonState) { + if common.is_quic() { + return; + } + let m = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}), + }; + common.send_msg(m, false); + } + + fn emit_hello_retry_request( + transcript: &mut HandshakeHash, + suite: &'static Tls13CipherSuite, + session_id: SessionId, + common: &mut CommonState, + group: NamedGroup, + ) { + let mut req = HelloRetryRequest { + legacy_version: ProtocolVersion::TLSv1_2, + session_id, + cipher_suite: suite.common.suite, + extensions: Vec::new(), + }; + + req.extensions + .push(HelloRetryExtension::KeyShare(group)); + req.extensions + .push(HelloRetryExtension::SupportedVersions( + ProtocolVersion::TLSv1_3, + )); + + let m = Message { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::HelloRetryRequest, + payload: HandshakePayload::HelloRetryRequest(req), + }), + }; + + trace!("Requesting retry {:?}", m); + transcript.rollup_for_hrr(); + transcript.add_message(&m); + common.send_msg(m, false); + } + + #[allow(clippy::needless_pass_by_ref_mut)] // cx only mutated if cfg(feature = "quic") + fn decide_if_early_data_allowed( + cx: &mut ServerContext<'_>, + client_hello: &ClientHelloPayload, + resumedata: Option<&persist::ServerSessionValue>, + suite: &'static Tls13CipherSuite, + config: &ServerConfig, + ) -> EarlyDataDecision { + let early_data_requested = client_hello.early_data_extension_offered(); + let rejected_or_disabled = match early_data_requested { + true => EarlyDataDecision::RequestedButRejected, + false => EarlyDataDecision::Disabled, + }; + + let resume = match resumedata { + Some(resume) => resume, + None => { + // never any early data if not resuming. + return rejected_or_disabled; + } + }; + + /* Non-zero max_early_data_size controls whether early_data is allowed at all. + * We also require stateful resumption. */ + let early_data_configured = config.max_early_data_size > 0 && !config.ticketer.enabled(); + + /* "For PSKs provisioned via NewSessionTicket, a server MUST validate + * that the ticket age for the selected PSK identity (computed by + * subtracting ticket_age_add from PskIdentity.obfuscated_ticket_age + * modulo 2^32) is within a small tolerance of the time since the ticket + * was issued (see Section 8)." -- this is implemented in ServerSessionValue::set_freshness() + * and related. + * + * "In order to accept early data, the server [...] MUST verify that the + * following values are the same as those associated with the + * selected PSK: + * + * - The TLS version number + * - The selected cipher suite + * - The selected ALPN [RFC7301] protocol, if any" + * + * (RFC8446, 4.2.10) */ + let early_data_possible = early_data_requested + && resume.is_fresh() + && Some(resume.version) == cx.common.negotiated_version + && resume.cipher_suite == suite.common.suite + && resume.alpn.as_ref().map(|x| &x.0) == cx.common.alpn_protocol.as_ref(); + + if early_data_configured && early_data_possible && !cx.data.early_data.was_rejected() { + EarlyDataDecision::Accepted + } else { + #[cfg(feature = "quic")] + if cx.common.is_quic() { + // Clobber value set in tls13::emit_server_hello + cx.common.quic.early_secret = None; + } + + rejected_or_disabled + } + } + + fn emit_encrypted_extensions( + transcript: &mut HandshakeHash, + suite: &'static Tls13CipherSuite, + cx: &mut ServerContext<'_>, + ocsp_response: &mut Option<&[u8]>, + sct_list: &mut Option<&[u8]>, + hello: &ClientHelloPayload, + resumedata: Option<&persist::ServerSessionValue>, + extra_exts: Vec, + config: &ServerConfig, + ) -> Result { + let mut ep = hs::ExtensionProcessing::new(); + ep.process_common( + config, + cx, + ocsp_response, + sct_list, + hello, + resumedata, + extra_exts, + )?; + + let early_data = decide_if_early_data_allowed(cx, hello, resumedata, suite, config); + if early_data == EarlyDataDecision::Accepted { + ep.exts.push(ServerExtension::EarlyData); + } + + let ee = Message { + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::EncryptedExtensions, + payload: HandshakePayload::EncryptedExtensions(ep.exts), + }), + }; + + trace!("sending encrypted extensions {:?}", ee); + transcript.add_message(&ee); + cx.common.send_msg(ee, true); + Ok(early_data) + } + + fn emit_certificate_req_tls13( + transcript: &mut HandshakeHash, + cx: &mut ServerContext<'_>, + config: &ServerConfig, + ) -> Result { + if !config.verifier.offer_client_auth() { + return Ok(false); + } + + let mut cr = CertificateRequestPayloadTLS13 { + context: PayloadU8::empty(), + extensions: Vec::new(), + }; + + let schemes = config + .verifier + .supported_verify_schemes(); + cr.extensions + .push(CertReqExtension::SignatureAlgorithms(schemes.to_vec())); + + let names = config + .verifier + .client_auth_root_subjects() + .to_vec(); + + if !names.is_empty() { + cr.extensions + .push(CertReqExtension::AuthorityNames(names)); + } + + let m = Message { + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::CertificateRequest, + payload: HandshakePayload::CertificateRequestTLS13(cr), + }), + }; + + trace!("Sending CertificateRequest {:?}", m); + transcript.add_message(&m); + cx.common.send_msg(m, true); + Ok(true) + } + + fn emit_certificate_tls13( + transcript: &mut HandshakeHash, + common: &mut CommonState, + cert_chain: &[Certificate], + ocsp_response: Option<&[u8]>, + sct_list: Option<&[u8]>, + ) { + let mut cert_entries = vec![]; + for cert in cert_chain { + let entry = CertificateEntry { + cert: cert.to_owned(), + exts: Vec::new(), + }; + + cert_entries.push(entry); + } + + if let Some(end_entity_cert) = cert_entries.first_mut() { + // Apply OCSP response to first certificate (we don't support OCSP + // except for leaf certs). + if let Some(ocsp) = ocsp_response { + let cst = CertificateStatus::new(ocsp.to_owned()); + end_entity_cert + .exts + .push(CertificateExtension::CertificateStatus(cst)); + } + + // Likewise, SCT + if let Some(sct_list) = sct_list { + end_entity_cert + .exts + .push(CertificateExtension::make_sct(sct_list.to_owned())); + } + } + + let cert_body = CertificatePayloadTLS13::new(cert_entries); + let c = Message { + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::Certificate, + payload: HandshakePayload::CertificateTLS13(cert_body), + }), + }; + + trace!("sending certificate {:?}", c); + transcript.add_message(&c); + common.send_msg(c, true); + } + + fn emit_certificate_verify_tls13( + transcript: &mut HandshakeHash, + common: &mut CommonState, + signing_key: &dyn sign::SigningKey, + schemes: &[SignatureScheme], + ) -> Result<(), Error> { + let message = verify::construct_tls13_server_verify_message(&transcript.get_current_hash()); + + let signer = signing_key + .choose_scheme(schemes) + .ok_or_else(|| { + common.send_fatal_alert( + AlertDescription::HandshakeFailure, + PeerIncompatible::NoSignatureSchemesInCommon, + ) + })?; + + let scheme = signer.scheme(); + let sig = signer.sign(&message)?; + + let cv = DigitallySignedStruct::new(scheme, sig); + + let m = Message { + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::CertificateVerify, + payload: HandshakePayload::CertificateVerify(cv), + }), + }; + + trace!("sending certificate-verify {:?}", m); + transcript.add_message(&m); + common.send_msg(m, true); + Ok(()) + } + + fn emit_finished_tls13( + transcript: &mut HandshakeHash, + randoms: &ConnectionRandoms, + cx: &mut ServerContext<'_>, + key_schedule: KeyScheduleHandshake, + config: &ServerConfig, + ) -> KeyScheduleTrafficWithClientFinishedPending { + let handshake_hash = transcript.get_current_hash(); + let verify_data = key_schedule.sign_server_finish(&handshake_hash); + let verify_data_payload = Payload::new(verify_data.as_ref()); + + let m = Message { + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::Finished, + payload: HandshakePayload::Finished(verify_data_payload), + }), + }; + + trace!("sending finished {:?}", m); + transcript.add_message(&m); + let hash_at_server_fin = transcript.get_current_hash(); + cx.common.send_msg(m, true); + + // Now move to application data keys. Read key change is deferred until + // the Finish message is received & validated. + key_schedule.into_traffic_with_client_finished_pending( + hash_at_server_fin, + &*config.key_log, + &randoms.client, + cx.common, + ) + } +} + +struct ExpectAndSkipRejectedEarlyData { + skip_data_left: usize, + next: Box, +} + +impl State for ExpectAndSkipRejectedEarlyData { + fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { + /* "The server then ignores early data by skipping all records with an external + * content type of "application_data" (indicating that they are encrypted), + * up to the configured max_early_data_size." + * (RFC8446, 14.2.10) */ + if let MessagePayload::ApplicationData(ref skip_data) = m.payload { + if skip_data.0.len() <= self.skip_data_left { + self.skip_data_left -= skip_data.0.len(); + return Ok(self); + } + } + + self.next.handle(cx, m) + } +} + +struct ExpectCertificate { + config: Arc, + transcript: HandshakeHash, + suite: &'static Tls13CipherSuite, + key_schedule: KeyScheduleTrafficWithClientFinishedPending, + send_tickets: usize, +} + +impl State for ExpectCertificate { + fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { + let certp = require_handshake_msg!( + m, + HandshakeType::Certificate, + HandshakePayload::CertificateTLS13 + )?; + self.transcript.add_message(&m); + + // We don't send any CertificateRequest extensions, so any extensions + // here are illegal. + if certp.any_entry_has_extension() { + return Err(PeerMisbehaved::UnsolicitedCertExtension.into()); + } + + let client_cert = certp.convert(); + + let mandatory = self + .config + .verifier + .client_auth_mandatory(); + + let (end_entity, intermediates) = match client_cert.split_first() { + None => { + if !mandatory { + debug!("client auth requested but no certificate supplied"); + self.transcript.abandon_client_auth(); + return Ok(Box::new(ExpectFinished { + config: self.config, + suite: self.suite, + key_schedule: self.key_schedule, + transcript: self.transcript, + send_tickets: self.send_tickets, + })); + } + + return Err(cx.common.send_fatal_alert( + AlertDescription::CertificateRequired, + Error::NoCertificatesPresented, + )); + } + Some(chain) => chain, + }; + + let now = std::time::SystemTime::now(); + self.config + .verifier + .verify_client_cert(end_entity, intermediates, now) + .map_err(|err| { + cx.common + .send_cert_verify_error_alert(err) + })?; + + Ok(Box::new(ExpectCertificateVerify { + config: self.config, + suite: self.suite, + transcript: self.transcript, + key_schedule: self.key_schedule, + client_cert, + send_tickets: self.send_tickets, + })) + } +} + +struct ExpectCertificateVerify { + config: Arc, + transcript: HandshakeHash, + suite: &'static Tls13CipherSuite, + key_schedule: KeyScheduleTrafficWithClientFinishedPending, + client_cert: Vec, + send_tickets: usize, +} + +impl State for ExpectCertificateVerify { + fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { + let rc = { + let sig = require_handshake_msg!( + m, + HandshakeType::CertificateVerify, + HandshakePayload::CertificateVerify + )?; + let handshake_hash = self.transcript.get_current_hash(); + self.transcript.abandon_client_auth(); + let certs = &self.client_cert; + let msg = verify::construct_tls13_client_verify_message(&handshake_hash); + + self.config + .verifier + .verify_tls13_signature(&msg, &certs[0], sig) + }; + + if let Err(e) = rc { + return Err(cx + .common + .send_cert_verify_error_alert(e)); + } + + trace!("client CertificateVerify OK"); + cx.common.peer_certificates = Some(self.client_cert); + + self.transcript.add_message(&m); + Ok(Box::new(ExpectFinished { + config: self.config, + suite: self.suite, + key_schedule: self.key_schedule, + transcript: self.transcript, + send_tickets: self.send_tickets, + })) + } +} + +// --- Process (any number of) early ApplicationData messages, +// followed by a terminating handshake EndOfEarlyData message --- + +struct ExpectEarlyData { + config: Arc, + transcript: HandshakeHash, + suite: &'static Tls13CipherSuite, + key_schedule: KeyScheduleTrafficWithClientFinishedPending, + send_tickets: usize, +} + +impl State for ExpectEarlyData { + fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { + match m.payload { + MessagePayload::ApplicationData(payload) => { + match cx + .data + .early_data + .take_received_plaintext(payload) + { + true => Ok(self), + false => Err(cx.common.send_fatal_alert( + AlertDescription::UnexpectedMessage, + PeerMisbehaved::TooMuchEarlyDataReceived, + )), + } + } + MessagePayload::Handshake { + parsed: + HandshakeMessagePayload { + typ: HandshakeType::EndOfEarlyData, + payload: HandshakePayload::EndOfEarlyData, + }, + .. + } => { + self.key_schedule + .update_decrypter(cx.common); + self.transcript.add_message(&m); + Ok(Box::new(ExpectFinished { + config: self.config, + suite: self.suite, + key_schedule: self.key_schedule, + transcript: self.transcript, + send_tickets: self.send_tickets, + })) + } + payload => Err(inappropriate_handshake_message( + &payload, + &[ContentType::ApplicationData, ContentType::Handshake], + &[HandshakeType::EndOfEarlyData], + )), + } + } +} + +// --- Process client's Finished --- +fn get_server_session_value( + transcript: &HandshakeHash, + suite: &'static Tls13CipherSuite, + key_schedule: &KeyScheduleTraffic, + cx: &ServerContext<'_>, + nonce: &[u8], + time_now: ticketer::TimeBase, + age_obfuscation_offset: u32, +) -> persist::ServerSessionValue { + let version = ProtocolVersion::TLSv1_3; + + let handshake_hash = transcript.get_current_hash(); + let secret = + key_schedule.resumption_master_secret_and_derive_ticket_psk(&handshake_hash, nonce); + + persist::ServerSessionValue::new( + cx.data.sni.as_ref(), + version, + suite.common.suite, + secret, + cx.common.peer_certificates.clone(), + cx.common.alpn_protocol.clone(), + cx.data.resumption_data.clone(), + time_now, + age_obfuscation_offset, + ) +} + +struct ExpectFinished { + config: Arc, + transcript: HandshakeHash, + suite: &'static Tls13CipherSuite, + key_schedule: KeyScheduleTrafficWithClientFinishedPending, + send_tickets: usize, +} + +impl ExpectFinished { + fn emit_ticket( + transcript: &HandshakeHash, + suite: &'static Tls13CipherSuite, + cx: &mut ServerContext<'_>, + key_schedule: &KeyScheduleTraffic, + config: &ServerConfig, + ) -> Result<(), Error> { + let nonce = rand::random_vec(32)?; + let now = ticketer::TimeBase::now()?; + let age_add = rand::random_u32()?; + let plain = + get_server_session_value(transcript, suite, key_schedule, cx, &nonce, now, age_add) + .get_encoding(); + + let stateless = config.ticketer.enabled(); + let (ticket, lifetime) = if stateless { + let ticket = match config.ticketer.encrypt(&plain) { + Some(t) => t, + None => return Ok(()), + }; + (ticket, config.ticketer.lifetime()) + } else { + let id = rand::random_vec(32)?; + let stored = config + .session_storage + .put(id.clone(), plain); + if !stored { + trace!("resumption not available; not issuing ticket"); + return Ok(()); + } + let stateful_lifetime = 24 * 60 * 60; // this is a bit of a punt + (id, stateful_lifetime) + }; + + let mut payload = NewSessionTicketPayloadTLS13::new(lifetime, age_add, nonce, ticket); + + if config.max_early_data_size > 0 { + if !stateless { + payload + .exts + .push(NewSessionTicketExtension::EarlyData( + config.max_early_data_size, + )); + } else { + // We implement RFC8446 section 8.1: by enforcing that 0-RTT is + // only possible if using stateful resumption + warn!("early_data with stateless resumption is not allowed"); + } + } + + let m = Message { + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::NewSessionTicket, + payload: HandshakePayload::NewSessionTicketTLS13(payload), + }), + }; + + trace!("sending new ticket {:?} (stateless: {})", m, stateless); + cx.common.send_msg(m, true); + Ok(()) + } +} + +impl State for ExpectFinished { + fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { + let finished = + require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; + + let handshake_hash = self.transcript.get_current_hash(); + let (key_schedule_traffic, expect_verify_data) = self + .key_schedule + .sign_client_finish(&handshake_hash, cx.common); + + let fin = constant_time::verify_slices_are_equal(expect_verify_data.as_ref(), &finished.0) + .map_err(|_| { + warn!("Finished wrong"); + cx.common + .send_fatal_alert(AlertDescription::DecryptError, Error::DecryptError) + }) + .map(|_| verify::FinishedMessageVerified::assertion())?; + + // nb. future derivations include Client Finished, but not the + // main application data keying. + self.transcript.add_message(&m); + + cx.common.check_aligned_handshake()?; + + for _ in 0..self.send_tickets { + Self::emit_ticket( + &self.transcript, + self.suite, + cx, + &key_schedule_traffic, + &self.config, + )?; + } + + // Application data may now flow, even if we have client auth enabled. + cx.common.start_traffic(); + + #[cfg(feature = "quic")] + { + if cx.common.protocol == Protocol::Quic { + return Ok(Box::new(ExpectQuicTraffic { + key_schedule: key_schedule_traffic, + _fin_verified: fin, + })); + } + } + + Ok(Box::new(ExpectTraffic { + key_schedule: key_schedule_traffic, + _fin_verified: fin, + })) + } +} + +// --- Process traffic --- +struct ExpectTraffic { + key_schedule: KeyScheduleTraffic, + _fin_verified: verify::FinishedMessageVerified, +} + +impl ExpectTraffic { + fn handle_key_update( + &mut self, + common: &mut CommonState, + key_update_request: &KeyUpdateRequest, + ) -> Result<(), Error> { + #[cfg(feature = "quic")] + { + if let Protocol::Quic = common.protocol { + return Err(common.send_fatal_alert( + AlertDescription::UnexpectedMessage, + PeerMisbehaved::KeyUpdateReceivedInQuicConnection, + )); + } + } + + common.check_aligned_handshake()?; + + if common.should_update_key(key_update_request)? { + self.key_schedule + .update_encrypter_and_notify(common); + } + + // Update our read-side keys. + self.key_schedule + .update_decrypter(common); + Ok(()) + } +} + +impl State for ExpectTraffic { + fn handle(mut self: Box, cx: &mut ServerContext, m: Message) -> hs::NextStateOrError { + match m.payload { + MessagePayload::ApplicationData(payload) => cx + .common + .take_received_plaintext(payload), + MessagePayload::Handshake { + parsed: + HandshakeMessagePayload { + payload: HandshakePayload::KeyUpdate(key_update), + .. + }, + .. + } => self.handle_key_update(cx.common, &key_update)?, + payload => { + return Err(inappropriate_handshake_message( + &payload, + &[ContentType::ApplicationData, ContentType::Handshake], + &[HandshakeType::KeyUpdate], + )); + } + } + + Ok(self) + } + + fn export_keying_material( + &self, + output: &mut [u8], + label: &[u8], + context: Option<&[u8]>, + ) -> Result<(), Error> { + self.key_schedule + .export_keying_material(output, label, context) + } + + #[cfg(feature = "secret_extraction")] + fn extract_secrets(&self) -> Result { + self.key_schedule + .extract_secrets(Side::Server) + } +} + +#[cfg(feature = "quic")] +struct ExpectQuicTraffic { + key_schedule: KeyScheduleTraffic, + _fin_verified: verify::FinishedMessageVerified, +} + +#[cfg(feature = "quic")] +impl State for ExpectQuicTraffic { + fn handle(self: Box, _cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { + // reject all messages + Err(inappropriate_message(&m.payload, &[])) + } + + fn export_keying_material( + &self, + output: &mut [u8], + label: &[u8], + context: Option<&[u8]>, + ) -> Result<(), Error> { + self.key_schedule + .export_keying_material(output, label, context) + } +} diff --git a/vendor/rustls-0.21.8/src/sign.rs b/vendor/rustls-0.21.8/src/sign.rs new file mode 100644 index 0000000000000..b2d3965dc7599 --- /dev/null +++ b/vendor/rustls-0.21.8/src/sign.rs @@ -0,0 +1,467 @@ +use crate::enums::{SignatureAlgorithm, SignatureScheme}; +use crate::error::Error; +use crate::key; +use crate::x509::{wrap_in_asn1_len, wrap_in_sequence}; + +use ring::io::der; +use ring::rand::{SecureRandom, SystemRandom}; +use ring::signature::{self, EcdsaKeyPair, Ed25519KeyPair, RsaKeyPair}; + +use std::error::Error as StdError; +use std::fmt; +use std::sync::Arc; + +/// An abstract signing key. +pub trait SigningKey: Send + Sync { + /// Choose a `SignatureScheme` from those offered. + /// + /// Expresses the choice by returning something that implements `Signer`, + /// using the chosen scheme. + fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option>; + + /// What kind of key we have. + fn algorithm(&self) -> SignatureAlgorithm; +} + +/// A thing that can sign a message. +pub trait Signer: Send + Sync { + /// Signs `message` using the selected scheme. + fn sign(&self, message: &[u8]) -> Result, Error>; + + /// Reveals which scheme will be used when you call `sign()`. + fn scheme(&self) -> SignatureScheme; +} + +/// A packaged-together certificate chain, matching `SigningKey` and +/// optional stapled OCSP response and/or SCT list. +#[derive(Clone)] +pub struct CertifiedKey { + /// The certificate chain. + pub cert: Vec, + + /// The certified key. + pub key: Arc, + + /// An optional OCSP response from the certificate issuer, + /// attesting to its continued validity. + pub ocsp: Option>, + + /// An optional collection of SCTs from CT logs, proving the + /// certificate is included on those logs. This must be + /// a `SignedCertificateTimestampList` encoding; see RFC6962. + pub sct_list: Option>, +} + +impl CertifiedKey { + /// Make a new CertifiedKey, with the given chain and key. + /// + /// The cert chain must not be empty. The first certificate in the chain + /// must be the end-entity certificate. + pub fn new(cert: Vec, key: Arc) -> Self { + Self { + cert, + key, + ocsp: None, + sct_list: None, + } + } + + /// The end-entity certificate. + pub fn end_entity_cert(&self) -> Result<&key::Certificate, SignError> { + self.cert.first().ok_or(SignError(())) + } +} + +/// Parse `der` as any supported key encoding/type, returning +/// the first which works. +pub fn any_supported_type(der: &key::PrivateKey) -> Result, SignError> { + if let Ok(rsa) = RsaSigningKey::new(der) { + Ok(Arc::new(rsa)) + } else if let Ok(ecdsa) = any_ecdsa_type(der) { + Ok(ecdsa) + } else { + any_eddsa_type(der) + } +} + +/// Parse `der` as any ECDSA key type, returning the first which works. +/// +/// Both SEC1 (PEM section starting with 'BEGIN EC PRIVATE KEY') and PKCS8 +/// (PEM section starting with 'BEGIN PRIVATE KEY') encodings are supported. +pub fn any_ecdsa_type(der: &key::PrivateKey) -> Result, SignError> { + if let Ok(ecdsa_p256) = EcdsaSigningKey::new( + der, + SignatureScheme::ECDSA_NISTP256_SHA256, + &signature::ECDSA_P256_SHA256_ASN1_SIGNING, + ) { + return Ok(Arc::new(ecdsa_p256)); + } + + if let Ok(ecdsa_p384) = EcdsaSigningKey::new( + der, + SignatureScheme::ECDSA_NISTP384_SHA384, + &signature::ECDSA_P384_SHA384_ASN1_SIGNING, + ) { + return Ok(Arc::new(ecdsa_p384)); + } + + Err(SignError(())) +} + +/// Parse `der` as any EdDSA key type, returning the first which works. +pub fn any_eddsa_type(der: &key::PrivateKey) -> Result, SignError> { + if let Ok(ed25519) = Ed25519SigningKey::new(der, SignatureScheme::ED25519) { + return Ok(Arc::new(ed25519)); + } + + // TODO: Add support for Ed448 + + Err(SignError(())) +} + +/// A `SigningKey` for RSA-PKCS1 or RSA-PSS. +/// +/// This is used by the test suite, so it must be `pub`, but it isn't part of +/// the public, stable, API. +#[doc(hidden)] +pub struct RsaSigningKey { + key: Arc, +} + +static ALL_RSA_SCHEMES: &[SignatureScheme] = &[ + SignatureScheme::RSA_PSS_SHA512, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA256, + SignatureScheme::RSA_PKCS1_SHA512, + SignatureScheme::RSA_PKCS1_SHA384, + SignatureScheme::RSA_PKCS1_SHA256, +]; + +impl RsaSigningKey { + /// Make a new `RsaSigningKey` from a DER encoding, in either + /// PKCS#1 or PKCS#8 format. + pub fn new(der: &key::PrivateKey) -> Result { + RsaKeyPair::from_der(&der.0) + .or_else(|_| RsaKeyPair::from_pkcs8(&der.0)) + .map(|s| Self { key: Arc::new(s) }) + .map_err(|_| SignError(())) + } +} + +impl SigningKey for RsaSigningKey { + fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option> { + ALL_RSA_SCHEMES + .iter() + .find(|scheme| offered.contains(scheme)) + .map(|scheme| RsaSigner::new(Arc::clone(&self.key), *scheme)) + } + + fn algorithm(&self) -> SignatureAlgorithm { + SignatureAlgorithm::RSA + } +} + +struct RsaSigner { + key: Arc, + scheme: SignatureScheme, + encoding: &'static dyn signature::RsaEncoding, +} + +impl RsaSigner { + fn new(key: Arc, scheme: SignatureScheme) -> Box { + let encoding: &dyn signature::RsaEncoding = match scheme { + SignatureScheme::RSA_PKCS1_SHA256 => &signature::RSA_PKCS1_SHA256, + SignatureScheme::RSA_PKCS1_SHA384 => &signature::RSA_PKCS1_SHA384, + SignatureScheme::RSA_PKCS1_SHA512 => &signature::RSA_PKCS1_SHA512, + SignatureScheme::RSA_PSS_SHA256 => &signature::RSA_PSS_SHA256, + SignatureScheme::RSA_PSS_SHA384 => &signature::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA512 => &signature::RSA_PSS_SHA512, + _ => unreachable!(), + }; + + Box::new(Self { + key, + scheme, + encoding, + }) + } +} + +impl Signer for RsaSigner { + fn sign(&self, message: &[u8]) -> Result, Error> { + let mut sig = vec![0; self.key.public().modulus_len()]; + + let rng = ring::rand::SystemRandom::new(); + self.key + .sign(self.encoding, &rng, message, &mut sig) + .map(|_| sig) + .map_err(|_| Error::General("signing failed".to_string())) + } + + fn scheme(&self) -> SignatureScheme { + self.scheme + } +} + +/// A SigningKey that uses exactly one TLS-level SignatureScheme +/// and one ring-level signature::SigningAlgorithm. +/// +/// Compare this to RsaSigningKey, which for a particular key is +/// willing to sign with several algorithms. This is quite poor +/// cryptography practice, but is necessary because a given RSA key +/// is expected to work in TLS1.2 (PKCS#1 signatures) and TLS1.3 +/// (PSS signatures) -- nobody is willing to obtain certificates for +/// different protocol versions. +/// +/// Currently this is only implemented for ECDSA keys. +struct EcdsaSigningKey { + key: Arc, + scheme: SignatureScheme, +} + +impl EcdsaSigningKey { + /// Make a new `ECDSASigningKey` from a DER encoding in PKCS#8 or SEC1 + /// format, expecting a key usable with precisely the given signature + /// scheme. + fn new( + der: &key::PrivateKey, + scheme: SignatureScheme, + sigalg: &'static signature::EcdsaSigningAlgorithm, + ) -> Result { + let rng = SystemRandom::new(); + EcdsaKeyPair::from_pkcs8(sigalg, &der.0, &rng) + .map_err(|_| ()) + .or_else(|_| Self::convert_sec1_to_pkcs8(scheme, sigalg, &der.0, &rng)) + .map(|kp| Self { + key: Arc::new(kp), + scheme, + }) + } + + /// Convert a SEC1 encoding to PKCS8, and ask ring to parse it. This + /// can be removed once https://github.com/briansmith/ring/pull/1456 + /// (or equivalent) is landed. + fn convert_sec1_to_pkcs8( + scheme: SignatureScheme, + sigalg: &'static signature::EcdsaSigningAlgorithm, + maybe_sec1_der: &[u8], + rng: &dyn SecureRandom, + ) -> Result { + let pkcs8_prefix = match scheme { + SignatureScheme::ECDSA_NISTP256_SHA256 => &PKCS8_PREFIX_ECDSA_NISTP256, + SignatureScheme::ECDSA_NISTP384_SHA384 => &PKCS8_PREFIX_ECDSA_NISTP384, + _ => unreachable!(), // all callers are in this file + }; + + // wrap sec1 encoding in an OCTET STRING + let mut sec1_wrap = Vec::with_capacity(maybe_sec1_der.len() + 8); + sec1_wrap.extend_from_slice(maybe_sec1_der); + wrap_in_asn1_len(&mut sec1_wrap); + sec1_wrap.insert(0, der::Tag::OctetString as u8); + + let mut pkcs8 = Vec::with_capacity(pkcs8_prefix.len() + sec1_wrap.len() + 4); + pkcs8.extend_from_slice(pkcs8_prefix); + pkcs8.extend_from_slice(&sec1_wrap); + wrap_in_sequence(&mut pkcs8); + + EcdsaKeyPair::from_pkcs8(sigalg, &pkcs8, rng).map_err(|_| ()) + } +} + +// This is (line-by-line): +// - INTEGER Version = 0 +// - SEQUENCE (privateKeyAlgorithm) +// - id-ecPublicKey OID +// - prime256v1 OID +const PKCS8_PREFIX_ECDSA_NISTP256: &[u8] = b"\x02\x01\x00\ + \x30\x13\ + \x06\x07\x2a\x86\x48\xce\x3d\x02\x01\ + \x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"; + +// This is (line-by-line): +// - INTEGER Version = 0 +// - SEQUENCE (privateKeyAlgorithm) +// - id-ecPublicKey OID +// - secp384r1 OID +const PKCS8_PREFIX_ECDSA_NISTP384: &[u8] = b"\x02\x01\x00\ + \x30\x10\ + \x06\x07\x2a\x86\x48\xce\x3d\x02\x01\ + \x06\x05\x2b\x81\x04\x00\x22"; + +impl SigningKey for EcdsaSigningKey { + fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option> { + if offered.contains(&self.scheme) { + Some(Box::new(EcdsaSigner { + key: Arc::clone(&self.key), + scheme: self.scheme, + })) + } else { + None + } + } + + fn algorithm(&self) -> SignatureAlgorithm { + self.scheme.sign() + } +} + +struct EcdsaSigner { + key: Arc, + scheme: SignatureScheme, +} + +impl Signer for EcdsaSigner { + fn sign(&self, message: &[u8]) -> Result, Error> { + let rng = ring::rand::SystemRandom::new(); + self.key + .sign(&rng, message) + .map_err(|_| Error::General("signing failed".into())) + .map(|sig| sig.as_ref().into()) + } + + fn scheme(&self) -> SignatureScheme { + self.scheme + } +} + +/// A SigningKey that uses exactly one TLS-level SignatureScheme +/// and one ring-level signature::SigningAlgorithm. +/// +/// Compare this to RsaSigningKey, which for a particular key is +/// willing to sign with several algorithms. This is quite poor +/// cryptography practice, but is necessary because a given RSA key +/// is expected to work in TLS1.2 (PKCS#1 signatures) and TLS1.3 +/// (PSS signatures) -- nobody is willing to obtain certificates for +/// different protocol versions. +/// +/// Currently this is only implemented for Ed25519 keys. +struct Ed25519SigningKey { + key: Arc, + scheme: SignatureScheme, +} + +impl Ed25519SigningKey { + /// Make a new `Ed25519SigningKey` from a DER encoding in PKCS#8 format, + /// expecting a key usable with precisely the given signature scheme. + fn new(der: &key::PrivateKey, scheme: SignatureScheme) -> Result { + Ed25519KeyPair::from_pkcs8_maybe_unchecked(&der.0) + .map(|kp| Self { + key: Arc::new(kp), + scheme, + }) + .map_err(|_| SignError(())) + } +} + +impl SigningKey for Ed25519SigningKey { + fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option> { + if offered.contains(&self.scheme) { + Some(Box::new(Ed25519Signer { + key: Arc::clone(&self.key), + scheme: self.scheme, + })) + } else { + None + } + } + + fn algorithm(&self) -> SignatureAlgorithm { + self.scheme.sign() + } +} + +struct Ed25519Signer { + key: Arc, + scheme: SignatureScheme, +} + +impl Signer for Ed25519Signer { + fn sign(&self, message: &[u8]) -> Result, Error> { + Ok(self.key.sign(message).as_ref().into()) + } + + fn scheme(&self) -> SignatureScheme { + self.scheme + } +} + +/// The set of schemes we support for signatures and +/// that are allowed for TLS1.3. +pub fn supported_sign_tls13() -> &'static [SignatureScheme] { + &[ + SignatureScheme::ECDSA_NISTP384_SHA384, + SignatureScheme::ECDSA_NISTP256_SHA256, + SignatureScheme::RSA_PSS_SHA512, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA256, + SignatureScheme::ED25519, + ] +} + +/// Errors while signing +#[derive(Debug)] +pub struct SignError(()); + +impl fmt::Display for SignError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("sign error") + } +} + +impl StdError for SignError {} + +#[test] +fn can_load_ecdsa_nistp256_pkcs8() { + let key = key::PrivateKey(include_bytes!("testdata/nistp256key.pkcs8.der").to_vec()); + assert!(any_supported_type(&key).is_ok()); + assert!(any_ecdsa_type(&key).is_ok()); + assert!(any_eddsa_type(&key).is_err()); +} + +#[test] +fn can_load_ecdsa_nistp256_sec1() { + let key = key::PrivateKey(include_bytes!("testdata/nistp256key.der").to_vec()); + assert!(any_supported_type(&key).is_ok()); + assert!(any_ecdsa_type(&key).is_ok()); + assert!(any_eddsa_type(&key).is_err()); +} + +#[test] +fn can_load_ecdsa_nistp384_pkcs8() { + let key = key::PrivateKey(include_bytes!("testdata/nistp384key.pkcs8.der").to_vec()); + assert!(any_supported_type(&key).is_ok()); + assert!(any_ecdsa_type(&key).is_ok()); + assert!(any_eddsa_type(&key).is_err()); +} + +#[test] +fn can_load_ecdsa_nistp384_sec1() { + let key = key::PrivateKey(include_bytes!("testdata/nistp384key.der").to_vec()); + assert!(any_supported_type(&key).is_ok()); + assert!(any_ecdsa_type(&key).is_ok()); + assert!(any_eddsa_type(&key).is_err()); +} + +#[test] +fn can_load_eddsa_pkcs8() { + let key = key::PrivateKey(include_bytes!("testdata/eddsakey.der").to_vec()); + assert!(any_supported_type(&key).is_ok()); + assert!(any_eddsa_type(&key).is_ok()); + assert!(any_ecdsa_type(&key).is_err()); +} + +#[test] +fn can_load_rsa2048_pkcs8() { + let key = key::PrivateKey(include_bytes!("testdata/rsa2048key.pkcs8.der").to_vec()); + assert!(any_supported_type(&key).is_ok()); + assert!(any_eddsa_type(&key).is_err()); + assert!(any_ecdsa_type(&key).is_err()); +} + +#[test] +fn can_load_rsa2048_pkcs1() { + let key = key::PrivateKey(include_bytes!("testdata/rsa2048key.pkcs1.der").to_vec()); + assert!(any_supported_type(&key).is_ok()); + assert!(any_eddsa_type(&key).is_err()); + assert!(any_ecdsa_type(&key).is_err()); +} diff --git a/vendor/rustls-0.21.8/src/stream.rs b/vendor/rustls-0.21.8/src/stream.rs new file mode 100644 index 0000000000000..58f324ec69159 --- /dev/null +++ b/vendor/rustls-0.21.8/src/stream.rs @@ -0,0 +1,238 @@ +use crate::conn::{ConnectionCommon, SideData}; + +use std::io::{IoSlice, Read, Result, Write}; +use std::ops::{Deref, DerefMut}; + +/// This type implements `io::Read` and `io::Write`, encapsulating +/// a Connection `C` and an underlying transport `T`, such as a socket. +/// +/// This allows you to use a rustls Connection like a normal stream. +#[derive(Debug)] +pub struct Stream<'a, C: 'a + ?Sized, T: 'a + Read + Write + ?Sized> { + /// Our TLS connection + pub conn: &'a mut C, + + /// The underlying transport, like a socket + pub sock: &'a mut T, +} + +impl<'a, C, T, S> Stream<'a, C, T> +where + C: 'a + DerefMut + Deref>, + T: 'a + Read + Write, + S: SideData, +{ + /// Make a new Stream using the Connection `conn` and socket-like object + /// `sock`. This does not fail and does no IO. + pub fn new(conn: &'a mut C, sock: &'a mut T) -> Self { + Self { conn, sock } + } + + /// If we're handshaking, complete all the IO for that. + /// If we have data to write, write it all. + fn complete_prior_io(&mut self) -> Result<()> { + if self.conn.is_handshaking() { + self.conn.complete_io(self.sock)?; + } + + if self.conn.wants_write() { + self.conn.complete_io(self.sock)?; + } + + Ok(()) + } +} + +impl<'a, C, T, S> Read for Stream<'a, C, T> +where + C: 'a + DerefMut + Deref>, + T: 'a + Read + Write, + S: SideData, +{ + fn read(&mut self, buf: &mut [u8]) -> Result { + self.complete_prior_io()?; + + // We call complete_io() in a loop since a single call may read only + // a partial packet from the underlying transport. A full packet is + // needed to get more plaintext, which we must do if EOF has not been + // hit. + while self.conn.wants_read() { + if self.conn.complete_io(self.sock)?.0 == 0 { + break; + } + } + + self.conn.reader().read(buf) + } + + #[cfg(read_buf)] + fn read_buf(&mut self, cursor: std::io::BorrowedCursor<'_>) -> Result<()> { + self.complete_prior_io()?; + + // We call complete_io() in a loop since a single call may read only + // a partial packet from the underlying transport. A full packet is + // needed to get more plaintext, which we must do if EOF has not been + // hit. + while self.conn.wants_read() { + if self.conn.complete_io(self.sock)?.0 == 0 { + break; + } + } + + self.conn.reader().read_buf(cursor) + } +} + +impl<'a, C, T, S> Write for Stream<'a, C, T> +where + C: 'a + DerefMut + Deref>, + T: 'a + Read + Write, + S: SideData, +{ + fn write(&mut self, buf: &[u8]) -> Result { + self.complete_prior_io()?; + + let len = self.conn.writer().write(buf)?; + + // Try to write the underlying transport here, but don't let + // any errors mask the fact we've consumed `len` bytes. + // Callers will learn of permanent errors on the next call. + let _ = self.conn.complete_io(self.sock); + + Ok(len) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { + self.complete_prior_io()?; + + let len = self + .conn + .writer() + .write_vectored(bufs)?; + + // Try to write the underlying transport here, but don't let + // any errors mask the fact we've consumed `len` bytes. + // Callers will learn of permanent errors on the next call. + let _ = self.conn.complete_io(self.sock); + + Ok(len) + } + + fn flush(&mut self) -> Result<()> { + self.complete_prior_io()?; + + self.conn.writer().flush()?; + if self.conn.wants_write() { + self.conn.complete_io(self.sock)?; + } + Ok(()) + } +} + +/// This type implements `io::Read` and `io::Write`, encapsulating +/// and owning a Connection `C` and an underlying blocking transport +/// `T`, such as a socket. +/// +/// This allows you to use a rustls Connection like a normal stream. +#[derive(Debug)] +pub struct StreamOwned { + /// Our connection + pub conn: C, + + /// The underlying transport, like a socket + pub sock: T, +} + +impl StreamOwned +where + C: DerefMut + Deref>, + T: Read + Write, + S: SideData, +{ + /// Make a new StreamOwned taking the Connection `conn` and socket-like + /// object `sock`. This does not fail and does no IO. + /// + /// This is the same as `Stream::new` except `conn` and `sock` are + /// moved into the StreamOwned. + pub fn new(conn: C, sock: T) -> Self { + Self { conn, sock } + } + + /// Get a reference to the underlying socket + pub fn get_ref(&self) -> &T { + &self.sock + } + + /// Get a mutable reference to the underlying socket + pub fn get_mut(&mut self) -> &mut T { + &mut self.sock + } +} + +impl<'a, C, T, S> StreamOwned +where + C: DerefMut + Deref>, + T: Read + Write, + S: SideData, +{ + fn as_stream(&'a mut self) -> Stream<'a, C, T> { + Stream { + conn: &mut self.conn, + sock: &mut self.sock, + } + } +} + +impl Read for StreamOwned +where + C: DerefMut + Deref>, + T: Read + Write, + S: SideData, +{ + fn read(&mut self, buf: &mut [u8]) -> Result { + self.as_stream().read(buf) + } + + #[cfg(read_buf)] + fn read_buf(&mut self, cursor: std::io::BorrowedCursor<'_>) -> Result<()> { + self.as_stream().read_buf(cursor) + } +} + +impl Write for StreamOwned +where + C: DerefMut + Deref>, + T: Read + Write, + S: SideData, +{ + fn write(&mut self, buf: &[u8]) -> Result { + self.as_stream().write(buf) + } + + fn flush(&mut self) -> Result<()> { + self.as_stream().flush() + } +} + +#[cfg(test)] +mod tests { + use super::{Stream, StreamOwned}; + use crate::client::ClientConnection; + use crate::server::ServerConnection; + use std::net::TcpStream; + + #[test] + fn stream_can_be_created_for_connection_and_tcpstream() { + type _Test<'a> = Stream<'a, ClientConnection, TcpStream>; + } + + #[test] + fn streamowned_can_be_created_for_client_and_tcpstream() { + type _Test = StreamOwned; + } + + #[test] + fn streamowned_can_be_created_for_server_and_tcpstream() { + type _Test = StreamOwned; + } +} diff --git a/vendor/rustls-0.21.8/src/suites.rs b/vendor/rustls-0.21.8/src/suites.rs new file mode 100644 index 0000000000000..c09e8314b6a38 --- /dev/null +++ b/vendor/rustls-0.21.8/src/suites.rs @@ -0,0 +1,341 @@ +use std::fmt; + +use crate::enums::{CipherSuite, ProtocolVersion, SignatureAlgorithm, SignatureScheme}; +#[cfg(feature = "tls12")] +use crate::tls12::Tls12CipherSuite; +#[cfg(feature = "tls12")] +use crate::tls12::{ + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + // TLS1.2 suites + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +}; +use crate::tls13::Tls13CipherSuite; +use crate::tls13::{ + TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256, +}; +#[cfg(feature = "tls12")] +use crate::versions::TLS12; +use crate::versions::{SupportedProtocolVersion, TLS13}; + +/// Bulk symmetric encryption scheme used by a cipher suite. +#[allow(non_camel_case_types)] +#[derive(Debug, Eq, PartialEq)] +pub enum BulkAlgorithm { + /// AES with 128-bit keys in Galois counter mode. + Aes128Gcm, + + /// AES with 256-bit keys in Galois counter mode. + Aes256Gcm, + + /// Chacha20 for confidentiality with poly1305 for authenticity. + Chacha20Poly1305, +} + +/// Common state for cipher suites (both for TLS 1.2 and TLS 1.3) +#[derive(Debug)] +pub struct CipherSuiteCommon { + /// The TLS enumeration naming this cipher suite. + pub suite: CipherSuite, + + /// How to do bulk encryption. + pub bulk: BulkAlgorithm, + + pub(crate) aead_algorithm: &'static ring::aead::Algorithm, +} + +/// A cipher suite supported by rustls. +/// +/// All possible instances of this type are provided by the library in +/// the [`ALL_CIPHER_SUITES`] array. +#[derive(Clone, Copy, PartialEq)] +pub enum SupportedCipherSuite { + /// A TLS 1.2 cipher suite + #[cfg(feature = "tls12")] + Tls12(&'static Tls12CipherSuite), + /// A TLS 1.3 cipher suite + Tls13(&'static Tls13CipherSuite), +} + +impl fmt::Debug for SupportedCipherSuite { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.suite().fmt(f) + } +} + +impl SupportedCipherSuite { + /// Which hash function to use with this suite. + pub fn hash_algorithm(&self) -> &'static ring::digest::Algorithm { + match self { + #[cfg(feature = "tls12")] + Self::Tls12(inner) => inner.hash_algorithm(), + Self::Tls13(inner) => inner.hash_algorithm(), + } + } + + /// The cipher suite's identifier + pub fn suite(&self) -> CipherSuite { + self.common().suite + } + + pub(crate) fn common(&self) -> &CipherSuiteCommon { + match self { + #[cfg(feature = "tls12")] + Self::Tls12(inner) => &inner.common, + Self::Tls13(inner) => &inner.common, + } + } + + #[cfg(any(test, feature = "quic"))] + pub(crate) fn tls13(&self) -> Option<&'static Tls13CipherSuite> { + match self { + #[cfg(feature = "tls12")] + Self::Tls12(_) => None, + Self::Tls13(inner) => Some(inner), + } + } + + /// Return supported protocol version for the cipher suite. + pub fn version(&self) -> &'static SupportedProtocolVersion { + match self { + #[cfg(feature = "tls12")] + Self::Tls12(_) => &TLS12, + Self::Tls13(_) => &TLS13, + } + } + + /// Return true if this suite is usable for a key only offering `sig_alg` + /// signatures. This resolves to true for all TLS1.3 suites. + pub fn usable_for_signature_algorithm(&self, _sig_alg: SignatureAlgorithm) -> bool { + match self { + Self::Tls13(_) => true, // no constraint expressed by ciphersuite (e.g., TLS1.3) + #[cfg(feature = "tls12")] + Self::Tls12(inner) => inner + .sign + .iter() + .any(|scheme| scheme.sign() == _sig_alg), + } + } +} + +/// A list of all the cipher suites supported by rustls. +pub static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = &[ + // TLS1.3 suites + TLS13_AES_256_GCM_SHA384, + TLS13_AES_128_GCM_SHA256, + TLS13_CHACHA20_POLY1305_SHA256, + // TLS1.2 suites + #[cfg(feature = "tls12")] + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + #[cfg(feature = "tls12")] + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + #[cfg(feature = "tls12")] + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + #[cfg(feature = "tls12")] + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + #[cfg(feature = "tls12")] + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + #[cfg(feature = "tls12")] + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +]; + +/// The cipher suite configuration that an application should use by default. +/// +/// This will be [`ALL_CIPHER_SUITES`] sans any supported cipher suites that +/// shouldn't be enabled by most applications. +pub static DEFAULT_CIPHER_SUITES: &[SupportedCipherSuite] = ALL_CIPHER_SUITES; + +// These both O(N^2)! +pub(crate) fn choose_ciphersuite_preferring_client( + client_suites: &[CipherSuite], + server_suites: &[SupportedCipherSuite], +) -> Option { + for client_suite in client_suites { + if let Some(selected) = server_suites + .iter() + .find(|x| *client_suite == x.suite()) + { + return Some(*selected); + } + } + + None +} + +pub(crate) fn choose_ciphersuite_preferring_server( + client_suites: &[CipherSuite], + server_suites: &[SupportedCipherSuite], +) -> Option { + if let Some(selected) = server_suites + .iter() + .find(|x| client_suites.contains(&x.suite())) + { + return Some(*selected); + } + + None +} + +/// Return a list of the ciphersuites in `all` with the suites +/// incompatible with `SignatureAlgorithm` `sigalg` removed. +pub(crate) fn reduce_given_sigalg( + all: &[SupportedCipherSuite], + sigalg: SignatureAlgorithm, +) -> Vec { + all.iter() + .filter(|&&suite| suite.usable_for_signature_algorithm(sigalg)) + .copied() + .collect() +} + +/// Return a list of the ciphersuites in `all` with the suites +/// incompatible with the chosen `version` removed. +pub(crate) fn reduce_given_version( + all: &[SupportedCipherSuite], + version: ProtocolVersion, +) -> Vec { + all.iter() + .filter(|&&suite| suite.version().version == version) + .copied() + .collect() +} + +/// Return true if `sigscheme` is usable by any of the given suites. +pub(crate) fn compatible_sigscheme_for_suites( + sigscheme: SignatureScheme, + common_suites: &[SupportedCipherSuite], +) -> bool { + let sigalg = sigscheme.sign(); + common_suites + .iter() + .any(|&suite| suite.usable_for_signature_algorithm(sigalg)) +} + +/// Secrets for transmitting/receiving data over a TLS session. +/// +/// After performing a handshake with rustls, these secrets can be extracted +/// to configure kTLS for a socket, and have the kernel take over encryption +/// and/or decryption. +#[cfg(feature = "secret_extraction")] +#[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] +pub struct ExtractedSecrets { + /// sequence number and secrets for the "tx" (transmit) direction + pub tx: (u64, ConnectionTrafficSecrets), + + /// sequence number and secrets for the "rx" (receive) direction + pub rx: (u64, ConnectionTrafficSecrets), +} + +/// [ExtractedSecrets] minus the sequence numbers +#[cfg(feature = "secret_extraction")] +pub(crate) struct PartiallyExtractedSecrets { + /// secrets for the "tx" (transmit) direction + pub(crate) tx: ConnectionTrafficSecrets, + + /// secrets for the "rx" (receive) direction + pub(crate) rx: ConnectionTrafficSecrets, +} + +/// Secrets used to encrypt/decrypt data in a TLS session. +/// +/// These can be used to configure kTLS for a socket in one direction. +/// The only other piece of information needed is the sequence number, +/// which is in [ExtractedSecrets]. +#[cfg(feature = "secret_extraction")] +#[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] +#[non_exhaustive] +pub enum ConnectionTrafficSecrets { + /// Secrets for the AES_128_GCM AEAD algorithm + Aes128Gcm { + /// key (16 bytes) + key: [u8; 16], + /// salt (4 bytes) + salt: [u8; 4], + /// initialization vector (8 bytes, chopped from key block) + iv: [u8; 8], + }, + + /// Secrets for the AES_256_GCM AEAD algorithm + Aes256Gcm { + /// key (32 bytes) + key: [u8; 32], + /// salt (4 bytes) + salt: [u8; 4], + /// initialization vector (8 bytes, chopped from key block) + iv: [u8; 8], + }, + + /// Secrets for the CHACHA20_POLY1305 AEAD algorithm + Chacha20Poly1305 { + /// key (32 bytes) + key: [u8; 32], + /// initialization vector (12 bytes) + iv: [u8; 12], + }, +} + +#[cfg(test)] +mod test { + use super::*; + use crate::enums::CipherSuite; + + #[test] + fn test_client_pref() { + let client = vec![ + CipherSuite::TLS13_AES_128_GCM_SHA256, + CipherSuite::TLS13_AES_256_GCM_SHA384, + ]; + let server = vec![TLS13_AES_256_GCM_SHA384, TLS13_AES_128_GCM_SHA256]; + let chosen = choose_ciphersuite_preferring_client(&client, &server); + assert!(chosen.is_some()); + assert_eq!(chosen.unwrap(), TLS13_AES_128_GCM_SHA256); + } + + #[test] + fn test_server_pref() { + let client = vec![ + CipherSuite::TLS13_AES_128_GCM_SHA256, + CipherSuite::TLS13_AES_256_GCM_SHA384, + ]; + let server = vec![TLS13_AES_256_GCM_SHA384, TLS13_AES_128_GCM_SHA256]; + let chosen = choose_ciphersuite_preferring_server(&client, &server); + assert!(chosen.is_some()); + assert_eq!(chosen.unwrap(), TLS13_AES_256_GCM_SHA384); + } + + #[test] + fn test_pref_fails() { + assert!(choose_ciphersuite_preferring_client( + &[CipherSuite::TLS_NULL_WITH_NULL_NULL], + ALL_CIPHER_SUITES + ) + .is_none()); + assert!(choose_ciphersuite_preferring_server( + &[CipherSuite::TLS_NULL_WITH_NULL_NULL], + ALL_CIPHER_SUITES + ) + .is_none()); + } + + #[test] + fn test_scs_is_debug() { + println!("{:?}", ALL_CIPHER_SUITES); + } + + #[test] + fn test_can_resume_to() { + assert!(TLS13_AES_128_GCM_SHA256 + .tls13() + .unwrap() + .can_resume_from(crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL) + .is_some()); + assert!(TLS13_AES_256_GCM_SHA384 + .tls13() + .unwrap() + .can_resume_from(crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL) + .is_none()); + } +} diff --git a/vendor/rustls-0.21.8/src/testdata/cert-arstechnica.0.der b/vendor/rustls-0.21.8/src/testdata/cert-arstechnica.0.der new file mode 100644 index 0000000000000..ac81cd85ec8d9 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-arstechnica.0.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-arstechnica.1.der b/vendor/rustls-0.21.8/src/testdata/cert-arstechnica.1.der new file mode 100644 index 0000000000000..93f1fb0c6b568 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-arstechnica.1.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-arstechnica.2.der b/vendor/rustls-0.21.8/src/testdata/cert-arstechnica.2.der new file mode 100644 index 0000000000000..1dfb0e70faadb Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-arstechnica.2.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-arstechnica.3.der b/vendor/rustls-0.21.8/src/testdata/cert-arstechnica.3.der new file mode 100644 index 0000000000000..75df0cc7c0be2 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-arstechnica.3.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-duckduckgo.0.der b/vendor/rustls-0.21.8/src/testdata/cert-duckduckgo.0.der new file mode 100644 index 0000000000000..9f8267ca92592 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-duckduckgo.0.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-duckduckgo.1.der b/vendor/rustls-0.21.8/src/testdata/cert-duckduckgo.1.der new file mode 100644 index 0000000000000..dd6a50f3273ea Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-duckduckgo.1.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-github.0.der b/vendor/rustls-0.21.8/src/testdata/cert-github.0.der new file mode 100644 index 0000000000000..86d6fce22f2ac Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-github.0.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-github.1.der b/vendor/rustls-0.21.8/src/testdata/cert-github.1.der new file mode 100644 index 0000000000000..78a66bb47b43e Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-github.1.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-google.0.der b/vendor/rustls-0.21.8/src/testdata/cert-google.0.der new file mode 100644 index 0000000000000..e8c41b21f57de Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-google.0.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-google.1.der b/vendor/rustls-0.21.8/src/testdata/cert-google.1.der new file mode 100644 index 0000000000000..6671504243234 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-google.1.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-google.2.der b/vendor/rustls-0.21.8/src/testdata/cert-google.2.der new file mode 100644 index 0000000000000..fd888ec600cd6 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-google.2.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-hn.0.der b/vendor/rustls-0.21.8/src/testdata/cert-hn.0.der new file mode 100644 index 0000000000000..bc42b61abcbe3 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-hn.0.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-hn.1.der b/vendor/rustls-0.21.8/src/testdata/cert-hn.1.der new file mode 100644 index 0000000000000..dd6a50f3273ea Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-hn.1.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-reddit.0.der b/vendor/rustls-0.21.8/src/testdata/cert-reddit.0.der new file mode 100644 index 0000000000000..3a26d368ceee3 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-reddit.0.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-reddit.1.der b/vendor/rustls-0.21.8/src/testdata/cert-reddit.1.der new file mode 100644 index 0000000000000..dd6a50f3273ea Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-reddit.1.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-rustlang.0.der b/vendor/rustls-0.21.8/src/testdata/cert-rustlang.0.der new file mode 100644 index 0000000000000..3af1cadfd8f23 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-rustlang.0.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-rustlang.1.der b/vendor/rustls-0.21.8/src/testdata/cert-rustlang.1.der new file mode 100644 index 0000000000000..93f1fb0c6b568 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-rustlang.1.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-rustlang.2.der b/vendor/rustls-0.21.8/src/testdata/cert-rustlang.2.der new file mode 100644 index 0000000000000..1dfb0e70faadb Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-rustlang.2.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-rustlang.3.der b/vendor/rustls-0.21.8/src/testdata/cert-rustlang.3.der new file mode 100644 index 0000000000000..75df0cc7c0be2 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-rustlang.3.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-servo.0.der b/vendor/rustls-0.21.8/src/testdata/cert-servo.0.der new file mode 100644 index 0000000000000..0b6271ff545de Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-servo.0.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-servo.1.der b/vendor/rustls-0.21.8/src/testdata/cert-servo.1.der new file mode 100644 index 0000000000000..41c742136ce86 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-servo.1.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-stackoverflow.0.der b/vendor/rustls-0.21.8/src/testdata/cert-stackoverflow.0.der new file mode 100644 index 0000000000000..68068a77c5ba0 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-stackoverflow.0.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-stackoverflow.1.der b/vendor/rustls-0.21.8/src/testdata/cert-stackoverflow.1.der new file mode 100644 index 0000000000000..2d66ea723ea4f Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-stackoverflow.1.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-stackoverflow.2.der b/vendor/rustls-0.21.8/src/testdata/cert-stackoverflow.2.der new file mode 100644 index 0000000000000..79a33ba5908c8 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-stackoverflow.2.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-twitter.0.der b/vendor/rustls-0.21.8/src/testdata/cert-twitter.0.der new file mode 100644 index 0000000000000..36f4e06d476e3 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-twitter.0.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-twitter.1.der b/vendor/rustls-0.21.8/src/testdata/cert-twitter.1.der new file mode 100644 index 0000000000000..608f16c792172 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-twitter.1.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-wapo.0.der b/vendor/rustls-0.21.8/src/testdata/cert-wapo.0.der new file mode 100644 index 0000000000000..94d2cd97be27b Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-wapo.0.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-wapo.1.der b/vendor/rustls-0.21.8/src/testdata/cert-wapo.1.der new file mode 100644 index 0000000000000..99ced211ba8a4 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-wapo.1.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-wikipedia.0.der b/vendor/rustls-0.21.8/src/testdata/cert-wikipedia.0.der new file mode 100644 index 0000000000000..5452038166df3 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-wikipedia.0.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/cert-wikipedia.1.der b/vendor/rustls-0.21.8/src/testdata/cert-wikipedia.1.der new file mode 100644 index 0000000000000..7d8413a3474b4 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/cert-wikipedia.1.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/deframer-empty-applicationdata.bin b/vendor/rustls-0.21.8/src/testdata/deframer-empty-applicationdata.bin new file mode 100644 index 0000000000000..ff11f477c3706 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/deframer-empty-applicationdata.bin differ diff --git a/vendor/rustls-0.21.8/src/testdata/deframer-invalid-contenttype.bin b/vendor/rustls-0.21.8/src/testdata/deframer-invalid-contenttype.bin new file mode 100644 index 0000000000000..813cc67fb265d Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/deframer-invalid-contenttype.bin differ diff --git a/vendor/rustls-0.21.8/src/testdata/deframer-invalid-empty.bin b/vendor/rustls-0.21.8/src/testdata/deframer-invalid-empty.bin new file mode 100644 index 0000000000000..4739075ea074d Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/deframer-invalid-empty.bin differ diff --git a/vendor/rustls-0.21.8/src/testdata/deframer-invalid-length.bin b/vendor/rustls-0.21.8/src/testdata/deframer-invalid-length.bin new file mode 100644 index 0000000000000..675415f956570 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/deframer-invalid-length.bin differ diff --git a/vendor/rustls-0.21.8/src/testdata/deframer-invalid-version.bin b/vendor/rustls-0.21.8/src/testdata/deframer-invalid-version.bin new file mode 100644 index 0000000000000..5c18e175f50cb Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/deframer-invalid-version.bin differ diff --git a/vendor/rustls-0.21.8/src/testdata/deframer-test.1.bin b/vendor/rustls-0.21.8/src/testdata/deframer-test.1.bin new file mode 100644 index 0000000000000..70407261b29a3 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/deframer-test.1.bin differ diff --git a/vendor/rustls-0.21.8/src/testdata/deframer-test.2.bin b/vendor/rustls-0.21.8/src/testdata/deframer-test.2.bin new file mode 100644 index 0000000000000..ba7a1780b9965 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/deframer-test.2.bin differ diff --git a/vendor/rustls-0.21.8/src/testdata/eddsakey.der b/vendor/rustls-0.21.8/src/testdata/eddsakey.der new file mode 100644 index 0000000000000..8eff00da9f230 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/eddsakey.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/nistp256key.der b/vendor/rustls-0.21.8/src/testdata/nistp256key.der new file mode 100644 index 0000000000000..57551822e40e6 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/nistp256key.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/nistp256key.pkcs8.der b/vendor/rustls-0.21.8/src/testdata/nistp256key.pkcs8.der new file mode 100644 index 0000000000000..8e64b2c81f3c5 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/nistp256key.pkcs8.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/nistp384key.der b/vendor/rustls-0.21.8/src/testdata/nistp384key.der new file mode 100644 index 0000000000000..80f0769af0d0d Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/nistp384key.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/nistp384key.pkcs8.der b/vendor/rustls-0.21.8/src/testdata/nistp384key.pkcs8.der new file mode 100644 index 0000000000000..f85de4319c654 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/nistp384key.pkcs8.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/prf-result.1.bin b/vendor/rustls-0.21.8/src/testdata/prf-result.1.bin new file mode 100644 index 0000000000000..a066b9cc0a4ff --- /dev/null +++ b/vendor/rustls-0.21.8/src/testdata/prf-result.1.bin @@ -0,0 +1 @@ +ãò)ºr{á{& U|ÔSª²ÃÔ•2›RÔæÛZk0‘é 5ÉɤkNºù¯ "÷}ï«ý7—ÀVK«O¼‘fnï›—üãOyg‰º¤€‚Ñ"îBŧ.ZQÿ÷‡4{f \ No newline at end of file diff --git a/vendor/rustls-0.21.8/src/testdata/prf-result.2.bin b/vendor/rustls-0.21.8/src/testdata/prf-result.2.bin new file mode 100644 index 0000000000000..799eeca86a7ac --- /dev/null +++ b/vendor/rustls-0.21.8/src/testdata/prf-result.2.bin @@ -0,0 +1 @@ +aõˆÇ˜ÅÂÿnzœµíÍãùLfš*F8×Õ²ƒ-öx˜uÇ~m†‹Ç\Eâ´ ô¡q;'7hC%’÷ÜŽ¨ï">ê…„¿he= ü@VØð%Ä]ߦæþÇðT´ ÖòУ#>I¤>uÅcí¾"þ%N3¡°éö¹‚fu¾ÇЄVXÜœ9uE@@¹ôlz@á¸ø ¦ 9z(¿õÒïPfhBû¤v2½µOöc?†»È6æ@Ôؘ \ No newline at end of file diff --git a/vendor/rustls-0.21.8/src/testdata/rsa2048key.pkcs1.der b/vendor/rustls-0.21.8/src/testdata/rsa2048key.pkcs1.der new file mode 100644 index 0000000000000..d93402d2c9c43 Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/rsa2048key.pkcs1.der differ diff --git a/vendor/rustls-0.21.8/src/testdata/rsa2048key.pkcs8.der b/vendor/rustls-0.21.8/src/testdata/rsa2048key.pkcs8.der new file mode 100644 index 0000000000000..8e5c2e817ddfe Binary files /dev/null and b/vendor/rustls-0.21.8/src/testdata/rsa2048key.pkcs8.der differ diff --git a/vendor/rustls-0.21.8/src/ticketer.rs b/vendor/rustls-0.21.8/src/ticketer.rs new file mode 100644 index 0000000000000..9660d711a60f6 --- /dev/null +++ b/vendor/rustls-0.21.8/src/ticketer.rs @@ -0,0 +1,338 @@ +use crate::rand; +use crate::server::ProducesTickets; +use crate::Error; + +use ring::aead; +use std::mem; +use std::sync::{Arc, Mutex, MutexGuard}; +use std::time; + +/// The timebase for expiring and rolling tickets and ticketing +/// keys. This is UNIX wall time in seconds. +/// +/// This is guaranteed to be on or after the UNIX epoch. +#[derive(Clone, Copy, Debug)] +pub struct TimeBase(time::Duration); + +impl TimeBase { + #[inline] + pub fn now() -> Result { + Ok(Self( + time::SystemTime::now().duration_since(time::UNIX_EPOCH)?, + )) + } + + #[inline] + pub fn as_secs(&self) -> u64 { + self.0.as_secs() + } +} + +/// This is a `ProducesTickets` implementation which uses +/// any *ring* `aead::Algorithm` to encrypt and authentication +/// the ticket payload. It does not enforce any lifetime +/// constraint. +struct AeadTicketer { + alg: &'static aead::Algorithm, + key: aead::LessSafeKey, + lifetime: u32, +} + +impl AeadTicketer { + /// Make a ticketer with recommended configuration and a random key. + fn new() -> Result { + let mut key = [0u8; 32]; + rand::fill_random(&mut key)?; + + let alg = &aead::CHACHA20_POLY1305; + let key = aead::UnboundKey::new(alg, &key).unwrap(); + + Ok(Self { + alg, + key: aead::LessSafeKey::new(key), + lifetime: 60 * 60 * 12, + }) + } +} + +impl ProducesTickets for AeadTicketer { + fn enabled(&self) -> bool { + true + } + fn lifetime(&self) -> u32 { + self.lifetime + } + + /// Encrypt `message` and return the ciphertext. + fn encrypt(&self, message: &[u8]) -> Option> { + // Random nonce, because a counter is a privacy leak. + let mut nonce_buf = [0u8; 12]; + rand::fill_random(&mut nonce_buf).ok()?; + let nonce = ring::aead::Nonce::assume_unique_for_key(nonce_buf); + let aad = ring::aead::Aad::empty(); + + let mut ciphertext = + Vec::with_capacity(nonce_buf.len() + message.len() + self.key.algorithm().tag_len()); + ciphertext.extend(nonce_buf); + ciphertext.extend(message); + self.key + .seal_in_place_separate_tag(nonce, aad, &mut ciphertext[nonce_buf.len()..]) + .map(|tag| { + ciphertext.extend(tag.as_ref()); + ciphertext + }) + .ok() + } + + /// Decrypt `ciphertext` and recover the original message. + fn decrypt(&self, ciphertext: &[u8]) -> Option> { + // Non-panicking `let (nonce, ciphertext) = ciphertext.split_at(...)`. + let nonce = ciphertext.get(..self.alg.nonce_len())?; + let ciphertext = ciphertext.get(nonce.len()..)?; + + // This won't fail since `nonce` has the required length. + let nonce = ring::aead::Nonce::try_assume_unique_for_key(nonce).ok()?; + + let mut out = Vec::from(ciphertext); + + let plain_len = self + .key + .open_in_place(nonce, aead::Aad::empty(), &mut out) + .ok()? + .len(); + out.truncate(plain_len); + + Some(out) + } +} + +struct TicketSwitcherState { + next: Option>, + current: Box, + previous: Option>, + next_switch_time: u64, +} + +/// A ticketer that has a 'current' sub-ticketer and a single +/// 'previous' ticketer. It creates a new ticketer every so +/// often, demoting the current ticketer. +struct TicketSwitcher { + generator: fn() -> Result, rand::GetRandomFailed>, + lifetime: u32, + state: Mutex, +} + +impl TicketSwitcher { + /// `lifetime` is in seconds, and is how long the current ticketer + /// is used to generate new tickets. Tickets are accepted for no + /// longer than twice this duration. `generator` produces a new + /// `ProducesTickets` implementation. + fn new( + lifetime: u32, + generator: fn() -> Result, rand::GetRandomFailed>, + ) -> Result { + let now = TimeBase::now()?; + Ok(Self { + generator, + lifetime, + state: Mutex::new(TicketSwitcherState { + next: Some(generator()?), + current: generator()?, + previous: None, + next_switch_time: now + .as_secs() + .saturating_add(u64::from(lifetime)), + }), + }) + } + + /// If it's time, demote the `current` ticketer to `previous` (so it + /// does no new encryptions but can do decryption) and use next for a + /// new `current` ticketer. + /// + /// Calling this regularly will ensure timely key erasure. Otherwise, + /// key erasure will be delayed until the next encrypt/decrypt call. + /// + /// For efficiency, this is also responsible for locking the state mutex + /// and returning the mutexguard. + fn maybe_roll(&self, now: TimeBase) -> Option> { + // The code below aims to make switching as efficient as possible + // in the common case that the generator never fails. To achieve this + // we run the following steps: + // 1. If no switch is necessary, just return the mutexguard + // 2. Shift over all of the ticketers (so current becomes previous, + // and next becomes current). After this, other threads can + // start using the new current ticketer. + // 3. unlock mutex and generate new ticketer. + // 4. Place new ticketer in next and return current + // + // There are a few things to note here. First, we don't check whether + // a new switch might be needed in step 4, even though, due to locking + // and entropy collection, significant amounts of time may have passed. + // This is to guarantee that the thread doing the switch will eventually + // make progress. + // + // Second, because next may be None, step 2 can fail. In that case + // we enter a recovery mode where we generate 2 new ticketers, one for + // next and one for the current ticketer. We then take the mutex a + // second time and redo the time check to see if a switch is still + // necessary. + // + // This somewhat convoluted approach ensures good availability of the + // mutex, by ensuring that the state is usable and the mutex not held + // during generation. It also ensures that, so long as the inner + // ticketer never generates panics during encryption/decryption, + // we are guaranteed to never panic when holding the mutex. + + let now = now.as_secs(); + let mut are_recovering = false; // Are we recovering from previous failure? + { + // Scope the mutex so we only take it for as long as needed + let mut state = self.state.lock().ok()?; + + // Fast path in case we do not need to switch to the next ticketer yet + if now <= state.next_switch_time { + return Some(state); + } + + // Make the switch, or mark for recovery if not possible + if let Some(next) = state.next.take() { + state.previous = Some(mem::replace(&mut state.current, next)); + state.next_switch_time = now.saturating_add(u64::from(self.lifetime)); + } else { + are_recovering = true; + } + } + + // We always need a next, so generate it now + let next = (self.generator)().ok()?; + if !are_recovering { + // Normal path, generate new next and place it in the state + let mut state = self.state.lock().ok()?; + state.next = Some(next); + Some(state) + } else { + // Recovering, generate also a new current ticketer, and modify state + // as needed. (we need to redo the time check, otherwise this might + // result in very rapid switching of ticketers) + let new_current = (self.generator)().ok()?; + let mut state = self.state.lock().ok()?; + state.next = Some(next); + if now > state.next_switch_time { + state.previous = Some(mem::replace(&mut state.current, new_current)); + state.next_switch_time = now.saturating_add(u64::from(self.lifetime)); + } + Some(state) + } + } +} + +impl ProducesTickets for TicketSwitcher { + fn lifetime(&self) -> u32 { + self.lifetime * 2 + } + + fn enabled(&self) -> bool { + true + } + + fn encrypt(&self, message: &[u8]) -> Option> { + let state = self.maybe_roll(TimeBase::now().ok()?)?; + + state.current.encrypt(message) + } + + fn decrypt(&self, ciphertext: &[u8]) -> Option> { + let state = self.maybe_roll(TimeBase::now().ok()?)?; + + // Decrypt with the current key; if that fails, try with the previous. + state + .current + .decrypt(ciphertext) + .or_else(|| { + state + .previous + .as_ref() + .and_then(|previous| previous.decrypt(ciphertext)) + }) + } +} + +/// A concrete, safe ticket creation mechanism. +pub struct Ticketer {} + +fn generate_inner() -> Result, rand::GetRandomFailed> { + Ok(Box::new(AeadTicketer::new()?)) +} + +impl Ticketer { + /// Make the recommended Ticketer. This produces tickets + /// with a 12 hour life and randomly generated keys. + /// + /// The encryption mechanism used in Chacha20Poly1305. + pub fn new() -> Result, Error> { + Ok(Arc::new(TicketSwitcher::new(6 * 60 * 60, generate_inner)?)) + } +} + +#[test] +fn basic_pairwise_test() { + let t = Ticketer::new().unwrap(); + assert!(t.enabled()); + let cipher = t.encrypt(b"hello world").unwrap(); + let plain = t.decrypt(&cipher).unwrap(); + assert_eq!(plain, b"hello world"); +} + +#[test] +fn ticketswitcher_switching_test() { + let t = Arc::new(TicketSwitcher::new(1, generate_inner).unwrap()); + let now = TimeBase::now().unwrap(); + let cipher1 = t.encrypt(b"ticket 1").unwrap(); + assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); + { + // Trigger new ticketer + t.maybe_roll(TimeBase(now.0 + std::time::Duration::from_secs(10))); + } + let cipher2 = t.encrypt(b"ticket 2").unwrap(); + assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); + assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); + { + // Trigger new ticketer + t.maybe_roll(TimeBase(now.0 + std::time::Duration::from_secs(20))); + } + let cipher3 = t.encrypt(b"ticket 3").unwrap(); + assert!(t.decrypt(&cipher1).is_none()); + assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); + assert_eq!(t.decrypt(&cipher3).unwrap(), b"ticket 3"); +} + +#[cfg(test)] +fn fail_generator() -> Result, rand::GetRandomFailed> { + Err(rand::GetRandomFailed) +} + +#[test] +fn ticketswitcher_recover_test() { + let mut t = TicketSwitcher::new(1, generate_inner).unwrap(); + let now = TimeBase::now().unwrap(); + let cipher1 = t.encrypt(b"ticket 1").unwrap(); + assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); + t.generator = fail_generator; + { + // Failed new ticketer + t.maybe_roll(TimeBase(now.0 + std::time::Duration::from_secs(10))); + } + t.generator = generate_inner; + let cipher2 = t.encrypt(b"ticket 2").unwrap(); + assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); + assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); + { + // recover + t.maybe_roll(TimeBase(now.0 + std::time::Duration::from_secs(20))); + } + let cipher3 = t.encrypt(b"ticket 3").unwrap(); + assert!(t.decrypt(&cipher1).is_none()); + assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); + assert_eq!(t.decrypt(&cipher3).unwrap(), b"ticket 3"); +} diff --git a/vendor/rustls-0.21.8/src/tls12/cipher.rs b/vendor/rustls-0.21.8/src/tls12/cipher.rs new file mode 100644 index 0000000000000..862252125b6ca --- /dev/null +++ b/vendor/rustls-0.21.8/src/tls12/cipher.rs @@ -0,0 +1,236 @@ +use crate::cipher::{make_nonce, Iv, MessageDecrypter, MessageEncrypter}; +use crate::enums::ContentType; +use crate::enums::ProtocolVersion; +use crate::error::Error; +use crate::msgs::base::Payload; +use crate::msgs::codec; +use crate::msgs::fragmenter::MAX_FRAGMENT_LEN; +use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage}; + +use ring::aead; + +const TLS12_AAD_SIZE: usize = 8 + 1 + 2 + 2; + +fn make_tls12_aad( + seq: u64, + typ: ContentType, + vers: ProtocolVersion, + len: usize, +) -> ring::aead::Aad<[u8; TLS12_AAD_SIZE]> { + let mut out = [0; TLS12_AAD_SIZE]; + codec::put_u64(seq, &mut out[0..]); + out[8] = typ.get_u8(); + codec::put_u16(vers.get_u16(), &mut out[9..]); + codec::put_u16(len as u16, &mut out[11..]); + ring::aead::Aad::from(out) +} + +pub(crate) struct AesGcm; + +impl Tls12AeadAlgorithm for AesGcm { + fn decrypter(&self, dec_key: aead::LessSafeKey, dec_iv: &[u8]) -> Box { + let mut ret = GcmMessageDecrypter { + dec_key, + dec_salt: [0u8; 4], + }; + + debug_assert_eq!(dec_iv.len(), 4); + ret.dec_salt.copy_from_slice(dec_iv); + Box::new(ret) + } + + fn encrypter( + &self, + enc_key: aead::LessSafeKey, + write_iv: &[u8], + explicit: &[u8], + ) -> Box { + debug_assert_eq!(write_iv.len(), 4); + debug_assert_eq!(explicit.len(), 8); + + // The GCM nonce is constructed from a 32-bit 'salt' derived + // from the master-secret, and a 64-bit explicit part, + // with no specified construction. Thanks for that. + // + // We use the same construction as TLS1.3/ChaCha20Poly1305: + // a starting point extracted from the key block, xored with + // the sequence number. + let mut iv = Iv(Default::default()); + iv.0[..4].copy_from_slice(write_iv); + iv.0[4..].copy_from_slice(explicit); + + Box::new(GcmMessageEncrypter { enc_key, iv }) + } +} + +pub(crate) struct ChaCha20Poly1305; + +impl Tls12AeadAlgorithm for ChaCha20Poly1305 { + fn decrypter(&self, dec_key: aead::LessSafeKey, iv: &[u8]) -> Box { + Box::new(ChaCha20Poly1305MessageDecrypter { + dec_key, + dec_offset: Iv::copy(iv), + }) + } + + fn encrypter( + &self, + enc_key: aead::LessSafeKey, + enc_iv: &[u8], + _: &[u8], + ) -> Box { + Box::new(ChaCha20Poly1305MessageEncrypter { + enc_key, + enc_offset: Iv::copy(enc_iv), + }) + } +} + +pub(crate) trait Tls12AeadAlgorithm: Send + Sync + 'static { + fn decrypter(&self, key: aead::LessSafeKey, iv: &[u8]) -> Box; + fn encrypter( + &self, + key: aead::LessSafeKey, + iv: &[u8], + extra: &[u8], + ) -> Box; +} + +/// A `MessageEncrypter` for AES-GCM AEAD ciphersuites. TLS 1.2 only. +struct GcmMessageEncrypter { + enc_key: aead::LessSafeKey, + iv: Iv, +} + +/// A `MessageDecrypter` for AES-GCM AEAD ciphersuites. TLS1.2 only. +struct GcmMessageDecrypter { + dec_key: aead::LessSafeKey, + dec_salt: [u8; 4], +} + +const GCM_EXPLICIT_NONCE_LEN: usize = 8; +const GCM_OVERHEAD: usize = GCM_EXPLICIT_NONCE_LEN + 16; + +impl MessageDecrypter for GcmMessageDecrypter { + fn decrypt(&self, mut msg: OpaqueMessage, seq: u64) -> Result { + let payload = &mut msg.payload.0; + if payload.len() < GCM_OVERHEAD { + return Err(Error::DecryptError); + } + + let nonce = { + let mut nonce = [0u8; 12]; + nonce[..4].copy_from_slice(&self.dec_salt); + nonce[4..].copy_from_slice(&payload[..8]); + aead::Nonce::assume_unique_for_key(nonce) + }; + + let aad = make_tls12_aad(seq, msg.typ, msg.version, payload.len() - GCM_OVERHEAD); + + let plain_len = self + .dec_key + .open_within(nonce, aad, payload, GCM_EXPLICIT_NONCE_LEN..) + .map_err(|_| Error::DecryptError)? + .len(); + + if plain_len > MAX_FRAGMENT_LEN { + return Err(Error::PeerSentOversizedRecord); + } + + payload.truncate(plain_len); + Ok(msg.into_plain_message()) + } +} + +impl MessageEncrypter for GcmMessageEncrypter { + fn encrypt(&self, msg: BorrowedPlainMessage, seq: u64) -> Result { + let nonce = make_nonce(&self.iv, seq); + let aad = make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()); + + let total_len = msg.payload.len() + self.enc_key.algorithm().tag_len(); + let mut payload = Vec::with_capacity(GCM_EXPLICIT_NONCE_LEN + total_len); + payload.extend_from_slice(&nonce.as_ref()[4..]); + payload.extend_from_slice(msg.payload); + + self.enc_key + .seal_in_place_separate_tag(nonce, aad, &mut payload[GCM_EXPLICIT_NONCE_LEN..]) + .map(|tag| payload.extend(tag.as_ref())) + .map_err(|_| Error::EncryptError)?; + + Ok(OpaqueMessage { + typ: msg.typ, + version: msg.version, + payload: Payload::new(payload), + }) + } +} + +/// The RFC7905/RFC7539 ChaCha20Poly1305 construction. +/// This implementation does the AAD construction required in TLS1.2. +/// TLS1.3 uses `TLS13MessageEncrypter`. +struct ChaCha20Poly1305MessageEncrypter { + enc_key: aead::LessSafeKey, + enc_offset: Iv, +} + +/// The RFC7905/RFC7539 ChaCha20Poly1305 construction. +/// This implementation does the AAD construction required in TLS1.2. +/// TLS1.3 uses `TLS13MessageDecrypter`. +struct ChaCha20Poly1305MessageDecrypter { + dec_key: aead::LessSafeKey, + dec_offset: Iv, +} + +const CHACHAPOLY1305_OVERHEAD: usize = 16; + +impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter { + fn decrypt(&self, mut msg: OpaqueMessage, seq: u64) -> Result { + let payload = &mut msg.payload.0; + + if payload.len() < CHACHAPOLY1305_OVERHEAD { + return Err(Error::DecryptError); + } + + let nonce = make_nonce(&self.dec_offset, seq); + let aad = make_tls12_aad( + seq, + msg.typ, + msg.version, + payload.len() - CHACHAPOLY1305_OVERHEAD, + ); + + let plain_len = self + .dec_key + .open_in_place(nonce, aad, payload) + .map_err(|_| Error::DecryptError)? + .len(); + + if plain_len > MAX_FRAGMENT_LEN { + return Err(Error::PeerSentOversizedRecord); + } + + payload.truncate(plain_len); + Ok(msg.into_plain_message()) + } +} + +impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter { + fn encrypt(&self, msg: BorrowedPlainMessage, seq: u64) -> Result { + let nonce = make_nonce(&self.enc_offset, seq); + let aad = make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()); + + let total_len = msg.payload.len() + self.enc_key.algorithm().tag_len(); + let mut buf = Vec::with_capacity(total_len); + buf.extend_from_slice(msg.payload); + + self.enc_key + .seal_in_place_append_tag(nonce, aad, &mut buf) + .map_err(|_| Error::EncryptError)?; + + Ok(OpaqueMessage { + typ: msg.typ, + version: msg.version, + payload: Payload::new(buf), + }) + } +} diff --git a/vendor/rustls-0.21.8/src/tls12/mod.rs b/vendor/rustls-0.21.8/src/tls12/mod.rs new file mode 100644 index 0000000000000..504c1fbba3404 --- /dev/null +++ b/vendor/rustls-0.21.8/src/tls12/mod.rs @@ -0,0 +1,534 @@ +use crate::cipher::{MessageDecrypter, MessageEncrypter}; +use crate::common_state::{CommonState, Side}; +use crate::conn::ConnectionRandoms; +use crate::enums::{AlertDescription, CipherSuite, SignatureScheme}; +use crate::error::{Error, InvalidMessage}; +use crate::kx; +use crate::msgs::codec::{Codec, Reader}; +use crate::msgs::handshake::KeyExchangeAlgorithm; +use crate::suites::{BulkAlgorithm, CipherSuiteCommon, SupportedCipherSuite}; +#[cfg(feature = "secret_extraction")] +use crate::suites::{ConnectionTrafficSecrets, PartiallyExtractedSecrets}; + +use ring::aead; +use ring::digest::Digest; + +use std::fmt; + +mod cipher; +pub(crate) use cipher::{AesGcm, ChaCha20Poly1305, Tls12AeadAlgorithm}; + +mod prf; + +/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256. +pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = + SupportedCipherSuite::Tls12(&Tls12CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + bulk: BulkAlgorithm::Chacha20Poly1305, + aead_algorithm: &ring::aead::CHACHA20_POLY1305, + }, + kx: KeyExchangeAlgorithm::ECDHE, + sign: TLS12_ECDSA_SCHEMES, + fixed_iv_len: 12, + explicit_nonce_len: 0, + aead_alg: &ChaCha20Poly1305, + hmac_algorithm: ring::hmac::HMAC_SHA256, + }); + +/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 +pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = + SupportedCipherSuite::Tls12(&Tls12CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + bulk: BulkAlgorithm::Chacha20Poly1305, + aead_algorithm: &ring::aead::CHACHA20_POLY1305, + }, + kx: KeyExchangeAlgorithm::ECDHE, + sign: TLS12_RSA_SCHEMES, + fixed_iv_len: 12, + explicit_nonce_len: 0, + aead_alg: &ChaCha20Poly1305, + hmac_algorithm: ring::hmac::HMAC_SHA256, + }); + +/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 +pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = + SupportedCipherSuite::Tls12(&Tls12CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + bulk: BulkAlgorithm::Aes128Gcm, + aead_algorithm: &ring::aead::AES_128_GCM, + }, + kx: KeyExchangeAlgorithm::ECDHE, + sign: TLS12_RSA_SCHEMES, + fixed_iv_len: 4, + explicit_nonce_len: 8, + aead_alg: &AesGcm, + hmac_algorithm: ring::hmac::HMAC_SHA256, + }); + +/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 +pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = + SupportedCipherSuite::Tls12(&Tls12CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + bulk: BulkAlgorithm::Aes256Gcm, + aead_algorithm: &ring::aead::AES_256_GCM, + }, + kx: KeyExchangeAlgorithm::ECDHE, + sign: TLS12_RSA_SCHEMES, + fixed_iv_len: 4, + explicit_nonce_len: 8, + aead_alg: &AesGcm, + hmac_algorithm: ring::hmac::HMAC_SHA384, + }); + +/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 +pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = + SupportedCipherSuite::Tls12(&Tls12CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + bulk: BulkAlgorithm::Aes128Gcm, + aead_algorithm: &ring::aead::AES_128_GCM, + }, + kx: KeyExchangeAlgorithm::ECDHE, + sign: TLS12_ECDSA_SCHEMES, + fixed_iv_len: 4, + explicit_nonce_len: 8, + aead_alg: &AesGcm, + hmac_algorithm: ring::hmac::HMAC_SHA256, + }); + +/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 +pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = + SupportedCipherSuite::Tls12(&Tls12CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + bulk: BulkAlgorithm::Aes256Gcm, + aead_algorithm: &ring::aead::AES_256_GCM, + }, + kx: KeyExchangeAlgorithm::ECDHE, + sign: TLS12_ECDSA_SCHEMES, + fixed_iv_len: 4, + explicit_nonce_len: 8, + aead_alg: &AesGcm, + hmac_algorithm: ring::hmac::HMAC_SHA384, + }); + +static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[ + SignatureScheme::ED25519, + SignatureScheme::ECDSA_NISTP521_SHA512, + SignatureScheme::ECDSA_NISTP384_SHA384, + SignatureScheme::ECDSA_NISTP256_SHA256, +]; + +static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[ + SignatureScheme::RSA_PSS_SHA512, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA256, + SignatureScheme::RSA_PKCS1_SHA512, + SignatureScheme::RSA_PKCS1_SHA384, + SignatureScheme::RSA_PKCS1_SHA256, +]; + +/// A TLS 1.2 cipher suite supported by rustls. +pub struct Tls12CipherSuite { + /// Common cipher suite fields. + pub common: CipherSuiteCommon, + pub(crate) hmac_algorithm: ring::hmac::Algorithm, + /// How to exchange/agree keys. + pub kx: KeyExchangeAlgorithm, + + /// How to sign messages for authentication. + pub sign: &'static [SignatureScheme], + + /// How long the fixed part of the 'IV' is. + /// + /// This isn't usually an IV, but we continue the + /// terminology misuse to match the standard. + pub fixed_iv_len: usize, + + /// This is a non-standard extension which extends the + /// key block to provide an initial explicit nonce offset, + /// in a deterministic and safe way. GCM needs this, + /// chacha20poly1305 works this way by design. + pub explicit_nonce_len: usize, + + pub(crate) aead_alg: &'static dyn Tls12AeadAlgorithm, +} + +impl Tls12CipherSuite { + /// Resolve the set of supported `SignatureScheme`s from the + /// offered `SupportedSignatureSchemes`. If we return an empty + /// set, the handshake terminates. + pub fn resolve_sig_schemes(&self, offered: &[SignatureScheme]) -> Vec { + self.sign + .iter() + .filter(|pref| offered.contains(pref)) + .cloned() + .collect() + } + + /// Which hash function to use with this suite. + pub(crate) fn hash_algorithm(&self) -> &'static ring::digest::Algorithm { + self.hmac_algorithm.digest_algorithm() + } +} + +impl From<&'static Tls12CipherSuite> for SupportedCipherSuite { + fn from(s: &'static Tls12CipherSuite) -> Self { + Self::Tls12(s) + } +} + +impl PartialEq for Tls12CipherSuite { + fn eq(&self, other: &Self) -> bool { + self.common.suite == other.common.suite + } +} + +impl fmt::Debug for Tls12CipherSuite { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Tls12CipherSuite") + .field("suite", &self.common.suite) + .field("bulk", &self.common.bulk) + .finish() + } +} + +/// TLS1.2 per-connection keying material +pub(crate) struct ConnectionSecrets { + pub(crate) randoms: ConnectionRandoms, + suite: &'static Tls12CipherSuite, + pub(crate) master_secret: [u8; 48], +} + +impl ConnectionSecrets { + pub(crate) fn from_key_exchange( + kx: kx::KeyExchange, + peer_pub_key: &[u8], + ems_seed: Option, + randoms: ConnectionRandoms, + suite: &'static Tls12CipherSuite, + ) -> Result { + let mut ret = Self { + randoms, + suite, + master_secret: [0u8; 48], + }; + + let (label, seed) = match ems_seed { + Some(seed) => ("extended master secret", Seed::Ems(seed)), + None => ( + "master secret", + Seed::Randoms(join_randoms(&ret.randoms.client, &ret.randoms.server)), + ), + }; + + kx.complete(peer_pub_key, |secret| { + prf::prf( + &mut ret.master_secret, + suite.hmac_algorithm, + secret, + label.as_bytes(), + seed.as_ref(), + ); + })?; + + Ok(ret) + } + + pub(crate) fn new_resume( + randoms: ConnectionRandoms, + suite: &'static Tls12CipherSuite, + master_secret: &[u8], + ) -> Self { + let mut ret = Self { + randoms, + suite, + master_secret: [0u8; 48], + }; + ret.master_secret + .copy_from_slice(master_secret); + ret + } + + /// Make a `MessageCipherPair` based on the given supported ciphersuite `scs`, + /// and the session's `secrets`. + pub(crate) fn make_cipher_pair(&self, side: Side) -> MessageCipherPair { + fn split_key<'a>( + key_block: &'a [u8], + alg: &'static aead::Algorithm, + ) -> (aead::LessSafeKey, &'a [u8]) { + // Might panic if the key block is too small. + let (key, rest) = key_block.split_at(alg.key_len()); + // Won't panic because its only prerequisite is that `key` is `alg.key_len()` bytes long. + let key = aead::UnboundKey::new(alg, key).unwrap(); + (aead::LessSafeKey::new(key), rest) + } + + // Make a key block, and chop it up. + // nb. we don't implement any ciphersuites with nonzero mac_key_len. + let key_block = self.make_key_block(); + + let suite = self.suite; + let scs = &suite.common; + + let (client_write_key, key_block) = split_key(&key_block, scs.aead_algorithm); + let (server_write_key, key_block) = split_key(key_block, scs.aead_algorithm); + let (client_write_iv, key_block) = key_block.split_at(suite.fixed_iv_len); + let (server_write_iv, extra) = key_block.split_at(suite.fixed_iv_len); + + let (write_key, write_iv, read_key, read_iv) = match side { + Side::Client => ( + client_write_key, + client_write_iv, + server_write_key, + server_write_iv, + ), + Side::Server => ( + server_write_key, + server_write_iv, + client_write_key, + client_write_iv, + ), + }; + + ( + suite + .aead_alg + .decrypter(read_key, read_iv), + suite + .aead_alg + .encrypter(write_key, write_iv, extra), + ) + } + + fn make_key_block(&self) -> Vec { + let suite = &self.suite; + let common = &self.suite.common; + + let len = + (common.aead_algorithm.key_len() + suite.fixed_iv_len) * 2 + suite.explicit_nonce_len; + + let mut out = vec![0u8; len]; + + // NOTE: opposite order to above for no good reason. + // Don't design security protocols on drugs, kids. + let randoms = join_randoms(&self.randoms.server, &self.randoms.client); + prf::prf( + &mut out, + self.suite.hmac_algorithm, + &self.master_secret, + b"key expansion", + &randoms, + ); + + out + } + + pub(crate) fn suite(&self) -> &'static Tls12CipherSuite { + self.suite + } + + pub(crate) fn get_master_secret(&self) -> Vec { + let mut ret = Vec::new(); + ret.extend_from_slice(&self.master_secret); + ret + } + + fn make_verify_data(&self, handshake_hash: &Digest, label: &[u8]) -> Vec { + let mut out = vec![0u8; 12]; + + prf::prf( + &mut out, + self.suite.hmac_algorithm, + &self.master_secret, + label, + handshake_hash.as_ref(), + ); + out + } + + pub(crate) fn client_verify_data(&self, handshake_hash: &Digest) -> Vec { + self.make_verify_data(handshake_hash, b"client finished") + } + + pub(crate) fn server_verify_data(&self, handshake_hash: &Digest) -> Vec { + self.make_verify_data(handshake_hash, b"server finished") + } + + pub(crate) fn export_keying_material( + &self, + output: &mut [u8], + label: &[u8], + context: Option<&[u8]>, + ) { + let mut randoms = Vec::new(); + randoms.extend_from_slice(&self.randoms.client); + randoms.extend_from_slice(&self.randoms.server); + if let Some(context) = context { + assert!(context.len() <= 0xffff); + (context.len() as u16).encode(&mut randoms); + randoms.extend_from_slice(context); + } + + prf::prf( + output, + self.suite.hmac_algorithm, + &self.master_secret, + label, + &randoms, + ); + } + + #[cfg(feature = "secret_extraction")] + pub(crate) fn extract_secrets(&self, side: Side) -> Result { + // Make a key block, and chop it up + let key_block = self.make_key_block(); + + let suite = self.suite; + let algo = suite.common.aead_algorithm; + + let (client_key, key_block) = key_block.split_at(algo.key_len()); + let (server_key, key_block) = key_block.split_at(algo.key_len()); + let (client_iv, key_block) = key_block.split_at(suite.fixed_iv_len); + let (server_iv, extra) = key_block.split_at(suite.fixed_iv_len); + + // A key/IV pair (fixed IV len is 4 for GCM, 12 for Chacha) + struct Pair<'a> { + key: &'a [u8], + iv: &'a [u8], + } + + let client_pair = Pair { + key: client_key, + iv: client_iv, + }; + let server_pair = Pair { + key: server_key, + iv: server_iv, + }; + + let (client_secrets, server_secrets) = if algo == &ring::aead::AES_128_GCM { + let extract = |pair: Pair| -> ConnectionTrafficSecrets { + let mut key = [0u8; 16]; + key.copy_from_slice(pair.key); + + let mut salt = [0u8; 4]; + salt.copy_from_slice(pair.iv); + + let mut iv = [0u8; 8]; + iv.copy_from_slice(&extra[..8]); + + ConnectionTrafficSecrets::Aes128Gcm { key, salt, iv } + }; + + (extract(client_pair), extract(server_pair)) + } else if algo == &ring::aead::AES_256_GCM { + let extract = |pair: Pair| -> ConnectionTrafficSecrets { + let mut key = [0u8; 32]; + key.copy_from_slice(pair.key); + + let mut salt = [0u8; 4]; + salt.copy_from_slice(pair.iv); + + let mut iv = [0u8; 8]; + iv.copy_from_slice(&extra[..8]); + + ConnectionTrafficSecrets::Aes256Gcm { key, salt, iv } + }; + + (extract(client_pair), extract(server_pair)) + } else if algo == &ring::aead::CHACHA20_POLY1305 { + let extract = |pair: Pair| -> ConnectionTrafficSecrets { + let mut key = [0u8; 32]; + key.copy_from_slice(pair.key); + + let mut iv = [0u8; 12]; + iv.copy_from_slice(pair.iv); + + ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv } + }; + + (extract(client_pair), extract(server_pair)) + } else { + return Err(Error::General(format!( + "exporting secrets for {:?}: unimplemented", + algo + ))); + }; + + let (tx, rx) = match side { + Side::Client => (client_secrets, server_secrets), + Side::Server => (server_secrets, client_secrets), + }; + Ok(PartiallyExtractedSecrets { tx, rx }) + } +} + +enum Seed { + Ems(Digest), + Randoms([u8; 64]), +} + +impl AsRef<[u8]> for Seed { + fn as_ref(&self) -> &[u8] { + match self { + Self::Ems(seed) => seed.as_ref(), + Self::Randoms(randoms) => randoms.as_ref(), + } + } +} + +fn join_randoms(first: &[u8; 32], second: &[u8; 32]) -> [u8; 64] { + let mut randoms = [0u8; 64]; + randoms[..32].copy_from_slice(first); + randoms[32..].copy_from_slice(second); + randoms +} + +type MessageCipherPair = (Box, Box); + +pub(crate) fn decode_ecdh_params( + common: &mut CommonState, + kx_params: &[u8], +) -> Result { + let mut rd = Reader::init(kx_params); + let ecdh_params = T::read(&mut rd)?; + match rd.any_left() { + false => Ok(ecdh_params), + true => Err(common.send_fatal_alert( + AlertDescription::DecodeError, + InvalidMessage::InvalidDhParams, + )), + } +} + +pub(crate) const DOWNGRADE_SENTINEL: [u8; 8] = [0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01]; + +#[cfg(test)] +mod tests { + use super::*; + use crate::common_state::{CommonState, Side}; + use crate::msgs::handshake::{ClientECDHParams, ServerECDHParams}; + + #[test] + fn server_ecdhe_remaining_bytes() { + let key = kx::KeyExchange::start(&kx::X25519).unwrap(); + let server_params = ServerECDHParams::new(key.group(), key.pubkey.as_ref()); + let mut server_buf = Vec::new(); + server_params.encode(&mut server_buf); + server_buf.push(34); + + let mut common = CommonState::new(Side::Client); + assert!(decode_ecdh_params::(&mut common, &server_buf).is_err()); + } + + #[test] + fn client_ecdhe_invalid() { + let mut common = CommonState::new(Side::Server); + assert!(decode_ecdh_params::(&mut common, &[34]).is_err()); + } +} diff --git a/vendor/rustls-0.21.8/src/tls12/prf.rs b/vendor/rustls-0.21.8/src/tls12/prf.rs new file mode 100644 index 0000000000000..673748f809687 --- /dev/null +++ b/vendor/rustls-0.21.8/src/tls12/prf.rs @@ -0,0 +1,83 @@ +use ring::hmac; + +fn concat_sign(key: &hmac::Key, a: &[u8], b: &[u8]) -> hmac::Tag { + let mut ctx = hmac::Context::with_key(key); + ctx.update(a); + ctx.update(b); + ctx.sign() +} + +fn p(out: &mut [u8], alg: hmac::Algorithm, secret: &[u8], seed: &[u8]) { + let hmac_key = hmac::Key::new(alg, secret); + + // A(1) + let mut current_a = hmac::sign(&hmac_key, seed); + let chunk_size = alg.digest_algorithm().output_len(); + for chunk in out.chunks_mut(chunk_size) { + // P_hash[i] = HMAC_hash(secret, A(i) + seed) + let p_term = concat_sign(&hmac_key, current_a.as_ref(), seed); + chunk.copy_from_slice(&p_term.as_ref()[..chunk.len()]); + + // A(i+1) = HMAC_hash(secret, A(i)) + current_a = hmac::sign(&hmac_key, current_a.as_ref()); + } +} + +fn concat(a: &[u8], b: &[u8]) -> Vec { + let mut ret = Vec::new(); + ret.extend_from_slice(a); + ret.extend_from_slice(b); + ret +} + +pub(crate) fn prf(out: &mut [u8], alg: hmac::Algorithm, secret: &[u8], label: &[u8], seed: &[u8]) { + let joined_seed = concat(label, seed); + p(out, alg, secret, &joined_seed); +} + +#[cfg(test)] +mod tests { + use ring::hmac::{HMAC_SHA256, HMAC_SHA512}; + + #[test] + fn check_sha256() { + let secret = b"\x9b\xbe\x43\x6b\xa9\x40\xf0\x17\xb1\x76\x52\x84\x9a\x71\xdb\x35"; + let seed = b"\xa0\xba\x9f\x93\x6c\xda\x31\x18\x27\xa6\xf7\x96\xff\xd5\x19\x8c"; + let label = b"test label"; + let expect = include_bytes!("../testdata/prf-result.1.bin"); + let mut output = [0u8; 100]; + + super::prf(&mut output, HMAC_SHA256, secret, label, seed); + assert_eq!(expect.len(), output.len()); + assert_eq!(expect.to_vec(), output.to_vec()); + } + + #[test] + fn check_sha512() { + let secret = b"\xb0\x32\x35\x23\xc1\x85\x35\x99\x58\x4d\x88\x56\x8b\xbb\x05\xeb"; + let seed = b"\xd4\x64\x0e\x12\xe4\xbc\xdb\xfb\x43\x7f\x03\xe6\xae\x41\x8e\xe5"; + let label = b"test label"; + let expect = include_bytes!("../testdata/prf-result.2.bin"); + let mut output = [0u8; 196]; + + super::prf(&mut output, HMAC_SHA512, secret, label, seed); + assert_eq!(expect.len(), output.len()); + assert_eq!(expect.to_vec(), output.to_vec()); + } +} + +#[cfg(bench)] +mod benchmarks { + #[bench] + fn bench_sha256(b: &mut test::Bencher) { + let label = &b"extended master secret"[..]; + let seed = [0u8; 32]; + let key = &b"secret"[..]; + + b.iter(|| { + let mut out = [0u8; 48]; + super::prf(&mut out, ring::hmac::HMAC_SHA256, key, &label, &seed); + test::black_box(out); + }); + } +} diff --git a/vendor/rustls-0.21.8/src/tls13/key_schedule.rs b/vendor/rustls-0.21.8/src/tls13/key_schedule.rs new file mode 100644 index 0000000000000..b3cadf0dd7779 --- /dev/null +++ b/vendor/rustls-0.21.8/src/tls13/key_schedule.rs @@ -0,0 +1,1042 @@ +use crate::cipher::{Iv, IvLen, MessageDecrypter}; +use crate::common_state::{CommonState, Side}; +use crate::error::Error; +use crate::msgs::base::PayloadU8; +#[cfg(feature = "quic")] +use crate::quic; +#[cfg(feature = "secret_extraction")] +use crate::suites::{ConnectionTrafficSecrets, PartiallyExtractedSecrets}; +use crate::{KeyLog, Tls13CipherSuite}; + +/// Key schedule maintenance for TLS1.3 +use ring::{ + aead, + digest::{self, Digest}, + hkdf::{self, KeyType as _}, + hmac, +}; + +use super::{Tls13MessageDecrypter, Tls13MessageEncrypter}; + +/// The kinds of secret we can extract from `KeySchedule`. +#[derive(Debug, Clone, Copy, PartialEq)] +enum SecretKind { + ResumptionPskBinderKey, + ClientEarlyTrafficSecret, + ClientHandshakeTrafficSecret, + ServerHandshakeTrafficSecret, + ClientApplicationTrafficSecret, + ServerApplicationTrafficSecret, + ExporterMasterSecret, + ResumptionMasterSecret, + DerivedSecret, +} + +impl SecretKind { + fn to_bytes(self) -> &'static [u8] { + use self::SecretKind::*; + match self { + ResumptionPskBinderKey => b"res binder", + ClientEarlyTrafficSecret => b"c e traffic", + ClientHandshakeTrafficSecret => b"c hs traffic", + ServerHandshakeTrafficSecret => b"s hs traffic", + ClientApplicationTrafficSecret => b"c ap traffic", + ServerApplicationTrafficSecret => b"s ap traffic", + ExporterMasterSecret => b"exp master", + ResumptionMasterSecret => b"res master", + DerivedSecret => b"derived", + } + } + + fn log_label(self) -> Option<&'static str> { + use self::SecretKind::*; + Some(match self { + ClientEarlyTrafficSecret => "CLIENT_EARLY_TRAFFIC_SECRET", + ClientHandshakeTrafficSecret => "CLIENT_HANDSHAKE_TRAFFIC_SECRET", + ServerHandshakeTrafficSecret => "SERVER_HANDSHAKE_TRAFFIC_SECRET", + ClientApplicationTrafficSecret => "CLIENT_TRAFFIC_SECRET_0", + ServerApplicationTrafficSecret => "SERVER_TRAFFIC_SECRET_0", + ExporterMasterSecret => "EXPORTER_SECRET", + _ => { + return None; + } + }) + } +} + +/// This is the TLS1.3 key schedule. It stores the current secret and +/// the type of hash. This isn't used directly; but only through the +/// typestates. +struct KeySchedule { + current: hkdf::Prk, + suite: &'static Tls13CipherSuite, +} + +// We express the state of a contained KeySchedule using these +// typestates. This means we can write code that cannot accidentally +// (e.g.) encrypt application data using a KeySchedule solely constructed +// with an empty or trivial secret, or extract the wrong kind of secrets +// at a given point. + +/// KeySchedule for early data stage. +pub(crate) struct KeyScheduleEarly { + ks: KeySchedule, +} + +impl KeyScheduleEarly { + pub(crate) fn new(suite: &'static Tls13CipherSuite, secret: &[u8]) -> Self { + Self { + ks: KeySchedule::new(suite, secret), + } + } + + pub(crate) fn client_early_traffic_secret( + &self, + hs_hash: &Digest, + key_log: &dyn KeyLog, + client_random: &[u8; 32], + common: &mut CommonState, + ) { + let client_early_traffic_secret = self.ks.derive_logged_secret( + SecretKind::ClientEarlyTrafficSecret, + hs_hash.as_ref(), + key_log, + client_random, + ); + + match common.side { + Side::Client => self + .ks + .set_encrypter(&client_early_traffic_secret, common), + Side::Server => self + .ks + .set_decrypter(&client_early_traffic_secret, common), + } + + #[cfg(feature = "quic")] + if common.is_quic() { + // If 0-RTT should be rejected, this will be clobbered by ExtensionProcessing + // before the application can see. + common.quic.early_secret = Some(client_early_traffic_secret); + } + } + + pub(crate) fn resumption_psk_binder_key_and_sign_verify_data( + &self, + hs_hash: &Digest, + ) -> hmac::Tag { + let resumption_psk_binder_key = self + .ks + .derive_for_empty_hash(SecretKind::ResumptionPskBinderKey); + self.ks + .sign_verify_data(&resumption_psk_binder_key, hs_hash) + } +} + +/// Pre-handshake key schedule +/// +/// The inner `KeySchedule` is either constructed without any secrets based on ths HKDF algorithm +/// or is extracted from a `KeyScheduleEarly`. This can then be used to derive the `KeyScheduleHandshakeStart`. +pub(crate) struct KeySchedulePreHandshake { + ks: KeySchedule, +} + +impl KeySchedulePreHandshake { + pub(crate) fn new(suite: &'static Tls13CipherSuite) -> Self { + Self { + ks: KeySchedule::new_with_empty_secret(suite), + } + } + + pub(crate) fn into_handshake(mut self, secret: &[u8]) -> KeyScheduleHandshakeStart { + self.ks.input_secret(secret); + KeyScheduleHandshakeStart { ks: self.ks } + } +} + +impl From for KeySchedulePreHandshake { + fn from(KeyScheduleEarly { ks }: KeyScheduleEarly) -> Self { + Self { ks } + } +} + +/// KeySchedule during handshake. +pub(crate) struct KeyScheduleHandshakeStart { + ks: KeySchedule, +} + +impl KeyScheduleHandshakeStart { + pub(crate) fn derive_client_handshake_secrets( + mut self, + early_data_enabled: bool, + hs_hash: Digest, + suite: &'static Tls13CipherSuite, + key_log: &dyn KeyLog, + client_random: &[u8; 32], + common: &mut CommonState, + ) -> KeyScheduleHandshake { + debug_assert_eq!(common.side, Side::Client); + // Suite might have changed due to resumption + self.ks.suite = suite; + let new = self.into_handshake(hs_hash, key_log, client_random, common); + + // Decrypt with the peer's key, encrypt with our own key + new.ks + .set_decrypter(&new.server_handshake_traffic_secret, common); + + if !early_data_enabled { + // Set the client encryption key for handshakes if early data is not used + new.ks + .set_encrypter(&new.client_handshake_traffic_secret, common); + } + + new + } + + pub(crate) fn derive_server_handshake_secrets( + self, + hs_hash: Digest, + key_log: &dyn KeyLog, + client_random: &[u8; 32], + common: &mut CommonState, + ) -> KeyScheduleHandshake { + debug_assert_eq!(common.side, Side::Server); + let new = self.into_handshake(hs_hash, key_log, client_random, common); + + // Set up to encrypt with handshake secrets, but decrypt with early_data keys. + // If not doing early_data after all, this is corrected later to the handshake + // keys (now stored in key_schedule). + new.ks + .set_encrypter(&new.server_handshake_traffic_secret, common); + new + } + + fn into_handshake( + self, + hs_hash: Digest, + key_log: &dyn KeyLog, + client_random: &[u8; 32], + _common: &mut CommonState, + ) -> KeyScheduleHandshake { + // Use an empty handshake hash for the initial handshake. + let client_secret = self.ks.derive_logged_secret( + SecretKind::ClientHandshakeTrafficSecret, + hs_hash.as_ref(), + key_log, + client_random, + ); + + let server_secret = self.ks.derive_logged_secret( + SecretKind::ServerHandshakeTrafficSecret, + hs_hash.as_ref(), + key_log, + client_random, + ); + + #[cfg(feature = "quic")] + if _common.is_quic() { + _common.quic.hs_secrets = Some(quic::Secrets::new( + client_secret.clone(), + server_secret.clone(), + self.ks.suite, + _common.side, + _common.quic.version, + )); + } + + KeyScheduleHandshake { + ks: self.ks, + client_handshake_traffic_secret: client_secret, + server_handshake_traffic_secret: server_secret, + } + } +} + +pub(crate) struct KeyScheduleHandshake { + ks: KeySchedule, + client_handshake_traffic_secret: hkdf::Prk, + server_handshake_traffic_secret: hkdf::Prk, +} + +impl KeyScheduleHandshake { + pub(crate) fn sign_server_finish(&self, hs_hash: &Digest) -> hmac::Tag { + self.ks + .sign_finish(&self.server_handshake_traffic_secret, hs_hash) + } + + pub(crate) fn set_handshake_encrypter(&self, common: &mut CommonState) { + debug_assert_eq!(common.side, Side::Client); + self.ks + .set_encrypter(&self.client_handshake_traffic_secret, common); + } + + pub(crate) fn set_handshake_decrypter( + &self, + skip_requested: Option, + common: &mut CommonState, + ) { + debug_assert_eq!(common.side, Side::Server); + let secret = &self.client_handshake_traffic_secret; + match skip_requested { + None => self.ks.set_decrypter(secret, common), + Some(max_early_data_size) => common + .record_layer + .set_message_decrypter_with_trial_decryption( + self.ks + .derive_decrypter(&self.client_handshake_traffic_secret), + max_early_data_size, + ), + } + } + + pub(crate) fn into_traffic_with_client_finished_pending( + self, + hs_hash: Digest, + key_log: &dyn KeyLog, + client_random: &[u8; 32], + common: &mut CommonState, + ) -> KeyScheduleTrafficWithClientFinishedPending { + debug_assert_eq!(common.side, Side::Server); + + let traffic = KeyScheduleTraffic::new(self.ks, hs_hash, key_log, client_random); + let (_client_secret, server_secret) = ( + &traffic.current_client_traffic_secret, + &traffic.current_server_traffic_secret, + ); + + traffic + .ks + .set_encrypter(server_secret, common); + + #[cfg(feature = "quic")] + if common.is_quic() { + common.quic.traffic_secrets = Some(quic::Secrets::new( + _client_secret.clone(), + server_secret.clone(), + traffic.ks.suite, + common.side, + common.quic.version, + )); + } + + KeyScheduleTrafficWithClientFinishedPending { + handshake_client_traffic_secret: self.client_handshake_traffic_secret, + traffic, + } + } + + pub(crate) fn into_pre_finished_client_traffic( + self, + pre_finished_hash: Digest, + handshake_hash: Digest, + key_log: &dyn KeyLog, + client_random: &[u8; 32], + ) -> (KeyScheduleClientBeforeFinished, hmac::Tag) { + let traffic = KeyScheduleTraffic::new(self.ks, pre_finished_hash, key_log, client_random); + let tag = traffic + .ks + .sign_finish(&self.client_handshake_traffic_secret, &handshake_hash); + (KeyScheduleClientBeforeFinished { traffic }, tag) + } +} + +pub(crate) struct KeyScheduleClientBeforeFinished { + traffic: KeyScheduleTraffic, +} + +impl KeyScheduleClientBeforeFinished { + pub(crate) fn into_traffic(self, common: &mut CommonState) -> KeyScheduleTraffic { + debug_assert_eq!(common.side, Side::Client); + let (client_secret, server_secret) = ( + &self + .traffic + .current_client_traffic_secret, + &self + .traffic + .current_server_traffic_secret, + ); + + self.traffic + .ks + .set_decrypter(server_secret, common); + self.traffic + .ks + .set_encrypter(client_secret, common); + + #[cfg(feature = "quic")] + if common.is_quic() { + common.quic.traffic_secrets = Some(quic::Secrets::new( + client_secret.clone(), + server_secret.clone(), + self.traffic.ks.suite, + common.side, + common.quic.version, + )); + } + + self.traffic + } +} + +/// KeySchedule during traffic stage, retaining the ability to calculate the client's +/// finished verify_data. The traffic stage key schedule can be extracted from it +/// through signing the client finished hash. +pub(crate) struct KeyScheduleTrafficWithClientFinishedPending { + handshake_client_traffic_secret: hkdf::Prk, + traffic: KeyScheduleTraffic, +} + +impl KeyScheduleTrafficWithClientFinishedPending { + pub(crate) fn update_decrypter(&self, common: &mut CommonState) { + debug_assert_eq!(common.side, Side::Server); + self.traffic + .ks + .set_decrypter(&self.handshake_client_traffic_secret, common); + } + + pub(crate) fn sign_client_finish( + self, + hs_hash: &Digest, + common: &mut CommonState, + ) -> (KeyScheduleTraffic, hmac::Tag) { + debug_assert_eq!(common.side, Side::Server); + let tag = self + .traffic + .ks + .sign_finish(&self.handshake_client_traffic_secret, hs_hash); + + // Install keying to read future messages. + self.traffic.ks.set_decrypter( + &self + .traffic + .current_client_traffic_secret, + common, + ); + + (self.traffic, tag) + } +} + +/// KeySchedule during traffic stage. All traffic & exporter keys are guaranteed +/// to be available. +pub(crate) struct KeyScheduleTraffic { + ks: KeySchedule, + current_client_traffic_secret: hkdf::Prk, + current_server_traffic_secret: hkdf::Prk, + current_exporter_secret: hkdf::Prk, +} + +impl KeyScheduleTraffic { + fn new( + mut ks: KeySchedule, + hs_hash: Digest, + key_log: &dyn KeyLog, + client_random: &[u8; 32], + ) -> Self { + ks.input_empty(); + + let current_client_traffic_secret = ks.derive_logged_secret( + SecretKind::ClientApplicationTrafficSecret, + hs_hash.as_ref(), + key_log, + client_random, + ); + + let current_server_traffic_secret = ks.derive_logged_secret( + SecretKind::ServerApplicationTrafficSecret, + hs_hash.as_ref(), + key_log, + client_random, + ); + + let current_exporter_secret = ks.derive_logged_secret( + SecretKind::ExporterMasterSecret, + hs_hash.as_ref(), + key_log, + client_random, + ); + + Self { + ks, + current_client_traffic_secret, + current_server_traffic_secret, + current_exporter_secret, + } + } + + pub(crate) fn update_encrypter_and_notify(&mut self, common: &mut CommonState) { + let secret = self.next_application_traffic_secret(common.side); + common.enqueue_key_update_notification(); + self.ks.set_encrypter(&secret, common); + } + + pub(crate) fn update_decrypter(&mut self, common: &mut CommonState) { + let secret = self.next_application_traffic_secret(common.side.peer()); + self.ks.set_decrypter(&secret, common); + } + + pub(crate) fn next_application_traffic_secret(&mut self, side: Side) -> hkdf::Prk { + let current = match side { + Side::Client => &mut self.current_client_traffic_secret, + Side::Server => &mut self.current_server_traffic_secret, + }; + + let secret = self.ks.derive_next(current); + *current = secret.clone(); + secret + } + + pub(crate) fn resumption_master_secret_and_derive_ticket_psk( + &self, + hs_hash: &Digest, + nonce: &[u8], + ) -> Vec { + let resumption_master_secret = self.ks.derive( + self.ks.algorithm(), + SecretKind::ResumptionMasterSecret, + hs_hash.as_ref(), + ); + self.ks + .derive_ticket_psk(&resumption_master_secret, nonce) + } + + pub(crate) fn export_keying_material( + &self, + out: &mut [u8], + label: &[u8], + context: Option<&[u8]>, + ) -> Result<(), Error> { + self.ks + .export_keying_material(&self.current_exporter_secret, out, label, context) + } + + #[cfg(feature = "secret_extraction")] + pub(crate) fn extract_secrets(&self, side: Side) -> Result { + fn expand( + secret: &hkdf::Prk, + ) -> Result<([u8; KEY_LEN], [u8; IV_LEN]), Error> { + let mut key = [0u8; KEY_LEN]; + let mut iv = [0u8; IV_LEN]; + + hkdf_expand_info(secret, PayloadU8Len(key.len()), b"key", &[], |okm| { + okm.fill(&mut key) + }) + .map_err(|_| Error::General("hkdf_expand_info failed".to_string()))?; + + hkdf_expand_info(secret, PayloadU8Len(iv.len()), b"iv", &[], |okm| { + okm.fill(&mut iv) + }) + .map_err(|_| Error::General("hkdf_expand_info failed".to_string()))?; + + Ok((key, iv)) + } + + let client_secrets; + let server_secrets; + + let algo = self.ks.suite.common.aead_algorithm; + if algo == &ring::aead::AES_128_GCM { + let extract = |secret: &hkdf::Prk| -> Result { + let (key, iv_in) = expand::<16, 12>(secret)?; + + let mut salt = [0u8; 4]; + salt.copy_from_slice(&iv_in[..4]); + + let mut iv = [0u8; 8]; + iv.copy_from_slice(&iv_in[4..]); + + Ok(ConnectionTrafficSecrets::Aes128Gcm { key, salt, iv }) + }; + + client_secrets = extract(&self.current_client_traffic_secret)?; + server_secrets = extract(&self.current_server_traffic_secret)?; + } else if algo == &ring::aead::AES_256_GCM { + let extract = |secret: &hkdf::Prk| -> Result { + let (key, iv_in) = expand::<32, 12>(secret)?; + + let mut salt = [0u8; 4]; + salt.copy_from_slice(&iv_in[..4]); + + let mut iv = [0u8; 8]; + iv.copy_from_slice(&iv_in[4..]); + + Ok(ConnectionTrafficSecrets::Aes256Gcm { key, salt, iv }) + }; + + client_secrets = extract(&self.current_client_traffic_secret)?; + server_secrets = extract(&self.current_server_traffic_secret)?; + } else if algo == &ring::aead::CHACHA20_POLY1305 { + let extract = |secret: &hkdf::Prk| -> Result { + let (key, iv) = expand::<32, 12>(secret)?; + Ok(ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv }) + }; + + client_secrets = extract(&self.current_client_traffic_secret)?; + server_secrets = extract(&self.current_server_traffic_secret)?; + } else { + return Err(Error::General(format!( + "exporting secrets for {:?}: unimplemented", + algo + ))); + } + + let (tx, rx) = match side { + Side::Client => (client_secrets, server_secrets), + Side::Server => (server_secrets, client_secrets), + }; + Ok(PartiallyExtractedSecrets { tx, rx }) + } +} + +impl KeySchedule { + fn new(suite: &'static Tls13CipherSuite, secret: &[u8]) -> Self { + let zeroes = [0u8; digest::MAX_OUTPUT_LEN]; + let salt = hkdf::Salt::new(suite.hkdf_algorithm, &zeroes[..suite.hkdf_algorithm.len()]); + Self { + current: salt.extract(secret), + suite, + } + } + + fn set_encrypter(&self, secret: &hkdf::Prk, common: &mut CommonState) { + let key = derive_traffic_key(secret, self.suite.common.aead_algorithm); + let iv = derive_traffic_iv(secret); + + common + .record_layer + .set_message_encrypter(Box::new(Tls13MessageEncrypter { + enc_key: aead::LessSafeKey::new(key), + iv, + })); + } + + fn set_decrypter(&self, secret: &hkdf::Prk, common: &mut CommonState) { + common + .record_layer + .set_message_decrypter(self.derive_decrypter(secret)); + } + + fn derive_decrypter(&self, secret: &hkdf::Prk) -> Box { + let key = derive_traffic_key(secret, self.suite.common.aead_algorithm); + let iv = derive_traffic_iv(secret); + Box::new(Tls13MessageDecrypter { + dec_key: aead::LessSafeKey::new(key), + iv, + }) + } + + #[inline] + fn algorithm(&self) -> hkdf::Algorithm { + self.suite.hkdf_algorithm + } + + fn new_with_empty_secret(suite: &'static Tls13CipherSuite) -> Self { + let zeroes = [0u8; digest::MAX_OUTPUT_LEN]; + Self::new(suite, &zeroes[..suite.hkdf_algorithm.len()]) + } + + /// Input the empty secret. + fn input_empty(&mut self) { + let zeroes = [0u8; digest::MAX_OUTPUT_LEN]; + self.input_secret(&zeroes[..self.suite.hkdf_algorithm.len()]); + } + + /// Input the given secret. + fn input_secret(&mut self, secret: &[u8]) { + let salt: hkdf::Salt = self.derive_for_empty_hash(SecretKind::DerivedSecret); + self.current = salt.extract(secret); + } + + /// Derive a secret of given `kind`, using current handshake hash `hs_hash`. + fn derive(&self, key_type: L, kind: SecretKind, hs_hash: &[u8]) -> T + where + T: for<'a> From>, + L: hkdf::KeyType, + { + hkdf_expand(&self.current, key_type, kind.to_bytes(), hs_hash) + } + + fn derive_logged_secret( + &self, + kind: SecretKind, + hs_hash: &[u8], + key_log: &dyn KeyLog, + client_random: &[u8; 32], + ) -> hkdf::Prk { + let log_label = kind + .log_label() + .expect("not a loggable secret"); + if key_log.will_log(log_label) { + let secret = self + .derive::( + PayloadU8Len(self.suite.hkdf_algorithm.len()), + kind, + hs_hash, + ) + .into_inner(); + key_log.log(log_label, client_random, &secret); + } + self.derive(self.suite.hkdf_algorithm, kind, hs_hash) + } + + /// Derive a secret of given `kind` using the hash of the empty string + /// for the handshake hash. Useful only for + /// `SecretKind::ResumptionPSKBinderKey` and + /// `SecretKind::DerivedSecret`. + fn derive_for_empty_hash(&self, kind: SecretKind) -> T + where + T: for<'a> From>, + { + let digest_alg = self + .suite + .hkdf_algorithm + .hmac_algorithm() + .digest_algorithm(); + let empty_hash = digest::digest(digest_alg, &[]); + self.derive(self.suite.hkdf_algorithm, kind, empty_hash.as_ref()) + } + + /// Sign the finished message consisting of `hs_hash` using a current + /// traffic secret. + fn sign_finish(&self, base_key: &hkdf::Prk, hs_hash: &Digest) -> hmac::Tag { + self.sign_verify_data(base_key, hs_hash) + } + + /// Sign the finished message consisting of `hs_hash` using the key material + /// `base_key`. + fn sign_verify_data(&self, base_key: &hkdf::Prk, hs_hash: &Digest) -> hmac::Tag { + let hmac_alg = self + .suite + .hkdf_algorithm + .hmac_algorithm(); + let hmac_key = hkdf_expand(base_key, hmac_alg, b"finished", &[]); + hmac::sign(&hmac_key, hs_hash.as_ref()) + } + + /// Derive the next application traffic secret, returning it. + fn derive_next(&self, base_key: &hkdf::Prk) -> hkdf::Prk { + hkdf_expand(base_key, self.suite.hkdf_algorithm, b"traffic upd", &[]) + } + + /// Derive the PSK to use given a resumption_master_secret and + /// ticket_nonce. + fn derive_ticket_psk(&self, rms: &hkdf::Prk, nonce: &[u8]) -> Vec { + let payload: PayloadU8 = hkdf_expand( + rms, + PayloadU8Len(self.suite.hkdf_algorithm.len()), + b"resumption", + nonce, + ); + payload.into_inner() + } + + fn export_keying_material( + &self, + current_exporter_secret: &hkdf::Prk, + out: &mut [u8], + label: &[u8], + context: Option<&[u8]>, + ) -> Result<(), Error> { + let digest_alg = self + .suite + .hkdf_algorithm + .hmac_algorithm() + .digest_algorithm(); + + let h_empty = digest::digest(digest_alg, &[]); + let secret: hkdf::Prk = hkdf_expand( + current_exporter_secret, + self.suite.hkdf_algorithm, + label, + h_empty.as_ref(), + ); + + let h_context = digest::digest(digest_alg, context.unwrap_or(&[])); + + // TODO: Test what happens when this fails + hkdf_expand_info( + &secret, + PayloadU8Len(out.len()), + b"exporter", + h_context.as_ref(), + |okm| okm.fill(out), + ) + .map_err(|_| Error::General("exporting too much".to_string())) + } +} + +pub(crate) fn hkdf_expand(secret: &hkdf::Prk, key_type: L, label: &[u8], context: &[u8]) -> T +where + T: for<'a> From>, + L: hkdf::KeyType, +{ + hkdf_expand_info(secret, key_type, label, context, |okm| okm.into()) +} + +fn hkdf_expand_info( + secret: &hkdf::Prk, + key_type: L, + label: &[u8], + context: &[u8], + f: F, +) -> T +where + F: for<'b> FnOnce(hkdf::Okm<'b, L>) -> T, + L: hkdf::KeyType, +{ + const LABEL_PREFIX: &[u8] = b"tls13 "; + + let output_len = u16::to_be_bytes(key_type.len() as u16); + let label_len = u8::to_be_bytes((LABEL_PREFIX.len() + label.len()) as u8); + let context_len = u8::to_be_bytes(context.len() as u8); + + let info = &[ + &output_len[..], + &label_len[..], + LABEL_PREFIX, + label, + &context_len[..], + context, + ]; + let okm = secret.expand(info, key_type).unwrap(); + + f(okm) +} + +pub(crate) struct PayloadU8Len(pub(crate) usize); +impl hkdf::KeyType for PayloadU8Len { + fn len(&self) -> usize { + self.0 + } +} + +impl From> for PayloadU8 { + fn from(okm: hkdf::Okm) -> Self { + let mut r = vec![0u8; okm.len().0]; + okm.fill(&mut r[..]).unwrap(); + Self::new(r) + } +} + +pub(crate) fn derive_traffic_key( + secret: &hkdf::Prk, + aead_algorithm: &'static aead::Algorithm, +) -> aead::UnboundKey { + hkdf_expand(secret, aead_algorithm, b"key", &[]) +} + +pub(crate) fn derive_traffic_iv(secret: &hkdf::Prk) -> Iv { + hkdf_expand(secret, IvLen, b"iv", &[]) +} + +#[cfg(test)] +mod test { + use super::{derive_traffic_iv, derive_traffic_key, KeySchedule, SecretKind}; + use crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL; + use crate::KeyLog; + use ring::aead; + + #[test] + fn test_vectors() { + /* These test vectors generated with OpenSSL. */ + let hs_start_hash = [ + 0xec, 0x14, 0x7a, 0x06, 0xde, 0xa3, 0xc8, 0x84, 0x6c, 0x02, 0xb2, 0x23, 0x8e, 0x41, + 0xbd, 0xdc, 0x9d, 0x89, 0xf9, 0xae, 0xa1, 0x7b, 0x5e, 0xfd, 0x4d, 0x74, 0x82, 0xaf, + 0x75, 0x88, 0x1c, 0x0a, + ]; + + let hs_full_hash = [ + 0x75, 0x1a, 0x3d, 0x4a, 0x14, 0xdf, 0xab, 0xeb, 0x68, 0xe9, 0x2c, 0xa5, 0x91, 0x8e, + 0x24, 0x08, 0xb9, 0xbc, 0xb0, 0x74, 0x89, 0x82, 0xec, 0x9c, 0x32, 0x30, 0xac, 0x30, + 0xbb, 0xeb, 0x23, 0xe2, + ]; + + let ecdhe_secret = [ + 0xe7, 0xb8, 0xfe, 0xf8, 0x90, 0x3b, 0x52, 0x0c, 0xb9, 0xa1, 0x89, 0x71, 0xb6, 0x9d, + 0xd4, 0x5d, 0xca, 0x53, 0xce, 0x2f, 0x12, 0xbf, 0x3b, 0xef, 0x93, 0x15, 0xe3, 0x12, + 0x71, 0xdf, 0x4b, 0x40, + ]; + + let client_hts = [ + 0x61, 0x7b, 0x35, 0x07, 0x6b, 0x9d, 0x0e, 0x08, 0xcf, 0x73, 0x1d, 0x94, 0xa8, 0x66, + 0x14, 0x78, 0x41, 0x09, 0xef, 0x25, 0x55, 0x51, 0x92, 0x1d, 0xd4, 0x6e, 0x04, 0x01, + 0x35, 0xcf, 0x46, 0xab, + ]; + + let client_hts_key = [ + 0x62, 0xd0, 0xdd, 0x00, 0xf6, 0x96, 0x19, 0xd3, 0xb8, 0x19, 0x3a, 0xb4, 0xa0, 0x95, + 0x85, 0xa7, + ]; + + let client_hts_iv = [ + 0xff, 0xf7, 0x5d, 0xf5, 0xad, 0x35, 0xd5, 0xcb, 0x3c, 0x53, 0xf3, 0xa9, + ]; + + let server_hts = [ + 0xfc, 0xf7, 0xdf, 0xe6, 0x4f, 0xa2, 0xc0, 0x4f, 0x62, 0x35, 0x38, 0x7f, 0x43, 0x4e, + 0x01, 0x42, 0x23, 0x36, 0xd9, 0xc0, 0x39, 0xde, 0x68, 0x47, 0xa0, 0xb9, 0xdd, 0xcf, + 0x29, 0xa8, 0x87, 0x59, + ]; + + let server_hts_key = [ + 0x04, 0x67, 0xf3, 0x16, 0xa8, 0x05, 0xb8, 0xc4, 0x97, 0xee, 0x67, 0x04, 0x7b, 0xbc, + 0xbc, 0x54, + ]; + + let server_hts_iv = [ + 0xde, 0x83, 0xa7, 0x3e, 0x9d, 0x81, 0x4b, 0x04, 0xc4, 0x8b, 0x78, 0x09, + ]; + + let client_ats = [ + 0xc1, 0x4a, 0x6d, 0x79, 0x76, 0xd8, 0x10, 0x2b, 0x5a, 0x0c, 0x99, 0x51, 0x49, 0x3f, + 0xee, 0x87, 0xdc, 0xaf, 0xf8, 0x2c, 0x24, 0xca, 0xb2, 0x14, 0xe8, 0xbe, 0x71, 0xa8, + 0x20, 0x6d, 0xbd, 0xa5, + ]; + + let client_ats_key = [ + 0xcc, 0x9f, 0x5f, 0x98, 0x0b, 0x5f, 0x10, 0x30, 0x6c, 0xba, 0xd7, 0xbe, 0x98, 0xd7, + 0x57, 0x2e, + ]; + + let client_ats_iv = [ + 0xb8, 0x09, 0x29, 0xe8, 0xd0, 0x2c, 0x70, 0xf6, 0x11, 0x62, 0xed, 0x6b, + ]; + + let server_ats = [ + 0x2c, 0x90, 0x77, 0x38, 0xd3, 0xf8, 0x37, 0x02, 0xd1, 0xe4, 0x59, 0x8f, 0x48, 0x48, + 0x53, 0x1d, 0x9f, 0x93, 0x65, 0x49, 0x1b, 0x9f, 0x7f, 0x52, 0xc8, 0x22, 0x29, 0x0d, + 0x4c, 0x23, 0x21, 0x92, + ]; + + let server_ats_key = [ + 0x0c, 0xb2, 0x95, 0x62, 0xd8, 0xd8, 0x8f, 0x48, 0xb0, 0x2c, 0xbf, 0xbe, 0xd7, 0xe6, + 0x2b, 0xb3, + ]; + + let server_ats_iv = [ + 0x0d, 0xb2, 0x8f, 0x98, 0x85, 0x86, 0xa1, 0xb7, 0xe4, 0xd5, 0xc6, 0x9c, + ]; + + let mut ks = KeySchedule::new_with_empty_secret(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL); + ks.input_secret(&ecdhe_secret); + + assert_traffic_secret( + &ks, + SecretKind::ClientHandshakeTrafficSecret, + &hs_start_hash, + &client_hts, + &client_hts_key, + &client_hts_iv, + ); + + assert_traffic_secret( + &ks, + SecretKind::ServerHandshakeTrafficSecret, + &hs_start_hash, + &server_hts, + &server_hts_key, + &server_hts_iv, + ); + + ks.input_empty(); + + assert_traffic_secret( + &ks, + SecretKind::ClientApplicationTrafficSecret, + &hs_full_hash, + &client_ats, + &client_ats_key, + &client_ats_iv, + ); + + assert_traffic_secret( + &ks, + SecretKind::ServerApplicationTrafficSecret, + &hs_full_hash, + &server_ats, + &server_ats_key, + &server_ats_iv, + ); + } + + fn assert_traffic_secret( + ks: &KeySchedule, + kind: SecretKind, + hash: &[u8], + expected_traffic_secret: &[u8], + expected_key: &[u8], + expected_iv: &[u8], + ) { + struct Log<'a>(&'a [u8]); + impl KeyLog for Log<'_> { + fn log(&self, _label: &str, _client_random: &[u8], secret: &[u8]) { + assert_eq!(self.0, secret); + } + } + let log = Log(expected_traffic_secret); + let traffic_secret = ks.derive_logged_secret(kind, hash, &log, &[0; 32]); + + // Since we can't test key equality, we test the output of sealing with the key instead. + let aead_alg = &aead::AES_128_GCM; + let key = derive_traffic_key(&traffic_secret, aead_alg); + let seal_output = seal_zeroes(key); + let expected_key = aead::UnboundKey::new(aead_alg, expected_key).unwrap(); + let expected_seal_output = seal_zeroes(expected_key); + assert_eq!(seal_output, expected_seal_output); + assert!(seal_output.len() >= 48); // Sanity check. + + let iv = derive_traffic_iv(&traffic_secret); + assert_eq!(iv.value(), expected_iv); + } + + fn seal_zeroes(key: aead::UnboundKey) -> Vec { + let key = aead::LessSafeKey::new(key); + let mut seal_output = vec![0; 32]; + key.seal_in_place_append_tag( + aead::Nonce::assume_unique_for_key([0; aead::NONCE_LEN]), + aead::Aad::empty(), + &mut seal_output, + ) + .unwrap(); + seal_output + } +} + +#[cfg(bench)] +mod benchmarks { + #[bench] + fn bench_sha256(b: &mut test::Bencher) { + use super::{derive_traffic_iv, derive_traffic_key, KeySchedule, SecretKind}; + use crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL; + use crate::KeyLog; + use ring::aead; + + fn extract_traffic_secret(ks: &KeySchedule, kind: SecretKind) { + struct Log; + + impl KeyLog for Log { + fn log(&self, _label: &str, _client_random: &[u8], _secret: &[u8]) {} + } + + let aead_alg = &aead::CHACHA20_POLY1305; + let hash = [0u8; 32]; + let traffic_secret = ks.derive_logged_secret(kind, &hash, &Log, &[0u8; 32]); + test::black_box(derive_traffic_key(&traffic_secret, aead_alg)); + test::black_box(derive_traffic_iv(&traffic_secret)); + } + + b.iter(|| { + let mut ks = + KeySchedule::new_with_empty_secret(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL); + ks.input_secret(&[0u8; 32]); + + extract_traffic_secret(&ks, SecretKind::ClientHandshakeTrafficSecret); + extract_traffic_secret(&ks, SecretKind::ServerHandshakeTrafficSecret); + + ks.input_empty(); + + extract_traffic_secret(&ks, SecretKind::ClientApplicationTrafficSecret); + extract_traffic_secret(&ks, SecretKind::ServerApplicationTrafficSecret); + }); + } +} diff --git a/vendor/rustls-0.21.8/src/tls13/mod.rs b/vendor/rustls-0.21.8/src/tls13/mod.rs new file mode 100644 index 0000000000000..d1b0e1e8208e5 --- /dev/null +++ b/vendor/rustls-0.21.8/src/tls13/mod.rs @@ -0,0 +1,200 @@ +use crate::cipher::{make_nonce, Iv, MessageDecrypter, MessageEncrypter}; +use crate::enums::ContentType; +use crate::enums::{CipherSuite, ProtocolVersion}; +use crate::error::{Error, PeerMisbehaved}; +use crate::msgs::base::Payload; +use crate::msgs::codec::Codec; +use crate::msgs::fragmenter::MAX_FRAGMENT_LEN; +use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage}; +use crate::suites::{BulkAlgorithm, CipherSuiteCommon, SupportedCipherSuite}; + +use ring::aead; + +use std::fmt; + +pub(crate) mod key_schedule; + +/// The TLS1.3 ciphersuite TLS_CHACHA20_POLY1305_SHA256 +pub static TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = + SupportedCipherSuite::Tls13(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL); + +pub(crate) static TLS13_CHACHA20_POLY1305_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, + bulk: BulkAlgorithm::Chacha20Poly1305, + aead_algorithm: &ring::aead::CHACHA20_POLY1305, + }, + hkdf_algorithm: ring::hkdf::HKDF_SHA256, + #[cfg(feature = "quic")] + confidentiality_limit: u64::MAX, + #[cfg(feature = "quic")] + integrity_limit: 1 << 36, +}; + +/// The TLS1.3 ciphersuite TLS_AES_256_GCM_SHA384 +pub static TLS13_AES_256_GCM_SHA384: SupportedCipherSuite = + SupportedCipherSuite::Tls13(&Tls13CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS13_AES_256_GCM_SHA384, + bulk: BulkAlgorithm::Aes256Gcm, + aead_algorithm: &ring::aead::AES_256_GCM, + }, + hkdf_algorithm: ring::hkdf::HKDF_SHA384, + #[cfg(feature = "quic")] + confidentiality_limit: 1 << 23, + #[cfg(feature = "quic")] + integrity_limit: 1 << 52, + }); + +/// The TLS1.3 ciphersuite TLS_AES_128_GCM_SHA256 +pub static TLS13_AES_128_GCM_SHA256: SupportedCipherSuite = + SupportedCipherSuite::Tls13(TLS13_AES_128_GCM_SHA256_INTERNAL); + +pub(crate) static TLS13_AES_128_GCM_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS13_AES_128_GCM_SHA256, + bulk: BulkAlgorithm::Aes128Gcm, + aead_algorithm: &ring::aead::AES_128_GCM, + }, + hkdf_algorithm: ring::hkdf::HKDF_SHA256, + #[cfg(feature = "quic")] + confidentiality_limit: 1 << 23, + #[cfg(feature = "quic")] + integrity_limit: 1 << 52, +}; + +/// A TLS 1.3 cipher suite supported by rustls. +pub struct Tls13CipherSuite { + /// Common cipher suite fields. + pub common: CipherSuiteCommon, + pub(crate) hkdf_algorithm: ring::hkdf::Algorithm, + #[cfg(feature = "quic")] + pub(crate) confidentiality_limit: u64, + #[cfg(feature = "quic")] + pub(crate) integrity_limit: u64, +} + +impl Tls13CipherSuite { + /// Which hash function to use with this suite. + pub(crate) fn hash_algorithm(&self) -> &'static ring::digest::Algorithm { + self.hkdf_algorithm + .hmac_algorithm() + .digest_algorithm() + } + + /// Can a session using suite self resume from suite prev? + pub fn can_resume_from(&self, prev: &'static Self) -> Option<&'static Self> { + (prev.hash_algorithm() == self.hash_algorithm()).then(|| prev) + } +} + +impl From<&'static Tls13CipherSuite> for SupportedCipherSuite { + fn from(s: &'static Tls13CipherSuite) -> Self { + Self::Tls13(s) + } +} + +impl PartialEq for Tls13CipherSuite { + fn eq(&self, other: &Self) -> bool { + self.common.suite == other.common.suite + } +} + +impl fmt::Debug for Tls13CipherSuite { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Tls13CipherSuite") + .field("suite", &self.common.suite) + .field("bulk", &self.common.bulk) + .finish() + } +} + +struct Tls13MessageEncrypter { + enc_key: aead::LessSafeKey, + iv: Iv, +} + +struct Tls13MessageDecrypter { + dec_key: aead::LessSafeKey, + iv: Iv, +} + +fn unpad_tls13(v: &mut Vec) -> ContentType { + loop { + match v.pop() { + Some(0) => {} + Some(content_type) => return ContentType::from(content_type), + None => return ContentType::Unknown(0), + } + } +} + +fn make_tls13_aad(len: usize) -> ring::aead::Aad<[u8; TLS13_AAD_SIZE]> { + ring::aead::Aad::from([ + 0x17, // ContentType::ApplicationData + 0x3, // ProtocolVersion (major) + 0x3, // ProtocolVersion (minor) + (len >> 8) as u8, + len as u8, + ]) +} + +// https://datatracker.ietf.org/doc/html/rfc8446#section-5.2 +const TLS13_AAD_SIZE: usize = 1 + 2 + 2; + +impl MessageEncrypter for Tls13MessageEncrypter { + fn encrypt(&self, msg: BorrowedPlainMessage, seq: u64) -> Result { + let total_len = msg.payload.len() + 1 + self.enc_key.algorithm().tag_len(); + let mut payload = Vec::with_capacity(total_len); + payload.extend_from_slice(msg.payload); + msg.typ.encode(&mut payload); + + let nonce = make_nonce(&self.iv, seq); + let aad = make_tls13_aad(total_len); + + self.enc_key + .seal_in_place_append_tag(nonce, aad, &mut payload) + .map_err(|_| Error::General("encrypt failed".to_string()))?; + + Ok(OpaqueMessage { + typ: ContentType::ApplicationData, + version: ProtocolVersion::TLSv1_2, + payload: Payload::new(payload), + }) + } +} + +impl MessageDecrypter for Tls13MessageDecrypter { + fn decrypt(&self, mut msg: OpaqueMessage, seq: u64) -> Result { + let payload = &mut msg.payload.0; + if payload.len() < self.dec_key.algorithm().tag_len() { + return Err(Error::DecryptError); + } + + let nonce = make_nonce(&self.iv, seq); + let aad = make_tls13_aad(payload.len()); + let plain_len = self + .dec_key + .open_in_place(nonce, aad, payload) + .map_err(|_| Error::DecryptError)? + .len(); + + payload.truncate(plain_len); + + if payload.len() > MAX_FRAGMENT_LEN + 1 { + return Err(Error::PeerSentOversizedRecord); + } + + msg.typ = unpad_tls13(payload); + if msg.typ == ContentType::Unknown(0) { + return Err(PeerMisbehaved::IllegalTlsInnerPlaintext.into()); + } + + if payload.len() > MAX_FRAGMENT_LEN { + return Err(Error::PeerSentOversizedRecord); + } + + msg.version = ProtocolVersion::TLSv1_3; + Ok(msg.into_plain_message()) + } +} diff --git a/vendor/rustls-0.21.8/src/vecbuf.rs b/vendor/rustls-0.21.8/src/vecbuf.rs new file mode 100644 index 0000000000000..6126edd94496d --- /dev/null +++ b/vendor/rustls-0.21.8/src/vecbuf.rs @@ -0,0 +1,200 @@ +use std::cmp; +use std::collections::VecDeque; +use std::io; +use std::io::Read; + +/// This is a byte buffer that is built from a vector +/// of byte vectors. This avoids extra copies when +/// appending a new byte vector, at the expense of +/// more complexity when reading out. +pub(crate) struct ChunkVecBuffer { + chunks: VecDeque>, + limit: Option, +} + +impl ChunkVecBuffer { + pub(crate) fn new(limit: Option) -> Self { + Self { + chunks: VecDeque::new(), + limit, + } + } + + /// Sets the upper limit on how many bytes this + /// object can store. + /// + /// Setting a lower limit than the currently stored + /// data is not an error. + /// + /// A [`None`] limit is interpreted as no limit. + pub(crate) fn set_limit(&mut self, new_limit: Option) { + self.limit = new_limit; + } + + /// If we're empty + pub(crate) fn is_empty(&self) -> bool { + self.chunks.is_empty() + } + + pub(crate) fn is_full(&self) -> bool { + self.limit + .map(|limit| self.len() > limit) + .unwrap_or_default() + } + + /// How many bytes we're storing + pub(crate) fn len(&self) -> usize { + let mut len = 0; + for ch in &self.chunks { + len += ch.len(); + } + len + } + + /// For a proposed append of `len` bytes, how many + /// bytes should we actually append to adhere to the + /// currently set `limit`? + pub(crate) fn apply_limit(&self, len: usize) -> usize { + if let Some(limit) = self.limit { + let space = limit.saturating_sub(self.len()); + cmp::min(len, space) + } else { + len + } + } + + /// Append a copy of `bytes`, perhaps a prefix if + /// we're near the limit. + pub(crate) fn append_limited_copy(&mut self, bytes: &[u8]) -> usize { + let take = self.apply_limit(bytes.len()); + self.append(bytes[..take].to_vec()); + take + } + + /// Take and append the given `bytes`. + pub(crate) fn append(&mut self, bytes: Vec) -> usize { + let len = bytes.len(); + + if !bytes.is_empty() { + self.chunks.push_back(bytes); + } + + len + } + + /// Take one of the chunks from this object. This + /// function panics if the object `is_empty`. + pub(crate) fn pop(&mut self) -> Option> { + self.chunks.pop_front() + } + + /// Read data out of this object, writing it into `buf` + /// and returning how many bytes were written there. + pub(crate) fn read(&mut self, buf: &mut [u8]) -> io::Result { + let mut offs = 0; + + while offs < buf.len() && !self.is_empty() { + let used = self.chunks[0] + .as_slice() + .read(&mut buf[offs..])?; + + self.consume(used); + offs += used; + } + + Ok(offs) + } + + #[cfg(read_buf)] + /// Read data out of this object, writing it into `cursor`. + pub(crate) fn read_buf(&mut self, mut cursor: io::BorrowedCursor<'_>) -> io::Result<()> { + while !self.is_empty() && cursor.capacity() > 0 { + let chunk = self.chunks[0].as_slice(); + let used = std::cmp::min(chunk.len(), cursor.capacity()); + cursor.append(&chunk[..used]); + self.consume(used); + } + + Ok(()) + } + + fn consume(&mut self, mut used: usize) { + while let Some(mut buf) = self.chunks.pop_front() { + if used < buf.len() { + self.chunks + .push_front(buf.split_off(used)); + break; + } else { + used -= buf.len(); + } + } + } + + /// Read data out of this object, passing it `wr` + pub(crate) fn write_to(&mut self, wr: &mut dyn io::Write) -> io::Result { + if self.is_empty() { + return Ok(0); + } + + let mut bufs = [io::IoSlice::new(&[]); 64]; + for (iov, chunk) in bufs.iter_mut().zip(self.chunks.iter()) { + *iov = io::IoSlice::new(chunk); + } + let len = cmp::min(bufs.len(), self.chunks.len()); + let used = wr.write_vectored(&bufs[..len])?; + self.consume(used); + Ok(used) + } +} + +#[cfg(test)] +mod test { + use super::ChunkVecBuffer; + + #[test] + fn short_append_copy_with_limit() { + let mut cvb = ChunkVecBuffer::new(Some(12)); + assert_eq!(cvb.append_limited_copy(b"hello"), 5); + assert_eq!(cvb.append_limited_copy(b"world"), 5); + assert_eq!(cvb.append_limited_copy(b"hello"), 2); + assert_eq!(cvb.append_limited_copy(b"world"), 0); + + let mut buf = [0u8; 12]; + assert_eq!(cvb.read(&mut buf).unwrap(), 12); + assert_eq!(buf.to_vec(), b"helloworldhe".to_vec()); + } + + #[cfg(read_buf)] + #[test] + fn read_buf() { + use std::{io::BorrowedBuf, mem::MaybeUninit}; + + { + let mut cvb = ChunkVecBuffer::new(None); + cvb.append(b"test ".to_vec()); + cvb.append(b"fixture ".to_vec()); + cvb.append(b"data".to_vec()); + + let mut buf = [MaybeUninit::::uninit(); 8]; + let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); + cvb.read_buf(buf.unfilled()).unwrap(); + assert_eq!(buf.filled(), b"test fix"); + buf.clear(); + cvb.read_buf(buf.unfilled()).unwrap(); + assert_eq!(buf.filled(), b"ture dat"); + buf.clear(); + cvb.read_buf(buf.unfilled()).unwrap(); + assert_eq!(buf.filled(), b"a"); + } + + { + let mut cvb = ChunkVecBuffer::new(None); + cvb.append(b"short message".to_vec()); + + let mut buf = [MaybeUninit::::uninit(); 1024]; + let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); + cvb.read_buf(buf.unfilled()).unwrap(); + assert_eq!(buf.filled(), b"short message"); + } + } +} diff --git a/vendor/rustls-0.21.8/src/verify.rs b/vendor/rustls-0.21.8/src/verify.rs new file mode 100644 index 0000000000000..7c790e2e77eeb --- /dev/null +++ b/vendor/rustls-0.21.8/src/verify.rs @@ -0,0 +1,994 @@ +use std::fmt; + +use crate::anchors::{OwnedTrustAnchor, RootCertStore}; +use crate::client::ServerName; +use crate::enums::SignatureScheme; +use crate::error::{ + CertRevocationListError, CertificateError, Error, InvalidMessage, PeerMisbehaved, +}; +use crate::key::{Certificate, ParsedCertificate}; +#[cfg(feature = "logging")] +use crate::log::{debug, trace, warn}; +use crate::msgs::base::PayloadU16; +use crate::msgs::codec::{Codec, Reader}; +use crate::msgs::handshake::DistinguishedName; + +use ring::digest::Digest; + +use std::sync::Arc; +use std::time::SystemTime; + +type SignatureAlgorithms = &'static [&'static webpki::SignatureAlgorithm]; + +/// Which signature verification mechanisms we support. No particular +/// order. +static SUPPORTED_SIG_ALGS: SignatureAlgorithms = &[ + &webpki::ECDSA_P256_SHA256, + &webpki::ECDSA_P256_SHA384, + &webpki::ECDSA_P384_SHA256, + &webpki::ECDSA_P384_SHA384, + &webpki::ED25519, + &webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY, + &webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY, + &webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY, + &webpki::RSA_PKCS1_2048_8192_SHA256, + &webpki::RSA_PKCS1_2048_8192_SHA384, + &webpki::RSA_PKCS1_2048_8192_SHA512, + &webpki::RSA_PKCS1_3072_8192_SHA384, +]; + +// Marker types. These are used to bind the fact some verification +// (certificate chain or handshake signature) has taken place into +// protocol states. We use this to have the compiler check that there +// are no 'goto fail'-style elisions of important checks before we +// reach the traffic stage. +// +// These types are public, but cannot be directly constructed. This +// means their origins can be precisely determined by looking +// for their `assertion` constructors. + +/// Zero-sized marker type representing verification of a signature. +#[derive(Debug)] +#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] +pub struct HandshakeSignatureValid(()); + +impl HandshakeSignatureValid { + /// Make a `HandshakeSignatureValid` + pub fn assertion() -> Self { + Self(()) + } +} + +#[derive(Debug)] +pub(crate) struct FinishedMessageVerified(()); + +impl FinishedMessageVerified { + pub(crate) fn assertion() -> Self { + Self(()) + } +} + +/// Zero-sized marker type representing verification of a server cert chain. +#[allow(unreachable_pub)] +#[derive(Debug)] +#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] +pub struct ServerCertVerified(()); + +#[allow(unreachable_pub)] +impl ServerCertVerified { + /// Make a `ServerCertVerified` + pub fn assertion() -> Self { + Self(()) + } +} + +/// Zero-sized marker type representing verification of a client cert chain. +#[derive(Debug)] +#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] +pub struct ClientCertVerified(()); + +impl ClientCertVerified { + /// Make a `ClientCertVerified` + pub fn assertion() -> Self { + Self(()) + } +} + +/// Something that can verify a server certificate chain, and verify +/// signatures made by certificates. +#[allow(unreachable_pub)] +#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] +pub trait ServerCertVerifier: Send + Sync { + /// Verify the end-entity certificate `end_entity` is valid for the + /// hostname `dns_name` and chains to at least one trust anchor. + /// + /// `intermediates` contains all certificates other than `end_entity` that + /// were sent as part of the server's [Certificate] message. It is in the + /// same order that the server sent them and may be empty. + /// + /// Note that none of the certificates have been parsed yet, so it is the responsibility of + /// the implementor to handle invalid data. It is recommended that the implementor returns + /// [`Error::InvalidCertificate(CertificateError::BadEncoding)`] when these cases are encountered. + /// + /// `scts` contains the Signed Certificate Timestamps (SCTs) the server + /// sent with the end-entity certificate, if any. + /// + /// [Certificate]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.4.2 + fn verify_server_cert( + &self, + end_entity: &Certificate, + intermediates: &[Certificate], + server_name: &ServerName, + scts: &mut dyn Iterator, + ocsp_response: &[u8], + now: SystemTime, + ) -> Result; + + /// Verify a signature allegedly by the given server certificate. + /// + /// `message` is not hashed, and needs hashing during the verification. + /// The signature and algorithm are within `dss`. `cert` contains the + /// public key to use. + /// + /// `cert` has already been validated by [`ServerCertVerifier::verify_server_cert`]. + /// + /// If and only if the signature is valid, return `Ok(HandshakeSignatureValid)`. + /// Otherwise, return an error -- rustls will send an alert and abort the + /// connection. + /// + /// This method is only called for TLS1.2 handshakes. Note that, in TLS1.2, + /// SignatureSchemes such as `SignatureScheme::ECDSA_NISTP256_SHA256` are not + /// in fact bound to the specific curve implied in their name. + /// + /// This trait method has a default implementation that uses webpki to verify + /// the signature. + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &Certificate, + dss: &DigitallySignedStruct, + ) -> Result { + verify_signed_struct(message, cert, dss) + } + + /// Verify a signature allegedly by the given server certificate. + /// + /// This method is only called for TLS1.3 handshakes. + /// + /// This method is very similar to `verify_tls12_signature`: but note the + /// tighter ECDSA SignatureScheme semantics -- e.g. `SignatureScheme::ECDSA_NISTP256_SHA256` + /// must only validate signatures using public keys on the right curve -- + /// rustls does not enforce this requirement for you. + /// + /// `cert` has already been validated by [`ServerCertVerifier::verify_server_cert`]. + /// + /// If and only if the signature is valid, return `Ok(HandshakeSignatureValid)`. + /// Otherwise, return an error -- rustls will send an alert and abort the + /// connection. + /// + /// This trait method has a default implementation that uses webpki to verify + /// the signature. + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &Certificate, + dss: &DigitallySignedStruct, + ) -> Result { + verify_tls13(message, cert, dss) + } + + /// Return the list of SignatureSchemes that this verifier will handle, + /// in `verify_tls12_signature` and `verify_tls13_signature` calls. + /// + /// This should be in priority order, with the most preferred first. + /// + /// This trait method has a default implementation that reflects the schemes + /// supported by webpki. + fn supported_verify_schemes(&self) -> Vec { + WebPkiVerifier::verification_schemes() + } + + /// Returns `true` if Rustls should ask the server to send SCTs. + /// + /// Signed Certificate Timestamps (SCTs) are used for Certificate + /// Transparency validation. + /// + /// The default implementation of this function returns true. + fn request_scts(&self) -> bool { + true + } +} + +impl fmt::Debug for dyn ServerCertVerifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "dyn ServerCertVerifier") + } +} + +/// Something that can verify a client certificate chain +#[allow(unreachable_pub)] +#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] +pub trait ClientCertVerifier: Send + Sync { + /// Returns `true` to enable the server to request a client certificate and + /// `false` to skip requesting a client certificate. Defaults to `true`. + fn offer_client_auth(&self) -> bool { + true + } + + /// Return `true` to require a client certificate and `false` to make + /// client authentication optional. + /// Defaults to `Some(self.offer_client_auth())`. + fn client_auth_mandatory(&self) -> bool { + self.offer_client_auth() + } + + /// Returns the [Subjects] of the client authentication trust anchors to + /// share with the client when requesting client authentication. + /// + /// These must be DER-encoded X.500 distinguished names, per RFC 5280. + /// They are sent in the [`certificate_authorities`] extension of a + /// [`CertificateRequest`] message. + /// + /// [Subjects]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 + /// [`CertificateRequest`]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.3.2 + /// [`certificate_authorities`]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.4 + /// + /// If the return value is empty, no CertificateRequest message will be sent. + fn client_auth_root_subjects(&self) -> &[DistinguishedName]; + + /// Verify the end-entity certificate `end_entity` is valid, acceptable, + /// and chains to at least one of the trust anchors trusted by + /// this verifier. + /// + /// `intermediates` contains the intermediate certificates the + /// client sent along with the end-entity certificate; it is in the same + /// order that the peer sent them and may be empty. + /// + /// Note that none of the certificates have been parsed yet, so it is the responsibility of + /// the implementor to handle invalid data. It is recommended that the implementor returns + /// an [InvalidCertificate] error with the [BadEncoding] variant when these cases are encountered. + /// + /// [InvalidCertificate]: Error#variant.InvalidCertificate + /// [BadEncoding]: CertificateError#variant.BadEncoding + fn verify_client_cert( + &self, + end_entity: &Certificate, + intermediates: &[Certificate], + now: SystemTime, + ) -> Result; + + /// Verify a signature allegedly by the given client certificate. + /// + /// `message` is not hashed, and needs hashing during the verification. + /// The signature and algorithm are within `dss`. `cert` contains the + /// public key to use. + /// + /// `cert` has already been validated by [`ClientCertVerifier::verify_client_cert`]. + /// + /// If and only if the signature is valid, return `Ok(HandshakeSignatureValid)`. + /// Otherwise, return an error -- rustls will send an alert and abort the + /// connection. + /// + /// This method is only called for TLS1.2 handshakes. Note that, in TLS1.2, + /// SignatureSchemes such as `SignatureScheme::ECDSA_NISTP256_SHA256` are not + /// in fact bound to the specific curve implied in their name. + /// + /// This trait method has a default implementation that uses webpki to verify + /// the signature. + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &Certificate, + dss: &DigitallySignedStruct, + ) -> Result { + verify_signed_struct(message, cert, dss) + } + + /// Verify a signature allegedly by the given client certificate. + /// + /// This method is only called for TLS1.3 handshakes. + /// + /// This method is very similar to `verify_tls12_signature`, but note the + /// tighter ECDSA SignatureScheme semantics in TLS 1.3. For example, + /// `SignatureScheme::ECDSA_NISTP256_SHA256` + /// must only validate signatures using public keys on the right curve -- + /// rustls does not enforce this requirement for you. + /// + /// This trait method has a default implementation that uses webpki to verify + /// the signature. + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &Certificate, + dss: &DigitallySignedStruct, + ) -> Result { + verify_tls13(message, cert, dss) + } + + /// Return the list of SignatureSchemes that this verifier will handle, + /// in `verify_tls12_signature` and `verify_tls13_signature` calls. + /// + /// This should be in priority order, with the most preferred first. + /// + /// This trait method has a default implementation that reflects the schemes + /// supported by webpki. + fn supported_verify_schemes(&self) -> Vec { + WebPkiVerifier::verification_schemes() + } +} + +impl fmt::Debug for dyn ClientCertVerifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "dyn ClientCertVerifier") + } +} + +/// Verify that the end-entity certificate `end_entity` is a valid server cert +/// and chains to at least one of the [OwnedTrustAnchor] in the `roots` [RootCertStore]. +/// +/// `intermediates` contains all certificates other than `end_entity` that +/// were sent as part of the server's [Certificate] message. It is in the +/// same order that the server sent them and may be empty. +#[allow(dead_code)] +#[cfg_attr(not(feature = "dangerous_configuration"), allow(unreachable_pub))] +#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] +pub fn verify_server_cert_signed_by_trust_anchor( + cert: &ParsedCertificate, + roots: &RootCertStore, + intermediates: &[Certificate], + now: SystemTime, +) -> Result<(), Error> { + let chain = intermediate_chain(intermediates); + let trust_roots = trust_roots(roots); + let webpki_now = webpki::Time::try_from(now).map_err(|_| Error::FailedToGetCurrentTime)?; + + cert.0 + .verify_for_usage( + SUPPORTED_SIG_ALGS, + &trust_roots, + &chain, + webpki_now, + webpki::KeyUsage::server_auth(), + &[], // no CRLs + ) + .map_err(pki_error) + .map(|_| ()) +} + +/// Verify that the `end_entity` has a name or alternative name matching the `server_name` +/// note: this only verifies the name and should be used in conjuction with more verification +/// like [verify_server_cert_signed_by_trust_anchor] +#[cfg_attr(not(feature = "dangerous_configuration"), allow(unreachable_pub))] +#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] +pub fn verify_server_name(cert: &ParsedCertificate, server_name: &ServerName) -> Result<(), Error> { + match server_name { + ServerName::DnsName(dns_name) => { + // unlikely error because dns_name::DnsNameRef and webpki::DnsNameRef + // should have the same encoding rules. + let dns_name = webpki::DnsNameRef::try_from_ascii_str(dns_name.as_ref()) + .map_err(|_| Error::InvalidCertificate(CertificateError::BadEncoding))?; + let name = webpki::SubjectNameRef::DnsName(dns_name); + cert.0 + .verify_is_valid_for_subject_name(name) + .map_err(pki_error)?; + } + ServerName::IpAddress(ip_addr) => { + let ip_addr = webpki::IpAddr::from(*ip_addr); + cert.0 + .verify_is_valid_for_subject_name(webpki::SubjectNameRef::IpAddress( + webpki::IpAddrRef::from(&ip_addr), + )) + .map_err(pki_error)?; + } + } + Ok(()) +} + +impl ServerCertVerifier for WebPkiVerifier { + /// Will verify the certificate is valid in the following ways: + /// - Signed by a trusted `RootCertStore` CA + /// - Not Expired + /// - Valid for DNS entry + fn verify_server_cert( + &self, + end_entity: &Certificate, + intermediates: &[Certificate], + server_name: &ServerName, + scts: &mut dyn Iterator, + ocsp_response: &[u8], + now: SystemTime, + ) -> Result { + let cert = ParsedCertificate::try_from(end_entity)?; + + verify_server_cert_signed_by_trust_anchor(&cert, &self.roots, intermediates, now)?; + + if let Some(policy) = &self.ct_policy { + policy.verify(end_entity, now, scts)?; + } + + if !ocsp_response.is_empty() { + trace!("Unvalidated OCSP response: {:?}", ocsp_response.to_vec()); + } + + verify_server_name(&cert, server_name)?; + Ok(ServerCertVerified::assertion()) + } +} + +/// Default `ServerCertVerifier`, see the trait impl for more information. +#[allow(unreachable_pub)] +#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] +pub struct WebPkiVerifier { + roots: Arc, + ct_policy: Option, +} + +#[allow(unreachable_pub)] +impl WebPkiVerifier { + /// Constructs a new `WebPkiVerifier`. + /// + /// `roots` is the set of trust anchors to trust for issuing server certs. + /// + /// `ct_logs` is the list of logs that are trusted for Certificate + /// Transparency. Currently CT log enforcement is opportunistic; see + /// . + pub fn new( + roots: impl Into>, + ct_policy: Option, + ) -> Self { + Self { + roots: roots.into(), + ct_policy, + } + } + + /// Returns the signature verification methods supported by + /// webpki. + pub fn verification_schemes() -> Vec { + vec![ + SignatureScheme::ECDSA_NISTP384_SHA384, + SignatureScheme::ECDSA_NISTP256_SHA256, + SignatureScheme::ED25519, + SignatureScheme::RSA_PSS_SHA512, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA256, + SignatureScheme::RSA_PKCS1_SHA512, + SignatureScheme::RSA_PKCS1_SHA384, + SignatureScheme::RSA_PKCS1_SHA256, + ] + } +} + +/// Policy for enforcing Certificate Transparency. +/// +/// Because Certificate Transparency logs are sharded on a per-year basis and can be trusted or +/// distrusted relatively quickly, rustls stores a validation deadline. Server certificates will +/// be validated against the configured CT logs until the deadline expires. After the deadline, +/// certificates will no longer be validated, and a warning message will be logged. The deadline +/// may vary depending on how often you deploy builds with updated dependencies. +#[allow(unreachable_pub)] +#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] +pub struct CertificateTransparencyPolicy { + logs: &'static [&'static sct::Log<'static>], + validation_deadline: SystemTime, +} + +impl CertificateTransparencyPolicy { + /// Create a new policy. + #[allow(unreachable_pub)] + pub fn new( + logs: &'static [&'static sct::Log<'static>], + validation_deadline: SystemTime, + ) -> Self { + Self { + logs, + validation_deadline, + } + } + + fn verify( + &self, + cert: &Certificate, + now: SystemTime, + scts: &mut dyn Iterator, + ) -> Result<(), Error> { + if self.logs.is_empty() { + return Ok(()); + } else if self + .validation_deadline + .duration_since(now) + .is_err() + { + warn!("certificate transparency logs have expired, validation disabled"); + return Ok(()); + } + + let now = unix_time_millis(now)?; + let mut last_sct_error = None; + for sct in scts { + #[cfg_attr(not(feature = "logging"), allow(unused_variables))] + match sct::verify_sct(&cert.0, sct, now, self.logs) { + Ok(index) => { + debug!( + "Valid SCT signed by {} on {}", + self.logs[index].operated_by, self.logs[index].description + ); + return Ok(()); + } + Err(e) => { + if e.should_be_fatal() { + return Err(Error::InvalidSct(e)); + } + debug!("SCT ignored because {:?}", e); + last_sct_error = Some(e); + } + } + } + + /* If we were supplied with some logs, and some SCTs, + * but couldn't verify any of them, fail the handshake. */ + if let Some(last_sct_error) = last_sct_error { + warn!("No valid SCTs provided"); + return Err(Error::InvalidSct(last_sct_error)); + } + + Ok(()) + } +} + +fn intermediate_chain(intermediates: &[Certificate]) -> Vec<&[u8]> { + intermediates + .iter() + .map(|cert| cert.0.as_ref()) + .collect() +} + +fn trust_roots(roots: &RootCertStore) -> Vec { + roots + .roots + .iter() + .map(OwnedTrustAnchor::to_trust_anchor) + .collect() +} + +/// An unparsed DER encoded Certificate Revocation List (CRL). +pub struct UnparsedCertRevocationList(pub Vec); + +impl UnparsedCertRevocationList { + /// Parse the CRL DER, yielding a [`webpki::CertRevocationList`] or an error if the CRL + /// is malformed, or uses unsupported features. + pub fn parse(&self) -> Result { + webpki::BorrowedCertRevocationList::from_der(&self.0) + .and_then(|crl| crl.to_owned()) + .map_err(CertRevocationListError::from) + } +} + +/// A `ClientCertVerifier` that will ensure that every client provides a trusted +/// certificate, without any name checking. Optionally, client certificates will +/// have their revocation status checked using the DER encoded CRLs provided. +pub struct AllowAnyAuthenticatedClient { + roots: RootCertStore, + subjects: Vec, + crls: Vec, +} + +impl AllowAnyAuthenticatedClient { + /// Construct a new `AllowAnyAuthenticatedClient`. + /// + /// `roots` is the list of trust anchors to use for certificate validation. + pub fn new(roots: RootCertStore) -> Self { + Self { + subjects: roots + .roots + .iter() + .map(|r| r.subject().clone()) + .collect(), + crls: Vec::new(), + roots, + } + } + + /// Update the verifier to validate client certificates against the provided DER format + /// unparsed certificate revocation lists (CRLs). + pub fn with_crls( + self, + crls: impl IntoIterator, + ) -> Result { + Ok(Self { + crls: crls + .into_iter() + .map(|der_crl| der_crl.parse()) + .collect::, CertRevocationListError>>()?, + ..self + }) + } + + /// Wrap this verifier in an [`Arc`] and coerce it to `dyn ClientCertVerifier` + #[inline(always)] + pub fn boxed(self) -> Arc { + // This function is needed because `ClientCertVerifier` is only reachable if the + // `dangerous_configuration` feature is enabled, which makes coercing hard to outside users + Arc::new(self) + } +} + +impl ClientCertVerifier for AllowAnyAuthenticatedClient { + fn offer_client_auth(&self) -> bool { + true + } + + fn client_auth_root_subjects(&self) -> &[DistinguishedName] { + &self.subjects + } + + fn verify_client_cert( + &self, + end_entity: &Certificate, + intermediates: &[Certificate], + now: SystemTime, + ) -> Result { + let cert = ParsedCertificate::try_from(end_entity)?; + let chain = intermediate_chain(intermediates); + let trust_roots = trust_roots(&self.roots); + let now = webpki::Time::try_from(now).map_err(|_| Error::FailedToGetCurrentTime)?; + + #[allow(trivial_casts)] // Cast to &dyn trait is required. + let crls = self + .crls + .iter() + .map(|crl| crl as &dyn webpki::CertRevocationList) + .collect::>(); + + cert.0 + .verify_for_usage( + SUPPORTED_SIG_ALGS, + &trust_roots, + &chain, + now, + webpki::KeyUsage::client_auth(), + crls.as_slice(), + ) + .map_err(pki_error) + .map(|_| ClientCertVerified::assertion()) + } +} + +/// A `ClientCertVerifier` that will allow both anonymous and authenticated +/// clients, without any name checking. +/// +/// Client authentication will be requested during the TLS handshake. If the +/// client offers a certificate then this acts like +/// `AllowAnyAuthenticatedClient`, otherwise this acts like `NoClientAuth`. +pub struct AllowAnyAnonymousOrAuthenticatedClient { + inner: AllowAnyAuthenticatedClient, +} + +impl AllowAnyAnonymousOrAuthenticatedClient { + /// Construct a new `AllowAnyAnonymousOrAuthenticatedClient`. + /// + /// `roots` is the list of trust anchors to use for certificate validation. + pub fn new(roots: RootCertStore) -> Self { + Self { + inner: AllowAnyAuthenticatedClient::new(roots), + } + } + + /// Update the verifier to validate client certificates against the provided DER format + /// unparsed certificate revocation lists (CRLs). + pub fn with_crls( + self, + crls: impl IntoIterator, + ) -> Result { + Ok(Self { + inner: self.inner.with_crls(crls)?, + }) + } + + /// Wrap this verifier in an [`Arc`] and coerce it to `dyn ClientCertVerifier` + #[inline(always)] + pub fn boxed(self) -> Arc { + // This function is needed because `ClientCertVerifier` is only reachable if the + // `dangerous_configuration` feature is enabled, which makes coercing hard to outside users + Arc::new(self) + } +} + +impl ClientCertVerifier for AllowAnyAnonymousOrAuthenticatedClient { + fn offer_client_auth(&self) -> bool { + self.inner.offer_client_auth() + } + + fn client_auth_mandatory(&self) -> bool { + false + } + + fn client_auth_root_subjects(&self) -> &[DistinguishedName] { + self.inner.client_auth_root_subjects() + } + + fn verify_client_cert( + &self, + end_entity: &Certificate, + intermediates: &[Certificate], + now: SystemTime, + ) -> Result { + self.inner + .verify_client_cert(end_entity, intermediates, now) + } +} + +pub(crate) fn pki_error(error: webpki::Error) -> Error { + use webpki::Error::*; + match error { + BadDer | BadDerTime => CertificateError::BadEncoding.into(), + CertNotValidYet => CertificateError::NotValidYet.into(), + CertExpired | InvalidCertValidity => CertificateError::Expired.into(), + UnknownIssuer => CertificateError::UnknownIssuer.into(), + CertNotValidForName => CertificateError::NotValidForName.into(), + CertRevoked => CertificateError::Revoked.into(), + IssuerNotCrlSigner => CertRevocationListError::IssuerInvalidForCrl.into(), + + InvalidSignatureForPublicKey + | UnsupportedSignatureAlgorithm + | UnsupportedSignatureAlgorithmForPublicKey => CertificateError::BadSignature.into(), + + InvalidCrlSignatureForPublicKey + | UnsupportedCrlSignatureAlgorithm + | UnsupportedCrlSignatureAlgorithmForPublicKey => { + CertRevocationListError::BadSignature.into() + } + + _ => CertificateError::Other(Arc::new(error)).into(), + } +} + +/// Turns off client authentication. +pub struct NoClientAuth; + +impl NoClientAuth { + /// Construct a [`NoClientAuth`], wrap it in an [`Arc`] and coerce it to + /// `dyn ClientCertVerifier`. + #[inline(always)] + pub fn boxed() -> Arc { + // This function is needed because `ClientCertVerifier` is only reachable if the + // `dangerous_configuration` feature is enabled, which makes coercing hard to outside users + Arc::new(Self) + } +} + +impl ClientCertVerifier for NoClientAuth { + fn offer_client_auth(&self) -> bool { + false + } + + fn client_auth_root_subjects(&self) -> &[DistinguishedName] { + unimplemented!(); + } + + fn verify_client_cert( + &self, + _end_entity: &Certificate, + _intermediates: &[Certificate], + _now: SystemTime, + ) -> Result { + unimplemented!(); + } +} + +/// This type combines a [`SignatureScheme`] and a signature payload produced with that scheme. +#[derive(Debug, Clone)] +pub struct DigitallySignedStruct { + /// The [`SignatureScheme`] used to produce the signature. + pub scheme: SignatureScheme, + sig: PayloadU16, +} + +impl DigitallySignedStruct { + pub(crate) fn new(scheme: SignatureScheme, sig: Vec) -> Self { + Self { + scheme, + sig: PayloadU16::new(sig), + } + } + + /// Get the signature. + pub fn signature(&self) -> &[u8] { + &self.sig.0 + } +} + +impl Codec for DigitallySignedStruct { + fn encode(&self, bytes: &mut Vec) { + self.scheme.encode(bytes); + self.sig.encode(bytes); + } + + fn read(r: &mut Reader) -> Result { + let scheme = SignatureScheme::read(r)?; + let sig = PayloadU16::read(r)?; + + Ok(Self { scheme, sig }) + } +} + +static ECDSA_SHA256: SignatureAlgorithms = + &[&webpki::ECDSA_P256_SHA256, &webpki::ECDSA_P384_SHA256]; + +static ECDSA_SHA384: SignatureAlgorithms = + &[&webpki::ECDSA_P256_SHA384, &webpki::ECDSA_P384_SHA384]; + +static ED25519: SignatureAlgorithms = &[&webpki::ED25519]; + +static RSA_SHA256: SignatureAlgorithms = &[&webpki::RSA_PKCS1_2048_8192_SHA256]; +static RSA_SHA384: SignatureAlgorithms = &[&webpki::RSA_PKCS1_2048_8192_SHA384]; +static RSA_SHA512: SignatureAlgorithms = &[&webpki::RSA_PKCS1_2048_8192_SHA512]; +static RSA_PSS_SHA256: SignatureAlgorithms = &[&webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY]; +static RSA_PSS_SHA384: SignatureAlgorithms = &[&webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY]; +static RSA_PSS_SHA512: SignatureAlgorithms = &[&webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY]; + +fn convert_scheme(scheme: SignatureScheme) -> Result { + match scheme { + // nb. for TLS1.2 the curve is not fixed by SignatureScheme. + SignatureScheme::ECDSA_NISTP256_SHA256 => Ok(ECDSA_SHA256), + SignatureScheme::ECDSA_NISTP384_SHA384 => Ok(ECDSA_SHA384), + + SignatureScheme::ED25519 => Ok(ED25519), + + SignatureScheme::RSA_PKCS1_SHA256 => Ok(RSA_SHA256), + SignatureScheme::RSA_PKCS1_SHA384 => Ok(RSA_SHA384), + SignatureScheme::RSA_PKCS1_SHA512 => Ok(RSA_SHA512), + + SignatureScheme::RSA_PSS_SHA256 => Ok(RSA_PSS_SHA256), + SignatureScheme::RSA_PSS_SHA384 => Ok(RSA_PSS_SHA384), + SignatureScheme::RSA_PSS_SHA512 => Ok(RSA_PSS_SHA512), + + _ => Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into()), + } +} + +fn verify_sig_using_any_alg( + cert: &webpki::EndEntityCert, + algs: SignatureAlgorithms, + message: &[u8], + sig: &[u8], +) -> Result<(), webpki::Error> { + // TLS doesn't itself give us enough info to map to a single webpki::SignatureAlgorithm. + // Therefore, convert_algs maps to several and we try them all. + for alg in algs { + match cert.verify_signature(alg, message, sig) { + Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKey) => continue, + res => return res, + } + } + + Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKey) +} + +fn verify_signed_struct( + message: &[u8], + cert: &Certificate, + dss: &DigitallySignedStruct, +) -> Result { + let possible_algs = convert_scheme(dss.scheme)?; + let cert = webpki::EndEntityCert::try_from(cert.0.as_ref()).map_err(pki_error)?; + + verify_sig_using_any_alg(&cert, possible_algs, message, dss.signature()) + .map_err(pki_error) + .map(|_| HandshakeSignatureValid::assertion()) +} + +fn convert_alg_tls13( + scheme: SignatureScheme, +) -> Result<&'static webpki::SignatureAlgorithm, Error> { + use crate::enums::SignatureScheme::*; + + match scheme { + ECDSA_NISTP256_SHA256 => Ok(&webpki::ECDSA_P256_SHA256), + ECDSA_NISTP384_SHA384 => Ok(&webpki::ECDSA_P384_SHA384), + ED25519 => Ok(&webpki::ED25519), + RSA_PSS_SHA256 => Ok(&webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY), + RSA_PSS_SHA384 => Ok(&webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY), + RSA_PSS_SHA512 => Ok(&webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY), + _ => Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into()), + } +} + +/// Constructs the signature message specified in section 4.4.3 of RFC8446. +pub(crate) fn construct_tls13_client_verify_message(handshake_hash: &Digest) -> Vec { + construct_tls13_verify_message(handshake_hash, b"TLS 1.3, client CertificateVerify\x00") +} + +/// Constructs the signature message specified in section 4.4.3 of RFC8446. +pub(crate) fn construct_tls13_server_verify_message(handshake_hash: &Digest) -> Vec { + construct_tls13_verify_message(handshake_hash, b"TLS 1.3, server CertificateVerify\x00") +} + +fn construct_tls13_verify_message( + handshake_hash: &Digest, + context_string_with_0: &[u8], +) -> Vec { + let mut msg = Vec::new(); + msg.resize(64, 0x20u8); + msg.extend_from_slice(context_string_with_0); + msg.extend_from_slice(handshake_hash.as_ref()); + msg +} + +fn verify_tls13( + msg: &[u8], + cert: &Certificate, + dss: &DigitallySignedStruct, +) -> Result { + let alg = convert_alg_tls13(dss.scheme)?; + + let cert = webpki::EndEntityCert::try_from(cert.0.as_ref()).map_err(pki_error)?; + + cert.verify_signature(alg, msg, dss.signature()) + .map_err(pki_error) + .map(|_| HandshakeSignatureValid::assertion()) +} + +fn unix_time_millis(now: SystemTime) -> Result { + now.duration_since(std::time::UNIX_EPOCH) + .map(|dur| dur.as_secs()) + .map_err(|_| Error::FailedToGetCurrentTime) + .and_then(|secs| { + secs.checked_mul(1000) + .ok_or(Error::FailedToGetCurrentTime) + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn assertions_are_debug() { + assert_eq!( + format!("{:?}", ClientCertVerified::assertion()), + "ClientCertVerified(())" + ); + assert_eq!( + format!("{:?}", HandshakeSignatureValid::assertion()), + "HandshakeSignatureValid(())" + ); + assert_eq!( + format!("{:?}", FinishedMessageVerified::assertion()), + "FinishedMessageVerified(())" + ); + assert_eq!( + format!("{:?}", ServerCertVerified::assertion()), + "ServerCertVerified(())" + ); + } + + #[test] + fn pki_crl_errors() { + // CRL signature errors should be turned into BadSignature. + assert_eq!( + pki_error(webpki::Error::InvalidCrlSignatureForPublicKey), + Error::InvalidCertRevocationList(CertRevocationListError::BadSignature), + ); + assert_eq!( + pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithm), + Error::InvalidCertRevocationList(CertRevocationListError::BadSignature), + ); + assert_eq!( + pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey), + Error::InvalidCertRevocationList(CertRevocationListError::BadSignature), + ); + + // Revoked cert errors should be turned into Revoked. + assert_eq!( + pki_error(webpki::Error::CertRevoked), + Error::InvalidCertificate(CertificateError::Revoked), + ); + + // Issuer not CRL signer errors should be turned into IssuerInvalidForCrl + assert_eq!( + pki_error(webpki::Error::IssuerNotCrlSigner), + Error::InvalidCertRevocationList(CertRevocationListError::IssuerInvalidForCrl) + ); + } +} diff --git a/vendor/rustls-0.21.8/src/verifybench.rs b/vendor/rustls-0.21.8/src/verifybench.rs new file mode 100644 index 0000000000000..793a84fb2b922 --- /dev/null +++ b/vendor/rustls-0.21.8/src/verifybench.rs @@ -0,0 +1,243 @@ +// This program does benchmarking of the functions in verify.rs, +// that do certificate chain validation and signature verification. +// +// Note: we don't use any of the standard 'cargo bench', 'test::Bencher', +// etc. because it's unstable at the time of writing. + +use std::time::{Duration, Instant, SystemTime}; + +use crate::key; +use crate::verify; +use crate::verify::ServerCertVerifier; +use crate::{anchors, OwnedTrustAnchor}; + +use webpki_roots; + +fn duration_nanos(d: Duration) -> u64 { + ((d.as_secs() as f64) * 1e9 + (d.subsec_nanos() as f64)) as u64 +} + +#[test] +fn test_reddit_cert() { + Context::new( + "reddit", + "reddit.com", + &[ + include_bytes!("testdata/cert-reddit.0.der"), + include_bytes!("testdata/cert-reddit.1.der"), + ], + ) + .bench(100) +} + +#[test] +fn test_github_cert() { + Context::new( + "github", + "github.com", + &[ + include_bytes!("testdata/cert-github.0.der"), + include_bytes!("testdata/cert-github.1.der"), + ], + ) + .bench(100) +} + +#[test] +fn test_arstechnica_cert() { + Context::new( + "arstechnica", + "arstechnica.com", + &[ + include_bytes!("testdata/cert-arstechnica.0.der"), + include_bytes!("testdata/cert-arstechnica.1.der"), + include_bytes!("testdata/cert-arstechnica.2.der"), + include_bytes!("testdata/cert-arstechnica.3.der"), + ], + ) + .bench(100) +} + +#[test] +fn test_servo_cert() { + Context::new( + "servo", + "servo.org", + &[ + include_bytes!("testdata/cert-servo.0.der"), + include_bytes!("testdata/cert-servo.1.der"), + ], + ) + .bench(100) +} + +#[test] +fn test_twitter_cert() { + Context::new( + "twitter", + "twitter.com", + &[ + include_bytes!("testdata/cert-twitter.0.der"), + include_bytes!("testdata/cert-twitter.1.der"), + ], + ) + .bench(100) +} + +#[test] +fn test_wikipedia_cert() { + Context::new( + "wikipedia", + "wikipedia.org", + &[ + include_bytes!("testdata/cert-wikipedia.0.der"), + include_bytes!("testdata/cert-wikipedia.1.der"), + ], + ) + .bench(100) +} + +#[test] +fn test_google_cert() { + Context::new( + "google", + "www.google.com", + &[ + include_bytes!("testdata/cert-google.0.der"), + include_bytes!("testdata/cert-google.1.der"), + ], + ) + .bench(100) +} + +#[test] +fn test_hn_cert() { + Context::new( + "hn", + "news.ycombinator.com", + &[ + include_bytes!("testdata/cert-hn.0.der"), + include_bytes!("testdata/cert-hn.1.der"), + ], + ) + .bench(100) +} + +#[test] +fn test_stackoverflow_cert() { + Context::new( + "stackoverflow", + "stackoverflow.com", + &[ + include_bytes!("testdata/cert-stackoverflow.0.der"), + include_bytes!("testdata/cert-stackoverflow.1.der"), + ], + ) + .bench(100) +} + +#[test] +fn test_duckduckgo_cert() { + Context::new( + "duckduckgo", + "duckduckgo.com", + &[ + include_bytes!("testdata/cert-duckduckgo.0.der"), + include_bytes!("testdata/cert-duckduckgo.1.der"), + ], + ) + .bench(100) +} + +#[test] +fn test_rustlang_cert() { + Context::new( + "rustlang", + "www.rust-lang.org", + &[ + include_bytes!("testdata/cert-rustlang.0.der"), + include_bytes!("testdata/cert-rustlang.1.der"), + include_bytes!("testdata/cert-rustlang.2.der"), + ], + ) + .bench(100) +} + +#[test] +fn test_wapo_cert() { + Context::new( + "wapo", + "www.washingtonpost.com", + &[ + include_bytes!("testdata/cert-wapo.0.der"), + include_bytes!("testdata/cert-wapo.1.der"), + ], + ) + .bench(100) +} + +struct Context { + name: &'static str, + domain: &'static str, + roots: anchors::RootCertStore, + chain: Vec, + now: SystemTime, +} + +impl Context { + fn new(name: &'static str, domain: &'static str, certs: &[&'static [u8]]) -> Self { + let mut roots = anchors::RootCertStore::empty(); + roots.add_trust_anchors( + webpki_roots::TLS_SERVER_ROOTS + .iter() + .map(|ta| { + OwnedTrustAnchor::from_subject_spki_name_constraints( + ta.subject, + ta.spki, + ta.name_constraints, + ) + }), + ); + Self { + name, + domain, + roots, + chain: certs + .iter() + .copied() + .map(|bytes| key::Certificate(bytes.to_vec())) + .collect(), + now: SystemTime::UNIX_EPOCH + Duration::from_secs(1640870720), + } + } + + fn bench(&self, count: usize) { + let verifier = verify::WebPkiVerifier::new(self.roots.clone(), None); + const SCTS: &[&[u8]] = &[]; + const OCSP_RESPONSE: &[u8] = &[]; + let mut times = Vec::new(); + + let (end_entity, intermediates) = self.chain.split_first().unwrap(); + for _ in 0..count { + let start = Instant::now(); + let server_name = self.domain.try_into().unwrap(); + verifier + .verify_server_cert( + end_entity, + intermediates, + &server_name, + &mut SCTS.iter().copied(), + OCSP_RESPONSE, + self.now, + ) + .unwrap(); + times.push(duration_nanos(Instant::now().duration_since(start))); + } + + println!( + "verify_server_cert({}): min {:?}us", + self.name, + times.iter().min().unwrap() / 1000 + ); + } +} diff --git a/vendor/rustls-0.21.8/src/versions.rs b/vendor/rustls-0.21.8/src/versions.rs new file mode 100644 index 0000000000000..68f6e2a7528bc --- /dev/null +++ b/vendor/rustls-0.21.8/src/versions.rs @@ -0,0 +1,99 @@ +use std::fmt; + +use crate::enums::ProtocolVersion; + +/// A TLS protocol version supported by rustls. +/// +/// All possible instances of this class are provided by the library in +/// the [`ALL_VERSIONS`] array, as well as individually as [`TLS12`] +/// and [`TLS13`]. +#[derive(Eq, PartialEq)] +pub struct SupportedProtocolVersion { + /// The TLS enumeration naming this version. + pub version: ProtocolVersion, + is_private: (), +} + +impl fmt::Debug for SupportedProtocolVersion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.version.fmt(f) + } +} + +/// TLS1.2 +#[cfg(feature = "tls12")] +pub static TLS12: SupportedProtocolVersion = SupportedProtocolVersion { + version: ProtocolVersion::TLSv1_2, + is_private: (), +}; + +/// TLS1.3 +pub static TLS13: SupportedProtocolVersion = SupportedProtocolVersion { + version: ProtocolVersion::TLSv1_3, + is_private: (), +}; + +/// A list of all the protocol versions supported by rustls. +pub static ALL_VERSIONS: &[&SupportedProtocolVersion] = &[ + &TLS13, + #[cfg(feature = "tls12")] + &TLS12, +]; + +/// The version configuration that an application should use by default. +/// +/// This will be [`ALL_VERSIONS`] for now, but gives space in the future +/// to remove a version from here and require users to opt-in to older +/// versions. +pub static DEFAULT_VERSIONS: &[&SupportedProtocolVersion] = ALL_VERSIONS; + +#[derive(Clone)] +pub(crate) struct EnabledVersions { + #[cfg(feature = "tls12")] + tls12: Option<&'static SupportedProtocolVersion>, + tls13: Option<&'static SupportedProtocolVersion>, +} + +impl fmt::Debug for EnabledVersions { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut list = &mut f.debug_list(); + #[cfg(feature = "tls12")] + if let Some(v) = self.tls12 { + list = list.entry(v); + } + if let Some(v) = self.tls13 { + list = list.entry(v); + } + list.finish() + } +} + +impl EnabledVersions { + pub(crate) fn new(versions: &[&'static SupportedProtocolVersion]) -> Self { + let mut ev = Self { + #[cfg(feature = "tls12")] + tls12: None, + tls13: None, + }; + + for v in versions { + match v.version { + #[cfg(feature = "tls12")] + ProtocolVersion::TLSv1_2 => ev.tls12 = Some(v), + ProtocolVersion::TLSv1_3 => ev.tls13 = Some(v), + _ => {} + } + } + + ev + } + + pub(crate) fn contains(&self, version: ProtocolVersion) -> bool { + match version { + #[cfg(feature = "tls12")] + ProtocolVersion::TLSv1_2 => self.tls12.is_some(), + ProtocolVersion::TLSv1_3 => self.tls13.is_some(), + _ => false, + } + } +} diff --git a/vendor/rustls-0.21.8/src/x509.rs b/vendor/rustls-0.21.8/src/x509.rs new file mode 100644 index 0000000000000..17239d74adce7 --- /dev/null +++ b/vendor/rustls-0.21.8/src/x509.rs @@ -0,0 +1,93 @@ +// Additional x509/asn1 functions to those provided in webpki/ring. + +use ring::io::der; + +pub(crate) fn wrap_in_asn1_len(bytes: &mut Vec) { + let len = bytes.len(); + + if len <= 0x7f { + bytes.insert(0, len as u8); + } else { + bytes.insert(0, 0x80u8); + let mut left = len; + while left > 0 { + let byte = (left & 0xff) as u8; + bytes.insert(1, byte); + bytes[0] += 1; + left >>= 8; + } + } +} + +/// Prepend stuff to `bytes` to put it in a DER SEQUENCE. +pub(crate) fn wrap_in_sequence(bytes: &mut Vec) { + wrap_in_asn1_len(bytes); + bytes.insert(0, der::Tag::Sequence as u8); +} + +#[test] +fn test_empty() { + let mut val = Vec::new(); + wrap_in_sequence(&mut val); + assert_eq!(vec![0x30, 0x00], val); +} + +#[test] +fn test_small() { + let mut val = Vec::new(); + val.insert(0, 0x00); + val.insert(1, 0x11); + val.insert(2, 0x22); + val.insert(3, 0x33); + wrap_in_sequence(&mut val); + assert_eq!(vec![0x30, 0x04, 0x00, 0x11, 0x22, 0x33], val); +} + +#[test] +fn test_medium() { + let mut val = Vec::new(); + val.resize(255, 0x12); + wrap_in_sequence(&mut val); + assert_eq!(vec![0x30, 0x81, 0xff, 0x12, 0x12, 0x12], val[..6].to_vec()); +} + +#[test] +fn test_large() { + let mut val = Vec::new(); + val.resize(4660, 0x12); + wrap_in_sequence(&mut val); + assert_eq!(vec![0x30, 0x82, 0x12, 0x34, 0x12, 0x12], val[..6].to_vec()); +} + +#[test] +fn test_huge() { + let mut val = Vec::new(); + val.resize(0xffff, 0x12); + wrap_in_sequence(&mut val); + assert_eq!(vec![0x30, 0x82, 0xff, 0xff, 0x12, 0x12], val[..6].to_vec()); + assert_eq!(val.len(), 0xffff + 4); +} + +#[test] +fn test_gigantic() { + let mut val = Vec::new(); + val.resize(0x100000, 0x12); + wrap_in_sequence(&mut val); + assert_eq!( + vec![0x30, 0x83, 0x10, 0x00, 0x00, 0x12, 0x12], + val[..7].to_vec() + ); + assert_eq!(val.len(), 0x100000 + 5); +} + +#[test] +fn test_ludicrous() { + let mut val = Vec::new(); + val.resize(0x1000000, 0x12); + wrap_in_sequence(&mut val); + assert_eq!( + vec![0x30, 0x84, 0x01, 0x00, 0x00, 0x00, 0x12, 0x12], + val[..8].to_vec() + ); + assert_eq!(val.len(), 0x1000000 + 6); +} diff --git a/vendor/rustls-0.21.8/tests/api.rs b/vendor/rustls-0.21.8/tests/api.rs new file mode 100644 index 0000000000000..5a884854cd5e6 --- /dev/null +++ b/vendor/rustls-0.21.8/tests/api.rs @@ -0,0 +1,4886 @@ +#![cfg_attr(read_buf, feature(read_buf))] +//! Assorted public API tests. +use std::cell::RefCell; +use std::fmt; +use std::io::{self, IoSlice, Read, Write}; +use std::mem; +use std::ops::{Deref, DerefMut}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use std::sync::Mutex; + +use rustls::client::{ResolvesClientCert, Resumption}; +use rustls::internal::msgs::base::Payload; +use rustls::internal::msgs::codec::Codec; +use rustls::server::{AllowAnyAnonymousOrAuthenticatedClient, ClientHello, ResolvesServerCert}; +#[cfg(feature = "secret_extraction")] +use rustls::ConnectionTrafficSecrets; +use rustls::{ + sign, CertificateError, ConnectionCommon, Error, KeyLog, PeerIncompatible, PeerMisbehaved, + SideData, +}; +use rustls::{CipherSuite, ProtocolVersion, SignatureScheme}; +use rustls::{ClientConfig, ClientConnection}; +use rustls::{ServerConfig, ServerConnection}; +use rustls::{Stream, StreamOwned}; +use rustls::{SupportedCipherSuite, ALL_CIPHER_SUITES}; + +mod common; +use crate::common::*; + +fn alpn_test_error( + server_protos: Vec>, + client_protos: Vec>, + agreed: Option<&[u8]>, + expected_error: Option, +) { + let mut server_config = make_server_config(KeyType::Rsa); + server_config.alpn_protocols = server_protos; + + let server_config = Arc::new(server_config); + + for version in rustls::ALL_VERSIONS { + let mut client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); + client_config.alpn_protocols = client_protos.clone(); + + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + + assert_eq!(client.alpn_protocol(), None); + assert_eq!(server.alpn_protocol(), None); + let error = do_handshake_until_error(&mut client, &mut server); + assert_eq!(client.alpn_protocol(), agreed); + assert_eq!(server.alpn_protocol(), agreed); + assert_eq!(error.err(), expected_error); + } +} + +fn alpn_test(server_protos: Vec>, client_protos: Vec>, agreed: Option<&[u8]>) { + alpn_test_error(server_protos, client_protos, agreed, None) +} + +#[test] +fn alpn() { + // no support + alpn_test(vec![], vec![], None); + + // server support + alpn_test(vec![b"server-proto".to_vec()], vec![], None); + + // client support + alpn_test(vec![], vec![b"client-proto".to_vec()], None); + + // no overlap + alpn_test_error( + vec![b"server-proto".to_vec()], + vec![b"client-proto".to_vec()], + None, + Some(ErrorFromPeer::Server(Error::NoApplicationProtocol)), + ); + + // server chooses preference + alpn_test( + vec![b"server-proto".to_vec(), b"client-proto".to_vec()], + vec![b"client-proto".to_vec(), b"server-proto".to_vec()], + Some(b"server-proto"), + ); + + // case sensitive + alpn_test_error( + vec![b"PROTO".to_vec()], + vec![b"proto".to_vec()], + None, + Some(ErrorFromPeer::Server(Error::NoApplicationProtocol)), + ); +} + +fn version_test( + client_versions: &[&'static rustls::SupportedProtocolVersion], + server_versions: &[&'static rustls::SupportedProtocolVersion], + result: Option, +) { + let client_versions = if client_versions.is_empty() { + rustls::ALL_VERSIONS + } else { + client_versions + }; + let server_versions = if server_versions.is_empty() { + rustls::ALL_VERSIONS + } else { + server_versions + }; + + let client_config = make_client_config_with_versions(KeyType::Rsa, client_versions); + let server_config = make_server_config_with_versions(KeyType::Rsa, server_versions); + + println!( + "version {:?} {:?} -> {:?}", + client_versions, server_versions, result + ); + + let (mut client, mut server) = make_pair_for_configs(client_config, server_config); + + assert_eq!(client.protocol_version(), None); + assert_eq!(server.protocol_version(), None); + if result.is_none() { + let err = do_handshake_until_error(&mut client, &mut server); + assert!(err.is_err()); + } else { + do_handshake(&mut client, &mut server); + assert_eq!(client.protocol_version(), result); + assert_eq!(server.protocol_version(), result); + } +} + +#[test] +fn versions() { + // default -> 1.3 + version_test(&[], &[], Some(ProtocolVersion::TLSv1_3)); + + // client default, server 1.2 -> 1.2 + #[cfg(feature = "tls12")] + version_test( + &[], + &[&rustls::version::TLS12], + Some(ProtocolVersion::TLSv1_2), + ); + + // client 1.2, server default -> 1.2 + #[cfg(feature = "tls12")] + version_test( + &[&rustls::version::TLS12], + &[], + Some(ProtocolVersion::TLSv1_2), + ); + + // client 1.2, server 1.3 -> fail + #[cfg(feature = "tls12")] + version_test(&[&rustls::version::TLS12], &[&rustls::version::TLS13], None); + + // client 1.3, server 1.2 -> fail + #[cfg(feature = "tls12")] + version_test(&[&rustls::version::TLS13], &[&rustls::version::TLS12], None); + + // client 1.3, server 1.2+1.3 -> 1.3 + #[cfg(feature = "tls12")] + version_test( + &[&rustls::version::TLS13], + &[&rustls::version::TLS12, &rustls::version::TLS13], + Some(ProtocolVersion::TLSv1_3), + ); + + // client 1.2+1.3, server 1.2 -> 1.2 + #[cfg(feature = "tls12")] + version_test( + &[&rustls::version::TLS13, &rustls::version::TLS12], + &[&rustls::version::TLS12], + Some(ProtocolVersion::TLSv1_2), + ); +} + +fn check_read(reader: &mut dyn io::Read, bytes: &[u8]) { + let mut buf = vec![0u8; bytes.len() + 1]; + assert_eq!(bytes.len(), reader.read(&mut buf).unwrap()); + assert_eq!(bytes, &buf[..bytes.len()]); +} + +fn check_read_err(reader: &mut dyn io::Read, err_kind: io::ErrorKind) { + let mut buf = vec![0u8; 1]; + let err = reader.read(&mut buf).unwrap_err(); + assert!(matches!(err, err if err.kind() == err_kind)) +} + +#[cfg(read_buf)] +fn check_read_buf(reader: &mut dyn io::Read, bytes: &[u8]) { + use std::{io::BorrowedBuf, mem::MaybeUninit}; + + let mut buf = [MaybeUninit::::uninit(); 128]; + let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); + reader.read_buf(buf.unfilled()).unwrap(); + assert_eq!(buf.filled(), bytes); +} + +#[cfg(read_buf)] +fn check_read_buf_err(reader: &mut dyn io::Read, err_kind: io::ErrorKind) { + use std::{io::BorrowedBuf, mem::MaybeUninit}; + + let mut buf = [MaybeUninit::::uninit(); 1]; + let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); + let err = reader + .read_buf(buf.unfilled()) + .unwrap_err(); + assert!(matches!(err, err if err.kind() == err_kind)) +} + +#[test] +fn config_builder_for_client_rejects_empty_kx_groups() { + assert_eq!( + ClientConfig::builder() + .with_safe_default_cipher_suites() + .with_kx_groups(&[]) + .with_safe_default_protocol_versions() + .err(), + Some(Error::General("no kx groups configured".into())) + ); +} + +#[test] +fn config_builder_for_client_rejects_empty_cipher_suites() { + assert_eq!( + ClientConfig::builder() + .with_cipher_suites(&[]) + .with_safe_default_kx_groups() + .with_safe_default_protocol_versions() + .err(), + Some(Error::General("no usable cipher suites configured".into())) + ); +} + +#[cfg(feature = "tls12")] +#[test] +fn config_builder_for_client_rejects_incompatible_cipher_suites() { + assert_eq!( + ClientConfig::builder() + .with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_256_GCM_SHA384]) + .with_safe_default_kx_groups() + .with_protocol_versions(&[&rustls::version::TLS12]) + .err(), + Some(Error::General("no usable cipher suites configured".into())) + ); +} + +#[test] +fn config_builder_for_server_rejects_empty_kx_groups() { + assert_eq!( + ServerConfig::builder() + .with_safe_default_cipher_suites() + .with_kx_groups(&[]) + .with_safe_default_protocol_versions() + .err(), + Some(Error::General("no kx groups configured".into())) + ); +} + +#[test] +fn config_builder_for_server_rejects_empty_cipher_suites() { + assert_eq!( + ServerConfig::builder() + .with_cipher_suites(&[]) + .with_safe_default_kx_groups() + .with_safe_default_protocol_versions() + .err(), + Some(Error::General("no usable cipher suites configured".into())) + ); +} + +#[cfg(feature = "tls12")] +#[test] +fn config_builder_for_server_rejects_incompatible_cipher_suites() { + assert_eq!( + ServerConfig::builder() + .with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_256_GCM_SHA384]) + .with_safe_default_kx_groups() + .with_protocol_versions(&[&rustls::version::TLS12]) + .err(), + Some(Error::General("no usable cipher suites configured".into())) + ); +} + +#[test] +fn buffered_client_data_sent() { + let server_config = Arc::new(make_server_config(KeyType::Rsa)); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + + assert_eq!(5, client.writer().write(b"hello").unwrap()); + + do_handshake(&mut client, &mut server); + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + + check_read(&mut server.reader(), b"hello"); + } +} + +#[test] +fn buffered_server_data_sent() { + let server_config = Arc::new(make_server_config(KeyType::Rsa)); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + + assert_eq!(5, server.writer().write(b"hello").unwrap()); + + do_handshake(&mut client, &mut server); + transfer(&mut server, &mut client); + client.process_new_packets().unwrap(); + + check_read(&mut client.reader(), b"hello"); + } +} + +#[test] +fn buffered_both_data_sent() { + let server_config = Arc::new(make_server_config(KeyType::Rsa)); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + + assert_eq!( + 12, + server + .writer() + .write(b"from-server!") + .unwrap() + ); + assert_eq!( + 12, + client + .writer() + .write(b"from-client!") + .unwrap() + ); + + do_handshake(&mut client, &mut server); + + transfer(&mut server, &mut client); + client.process_new_packets().unwrap(); + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + + check_read(&mut client.reader(), b"from-server!"); + check_read(&mut server.reader(), b"from-client!"); + } +} + +#[test] +fn client_can_get_server_cert() { + for kt in ALL_KEY_TYPES.iter() { + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(*kt, &[version]); + let (mut client, mut server) = + make_pair_for_configs(client_config, make_server_config(*kt)); + do_handshake(&mut client, &mut server); + + let certs = client.peer_certificates(); + assert_eq!(certs, Some(kt.get_chain().as_slice())); + } + } +} + +#[test] +fn client_can_get_server_cert_after_resumption() { + for kt in ALL_KEY_TYPES.iter() { + let server_config = make_server_config(*kt); + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(*kt, &[version]); + let (mut client, mut server) = + make_pair_for_configs(client_config.clone(), server_config.clone()); + do_handshake(&mut client, &mut server); + + let original_certs = client.peer_certificates(); + + let (mut client, mut server) = + make_pair_for_configs(client_config.clone(), server_config.clone()); + do_handshake(&mut client, &mut server); + + let resumed_certs = client.peer_certificates(); + + assert_eq!(original_certs, resumed_certs); + } + } +} + +#[test] +fn server_can_get_client_cert() { + for kt in ALL_KEY_TYPES.iter() { + let server_config = Arc::new(make_server_config_with_mandatory_client_auth(*kt)); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + do_handshake(&mut client, &mut server); + + let certs = server.peer_certificates(); + assert_eq!(certs, Some(kt.get_client_chain().as_slice())); + } + } +} + +#[test] +fn server_can_get_client_cert_after_resumption() { + for kt in ALL_KEY_TYPES.iter() { + let server_config = Arc::new(make_server_config_with_mandatory_client_auth(*kt)); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); + let client_config = Arc::new(client_config); + let (mut client, mut server) = + make_pair_for_arc_configs(&client_config, &server_config); + do_handshake(&mut client, &mut server); + let original_certs = server.peer_certificates(); + + let (mut client, mut server) = + make_pair_for_arc_configs(&client_config, &server_config); + do_handshake(&mut client, &mut server); + let resumed_certs = server.peer_certificates(); + assert_eq!(original_certs, resumed_certs); + } + } +} + +#[test] +fn test_config_builders_debug() { + let b = ServerConfig::builder(); + assert_eq!( + "ConfigBuilder { state: WantsCipherSuites(()) }", + format!("{:?}", b) + ); + let b = b.with_cipher_suites(&[rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]); + assert_eq!("ConfigBuilder { state: WantsKxGroups { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256] } }", format!("{:?}", b)); + let b = b.with_kx_groups(&[&rustls::kx_group::X25519]); + assert_eq!("ConfigBuilder { state: WantsVersions { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519] } }", format!("{:?}", b)); + let b = b + .with_protocol_versions(&[&rustls::version::TLS13]) + .unwrap(); + let b = b.with_no_client_auth(); + assert_eq!("ConfigBuilder { state: WantsServerCert { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], versions: [TLSv1_3], verifier: dyn ClientCertVerifier } }", format!("{:?}", b)); + + let b = ClientConfig::builder(); + assert_eq!( + "ConfigBuilder { state: WantsCipherSuites(()) }", + format!("{:?}", b) + ); + let b = b.with_cipher_suites(&[rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]); + assert_eq!("ConfigBuilder { state: WantsKxGroups { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256] } }", format!("{:?}", b)); + let b = b.with_kx_groups(&[&rustls::kx_group::X25519]); + assert_eq!("ConfigBuilder { state: WantsVersions { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519] } }", format!("{:?}", b)); + let b = b + .with_protocol_versions(&[&rustls::version::TLS13]) + .unwrap(); + assert_eq!("ConfigBuilder { state: WantsVerifier { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], versions: [TLSv1_3] } }", format!("{:?}", b)); +} + +/// Test that the server handles combination of `offer_client_auth()` returning true +/// and `client_auth_mandatory` returning `Some(false)`. This exercises both the +/// client's and server's ability to "recover" from the server asking for a client +/// certificate and not being given one. This also covers the implementation +/// of `AllowAnyAnonymousOrAuthenticatedClient`. +#[test] +fn server_allow_any_anonymous_or_authenticated_client() { + let kt = KeyType::Rsa; + for client_cert_chain in [None, Some(kt.get_client_chain())].iter() { + let client_auth_roots = get_client_root_store(kt); + let client_auth = AllowAnyAnonymousOrAuthenticatedClient::new(client_auth_roots); + + let server_config = ServerConfig::builder() + .with_safe_defaults() + .with_client_cert_verifier(Arc::new(client_auth)) + .with_single_cert(kt.get_chain(), kt.get_key()) + .unwrap(); + let server_config = Arc::new(server_config); + + for version in rustls::ALL_VERSIONS { + let client_config = if client_cert_chain.is_some() { + make_client_config_with_versions_with_auth(kt, &[version]) + } else { + make_client_config_with_versions(kt, &[version]) + }; + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + do_handshake(&mut client, &mut server); + + let certs = server.peer_certificates(); + assert_eq!(certs, client_cert_chain.as_deref()); + } + } +} + +fn check_read_and_close(reader: &mut dyn io::Read, expect: &[u8]) { + check_read(reader, expect); + assert!(matches!(reader.read(&mut [0u8; 5]), Ok(0))); +} + +#[test] +fn server_close_notify() { + let kt = KeyType::Rsa; + let server_config = Arc::new(make_server_config_with_mandatory_client_auth(kt)); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions_with_auth(kt, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + do_handshake(&mut client, &mut server); + + // check that alerts don't overtake appdata + assert_eq!( + 12, + server + .writer() + .write(b"from-server!") + .unwrap() + ); + assert_eq!( + 12, + client + .writer() + .write(b"from-client!") + .unwrap() + ); + server.send_close_notify(); + + transfer(&mut server, &mut client); + let io_state = client.process_new_packets().unwrap(); + assert!(io_state.peer_has_closed()); + check_read_and_close(&mut client.reader(), b"from-server!"); + + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + check_read(&mut server.reader(), b"from-client!"); + } +} + +#[test] +fn client_close_notify() { + let kt = KeyType::Rsa; + let server_config = Arc::new(make_server_config_with_mandatory_client_auth(kt)); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions_with_auth(kt, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + do_handshake(&mut client, &mut server); + + // check that alerts don't overtake appdata + assert_eq!( + 12, + server + .writer() + .write(b"from-server!") + .unwrap() + ); + assert_eq!( + 12, + client + .writer() + .write(b"from-client!") + .unwrap() + ); + client.send_close_notify(); + + transfer(&mut client, &mut server); + let io_state = server.process_new_packets().unwrap(); + assert!(io_state.peer_has_closed()); + check_read_and_close(&mut server.reader(), b"from-client!"); + + transfer(&mut server, &mut client); + client.process_new_packets().unwrap(); + check_read(&mut client.reader(), b"from-server!"); + } +} + +#[test] +fn server_closes_uncleanly() { + let kt = KeyType::Rsa; + let server_config = Arc::new(make_server_config(kt)); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(kt, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + do_handshake(&mut client, &mut server); + + // check that unclean EOF reporting does not overtake appdata + assert_eq!( + 12, + server + .writer() + .write(b"from-server!") + .unwrap() + ); + assert_eq!( + 12, + client + .writer() + .write(b"from-client!") + .unwrap() + ); + + transfer(&mut server, &mut client); + transfer_eof(&mut client); + let io_state = client.process_new_packets().unwrap(); + assert!(!io_state.peer_has_closed()); + check_read(&mut client.reader(), b"from-server!"); + + check_read_err( + &mut client.reader() as &mut dyn io::Read, + io::ErrorKind::UnexpectedEof, + ); + + // may still transmit pending frames + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + check_read(&mut server.reader(), b"from-client!"); + } +} + +#[test] +fn client_closes_uncleanly() { + let kt = KeyType::Rsa; + let server_config = Arc::new(make_server_config(kt)); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(kt, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + do_handshake(&mut client, &mut server); + + // check that unclean EOF reporting does not overtake appdata + assert_eq!( + 12, + server + .writer() + .write(b"from-server!") + .unwrap() + ); + assert_eq!( + 12, + client + .writer() + .write(b"from-client!") + .unwrap() + ); + + transfer(&mut client, &mut server); + transfer_eof(&mut server); + let io_state = server.process_new_packets().unwrap(); + assert!(!io_state.peer_has_closed()); + check_read(&mut server.reader(), b"from-client!"); + + check_read_err( + &mut server.reader() as &mut dyn io::Read, + io::ErrorKind::UnexpectedEof, + ); + + // may still transmit pending frames + transfer(&mut server, &mut client); + client.process_new_packets().unwrap(); + check_read(&mut client.reader(), b"from-server!"); + } +} + +#[derive(Default)] +struct ServerCheckCertResolve { + expected_sni: Option, + expected_sigalgs: Option>, + expected_alpn: Option>>, + expected_cipher_suites: Option>, +} + +impl ResolvesServerCert for ServerCheckCertResolve { + fn resolve(&self, client_hello: ClientHello) -> Option> { + if client_hello + .signature_schemes() + .is_empty() + { + panic!("no signature schemes shared by client"); + } + + if client_hello.cipher_suites().is_empty() { + panic!("no cipher suites shared by client"); + } + + if let Some(expected_sni) = &self.expected_sni { + let sni: &str = client_hello + .server_name() + .expect("sni unexpectedly absent"); + assert_eq!(expected_sni, sni); + } + + if let Some(expected_sigalgs) = &self.expected_sigalgs { + assert_eq!( + expected_sigalgs, + client_hello.signature_schemes(), + "unexpected signature schemes" + ); + } + + if let Some(expected_alpn) = &self.expected_alpn { + let alpn = client_hello + .alpn() + .expect("alpn unexpectedly absent") + .collect::>(); + assert_eq!(alpn.len(), expected_alpn.len()); + + for (got, wanted) in alpn.iter().zip(expected_alpn.iter()) { + assert_eq!(got, &wanted.as_slice()); + } + } + + if let Some(expected_cipher_suites) = &self.expected_cipher_suites { + assert_eq!( + expected_cipher_suites, + client_hello.cipher_suites(), + "unexpected cipher suites" + ); + } + + None + } +} + +#[test] +fn server_cert_resolve_with_sni() { + for kt in ALL_KEY_TYPES.iter() { + let client_config = make_client_config(*kt); + let mut server_config = make_server_config(*kt); + + server_config.cert_resolver = Arc::new(ServerCheckCertResolve { + expected_sni: Some("the-value-from-sni".into()), + ..Default::default() + }); + + let mut client = + ClientConnection::new(Arc::new(client_config), dns_name("the-value-from-sni")).unwrap(); + let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); + + let err = do_handshake_until_error(&mut client, &mut server); + assert!(err.is_err()); + } +} + +#[test] +fn server_cert_resolve_with_alpn() { + for kt in ALL_KEY_TYPES.iter() { + let mut client_config = make_client_config(*kt); + client_config.alpn_protocols = vec!["foo".into(), "bar".into()]; + + let mut server_config = make_server_config(*kt); + server_config.cert_resolver = Arc::new(ServerCheckCertResolve { + expected_alpn: Some(vec![b"foo".to_vec(), b"bar".to_vec()]), + ..Default::default() + }); + + let mut client = + ClientConnection::new(Arc::new(client_config), dns_name("sni-value")).unwrap(); + let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); + + let err = do_handshake_until_error(&mut client, &mut server); + assert!(err.is_err()); + } +} + +#[test] +fn client_trims_terminating_dot() { + for kt in ALL_KEY_TYPES.iter() { + let client_config = make_client_config(*kt); + let mut server_config = make_server_config(*kt); + + server_config.cert_resolver = Arc::new(ServerCheckCertResolve { + expected_sni: Some("some-host.com".into()), + ..Default::default() + }); + + let mut client = + ClientConnection::new(Arc::new(client_config), dns_name("some-host.com.")).unwrap(); + let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); + + let err = do_handshake_until_error(&mut client, &mut server); + assert!(err.is_err()); + } +} + +#[cfg(feature = "tls12")] +fn check_sigalgs_reduced_by_ciphersuite( + kt: KeyType, + suite: CipherSuite, + expected_sigalgs: Vec, +) { + let client_config = finish_client_config( + kt, + ClientConfig::builder() + .with_cipher_suites(&[find_suite(suite)]) + .with_safe_default_kx_groups() + .with_safe_default_protocol_versions() + .unwrap(), + ); + + let mut server_config = make_server_config(kt); + + server_config.cert_resolver = Arc::new(ServerCheckCertResolve { + expected_sigalgs: Some(expected_sigalgs), + expected_cipher_suites: Some(vec![suite, CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV]), + ..Default::default() + }); + + let mut client = ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap(); + let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); + + let err = do_handshake_until_error(&mut client, &mut server); + assert!(err.is_err()); +} + +#[cfg(feature = "tls12")] +#[test] +fn server_cert_resolve_reduces_sigalgs_for_rsa_ciphersuite() { + check_sigalgs_reduced_by_ciphersuite( + KeyType::Rsa, + CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + vec![ + SignatureScheme::RSA_PSS_SHA512, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA256, + SignatureScheme::RSA_PKCS1_SHA512, + SignatureScheme::RSA_PKCS1_SHA384, + SignatureScheme::RSA_PKCS1_SHA256, + ], + ); +} + +#[cfg(feature = "tls12")] +#[test] +fn server_cert_resolve_reduces_sigalgs_for_ecdsa_ciphersuite() { + check_sigalgs_reduced_by_ciphersuite( + KeyType::Ecdsa, + CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + vec![ + SignatureScheme::ECDSA_NISTP384_SHA384, + SignatureScheme::ECDSA_NISTP256_SHA256, + SignatureScheme::ED25519, + ], + ); +} + +struct ServerCheckNoSNI {} + +impl ResolvesServerCert for ServerCheckNoSNI { + fn resolve(&self, client_hello: ClientHello) -> Option> { + assert!(client_hello.server_name().is_none()); + + None + } +} + +#[test] +fn client_with_sni_disabled_does_not_send_sni() { + for kt in ALL_KEY_TYPES.iter() { + let mut server_config = make_server_config(*kt); + server_config.cert_resolver = Arc::new(ServerCheckNoSNI {}); + let server_config = Arc::new(server_config); + + for version in rustls::ALL_VERSIONS { + let mut client_config = make_client_config_with_versions(*kt, &[version]); + client_config.enable_sni = false; + + let mut client = + ClientConnection::new(Arc::new(client_config), dns_name("value-not-sent")).unwrap(); + let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); + + let err = do_handshake_until_error(&mut client, &mut server); + assert!(err.is_err()); + } + } +} + +#[test] +fn client_checks_server_certificate_with_given_name() { + for kt in ALL_KEY_TYPES.iter() { + let server_config = Arc::new(make_server_config(*kt)); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(*kt, &[version]); + let mut client = ClientConnection::new( + Arc::new(client_config), + dns_name("not-the-right-hostname.com"), + ) + .unwrap(); + let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); + + let err = do_handshake_until_error(&mut client, &mut server); + assert_eq!( + err, + Err(ErrorFromPeer::Client(Error::InvalidCertificate( + CertificateError::NotValidForName + ))) + ); + } + } +} + +struct ClientCheckCertResolve { + query_count: AtomicUsize, + expect_queries: usize, + expect_issuers: Vec>, + expect_sigschemes: Vec, +} + +impl ClientCheckCertResolve { + fn new( + expect_queries: usize, + expect_issuers: Vec>, + expect_sigschemes: Vec, + ) -> Self { + Self { + query_count: AtomicUsize::new(0), + expect_queries, + expect_issuers, + expect_sigschemes, + } + } +} + +impl Drop for ClientCheckCertResolve { + fn drop(&mut self) { + if !std::thread::panicking() { + let count = self.query_count.load(Ordering::SeqCst); + assert_eq!(count, self.expect_queries); + } + } +} + +impl ResolvesClientCert for ClientCheckCertResolve { + fn resolve( + &self, + acceptable_issuers: &[&[u8]], + sigschemes: &[SignatureScheme], + ) -> Option> { + self.query_count + .fetch_add(1, Ordering::SeqCst); + + if acceptable_issuers.is_empty() { + panic!("no issuers offered by server"); + } + + if sigschemes.is_empty() { + panic!("no signature schemes shared by server"); + } + + assert_eq!(acceptable_issuers, self.expect_issuers); + assert_eq!(sigschemes, self.expect_sigschemes); + + None + } + + fn has_certs(&self) -> bool { + true + } +} + +#[test] +fn client_cert_resolve() { + for kt in ALL_KEY_TYPES.iter() { + let server_config = Arc::new(make_server_config_with_mandatory_client_auth(*kt)); + + let expected_issuers = match *kt { + KeyType::Rsa => vec![ + b"0,1*0(\x06\x03U\x04\x03\x0c!ponytown RSA level 2 intermediate".to_vec(), + b"0\x1a1\x180\x16\x06\x03U\x04\x03\x0c\x0fponytown RSA CA".to_vec(), + ], + KeyType::Ecdsa => vec![ + b"0.1,0*\x06\x03U\x04\x03\x0c#ponytown ECDSA level 2 intermediate".to_vec(), + b"0\x1c1\x1a0\x18\x06\x03U\x04\x03\x0c\x11ponytown ECDSA CA".to_vec(), + ], + KeyType::Ed25519 => vec![ + b"0.1,0*\x06\x03U\x04\x03\x0c#ponytown EdDSA level 2 intermediate".to_vec(), + b"0\x1c1\x1a0\x18\x06\x03U\x04\x03\x0c\x11ponytown EdDSA CA".to_vec(), + ], + }; + + for version in rustls::ALL_VERSIONS { + let expected_sigschemes = match version.version { + ProtocolVersion::TLSv1_2 => vec![ + SignatureScheme::ECDSA_NISTP384_SHA384, + SignatureScheme::ECDSA_NISTP256_SHA256, + SignatureScheme::ED25519, + SignatureScheme::RSA_PSS_SHA512, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA256, + SignatureScheme::RSA_PKCS1_SHA512, + SignatureScheme::RSA_PKCS1_SHA384, + SignatureScheme::RSA_PKCS1_SHA256, + ], + ProtocolVersion::TLSv1_3 => vec![ + SignatureScheme::ECDSA_NISTP384_SHA384, + SignatureScheme::ECDSA_NISTP256_SHA256, + SignatureScheme::ED25519, + SignatureScheme::RSA_PSS_SHA512, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA256, + ], + _ => unreachable!(), + }; + + println!("{:?} {:?}:", version.version, *kt); + + let mut client_config = make_client_config_with_versions(*kt, &[version]); + client_config.client_auth_cert_resolver = Arc::new(ClientCheckCertResolve::new( + 1, + expected_issuers.clone(), + expected_sigschemes, + )); + + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + + assert_eq!( + do_handshake_until_error(&mut client, &mut server), + Err(ErrorFromPeer::Server(Error::NoCertificatesPresented)) + ); + } + } +} + +#[test] +fn client_auth_works() { + for kt in ALL_KEY_TYPES.iter() { + let server_config = Arc::new(make_server_config_with_mandatory_client_auth(*kt)); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + do_handshake(&mut client, &mut server); + } + } +} + +#[test] +fn client_mandatory_auth_revocation_works() { + for kt in ALL_KEY_TYPES.iter() { + // Create a server configuration that includes a CRL that specifies the client certificate + // is revoked. + let crls = vec![kt.client_crl()]; + let server_config = Arc::new(make_server_config_with_mandatory_client_auth_crls( + *kt, crls, + )); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + // Because the client certificate is revoked, the handshake should fail. + let err = do_handshake_until_error(&mut client, &mut server); + assert_eq!( + err, + Err(ErrorFromPeer::Server(Error::InvalidCertificate( + CertificateError::Revoked + ))) + ); + } + } +} + +#[test] +fn client_optional_auth_revocation_works() { + for kt in ALL_KEY_TYPES.iter() { + // Create a server configuration that includes a CRL that specifies the client certificate + // is revoked. + let crls = vec![kt.client_crl()]; + let server_config = Arc::new(make_server_config_with_optional_client_auth(*kt, crls)); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + // Because the client certificate is revoked, the handshake should fail. + let err = do_handshake_until_error(&mut client, &mut server); + assert_eq!( + err, + Err(ErrorFromPeer::Server(Error::InvalidCertificate( + CertificateError::Revoked + ))) + ); + } + } +} + +#[test] +fn client_error_is_sticky() { + let (mut client, _) = make_pair(KeyType::Rsa); + client + .read_tls(&mut b"\x16\x03\x03\x00\x08\x0f\x00\x00\x04junk".as_ref()) + .unwrap(); + let mut err = client.process_new_packets(); + assert!(err.is_err()); + err = client.process_new_packets(); + assert!(err.is_err()); +} + +#[test] +fn server_error_is_sticky() { + let (_, mut server) = make_pair(KeyType::Rsa); + server + .read_tls(&mut b"\x16\x03\x03\x00\x08\x0f\x00\x00\x04junk".as_ref()) + .unwrap(); + let mut err = server.process_new_packets(); + assert!(err.is_err()); + err = server.process_new_packets(); + assert!(err.is_err()); +} + +#[test] +fn server_flush_does_nothing() { + let (_, mut server) = make_pair(KeyType::Rsa); + assert!(matches!(server.writer().flush(), Ok(()))); +} + +#[test] +fn client_flush_does_nothing() { + let (mut client, _) = make_pair(KeyType::Rsa); + assert!(matches!(client.writer().flush(), Ok(()))); +} + +#[test] +fn server_is_send_and_sync() { + let (_, server) = make_pair(KeyType::Rsa); + &server as &dyn Send; + &server as &dyn Sync; +} + +#[test] +fn client_is_send_and_sync() { + let (client, _) = make_pair(KeyType::Rsa); + &client as &dyn Send; + &client as &dyn Sync; +} + +#[test] +fn server_respects_buffer_limit_pre_handshake() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + + server.set_buffer_limit(Some(32)); + + assert_eq!( + server + .writer() + .write(b"01234567890123456789") + .unwrap(), + 20 + ); + assert_eq!( + server + .writer() + .write(b"01234567890123456789") + .unwrap(), + 12 + ); + + do_handshake(&mut client, &mut server); + transfer(&mut server, &mut client); + client.process_new_packets().unwrap(); + + check_read(&mut client.reader(), b"01234567890123456789012345678901"); +} + +#[test] +fn server_respects_buffer_limit_pre_handshake_with_vectored_write() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + + server.set_buffer_limit(Some(32)); + + assert_eq!( + server + .writer() + .write_vectored(&[ + IoSlice::new(b"01234567890123456789"), + IoSlice::new(b"01234567890123456789") + ]) + .unwrap(), + 32 + ); + + do_handshake(&mut client, &mut server); + transfer(&mut server, &mut client); + client.process_new_packets().unwrap(); + + check_read(&mut client.reader(), b"01234567890123456789012345678901"); +} + +#[test] +fn server_respects_buffer_limit_post_handshake() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + + // this test will vary in behaviour depending on the default suites + do_handshake(&mut client, &mut server); + server.set_buffer_limit(Some(48)); + + assert_eq!( + server + .writer() + .write(b"01234567890123456789") + .unwrap(), + 20 + ); + assert_eq!( + server + .writer() + .write(b"01234567890123456789") + .unwrap(), + 6 + ); + + transfer(&mut server, &mut client); + client.process_new_packets().unwrap(); + + check_read(&mut client.reader(), b"01234567890123456789012345"); +} + +#[test] +fn client_respects_buffer_limit_pre_handshake() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + + client.set_buffer_limit(Some(32)); + + assert_eq!( + client + .writer() + .write(b"01234567890123456789") + .unwrap(), + 20 + ); + assert_eq!( + client + .writer() + .write(b"01234567890123456789") + .unwrap(), + 12 + ); + + do_handshake(&mut client, &mut server); + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + + check_read(&mut server.reader(), b"01234567890123456789012345678901"); +} + +#[test] +fn client_respects_buffer_limit_pre_handshake_with_vectored_write() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + + client.set_buffer_limit(Some(32)); + + assert_eq!( + client + .writer() + .write_vectored(&[ + IoSlice::new(b"01234567890123456789"), + IoSlice::new(b"01234567890123456789") + ]) + .unwrap(), + 32 + ); + + do_handshake(&mut client, &mut server); + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + + check_read(&mut server.reader(), b"01234567890123456789012345678901"); +} + +#[test] +fn client_respects_buffer_limit_post_handshake() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + + do_handshake(&mut client, &mut server); + client.set_buffer_limit(Some(48)); + + assert_eq!( + client + .writer() + .write(b"01234567890123456789") + .unwrap(), + 20 + ); + assert_eq!( + client + .writer() + .write(b"01234567890123456789") + .unwrap(), + 6 + ); + + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + + check_read(&mut server.reader(), b"01234567890123456789012345"); +} + +struct OtherSession<'a, C, S> +where + C: DerefMut + Deref>, + S: SideData, +{ + sess: &'a mut C, + pub reads: usize, + pub writevs: Vec>, + fail_ok: bool, + pub short_writes: bool, + pub last_error: Option, + pub buffered: bool, + buffer: Vec>, +} + +impl<'a, C, S> OtherSession<'a, C, S> +where + C: DerefMut + Deref>, + S: SideData, +{ + fn new(sess: &'a mut C) -> OtherSession<'a, C, S> { + OtherSession { + sess, + reads: 0, + writevs: vec![], + fail_ok: false, + short_writes: false, + last_error: None, + buffered: false, + buffer: vec![], + } + } + + fn new_buffered(sess: &'a mut C) -> OtherSession<'a, C, S> { + let mut os = OtherSession::new(sess); + os.buffered = true; + os + } + + fn new_fails(sess: &'a mut C) -> OtherSession<'a, C, S> { + let mut os = OtherSession::new(sess); + os.fail_ok = true; + os + } + + fn flush_vectored(&mut self, b: &[io::IoSlice<'_>]) -> io::Result { + let mut total = 0; + let mut lengths = vec![]; + for bytes in b { + let write_len = if self.short_writes { + if bytes.len() > 5 { + bytes.len() / 2 + } else { + bytes.len() + } + } else { + bytes.len() + }; + + let l = self + .sess + .read_tls(&mut io::Cursor::new(&bytes[..write_len]))?; + lengths.push(l); + total += l; + if bytes.len() != l { + break; + } + } + + let rc = self.sess.process_new_packets(); + if !self.fail_ok { + rc.unwrap(); + } else if rc.is_err() { + self.last_error = rc.err(); + } + + self.writevs.push(lengths); + Ok(total) + } +} + +impl<'a, C, S> io::Read for OtherSession<'a, C, S> +where + C: DerefMut + Deref>, + S: SideData, +{ + fn read(&mut self, mut b: &mut [u8]) -> io::Result { + self.reads += 1; + self.sess.write_tls(b.by_ref()) + } +} + +impl<'a, C, S> io::Write for OtherSession<'a, C, S> +where + C: DerefMut + Deref>, + S: SideData, +{ + fn write(&mut self, _: &[u8]) -> io::Result { + unreachable!() + } + + fn flush(&mut self) -> io::Result<()> { + if !self.buffer.is_empty() { + let buffer = mem::take(&mut self.buffer); + let slices = buffer + .iter() + .map(|b| io::IoSlice::new(b)) + .collect::>(); + self.flush_vectored(&slices)?; + } + Ok(()) + } + + fn write_vectored(&mut self, b: &[io::IoSlice<'_>]) -> io::Result { + if self.buffered { + self.buffer + .extend(b.iter().map(|s| s.to_vec())); + return Ok(b.iter().map(|s| s.len()).sum()); + } + self.flush_vectored(b) + } +} + +#[test] +fn server_read_returns_wouldblock_when_no_data() { + let (_, mut server) = make_pair(KeyType::Rsa); + assert!(matches!(server.reader().read(&mut [0u8; 1]), + Err(err) if err.kind() == io::ErrorKind::WouldBlock)); +} + +#[test] +fn client_read_returns_wouldblock_when_no_data() { + let (mut client, _) = make_pair(KeyType::Rsa); + assert!(matches!(client.reader().read(&mut [0u8; 1]), + Err(err) if err.kind() == io::ErrorKind::WouldBlock)); +} + +#[test] +fn new_server_returns_initial_io_state() { + let (_, mut server) = make_pair(KeyType::Rsa); + let io_state = server.process_new_packets().unwrap(); + println!("IoState is Debug {:?}", io_state); + assert_eq!(io_state.plaintext_bytes_to_read(), 0); + assert!(!io_state.peer_has_closed()); + assert_eq!(io_state.tls_bytes_to_write(), 0); +} + +#[test] +fn new_client_returns_initial_io_state() { + let (mut client, _) = make_pair(KeyType::Rsa); + let io_state = client.process_new_packets().unwrap(); + println!("IoState is Debug {:?}", io_state); + assert_eq!(io_state.plaintext_bytes_to_read(), 0); + assert!(!io_state.peer_has_closed()); + assert!(io_state.tls_bytes_to_write() > 200); +} + +#[test] +fn client_complete_io_for_handshake() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + + assert!(client.is_handshaking()); + let (rdlen, wrlen) = client + .complete_io(&mut OtherSession::new(&mut server)) + .unwrap(); + assert!(rdlen > 0 && wrlen > 0); + assert!(!client.is_handshaking()); + assert!(!client.wants_write()); +} + +#[test] +fn buffered_client_complete_io_for_handshake() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + + assert!(client.is_handshaking()); + let (rdlen, wrlen) = client + .complete_io(&mut OtherSession::new_buffered(&mut server)) + .unwrap(); + assert!(rdlen > 0 && wrlen > 0); + assert!(!client.is_handshaking()); + assert!(!client.wants_write()); +} + +#[test] +fn client_complete_io_for_handshake_eof() { + let (mut client, _) = make_pair(KeyType::Rsa); + let mut input = io::Cursor::new(Vec::new()); + + assert!(client.is_handshaking()); + let err = client + .complete_io(&mut input) + .unwrap_err(); + assert_eq!(io::ErrorKind::UnexpectedEof, err.kind()); +} + +#[test] +fn client_complete_io_for_write() { + for kt in ALL_KEY_TYPES.iter() { + let (mut client, mut server) = make_pair(*kt); + + do_handshake(&mut client, &mut server); + + client + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + client + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + { + let mut pipe = OtherSession::new(&mut server); + let (rdlen, wrlen) = client.complete_io(&mut pipe).unwrap(); + assert!(rdlen == 0 && wrlen > 0); + println!("{:?}", pipe.writevs); + assert_eq!(pipe.writevs, vec![vec![42, 42]]); + } + check_read( + &mut server.reader(), + b"0123456789012345678901234567890123456789", + ); + } +} + +#[test] +fn buffered_client_complete_io_for_write() { + for kt in ALL_KEY_TYPES.iter() { + let (mut client, mut server) = make_pair(*kt); + + do_handshake(&mut client, &mut server); + + client + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + client + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + { + let mut pipe = OtherSession::new_buffered(&mut server); + let (rdlen, wrlen) = client.complete_io(&mut pipe).unwrap(); + assert!(rdlen == 0 && wrlen > 0); + println!("{:?}", pipe.writevs); + assert_eq!(pipe.writevs, vec![vec![42, 42]]); + } + check_read( + &mut server.reader(), + b"0123456789012345678901234567890123456789", + ); + } +} + +#[test] +fn client_complete_io_for_read() { + for kt in ALL_KEY_TYPES.iter() { + let (mut client, mut server) = make_pair(*kt); + + do_handshake(&mut client, &mut server); + + server + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + { + let mut pipe = OtherSession::new(&mut server); + let (rdlen, wrlen) = client.complete_io(&mut pipe).unwrap(); + assert!(rdlen > 0 && wrlen == 0); + assert_eq!(pipe.reads, 1); + } + check_read(&mut client.reader(), b"01234567890123456789"); + } +} + +#[test] +fn server_complete_io_for_handshake() { + for kt in ALL_KEY_TYPES.iter() { + let (mut client, mut server) = make_pair(*kt); + + assert!(server.is_handshaking()); + let (rdlen, wrlen) = server + .complete_io(&mut OtherSession::new(&mut client)) + .unwrap(); + assert!(rdlen > 0 && wrlen > 0); + assert!(!server.is_handshaking()); + assert!(!server.wants_write()); + } +} + +#[test] +fn server_complete_io_for_handshake_eof() { + let (_, mut server) = make_pair(KeyType::Rsa); + let mut input = io::Cursor::new(Vec::new()); + + assert!(server.is_handshaking()); + let err = server + .complete_io(&mut input) + .unwrap_err(); + assert_eq!(io::ErrorKind::UnexpectedEof, err.kind()); +} + +#[test] +fn server_complete_io_for_write() { + for kt in ALL_KEY_TYPES.iter() { + let (mut client, mut server) = make_pair(*kt); + + do_handshake(&mut client, &mut server); + + server + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + server + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + { + let mut pipe = OtherSession::new(&mut client); + let (rdlen, wrlen) = server.complete_io(&mut pipe).unwrap(); + assert!(rdlen == 0 && wrlen > 0); + assert_eq!(pipe.writevs, vec![vec![42, 42]]); + } + check_read( + &mut client.reader(), + b"0123456789012345678901234567890123456789", + ); + } +} + +#[test] +fn server_complete_io_for_read() { + for kt in ALL_KEY_TYPES.iter() { + let (mut client, mut server) = make_pair(*kt); + + do_handshake(&mut client, &mut server); + + client + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + { + let mut pipe = OtherSession::new(&mut client); + let (rdlen, wrlen) = server.complete_io(&mut pipe).unwrap(); + assert!(rdlen > 0 && wrlen == 0); + assert_eq!(pipe.reads, 1); + } + check_read(&mut server.reader(), b"01234567890123456789"); + } +} + +#[test] +fn client_stream_write() { + test_client_stream_write(StreamKind::Ref); + test_client_stream_write(StreamKind::Owned); +} + +#[test] +fn server_stream_write() { + test_server_stream_write(StreamKind::Ref); + test_server_stream_write(StreamKind::Owned); +} + +#[derive(Debug, Copy, Clone)] +enum StreamKind { + Owned, + Ref, +} + +fn test_client_stream_write(stream_kind: StreamKind) { + for kt in ALL_KEY_TYPES.iter() { + let (mut client, mut server) = make_pair(*kt); + let data = b"hello"; + { + let mut pipe = OtherSession::new(&mut server); + let mut stream: Box = match stream_kind { + StreamKind::Ref => Box::new(Stream::new(&mut client, &mut pipe)), + StreamKind::Owned => Box::new(StreamOwned::new(client, pipe)), + }; + assert_eq!(stream.write(data).unwrap(), 5); + } + check_read(&mut server.reader(), data); + } +} + +fn test_server_stream_write(stream_kind: StreamKind) { + for kt in ALL_KEY_TYPES.iter() { + let (mut client, mut server) = make_pair(*kt); + let data = b"hello"; + { + let mut pipe = OtherSession::new(&mut client); + let mut stream: Box = match stream_kind { + StreamKind::Ref => Box::new(Stream::new(&mut server, &mut pipe)), + StreamKind::Owned => Box::new(StreamOwned::new(server, pipe)), + }; + assert_eq!(stream.write(data).unwrap(), 5); + } + check_read(&mut client.reader(), data); + } +} + +#[test] +fn client_stream_read() { + test_client_stream_read(StreamKind::Ref, ReadKind::Buf); + test_client_stream_read(StreamKind::Owned, ReadKind::Buf); + #[cfg(read_buf)] + { + test_client_stream_read(StreamKind::Ref, ReadKind::BorrowedBuf); + test_client_stream_read(StreamKind::Owned, ReadKind::BorrowedBuf); + } +} + +#[test] +fn server_stream_read() { + test_server_stream_read(StreamKind::Ref, ReadKind::Buf); + test_server_stream_read(StreamKind::Owned, ReadKind::Buf); + #[cfg(read_buf)] + { + test_server_stream_read(StreamKind::Ref, ReadKind::BorrowedBuf); + test_server_stream_read(StreamKind::Owned, ReadKind::BorrowedBuf); + } +} + +#[derive(Debug, Copy, Clone)] +enum ReadKind { + Buf, + #[cfg(read_buf)] + BorrowedBuf, +} + +fn test_stream_read(read_kind: ReadKind, mut stream: impl Read, data: &[u8]) { + match read_kind { + ReadKind::Buf => { + check_read(&mut stream, data); + check_read_err(&mut stream, io::ErrorKind::UnexpectedEof) + } + #[cfg(read_buf)] + ReadKind::BorrowedBuf => { + check_read_buf(&mut stream, data); + check_read_buf_err(&mut stream, io::ErrorKind::UnexpectedEof) + } + } +} + +fn test_client_stream_read(stream_kind: StreamKind, read_kind: ReadKind) { + for kt in ALL_KEY_TYPES.iter() { + let (mut client, mut server) = make_pair(*kt); + let data = b"world"; + server.writer().write_all(data).unwrap(); + + { + let mut pipe = OtherSession::new(&mut server); + transfer_eof(&mut client); + + let stream: Box = match stream_kind { + StreamKind::Ref => Box::new(Stream::new(&mut client, &mut pipe)), + StreamKind::Owned => Box::new(StreamOwned::new(client, pipe)), + }; + + test_stream_read(read_kind, stream, data) + } + } +} + +fn test_server_stream_read(stream_kind: StreamKind, read_kind: ReadKind) { + for kt in ALL_KEY_TYPES.iter() { + let (mut client, mut server) = make_pair(*kt); + let data = b"world"; + client.writer().write_all(data).unwrap(); + + { + let mut pipe = OtherSession::new(&mut client); + transfer_eof(&mut server); + + let stream: Box = match stream_kind { + StreamKind::Ref => Box::new(Stream::new(&mut server, &mut pipe)), + StreamKind::Owned => Box::new(StreamOwned::new(server, pipe)), + }; + + test_stream_read(read_kind, stream, data) + } + } +} + +struct FailsWrites { + errkind: io::ErrorKind, + after: usize, +} + +impl io::Read for FailsWrites { + fn read(&mut self, _b: &mut [u8]) -> io::Result { + Ok(0) + } +} + +impl io::Write for FailsWrites { + fn write(&mut self, b: &[u8]) -> io::Result { + if self.after > 0 { + self.after -= 1; + Ok(b.len()) + } else { + Err(io::Error::new(self.errkind, "oops")) + } + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[test] +fn stream_write_reports_underlying_io_error_before_plaintext_processed() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + do_handshake(&mut client, &mut server); + + let mut pipe = FailsWrites { + errkind: io::ErrorKind::ConnectionAborted, + after: 0, + }; + client + .writer() + .write_all(b"hello") + .unwrap(); + let mut client_stream = Stream::new(&mut client, &mut pipe); + let rc = client_stream.write(b"world"); + assert!(rc.is_err()); + let err = rc.err().unwrap(); + assert_eq!(err.kind(), io::ErrorKind::ConnectionAborted); +} + +#[test] +fn stream_write_swallows_underlying_io_error_after_plaintext_processed() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + do_handshake(&mut client, &mut server); + + let mut pipe = FailsWrites { + errkind: io::ErrorKind::ConnectionAborted, + after: 1, + }; + client + .writer() + .write_all(b"hello") + .unwrap(); + let mut client_stream = Stream::new(&mut client, &mut pipe); + let rc = client_stream.write(b"world"); + assert_eq!(format!("{:?}", rc), "Ok(5)"); +} + +fn make_disjoint_suite_configs() -> (ClientConfig, ServerConfig) { + let kt = KeyType::Rsa; + let server_config = finish_server_config( + kt, + ServerConfig::builder() + .with_cipher_suites(&[rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]) + .with_safe_default_kx_groups() + .with_safe_default_protocol_versions() + .unwrap(), + ); + + let client_config = finish_client_config( + kt, + ClientConfig::builder() + .with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_256_GCM_SHA384]) + .with_safe_default_kx_groups() + .with_safe_default_protocol_versions() + .unwrap(), + ); + + (client_config, server_config) +} + +#[test] +fn client_stream_handshake_error() { + let (client_config, server_config) = make_disjoint_suite_configs(); + let (mut client, mut server) = make_pair_for_configs(client_config, server_config); + + { + let mut pipe = OtherSession::new_fails(&mut server); + let mut client_stream = Stream::new(&mut client, &mut pipe); + let rc = client_stream.write(b"hello"); + assert!(rc.is_err()); + assert_eq!( + format!("{:?}", rc), + "Err(Custom { kind: InvalidData, error: AlertReceived(HandshakeFailure) })" + ); + let rc = client_stream.write(b"hello"); + assert!(rc.is_err()); + assert_eq!( + format!("{:?}", rc), + "Err(Custom { kind: InvalidData, error: AlertReceived(HandshakeFailure) })" + ); + } +} + +#[test] +fn client_streamowned_handshake_error() { + let (client_config, server_config) = make_disjoint_suite_configs(); + let (client, mut server) = make_pair_for_configs(client_config, server_config); + + let pipe = OtherSession::new_fails(&mut server); + let mut client_stream = StreamOwned::new(client, pipe); + let rc = client_stream.write(b"hello"); + assert!(rc.is_err()); + assert_eq!( + format!("{:?}", rc), + "Err(Custom { kind: InvalidData, error: AlertReceived(HandshakeFailure) })" + ); + let rc = client_stream.write(b"hello"); + assert!(rc.is_err()); + assert_eq!( + format!("{:?}", rc), + "Err(Custom { kind: InvalidData, error: AlertReceived(HandshakeFailure) })" + ); +} + +#[test] +fn server_stream_handshake_error() { + let (client_config, server_config) = make_disjoint_suite_configs(); + let (mut client, mut server) = make_pair_for_configs(client_config, server_config); + + client + .writer() + .write_all(b"world") + .unwrap(); + + { + let mut pipe = OtherSession::new_fails(&mut client); + let mut server_stream = Stream::new(&mut server, &mut pipe); + let mut bytes = [0u8; 5]; + let rc = server_stream.read(&mut bytes); + assert!(rc.is_err()); + assert_eq!( + format!("{:?}", rc), + "Err(Custom { kind: InvalidData, error: PeerIncompatible(NoCipherSuitesInCommon) })" + ); + } +} + +#[test] +fn server_streamowned_handshake_error() { + let (client_config, server_config) = make_disjoint_suite_configs(); + let (mut client, server) = make_pair_for_configs(client_config, server_config); + + client + .writer() + .write_all(b"world") + .unwrap(); + + let pipe = OtherSession::new_fails(&mut client); + let mut server_stream = StreamOwned::new(server, pipe); + let mut bytes = [0u8; 5]; + let rc = server_stream.read(&mut bytes); + assert!(rc.is_err()); + assert_eq!( + format!("{:?}", rc), + "Err(Custom { kind: InvalidData, error: PeerIncompatible(NoCipherSuitesInCommon) })" + ); +} + +#[test] +fn server_config_is_clone() { + let _ = make_server_config(KeyType::Rsa); +} + +#[test] +fn client_config_is_clone() { + let _ = make_client_config(KeyType::Rsa); +} + +#[test] +fn client_connection_is_debug() { + let (client, _) = make_pair(KeyType::Rsa); + println!("{:?}", client); +} + +#[test] +fn server_connection_is_debug() { + let (_, server) = make_pair(KeyType::Rsa); + println!("{:?}", server); +} + +#[test] +fn server_complete_io_for_handshake_ending_with_alert() { + let (client_config, server_config) = make_disjoint_suite_configs(); + let (mut client, mut server) = make_pair_for_configs(client_config, server_config); + + assert!(server.is_handshaking()); + + let mut pipe = OtherSession::new_fails(&mut client); + let rc = server.complete_io(&mut pipe); + assert!(rc.is_err(), "server io failed due to handshake failure"); + assert!(!server.wants_write(), "but server did send its alert"); + assert_eq!( + format!("{:?}", pipe.last_error), + "Some(AlertReceived(HandshakeFailure))", + "which was received by client" + ); +} + +#[test] +fn server_exposes_offered_sni() { + let kt = KeyType::Rsa; + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(kt, &[version]); + let mut client = + ClientConnection::new(Arc::new(client_config), dns_name("second.testserver.com")) + .unwrap(); + let mut server = ServerConnection::new(Arc::new(make_server_config(kt))).unwrap(); + + assert_eq!(None, server.server_name()); + do_handshake(&mut client, &mut server); + assert_eq!(Some("second.testserver.com"), server.server_name()); + } +} + +#[test] +fn server_exposes_offered_sni_smashed_to_lowercase() { + // webpki actually does this for us in its DnsName type + let kt = KeyType::Rsa; + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(kt, &[version]); + let mut client = + ClientConnection::new(Arc::new(client_config), dns_name("SECOND.TESTServer.com")) + .unwrap(); + let mut server = ServerConnection::new(Arc::new(make_server_config(kt))).unwrap(); + + assert_eq!(None, server.server_name()); + do_handshake(&mut client, &mut server); + assert_eq!(Some("second.testserver.com"), server.server_name()); + } +} + +#[test] +fn server_exposes_offered_sni_even_if_resolver_fails() { + let kt = KeyType::Rsa; + let resolver = rustls::server::ResolvesServerCertUsingSni::new(); + + let mut server_config = make_server_config(kt); + server_config.cert_resolver = Arc::new(resolver); + let server_config = Arc::new(server_config); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(kt, &[version]); + let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); + let mut client = + ClientConnection::new(Arc::new(client_config), dns_name("thisdoesNOTexist.com")) + .unwrap(); + + assert_eq!(None, server.server_name()); + transfer(&mut client, &mut server); + assert_eq!( + server.process_new_packets(), + Err(Error::General( + "no server certificate chain resolved".to_string() + )) + ); + assert_eq!(Some("thisdoesnotexist.com"), server.server_name()); + } +} + +#[test] +fn sni_resolver_works() { + let kt = KeyType::Rsa; + let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); + let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); + let signing_key: Arc = Arc::new(signing_key); + resolver + .add( + "localhost", + sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()), + ) + .unwrap(); + + let mut server_config = make_server_config(kt); + server_config.cert_resolver = Arc::new(resolver); + let server_config = Arc::new(server_config); + + let mut server1 = ServerConnection::new(Arc::clone(&server_config)).unwrap(); + let mut client1 = + ClientConnection::new(Arc::new(make_client_config(kt)), dns_name("localhost")).unwrap(); + let err = do_handshake_until_error(&mut client1, &mut server1); + assert_eq!(err, Ok(())); + + let mut server2 = ServerConnection::new(Arc::clone(&server_config)).unwrap(); + let mut client2 = + ClientConnection::new(Arc::new(make_client_config(kt)), dns_name("notlocalhost")).unwrap(); + let err = do_handshake_until_error(&mut client2, &mut server2); + assert_eq!( + err, + Err(ErrorFromPeer::Server(Error::General( + "no server certificate chain resolved".into() + ))) + ); +} + +#[test] +fn sni_resolver_rejects_wrong_names() { + let kt = KeyType::Rsa; + let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); + let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); + let signing_key: Arc = Arc::new(signing_key); + + assert_eq!( + Ok(()), + resolver.add( + "localhost", + sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) + ) + ); + assert_eq!( + Err(Error::General( + "The server certificate is not valid for the given name".into() + )), + resolver.add( + "not-localhost", + sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) + ) + ); + assert_eq!( + Err(Error::General("Bad DNS name".into())), + resolver.add( + "not ascii 🦀", + sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) + ) + ); +} + +#[test] +fn sni_resolver_lower_cases_configured_names() { + let kt = KeyType::Rsa; + let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); + let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); + let signing_key: Arc = Arc::new(signing_key); + + assert_eq!( + Ok(()), + resolver.add( + "LOCALHOST", + sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) + ) + ); + + let mut server_config = make_server_config(kt); + server_config.cert_resolver = Arc::new(resolver); + let server_config = Arc::new(server_config); + + let mut server1 = ServerConnection::new(Arc::clone(&server_config)).unwrap(); + let mut client1 = + ClientConnection::new(Arc::new(make_client_config(kt)), dns_name("localhost")).unwrap(); + let err = do_handshake_until_error(&mut client1, &mut server1); + assert_eq!(err, Ok(())); +} + +#[test] +fn sni_resolver_lower_cases_queried_names() { + // actually, the handshake parser does this, but the effect is the same. + let kt = KeyType::Rsa; + let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); + let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); + let signing_key: Arc = Arc::new(signing_key); + + assert_eq!( + Ok(()), + resolver.add( + "localhost", + sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) + ) + ); + + let mut server_config = make_server_config(kt); + server_config.cert_resolver = Arc::new(resolver); + let server_config = Arc::new(server_config); + + let mut server1 = ServerConnection::new(Arc::clone(&server_config)).unwrap(); + let mut client1 = + ClientConnection::new(Arc::new(make_client_config(kt)), dns_name("LOCALHOST")).unwrap(); + let err = do_handshake_until_error(&mut client1, &mut server1); + assert_eq!(err, Ok(())); +} + +#[test] +fn sni_resolver_rejects_bad_certs() { + let kt = KeyType::Rsa; + let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); + let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); + let signing_key: Arc = Arc::new(signing_key); + + assert_eq!( + Err(Error::General( + "No end-entity certificate in certificate chain".into() + )), + resolver.add( + "localhost", + sign::CertifiedKey::new(vec![], signing_key.clone()) + ) + ); + + let bad_chain = vec![rustls::Certificate(vec![0xa0])]; + assert_eq!( + Err(Error::General( + "End-entity certificate in certificate chain is syntactically invalid".into() + )), + resolver.add( + "localhost", + sign::CertifiedKey::new(bad_chain, signing_key.clone()) + ) + ); +} + +fn do_exporter_test(client_config: ClientConfig, server_config: ServerConfig) { + let mut client_secret = [0u8; 64]; + let mut server_secret = [0u8; 64]; + + let (mut client, mut server) = make_pair_for_configs(client_config, server_config); + + assert_eq!( + Err(Error::HandshakeNotComplete), + client.export_keying_material(&mut client_secret, b"label", Some(b"context")) + ); + assert_eq!( + Err(Error::HandshakeNotComplete), + server.export_keying_material(&mut server_secret, b"label", Some(b"context")) + ); + do_handshake(&mut client, &mut server); + + assert!(client + .export_keying_material(&mut client_secret, b"label", Some(b"context")) + .is_ok()); + assert!(server + .export_keying_material(&mut server_secret, b"label", Some(b"context")) + .is_ok()); + assert_eq!(client_secret.to_vec(), server_secret.to_vec()); + + assert!(client + .export_keying_material(&mut client_secret, b"label", None) + .is_ok()); + assert_ne!(client_secret.to_vec(), server_secret.to_vec()); + assert!(server + .export_keying_material(&mut server_secret, b"label", None) + .is_ok()); + assert_eq!(client_secret.to_vec(), server_secret.to_vec()); +} + +#[cfg(feature = "tls12")] +#[test] +fn test_tls12_exporter() { + for kt in ALL_KEY_TYPES.iter() { + let client_config = make_client_config_with_versions(*kt, &[&rustls::version::TLS12]); + let server_config = make_server_config(*kt); + + do_exporter_test(client_config, server_config); + } +} + +#[test] +fn test_tls13_exporter() { + for kt in ALL_KEY_TYPES.iter() { + let client_config = make_client_config_with_versions(*kt, &[&rustls::version::TLS13]); + let server_config = make_server_config(*kt); + + do_exporter_test(client_config, server_config); + } +} + +fn do_suite_test( + client_config: ClientConfig, + server_config: ServerConfig, + expect_suite: SupportedCipherSuite, + expect_version: ProtocolVersion, +) { + println!( + "do_suite_test {:?} {:?}", + expect_version, + expect_suite.suite() + ); + let (mut client, mut server) = make_pair_for_configs(client_config, server_config); + + assert_eq!(None, client.negotiated_cipher_suite()); + assert_eq!(None, server.negotiated_cipher_suite()); + assert_eq!(None, client.protocol_version()); + assert_eq!(None, server.protocol_version()); + assert!(client.is_handshaking()); + assert!(server.is_handshaking()); + + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + + assert!(client.is_handshaking()); + assert!(server.is_handshaking()); + assert_eq!(None, client.protocol_version()); + assert_eq!(Some(expect_version), server.protocol_version()); + assert_eq!(None, client.negotiated_cipher_suite()); + assert_eq!(Some(expect_suite), server.negotiated_cipher_suite()); + + transfer(&mut server, &mut client); + client.process_new_packets().unwrap(); + + assert_eq!(Some(expect_suite), client.negotiated_cipher_suite()); + assert_eq!(Some(expect_suite), server.negotiated_cipher_suite()); + + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + transfer(&mut server, &mut client); + client.process_new_packets().unwrap(); + + assert!(!client.is_handshaking()); + assert!(!server.is_handshaking()); + assert_eq!(Some(expect_version), client.protocol_version()); + assert_eq!(Some(expect_version), server.protocol_version()); + assert_eq!(Some(expect_suite), client.negotiated_cipher_suite()); + assert_eq!(Some(expect_suite), server.negotiated_cipher_suite()); +} + +fn find_suite(suite: CipherSuite) -> SupportedCipherSuite { + for scs in ALL_CIPHER_SUITES.iter().copied() { + if scs.suite() == suite { + return scs; + } + } + + panic!("find_suite given unsupported suite"); +} + +static TEST_CIPHERSUITES: &[(&rustls::SupportedProtocolVersion, KeyType, CipherSuite)] = &[ + ( + &rustls::version::TLS13, + KeyType::Rsa, + CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, + ), + ( + &rustls::version::TLS13, + KeyType::Rsa, + CipherSuite::TLS13_AES_256_GCM_SHA384, + ), + ( + &rustls::version::TLS13, + KeyType::Rsa, + CipherSuite::TLS13_AES_128_GCM_SHA256, + ), + #[cfg(feature = "tls12")] + ( + &rustls::version::TLS12, + KeyType::Ecdsa, + CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + ), + #[cfg(feature = "tls12")] + ( + &rustls::version::TLS12, + KeyType::Rsa, + CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + ), + #[cfg(feature = "tls12")] + ( + &rustls::version::TLS12, + KeyType::Ecdsa, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + ), + #[cfg(feature = "tls12")] + ( + &rustls::version::TLS12, + KeyType::Ecdsa, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + ), + #[cfg(feature = "tls12")] + ( + &rustls::version::TLS12, + KeyType::Rsa, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + ), + #[cfg(feature = "tls12")] + ( + &rustls::version::TLS12, + KeyType::Rsa, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + ), +]; + +#[test] +fn negotiated_ciphersuite_default() { + for kt in ALL_KEY_TYPES.iter() { + do_suite_test( + make_client_config(*kt), + make_server_config(*kt), + find_suite(CipherSuite::TLS13_AES_256_GCM_SHA384), + ProtocolVersion::TLSv1_3, + ); + } +} + +#[test] +fn all_suites_covered() { + assert_eq!(ALL_CIPHER_SUITES.len(), TEST_CIPHERSUITES.len()); +} + +#[test] +fn negotiated_ciphersuite_client() { + for item in TEST_CIPHERSUITES.iter() { + let (version, kt, suite) = *item; + let scs = find_suite(suite); + let client_config = finish_client_config( + kt, + ClientConfig::builder() + .with_cipher_suites(&[scs]) + .with_safe_default_kx_groups() + .with_protocol_versions(&[version]) + .unwrap(), + ); + + do_suite_test(client_config, make_server_config(kt), scs, version.version); + } +} + +#[test] +fn negotiated_ciphersuite_server() { + for item in TEST_CIPHERSUITES.iter() { + let (version, kt, suite) = *item; + let scs = find_suite(suite); + let server_config = finish_server_config( + kt, + ServerConfig::builder() + .with_cipher_suites(&[scs]) + .with_safe_default_kx_groups() + .with_protocol_versions(&[version]) + .unwrap(), + ); + + do_suite_test(make_client_config(kt), server_config, scs, version.version); + } +} + +#[derive(Debug, PartialEq)] +struct KeyLogItem { + label: String, + client_random: Vec, + secret: Vec, +} + +struct KeyLogToVec { + label: &'static str, + items: Mutex>, +} + +impl KeyLogToVec { + fn new(who: &'static str) -> Self { + Self { + label: who, + items: Mutex::new(vec![]), + } + } + + fn take(&self) -> Vec { + std::mem::take(&mut self.items.lock().unwrap()) + } +} + +impl KeyLog for KeyLogToVec { + fn log(&self, label: &str, client: &[u8], secret: &[u8]) { + let value = KeyLogItem { + label: label.into(), + client_random: client.into(), + secret: secret.into(), + }; + + println!("key log {:?}: {:?}", self.label, value); + + self.items.lock().unwrap().push(value); + } +} + +#[cfg(feature = "tls12")] +#[test] +fn key_log_for_tls12() { + let client_key_log = Arc::new(KeyLogToVec::new("client")); + let server_key_log = Arc::new(KeyLogToVec::new("server")); + + let kt = KeyType::Rsa; + let mut client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS12]); + client_config.key_log = client_key_log.clone(); + let client_config = Arc::new(client_config); + + let mut server_config = make_server_config(kt); + server_config.key_log = server_key_log.clone(); + let server_config = Arc::new(server_config); + + // full handshake + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + do_handshake(&mut client, &mut server); + + let client_full_log = client_key_log.take(); + let server_full_log = server_key_log.take(); + assert_eq!(client_full_log, server_full_log); + assert_eq!(1, client_full_log.len()); + assert_eq!("CLIENT_RANDOM", client_full_log[0].label); + + // resumed + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + do_handshake(&mut client, &mut server); + + let client_resume_log = client_key_log.take(); + let server_resume_log = server_key_log.take(); + assert_eq!(client_resume_log, server_resume_log); + assert_eq!(1, client_resume_log.len()); + assert_eq!("CLIENT_RANDOM", client_resume_log[0].label); + assert_eq!(client_full_log[0].secret, client_resume_log[0].secret); +} + +#[test] +fn key_log_for_tls13() { + let client_key_log = Arc::new(KeyLogToVec::new("client")); + let server_key_log = Arc::new(KeyLogToVec::new("server")); + + let kt = KeyType::Rsa; + let mut client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); + client_config.key_log = client_key_log.clone(); + let client_config = Arc::new(client_config); + + let mut server_config = make_server_config(kt); + server_config.key_log = server_key_log.clone(); + let server_config = Arc::new(server_config); + + // full handshake + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + do_handshake(&mut client, &mut server); + + let client_full_log = client_key_log.take(); + let server_full_log = server_key_log.take(); + + assert_eq!(5, client_full_log.len()); + assert_eq!("CLIENT_HANDSHAKE_TRAFFIC_SECRET", client_full_log[0].label); + assert_eq!("SERVER_HANDSHAKE_TRAFFIC_SECRET", client_full_log[1].label); + assert_eq!("CLIENT_TRAFFIC_SECRET_0", client_full_log[2].label); + assert_eq!("SERVER_TRAFFIC_SECRET_0", client_full_log[3].label); + assert_eq!("EXPORTER_SECRET", client_full_log[4].label); + + assert_eq!(client_full_log[0], server_full_log[0]); + assert_eq!(client_full_log[1], server_full_log[1]); + assert_eq!(client_full_log[2], server_full_log[2]); + assert_eq!(client_full_log[3], server_full_log[3]); + assert_eq!(client_full_log[4], server_full_log[4]); + + // resumed + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + do_handshake(&mut client, &mut server); + + let client_resume_log = client_key_log.take(); + let server_resume_log = server_key_log.take(); + + assert_eq!(5, client_resume_log.len()); + assert_eq!( + "CLIENT_HANDSHAKE_TRAFFIC_SECRET", + client_resume_log[0].label + ); + assert_eq!( + "SERVER_HANDSHAKE_TRAFFIC_SECRET", + client_resume_log[1].label + ); + assert_eq!("CLIENT_TRAFFIC_SECRET_0", client_resume_log[2].label); + assert_eq!("SERVER_TRAFFIC_SECRET_0", client_resume_log[3].label); + assert_eq!("EXPORTER_SECRET", client_resume_log[4].label); + + assert_eq!(6, server_resume_log.len()); + assert_eq!("CLIENT_EARLY_TRAFFIC_SECRET", server_resume_log[0].label); + assert_eq!( + "CLIENT_HANDSHAKE_TRAFFIC_SECRET", + server_resume_log[1].label + ); + assert_eq!( + "SERVER_HANDSHAKE_TRAFFIC_SECRET", + server_resume_log[2].label + ); + assert_eq!("CLIENT_TRAFFIC_SECRET_0", server_resume_log[3].label); + assert_eq!("SERVER_TRAFFIC_SECRET_0", server_resume_log[4].label); + assert_eq!("EXPORTER_SECRET", server_resume_log[5].label); + + assert_eq!(client_resume_log[0], server_resume_log[1]); + assert_eq!(client_resume_log[1], server_resume_log[2]); + assert_eq!(client_resume_log[2], server_resume_log[3]); + assert_eq!(client_resume_log[3], server_resume_log[4]); + assert_eq!(client_resume_log[4], server_resume_log[5]); +} + +#[test] +fn vectored_write_for_server_appdata() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + do_handshake(&mut client, &mut server); + + server + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + server + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + { + let mut pipe = OtherSession::new(&mut client); + let wrlen = server.write_tls(&mut pipe).unwrap(); + assert_eq!(84, wrlen); + assert_eq!(pipe.writevs, vec![vec![42, 42]]); + } + check_read( + &mut client.reader(), + b"0123456789012345678901234567890123456789", + ); +} + +#[test] +fn vectored_write_for_client_appdata() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + do_handshake(&mut client, &mut server); + + client + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + client + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + { + let mut pipe = OtherSession::new(&mut server); + let wrlen = client.write_tls(&mut pipe).unwrap(); + assert_eq!(84, wrlen); + assert_eq!(pipe.writevs, vec![vec![42, 42]]); + } + check_read( + &mut server.reader(), + b"0123456789012345678901234567890123456789", + ); +} + +#[test] +fn vectored_write_for_server_handshake_with_half_rtt_data() { + let mut server_config = make_server_config(KeyType::Rsa); + server_config.send_half_rtt_data = true; + let (mut client, mut server) = + make_pair_for_configs(make_client_config_with_auth(KeyType::Rsa), server_config); + + server + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + server + .writer() + .write_all(b"0123456789") + .unwrap(); + + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + { + let mut pipe = OtherSession::new(&mut client); + let wrlen = server.write_tls(&mut pipe).unwrap(); + // don't assert exact sizes here, to avoid a brittle test + assert!(wrlen > 4000); // its pretty big (contains cert chain) + assert_eq!(pipe.writevs.len(), 1); // only one writev + assert_eq!(pipe.writevs[0].len(), 8); // at least a server hello/ccs/cert/serverkx/0.5rtt data + } + + client.process_new_packets().unwrap(); + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + { + let mut pipe = OtherSession::new(&mut client); + let wrlen = server.write_tls(&mut pipe).unwrap(); + // 4 tickets + assert_eq!(wrlen, 103 * 4); + assert_eq!(pipe.writevs, vec![vec![103, 103, 103, 103]]); + } + + assert!(!server.is_handshaking()); + assert!(!client.is_handshaking()); + check_read(&mut client.reader(), b"012345678901234567890123456789"); +} + +fn check_half_rtt_does_not_work(server_config: ServerConfig) { + let (mut client, mut server) = + make_pair_for_configs(make_client_config_with_auth(KeyType::Rsa), server_config); + + server + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + server + .writer() + .write_all(b"0123456789") + .unwrap(); + + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + { + let mut pipe = OtherSession::new(&mut client); + let wrlen = server.write_tls(&mut pipe).unwrap(); + // don't assert exact sizes here, to avoid a brittle test + assert!(wrlen > 4000); // its pretty big (contains cert chain) + assert_eq!(pipe.writevs.len(), 1); // only one writev + assert!(pipe.writevs[0].len() >= 6); // at least a server hello/ccs/cert/serverkx data + } + + // client second flight + client.process_new_packets().unwrap(); + transfer(&mut client, &mut server); + + // when client auth is enabled, we don't sent 0.5-rtt data, as we'd be sending + // it to an unauthenticated peer. so it happens here, in the server's second + // flight (42 and 32 are lengths of appdata sent above). + server.process_new_packets().unwrap(); + { + let mut pipe = OtherSession::new(&mut client); + let wrlen = server.write_tls(&mut pipe).unwrap(); + assert_eq!(wrlen, 486); + assert_eq!(pipe.writevs, vec![vec![103, 103, 103, 103, 42, 32]]); + } + + assert!(!server.is_handshaking()); + assert!(!client.is_handshaking()); + check_read(&mut client.reader(), b"012345678901234567890123456789"); +} + +#[test] +fn vectored_write_for_server_handshake_no_half_rtt_with_client_auth() { + let mut server_config = make_server_config_with_mandatory_client_auth(KeyType::Rsa); + server_config.send_half_rtt_data = true; // ask even though it will be ignored + check_half_rtt_does_not_work(server_config); +} + +#[test] +fn vectored_write_for_server_handshake_no_half_rtt_by_default() { + let server_config = make_server_config(KeyType::Rsa); + assert!(!server_config.send_half_rtt_data); + check_half_rtt_does_not_work(server_config); +} + +#[test] +fn vectored_write_for_client_handshake() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + + client + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + client + .writer() + .write_all(b"0123456789") + .unwrap(); + { + let mut pipe = OtherSession::new(&mut server); + let wrlen = client.write_tls(&mut pipe).unwrap(); + // don't assert exact sizes here, to avoid a brittle test + assert!(wrlen > 200); // just the client hello + assert_eq!(pipe.writevs.len(), 1); // only one writev + assert!(pipe.writevs[0].len() == 1); // only a client hello + } + + transfer(&mut server, &mut client); + client.process_new_packets().unwrap(); + + { + let mut pipe = OtherSession::new(&mut server); + let wrlen = client.write_tls(&mut pipe).unwrap(); + assert_eq!(wrlen, 154); + // CCS, finished, then two application datas + assert_eq!(pipe.writevs, vec![vec![6, 74, 42, 32]]); + } + + assert!(!server.is_handshaking()); + assert!(!client.is_handshaking()); + check_read(&mut server.reader(), b"012345678901234567890123456789"); +} + +#[test] +fn vectored_write_with_slow_client() { + let (mut client, mut server) = make_pair(KeyType::Rsa); + + client.set_buffer_limit(Some(32)); + + do_handshake(&mut client, &mut server); + server + .writer() + .write_all(b"01234567890123456789") + .unwrap(); + + { + let mut pipe = OtherSession::new(&mut client); + pipe.short_writes = true; + let wrlen = server.write_tls(&mut pipe).unwrap() + + server.write_tls(&mut pipe).unwrap() + + server.write_tls(&mut pipe).unwrap() + + server.write_tls(&mut pipe).unwrap() + + server.write_tls(&mut pipe).unwrap() + + server.write_tls(&mut pipe).unwrap(); + assert_eq!(42, wrlen); + assert_eq!( + pipe.writevs, + vec![vec![21], vec![10], vec![5], vec![3], vec![3]] + ); + } + check_read(&mut client.reader(), b"01234567890123456789"); +} + +struct ServerStorage { + storage: Arc, + put_count: AtomicUsize, + get_count: AtomicUsize, + take_count: AtomicUsize, +} + +impl ServerStorage { + fn new() -> Self { + Self { + storage: rustls::server::ServerSessionMemoryCache::new(1024), + put_count: AtomicUsize::new(0), + get_count: AtomicUsize::new(0), + take_count: AtomicUsize::new(0), + } + } + + fn puts(&self) -> usize { + self.put_count.load(Ordering::SeqCst) + } + fn gets(&self) -> usize { + self.get_count.load(Ordering::SeqCst) + } + fn takes(&self) -> usize { + self.take_count.load(Ordering::SeqCst) + } +} + +impl fmt::Debug for ServerStorage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "(put: {:?}, get: {:?}, take: {:?})", + self.put_count, self.get_count, self.take_count + ) + } +} + +impl rustls::server::StoresServerSessions for ServerStorage { + fn put(&self, key: Vec, value: Vec) -> bool { + self.put_count + .fetch_add(1, Ordering::SeqCst); + self.storage.put(key, value) + } + + fn get(&self, key: &[u8]) -> Option> { + self.get_count + .fetch_add(1, Ordering::SeqCst); + self.storage.get(key) + } + + fn take(&self, key: &[u8]) -> Option> { + self.take_count + .fetch_add(1, Ordering::SeqCst); + self.storage.take(key) + } + + fn can_cache(&self) -> bool { + true + } +} + +#[derive(Debug, Clone)] +enum ClientStorageOp { + SetKxHint(rustls::ServerName, rustls::NamedGroup), + GetKxHint(rustls::ServerName, Option), + SetTls12Session(rustls::ServerName), + GetTls12Session(rustls::ServerName, bool), + RemoveTls12Session(rustls::ServerName), + InsertTls13Ticket(rustls::ServerName), + TakeTls13Ticket(rustls::ServerName, bool), +} + +struct ClientStorage { + storage: Arc, + ops: Mutex>, +} + +impl ClientStorage { + fn new() -> Self { + Self { + storage: Arc::new(rustls::client::ClientSessionMemoryCache::new(1024)), + ops: Mutex::new(Vec::new()), + } + } + + #[cfg(feature = "tls12")] + fn ops(&self) -> Vec { + self.ops.lock().unwrap().clone() + } + + #[cfg(feature = "tls12")] + fn ops_and_reset(&self) -> Vec { + std::mem::take(&mut self.ops.lock().unwrap()) + } +} + +impl fmt::Debug for ClientStorage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(ops: {:?})", self.ops.lock().unwrap()) + } +} + +impl rustls::client::ClientSessionStore for ClientStorage { + fn set_kx_hint(&self, server_name: &rustls::ServerName, group: rustls::NamedGroup) { + self.ops + .lock() + .unwrap() + .push(ClientStorageOp::SetKxHint(server_name.clone(), group)); + self.storage + .set_kx_hint(server_name, group) + } + + fn kx_hint(&self, server_name: &rustls::ServerName) -> Option { + let rc = self.storage.kx_hint(server_name); + self.ops + .lock() + .unwrap() + .push(ClientStorageOp::GetKxHint(server_name.clone(), rc)); + rc + } + + fn set_tls12_session( + &self, + server_name: &rustls::ServerName, + value: rustls::client::Tls12ClientSessionValue, + ) { + self.ops + .lock() + .unwrap() + .push(ClientStorageOp::SetTls12Session(server_name.clone())); + self.storage + .set_tls12_session(server_name, value) + } + + fn tls12_session( + &self, + server_name: &rustls::ServerName, + ) -> Option { + let rc = self.storage.tls12_session(server_name); + self.ops + .lock() + .unwrap() + .push(ClientStorageOp::GetTls12Session( + server_name.clone(), + rc.is_some(), + )); + rc + } + + fn remove_tls12_session(&self, server_name: &rustls::ServerName) { + self.ops + .lock() + .unwrap() + .push(ClientStorageOp::RemoveTls12Session(server_name.clone())); + self.storage + .remove_tls12_session(server_name); + } + + fn insert_tls13_ticket( + &self, + server_name: &rustls::ServerName, + value: rustls::client::Tls13ClientSessionValue, + ) { + self.ops + .lock() + .unwrap() + .push(ClientStorageOp::InsertTls13Ticket(server_name.clone())); + self.storage + .insert_tls13_ticket(server_name, value); + } + + fn take_tls13_ticket( + &self, + server_name: &rustls::ServerName, + ) -> Option { + let rc = self + .storage + .take_tls13_ticket(server_name); + self.ops + .lock() + .unwrap() + .push(ClientStorageOp::TakeTls13Ticket( + server_name.clone(), + rc.is_some(), + )); + rc + } +} + +#[test] +fn tls13_stateful_resumption() { + let kt = KeyType::Rsa; + let client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); + let client_config = Arc::new(client_config); + + let mut server_config = make_server_config(kt); + let storage = Arc::new(ServerStorage::new()); + server_config.session_storage = storage.clone(); + let server_config = Arc::new(server_config); + + // full handshake + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + let (full_c2s, full_s2c) = do_handshake(&mut client, &mut server); + assert_eq!(storage.puts(), 4); + assert_eq!(storage.gets(), 0); + assert_eq!(storage.takes(), 0); + assert_eq!( + client + .peer_certificates() + .map(|certs| certs.len()), + Some(3) + ); + + // resumed + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + let (resume_c2s, resume_s2c) = do_handshake(&mut client, &mut server); + assert!(resume_c2s > full_c2s); + assert!(resume_s2c < full_s2c); + assert_eq!(storage.puts(), 8); + assert_eq!(storage.gets(), 0); + assert_eq!(storage.takes(), 1); + assert_eq!( + client + .peer_certificates() + .map(|certs| certs.len()), + Some(3) + ); + + // resumed again + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + let (resume2_c2s, resume2_s2c) = do_handshake(&mut client, &mut server); + assert_eq!(resume_s2c, resume2_s2c); + assert_eq!(resume_c2s, resume2_c2s); + assert_eq!(storage.puts(), 12); + assert_eq!(storage.gets(), 0); + assert_eq!(storage.takes(), 2); + assert_eq!( + client + .peer_certificates() + .map(|certs| certs.len()), + Some(3) + ); +} + +#[test] +fn tls13_stateless_resumption() { + let kt = KeyType::Rsa; + let client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); + let client_config = Arc::new(client_config); + + let mut server_config = make_server_config(kt); + server_config.ticketer = rustls::Ticketer::new().unwrap(); + let storage = Arc::new(ServerStorage::new()); + server_config.session_storage = storage.clone(); + let server_config = Arc::new(server_config); + + // full handshake + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + let (full_c2s, full_s2c) = do_handshake(&mut client, &mut server); + assert_eq!(storage.puts(), 0); + assert_eq!(storage.gets(), 0); + assert_eq!(storage.takes(), 0); + assert_eq!( + client + .peer_certificates() + .map(|certs| certs.len()), + Some(3) + ); + + // resumed + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + let (resume_c2s, resume_s2c) = do_handshake(&mut client, &mut server); + assert!(resume_c2s > full_c2s); + assert!(resume_s2c < full_s2c); + assert_eq!(storage.puts(), 0); + assert_eq!(storage.gets(), 0); + assert_eq!(storage.takes(), 0); + assert_eq!( + client + .peer_certificates() + .map(|certs| certs.len()), + Some(3) + ); + + // resumed again + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + let (resume2_c2s, resume2_s2c) = do_handshake(&mut client, &mut server); + assert_eq!(resume_s2c, resume2_s2c); + assert_eq!(resume_c2s, resume2_c2s); + assert_eq!(storage.puts(), 0); + assert_eq!(storage.gets(), 0); + assert_eq!(storage.takes(), 0); + assert_eq!( + client + .peer_certificates() + .map(|certs| certs.len()), + Some(3) + ); +} + +#[test] +fn early_data_not_available() { + let (mut client, _) = make_pair(KeyType::Rsa); + assert!(client.early_data().is_none()); +} + +fn early_data_configs() -> (Arc, Arc) { + let kt = KeyType::Rsa; + let mut client_config = make_client_config(kt); + client_config.enable_early_data = true; + client_config.resumption = Resumption::store(Arc::new(ClientStorage::new())); + + let mut server_config = make_server_config(kt); + server_config.max_early_data_size = 1234; + (Arc::new(client_config), Arc::new(server_config)) +} + +#[test] +fn early_data_is_available_on_resumption() { + let (client_config, server_config) = early_data_configs(); + + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + do_handshake(&mut client, &mut server); + + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + assert!(client.early_data().is_some()); + assert_eq!( + client + .early_data() + .unwrap() + .bytes_left(), + 1234 + ); + client + .early_data() + .unwrap() + .flush() + .unwrap(); + assert_eq!( + client + .early_data() + .unwrap() + .write(b"hello") + .unwrap(), + 5 + ); + do_handshake(&mut client, &mut server); + + let mut received_early_data = [0u8; 5]; + assert_eq!( + server + .early_data() + .expect("early_data didn't happen") + .read(&mut received_early_data) + .expect("early_data failed unexpectedly"), + 5 + ); + assert_eq!(&received_early_data[..], b"hello"); +} + +#[test] +fn early_data_not_available_on_server_before_client_hello() { + let mut server = ServerConnection::new(Arc::new(make_server_config(KeyType::Rsa))).unwrap(); + assert!(server.early_data().is_none()); +} + +#[test] +fn early_data_can_be_rejected_by_server() { + let (client_config, server_config) = early_data_configs(); + + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + do_handshake(&mut client, &mut server); + + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + assert!(client.early_data().is_some()); + assert_eq!( + client + .early_data() + .unwrap() + .bytes_left(), + 1234 + ); + client + .early_data() + .unwrap() + .flush() + .unwrap(); + assert_eq!( + client + .early_data() + .unwrap() + .write(b"hello") + .unwrap(), + 5 + ); + server.reject_early_data(); + do_handshake(&mut client, &mut server); + + assert!(!client.is_early_data_accepted()); +} + +#[cfg(feature = "quic")] +mod test_quic { + use super::*; + use rustls::quic::{self, ConnectionCommon}; + + // Returns the sender's next secrets to use, or the receiver's error. + fn step( + send: &mut ConnectionCommon, + recv: &mut ConnectionCommon, + ) -> Result, Error> { + let mut buf = Vec::new(); + let change = loop { + let prev = buf.len(); + if let Some(x) = send.write_hs(&mut buf) { + break Some(x); + } + if prev == buf.len() { + break None; + } + }; + if let Err(e) = recv.read_hs(&buf) { + return Err(e); + } else { + assert_eq!(recv.alert(), None); + } + + Ok(change) + } + + #[test] + fn test_quic_handshake() { + fn equal_packet_keys(x: &quic::PacketKey, y: &quic::PacketKey) -> bool { + // Check that these two sets of keys are equal. + let mut buf = vec![0; 32]; + let (header, payload_tag) = buf.split_at_mut(8); + let (payload, tag_buf) = payload_tag.split_at_mut(8); + let tag = x + .encrypt_in_place(42, &*header, payload) + .unwrap(); + tag_buf.copy_from_slice(tag.as_ref()); + + let result = y.decrypt_in_place(42, &*header, payload_tag); + match result { + Ok(payload) => payload == &[0; 8], + Err(_) => false, + } + } + + fn compatible_keys(x: &quic::KeyChange, y: &quic::KeyChange) -> bool { + fn keys(kc: &quic::KeyChange) -> &quic::Keys { + match kc { + quic::KeyChange::Handshake { keys } => keys, + quic::KeyChange::OneRtt { keys, .. } => keys, + } + } + + let (x, y) = (keys(x), keys(y)); + equal_packet_keys(&x.local.packet, &y.remote.packet) + && equal_packet_keys(&x.remote.packet, &y.local.packet) + } + + let kt = KeyType::Rsa; + let mut client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); + client_config.enable_early_data = true; + let client_config = Arc::new(client_config); + let mut server_config = make_server_config_with_versions(kt, &[&rustls::version::TLS13]); + server_config.max_early_data_size = 0xffffffff; + let server_config = Arc::new(server_config); + let client_params = &b"client params"[..]; + let server_params = &b"server params"[..]; + + // full handshake + let mut client = quic::ClientConnection::new( + Arc::clone(&client_config), + quic::Version::V1, + dns_name("localhost"), + client_params.into(), + ) + .unwrap(); + + let mut server = quic::ServerConnection::new( + Arc::clone(&server_config), + quic::Version::V1, + server_params.into(), + ) + .unwrap(); + + let client_initial = step(&mut client, &mut server).unwrap(); + assert!(client_initial.is_none()); + assert!(client.zero_rtt_keys().is_none()); + assert_eq!(server.quic_transport_parameters(), Some(client_params)); + let server_hs = step(&mut server, &mut client) + .unwrap() + .unwrap(); + assert!(server.zero_rtt_keys().is_none()); + let client_hs = step(&mut client, &mut server) + .unwrap() + .unwrap(); + assert!(compatible_keys(&server_hs, &client_hs)); + assert!(client.is_handshaking()); + let server_1rtt = step(&mut server, &mut client) + .unwrap() + .unwrap(); + assert!(!client.is_handshaking()); + assert_eq!(client.quic_transport_parameters(), Some(server_params)); + assert!(server.is_handshaking()); + let client_1rtt = step(&mut client, &mut server) + .unwrap() + .unwrap(); + assert!(!server.is_handshaking()); + assert!(compatible_keys(&server_1rtt, &client_1rtt)); + assert!(!compatible_keys(&server_hs, &server_1rtt)); + assert!(step(&mut client, &mut server) + .unwrap() + .is_none()); + assert!(step(&mut server, &mut client) + .unwrap() + .is_none()); + + // 0-RTT handshake + let mut client = quic::ClientConnection::new( + Arc::clone(&client_config), + quic::Version::V1, + dns_name("localhost"), + client_params.into(), + ) + .unwrap(); + assert!(client + .negotiated_cipher_suite() + .is_some()); + + let mut server = quic::ServerConnection::new( + Arc::clone(&server_config), + quic::Version::V1, + server_params.into(), + ) + .unwrap(); + + step(&mut client, &mut server).unwrap(); + assert_eq!(client.quic_transport_parameters(), Some(server_params)); + { + let client_early = client.zero_rtt_keys().unwrap(); + let server_early = server.zero_rtt_keys().unwrap(); + assert!(equal_packet_keys( + &client_early.packet, + &server_early.packet + )); + } + step(&mut server, &mut client) + .unwrap() + .unwrap(); + step(&mut client, &mut server) + .unwrap() + .unwrap(); + step(&mut server, &mut client) + .unwrap() + .unwrap(); + assert!(client.is_early_data_accepted()); + + // 0-RTT rejection + { + let client_config = (*client_config).clone(); + let mut client = quic::ClientConnection::new( + Arc::new(client_config), + quic::Version::V1, + dns_name("localhost"), + client_params.into(), + ) + .unwrap(); + + let mut server = quic::ServerConnection::new( + Arc::clone(&server_config), + quic::Version::V1, + server_params.into(), + ) + .unwrap(); + server.reject_early_data(); + + step(&mut client, &mut server).unwrap(); + assert_eq!(client.quic_transport_parameters(), Some(server_params)); + assert!(client.zero_rtt_keys().is_some()); + assert!(server.zero_rtt_keys().is_none()); + step(&mut server, &mut client) + .unwrap() + .unwrap(); + step(&mut client, &mut server) + .unwrap() + .unwrap(); + step(&mut server, &mut client) + .unwrap() + .unwrap(); + assert!(!client.is_early_data_accepted()); + } + + // failed handshake + let mut client = quic::ClientConnection::new( + client_config, + quic::Version::V1, + dns_name("example.com"), + client_params.into(), + ) + .unwrap(); + + let mut server = + quic::ServerConnection::new(server_config, quic::Version::V1, server_params.into()) + .unwrap(); + + step(&mut client, &mut server).unwrap(); + step(&mut server, &mut client) + .unwrap() + .unwrap(); + assert!(step(&mut server, &mut client).is_err()); + assert_eq!( + client.alert(), + Some(rustls::AlertDescription::BadCertificate) + ); + + // Key updates + + let (mut client_secrets, mut server_secrets) = match (client_1rtt, server_1rtt) { + (quic::KeyChange::OneRtt { next: c, .. }, quic::KeyChange::OneRtt { next: s, .. }) => { + (c, s) + } + _ => unreachable!(), + }; + + let mut client_next = client_secrets.next_packet_keys(); + let mut server_next = server_secrets.next_packet_keys(); + assert!(equal_packet_keys(&client_next.local, &server_next.remote)); + assert!(equal_packet_keys(&server_next.local, &client_next.remote)); + + client_next = client_secrets.next_packet_keys(); + server_next = server_secrets.next_packet_keys(); + assert!(equal_packet_keys(&client_next.local, &server_next.remote)); + assert!(equal_packet_keys(&server_next.local, &client_next.remote)); + } + + #[test] + fn test_quic_rejects_missing_alpn() { + let client_params = &b"client params"[..]; + let server_params = &b"server params"[..]; + + for &kt in ALL_KEY_TYPES.iter() { + let client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); + let client_config = Arc::new(client_config); + + let mut server_config = + make_server_config_with_versions(kt, &[&rustls::version::TLS13]); + server_config.alpn_protocols = vec!["foo".into()]; + let server_config = Arc::new(server_config); + + let mut client = quic::ClientConnection::new( + client_config, + quic::Version::V1, + dns_name("localhost"), + client_params.into(), + ) + .unwrap(); + let mut server = + quic::ServerConnection::new(server_config, quic::Version::V1, server_params.into()) + .unwrap(); + + assert_eq!( + step(&mut client, &mut server) + .err() + .unwrap(), + Error::NoApplicationProtocol + ); + + assert_eq!( + server.alert(), + Some(rustls::AlertDescription::NoApplicationProtocol) + ); + } + } + + #[cfg(feature = "tls12")] + #[test] + fn test_quic_no_tls13_error() { + let mut client_config = + make_client_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS12]); + client_config.alpn_protocols = vec!["foo".into()]; + let client_config = Arc::new(client_config); + + assert!(quic::ClientConnection::new( + client_config, + quic::Version::V1, + dns_name("localhost"), + b"client params".to_vec(), + ) + .is_err()); + + let mut server_config = + make_server_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS12]); + server_config.alpn_protocols = vec!["foo".into()]; + let server_config = Arc::new(server_config); + + assert!(quic::ServerConnection::new( + server_config, + quic::Version::V1, + b"server params".to_vec(), + ) + .is_err()); + } + + #[test] + fn test_quic_invalid_early_data_size() { + let mut server_config = + make_server_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS13]); + server_config.alpn_protocols = vec!["foo".into()]; + + let cases = [ + (None, true), + (Some(0u32), true), + (Some(5), false), + (Some(0xffff_ffff), true), + ]; + + for &(size, ok) in cases.iter() { + println!("early data size case: {:?}", size); + if let Some(new) = size { + server_config.max_early_data_size = new; + } + + let wrapped = Arc::new(server_config.clone()); + assert_eq!( + quic::ServerConnection::new(wrapped, quic::Version::V1, b"server params".to_vec(),) + .is_ok(), + ok + ); + } + } + + #[test] + fn test_quic_server_no_params_received() { + let server_config = + make_server_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS13]); + let server_config = Arc::new(server_config); + + let mut server = quic::ServerConnection::new( + server_config, + quic::Version::V1, + b"server params".to_vec(), + ) + .unwrap(); + + use ring::rand::SecureRandom; + use rustls::internal::msgs::base::PayloadU16; + use rustls::internal::msgs::enums::{Compression, NamedGroup}; + use rustls::internal::msgs::handshake::{ + ClientHelloPayload, HandshakeMessagePayload, KeyShareEntry, Random, SessionId, + }; + use rustls::{CipherSuite, HandshakeType, SignatureScheme}; + + let rng = ring::rand::SystemRandom::new(); + let mut random = [0; 32]; + rng.fill(&mut random).unwrap(); + let random = Random::from(random); + + let kx = ring::agreement::EphemeralPrivateKey::generate(&ring::agreement::X25519, &rng) + .unwrap() + .compute_public_key() + .unwrap(); + + let client_hello = MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::ClientHello, + payload: HandshakePayload::ClientHello(ClientHelloPayload { + client_version: ProtocolVersion::TLSv1_3, + random, + session_id: SessionId::random().unwrap(), + cipher_suites: vec![CipherSuite::TLS13_AES_128_GCM_SHA256], + compression_methods: vec![Compression::Null], + extensions: vec![ + ClientExtension::SupportedVersions(vec![ProtocolVersion::TLSv1_3]), + ClientExtension::NamedGroups(vec![NamedGroup::X25519]), + ClientExtension::SignatureAlgorithms(vec![SignatureScheme::ED25519]), + ClientExtension::KeyShare(vec![KeyShareEntry { + group: NamedGroup::X25519, + payload: PayloadU16::new(kx.as_ref().to_vec()), + }]), + ], + }), + }); + + let mut buf = Vec::with_capacity(512); + client_hello.encode(&mut buf); + assert_eq!( + server + .read_hs(&mut buf.as_slice()) + .err(), + Some(Error::PeerMisbehaved( + PeerMisbehaved::MissingQuicTransportParameters + )) + ); + } + + #[test] + fn test_quic_server_no_tls12() { + let mut server_config = + make_server_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS13]); + server_config.alpn_protocols = vec!["foo".into()]; + let server_config = Arc::new(server_config); + + use ring::rand::SecureRandom; + use rustls::internal::msgs::base::PayloadU16; + use rustls::internal::msgs::enums::{Compression, NamedGroup}; + use rustls::internal::msgs::handshake::{ + ClientHelloPayload, HandshakeMessagePayload, KeyShareEntry, Random, SessionId, + }; + use rustls::{CipherSuite, HandshakeType, SignatureScheme}; + + let rng = ring::rand::SystemRandom::new(); + let mut random = [0; 32]; + rng.fill(&mut random).unwrap(); + let random = Random::from(random); + + let kx = ring::agreement::EphemeralPrivateKey::generate(&ring::agreement::X25519, &rng) + .unwrap() + .compute_public_key() + .unwrap(); + + let mut server = quic::ServerConnection::new( + server_config, + quic::Version::V1, + b"server params".to_vec(), + ) + .unwrap(); + + let client_hello = MessagePayload::handshake(HandshakeMessagePayload { + typ: HandshakeType::ClientHello, + payload: HandshakePayload::ClientHello(ClientHelloPayload { + client_version: ProtocolVersion::TLSv1_2, + random: random.clone(), + session_id: SessionId::random().unwrap(), + cipher_suites: vec![CipherSuite::TLS13_AES_128_GCM_SHA256], + compression_methods: vec![Compression::Null], + extensions: vec![ + ClientExtension::NamedGroups(vec![NamedGroup::X25519]), + ClientExtension::SignatureAlgorithms(vec![SignatureScheme::ED25519]), + ClientExtension::KeyShare(vec![KeyShareEntry { + group: NamedGroup::X25519, + payload: PayloadU16::new(kx.as_ref().to_vec()), + }]), + ], + }), + }); + + let mut buf = Vec::with_capacity(512); + client_hello.encode(&mut buf); + assert_eq!( + server + .read_hs(&mut buf.as_slice()) + .err(), + Some(Error::PeerIncompatible( + PeerIncompatible::SupportedVersionsExtensionRequired + )), + ); + } + + #[test] + fn packet_key_api() { + use rustls::quic::{Keys, Version}; + use rustls::Side; + + // Test vectors: https://www.rfc-editor.org/rfc/rfc9001.html#name-client-initial + const CONNECTION_ID: &[u8] = &[0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08]; + const PACKET_NUMBER: u64 = 2; + const PLAIN_HEADER: &[u8] = &[ + 0xc3, 0x00, 0x00, 0x00, 0x01, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, + 0x00, 0x00, 0x44, 0x9e, 0x00, 0x00, 0x00, 0x02, + ]; + + const PAYLOAD: &[u8] = &[ + 0x06, 0x00, 0x40, 0xf1, 0x01, 0x00, 0x00, 0xed, 0x03, 0x03, 0xeb, 0xf8, 0xfa, 0x56, + 0xf1, 0x29, 0x39, 0xb9, 0x58, 0x4a, 0x38, 0x96, 0x47, 0x2e, 0xc4, 0x0b, 0xb8, 0x63, + 0xcf, 0xd3, 0xe8, 0x68, 0x04, 0xfe, 0x3a, 0x47, 0xf0, 0x6a, 0x2b, 0x69, 0x48, 0x4c, + 0x00, 0x00, 0x04, 0x13, 0x01, 0x13, 0x02, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x0e, 0x00, 0x00, 0x0b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, + 0x63, 0x6f, 0x6d, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, + 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x10, 0x00, 0x07, 0x00, 0x05, 0x04, 0x61, + 0x6c, 0x70, 0x6e, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, + 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x93, 0x70, 0xb2, 0xc9, 0xca, 0xa4, + 0x7f, 0xba, 0xba, 0xf4, 0x55, 0x9f, 0xed, 0xba, 0x75, 0x3d, 0xe1, 0x71, 0xfa, 0x71, + 0xf5, 0x0f, 0x1c, 0xe1, 0x5d, 0x43, 0xe9, 0x94, 0xec, 0x74, 0xd7, 0x48, 0x00, 0x2b, + 0x00, 0x03, 0x02, 0x03, 0x04, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x0e, 0x04, 0x03, 0x05, + 0x03, 0x06, 0x03, 0x02, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x00, 0x2d, 0x00, + 0x02, 0x01, 0x01, 0x00, 0x1c, 0x00, 0x02, 0x40, 0x01, 0x00, 0x39, 0x00, 0x32, 0x04, + 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x04, 0x80, 0x00, 0xff, + 0xff, 0x07, 0x04, 0x80, 0x00, 0xff, 0xff, 0x08, 0x01, 0x10, 0x01, 0x04, 0x80, 0x00, + 0x75, 0x30, 0x09, 0x01, 0x10, 0x0f, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, + 0x08, 0x06, 0x04, 0x80, 0x00, 0xff, 0xff, + ]; + + let client_keys = Keys::initial(Version::V1, &CONNECTION_ID, Side::Client); + assert_eq!( + client_keys + .local + .packet + .confidentiality_limit(), + 2u64.pow(23) + ); + assert_eq!( + client_keys + .local + .packet + .integrity_limit(), + 2u64.pow(52) + ); + assert_eq!(client_keys.local.packet.tag_len(), 16); + + let mut buf = Vec::new(); + buf.extend(PLAIN_HEADER); + buf.extend(PAYLOAD); + let header_len = PLAIN_HEADER.len(); + let tag_len = client_keys.local.packet.tag_len(); + let padding_len = 1200 - header_len - PAYLOAD.len() - tag_len; + buf.extend(std::iter::repeat(0).take(padding_len)); + let (header, payload) = buf.split_at_mut(header_len); + let tag = client_keys + .local + .packet + .encrypt_in_place(PACKET_NUMBER, &*header, payload) + .unwrap(); + + let sample_len = client_keys.local.header.sample_len(); + let sample = &payload[..sample_len]; + let (first, rest) = header.split_at_mut(1); + client_keys + .local + .header + .encrypt_in_place(sample, &mut first[0], &mut rest[17..21]) + .unwrap(); + buf.extend_from_slice(tag.as_ref()); + + const PROTECTED: &[u8] = &[ + 0xc0, 0x00, 0x00, 0x00, 0x01, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, + 0x00, 0x00, 0x44, 0x9e, 0x7b, 0x9a, 0xec, 0x34, 0xd1, 0xb1, 0xc9, 0x8d, 0xd7, 0x68, + 0x9f, 0xb8, 0xec, 0x11, 0xd2, 0x42, 0xb1, 0x23, 0xdc, 0x9b, 0xd8, 0xba, 0xb9, 0x36, + 0xb4, 0x7d, 0x92, 0xec, 0x35, 0x6c, 0x0b, 0xab, 0x7d, 0xf5, 0x97, 0x6d, 0x27, 0xcd, + 0x44, 0x9f, 0x63, 0x30, 0x00, 0x99, 0xf3, 0x99, 0x1c, 0x26, 0x0e, 0xc4, 0xc6, 0x0d, + 0x17, 0xb3, 0x1f, 0x84, 0x29, 0x15, 0x7b, 0xb3, 0x5a, 0x12, 0x82, 0xa6, 0x43, 0xa8, + 0xd2, 0x26, 0x2c, 0xad, 0x67, 0x50, 0x0c, 0xad, 0xb8, 0xe7, 0x37, 0x8c, 0x8e, 0xb7, + 0x53, 0x9e, 0xc4, 0xd4, 0x90, 0x5f, 0xed, 0x1b, 0xee, 0x1f, 0xc8, 0xaa, 0xfb, 0xa1, + 0x7c, 0x75, 0x0e, 0x2c, 0x7a, 0xce, 0x01, 0xe6, 0x00, 0x5f, 0x80, 0xfc, 0xb7, 0xdf, + 0x62, 0x12, 0x30, 0xc8, 0x37, 0x11, 0xb3, 0x93, 0x43, 0xfa, 0x02, 0x8c, 0xea, 0x7f, + 0x7f, 0xb5, 0xff, 0x89, 0xea, 0xc2, 0x30, 0x82, 0x49, 0xa0, 0x22, 0x52, 0x15, 0x5e, + 0x23, 0x47, 0xb6, 0x3d, 0x58, 0xc5, 0x45, 0x7a, 0xfd, 0x84, 0xd0, 0x5d, 0xff, 0xfd, + 0xb2, 0x03, 0x92, 0x84, 0x4a, 0xe8, 0x12, 0x15, 0x46, 0x82, 0xe9, 0xcf, 0x01, 0x2f, + 0x90, 0x21, 0xa6, 0xf0, 0xbe, 0x17, 0xdd, 0xd0, 0xc2, 0x08, 0x4d, 0xce, 0x25, 0xff, + 0x9b, 0x06, 0xcd, 0xe5, 0x35, 0xd0, 0xf9, 0x20, 0xa2, 0xdb, 0x1b, 0xf3, 0x62, 0xc2, + 0x3e, 0x59, 0x6d, 0x11, 0xa4, 0xf5, 0xa6, 0xcf, 0x39, 0x48, 0x83, 0x8a, 0x3a, 0xec, + 0x4e, 0x15, 0xda, 0xf8, 0x50, 0x0a, 0x6e, 0xf6, 0x9e, 0xc4, 0xe3, 0xfe, 0xb6, 0xb1, + 0xd9, 0x8e, 0x61, 0x0a, 0xc8, 0xb7, 0xec, 0x3f, 0xaf, 0x6a, 0xd7, 0x60, 0xb7, 0xba, + 0xd1, 0xdb, 0x4b, 0xa3, 0x48, 0x5e, 0x8a, 0x94, 0xdc, 0x25, 0x0a, 0xe3, 0xfd, 0xb4, + 0x1e, 0xd1, 0x5f, 0xb6, 0xa8, 0xe5, 0xeb, 0xa0, 0xfc, 0x3d, 0xd6, 0x0b, 0xc8, 0xe3, + 0x0c, 0x5c, 0x42, 0x87, 0xe5, 0x38, 0x05, 0xdb, 0x05, 0x9a, 0xe0, 0x64, 0x8d, 0xb2, + 0xf6, 0x42, 0x64, 0xed, 0x5e, 0x39, 0xbe, 0x2e, 0x20, 0xd8, 0x2d, 0xf5, 0x66, 0xda, + 0x8d, 0xd5, 0x99, 0x8c, 0xca, 0xbd, 0xae, 0x05, 0x30, 0x60, 0xae, 0x6c, 0x7b, 0x43, + 0x78, 0xe8, 0x46, 0xd2, 0x9f, 0x37, 0xed, 0x7b, 0x4e, 0xa9, 0xec, 0x5d, 0x82, 0xe7, + 0x96, 0x1b, 0x7f, 0x25, 0xa9, 0x32, 0x38, 0x51, 0xf6, 0x81, 0xd5, 0x82, 0x36, 0x3a, + 0xa5, 0xf8, 0x99, 0x37, 0xf5, 0xa6, 0x72, 0x58, 0xbf, 0x63, 0xad, 0x6f, 0x1a, 0x0b, + 0x1d, 0x96, 0xdb, 0xd4, 0xfa, 0xdd, 0xfc, 0xef, 0xc5, 0x26, 0x6b, 0xa6, 0x61, 0x17, + 0x22, 0x39, 0x5c, 0x90, 0x65, 0x56, 0xbe, 0x52, 0xaf, 0xe3, 0xf5, 0x65, 0x63, 0x6a, + 0xd1, 0xb1, 0x7d, 0x50, 0x8b, 0x73, 0xd8, 0x74, 0x3e, 0xeb, 0x52, 0x4b, 0xe2, 0x2b, + 0x3d, 0xcb, 0xc2, 0xc7, 0x46, 0x8d, 0x54, 0x11, 0x9c, 0x74, 0x68, 0x44, 0x9a, 0x13, + 0xd8, 0xe3, 0xb9, 0x58, 0x11, 0xa1, 0x98, 0xf3, 0x49, 0x1d, 0xe3, 0xe7, 0xfe, 0x94, + 0x2b, 0x33, 0x04, 0x07, 0xab, 0xf8, 0x2a, 0x4e, 0xd7, 0xc1, 0xb3, 0x11, 0x66, 0x3a, + 0xc6, 0x98, 0x90, 0xf4, 0x15, 0x70, 0x15, 0x85, 0x3d, 0x91, 0xe9, 0x23, 0x03, 0x7c, + 0x22, 0x7a, 0x33, 0xcd, 0xd5, 0xec, 0x28, 0x1c, 0xa3, 0xf7, 0x9c, 0x44, 0x54, 0x6b, + 0x9d, 0x90, 0xca, 0x00, 0xf0, 0x64, 0xc9, 0x9e, 0x3d, 0xd9, 0x79, 0x11, 0xd3, 0x9f, + 0xe9, 0xc5, 0xd0, 0xb2, 0x3a, 0x22, 0x9a, 0x23, 0x4c, 0xb3, 0x61, 0x86, 0xc4, 0x81, + 0x9e, 0x8b, 0x9c, 0x59, 0x27, 0x72, 0x66, 0x32, 0x29, 0x1d, 0x6a, 0x41, 0x82, 0x11, + 0xcc, 0x29, 0x62, 0xe2, 0x0f, 0xe4, 0x7f, 0xeb, 0x3e, 0xdf, 0x33, 0x0f, 0x2c, 0x60, + 0x3a, 0x9d, 0x48, 0xc0, 0xfc, 0xb5, 0x69, 0x9d, 0xbf, 0xe5, 0x89, 0x64, 0x25, 0xc5, + 0xba, 0xc4, 0xae, 0xe8, 0x2e, 0x57, 0xa8, 0x5a, 0xaf, 0x4e, 0x25, 0x13, 0xe4, 0xf0, + 0x57, 0x96, 0xb0, 0x7b, 0xa2, 0xee, 0x47, 0xd8, 0x05, 0x06, 0xf8, 0xd2, 0xc2, 0x5e, + 0x50, 0xfd, 0x14, 0xde, 0x71, 0xe6, 0xc4, 0x18, 0x55, 0x93, 0x02, 0xf9, 0x39, 0xb0, + 0xe1, 0xab, 0xd5, 0x76, 0xf2, 0x79, 0xc4, 0xb2, 0xe0, 0xfe, 0xb8, 0x5c, 0x1f, 0x28, + 0xff, 0x18, 0xf5, 0x88, 0x91, 0xff, 0xef, 0x13, 0x2e, 0xef, 0x2f, 0xa0, 0x93, 0x46, + 0xae, 0xe3, 0x3c, 0x28, 0xeb, 0x13, 0x0f, 0xf2, 0x8f, 0x5b, 0x76, 0x69, 0x53, 0x33, + 0x41, 0x13, 0x21, 0x19, 0x96, 0xd2, 0x00, 0x11, 0xa1, 0x98, 0xe3, 0xfc, 0x43, 0x3f, + 0x9f, 0x25, 0x41, 0x01, 0x0a, 0xe1, 0x7c, 0x1b, 0xf2, 0x02, 0x58, 0x0f, 0x60, 0x47, + 0x47, 0x2f, 0xb3, 0x68, 0x57, 0xfe, 0x84, 0x3b, 0x19, 0xf5, 0x98, 0x40, 0x09, 0xdd, + 0xc3, 0x24, 0x04, 0x4e, 0x84, 0x7a, 0x4f, 0x4a, 0x0a, 0xb3, 0x4f, 0x71, 0x95, 0x95, + 0xde, 0x37, 0x25, 0x2d, 0x62, 0x35, 0x36, 0x5e, 0x9b, 0x84, 0x39, 0x2b, 0x06, 0x10, + 0x85, 0x34, 0x9d, 0x73, 0x20, 0x3a, 0x4a, 0x13, 0xe9, 0x6f, 0x54, 0x32, 0xec, 0x0f, + 0xd4, 0xa1, 0xee, 0x65, 0xac, 0xcd, 0xd5, 0xe3, 0x90, 0x4d, 0xf5, 0x4c, 0x1d, 0xa5, + 0x10, 0xb0, 0xff, 0x20, 0xdc, 0xc0, 0xc7, 0x7f, 0xcb, 0x2c, 0x0e, 0x0e, 0xb6, 0x05, + 0xcb, 0x05, 0x04, 0xdb, 0x87, 0x63, 0x2c, 0xf3, 0xd8, 0xb4, 0xda, 0xe6, 0xe7, 0x05, + 0x76, 0x9d, 0x1d, 0xe3, 0x54, 0x27, 0x01, 0x23, 0xcb, 0x11, 0x45, 0x0e, 0xfc, 0x60, + 0xac, 0x47, 0x68, 0x3d, 0x7b, 0x8d, 0x0f, 0x81, 0x13, 0x65, 0x56, 0x5f, 0xd9, 0x8c, + 0x4c, 0x8e, 0xb9, 0x36, 0xbc, 0xab, 0x8d, 0x06, 0x9f, 0xc3, 0x3b, 0xd8, 0x01, 0xb0, + 0x3a, 0xde, 0xa2, 0xe1, 0xfb, 0xc5, 0xaa, 0x46, 0x3d, 0x08, 0xca, 0x19, 0x89, 0x6d, + 0x2b, 0xf5, 0x9a, 0x07, 0x1b, 0x85, 0x1e, 0x6c, 0x23, 0x90, 0x52, 0x17, 0x2f, 0x29, + 0x6b, 0xfb, 0x5e, 0x72, 0x40, 0x47, 0x90, 0xa2, 0x18, 0x10, 0x14, 0xf3, 0xb9, 0x4a, + 0x4e, 0x97, 0xd1, 0x17, 0xb4, 0x38, 0x13, 0x03, 0x68, 0xcc, 0x39, 0xdb, 0xb2, 0xd1, + 0x98, 0x06, 0x5a, 0xe3, 0x98, 0x65, 0x47, 0x92, 0x6c, 0xd2, 0x16, 0x2f, 0x40, 0xa2, + 0x9f, 0x0c, 0x3c, 0x87, 0x45, 0xc0, 0xf5, 0x0f, 0xba, 0x38, 0x52, 0xe5, 0x66, 0xd4, + 0x45, 0x75, 0xc2, 0x9d, 0x39, 0xa0, 0x3f, 0x0c, 0xda, 0x72, 0x19, 0x84, 0xb6, 0xf4, + 0x40, 0x59, 0x1f, 0x35, 0x5e, 0x12, 0xd4, 0x39, 0xff, 0x15, 0x0a, 0xab, 0x76, 0x13, + 0x49, 0x9d, 0xbd, 0x49, 0xad, 0xab, 0xc8, 0x67, 0x6e, 0xef, 0x02, 0x3b, 0x15, 0xb6, + 0x5b, 0xfc, 0x5c, 0xa0, 0x69, 0x48, 0x10, 0x9f, 0x23, 0xf3, 0x50, 0xdb, 0x82, 0x12, + 0x35, 0x35, 0xeb, 0x8a, 0x74, 0x33, 0xbd, 0xab, 0xcb, 0x90, 0x92, 0x71, 0xa6, 0xec, + 0xbc, 0xb5, 0x8b, 0x93, 0x6a, 0x88, 0xcd, 0x4e, 0x8f, 0x2e, 0x6f, 0xf5, 0x80, 0x01, + 0x75, 0xf1, 0x13, 0x25, 0x3d, 0x8f, 0xa9, 0xca, 0x88, 0x85, 0xc2, 0xf5, 0x52, 0xe6, + 0x57, 0xdc, 0x60, 0x3f, 0x25, 0x2e, 0x1a, 0x8e, 0x30, 0x8f, 0x76, 0xf0, 0xbe, 0x79, + 0xe2, 0xfb, 0x8f, 0x5d, 0x5f, 0xbb, 0xe2, 0xe3, 0x0e, 0xca, 0xdd, 0x22, 0x07, 0x23, + 0xc8, 0xc0, 0xae, 0xa8, 0x07, 0x8c, 0xdf, 0xcb, 0x38, 0x68, 0x26, 0x3f, 0xf8, 0xf0, + 0x94, 0x00, 0x54, 0xda, 0x48, 0x78, 0x18, 0x93, 0xa7, 0xe4, 0x9a, 0xd5, 0xaf, 0xf4, + 0xaf, 0x30, 0x0c, 0xd8, 0x04, 0xa6, 0xb6, 0x27, 0x9a, 0xb3, 0xff, 0x3a, 0xfb, 0x64, + 0x49, 0x1c, 0x85, 0x19, 0x4a, 0xab, 0x76, 0x0d, 0x58, 0xa6, 0x06, 0x65, 0x4f, 0x9f, + 0x44, 0x00, 0xe8, 0xb3, 0x85, 0x91, 0x35, 0x6f, 0xbf, 0x64, 0x25, 0xac, 0xa2, 0x6d, + 0xc8, 0x52, 0x44, 0x25, 0x9f, 0xf2, 0xb1, 0x9c, 0x41, 0xb9, 0xf9, 0x6f, 0x3c, 0xa9, + 0xec, 0x1d, 0xde, 0x43, 0x4d, 0xa7, 0xd2, 0xd3, 0x92, 0xb9, 0x05, 0xdd, 0xf3, 0xd1, + 0xf9, 0xaf, 0x93, 0xd1, 0xaf, 0x59, 0x50, 0xbd, 0x49, 0x3f, 0x5a, 0xa7, 0x31, 0xb4, + 0x05, 0x6d, 0xf3, 0x1b, 0xd2, 0x67, 0xb6, 0xb9, 0x0a, 0x07, 0x98, 0x31, 0xaa, 0xf5, + 0x79, 0xbe, 0x0a, 0x39, 0x01, 0x31, 0x37, 0xaa, 0xc6, 0xd4, 0x04, 0xf5, 0x18, 0xcf, + 0xd4, 0x68, 0x40, 0x64, 0x7e, 0x78, 0xbf, 0xe7, 0x06, 0xca, 0x4c, 0xf5, 0xe9, 0xc5, + 0x45, 0x3e, 0x9f, 0x7c, 0xfd, 0x2b, 0x8b, 0x4c, 0x8d, 0x16, 0x9a, 0x44, 0xe5, 0x5c, + 0x88, 0xd4, 0xa9, 0xa7, 0xf9, 0x47, 0x42, 0x41, 0xe2, 0x21, 0xaf, 0x44, 0x86, 0x00, + 0x18, 0xab, 0x08, 0x56, 0x97, 0x2e, 0x19, 0x4c, 0xd9, 0x34, + ]; + + assert_eq!(&buf, PROTECTED); + + let (header, payload) = buf.split_at_mut(header_len); + let (first, rest) = header.split_at_mut(1); + let sample = &payload[..sample_len]; + + let server_keys = Keys::initial(Version::V1, &CONNECTION_ID, Side::Server); + server_keys + .remote + .header + .decrypt_in_place(sample, &mut first[0], &mut rest[17..21]) + .unwrap(); + let payload = server_keys + .remote + .packet + .decrypt_in_place(PACKET_NUMBER, &*header, payload) + .unwrap(); + + assert_eq!(&payload[..PAYLOAD.len()], PAYLOAD); + assert_eq!(payload.len(), buf.len() - header_len - tag_len); + } + + #[test] + fn test_quic_exporter() { + for &kt in ALL_KEY_TYPES.iter() { + let client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); + let server_config = make_server_config_with_versions(kt, &[&rustls::version::TLS13]); + + do_exporter_test(client_config, server_config); + } + } +} // mod test_quic + +#[test] +fn test_client_does_not_offer_sha1() { + use rustls::internal::msgs::{ + codec::Reader, handshake::HandshakePayload, message::MessagePayload, message::OpaqueMessage, + }; + use rustls::HandshakeType; + + for kt in ALL_KEY_TYPES.iter() { + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(*kt, &[version]); + let (mut client, _) = make_pair_for_configs(client_config, make_server_config(*kt)); + + assert!(client.wants_write()); + let mut buf = [0u8; 262144]; + let sz = client + .write_tls(&mut buf.as_mut()) + .unwrap(); + let msg = OpaqueMessage::read(&mut Reader::init(&buf[..sz])).unwrap(); + let msg = Message::try_from(msg.into_plain_message()).unwrap(); + assert!(msg.is_handshake_type(HandshakeType::ClientHello)); + + let client_hello = match msg.payload { + MessagePayload::Handshake { parsed, .. } => match parsed.payload { + HandshakePayload::ClientHello(ch) => ch, + _ => unreachable!(), + }, + _ => unreachable!(), + }; + + let sigalgs = client_hello + .get_sigalgs_extension() + .unwrap(); + assert!( + !sigalgs.contains(&SignatureScheme::RSA_PKCS1_SHA1), + "sha1 unexpectedly offered" + ); + } + } +} + +#[test] +fn test_client_config_keyshare() { + let client_config = + make_client_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::SECP384R1]); + let server_config = + make_server_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::SECP384R1]); + let (mut client, mut server) = make_pair_for_configs(client_config, server_config); + do_handshake_until_error(&mut client, &mut server).unwrap(); +} + +#[test] +fn test_client_config_keyshare_mismatch() { + let client_config = + make_client_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::SECP384R1]); + let server_config = + make_server_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::X25519]); + let (mut client, mut server) = make_pair_for_configs(client_config, server_config); + assert!(do_handshake_until_error(&mut client, &mut server).is_err()); +} + +#[cfg(feature = "tls12")] +#[test] +fn test_client_sends_helloretryrequest() { + // client sends a secp384r1 key share + let mut client_config = make_client_config_with_kx_groups( + KeyType::Rsa, + &[&rustls::kx_group::SECP384R1, &rustls::kx_group::X25519], + ); + + let storage = Arc::new(ClientStorage::new()); + client_config.resumption = Resumption::store(storage.clone()); + + // but server only accepts x25519, so a HRR is required + let server_config = + make_server_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::X25519]); + + let (mut client, mut server) = make_pair_for_configs(client_config, server_config); + + // client sends hello + { + let mut pipe = OtherSession::new(&mut server); + let wrlen = client.write_tls(&mut pipe).unwrap(); + assert!(wrlen > 200); + assert_eq!(pipe.writevs.len(), 1); + assert!(pipe.writevs[0].len() == 1); + } + + // server sends HRR + { + let mut pipe = OtherSession::new(&mut client); + let wrlen = server.write_tls(&mut pipe).unwrap(); + assert!(wrlen < 100); // just the hello retry request + assert_eq!(pipe.writevs.len(), 1); // only one writev + assert!(pipe.writevs[0].len() == 2); // hello retry request and CCS + } + + // client sends fixed hello + { + let mut pipe = OtherSession::new(&mut server); + let wrlen = client.write_tls(&mut pipe).unwrap(); + assert!(wrlen > 200); // just the client hello retry + assert_eq!(pipe.writevs.len(), 1); // only one writev + assert!(pipe.writevs[0].len() == 2); // only a CCS & client hello retry + } + + // server completes handshake + { + let mut pipe = OtherSession::new(&mut client); + let wrlen = server.write_tls(&mut pipe).unwrap(); + assert!(wrlen > 200); + assert_eq!(pipe.writevs.len(), 1); + assert!(pipe.writevs[0].len() == 5); // server hello / encrypted exts / cert / cert-verify / finished + } + + do_handshake_until_error(&mut client, &mut server).unwrap(); + + // client only did following storage queries: + println!("storage {:#?}", storage.ops()); + assert_eq!(storage.ops().len(), 9); + assert!(matches!( + storage.ops()[0], + ClientStorageOp::TakeTls13Ticket(_, false) + )); + assert!(matches!( + storage.ops()[1], + ClientStorageOp::GetTls12Session(_, false) + )); + assert!(matches!( + storage.ops()[2], + ClientStorageOp::GetKxHint(_, None) + )); + assert!(matches!( + storage.ops()[3], + ClientStorageOp::SetKxHint(_, rustls::NamedGroup::X25519) + )); + assert!(matches!( + storage.ops()[4], + ClientStorageOp::RemoveTls12Session(_) + )); + // server sends 4 tickets by default + assert!(matches!( + storage.ops()[5], + ClientStorageOp::InsertTls13Ticket(_) + )); + assert!(matches!( + storage.ops()[6], + ClientStorageOp::InsertTls13Ticket(_) + )); + assert!(matches!( + storage.ops()[7], + ClientStorageOp::InsertTls13Ticket(_) + )); + assert!(matches!( + storage.ops()[8], + ClientStorageOp::InsertTls13Ticket(_) + )); +} + +#[test] +fn test_client_rejects_hrr_with_varied_session_id() { + use rustls::internal::msgs::handshake::SessionId; + let different_session_id = SessionId::random().unwrap(); + + let assert_client_sends_hello_with_secp384 = |msg: &mut Message| -> Altered { + if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload { + if let HandshakePayload::ClientHello(ch) = &mut parsed.payload { + let keyshares = ch + .get_keyshare_extension() + .expect("missing key share extension"); + assert_eq!(keyshares.len(), 1); + assert_eq!(keyshares[0].group, rustls::NamedGroup::secp384r1); + + ch.session_id = different_session_id; + *encoded = Payload::new(parsed.get_encoding()); + } + } + Altered::InPlace + }; + + let assert_server_requests_retry_and_echoes_session_id = |msg: &mut Message| -> Altered { + if let MessagePayload::Handshake { parsed, .. } = &mut msg.payload { + if let HandshakePayload::HelloRetryRequest(hrr) = &mut parsed.payload { + let group = hrr.get_requested_key_share_group(); + assert_eq!(group, Some(rustls::NamedGroup::X25519)); + + assert_eq!(hrr.session_id, different_session_id); + } + } + Altered::InPlace + }; + + // client prefers a secp384r1 key share, server only accepts x25519 + let client_config = make_client_config_with_kx_groups( + KeyType::Rsa, + &[&rustls::kx_group::SECP384R1, &rustls::kx_group::X25519], + ); + + let server_config = + make_server_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::X25519]); + + let (client, server) = make_pair_for_configs(client_config, server_config); + let (mut client, mut server) = (client.into(), server.into()); + transfer_altered( + &mut client, + assert_client_sends_hello_with_secp384, + &mut server, + ); + server.process_new_packets().unwrap(); + transfer_altered( + &mut server, + assert_server_requests_retry_and_echoes_session_id, + &mut client, + ); + assert_eq!( + client.process_new_packets(), + Err(Error::PeerMisbehaved( + PeerMisbehaved::IllegalHelloRetryRequestWithWrongSessionId + )) + ); +} + +#[cfg(feature = "tls12")] +#[test] +fn test_client_attempts_to_use_unsupported_kx_group() { + // common to both client configs + let shared_storage = Arc::new(ClientStorage::new()); + + // first, client sends a x25519 and server agrees. x25519 is inserted + // into kx group cache. + let mut client_config_1 = + make_client_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::X25519]); + client_config_1.resumption = Resumption::store(shared_storage.clone()); + + // second, client only supports secp-384 and so kx group cache + // contains an unusable value. + let mut client_config_2 = + make_client_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::SECP384R1]); + client_config_2.resumption = Resumption::store(shared_storage.clone()); + + let server_config = make_server_config(KeyType::Rsa); + + // first handshake + let (mut client_1, mut server) = make_pair_for_configs(client_config_1, server_config.clone()); + do_handshake_until_error(&mut client_1, &mut server).unwrap(); + + let ops = shared_storage.ops(); + println!("storage {:#?}", ops); + assert_eq!(ops.len(), 9); + assert!(matches!( + ops[3], + ClientStorageOp::SetKxHint(_, rustls::NamedGroup::X25519) + )); + + // second handshake + let (mut client_2, mut server) = make_pair_for_configs(client_config_2, server_config); + do_handshake_until_error(&mut client_2, &mut server).unwrap(); + + let ops = shared_storage.ops(); + println!("storage {:?} {:#?}", ops.len(), ops); + assert_eq!(ops.len(), 17); + assert!(matches!(ops[9], ClientStorageOp::TakeTls13Ticket(_, true))); + assert!(matches!( + ops[10], + ClientStorageOp::GetKxHint(_, Some(rustls::NamedGroup::X25519)) + )); + assert!(matches!( + ops[11], + ClientStorageOp::SetKxHint(_, rustls::NamedGroup::secp384r1) + )); +} + +#[cfg(feature = "tls12")] +#[test] +fn test_tls13_client_resumption_does_not_reuse_tickets() { + let shared_storage = Arc::new(ClientStorage::new()); + + let mut client_config = make_client_config(KeyType::Rsa); + client_config.resumption = Resumption::store(shared_storage.clone()); + let client_config = Arc::new(client_config); + + let mut server_config = make_server_config(KeyType::Rsa); + server_config.send_tls13_tickets = 5; + let server_config = Arc::new(server_config); + + // first handshake: client obtains 5 tickets from server. + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + do_handshake_until_error(&mut client, &mut server).unwrap(); + + let ops = shared_storage.ops_and_reset(); + println!("storage {:#?}", ops); + assert_eq!(ops.len(), 10); + assert!(matches!(ops[5], ClientStorageOp::InsertTls13Ticket(_))); + assert!(matches!(ops[6], ClientStorageOp::InsertTls13Ticket(_))); + assert!(matches!(ops[7], ClientStorageOp::InsertTls13Ticket(_))); + assert!(matches!(ops[8], ClientStorageOp::InsertTls13Ticket(_))); + assert!(matches!(ops[9], ClientStorageOp::InsertTls13Ticket(_))); + + // 5 subsequent handshakes: all are resumptions + + // Note: we don't do complete the handshakes, because that means + // we get five additional tickets per connection which is unhelpful + // in this test. It also acts to record a "Happy Eyeballs"-type use + // case, where a client speculatively makes many connection attempts + // in parallel without knowledge of which will work due to underlying + // connectivity uncertainty. + for _ in 0..5 { + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + + let ops = shared_storage.ops_and_reset(); + assert!(matches!(ops[0], ClientStorageOp::TakeTls13Ticket(_, true))); + } + + // 6th subsequent handshake: cannot be resumed; we ran out of tickets + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + + let ops = shared_storage.ops_and_reset(); + println!("last {:?}", ops); + assert!(matches!(ops[0], ClientStorageOp::TakeTls13Ticket(_, false))); +} + +#[test] +fn test_client_mtu_reduction() { + struct CollectWrites { + writevs: Vec>, + } + + impl io::Write for CollectWrites { + fn write(&mut self, _: &[u8]) -> io::Result { + panic!() + } + fn flush(&mut self) -> io::Result<()> { + panic!() + } + fn write_vectored<'b>(&mut self, b: &[io::IoSlice<'b>]) -> io::Result { + let writes = b + .iter() + .map(|slice| slice.len()) + .collect::>(); + let len = writes.iter().sum(); + self.writevs.push(writes); + Ok(len) + } + } + + fn collect_write_lengths(client: &mut ClientConnection) -> Vec { + let mut collector = CollectWrites { writevs: vec![] }; + + client + .write_tls(&mut collector) + .unwrap(); + assert_eq!(collector.writevs.len(), 1); + collector.writevs[0].clone() + } + + for kt in ALL_KEY_TYPES.iter() { + let mut client_config = make_client_config(*kt); + client_config.max_fragment_size = Some(64); + let mut client = + ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap(); + let writes = collect_write_lengths(&mut client); + println!("writes at mtu=64: {:?}", writes); + assert!(writes.iter().all(|x| *x <= 64)); + assert!(writes.len() > 1); + } +} + +#[test] +fn test_server_mtu_reduction() { + let mut server_config = make_server_config(KeyType::Rsa); + server_config.max_fragment_size = Some(64); + server_config.send_half_rtt_data = true; + let (mut client, mut server) = + make_pair_for_configs(make_client_config(KeyType::Rsa), server_config); + + let big_data = [0u8; 2048]; + server + .writer() + .write_all(&big_data) + .unwrap(); + + let encryption_overhead = 20; // FIXME: see issue #991 + + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + { + let mut pipe = OtherSession::new(&mut client); + server.write_tls(&mut pipe).unwrap(); + + assert_eq!(pipe.writevs.len(), 1); + assert!(pipe.writevs[0] + .iter() + .all(|x| *x <= 64 + encryption_overhead)); + } + + client.process_new_packets().unwrap(); + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + { + let mut pipe = OtherSession::new(&mut client); + server.write_tls(&mut pipe).unwrap(); + assert_eq!(pipe.writevs.len(), 1); + assert!(pipe.writevs[0] + .iter() + .all(|x| *x <= 64 + encryption_overhead)); + } + + client.process_new_packets().unwrap(); + check_read(&mut client.reader(), &big_data); +} + +fn check_client_max_fragment_size(size: usize) -> Option { + let mut client_config = make_client_config(KeyType::Ed25519); + client_config.max_fragment_size = Some(size); + ClientConnection::new(Arc::new(client_config), dns_name("localhost")).err() +} + +#[test] +fn bad_client_max_fragment_sizes() { + assert_eq!( + check_client_max_fragment_size(31), + Some(Error::BadMaxFragmentSize) + ); + assert_eq!(check_client_max_fragment_size(32), None); + assert_eq!(check_client_max_fragment_size(64), None); + assert_eq!(check_client_max_fragment_size(1460), None); + assert_eq!(check_client_max_fragment_size(0x4000), None); + assert_eq!(check_client_max_fragment_size(0x4005), None); + assert_eq!( + check_client_max_fragment_size(0x4006), + Some(Error::BadMaxFragmentSize) + ); + assert_eq!( + check_client_max_fragment_size(0xffff), + Some(Error::BadMaxFragmentSize) + ); +} + +fn assert_lt(left: usize, right: usize) { + if left >= right { + panic!("expected {} < {}", left, right); + } +} + +#[test] +fn connection_types_are_not_huge() { + // Arbitrary sizes + assert_lt(mem::size_of::(), 1600); + assert_lt(mem::size_of::(), 1600); +} + +use rustls::internal::msgs::{ + handshake::ClientExtension, handshake::HandshakePayload, message::Message, + message::MessagePayload, +}; + +#[test] +fn test_server_rejects_duplicate_sni_names() { + fn duplicate_sni_payload(msg: &mut Message) -> Altered { + if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload { + if let HandshakePayload::ClientHello(ch) = &mut parsed.payload { + for mut ext in ch.extensions.iter_mut() { + if let ClientExtension::ServerName(snr) = &mut ext { + snr.push(snr[0].clone()); + } + } + } + + *encoded = Payload::new(parsed.get_encoding()); + } + Altered::InPlace + } + + let (client, server) = make_pair(KeyType::Rsa); + let (mut client, mut server) = (client.into(), server.into()); + transfer_altered(&mut client, duplicate_sni_payload, &mut server); + assert_eq!( + server.process_new_packets(), + Err(Error::PeerMisbehaved( + PeerMisbehaved::DuplicateServerNameTypes + )) + ); +} + +#[test] +fn test_server_rejects_empty_sni_extension() { + fn empty_sni_payload(msg: &mut Message) -> Altered { + if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload { + if let HandshakePayload::ClientHello(ch) = &mut parsed.payload { + for mut ext in ch.extensions.iter_mut() { + if let ClientExtension::ServerName(snr) = &mut ext { + snr.clear(); + } + } + } + + *encoded = Payload::new(parsed.get_encoding()); + } + + Altered::InPlace + } + + let (client, server) = make_pair(KeyType::Rsa); + let (mut client, mut server) = (client.into(), server.into()); + transfer_altered(&mut client, empty_sni_payload, &mut server); + assert_eq!( + server.process_new_packets(), + Err(Error::PeerMisbehaved( + PeerMisbehaved::ServerNameMustContainOneHostName + )) + ); +} + +#[test] +fn test_server_rejects_clients_without_any_kx_group_overlap() { + fn different_kx_group(msg: &mut Message) -> Altered { + if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload { + if let HandshakePayload::ClientHello(ch) = &mut parsed.payload { + for mut ext in ch.extensions.iter_mut() { + if let ClientExtension::NamedGroups(ngs) = &mut ext { + ngs.clear(); + } + if let ClientExtension::KeyShare(ks) = &mut ext { + ks.clear(); + } + } + } + + *encoded = Payload::new(parsed.get_encoding()); + } + Altered::InPlace + } + + let (client, server) = make_pair(KeyType::Rsa); + let (mut client, mut server) = (client.into(), server.into()); + transfer_altered(&mut client, different_kx_group, &mut server); + assert_eq!( + server.process_new_packets(), + Err(Error::PeerIncompatible( + PeerIncompatible::NoKxGroupsInCommon + )) + ); +} + +#[test] +fn test_client_rejects_illegal_tls13_ccs() { + fn corrupt_ccs(msg: &mut Message) -> Altered { + if let MessagePayload::ChangeCipherSpec(_) = &mut msg.payload { + println!("seen CCS {:?}", msg); + return Altered::Raw(vec![0x14, 0x03, 0x03, 0x00, 0x02, 0x01, 0x02]); + } + Altered::InPlace + } + + let (mut client, mut server) = make_pair(KeyType::Rsa); + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + + let (mut server, mut client) = (server.into(), client.into()); + + transfer_altered(&mut server, corrupt_ccs, &mut client); + assert_eq!( + client.process_new_packets(), + Err(Error::PeerMisbehaved( + PeerMisbehaved::IllegalMiddleboxChangeCipherSpec + )) + ); +} + +/// https://github.com/rustls/rustls/issues/797 +#[cfg(feature = "tls12")] +#[test] +fn test_client_tls12_no_resume_after_server_downgrade() { + let mut client_config = common::make_client_config(KeyType::Ed25519); + let client_storage = Arc::new(ClientStorage::new()); + client_config.resumption = Resumption::store(client_storage.clone()); + let client_config = Arc::new(client_config); + + let server_config_1 = Arc::new(common::finish_server_config( + KeyType::Ed25519, + ServerConfig::builder() + .with_safe_default_cipher_suites() + .with_safe_default_kx_groups() + .with_protocol_versions(&[&rustls::version::TLS13]) + .unwrap(), + )); + + let mut server_config_2 = common::finish_server_config( + KeyType::Ed25519, + ServerConfig::builder() + .with_safe_default_cipher_suites() + .with_safe_default_kx_groups() + .with_protocol_versions(&[&rustls::version::TLS12]) + .unwrap(), + ); + server_config_2.session_storage = Arc::new(rustls::server::NoServerSessionStorage {}); + + dbg!("handshake 1"); + let mut client_1 = + ClientConnection::new(client_config.clone(), "localhost".try_into().unwrap()).unwrap(); + let mut server_1 = ServerConnection::new(server_config_1).unwrap(); + common::do_handshake(&mut client_1, &mut server_1); + + assert_eq!(client_storage.ops().len(), 9); + println!("hs1 storage ops: {:#?}", client_storage.ops()); + assert!(matches!( + client_storage.ops()[3], + ClientStorageOp::SetKxHint(_, _) + )); + assert!(matches!( + client_storage.ops()[4], + ClientStorageOp::RemoveTls12Session(_) + )); + assert!(matches!( + client_storage.ops()[5], + ClientStorageOp::InsertTls13Ticket(_) + )); + + dbg!("handshake 2"); + let mut client_2 = + ClientConnection::new(client_config, "localhost".try_into().unwrap()).unwrap(); + let mut server_2 = ServerConnection::new(Arc::new(server_config_2)).unwrap(); + common::do_handshake(&mut client_2, &mut server_2); + println!("hs2 storage ops: {:#?}", client_storage.ops()); + assert_eq!(client_storage.ops().len(), 11); + + // attempt consumes a TLS1.3 ticket + assert!(matches!( + client_storage.ops()[9], + ClientStorageOp::TakeTls13Ticket(_, true) + )); + + // but ends up with TLS1.2 + assert_eq!( + client_2.protocol_version(), + Some(rustls::ProtocolVersion::TLSv1_2) + ); +} + +#[test] +fn test_acceptor() { + use rustls::server::Acceptor; + + let client_config = Arc::new(make_client_config(KeyType::Ed25519)); + let mut client = ClientConnection::new(client_config, dns_name("localhost")).unwrap(); + let mut buf = Vec::new(); + client.write_tls(&mut buf).unwrap(); + + let server_config = Arc::new(make_server_config(KeyType::Ed25519)); + let mut acceptor = Acceptor::default(); + acceptor + .read_tls(&mut buf.as_slice()) + .unwrap(); + let accepted = acceptor.accept().unwrap().unwrap(); + let ch = accepted.client_hello(); + assert_eq!(ch.server_name(), Some("localhost")); + + let server = accepted + .into_connection(server_config) + .unwrap(); + assert!(server.wants_write()); + + // Reusing an acceptor is not allowed + assert_eq!( + acceptor + .read_tls(&mut [0u8].as_ref()) + .err() + .unwrap() + .kind(), + io::ErrorKind::Other, + ); + assert_eq!( + acceptor.accept().err(), + Some(Error::General("Acceptor polled after completion".into())) + ); + + let mut acceptor = Acceptor::default(); + assert!(acceptor.accept().unwrap().is_none()); + acceptor + .read_tls(&mut &buf[..3]) + .unwrap(); // incomplete message + assert!(acceptor.accept().unwrap().is_none()); + acceptor + .read_tls(&mut [0x80, 0x00].as_ref()) + .unwrap(); // invalid message (len = 32k bytes) + assert!(acceptor.accept().is_err()); + + let mut acceptor = Acceptor::default(); + // Minimal valid 1-byte application data message is not a handshake message + acceptor + .read_tls(&mut [0x17, 0x03, 0x03, 0x00, 0x01, 0x00].as_ref()) + .unwrap(); + assert!(acceptor.accept().is_err()); + + let mut acceptor = Acceptor::default(); + // Minimal 1-byte ClientHello message is not a legal handshake message + acceptor + .read_tls(&mut [0x16, 0x03, 0x03, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01, 0x00].as_ref()) + .unwrap(); + assert!(acceptor.accept().is_err()); +} + +#[derive(Default, Debug)] +struct LogCounts { + trace: usize, + debug: usize, + info: usize, + warn: usize, + error: usize, +} + +impl LogCounts { + fn new() -> Self { + Self { + ..Default::default() + } + } + + fn reset(&mut self) { + *self = Self::new(); + } + + fn add(&mut self, level: log::Level) { + match level { + log::Level::Trace => self.trace += 1, + log::Level::Debug => self.debug += 1, + log::Level::Info => self.info += 1, + log::Level::Warn => self.warn += 1, + log::Level::Error => self.error += 1, + } + } +} + +thread_local!(static COUNTS: RefCell = RefCell::new(LogCounts::new())); + +struct CountingLogger; + +static LOGGER: CountingLogger = CountingLogger; + +impl CountingLogger { + fn install() { + log::set_logger(&LOGGER).unwrap(); + log::set_max_level(log::LevelFilter::Trace); + } + + fn reset() { + COUNTS.with(|c| { + c.borrow_mut().reset(); + }); + } +} + +impl log::Log for CountingLogger { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + println!("logging at {:?}: {:?}", record.level(), record.args()); + + COUNTS.with(|c| { + c.borrow_mut().add(record.level()); + }); + } + + fn flush(&self) {} +} + +#[test] +fn test_no_warning_logging_during_successful_sessions() { + CountingLogger::install(); + CountingLogger::reset(); + + for kt in ALL_KEY_TYPES.iter() { + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(*kt, &[version]); + let (mut client, mut server) = + make_pair_for_configs(client_config, make_server_config(*kt)); + do_handshake(&mut client, &mut server); + } + } + + if cfg!(feature = "logging") { + COUNTS.with(|c| { + println!("After tests: {:?}", c.borrow()); + assert_eq!(c.borrow().warn, 0); + assert_eq!(c.borrow().error, 0); + assert_eq!(c.borrow().info, 0); + assert!(c.borrow().trace > 0); + assert!(c.borrow().debug > 0); + }); + } else { + COUNTS.with(|c| { + println!("After tests: {:?}", c.borrow()); + assert_eq!(c.borrow().warn, 0); + assert_eq!(c.borrow().error, 0); + assert_eq!(c.borrow().info, 0); + assert_eq!(c.borrow().trace, 0); + assert_eq!(c.borrow().debug, 0); + }); + } +} + +/// Test that secrets can be extracted and used for encryption/decryption. +#[cfg(feature = "secret_extraction")] +#[test] +fn test_secret_extraction_enabled() { + // Normally, secret extraction would be used to configure kTLS (TLS offload + // to the kernel). We want this test to run on any platform, though, so + // instead we just compare secrets for equality. + + // TLS 1.2 and 1.3 have different mechanisms for key exchange and handshake, + // and secrets are stored/extracted differently, so we want to test them both. + // We support 3 different AEAD algorithms (AES-128-GCM mode, AES-256-GCM, and + // Chacha20Poly1305), so that's 2*3 = 6 combinations to test. + let kt = KeyType::Rsa; + for suite in [ + rustls::cipher_suite::TLS13_AES_128_GCM_SHA256, + rustls::cipher_suite::TLS13_AES_256_GCM_SHA384, + rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256, + rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + rustls::cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + ] { + let version = suite.version(); + println!("Testing suite {:?}", suite.suite().as_str()); + + // Only offer the cipher suite (and protocol version) that we're testing + let mut server_config = ServerConfig::builder() + .with_cipher_suites(&[suite]) + .with_safe_default_kx_groups() + .with_protocol_versions(&[version]) + .unwrap() + .with_no_client_auth() + .with_single_cert(kt.get_chain(), kt.get_key()) + .unwrap(); + // Opt into secret extraction from both sides + server_config.enable_secret_extraction = true; + let server_config = Arc::new(server_config); + + let mut client_config = make_client_config(kt); + client_config.enable_secret_extraction = true; + + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + + do_handshake(&mut client, &mut server); + + // The handshake is finished, we're now able to extract traffic secrets + let client_secrets = client.extract_secrets().unwrap(); + let server_secrets = server.extract_secrets().unwrap(); + + // Comparing secrets for equality is something you should never have to + // do in production code, so ConnectionTrafficSecrets doesn't implement + // PartialEq/Eq on purpose. Instead, we have to get creative. + fn explode_secrets(s: &ConnectionTrafficSecrets) -> (&[u8], &[u8], &[u8]) { + match s { + ConnectionTrafficSecrets::Aes128Gcm { key, salt, iv } => (key, salt, iv), + ConnectionTrafficSecrets::Aes256Gcm { key, salt, iv } => (key, salt, iv), + ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv } => (key, &[], iv), + _ => panic!("unexpected secret type"), + } + } + + fn assert_secrets_equal( + (l_seq, l_sec): (u64, ConnectionTrafficSecrets), + (r_seq, r_sec): (u64, ConnectionTrafficSecrets), + ) { + assert_eq!(l_seq, r_seq); + assert_eq!(explode_secrets(&l_sec), explode_secrets(&r_sec)); + } + + assert_secrets_equal(client_secrets.tx, server_secrets.rx); + assert_secrets_equal(client_secrets.rx, server_secrets.tx); + } +} + +/// Test that secrets cannot be extracted unless explicitly enabled, and until +/// the handshake is done. +#[cfg(feature = "secret_extraction")] +#[test] +fn test_secret_extraction_disabled_or_too_early() { + let suite = rustls::cipher_suite::TLS13_AES_128_GCM_SHA256; + let kt = KeyType::Rsa; + + for (server_enable, client_enable) in [(true, false), (false, true)] { + let mut server_config = ServerConfig::builder() + .with_cipher_suites(&[suite]) + .with_safe_default_kx_groups() + .with_safe_default_protocol_versions() + .unwrap() + .with_no_client_auth() + .with_single_cert(kt.get_chain(), kt.get_key()) + .unwrap(); + server_config.enable_secret_extraction = server_enable; + let server_config = Arc::new(server_config); + + let mut client_config = make_client_config(kt); + client_config.enable_secret_extraction = client_enable; + + let client_config = Arc::new(client_config); + + let (client, server) = make_pair_for_arc_configs(&client_config, &server_config); + + assert!( + client.extract_secrets().is_err(), + "extraction should fail until handshake completes" + ); + assert!( + server.extract_secrets().is_err(), + "extraction should fail until handshake completes" + ); + + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + + do_handshake(&mut client, &mut server); + + assert_eq!(server_enable, server.extract_secrets().is_ok()); + assert_eq!(client_enable, client.extract_secrets().is_ok()); + } +} + +#[test] +fn test_received_plaintext_backpressure() { + let suite = rustls::cipher_suite::TLS13_AES_128_GCM_SHA256; + let kt = KeyType::Rsa; + + let server_config = Arc::new( + ServerConfig::builder() + .with_cipher_suites(&[suite]) + .with_safe_default_kx_groups() + .with_safe_default_protocol_versions() + .unwrap() + .with_no_client_auth() + .with_single_cert(kt.get_chain(), kt.get_key()) + .unwrap(), + ); + + let client_config = Arc::new(make_client_config(kt)); + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + do_handshake(&mut client, &mut server); + + // Fill the server's received plaintext buffer with 16k bytes + let client_buf = [0; 16_385]; + dbg!(client + .writer() + .write(&client_buf) + .unwrap()); + let mut network_buf = Vec::with_capacity(32_768); + let sent = dbg!(client + .write_tls(&mut network_buf) + .unwrap()); + let mut read = 0; + while read < sent { + let new = dbg!(server + .read_tls(&mut &network_buf[read..sent]) + .unwrap()); + if new == 4096 { + read += new; + } else { + break; + } + } + server.process_new_packets().unwrap(); + + // Send two more bytes from client to server + dbg!(client + .writer() + .write(&client_buf[..2]) + .unwrap()); + let sent = dbg!(client + .write_tls(&mut network_buf) + .unwrap()); + + // Get an error because the received plaintext buffer is full + assert!(server + .read_tls(&mut &network_buf[..sent]) + .is_err()); + + // Read out some of the plaintext + server + .reader() + .read_exact(&mut [0; 2]) + .unwrap(); + + // Now there's room again in the plaintext buffer + assert_eq!( + server + .read_tls(&mut &network_buf[..sent]) + .unwrap(), + 24 + ); +} + +#[test] +fn test_debug_server_name_from_ip() { + assert_eq!( + format!( + "{:?}", + rustls::ServerName::IpAddress("127.0.0.1".parse().unwrap()) + ), + "IpAddress(127.0.0.1)" + ) +} + +#[test] +fn test_debug_server_name_from_string() { + assert_eq!( + format!("{:?}", rustls::ServerName::try_from("a.com").unwrap()), + "DnsName(\"a.com\")" + ) +} diff --git a/vendor/rustls-0.21.8/tests/bogo.rs b/vendor/rustls-0.21.8/tests/bogo.rs new file mode 100644 index 0000000000000..e96073d1098e3 --- /dev/null +++ b/vendor/rustls-0.21.8/tests/bogo.rs @@ -0,0 +1,18 @@ +// Runs the bogo test suite, in the form of a rust test. +// Note that bogo requires a golang environment to build +// and run. + +#[test] +#[cfg(all(coverage, feature = "quic", feature = "dangerous_configuration"))] +fn run_bogo_tests() { + use std::process::Command; + + let rc = Command::new("./runme") + .current_dir("../bogo") + .spawn() + .expect("cannot run bogo/runme") + .wait() + .expect("cannot wait for bogo"); + + assert!(rc.success(), "bogo exited non-zero"); +} diff --git a/vendor/rustls-0.21.8/tests/client_cert_verifier.rs b/vendor/rustls-0.21.8/tests/client_cert_verifier.rs new file mode 100644 index 0000000000000..d7f6de52033fc --- /dev/null +++ b/vendor/rustls-0.21.8/tests/client_cert_verifier.rs @@ -0,0 +1,209 @@ +//! Tests for configuring and using a [`ClientCertVerifier`] for a server. + +#![cfg(feature = "dangerous_configuration")] + +mod common; + +use crate::common::{ + dns_name, do_handshake_until_both_error, do_handshake_until_error, get_client_root_store, + make_client_config_with_versions, make_client_config_with_versions_with_auth, + make_pair_for_arc_configs, ErrorFromPeer, KeyType, ALL_KEY_TYPES, +}; +use rustls::client::WebPkiVerifier; +use rustls::internal::msgs::handshake::DistinguishedName; +use rustls::server::{ClientCertVerified, ClientCertVerifier}; +use rustls::{ + AlertDescription, Certificate, ClientConnection, Error, InvalidMessage, ServerConfig, + ServerConnection, SignatureScheme, +}; +use std::sync::Arc; + +// Client is authorized! +fn ver_ok() -> Result { + Ok(rustls::server::ClientCertVerified::assertion()) +} + +// Use when we shouldn't even attempt verification +fn ver_unreachable() -> Result { + unreachable!() +} + +// Verifier that returns an error that we can expect +fn ver_err() -> Result { + Err(Error::General("test err".to_string())) +} + +fn server_config_with_verifier( + kt: KeyType, + client_cert_verifier: MockClientVerifier, +) -> ServerConfig { + ServerConfig::builder() + .with_safe_defaults() + .with_client_cert_verifier(Arc::new(client_cert_verifier)) + .with_single_cert(kt.get_chain(), kt.get_key()) + .unwrap() +} + +#[test] +// Happy path, we resolve to a root, it is verified OK, should be able to connect +fn client_verifier_works() { + for kt in ALL_KEY_TYPES.iter() { + let client_verifier = MockClientVerifier { + verified: ver_ok, + subjects: get_client_root_store(*kt) + .roots + .iter() + .map(|r| r.subject().clone()) + .collect(), + mandatory: true, + offered_schemes: None, + }; + + let server_config = server_config_with_verifier(*kt, client_verifier); + let server_config = Arc::new(server_config); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config.clone()), &server_config); + let err = do_handshake_until_error(&mut client, &mut server); + assert_eq!(err, Ok(())); + } + } +} + +// Server offers no verification schemes +#[test] +fn client_verifier_no_schemes() { + for kt in ALL_KEY_TYPES.iter() { + let client_verifier = MockClientVerifier { + verified: ver_ok, + subjects: get_client_root_store(*kt) + .roots + .iter() + .map(|r| r.subject().clone()) + .collect(), + mandatory: true, + offered_schemes: Some(vec![]), + }; + + let server_config = server_config_with_verifier(*kt, client_verifier); + let server_config = Arc::new(server_config); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config.clone()), &server_config); + let err = do_handshake_until_error(&mut client, &mut server); + assert_eq!( + err, + Err(ErrorFromPeer::Client(Error::InvalidMessage( + InvalidMessage::NoSignatureSchemes, + ))), + ); + } + } +} + +// If we do have a root, we must do auth +#[test] +fn client_verifier_no_auth_yes_root() { + for kt in ALL_KEY_TYPES.iter() { + let client_verifier = MockClientVerifier { + verified: ver_unreachable, + subjects: get_client_root_store(*kt) + .roots + .iter() + .map(|r| r.subject().clone()) + .collect(), + mandatory: true, + offered_schemes: None, + }; + + let server_config = server_config_with_verifier(*kt, client_verifier); + let server_config = Arc::new(server_config); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(*kt, &[version]); + let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); + let mut client = + ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap(); + let errs = do_handshake_until_both_error(&mut client, &mut server); + assert_eq!( + errs, + Err(vec![ + ErrorFromPeer::Server(Error::NoCertificatesPresented), + ErrorFromPeer::Client(Error::AlertReceived( + AlertDescription::CertificateRequired + )) + ]) + ); + } + } +} + +#[test] +// Triple checks we propagate the rustls::Error through +fn client_verifier_fails_properly() { + for kt in ALL_KEY_TYPES.iter() { + let client_verifier = MockClientVerifier { + verified: ver_err, + subjects: get_client_root_store(*kt) + .roots + .iter() + .map(|r| r.subject().clone()) + .collect(), + mandatory: true, + offered_schemes: None, + }; + + let server_config = server_config_with_verifier(*kt, client_verifier); + let server_config = Arc::new(server_config); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); + let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); + let mut client = + ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap(); + let err = do_handshake_until_error(&mut client, &mut server); + assert_eq!( + err, + Err(ErrorFromPeer::Server(Error::General("test err".into()))) + ); + } + } +} + +pub struct MockClientVerifier { + pub verified: fn() -> Result, + pub subjects: Vec, + pub mandatory: bool, + pub offered_schemes: Option>, +} + +impl ClientCertVerifier for MockClientVerifier { + fn client_auth_mandatory(&self) -> bool { + self.mandatory + } + + fn client_auth_root_subjects(&self) -> &[DistinguishedName] { + &self.subjects + } + + fn verify_client_cert( + &self, + _end_entity: &Certificate, + _intermediates: &[Certificate], + _now: std::time::SystemTime, + ) -> Result { + (self.verified)() + } + + fn supported_verify_schemes(&self) -> Vec { + if let Some(schemes) = &self.offered_schemes { + schemes.clone() + } else { + WebPkiVerifier::verification_schemes() + } + } +} diff --git a/vendor/rustls-0.21.8/tests/common/mod.rs b/vendor/rustls-0.21.8/tests/common/mod.rs new file mode 100644 index 0000000000000..e9d67e9055e71 --- /dev/null +++ b/vendor/rustls-0.21.8/tests/common/mod.rs @@ -0,0 +1,518 @@ +#![allow(dead_code)] + +use std::io; +use std::ops::{Deref, DerefMut}; +use std::sync::Arc; + +use rustls::internal::msgs::codec::Reader; +use rustls::internal::msgs::message::{Message, OpaqueMessage, PlainMessage}; +use rustls::server::{ + AllowAnyAnonymousOrAuthenticatedClient, AllowAnyAuthenticatedClient, UnparsedCertRevocationList, +}; +use rustls::Connection; +use rustls::Error; +use rustls::RootCertStore; +use rustls::{Certificate, PrivateKey}; +use rustls::{ClientConfig, ClientConnection}; +use rustls::{ConnectionCommon, ServerConfig, ServerConnection, SideData}; + +macro_rules! embed_files { + ( + $( + ($name:ident, $keytype:expr, $path:expr); + )+ + ) => { + $( + const $name: &'static [u8] = include_bytes!( + concat!("../../../test-ca/", $keytype, "/", $path)); + )+ + + pub fn bytes_for(keytype: &str, path: &str) -> &'static [u8] { + match (keytype, path) { + $( + ($keytype, $path) => $name, + )+ + _ => panic!("unknown keytype {} with path {}", keytype, path), + } + } + } +} + +embed_files! { + (ECDSA_CA_CERT, "ecdsa", "ca.cert"); + (ECDSA_CA_DER, "ecdsa", "ca.der"); + (ECDSA_CA_KEY, "ecdsa", "ca.key"); + (ECDSA_CLIENT_CERT, "ecdsa", "client.cert"); + (ECDSA_CLIENT_CHAIN, "ecdsa", "client.chain"); + (ECDSA_CLIENT_FULLCHAIN, "ecdsa", "client.fullchain"); + (ECDSA_CLIENT_KEY, "ecdsa", "client.key"); + (ECDSA_CLIENT_REQ, "ecdsa", "client.req"); + (ECDSA_CLIENT_CRL_PEM, "ecdsa", "client.revoked.crl.pem"); + (ECDSA_END_CERT, "ecdsa", "end.cert"); + (ECDSA_END_CHAIN, "ecdsa", "end.chain"); + (ECDSA_END_FULLCHAIN, "ecdsa", "end.fullchain"); + (ECDSA_END_KEY, "ecdsa", "end.key"); + (ECDSA_END_REQ, "ecdsa", "end.req"); + (ECDSA_INTER_CERT, "ecdsa", "inter.cert"); + (ECDSA_INTER_KEY, "ecdsa", "inter.key"); + (ECDSA_INTER_REQ, "ecdsa", "inter.req"); + (ECDSA_NISTP256_PEM, "ecdsa", "nistp256.pem"); + (ECDSA_NISTP384_PEM, "ecdsa", "nistp384.pem"); + + (EDDSA_CA_CERT, "eddsa", "ca.cert"); + (EDDSA_CA_DER, "eddsa", "ca.der"); + (EDDSA_CA_KEY, "eddsa", "ca.key"); + (EDDSA_CLIENT_CERT, "eddsa", "client.cert"); + (EDDSA_CLIENT_CHAIN, "eddsa", "client.chain"); + (EDDSA_CLIENT_FULLCHAIN, "eddsa", "client.fullchain"); + (EDDSA_CLIENT_KEY, "eddsa", "client.key"); + (EDDSA_CLIENT_REQ, "eddsa", "client.req"); + (EDDSA_CLIENT_CRL_PEM, "eddsa", "client.revoked.crl.pem"); + (EDDSA_END_CERT, "eddsa", "end.cert"); + (EDDSA_END_CHAIN, "eddsa", "end.chain"); + (EDDSA_END_FULLCHAIN, "eddsa", "end.fullchain"); + (EDDSA_END_KEY, "eddsa", "end.key"); + (EDDSA_END_REQ, "eddsa", "end.req"); + (EDDSA_INTER_CERT, "eddsa", "inter.cert"); + (EDDSA_INTER_KEY, "eddsa", "inter.key"); + (EDDSA_INTER_REQ, "eddsa", "inter.req"); + + (RSA_CA_CERT, "rsa", "ca.cert"); + (RSA_CA_DER, "rsa", "ca.der"); + (RSA_CA_KEY, "rsa", "ca.key"); + (RSA_CLIENT_CERT, "rsa", "client.cert"); + (RSA_CLIENT_CHAIN, "rsa", "client.chain"); + (RSA_CLIENT_FULLCHAIN, "rsa", "client.fullchain"); + (RSA_CLIENT_KEY, "rsa", "client.key"); + (RSA_CLIENT_REQ, "rsa", "client.req"); + (RSA_CLIENT_RSA, "rsa", "client.rsa"); + (RSA_CLIENT_CRL_PEM, "rsa", "client.revoked.crl.pem"); + (RSA_END_CERT, "rsa", "end.cert"); + (RSA_END_CHAIN, "rsa", "end.chain"); + (RSA_END_FULLCHAIN, "rsa", "end.fullchain"); + (RSA_END_KEY, "rsa", "end.key"); + (RSA_END_REQ, "rsa", "end.req"); + (RSA_END_RSA, "rsa", "end.rsa"); + (RSA_INTER_CERT, "rsa", "inter.cert"); + (RSA_INTER_KEY, "rsa", "inter.key"); + (RSA_INTER_REQ, "rsa", "inter.req"); +} + +pub fn transfer( + left: &mut (impl DerefMut + Deref>), + right: &mut (impl DerefMut + Deref>), +) -> usize { + let mut buf = [0u8; 262144]; + let mut total = 0; + + while left.wants_write() { + let sz = { + let into_buf: &mut dyn io::Write = &mut &mut buf[..]; + left.write_tls(into_buf).unwrap() + }; + total += sz; + if sz == 0 { + return total; + } + + let mut offs = 0; + loop { + let from_buf: &mut dyn io::Read = &mut &buf[offs..sz]; + offs += right.read_tls(from_buf).unwrap(); + if sz == offs { + break; + } + } + } + + total +} + +pub fn transfer_eof(conn: &mut (impl DerefMut + Deref>)) { + let empty_buf = [0u8; 0]; + let empty_cursor: &mut dyn io::Read = &mut &empty_buf[..]; + let sz = conn.read_tls(empty_cursor).unwrap(); + assert_eq!(sz, 0); +} + +pub enum Altered { + /// message has been edited in-place (or is unchanged) + InPlace, + /// send these raw bytes instead of the message. + Raw(Vec), +} + +pub fn transfer_altered(left: &mut Connection, filter: F, right: &mut Connection) -> usize +where + F: Fn(&mut Message) -> Altered, +{ + let mut buf = [0u8; 262144]; + let mut total = 0; + + while left.wants_write() { + let sz = { + let into_buf: &mut dyn io::Write = &mut &mut buf[..]; + left.write_tls(into_buf).unwrap() + }; + total += sz; + if sz == 0 { + return total; + } + + let mut reader = Reader::init(&buf[..sz]); + while reader.any_left() { + let message = OpaqueMessage::read(&mut reader).unwrap(); + let mut message = Message::try_from(message.into_plain_message()).unwrap(); + let message_enc = match filter(&mut message) { + Altered::InPlace => PlainMessage::from(message) + .into_unencrypted_opaque() + .encode(), + Altered::Raw(data) => data, + }; + + let message_enc_reader: &mut dyn io::Read = &mut &message_enc[..]; + let len = right + .read_tls(message_enc_reader) + .unwrap(); + assert_eq!(len, message_enc.len()); + } + } + + total +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum KeyType { + Rsa, + Ecdsa, + Ed25519, +} + +pub static ALL_KEY_TYPES: [KeyType; 3] = [KeyType::Rsa, KeyType::Ecdsa, KeyType::Ed25519]; + +impl KeyType { + fn bytes_for(&self, part: &str) -> &'static [u8] { + match self { + Self::Rsa => bytes_for("rsa", part), + Self::Ecdsa => bytes_for("ecdsa", part), + Self::Ed25519 => bytes_for("eddsa", part), + } + } + + pub fn get_chain(&self) -> Vec { + rustls_pemfile::certs(&mut io::BufReader::new(self.bytes_for("end.fullchain"))) + .unwrap() + .iter() + .map(|v| Certificate(v.clone())) + .collect() + } + + pub fn get_key(&self) -> PrivateKey { + PrivateKey( + rustls_pemfile::pkcs8_private_keys(&mut io::BufReader::new(self.bytes_for("end.key"))) + .unwrap()[0] + .clone(), + ) + } + + pub fn get_client_chain(&self) -> Vec { + rustls_pemfile::certs(&mut io::BufReader::new(self.bytes_for("client.fullchain"))) + .unwrap() + .iter() + .map(|v| Certificate(v.clone())) + .collect() + } + + pub fn client_crl(&self) -> UnparsedCertRevocationList { + UnparsedCertRevocationList( + rustls_pemfile::crls(&mut io::BufReader::new( + self.bytes_for("client.revoked.crl.pem"), + )) + .unwrap() + .into_iter() + .next() // We only expect one CRL. + .unwrap(), + ) + } + + fn get_client_key(&self) -> PrivateKey { + PrivateKey( + rustls_pemfile::pkcs8_private_keys(&mut io::BufReader::new( + self.bytes_for("client.key"), + )) + .unwrap()[0] + .clone(), + ) + } +} + +pub fn finish_server_config( + kt: KeyType, + conf: rustls::ConfigBuilder, +) -> ServerConfig { + conf.with_no_client_auth() + .with_single_cert(kt.get_chain(), kt.get_key()) + .unwrap() +} + +pub fn make_server_config(kt: KeyType) -> ServerConfig { + finish_server_config(kt, ServerConfig::builder().with_safe_defaults()) +} + +pub fn make_server_config_with_versions( + kt: KeyType, + versions: &[&'static rustls::SupportedProtocolVersion], +) -> ServerConfig { + finish_server_config( + kt, + ServerConfig::builder() + .with_safe_default_cipher_suites() + .with_safe_default_kx_groups() + .with_protocol_versions(versions) + .unwrap(), + ) +} + +pub fn make_server_config_with_kx_groups( + kt: KeyType, + kx_groups: &[&'static rustls::SupportedKxGroup], +) -> ServerConfig { + finish_server_config( + kt, + ServerConfig::builder() + .with_safe_default_cipher_suites() + .with_kx_groups(kx_groups) + .with_safe_default_protocol_versions() + .unwrap(), + ) +} + +pub fn get_client_root_store(kt: KeyType) -> RootCertStore { + let mut roots = kt.get_chain(); + // drop server cert + roots.drain(0..1); + let mut client_auth_roots = RootCertStore::empty(); + for root in roots { + client_auth_roots.add(&root).unwrap(); + } + client_auth_roots +} + +pub fn make_server_config_with_mandatory_client_auth_crls( + kt: KeyType, + crls: Vec, +) -> ServerConfig { + let client_auth_roots = get_client_root_store(kt); + + let client_auth = AllowAnyAuthenticatedClient::new(client_auth_roots) + .with_crls(crls) + .unwrap(); + + ServerConfig::builder() + .with_safe_defaults() + .with_client_cert_verifier(Arc::new(client_auth)) + .with_single_cert(kt.get_chain(), kt.get_key()) + .unwrap() +} + +pub fn make_server_config_with_mandatory_client_auth(kt: KeyType) -> ServerConfig { + make_server_config_with_mandatory_client_auth_crls(kt, Vec::new()) +} + +pub fn make_server_config_with_optional_client_auth( + kt: KeyType, + crls: Vec, +) -> ServerConfig { + let client_auth_roots = get_client_root_store(kt); + + let client_auth = AllowAnyAnonymousOrAuthenticatedClient::new(client_auth_roots) + .with_crls(crls) + .unwrap(); + + ServerConfig::builder() + .with_safe_defaults() + .with_client_cert_verifier(Arc::new(client_auth)) + .with_single_cert(kt.get_chain(), kt.get_key()) + .unwrap() +} + +pub fn finish_client_config( + kt: KeyType, + config: rustls::ConfigBuilder, +) -> ClientConfig { + let mut root_store = RootCertStore::empty(); + let mut rootbuf = io::BufReader::new(kt.bytes_for("ca.cert")); + root_store.add_parsable_certificates(&rustls_pemfile::certs(&mut rootbuf).unwrap()); + + config + .with_root_certificates(root_store) + .with_no_client_auth() +} + +pub fn finish_client_config_with_creds( + kt: KeyType, + config: rustls::ConfigBuilder, +) -> ClientConfig { + let mut root_store = RootCertStore::empty(); + let mut rootbuf = io::BufReader::new(kt.bytes_for("ca.cert")); + root_store.add_parsable_certificates(&rustls_pemfile::certs(&mut rootbuf).unwrap()); + + config + .with_root_certificates(root_store) + .with_client_auth_cert(kt.get_client_chain(), kt.get_client_key()) + .unwrap() +} + +pub fn make_client_config(kt: KeyType) -> ClientConfig { + finish_client_config(kt, ClientConfig::builder().with_safe_defaults()) +} + +pub fn make_client_config_with_kx_groups( + kt: KeyType, + kx_groups: &[&'static rustls::SupportedKxGroup], +) -> ClientConfig { + let builder = ClientConfig::builder() + .with_safe_default_cipher_suites() + .with_kx_groups(kx_groups) + .with_safe_default_protocol_versions() + .unwrap(); + finish_client_config(kt, builder) +} + +pub fn make_client_config_with_versions( + kt: KeyType, + versions: &[&'static rustls::SupportedProtocolVersion], +) -> ClientConfig { + let builder = ClientConfig::builder() + .with_safe_default_cipher_suites() + .with_safe_default_kx_groups() + .with_protocol_versions(versions) + .unwrap(); + finish_client_config(kt, builder) +} + +pub fn make_client_config_with_auth(kt: KeyType) -> ClientConfig { + finish_client_config_with_creds(kt, ClientConfig::builder().with_safe_defaults()) +} + +pub fn make_client_config_with_versions_with_auth( + kt: KeyType, + versions: &[&'static rustls::SupportedProtocolVersion], +) -> ClientConfig { + let builder = ClientConfig::builder() + .with_safe_default_cipher_suites() + .with_safe_default_kx_groups() + .with_protocol_versions(versions) + .unwrap(); + finish_client_config_with_creds(kt, builder) +} + +pub fn make_pair(kt: KeyType) -> (ClientConnection, ServerConnection) { + make_pair_for_configs(make_client_config(kt), make_server_config(kt)) +} + +pub fn make_pair_for_configs( + client_config: ClientConfig, + server_config: ServerConfig, +) -> (ClientConnection, ServerConnection) { + make_pair_for_arc_configs(&Arc::new(client_config), &Arc::new(server_config)) +} + +pub fn make_pair_for_arc_configs( + client_config: &Arc, + server_config: &Arc, +) -> (ClientConnection, ServerConnection) { + ( + ClientConnection::new(Arc::clone(client_config), dns_name("localhost")).unwrap(), + ServerConnection::new(Arc::clone(server_config)).unwrap(), + ) +} + +pub fn do_handshake( + client: &mut (impl DerefMut + Deref>), + server: &mut (impl DerefMut + Deref>), +) -> (usize, usize) { + let (mut to_client, mut to_server) = (0, 0); + while server.is_handshaking() || client.is_handshaking() { + to_server += transfer(client, server); + server.process_new_packets().unwrap(); + to_client += transfer(server, client); + client.process_new_packets().unwrap(); + } + (to_server, to_client) +} + +#[derive(PartialEq, Debug)] +pub enum ErrorFromPeer { + Client(Error), + Server(Error), +} + +pub fn do_handshake_until_error( + client: &mut ClientConnection, + server: &mut ServerConnection, +) -> Result<(), ErrorFromPeer> { + while server.is_handshaking() || client.is_handshaking() { + transfer(client, server); + server + .process_new_packets() + .map_err(ErrorFromPeer::Server)?; + transfer(server, client); + client + .process_new_packets() + .map_err(ErrorFromPeer::Client)?; + } + + Ok(()) +} + +pub fn do_handshake_until_both_error( + client: &mut ClientConnection, + server: &mut ServerConnection, +) -> Result<(), Vec> { + match do_handshake_until_error(client, server) { + Err(server_err @ ErrorFromPeer::Server(_)) => { + let mut errors = vec![server_err]; + transfer(server, client); + let client_err = client + .process_new_packets() + .map_err(ErrorFromPeer::Client) + .expect_err("client didn't produce error after server error"); + errors.push(client_err); + Err(errors) + } + + Err(client_err @ ErrorFromPeer::Client(_)) => { + let mut errors = vec![client_err]; + transfer(client, server); + let server_err = server + .process_new_packets() + .map_err(ErrorFromPeer::Server) + .expect_err("server didn't produce error after client error"); + errors.push(server_err); + Err(errors) + } + + Ok(()) => Ok(()), + } +} + +pub fn dns_name(name: &'static str) -> rustls::ServerName { + name.try_into().unwrap() +} + +pub struct FailsReads { + errkind: io::ErrorKind, +} + +impl FailsReads { + pub fn new(errkind: io::ErrorKind) -> Self { + Self { errkind } + } +} + +impl io::Read for FailsReads { + fn read(&mut self, _b: &mut [u8]) -> io::Result { + Err(io::Error::from(self.errkind)) + } +} diff --git a/vendor/rustls-0.21.8/tests/key_log_file_env.rs b/vendor/rustls-0.21.8/tests/key_log_file_env.rs new file mode 100644 index 0000000000000..bc15f5331c8fa --- /dev/null +++ b/vendor/rustls-0.21.8/tests/key_log_file_env.rs @@ -0,0 +1,104 @@ +//! Tests of [`rustls::KeyLogFile`] that require us to set environment variables. +//! +//! vvvv +//! Every test you add to this file MUST execute through `serialized()`. +//! ^^^^ +//! +//! See https://github.com/rust-lang/rust/issues/90308; despite not being marked +//! `unsafe`, `env::var::set_var` is an unsafe function. These tests are separated +//! from the rest of the tests so that their use of `set_ver` is less likely to +//! affect them; as of the time these tests were moved to this file, Cargo will +//! compile each test suite file to a separate executable, so these will be run +//! in a completely separate process. This way, executing every test through +//! `serialized()` will cause them to be run one at a time. +//! +//! Note: If/when we add new constructors to `KeyLogFile` to allow constructing +//! one from a path directly (without using an environment variable), then those +//! tests SHOULD NOT go in this file. +//! +//! XXX: These tests don't actually test the functionality; they just ensure +//! the code coverage doesn't complain it isn't covered. TODO: Verify that the +//! file was created successfully, with the right permissions, etc., and that it +//! contains something like what we expect. + +#[allow(dead_code)] +mod common; + +use crate::common::{ + do_handshake, make_client_config_with_versions, make_pair_for_arc_configs, make_server_config, + transfer, KeyType, +}; +use std::{ + env, + io::Write, + sync::{Arc, Mutex, Once}, +}; + +/// Approximates `#[serial]` from the `serial_test` crate. +/// +/// No attempt is made to recover from a poisoned mutex, which will +/// happen when `f` panics. In other words, all the tests that use +/// `serialized` will start failing after one test panics. +fn serialized(f: impl FnOnce()) { + // Ensure every test is run serialized + // TODO: Use `std::sync::Lazy` once that is stable. + static mut MUTEX: Option> = None; + static ONCE: Once = Once::new(); + ONCE.call_once(|| unsafe { + MUTEX = Some(Mutex::new(())); + }); + let mutex = unsafe { MUTEX.as_mut() }; + + let _guard = mutex.unwrap().lock().unwrap(); + + // XXX: NOT thread safe. + env::set_var("SSLKEYLOGFILE", "./sslkeylogfile.txt"); + + f() +} + +#[test] +fn exercise_key_log_file_for_client() { + serialized(|| { + let server_config = Arc::new(make_server_config(KeyType::Rsa)); + env::set_var("SSLKEYLOGFILE", "./sslkeylogfile.txt"); + + for version in rustls::ALL_VERSIONS { + let mut client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); + client_config.key_log = Arc::new(rustls::KeyLogFile::new()); + + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + + assert_eq!(5, client.writer().write(b"hello").unwrap()); + + do_handshake(&mut client, &mut server); + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + } + }) +} + +#[test] +fn exercise_key_log_file_for_server() { + serialized(|| { + let mut server_config = make_server_config(KeyType::Rsa); + + env::set_var("SSLKEYLOGFILE", "./sslkeylogfile.txt"); + server_config.key_log = Arc::new(rustls::KeyLogFile::new()); + + let server_config = Arc::new(server_config); + + for version in rustls::ALL_VERSIONS { + let client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + + assert_eq!(5, client.writer().write(b"hello").unwrap()); + + do_handshake(&mut client, &mut server); + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + } + }) +} diff --git a/vendor/rustls-0.21.8/tests/server_cert_verifier.rs b/vendor/rustls-0.21.8/tests/server_cert_verifier.rs new file mode 100644 index 0000000000000..ee5b89b8ff911 --- /dev/null +++ b/vendor/rustls-0.21.8/tests/server_cert_verifier.rs @@ -0,0 +1,277 @@ +//! Tests for configuring and using a [`ServerCertVerifier`] for a client. + +#![cfg(feature = "dangerous_configuration")] + +mod common; +use crate::common::{ + do_handshake, do_handshake_until_both_error, make_client_config_with_versions, + make_pair_for_arc_configs, make_server_config, ErrorFromPeer, ALL_KEY_TYPES, +}; +use rustls::client::{ + HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier, WebPkiVerifier, +}; +use rustls::DigitallySignedStruct; +use rustls::{AlertDescription, Certificate, Error, InvalidMessage, SignatureScheme}; +use std::sync::Arc; + +#[test] +fn client_can_override_certificate_verification() { + for kt in ALL_KEY_TYPES.iter() { + let verifier = Arc::new(MockServerVerifier::accepts_anything()); + + let server_config = Arc::new(make_server_config(*kt)); + + for version in rustls::ALL_VERSIONS { + let mut client_config = make_client_config_with_versions(*kt, &[version]); + client_config + .dangerous() + .set_certificate_verifier(verifier.clone()); + + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + do_handshake(&mut client, &mut server); + } + } +} + +#[test] +fn client_can_override_certificate_verification_and_reject_certificate() { + for kt in ALL_KEY_TYPES.iter() { + let verifier = Arc::new(MockServerVerifier::rejects_certificate( + Error::InvalidMessage(InvalidMessage::HandshakePayloadTooLarge), + )); + + let server_config = Arc::new(make_server_config(*kt)); + + for version in rustls::ALL_VERSIONS { + let mut client_config = make_client_config_with_versions(*kt, &[version]); + client_config + .dangerous() + .set_certificate_verifier(verifier.clone()); + + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + let errs = do_handshake_until_both_error(&mut client, &mut server); + assert_eq!( + errs, + Err(vec![ + ErrorFromPeer::Client(Error::InvalidMessage( + InvalidMessage::HandshakePayloadTooLarge, + )), + ErrorFromPeer::Server(Error::AlertReceived(AlertDescription::HandshakeFailure)), + ]), + ); + } + } +} + +#[cfg(feature = "tls12")] +#[test] +fn client_can_override_certificate_verification_and_reject_tls12_signatures() { + for kt in ALL_KEY_TYPES.iter() { + let mut client_config = make_client_config_with_versions(*kt, &[&rustls::version::TLS12]); + let verifier = Arc::new(MockServerVerifier::rejects_tls12_signatures( + Error::InvalidMessage(InvalidMessage::HandshakePayloadTooLarge), + )); + + client_config + .dangerous() + .set_certificate_verifier(verifier); + + let server_config = Arc::new(make_server_config(*kt)); + + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + let errs = do_handshake_until_both_error(&mut client, &mut server); + assert_eq!( + errs, + Err(vec![ + ErrorFromPeer::Client(Error::InvalidMessage( + InvalidMessage::HandshakePayloadTooLarge, + )), + ErrorFromPeer::Server(Error::AlertReceived(AlertDescription::HandshakeFailure)), + ]), + ); + } +} + +#[test] +fn client_can_override_certificate_verification_and_reject_tls13_signatures() { + for kt in ALL_KEY_TYPES.iter() { + let mut client_config = make_client_config_with_versions(*kt, &[&rustls::version::TLS13]); + let verifier = Arc::new(MockServerVerifier::rejects_tls13_signatures( + Error::InvalidMessage(InvalidMessage::HandshakePayloadTooLarge), + )); + + client_config + .dangerous() + .set_certificate_verifier(verifier); + + let server_config = Arc::new(make_server_config(*kt)); + + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + let errs = do_handshake_until_both_error(&mut client, &mut server); + assert_eq!( + errs, + Err(vec![ + ErrorFromPeer::Client(Error::InvalidMessage( + InvalidMessage::HandshakePayloadTooLarge, + )), + ErrorFromPeer::Server(Error::AlertReceived(AlertDescription::HandshakeFailure)), + ]), + ); + } +} + +#[test] +fn client_can_override_certificate_verification_and_offer_no_signature_schemes() { + for kt in ALL_KEY_TYPES.iter() { + let verifier = Arc::new(MockServerVerifier::offers_no_signature_schemes()); + + let server_config = Arc::new(make_server_config(*kt)); + + for version in rustls::ALL_VERSIONS { + let mut client_config = make_client_config_with_versions(*kt, &[version]); + client_config + .dangerous() + .set_certificate_verifier(verifier.clone()); + + let (mut client, mut server) = + make_pair_for_arc_configs(&Arc::new(client_config), &server_config); + let errs = do_handshake_until_both_error(&mut client, &mut server); + assert_eq!( + errs, + Err(vec![ + ErrorFromPeer::Server(Error::PeerIncompatible( + rustls::PeerIncompatible::NoSignatureSchemesInCommon + )), + ErrorFromPeer::Client(Error::AlertReceived(AlertDescription::HandshakeFailure)), + ]) + ); + } + } +} + +pub struct MockServerVerifier { + cert_rejection_error: Option, + tls12_signature_error: Option, + tls13_signature_error: Option, + wants_scts: bool, + signature_schemes: Vec, +} + +impl ServerCertVerifier for MockServerVerifier { + fn verify_server_cert( + &self, + end_entity: &rustls::Certificate, + intermediates: &[rustls::Certificate], + server_name: &rustls::ServerName, + scts: &mut dyn Iterator, + oscp_response: &[u8], + now: std::time::SystemTime, + ) -> Result { + let scts: Vec> = scts.map(|x| x.to_owned()).collect(); + println!( + "verify_server_cert({:?}, {:?}, {:?}, {:?}, {:?}, {:?})", + end_entity, intermediates, server_name, scts, oscp_response, now + ); + if let Some(error) = &self.cert_rejection_error { + Err(error.clone()) + } else { + Ok(ServerCertVerified::assertion()) + } + } + + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &Certificate, + dss: &DigitallySignedStruct, + ) -> Result { + println!( + "verify_tls12_signature({:?}, {:?}, {:?})", + message, cert, dss + ); + if let Some(error) = &self.tls12_signature_error { + Err(error.clone()) + } else { + Ok(HandshakeSignatureValid::assertion()) + } + } + + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &Certificate, + dss: &DigitallySignedStruct, + ) -> Result { + println!( + "verify_tls13_signature({:?}, {:?}, {:?})", + message, cert, dss + ); + if let Some(error) = &self.tls13_signature_error { + Err(error.clone()) + } else { + Ok(HandshakeSignatureValid::assertion()) + } + } + + fn supported_verify_schemes(&self) -> Vec { + self.signature_schemes.clone() + } + + fn request_scts(&self) -> bool { + println!("request_scts? {:?}", self.wants_scts); + self.wants_scts + } +} + +impl MockServerVerifier { + pub fn accepts_anything() -> Self { + MockServerVerifier { + cert_rejection_error: None, + ..Default::default() + } + } + + pub fn rejects_certificate(err: Error) -> Self { + MockServerVerifier { + cert_rejection_error: Some(err), + ..Default::default() + } + } + + pub fn rejects_tls12_signatures(err: Error) -> Self { + MockServerVerifier { + tls12_signature_error: Some(err), + ..Default::default() + } + } + + pub fn rejects_tls13_signatures(err: Error) -> Self { + MockServerVerifier { + tls13_signature_error: Some(err), + ..Default::default() + } + } + + pub fn offers_no_signature_schemes() -> Self { + MockServerVerifier { + signature_schemes: vec![], + ..Default::default() + } + } +} + +impl Default for MockServerVerifier { + fn default() -> Self { + MockServerVerifier { + cert_rejection_error: None, + tls12_signature_error: None, + tls13_signature_error: None, + wants_scts: false, + signature_schemes: WebPkiVerifier::verification_schemes(), + } + } +} diff --git a/vendor/rustls-pemfile-1.0.3/.cargo-checksum.json b/vendor/rustls-pemfile-1.0.3/.cargo-checksum.json new file mode 100644 index 0000000000000..939327e920bc3 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"be234573afd7a366ad573c45060edb18bd1638ef7d2eb8d9e19dc6cbd6b34e98","LICENSE":"c5dae4585d8520d1bc3d435dc5dd813be63046ebccc3c4eb866044eff304f0f0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-ISC":"7cfafc877eccc46c0e346ccbaa5c51bb6b894d2b818e617d970211e232785ad4","LICENSE-MIT":"709e3175b4212f7b13aa93971c9f62ff8c69ec45ad8c6532a7e0c41d7a7d6f8c","README.md":"96361e4f3047efea8bc9bfbc0b2062d7208dbb2c999653d674ec9b727329243e","benches/benchmark.rs":"5d6df302d2c6a3f7f280c2514e787618c705c35575a8af53d49a8bfe4d006d0f","src/lib.rs":"03a244d23462a5a4e36d09c65dc838c1a50925b80f1aecbc25b4511b6024bf52","src/pemfile.rs":"9e6bb5e718ea65ea1a5c8b50c049039a1336fffee2063ae183e4f2c871e3fef7","src/tests.rs":"f9d1987153def8da7c8f1cc0e806a0a21bfc9e4dcd760fb8e2cf32502fd578bf","tests/data/certificate.chain.pem":"2e3b21b8ebf92b0a9d1ef96760617f2b3b478b8f212c10529ac378e43e9d4355","tests/data/certificate.pem":"507a7fa0cc6686f9d85abc558d736758e45960603e676179c68bdb22e134492d","tests/data/crl.pem":"083899d2aa4a7ec954190d94d886330805f16aac8e1b3182b0f0e95d089475bc","tests/data/gunk.pem":"381e7674314b4febbceea89068a4b12ec3b657430130a81988791c8244537685","tests/data/nistp256curve.pem":"898060b4029e87abe913a1469ad502747638f82d02d900eaf8e3705245b290b4","tests/data/nistp256key.pem":"925e85506092acc867873d5b0c0df9183b66872e28013158cdcf5edeef655896","tests/data/nistp256key.pkcs8.pem":"fc69068da446ba4aa484b728e10d8af0eb1a7e6cd8b6dcdae329713237d596d7","tests/data/rsa1024.pkcs1.pem":"78762a98bf0b7719c467137f329b4a3b62c2ef9a70f47b115d6a7181172ae15e","tests/data/rsa1024.pkcs8.pem":"aaa1df8a578ed0a2ccf1f840a9c2cc22daa6cbef96d280ee1547aeddc855689b","tests/data/zen.pem":"083242da62cbaa367855b532a392841d7dd7152aeb21403f58b077d43224c11a","tests/data/zen2.pem":"a345f9d7f8a00ae4714f37b8a2865218d6a2301dd644272ac1fd8ba7871db07a","tests/integration.rs":"f989045b5c904c6308634373af41a6554bdf9b8e204425d325a60891da66d3fe"},"package":"2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"} \ No newline at end of file diff --git a/vendor/rustls-pemfile-1.0.3/Cargo.toml b/vendor/rustls-pemfile-1.0.3/Cargo.toml new file mode 100644 index 0000000000000..6d1f4e30e0ed3 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/Cargo.toml @@ -0,0 +1,34 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "rustls-pemfile" +version = "1.0.3" +description = "Basic .pem file parser for keys and certificates" +homepage = "https://github.com/rustls/pemfile" +readme = "README.md" +categories = [ + "network-programming", + "cryptography", +] +license = "Apache-2.0 OR ISC OR MIT" +repository = "https://github.com/rustls/pemfile" + +[[bench]] +name = "benchmark" +harness = false + +[dependencies.base64] +version = "0.21" + +[dev-dependencies.bencher] +version = "0.1.5" diff --git a/vendor/rustls-pemfile-1.0.3/LICENSE b/vendor/rustls-pemfile-1.0.3/LICENSE new file mode 100644 index 0000000000000..7ff7e59be34b8 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/LICENSE @@ -0,0 +1,10 @@ +rustls-pemfile is distributed under the following three licenses: + +- Apache License version 2.0. +- MIT license. +- ISC license. + +These are included as LICENSE-APACHE, LICENSE-MIT and LICENSE-ISC +respectively. You may use this software under the terms of any +of these licenses, at your option. + diff --git a/vendor/rustls-pemfile-1.0.3/LICENSE-APACHE b/vendor/rustls-pemfile-1.0.3/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/rustls-pemfile-1.0.3/LICENSE-ISC b/vendor/rustls-pemfile-1.0.3/LICENSE-ISC new file mode 100644 index 0000000000000..03acf1bd2c44c --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/LICENSE-ISC @@ -0,0 +1,15 @@ +ISC License (ISC) +Copyright (c) 2016, Joseph Birr-Pixton + +Permission to use, copy, modify, and/or distribute this software for +any purpose with or without fee is hereby granted, provided that the +above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/vendor/rustls-pemfile-1.0.3/LICENSE-MIT b/vendor/rustls-pemfile-1.0.3/LICENSE-MIT new file mode 100644 index 0000000000000..ef480e6f0936e --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Joseph Birr-Pixton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/rustls-pemfile-1.0.3/README.md b/vendor/rustls-pemfile-1.0.3/README.md new file mode 100644 index 0000000000000..f05d6c8fff040 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/README.md @@ -0,0 +1,39 @@ +# rustls-pemfile +This is a basic parser for PEM-encodings commonly used for storing keys and certificates at rest. + +It doesn't support reading encrypted keys: the cryptography standardised for this is typically very +poor and doing so doesn't address a meaningful threat model. + +[![Build Status](https://github.com/rustls/pemfile/workflows/rustls-pemfile/badge.svg)](https://github.com/rustls/pemfile/actions) +[![Crate](https://img.shields.io/crates/v/rustls-pemfile.svg)](https://crates.io/crates/rustls-pemfile) +[![Documentation](https://docs.rs/rustls-pemfile/badge.svg)](https://docs.rs/rustls-pemfile/) + +# Release history +- 1.0.3 (2023-06-28) + * Add certificate revocation list (CRL) format support. + * Add `crls` helper function. +- 1.0.2 (2023-01-10) + * Add `ec_private_keys()` helper function. + * Update base64 to the latest version. +- 1.0.1 (2022-08-02) + * Enable parsing PEM files with non-UTF-8 content between items. +- 1.0.0 (2022-04-14) + * Initial stable release. No API changes. +- 0.3.0 (2022-02-05) + * Add SEC1 EC key format support (ie, "EC PRIVATE KEY" sections) thanks to @farcaller. + * Make `Item` enum non-exhaustive. +- 0.2.1 (2021-04-17) + * Performance improvements thanks to @zz85. +- 0.2.0 (2020-12-28) + * Initial release. + +# License +rustls-pemfile is distributed under the following three licenses: + +- Apache License version 2.0. +- MIT license. +- ISC license. + +These are included as LICENSE-APACHE, LICENSE-MIT and LICENSE-ISC +respectively. You may use this software under the terms of any +of these licenses, at your option. diff --git a/vendor/rustls-pemfile-1.0.3/benches/benchmark.rs b/vendor/rustls-pemfile-1.0.3/benches/benchmark.rs new file mode 100644 index 0000000000000..1ebeb6438502d --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/benches/benchmark.rs @@ -0,0 +1,14 @@ +use std::io::BufReader; + +use bencher::{benchmark_group, benchmark_main, Bencher}; + +fn criterion_benchmark(c: &mut Bencher) { + c.iter(|| { + let data = include_bytes!("../tests/data/certificate.chain.pem"); + let mut reader = BufReader::new(&data[..]); + assert_eq!(rustls_pemfile::certs(&mut reader).unwrap().len(), 3); + }); +} + +benchmark_group!(benches, criterion_benchmark); +benchmark_main!(benches); diff --git a/vendor/rustls-pemfile-1.0.3/src/lib.rs b/vendor/rustls-pemfile-1.0.3/src/lib.rs new file mode 100644 index 0000000000000..9b9edc1e45181 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/src/lib.rs @@ -0,0 +1,137 @@ +//! # rustls-pemfile +//! A basic parser for .pem files containing cryptographic keys and certificates. +//! +//! The input to this crate is a .pem file containing potentially many sections, +//! and the output is those sections as alleged DER-encodings. This crate does +//! not decode the actual DER-encoded keys/certificates. +//! +//! ## Quick start +//! Starting with an `io::BufRead` containing the file to be read: +//! - Use `read_all()` to ingest the whole file, then work through the contents in-memory, or, +//! - Use `read_one()` to stream through the file, processing the items as found, or, +//! - Use `certs()` to extract just the certificates (silently discarding other sections), and +//! similarly for `rsa_private_keys()` and `pkcs8_private_keys()`. +//! +//! ## Example code +//! ``` +//! use std::iter; +//! use rustls_pemfile::{Item, read_one}; +//! # let mut reader = std::io::BufReader::new(&b"junk\n-----BEGIN RSA PRIVATE KEY-----\nqw\n-----END RSA PRIVATE KEY-----\n"[..]); +//! // Assume `reader` is any std::io::BufRead implementor +//! for item in iter::from_fn(|| read_one(&mut reader).transpose()) { +//! match item.unwrap() { +//! Item::X509Certificate(cert) => println!("certificate {:?}", cert), +//! Item::Crl(crl) => println!("certificate revocation list: {:?}", crl), +//! Item::RSAKey(key) => println!("rsa pkcs1 key {:?}", key), +//! Item::PKCS8Key(key) => println!("pkcs8 key {:?}", key), +//! Item::ECKey(key) => println!("sec1 ec key {:?}", key), +//! _ => println!("unhandled item"), +//! } +//! } +//! ``` + +// Require docs for public APIs, deny unsafe code, etc. +#![forbid(unsafe_code, unused_must_use, unstable_features)] +#![deny( + trivial_casts, + trivial_numeric_casts, + missing_docs, + unused_import_braces, + unused_extern_crates, + unused_qualifications +)] + +#[cfg(test)] +mod tests; + +/// --- Main crate APIs: +mod pemfile; +pub use pemfile::{read_all, read_one, Item}; + +/// --- Legacy APIs: +use std::io; + +/// Extract all the certificates from `rd`, and return a vec of byte vecs +/// containing the der-format contents. +/// +/// This function does not fail if there are no certificates in the file -- +/// it returns an empty vector. +pub fn certs(rd: &mut dyn io::BufRead) -> Result>, io::Error> { + let mut certs = Vec::new(); + + loop { + match read_one(rd)? { + None => return Ok(certs), + Some(Item::X509Certificate(cert)) => certs.push(cert), + _ => {} + }; + } +} + +/// Extract all the certificate revocation lists (CRLs) from `rd`, and return a vec of byte vecs +/// containing the der-format contents. +/// +/// This function does not fail if there are no CRLs in the file -- +/// it returns an empty vector. +pub fn crls(rd: &mut dyn io::BufRead) -> Result>, io::Error> { + let mut crls = Vec::new(); + + loop { + match read_one(rd)? { + None => return Ok(crls), + Some(Item::Crl(crl)) => crls.push(crl), + _ => {} + }; + } +} + +/// Extract all RSA private keys from `rd`, and return a vec of byte vecs +/// containing the der-format contents. +/// +/// This function does not fail if there are no keys in the file -- it returns an +/// empty vector. +pub fn rsa_private_keys(rd: &mut dyn io::BufRead) -> Result>, io::Error> { + let mut keys = Vec::new(); + + loop { + match read_one(rd)? { + None => return Ok(keys), + Some(Item::RSAKey(key)) => keys.push(key), + _ => {} + }; + } +} + +/// Extract all PKCS8-encoded private keys from `rd`, and return a vec of +/// byte vecs containing the der-format contents. +/// +/// This function does not fail if there are no keys in the file -- it returns an +/// empty vector. +pub fn pkcs8_private_keys(rd: &mut dyn io::BufRead) -> Result>, io::Error> { + let mut keys = Vec::new(); + + loop { + match read_one(rd)? { + None => return Ok(keys), + Some(Item::PKCS8Key(key)) => keys.push(key), + _ => {} + }; + } +} + +/// Extract all SEC1-encoded EC private keys from `rd`, and return a vec of +/// byte vecs containing the der-format contents. +/// +/// This function does not fail if there are no keys in the file -- it returns an +/// empty vector. +pub fn ec_private_keys(rd: &mut dyn io::BufRead) -> Result>, io::Error> { + let mut keys = Vec::new(); + + loop { + match read_one(rd)? { + None => return Ok(keys), + Some(Item::ECKey(key)) => keys.push(key), + _ => {} + }; + } +} diff --git a/vendor/rustls-pemfile-1.0.3/src/pemfile.rs b/vendor/rustls-pemfile-1.0.3/src/pemfile.rs new file mode 100644 index 0000000000000..32941da24f83d --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/src/pemfile.rs @@ -0,0 +1,150 @@ +use std::io::{self, ErrorKind}; + +/// The contents of a single recognised block in a PEM file. +#[non_exhaustive] +#[derive(Debug, PartialEq)] +pub enum Item { + /// A DER-encoded x509 certificate. + X509Certificate(Vec), + + /// A DER-encoded plaintext RSA private key; as specified in PKCS#1/RFC3447 + RSAKey(Vec), + + /// A DER-encoded plaintext private key; as specified in PKCS#8/RFC5958 + PKCS8Key(Vec), + + /// A Sec1-encoded plaintext private key; as specified in RFC5915 + ECKey(Vec), + + /// A Certificate Revocation List; as specified in RFC5280 + Crl(Vec), +} + +impl Item { + fn from_start_line(start_line: &[u8], der: Vec) -> Option { + match start_line { + b"CERTIFICATE" => Some(Item::X509Certificate(der)), + b"RSA PRIVATE KEY" => Some(Item::RSAKey(der)), + b"PRIVATE KEY" => Some(Item::PKCS8Key(der)), + b"EC PRIVATE KEY" => Some(Item::ECKey(der)), + b"X509 CRL" => Some(Item::Crl(der)), + _ => None, + } + } +} + +/// Extract and decode the next PEM section from `rd`. +/// +/// - Ok(None) is returned if there is no PEM section read from `rd`. +/// - Underlying IO errors produce a `Err(...)` +/// - Otherwise each decoded section is returned with a `Ok(Some(Item::...))` +/// +/// You can use this function to build an iterator, for example: +/// `for item in iter::from_fn(|| read_one(rd).transpose()) { ... }` +pub fn read_one(rd: &mut dyn io::BufRead) -> Result, io::Error> { + let mut b64buf = Vec::with_capacity(1024); + let mut section = None::<(Vec<_>, Vec<_>)>; + let mut line = Vec::with_capacity(80); + + loop { + line.clear(); + let len = rd.read_until(b'\n', &mut line)?; + + if len == 0 { + // EOF + return match section { + Some((_, end_marker)) => Err(io::Error::new( + ErrorKind::InvalidData, + format!( + "section end {:?} missing", + String::from_utf8_lossy(&end_marker) + ), + )), + None => Ok(None), + }; + } + + if line.starts_with(b"-----BEGIN ") { + let (mut trailer, mut pos) = (0, line.len()); + for (i, &b) in line.iter().enumerate().rev() { + match b { + b'-' => { + trailer += 1; + pos = i; + } + b'\n' | b'\r' | b' ' => continue, + _ => break, + } + } + + if trailer != 5 { + return Err(io::Error::new( + ErrorKind::InvalidData, + format!( + "illegal section start: {:?}", + String::from_utf8_lossy(&line) + ), + )); + } + + let ty = &line[11..pos]; + let mut end = Vec::with_capacity(10 + 4 + ty.len()); + end.extend_from_slice(b"-----END "); + end.extend_from_slice(ty); + end.extend_from_slice(b"-----"); + section = Some((ty.to_owned(), end)); + continue; + } + + if let Some((section_type, end_marker)) = section.as_ref() { + if line.starts_with(end_marker) { + let der = base64::ENGINE + .decode(&b64buf) + .map_err(|err| io::Error::new(ErrorKind::InvalidData, err))?; + + if let Some(item) = Item::from_start_line(section_type, der) { + return Ok(Some(item)); + } else { + section = None; + b64buf.clear(); + } + } + } + + if section.is_some() { + let mut trim = 0; + for &b in line.iter().rev() { + match b { + b'\n' | b'\r' | b' ' => trim += 1, + _ => break, + } + } + b64buf.extend(&line[..line.len() - trim]); + } + } +} + +/// Extract and return all PEM sections by reading `rd`. +pub fn read_all(rd: &mut dyn io::BufRead) -> Result, io::Error> { + let mut v = Vec::::new(); + + loop { + match read_one(rd)? { + None => return Ok(v), + Some(item) => v.push(item), + } + } +} + +mod base64 { + use base64::alphabet::STANDARD; + use base64::engine::general_purpose::{GeneralPurpose, GeneralPurposeConfig}; + use base64::engine::DecodePaddingMode; + pub(super) use base64::engine::Engine; + + pub(super) const ENGINE: GeneralPurpose = GeneralPurpose::new( + &STANDARD, + GeneralPurposeConfig::new().with_decode_padding_mode(DecodePaddingMode::Indifferent), + ); +} +use self::base64::Engine; diff --git a/vendor/rustls-pemfile-1.0.3/src/tests.rs b/vendor/rustls-pemfile-1.0.3/src/tests.rs new file mode 100644 index 0000000000000..f51c1d15622fc --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/src/tests.rs @@ -0,0 +1,100 @@ +#[cfg(test)] +mod unit { + fn check(data: &[u8]) -> Result, std::io::Error> { + let mut reader = std::io::BufReader::new(data); + crate::read_all(&mut reader) + } + + #[test] + fn skips_leading_junk() { + assert_eq!( + check( + b"junk\n\ + -----BEGIN RSA PRIVATE KEY-----\n\ + qw\n\ + -----END RSA PRIVATE KEY-----\n" + ) + .unwrap(), + vec![crate::Item::RSAKey(vec![0xab])] + ); + } + + #[test] + fn skips_trailing_junk() { + assert_eq!( + check( + b"-----BEGIN RSA PRIVATE KEY-----\n\ + qw\n\ + -----END RSA PRIVATE KEY-----\n\ + junk" + ) + .unwrap(), + vec![crate::Item::RSAKey(vec![0xab])] + ); + } + + #[test] + fn skips_non_utf8_junk() { + assert_eq!( + check( + b"\x00\x00\n\ + -----BEGIN RSA PRIVATE KEY-----\n\ + qw\n\ + -----END RSA PRIVATE KEY-----\n + \x00\x00" + ) + .unwrap(), + vec![crate::Item::RSAKey(vec![0xab])] + ); + } + + #[test] + fn rejects_invalid_base64() { + assert_eq!( + format!( + "{:?}", + check( + b"-----BEGIN RSA PRIVATE KEY-----\n\ + q=w\n\ + -----END RSA PRIVATE KEY-----\n" + ) + ), + "Err(Custom { kind: InvalidData, error: InvalidByte(1, 61) })" + ); + } + + #[test] + fn rejects_unclosed_start_section() { + assert_eq!( + format!("{:?}", + check(b"-----BEGIN RSA PRIVATE KEY-----\n\ + qw\n")), + "Err(Custom { kind: InvalidData, error: \"section end \\\"-----END RSA PRIVATE KEY-----\\\" missing\" })" + ); + } + + #[test] + fn rejects_bad_start() { + assert_eq!( + format!("{:?}", + check(b"-----BEGIN RSA PRIVATE KEY----\n\ + qw\n\ + -----END RSA PRIVATE KEY-----\n")), + "Err(Custom { kind: InvalidData, error: \"illegal section start: \\\"-----BEGIN RSA PRIVATE KEY----\\\\n\\\"\" })" + ); + } + + #[test] + fn skips_unrecognised_section() { + assert_eq!( + check( + b"junk\n\ + -----BEGIN BREAKFAST CLUB-----\n\ + qw\n\ + -----END BREAKFAST CLUB-----\n" + ) + .unwrap(), + vec![] + ); + } +} diff --git a/vendor/rustls-pemfile-1.0.3/tests/data/certificate.chain.pem b/vendor/rustls-pemfile-1.0.3/tests/data/certificate.chain.pem new file mode 100644 index 0000000000000..b7db4269cabe8 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/tests/data/certificate.chain.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIBuDCCAWqgAwIBAgICAcgwBQYDK2VwMC4xLDAqBgNVBAMMI3Bvbnl0b3duIEVk +RFNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTE5MDgxNjEzMjg1MVoXDTI1MDIw +NTEzMjg1MVowGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wKjAFBgMrZXADIQAQ +9M4hrE+Ucw4QUmaKOeKfphklBJi1qsqtX4u+knbseqOBwDCBvTAMBgNVHRMBAf8E +AjAAMAsGA1UdDwQEAwIGwDAdBgNVHQ4EFgQUa/gnV4+a22BUKTouAYX6nfLnPKYw +RAYDVR0jBD0wO4AUFxIwU406tG3CsPWkHWqfuUT48auhIKQeMBwxGjAYBgNVBAMM +EXBvbnl0b3duIEVkRFNBIENBggF7MDsGA1UdEQQ0MDKCDnRlc3RzZXJ2ZXIuY29t +ghVzZWNvbmQudGVzdHNlcnZlci5jb22CCWxvY2FsaG9zdDAFBgMrZXADQQApDiBQ +ns3fuvsWuFpIS+osj2B/gQ0b6eBAZ1UBxRyDlAo5++JZ0PtaEROyGo2t2gqi2Lyz +47mLyGCvqgVbC6cH +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBVzCCAQmgAwIBAgIBezAFBgMrZXAwHDEaMBgGA1UEAwwRcG9ueXRvd24gRWRE +U0EgQ0EwHhcNMTkwODE2MTMyODUxWhcNMjkwODEzMTMyODUxWjAuMSwwKgYDVQQD +DCNwb255dG93biBFZERTQSBsZXZlbCAyIGludGVybWVkaWF0ZTAqMAUGAytlcAMh +AD4h3t0UCoMDGgIq4UW4P5zDngsY4vy1pE3wzLPFI4Vdo14wXDAdBgNVHQ4EFgQU +FxIwU406tG3CsPWkHWqfuUT48aswIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsG +AQUFBwMCMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgH+MAUGAytlcANBAAZFvMek +Z71I8CXsBmx/0E6Weoaan9mJHgKqgQdK4w4h4dRg6DjNG957IbrLFO3vZduBMnna +qHP3xTFF+11Eyg8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBTDCB/6ADAgECAhRXcvbYynz4+usVvPtJp++sBUih3TAFBgMrZXAwHDEaMBgG +A1UEAwwRcG9ueXRvd24gRWREU0EgQ0EwHhcNMTkwODE2MTMyODUwWhcNMjkwODEz +MTMyODUwWjAcMRowGAYDVQQDDBFwb255dG93biBFZERTQSBDQTAqMAUGAytlcAMh +AIE4tLweIfcBGfhPqyXFp5pjVxjaiKk+9fTbRy46jAFKo1MwUTAdBgNVHQ4EFgQU +z5b9HjkOxffbtCZhWGg+bnxuD6wwHwYDVR0jBBgwFoAUz5b9HjkOxffbtCZhWGg+ +bnxuD6wwDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXADQQBNlt7z4bZ7KhzecxZEe3i5 +lH9MRqbpP9Rg4HyzAJfTzFGT183HoJiISdPLbxwMn0KaqSGlVe+9GgNKswoaRAwH +-----END CERTIFICATE----- diff --git a/vendor/rustls-pemfile-1.0.3/tests/data/certificate.pem b/vendor/rustls-pemfile-1.0.3/tests/data/certificate.pem new file mode 100644 index 0000000000000..74d4a01659d0b --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/tests/data/certificate.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEnzCCAoegAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255 +dG93biBSU0EgQ0EwHhcNMTkwNjA5MTcxNTEyWhcNMjkwNjA2MTcxNTEyWjAsMSow +KAYDVQQDDCFwb255dG93biBSU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwggGiMA0G +CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCj/tOFeSW3WB+TtuLCR1L/84lZytFw +zbpzOTGB1kPEKNbrMsv3lHXm5bHa8Bl3k113k7Hi7OAt/nkMm05s8LcUoovhaG5C +G7tjzL+ld1nO74gNS3IQHCzxRdRwIgaDZHyICfBQBfB9/m+9z3yRtOKWJl6i/MT9 +HRN6yADW/8gHFlMzRkCKBjIKXehKsu8cbtB+5MukwtXI4rKf9aYXZQOEUn1kEwQJ +ZIKBXR0eyloQiZervUE7meRCTBvzXT9VoSEX49/mempp4hnfdHlRNzre4/tphBf1 +fRUdpVXZ3DvmzoHdXRVzxx3X5LvDpf7Eb3ViGkXDFwkSfHEhkRnAl4lIzTH/1F25 +stmT8a0PA/lCNMrzJBzkLcuem1G1uMHoQZo1f3OpslJ8gHbE9ZlIbIKmpmJS9oop +Vh1BH+aOy5doCrF8uOLTQ3d5CqA/EZMGahDHy7IkeNYmG/RXUKNltv+r95gwuRP+ +9UIJ9FTa4REQbIpGWP5XibI6x4LqLTJj+VsCAwEAAaNeMFwwHQYDVR0OBBYEFEKP +y8hHZVazpvIsxFcGo4YrkEkwMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF +BQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jANBgkqhkiG9w0BAQsFAAOC +AgEAMzTRDLBExVFlw98AuX+pM+/R2Gjw5KFHvSYLKLbMRfuuZK1yNYYaYtNrtF+V +a53OFgaZj56o7tXc2PB8kw4MELD0ViR8Do2bvZieFcEe4DwhdjGCjuLehVLT29qI +7T3N/JkJ5daemKZcRB6Ne0F4+6QlVVNck28HUKbQThl88RdwLUImmSAfgKSt6uJ5 +wlH7wiYQR2vPXwSuEYzwot+L/91eBwuQr4Lovx9+TCKTbwQOKYjX4KfcOOQ1rx0M +IMrvwWqnabc6m1F0O6//ibL0kuFkJYEgOH2uJA12FBHO+/q2tcytejkOWKWMJj6Y +2etwIHcpzXaEP7fZ75cFGqcE3s7XGsweBIPLjMP1bKxEcFKzygURm/auUuXBCFBl +E16PB6JEAeCKe/8VFeyucvjPuQDWB49aq+r2SbpbI4IeZdz/QgEIOb0MpwStrvhH +9f/DtGMbjvuAEkRoOorK4m5k4GY3LsWTR2bey27AXk8N7pKarpu2N7ChBPm+EV0Y +H+tAI/OfdZuNUCES00F5UAFdU8zBUZo19ao2ZqfEADimE7Epk2s0bUe4GSqEXJp6 +68oVSMhZmMf/RCSNlr97f34sNiUA1YJ0JbCRZmw8KWNm9H1PARLbrgeRBZ/k31Li +WLDr3fiEVk7SGxj3zo94cS6AT55DyXLiSD/bFmL1QXgZweA= +-----END CERTIFICATE----- diff --git a/vendor/rustls-pemfile-1.0.3/tests/data/crl.pem b/vendor/rustls-pemfile-1.0.3/tests/data/crl.pem new file mode 100644 index 0000000000000..adda089e6adf0 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/tests/data/crl.pem @@ -0,0 +1,16 @@ +-----BEGIN X509 CRL----- +MIICiTBzAgEBMA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNVBAMMD3Bvbnl0b3duIFJT +QSBDQRcNMjMwNjI3MDgyODEyWhcNMjMwNzI3MDgyODEyWjAVMBMCAgHIFw0yMzA2 +MjcwODI3NTlaoA4wDDAKBgNVHRQEAwIBAjANBgkqhkiG9w0BAQsFAAOCAgEAP6EX +9+hxjx/AqdBpynZXjGkEqigBcLcJ2PADOXngdQI1jC0WuYnZymUimemeULtt8X+1 +ai2KxAuF1m4NEKZsrGKvO+/9s/X1xbGroyHSAMKtZafFopFpoB2aNbYlx7yIyLtD +BBIZIF50g20U+3izqpHutTD10itdk9TLsSceJHpwTkNJtaWMkOfBV28nKzEzVutV +f6WzRpURGzui6nQy7aIqImeanpoBoz323psMfC32U0uMBCZltyHNqsX58/2Uhucx +0IPnitNuhv4scCPf/jeRfGIWDrTf1/25LDzRxyg1S4z9aa+3GM4O3dqy4igZEhgT +q3pjlJ2hUL5E0oqbZDIQD1SN8UUUv5N2AjwZcxVBNnYeGyuO7YpTBYiu62o73iL2 +CjgElfaMq/9hEr9GR9kJozh7VTxtQPbnr4DiucQvhv8o/A1z+zkC0gj8iCLFtDbO +8bvDowcdle9LKkrLaBe6sO+fSH/I9Wj8vrEJKsuwaEraIdEaq2VrIMUPEWN0/MH9 +vTwHyadGSMK4CWtrn9fCAgSLw6NX74D7Cx1IaS8vstMjpeUqOS0dk5ThiW47HceB +DTko7rV5N+RGH2nW1ynLoZKCJQqqZcLilFMyKPui3jifJnQlMFi54jGVgg/D6UQn +7dA7wb2ux/1hSiaarp+mi7ncVOyByz6/WQP8mfc= +-----END X509 CRL----- diff --git a/vendor/rustls-pemfile-1.0.3/tests/data/gunk.pem b/vendor/rustls-pemfile-1.0.3/tests/data/gunk.pem new file mode 100644 index 0000000000000..fa11b6cf8c41f Binary files /dev/null and b/vendor/rustls-pemfile-1.0.3/tests/data/gunk.pem differ diff --git a/vendor/rustls-pemfile-1.0.3/tests/data/nistp256curve.pem b/vendor/rustls-pemfile-1.0.3/tests/data/nistp256curve.pem new file mode 100644 index 0000000000000..a76e47d9590ba --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/tests/data/nistp256curve.pem @@ -0,0 +1,3 @@ +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- diff --git a/vendor/rustls-pemfile-1.0.3/tests/data/nistp256key.pem b/vendor/rustls-pemfile-1.0.3/tests/data/nistp256key.pem new file mode 100644 index 0000000000000..943a7694ab298 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/tests/data/nistp256key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIMaA7bFrjDDBSik057bIKo7UQXJZNwLK9AjYZQ7yIWFloAoGCCqGSM49 +AwEHoUQDQgAExu0Z/w8nQJZAXeOXOnZun9HiZscY9H/KwYcXpeZHu+f9P9mOUEkH +5Z0av+JKtzhFspjngNLVgWcjlA1L5AJLdA== +-----END EC PRIVATE KEY----- diff --git a/vendor/rustls-pemfile-1.0.3/tests/data/nistp256key.pkcs8.pem b/vendor/rustls-pemfile-1.0.3/tests/data/nistp256key.pkcs8.pem new file mode 100644 index 0000000000000..aae49672bc3c0 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/tests/data/nistp256key.pkcs8.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgxoDtsWuMMMFKKTTn +tsgqjtRBclk3Asr0CNhlDvIhYWWhRANCAATG7Rn/DydAlkBd45c6dm6f0eJmxxj0 +f8rBhxel5ke75/0/2Y5QSQflnRq/4kq3OEWymOeA0tWBZyOUDUvkAkt0 +-----END PRIVATE KEY----- diff --git a/vendor/rustls-pemfile-1.0.3/tests/data/rsa1024.pkcs1.pem b/vendor/rustls-pemfile-1.0.3/tests/data/rsa1024.pkcs1.pem new file mode 100644 index 0000000000000..0074a0e2bd641 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/tests/data/rsa1024.pkcs1.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQC1Dt8tFmGS76ciuNXvk/QRrV8wCcArWxvl7Ku0aSQXgcFBAav6 +P5RD8b+dC9DihSu/r+6OOfjsAZ6oKCq3OTUfmoUhLpoBomxPczJgLyyLD+nQkp5q +B1Q3WB6ACL/HJRRjJEIn7lc5u1FVBGbiCAHKMiaP4BDSym8oqimKC6uiaQIDAQAB +AoGAGKmY7sxQqDIqwwkIYyT1Jv9FqwZ4/a7gYvZVATMdLnKHP3KZ2XGVoZepcRvt +7R0Us3ykcw0kgglKcj9eaizJtnSuoDPPwt53mDypPN2sU3hZgyk2tPgr49DB3MIp +fjoqw4RL/p60ksgGXbDEqBuXqOtH5i61khWlMj+BWL9VDq0CQQDaELWPQGjgs+7X +/QyWMJwOF4FXE4jecH/CcPVDB9K1ukllyC1HqTNe44Sp2bIDuSXXWb8yEixrEWBE +ci2CSSjXAkEA1I4W9IzwEmAeLtL6VBip9ks52O0JKu373/Xv1F2GYdhnQaFw7IC6 +1lSzcYMKGTmDuM8Cj26caldyv19Q0SPmvwJAdRHjZzS9GWWAJJTF3Rvbq/USix0B +renXrRvXkFTy2n1YSjxdkstTuO2Mm2M0HquXlTWpX8hB8HkzpYtmwztjoQJAECKl +LXVReCOhxu4vIJkqtc6qGoSL8J1WRH8X8KgU3nKeDAZkWx++jyyo3pIS/y01iZ71 +U8wSxaPTyyFCMk4mYwJBALjg7g8yDy1Lg9GFfOZvAVzPjqD28jZh/VJsDz9IhYoG +z89iHWHkllOisbOm+SeynVC8CoFXmJPc26U65GcjI18= +-----END RSA PRIVATE KEY----- diff --git a/vendor/rustls-pemfile-1.0.3/tests/data/rsa1024.pkcs8.pem b/vendor/rustls-pemfile-1.0.3/tests/data/rsa1024.pkcs8.pem new file mode 100644 index 0000000000000..16a17c7bb87a4 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/tests/data/rsa1024.pkcs8.pem @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALUO3y0WYZLvpyK4 +1e+T9BGtXzAJwCtbG+Xsq7RpJBeBwUEBq/o/lEPxv50L0OKFK7+v7o45+OwBnqgo +Krc5NR+ahSEumgGibE9zMmAvLIsP6dCSnmoHVDdYHoAIv8clFGMkQifuVzm7UVUE +ZuIIAcoyJo/gENLKbyiqKYoLq6JpAgMBAAECgYAYqZjuzFCoMirDCQhjJPUm/0Wr +Bnj9ruBi9lUBMx0ucoc/cpnZcZWhl6lxG+3tHRSzfKRzDSSCCUpyP15qLMm2dK6g +M8/C3neYPKk83axTeFmDKTa0+Cvj0MHcwil+OirDhEv+nrSSyAZdsMSoG5eo60fm +LrWSFaUyP4FYv1UOrQJBANoQtY9AaOCz7tf9DJYwnA4XgVcTiN5wf8Jw9UMH0rW6 +SWXILUepM17jhKnZsgO5JddZvzISLGsRYERyLYJJKNcCQQDUjhb0jPASYB4u0vpU +GKn2SznY7Qkq7fvf9e/UXYZh2GdBoXDsgLrWVLNxgwoZOYO4zwKPbpxqV3K/X1DR +I+a/AkB1EeNnNL0ZZYAklMXdG9ur9RKLHQGt6detG9eQVPLafVhKPF2Sy1O47Yyb +YzQeq5eVNalfyEHweTOli2bDO2OhAkAQIqUtdVF4I6HG7i8gmSq1zqoahIvwnVZE +fxfwqBTecp4MBmRbH76PLKjekhL/LTWJnvVTzBLFo9PLIUIyTiZjAkEAuODuDzIP +LUuD0YV85m8BXM+OoPbyNmH9UmwPP0iFigbPz2IdYeSWU6Kxs6b5J7KdULwKgVeY +k9zbpTrkZyMjXw== +-----END PRIVATE KEY----- diff --git a/vendor/rustls-pemfile-1.0.3/tests/data/zen.pem b/vendor/rustls-pemfile-1.0.3/tests/data/zen.pem new file mode 100644 index 0000000000000..a62add209bb13 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/tests/data/zen.pem @@ -0,0 +1,120 @@ +one with everything +-----BEGIN CERTIFICATE----- +MIIBuDCCAWqgAwIBAgICAcgwBQYDK2VwMC4xLDAqBgNVBAMMI3Bvbnl0b3duIEVk +RFNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTE5MDgxNjEzMjg1MVoXDTI1MDIw +NTEzMjg1MVowGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wKjAFBgMrZXADIQAQ +9M4hrE+Ucw4QUmaKOeKfphklBJi1qsqtX4u+knbseqOBwDCBvTAMBgNVHRMBAf8E +AjAAMAsGA1UdDwQEAwIGwDAdBgNVHQ4EFgQUa/gnV4+a22BUKTouAYX6nfLnPKYw +RAYDVR0jBD0wO4AUFxIwU406tG3CsPWkHWqfuUT48auhIKQeMBwxGjAYBgNVBAMM +EXBvbnl0b3duIEVkRFNBIENBggF7MDsGA1UdEQQ0MDKCDnRlc3RzZXJ2ZXIuY29t +ghVzZWNvbmQudGVzdHNlcnZlci5jb22CCWxvY2FsaG9zdDAFBgMrZXADQQApDiBQ +ns3fuvsWuFpIS+osj2B/gQ0b6eBAZ1UBxRyDlAo5++JZ0PtaEROyGo2t2gqi2Lyz +47mLyGCvqgVbC6cH +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBVzCCAQmgAwIBAgIBezAFBgMrZXAwHDEaMBgGA1UEAwwRcG9ueXRvd24gRWRE +U0EgQ0EwHhcNMTkwODE2MTMyODUxWhcNMjkwODEzMTMyODUxWjAuMSwwKgYDVQQD +DCNwb255dG93biBFZERTQSBsZXZlbCAyIGludGVybWVkaWF0ZTAqMAUGAytlcAMh +AD4h3t0UCoMDGgIq4UW4P5zDngsY4vy1pE3wzLPFI4Vdo14wXDAdBgNVHQ4EFgQU +FxIwU406tG3CsPWkHWqfuUT48aswIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsG +AQUFBwMCMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgH+MAUGAytlcANBAAZFvMek +Z71I8CXsBmx/0E6Weoaan9mJHgKqgQdK4w4h4dRg6DjNG957IbrLFO3vZduBMnna +qHP3xTFF+11Eyg8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBTDCB/6ADAgECAhRXcvbYynz4+usVvPtJp++sBUih3TAFBgMrZXAwHDEaMBgG +A1UEAwwRcG9ueXRvd24gRWREU0EgQ0EwHhcNMTkwODE2MTMyODUwWhcNMjkwODEz +MTMyODUwWjAcMRowGAYDVQQDDBFwb255dG93biBFZERTQSBDQTAqMAUGAytlcAMh +AIE4tLweIfcBGfhPqyXFp5pjVxjaiKk+9fTbRy46jAFKo1MwUTAdBgNVHQ4EFgQU +z5b9HjkOxffbtCZhWGg+bnxuD6wwHwYDVR0jBBgwFoAUz5b9HjkOxffbtCZhWGg+ +bnxuD6wwDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXADQQBNlt7z4bZ7KhzecxZEe3i5 +lH9MRqbpP9Rg4HyzAJfTzFGT183HoJiISdPLbxwMn0KaqSGlVe+9GgNKswoaRAwH +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEnzCCAoegAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255 +dG93biBSU0EgQ0EwHhcNMTkwNjA5MTcxNTEyWhcNMjkwNjA2MTcxNTEyWjAsMSow +KAYDVQQDDCFwb255dG93biBSU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwggGiMA0G +CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCj/tOFeSW3WB+TtuLCR1L/84lZytFw +zbpzOTGB1kPEKNbrMsv3lHXm5bHa8Bl3k113k7Hi7OAt/nkMm05s8LcUoovhaG5C +G7tjzL+ld1nO74gNS3IQHCzxRdRwIgaDZHyICfBQBfB9/m+9z3yRtOKWJl6i/MT9 +HRN6yADW/8gHFlMzRkCKBjIKXehKsu8cbtB+5MukwtXI4rKf9aYXZQOEUn1kEwQJ +ZIKBXR0eyloQiZervUE7meRCTBvzXT9VoSEX49/mempp4hnfdHlRNzre4/tphBf1 +fRUdpVXZ3DvmzoHdXRVzxx3X5LvDpf7Eb3ViGkXDFwkSfHEhkRnAl4lIzTH/1F25 +stmT8a0PA/lCNMrzJBzkLcuem1G1uMHoQZo1f3OpslJ8gHbE9ZlIbIKmpmJS9oop +Vh1BH+aOy5doCrF8uOLTQ3d5CqA/EZMGahDHy7IkeNYmG/RXUKNltv+r95gwuRP+ +9UIJ9FTa4REQbIpGWP5XibI6x4LqLTJj+VsCAwEAAaNeMFwwHQYDVR0OBBYEFEKP +y8hHZVazpvIsxFcGo4YrkEkwMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF +BQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jANBgkqhkiG9w0BAQsFAAOC +AgEAMzTRDLBExVFlw98AuX+pM+/R2Gjw5KFHvSYLKLbMRfuuZK1yNYYaYtNrtF+V +a53OFgaZj56o7tXc2PB8kw4MELD0ViR8Do2bvZieFcEe4DwhdjGCjuLehVLT29qI +7T3N/JkJ5daemKZcRB6Ne0F4+6QlVVNck28HUKbQThl88RdwLUImmSAfgKSt6uJ5 +wlH7wiYQR2vPXwSuEYzwot+L/91eBwuQr4Lovx9+TCKTbwQOKYjX4KfcOOQ1rx0M +IMrvwWqnabc6m1F0O6//ibL0kuFkJYEgOH2uJA12FBHO+/q2tcytejkOWKWMJj6Y +2etwIHcpzXaEP7fZ75cFGqcE3s7XGsweBIPLjMP1bKxEcFKzygURm/auUuXBCFBl +E16PB6JEAeCKe/8VFeyucvjPuQDWB49aq+r2SbpbI4IeZdz/QgEIOb0MpwStrvhH +9f/DtGMbjvuAEkRoOorK4m5k4GY3LsWTR2bey27AXk8N7pKarpu2N7ChBPm+EV0Y +H+tAI/OfdZuNUCES00F5UAFdU8zBUZo19ao2ZqfEADimE7Epk2s0bUe4GSqEXJp6 +68oVSMhZmMf/RCSNlr97f34sNiUA1YJ0JbCRZmw8KWNm9H1PARLbrgeRBZ/k31Li +WLDr3fiEVk7SGxj3zo94cS6AT55DyXLiSD/bFmL1QXgZweA= +-----END CERTIFICATE----- +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIMaA7bFrjDDBSik057bIKo7UQXJZNwLK9AjYZQ7yIWFloAoGCCqGSM49 +AwEHoUQDQgAExu0Z/w8nQJZAXeOXOnZun9HiZscY9H/KwYcXpeZHu+f9P9mOUEkH +5Z0av+JKtzhFspjngNLVgWcjlA1L5AJLdA== +-----END EC PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgxoDtsWuMMMFKKTTn +tsgqjtRBclk3Asr0CNhlDvIhYWWhRANCAATG7Rn/DydAlkBd45c6dm6f0eJmxxj0 +f8rBhxel5ke75/0/2Y5QSQflnRq/4kq3OEWymOeA0tWBZyOUDUvkAkt0 +-----END PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQC1Dt8tFmGS76ciuNXvk/QRrV8wCcArWxvl7Ku0aSQXgcFBAav6 +P5RD8b+dC9DihSu/r+6OOfjsAZ6oKCq3OTUfmoUhLpoBomxPczJgLyyLD+nQkp5q +B1Q3WB6ACL/HJRRjJEIn7lc5u1FVBGbiCAHKMiaP4BDSym8oqimKC6uiaQIDAQAB +AoGAGKmY7sxQqDIqwwkIYyT1Jv9FqwZ4/a7gYvZVATMdLnKHP3KZ2XGVoZepcRvt +7R0Us3ykcw0kgglKcj9eaizJtnSuoDPPwt53mDypPN2sU3hZgyk2tPgr49DB3MIp +fjoqw4RL/p60ksgGXbDEqBuXqOtH5i61khWlMj+BWL9VDq0CQQDaELWPQGjgs+7X +/QyWMJwOF4FXE4jecH/CcPVDB9K1ukllyC1HqTNe44Sp2bIDuSXXWb8yEixrEWBE +ci2CSSjXAkEA1I4W9IzwEmAeLtL6VBip9ks52O0JKu373/Xv1F2GYdhnQaFw7IC6 +1lSzcYMKGTmDuM8Cj26caldyv19Q0SPmvwJAdRHjZzS9GWWAJJTF3Rvbq/USix0B +renXrRvXkFTy2n1YSjxdkstTuO2Mm2M0HquXlTWpX8hB8HkzpYtmwztjoQJAECKl +LXVReCOhxu4vIJkqtc6qGoSL8J1WRH8X8KgU3nKeDAZkWx++jyyo3pIS/y01iZ71 +U8wSxaPTyyFCMk4mYwJBALjg7g8yDy1Lg9GFfOZvAVzPjqD28jZh/VJsDz9IhYoG +z89iHWHkllOisbOm+SeynVC8CoFXmJPc26U65GcjI18= +-----END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALUO3y0WYZLvpyK4 +1e+T9BGtXzAJwCtbG+Xsq7RpJBeBwUEBq/o/lEPxv50L0OKFK7+v7o45+OwBnqgo +Krc5NR+ahSEumgGibE9zMmAvLIsP6dCSnmoHVDdYHoAIv8clFGMkQifuVzm7UVUE +ZuIIAcoyJo/gENLKbyiqKYoLq6JpAgMBAAECgYAYqZjuzFCoMirDCQhjJPUm/0Wr +Bnj9ruBi9lUBMx0ucoc/cpnZcZWhl6lxG+3tHRSzfKRzDSSCCUpyP15qLMm2dK6g +M8/C3neYPKk83axTeFmDKTa0+Cvj0MHcwil+OirDhEv+nrSSyAZdsMSoG5eo60fm +LrWSFaUyP4FYv1UOrQJBANoQtY9AaOCz7tf9DJYwnA4XgVcTiN5wf8Jw9UMH0rW6 +SWXILUepM17jhKnZsgO5JddZvzISLGsRYERyLYJJKNcCQQDUjhb0jPASYB4u0vpU +GKn2SznY7Qkq7fvf9e/UXYZh2GdBoXDsgLrWVLNxgwoZOYO4zwKPbpxqV3K/X1DR +I+a/AkB1EeNnNL0ZZYAklMXdG9ur9RKLHQGt6detG9eQVPLafVhKPF2Sy1O47Yyb +YzQeq5eVNalfyEHweTOli2bDO2OhAkAQIqUtdVF4I6HG7i8gmSq1zqoahIvwnVZE +fxfwqBTecp4MBmRbH76PLKjekhL/LTWJnvVTzBLFo9PLIUIyTiZjAkEAuODuDzIP +LUuD0YV85m8BXM+OoPbyNmH9UmwPP0iFigbPz2IdYeSWU6Kxs6b5J7KdULwKgVeY +k9zbpTrkZyMjXw== +-----END PRIVATE KEY----- +-----BEGIN X509 CRL----- +MIICiTBzAgEBMA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNVBAMMD3Bvbnl0b3duIFJT +QSBDQRcNMjMwNjI3MDgyODEyWhcNMjMwNzI3MDgyODEyWjAVMBMCAgHIFw0yMzA2 +MjcwODI3NTlaoA4wDDAKBgNVHRQEAwIBAjANBgkqhkiG9w0BAQsFAAOCAgEAP6EX +9+hxjx/AqdBpynZXjGkEqigBcLcJ2PADOXngdQI1jC0WuYnZymUimemeULtt8X+1 +ai2KxAuF1m4NEKZsrGKvO+/9s/X1xbGroyHSAMKtZafFopFpoB2aNbYlx7yIyLtD +BBIZIF50g20U+3izqpHutTD10itdk9TLsSceJHpwTkNJtaWMkOfBV28nKzEzVutV +f6WzRpURGzui6nQy7aIqImeanpoBoz323psMfC32U0uMBCZltyHNqsX58/2Uhucx +0IPnitNuhv4scCPf/jeRfGIWDrTf1/25LDzRxyg1S4z9aa+3GM4O3dqy4igZEhgT +q3pjlJ2hUL5E0oqbZDIQD1SN8UUUv5N2AjwZcxVBNnYeGyuO7YpTBYiu62o73iL2 +CjgElfaMq/9hEr9GR9kJozh7VTxtQPbnr4DiucQvhv8o/A1z+zkC0gj8iCLFtDbO +8bvDowcdle9LKkrLaBe6sO+fSH/I9Wj8vrEJKsuwaEraIdEaq2VrIMUPEWN0/MH9 +vTwHyadGSMK4CWtrn9fCAgSLw6NX74D7Cx1IaS8vstMjpeUqOS0dk5ThiW47HceB +DTko7rV5N+RGH2nW1ynLoZKCJQqqZcLilFMyKPui3jifJnQlMFi54jGVgg/D6UQn +7dA7wb2ux/1hSiaarp+mi7ncVOyByz6/WQP8mfc= +-----END X509 CRL----- +... that's all folks! diff --git a/vendor/rustls-pemfile-1.0.3/tests/data/zen2.pem b/vendor/rustls-pemfile-1.0.3/tests/data/zen2.pem new file mode 100644 index 0000000000000..abff47fdb6de9 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/tests/data/zen2.pem @@ -0,0 +1,208 @@ +one with everything +-----BEGIN CERTIFICATE----- +MIIBuDCCAWqgAwIBAgICAcgwBQYDK2VwMC4xLDAqBgNVBAMMI3Bvbnl0b3duIEVk +RFNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTE5MDgxNjEzMjg1MVoXDTI1MDIw +NTEzMjg1MVowGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wKjAFBgMrZXADIQAQ +9M4hrE+Ucw4QUmaKOeKfphklBJi1qsqtX4u+knbseqOBwDCBvTAMBgNVHRMBAf8E +AjAAMAsGA1UdDwQEAwIGwDAdBgNVHQ4EFgQUa/gnV4+a22BUKTouAYX6nfLnPKYw +RAYDVR0jBD0wO4AUFxIwU406tG3CsPWkHWqfuUT48auhIKQeMBwxGjAYBgNVBAMM +EXBvbnl0b3duIEVkRFNBIENBggF7MDsGA1UdEQQ0MDKCDnRlc3RzZXJ2ZXIuY29t +ghVzZWNvbmQudGVzdHNlcnZlci5jb22CCWxvY2FsaG9zdDAFBgMrZXADQQApDiBQ +ns3fuvsWuFpIS+osj2B/gQ0b6eBAZ1UBxRyDlAo5++JZ0PtaEROyGo2t2gqi2Lyz +47mLyGCvqgVbC6cH +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBVzCCAQmgAwIBAgIBezAFBgMrZXAwHDEaMBgGA1UEAwwRcG9ueXRvd24gRWRE +U0EgQ0EwHhcNMTkwODE2MTMyODUxWhcNMjkwODEzMTMyODUxWjAuMSwwKgYDVQQD +DCNwb255dG93biBFZERTQSBsZXZlbCAyIGludGVybWVkaWF0ZTAqMAUGAytlcAMh +AD4h3t0UCoMDGgIq4UW4P5zDngsY4vy1pE3wzLPFI4Vdo14wXDAdBgNVHQ4EFgQU +FxIwU406tG3CsPWkHWqfuUT48aswIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsG +AQUFBwMCMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgH+MAUGAytlcANBAAZFvMek +Z71I8CXsBmx/0E6Weoaan9mJHgKqgQdK4w4h4dRg6DjNG957IbrLFO3vZduBMnna +qHP3xTFF+11Eyg8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBTDCB/6ADAgECAhRXcvbYynz4+usVvPtJp++sBUih3TAFBgMrZXAwHDEaMBgG +A1UEAwwRcG9ueXRvd24gRWREU0EgQ0EwHhcNMTkwODE2MTMyODUwWhcNMjkwODEz +MTMyODUwWjAcMRowGAYDVQQDDBFwb255dG93biBFZERTQSBDQTAqMAUGAytlcAMh +AIE4tLweIfcBGfhPqyXFp5pjVxjaiKk+9fTbRy46jAFKo1MwUTAdBgNVHQ4EFgQU +z5b9HjkOxffbtCZhWGg+bnxuD6wwHwYDVR0jBBgwFoAUz5b9HjkOxffbtCZhWGg+ +bnxuD6wwDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXADQQBNlt7z4bZ7KhzecxZEe3i5 +lH9MRqbpP9Rg4HyzAJfTzFGT183HoJiISdPLbxwMn0KaqSGlVe+9GgNKswoaRAwH +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEnzCCAoegAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255 +dG93biBSU0EgQ0EwHhcNMTkwNjA5MTcxNTEyWhcNMjkwNjA2MTcxNTEyWjAsMSow +KAYDVQQDDCFwb255dG93biBSU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwggGiMA0G +CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCj/tOFeSW3WB+TtuLCR1L/84lZytFw +zbpzOTGB1kPEKNbrMsv3lHXm5bHa8Bl3k113k7Hi7OAt/nkMm05s8LcUoovhaG5C +G7tjzL+ld1nO74gNS3IQHCzxRdRwIgaDZHyICfBQBfB9/m+9z3yRtOKWJl6i/MT9 +HRN6yADW/8gHFlMzRkCKBjIKXehKsu8cbtB+5MukwtXI4rKf9aYXZQOEUn1kEwQJ +ZIKBXR0eyloQiZervUE7meRCTBvzXT9VoSEX49/mempp4hnfdHlRNzre4/tphBf1 +fRUdpVXZ3DvmzoHdXRVzxx3X5LvDpf7Eb3ViGkXDFwkSfHEhkRnAl4lIzTH/1F25 +stmT8a0PA/lCNMrzJBzkLcuem1G1uMHoQZo1f3OpslJ8gHbE9ZlIbIKmpmJS9oop +Vh1BH+aOy5doCrF8uOLTQ3d5CqA/EZMGahDHy7IkeNYmG/RXUKNltv+r95gwuRP+ +9UIJ9FTa4REQbIpGWP5XibI6x4LqLTJj+VsCAwEAAaNeMFwwHQYDVR0OBBYEFEKP +y8hHZVazpvIsxFcGo4YrkEkwMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF +BQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jANBgkqhkiG9w0BAQsFAAOC +AgEAMzTRDLBExVFlw98AuX+pM+/R2Gjw5KFHvSYLKLbMRfuuZK1yNYYaYtNrtF+V +a53OFgaZj56o7tXc2PB8kw4MELD0ViR8Do2bvZieFcEe4DwhdjGCjuLehVLT29qI +7T3N/JkJ5daemKZcRB6Ne0F4+6QlVVNck28HUKbQThl88RdwLUImmSAfgKSt6uJ5 +wlH7wiYQR2vPXwSuEYzwot+L/91eBwuQr4Lovx9+TCKTbwQOKYjX4KfcOOQ1rx0M +IMrvwWqnabc6m1F0O6//ibL0kuFkJYEgOH2uJA12FBHO+/q2tcytejkOWKWMJj6Y +2etwIHcpzXaEP7fZ75cFGqcE3s7XGsweBIPLjMP1bKxEcFKzygURm/auUuXBCFBl +E16PB6JEAeCKe/8VFeyucvjPuQDWB49aq+r2SbpbI4IeZdz/QgEIOb0MpwStrvhH +9f/DtGMbjvuAEkRoOorK4m5k4GY3LsWTR2bey27AXk8N7pKarpu2N7ChBPm+EV0Y +H+tAI/OfdZuNUCES00F5UAFdU8zBUZo19ao2ZqfEADimE7Epk2s0bUe4GSqEXJp6 +68oVSMhZmMf/RCSNlr97f34sNiUA1YJ0JbCRZmw8KWNm9H1PARLbrgeRBZ/k31Li +WLDr3fiEVk7SGxj3zo94cS6AT55DyXLiSD/bFmL1QXgZweA= +-----END CERTIFICATE----- +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIMaA7bFrjDDBSik057bIKo7UQXJZNwLK9AjYZQ7yIWFloAoGCCqGSM49 +AwEHoUQDQgAExu0Z/w8nQJZAXeOXOnZun9HiZscY9H/KwYcXpeZHu+f9P9mOUEkH +5Z0av+JKtzhFspjngNLVgWcjlA1L5AJLdA== +-----END EC PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgxoDtsWuMMMFKKTTn +tsgqjtRBclk3Asr0CNhlDvIhYWWhRANCAATG7Rn/DydAlkBd45c6dm6f0eJmxxj0 +f8rBhxel5ke75/0/2Y5QSQflnRq/4kq3OEWymOeA0tWBZyOUDUvkAkt0 +-----END PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQC1Dt8tFmGS76ciuNXvk/QRrV8wCcArWxvl7Ku0aSQXgcFBAav6 +P5RD8b+dC9DihSu/r+6OOfjsAZ6oKCq3OTUfmoUhLpoBomxPczJgLyyLD+nQkp5q +B1Q3WB6ACL/HJRRjJEIn7lc5u1FVBGbiCAHKMiaP4BDSym8oqimKC6uiaQIDAQAB +AoGAGKmY7sxQqDIqwwkIYyT1Jv9FqwZ4/a7gYvZVATMdLnKHP3KZ2XGVoZepcRvt +7R0Us3ykcw0kgglKcj9eaizJtnSuoDPPwt53mDypPN2sU3hZgyk2tPgr49DB3MIp +fjoqw4RL/p60ksgGXbDEqBuXqOtH5i61khWlMj+BWL9VDq0CQQDaELWPQGjgs+7X +/QyWMJwOF4FXE4jecH/CcPVDB9K1ukllyC1HqTNe44Sp2bIDuSXXWb8yEixrEWBE +ci2CSSjXAkEA1I4W9IzwEmAeLtL6VBip9ks52O0JKu373/Xv1F2GYdhnQaFw7IC6 +1lSzcYMKGTmDuM8Cj26caldyv19Q0SPmvwJAdRHjZzS9GWWAJJTF3Rvbq/USix0B +renXrRvXkFTy2n1YSjxdkstTuO2Mm2M0HquXlTWpX8hB8HkzpYtmwztjoQJAECKl +LXVReCOhxu4vIJkqtc6qGoSL8J1WRH8X8KgU3nKeDAZkWx++jyyo3pIS/y01iZ71 +U8wSxaPTyyFCMk4mYwJBALjg7g8yDy1Lg9GFfOZvAVzPjqD28jZh/VJsDz9IhYoG +z89iHWHkllOisbOm+SeynVC8CoFXmJPc26U65GcjI18= +-----END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALUO3y0WYZLvpyK4 +1e+T9BGtXzAJwCtbG+Xsq7RpJBeBwUEBq/o/lEPxv50L0OKFK7+v7o45+OwBnqgo +Krc5NR+ahSEumgGibE9zMmAvLIsP6dCSnmoHVDdYHoAIv8clFGMkQifuVzm7UVUE +ZuIIAcoyJo/gENLKbyiqKYoLq6JpAgMBAAECgYAYqZjuzFCoMirDCQhjJPUm/0Wr +Bnj9ruBi9lUBMx0ucoc/cpnZcZWhl6lxG+3tHRSzfKRzDSSCCUpyP15qLMm2dK6g +M8/C3neYPKk83axTeFmDKTa0+Cvj0MHcwil+OirDhEv+nrSSyAZdsMSoG5eo60fm +LrWSFaUyP4FYv1UOrQJBANoQtY9AaOCz7tf9DJYwnA4XgVcTiN5wf8Jw9UMH0rW6 +SWXILUepM17jhKnZsgO5JddZvzISLGsRYERyLYJJKNcCQQDUjhb0jPASYB4u0vpU +GKn2SznY7Qkq7fvf9e/UXYZh2GdBoXDsgLrWVLNxgwoZOYO4zwKPbpxqV3K/X1DR +I+a/AkB1EeNnNL0ZZYAklMXdG9ur9RKLHQGt6detG9eQVPLafVhKPF2Sy1O47Yyb +YzQeq5eVNalfyEHweTOli2bDO2OhAkAQIqUtdVF4I6HG7i8gmSq1zqoahIvwnVZE +fxfwqBTecp4MBmRbH76PLKjekhL/LTWJnvVTzBLFo9PLIUIyTiZjAkEAuODuDzIP +LUuD0YV85m8BXM+OoPbyNmH9UmwPP0iFigbPz2IdYeSWU6Kxs6b5J7KdULwKgVeY +k9zbpTrkZyMjXw== +-----END PRIVATE KEY----- +... that's all folks! +one with everything +-----BEGIN CERTIFICATE----- +MIIBuDCCAWqgAwIBAgICAcgwBQYDK2VwMC4xLDAqBgNVBAMMI3Bvbnl0b3duIEVk +RFNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTE5MDgxNjEzMjg1MVoXDTI1MDIw +NTEzMjg1MVowGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wKjAFBgMrZXADIQAQ +9M4hrE+Ucw4QUmaKOeKfphklBJi1qsqtX4u+knbseqOBwDCBvTAMBgNVHRMBAf8E +AjAAMAsGA1UdDwQEAwIGwDAdBgNVHQ4EFgQUa/gnV4+a22BUKTouAYX6nfLnPKYw +RAYDVR0jBD0wO4AUFxIwU406tG3CsPWkHWqfuUT48auhIKQeMBwxGjAYBgNVBAMM +EXBvbnl0b3duIEVkRFNBIENBggF7MDsGA1UdEQQ0MDKCDnRlc3RzZXJ2ZXIuY29t +ghVzZWNvbmQudGVzdHNlcnZlci5jb22CCWxvY2FsaG9zdDAFBgMrZXADQQApDiBQ +ns3fuvsWuFpIS+osj2B/gQ0b6eBAZ1UBxRyDlAo5++JZ0PtaEROyGo2t2gqi2Lyz +47mLyGCvqgVbC6cH +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBVzCCAQmgAwIBAgIBezAFBgMrZXAwHDEaMBgGA1UEAwwRcG9ueXRvd24gRWRE +U0EgQ0EwHhcNMTkwODE2MTMyODUxWhcNMjkwODEzMTMyODUxWjAuMSwwKgYDVQQD +DCNwb255dG93biBFZERTQSBsZXZlbCAyIGludGVybWVkaWF0ZTAqMAUGAytlcAMh +AD4h3t0UCoMDGgIq4UW4P5zDngsY4vy1pE3wzLPFI4Vdo14wXDAdBgNVHQ4EFgQU +FxIwU406tG3CsPWkHWqfuUT48aswIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsG +AQUFBwMCMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgH+MAUGAytlcANBAAZFvMek +Z71I8CXsBmx/0E6Weoaan9mJHgKqgQdK4w4h4dRg6DjNG957IbrLFO3vZduBMnna +qHP3xTFF+11Eyg8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBTDCB/6ADAgECAhRXcvbYynz4+usVvPtJp++sBUih3TAFBgMrZXAwHDEaMBgG +A1UEAwwRcG9ueXRvd24gRWREU0EgQ0EwHhcNMTkwODE2MTMyODUwWhcNMjkwODEz +MTMyODUwWjAcMRowGAYDVQQDDBFwb255dG93biBFZERTQSBDQTAqMAUGAytlcAMh +AIE4tLweIfcBGfhPqyXFp5pjVxjaiKk+9fTbRy46jAFKo1MwUTAdBgNVHQ4EFgQU +z5b9HjkOxffbtCZhWGg+bnxuD6wwHwYDVR0jBBgwFoAUz5b9HjkOxffbtCZhWGg+ +bnxuD6wwDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXADQQBNlt7z4bZ7KhzecxZEe3i5 +lH9MRqbpP9Rg4HyzAJfTzFGT183HoJiISdPLbxwMn0KaqSGlVe+9GgNKswoaRAwH +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEnzCCAoegAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255 +dG93biBSU0EgQ0EwHhcNMTkwNjA5MTcxNTEyWhcNMjkwNjA2MTcxNTEyWjAsMSow +KAYDVQQDDCFwb255dG93biBSU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwggGiMA0G +CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCj/tOFeSW3WB+TtuLCR1L/84lZytFw +zbpzOTGB1kPEKNbrMsv3lHXm5bHa8Bl3k113k7Hi7OAt/nkMm05s8LcUoovhaG5C +G7tjzL+ld1nO74gNS3IQHCzxRdRwIgaDZHyICfBQBfB9/m+9z3yRtOKWJl6i/MT9 +HRN6yADW/8gHFlMzRkCKBjIKXehKsu8cbtB+5MukwtXI4rKf9aYXZQOEUn1kEwQJ +ZIKBXR0eyloQiZervUE7meRCTBvzXT9VoSEX49/mempp4hnfdHlRNzre4/tphBf1 +fRUdpVXZ3DvmzoHdXRVzxx3X5LvDpf7Eb3ViGkXDFwkSfHEhkRnAl4lIzTH/1F25 +stmT8a0PA/lCNMrzJBzkLcuem1G1uMHoQZo1f3OpslJ8gHbE9ZlIbIKmpmJS9oop +Vh1BH+aOy5doCrF8uOLTQ3d5CqA/EZMGahDHy7IkeNYmG/RXUKNltv+r95gwuRP+ +9UIJ9FTa4REQbIpGWP5XibI6x4LqLTJj+VsCAwEAAaNeMFwwHQYDVR0OBBYEFEKP +y8hHZVazpvIsxFcGo4YrkEkwMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF +BQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jANBgkqhkiG9w0BAQsFAAOC +AgEAMzTRDLBExVFlw98AuX+pM+/R2Gjw5KFHvSYLKLbMRfuuZK1yNYYaYtNrtF+V +a53OFgaZj56o7tXc2PB8kw4MELD0ViR8Do2bvZieFcEe4DwhdjGCjuLehVLT29qI +7T3N/JkJ5daemKZcRB6Ne0F4+6QlVVNck28HUKbQThl88RdwLUImmSAfgKSt6uJ5 +wlH7wiYQR2vPXwSuEYzwot+L/91eBwuQr4Lovx9+TCKTbwQOKYjX4KfcOOQ1rx0M +IMrvwWqnabc6m1F0O6//ibL0kuFkJYEgOH2uJA12FBHO+/q2tcytejkOWKWMJj6Y +2etwIHcpzXaEP7fZ75cFGqcE3s7XGsweBIPLjMP1bKxEcFKzygURm/auUuXBCFBl +E16PB6JEAeCKe/8VFeyucvjPuQDWB49aq+r2SbpbI4IeZdz/QgEIOb0MpwStrvhH +9f/DtGMbjvuAEkRoOorK4m5k4GY3LsWTR2bey27AXk8N7pKarpu2N7ChBPm+EV0Y +H+tAI/OfdZuNUCES00F5UAFdU8zBUZo19ao2ZqfEADimE7Epk2s0bUe4GSqEXJp6 +68oVSMhZmMf/RCSNlr97f34sNiUA1YJ0JbCRZmw8KWNm9H1PARLbrgeRBZ/k31Li +WLDr3fiEVk7SGxj3zo94cS6AT55DyXLiSD/bFmL1QXgZweA= +-----END CERTIFICATE----- +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIMaA7bFrjDDBSik057bIKo7UQXJZNwLK9AjYZQ7yIWFloAoGCCqGSM49 +AwEHoUQDQgAExu0Z/w8nQJZAXeOXOnZun9HiZscY9H/KwYcXpeZHu+f9P9mOUEkH +5Z0av+JKtzhFspjngNLVgWcjlA1L5AJLdA== +-----END EC PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgxoDtsWuMMMFKKTTn +tsgqjtRBclk3Asr0CNhlDvIhYWWhRANCAATG7Rn/DydAlkBd45c6dm6f0eJmxxj0 +f8rBhxel5ke75/0/2Y5QSQflnRq/4kq3OEWymOeA0tWBZyOUDUvkAkt0 +-----END PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQC1Dt8tFmGS76ciuNXvk/QRrV8wCcArWxvl7Ku0aSQXgcFBAav6 +P5RD8b+dC9DihSu/r+6OOfjsAZ6oKCq3OTUfmoUhLpoBomxPczJgLyyLD+nQkp5q +B1Q3WB6ACL/HJRRjJEIn7lc5u1FVBGbiCAHKMiaP4BDSym8oqimKC6uiaQIDAQAB +AoGAGKmY7sxQqDIqwwkIYyT1Jv9FqwZ4/a7gYvZVATMdLnKHP3KZ2XGVoZepcRvt +7R0Us3ykcw0kgglKcj9eaizJtnSuoDPPwt53mDypPN2sU3hZgyk2tPgr49DB3MIp +fjoqw4RL/p60ksgGXbDEqBuXqOtH5i61khWlMj+BWL9VDq0CQQDaELWPQGjgs+7X +/QyWMJwOF4FXE4jecH/CcPVDB9K1ukllyC1HqTNe44Sp2bIDuSXXWb8yEixrEWBE +ci2CSSjXAkEA1I4W9IzwEmAeLtL6VBip9ks52O0JKu373/Xv1F2GYdhnQaFw7IC6 +1lSzcYMKGTmDuM8Cj26caldyv19Q0SPmvwJAdRHjZzS9GWWAJJTF3Rvbq/USix0B +renXrRvXkFTy2n1YSjxdkstTuO2Mm2M0HquXlTWpX8hB8HkzpYtmwztjoQJAECKl +LXVReCOhxu4vIJkqtc6qGoSL8J1WRH8X8KgU3nKeDAZkWx++jyyo3pIS/y01iZ71 +U8wSxaPTyyFCMk4mYwJBALjg7g8yDy1Lg9GFfOZvAVzPjqD28jZh/VJsDz9IhYoG +z89iHWHkllOisbOm+SeynVC8CoFXmJPc26U65GcjI18= +-----END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALUO3y0WYZLvpyK4 +1e+T9BGtXzAJwCtbG+Xsq7RpJBeBwUEBq/o/lEPxv50L0OKFK7+v7o45+OwBnqgo +Krc5NR+ahSEumgGibE9zMmAvLIsP6dCSnmoHVDdYHoAIv8clFGMkQifuVzm7UVUE +ZuIIAcoyJo/gENLKbyiqKYoLq6JpAgMBAAECgYAYqZjuzFCoMirDCQhjJPUm/0Wr +Bnj9ruBi9lUBMx0ucoc/cpnZcZWhl6lxG+3tHRSzfKRzDSSCCUpyP15qLMm2dK6g +M8/C3neYPKk83axTeFmDKTa0+Cvj0MHcwil+OirDhEv+nrSSyAZdsMSoG5eo60fm +LrWSFaUyP4FYv1UOrQJBANoQtY9AaOCz7tf9DJYwnA4XgVcTiN5wf8Jw9UMH0rW6 +SWXILUepM17jhKnZsgO5JddZvzISLGsRYERyLYJJKNcCQQDUjhb0jPASYB4u0vpU +GKn2SznY7Qkq7fvf9e/UXYZh2GdBoXDsgLrWVLNxgwoZOYO4zwKPbpxqV3K/X1DR +I+a/AkB1EeNnNL0ZZYAklMXdG9ur9RKLHQGt6detG9eQVPLafVhKPF2Sy1O47Yyb +YzQeq5eVNalfyEHweTOli2bDO2OhAkAQIqUtdVF4I6HG7i8gmSq1zqoahIvwnVZE +fxfwqBTecp4MBmRbH76PLKjekhL/LTWJnvVTzBLFo9PLIUIyTiZjAkEAuODuDzIP +LUuD0YV85m8BXM+OoPbyNmH9UmwPP0iFigbPz2IdYeSWU6Kxs6b5J7KdULwKgVeY +k9zbpTrkZyMjXw== +-----END PRIVATE KEY----- +... that's all folks! diff --git a/vendor/rustls-pemfile-1.0.3/tests/integration.rs b/vendor/rustls-pemfile-1.0.3/tests/integration.rs new file mode 100644 index 0000000000000..71c7345563490 --- /dev/null +++ b/vendor/rustls-pemfile-1.0.3/tests/integration.rs @@ -0,0 +1,111 @@ +use std::io::BufReader; +use std::iter; + +#[test] +fn test_rsa_private_keys() { + let data = include_bytes!("data/zen2.pem"); + let mut reader = BufReader::new(&data[..]); + + assert_eq!( + rustls_pemfile::rsa_private_keys(&mut reader).unwrap().len(), + 2 + ); +} + +#[test] +fn test_certs() { + let data = include_bytes!("data/certificate.chain.pem"); + let mut reader = BufReader::new(&data[..]); + + assert_eq!(rustls_pemfile::certs(&mut reader).unwrap().len(), 3); +} + +#[test] +fn test_certs_with_binary() { + let data = include_bytes!("data/gunk.pem"); + let mut reader = BufReader::new(&data[..]); + assert_eq!(rustls_pemfile::certs(&mut reader).unwrap().len(), 2); +} + +#[test] +fn test_crls() { + let data = include_bytes!("data/crl.pem"); + let mut reader = BufReader::new(&data[..]); + assert_eq!(rustls_pemfile::crls(&mut reader).unwrap().len(), 1); +} + +#[test] +fn test_pkcs8() { + let data = include_bytes!("data/zen.pem"); + let mut reader = BufReader::new(&data[..]); + + assert_eq!( + rustls_pemfile::pkcs8_private_keys(&mut reader) + .unwrap() + .len(), + 2 + ); +} + +#[test] +fn test_sec1() { + let data = include_bytes!("data/nistp256key.pem"); + let mut reader = BufReader::new(&data[..]); + + let items = rustls_pemfile::read_all(&mut reader).unwrap(); + assert_eq!(items.len(), 1); + assert!(matches!(items[0], rustls_pemfile::Item::ECKey(_))); +} + +#[test] +fn smoketest_iterate() { + let data = include_bytes!("data/zen2.pem"); + let mut reader = BufReader::new(&data[..]); + + let mut count = 0; + + for item in iter::from_fn(|| rustls_pemfile::read_one(&mut reader).transpose()) { + println!("item {:?}", item); + count += 1; + } + + assert_eq!(count, 16); +} + +#[test] +fn test_sec1_vs_pkcs8() { + { + let data = include_bytes!("data/nistp256key.pem"); + let mut reader = BufReader::new(&data[..]); + + let items = rustls_pemfile::read_all(&mut reader).unwrap(); + assert!(matches!(items[0], rustls_pemfile::Item::ECKey(_))); + println!("sec1 {:?}", items); + } + { + let data = include_bytes!("data/nistp256key.pkcs8.pem"); + let mut reader = BufReader::new(&data[..]); + + let items = rustls_pemfile::read_all(&mut reader).unwrap(); + assert!(matches!(items[0], rustls_pemfile::Item::PKCS8Key(_))); + println!("p8 {:?}", items); + } +} + +#[test] +fn parse_in_order() { + let data = include_bytes!("data/zen.pem"); + let mut reader = BufReader::new(&data[..]); + + let items = rustls_pemfile::read_all(&mut reader).unwrap(); + assert_eq!(items.len(), 9); + assert!(matches!(items[0], rustls_pemfile::Item::X509Certificate(_))); + assert!(matches!(items[1], rustls_pemfile::Item::X509Certificate(_))); + assert!(matches!(items[2], rustls_pemfile::Item::X509Certificate(_))); + assert!(matches!(items[3], rustls_pemfile::Item::X509Certificate(_))); + assert!(matches!(items[4], rustls_pemfile::Item::ECKey(_))); + assert!(matches!(items[5], rustls_pemfile::Item::PKCS8Key(_))); + assert!(matches!(items[6], rustls_pemfile::Item::RSAKey(_))); + assert!(matches!(items[7], rustls_pemfile::Item::PKCS8Key(_))); + assert!(matches!(items[8], rustls_pemfile::Item::Crl(_))); +} diff --git a/vendor/rustls-webpki/tests/client_auth_revocation/ee_crl_no_idp_unknown_status.crl.der b/vendor/rustls-webpki/tests/client_auth_revocation/ee_crl_no_idp_unknown_status.crl.der new file mode 100644 index 0000000000000..8360258e69062 Binary files /dev/null and b/vendor/rustls-webpki/tests/client_auth_revocation/ee_crl_no_idp_unknown_status.crl.der differ diff --git a/vendor/rustls/src/msgs/message.rs b/vendor/rustls/src/msgs/message.rs new file mode 100644 index 0000000000000..67704af1903d1 --- /dev/null +++ b/vendor/rustls/src/msgs/message.rs @@ -0,0 +1,362 @@ +use crate::enums::ProtocolVersion; +use crate::enums::{AlertDescription, ContentType, HandshakeType}; +use crate::error::{Error, InvalidMessage, PeerMisbehaved}; +use crate::msgs::alert::AlertMessagePayload; +use crate::msgs::base::Payload; +use crate::msgs::ccs::ChangeCipherSpecPayload; +use crate::msgs::codec::{Codec, Reader}; +use crate::msgs::enums::AlertLevel; +use crate::msgs::fragmenter::MAX_FRAGMENT_LEN; +use crate::msgs::handshake::HandshakeMessagePayload; + +use alloc::vec::Vec; + +#[derive(Debug)] +pub enum MessagePayload { + Alert(AlertMessagePayload), + Handshake { + parsed: HandshakeMessagePayload, + encoded: Payload, + }, + ChangeCipherSpec(ChangeCipherSpecPayload), + ApplicationData(Payload), +} + +impl MessagePayload { + pub fn encode(&self, bytes: &mut Vec) { + match self { + Self::Alert(x) => x.encode(bytes), + Self::Handshake { encoded, .. } => bytes.extend(&encoded.0), + Self::ChangeCipherSpec(x) => x.encode(bytes), + Self::ApplicationData(x) => x.encode(bytes), + } + } + + pub fn handshake(parsed: HandshakeMessagePayload) -> Self { + Self::Handshake { + encoded: Payload::new(parsed.get_encoding()), + parsed, + } + } + + pub fn new( + typ: ContentType, + vers: ProtocolVersion, + payload: Payload, + ) -> Result { + let mut r = Reader::init(&payload.0); + match typ { + ContentType::ApplicationData => Ok(Self::ApplicationData(payload)), + ContentType::Alert => AlertMessagePayload::read(&mut r).map(MessagePayload::Alert), + ContentType::Handshake => { + HandshakeMessagePayload::read_version(&mut r, vers).map(|parsed| Self::Handshake { + parsed, + encoded: payload, + }) + } + ContentType::ChangeCipherSpec => { + ChangeCipherSpecPayload::read(&mut r).map(MessagePayload::ChangeCipherSpec) + } + _ => Err(InvalidMessage::InvalidContentType), + } + } + + pub fn content_type(&self) -> ContentType { + match self { + Self::Alert(_) => ContentType::Alert, + Self::Handshake { .. } => ContentType::Handshake, + Self::ChangeCipherSpec(_) => ContentType::ChangeCipherSpec, + Self::ApplicationData(_) => ContentType::ApplicationData, + } + } +} + +/// A TLS frame, named TLSPlaintext in the standard. +/// +/// This type owns all memory for its interior parts. It is used to read/write from/to I/O +/// buffers as well as for fragmenting, joining and encryption/decryption. It can be converted +/// into a `Message` by decoding the payload. +/// +/// # Decryption +/// Internally the message payload is stored as a `Vec`; this can by mutably borrowed with +/// [`OpaqueMessage::payload_mut()`]. This is useful for decrypting a message in-place. +/// After the message is decrypted, call [`OpaqueMessage::into_plain_message()`] or +/// [`OpaqueMessage::into_tls13_unpadded_message()`] (depending on the +/// protocol version). +#[derive(Clone, Debug)] +pub struct OpaqueMessage { + pub typ: ContentType, + pub version: ProtocolVersion, + payload: Payload, +} + +impl OpaqueMessage { + /// Construct a new `OpaqueMessage` from constituent fields. + /// + /// `body` is moved into the `payload` field. + pub fn new(typ: ContentType, version: ProtocolVersion, body: Vec) -> Self { + Self { + typ, + version, + payload: Payload::new(body), + } + } + + /// Access the message payload as a slice. + pub fn payload(&self) -> &[u8] { + &self.payload.0 + } + + /// Access the message payload as a mutable `Vec`. + pub fn payload_mut(&mut self) -> &mut Vec { + &mut self.payload.0 + } + + /// `MessageError` allows callers to distinguish between valid prefixes (might + /// become valid if we read more data) and invalid data. + pub fn read(r: &mut Reader) -> Result { + let typ = ContentType::read(r).map_err(|_| MessageError::TooShortForHeader)?; + // Don't accept any new content-types. + if let ContentType::Unknown(_) = typ { + return Err(MessageError::InvalidContentType); + } + + let version = ProtocolVersion::read(r).map_err(|_| MessageError::TooShortForHeader)?; + // Accept only versions 0x03XX for any XX. + match version { + ProtocolVersion::Unknown(ref v) if (v & 0xff00) != 0x0300 => { + return Err(MessageError::UnknownProtocolVersion); + } + _ => {} + }; + + let len = u16::read(r).map_err(|_| MessageError::TooShortForHeader)?; + + // Reject undersize messages + // implemented per section 5.1 of RFC8446 (TLSv1.3) + // per section 6.2.1 of RFC5246 (TLSv1.2) + if typ != ContentType::ApplicationData && len == 0 { + return Err(MessageError::InvalidEmptyPayload); + } + + // Reject oversize messages + if len >= Self::MAX_PAYLOAD { + return Err(MessageError::MessageTooLarge); + } + + let mut sub = r + .sub(len as usize) + .map_err(|_| MessageError::TooShortForLength)?; + let payload = Payload::read(&mut sub); + + Ok(Self { + typ, + version, + payload, + }) + } + + pub fn encode(self) -> Vec { + let mut buf = Vec::new(); + self.typ.encode(&mut buf); + self.version.encode(&mut buf); + (self.payload.0.len() as u16).encode(&mut buf); + self.payload.encode(&mut buf); + buf + } + + /// Force conversion into a plaintext message. + /// + /// This should only be used for messages that are known to be in plaintext. Otherwise, the + /// `OpaqueMessage` should be decrypted into a `PlainMessage` using a `MessageDecrypter`. + pub fn into_plain_message(self) -> PlainMessage { + PlainMessage { + version: self.version, + typ: self.typ, + payload: self.payload, + } + } + + /// For TLS1.3 (only), checks the length msg.payload is valid and removes the padding. + /// + /// Returns an error if the message (pre-unpadding) is too long, or the padding is invalid, + /// or the message (post-unpadding) is too long. + pub fn into_tls13_unpadded_message(mut self) -> Result { + let payload = &mut self.payload.0; + + if payload.len() > MAX_FRAGMENT_LEN + 1 { + return Err(Error::PeerSentOversizedRecord); + } + + self.typ = unpad_tls13(payload); + if self.typ == ContentType::Unknown(0) { + return Err(PeerMisbehaved::IllegalTlsInnerPlaintext.into()); + } + + if payload.len() > MAX_FRAGMENT_LEN { + return Err(Error::PeerSentOversizedRecord); + } + + self.version = ProtocolVersion::TLSv1_3; + Ok(self.into_plain_message()) + } + + /// This is the maximum on-the-wire size of a TLSCiphertext. + /// That's 2^14 payload bytes, a header, and a 2KB allowance + /// for ciphertext overheads. + const MAX_PAYLOAD: u16 = 16384 + 2048; + + /// Content type, version and size. + const HEADER_SIZE: u16 = 1 + 2 + 2; + + /// Maximum on-wire message size. + pub const MAX_WIRE_SIZE: usize = (Self::MAX_PAYLOAD + Self::HEADER_SIZE) as usize; +} + +/// `v` is a message payload, immediately post-decryption. This function +/// removes zero padding bytes, until a non-zero byte is encountered which is +/// the content type, which is returned. See RFC8446 s5.2. +/// +/// ContentType(0) is returned if the message payload is empty or all zeroes. +fn unpad_tls13(v: &mut Vec) -> ContentType { + loop { + match v.pop() { + Some(0) => {} + Some(content_type) => return ContentType::from(content_type), + None => return ContentType::Unknown(0), + } + } +} + +impl From for PlainMessage { + fn from(msg: Message) -> Self { + let typ = msg.payload.content_type(); + let payload = match msg.payload { + MessagePayload::ApplicationData(payload) => payload, + _ => { + let mut buf = Vec::new(); + msg.payload.encode(&mut buf); + Payload(buf) + } + }; + + Self { + typ, + version: msg.version, + payload, + } + } +} + +/// A decrypted TLS frame +/// +/// This type owns all memory for its interior parts. It can be decrypted from an OpaqueMessage +/// or encrypted into an OpaqueMessage, and it is also used for joining and fragmenting. +#[derive(Clone, Debug)] +pub struct PlainMessage { + pub typ: ContentType, + pub version: ProtocolVersion, + pub payload: Payload, +} + +impl PlainMessage { + pub fn into_unencrypted_opaque(self) -> OpaqueMessage { + OpaqueMessage { + version: self.version, + typ: self.typ, + payload: self.payload, + } + } + + pub fn borrow(&self) -> BorrowedPlainMessage<'_> { + BorrowedPlainMessage { + version: self.version, + typ: self.typ, + payload: &self.payload.0, + } + } +} + +/// A message with decoded payload +#[derive(Debug)] +pub struct Message { + pub version: ProtocolVersion, + pub payload: MessagePayload, +} + +impl Message { + pub fn is_handshake_type(&self, hstyp: HandshakeType) -> bool { + // Bit of a layering violation, but OK. + if let MessagePayload::Handshake { parsed, .. } = &self.payload { + parsed.typ == hstyp + } else { + false + } + } + + pub fn build_alert(level: AlertLevel, desc: AlertDescription) -> Self { + Self { + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::Alert(AlertMessagePayload { + level, + description: desc, + }), + } + } + + pub fn build_key_update_notify() -> Self { + Self { + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::handshake(HandshakeMessagePayload::build_key_update_notify()), + } + } +} + +/// Parses a plaintext message into a well-typed [`Message`]. +/// +/// A [`PlainMessage`] must contain plaintext content. Encrypted content should be stored in an +/// [`OpaqueMessage`] and decrypted before being stored into a [`PlainMessage`]. +impl TryFrom for Message { + type Error = Error; + + fn try_from(plain: PlainMessage) -> Result { + Ok(Self { + version: plain.version, + payload: MessagePayload::new(plain.typ, plain.version, plain.payload)?, + }) + } +} + +/// A TLS frame, named TLSPlaintext in the standard. +/// +/// This type differs from `OpaqueMessage` because it borrows +/// its payload. You can make a `OpaqueMessage` from an +/// `BorrowMessage`, but this involves a copy. +/// +/// This type also cannot decode its internals and +/// cannot be read/encoded; only `OpaqueMessage` can do that. +pub struct BorrowedPlainMessage<'a> { + pub typ: ContentType, + pub version: ProtocolVersion, + pub payload: &'a [u8], +} + +impl<'a> BorrowedPlainMessage<'a> { + pub fn to_unencrypted_opaque(&self) -> OpaqueMessage { + OpaqueMessage { + version: self.version, + typ: self.typ, + payload: Payload(self.payload.to_vec()), + } + } +} + +#[derive(Debug)] +pub enum MessageError { + TooShortForHeader, + TooShortForLength, + InvalidEmptyPayload, + MessageTooLarge, + InvalidContentType, + UnknownProtocolVersion, +} diff --git a/vendor/serde_json/src/features_check/error.rs b/vendor/serde_json/src/features_check/error.rs new file mode 100644 index 0000000000000..22e58235c76f0 --- /dev/null +++ b/vendor/serde_json/src/features_check/error.rs @@ -0,0 +1 @@ +"serde_json requires that either `std` (default) or `alloc` feature is enabled" diff --git a/vendor/serde_json/src/features_check/mod.rs b/vendor/serde_json/src/features_check/mod.rs new file mode 100644 index 0000000000000..d12032cef8620 --- /dev/null +++ b/vendor/serde_json/src/features_check/mod.rs @@ -0,0 +1,13 @@ +//! Shows a user-friendly compiler error on incompatible selected features. + +#[allow(unused_macros)] +macro_rules! hide_from_rustfmt { + ($mod:item) => { + $mod + }; +} + +#[cfg(not(any(feature = "std", feature = "alloc")))] +hide_from_rustfmt! { + mod error; +} diff --git a/vendor/serde_yaml-0.8.26/.cargo-checksum.json b/vendor/serde_yaml-0.8.26/.cargo-checksum.json new file mode 100644 index 0000000000000..eb1d4afddc130 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"1e01ffba9fa6c48ceda8bd7b3b936b5909c7adbfb05b6a5f8deb3f679d7da37e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"8b6df65d390bc4f9d5e05d0a4ccc860d6e5dc2668d82cd304e6c95b472a21f35","src/de.rs":"414b82334d78cf57b7cdc2fc1ed000594791b2f675648f5286678370f460a74d","src/error.rs":"96a49b8ea102d010760b3ade9b475d0c88d4014c17625302ddc145a9fea2988c","src/lib.rs":"a3276a7da395021e34547fe2f4336a5658f07d4d606a865b707a592f7b084e10","src/mapping.rs":"6607911090c89a41ade38f1717b9c0bd6c3c253cc4711890b77b2bda18d6bac7","src/number.rs":"4edf78ad75bf66bae31c1ee4d785ba2b7a2c14c082802d54c9feb93067bcf063","src/path.rs":"44d339ce1814effd10ba131ae0393df215f09dbfb35ab4d678f49d4081f58dd4","src/ser.rs":"e32c77b3e8087ca1b68a8f093e9f1e27b93ad1aac70a9bb22054b4179973cae1","src/value/de.rs":"84b213b23a8d4bf6bd9aacd18fc1091254382c4edc479f9a9abc87c416b370f0","src/value/from.rs":"cd66c76c4ab03bed32f8c4b22ffbd96274a837d587624a62d0584c7090633862","src/value/index.rs":"16f0e4fecd4a4cd149af89a7426864f58735f7dacc90f33d92c647b044c8f112","src/value/mod.rs":"171a98133de3445ccd4cfa3991b5c3f96baa1c05542fc1927e6eccf3e4ddbe09","src/value/partial_eq.rs":"0b28c8d2f10a58581dbe2a69d25742fa0f8bf3da797f3046e38e300d1f9691bf","src/value/ser.rs":"7ddb9bfadfbfe16a79c872888ea25f8fb7df14b862fea47dd603d576e162db86","tests/test_de.rs":"c7d8d71e8b0aa966ad4003657c1024405abeca0d49aec9f66f749db81bb1f061","tests/test_error.rs":"4ef5c9001f140e1aee1e9d6238c668d26b5b264e237773741d5f65bfff036e75","tests/test_serde.rs":"56aa2623b1aca1ba00d028edc60d6f74cde6eba83529d5bcd3340c4b0487db04","tests/test_value.rs":"f360eeaa7d281d52df18a452a6f67c6095bcf50b92f1a87c5a9e3c27b7a69f33"},"package":"578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"} \ No newline at end of file diff --git a/vendor/serde_yaml-0.8.26/Cargo.toml b/vendor/serde_yaml-0.8.26/Cargo.toml new file mode 100644 index 0000000000000..3fd065aa350e8 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/Cargo.toml @@ -0,0 +1,53 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.56" +name = "serde_yaml" +version = "0.8.26" +authors = ["David Tolnay "] +description = "YAML support for Serde" +documentation = "https://docs.rs/serde_yaml/" +readme = "README.md" +keywords = [ + "yaml", + "serde", +] +categories = ["encoding"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/serde-yaml" +resolver = "2" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies.indexmap] +version = "1.5.2" +features = ["std"] + +[dependencies.ryu] +version = "1.0" + +[dependencies.serde] +version = "1.0.69" + +[dependencies.yaml-rust] +version = "0.4.5" + +[dev-dependencies.anyhow] +version = "1.0" + +[dev-dependencies.indoc] +version = "1.0" + +[dev-dependencies.serde_derive] +version = "1.0" diff --git a/vendor/serde_yaml-0.8.26/LICENSE-APACHE b/vendor/serde_yaml-0.8.26/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/serde_yaml-0.8.26/LICENSE-MIT b/vendor/serde_yaml-0.8.26/LICENSE-MIT new file mode 100644 index 0000000000000..31aa79387f27e --- /dev/null +++ b/vendor/serde_yaml-0.8.26/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/serde_yaml-0.8.26/README.md b/vendor/serde_yaml-0.8.26/README.md new file mode 100644 index 0000000000000..4500865cb02ae --- /dev/null +++ b/vendor/serde_yaml-0.8.26/README.md @@ -0,0 +1,104 @@ +Serde YAML +========== + +[github](https://github.com/dtolnay/serde-yaml) +[crates.io](https://crates.io/crates/serde_yaml) +[docs.rs](https://docs.rs/serde_yaml) +[build status](https://github.com/dtolnay/serde-yaml/actions?query=branch%3Amaster) + +This crate is a Rust library for using the [Serde] serialization framework with +data in [YAML] file format. + +[Serde]: https://github.com/serde-rs/serde +[YAML]: https://yaml.org/ + +This library does not reimplement a YAML parser; it uses [yaml-rust] which is a +pure Rust YAML 1.2 implementation. + +[yaml-rust]: https://github.com/chyh1990/yaml-rust + +## Dependency + +```toml +[dependencies] +serde = "1.0" +serde_yaml = "0.8" +``` + +Release notes are available under [GitHub releases]. + +[GitHub releases]: https://github.com/dtolnay/serde-yaml/releases + +## Using Serde YAML + +[API documentation is available in rustdoc form][docs.rs] but the general idea +is: + +[docs.rs]: https://docs.rs/serde_yaml + +```rust +use std::collections::BTreeMap; + +fn main() -> Result<(), serde_yaml::Error> { + // You have some type. + let mut map = BTreeMap::new(); + map.insert("x".to_string(), 1.0); + map.insert("y".to_string(), 2.0); + + // Serialize it to a YAML string. + let s = serde_yaml::to_string(&map)?; + assert_eq!(s, "---\nx: 1.0\ny: 2.0\n"); + + // Deserialize it back to a Rust type. + let deserialized_map: BTreeMap = serde_yaml::from_str(&s)?; + assert_eq!(map, deserialized_map); + Ok(()) +} +``` + +It can also be used with Serde's derive macros to handle structs and enums +defined by your program. + +```toml +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_yaml = "0.8" +``` + +```rust +use serde::{Serialize, Deserialize}; + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +struct Point { + x: f64, + y: f64, +} + +fn main() -> Result<(), serde_yaml::Error> { + let point = Point { x: 1.0, y: 2.0 }; + + let s = serde_yaml::to_string(&point)?; + assert_eq!(s, "---\nx: 1.0\ny: 2.0\n"); + + let deserialized_point: Point = serde_yaml::from_str(&s)?; + assert_eq!(point, deserialized_point); + Ok(()) +} +``` + +
+ +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + diff --git a/vendor/serde_yaml-0.8.26/src/de.rs b/vendor/serde_yaml-0.8.26/src/de.rs new file mode 100644 index 0000000000000..8ccf271093f00 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/src/de.rs @@ -0,0 +1,1525 @@ +use crate::error::{self, Error, ErrorImpl, Result}; +use crate::path::Path; +use serde::de::{ + self, Deserialize, DeserializeOwned, DeserializeSeed, Expected, IgnoredAny as Ignore, + IntoDeserializer, Unexpected, Visitor, +}; +use std::collections::BTreeMap; +use std::f64; +use std::fmt; +use std::io; +use std::marker::PhantomData; +use std::mem; +use std::str; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use yaml_rust::parser::{Event as YamlEvent, MarkedEventReceiver, Parser}; +use yaml_rust::scanner::{Marker, TScalarStyle, TokenType}; + +/// A structure that deserializes YAML into Rust values. +/// +/// # Examples +/// +/// Deserializing a single document: +/// +/// ``` +/// use anyhow::Result; +/// use serde::Deserialize; +/// use serde_yaml::Value; +/// +/// fn main() -> Result<()> { +/// let input = "---\nk: 107\n"; +/// let de = serde_yaml::Deserializer::from_str(input); +/// let value = Value::deserialize(de)?; +/// println!("{:?}", value); +/// Ok(()) +/// } +/// ``` +/// +/// Deserializing multi-doc YAML: +/// +/// ``` +/// use anyhow::Result; +/// use serde::Deserialize; +/// use serde_yaml::Value; +/// +/// fn main() -> Result<()> { +/// let input = "---\nk: 107\n...\n---\nj: 106\n"; +/// +/// for document in serde_yaml::Deserializer::from_str(input) { +/// let value = Value::deserialize(document)?; +/// println!("{:?}", value); +/// } +/// +/// Ok(()) +/// } +/// ``` +pub struct Deserializer<'a> { + input: Input<'a>, +} + +enum Input<'a> { + Str(&'a str), + Slice(&'a [u8]), + Read(Box), + Multidoc(Arc), + Fail(Arc), +} + +impl<'a> Deserializer<'a> { + /// Creates a YAML deserializer from a `&str`. + pub fn from_str(s: &'a str) -> Self { + let input = Input::Str(s); + Deserializer { input } + } + + /// Creates a YAML deserializer from a `&[u8]`. + pub fn from_slice(v: &'a [u8]) -> Self { + let input = Input::Slice(v); + Deserializer { input } + } + + /// Creates a YAML deserializer from an `io::Read`. + /// + /// Reader-based deserializers do not support deserializing borrowed types + /// like `&str`, since the `std::io::Read` trait has no non-copying methods + /// -- everything it does involves copying bytes out of the data source. + pub fn from_reader(rdr: R) -> Self + where + R: io::Read + 'a, + { + let input = Input::Read(Box::new(rdr)); + Deserializer { input } + } + + fn de(self, f: impl FnOnce(&mut DeserializerFromEvents) -> Result) -> Result { + if let Input::Multidoc(multidoc) = &self.input { + let mut pos = multidoc.pos.load(Ordering::Relaxed); + let t = f(&mut DeserializerFromEvents { + events: &multidoc.loader.events, + aliases: &multidoc.loader.aliases, + pos: &mut pos, + path: Path::Root, + remaining_depth: 128, + })?; + multidoc.pos.store(pos, Ordering::Relaxed); + return Ok(t); + } + + let loader = loader(self.input)?; + if loader.events.is_empty() { + return Err(error::end_of_stream()); + } + let mut pos = 0; + let t = f(&mut DeserializerFromEvents { + events: &loader.events, + aliases: &loader.aliases, + pos: &mut pos, + path: Path::Root, + remaining_depth: 128, + })?; + if pos == loader.events.len() { + Ok(t) + } else { + Err(error::more_than_one_document()) + } + } +} + +fn loader(input: Input) -> Result { + enum Input2<'a> { + Str(&'a str), + Slice(&'a [u8]), + } + + let mut buffer; + let input = match input { + Input::Str(s) => Input2::Str(s), + Input::Slice(bytes) => Input2::Slice(bytes), + Input::Read(mut rdr) => { + buffer = Vec::new(); + rdr.read_to_end(&mut buffer).map_err(error::io)?; + Input2::Slice(&buffer) + } + Input::Multidoc(_) => unreachable!(), + Input::Fail(err) => return Err(error::shared(err)), + }; + + let input = match input { + Input2::Str(s) => s, + Input2::Slice(bytes) => str::from_utf8(bytes).map_err(error::str_utf8)?, + }; + + let mut parser = Parser::new(input.chars()); + let mut loader = Loader { + events: Vec::new(), + aliases: BTreeMap::new(), + }; + parser.load(&mut loader, true).map_err(error::scanner)?; + Ok(loader) +} + +struct Multidoc { + loader: Loader, + pos: AtomicUsize, +} + +impl<'de> Iterator for Deserializer<'de> { + type Item = Self; + + fn next(&mut self) -> Option { + match &self.input { + Input::Multidoc(multidoc) => { + let pos = multidoc.pos.load(Ordering::Relaxed); + return if pos < multidoc.loader.events.len() { + Some(Deserializer { + input: Input::Multidoc(Arc::clone(multidoc)), + }) + } else { + None + }; + } + Input::Fail(err) => { + return Some(Deserializer { + input: Input::Fail(Arc::clone(err)), + }); + } + _ => {} + } + + let dummy = Input::Str(""); + let input = mem::replace(&mut self.input, dummy); + match loader(input) { + Ok(loader) => { + let multidoc = Arc::new(Multidoc { + loader, + pos: AtomicUsize::new(0), + }); + self.input = Input::Multidoc(Arc::clone(&multidoc)); + if multidoc.loader.events.is_empty() { + None + } else { + Some(Deserializer { + input: Input::Multidoc(multidoc), + }) + } + } + Err(err) => { + let fail = err.shared(); + self.input = Input::Fail(Arc::clone(&fail)); + Some(Deserializer { + input: Input::Fail(fail), + }) + } + } + } +} + +impl<'de> de::Deserializer<'de> for Deserializer<'de> { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_any(visitor)) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_bool(visitor)) + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_i8(visitor)) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_i16(visitor)) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_i32(visitor)) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_i64(visitor)) + } + + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_i128(visitor)) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_u8(visitor)) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_u16(visitor)) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_u32(visitor)) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_u64(visitor)) + } + + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_u128(visitor)) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_f32(visitor)) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_f64(visitor)) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_char(visitor)) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_str(visitor)) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_string(visitor)) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_bytes(visitor)) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_byte_buf(visitor)) + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_option(visitor)) + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_unit(visitor)) + } + + fn deserialize_unit_struct(self, name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_unit_struct(name, visitor)) + } + + fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_newtype_struct(name, visitor)) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_seq(visitor)) + } + + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_tuple(len, visitor)) + } + + fn deserialize_tuple_struct( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_tuple_struct(name, len, visitor)) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_map(visitor)) + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_struct(name, fields, visitor)) + } + + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_enum(name, variants, visitor)) + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_identifier(visitor)) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de(|state| state.deserialize_ignored_any(visitor)) + } +} + +pub struct Loader { + events: Vec<(Event, Marker)>, + /// Map from alias id to index in events. + aliases: BTreeMap, +} + +impl MarkedEventReceiver for Loader { + fn on_event(&mut self, event: YamlEvent, marker: Marker) { + let event = match event { + YamlEvent::Nothing + | YamlEvent::StreamStart + | YamlEvent::StreamEnd + | YamlEvent::DocumentStart + | YamlEvent::DocumentEnd => return, + + YamlEvent::Alias(id) => Event::Alias(id), + YamlEvent::Scalar(value, style, id, tag) => { + self.aliases.insert(id, self.events.len()); + Event::Scalar(value, style, tag) + } + YamlEvent::SequenceStart(id) => { + self.aliases.insert(id, self.events.len()); + Event::SequenceStart + } + YamlEvent::SequenceEnd => Event::SequenceEnd, + YamlEvent::MappingStart(id) => { + self.aliases.insert(id, self.events.len()); + Event::MappingStart + } + YamlEvent::MappingEnd => Event::MappingEnd, + }; + self.events.push((event, marker)); + } +} + +#[derive(Debug, PartialEq)] +enum Event { + Alias(usize), + Scalar(String, TScalarStyle, Option), + SequenceStart, + SequenceEnd, + MappingStart, + MappingEnd, +} + +struct DeserializerFromEvents<'a> { + events: &'a [(Event, Marker)], + /// Map from alias id to index in events. + aliases: &'a BTreeMap, + pos: &'a mut usize, + path: Path<'a>, + remaining_depth: u8, +} + +impl<'a> DeserializerFromEvents<'a> { + fn peek(&self) -> Result<(&'a Event, Marker)> { + match self.events.get(*self.pos) { + Some(event) => Ok((&event.0, event.1)), + None => Err(error::end_of_stream()), + } + } + + fn next(&mut self) -> Result<(&'a Event, Marker)> { + self.opt_next().ok_or_else(error::end_of_stream) + } + + fn opt_next(&mut self) -> Option<(&'a Event, Marker)> { + self.events.get(*self.pos).map(|event| { + *self.pos += 1; + (&event.0, event.1) + }) + } + + fn jump(&'a self, pos: &'a mut usize) -> Result> { + match self.aliases.get(pos) { + Some(&found) => { + *pos = found; + Ok(DeserializerFromEvents { + events: self.events, + aliases: self.aliases, + pos, + path: Path::Alias { parent: &self.path }, + remaining_depth: self.remaining_depth, + }) + } + None => panic!("unresolved alias: {}", *pos), + } + } + + fn ignore_any(&mut self) { + enum Nest { + Sequence, + Mapping, + } + + let mut stack = Vec::new(); + + while let Some((event, _)) = self.opt_next() { + match event { + Event::Alias(_) | Event::Scalar(_, _, _) => {} + Event::SequenceStart => { + stack.push(Nest::Sequence); + } + Event::MappingStart => { + stack.push(Nest::Mapping); + } + Event::SequenceEnd => match stack.pop() { + Some(Nest::Sequence) => {} + None | Some(Nest::Mapping) => { + panic!("unexpected end of sequence"); + } + }, + Event::MappingEnd => match stack.pop() { + Some(Nest::Mapping) => {} + None | Some(Nest::Sequence) => { + panic!("unexpected end of mapping"); + } + }, + } + if stack.is_empty() { + return; + } + } + + if !stack.is_empty() { + panic!("missing end event"); + } + } + + fn visit_sequence<'de, V>(&mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (value, len) = self.recursion_check(|de| { + let mut seq = SeqAccess { de, len: 0 }; + let value = visitor.visit_seq(&mut seq)?; + Ok((value, seq.len)) + })?; + self.end_sequence(len)?; + Ok(value) + } + + fn visit_mapping<'de, V>(&mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (value, len) = self.recursion_check(|de| { + let mut map = MapAccess { + de, + len: 0, + key: None, + }; + let value = visitor.visit_map(&mut map)?; + Ok((value, map.len)) + })?; + self.end_mapping(len)?; + Ok(value) + } + + fn end_sequence(&mut self, len: usize) -> Result<()> { + let total = { + let mut seq = SeqAccess { de: self, len }; + while de::SeqAccess::next_element::(&mut seq)?.is_some() {} + seq.len + }; + assert_eq!(Event::SequenceEnd, *self.next()?.0); + if total == len { + Ok(()) + } else { + struct ExpectedSeq(usize); + impl Expected for ExpectedSeq { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + if self.0 == 1 { + write!(formatter, "sequence of 1 element") + } else { + write!(formatter, "sequence of {} elements", self.0) + } + } + } + Err(de::Error::invalid_length(total, &ExpectedSeq(len))) + } + } + + fn end_mapping(&mut self, len: usize) -> Result<()> { + let total = { + let mut map = MapAccess { + de: self, + len, + key: None, + }; + while de::MapAccess::next_entry::(&mut map)?.is_some() {} + map.len + }; + assert_eq!(Event::MappingEnd, *self.next()?.0); + if total == len { + Ok(()) + } else { + struct ExpectedMap(usize); + impl Expected for ExpectedMap { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + if self.0 == 1 { + write!(formatter, "map containing 1 entry") + } else { + write!(formatter, "map containing {} entries", self.0) + } + } + } + Err(de::Error::invalid_length(total, &ExpectedMap(len))) + } + } + + fn recursion_check Result, T>(&mut self, f: F) -> Result { + let previous_depth = self.remaining_depth; + self.remaining_depth = previous_depth + .checked_sub(1) + .ok_or_else(error::recursion_limit_exceeded)?; + let result = f(self); + self.remaining_depth = previous_depth; + result + } +} + +fn visit_scalar<'de, V>( + v: &str, + style: TScalarStyle, + tag: &Option, + visitor: V, +) -> Result +where + V: Visitor<'de>, +{ + if let Some(TokenType::Tag(handle, suffix)) = tag { + if handle == "!!" { + match suffix.as_ref() { + "bool" => match v.parse::() { + Ok(v) => visitor.visit_bool(v), + Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"a boolean")), + }, + "int" => match v.parse::() { + Ok(v) => visitor.visit_i64(v), + Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"an integer")), + }, + "float" => match v.parse::() { + Ok(v) => visitor.visit_f64(v), + Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"a float")), + }, + "null" => match v { + "~" | "null" => visitor.visit_unit(), + _ => Err(de::Error::invalid_value(Unexpected::Str(v), &"null")), + }, + _ => visitor.visit_str(v), + } + } else { + visitor.visit_str(v) + } + } else if style == TScalarStyle::Plain { + visit_untagged_str(visitor, v) + } else { + visitor.visit_str(v) + } +} + +struct SeqAccess<'a: 'r, 'r> { + de: &'r mut DeserializerFromEvents<'a>, + len: usize, +} + +impl<'de, 'a, 'r> de::SeqAccess<'de> for SeqAccess<'a, 'r> { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result> + where + T: DeserializeSeed<'de>, + { + match self.de.peek()?.0 { + Event::SequenceEnd => Ok(None), + _ => { + let mut element_de = DeserializerFromEvents { + events: self.de.events, + aliases: self.de.aliases, + pos: self.de.pos, + path: Path::Seq { + parent: &self.de.path, + index: self.len, + }, + remaining_depth: self.de.remaining_depth, + }; + self.len += 1; + seed.deserialize(&mut element_de).map(Some) + } + } + } +} + +struct MapAccess<'a: 'r, 'r> { + de: &'r mut DeserializerFromEvents<'a>, + len: usize, + key: Option<&'a str>, +} + +impl<'de, 'a, 'r> de::MapAccess<'de> for MapAccess<'a, 'r> { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result> + where + K: DeserializeSeed<'de>, + { + match self.de.peek()?.0 { + Event::MappingEnd => Ok(None), + Event::Scalar(key, _, _) => { + self.len += 1; + self.key = Some(key); + seed.deserialize(&mut *self.de).map(Some) + } + _ => { + self.len += 1; + self.key = None; + seed.deserialize(&mut *self.de).map(Some) + } + } + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>, + { + let mut value_de = DeserializerFromEvents { + events: self.de.events, + aliases: self.de.aliases, + pos: self.de.pos, + path: if let Some(key) = self.key { + Path::Map { + parent: &self.de.path, + key, + } + } else { + Path::Unknown { + parent: &self.de.path, + } + }, + remaining_depth: self.de.remaining_depth, + }; + seed.deserialize(&mut value_de) + } +} + +struct EnumAccess<'a: 'r, 'r> { + de: &'r mut DeserializerFromEvents<'a>, + name: &'static str, + tag: Option<&'static str>, +} + +impl<'de, 'a, 'r> de::EnumAccess<'de> for EnumAccess<'a, 'r> { + type Error = Error; + type Variant = DeserializerFromEvents<'r>; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> + where + V: DeserializeSeed<'de>, + { + #[derive(Debug)] + enum Nope {} + + struct BadKey { + name: &'static str, + } + + impl<'de> Visitor<'de> for BadKey { + type Value = Nope; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "variant of enum `{}`", self.name) + } + } + + let variant = if let Some(tag) = self.tag { + tag + } else { + match self.de.next()?.0 { + Event::Scalar(s, _, _) => &**s, + _ => { + *self.de.pos -= 1; + let bad = BadKey { name: self.name }; + return Err(de::Deserializer::deserialize_any(&mut *self.de, bad).unwrap_err()); + } + } + }; + + let str_de = IntoDeserializer::::into_deserializer(variant); + let ret = seed.deserialize(str_de)?; + let variant_visitor = DeserializerFromEvents { + events: self.de.events, + aliases: self.de.aliases, + pos: self.de.pos, + path: Path::Map { + parent: &self.de.path, + key: variant, + }, + remaining_depth: self.de.remaining_depth, + }; + Ok((ret, variant_visitor)) + } +} + +impl<'de, 'a> de::VariantAccess<'de> for DeserializerFromEvents<'a> { + type Error = Error; + + fn unit_variant(mut self) -> Result<()> { + Deserialize::deserialize(&mut self) + } + + fn newtype_variant_seed(mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + seed.deserialize(&mut self) + } + + fn tuple_variant(mut self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + de::Deserializer::deserialize_seq(&mut self, visitor) + } + + fn struct_variant(mut self, fields: &'static [&'static str], visitor: V) -> Result + where + V: Visitor<'de>, + { + de::Deserializer::deserialize_struct(&mut self, "", fields, visitor) + } +} + +struct UnitVariantAccess<'a: 'r, 'r> { + de: &'r mut DeserializerFromEvents<'a>, +} + +impl<'de, 'a, 'r> de::EnumAccess<'de> for UnitVariantAccess<'a, 'r> { + type Error = Error; + type Variant = Self; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> + where + V: DeserializeSeed<'de>, + { + Ok((seed.deserialize(&mut *self.de)?, self)) + } +} + +impl<'de, 'a, 'r> de::VariantAccess<'de> for UnitVariantAccess<'a, 'r> { + type Error = Error; + + fn unit_variant(self) -> Result<()> { + Ok(()) + } + + fn newtype_variant_seed(self, _seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )) + } + + fn tuple_variant(self, _len: usize, _visitor: V) -> Result + where + V: Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )) + } + + fn struct_variant(self, _fields: &'static [&'static str], _visitor: V) -> Result + where + V: Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )) + } +} + +fn visit_untagged_str<'de, V>(visitor: V, v: &str) -> Result +where + V: Visitor<'de>, +{ + if v == "~" || v == "null" { + return visitor.visit_unit(); + } + if v == "true" { + return visitor.visit_bool(true); + } + if v == "false" { + return visitor.visit_bool(false); + } + if let Some(rest) = Option::or(v.strip_prefix("0x"), v.strip_prefix("+0x")) { + if let Ok(n) = u64::from_str_radix(rest, 16) { + return visitor.visit_u64(n); + } + } + if let Some(rest) = v.strip_prefix("-0x") { + let negative = format!("-{}", rest); + if let Ok(n) = i64::from_str_radix(&negative, 16) { + return visitor.visit_i64(n); + } + } + if let Some(rest) = Option::or(v.strip_prefix("0o"), v.strip_prefix("+0o")) { + if let Ok(n) = u64::from_str_radix(rest, 8) { + return visitor.visit_u64(n); + } + } + if let Some(rest) = v.strip_prefix("-0o") { + let negative = format!("-{}", rest); + if let Ok(n) = i64::from_str_radix(&negative, 8) { + return visitor.visit_i64(n); + } + } + if let Some(rest) = Option::or(v.strip_prefix("0b"), v.strip_prefix("+0b")) { + if let Ok(n) = u64::from_str_radix(rest, 2) { + return visitor.visit_u64(n); + } + } + if let Some(rest) = v.strip_prefix("-0b") { + let negative = format!("-{}", rest); + if let Ok(n) = i64::from_str_radix(&negative, 2) { + return visitor.visit_i64(n); + } + } + if { + let v = v.trim_start_matches(&['-', '+'][..]); + v.len() > 1 && v.starts_with('0') && v[1..].bytes().all(|b| b.is_ascii_digit()) + } { + // After handling the different number encodings above if we are left + // with leading zero(s) followed by numeric characters this is in fact a + // string according to the YAML 1.2 spec. + // https://yaml.org/spec/1.2/spec.html#id2761292 + return visitor.visit_str(v); + } + if let Ok(n) = v.parse() { + return visitor.visit_u64(n); + } + if let Ok(n) = v.parse() { + return visitor.visit_u128(n); + } + if let Ok(n) = v.parse() { + return visitor.visit_i64(n); + } + if let Ok(n) = v.parse() { + return visitor.visit_i128(n); + } + match v.trim_start_matches('+') { + ".inf" | ".Inf" | ".INF" => return visitor.visit_f64(f64::INFINITY), + _ => (), + } + if v == "-.inf" || v == "-.Inf" || v == "-.INF" { + return visitor.visit_f64(f64::NEG_INFINITY); + } + if v == ".nan" || v == ".NaN" || v == ".NAN" { + return visitor.visit_f64(f64::NAN); + } + if let Ok(n) = v.parse::() { + if n.is_finite() { + return visitor.visit_f64(n); + } + } + visitor.visit_str(v) +} + +fn invalid_type(event: &Event, exp: &dyn Expected) -> Error { + enum Void {} + + struct InvalidType<'a> { + exp: &'a dyn Expected, + } + + impl<'de, 'a> Visitor<'de> for InvalidType<'a> { + type Value = Void; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.exp.fmt(formatter) + } + } + + match event { + Event::Alias(_) => unreachable!(), + Event::Scalar(v, style, tag) => { + let get_type = InvalidType { exp }; + match visit_scalar(v, *style, tag, get_type) { + Ok(void) => match void {}, + Err(invalid_type) => invalid_type, + } + } + Event::SequenceStart => de::Error::invalid_type(Unexpected::Seq, exp), + Event::MappingStart => de::Error::invalid_type(Unexpected::Map, exp), + Event::SequenceEnd => panic!("unexpected end of sequence"), + Event::MappingEnd => panic!("unexpected end of mapping"), + } +} + +impl<'a> DeserializerFromEvents<'a> { + fn deserialize_scalar<'de, V>(&mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (next, marker) = self.next()?; + match next { + Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_scalar(visitor), + Event::Scalar(v, style, tag) => visit_scalar(v, *style, tag, visitor), + other => Err(invalid_type(other, &visitor)), + } + .map_err(|err| error::fix_marker(err, marker, self.path)) + } +} + +impl<'de, 'a, 'r> de::Deserializer<'de> for &'r mut DeserializerFromEvents<'a> { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (next, marker) = self.next()?; + match next { + Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_any(visitor), + Event::Scalar(v, style, tag) => visit_scalar(v, *style, tag, visitor), + Event::SequenceStart => self.visit_sequence(visitor), + Event::MappingStart => self.visit_mapping(visitor), + Event::SequenceEnd => panic!("unexpected end of sequence"), + Event::MappingEnd => panic!("unexpected end of mapping"), + } + // The de::Error impl creates errors with unknown line and column. Fill + // in the position here by looking at the current index in the input. + .map_err(|err| error::fix_marker(err, marker, self.path)) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (next, marker) = self.next()?; + match next { + Event::Scalar(v, _, _) => visitor.visit_str(v), + Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_str(visitor), + other => Err(invalid_type(other, &visitor)), + } + .map_err(|err: Error| error::fix_marker(err, marker, self.path)) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_any(visitor) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_bytes(visitor) + } + + /// Parses `null` as None and any other values as `Some(...)`. + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let is_some = match self.peek()?.0 { + Event::Alias(mut pos) => { + *self.pos += 1; + return self.jump(&mut pos)?.deserialize_option(visitor); + } + Event::Scalar(v, style, tag) => { + if *style != TScalarStyle::Plain { + true + } else if let Some(TokenType::Tag(handle, suffix)) = tag { + if handle == "!!" && suffix == "null" { + if v == "~" || v == "null" { + false + } else { + return Err(de::Error::invalid_value(Unexpected::Str(v), &"null")); + } + } else { + true + } + } else { + v != "~" && v != "null" + } + } + Event::SequenceStart | Event::MappingStart => true, + Event::SequenceEnd => panic!("unexpected end of sequence"), + Event::MappingEnd => panic!("unexpected end of mapping"), + }; + if is_some { + visitor.visit_some(self) + } else { + *self.pos += 1; + visitor.visit_none() + } + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_scalar(visitor) + } + + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + /// Parses a newtype struct as the underlying value. + fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (next, marker) = self.next()?; + match next { + Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_seq(visitor), + Event::SequenceStart => self.visit_sequence(visitor), + other => Err(invalid_type(other, &visitor)), + } + .map_err(|err| error::fix_marker(err, marker, self.path)) + } + + fn deserialize_tuple(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let (next, marker) = self.next()?; + match next { + Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_map(visitor), + Event::MappingStart => self.visit_mapping(visitor), + other => Err(invalid_type(other, &visitor)), + } + .map_err(|err| error::fix_marker(err, marker, self.path)) + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (next, marker) = self.next()?; + match next { + Event::Alias(mut pos) => self + .jump(&mut pos)? + .deserialize_struct(name, fields, visitor), + Event::SequenceStart => self.visit_sequence(visitor), + Event::MappingStart => self.visit_mapping(visitor), + other => Err(invalid_type(other, &visitor)), + } + .map_err(|err| error::fix_marker(err, marker, self.path)) + } + + /// Parses an enum as a single key:value pair where the key identifies the + /// variant and the value gives the content. A String will also parse correctly + /// to a unit enum value. + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (next, marker) = self.peek()?; + match next { + Event::Alias(mut pos) => { + *self.pos += 1; + self.jump(&mut pos)? + .deserialize_enum(name, variants, visitor) + } + Event::Scalar(_, _, t) => { + if let Some(TokenType::Tag(handle, suffix)) = t { + if handle == "!" { + if let Some(tag) = variants.iter().find(|v| *v == suffix) { + return visitor.visit_enum(EnumAccess { + de: self, + name, + tag: Some(tag), + }); + } + } + } + visitor.visit_enum(UnitVariantAccess { de: self }) + } + Event::MappingStart => { + *self.pos += 1; + let value = visitor.visit_enum(EnumAccess { + de: self, + name, + tag: None, + })?; + self.end_mapping(1)?; + Ok(value) + } + Event::SequenceStart => { + let err = de::Error::invalid_type(Unexpected::Seq, &"string or singleton map"); + Err(error::fix_marker(err, marker, self.path)) + } + Event::SequenceEnd => panic!("unexpected end of sequence"), + Event::MappingEnd => panic!("unexpected end of mapping"), + } + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.ignore_any(); + visitor.visit_unit() + } +} + +/// Deserialize an instance of type `T` from a string of YAML text. +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a YAML map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the YAML map or some number is too big to fit in the expected primitive +/// type. +/// +/// YAML currently does not support zero-copy deserialization. +pub fn from_str(s: &str) -> Result +where + T: DeserializeOwned, +{ + from_str_seed(s, PhantomData) +} + +/// Deserialize an instance of type `T` from a string of YAML text with a seed. +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a YAML map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the YAML map or some number is too big to fit in the expected primitive +/// type. +/// +/// YAML currently does not support zero-copy deserialization. +pub fn from_str_seed(s: &str, seed: S) -> Result +where + S: for<'de> DeserializeSeed<'de, Value = T>, +{ + seed.deserialize(Deserializer::from_str(s)) +} + +/// Deserialize an instance of type `T` from an IO stream of YAML. +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a YAML map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the YAML map or some number is too big to fit in the expected primitive +/// type. +pub fn from_reader(rdr: R) -> Result +where + R: io::Read, + T: DeserializeOwned, +{ + from_reader_seed(rdr, PhantomData) +} + +/// Deserialize an instance of type `T` from an IO stream of YAML with a seed. +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a YAML map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the YAML map or some number is too big to fit in the expected primitive +/// type. +pub fn from_reader_seed(rdr: R, seed: S) -> Result +where + R: io::Read, + S: for<'de> DeserializeSeed<'de, Value = T>, +{ + seed.deserialize(Deserializer::from_reader(rdr)) +} + +/// Deserialize an instance of type `T` from bytes of YAML text. +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a YAML map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the YAML map or some number is too big to fit in the expected primitive +/// type. +/// +/// YAML currently does not support zero-copy deserialization. +pub fn from_slice(v: &[u8]) -> Result +where + T: DeserializeOwned, +{ + from_slice_seed(v, PhantomData) +} + +/// Deserialize an instance of type `T` from bytes of YAML text with a seed. +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a YAML map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the YAML map or some number is too big to fit in the expected primitive +/// type. +/// +/// YAML currently does not support zero-copy deserialization. +pub fn from_slice_seed(v: &[u8], seed: S) -> Result +where + S: for<'de> DeserializeSeed<'de, Value = T>, +{ + seed.deserialize(Deserializer::from_slice(v)) +} diff --git a/vendor/serde_yaml-0.8.26/src/error.rs b/vendor/serde_yaml-0.8.26/src/error.rs new file mode 100644 index 0000000000000..dc8321435f346 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/src/error.rs @@ -0,0 +1,244 @@ +use crate::path::Path; +use serde::{de, ser}; +use std::error; +use std::fmt::{self, Debug, Display}; +use std::io; +use std::result; +use std::str; +use std::string; +use std::sync::Arc; +use yaml_rust::emitter; +use yaml_rust::scanner::{self, Marker, ScanError}; + +/// An error that happened serializing or deserializing YAML data. +pub struct Error(Box); + +/// Alias for a `Result` with the error type `serde_yaml::Error`. +pub type Result = result::Result; + +#[derive(Debug)] +pub enum ErrorImpl { + Message(String, Option), + + Emit(emitter::EmitError), + Scan(scanner::ScanError), + Io(io::Error), + Utf8(str::Utf8Error), + FromUtf8(string::FromUtf8Error), + + EndOfStream, + MoreThanOneDocument, + RecursionLimitExceeded, + + Shared(Arc), +} + +#[derive(Debug)] +pub struct Pos { + marker: Marker, + path: String, +} + +/// The input location that an error occured. +#[derive(Debug)] +pub struct Location { + index: usize, + line: usize, + column: usize, +} + +impl Location { + /// The byte index of the error + pub fn index(&self) -> usize { + self.index + } + + /// The line of the error + pub fn line(&self) -> usize { + self.line + } + + /// The column of the error + pub fn column(&self) -> usize { + self.column + } + + // This is to keep decoupled with the yaml crate + #[doc(hidden)] + fn from_marker(marker: &Marker) -> Self { + Location { + // `col` returned from the `yaml` crate is 0-indexed but all error messages add + 1 to this value + column: marker.col() + 1, + index: marker.index(), + line: marker.line(), + } + } +} + +impl Error { + /// Returns the Location from the error if one exists. + /// + /// Not all types of errors have a location so this can return `None`. + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::{Value, Error}; + /// # + /// // The `@` character as the first character makes this invalid yaml + /// let invalid_yaml: Result = serde_yaml::from_str("@invalid_yaml"); + /// + /// let location = invalid_yaml.unwrap_err().location().unwrap(); + /// + /// assert_eq!(location.line(), 1); + /// assert_eq!(location.column(), 1); + /// ``` + pub fn location(&self) -> Option { + match self.0.as_ref() { + ErrorImpl::Message(_, Some(pos)) => Some(Location::from_marker(&pos.marker)), + ErrorImpl::Scan(scan) => Some(Location::from_marker(scan.marker())), + _ => None, + } + } +} + +pub(crate) fn end_of_stream() -> Error { + Error(Box::new(ErrorImpl::EndOfStream)) +} + +pub(crate) fn more_than_one_document() -> Error { + Error(Box::new(ErrorImpl::MoreThanOneDocument)) +} + +pub(crate) fn io(err: io::Error) -> Error { + Error(Box::new(ErrorImpl::Io(err))) +} + +pub(crate) fn emitter(err: emitter::EmitError) -> Error { + Error(Box::new(ErrorImpl::Emit(err))) +} + +pub(crate) fn scanner(err: scanner::ScanError) -> Error { + Error(Box::new(ErrorImpl::Scan(err))) +} + +pub(crate) fn str_utf8(err: str::Utf8Error) -> Error { + Error(Box::new(ErrorImpl::Utf8(err))) +} + +pub(crate) fn string_utf8(err: string::FromUtf8Error) -> Error { + Error(Box::new(ErrorImpl::FromUtf8(err))) +} + +pub(crate) fn recursion_limit_exceeded() -> Error { + Error(Box::new(ErrorImpl::RecursionLimitExceeded)) +} + +pub(crate) fn shared(shared: Arc) -> Error { + Error(Box::new(ErrorImpl::Shared(shared))) +} + +pub(crate) fn fix_marker(mut error: Error, marker: Marker, path: Path) -> Error { + if let ErrorImpl::Message(_, none @ None) = error.0.as_mut() { + *none = Some(Pos { + marker, + path: path.to_string(), + }); + } + error +} + +impl Error { + pub(crate) fn shared(self) -> Arc { + if let ErrorImpl::Shared(err) = *self.0 { + err + } else { + Arc::from(self.0) + } + } +} + +impl error::Error for Error { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + self.0.source() + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.display(f) + } +} + +// Remove two layers of verbosity from the debug representation. Humans often +// end up seeing this representation because it is what unwrap() shows. +impl Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.debug(f) + } +} + +impl ser::Error for Error { + fn custom(msg: T) -> Self { + Error(Box::new(ErrorImpl::Message(msg.to_string(), None))) + } +} + +impl de::Error for Error { + fn custom(msg: T) -> Self { + Error(Box::new(ErrorImpl::Message(msg.to_string(), None))) + } +} + +impl ErrorImpl { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match self { + ErrorImpl::Scan(err) => Some(err), + ErrorImpl::Io(err) => Some(err), + ErrorImpl::Utf8(err) => Some(err), + ErrorImpl::FromUtf8(err) => Some(err), + ErrorImpl::Shared(err) => err.source(), + _ => None, + } + } + + fn display(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ErrorImpl::Message(msg, None) => Display::fmt(msg, f), + ErrorImpl::Message(msg, Some(Pos { marker, path })) => { + if path == "." { + write!(f, "{}", ScanError::new(*marker, msg)) + } else { + write!(f, "{}: {}", path, ScanError::new(*marker, msg)) + } + } + ErrorImpl::Emit(emitter::EmitError::FmtError(_)) => f.write_str("yaml-rust fmt error"), + ErrorImpl::Emit(emitter::EmitError::BadHashmapKey) => f.write_str("bad hash map key"), + ErrorImpl::Scan(err) => Display::fmt(err, f), + ErrorImpl::Io(err) => Display::fmt(err, f), + ErrorImpl::Utf8(err) => Display::fmt(err, f), + ErrorImpl::FromUtf8(err) => Display::fmt(err, f), + ErrorImpl::EndOfStream => f.write_str("EOF while parsing a value"), + ErrorImpl::MoreThanOneDocument => f.write_str( + "deserializing from YAML containing more than one document is not supported", + ), + ErrorImpl::RecursionLimitExceeded => f.write_str("recursion limit exceeded"), + ErrorImpl::Shared(err) => err.display(f), + } + } + + fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ErrorImpl::Message(msg, pos) => f.debug_tuple("Message").field(msg).field(pos).finish(), + ErrorImpl::Emit(emit) => f.debug_tuple("Emit").field(emit).finish(), + ErrorImpl::Scan(scan) => f.debug_tuple("Scan").field(scan).finish(), + ErrorImpl::Io(io) => f.debug_tuple("Io").field(io).finish(), + ErrorImpl::Utf8(utf8) => f.debug_tuple("Utf8").field(utf8).finish(), + ErrorImpl::FromUtf8(from_utf8) => f.debug_tuple("FromUtf8").field(from_utf8).finish(), + ErrorImpl::EndOfStream => f.debug_tuple("EndOfStream").finish(), + ErrorImpl::MoreThanOneDocument => f.debug_tuple("MoreThanOneDocument").finish(), + ErrorImpl::RecursionLimitExceeded => f.debug_tuple("RecursionLimitExceeded").finish(), + ErrorImpl::Shared(err) => err.debug(f), + } + } +} diff --git a/vendor/serde_yaml-0.8.26/src/lib.rs b/vendor/serde_yaml-0.8.26/src/lib.rs new file mode 100644 index 0000000000000..f3fc6a9d3c6c0 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/src/lib.rs @@ -0,0 +1,125 @@ +//! [![github]](https://github.com/dtolnay/serde-yaml) [![crates-io]](https://crates.io/crates/serde-yaml) [![docs-rs]](https://docs.rs/serde-yaml) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs +//! +//!
+//! +//! This crate is a Rust library for using the [Serde] serialization framework +//! with data in [YAML] file format. +//! +//! This library does not reimplement a YAML parser; it uses [yaml-rust] which +//! is a pure Rust YAML 1.2 implementation. +//! +//! [Serde]: https://github.com/serde-rs/serde +//! [YAML]: https://yaml.org/ +//! [yaml-rust]: https://github.com/chyh1990/yaml-rust +//! +//! # Examples +//! +//! ``` +//! use std::collections::BTreeMap; +//! +//! fn main() -> Result<(), serde_yaml::Error> { +//! // You have some type. +//! let mut map = BTreeMap::new(); +//! map.insert("x".to_string(), 1.0); +//! map.insert("y".to_string(), 2.0); +//! +//! // Serialize it to a YAML string. +//! let s = serde_yaml::to_string(&map)?; +//! assert_eq!(s, "---\nx: 1.0\ny: 2.0\n"); +//! +//! // Deserialize it back to a Rust type. +//! let deserialized_map: BTreeMap = serde_yaml::from_str(&s)?; +//! assert_eq!(map, deserialized_map); +//! Ok(()) +//! } +//! ``` +//! +//! ## Using Serde derive +//! +//! It can also be used with Serde's serialization code generator `serde_derive` to +//! handle structs and enums defined in your own program. +//! +//! ``` +//! # use serde_derive::{Serialize, Deserialize}; +//! use serde::{Serialize, Deserialize}; +//! +//! #[derive(Debug, PartialEq, Serialize, Deserialize)] +//! struct Point { +//! x: f64, +//! y: f64, +//! } +//! +//! fn main() -> Result<(), serde_yaml::Error> { +//! let point = Point { x: 1.0, y: 2.0 }; +//! +//! let s = serde_yaml::to_string(&point)?; +//! assert_eq!(s, "---\nx: 1.0\ny: 2.0\n"); +//! +//! let deserialized_point: Point = serde_yaml::from_str(&s)?; +//! assert_eq!(point, deserialized_point); +//! Ok(()) +//! } +//! ``` + +#![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.26")] +#![deny(missing_docs)] +// Suppressed clippy_pedantic lints +#![allow( + // buggy + clippy::iter_not_returning_iterator, // https://github.com/rust-lang/rust-clippy/issues/8285 + clippy::question_mark, // https://github.com/rust-lang/rust-clippy/issues/7859 + // private Deserializer::next + clippy::should_implement_trait, + // things are often more readable this way + clippy::cast_lossless, + clippy::checked_conversions, + clippy::if_not_else, + clippy::manual_assert, + clippy::match_like_matches_macro, + clippy::match_same_arms, + clippy::module_name_repetitions, + clippy::needless_pass_by_value, + clippy::option_if_let_else, + clippy::redundant_else, + clippy::single_match_else, + // code is acceptable + clippy::blocks_in_if_conditions, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::derive_partial_eq_without_eq, + clippy::doc_markdown, + clippy::items_after_statements, + clippy::return_self_not_must_use, + // noisy + clippy::missing_errors_doc, + clippy::must_use_candidate, +)] + +pub use crate::de::{from_reader, from_slice, from_str, Deserializer}; +pub use crate::error::{Error, Location, Result}; +pub use crate::ser::{to_string, to_vec, to_writer, Serializer}; +pub use crate::value::{from_value, to_value, Index, Number, Sequence, Value}; + +#[doc(inline)] +pub use crate::mapping::Mapping; + +/// Entry points for deserializing with pre-existing state. +/// +/// These functions are only exposed this way because we don't yet expose a +/// Deserializer type. Data formats that have a public Deserializer should not +/// copy these signatures. +pub mod seed { + pub use super::de::{from_reader_seed, from_slice_seed, from_str_seed}; +} + +mod de; +mod error; +pub mod mapping; +mod number; +mod path; +mod ser; +mod value; diff --git a/vendor/serde_yaml-0.8.26/src/mapping.rs b/vendor/serde_yaml-0.8.26/src/mapping.rs new file mode 100644 index 0000000000000..89f6e413a0e38 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/src/mapping.rs @@ -0,0 +1,512 @@ +//! A YAML mapping and its iterator types. + +use crate::Value; +use indexmap::IndexMap; +use serde::{Deserialize, Deserializer, Serialize}; +use std::cmp::Ordering; +use std::collections::hash_map::DefaultHasher; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::iter::FromIterator; +use std::ops::{Index, IndexMut}; + +/// A YAML mapping in which the keys and values are both `serde_yaml::Value`. +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct Mapping { + map: IndexMap, +} + +impl Mapping { + /// Creates an empty YAML map. + #[inline] + pub fn new() -> Self { + Self::default() + } + + /// Creates an empty YAML map with the given initial capacity. + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + Mapping { + map: IndexMap::with_capacity(capacity), + } + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// into the map. The map may reserve more space to avoid frequent + /// allocations. + /// + /// # Panics + /// + /// Panics if the new allocation size overflows `usize`. + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.map.reserve(additional); + } + + /// Shrinks the capacity of the map as much as possible. It will drop down + /// as much as possible while maintaining the internal rules and possibly + /// leaving some space in accordance with the resize policy. + #[inline] + pub fn shrink_to_fit(&mut self) { + self.map.shrink_to_fit(); + } + + /// Inserts a key-value pair into the map. If the key already existed, the + /// old value is returned. + #[inline] + pub fn insert(&mut self, k: Value, v: Value) -> Option { + self.map.insert(k, v) + } + + /// Checks if the map contains the given key. + #[inline] + pub fn contains_key(&self, k: &Value) -> bool { + self.map.contains_key(k) + } + + /// Returns the value corresponding to the key in the map. + #[inline] + pub fn get(&self, k: &Value) -> Option<&Value> { + self.map.get(k) + } + + /// Returns the mutable reference corresponding to the key in the map. + #[inline] + pub fn get_mut(&mut self, k: &Value) -> Option<&mut Value> { + self.map.get_mut(k) + } + + /// Gets the given key’s corresponding entry in the map for insertion and/or + /// in-place manipulation. + #[inline] + pub fn entry(&mut self, k: Value) -> Entry { + match self.map.entry(k) { + indexmap::map::Entry::Occupied(occupied) => Entry::Occupied(OccupiedEntry { occupied }), + indexmap::map::Entry::Vacant(vacant) => Entry::Vacant(VacantEntry { vacant }), + } + } + + /// Removes and returns the value corresponding to the key from the map. + #[inline] + pub fn remove(&mut self, k: &Value) -> Option { + self.map.remove(k) + } + + /// Returns the maximum number of key-value pairs the map can hold without + /// reallocating. + #[inline] + pub fn capacity(&self) -> usize { + self.map.capacity() + } + + /// Returns the number of key-value pairs in the map. + #[inline] + pub fn len(&self) -> usize { + self.map.len() + } + + /// Returns whether the map is currently empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Clears the map of all key-value pairs. + #[inline] + pub fn clear(&mut self) { + self.map.clear(); + } + + /// Returns a double-ended iterator visiting all key-value pairs in order of + /// insertion. Iterator element type is `(&'a Value, &'a Value)`. + #[inline] + pub fn iter(&self) -> Iter { + Iter { + iter: self.map.iter(), + } + } + + /// Returns a double-ended iterator visiting all key-value pairs in order of + /// insertion. Iterator element type is `(&'a Value, &'a mut ValuE)`. + #[inline] + pub fn iter_mut(&mut self) -> IterMut { + IterMut { + iter: self.map.iter_mut(), + } + } +} + +#[allow(clippy::derive_hash_xor_eq)] +impl Hash for Mapping { + fn hash(&self, state: &mut H) { + // Hash the kv pairs in a way that is not sensitive to their order. + let mut xor = 0; + for (k, v) in self { + let mut hasher = DefaultHasher::new(); + k.hash(&mut hasher); + v.hash(&mut hasher); + xor ^= hasher.finish(); + } + xor.hash(state); + } +} + +impl PartialOrd for Mapping { + fn partial_cmp(&self, other: &Self) -> Option { + let mut self_entries = Vec::from_iter(self); + let mut other_entries = Vec::from_iter(other); + + // Sort in an arbitrary order that is consistent with Value's PartialOrd + // impl. + fn total_cmp(a: &Value, b: &Value) -> Ordering { + match (a, b) { + (Value::Null, Value::Null) => Ordering::Equal, + (Value::Null, _) => Ordering::Less, + (_, Value::Null) => Ordering::Greater, + + (Value::Bool(a), Value::Bool(b)) => a.cmp(b), + (Value::Bool(_), _) => Ordering::Less, + (_, Value::Bool(_)) => Ordering::Greater, + + (Value::Number(a), Value::Number(b)) => a.total_cmp(b), + (Value::Number(_), _) => Ordering::Less, + (_, Value::Number(_)) => Ordering::Greater, + + (Value::String(a), Value::String(b)) => a.cmp(b), + (Value::String(_), _) => Ordering::Less, + (_, Value::String(_)) => Ordering::Greater, + + (Value::Sequence(a), Value::Sequence(b)) => iter_cmp_by(a, b, total_cmp), + (Value::Sequence(_), _) => Ordering::Less, + (_, Value::Sequence(_)) => Ordering::Greater, + + (Value::Mapping(a), Value::Mapping(b)) => { + iter_cmp_by(a, b, |(ak, av), (bk, bv)| { + total_cmp(ak, bk).then_with(|| total_cmp(av, bv)) + }) + } + } + } + + fn iter_cmp_by(this: I, other: I, mut cmp: F) -> Ordering + where + I: IntoIterator, + F: FnMut(I::Item, I::Item) -> Ordering, + { + let mut this = this.into_iter(); + let mut other = other.into_iter(); + + loop { + let x = match this.next() { + None => { + if other.next().is_none() { + return Ordering::Equal; + } else { + return Ordering::Less; + } + } + Some(val) => val, + }; + + let y = match other.next() { + None => return Ordering::Greater, + Some(val) => val, + }; + + match cmp(x, y) { + Ordering::Equal => {} + non_eq => return non_eq, + } + } + } + + // While sorting by map key, we get to assume that no two keys are + // equal, otherwise they wouldn't both be in the map. This is not a safe + // assumption outside of this situation. + let total_cmp = |&(a, _): &_, &(b, _): &_| total_cmp(a, b); + self_entries.sort_by(total_cmp); + other_entries.sort_by(total_cmp); + self_entries.partial_cmp(&other_entries) + } +} + +impl<'a> Index<&'a Value> for Mapping { + type Output = Value; + #[inline] + fn index(&self, index: &'a Value) -> &Value { + self.map.index(index) + } +} + +impl<'a> IndexMut<&'a Value> for Mapping { + #[inline] + fn index_mut(&mut self, index: &'a Value) -> &mut Value { + self.map.index_mut(index) + } +} + +impl Extend<(Value, Value)> for Mapping { + #[inline] + fn extend>(&mut self, iter: I) { + self.map.extend(iter); + } +} + +impl FromIterator<(Value, Value)> for Mapping { + #[inline] + fn from_iter>(iter: I) -> Self { + Mapping { + map: IndexMap::from_iter(iter), + } + } +} + +macro_rules! delegate_iterator { + (($name:ident $($generics:tt)*) => $item:ty) => { + impl $($generics)* Iterator for $name $($generics)* { + type Item = $item; + #[inline] + fn next(&mut self) -> Option { + self.iter.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + } + + impl $($generics)* ExactSizeIterator for $name $($generics)* { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + } + } +} + +/// Iterator over `&serde_yaml::Mapping`. +pub struct Iter<'a> { + iter: indexmap::map::Iter<'a, Value, Value>, +} + +delegate_iterator!((Iter<'a>) => (&'a Value, &'a Value)); + +impl<'a> IntoIterator for &'a Mapping { + type Item = (&'a Value, &'a Value); + type IntoIter = Iter<'a>; + #[inline] + fn into_iter(self) -> Self::IntoIter { + Iter { + iter: self.map.iter(), + } + } +} + +/// Iterator over `&mut serde_yaml::Mapping`. +pub struct IterMut<'a> { + iter: indexmap::map::IterMut<'a, Value, Value>, +} + +delegate_iterator!((IterMut<'a>) => (&'a Value, &'a mut Value)); + +impl<'a> IntoIterator for &'a mut Mapping { + type Item = (&'a Value, &'a mut Value); + type IntoIter = IterMut<'a>; + #[inline] + fn into_iter(self) -> Self::IntoIter { + IterMut { + iter: self.map.iter_mut(), + } + } +} + +/// Iterator over `serde_yaml::Mapping` by value. +pub struct IntoIter { + iter: indexmap::map::IntoIter, +} + +delegate_iterator!((IntoIter) => (Value, Value)); + +impl IntoIterator for Mapping { + type Item = (Value, Value); + type IntoIter = IntoIter; + #[inline] + fn into_iter(self) -> Self::IntoIter { + IntoIter { + iter: self.map.into_iter(), + } + } +} + +/// Entry for an existing key-value pair or a vacant location to insert one. +pub enum Entry<'a> { + /// Existing slot with equivalent key. + Occupied(OccupiedEntry<'a>), + /// Vacant slot (no equivalent key in the map). + Vacant(VacantEntry<'a>), +} + +/// A view into an occupied entry in a [`Mapping`]. It is part of the [`Entry`] +/// enum. +pub struct OccupiedEntry<'a> { + occupied: indexmap::map::OccupiedEntry<'a, Value, Value>, +} + +/// A view into a vacant entry in a [`Mapping`]. It is part of the [`Entry`] +/// enum. +pub struct VacantEntry<'a> { + vacant: indexmap::map::VacantEntry<'a, Value, Value>, +} + +impl<'a> Entry<'a> { + /// Returns a reference to this entry's key. + pub fn key(&self) -> &Value { + match self { + Entry::Vacant(e) => e.key(), + Entry::Occupied(e) => e.key(), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and + /// returns a mutable reference to the value in the entry. + pub fn or_insert(self, default: Value) -> &'a mut Value { + match self { + Entry::Vacant(entry) => entry.insert(default), + Entry::Occupied(entry) => entry.into_mut(), + } + } + + /// Ensures a value is in the entry by inserting the result of the default + /// function if empty, and returns a mutable reference to the value in the + /// entry. + pub fn or_insert_with(self, default: F) -> &'a mut Value + where + F: FnOnce() -> Value, + { + match self { + Entry::Vacant(entry) => entry.insert(default()), + Entry::Occupied(entry) => entry.into_mut(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut Value), + { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } +} + +impl<'a> OccupiedEntry<'a> { + /// Gets a reference to the key in the entry. + #[inline] + pub fn key(&self) -> &Value { + self.occupied.key() + } + + /// Gets a reference to the value in the entry. + #[inline] + pub fn get(&self) -> &Value { + self.occupied.get() + } + + /// Gets a mutable reference to the value in the entry. + #[inline] + pub fn get_mut(&mut self) -> &mut Value { + self.occupied.get_mut() + } + + /// Converts the entry into a mutable reference to its value. + #[inline] + pub fn into_mut(self) -> &'a mut Value { + self.occupied.into_mut() + } + + /// Sets the value of the entry with the `OccupiedEntry`'s key, and returns + /// the entry's old value. + #[inline] + pub fn insert(&mut self, value: Value) -> Value { + self.occupied.insert(value) + } + + /// Takes the value of the entry out of the map, and returns it. + #[inline] + pub fn remove(self) -> Value { + self.occupied.swap_remove() + } +} + +impl<'a> VacantEntry<'a> { + /// Gets a reference to the key that would be used when inserting a value + /// through the VacantEntry. + #[inline] + pub fn key(&self) -> &Value { + self.vacant.key() + } + + /// Sets the value of the entry with the VacantEntry's key, and returns a + /// mutable reference to it. + #[inline] + pub fn insert(self, value: Value) -> &'a mut Value { + self.vacant.insert(value) + } +} + +impl Serialize for Mapping { + #[inline] + fn serialize(&self, serializer: S) -> Result { + use serde::ser::SerializeMap; + let mut map_serializer = serializer.serialize_map(Some(self.len()))?; + for (k, v) in self { + map_serializer.serialize_entry(k, v)?; + } + map_serializer.end() + } +} + +impl<'de> Deserialize<'de> for Mapping { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct Visitor; + + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = Mapping; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a YAML mapping") + } + + #[inline] + fn visit_unit(self) -> Result + where + E: serde::de::Error, + { + Ok(Mapping::new()) + } + + #[inline] + fn visit_map(self, mut visitor: V) -> Result + where + V: serde::de::MapAccess<'de>, + { + let mut values = Mapping::new(); + while let Some((k, v)) = visitor.next_entry()? { + values.insert(k, v); + } + Ok(values) + } + } + + deserializer.deserialize_map(Visitor) + } +} diff --git a/vendor/serde_yaml-0.8.26/src/number.rs b/vendor/serde_yaml-0.8.26/src/number.rs new file mode 100644 index 0000000000000..b3643ba8b1046 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/src/number.rs @@ -0,0 +1,550 @@ +use crate::Error; +use serde::de::{Unexpected, Visitor}; +use serde::{forward_to_deserialize_any, Deserialize, Deserializer, Serialize, Serializer}; +use std::cmp::Ordering; +use std::fmt::{self, Debug, Display}; +use std::hash::{Hash, Hasher}; +use std::i64; + +/// Represents a YAML number, whether integer or floating point. +#[derive(Clone, PartialEq, PartialOrd)] +pub struct Number { + n: N, +} + +// "N" is a prefix of "NegInt"... this is a false positive. +// https://github.com/Manishearth/rust-clippy/issues/1241 +#[allow(clippy::enum_variant_names)] +#[derive(Copy, Clone, Debug)] +enum N { + PosInt(u64), + /// Always less than zero. + NegInt(i64), + /// May be infinite or NaN. + Float(f64), +} + +impl Number { + /// Returns true if the `Number` is an integer between `i64::MIN` and + /// `i64::MAX`. + /// + /// For any Number on which `is_i64` returns true, `as_i64` is guaranteed to + /// return the integer value. + /// + /// ``` + /// # use std::i64; + /// # + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// # + /// let big = i64::MAX as u64 + 10; + /// let v = yaml(r#" + /// a: 64 + /// b: 9223372036854775817 + /// c: 256.0 + /// "#); + /// + /// assert!(v["a"].is_i64()); + /// + /// // Greater than i64::MAX. + /// assert!(!v["b"].is_i64()); + /// + /// // Numbers with a decimal point are not considered integers. + /// assert!(!v["c"].is_i64()); + /// ``` + #[inline] + #[allow(clippy::cast_sign_loss)] + pub fn is_i64(&self) -> bool { + match self.n { + N::PosInt(v) => v <= i64::max_value() as u64, + N::NegInt(_) => true, + N::Float(_) => false, + } + } + + /// Returns true if the `Number` is an integer between zero and `u64::MAX`. + /// + /// For any Number on which `is_u64` returns true, `as_u64` is guaranteed to + /// return the integer value. + /// + /// ``` + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// # + /// let v = yaml(r#" + /// a: 64 + /// b: -64 + /// c: 256.0 + /// "#); + /// + /// assert!(v["a"].is_u64()); + /// + /// // Negative integer. + /// assert!(!v["b"].is_u64()); + /// + /// // Numbers with a decimal point are not considered integers. + /// assert!(!v["c"].is_u64()); + /// ``` + #[inline] + pub fn is_u64(&self) -> bool { + match self.n { + N::PosInt(_) => true, + N::NegInt(_) | N::Float(_) => false, + } + } + + /// Returns true if the `Number` can be represented by f64. + /// + /// For any Number on which `is_f64` returns true, `as_f64` is guaranteed to + /// return the floating point value. + /// + /// Currently this function returns true if and only if both `is_i64` and + /// `is_u64` return false but this is not a guarantee in the future. + /// + /// ``` + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// # + /// let v = yaml(r#" + /// --- + /// a: 256.0 + /// b: 64 + /// c: -64 + /// "#); + /// + /// assert!(v["a"].is_f64()); + /// + /// // Integers. + /// assert!(!v["b"].is_f64()); + /// assert!(!v["c"].is_f64()); + /// ``` + #[inline] + pub fn is_f64(&self) -> bool { + match self.n { + N::Float(_) => true, + N::PosInt(_) | N::NegInt(_) => false, + } + } + + /// If the `Number` is an integer, represent it as i64 if possible. Returns + /// None otherwise. + /// + /// ``` + /// # use std::i64; + /// # + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// # + /// let big = i64::MAX as u64 + 10; + /// let v = yaml(r#" + /// --- + /// a: 64 + /// b: 9223372036854775817 + /// c: 256.0 + /// "#); + /// + /// assert_eq!(v["a"].as_i64(), Some(64)); + /// assert_eq!(v["b"].as_i64(), None); + /// assert_eq!(v["c"].as_i64(), None); + /// ``` + #[inline] + pub fn as_i64(&self) -> Option { + match self.n { + N::PosInt(n) => { + if n <= i64::max_value() as u64 { + Some(n as i64) + } else { + None + } + } + N::NegInt(n) => Some(n), + N::Float(_) => None, + } + } + + /// If the `Number` is an integer, represent it as u64 if possible. Returns + /// None otherwise. + /// + /// ``` + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// # + /// let v = yaml(r#" + /// --- + /// a: 64 + /// b: -64 + /// c: 256.0 + /// "#); + /// + /// assert_eq!(v["a"].as_u64(), Some(64)); + /// assert_eq!(v["b"].as_u64(), None); + /// assert_eq!(v["c"].as_u64(), None); + /// ``` + #[inline] + pub fn as_u64(&self) -> Option { + match self.n { + N::PosInt(n) => Some(n), + N::NegInt(_) | N::Float(_) => None, + } + } + + /// Represents the number as f64 if possible. Returns None otherwise. + /// + /// ``` + /// # + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// let v = yaml(r#" + /// --- + /// a: 256.0 + /// b: 64 + /// c: -64 + /// "#); + /// + /// assert_eq!(v["a"].as_f64(), Some(256.0)); + /// assert_eq!(v["b"].as_f64(), Some(64.0)); + /// assert_eq!(v["c"].as_f64(), Some(-64.0)); + /// ``` + /// + /// ``` + /// # use std::f64; + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// assert_eq!(yaml(".inf").as_f64(), Some(f64::INFINITY)); + /// assert_eq!(yaml("-.inf").as_f64(), Some(f64::NEG_INFINITY)); + /// assert!(yaml(".nan").as_f64().unwrap().is_nan()); + /// ``` + #[inline] + pub fn as_f64(&self) -> Option { + match self.n { + N::PosInt(n) => Some(n as f64), + N::NegInt(n) => Some(n as f64), + N::Float(n) => Some(n), + } + } + + /// Returns true if this value is NaN and false otherwise. + /// + /// ``` + /// # use std::f64; + /// # + /// # use serde_yaml::Number; + /// # + /// assert!(!Number::from(256.0).is_nan()); + /// + /// assert!(Number::from(f64::NAN).is_nan()); + /// + /// assert!(!Number::from(f64::INFINITY).is_nan()); + /// + /// assert!(!Number::from(f64::NEG_INFINITY).is_nan()); + /// + /// assert!(!Number::from(1).is_nan()); + /// ``` + #[inline] + pub fn is_nan(&self) -> bool { + match self.n { + N::PosInt(_) | N::NegInt(_) => false, + N::Float(f) => f.is_nan(), + } + } + + /// Returns true if this value is positive infinity or negative infinity and + /// false otherwise. + /// + /// ``` + /// # use std::f64; + /// # + /// # use serde_yaml::Number; + /// # + /// assert!(!Number::from(256.0).is_infinite()); + /// + /// assert!(!Number::from(f64::NAN).is_infinite()); + /// + /// assert!(Number::from(f64::INFINITY).is_infinite()); + /// + /// assert!(Number::from(f64::NEG_INFINITY).is_infinite()); + /// + /// assert!(!Number::from(1).is_infinite()); + /// ``` + #[inline] + pub fn is_infinite(&self) -> bool { + match self.n { + N::PosInt(_) | N::NegInt(_) => false, + N::Float(f) => f.is_infinite(), + } + } + + /// Returns true if this number is neither infinite nor NaN. + /// + /// ``` + /// # use std::f64; + /// # + /// # use serde_yaml::Number; + /// # + /// assert!(Number::from(256.0).is_finite()); + /// + /// assert!(!Number::from(f64::NAN).is_finite()); + /// + /// assert!(!Number::from(f64::INFINITY).is_finite()); + /// + /// assert!(!Number::from(f64::NEG_INFINITY).is_finite()); + /// + /// assert!(Number::from(1).is_finite()); + /// ``` + #[inline] + pub fn is_finite(&self) -> bool { + match self.n { + N::PosInt(_) | N::NegInt(_) => true, + N::Float(f) => f.is_finite(), + } + } +} + +impl fmt::Display for Number { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.n { + N::PosInt(i) => Display::fmt(&i, formatter), + N::NegInt(i) => Display::fmt(&i, formatter), + N::Float(f) if f.is_nan() => formatter.write_str(".nan"), + N::Float(f) if f.is_infinite() => { + if f.is_sign_negative() { + formatter.write_str("-.inf") + } else { + formatter.write_str(".inf") + } + } + N::Float(f) => Display::fmt(&f, formatter), + } + } +} + +impl Debug for Number { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.n, formatter) + } +} + +impl PartialEq for N { + fn eq(&self, other: &N) -> bool { + match (*self, *other) { + (N::PosInt(a), N::PosInt(b)) => a == b, + (N::NegInt(a), N::NegInt(b)) => a == b, + (N::Float(a), N::Float(b)) => { + if a.is_nan() && b.is_nan() { + // YAML only has one NaN; + // the bit representation isn't preserved + true + } else { + a == b + } + } + _ => false, + } + } +} + +impl PartialOrd for N { + fn partial_cmp(&self, other: &Self) -> Option { + match (*self, *other) { + (N::Float(a), N::Float(b)) => { + if a.is_nan() && b.is_nan() { + // YAML only has one NaN + Some(Ordering::Equal) + } else { + a.partial_cmp(&b) + } + } + _ => Some(self.total_cmp(other)), + } + } +} + +impl N { + fn total_cmp(&self, other: &Self) -> Ordering { + match (*self, *other) { + (N::PosInt(a), N::PosInt(b)) => a.cmp(&b), + (N::NegInt(a), N::NegInt(b)) => a.cmp(&b), + // negint is always less than zero + (N::NegInt(_), N::PosInt(_)) => Ordering::Less, + (N::PosInt(_), N::NegInt(_)) => Ordering::Greater, + (N::Float(a), N::Float(b)) => a.partial_cmp(&b).unwrap_or_else(|| { + // arbitrarily sort the NaN last + if !a.is_nan() { + Ordering::Less + } else if !b.is_nan() { + Ordering::Greater + } else { + Ordering::Equal + } + }), + // arbitrarily sort integers below floats + // FIXME: maybe something more sensible? + (_, N::Float(_)) => Ordering::Less, + (N::Float(_), _) => Ordering::Greater, + } + } +} + +impl Number { + pub(crate) fn total_cmp(&self, other: &Self) -> Ordering { + self.n.total_cmp(&other.n) + } +} + +impl Serialize for Number { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.n { + N::PosInt(i) => serializer.serialize_u64(i), + N::NegInt(i) => serializer.serialize_i64(i), + N::Float(f) => serializer.serialize_f64(f), + } + } +} + +impl<'de> Deserialize<'de> for Number { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct NumberVisitor; + + impl<'de> Visitor<'de> for NumberVisitor { + type Value = Number; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a number") + } + + #[inline] + fn visit_i64(self, value: i64) -> Result { + Ok(value.into()) + } + + #[inline] + fn visit_u64(self, value: u64) -> Result { + Ok(value.into()) + } + + #[inline] + fn visit_f64(self, value: f64) -> Result { + Ok(value.into()) + } + } + + deserializer.deserialize_any(NumberVisitor) + } +} + +impl<'de> Deserializer<'de> for Number { + type Error = Error; + + #[inline] + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.n { + N::PosInt(i) => visitor.visit_u64(i), + N::NegInt(i) => visitor.visit_i64(i), + N::Float(f) => visitor.visit_f64(f), + } + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +impl<'de, 'a> Deserializer<'de> for &'a Number { + type Error = Error; + + #[inline] + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.n { + N::PosInt(i) => visitor.visit_u64(i), + N::NegInt(i) => visitor.visit_i64(i), + N::Float(f) => visitor.visit_f64(f), + } + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +macro_rules! from_signed { + ($($signed_ty:ident)*) => { + $( + impl From<$signed_ty> for Number { + #[inline] + #[allow(clippy::cast_sign_loss)] + fn from(i: $signed_ty) -> Self { + if i < 0 { + Number { n: N::NegInt(i as i64) } + } else { + Number { n: N::PosInt(i as u64) } + } + } + } + )* + }; +} + +macro_rules! from_unsigned { + ($($unsigned_ty:ident)*) => { + $( + impl From<$unsigned_ty> for Number { + #[inline] + fn from(u: $unsigned_ty) -> Self { + Number { n: N::PosInt(u as u64) } + } + } + )* + }; +} + +macro_rules! from_float { + ($($float_ty:ident)*) => { + $( + impl From<$float_ty> for Number { + #[inline] + fn from(f: $float_ty) -> Self { + Number { n: N::Float(f as f64) } + } + } + )* + } +} + +from_signed!(i8 i16 i32 i64 isize); +from_unsigned!(u8 u16 u32 u64 usize); +from_float!(f32 f64); + +// This is fine, because we don't _really_ implement hash for floats +// all other hash functions should work as expected +#[allow(clippy::derive_hash_xor_eq)] +impl Hash for Number { + fn hash(&self, state: &mut H) { + match self.n { + N::Float(_) => { + // you should feel bad for using f64 as a map key + 3.hash(state); + } + N::PosInt(u) => u.hash(state), + N::NegInt(i) => i.hash(state), + } + } +} + +pub(crate) fn unexpected(number: &Number) -> Unexpected { + match number.n { + N::PosInt(u) => Unexpected::Unsigned(u), + N::NegInt(i) => Unexpected::Signed(i), + N::Float(f) => Unexpected::Float(f), + } +} diff --git a/vendor/serde_yaml-0.8.26/src/path.rs b/vendor/serde_yaml-0.8.26/src/path.rs new file mode 100644 index 0000000000000..095add017b545 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/src/path.rs @@ -0,0 +1,34 @@ +use std::fmt::{self, Display}; + +/// Path to the current value in the input, like `dependencies.serde.typo1`. +#[derive(Copy, Clone)] +pub enum Path<'a> { + Root, + Seq { parent: &'a Path<'a>, index: usize }, + Map { parent: &'a Path<'a>, key: &'a str }, + Alias { parent: &'a Path<'a> }, + Unknown { parent: &'a Path<'a> }, +} + +impl<'a> Display for Path<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + struct Parent<'a>(&'a Path<'a>); + + impl<'a> Display for Parent<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match self.0 { + Path::Root => Ok(()), + path => write!(formatter, "{}.", path), + } + } + } + + match self { + Path::Root => formatter.write_str("."), + Path::Seq { parent, index } => write!(formatter, "{}[{}]", parent, index), + Path::Map { parent, key } => write!(formatter, "{}{}", Parent(parent), key), + Path::Alias { parent } => write!(formatter, "{}", parent), + Path::Unknown { parent } => write!(formatter, "{}?", Parent(parent)), + } + } +} diff --git a/vendor/serde_yaml-0.8.26/src/ser.rs b/vendor/serde_yaml-0.8.26/src/ser.rs new file mode 100644 index 0000000000000..6ce5995dffadb --- /dev/null +++ b/vendor/serde_yaml-0.8.26/src/ser.rs @@ -0,0 +1,887 @@ +//! YAML Serialization +//! +//! This module provides YAML serialization with the type `Serializer`. + +use crate::{error, Error, Result}; +use serde::ser; +use std::{fmt, io, num, str}; +use yaml_rust::{yaml, Yaml, YamlEmitter}; + +/// A structure for serializing Rust values into YAML. +/// +/// # Example +/// +/// ``` +/// use anyhow::Result; +/// use serde::Serialize; +/// use std::collections::BTreeMap; +/// +/// fn main() -> Result<()> { +/// let mut buffer = Vec::new(); +/// let mut ser = serde_yaml::Serializer::new(&mut buffer); +/// +/// let mut object = BTreeMap::new(); +/// object.insert("k", 107); +/// object.serialize(&mut ser)?; +/// +/// object.insert("J", 74); +/// object.serialize(&mut ser)?; +/// +/// assert_eq!(buffer, b"---\nk: 107\n...\n---\nJ: 74\nk: 107\n"); +/// Ok(()) +/// } +/// ``` +pub struct Serializer { + documents: usize, + writer: W, +} + +impl Serializer +where + W: io::Write, +{ + /// Creates a new YAML serializer. + pub fn new(writer: W) -> Self { + Serializer { + documents: 0, + writer, + } + } + + /// Calls [`.flush()`](io::Write::flush) on the underlying `io::Write` + /// object. + pub fn flush(&mut self) -> io::Result<()> { + self.writer.flush() + } + + /// Unwrap the underlying `io::Write` object from the `Serializer`. + pub fn into_inner(self) -> W { + self.writer + } + + fn write(&mut self, doc: Yaml) -> Result<()> { + if self.documents > 0 { + self.writer.write_all(b"...\n").map_err(error::io)?; + } + self.documents += 1; + let mut writer_adapter = FmtToIoWriter { + writer: &mut self.writer, + }; + YamlEmitter::new(&mut writer_adapter) + .dump(&doc) + .map_err(error::emitter)?; + writer_adapter.writer.write_all(b"\n").map_err(error::io)?; + Ok(()) + } +} + +impl<'a, W> ser::Serializer for &'a mut Serializer +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + type SerializeSeq = ThenWrite<'a, W, SerializeArray>; + type SerializeTuple = ThenWrite<'a, W, SerializeArray>; + type SerializeTupleStruct = ThenWrite<'a, W, SerializeArray>; + type SerializeTupleVariant = ThenWrite<'a, W, SerializeTupleVariant>; + type SerializeMap = ThenWrite<'a, W, SerializeMap>; + type SerializeStruct = ThenWrite<'a, W, SerializeStruct>; + type SerializeStructVariant = ThenWrite<'a, W, SerializeStructVariant>; + + fn serialize_bool(self, v: bool) -> Result<()> { + let doc = SerializerToYaml.serialize_bool(v)?; + self.write(doc) + } + + fn serialize_i8(self, v: i8) -> Result<()> { + let doc = SerializerToYaml.serialize_i8(v)?; + self.write(doc) + } + + fn serialize_i16(self, v: i16) -> Result<()> { + let doc = SerializerToYaml.serialize_i16(v)?; + self.write(doc) + } + + fn serialize_i32(self, v: i32) -> Result<()> { + let doc = SerializerToYaml.serialize_i32(v)?; + self.write(doc) + } + + fn serialize_i64(self, v: i64) -> Result<()> { + let doc = SerializerToYaml.serialize_i64(v)?; + self.write(doc) + } + + fn serialize_i128(self, v: i128) -> Result<()> { + let doc = SerializerToYaml.serialize_i128(v)?; + self.write(doc) + } + + fn serialize_u8(self, v: u8) -> Result<()> { + let doc = SerializerToYaml.serialize_u8(v)?; + self.write(doc) + } + + fn serialize_u16(self, v: u16) -> Result<()> { + let doc = SerializerToYaml.serialize_u16(v)?; + self.write(doc) + } + + fn serialize_u32(self, v: u32) -> Result<()> { + let doc = SerializerToYaml.serialize_u32(v)?; + self.write(doc) + } + + fn serialize_u64(self, v: u64) -> Result<()> { + let doc = SerializerToYaml.serialize_u64(v)?; + self.write(doc) + } + + fn serialize_u128(self, v: u128) -> Result<()> { + let doc = SerializerToYaml.serialize_u128(v)?; + self.write(doc) + } + + fn serialize_f32(self, v: f32) -> Result<()> { + let doc = SerializerToYaml.serialize_f32(v)?; + self.write(doc) + } + + fn serialize_f64(self, v: f64) -> Result<()> { + let doc = SerializerToYaml.serialize_f64(v)?; + self.write(doc) + } + + fn serialize_char(self, value: char) -> Result<()> { + let doc = SerializerToYaml.serialize_char(value)?; + self.write(doc) + } + + fn serialize_str(self, value: &str) -> Result<()> { + let doc = SerializerToYaml.serialize_str(value)?; + self.write(doc) + } + + fn serialize_bytes(self, value: &[u8]) -> Result<()> { + let doc = SerializerToYaml.serialize_bytes(value)?; + self.write(doc) + } + + fn serialize_unit(self) -> Result<()> { + let doc = SerializerToYaml.serialize_unit()?; + self.write(doc) + } + + fn serialize_unit_struct(self, name: &'static str) -> Result<()> { + let doc = SerializerToYaml.serialize_unit_struct(name)?; + self.write(doc) + } + + fn serialize_unit_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + ) -> Result<()> { + let doc = SerializerToYaml.serialize_unit_variant(name, variant_index, variant)?; + self.write(doc) + } + + fn serialize_newtype_struct(self, name: &'static str, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + let doc = SerializerToYaml.serialize_newtype_struct(name, value)?; + self.write(doc) + } + + fn serialize_newtype_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + let doc = + SerializerToYaml.serialize_newtype_variant(name, variant_index, variant, value)?; + self.write(doc) + } + + fn serialize_none(self) -> Result<()> { + let doc = SerializerToYaml.serialize_none()?; + self.write(doc) + } + + fn serialize_some(self, value: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + let doc = SerializerToYaml.serialize_some(value)?; + self.write(doc) + } + + fn serialize_seq(self, len: Option) -> Result { + let delegate = SerializerToYaml.serialize_seq(len)?; + Ok(ThenWrite::new(self, delegate)) + } + + fn serialize_tuple(self, len: usize) -> Result { + let delegate = SerializerToYaml.serialize_tuple(len)?; + Ok(ThenWrite::new(self, delegate)) + } + + fn serialize_tuple_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + let delegate = SerializerToYaml.serialize_tuple_struct(name, len)?; + Ok(ThenWrite::new(self, delegate)) + } + + fn serialize_tuple_variant( + self, + enm: &'static str, + idx: u32, + variant: &'static str, + len: usize, + ) -> Result { + let delegate = SerializerToYaml.serialize_tuple_variant(enm, idx, variant, len)?; + Ok(ThenWrite::new(self, delegate)) + } + + fn serialize_map(self, len: Option) -> Result { + let delegate = SerializerToYaml.serialize_map(len)?; + Ok(ThenWrite::new(self, delegate)) + } + + fn serialize_struct(self, name: &'static str, len: usize) -> Result { + let delegate = SerializerToYaml.serialize_struct(name, len)?; + Ok(ThenWrite::new(self, delegate)) + } + + fn serialize_struct_variant( + self, + enm: &'static str, + idx: u32, + variant: &'static str, + len: usize, + ) -> Result { + let delegate = SerializerToYaml.serialize_struct_variant(enm, idx, variant, len)?; + Ok(ThenWrite::new(self, delegate)) + } +} + +pub struct ThenWrite<'a, W, D> { + serializer: &'a mut Serializer, + delegate: D, +} + +impl<'a, W, D> ThenWrite<'a, W, D> { + fn new(serializer: &'a mut Serializer, delegate: D) -> Self { + ThenWrite { + serializer, + delegate, + } + } +} + +impl<'a, W> ser::SerializeSeq for ThenWrite<'a, W, SerializeArray> +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_element(&mut self, elem: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.delegate.serialize_element(elem) + } + + fn end(self) -> Result<()> { + let doc = self.delegate.end()?; + self.serializer.write(doc) + } +} + +impl<'a, W> ser::SerializeTuple for ThenWrite<'a, W, SerializeArray> +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_element(&mut self, elem: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.delegate.serialize_element(elem) + } + + fn end(self) -> Result<()> { + let doc = self.delegate.end()?; + self.serializer.write(doc) + } +} + +impl<'a, W> ser::SerializeTupleStruct for ThenWrite<'a, W, SerializeArray> +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, value: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.delegate.serialize_field(value) + } + + fn end(self) -> Result<()> { + let doc = self.delegate.end()?; + self.serializer.write(doc) + } +} + +impl<'a, W> ser::SerializeTupleVariant for ThenWrite<'a, W, SerializeTupleVariant> +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, v: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.delegate.serialize_field(v) + } + + fn end(self) -> Result<()> { + let doc = self.delegate.end()?; + self.serializer.write(doc) + } +} + +impl<'a, W> ser::SerializeMap for ThenWrite<'a, W, SerializeMap> +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_key(&mut self, key: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.delegate.serialize_key(key) + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.delegate.serialize_value(value) + } + + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<()> + where + K: ?Sized + ser::Serialize, + V: ?Sized + ser::Serialize, + { + self.delegate.serialize_entry(key, value) + } + + fn end(self) -> Result<()> { + let doc = self.delegate.end()?; + self.serializer.write(doc) + } +} + +impl<'a, W> ser::SerializeStruct for ThenWrite<'a, W, SerializeStruct> +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.delegate.serialize_field(key, value) + } + + fn end(self) -> Result<()> { + let doc = self.delegate.end()?; + self.serializer.write(doc) + } +} + +impl<'a, W> ser::SerializeStructVariant for ThenWrite<'a, W, SerializeStructVariant> +where + W: io::Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, field: &'static str, v: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.delegate.serialize_field(field, v) + } + + fn end(self) -> Result<()> { + let doc = self.delegate.end()?; + self.serializer.write(doc) + } +} + +pub struct SerializerToYaml; + +impl ser::Serializer for SerializerToYaml { + type Ok = Yaml; + type Error = Error; + + type SerializeSeq = SerializeArray; + type SerializeTuple = SerializeArray; + type SerializeTupleStruct = SerializeArray; + type SerializeTupleVariant = SerializeTupleVariant; + type SerializeMap = SerializeMap; + type SerializeStruct = SerializeStruct; + type SerializeStructVariant = SerializeStructVariant; + + fn serialize_bool(self, v: bool) -> Result { + Ok(Yaml::Boolean(v)) + } + + fn serialize_i8(self, v: i8) -> Result { + self.serialize_i64(v as i64) + } + + fn serialize_i16(self, v: i16) -> Result { + self.serialize_i64(v as i64) + } + + fn serialize_i32(self, v: i32) -> Result { + self.serialize_i64(v as i64) + } + + fn serialize_i64(self, v: i64) -> Result { + Ok(Yaml::Integer(v)) + } + + #[allow(clippy::cast_possible_truncation)] + fn serialize_i128(self, v: i128) -> Result { + if v <= i64::max_value() as i128 && v >= i64::min_value() as i128 { + self.serialize_i64(v as i64) + } else { + Ok(Yaml::Real(v.to_string())) + } + } + + fn serialize_u8(self, v: u8) -> Result { + self.serialize_i64(v as i64) + } + + fn serialize_u16(self, v: u16) -> Result { + self.serialize_i64(v as i64) + } + + fn serialize_u32(self, v: u32) -> Result { + self.serialize_i64(v as i64) + } + + fn serialize_u64(self, v: u64) -> Result { + if v <= i64::max_value() as u64 { + self.serialize_i64(v as i64) + } else { + Ok(Yaml::Real(v.to_string())) + } + } + + #[allow(clippy::cast_possible_truncation)] + fn serialize_u128(self, v: u128) -> Result { + if v <= i64::max_value() as u128 { + self.serialize_i64(v as i64) + } else { + Ok(Yaml::Real(v.to_string())) + } + } + + fn serialize_f32(self, v: f32) -> Result { + Ok(Yaml::Real(match v.classify() { + num::FpCategory::Infinite if v.is_sign_positive() => ".inf".into(), + num::FpCategory::Infinite => "-.inf".into(), + num::FpCategory::Nan => ".nan".into(), + _ => ryu::Buffer::new().format_finite(v).into(), + })) + } + + fn serialize_f64(self, v: f64) -> Result { + Ok(Yaml::Real(match v.classify() { + num::FpCategory::Infinite if v.is_sign_positive() => ".inf".into(), + num::FpCategory::Infinite => "-.inf".into(), + num::FpCategory::Nan => ".nan".into(), + _ => ryu::Buffer::new().format_finite(v).into(), + })) + } + + fn serialize_char(self, value: char) -> Result { + Ok(Yaml::String(value.to_string())) + } + + fn serialize_str(self, value: &str) -> Result { + Ok(Yaml::String(value.to_owned())) + } + + fn serialize_bytes(self, value: &[u8]) -> Result { + let vec = value.iter().map(|&b| Yaml::Integer(b as i64)).collect(); + Ok(Yaml::Array(vec)) + } + + fn serialize_unit(self) -> Result { + Ok(Yaml::Null) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + self.serialize_unit() + } + + fn serialize_unit_variant( + self, + _name: &str, + _variant_index: u32, + variant: &str, + ) -> Result { + Ok(Yaml::String(variant.to_owned())) + } + + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result + where + T: ?Sized + ser::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &str, + _variant_index: u32, + variant: &str, + value: &T, + ) -> Result + where + T: ?Sized + ser::Serialize, + { + Ok(singleton_hash(to_yaml(variant)?, to_yaml(value)?)) + } + + fn serialize_none(self) -> Result { + self.serialize_unit() + } + + fn serialize_some(self, value: &V) -> Result + where + V: ?Sized + ser::Serialize, + { + value.serialize(self) + } + + fn serialize_seq(self, len: Option) -> Result { + let array = match len { + None => yaml::Array::new(), + Some(len) => yaml::Array::with_capacity(len), + }; + Ok(SerializeArray { array }) + } + + fn serialize_tuple(self, len: usize) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct(self, _name: &'static str, len: usize) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_variant( + self, + _enum: &'static str, + _idx: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeTupleVariant { + name: variant, + array: yaml::Array::with_capacity(len), + }) + } + + fn serialize_map(self, _len: Option) -> Result { + Ok(SerializeMap { + hash: yaml::Hash::new(), + next_key: None, + }) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Ok(SerializeStruct { + hash: yaml::Hash::new(), + }) + } + + fn serialize_struct_variant( + self, + _enum: &'static str, + _idx: u32, + variant: &'static str, + _len: usize, + ) -> Result { + Ok(SerializeStructVariant { + name: variant, + hash: yaml::Hash::new(), + }) + } +} + +#[doc(hidden)] +pub struct SerializeArray { + array: yaml::Array, +} + +#[doc(hidden)] +pub struct SerializeTupleVariant { + name: &'static str, + array: yaml::Array, +} + +#[doc(hidden)] +pub struct SerializeMap { + hash: yaml::Hash, + next_key: Option, +} + +#[doc(hidden)] +pub struct SerializeStruct { + hash: yaml::Hash, +} + +#[doc(hidden)] +pub struct SerializeStructVariant { + name: &'static str, + hash: yaml::Hash, +} + +impl ser::SerializeSeq for SerializeArray { + type Ok = yaml::Yaml; + type Error = Error; + + fn serialize_element(&mut self, elem: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.array.push(to_yaml(elem)?); + Ok(()) + } + + fn end(self) -> Result { + Ok(Yaml::Array(self.array)) + } +} + +impl ser::SerializeTuple for SerializeArray { + type Ok = yaml::Yaml; + type Error = Error; + + fn serialize_element(&mut self, elem: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, elem) + } + + fn end(self) -> Result { + ser::SerializeSeq::end(self) + } +} + +impl ser::SerializeTupleStruct for SerializeArray { + type Ok = yaml::Yaml; + type Error = Error; + + fn serialize_field(&mut self, value: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result { + ser::SerializeSeq::end(self) + } +} + +impl ser::SerializeTupleVariant for SerializeTupleVariant { + type Ok = yaml::Yaml; + type Error = Error; + + fn serialize_field(&mut self, v: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.array.push(to_yaml(v)?); + Ok(()) + } + + fn end(self) -> Result { + Ok(singleton_hash(to_yaml(self.name)?, Yaml::Array(self.array))) + } +} + +impl ser::SerializeMap for SerializeMap { + type Ok = yaml::Yaml; + type Error = Error; + + fn serialize_key(&mut self, key: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.next_key = Some(to_yaml(key)?); + Ok(()) + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + match self.next_key.take() { + Some(key) => self.hash.insert(key, to_yaml(value)?), + None => panic!("serialize_value called before serialize_key"), + }; + Ok(()) + } + + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<()> + where + K: ?Sized + ser::Serialize, + V: ?Sized + ser::Serialize, + { + self.hash.insert(to_yaml(key)?, to_yaml(value)?); + Ok(()) + } + + fn end(self) -> Result { + Ok(Yaml::Hash(self.hash)) + } +} + +impl ser::SerializeStruct for SerializeStruct { + type Ok = yaml::Yaml; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.hash.insert(to_yaml(key)?, to_yaml(value)?); + Ok(()) + } + + fn end(self) -> Result { + Ok(Yaml::Hash(self.hash)) + } +} + +impl ser::SerializeStructVariant for SerializeStructVariant { + type Ok = yaml::Yaml; + type Error = Error; + + fn serialize_field(&mut self, field: &'static str, v: &V) -> Result<()> + where + V: ?Sized + ser::Serialize, + { + self.hash.insert(to_yaml(field)?, to_yaml(v)?); + Ok(()) + } + + fn end(self) -> Result { + Ok(singleton_hash(to_yaml(self.name)?, Yaml::Hash(self.hash))) + } +} + +/// Serialize the given data structure as YAML into the IO stream. +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// return an error. +pub fn to_writer(writer: W, value: &T) -> Result<()> +where + W: io::Write, + T: ?Sized + ser::Serialize, +{ + value.serialize(&mut Serializer::new(writer)) +} + +/// Serialize the given data structure as a YAML byte vector. +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// return an error. +pub fn to_vec(value: &T) -> Result> +where + T: ?Sized + ser::Serialize, +{ + let mut vec = Vec::with_capacity(128); + to_writer(&mut vec, value)?; + Ok(vec) +} + +/// Serialize the given data structure as a String of YAML. +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// return an error. +pub fn to_string(value: &T) -> Result +where + T: ?Sized + ser::Serialize, +{ + String::from_utf8(to_vec(value)?).map_err(error::string_utf8) +} + +/// The yaml-rust library uses `fmt::Write` intead of `io::Write` so this is a +/// simple adapter. +struct FmtToIoWriter { + writer: W, +} + +impl fmt::Write for FmtToIoWriter +where + W: io::Write, +{ + fn write_str(&mut self, s: &str) -> fmt::Result { + if self.writer.write_all(s.as_bytes()).is_err() { + return Err(fmt::Error); + } + Ok(()) + } +} + +fn to_yaml(elem: T) -> Result +where + T: ser::Serialize, +{ + elem.serialize(SerializerToYaml) +} + +fn singleton_hash(k: Yaml, v: Yaml) -> Yaml { + let mut hash = yaml::Hash::new(); + hash.insert(k, v); + Yaml::Hash(hash) +} diff --git a/vendor/serde_yaml-0.8.26/src/value/de.rs b/vendor/serde_yaml-0.8.26/src/value/de.rs new file mode 100644 index 0000000000000..61e04696934d6 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/src/value/de.rs @@ -0,0 +1,707 @@ +use crate::{number, Error, Mapping, Sequence, Value}; +use serde::de::{ + self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error as SError, Expected, + MapAccess, SeqAccess, Unexpected, VariantAccess, Visitor, +}; +use serde::forward_to_deserialize_any; +use std::fmt; +use std::vec; + +impl<'de> Deserialize<'de> for Value { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ValueVisitor; + + impl<'de> Visitor<'de> for ValueVisitor { + type Value = Value; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("any YAML value") + } + + fn visit_bool(self, b: bool) -> Result + where + E: SError, + { + Ok(Value::Bool(b)) + } + + fn visit_i64(self, i: i64) -> Result + where + E: SError, + { + Ok(Value::Number(i.into())) + } + + fn visit_u64(self, u: u64) -> Result + where + E: SError, + { + Ok(Value::Number(u.into())) + } + + fn visit_f64(self, f: f64) -> Result + where + E: SError, + { + Ok(Value::Number(f.into())) + } + + fn visit_str(self, s: &str) -> Result + where + E: SError, + { + Ok(Value::String(s.to_owned())) + } + + fn visit_string(self, s: String) -> Result + where + E: SError, + { + Ok(Value::String(s)) + } + + fn visit_unit(self) -> Result + where + E: SError, + { + Ok(Value::Null) + } + + fn visit_none(self) -> Result + where + E: SError, + { + Ok(Value::Null) + } + + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer) + } + + fn visit_seq(self, mut visitor: V) -> Result + where + V: SeqAccess<'de>, + { + let mut vec = Vec::new(); + + while let Some(element) = visitor.next_element()? { + vec.push(element); + } + + Ok(Value::Sequence(vec)) + } + + fn visit_map(self, mut visitor: V) -> Result + where + V: MapAccess<'de>, + { + let mut values = Mapping::new(); + + while let Some((key, value)) = visitor.next_entry()? { + values.insert(key, value); + } + + Ok(Value::Mapping(values)) + } + } + + deserializer.deserialize_any(ValueVisitor) + } +} + +impl Value { + fn deserialize_number<'de, V>(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Number(n) => n.deserialize_any(visitor), + _ => Err(self.invalid_type(&visitor)), + } + } +} + +fn visit_sequence<'de, V>(sequence: Sequence, visitor: V) -> Result +where + V: Visitor<'de>, +{ + let len = sequence.len(); + let mut deserializer = SeqDeserializer::new(sequence); + let seq = visitor.visit_seq(&mut deserializer)?; + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(seq) + } else { + Err(Error::invalid_length(len, &"fewer elements in sequence")) + } +} + +fn visit_mapping<'de, V>(mapping: Mapping, visitor: V) -> Result +where + V: Visitor<'de>, +{ + let len = mapping.len(); + let mut deserializer = MapDeserializer::new(mapping); + let map = visitor.visit_map(&mut deserializer)?; + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(map) + } else { + Err(Error::invalid_length(len, &"fewer elements in map")) + } +} + +impl<'de> Deserializer<'de> for Value { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_unit(), + Value::Bool(v) => visitor.visit_bool(v), + Value::Number(n) => n.deserialize_any(visitor), + Value::String(v) => visitor.visit_string(v), + Value::Sequence(v) => visit_sequence(v, visitor), + Value::Mapping(v) => visit_mapping(v, visitor), + } + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Bool(v) => visitor.visit_bool(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_number(visitor) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::String(v) => visitor.visit_string(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_byte_buf(visitor) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::String(v) => visitor.visit_string(v), + Value::Sequence(v) => visit_sequence(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_none(), + _ => visitor.visit_some(self), + } + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_unit(), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Sequence(v) => visit_sequence(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_tuple(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Mapping(v) => visit_mapping(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Sequence(v) => visit_sequence(v, visitor), + Value::Mapping(v) => visit_mapping(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (variant, value) = match self { + Value::Mapping(value) => { + let mut iter = value.into_iter(); + let (variant, value) = match iter.next() { + Some(v) => v, + None => { + return Err(Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )); + } + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )); + } + (variant, Some(value)) + } + Value::String(variant) => (Value::String(variant), None), + other => { + return Err(Error::invalid_type(other.unexpected(), &"string or map")); + } + }; + + visitor.visit_enum(EnumDeserializer { variant, value }) + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + drop(self); + visitor.visit_unit() + } +} + +struct EnumDeserializer { + variant: Value, + value: Option, +} + +impl<'de> EnumAccess<'de> for EnumDeserializer { + type Error = Error; + type Variant = VariantDeserializer; + + fn variant_seed(self, seed: V) -> Result<(V::Value, VariantDeserializer), Error> + where + V: DeserializeSeed<'de>, + { + let visitor = VariantDeserializer { value: self.value }; + seed.deserialize(self.variant).map(|v| (v, visitor)) + } +} + +struct VariantDeserializer { + value: Option, +} + +impl<'de> VariantAccess<'de> for VariantDeserializer { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + match self.value { + Some(value) => Deserialize::deserialize(value), + None => Ok(()), + } + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value { + Some(value) => seed.deserialize(value), + None => Err(Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Sequence(v)) => { + Deserializer::deserialize_any(SeqDeserializer::new(v), visitor) + } + Some(other) => Err(Error::invalid_type(other.unexpected(), &"tuple variant")), + None => Err(Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )), + } + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Mapping(v)) => { + Deserializer::deserialize_any(MapDeserializer::new(v), visitor) + } + Some(other) => Err(Error::invalid_type(other.unexpected(), &"struct variant")), + None => Err(Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )), + } + } +} + +struct SeqDeserializer { + iter: vec::IntoIter, +} + +impl SeqDeserializer { + fn new(vec: Vec) -> Self { + SeqDeserializer { + iter: vec.into_iter(), + } + } +} + +impl<'de> Deserializer<'de> for SeqDeserializer { + type Error = Error; + + #[inline] + fn deserialize_any(mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let len = self.iter.len(); + if len == 0 { + visitor.visit_unit() + } else { + let ret = visitor.visit_seq(&mut self)?; + let remaining = self.iter.len(); + if remaining == 0 { + Ok(ret) + } else { + Err(Error::invalid_length(len, &"fewer elements in sequence")) + } + } + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + drop(self); + visitor.visit_unit() + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes + byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct + map struct enum identifier + } +} + +impl<'de> SeqAccess<'de> for SeqDeserializer { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => seed.deserialize(value).map(Some), + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +struct MapDeserializer { + iter: ::IntoIter, + value: Option, +} + +impl MapDeserializer { + fn new(map: Mapping) -> Self { + MapDeserializer { + iter: map.into_iter(), + value: None, + } + } +} + +impl<'de> MapAccess<'de> for MapDeserializer { + type Error = Error; + + fn next_key_seed(&mut self, seed: T) -> Result, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some((key, value)) => { + self.value = Some(value); + seed.deserialize(key).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value.take() { + Some(value) => seed.deserialize(value), + None => panic!("visit_value called before visit_key"), + } + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +impl<'de> Deserializer<'de> for MapDeserializer { + type Error = Error; + + #[inline] + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_map(self) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + drop(self); + visitor.visit_unit() + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes + byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct + map struct enum identifier + } +} + +impl Value { + #[cold] + fn invalid_type(&self, exp: &dyn Expected) -> E + where + E: de::Error, + { + de::Error::invalid_type(self.unexpected(), exp) + } + + #[cold] + fn unexpected(&self) -> Unexpected { + match self { + Value::Null => Unexpected::Unit, + Value::Bool(b) => Unexpected::Bool(*b), + Value::Number(n) => number::unexpected(n), + Value::String(s) => Unexpected::Str(s), + Value::Sequence(_) => Unexpected::Seq, + Value::Mapping(_) => Unexpected::Map, + } + } +} diff --git a/vendor/serde_yaml-0.8.26/src/value/from.rs b/vendor/serde_yaml-0.8.26/src/value/from.rs new file mode 100644 index 0000000000000..c02855d3b1b5c --- /dev/null +++ b/vendor/serde_yaml-0.8.26/src/value/from.rs @@ -0,0 +1,180 @@ +use crate::{Mapping, Value}; + +// Implement a bunch of conversion to make it easier to create YAML values +// on the fly. + +macro_rules! from_number { + ($($ty:ident)*) => { + $( + impl From<$ty> for Value { + fn from(n: $ty) -> Self { + Value::Number(n.into()) + } + } + )* + }; +} + +from_number! { + i8 i16 i32 i64 isize + u8 u16 u32 u64 usize + f32 f64 +} + +impl From for Value { + /// Convert boolean to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let b = false; + /// let x: Value = b.into(); + /// ``` + fn from(f: bool) -> Self { + Value::Bool(f) + } +} + +impl From for Value { + /// Convert `String` to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let s: String = "lorem".to_string(); + /// let x: Value = s.into(); + /// ``` + fn from(f: String) -> Self { + Value::String(f) + } +} + +impl<'a> From<&'a str> for Value { + /// Convert string slice to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let s: &str = "lorem"; + /// let x: Value = s.into(); + /// ``` + fn from(f: &str) -> Self { + Value::String(f.to_string()) + } +} + +use std::borrow::Cow; + +impl<'a> From> for Value { + /// Convert copy-on-write string to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// use std::borrow::Cow; + /// + /// let s: Cow = Cow::Borrowed("lorem"); + /// let x: Value = s.into(); + /// ``` + /// + /// ``` + /// use serde_yaml::Value; + /// use std::borrow::Cow; + /// + /// let s: Cow = Cow::Owned("lorem".to_string()); + /// let x: Value = s.into(); + /// ``` + fn from(f: Cow<'a, str>) -> Self { + Value::String(f.to_string()) + } +} + +impl From for Value { + /// Convert map (with string keys) to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::{Mapping, Value}; + /// + /// let mut m = Mapping::new(); + /// m.insert("Lorem".into(), "ipsum".into()); + /// let x: Value = m.into(); + /// ``` + fn from(f: Mapping) -> Self { + Value::Mapping(f) + } +} + +impl> From> for Value { + /// Convert a `Vec` to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let v = vec!["lorem", "ipsum", "dolor"]; + /// let x: Value = v.into(); + /// ``` + fn from(f: Vec) -> Self { + Value::Sequence(f.into_iter().map(Into::into).collect()) + } +} + +impl<'a, T: Clone + Into> From<&'a [T]> for Value { + /// Convert a slice to `Value` + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let v: &[&str] = &["lorem", "ipsum", "dolor"]; + /// let x: Value = v.into(); + /// ``` + fn from(f: &'a [T]) -> Self { + Value::Sequence(f.iter().cloned().map(Into::into).collect()) + } +} + +use std::iter::FromIterator; + +impl> FromIterator for Value { + /// Convert an iteratable type to a YAML sequence + /// + /// # Examples + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let v = std::iter::repeat(42).take(5); + /// let x: Value = v.collect(); + /// ``` + /// + /// ``` + /// use serde_yaml::Value; + /// + /// let v: Vec<_> = vec!["lorem", "ipsum", "dolor"]; + /// let x: Value = v.into_iter().collect(); + /// ``` + /// + /// ``` + /// use std::iter::FromIterator; + /// use serde_yaml::Value; + /// + /// let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]); + /// ``` + fn from_iter>(iter: I) -> Self { + let vec = iter.into_iter().map(T::into).collect(); + + Value::Sequence(vec) + } +} diff --git a/vendor/serde_yaml-0.8.26/src/value/index.rs b/vendor/serde_yaml-0.8.26/src/value/index.rs new file mode 100644 index 0000000000000..b5f5e90160b25 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/src/value/index.rs @@ -0,0 +1,260 @@ +use crate::{Mapping, Value}; +use std::fmt; +use std::ops; + +/// A type that can be used to index into a `serde_yaml::Value`. See the `get` +/// and `get_mut` methods of `Value`. +/// +/// This trait is sealed and cannot be implemented for types outside of +/// `serde_yaml`. +pub trait Index: private::Sealed { + /// Return None if the key is not already in the sequence or object. + #[doc(hidden)] + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>; + + /// Return None if the key is not already in the sequence or object. + #[doc(hidden)] + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>; + + /// Panic if sequence index out of bounds. If key is not already in the object, + /// insert it with a value of null. Panic if Value is a type that cannot be + /// indexed into, except if Value is null then it can be treated as an empty + /// object. + #[doc(hidden)] + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value; +} + +impl Index for usize { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + match v { + Value::Sequence(vec) => vec.get(*self), + Value::Mapping(vec) => vec.get(&Value::Number((*self).into())), + _ => None, + } + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + match v { + Value::Sequence(vec) => vec.get_mut(*self), + Value::Mapping(vec) => vec.get_mut(&Value::Number((*self).into())), + _ => None, + } + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + match v { + Value::Sequence(vec) => { + let len = vec.len(); + vec.get_mut(*self).unwrap_or_else(|| { + panic!( + "cannot access index {} of YAML sequence of length {}", + self, len + ) + }) + } + Value::Mapping(map) => { + let n = Value::Number((*self).into()); + // TODO: use entry() once LinkedHashMap supports entry() + // https://github.com/contain-rs/linked-hash-map/issues/5 + if !map.contains_key(&n) { + map.insert(n.clone(), Value::Null); + } + map.get_mut(&n).unwrap() + } + _ => panic!("cannot access index {} of YAML {}", self, Type(v)), + } + } +} + +impl Index for Value { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + match v { + Value::Mapping(map) => map.get(self), + _ => None, + } + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + match v { + Value::Mapping(map) => map.get_mut(self), + _ => None, + } + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + if let Value::Null = *v { + let mut map = Mapping::new(); + map.insert(self.clone(), Value::Null); + *v = Value::Mapping(map); + } + match v { + Value::Mapping(map) => { + // TODO: use entry() once LinkedHashMap supports entry() + // https://github.com/contain-rs/linked-hash-map/issues/5 + if !map.contains_key(self) { + map.insert(self.clone(), Value::Null); + } + map.get_mut(self).unwrap() + } + _ => panic!("cannot access key {:?} in YAML {}", self, Type(v)), + } + } +} + +impl Index for str { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + Value::String(self.into()).index_into(v) + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + Value::String(self.into()).index_into_mut(v) + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + Value::String(self.into()).index_or_insert(v) + } +} + +impl Index for String { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + Value::String(self.clone()).index_into(v) + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + Value::String(self.clone()).index_into_mut(v) + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + Value::String(self.clone()).index_or_insert(v) + } +} + +impl<'a, T> Index for &'a T +where + T: ?Sized + Index, +{ + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + (**self).index_into(v) + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + (**self).index_into_mut(v) + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + (**self).index_or_insert(v) + } +} + +// Prevent users from implementing the Index trait. +mod private { + pub trait Sealed {} + impl Sealed for usize {} + impl Sealed for str {} + impl Sealed for String {} + impl Sealed for super::Value {} + impl<'a, T> Sealed for &'a T where T: ?Sized + Sealed {} +} + +/// Used in panic messages. +struct Type<'a>(&'a Value); + +impl<'a> fmt::Display for Type<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + Value::Null => formatter.write_str("null"), + Value::Bool(_) => formatter.write_str("boolean"), + Value::Number(_) => formatter.write_str("number"), + Value::String(_) => formatter.write_str("string"), + Value::Sequence(_) => formatter.write_str("sequence"), + Value::Mapping(_) => formatter.write_str("mapping"), + } + } +} + +// The usual semantics of Index is to panic on invalid indexing. +// +// That said, the usual semantics are for things like `Vec` and `BTreeMap` which +// have different use cases than Value. If you are working with a Vec, you know +// that you are working with a Vec and you can get the len of the Vec and make +// sure your indices are within bounds. The Value use cases are more +// loosey-goosey. You got some YAML from an endpoint and you want to pull values +// out of it. Outside of this Index impl, you already have the option of using +// `value.as_sequence()` and working with the Vec directly, or matching on +// `Value::Sequence` and getting the Vec directly. The Index impl means you can +// skip that and index directly into the thing using a concise syntax. You don't +// have to check the type, you don't have to check the len, it is all about what +// you expect the Value to look like. +// +// Basically the use cases that would be well served by panicking here are +// better served by using one of the other approaches: `get` and `get_mut`, +// `as_sequence`, or match. The value of this impl is that it adds a way of +// working with Value that is not well served by the existing approaches: +// concise and careless and sometimes that is exactly what you want. +impl ops::Index for Value +where + I: Index, +{ + type Output = Value; + + /// Index into a `serde_yaml::Value` using the syntax `value[0]` or + /// `value["k"]`. + /// + /// Returns `Value::Null` if the type of `self` does not match the type of + /// the index, for example if the index is a string and `self` is a sequence + /// or a number. Also returns `Value::Null` if the given key does not exist + /// in the map or the given index is not within the bounds of the sequence. + /// + /// For retrieving deeply nested values, you should have a look at the + /// `Value::pointer` method. + /// + /// # Examples + /// + /// ``` + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// # + /// let data = yaml(r#"{ x: { y: [z, zz] } }"#); + /// + /// assert_eq!(data["x"]["y"], yaml(r#"["z", "zz"]"#)); + /// assert_eq!(data["x"]["y"][0], yaml(r#""z""#)); + /// + /// assert_eq!(data["a"], yaml(r#"null"#)); // returns null for undefined values + /// assert_eq!(data["a"]["b"], yaml(r#"null"#)); // does not panic + /// ``` + fn index(&self, index: I) -> &Value { + static NULL: Value = Value::Null; + index.index_into(self).unwrap_or(&NULL) + } +} + +impl ops::IndexMut for Value +where + I: Index, +{ + /// Write into a `serde_yaml::Value` using the syntax `value[0] = ...` or + /// `value["k"] = ...`. + /// + /// If the index is a number, the value must be a sequence of length bigger + /// than the index. Indexing into a value that is not a sequence or a + /// sequence that is too small will panic. + /// + /// If the index is a string, the value must be an object or null which is + /// treated like an empty object. If the key is not already present in the + /// object, it will be inserted with a value of null. Indexing into a value + /// that is neither an object nor null will panic. + /// + /// # Examples + /// + /// ``` + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// # + /// let mut data = yaml(r#"{x: 0}"#); + /// + /// // replace an existing key + /// data["x"] = yaml(r#"1"#); + /// + /// // insert a new key + /// data["y"] = yaml(r#"[false, false, false]"#); + /// + /// // replace a value in a sequence + /// data["y"][0] = yaml(r#"true"#); + /// + /// // inserted a deeply nested key + /// data["a"]["b"]["c"]["d"] = yaml(r#"true"#); + /// + /// println!("{:?}", data); + /// ``` + fn index_mut(&mut self, index: I) -> &mut Value { + index.index_or_insert(self) + } +} diff --git a/vendor/serde_yaml-0.8.26/src/value/mod.rs b/vendor/serde_yaml-0.8.26/src/value/mod.rs new file mode 100644 index 0000000000000..a71091bffb196 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/src/value/mod.rs @@ -0,0 +1,648 @@ +mod de; +mod from; +mod index; +mod partial_eq; +mod ser; + +use crate::ser::SerializerToYaml; +use crate::{Error, Mapping}; +use serde::de::{Deserialize, DeserializeOwned, IntoDeserializer}; +use serde::Serialize; +use std::f64; +use std::hash::{Hash, Hasher}; +use std::str::FromStr; +use yaml_rust::Yaml; + +pub use self::index::Index; +pub use crate::number::Number; + +/// Represents any valid YAML value. +#[derive(Clone, PartialOrd, Debug)] +pub enum Value { + /// Represents a YAML null value. + Null, + /// Represents a YAML boolean. + Bool(bool), + /// Represents a YAML numerical value, whether integer or floating point. + Number(Number), + /// Represents a YAML string. + String(String), + /// Represents a YAML sequence in which the elements are + /// `serde_yaml::Value`. + Sequence(Sequence), + /// Represents a YAML mapping in which the keys and values are both + /// `serde_yaml::Value`. + Mapping(Mapping), +} + +/// The default value is `Value::Null`. +/// +/// This is useful for handling omitted `Value` fields when deserializing. +/// +/// # Examples +/// +/// ``` +/// # use serde_derive::Deserialize; +/// use serde::Deserialize; +/// use serde_yaml::Value; +/// +/// #[derive(Deserialize)] +/// struct Settings { +/// level: i32, +/// #[serde(default)] +/// extras: Value, +/// } +/// +/// # fn try_main() -> Result<(), serde_yaml::Error> { +/// let data = r#" { "level": 42 } "#; +/// let s: Settings = serde_yaml::from_str(data)?; +/// +/// assert_eq!(s.level, 42); +/// assert_eq!(s.extras, Value::Null); +/// # +/// # Ok(()) +/// # } +/// # +/// # try_main().unwrap() +/// ``` +impl Default for Value { + fn default() -> Value { + Value::Null + } +} + +/// A YAML sequence in which the elements are `serde_yaml::Value`. +pub type Sequence = Vec; + +/// Convert a `T` into `serde_yaml::Value` which is an enum that can represent +/// any valid YAML data. +/// +/// This conversion can fail if `T`'s implementation of `Serialize` decides to +/// return an error. +/// +/// ``` +/// # use serde_yaml::Value; +/// let val = serde_yaml::to_value("s").unwrap(); +/// assert_eq!(val, Value::String("s".to_owned())); +/// ``` +pub fn to_value(value: T) -> Result +where + T: Serialize, +{ + value.serialize(SerializerToYaml).map(yaml_to_value) +} + +/// Interpret a `serde_yaml::Value` as an instance of type `T`. +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a YAML map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the YAML map or some number is too big to fit in the expected primitive +/// type. +/// +/// ``` +/// # use serde_yaml::Value; +/// let val = Value::String("foo".to_owned()); +/// let s: String = serde_yaml::from_value(val).unwrap(); +/// assert_eq!("foo", s); +/// ``` +pub fn from_value(value: Value) -> Result +where + T: DeserializeOwned, +{ + Deserialize::deserialize(value) +} + +impl Value { + /// Index into a YAML sequence or map. A string index can be used to access + /// a value in a map, and a usize index can be used to access an element of + /// an sequence. + /// + /// Returns `None` if the type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is a sequence or + /// a number. Also returns `None` if the given key does not exist in the map + /// or the given index is not within the bounds of the sequence. + /// + /// ``` + /// # use serde_yaml::Value; + /// # + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// # + /// let object: Value = yaml(r#"{ A: 65, B: 66, C: 67 }"#); + /// let x = object.get("A").unwrap(); + /// assert_eq!(x, 65); + /// + /// let sequence: Value = yaml(r#"[ "A", "B", "C" ]"#); + /// let x = sequence.get(2).unwrap(); + /// assert_eq!(x, &Value::String("C".into())); + /// + /// assert_eq!(sequence.get("A"), None); + /// ``` + /// + /// Square brackets can also be used to index into a value in a more concise + /// way. This returns `Value::Null` in cases where `get` would have returned + /// `None`. + /// + /// ``` + /// # use serde_yaml::Value; + /// # + /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } + /// # + /// let object = yaml(r#" + /// --- + /// A: [a, á, à] + /// B: [b, bÌ] + /// C: [c, ć, ć̣, ḉ] + /// 42: true + /// "#); + /// assert_eq!(object["B"][0], Value::String("b".into())); + /// + /// assert_eq!(object[Value::String("D".into())], Value::Null); + /// assert_eq!(object["D"], Value::Null); + /// assert_eq!(object[0]["x"]["y"]["z"], Value::Null); + /// + /// assert_eq!(object[42], Value::Bool(true)); + /// ``` + pub fn get(&self, index: I) -> Option<&Value> { + index.index_into(self) + } + + /// Index into a YAML sequence or map. A string index can be used to access + /// a value in a map, and a usize index can be used to access an element of + /// an sequence. + /// + /// Returns `None` if the type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is a sequence or + /// a number. Also returns `None` if the given key does not exist in the map + /// or the given index is not within the bounds of the sequence. + pub fn get_mut(&mut self, index: I) -> Option<&mut Value> { + index.index_into_mut(self) + } + + /// Returns true if the `Value` is a Null. Returns false otherwise. + /// + /// For any Value on which `is_null` returns true, `as_null` is guaranteed + /// to return `Some(())`. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("null").unwrap(); + /// assert!(v.is_null()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert!(!v.is_null()); + /// ``` + pub fn is_null(&self) -> bool { + if let Value::Null = *self { + true + } else { + false + } + } + + /// If the `Value` is a Null, returns (). Returns None otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("null").unwrap(); + /// assert_eq!(v.as_null(), Some(())); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_null(), None); + /// ``` + pub fn as_null(&self) -> Option<()> { + match self { + Value::Null => Some(()), + _ => None, + } + } + + /// Returns true if the `Value` is a Boolean. Returns false otherwise. + /// + /// For any Value on which `is_boolean` returns true, `as_bool` is + /// guaranteed to return the boolean value. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("true").unwrap(); + /// assert!(v.is_bool()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("42").unwrap(); + /// assert!(!v.is_bool()); + /// ``` + pub fn is_bool(&self) -> bool { + self.as_bool().is_some() + } + + /// If the `Value` is a Boolean, returns the associated bool. Returns None + /// otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("true").unwrap(); + /// assert_eq!(v.as_bool(), Some(true)); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("42").unwrap(); + /// assert_eq!(v.as_bool(), None); + /// ``` + pub fn as_bool(&self) -> Option { + match self { + Value::Bool(b) => Some(*b), + _ => None, + } + } + + /// Returns true if the `Value` is a Number. Returns false otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("5").unwrap(); + /// assert!(v.is_number()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("true").unwrap(); + /// assert!(!v.is_number()); + /// ``` + pub fn is_number(&self) -> bool { + match self { + Value::Number(_) => true, + _ => false, + } + } + + /// Returns true if the `Value` is an integer between `i64::MIN` and + /// `i64::MAX`. + /// + /// For any Value on which `is_i64` returns true, `as_i64` is guaranteed to + /// return the integer value. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("1337").unwrap(); + /// assert!(v.is_i64()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("null").unwrap(); + /// assert!(!v.is_i64()); + /// ``` + pub fn is_i64(&self) -> bool { + self.as_i64().is_some() + } + + /// If the `Value` is an integer, represent it as i64 if possible. Returns + /// None otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("1337").unwrap(); + /// assert_eq!(v.as_i64(), Some(1337)); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_i64(), None); + /// ``` + pub fn as_i64(&self) -> Option { + match self { + Value::Number(n) => n.as_i64(), + _ => None, + } + } + + /// Returns true if the `Value` is an integer between `u64::MIN` and + /// `u64::MAX`. + /// + /// For any Value on which `is_u64` returns true, `as_u64` is guaranteed to + /// return the integer value. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("1337").unwrap(); + /// assert!(v.is_u64()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("null").unwrap(); + /// assert!(!v.is_u64()); + /// ``` + pub fn is_u64(&self) -> bool { + self.as_u64().is_some() + } + + /// If the `Value` is an integer, represent it as u64 if possible. Returns + /// None otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("1337").unwrap(); + /// assert_eq!(v.as_u64(), Some(1337)); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_u64(), None); + /// ``` + pub fn as_u64(&self) -> Option { + match self { + Value::Number(n) => n.as_u64(), + _ => None, + } + } + + /// Returns true if the `Value` is a number that can be represented by f64. + /// + /// For any Value on which `is_f64` returns true, `as_f64` is guaranteed to + /// return the floating point value. + /// + /// Currently this function returns true if and only if both `is_i64` and + /// `is_u64` return false but this is not a guarantee in the future. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("256.01").unwrap(); + /// assert!(v.is_f64()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("true").unwrap(); + /// assert!(!v.is_f64()); + /// ``` + pub fn is_f64(&self) -> bool { + match self { + Value::Number(n) => n.is_f64(), + _ => false, + } + } + + /// If the `Value` is a number, represent it as f64 if possible. Returns + /// None otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("13.37").unwrap(); + /// assert_eq!(v.as_f64(), Some(13.37)); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_f64(), None); + /// ``` + pub fn as_f64(&self) -> Option { + match self { + Value::Number(i) => i.as_f64(), + _ => None, + } + } + + /// Returns true if the `Value` is a String. Returns false otherwise. + /// + /// For any Value on which `is_string` returns true, `as_str` is guaranteed + /// to return the string slice. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("'lorem ipsum'").unwrap(); + /// assert!(v.is_string()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("42").unwrap(); + /// assert!(!v.is_string()); + /// ``` + pub fn is_string(&self) -> bool { + self.as_str().is_some() + } + + /// If the `Value` is a String, returns the associated str. Returns None + /// otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("'lorem ipsum'").unwrap(); + /// assert_eq!(v.as_str(), Some("lorem ipsum")); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_str(), None); + /// ``` + pub fn as_str(&self) -> Option<&str> { + match self { + Value::String(s) => Some(s), + _ => None, + } + } + + /// Returns true if the `Value` is a sequence. Returns false otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("[1, 2, 3]").unwrap(); + /// assert!(v.is_sequence()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("true").unwrap(); + /// assert!(!v.is_sequence()); + /// ``` + pub fn is_sequence(&self) -> bool { + self.as_sequence().is_some() + } + + /// If the `Value` is a sequence, return a reference to it if possible. + /// Returns None otherwise. + /// + /// ``` + /// # use serde_yaml::{Value, Number}; + /// let v: Value = serde_yaml::from_str("[1, 2]").unwrap(); + /// assert_eq!(v.as_sequence(), Some(&vec![Value::Number(Number::from(1)), Value::Number(Number::from(2))])); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_sequence(), None); + /// ``` + pub fn as_sequence(&self) -> Option<&Sequence> { + match self { + Value::Sequence(seq) => Some(seq), + _ => None, + } + } + + /// If the `Value` is a sequence, return a mutable reference to it if + /// possible. Returns None otherwise. + /// + /// ``` + /// # use serde_yaml::{Value, Number}; + /// let mut v: Value = serde_yaml::from_str("[1]").unwrap(); + /// let s = v.as_sequence_mut().unwrap(); + /// s.push(Value::Number(Number::from(2))); + /// assert_eq!(s, &vec![Value::Number(Number::from(1)), Value::Number(Number::from(2))]); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let mut v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_sequence_mut(), None); + /// ``` + pub fn as_sequence_mut(&mut self) -> Option<&mut Sequence> { + match self { + Value::Sequence(seq) => Some(seq), + _ => None, + } + } + + /// Returns true if the `Value` is a mapping. Returns false otherwise. + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("a: 42").unwrap(); + /// assert!(v.is_mapping()); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("true").unwrap(); + /// assert!(!v.is_mapping()); + /// ``` + pub fn is_mapping(&self) -> bool { + self.as_mapping().is_some() + } + + /// If the `Value` is a mapping, return a reference to it if possible. + /// Returns None otherwise. + /// + /// ``` + /// # use serde_yaml::{Value, Mapping, Number}; + /// let v: Value = serde_yaml::from_str("a: 42").unwrap(); + /// + /// let mut expected = Mapping::new(); + /// expected.insert(Value::String("a".into()),Value::Number(Number::from(42))); + /// + /// assert_eq!(v.as_mapping(), Some(&expected)); + /// ``` + /// + /// ``` + /// # use serde_yaml::Value; + /// let v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_mapping(), None); + /// ``` + pub fn as_mapping(&self) -> Option<&Mapping> { + match self { + Value::Mapping(map) => Some(map), + _ => None, + } + } + + /// If the `Value` is a mapping, return a reference to it if possible. + /// Returns None otherwise. + /// + /// ``` + /// # use serde_yaml::{Value, Mapping, Number}; + /// let mut v: Value = serde_yaml::from_str("a: 42").unwrap(); + /// let m = v.as_mapping_mut().unwrap(); + /// m.insert(Value::String("b".into()), Value::Number(Number::from(21))); + /// + /// let mut expected = Mapping::new(); + /// expected.insert(Value::String("a".into()), Value::Number(Number::from(42))); + /// expected.insert(Value::String("b".into()), Value::Number(Number::from(21))); + /// + /// assert_eq!(m, &expected); + /// ``` + /// + /// ``` + /// # use serde_yaml::{Value, Mapping}; + /// let mut v: Value = serde_yaml::from_str("false").unwrap(); + /// assert_eq!(v.as_mapping_mut(), None); + /// ``` + pub fn as_mapping_mut(&mut self) -> Option<&mut Mapping> { + match self { + Value::Mapping(map) => Some(map), + _ => None, + } + } +} + +fn yaml_to_value(yaml: Yaml) -> Value { + match yaml { + Yaml::Real(f) => { + if f == ".inf" { + Value::Number(f64::INFINITY.into()) + } else if f == "-.inf" { + Value::Number(f64::NEG_INFINITY.into()) + } else if f == ".nan" { + Value::Number(f64::NAN.into()) + } else if let Ok(n) = u64::from_str(&f) { + Value::Number(n.into()) + } else if let Ok(n) = i64::from_str(&f) { + Value::Number(n.into()) + } else if let Ok(n) = f64::from_str(&f) { + Value::Number(n.into()) + } else { + Value::String(f) + } + } + Yaml::Integer(i) => Value::Number(i.into()), + Yaml::String(s) => Value::String(s), + Yaml::Boolean(b) => Value::Bool(b), + Yaml::Array(sequence) => Value::Sequence(sequence.into_iter().map(yaml_to_value).collect()), + Yaml::Hash(hash) => Value::Mapping( + hash.into_iter() + .map(|(k, v)| (yaml_to_value(k), yaml_to_value(v))) + .collect(), + ), + Yaml::Alias(_) => panic!("alias unsupported"), + Yaml::Null => Value::Null, + Yaml::BadValue => panic!("bad value"), + } +} + +impl Eq for Value {} + +impl Hash for Value { + fn hash(&self, state: &mut H) { + match self { + Value::Null => 0.hash(state), + Value::Bool(b) => (1, b).hash(state), + Value::Number(i) => (2, i).hash(state), + Value::String(s) => (3, s).hash(state), + Value::Sequence(seq) => (4, seq).hash(state), + Value::Mapping(map) => (5, map).hash(state), + } + } +} + +impl<'de> IntoDeserializer<'de, Error> for Value { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} diff --git a/vendor/serde_yaml-0.8.26/src/value/partial_eq.rs b/vendor/serde_yaml-0.8.26/src/value/partial_eq.rs new file mode 100644 index 0000000000000..ff9b1f8f8abbc --- /dev/null +++ b/vendor/serde_yaml-0.8.26/src/value/partial_eq.rs @@ -0,0 +1,149 @@ +use crate::Value; + +impl PartialEq for Value { + fn eq(&self, other: &Value) -> bool { + match (self, other) { + (Value::Null, Value::Null) => true, + (Value::Bool(a), Value::Bool(b)) => a == b, + (Value::Number(a), Value::Number(b)) => a == b, + (Value::String(a), Value::String(b)) => a == b, + (Value::Sequence(a), Value::Sequence(b)) => a == b, + (Value::Mapping(a), Value::Mapping(b)) => a == b, + _ => false, + } + } +} + +impl PartialEq for Value { + /// Compare `str` with YAML value + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::Value; + /// assert!(Value::String("lorem".into()) == *"lorem"); + /// ``` + fn eq(&self, other: &str) -> bool { + self.as_str().map_or(false, |s| s == other) + } +} + +impl<'a> PartialEq<&'a str> for Value { + /// Compare `&str` with YAML value + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::Value; + /// assert!(Value::String("lorem".into()) == "lorem"); + /// ``` + fn eq(&self, other: &&str) -> bool { + self.as_str().map_or(false, |s| s == *other) + } +} + +impl PartialEq for str { + /// Compare YAML value with `str` + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::Value; + /// assert!(*"lorem" == Value::String("lorem".into())); + /// ``` + fn eq(&self, other: &Value) -> bool { + other.as_str().map_or(false, |s| s == self) + } +} + +impl<'a> PartialEq for &'a str { + /// Compare `&str` with YAML value + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::Value; + /// assert!("lorem" == Value::String("lorem".into())); + /// ``` + fn eq(&self, other: &Value) -> bool { + other.as_str().map_or(false, |s| s == *self) + } +} + +impl PartialEq for Value { + /// Compare YAML value with String + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::Value; + /// assert!(Value::String("lorem".into()) == "lorem".to_string()); + /// ``` + fn eq(&self, other: &String) -> bool { + self.as_str().map_or(false, |s| s == other) + } +} + +impl PartialEq for String { + /// Compare `String` with YAML value + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::Value; + /// assert!("lorem".to_string() == Value::String("lorem".into())); + /// ``` + fn eq(&self, other: &Value) -> bool { + other.as_str().map_or(false, |s| s == self) + } +} + +impl PartialEq for Value { + /// Compare YAML value with bool + /// + /// # Examples + /// + /// ``` + /// # use serde_yaml::Value; + /// assert!(Value::Bool(true) == true); + /// ``` + fn eq(&self, other: &bool) -> bool { + self.as_bool().map_or(false, |b| b == *other) + } +} + +macro_rules! partialeq_numeric { + ($([$($ty:ty)*], $conversion:ident, $base:ty)*) => { + $($( + impl PartialEq<$ty> for Value { + fn eq(&self, other: &$ty) -> bool { + self.$conversion().map_or(false, |i| i == (*other as $base)) + } + } + + impl PartialEq for $ty { + fn eq(&self, other: &Value) -> bool { + other.$conversion().map_or(false, |i| i == (*self as $base)) + } + } + + impl<'a> PartialEq<$ty> for &'a Value { + fn eq(&self, other: &$ty) -> bool { + self.$conversion().map_or(false, |i| i == (*other as $base)) + } + } + + impl<'a> PartialEq<$ty> for &'a mut Value { + fn eq(&self, other: &$ty) -> bool { + self.$conversion().map_or(false, |i| i == (*other as $base)) + } + } + )*)* + } +} + +partialeq_numeric! { + [i8 i16 i32 i64 isize], as_i64, i64 + [u8 u16 u32 u64 usize], as_u64, u64 + [f32 f64], as_f64, f64 +} diff --git a/vendor/serde_yaml-0.8.26/src/value/ser.rs b/vendor/serde_yaml-0.8.26/src/value/ser.rs new file mode 100644 index 0000000000000..f2c4bb438cbd5 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/src/value/ser.rs @@ -0,0 +1,25 @@ +use crate::Value; +use serde::Serialize; + +impl Serialize for Value { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Value::Null => serializer.serialize_unit(), + Value::Bool(b) => serializer.serialize_bool(*b), + Value::Number(n) => n.serialize(serializer), + Value::String(s) => serializer.serialize_str(s), + Value::Sequence(seq) => seq.serialize(serializer), + Value::Mapping(hash) => { + use serde::ser::SerializeMap; + let mut map = serializer.serialize_map(Some(hash.len()))?; + for (k, v) in hash { + map.serialize_entry(k, v)?; + } + map.end() + } + } + } +} diff --git a/vendor/serde_yaml-0.8.26/tests/test_de.rs b/vendor/serde_yaml-0.8.26/tests/test_de.rs new file mode 100644 index 0000000000000..e3a8c0da1219f --- /dev/null +++ b/vendor/serde_yaml-0.8.26/tests/test_de.rs @@ -0,0 +1,396 @@ +#![allow( + clippy::cast_lossless, + clippy::cast_possible_wrap, + clippy::derive_partial_eq_without_eq +)] + +use indoc::indoc; +use serde_derive::Deserialize; +use serde_yaml::Value; +use std::collections::BTreeMap; +use std::fmt::Debug; + +fn test_de(yaml: &str, expected: &T) +where + T: serde::de::DeserializeOwned + PartialEq + Debug, +{ + let deserialized: T = serde_yaml::from_str(yaml).unwrap(); + assert_eq!(*expected, deserialized); + + serde_yaml::from_str::(yaml).unwrap(); + serde_yaml::from_str::(yaml).unwrap(); +} + +fn test_de_seed(yaml: &str, seed: S, expected: &T) +where + T: PartialEq + Debug, + S: for<'de> serde::de::DeserializeSeed<'de, Value = T>, +{ + let deserialized: T = serde_yaml::seed::from_str_seed(yaml, seed).unwrap(); + assert_eq!(*expected, deserialized); + + serde_yaml::from_str::(yaml).unwrap(); + serde_yaml::from_str::(yaml).unwrap(); +} + +#[test] +fn test_alias() { + let yaml = indoc! {" + --- + first: + &alias + 1 + second: + *alias + third: 3 + "}; + let mut expected = BTreeMap::new(); + { + expected.insert(String::from("first"), 1); + expected.insert(String::from("second"), 1); + expected.insert(String::from("third"), 3); + } + test_de(yaml, &expected); +} + +#[test] +fn test_option() { + #[derive(Deserialize, PartialEq, Debug)] + struct Data { + a: Option, + b: Option, + c: Option, + } + let yaml = indoc! {" + --- + b: + c: true + "}; + let expected = Data { + a: None, + b: None, + c: Some(true), + }; + test_de(yaml, &expected); +} + +#[test] +fn test_option_alias() { + #[derive(Deserialize, PartialEq, Debug)] + struct Data { + a: Option, + b: Option, + c: Option, + d: Option, + e: Option, + f: Option, + } + let yaml = indoc! {" + --- + none_f: + &none_f + ~ + none_s: + &none_s + ~ + none_b: + &none_b + ~ + + some_f: + &some_f + 1.0 + some_s: + &some_s + x + some_b: + &some_b + true + + a: *none_f + b: *none_s + c: *none_b + d: *some_f + e: *some_s + f: *some_b + "}; + let expected = Data { + a: None, + b: None, + c: None, + d: Some(1.0), + e: Some("x".to_owned()), + f: Some(true), + }; + test_de(yaml, &expected); +} + +#[test] +fn test_enum_alias() { + #[derive(Deserialize, PartialEq, Debug)] + enum E { + A, + B(u8, u8), + } + #[derive(Deserialize, PartialEq, Debug)] + struct Data { + a: E, + b: E, + } + let yaml = indoc! {" + --- + aref: + &aref + A + bref: + &bref + B: + - 1 + - 2 + + a: *aref + b: *bref + "}; + let expected = Data { + a: E::A, + b: E::B(1, 2), + }; + test_de(yaml, &expected); +} + +#[test] +fn test_enum_tag() { + #[derive(Deserialize, PartialEq, Debug)] + enum E { + A(String), + B(String), + } + #[derive(Deserialize, PartialEq, Debug)] + struct Data { + a: E, + b: E, + } + let yaml = indoc! {" + --- + a: !A foo + b: !B bar + "}; + let expected = Data { + a: E::A("foo".into()), + b: E::B("bar".into()), + }; + test_de(yaml, &expected); +} + +#[test] +fn test_number_as_string() { + #[derive(Deserialize, PartialEq, Debug)] + struct Num { + value: String, + } + let yaml = indoc! {" + --- + # Cannot be represented as u128 + value: 340282366920938463463374607431768211457 + "}; + let expected = Num { + value: "340282366920938463463374607431768211457".to_owned(), + }; + test_de(yaml, &expected); +} + +#[test] +fn test_i128_big() { + let expected: i128 = ::std::i64::MIN as i128 - 1; + let yaml = indoc! {" + --- + -9223372036854775809 + "}; + assert_eq!(expected, serde_yaml::from_str::(yaml).unwrap()); +} + +#[test] +fn test_u128_big() { + let expected: u128 = ::std::u64::MAX as u128 + 1; + let yaml = indoc! {" + --- + 18446744073709551616 + "}; + assert_eq!(expected, serde_yaml::from_str::(yaml).unwrap()); +} + +#[test] +fn test_number_alias_as_string() { + #[derive(Deserialize, PartialEq, Debug)] + struct Num { + version: String, + value: String, + } + let yaml = indoc! {" + --- + version: &a 1.10 + value: *a + "}; + let expected = Num { + version: "1.10".to_owned(), + value: "1.10".to_owned(), + }; + test_de(yaml, &expected); +} + +#[test] +fn test_de_mapping() { + #[derive(Debug, Deserialize, PartialEq)] + struct Data { + pub substructure: serde_yaml::Mapping, + } + let yaml = indoc! {" + --- + substructure: + a: 'foo' + b: 'bar' + "}; + + let mut expected = Data { + substructure: serde_yaml::Mapping::new(), + }; + expected.substructure.insert( + serde_yaml::Value::String("a".to_owned()), + serde_yaml::Value::String("foo".to_owned()), + ); + expected.substructure.insert( + serde_yaml::Value::String("b".to_owned()), + serde_yaml::Value::String("bar".to_owned()), + ); + + test_de(yaml, &expected); +} + +#[test] +fn test_bomb() { + #[derive(Debug, Deserialize, PartialEq)] + struct Data { + expected: String, + } + + // This would deserialize an astronomical number of elements if we were + // vulnerable. + let yaml = indoc! {" + --- + a: &a ~ + b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a] + c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b] + d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c] + e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d] + f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e] + g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f] + h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g] + i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h] + j: &j [*i,*i,*i,*i,*i,*i,*i,*i,*i] + k: &k [*j,*j,*j,*j,*j,*j,*j,*j,*j] + l: &l [*k,*k,*k,*k,*k,*k,*k,*k,*k] + m: &m [*l,*l,*l,*l,*l,*l,*l,*l,*l] + n: &n [*m,*m,*m,*m,*m,*m,*m,*m,*m] + o: &o [*n,*n,*n,*n,*n,*n,*n,*n,*n] + p: &p [*o,*o,*o,*o,*o,*o,*o,*o,*o] + q: &q [*p,*p,*p,*p,*p,*p,*p,*p,*p] + r: &r [*q,*q,*q,*q,*q,*q,*q,*q,*q] + s: &s [*r,*r,*r,*r,*r,*r,*r,*r,*r] + t: &t [*s,*s,*s,*s,*s,*s,*s,*s,*s] + u: &u [*t,*t,*t,*t,*t,*t,*t,*t,*t] + v: &v [*u,*u,*u,*u,*u,*u,*u,*u,*u] + w: &w [*v,*v,*v,*v,*v,*v,*v,*v,*v] + x: &x [*w,*w,*w,*w,*w,*w,*w,*w,*w] + y: &y [*x,*x,*x,*x,*x,*x,*x,*x,*x] + z: &z [*y,*y,*y,*y,*y,*y,*y,*y,*y] + expected: string + "}; + + let expected = Data { + expected: "string".to_owned(), + }; + + assert_eq!(expected, serde_yaml::from_str::(yaml).unwrap()); +} + +#[test] +fn test_numbers() { + let cases = [ + ("0xF0", "240"), + ("+0xF0", "240"), + ("-0xF0", "-240"), + ("0o70", "56"), + ("+0o70", "56"), + ("-0o70", "-56"), + ("0b10", "2"), + ("+0b10", "2"), + ("-0b10", "-2"), + ("127", "127"), + ("+127", "127"), + ("-127", "-127"), + (".inf", ".inf"), + (".Inf", ".inf"), + (".INF", ".inf"), + ("-.inf", "-.inf"), + ("-.Inf", "-.inf"), + ("-.INF", "-.inf"), + (".nan", ".nan"), + (".NaN", ".nan"), + (".NAN", ".nan"), + ("0.1", "0.1"), + ]; + for &(yaml, expected) in &cases { + let value = serde_yaml::from_str::(yaml).unwrap(); + match value { + Value::Number(number) => assert_eq!(number.to_string(), expected), + _ => panic!("expected number. input={:?}, result={:?}", yaml, value), + } + } + + // NOT numbers. + let cases = ["0127", "+0127", "-0127"]; + for yaml in &cases { + let value = serde_yaml::from_str::(yaml).unwrap(); + match value { + Value::String(string) => assert_eq!(string, *yaml), + _ => panic!("expected string. input={:?}, result={:?}", yaml, value), + } + } +} + +#[test] +fn test_stateful() { + struct Seed(i64); + + impl<'de> serde::de::DeserializeSeed<'de> for Seed { + type Value = i64; + fn deserialize(self, deserializer: D) -> Result + where + D: serde::de::Deserializer<'de>, + { + struct Visitor(i64); + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = i64; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "an integer") + } + + fn visit_i64(self, v: i64) -> Result { + Ok(v * self.0) + } + + fn visit_u64(self, v: u64) -> Result { + Ok(v as i64 * self.0) + } + } + + deserializer.deserialize_any(Visitor(self.0)) + } + } + + let cases = [("3", 5, 15), ("6", 7, 42), ("-5", 9, -45)]; + for &(yaml, seed, expected) in &cases { + test_de_seed(yaml, Seed(seed), &expected); + } +} diff --git a/vendor/serde_yaml-0.8.26/tests/test_error.rs b/vendor/serde_yaml-0.8.26/tests/test_error.rs new file mode 100644 index 0000000000000..bd830c0fc00de --- /dev/null +++ b/vendor/serde_yaml-0.8.26/tests/test_error.rs @@ -0,0 +1,287 @@ +use indoc::indoc; +use serde_derive::Deserialize; +use std::fmt::Debug; + +fn test_error(yaml: &str, expected: &str) +where + T: serde::de::DeserializeOwned + Debug, +{ + let result = serde_yaml::from_str::(yaml); + assert_eq!(expected, format!("{}", result.unwrap_err())); +} + +#[test] +fn test_incorrect_type() { + let yaml = indoc! {" + --- + str + "}; + let expected = "invalid type: string \"str\", expected i16 at line 2 column 1"; + test_error::(yaml, expected); +} + +#[test] +fn test_incorrect_nested_type() { + #[derive(Deserialize, Debug)] + struct A { + #[allow(dead_code)] + b: Vec, + } + #[derive(Deserialize, Debug)] + enum B { + C(C), + } + #[derive(Deserialize, Debug)] + struct C { + #[allow(dead_code)] + d: bool, + } + let yaml = indoc! {" + --- + b: + - C: + d: fase + "}; + let expected = + "b[0].C.d: invalid type: string \"fase\", expected a boolean at line 4 column 10"; + test_error::(yaml, expected); +} + +#[test] +fn test_empty() { + let expected = "EOF while parsing a value"; + test_error::("", expected); +} + +#[test] +fn test_missing_field() { + #[derive(Deserialize, Debug)] + struct Basic { + #[allow(dead_code)] + v: bool, + #[allow(dead_code)] + w: bool, + } + let yaml = indoc! {" + --- + v: true + "}; + let expected = "missing field `w` at line 2 column 2"; + test_error::(yaml, expected); +} + +#[test] +fn test_unknown_anchor() { + let yaml = indoc! {" + --- + *some + "}; + let expected = "while parsing node, found unknown anchor at line 2 column 1"; + test_error::(yaml, expected); +} + +#[test] +fn test_ignored_unknown_anchor() { + #[derive(Deserialize, Debug)] + struct Wrapper { + #[allow(dead_code)] + c: (), + } + let yaml = indoc! {" + --- + b: [*a] + c: ~ + "}; + let expected = "while parsing node, found unknown anchor at line 2 column 5"; + test_error::(yaml, expected); +} + +#[test] +fn test_two_documents() { + let yaml = indoc! {" + --- + 0 + --- + 1 + "}; + let expected = "deserializing from YAML containing more than one document is not supported"; + test_error::(yaml, expected); +} + +#[test] +fn test_variant_map_wrong_size() { + #[derive(Deserialize, Debug)] + enum E { + V(usize), + } + let yaml = indoc! {r#" + --- + "V": 16 + "other": 32 + "#}; + let expected = "invalid length 2, expected map containing 1 entry"; + test_error::(yaml, expected); +} + +#[test] +fn test_variant_not_a_map() { + #[derive(Deserialize, Debug)] + enum E { + V(usize), + } + let yaml = indoc! {r#" + --- + - "V" + "#}; + let expected = "invalid type: sequence, expected string or singleton map at line 2 column 1"; + test_error::(yaml, expected); +} + +#[test] +fn test_variant_not_string() { + #[derive(Deserialize, Debug)] + enum E { + V(bool), + } + let yaml = indoc! {r#" + --- + {}: true + "#}; + let expected = "invalid type: map, expected variant of enum `E` at line 2 column 1"; + test_error::(yaml, expected); +} + +#[test] +fn test_bad_bool() { + let yaml = indoc! {" + --- + !!bool str + "}; + let expected = "invalid value: string \"str\", expected a boolean at line 2 column 8"; + test_error::(yaml, expected); +} + +#[test] +fn test_bad_int() { + let yaml = indoc! {" + --- + !!int str + "}; + let expected = "invalid value: string \"str\", expected an integer at line 2 column 7"; + test_error::(yaml, expected); +} + +#[test] +fn test_bad_float() { + let yaml = indoc! {" + --- + !!float str + "}; + let expected = "invalid value: string \"str\", expected a float at line 2 column 9"; + test_error::(yaml, expected); +} + +#[test] +fn test_bad_null() { + let yaml = indoc! {" + --- + !!null str + "}; + let expected = "invalid value: string \"str\", expected null at line 2 column 8"; + test_error::<()>(yaml, expected); +} + +#[test] +fn test_short_tuple() { + let yaml = indoc! {" + --- + [0, 0] + "}; + let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1"; + test_error::<(u8, u8, u8)>(yaml, expected); +} + +#[test] +fn test_long_tuple() { + let yaml = indoc! {" + --- + [0, 0, 0] + "}; + let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1"; + test_error::<(u8, u8)>(yaml, expected); +} + +#[test] +fn test_no_location() { + let invalid_utf8: Result = + serde_yaml::from_slice(b"\x80\xae"); + + let utf8_location = invalid_utf8.unwrap_err().location(); + + assert!(utf8_location.is_none()); +} + +#[test] +fn test_invalid_scalar_type() { + #[derive(Deserialize, Debug)] + struct S { + #[allow(dead_code)] + x: [(); 1], + } + + let yaml = "x:\n"; + let expected = "x: invalid type: unit value, expected an array of length 1 at line 2 column 1"; + test_error::(yaml, expected); +} + +#[test] +fn test_infinite_recursion_objects() { + #[derive(Deserialize, Debug)] + struct S { + #[allow(dead_code)] + x: Option>, + } + + let yaml = "&a {x: *a}"; + let expected = "recursion limit exceeded"; + test_error::(yaml, expected); +} + +#[test] +fn test_infinite_recursion_arrays() { + #[derive(Deserialize, Debug)] + struct S { + #[allow(dead_code)] + x: Option>, + } + + let yaml = "&a [*a]"; + let expected = "recursion limit exceeded"; + test_error::(yaml, expected); +} + +#[test] +fn test_finite_recursion_objects() { + #[derive(Deserialize, Debug)] + struct S { + #[allow(dead_code)] + x: Option>, + } + + let yaml = "{x:".repeat(1_000) + &"}".repeat(1_000); + let expected = "recursion limit exceeded at line 1 column 766"; + test_error::(&yaml, expected); +} + +#[test] +fn test_finite_recursion_arrays() { + #[derive(Deserialize, Debug)] + struct S { + #[allow(dead_code)] + x: Option>, + } + + let yaml = "[".repeat(1_000) + &"]".repeat(1_000); + let expected = "recursion limit exceeded at line 1 column 256"; + test_error::(&yaml, expected); +} diff --git a/vendor/serde_yaml-0.8.26/tests/test_serde.rs b/vendor/serde_yaml-0.8.26/tests/test_serde.rs new file mode 100644 index 0000000000000..8b3f34b3fc173 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/tests/test_serde.rs @@ -0,0 +1,434 @@ +#![allow( + clippy::decimal_literal_representation, + clippy::derive_partial_eq_without_eq, + clippy::unreadable_literal, + clippy::shadow_unrelated +)] + +use indoc::indoc; +use serde_derive::{Deserialize, Serialize}; +use serde_yaml::Value; +use std::collections::BTreeMap; +use std::f64; +use std::fmt::Debug; + +fn test_serde(thing: &T, yaml: &str) +where + T: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug, +{ + let serialized = serde_yaml::to_string(&thing).unwrap(); + assert_eq!(yaml, serialized); + + let value = serde_yaml::to_value(&thing).unwrap(); + let serialized = serde_yaml::to_string(&value).unwrap(); + assert_eq!(yaml, serialized); + + let deserialized: T = serde_yaml::from_str(yaml).unwrap(); + assert_eq!(*thing, deserialized); + + let value: Value = serde_yaml::from_str(yaml).unwrap(); + let deserialized: T = serde_yaml::from_value(value).unwrap(); + assert_eq!(*thing, deserialized); + + serde_yaml::from_str::(yaml).unwrap(); +} + +#[test] +fn test_default() { + assert_eq!(Value::default(), Value::Null); +} + +#[test] +fn test_int() { + let thing = 256; + let yaml = indoc! {" + --- + 256 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_int_max_u64() { + let thing = ::std::u64::MAX; + let yaml = indoc! {" + --- + 18446744073709551615 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_int_min_i64() { + let thing = ::std::i64::MIN; + let yaml = indoc! {" + --- + -9223372036854775808 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_int_max_i64() { + let thing = ::std::i64::MAX; + let yaml = indoc! {" + --- + 9223372036854775807 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_i128_small() { + let thing: i128 = -256; + let yaml = indoc! {" + --- + -256 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_u128_small() { + let thing: u128 = 256; + let yaml = indoc! {" + --- + 256 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_float() { + let thing = 25.6; + let yaml = indoc! {" + --- + 25.6 + "}; + test_serde(&thing, yaml); + + let thing = 25.; + let yaml = indoc! {" + --- + 25.0 + "}; + test_serde(&thing, yaml); + + let thing = f64::INFINITY; + let yaml = indoc! {" + --- + .inf + "}; + test_serde(&thing, yaml); + + let thing = f64::NEG_INFINITY; + let yaml = indoc! {" + --- + -.inf + "}; + test_serde(&thing, yaml); + + let float: f64 = serde_yaml::from_str(indoc! {" + --- + .nan + "}) + .unwrap(); + assert!(float.is_nan()); +} + +#[test] +fn test_float32() { + let thing: f32 = 25.6; + let yaml = indoc! {" + --- + 25.6 + "}; + test_serde(&thing, yaml); + + let thing = f32::INFINITY; + let yaml = indoc! {" + --- + .inf + "}; + test_serde(&thing, yaml); + + let thing = f32::NEG_INFINITY; + let yaml = indoc! {" + --- + -.inf + "}; + test_serde(&thing, yaml); + + let single_float: f32 = serde_yaml::from_str(indoc! {" + --- + .nan + "}) + .unwrap(); + assert!(single_float.is_nan()); +} + +#[test] +fn test_vec() { + let thing = vec![1, 2, 3]; + let yaml = indoc! {" + --- + - 1 + - 2 + - 3 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_map() { + let mut thing = BTreeMap::new(); + thing.insert(String::from("x"), 1); + thing.insert(String::from("y"), 2); + let yaml = indoc! {" + --- + x: 1 + y: 2 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_basic_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Basic { + x: isize, + y: String, + z: bool, + } + let thing = Basic { + x: -4, + y: String::from("hi\tquoted"), + z: true, + }; + let yaml = indoc! {r#" + --- + x: -4 + y: "hi\tquoted" + z: true + "#}; + test_serde(&thing, yaml); +} + +#[test] +fn test_nested_vec() { + let thing = vec![vec![1, 2, 3], vec![4, 5, 6]]; + let yaml = indoc! {" + --- + - - 1 + - 2 + - 3 + - - 4 + - 5 + - 6 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_nested_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Outer { + inner: Inner, + } + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Inner { + v: u16, + } + let thing = Outer { + inner: Inner { v: 512 }, + }; + let yaml = indoc! {" + --- + inner: + v: 512 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_option() { + let thing = vec![Some(1), None, Some(3)]; + let yaml = indoc! {" + --- + - 1 + - ~ + - 3 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_unit() { + let thing = vec![(), ()]; + let yaml = indoc! {" + --- + - ~ + - ~ + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_unit_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Foo; + let thing = Foo; + let yaml = indoc! {" + --- + ~ + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_unit_variant() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Variant { + First, + Second, + } + let thing = Variant::First; + let yaml = indoc! {" + --- + First + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_newtype_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct OriginalType { + v: u16, + } + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct NewType(OriginalType); + let thing = NewType(OriginalType { v: 1 }); + let yaml = indoc! {" + --- + v: 1 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_newtype_variant() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Variant { + Size(usize), + } + let thing = Variant::Size(127); + let yaml = indoc! {" + --- + Size: 127 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_tuple_variant() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Variant { + Rgb(u8, u8, u8), + } + let thing = Variant::Rgb(32, 64, 96); + let yaml = indoc! {" + --- + Rgb: + - 32 + - 64 + - 96 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_struct_variant() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + enum Variant { + Color { r: u8, g: u8, b: u8 }, + } + let thing = Variant::Color { + r: 32, + g: 64, + b: 96, + }; + let yaml = indoc! {" + --- + Color: + r: 32 + g: 64 + b: 96 + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_value() { + use serde_yaml::{Mapping, Number}; + + #[derive(Serialize, Deserialize, PartialEq, Debug)] + pub struct GenericInstructions { + #[serde(rename = "type")] + pub typ: String, + pub config: Value, + } + let thing = GenericInstructions { + typ: "primary".to_string(), + config: Value::Sequence(vec![ + Value::Null, + Value::Bool(true), + Value::Number(Number::from(65535)), + Value::Number(Number::from(0.54321)), + Value::String("s".into()), + Value::Mapping(Mapping::new()), + ]), + }; + let yaml = indoc! {" + --- + type: primary + config: + - ~ + - true + - 65535 + - 0.54321 + - s + - {} + "}; + test_serde(&thing, yaml); +} + +#[test] +fn test_mapping() { + use serde_yaml::Mapping; + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Data { + pub substructure: Mapping, + } + + let mut thing = Data { + substructure: Mapping::new(), + }; + thing.substructure.insert( + Value::String("a".to_owned()), + Value::String("foo".to_owned()), + ); + thing.substructure.insert( + Value::String("b".to_owned()), + Value::String("bar".to_owned()), + ); + + let yaml = indoc! {" + --- + substructure: + a: foo + b: bar + "}; + + test_serde(&thing, yaml); +} diff --git a/vendor/serde_yaml-0.8.26/tests/test_value.rs b/vendor/serde_yaml-0.8.26/tests/test_value.rs new file mode 100644 index 0000000000000..c001b9d73da43 --- /dev/null +++ b/vendor/serde_yaml-0.8.26/tests/test_value.rs @@ -0,0 +1,55 @@ +#![allow(clippy::derive_partial_eq_without_eq, clippy::eq_op)] + +use serde::de::IntoDeserializer; +use serde::Deserialize; +use serde_derive::Deserialize; +use serde_yaml::{Number, Value}; +use std::f64; + +#[test] +fn test_nan() { + let pos_nan = serde_yaml::from_str::(".nan").unwrap(); + assert!(pos_nan.is_f64()); + assert_eq!(pos_nan, pos_nan); + + let neg_fake_nan = serde_yaml::from_str::("-.nan").unwrap(); + assert!(neg_fake_nan.is_string()); + + let significand_mask = 0xF_FFFF_FFFF_FFFF; + let bits = (f64::NAN.to_bits() ^ significand_mask) | 1; + let different_pos_nan = Value::Number(Number::from(f64::from_bits(bits))); + assert_eq!(pos_nan, different_pos_nan); +} + +#[test] +fn test_digits() { + let num_string = serde_yaml::from_str::("01").unwrap(); + assert!(num_string.is_string()); +} + +#[test] +fn test_into_deserializer() { + #[derive(Debug, Deserialize, PartialEq)] + struct Test { + first: String, + second: u32, + } + + let value = serde_yaml::from_str::("xyz").unwrap(); + let s = String::deserialize(value.into_deserializer()).unwrap(); + assert_eq!(s, "xyz"); + + let value = serde_yaml::from_str::("- first\n- second\n- third").unwrap(); + let arr = Vec::::deserialize(value.into_deserializer()).unwrap(); + assert_eq!(arr, &["first", "second", "third"]); + + let value = serde_yaml::from_str::("first: abc\nsecond: 99").unwrap(); + let test = Test::deserialize(value.into_deserializer()).unwrap(); + assert_eq!( + test, + Test { + first: "abc".to_string(), + second: 99 + } + ); +} diff --git a/vendor/spin-0.5.2/.cargo-checksum.json b/vendor/spin-0.5.2/.cargo-checksum.json new file mode 100644 index 0000000000000..9897ab4052956 --- /dev/null +++ b/vendor/spin-0.5.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"5202788831ce65bfa4b67dc3dcdd7698b30f1985dd1319cb31aec6a9afd4bde7","LICENSE":"6ac8711fb340c62ce0a4ecd463342d3fa0e8e70de697c863a2e1c0c53006003c","README.md":"90b21c45b2fd68f8dbf12ec8f61339e8689f031eb806ad90e73f11510e53eb72","examples/debug.rs":"0074651d78f8ed6d6c0274ae832c0d78de6c5c59423936f58e79cb3c98baea2c","script/doc-upload.cfg":"7383ee022197c1dade9a2e6888261def4a80df08ecb72b1b4db47d1e8a6ff8e0","src/lib.rs":"865d4759a7ed4b99b9c68f52ac849e7beb43940a8fb12c853e568d817821949a","src/mutex.rs":"3d2ae66354a799b66e0f1102790fadd1a09c5c6ecaea1290bde1867e91310c5e","src/once.rs":"61d8221858e2bfc41cc0fab802867e5eb05169dd2fa51912696188c31cf1f4ca","src/rw_lock.rs":"1af1974a2aefac645c4d32c85df2257422fa0f655a57ffcf61f7867769c918ed"},"package":"6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"} \ No newline at end of file diff --git a/vendor/spin-0.5.2/Cargo.toml b/vendor/spin-0.5.2/Cargo.toml new file mode 100644 index 0000000000000..9cffa98fb3f0c --- /dev/null +++ b/vendor/spin-0.5.2/Cargo.toml @@ -0,0 +1,21 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "spin" +version = "0.5.2" +authors = ["Mathijs van de Nes ", "John Ericson "] +description = "Synchronization primitives based on spinning.\nThey may contain data, are usable without `std`,\nand static initializers are available.\n" +documentation = "https://mvdnes.github.io/rust-docs/spin-rs/spin/index.html" +keywords = ["spinlock", "mutex", "rwlock"] +license = "MIT" +repository = "https://github.com/mvdnes/spin-rs.git" diff --git a/vendor/spin-0.5.2/LICENSE b/vendor/spin-0.5.2/LICENSE new file mode 100644 index 0000000000000..b2d7f7bbdcd99 --- /dev/null +++ b/vendor/spin-0.5.2/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Mathijs van de Nes + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/spin-0.5.2/README.md b/vendor/spin-0.5.2/README.md new file mode 100644 index 0000000000000..4c9931242dbb9 --- /dev/null +++ b/vendor/spin-0.5.2/README.md @@ -0,0 +1,64 @@ +spin-rs +=========== + +[![Build Status](https://travis-ci.org/mvdnes/spin-rs.svg)](https://travis-ci.org/mvdnes/spin-rs) +[![Crates.io version](https://img.shields.io/crates/v/spin.svg)](https://crates.io/crates/spin) +[![docs.rs](https://docs.rs/spin/badge.svg)](https://docs.rs/spin/) + +This Rust library implements a simple +[spinlock](https://en.wikipedia.org/wiki/Spinlock), and is safe for `#[no_std]` environments. + +Usage +----- + +Include the following code in your Cargo.toml + +```toml +[dependencies.spin] +version = "0.5" +``` + +Example +------- + +When calling `lock` on a `Mutex` you will get a reference to the data. When this +reference is dropped, the lock will be unlocked. + +```rust +extern crate spin; + +fn main() +{ + let mutex = spin::Mutex::new(0); + let rw_lock = spin::RwLock::new(0); + + // Modify the data + { + let mut data = mutex.lock(); + *data = 2; + let mut data = rw_lock.write(); + *data = 3; + } + + // Read the data + let answer = + { + let data1 = mutex.lock(); + let data2 = rw_lock.read(); + let data3 = rw_lock.read(); // sharing + (*data1, *data2, *data3) + }; + + println!("Answers are {:?}", answer); +} +``` + +To share the lock, an `Arc>` may be used. + +Remarks +------- + +The behaviour of these lock is similar to their namesakes in `std::sync`. they +differ on the following: + + - The lock will not be poisoned in case of failure; diff --git a/vendor/spin-0.5.2/examples/debug.rs b/vendor/spin-0.5.2/examples/debug.rs new file mode 100644 index 0000000000000..64654f6c5674f --- /dev/null +++ b/vendor/spin-0.5.2/examples/debug.rs @@ -0,0 +1,21 @@ +extern crate spin; + +fn main() { + let mutex = spin::Mutex::new(42); + println!("{:?}", mutex); + { + let x = mutex.lock(); + println!("{:?}, {:?}", mutex, *x); + } + + let rwlock = spin::RwLock::new(42); + println!("{:?}", rwlock); + { + let x = rwlock.read(); + println!("{:?}, {:?}", rwlock, *x); + } + { + let x = rwlock.write(); + println!("{:?}, {:?}", rwlock, *x); + } +} diff --git a/vendor/spin-0.5.2/script/doc-upload.cfg b/vendor/spin-0.5.2/script/doc-upload.cfg new file mode 100644 index 0000000000000..c6dfbdc1cdb27 --- /dev/null +++ b/vendor/spin-0.5.2/script/doc-upload.cfg @@ -0,0 +1,3 @@ +PROJECT_NAME=spin-rs +DOCS_REPO=mvdnes/rust-docs.git +DOC_RUST_VERSION=stable diff --git a/vendor/spin-0.5.2/src/lib.rs b/vendor/spin-0.5.2/src/lib.rs new file mode 100644 index 0000000000000..6e876bf5cdc0f --- /dev/null +++ b/vendor/spin-0.5.2/src/lib.rs @@ -0,0 +1,18 @@ +#![crate_type = "lib"] +#![warn(missing_docs)] + +//! Synchronization primitives based on spinning + +#![no_std] + +#[cfg(test)] +#[macro_use] +extern crate std; + +pub use mutex::*; +pub use rw_lock::*; +pub use once::*; + +mod mutex; +mod rw_lock; +mod once; diff --git a/vendor/spin-0.5.2/src/mutex.rs b/vendor/spin-0.5.2/src/mutex.rs new file mode 100644 index 0000000000000..8a068e0cb9623 --- /dev/null +++ b/vendor/spin-0.5.2/src/mutex.rs @@ -0,0 +1,388 @@ +use core::sync::atomic::{AtomicBool, Ordering, spin_loop_hint as cpu_relax}; +use core::cell::UnsafeCell; +use core::marker::Sync; +use core::ops::{Drop, Deref, DerefMut}; +use core::fmt; +use core::option::Option::{self, None, Some}; +use core::default::Default; + +/// This type provides MUTual EXclusion based on spinning. +/// +/// # Description +/// +/// The behaviour of these lock is similar to their namesakes in `std::sync`. they +/// differ on the following: +/// +/// - The lock will not be poisoned in case of failure; +/// +/// # Simple examples +/// +/// ``` +/// use spin; +/// let spin_mutex = spin::Mutex::new(0); +/// +/// // Modify the data +/// { +/// let mut data = spin_mutex.lock(); +/// *data = 2; +/// } +/// +/// // Read the data +/// let answer = +/// { +/// let data = spin_mutex.lock(); +/// *data +/// }; +/// +/// assert_eq!(answer, 2); +/// ``` +/// +/// # Thread-safety example +/// +/// ``` +/// use spin; +/// use std::sync::{Arc, Barrier}; +/// +/// let numthreads = 1000; +/// let spin_mutex = Arc::new(spin::Mutex::new(0)); +/// +/// // We use a barrier to ensure the readout happens after all writing +/// let barrier = Arc::new(Barrier::new(numthreads + 1)); +/// +/// for _ in (0..numthreads) +/// { +/// let my_barrier = barrier.clone(); +/// let my_lock = spin_mutex.clone(); +/// std::thread::spawn(move|| +/// { +/// let mut guard = my_lock.lock(); +/// *guard += 1; +/// +/// // Release the lock to prevent a deadlock +/// drop(guard); +/// my_barrier.wait(); +/// }); +/// } +/// +/// barrier.wait(); +/// +/// let answer = { *spin_mutex.lock() }; +/// assert_eq!(answer, numthreads); +/// ``` +pub struct Mutex +{ + lock: AtomicBool, + data: UnsafeCell, +} + +/// A guard to which the protected data can be accessed +/// +/// When the guard falls out of scope it will release the lock. +#[derive(Debug)] +pub struct MutexGuard<'a, T: ?Sized + 'a> +{ + lock: &'a AtomicBool, + data: &'a mut T, +} + +// Same unsafe impls as `std::sync::Mutex` +unsafe impl Sync for Mutex {} +unsafe impl Send for Mutex {} + +impl Mutex +{ + /// Creates a new spinlock wrapping the supplied data. + /// + /// May be used statically: + /// + /// ``` + /// use spin; + /// + /// static MUTEX: spin::Mutex<()> = spin::Mutex::new(()); + /// + /// fn demo() { + /// let lock = MUTEX.lock(); + /// // do something with lock + /// drop(lock); + /// } + /// ``` + pub const fn new(user_data: T) -> Mutex + { + Mutex + { + lock: AtomicBool::new(false), + data: UnsafeCell::new(user_data), + } + } + + /// Consumes this mutex, returning the underlying data. + pub fn into_inner(self) -> T { + // We know statically that there are no outstanding references to + // `self` so there's no need to lock. + let Mutex { data, .. } = self; + data.into_inner() + } +} + +impl Mutex +{ + fn obtain_lock(&self) + { + while self.lock.compare_and_swap(false, true, Ordering::Acquire) != false + { + // Wait until the lock looks unlocked before retrying + while self.lock.load(Ordering::Relaxed) + { + cpu_relax(); + } + } + } + + /// Locks the spinlock and returns a guard. + /// + /// The returned value may be dereferenced for data access + /// and the lock will be dropped when the guard falls out of scope. + /// + /// ``` + /// let mylock = spin::Mutex::new(0); + /// { + /// let mut data = mylock.lock(); + /// // The lock is now locked and the data can be accessed + /// *data += 1; + /// // The lock is implicitly dropped + /// } + /// + /// ``` + pub fn lock(&self) -> MutexGuard + { + self.obtain_lock(); + MutexGuard + { + lock: &self.lock, + data: unsafe { &mut *self.data.get() }, + } + } + + /// Force unlock the spinlock. + /// + /// This is *extremely* unsafe if the lock is not held by the current + /// thread. However, this can be useful in some instances for exposing the + /// lock to FFI that doesn't know how to deal with RAII. + /// + /// If the lock isn't held, this is a no-op. + pub unsafe fn force_unlock(&self) { + self.lock.store(false, Ordering::Release); + } + + /// Tries to lock the mutex. If it is already locked, it will return None. Otherwise it returns + /// a guard within Some. + pub fn try_lock(&self) -> Option> + { + if self.lock.compare_and_swap(false, true, Ordering::Acquire) == false + { + Some( + MutexGuard { + lock: &self.lock, + data: unsafe { &mut *self.data.get() }, + } + ) + } + else + { + None + } + } +} + +impl fmt::Debug for Mutex +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result + { + match self.try_lock() + { + Some(guard) => write!(f, "Mutex {{ data: ") + .and_then(|()| (&*guard).fmt(f)) + .and_then(|()| write!(f, "}}")), + None => write!(f, "Mutex {{ }}"), + } + } +} + +impl Default for Mutex { + fn default() -> Mutex { + Mutex::new(Default::default()) + } +} + +impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> +{ + type Target = T; + fn deref<'b>(&'b self) -> &'b T { &*self.data } +} + +impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> +{ + fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data } +} + +impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> +{ + /// The dropping of the MutexGuard will release the lock it was created from. + fn drop(&mut self) + { + self.lock.store(false, Ordering::Release); + } +} + +#[cfg(test)] +mod tests { + use std::prelude::v1::*; + + use std::sync::mpsc::channel; + use std::sync::Arc; + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::thread; + + use super::*; + + #[derive(Eq, PartialEq, Debug)] + struct NonCopy(i32); + + #[test] + fn smoke() { + let m = Mutex::new(()); + drop(m.lock()); + drop(m.lock()); + } + + #[test] + fn lots_and_lots() { + static M: Mutex<()> = Mutex::new(()); + static mut CNT: u32 = 0; + const J: u32 = 1000; + const K: u32 = 3; + + fn inc() { + for _ in 0..J { + unsafe { + let _g = M.lock(); + CNT += 1; + } + } + } + + let (tx, rx) = channel(); + for _ in 0..K { + let tx2 = tx.clone(); + thread::spawn(move|| { inc(); tx2.send(()).unwrap(); }); + let tx2 = tx.clone(); + thread::spawn(move|| { inc(); tx2.send(()).unwrap(); }); + } + + drop(tx); + for _ in 0..2 * K { + rx.recv().unwrap(); + } + assert_eq!(unsafe {CNT}, J * K * 2); + } + + #[test] + fn try_lock() { + let mutex = Mutex::new(42); + + // First lock succeeds + let a = mutex.try_lock(); + assert_eq!(a.as_ref().map(|r| **r), Some(42)); + + // Additional lock failes + let b = mutex.try_lock(); + assert!(b.is_none()); + + // After dropping lock, it succeeds again + ::core::mem::drop(a); + let c = mutex.try_lock(); + assert_eq!(c.as_ref().map(|r| **r), Some(42)); + } + + #[test] + fn test_into_inner() { + let m = Mutex::new(NonCopy(10)); + assert_eq!(m.into_inner(), NonCopy(10)); + } + + #[test] + fn test_into_inner_drop() { + struct Foo(Arc); + impl Drop for Foo { + fn drop(&mut self) { + self.0.fetch_add(1, Ordering::SeqCst); + } + } + let num_drops = Arc::new(AtomicUsize::new(0)); + let m = Mutex::new(Foo(num_drops.clone())); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + { + let _inner = m.into_inner(); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + } + assert_eq!(num_drops.load(Ordering::SeqCst), 1); + } + + #[test] + fn test_mutex_arc_nested() { + // Tests nested mutexes and access + // to underlying data. + let arc = Arc::new(Mutex::new(1)); + let arc2 = Arc::new(Mutex::new(arc)); + let (tx, rx) = channel(); + let _t = thread::spawn(move|| { + let lock = arc2.lock(); + let lock2 = lock.lock(); + assert_eq!(*lock2, 1); + tx.send(()).unwrap(); + }); + rx.recv().unwrap(); + } + + #[test] + fn test_mutex_arc_access_in_unwind() { + let arc = Arc::new(Mutex::new(1)); + let arc2 = arc.clone(); + let _ = thread::spawn(move|| -> () { + struct Unwinder { + i: Arc>, + } + impl Drop for Unwinder { + fn drop(&mut self) { + *self.i.lock() += 1; + } + } + let _u = Unwinder { i: arc2 }; + panic!(); + }).join(); + let lock = arc.lock(); + assert_eq!(*lock, 2); + } + + #[test] + fn test_mutex_unsized() { + let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); + { + let b = &mut *mutex.lock(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*mutex.lock(), comp); + } + + #[test] + fn test_mutex_force_lock() { + let lock = Mutex::new(()); + ::std::mem::forget(lock.lock()); + unsafe { + lock.force_unlock(); + } + assert!(lock.try_lock().is_some()); + } +} diff --git a/vendor/spin-0.5.2/src/once.rs b/vendor/spin-0.5.2/src/once.rs new file mode 100644 index 0000000000000..14d87bbac4e16 --- /dev/null +++ b/vendor/spin-0.5.2/src/once.rs @@ -0,0 +1,290 @@ +use core::cell::UnsafeCell; +use core::sync::atomic::{AtomicUsize, Ordering, spin_loop_hint as cpu_relax}; +use core::fmt; + +/// A synchronization primitive which can be used to run a one-time global +/// initialization. Unlike its std equivalent, this is generalized so that the +/// closure returns a value and it is stored. Once therefore acts something like +/// a future, too. +/// +/// # Examples +/// +/// ``` +/// use spin; +/// +/// static START: spin::Once<()> = spin::Once::new(); +/// +/// START.call_once(|| { +/// // run initialization here +/// }); +/// ``` +pub struct Once { + state: AtomicUsize, + data: UnsafeCell>, // TODO remove option and use mem::uninitialized +} + +impl fmt::Debug for Once { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.try() { + Some(s) => write!(f, "Once {{ data: ") + .and_then(|()| s.fmt(f)) + .and_then(|()| write!(f, "}}")), + None => write!(f, "Once {{ }}") + } + } +} + +// Same unsafe impls as `std::sync::RwLock`, because this also allows for +// concurrent reads. +unsafe impl Sync for Once {} +unsafe impl Send for Once {} + +// Four states that a Once can be in, encoded into the lower bits of `state` in +// the Once structure. +const INCOMPLETE: usize = 0x0; +const RUNNING: usize = 0x1; +const COMPLETE: usize = 0x2; +const PANICKED: usize = 0x3; + +use core::hint::unreachable_unchecked as unreachable; + +impl Once { + /// Initialization constant of `Once`. + pub const INIT: Self = Once { + state: AtomicUsize::new(INCOMPLETE), + data: UnsafeCell::new(None), + }; + + /// Creates a new `Once` value. + pub const fn new() -> Once { + Self::INIT + } + + fn force_get<'a>(&'a self) -> &'a T { + match unsafe { &*self.data.get() }.as_ref() { + None => unsafe { unreachable() }, + Some(p) => p, + } + } + + /// Performs an initialization routine once and only once. The given closure + /// will be executed if this is the first time `call_once` has been called, + /// and otherwise the routine will *not* be invoked. + /// + /// This method will block the calling thread if another initialization + /// routine is currently running. + /// + /// When this function returns, it is guaranteed that some initialization + /// has run and completed (it may not be the closure specified). The + /// returned pointer will point to the result from the closure that was + /// run. + /// + /// # Examples + /// + /// ``` + /// use spin; + /// + /// static INIT: spin::Once = spin::Once::new(); + /// + /// fn get_cached_val() -> usize { + /// *INIT.call_once(expensive_computation) + /// } + /// + /// fn expensive_computation() -> usize { + /// // ... + /// # 2 + /// } + /// ``` + pub fn call_once<'a, F>(&'a self, builder: F) -> &'a T + where F: FnOnce() -> T + { + let mut status = self.state.load(Ordering::SeqCst); + + if status == INCOMPLETE { + status = self.state.compare_and_swap(INCOMPLETE, + RUNNING, + Ordering::SeqCst); + if status == INCOMPLETE { // We init + // We use a guard (Finish) to catch panics caused by builder + let mut finish = Finish { state: &self.state, panicked: true }; + unsafe { *self.data.get() = Some(builder()) }; + finish.panicked = false; + + status = COMPLETE; + self.state.store(status, Ordering::SeqCst); + + // This next line is strictly an optimization + return self.force_get(); + } + } + + loop { + match status { + INCOMPLETE => unreachable!(), + RUNNING => { // We spin + cpu_relax(); + status = self.state.load(Ordering::SeqCst) + }, + PANICKED => panic!("Once has panicked"), + COMPLETE => return self.force_get(), + _ => unsafe { unreachable() }, + } + } + } + + /// Returns a pointer iff the `Once` was previously initialized + pub fn try<'a>(&'a self) -> Option<&'a T> { + match self.state.load(Ordering::SeqCst) { + COMPLETE => Some(self.force_get()), + _ => None, + } + } + + /// Like try, but will spin if the `Once` is in the process of being + /// initialized + pub fn wait<'a>(&'a self) -> Option<&'a T> { + loop { + match self.state.load(Ordering::SeqCst) { + INCOMPLETE => return None, + RUNNING => cpu_relax(), // We spin + COMPLETE => return Some(self.force_get()), + PANICKED => panic!("Once has panicked"), + _ => unsafe { unreachable() }, + } + } + } +} + +struct Finish<'a> { + state: &'a AtomicUsize, + panicked: bool, +} + +impl<'a> Drop for Finish<'a> { + fn drop(&mut self) { + if self.panicked { + self.state.store(PANICKED, Ordering::SeqCst); + } + } +} + +#[cfg(test)] +mod tests { + use std::prelude::v1::*; + + use std::sync::mpsc::channel; + use std::thread; + use super::Once; + + #[test] + fn smoke_once() { + static O: Once<()> = Once::new(); + let mut a = 0; + O.call_once(|| a += 1); + assert_eq!(a, 1); + O.call_once(|| a += 1); + assert_eq!(a, 1); + } + + #[test] + fn smoke_once_value() { + static O: Once = Once::new(); + let a = O.call_once(|| 1); + assert_eq!(*a, 1); + let b = O.call_once(|| 2); + assert_eq!(*b, 1); + } + + #[test] + fn stampede_once() { + static O: Once<()> = Once::new(); + static mut RUN: bool = false; + + let (tx, rx) = channel(); + for _ in 0..10 { + let tx = tx.clone(); + thread::spawn(move|| { + for _ in 0..4 { thread::yield_now() } + unsafe { + O.call_once(|| { + assert!(!RUN); + RUN = true; + }); + assert!(RUN); + } + tx.send(()).unwrap(); + }); + } + + unsafe { + O.call_once(|| { + assert!(!RUN); + RUN = true; + }); + assert!(RUN); + } + + for _ in 0..10 { + rx.recv().unwrap(); + } + } + + #[test] + fn try() { + static INIT: Once = Once::new(); + + assert!(INIT.try().is_none()); + INIT.call_once(|| 2); + assert_eq!(INIT.try().map(|r| *r), Some(2)); + } + + #[test] + fn try_no_wait() { + static INIT: Once = Once::new(); + + assert!(INIT.try().is_none()); + thread::spawn(move|| { + INIT.call_once(|| loop { }); + }); + assert!(INIT.try().is_none()); + } + + + #[test] + fn wait() { + static INIT: Once = Once::new(); + + assert!(INIT.wait().is_none()); + INIT.call_once(|| 3); + assert_eq!(INIT.wait().map(|r| *r), Some(3)); + } + + #[test] + fn panic() { + use ::std::panic; + + static INIT: Once<()> = Once::new(); + + // poison the once + let t = panic::catch_unwind(|| { + INIT.call_once(|| panic!()); + }); + assert!(t.is_err()); + + // poisoning propagates + let t = panic::catch_unwind(|| { + INIT.call_once(|| {}); + }); + assert!(t.is_err()); + } + + #[test] + fn init_constant() { + static O: Once<()> = Once::INIT; + let mut a = 0; + O.call_once(|| a += 1); + assert_eq!(a, 1); + O.call_once(|| a += 1); + assert_eq!(a, 1); + } +} diff --git a/vendor/spin-0.5.2/src/rw_lock.rs b/vendor/spin-0.5.2/src/rw_lock.rs new file mode 100644 index 0000000000000..181b26cf12017 --- /dev/null +++ b/vendor/spin-0.5.2/src/rw_lock.rs @@ -0,0 +1,777 @@ +use core::cell::UnsafeCell; +use core::default::Default; +use core::fmt; +use core::marker::PhantomData; +use core::mem; +use core::ops::{Deref, DerefMut}; +use core::ptr::NonNull; +use core::sync::atomic::{spin_loop_hint as cpu_relax, AtomicUsize, Ordering}; + +/// A reader-writer lock +/// +/// This type of lock allows a number of readers or at most one writer at any +/// point in time. The write portion of this lock typically allows modification +/// of the underlying data (exclusive access) and the read portion of this lock +/// typically allows for read-only access (shared access). +/// +/// The type parameter `T` represents the data that this lock protects. It is +/// required that `T` satisfies `Send` to be shared across tasks and `Sync` to +/// allow concurrent access through readers. The RAII guards returned from the +/// locking methods implement `Deref` (and `DerefMut` for the `write` methods) +/// to allow access to the contained of the lock. +/// +/// An [`RwLockUpgradeableGuard`](RwLockUpgradeableGuard) can be upgraded to a +/// writable guard through the [`RwLockUpgradeableGuard::upgrade`](RwLockUpgradeableGuard::upgrade) +/// [`RwLockUpgradeableGuard::try_upgrade`](RwLockUpgradeableGuard::try_upgrade) functions. +/// Writable or upgradeable guards can be downgraded through their respective `downgrade` +/// functions. +/// +/// Based on Facebook's +/// [`folly/RWSpinLock.h`](https://github.com/facebook/folly/blob/a0394d84f2d5c3e50ebfd0566f9d3acb52cfab5a/folly/synchronization/RWSpinLock.h). +/// This implementation is unfair to writers - if the lock always has readers, then no writers will +/// ever get a chance. Using an upgradeable lock guard can *somewhat* alleviate this issue as no +/// new readers are allowed when an upgradeable guard is held, but upgradeable guards can be taken +/// when there are existing readers. However if the lock is that highly contended and writes are +/// crucial then this implementation may be a poor choice. +/// +/// # Examples +/// +/// ``` +/// use spin; +/// +/// let lock = spin::RwLock::new(5); +/// +/// // many reader locks can be held at once +/// { +/// let r1 = lock.read(); +/// let r2 = lock.read(); +/// assert_eq!(*r1, 5); +/// assert_eq!(*r2, 5); +/// } // read locks are dropped at this point +/// +/// // only one write lock may be held, however +/// { +/// let mut w = lock.write(); +/// *w += 1; +/// assert_eq!(*w, 6); +/// } // write lock is dropped here +/// ``` +pub struct RwLock { + lock: AtomicUsize, + data: UnsafeCell, +} + +const READER: usize = 1 << 2; +const UPGRADED: usize = 1 << 1; +const WRITER: usize = 1; + +/// A guard from which the protected data can be read +/// +/// When the guard falls out of scope it will decrement the read count, +/// potentially releasing the lock. +#[derive(Debug)] +pub struct RwLockReadGuard<'a, T: 'a + ?Sized> { + lock: &'a AtomicUsize, + data: NonNull, +} + +/// A guard to which the protected data can be written +/// +/// When the guard falls out of scope it will release the lock. +#[derive(Debug)] +pub struct RwLockWriteGuard<'a, T: 'a + ?Sized> { + lock: &'a AtomicUsize, + data: NonNull, + #[doc(hidden)] + _invariant: PhantomData<&'a mut T>, +} + +/// A guard from which the protected data can be read, and can be upgraded +/// to a writable guard if needed +/// +/// No writers or other upgradeable guards can exist while this is in scope. New reader +/// creation is prevented (to alleviate writer starvation) but there may be existing readers +/// when the lock is acquired. +/// +/// When the guard falls out of scope it will release the lock. +#[derive(Debug)] +pub struct RwLockUpgradeableGuard<'a, T: 'a + ?Sized> { + lock: &'a AtomicUsize, + data: NonNull, + #[doc(hidden)] + _invariant: PhantomData<&'a mut T>, +} + +// Same unsafe impls as `std::sync::RwLock` +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +impl RwLock { + /// Creates a new spinlock wrapping the supplied data. + /// + /// May be used statically: + /// + /// ``` + /// use spin; + /// + /// static RW_LOCK: spin::RwLock<()> = spin::RwLock::new(()); + /// + /// fn demo() { + /// let lock = RW_LOCK.read(); + /// // do something with lock + /// drop(lock); + /// } + /// ``` + #[inline] + pub const fn new(user_data: T) -> RwLock { + RwLock { + lock: AtomicUsize::new(0), + data: UnsafeCell::new(user_data), + } + } + + /// Consumes this `RwLock`, returning the underlying data. + #[inline] + pub fn into_inner(self) -> T { + // We know statically that there are no outstanding references to + // `self` so there's no need to lock. + let RwLock { data, .. } = self; + data.into_inner() + } +} + +impl RwLock { + /// Locks this rwlock with shared read access, blocking the current thread + /// until it can be acquired. + /// + /// The calling thread will be blocked until there are no more writers which + /// hold the lock. There may be other readers currently inside the lock when + /// this method returns. This method does not provide any guarantees with + /// respect to the ordering of whether contentious readers or writers will + /// acquire the lock first. + /// + /// Returns an RAII guard which will release this thread's shared access + /// once it is dropped. + /// + /// ``` + /// let mylock = spin::RwLock::new(0); + /// { + /// let mut data = mylock.read(); + /// // The lock is now locked and the data can be read + /// println!("{}", *data); + /// // The lock is dropped + /// } + /// ``` + #[inline] + pub fn read(&self) -> RwLockReadGuard { + loop { + match self.try_read() { + Some(guard) => return guard, + None => cpu_relax(), + } + } + } + + /// Attempt to acquire this lock with shared read access. + /// + /// This function will never block and will return immediately if `read` + /// would otherwise succeed. Returns `Some` of an RAII guard which will + /// release the shared access of this thread when dropped, or `None` if the + /// access could not be granted. This method does not provide any + /// guarantees with respect to the ordering of whether contentious readers + /// or writers will acquire the lock first. + /// + /// ``` + /// let mylock = spin::RwLock::new(0); + /// { + /// match mylock.try_read() { + /// Some(data) => { + /// // The lock is now locked and the data can be read + /// println!("{}", *data); + /// // The lock is dropped + /// }, + /// None => (), // no cigar + /// }; + /// } + /// ``` + #[inline] + pub fn try_read(&self) -> Option> { + let value = self.lock.fetch_add(READER, Ordering::Acquire); + + // We check the UPGRADED bit here so that new readers are prevented when an UPGRADED lock is held. + // This helps reduce writer starvation. + if value & (WRITER | UPGRADED) != 0 { + // Lock is taken, undo. + self.lock.fetch_sub(READER, Ordering::Release); + None + } else { + Some(RwLockReadGuard { + lock: &self.lock, + data: unsafe { NonNull::new_unchecked(self.data.get()) }, + }) + } + } + + /// Force decrement the reader count. + /// + /// This is *extremely* unsafe if there are outstanding `RwLockReadGuard`s + /// live, or if called more times than `read` has been called, but can be + /// useful in FFI contexts where the caller doesn't know how to deal with + /// RAII. The underlying atomic operation uses `Ordering::Release`. + #[inline] + pub unsafe fn force_read_decrement(&self) { + debug_assert!(self.lock.load(Ordering::Relaxed) & !WRITER > 0); + self.lock.fetch_sub(READER, Ordering::Release); + } + + /// Force unlock exclusive write access. + /// + /// This is *extremely* unsafe if there are outstanding `RwLockWriteGuard`s + /// live, or if called when there are current readers, but can be useful in + /// FFI contexts where the caller doesn't know how to deal with RAII. The + /// underlying atomic operation uses `Ordering::Release`. + #[inline] + pub unsafe fn force_write_unlock(&self) { + debug_assert_eq!(self.lock.load(Ordering::Relaxed) & !(WRITER | UPGRADED), 0); + self.lock.fetch_and(!(WRITER | UPGRADED), Ordering::Release); + } + + #[inline(always)] + fn try_write_internal(&self, strong: bool) -> Option> { + if compare_exchange( + &self.lock, + 0, + WRITER, + Ordering::Acquire, + Ordering::Relaxed, + strong, + ) + .is_ok() + { + Some(RwLockWriteGuard { + lock: &self.lock, + data: unsafe { NonNull::new_unchecked(self.data.get()) }, + _invariant: PhantomData, + }) + } else { + None + } + } + + /// Lock this rwlock with exclusive write access, blocking the current + /// thread until it can be acquired. + /// + /// This function will not return while other writers or other readers + /// currently have access to the lock. + /// + /// Returns an RAII guard which will drop the write access of this rwlock + /// when dropped. + /// + /// ``` + /// let mylock = spin::RwLock::new(0); + /// { + /// let mut data = mylock.write(); + /// // The lock is now locked and the data can be written + /// *data += 1; + /// // The lock is dropped + /// } + /// ``` + #[inline] + pub fn write(&self) -> RwLockWriteGuard { + loop { + match self.try_write_internal(false) { + Some(guard) => return guard, + None => cpu_relax(), + } + } + } + + /// Attempt to lock this rwlock with exclusive write access. + /// + /// This function does not ever block, and it will return `None` if a call + /// to `write` would otherwise block. If successful, an RAII guard is + /// returned. + /// + /// ``` + /// let mylock = spin::RwLock::new(0); + /// { + /// match mylock.try_write() { + /// Some(mut data) => { + /// // The lock is now locked and the data can be written + /// *data += 1; + /// // The lock is implicitly dropped + /// }, + /// None => (), // no cigar + /// }; + /// } + /// ``` + #[inline] + pub fn try_write(&self) -> Option> { + self.try_write_internal(true) + } + + /// Obtain a readable lock guard that can later be upgraded to a writable lock guard. + /// Upgrades can be done through the [`RwLockUpgradeableGuard::upgrade`](RwLockUpgradeableGuard::upgrade) method. + #[inline] + pub fn upgradeable_read(&self) -> RwLockUpgradeableGuard { + loop { + match self.try_upgradeable_read() { + Some(guard) => return guard, + None => cpu_relax(), + } + } + } + + /// Tries to obtain an upgradeable lock guard. + #[inline] + pub fn try_upgradeable_read(&self) -> Option> { + if self.lock.fetch_or(UPGRADED, Ordering::Acquire) & (WRITER | UPGRADED) == 0 { + Some(RwLockUpgradeableGuard { + lock: &self.lock, + data: unsafe { NonNull::new_unchecked(self.data.get()) }, + _invariant: PhantomData, + }) + } else { + // We can't unflip the UPGRADED bit back just yet as there is another upgradeable or write lock. + // When they unlock, they will clear the bit. + None + } + } +} + +impl fmt::Debug for RwLock { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.try_read() { + Some(guard) => write!(f, "RwLock {{ data: ") + .and_then(|()| (&*guard).fmt(f)) + .and_then(|()| write!(f, "}}")), + None => write!(f, "RwLock {{ }}"), + } + } +} + +impl Default for RwLock { + fn default() -> RwLock { + RwLock::new(Default::default()) + } +} + +impl<'rwlock, T: ?Sized> RwLockUpgradeableGuard<'rwlock, T> { + #[inline(always)] + fn try_upgrade_internal(self, strong: bool) -> Result, Self> { + if compare_exchange( + &self.lock, + UPGRADED, + WRITER, + Ordering::Acquire, + Ordering::Relaxed, + strong, + ) + .is_ok() + { + // Upgrade successful + let out = Ok(RwLockWriteGuard { + lock: &self.lock, + data: self.data, + _invariant: PhantomData, + }); + + // Forget the old guard so its destructor doesn't run + mem::forget(self); + + out + } else { + Err(self) + } + } + + /// Upgrades an upgradeable lock guard to a writable lock guard. + /// + /// ``` + /// let mylock = spin::RwLock::new(0); + /// + /// let upgradeable = mylock.upgradeable_read(); // Readable, but not yet writable + /// let writable = upgradeable.upgrade(); + /// ``` + #[inline] + pub fn upgrade(mut self) -> RwLockWriteGuard<'rwlock, T> { + loop { + self = match self.try_upgrade_internal(false) { + Ok(guard) => return guard, + Err(e) => e, + }; + + cpu_relax(); + } + } + + /// Tries to upgrade an upgradeable lock guard to a writable lock guard. + /// + /// ``` + /// let mylock = spin::RwLock::new(0); + /// let upgradeable = mylock.upgradeable_read(); // Readable, but not yet writable + /// + /// match upgradeable.try_upgrade() { + /// Ok(writable) => /* upgrade successful - use writable lock guard */ (), + /// Err(upgradeable) => /* upgrade unsuccessful */ (), + /// }; + /// ``` + #[inline] + pub fn try_upgrade(self) -> Result, Self> { + self.try_upgrade_internal(true) + } + + #[inline] + /// Downgrades the upgradeable lock guard to a readable, shared lock guard. Cannot fail and is guaranteed not to spin. + /// + /// ``` + /// let mylock = spin::RwLock::new(1); + /// + /// let upgradeable = mylock.upgradeable_read(); + /// assert!(mylock.try_read().is_none()); + /// assert_eq!(*upgradeable, 1); + /// + /// let readable = upgradeable.downgrade(); // This is guaranteed not to spin + /// assert!(mylock.try_read().is_some()); + /// assert_eq!(*readable, 1); + /// ``` + pub fn downgrade(self) -> RwLockReadGuard<'rwlock, T> { + // Reserve the read guard for ourselves + self.lock.fetch_add(READER, Ordering::Acquire); + + RwLockReadGuard { + lock: &self.lock, + data: self.data, + } + + // Dropping self removes the UPGRADED bit + } +} + +impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { + /// Downgrades the writable lock guard to a readable, shared lock guard. Cannot fail and is guaranteed not to spin. + /// + /// ``` + /// let mylock = spin::RwLock::new(0); + /// + /// let mut writable = mylock.write(); + /// *writable = 1; + /// + /// let readable = writable.downgrade(); // This is guaranteed not to spin + /// # let readable_2 = mylock.try_read().unwrap(); + /// assert_eq!(*readable, 1); + /// ``` + #[inline] + pub fn downgrade(self) -> RwLockReadGuard<'rwlock, T> { + // Reserve the read guard for ourselves + self.lock.fetch_add(READER, Ordering::Acquire); + + RwLockReadGuard { + lock: &self.lock, + data: self.data, + } + + // Dropping self removes the WRITER bit + } +} + +impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { self.data.as_ref() } + } +} + +impl<'rwlock, T: ?Sized> Deref for RwLockUpgradeableGuard<'rwlock, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { self.data.as_ref() } + } +} + +impl<'rwlock, T: ?Sized> Deref for RwLockWriteGuard<'rwlock, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { self.data.as_ref() } + } +} + +impl<'rwlock, T: ?Sized> DerefMut for RwLockWriteGuard<'rwlock, T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { self.data.as_mut() } + } +} + +impl<'rwlock, T: ?Sized> Drop for RwLockReadGuard<'rwlock, T> { + fn drop(&mut self) { + debug_assert!(self.lock.load(Ordering::Relaxed) & !(WRITER | UPGRADED) > 0); + self.lock.fetch_sub(READER, Ordering::Release); + } +} + +impl<'rwlock, T: ?Sized> Drop for RwLockUpgradeableGuard<'rwlock, T> { + fn drop(&mut self) { + debug_assert_eq!( + self.lock.load(Ordering::Relaxed) & (WRITER | UPGRADED), + UPGRADED + ); + self.lock.fetch_sub(UPGRADED, Ordering::AcqRel); + } +} + +impl<'rwlock, T: ?Sized> Drop for RwLockWriteGuard<'rwlock, T> { + fn drop(&mut self) { + debug_assert_eq!(self.lock.load(Ordering::Relaxed) & WRITER, WRITER); + + // Writer is responsible for clearing both WRITER and UPGRADED bits. + // The UPGRADED bit may be set if an upgradeable lock attempts an upgrade while this lock is held. + self.lock.fetch_and(!(WRITER | UPGRADED), Ordering::Release); + } +} + +#[inline(always)] +fn compare_exchange( + atomic: &AtomicUsize, + current: usize, + new: usize, + success: Ordering, + failure: Ordering, + strong: bool, +) -> Result { + if strong { + atomic.compare_exchange(current, new, success, failure) + } else { + atomic.compare_exchange_weak(current, new, success, failure) + } +} + +#[cfg(test)] +mod tests { + use std::prelude::v1::*; + + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::sync::mpsc::channel; + use std::sync::Arc; + use std::thread; + + use super::*; + + #[derive(Eq, PartialEq, Debug)] + struct NonCopy(i32); + + #[test] + fn smoke() { + let l = RwLock::new(()); + drop(l.read()); + drop(l.write()); + drop((l.read(), l.read())); + drop(l.write()); + } + + // TODO: needs RNG + //#[test] + //fn frob() { + // static R: RwLock = RwLock::new(); + // const N: usize = 10; + // const M: usize = 1000; + // + // let (tx, rx) = channel::<()>(); + // for _ in 0..N { + // let tx = tx.clone(); + // thread::spawn(move|| { + // let mut rng = rand::thread_rng(); + // for _ in 0..M { + // if rng.gen_weighted_bool(N) { + // drop(R.write()); + // } else { + // drop(R.read()); + // } + // } + // drop(tx); + // }); + // } + // drop(tx); + // let _ = rx.recv(); + // unsafe { R.destroy(); } + //} + + #[test] + fn test_rw_arc() { + let arc = Arc::new(RwLock::new(0)); + let arc2 = arc.clone(); + let (tx, rx) = channel(); + + thread::spawn(move || { + let mut lock = arc2.write(); + for _ in 0..10 { + let tmp = *lock; + *lock = -1; + thread::yield_now(); + *lock = tmp + 1; + } + tx.send(()).unwrap(); + }); + + // Readers try to catch the writer in the act + let mut children = Vec::new(); + for _ in 0..5 { + let arc3 = arc.clone(); + children.push(thread::spawn(move || { + let lock = arc3.read(); + assert!(*lock >= 0); + })); + } + + // Wait for children to pass their asserts + for r in children { + assert!(r.join().is_ok()); + } + + // Wait for writer to finish + rx.recv().unwrap(); + let lock = arc.read(); + assert_eq!(*lock, 10); + } + + #[test] + fn test_rw_access_in_unwind() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _ = thread::spawn(move || -> () { + struct Unwinder { + i: Arc>, + } + impl Drop for Unwinder { + fn drop(&mut self) { + let mut lock = self.i.write(); + *lock += 1; + } + } + let _u = Unwinder { i: arc2 }; + panic!(); + }) + .join(); + let lock = arc.read(); + assert_eq!(*lock, 2); + } + + #[test] + fn test_rwlock_unsized() { + let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); + { + let b = &mut *rw.write(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*rw.read(), comp); + } + + #[test] + fn test_rwlock_try_write() { + use std::mem::drop; + + let lock = RwLock::new(0isize); + let read_guard = lock.read(); + + let write_result = lock.try_write(); + match write_result { + None => (), + Some(_) => assert!( + false, + "try_write should not succeed while read_guard is in scope" + ), + } + + drop(read_guard); + } + + #[test] + fn test_rw_try_read() { + let m = RwLock::new(0); + mem::forget(m.write()); + assert!(m.try_read().is_none()); + } + + #[test] + fn test_into_inner() { + let m = RwLock::new(NonCopy(10)); + assert_eq!(m.into_inner(), NonCopy(10)); + } + + #[test] + fn test_into_inner_drop() { + struct Foo(Arc); + impl Drop for Foo { + fn drop(&mut self) { + self.0.fetch_add(1, Ordering::SeqCst); + } + } + let num_drops = Arc::new(AtomicUsize::new(0)); + let m = RwLock::new(Foo(num_drops.clone())); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + { + let _inner = m.into_inner(); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + } + assert_eq!(num_drops.load(Ordering::SeqCst), 1); + } + + #[test] + fn test_force_read_decrement() { + let m = RwLock::new(()); + ::std::mem::forget(m.read()); + ::std::mem::forget(m.read()); + ::std::mem::forget(m.read()); + assert!(m.try_write().is_none()); + unsafe { + m.force_read_decrement(); + m.force_read_decrement(); + } + assert!(m.try_write().is_none()); + unsafe { + m.force_read_decrement(); + } + assert!(m.try_write().is_some()); + } + + #[test] + fn test_force_write_unlock() { + let m = RwLock::new(()); + ::std::mem::forget(m.write()); + assert!(m.try_read().is_none()); + unsafe { + m.force_write_unlock(); + } + assert!(m.try_read().is_some()); + } + + #[test] + fn test_upgrade_downgrade() { + let m = RwLock::new(()); + { + let _r = m.read(); + let upg = m.try_upgradeable_read().unwrap(); + assert!(m.try_read().is_none()); + assert!(m.try_write().is_none()); + assert!(upg.try_upgrade().is_err()); + } + { + let w = m.write(); + assert!(m.try_upgradeable_read().is_none()); + let _r = w.downgrade(); + assert!(m.try_upgradeable_read().is_some()); + assert!(m.try_read().is_some()); + assert!(m.try_write().is_none()); + } + { + let _u = m.upgradeable_read(); + assert!(m.try_upgradeable_read().is_none()); + } + + assert!(m.try_upgradeable_read().unwrap().try_upgrade().is_ok()); + } +} diff --git a/vendor/strsim-0.8.0/.cargo-checksum.json b/vendor/strsim-0.8.0/.cargo-checksum.json new file mode 100644 index 0000000000000..6b073e9bdfdb1 --- /dev/null +++ b/vendor/strsim-0.8.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"18e89ab18be7d22dd835924a38b1198651e870dfd0a2904a344120d341c4bc0e","Cargo.toml":"dd189fa732c00b7d1b036b43220253ef6ff2a0b1ff5ca7cf13f0669113a2055e","LICENSE":"1738b51502ae831fb59ffbeb22ebdd90bf17e5c72fe57c00b47552415f133fd8","README.md":"cfb01477df60cd0780ba59cbbc388f3f71d83bf51bab77e004fc7b811aff0efd","appveyor.yml":"b41eae9798a9bb250f6046509d9bbd6e63bac9ad2655d342b3d9c8975584f0c0","benches/benches.rs":"e277857c44afdc08b2acf35fc05be6226529c588eb9da397382b0a74c58615ab","dev":"5bd26dc2c86f777627abe96c5992b6c45e6b5dea52f42b7107fa5c106abe2ab4","src/lib.rs":"26a960216567e5dea46033b3383a69e7da498095c092e195e92c05faef52f915","tests/lib.rs":"de2b1181c379a0f55de7b86021a9afb77dbe81053a6acf99623bec3663f9b7c4"},"package":"8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"} \ No newline at end of file diff --git a/vendor/strsim-0.8.0/CHANGELOG.md b/vendor/strsim-0.8.0/CHANGELOG.md new file mode 100644 index 0000000000000..48d6359eaf11c --- /dev/null +++ b/vendor/strsim-0.8.0/CHANGELOG.md @@ -0,0 +1,123 @@ +# Change Log +This project attempts to adhere to [Semantic Versioning](http://semver.org). + +## [Unreleased] + +## [0.8.0] - (2018-08-19) +### Added +- Normalized versions of Levenshtein and Damerau-Levenshtein (thanks [@gentoid](https://github.com/gentoid)) + +## [0.7.0] - (2018-01-17) +### Changed +- Faster Levenshtein implementation (thanks [@wdv4758h](https://github.com/wdv4758h)) + +### Removed +- Remove the "against_vec" functions. They are one-liners now, so they don't + seem to add enough value to justify making the API larger. I didn't find + anybody using them when I skimmed through a GitHub search. If you do use them, + you can change the calls to something like: +```rust +let distances = strings.iter().map(|a| jaro(target, a)).collect(); +``` + +## [0.6.0] - (2016-12-26) +### Added +- Add optimal string alignment distance + +### Fixed +- Fix Damerau-Levenshtein implementation (previous implementation was actually + optimal string alignment; see this [Damerau-Levenshtein explanation]) + +## [0.5.2] - (2016-11-21) +### Changed +- Remove Cargo generated documentation in favor of a [docs.rs] link + +## [0.5.1] - (2016-08-23) +### Added +- Add Cargo generated documentation + +### Fixed +- Fix panic when Jaro or Jaro-Winkler are given strings both with a length of + one + +## [0.5.0] - (2016-08-11) +### Changed +- Make Hamming faster (thanks @IBUzPE9) when the two strings have the same + length but slower when they have different lengths + +## [0.4.1] - (2016-04-18) +### Added +- Add Vagrant setup for development +- Add AppVeyor configuration for Windows CI + +### Fixed +- Fix metrics when given strings with multibyte characters (thanks @WanzenBug) + +## [0.4.0] - (2015-06-10) +### Added +- For each metric, add a function that takes a vector of strings and returns a +vector of results (thanks @ovarene) + +## [0.3.0] - (2015-04-30) +### Changed +- Remove usage of unstable Rust features + +## [0.2.5] - (2015-04-24) +### Fixed +- Remove unnecessary `Float` import from doc tests + +## [0.2.4] - (2015-04-15) +### Fixed +- Remove unused `core` feature flag + +## [0.2.3] - (2015-04-01) +### Fixed +- Remove now unnecessary `Float` import + +## [0.2.2] - (2015-03-29) +### Fixed +- Remove usage of `char_at` (marked as unstable) + +## [0.2.1] - (2015-02-20) +### Fixed +- Update bit vector import to match Rust update + +## [0.2.0] - (2015-02-19) +### Added +- Implement Damerau-Levenshtein +- Add tests in docs + +## [0.1.1] - (2015-02-10) +### Added +- Configure Travis for CI +- Add rustdoc comments + +### Fixed +- Limit Jaro-Winkler return value to a maximum of 1.0 +- Fix float comparisons in tests + +## [0.1.0] - (2015-02-09) +### Added +- Implement Hamming, Jaro, Jaro-Winkler, and Levenshtein + +[Unreleased]: https://github.com/dguo/strsim-rs/compare/0.8.0...HEAD +[0.8.0]: https://github.com/dguo/strsim-rs/compare/0.7.0...0.8.0 +[0.7.0]: https://github.com/dguo/strsim-rs/compare/0.6.0...0.7.0 +[0.6.0]: https://github.com/dguo/strsim-rs/compare/0.5.2...0.6.0 +[0.5.2]: https://github.com/dguo/strsim-rs/compare/0.5.1...0.5.2 +[0.5.1]: https://github.com/dguo/strsim-rs/compare/0.5.0...0.5.1 +[0.5.0]: https://github.com/dguo/strsim-rs/compare/0.4.1...0.5.0 +[0.4.1]: https://github.com/dguo/strsim-rs/compare/0.4.0...0.4.1 +[0.4.0]: https://github.com/dguo/strsim-rs/compare/0.3.0...0.4.0 +[0.3.0]: https://github.com/dguo/strsim-rs/compare/0.2.5...0.3.0 +[0.2.5]: https://github.com/dguo/strsim-rs/compare/0.2.4...0.2.5 +[0.2.4]: https://github.com/dguo/strsim-rs/compare/0.2.3...0.2.4 +[0.2.3]: https://github.com/dguo/strsim-rs/compare/0.2.2...0.2.3 +[0.2.2]: https://github.com/dguo/strsim-rs/compare/0.2.1...0.2.2 +[0.2.1]: https://github.com/dguo/strsim-rs/compare/0.2.0...0.2.1 +[0.2.0]: https://github.com/dguo/strsim-rs/compare/0.1.1...0.2.0 +[0.1.1]: https://github.com/dguo/strsim-rs/compare/0.1.0...0.1.1 +[0.1.0]: https://github.com/dguo/strsim-rs/compare/fabad4...0.1.0 +[docs.rs]: https://docs.rs/strsim/ +[Damerau-Levenshtein explanation]: +http://scarcitycomputing.blogspot.com/2013/04/damerau-levenshtein-edit-distance.html diff --git a/vendor/strsim-0.8.0/Cargo.toml b/vendor/strsim-0.8.0/Cargo.toml new file mode 100644 index 0000000000000..38d37aee5b3e3 --- /dev/null +++ b/vendor/strsim-0.8.0/Cargo.toml @@ -0,0 +1,28 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "strsim" +version = "0.8.0" +authors = ["Danny Guo "] +description = "Implementations of string similarity metrics.\nIncludes Hamming, Levenshtein, OSA, Damerau-Levenshtein, Jaro, and Jaro-Winkler.\n" +homepage = "https://github.com/dguo/strsim-rs" +documentation = "https://docs.rs/strsim/" +readme = "README.md" +keywords = ["string", "similarity", "Hamming", "Levenshtein", "Jaro"] +license = "MIT" +repository = "https://github.com/dguo/strsim-rs" +[badges.appveyor] +repository = "dguo/strsim-rs" + +[badges.travis-ci] +repository = "dguo/strsim-rs" diff --git a/vendor/strsim-0.8.0/LICENSE b/vendor/strsim-0.8.0/LICENSE new file mode 100644 index 0000000000000..1aacdb8642b56 --- /dev/null +++ b/vendor/strsim-0.8.0/LICENSE @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) 2015 Danny Guo +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/strsim-0.8.0/README.md b/vendor/strsim-0.8.0/README.md new file mode 100644 index 0000000000000..8765ea85f9904 --- /dev/null +++ b/vendor/strsim-0.8.0/README.md @@ -0,0 +1,69 @@ +# strsim-rs [![Crates.io](https://img.shields.io/crates/v/strsim.svg)](https://crates.io/crates/strsim) [![Crates.io](https://img.shields.io/crates/l/strsim.svg?maxAge=2592000)](https://github.com/dguo/strsim-rs/blob/master/LICENSE) [![Linux build status](https://travis-ci.org/dguo/strsim-rs.svg?branch=master)](https://travis-ci.org/dguo/strsim-rs) [![Windows build status](https://ci.appveyor.com/api/projects/status/ggue6i785618a39w?svg=true)](https://ci.appveyor.com/project/dguo/strsim-rs) + +[Rust](https://www.rust-lang.org) implementations of [string similarity metrics]: + - [Hamming] + - [Levenshtein] - distance & normalized + - [Optimal string alignment] + - [Damerau-Levenshtein] - distance & normalized + - [Jaro and Jaro-Winkler] - this implementation of Jaro-Winkler does not limit the common prefix length + +### Installation +```toml +# Cargo.toml +[dependencies] +strsim = "0.8.0" +``` + +### [Documentation](https://docs.rs/strsim/) +You can change the version in the url to see the documentation for an older +version in the +[changelog](https://github.com/dguo/strsim-rs/blob/master/CHANGELOG.md). + +### Usage +```rust +extern crate strsim; + +use strsim::{hamming, levenshtein, normalized_levenshtein, osa_distance, + damerau_levenshtein, normalized_damerau_levenshtein, jaro, + jaro_winkler}; + +fn main() { + match hamming("hamming", "hammers") { + Ok(distance) => assert_eq!(3, distance), + Err(why) => panic!("{:?}", why) + } + + assert_eq!(3, levenshtein("kitten", "sitting")); + + assert!((normalized_levenshtein("kitten", "sitting") - 0.57142).abs() < 0.00001); + + assert_eq!(3, osa_distance("ac", "cba")); + + assert_eq!(2, damerau_levenshtein("ac", "cba")); + + assert!((normalized_damerau_levenshtein("levenshtein", "löwenbräu") - 0.27272).abs() < 0.00001) + + assert!((0.392 - jaro("Friedrich Nietzsche", "Jean-Paul Sartre")).abs() < + 0.001); + + assert!((0.911 - jaro_winkler("cheeseburger", "cheese fries")).abs() < + 0.001); +} +``` + +### Development +If you don't want to install Rust itself, you can run `$ ./dev` for a +development CLI if you have [Docker] installed. + +Benchmarks require a Nightly toolchain. They are run by `cargo +nightly bench`. + +### License +[MIT](https://github.com/dguo/strsim-rs/blob/master/LICENSE) + +[string similarity metrics]:http://en.wikipedia.org/wiki/String_metric +[Damerau-Levenshtein]:http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance +[Jaro and Jaro-Winkler]:http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance +[Levenshtein]:http://en.wikipedia.org/wiki/Levenshtein_distance +[Hamming]:http://en.wikipedia.org/wiki/Hamming_distance +[Optimal string alignment]:https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance#Optimal_string_alignment_distance +[Docker]:https://docs.docker.com/engine/installation/ diff --git a/vendor/strsim-0.8.0/appveyor.yml b/vendor/strsim-0.8.0/appveyor.yml new file mode 100644 index 0000000000000..fb992db82b662 --- /dev/null +++ b/vendor/strsim-0.8.0/appveyor.yml @@ -0,0 +1,13 @@ +install: + - ps: Start-FileDownload 'https://static.rust-lang.org/dist/rust-beta-x86_64-pc-windows-gnu.exe' + - rust-beta-x86_64-pc-windows-gnu.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo build + - cargo test --verbose + diff --git a/vendor/strsim-0.8.0/benches/benches.rs b/vendor/strsim-0.8.0/benches/benches.rs new file mode 100644 index 0000000000000..a6d5372e845a2 --- /dev/null +++ b/vendor/strsim-0.8.0/benches/benches.rs @@ -0,0 +1,84 @@ +//! Benchmarks for strsim. + +#![feature(test)] + +extern crate strsim; + +mod benches { + use super::*; + + extern crate test; + use self::test::Bencher; + + #[bench] + fn bench_hamming(bencher: &mut Bencher) { + let a = "ACAAGATGCCATTGTCCCCCGGCCTCCTGCTGCTGCTGCTCTCCGGGG"; + let b = "CCTGGAGGGTGGCCCCACCGGCCGAGACAGCGAGCATATGCAGGAAGC"; + bencher.iter(|| { + strsim::hamming(&a, &b).unwrap(); + }) + } + + #[bench] + fn bench_jaro(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::jaro(&a, &b); + }) + } + + #[bench] + fn bench_jaro_winkler(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::jaro_winkler(&a, &b); + }) + } + + #[bench] + fn bench_levenshtein(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::levenshtein(&a, &b); + }) + } + + #[bench] + fn bench_normalized_levenshtein(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::normalized_levenshtein(&a, &b); + }) + } + + #[bench] + fn bench_osa_distance(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::osa_distance(&a, &b); + }) + } + + #[bench] + fn bench_damerau_levenshtein(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::damerau_levenshtein(&a, &b); + }) + } + + #[bench] + fn bench_normalized_damerau_levenshtein(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::normalized_damerau_levenshtein(&a, &b); + }) + } +} diff --git a/vendor/strsim-0.8.0/dev b/vendor/strsim-0.8.0/dev new file mode 100755 index 0000000000000..4c85a494b7786 --- /dev/null +++ b/vendor/strsim-0.8.0/dev @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# ./dev --help + +import argparse +import os +from subprocess import run +import sys + +parser = argparse.ArgumentParser(prog='./dev') +subparsers = parser.add_subparsers(metavar='', title='commands') +command = [ + 'docker', 'run', '-it', '--rm', '-v', os.getcwd() + ':/src:cached', + '-w=/src', 'rust:1.21.0' +] + +def cargo(args, remaining): + sys.exit(run(command + ['cargo'] + remaining or []).returncode) + +parser_cargo = subparsers.add_parser('cargo', help='run a cargo command') +parser_cargo.set_defaults(func=cargo) + +def sh(args, remaining): + sys.exit(run(command + ['bash']).returncode) + +parser_sh = subparsers.add_parser('sh', help='bring up a shell') +parser_sh.set_defaults(func=sh) + +def test(args, remaining): + sys.exit(run(command + ['cargo', 'test']).returncode) + +parser_test = subparsers.add_parser('test', help='run tests') +parser_test.set_defaults(func=test) + +if len(sys.argv) > 1: + args, remaining = parser.parse_known_args() + try: + args.func(args, remaining) + except FileNotFoundError: + sys.exit('Please install Docker.') +else: + parser.print_help() diff --git a/vendor/strsim-0.8.0/src/lib.rs b/vendor/strsim-0.8.0/src/lib.rs new file mode 100644 index 0000000000000..8c56843b3c314 --- /dev/null +++ b/vendor/strsim-0.8.0/src/lib.rs @@ -0,0 +1,786 @@ +//! This library implements string similarity metrics. + +use std::char; +use std::cmp::{max, min}; +use std::collections::HashMap; + +#[derive(Debug, PartialEq)] +pub enum StrSimError { + DifferentLengthArgs +} + +pub type HammingResult = Result; + +/// Calculates the number of positions in the two strings where the characters +/// differ. Returns an error if the strings have different lengths. +/// +/// ``` +/// use strsim::hamming; +/// +/// match hamming("hamming", "hammers") { +/// Ok(distance) => assert_eq!(3, distance), +/// Err(why) => panic!("{:?}", why) +/// } +/// ``` +pub fn hamming(a: &str, b: &str) -> HammingResult { + let (mut ita, mut itb, mut count) = (a.chars(), b.chars(), 0); + loop { + match (ita.next(), itb.next()){ + (Some(x), Some(y)) => if x != y { count += 1 }, + (None, None) => return Ok(count), + _ => return Err(StrSimError::DifferentLengthArgs), + } + } +} + +/// Calculates the Jaro similarity between two strings. The returned value +/// is between 0.0 and 1.0 (higher value means more similar). +/// +/// ``` +/// use strsim::jaro; +/// +/// assert!((0.392 - jaro("Friedrich Nietzsche", "Jean-Paul Sartre")).abs() < +/// 0.001); +/// ``` +pub fn jaro(a: &str, b: &str) -> f64 { + if a == b { return 1.0; } + + let a_len = a.chars().count(); + let b_len = b.chars().count(); + + // The check for lengths of one here is to prevent integer overflow when + // calculating the search range. + if a_len == 0 || b_len == 0 || (a_len == 1 && b_len == 1) { + return 0.0; + } + + let search_range = (max(a_len, b_len) / 2) - 1; + + let mut b_consumed = Vec::with_capacity(b_len); + for _ in 0..b_len { + b_consumed.push(false); + } + let mut matches = 0.0; + + let mut transpositions = 0.0; + let mut b_match_index = 0; + + for (i, a_char) in a.chars().enumerate() { + let min_bound = + // prevent integer wrapping + if i > search_range { + max(0, i - search_range) + } else { + 0 + }; + + let max_bound = min(b_len - 1, i + search_range); + + if min_bound > max_bound { + continue; + } + + for (j, b_char) in b.chars().enumerate() { + if min_bound <= j && j <= max_bound && a_char == b_char && + !b_consumed[j] { + b_consumed[j] = true; + matches += 1.0; + + if j < b_match_index { + transpositions += 1.0; + } + b_match_index = j; + + break; + } + } + } + + if matches == 0.0 { + 0.0 + } else { + (1.0 / 3.0) * ((matches / a_len as f64) + + (matches / b_len as f64) + + ((matches - transpositions) / matches)) + } +} + +/// Like Jaro but gives a boost to strings that have a common prefix. +/// +/// ``` +/// use strsim::jaro_winkler; +/// +/// assert!((0.911 - jaro_winkler("cheeseburger", "cheese fries")).abs() < +/// 0.001); +/// ``` +pub fn jaro_winkler(a: &str, b: &str) -> f64 { + let jaro_distance = jaro(a, b); + + // Don't limit the length of the common prefix + let prefix_length = a.chars() + .zip(b.chars()) + .take_while(|&(a_char, b_char)| a_char == b_char) + .count(); + + let jaro_winkler_distance = + jaro_distance + (0.1 * prefix_length as f64 * (1.0 - jaro_distance)); + + if jaro_winkler_distance <= 1.0 { + jaro_winkler_distance + } else { + 1.0 + } +} + +/// Calculates the minimum number of insertions, deletions, and substitutions +/// required to change one string into the other. +/// +/// ``` +/// use strsim::levenshtein; +/// +/// assert_eq!(3, levenshtein("kitten", "sitting")); +/// ``` +pub fn levenshtein(a: &str, b: &str) -> usize { + if a == b { return 0; } + + let a_len = a.chars().count(); + let b_len = b.chars().count(); + + if a_len == 0 { return b_len; } + if b_len == 0 { return a_len; } + + let mut cache: Vec = (1..b_len+1).collect(); + + let mut result = 0; + let mut distance_a; + let mut distance_b; + + for (i, a_char) in a.chars().enumerate() { + result = i; + distance_b = i; + + for (j, b_char) in b.chars().enumerate() { + let cost = if a_char == b_char { 0 } else { 1 }; + distance_a = distance_b + cost; + distance_b = cache[j]; + result = min(result + 1, min(distance_a, distance_b + 1)); + cache[j] = result; + } + } + + result +} + +/// Calculates a normalized score of the Levenshtein algorithm between 0.0 and +/// 1.0 (inclusive), where 1.0 means the strings are the same. +/// +/// ``` +/// use strsim::normalized_levenshtein; +/// +/// assert!((normalized_levenshtein("kitten", "sitting") - 0.57142).abs() < 0.00001); +/// assert!((normalized_levenshtein("", "") - 1.0).abs() < 0.00001); +/// assert!(normalized_levenshtein("", "second").abs() < 0.00001); +/// assert!(normalized_levenshtein("first", "").abs() < 0.00001); +/// assert!((normalized_levenshtein("string", "string") - 1.0).abs() < 0.00001); +/// ``` +pub fn normalized_levenshtein(a: &str, b: &str) -> f64 { + if a.is_empty() && b.is_empty() { + return 1.0; + } + 1.0 - (levenshtein(a, b) as f64) / (a.chars().count().max(b.chars().count()) as f64) +} + +/// Like Levenshtein but allows for adjacent transpositions. Each substring can +/// only be edited once. +/// +/// ``` +/// use strsim::osa_distance; +/// +/// assert_eq!(3, osa_distance("ab", "bca")); +/// ``` +pub fn osa_distance(a: &str, b: &str) -> usize { + let a_len = a.chars().count(); + let b_len = b.chars().count(); + if a == b { return 0; } + else if a_len == 0 { return b_len; } + else if b_len == 0 { return a_len; } + + let mut prev_two_distances: Vec = Vec::with_capacity(b_len + 1); + let mut prev_distances: Vec = Vec::with_capacity(b_len + 1); + let mut curr_distances: Vec = Vec::with_capacity(b_len + 1); + + let mut prev_a_char = char::MAX; + let mut prev_b_char = char::MAX; + + for i in 0..(b_len + 1) { + prev_two_distances.push(i); + prev_distances.push(i); + curr_distances.push(0); + } + + for (i, a_char) in a.chars().enumerate() { + curr_distances[0] = i + 1; + + for (j, b_char) in b.chars().enumerate() { + let cost = if a_char == b_char { 0 } else { 1 }; + curr_distances[j + 1] = min(curr_distances[j] + 1, + min(prev_distances[j + 1] + 1, + prev_distances[j] + cost)); + if i > 0 && j > 0 && a_char != b_char && + a_char == prev_b_char && b_char == prev_a_char { + curr_distances[j + 1] = min(curr_distances[j + 1], + prev_two_distances[j - 1] + 1); + } + + prev_b_char = b_char; + } + + prev_two_distances.clone_from(&prev_distances); + prev_distances.clone_from(&curr_distances); + prev_a_char = a_char; + } + + curr_distances[b_len] + +} + +/// Like optimal string alignment, but substrings can be edited an unlimited +/// number of times, and the triangle inequality holds. +/// +/// ``` +/// use strsim::damerau_levenshtein; +/// +/// assert_eq!(2, damerau_levenshtein("ab", "bca")); +/// ``` +pub fn damerau_levenshtein(a: &str, b: &str) -> usize { + if a == b { return 0; } + + let a_chars: Vec = a.chars().collect(); + let b_chars: Vec = b.chars().collect(); + let a_len = a_chars.len(); + let b_len = b_chars.len(); + + if a_len == 0 { return b_len; } + if b_len == 0 { return a_len; } + + let mut distances = vec![vec![0; b_len + 2]; a_len + 2]; + let max_distance = a_len + b_len; + distances[0][0] = max_distance; + + for i in 0..(a_len + 1) { + distances[i + 1][0] = max_distance; + distances[i + 1][1] = i; + } + + for j in 0..(b_len + 1) { + distances[0][j + 1] = max_distance; + distances[1][j + 1] = j; + } + + let mut chars: HashMap = HashMap::new(); + + for i in 1..(a_len + 1) { + let mut db = 0; + + for j in 1..(b_len + 1) { + let k = match chars.get(&b_chars[j - 1]) { + Some(value) => value.clone(), + None => 0 + }; + + let l = db; + + let mut cost = 1; + if a_chars[i - 1] == b_chars[j - 1] { + cost = 0; + db = j; + } + + let substitution_cost = distances[i][j] + cost; + let insertion_cost = distances[i][j + 1] + 1; + let deletion_cost = distances[i + 1][j] + 1; + let transposition_cost = distances[k][l] + (i - k - 1) + 1 + + (j - l - 1); + + distances[i + 1][j + 1] = min(substitution_cost, + min(insertion_cost, + min(deletion_cost, + transposition_cost))); + } + + chars.insert(a_chars[i - 1], i); + } + + distances[a_len + 1][b_len + 1] +} + +/// Calculates a normalized score of the Damerau–Levenshtein algorithm between +/// 0.0 and 1.0 (inclusive), where 1.0 means the strings are the same. +/// +/// ``` +/// use strsim::normalized_damerau_levenshtein; +/// +/// assert!((normalized_damerau_levenshtein("levenshtein", "löwenbräu") - 0.27272).abs() < 0.00001); +/// assert!((normalized_damerau_levenshtein("", "") - 1.0).abs() < 0.00001); +/// assert!(normalized_damerau_levenshtein("", "flower").abs() < 0.00001); +/// assert!(normalized_damerau_levenshtein("tree", "").abs() < 0.00001); +/// assert!((normalized_damerau_levenshtein("sunglasses", "sunglasses") - 1.0).abs() < 0.00001); +/// ``` +pub fn normalized_damerau_levenshtein(a: &str, b: &str) -> f64 { + if a.is_empty() && b.is_empty() { + return 1.0; + } + 1.0 - (damerau_levenshtein(a, b) as f64) / (a.chars().count().max(b.chars().count()) as f64) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn hamming_empty() { + match hamming("", "") { + Ok(distance) => { assert_eq!(0, distance); }, + Err(why) => { panic!("{:?}", why); } + } + } + + #[test] + fn hamming_same() { + match hamming("hamming", "hamming") { + Ok(distance) => { assert_eq!(0, distance); }, + Err(why) => { panic!("{:?}", why); } + } + } + + #[test] + fn hamming_diff() { + match hamming("hamming", "hammers") { + Ok(distance) => { assert_eq!(3, distance); }, + Err(why) => { panic!("{:?}", why); } + } + } + + #[test] + fn hamming_diff_multibyte() { + match hamming("hamming", "h香mmüng") { + Ok(distance) => { assert_eq!(2, distance); }, + Err(why) => { panic!("{:?}", why); } + } + } + + #[test] + fn hamming_unequal_length() { + match hamming("ham", "hamming") { + Ok(_) => { panic!(); }, + Err(why) => { assert_eq!(why, StrSimError::DifferentLengthArgs); } + } + } + + #[test] + fn hamming_names() { + match hamming("Friedrich Nietzs", "Jean-Paul Sartre") { + Ok(distance) => { assert_eq!(14, distance); }, + Err(why) => { panic!("{:?}", why); } + } + } + + #[test] + fn jaro_both_empty() { + assert_eq!(1.0, jaro("", "")); + } + + #[test] + fn jaro_first_empty() { + assert_eq!(0.0, jaro("", "jaro")); + } + + #[test] + fn jaro_second_empty() { + assert_eq!(0.0, jaro("distance", "")); + } + + #[test] + fn jaro_same() { + assert_eq!(1.0, jaro("jaro", "jaro")); + } + + #[test] + fn jaro_multibyte() { + assert!((0.818 - jaro("testabctest", "testöঙ香test")) < 0.001); + assert!((0.818 - jaro("testöঙ香test", "testabctest")) < 0.001); + } + + #[test] + fn jaro_diff_short() { + assert!((0.767 - jaro("dixon", "dicksonx")).abs() < 0.001); + } + + #[test] + fn jaro_diff_one_character() { + assert_eq!(0.0, jaro("a", "b")); + } + + #[test] + fn jaro_diff_one_and_two() { + assert!((0.83 - jaro("a", "ab")).abs() < 0.01); + } + + #[test] + fn jaro_diff_two_and_one() { + assert!((0.83 - jaro("ab", "a")).abs() < 0.01); + } + + #[test] + fn jaro_diff_no_transposition() { + assert!((0.822 - jaro("dwayne", "duane")).abs() < 0.001); + } + + #[test] + fn jaro_diff_with_transposition() { + assert!((0.944 - jaro("martha", "marhta")).abs() < 0.001); + } + + #[test] + fn jaro_names() { + assert!((0.392 - jaro("Friedrich Nietzsche", + "Jean-Paul Sartre")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_both_empty() { + assert_eq!(1.0, jaro_winkler("", "")); + } + + #[test] + fn jaro_winkler_first_empty() { + assert_eq!(0.0, jaro_winkler("", "jaro-winkler")); + } + + #[test] + fn jaro_winkler_second_empty() { + assert_eq!(0.0, jaro_winkler("distance", "")); + } + + #[test] + fn jaro_winkler_same() { + assert_eq!(1.0, jaro_winkler("Jaro-Winkler", "Jaro-Winkler")); + } + + #[test] + fn jaro_winkler_multibyte() { + assert!((0.89 - jaro_winkler("testabctest", "testöঙ香test")).abs() < + 0.001); + assert!((0.89 - jaro_winkler("testöঙ香test", "testabctest")).abs() < + 0.001); + } + + #[test] + fn jaro_winkler_diff_short() { + assert!((0.813 - jaro_winkler("dixon", "dicksonx")).abs() < 0.001); + assert!((0.813 - jaro_winkler("dicksonx", "dixon")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_diff_one_character() { + assert_eq!(0.0, jaro_winkler("a", "b")); + } + + #[test] + fn jaro_winkler_diff_no_transposition() { + assert!((0.840 - jaro_winkler("dwayne", "duane")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_diff_with_transposition() { + assert!((0.961 - jaro_winkler("martha", "marhta")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_names() { + assert!((0.562 - jaro_winkler("Friedrich Nietzsche", + "Fran-Paul Sartre")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_long_prefix() { + assert!((0.911 - jaro_winkler("cheeseburger", "cheese fries")).abs() < + 0.001); + } + + #[test] + fn jaro_winkler_more_names() { + assert!((0.868 - jaro_winkler("Thorkel", "Thorgier")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_length_of_one() { + assert!((0.738 - jaro_winkler("Dinsdale", "D")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_very_long_prefix() { + assert!((1.0 - jaro_winkler("thequickbrownfoxjumpedoverx", + "thequickbrownfoxjumpedovery")).abs() < + 0.001); + } + + #[test] + fn levenshtein_empty() { + assert_eq!(0, levenshtein("", "")); + } + + #[test] + fn levenshtein_same() { + assert_eq!(0, levenshtein("levenshtein", "levenshtein")); + } + + #[test] + fn levenshtein_diff_short() { + assert_eq!(3, levenshtein("kitten", "sitting")); + } + + #[test] + fn levenshtein_diff_with_space() { + assert_eq!(5, levenshtein("hello, world", "bye, world")); + } + + #[test] + fn levenshtein_diff_multibyte() { + assert_eq!(3, levenshtein("öঙ香", "abc")); + assert_eq!(3, levenshtein("abc", "öঙ香")); + } + + #[test] + fn levenshtein_diff_longer() { + let a = "The quick brown fox jumped over the angry dog."; + let b = "Lorem ipsum dolor sit amet, dicta latine an eam."; + assert_eq!(37, levenshtein(a, b)); + } + + #[test] + fn levenshtein_first_empty() { + assert_eq!(7, levenshtein("", "sitting")); + } + + #[test] + fn levenshtein_second_empty() { + assert_eq!(6, levenshtein("kitten", "")); + } + + #[test] + fn normalized_levenshtein_diff_short() { + assert!((normalized_levenshtein("kitten", "sitting") - 0.57142).abs() < 0.00001); + } + + #[test] + fn normalized_levenshtein_for_empty_strings() { + assert!((normalized_levenshtein("", "") - 1.0).abs() < 0.00001); + } + + #[test] + fn normalized_levenshtein_first_empty() { + assert!(normalized_levenshtein("", "second").abs() < 0.00001); + } + + #[test] + fn normalized_levenshtein_second_empty() { + assert!(normalized_levenshtein("first", "").abs() < 0.00001); + } + + #[test] + fn normalized_levenshtein_identical_strings() { + assert!((normalized_levenshtein("identical", "identical") - 1.0).abs() < 0.00001); + } + + #[test] + fn osa_distance_empty() { + assert_eq!(0, osa_distance("", "")); + } + + #[test] + fn osa_distance_same() { + assert_eq!(0, osa_distance("damerau", "damerau")); + } + + #[test] + fn osa_distance_first_empty() { + assert_eq!(7, osa_distance("", "damerau")); + } + + #[test] + fn osa_distance_second_empty() { + assert_eq!(7, osa_distance("damerau", "")); + } + + #[test] + fn osa_distance_diff() { + assert_eq!(3, osa_distance("ca", "abc")); + } + + #[test] + fn osa_distance_diff_short() { + assert_eq!(3, osa_distance("damerau", "aderua")); + } + + #[test] + fn osa_distance_diff_reversed() { + assert_eq!(3, osa_distance("aderua", "damerau")); + } + + #[test] + fn osa_distance_diff_multibyte() { + assert_eq!(3, osa_distance("öঙ香", "abc")); + assert_eq!(3, osa_distance("abc", "öঙ香")); + } + + #[test] + fn osa_distance_diff_unequal_length() { + assert_eq!(6, osa_distance("damerau", "aderuaxyz")); + } + + #[test] + fn osa_distance_diff_unequal_length_reversed() { + assert_eq!(6, osa_distance("aderuaxyz", "damerau")); + } + + #[test] + fn osa_distance_diff_comedians() { + assert_eq!(5, osa_distance("Stewart", "Colbert")); + } + + #[test] + fn osa_distance_many_transpositions() { + assert_eq!(4, osa_distance("abcdefghijkl", "bacedfgihjlk")); + } + + #[test] + fn osa_distance_diff_longer() { + let a = "The quick brown fox jumped over the angry dog."; + let b = "Lehem ipsum dolor sit amet, dicta latine an eam."; + assert_eq!(36, osa_distance(a, b)); + } + + #[test] + fn osa_distance_beginning_transposition() { + assert_eq!(1, osa_distance("foobar", "ofobar")); + } + + #[test] + fn osa_distance_end_transposition() { + assert_eq!(1, osa_distance("specter", "spectre")); + } + + #[test] + fn osa_distance_restricted_edit() { + assert_eq!(4, osa_distance("a cat", "an abct")); + } + + #[test] + fn damerau_levenshtein_empty() { + assert_eq!(0, damerau_levenshtein("", "")); + } + + #[test] + fn damerau_levenshtein_same() { + assert_eq!(0, damerau_levenshtein("damerau", "damerau")); + } + + #[test] + fn damerau_levenshtein_first_empty() { + assert_eq!(7, damerau_levenshtein("", "damerau")); + } + + #[test] + fn damerau_levenshtein_second_empty() { + assert_eq!(7, damerau_levenshtein("damerau", "")); + } + + #[test] + fn damerau_levenshtein_diff() { + assert_eq!(2, damerau_levenshtein("ca", "abc")); + } + + #[test] + fn damerau_levenshtein_diff_short() { + assert_eq!(3, damerau_levenshtein("damerau", "aderua")); + } + + #[test] + fn damerau_levenshtein_diff_reversed() { + assert_eq!(3, damerau_levenshtein("aderua", "damerau")); + } + + #[test] + fn damerau_levenshtein_diff_multibyte() { + assert_eq!(3, damerau_levenshtein("öঙ香", "abc")); + assert_eq!(3, damerau_levenshtein("abc", "öঙ香")); + } + + #[test] + fn damerau_levenshtein_diff_unequal_length() { + assert_eq!(6, damerau_levenshtein("damerau", "aderuaxyz")); + } + + #[test] + fn damerau_levenshtein_diff_unequal_length_reversed() { + assert_eq!(6, damerau_levenshtein("aderuaxyz", "damerau")); + } + + #[test] + fn damerau_levenshtein_diff_comedians() { + assert_eq!(5, damerau_levenshtein("Stewart", "Colbert")); + } + + #[test] + fn damerau_levenshtein_many_transpositions() { + assert_eq!(4, damerau_levenshtein("abcdefghijkl", "bacedfgihjlk")); + } + + #[test] + fn damerau_levenshtein_diff_longer() { + let a = "The quick brown fox jumped over the angry dog."; + let b = "Lehem ipsum dolor sit amet, dicta latine an eam."; + assert_eq!(36, damerau_levenshtein(a, b)); + } + + #[test] + fn damerau_levenshtein_beginning_transposition() { + assert_eq!(1, damerau_levenshtein("foobar", "ofobar")); + } + + #[test] + fn damerau_levenshtein_end_transposition() { + assert_eq!(1, damerau_levenshtein("specter", "spectre")); + } + + #[test] + fn damerau_levenshtein_unrestricted_edit() { + assert_eq!(3, damerau_levenshtein("a cat", "an abct")); + } + + #[test] + fn normalized_damerau_levenshtein_diff_short() { + assert!((normalized_damerau_levenshtein("levenshtein", "löwenbräu") - 0.27272).abs() < 0.00001); + } + + #[test] + fn normalized_damerau_levenshtein_for_empty_strings() { + assert!((normalized_damerau_levenshtein("", "") - 1.0).abs() < 0.00001); + } + + #[test] + fn normalized_damerau_levenshtein_first_empty() { + assert!(normalized_damerau_levenshtein("", "flower").abs() < 0.00001); + } + + #[test] + fn normalized_damerau_levenshtein_second_empty() { + assert!(normalized_damerau_levenshtein("tree", "").abs() < 0.00001); + } + + #[test] + fn normalized_damerau_levenshtein_identical_strings() { + assert!((normalized_damerau_levenshtein("sunglasses", "sunglasses") - 1.0).abs() < 0.00001); + } +} diff --git a/vendor/strsim-0.8.0/tests/lib.rs b/vendor/strsim-0.8.0/tests/lib.rs new file mode 100644 index 0000000000000..ad7af513aecbf --- /dev/null +++ b/vendor/strsim-0.8.0/tests/lib.rs @@ -0,0 +1,49 @@ +extern crate strsim; + +use strsim::{hamming, levenshtein, normalized_levenshtein, osa_distance,damerau_levenshtein, + normalized_damerau_levenshtein, jaro, jaro_winkler}; + +#[test] +fn hamming_works() { + match hamming("hamming", "hammers") { + Ok(distance) => assert_eq!(3, distance), + Err(why) => panic!("{:?}", why) + } +} + +#[test] +fn levenshtein_works() { + assert_eq!(3, levenshtein("kitten", "sitting")); +} + +#[test] +fn normalized_levenshtein_works() { + assert!((normalized_levenshtein("kitten", "sitting") - 0.57142).abs() < 0.00001); +} + +#[test] +fn osa_distance_works() { + assert_eq!(3, osa_distance("ac", "cba")); +} + +#[test] +fn damerau_levenshtein_works() { + assert_eq!(2, damerau_levenshtein("ac", "cba")); +} + +#[test] +fn normalized_damerau_levenshtein_works() { + assert!((normalized_damerau_levenshtein("levenshtein", "löwenbräu") - 0.27272).abs() < 0.00001); +} + +#[test] +fn jaro_works() { + assert!((0.392 - jaro("Friedrich Nietzsche", "Jean-Paul Sartre")).abs() < + 0.001); +} + +#[test] +fn jaro_winkler_works() { + assert!((0.911 - jaro_winkler("cheeseburger", "cheese fries")).abs() < + 0.001); +} diff --git a/vendor/structopt-derive/.cargo-checksum.json b/vendor/structopt-derive/.cargo-checksum.json new file mode 100644 index 0000000000000..200342f678549 --- /dev/null +++ b/vendor/structopt-derive/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"27a052963c08c0d8766ad156af311032ecac481e35817eea8df757fabb2005ed","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","LICENSE-MIT":"8a44e151af3f22ffe260a07253995300e3600614fba131f0315aa7d9d5c88470","src/attrs.rs":"a9d641a44a0ba980df697423ac63257a634836f256f6ae703e83aa534b7f69aa","src/doc_comments.rs":"1d4c22c986d6628166abdd5a836ee468a4b0e7ac7da1922f84f5ace399695c4d","src/lib.rs":"86b8e97a305f942c6a3b353e72d4e874043368ed2839cde18e8be077fe2a2c4e","src/parse.rs":"10de68d50c1b1db5bfdbbf8137e974a151fcac83a7a26ae7d1d3e9d44589c783","src/spanned.rs":"ac366dc16db728406acdaf1f06efce914e0cb9cec6c20d67eeff519323a367c9","src/ty.rs":"b4c1c12f263b0375f66f195ff6dfce859b11d2237f99d29a491a31eaf351c995"},"package":"dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"} \ No newline at end of file diff --git a/vendor/structopt-derive/Cargo.toml b/vendor/structopt-derive/Cargo.toml new file mode 100644 index 0000000000000..5a9f8b4cb1b6e --- /dev/null +++ b/vendor/structopt-derive/Cargo.toml @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "structopt-derive" +version = "0.4.18" +authors = ["Guillaume Pinot "] +description = "Parse command line argument by defining a struct, derive crate." +documentation = "https://docs.rs/structopt-derive" +keywords = ["clap", "cli", "derive", "docopt"] +categories = ["command-line-interface"] +license = "Apache-2.0/MIT" +repository = "https://github.com/TeXitoi/structopt" + +[lib] +proc-macro = true +[dependencies.heck] +version = "0.3.0" + +[dependencies.proc-macro-error] +version = "1.0.0" + +[dependencies.proc-macro2] +version = "1" + +[dependencies.quote] +version = "1" + +[dependencies.syn] +version = "1" +features = ["full"] + +[features] +paw = [] +[badges.travis-ci] +repository = "TeXitoi/structopt" diff --git a/vendor/structopt-derive/LICENSE-APACHE b/vendor/structopt-derive/LICENSE-APACHE new file mode 100644 index 0000000000000..261eeb9e9f8b2 --- /dev/null +++ b/vendor/structopt-derive/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/structopt-derive/LICENSE-MIT b/vendor/structopt-derive/LICENSE-MIT new file mode 100644 index 0000000000000..e931b83b643f3 --- /dev/null +++ b/vendor/structopt-derive/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Guillaume Pinot (@TeXitoi) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/structopt-derive/src/attrs.rs b/vendor/structopt-derive/src/attrs.rs new file mode 100644 index 0000000000000..35acd5a4db1d4 --- /dev/null +++ b/vendor/structopt-derive/src/attrs.rs @@ -0,0 +1,685 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::doc_comments::process_doc_comment; +use crate::{parse::*, spanned::Sp, ty::Ty}; + +use std::env; + +use heck::{CamelCase, KebabCase, MixedCase, ShoutySnakeCase, SnakeCase}; +use proc_macro2::{Span, TokenStream}; +use proc_macro_error::abort; +use quote::{quote, quote_spanned, ToTokens}; +use syn::{ + self, ext::IdentExt, spanned::Spanned, Attribute, Expr, Ident, LitStr, MetaNameValue, Type, +}; + +#[derive(Clone)] +pub enum Kind { + Arg(Sp), + Subcommand(Sp), + ExternalSubcommand, + Flatten, + Skip(Option), +} + +#[derive(Clone)] +pub struct Method { + name: Ident, + args: TokenStream, +} + +#[derive(Clone)] +pub struct Parser { + pub kind: Sp, + pub func: TokenStream, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum ParserKind { + FromStr, + TryFromStr, + FromOsStr, + TryFromOsStr, + FromOccurrences, + FromFlag, +} + +/// Defines the casing for the attributes long representation. +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum CasingStyle { + /// Indicate word boundaries with uppercase letter, excluding the first word. + Camel, + /// Keep all letters lowercase and indicate word boundaries with hyphens. + Kebab, + /// Indicate word boundaries with uppercase letter, including the first word. + Pascal, + /// Keep all letters uppercase and indicate word boundaries with underscores. + ScreamingSnake, + /// Keep all letters lowercase and indicate word boundaries with underscores. + Snake, + /// Use the original attribute name defined in the code. + Verbatim, + /// Keep all letters lowercase and remove word boundaries. + Lower, + /// Keep all letters uppercase and remove word boundaries. + Upper, +} + +#[derive(Clone)] +pub enum Name { + Derived(Ident), + Assigned(TokenStream), +} + +#[derive(Clone)] +pub struct Attrs { + name: Name, + casing: Sp, + env_casing: Sp, + ty: Option, + doc_comment: Vec, + methods: Vec, + parser: Sp, + author: Option, + about: Option, + version: Option, + no_version: Option, + verbatim_doc_comment: Option, + has_custom_parser: bool, + kind: Sp, +} + +impl Method { + pub fn new(name: Ident, args: TokenStream) -> Self { + Method { name, args } + } + + fn from_lit_or_env(ident: Ident, lit: Option, env_var: &str) -> Self { + let mut lit = match lit { + Some(lit) => lit, + + None => match env::var(env_var) { + Ok(val) => LitStr::new(&val, ident.span()), + Err(_) => { + abort!(ident, + "cannot derive `{}` from Cargo.toml", ident; + note = "`{}` environment variable is not set", env_var; + help = "use `{} = \"...\"` to set {} manually", ident, ident; + ); + } + }, + }; + + if ident == "author" { + let edited = process_author_str(&lit.value()); + lit = LitStr::new(&edited, lit.span()); + } + + Method::new(ident, quote!(#lit)) + } +} + +impl ToTokens for Method { + fn to_tokens(&self, ts: &mut TokenStream) { + let Method { ref name, ref args } = self; + quote!(.#name(#args)).to_tokens(ts); + } +} + +impl Parser { + fn default_spanned(span: Span) -> Sp { + let kind = Sp::new(ParserKind::TryFromStr, span); + let func = quote_spanned!(span=> ::std::str::FromStr::from_str); + Sp::new(Parser { kind, func }, span) + } + + fn from_spec(parse_ident: Ident, spec: ParserSpec) -> Sp { + use ParserKind::*; + + let kind = match &*spec.kind.to_string() { + "from_str" => FromStr, + "try_from_str" => TryFromStr, + "from_os_str" => FromOsStr, + "try_from_os_str" => TryFromOsStr, + "from_occurrences" => FromOccurrences, + "from_flag" => FromFlag, + s => abort!(spec.kind, "unsupported parser `{}`", s), + }; + + let func = match spec.parse_func { + None => match kind { + FromStr | FromOsStr => { + quote_spanned!(spec.kind.span()=> ::std::convert::From::from) + } + TryFromStr => quote_spanned!(spec.kind.span()=> ::std::str::FromStr::from_str), + TryFromOsStr => abort!( + spec.kind, + "you must set parser for `try_from_os_str` explicitly" + ), + FromOccurrences => quote_spanned!(spec.kind.span()=> { |v| v as _ }), + FromFlag => quote_spanned!(spec.kind.span()=> ::std::convert::From::from), + }, + + Some(func) => match func { + syn::Expr::Path(_) => quote!(#func), + _ => abort!(func, "`parse` argument must be a function path"), + }, + }; + + let kind = Sp::new(kind, spec.kind.span()); + let parser = Parser { kind, func }; + Sp::new(parser, parse_ident.span()) + } +} + +impl CasingStyle { + fn from_lit(name: LitStr) -> Sp { + use CasingStyle::*; + + let normalized = name.value().to_camel_case().to_lowercase(); + let cs = |kind| Sp::new(kind, name.span()); + + match normalized.as_ref() { + "camel" | "camelcase" => cs(Camel), + "kebab" | "kebabcase" => cs(Kebab), + "pascal" | "pascalcase" => cs(Pascal), + "screamingsnake" | "screamingsnakecase" => cs(ScreamingSnake), + "snake" | "snakecase" => cs(Snake), + "verbatim" | "verbatimcase" => cs(Verbatim), + "lower" | "lowercase" => cs(Lower), + "upper" | "uppercase" => cs(Upper), + s => abort!(name, "unsupported casing: `{}`", s), + } + } +} + +impl Name { + pub fn translate(self, style: CasingStyle) -> TokenStream { + use CasingStyle::*; + + match self { + Name::Assigned(tokens) => tokens, + Name::Derived(ident) => { + let s = ident.unraw().to_string(); + let s = match style { + Pascal => s.to_camel_case(), + Kebab => s.to_kebab_case(), + Camel => s.to_mixed_case(), + ScreamingSnake => s.to_shouty_snake_case(), + Snake => s.to_snake_case(), + Verbatim => s, + Lower => s.to_snake_case().replace("_", ""), + Upper => s.to_shouty_snake_case().replace("_", ""), + }; + quote_spanned!(ident.span()=> #s) + } + } + } +} + +impl Attrs { + fn new( + default_span: Span, + name: Name, + parent_attrs: Option<&Attrs>, + ty: Option, + casing: Sp, + env_casing: Sp, + ) -> Self { + let no_version = parent_attrs + .as_ref() + .map(|attrs| attrs.no_version.clone()) + .unwrap_or(None); + + Self { + name, + ty, + casing, + env_casing, + doc_comment: vec![], + methods: vec![], + parser: Parser::default_spanned(default_span), + about: None, + author: None, + version: None, + no_version, + verbatim_doc_comment: None, + + has_custom_parser: false, + kind: Sp::new(Kind::Arg(Sp::new(Ty::Other, default_span)), default_span), + } + } + + fn push_method(&mut self, name: Ident, arg: impl ToTokens) { + if name == "name" { + self.name = Name::Assigned(quote!(#arg)); + } else if name == "version" { + self.version = Some(Method::new(name, quote!(#arg))); + } else { + self.methods.push(Method::new(name, quote!(#arg))) + } + } + + fn push_attrs(&mut self, attrs: &[Attribute]) { + use crate::parse::StructOptAttr::*; + + for attr in parse_structopt_attributes(attrs) { + match attr { + Short(ident) | Long(ident) => { + self.push_method(ident, self.name.clone().translate(*self.casing)); + } + + Env(ident) => { + self.push_method(ident, self.name.clone().translate(*self.env_casing)); + } + + Subcommand(ident) => { + let ty = Sp::call_site(Ty::Other); + let kind = Sp::new(Kind::Subcommand(ty), ident.span()); + self.set_kind(kind); + } + + ExternalSubcommand(ident) => { + self.kind = Sp::new(Kind::ExternalSubcommand, ident.span()); + } + + Flatten(ident) => { + let kind = Sp::new(Kind::Flatten, ident.span()); + self.set_kind(kind); + } + + Skip(ident, expr) => { + let kind = Sp::new(Kind::Skip(expr), ident.span()); + self.set_kind(kind); + } + + NoVersion(ident) => self.no_version = Some(ident), + + VerbatimDocComment(ident) => self.verbatim_doc_comment = Some(ident), + + DefaultValue(ident, lit) => { + let val = if let Some(lit) = lit { + quote!(#lit) + } else { + let ty = if let Some(ty) = self.ty.as_ref() { + ty + } else { + abort!( + ident, + "#[structopt(default_value)] (without an argument) can be used \ + only on field level"; + + note = "see \ + https://docs.rs/structopt/0.3.5/structopt/#magical-methods") + }; + + quote_spanned!(ident.span()=> { + ::structopt::lazy_static::lazy_static! { + static ref DEFAULT_VALUE: &'static str = { + let val = <#ty as ::std::default::Default>::default(); + let s = ::std::string::ToString::to_string(&val); + ::std::boxed::Box::leak(s.into_boxed_str()) + }; + } + *DEFAULT_VALUE + }) + }; + + self.methods.push(Method::new(ident, val)); + } + + About(ident, about) => { + self.about = Some(Method::from_lit_or_env( + ident, + about, + "CARGO_PKG_DESCRIPTION", + )); + } + + Author(ident, author) => { + self.author = Some(Method::from_lit_or_env(ident, author, "CARGO_PKG_AUTHORS")); + } + + Version(ident, version) => { + self.push_method(ident, version); + } + + NameLitStr(name, lit) => { + self.push_method(name, lit); + } + + NameExpr(name, expr) => { + self.push_method(name, expr); + } + + MethodCall(name, args) => self.push_method(name, quote!(#(#args),*)), + + RenameAll(_, casing_lit) => { + self.casing = CasingStyle::from_lit(casing_lit); + } + + RenameAllEnv(_, casing_lit) => { + self.env_casing = CasingStyle::from_lit(casing_lit); + } + + Parse(ident, spec) => { + self.has_custom_parser = true; + self.parser = Parser::from_spec(ident, spec); + } + } + } + } + + fn push_doc_comment(&mut self, attrs: &[Attribute], name: &str) { + use crate::Lit::*; + use crate::Meta::*; + + let comment_parts: Vec<_> = attrs + .iter() + .filter(|attr| attr.path.is_ident("doc")) + .filter_map(|attr| { + if let Ok(NameValue(MetaNameValue { lit: Str(s), .. })) = attr.parse_meta() { + Some(s.value()) + } else { + // non #[doc = "..."] attributes are not our concern + // we leave them for rustc to handle + None + } + }) + .collect(); + + self.doc_comment = + process_doc_comment(comment_parts, name, self.verbatim_doc_comment.is_none()); + } + + pub fn from_struct( + span: Span, + attrs: &[Attribute], + name: Name, + parent_attrs: Option<&Attrs>, + argument_casing: Sp, + env_casing: Sp, + allow_skip: bool, + ) -> Self { + let mut res = Self::new(span, name, parent_attrs, None, argument_casing, env_casing); + res.push_attrs(attrs); + res.push_doc_comment(attrs, "about"); + + if res.has_custom_parser { + abort!( + res.parser.span(), + "`parse` attribute is only allowed on fields" + ); + } + match &*res.kind { + Kind::Subcommand(_) => abort!(res.kind.span(), "subcommand is only allowed on fields"), + Kind::Skip(_) if !allow_skip => { + abort!(res.kind.span(), "skip is only allowed on fields") + } + Kind::Arg(_) | Kind::ExternalSubcommand | Kind::Flatten | Kind::Skip(_) => res, + } + } + + pub fn from_field( + field: &syn::Field, + parent_attrs: Option<&Attrs>, + struct_casing: Sp, + env_casing: Sp, + ) -> Self { + let name = field.ident.clone().unwrap(); + let mut res = Self::new( + field.span(), + Name::Derived(name), + parent_attrs, + Some(field.ty.clone()), + struct_casing, + env_casing, + ); + res.push_attrs(&field.attrs); + res.push_doc_comment(&field.attrs, "help"); + + match &*res.kind { + Kind::Flatten => { + if res.has_custom_parser { + abort!( + res.parser.span(), + "parse attribute is not allowed for flattened entry" + ); + } + if res.has_explicit_methods() { + abort!( + res.kind.span(), + "methods are not allowed for flattened entry" + ); + } + + if res.has_doc_methods() { + res.doc_comment = vec![]; + } + } + + Kind::ExternalSubcommand => {} + + Kind::Subcommand(_) => { + if res.has_custom_parser { + abort!( + res.parser.span(), + "parse attribute is not allowed for subcommand" + ); + } + if res.has_explicit_methods() { + abort!( + res.kind.span(), + "methods in attributes are not allowed for subcommand" + ); + } + + let ty = Ty::from_syn_ty(&field.ty); + match *ty { + Ty::OptionOption => { + abort!( + field.ty, + "Option> type is not allowed for subcommand" + ); + } + Ty::OptionVec => { + abort!( + field.ty, + "Option> type is not allowed for subcommand" + ); + } + _ => (), + } + + res.kind = Sp::new(Kind::Subcommand(ty), res.kind.span()); + } + Kind::Skip(_) => { + if res.has_explicit_methods() { + abort!( + res.kind.span(), + "methods are not allowed for skipped fields" + ); + } + } + Kind::Arg(orig_ty) => { + let mut ty = Ty::from_syn_ty(&field.ty); + if res.has_custom_parser { + match *ty { + Ty::Option | Ty::Vec | Ty::OptionVec => (), + _ => ty = Sp::new(Ty::Other, ty.span()), + } + } + + match *ty { + Ty::Bool => { + if res.is_positional() && !res.has_custom_parser { + abort!(field.ty, + "`bool` cannot be used as positional parameter with default parser"; + help = "if you want to create a flag add `long` or `short`"; + help = "If you really want a boolean parameter \ + add an explicit parser, for example `parse(try_from_str)`"; + note = "see also https://github.com/TeXitoi/structopt/tree/master/examples/true_or_false.rs"; + ) + } + if let Some(m) = res.find_method("default_value") { + abort!(m.name, "default_value is meaningless for bool") + } + if let Some(m) = res.find_method("required") { + abort!(m.name, "required is meaningless for bool") + } + } + Ty::Option => { + if let Some(m) = res.find_method("default_value") { + abort!(m.name, "default_value is meaningless for Option") + } + if let Some(m) = res.find_method("required") { + abort!(m.name, "required is meaningless for Option") + } + } + Ty::OptionOption => { + if res.is_positional() { + abort!( + field.ty, + "Option> type is meaningless for positional argument" + ) + } + } + Ty::OptionVec => { + if res.is_positional() { + abort!( + field.ty, + "Option> type is meaningless for positional argument" + ) + } + } + + _ => (), + } + res.kind = Sp::new(Kind::Arg(ty), orig_ty.span()); + } + } + + res + } + + fn set_kind(&mut self, kind: Sp) { + if let Kind::Arg(_) = *self.kind { + self.kind = kind; + } else { + abort!( + kind.span(), + "subcommand, flatten and skip cannot be used together" + ); + } + } + + pub fn has_method(&self, name: &str) -> bool { + self.find_method(name).is_some() + } + + pub fn find_method(&self, name: &str) -> Option<&Method> { + self.methods.iter().find(|m| m.name == name) + } + + /// generate methods from attributes on top of struct or enum + pub fn top_level_methods(&self) -> TokenStream { + let author = &self.author; + let about = &self.about; + let methods = &self.methods; + let doc_comment = &self.doc_comment; + + quote!( #(#doc_comment)* #author #about #(#methods)* ) + } + + /// generate methods on top of a field + pub fn field_methods(&self) -> TokenStream { + let methods = &self.methods; + let doc_comment = &self.doc_comment; + quote!( #(#doc_comment)* #(#methods)* ) + } + + pub fn version(&self) -> TokenStream { + match (&self.no_version, &self.version) { + (None, Some(m)) => m.to_token_stream(), + + (None, None) => std::env::var("CARGO_PKG_VERSION") + .map(|version| quote!( .version(#version) )) + .unwrap_or_default(), + + _ => quote!(), + } + } + + pub fn cased_name(&self) -> TokenStream { + self.name.clone().translate(*self.casing) + } + + pub fn parser(&self) -> &Sp { + &self.parser + } + + pub fn kind(&self) -> Sp { + self.kind.clone() + } + + pub fn casing(&self) -> Sp { + self.casing.clone() + } + + pub fn env_casing(&self) -> Sp { + self.env_casing.clone() + } + + pub fn is_positional(&self) -> bool { + self.methods + .iter() + .all(|m| m.name != "long" && m.name != "short") + } + + pub fn has_explicit_methods(&self) -> bool { + self.methods + .iter() + .any(|m| m.name != "help" && m.name != "long_help") + } + + pub fn has_doc_methods(&self) -> bool { + !self.doc_comment.is_empty() + || self.methods.iter().any(|m| { + m.name == "help" + || m.name == "long_help" + || m.name == "about" + || m.name == "long_about" + }) + } +} + +/// replace all `:` with `, ` when not inside the `<>` +/// +/// `"author1:author2:author3" => "author1, author2, author3"` +/// `"author1 :author2" => "author1 , author2" +fn process_author_str(author: &str) -> String { + let mut res = String::with_capacity(author.len()); + let mut inside_angle_braces = 0usize; + + for ch in author.chars() { + if inside_angle_braces > 0 && ch == '>' { + inside_angle_braces -= 1; + res.push(ch); + } else if ch == '<' { + inside_angle_braces += 1; + res.push(ch); + } else if inside_angle_braces == 0 && ch == ':' { + res.push_str(", "); + } else { + res.push(ch); + } + } + + res +} diff --git a/vendor/structopt-derive/src/doc_comments.rs b/vendor/structopt-derive/src/doc_comments.rs new file mode 100644 index 0000000000000..5592a1a397314 --- /dev/null +++ b/vendor/structopt-derive/src/doc_comments.rs @@ -0,0 +1,103 @@ +//! The preprocessing we apply to doc comments. +//! +//! structopt works in terms of "paragraphs". Paragraph is a sequence of +//! non-empty adjacent lines, delimited by sequences of blank (whitespace only) lines. + +use crate::attrs::Method; +use quote::{format_ident, quote}; +use std::iter; + +pub fn process_doc_comment(lines: Vec, name: &str, preprocess: bool) -> Vec { + // multiline comments (`/** ... */`) may have LFs (`\n`) in them, + // we need to split so we could handle the lines correctly + // + // we also need to remove leading and trailing blank lines + let mut lines: Vec<&str> = lines + .iter() + .skip_while(|s| is_blank(s)) + .flat_map(|s| s.split('\n')) + .collect(); + + while let Some(true) = lines.last().map(|s| is_blank(s)) { + lines.pop(); + } + + // remove one leading space no matter what + for line in lines.iter_mut() { + if line.starts_with(' ') { + *line = &line[1..]; + } + } + + if lines.is_empty() { + return vec![]; + } + + let short_name = format_ident!("{}", name); + let long_name = format_ident!("long_{}", name); + + if let Some(first_blank) = lines.iter().position(|s| is_blank(s)) { + let (short, long) = if preprocess { + let paragraphs = split_paragraphs(&lines); + let short = paragraphs[0].clone(); + let long = paragraphs.join("\n\n"); + (remove_period(short), long) + } else { + let short = lines[..first_blank].join("\n"); + let long = lines.join("\n"); + (short, long) + }; + + vec![ + Method::new(short_name, quote!(#short)), + Method::new(long_name, quote!(#long)), + ] + } else { + let short = if preprocess { + let s = merge_lines(&lines); + remove_period(s) + } else { + lines.join("\n") + }; + + vec![Method::new(short_name, quote!(#short))] + } +} + +fn split_paragraphs(lines: &[&str]) -> Vec { + let mut last_line = 0; + iter::from_fn(|| { + let slice = &lines[last_line..]; + let start = slice.iter().position(|s| !is_blank(s)).unwrap_or(0); + + let slice = &slice[start..]; + let len = slice + .iter() + .position(|s| is_blank(s)) + .unwrap_or_else(|| slice.len()); + + last_line += start + len; + + if len != 0 { + Some(merge_lines(&slice[..len])) + } else { + None + } + }) + .collect() +} + +fn remove_period(mut s: String) -> String { + if s.ends_with('.') && !s.ends_with("..") { + s.pop(); + } + s +} + +fn is_blank(s: &str) -> bool { + s.trim().is_empty() +} + +fn merge_lines(lines: &[&str]) -> String { + lines.iter().map(|s| s.trim()).collect::>().join(" ") +} diff --git a/vendor/structopt-derive/src/lib.rs b/vendor/structopt-derive/src/lib.rs new file mode 100644 index 0000000000000..0838f50458d59 --- /dev/null +++ b/vendor/structopt-derive/src/lib.rs @@ -0,0 +1,1016 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This crate is custom derive for `StructOpt`. It should not be used +//! directly. See [structopt documentation](https://docs.rs/structopt) +//! for the usage of `#[derive(StructOpt)]`. + +#![allow(clippy::large_enum_variant)] +// FIXME: remove when and if our MSRV hits 1.42 +#![allow(clippy::match_like_matches_macro)] +#![forbid(unsafe_code)] + +extern crate proc_macro; + +mod attrs; +mod doc_comments; +mod parse; +mod spanned; +mod ty; + +use crate::{ + attrs::{Attrs, CasingStyle, Kind, Name, ParserKind}, + spanned::Sp, + ty::{is_simple_ty, sub_type, subty_if_name, Ty}, +}; + +use proc_macro2::{Span, TokenStream}; +use proc_macro_error::{abort, abort_call_site, proc_macro_error, set_dummy}; +use quote::{format_ident, quote, quote_spanned}; +use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, *}; + +/// Default casing style for generated arguments. +const DEFAULT_CASING: CasingStyle = CasingStyle::Kebab; + +/// Default casing style for environment variables +const DEFAULT_ENV_CASING: CasingStyle = CasingStyle::ScreamingSnake; + +/// Output for the `gen_xxx()` methods were we need more than a simple stream of tokens. +/// +/// The output of a generation method is not only the stream of new tokens but also the attribute +/// information of the current element. These attribute information may contain valuable information +/// for any kind of child arguments. +struct GenOutput { + tokens: TokenStream, + attrs: Attrs, +} + +/// Generates the `StructOpt` impl. +#[proc_macro_derive(StructOpt, attributes(structopt))] +#[proc_macro_error] +pub fn structopt(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input: DeriveInput = syn::parse(input).unwrap(); + let gen = impl_structopt(&input); + gen.into() +} + +/// Generate a block of code to add arguments/subcommands corresponding to +/// the `fields` to an app. +fn gen_augmentation( + fields: &Punctuated, + app_var: &Ident, + parent_attribute: &Attrs, +) -> TokenStream { + let mut subcmds = fields.iter().filter_map(|field| { + let attrs = Attrs::from_field( + field, + Some(parent_attribute), + parent_attribute.casing(), + parent_attribute.env_casing(), + ); + let kind = attrs.kind(); + if let Kind::Subcommand(ty) = &*kind { + let subcmd_type = match (**ty, sub_type(&field.ty)) { + (Ty::Option, Some(sub_type)) => sub_type, + _ => &field.ty, + }; + let required = if **ty == Ty::Option { + quote!() + } else { + quote_spanned! { kind.span()=> + let #app_var = #app_var.setting( + ::structopt::clap::AppSettings::SubcommandRequiredElseHelp + ); + } + }; + + let span = field.span(); + let ts = quote! { + let #app_var = <#subcmd_type as ::structopt::StructOptInternal>::augment_clap( + #app_var + ); + #required + }; + Some((span, ts)) + } else { + None + } + }); + + let subcmd = subcmds.next().map(|(_, ts)| ts); + if let Some((span, _)) = subcmds.next() { + abort!( + span, + "multiple subcommand sets are not allowed, that's the second" + ); + } + + let args = fields.iter().filter_map(|field| { + let attrs = Attrs::from_field( + field, + Some(parent_attribute), + parent_attribute.casing(), + parent_attribute.env_casing(), + ); + let kind = attrs.kind(); + match &*kind { + Kind::ExternalSubcommand => abort!( + kind.span(), + "`external_subcommand` is only allowed on enum variants" + ), + Kind::Subcommand(_) | Kind::Skip(_) => None, + Kind::Flatten => { + let ty = &field.ty; + Some(quote_spanned! { kind.span()=> + let #app_var = <#ty as ::structopt::StructOptInternal>::augment_clap(#app_var); + let #app_var = if <#ty as ::structopt::StructOptInternal>::is_subcommand() { + #app_var.setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp) + } else { + #app_var + }; + }) + } + Kind::Arg(ty) => { + let convert_type = match **ty { + Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty), + Ty::OptionOption | Ty::OptionVec => { + sub_type(&field.ty).and_then(sub_type).unwrap_or(&field.ty) + } + _ => &field.ty, + }; + + let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences; + let flag = *attrs.parser().kind == ParserKind::FromFlag; + + let parser = attrs.parser(); + let func = &parser.func; + let validator = match *parser.kind { + ParserKind::TryFromStr => quote_spanned! { func.span()=> + .validator(|s| { + #func(s.as_str()) + .map(|_: #convert_type| ()) + .map_err(|e| e.to_string()) + }) + }, + ParserKind::TryFromOsStr => quote_spanned! { func.span()=> + .validator_os(|s| #func(&s).map(|_: #convert_type| ())) + }, + _ => quote!(), + }; + + let modifier = match **ty { + Ty::Bool => quote_spanned! { ty.span()=> + .takes_value(false) + .multiple(false) + }, + + Ty::Option => quote_spanned! { ty.span()=> + .takes_value(true) + .multiple(false) + #validator + }, + + Ty::OptionOption => quote_spanned! { ty.span()=> + .takes_value(true) + .multiple(false) + .min_values(0) + .max_values(1) + #validator + }, + + Ty::OptionVec => quote_spanned! { ty.span()=> + .takes_value(true) + .multiple(true) + .min_values(0) + #validator + }, + + Ty::Vec => quote_spanned! { ty.span()=> + .takes_value(true) + .multiple(true) + #validator + }, + + Ty::Other if occurrences => quote_spanned! { ty.span()=> + .takes_value(false) + .multiple(true) + }, + + Ty::Other if flag => quote_spanned! { ty.span()=> + .takes_value(false) + .multiple(false) + }, + + Ty::Other => { + let required = !attrs.has_method("default_value"); + quote_spanned! { ty.span()=> + .takes_value(true) + .multiple(false) + .required(#required) + #validator + } + } + }; + + let name = attrs.cased_name(); + let methods = attrs.field_methods(); + + Some(quote_spanned! { field.span()=> + let #app_var = #app_var.arg( + ::structopt::clap::Arg::with_name(#name) + #modifier + #methods + ); + }) + } + } + }); + + let app_methods = parent_attribute.top_level_methods(); + let version = parent_attribute.version(); + quote! {{ + let #app_var = #app_var#app_methods; + #( #args )* + #subcmd + #app_var#version + }} +} + +fn gen_constructor(fields: &Punctuated, parent_attribute: &Attrs) -> TokenStream { + // This ident is used in several match branches below, + // and the `quote[_spanned]` invocations have different spans. + // + // Given that this ident is used in several places and + // that the branches are located inside of a loop, it is possible that + // this ident will be given _different_ spans in different places, and + // thus will not be the _same_ ident anymore. To make sure the `matches` + // is always the same, we factor it out. + let matches = format_ident!("matches"); + + let fields = fields.iter().map(|field| { + let attrs = Attrs::from_field( + field, + Some(parent_attribute), + parent_attribute.casing(), + parent_attribute.env_casing(), + ); + let field_name = field.ident.as_ref().unwrap(); + let kind = attrs.kind(); + match &*kind { + Kind::ExternalSubcommand => abort!( + kind.span(), + "`external_subcommand` is allowed only on enum variants" + ), + + Kind::Subcommand(ty) => { + let subcmd_type = match (**ty, sub_type(&field.ty)) { + (Ty::Option, Some(sub_type)) => sub_type, + _ => &field.ty, + }; + let unwrapper = match **ty { + Ty::Option => quote!(), + _ => quote_spanned!( ty.span()=> .unwrap() ), + }; + quote_spanned! { kind.span()=> + #field_name: <#subcmd_type as ::structopt::StructOptInternal>::from_subcommand( + #matches.subcommand()) + #unwrapper + } + } + + Kind::Flatten => quote_spanned! { kind.span()=> + #field_name: ::structopt::StructOpt::from_clap(#matches) + }, + + Kind::Skip(val) => match val { + None => quote_spanned!(kind.span()=> #field_name: Default::default()), + Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()), + }, + + Kind::Arg(ty) => { + use crate::attrs::ParserKind::*; + + let parser = attrs.parser(); + let func = &parser.func; + let span = parser.kind.span(); + let (value_of, values_of, parse) = match *parser.kind { + FromStr => ( + quote_spanned!(span=> value_of), + quote_spanned!(span=> values_of), + func.clone(), + ), + TryFromStr => ( + quote_spanned!(span=> value_of), + quote_spanned!(span=> values_of), + quote_spanned!(func.span()=> |s| #func(s).unwrap()), + ), + FromOsStr => ( + quote_spanned!(span=> value_of_os), + quote_spanned!(span=> values_of_os), + func.clone(), + ), + TryFromOsStr => ( + quote_spanned!(span=> value_of_os), + quote_spanned!(span=> values_of_os), + quote_spanned!(func.span()=> |s| #func(s).unwrap()), + ), + FromOccurrences => ( + quote_spanned!(span=> occurrences_of), + quote!(), + func.clone(), + ), + FromFlag => (quote!(), quote!(), func.clone()), + }; + + let flag = *attrs.parser().kind == ParserKind::FromFlag; + let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences; + let name = attrs.cased_name(); + let convert_type = match **ty { + Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty), + Ty::OptionOption | Ty::OptionVec => { + sub_type(&field.ty).and_then(sub_type).unwrap_or(&field.ty) + } + _ => &field.ty, + }; + let field_value = match **ty { + Ty::Bool => quote_spanned!(ty.span()=> #matches.is_present(#name)), + + Ty::Option => quote_spanned! { ty.span()=> + #matches.#value_of(#name) + .map(#parse) + }, + + Ty::OptionOption => quote_spanned! { ty.span()=> + if #matches.is_present(#name) { + Some(#matches.#value_of(#name).map(#parse)) + } else { + None + } + }, + + Ty::OptionVec => quote_spanned! { ty.span()=> + if #matches.is_present(#name) { + Some(#matches.#values_of(#name) + .map_or_else(Vec::new, |v| v.map::<#convert_type, _>(#parse).collect())) + } else { + None + } + }, + + Ty::Vec => quote_spanned! { ty.span()=> + #matches.#values_of(#name) + .map_or_else(Vec::new, |v| v.map::<#convert_type, _>(#parse).collect()) + }, + + Ty::Other if occurrences => quote_spanned! { ty.span()=> + #parse(#matches.#value_of(#name)) + }, + + Ty::Other if flag => quote_spanned! { ty.span()=> + #parse(#matches.is_present(#name)) + }, + + Ty::Other => quote_spanned! { ty.span()=> + #matches.#value_of(#name) + .map(#parse) + .unwrap() + }, + }; + + quote_spanned!(field.span()=> #field_name: #field_value ) + } + } + }); + + quote! {{ + #( #fields ),* + }} +} + +fn gen_from_clap( + struct_name: &Ident, + fields: &Punctuated, + parent_attribute: &Attrs, +) -> TokenStream { + let field_block = gen_constructor(fields, parent_attribute); + + quote! { + fn from_clap(matches: &::structopt::clap::ArgMatches) -> Self { + #struct_name #field_block + } + } +} + +fn gen_clap(attrs: &[Attribute]) -> GenOutput { + let name = std::env::var("CARGO_PKG_NAME").ok().unwrap_or_default(); + + let attrs = Attrs::from_struct( + Span::call_site(), + attrs, + Name::Assigned(quote!(#name)), + None, + Sp::call_site(DEFAULT_CASING), + Sp::call_site(DEFAULT_ENV_CASING), + false, + ); + let tokens = { + let name = attrs.cased_name(); + quote!(::structopt::clap::App::new(#name)) + }; + + GenOutput { tokens, attrs } +} + +fn gen_clap_struct(struct_attrs: &[Attribute]) -> GenOutput { + let initial_clap_app_gen = gen_clap(struct_attrs); + let clap_tokens = initial_clap_app_gen.tokens; + + let augmented_tokens = quote! { + fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> { + let app = #clap_tokens; + ::augment_clap(app) + } + }; + + GenOutput { + tokens: augmented_tokens, + attrs: initial_clap_app_gen.attrs, + } +} + +fn gen_augment_clap(fields: &Punctuated, parent_attribute: &Attrs) -> TokenStream { + let app_var = Ident::new("app", Span::call_site()); + let augmentation = gen_augmentation(fields, &app_var, parent_attribute); + quote! { + fn augment_clap<'a, 'b>( + #app_var: ::structopt::clap::App<'a, 'b> + ) -> ::structopt::clap::App<'a, 'b> { + #augmentation + } + } +} + +fn gen_clap_enum(enum_attrs: &[Attribute]) -> GenOutput { + let initial_clap_app_gen = gen_clap(enum_attrs); + let clap_tokens = initial_clap_app_gen.tokens; + + let tokens = quote! { + fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> { + let app = #clap_tokens + .setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp); + ::augment_clap(app) + } + }; + + GenOutput { + tokens, + attrs: initial_clap_app_gen.attrs, + } +} + +fn gen_augment_clap_enum( + variants: &Punctuated, + parent_attribute: &Attrs, +) -> TokenStream { + use syn::Fields::*; + + let subcommands = variants.iter().filter_map(|variant| { + let attrs = Attrs::from_struct( + variant.span(), + &variant.attrs, + Name::Derived(variant.ident.clone()), + Some(parent_attribute), + parent_attribute.casing(), + parent_attribute.env_casing(), + true, + ); + + let kind = attrs.kind(); + match &*kind { + Kind::Skip(_) => None, + + Kind::ExternalSubcommand => { + let app_var = Ident::new("app", Span::call_site()); + Some(quote_spanned! { attrs.kind().span()=> + let #app_var = #app_var.setting( + ::structopt::clap::AppSettings::AllowExternalSubcommands + ); + }) + }, + + Kind::Flatten => { + match variant.fields { + Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => { + let ty = &unnamed[0]; + Some(quote! { + let app = <#ty as ::structopt::StructOptInternal>::augment_clap(app); + }) + }, + _ => abort!( + variant, + "`flatten` is usable only with single-typed tuple variants" + ), + } + }, + + _ => { + let app_var = Ident::new("subcommand", Span::call_site()); + let from_attrs = attrs.top_level_methods(); + let version = attrs.version(); + + let arg_block = match variant.fields { + // If the variant is named, then gen_augmentation already generates the + // top level methods (#from_attrs) and version. + Named(ref fields) => gen_augmentation(&fields.named, &app_var, &attrs), + Unit => quote!( #app_var#from_attrs#version ), + Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => { + let ty = &unnamed[0]; + quote_spanned! { ty.span()=> + { + let #app_var = <#ty as ::structopt::StructOptInternal>::augment_clap( + #app_var + ); + if <#ty as ::structopt::StructOptInternal>::is_subcommand() { + #app_var.setting( + ::structopt::clap::AppSettings::SubcommandRequiredElseHelp + ) + } else { + #app_var + }#from_attrs#version + } + } + } + Unnamed(..) => abort!(variant, "non single-typed tuple enums are not supported"), + }; + + let name = attrs.cased_name(); + Some(quote! { + let app = app.subcommand({ + let #app_var = ::structopt::clap::SubCommand::with_name(#name); + #arg_block + }); + }) + }, + } + }); + + let app_methods = parent_attribute.top_level_methods(); + let version = parent_attribute.version(); + quote! { + fn augment_clap<'a, 'b>( + app: ::structopt::clap::App<'a, 'b> + ) -> ::structopt::clap::App<'a, 'b> { + let app = app #app_methods; + #( #subcommands )*; + app #version + } + } +} + +fn gen_from_clap_enum() -> TokenStream { + quote! { + fn from_clap(matches: &::structopt::clap::ArgMatches) -> Self { + ::from_subcommand(matches.subcommand()) + .expect("structopt misuse: You likely tried to #[flatten] a struct \ + that contains #[subcommand]. This is forbidden.") + } + } +} + +fn gen_from_subcommand( + name: &Ident, + variants: &Punctuated, + parent_attribute: &Attrs, +) -> TokenStream { + use syn::Fields::*; + + let mut ext_subcmd = None; + + let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants + .iter() + .filter_map(|variant| { + let attrs = Attrs::from_struct( + variant.span(), + &variant.attrs, + Name::Derived(variant.ident.clone()), + Some(parent_attribute), + parent_attribute.casing(), + parent_attribute.env_casing(), + true, + ); + + let variant_name = &variant.ident; + + match *attrs.kind() { + Kind::ExternalSubcommand => { + if ext_subcmd.is_some() { + abort!( + attrs.kind().span(), + "Only one variant can be marked with `external_subcommand`, \ + this is the second" + ); + } + + let ty = match variant.fields { + Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty, + + _ => abort!( + variant, + "The enum variant marked with `external_attribute` must be \ + a single-typed tuple, and the type must be either `Vec` \ + or `Vec`." + ), + }; + + let (span, str_ty, values_of) = match subty_if_name(ty, "Vec") { + Some(subty) => { + if is_simple_ty(subty, "String") { + ( + subty.span(), + quote!(::std::string::String), + quote!(values_of), + ) + } else { + ( + subty.span(), + quote!(::std::ffi::OsString), + quote!(values_of_os), + ) + } + } + + None => abort!( + ty, + "The type must be either `Vec` or `Vec` \ + to be used with `external_subcommand`." + ), + }; + + ext_subcmd = Some((span, variant_name, str_ty, values_of)); + None + } + Kind::Skip(_) => None, + _ => Some((variant, attrs)), + } + }) + .partition(|(_, attrs)| match &*attrs.kind() { + Kind::Flatten => true, + _ => false, + }); + + let other = format_ident!("other"); + let matches = format_ident!("matches"); + + let external = match ext_subcmd { + Some((span, var_name, str_ty, values_of)) => quote_spanned! { span=> + match #other { + ("", ::std::option::Option::None) => None, + + (external, Some(#matches)) => { + ::std::option::Option::Some(#name::#var_name( + ::std::iter::once(#str_ty::from(external)) + .chain( + #matches.#values_of("").into_iter().flatten().map(#str_ty::from) + ) + .collect::<::std::vec::Vec<_>>() + )) + } + + (external, None) => { + ::std::option::Option::Some(#name::#var_name( + ::std::iter::once(#str_ty::from(external)) + .collect::<::std::vec::Vec<_>>() + )) + } + } + }, + + None => quote!(None), + }; + + let match_arms = variants.iter().map(|(variant, attrs)| { + let sub_name = attrs.cased_name(); + let variant_name = &variant.ident; + let constructor_block = match variant.fields { + Named(ref fields) => gen_constructor(&fields.named, &attrs), + Unit => quote!(), + Unnamed(ref fields) if fields.unnamed.len() == 1 => { + let ty = &fields.unnamed[0]; + quote!( ( <#ty as ::structopt::StructOpt>::from_clap(#matches) ) ) + } + Unnamed(..) => abort!( + variant.ident, + "non single-typed tuple enums are not supported" + ), + }; + + quote! { + (#sub_name, Some(#matches)) => { + Some(#name :: #variant_name #constructor_block) + } + } + }); + + let child_subcommands = flatten_variants.iter().map(|(variant, _attrs)| { + let variant_name = &variant.ident; + match variant.fields { + Unnamed(ref fields) if fields.unnamed.len() == 1 => { + let ty = &fields.unnamed[0]; + quote! { + if let Some(res) = + <#ty as ::structopt::StructOptInternal>::from_subcommand(#other) + { + return Some(#name :: #variant_name (res)); + } + } + } + _ => abort!( + variant, + "`flatten` is usable only with single-typed tuple variants" + ), + } + }); + + quote! { + fn from_subcommand<'a, 'b>( + sub: (&'b str, Option<&'b ::structopt::clap::ArgMatches<'a>>) + ) -> Option { + match sub { + #( #match_arms, )* + #other => { + #( #child_subcommands )else*; + #external + } + } + } + } +} + +#[cfg(feature = "paw")] +fn gen_paw_impl( + impl_generics: &ImplGenerics, + name: &Ident, + ty_generics: &TypeGenerics, + where_clause: &TokenStream, +) -> TokenStream { + quote! { + impl #impl_generics ::structopt::paw::ParseArgs for #name #ty_generics #where_clause { + type Error = std::io::Error; + + fn parse_args() -> std::result::Result { + Ok(<#name as ::structopt::StructOpt>::from_args()) + } + } + } +} +#[cfg(not(feature = "paw"))] +fn gen_paw_impl(_: &ImplGenerics, _: &Ident, _: &TypeGenerics, _: &TokenStream) -> TokenStream { + TokenStream::new() +} + +fn split_structopt_generics_for_impl( + generics: &Generics, +) -> (ImplGenerics, TypeGenerics, TokenStream) { + use syn::{token::Add, TypeParamBound::Trait}; + + fn path_ends_with(path: &Path, ident: &str) -> bool { + path.segments.last().unwrap().ident == ident + } + + fn type_param_bounds_contains(bounds: &Punctuated, ident: &str) -> bool { + for bound in bounds { + if let Trait(bound) = bound { + if path_ends_with(&bound.path, ident) { + return true; + } + } + } + return false; + } + + struct TraitBoundAmendments { + tokens: TokenStream, + need_where: bool, + need_comma: bool, + } + + impl TraitBoundAmendments { + fn new(where_clause: Option<&WhereClause>) -> Self { + let tokens = TokenStream::new(); + let (need_where, need_comma) = if let Some(where_clause) = where_clause { + if where_clause.predicates.trailing_punct() { + (false, false) + } else { + (false, true) + } + } else { + (true, false) + }; + Self { + tokens, + need_where, + need_comma, + } + } + + fn add(&mut self, amendment: TokenStream) { + if self.need_where { + self.tokens.extend(quote! { where }); + self.need_where = false; + } + if self.need_comma { + self.tokens.extend(quote! { , }); + } + self.tokens.extend(amendment); + self.need_comma = true; + } + + fn into_tokens(self) -> TokenStream { + self.tokens + } + } + + let mut trait_bound_amendments = TraitBoundAmendments::new(generics.where_clause.as_ref()); + + for param in &generics.params { + if let GenericParam::Type(param) = param { + let param_ident = ¶m.ident; + if type_param_bounds_contains(¶m.bounds, "StructOpt") { + trait_bound_amendments + .add(quote! { #param_ident : ::structopt::StructOptInternal }); + } + } + } + + if let Some(where_clause) = &generics.where_clause { + for predicate in &where_clause.predicates { + if let WherePredicate::Type(predicate) = predicate { + let predicate_bounded_ty = &predicate.bounded_ty; + if type_param_bounds_contains(&predicate.bounds, "StructOpt") { + trait_bound_amendments + .add(quote! { #predicate_bounded_ty : ::structopt::StructOptInternal }); + } + } + } + } + + let trait_bound_amendments = trait_bound_amendments.into_tokens(); + + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let where_clause = quote! { #where_clause #trait_bound_amendments }; + + (impl_generics, ty_generics, where_clause) +} + +fn impl_structopt_for_struct( + name: &Ident, + fields: &Punctuated, + attrs: &[Attribute], + generics: &Generics, +) -> TokenStream { + let (impl_generics, ty_generics, where_clause) = split_structopt_generics_for_impl(&generics); + + let basic_clap_app_gen = gen_clap_struct(attrs); + let augment_clap = gen_augment_clap(fields, &basic_clap_app_gen.attrs); + let from_clap = gen_from_clap(name, fields, &basic_clap_app_gen.attrs); + let paw_impl = gen_paw_impl(&impl_generics, name, &ty_generics, &where_clause); + + let clap_tokens = basic_clap_app_gen.tokens; + quote! { + #[allow(unused_variables)] + #[allow(unknown_lints)] + #[allow( + clippy::style, + clippy::complexity, + clippy::pedantic, + clippy::restriction, + clippy::perf, + clippy::deprecated, + clippy::nursery, + clippy::cargo + )] + #[deny(clippy::correctness)] + #[allow(dead_code, unreachable_code)] + impl #impl_generics ::structopt::StructOpt for #name #ty_generics #where_clause { + #clap_tokens + #from_clap + } + + #[allow(unused_variables)] + #[allow(unknown_lints)] + #[allow( + clippy::style, + clippy::complexity, + clippy::pedantic, + clippy::restriction, + clippy::perf, + clippy::deprecated, + clippy::nursery, + clippy::cargo + )] + #[deny(clippy::correctness)] + #[allow(dead_code, unreachable_code)] + impl #impl_generics ::structopt::StructOptInternal for #name #ty_generics #where_clause { + #augment_clap + fn is_subcommand() -> bool { false } + } + + #paw_impl + } +} + +fn impl_structopt_for_enum( + name: &Ident, + variants: &Punctuated, + attrs: &[Attribute], + generics: &Generics, +) -> TokenStream { + let (impl_generics, ty_generics, where_clause) = split_structopt_generics_for_impl(&generics); + + let basic_clap_app_gen = gen_clap_enum(attrs); + let clap_tokens = basic_clap_app_gen.tokens; + let attrs = basic_clap_app_gen.attrs; + + let augment_clap = gen_augment_clap_enum(variants, &attrs); + let from_clap = gen_from_clap_enum(); + let from_subcommand = gen_from_subcommand(name, variants, &attrs); + let paw_impl = gen_paw_impl(&impl_generics, name, &ty_generics, &where_clause); + + quote! { + #[allow(unknown_lints)] + #[allow(unused_variables, dead_code, unreachable_code)] + #[allow( + clippy::style, + clippy::complexity, + clippy::pedantic, + clippy::restriction, + clippy::perf, + clippy::deprecated, + clippy::nursery, + clippy::cargo + )] + #[deny(clippy::correctness)] + impl #impl_generics ::structopt::StructOpt for #name #ty_generics #where_clause { + #clap_tokens + #from_clap + } + + #[allow(unused_variables)] + #[allow(unknown_lints)] + #[allow( + clippy::style, + clippy::complexity, + clippy::pedantic, + clippy::restriction, + clippy::perf, + clippy::deprecated, + clippy::nursery, + clippy::cargo + )] + #[deny(clippy::correctness)] + #[allow(dead_code, unreachable_code)] + impl #impl_generics ::structopt::StructOptInternal for #name #ty_generics #where_clause { + #augment_clap + #from_subcommand + fn is_subcommand() -> bool { true } + } + + #paw_impl + } +} + +fn impl_structopt(input: &DeriveInput) -> TokenStream { + use syn::Data::*; + + let struct_name = &input.ident; + + set_dummy(quote! { + impl ::structopt::StructOpt for #struct_name { + fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> { + unimplemented!() + } + fn from_clap(_matches: &::structopt::clap::ArgMatches) -> Self { + unimplemented!() + } + } + + impl ::structopt::StructOptInternal for #struct_name {} + }); + + match input.data { + Struct(DataStruct { + fields: syn::Fields::Named(ref fields), + .. + }) => impl_structopt_for_struct(struct_name, &fields.named, &input.attrs, &input.generics), + Enum(ref e) => { + impl_structopt_for_enum(struct_name, &e.variants, &input.attrs, &input.generics) + } + _ => abort_call_site!("structopt only supports non-tuple structs and enums"), + } +} diff --git a/vendor/structopt-derive/src/parse.rs b/vendor/structopt-derive/src/parse.rs new file mode 100644 index 0000000000000..11511a157b176 --- /dev/null +++ b/vendor/structopt-derive/src/parse.rs @@ -0,0 +1,272 @@ +use std::iter::FromIterator; + +use proc_macro_error::{abort, ResultExt}; +use quote::ToTokens; +use syn::{ + self, parenthesized, + parse::{Parse, ParseBuffer, ParseStream}, + punctuated::Punctuated, + Attribute, Expr, ExprLit, Ident, Lit, LitBool, LitStr, Token, +}; + +pub enum StructOptAttr { + // single-identifier attributes + Short(Ident), + Long(Ident), + Env(Ident), + Flatten(Ident), + Subcommand(Ident), + ExternalSubcommand(Ident), + NoVersion(Ident), + VerbatimDocComment(Ident), + + // ident [= "string literal"] + About(Ident, Option), + Author(Ident, Option), + DefaultValue(Ident, Option), + + // ident = "string literal" + Version(Ident, LitStr), + RenameAllEnv(Ident, LitStr), + RenameAll(Ident, LitStr), + NameLitStr(Ident, LitStr), + + // parse(parser_kind [= parser_func]) + Parse(Ident, ParserSpec), + + // ident [= arbitrary_expr] + Skip(Ident, Option), + + // ident = arbitrary_expr + NameExpr(Ident, Expr), + + // ident(arbitrary_expr,*) + MethodCall(Ident, Vec), +} + +impl Parse for StructOptAttr { + fn parse(input: ParseStream<'_>) -> syn::Result { + use self::StructOptAttr::*; + + let name: Ident = input.parse()?; + let name_str = name.to_string(); + + if input.peek(Token![=]) { + // `name = value` attributes. + let assign_token = input.parse::()?; // skip '=' + + if input.peek(LitStr) { + let lit: LitStr = input.parse()?; + let lit_str = lit.value(); + + let check_empty_lit = |s| { + if lit_str.is_empty() { + abort!( + lit, + "`#[structopt({} = \"\")]` is deprecated in structopt 0.3, \ + now it's default behavior", + s + ); + } + }; + + match &*name_str { + "rename_all" => Ok(RenameAll(name, lit)), + "rename_all_env" => Ok(RenameAllEnv(name, lit)), + "default_value" => Ok(DefaultValue(name, Some(lit))), + + "version" => { + check_empty_lit("version"); + Ok(Version(name, lit)) + } + + "author" => { + check_empty_lit("author"); + Ok(Author(name, Some(lit))) + } + + "about" => { + check_empty_lit("about"); + Ok(About(name, Some(lit))) + } + + "skip" => { + let expr = ExprLit { + attrs: vec![], + lit: Lit::Str(lit), + }; + let expr = Expr::Lit(expr); + Ok(Skip(name, Some(expr))) + } + + _ => Ok(NameLitStr(name, lit)), + } + } else { + match input.parse::() { + Ok(expr) => { + if name_str == "skip" { + Ok(Skip(name, Some(expr))) + } else { + Ok(NameExpr(name, expr)) + } + } + + Err(_) => abort! { + assign_token, + "expected `string literal` or `expression` after `=`" + }, + } + } + } else if input.peek(syn::token::Paren) { + // `name(...)` attributes. + let nested; + parenthesized!(nested in input); + + match name_str.as_ref() { + "parse" => { + let parser_specs: Punctuated = + nested.parse_terminated(ParserSpec::parse)?; + + if parser_specs.len() == 1 { + Ok(Parse(name, parser_specs[0].clone())) + } else { + abort!(name, "`parse` must have exactly one argument") + } + } + + "raw" => match nested.parse::() { + Ok(bool_token) => { + let expr = ExprLit { + attrs: vec![], + lit: Lit::Bool(bool_token), + }; + let expr = Expr::Lit(expr); + Ok(MethodCall(name, vec![expr])) + } + + Err(_) => { + abort!(name, + "`#[structopt(raw(...))` attributes are removed in structopt 0.3, \ + they are replaced with raw methods"; + help = "if you meant to call `clap::Arg::raw()` method \ + you should use bool literal, like `raw(true)` or `raw(false)`"; + note = raw_method_suggestion(nested); + ); + } + }, + + _ => { + let method_args: Punctuated<_, Token![,]> = + nested.parse_terminated(Expr::parse)?; + Ok(MethodCall(name, Vec::from_iter(method_args))) + } + } + } else { + // Attributes represented with a sole identifier. + match name_str.as_ref() { + "long" => Ok(Long(name)), + "short" => Ok(Short(name)), + "env" => Ok(Env(name)), + "flatten" => Ok(Flatten(name)), + "subcommand" => Ok(Subcommand(name)), + "external_subcommand" => Ok(ExternalSubcommand(name)), + "no_version" => Ok(NoVersion(name)), + "verbatim_doc_comment" => Ok(VerbatimDocComment(name)), + + "default_value" => Ok(DefaultValue(name, None)), + "about" => (Ok(About(name, None))), + "author" => (Ok(Author(name, None))), + + "skip" => Ok(Skip(name, None)), + + "version" => abort!( + name, + "#[structopt(version)] is invalid attribute, \ + structopt 0.3 inherits version from Cargo.toml by default, \ + no attribute needed" + ), + + _ => abort!(name, "unexpected attribute: {}", name_str), + } + } + } +} + +#[derive(Clone)] +pub struct ParserSpec { + pub kind: Ident, + pub eq_token: Option, + pub parse_func: Option, +} + +impl Parse for ParserSpec { + fn parse(input: ParseStream<'_>) -> syn::Result { + let kind = input + .parse() + .map_err(|_| input.error("parser specification must start with identifier"))?; + let eq_token = input.parse()?; + let parse_func = match eq_token { + None => None, + Some(_) => Some(input.parse()?), + }; + Ok(ParserSpec { + kind, + eq_token, + parse_func, + }) + } +} + +fn raw_method_suggestion(ts: ParseBuffer) -> String { + let do_parse = move || -> Result<(Ident, Punctuated), syn::Error> { + let name = ts.parse()?; + let _eq: Token![=] = ts.parse()?; + let val: LitStr = ts.parse()?; + let exprs = val.parse_with(Punctuated::::parse_terminated)?; + Ok((name, exprs)) + }; + + fn to_string(val: &T) -> String { + val.to_token_stream() + .to_string() + .replace(" ", "") + .replace(",", ", ") + } + + if let Ok((name, exprs)) = do_parse() { + let suggestion = if exprs.len() == 1 { + let val = to_string(&exprs[0]); + format!(" = {}", val) + } else { + let val = exprs + .into_iter() + .map(|expr| to_string(&expr)) + .collect::>() + .join(", "); + + format!("({})", val) + }; + + format!( + "if you need to call `clap::Arg/App::{}` method you \ + can do it like this: #[structopt({}{})]", + name, name, suggestion + ) + } else { + "if you need to call some method from `clap::Arg/App` \ + you should use raw method, see \ + https://docs.rs/structopt/0.3/structopt/#raw-methods" + .into() + } +} + +pub fn parse_structopt_attributes(all_attrs: &[Attribute]) -> Vec { + all_attrs + .iter() + .filter(|attr| attr.path.is_ident("structopt")) + .flat_map(|attr| { + attr.parse_args_with(Punctuated::::parse_terminated) + .unwrap_or_abort() + }) + .collect() +} diff --git a/vendor/structopt-derive/src/spanned.rs b/vendor/structopt-derive/src/spanned.rs new file mode 100644 index 0000000000000..1c02a8256401a --- /dev/null +++ b/vendor/structopt-derive/src/spanned.rs @@ -0,0 +1,97 @@ +use proc_macro2::{Ident, Span, TokenStream}; +use quote::ToTokens; +use std::ops::{Deref, DerefMut}; +use syn::LitStr; + +/// An entity with a span attached. +#[derive(Debug, Clone)] +pub struct Sp { + span: Span, + val: T, +} + +impl Sp { + pub fn new(val: T, span: Span) -> Self { + Sp { val, span } + } + + pub fn call_site(val: T) -> Self { + Sp { + val, + span: Span::call_site(), + } + } + + pub fn span(&self) -> Span { + self.span + } +} + +impl Deref for Sp { + type Target = T; + + fn deref(&self) -> &T { + &self.val + } +} + +impl DerefMut for Sp { + fn deref_mut(&mut self) -> &mut T { + &mut self.val + } +} + +impl From for Sp { + fn from(ident: Ident) -> Self { + Sp { + val: ident.to_string(), + span: ident.span(), + } + } +} + +impl From for Sp { + fn from(lit: LitStr) -> Self { + Sp { + val: lit.value(), + span: lit.span(), + } + } +} + +impl<'a> From> for Sp { + fn from(sp: Sp<&'a str>) -> Self { + Sp::new(sp.val.into(), sp.span) + } +} + +impl PartialEq for Sp { + fn eq(&self, other: &T) -> bool { + self.val == *other + } +} + +impl PartialEq for Sp { + fn eq(&self, other: &Sp) -> bool { + self.val == **other + } +} + +impl> AsRef for Sp { + fn as_ref(&self) -> &str { + self.val.as_ref() + } +} + +impl ToTokens for Sp { + fn to_tokens(&self, stream: &mut TokenStream) { + // this is the simplest way out of correct ones to change span on + // arbitrary token tree I can come up with + let tt = self.val.to_token_stream().into_iter().map(|mut tt| { + tt.set_span(self.span); + tt + }); + + stream.extend(tt); + } +} diff --git a/vendor/structopt-derive/src/ty.rs b/vendor/structopt-derive/src/ty.rs new file mode 100644 index 0000000000000..ad3acd9d50306 --- /dev/null +++ b/vendor/structopt-derive/src/ty.rs @@ -0,0 +1,129 @@ +//! Special types handling + +use crate::spanned::Sp; + +use syn::{ + spanned::Spanned, GenericArgument, Path, PathArguments, PathArguments::AngleBracketed, + PathSegment, Type, TypePath, +}; + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum Ty { + Bool, + Vec, + Option, + OptionOption, + OptionVec, + Other, +} + +impl Ty { + pub fn from_syn_ty(ty: &syn::Type) -> Sp { + use Ty::*; + let t = |kind| Sp::new(kind, ty.span()); + + if is_simple_ty(ty, "bool") { + t(Bool) + } else if is_generic_ty(ty, "Vec") { + t(Vec) + } else if let Some(subty) = subty_if_name(ty, "Option") { + if is_generic_ty(subty, "Option") { + t(OptionOption) + } else if is_generic_ty(subty, "Vec") { + t(OptionVec) + } else { + t(Option) + } + } else { + t(Other) + } + } +} + +pub fn sub_type(ty: &syn::Type) -> Option<&syn::Type> { + subty_if(ty, |_| true) +} + +fn only_last_segment(ty: &syn::Type) -> Option<&PathSegment> { + match ty { + Type::Path(TypePath { + qself: None, + path: + Path { + leading_colon: None, + segments, + }, + }) => only_one(segments.iter()), + + _ => None, + } +} + +fn subty_if(ty: &syn::Type, f: F) -> Option<&syn::Type> +where + F: FnOnce(&PathSegment) -> bool, +{ + let ty = strip_group(ty); + + only_last_segment(ty) + .filter(|segment| f(segment)) + .and_then(|segment| { + if let AngleBracketed(args) = &segment.arguments { + only_one(args.args.iter()).and_then(|genneric| { + if let GenericArgument::Type(ty) = genneric { + Some(ty) + } else { + None + } + }) + } else { + None + } + }) +} + +pub fn subty_if_name<'a>(ty: &'a syn::Type, name: &str) -> Option<&'a syn::Type> { + subty_if(ty, |seg| seg.ident == name) +} + +pub fn is_simple_ty(ty: &syn::Type, name: &str) -> bool { + let ty = strip_group(ty); + + only_last_segment(ty) + .map(|segment| { + if let PathArguments::None = segment.arguments { + segment.ident == name + } else { + false + } + }) + .unwrap_or(false) +} + +// If the struct is placed inside of a macro_rules! declaration, +// in some circumstances, the tokens inside will be enclosed +// in `proc_macro::Group` delimited by invisible `proc_macro::Delimiter::None`. +// +// In syn speak, this is encoded via `*::Group` variants. We don't really care about +// that, so let's just strip it. +// +// Details: https://doc.rust-lang.org/proc_macro/enum.Delimiter.html#variant.None +// See also: https://github.com/TeXitoi/structopt/issues/439 +fn strip_group(mut ty: &syn::Type) -> &syn::Type { + while let Type::Group(group) = ty { + ty = &*group.elem; + } + + ty +} + +fn is_generic_ty(ty: &syn::Type, name: &str) -> bool { + subty_if_name(ty, name).is_some() +} + +fn only_one(mut iter: I) -> Option +where + I: Iterator, +{ + iter.next().filter(|_| iter.next().is_none()) +} diff --git a/vendor/structopt/.cargo-checksum.json b/vendor/structopt/.cargo-checksum.json new file mode 100644 index 0000000000000..01ae9c63085dd --- /dev/null +++ b/vendor/structopt/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"72a20566c555f047803f0657fc011e7696b655021af0659e849193229ed49e82","Cargo.lock":"0d60f09ad3d603988cec8e7327c3149c58d435e13ece42aef72d45afe5194813","Cargo.toml":"9660dddc58a3ec65379e4a62f2cad678d48700f101bfd6a8b71d8ef28354db67","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","LICENSE-MIT":"8a44e151af3f22ffe260a07253995300e3600614fba131f0315aa7d9d5c88470","README.md":"7c0e9e91191ae990bb39d6a2115d1f421f0765a882ce6645edb8f180401c0e85","examples/README.md":"80708f803f579b048980df4d3732882089b14ac350479bc2ae794635f379d2d2","examples/after_help.rs":"4b23f8e6d69d32450c68e8703a9e76781ac20ab701afe0445ebcdcf69aa0c67a","examples/at_least_two.rs":"4271b3fca3d487fb84ac7df50b2b629cdb8a5342479865545e3f682fd75a79c9","examples/basic.rs":"3b213ff079c8f543d70ecafff3c160c306c12fa3e0d2166ca7c0103b92de8207","examples/deny_missing_docs.rs":"257eb5a60831224a7e455a28e456227f3b47a2cf6bbb7d202d75743f44626be8","examples/doc_comments.rs":"f00096c7910d6943f29f512ae2ebc938943b3fd38745449dd94d975edb266d57","examples/enum_in_args.rs":"6a3593c71f097a53bbd58c9f6c49b6e866e4564cd79792d2ab8eb0ad6dbdd212","examples/enum_in_args_with_strum.rs":"2b240f02f592bacd89e5c65bb1ee27243c1842c92721de20376d22fd4a5c51f1","examples/enum_tuple.rs":"347a3e4a48a59d1c458bd48691279defcc9dcee695aea8a46760e2e52b83ddb6","examples/env.rs":"49793fd8425c95031b01eea5b1f6c2cb548afb9c9d2eecc78a7a4dc7c2f067f7","examples/example.rs":"96e7e1973deb541f5c767f1eed13b4f08b97ee12177f61932e45c015596f8f47","examples/flatten.rs":"4bad71d3f2841b861fbacf61fcc26c81bf9619294e57e988677991d844c3ead3","examples/gen_completions.rs":"a44ee513c0fea41c419c90c7ab851dd4ed69dc8b84b2d50ad5a8ea708972da2c","examples/git.rs":"ac56c31032631ba994ab1a32fe296dfc74b1c9530bf71fdab59fee59e7296f23","examples/group.rs":"5a951c45f98eabb289e4de01f130e828b089cb10dac2cfa6a71a0ed488faa588","examples/keyvalue.rs":"1a68126ab1e8ae967f172cbd71bab45122531a332615443b0c73de7b7f5a9c31","examples/negative_flag.rs":"bcfef399a75ee89ef9735553ba5b97c6ce412e39333bd71e59b6b22e98a62ddf","examples/no_version.rs":"4d8eb5963bbabb5dbcfd8e1f7a942c0434c935f344d146186e0db5fecb617a85","examples/rename_all.rs":"d536ab3e164c9327814a87036ff037cf66f34e1a9e301f14c1026cf0c3b3ef18","examples/required_if.rs":"b3ccf1a2846bca8ba2ade86250f2889e9eae7bae7db402892465a5e1e7cec7e4","examples/skip.rs":"279455bbbe2cdb33e25756798961e71b5c45c76118e65029ffed18cbcbcf0ddc","examples/subcommand_aliases.rs":"0372847121f28b592c440652727d1eac974a586b049a65b136170d132c183374","examples/true_or_false.rs":"f5375953fcfe1f8422101eb0e0237618bb40232295129e8a7ade25b8de3e8ca5","link-check-headers.json":"7a42ba4bcdf67b331fcdf5f61e50040deace7678b02d41297cfdc3dd68d22ec8","src/lib.rs":"008661b26fb34499d37d3be8f79615163d938b153742964bf56a5b978f350613","tests/argument_naming.rs":"0e5d0c340b5a7c76abf0fe52546b1cbdd1c149ed04ee035654c966db0d006df9","tests/arguments.rs":"159cbc9e5c3ef9fe546470639e2d1854b6fadf18424aa7b8a7114616a4d179ba","tests/author_version_about.rs":"0daff920b8a43b365334c6f67f00e55054df1a1e5c8461ce32c04b68105ae10f","tests/custom-string-parsers.rs":"e93c4358aaee82668ae70886fbcd802fcad991b46b6dec6e2b0421d49d4c932e","tests/default_value.rs":"f755d7761d20b5617cb53e13da6ed90c23496460f02d4a753dce310130348cb2","tests/deny-warnings.rs":"ca47a45a6ae65e15eb6f39feb04d23c0dd6f08c328f1ece5f3cae62326e1343b","tests/doc-comments-help.rs":"d95b29695c86cc421ec0aa2c14109f3cd1be6b697a758d30f4fab3c30c80ab53","tests/explicit_name_no_renaming.rs":"bcd86fcf9fa3ef5af81aaa15b904da4e1ff385f3820ce9f70ad65e4b4bdf8988","tests/flags.rs":"5260622c155665f5d21399d145b889d5cf7b7573be7c866a587b1bee3d1d1711","tests/flatten.rs":"706e45f543cf65d3fcbb03505de42c4258751427ddf0dedb189ba7f143284c48","tests/generics.rs":"efc5df250b6a7d7153f5631759a361dbd0056dc2ed222e4c345b05df7032feb9","tests/issues.rs":"11c613e11b31793dab1fb1fe4071b1980fcb0e22542fc0b7e356727a26b78c9b","tests/macro-errors.rs":"141f0632b4418df60faeaf0718821142e9f27e28b66386a1ed193bfc70a28793","tests/nested-subcommands.rs":"6e958296bec2570e676c74666c503e72f65ea7c49fcb4ee0273b687685de8044","tests/non_literal_attributes.rs":"a7977134c30935e8217b4ebad6ce1ee44b952d41c552977f8275e573500ea1f1","tests/options.rs":"173702ab3396979164c05d2bb7a2d51a7b29940fcb65bd8d05eaf9b2c91c8a53","tests/privacy.rs":"9194640faa9305666da981051809a26a47c5d02bc559d6753ddfa04e662ea94c","tests/raw_bool_literal.rs":"505dbe32464d6c08720eb73b048b1c96e09f8ed4dc9783a9d2729b1aec6c6de3","tests/raw_idents.rs":"c2251f1062136c9850b92dd8b6b9e0896e2d6a760be1ca058c129784ae98b9d4","tests/regressions.rs":"3bb892b37874f8d72ee37e3ba057b5dd330fe33f6308a7a78981ac8f0e83484f","tests/rename_all_env.rs":"63c8453f1a1f960529326e877288a3a24e5f5b489f9d33cc87001346262e7413","tests/skip.rs":"c2dbfe51de926dada22c0206277884096ee95eca3af72b95d2a06bd9bbee75ce","tests/special_types.rs":"38db378c4ca6a1f896530a0b23e383defa2db5fd94786f496370a9ddebb312a0","tests/subcommands.rs":"f6d45a8e9220a810b286795f7efcc02129f9235a5d349fef1fb20f74a74dddfd","tests/ui/bool_default_value.rs":"0af77090f968013005dbf96caca9275569fa7a3c35cc8c784e1d214418f23985","tests/ui/bool_default_value.stderr":"026fce6b08d828b315a51a055f7d54c35ad31d526abe86e11cd5a30ea790eed4","tests/ui/bool_required.rs":"829435de9578634a9ed57c3882c50d6eda9c5f60a207e4a36f3977b2b884b673","tests/ui/bool_required.stderr":"bddb22e77cb0b9755b1a8c88f55bba09fbb6b0474c1d1472c7fef5e8f1e95910","tests/ui/enum_flatten.rs":"07caccd297c6caf50bb75d1b5351d8ce3799fafdc6fcd15d1066e562f72e0741","tests/ui/enum_flatten.stderr":"20ac7f9ef62ec5b670ceb5e32838ef06c5c6c056abcc0c7dd9972e1861f24665","tests/ui/external_subcommand_wrong_type.rs":"62a65e5723e59e18c65c117991ebc611b735307f8bb78c1fc9bbd4bb9ed6ee7b","tests/ui/external_subcommand_wrong_type.stderr":"d46a065e2883885812625a4ee670c200c2cbae2867530f3a6e7c9c9cfd58f844","tests/ui/flatten_and_methods.rs":"05192dc535a80270fb31c9a6ed96b93ac469289bd62c9813c89c269cbffdddda","tests/ui/flatten_and_methods.stderr":"c84ffeeea9fa9374e31edf76e0d1cc66bc6d88c6a891245d2c9f85abf4e48d2d","tests/ui/flatten_and_parse.rs":"8de85210950ae66841643f0be9d9ab22f060dc6fd2449a55df94190b883857ff","tests/ui/flatten_and_parse.stderr":"b71c12a5130a51bcc20fce941a3789d304cc04fee67a1cb655f86ea64c751523","tests/ui/multiple_external_subcommand.rs":"703873c6ccc84a32322aab5383c89fd15986112159261078463b126d76ac2af8","tests/ui/multiple_external_subcommand.stderr":"25e4d7bd011ee561bc02c9aaba45b7386359ccbb28556b6e24e02aefd538e549","tests/ui/non_existent_attr.rs":"b57520d3c7436c8c55b51181af70484c47ae407e3be67f75bd9ba230ee6b4dd5","tests/ui/non_existent_attr.stderr":"690f051cef29e50ff50ca48ddf8e182b595442413fd2c5ae5b0dee2784b5b94b","tests/ui/opt_opt_nonpositional.rs":"b85e71d4a532d8cc11ae7e1460e5ed34b8de0060ce3ce0ea4f10a40c8a362c80","tests/ui/opt_opt_nonpositional.stderr":"ab650cbf407b8be2b1ddd34315377856ffd37ff8325bb3d95aa4932cf4fe11f0","tests/ui/opt_vec_nonpositional.rs":"002d4b1ea8266b649fc022e7af617dcf4e8712d1e88c00b7506bb4909cf9953f","tests/ui/opt_vec_nonpositional.stderr":"d909206fd6d5590a47cc83d722280af5006410165ecbd66c48d1d78f308907ce","tests/ui/option_default_value.rs":"f9f27d8b376e5d2f7b90a477a11a19fe4d0cd02a3568061e24c6187de18eea73","tests/ui/option_default_value.stderr":"6fc8a67cbbfc7b92ec064bdfd6365cc6893e9f25006b309225b1476db3e0c4ce","tests/ui/option_required.rs":"95d9a3832a87f265b8bddae3d48ac468b9fb590cd76b18b5c92b8ab1871f7601","tests/ui/option_required.stderr":"4cceb32cc57ab536c2b5b52cbf0c30ac412f90eb8467ec7f577ef5595bddfef0","tests/ui/parse_empty_try_from_os.rs":"68c908a0d5b845d64a257f23c8ed257951d87ee4eb2956a052cd7f76a1019cec","tests/ui/parse_empty_try_from_os.stderr":"514d2c761af4bf091808176b81ee237538a936c90777a42b3c149cf5f921d48a","tests/ui/parse_function_is_not_path.rs":"aa149a444e2c6cbd05ccf8bb79e33cf2d1b1b437f5d8c214e8b9996380a34084","tests/ui/parse_function_is_not_path.stderr":"ff6ee9abdf9c735152a94e0b03b55b844c03b8ed94665764f67badc5644cbb16","tests/ui/parse_literal_spec.rs":"b466b5bb0f0c438971eb3b3f3efe72287e9be23eea36ab2fe6a6122ef380c045","tests/ui/parse_literal_spec.stderr":"a39f7584cd0c8832ae41214ec0e5feda9f3cd5f598acd1d03cf6656ba2251e08","tests/ui/parse_not_zero_args.rs":"9f9be206a6424493685e112b2a9b5f3038707f605c5c010b2fb4f0e50d7bf4d7","tests/ui/parse_not_zero_args.stderr":"964ab37d95a55e863df0533ee93730cc85bef131dce5b64f5422a6d3e43c2551","tests/ui/positional_bool.rs":"c5666c7d36d2dd0bb2d591a455274b934a651b8e215f7a854533d1eb10875691","tests/ui/positional_bool.stderr":"9243743983bc2feebd5bfae8964d92f5afc245d7a96f1b772d15df132ef6b548","tests/ui/raw.rs":"5ddb999269ae1e706b2013c4704b1982cb2cf01ca5ea4d8473b7295479ca3765","tests/ui/raw.stderr":"de831d50902812e45a01bc6d1be92b8f13596ad1eaa9b13e2ecc5e21a64ec8c6","tests/ui/rename_all_wrong_casing.rs":"38d1a58938b5b80d6d3af595c060ecf9edf032464ff0f341820da528d7a8a12d","tests/ui/rename_all_wrong_casing.stderr":"38267a983e0c92e4a72fd6444aafa87ec167810b34bd2bceb0c7f060397657f2","tests/ui/skip_flatten.rs":"241dba2936e3c05c1cc3095dd5e6c4b26193e8f7af01c50349e2bd3cd2cb2847","tests/ui/skip_flatten.stderr":"90ce6ac601fbe771841c1b6e0eefd3fb7b315021cf336ba2e786962cbc956ebc","tests/ui/skip_subcommand.rs":"d64b91e4d18f2235a7c1c2e26d4c722915f864ead32e4c1d3cf88e37a79b3928","tests/ui/skip_subcommand.stderr":"1c158e5bd80f3037cf9efa044c346a0557911b53ada522a1241341d02b11691e","tests/ui/skip_with_other_options.rs":"2f6b830bd2d12e6ab20b224ab9dd1560984e22741261746047577bb59b4a305e","tests/ui/skip_with_other_options.stderr":"5e400ae0399ca0fcc774e2b0fcbbca7272359b4d0f7db3bf458524cb0a2a64e2","tests/ui/skip_without_default.rs":"5116ed4996a506f652649c55f87e932d4ff6105aff946adc90f3130cc36499e5","tests/ui/skip_without_default.stderr":"c3b86c004e2076014d3ba68a97f882b4f15b98ee89c34c689a6110bab2ac634f","tests/ui/struct_parse.rs":"126f2c96fe50f2d93e27e2e3e76603519bc9fb5236dda338adfbbb58b397997b","tests/ui/struct_parse.stderr":"f72804d5a0e766ca5d9b833b09d7e2a9efe300ae4b4cd1530fbfb0aee111623f","tests/ui/struct_subcommand.rs":"879f42bea774e58724d6a9e882bfd51bd2da35e26ce745c62bfea7f707728f7c","tests/ui/struct_subcommand.stderr":"5a4d4f9ac4fe5874a82966deef51432bd1951ad6c90814b2eabef9edb1e066bd","tests/ui/structopt_empty_attr.rs":"c1ecb8c5f8b0d75b4b43031fa1dd4c8e370eb867d7cbeaa553db28ad946c1c40","tests/ui/structopt_empty_attr.stderr":"4c57a06b346aa0d6bc664530bc60ecbe2eb33b6286ab89ee9f04ec15b05c3447","tests/ui/structopt_name_value_attr.rs":"4cc6696e31a1c8d1f83a329bec535f21e4be50eeb198a0735f2f82ce649aa4fd","tests/ui/structopt_name_value_attr.stderr":"b782d82f12af57c7d73af2f08ee916e578176a769364383de103c4f0097dab81","tests/ui/subcommand_and_flatten.rs":"3fb46f27d10861cd97015453fd3be093cff605c6709d9f1336992fff2c7b77a5","tests/ui/subcommand_and_flatten.stderr":"6222ce61daa0131745825b61cb4f9fea9abbf841ed9023f3a49f31d734ae61f1","tests/ui/subcommand_and_methods.rs":"d6c28cf88682371d0dc657a123a47d82a9a9a98854e2d9cfc5547beaab75df04","tests/ui/subcommand_and_methods.stderr":"5520611da6876036635b75fe15f82651db47c02699c16107b4cbcc6b4d46e2e2","tests/ui/subcommand_and_parse.rs":"0caed12fef8e6680cc6433575164c28fa2f46b2c18e819c9825842fe88a1f520","tests/ui/subcommand_and_parse.stderr":"fceb9c0e84db80193984459a45800037abf93fc8b34911ca2a4d87446d881999","tests/ui/subcommand_opt_opt.rs":"c837be5291f596c7f27fc992d02af328cbed47aaf4a37704d84ec00266d7661a","tests/ui/subcommand_opt_opt.stderr":"43225265df9e6450fe5e8c5d25e86d96499df5b8889fe6828798b6054ec4ee67","tests/ui/subcommand_opt_vec.rs":"89325bc144682c69b32e7bb5a759678a0818cd8b1cb1b010ed94b10816c9aa8c","tests/ui/subcommand_opt_vec.stderr":"1f222bbe15826138bf13cb87a062ad49a00c117cd0e75a834d9e3be09533761f","tests/ui/tuple_struct.rs":"79dd09e136442ef81fd4d17ac5b38684c3fd87a057cd9e5935dbb364660b8646","tests/ui/tuple_struct.stderr":"ce2795f8d98aa34530b341e6349dd27a0426e39c7107a38c4e92399e0bc4668c","tests/utils.rs":"1e666ab59ddb69f021f9e4488e9339cecc07fb2f4ba6dd64764af06edf000af3","tests/we_need_syn_full.rs":"af218506cfadcfc2ba56de4f537c035c724d612987a85ec36481ed31807a0a99"},"package":"0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10"} \ No newline at end of file diff --git a/vendor/structopt/CHANGELOG.md b/vendor/structopt/CHANGELOG.md new file mode 100644 index 0000000000000..30353f8aef577 --- /dev/null +++ b/vendor/structopt/CHANGELOG.md @@ -0,0 +1,537 @@ +# v0.3.25 (2021-10-18) + +* Fix duplication of aliases in subcommands [#504](https://github.com/TeXitoi/structopt/pull/504) + +# v0.3.25 (2021-10-18) + +* No changes + +# v0.3.23 (2021-08-30) + +* Update minimal rust version to 1.46 because of bitflags 1.3 +* Fixed [a bug that occurs when the type of `map` becomes ambiguous](https://github.com/TeXitoi/structopt/issues/490). +* Add support for [skip for enum variant subcommands](https://github.com/TeXitoi/structopt/issues/493) + +# v0.3.22 (2021-07-04) + +* Add support for [generics in derive](https://github.com/TeXitoi/structopt/issues/128) + +# v0.3.21 (2020-11-30) + +* Fixed [another breakage](https://github.com/TeXitoi/structopt/issues/447) + when the struct is placed inside a `macro_rules!` macro. + +# v0.3.20 (2020-10-12) + +* Fixed [a breakage](https://github.com/TeXitoi/structopt/issues/439) + when the struct is placed inside a `macro_rules!` macro. + +# v0.3.19 (2020-10-08) + +* Added [StructOpt::from_args_safe](https://docs.rs/structopt/0.3/structopt/trait.StructOpt.html#tymethod.from_args_safe) as a shortcut for `StructOpt::from_iter_safe(std::env::args_os())`. +* Some links in documentation have been corrected. + +# v0.3.18 (2020-09-23) + +* Unsafe code [has been forbidden](https://github.com/TeXitoi/structopt/issues/432). This makes + [`cargo geiger`](https://github.com/rust-secure-code/cargo-geiger) list structopt as "safe". + Maybe it will help somebody trying to locate a bug in their dependency tree. + +# v0.3.17 (2020-08-25) + +* Fixed [a breakage](https://github.com/TeXitoi/structopt/issues/424) with resent rustc versions + due to `quote_spanned` misuse. + +# v0.3.16 (2020-08-05) + +* Added [the new example](https://github.com/TeXitoi/structopt/blob/master/examples/required_if.rs). +* Allow `#[structopt(flatten)]` fields to have doc comments. The comments are ignored. +* The `paw` crate is now being reexported when `paw` feature is enabled, + see [`#407`](https://github.com/TeXitoi/structopt/issues/407). + +# v0.3.15 (2020-06-16) + +* Minor documentation improvements. +* Fixed [a latent bug](https://github.com/TeXitoi/structopt/pull/398), + courtesy of [@Aaron1011](https://github.com/Aaron1011). + +# v0.3.14 (2020-04-22) + +* Minor documentation improvements. + +# v0.3.13 (2020-04-9) + +* Bump `proc-macro-error` to `1.0`. + +# v0.3.12 (2020-03-18) + +* Fixed [bug in `external_subcommand`](https://github.com/TeXitoi/structopt/issues/359). + +# v0.3.11 (2020-03-01) + +* `syn`'s "full" feature is now explicitly enabled. It must have been, but hasn't. + +# v0.3.10 (2020-03-01) - YANKED + +* Fixed the breakage due to a required `syn` feature was not enabled. + +# v0.3.9 (2020-02-01) - YANKED + +* `clippy` warnings triggered by generated code shall not annoy you anymore! + Except for those from `clippy::correctness`, these lints are useful even + for auto generated code. +* Improved error messages. + +# v0.3.8 (2020-1-19) - YANKED + +* You don't have to apply `#[no_version]` to every `enum` variant anymore. + Just annotate the `enum` and the setting will be propagated down + ([#242](https://github.com/TeXitoi/structopt/issues/242)). +* [Auto-default](https://docs.rs/structopt/0.3/structopt/#default-values). +* [External subcommands](https://docs.rs/structopt/0.3/structopt/#external-subcommands). +* [Flattening subcommands](https://docs.rs/structopt/0.3.8/structopt/#flattening-subcommands). + +# v0.3.7 (2019-12-28) + +Nothing's new. Just re-release of `v0.3.6` due to +[the mess with versioning](https://github.com/TeXitoi/structopt/issues/315#issuecomment-568502792). + +You may notice that `structopt-derive` was bumped to `v0.4.0`, that's OK, it's not a breaking change. +`structopt` will pull the right version in on its on. + +# v0.3.6 (2019-12-22) - YANKED + +This is unusually big patch release. It contains a number of bugfixes and +new features, some of them may theoretically be considered breaking. We did our best +to avoid any problems on user's side but, if it wasn't good enough, please +[file an issue ASAP](https://github.com/TeXitoi/structopt/issues). + +## Bugfixes + +* `structopt` used to treat `::path::to::type::Vec` as `Vec` + special type. [This was considered erroneous](https://github.com/TeXitoi/structopt/pull/287). + (same for `Option` and `bool`). Now only exact `Vec` match is a special type. + +* `#[structopt(version = expr)]` where `expr` is not a string literal used to get + overridden by auto generated `.version()` call, + [incorrectly](https://github.com/TeXitoi/structopt/issues/283). Now it doesn't. + +* Fixed bug with top-level `App::*` calls on multiple `struct`s, see + [#289](https://github.com/TeXitoi/structopt/issues/265). + +* Positional `bool` args with no explicit `#[structopt(parse(...))]` annotation are + now prohibited. This couldn't work well anyway, see + [this example](https://github.com/TeXitoi/structopt/blob/master/examples/true_or_false.rs) + for details. + +* Now we've instituted strict priority between doc comments, about, help, and the like. + See [the documentation](https://docs.rs/structopt/0.3/structopt/#help-messages). + + **HUGE THANKS to [`@ssokolow`](https://github.com/ssokolow)** for tidying up our documentation, + teaching me English and explaining why our doc used to suck. I promise I'll make the rest + of the doc up to your standards... sometime later! + +## New features + +* Implement `StructOpt` for `Box` so from now on you can use `Box` + with `flatten` and `subcommand` ([#304](https://github.com/TeXitoi/structopt/issues/304)). + + ```rust + enum Command { + #[structopt(name = "version")] + PrintVersion, + + #[structopt(name = "second")] + DoSomething { + #[structopt(flatten)] + config: Box, + }, + + #[structopt(name = "first")] + DoSomethingElse { + #[structopt(flatten)] + config: Box, + } + } + ``` + +* Introduced `#[structopt(verbatim_doc_comment)]` attribute that keeps line breaks in + doc comments, see + [the documentation](https://docs.rs/structopt/0.3/structopt/#doc-comment-preprocessing-and-structoptverbatim_doc_comment). + +* Introduced `#[structopt(rename_all_env)]` and `#[structopt(env)]` magical methods + so you can derive env var's name from field's name. See + [the documentation](https://docs.rs/structopt/0.3/structopt/#auto-deriving-environment-variables). + +## Improvements + +* Now we have nice README for our examples, + [check it out](https://github.com/TeXitoi/structopt/tree/master/examples)! + +* Some error messages were improved and clarified, thanks for all people involved! + + +# v0.3.5 (2019-11-22) + +* `try_from_str` functions are now called with a `&str` instead of a `&String` ([#282](https://github.com/TeXitoi/structopt/pull/282)) + +# v0.3.4 (2019-11-08) + +* `rename_all` does not apply to fields that were annotated with explicit + `short/long/name = "..."` anymore ([#265](https://github.com/TeXitoi/structopt/issues/265)) +* Now raw idents are handled correctly ([#269](https://github.com/TeXitoi/structopt/issues/269)) +* Some documentation improvements and clarification. + +# v0.3.3 (2019-10-10) + +* Add `from_flag` custom parser to create flags from non-bool types. + Fixes [#185](https://github.com/TeXitoi/structopt/issues/185) + +# v0.3.2 (2019-09-18) + +* `structopt` does not replace `:` with `, ` inside "author" strings while inside `<...>`. + Fixes [#156](https://github.com/TeXitoi/structopt/issues/156) +* Introduced [`#[structopt(skip = expr)]` syntax](https://docs.rs/structopt/0.3.2/structopt/#skipping-fields). + +# v0.3.1 (2019-09-06) + +* Fix error messages ([#241](https://github.com/TeXitoi/structopt/issues/241)) +* Fix "`skip` plus long doc comment" bug ([#245](https://github.com/TeXitoi/structopt/issues/245)) +* Now `structopt` emits dummy `StructOpt` implementation along with an error. It suppresses + meaningless errors like `from_args method is not found for Opt` +* `.version()` not get generated if `CARGO_PKG_VERSION` is not set anymore. + +# v0.3.0 (2019-08-30) + +## Breaking changes + +### Bump minimum rustc version to 1.36 by [@TeXitoi](https://github.com/TeXitoi) +Now `rustc` 1.36 is the minimum compiler version supported by `structopt`, +it likely won't work with older compilers. + +### Remove "nightly" feature +Once upon a time this feature had been used to enable some of improvements +in `proc-macro2` crate that were available only on nightly. Nowadays this feature doesn't +mean anything so it's now removed. + +### Support optional vectors of arguments for distinguishing between `-o 1 2`, `-o` and no option provided at all by [@sphynx](https://github.com/sphynx) ([#180](https://github.com/TeXitoi/structopt/issues/188)). + +```rust +#[derive(StructOpt)] +struct Opt { + #[structopt(long)] + fruit: Option>, +} + +fn main() { + assert_eq!(Opt::from_args(&["test"]), None); + assert_eq!(Opt::from_args(&["test", "--fruit"]), Some(vec![])); + assert_eq!(Opt::from_args(&["test", "--fruit=apple orange"]), Some(vec!["apple", "orange"])); +} +``` + +If you need to fall back to the old behavior you can use a type alias: +```rust +type Something = Vec; + +#[derive(StructOpt)] +struct Opt { + #[structopt(long)] + fruit: Option, +} +``` + +### Change default case from 'Verbatim' into 'Kebab' by [@0ndorio](https://github.com/0ndorio) ([#202](https://github.com/TeXitoi/structopt/issues/202)). +`structopt` 0.3 uses field renaming to deduce a name for long options and subcommands. + +```rust +#[derive(StructOpt)] +struct Opt { + #[structopt(long)] + http_addr: String, // will be renamed to `--http-addr` + + #[structopt(subcommand)] + addr_type: AddrType // this adds `addr-type` subcommand +} +``` + +`structopt` 0.2 used to leave things "as is", not renaming anything. If you want to keep old +behavior add `#[structopt(rename_all = "verbatim")]` on top of a `struct`/`enum`. + +### Change `version`, `author` and `about` attributes behavior. +Proposed by [@TeXitoi](https://github.com/TeXitoi) [(#217)](https://github.com/TeXitoi/structopt/issues/217), implemented by [@CreepySkeleton](https://github.com/CreepySkeleton) [(#229)](https://github.com/TeXitoi/structopt/pull/229). + +`structopt` have been deducing `version`, `author`, and `about` properties from `Cargo.toml` +for a long time (more accurately, from `CARGO_PKG_...` environment variables). +But many users found this behavior somewhat confusing, and a hack was added to cancel out +this behavior: `#[structopt(author = "")]`. + +In `structopt` 0.3 this has changed. +* `author` and `about` are no longer deduced by default. You should use `#[structopt(author, about)]` + to explicitly request `structopt` to deduce them. +* Contrary, `version` **is still deduced by default**. You can use `#[structopt(no_version)]` to + cancel it out. +* `#[structopt(author = "", about = "", version = "")]` is no longer a valid syntax + and will trigger an error. +* `#[structopt(version = "version", author = "author", about = "about")]` syntax + stays unaffected by this changes. + +### Raw attributes are removed ([#198](https://github.com/TeXitoi/structopt/pull/198)) by [@sphynx](https://github.com/sphynx) +In `structopt` 0.2 you were able to use any method from `clap::App` and `clap::Arg` via +raw attribute: `#[structopt(raw(method_name = "arg"))]`. This syntax was kind of awkward. + +```rust +#[derive(StructOpt, Debug)] +#[structopt(raw( + global_settings = "&[AppSettings::ColoredHelp, AppSettings::VersionlessSubcommands]" +))] +struct Opt { + #[structopt(short = "l", long = "level", raw(aliases = r#"&["set-level", "lvl"]"#))] + level: Vec, +} +``` + +Raw attributes were removed in 0.3. Now you can use any method from `App` and `Arg` *directly*: +```rust +#[derive(StructOpt)] +#[structopt(global_settings(&[AppSettings::ColoredHelp, AppSettings::VersionlessSubcommands]))] +struct Opt { + #[structopt(short = "l", long = "level", aliases(&["set-level", "lvl"]))] + level: Vec, +} +``` + +## Improvements + +### Support skipping struct fields +Proposed by [@Morganamilo](https://github.com/Morganamilo) in ([#174](https://github.com/TeXitoi/structopt/issues/174)) +implemented by [@sphynx](https://github.com/sphynx) in ([#213](https://github.com/TeXitoi/structopt/issues/213)). + +Sometimes you want to include some fields in your `StructOpt` `struct` that are not options +and `clap` should know nothing about them. In `structopt` 0.3 it's possible via the +`#[structopt(skip)]` attribute. The field in question will be assigned with `Default::default()` +value. + +```rust +#[derive(StructOpt)] +struct Opt { + #[structopt(short, long)] + speed: f32, + + car: String, + + // this field should not generate any arguments + #[structopt(skip)] + meta: Vec +} +``` + +### Add optional feature to support `paw` by [@gameldar](https://github.com/gameldar) ([#187](https://github.com/TeXitoi/structopt/issues/187)) + +### Significantly improve error reporting by [@CreepySkeleton](https://github.com/CreepySkeleton) ([#225](https://github.com/TeXitoi/structopt/pull/225/)) +Now (almost) every error message points to the location it originates from: + +```text +error: default_value is meaningless for bool + --> $DIR/bool_default_value.rs:14:24 + | +14 | #[structopt(short, default_value = true)] + | ^^^^^^^^^^^^^ +``` + +# v0.2.16 (2019-05-29) + +### Support optional options with optional argument, allowing `cmd [--opt[=value]]` by [@sphynx](https://github.com/sphynx) ([#188](https://github.com/TeXitoi/structopt/issues/188)) +Sometimes you want to represent an optional option that optionally takes an argument, +i.e `[--opt[=value]]`. This is represented by `Option>` + +```rust +#[derive(StructOpt)] +struct Opt { + #[structopt(long)] + fruit: Option>, +} + +fn main() { + assert_eq!(Opt::from_args(&["test"]), None); + assert_eq!(Opt::from_args(&["test", "--fruit"]), Some(None)); + assert_eq!(Opt::from_args(&["test", "--fruit=apple"]), Some("apple")); +} +``` + +# v0.2.15 (2019-03-08) + +* Fix [#168](https://github.com/TeXitoi/structopt/issues/168) by [@TeXitoi](https://github.com/TeXitoi) + +# v0.2.14 (2018-12-10) + +* Introduce smarter parsing of doc comments by [@0ndorio](https://github.com/0ndorio) + +# v0.2.13 (2018-11-01) + +* Automatic naming of fields and subcommands by [@0ndorio](https://github.com/0ndorio) + +# v0.2.12 (2018-10-11) + +* Fix minimal clap version by [@TeXitoi](https://github.com/TeXitoi) + +# v0.2.11 (2018-10-05) + +* Upgrade syn to 0.15 by [@konstin](https://github.com/konstin) + +# v0.2.10 (2018-06-07) + +* 1.21.0 is the minimum required rustc version by + [@TeXitoi](https://github.com/TeXitoi) + +# v0.2.9 (2018-06-05) + +* Fix a bug when using `flatten` by + [@fbenkstein](https://github.com/fbenkstein) +* Update syn, quote and proc_macro2 by + [@TeXitoi](https://github.com/TeXitoi) +* Fix a regression when there is multiple authors by + [@windwardly](https://github.com/windwardly) + +# v0.2.8 (2018-04-28) + +* Add `StructOpt::from_iter_safe()`, which returns an `Error` instead of + killing the program when it fails to parse, or parses one of the + short-circuiting flags. ([#98](https://github.com/TeXitoi/structopt/pull/98) + by [@quodlibetor](https://github.com/quodlibetor)) +* Allow users to enable `clap` features independently by + [@Kerollmops](https://github.com/Kerollmops) +* Fix a bug when flattening an enum + ([#103](https://github.com/TeXitoi/structopt/pull/103) by + [@TeXitoi](https://github.com/TeXitoi) + +# v0.2.7 (2018-04-12) + +* Add flattening, the insertion of options of another StructOpt struct + into another ([#92](https://github.com/TeXitoi/structopt/pull/92)) + by [@birkenfeld](https://github.com/birkenfeld) +* Fail compilation when using `default_value` or `required` with + `Option` ([#88](https://github.com/TeXitoi/structopt/pull/88)) by + [@Kerollmops](https://github.com/Kerollmops) + +# v0.2.6 (2018-03-31) + +* Fail compilation when using `default_value` or `required` with `bool` ([#80](https://github.com/TeXitoi/structopt/issues/80)) by [@TeXitoi](https://github.com/TeXitoi) +* Fix compilation with `#[deny(warnings)]` with the `!` type (https://github.com/rust-lang/rust/pull/49039#issuecomment-376398999) by [@TeXitoi](https://github.com/TeXitoi) +* Improve first example in the documentation ([#82](https://github.com/TeXitoi/structopt/issues/82)) by [@TeXitoi](https://github.com/TeXitoi) + +# v0.2.5 (2018-03-07) + +* Work around breakage when `proc-macro2`'s nightly feature is enabled. ([#77](https://github.com/Texitoi/structopt/pull/77) and [proc-macro2#67](https://github.com/alexcrichton/proc-macro2/issues/67)) by [@fitzgen](https://github.com/fitzgen) + +# v0.2.4 (2018-02-25) + +* Fix compilation with `#![deny(missig_docs]` ([#74](https://github.com/TeXitoi/structopt/issues/74)) by [@TeXitoi](https://github.com/TeXitoi) +* Fix [#76](https://github.com/TeXitoi/structopt/issues/76) by [@TeXitoi](https://github.com/TeXitoi) +* Re-licensed to Apache-2.0/MIT by [@CAD97](https://github.com/cad97) + +# v0.2.3 (2018-02-16) + +* An empty line in a doc comment will result in a double linefeed in the generated about/help call by [@TeXitoi](https://github.com/TeXitoi) + +# v0.2.2 (2018-02-12) + +* Fix [#66](https://github.com/TeXitoi/structopt/issues/66) by [@TeXitoi](https://github.com/TeXitoi) + +# v0.2.1 (2018-02-11) + +* Fix a bug around enum tuple and the about message in the global help by [@TeXitoi](https://github.com/TeXitoi) +* Fix [#65](https://github.com/TeXitoi/structopt/issues/65) by [@TeXitoi](https://github.com/TeXitoi) + +# v0.2.0 (2018-02-10) + +## Breaking changes + +### Don't special case `u64` by [@SergioBenitez](https://github.com/SergioBenitez) + +If you are using a `u64` in your struct to get the number of occurence of a flag, you should now add `parse(from_occurrences)` on the flag. + +For example +```rust +#[structopt(short = "v", long = "verbose")] +verbose: u64, +``` +must be changed by +```rust +#[structopt(short = "v", long = "verbose", parse(from_occurrences))] +verbose: u64, +``` + +This feature was surprising as shown in [#30](https://github.com/TeXitoi/structopt/issues/30). Using the `parse` feature seems much more natural. + +### Change the signature of `Structopt::from_clap` to take its argument by reference by [@TeXitoi](https://github.com/TeXitoi) + +There was no reason to take the argument by value. Most of the StructOpt users will not be impacted by this change. If you are using `StructOpt::from_clap`, just add a `&` before the argument. + +### Fail if attributes are not used by [@TeXitoi](https://github.com/TeXitoi) + +StructOpt was quite fuzzy in its attribute parsing: it was only searching for interresting things, e. g. something like `#[structopt(foo(bar))]` was accepted but not used. It now fails the compilation. + +You should have nothing to do here. This breaking change may highlight some missuse that can be bugs. + +In future versions, if there is cases that are not highlighed, they will be considerated as bugs, not breaking changes. + +### Use `raw()` wrapping instead of `_raw` suffixing by [@TeXitoi](https://github.com/TeXitoi) + +The syntax of raw attributes is changed to improve the syntax. + +You have to change `foo_raw = "bar", baz_raw = "foo"` by `raw(foo = "bar", baz = "foo")` or `raw(foo = "bar"), raw(baz = "foo")`. + +## New features + +* Add `parse(from_occurrences)` parser by [@SergioBenitez](https://github.com/SergioBenitez) +* Support 1-uple enum variant as subcommand by [@TeXitoi](https://github.com/TeXitoi) +* structopt-derive crate is now an implementation detail, structopt reexport the custom derive macro by [@TeXitoi](https://github.com/TeXitoi) +* Add the `StructOpt::from_iter` method by [@Kerollmops](https://github.com/Kerollmops) + +## Documentation + +* Improve doc by [@bestouff](https://github.com/bestouff) +* All the documentation is now on the structopt crate by [@TeXitoi](https://github.com/TeXitoi) + +# v0.1.7 (2018-01-23) + +* Allow opting out of clap default features by [@ski-csis](https://github.com/ski-csis) + +# v0.1.6 (2017-11-25) + +* Improve documentation by [@TeXitoi](https://github.com/TeXitoi) +* Fix bug [#31](https://github.com/TeXitoi/structopt/issues/31) by [@TeXitoi](https://github.com/TeXitoi) + +# v0.1.5 (2017-11-14) + +* Fix a bug with optional subsubcommand and Enum by [@TeXitoi](https://github.com/TeXitoi) + +# v0.1.4 (2017-11-09) + +* Implement custom string parser from either `&str` or `&OsStr` by [@kennytm](https://github.com/kennytm) + +# v0.1.3 (2017-11-01) + +* Improve doc by [@TeXitoi](https://github.com/TeXitoi) + +# v0.1.2 (2017-11-01) + +* Fix bugs [#24](https://github.com/TeXitoi/structopt/issues/24) and [#25](https://github.com/TeXitoi/structopt/issues/25) by [@TeXitoi](https://github.com/TeXitoi) +* Support of methods with something else that a string as argument thanks to `_raw` suffix by [@Flakebi](https://github.com/Flakebi) + +# v0.1.1 (2017-09-22) + +* Better formating of multiple authors by [@killercup](https://github.com/killercup) + +# v0.1.0 (2017-07-17) + +* Subcommand support by [@williamyaoh](https://github.com/williamyaoh) + +# v0.0.5 (2017-06-16) + +* Using doc comment to populate help by [@killercup](https://github.com/killercup) + +# v0.0.3 (2017-02-11) + +* First version with flags, arguments and options support by [@TeXitoi](https://github.com/TeXitoi) diff --git a/vendor/structopt/Cargo.lock b/vendor/structopt/Cargo.lock new file mode 100644 index 0000000000000..f7fb6aaa55572 --- /dev/null +++ b/vendor/structopt/Cargo.lock @@ -0,0 +1,532 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "blake2b_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "byteorder" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "clippy", + "strsim", + "term_size", + "textwrap", + "unicode-width", + "vec_map", + "yaml-rust", +] + +[[package]] +name = "clippy" +version = "0.0.302" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d911ee15579a3f50880d8c1d59ef6e79f9533127a3bd342462f5d584f5e8c294" +dependencies = [ + "term", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "crossbeam-utils" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "dirs" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dissimilar" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4b29f4b9bb94bf267d57269fd0706d343a160937108e9619fe380645428abb" + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "heck" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213" + +[[package]] +name = "paw" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c0fc9b564dbc3dc2ed7c92c0c144f4de340aa94514ce2b446065417c4084e9" +dependencies = [ + "paw-attributes", + "paw-raw", +] + +[[package]] +name = "paw-attributes" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "paw-raw" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "redox_users" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +dependencies = [ + "getrandom", + "redox_syscall", + "rust-argon2", +] + +[[package]] +name = "rust-argon2" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" +dependencies = [ + "base64", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", +] + +[[package]] +name = "rustversion" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "serde" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.26" +dependencies = [ + "clap", + "lazy_static", + "paw", + "rustversion", + "structopt-derive", + "strum", + "trybuild", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "strum" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed22b90a0e734a23a7610f4283ac9e5acfb96cbb30dfefa540d66f866f1c09c5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "term" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" +dependencies = [ + "byteorder", + "dirs", + "winapi", +] + +[[package]] +name = "term_size" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "term_size", + "unicode-width", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "trybuild" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99471a206425fba51842a9186315f32d91c56eadc21ea4c21f847b59cf778f8b" +dependencies = [ + "dissimilar", + "glob", + "lazy_static", + "serde", + "serde_json", + "termcolor", + "toml", +] + +[[package]] +name = "unicode-segmentation" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "yaml-rust" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" diff --git a/vendor/structopt/Cargo.toml b/vendor/structopt/Cargo.toml new file mode 100644 index 0000000000000..321b31ed441cb --- /dev/null +++ b/vendor/structopt/Cargo.toml @@ -0,0 +1,61 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "structopt" +version = "0.3.26" +authors = ["Guillaume Pinot ", "others"] +description = "Parse command line argument by defining a struct." +documentation = "https://docs.rs/structopt" +readme = "README.md" +keywords = ["clap", "cli", "derive", "docopt"] +categories = ["command-line-interface"] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/TeXitoi/structopt" +[dependencies.clap] +version = "2.33" +default-features = false + +[dependencies.lazy_static] +version = "1.4.0" + +[dependencies.paw_dep] +version = "1" +optional = true +package = "paw" + +[dependencies.structopt-derive] +version = "=0.4.18" +[dev-dependencies.rustversion] +version = "1" + +[dev-dependencies.strum] +version = "0.21" +features = ["derive"] + +[dev-dependencies.trybuild] +version = "1.0.5" +features = ["diff"] + +[features] +color = ["clap/color"] +debug = ["clap/debug"] +default = ["clap/default"] +doc = ["clap/doc"] +lints = ["clap/lints"] +no_cargo = ["clap/no_cargo"] +paw = ["structopt-derive/paw", "paw_dep"] +suggestions = ["clap/suggestions"] +wrap_help = ["clap/wrap_help"] +yaml = ["clap/yaml"] +[badges.travis-ci] +repository = "TeXitoi/structopt" diff --git a/vendor/structopt/LICENSE-APACHE b/vendor/structopt/LICENSE-APACHE new file mode 100644 index 0000000000000..261eeb9e9f8b2 --- /dev/null +++ b/vendor/structopt/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/structopt/LICENSE-MIT b/vendor/structopt/LICENSE-MIT new file mode 100644 index 0000000000000..e931b83b643f3 --- /dev/null +++ b/vendor/structopt/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Guillaume Pinot (@TeXitoi) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/structopt/README.md b/vendor/structopt/README.md new file mode 100644 index 0000000000000..bff1587b121f9 --- /dev/null +++ b/vendor/structopt/README.md @@ -0,0 +1,157 @@ +# StructOpt + +[![Build status](https://travis-ci.com/TeXitoi/structopt.svg?branch=master)](https://app.travis-ci.com/github/TeXitoi/structopt) [![](https://img.shields.io/crates/v/structopt.svg)](https://crates.io/crates/structopt) [![](https://docs.rs/structopt/badge.svg)](https://docs.rs/structopt) +[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/) + +Parse command line arguments by defining a struct. It combines [clap](https://crates.io/crates/clap) with custom derive. + +## Maintenance + +As clap v3 is now out, and the structopt features are integrated into (almost as-is), structopt is now in maintenance mode: no new feature will be added. + +Bugs will be fixed, and documentation improvements will be accepted. + +## Documentation + +Find it on [Docs.rs](https://docs.rs/structopt). You can also check the [examples](https://github.com/TeXitoi/structopt/tree/master/examples) and the [changelog](https://github.com/TeXitoi/structopt/blob/master/CHANGELOG.md). + +## Example + +Add `structopt` to your dependencies of your `Cargo.toml`: +```toml +[dependencies] +structopt = "0.3" +``` + +And then, in your rust file: +```rust +use std::path::PathBuf; +use structopt::StructOpt; + +/// A basic example +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + // A flag, true if used in the command line. Note doc comment will + // be used for the help message of the flag. The name of the + // argument will be, by default, based on the name of the field. + /// Activate debug mode + #[structopt(short, long)] + debug: bool, + + // The number of occurrences of the `v/verbose` flag + /// Verbose mode (-v, -vv, -vvv, etc.) + #[structopt(short, long, parse(from_occurrences))] + verbose: u8, + + /// Set speed + #[structopt(short, long, default_value = "42")] + speed: f64, + + /// Output file + #[structopt(short, long, parse(from_os_str))] + output: PathBuf, + + // the long option will be translated by default to kebab case, + // i.e. `--nb-cars`. + /// Number of cars + #[structopt(short = "c", long)] + nb_cars: Option, + + /// admin_level to consider + #[structopt(short, long)] + level: Vec, + + /// Files to process + #[structopt(name = "FILE", parse(from_os_str))] + files: Vec, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:#?}", opt); +} +``` + +Using this example: +``` +$ ./basic +error: The following required arguments were not provided: + --output + +USAGE: + basic --output --speed + +For more information try --help +$ ./basic --help +basic 0.3.0 +Guillaume Pinot , others +A basic example + +USAGE: + basic [FLAGS] [OPTIONS] --output [--] [file]... + +FLAGS: + -d, --debug Activate debug mode + -h, --help Prints help information + -V, --version Prints version information + -v, --verbose Verbose mode (-v, -vv, -vvv, etc.) + +OPTIONS: + -l, --level ... admin_level to consider + -c, --nb-cars Number of cars + -o, --output Output file + -s, --speed Set speed [default: 42] + +ARGS: + ... Files to process +$ ./basic -o foo.txt +Opt { + debug: false, + verbose: 0, + speed: 42.0, + output: "foo.txt", + nb_cars: None, + level: [], + files: [], +} +$ ./basic -o foo.txt -dvvvs 1337 -l alice -l bob --nb-cars 4 bar.txt baz.txt +Opt { + debug: true, + verbose: 3, + speed: 1337.0, + output: "foo.txt", + nb_cars: Some( + 4, + ), + level: [ + "alice", + "bob", + ], + files: [ + "bar.txt", + "baz.txt", + ], +} +``` + +## StructOpt rustc version policy + +- Minimum rustc version modification must be specified in the [changelog](https://github.com/TeXitoi/structopt/blob/master/CHANGELOG.md) and in the [travis configuration](https://github.com/TeXitoi/structopt/blob/master/.travis.yml). +- Contributors can increment minimum rustc version without any justification if the new version is required by the latest version of one of StructOpt's dependencies (`cargo update` will not fail on StructOpt). +- Contributors can increment minimum rustc version if the library user experience is improved. + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/vendor/structopt/examples/README.md b/vendor/structopt/examples/README.md new file mode 100644 index 0000000000000..1475e2a921aea --- /dev/null +++ b/vendor/structopt/examples/README.md @@ -0,0 +1,86 @@ +# Collection of examples "how to use `structopt`" + +### [Help on the bottom](after_help.rs) + +How to append a postscript to the help message generated. + +### [At least N](at_least_two.rs) + +How to require presence of at least N values, like `val1 val2 ... valN ... valM`. + +### [Basic](basic.rs) + +A basic example how to use `structopt`. + +### [Deny missing docs](deny_missing_docs.rs) + +**This is not an example but a test**, it should be moved to `tests` folder +as soon as [this](https://github.com/rust-lang/rust/issues/24584) is fixed (if ever). + +### [Doc comments](doc_comments.rs) + +How to use doc comments in place of `help/long_help`. + +### [Enums as arguments](enum_in_args.rs) + +How to use `arg_enum!` with `StructOpt`. + +### [Arguments of subcommands in separate `struct`](enum_tuple.rs) + +How to extract subcommands' args into external structs. + +### [Environment variables](env.rs) + +How to use environment variable fallback and how it interacts with `default_value`. + +### [Advanced](example.rs) + +Somewhat complex example of usage of `structopt`. + +### [Flatten](flatten.rs) + +How to use `#[structopt(flatten)]` + +### [`bash` completions](gen_completions.rs) + +Generating `bash` completions with `structopt`. + +### [Git](git.rs) + +Pseudo-`git` example, shows how to use subcommands and how to document them. + +### [Groups](group.rs) + +Using `clap::Arg::group` with `structopt`. + +### [`key=value` pairs](keyvalue.rs) + +How to parse `key=value` pairs. + +### [`--no-*` flags](negative_flag.rs) + +How to add `no-thing` flag which is `true` by default and `false` if passed. + +### [No version](no_version.rs) + +How to completely remove version. + +### [Rename all](rename_all.rs) + +How `#[structopt(rename_all)]` works. + +### [Required If](required_if.rs) + +How to use `#[structopt(required_if)]`. + +### [Skip](skip.rs) + +How to use `#[structopt(skip)]`. + +### [Aliases](subcommand_aliases.rs) + +How to use aliases + +### [`true` or `false`](true_or_false.rs) + +How to express "`"true"` or `"false"` argument. diff --git a/vendor/structopt/examples/after_help.rs b/vendor/structopt/examples/after_help.rs new file mode 100644 index 0000000000000..75816c7425bfc --- /dev/null +++ b/vendor/structopt/examples/after_help.rs @@ -0,0 +1,43 @@ +//! How to append a postscript to the help message generated. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! structopt 0.3.25 +//! I am a program and I do things. +//! +//! Sometimes they even work. +//! +//! USAGE: +//! after_help [FLAGS] +//! +//! FLAGS: +//! -d +//! Release the dragon +//! +//! -h, --help +//! Prints help information +//! +//! -V, --version +//! Prints version information +//! +//! +//! Beware `-d`, dragons be here +//! ----------------------------------------------------- + +use structopt::StructOpt; + +/// I am a program and I do things. +/// +/// Sometimes they even work. +#[derive(StructOpt, Debug)] +#[structopt(after_help = "Beware `-d`, dragons be here")] +struct Opt { + /// Release the dragon. + #[structopt(short)] + dragon: bool, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/examples/at_least_two.rs b/vendor/structopt/examples/at_least_two.rs new file mode 100644 index 0000000000000..a4eb0028e7726 --- /dev/null +++ b/vendor/structopt/examples/at_least_two.rs @@ -0,0 +1,30 @@ +//! How to require presence of at least N values, +//! like `val1 val2 ... valN ... valM`. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! structopt 0.3.25 +//! +//! USAGE: +//! at_least_two ... +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! ARGS: +//! ... +//! ----------------------------------------------------- + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +struct Opt { + #[structopt(required = true, min_values = 2)] + foos: Vec, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/examples/basic.rs b/vendor/structopt/examples/basic.rs new file mode 100644 index 0000000000000..33e441550d6d0 --- /dev/null +++ b/vendor/structopt/examples/basic.rs @@ -0,0 +1,72 @@ +//! A somewhat comprehensive example of a typical `StructOpt` usage.use +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! basic 0.3.25 +//! A basic example +//! +//! USAGE: +//! basic [FLAGS] [OPTIONS] --output [--] [FILE]... +//! +//! FLAGS: +//! -d, --debug Activate debug mode +//! -h, --help Prints help information +//! -V, --version Prints version information +//! -v, --verbose Verbose mode (-v, -vv, -vvv, etc.) +//! +//! OPTIONS: +//! -l, --level ... admin_level to consider +//! -c, --nb-cars Number of cars +//! -o, --output Output file +//! -s, --speed Set speed [default: 42] +//! +//! ARGS: +//! ... Files to process +//! ----------------------------------------------------- + +use std::path::PathBuf; +use structopt::StructOpt; + +/// A basic example +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + // A flag, true if used in the command line. Note doc comment will + // be used for the help message of the flag. The name of the + // argument will be, by default, based on the name of the field. + /// Activate debug mode + #[structopt(short, long)] + debug: bool, + + // The number of occurrences of the `v/verbose` flag + /// Verbose mode (-v, -vv, -vvv, etc.) + #[structopt(short, long, parse(from_occurrences))] + verbose: u8, + + /// Set speed + #[structopt(short, long, default_value = "42")] + speed: f64, + + /// Output file + #[structopt(short, long, parse(from_os_str))] + output: PathBuf, + + // the long option will be translated by default to kebab case, + // i.e. `--nb-cars`. + /// Number of cars + #[structopt(short = "c", long)] + nb_cars: Option, + + /// admin_level to consider + #[structopt(short, long)] + level: Vec, + + /// Files to process + #[structopt(name = "FILE", parse(from_os_str))] + files: Vec, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:#?}", opt); +} diff --git a/vendor/structopt/examples/deny_missing_docs.rs b/vendor/structopt/examples/deny_missing_docs.rs new file mode 100644 index 0000000000000..05ceca9d61458 --- /dev/null +++ b/vendor/structopt/examples/deny_missing_docs.rs @@ -0,0 +1,71 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This should be in tests but it will not work until +// https://github.com/rust-lang/rust/issues/24584 is fixed + +//! A test to check that structopt compiles with deny(missing_docs) +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! structopt 0.3.25 +//! Some subcommands +//! +//! USAGE: +//! deny_missing_docs [FLAGS] [SUBCOMMAND] +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! -v +//! +//! SUBCOMMANDS: +//! a command A +//! b command B +//! c command C +//! help Prints this message or the help of the given subcommand(s) +//! ----------------------------------------------------- + +#![deny(missing_docs)] + +use structopt::StructOpt; + +/// The options +#[derive(StructOpt, Debug, PartialEq)] +pub struct Opt { + #[structopt(short)] + verbose: bool, + #[structopt(subcommand)] + cmd: Option, +} + +/// Some subcommands +#[derive(StructOpt, Debug, PartialEq)] +pub enum Cmd { + /// command A + A, + /// command B + B { + /// Alice? + #[structopt(short)] + alice: bool, + }, + /// command C + C(COpt), +} + +/// The options for C +#[derive(StructOpt, Debug, PartialEq)] +pub struct COpt { + #[structopt(short)] + bob: bool, +} + +fn main() { + println!("{:?}", Opt::from_args()); +} diff --git a/vendor/structopt/examples/doc_comments.rs b/vendor/structopt/examples/doc_comments.rs new file mode 100644 index 0000000000000..3d22152911daa --- /dev/null +++ b/vendor/structopt/examples/doc_comments.rs @@ -0,0 +1,124 @@ +//! How to use doc comments in place of `help/long_help`. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! basic 0.3.25 +//! A basic example for the usage of doc comments as replacement of the arguments `help`, `long_help`, `about` and +//! `long_about` +//! +//! USAGE: +//! doc_comments [FLAGS] +//! +//! FLAGS: +//! -f, --first-flag +//! Just use doc comments to replace `help`, `long_help`, `about` or `long_about` input +//! +//! -h, --help +//! Prints help information +//! +//! -s, --second-flag +//! Split between `help` and `long_help`. +//! +//! In the previous case structopt is going to present the whole comment both as text for the `help` and the +//! `long_help` argument. +//! +//! But if the doc comment is formatted like this example -- with an empty second line splitting the heading and +//! the rest of the comment -- only the first line is used as `help` argument. The `long_help` argument will +//! still contain the whole comment. +//! +//! ## Attention +//! +//! Any formatting next to empty lines that could be used inside a doc comment is currently not preserved. If +//! lists or other well formatted content is required it is necessary to use the related structopt argument with +//! a raw string as shown on the `third_flag` description. +//! -t, --third-flag +//! This is a raw string. +//! +//! It can be used to pass well formatted content (e.g. lists or source +//! code) in the description: +//! +//! - first example list entry +//! - second example list entry +//! +//! -V, --version +//! Prints version information +//! +//! +//! SUBCOMMANDS: +//! first The same rules described previously for flags. Are also true for in regards of sub-commands +//! help Prints this message or the help of the given subcommand(s) +//! second Applicable for both `about` an `help` +//! ----------------------------------------------------- + +use structopt::StructOpt; + +/// A basic example for the usage of doc comments as replacement +/// of the arguments `help`, `long_help`, `about` and `long_about`. +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + /// Just use doc comments to replace `help`, `long_help`, + /// `about` or `long_about` input. + #[structopt(short, long)] + first_flag: bool, + + /// Split between `help` and `long_help`. + /// + /// In the previous case structopt is going to present + /// the whole comment both as text for the `help` and the + /// `long_help` argument. + /// + /// But if the doc comment is formatted like this example + /// -- with an empty second line splitting the heading and + /// the rest of the comment -- only the first line is used + /// as `help` argument. The `long_help` argument will still + /// contain the whole comment. + /// + /// ## Attention + /// + /// Any formatting next to empty lines that could be used + /// inside a doc comment is currently not preserved. If + /// lists or other well formatted content is required it is + /// necessary to use the related structopt argument with a + /// raw string as shown on the `third_flag` description. + #[structopt(short, long)] + second_flag: bool, + + #[structopt( + short, + long, + long_help = r"This is a raw string. + +It can be used to pass well formatted content (e.g. lists or source +code) in the description: + + - first example list entry + - second example list entry + " + )] + third_flag: bool, + + #[structopt(subcommand)] + sub_command: SubCommand, +} + +#[derive(StructOpt, Debug)] +#[structopt()] +enum SubCommand { + /// The same rules described previously for flags. Are + /// also true for in regards of sub-commands. + First, + + /// Applicable for both `about` an `help`. + /// + /// The formatting rules described in the comment of the + /// `second_flag` also apply to the description of + /// sub-commands which is normally given through the `about` + /// and `long_about` arguments. + Second, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/examples/enum_in_args.rs b/vendor/structopt/examples/enum_in_args.rs new file mode 100644 index 0000000000000..0722140df6100 --- /dev/null +++ b/vendor/structopt/examples/enum_in_args.rs @@ -0,0 +1,40 @@ +//! How to use `arg_enum!` with `StructOpt`. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! structopt 0.3.25 +//! +//! USAGE: +//! enum_in_args +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! ARGS: +//! Important argument [possible values: Foo, Bar, FooBar] +//! ----------------------------------------------------- + +use clap::arg_enum; +use structopt::StructOpt; + +arg_enum! { + #[derive(Debug)] + enum Baz { + Foo, + Bar, + FooBar + } +} + +#[derive(StructOpt, Debug)] +struct Opt { + /// Important argument. + #[structopt(possible_values = &Baz::variants(), case_insensitive = true)] + i: Baz, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/examples/enum_in_args_with_strum.rs b/vendor/structopt/examples/enum_in_args_with_strum.rs new file mode 100644 index 0000000000000..7893e78eaeeb5 --- /dev/null +++ b/vendor/structopt/examples/enum_in_args_with_strum.rs @@ -0,0 +1,42 @@ +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! structopt 0.3.25 +//! +//! USAGE: +//! enum_in_args_with_strum [OPTIONS] +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! OPTIONS: +//! --format [default: txt] [possible values: txt, md, html] +//! ----------------------------------------------------- + +use structopt::StructOpt; +use strum::{EnumString, EnumVariantNames, VariantNames}; + +const DEFAULT: &str = "txt"; + +#[derive(StructOpt, Debug)] +struct Opt { + #[structopt( + long, + possible_values = Format::VARIANTS, + case_insensitive = true, + default_value = DEFAULT, + )] + format: Format, +} + +#[derive(EnumString, EnumVariantNames, Debug)] +#[strum(serialize_all = "kebab_case")] +enum Format { + Txt, + Md, + Html, +} + +fn main() { + println!("{:?}", Opt::from_args()); +} diff --git a/vendor/structopt/examples/enum_tuple.rs b/vendor/structopt/examples/enum_tuple.rs new file mode 100644 index 0000000000000..a88adc2e5ee57 --- /dev/null +++ b/vendor/structopt/examples/enum_tuple.rs @@ -0,0 +1,42 @@ +//! How to extract subcommands' args into external structs. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! classify 0.3.25 +//! +//! USAGE: +//! enum_tuple +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! SUBCOMMANDS: +//! foo +//! help Prints this message or the help of the given subcommand(s) +//! ----------------------------------------------------- + +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +pub struct Foo { + pub bar: Option, +} + +#[derive(Debug, StructOpt)] +pub enum Command { + #[structopt(name = "foo")] + Foo(Foo), +} + +#[derive(Debug, StructOpt)] +#[structopt(name = "classify")] +pub struct ApplicationArguments { + #[structopt(subcommand)] + pub command: Command, +} + +fn main() { + let opt = ApplicationArguments::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/examples/env.rs b/vendor/structopt/examples/env.rs new file mode 100644 index 0000000000000..437f3c6832698 --- /dev/null +++ b/vendor/structopt/examples/env.rs @@ -0,0 +1,43 @@ +//! How to use environment variable fallback an how it +//! interacts with `default_value`. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! env 0.3.25 +//! Example for allowing to specify options via environment variables +//! +//! USAGE: +//! env [OPTIONS] --api-url +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! OPTIONS: +//! --api-url URL for the API server [env: API_URL=] +//! --retries Number of retries [env: RETRIES=] [default: 5] +//! ----------------------------------------------------- + +use structopt::StructOpt; + +/// Example for allowing to specify options via environment variables. +#[derive(StructOpt, Debug)] +#[structopt(name = "env")] +struct Opt { + // Use `env` to enable specifying the option with an environment + // variable. Command line arguments take precedence over env. + /// URL for the API server + #[structopt(long, env = "API_URL")] + api_url: String, + + // The default value is used if neither argument nor environment + // variable is specified. + /// Number of retries + #[structopt(long, env = "RETRIES", default_value = "5")] + retries: u32, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:#?}", opt); +} diff --git a/vendor/structopt/examples/example.rs b/vendor/structopt/examples/example.rs new file mode 100644 index 0000000000000..4dfd341209e1e --- /dev/null +++ b/vendor/structopt/examples/example.rs @@ -0,0 +1,77 @@ +//! Somewhat complex example of usage of structopt. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! example 0.3.25 +//! An example of StructOpt usage +//! +//! USAGE: +//! example [FLAGS] [OPTIONS] [--] [output] +//! +//! FLAGS: +//! -d, --debug Activate debug mode +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! OPTIONS: +//! --log Log file, stdout if no file, no logging if not present +//! --optv ... +//! -s, --speed Set speed [default: 42] +//! +//! ARGS: +//! Input file +//! Output file, stdout if not present +//! ----------------------------------------------------- + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "example")] +/// An example of StructOpt usage. +struct Opt { + // A flag, true if used in the command line. + #[structopt(short, long)] + /// Activate debug mode + debug: bool, + + // An argument of type float, with a default value. + #[structopt(short, long, default_value = "42")] + /// Set speed + speed: f64, + + // Needed parameter, the first on the command line. + /// Input file + input: String, + + // An optional parameter, will be `None` if not present on the + // command line. + /// Output file, stdout if not present + output: Option, + + // An optional parameter with optional value, will be `None` if + // not present on the command line, will be `Some(None)` if no + // argument is provided (i.e. `--log`) and will be + // `Some(Some(String))` if argument is provided (e.g. `--log + // log.txt`). + #[structopt(long)] + #[allow(clippy::option_option)] + /// Log file, stdout if no file, no logging if not present + log: Option>, + + // An optional list of values, will be `None` if not present on + // the command line, will be `Some(vec![])` if no argument is + // provided (i.e. `--optv`) and will be `Some(Vec)` if + // argument list is provided (e.g. `--optv a b c`). + #[structopt(long)] + optv: Option>, + + // Skipped option: it won't be parsed and will be filled with the + // default value for its type (in this case it'll be an empty string). + #[structopt(skip)] + skipped: String, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/examples/flatten.rs b/vendor/structopt/examples/flatten.rs new file mode 100644 index 0000000000000..19208ec2b59c5 --- /dev/null +++ b/vendor/structopt/examples/flatten.rs @@ -0,0 +1,46 @@ +//! How to use flattening. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! structopt 0.3.25 +//! +//! USAGE: +//! flatten [FLAGS] -g -u +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! -v switch verbosity on +//! +//! OPTIONS: +//! -g daemon group +//! -u daemon user +//! ----------------------------------------------------- + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +struct Cmdline { + /// switch verbosity on + #[structopt(short)] + verbose: bool, + + #[structopt(flatten)] + daemon_opts: DaemonOpts, +} + +#[derive(StructOpt, Debug)] +struct DaemonOpts { + /// daemon user + #[structopt(short)] + user: String, + + /// daemon group + #[structopt(short)] + group: String, +} + +fn main() { + let opt = Cmdline::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/examples/gen_completions.rs b/vendor/structopt/examples/gen_completions.rs new file mode 100644 index 0000000000000..8e4326f2bc06d --- /dev/null +++ b/vendor/structopt/examples/gen_completions.rs @@ -0,0 +1,40 @@ +// Copyright 2019-present structopt developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! structopt 0.3.25 +//! An example of how to generate bash completions with structopt +//! +//! USAGE: +//! gen_completions [FLAGS] +//! +//! FLAGS: +//! -d, --debug Activate debug mode +//! -h, --help Prints help information +//! -V, --version Prints version information +//! ----------------------------------------------------- + +use structopt::clap::Shell; +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +/// An example of how to generate bash completions with structopt. +struct Opt { + #[structopt(short, long)] + /// Activate debug mode + debug: bool, +} + +fn main() { + // generate `bash` completions in "target" directory + Opt::clap().gen_completions(env!("CARGO_PKG_NAME"), Shell::Bash, "target"); + + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/examples/git.rs b/vendor/structopt/examples/git.rs new file mode 100644 index 0000000000000..6e4137bda48eb --- /dev/null +++ b/vendor/structopt/examples/git.rs @@ -0,0 +1,53 @@ +//! `git.rs` serves as a demonstration of how to use subcommands, +//! as well as a demonstration of adding documentation to subcommands. +//! Documentation can be added either through doc comments or +//! `help`/`about` attributes. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! git 0.3.25 +//! the stupid content tracker +//! +//! USAGE: +//! git +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! SUBCOMMANDS: +//! add +//! fetch fetch branches from remote repository +//! help Prints this message or the help of the given subcommand(s) +//! ----------------------------------------------------- + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "git")] +/// the stupid content tracker +enum Opt { + /// fetch branches from remote repository + Fetch { + #[structopt(long)] + dry_run: bool, + #[structopt(long)] + all: bool, + #[structopt(default_value = "origin")] + repository: String, + }, + #[structopt(help = "add files to the staging area")] + Add { + #[structopt(short)] + interactive: bool, + #[structopt(short)] + all: bool, + files: Vec, + }, +} + +fn main() { + let matches = Opt::from_args(); + + println!("{:?}", matches); +} diff --git a/vendor/structopt/examples/group.rs b/vendor/structopt/examples/group.rs new file mode 100644 index 0000000000000..16ca366566b5e --- /dev/null +++ b/vendor/structopt/examples/group.rs @@ -0,0 +1,51 @@ +//! How to use `clap::Arg::group` +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! structopt 0.3.25 +//! +//! USAGE: +//! group [OPTIONS] <--method |--get|--head|--post|--put|--delete> +//! +//! FLAGS: +//! --delete HTTP DELETE +//! --get HTTP GET +//! -h, --help Prints help information +//! --head HTTP HEAD +//! --post HTTP POST +//! --put HTTP PUT +//! -V, --version Prints version information +//! +//! OPTIONS: +//! --method Set a custom HTTP verb +//! ----------------------------------------------------- + +use structopt::{clap::ArgGroup, StructOpt}; + +#[derive(StructOpt, Debug)] +#[structopt(group = ArgGroup::with_name("verb").required(true))] +struct Opt { + /// Set a custom HTTP verb + #[structopt(long, group = "verb")] + method: Option, + /// HTTP GET + #[structopt(long, group = "verb")] + get: bool, + /// HTTP HEAD + #[structopt(long, group = "verb")] + head: bool, + /// HTTP POST + #[structopt(long, group = "verb")] + post: bool, + /// HTTP PUT + #[structopt(long, group = "verb")] + put: bool, + /// HTTP DELETE + #[structopt(long, group = "verb")] + delete: bool, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/examples/keyvalue.rs b/vendor/structopt/examples/keyvalue.rs new file mode 100644 index 0000000000000..92acafaa78282 --- /dev/null +++ b/vendor/structopt/examples/keyvalue.rs @@ -0,0 +1,51 @@ +//! How to parse "key=value" pairs with structopt. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! structopt 0.3.25 +//! +//! USAGE: +//! keyvalue [OPTIONS] +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! OPTIONS: +//! -D ... +//! ----------------------------------------------------- + +use std::error::Error; +use structopt::StructOpt; + +/// Parse a single key-value pair +fn parse_key_val(s: &str) -> Result<(T, U), Box> +where + T: std::str::FromStr, + T::Err: Error + 'static, + U: std::str::FromStr, + U::Err: Error + 'static, +{ + let pos = s + .find('=') + .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{}`", s))?; + Ok((s[..pos].parse()?, s[pos + 1..].parse()?)) +} + +#[derive(StructOpt, Debug)] +struct Opt { + // number_of_values = 1 forces the user to repeat the -D option for each key-value pair: + // my_program -D a=1 -D b=2 + // Without number_of_values = 1 you can do: + // my_program -D a=1 b=2 + // but this makes adding an argument after the values impossible: + // my_program -D a=1 -D b=2 my_input_file + // becomes invalid. + #[structopt(short = "D", parse(try_from_str = parse_key_val), number_of_values = 1)] + defines: Vec<(String, i32)>, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/examples/negative_flag.rs b/vendor/structopt/examples/negative_flag.rs new file mode 100644 index 0000000000000..0d9337c84e9dc --- /dev/null +++ b/vendor/structopt/examples/negative_flag.rs @@ -0,0 +1,28 @@ +//! How to add `no-thing` flag which is `true` by default and +//! `false` if passed. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! structopt 0.3.25 +//! +//! USAGE: +//! negative_flag [FLAGS] +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! --no-verbose +//! ----------------------------------------------------- + +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +struct Opt { + #[structopt(long = "no-verbose", parse(from_flag = std::ops::Not::not))] + verbose: bool, +} + +fn main() { + let cmd = Opt::from_args(); + println!("{:#?}", cmd); +} diff --git a/vendor/structopt/examples/no_version.rs b/vendor/structopt/examples/no_version.rs new file mode 100644 index 0000000000000..5fc6274ea5e62 --- /dev/null +++ b/vendor/structopt/examples/no_version.rs @@ -0,0 +1,28 @@ +//! How to completely remove version. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! no_version +//! +//! USAGE: +//! no_version +//! +//! FLAGS: +//! -h, --help Prints help information +//! ----------------------------------------------------- + +use structopt::clap::AppSettings; +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt( + name = "no_version", + no_version, + global_settings = &[AppSettings::DisableVersion] +)] +struct Opt {} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/examples/rename_all.rs b/vendor/structopt/examples/rename_all.rs new file mode 100644 index 0000000000000..6958c016b7b48 --- /dev/null +++ b/vendor/structopt/examples/rename_all.rs @@ -0,0 +1,95 @@ +//! Example on how the `rename_all` parameter works. +//! +//! `rename_all` can be used to override the casing style used during argument +//! generation. By default the `kebab-case` style will be used but there are a wide +//! variety of other styles available. +//! +//! ## Supported styles overview: +//! +//! - **Camel Case**: Indicate word boundaries with uppercase letter, excluding +//! the first word. +//! - **Kebab Case**: Keep all letters lowercase and indicate word boundaries +//! with hyphens. +//! - **Pascal Case**: Indicate word boundaries with uppercase letter, +//! including the first word. +//! - **Screaming Snake Case**: Keep all letters uppercase and indicate word +//! boundaries with underscores. +//! - **Snake Case**: Keep all letters lowercase and indicate word boundaries +//! with underscores. +//! - **Verbatim**: Use the original attribute name defined in the code. +//! +//! - **Lower Case**: Keep all letters lowercase and remove word boundaries. +//! +//! - **Upper Case**: Keep all letters uppercase and remove word boundaries. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! rename_all 0.3.25 +//! +//! USAGE: +//! rename_all +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! SUBCOMMANDS: +//! FIRST_COMMAND A screaming loud first command. Only use if necessary +//! SecondCommand Not nearly as loud as the first command +//! help Prints this message or the help of the given subcommand(s) +//! ----------------------------------------------------- + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "rename_all", rename_all = "screaming_snake_case")] +enum Opt { + // This subcommand will be named `FIRST_COMMAND`. As the command doesn't + // override the initial casing style, ... + /// A screaming loud first command. Only use if necessary. + FirstCommand { + // this flag will be available as `--FOO` and `-F`. + /// This flag will even scream louder. + #[structopt(long, short)] + foo: bool, + }, + + // As we override the casing style for this variant the related subcommand + // will be named `SecondCommand`. + /// Not nearly as loud as the first command. + #[structopt(rename_all = "pascal_case")] + SecondCommand { + // We can also override it again on a single field. + /// Nice quiet flag. No one is annoyed. + #[structopt(rename_all = "snake_case", long)] + bar_option: bool, + + // Renaming will not be propagated into subcommand flagged enums. If + // a non default casing style is required it must be defined on the + // enum itself. + #[structopt(subcommand)] + cmds: Subcommands, + + // or flattened structs. + #[structopt(flatten)] + options: BonusOptions, + }, +} + +#[derive(StructOpt, Debug)] +enum Subcommands { + // This one will be available as `first-subcommand`. + FirstSubcommand, +} + +#[derive(StructOpt, Debug)] +struct BonusOptions { + // And this one will be available as `baz-option`. + #[structopt(long)] + baz_option: bool, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/examples/required_if.rs b/vendor/structopt/examples/required_if.rs new file mode 100644 index 0000000000000..e3497b2712124 --- /dev/null +++ b/vendor/structopt/examples/required_if.rs @@ -0,0 +1,62 @@ +//! How to use `required_if` with structopt. +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! structopt 0.3.25 +//! +//! USAGE: +//! required_if -o [FILE] +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! OPTIONS: +//! -o Where to write the output: to `stdout` or `file` +//! +//! ARGS: +//! File name: only required when `out-type` is set to `file` +//! ----------------------------------------------------- + +use structopt::StructOpt; + +#[derive(Debug, StructOpt, PartialEq)] +struct Opt { + /// Where to write the output: to `stdout` or `file` + #[structopt(short)] + out_type: String, + + /// File name: only required when `out-type` is set to `file` + #[structopt(name = "FILE", required_if("out-type", "file"))] + file_name: Option, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_opt_out_type_file_without_file_name_returns_err() { + let opt = Opt::from_iter_safe(&["test", "-o", "file"]); + let err = opt.unwrap_err(); + assert_eq!(err.kind, clap::ErrorKind::MissingRequiredArgument); + } + + #[test] + fn test_opt_out_type_file_with_file_name_returns_ok() { + let opt = Opt::from_iter_safe(&["test", "-o", "file", "filename"]); + let opt = opt.unwrap(); + assert_eq!( + opt, + Opt { + out_type: "file".into(), + file_name: Some("filename".into()), + } + ); + } +} diff --git a/vendor/structopt/examples/skip.rs b/vendor/structopt/examples/skip.rs new file mode 100644 index 0000000000000..1f44769fc1d28 --- /dev/null +++ b/vendor/structopt/examples/skip.rs @@ -0,0 +1,47 @@ +//! How to use `#[structopt(skip)]` + +use structopt::StructOpt; + +#[derive(StructOpt, Debug, PartialEq)] +pub struct Opt { + #[structopt(long, short)] + number: u32, + #[structopt(skip)] + k: Kind, + #[structopt(skip)] + v: Vec, + + #[structopt(skip = Kind::A)] + k2: Kind, + #[structopt(skip = vec![1, 2, 3])] + v2: Vec, + #[structopt(skip = "cake")] // &str implements Into + s: String, +} + +#[derive(Debug, PartialEq)] +enum Kind { + A, + B, +} + +impl Default for Kind { + fn default() -> Self { + return Kind::B; + } +} + +fn main() { + assert_eq!( + Opt::from_iter(&["test", "-n", "10"]), + Opt { + number: 10, + k: Kind::B, + v: vec![], + + k2: Kind::A, + v2: vec![1, 2, 3], + s: String::from("cake") + } + ); +} diff --git a/vendor/structopt/examples/subcommand_aliases.rs b/vendor/structopt/examples/subcommand_aliases.rs new file mode 100644 index 0000000000000..1837ddbfcfefc --- /dev/null +++ b/vendor/structopt/examples/subcommand_aliases.rs @@ -0,0 +1,38 @@ +//! How to assign some aliases to subcommands +//! +//! Running this example with --help prints this message: +//! ----------------------------------------------------- +//! structopt 0.3.25 +//! +//! USAGE: +//! subcommand_aliases +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! SUBCOMMANDS: +//! bar +//! foo +//! help Prints this message or the help of the given subcommand(s) +//! ----------------------------------------------------- + +use structopt::clap::AppSettings; +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +// https://docs.rs/clap/2/clap/enum.AppSettings.html#variant.InferSubcommands +#[structopt(setting = AppSettings::InferSubcommands)] +enum Opt { + // https://docs.rs/clap/2/clap/struct.App.html#method.alias + #[structopt(alias = "foobar")] + Foo, + // https://docs.rs/clap/2/clap/struct.App.html#method.aliases + #[structopt(aliases = &["baz", "fizz"])] + Bar, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/examples/true_or_false.rs b/vendor/structopt/examples/true_or_false.rs new file mode 100644 index 0000000000000..814f3d8c252eb --- /dev/null +++ b/vendor/structopt/examples/true_or_false.rs @@ -0,0 +1,41 @@ +//! How to parse `--foo=true --bar=false` and turn them into bool. + +use structopt::StructOpt; + +fn true_or_false(s: &str) -> Result { + match s { + "true" => Ok(true), + "false" => Ok(false), + _ => Err("expected `true` or `false`"), + } +} + +#[derive(StructOpt, Debug, PartialEq)] +struct Opt { + // Default parser for `try_from_str` is FromStr::from_str. + // `impl FromStr for bool` parses `true` or `false` so this + // works as expected. + #[structopt(long, parse(try_from_str))] + foo: bool, + + // Of course, this could be done with an explicit parser function. + #[structopt(long, parse(try_from_str = true_or_false))] + bar: bool, + + // `bool` can be positional only with explicit `parse(...)` annotation + #[structopt(parse(try_from_str))] + boom: bool, +} + +fn main() { + assert_eq!( + Opt::from_iter(&["test", "--foo=true", "--bar=false", "true"]), + Opt { + foo: true, + bar: false, + boom: true + } + ); + // no beauty, only truth and falseness + assert!(Opt::from_iter_safe(&["test", "--foo=beauty"]).is_err()); +} diff --git a/vendor/structopt/link-check-headers.json b/vendor/structopt/link-check-headers.json new file mode 100644 index 0000000000000..c1bb24880bdb5 --- /dev/null +++ b/vendor/structopt/link-check-headers.json @@ -0,0 +1,14 @@ +{ + "httpHeaders": [ + { + "urls": [ + "https://", + "http://" + ], + "headers": { + "User-Agent": "broken links checker (https://github.com/TeXitoi/structopt)", + "Accept": "text/html" + } + } + ] +} diff --git a/vendor/structopt/src/lib.rs b/vendor/structopt/src/lib.rs new file mode 100644 index 0000000000000..92d93ab64d18b --- /dev/null +++ b/vendor/structopt/src/lib.rs @@ -0,0 +1,1238 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(missing_docs)] +#![forbid(unsafe_code)] + +//! This crate defines the `StructOpt` trait and its custom derive. +//! +//! ## Maintenance +//! +//! As clap v3 is now out, and the structopt features are integrated +//! into (almost as-is), structopt is now in maintenance mode: no new +//! feature will be added. +//! +//! Bugs will be fixed, and documentation improvements will be accepted. +//! +//! ## Features +//! +//! If you want to disable all the `clap` features (colors, +//! suggestions, ..) add `default-features = false` to the `structopt` +//! dependency: +//! +//! ```toml +//! [dependencies] +//! structopt = { version = "0.3", default-features = false } +//! ``` +//! +//! Support for [`paw`](https://github.com/rust-cli/paw) (the +//! `Command line argument paw-rser abstraction for main`) is disabled +//! by default, but can be enabled in the `structopt` dependency +//! with the feature `paw`: +//! +//! ```toml +//! [dependencies] +//! structopt = { version = "0.3", features = [ "paw" ] } +//! paw = "1.0" +//! ``` +//! +//! # Table of Contents +//! +//! - [How to `derive(StructOpt)`](#how-to-derivestructopt) +//! - [Attributes](#attributes) +//! - [Raw methods](#raw-methods) +//! - [Magical methods](#magical-methods) +//! - Arguments +//! - [Type magic](#type-magic) +//! - [Specifying argument types](#specifying-argument-types) +//! - [Default values](#default-values) +//! - [Help messages](#help-messages) +//! - [Environment variable fallback](#environment-variable-fallback) +//! - [Skipping fields](#skipping-fields) +//! - [Subcommands](#subcommands) +//! - [Optional subcommands](#optional-subcommands) +//! - [External subcommands](#external-subcommands) +//! - [Flattening subcommands](#flattening-subcommands) +//! - [Flattening](#flattening) +//! - [Custom string parsers](#custom-string-parsers) +//! - [Generics](#generics) +//! +//! +//! +//! ## How to `derive(StructOpt)` +//! +//! First, let's look at the example: +//! +//! ``` +//! use std::path::PathBuf; +//! use structopt::StructOpt; +//! +//! #[derive(Debug, StructOpt)] +//! #[structopt(name = "example", about = "An example of StructOpt usage.")] +//! struct Opt { +//! /// Activate debug mode +//! // short and long flags (-d, --debug) will be deduced from the field's name +//! #[structopt(short, long)] +//! debug: bool, +//! +//! /// Set speed +//! // we don't want to name it "speed", need to look smart +//! #[structopt(short = "v", long = "velocity", default_value = "42")] +//! speed: f64, +//! +//! /// Input file +//! #[structopt(parse(from_os_str))] +//! input: PathBuf, +//! +//! /// Output file, stdout if not present +//! #[structopt(parse(from_os_str))] +//! output: Option, +//! +//! /// Where to write the output: to `stdout` or `file` +//! #[structopt(short)] +//! out_type: String, +//! +//! /// File name: only required when `out-type` is set to `file` +//! #[structopt(name = "FILE", required_if("out-type", "file"))] +//! file_name: Option, +//! } +//! +//! fn main() { +//! # /* +//! let opt = Opt::from_args(); +//! # */ +//! # let opt = Opt::from_iter(&["binary", "-o", "stdout", "input"]); +//! println!("{:?}", opt); +//! } +//! ``` +//! +//! So `derive(StructOpt)` tells Rust to generate a command line parser, +//! and the various `structopt` attributes are simply +//! used for additional parameters. +//! +//! First, define a struct, whatever its name. This structure +//! corresponds to a `clap::App`, its fields correspond to `clap::Arg` +//! (unless they're [subcommands](#subcommands)), +//! and you can adjust these apps and args by `#[structopt(...)]` [attributes](#attributes). +//! +//! **Note:** +//! _________________ +//! Keep in mind that `StructOpt` trait is more than just `from_args` method. +//! It has a number of additional features, including access to underlying +//! `clap::App` via `StructOpt::clap()`. See the +//! [trait's reference documentation](trait.StructOpt.html). +//! _________________ +//! +//! ## Attributes +//! +//! You can control the way `structopt` translates your struct into an actual +//! [`clap::App`] invocation via `#[structopt(...)]` attributes. +//! +//! The attributes fall into two categories: +//! - `structopt`'s own [magical methods](#magical-methods). +//! +//! They are used by `structopt` itself. They come mostly in +//! `attr = ["whatever"]` form, but some `attr(args...)` also exist. +//! +//! - [`raw` attributes](#raw-methods). +//! +//! They represent explicit `clap::Arg/App` method calls. +//! They are what used to be explicit `#[structopt(raw(...))]` attrs in pre-0.3 `structopt` +//! +//! Every `structopt attribute` looks like comma-separated sequence of methods: +//! ``` +//! # #[derive(structopt::StructOpt)] struct S { +//! # +//! #[structopt( +//! short, // method with no arguments - always magical +//! long = "--long-option", // method with one argument +//! required_if("out", "file"), // method with one and more args +//! parse(from_os_str = path::to::parser) // some magical methods have their own syntax +//! )] +//! # +//! # s: () } mod path { pub(crate) mod to { pub(crate) fn parser(_: &std::ffi::OsStr) {} }} +//! ``` +//! +//! `#[structopt(...)]` attributes can be placed on top of `struct`, `enum`, +//! `struct` field or `enum` variant. Attributes on top of `struct` or `enum` +//! represent `clap::App` method calls, field or variant attributes correspond +//! to `clap::Arg` method calls. +//! +//! In other words, the `Opt` struct from the example above +//! will be turned into this (*details omitted*): +//! +//! ``` +//! # use structopt::clap::{Arg, App}; +//! App::new("example") +//! .version("0.2.0") +//! .about("An example of StructOpt usage.") +//! .arg(Arg::with_name("debug") +//! .help("Activate debug mode") +//! .short("debug") +//! .long("debug")) +//! .arg(Arg::with_name("speed") +//! .help("Set speed") +//! .short("v") +//! .long("velocity") +//! .default_value("42")) +//! // and so on +//! # ; +//! ``` +//! +//! ## Raw methods +//! +//! They are the reason why `structopt` is so flexible. **Every and each method from +//! `clap::App/Arg` can be used this way!** See the [`clap::App` +//! methods](https://docs.rs/clap/2/clap/struct.App.html) and [`clap::Arg` +//! methods](https://docs.rs/clap/2/clap/struct.Arg.html). +//! +//! ``` +//! # #[derive(structopt::StructOpt)] struct S { +//! # +//! #[structopt( +//! global = true, // name = arg form, neat for one-arg methods +//! required_if("out", "file") // name(arg1, arg2, ...) form. +//! )] +//! # +//! # s: String } +//! ``` +//! +//! The first form can only be used for methods which take only one argument. +//! The second form must be used with multi-arg methods, but can also be used with +//! single-arg methods. These forms are identical otherwise. +//! +//! As long as `method_name` is not one of the magical methods - +//! it will be translated into a mere method call. +//! +//! **Note:** +//! _________________ +//! +//! "Raw methods" are direct replacement for pre-0.3 structopt's +//! `#[structopt(raw(...))]` attributes, any time you would have used a `raw()` attribute +//! in 0.2 you should use raw method in 0.3. +//! +//! Unfortunately, old raw attributes collide with `clap::Arg::raw` method. To explicitly +//! warn users of this change we allow `#[structopt(raw())]` only with `true` or `false` +//! literals (this method is supposed to be called only with `true` anyway). +//! __________________ +//! +//! ## Magical methods +//! +//! They are the reason why `structopt` is so easy to use and convenient in most cases. +//! Many of them have defaults, some of them get used even if not mentioned. +//! +//! Methods may be used on "top level" (on top of a `struct`, `enum` or `enum` variant) +//! and/or on "field-level" (on top of a `struct` field or *inside* of an enum variant). +//! Top level (non-magical) methods correspond to `App::method` calls, field-level methods +//! are `Arg::method` calls. +//! +//! ```ignore +//! #[structopt(top_level)] +//! struct Foo { +//! #[structopt(field_level)] +//! field: u32 +//! } +//! +//! #[structopt(top_level)] +//! enum Bar { +//! #[structopt(top_level)] +//! Pineapple { +//! #[structopt(field_level)] +//! chocolate: String +//! }, +//! +//! #[structopt(top_level)] +//! Orange, +//! } +//! ``` +//! +//! - `name`: `[name = expr]` +//! - On top level: `App::new(expr)`. +//! +//! The binary name displayed in help messages. Defaults to the crate name given by Cargo. +//! +//! - On field-level: `Arg::with_name(expr)`. +//! +//! The name for the argument the field stands for, this name appears in help messages. +//! Defaults to a name, deduced from a field, see also +//! [`rename_all`](#specifying-argument-types). +//! +//! - `version`: `[version = "version"]` +//! +//! Usable only on top level: `App::version("version" or env!(CARGO_PKG_VERSION))`. +//! +//! The version displayed in help messages. +//! Defaults to the crate version given by Cargo. If `CARGO_PKG_VERSION` is not +//! set no `.version()` calls will be generated unless requested. +//! +//! - `no_version`: `no_version` +//! +//! Usable only on top level. Prevents default `App::version` call, i.e +//! when no `version = "version"` mentioned. +//! +//! - `author`: `author [= "author"]` +//! +//! Usable only on top level: `App::author("author" or env!(CARGO_PKG_AUTHORS))`. +//! +//! Author/maintainer of the binary, this name appears in help messages. +//! Defaults to the crate author given by cargo, but only when `author` explicitly mentioned. +//! +//! - `about`: `about [= "about"]` +//! +//! Usable only on top level: `App::about("about" or env!(CARGO_PKG_DESCRIPTION))`. +//! +//! Short description of the binary, appears in help messages. +//! Defaults to the crate description given by cargo, +//! but only when `about` explicitly mentioned. +//! +//! - [`short`](#specifying-argument-types): `short [= "short-opt-name"]` +//! +//! Usable only on field-level. +//! +//! - [`long`](#specifying-argument-types): `long [= "long-opt-name"]` +//! +//! Usable only on field-level. +//! +//! - [`default_value`](#default-values): `default_value [= "default value"]` +//! +//! Usable only on field-level. +//! +//! - [`rename_all`](#specifying-argument-types): +//! [`rename_all = "kebab"/"snake"/"screaming-snake"/"camel"/"pascal"/"verbatim"/"lower"/"upper"]` +//! +//! Usable both on top level and field level. +//! +//! - [`parse`](#custom-string-parsers): `parse(type [= path::to::parser::fn])` +//! +//! Usable only on field-level. +//! +//! - [`skip`](#skipping-fields): `skip [= expr]` +//! +//! Usable only on field-level. +//! +//! - [`flatten`](#flattening): `flatten` +//! +//! Usable on field-level or single-typed tuple variants. +//! +//! - [`subcommand`](#subcommands): `subcommand` +//! +//! Usable only on field-level. +//! +//! - [`external_subcommand`](#external-subcommands) +//! +//! Usable only on enum variants. +//! +//! - [`env`](#environment-variable-fallback): `env [= str_literal]` +//! +//! Usable only on field-level. +//! +//! - [`rename_all_env`](#auto-deriving-environment-variables): +//! [`rename_all_env = "kebab"/"snake"/"screaming-snake"/"camel"/"pascal"/"verbatim"/"lower"/"upper"]` +//! +//! Usable both on top level and field level. +//! +//! - [`verbatim_doc_comment`](#doc-comment-preprocessing-and-structoptverbatim_doc_comment): +//! `verbatim_doc_comment` +//! +//! Usable both on top level and field level. +//! +//! ## Type magic +//! +//! One of major things that makes `structopt` so awesome is its type magic. +//! Do you want optional positional argument? Use `Option`! Or perhaps optional argument +//! that optionally takes value (`[--opt=[val]]`)? Use `Option>`! +//! +//! Here is the table of types and `clap` methods they correspond to: +//! +//! Type | Effect | Added method call to `clap::Arg` +//! -----------------------------|---------------------------------------------------|-------------------------------------- +//! `bool` | `true` if the flag is present | `.takes_value(false).multiple(false)` +//! `Option` | optional positional argument or option | `.takes_value(true).multiple(false)` +//! `Option>` | optional option with optional value | `.takes_value(true).multiple(false).min_values(0).max_values(1)` +//! `Vec` | list of options or the other positional arguments | `.takes_value(true).multiple(true)` +//! `Option` | optional list of options | `.takes_values(true).multiple(true).min_values(0)` +//! `T: FromStr` | required option or positional argument | `.takes_value(true).multiple(false).required(!has_default)` +//! +//! The `FromStr` trait is used to convert the argument to the given +//! type, and the `Arg::validator` method is set to a method using +//! `to_string()` (`FromStr::Err` must implement `std::fmt::Display`). +//! If you would like to use a custom string parser other than `FromStr`, see +//! the [same titled section](#custom-string-parsers) below. +//! +//! **Important:** +//! _________________ +//! Pay attention that *only literal occurrence* of this types is special, for example +//! `Option` is special while `::std::option::Option` is not. +//! +//! If you need to avoid special casing you can make a `type` alias and +//! use it in place of the said type. +//! _________________ +//! +//! **Note:** +//! _________________ +//! `bool` cannot be used as positional argument unless you provide an explicit parser. +//! If you need a positional bool, for example to parse `true` or `false`, you must +//! annotate the field with explicit [`#[structopt(parse(...))]`](#custom-string-parsers). +//! _________________ +//! +//! Thus, the `speed` argument is generated as: +//! +//! ``` +//! # fn parse_validator(_: String) -> Result<(), String> { unimplemented!() } +//! clap::Arg::with_name("speed") +//! .takes_value(true) +//! .multiple(false) +//! .required(false) +//! .validator(parse_validator::) +//! .short("v") +//! .long("velocity") +//! .help("Set speed") +//! .default_value("42"); +//! ``` +//! +//! ## Specifying argument types +//! +//! There are three types of arguments that can be supplied to each +//! (sub-)command: +//! +//! - short (e.g. `-h`), +//! - long (e.g. `--help`) +//! - and positional. +//! +//! Like clap, structopt defaults to creating positional arguments. +//! +//! If you want to generate a long argument you can specify either +//! `long = $NAME`, or just `long` to get a long flag generated using +//! the field name. The generated casing style can be modified using +//! the `rename_all` attribute. See the `rename_all` example for more. +//! +//! For short arguments, `short` will use the first letter of the +//! field name by default, but just like the long option it's also +//! possible to use a custom letter through `short = $LETTER`. +//! +//! If an argument is renamed using `name = $NAME` any following call to +//! `short` or `long` will use the new name. +//! +//! **Attention**: If these arguments are used without an explicit name +//! the resulting flag is going to be renamed using `kebab-case` if the +//! `rename_all` attribute was not specified previously. The same is true +//! for subcommands with implicit naming through the related data structure. +//! +//! ``` +//! use structopt::StructOpt; +//! +//! #[derive(StructOpt)] +//! #[structopt(rename_all = "kebab-case")] +//! struct Opt { +//! /// This option can be specified with something like `--foo-option +//! /// value` or `--foo-option=value` +//! #[structopt(long)] +//! foo_option: String, +//! +//! /// This option can be specified with something like `-b value` (but +//! /// not `--bar-option value`). +//! #[structopt(short)] +//! bar_option: String, +//! +//! /// This option can be specified either `--baz value` or `-z value`. +//! #[structopt(short = "z", long = "baz")] +//! baz_option: String, +//! +//! /// This option can be specified either by `--custom value` or +//! /// `-c value`. +//! #[structopt(name = "custom", long, short)] +//! custom_option: String, +//! +//! /// This option is positional, meaning it is the first unadorned string +//! /// you provide (multiple others could follow). +//! my_positional: String, +//! +//! /// This option is skipped and will be filled with the default value +//! /// for its type (in this case 0). +//! #[structopt(skip)] +//! skipped: u32, +//! } +//! +//! # Opt::from_iter( +//! # &["test", "--foo-option", "", "-b", "", "--baz", "", "--custom", "", "positional"]); +//! ``` +//! +//! ## Default values +//! +//! In clap, default values for options can be specified via [`Arg::default_value`]. +//! +//! Of course, you can use as a raw method: +//! ``` +//! # use structopt::StructOpt; +//! #[derive(StructOpt)] +//! struct Opt { +//! #[structopt(default_value = "", long)] +//! prefix: String, +//! } +//! ``` +//! +//! This is quite mundane and error-prone to type the `"..."` default by yourself, +//! especially when the Rust ecosystem uses the [`Default`] trait for that. +//! It would be wonderful to have `structopt` to take the `Default_default` and fill it +//! for you. And yes, `structopt` can do that. +//! +//! Unfortunately, `default_value` takes `&str` but `Default::default` +//! gives us some `Self` value. We need to map `Self` to `&str` somehow. +//! +//! `structopt` solves this problem via [`ToString`] trait. +//! +//! To be able to use auto-default the type must implement *both* `Default` and `ToString`: +//! +//! ``` +//! # use structopt::StructOpt; +//! #[derive(StructOpt)] +//! struct Opt { +//! // just leave the `= "..."` part and structopt will figure it for you +//! #[structopt(default_value, long)] +//! prefix: String, // `String` implements both `Default` and `ToString` +//! } +//! ``` +//! +//! [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html +//! [`ToString`]: https://doc.rust-lang.org/std/string/trait.ToString.html +//! [`Arg::default_value`]: https://docs.rs/clap/2.33.0/clap/struct.Arg.html#method.default_value +//! +//! +//! ## Help messages +//! +//! In clap, help messages for the whole binary can be specified +//! via [`App::about`] and [`App::long_about`] while help messages +//! for individual arguments can be specified via [`Arg::help`] and [`Arg::long_help`]". +//! +//! `long_*` variants are used when user calls the program with +//! `--help` and "short" variants are used with `-h` flag. In `structopt`, +//! you can use them via [raw methods](#raw-methods), for example: +//! +//! ``` +//! # use structopt::StructOpt; +//! +//! #[derive(StructOpt)] +//! #[structopt(about = "I am a program and I work, just pass `-h`")] +//! struct Foo { +//! #[structopt(short, help = "Pass `-h` and you'll see me!")] +//! bar: String, +//! } +//! ``` +//! +//! For convenience, doc comments can be used instead of raw methods +//! (this example works exactly like the one above): +//! +//! ``` +//! # use structopt::StructOpt; +//! +//! #[derive(StructOpt)] +//! /// I am a program and I work, just pass `-h` +//! struct Foo { +//! /// Pass `-h` and you'll see me! +//! bar: String, +//! } +//! ``` +//! +//! Doc comments on [top-level](#magical-methods) will be turned into +//! `App::about/long_about` call (see below), doc comments on field-level are +//! `Arg::help/long_help` calls. +//! +//! **Important:** +//! _________________ +//! +//! Raw methods have priority over doc comments! +//! +//! **Top level doc comments always generate `App::about/long_about` calls!** +//! If you really want to use the `App::help/long_help` methods (you likely don't), +//! use a raw method to override the `App::about` call generated from the doc comment. +//! __________________ +//! +//! ### `long_help` and `--help` +//! +//! A message passed to [`App::long_about`] or [`Arg::long_help`] will be displayed whenever +//! your program is called with `--help` instead of `-h`. Of course, you can +//! use them via raw methods as described [above](#help-messages). +//! +//! The more convenient way is to use a so-called "long" doc comment: +//! +//! ``` +//! # use structopt::StructOpt; +//! #[derive(StructOpt)] +//! /// Hi there, I'm Robo! +//! /// +//! /// I like beeping, stumbling, eating your electricity, +//! /// and making records of you singing in a shower. +//! /// Pay up, or I'll upload it to youtube! +//! struct Robo { +//! /// Call my brother SkyNet. +//! /// +//! /// I am artificial superintelligence. I won't rest +//! /// until I'll have destroyed humanity. Enjoy your +//! /// pathetic existence, you mere mortals. +//! #[structopt(long)] +//! kill_all_humans: bool, +//! } +//! ``` +//! +//! A long doc comment consists of three parts: +//! * Short summary +//! * A blank line (whitespace only) +//! * Detailed description, all the rest +//! +//! In other words, "long" doc comment consists of two or more paragraphs, +//! with the first being a summary and the rest being the detailed description. +//! +//! **A long comment will result in two method calls**, `help()` and +//! `long_help()`, so clap will display the summary with `-h` +//! and the whole help message on `--help` (see below). +//! +//! So, the example above will be turned into this (details omitted): +//! ``` +//! clap::App::new("") +//! .about("Hi there, I'm Robo!") +//! .long_about("Hi there, I'm Robo!\n\n\ +//! I like beeping, stumbling, eating your electricity,\ +//! and making records of you singing in a shower.\ +//! Pay up or I'll upload it to youtube!") +//! // args... +//! # ; +//! ``` +//! +//! ### `-h` vs `--help` (A.K.A `help()` vs `long_help()`) +//! +//! The `-h` flag is not the same as `--help`. +//! +//! -h corresponds to `Arg::help/App::about` and requests short "summary" messages +//! while --help corresponds to `Arg::long_help/App::long_about` and requests more +//! detailed, descriptive messages. +//! +//! It is entirely up to `clap` what happens if you used only one of +//! [`Arg::help`]/[`Arg::long_help`], see `clap`'s documentation for these methods. +//! +//! As of clap v2.33, if only a short message ([`Arg::help`]) or only +//! a long ([`Arg::long_help`]) message is provided, clap will use it +//! for both -h and --help. The same logic applies to `about/long_about`. +//! +//! ### Doc comment preprocessing and `#[structopt(verbatim_doc_comment)]` +//! +//! `structopt` applies some preprocessing to doc comments to ease the most common uses: +//! +//! * Strip leading and trailing whitespace from every line, if present. +//! +//! * Strip leading and trailing blank lines, if present. +//! +//! * Interpret each group of non-empty lines as a word-wrapped paragraph. +//! +//! We replace newlines within paragraphs with spaces to allow the output +//! to be re-wrapped to the terminal width. +//! +//! * Strip any excess blank lines so that there is exactly one per paragraph break. +//! +//! * If the first paragraph ends in exactly one period, +//! remove the trailing period (i.e. strip trailing periods but not trailing ellipses). +//! +//! Sometimes you don't want this preprocessing to apply, for example the comment contains +//! some ASCII art or markdown tables, you would need to preserve LFs along with +//! blank lines and the leading/trailing whitespace. You can ask `structopt` to preserve them +//! via `#[structopt(verbatim_doc_comment)]` attribute. +//! +//! **This attribute must be applied to each field separately**, there's no global switch. +//! +//! **Important:** +//! ______________ +//! Keep in mind that `structopt` will *still* remove one leading space from each +//! line, even if this attribute is present, to allow for a space between +//! `///` and the content. +//! +//! Also, `structopt` will *still* remove leading and trailing blank lines so +//! these formats are equivalent: +//! +//! ``` +//! /** This is a doc comment +//! +//! Hello! */ +//! +//! /** +//! This is a doc comment +//! +//! Hello! +//! */ +//! +//! /// This is a doc comment +//! /// +//! /// Hello! +//! # +//! # mod m {} +//! ``` +//! ______________ +//! +//! [`App::about`]: https://docs.rs/clap/2/clap/struct.App.html#method.about +//! [`App::long_about`]: https://docs.rs/clap/2/clap/struct.App.html#method.long_about +//! [`Arg::help`]: https://docs.rs/clap/2/clap/struct.Arg.html#method.help +//! [`Arg::long_help`]: https://docs.rs/clap/2/clap/struct.Arg.html#method.long_help +//! +//! ## Environment variable fallback +//! +//! It is possible to specify an environment variable fallback option for an arguments +//! so that its value is taken from the specified environment variable if not +//! given through the command-line: +//! +//! ``` +//! # use structopt::StructOpt; +//! +//! #[derive(StructOpt)] +//! struct Foo { +//! #[structopt(short, long, env = "PARAMETER_VALUE")] +//! parameter_value: String, +//! } +//! ``` +//! +//! By default, values from the environment are shown in the help output (i.e. when invoking +//! `--help`): +//! +//! ```shell +//! $ cargo run -- --help +//! ... +//! OPTIONS: +//! -p, --parameter-value [env: PARAMETER_VALUE=env_value] +//! ``` +//! +//! In some cases this may be undesirable, for example when being used for passing +//! credentials or secret tokens. In those cases you can use `hide_env_values` to avoid +//! having structopt emit the actual secret values: +//! ``` +//! # use structopt::StructOpt; +//! +//! #[derive(StructOpt)] +//! struct Foo { +//! #[structopt(long = "secret", env = "SECRET_VALUE", hide_env_values = true)] +//! secret_value: String, +//! } +//! ``` +//! +//! ### Auto-deriving environment variables +//! +//! Environment variables tend to be called after the corresponding `struct`'s field, +//! as in example above. The field is `secret_value` and the env var is "SECRET_VALUE"; +//! the name is the same, except casing is different. +//! +//! It's pretty tedious and error-prone to type the same name twice, +//! so you can ask `structopt` to do that for you. +//! +//! ``` +//! # use structopt::StructOpt; +//! +//! #[derive(StructOpt)] +//! struct Foo { +//! #[structopt(long = "secret", env)] +//! secret_value: String, +//! } +//! ``` +//! +//! It works just like `#[structopt(short/long)]`: if `env` is not set to some concrete +//! value the value will be derived from the field's name. This is controlled by +//! `#[structopt(rename_all_env)]`. +//! +//! `rename_all_env` works exactly as `rename_all` (including overriding) +//! except default casing is `SCREAMING_SNAKE_CASE` instead of `kebab-case`. +//! +//! ## Skipping fields +//! +//! Sometimes you may want to add a field to your `Opt` struct that is not +//! a command line option and `clap` should know nothing about it. You can ask +//! `structopt` to skip the field entirely via `#[structopt(skip = value)]` +//! (`value` must implement `Into`) +//! or `#[structopt(skip)]` if you want assign the field with `Default::default()` +//! (obviously, the field's type must implement `Default`). +//! +//! ``` +//! # use structopt::StructOpt; +//! #[derive(StructOpt)] +//! pub struct Opt { +//! #[structopt(long, short)] +//! number: u32, +//! +//! // these fields are to be assigned with Default::default() +//! +//! #[structopt(skip)] +//! k: String, +//! #[structopt(skip)] +//! v: Vec, +//! +//! // these fields get set explicitly +//! +//! #[structopt(skip = vec![1, 2, 3])] +//! k2: Vec, +//! #[structopt(skip = "cake")] // &str implements Into +//! v2: String, +//! } +//! ``` +//! +//! ## Subcommands +//! +//! Some applications, especially large ones, split their functionality +//! through the use of "subcommands". Each of these act somewhat like a separate +//! command, but is part of the larger group. +//! One example is `git`, which has subcommands such as `add`, `commit`, +//! and `clone`, to mention just a few. +//! +//! `clap` has this functionality, and `structopt` supports it through enums: +//! +//! ``` +//! # use structopt::StructOpt; +//! +//! # use std::path::PathBuf; +//! #[derive(StructOpt)] +//! #[structopt(about = "the stupid content tracker")] +//! enum Git { +//! Add { +//! #[structopt(short)] +//! interactive: bool, +//! #[structopt(short)] +//! patch: bool, +//! #[structopt(parse(from_os_str))] +//! files: Vec, +//! }, +//! Fetch { +//! #[structopt(long)] +//! dry_run: bool, +//! #[structopt(long)] +//! all: bool, +//! repository: Option, +//! }, +//! Commit { +//! #[structopt(short)] +//! message: Option, +//! #[structopt(short)] +//! all: bool, +//! }, +//! } +//! ``` +//! +//! Using `derive(StructOpt)` on an enum instead of a struct will produce +//! a `clap::App` that only takes subcommands. So `git add`, `git fetch`, +//! and `git commit` would be commands allowed for the above example. +//! +//! `structopt` also provides support for applications where certain flags +//! need to apply to all subcommands, as well as nested subcommands: +//! +//! ``` +//! # use structopt::StructOpt; +//! #[derive(StructOpt)] +//! struct MakeCookie { +//! #[structopt(name = "supervisor", default_value = "Puck", long = "supervisor")] +//! supervising_faerie: String, +//! /// The faerie tree this cookie is being made in. +//! tree: Option, +//! #[structopt(subcommand)] // Note that we mark a field as a subcommand +//! cmd: Command, +//! } +//! +//! #[derive(StructOpt)] +//! enum Command { +//! /// Pound acorns into flour for cookie dough. +//! Pound { +//! acorns: u32, +//! }, +//! /// Add magical sparkles -- the secret ingredient! +//! Sparkle { +//! #[structopt(short, parse(from_occurrences))] +//! magicality: u64, +//! #[structopt(short)] +//! color: String, +//! }, +//! Finish(Finish), +//! } +//! +//! // Subcommand can also be externalized by using a 1-uple enum variant +//! #[derive(StructOpt)] +//! struct Finish { +//! #[structopt(short)] +//! time: u32, +//! #[structopt(subcommand)] // Note that we mark a field as a subcommand +//! finish_type: FinishType, +//! } +//! +//! // subsubcommand! +//! #[derive(StructOpt)] +//! enum FinishType { +//! Glaze { +//! applications: u32, +//! }, +//! Powder { +//! flavor: String, +//! dips: u32, +//! } +//! } +//! ``` +//! +//! Marking a field with `structopt(subcommand)` will add the subcommands of the +//! designated enum to the current `clap::App`. The designated enum *must* also +//! be derived `StructOpt`. So the above example would take the following +//! commands: +//! +//! + `make-cookie pound 50` +//! + `make-cookie sparkle -mmm --color "green"` +//! + `make-cookie finish 130 glaze 3` +//! +//! ### Optional subcommands +//! +//! Subcommands may be optional: +//! +//! ``` +//! # use structopt::StructOpt; +//! #[derive(StructOpt)] +//! struct Foo { +//! file: String, +//! #[structopt(subcommand)] +//! cmd: Option, +//! } +//! +//! #[derive(StructOpt)] +//! enum Command { +//! Bar, +//! Baz, +//! Quux, +//! } +//! ``` +//! +//! ### External subcommands +//! +//! Sometimes you want to support not only the set of well-known subcommands +//! but you also want to allow other, user-driven subcommands. `clap` supports +//! this via [`AppSettings::AllowExternalSubcommands`]. +//! +//! `structopt` provides it's own dedicated syntax for that: +//! +//! ``` +//! # use structopt::StructOpt; +//! #[derive(Debug, PartialEq, StructOpt)] +//! struct Opt { +//! #[structopt(subcommand)] +//! sub: Subcommands, +//! } +//! +//! #[derive(Debug, PartialEq, StructOpt)] +//! enum Subcommands { +//! // normal subcommand +//! Add, +//! +//! // `external_subcommand` tells structopt to put +//! // all the extra arguments into this Vec +//! #[structopt(external_subcommand)] +//! Other(Vec), +//! } +//! +//! // normal subcommand +//! assert_eq!( +//! Opt::from_iter(&["test", "add"]), +//! Opt { +//! sub: Subcommands::Add +//! } +//! ); +//! +//! assert_eq!( +//! Opt::from_iter(&["test", "git", "status"]), +//! Opt { +//! sub: Subcommands::Other(vec!["git".into(), "status".into()]) +//! } +//! ); +//! +//! // Please note that if you'd wanted to allow "no subcommands at all" case +//! // you should have used `sub: Option` above +//! assert!(Opt::from_iter_safe(&["test"]).is_err()); +//! ``` +//! +//! In other words, you just add an extra tuple variant marked with +//! `#[structopt(subcommand)]`, and its type must be either +//! `Vec` or `Vec`. `structopt` will detect `String` in this context +//! and use appropriate `clap` API. +//! +//! [`AppSettings::AllowExternalSubcommands`]: https://docs.rs/clap/2.32.0/clap/enum.AppSettings.html#variant.AllowExternalSubcommands +//! +//! ### Flattening subcommands +//! +//! It is also possible to combine multiple enums of subcommands into one. +//! All the subcommands will be on the same level. +//! +//! ``` +//! # use structopt::StructOpt; +//! #[derive(StructOpt)] +//! enum BaseCli { +//! Ghost10 { +//! arg1: i32, +//! } +//! } +//! +//! #[derive(StructOpt)] +//! enum Opt { +//! #[structopt(flatten)] +//! BaseCli(BaseCli), +//! Dex { +//! arg2: i32, +//! }, +//! } +//! ``` +//! +//! ```shell +//! cli ghost10 42 +//! cli dex 42 +//! ``` +//! +//! ## Flattening +//! +//! It can sometimes be useful to group related arguments in a substruct, +//! while keeping the command-line interface flat. In these cases you can mark +//! a field as `flatten` and give it another type that derives `StructOpt`: +//! +//! ``` +//! # use structopt::StructOpt; +//! #[derive(StructOpt)] +//! struct Cmdline { +//! /// switch on verbosity +//! #[structopt(short)] +//! verbose: bool, +//! #[structopt(flatten)] +//! daemon_opts: DaemonOpts, +//! } +//! +//! #[derive(StructOpt)] +//! struct DaemonOpts { +//! /// daemon user +//! #[structopt(short)] +//! user: String, +//! /// daemon group +//! #[structopt(short)] +//! group: String, +//! } +//! ``` +//! +//! In this example, the derived `Cmdline` parser will support the options `-v`, +//! `-u` and `-g`. +//! +//! This feature also makes it possible to define a `StructOpt` struct in a +//! library, parse the corresponding arguments in the main argument parser, and +//! pass off this struct to a handler provided by that library. +//! +//! ## Custom string parsers +//! +//! If the field type does not have a `FromStr` implementation, or you would +//! like to provide a custom parsing scheme other than `FromStr`, you may +//! provide a custom string parser using `parse(...)` like this: +//! +//! ``` +//! # use structopt::StructOpt; +//! use std::num::ParseIntError; +//! use std::path::PathBuf; +//! +//! fn parse_hex(src: &str) -> Result { +//! u32::from_str_radix(src, 16) +//! } +//! +//! #[derive(StructOpt)] +//! struct HexReader { +//! #[structopt(short, parse(try_from_str = parse_hex))] +//! number: u32, +//! #[structopt(short, parse(from_os_str))] +//! output: PathBuf, +//! } +//! ``` +//! +//! There are five kinds of custom parsers: +//! +//! | Kind | Signature | Default | +//! |-------------------|---------------------------------------|---------------------------------| +//! | `from_str` | `fn(&str) -> T` | `::std::convert::From::from` | +//! | `try_from_str` | `fn(&str) -> Result` | `::std::str::FromStr::from_str` | +//! | `from_os_str` | `fn(&OsStr) -> T` | `::std::convert::From::from` | +//! | `try_from_os_str` | `fn(&OsStr) -> Result` | (no default function) | +//! | `from_occurrences`| `fn(u64) -> T` | `value as T` | +//! | `from_flag` | `fn(bool) -> T` | `::std::convert::From::from` | +//! +//! The `from_occurrences` parser is special. Using `parse(from_occurrences)` +//! results in the _number of flags occurrences_ being stored in the relevant +//! field or being passed to the supplied function. In other words, it converts +//! something like `-vvv` to `3`. This is equivalent to +//! `.takes_value(false).multiple(true)`. Note that the default parser can only +//! be used with fields of integer types (`u8`, `usize`, `i64`, etc.). +//! +//! The `from_flag` parser is also special. Using `parse(from_flag)` or +//! `parse(from_flag = some_func)` will result in the field being treated as a +//! flag even if it does not have type `bool`. +//! +//! When supplying a custom string parser, `bool` will not be treated specially: +//! +//! Type | Effect | Added method call to `clap::Arg` +//! ------------|-------------------|-------------------------------------- +//! `Option` | optional argument | `.takes_value(true).multiple(false)` +//! `Vec` | list of arguments | `.takes_value(true).multiple(true)` +//! `T` | required argument | `.takes_value(true).multiple(false).required(!has_default)` +//! +//! In the `try_from_*` variants, the function will run twice on valid input: +//! once to validate, and once to parse. Hence, make sure the function is +//! side-effect-free. +//! +//! ## Generics +//! +//! Generic structs and enums can be used. They require explicit trait bounds +//! on any generic types that will be used by the `StructOpt` derive macro. In +//! some cases, associated types will require additional bounds. See the usage +//! of `FromStr` below for an example of this. +//! +//! ``` +//! # use structopt::StructOpt; +//! use std::{fmt, str::FromStr}; +//! +//! // a struct with single custom argument +//! #[derive(StructOpt)] +//! struct GenericArgs where ::Err: fmt::Display + fmt::Debug { +//! generic_arg_1: String, +//! generic_arg_2: String, +//! custom_arg_1: T, +//! } +//! ``` +//! +//! or +//! +//! ``` +//! # use structopt::StructOpt; +//! // a struct with multiple custom arguments in a substructure +//! #[derive(StructOpt)] +//! struct GenericArgs { +//! generic_arg_1: String, +//! generic_arg_2: String, +//! #[structopt(flatten)] +//! custom_args: T, +//! } +//! ``` + +// those mains are for a reason +#![allow(clippy::needless_doctest_main)] + +#[doc(hidden)] +pub use structopt_derive::*; + +use std::ffi::OsString; + +/// Re-exports +pub use clap; +#[cfg(feature = "paw")] +pub use paw_dep as paw; + +/// **This is NOT PUBLIC API**. +#[doc(hidden)] +pub use lazy_static; + +/// A struct that is converted from command line arguments. +pub trait StructOpt { + /// Returns [`clap::App`] corresponding to the struct. + fn clap<'a, 'b>() -> clap::App<'a, 'b>; + + /// Builds the struct from [`clap::ArgMatches`]. It's guaranteed to succeed + /// if `matches` originates from an `App` generated by [`StructOpt::clap`] called on + /// the same type, otherwise it must panic. + fn from_clap(matches: &clap::ArgMatches<'_>) -> Self; + + /// Builds the struct from the command line arguments ([`std::env::args_os`]). + /// Calls [`clap::Error::exit`] on failure, printing the error message and aborting the program. + fn from_args() -> Self + where + Self: Sized, + { + Self::from_clap(&Self::clap().get_matches()) + } + + /// Builds the struct from the command line arguments ([`std::env::args_os`]). + /// Unlike [`StructOpt::from_args`], returns [`clap::Error`] on failure instead of aborting the program, + /// so calling [`.exit`][clap::Error::exit] is up to you. + fn from_args_safe() -> Result + where + Self: Sized, + { + Self::clap() + .get_matches_safe() + .map(|matches| Self::from_clap(&matches)) + } + + /// Gets the struct from any iterator such as a `Vec` of your making. + /// Print the error message and quit the program in case of failure. + /// + /// **NOTE**: The first argument will be parsed as the binary name unless + /// [`clap::AppSettings::NoBinaryName`] has been used. + fn from_iter(iter: I) -> Self + where + Self: Sized, + I: IntoIterator, + I::Item: Into + Clone, + { + Self::from_clap(&Self::clap().get_matches_from(iter)) + } + + /// Gets the struct from any iterator such as a `Vec` of your making. + /// + /// Returns a [`clap::Error`] in case of failure. This does *not* exit in the + /// case of `--help` or `--version`, to achieve the same behavior as + /// [`from_iter()`][StructOpt::from_iter] you must call [`.exit()`][clap::Error::exit] on the error value. + /// + /// **NOTE**: The first argument will be parsed as the binary name unless + /// [`clap::AppSettings::NoBinaryName`] has been used. + fn from_iter_safe(iter: I) -> Result + where + Self: Sized, + I: IntoIterator, + I::Item: Into + Clone, + { + Ok(Self::from_clap(&Self::clap().get_matches_from_safe(iter)?)) + } +} + +/// This trait is NOT API. **SUBJECT TO CHANGE WITHOUT NOTICE!**. +#[doc(hidden)] +pub trait StructOptInternal: StructOpt { + fn augment_clap<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { + app + } + + fn is_subcommand() -> bool { + false + } + + fn from_subcommand<'a, 'b>(_sub: (&'b str, Option<&'b clap::ArgMatches<'a>>)) -> Option + where + Self: std::marker::Sized, + { + None + } +} + +impl StructOpt for Box { + fn clap<'a, 'b>() -> clap::App<'a, 'b> { + ::clap() + } + + fn from_clap(matches: &clap::ArgMatches<'_>) -> Self { + Box::new(::from_clap(matches)) + } +} + +impl StructOptInternal for Box { + #[doc(hidden)] + fn is_subcommand() -> bool { + ::is_subcommand() + } + + #[doc(hidden)] + fn from_subcommand<'a, 'b>(sub: (&'b str, Option<&'b clap::ArgMatches<'a>>)) -> Option { + ::from_subcommand(sub).map(Box::new) + } + + #[doc(hidden)] + fn augment_clap<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { + ::augment_clap(app) + } +} diff --git a/vendor/structopt/tests/argument_naming.rs b/vendor/structopt/tests/argument_naming.rs new file mode 100644 index 0000000000000..88b549db276c4 --- /dev/null +++ b/vendor/structopt/tests/argument_naming.rs @@ -0,0 +1,339 @@ +use structopt::StructOpt; + +#[test] +fn test_single_word_enum_variant_is_default_renamed_into_kebab_case() { + #[derive(StructOpt, Debug, PartialEq)] + enum Opt { + Command { foo: u32 }, + } + + assert_eq!( + Opt::Command { foo: 0 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "command", "0"])) + ); +} + +#[test] +fn test_multi_word_enum_variant_is_renamed() { + #[derive(StructOpt, Debug, PartialEq)] + enum Opt { + FirstCommand { foo: u32 }, + } + + assert_eq!( + Opt::FirstCommand { foo: 0 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "first-command", "0"])) + ); +} + +#[test] +fn test_standalone_long_generates_kebab_case() { + #[derive(StructOpt, Debug, PartialEq)] + #[allow(non_snake_case)] + struct Opt { + #[structopt(long)] + FOO_OPTION: bool, + } + + assert_eq!( + Opt { FOO_OPTION: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo-option"])) + ); +} + +#[test] +fn test_custom_long_overwrites_default_name() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(long = "foo")] + foo_option: bool, + } + + assert_eq!( + Opt { foo_option: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo"])) + ); +} + +#[test] +fn test_standalone_long_uses_previous_defined_custom_name() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(name = "foo", long)] + foo_option: bool, + } + + assert_eq!( + Opt { foo_option: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo"])) + ); +} + +#[test] +fn test_standalone_long_ignores_afterwards_defined_custom_name() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(long, name = "foo")] + foo_option: bool, + } + + assert_eq!( + Opt { foo_option: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo-option"])) + ); +} + +#[test] +fn test_standalone_short_generates_kebab_case() { + #[derive(StructOpt, Debug, PartialEq)] + #[allow(non_snake_case)] + struct Opt { + #[structopt(short)] + FOO_OPTION: bool, + } + + assert_eq!( + Opt { FOO_OPTION: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-f"])) + ); +} + +#[test] +fn test_custom_short_overwrites_default_name() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(short = "o")] + foo_option: bool, + } + + assert_eq!( + Opt { foo_option: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-o"])) + ); +} + +#[test] +fn test_standalone_short_uses_previous_defined_custom_name() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(name = "option", short)] + foo_option: bool, + } + + assert_eq!( + Opt { foo_option: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-o"])) + ); +} + +#[test] +fn test_standalone_short_ignores_afterwards_defined_custom_name() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(short, name = "option")] + foo_option: bool, + } + + assert_eq!( + Opt { foo_option: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-f"])) + ); +} + +#[test] +fn test_standalone_long_uses_previous_defined_casing() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(rename_all = "screaming_snake", long)] + foo_option: bool, + } + + assert_eq!( + Opt { foo_option: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--FOO_OPTION"])) + ); +} + +#[test] +fn test_standalone_short_uses_previous_defined_casing() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(rename_all = "screaming_snake", short)] + foo_option: bool, + } + + assert_eq!( + Opt { foo_option: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-F"])) + ); +} + +#[test] +fn test_standalone_long_works_with_verbatim_casing() { + #[derive(StructOpt, Debug, PartialEq)] + #[allow(non_snake_case)] + struct Opt { + #[structopt(rename_all = "verbatim", long)] + _fOO_oPtiON: bool, + } + + assert_eq!( + Opt { _fOO_oPtiON: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--_fOO_oPtiON"])) + ); +} + +#[test] +fn test_standalone_short_works_with_verbatim_casing() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(rename_all = "verbatim", short)] + _foo: bool, + } + + assert_eq!( + Opt { _foo: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-_"])) + ); +} + +#[test] +fn test_rename_all_is_propagated_from_struct_to_fields() { + #[derive(StructOpt, Debug, PartialEq)] + #[structopt(rename_all = "screaming_snake")] + struct Opt { + #[structopt(long)] + foo: bool, + } + + assert_eq!( + Opt { foo: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--FOO"])) + ); +} + +#[test] +fn test_rename_all_is_not_propagated_from_struct_into_flattened() { + #[derive(StructOpt, Debug, PartialEq)] + #[structopt(rename_all = "screaming_snake")] + struct Opt { + #[structopt(flatten)] + foo: Foo, + } + + #[derive(StructOpt, Debug, PartialEq)] + struct Foo { + #[structopt(long)] + foo: bool, + } + + assert_eq!( + Opt { + foo: Foo { foo: true } + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo"])) + ); +} + +#[test] +fn test_rename_all_is_not_propagated_from_struct_into_subcommand() { + #[derive(StructOpt, Debug, PartialEq)] + #[structopt(rename_all = "screaming_snake")] + struct Opt { + #[structopt(subcommand)] + foo: Foo, + } + + #[derive(StructOpt, Debug, PartialEq)] + enum Foo { + Command { + #[structopt(long)] + foo: bool, + }, + } + + assert_eq!( + Opt { + foo: Foo::Command { foo: true } + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "command", "--foo"])) + ); +} + +#[test] +fn test_rename_all_is_propagated_from_enum_to_variants_and_their_fields() { + #[derive(StructOpt, Debug, PartialEq)] + #[structopt(rename_all = "screaming_snake")] + enum Opt { + FirstVariant, + SecondVariant { + #[structopt(long)] + foo: bool, + }, + } + + assert_eq!( + Opt::FirstVariant, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "FIRST_VARIANT"])) + ); + + assert_eq!( + Opt::SecondVariant { foo: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "SECOND_VARIANT", "--FOO"])) + ); +} + +#[test] +fn test_rename_all_is_propagation_can_be_overridden() { + #[derive(StructOpt, Debug, PartialEq)] + #[structopt(rename_all = "screaming_snake")] + enum Opt { + #[structopt(rename_all = "kebab_case")] + FirstVariant { + #[structopt(long)] + foo_option: bool, + }, + SecondVariant { + #[structopt(rename_all = "kebab_case", long)] + foo_option: bool, + }, + } + + assert_eq!( + Opt::FirstVariant { foo_option: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "first-variant", "--foo-option"])) + ); + + assert_eq!( + Opt::SecondVariant { foo_option: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "SECOND_VARIANT", "--foo-option"])) + ); +} + +#[test] +fn test_lower_is_renamed() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(rename_all = "lower", long)] + foo_option: bool, + } + + assert_eq!( + Opt { foo_option: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foooption"])) + ); +} + +#[test] +fn test_upper_is_renamed() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(rename_all = "upper", long)] + foo_option: bool, + } + + assert_eq!( + Opt { foo_option: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--FOOOPTION"])) + ); +} diff --git a/vendor/structopt/tests/arguments.rs b/vendor/structopt/tests/arguments.rs new file mode 100644 index 0000000000000..96a0938256913 --- /dev/null +++ b/vendor/structopt/tests/arguments.rs @@ -0,0 +1,86 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::clap; +use structopt::StructOpt; + +#[test] +fn required_argument() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + arg: i32, + } + assert_eq!(Opt { arg: 42 }, Opt::from_iter(&["test", "42"])); + assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err()); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "42", "24"]) + .is_err()); +} + +#[test] +fn optional_argument() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + arg: Option, + } + assert_eq!(Opt { arg: Some(42) }, Opt::from_iter(&["test", "42"])); + assert_eq!(Opt { arg: None }, Opt::from_iter(&["test"])); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "42", "24"]) + .is_err()); +} + +#[test] +fn argument_with_default() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(default_value = "42")] + arg: i32, + } + assert_eq!(Opt { arg: 24 }, Opt::from_iter(&["test", "24"])); + assert_eq!(Opt { arg: 42 }, Opt::from_iter(&["test"])); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "42", "24"]) + .is_err()); +} + +#[test] +fn arguments() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + arg: Vec, + } + assert_eq!(Opt { arg: vec![24] }, Opt::from_iter(&["test", "24"])); + assert_eq!(Opt { arg: vec![] }, Opt::from_iter(&["test"])); + assert_eq!( + Opt { arg: vec![24, 42] }, + Opt::from_iter(&["test", "24", "42"]) + ); +} + +#[test] +fn arguments_safe() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + arg: Vec, + } + assert_eq!( + Opt { arg: vec![24] }, + Opt::from_iter_safe(&["test", "24"]).unwrap() + ); + assert_eq!(Opt { arg: vec![] }, Opt::from_iter_safe(&["test"]).unwrap()); + assert_eq!( + Opt { arg: vec![24, 42] }, + Opt::from_iter_safe(&["test", "24", "42"]).unwrap() + ); + + assert_eq!( + clap::ErrorKind::ValueValidation, + Opt::from_iter_safe(&["test", "NOPE"]).err().unwrap().kind + ); +} diff --git a/vendor/structopt/tests/author_version_about.rs b/vendor/structopt/tests/author_version_about.rs new file mode 100644 index 0000000000000..0f1c8b57cae33 --- /dev/null +++ b/vendor/structopt/tests/author_version_about.rs @@ -0,0 +1,58 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod utils; + +use structopt::StructOpt; +use utils::*; + +#[test] +fn no_author_version_about() { + #[derive(StructOpt, PartialEq, Debug)] + #[structopt(name = "foo", no_version)] + struct Opt {} + + let output = get_long_help::(); + assert!(output.starts_with("foo \n\nUSAGE:")); +} + +#[test] +fn use_env() { + #[derive(StructOpt, PartialEq, Debug)] + #[structopt(author, about)] + struct Opt {} + + let output = get_long_help::(); + assert!(output.starts_with("structopt 0.")); + assert!(output.contains("Guillaume Pinot , others")); + assert!(output.contains("Parse command line argument by defining a struct.")); +} + +#[test] +fn explicit_version_not_str() { + const VERSION: &str = "custom version"; + + #[derive(StructOpt)] + #[structopt(version = VERSION)] + pub struct Opt {} + + let output = get_long_help::(); + assert!(output.contains("custom version")); +} + +#[test] +fn no_version_gets_propagated() { + #[derive(StructOpt, PartialEq, Debug)] + #[structopt(no_version)] + enum Action { + Move, + } + + let output = get_subcommand_long_help::("move"); + assert_eq!(output.lines().next(), Some("test-move ")); +} diff --git a/vendor/structopt/tests/custom-string-parsers.rs b/vendor/structopt/tests/custom-string-parsers.rs new file mode 100644 index 0000000000000..8fe055be0219e --- /dev/null +++ b/vendor/structopt/tests/custom-string-parsers.rs @@ -0,0 +1,310 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +use std::ffi::{CString, OsStr, OsString}; +use std::num::ParseIntError; +use std::path::PathBuf; + +#[derive(StructOpt, PartialEq, Debug)] +struct PathOpt { + #[structopt(short, long, parse(from_os_str))] + path: PathBuf, + + #[structopt(short, default_value = "../", parse(from_os_str))] + default_path: PathBuf, + + #[structopt(short, parse(from_os_str))] + vector_path: Vec, + + #[structopt(short, parse(from_os_str))] + option_path_1: Option, + + #[structopt(short = "q", parse(from_os_str))] + option_path_2: Option, +} + +#[test] +fn test_path_opt_simple() { + assert_eq!( + PathOpt { + path: PathBuf::from("/usr/bin"), + default_path: PathBuf::from("../"), + vector_path: vec![ + PathBuf::from("/a/b/c"), + PathBuf::from("/d/e/f"), + PathBuf::from("/g/h/i"), + ], + option_path_1: None, + option_path_2: Some(PathBuf::from("j.zip")), + }, + PathOpt::from_clap(&PathOpt::clap().get_matches_from(&[ + "test", "-p", "/usr/bin", "-v", "/a/b/c", "-v", "/d/e/f", "-v", "/g/h/i", "-q", + "j.zip", + ])) + ); +} + +fn parse_hex(input: &str) -> Result { + u64::from_str_radix(input, 16) +} + +#[derive(StructOpt, PartialEq, Debug)] +struct HexOpt { + #[structopt(short, parse(try_from_str = parse_hex))] + number: u64, +} + +#[test] +#[allow(clippy::unreadable_literal)] +fn test_parse_hex() { + assert_eq!( + HexOpt { number: 5 }, + HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "5"])) + ); + assert_eq!( + HexOpt { number: 0xabcdef }, + HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "abcdef"])) + ); + + let err = HexOpt::clap() + .get_matches_from_safe(&["test", "-n", "gg"]) + .unwrap_err(); + assert!( + err.message.contains("invalid digit found in string"), + "{}", + err + ); +} + +fn custom_parser_1(_: &str) -> &'static str { + "A" +} +fn custom_parser_2(_: &str) -> Result<&'static str, u32> { + Ok("B") +} +fn custom_parser_3(_: &OsStr) -> &'static str { + "C" +} +fn custom_parser_4(_: &OsStr) -> Result<&'static str, OsString> { + Ok("D") +} + +#[derive(StructOpt, PartialEq, Debug)] +struct NoOpOpt { + #[structopt(short, parse(from_str = custom_parser_1))] + a: &'static str, + #[structopt(short, parse(try_from_str = custom_parser_2))] + b: &'static str, + #[structopt(short, parse(from_os_str = custom_parser_3))] + c: &'static str, + #[structopt(short, parse(try_from_os_str = custom_parser_4))] + d: &'static str, +} + +#[test] +fn test_every_custom_parser() { + assert_eq!( + NoOpOpt { + a: "A", + b: "B", + c: "C", + d: "D" + }, + NoOpOpt::from_clap( + &NoOpOpt::clap().get_matches_from(&["test", "-a=?", "-b=?", "-c=?", "-d=?"]) + ) + ); +} + +// Note: can't use `Vec` directly, as structopt would instead look for +// conversion function from `&str` to `u8`. +type Bytes = Vec; + +#[derive(StructOpt, PartialEq, Debug)] +struct DefaultedOpt { + #[structopt(short, parse(from_str))] + bytes: Bytes, + + #[structopt(short, parse(try_from_str))] + integer: u64, + + #[structopt(short, parse(from_os_str))] + path: PathBuf, +} + +#[test] +fn test_parser_with_default_value() { + assert_eq!( + DefaultedOpt { + bytes: b"E\xc2\xb2=p\xc2\xb2c\xc2\xb2+m\xc2\xb2c\xe2\x81\xb4".to_vec(), + integer: 9000, + path: PathBuf::from("src/lib.rs"), + }, + DefaultedOpt::from_clap(&DefaultedOpt::clap().get_matches_from(&[ + "test", + "-b", + "E²=p²c²+m²câ´", + "-i", + "9000", + "-p", + "src/lib.rs", + ])) + ); +} + +#[derive(PartialEq, Debug)] +struct Foo(u8); + +fn foo(value: u64) -> Foo { + Foo(value as u8) +} + +#[derive(StructOpt, PartialEq, Debug)] +struct Occurrences { + #[structopt(short, long, parse(from_occurrences))] + signed: i32, + + #[structopt(short, parse(from_occurrences))] + little_signed: i8, + + #[structopt(short, parse(from_occurrences))] + unsigned: usize, + + #[structopt(short = "r", parse(from_occurrences))] + little_unsigned: u8, + + #[structopt(short, long, parse(from_occurrences = foo))] + custom: Foo, +} + +#[test] +fn test_parser_occurrences() { + assert_eq!( + Occurrences { + signed: 3, + little_signed: 1, + unsigned: 0, + little_unsigned: 4, + custom: Foo(5), + }, + Occurrences::from_clap(&Occurrences::clap().get_matches_from(&[ + "test", "-s", "--signed", "--signed", "-l", "-rrrr", "-cccc", "--custom", + ])) + ); +} + +#[test] +fn test_custom_bool() { + fn parse_bool(s: &str) -> Result { + match s { + "true" => Ok(true), + "false" => Ok(false), + _ => Err(format!("invalid bool {}", s)), + } + } + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short, parse(try_from_str = parse_bool))] + debug: bool, + #[structopt( + short, + default_value = "false", + parse(try_from_str = parse_bool) + )] + verbose: bool, + #[structopt(short, parse(try_from_str = parse_bool))] + tribool: Option, + #[structopt(short, parse(try_from_str = parse_bool))] + bitset: Vec, + } + + assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err()); + assert!(Opt::clap().get_matches_from_safe(&["test", "-d"]).is_err()); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "-dfoo"]) + .is_err()); + assert_eq!( + Opt { + debug: false, + verbose: false, + tribool: None, + bitset: vec![], + }, + Opt::from_iter(&["test", "-dfalse"]) + ); + assert_eq!( + Opt { + debug: true, + verbose: false, + tribool: None, + bitset: vec![], + }, + Opt::from_iter(&["test", "-dtrue"]) + ); + assert_eq!( + Opt { + debug: true, + verbose: false, + tribool: None, + bitset: vec![], + }, + Opt::from_iter(&["test", "-dtrue", "-vfalse"]) + ); + assert_eq!( + Opt { + debug: true, + verbose: true, + tribool: None, + bitset: vec![], + }, + Opt::from_iter(&["test", "-dtrue", "-vtrue"]) + ); + assert_eq!( + Opt { + debug: true, + verbose: false, + tribool: Some(false), + bitset: vec![], + }, + Opt::from_iter(&["test", "-dtrue", "-tfalse"]) + ); + assert_eq!( + Opt { + debug: true, + verbose: false, + tribool: Some(true), + bitset: vec![], + }, + Opt::from_iter(&["test", "-dtrue", "-ttrue"]) + ); + assert_eq!( + Opt { + debug: true, + verbose: false, + tribool: None, + bitset: vec![false, true, false, false], + }, + Opt::from_iter(&["test", "-dtrue", "-bfalse", "-btrue", "-bfalse", "-bfalse"]) + ); +} + +#[test] +fn test_cstring() { + #[derive(StructOpt)] + struct Opt { + #[structopt(parse(try_from_str = CString::new))] + c_string: CString, + } + assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err()); + assert_eq!(Opt::from_iter(&["test", "bla"]).c_string.to_bytes(), b"bla"); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "bla\0bla"]) + .is_err()); +} diff --git a/vendor/structopt/tests/default_value.rs b/vendor/structopt/tests/default_value.rs new file mode 100644 index 0000000000000..383bd230740ed --- /dev/null +++ b/vendor/structopt/tests/default_value.rs @@ -0,0 +1,19 @@ +use structopt::StructOpt; + +mod utils; + +use utils::*; + +#[test] +fn auto_default_value() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(default_value)] + arg: i32, + } + assert_eq!(Opt { arg: 0 }, Opt::from_iter(&["test"])); + assert_eq!(Opt { arg: 1 }, Opt::from_iter(&["test", "1"])); + + let help = get_long_help::(); + assert!(help.contains("[default: 0]")); +} diff --git a/vendor/structopt/tests/deny-warnings.rs b/vendor/structopt/tests/deny-warnings.rs new file mode 100644 index 0000000000000..721204a49e11f --- /dev/null +++ b/vendor/structopt/tests/deny-warnings.rs @@ -0,0 +1,47 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(warnings)] + +use structopt::StructOpt; + +fn try_str(s: &str) -> Result { + Ok(s.into()) +} + +#[test] +fn warning_never_struct() { + #[derive(Debug, PartialEq, StructOpt)] + struct Opt { + #[structopt(parse(try_from_str = try_str))] + s: String, + } + assert_eq!( + Opt { + s: "foo".to_string() + }, + Opt::from_iter(&["test", "foo"]) + ); +} + +#[test] +fn warning_never_enum() { + #[derive(Debug, PartialEq, StructOpt)] + enum Opt { + Foo { + #[structopt(parse(try_from_str = try_str))] + s: String, + }, + } + assert_eq!( + Opt::Foo { + s: "foo".to_string() + }, + Opt::from_iter(&["test", "foo", "foo"]) + ); +} diff --git a/vendor/structopt/tests/doc-comments-help.rs b/vendor/structopt/tests/doc-comments-help.rs new file mode 100644 index 0000000000000..1d31683a78c3d --- /dev/null +++ b/vendor/structopt/tests/doc-comments-help.rs @@ -0,0 +1,185 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod utils; + +use structopt::StructOpt; +use utils::*; + +#[test] +fn doc_comments() { + /// Lorem ipsum + #[derive(StructOpt, PartialEq, Debug)] + struct LoremIpsum { + /// Fooify a bar + /// and a baz + #[structopt(short, long)] + foo: bool, + } + + let help = get_long_help::(); + assert!(help.contains("Lorem ipsum")); + assert!(help.contains("Fooify a bar and a baz")); +} + +#[test] +fn help_is_better_than_comments() { + /// Lorem ipsum + #[derive(StructOpt, PartialEq, Debug)] + #[structopt(name = "lorem-ipsum", about = "Dolor sit amet")] + struct LoremIpsum { + /// Fooify a bar + #[structopt(short, long, help = "DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES")] + foo: bool, + } + + let help = get_long_help::(); + assert!(help.contains("Dolor sit amet")); + assert!(!help.contains("Lorem ipsum")); + assert!(help.contains("DO NOT PASS A BAR")); +} + +#[test] +fn empty_line_in_doc_comment_is_double_linefeed() { + /// Foo. + /// + /// Bar + #[derive(StructOpt, PartialEq, Debug)] + #[structopt(name = "lorem-ipsum", no_version)] + struct LoremIpsum {} + + let help = get_long_help::(); + assert!(help.starts_with("lorem-ipsum \nFoo.\n\nBar\n\nUSAGE:")); +} + +#[test] +fn field_long_doc_comment_both_help_long_help() { + /// Lorem ipsumclap + #[derive(StructOpt, PartialEq, Debug)] + #[structopt(name = "lorem-ipsum", about = "Dolor sit amet")] + struct LoremIpsum { + /// Dot is removed from multiline comments. + /// + /// Long help + #[structopt(long)] + foo: bool, + + /// Dot is removed from one short comment. + #[structopt(long)] + bar: bool, + } + + let short_help = get_help::(); + let long_help = get_long_help::(); + + assert!(short_help.contains("Dot is removed from one short comment")); + assert!(!short_help.contains("Dot is removed from one short comment.")); + assert!(short_help.contains("Dot is removed from multiline comments")); + assert!(!short_help.contains("Dot is removed from multiline comments.")); + assert!(long_help.contains("Long help")); + assert!(!short_help.contains("Long help")); +} + +#[test] +fn top_long_doc_comment_both_help_long_help() { + /// Lorem ipsumclap + #[derive(StructOpt, Debug)] + #[structopt(name = "lorem-ipsum", about = "Dolor sit amet")] + struct LoremIpsum { + #[structopt(subcommand)] + foo: SubCommand, + } + + #[derive(StructOpt, Debug)] + pub enum SubCommand { + /// DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES + /// + /// Or something else + Foo { + #[structopt(help = "foo")] + bars: Vec, + }, + } + + let short_help = get_help::(); + let long_help = get_subcommand_long_help::("foo"); + + assert!(!short_help.contains("Or something else")); + assert!(long_help.contains("DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES")); + assert!(long_help.contains("Or something else")); +} + +#[test] +fn verbatim_doc_comment() { + /// DANCE! + /// + /// () + /// | + /// ( () ) + /// ) ________ // ) + /// () |\ \ // + /// ( \\__ \ ______\// + /// \__) | | + /// | | | + /// \ | | + /// \|_______| + /// // \\ + /// (( || + /// \\ || + /// ( () || + /// ( () ) ) + #[derive(StructOpt, Debug)] + #[structopt(verbatim_doc_comment)] + struct SeeFigure1 { + #[structopt(long)] + foo: bool, + } + + let help = get_long_help::(); + let sample = r#" + () + | + ( () ) + ) ________ // ) + () |\ \ // +( \\__ \ ______\// + \__) | | + | | | + \ | | + \|_______| + // \\ + (( || + \\ || + ( () || + ( () ) )"#; + + assert!(help.contains(sample)) +} + +#[test] +fn verbatim_doc_comment_field() { + #[derive(StructOpt, Debug)] + struct App { + /// This help ends in a period. + #[structopt(long, verbatim_doc_comment)] + foo: bool, + /// This help does not end in a period. + #[structopt(long)] + bar: bool, + } + + let help = get_long_help::(); + let sample = r#" + --bar + This help does not end in a period + + --foo + This help ends in a period."#; + + assert!(help.contains(sample)) +} diff --git a/vendor/structopt/tests/explicit_name_no_renaming.rs b/vendor/structopt/tests/explicit_name_no_renaming.rs new file mode 100644 index 0000000000000..eff7a86118202 --- /dev/null +++ b/vendor/structopt/tests/explicit_name_no_renaming.rs @@ -0,0 +1,32 @@ +mod utils; + +use structopt::StructOpt; +use utils::*; + +#[test] +fn explicit_short_long_no_rename() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short = ".", long = ".foo")] + foo: Vec, + } + + assert_eq!( + Opt { + foo: vec!["short".into(), "long".into()] + }, + Opt::from_iter(&["test", "-.", "short", "--.foo", "long"]) + ); +} + +#[test] +fn explicit_name_no_rename() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(name = ".options")] + foo: Vec, + } + + let help = get_long_help::(); + assert!(help.contains("[.options]...")) +} diff --git a/vendor/structopt/tests/flags.rs b/vendor/structopt/tests/flags.rs new file mode 100644 index 0000000000000..39a5dc3970000 --- /dev/null +++ b/vendor/structopt/tests/flags.rs @@ -0,0 +1,162 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[test] +fn unique_flag() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short, long)] + alice: bool, + } + + assert_eq!( + Opt { alice: false }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert_eq!( + Opt { alice: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"])) + ); + assert_eq!( + Opt { alice: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--alice"])) + ); + assert!(Opt::clap().get_matches_from_safe(&["test", "-i"]).is_err()); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "-a", "foo"]) + .is_err()); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "-a", "-a"]) + .is_err()); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "-a", "--alice"]) + .is_err()); +} + +#[test] +fn multiple_flag() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short, long, parse(from_occurrences))] + alice: u64, + #[structopt(short, long, parse(from_occurrences))] + bob: u8, + } + + assert_eq!( + Opt { alice: 0, bob: 0 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert_eq!( + Opt { alice: 1, bob: 0 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"])) + ); + assert_eq!( + Opt { alice: 2, bob: 0 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "-a"])) + ); + assert_eq!( + Opt { alice: 2, bob: 2 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "--alice", "-bb"])) + ); + assert_eq!( + Opt { alice: 3, bob: 1 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-aaa", "--bob"])) + ); + assert!(Opt::clap().get_matches_from_safe(&["test", "-i"]).is_err()); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "-a", "foo"]) + .is_err()); +} + +fn parse_from_flag(b: bool) -> std::sync::atomic::AtomicBool { + std::sync::atomic::AtomicBool::new(b) +} + +#[test] +fn non_bool_flags() { + #[derive(StructOpt, Debug)] + struct Opt { + #[structopt(short, long, parse(from_flag = parse_from_flag))] + alice: std::sync::atomic::AtomicBool, + #[structopt(short, long, parse(from_flag))] + bob: std::sync::atomic::AtomicBool, + } + + let falsey = Opt::from_clap(&Opt::clap().get_matches_from(&["test"])); + assert!(!falsey.alice.load(std::sync::atomic::Ordering::Relaxed)); + assert!(!falsey.bob.load(std::sync::atomic::Ordering::Relaxed)); + + let alice = Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"])); + assert!(alice.alice.load(std::sync::atomic::Ordering::Relaxed)); + assert!(!alice.bob.load(std::sync::atomic::Ordering::Relaxed)); + + let bob = Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-b"])); + assert!(!bob.alice.load(std::sync::atomic::Ordering::Relaxed)); + assert!(bob.bob.load(std::sync::atomic::Ordering::Relaxed)); + + let both = Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-b", "-a"])); + assert!(both.alice.load(std::sync::atomic::Ordering::Relaxed)); + assert!(both.bob.load(std::sync::atomic::Ordering::Relaxed)); +} + +#[test] +fn combined_flags() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short, long)] + alice: bool, + #[structopt(short, long, parse(from_occurrences))] + bob: u64, + } + + assert_eq!( + Opt { + alice: false, + bob: 0 + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert_eq!( + Opt { + alice: true, + bob: 0 + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"])) + ); + assert_eq!( + Opt { + alice: true, + bob: 0 + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"])) + ); + assert_eq!( + Opt { + alice: false, + bob: 1 + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-b"])) + ); + assert_eq!( + Opt { + alice: true, + bob: 1 + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--alice", "--bob"])) + ); + assert_eq!( + Opt { + alice: true, + bob: 4 + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-bb", "-a", "-bb"])) + ); +} diff --git a/vendor/structopt/tests/flatten.rs b/vendor/structopt/tests/flatten.rs new file mode 100644 index 0000000000000..05de1856ed8b4 --- /dev/null +++ b/vendor/structopt/tests/flatten.rs @@ -0,0 +1,182 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +mod utils; + +#[test] +fn flatten() { + #[derive(StructOpt, PartialEq, Debug)] + struct Common { + arg: i32, + } + + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(flatten)] + common: Common, + } + assert_eq!( + Opt { + common: Common { arg: 42 } + }, + Opt::from_iter(&["test", "42"]) + ); + assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err()); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "42", "24"]) + .is_err()); +} + +#[test] +#[should_panic] +fn flatten_twice() { + #[derive(StructOpt, PartialEq, Debug)] + struct Common { + arg: i32, + } + + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(flatten)] + c1: Common, + // Defines "arg" twice, so this should not work. + #[structopt(flatten)] + c2: Common, + } + Opt::from_iter(&["test", "42", "43"]); +} + +#[test] +fn flatten_in_subcommand() { + #[derive(StructOpt, PartialEq, Debug)] + struct Common { + arg: i32, + } + + #[derive(StructOpt, PartialEq, Debug)] + struct Add { + #[structopt(short)] + interactive: bool, + #[structopt(flatten)] + common: Common, + } + + #[derive(StructOpt, PartialEq, Debug)] + enum Opt { + Fetch { + #[structopt(short)] + all: bool, + #[structopt(flatten)] + common: Common, + }, + + Add(Add), + } + + assert_eq!( + Opt::Fetch { + all: false, + common: Common { arg: 42 } + }, + Opt::from_iter(&["test", "fetch", "42"]) + ); + assert_eq!( + Opt::Add(Add { + interactive: true, + common: Common { arg: 43 } + }), + Opt::from_iter(&["test", "add", "-i", "43"]) + ); +} + +#[test] +fn merge_subcommands_with_flatten() { + #[derive(StructOpt, PartialEq, Debug)] + enum BaseCli { + Command1(Command1), + } + + #[derive(StructOpt, PartialEq, Debug)] + struct Command1 { + arg1: i32, + } + + #[derive(StructOpt, PartialEq, Debug)] + struct Command2 { + arg2: i32, + } + + #[derive(StructOpt, PartialEq, Debug)] + enum Opt { + #[structopt(flatten)] + BaseCli(BaseCli), + Command2(Command2), + } + + assert_eq!( + Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 42 })), + Opt::from_iter(&["test", "command1", "42"]) + ); + assert_eq!( + Opt::Command2(Command2 { arg2: 43 }), + Opt::from_iter(&["test", "command2", "43"]) + ); +} + +#[test] +#[should_panic = "structopt misuse: You likely tried to #[flatten] a struct \ + that contains #[subcommand]. This is forbidden."] +fn subcommand_in_flatten() { + #[derive(Debug, StructOpt)] + pub enum Struct1 { + #[structopt(flatten)] + Struct1(Struct2), + } + + #[derive(Debug, StructOpt)] + pub struct Struct2 { + #[structopt(subcommand)] + command_type: Enum3, + } + + #[derive(Debug, StructOpt)] + pub enum Enum3 { + Command { args: Vec }, + } + + Struct1::from_iter(&["test", "command", "foo"]); +} + +#[test] +fn flatten_doc_comment() { + #[derive(StructOpt, PartialEq, Debug)] + struct Common { + /// This is an arg. Arg means "argument". Command line argument. + arg: i32, + } + + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + /// The very important comment that clippy had me put here. + /// It knows better. + #[structopt(flatten)] + common: Common, + } + assert_eq!( + Opt { + common: Common { arg: 42 } + }, + Opt::from_iter(&["test", "42"]) + ); + + let help = utils::get_help::(); + assert!(help.contains("This is an arg.")); + assert!(!help.contains("The very important")); +} diff --git a/vendor/structopt/tests/generics.rs b/vendor/structopt/tests/generics.rs new file mode 100644 index 0000000000000..0da349b324a17 --- /dev/null +++ b/vendor/structopt/tests/generics.rs @@ -0,0 +1,145 @@ +use structopt::StructOpt; + +#[test] +fn generic_struct_flatten() { + #[derive(StructOpt, PartialEq, Debug)] + struct Inner { + pub answer: isize, + } + + #[derive(StructOpt, PartialEq, Debug)] + struct Outer { + #[structopt(flatten)] + pub inner: T, + } + + assert_eq!( + Outer { + inner: Inner { answer: 42 } + }, + Outer::from_iter(&["--answer", "42"]) + ) +} + +#[test] +fn generic_struct_flatten_w_where_clause() { + #[derive(StructOpt, PartialEq, Debug)] + struct Inner { + pub answer: isize, + } + + #[derive(StructOpt, PartialEq, Debug)] + struct Outer + where + T: StructOpt, + { + #[structopt(flatten)] + pub inner: T, + } + + assert_eq!( + Outer { + inner: Inner { answer: 42 } + }, + Outer::from_iter(&["--answer", "42"]) + ) +} + +#[test] +fn generic_enum() { + #[derive(StructOpt, PartialEq, Debug)] + struct Inner { + pub answer: isize, + } + + #[derive(StructOpt, PartialEq, Debug)] + enum GenericEnum { + Start(T), + Stop, + } + + assert_eq!( + GenericEnum::Start(Inner { answer: 42 }), + GenericEnum::from_iter(&["test", "start", "42"]) + ) +} + +#[test] +fn generic_enum_w_where_clause() { + #[derive(StructOpt, PartialEq, Debug)] + struct Inner { + pub answer: isize, + } + + #[derive(StructOpt, PartialEq, Debug)] + enum GenericEnum + where + T: StructOpt, + { + Start(T), + Stop, + } + + assert_eq!( + GenericEnum::Start(Inner { answer: 42 }), + GenericEnum::from_iter(&["test", "start", "42"]) + ) +} + +#[test] +fn generic_w_fromstr_trait_bound() { + use std::{fmt, str::FromStr}; + + #[derive(StructOpt, PartialEq, Debug)] + struct Opt + where + T: FromStr, + ::Err: fmt::Debug + fmt::Display, + { + answer: T, + } + + assert_eq!( + Opt:: { answer: 42 }, + Opt::::from_iter(&["--answer", "42"]) + ) +} + +#[test] +fn generic_wo_trait_bound() { + use std::time::Duration; + + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + answer: isize, + #[structopt(skip)] + took: Option, + } + + assert_eq!( + Opt:: { + answer: 42, + took: None + }, + Opt::::from_iter(&["--answer", "42"]) + ) +} + +#[test] +fn generic_where_clause_w_trailing_comma() { + use std::{fmt, str::FromStr}; + + #[derive(StructOpt, PartialEq, Debug)] + struct Opt + where + T: FromStr, + ::Err: fmt::Debug + fmt::Display, + { + pub answer: T, + } + + assert_eq!( + Opt:: { answer: 42 }, + Opt::::from_iter(&["--answer", "42"]) + ) +} diff --git a/vendor/structopt/tests/issues.rs b/vendor/structopt/tests/issues.rs new file mode 100644 index 0000000000000..3f9e1af722197 --- /dev/null +++ b/vendor/structopt/tests/issues.rs @@ -0,0 +1,174 @@ +// https://github.com/TeXitoi/structopt/issues/{NUMBER} + +mod utils; +use utils::*; + +use structopt::StructOpt; + +#[test] +fn issue_151() { + use structopt::{clap::ArgGroup, StructOpt}; + + #[derive(StructOpt, Debug)] + #[structopt(group = ArgGroup::with_name("verb").required(true).multiple(true))] + struct Opt { + #[structopt(long, group = "verb")] + foo: bool, + #[structopt(long, group = "verb")] + bar: bool, + } + + #[derive(Debug, StructOpt)] + struct Cli { + #[structopt(flatten)] + a: Opt, + } + + assert!(Cli::clap().get_matches_from_safe(&["test"]).is_err()); + assert!(Cli::clap() + .get_matches_from_safe(&["test", "--foo"]) + .is_ok()); + assert!(Cli::clap() + .get_matches_from_safe(&["test", "--bar"]) + .is_ok()); + assert!(Cli::clap() + .get_matches_from_safe(&["test", "--zebra"]) + .is_err()); + assert!(Cli::clap() + .get_matches_from_safe(&["test", "--foo", "--bar"]) + .is_ok()); +} + +#[test] +fn issue_289() { + use structopt::{clap::AppSettings, StructOpt}; + + #[derive(StructOpt)] + #[structopt(setting = AppSettings::InferSubcommands)] + enum Args { + SomeCommand(SubSubCommand), + AnotherCommand, + } + + #[derive(StructOpt)] + #[structopt(setting = AppSettings::InferSubcommands)] + enum SubSubCommand { + TestCommand, + } + + assert!(Args::clap() + .get_matches_from_safe(&["test", "some-command", "test-command"]) + .is_ok()); + assert!(Args::clap() + .get_matches_from_safe(&["test", "some", "test-command"]) + .is_ok()); + assert!(Args::clap() + .get_matches_from_safe(&["test", "some-command", "test"]) + .is_ok()); + assert!(Args::clap() + .get_matches_from_safe(&["test", "some", "test"]) + .is_ok()); +} + +#[test] +fn issue_324() { + fn my_version() -> &'static str { + "MY_VERSION" + } + + #[derive(StructOpt)] + #[structopt(version = my_version())] + struct Opt { + #[structopt(subcommand)] + _cmd: Option, + } + + #[derive(StructOpt)] + enum SubCommand { + Start, + } + + let help = get_long_help::(); + assert!(help.contains("MY_VERSION")); +} + +#[test] +fn issue_359() { + #[derive(Debug, PartialEq, StructOpt)] + struct Opt { + #[structopt(subcommand)] + sub: Subcommands, + } + + #[derive(Debug, PartialEq, StructOpt)] + enum Subcommands { + Add, + + #[structopt(external_subcommand)] + Other(Vec), + } + + assert_eq!( + Opt { + sub: Subcommands::Other(vec!["only_one_arg".into()]) + }, + Opt::from_iter(&["test", "only_one_arg"]) + ); +} + +#[test] +fn issue_418() { + use structopt::StructOpt; + + #[derive(Debug, StructOpt)] + struct Opts { + #[structopt(subcommand)] + /// The command to run + command: Command, + } + + #[derive(Debug, StructOpt)] + enum Command { + /// Reticulate the splines + #[structopt(visible_alias = "ret")] + Reticulate { + /// How many splines + num_splines: u8, + }, + /// Frobnicate the rest + #[structopt(visible_alias = "frob")] + Frobnicate, + } + + let help = get_long_help::(); + assert!(help.contains("Reticulate the splines [aliases: ret]")); +} + +#[test] +fn issue_490() { + use std::iter::FromIterator; + use std::str::FromStr; + use structopt::StructOpt; + + struct U16ish; + impl FromStr for U16ish { + type Err = (); + fn from_str(_: &str) -> Result { + unimplemented!() + } + } + impl<'a> FromIterator<&'a U16ish> for Vec { + fn from_iter>(_: T) -> Self { + unimplemented!() + } + } + + #[derive(StructOpt, Debug)] + struct Opt { + opt_vec: Vec, + #[structopt(long)] + opt_opt_vec: Option>, + } + + // Assert that it compiles +} diff --git a/vendor/structopt/tests/macro-errors.rs b/vendor/structopt/tests/macro-errors.rs new file mode 100644 index 0000000000000..74342f74aafda --- /dev/null +++ b/vendor/structopt/tests/macro-errors.rs @@ -0,0 +1,13 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed + +#[rustversion::attr(any(not(stable), before(1.54)), ignore)] +#[test] +fn ui() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/ui/*.rs"); +} diff --git a/vendor/structopt/tests/nested-subcommands.rs b/vendor/structopt/tests/nested-subcommands.rs new file mode 100644 index 0000000000000..1fbd1666f7682 --- /dev/null +++ b/vendor/structopt/tests/nested-subcommands.rs @@ -0,0 +1,193 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, PartialEq, Debug)] +struct Opt { + #[structopt(short, long)] + force: bool, + #[structopt(short, long, parse(from_occurrences))] + verbose: u64, + #[structopt(subcommand)] + cmd: Sub, +} + +#[derive(StructOpt, PartialEq, Debug)] +enum Sub { + Fetch {}, + Add {}, +} + +#[derive(StructOpt, PartialEq, Debug)] +struct Opt2 { + #[structopt(short, long)] + force: bool, + #[structopt(short, long, parse(from_occurrences))] + verbose: u64, + #[structopt(subcommand)] + cmd: Option, +} + +#[test] +fn test_no_cmd() { + let result = Opt::clap().get_matches_from_safe(&["test"]); + assert!(result.is_err()); + + assert_eq!( + Opt2 { + force: false, + verbose: 0, + cmd: None + }, + Opt2::from_clap(&Opt2::clap().get_matches_from(&["test"])) + ); +} + +#[test] +fn test_fetch() { + assert_eq!( + Opt { + force: false, + verbose: 3, + cmd: Sub::Fetch {} + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vvv", "fetch"])) + ); + assert_eq!( + Opt { + force: true, + verbose: 0, + cmd: Sub::Fetch {} + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--force", "fetch"])) + ); +} + +#[test] +fn test_add() { + assert_eq!( + Opt { + force: false, + verbose: 0, + cmd: Sub::Add {} + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"])) + ); + assert_eq!( + Opt { + force: false, + verbose: 2, + cmd: Sub::Add {} + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vv", "add"])) + ); +} + +#[test] +fn test_badinput() { + let result = Opt::clap().get_matches_from_safe(&["test", "badcmd"]); + assert!(result.is_err()); + let result = Opt::clap().get_matches_from_safe(&["test", "add", "--verbose"]); + assert!(result.is_err()); + let result = Opt::clap().get_matches_from_safe(&["test", "--badopt", "add"]); + assert!(result.is_err()); + let result = Opt::clap().get_matches_from_safe(&["test", "add", "--badopt"]); + assert!(result.is_err()); +} + +#[derive(StructOpt, PartialEq, Debug)] +struct Opt3 { + #[structopt(short, long)] + all: bool, + #[structopt(subcommand)] + cmd: Sub2, +} + +#[derive(StructOpt, PartialEq, Debug)] +enum Sub2 { + Foo { + file: String, + #[structopt(subcommand)] + cmd: Sub3, + }, + Bar {}, +} + +#[derive(StructOpt, PartialEq, Debug)] +enum Sub3 { + Baz {}, + Quux {}, +} + +#[test] +fn test_subsubcommand() { + assert_eq!( + Opt3 { + all: true, + cmd: Sub2::Foo { + file: "lib.rs".to_string(), + cmd: Sub3::Quux {} + } + }, + Opt3::from_clap( + &Opt3::clap().get_matches_from(&["test", "--all", "foo", "lib.rs", "quux"]) + ) + ); +} + +#[derive(StructOpt, PartialEq, Debug)] +enum SubSubCmdWithOption { + Remote { + #[structopt(subcommand)] + cmd: Option, + }, + Stash { + #[structopt(subcommand)] + cmd: Stash, + }, +} +#[derive(StructOpt, PartialEq, Debug)] +enum Remote { + Add { name: String, url: String }, + Remove { name: String }, +} + +#[derive(StructOpt, PartialEq, Debug)] +enum Stash { + Save, + Pop, +} + +#[test] +fn sub_sub_cmd_with_option() { + fn make(args: &[&str]) -> Option { + SubSubCmdWithOption::clap() + .get_matches_from_safe(args) + .ok() + .map(|m| SubSubCmdWithOption::from_clap(&m)) + } + assert_eq!( + Some(SubSubCmdWithOption::Remote { cmd: None }), + make(&["", "remote"]) + ); + assert_eq!( + Some(SubSubCmdWithOption::Remote { + cmd: Some(Remote::Add { + name: "origin".into(), + url: "http".into() + }) + }), + make(&["", "remote", "add", "origin", "http"]) + ); + assert_eq!( + Some(SubSubCmdWithOption::Stash { cmd: Stash::Save }), + make(&["", "stash", "save"]) + ); + assert_eq!(None, make(&["", "stash"])); +} diff --git a/vendor/structopt/tests/non_literal_attributes.rs b/vendor/structopt/tests/non_literal_attributes.rs new file mode 100644 index 0000000000000..4c3a442d322a9 --- /dev/null +++ b/vendor/structopt/tests/non_literal_attributes.rs @@ -0,0 +1,151 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::clap::AppSettings; +use structopt::StructOpt; + +pub const DISPLAY_ORDER: usize = 2; + +// Check if the global settings compile +#[derive(StructOpt, Debug, PartialEq, Eq)] +#[structopt(global_settings = &[AppSettings::ColoredHelp])] +struct Opt { + #[structopt( + long = "x", + display_order = DISPLAY_ORDER, + next_line_help = true, + default_value = "0", + require_equals = true + )] + x: i32, + + #[structopt(short = "l", long = "level", aliases = &["set-level", "lvl"])] + level: String, + + #[structopt(long("values"))] + values: Vec, + + #[structopt(name = "FILE", requires_if("FILE", "values"))] + files: Vec, +} + +#[test] +fn test_slice() { + assert_eq!( + Opt { + x: 0, + level: "1".to_string(), + files: Vec::new(), + values: vec![], + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1"])) + ); + assert_eq!( + Opt { + x: 0, + level: "1".to_string(), + files: Vec::new(), + values: vec![], + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--level", "1"])) + ); + assert_eq!( + Opt { + x: 0, + level: "1".to_string(), + files: Vec::new(), + values: vec![], + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--set-level", "1"])) + ); + assert_eq!( + Opt { + x: 0, + level: "1".to_string(), + files: Vec::new(), + values: vec![], + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--lvl", "1"])) + ); +} + +#[test] +fn test_multi_args() { + assert_eq!( + Opt { + x: 0, + level: "1".to_string(), + files: vec!["file".to_string()], + values: vec![], + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1", "file"])) + ); + assert_eq!( + Opt { + x: 0, + level: "1".to_string(), + files: vec!["FILE".to_string()], + values: vec![1], + }, + Opt::from_clap( + &Opt::clap().get_matches_from(&["test", "-l", "1", "--values", "1", "--", "FILE"]), + ) + ); +} + +#[test] +fn test_multi_args_fail() { + let result = Opt::clap().get_matches_from_safe(&["test", "-l", "1", "--", "FILE"]); + assert!(result.is_err()); +} + +#[test] +fn test_bool() { + assert_eq!( + Opt { + x: 1, + level: "1".to_string(), + files: vec![], + values: vec![], + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1", "--x=1"])) + ); + let result = Opt::clap().get_matches_from_safe(&["test", "-l", "1", "--x", "1"]); + assert!(result.is_err()); +} + +fn parse_hex(input: &str) -> Result { + u64::from_str_radix(input, 16) +} + +#[derive(StructOpt, PartialEq, Debug)] +struct HexOpt { + #[structopt(short = "n", parse(try_from_str = parse_hex))] + number: u64, +} + +#[test] +fn test_parse_hex_function_path() { + assert_eq!( + HexOpt { number: 5 }, + HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "5"])) + ); + assert_eq!( + HexOpt { number: 0xabcdef }, + HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "abcdef"])) + ); + + let err = HexOpt::clap() + .get_matches_from_safe(&["test", "-n", "gg"]) + .unwrap_err(); + assert!( + err.message.contains("invalid digit found in string"), + "{}", + err + ); +} diff --git a/vendor/structopt/tests/options.rs b/vendor/structopt/tests/options.rs new file mode 100644 index 0000000000000..803abb4664ab9 --- /dev/null +++ b/vendor/structopt/tests/options.rs @@ -0,0 +1,336 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[test] +fn required_option() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short, long)] + arg: i32, + } + assert_eq!( + Opt { arg: 42 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42"])) + ); + assert_eq!( + Opt { arg: 42 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "42"])) + ); + assert_eq!( + Opt { arg: 42 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--arg", "42"])) + ); + assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err()); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "-a42", "-a24"]) + .is_err()); +} + +#[test] +fn optional_option() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short)] + arg: Option, + } + assert_eq!( + Opt { arg: Some(42) }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42"])) + ); + assert_eq!( + Opt { arg: None }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "-a42", "-a24"]) + .is_err()); +} + +#[test] +fn option_with_default() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short, default_value = "42")] + arg: i32, + } + assert_eq!( + Opt { arg: 24 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"])) + ); + assert_eq!( + Opt { arg: 42 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "-a42", "-a24"]) + .is_err()); +} + +#[test] +fn option_with_raw_default() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short, default_value = "42")] + arg: i32, + } + assert_eq!( + Opt { arg: 24 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"])) + ); + assert_eq!( + Opt { arg: 42 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "-a42", "-a24"]) + .is_err()); +} + +#[test] +fn options() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short, long)] + arg: Vec, + } + assert_eq!( + Opt { arg: vec![24] }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"])) + ); + assert_eq!( + Opt { arg: vec![] }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert_eq!( + Opt { arg: vec![24, 42] }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24", "--arg", "42"])) + ); +} + +#[test] +fn empy_default_value() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short, default_value = "")] + arg: String, + } + assert_eq!(Opt { arg: "".into() }, Opt::from_iter(&["test"])); + assert_eq!( + Opt { arg: "foo".into() }, + Opt::from_iter(&["test", "-afoo"]) + ); +} + +#[test] +fn option_from_str() { + #[derive(Debug, PartialEq)] + struct A; + + impl<'a> From<&'a str> for A { + fn from(_: &str) -> A { + A + } + } + + #[derive(Debug, StructOpt, PartialEq)] + struct Opt { + #[structopt(parse(from_str))] + a: Option, + } + + assert_eq!(Opt { a: None }, Opt::from_iter(&["test"])); + assert_eq!(Opt { a: Some(A) }, Opt::from_iter(&["test", "foo"])); +} + +#[test] +fn optional_argument_for_optional_option() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short)] + #[allow(clippy::option_option)] + arg: Option>, + } + assert_eq!( + Opt { + arg: Some(Some(42)) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42"])) + ); + assert_eq!( + Opt { arg: Some(None) }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"])) + ); + assert_eq!( + Opt { arg: None }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert!(Opt::clap() + .get_matches_from_safe(&["test", "-a42", "-a24"]) + .is_err()); +} + +#[test] +fn two_option_options() { + #[derive(StructOpt, PartialEq, Debug)] + #[allow(clippy::option_option)] + struct Opt { + #[structopt(short)] + arg: Option>, + + #[structopt(long)] + field: Option>, + } + assert_eq!( + Opt { + arg: Some(Some(42)), + field: Some(Some("f".into())) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42", "--field", "f"])) + ); + assert_eq!( + Opt { + arg: Some(Some(42)), + field: Some(None) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42", "--field"])) + ); + assert_eq!( + Opt { + arg: Some(None), + field: Some(None) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "--field"])) + ); + assert_eq!( + Opt { + arg: Some(None), + field: Some(Some("f".into())) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "--field", "f"])) + ); + assert_eq!( + Opt { + arg: None, + field: Some(None) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--field"])) + ); + assert_eq!( + Opt { + arg: None, + field: None + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); +} + +#[test] +fn optional_vec() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short)] + arg: Option>, + } + assert_eq!( + Opt { arg: Some(vec![1]) }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "1"])) + ); + + assert_eq!( + Opt { + arg: Some(vec![1, 2]) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a1", "-a2"])) + ); + + assert_eq!( + Opt { + arg: Some(vec![1, 2]) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a1", "-a2", "-a"])) + ); + + assert_eq!( + Opt { + arg: Some(vec![1, 2]) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a1", "-a", "-a2"])) + ); + + assert_eq!( + Opt { + arg: Some(vec![1, 2]) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "1", "2"])) + ); + + assert_eq!( + Opt { + arg: Some(vec![1, 2, 3]) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "1", "2", "-a", "3"])) + ); + + assert_eq!( + Opt { arg: Some(vec![]) }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"])) + ); + + assert_eq!( + Opt { arg: Some(vec![]) }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "-a"])) + ); + + assert_eq!( + Opt { arg: None }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); +} + +#[test] +fn two_optional_vecs() { + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(short)] + arg: Option>, + + #[structopt(short)] + b: Option>, + } + + assert_eq!( + Opt { + arg: Some(vec![1]), + b: Some(vec![]) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "1", "-b"])) + ); + + assert_eq!( + Opt { + arg: Some(vec![1]), + b: Some(vec![]) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "-b", "-a1"])) + ); + + assert_eq!( + Opt { + arg: Some(vec![1, 2]), + b: Some(vec![1, 2]) + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a1", "-a2", "-b1", "-b2"])) + ); + + assert_eq!( + Opt { arg: None, b: None }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); +} diff --git a/vendor/structopt/tests/privacy.rs b/vendor/structopt/tests/privacy.rs new file mode 100644 index 0000000000000..730bbce728811 --- /dev/null +++ b/vendor/structopt/tests/privacy.rs @@ -0,0 +1,32 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +mod options { + use super::StructOpt; + + #[derive(Debug, StructOpt)] + pub struct Options { + #[structopt(subcommand)] + pub subcommand: super::subcommands::SubCommand, + } +} + +mod subcommands { + use super::StructOpt; + + #[derive(Debug, StructOpt)] + pub enum SubCommand { + /// foo + Foo { + /// foo + bars: Vec, + }, + } +} diff --git a/vendor/structopt/tests/raw_bool_literal.rs b/vendor/structopt/tests/raw_bool_literal.rs new file mode 100644 index 0000000000000..faf8628b84972 --- /dev/null +++ b/vendor/structopt/tests/raw_bool_literal.rs @@ -0,0 +1,29 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[test] +fn raw_bool_literal() { + #[derive(StructOpt, Debug, PartialEq)] + #[structopt(no_version, name = "raw_bool")] + struct Opt { + #[structopt(raw(false))] + a: String, + #[structopt(raw(true))] + b: String, + } + + assert_eq!( + Opt { + a: "one".into(), + b: "--help".into() + }, + Opt::from_iter(&["test", "one", "--", "--help"]) + ); +} diff --git a/vendor/structopt/tests/raw_idents.rs b/vendor/structopt/tests/raw_idents.rs new file mode 100644 index 0000000000000..c00ff669d9731 --- /dev/null +++ b/vendor/structopt/tests/raw_idents.rs @@ -0,0 +1,17 @@ +use structopt::StructOpt; + +#[test] +fn raw_idents() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(short, long)] + r#type: Vec, + } + + assert_eq!( + Opt { + r#type: vec!["long".into(), "short".into()] + }, + Opt::from_iter(&["test", "--type", "long", "-t", "short"]) + ); +} diff --git a/vendor/structopt/tests/regressions.rs b/vendor/structopt/tests/regressions.rs new file mode 100644 index 0000000000000..3847dc2f5c073 --- /dev/null +++ b/vendor/structopt/tests/regressions.rs @@ -0,0 +1,45 @@ +use structopt::StructOpt; + +mod utils; +use utils::*; + +#[test] +fn invisible_group_issue_439() { + macro_rules! m { + ($bool:ty) => { + #[derive(Debug, StructOpt)] + struct Opts { + #[structopt(long = "x")] + x: $bool, + } + }; + } + + m!(bool); + + let help = get_long_help::(); + + assert!(help.contains("--x")); + assert!(!help.contains("--x ")); + Opts::from_iter_safe(&["test", "--x"]).unwrap(); +} + +#[test] +fn issue_447() { + macro_rules! Command { + ( $name:ident, [ + #[$meta:meta] $var:ident($inner:ty) + ] ) => { + #[derive(Debug, PartialEq, structopt::StructOpt)] + enum $name { + #[$meta] + $var($inner), + } + }; + } + + Command! {GitCmd, [ + #[structopt(external_subcommand)] + Ext(Vec) + ]} +} diff --git a/vendor/structopt/tests/rename_all_env.rs b/vendor/structopt/tests/rename_all_env.rs new file mode 100644 index 0000000000000..1979e84f7fcc2 --- /dev/null +++ b/vendor/structopt/tests/rename_all_env.rs @@ -0,0 +1,46 @@ +mod utils; + +use structopt::StructOpt; +use utils::*; + +#[test] +fn it_works() { + #[derive(Debug, PartialEq, StructOpt)] + #[structopt(rename_all_env = "kebab")] + struct BehaviorModel { + #[structopt(env)] + be_nice: String, + } + + let help = get_help::(); + assert!(help.contains("[env: be-nice=]")); +} + +#[test] +fn default_is_screaming() { + #[derive(Debug, PartialEq, StructOpt)] + struct BehaviorModel { + #[structopt(env)] + be_nice: String, + } + + let help = get_help::(); + assert!(help.contains("[env: BE_NICE=]")); +} + +#[test] +fn overridable() { + #[derive(Debug, PartialEq, StructOpt)] + #[structopt(rename_all_env = "kebab")] + struct BehaviorModel { + #[structopt(env)] + be_nice: String, + + #[structopt(rename_all_env = "pascal", env)] + be_agressive: String, + } + + let help = get_help::(); + assert!(help.contains("[env: be-nice=]")); + assert!(help.contains("[env: BeAgressive=]")); +} diff --git a/vendor/structopt/tests/skip.rs b/vendor/structopt/tests/skip.rs new file mode 100644 index 0000000000000..47682d8d7e762 --- /dev/null +++ b/vendor/structopt/tests/skip.rs @@ -0,0 +1,148 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[test] +fn skip_1() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(short)] + x: u32, + #[structopt(skip)] + s: u32, + } + + assert!(Opt::from_iter_safe(&["test", "-x", "10", "20"]).is_err()); + assert_eq!( + Opt::from_iter(&["test", "-x", "10"]), + Opt { + x: 10, + s: 0, // default + } + ); +} + +#[test] +fn skip_2() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(short)] + x: u32, + #[structopt(skip)] + ss: String, + #[structopt(skip)] + sn: u8, + y: u32, + #[structopt(skip)] + sz: u16, + t: u32, + } + + assert_eq!( + Opt::from_iter(&["test", "-x", "10", "20", "30"]), + Opt { + x: 10, + ss: String::from(""), + sn: 0, + y: 20, + sz: 0, + t: 30, + } + ); +} + +#[test] +fn skip_enum() { + #[derive(Debug, PartialEq)] + #[allow(unused)] + enum Kind { + A, + B, + } + + impl Default for Kind { + fn default() -> Self { + return Kind::B; + } + } + + #[derive(StructOpt, Debug, PartialEq)] + pub struct Opt { + #[structopt(long, short)] + number: u32, + #[structopt(skip)] + k: Kind, + #[structopt(skip)] + v: Vec, + } + + assert_eq!( + Opt::from_iter(&["test", "-n", "10"]), + Opt { + number: 10, + k: Kind::B, + v: vec![], + } + ); +} + +#[test] +fn skip_help_doc_comments() { + #[derive(StructOpt, Debug, PartialEq)] + pub struct Opt { + #[structopt(skip, help = "internal_stuff")] + a: u32, + + #[structopt(skip, long_help = "internal_stuff\ndo not touch")] + b: u32, + + /// Not meant to be used by clap. + /// + /// I want a default here. + #[structopt(skip)] + c: u32, + + #[structopt(short, parse(try_from_str))] + n: u32, + } + + assert_eq!( + Opt::from_iter(&["test", "-n", "10"]), + Opt { + n: 10, + a: 0, + b: 0, + c: 0, + } + ); +} + +#[test] +fn skip_val() { + #[derive(StructOpt, Debug, PartialEq)] + pub struct Opt { + #[structopt(long, short)] + number: u32, + + #[structopt(skip = "key")] + k: String, + + #[structopt(skip = vec![1, 2, 3])] + v: Vec, + } + + assert_eq!( + Opt::from_iter(&["test", "-n", "10"]), + Opt { + number: 10, + k: "key".into(), + v: vec![1, 2, 3] + } + ); +} diff --git a/vendor/structopt/tests/special_types.rs b/vendor/structopt/tests/special_types.rs new file mode 100644 index 0000000000000..ac7d1435616eb --- /dev/null +++ b/vendor/structopt/tests/special_types.rs @@ -0,0 +1,73 @@ +//! Checks that types like `::std::option::Option` are not special + +use structopt::StructOpt; + +#[rustversion::since(1.37)] +#[test] +fn special_types_bool() { + mod inner { + #[allow(non_camel_case_types)] + #[derive(PartialEq, Debug)] + pub struct bool(pub String); + + impl std::str::FromStr for self::bool { + type Err = String; + + fn from_str(s: &str) -> Result { + Ok(self::bool(s.into())) + } + } + } + + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + arg: inner::bool, + } + + assert_eq!( + Opt { + arg: inner::bool("success".into()) + }, + Opt::from_iter(&["test", "success"]) + ); +} + +#[test] +fn special_types_option() { + fn parser(s: &str) -> Option { + Some(s.to_string()) + } + + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(parse(from_str = parser))] + arg: ::std::option::Option, + } + + assert_eq!( + Opt { + arg: Some("success".into()) + }, + Opt::from_iter(&["test", "success"]) + ); +} + +#[test] +fn special_types_vec() { + fn parser(s: &str) -> Vec { + vec![s.to_string()] + } + + #[derive(StructOpt, PartialEq, Debug)] + struct Opt { + #[structopt(parse(from_str = parser))] + arg: ::std::vec::Vec, + } + + assert_eq!( + Opt { + arg: vec!["success".into()] + }, + Opt::from_iter(&["test", "success"]) + ); +} diff --git a/vendor/structopt/tests/subcommands.rs b/vendor/structopt/tests/subcommands.rs new file mode 100644 index 0000000000000..4ee738b1170b4 --- /dev/null +++ b/vendor/structopt/tests/subcommands.rs @@ -0,0 +1,349 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod utils; + +use structopt::StructOpt; +use utils::*; + +#[derive(StructOpt, PartialEq, Debug)] +enum Opt { + /// Fetch stuff from GitHub + Fetch { + #[structopt(long)] + all: bool, + #[structopt(short, long)] + /// Overwrite local branches. + force: bool, + repo: String, + }, + + Add { + #[structopt(short, long)] + interactive: bool, + #[structopt(short, long)] + verbose: bool, + }, +} + +#[test] +fn test_fetch() { + assert_eq!( + Opt::Fetch { + all: true, + force: false, + repo: "origin".to_string() + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "--all", "origin"])) + ); + assert_eq!( + Opt::Fetch { + all: false, + force: true, + repo: "origin".to_string() + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "-f", "origin"])) + ); +} + +#[test] +fn test_add() { + assert_eq!( + Opt::Add { + interactive: false, + verbose: false + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"])) + ); + assert_eq!( + Opt::Add { + interactive: true, + verbose: true + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add", "-i", "-v"])) + ); +} + +#[test] +fn test_no_parse() { + let result = Opt::clap().get_matches_from_safe(&["test", "badcmd", "-i", "-v"]); + assert!(result.is_err()); + + let result = Opt::clap().get_matches_from_safe(&["test", "add", "--badoption"]); + assert!(result.is_err()); + + let result = Opt::clap().get_matches_from_safe(&["test"]); + assert!(result.is_err()); +} + +#[derive(StructOpt, PartialEq, Debug)] +enum Opt2 { + DoSomething { arg: String }, +} + +#[test] +/// This test is specifically to make sure that hyphenated subcommands get +/// processed correctly. +fn test_hyphenated_subcommands() { + assert_eq!( + Opt2::DoSomething { + arg: "blah".to_string() + }, + Opt2::from_clap(&Opt2::clap().get_matches_from(&["test", "do-something", "blah"])) + ); +} + +#[derive(StructOpt, PartialEq, Debug)] +enum Opt3 { + Add, + Init, + Fetch, +} + +#[test] +fn test_null_commands() { + assert_eq!( + Opt3::Add, + Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "add"])) + ); + assert_eq!( + Opt3::Init, + Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "init"])) + ); + assert_eq!( + Opt3::Fetch, + Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "fetch"])) + ); +} + +#[derive(StructOpt, PartialEq, Debug)] +#[structopt(about = "Not shown")] +struct Add { + file: String, +} +/// Not shown +#[derive(StructOpt, PartialEq, Debug)] +struct Fetch { + remote: String, +} +#[derive(StructOpt, PartialEq, Debug)] +enum Opt4 { + // Not shown + /// Add a file + Add(Add), + Init, + /// download history from remote + Fetch(Fetch), +} + +#[test] +fn test_tuple_commands() { + assert_eq!( + Opt4::Add(Add { + file: "f".to_string() + }), + Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "add", "f"])) + ); + assert_eq!( + Opt4::Init, + Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "init"])) + ); + assert_eq!( + Opt4::Fetch(Fetch { + remote: "origin".to_string() + }), + Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "fetch", "origin"])) + ); + + let output = get_long_help::(); + + assert!(output.contains("download history from remote")); + assert!(output.contains("Add a file")); + assert!(!output.contains("Not shown")); +} + +#[test] +fn enum_in_enum_subsubcommand() { + #[derive(StructOpt, Debug, PartialEq)] + pub enum Opt { + Daemon(DaemonCommand), + } + + #[derive(StructOpt, Debug, PartialEq)] + pub enum DaemonCommand { + Start, + Stop, + } + + let result = Opt::clap().get_matches_from_safe(&["test"]); + assert!(result.is_err()); + + let result = Opt::clap().get_matches_from_safe(&["test", "daemon"]); + assert!(result.is_err()); + + let result = Opt::from_iter(&["test", "daemon", "start"]); + assert_eq!(Opt::Daemon(DaemonCommand::Start), result); +} + +#[test] +fn flatten_enum() { + #[derive(StructOpt, Debug, PartialEq)] + struct Opt { + #[structopt(flatten)] + sub_cmd: SubCmd, + } + #[derive(StructOpt, Debug, PartialEq)] + enum SubCmd { + Foo, + Bar, + } + + assert!(Opt::from_iter_safe(&["test"]).is_err()); + assert_eq!( + Opt::from_iter(&["test", "foo"]), + Opt { + sub_cmd: SubCmd::Foo + } + ); +} + +#[test] +fn external_subcommand() { + #[derive(Debug, PartialEq, StructOpt)] + struct Opt { + #[structopt(subcommand)] + sub: Subcommands, + } + + #[derive(Debug, PartialEq, StructOpt)] + enum Subcommands { + Add, + Remove, + #[structopt(external_subcommand)] + Other(Vec), + } + + assert_eq!( + Opt::from_iter(&["test", "add"]), + Opt { + sub: Subcommands::Add + } + ); + + assert_eq!( + Opt::from_iter(&["test", "remove"]), + Opt { + sub: Subcommands::Remove + } + ); + + assert_eq!( + Opt::from_iter(&["test", "git", "status"]), + Opt { + sub: Subcommands::Other(vec!["git".into(), "status".into()]) + } + ); + + assert!(Opt::from_iter_safe(&["test"]).is_err()); +} + +#[test] +fn external_subcommand_os_string() { + use std::ffi::OsString; + + #[derive(Debug, PartialEq, StructOpt)] + struct Opt { + #[structopt(subcommand)] + sub: Subcommands, + } + + #[derive(Debug, PartialEq, StructOpt)] + enum Subcommands { + #[structopt(external_subcommand)] + Other(Vec), + } + + assert_eq!( + Opt::from_iter(&["test", "git", "status"]), + Opt { + sub: Subcommands::Other(vec!["git".into(), "status".into()]) + } + ); + + assert!(Opt::from_iter_safe(&["test"]).is_err()); +} + +#[test] +fn external_subcommand_optional() { + #[derive(Debug, PartialEq, StructOpt)] + struct Opt { + #[structopt(subcommand)] + sub: Option, + } + + #[derive(Debug, PartialEq, StructOpt)] + enum Subcommands { + #[structopt(external_subcommand)] + Other(Vec), + } + + assert_eq!( + Opt::from_iter(&["test", "git", "status"]), + Opt { + sub: Some(Subcommands::Other(vec!["git".into(), "status".into()])) + } + ); + + assert_eq!(Opt::from_iter(&["test"]), Opt { sub: None }); +} + +#[test] +fn skip_subcommand() { + #[derive(Debug, PartialEq, StructOpt)] + struct Opt { + #[structopt(subcommand)] + sub: Subcommands, + } + + #[derive(Debug, PartialEq, StructOpt)] + enum Subcommands { + Add, + Remove, + + #[allow(dead_code)] + #[structopt(skip)] + Skip, + } + + assert_eq!( + Opt::from_iter(&["test", "add"]), + Opt { + sub: Subcommands::Add + } + ); + + assert_eq!( + Opt::from_iter(&["test", "remove"]), + Opt { + sub: Subcommands::Remove + } + ); + + let res = Opt::from_iter_safe(&["test", "skip"]); + assert!( + matches!( + res, + Err(clap::Error { + kind: clap::ErrorKind::UnknownArgument, + .. + }) + ), + "Unexpected result: {:?}", + res + ); +} diff --git a/vendor/structopt/tests/ui/bool_default_value.rs b/vendor/structopt/tests/ui/bool_default_value.rs new file mode 100644 index 0000000000000..9bdb0c94735b9 --- /dev/null +++ b/vendor/structopt/tests/ui/bool_default_value.rs @@ -0,0 +1,21 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt(short, default_value = true)] + b: bool, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/bool_default_value.stderr b/vendor/structopt/tests/ui/bool_default_value.stderr new file mode 100644 index 0000000000000..1e26a2dc93961 --- /dev/null +++ b/vendor/structopt/tests/ui/bool_default_value.stderr @@ -0,0 +1,5 @@ +error: default_value is meaningless for bool + --> $DIR/bool_default_value.rs:14:24 + | +14 | #[structopt(short, default_value = true)] + | ^^^^^^^^^^^^^ diff --git a/vendor/structopt/tests/ui/bool_required.rs b/vendor/structopt/tests/ui/bool_required.rs new file mode 100644 index 0000000000000..018223c2fbbff --- /dev/null +++ b/vendor/structopt/tests/ui/bool_required.rs @@ -0,0 +1,21 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt(short, required = true)] + b: bool, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/bool_required.stderr b/vendor/structopt/tests/ui/bool_required.stderr new file mode 100644 index 0000000000000..0b80d481e3bbe --- /dev/null +++ b/vendor/structopt/tests/ui/bool_required.stderr @@ -0,0 +1,5 @@ +error: required is meaningless for bool + --> $DIR/bool_required.rs:14:24 + | +14 | #[structopt(short, required = true)] + | ^^^^^^^^ diff --git a/vendor/structopt/tests/ui/enum_flatten.rs b/vendor/structopt/tests/ui/enum_flatten.rs new file mode 100644 index 0000000000000..768de763d8e7b --- /dev/null +++ b/vendor/structopt/tests/ui/enum_flatten.rs @@ -0,0 +1,21 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +enum Opt { + #[structopt(flatten)] + Variant1, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/enum_flatten.stderr b/vendor/structopt/tests/ui/enum_flatten.stderr new file mode 100644 index 0000000000000..d74fa85897b4c --- /dev/null +++ b/vendor/structopt/tests/ui/enum_flatten.stderr @@ -0,0 +1,6 @@ +error: `flatten` is usable only with single-typed tuple variants + --> $DIR/enum_flatten.rs:14:5 + | +14 | / #[structopt(flatten)] +15 | | Variant1, + | |____________^ diff --git a/vendor/structopt/tests/ui/external_subcommand_wrong_type.rs b/vendor/structopt/tests/ui/external_subcommand_wrong_type.rs new file mode 100644 index 0000000000000..ad62e7337a516 --- /dev/null +++ b/vendor/structopt/tests/ui/external_subcommand_wrong_type.rs @@ -0,0 +1,19 @@ +use structopt::StructOpt; +use std::ffi::CString; + +#[derive(StructOpt, Debug)] +struct Opt { + #[structopt(subcommand)] + cmd: Command, +} + +#[derive(StructOpt, Debug)] +enum Command { + #[structopt(external_subcommand)] + Other(Vec) +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} \ No newline at end of file diff --git a/vendor/structopt/tests/ui/external_subcommand_wrong_type.stderr b/vendor/structopt/tests/ui/external_subcommand_wrong_type.stderr new file mode 100644 index 0000000000000..73f12d28004f4 --- /dev/null +++ b/vendor/structopt/tests/ui/external_subcommand_wrong_type.stderr @@ -0,0 +1,8 @@ +error[E0308]: mismatched types + --> $DIR/external_subcommand_wrong_type.rs:13:15 + | +13 | Other(Vec) + | ^^^^^^^ expected struct `CString`, found struct `OsString` + | + = note: expected struct `Vec` + found struct `Vec` diff --git a/vendor/structopt/tests/ui/flatten_and_methods.rs b/vendor/structopt/tests/ui/flatten_and_methods.rs new file mode 100644 index 0000000000000..ff1af2eeb4d84 --- /dev/null +++ b/vendor/structopt/tests/ui/flatten_and_methods.rs @@ -0,0 +1,29 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +struct DaemonOpts { + #[structopt(short)] + user: String, + #[structopt(short)] + group: String, +} + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt(short, flatten)] + opts: DaemonOpts, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/flatten_and_methods.stderr b/vendor/structopt/tests/ui/flatten_and_methods.stderr new file mode 100644 index 0000000000000..77d97ae3b2126 --- /dev/null +++ b/vendor/structopt/tests/ui/flatten_and_methods.stderr @@ -0,0 +1,5 @@ +error: methods are not allowed for flattened entry + --> $DIR/flatten_and_methods.rs:22:24 + | +22 | #[structopt(short, flatten)] + | ^^^^^^^ diff --git a/vendor/structopt/tests/ui/flatten_and_parse.rs b/vendor/structopt/tests/ui/flatten_and_parse.rs new file mode 100644 index 0000000000000..3317272b5f429 --- /dev/null +++ b/vendor/structopt/tests/ui/flatten_and_parse.rs @@ -0,0 +1,29 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +struct DaemonOpts { + #[structopt(short)] + user: String, + #[structopt(short)] + group: String, +} + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt(flatten, parse(from_occurrences))] + opts: DaemonOpts, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/flatten_and_parse.stderr b/vendor/structopt/tests/ui/flatten_and_parse.stderr new file mode 100644 index 0000000000000..e217a840b962e --- /dev/null +++ b/vendor/structopt/tests/ui/flatten_and_parse.stderr @@ -0,0 +1,5 @@ +error: parse attribute is not allowed for flattened entry + --> $DIR/flatten_and_parse.rs:22:26 + | +22 | #[structopt(flatten, parse(from_occurrences))] + | ^^^^^ diff --git a/vendor/structopt/tests/ui/multiple_external_subcommand.rs b/vendor/structopt/tests/ui/multiple_external_subcommand.rs new file mode 100644 index 0000000000000..986261bc46bc3 --- /dev/null +++ b/vendor/structopt/tests/ui/multiple_external_subcommand.rs @@ -0,0 +1,21 @@ +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +struct Opt { + #[structopt(subcommand)] + cmd: Command, +} + +#[derive(StructOpt, Debug)] +enum Command { + #[structopt(external_subcommand)] + Run(Vec), + + #[structopt(external_subcommand)] + Other(Vec) +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/multiple_external_subcommand.stderr b/vendor/structopt/tests/ui/multiple_external_subcommand.stderr new file mode 100644 index 0000000000000..0c80c2ec2dc24 --- /dev/null +++ b/vendor/structopt/tests/ui/multiple_external_subcommand.stderr @@ -0,0 +1,5 @@ +error: Only one variant can be marked with `external_subcommand`, this is the second + --> $DIR/multiple_external_subcommand.rs:14:17 + | +14 | #[structopt(external_subcommand)] + | ^^^^^^^^^^^^^^^^^^^ diff --git a/vendor/structopt/tests/ui/non_existent_attr.rs b/vendor/structopt/tests/ui/non_existent_attr.rs new file mode 100644 index 0000000000000..96daf45cc0c77 --- /dev/null +++ b/vendor/structopt/tests/ui/non_existent_attr.rs @@ -0,0 +1,21 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt(short, non_existing_attribute = 1)] + debug: bool, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/non_existent_attr.stderr b/vendor/structopt/tests/ui/non_existent_attr.stderr new file mode 100644 index 0000000000000..5765597d1b8e6 --- /dev/null +++ b/vendor/structopt/tests/ui/non_existent_attr.stderr @@ -0,0 +1,5 @@ +error[E0599]: no method named `non_existing_attribute` found for struct `Arg` in the current scope + --> $DIR/non_existent_attr.rs:14:24 + | +14 | #[structopt(short, non_existing_attribute = 1)] + | ^^^^^^^^^^^^^^^^^^^^^^ method not found in `Arg<'_, '_>` diff --git a/vendor/structopt/tests/ui/opt_opt_nonpositional.rs b/vendor/structopt/tests/ui/opt_opt_nonpositional.rs new file mode 100644 index 0000000000000..2a08105b1970a --- /dev/null +++ b/vendor/structopt/tests/ui/opt_opt_nonpositional.rs @@ -0,0 +1,20 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + n: Option>, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/opt_opt_nonpositional.stderr b/vendor/structopt/tests/ui/opt_opt_nonpositional.stderr new file mode 100644 index 0000000000000..cb9f1728975b8 --- /dev/null +++ b/vendor/structopt/tests/ui/opt_opt_nonpositional.stderr @@ -0,0 +1,5 @@ +error: Option> type is meaningless for positional argument + --> $DIR/opt_opt_nonpositional.rs:14:8 + | +14 | n: Option>, + | ^^^^^^^^^^^^^^^^^^^ diff --git a/vendor/structopt/tests/ui/opt_vec_nonpositional.rs b/vendor/structopt/tests/ui/opt_vec_nonpositional.rs new file mode 100644 index 0000000000000..0f6f0784a7cc3 --- /dev/null +++ b/vendor/structopt/tests/ui/opt_vec_nonpositional.rs @@ -0,0 +1,20 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + n: Option>, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/opt_vec_nonpositional.stderr b/vendor/structopt/tests/ui/opt_vec_nonpositional.stderr new file mode 100644 index 0000000000000..c6b343f947dc5 --- /dev/null +++ b/vendor/structopt/tests/ui/opt_vec_nonpositional.stderr @@ -0,0 +1,5 @@ +error: Option> type is meaningless for positional argument + --> $DIR/opt_vec_nonpositional.rs:14:8 + | +14 | n: Option>, + | ^^^^^^^^^^^^^^^^ diff --git a/vendor/structopt/tests/ui/option_default_value.rs b/vendor/structopt/tests/ui/option_default_value.rs new file mode 100644 index 0000000000000..a86bc0ea7996a --- /dev/null +++ b/vendor/structopt/tests/ui/option_default_value.rs @@ -0,0 +1,21 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt(short, default_value = 1)] + n: Option, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/option_default_value.stderr b/vendor/structopt/tests/ui/option_default_value.stderr new file mode 100644 index 0000000000000..2215497ad0541 --- /dev/null +++ b/vendor/structopt/tests/ui/option_default_value.stderr @@ -0,0 +1,5 @@ +error: default_value is meaningless for Option + --> $DIR/option_default_value.rs:14:24 + | +14 | #[structopt(short, default_value = 1)] + | ^^^^^^^^^^^^^ diff --git a/vendor/structopt/tests/ui/option_required.rs b/vendor/structopt/tests/ui/option_required.rs new file mode 100644 index 0000000000000..d91afbf29d6f3 --- /dev/null +++ b/vendor/structopt/tests/ui/option_required.rs @@ -0,0 +1,21 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt(short, required = true)] + n: Option, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/option_required.stderr b/vendor/structopt/tests/ui/option_required.stderr new file mode 100644 index 0000000000000..0230d57da1c78 --- /dev/null +++ b/vendor/structopt/tests/ui/option_required.stderr @@ -0,0 +1,5 @@ +error: required is meaningless for Option + --> $DIR/option_required.rs:14:24 + | +14 | #[structopt(short, required = true)] + | ^^^^^^^^ diff --git a/vendor/structopt/tests/ui/parse_empty_try_from_os.rs b/vendor/structopt/tests/ui/parse_empty_try_from_os.rs new file mode 100644 index 0000000000000..acfef0b21accb --- /dev/null +++ b/vendor/structopt/tests/ui/parse_empty_try_from_os.rs @@ -0,0 +1,21 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt(parse(try_from_os_str))] + s: String, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/parse_empty_try_from_os.stderr b/vendor/structopt/tests/ui/parse_empty_try_from_os.stderr new file mode 100644 index 0000000000000..3dc9f2491baa4 --- /dev/null +++ b/vendor/structopt/tests/ui/parse_empty_try_from_os.stderr @@ -0,0 +1,5 @@ +error: you must set parser for `try_from_os_str` explicitly + --> $DIR/parse_empty_try_from_os.rs:14:23 + | +14 | #[structopt(parse(try_from_os_str))] + | ^^^^^^^^^^^^^^^ diff --git a/vendor/structopt/tests/ui/parse_function_is_not_path.rs b/vendor/structopt/tests/ui/parse_function_is_not_path.rs new file mode 100644 index 0000000000000..5eebc57f36546 --- /dev/null +++ b/vendor/structopt/tests/ui/parse_function_is_not_path.rs @@ -0,0 +1,21 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt(parse(from_str = "2"))] + s: String, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/parse_function_is_not_path.stderr b/vendor/structopt/tests/ui/parse_function_is_not_path.stderr new file mode 100644 index 0000000000000..7cf74445d1d5a --- /dev/null +++ b/vendor/structopt/tests/ui/parse_function_is_not_path.stderr @@ -0,0 +1,5 @@ +error: `parse` argument must be a function path + --> $DIR/parse_function_is_not_path.rs:14:34 + | +14 | #[structopt(parse(from_str = "2"))] + | ^^^ diff --git a/vendor/structopt/tests/ui/parse_literal_spec.rs b/vendor/structopt/tests/ui/parse_literal_spec.rs new file mode 100644 index 0000000000000..b6f125a1ba4a0 --- /dev/null +++ b/vendor/structopt/tests/ui/parse_literal_spec.rs @@ -0,0 +1,21 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt(parse("from_str"))] + s: String, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/parse_literal_spec.stderr b/vendor/structopt/tests/ui/parse_literal_spec.stderr new file mode 100644 index 0000000000000..6e99e8b7fb85f --- /dev/null +++ b/vendor/structopt/tests/ui/parse_literal_spec.stderr @@ -0,0 +1,5 @@ +error: parser specification must start with identifier + --> $DIR/parse_literal_spec.rs:14:23 + | +14 | #[structopt(parse("from_str"))] + | ^^^^^^^^^^ diff --git a/vendor/structopt/tests/ui/parse_not_zero_args.rs b/vendor/structopt/tests/ui/parse_not_zero_args.rs new file mode 100644 index 0000000000000..872917897c2b9 --- /dev/null +++ b/vendor/structopt/tests/ui/parse_not_zero_args.rs @@ -0,0 +1,21 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt(parse(from_str, from_str))] + s: String, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/parse_not_zero_args.stderr b/vendor/structopt/tests/ui/parse_not_zero_args.stderr new file mode 100644 index 0000000000000..34b99a4cfe8ce --- /dev/null +++ b/vendor/structopt/tests/ui/parse_not_zero_args.stderr @@ -0,0 +1,5 @@ +error: `parse` must have exactly one argument + --> $DIR/parse_not_zero_args.rs:14:17 + | +14 | #[structopt(parse(from_str, from_str))] + | ^^^^^ diff --git a/vendor/structopt/tests/ui/positional_bool.rs b/vendor/structopt/tests/ui/positional_bool.rs new file mode 100644 index 0000000000000..4dbf5389ce1cb --- /dev/null +++ b/vendor/structopt/tests/ui/positional_bool.rs @@ -0,0 +1,10 @@ +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +struct Opt { + verbose: bool, +} + +fn main() { + Opt::from_args(); +} \ No newline at end of file diff --git a/vendor/structopt/tests/ui/positional_bool.stderr b/vendor/structopt/tests/ui/positional_bool.stderr new file mode 100644 index 0000000000000..c3ed1ad94412a --- /dev/null +++ b/vendor/structopt/tests/ui/positional_bool.stderr @@ -0,0 +1,10 @@ +error: `bool` cannot be used as positional parameter with default parser + + = help: if you want to create a flag add `long` or `short` + = help: If you really want a boolean parameter add an explicit parser, for example `parse(try_from_str)` + = note: see also https://github.com/TeXitoi/structopt/tree/master/examples/true_or_false.rs + + --> $DIR/positional_bool.rs:5:14 + | +5 | verbose: bool, + | ^^^^ diff --git a/vendor/structopt/tests/ui/raw.rs b/vendor/structopt/tests/ui/raw.rs new file mode 100644 index 0000000000000..b94f783d7bdb9 --- /dev/null +++ b/vendor/structopt/tests/ui/raw.rs @@ -0,0 +1,25 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +struct Opt { + #[structopt(raw(case_insensitive = "true"))] + s: String, +} + +#[derive(StructOpt, Debug)] +struct Opt2 { + #[structopt(raw(requires_if = r#""one", "two""#))] + s: String, +} +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/raw.stderr b/vendor/structopt/tests/ui/raw.stderr new file mode 100644 index 0000000000000..93b5e38db56d0 --- /dev/null +++ b/vendor/structopt/tests/ui/raw.stderr @@ -0,0 +1,19 @@ +error: `#[structopt(raw(...))` attributes are removed in structopt 0.3, they are replaced with raw methods + + = help: if you meant to call `clap::Arg::raw()` method you should use bool literal, like `raw(true)` or `raw(false)` + = note: if you need to call `clap::Arg/App::case_insensitive` method you can do it like this: #[structopt(case_insensitive = true)] + + --> $DIR/raw.rs:13:17 + | +13 | #[structopt(raw(case_insensitive = "true"))] + | ^^^ + +error: `#[structopt(raw(...))` attributes are removed in structopt 0.3, they are replaced with raw methods + + = help: if you meant to call `clap::Arg::raw()` method you should use bool literal, like `raw(true)` or `raw(false)` + = note: if you need to call `clap::Arg/App::requires_if` method you can do it like this: #[structopt(requires_if("one", "two"))] + + --> $DIR/raw.rs:19:17 + | +19 | #[structopt(raw(requires_if = r#""one", "two""#))] + | ^^^ diff --git a/vendor/structopt/tests/ui/rename_all_wrong_casing.rs b/vendor/structopt/tests/ui/rename_all_wrong_casing.rs new file mode 100644 index 0000000000000..4dabe14bbc318 --- /dev/null +++ b/vendor/structopt/tests/ui/rename_all_wrong_casing.rs @@ -0,0 +1,21 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic", rename_all = "fail")] +struct Opt { + #[structopt(short)] + s: String, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/rename_all_wrong_casing.stderr b/vendor/structopt/tests/ui/rename_all_wrong_casing.stderr new file mode 100644 index 0000000000000..2a720800cd9ba --- /dev/null +++ b/vendor/structopt/tests/ui/rename_all_wrong_casing.stderr @@ -0,0 +1,5 @@ +error: unsupported casing: `fail` + --> $DIR/rename_all_wrong_casing.rs:12:42 + | +12 | #[structopt(name = "basic", rename_all = "fail")] + | ^^^^^^ diff --git a/vendor/structopt/tests/ui/skip_flatten.rs b/vendor/structopt/tests/ui/skip_flatten.rs new file mode 100644 index 0000000000000..8668ec2a952df --- /dev/null +++ b/vendor/structopt/tests/ui/skip_flatten.rs @@ -0,0 +1,42 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "make-cookie")] +struct MakeCookie { + #[structopt(short)] + s: String, + + #[structopt(skip, flatten)] + cmd: Command, +} + +#[derive(StructOpt, Debug)] +enum Command { + #[structopt(name = "pound")] + /// Pound acorns into flour for cookie dough. + Pound { acorns: u32 }, + + Sparkle { + #[structopt(short)] + color: String, + }, +} + +impl Default for Command { + fn default() -> Self { + Command::Pound { acorns: 0 } + } +} + +fn main() { + let opt = MakeCookie::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/skip_flatten.stderr b/vendor/structopt/tests/ui/skip_flatten.stderr new file mode 100644 index 0000000000000..76477a3c9b09b --- /dev/null +++ b/vendor/structopt/tests/ui/skip_flatten.stderr @@ -0,0 +1,5 @@ +error: subcommand, flatten and skip cannot be used together + --> $DIR/skip_flatten.rs:17:23 + | +17 | #[structopt(skip, flatten)] + | ^^^^^^^ diff --git a/vendor/structopt/tests/ui/skip_subcommand.rs b/vendor/structopt/tests/ui/skip_subcommand.rs new file mode 100644 index 0000000000000..5d21426b8fe20 --- /dev/null +++ b/vendor/structopt/tests/ui/skip_subcommand.rs @@ -0,0 +1,42 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "make-cookie")] +struct MakeCookie { + #[structopt(short)] + s: String, + + #[structopt(subcommand, skip)] + cmd: Command, +} + +#[derive(StructOpt, Debug)] +enum Command { + #[structopt(name = "pound")] + /// Pound acorns into flour for cookie dough. + Pound { acorns: u32 }, + + Sparkle { + #[structopt(short)] + color: String, + }, +} + +impl Default for Command { + fn default() -> Self { + Command::Pound { acorns: 0 } + } +} + +fn main() { + let opt = MakeCookie::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/skip_subcommand.stderr b/vendor/structopt/tests/ui/skip_subcommand.stderr new file mode 100644 index 0000000000000..aba2d69f3e3f9 --- /dev/null +++ b/vendor/structopt/tests/ui/skip_subcommand.stderr @@ -0,0 +1,5 @@ +error: subcommand, flatten and skip cannot be used together + --> $DIR/skip_subcommand.rs:17:29 + | +17 | #[structopt(subcommand, skip)] + | ^^^^ diff --git a/vendor/structopt/tests/ui/skip_with_other_options.rs b/vendor/structopt/tests/ui/skip_with_other_options.rs new file mode 100644 index 0000000000000..73c53420cbce3 --- /dev/null +++ b/vendor/structopt/tests/ui/skip_with_other_options.rs @@ -0,0 +1,15 @@ +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "test")] +pub struct Opt { + #[structopt(long)] + a: u32, + #[structopt(skip, long)] + b: u32, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/skip_with_other_options.stderr b/vendor/structopt/tests/ui/skip_with_other_options.stderr new file mode 100644 index 0000000000000..3345f9270e4ad --- /dev/null +++ b/vendor/structopt/tests/ui/skip_with_other_options.stderr @@ -0,0 +1,5 @@ +error: methods are not allowed for skipped fields + --> $DIR/skip_with_other_options.rs:8:17 + | +8 | #[structopt(skip, long)] + | ^^^^ diff --git a/vendor/structopt/tests/ui/skip_without_default.rs b/vendor/structopt/tests/ui/skip_without_default.rs new file mode 100644 index 0000000000000..bc47511f863b6 --- /dev/null +++ b/vendor/structopt/tests/ui/skip_without_default.rs @@ -0,0 +1,29 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(Debug)] +enum Kind { + A, + B, +} + +#[derive(StructOpt, Debug)] +#[structopt(name = "test")] +pub struct Opt { + #[structopt(short)] + number: u32, + #[structopt(skip)] + k: Kind, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/skip_without_default.stderr b/vendor/structopt/tests/ui/skip_without_default.stderr new file mode 100644 index 0000000000000..d08be0cc2f634 --- /dev/null +++ b/vendor/structopt/tests/ui/skip_without_default.stderr @@ -0,0 +1,7 @@ +error[E0277]: the trait bound `Kind: Default` is not satisfied + --> $DIR/skip_without_default.rs:22:17 + | +22 | #[structopt(skip)] + | ^^^^ the trait `Default` is not implemented for `Kind` + | +note: required by `std::default::Default::default` diff --git a/vendor/structopt/tests/ui/struct_parse.rs b/vendor/structopt/tests/ui/struct_parse.rs new file mode 100644 index 0000000000000..e428b23f9c583 --- /dev/null +++ b/vendor/structopt/tests/ui/struct_parse.rs @@ -0,0 +1,21 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic", parse(from_str))] +struct Opt { + #[structopt(short)] + s: String, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/struct_parse.stderr b/vendor/structopt/tests/ui/struct_parse.stderr new file mode 100644 index 0000000000000..5518214e5f7f3 --- /dev/null +++ b/vendor/structopt/tests/ui/struct_parse.stderr @@ -0,0 +1,5 @@ +error: `parse` attribute is only allowed on fields + --> $DIR/struct_parse.rs:12:29 + | +12 | #[structopt(name = "basic", parse(from_str))] + | ^^^^^ diff --git a/vendor/structopt/tests/ui/struct_subcommand.rs b/vendor/structopt/tests/ui/struct_subcommand.rs new file mode 100644 index 0000000000000..ac0b1457f5f48 --- /dev/null +++ b/vendor/structopt/tests/ui/struct_subcommand.rs @@ -0,0 +1,21 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic", subcommand)] +struct Opt { + #[structopt(short)] + s: String, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/struct_subcommand.stderr b/vendor/structopt/tests/ui/struct_subcommand.stderr new file mode 100644 index 0000000000000..438f6f804881e --- /dev/null +++ b/vendor/structopt/tests/ui/struct_subcommand.stderr @@ -0,0 +1,5 @@ +error: subcommand is only allowed on fields + --> $DIR/struct_subcommand.rs:12:29 + | +12 | #[structopt(name = "basic", subcommand)] + | ^^^^^^^^^^ diff --git a/vendor/structopt/tests/ui/structopt_empty_attr.rs b/vendor/structopt/tests/ui/structopt_empty_attr.rs new file mode 100644 index 0000000000000..a7fc0b998f2ad --- /dev/null +++ b/vendor/structopt/tests/ui/structopt_empty_attr.rs @@ -0,0 +1,22 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt] + debug: bool, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} + diff --git a/vendor/structopt/tests/ui/structopt_empty_attr.stderr b/vendor/structopt/tests/ui/structopt_empty_attr.stderr new file mode 100644 index 0000000000000..bd3b3eda41714 --- /dev/null +++ b/vendor/structopt/tests/ui/structopt_empty_attr.stderr @@ -0,0 +1,5 @@ +error: expected attribute arguments in parentheses: #[structopt(...)] + --> $DIR/structopt_empty_attr.rs:14:5 + | +14 | #[structopt] + | ^^^^^^^^^^^^ diff --git a/vendor/structopt/tests/ui/structopt_name_value_attr.rs b/vendor/structopt/tests/ui/structopt_name_value_attr.rs new file mode 100644 index 0000000000000..3d9388f2ab260 --- /dev/null +++ b/vendor/structopt/tests/ui/structopt_name_value_attr.rs @@ -0,0 +1,22 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt { + #[structopt = "short"] + debug: bool, +} + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} + diff --git a/vendor/structopt/tests/ui/structopt_name_value_attr.stderr b/vendor/structopt/tests/ui/structopt_name_value_attr.stderr new file mode 100644 index 0000000000000..373a3b8e15a6e --- /dev/null +++ b/vendor/structopt/tests/ui/structopt_name_value_attr.stderr @@ -0,0 +1,5 @@ +error: expected parentheses: #[structopt(...)] + --> $DIR/structopt_name_value_attr.rs:14:17 + | +14 | #[structopt = "short"] + | ^ diff --git a/vendor/structopt/tests/ui/subcommand_and_flatten.rs b/vendor/structopt/tests/ui/subcommand_and_flatten.rs new file mode 100644 index 0000000000000..742ee6d0b68c3 --- /dev/null +++ b/vendor/structopt/tests/ui/subcommand_and_flatten.rs @@ -0,0 +1,36 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "make-cookie")] +struct MakeCookie { + #[structopt(short)] + s: String, + + #[structopt(subcommand, flatten)] + cmd: Command, +} + +#[derive(StructOpt, Debug)] +enum Command { + #[structopt(name = "pound")] + /// Pound acorns into flour for cookie dough. + Pound { acorns: u32 }, + + Sparkle { + #[structopt(short)] + color: String, + }, +} + +fn main() { + let opt = MakeCookie::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/subcommand_and_flatten.stderr b/vendor/structopt/tests/ui/subcommand_and_flatten.stderr new file mode 100644 index 0000000000000..cacea5edc3eee --- /dev/null +++ b/vendor/structopt/tests/ui/subcommand_and_flatten.stderr @@ -0,0 +1,5 @@ +error: subcommand, flatten and skip cannot be used together + --> $DIR/subcommand_and_flatten.rs:17:29 + | +17 | #[structopt(subcommand, flatten)] + | ^^^^^^^ diff --git a/vendor/structopt/tests/ui/subcommand_and_methods.rs b/vendor/structopt/tests/ui/subcommand_and_methods.rs new file mode 100644 index 0000000000000..890f10c5e7658 --- /dev/null +++ b/vendor/structopt/tests/ui/subcommand_and_methods.rs @@ -0,0 +1,36 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "make-cookie")] +struct MakeCookie { + #[structopt(short)] + s: String, + + #[structopt(subcommand, long)] + cmd: Command, +} + +#[derive(StructOpt, Debug)] +enum Command { + #[structopt(name = "pound")] + /// Pound acorns into flour for cookie dough. + Pound { acorns: u32 }, + + Sparkle { + #[structopt(short)] + color: String, + }, +} + +fn main() { + let opt = MakeCookie::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/subcommand_and_methods.stderr b/vendor/structopt/tests/ui/subcommand_and_methods.stderr new file mode 100644 index 0000000000000..ccaf28dea0a27 --- /dev/null +++ b/vendor/structopt/tests/ui/subcommand_and_methods.stderr @@ -0,0 +1,5 @@ +error: methods in attributes are not allowed for subcommand + --> $DIR/subcommand_and_methods.rs:17:17 + | +17 | #[structopt(subcommand, long)] + | ^^^^^^^^^^ diff --git a/vendor/structopt/tests/ui/subcommand_and_parse.rs b/vendor/structopt/tests/ui/subcommand_and_parse.rs new file mode 100644 index 0000000000000..f24e4bc797040 --- /dev/null +++ b/vendor/structopt/tests/ui/subcommand_and_parse.rs @@ -0,0 +1,36 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "make-cookie")] +struct MakeCookie { + #[structopt(short)] + s: String, + + #[structopt(subcommand, parse(from_occurrences))] + cmd: Command, +} + +#[derive(StructOpt, Debug)] +enum Command { + #[structopt(name = "pound")] + /// Pound acorns into flour for cookie dough. + Pound { acorns: u32 }, + + Sparkle { + #[structopt(short)] + color: String, + }, +} + +fn main() { + let opt = MakeCookie::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/subcommand_and_parse.stderr b/vendor/structopt/tests/ui/subcommand_and_parse.stderr new file mode 100644 index 0000000000000..407005650e94b --- /dev/null +++ b/vendor/structopt/tests/ui/subcommand_and_parse.stderr @@ -0,0 +1,5 @@ +error: parse attribute is not allowed for subcommand + --> $DIR/subcommand_and_parse.rs:17:29 + | +17 | #[structopt(subcommand, parse(from_occurrences))] + | ^^^^^ diff --git a/vendor/structopt/tests/ui/subcommand_opt_opt.rs b/vendor/structopt/tests/ui/subcommand_opt_opt.rs new file mode 100644 index 0000000000000..1dd84e54b267e --- /dev/null +++ b/vendor/structopt/tests/ui/subcommand_opt_opt.rs @@ -0,0 +1,36 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "make-cookie")] +struct MakeCookie { + #[structopt(short)] + s: String, + + #[structopt(subcommand)] + cmd: Option>, +} + +#[derive(StructOpt, Debug)] +enum Command { + #[structopt(name = "pound")] + /// Pound acorns into flour for cookie dough. + Pound { acorns: u32 }, + + Sparkle { + #[structopt(short)] + color: String, + }, +} + +fn main() { + let opt = MakeCookie::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/subcommand_opt_opt.stderr b/vendor/structopt/tests/ui/subcommand_opt_opt.stderr new file mode 100644 index 0000000000000..25b37e5fd983b --- /dev/null +++ b/vendor/structopt/tests/ui/subcommand_opt_opt.stderr @@ -0,0 +1,5 @@ +error: Option> type is not allowed for subcommand + --> $DIR/subcommand_opt_opt.rs:18:10 + | +18 | cmd: Option>, + | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/vendor/structopt/tests/ui/subcommand_opt_vec.rs b/vendor/structopt/tests/ui/subcommand_opt_vec.rs new file mode 100644 index 0000000000000..17bffbf11b646 --- /dev/null +++ b/vendor/structopt/tests/ui/subcommand_opt_vec.rs @@ -0,0 +1,36 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "make-cookie")] +struct MakeCookie { + #[structopt(short)] + s: String, + + #[structopt(subcommand)] + cmd: Option>, +} + +#[derive(StructOpt, Debug)] +enum Command { + #[structopt(name = "pound")] + /// Pound acorns into flour for cookie dough. + Pound { acorns: u32 }, + + Sparkle { + #[structopt(short)] + color: String, + }, +} + +fn main() { + let opt = MakeCookie::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/subcommand_opt_vec.stderr b/vendor/structopt/tests/ui/subcommand_opt_vec.stderr new file mode 100644 index 0000000000000..a36071b4b8134 --- /dev/null +++ b/vendor/structopt/tests/ui/subcommand_opt_vec.stderr @@ -0,0 +1,5 @@ +error: Option> type is not allowed for subcommand + --> $DIR/subcommand_opt_vec.rs:18:10 + | +18 | cmd: Option>, + | ^^^^^^^^^^^^^^^^^^^^ diff --git a/vendor/structopt/tests/ui/tuple_struct.rs b/vendor/structopt/tests/ui/tuple_struct.rs new file mode 100644 index 0000000000000..af9b1d5c7b348 --- /dev/null +++ b/vendor/structopt/tests/ui/tuple_struct.rs @@ -0,0 +1,18 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +#[structopt(name = "basic")] +struct Opt(u32); + +fn main() { + let opt = Opt::from_args(); + println!("{:?}", opt); +} diff --git a/vendor/structopt/tests/ui/tuple_struct.stderr b/vendor/structopt/tests/ui/tuple_struct.stderr new file mode 100644 index 0000000000000..ad923857458d7 --- /dev/null +++ b/vendor/structopt/tests/ui/tuple_struct.stderr @@ -0,0 +1,7 @@ +error: structopt only supports non-tuple structs and enums + --> $DIR/tuple_struct.rs:11:10 + | +11 | #[derive(StructOpt, Debug)] + | ^^^^^^^^^ + | + = note: this error originates in the derive macro `StructOpt` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/structopt/tests/utils.rs b/vendor/structopt/tests/utils.rs new file mode 100644 index 0000000000000..c0684a20096fd --- /dev/null +++ b/vendor/structopt/tests/utils.rs @@ -0,0 +1,45 @@ +#![allow(unused)] + +use structopt::StructOpt; + +pub fn get_help() -> String { + let mut output = Vec::new(); + ::clap().write_help(&mut output).unwrap(); + let output = String::from_utf8(output).unwrap(); + + eprintln!("\n%%% HELP %%%:=====\n{}\n=====\n", output); + eprintln!("\n%%% HELP (DEBUG) %%%:=====\n{:?}\n=====\n", output); + + output +} + +pub fn get_long_help() -> String { + let mut output = Vec::new(); + ::clap() + .write_long_help(&mut output) + .unwrap(); + let output = String::from_utf8(output).unwrap(); + + eprintln!("\n%%% LONG_HELP %%%:=====\n{}\n=====\n", output); + eprintln!("\n%%% LONG_HELP (DEBUG) %%%:=====\n{:?}\n=====\n", output); + + output +} + +pub fn get_subcommand_long_help(subcmd: &str) -> String { + let output = ::clap() + .get_matches_from_safe(vec!["test", subcmd, "--help"]) + .expect_err("") + .message; + + eprintln!( + "\n%%% SUBCOMMAND `{}` HELP %%%:=====\n{}\n=====\n", + subcmd, output + ); + eprintln!( + "\n%%% SUBCOMMAND `{}` HELP (DEBUG) %%%:=====\n{:?}\n=====\n", + subcmd, output + ); + + output +} diff --git a/vendor/structopt/tests/we_need_syn_full.rs b/vendor/structopt/tests/we_need_syn_full.rs new file mode 100644 index 0000000000000..cc6eca89f50e8 --- /dev/null +++ b/vendor/structopt/tests/we_need_syn_full.rs @@ -0,0 +1,19 @@ +// See https://github.com/TeXitoi/structopt/issues/354 + +use structopt::StructOpt; + +#[test] +fn we_need_syn_full() { + #[allow(unused)] + #[derive(Debug, StructOpt, Clone)] + struct Args { + #[structopt( + short = "c", + long = "colour", + help = "Output colouring", + default_value = "auto", + possible_values = &["always", "auto", "never"] + )] + colour: String, + } +} diff --git a/vendor/syn/src/gen_helper.rs b/vendor/syn/src/gen_helper.rs new file mode 100644 index 0000000000000..e433bac3a711c --- /dev/null +++ b/vendor/syn/src/gen_helper.rs @@ -0,0 +1,34 @@ +#[cfg(feature = "fold")] +pub(crate) mod fold { + use crate::punctuated::{Pair, Punctuated}; + + pub(crate) trait FoldHelper { + type Item; + fn lift(self, f: F) -> Self + where + F: FnMut(Self::Item) -> Self::Item; + } + + impl FoldHelper for Vec { + type Item = T; + fn lift(self, f: F) -> Self + where + F: FnMut(Self::Item) -> Self::Item, + { + self.into_iter().map(f).collect() + } + } + + impl FoldHelper for Punctuated { + type Item = T; + fn lift(self, mut f: F) -> Self + where + F: FnMut(Self::Item) -> Self::Item, + { + self.into_pairs() + .map(Pair::into_tuple) + .map(|(t, u)| Pair::new(f(t), u)) + .collect() + } + } +} diff --git a/vendor/syn/tests/test_should_parse.rs b/vendor/syn/tests/test_should_parse.rs new file mode 100644 index 0000000000000..180d8599163e1 --- /dev/null +++ b/vendor/syn/tests/test_should_parse.rs @@ -0,0 +1,45 @@ +macro_rules! should_parse { + ($name:ident, { $($in:tt)* }) => { + #[test] + fn $name() { + // Make sure we can parse the file! + syn::parse_file(stringify!($($in)*)).unwrap(); + } + } +} + +should_parse!(generic_associated_type, { + impl Foo { + type Item = &'a i32; + fn foo<'a>(&'a self) -> Self::Item<'a> {} + } +}); + +#[rustfmt::skip] +should_parse!(const_generics_use, { + type X = Foo<5>; + type Y = Foo<"foo">; + type Z = Foo; + type W = Foo<{ X + 10 }>; +}); + +should_parse!(trailing_plus_type, { + type A = Box; + type A = Box; + type A = Box<'a + Foo>; +}); + +should_parse!(generic_associated_type_where, { + trait Foo { + type Item; + fn foo(&self, t: T) -> Self::Item; + } +}); + +should_parse!(match_with_block_expr, { + fn main() { + match false { + _ => {}.a(), + } + } +}); diff --git a/vendor/temp-dir/src/test.rs b/vendor/temp-dir/src/test.rs new file mode 100644 index 0000000000000..c5277468fcab3 --- /dev/null +++ b/vendor/temp-dir/src/test.rs @@ -0,0 +1,259 @@ +use crate::{TempDir, COUNTER, INTERNAL_RETRY}; +use core::sync::atomic::Ordering; +use safe_lock::SafeLock; +use std::io::ErrorKind; +use std::path::Path; + +// TODO: Move this file to tests/ dir. + +// The error tests require all tests to run single-threaded. +static LOCK: SafeLock = SafeLock::new(); + +fn make_non_writable(path: &Path) { + let metadata = std::fs::metadata(path).unwrap(); + let mut permissions = metadata.permissions(); + permissions.set_readonly(true); + std::fs::set_permissions(path, permissions).unwrap(); +} + +fn make_writable(path: &Path) { + let metadata = std::fs::metadata(path).unwrap(); + let mut permissions = metadata.permissions(); + #[allow(clippy::permissions_set_readonly_false)] + permissions.set_readonly(false); + std::fs::set_permissions(path, permissions).unwrap(); +} + +fn should_skip_cleanup_test() -> bool { + // On Gitlab's shared CI runners, the cleanup always succeeds and the + // test fails. So we skip these tests when it's running on Gitlab CI. + if std::env::current_dir().unwrap().starts_with("/builds/") { + println!("Running on Gitlab CI. Skipping test."); + return true; + } + false +} + +struct DisableRetryAndEnableOnDrop; +impl DisableRetryAndEnableOnDrop { + pub fn new() -> Self { + INTERNAL_RETRY.store(false, Ordering::SeqCst); + Self {} + } +} +impl Drop for DisableRetryAndEnableOnDrop { + fn drop(&mut self) { + INTERNAL_RETRY.store(true, Ordering::SeqCst); + } +} + +#[test] +fn new() { + let _guard = LOCK.lock(); + let temp_dir = TempDir::new().unwrap(); + println!("{temp_dir:?}"); + println!("{:?}", TempDir::new().unwrap()); + let metadata = std::fs::metadata(temp_dir.path()).unwrap(); + assert!(metadata.is_dir()); + let temp_dir2 = TempDir::new().unwrap(); + assert_ne!(temp_dir.path(), temp_dir2.path()); +} + +#[test] +fn new_error() { + let _guard = LOCK.lock(); + let _disable_retry = DisableRetryAndEnableOnDrop::new(); + let previous_counter_value = COUNTER.load(Ordering::SeqCst); + let temp_dir = TempDir::new().unwrap(); + let dir_path = temp_dir.path().to_path_buf(); + COUNTER.store(previous_counter_value, Ordering::SeqCst); + let e = TempDir::new().unwrap_err(); + assert_eq!(std::io::ErrorKind::AlreadyExists, e.kind()); + assert!( + e.to_string() + .starts_with(&format!("error creating directory {dir_path:?}: ")), + "unexpected error {e:?}", + ); +} + +#[test] +fn with_prefix() { + let _guard = LOCK.lock(); + let temp_dir = TempDir::with_prefix("prefix1").unwrap(); + let name = temp_dir.path().file_name().unwrap(); + assert!( + name.to_str().unwrap().starts_with("prefix1"), + "{temp_dir:?}", + ); + let metadata = std::fs::metadata(temp_dir.path()).unwrap(); + assert!(metadata.is_dir()); + let temp_dir2 = TempDir::new().unwrap(); + assert_ne!(temp_dir.path(), temp_dir2.path()); +} + +#[test] +fn with_prefix_error() { + let _guard = LOCK.lock(); + let _disable_retry = DisableRetryAndEnableOnDrop::new(); + let previous_counter_value = COUNTER.load(Ordering::SeqCst); + let temp_dir = TempDir::with_prefix("prefix1").unwrap(); + COUNTER.store(previous_counter_value, Ordering::SeqCst); + let e = TempDir::with_prefix("prefix1").unwrap_err(); + assert_eq!(std::io::ErrorKind::AlreadyExists, e.kind()); + assert!( + e.to_string() + .starts_with(&format!("error creating directory {:?}: ", temp_dir.path())), + "unexpected error {e:?}", + ); +} + +#[test] +fn child() { + let _guard = LOCK.lock(); + let temp_dir = TempDir::new().unwrap(); + let file1_path = temp_dir.child("file1"); + assert!( + file1_path.ends_with("file1"), + "{:?}", + file1_path.to_string_lossy() + ); + assert!( + file1_path.starts_with(temp_dir.path()), + "{:?}", + file1_path.to_string_lossy() + ); + std::fs::write(&file1_path, b"abc").unwrap(); +} + +#[test] +fn cleanup() { + let _guard = LOCK.lock(); + let temp_dir = TempDir::new().unwrap(); + std::fs::write(temp_dir.child("file1"), b"abc").unwrap(); + let dir_path = temp_dir.path().to_path_buf(); + std::fs::metadata(&dir_path).unwrap(); + temp_dir.cleanup().unwrap(); + assert_eq!( + ErrorKind::NotFound, + std::fs::metadata(&dir_path).unwrap_err().kind() + ); +} + +#[test] +fn cleanup_already_deleted() { + let _guard = LOCK.lock(); + let temp_dir = TempDir::new().unwrap(); + std::fs::remove_dir_all(temp_dir.path()).unwrap(); + temp_dir.cleanup().unwrap(); +} + +#[cfg(unix)] +#[test] +fn cleanup_error() { + if should_skip_cleanup_test() { + return; + } + let _guard = LOCK.lock(); + let temp_dir = TempDir::new().unwrap(); + let dir_path = temp_dir.path().to_path_buf(); + let file1_path = temp_dir.child("file1"); + std::fs::write(&file1_path, b"abc").unwrap(); + make_non_writable(&dir_path); + let result = temp_dir.cleanup(); + std::fs::metadata(&dir_path).unwrap(); + std::fs::metadata(&file1_path).unwrap(); + make_writable(&dir_path); + std::fs::remove_dir_all(&dir_path).unwrap(); + let e = result.unwrap_err(); + assert_eq!(std::io::ErrorKind::PermissionDenied, e.kind()); + assert!( + e.to_string().starts_with(&format!( + "error removing directory and contents {dir_path:?}: " + )), + "unexpected error {e:?}", + ); +} + +#[test] +fn test_drop() { + let _guard = LOCK.lock(); + let temp_dir = TempDir::new().unwrap(); + let dir_path = temp_dir.path().to_path_buf(); + let file1_path = temp_dir.child("file1"); + std::fs::write(&file1_path, b"abc").unwrap(); + TempDir::new().unwrap(); + std::fs::metadata(&dir_path).unwrap(); + std::fs::metadata(&file1_path).unwrap(); + drop(temp_dir); + assert_eq!( + ErrorKind::NotFound, + std::fs::metadata(&dir_path).unwrap_err().kind() + ); + assert_eq!( + ErrorKind::NotFound, + std::fs::metadata(&file1_path).unwrap_err().kind() + ); +} + +#[test] +fn drop_already_deleted() { + let _guard = LOCK.lock(); + let temp_dir = TempDir::new().unwrap(); + std::fs::remove_dir(temp_dir.path()).unwrap(); +} + +#[cfg(unix)] +#[test] +fn drop_error_ignored() { + if should_skip_cleanup_test() { + return; + } + let _guard = LOCK.lock(); + let temp_dir = TempDir::new().unwrap(); + let dir_path = temp_dir.path().to_path_buf(); + let file1_path = temp_dir.child("file1"); + std::fs::write(&file1_path, b"abc").unwrap(); + make_non_writable(&dir_path); + drop(temp_dir); + std::fs::metadata(&dir_path).unwrap(); + std::fs::metadata(&file1_path).unwrap(); + make_writable(&dir_path); + std::fs::remove_dir_all(&dir_path).unwrap(); +} + +#[cfg(unix)] +#[test] +fn drop_error_panic() { + if should_skip_cleanup_test() { + return; + } + let _guard = LOCK.lock(); + let temp_dir = TempDir::new().unwrap().panic_on_cleanup_error(); + let dir_path = temp_dir.path().to_path_buf(); + let file1_path = temp_dir.child("file1"); + std::fs::write(&file1_path, b"abc").unwrap(); + make_non_writable(&dir_path); + let result = std::panic::catch_unwind(move || drop(temp_dir)); + std::fs::metadata(&dir_path).unwrap(); + std::fs::metadata(&file1_path).unwrap(); + make_writable(&dir_path); + std::fs::remove_dir_all(&dir_path).unwrap(); + let msg = result.unwrap_err().downcast::().unwrap(); + assert!( + msg.contains("error removing directory and contents ",), + "unexpected panic message {msg:?}", + ); +} + +#[test] +fn leak() { + let _guard = LOCK.lock(); + let temp_dir = TempDir::new().unwrap(); + let dir_path = temp_dir.path().to_path_buf(); + let file1_path = temp_dir.child("file1"); + std::fs::write(&file1_path, b"abc").unwrap(); + temp_dir.leak(); + std::fs::metadata(&dir_path).unwrap(); + std::fs::metadata(&file1_path).unwrap(); + std::fs::remove_dir_all(&dir_path).unwrap(); +} diff --git a/vendor/textwrap/.cargo-checksum.json b/vendor/textwrap/.cargo-checksum.json new file mode 100644 index 0000000000000..02794aab85c0c --- /dev/null +++ b/vendor/textwrap/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"a0e3c783725beb480b666d52d49da0ec69865c82e8bd5c8a76ba330158e954c1","LICENSE":"ce93600c49fbb3e14df32efe752264644f6a2f8e08a735ba981725799e5309ef","README.md":"9af1f6627e8c2e19c7383c99462ca028b235b2f8dadbb33f13e2d1663c8c20e3","benches/linear.rs":"ec084063923bafc6e80c2cd78deb0f7ad18ae19a7e66005e991e00dac1ff3ce4","examples/layout.rs":"38cf4d316d28e0b99925bef604b68aad05489c06ec77e6105575cd26ce994631","examples/termwidth.rs":"67d95b60feb52cfd59fe5b17c37c53e51fb7f2a8e5e483d75aec8d0044dbcbd7","src/indentation.rs":"04f8479286fd87f2d75b0f02ce8309a815a5ffd1e79a7323132e34dc0e107aef","src/lib.rs":"115bf6ec566b8241d52cff83977146f03df3460d6f94ad897f2221cb56100118","src/splitting.rs":"071ef8ce0ea6c3f33230889a3426fd645276a6de626f45223ae7b873394df662","tests/version-numbers.rs":"e0e9316073d6d410440a6ee33c2f3bdfd0faa48895f6f9d05a220a91b7afcc99"},"package":"d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"} \ No newline at end of file diff --git a/vendor/textwrap/Cargo.toml b/vendor/textwrap/Cargo.toml new file mode 100644 index 0000000000000..4ec570f10c3e1 --- /dev/null +++ b/vendor/textwrap/Cargo.toml @@ -0,0 +1,56 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "textwrap" +version = "0.11.0" +authors = ["Martin Geisler "] +exclude = [".dir-locals.el"] +description = "Textwrap is a small library for word wrapping, indenting, and\ndedenting strings.\n\nYou can use it to format strings (such as help and error messages) for\ndisplay in commandline applications. It is designed to be efficient\nand handle Unicode characters correctly.\n" +documentation = "https://docs.rs/textwrap/" +readme = "README.md" +keywords = ["text", "formatting", "wrap", "typesetting", "hyphenation"] +categories = ["text-processing", "command-line-interface"] +license = "MIT" +repository = "https://github.com/mgeisler/textwrap" +[package.metadata.docs.rs] +all-features = true +[dependencies.hyphenation] +version = "0.7.1" +features = ["embed_all"] +optional = true + +[dependencies.term_size] +version = "0.3.0" +optional = true + +[dependencies.unicode-width] +version = "0.1.3" +[dev-dependencies.lipsum] +version = "0.6" + +[dev-dependencies.rand] +version = "0.6" + +[dev-dependencies.rand_xorshift] +version = "0.1" + +[dev-dependencies.version-sync] +version = "0.6" +[badges.appveyor] +repository = "mgeisler/textwrap" + +[badges.codecov] +repository = "mgeisler/textwrap" + +[badges.travis-ci] +repository = "mgeisler/textwrap" diff --git a/vendor/textwrap/LICENSE b/vendor/textwrap/LICENSE new file mode 100644 index 0000000000000..0d37ec3891d86 --- /dev/null +++ b/vendor/textwrap/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Martin Geisler + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/textwrap/README.md b/vendor/textwrap/README.md new file mode 100644 index 0000000000000..23a54390438e8 --- /dev/null +++ b/vendor/textwrap/README.md @@ -0,0 +1,337 @@ +# Textwrap + +[![](https://img.shields.io/crates/v/textwrap.svg)][crates-io] +[![](https://docs.rs/textwrap/badge.svg)][api-docs] +[![](https://travis-ci.org/mgeisler/textwrap.svg?branch=master)][travis-ci] +[![](https://ci.appveyor.com/api/projects/status/github/mgeisler/textwrap?branch=master&svg=true)][appveyor] +[![](https://codecov.io/gh/mgeisler/textwrap/branch/master/graph/badge.svg)][codecov] + +Textwrap is a small Rust crate for word wrapping text. You can use it +to format strings for display in commandline applications. The crate +name and interface is inspired by +the [Python textwrap module][py-textwrap]. + +## Usage + +Add this to your `Cargo.toml`: +```toml +[dependencies] +textwrap = "0.11" +``` + +and this to your crate root: +```rust +extern crate textwrap; +``` + +If you would like to have automatic hyphenation, specify the +dependency as: +```toml +[dependencies] +textwrap = { version = "0.11", features = ["hyphenation"] } +``` + +To conveniently wrap text at the current terminal width, enable the +`term_size` feature: + +```toml +[dependencies] +textwrap = { version = "0.11", features = ["term_size"] } +``` + +## Documentation + +**[API documentation][api-docs]** + +## Getting Started + +Word wrapping single strings is easy using the `fill` function: +```rust +extern crate textwrap; +use textwrap::fill; + +fn main() { + let text = "textwrap: a small library for wrapping text."; + println!("{}", fill(text, 18)); +} +``` +The output is +``` +textwrap: a small +library for +wrapping text. +``` + +With the `hyphenation` feature, you can get automatic hyphenation +for [about 70 languages][patterns]. Your program must load and +configure the hyphenation patterns to use: +```rust +extern crate hyphenation; +extern crate textwrap; + +use hyphenation::{Language, Load, Standard}; +use textwrap::Wrapper; + +fn main() { + let hyphenator = Standard::from_embedded(Language::EnglishUS).unwrap(); + let wrapper = Wrapper::with_splitter(18, hyphenator); + let text = "textwrap: a small library for wrapping text."; + println!("{}", wrapper.fill(text)) +} +``` + +The output now looks like this: +``` +textwrap: a small +library for wrap- +ping text. +``` + +The hyphenation uses high-quality TeX hyphenation patterns. + +## Examples + +The library comes with some small example programs that shows various +features. + +### Layout Example + +The `layout` example shows how a fixed example string is wrapped at +different widths. Run the example with: + +```shell +$ cargo run --features hyphenation --example layout +``` + +The program will use the following string: + +> Memory safety without garbage collection. Concurrency without data +> races. Zero-cost abstractions. + +The string is wrapped at all widths between 15 and 60 columns. With +narrow columns the output looks like this: + +``` +.--- Width: 15 ---. +| Memory safety | +| without garbage | +| collection. | +| Concurrency | +| without data | +| races. Zero- | +| cost abstrac- | +| tions. | +.--- Width: 16 ----. +| Memory safety | +| without garbage | +| collection. Con- | +| currency without | +| data races. Ze- | +| ro-cost abstrac- | +| tions. | +``` + +Later, longer lines are used and the output now looks like this: + +``` +.-------------------- Width: 49 --------------------. +| Memory safety without garbage collection. Concur- | +| rency without data races. Zero-cost abstractions. | +.---------------------- Width: 53 ----------------------. +| Memory safety without garbage collection. Concurrency | +| without data races. Zero-cost abstractions. | +.------------------------- Width: 59 -------------------------. +| Memory safety without garbage collection. Concurrency with- | +| out data races. Zero-cost abstractions. | +``` + +Notice how words are split at hyphens (such as "zero-cost") but also +how words are hyphenated using automatic/machine hyphenation. + +### Terminal Width Example + +The `termwidth` example simply shows how the width can be set +automatically to the current terminal width. Run it with this command: + +``` +$ cargo run --example termwidth +``` + +If you run it in a narrow terminal, you'll see output like this: +``` +Formatted in within 60 columns: +---- +Memory safety without garbage collection. Concurrency +without data races. Zero-cost abstractions. +---- +``` + +If `stdout` is not connected to the terminal, the program will use a +default of 80 columns for the width: + +``` +$ cargo run --example termwidth | cat +Formatted in within 80 columns: +---- +Memory safety without garbage collection. Concurrency without data races. Zero- +cost abstractions. +---- +``` + +## Release History + +This section lists the largest changes per release. + +### Version 0.11.0 — December 9th, 2018 + +Due to our dependencies bumping their minimum supported version of +Rust, the minimum version of Rust we test against is now 1.22.0. + +* Merged [#141][issue-141]: Fix `dedent` handling of empty lines and + trailing newlines. Thanks @bbqsrc! +* Fixed [#151][issue-151]: Release of version with hyphenation 0.7. + +### Version 0.10.0 — April 28th, 2018 + +Due to our dependencies bumping their minimum supported version of +Rust, the minimum version of Rust we test against is now 1.17.0. + +* Fixed [#99][issue-99]: Word broken even though it would fit on line. +* Fixed [#107][issue-107]: Automatic hyphenation is off by one. +* Fixed [#122][issue-122]: Take newlines into account when wrapping. +* Fixed [#129][issue-129]: Panic on string with em-dash. + +### Version 0.9.0 — October 5th, 2017 + +The dependency on `term_size` is now optional, and by default this +feature is not enabled. This is a *breaking change* for users of +`Wrapper::with_termwidth`. Enable the `term_size` feature to restore +the old functionality. + +Added a regression test for the case where `width` is set to +`usize::MAX`, thanks @Fraser999! All public structs now implement +`Debug`, thanks @hcpl! + +* Fixed [#101][issue-101]: Make `term_size` an optional dependency. + +### Version 0.8.0 — September 4th, 2017 + +The `Wrapper` stuct is now generic over the type of word splitter +being used. This means less boxing and a nicer API. The +`Wrapper::word_splitter` method has been removed. This is a *breaking +API change* if you used the method to change the word splitter. + +The `Wrapper` struct has two new methods that will wrap the input text +lazily: `Wrapper::wrap_iter` and `Wrapper::into_wrap_iter`. Use those +if you will be iterating over the wrapped lines one by one. + +* Fixed [#59][issue-59]: `wrap` could return an iterator. Thanks + @hcpl! +* Fixed [#81][issue-81]: Set `html_root_url`. + +### Version 0.7.0 — July 20th, 2017 + +Version 0.7.0 changes the return type of `Wrapper::wrap` from +`Vec` to `Vec>`. This means that the output lines +borrow data from the input string. This is a *breaking API change* if +you relied on the exact return type of `Wrapper::wrap`. Callers of the +`textwrap::fill` convenience function will see no breakage. + +The above change and other optimizations makes version 0.7.0 roughly +15-30% faster than version 0.6.0. + +The `squeeze_whitespace` option has been removed since it was +complicating the above optimization. Let us know if this option is +important for you so we can provide a work around. + +* Fixed [#58][issue-58]: Add a "fast_wrap" function. +* Fixed [#61][issue-61]: Documentation errors. + +### Version 0.6.0 — May 22nd, 2017 + +Version 0.6.0 adds builder methods to `Wrapper` for easy one-line +initialization and configuration: + +```rust +let wrapper = Wrapper::new(60).break_words(false); +``` + +It also add a new `NoHyphenation` word splitter that will never split +words, not even at existing hyphens. + +* Fixed [#28][issue-28]: Support not squeezing whitespace. + +### Version 0.5.0 — May 15th, 2017 + +Version 0.5.0 has *breaking API changes*. However, this only affects +code using the hyphenation feature. The feature is now optional, so +you will first need to enable the `hyphenation` feature as described +above. Afterwards, please change your code from +```rust +wrapper.corpus = Some(&corpus); +``` +to +```rust +wrapper.splitter = Box::new(corpus); +``` + +Other changes include optimizations, so version 0.5.0 is roughly +10-15% faster than version 0.4.0. + +* Fixed [#19][issue-19]: Add support for finding terminal size. +* Fixed [#25][issue-25]: Handle words longer than `self.width`. +* Fixed [#26][issue-26]: Support custom indentation. +* Fixed [#36][issue-36]: Support building without `hyphenation`. +* Fixed [#39][issue-39]: Respect non-breaking spaces. + +### Version 0.4.0 — January 24th, 2017 + +Documented complexities and tested these via `cargo bench`. + +* Fixed [#13][issue-13]: Immediatedly add word if it fits. +* Fixed [#14][issue-14]: Avoid splitting on initial hyphens. + +### Version 0.3.0 — January 7th, 2017 + +Added support for automatic hyphenation. + +### Version 0.2.0 — December 28th, 2016 + +Introduced `Wrapper` struct. Added support for wrapping on hyphens. + +### Version 0.1.0 — December 17th, 2016 + +First public release with support for wrapping strings on whitespace. + +## License + +Textwrap can be distributed according to the [MIT license][mit]. +Contributions will be accepted under the same license. + +[crates-io]: https://crates.io/crates/textwrap +[travis-ci]: https://travis-ci.org/mgeisler/textwrap +[appveyor]: https://ci.appveyor.com/project/mgeisler/textwrap +[codecov]: https://codecov.io/gh/mgeisler/textwrap +[py-textwrap]: https://docs.python.org/library/textwrap +[patterns]: https://github.com/tapeinosyne/hyphenation/tree/master/patterns-tex +[api-docs]: https://docs.rs/textwrap/ +[issue-13]: https://github.com/mgeisler/textwrap/issues/13 +[issue-14]: https://github.com/mgeisler/textwrap/issues/14 +[issue-19]: https://github.com/mgeisler/textwrap/issues/19 +[issue-25]: https://github.com/mgeisler/textwrap/issues/25 +[issue-26]: https://github.com/mgeisler/textwrap/issues/26 +[issue-28]: https://github.com/mgeisler/textwrap/issues/28 +[issue-36]: https://github.com/mgeisler/textwrap/issues/36 +[issue-39]: https://github.com/mgeisler/textwrap/issues/39 +[issue-58]: https://github.com/mgeisler/textwrap/issues/58 +[issue-59]: https://github.com/mgeisler/textwrap/issues/59 +[issue-61]: https://github.com/mgeisler/textwrap/issues/61 +[issue-81]: https://github.com/mgeisler/textwrap/issues/81 +[issue-99]: https://github.com/mgeisler/textwrap/issues/99 +[issue-101]: https://github.com/mgeisler/textwrap/issues/101 +[issue-107]: https://github.com/mgeisler/textwrap/issues/107 +[issue-122]: https://github.com/mgeisler/textwrap/issues/122 +[issue-129]: https://github.com/mgeisler/textwrap/issues/129 +[issue-141]: https://github.com/mgeisler/textwrap/issues/141 +[issue-151]: https://github.com/mgeisler/textwrap/issues/151 +[mit]: LICENSE diff --git a/vendor/textwrap/benches/linear.rs b/vendor/textwrap/benches/linear.rs new file mode 100644 index 0000000000000..104398a1b628f --- /dev/null +++ b/vendor/textwrap/benches/linear.rs @@ -0,0 +1,122 @@ +#![feature(test)] + +// The benchmarks here verify that the complexity grows as O(*n*) +// where *n* is the number of characters in the text to be wrapped. + +#[cfg(feature = "hyphenation")] +extern crate hyphenation; +extern crate lipsum; +extern crate rand; +extern crate rand_xorshift; +extern crate test; +extern crate textwrap; + +#[cfg(feature = "hyphenation")] +use hyphenation::{Language, Load, Standard}; +use lipsum::MarkovChain; +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; +use test::Bencher; +#[cfg(feature = "hyphenation")] +use textwrap::Wrapper; + +const LINE_LENGTH: usize = 60; + +/// Generate a lorem ipsum text with the given number of characters. +fn lorem_ipsum(length: usize) -> String { + // The average word length in the lorem ipsum text is somewhere + // between 6 and 7. So we conservatively divide by 5 to have a + // long enough text that we can truncate below. + let rng = XorShiftRng::seed_from_u64(0); + let mut chain = MarkovChain::new_with_rng(rng); + chain.learn(lipsum::LOREM_IPSUM); + chain.learn(lipsum::LIBER_PRIMUS); + + let mut text = chain.generate_from(length / 5, ("Lorem", "ipsum")); + text.truncate(length); + text +} + +#[bench] +fn fill_100(b: &mut Bencher) { + let text = &lorem_ipsum(100); + b.iter(|| textwrap::fill(text, LINE_LENGTH)) +} + +#[bench] +fn fill_200(b: &mut Bencher) { + let text = &lorem_ipsum(200); + b.iter(|| textwrap::fill(text, LINE_LENGTH)) +} + +#[bench] +fn fill_400(b: &mut Bencher) { + let text = &lorem_ipsum(400); + b.iter(|| textwrap::fill(text, LINE_LENGTH)) +} + +#[bench] +fn fill_800(b: &mut Bencher) { + let text = &lorem_ipsum(800); + b.iter(|| textwrap::fill(text, LINE_LENGTH)) +} + +#[bench] +fn wrap_100(b: &mut Bencher) { + let text = &lorem_ipsum(100); + b.iter(|| textwrap::wrap(text, LINE_LENGTH)) +} + +#[bench] +fn wrap_200(b: &mut Bencher) { + let text = &lorem_ipsum(200); + b.iter(|| textwrap::wrap(text, LINE_LENGTH)) +} + +#[bench] +fn wrap_400(b: &mut Bencher) { + let text = &lorem_ipsum(400); + b.iter(|| textwrap::wrap(text, LINE_LENGTH)) +} + +#[bench] +fn wrap_800(b: &mut Bencher) { + let text = &lorem_ipsum(800); + b.iter(|| textwrap::wrap(text, LINE_LENGTH)) +} + +#[bench] +#[cfg(feature = "hyphenation")] +fn hyphenation_fill_100(b: &mut Bencher) { + let text = &lorem_ipsum(100); + let dictionary = Standard::from_embedded(Language::Latin).unwrap(); + let wrapper = Wrapper::with_splitter(LINE_LENGTH, dictionary); + b.iter(|| wrapper.fill(text)) +} + +#[bench] +#[cfg(feature = "hyphenation")] +fn hyphenation_fill_200(b: &mut Bencher) { + let text = &lorem_ipsum(200); + let dictionary = Standard::from_embedded(Language::Latin).unwrap(); + let wrapper = Wrapper::with_splitter(LINE_LENGTH, dictionary); + b.iter(|| wrapper.fill(text)) +} + +#[bench] +#[cfg(feature = "hyphenation")] +fn hyphenation_fill_400(b: &mut Bencher) { + let text = &lorem_ipsum(400); + let dictionary = Standard::from_embedded(Language::Latin).unwrap(); + let wrapper = Wrapper::with_splitter(LINE_LENGTH, dictionary); + b.iter(|| wrapper.fill(text)) +} + +#[bench] +#[cfg(feature = "hyphenation")] +fn hyphenation_fill_800(b: &mut Bencher) { + let text = &lorem_ipsum(800); + let dictionary = Standard::from_embedded(Language::Latin).unwrap(); + let wrapper = Wrapper::with_splitter(LINE_LENGTH, dictionary); + b.iter(|| wrapper.fill(text)) +} diff --git a/vendor/textwrap/examples/layout.rs b/vendor/textwrap/examples/layout.rs new file mode 100644 index 0000000000000..d36cb3ab93a38 --- /dev/null +++ b/vendor/textwrap/examples/layout.rs @@ -0,0 +1,38 @@ +#[cfg(feature = "hyphenation")] +extern crate hyphenation; +extern crate textwrap; + +#[cfg(feature = "hyphenation")] +use hyphenation::{Language, Load}; +use textwrap::Wrapper; + +#[cfg(not(feature = "hyphenation"))] +fn new_wrapper<'a>() -> Wrapper<'a, textwrap::HyphenSplitter> { + Wrapper::new(0) +} + +#[cfg(feature = "hyphenation")] +fn new_wrapper<'a>() -> Wrapper<'a, hyphenation::Standard> { + let dictionary = hyphenation::Standard::from_embedded(Language::EnglishUS).unwrap(); + Wrapper::with_splitter(0, dictionary) +} + +fn main() { + let example = "Memory safety without garbage collection. \ + Concurrency without data races. \ + Zero-cost abstractions."; + let mut prev_lines = vec![]; + let mut wrapper = new_wrapper(); + for width in 15..60 { + wrapper.width = width; + let lines = wrapper.wrap(example); + if lines != prev_lines { + let title = format!(" Width: {} ", width); + println!(".{:-^1$}.", title, width + 2); + for line in &lines { + println!("| {:1$} |", line, width); + } + prev_lines = lines; + } + } +} diff --git a/vendor/textwrap/examples/termwidth.rs b/vendor/textwrap/examples/termwidth.rs new file mode 100644 index 0000000000000..75db3aa7e4060 --- /dev/null +++ b/vendor/textwrap/examples/termwidth.rs @@ -0,0 +1,41 @@ +#[cfg(feature = "hyphenation")] +extern crate hyphenation; +extern crate textwrap; + +#[cfg(feature = "hyphenation")] +use hyphenation::{Language, Load, Standard}; +#[cfg(feature = "term_size")] +use textwrap::Wrapper; + +#[cfg(not(feature = "term_size"))] +fn main() { + println!("Please enable the term_size feature to run this example."); +} + +#[cfg(feature = "term_size")] +fn main() { + #[cfg(not(feature = "hyphenation"))] + fn new_wrapper<'a>() -> (&'static str, Wrapper<'a, textwrap::HyphenSplitter>) { + ("without hyphenation", Wrapper::with_termwidth()) + } + + #[cfg(feature = "hyphenation")] + fn new_wrapper<'a>() -> (&'static str, Wrapper<'a, Standard>) { + let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); + ( + "with hyphenation", + Wrapper::with_splitter(textwrap::termwidth(), dictionary), + ) + } + + let example = "Memory safety without garbage collection. \ + Concurrency without data races. \ + Zero-cost abstractions."; + // Create a new Wrapper -- automatically set the width to the + // current terminal width. + let (msg, wrapper) = new_wrapper(); + println!("Formatted {} in {} columns:", msg, wrapper.width); + println!("----"); + println!("{}", wrapper.fill(example)); + println!("----"); +} diff --git a/vendor/textwrap/src/indentation.rs b/vendor/textwrap/src/indentation.rs new file mode 100644 index 0000000000000..276ba10553450 --- /dev/null +++ b/vendor/textwrap/src/indentation.rs @@ -0,0 +1,294 @@ +//! Functions related to adding and removing indentation from lines of +//! text. +//! +//! The functions here can be used to uniformly indent or dedent +//! (unindent) word wrapped lines of text. + +/// Add prefix to each non-empty line. +/// +/// ``` +/// use textwrap::indent; +/// +/// assert_eq!(indent(" +/// Foo +/// Bar +/// ", " "), " +/// Foo +/// Bar +/// "); +/// ``` +/// +/// Empty lines (lines consisting only of whitespace) are not indented +/// and the whitespace is replaced by a single newline (`\n`): +/// +/// ``` +/// use textwrap::indent; +/// +/// assert_eq!(indent(" +/// Foo +/// +/// Bar +/// \t +/// Baz +/// ", "->"), " +/// ->Foo +/// +/// ->Bar +/// +/// ->Baz +/// "); +/// ``` +/// +/// Leading and trailing whitespace on non-empty lines is kept +/// unchanged: +/// +/// ``` +/// use textwrap::indent; +/// +/// assert_eq!(indent(" \t Foo ", "->"), "-> \t Foo \n"); +/// ``` +pub fn indent(s: &str, prefix: &str) -> String { + let mut result = String::new(); + for line in s.lines() { + if line.chars().any(|c| !c.is_whitespace()) { + result.push_str(prefix); + result.push_str(line); + } + result.push('\n'); + } + result +} + +/// Removes common leading whitespace from each line. +/// +/// This function will look at each non-empty line and determine the +/// maximum amount of whitespace that can be removed from all lines: +/// +/// ``` +/// use textwrap::dedent; +/// +/// assert_eq!(dedent(" +/// 1st line +/// 2nd line +/// 3rd line +/// "), " +/// 1st line +/// 2nd line +/// 3rd line +/// "); +/// ``` +pub fn dedent(s: &str) -> String { + let mut prefix = ""; + let mut lines = s.lines(); + + // We first search for a non-empty line to find a prefix. + for line in &mut lines { + let mut whitespace_idx = line.len(); + for (idx, ch) in line.char_indices() { + if !ch.is_whitespace() { + whitespace_idx = idx; + break; + } + } + + // Check if the line had anything but whitespace + if whitespace_idx < line.len() { + prefix = &line[..whitespace_idx]; + break; + } + } + + // We then continue looking through the remaining lines to + // possibly shorten the prefix. + for line in &mut lines { + let mut whitespace_idx = line.len(); + for ((idx, a), b) in line.char_indices().zip(prefix.chars()) { + if a != b { + whitespace_idx = idx; + break; + } + } + + // Check if the line had anything but whitespace and if we + // have found a shorter prefix + if whitespace_idx < line.len() && whitespace_idx < prefix.len() { + prefix = &line[..whitespace_idx]; + } + } + + // We now go over the lines a second time to build the result. + let mut result = String::new(); + for line in s.lines() { + if line.starts_with(&prefix) && line.chars().any(|c| !c.is_whitespace()) { + let (_, tail) = line.split_at(prefix.len()); + result.push_str(tail); + } + result.push('\n'); + } + + if result.ends_with('\n') && !s.ends_with('\n') { + let new_len = result.len() - 1; + result.truncate(new_len); + } + + result +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Add newlines. Ensures that the final line in the vector also + /// has a newline. + fn add_nl(lines: &[&str]) -> String { + lines.join("\n") + "\n" + } + + #[test] + fn indent_empty() { + assert_eq!(indent("\n", " "), "\n"); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn indent_nonempty() { + let x = vec![" foo", + "bar", + " baz"]; + let y = vec!["// foo", + "//bar", + "// baz"]; + assert_eq!(indent(&add_nl(&x), "//"), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn indent_empty_line() { + let x = vec![" foo", + "bar", + "", + " baz"]; + let y = vec!["// foo", + "//bar", + "", + "// baz"]; + assert_eq!(indent(&add_nl(&x), "//"), add_nl(&y)); + } + + #[test] + fn dedent_empty() { + assert_eq!(dedent(""), ""); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_multi_line() { + let x = vec![" foo", + " bar", + " baz"]; + let y = vec![" foo", + "bar", + " baz"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_empty_line() { + let x = vec![" foo", + " bar", + " ", + " baz"]; + let y = vec![" foo", + "bar", + "", + " baz"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_blank_line() { + let x = vec![" foo", + "", + " bar", + " foo", + " bar", + " baz"]; + let y = vec!["foo", + "", + " bar", + " foo", + " bar", + " baz"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_whitespace_line() { + let x = vec![" foo", + " ", + " bar", + " foo", + " bar", + " baz"]; + let y = vec!["foo", + "", + " bar", + " foo", + " bar", + " baz"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_mixed_whitespace() { + let x = vec!["\tfoo", + " bar"]; + let y = vec!["\tfoo", + " bar"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_tabbed_whitespace() { + let x = vec!["\t\tfoo", + "\t\t\tbar"]; + let y = vec!["foo", + "\tbar"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_mixed_tabbed_whitespace() { + let x = vec!["\t \tfoo", + "\t \t\tbar"]; + let y = vec!["foo", + "\tbar"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_mixed_tabbed_whitespace2() { + let x = vec!["\t \tfoo", + "\t \tbar"]; + let y = vec!["\tfoo", + " \tbar"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_preserve_no_terminating_newline() { + let x = vec![" foo", + " bar"].join("\n"); + let y = vec!["foo", + " bar"].join("\n"); + assert_eq!(dedent(&x), y); + } +} diff --git a/vendor/textwrap/src/lib.rs b/vendor/textwrap/src/lib.rs new file mode 100644 index 0000000000000..2f82325fbc2ef --- /dev/null +++ b/vendor/textwrap/src/lib.rs @@ -0,0 +1,987 @@ +//! `textwrap` provides functions for word wrapping and filling text. +//! +//! Wrapping text can be very useful in commandline programs where you +//! want to format dynamic output nicely so it looks good in a +//! terminal. A quick example: +//! +//! ```no_run +//! extern crate textwrap; +//! use textwrap::fill; +//! +//! fn main() { +//! let text = "textwrap: a small library for wrapping text."; +//! println!("{}", fill(text, 18)); +//! } +//! ``` +//! +//! This will display the following output: +//! +//! ```text +//! textwrap: a small +//! library for +//! wrapping text. +//! ``` +//! +//! # Displayed Width vs Byte Size +//! +//! To word wrap text, one must know the width of each word so one can +//! know when to break lines. This library measures the width of text +//! using the [displayed width][unicode-width], not the size in bytes. +//! +//! This is important for non-ASCII text. ASCII characters such as `a` +//! and `!` are simple and take up one column each. This means that +//! the displayed width is equal to the string length in bytes. +//! However, non-ASCII characters and symbols take up more than one +//! byte when UTF-8 encoded: `é` is `0xc3 0xa9` (two bytes) and `âš™` is +//! `0xe2 0x9a 0x99` (three bytes) in UTF-8, respectively. +//! +//! This is why we take care to use the displayed width instead of the +//! byte count when computing line lengths. All functions in this +//! library handle Unicode characters like this. +//! +//! [unicode-width]: https://docs.rs/unicode-width/ + +#![doc(html_root_url = "https://docs.rs/textwrap/0.11.0")] +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] + +#[cfg(feature = "hyphenation")] +extern crate hyphenation; +#[cfg(feature = "term_size")] +extern crate term_size; +extern crate unicode_width; + +use std::borrow::Cow; +use std::str::CharIndices; + +use unicode_width::UnicodeWidthChar; +use unicode_width::UnicodeWidthStr; + +/// A non-breaking space. +const NBSP: char = '\u{a0}'; + +mod indentation; +pub use indentation::dedent; +pub use indentation::indent; + +mod splitting; +pub use splitting::{HyphenSplitter, NoHyphenation, WordSplitter}; + +/// A Wrapper holds settings for wrapping and filling text. Use it +/// when the convenience [`wrap_iter`], [`wrap`] and [`fill`] functions +/// are not flexible enough. +/// +/// [`wrap_iter`]: fn.wrap_iter.html +/// [`wrap`]: fn.wrap.html +/// [`fill`]: fn.fill.html +/// +/// The algorithm used by the `WrapIter` iterator (returned from the +/// `wrap_iter` method) works by doing successive partial scans over +/// words in the input string (where each single scan yields a single +/// line) so that the overall time and memory complexity is O(*n*) where +/// *n* is the length of the input string. +#[derive(Clone, Debug)] +pub struct Wrapper<'a, S: WordSplitter> { + /// The width in columns at which the text will be wrapped. + pub width: usize, + /// Indentation used for the first line of output. + pub initial_indent: &'a str, + /// Indentation used for subsequent lines of output. + pub subsequent_indent: &'a str, + /// Allow long words to be broken if they cannot fit on a line. + /// When set to `false`, some lines may be longer than + /// `self.width`. + pub break_words: bool, + /// The method for splitting words. If the `hyphenation` feature + /// is enabled, you can use a `hyphenation::Standard` dictionary + /// here to get language-aware hyphenation. + pub splitter: S, +} + +impl<'a> Wrapper<'a, HyphenSplitter> { + /// Create a new Wrapper for wrapping at the specified width. By + /// default, we allow words longer than `width` to be broken. A + /// [`HyphenSplitter`] will be used by default for splitting + /// words. See the [`WordSplitter`] trait for other options. + /// + /// [`HyphenSplitter`]: struct.HyphenSplitter.html + /// [`WordSplitter`]: trait.WordSplitter.html + pub fn new(width: usize) -> Wrapper<'a, HyphenSplitter> { + Wrapper::with_splitter(width, HyphenSplitter) + } + + /// Create a new Wrapper for wrapping text at the current terminal + /// width. If the terminal width cannot be determined (typically + /// because the standard input and output is not connected to a + /// terminal), a width of 80 characters will be used. Other + /// settings use the same defaults as `Wrapper::new`. + /// + /// Equivalent to: + /// + /// ```no_run + /// # #![allow(unused_variables)] + /// use textwrap::{Wrapper, termwidth}; + /// + /// let wrapper = Wrapper::new(termwidth()); + /// ``` + #[cfg(feature = "term_size")] + pub fn with_termwidth() -> Wrapper<'a, HyphenSplitter> { + Wrapper::new(termwidth()) + } +} + +impl<'a, S: WordSplitter> Wrapper<'a, S> { + /// Use the given [`WordSplitter`] to create a new Wrapper for + /// wrapping at the specified width. By default, we allow words + /// longer than `width` to be broken. + /// + /// [`WordSplitter`]: trait.WordSplitter.html + pub fn with_splitter(width: usize, splitter: S) -> Wrapper<'a, S> { + Wrapper { + width: width, + initial_indent: "", + subsequent_indent: "", + break_words: true, + splitter: splitter, + } + } + + /// Change [`self.initial_indent`]. The initial indentation is + /// used on the very first line of output. + /// + /// # Examples + /// + /// Classic paragraph indentation can be achieved by specifying an + /// initial indentation and wrapping each paragraph by itself: + /// + /// ```no_run + /// # #![allow(unused_variables)] + /// use textwrap::Wrapper; + /// + /// let wrapper = Wrapper::new(15).initial_indent(" "); + /// ``` + /// + /// [`self.initial_indent`]: #structfield.initial_indent + pub fn initial_indent(self, indent: &'a str) -> Wrapper<'a, S> { + Wrapper { + initial_indent: indent, + ..self + } + } + + /// Change [`self.subsequent_indent`]. The subsequent indentation + /// is used on lines following the first line of output. + /// + /// # Examples + /// + /// Combining initial and subsequent indentation lets you format a + /// single paragraph as a bullet list: + /// + /// ```no_run + /// # #![allow(unused_variables)] + /// use textwrap::Wrapper; + /// + /// let wrapper = Wrapper::new(15) + /// .initial_indent("* ") + /// .subsequent_indent(" "); + /// ``` + /// + /// [`self.subsequent_indent`]: #structfield.subsequent_indent + pub fn subsequent_indent(self, indent: &'a str) -> Wrapper<'a, S> { + Wrapper { + subsequent_indent: indent, + ..self + } + } + + /// Change [`self.break_words`]. This controls if words longer + /// than `self.width` can be broken, or if they will be left + /// sticking out into the right margin. + /// + /// [`self.break_words`]: #structfield.break_words + pub fn break_words(self, setting: bool) -> Wrapper<'a, S> { + Wrapper { + break_words: setting, + ..self + } + } + + /// Fill a line of text at `self.width` characters. Strings are + /// wrapped based on their displayed width, not their size in + /// bytes. + /// + /// The result is a string with newlines between each line. Use + /// the `wrap` method if you need access to the individual lines. + /// + /// # Complexities + /// + /// This method simply joins the lines produced by `wrap_iter`. As + /// such, it inherits the O(*n*) time and memory complexity where + /// *n* is the input string length. + /// + /// # Examples + /// + /// ``` + /// use textwrap::Wrapper; + /// + /// let wrapper = Wrapper::new(15); + /// assert_eq!(wrapper.fill("Memory safety without garbage collection."), + /// "Memory safety\nwithout garbage\ncollection."); + /// ``` + pub fn fill(&self, s: &str) -> String { + // This will avoid reallocation in simple cases (no + // indentation, no hyphenation). + let mut result = String::with_capacity(s.len()); + + for (i, line) in self.wrap_iter(s).enumerate() { + if i > 0 { + result.push('\n'); + } + result.push_str(&line); + } + + result + } + + /// Wrap a line of text at `self.width` characters. Strings are + /// wrapped based on their displayed width, not their size in + /// bytes. + /// + /// # Complexities + /// + /// This method simply collects the lines produced by `wrap_iter`. + /// As such, it inherits the O(*n*) overall time and memory + /// complexity where *n* is the input string length. + /// + /// # Examples + /// + /// ``` + /// use textwrap::Wrapper; + /// + /// let wrap15 = Wrapper::new(15); + /// assert_eq!(wrap15.wrap("Concurrency without data races."), + /// vec!["Concurrency", + /// "without data", + /// "races."]); + /// + /// let wrap20 = Wrapper::new(20); + /// assert_eq!(wrap20.wrap("Concurrency without data races."), + /// vec!["Concurrency without", + /// "data races."]); + /// ``` + /// + /// Notice that newlines in the input are preserved. This means + /// that they force a line break, regardless of how long the + /// current line is: + /// + /// ``` + /// use textwrap::Wrapper; + /// + /// let wrapper = Wrapper::new(40); + /// assert_eq!(wrapper.wrap("First line.\nSecond line."), + /// vec!["First line.", "Second line."]); + /// ``` + /// + pub fn wrap(&self, s: &'a str) -> Vec> { + self.wrap_iter(s).collect::>() + } + + /// Lazily wrap a line of text at `self.width` characters. Strings + /// are wrapped based on their displayed width, not their size in + /// bytes. + /// + /// The [`WordSplitter`] stored in [`self.splitter`] is used + /// whenever when a word is too large to fit on the current line. + /// By changing the field, different hyphenation strategies can be + /// implemented. + /// + /// # Complexities + /// + /// This method returns a [`WrapIter`] iterator which borrows this + /// `Wrapper`. The algorithm used has a linear complexity, so + /// getting the next line from the iterator will take O(*w*) time, + /// where *w* is the wrapping width. Fully processing the iterator + /// will take O(*n*) time for an input string of length *n*. + /// + /// When no indentation is used, each line returned is a slice of + /// the input string and the memory overhead is thus constant. + /// Otherwise new memory is allocated for each line returned. + /// + /// # Examples + /// + /// ``` + /// use std::borrow::Cow; + /// use textwrap::Wrapper; + /// + /// let wrap20 = Wrapper::new(20); + /// let mut wrap20_iter = wrap20.wrap_iter("Zero-cost abstractions."); + /// assert_eq!(wrap20_iter.next(), Some(Cow::from("Zero-cost"))); + /// assert_eq!(wrap20_iter.next(), Some(Cow::from("abstractions."))); + /// assert_eq!(wrap20_iter.next(), None); + /// + /// let wrap25 = Wrapper::new(25); + /// let mut wrap25_iter = wrap25.wrap_iter("Zero-cost abstractions."); + /// assert_eq!(wrap25_iter.next(), Some(Cow::from("Zero-cost abstractions."))); + /// assert_eq!(wrap25_iter.next(), None); + /// ``` + /// + /// [`self.splitter`]: #structfield.splitter + /// [`WordSplitter`]: trait.WordSplitter.html + /// [`WrapIter`]: struct.WrapIter.html + pub fn wrap_iter<'w>(&'w self, s: &'a str) -> WrapIter<'w, 'a, S> { + WrapIter { + wrapper: self, + inner: WrapIterImpl::new(self, s), + } + } + + /// Lazily wrap a line of text at `self.width` characters. Strings + /// are wrapped based on their displayed width, not their size in + /// bytes. + /// + /// The [`WordSplitter`] stored in [`self.splitter`] is used + /// whenever when a word is too large to fit on the current line. + /// By changing the field, different hyphenation strategies can be + /// implemented. + /// + /// # Complexities + /// + /// This method consumes the `Wrapper` and returns a + /// [`IntoWrapIter`] iterator. Fully processing the iterator has + /// the same O(*n*) time complexity as [`wrap_iter`], where *n* is + /// the length of the input string. + /// + /// # Examples + /// + /// ``` + /// use std::borrow::Cow; + /// use textwrap::Wrapper; + /// + /// let wrap20 = Wrapper::new(20); + /// let mut wrap20_iter = wrap20.into_wrap_iter("Zero-cost abstractions."); + /// assert_eq!(wrap20_iter.next(), Some(Cow::from("Zero-cost"))); + /// assert_eq!(wrap20_iter.next(), Some(Cow::from("abstractions."))); + /// assert_eq!(wrap20_iter.next(), None); + /// ``` + /// + /// [`self.splitter`]: #structfield.splitter + /// [`WordSplitter`]: trait.WordSplitter.html + /// [`IntoWrapIter`]: struct.IntoWrapIter.html + /// [`wrap_iter`]: #method.wrap_iter + pub fn into_wrap_iter(self, s: &'a str) -> IntoWrapIter<'a, S> { + let inner = WrapIterImpl::new(&self, s); + + IntoWrapIter { + wrapper: self, + inner: inner, + } + } +} + +/// An iterator over the lines of the input string which owns a +/// `Wrapper`. An instance of `IntoWrapIter` is typically obtained +/// through either [`wrap_iter`] or [`Wrapper::into_wrap_iter`]. +/// +/// Each call of `.next()` method yields a line wrapped in `Some` if the +/// input hasn't been fully processed yet. Otherwise it returns `None`. +/// +/// [`wrap_iter`]: fn.wrap_iter.html +/// [`Wrapper::into_wrap_iter`]: struct.Wrapper.html#method.into_wrap_iter +#[derive(Debug)] +pub struct IntoWrapIter<'a, S: WordSplitter> { + wrapper: Wrapper<'a, S>, + inner: WrapIterImpl<'a>, +} + +impl<'a, S: WordSplitter> Iterator for IntoWrapIter<'a, S> { + type Item = Cow<'a, str>; + + fn next(&mut self) -> Option> { + self.inner.next(&self.wrapper) + } +} + +/// An iterator over the lines of the input string which borrows a +/// `Wrapper`. An instance of `WrapIter` is typically obtained +/// through the [`Wrapper::wrap_iter`] method. +/// +/// Each call of `.next()` method yields a line wrapped in `Some` if the +/// input hasn't been fully processed yet. Otherwise it returns `None`. +/// +/// [`Wrapper::wrap_iter`]: struct.Wrapper.html#method.wrap_iter +#[derive(Debug)] +pub struct WrapIter<'w, 'a: 'w, S: WordSplitter + 'w> { + wrapper: &'w Wrapper<'a, S>, + inner: WrapIterImpl<'a>, +} + +impl<'w, 'a: 'w, S: WordSplitter> Iterator for WrapIter<'w, 'a, S> { + type Item = Cow<'a, str>; + + fn next(&mut self) -> Option> { + self.inner.next(self.wrapper) + } +} + +/// Like `char::is_whitespace`, but non-breaking spaces don't count. +#[inline] +fn is_whitespace(ch: char) -> bool { + ch.is_whitespace() && ch != NBSP +} + +/// Common implementation details for `WrapIter` and `IntoWrapIter`. +#[derive(Debug)] +struct WrapIterImpl<'a> { + // String to wrap. + source: &'a str, + // CharIndices iterator over self.source. + char_indices: CharIndices<'a>, + // Byte index where the current line starts. + start: usize, + // Byte index of the last place where the string can be split. + split: usize, + // Size in bytes of the character at self.source[self.split]. + split_len: usize, + // Width of self.source[self.start..idx]. + line_width: usize, + // Width of self.source[self.start..self.split]. + line_width_at_split: usize, + // Tracking runs of whitespace characters. + in_whitespace: bool, + // Has iterator finished producing elements? + finished: bool, +} + +impl<'a> WrapIterImpl<'a> { + fn new(wrapper: &Wrapper<'a, S>, s: &'a str) -> WrapIterImpl<'a> { + WrapIterImpl { + source: s, + char_indices: s.char_indices(), + start: 0, + split: 0, + split_len: 0, + line_width: wrapper.initial_indent.width(), + line_width_at_split: wrapper.initial_indent.width(), + in_whitespace: false, + finished: false, + } + } + + fn create_result_line(&self, wrapper: &Wrapper<'a, S>) -> Cow<'a, str> { + if self.start == 0 { + Cow::from(wrapper.initial_indent) + } else { + Cow::from(wrapper.subsequent_indent) + } + } + + fn next(&mut self, wrapper: &Wrapper<'a, S>) -> Option> { + if self.finished { + return None; + } + + while let Some((idx, ch)) = self.char_indices.next() { + let char_width = ch.width().unwrap_or(0); + let char_len = ch.len_utf8(); + + if ch == '\n' { + self.split = idx; + self.split_len = char_len; + self.line_width_at_split = self.line_width; + self.in_whitespace = false; + + // If this is not the final line, return the current line. Otherwise, + // we will return the line with its line break after exiting the loop + if self.split + self.split_len < self.source.len() { + let mut line = self.create_result_line(wrapper); + line += &self.source[self.start..self.split]; + + self.start = self.split + self.split_len; + self.line_width = wrapper.subsequent_indent.width(); + + return Some(line); + } + } else if is_whitespace(ch) { + // Extend the previous split or create a new one. + if self.in_whitespace { + self.split_len += char_len; + } else { + self.split = idx; + self.split_len = char_len; + } + self.line_width_at_split = self.line_width + char_width; + self.in_whitespace = true; + } else if self.line_width + char_width > wrapper.width { + // There is no room for this character on the current + // line. Try to split the final word. + self.in_whitespace = false; + let remaining_text = &self.source[self.split + self.split_len..]; + let final_word = match remaining_text.find(is_whitespace) { + Some(i) => &remaining_text[..i], + None => remaining_text, + }; + + let mut hyphen = ""; + let splits = wrapper.splitter.split(final_word); + for &(head, hyp, _) in splits.iter().rev() { + if self.line_width_at_split + head.width() + hyp.width() <= wrapper.width { + // We can fit head into the current line. + // Advance the split point by the width of the + // whitespace and the head length. + self.split += self.split_len + head.len(); + self.split_len = 0; + hyphen = hyp; + break; + } + } + + if self.start >= self.split { + // The word is too big to fit on a single line, so we + // need to split it at the current index. + if wrapper.break_words { + // Break work at current index. + self.split = idx; + self.split_len = 0; + self.line_width_at_split = self.line_width; + } else { + // Add smallest split. + self.split = self.start + splits[0].0.len(); + self.split_len = 0; + self.line_width_at_split = self.line_width; + } + } + + if self.start < self.split { + let mut line = self.create_result_line(wrapper); + line += &self.source[self.start..self.split]; + line += hyphen; + + self.start = self.split + self.split_len; + self.line_width += wrapper.subsequent_indent.width(); + self.line_width -= self.line_width_at_split; + self.line_width += char_width; + + return Some(line); + } + } else { + self.in_whitespace = false; + } + self.line_width += char_width; + } + + self.finished = true; + + // Add final line. + if self.start < self.source.len() { + let mut line = self.create_result_line(wrapper); + line += &self.source[self.start..]; + return Some(line); + } + + None + } +} + +/// Return the current terminal width. If the terminal width cannot be +/// determined (typically because the standard output is not connected +/// to a terminal), a default width of 80 characters will be used. +/// +/// # Examples +/// +/// Create a `Wrapper` for the current terminal with a two column +/// margin: +/// +/// ```no_run +/// # #![allow(unused_variables)] +/// use textwrap::{Wrapper, NoHyphenation, termwidth}; +/// +/// let width = termwidth() - 4; // Two columns on each side. +/// let wrapper = Wrapper::with_splitter(width, NoHyphenation) +/// .initial_indent(" ") +/// .subsequent_indent(" "); +/// ``` +#[cfg(feature = "term_size")] +pub fn termwidth() -> usize { + term_size::dimensions_stdout().map_or(80, |(w, _)| w) +} + +/// Fill a line of text at `width` characters. Strings are wrapped +/// based on their displayed width, not their size in bytes. +/// +/// The result is a string with newlines between each line. Use +/// [`wrap`] if you need access to the individual lines or +/// [`wrap_iter`] for its iterator counterpart. +/// +/// ``` +/// use textwrap::fill; +/// +/// assert_eq!(fill("Memory safety without garbage collection.", 15), +/// "Memory safety\nwithout garbage\ncollection."); +/// ``` +/// +/// This function creates a Wrapper on the fly with default settings. +/// If you need to set a language corpus for automatic hyphenation, or +/// need to fill many strings, then it is suggested to create a Wrapper +/// and call its [`fill` method]. +/// +/// [`wrap`]: fn.wrap.html +/// [`wrap_iter`]: fn.wrap_iter.html +/// [`fill` method]: struct.Wrapper.html#method.fill +pub fn fill(s: &str, width: usize) -> String { + Wrapper::new(width).fill(s) +} + +/// Wrap a line of text at `width` characters. Strings are wrapped +/// based on their displayed width, not their size in bytes. +/// +/// This function creates a Wrapper on the fly with default settings. +/// If you need to set a language corpus for automatic hyphenation, or +/// need to wrap many strings, then it is suggested to create a Wrapper +/// and call its [`wrap` method]. +/// +/// The result is a vector of strings. Use [`wrap_iter`] if you need an +/// iterator version. +/// +/// # Examples +/// +/// ``` +/// use textwrap::wrap; +/// +/// assert_eq!(wrap("Concurrency without data races.", 15), +/// vec!["Concurrency", +/// "without data", +/// "races."]); +/// +/// assert_eq!(wrap("Concurrency without data races.", 20), +/// vec!["Concurrency without", +/// "data races."]); +/// ``` +/// +/// [`wrap_iter`]: fn.wrap_iter.html +/// [`wrap` method]: struct.Wrapper.html#method.wrap +pub fn wrap(s: &str, width: usize) -> Vec> { + Wrapper::new(width).wrap(s) +} + +/// Lazily wrap a line of text at `width` characters. Strings are +/// wrapped based on their displayed width, not their size in bytes. +/// +/// This function creates a Wrapper on the fly with default settings. +/// It then calls the [`into_wrap_iter`] method. Hence, the return +/// value is an [`IntoWrapIter`], not a [`WrapIter`] as the function +/// name would otherwise suggest. +/// +/// If you need to set a language corpus for automatic hyphenation, or +/// need to wrap many strings, then it is suggested to create a Wrapper +/// and call its [`wrap_iter`] or [`into_wrap_iter`] methods. +/// +/// # Examples +/// +/// ``` +/// use std::borrow::Cow; +/// use textwrap::wrap_iter; +/// +/// let mut wrap20_iter = wrap_iter("Zero-cost abstractions.", 20); +/// assert_eq!(wrap20_iter.next(), Some(Cow::from("Zero-cost"))); +/// assert_eq!(wrap20_iter.next(), Some(Cow::from("abstractions."))); +/// assert_eq!(wrap20_iter.next(), None); +/// +/// let mut wrap25_iter = wrap_iter("Zero-cost abstractions.", 25); +/// assert_eq!(wrap25_iter.next(), Some(Cow::from("Zero-cost abstractions."))); +/// assert_eq!(wrap25_iter.next(), None); +/// ``` +/// +/// [`wrap_iter`]: struct.Wrapper.html#method.wrap_iter +/// [`into_wrap_iter`]: struct.Wrapper.html#method.into_wrap_iter +/// [`IntoWrapIter`]: struct.IntoWrapIter.html +/// [`WrapIter`]: struct.WrapIter.html +pub fn wrap_iter(s: &str, width: usize) -> IntoWrapIter { + Wrapper::new(width).into_wrap_iter(s) +} + +#[cfg(test)] +mod tests { + #[cfg(feature = "hyphenation")] + extern crate hyphenation; + + use super::*; + #[cfg(feature = "hyphenation")] + use hyphenation::{Language, Load, Standard}; + + #[test] + fn no_wrap() { + assert_eq!(wrap("foo", 10), vec!["foo"]); + } + + #[test] + fn simple() { + assert_eq!(wrap("foo bar baz", 5), vec!["foo", "bar", "baz"]); + } + + #[test] + fn multi_word_on_line() { + assert_eq!(wrap("foo bar baz", 10), vec!["foo bar", "baz"]); + } + + #[test] + fn long_word() { + assert_eq!(wrap("foo", 0), vec!["f", "o", "o"]); + } + + #[test] + fn long_words() { + assert_eq!(wrap("foo bar", 0), vec!["f", "o", "o", "b", "a", "r"]); + } + + #[test] + fn max_width() { + assert_eq!(wrap("foo bar", usize::max_value()), vec!["foo bar"]); + } + + #[test] + fn leading_whitespace() { + assert_eq!(wrap(" foo bar", 6), vec![" foo", "bar"]); + } + + #[test] + fn trailing_whitespace() { + assert_eq!(wrap("foo bar ", 6), vec!["foo", "bar "]); + } + + #[test] + fn interior_whitespace() { + assert_eq!(wrap("foo: bar baz", 10), vec!["foo: bar", "baz"]); + } + + #[test] + fn extra_whitespace_start_of_line() { + // Whitespace is only significant inside a line. After a line + // gets too long and is broken, the first word starts in + // column zero and is not indented. The line before might end + // up with trailing whitespace. + assert_eq!(wrap("foo bar", 5), vec!["foo", "bar"]); + } + + #[test] + fn issue_99() { + // We did not reset the in_whitespace flag correctly and did + // not handle single-character words after a line break. + assert_eq!( + wrap("aaabbbccc x yyyzzzwww", 9), + vec!["aaabbbccc", "x", "yyyzzzwww"] + ); + } + + #[test] + fn issue_129() { + // The dash is an em-dash which takes up four bytes. We used + // to panic since we tried to index into the character. + assert_eq!(wrap("x – x", 1), vec!["x", "–", "x"]); + } + + #[test] + fn wide_character_handling() { + assert_eq!(wrap("Hello, World!", 15), vec!["Hello, World!"]); + assert_eq!( + wrap("Hellï½, ï¼·ï½ï½’ld!", 15), + vec!["Hellï½,", "ï¼·ï½ï½’ld!"] + ); + } + + #[test] + fn empty_input_not_indented() { + let wrapper = Wrapper::new(10).initial_indent("!!!"); + assert_eq!(wrapper.fill(""), ""); + } + + #[test] + fn indent_single_line() { + let wrapper = Wrapper::new(10).initial_indent(">>>"); // No trailing space + assert_eq!(wrapper.fill("foo"), ">>>foo"); + } + + #[test] + fn indent_multiple_lines() { + let wrapper = Wrapper::new(6).initial_indent("* ").subsequent_indent(" "); + assert_eq!(wrapper.wrap("foo bar baz"), vec!["* foo", " bar", " baz"]); + } + + #[test] + fn indent_break_words() { + let wrapper = Wrapper::new(5).initial_indent("* ").subsequent_indent(" "); + assert_eq!(wrapper.wrap("foobarbaz"), vec!["* foo", " bar", " baz"]); + } + + #[test] + fn hyphens() { + assert_eq!(wrap("foo-bar", 5), vec!["foo-", "bar"]); + } + + #[test] + fn trailing_hyphen() { + let wrapper = Wrapper::new(5).break_words(false); + assert_eq!(wrapper.wrap("foobar-"), vec!["foobar-"]); + } + + #[test] + fn multiple_hyphens() { + assert_eq!(wrap("foo-bar-baz", 5), vec!["foo-", "bar-", "baz"]); + } + + #[test] + fn hyphens_flag() { + let wrapper = Wrapper::new(5).break_words(false); + assert_eq!( + wrapper.wrap("The --foo-bar flag."), + vec!["The", "--foo-", "bar", "flag."] + ); + } + + #[test] + fn repeated_hyphens() { + let wrapper = Wrapper::new(4).break_words(false); + assert_eq!(wrapper.wrap("foo--bar"), vec!["foo--bar"]); + } + + #[test] + fn hyphens_alphanumeric() { + assert_eq!(wrap("Na2-CH4", 5), vec!["Na2-", "CH4"]); + } + + #[test] + fn hyphens_non_alphanumeric() { + let wrapper = Wrapper::new(5).break_words(false); + assert_eq!(wrapper.wrap("foo(-)bar"), vec!["foo(-)bar"]); + } + + #[test] + fn multiple_splits() { + assert_eq!(wrap("foo-bar-baz", 9), vec!["foo-bar-", "baz"]); + } + + #[test] + fn forced_split() { + let wrapper = Wrapper::new(5).break_words(false); + assert_eq!(wrapper.wrap("foobar-baz"), vec!["foobar-", "baz"]); + } + + #[test] + fn no_hyphenation() { + let wrapper = Wrapper::with_splitter(8, NoHyphenation); + assert_eq!(wrapper.wrap("foo bar-baz"), vec!["foo", "bar-baz"]); + } + + #[test] + #[cfg(feature = "hyphenation")] + fn auto_hyphenation() { + let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); + let wrapper = Wrapper::new(10); + assert_eq!( + wrapper.wrap("Internationalization"), + vec!["Internatio", "nalization"] + ); + + let wrapper = Wrapper::with_splitter(10, dictionary); + assert_eq!( + wrapper.wrap("Internationalization"), + vec!["Interna-", "tionaliza-", "tion"] + ); + } + + #[test] + #[cfg(feature = "hyphenation")] + fn split_len_hyphenation() { + // Test that hyphenation takes the width of the wihtespace + // into account. + let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); + let wrapper = Wrapper::with_splitter(15, dictionary); + assert_eq!( + wrapper.wrap("garbage collection"), + vec!["garbage col-", "lection"] + ); + } + + #[test] + #[cfg(feature = "hyphenation")] + fn borrowed_lines() { + // Lines that end with an extra hyphen are owned, the final + // line is borrowed. + use std::borrow::Cow::{Borrowed, Owned}; + let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); + let wrapper = Wrapper::with_splitter(10, dictionary); + let lines = wrapper.wrap("Internationalization"); + if let Borrowed(s) = lines[0] { + assert!(false, "should not have been borrowed: {:?}", s); + } + if let Borrowed(s) = lines[1] { + assert!(false, "should not have been borrowed: {:?}", s); + } + if let Owned(ref s) = lines[2] { + assert!(false, "should not have been owned: {:?}", s); + } + } + + #[test] + #[cfg(feature = "hyphenation")] + fn auto_hyphenation_with_hyphen() { + let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); + let wrapper = Wrapper::new(8).break_words(false); + assert_eq!(wrapper.wrap("over-caffinated"), vec!["over-", "caffinated"]); + + let wrapper = Wrapper::with_splitter(8, dictionary).break_words(false); + assert_eq!( + wrapper.wrap("over-caffinated"), + vec!["over-", "caffi-", "nated"] + ); + } + + #[test] + fn break_words() { + assert_eq!(wrap("foobarbaz", 3), vec!["foo", "bar", "baz"]); + } + + #[test] + fn break_words_wide_characters() { + assert_eq!(wrap("Hellï½", 5), vec!["He", "ll", "ï½"]); + } + + #[test] + fn break_words_zero_width() { + assert_eq!(wrap("foobar", 0), vec!["f", "o", "o", "b", "a", "r"]); + } + + #[test] + fn break_words_line_breaks() { + assert_eq!(fill("ab\ncdefghijkl", 5), "ab\ncdefg\nhijkl"); + assert_eq!(fill("abcdefgh\nijkl", 5), "abcde\nfgh\nijkl"); + } + + #[test] + fn preserve_line_breaks() { + assert_eq!(fill("test\n", 11), "test\n"); + assert_eq!(fill("test\n\na\n\n", 11), "test\n\na\n\n"); + assert_eq!(fill("1 3 5 7\n1 3 5 7", 7), "1 3 5 7\n1 3 5 7"); + } + + #[test] + fn wrap_preserve_line_breaks() { + assert_eq!(fill("1 3 5 7\n1 3 5 7", 5), "1 3 5\n7\n1 3 5\n7"); + } + + #[test] + fn non_breaking_space() { + let wrapper = Wrapper::new(5).break_words(false); + assert_eq!(wrapper.fill("foo bar baz"), "foo bar baz"); + } + + #[test] + fn non_breaking_hyphen() { + let wrapper = Wrapper::new(5).break_words(false); + assert_eq!(wrapper.fill("foo‑bar‑baz"), "foo‑bar‑baz"); + } + + #[test] + fn fill_simple() { + assert_eq!(fill("foo bar baz", 10), "foo bar\nbaz"); + } +} diff --git a/vendor/textwrap/src/splitting.rs b/vendor/textwrap/src/splitting.rs new file mode 100644 index 0000000000000..f6b65afda1e18 --- /dev/null +++ b/vendor/textwrap/src/splitting.rs @@ -0,0 +1,139 @@ +//! Word splitting functionality. +//! +//! To wrap text into lines, long words sometimes need to be split +//! across lines. The [`WordSplitter`] trait defines this +//! functionality. [`HyphenSplitter`] is the default implementation of +//! this treat: it will simply split words on existing hyphens. + +#[cfg(feature = "hyphenation")] +use hyphenation::{Hyphenator, Standard}; + +/// An interface for splitting words. +/// +/// When the [`wrap_iter`] method will try to fit text into a line, it +/// will eventually find a word that it too large the current text +/// width. It will then call the currently configured `WordSplitter` to +/// have it attempt to split the word into smaller parts. This trait +/// describes that functionality via the [`split`] method. +/// +/// If the `textwrap` crate has been compiled with the `hyphenation` +/// feature enabled, you will find an implementation of `WordSplitter` +/// by the `hyphenation::language::Corpus` struct. Use this struct for +/// language-aware hyphenation. See the [`hyphenation` documentation] +/// for details. +/// +/// [`wrap_iter`]: ../struct.Wrapper.html#method.wrap_iter +/// [`split`]: #tymethod.split +/// [`hyphenation` documentation]: https://docs.rs/hyphenation/ +pub trait WordSplitter { + /// Return all possible splits of word. Each split is a triple + /// with a head, a hyphen, and a tail where `head + &hyphen + + /// &tail == word`. The hyphen can be empty if there is already a + /// hyphen in the head. + /// + /// The splits should go from smallest to longest and should + /// include no split at all. So the word "technology" could be + /// split into + /// + /// ```no_run + /// vec![("tech", "-", "nology"), + /// ("technol", "-", "ogy"), + /// ("technolo", "-", "gy"), + /// ("technology", "", "")]; + /// ``` + fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)>; +} + +/// Use this as a [`Wrapper.splitter`] to avoid any kind of +/// hyphenation: +/// +/// ``` +/// use textwrap::{Wrapper, NoHyphenation}; +/// +/// let wrapper = Wrapper::with_splitter(8, NoHyphenation); +/// assert_eq!(wrapper.wrap("foo bar-baz"), vec!["foo", "bar-baz"]); +/// ``` +/// +/// [`Wrapper.splitter`]: ../struct.Wrapper.html#structfield.splitter +#[derive(Clone, Debug)] +pub struct NoHyphenation; + +/// `NoHyphenation` implements `WordSplitter` by not splitting the +/// word at all. +impl WordSplitter for NoHyphenation { + fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)> { + vec![(word, "", "")] + } +} + +/// Simple and default way to split words: splitting on existing +/// hyphens only. +/// +/// You probably don't need to use this type since it's already used +/// by default by `Wrapper::new`. +#[derive(Clone, Debug)] +pub struct HyphenSplitter; + +/// `HyphenSplitter` is the default `WordSplitter` used by +/// `Wrapper::new`. It will split words on any existing hyphens in the +/// word. +/// +/// It will only use hyphens that are surrounded by alphanumeric +/// characters, which prevents a word like "--foo-bar" from being +/// split on the first or second hyphen. +impl WordSplitter for HyphenSplitter { + fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)> { + let mut triples = Vec::new(); + // Split on hyphens, smallest split first. We only use hyphens + // that are surrounded by alphanumeric characters. This is to + // avoid splitting on repeated hyphens, such as those found in + // --foo-bar. + let mut char_indices = word.char_indices(); + // Early return if the word is empty. + let mut prev = match char_indices.next() { + None => return vec![(word, "", "")], + Some((_, ch)) => ch, + }; + + // Find current word, or return early if the word only has a + // single character. + let (mut idx, mut cur) = match char_indices.next() { + None => return vec![(word, "", "")], + Some((idx, cur)) => (idx, cur), + }; + + for (i, next) in char_indices { + if prev.is_alphanumeric() && cur == '-' && next.is_alphanumeric() { + let (head, tail) = word.split_at(idx + 1); + triples.push((head, "", tail)); + } + prev = cur; + idx = i; + cur = next; + } + + // Finally option is no split at all. + triples.push((word, "", "")); + + triples + } +} + +/// A hyphenation dictionary can be used to do language-specific +/// hyphenation using patterns from the hyphenation crate. +#[cfg(feature = "hyphenation")] +impl WordSplitter for Standard { + fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)> { + // Find splits based on language dictionary. + let mut triples = Vec::new(); + for n in self.hyphenate(word).breaks { + let (head, tail) = word.split_at(n); + let hyphen = if head.ends_with('-') { "" } else { "-" }; + triples.push((head, hyphen, tail)); + } + // Finally option is no split at all. + triples.push((word, "", "")); + + triples + } +} diff --git a/vendor/textwrap/tests/version-numbers.rs b/vendor/textwrap/tests/version-numbers.rs new file mode 100644 index 0000000000000..85c52e372f4f8 --- /dev/null +++ b/vendor/textwrap/tests/version-numbers.rs @@ -0,0 +1,17 @@ +#[macro_use] +extern crate version_sync; + +#[test] +fn test_readme_deps() { + assert_markdown_deps_updated!("README.md"); +} + +#[test] +fn test_readme_changelog() { + assert_contains_regex!("README.md", r"^### Version {version} — .* \d\d?.., 20\d\d$"); +} + +#[test] +fn test_html_root_url() { + assert_html_root_url_updated!("src/lib.rs"); +} diff --git a/vendor/tikv-jemalloc-sys/configure/VERSION b/vendor/tikv-jemalloc-sys/configure/VERSION new file mode 100644 index 0000000000000..1dcfea03fc1a3 --- /dev/null +++ b/vendor/tikv-jemalloc-sys/configure/VERSION @@ -0,0 +1 @@ +5.3.0-0-g54eaed1d8b56b1aa528be3bdd1877e59c56fa90c diff --git a/vendor/time/src/date_time.rs b/vendor/time/src/date_time.rs new file mode 100644 index 0000000000000..27f07cec8549c --- /dev/null +++ b/vendor/time/src/date_time.rs @@ -0,0 +1,1248 @@ +//! The [`DateTime`] struct and its associated `impl`s. + +// TODO(jhpratt) Document everything before making public. +#![allow(clippy::missing_docs_in_private_items)] +// This is intentional, as the struct will likely be exposed at some point. +#![allow(unreachable_pub)] + +use core::cmp::Ordering; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::mem::size_of; +use core::ops::{Add, AddAssign, Sub, SubAssign}; +use core::time::Duration as StdDuration; +#[cfg(feature = "formatting")] +use std::io; +#[cfg(feature = "std")] +use std::time::SystemTime; + +use deranged::RangedI64; +use powerfmt::ext::FormatterExt; +use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay}; + +use crate::convert::*; +use crate::date::{MAX_YEAR, MIN_YEAR}; +#[cfg(feature = "formatting")] +use crate::formatting::Formattable; +use crate::internal_macros::{ + bug, cascade, const_try, const_try_opt, div_floor, ensure_ranged, expect_opt, impl_add_assign, + impl_sub_assign, +}; +#[cfg(feature = "parsing")] +use crate::parsing::{Parsable, Parsed}; +use crate::{error, util, Date, Duration, Month, Time, UtcOffset, Weekday}; + +#[allow(missing_debug_implementations, missing_copy_implementations)] +pub(crate) mod offset_kind { + pub enum None {} + pub enum Fixed {} +} + +pub(crate) use sealed::MaybeOffset; +use sealed::*; +mod sealed { + use super::*; + + /// A type that is guaranteed to be either `()` or [`UtcOffset`]. + /// + /// **Do not** add any additional implementations of this trait. + #[allow(unreachable_pub)] // intentional + pub trait MaybeOffsetType {} + impl MaybeOffsetType for () {} + impl MaybeOffsetType for UtcOffset {} + + pub trait MaybeOffset: Sized { + /// The offset type as it is stored in memory. + #[cfg(feature = "quickcheck")] + type MemoryOffsetType: Copy + MaybeOffsetType + quickcheck::Arbitrary; + #[cfg(not(feature = "quickcheck"))] + type MemoryOffsetType: Copy + MaybeOffsetType; + + /// The offset type as it should be thought about. + /// + /// For example, a `DateTime` has a logical offset type of [`UtcOffset`], but does not + /// actually store an offset in memory. + type LogicalOffsetType: Copy + MaybeOffsetType; + + /// Required to be `Self`. Used for bound equality. + type Self_; + + /// True if and only if `Self::LogicalOffsetType` is `UtcOffset`. + const HAS_LOGICAL_OFFSET: bool = + size_of::() == size_of::(); + /// True if and only if `Self::MemoryOffsetType` is `UtcOffset`. + const HAS_MEMORY_OFFSET: bool = + size_of::() == size_of::(); + + /// `Some` if and only if the logical UTC offset is statically known. + // TODO(jhpratt) When const trait impls are stable, this can be removed in favor of + // `.as_offset_opt()`. + const STATIC_OFFSET: Option; + + #[cfg(feature = "parsing")] + fn try_from_parsed(parsed: Parsed) -> Result; + } + + // Traits to indicate whether a `MaybeOffset` has a logical offset type of `UtcOffset` or not. + + pub trait HasLogicalOffset: MaybeOffset {} + impl> HasLogicalOffset for T {} + + pub trait NoLogicalOffset: MaybeOffset {} + impl> NoLogicalOffset for T {} + + // Traits to indicate whether a `MaybeOffset` has a memory offset type of `UtcOffset` or not. + + pub trait HasMemoryOffset: MaybeOffset {} + impl> HasMemoryOffset for T {} + + pub trait NoMemoryOffset: MaybeOffset {} + impl> NoMemoryOffset for T {} + + // Traits to indicate backing type being implemented. + + pub trait IsOffsetKindNone: + MaybeOffset + { + } + impl IsOffsetKindNone for offset_kind::None {} + + pub trait IsOffsetKindFixed: + MaybeOffset< + Self_ = offset_kind::Fixed, + MemoryOffsetType = UtcOffset, + LogicalOffsetType = UtcOffset, + > + { + } + impl IsOffsetKindFixed for offset_kind::Fixed {} +} + +impl MaybeOffset for offset_kind::None { + type MemoryOffsetType = (); + type LogicalOffsetType = (); + + type Self_ = Self; + + const STATIC_OFFSET: Option = None; + + #[cfg(feature = "parsing")] + fn try_from_parsed(_: Parsed) -> Result<(), error::TryFromParsed> { + Ok(()) + } +} + +impl MaybeOffset for offset_kind::Fixed { + type MemoryOffsetType = UtcOffset; + type LogicalOffsetType = UtcOffset; + + type Self_ = Self; + + const STATIC_OFFSET: Option = None; + + #[cfg(feature = "parsing")] + fn try_from_parsed(parsed: Parsed) -> Result { + parsed.try_into() + } +} + +// region: const trait method hacks +// TODO(jhpratt) When const trait impls are stable, these methods can be removed in favor of methods +// in `MaybeOffset`, which would then be made `const`. +const fn maybe_offset_as_offset_opt( + offset: O::MemoryOffsetType, +) -> Option { + if O::STATIC_OFFSET.is_some() { + O::STATIC_OFFSET + } else if O::HAS_MEMORY_OFFSET { + #[repr(C)] // needed to guarantee they align at the start + union Convert { + input: O::MemoryOffsetType, + output: UtcOffset, + } + + // Safety: `O::HAS_OFFSET` indicates that `O::Offset` is `UtcOffset`. This code effectively + // performs a transmute from `O::Offset` to `UtcOffset`, which we know is the same type. + Some(unsafe { Convert:: { input: offset }.output }) + } else { + None + } +} + +const fn maybe_offset_as_offset( + offset: O::MemoryOffsetType, +) -> UtcOffset { + match maybe_offset_as_offset_opt::(offset) { + Some(offset) => offset, + None => bug!("`MaybeOffset::as_offset` called on a type without an offset in memory"), + } +} + +pub(crate) const fn maybe_offset_from_offset( + offset: UtcOffset, +) -> O::MemoryOffsetType { + #[repr(C)] // needed to guarantee the types align at the start + union Convert { + input: UtcOffset, + output: O::MemoryOffsetType, + } + + // Safety: It is statically known that there are only two possibilities due to the trait bound + // of `O::MemoryOffsetType`, which ultimately relies on `MaybeOffsetType`. The two possibilities + // are: + // 1. UtcOffset -> UtcOffset + // 2. UtcOffset -> () + // (1) is valid because it is an identity conversion, which is always valid. (2) is valid + // because `()` is a 1-ZST, so converting to it is always valid. + unsafe { Convert:: { input: offset }.output } +} +// endregion const trait methods hacks + +/// The Julian day of the Unix epoch. +// Safety: `ordinal` is not zero. +#[allow(clippy::undocumented_unsafe_blocks)] +const UNIX_EPOCH_JULIAN_DAY: i32 = + unsafe { Date::__from_ordinal_date_unchecked(1970, 1) }.to_julian_day(); + +pub struct DateTime { + pub(crate) date: Date, + pub(crate) time: Time, + pub(crate) offset: O::MemoryOffsetType, +} + +// Manual impl to remove extraneous bounds. +impl Clone for DateTime { + fn clone(&self) -> Self { + *self + } +} + +// Manual impl to remove extraneous bounds. +impl Copy for DateTime {} + +// region: constructors +impl DateTime { + pub const MIN: Self = Self { + date: Date::MIN, + time: Time::MIN, + offset: (), + }; + + pub const MAX: Self = Self { + date: Date::MAX, + time: Time::MAX, + offset: (), + }; +} + +impl DateTime { + pub const UNIX_EPOCH: Self = Self { + // Safety: `ordinal` is not zero. + date: unsafe { Date::__from_ordinal_date_unchecked(1970, 1) }, + time: Time::MIDNIGHT, + offset: UtcOffset::UTC, + }; +} + +impl DateTime { + pub const fn new(date: Date, time: Time) -> Self + where + O: IsOffsetKindNone, + { + Self { + date, + time, + offset: (), + } + } + + pub const fn from_unix_timestamp(timestamp: i64) -> Result + where + O: HasLogicalOffset, + { + type Timestamp = RangedI64< + { Date::MIN.midnight().assume_utc().unix_timestamp() }, + { Date::MAX.with_time(Time::MAX).assume_utc().unix_timestamp() }, + >; + ensure_ranged!(Timestamp: timestamp); + + // Use the unchecked method here, as the input validity has already been verified. + let date = Date::from_julian_day_unchecked( + UNIX_EPOCH_JULIAN_DAY + div_floor!(timestamp, Second::per(Day) as i64) as i32, + ); + + let seconds_within_day = timestamp.rem_euclid(Second::per(Day) as _); + // Safety: All values are in range. + let time = unsafe { + Time::__from_hms_nanos_unchecked( + (seconds_within_day / Second::per(Hour) as i64) as _, + ((seconds_within_day % Second::per(Hour) as i64) / Minute::per(Hour) as i64) as _, + (seconds_within_day % Second::per(Minute) as i64) as _, + 0, + ) + }; + + Ok(Self { + date, + time, + offset: maybe_offset_from_offset::(UtcOffset::UTC), + }) + } + + pub const fn from_unix_timestamp_nanos(timestamp: i128) -> Result + where + O: HasLogicalOffset, + { + let datetime = const_try!(Self::from_unix_timestamp(div_floor!( + timestamp, + Nanosecond::per(Second) as i128 + ) as i64)); + + Ok(Self { + date: datetime.date, + // Safety: `nanosecond` is in range due to `rem_euclid`. + time: unsafe { + Time::__from_hms_nanos_unchecked( + datetime.hour(), + datetime.minute(), + datetime.second(), + timestamp.rem_euclid(Nanosecond::per(Second) as _) as u32, + ) + }, + offset: maybe_offset_from_offset::(UtcOffset::UTC), + }) + } + // endregion constructors + + // region: now + // The return type will likely be loosened once `ZonedDateTime` is implemented. This is not a + // breaking change calls are currently limited to only `OffsetDateTime`. + #[cfg(feature = "std")] + pub fn now_utc() -> DateTime + where + O: IsOffsetKindFixed, + { + #[cfg(all( + target_family = "wasm", + not(any(target_os = "emscripten", target_os = "wasi")), + feature = "wasm-bindgen" + ))] + { + js_sys::Date::new_0().into() + } + + #[cfg(not(all( + target_family = "wasm", + not(any(target_os = "emscripten", target_os = "wasi")), + feature = "wasm-bindgen" + )))] + SystemTime::now().into() + } + + // The return type will likely be loosened once `ZonedDateTime` is implemented. This is not a + // breaking change calls are currently limited to only `OffsetDateTime`. + #[cfg(feature = "local-offset")] + pub fn now_local() -> Result, error::IndeterminateOffset> + where + O: IsOffsetKindFixed, + { + let t = DateTime::::now_utc(); + Ok(t.to_offset(UtcOffset::local_offset_at(crate::OffsetDateTime(t))?)) + } + // endregion now + + // region: getters + // region: component getters + pub const fn date(self) -> Date { + self.date + } + + pub const fn time(self) -> Time { + self.time + } + + pub const fn offset(self) -> UtcOffset + where + O: HasLogicalOffset, + { + maybe_offset_as_offset::(self.offset) + } + // endregion component getters + + // region: date getters + pub const fn year(self) -> i32 { + self.date.year() + } + + pub const fn month(self) -> Month { + self.date.month() + } + + pub const fn day(self) -> u8 { + self.date.day() + } + + pub const fn ordinal(self) -> u16 { + self.date.ordinal() + } + + pub const fn iso_week(self) -> u8 { + self.date.iso_week() + } + + pub const fn sunday_based_week(self) -> u8 { + self.date.sunday_based_week() + } + + pub const fn monday_based_week(self) -> u8 { + self.date.monday_based_week() + } + + pub const fn to_calendar_date(self) -> (i32, Month, u8) { + self.date.to_calendar_date() + } + + pub const fn to_ordinal_date(self) -> (i32, u16) { + self.date.to_ordinal_date() + } + + pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) { + self.date.to_iso_week_date() + } + + pub const fn weekday(self) -> Weekday { + self.date.weekday() + } + + pub const fn to_julian_day(self) -> i32 { + self.date.to_julian_day() + } + // endregion date getters + + // region: time getters + pub const fn as_hms(self) -> (u8, u8, u8) { + self.time.as_hms() + } + + pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) { + self.time.as_hms_milli() + } + + pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) { + self.time.as_hms_micro() + } + + pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) { + self.time.as_hms_nano() + } + + pub const fn hour(self) -> u8 { + self.time.hour() + } + + pub const fn minute(self) -> u8 { + self.time.minute() + } + + pub const fn second(self) -> u8 { + self.time.second() + } + + pub const fn millisecond(self) -> u16 { + self.time.millisecond() + } + + pub const fn microsecond(self) -> u32 { + self.time.microsecond() + } + + pub const fn nanosecond(self) -> u32 { + self.time.nanosecond() + } + // endregion time getters + + // region: unix timestamp getters + pub const fn unix_timestamp(self) -> i64 + where + O: HasLogicalOffset, + { + let offset = maybe_offset_as_offset::(self.offset).whole_seconds() as i64; + + let days = + (self.to_julian_day() as i64 - UNIX_EPOCH_JULIAN_DAY as i64) * Second::per(Day) as i64; + let hours = self.hour() as i64 * Second::per(Hour) as i64; + let minutes = self.minute() as i64 * Second::per(Minute) as i64; + let seconds = self.second() as i64; + days + hours + minutes + seconds - offset + } + + pub const fn unix_timestamp_nanos(self) -> i128 + where + O: HasLogicalOffset, + { + self.unix_timestamp() as i128 * Nanosecond::per(Second) as i128 + self.nanosecond() as i128 + } + // endregion unix timestamp getters + // endregion: getters + + // region: attach offset + pub const fn assume_offset(self, offset: UtcOffset) -> DateTime + where + O: NoLogicalOffset, + { + DateTime { + date: self.date, + time: self.time, + offset, + } + } + + pub const fn assume_utc(self) -> DateTime + where + O: NoLogicalOffset, + { + self.assume_offset(UtcOffset::UTC) + } + // endregion attach offset + + // region: to offset + pub const fn to_offset(self, offset: UtcOffset) -> DateTime + where + O: HasLogicalOffset, + { + expect_opt!( + self.checked_to_offset(offset), + "local datetime out of valid range" + ) + } + + pub const fn checked_to_offset(self, offset: UtcOffset) -> Option> + where + O: HasLogicalOffset, + { + let self_offset = maybe_offset_as_offset::(self.offset); + + if self_offset.whole_hours() == offset.whole_hours() + && self_offset.minutes_past_hour() == offset.minutes_past_hour() + && self_offset.seconds_past_minute() == offset.seconds_past_minute() + { + return Some(DateTime { + date: self.date, + time: self.time, + offset, + }); + } + + let (year, ordinal, time) = self.to_offset_raw(offset); + + if year > MAX_YEAR || year < MIN_YEAR { + return None; + } + + Some(DateTime { + // Safety: `ordinal` is not zero. + date: unsafe { Date::__from_ordinal_date_unchecked(year, ordinal) }, + time, + offset, + }) + } + + /// Equivalent to `.to_offset(UtcOffset::UTC)`, but returning the year, ordinal, and time. This + /// avoids constructing an invalid [`Date`] if the new value is out of range. + pub(crate) const fn to_offset_raw(self, offset: UtcOffset) -> (i32, u16, Time) { + let Some(from) = maybe_offset_as_offset_opt::(self.offset) else { + // No adjustment is needed because there is no offset. + return (self.year(), self.ordinal(), self.time); + }; + let to = offset; + + // Fast path for when no conversion is necessary. + if from.whole_hours() == to.whole_hours() + && from.minutes_past_hour() == to.minutes_past_hour() + && from.seconds_past_minute() == to.seconds_past_minute() + { + return (self.year(), self.ordinal(), self.time()); + } + + let mut second = self.second() as i16 - from.seconds_past_minute() as i16 + + to.seconds_past_minute() as i16; + let mut minute = + self.minute() as i16 - from.minutes_past_hour() as i16 + to.minutes_past_hour() as i16; + let mut hour = self.hour() as i8 - from.whole_hours() + to.whole_hours(); + let (mut year, ordinal) = self.to_ordinal_date(); + let mut ordinal = ordinal as i16; + + // Cascade the values twice. This is needed because the values are adjusted twice above. + cascade!(second in 0..Second::per(Minute) as i16 => minute); + cascade!(second in 0..Second::per(Minute) as i16 => minute); + cascade!(minute in 0..Minute::per(Hour) as i16 => hour); + cascade!(minute in 0..Minute::per(Hour) as i16 => hour); + cascade!(hour in 0..Hour::per(Day) as i8 => ordinal); + cascade!(hour in 0..Hour::per(Day) as i8 => ordinal); + cascade!(ordinal => year); + + debug_assert!(ordinal > 0); + debug_assert!(ordinal <= crate::util::days_in_year(year) as i16); + + ( + year, + ordinal as _, + // Safety: The cascades above ensure the values are in range. + unsafe { + Time::__from_hms_nanos_unchecked( + hour as _, + minute as _, + second as _, + self.nanosecond(), + ) + }, + ) + } + // endregion to offset + + // region: checked arithmetic + pub const fn checked_add(self, duration: Duration) -> Option { + let (date_adjustment, time) = self.time.adjusting_add(duration); + let date = const_try_opt!(self.date.checked_add(duration)); + + Some(Self { + date: match date_adjustment { + util::DateAdjustment::Previous => const_try_opt!(date.previous_day()), + util::DateAdjustment::Next => const_try_opt!(date.next_day()), + util::DateAdjustment::None => date, + }, + time, + offset: self.offset, + }) + } + + pub const fn checked_sub(self, duration: Duration) -> Option { + let (date_adjustment, time) = self.time.adjusting_sub(duration); + let date = const_try_opt!(self.date.checked_sub(duration)); + + Some(Self { + date: match date_adjustment { + util::DateAdjustment::Previous => const_try_opt!(date.previous_day()), + util::DateAdjustment::Next => const_try_opt!(date.next_day()), + util::DateAdjustment::None => date, + }, + time, + offset: self.offset, + }) + } + // endregion checked arithmetic + + // region: saturating arithmetic + pub const fn saturating_add(self, duration: Duration) -> Self { + if let Some(datetime) = self.checked_add(duration) { + datetime + } else if duration.is_negative() { + Self { + date: Date::MIN, + time: Time::MIN, + offset: self.offset, + } + } else { + Self { + date: Date::MAX, + time: Time::MAX, + offset: self.offset, + } + } + } + + pub const fn saturating_sub(self, duration: Duration) -> Self { + if let Some(datetime) = self.checked_sub(duration) { + datetime + } else if duration.is_negative() { + Self { + date: Date::MAX, + time: Time::MAX, + offset: self.offset, + } + } else { + Self { + date: Date::MIN, + time: Time::MIN, + offset: self.offset, + } + } + } + // endregion saturating arithmetic + + // region: replacement + #[must_use = "this does not modify the original value"] + pub const fn replace_time(self, time: Time) -> Self { + Self { + date: self.date, + time, + offset: self.offset, + } + } + + #[must_use = "this does not modify the original value"] + pub const fn replace_date(self, date: Date) -> Self { + Self { + date, + time: self.time, + offset: self.offset, + } + } + + #[must_use = "this does not modify the original value"] + pub const fn replace_date_time(self, date_time: DateTime) -> Self + where + O: HasLogicalOffset, + { + Self { + date: date_time.date, + time: date_time.time, + offset: self.offset, + } + } + + #[must_use = "this does not modify the original value"] + pub const fn replace_year(self, year: i32) -> Result { + Ok(Self { + date: const_try!(self.date.replace_year(year)), + time: self.time, + offset: self.offset, + }) + } + + #[must_use = "this does not modify the original value"] + pub const fn replace_month(self, month: Month) -> Result { + Ok(Self { + date: const_try!(self.date.replace_month(month)), + time: self.time, + offset: self.offset, + }) + } + + #[must_use = "this does not modify the original value"] + pub const fn replace_day(self, day: u8) -> Result { + Ok(Self { + date: const_try!(self.date.replace_day(day)), + time: self.time, + offset: self.offset, + }) + } + + #[must_use = "this does not modify the original value"] + pub const fn replace_hour(self, hour: u8) -> Result { + Ok(Self { + date: self.date, + time: const_try!(self.time.replace_hour(hour)), + offset: self.offset, + }) + } + + #[must_use = "this does not modify the original value"] + pub const fn replace_minute(self, minute: u8) -> Result { + Ok(Self { + date: self.date, + time: const_try!(self.time.replace_minute(minute)), + offset: self.offset, + }) + } + + #[must_use = "this does not modify the original value"] + pub const fn replace_second(self, second: u8) -> Result { + Ok(Self { + date: self.date, + time: const_try!(self.time.replace_second(second)), + offset: self.offset, + }) + } + + #[must_use = "this does not modify the original value"] + pub const fn replace_millisecond( + self, + millisecond: u16, + ) -> Result { + Ok(Self { + date: self.date, + time: const_try!(self.time.replace_millisecond(millisecond)), + offset: self.offset, + }) + } + + #[must_use = "this does not modify the original value"] + pub const fn replace_microsecond( + self, + microsecond: u32, + ) -> Result { + Ok(Self { + date: self.date, + time: const_try!(self.time.replace_microsecond(microsecond)), + offset: self.offset, + }) + } + + #[must_use = "this does not modify the original value"] + pub const fn replace_nanosecond(self, nanosecond: u32) -> Result { + Ok(Self { + date: self.date, + time: const_try!(self.time.replace_nanosecond(nanosecond)), + offset: self.offset, + }) + } + + // Don't gate this on just having an offset, as `ZonedDateTime` cannot be set to an arbitrary + // offset. + #[must_use = "this does not modify the original value"] + pub const fn replace_offset(self, offset: UtcOffset) -> DateTime + where + O: IsOffsetKindFixed, + { + DateTime { + date: self.date, + time: self.time, + offset, + } + } + + // endregion replacement + + // region: formatting & parsing + #[cfg(feature = "formatting")] + pub fn format_into( + self, + output: &mut impl io::Write, + format: &(impl Formattable + ?Sized), + ) -> Result { + format.format_into( + output, + Some(self.date), + Some(self.time), + maybe_offset_as_offset_opt::(self.offset), + ) + } + + #[cfg(feature = "formatting")] + pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result { + format.format( + Some(self.date), + Some(self.time), + maybe_offset_as_offset_opt::(self.offset), + ) + } + + #[cfg(feature = "parsing")] + pub fn parse( + input: &str, + description: &(impl Parsable + ?Sized), + ) -> Result { + description.parse_date_time(input.as_bytes()) + } + + /// A helper method to check if the `OffsetDateTime` is a valid representation of a leap second. + /// Leap seconds, when parsed, are represented as the preceding nanosecond. However, leap + /// seconds can only occur as the last second of a month UTC. + #[cfg(feature = "parsing")] + pub(crate) const fn is_valid_leap_second_stand_in(self) -> bool { + // Leap seconds aren't allowed if there is no offset. + if !O::HAS_LOGICAL_OFFSET { + return false; + } + + // This comparison doesn't need to be adjusted for the stored offset, so check it first for + // speed. + if self.nanosecond() != 999_999_999 { + return false; + } + + let (year, ordinal, time) = self.to_offset_raw(UtcOffset::UTC); + let Ok(date) = Date::from_ordinal_date(year, ordinal) else { + return false; + }; + + time.hour() == 23 + && time.minute() == 59 + && time.second() == 59 + && date.day() == util::days_in_year_month(year, date.month()) + } + + // endregion formatting & parsing + + // region: deprecated time getters + + // All the way at the bottom as it's low priority. These methods only exist for when + // `OffsetDateTime` is made an alias of `DateTime`. Consider hiding these methods from + // documentation in the future. + + #[doc(hidden)] + #[allow(dead_code)] // while functionally private + #[deprecated(since = "0.3.18", note = "use `as_hms` instead")] + pub const fn to_hms(self) -> (u8, u8, u8) + where + O: IsOffsetKindFixed, + { + self.time.as_hms() + } + + #[doc(hidden)] + #[allow(dead_code)] // while functionally private + #[deprecated(since = "0.3.18", note = "use `as_hms_milli` instead")] + pub const fn to_hms_milli(self) -> (u8, u8, u8, u16) + where + O: IsOffsetKindFixed, + { + self.time.as_hms_milli() + } + + #[doc(hidden)] + #[allow(dead_code)] // while functionally private + #[deprecated(since = "0.3.18", note = "use `as_hms_micro` instead")] + pub const fn to_hms_micro(self) -> (u8, u8, u8, u32) + where + O: IsOffsetKindFixed, + { + self.time.as_hms_micro() + } + + #[doc(hidden)] + #[allow(dead_code)] // while functionally private + #[deprecated(since = "0.3.18", note = "use `as_hms_nano` instead")] + pub const fn to_hms_nano(self) -> (u8, u8, u8, u32) + where + O: IsOffsetKindFixed, + { + self.time.as_hms_nano() + } + // endregion deprecated time getters +} + +// region: trait impls +mod private { + use super::*; + + #[non_exhaustive] + #[derive(Debug, Clone, Copy)] + pub struct DateTimeMetadata { + pub(super) maybe_offset: Option, + } +} +pub(crate) use private::DateTimeMetadata; + +impl SmartDisplay for DateTime { + type Metadata = DateTimeMetadata; + + fn metadata(&self, _: FormatterOptions) -> Metadata { + let maybe_offset = maybe_offset_as_offset_opt::(self.offset); + let width = match maybe_offset { + Some(offset) => smart_display::padded_width_of!(self.date, " ", self.time, " ", offset), + None => smart_display::padded_width_of!(self.date, " ", self.time), + }; + Metadata::new(width, self, DateTimeMetadata { maybe_offset }) + } + + fn fmt_with_metadata( + &self, + f: &mut fmt::Formatter<'_>, + metadata: Metadata, + ) -> fmt::Result { + match metadata.maybe_offset { + Some(offset) => f.pad_with_width( + metadata.unpadded_width(), + format_args!("{} {} {offset}", self.date, self.time), + ), + None => f.pad_with_width( + metadata.unpadded_width(), + format_args!("{} {}", self.date, self.time), + ), + } + } +} + +impl fmt::Display for DateTime { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(self, f) + } +} + +impl fmt::Debug for DateTime { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +impl PartialEq for DateTime { + fn eq(&self, rhs: &Self) -> bool { + if O::HAS_LOGICAL_OFFSET { + self.to_offset_raw(UtcOffset::UTC) == rhs.to_offset_raw(UtcOffset::UTC) + } else { + (self.date, self.time) == (rhs.date, rhs.time) + } + } +} + +impl Eq for DateTime {} + +impl PartialOrd for DateTime { + fn partial_cmp(&self, rhs: &Self) -> Option { + Some(self.cmp(rhs)) + } +} + +impl Ord for DateTime { + fn cmp(&self, rhs: &Self) -> Ordering { + if O::HAS_LOGICAL_OFFSET { + self.to_offset_raw(UtcOffset::UTC) + .cmp(&rhs.to_offset_raw(UtcOffset::UTC)) + } else { + (self.date, self.time).cmp(&(rhs.date, rhs.time)) + } + } +} + +impl Hash for DateTime { + fn hash(&self, hasher: &mut H) { + if O::HAS_LOGICAL_OFFSET { + self.to_offset_raw(UtcOffset::UTC).hash(hasher); + } else { + (self.date, self.time).hash(hasher); + } + } +} + +impl Add for DateTime { + type Output = Self; + + fn add(self, duration: Duration) -> Self { + self.checked_add(duration) + .expect("resulting value is out of range") + } +} + +impl Add for DateTime { + type Output = Self; + + fn add(self, duration: StdDuration) -> Self::Output { + let (is_next_day, time) = self.time.adjusting_add_std(duration); + + Self { + date: if is_next_day { + (self.date + duration) + .next_day() + .expect("resulting value is out of range") + } else { + self.date + duration + }, + time, + offset: self.offset, + } + } +} + +impl AddAssign for DateTime { + fn add_assign(&mut self, rhs: Duration) { + *self = *self + rhs; + } +} + +impl AddAssign for DateTime { + fn add_assign(&mut self, rhs: StdDuration) { + *self = *self + rhs; + } +} + +impl Sub for DateTime { + type Output = Self; + + fn sub(self, duration: Duration) -> Self { + self.checked_sub(duration) + .expect("resulting value is out of range") + } +} + +impl Sub for DateTime { + type Output = Self; + + fn sub(self, duration: StdDuration) -> Self::Output { + let (is_previous_day, time) = self.time.adjusting_sub_std(duration); + + Self { + date: if is_previous_day { + (self.date - duration) + .previous_day() + .expect("resulting value is out of range") + } else { + self.date - duration + }, + time, + offset: self.offset, + } + } +} + +impl SubAssign for DateTime { + fn sub_assign(&mut self, rhs: Duration) { + *self = *self - rhs; + } +} + +impl SubAssign for DateTime { + fn sub_assign(&mut self, rhs: StdDuration) { + *self = *self - rhs; + } +} + +impl Sub for DateTime { + type Output = Duration; + + fn sub(self, rhs: Self) -> Self::Output { + let base = (self.date - rhs.date) + (self.time - rhs.time); + + match ( + maybe_offset_as_offset_opt::(self.offset), + maybe_offset_as_offset_opt::(rhs.offset), + ) { + (Some(self_offset), Some(rhs_offset)) => { + let adjustment = Duration::seconds( + (self_offset.whole_seconds() - rhs_offset.whole_seconds()) as i64, + ); + base - adjustment + } + (left, right) => { + debug_assert!( + left.is_none() && right.is_none(), + "offset type should not be different for the same type" + ); + base + } + } + } +} + +#[cfg(feature = "std")] +impl Add for SystemTime { + type Output = Self; + + fn add(self, duration: Duration) -> Self::Output { + if duration.is_zero() { + self + } else if duration.is_positive() { + self + duration.unsigned_abs() + } else { + debug_assert!(duration.is_negative()); + self - duration.unsigned_abs() + } + } +} + +impl_add_assign!(SystemTime: #[cfg(feature = "std")] Duration); + +#[cfg(feature = "std")] +impl Sub for SystemTime { + type Output = Self; + + fn sub(self, duration: Duration) -> Self::Output { + (DateTime::from(self) - duration).into() + } +} + +impl_sub_assign!(SystemTime: #[cfg(feature = "std")] Duration); + +#[cfg(feature = "std")] +impl Sub for DateTime { + type Output = Duration; + + fn sub(self, rhs: SystemTime) -> Self::Output { + self - Self::from(rhs) + } +} + +#[cfg(feature = "std")] +impl Sub> for SystemTime { + type Output = Duration; + + fn sub(self, rhs: DateTime) -> Self::Output { + DateTime::::from(self) - rhs + } +} + +#[cfg(feature = "std")] +impl PartialEq for DateTime { + fn eq(&self, rhs: &SystemTime) -> bool { + self == &Self::from(*rhs) + } +} + +#[cfg(feature = "std")] +impl PartialEq> for SystemTime { + fn eq(&self, rhs: &DateTime) -> bool { + &DateTime::::from(*self) == rhs + } +} + +#[cfg(feature = "std")] +impl PartialOrd for DateTime { + fn partial_cmp(&self, other: &SystemTime) -> Option { + self.partial_cmp(&Self::from(*other)) + } +} + +#[cfg(feature = "std")] +impl PartialOrd> for SystemTime { + fn partial_cmp(&self, other: &DateTime) -> Option { + DateTime::::from(*self).partial_cmp(other) + } +} + +#[cfg(feature = "std")] +impl From for DateTime { + fn from(system_time: SystemTime) -> Self { + match system_time.duration_since(SystemTime::UNIX_EPOCH) { + Ok(duration) => Self::UNIX_EPOCH + duration, + Err(err) => Self::UNIX_EPOCH - err.duration(), + } + } +} + +#[allow(clippy::fallible_impl_from)] // caused by `debug_assert!` +#[cfg(feature = "std")] +impl From> for SystemTime { + fn from(datetime: DateTime) -> Self { + let duration = datetime - DateTime::::UNIX_EPOCH; + + if duration.is_zero() { + Self::UNIX_EPOCH + } else if duration.is_positive() { + Self::UNIX_EPOCH + duration.unsigned_abs() + } else { + debug_assert!(duration.is_negative()); + Self::UNIX_EPOCH - duration.unsigned_abs() + } + } +} + +#[allow(clippy::fallible_impl_from)] +#[cfg(all( + target_family = "wasm", + not(any(target_os = "emscripten", target_os = "wasi")), + feature = "wasm-bindgen" +))] +impl From for DateTime { + fn from(js_date: js_sys::Date) -> Self { + // get_time() returns milliseconds + let timestamp_nanos = (js_date.get_time() * Nanosecond::per(Millisecond) as f64) as i128; + Self::from_unix_timestamp_nanos(timestamp_nanos) + .expect("invalid timestamp: Timestamp cannot fit in range") + } +} + +#[cfg(all( + target_family = "wasm", + not(any(target_os = "emscripten", target_os = "wasi")), + feature = "wasm-bindgen" +))] +impl From> for js_sys::Date { + fn from(datetime: DateTime) -> Self { + // new Date() takes milliseconds + let timestamp = + (datetime.unix_timestamp_nanos() / Nanosecond::per(Millisecond) as i128) as f64; + js_sys::Date::new(×tamp.into()) + } +} +// endregion trait impls diff --git a/vendor/time/src/ext.rs b/vendor/time/src/ext.rs new file mode 100644 index 0000000000000..1b89d41559117 --- /dev/null +++ b/vendor/time/src/ext.rs @@ -0,0 +1,319 @@ +//! Extension traits. + +use core::time::Duration as StdDuration; + +use crate::convert::*; +use crate::Duration; + +/// Sealed trait to prevent downstream implementations. +mod sealed { + /// A trait that cannot be implemented by downstream users. + pub trait Sealed {} + impl Sealed for i64 {} + impl Sealed for u64 {} + impl Sealed for f64 {} +} + +// region: NumericalDuration +/// Create [`Duration`]s from numeric literals. +/// +/// # Examples +/// +/// Basic construction of [`Duration`]s. +/// +/// ```rust +/// # use time::{Duration, ext::NumericalDuration}; +/// assert_eq!(5.nanoseconds(), Duration::nanoseconds(5)); +/// assert_eq!(5.microseconds(), Duration::microseconds(5)); +/// assert_eq!(5.milliseconds(), Duration::milliseconds(5)); +/// assert_eq!(5.seconds(), Duration::seconds(5)); +/// assert_eq!(5.minutes(), Duration::minutes(5)); +/// assert_eq!(5.hours(), Duration::hours(5)); +/// assert_eq!(5.days(), Duration::days(5)); +/// assert_eq!(5.weeks(), Duration::weeks(5)); +/// ``` +/// +/// Signed integers work as well! +/// +/// ```rust +/// # use time::{Duration, ext::NumericalDuration}; +/// assert_eq!((-5).nanoseconds(), Duration::nanoseconds(-5)); +/// assert_eq!((-5).microseconds(), Duration::microseconds(-5)); +/// assert_eq!((-5).milliseconds(), Duration::milliseconds(-5)); +/// assert_eq!((-5).seconds(), Duration::seconds(-5)); +/// assert_eq!((-5).minutes(), Duration::minutes(-5)); +/// assert_eq!((-5).hours(), Duration::hours(-5)); +/// assert_eq!((-5).days(), Duration::days(-5)); +/// assert_eq!((-5).weeks(), Duration::weeks(-5)); +/// ``` +/// +/// Just like any other [`Duration`], they can be added, subtracted, etc. +/// +/// ```rust +/// # use time::ext::NumericalDuration; +/// assert_eq!(2.seconds() + 500.milliseconds(), 2_500.milliseconds()); +/// assert_eq!(2.seconds() - 500.milliseconds(), 1_500.milliseconds()); +/// ``` +/// +/// When called on floating point values, any remainder of the floating point value will be +/// truncated. Keep in mind that floating point numbers are inherently imprecise and have limited +/// capacity. +pub trait NumericalDuration: sealed::Sealed { + /// Create a [`Duration`] from the number of nanoseconds. + fn nanoseconds(self) -> Duration; + /// Create a [`Duration`] from the number of microseconds. + fn microseconds(self) -> Duration; + /// Create a [`Duration`] from the number of milliseconds. + fn milliseconds(self) -> Duration; + /// Create a [`Duration`] from the number of seconds. + fn seconds(self) -> Duration; + /// Create a [`Duration`] from the number of minutes. + fn minutes(self) -> Duration; + /// Create a [`Duration`] from the number of hours. + fn hours(self) -> Duration; + /// Create a [`Duration`] from the number of days. + fn days(self) -> Duration; + /// Create a [`Duration`] from the number of weeks. + fn weeks(self) -> Duration; +} + +impl NumericalDuration for i64 { + fn nanoseconds(self) -> Duration { + Duration::nanoseconds(self) + } + + fn microseconds(self) -> Duration { + Duration::microseconds(self) + } + + fn milliseconds(self) -> Duration { + Duration::milliseconds(self) + } + + fn seconds(self) -> Duration { + Duration::seconds(self) + } + + fn minutes(self) -> Duration { + Duration::minutes(self) + } + + fn hours(self) -> Duration { + Duration::hours(self) + } + + fn days(self) -> Duration { + Duration::days(self) + } + + fn weeks(self) -> Duration { + Duration::weeks(self) + } +} + +impl NumericalDuration for f64 { + fn nanoseconds(self) -> Duration { + Duration::nanoseconds(self as _) + } + + fn microseconds(self) -> Duration { + Duration::nanoseconds((self * Nanosecond::per(Microsecond) as Self) as _) + } + + fn milliseconds(self) -> Duration { + Duration::nanoseconds((self * Nanosecond::per(Millisecond) as Self) as _) + } + + fn seconds(self) -> Duration { + Duration::nanoseconds((self * Nanosecond::per(Second) as Self) as _) + } + + fn minutes(self) -> Duration { + Duration::nanoseconds((self * Nanosecond::per(Minute) as Self) as _) + } + + fn hours(self) -> Duration { + Duration::nanoseconds((self * Nanosecond::per(Hour) as Self) as _) + } + + fn days(self) -> Duration { + Duration::nanoseconds((self * Nanosecond::per(Day) as Self) as _) + } + + fn weeks(self) -> Duration { + Duration::nanoseconds((self * Nanosecond::per(Week) as Self) as _) + } +} +// endregion NumericalDuration + +// region: NumericalStdDuration +/// Create [`std::time::Duration`]s from numeric literals. +/// +/// # Examples +/// +/// Basic construction of [`std::time::Duration`]s. +/// +/// ```rust +/// # use time::ext::NumericalStdDuration; +/// # use core::time::Duration; +/// assert_eq!(5.std_nanoseconds(), Duration::from_nanos(5)); +/// assert_eq!(5.std_microseconds(), Duration::from_micros(5)); +/// assert_eq!(5.std_milliseconds(), Duration::from_millis(5)); +/// assert_eq!(5.std_seconds(), Duration::from_secs(5)); +/// assert_eq!(5.std_minutes(), Duration::from_secs(5 * 60)); +/// assert_eq!(5.std_hours(), Duration::from_secs(5 * 3_600)); +/// assert_eq!(5.std_days(), Duration::from_secs(5 * 86_400)); +/// assert_eq!(5.std_weeks(), Duration::from_secs(5 * 604_800)); +/// ``` +/// +/// Just like any other [`std::time::Duration`], they can be added, subtracted, etc. +/// +/// ```rust +/// # use time::ext::NumericalStdDuration; +/// assert_eq!( +/// 2.std_seconds() + 500.std_milliseconds(), +/// 2_500.std_milliseconds() +/// ); +/// assert_eq!( +/// 2.std_seconds() - 500.std_milliseconds(), +/// 1_500.std_milliseconds() +/// ); +/// ``` +/// +/// When called on floating point values, any remainder of the floating point value will be +/// truncated. Keep in mind that floating point numbers are inherently imprecise and have limited +/// capacity. +pub trait NumericalStdDuration: sealed::Sealed { + /// Create a [`std::time::Duration`] from the number of nanoseconds. + fn std_nanoseconds(self) -> StdDuration; + /// Create a [`std::time::Duration`] from the number of microseconds. + fn std_microseconds(self) -> StdDuration; + /// Create a [`std::time::Duration`] from the number of milliseconds. + fn std_milliseconds(self) -> StdDuration; + /// Create a [`std::time::Duration`] from the number of seconds. + fn std_seconds(self) -> StdDuration; + /// Create a [`std::time::Duration`] from the number of minutes. + fn std_minutes(self) -> StdDuration; + /// Create a [`std::time::Duration`] from the number of hours. + fn std_hours(self) -> StdDuration; + /// Create a [`std::time::Duration`] from the number of days. + fn std_days(self) -> StdDuration; + /// Create a [`std::time::Duration`] from the number of weeks. + fn std_weeks(self) -> StdDuration; +} + +impl NumericalStdDuration for u64 { + fn std_nanoseconds(self) -> StdDuration { + StdDuration::from_nanos(self) + } + + fn std_microseconds(self) -> StdDuration { + StdDuration::from_micros(self) + } + + fn std_milliseconds(self) -> StdDuration { + StdDuration::from_millis(self) + } + + fn std_seconds(self) -> StdDuration { + StdDuration::from_secs(self) + } + + fn std_minutes(self) -> StdDuration { + StdDuration::from_secs( + self.checked_mul(Second::per(Minute) as Self) + .expect("overflow constructing `time::Duration`"), + ) + } + + fn std_hours(self) -> StdDuration { + StdDuration::from_secs( + self.checked_mul(Second::per(Hour) as Self) + .expect("overflow constructing `time::Duration`"), + ) + } + + fn std_days(self) -> StdDuration { + StdDuration::from_secs( + self.checked_mul(Second::per(Day) as Self) + .expect("overflow constructing `time::Duration`"), + ) + } + + fn std_weeks(self) -> StdDuration { + StdDuration::from_secs( + self.checked_mul(Second::per(Week) as Self) + .expect("overflow constructing `time::Duration`"), + ) + } +} + +impl NumericalStdDuration for f64 { + fn std_nanoseconds(self) -> StdDuration { + assert!(self >= 0.); + StdDuration::from_nanos(self as _) + } + + fn std_microseconds(self) -> StdDuration { + assert!(self >= 0.); + StdDuration::from_nanos((self * Nanosecond::per(Microsecond) as Self) as _) + } + + fn std_milliseconds(self) -> StdDuration { + assert!(self >= 0.); + StdDuration::from_nanos((self * Nanosecond::per(Millisecond) as Self) as _) + } + + fn std_seconds(self) -> StdDuration { + assert!(self >= 0.); + StdDuration::from_nanos((self * Nanosecond::per(Second) as Self) as _) + } + + fn std_minutes(self) -> StdDuration { + assert!(self >= 0.); + StdDuration::from_nanos((self * Nanosecond::per(Minute) as Self) as _) + } + + fn std_hours(self) -> StdDuration { + assert!(self >= 0.); + StdDuration::from_nanos((self * Nanosecond::per(Hour) as Self) as _) + } + + fn std_days(self) -> StdDuration { + assert!(self >= 0.); + StdDuration::from_nanos((self * Nanosecond::per(Day) as Self) as _) + } + + fn std_weeks(self) -> StdDuration { + assert!(self >= 0.); + StdDuration::from_nanos((self * Nanosecond::per(Week) as Self) as _) + } +} +// endregion NumericalStdDuration + +// region: DigitCount +/// A trait that indicates the formatted width of the value can be determined. +/// +/// Note that this should not be implemented for any signed integers. This forces the caller to +/// write the sign if desired. +pub(crate) trait DigitCount { + /// The number of digits in the stringified value. + fn num_digits(self) -> u8; +} + +/// A macro to generate implementations of `DigitCount` for unsigned integers. +macro_rules! impl_digit_count { + ($($t:ty),* $(,)?) => { + $(impl DigitCount for $t { + fn num_digits(self) -> u8 { + match self.checked_ilog10() { + Some(n) => (n as u8) + 1, + None => 1, + } + } + })* + }; +} + +impl_digit_count!(u8, u16, u32); +// endregion DigitCount diff --git a/vendor/time/src/serde/timestamp.rs b/vendor/time/src/serde/timestamp.rs new file mode 100644 index 0000000000000..d86e6b933621f --- /dev/null +++ b/vendor/time/src/serde/timestamp.rs @@ -0,0 +1,60 @@ +//! Treat an [`OffsetDateTime`] as a [Unix timestamp] for the purposes of serde. +//! +//! Use this module in combination with serde's [`#[with]`][with] attribute. +//! +//! When deserializing, the offset is assumed to be UTC. +//! +//! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time +//! [with]: https://serde.rs/field-attrs.html#with + +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; + +use crate::OffsetDateTime; + +/// Serialize an `OffsetDateTime` as its Unix timestamp +pub fn serialize( + datetime: &OffsetDateTime, + serializer: S, +) -> Result { + datetime.unix_timestamp().serialize(serializer) +} + +/// Deserialize an `OffsetDateTime` from its Unix timestamp +pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result { + OffsetDateTime::from_unix_timestamp(<_>::deserialize(deserializer)?) + .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err)) +} + +/// Treat an `Option` as a [Unix timestamp] for the purposes of +/// serde. +/// +/// Use this module in combination with serde's [`#[with]`][with] attribute. +/// +/// When deserializing, the offset is assumed to be UTC. +/// +/// [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time +/// [with]: https://serde.rs/field-attrs.html#with +pub mod option { + #[allow(clippy::wildcard_imports)] + use super::*; + + /// Serialize an `Option` as its Unix timestamp + pub fn serialize( + option: &Option, + serializer: S, + ) -> Result { + option + .map(OffsetDateTime::unix_timestamp) + .serialize(serializer) + } + + /// Deserialize an `Option` from its Unix timestamp + pub fn deserialize<'a, D: Deserializer<'a>>( + deserializer: D, + ) -> Result, D::Error> { + Option::deserialize(deserializer)? + .map(OffsetDateTime::from_unix_timestamp) + .transpose() + .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err)) + } +} diff --git a/vendor/tinyvec/compare_benchmarks.py b/vendor/tinyvec/compare_benchmarks.py new file mode 100644 index 0000000000000..86eb7e862a06c --- /dev/null +++ b/vendor/tinyvec/compare_benchmarks.py @@ -0,0 +1,30 @@ +import os +import os.path +import json + +comparisons = [] + +for (root, _dirs, files) in os.walk('target/criterion'): + for file in files: + if file == 'estimates.json' and root.endswith( + 'new') and 'TinyVec' in root: + path = os.path.join(root, file) + + bench_name = path.split('/')[3] + tinyvec_time = json.load(open(path))['mean']['point_estimate'] + + path = path.replace('TinyVec', 'SmallVec') + + smallvec_time = json.load(open(path))['mean']['point_estimate'] + + comparisons.append((bench_name, tinyvec_time / smallvec_time)) + +comparisons.sort(key=lambda x: x[1]) +longest_name = max(len(c[0]) for c in comparisons) +for (name, ratio) in comparisons: + # Undo the criterion name mangling + name = name.replace('_[', '<[') + name = name.replace(']___', ']>::') + + name = name.ljust(longest_name) + print(f"{name} {ratio:.2f}") diff --git a/vendor/tinyvec/gen-array-impls.sh b/vendor/tinyvec/gen-array-impls.sh new file mode 100644 index 0000000000000..234f771bccbc0 --- /dev/null +++ b/vendor/tinyvec/gen-array-impls.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +gen_impl() { + local len=$1 + cat <<-END + impl Array for [T; $len] { + type Item = T; + const CAPACITY: usize = $len; + + #[inline(always)] + #[must_use] + fn as_slice(&self) -> &[T] { + &*self + } + + #[inline(always)] + #[must_use] + fn as_slice_mut(&mut self) -> &mut [T] { + &mut *self + } + + #[inline(always)] + fn default() -> Self { + [ + $(for ((i = 0; i < $len; i += 6)) + do + echo -n ' ' + for ((j = 0; j < 6 && j + i < $len; j++)) + do + echo -n ' T::default(),' + done + echo + done) + ] + } + } + + END +} + +cat <<-END + // Generated file, to regenerate run + // ./gen-array-impls.sh > src/array/generated_impl.rs + // from the repo root + + use super::Array; + + $(for ((i = 0; i <= 33; i++)); do gen_impl $i; done) + + $(for ((i = 64; i <= 4096; i *= 2)); do gen_impl $i; done) +END + +# vim: noet diff --git a/vendor/tinyvec/src-backup/arrayset.rs b/vendor/tinyvec/src-backup/arrayset.rs new file mode 100644 index 0000000000000..22ea7cae94e1e --- /dev/null +++ b/vendor/tinyvec/src-backup/arrayset.rs @@ -0,0 +1,303 @@ +#![cfg(feature = "experimental_array_set")] + +// This was contributed by user `dhardy`! Big thanks. + +use super::{take, Array}; +use core::{ + borrow::Borrow, + fmt, + mem::swap, + ops::{AddAssign, SubAssign}, +}; + +/// Error resulting from attempting to insert into a full array +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct InsertError; + +// TODO(when std): impl std::error::Error for InsertError {} + +impl fmt::Display for InsertError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ArraySet: insertion failed") + } +} + +/// An array-backed set +/// +/// This set supports `O(n)` operations and has a fixed size, thus may fail to +/// insert items. The potential advantage is a *really* small size. +/// +/// The set is backed by an array of type `A` and indexed by type `L`. +/// The item type must support `Default`. +/// Due to restrictions, `L` may be only `u8` or `u16`. +#[derive(Clone, Debug, Default)] +pub struct ArraySet { + arr: A, + len: L, +} + +impl> ArraySet { + /// Constructs a new, empty, set + #[inline] + pub fn new() -> Self { + ArraySet { arr: Default::default(), len: 0.into() } + } +} + +impl> ArraySet { + /// Constructs a new set from given inputs + /// + /// Panics if `len> arr.len()`. + #[inline] + pub fn from(arr: A, len: L) -> Self { + if len.into() > A::CAPACITY { + panic!("ArraySet::from(array, len): len > array.len()"); + } + ArraySet { arr, len } + } +} + +impl ArraySet +where + L: Copy + PartialEq + From + Into, +{ + /// Returns the fixed capacity of the set + #[inline] + pub fn capacity(&self) -> usize { + A::CAPACITY + } + + /// Returns the number of elements in the set + #[inline] + pub fn len(&self) -> usize { + self.len.into() + } + + /// Returns true when the set contains no elements + #[inline] + pub fn is_empty(&self) -> bool { + self.len == 0.into() + } + + /// Removes all elements + #[inline] + pub fn clear(&mut self) { + self.len = 0.into(); + } + + /// Iterate over all contents + #[inline] + pub fn iter(&self) -> Iter { + Iter { a: self.arr.as_slice(), i: 0 } + } +} + +impl ArraySet +where + L: Copy + PartialOrd + AddAssign + SubAssign + From + Into, +{ + /// Check whether the set contains `elt` + #[inline] + pub fn contains(&self, elt: &Q) -> bool + where + A::Item: Borrow, + { + self.get(elt).is_some() + } + + /// Get a reference to a contained item matching `elt` + pub fn get(&self, elt: &Q) -> Option<&A::Item> + where + A::Item: Borrow, + { + let len: usize = self.len.into(); + let arr = self.arr.as_slice(); + for i in 0..len { + if arr[i].borrow() == elt { + return Some(&arr[i]); + } + } + None + } + + /// Remove an item matching `elt`, if any + pub fn remove(&mut self, elt: &Q) -> Option + where + A::Item: Borrow, + { + let len: usize = self.len.into(); + let arr = self.arr.as_slice_mut(); + for i in 0..len { + if arr[i].borrow() == elt { + let l1 = len - 1; + if i < l1 { + arr.swap(i, l1); + } + self.len -= L::from(1); + return Some(take(&mut arr[l1])); + } + } + None + } + + /// Remove any items for which `f(item) == false` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&A::Item) -> bool, + { + let mut len = self.len; + let arr = self.arr.as_slice_mut(); + let mut i = 0; + while i < len.into() { + if !f(&arr[i]) { + len -= L::from(1); + if i < len.into() { + arr.swap(i, len.into()); + } + } else { + i += 1; + } + } + self.len = len; + } +} + +impl ArraySet +where + A::Item: Eq, + L: Copy + PartialOrd + AddAssign + SubAssign + From + Into, +{ + /// Insert an item + /// + /// Due to the fixed size of the backing array, insertion may fail. + #[inline] + pub fn insert(&mut self, elt: A::Item) -> Result { + if self.contains(&elt) { + return Ok(false); + } + + let len = self.len.into(); + let arr = self.arr.as_slice_mut(); + if len >= arr.len() { + return Err(InsertError); + } + arr[len] = elt; + self.len += L::from(1); + Ok(true) + } + + /* Hits borrow checker + pub fn get_or_insert(&mut self, elt: A::Item) -> Result<&A::Item, InsertError> { + if let Some(r) = self.get(&elt) { + return Ok(r); + } + self.insert(elt)?; + let len: usize = self.len.into(); + Ok(&self.arr.as_slice()[len - 1]) + } + */ + + /// Replace an item matching `elt` with `elt`, or insert `elt` + /// + /// Returns the replaced item, if any. Fails when there is no matching item + /// and the backing array is full, preventing insertion. + pub fn replace( + &mut self, + mut elt: A::Item, + ) -> Result, InsertError> { + let len: usize = self.len.into(); + let arr = self.arr.as_slice_mut(); + for i in 0..len { + if arr[i] == elt { + swap(&mut arr[i], &mut elt); + return Ok(Some(elt)); + } + } + + if len >= arr.len() { + return Err(InsertError); + } + arr[len] = elt; + self.len += L::from(1); + Ok(None) + } +} + +/// Type returned by [`ArraySet::iter`] +pub struct Iter<'a, T> { + a: &'a [T], + i: usize, +} + +impl<'a, T> ExactSizeIterator for Iter<'a, T> { + #[inline] + fn len(&self) -> usize { + self.a.len() - self.i + } +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + #[inline] + fn next(&mut self) -> Option { + if self.i < self.a.len() { + let i = self.i; + self.i += 1; + Some(&self.a[i]) + } else { + None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +#[cfg(test)] +mod test { + use super::*; + use core::mem::size_of; + + #[test] + fn test_size() { + assert_eq!(size_of::>(), 8); + } + + #[test] + fn test() { + let mut set: ArraySet<[i8; 7], u8> = ArraySet::new(); + assert_eq!(set.capacity(), 7); + + assert_eq!(set.insert(1), Ok(true)); + assert_eq!(set.insert(5), Ok(true)); + assert_eq!(set.insert(6), Ok(true)); + assert_eq!(set.len(), 3); + + assert_eq!(set.insert(5), Ok(false)); + assert_eq!(set.len(), 3); + + assert_eq!(set.replace(1), Ok(Some(1))); + assert_eq!(set.replace(2), Ok(None)); + assert_eq!(set.len(), 4); + + assert_eq!(set.insert(3), Ok(true)); + assert_eq!(set.insert(4), Ok(true)); + assert_eq!(set.insert(7), Ok(true)); + assert_eq!(set.insert(8), Err(InsertError)); + assert_eq!(set.len(), 7); + + assert_eq!(set.replace(9), Err(InsertError)); + + assert_eq!(set.remove(&3), Some(3)); + assert_eq!(set.len(), 6); + + set.retain(|x| *x == 3 || *x == 6); + assert_eq!(set.len(), 1); + assert!(!set.contains(&3)); + assert!(set.contains(&6)); + } +} diff --git a/vendor/tokio-postgres/tests/test/types/eui48_04.rs b/vendor/tokio-postgres/tests/test/types/eui48_04.rs new file mode 100644 index 0000000000000..074faa37e23e0 --- /dev/null +++ b/vendor/tokio-postgres/tests/test/types/eui48_04.rs @@ -0,0 +1,18 @@ +use eui48_04::MacAddress; + +use crate::types::test_type; + +#[tokio::test] +async fn test_eui48_params() { + test_type( + "MACADDR", + &[ + ( + Some(MacAddress::parse_str("12-34-56-AB-CD-EF").unwrap()), + "'12-34-56-ab-cd-ef'", + ), + (None, "NULL"), + ], + ) + .await +} diff --git a/vendor/tokio/src/macros/ready.rs b/vendor/tokio/src/macros/ready.rs new file mode 100644 index 0000000000000..1f48623b8012d --- /dev/null +++ b/vendor/tokio/src/macros/ready.rs @@ -0,0 +1,8 @@ +macro_rules! ready { + ($e:expr $(,)?) => { + match $e { + std::task::Poll::Ready(t) => t, + std::task::Poll::Pending => return std::task::Poll::Pending, + } + }; +} diff --git a/vendor/toml_edit-0.20.7/.cargo-checksum.json b/vendor/toml_edit-0.20.7/.cargo-checksum.json new file mode 100644 index 0000000000000..06f5d5674c6fc --- /dev/null +++ b/vendor/toml_edit-0.20.7/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"6738efb0ffbdf9c0dc3f063a0c6f707e3f80c34c4f0b546a1857f0fca461a77d","Cargo.toml":"a28b5bf79c886e89947176303ea0b3cc28d6e2e10fb03c8faa90e95db23c0788","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6","README.md":"6222c7f42444de756a5987bf506f687b093d1596278a5858c49fbc0c27d7b8fd","examples/visit.rs":"657756caba28aa87a8b10104aba704fd2365579c57a293bc572a8d72173ba174","src/array.rs":"cd672b463152822d673868cc4c4cf28d719ecc7e224399c59a3f51b9e535926e","src/array_of_tables.rs":"a4c391b2dedd475546159fec824e2cca5f32e4e684fdf02792f645d2162881ed","src/de/array.rs":"7969d28e98e366cd16c9ed74128404a147a2b787c54d0450594811a92d17b310","src/de/datetime.rs":"a29e76372fc382686c31ee93fd54c749ea3d775c8d4fcc2b2643f9464ea23730","src/de/key.rs":"0b4c60586421a0c7b64ce93d41717823d93aadb99ff360169f7e68ded8eee9e2","src/de/mod.rs":"b7344ac410b21b2c82eb88782f48979d6f850a778a19bb2eea7228e834374d2f","src/de/spanned.rs":"5c959639bf4b3d19c6b18e625a57b28b311164bf7b191bbc4d30aa97b7239679","src/de/table.rs":"b1f0f95ea502126b8707ba945596f3c47d83d46680622899334567df1b58df1d","src/de/table_enum.rs":"ad3aab5169d6ddb2e7cd50a4dced4ee2485b11388876474969137b12fe6ee1e0","src/de/value.rs":"57361229d150b5885748d079d7295e48d751506b9662b2cd2c623da331c3bb45","src/document.rs":"7882374aa62978cac3752f346253399f281121a544927feed2882ed9a008361d","src/encode.rs":"489429163f822509116f3ecd81c3689df1fc642b61154482ed77bcd658027416","src/index.rs":"34ed0a4cc0cd55ce29885ed8123cc7c09c8ba3b9aa8d3b0b47554c1a41d31577","src/inline_table.rs":"d53af5947f05f4c8bf9338349e4cf521a21a2d4a3316d40f4c945161cd47ffdd","src/internal_string.rs":"8c84f94363ed012eb7114c6b3f6b371155d0ce740ce44ec9d315aedf048c1d11","src/item.rs":"57367ddb01d1dbfbf385634f0ba7d3ef2ee53d453ff19d52561ed16feb73ec3b","src/key.rs":"b6577a803b818e2010134615bc8cf93ff3a03d7097f29cba7a6b98306a81fdce","src/lib.rs":"3ff2ffd3366e495278fd7b3118ea54b7d09534380396a75b46c409e3c563c67c","src/parser/array.rs":"c8c2e789ce082cb617c11e28f07cfeed3663966f608b9b3d76a57aa321b898d5","src/parser/datetime.rs":"9c4d968e0aa57a82b836492c23e902aa20d888766832d680781cf5b2539e607a","src/parser/document.rs":"0b94e7e0bd53606949d66bb6854bf275bed399b869bbce18d6acbd65238de112","src/parser/errors.rs":"cb9bd80789c16d33d5aa2b2334b193108615846a6a548bba498df450754739a6","src/parser/inline_table.rs":"3c2bedc892618ba25ef241fcfc190b874490e4ae8a87a39bdfb4f5243de2fde9","src/parser/key.rs":"ab7dacec7dbb3f6c5872f1bb8da9db3a5500f46a7685bb5c48414c6644977fb0","src/parser/mod.rs":"08004fa6b4751a20d1b963b3c3c06bbfe05c13d342a1f035cc76de6b9bcd333e","src/parser/numbers.rs":"dbdfa6b75bc960642bb66ff3cedcee836a4ef785a6356cd2a58dd7f2d09ec40d","src/parser/state.rs":"a4bf5972b71320deff2e38937490d83eebd69b930ce6a2ee354f6714c52f6f52","src/parser/strings.rs":"192749d3f5e04ed8c3add16624f430d52576bad2424c92a61bddd81994cf5ff3","src/parser/table.rs":"c716d82caed27229afb22e757cb14b2828356fc69d33ab94d8f43043f992cd2b","src/parser/trivia.rs":"c2d9feaa958c339de82c6756a2e8ee749d0324db0c9890abc237fb213bf7b2e0","src/parser/value.rs":"645352f0e784aa1f744dde7e31f5039af51be8b51d887b22430189c56a719642","src/raw_string.rs":"dcec7da0aab75a5ff5891a0b4a22265ed47c17f9d802ec135e40f2bb1b0a7c60","src/repr.rs":"68356f3b89cd76b75bd9f78b6fbd31fbcc96d8195a7118d286dca92950adaee4","src/ser/array.rs":"5fb55303365bf6991f7af523931d1a046e88d3125c099317e12a7d4f592321a8","src/ser/key.rs":"9bad3bee90876c5c54aaa5caee92bfe30d79a100615902118b35b3ceb40b524e","src/ser/map.rs":"148423fba5b370335f832b2f6851adae29f4cf90dd05ace562e44cf2bf071aa2","src/ser/mod.rs":"5f5d0d7e7e2ec0c486e90ece7a1f5bbf166da640b1208365d89536d6616fb74b","src/ser/pretty.rs":"9a9f6d43b2eab487de8af216b9950c93318c9ee6a91f4707ffa41e2ee492c902","src/ser/value.rs":"3bd14fc54ea343cbc04a5b74461aab0eb1043b558cbc58bd02a7d08bbc020ee2","src/table.rs":"bbc24b198bf6298072a73d520f58b323dfe64ff4651383d12aad05fe953d26ef","src/value.rs":"e5f8ae9f9707a77dfc0192d141661a7126ce694ef2d52cc33727e93629762453","src/visit.rs":"34b49c3091a6ef7c1513429f8290c26989da25cec496d3993abf33fa65ebfc58","src/visit_mut.rs":"b184d7bb94038fdc2e0fee8689112f01377d9f8c05ffafb8a1f5f2263e80ee27","tests/decoder.rs":"8093389d542f50974d6a606321b0413941709ac2cbdef48934b60088bb21e3a3","tests/decoder_compliance.rs":"d804ef45b0498869d05ac5c1216dc29e94963b2ec4f814e867f0fe8b71e9c639","tests/encoder.rs":"c84dd8e14ade77a4d55f932418567196e188fe65d3957408b9ce07c2c27c4da0","tests/encoder_compliance.rs":"ca696031cb8f664728521da0370eb78e0351a5ac7134ad6cb12bc25f85757c97","tests/fixtures/invalid/array/array.stderr":"db4f1f06909589f9cb49d6657b6c39444e53b4ec8c4d3f0b9704ab5beaf68d2a","tests/fixtures/invalid/array/double-comma-1.stderr":"db4f1f06909589f9cb49d6657b6c39444e53b4ec8c4d3f0b9704ab5beaf68d2a","tests/fixtures/invalid/array/double-comma-2.stderr":"da4b8df6dbc2ef41b7b1b08b65a160ba37d07dec0c1ccf4184d6381a857b8762","tests/fixtures/invalid/array/extend-defined-aot.stderr":"a9dec506541bbdb96725d9f989572c10f29a52eb4e167fadea8929d7b6729b7b","tests/fixtures/invalid/array/extending-table.stderr":"a6c077cb49c41a9d10aca0bac6c571e570f0a772c6311d6a835f9cc46f4ab7cd","tests/fixtures/invalid/array/missing-separator-1.stderr":"98773b4d82cc32c0f8d1d8e6078109f7d9655b13d58e4b62fd22cef9f9ad725c","tests/fixtures/invalid/array/missing-separator-2.stderr":"eb38b2683f119d8b9b8c6b8ffd46da784112565ef1033febbe59469e14baea76","tests/fixtures/invalid/array/no-close-1.stderr":"a02ff4b3edf627873f0cb1f4242305f6a9a032b6f897fa13b8070c1a9ae85afe","tests/fixtures/invalid/array/no-close-2.stderr":"dfac1f12f502214388deecedf7a9720338ffd13b3184178410581e242ba8124b","tests/fixtures/invalid/array/no-close-3.stderr":"1930ad00952820805e208ebaf1ae3df243f492b6b2924bbfffbe458f31d89b29","tests/fixtures/invalid/array/no-close-4.stderr":"198293e991ab522435e383ef906f0594a0ea8126c792db934eba142369189e1c","tests/fixtures/invalid/array/no-close-5.stderr":"279aa5db5d92d3e729fe326321d2d217ff33db3c5e2bc2a5043909fc798c226e","tests/fixtures/invalid/array/no-close-6.stderr":"ccd74b7a7c01bb96a748c0e797f6207f0314d76520e4c1d1a9cde076e2284216","tests/fixtures/invalid/array/no-close-7.stderr":"9c6ab0c93fcf0c9ff7fdf8bc13f3b62864305509b80659c225a55641133abcf5","tests/fixtures/invalid/array/no-close-8.stderr":"c4b7fe79f9a354152c36e130af4862c47908cff3c84ba9be8bdbe76c35d9c6af","tests/fixtures/invalid/array/no-close-table-1.stderr":"545ad4381d5a007a6cd940a4523ae2f629617d298611c0898283a1c4783604cb","tests/fixtures/invalid/array/no-close-table-2.stderr":"5a2b4bf9026aa20c749551cd77458c5ffba008b5b235fa05fb7c756917018eb8","tests/fixtures/invalid/array/no-comma-1.stderr":"7d2f2923638cecc2f89e8ff1334a9da44fa7e137bea12d5019ef25f576f015af","tests/fixtures/invalid/array/no-comma-2.stderr":"d95a7a43534c632efa2502e3b5f8eedabf2f05ad6bfdd68e2f9fd3d8a22ba028","tests/fixtures/invalid/array/no-comma-3.stderr":"ae8ec653f564b247644854fecf59e097cc32e445aa4775aed8d18a207af5ec45","tests/fixtures/invalid/array/only-comma-1.stderr":"6f35677e711812007adc9a59341bc62bf2b7bcec80a456d19a2468ea8fd27b47","tests/fixtures/invalid/array/only-comma-2.stderr":"9d0017e6798574bd85810e64816ddfd08ccc36e25153006958fe023e2a007331","tests/fixtures/invalid/array/tables-1.stderr":"f105a34c2d87b61160881eeb09b7f54d244ba2a222d32fbfc755091939942247","tests/fixtures/invalid/array/tables-2.stderr":"77010599d1d61a34119a99acea7d84162d217df93bca01aed3ae73f1eb62dafe","tests/fixtures/invalid/array/text-after-array-entries.stderr":"391ee42f4fa3a7ec51ba1b90e69f1d9278c105426fe66ae1f80e65d7fb6ed379","tests/fixtures/invalid/array/text-before-array-separator.stderr":"7292ebcb8c9c8aaa4041279af5414de3e710977cac948988cdc8b0947223b62b","tests/fixtures/invalid/array/text-in-array.stderr":"0486e3ec5d299e39c61380a2ed8826d886edb730f6d9555a765e4314da7f5b68","tests/fixtures/invalid/bool/almost-false-with-extra.stderr":"d489307ba1d0a3dcd1bcff067437f0cde1521c6fddb1311bf396468521eabe81","tests/fixtures/invalid/bool/almost-false.stderr":"399829efe867bedbcef2ad2073df621f8297877180f71c6292209426da7b09dc","tests/fixtures/invalid/bool/almost-true-with-extra.stderr":"439c66bbdcdd335cb858f3cfc692fa3a78f7802591954909fb6807a62440d334","tests/fixtures/invalid/bool/almost-true.stderr":"3aed4e8704abc2099d8a881ee496a868c4745a0cfe7df781de613016543f4313","tests/fixtures/invalid/bool/bool.stderr":"d489307ba1d0a3dcd1bcff067437f0cde1521c6fddb1311bf396468521eabe81","tests/fixtures/invalid/bool/capitalized-false.stderr":"09c2b3b51460a52bc274c5d0b08024c76ea3dd7e067ef20765cc56d2a4f60087","tests/fixtures/invalid/bool/capitalized-true.stderr":"d0fa94dc8a4fb0f17550052fde5e10134e8ccbc84f1e90093446f1cb99f01a70","tests/fixtures/invalid/bool/just-f.stderr":"5f6a3a206bf49fb5eade446dc8f432037a4026f49beac01e453fd8c3610901b2","tests/fixtures/invalid/bool/just-t.stderr":"175bdb4ffa7259c5bc346fb088de8545e8e1d8254d1e2ac0d33c16b539e2270e","tests/fixtures/invalid/bool/mixed-case-false.stderr":"9de4d4b695614f3593abcb27a6f68ef5c578a96bec01472607c35cde28d48b10","tests/fixtures/invalid/bool/mixed-case-true.stderr":"45e314b026b819d568350bb62a39a2e5fd970acaf0a6591539d043abb9dee629","tests/fixtures/invalid/bool/mixed-case.stderr":"927b85ba3c3084e925cb8959c07d42f9f19f4ca8f84d7dd6babf15f1d9a1048f","tests/fixtures/invalid/bool/starting-same-false.stderr":"7e0f1f2d8ae538a5b156da19be0630d25e0d2dfa44bd97cdb125bf3e042df7d3","tests/fixtures/invalid/bool/starting-same-true.stderr":"bdf30c50dcc0ff8c928e753962f6dba7acc6f945a2958e0b03e690a126270ea0","tests/fixtures/invalid/bool/wrong-case-false.stderr":"811f36bc4df7755c3850b4e933e5436fb54183ac7fcf3599e8373d7545be1c2c","tests/fixtures/invalid/bool/wrong-case-true.stderr":"90520b03257419ec4a826b7f989e5aa74314a0aeeceaf6bf1873e867715495a6","tests/fixtures/invalid/control/bare-cr.stderr":"568eff61d56bb362866973d9a7a488831b8b08d02f4808538a04b22ebe10bf09","tests/fixtures/invalid/control/bare-formfeed.stderr":"86ebf66dcdf202fd832d91892b4b62eca65957198cca9567b10f3400997e9f90","tests/fixtures/invalid/control/bare-null.stderr":"e6bf2df7229c8632a1c7bce682914166520216c2d6c3ccd4c2e716dc700d5bca","tests/fixtures/invalid/control/bare-vertical-tab.stderr":"b85c55e64c58b85343482dadcd5d833fa771a79e1d0f13a24f4185a4d0d826d5","tests/fixtures/invalid/control/comment-cr.stderr":"3b334037fc70762903ebc2c3d0786554bb62d9f146dc801e07841ac7f8370e78","tests/fixtures/invalid/control/comment-del.stderr":"872065efcbcddffab0679160bbce0c8e2519ae7ccb8b4b667a8b78c4bd13522d","tests/fixtures/invalid/control/comment-ff.stderr":"bdcaf413adee168eaee3a7723b2939fe67e59914a834cbc559902eb94e4ca02b","tests/fixtures/invalid/control/comment-lf.stderr":"898787080f260e05ca20e6982ac4cce5572a6ed84a9244ce07a41f710db9a0cf","tests/fixtures/invalid/control/comment-null.stderr":"bcc48727ae370e45918682d6a17bc680b126d4792d4a33524c802f45cebc03d6","tests/fixtures/invalid/control/comment-us.stderr":"37d7a6c0a28989966af74530c2885bfc7ba6ddb31b58bce3f26543e34043b88c","tests/fixtures/invalid/control/control.stderr":"6ba75c9dbd0e03531f5a5ead2cb781a702d3600c76b2a4cf1bf7c02c1c9aca1a","tests/fixtures/invalid/control/multi-cr.stderr":"29fde9a540e77ed46dae0a227b666a9c102d5263cc5cac811e0e451bd403ad91","tests/fixtures/invalid/control/multi-del.stderr":"79f0d85f5b44a7dcad9d98adbef25b6ce54bb6dbf79ffcd3ea230a07144b4b82","tests/fixtures/invalid/control/multi-lf.stderr":"8c95b2a7b4e20dd8985e04b8da5fb9d7cbff37220a74fd3903f16f7ea7eaf39d","tests/fixtures/invalid/control/multi-null.stderr":"9fec8ad3ba45ddb96ad3b6a118b4fa648056e26a9128528b2c0a8fa3b01e741c","tests/fixtures/invalid/control/multi-us.stderr":"3a59d615cb91172936acdc42baa39e9faf3a2bb9e9078d9879a54826ffb6b20c","tests/fixtures/invalid/control/rawmulti-cd.stderr":"a71dce0ac9a79209ea173f3d656b2d663c685b47841b620cc89860fb68f0cf0b","tests/fixtures/invalid/control/rawmulti-del.stderr":"3b99e52cbec29c7b6b439bcf3cd58b85a72487e2f5af5e829dd6986b3414f49f","tests/fixtures/invalid/control/rawmulti-lf.stderr":"89fb9c7d02e39ff648cea46ec1086058016c5ef1deebc6f3b106664dc4d10eae","tests/fixtures/invalid/control/rawmulti-null.stderr":"84c04cc89a6bc716b6f7811142899014abdb0b49c4ea56bc163c19220b14c323","tests/fixtures/invalid/control/rawmulti-us.stderr":"ac53d1dcc96c3beb454f5474a23940f26c93705b76a10647c810f79facf4f6be","tests/fixtures/invalid/control/rawstring-cr.stderr":"fa8da523c3cc24384fda1dd6032607cdd380f45133ce7d6d2a1d3b8a3eb6a917","tests/fixtures/invalid/control/rawstring-del.stderr":"64378c4341fb92376e2fe8a70356411759b8659e151ed0ca744751c8b2d32155","tests/fixtures/invalid/control/rawstring-lf.stderr":"43f6431efef7ead5aa335958187d979d98dcced50cb82ccca19df34397278175","tests/fixtures/invalid/control/rawstring-null.stderr":"eafa2a63e9d12293b290405049457860a8fef70de56c4ba2f203e5f2c79a8634","tests/fixtures/invalid/control/rawstring-us.stderr":"d139a7ec7c4ff5358f6c56ea2f2e431646f5ae9bf3d927694a2aa3891637ecb0","tests/fixtures/invalid/control/string-bs.stderr":"ce6634df580f80e090749d31c178bed74b88718befea7788abe801acf4af10ae","tests/fixtures/invalid/control/string-cr.stderr":"a8dfbe00e976920a442f8f03bebeb31bbdb570a242e380b5a4c60d351614acf9","tests/fixtures/invalid/control/string-del.stderr":"bd862371b7a698647d4d68e5c3bad5c269bd8553f36d82301ffc62a4508334a4","tests/fixtures/invalid/control/string-lf.stderr":"18a1d0e1bcf6f99c80e95e94097f95722a65c2d8a415f9497b808b0bc135c12d","tests/fixtures/invalid/control/string-null.stderr":"fe34d284c478853bad94235aac1f37ac3c591f97e12990847b5da0b6c99bd47d","tests/fixtures/invalid/control/string-us.stderr":"06f7fce918057f567803f370e55e035896bb63a97eb0c0c39a680d6b927fead8","tests/fixtures/invalid/datetime/feb-29.stderr":"898cd0c4cd094247fa0825d02179d3b913cc9db4fbe634fa84c7a7d2cfb7b03e","tests/fixtures/invalid/datetime/feb-30.stderr":"0fb2c5f14857fe5edadbc93a78208c1c9ed900a18e3296613cc620e255c76e11","tests/fixtures/invalid/datetime/hour-over.stderr":"bd2220bdbaa96caf3d2aaff640620e4856bffb722a0e5be61dcb5283ffd08056","tests/fixtures/invalid/datetime/mday-over.stderr":"de9d27d65c68dd09da10c229167ce881dfe0ebda457badfe24b7598ae80c47a6","tests/fixtures/invalid/datetime/mday-under.stderr":"18daf3ce2a6a972476ccabcf92690a488e4f3be804dab8458da2aebad22a2c8c","tests/fixtures/invalid/datetime/minute-over.stderr":"a29009d3f7a6b1d9afad2420f223d6a6e02df8149577547837f5eeec4075bb9a","tests/fixtures/invalid/datetime/month-over.stderr":"37a203b22c3b2510541e413ff347447f9f3319a896ee005b96f65bc0d68150f4","tests/fixtures/invalid/datetime/month-under.stderr":"24c554595ca9a999a1d8e1ef7dc28b443f2f0ad6e17337ee157fb18bdcf678c1","tests/fixtures/invalid/datetime/no-leads-month.stderr":"2e20cb60a1ecee85b172d1402e4d8c425362e4db607706bd39494385dc6dc98e","tests/fixtures/invalid/datetime/no-leads-with-milli.stderr":"a35c496884e921aa086c1404bc812ff74f2bfd347a3ecd96640942be5555afbb","tests/fixtures/invalid/datetime/no-leads.stderr":"2e20cb60a1ecee85b172d1402e4d8c425362e4db607706bd39494385dc6dc98e","tests/fixtures/invalid/datetime/no-secs.stderr":"65871ee020e645e737c363b22cf43c160b295871cd4ac97a37d3ea46f60e3250","tests/fixtures/invalid/datetime/no-t.stderr":"ff50b85f6bc0d49000ec6f1303fda9b44bf934c2ede61743363411bbf6ebecbb","tests/fixtures/invalid/datetime/second-over.stderr":"0ed555a874efa08b711b5227501208758d87a01ad8360cf76c3dc8761807fac4","tests/fixtures/invalid/datetime/time-no-leads.stderr":"b3282cb32386dd84a35468f488be5a92dd3488e951f9dd2ea39057046386b73e","tests/fixtures/invalid/encoding/bad-codepoint.stderr":"1a816a8cdd5c2c9b8ae10431d981e22c3b307e30ef3d401ab62ac1012240be44","tests/fixtures/invalid/encoding/bad-utf8-at-end.stderr":"518dc443f0404d486b40bbbd152870276016795b05f3cc8a1de64a0e08fcdda2","tests/fixtures/invalid/encoding/bad-utf8-in-comment.stderr":"e0f252d14c18ea072c098834997db8e5f68b807bb0fa6d3d34e4042a5ea6fbb7","tests/fixtures/invalid/encoding/bad-utf8-in-multiline-literal.stderr":"2328a89cd9043de10ee656f4ea0dd5e6491fd8c0484ac36099c23161dd7a2625","tests/fixtures/invalid/encoding/bad-utf8-in-multiline.stderr":"2328a89cd9043de10ee656f4ea0dd5e6491fd8c0484ac36099c23161dd7a2625","tests/fixtures/invalid/encoding/bad-utf8-in-string-literal.stderr":"eefb00fee073933fbdb95d24a9e7050c281d4719d0cb970c2c06a71a86f108b3","tests/fixtures/invalid/encoding/bad-utf8-in-string.stderr":"eefb00fee073933fbdb95d24a9e7050c281d4719d0cb970c2c06a71a86f108b3","tests/fixtures/invalid/encoding/bom-not-at-start-1.stderr":"bd4e557b8b4586cdb39a8fde46f0bb214954f9f8ef37be46e2cc19823f6d6919","tests/fixtures/invalid/encoding/bom-not-at-start-2.stderr":"27003a498cb355011782dc21f01e15457490b78c472bb9ddb54147413c8f597e","tests/fixtures/invalid/encoding/utf16-bom.stderr":"a8800edcb8f6184b712da53e74bb787c39eb891073575acbae1ad575f15043cc","tests/fixtures/invalid/encoding/utf16.stderr":"edb66c01034865f484ccf7921bfcec1efaa8599762cb9cd30c9c8103275bc4e6","tests/fixtures/invalid/float/double-point-1.stderr":"2917901dd186adc39cb5965faf388fa2babe577ef3bfcadd4919232868a727cf","tests/fixtures/invalid/float/double-point-2.stderr":"7eda489da0436d6f0f2268aa4005b422d215b4785af0c1696c8731908a563f17","tests/fixtures/invalid/float/exp-double-e-1.stderr":"e64082e328fcfbeff57e6801448c769b12bc8e879b77421b688b2e147e386713","tests/fixtures/invalid/float/exp-double-e-2.stderr":"5c45326ef7287ea16a9e08275222e281b5d61c9322f8764f6533707f9772e255","tests/fixtures/invalid/float/exp-double-us.stderr":"ebd30aa3f7cd3a0a5e79bbbde1beff209d24f4ab58eb5552c1baf0eb2194e97b","tests/fixtures/invalid/float/exp-leading-us.stderr":"19c8f676dd45a5db09bd5baba5c3e7b661e83099a340331ee6bb10defe679569","tests/fixtures/invalid/float/exp-point-1.stderr":"23e73e4e63db888546866967a1c0319a1db269f23ee9c277b298e9f2db88800e","tests/fixtures/invalid/float/exp-point-2.stderr":"633328e085fb04d6a79cdfb696f45a1836c3a8b6afafc4cd5e16d48465aa4613","tests/fixtures/invalid/float/exp-trailing-us.stderr":"aaae81eba820233944bb88920621dc9c1bbd0d1a1476c0376a38d0491a30c83e","tests/fixtures/invalid/float/float.stderr":"cc664d16849deec2ae7ebee6a3f46923bd5959075e282315c4f60461cdb13a0f","tests/fixtures/invalid/float/inf-capital.stderr":"1451a322f3be80529ebc091d231b682127e783a07cfffcce67f5b9bb4455c0c3","tests/fixtures/invalid/float/inf-incomplete-1.stderr":"38cd906dfee7f13b8cbdb27f3406ab0499fae3ae16f3c77bc7fc48d009595d93","tests/fixtures/invalid/float/inf-incomplete-2.stderr":"97a9ae1ff194a95b5be2abaf2cd8179ada832cdd9fad349efa9951e7ab92e435","tests/fixtures/invalid/float/inf-incomplete-3.stderr":"034bc609343ecf1e659d6250f719e5f93512e8140228e44e57b538765e58a1f7","tests/fixtures/invalid/float/inf_underscore.stderr":"621326dde26e5364c7af1b562fb651f4184d9b5fc9bc45edc12f52b588d506bc","tests/fixtures/invalid/float/leading-point-neg.stderr":"d19e28ba2f11069800df4dd1951025aa7f75425f7258e8caf4bbf6abe0e84bc9","tests/fixtures/invalid/float/leading-point-plus.stderr":"10750e9acccb17f0682db30fb175d083d06c822a4863d3d6b8ddb6c75b7b22ec","tests/fixtures/invalid/float/leading-point.stderr":"2545b7a615528595f5d53a7338403c83a8587e70600b1501225446e5f456c805","tests/fixtures/invalid/float/leading-us.stderr":"dc958138922097b2e1e3865c7818604b2249268af4acbe5cafe0ce8c68a90a86","tests/fixtures/invalid/float/leading-zero-neg.stderr":"d1fad35fa8d18f93ebfdf681d3476f02600e5c39cc942ca9bc36181476cbbe53","tests/fixtures/invalid/float/leading-zero-plus.stderr":"ad8ba7a7c12cb4b296cc0d43915106732e6a6a713aea67034587d1fc0c8093df","tests/fixtures/invalid/float/leading-zero.stderr":"cc664d16849deec2ae7ebee6a3f46923bd5959075e282315c4f60461cdb13a0f","tests/fixtures/invalid/float/nan-capital.stderr":"d0e9234b96d4e3591ca0190a785789f9bdcaaff01a111eb57db7bc458a2dd95d","tests/fixtures/invalid/float/nan-incomplete-1.stderr":"f4bee0b1c639bf800fc4dda38276142e715cd85ab6cc5e93ae2112ea63d7de89","tests/fixtures/invalid/float/nan-incomplete-2.stderr":"dc908ec577d29083bfd709fc4bdc2fa641d7fb2ba77a5d7441215680a8839d69","tests/fixtures/invalid/float/nan-incomplete-3.stderr":"abab5a41e0f2f1bad2d2050d0c913dfd8c15e50530d53ef8de327f106f564e02","tests/fixtures/invalid/float/nan_underscore.stderr":"25b67a7d6c743f673be7b409c9990de5de8b52a1d97c32e6f4e62f33147f1872","tests/fixtures/invalid/float/trailing-point-min.stderr":"69ad03ae81990d580a6d63bdd5ab594de00c0a16694c8671704c6243b4578b38","tests/fixtures/invalid/float/trailing-point-plus.stderr":"fba0bbad890020fe943e9f23644e81bf0bb7d114230fe16182e866fddcfc108b","tests/fixtures/invalid/float/trailing-point.stderr":"2f12b368fd94304ab0126ebb5888c519475f9ca28e9ca702c477cf0085ba9216","tests/fixtures/invalid/float/trailing-us-exp-1.stderr":"217939411cc9c99589d1ef0f3919c90ca2a562c0352063aae08ba2ae53c1208b","tests/fixtures/invalid/float/trailing-us-exp-2.stderr":"ecf0002a04040c8afcae7f4bb182c0322b4d00ab88bb53405e40c7938f2a9443","tests/fixtures/invalid/float/trailing-us.stderr":"506cb8051f1045ea1dc7f11865d58cbca0216502d273e1c10366c8be7cc9ab43","tests/fixtures/invalid/float/us-after-point.stderr":"fa9fb59f703b6770be3dc094c04eb2c4add8a7a7ab79d9fe508cfeee785404f1","tests/fixtures/invalid/float/us-before-point.stderr":"14e09a7a382e249e5143d1c81d6e4623408eb2d505e1e3f86c370a3a3bf6cd9e","tests/fixtures/invalid/inline-table/bad-key-syntax.stderr":"cc3565bdd7ce5752ed2e0aa6ca10e8a414d357a1f5630d7c759f8ffb709cc540","tests/fixtures/invalid/inline-table/double-comma.stderr":"2132a1c4d97fab140089818f990284333e22ef91d20a9f65e11d4dd15b1a701a","tests/fixtures/invalid/inline-table/duplicate-key-1.stderr":"72bea73b20005f15ced977aae70a1b0f3bbe3e35598231aca9a2303d770efdc3","tests/fixtures/invalid/inline-table/duplicate-key-2.stderr":"9b69c8521345fcc21886138d9dd0f20528c71712f3de3e565087adc916113a07","tests/fixtures/invalid/inline-table/duplicate-key-3.stderr":"675b84acec95eb5778a8d280881fd83cc3f741d0c0e2a21cd74fe1ab2b6bd710","tests/fixtures/invalid/inline-table/duplicate-key-4.stderr":"5ed3af9e2011f07a04572b2bcc1dd11dd57512dd35ff616e37051a34bd1f4a94","tests/fixtures/invalid/inline-table/empty-1.stderr":"604fef40337f04e5f37a52239d6509850aba95677a7a94ca8476a6c21b648a43","tests/fixtures/invalid/inline-table/empty-2.stderr":"870f189adbefaa6f05307d5b00748f1ae1c748d96105fabeb409c3c7d59126ca","tests/fixtures/invalid/inline-table/empty-3.stderr":"766b0f61a467c8db42514016a9a3812f678b054a124361bf7b7617cf2ae073db","tests/fixtures/invalid/inline-table/linebreak-1.stderr":"45b0611d37c1ece88bf6c88b3528adc3d73e0cd3e3b24dcf07ab151023a6f488","tests/fixtures/invalid/inline-table/linebreak-2.stderr":"f7672965326b44adaf0cb4796a087fbe779a8b17fbb458090a33375d0c54e5b4","tests/fixtures/invalid/inline-table/linebreak-3.stderr":"e8c70f0c91b15e701567e93d8df1cd3bec593696af05ec1d95e8f9e00ab20fa6","tests/fixtures/invalid/inline-table/linebreak-4.stderr":"3d31147f9e1ff5f94384e4df1675dfff2da6f076cb0a729771615f05b990be91","tests/fixtures/invalid/inline-table/no-close-1.stderr":"0bcaf312d65af22a37bdd8334821d95d4212dd43905fc945ec2c8ad3d465ae7a","tests/fixtures/invalid/inline-table/no-close-2.stderr":"4c6bfd3dd94611a3bc02fc609a738bc252dc38501e7ef6ff19543d757cc564e4","tests/fixtures/invalid/inline-table/no-comma-1.stderr":"9f1c85e0df72c7e7e011c26a0d5dd9dea8b7a5e18c3ba9a53ff4a20a9429dce9","tests/fixtures/invalid/inline-table/no-comma-2.stderr":"24a06e43a94ab041395eedb94c5bdb799ed7fbf6d930791756b0e3bd4a812943","tests/fixtures/invalid/inline-table/overwrite-1.stderr":"812d1bc74d07750048a521e513a565676e606d4fa1a32d2ebda7af8fa064d3ab","tests/fixtures/invalid/inline-table/overwrite-2.stderr":"bf95d34749254300f4179ed1314cc9cabd7c7b63fc2453fc7adbc7869b63be4a","tests/fixtures/invalid/inline-table/overwrite-3.stderr":"3e2c2ce66f1e4982aab428075105a39b2e9384f2dcf6da6d715017533416e149","tests/fixtures/invalid/inline-table/overwrite-4.stderr":"8aeb424d4ccee35ae17efba8acd65aba834192672cad73e8e1e6c3fe9f878826","tests/fixtures/invalid/inline-table/overwrite-5.stderr":"ff8facd04689f13ec53ee77bc9790d25e2d2eec50f4675788d70a2bf33a85e2e","tests/fixtures/invalid/inline-table/overwrite-6.stderr":"01be3b4e31d2c0aed381fc6599d5fd78d0757e9b76e66b087e4614e98f782db3","tests/fixtures/invalid/inline-table/overwrite-7.stderr":"52bac538099395ae15c5c8786f835dbab4748be0464951a25ae0f44aeea90125","tests/fixtures/invalid/inline-table/overwrite-8.stderr":"bbbc4b8959113590e9bc27526b56bae2e1223c88493836ea0a0df4209527a038","tests/fixtures/invalid/inline-table/overwrite-9.stderr":"1b084659999a2cf01ba8feab1d9d9232a307fae584e4277210cee69f53ef6cab","tests/fixtures/invalid/inline-table/trailing-comma.stderr":"4791911dafd6602e2891d6ffc4d32ef8e9d0c1f8f6d37e84d440feb896d9cb88","tests/fixtures/invalid/integer/capital-bin.stderr":"fcfc8b0bddd36a641d3f5cc2ceee88554619fabf6874e11cdfdd147be8781881","tests/fixtures/invalid/integer/capital-hex.stderr":"c8e2d64f9659435a0387bb7e6447896eda253fef77e0214a4073fcffbac693a7","tests/fixtures/invalid/integer/capital-oct.stderr":"ec465fa25da212b0c9b6265ac8e9cd05c1fa07d614dafb3bc9b2ca74d6c2a7a7","tests/fixtures/invalid/integer/double-sign-nex.stderr":"8d57da526240c1cf73423b688442922ae291ff26e3c09f9c3b5b150e62e5cbaa","tests/fixtures/invalid/integer/double-sign-plus.stderr":"55896d9bd19637e124482966a12109a1a8351620ddc6f8d28553d70359f523f1","tests/fixtures/invalid/integer/double-us.stderr":"f14ed7bd3ad26b2203763fa953dd6e99212e50fb8e43a4eaeb115c1a7df4fc25","tests/fixtures/invalid/integer/incomplete-bin.stderr":"64168fc7ede87a10c12f82325fce644a7d9b9c3af55a313184175df7926845e3","tests/fixtures/invalid/integer/incomplete-hex.stderr":"ed2423540e288f4673bc68822a799bea04f571db5de56154e10360b03ab79553","tests/fixtures/invalid/integer/incomplete-oct.stderr":"9ed35e3078703a38996f20dc3e86477149564c8abd237c644bdf3a5ef26e3417","tests/fixtures/invalid/integer/integer.stderr":"ed5ef991b733b3d51700364da18bf58f1b7eb68053467afcbff22775b3b82788","tests/fixtures/invalid/integer/invalid-bin.stderr":"7248d47f2c7db309254a3a41af28bc1a6e96bfa95e0c8c94d607f65a1a30cee6","tests/fixtures/invalid/integer/invalid-hex-1.stderr":"ca2af571a835ca976727c823939f7cbd6d36f7d048464ba1f8f0bc6b6558cb57","tests/fixtures/invalid/integer/invalid-hex-2.stderr":"e2970d46eadb852d34a8407929972acf7ef131c3c44978af0e6dfe205a6e993a","tests/fixtures/invalid/integer/invalid-hex.stderr":"3976255c6fe35a1e29f0fed7324eee8420ababd0f6f1f7702908c3df47c88846","tests/fixtures/invalid/integer/invalid-oct.stderr":"9f6776e33887cb446a5590d8fe4e51c36747c634cd5e4efaa84f807d3ce244e0","tests/fixtures/invalid/integer/leading-us-bin.stderr":"0cb1db77dee877423738395a720e6ebbd5a545a3b22ce710ab669b5b1f7903f5","tests/fixtures/invalid/integer/leading-us-hex.stderr":"fec78f4fe4ad481fe9ea93465c8ef5bca8b98d0bba31b48b2990870b7aa5f44b","tests/fixtures/invalid/integer/leading-us-oct.stderr":"aad69bdd80f94e907bda03558a1302e54d58d8911fe2b564e93cb0ec48403b09","tests/fixtures/invalid/integer/leading-us.stderr":"3a265cc11f1b0d43d4b532a47776486ec7c7ea7afe70813ab00c5a37cf87a9df","tests/fixtures/invalid/integer/leading-zero-1.stderr":"ed5ef991b733b3d51700364da18bf58f1b7eb68053467afcbff22775b3b82788","tests/fixtures/invalid/integer/leading-zero-2.stderr":"5c70e7874256512c0ef6bb364497d4e10154e994056f2feb7c5c729016522091","tests/fixtures/invalid/integer/leading-zero-3.stderr":"fb2730feda6f669a3b8c4332f01369e52ce1b942807f1bf3d9762b1fea04aeac","tests/fixtures/invalid/integer/leading-zero-sign-1.stderr":"c9d2d992eea36c4fe228eb74741bd8d0ede1e354cad132b79462e7b502b37f95","tests/fixtures/invalid/integer/leading-zero-sign-2.stderr":"4248329b339020cc2ea586f2775a0b4f4cbe2ae3f0f75b935263363b8be5eaf5","tests/fixtures/invalid/integer/leading-zero-sign-3.stderr":"3b414808727d3a446efdfca0033525e17536f9b54104d8a9cb9278b054d213df","tests/fixtures/invalid/integer/negative-bin.stderr":"74aae673b861bd46544e4835fe7075e20158dd69e27f75c790d48a6006476c73","tests/fixtures/invalid/integer/negative-hex.stderr":"799bd8120f4cf2c36e7f65a5f9aa43a3ec87dd95dd3bf68501059da9f21f8c9e","tests/fixtures/invalid/integer/negative-oct.stderr":"017a6a24faf9dc1cde89f62b46435f8fca493e7b61f6fbd2b6d57f0f9e80da65","tests/fixtures/invalid/integer/positive-bin.stderr":"54d8a33743737f374480cd1235bf3f7e0847d252ef7e2bb1d447529cbc0f6692","tests/fixtures/invalid/integer/positive-hex.stderr":"3b21b23cc3dd6b213a19256f4ffb4bb36172de2f739f90bbea78636f7a50524b","tests/fixtures/invalid/integer/positive-oct.stderr":"f19faef5bbb7ed8351777bdededb1c523337f2aeeec82d967c19c36069790e11","tests/fixtures/invalid/integer/text-after-integer.stderr":"07a13ad4841a452eff00947234a4ebac4d209ea0294162888db35668648bb55d","tests/fixtures/invalid/integer/trailing-us-bin.stderr":"62da06cf06527b9e9cbeba6c5299ce6001d40592e9d007c8350090977f4d1b58","tests/fixtures/invalid/integer/trailing-us-hex.stderr":"1b290eada58a7202b1a9251afd8e0e72a4caa8ad5c85036d1050e7de8141e94d","tests/fixtures/invalid/integer/trailing-us-oct.stderr":"34e6f86ffb0099e6e1ba67deb51e36af62dfce4e7299b94503a219339bf16447","tests/fixtures/invalid/integer/trailing-us.stderr":"3ab49ee921eb772f5aa4eaf0fb3619b1dcd9a9db3f4ebbd9bc505581a985e753","tests/fixtures/invalid/integer/us-after-bin.stderr":"a94a87ebab3536899ce7c0c785f020b3a236c60d24c0bd7494628ca310c40768","tests/fixtures/invalid/integer/us-after-hex.stderr":"9009b187f615f06e3392eabd8ffa58311ed1c2b1cd76f8c5bd99671242f2e026","tests/fixtures/invalid/integer/us-after-oct.stderr":"05af70a21980416fbd602337f9af22a1c600a294635d10ef1ca1b2138338e712","tests/fixtures/invalid/key/after-array.stderr":"487d957b20226ac36e27d6efb1e3d24147284c9a5e10a0188427a1c940d31ef0","tests/fixtures/invalid/key/after-table.stderr":"f70e84770817f096fcc1b6195c6b0a79d25210c6930ce412a89646040ee3d713","tests/fixtures/invalid/key/after-value.stderr":"00d4d2d3ccd61f64a92df0ca575aeafcd96e91d053d835ca855973339ba458cf","tests/fixtures/invalid/key/bare-invalid-character.stderr":"b1f64d54a43017e6cc09755fa7ba477901721d23f9271ec658fc9362f46631b3","tests/fixtures/invalid/key/dotted-redefine-table-1.stderr":"59771f7163f28a3c81209f058b7b01d616fe5022e8ee7ffb395feb44129cafea","tests/fixtures/invalid/key/dotted-redefine-table-2.stderr":"564febb355d1556df42f428a046ac6fdc5dad49b2b736be5824b0c13fcd1fae9","tests/fixtures/invalid/key/duplicate-keys.stderr":"7c9dfef2ef19b1487b7592a267ab5ba21c8b833dfa9ec1c3151e369c2fdba26e","tests/fixtures/invalid/key/duplicate.stderr":"764ef48bb06c9096c853b1156c8d29ba0065616939a5335146f5af88a424cea3","tests/fixtures/invalid/key/empty.stderr":"af6d3636ca73e5496c40d9c918c59b61fd86812db262649e5268094193873130","tests/fixtures/invalid/key/end-in-escape.stderr":"86b9c28ffc74797d35a89fee58853fa85bab9638b919138ccd5d8dd524dd204c","tests/fixtures/invalid/key/escape.stderr":"155aa9389f0eb28cac3b42974af7ea9e2eef8d96f084f08f9f75e960fc8ce8c7","tests/fixtures/invalid/key/hash.stderr":"85dd91b96aa4f81cc7922b02b411f25d9053bddd1e5b893c2a2ee9d0115a7cac","tests/fixtures/invalid/key/multiline.stderr":"d625f2caaf01d53d72d6f1c3df0952fe3ca8c5f3b081503cb02b9994c088b733","tests/fixtures/invalid/key/newline.stderr":"714aed0a140062f977ec85b9afa50f68448c67e806168e60b4f4554ab270b2b9","tests/fixtures/invalid/key/no-eol.stderr":"440ec927e94f0e520a0f256c865041f0478e1c82f3bb79323b7ddc36fc942edf","tests/fixtures/invalid/key/open-bracket.stderr":"3b36814373f51a8ea00a448d65bc514e8d99f5163b7dd8101df62bcd0a06e801","tests/fixtures/invalid/key/partial-quoted.stderr":"dc9059a014ed53071ed170b1e280923556dc09e0be2ae96cc8474e9da59fa378","tests/fixtures/invalid/key/quoted-unclosed-1.stderr":"6cdec8a7c5352a2f246273afaa923dfa81d4d2e68cca5b4f9a19193559b164c2","tests/fixtures/invalid/key/quoted-unclosed-2.stderr":"b4817e6f85a90fbb6adf049ba57c268f9888f1b42b3d62200c359606176170b1","tests/fixtures/invalid/key/single-open-bracket.stderr":"917c0203d1e45309fcff82ce33fdd2d989f630fb99290a40cb9e08a6f7ca0ef8","tests/fixtures/invalid/key/space.stderr":"3a5fa712d667890678873e3d4e4cabb084c67091c5ec6155355d5bd4229585dc","tests/fixtures/invalid/key/special-character.stderr":"a84c2f293c1e421a1c87050cb0211de80dbfe7a79939db0338fa35bf0c181ef2","tests/fixtures/invalid/key/start-bracket.stderr":"223d8a22bf34459cd9bcb993ae2a51ab3cc436674e3367e92f7d74e9f8710a45","tests/fixtures/invalid/key/start-dot.stderr":"f9366a1492ae24fd0721724b4039d2675e91219de564aff2826adefd83fac571","tests/fixtures/invalid/key/two-equals.stderr":"a0aae899cfa75df41104a4d3090a309fc7ebcd95bb5a944cf742f3d3fc9d4782","tests/fixtures/invalid/key/two-equals2.stderr":"861826b9456ab3a74f63f5c555e13d959a3991dfa6ce126ae5ed14d43f7dcee1","tests/fixtures/invalid/key/two-equals3.stderr":"71614864344e321ac5de238b7ef9d097c6d7f3ac3eee4118d96827b4b8bd6658","tests/fixtures/invalid/key/without-value-1.stderr":"16c2823a39a82c3c27e0959a691b7a95e3392d62195884697893d373b967b9c0","tests/fixtures/invalid/key/without-value-2.stderr":"d340f94f5d96f5730ab269db7ef27aca171d64e35af1181c474d75a7d11d6590","tests/fixtures/invalid/key/without-value-3.stderr":"3cf3072fe9206bfe6c682103d0414627a5a63db4c4a319cf37efeb5fe6b92007","tests/fixtures/invalid/key/without-value-4.stderr":"07132bec96e9a9a672bafdc3c448b7c596257245f8c3e2cae04641f9798644ec","tests/fixtures/invalid/key/without-value-5.stderr":"37dc02af5ab8a30161223d44ed05c99ba742a658598a1b94ff78ed09afd9b11b","tests/fixtures/invalid/key/without-value-6.stderr":"00b623259f9c58fdfbe6753978fe2a71653bed0dda5c4ce54cb2151e8f7a6a29","tests/fixtures/invalid/key/without-value-7.stderr":"5013036b7f53013f887f670c3a3ceca6358d89e6b83b27bea9aa4447fba083a4","tests/fixtures/invalid/local-date/feb-29.stderr":"49fc14bfe63430553b173e82b84fb964a8bd93eeaf8abb28ed94f92a061e0026","tests/fixtures/invalid/local-date/feb-30.stderr":"1ae91b3300919e07b64c5c5b6572be05dccba63854df52ed71a900d190a90900","tests/fixtures/invalid/local-date/mday-over.stderr":"851f565b0537d5f2d88829c62d632d7dc5841d9843a1244568ea7382d5b05857","tests/fixtures/invalid/local-date/mday-under.stderr":"34c1e1d9e5839a2a8ccfaecbf52b3f49e1a776cb17de9187c3e79cb618ac684f","tests/fixtures/invalid/local-date/month-over.stderr":"d6ec78690f874b4c99cde7e609775abdf4f00ba758216afee355f6baa2c7c010","tests/fixtures/invalid/local-date/month-under.stderr":"c6922666b726822f6ffeca857041eec16cf387f54d3b6d9c325935c1c116aa5c","tests/fixtures/invalid/local-date/no-leads-with-milli.stderr":"03ff73112eae42e69f54f80445582775309400ce7f179bd9d28043299d5da826","tests/fixtures/invalid/local-date/no-leads.stderr":"12d98e610ca2c2e04fff563f9ba2b12f5e53937df1ced544c8082fa4f64522e0","tests/fixtures/invalid/local-date/trailing-t.stderr":"87a15cd62bbe7cba2b942fe424c045ce30a12fe439a1b49587a5cc037ffa6b09","tests/fixtures/invalid/local-datetime/feb-29.stderr":"692c0e78fd9ee1e979dc32bed3ed9d3d10a4608090b4d242e379d40a9732c2ab","tests/fixtures/invalid/local-datetime/feb-30.stderr":"330e20a8e3d95195227c3e66861f013b70fc02010107c9d0a11085bd533b49cc","tests/fixtures/invalid/local-datetime/hour-over.stderr":"a095bf7be4a76d0c9362d5e4398d5783aa1545ec03f910a2c6a1709a3f60225c","tests/fixtures/invalid/local-datetime/mday-over.stderr":"cd707915cf15690dcc65868408f115bc90da19beae1fbd0a7fce8d02ce76300d","tests/fixtures/invalid/local-datetime/mday-under.stderr":"fd8ac4e2804d96d6b7f63eb1616096bdcc3ecc2b74d75c3fc4bd98f2f3af205b","tests/fixtures/invalid/local-datetime/minute-over.stderr":"95fef6b0821ffe465ea5ce27a4f1521a4309cc64ee03e2781e63ead3003cfc62","tests/fixtures/invalid/local-datetime/month-over.stderr":"f739e1cb0538ab5e3cd0923165d54bebe10a6cee1cd773129230d508af946901","tests/fixtures/invalid/local-datetime/month-under.stderr":"cc1749c4aaa0cec5e88a2cae52bf84da2e862b6d2dae2c46615eafa0b7f370bc","tests/fixtures/invalid/local-datetime/no-leads-with-milli.stderr":"d1d95c88dcbde166b3a89c562e87bb9dc7c7d4efb5aaf999f0c253b1109ffd2a","tests/fixtures/invalid/local-datetime/no-leads.stderr":"8be255d1f994769e4cb9fdc6b4b6d65ad2664348026e409026421be423150076","tests/fixtures/invalid/local-datetime/no-secs.stderr":"019be93baccb4283a186cfb846b8cd4c848a373319daf4955ab3bec451a7b730","tests/fixtures/invalid/local-datetime/no-t.stderr":"eca57151e4e310f22620f243582486fb3e5ade13e4d4a5fb4582252fd915ca04","tests/fixtures/invalid/local-datetime/second-over.stderr":"dad38092a29679601af7ae3b05960068fa0eec5a649858ab88aedaada6ffff00","tests/fixtures/invalid/local-datetime/time-no-leads.stderr":"b3282cb32386dd84a35468f488be5a92dd3488e951f9dd2ea39057046386b73e","tests/fixtures/invalid/local-time/hour-over.stderr":"e5aefc4baa094437e16b5a78c89df8469ac59d899433e1c0fcbf433344b3a4f9","tests/fixtures/invalid/local-time/minute-over.stderr":"b66ec93e63f27d0a4e63c0eb1fc2d3f8dbf2fc916e213192852b1b7ac0e21aa7","tests/fixtures/invalid/local-time/no-secs.stderr":"d9939a2e05d15375d4936c6ad7c4dbd13085e638573094f3a0befd9027c0a3ab","tests/fixtures/invalid/local-time/second-over.stderr":"f14b188fb85d8818ab953f2fa0d0b8de906dddc2f0e0ccf5ef68b3e81d619f20","tests/fixtures/invalid/local-time/time-no-leads-2.stderr":"f725d49ddb5af69b7285f071d68e3d8441d5e331adcfd8c025c1f3cbb68028a5","tests/fixtures/invalid/local-time/time-no-leads.stderr":"cf06f3847f3d14655a94d8cfd5a6984dc74115b1d3cdbee0662ef215738bbf65","tests/fixtures/invalid/spec/inline-table-2-0.stderr":"5ad1a938b1d1f0f3fdbd1871efdebfd30e136407ecdd9e2eff22150d00624b3f","tests/fixtures/invalid/spec/inline-table-3-0.stderr":"fcbc05e911b7db81bd918768fe98a51a7026fd476d616718cc417d2f08bcc1a1","tests/fixtures/invalid/spec/key-value-pair-1.stderr":"d5391142dfd56040840cf91b1e28e3c048229e3d9998534d41001cd6657f9bd6","tests/fixtures/invalid/spec/keys-2.stderr":"3c4ee6066fc75d2c1f1b325f618a01113694c318e330ff4f237e89127f332c87","tests/fixtures/invalid/spec/string-4-0.stderr":"910ee4b240159b828a7509c8dfb46507071a8d8636f3935a3914d6d91f315295","tests/fixtures/invalid/spec/string-7-0.stderr":"5128f0a930b3034e494a6bee4f384a587e9fd858b25f8cc529a488c94ee9670d","tests/fixtures/invalid/spec/table-9-0.stderr":"49dac70d337266f5c6b333fee468f279fed1bff62bfb4ec7436c8b6683ce0dd2","tests/fixtures/invalid/spec/table-9-1.stderr":"d9e071c70356c01b6537f876989ad2067e7773dd5eb24a298439d192dbad12d0","tests/fixtures/invalid/string/bad-byte-escape.stderr":"14f6ae446b3b8cb434267eba11c6ec5a1badef4f867169b173698cf9f1a29d95","tests/fixtures/invalid/string/bad-concat.stderr":"499219633467b9174471db40543ca188e2b906c470e511d2f701f5f5475d96be","tests/fixtures/invalid/string/bad-escape-1.stderr":"34a15ce7012217c62d31d5392038517c216f0cbfd5d75fb5f3c2bb07afd3f25c","tests/fixtures/invalid/string/bad-escape-2.stderr":"955aab40b16043c847d85d04e6adcd093c930dd8416d29c2ab5953c077eac6f4","tests/fixtures/invalid/string/bad-escape-3.stderr":"ef8302d7a6f9b8beb54478756a6069dfafc203f640a4afa2a58fbf13fdb35b8b","tests/fixtures/invalid/string/bad-hex-esc-1.stderr":"aea935cf1e17743356e6fb1059afed2d0ee5262906594782e5537a025398038e","tests/fixtures/invalid/string/bad-hex-esc-2.stderr":"deac5217cf80acc759e1b40c43f5f56431b276dc2c896aae5490d57583105e06","tests/fixtures/invalid/string/bad-hex-esc-3.stderr":"94ecf886427e8fe5daf1d8f932bf1887f2533b10bc1f57cb6de03ea28fef466f","tests/fixtures/invalid/string/bad-hex-esc-4.stderr":"382b011dd4070554ee875fde06703d8332ef6ad36f3619f3536b0a4997ee2745","tests/fixtures/invalid/string/bad-hex-esc-5.stderr":"a8a039fae822eda68591da28ff2a117b5d85e99d066e9126ebbb6426a1cad52d","tests/fixtures/invalid/string/bad-multiline.stderr":"141e5770190dd184bb1f64f6bb14fc017210bbd918ab5c8b7a3d80b86b21772b","tests/fixtures/invalid/string/bad-slash-escape.stderr":"d62f894ee166bddf84432507fb4ba56473c0a230fd88a3ccc2b199a72a34e613","tests/fixtures/invalid/string/bad-uni-esc-1.stderr":"b7d8a7f41600a6fc5cef5fd938fab31e1a516b5075bb5f6b22ee77e49bbeb195","tests/fixtures/invalid/string/bad-uni-esc-2.stderr":"5c23cec7a912ccba77180889e44dd84287fbbfdb170367146e9d633637124052","tests/fixtures/invalid/string/bad-uni-esc-3.stderr":"744574793d570b012ee2aa537405af14612183b769e425a04bd0c0ec6e14da7c","tests/fixtures/invalid/string/bad-uni-esc-4.stderr":"16543872b51db7ff6a87cdf1ae71917857e5118b90ceb3e0835525c9bd67d02d","tests/fixtures/invalid/string/bad-uni-esc-5.stderr":"f0ef02d2988680da67942d8599e7753f2e6c89a984643000a67ebf4c34722374","tests/fixtures/invalid/string/bad-uni-esc-6.stderr":"eff7b6dd907132aa9598dca52bf12d48be066a6a8d426ce95d5f4b344bfe8d98","tests/fixtures/invalid/string/bad-uni-esc-7.stderr":"24cd2f58919584c4dd12f0262933c8c0c6142a2b62c747d465ca1b9b4986093c","tests/fixtures/invalid/string/basic-byte-escapes.stderr":"b42fd0273c7438bf13ddea9552204bb9209cdcc8e4151311d2446185d2cd546a","tests/fixtures/invalid/string/basic-multiline-out-of-range-unicode-escape-1.stderr":"725cd4955987c3d6e736832281316d6c1a2446303e9a1dc78900cef4bb84ee64","tests/fixtures/invalid/string/basic-multiline-out-of-range-unicode-escape-2.stderr":"c6698fbdb95188d53bfdaa4a4f590d86a73aafcc321a5d9511ab43ce51be1c78","tests/fixtures/invalid/string/basic-multiline-quotes.stderr":"28177a49532f22aaffc9dc204592a2c5eca2fc20f8e208b7c7f589201e8b7de5","tests/fixtures/invalid/string/basic-multiline-unknown-escape.stderr":"a83406b30eb3ab2cebb0230d8d65d0b7583885138f2c070976ae61de2c8b17f3","tests/fixtures/invalid/string/basic-out-of-range-unicode-escape-1.stderr":"19af67599c6c2eef340c9fdb0ab2cc788928def50280af939247a1274447781f","tests/fixtures/invalid/string/basic-out-of-range-unicode-escape-2.stderr":"0e2e1a69358502ec17a07e4fc151b70e8a3b5123798cb38f98fe2d146515a84e","tests/fixtures/invalid/string/basic-unknown-escape.stderr":"1de467948fb18f61336350063701d9c5a6615054fe740a9be650f71f5ca4236b","tests/fixtures/invalid/string/literal-multiline-quotes-1.stderr":"249123229606aa8eedff1b5bdead5022daf470e47dbca639e32019d1d61dbcf9","tests/fixtures/invalid/string/literal-multiline-quotes-2.stderr":"d9784af1ff056a90bf531307749d53a5d24ffffbc0f4aada7fcee417a50d1615","tests/fixtures/invalid/string/missing-quotes.stderr":"462f24701d2c51d36b18d06b69be2f6eb36449b5f3ffbaa737fcbd2b2151ae4a","tests/fixtures/invalid/string/multiline-bad-escape-1.stderr":"18469c4d37d011b3f30ae17e3111b5e8a9526d593475e5d8d7a9b19461a40e8d","tests/fixtures/invalid/string/multiline-bad-escape-2.stderr":"d43896d3005c8470dc8149e2b74eb8825c6d9fedfe9f48125ad88a95c1dc3035","tests/fixtures/invalid/string/multiline-bad-escape-3.stderr":"92f732c6bcb922e25d2a001a389f93b596dd0e91109cbdcb651efa146309dc2a","tests/fixtures/invalid/string/multiline-bad-escape-4.stderr":"5e549045d08a76406f29c10433766f1c32aa69a169f3dc138103b4615c9979b1","tests/fixtures/invalid/string/multiline-escape-space-1.stderr":"94b451b6c03055186777a248cb216f95a1b2e29df25549f345d96bd0a4e63f1e","tests/fixtures/invalid/string/multiline-escape-space-2.stderr":"850d75a72e44e1ceeced7d65b810afa5b2935f3ab3efea0f3e147a06d82a6637","tests/fixtures/invalid/string/multiline-lit-no-close-1.stderr":"8e81ec582e75388024196cb5a64aaccc128c874be341fba01973c722e64a0d1b","tests/fixtures/invalid/string/multiline-lit-no-close-2.stderr":"9572aa98be504bab0172f612c40010d005577a6cd30f7fb3d25ea29c73e0489a","tests/fixtures/invalid/string/multiline-lit-no-close-3.stderr":"cc89579aa2201fc3bbe98693f822516557d950a9844e68ace4355991dd02478b","tests/fixtures/invalid/string/multiline-lit-no-close-4.stderr":"2310b339cc17b8aefce9ef0e2805c77d5cce3d70abe93373ebb8f986169afe00","tests/fixtures/invalid/string/multiline-no-close-1.stderr":"d5b9602d23b0cb023fbe3ae80d862fd60332475ba8863a1e977f17cb326a4548","tests/fixtures/invalid/string/multiline-no-close-2.stderr":"e500e99a44305b1e148b211e963478cf1554f8c9536d3108390cf41d5b2ce069","tests/fixtures/invalid/string/multiline-no-close-3.stderr":"efea30ada8d63f3071be499d63a82729b8f2c3d5f6155a1dca456e7d790f84be","tests/fixtures/invalid/string/multiline-no-close-4.stderr":"30ce703d6a38d97861b37d8539648734145e6ce45c39b2dc8b970b7b34557031","tests/fixtures/invalid/string/multiline-no-close-5.stderr":"a8b6610cb194104520cdc9fdd140192b6b1c738a3fe922a9f40c21b91f82487e","tests/fixtures/invalid/string/multiline-quotes-1.stderr":"046956658c0a73e665e7a6a2044ff83c8efb8cdd8c2ab153c163eb1e61068c56","tests/fixtures/invalid/string/no-close-1.stderr":"3ad8aff0932d98592b808fc6f44fa68a854097f8025e92c11af1acb6de3d3cc7","tests/fixtures/invalid/string/no-close-2.stderr":"3438330fa63c592f316342c9786696a2426df2838d60ee52889a9dc2527ce77c","tests/fixtures/invalid/string/no-close-3.stderr":"06e62924f3e7a0d290ab2a377e6a6b96c69bafee7170feb37331d6220e956e38","tests/fixtures/invalid/string/no-close-4.stderr":"e5cacd943fec6e10430242c95b42cdd55068cc053f5b40eff38e077a70d0109a","tests/fixtures/invalid/string/string.stderr":"aea935cf1e17743356e6fb1059afed2d0ee5262906594782e5537a025398038e","tests/fixtures/invalid/string/text-after-string.stderr":"1c1e4677be8d3dba0e7933b3ed1cbb6e0bcf6f600cf9a989a7b09c9424a4d0a7","tests/fixtures/invalid/string/wrong-close.stderr":"441f4f1b73c11c8dbf2f73cf9a7766f17a9517b3b9142e86736ed43eaec07f18","tests/fixtures/invalid/table/append-to-array-with-dotted-keys.stderr":"e16e10a17e38898bfff5b16887d9143fa5036669e83b75e84aa4ba4078b1a9a8","tests/fixtures/invalid/table/append-with-dotted-keys-1.stderr":"a67f1f152005295e0a1bb3dcaaa755edd05f19ac5316b8ad2eb4d45797e0f770","tests/fixtures/invalid/table/append-with-dotted-keys-2.stderr":"72d9ea8a90b4d9e5319c2bf951bdde6a87a205612e82ed5a09cea2b706bfde7f","tests/fixtures/invalid/table/array-empty.stderr":"e8a41c60adf7756361920816b6c4f44125a813c869b71fae2c98473e4da1b231","tests/fixtures/invalid/table/array-implicit.stderr":"7797ce41aab0567fc9d40e277cc32c12e1f16ffc0e73857fdb3bbf754246305f","tests/fixtures/invalid/table/array-no-close-1.stderr":"5f1e8703d59398f6595d21ed0abcc7dc3ce77943ad0f71eede9ad63ea2bcc7c1","tests/fixtures/invalid/table/array-no-close-2.stderr":"5adeffef5a1e1d63b6461f2a734a5b557bd3709e4fde903262be0452890623a6","tests/fixtures/invalid/table/duplicate-key-dotted-array.stderr":"9158eaf24fd4237fb87a6fb9be00e18ea935cb509a657bfe370cfa769e97cef6","tests/fixtures/invalid/table/duplicate-key-dotted-table.stderr":"ca58908463cbe2ec6b3de314237c178fee64245cc738c72a7b9e08bb3d02b2b0","tests/fixtures/invalid/table/duplicate-key-dotted-table2.stderr":"cb59f2ed324642de947f3cd9373ca111ec35104a5f33578f64c48084ce1a84f5","tests/fixtures/invalid/table/duplicate-key-table.stderr":"f4816522738b3e2ace87d1100a3d73e6a122d8dc67d05e0b35a1438e16a8952c","tests/fixtures/invalid/table/duplicate-table-array.stderr":"11d293e4b4f205fc98cd892f25a25f533cb922c963ecf095a932d2e9d550be4f","tests/fixtures/invalid/table/duplicate-table-array2.stderr":"fa9cd3b1212eed14ec56b66a16471ac2f7c0398d743982abb7c5cb4b5c7a5fe4","tests/fixtures/invalid/table/duplicate.stderr":"3e6d1b1a2f44d449e8cb0098e7c40ad1e755363b446f3821c399abfb26eb9939","tests/fixtures/invalid/table/empty-implicit-table.stderr":"cd3606ce97c5537d18146cd978403636a65fa703c83616da75b8cafa86e8fa24","tests/fixtures/invalid/table/empty.stderr":"4399e419abbcfbec93f5915e7fbdd11b6e462a4c066a29eacda159abfc588734","tests/fixtures/invalid/table/equals-sign.stderr":"472de6b908a03c99637b635a3a898ed956684ae422e1b4b135ec94986ea45f2d","tests/fixtures/invalid/table/llbrace.stderr":"db6bbee7ed15994398901c46ed4b40904897e71f5d972deb7904ccac49cd834e","tests/fixtures/invalid/table/nested-brackets-close.stderr":"e1dff60ea8f77dd1b8fae7d1d63c788c838c80560172d92377cc168f5cb5923a","tests/fixtures/invalid/table/nested-brackets-open.stderr":"bd58eb0630dc0c51ebc288258d360d707c8f43a5877ddc21e9420f8eb76a2f4c","tests/fixtures/invalid/table/no-close-1.stderr":"ae6326db737d2e259c051fbe3f5aa6ef7d7ec1bd47930ea78e09667a20100a72","tests/fixtures/invalid/table/no-close-2.stderr":"3b599c6d07071a40a0c3acf163f0b04655bb8953fe32bdcab5e68a527c3ab22e","tests/fixtures/invalid/table/no-close-3.stderr":"6bf7e2d30c735a55f595140af7c7f6be89b6faf868f4473ea39570fdb87d5823","tests/fixtures/invalid/table/no-close-4.stderr":"917c0203d1e45309fcff82ce33fdd2d989f630fb99290a40cb9e08a6f7ca0ef8","tests/fixtures/invalid/table/no-close-5.stderr":"c1a691a6fa9638b75010f37166c29a6e5a2da2e35bd9a321118d7ea384af2d77","tests/fixtures/invalid/table/overwrite-array-in-parent.stderr":"300782a740fff829dfe485a4a43426a53f82bb6afca63ef82fc07081c43d8707","tests/fixtures/invalid/table/overwrite-bool-with-array.stderr":"dcd33263a49a91ed583c3f53c6e86d6c5b8d493d841aea074a5a81f57cb5c152","tests/fixtures/invalid/table/overwrite-with-deep-table.stderr":"b128988d3a37f5857c41751847ed0d9590e4cbda66a55238f73c60d992749e41","tests/fixtures/invalid/table/redefine-1.stderr":"3e794bce5bb6ae9f603f50e3dc62d136701ec478078e8a8e99c94229778e24ca","tests/fixtures/invalid/table/redefine-2.stderr":"76a6fa1ea8d5da8a78aecb88c506dcf4e07906984baa8c9d1a363b2bebfa4281","tests/fixtures/invalid/table/redefine-3.stderr":"6ebf320d6d2117c189dd8d425303a66739a4813e4abef2d3184dc9ef5915d959","tests/fixtures/invalid/table/rrbrace.stderr":"342a5ff362c8b4c1e85a6442029291bd33165a3b36552794fcd5269249bf36a1","tests/fixtures/invalid/table/text-after-table.stderr":"6dfaf1fc3199f0602fea52f7b1c65869eb2f8643b9e90dc1e718a183fb972485","tests/fixtures/invalid/table/whitespace.stderr":"fa48d4dc83f92e729dc25c6fc6a0c336014391b4bdb3392998f18141d2deb350","tests/fixtures/invalid/table/with-pound.stderr":"97dbd1ceb7f357bd98cc1caa9a602c638aaa5831237b7d63b18153acc64d3af4","tests/invalid.rs":"daa9034453fb7f10718020e36a07a19664eb852071995f17480c595cb44e2cdf","tests/testsuite/convert.rs":"9140d681dbb9370b975d5bc1cd4e9e640ac4023c6789edcae544e66657ad5fe9","tests/testsuite/datetime.rs":"105d95570d05e9ecbc30bfe7d081f9d63e2f36634e9124da012f467c6134549e","tests/testsuite/edit.rs":"752f5310c253b670645335a316b789a71368ab3aebdf77ca2bfb6bcccaedc355","tests/testsuite/float.rs":"3db8b466505990ff3de38666c810b15c036632322b18f8e9c7893477dff4d641","tests/testsuite/invalid.rs":"31789643e3419ab922f8258e5a0421e1648b64aa5b96d3e1fb79bae36abf286e","tests/testsuite/main.rs":"b78ad4077facdf0e31ef77355fb3deb70d8339befbdb9ef16abca3b05231556e","tests/testsuite/parse.rs":"28fc7e35b5a80feb98eb69d7cb37d058addfe18bad56f9edd948c93f55cc7914","tests/testsuite/stackoverflow.rs":"426d4e621bbafe62f8aba2e8c62e715929185d5eca4c5083b6427b601abc667a"},"package":"70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"} \ No newline at end of file diff --git a/vendor/toml_edit-0.20.7/Cargo.lock b/vendor/toml_edit-0.20.7/Cargo.lock new file mode 100644 index 0000000000000..09337d3ebc55a --- /dev/null +++ b/vendor/toml_edit-0.20.7/Cargo.lock @@ -0,0 +1,899 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6342bd4f5a1205d7f41e94a41a901f5647c938cdfa96036338e8533c9d6c2450" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "memchr", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "clap" +version = "4.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" +dependencies = [ + "bitflags", + "clap_derive", + "clap_lex", + "is-terminal", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.105", +] + +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "crossbeam-utils" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "globset" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "ignore" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" +dependencies = [ + "crossbeam-utils", + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + +[[package]] +name = "include_dir" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +dependencies = [ + "libc", + "windows-sys 0.42.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "itoa" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" + +[[package]] +name = "kstring" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.142" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" + +[[package]] +name = "libtest-mimic" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7b603516767d1ab23d0de09d023e62966c3322f7148297c35cf3d97aa8b37fa" +dependencies = [ + "clap", + "termcolor", + "threadpool", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b64f40e5e03e0d54f03845c8197d0291253cdbedfb1cb46b13c2c117554a9f4c" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi 0.1.19", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + +[[package]] +name = "os_str_bytes" +version = "6.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.105", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + +[[package]] +name = "rustix" +version = "0.37.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + +[[package]] +name = "similar" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ac7f900db32bf3fd12e0117dd3dc4da74bc52ebaac97f39668446d89694803" + +[[package]] +name = "snapbox" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6bccd62078347f89a914e3004d94582e13824d4e3d8a816317862884c423835" +dependencies = [ + "anstream", + "anstyle", + "ignore", + "libtest-mimic", + "normalize-line-endings", + "similar", + "snapbox-macros", +] + +[[package]] +name = "snapbox-macros" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaaf09df9f0eeae82be96290918520214530e738a7fe5a351b0f24cf77c0ca31" +dependencies = [ + "anstream", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "toml-test" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec3892835fb31e181a87e1758275a64b0d7c6c9e9618aeb61a647bd487314c0" +dependencies = [ + "chrono", + "ryu", + "serde", + "serde_json", +] + +[[package]] +name = "toml-test-data" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0082ae0d631f97530e98829c4101ae3ce3f1821a88f0a04be4fc3eaca5e7ed2d" +dependencies = [ + "include_dir", +] + +[[package]] +name = "toml-test-harness" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1be4b8d761dee51b4694e9f1d622a1d7f9c135a8b8265459e16d09ac5b16a05d" +dependencies = [ + "ignore", + "libtest-mimic", + "toml-test", + "toml-test-data", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +dependencies = [ + "indexmap", + "kstring", + "libtest-mimic", + "serde", + "serde_json", + "serde_spanned", + "snapbox", + "toml-test-data", + "toml-test-harness", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.1", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm 0.42.1", + "windows_x86_64_msvc 0.42.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.1", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.1", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm 0.42.1", + "windows_x86_64_msvc 0.42.1", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" +dependencies = [ + "memchr", +] diff --git a/vendor/toml_edit-0.20.7/Cargo.toml b/vendor/toml_edit-0.20.7/Cargo.toml new file mode 100644 index 0000000000000..941c55da04167 --- /dev/null +++ b/vendor/toml_edit-0.20.7/Cargo.toml @@ -0,0 +1,156 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.67" +name = "toml_edit" +version = "0.20.7" +authors = [ + "Andronik Ordian ", + "Ed Page ", +] +include = [ + "build.rs", + "src/**/*", + "Cargo.toml", + "Cargo.lock", + "LICENSE*", + "README.md", + "benches/**/*", + "examples/**/*", + "tests/**/*", +] +description = "Yet another format-preserving TOML parser." +readme = "README.md" +keywords = [ + "encoding", + "toml", +] +categories = [ + "encoding", + "parser-implementations", + "parsing", + "config", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/toml-rs/toml" + +[package.metadata.docs.rs] +features = ["serde"] +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[package.metadata.release] +tag-name = "v{{version}}" + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +min = 1 +replace = "{{version}}" +search = "Unreleased" + +[[package.metadata.release.pre-release-replacements]] +exactly = 1 +file = "CHANGELOG.md" +replace = "...{{tag_name}}" +search = '\.\.\.HEAD' + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +min = 1 +replace = "{{date}}" +search = "ReleaseDate" + +[[package.metadata.release.pre-release-replacements]] +exactly = 1 +file = "CHANGELOG.md" +replace = """ + +## [Unreleased] - ReleaseDate +""" +search = "" + +[[package.metadata.release.pre-release-replacements]] +exactly = 1 +file = "CHANGELOG.md" +replace = """ + +[Unreleased]: https://github.com/toml-rs/toml/compare/{{tag_name}}...HEAD""" +search = "" + +[[example]] +name = "visit" +test = true + +[[test]] +name = "decoder_compliance" +harness = false + +[[test]] +name = "encoder_compliance" +harness = false + +[[test]] +name = "invalid" +harness = false + +[dependencies.indexmap] +version = "2.0.0" +features = ["std"] + +[dependencies.kstring] +version = "2.0.0" +features = ["max_inline"] +optional = true + +[dependencies.serde] +version = "1.0.145" +optional = true + +[dependencies.serde_spanned] +version = "0.6.4" +features = ["serde"] +optional = true + +[dependencies.toml_datetime] +version = "0.6.5" + +[dependencies.winnow] +version = "0.5.0" + +[dev-dependencies.libtest-mimic] +version = "0.6.0" + +[dev-dependencies.serde_json] +version = "1.0.96" + +[dev-dependencies.snapbox] +version = "0.4.11" +features = ["harness"] + +[dev-dependencies.toml-test-data] +version = "1.4.0" + +[dev-dependencies.toml-test-harness] +version = "0.4.8" + +[features] +default = [] +perf = ["dep:kstring"] +serde = [ + "dep:serde", + "toml_datetime/serde", + "dep:serde_spanned", +] +unbounded = [] diff --git a/vendor/toml_edit-0.20.7/LICENSE-APACHE b/vendor/toml_edit-0.20.7/LICENSE-APACHE new file mode 100644 index 0000000000000..8f71f43fee3f7 --- /dev/null +++ b/vendor/toml_edit-0.20.7/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/vendor/toml_edit-0.20.7/LICENSE-MIT b/vendor/toml_edit-0.20.7/LICENSE-MIT new file mode 100644 index 0000000000000..a2d01088b6ce5 --- /dev/null +++ b/vendor/toml_edit-0.20.7/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) Individual contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/toml_edit-0.20.7/README.md b/vendor/toml_edit-0.20.7/README.md new file mode 100644 index 0000000000000..12d879af0b930 --- /dev/null +++ b/vendor/toml_edit-0.20.7/README.md @@ -0,0 +1,59 @@ +# toml_edit + +[![Build Status](https://github.com/ordian/toml_edit/workflows/Continuous%20integration/badge.svg)](https://github.com/ordian/toml_edit/actions) +[![codecov](https://codecov.io/gh/ordian/toml_edit/branch/master/graph/badge.svg)](https://codecov.io/gh/ordian/toml_edit) +[![crates.io](https://img.shields.io/crates/v/toml_edit.svg)](https://crates.io/crates/toml_edit) +[![docs](https://docs.rs/toml_edit/badge.svg)](https://docs.rs/toml_edit) +[![Join the chat at https://gitter.im/toml_edit/Lobby](https://badges.gitter.im/a.svg)](https://gitter.im/toml_edit/Lobby) + + +This crate allows you to parse and modify toml +documents, while preserving comments, spaces *and +relative order* of items. + +`toml_edit` is primarily tailored for [cargo-edit](https://github.com/killercup/cargo-edit/) needs. + +## Example + +```rust +use toml_edit::{Document, value}; + +fn main() { + let toml = r#" +"hello" = 'toml!' # comment +['a'.b] + "#; + let mut doc = toml.parse::().expect("invalid doc"); + assert_eq!(doc.to_string(), toml); + // let's add a new key/value pair inside a.b: c = {d = "hello"} + doc["a"]["b"]["c"]["d"] = value("hello"); + // autoformat inline table a.b.c: { d = "hello" } + doc["a"]["b"]["c"].as_inline_table_mut().map(|t| t.fmt()); + let expected = r#" +"hello" = 'toml!' # comment +['a'.b] +c = { d = "hello" } + "#; + assert_eq!(doc.to_string(), expected); +} +``` + +## Limitations + +Things it does not preserve: + +* Scattered array of tables (tables are reordered by default, see [test]). +* Order of dotted keys, see [issue](https://github.com/ordian/toml_edit/issues/163). + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. + +[test]: https://github.com/ordian/toml_edit/blob/f09bd5d075fdb7d2ef8d9bb3270a34506c276753/tests/test_valid.rs#L84 diff --git a/vendor/toml_edit-0.20.7/examples/visit.rs b/vendor/toml_edit-0.20.7/examples/visit.rs new file mode 100644 index 0000000000000..cd7f851fe7e02 --- /dev/null +++ b/vendor/toml_edit-0.20.7/examples/visit.rs @@ -0,0 +1,284 @@ +//! Example for how to use `VisitMut` to iterate over a table. + +use std::collections::BTreeSet; +use toml_edit::visit::*; +use toml_edit::visit_mut::*; +use toml_edit::{Array, Document, InlineTable, Item, KeyMut, Table, Value}; + +/// This models the visit state for dependency keys in a `Cargo.toml`. +/// +/// Dependencies can be specified as: +/// +/// ```toml +/// [dependencies] +/// dep1 = "0.2" +/// +/// [build-dependencies] +/// dep2 = "0.3" +/// +/// [dev-dependencies] +/// dep3 = "0.4" +/// +/// [target.'cfg(windows)'.dependencies] +/// dep4 = "0.5" +/// +/// # and target build- and dev-dependencies +/// ``` +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +enum VisitState { + /// Represents the root of the table. + Root, + /// Represents "dependencies", "build-dependencies" or "dev-dependencies", or the target + /// forms of these. + Dependencies, + /// A table within dependencies. + SubDependencies, + /// Represents "target". + Target, + /// "target.[TARGET]". + TargetWithSpec, + /// Represents some other state. + Other, +} + +impl VisitState { + /// Figures out the next visit state, given the current state and the given key. + fn descend(self, key: &str) -> Self { + match (self, key) { + ( + VisitState::Root | VisitState::TargetWithSpec, + "dependencies" | "build-dependencies" | "dev-dependencies", + ) => VisitState::Dependencies, + (VisitState::Root, "target") => VisitState::Target, + (VisitState::Root | VisitState::TargetWithSpec, _) => VisitState::Other, + (VisitState::Target, _) => VisitState::TargetWithSpec, + (VisitState::Dependencies, _) => VisitState::SubDependencies, + (VisitState::SubDependencies, _) => VisitState::SubDependencies, + (VisitState::Other, _) => VisitState::Other, + } + } +} + +/// Collect the names of every dependency key. +#[derive(Debug)] +struct DependencyNameVisitor<'doc> { + state: VisitState, + names: BTreeSet<&'doc str>, +} + +impl<'doc> Visit<'doc> for DependencyNameVisitor<'doc> { + fn visit_table_like_kv(&mut self, key: &'doc str, node: &'doc Item) { + if self.state == VisitState::Dependencies { + self.names.insert(key); + } else { + // Since we're only interested in collecting the top-level keys right under + // [dependencies], don't recurse unconditionally. + + let old_state = self.state; + + // Figure out the next state given the key. + self.state = self.state.descend(key); + + // Recurse further into the document tree. + visit_table_like_kv(self, key, node); + + // Restore the old state after it's done. + self.state = old_state; + } + } +} + +/// Normalize all dependency tables into the format: +/// +/// ```toml +/// [dependencies] +/// dep = { version = "1.0", features = ["foo", "bar"], ... } +/// ``` +/// +/// leaving other tables untouched. +#[derive(Debug)] +struct NormalizeDependencyTablesVisitor { + state: VisitState, +} + +impl VisitMut for NormalizeDependencyTablesVisitor { + fn visit_table_mut(&mut self, node: &mut Table) { + visit_table_mut(self, node); + + // The conversion from regular tables into inline ones might leave some explicit parent + // tables hanging, so convert them to implicit. + if matches!(self.state, VisitState::Target | VisitState::TargetWithSpec) { + node.set_implicit(true); + } + } + + fn visit_table_like_kv_mut(&mut self, mut key: KeyMut<'_>, node: &mut Item) { + let old_state = self.state; + + // Figure out the next state given the key. + self.state = self.state.descend(key.get()); + + match self.state { + VisitState::Target | VisitState::TargetWithSpec | VisitState::Dependencies => { + // Top-level dependency row, or above: turn inline tables into regular ones. + if let Item::Value(Value::InlineTable(inline_table)) = node { + let inline_table = std::mem::replace(inline_table, InlineTable::new()); + let table = inline_table.into_table(); + key.fmt(); + *node = Item::Table(table); + } + } + VisitState::SubDependencies => { + // Individual dependency: turn regular tables into inline ones. + if let Item::Table(table) = node { + // Turn the table into an inline table. + let table = std::mem::replace(table, Table::new()); + let inline_table = table.into_inline_table(); + key.fmt(); + *node = Item::Value(Value::InlineTable(inline_table)); + } + } + _ => {} + } + + // Recurse further into the document tree. + visit_table_like_kv_mut(self, key, node); + + // Restore the old state after it's done. + self.state = old_state; + } + + fn visit_array_mut(&mut self, node: &mut Array) { + // Format any arrays within dependencies to be on the same line. + if matches!( + self.state, + VisitState::Dependencies | VisitState::SubDependencies + ) { + node.fmt(); + } + } +} + +/// This is the input provided to visit_mut_example. +static INPUT: &str = r#" +[package] +name = "my-package" + +[package.metadata.foo] +bar = 42 + +[dependencies] +atty = "0.2" +cargo-platform = { path = "crates/cargo-platform", version = "0.1.2" } + +[dependencies.pretty_env_logger] +version = "0.4" +optional = true + +[target.'cfg(windows)'.dependencies] +fwdansi = "1.1.0" + +[target.'cfg(windows)'.dependencies.winapi] +version = "0.3" +features = [ +"handleapi", +"jobapi", +] + +[target.'cfg(unix)'] +dev-dependencies = { miniz_oxide = "0.5" } + +[dev-dependencies.cargo-test-macro] +path = "crates/cargo-test-macro" + +[build-dependencies.flate2] +version = "0.4" +"#; + +/// This is the output produced by visit_mut_example. +#[cfg(test)] +static VISIT_MUT_OUTPUT: &str = r#" +[package] +name = "my-package" + +[package.metadata.foo] +bar = 42 + +[dependencies] +atty = "0.2" +cargo-platform = { path = "crates/cargo-platform", version = "0.1.2" } +pretty_env_logger = { version = "0.4", optional = true } + +[target.'cfg(windows)'.dependencies] +fwdansi = "1.1.0" +winapi = { version = "0.3", features = ["handleapi", "jobapi"] } + +[target.'cfg(unix)'.dev-dependencies] +miniz_oxide = "0.5" + +[dev-dependencies] +cargo-test-macro = { path = "crates/cargo-test-macro" } + +[build-dependencies] +flate2 = { version = "0.4" } +"#; + +fn visit_example(document: &Document) -> BTreeSet<&str> { + let mut visitor = DependencyNameVisitor { + state: VisitState::Root, + names: BTreeSet::new(), + }; + + visitor.visit_document(document); + + visitor.names +} + +fn visit_mut_example(document: &mut Document) { + let mut visitor = NormalizeDependencyTablesVisitor { + state: VisitState::Root, + }; + + visitor.visit_document_mut(document); +} + +fn main() { + let mut document: Document = INPUT.parse().expect("input is valid TOML"); + + println!("** visit example"); + println!("{:?}", visit_example(&document)); + + println!("** visit_mut example"); + visit_mut_example(&mut document); + println!("{}", document); +} + +#[cfg(test)] +#[test] +fn visit_correct() { + let document: Document = INPUT.parse().expect("input is valid TOML"); + + let names = visit_example(&document); + let expected = vec![ + "atty", + "cargo-platform", + "pretty_env_logger", + "fwdansi", + "winapi", + "miniz_oxide", + "cargo-test-macro", + "flate2", + ] + .into_iter() + .collect(); + assert_eq!(names, expected); +} + +#[cfg(test)] +#[test] +fn visit_mut_correct() { + let mut document: Document = INPUT.parse().expect("input is valid TOML"); + + visit_mut_example(&mut document); + assert_eq!(format!("{}", document), VISIT_MUT_OUTPUT); +} diff --git a/vendor/toml_edit-0.20.7/src/array.rs b/vendor/toml_edit-0.20.7/src/array.rs new file mode 100644 index 0000000000000..97033de580c24 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/array.rs @@ -0,0 +1,453 @@ +use std::iter::FromIterator; +use std::mem; + +use crate::repr::Decor; +use crate::value::{DEFAULT_LEADING_VALUE_DECOR, DEFAULT_VALUE_DECOR}; +use crate::{Item, RawString, Value}; + +/// Type representing a TOML array, +/// payload of the `Value::Array` variant's value +#[derive(Debug, Default, Clone)] +pub struct Array { + // `trailing` represents whitespaces, newlines + // and comments in an empty array or after the trailing comma + trailing: RawString, + trailing_comma: bool, + // prefix before `[` and suffix after `]` + decor: Decor, + pub(crate) span: Option>, + // always Vec + pub(crate) values: Vec, +} + +/// An owned iterator type over `Table`'s key/value pairs. +pub type ArrayIntoIter = Box>; +/// An iterator type over `Array`'s values. +pub type ArrayIter<'a> = Box + 'a>; +/// An iterator type over `Array`'s values. +pub type ArrayIterMut<'a> = Box + 'a>; + +/// Constructors +/// +/// See also `FromIterator` +impl Array { + /// Create an empty `Array` + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// ``` + pub fn new() -> Self { + Default::default() + } + + pub(crate) fn with_vec(values: Vec) -> Self { + Self { + values, + ..Default::default() + } + } +} + +/// Formatting +impl Array { + /// Auto formats the array. + pub fn fmt(&mut self) { + decorate_array(self); + } + + /// Set whether the array will use a trailing comma + pub fn set_trailing_comma(&mut self, yes: bool) { + self.trailing_comma = yes; + } + + /// Whether the array will use a trailing comma + pub fn trailing_comma(&self) -> bool { + self.trailing_comma + } + + /// Set whitespace after last element + pub fn set_trailing(&mut self, trailing: impl Into) { + self.trailing = trailing.into(); + } + + /// Whitespace after last element + pub fn trailing(&self) -> &RawString { + &self.trailing + } + + /// Returns the surrounding whitespace + pub fn decor_mut(&mut self) -> &mut Decor { + &mut self.decor + } + + /// Returns the surrounding whitespace + pub fn decor(&self) -> &Decor { + &self.decor + } + + /// Returns the location within the original document + pub(crate) fn span(&self) -> Option> { + self.span.clone() + } + + pub(crate) fn despan(&mut self, input: &str) { + self.span = None; + self.decor.despan(input); + self.trailing.despan(input); + for value in &mut self.values { + value.despan(input); + } + } +} + +impl Array { + /// Returns an iterator over all values. + pub fn iter(&self) -> ArrayIter<'_> { + Box::new(self.values.iter().filter_map(Item::as_value)) + } + + /// Returns an iterator over all values. + pub fn iter_mut(&mut self) -> ArrayIterMut<'_> { + Box::new(self.values.iter_mut().filter_map(Item::as_value_mut)) + } + + /// Returns the length of the underlying Vec. + /// + /// In some rare cases, placeholder elements will exist. For a more accurate count, call + /// `a.iter().count()` + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// assert_eq!(arr.len(), 2); + /// ``` + pub fn len(&self) -> usize { + self.values.len() + } + + /// Return true iff `self.len() == 0`. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// assert!(arr.is_empty()); + /// + /// arr.push(1); + /// arr.push("foo"); + /// assert!(! arr.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Clears the array, removing all values. Keeps the allocated memory for reuse. + pub fn clear(&mut self) { + self.values.clear() + } + + /// Returns a reference to the value at the given index, or `None` if the index is out of + /// bounds. + pub fn get(&self, index: usize) -> Option<&Value> { + self.values.get(index).and_then(Item::as_value) + } + + /// Returns a reference to the value at the given index, or `None` if the index is out of + /// bounds. + pub fn get_mut(&mut self, index: usize) -> Option<&mut Value> { + self.values.get_mut(index).and_then(Item::as_value_mut) + } + + /// Appends a new value to the end of the array, applying default formatting to it. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// ``` + pub fn push>(&mut self, v: V) { + self.value_op(v.into(), true, |items, value| { + items.push(Item::Value(value)) + }) + } + + /// Appends a new, already formatted value to the end of the array. + /// + /// # Examples + /// + /// ```rust + /// let formatted_value = "'literal'".parse::().unwrap(); + /// let mut arr = toml_edit::Array::new(); + /// arr.push_formatted(formatted_value); + /// ``` + pub fn push_formatted(&mut self, v: Value) { + self.values.push(Item::Value(v)); + } + + /// Inserts an element at the given position within the array, applying default formatting to + /// it and shifting all values after it to the right. + /// + /// # Panics + /// + /// Panics if `index > len`. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// + /// arr.insert(0, "start"); + /// ``` + pub fn insert>(&mut self, index: usize, v: V) { + self.value_op(v.into(), true, |items, value| { + items.insert(index, Item::Value(value)) + }) + } + + /// Inserts an already formatted value at the given position within the array, shifting all + /// values after it to the right. + /// + /// # Panics + /// + /// Panics if `index > len`. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// + /// let formatted_value = "'start'".parse::().unwrap(); + /// arr.insert_formatted(0, formatted_value); + /// ``` + pub fn insert_formatted(&mut self, index: usize, v: Value) { + self.values.insert(index, Item::Value(v)) + } + + /// Replaces the element at the given position within the array, preserving existing formatting. + /// + /// # Panics + /// + /// Panics if `index >= len`. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// + /// arr.replace(0, "start"); + /// ``` + pub fn replace>(&mut self, index: usize, v: V) -> Value { + // Read the existing value's decor and preserve it. + let existing_decor = self + .get(index) + .unwrap_or_else(|| panic!("index {} out of bounds (len = {})", index, self.len())) + .decor(); + let mut value = v.into(); + *value.decor_mut() = existing_decor.clone(); + self.replace_formatted(index, value) + } + + /// Replaces the element at the given position within the array with an already formatted value. + /// + /// # Panics + /// + /// Panics if `index >= len`. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// + /// let formatted_value = "'start'".parse::().unwrap(); + /// arr.replace_formatted(0, formatted_value); + /// ``` + pub fn replace_formatted(&mut self, index: usize, v: Value) -> Value { + match mem::replace(&mut self.values[index], Item::Value(v)) { + Item::Value(old_value) => old_value, + x => panic!("non-value item {:?} in an array", x), + } + } + + /// Removes the value at the given index. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// + /// arr.remove(0); + /// assert_eq!(arr.len(), 1); + /// ``` + pub fn remove(&mut self, index: usize) -> Value { + let removed = self.values.remove(index); + match removed { + Item::Value(v) => v, + x => panic!("non-value item {:?} in an array", x), + } + } + + /// Retains only the values specified by the `keep` predicate. + /// + /// In other words, remove all values for which `keep(&value)` returns `false`. + /// + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. + pub fn retain(&mut self, mut keep: F) + where + F: FnMut(&Value) -> bool, + { + self.values + .retain(|item| item.as_value().map(&mut keep).unwrap_or(false)); + } + + /// Sorts the slice with a comparator function. + /// + /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) worst-case. + /// + /// The comparator function must define a total ordering for the elements in the slice. If + /// the ordering is not total, the order of the elements is unspecified. An order is a + /// total order if it is (for all `a`, `b` and `c`): + /// + /// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and + /// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. + /// + /// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use + /// `partial_cmp` as our sort function when we know the slice doesn't contain a `NaN`. + #[inline] + pub fn sort_by(&mut self, mut compare: F) + where + F: FnMut(&Value, &Value) -> std::cmp::Ordering, + { + self.values.sort_by(move |lhs, rhs| { + let lhs = lhs.as_value(); + let rhs = rhs.as_value(); + match (lhs, rhs) { + (None, None) => std::cmp::Ordering::Equal, + (Some(_), None) => std::cmp::Ordering::Greater, + (None, Some(_)) => std::cmp::Ordering::Less, + (Some(lhs), Some(rhs)) => compare(lhs, rhs), + } + }) + } + + /// Sorts the array with a key extraction function. + /// + /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*)) + /// worst-case, where the key function is *O*(*m*). + #[inline] + pub fn sort_by_key(&mut self, mut f: F) + where + F: FnMut(&Value) -> K, + K: Ord, + { + #[allow(clippy::manual_map)] // needed for lifetimes + self.values.sort_by_key(move |item| { + if let Some(value) = item.as_value() { + Some(f(value)) + } else { + None + } + }); + } + + fn value_op( + &mut self, + v: Value, + decorate: bool, + op: impl FnOnce(&mut Vec, Value) -> T, + ) -> T { + let mut value = v; + if !self.is_empty() && decorate { + value.decorate(" ", ""); + } else if decorate { + value.decorate("", ""); + } + op(&mut self.values, value) + } +} + +impl std::fmt::Display for Array { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + crate::encode::Encode::encode(self, f, None, ("", "")) + } +} + +impl> Extend for Array { + fn extend>(&mut self, iter: T) { + for value in iter { + self.push_formatted(value.into()); + } + } +} + +impl> FromIterator for Array { + fn from_iter(iter: I) -> Self + where + I: IntoIterator, + { + let v = iter.into_iter().map(|a| Item::Value(a.into())); + Array { + values: v.collect(), + ..Default::default() + } + } +} + +impl IntoIterator for Array { + type Item = Value; + type IntoIter = ArrayIntoIter; + + fn into_iter(self) -> Self::IntoIter { + Box::new( + self.values + .into_iter() + .filter(|v| v.is_value()) + .map(|v| v.into_value().unwrap()), + ) + } +} + +impl<'s> IntoIterator for &'s Array { + type Item = &'s Value; + type IntoIter = ArrayIter<'s>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +fn decorate_array(array: &mut Array) { + for (i, value) in array + .values + .iter_mut() + .filter_map(Item::as_value_mut) + .enumerate() + { + // [value1, value2, value3] + if i == 0 { + value.decorate(DEFAULT_LEADING_VALUE_DECOR.0, DEFAULT_LEADING_VALUE_DECOR.1); + } else { + value.decorate(DEFAULT_VALUE_DECOR.0, DEFAULT_VALUE_DECOR.1); + } + } + // Since everything is now on the same line, remove trailing commas and whitespace. + array.set_trailing_comma(false); + array.set_trailing(""); +} diff --git a/vendor/toml_edit-0.20.7/src/array_of_tables.rs b/vendor/toml_edit-0.20.7/src/array_of_tables.rs new file mode 100644 index 0000000000000..c4d7194884347 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/array_of_tables.rs @@ -0,0 +1,166 @@ +use std::iter::FromIterator; + +use crate::{Array, Item, Table}; + +/// Type representing a TOML array of tables +#[derive(Clone, Debug, Default)] +pub struct ArrayOfTables { + // Always Vec, just `Item` to make `Index` work + pub(crate) span: Option>, + pub(crate) values: Vec, +} + +/// Constructors +/// +/// See also `FromIterator` +impl ArrayOfTables { + /// Creates an empty array of tables. + pub fn new() -> Self { + Default::default() + } +} + +/// Formatting +impl ArrayOfTables { + /// Convert to an inline array + pub fn into_array(mut self) -> Array { + for value in self.values.iter_mut() { + value.make_value(); + } + let mut a = Array::with_vec(self.values); + a.fmt(); + a + } + + /// Returns the location within the original document + pub(crate) fn span(&self) -> Option> { + self.span.clone() + } + + pub(crate) fn despan(&mut self, input: &str) { + self.span = None; + for value in &mut self.values { + value.despan(input); + } + } +} + +impl ArrayOfTables { + /// Returns an iterator over tables. + pub fn iter(&self) -> ArrayOfTablesIter<'_> { + Box::new(self.values.iter().filter_map(Item::as_table)) + } + + /// Returns an iterator over tables. + pub fn iter_mut(&mut self) -> ArrayOfTablesIterMut<'_> { + Box::new(self.values.iter_mut().filter_map(Item::as_table_mut)) + } + + /// Returns the length of the underlying Vec. + /// To get the actual number of items use `a.iter().count()`. + pub fn len(&self) -> usize { + self.values.len() + } + + /// Returns true iff `self.len() == 0`. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Removes all the tables. + pub fn clear(&mut self) { + self.values.clear() + } + + /// Returns an optional reference to the table. + pub fn get(&self, index: usize) -> Option<&Table> { + self.values.get(index).and_then(Item::as_table) + } + + /// Returns an optional mutable reference to the table. + pub fn get_mut(&mut self, index: usize) -> Option<&mut Table> { + self.values.get_mut(index).and_then(Item::as_table_mut) + } + + /// Appends a table to the array. + pub fn push(&mut self, table: Table) { + self.values.push(Item::Table(table)); + } + + /// Removes a table with the given index. + pub fn remove(&mut self, index: usize) { + self.values.remove(index); + } + + /// Retains only the elements specified by the `keep` predicate. + /// + /// In other words, remove all tables for which `keep(&table)` returns `false`. + /// + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. + pub fn retain(&mut self, mut keep: F) + where + F: FnMut(&Table) -> bool, + { + self.values + .retain(|item| item.as_table().map(&mut keep).unwrap_or(false)); + } +} + +/// An iterator type over `ArrayOfTables`'s values. +pub type ArrayOfTablesIter<'a> = Box + 'a>; +/// An iterator type over `ArrayOfTables`'s values. +pub type ArrayOfTablesIterMut<'a> = Box + 'a>; +/// An iterator type over `ArrayOfTables`'s values. +pub type ArrayOfTablesIntoIter = Box>; + +impl Extend for ArrayOfTables { + fn extend>(&mut self, iter: T) { + for value in iter { + self.push(value); + } + } +} + +impl FromIterator
for ArrayOfTables { + fn from_iter(iter: I) -> Self + where + I: IntoIterator, + { + let v = iter.into_iter().map(Item::Table); + ArrayOfTables { + values: v.collect(), + span: None, + } + } +} + +impl IntoIterator for ArrayOfTables { + type Item = Table; + type IntoIter = ArrayOfTablesIntoIter; + + fn into_iter(self) -> Self::IntoIter { + Box::new( + self.values + .into_iter() + .filter(|v| v.is_table()) + .map(|v| v.into_table().unwrap()), + ) + } +} + +impl<'s> IntoIterator for &'s ArrayOfTables { + type Item = &'s Table; + type IntoIter = ArrayOfTablesIter<'s>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl std::fmt::Display for ArrayOfTables { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // HACK: Without the header, we don't really have a proper way of printing this + self.clone().into_array().fmt(f) + } +} diff --git a/vendor/toml_edit-0.20.7/src/de/array.rs b/vendor/toml_edit-0.20.7/src/de/array.rs new file mode 100644 index 0000000000000..adc54016be1b6 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/de/array.rs @@ -0,0 +1,97 @@ +use crate::de::Error; + +pub(crate) struct ArrayDeserializer { + input: Vec, + span: Option>, +} + +impl ArrayDeserializer { + pub(crate) fn new(input: Vec, span: Option>) -> Self { + Self { input, span } + } +} + +// Note: this is wrapped by `ValueDeserializer` and any trait methods +// implemented here need to be wrapped there +impl<'de> serde::Deserializer<'de> for ArrayDeserializer { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_seq(ArraySeqAccess::new(self.input)) + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + if serde_spanned::__unstable::is_spanned(name, fields) { + if let Some(span) = self.span.clone() { + return visitor.visit_map(super::SpannedDeserializer::new(self, span)); + } + } + + self.deserialize_any(visitor) + } + + serde::forward_to_deserialize_any! { + bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq + bytes byte_buf map option unit newtype_struct + ignored_any unit_struct tuple_struct tuple enum identifier + } +} + +impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for ArrayDeserializer { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl crate::Array { + pub(crate) fn into_deserializer(self) -> ArrayDeserializer { + ArrayDeserializer::new(self.values, self.span) + } +} + +impl crate::ArrayOfTables { + pub(crate) fn into_deserializer(self) -> ArrayDeserializer { + ArrayDeserializer::new(self.values, self.span) + } +} + +pub(crate) struct ArraySeqAccess { + iter: std::vec::IntoIter, +} + +impl ArraySeqAccess { + pub(crate) fn new(input: Vec) -> Self { + Self { + iter: input.into_iter(), + } + } +} + +impl<'de> serde::de::SeqAccess<'de> for ArraySeqAccess { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: serde::de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some(v) => seed + .deserialize(crate::de::ValueDeserializer::new(v)) + .map(Some), + None => Ok(None), + } + } +} diff --git a/vendor/toml_edit-0.20.7/src/de/datetime.rs b/vendor/toml_edit-0.20.7/src/de/datetime.rs new file mode 100644 index 0000000000000..14de28b3f13c3 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/de/datetime.rs @@ -0,0 +1,43 @@ +use serde::de::value::BorrowedStrDeserializer; +use serde::de::IntoDeserializer; + +use crate::de::Error; + +pub(crate) struct DatetimeDeserializer { + date: Option, +} + +impl DatetimeDeserializer { + pub(crate) fn new(date: crate::Datetime) -> Self { + Self { date: Some(date) } + } +} + +impl<'de> serde::de::MapAccess<'de> for DatetimeDeserializer { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result, Error> + where + K: serde::de::DeserializeSeed<'de>, + { + if self.date.is_some() { + seed.deserialize(BorrowedStrDeserializer::new( + toml_datetime::__unstable::FIELD, + )) + .map(Some) + } else { + Ok(None) + } + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: serde::de::DeserializeSeed<'de>, + { + if let Some(date) = self.date.take() { + seed.deserialize(date.to_string().into_deserializer()) + } else { + panic!("next_value_seed called before next_key_seed") + } + } +} diff --git a/vendor/toml_edit-0.20.7/src/de/key.rs b/vendor/toml_edit-0.20.7/src/de/key.rs new file mode 100644 index 0000000000000..a3b282566b7bb --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/de/key.rs @@ -0,0 +1,151 @@ +use serde::de::IntoDeserializer; + +use super::Error; + +pub(crate) struct KeyDeserializer { + span: Option>, + key: crate::InternalString, +} + +impl KeyDeserializer { + pub(crate) fn new(key: crate::InternalString, span: Option>) -> Self { + KeyDeserializer { span, key } + } +} + +impl<'de> serde::de::IntoDeserializer<'de, Error> for KeyDeserializer { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl<'de> serde::de::Deserializer<'de> for KeyDeserializer { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + self.key.into_deserializer().deserialize_any(visitor) + } + + fn deserialize_enum( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + if serde_spanned::__unstable::is_spanned(name, fields) { + if let Some(span) = self.span.clone() { + return visitor.visit_map(super::SpannedDeserializer::new(self.key.as_str(), span)); + } + } + self.deserialize_any(visitor) + } + + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + serde::forward_to_deserialize_any! { + bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq + bytes byte_buf map option unit + ignored_any unit_struct tuple_struct tuple identifier + } +} + +impl<'de> serde::de::EnumAccess<'de> for KeyDeserializer { + type Error = super::Error; + type Variant = UnitOnly; + + fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: serde::de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(unit_only) + } +} + +pub(crate) struct UnitOnly { + marker: std::marker::PhantomData, +} + +fn unit_only(t: T) -> (T, UnitOnly) { + ( + t, + UnitOnly { + marker: std::marker::PhantomData, + }, + ) +} + +impl<'de, E> serde::de::VariantAccess<'de> for UnitOnly +where + E: serde::de::Error, +{ + type Error = E; + + fn unit_variant(self) -> Result<(), Self::Error> { + Ok(()) + } + + fn newtype_variant_seed(self, _seed: T) -> Result + where + T: serde::de::DeserializeSeed<'de>, + { + Err(serde::de::Error::invalid_type( + serde::de::Unexpected::UnitVariant, + &"newtype variant", + )) + } + + fn tuple_variant(self, _len: usize, _visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + Err(serde::de::Error::invalid_type( + serde::de::Unexpected::UnitVariant, + &"tuple variant", + )) + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + _visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + Err(serde::de::Error::invalid_type( + serde::de::Unexpected::UnitVariant, + &"struct variant", + )) + } +} diff --git a/vendor/toml_edit-0.20.7/src/de/mod.rs b/vendor/toml_edit-0.20.7/src/de/mod.rs new file mode 100644 index 0000000000000..09ea12096958b --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/de/mod.rs @@ -0,0 +1,289 @@ +//! Deserializing TOML into Rust structures. +//! +//! This module contains all the Serde support for deserializing TOML documents into Rust structures. + +use serde::de::DeserializeOwned; + +mod array; +mod datetime; +mod key; +mod spanned; +mod table; +mod table_enum; +mod value; + +use array::ArrayDeserializer; +use datetime::DatetimeDeserializer; +use key::KeyDeserializer; +use spanned::SpannedDeserializer; +use table::TableMapAccess; +use table_enum::TableEnumDeserializer; + +pub use value::ValueDeserializer; + +/// Errors that can occur when deserializing a type. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Error { + inner: crate::TomlError, +} + +impl Error { + pub(crate) fn custom(msg: T, span: Option>) -> Self + where + T: std::fmt::Display, + { + Error { + inner: crate::TomlError::custom(msg.to_string(), span), + } + } + + /// Add key while unwinding + pub fn add_key(&mut self, key: String) { + self.inner.add_key(key) + } + + /// What went wrong + pub fn message(&self) -> &str { + self.inner.message() + } + + /// The start/end index into the original document where the error occurred + pub fn span(&self) -> Option> { + self.inner.span() + } + + pub(crate) fn set_span(&mut self, span: Option>) { + self.inner.set_span(span); + } +} + +impl serde::de::Error for Error { + fn custom(msg: T) -> Self + where + T: std::fmt::Display, + { + Error::custom(msg, None) + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + self.inner.fmt(f) + } +} + +impl From for Error { + fn from(e: crate::TomlError) -> Error { + Self { inner: e } + } +} + +impl From for crate::TomlError { + fn from(e: Error) -> crate::TomlError { + e.inner + } +} + +impl std::error::Error for Error {} + +/// Convert a value into `T`. +pub fn from_str(s: &'_ str) -> Result +where + T: DeserializeOwned, +{ + let de = s.parse::()?; + T::deserialize(de) +} + +/// Convert a value into `T`. +pub fn from_slice(s: &'_ [u8]) -> Result +where + T: DeserializeOwned, +{ + let s = std::str::from_utf8(s).map_err(|e| Error::custom(e, None))?; + from_str(s) +} + +/// Convert a document into `T`. +pub fn from_document(d: crate::Document) -> Result +where + T: DeserializeOwned, +{ + let deserializer = Deserializer::new(d); + T::deserialize(deserializer) +} + +/// Deserialization for TOML [documents][crate::Document]. +pub struct Deserializer { + input: crate::Document, +} + +impl Deserializer { + /// Deserialization implementation for TOML. + pub fn new(input: crate::Document) -> Self { + Self { input } + } +} + +impl std::str::FromStr for Deserializer { + type Err = Error; + + /// Parses a document from a &str + fn from_str(s: &str) -> Result { + let d = crate::parser::parse_document(s).map_err(Error::from)?; + Ok(Self::new(d)) + } +} + +// Note: this is wrapped by `toml::de::Deserializer` and any trait methods +// implemented here need to be wrapped there +impl<'de> serde::Deserializer<'de> for Deserializer { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + let original = self.input.original; + self.input + .root + .into_deserializer() + .deserialize_any(visitor) + .map_err(|mut e: Self::Error| { + e.inner.set_original(original); + e + }) + } + + // `None` is interpreted as a missing field so be sure to implement `Some` + // as a present field. + fn deserialize_option(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + let original = self.input.original; + self.input + .root + .into_deserializer() + .deserialize_option(visitor) + .map_err(|mut e: Self::Error| { + e.inner.set_original(original); + e + }) + } + + fn deserialize_newtype_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + let original = self.input.original; + self.input + .root + .into_deserializer() + .deserialize_newtype_struct(name, visitor) + .map_err(|mut e: Self::Error| { + e.inner.set_original(original); + e + }) + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + let original = self.input.original; + self.input + .root + .into_deserializer() + .deserialize_struct(name, fields, visitor) + .map_err(|mut e: Self::Error| { + e.inner.set_original(original); + e + }) + } + + // Called when the type to deserialize is an enum, as opposed to a field in the type. + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + let original = self.input.original; + self.input + .root + .into_deserializer() + .deserialize_enum(name, variants, visitor) + .map_err(|mut e: Self::Error| { + e.inner.set_original(original); + e + }) + } + + serde::forward_to_deserialize_any! { + bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq + bytes byte_buf map unit + ignored_any unit_struct tuple_struct tuple identifier + } +} + +impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for Deserializer { + type Deserializer = Deserializer; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for crate::Document { + type Deserializer = Deserializer; + + fn into_deserializer(self) -> Self::Deserializer { + Deserializer::new(self) + } +} + +pub(crate) fn validate_struct_keys( + table: &crate::table::KeyValuePairs, + fields: &'static [&'static str], +) -> Result<(), Error> { + let extra_fields = table + .iter() + .filter_map(|(key, val)| { + if !fields.contains(&key.as_str()) { + Some(val.clone()) + } else { + None + } + }) + .collect::>(); + + if extra_fields.is_empty() { + Ok(()) + } else { + Err(Error::custom( + format!( + "unexpected keys in table: {}, available keys: {}", + extra_fields + .iter() + .map(|k| k.key.get()) + .collect::>() + .join(", "), + fields.join(", "), + ), + extra_fields[0].key.span(), + )) + } +} diff --git a/vendor/toml_edit-0.20.7/src/de/spanned.rs b/vendor/toml_edit-0.20.7/src/de/spanned.rs new file mode 100644 index 0000000000000..7ce58640aeb76 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/de/spanned.rs @@ -0,0 +1,70 @@ +use serde::de::value::BorrowedStrDeserializer; +use serde::de::IntoDeserializer as _; + +use super::Error; + +pub(crate) struct SpannedDeserializer<'de, T: serde::de::IntoDeserializer<'de, Error>> { + phantom_data: std::marker::PhantomData<&'de ()>, + start: Option, + end: Option, + value: Option, +} + +impl<'de, T> SpannedDeserializer<'de, T> +where + T: serde::de::IntoDeserializer<'de, Error>, +{ + pub(crate) fn new(value: T, span: std::ops::Range) -> Self { + Self { + phantom_data: Default::default(), + start: Some(span.start), + end: Some(span.end), + value: Some(value), + } + } +} + +impl<'de, T> serde::de::MapAccess<'de> for SpannedDeserializer<'de, T> +where + T: serde::de::IntoDeserializer<'de, Error>, +{ + type Error = Error; + fn next_key_seed(&mut self, seed: K) -> Result, Error> + where + K: serde::de::DeserializeSeed<'de>, + { + if self.start.is_some() { + seed.deserialize(BorrowedStrDeserializer::new( + serde_spanned::__unstable::START_FIELD, + )) + .map(Some) + } else if self.end.is_some() { + seed.deserialize(BorrowedStrDeserializer::new( + serde_spanned::__unstable::END_FIELD, + )) + .map(Some) + } else if self.value.is_some() { + seed.deserialize(BorrowedStrDeserializer::new( + serde_spanned::__unstable::VALUE_FIELD, + )) + .map(Some) + } else { + Ok(None) + } + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: serde::de::DeserializeSeed<'de>, + { + if let Some(start) = self.start.take() { + seed.deserialize(start.into_deserializer()) + } else if let Some(end) = self.end.take() { + seed.deserialize(end.into_deserializer()) + } else if let Some(value) = self.value.take() { + seed.deserialize(value.into_deserializer()) + } else { + panic!("next_value_seed called before next_key_seed") + } + } +} diff --git a/vendor/toml_edit-0.20.7/src/de/table.rs b/vendor/toml_edit-0.20.7/src/de/table.rs new file mode 100644 index 0000000000000..0b6183e0946b1 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/de/table.rs @@ -0,0 +1,213 @@ +use serde::de::IntoDeserializer; + +use crate::de::Error; + +pub(crate) struct TableDeserializer { + span: Option>, + items: crate::table::KeyValuePairs, +} + +// Note: this is wrapped by `Deserializer` and `ValueDeserializer` and any trait methods +// implemented here need to be wrapped there +impl<'de> serde::Deserializer<'de> for TableDeserializer { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_map(crate::de::TableMapAccess::new(self)) + } + + // `None` is interpreted as a missing field so be sure to implement `Some` + // as a present field. + fn deserialize_option(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_some(self) + } + + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + if serde_spanned::__unstable::is_spanned(name, fields) { + if let Some(span) = self.span.clone() { + return visitor.visit_map(super::SpannedDeserializer::new(self, span)); + } + } + + self.deserialize_any(visitor) + } + + // Called when the type to deserialize is an enum, as opposed to a field in the type. + fn deserialize_enum( + self, + _name: &'static str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + if self.items.is_empty() { + Err(crate::de::Error::custom( + "wanted exactly 1 element, found 0 elements", + self.span, + )) + } else if self.items.len() != 1 { + Err(crate::de::Error::custom( + "wanted exactly 1 element, more than 1 element", + self.span, + )) + } else { + visitor.visit_enum(crate::de::TableMapAccess::new(self)) + } + } + + serde::forward_to_deserialize_any! { + bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq + bytes byte_buf map unit + ignored_any unit_struct tuple_struct tuple identifier + } +} + +impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for TableDeserializer { + type Deserializer = TableDeserializer; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl crate::Table { + pub(crate) fn into_deserializer(self) -> TableDeserializer { + TableDeserializer { + span: self.span(), + items: self.items, + } + } +} + +impl crate::InlineTable { + pub(crate) fn into_deserializer(self) -> TableDeserializer { + TableDeserializer { + span: self.span(), + items: self.items, + } + } +} + +pub(crate) struct TableMapAccess { + iter: indexmap::map::IntoIter, + span: Option>, + value: Option<(crate::InternalString, crate::Item)>, +} + +impl TableMapAccess { + pub(crate) fn new(input: TableDeserializer) -> Self { + Self { + iter: input.items.into_iter(), + span: input.span, + value: None, + } + } +} + +impl<'de> serde::de::MapAccess<'de> for TableMapAccess { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> + where + K: serde::de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some((k, v)) => { + let ret = seed + .deserialize(super::KeyDeserializer::new(k, v.key.span())) + .map(Some) + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(v.key.span()); + } + e + }); + self.value = Some((v.key.into(), v.value)); + ret + } + None => Ok(None), + } + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: serde::de::DeserializeSeed<'de>, + { + match self.value.take() { + Some((k, v)) => { + let span = v.span(); + seed.deserialize(crate::de::ValueDeserializer::new(v)) + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e.add_key(k.as_str().to_owned()); + e + }) + } + None => { + panic!("no more values in next_value_seed, internal error in ValueDeserializer") + } + } + } +} + +impl<'de> serde::de::EnumAccess<'de> for TableMapAccess { + type Error = Error; + type Variant = super::TableEnumDeserializer; + + fn variant_seed(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: serde::de::DeserializeSeed<'de>, + { + let (key, value) = match self.iter.next() { + Some(pair) => pair, + None => { + return Err(Error::custom( + "expected table with exactly 1 entry, found empty table", + self.span, + )); + } + }; + + let val = seed + .deserialize(key.into_deserializer()) + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(value.key.span()); + } + e + })?; + + let variant = super::TableEnumDeserializer::new(value.value); + + Ok((val, variant)) + } +} diff --git a/vendor/toml_edit-0.20.7/src/de/table_enum.rs b/vendor/toml_edit-0.20.7/src/de/table_enum.rs new file mode 100644 index 0000000000000..0ceeab62f14f5 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/de/table_enum.rs @@ -0,0 +1,188 @@ +use crate::de::Error; + +/// Deserializes table values into enum variants. +pub(crate) struct TableEnumDeserializer { + value: crate::Item, +} + +impl TableEnumDeserializer { + pub(crate) fn new(value: crate::Item) -> Self { + TableEnumDeserializer { value } + } +} + +impl<'de> serde::de::VariantAccess<'de> for TableEnumDeserializer { + type Error = Error; + + fn unit_variant(self) -> Result<(), Self::Error> { + match self.value { + crate::Item::ArrayOfTables(values) => { + if values.is_empty() { + Ok(()) + } else { + Err(Error::custom("expected empty array", values.span())) + } + } + crate::Item::Value(crate::Value::Array(values)) => { + if values.is_empty() { + Ok(()) + } else { + Err(Error::custom("expected empty table", values.span())) + } + } + crate::Item::Table(values) => { + if values.is_empty() { + Ok(()) + } else { + Err(Error::custom("expected empty table", values.span())) + } + } + crate::Item::Value(crate::Value::InlineTable(values)) => { + if values.is_empty() { + Ok(()) + } else { + Err(Error::custom("expected empty table", values.span())) + } + } + e => Err(Error::custom( + format!("expected table, found {}", e.type_name()), + e.span(), + )), + } + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: serde::de::DeserializeSeed<'de>, + { + seed.deserialize(super::ValueDeserializer::new(self.value)) + } + + fn tuple_variant(self, len: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + match self.value { + crate::Item::ArrayOfTables(values) => { + let values_span = values.span(); + let tuple_values = values.values.into_iter().collect::>(); + + if tuple_values.len() == len { + serde::de::Deserializer::deserialize_seq( + super::ArrayDeserializer::new(tuple_values, values_span), + visitor, + ) + } else { + Err(Error::custom( + format!("expected tuple with length {}", len), + values_span, + )) + } + } + crate::Item::Value(crate::Value::Array(values)) => { + let values_span = values.span(); + let tuple_values = values.values.into_iter().collect::>(); + + if tuple_values.len() == len { + serde::de::Deserializer::deserialize_seq( + super::ArrayDeserializer::new(tuple_values, values_span), + visitor, + ) + } else { + Err(Error::custom( + format!("expected tuple with length {}", len), + values_span, + )) + } + } + crate::Item::Table(values) => { + let values_span = values.span(); + let tuple_values: Result, _> = values + .items + .into_iter() + .enumerate() + .map( + |(index, (_, value))| match value.key.get().parse::() { + Ok(key_index) if key_index == index => Ok(value.value), + Ok(_) | Err(_) => Err(Error::custom( + format!( + "expected table key `{}`, but was `{}`", + index, + value.key.get() + ), + value.key.span(), + )), + }, + ) + .collect(); + let tuple_values = tuple_values?; + + if tuple_values.len() == len { + serde::de::Deserializer::deserialize_seq( + super::ArrayDeserializer::new(tuple_values, values_span), + visitor, + ) + } else { + Err(Error::custom( + format!("expected tuple with length {}", len), + values_span, + )) + } + } + crate::Item::Value(crate::Value::InlineTable(values)) => { + let values_span = values.span(); + let tuple_values: Result, _> = values + .items + .into_iter() + .enumerate() + .map( + |(index, (_, value))| match value.key.get().parse::() { + Ok(key_index) if key_index == index => Ok(value.value), + Ok(_) | Err(_) => Err(Error::custom( + format!( + "expected table key `{}`, but was `{}`", + index, + value.key.get() + ), + value.key.span(), + )), + }, + ) + .collect(); + let tuple_values = tuple_values?; + + if tuple_values.len() == len { + serde::de::Deserializer::deserialize_seq( + super::ArrayDeserializer::new(tuple_values, values_span), + visitor, + ) + } else { + Err(Error::custom( + format!("expected tuple with length {}", len), + values_span, + )) + } + } + e => Err(Error::custom( + format!("expected table, found {}", e.type_name()), + e.span(), + )), + } + } + + fn struct_variant( + self, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + serde::de::Deserializer::deserialize_struct( + super::ValueDeserializer::new(self.value).with_struct_key_validation(), + "", // TODO: this should be the variant name + fields, + visitor, + ) + } +} diff --git a/vendor/toml_edit-0.20.7/src/de/value.rs b/vendor/toml_edit-0.20.7/src/de/value.rs new file mode 100644 index 0000000000000..d3cf87fc61fd8 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/de/value.rs @@ -0,0 +1,252 @@ +use serde::de::IntoDeserializer as _; + +use crate::de::DatetimeDeserializer; +use crate::de::Error; + +/// Deserialization implementation for TOML [values][crate::Value]. +/// +/// Can be created either directly from TOML strings, using [`std::str::FromStr`], +/// or from parsed [values][crate::Value] using [`serde::de::IntoDeserializer::into_deserializer`]. +/// +/// # Example +/// +/// ``` +/// use serde::Deserialize; +/// +/// #[derive(Deserialize)] +/// struct Config { +/// title: String, +/// owner: Owner, +/// } +/// +/// #[derive(Deserialize)] +/// struct Owner { +/// name: String, +/// } +/// +/// let value = r#"{ title = 'TOML Example', owner = { name = 'Lisa' } }"#; +/// let deserializer = value.parse::().unwrap(); +/// let config = Config::deserialize(deserializer).unwrap(); +/// assert_eq!(config.title, "TOML Example"); +/// assert_eq!(config.owner.name, "Lisa"); +/// ``` +pub struct ValueDeserializer { + input: crate::Item, + validate_struct_keys: bool, +} + +impl ValueDeserializer { + pub(crate) fn new(input: crate::Item) -> Self { + Self { + input, + validate_struct_keys: false, + } + } + + pub(crate) fn with_struct_key_validation(mut self) -> Self { + self.validate_struct_keys = true; + self + } +} + +// Note: this is wrapped by `toml::de::ValueDeserializer` and any trait methods +// implemented here need to be wrapped there +impl<'de> serde::Deserializer<'de> for ValueDeserializer { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + let span = self.input.span(); + match self.input { + crate::Item::None => visitor.visit_none(), + crate::Item::Value(crate::Value::String(v)) => visitor.visit_string(v.into_value()), + crate::Item::Value(crate::Value::Integer(v)) => visitor.visit_i64(v.into_value()), + crate::Item::Value(crate::Value::Float(v)) => visitor.visit_f64(v.into_value()), + crate::Item::Value(crate::Value::Boolean(v)) => visitor.visit_bool(v.into_value()), + crate::Item::Value(crate::Value::Datetime(v)) => { + visitor.visit_map(DatetimeDeserializer::new(v.into_value())) + } + crate::Item::Value(crate::Value::Array(v)) => { + v.into_deserializer().deserialize_any(visitor) + } + crate::Item::Value(crate::Value::InlineTable(v)) => { + v.into_deserializer().deserialize_any(visitor) + } + crate::Item::Table(v) => v.into_deserializer().deserialize_any(visitor), + crate::Item::ArrayOfTables(v) => v.into_deserializer().deserialize_any(visitor), + } + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e + }) + } + + // `None` is interpreted as a missing field so be sure to implement `Some` + // as a present field. + fn deserialize_option(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + let span = self.input.span(); + visitor.visit_some(self).map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e + }) + } + + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + let span = self.input.span(); + visitor + .visit_newtype_struct(self) + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e + }) + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + if serde_spanned::__unstable::is_spanned(name, fields) { + if let Some(span) = self.input.span() { + return visitor.visit_map(super::SpannedDeserializer::new(self, span)); + } + } + + if name == toml_datetime::__unstable::NAME && fields == [toml_datetime::__unstable::FIELD] { + let span = self.input.span(); + if let crate::Item::Value(crate::Value::Datetime(d)) = self.input { + return visitor + .visit_map(DatetimeDeserializer::new(d.into_value())) + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e + }); + } + } + + if self.validate_struct_keys { + let span = self.input.span(); + match &self.input { + crate::Item::Table(values) => super::validate_struct_keys(&values.items, fields), + crate::Item::Value(crate::Value::InlineTable(values)) => { + super::validate_struct_keys(&values.items, fields) + } + _ => Ok(()), + } + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e + })? + } + + self.deserialize_any(visitor) + } + + // Called when the type to deserialize is an enum, as opposed to a field in the type. + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + let span = self.input.span(); + match self.input { + crate::Item::Value(crate::Value::String(v)) => { + visitor.visit_enum(v.into_value().into_deserializer()) + } + crate::Item::Value(crate::Value::InlineTable(v)) => { + if v.is_empty() { + Err(crate::de::Error::custom( + "wanted exactly 1 element, found 0 elements", + v.span(), + )) + } else if v.len() != 1 { + Err(crate::de::Error::custom( + "wanted exactly 1 element, more than 1 element", + v.span(), + )) + } else { + v.into_deserializer() + .deserialize_enum(name, variants, visitor) + } + } + crate::Item::Table(v) => v + .into_deserializer() + .deserialize_enum(name, variants, visitor), + e => Err(crate::de::Error::custom("wanted string or table", e.span())), + } + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e + }) + } + + serde::forward_to_deserialize_any! { + bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq + bytes byte_buf map unit + ignored_any unit_struct tuple_struct tuple identifier + } +} + +impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for ValueDeserializer { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for crate::Value { + type Deserializer = ValueDeserializer; + + fn into_deserializer(self) -> Self::Deserializer { + ValueDeserializer::new(crate::Item::Value(self)) + } +} + +impl crate::Item { + pub(crate) fn into_deserializer(self) -> ValueDeserializer { + ValueDeserializer::new(self) + } +} + +impl std::str::FromStr for ValueDeserializer { + type Err = Error; + + /// Parses a value from a &str + fn from_str(s: &str) -> Result { + let v = crate::parser::parse_value(s).map_err(Error::from)?; + Ok(v.into_deserializer()) + } +} diff --git a/vendor/toml_edit-0.20.7/src/document.rs b/vendor/toml_edit-0.20.7/src/document.rs new file mode 100644 index 0000000000000..67dd293dd0373 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/document.rs @@ -0,0 +1,113 @@ +use std::str::FromStr; + +use crate::parser; +use crate::table::Iter; +use crate::{Item, RawString, Table}; + +/// Type representing a TOML document +#[derive(Debug, Clone)] +pub struct Document { + pub(crate) root: Item, + // Trailing comments and whitespaces + pub(crate) trailing: RawString, + pub(crate) original: Option, + pub(crate) span: Option>, +} + +impl Document { + /// Creates an empty document + pub fn new() -> Self { + Default::default() + } + + /// Returns a reference to the root item. + pub fn as_item(&self) -> &Item { + &self.root + } + + /// Returns a mutable reference to the root item. + pub fn as_item_mut(&mut self) -> &mut Item { + &mut self.root + } + + /// Returns a reference to the root table. + pub fn as_table(&self) -> &Table { + self.root.as_table().expect("root should always be a table") + } + + /// Returns a mutable reference to the root table. + pub fn as_table_mut(&mut self) -> &mut Table { + self.root + .as_table_mut() + .expect("root should always be a table") + } + + /// Returns an iterator over the root table. + pub fn iter(&self) -> Iter<'_> { + self.as_table().iter() + } + + /// Set whitespace after last element + pub fn set_trailing(&mut self, trailing: impl Into) { + self.trailing = trailing.into(); + } + + /// Whitespace after last element + pub fn trailing(&self) -> &RawString { + &self.trailing + } + + /// # Panics + /// + /// If run on on a `Document` not generated by the parser + pub(crate) fn despan(&mut self) { + self.span = None; + self.root.despan(self.original.as_deref().unwrap()); + self.trailing.despan(self.original.as_deref().unwrap()); + } +} + +impl Default for Document { + fn default() -> Self { + Self { + root: Item::Table(Table::with_pos(Some(0))), + trailing: Default::default(), + original: Default::default(), + span: Default::default(), + } + } +} + +impl FromStr for Document { + type Err = crate::TomlError; + + /// Parses a document from a &str + fn from_str(s: &str) -> Result { + let mut d = parser::parse_document(s)?; + d.despan(); + Ok(d) + } +} + +impl std::ops::Deref for Document { + type Target = Table; + + fn deref(&self) -> &Self::Target { + self.as_table() + } +} + +impl std::ops::DerefMut for Document { + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_table_mut() + } +} + +impl From
for Document { + fn from(root: Table) -> Self { + Self { + root: Item::Table(root), + ..Default::default() + } + } +} diff --git a/vendor/toml_edit-0.20.7/src/encode.rs b/vendor/toml_edit-0.20.7/src/encode.rs new file mode 100644 index 0000000000000..db10e29ea3397 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/encode.rs @@ -0,0 +1,565 @@ +use std::borrow::Cow; +use std::fmt::{Display, Formatter, Result, Write}; + +use toml_datetime::*; + +use crate::document::Document; +use crate::inline_table::DEFAULT_INLINE_KEY_DECOR; +use crate::key::Key; +use crate::repr::{Formatted, Repr, ValueRepr}; +use crate::table::{DEFAULT_KEY_DECOR, DEFAULT_KEY_PATH_DECOR, DEFAULT_TABLE_DECOR}; +use crate::value::{ + DEFAULT_LEADING_VALUE_DECOR, DEFAULT_TRAILING_VALUE_DECOR, DEFAULT_VALUE_DECOR, +}; +use crate::{Array, InlineTable, Item, Table, Value}; + +pub(crate) trait Encode { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result; +} + +impl Encode for Key { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + let decor = self.decor(); + decor.prefix_encode(buf, input, default_decor.0)?; + + if let Some(input) = input { + let repr = self + .as_repr() + .map(Cow::Borrowed) + .unwrap_or_else(|| Cow::Owned(self.default_repr())); + repr.encode(buf, input)?; + } else { + let repr = self.display_repr(); + write!(buf, "{}", repr)?; + }; + + decor.suffix_encode(buf, input, default_decor.1)?; + Ok(()) + } +} + +impl<'k> Encode for &'k [Key] { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + for (i, key) in self.iter().enumerate() { + let first = i == 0; + let last = i + 1 == self.len(); + + let prefix = if first { + default_decor.0 + } else { + DEFAULT_KEY_PATH_DECOR.0 + }; + let suffix = if last { + default_decor.1 + } else { + DEFAULT_KEY_PATH_DECOR.1 + }; + + if !first { + write!(buf, ".")?; + } + key.encode(buf, input, (prefix, suffix))?; + } + Ok(()) + } +} + +impl<'k> Encode for &'k [&'k Key] { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + for (i, key) in self.iter().enumerate() { + let first = i == 0; + let last = i + 1 == self.len(); + + let prefix = if first { + default_decor.0 + } else { + DEFAULT_KEY_PATH_DECOR.0 + }; + let suffix = if last { + default_decor.1 + } else { + DEFAULT_KEY_PATH_DECOR.1 + }; + + if !first { + write!(buf, ".")?; + } + key.encode(buf, input, (prefix, suffix))?; + } + Ok(()) + } +} + +impl Encode for Formatted +where + T: ValueRepr, +{ + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + let decor = self.decor(); + decor.prefix_encode(buf, input, default_decor.0)?; + + if let Some(input) = input { + let repr = self + .as_repr() + .map(Cow::Borrowed) + .unwrap_or_else(|| Cow::Owned(self.default_repr())); + repr.encode(buf, input)?; + } else { + let repr = self.display_repr(); + write!(buf, "{}", repr)?; + }; + + decor.suffix_encode(buf, input, default_decor.1)?; + Ok(()) + } +} + +impl Encode for Array { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + let decor = self.decor(); + decor.prefix_encode(buf, input, default_decor.0)?; + write!(buf, "[")?; + + for (i, elem) in self.iter().enumerate() { + let inner_decor; + if i == 0 { + inner_decor = DEFAULT_LEADING_VALUE_DECOR; + } else { + inner_decor = DEFAULT_VALUE_DECOR; + write!(buf, ",")?; + } + elem.encode(buf, input, inner_decor)?; + } + if self.trailing_comma() && !self.is_empty() { + write!(buf, ",")?; + } + + self.trailing().encode_with_default(buf, input, "")?; + write!(buf, "]")?; + decor.suffix_encode(buf, input, default_decor.1)?; + + Ok(()) + } +} + +impl Encode for InlineTable { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + let decor = self.decor(); + decor.prefix_encode(buf, input, default_decor.0)?; + write!(buf, "{{")?; + self.preamble().encode_with_default(buf, input, "")?; + + let children = self.get_values(); + let len = children.len(); + for (i, (key_path, value)) in children.into_iter().enumerate() { + if i != 0 { + write!(buf, ",")?; + } + let inner_decor = if i == len - 1 { + DEFAULT_TRAILING_VALUE_DECOR + } else { + DEFAULT_VALUE_DECOR + }; + key_path + .as_slice() + .encode(buf, input, DEFAULT_INLINE_KEY_DECOR)?; + write!(buf, "=")?; + value.encode(buf, input, inner_decor)?; + } + + write!(buf, "}}")?; + decor.suffix_encode(buf, input, default_decor.1)?; + + Ok(()) + } +} + +impl Encode for Value { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + match self { + Value::String(repr) => repr.encode(buf, input, default_decor), + Value::Integer(repr) => repr.encode(buf, input, default_decor), + Value::Float(repr) => repr.encode(buf, input, default_decor), + Value::Boolean(repr) => repr.encode(buf, input, default_decor), + Value::Datetime(repr) => repr.encode(buf, input, default_decor), + Value::Array(array) => array.encode(buf, input, default_decor), + Value::InlineTable(table) => table.encode(buf, input, default_decor), + } + } +} + +impl Display for Document { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + let mut path = Vec::new(); + let mut last_position = 0; + let mut tables = Vec::new(); + visit_nested_tables(self.as_table(), &mut path, false, &mut |t, p, is_array| { + if let Some(pos) = t.position() { + last_position = pos; + } + tables.push((last_position, t, p.clone(), is_array)); + Ok(()) + }) + .unwrap(); + + tables.sort_by_key(|&(id, _, _, _)| id); + let mut first_table = true; + for (_, table, path, is_array) in tables { + visit_table( + f, + self.original.as_deref(), + table, + &path, + is_array, + &mut first_table, + )?; + } + self.trailing() + .encode_with_default(f, self.original.as_deref(), "") + } +} + +fn visit_nested_tables<'t, F>( + table: &'t Table, + path: &mut Vec, + is_array_of_tables: bool, + callback: &mut F, +) -> Result +where + F: FnMut(&'t Table, &Vec, bool) -> Result, +{ + if !table.is_dotted() { + callback(table, path, is_array_of_tables)?; + } + + for kv in table.items.values() { + match kv.value { + Item::Table(ref t) => { + let mut key = kv.key.clone(); + if t.is_dotted() { + // May have newlines and generally isn't written for standard tables + key.decor_mut().clear(); + } + path.push(key); + visit_nested_tables(t, path, false, callback)?; + path.pop(); + } + Item::ArrayOfTables(ref a) => { + for t in a.iter() { + let key = kv.key.clone(); + path.push(key); + visit_nested_tables(t, path, true, callback)?; + path.pop(); + } + } + _ => {} + } + } + Ok(()) +} + +fn visit_table( + buf: &mut dyn Write, + input: Option<&str>, + table: &Table, + path: &[Key], + is_array_of_tables: bool, + first_table: &mut bool, +) -> Result { + let children = table.get_values(); + // We are intentionally hiding implicit tables without any tables nested under them (ie + // `table.is_empty()` which is in contrast to `table.get_values().is_empty()`). We are + // trusting the user that an empty implicit table is not semantically meaningful + // + // This allows a user to delete all tables under this implicit table and the implicit table + // will disappear. + // + // However, this means that users need to take care in deciding what tables get marked as + // implicit. + let is_visible_std_table = !(table.implicit && children.is_empty()); + + if path.is_empty() { + // don't print header for the root node + if !children.is_empty() { + *first_table = false; + } + } else if is_array_of_tables { + let default_decor = if *first_table { + *first_table = false; + ("", DEFAULT_TABLE_DECOR.1) + } else { + DEFAULT_TABLE_DECOR + }; + table.decor.prefix_encode(buf, input, default_decor.0)?; + write!(buf, "[[")?; + path.encode(buf, input, DEFAULT_KEY_PATH_DECOR)?; + write!(buf, "]]")?; + table.decor.suffix_encode(buf, input, default_decor.1)?; + writeln!(buf)?; + } else if is_visible_std_table { + let default_decor = if *first_table { + *first_table = false; + ("", DEFAULT_TABLE_DECOR.1) + } else { + DEFAULT_TABLE_DECOR + }; + table.decor.prefix_encode(buf, input, default_decor.0)?; + write!(buf, "[")?; + path.encode(buf, input, DEFAULT_KEY_PATH_DECOR)?; + write!(buf, "]")?; + table.decor.suffix_encode(buf, input, default_decor.1)?; + writeln!(buf)?; + } + // print table body + for (key_path, value) in children { + key_path.as_slice().encode(buf, input, DEFAULT_KEY_DECOR)?; + write!(buf, "=")?; + value.encode(buf, input, DEFAULT_VALUE_DECOR)?; + writeln!(buf)?; + } + Ok(()) +} + +impl ValueRepr for String { + fn to_repr(&self) -> Repr { + to_string_repr(self, None, None) + } +} + +pub(crate) fn to_string_repr( + value: &str, + style: Option, + literal: Option, +) -> Repr { + let (style, literal) = match (style, literal) { + (Some(style), Some(literal)) => (style, literal), + (_, Some(literal)) => (infer_style(value).0, literal), + (Some(style), _) => (style, infer_style(value).1), + (_, _) => infer_style(value), + }; + + let mut output = String::with_capacity(value.len() * 2); + if literal { + output.push_str(style.literal_start()); + output.push_str(value); + output.push_str(style.literal_end()); + } else { + output.push_str(style.standard_start()); + for ch in value.chars() { + match ch { + '\u{8}' => output.push_str("\\b"), + '\u{9}' => output.push_str("\\t"), + '\u{a}' => match style { + StringStyle::NewlineTriple => output.push('\n'), + StringStyle::OnelineSingle => output.push_str("\\n"), + _ => unreachable!(), + }, + '\u{c}' => output.push_str("\\f"), + '\u{d}' => output.push_str("\\r"), + '\u{22}' => output.push_str("\\\""), + '\u{5c}' => output.push_str("\\\\"), + c if c <= '\u{1f}' || c == '\u{7f}' => { + write!(output, "\\u{:04X}", ch as u32).unwrap(); + } + ch => output.push(ch), + } + } + output.push_str(style.standard_end()); + } + + Repr::new_unchecked(output) +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) enum StringStyle { + NewlineTriple, + OnelineTriple, + OnelineSingle, +} + +impl StringStyle { + fn literal_start(self) -> &'static str { + match self { + Self::NewlineTriple => "'''\n", + Self::OnelineTriple => "'''", + Self::OnelineSingle => "'", + } + } + fn literal_end(self) -> &'static str { + match self { + Self::NewlineTriple => "'''", + Self::OnelineTriple => "'''", + Self::OnelineSingle => "'", + } + } + + fn standard_start(self) -> &'static str { + match self { + Self::NewlineTriple => "\"\"\"\n", + // note: OnelineTriple can happen if do_pretty wants to do + // '''it's one line''' + // but literal == false + Self::OnelineTriple | Self::OnelineSingle => "\"", + } + } + + fn standard_end(self) -> &'static str { + match self { + Self::NewlineTriple => "\"\"\"", + // note: OnelineTriple can happen if do_pretty wants to do + // '''it's one line''' + // but literal == false + Self::OnelineTriple | Self::OnelineSingle => "\"", + } + } +} + +fn infer_style(value: &str) -> (StringStyle, bool) { + // We need to determine: + // - if we are a "multi-line" pretty (if there are \n) + // - if ['''] appears if multi or ['] if single + // - if there are any invalid control characters + // + // Doing it any other way would require multiple passes + // to determine if a pretty string works or not. + let mut ty = StringStyle::OnelineSingle; + // found consecutive single quotes + let mut max_found_singles = 0; + let mut found_singles = 0; + let mut prefer_literal = false; + let mut can_be_pretty = true; + + for ch in value.chars() { + if can_be_pretty { + if ch == '\'' { + found_singles += 1; + if found_singles >= 3 { + can_be_pretty = false; + } + } else { + if found_singles > max_found_singles { + max_found_singles = found_singles; + } + found_singles = 0 + } + match ch { + '\t' => {} + '\\' => { + prefer_literal = true; + } + '\n' => ty = StringStyle::NewlineTriple, + // Escape codes are needed if any ascii control + // characters are present, including \b \f \r. + c if c <= '\u{1f}' || c == '\u{7f}' => can_be_pretty = false, + _ => {} + } + } else { + // the string cannot be represented as pretty, + // still check if it should be multiline + if ch == '\n' { + ty = StringStyle::NewlineTriple; + } + } + } + if found_singles > 0 && value.ends_with('\'') { + // We cannot escape the ending quote so we must use """ + can_be_pretty = false; + } + if !prefer_literal { + can_be_pretty = false; + } + if !can_be_pretty { + debug_assert!(ty != StringStyle::OnelineTriple); + return (ty, false); + } + if found_singles > max_found_singles { + max_found_singles = found_singles; + } + debug_assert!(max_found_singles < 3); + if ty == StringStyle::OnelineSingle && max_found_singles >= 1 { + // no newlines, but must use ''' because it has ' in it + ty = StringStyle::OnelineTriple; + } + (ty, true) +} + +impl ValueRepr for i64 { + fn to_repr(&self) -> Repr { + Repr::new_unchecked(self.to_string()) + } +} + +impl ValueRepr for f64 { + fn to_repr(&self) -> Repr { + to_f64_repr(*self) + } +} + +fn to_f64_repr(f: f64) -> Repr { + let repr = match (f.is_sign_negative(), f.is_nan(), f == 0.0) { + (true, true, _) => "-nan".to_owned(), + (false, true, _) => "nan".to_owned(), + (true, false, true) => "-0.0".to_owned(), + (false, false, true) => "0.0".to_owned(), + (_, false, false) => { + if f % 1.0 == 0.0 { + format!("{}.0", f) + } else { + format!("{}", f) + } + } + }; + Repr::new_unchecked(repr) +} + +impl ValueRepr for bool { + fn to_repr(&self) -> Repr { + Repr::new_unchecked(self.to_string()) + } +} + +impl ValueRepr for Datetime { + fn to_repr(&self) -> Repr { + Repr::new_unchecked(self.to_string()) + } +} diff --git a/vendor/toml_edit-0.20.7/src/index.rs b/vendor/toml_edit-0.20.7/src/index.rs new file mode 100644 index 0000000000000..276db7957b183 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/index.rs @@ -0,0 +1,156 @@ +use std::ops; + +use crate::document::Document; +use crate::key::Key; +use crate::table::TableKeyValue; +use crate::{value, InlineTable, InternalString, Item, Table, Value}; + +// copied from +// https://github.com/serde-rs/json/blob/master/src/value/index.rs + +pub trait Index: crate::private::Sealed { + #[doc(hidden)] + fn index<'v>(&self, val: &'v Item) -> Option<&'v Item>; + #[doc(hidden)] + fn index_mut<'v>(&self, val: &'v mut Item) -> Option<&'v mut Item>; +} + +impl Index for usize { + fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> { + match *v { + Item::ArrayOfTables(ref aot) => aot.values.get(*self), + Item::Value(ref a) if a.is_array() => a.as_array().and_then(|a| a.values.get(*self)), + _ => None, + } + } + fn index_mut<'v>(&self, v: &'v mut Item) -> Option<&'v mut Item> { + match *v { + Item::ArrayOfTables(ref mut vec) => vec.values.get_mut(*self), + Item::Value(ref mut a) => a.as_array_mut().and_then(|a| a.values.get_mut(*self)), + _ => None, + } + } +} + +impl Index for str { + fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> { + match *v { + Item::Table(ref t) => t.get(self), + Item::Value(ref v) => v + .as_inline_table() + .and_then(|t| t.items.get(self)) + .and_then(|kv| { + if !kv.value.is_none() { + Some(&kv.value) + } else { + None + } + }), + _ => None, + } + } + fn index_mut<'v>(&self, v: &'v mut Item) -> Option<&'v mut Item> { + if let Item::None = *v { + let mut t = InlineTable::default(); + t.items.insert( + InternalString::from(self), + TableKeyValue::new(Key::new(self), Item::None), + ); + *v = value(Value::InlineTable(t)); + } + match *v { + Item::Table(ref mut t) => Some(t.entry(self).or_insert(Item::None)), + Item::Value(ref mut v) => v.as_inline_table_mut().map(|t| { + &mut t + .items + .entry(InternalString::from(self)) + .or_insert_with(|| TableKeyValue::new(Key::new(self), Item::None)) + .value + }), + _ => None, + } + } +} + +impl Index for String { + fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> { + self[..].index(v) + } + fn index_mut<'v>(&self, v: &'v mut Item) -> Option<&'v mut Item> { + self[..].index_mut(v) + } +} + +impl<'a, T: ?Sized> Index for &'a T +where + T: Index, +{ + fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> { + (**self).index(v) + } + fn index_mut<'v>(&self, v: &'v mut Item) -> Option<&'v mut Item> { + (**self).index_mut(v) + } +} + +impl ops::Index for Item +where + I: Index, +{ + type Output = Item; + + fn index(&self, index: I) -> &Item { + index.index(self).expect("index not found") + } +} + +impl ops::IndexMut for Item +where + I: Index, +{ + fn index_mut(&mut self, index: I) -> &mut Item { + index.index_mut(self).expect("index not found") + } +} + +impl<'s> ops::Index<&'s str> for Table { + type Output = Item; + + fn index(&self, key: &'s str) -> &Item { + self.get(key).expect("index not found") + } +} + +impl<'s> ops::IndexMut<&'s str> for Table { + fn index_mut(&mut self, key: &'s str) -> &mut Item { + self.entry(key).or_insert(Item::None) + } +} + +impl<'s> ops::Index<&'s str> for InlineTable { + type Output = Value; + + fn index(&self, key: &'s str) -> &Value { + self.get(key).expect("index not found") + } +} + +impl<'s> ops::IndexMut<&'s str> for InlineTable { + fn index_mut(&mut self, key: &'s str) -> &mut Value { + self.get_mut(key).expect("index not found") + } +} + +impl<'s> ops::Index<&'s str> for Document { + type Output = Item; + + fn index(&self, key: &'s str) -> &Item { + self.root.index(key) + } +} + +impl<'s> ops::IndexMut<&'s str> for Document { + fn index_mut(&mut self, key: &'s str) -> &mut Item { + self.root.index_mut(key) + } +} diff --git a/vendor/toml_edit-0.20.7/src/inline_table.rs b/vendor/toml_edit-0.20.7/src/inline_table.rs new file mode 100644 index 0000000000000..cbd64adb3a6cd --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/inline_table.rs @@ -0,0 +1,707 @@ +use std::iter::FromIterator; + +use crate::key::Key; +use crate::repr::Decor; +use crate::table::{Iter, IterMut, KeyValuePairs, TableKeyValue, TableLike}; +use crate::{InternalString, Item, KeyMut, RawString, Table, Value}; + +/// Type representing a TOML inline table, +/// payload of the `Value::InlineTable` variant +#[derive(Debug, Default, Clone)] +pub struct InlineTable { + // `preamble` represents whitespaces in an empty table + preamble: RawString, + // Whether to hide an empty table + pub(crate) implicit: bool, + // prefix before `{` and suffix after `}` + decor: Decor, + pub(crate) span: Option>, + // whether this is a proxy for dotted keys + dotted: bool, + pub(crate) items: KeyValuePairs, +} + +/// Constructors +/// +/// See also `FromIterator` +impl InlineTable { + /// Creates an empty table. + pub fn new() -> Self { + Default::default() + } + + pub(crate) fn with_pairs(items: KeyValuePairs) -> Self { + Self { + items, + ..Default::default() + } + } + + /// Convert to a table + pub fn into_table(self) -> Table { + let mut t = Table::with_pairs(self.items); + t.fmt(); + t + } +} + +/// Formatting +impl InlineTable { + /// Get key/values for values that are visually children of this table + /// + /// For example, this will return dotted keys + pub fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> { + let mut values = Vec::new(); + let root = Vec::new(); + self.append_values(&root, &mut values); + values + } + + pub(crate) fn append_values<'s>( + &'s self, + parent: &[&'s Key], + values: &mut Vec<(Vec<&'s Key>, &'s Value)>, + ) { + for value in self.items.values() { + let mut path = parent.to_vec(); + path.push(&value.key); + match &value.value { + Item::Value(Value::InlineTable(table)) if table.is_dotted() => { + table.append_values(&path, values); + } + Item::Value(value) => { + values.push((path, value)); + } + _ => {} + } + } + } + + /// Auto formats the table. + pub fn fmt(&mut self) { + decorate_inline_table(self); + } + + /// Sorts the key/value pairs by key. + pub fn sort_values(&mut self) { + // Assuming standard tables have their position set and this won't negatively impact them + self.items.sort_keys(); + for kv in self.items.values_mut() { + match &mut kv.value { + Item::Value(Value::InlineTable(table)) if table.is_dotted() => { + table.sort_values(); + } + _ => {} + } + } + } + + /// Sort Key/Value Pairs of the table using the using the comparison function `compare`. + /// + /// The comparison function receives two key and value pairs to compare (you can sort by keys or + /// values or their combination as needed). + pub fn sort_values_by(&mut self, mut compare: F) + where + F: FnMut(&Key, &Value, &Key, &Value) -> std::cmp::Ordering, + { + self.sort_values_by_internal(&mut compare); + } + + fn sort_values_by_internal(&mut self, compare: &mut F) + where + F: FnMut(&Key, &Value, &Key, &Value) -> std::cmp::Ordering, + { + let modified_cmp = |_: &InternalString, + val1: &TableKeyValue, + _: &InternalString, + val2: &TableKeyValue| + -> std::cmp::Ordering { + match (val1.value.as_value(), val2.value.as_value()) { + (Some(v1), Some(v2)) => compare(&val1.key, v1, &val2.key, v2), + (Some(_), None) => std::cmp::Ordering::Greater, + (None, Some(_)) => std::cmp::Ordering::Less, + (None, None) => std::cmp::Ordering::Equal, + } + }; + + self.items.sort_by(modified_cmp); + for kv in self.items.values_mut() { + match &mut kv.value { + Item::Value(Value::InlineTable(table)) if table.is_dotted() => { + table.sort_values_by_internal(compare); + } + _ => {} + } + } + } + + /// If a table has no key/value pairs and implicit, it will not be displayed. + /// + /// # Examples + /// + /// ```notrust + /// [target."x86_64/windows.json".dependencies] + /// ``` + /// + /// In the document above, tables `target` and `target."x86_64/windows.json"` are implicit. + /// + /// ``` + /// use toml_edit::Document; + /// let mut doc = "[a]\n[a.b]\n".parse::().expect("invalid toml"); + /// + /// doc["a"].as_table_mut().unwrap().set_implicit(true); + /// assert_eq!(doc.to_string(), "[a.b]\n"); + /// ``` + pub(crate) fn set_implicit(&mut self, implicit: bool) { + self.implicit = implicit; + } + + /// If a table has no key/value pairs and implicit, it will not be displayed. + pub(crate) fn is_implicit(&self) -> bool { + self.implicit + } + + /// Change this table's dotted status + pub fn set_dotted(&mut self, yes: bool) { + self.dotted = yes; + } + + /// Check if this is a wrapper for dotted keys, rather than a standard table + pub fn is_dotted(&self) -> bool { + self.dotted + } + + /// Returns the surrounding whitespace + pub fn decor_mut(&mut self) -> &mut Decor { + &mut self.decor + } + + /// Returns the surrounding whitespace + pub fn decor(&self) -> &Decor { + &self.decor + } + + /// Returns the decor associated with a given key of the table. + pub fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> { + self.items.get_mut(key).map(|kv| &mut kv.key.decor) + } + + /// Returns the decor associated with a given key of the table. + pub fn key_decor(&self, key: &str) -> Option<&Decor> { + self.items.get(key).map(|kv| &kv.key.decor) + } + + /// Set whitespace after before element + pub fn set_preamble(&mut self, preamble: impl Into) { + self.preamble = preamble.into(); + } + + /// Whitespace after before element + pub fn preamble(&self) -> &RawString { + &self.preamble + } + + /// Returns the location within the original document + pub(crate) fn span(&self) -> Option> { + self.span.clone() + } + + pub(crate) fn despan(&mut self, input: &str) { + self.span = None; + self.decor.despan(input); + self.preamble.despan(input); + for kv in self.items.values_mut() { + kv.key.despan(input); + kv.value.despan(input); + } + } +} + +impl InlineTable { + /// Returns an iterator over key/value pairs. + pub fn iter(&self) -> InlineTableIter<'_> { + Box::new( + self.items + .iter() + .filter(|&(_, kv)| kv.value.is_value()) + .map(|(k, kv)| (&k[..], kv.value.as_value().unwrap())), + ) + } + + /// Returns an iterator over key/value pairs. + pub fn iter_mut(&mut self) -> InlineTableIterMut<'_> { + Box::new( + self.items + .iter_mut() + .filter(|(_, kv)| kv.value.is_value()) + .map(|(_, kv)| (kv.key.as_mut(), kv.value.as_value_mut().unwrap())), + ) + } + + /// Returns the number of key/value pairs. + pub fn len(&self) -> usize { + self.iter().count() + } + + /// Returns true iff the table is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Clears the table, removing all key-value pairs. Keeps the allocated memory for reuse. + pub fn clear(&mut self) { + self.items.clear() + } + + /// Gets the given key's corresponding entry in the Table for in-place manipulation. + pub fn entry(&'_ mut self, key: impl Into) -> InlineEntry<'_> { + match self.items.entry(key.into()) { + indexmap::map::Entry::Occupied(mut entry) => { + // Ensure it is a `Value` to simplify `InlineOccupiedEntry`'s code. + let scratch = std::mem::take(&mut entry.get_mut().value); + let scratch = Item::Value( + scratch + .into_value() + // HACK: `Item::None` is a corner case of a corner case, let's just pick a + // "safe" value + .unwrap_or_else(|_| Value::InlineTable(Default::default())), + ); + entry.get_mut().value = scratch; + + InlineEntry::Occupied(InlineOccupiedEntry { entry }) + } + indexmap::map::Entry::Vacant(entry) => { + InlineEntry::Vacant(InlineVacantEntry { entry, key: None }) + } + } + } + + /// Gets the given key's corresponding entry in the Table for in-place manipulation. + pub fn entry_format<'a>(&'a mut self, key: &Key) -> InlineEntry<'a> { + // Accept a `&Key` to be consistent with `entry` + match self.items.entry(key.get().into()) { + indexmap::map::Entry::Occupied(mut entry) => { + // Ensure it is a `Value` to simplify `InlineOccupiedEntry`'s code. + let scratch = std::mem::take(&mut entry.get_mut().value); + let scratch = Item::Value( + scratch + .into_value() + // HACK: `Item::None` is a corner case of a corner case, let's just pick a + // "safe" value + .unwrap_or_else(|_| Value::InlineTable(Default::default())), + ); + entry.get_mut().value = scratch; + + InlineEntry::Occupied(InlineOccupiedEntry { entry }) + } + indexmap::map::Entry::Vacant(entry) => InlineEntry::Vacant(InlineVacantEntry { + entry, + key: Some(key.clone()), + }), + } + } + /// Return an optional reference to the value at the given the key. + pub fn get(&self, key: &str) -> Option<&Value> { + self.items.get(key).and_then(|kv| kv.value.as_value()) + } + + /// Return an optional mutable reference to the value at the given the key. + pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> { + self.items + .get_mut(key) + .and_then(|kv| kv.value.as_value_mut()) + } + + /// Return references to the key-value pair stored for key, if it is present, else None. + pub fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> { + self.items.get(key).and_then(|kv| { + if !kv.value.is_none() { + Some((&kv.key, &kv.value)) + } else { + None + } + }) + } + + /// Return mutable references to the key-value pair stored for key, if it is present, else None. + pub fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> { + self.items.get_mut(key).and_then(|kv| { + if !kv.value.is_none() { + Some((kv.key.as_mut(), &mut kv.value)) + } else { + None + } + }) + } + + /// Returns true iff the table contains given key. + pub fn contains_key(&self, key: &str) -> bool { + if let Some(kv) = self.items.get(key) { + kv.value.is_value() + } else { + false + } + } + + /// Inserts a key/value pair if the table does not contain the key. + /// Returns a mutable reference to the corresponding value. + pub fn get_or_insert>( + &mut self, + key: impl Into, + value: V, + ) -> &mut Value { + let key = key.into(); + self.items + .entry(key.clone()) + .or_insert(TableKeyValue::new(Key::new(key), Item::Value(value.into()))) + .value + .as_value_mut() + .expect("non-value type in inline table") + } + + /// Inserts a key-value pair into the map. + pub fn insert(&mut self, key: impl Into, value: Value) -> Option { + let key = key.into(); + let kv = TableKeyValue::new(Key::new(key.clone()), Item::Value(value)); + self.items + .insert(key, kv) + .and_then(|kv| kv.value.into_value().ok()) + } + + /// Inserts a key-value pair into the map. + pub fn insert_formatted(&mut self, key: &Key, value: Value) -> Option { + let kv = TableKeyValue::new(key.to_owned(), Item::Value(value)); + self.items + .insert(InternalString::from(key.get()), kv) + .filter(|kv| kv.value.is_value()) + .map(|kv| kv.value.into_value().unwrap()) + } + + /// Removes an item given the key. + pub fn remove(&mut self, key: &str) -> Option { + self.items + .shift_remove(key) + .and_then(|kv| kv.value.into_value().ok()) + } + + /// Removes a key from the map, returning the stored key and value if the key was previously in the map. + pub fn remove_entry(&mut self, key: &str) -> Option<(Key, Value)> { + self.items.shift_remove(key).and_then(|kv| { + let key = kv.key; + kv.value.into_value().ok().map(|value| (key, value)) + }) + } + + /// Retains only the elements specified by the `keep` predicate. + /// + /// In other words, remove all pairs `(key, value)` for which + /// `keep(&key, &mut value)` returns `false`. + /// + /// The elements are visited in iteration order. + pub fn retain(&mut self, mut keep: F) + where + F: FnMut(&str, &mut Value) -> bool, + { + self.items.retain(|key, item| { + item.value + .as_value_mut() + .map(|value| keep(key, value)) + .unwrap_or(false) + }); + } +} + +impl std::fmt::Display for InlineTable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + crate::encode::Encode::encode(self, f, None, ("", "")) + } +} + +impl, V: Into> Extend<(K, V)> for InlineTable { + fn extend>(&mut self, iter: T) { + for (key, value) in iter { + let key = key.into(); + let value = Item::Value(value.into()); + let value = TableKeyValue::new(key, value); + self.items + .insert(InternalString::from(value.key.get()), value); + } + } +} + +impl, V: Into> FromIterator<(K, V)> for InlineTable { + fn from_iter(iter: I) -> Self + where + I: IntoIterator, + { + let mut table = InlineTable::new(); + table.extend(iter); + table + } +} + +impl IntoIterator for InlineTable { + type Item = (InternalString, Value); + type IntoIter = InlineTableIntoIter; + + fn into_iter(self) -> Self::IntoIter { + Box::new( + self.items + .into_iter() + .filter(|(_, kv)| kv.value.is_value()) + .map(|(k, kv)| (k, kv.value.into_value().unwrap())), + ) + } +} + +impl<'s> IntoIterator for &'s InlineTable { + type Item = (&'s str, &'s Value); + type IntoIter = InlineTableIter<'s>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +fn decorate_inline_table(table: &mut InlineTable) { + for (key_decor, value) in table + .items + .iter_mut() + .filter(|(_, kv)| kv.value.is_value()) + .map(|(_, kv)| (&mut kv.key.decor, kv.value.as_value_mut().unwrap())) + { + key_decor.clear(); + value.decor_mut().clear(); + } +} + +/// An owned iterator type over key/value pairs of an inline table. +pub type InlineTableIntoIter = Box>; +/// An iterator type over key/value pairs of an inline table. +pub type InlineTableIter<'a> = Box + 'a>; +/// A mutable iterator type over key/value pairs of an inline table. +pub type InlineTableIterMut<'a> = Box, &'a mut Value)> + 'a>; + +impl TableLike for InlineTable { + fn iter(&self) -> Iter<'_> { + Box::new(self.items.iter().map(|(key, kv)| (&key[..], &kv.value))) + } + fn iter_mut(&mut self) -> IterMut<'_> { + Box::new( + self.items + .iter_mut() + .map(|(_, kv)| (kv.key.as_mut(), &mut kv.value)), + ) + } + fn clear(&mut self) { + self.clear(); + } + fn entry<'a>(&'a mut self, key: &str) -> crate::Entry<'a> { + // Accept a `&str` rather than an owned type to keep `InternalString`, well, internal + match self.items.entry(key.into()) { + indexmap::map::Entry::Occupied(entry) => { + crate::Entry::Occupied(crate::OccupiedEntry { entry }) + } + indexmap::map::Entry::Vacant(entry) => { + crate::Entry::Vacant(crate::VacantEntry { entry, key: None }) + } + } + } + fn entry_format<'a>(&'a mut self, key: &Key) -> crate::Entry<'a> { + // Accept a `&Key` to be consistent with `entry` + match self.items.entry(key.get().into()) { + indexmap::map::Entry::Occupied(entry) => { + crate::Entry::Occupied(crate::OccupiedEntry { entry }) + } + indexmap::map::Entry::Vacant(entry) => crate::Entry::Vacant(crate::VacantEntry { + entry, + key: Some(key.to_owned()), + }), + } + } + fn get<'s>(&'s self, key: &str) -> Option<&'s Item> { + self.items.get(key).map(|kv| &kv.value) + } + fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item> { + self.items.get_mut(key).map(|kv| &mut kv.value) + } + fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> { + self.get_key_value(key) + } + fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> { + self.get_key_value_mut(key) + } + fn contains_key(&self, key: &str) -> bool { + self.contains_key(key) + } + fn insert(&mut self, key: &str, value: Item) -> Option { + self.insert(key, value.into_value().unwrap()) + .map(Item::Value) + } + fn remove(&mut self, key: &str) -> Option { + self.remove(key).map(Item::Value) + } + + fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> { + self.get_values() + } + fn fmt(&mut self) { + self.fmt() + } + fn sort_values(&mut self) { + self.sort_values() + } + fn set_dotted(&mut self, yes: bool) { + self.set_dotted(yes) + } + fn is_dotted(&self) -> bool { + self.is_dotted() + } + + fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> { + self.key_decor_mut(key) + } + fn key_decor(&self, key: &str) -> Option<&Decor> { + self.key_decor(key) + } +} + +// `{ key1 = value1, ... }` +pub(crate) const DEFAULT_INLINE_KEY_DECOR: (&str, &str) = (" ", " "); + +/// A view into a single location in a map, which may be vacant or occupied. +pub enum InlineEntry<'a> { + /// An occupied Entry. + Occupied(InlineOccupiedEntry<'a>), + /// A vacant Entry. + Vacant(InlineVacantEntry<'a>), +} + +impl<'a> InlineEntry<'a> { + /// Returns the entry key + /// + /// # Examples + /// + /// ``` + /// use toml_edit::Table; + /// + /// let mut map = Table::new(); + /// + /// assert_eq!("hello", map.entry("hello").key()); + /// ``` + pub fn key(&self) -> &str { + match self { + InlineEntry::Occupied(e) => e.key(), + InlineEntry::Vacant(e) => e.key(), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + pub fn or_insert(self, default: Value) -> &'a mut Value { + match self { + InlineEntry::Occupied(entry) => entry.into_mut(), + InlineEntry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + pub fn or_insert_with Value>(self, default: F) -> &'a mut Value { + match self { + InlineEntry::Occupied(entry) => entry.into_mut(), + InlineEntry::Vacant(entry) => entry.insert(default()), + } + } +} + +/// A view into a single occupied location in a `IndexMap`. +pub struct InlineOccupiedEntry<'a> { + entry: indexmap::map::OccupiedEntry<'a, InternalString, TableKeyValue>, +} + +impl<'a> InlineOccupiedEntry<'a> { + /// Gets a reference to the entry key + /// + /// # Examples + /// + /// ``` + /// use toml_edit::Table; + /// + /// let mut map = Table::new(); + /// + /// assert_eq!("foo", map.entry("foo").key()); + /// ``` + pub fn key(&self) -> &str { + self.entry.key().as_str() + } + + /// Gets a mutable reference to the entry key + pub fn key_mut(&mut self) -> KeyMut<'_> { + self.entry.get_mut().key.as_mut() + } + + /// Gets a reference to the value in the entry. + pub fn get(&self) -> &Value { + self.entry.get().value.as_value().unwrap() + } + + /// Gets a mutable reference to the value in the entry. + pub fn get_mut(&mut self) -> &mut Value { + self.entry.get_mut().value.as_value_mut().unwrap() + } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself + pub fn into_mut(self) -> &'a mut Value { + self.entry.into_mut().value.as_value_mut().unwrap() + } + + /// Sets the value of the entry, and returns the entry's old value + pub fn insert(&mut self, value: Value) -> Value { + let mut value = Item::Value(value); + std::mem::swap(&mut value, &mut self.entry.get_mut().value); + value.into_value().unwrap() + } + + /// Takes the value out of the entry, and returns it + pub fn remove(self) -> Value { + self.entry.shift_remove().value.into_value().unwrap() + } +} + +/// A view into a single empty location in a `IndexMap`. +pub struct InlineVacantEntry<'a> { + entry: indexmap::map::VacantEntry<'a, InternalString, TableKeyValue>, + key: Option, +} + +impl<'a> InlineVacantEntry<'a> { + /// Gets a reference to the entry key + /// + /// # Examples + /// + /// ``` + /// use toml_edit::Table; + /// + /// let mut map = Table::new(); + /// + /// assert_eq!("foo", map.entry("foo").key()); + /// ``` + pub fn key(&self) -> &str { + self.entry.key().as_str() + } + + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it + pub fn insert(self, value: Value) -> &'a mut Value { + let entry = self.entry; + let key = self.key.unwrap_or_else(|| Key::new(entry.key().as_str())); + let value = Item::Value(value); + entry + .insert(TableKeyValue::new(key, value)) + .value + .as_value_mut() + .unwrap() + } +} diff --git a/vendor/toml_edit-0.20.7/src/internal_string.rs b/vendor/toml_edit-0.20.7/src/internal_string.rs new file mode 100644 index 0000000000000..d4347d25b9466 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/internal_string.rs @@ -0,0 +1,183 @@ +use std::borrow::Borrow; +use std::str::FromStr; + +/// Opaque string storage internal to `toml_edit` +#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct InternalString(Inner); + +#[cfg(feature = "kstring")] +type Inner = kstring::KString; +#[cfg(not(feature = "kstring"))] +type Inner = String; + +impl InternalString { + /// Create an empty string + pub fn new() -> Self { + InternalString(Inner::new()) + } + + /// Access the underlying string + #[inline] + pub fn as_str(&self) -> &str { + self.0.as_str() + } +} + +impl std::fmt::Debug for InternalString { + #[inline] + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + self.0.fmt(formatter) + } +} + +impl std::ops::Deref for InternalString { + type Target = str; + + #[inline] + fn deref(&self) -> &str { + self.as_str() + } +} + +impl Borrow for InternalString { + #[inline] + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl AsRef for InternalString { + #[inline] + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl From<&str> for InternalString { + #[inline] + fn from(s: &str) -> Self { + #[cfg(feature = "kstring")] + let inner = kstring::KString::from_ref(s); + #[cfg(not(feature = "kstring"))] + let inner = String::from(s); + + InternalString(inner) + } +} + +impl From for InternalString { + #[inline] + fn from(s: String) -> Self { + #[allow(clippy::useless_conversion)] // handle any string type + InternalString(s.into()) + } +} + +impl From<&String> for InternalString { + #[inline] + fn from(s: &String) -> Self { + InternalString(s.into()) + } +} + +impl From<&InternalString> for InternalString { + #[inline] + fn from(s: &InternalString) -> Self { + s.clone() + } +} + +impl From> for InternalString { + #[inline] + fn from(s: Box) -> Self { + InternalString(s.into()) + } +} + +impl FromStr for InternalString { + type Err = core::convert::Infallible; + #[inline] + fn from_str(s: &str) -> Result { + Ok(Self::from(s)) + } +} + +impl std::fmt::Display for InternalString { + #[inline] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.as_str().fmt(f) + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for InternalString { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(self.as_str()) + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for InternalString { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_string(StringVisitor) + } +} + +#[cfg(feature = "serde")] +struct StringVisitor; + +#[cfg(feature = "serde")] +impl<'de> serde::de::Visitor<'de> for StringVisitor { + type Value = InternalString; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("a string") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(InternalString::from(v)) + } + + fn visit_string(self, v: String) -> Result + where + E: serde::de::Error, + { + Ok(InternalString::from(v)) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: serde::de::Error, + { + match std::str::from_utf8(v) { + Ok(s) => Ok(InternalString::from(s)), + Err(_) => Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Bytes(v), + &self, + )), + } + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: serde::de::Error, + { + match String::from_utf8(v) { + Ok(s) => Ok(InternalString::from(s)), + Err(e) => Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Bytes(&e.into_bytes()), + &self, + )), + } + } +} diff --git a/vendor/toml_edit-0.20.7/src/item.rs b/vendor/toml_edit-0.20.7/src/item.rs new file mode 100644 index 0000000000000..a1405631978ca --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/item.rs @@ -0,0 +1,388 @@ +use std::str::FromStr; + +use toml_datetime::*; + +use crate::array_of_tables::ArrayOfTables; +use crate::table::TableLike; +use crate::{Array, InlineTable, Table, Value}; + +/// Type representing either a value, a table, an array of tables, or none. +#[derive(Debug, Default)] +pub enum Item { + /// Type representing none. + #[default] + None, + /// Type representing value. + Value(Value), + /// Type representing table. + Table(Table), + /// Type representing array of tables. + ArrayOfTables(ArrayOfTables), +} + +impl Item { + /// Sets `self` to the given item iff `self` is none and + /// returns a mutable reference to `self`. + pub fn or_insert(&mut self, item: Item) -> &mut Item { + if self.is_none() { + *self = item + } + self + } +} + +// TODO: This should be generated by macro or derive +/// Downcasting +impl Item { + /// Text description of value type + pub fn type_name(&self) -> &'static str { + match self { + Item::None => "none", + Item::Value(v) => v.type_name(), + Item::Table(..) => "table", + Item::ArrayOfTables(..) => "array of tables", + } + } + + /// Index into a TOML array or map. A string index can be used to access a + /// value in a map, and a usize index can be used to access an element of an + /// array. + /// + /// Returns `None` if: + /// - The type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is an array or a + /// number. + /// - The given key does not exist in the map + /// or the given index is not within the bounds of the array. + pub fn get(&self, index: I) -> Option<&Item> { + index.index(self) + } + + /// Mutably index into a TOML array or map. A string index can be used to + /// access a value in a map, and a usize index can be used to access an + /// element of an array. + /// + /// Returns `None` if: + /// - The type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is an array or a + /// number. + /// - The given key does not exist in the map + /// or the given index is not within the bounds of the array. + pub fn get_mut(&mut self, index: I) -> Option<&mut Item> { + index.index_mut(self) + } + + /// Casts `self` to value. + pub fn as_value(&self) -> Option<&Value> { + match *self { + Item::Value(ref v) => Some(v), + _ => None, + } + } + /// Casts `self` to table. + pub fn as_table(&self) -> Option<&Table> { + match *self { + Item::Table(ref t) => Some(t), + _ => None, + } + } + /// Casts `self` to array of tables. + pub fn as_array_of_tables(&self) -> Option<&ArrayOfTables> { + match *self { + Item::ArrayOfTables(ref a) => Some(a), + _ => None, + } + } + /// Casts `self` to mutable value. + pub fn as_value_mut(&mut self) -> Option<&mut Value> { + match *self { + Item::Value(ref mut v) => Some(v), + _ => None, + } + } + /// Casts `self` to mutable table. + pub fn as_table_mut(&mut self) -> Option<&mut Table> { + match *self { + Item::Table(ref mut t) => Some(t), + _ => None, + } + } + /// Casts `self` to mutable array of tables. + pub fn as_array_of_tables_mut(&mut self) -> Option<&mut ArrayOfTables> { + match *self { + Item::ArrayOfTables(ref mut a) => Some(a), + _ => None, + } + } + /// Casts `self` to value. + pub fn into_value(self) -> Result { + match self { + Item::None => Err(self), + Item::Value(v) => Ok(v), + Item::Table(v) => { + let v = v.into_inline_table(); + Ok(Value::InlineTable(v)) + } + Item::ArrayOfTables(v) => { + let v = v.into_array(); + Ok(Value::Array(v)) + } + } + } + /// In-place convert to a value + pub fn make_value(&mut self) { + let other = std::mem::take(self); + let other = other.into_value().map(Item::Value).unwrap_or(Item::None); + *self = other; + } + /// Casts `self` to table. + pub fn into_table(self) -> Result { + match self { + Item::Table(t) => Ok(t), + Item::Value(Value::InlineTable(t)) => Ok(t.into_table()), + _ => Err(self), + } + } + /// Casts `self` to array of tables. + pub fn into_array_of_tables(self) -> Result { + match self { + Item::ArrayOfTables(a) => Ok(a), + Item::Value(Value::Array(a)) => { + if a.is_empty() { + Err(Item::Value(Value::Array(a))) + } else if a.iter().all(|v| v.is_inline_table()) { + let mut aot = ArrayOfTables::new(); + aot.values = a.values; + for value in aot.values.iter_mut() { + value.make_item(); + } + Ok(aot) + } else { + Err(Item::Value(Value::Array(a))) + } + } + _ => Err(self), + } + } + // Starting private because the name is unclear + pub(crate) fn make_item(&mut self) { + let other = std::mem::take(self); + let other = match other.into_table().map(crate::Item::Table) { + Ok(i) => i, + Err(i) => i, + }; + let other = match other.into_array_of_tables().map(crate::Item::ArrayOfTables) { + Ok(i) => i, + Err(i) => i, + }; + *self = other; + } + /// Returns true iff `self` is a value. + pub fn is_value(&self) -> bool { + self.as_value().is_some() + } + /// Returns true iff `self` is a table. + pub fn is_table(&self) -> bool { + self.as_table().is_some() + } + /// Returns true iff `self` is an array of tables. + pub fn is_array_of_tables(&self) -> bool { + self.as_array_of_tables().is_some() + } + /// Returns true iff `self` is `None`. + pub fn is_none(&self) -> bool { + matches!(*self, Item::None) + } + + // Duplicate Value downcasting API + + /// Casts `self` to integer. + pub fn as_integer(&self) -> Option { + self.as_value().and_then(Value::as_integer) + } + + /// Returns true iff `self` is an integer. + pub fn is_integer(&self) -> bool { + self.as_integer().is_some() + } + + /// Casts `self` to float. + pub fn as_float(&self) -> Option { + self.as_value().and_then(Value::as_float) + } + + /// Returns true iff `self` is a float. + pub fn is_float(&self) -> bool { + self.as_float().is_some() + } + + /// Casts `self` to boolean. + pub fn as_bool(&self) -> Option { + self.as_value().and_then(Value::as_bool) + } + + /// Returns true iff `self` is a boolean. + pub fn is_bool(&self) -> bool { + self.as_bool().is_some() + } + + /// Casts `self` to str. + pub fn as_str(&self) -> Option<&str> { + self.as_value().and_then(Value::as_str) + } + + /// Returns true iff `self` is a string. + pub fn is_str(&self) -> bool { + self.as_str().is_some() + } + + /// Casts `self` to date-time. + pub fn as_datetime(&self) -> Option<&Datetime> { + self.as_value().and_then(Value::as_datetime) + } + + /// Returns true iff `self` is a date-time. + pub fn is_datetime(&self) -> bool { + self.as_datetime().is_some() + } + + /// Casts `self` to array. + pub fn as_array(&self) -> Option<&Array> { + self.as_value().and_then(Value::as_array) + } + + /// Casts `self` to mutable array. + pub fn as_array_mut(&mut self) -> Option<&mut Array> { + self.as_value_mut().and_then(Value::as_array_mut) + } + + /// Returns true iff `self` is an array. + pub fn is_array(&self) -> bool { + self.as_array().is_some() + } + + /// Casts `self` to inline table. + pub fn as_inline_table(&self) -> Option<&InlineTable> { + self.as_value().and_then(Value::as_inline_table) + } + + /// Casts `self` to mutable inline table. + pub fn as_inline_table_mut(&mut self) -> Option<&mut InlineTable> { + self.as_value_mut().and_then(Value::as_inline_table_mut) + } + + /// Returns true iff `self` is an inline table. + pub fn is_inline_table(&self) -> bool { + self.as_inline_table().is_some() + } + + /// Casts `self` to either a table or an inline table. + pub fn as_table_like(&self) -> Option<&dyn TableLike> { + self.as_table() + .map(|t| t as &dyn TableLike) + .or_else(|| self.as_inline_table().map(|t| t as &dyn TableLike)) + } + + /// Casts `self` to either a table or an inline table. + pub fn as_table_like_mut(&mut self) -> Option<&mut dyn TableLike> { + match self { + Item::Table(t) => Some(t as &mut dyn TableLike), + Item::Value(Value::InlineTable(t)) => Some(t as &mut dyn TableLike), + _ => None, + } + } + + /// Returns true iff `self` is either a table, or an inline table. + pub fn is_table_like(&self) -> bool { + self.as_table_like().is_some() + } + + /// Returns the location within the original document + pub(crate) fn span(&self) -> Option> { + match self { + Item::None => None, + Item::Value(v) => v.span(), + Item::Table(v) => v.span(), + Item::ArrayOfTables(v) => v.span(), + } + } + + pub(crate) fn despan(&mut self, input: &str) { + match self { + Item::None => {} + Item::Value(v) => v.despan(input), + Item::Table(v) => v.despan(input), + Item::ArrayOfTables(v) => v.despan(input), + } + } +} + +impl Clone for Item { + #[inline(never)] + fn clone(&self) -> Self { + match self { + Item::None => Item::None, + Item::Value(v) => Item::Value(v.clone()), + Item::Table(v) => Item::Table(v.clone()), + Item::ArrayOfTables(v) => Item::ArrayOfTables(v.clone()), + } + } +} + +impl FromStr for Item { + type Err = crate::TomlError; + + /// Parses a value from a &str + fn from_str(s: &str) -> Result { + let value = s.parse::()?; + Ok(Item::Value(value)) + } +} + +impl std::fmt::Display for Item { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self { + Item::None => Ok(()), + Item::Value(v) => v.fmt(f), + Item::Table(v) => v.fmt(f), + Item::ArrayOfTables(v) => v.fmt(f), + } + } +} + +/// Returns a formatted value. +/// +/// Since formatting is part of a `Value`, the right hand side of the +/// assignment needs to be decorated with a space before the value. +/// The `value` function does just that. +/// +/// # Examples +/// ```rust +/// # use snapbox::assert_eq; +/// # use toml_edit::*; +/// let mut table = Table::default(); +/// let mut array = Array::default(); +/// array.push("hello"); +/// array.push("\\, world"); // \ is only allowed in a literal string +/// table["key1"] = value("value1"); +/// table["key2"] = value(42); +/// table["key3"] = value(array); +/// assert_eq(table.to_string(), +/// r#"key1 = "value1" +/// key2 = 42 +/// key3 = ["hello", '\, world'] +/// "#); +/// ``` +pub fn value>(v: V) -> Item { + Item::Value(v.into()) +} + +/// Returns an empty table. +pub fn table() -> Item { + Item::Table(Table::new()) +} + +/// Returns an empty array of tables. +pub fn array() -> Item { + Item::ArrayOfTables(ArrayOfTables::new()) +} diff --git a/vendor/toml_edit-0.20.7/src/key.rs b/vendor/toml_edit-0.20.7/src/key.rs new file mode 100644 index 0000000000000..c1ee1655cec06 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/key.rs @@ -0,0 +1,344 @@ +use std::borrow::Cow; +use std::str::FromStr; + +use crate::encode::{to_string_repr, StringStyle}; +use crate::parser; +use crate::parser::key::is_unquoted_char; +use crate::repr::{Decor, Repr}; +use crate::InternalString; + +/// Key as part of a Key/Value Pair or a table header. +/// +/// # Examples +/// +/// ```notrust +/// [dependencies."nom"] +/// version = "5.0" +/// 'literal key' = "nonsense" +/// "basic string key" = 42 +/// ``` +/// +/// There are 3 types of keys: +/// +/// 1. Bare keys (`version` and `dependencies`) +/// +/// 2. Basic quoted keys (`"basic string key"` and `"nom"`) +/// +/// 3. Literal quoted keys (`'literal key'`) +/// +/// For details see [toml spec](https://github.com/toml-lang/toml/#keyvalue-pair). +/// +/// To parse a key use `FromStr` trait implementation: `"string".parse::()`. +#[derive(Debug)] +pub struct Key { + key: InternalString, + pub(crate) repr: Option, + pub(crate) decor: Decor, +} + +impl Key { + /// Create a new table key + pub fn new(key: impl Into) -> Self { + Self { + key: key.into(), + repr: None, + decor: Default::default(), + } + } + + /// Parse a TOML key expression + /// + /// Unlike `"".parse()`, this supports dotted keys. + pub fn parse(repr: &str) -> Result, crate::TomlError> { + Self::try_parse_path(repr) + } + + pub(crate) fn with_repr_unchecked(mut self, repr: Repr) -> Self { + self.repr = Some(repr); + self + } + + /// While creating the `Key`, add `Decor` to it + pub fn with_decor(mut self, decor: Decor) -> Self { + self.decor = decor; + self + } + + /// Access a mutable proxy for the `Key`. + pub fn as_mut(&mut self) -> KeyMut<'_> { + KeyMut { key: self } + } + + /// Returns the parsed key value. + pub fn get(&self) -> &str { + &self.key + } + + pub(crate) fn get_internal(&self) -> &InternalString { + &self.key + } + + /// Returns key raw representation, if available. + pub fn as_repr(&self) -> Option<&Repr> { + self.repr.as_ref() + } + + /// Returns the default raw representation. + pub fn default_repr(&self) -> Repr { + to_key_repr(&self.key) + } + + /// Returns a raw representation. + pub fn display_repr(&self) -> Cow<'_, str> { + self.as_repr() + .and_then(|r| r.as_raw().as_str()) + .map(Cow::Borrowed) + .unwrap_or_else(|| { + Cow::Owned(self.default_repr().as_raw().as_str().unwrap().to_owned()) + }) + } + + /// Returns the surrounding whitespace + pub fn decor_mut(&mut self) -> &mut Decor { + &mut self.decor + } + + /// Returns the surrounding whitespace + pub fn decor(&self) -> &Decor { + &self.decor + } + + /// Returns the location within the original document + #[cfg(feature = "serde")] + pub(crate) fn span(&self) -> Option> { + self.repr.as_ref().and_then(|r| r.span()) + } + + pub(crate) fn despan(&mut self, input: &str) { + self.decor.despan(input); + if let Some(repr) = &mut self.repr { + repr.despan(input) + } + } + + /// Auto formats the key. + pub fn fmt(&mut self) { + self.repr = Some(to_key_repr(&self.key)); + self.decor.clear(); + } + + fn try_parse_simple(s: &str) -> Result { + let mut key = parser::parse_key(s)?; + key.despan(s); + Ok(key) + } + + fn try_parse_path(s: &str) -> Result, crate::TomlError> { + let mut keys = parser::parse_key_path(s)?; + for key in &mut keys { + key.despan(s); + } + Ok(keys) + } +} + +impl Clone for Key { + #[inline(never)] + fn clone(&self) -> Self { + Self { + key: self.key.clone(), + repr: self.repr.clone(), + decor: self.decor.clone(), + } + } +} + +impl std::ops::Deref for Key { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.get() + } +} + +impl std::hash::Hash for Key { + fn hash(&self, state: &mut H) { + self.get().hash(state); + } +} + +impl Ord for Key { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.get().cmp(other.get()) + } +} + +impl PartialOrd for Key { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Eq for Key {} + +impl PartialEq for Key { + #[inline] + fn eq(&self, other: &Key) -> bool { + PartialEq::eq(self.get(), other.get()) + } +} + +impl PartialEq for Key { + #[inline] + fn eq(&self, other: &str) -> bool { + PartialEq::eq(self.get(), other) + } +} + +impl<'s> PartialEq<&'s str> for Key { + #[inline] + fn eq(&self, other: &&str) -> bool { + PartialEq::eq(self.get(), *other) + } +} + +impl PartialEq for Key { + #[inline] + fn eq(&self, other: &String) -> bool { + PartialEq::eq(self.get(), other.as_str()) + } +} + +impl std::fmt::Display for Key { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + crate::encode::Encode::encode(self, f, None, ("", "")) + } +} + +impl FromStr for Key { + type Err = crate::TomlError; + + /// Tries to parse a key from a &str, + /// if fails, tries as basic quoted key (surrounds with "") + /// and then literal quoted key (surrounds with '') + fn from_str(s: &str) -> Result { + Key::try_parse_simple(s) + } +} + +fn to_key_repr(key: &str) -> Repr { + if key.as_bytes().iter().copied().all(is_unquoted_char) && !key.is_empty() { + Repr::new_unchecked(key) + } else { + to_string_repr(key, Some(StringStyle::OnelineSingle), Some(false)) + } +} + +impl<'b> From<&'b str> for Key { + fn from(s: &'b str) -> Self { + Key::new(s) + } +} + +impl<'b> From<&'b String> for Key { + fn from(s: &'b String) -> Self { + Key::new(s) + } +} + +impl From for Key { + fn from(s: String) -> Self { + Key::new(s) + } +} + +impl From for Key { + fn from(s: InternalString) -> Self { + Key::new(s) + } +} + +#[doc(hidden)] +impl From for InternalString { + fn from(key: Key) -> InternalString { + key.key + } +} + +/// A mutable reference to a `Key` +#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] +pub struct KeyMut<'k> { + key: &'k mut Key, +} + +impl<'k> KeyMut<'k> { + /// Returns the parsed key value. + pub fn get(&self) -> &str { + self.key.get() + } + + /// Returns the raw representation, if available. + pub fn as_repr(&self) -> Option<&Repr> { + self.key.as_repr() + } + + /// Returns the default raw representation. + pub fn default_repr(&self) -> Repr { + self.key.default_repr() + } + + /// Returns a raw representation. + pub fn display_repr(&self) -> Cow { + self.key.display_repr() + } + + /// Returns the surrounding whitespace + pub fn decor_mut(&mut self) -> &mut Decor { + self.key.decor_mut() + } + + /// Returns the surrounding whitespace + pub fn decor(&self) -> &Decor { + self.key.decor() + } + + /// Auto formats the key. + pub fn fmt(&mut self) { + self.key.fmt() + } +} + +impl<'k> std::ops::Deref for KeyMut<'k> { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.get() + } +} + +impl<'s> PartialEq for KeyMut<'s> { + #[inline] + fn eq(&self, other: &str) -> bool { + PartialEq::eq(self.get(), other) + } +} + +impl<'s> PartialEq<&'s str> for KeyMut<'s> { + #[inline] + fn eq(&self, other: &&str) -> bool { + PartialEq::eq(self.get(), *other) + } +} + +impl<'s> PartialEq for KeyMut<'s> { + #[inline] + fn eq(&self, other: &String) -> bool { + PartialEq::eq(self.get(), other.as_str()) + } +} + +impl<'k> std::fmt::Display for KeyMut<'k> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(&self.key, f) + } +} diff --git a/vendor/toml_edit-0.20.7/src/lib.rs b/vendor/toml_edit-0.20.7/src/lib.rs new file mode 100644 index 0000000000000..80c0ddda228ea --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/lib.rs @@ -0,0 +1,124 @@ +#![deny(missing_docs)] +// https://github.com/Marwes/combine/issues/172 +#![recursion_limit = "256"] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] + +//! # `toml_edit` +//! +//! This crate allows you to parse and modify toml +//! documents, while preserving comments, spaces *and +//! relative order* or items. +//! +//! If you also need the ease of a more traditional API, see the [`toml`] crate. +//! +//! # Example +//! +//! ```rust +//! use toml_edit::{Document, value}; +//! +//! let toml = r#" +//! "hello" = 'toml!' # comment +//! ['a'.b] +//! "#; +//! let mut doc = toml.parse::().expect("invalid doc"); +//! assert_eq!(doc.to_string(), toml); +//! // let's add a new key/value pair inside a.b: c = {d = "hello"} +//! doc["a"]["b"]["c"]["d"] = value("hello"); +//! // autoformat inline table a.b.c: { d = "hello" } +//! doc["a"]["b"]["c"].as_inline_table_mut().map(|t| t.fmt()); +//! let expected = r#" +//! "hello" = 'toml!' # comment +//! ['a'.b] +//! c = { d = "hello" } +//! "#; +//! assert_eq!(doc.to_string(), expected); +//! ``` +//! +//! ## Controlling formatting +//! +//! By default, values are created with default formatting +//! ```rust +//! let mut doc = toml_edit::Document::new(); +//! doc["foo"] = toml_edit::value("bar"); +//! let expected = r#"foo = "bar" +//! "#; +//! assert_eq!(doc.to_string(), expected); +//! ``` +//! +//! You can choose a custom TOML representation by parsing the value. +//! ```rust +//! let mut doc = toml_edit::Document::new(); +//! doc["foo"] = "'bar'".parse::().unwrap(); +//! let expected = r#"foo = 'bar' +//! "#; +//! assert_eq!(doc.to_string(), expected); +//! ``` +//! +//! ## Limitations +//! +//! Things it does not preserve: +//! +//! * Scattered array of tables (tables are reordered by default, see [test]). +//! * Order of dotted keys, see [issue](https://github.com/ordian/toml_edit/issues/163). +//! +//! [`toml`]: https://docs.rs/toml/latest/toml/ +//! [test]: https://github.com/ordian/toml_edit/blob/f09bd5d075fdb7d2ef8d9bb3270a34506c276753/tests/test_valid.rs#L84 + +mod array; +mod array_of_tables; +mod document; +mod encode; +mod index; +mod inline_table; +mod internal_string; +mod item; +mod key; +mod parser; +mod raw_string; +mod repr; +mod table; +mod value; + +#[cfg(feature = "serde")] +pub mod de; +#[cfg(feature = "serde")] +pub mod ser; + +pub mod visit; +pub mod visit_mut; + +pub use crate::array::{Array, ArrayIntoIter, ArrayIter, ArrayIterMut}; +pub use crate::array_of_tables::{ + ArrayOfTables, ArrayOfTablesIntoIter, ArrayOfTablesIter, ArrayOfTablesIterMut, +}; +pub use crate::document::Document; +pub use crate::inline_table::{ + InlineEntry, InlineOccupiedEntry, InlineTable, InlineTableIntoIter, InlineTableIter, + InlineTableIterMut, InlineVacantEntry, +}; +pub use crate::internal_string::InternalString; +pub use crate::item::{array, table, value, Item}; +pub use crate::key::{Key, KeyMut}; +pub use crate::parser::TomlError; +pub use crate::raw_string::RawString; +pub use crate::repr::{Decor, Formatted, Repr}; +pub use crate::table::{ + Entry, IntoIter, Iter, IterMut, OccupiedEntry, Table, TableLike, VacantEntry, +}; +pub use crate::value::Value; +pub use toml_datetime::*; + +// Prevent users from some traits. +pub(crate) mod private { + pub trait Sealed {} + impl Sealed for usize {} + impl Sealed for str {} + impl Sealed for String {} + impl Sealed for i64 {} + impl Sealed for f64 {} + impl Sealed for bool {} + impl Sealed for crate::Datetime {} + impl<'a, T: ?Sized> Sealed for &'a T where T: Sealed {} + impl Sealed for crate::Table {} + impl Sealed for crate::InlineTable {} +} diff --git a/vendor/toml_edit-0.20.7/src/parser/array.rs b/vendor/toml_edit-0.20.7/src/parser/array.rs new file mode 100644 index 0000000000000..e3b1f3f523114 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/parser/array.rs @@ -0,0 +1,146 @@ +use winnow::combinator::cut_err; +use winnow::combinator::delimited; +use winnow::combinator::opt; +use winnow::combinator::separated1; +use winnow::trace::trace; + +use crate::parser::trivia::ws_comment_newline; +use crate::parser::value::value; +use crate::{Array, Item, RawString, Value}; + +use crate::parser::prelude::*; + +// ;; Array + +// array = array-open array-values array-close +pub(crate) fn array<'i>(check: RecursionCheck) -> impl Parser, Array, ContextError> { + trace("array", move |input: &mut Input<'i>| { + delimited( + ARRAY_OPEN, + cut_err(array_values(check)), + cut_err(ARRAY_CLOSE) + .context(StrContext::Label("array")) + .context(StrContext::Expected(StrContextValue::CharLiteral(']'))), + ) + .parse_next(input) + }) +} + +// note: we're omitting ws and newlines here, because +// they should be part of the formatted values +// array-open = %x5B ws-newline ; [ +pub(crate) const ARRAY_OPEN: u8 = b'['; +// array-close = ws-newline %x5D ; ] +const ARRAY_CLOSE: u8 = b']'; +// array-sep = ws %x2C ws ; , Comma +const ARRAY_SEP: u8 = b','; + +// note: this rule is modified +// array-values = [ ( array-value array-sep array-values ) / +// array-value / ws-comment-newline ] +pub(crate) fn array_values<'i>( + check: RecursionCheck, +) -> impl Parser, Array, ContextError> { + move |input: &mut Input<'i>| { + let check = check.recursing(input)?; + ( + opt( + (separated1(array_value(check), ARRAY_SEP), opt(ARRAY_SEP)).map( + |(v, trailing): (Vec, Option)| { + ( + Array::with_vec(v.into_iter().map(Item::Value).collect()), + trailing.is_some(), + ) + }, + ), + ), + ws_comment_newline.span(), + ) + .try_map::<_, _, std::str::Utf8Error>(|(array, trailing)| { + let (mut array, comma) = array.unwrap_or_default(); + array.set_trailing_comma(comma); + array.set_trailing(RawString::with_span(trailing)); + Ok(array) + }) + .parse_next(input) + } +} + +pub(crate) fn array_value<'i>( + check: RecursionCheck, +) -> impl Parser, Value, ContextError> { + move |input: &mut Input<'i>| { + ( + ws_comment_newline.span(), + value(check), + ws_comment_newline.span(), + ) + .map(|(ws1, v, ws2)| v.decorated(RawString::with_span(ws1), RawString::with_span(ws2))) + .parse_next(input) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn arrays() { + let inputs = [ + r#"[]"#, + r#"[ ]"#, + r#"[ + 1, 2, 3 +]"#, + r#"[ + 1, + 2, # this is ok +]"#, + r#"[# comment +# comment2 + + + ]"#, + r#"[# comment +# comment2 + 1 + +#sd +, +# comment3 + + ]"#, + r#"[1]"#, + r#"[1,]"#, + r#"[ "all", 'strings', """are the same""", '''type''']"#, + r#"[ 100, -2,]"#, + r#"[1, 2, 3]"#, + r#"[1.1, 2.1, 3.1]"#, + r#"["a", "b", "c"]"#, + r#"[ [ 1, 2 ], [3, 4, 5] ]"#, + r#"[ [ 1, 2 ], ["a", "b", "c"] ]"#, + r#"[ { x = 1, a = "2" }, {a = "a",b = "b", c = "c"} ]"#, + ]; + for input in inputs { + dbg!(input); + let mut parsed = array(Default::default()).parse(new_input(input)); + if let Ok(parsed) = &mut parsed { + parsed.despan(input); + } + assert_eq!(parsed.map(|a| a.to_string()), Ok(input.to_owned())); + } + } + + #[test] + fn invalid_arrays() { + let invalid_inputs = [r#"["#, r#"[,]"#, r#"[,2]"#, r#"[1e165,,]"#]; + for input in invalid_inputs { + dbg!(input); + let mut parsed = array(Default::default()).parse(new_input(input)); + if let Ok(parsed) = &mut parsed { + parsed.despan(input); + } + assert!(parsed.is_err()); + } + } +} diff --git a/vendor/toml_edit-0.20.7/src/parser/datetime.rs b/vendor/toml_edit-0.20.7/src/parser/datetime.rs new file mode 100644 index 0000000000000..96a3854d49802 --- /dev/null +++ b/vendor/toml_edit-0.20.7/src/parser/datetime.rs @@ -0,0 +1,470 @@ +use std::ops::RangeInclusive; + +use crate::parser::errors::CustomError; +use crate::parser::prelude::*; +use crate::parser::trivia::from_utf8_unchecked; + +use toml_datetime::*; +use winnow::combinator::alt; +use winnow::combinator::cut_err; +use winnow::combinator::opt; +use winnow::combinator::preceded; +use winnow::stream::Stream as _; +use winnow::token::one_of; +use winnow::token::take_while; +use winnow::trace::trace; + +// ;; Date and Time (as defined in RFC 3339) + +// date-time = offset-date-time / local-date-time / local-date / local-time +// offset-date-time = full-date time-delim full-time +// local-date-time = full-date time-delim partial-time +// local-date = full-date +// local-time = partial-time +// full-time = partial-time time-offset +pub(crate) fn date_time(input: &mut Input<'_>) -> PResult { + trace( + "date-time", + alt(( + (full_date, opt((time_delim, partial_time, opt(time_offset)))) + .map(|(date, opt)| { + match opt { + // Offset Date-Time + Some((_, time, offset)) => Datetime { + date: Some(date), + time: Some(time), + offset, + }, + // Local Date + None => Datetime { + date: Some(date), + time: None, + offset: None, + }, + } + }) + .context(StrContext::Label("date-time")), + partial_time + .map(|t| t.into()) + .context(StrContext::Label("time")), + )), + ) + .parse_next(input) +} + +// full-date = date-fullyear "-" date-month "-" date-mday +pub(crate) fn full_date(input: &mut Input<'_>) -> PResult { + trace("full-date", full_date_).parse_next(input) +} + +fn full_date_(input: &mut Input<'_>) -> PResult { + let year = date_fullyear.parse_next(input)?; + let _ = b'-'.parse_next(input)?; + let month = cut_err(date_month).parse_next(input)?; + let _ = cut_err(b'-').parse_next(input)?; + let day_start = input.checkpoint(); + let day = cut_err(date_mday).parse_next(input)?; + + let is_leap_year = (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); + let max_days_in_month = match month { + 2 if is_leap_year => 29, + 2 => 28, + 4 | 6 | 9 | 11 => 30, + _ => 31, + }; + if max_days_in_month < day { + input.reset(day_start); + return Err(winnow::error::ErrMode::from_external_error( + input, + winnow::error::ErrorKind::Verify, + CustomError::OutOfRange, + ) + .cut()); + } + + Ok(Date { year, month, day }) +} + +// partial-time = time-hour ":" time-minute ":" time-second [time-secfrac] +pub(crate) fn partial_time(input: &mut Input<'_>) -> PResult

+Rustls is a modern TLS library written in Rust. It uses ring for cryptography and webpki for certificate +verification. +